diff --git a/TMessagesProj/build.gradle b/TMessagesProj/build.gradle index 4058cf00..7293dfe9 100644 --- a/TMessagesProj/build.gradle +++ b/TMessagesProj/build.gradle @@ -5,16 +5,16 @@ repositories { } dependencies { - compile 'com.android.support:support-v4:23.1.+' + compile 'com.android.support:support-v4:23.3.0' compile "com.google.android.gms:play-services-gcm:8.4.0" compile "com.google.android.gms:play-services-maps:8.4.0" - compile 'net.hockeyapp.android:HockeySDK:3.6.+' + compile 'net.hockeyapp.android:HockeySDK:4.0.0-beta.1' compile 'com.googlecode.mp4parser:isoparser:1.0.+' } android { compileSdkVersion 23 - buildToolsVersion '23.0.2' + buildToolsVersion '23.0.3' useLibrary 'org.apache.http.legacy' //defaultConfig.applicationId = "org.telegram.messenger" @@ -65,6 +65,10 @@ android { } } + defaultConfig.versionCode = 798 + + defaultConfig.manifestPlaceholders = [HOCKEYAPP_APP_ID: ""] + sourceSets.main { jniLibs.srcDir 'libs' jni.srcDirs = [] //disable automatic ndk-build call @@ -87,10 +91,40 @@ android { abortOnError false } + productFlavors { + arm { + ndk { + abiFilter "armeabi" + } + versionCode = 0 + } + armv7 { + ndk { + abiFilter "armeabi-v7a" + } + versionCode = 1 + } + x86 { + ndk { + abiFilter "x86" + } + versionCode = 2 + } + fat { + versionCode = 3 + } + } + + applicationVariants.all { variant -> + def abiVersion = variant.productFlavors.get(0).versionCode + variant.mergedFlavor.versionCode = defaultConfig.versionCode * 10 + abiVersion; + } + defaultConfig { minSdkVersion 9 targetSdkVersion 23 - versionCode 736 - versionName "3.4.2.5" + versionName "3.8.1.2" } -} + } + +apply plugin: 'com.google.gms.google-services' diff --git a/TMessagesProj/config/debug/AndroidManifest.xml b/TMessagesProj/config/debug/AndroidManifest.xml index c524d434..23da651d 100644 --- a/TMessagesProj/config/debug/AndroidManifest.xml +++ b/TMessagesProj/config/debug/AndroidManifest.xml @@ -23,9 +23,9 @@ + + +#include +#include "breakpad/client/linux/handler/exception_handler.h" +#include "breakpad/client/linux/handler/minidump_descriptor.h" + +/*static google_breakpad::ExceptionHandler *exceptionHandler; + +bool callback(const google_breakpad::MinidumpDescriptor &descriptor, void *context, bool succeeded) { + printf("dump path: %s\n", descriptor.path()); + return succeeded; +}*/ + +extern "C" { + void Java_org_telegram_messenger_NativeLoader_init(JNIEnv* env, jobject obj, jstring filepath, bool enable) { + return; + /*if (enable) { + const char *path = env->GetStringUTFChars(filepath, 0); + google_breakpad::MinidumpDescriptor descriptor(path); + exceptionHandler = new google_breakpad::ExceptionHandler(descriptor, NULL, callback, NULL, true, -1); + }*/ + } +} \ No newline at end of file diff --git a/TMessagesProj/jni/TgNetWrapper.cpp b/TMessagesProj/jni/TgNetWrapper.cpp new file mode 100644 index 00000000..decb50bd --- /dev/null +++ b/TMessagesProj/jni/TgNetWrapper.cpp @@ -0,0 +1,336 @@ +#include +#include "tgnet/BuffersStorage.h" +#include "tgnet/NativeByteBuffer.h" +#include "tgnet/ConnectionsManager.h" +#include "tgnet/MTProtoScheme.h" +#include "tgnet/FileLog.h" + +JavaVM *java; +jclass jclass_RequestDelegateInternal; +jmethodID jclass_RequestDelegateInternal_run; + +jclass jclass_QuickAckDelegate; +jmethodID jclass_QuickAckDelegate_run; + +jclass jclass_ConnectionsManager; +jmethodID jclass_ConnectionsManager_onUnparsedMessageReceived; +jmethodID jclass_ConnectionsManager_onUpdate; +jmethodID jclass_ConnectionsManager_onSessionCreated; +jmethodID jclass_ConnectionsManager_onLogout; +jmethodID jclass_ConnectionsManager_onConnectionStateChanged; +jmethodID jclass_ConnectionsManager_onInternalPushReceived; +jmethodID jclass_ConnectionsManager_onUpdateConfig; + +jint getFreeBuffer(JNIEnv *env, jclass c, jint length) { + return (jint) BuffersStorage::getInstance().getFreeBuffer(length); +} + +jint limit(JNIEnv *env, jclass c, jint address) { + NativeByteBuffer *buffer = (NativeByteBuffer *) address; + return buffer->limit(); +} + +jint position(JNIEnv *env, jclass c, jint address) { + NativeByteBuffer *buffer = (NativeByteBuffer *) address; + return buffer->position(); +} + +void reuse(JNIEnv *env, jclass c, jint address) { + NativeByteBuffer *buffer = (NativeByteBuffer *) address; + buffer->reuse(); +} + +jobject getJavaByteBuffer(JNIEnv *env, jclass c, jint address) { + NativeByteBuffer *buffer = (NativeByteBuffer *) address; + return buffer->getJavaByteBuffer(); +} + +static const char *NativeByteBufferClassPathName = "org/telegram/tgnet/NativeByteBuffer"; +static JNINativeMethod NativeByteBufferMethods[] = { + {"native_getFreeBuffer", "(I)I", (void *) getFreeBuffer}, + {"native_limit", "(I)I", (void *) limit}, + {"native_position", "(I)I", (void *) position}, + {"native_reuse", "(I)V", (void *) reuse}, + {"native_getJavaByteBuffer", "(I)Ljava/nio/ByteBuffer;", (void *) getJavaByteBuffer} +}; + +jlong getCurrentTimeMillis(JNIEnv *env, jclass c) { + return ConnectionsManager::getInstance().getCurrentTimeMillis(); +} + +jint getCurrentTime(JNIEnv *env, jclass c) { + return ConnectionsManager::getInstance().getCurrentTime(); +} + +jint getTimeDifference(JNIEnv *env, jclass c) { + return ConnectionsManager::getInstance().getTimeDifference(); +} + +void sendRequest(JNIEnv *env, jclass c, jint object, jobject onComplete, jobject onQuickAck, jint flags, jint datacenterId, jint connetionType, jboolean immediate, jint token) { + TL_api_request *request = new TL_api_request(); + request->request = (NativeByteBuffer *) object; + if (onComplete != nullptr) { + onComplete = env->NewGlobalRef(onComplete); + } + if (onQuickAck != nullptr) { + onQuickAck = env->NewGlobalRef(onQuickAck); + } + ConnectionsManager::getInstance().sendRequest(request, ([onComplete](TLObject *response, TL_error *error) { + TL_api_response *resp = (TL_api_response *) response; + jint ptr = 0; + jint errorCode = 0; + jstring errorText = nullptr; + if (resp != nullptr) { + ptr = (jint) resp->response.get(); + } else if (error != nullptr) { + errorCode = error->code; + errorText = jniEnv->NewStringUTF(error->text.c_str()); + } + if (onComplete != nullptr) { + jniEnv->CallVoidMethod(onComplete, jclass_RequestDelegateInternal_run, ptr, errorCode, errorText); + } + if (errorText != nullptr) { + jniEnv->DeleteLocalRef(errorText); + } + }), ([onQuickAck] { + if (onQuickAck != nullptr) { + jniEnv->CallVoidMethod(onQuickAck, jclass_QuickAckDelegate_run); + } + }), flags, datacenterId, (ConnectionType) connetionType, immediate, token, onComplete, onQuickAck); +} + +void cancelRequest(JNIEnv *env, jclass c, jint token, jboolean notifyServer) { + return ConnectionsManager::getInstance().cancelRequest(token, notifyServer); +} + +void cleanUp(JNIEnv *env, jclass c) { + return ConnectionsManager::getInstance().cleanUp(); +} + +void cancelRequestsForGuid(JNIEnv *env, jclass c, jint guid) { + return ConnectionsManager::getInstance().cancelRequestsForGuid(guid); +} + +void bindRequestToGuid(JNIEnv *env, jclass c, jint requestToken, jint guid) { + return ConnectionsManager::getInstance().bindRequestToGuid(requestToken, guid); +} + +void applyDatacenterAddress(JNIEnv *env, jclass c, jint datacenterId, jstring ipAddress, jint port) { + const char *valueStr = env->GetStringUTFChars(ipAddress, 0); + + ConnectionsManager::getInstance().applyDatacenterAddress(datacenterId, std::string(valueStr), port); + + if (valueStr != 0) { + env->ReleaseStringUTFChars(ipAddress, valueStr); + } +} + +jint getConnectionState(JNIEnv *env, jclass c) { + return ConnectionsManager::getInstance().getConnectionState(); +} + +void setUserId(JNIEnv *env, jclass c, int32_t id) { + ConnectionsManager::getInstance().setUserId(id); +} + +void switchBackend(JNIEnv *env, jclass c) { + ConnectionsManager::getInstance().switchBackend(); +} + +void pauseNetwork(JNIEnv *env, jclass c) { + ConnectionsManager::getInstance().pauseNetwork(); +} + +void resumeNetwork(JNIEnv *env, jclass c, jboolean partial) { + ConnectionsManager::getInstance().resumeNetwork(partial); +} + +void updateDcSettings(JNIEnv *env, jclass c) { + ConnectionsManager::getInstance().updateDcSettings(0); +} + +void setUseIpv6(JNIEnv *env, jclass c, bool value) { + ConnectionsManager::getInstance().setUseIpv6(value); +} + +void setNetworkAvailable(JNIEnv *env, jclass c, jboolean value) { + ConnectionsManager::getInstance().setNetworkAvailable(value); +} + +void setPushConnectionEnabled(JNIEnv *env, jclass c, jboolean value) { + ConnectionsManager::getInstance().setPushConnectionEnabled(value); +} + +class Delegate : public ConnectiosManagerDelegate { + + void onUpdate() { + jniEnv->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onUpdate); + } + + void onSessionCreated() { + jniEnv->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onSessionCreated); + } + + void onConnectionStateChanged(ConnectionState state) { + jniEnv->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onConnectionStateChanged, state); + } + + void onUnparsedMessageReceived(int64_t reqMessageId, NativeByteBuffer *buffer, ConnectionType connectionType) { + if (connectionType == ConnectionTypeGeneric) { + jniEnv->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onUnparsedMessageReceived, buffer); + } + } + + void onLogout() { + jniEnv->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onLogout); + } + + void onUpdateConfig(TL_config *config) { + NativeByteBuffer *buffer = BuffersStorage::getInstance().getFreeBuffer(config->getObjectSize()); + config->serializeToStream(buffer); + buffer->position(0); + jniEnv->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onUpdateConfig, buffer); + buffer->reuse(); + } + + void onInternalPushReceived() { + jniEnv->CallStaticVoidMethod(jclass_ConnectionsManager, jclass_ConnectionsManager_onInternalPushReceived); + } +}; + +void init(JNIEnv *env, jclass c, jint version, jint layer, jint apiId, jstring deviceModel, jstring systemVersion, jstring appVersion, jstring langCode, jstring configPath, jstring logPath, jint userId, jboolean enablePushConnection) { + const char *deviceModelStr = env->GetStringUTFChars(deviceModel, 0); + const char *systemVersionStr = env->GetStringUTFChars(systemVersion, 0); + const char *appVersionStr = env->GetStringUTFChars(appVersion, 0); + const char *langCodeStr = env->GetStringUTFChars(langCode, 0); + const char *configPathStr = env->GetStringUTFChars(configPath, 0); + const char *logPathStr = env->GetStringUTFChars(logPath, 0); + + ConnectionsManager::getInstance().init(version, layer, apiId, std::string(deviceModelStr), std::string(systemVersionStr), std::string(appVersionStr), std::string(langCodeStr), std::string(configPathStr), std::string(logPathStr), userId, true, enablePushConnection); + + if (deviceModelStr != 0) { + env->ReleaseStringUTFChars(deviceModel, deviceModelStr); + } + if (systemVersionStr != 0) { + env->ReleaseStringUTFChars(systemVersion, systemVersionStr); + } + if (appVersionStr != 0) { + env->ReleaseStringUTFChars(appVersion, appVersionStr); + } + if (langCodeStr != 0) { + env->ReleaseStringUTFChars(langCode, langCodeStr); + } + if (configPathStr != 0) { + env->ReleaseStringUTFChars(configPath, configPathStr); + } + if (logPathStr != 0) { + env->ReleaseStringUTFChars(logPath, logPathStr); + } +} + +void setJava(JNIEnv *env, jclass c, jboolean useJavaByteBuffers) { + ConnectionsManager::useJavaVM(java, useJavaByteBuffers); + ConnectionsManager::getInstance().setDelegate(new Delegate()); +} + +static const char *ConnectionsManagerClassPathName = "org/telegram/tgnet/ConnectionsManager"; +static JNINativeMethod ConnectionsManagerMethods[] = { + {"native_getCurrentTimeMillis", "()J", (void *) getCurrentTimeMillis}, + {"native_getCurrentTime", "()I", (void *) getCurrentTime}, + {"native_getTimeDifference", "()I", (void *) getTimeDifference}, + {"native_sendRequest", "(ILorg/telegram/tgnet/RequestDelegateInternal;Lorg/telegram/tgnet/QuickAckDelegate;IIIZI)V", (void *) sendRequest}, + {"native_cancelRequest", "(IZ)V", (void *) cancelRequest}, + {"native_cleanUp", "()V", (void *) cleanUp}, + {"native_cancelRequestsForGuid", "(I)V", (void *) cancelRequestsForGuid}, + {"native_bindRequestToGuid", "(II)V", (void *) bindRequestToGuid}, + {"native_applyDatacenterAddress", "(ILjava/lang/String;I)V", (void *) applyDatacenterAddress}, + {"native_getConnectionState", "()I", (void *) getConnectionState}, + {"native_setUserId", "(I)V", (void *) setUserId}, + {"native_init", "(IIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZ)V", (void *) init}, + {"native_switchBackend", "()V", (void *) switchBackend}, + {"native_pauseNetwork", "()V", (void *) pauseNetwork}, + {"native_resumeNetwork", "(Z)V", (void *) resumeNetwork}, + {"native_updateDcSettings", "()V", (void *) updateDcSettings}, + {"native_setUseIpv6", "(Z)V", (void *) setUseIpv6}, + {"native_setNetworkAvailable", "(Z)V", (void *) setNetworkAvailable}, + {"native_setPushConnectionEnabled", "(Z)V", (void *) setPushConnectionEnabled}, + {"native_setJava", "(Z)V", (void *) setJava} +}; + +inline int registerNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int methodsCount) { + jclass clazz; + clazz = env->FindClass(className); + if (clazz == NULL) { + return JNI_FALSE; + } + if (env->RegisterNatives(clazz, methods, methodsCount) < 0) { + return JNI_FALSE; + } + return JNI_TRUE; +} + +extern "C" int registerNativeTgNetFunctions(JavaVM *vm, JNIEnv *env) { + java = vm; + + if (!registerNativeMethods(env, NativeByteBufferClassPathName, NativeByteBufferMethods, sizeof(NativeByteBufferMethods) / sizeof(NativeByteBufferMethods[0]))) { + return JNI_FALSE; + } + + if (!registerNativeMethods(env, ConnectionsManagerClassPathName, ConnectionsManagerMethods, sizeof(ConnectionsManagerMethods) / sizeof(ConnectionsManagerMethods[0]))) { + return JNI_FALSE; + } + + jclass_RequestDelegateInternal = (jclass) env->NewGlobalRef(env->FindClass("org/telegram/tgnet/RequestDelegateInternal")); + if (jclass_RequestDelegateInternal == 0) { + return JNI_FALSE; + } + jclass_RequestDelegateInternal_run = env->GetMethodID(jclass_RequestDelegateInternal, "run", "(IILjava/lang/String;)V"); + if (jclass_RequestDelegateInternal_run == 0) { + return JNI_FALSE; + } + + jclass_QuickAckDelegate = (jclass) env->NewGlobalRef(env->FindClass("org/telegram/tgnet/QuickAckDelegate")); + if (jclass_RequestDelegateInternal == 0) { + return JNI_FALSE; + } + jclass_QuickAckDelegate_run = env->GetMethodID(jclass_QuickAckDelegate, "run", "()V"); + if (jclass_QuickAckDelegate_run == 0) { + return JNI_FALSE; + } + + jclass_ConnectionsManager = (jclass) env->NewGlobalRef(env->FindClass("org/telegram/tgnet/ConnectionsManager")); + if (jclass_ConnectionsManager == 0) { + return JNI_FALSE; + } + jclass_ConnectionsManager_onUnparsedMessageReceived = env->GetStaticMethodID(jclass_ConnectionsManager, "onUnparsedMessageReceived", "(I)V"); + if (jclass_ConnectionsManager_onUnparsedMessageReceived == 0) { + return JNI_FALSE; + } + jclass_ConnectionsManager_onUpdate = env->GetStaticMethodID(jclass_ConnectionsManager, "onUpdate", "()V"); + if (jclass_ConnectionsManager_onUpdate == 0) { + return JNI_FALSE; + } + jclass_ConnectionsManager_onSessionCreated = env->GetStaticMethodID(jclass_ConnectionsManager, "onSessionCreated", "()V"); + if (jclass_ConnectionsManager_onSessionCreated == 0) { + return JNI_FALSE; + } + jclass_ConnectionsManager_onLogout = env->GetStaticMethodID(jclass_ConnectionsManager, "onLogout", "()V"); + if (jclass_ConnectionsManager_onLogout == 0) { + return JNI_FALSE; + } + jclass_ConnectionsManager_onConnectionStateChanged = env->GetStaticMethodID(jclass_ConnectionsManager, "onConnectionStateChanged", "(I)V"); + if (jclass_ConnectionsManager_onConnectionStateChanged == 0) { + return JNI_FALSE; + } + jclass_ConnectionsManager_onInternalPushReceived = env->GetStaticMethodID(jclass_ConnectionsManager, "onInternalPushReceived", "()V"); + if (jclass_ConnectionsManager_onInternalPushReceived == 0) { + return JNI_FALSE; + } + jclass_ConnectionsManager_onUpdateConfig = env->GetStaticMethodID(jclass_ConnectionsManager, "onUpdateConfig", "(I)V"); + if (jclass_ConnectionsManager_onUpdateConfig == 0) { + return JNI_FALSE; + } + ConnectionsManager::getInstance().setDelegate(new Delegate()); + + return JNI_TRUE; +} diff --git a/TMessagesProj/jni/audio.c b/TMessagesProj/jni/audio.c index 70b6e2fc..c6fd3650 100644 --- a/TMessagesProj/jni/audio.c +++ b/TMessagesProj/jni/audio.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "utils.h" typedef struct { @@ -663,6 +664,155 @@ JNIEXPORT int Java_org_telegram_messenger_MediaController_isOpusFile(JNIEnv *env result = error == OPUS_OK; } + if (pathStr != 0) { + (*env)->ReleaseStringUTFChars(env, path, pathStr); + } + + return result; +} + +static inline void set_bits(uint8_t *bytes, int32_t bitOffset, int32_t value) { + bytes += bitOffset / 8; + bitOffset %= 8; + *((int32_t *) bytes) |= (value << bitOffset); +} + +JNIEXPORT jbyteArray Java_org_telegram_messenger_MediaController_getWaveform2(JNIEnv *env, jclass class, jshortArray array, jint length) { + + jshort *sampleBuffer = (*env)->GetShortArrayElements(env, array, 0); + + jbyteArray result = 0; + int32_t resultSamples = 100; + uint16_t *samples = malloc(100 * 2); + uint64_t sampleIndex = 0; + uint16_t peakSample = 0; + int32_t sampleRate = (int32_t) max(1, length / resultSamples); + int index = 0; + + for (int i = 0; i < length; i++) { + uint16_t sample = (uint16_t) abs(sampleBuffer[i]); + if (sample > peakSample) { + peakSample = sample; + } + if (sampleIndex++ % sampleRate == 0) { + if (index < resultSamples) { + samples[index++] = peakSample; + } + peakSample = 0; + } + } + + int64_t sumSamples = 0; + for (int i = 0; i < resultSamples; i++) { + sumSamples += samples[i]; + } + uint16_t peak = (uint16_t) (sumSamples * 1.8f / resultSamples); + if (peak < 2500) { + peak = 2500; + } + + for (int i = 0; i < resultSamples; i++) { + uint16_t sample = (uint16_t) ((int64_t) samples[i]); + if (sample > peak) { + samples[i] = peak; + } + } + + (*env)->ReleaseShortArrayElements(env, array, sampleBuffer, 0); + + int bitstreamLength = (resultSamples * 5) / 8 + (((resultSamples * 5) % 8) == 0 ? 0 : 1); + result = (*env)->NewByteArray(env, bitstreamLength); + jbyte *bytes = (*env)->GetByteArrayElements(env, result, NULL); + + for (int i = 0; i < resultSamples; i++) { + int32_t value = min(31, abs((int32_t) samples[i]) * 31 / peak); + set_bits(bytes, i * 5, value & 31); + } + + (*env)->ReleaseByteArrayElements(env, result, bytes, JNI_COMMIT); + free(samples); + + return result; +} + +int16_t *sampleBuffer = NULL; + + +JNIEXPORT jbyteArray Java_org_telegram_messenger_MediaController_getWaveform(JNIEnv *env, jclass class, jstring path) { + const char *pathStr = (*env)->GetStringUTFChars(env, path, 0); + jbyteArray result = 0; + + int error = OPUS_OK; + OggOpusFile *opusFile = op_open_file(pathStr, &error); + if (opusFile != NULL && error == OPUS_OK) { + int64_t totalSamples = op_pcm_total(opusFile, -1); + int32_t resultSamples = 100; + int32_t sampleRate = (int32_t) max(1, totalSamples / resultSamples); + + uint16_t *samples = malloc(100 * 2); + + int bufferSize = 1024 * 128; + if (sampleBuffer == NULL) { + sampleBuffer = malloc(bufferSize); + } + uint64_t sampleIndex = 0; + uint16_t peakSample = 0; + + int index = 0; + + while (1) { + int readSamples = op_read(opusFile, sampleBuffer, bufferSize / 2, NULL); + for (int i = 0; i < readSamples; i++) { + uint16_t sample = (uint16_t) abs(sampleBuffer[i]); + if (sample > peakSample) { + peakSample = sample; + } + if (sampleIndex++ % sampleRate == 0) { + if (index < resultSamples) { + samples[index++] = peakSample; + } + peakSample = 0; + } + } + if (readSamples == 0) { + break; + } + } + + int64_t sumSamples = 0; + for (int i = 0; i < resultSamples; i++) { + sumSamples += samples[i]; + } + uint16_t peak = (uint16_t) (sumSamples * 1.8f / resultSamples); + if (peak < 2500) { + peak = 2500; + } + + for (int i = 0; i < resultSamples; i++) { + uint16_t sample = (uint16_t) ((int64_t) samples[i]); + if (sample > peak) { + samples[i] = peak; + } + } + + //free(sampleBuffer); + op_free(opusFile); + + int bitstreamLength = (resultSamples * 5) / 8 + (((resultSamples * 5) % 8) == 0 ? 0 : 1); + result = (*env)->NewByteArray(env, bitstreamLength); + jbyte *bytes = (*env)->GetByteArrayElements(env, result, NULL); + + for (int i = 0; i < resultSamples; i++) { + int32_t value = min(31, abs((int32_t) samples[i]) * 31 / peak); + set_bits(bytes, i * 5, value & 31); + } + + (*env)->ReleaseByteArrayElements(env, result, bytes, JNI_COMMIT); + free(samples); + } + + + if (pathStr != 0) { (*env)->ReleaseStringUTFChars(env, path, pathStr); } diff --git a/TMessagesProj/jni/boringssl/LICENSE b/TMessagesProj/jni/boringssl/LICENSE new file mode 100644 index 00000000..b242dcb1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/LICENSE @@ -0,0 +1,185 @@ +BoringSSL is a fork of OpenSSL. As such, large parts of it fall under OpenSSL +licensing. Files that are completely new have a Google copyright and an ISC +license. This license is reproduced at the bottom of this file. + +Contributors to BoringSSL are required to follow the CLA rules for Chromium: +https://cla.developers.google.com/clas + +Some files from Intel are under yet another license, which is also included +underneath. + +The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the +OpenSSL License and the original SSLeay license apply to the toolkit. See below +for the actual license texts. Actually both licenses are BSD-style Open Source +licenses. In case of any license issues related to OpenSSL please contact +openssl-core@openssl.org. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2011 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + + +ISC license used for completely new code in BoringSSL: + +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + + +Some files from Intel carry the following license: + +# Copyright (c) 2012, Intel Corporation +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * 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. +# +# * Neither the name of the Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# +# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY +# EXPRESS 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 INTEL CORPORATION OR +# 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. diff --git a/TMessagesProj/jni/boringssl/README.MD b/TMessagesProj/jni/boringssl/README.MD new file mode 100644 index 00000000..b777c016 --- /dev/null +++ b/TMessagesProj/jni/boringssl/README.MD @@ -0,0 +1,10 @@ +cmake, ninja, go are required + +cmake -DANDROID_NATIVE_API_LEVEL=android-8 \ + -DANDROID_ABI=x86 \ + -DCMAKE_BUILD_TYPE=Release \ + -DANDROID_NDK=/Applications/sdk/ndk-bundle/ \ + -DCMAKE_TOOLCHAIN_FILE=../util/android-cmake/android.toolchain.cmake \ + -DANDROID_NATIVE_API_LEVEL=16 \ + -GNinja .. +cmake --build . \ No newline at end of file diff --git a/TMessagesProj/jni/boringssl/crypto/.gitignore b/TMessagesProj/jni/boringssl/crypto/.gitignore new file mode 100644 index 00000000..08633432 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/.gitignore @@ -0,0 +1 @@ +*.txt~ diff --git a/TMessagesProj/jni/boringssl/crypto/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/CMakeLists.txt new file mode 100644 index 00000000..bfde57a3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/CMakeLists.txt @@ -0,0 +1,197 @@ +include_directories(. ../include) + +if(APPLE) + if (${ARCH} STREQUAL "x86") + set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2") + endif() + set(PERLASM_STYLE macosx) + set(ASM_EXT S) + enable_language(ASM) +elseif(UNIX) + if (${ARCH} STREQUAL "aarch64") + # The "armx" Perl scripts look for "64" in the style argument + # in order to decide whether to generate 32- or 64-bit asm. + set(PERLASM_STYLE linux64) + elseif (${ARCH} STREQUAL "arm") + set(PERLASM_STYLE linux32) + elseif (${ARCH} STREQUAL "x86") + set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2") + set(PERLASM_STYLE elf) + else() + set(PERLASM_STYLE elf) + endif() + set(ASM_EXT S) + enable_language(ASM) +else() + if (CMAKE_CL_64) + message("Using nasm") + set(PERLASM_STYLE nasm) + else() + message("Using win32n") + set(PERLASM_STYLE win32n) + set(PERLASM_FLAGS "-DOPENSSL_IA32_SSE2") + endif() + + # On Windows, we use the NASM output, specifically built with Yasm. + set(ASM_EXT asm) + enable_language(ASM_NASM) +endif() + +function(perlasm dest src) + add_custom_command( + OUTPUT ${dest} + COMMAND ${PERL_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/${src} ${PERLASM_STYLE} ${PERLASM_FLAGS} ${ARGN} > ${dest} + DEPENDS + ${src} + ${PROJECT_SOURCE_DIR}/crypto/perlasm/arm-xlate.pl + ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86_64-xlate.pl + ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl + ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86gas.pl + ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86masm.pl + ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86nasm.pl + WORKING_DIRECTORY . + ) +endfunction() + +if (${ARCH} STREQUAL "x86_64") + set( + CRYPTO_ARCH_SOURCES + + cpu-intel.c + ) +endif() + +if (${ARCH} STREQUAL "x86") + set( + CRYPTO_ARCH_SOURCES + + cpu-intel.c + ) +endif() + +if (${ARCH} STREQUAL "arm") + set( + CRYPTO_ARCH_SOURCES + + cpu-arm.c + cpu-arm-asm.S + ) +endif() + +if (${ARCH} STREQUAL "aarch64") + set( + CRYPTO_ARCH_SOURCES + + cpu-arm.c + ) +endif() + +# Level 0.1 - depends on nothing outside this set. +add_subdirectory(stack) +add_subdirectory(lhash) +add_subdirectory(err) +add_subdirectory(buf) +add_subdirectory(base64) +add_subdirectory(bytestring) + +# Level 0.2 - depends on nothing but itself +add_subdirectory(sha) +add_subdirectory(md5) +add_subdirectory(modes) +add_subdirectory(aes) +add_subdirectory(des) +add_subdirectory(rc4) +add_subdirectory(conf) +add_subdirectory(chacha) +add_subdirectory(poly1305) + +# Level 1, depends only on 0.* +add_subdirectory(digest) +add_subdirectory(cipher) +add_subdirectory(rand) +add_subdirectory(bio) +add_subdirectory(bn) +add_subdirectory(obj) +add_subdirectory(asn1) + +# Level 2 +add_subdirectory(engine) +add_subdirectory(dh) +add_subdirectory(dsa) +add_subdirectory(rsa) +add_subdirectory(ec) +add_subdirectory(ecdh) +add_subdirectory(ecdsa) +add_subdirectory(hmac) + +# Level 3 +add_subdirectory(cmac) +add_subdirectory(evp) +add_subdirectory(hkdf) +add_subdirectory(pem) +add_subdirectory(x509) +add_subdirectory(x509v3) + +# Level 4 +add_subdirectory(pkcs8) + +add_library( + crypto + + crypto.c + directory_posix.c + directory_win.c + ex_data.c + mem.c + refcount_c11.c + refcount_lock.c + thread.c + thread_none.c + thread_pthread.c + thread_win.c + time_support.c + + ${CRYPTO_ARCH_SOURCES} + + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ +) + +if(NOT MSVC AND NOT ANDROID) + target_link_libraries(crypto pthread) +endif() diff --git a/TMessagesProj/jni/boringssl/crypto/aes/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/aes/CMakeLists.txt new file mode 100644 index 00000000..985af113 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/CMakeLists.txt @@ -0,0 +1,63 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "x86_64") + set( + AES_ARCH_SOURCES + + aes-x86_64.${ASM_EXT} + aesni-x86_64.${ASM_EXT} + bsaes-x86_64.${ASM_EXT} + vpaes-x86_64.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "x86") + set( + AES_ARCH_SOURCES + + aes-586.${ASM_EXT} + vpaes-x86.${ASM_EXT} + aesni-x86.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "arm") + set( + AES_ARCH_SOURCES + + aes-armv4.${ASM_EXT} + bsaes-armv7.${ASM_EXT} + aesv8-armx.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "aarch64") + set( + AES_ARCH_SOURCES + + aesv8-armx.${ASM_EXT} + ) +endif() + +add_library( + aes + + OBJECT + + aes.c + aes_ige.c + mode_wrappers.c + + ${AES_ARCH_SOURCES} +) + +perlasm(aes-x86_64.${ASM_EXT} asm/aes-x86_64.pl) +perlasm(aesni-x86_64.${ASM_EXT} asm/aesni-x86_64.pl) +perlasm(bsaes-x86_64.${ASM_EXT} asm/bsaes-x86_64.pl) +perlasm(vpaes-x86_64.${ASM_EXT} asm/vpaes-x86_64.pl) +perlasm(aes-586.${ASM_EXT} asm/aes-586.pl) +perlasm(vpaes-x86.${ASM_EXT} asm/vpaes-x86.pl) +perlasm(aesni-x86.${ASM_EXT} asm/aesni-x86.pl) +perlasm(aes-armv4.${ASM_EXT} asm/aes-armv4.pl) +perlasm(bsaes-armv7.${ASM_EXT} asm/bsaes-armv7.pl) +perlasm(aesv8-armx.${ASM_EXT} asm/aesv8-armx.pl) diff --git a/TMessagesProj/jni/boringssl/crypto/aes/aes.c b/TMessagesProj/jni/boringssl/crypto/aes/aes.c new file mode 100644 index 00000000..933aa073 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/aes.c @@ -0,0 +1,1085 @@ +/* ==================================================================== + * Copyright (c) 2002-2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== */ + +#include + +#include + +#include "internal.h" + + +#if defined(OPENSSL_NO_ASM) || \ + (!defined(OPENSSL_X86) && !defined(OPENSSL_X86_64) && !defined(OPENSSL_ARM)) + +/* Te0[x] = S [x].[02, 01, 01, 03]; + * Te1[x] = S [x].[03, 02, 01, 01]; + * Te2[x] = S [x].[01, 03, 02, 01]; + * Te3[x] = S [x].[01, 01, 03, 02]; + * + * Td0[x] = Si[x].[0e, 09, 0d, 0b]; + * Td1[x] = Si[x].[0b, 0e, 09, 0d]; + * Td2[x] = Si[x].[0d, 0b, 0e, 09]; + * Td3[x] = Si[x].[09, 0d, 0b, 0e]; + * Td4[x] = Si[x].[01]; */ + +static const uint32_t Te0[256] = { + 0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU, 0xfff2f20dU, + 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U, 0x60303050U, 0x02010103U, + 0xce6767a9U, 0x562b2b7dU, 0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, + 0xec76769aU, 0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U, + 0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU, 0x41adadecU, + 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU, 0x239c9cbfU, 0x53a4a4f7U, + 0xe4727296U, 0x9bc0c05bU, 0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, + 0x4c26266aU, 0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU, + 0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U, 0xe2717193U, + 0xabd8d873U, 0x62313153U, 0x2a15153fU, 0x0804040cU, 0x95c7c752U, + 0x46232365U, 0x9dc3c35eU, 0x30181828U, 0x379696a1U, 0x0a05050fU, + 0x2f9a9ab5U, 0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU, + 0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU, 0x1209091bU, + 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU, 0x361b1b2dU, 0xdc6e6eb2U, + 0xb45a5aeeU, 0x5ba0a0fbU, 0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, + 0x7db3b3ceU, 0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U, + 0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU, 0x40202060U, + 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU, 0xd46a6abeU, 0x8dcbcb46U, + 0x67bebed9U, 0x7239394bU, 0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, + 0x85cfcf4aU, 0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U, + 0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U, 0x8a4545cfU, + 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U, 0xa05050f0U, 0x783c3c44U, + 0x259f9fbaU, 0x4ba8a8e3U, 0xa25151f3U, 0x5da3a3feU, 0x804040c0U, + 0x058f8f8aU, 0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U, + 0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U, 0x20101030U, + 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU, 0x81cdcd4cU, 0x180c0c14U, + 0x26131335U, 0xc3ecec2fU, 0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, + 0x2e171739U, 0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U, + 0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U, 0xc06060a0U, + 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU, 0x44222266U, 0x542a2a7eU, + 0x3b9090abU, 0x0b888883U, 0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, + 0x2814143cU, 0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U, + 0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU, 0x924949dbU, + 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U, 0x9fc2c25dU, 0xbdd3d36eU, + 0x43acacefU, 0xc46262a6U, 0x399191a8U, 0x319595a4U, 0xd3e4e437U, + 0xf279798bU, 0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U, + 0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U, 0xd86c6cb4U, + 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U, 0xca6565afU, 0xf47a7a8eU, + 0x47aeaee9U, 0x10080818U, 0x6fbabad5U, 0xf0787888U, 0x4a25256fU, + 0x5c2e2e72U, 0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U, + 0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U, 0x964b4bddU, + 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U, 0xe0707090U, 0x7c3e3e42U, + 0x71b5b5c4U, 0xcc6666aaU, 0x904848d8U, 0x06030305U, 0xf7f6f601U, + 0x1c0e0e12U, 0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U, + 0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U, 0xd9e1e138U, + 0xebf8f813U, 0x2b9898b3U, 0x22111133U, 0xd26969bbU, 0xa9d9d970U, + 0x078e8e89U, 0x339494a7U, 0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, + 0xc9e9e920U, 0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU, + 0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U, 0x65bfbfdaU, + 0xd7e6e631U, 0x844242c6U, 0xd06868b8U, 0x824141c3U, 0x299999b0U, + 0x5a2d2d77U, 0x1e0f0f11U, 0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, + 0x2c16163aU, }; + +static const uint32_t Te1[256] = { + 0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU, 0x0dfff2f2U, + 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U, 0x50603030U, 0x03020101U, + 0xa9ce6767U, 0x7d562b2bU, 0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, + 0x9aec7676U, 0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU, + 0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U, 0xec41adadU, + 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU, 0xbf239c9cU, 0xf753a4a4U, + 0x96e47272U, 0x5b9bc0c0U, 0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, + 0x6a4c2626U, 0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU, + 0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U, 0x93e27171U, + 0x73abd8d8U, 0x53623131U, 0x3f2a1515U, 0x0c080404U, 0x5295c7c7U, + 0x65462323U, 0x5e9dc3c3U, 0x28301818U, 0xa1379696U, 0x0f0a0505U, + 0xb52f9a9aU, 0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U, + 0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U, 0x1b120909U, + 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU, 0x2d361b1bU, 0xb2dc6e6eU, + 0xeeb45a5aU, 0xfb5ba0a0U, 0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, + 0xce7db3b3U, 0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U, + 0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU, 0x60402020U, + 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU, 0xbed46a6aU, 0x468dcbcbU, + 0xd967bebeU, 0x4b723939U, 0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, + 0x4a85cfcfU, 0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU, + 0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U, 0xcf8a4545U, + 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU, 0xf0a05050U, 0x44783c3cU, + 0xba259f9fU, 0xe34ba8a8U, 0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, + 0x8a058f8fU, 0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U, + 0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U, 0x30201010U, + 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U, 0x4c81cdcdU, 0x14180c0cU, + 0x35261313U, 0x2fc3ececU, 0xe1be5f5fU, 0xa2359797U, 0xcc884444U, + 0x392e1717U, 0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU, + 0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U, 0xa0c06060U, + 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU, 0x66442222U, 0x7e542a2aU, + 0xab3b9090U, 0x830b8888U, 0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, + 0x3c281414U, 0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU, + 0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU, 0xdb924949U, + 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU, 0x5d9fc2c2U, 0x6ebdd3d3U, + 0xef43acacU, 0xa6c46262U, 0xa8399191U, 0xa4319595U, 0x37d3e4e4U, + 0x8bf27979U, 0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU, + 0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U, 0xb4d86c6cU, + 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU, 0xafca6565U, 0x8ef47a7aU, + 0xe947aeaeU, 0x18100808U, 0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, + 0x725c2e2eU, 0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U, + 0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU, 0xdd964b4bU, + 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU, 0x90e07070U, 0x427c3e3eU, + 0xc471b5b5U, 0xaacc6666U, 0xd8904848U, 0x05060303U, 0x01f7f6f6U, + 0x121c0e0eU, 0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U, + 0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU, 0x38d9e1e1U, + 0x13ebf8f8U, 0xb32b9898U, 0x33221111U, 0xbbd26969U, 0x70a9d9d9U, + 0x89078e8eU, 0xa7339494U, 0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, + 0x20c9e9e9U, 0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU, + 0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU, 0xda65bfbfU, + 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U, 0xc3824141U, 0xb0299999U, + 0x775a2d2dU, 0x111e0f0fU, 0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, + 0x3a2c1616U, }; + +static const uint32_t Te2[256] = { + 0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU, 0xf20dfff2U, + 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U, 0x30506030U, 0x01030201U, + 0x67a9ce67U, 0x2b7d562bU, 0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, + 0x769aec76U, 0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU, + 0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U, 0xadec41adU, + 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU, 0x9cbf239cU, 0xa4f753a4U, + 0x7296e472U, 0xc05b9bc0U, 0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, + 0x266a4c26U, 0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU, + 0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U, 0x7193e271U, + 0xd873abd8U, 0x31536231U, 0x153f2a15U, 0x040c0804U, 0xc75295c7U, + 0x23654623U, 0xc35e9dc3U, 0x18283018U, 0x96a13796U, 0x050f0a05U, + 0x9ab52f9aU, 0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U, + 0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U, 0x091b1209U, + 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU, 0x1b2d361bU, 0x6eb2dc6eU, + 0x5aeeb45aU, 0xa0fb5ba0U, 0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, + 0xb3ce7db3U, 0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U, + 0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU, 0x20604020U, + 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU, 0x6abed46aU, 0xcb468dcbU, + 0xbed967beU, 0x394b7239U, 0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, + 0xcf4a85cfU, 0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU, + 0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U, 0x45cf8a45U, + 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU, 0x50f0a050U, 0x3c44783cU, + 0x9fba259fU, 0xa8e34ba8U, 0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, + 0x8f8a058fU, 0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U, + 0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U, 0x10302010U, + 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U, 0xcd4c81cdU, 0x0c14180cU, + 0x13352613U, 0xec2fc3ecU, 0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, + 0x17392e17U, 0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU, + 0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U, 0x60a0c060U, + 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU, 0x22664422U, 0x2a7e542aU, + 0x90ab3b90U, 0x88830b88U, 0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, + 0x143c2814U, 0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU, + 0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU, 0x49db9249U, + 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU, 0xc25d9fc2U, 0xd36ebdd3U, + 0xacef43acU, 0x62a6c462U, 0x91a83991U, 0x95a43195U, 0xe437d3e4U, + 0x798bf279U, 0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU, + 0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U, 0x6cb4d86cU, + 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU, 0x65afca65U, 0x7a8ef47aU, + 0xaee947aeU, 0x08181008U, 0xbad56fbaU, 0x7888f078U, 0x256f4a25U, + 0x2e725c2eU, 0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U, + 0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU, 0x4bdd964bU, + 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU, 0x7090e070U, 0x3e427c3eU, + 0xb5c471b5U, 0x66aacc66U, 0x48d89048U, 0x03050603U, 0xf601f7f6U, + 0x0e121c0eU, 0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U, + 0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU, 0xe138d9e1U, + 0xf813ebf8U, 0x98b32b98U, 0x11332211U, 0x69bbd269U, 0xd970a9d9U, + 0x8e89078eU, 0x94a73394U, 0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, + 0xe920c9e9U, 0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU, + 0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU, 0xbfda65bfU, + 0xe631d7e6U, 0x42c68442U, 0x68b8d068U, 0x41c38241U, 0x99b02999U, + 0x2d775a2dU, 0x0f111e0fU, 0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, + 0x163a2c16U, }; + +static const uint32_t Te3[256] = { + 0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U, 0xf2f20dffU, + 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U, 0x30305060U, 0x01010302U, + 0x6767a9ceU, 0x2b2b7d56U, 0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, + 0x76769aecU, 0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU, + 0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU, 0xadadec41U, + 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U, 0x9c9cbf23U, 0xa4a4f753U, + 0x727296e4U, 0xc0c05b9bU, 0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, + 0x26266a4cU, 0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U, + 0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U, 0x717193e2U, + 0xd8d873abU, 0x31315362U, 0x15153f2aU, 0x04040c08U, 0xc7c75295U, + 0x23236546U, 0xc3c35e9dU, 0x18182830U, 0x9696a137U, 0x05050f0aU, + 0x9a9ab52fU, 0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU, + 0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU, 0x09091b12U, + 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U, 0x1b1b2d36U, 0x6e6eb2dcU, + 0x5a5aeeb4U, 0xa0a0fb5bU, 0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, + 0xb3b3ce7dU, 0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U, + 0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U, 0x20206040U, + 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U, 0x6a6abed4U, 0xcbcb468dU, + 0xbebed967U, 0x39394b72U, 0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, + 0xcfcf4a85U, 0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU, + 0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U, 0x4545cf8aU, + 0xf9f910e9U, 0x02020604U, 0x7f7f81feU, 0x5050f0a0U, 0x3c3c4478U, + 0x9f9fba25U, 0xa8a8e34bU, 0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, + 0x8f8f8a05U, 0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U, + 0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U, 0x10103020U, + 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU, 0xcdcd4c81U, 0x0c0c1418U, + 0x13133526U, 0xecec2fc3U, 0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, + 0x1717392eU, 0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU, + 0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U, 0x6060a0c0U, + 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U, 0x22226644U, 0x2a2a7e54U, + 0x9090ab3bU, 0x8888830bU, 0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, + 0x14143c28U, 0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU, + 0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U, 0x4949db92U, + 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U, 0xc2c25d9fU, 0xd3d36ebdU, + 0xacacef43U, 0x6262a6c4U, 0x9191a839U, 0x9595a431U, 0xe4e437d3U, + 0x79798bf2U, 0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU, + 0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U, 0x6c6cb4d8U, + 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU, 0x6565afcaU, 0x7a7a8ef4U, + 0xaeaee947U, 0x08081810U, 0xbabad56fU, 0x787888f0U, 0x25256f4aU, + 0x2e2e725cU, 0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U, + 0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU, 0x4b4bdd96U, + 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU, 0x707090e0U, 0x3e3e427cU, + 0xb5b5c471U, 0x6666aaccU, 0x4848d890U, 0x03030506U, 0xf6f601f7U, + 0x0e0e121cU, 0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U, + 0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U, 0xe1e138d9U, + 0xf8f813ebU, 0x9898b32bU, 0x11113322U, 0x6969bbd2U, 0xd9d970a9U, + 0x8e8e8907U, 0x9494a733U, 0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, + 0xe9e920c9U, 0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U, + 0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU, 0xbfbfda65U, + 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U, 0x4141c382U, 0x9999b029U, + 0x2d2d775aU, 0x0f0f111eU, 0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, + 0x16163a2cU, }; + +static const uint32_t Td0[256] = { + 0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U, 0x3bab6bcbU, + 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U, 0x2030fa55U, 0xad766df6U, + 0x88cc7691U, 0xf5024c25U, 0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, + 0xb562a38fU, 0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U, + 0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U, 0x038f5fe7U, + 0x15929c95U, 0xbf6d7aebU, 0x955259daU, 0xd4be832dU, 0x587421d3U, + 0x49e06929U, 0x8ec9c844U, 0x75c2896aU, 0xf48e7978U, 0x99583e6bU, + 0x27b971ddU, 0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U, + 0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U, 0xb16477e0U, + 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U, 0x70486858U, 0x8f45fd19U, + 0x94de6c87U, 0x527bf8b7U, 0xab73d323U, 0x724b02e2U, 0xe31f8f57U, + 0x6655ab2aU, 0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U, + 0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU, 0x8acf1c2bU, + 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U, 0x65daf4cdU, 0x0605bed5U, + 0xd134621fU, 0xc4a6fe8aU, 0x342e539dU, 0xa2f355a0U, 0x058ae132U, + 0xa4f6eb75U, 0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U, + 0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U, 0x91548db5U, + 0x71c45d05U, 0x0406d46fU, 0x605015ffU, 0x1998fb24U, 0xd6bde997U, + 0x894043ccU, 0x67d99e77U, 0xb0e842bdU, 0x07898b88U, 0xe7195b38U, + 0x79c8eedbU, 0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U, + 0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU, 0xfd0efffbU, + 0x0f853856U, 0x3daed51eU, 0x362d3927U, 0x0a0fd964U, 0x685ca621U, + 0x9b5b54d1U, 0x24362e3aU, 0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, + 0x1b9b919eU, 0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U, + 0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU, 0x0e090d0bU, + 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U, 0x57f11985U, 0xaf75074cU, + 0xee99ddbbU, 0xa37f60fdU, 0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, + 0x5bfb7e34U, 0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U, + 0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U, 0x854a247dU, + 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU, 0x1d9e2f4bU, 0xdcb230f3U, + 0x0d8652ecU, 0x77c1e3d0U, 0x2bb3166cU, 0xa970b999U, 0x119448faU, + 0x47e96422U, 0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU, + 0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U, 0xa6f581cfU, + 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U, 0x2c3a9de4U, 0x5078920dU, + 0x6a5fcc9bU, 0x547e4662U, 0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, + 0x82c3aff5U, 0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U, + 0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU, 0xcd267809U, + 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U, 0xe6956e65U, 0xaaffe67eU, + 0x21bccf08U, 0xef15e8e6U, 0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, + 0x29b07cd6U, 0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U, + 0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U, 0xf104984aU, + 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU, 0x764dd68dU, 0x43efb04dU, + 0xccaa4d54U, 0xe49604dfU, 0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, + 0x4665517fU, 0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU, + 0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U, 0x9ad7618cU, + 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U, 0xcea927eeU, 0xb761c935U, + 0xe11ce5edU, 0x7a47b13cU, 0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, + 0x73c737bfU, 0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U, + 0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU, 0x161dc372U, + 0xbce2250cU, 0x283c498bU, 0xff0d9541U, 0x39a80171U, 0x080cb3deU, + 0xd8b4e49cU, 0x6456c190U, 0x7bcb8461U, 0xd532b670U, 0x486c5c74U, + 0xd0b85742U, }; + +static const uint32_t Td1[256] = { + 0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU, 0xcb3bab6bU, + 0xf11f9d45U, 0xabacfa58U, 0x934be303U, 0x552030faU, 0xf6ad766dU, + 0x9188cc76U, 0x25f5024cU, 0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, + 0x8fb562a3U, 0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U, + 0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U, 0xe7038f5fU, + 0x9515929cU, 0xebbf6d7aU, 0xda955259U, 0x2dd4be83U, 0xd3587421U, + 0x2949e069U, 0x448ec9c8U, 0x6a75c289U, 0x78f48e79U, 0x6b99583eU, + 0xdd27b971U, 0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU, + 0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU, 0xe0b16477U, + 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU, 0x58704868U, 0x198f45fdU, + 0x8794de6cU, 0xb7527bf8U, 0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, + 0x2a6655abU, 0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U, + 0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U, 0x2b8acf1cU, + 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U, 0xcd65daf4U, 0xd50605beU, + 0x1fd13462U, 0x8ac4a6feU, 0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, + 0x75a4f6ebU, 0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U, + 0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU, 0xb591548dU, + 0x0571c45dU, 0x6f0406d4U, 0xff605015U, 0x241998fbU, 0x97d6bde9U, + 0xcc894043U, 0x7767d99eU, 0xbdb0e842U, 0x8807898bU, 0x38e7195bU, + 0xdb79c8eeU, 0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U, + 0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U, 0xfbfd0effU, + 0x560f8538U, 0x1e3daed5U, 0x27362d39U, 0x640a0fd9U, 0x21685ca6U, + 0xd19b5b54U, 0x3a24362eU, 0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, + 0x9e1b9b91U, 0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU, + 0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U, 0x0b0e090dU, + 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U, 0x8557f119U, 0x4caf7507U, + 0xbbee99ddU, 0xfda37f60U, 0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, + 0x345bfb7eU, 0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U, + 0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U, 0x7d854a24U, + 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U, 0x4b1d9e2fU, 0xf3dcb230U, + 0xec0d8652U, 0xd077c1e3U, 0x6c2bb316U, 0x99a970b9U, 0xfa119448U, + 0x2247e964U, 0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U, + 0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU, 0xcfa6f581U, + 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU, 0xe42c3a9dU, 0x0d507892U, + 0x9b6a5fccU, 0x62547e46U, 0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, + 0xf582c3afU, 0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U, + 0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU, 0x09cd2678U, + 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU, 0x65e6956eU, 0x7eaaffe6U, + 0x0821bccfU, 0xe6ef15e8U, 0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, + 0xd629b07cU, 0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U, + 0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U, 0x4af10498U, + 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U, 0x8d764dd6U, 0x4d43efb0U, + 0x54ccaa4dU, 0xdfe49604U, 0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, + 0x7f466551U, 0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U, + 0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U, 0x8c9ad761U, + 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU, 0xeecea927U, 0x35b761c9U, + 0xede11ce5U, 0x3c7a47b1U, 0x599cd2dfU, 0x3f55f273U, 0x791814ceU, + 0xbf73c737U, 0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU, + 0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U, 0x72161dc3U, + 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U, 0x7139a801U, 0xde080cb3U, + 0x9cd8b4e4U, 0x906456c1U, 0x617bcb84U, 0x70d532b6U, 0x74486c5cU, + 0x42d0b857U, }; + +static const uint32_t Td2[256] = { + 0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U, 0x6bcb3babU, + 0x45f11f9dU, 0x58abacfaU, 0x03934be3U, 0xfa552030U, 0x6df6ad76U, + 0x769188ccU, 0x4c25f502U, 0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, + 0xa38fb562U, 0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU, + 0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U, 0x5fe7038fU, + 0x9c951592U, 0x7aebbf6dU, 0x59da9552U, 0x832dd4beU, 0x21d35874U, + 0x692949e0U, 0xc8448ec9U, 0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, + 0x71dd27b9U, 0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU, + 0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U, 0x77e0b164U, + 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U, 0x68587048U, 0xfd198f45U, + 0x6c8794deU, 0xf8b7527bU, 0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, + 0xab2a6655U, 0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U, + 0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U, 0x1c2b8acfU, + 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U, 0xf4cd65daU, 0xbed50605U, + 0x621fd134U, 0xfe8ac4a6U, 0x539d342eU, 0x55a0a2f3U, 0xe132058aU, + 0xeb75a4f6U, 0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU, + 0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U, 0x8db59154U, + 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U, 0xfb241998U, 0xe997d6bdU, + 0x43cc8940U, 0x9e7767d9U, 0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, + 0xeedb79c8U, 0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U, + 0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU, 0xfffbfd0eU, + 0x38560f85U, 0xd51e3daeU, 0x3927362dU, 0xd9640a0fU, 0xa621685cU, + 0x54d19b5bU, 0x2e3a2436U, 0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, + 0x919e1b9bU, 0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U, + 0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU, 0x0d0b0e09U, + 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU, 0x198557f1U, 0x074caf75U, + 0xddbbee99U, 0x60fda37fU, 0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, + 0x7e345bfbU, 0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U, + 0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U, 0x247d854aU, + 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U, 0x2f4b1d9eU, 0x30f3dcb2U, + 0x52ec0d86U, 0xe3d077c1U, 0x166c2bb3U, 0xb999a970U, 0x48fa1194U, + 0x642247e9U, 0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U, + 0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U, 0x81cfa6f5U, + 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU, 0x9de42c3aU, 0x920d5078U, + 0xcc9b6a5fU, 0x4662547eU, 0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, + 0xaff582c3U, 0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U, + 0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU, 0x7809cd26U, + 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU, 0x6e65e695U, 0xe67eaaffU, + 0xcf0821bcU, 0xe8e6ef15U, 0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, + 0x7cd629b0U, 0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U, + 0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U, 0x984af104U, + 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U, 0xd68d764dU, 0xb04d43efU, + 0x4d54ccaaU, 0x04dfe496U, 0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, + 0x517f4665U, 0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU, + 0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U, 0x618c9ad7U, + 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U, 0x27eecea9U, 0xc935b761U, + 0xe5ede11cU, 0xb13c7a47U, 0xdf599cd2U, 0x733f55f2U, 0xce791814U, + 0x37bf73c7U, 0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U, + 0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U, 0xc372161dU, + 0x250cbce2U, 0x498b283cU, 0x9541ff0dU, 0x017139a8U, 0xb3de080cU, + 0xe49cd8b4U, 0xc1906456U, 0x84617bcbU, 0xb670d532U, 0x5c74486cU, + 0x5742d0b8U, }; + +static const uint32_t Td3[256] = { + 0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU, 0xab6bcb3bU, + 0x9d45f11fU, 0xfa58abacU, 0xe303934bU, 0x30fa5520U, 0x766df6adU, + 0xcc769188U, 0x024c25f5U, 0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, + 0x62a38fb5U, 0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU, + 0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU, 0x8f5fe703U, + 0x929c9515U, 0x6d7aebbfU, 0x5259da95U, 0xbe832dd4U, 0x7421d358U, + 0xe0692949U, 0xc9c8448eU, 0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, + 0xb971dd27U, 0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU, + 0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U, 0x6477e0b1U, + 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U, 0x48685870U, 0x45fd198fU, + 0xde6c8794U, 0x7bf8b752U, 0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, + 0x55ab2a66U, 0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U, + 0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU, 0xcf1c2b8aU, + 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU, 0xdaf4cd65U, 0x05bed506U, + 0x34621fd1U, 0xa6fe8ac4U, 0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, + 0xf6eb75a4U, 0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU, + 0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU, 0x548db591U, + 0xc45d0571U, 0x06d46f04U, 0x5015ff60U, 0x98fb2419U, 0xbde997d6U, + 0x4043cc89U, 0xd99e7767U, 0xe842bdb0U, 0x898b8807U, 0x195b38e7U, + 0xc8eedb79U, 0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U, + 0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU, 0x0efffbfdU, + 0x8538560fU, 0xaed51e3dU, 0x2d392736U, 0x0fd9640aU, 0x5ca62168U, + 0x5b54d19bU, 0x362e3a24U, 0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, + 0x9b919e1bU, 0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU, + 0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U, 0x090d0b0eU, + 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U, 0xf1198557U, 0x75074cafU, + 0x99ddbbeeU, 0x7f60fda3U, 0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, + 0xfb7e345bU, 0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U, + 0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U, 0x4a247d85U, + 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U, 0x9e2f4b1dU, 0xb230f3dcU, + 0x8652ec0dU, 0xc1e3d077U, 0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, + 0xe9642247U, 0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U, + 0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U, 0xf581cfa6U, + 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU, 0x3a9de42cU, 0x78920d50U, + 0x5fcc9b6aU, 0x7e466254U, 0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, + 0xc3aff582U, 0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU, + 0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU, 0x267809cdU, + 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U, 0x956e65e6U, 0xffe67eaaU, + 0xbccf0821U, 0x15e8e6efU, 0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, + 0xb07cd629U, 0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U, + 0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U, 0x04984af1U, + 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U, 0x4dd68d76U, 0xefb04d43U, + 0xaa4d54ccU, 0x9604dfe4U, 0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, + 0x65517f46U, 0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU, + 0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU, 0xd7618c9aU, + 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU, 0xa927eeceU, 0x61c935b7U, + 0x1ce5ede1U, 0x47b13c7aU, 0xd2df599cU, 0xf2733f55U, 0x14ce7918U, + 0xc737bf73U, 0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U, + 0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U, 0x1dc37216U, + 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU, 0xa8017139U, 0x0cb3de08U, + 0xb4e49cd8U, 0x56c19064U, 0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, + 0xb85742d0U, }; + +static const uint8_t Td4[256] = { + 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U, 0xbfU, 0x40U, 0xa3U, + 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU, 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, + 0xffU, 0x87U, 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU, 0x54U, + 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU, 0xeeU, 0x4cU, 0x95U, 0x0bU, + 0x42U, 0xfaU, 0xc3U, 0x4eU, 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, + 0xb2U, 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U, 0x72U, 0xf8U, + 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U, 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, + 0x65U, 0xb6U, 0x92U, 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU, + 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U, 0x90U, 0xd8U, 0xabU, + 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU, 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, + 0x45U, 0x06U, 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U, 0xc1U, + 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU, 0x3aU, 0x91U, 0x11U, 0x41U, + 0x4fU, 0x67U, 0xdcU, 0xeaU, 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, + 0x73U, 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U, 0xe2U, 0xf9U, + 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU, 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, + 0x29U, 0xc5U, 0x89U, 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU, + 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U, 0x9aU, 0xdbU, 0xc0U, + 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U, 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, + 0xc7U, 0x31U, 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU, 0x60U, + 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU, 0x2dU, 0xe5U, 0x7aU, 0x9fU, + 0x93U, 0xc9U, 0x9cU, 0xefU, 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, + 0xb0U, 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U, 0x17U, 0x2bU, + 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U, 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, + 0x21U, 0x0cU, 0x7dU, }; + +static const uint32_t rcon[] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, + 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, + /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */ +}; + +int AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) { + uint32_t *rk; + int i = 0; + uint32_t temp; + + if (!key || !aeskey) { + return -1; + } + + switch (bits) { + case 128: + aeskey->rounds = 10; + break; + case 192: + aeskey->rounds = 12; + break; + case 256: + aeskey->rounds = 14; + break; + default: + return -2; + } + + rk = aeskey->rd_key; + + rk[0] = GETU32(key); + rk[1] = GETU32(key + 4); + rk[2] = GETU32(key + 8); + rk[3] = GETU32(key + 12); + if (bits == 128) { + while (1) { + temp = rk[3]; + rk[4] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te0[(temp) & 0xff] & 0x0000ff00) ^ + (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i]; + rk[5] = rk[1] ^ rk[4]; + rk[6] = rk[2] ^ rk[5]; + rk[7] = rk[3] ^ rk[6]; + if (++i == 10) { + return 0; + } + rk += 4; + } + } + rk[4] = GETU32(key + 16); + rk[5] = GETU32(key + 20); + if (bits == 192) { + while (1) { + temp = rk[5]; + rk[6] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te0[(temp) & 0xff] & 0x0000ff00) ^ + (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i]; + rk[7] = rk[1] ^ rk[6]; + rk[8] = rk[2] ^ rk[7]; + rk[9] = rk[3] ^ rk[8]; + if (++i == 8) { + return 0; + } + rk[10] = rk[4] ^ rk[9]; + rk[11] = rk[5] ^ rk[10]; + rk += 6; + } + } + rk[6] = GETU32(key + 24); + rk[7] = GETU32(key + 28); + if (bits == 256) { + while (1) { + temp = rk[7]; + rk[8] = rk[0] ^ (Te2[(temp >> 16) & 0xff] & 0xff000000) ^ + (Te3[(temp >> 8) & 0xff] & 0x00ff0000) ^ + (Te0[(temp) & 0xff] & 0x0000ff00) ^ + (Te1[(temp >> 24)] & 0x000000ff) ^ rcon[i]; + rk[9] = rk[1] ^ rk[8]; + rk[10] = rk[2] ^ rk[9]; + rk[11] = rk[3] ^ rk[10]; + if (++i == 7) { + return 0; + } + temp = rk[11]; + rk[12] = rk[4] ^ (Te2[(temp >> 24)] & 0xff000000) ^ + (Te3[(temp >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(temp >> 8) & 0xff] & 0x0000ff00) ^ + (Te1[(temp) & 0xff] & 0x000000ff); + rk[13] = rk[5] ^ rk[12]; + rk[14] = rk[6] ^ rk[13]; + rk[15] = rk[7] ^ rk[14]; + + rk += 8; + } + } + return 0; +} + +int AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) { + uint32_t *rk; + int i, j, status; + uint32_t temp; + + /* first, start with an encryption schedule */ + status = AES_set_encrypt_key(key, bits, aeskey); + if (status < 0) { + return status; + } + + rk = aeskey->rd_key; + + /* invert the order of the round keys: */ + for (i = 0, j = 4 * aeskey->rounds; i < j; i += 4, j -= 4) { + temp = rk[i]; + rk[i] = rk[j]; + rk[j] = temp; + temp = rk[i + 1]; + rk[i + 1] = rk[j + 1]; + rk[j + 1] = temp; + temp = rk[i + 2]; + rk[i + 2] = rk[j + 2]; + rk[j + 2] = temp; + temp = rk[i + 3]; + rk[i + 3] = rk[j + 3]; + rk[j + 3] = temp; + } + /* apply the inverse MixColumn transform to all round keys but the first and + * the last: */ + for (i = 1; i < (int)aeskey->rounds; i++) { + rk += 4; + rk[0] = + Td0[Te1[(rk[0] >> 24)] & 0xff] ^ Td1[Te1[(rk[0] >> 16) & 0xff] & 0xff] ^ + Td2[Te1[(rk[0] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[0]) & 0xff] & 0xff]; + rk[1] = + Td0[Te1[(rk[1] >> 24)] & 0xff] ^ Td1[Te1[(rk[1] >> 16) & 0xff] & 0xff] ^ + Td2[Te1[(rk[1] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[1]) & 0xff] & 0xff]; + rk[2] = + Td0[Te1[(rk[2] >> 24)] & 0xff] ^ Td1[Te1[(rk[2] >> 16) & 0xff] & 0xff] ^ + Td2[Te1[(rk[2] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[2]) & 0xff] & 0xff]; + rk[3] = + Td0[Te1[(rk[3] >> 24)] & 0xff] ^ Td1[Te1[(rk[3] >> 16) & 0xff] & 0xff] ^ + Td2[Te1[(rk[3] >> 8) & 0xff] & 0xff] ^ Td3[Te1[(rk[3]) & 0xff] & 0xff]; + } + return 0; +} + +void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + const uint32_t *rk; + uint32_t s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + assert(in && out && key); + rk = key->rd_key; + + /* map byte array block to cipher state + * and add initial round key: */ + s0 = GETU32(in) ^ rk[0]; + s1 = GETU32(in + 4) ^ rk[1]; + s2 = GETU32(in + 8) ^ rk[2]; + s3 = GETU32(in + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[s3 & 0xff] ^ rk[4]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[s0 & 0xff] ^ rk[5]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[s1 & 0xff] ^ rk[6]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[s2 & 0xff] ^ rk[7]; + /* round 2: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ + Te3[t3 & 0xff] ^ rk[8]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ + Te3[t0 & 0xff] ^ rk[9]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ + Te3[t1 & 0xff] ^ rk[10]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ + Te3[t2 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[s3 & 0xff] ^ rk[12]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[s0 & 0xff] ^ rk[13]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[s1 & 0xff] ^ rk[14]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[s2 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ + Te3[t3 & 0xff] ^ rk[16]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ + Te3[t0 & 0xff] ^ rk[17]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ + Te3[t1 & 0xff] ^ rk[18]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ + Te3[t2 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[s3 & 0xff] ^ rk[20]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[s0 & 0xff] ^ rk[21]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[s1 & 0xff] ^ rk[22]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[s2 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ + Te3[t3 & 0xff] ^ rk[24]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ + Te3[t0 & 0xff] ^ rk[25]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ + Te3[t1 & 0xff] ^ rk[26]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ + Te3[t2 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[s3 & 0xff] ^ rk[28]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[s0 & 0xff] ^ rk[29]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[s1 & 0xff] ^ rk[30]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[s2 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ + Te3[t3 & 0xff] ^ rk[32]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ + Te3[t0 & 0xff] ^ rk[33]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ + Te3[t1 & 0xff] ^ rk[34]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ + Te3[t2 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[s3 & 0xff] ^ rk[36]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[s0 & 0xff] ^ rk[37]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[s1 & 0xff] ^ rk[38]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[s2 & 0xff] ^ rk[39]; + if (key->rounds > 10) { + /* round 10: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ + Te3[t3 & 0xff] ^ rk[40]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ + Te3[t0 & 0xff] ^ rk[41]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ + Te3[t1 & 0xff] ^ rk[42]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ + Te3[t2 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[s3 & 0xff] ^ rk[44]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[s0 & 0xff] ^ rk[45]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[s1 & 0xff] ^ rk[46]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[s2 & 0xff] ^ rk[47]; + if (key->rounds > 12) { + /* round 12: */ + s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ + Te3[t3 & 0xff] ^ rk[48]; + s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ + Te3[t0 & 0xff] ^ rk[49]; + s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ + Te3[t1 & 0xff] ^ rk[50]; + s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ + Te3[t2 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[s3 & 0xff] ^ rk[52]; + t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[s0 & 0xff] ^ rk[53]; + t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[s1 & 0xff] ^ rk[54]; + t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[s2 & 0xff] ^ rk[55]; + } + } + rk += key->rounds << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = key->rounds >> 1; + for (;;) { + t0 = Te0[(s0 >> 24)] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ + Te3[(s3) & 0xff] ^ rk[4]; + t1 = Te0[(s1 >> 24)] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ + Te3[(s0) & 0xff] ^ rk[5]; + t2 = Te0[(s2 >> 24)] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ + Te3[(s1) & 0xff] ^ rk[6]; + t3 = Te0[(s3 >> 24)] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ + Te3[(s2) & 0xff] ^ rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = Te0[(t0 >> 24)] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ + Te3[(t3) & 0xff] ^ rk[0]; + s1 = Te0[(t1 >> 24)] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ + Te3[(t0) & 0xff] ^ rk[1]; + s2 = Te0[(t2 >> 24)] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ + Te3[(t1) & 0xff] ^ rk[2]; + s3 = Te0[(t3 >> 24)] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ + Te3[(t2) & 0xff] ^ rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* apply last round and map cipher state to byte array block: */ + s0 = (Te2[(t0 >> 24)] & 0xff000000) ^ (Te3[(t1 >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(t2 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t3) & 0xff] & 0x000000ff) ^ + rk[0]; + PUTU32(out, s0); + s1 = (Te2[(t1 >> 24)] & 0xff000000) ^ (Te3[(t2 >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(t3 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t0) & 0xff] & 0x000000ff) ^ + rk[1]; + PUTU32(out + 4, s1); + s2 = (Te2[(t2 >> 24)] & 0xff000000) ^ (Te3[(t3 >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(t0 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t1) & 0xff] & 0x000000ff) ^ + rk[2]; + PUTU32(out + 8, s2); + s3 = (Te2[(t3 >> 24)] & 0xff000000) ^ (Te3[(t0 >> 16) & 0xff] & 0x00ff0000) ^ + (Te0[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t2) & 0xff] & 0x000000ff) ^ + rk[3]; + PUTU32(out + 12, s3); +} + +void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + const uint32_t *rk; + uint32_t s0, s1, s2, s3, t0, t1, t2, t3; +#ifndef FULL_UNROLL + int r; +#endif /* ?FULL_UNROLL */ + + assert(in && out && key); + rk = key->rd_key; + + /* map byte array block to cipher state + * and add initial round key: */ + s0 = GETU32(in) ^ rk[0]; + s1 = GETU32(in + 4) ^ rk[1]; + s2 = GETU32(in + 8) ^ rk[2]; + s3 = GETU32(in + 12) ^ rk[3]; +#ifdef FULL_UNROLL + /* round 1: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[s1 & 0xff] ^ rk[4]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[s2 & 0xff] ^ rk[5]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[s3 & 0xff] ^ rk[6]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[s0 & 0xff] ^ rk[7]; + /* round 2: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ + Td3[t1 & 0xff] ^ rk[8]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ + Td3[t2 & 0xff] ^ rk[9]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ + Td3[t3 & 0xff] ^ rk[10]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ + Td3[t0 & 0xff] ^ rk[11]; + /* round 3: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[s1 & 0xff] ^ rk[12]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[s2 & 0xff] ^ rk[13]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[s3 & 0xff] ^ rk[14]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[s0 & 0xff] ^ rk[15]; + /* round 4: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ + Td3[t1 & 0xff] ^ rk[16]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ + Td3[t2 & 0xff] ^ rk[17]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ + Td3[t3 & 0xff] ^ rk[18]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ + Td3[t0 & 0xff] ^ rk[19]; + /* round 5: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[s1 & 0xff] ^ rk[20]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[s2 & 0xff] ^ rk[21]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[s3 & 0xff] ^ rk[22]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[s0 & 0xff] ^ rk[23]; + /* round 6: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ + Td3[t1 & 0xff] ^ rk[24]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ + Td3[t2 & 0xff] ^ rk[25]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ + Td3[t3 & 0xff] ^ rk[26]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ + Td3[t0 & 0xff] ^ rk[27]; + /* round 7: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[s1 & 0xff] ^ rk[28]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[s2 & 0xff] ^ rk[29]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[s3 & 0xff] ^ rk[30]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[s0 & 0xff] ^ rk[31]; + /* round 8: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ + Td3[t1 & 0xff] ^ rk[32]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ + Td3[t2 & 0xff] ^ rk[33]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ + Td3[t3 & 0xff] ^ rk[34]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ + Td3[t0 & 0xff] ^ rk[35]; + /* round 9: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[s1 & 0xff] ^ rk[36]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[s2 & 0xff] ^ rk[37]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[s3 & 0xff] ^ rk[38]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[s0 & 0xff] ^ rk[39]; + if (key->rounds > 10) { + /* round 10: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ + Td3[t1 & 0xff] ^ rk[40]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ + Td3[t2 & 0xff] ^ rk[41]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ + Td3[t3 & 0xff] ^ rk[42]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ + Td3[t0 & 0xff] ^ rk[43]; + /* round 11: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[s1 & 0xff] ^ rk[44]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[s2 & 0xff] ^ rk[45]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[s3 & 0xff] ^ rk[46]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[s0 & 0xff] ^ rk[47]; + if (key->rounds > 12) { + /* round 12: */ + s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ + Td3[t1 & 0xff] ^ rk[48]; + s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ + Td3[t2 & 0xff] ^ rk[49]; + s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ + Td3[t3 & 0xff] ^ rk[50]; + s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ + Td3[t0 & 0xff] ^ rk[51]; + /* round 13: */ + t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[s1 & 0xff] ^ rk[52]; + t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[s2 & 0xff] ^ rk[53]; + t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[s3 & 0xff] ^ rk[54]; + t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[s0 & 0xff] ^ rk[55]; + } + } + rk += key->rounds << 2; +#else /* !FULL_UNROLL */ + /* + * Nr - 1 full rounds: + */ + r = key->rounds >> 1; + for (;;) { + t0 = Td0[(s0 >> 24)] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ + Td3[(s1) & 0xff] ^ rk[4]; + t1 = Td0[(s1 >> 24)] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ + Td3[(s2) & 0xff] ^ rk[5]; + t2 = Td0[(s2 >> 24)] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ + Td3[(s3) & 0xff] ^ rk[6]; + t3 = Td0[(s3 >> 24)] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ + Td3[(s0) & 0xff] ^ rk[7]; + + rk += 8; + if (--r == 0) { + break; + } + + s0 = Td0[(t0 >> 24)] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ + Td3[(t1) & 0xff] ^ rk[0]; + s1 = Td0[(t1 >> 24)] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ + Td3[(t2) & 0xff] ^ rk[1]; + s2 = Td0[(t2 >> 24)] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ + Td3[(t3) & 0xff] ^ rk[2]; + s3 = Td0[(t3 >> 24)] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ + Td3[(t0) & 0xff] ^ rk[3]; + } +#endif /* ?FULL_UNROLL */ + /* apply last round and + * map cipher state to byte array block: */ + s0 = ((uint32_t)Td4[(t0 >> 24)] << 24) ^ + ((uint32_t)Td4[(t3 >> 16) & 0xff] << 16) ^ + ((uint32_t)Td4[(t2 >> 8) & 0xff] << 8) ^ + ((uint32_t)Td4[(t1) & 0xff]) ^ rk[0]; + PUTU32(out, s0); + s1 = ((uint32_t)Td4[(t1 >> 24)] << 24) ^ + ((uint32_t)Td4[(t0 >> 16) & 0xff] << 16) ^ + ((uint32_t)Td4[(t3 >> 8) & 0xff] << 8) ^ + ((uint32_t)Td4[(t2) & 0xff]) ^ rk[1]; + PUTU32(out + 4, s1); + s2 = ((uint32_t)Td4[(t2 >> 24)] << 24) ^ + ((uint32_t)Td4[(t1 >> 16) & 0xff] << 16) ^ + ((uint32_t)Td4[(t0 >> 8) & 0xff] << 8) ^ + ((uint32_t)Td4[(t3) & 0xff]) ^ rk[2]; + PUTU32(out + 8, s2); + s3 = ((uint32_t)Td4[(t3 >> 24)] << 24) ^ + ((uint32_t)Td4[(t2 >> 16) & 0xff] << 16) ^ + ((uint32_t)Td4[(t1 >> 8) & 0xff] << 8) ^ + ((uint32_t)Td4[(t0) & 0xff]) ^ rk[3]; + PUTU32(out + 12, s3); +} + +#else + +/* In this case several functions are provided by asm code. However, one cannot + * control asm symbol visibility with command line flags and such so they are + * always hidden and wrapped by these C functions, which can be so + * controlled. */ + +void asm_AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + asm_AES_encrypt(in, out, key); +} + +void asm_AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + asm_AES_decrypt(in, out, key); +} + +int asm_AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey); +int AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) { + return asm_AES_set_encrypt_key(key, bits, aeskey); +} + +int asm_AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey); +int AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) { + return asm_AES_set_decrypt_key(key, bits, aeskey); +} + +#endif /* OPENSSL_NO_ASM || (!OPENSSL_X86 && !OPENSSL_X86_64 && !OPENSSL_ARM) */ diff --git a/TMessagesProj/jni/boringssl/crypto/aes/aes_ige.c b/TMessagesProj/jni/boringssl/crypto/aes/aes_ige.c new file mode 100644 index 00000000..b425c7d6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/aes_ige.c @@ -0,0 +1,323 @@ +/* crypto/aes/aes_ige.c -*- mode:C; c-file-style: "eay" -*- */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== + * + */ + +#include +#include +#include +#include + +#define N_WORDS (AES_BLOCK_SIZE / sizeof(unsigned long)) +typedef struct { + unsigned long data[N_WORDS]; +} aes_block_t; + +/* XXX: probably some better way to do this */ +#if defined(__i386__) || defined(__x86_64__) +#define UNALIGNED_MEMOPS_ARE_FAST 1 +#else +#define UNALIGNED_MEMOPS_ARE_FAST 0 +#endif + +#if UNALIGNED_MEMOPS_ARE_FAST +#define load_block(d, s) (d) = *(const aes_block_t *)(s) +#define store_block(d, s) *(aes_block_t *)(d) = (s) +#else +#define load_block(d, s) memcpy((d).data, (s), AES_BLOCK_SIZE) +#define store_block(d, s) memcpy((d), (s).data, AES_BLOCK_SIZE) +#endif + +/* N.B. The IV for this mode is _twice_ the block size */ + +void AES_ige_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char *ivec, const int enc) + { + size_t n; + size_t len = length; + + assert(in && out && key && ivec); + assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc)); + assert((length%AES_BLOCK_SIZE) == 0); + + len = length / AES_BLOCK_SIZE; + + if (AES_ENCRYPT == enc) + { + if (in != out && + (UNALIGNED_MEMOPS_ARE_FAST || ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(long)==0)) + { + aes_block_t *ivp = (aes_block_t *)ivec; + aes_block_t *iv2p = (aes_block_t *)(ivec + AES_BLOCK_SIZE); + + while (len) + { + aes_block_t *inp = (aes_block_t *)in; + aes_block_t *outp = (aes_block_t *)out; + + for(n=0 ; n < N_WORDS; ++n) + outp->data[n] = inp->data[n] ^ ivp->data[n]; + AES_encrypt((unsigned char *)outp->data, (unsigned char *)outp->data, key); + for(n=0 ; n < N_WORDS; ++n) + outp->data[n] ^= iv2p->data[n]; + ivp = outp; + iv2p = inp; + --len; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + memcpy(ivec, ivp->data, AES_BLOCK_SIZE); + memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE); + } + else + { + aes_block_t tmp, tmp2; + aes_block_t iv; + aes_block_t iv2; + + load_block(iv, ivec); + load_block(iv2, ivec + AES_BLOCK_SIZE); + + while (len) + { + load_block(tmp, in); + for(n=0 ; n < N_WORDS; ++n) + tmp2.data[n] = tmp.data[n] ^ iv.data[n]; + AES_encrypt((unsigned char *)tmp2.data, (unsigned char *)tmp2.data, key); + for(n=0 ; n < N_WORDS; ++n) + tmp2.data[n] ^= iv2.data[n]; + store_block(out, tmp2); + iv = tmp2; + iv2 = tmp; + --len; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + memcpy(ivec, iv.data, AES_BLOCK_SIZE); + memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE); + } + } + else + { + if (in != out && + (UNALIGNED_MEMOPS_ARE_FAST || ((size_t)in|(size_t)out|(size_t)ivec)%sizeof(long)==0)) + { + aes_block_t *ivp = (aes_block_t *)ivec; + aes_block_t *iv2p = (aes_block_t *)(ivec + AES_BLOCK_SIZE); + + while (len) + { + aes_block_t tmp; + aes_block_t *inp = (aes_block_t *)in; + aes_block_t *outp = (aes_block_t *)out; + + for(n=0 ; n < N_WORDS; ++n) + tmp.data[n] = inp->data[n] ^ iv2p->data[n]; + AES_decrypt((unsigned char *)tmp.data, (unsigned char *)outp->data, key); + for(n=0 ; n < N_WORDS; ++n) + outp->data[n] ^= ivp->data[n]; + ivp = inp; + iv2p = outp; + --len; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + memcpy(ivec, ivp->data, AES_BLOCK_SIZE); + memcpy(ivec + AES_BLOCK_SIZE, iv2p->data, AES_BLOCK_SIZE); + } + else + { + aes_block_t tmp, tmp2; + aes_block_t iv; + aes_block_t iv2; + + load_block(iv, ivec); + load_block(iv2, ivec + AES_BLOCK_SIZE); + + while (len) + { + load_block(tmp, in); + tmp2 = tmp; + for(n=0 ; n < N_WORDS; ++n) + tmp.data[n] ^= iv2.data[n]; + AES_decrypt((unsigned char *)tmp.data, (unsigned char *)tmp.data, key); + for(n=0 ; n < N_WORDS; ++n) + tmp.data[n] ^= iv.data[n]; + store_block(out, tmp); + iv = tmp2; + iv2 = tmp; + --len; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + memcpy(ivec, iv.data, AES_BLOCK_SIZE); + memcpy(ivec + AES_BLOCK_SIZE, iv2.data, AES_BLOCK_SIZE); + } + } + } + +/* + * Note that its effectively impossible to do biIGE in anything other + * than a single pass, so no provision is made for chaining. + */ + +/* N.B. The IV for this mode is _four times_ the block size */ + +void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + const AES_KEY *key2, const unsigned char *ivec, + const int enc) + { + size_t n; + size_t len = length; + unsigned char tmp[AES_BLOCK_SIZE]; + unsigned char tmp2[AES_BLOCK_SIZE]; + unsigned char tmp3[AES_BLOCK_SIZE]; + unsigned char prev[AES_BLOCK_SIZE]; + const unsigned char *iv; + const unsigned char *iv2; + + assert(in && out && key && ivec); + assert((AES_ENCRYPT == enc)||(AES_DECRYPT == enc)); + assert((length%AES_BLOCK_SIZE) == 0); + + if (AES_ENCRYPT == enc) + { + /* XXX: Do a separate case for when in != out (strictly should + check for overlap, too) */ + + /* First the forward pass */ + iv = ivec; + iv2 = ivec + AES_BLOCK_SIZE; + while (len >= AES_BLOCK_SIZE) + { + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + out[n] = in[n] ^ iv[n]; + AES_encrypt(out, out, key); + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + out[n] ^= iv2[n]; + iv = out; + memcpy(prev, in, AES_BLOCK_SIZE); + iv2 = prev; + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + + /* And now backwards */ + iv = ivec + AES_BLOCK_SIZE*2; + iv2 = ivec + AES_BLOCK_SIZE*3; + len = length; + while(len >= AES_BLOCK_SIZE) + { + out -= AES_BLOCK_SIZE; + /* XXX: reduce copies by alternating between buffers */ + memcpy(tmp, out, AES_BLOCK_SIZE); + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + out[n] ^= iv[n]; + /* hexdump(stdout, "out ^ iv", out, AES_BLOCK_SIZE); */ + AES_encrypt(out, out, key); + /* hexdump(stdout,"enc", out, AES_BLOCK_SIZE); */ + /* hexdump(stdout,"iv2", iv2, AES_BLOCK_SIZE); */ + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + out[n] ^= iv2[n]; + /* hexdump(stdout,"out", out, AES_BLOCK_SIZE); */ + iv = out; + memcpy(prev, tmp, AES_BLOCK_SIZE); + iv2 = prev; + len -= AES_BLOCK_SIZE; + } + } + else + { + /* First backwards */ + iv = ivec + AES_BLOCK_SIZE*2; + iv2 = ivec + AES_BLOCK_SIZE*3; + in += length; + out += length; + while (len >= AES_BLOCK_SIZE) + { + in -= AES_BLOCK_SIZE; + out -= AES_BLOCK_SIZE; + memcpy(tmp, in, AES_BLOCK_SIZE); + memcpy(tmp2, in, AES_BLOCK_SIZE); + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + tmp[n] ^= iv2[n]; + AES_decrypt(tmp, out, key); + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + out[n] ^= iv[n]; + memcpy(tmp3, tmp2, AES_BLOCK_SIZE); + iv = tmp3; + iv2 = out; + len -= AES_BLOCK_SIZE; + } + + /* And now forwards */ + iv = ivec; + iv2 = ivec + AES_BLOCK_SIZE; + len = length; + while (len >= AES_BLOCK_SIZE) + { + memcpy(tmp, out, AES_BLOCK_SIZE); + memcpy(tmp2, out, AES_BLOCK_SIZE); + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + tmp[n] ^= iv2[n]; + AES_decrypt(tmp, out, key); + for(n=0 ; n < AES_BLOCK_SIZE ; ++n) + out[n] ^= iv[n]; + memcpy(tmp3, tmp2, AES_BLOCK_SIZE); + iv = tmp3; + iv2 = out; + len -= AES_BLOCK_SIZE; + in += AES_BLOCK_SIZE; + out += AES_BLOCK_SIZE; + } + } + } diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-586.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-586.pl new file mode 100644 index 00000000..6e8a6a80 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-586.pl @@ -0,0 +1,2987 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# Version 4.3. +# +# You might fail to appreciate this module performance from the first +# try. If compared to "vanilla" linux-ia32-icc target, i.e. considered +# to be *the* best Intel C compiler without -KPIC, performance appears +# to be virtually identical... But try to re-configure with shared +# library support... Aha! Intel compiler "suddenly" lags behind by 30% +# [on P4, more on others]:-) And if compared to position-independent +# code generated by GNU C, this code performs *more* than *twice* as +# fast! Yes, all this buzz about PIC means that unlike other hand- +# coded implementations, this one was explicitly designed to be safe +# to use even in shared library context... This also means that this +# code isn't necessarily absolutely fastest "ever," because in order +# to achieve position independence an extra register has to be +# off-loaded to stack, which affects the benchmark result. +# +# Special note about instruction choice. Do you recall RC4_INT code +# performing poorly on P4? It might be the time to figure out why. +# RC4_INT code implies effective address calculations in base+offset*4 +# form. Trouble is that it seems that offset scaling turned to be +# critical path... At least eliminating scaling resulted in 2.8x RC4 +# performance improvement [as you might recall]. As AES code is hungry +# for scaling too, I [try to] avoid the latter by favoring off-by-2 +# shifts and masking the result with 0xFF<<2 instead of "boring" 0xFF. +# +# As was shown by Dean Gaudet , the above note turned +# void. Performance improvement with off-by-2 shifts was observed on +# intermediate implementation, which was spilling yet another register +# to stack... Final offset*4 code below runs just a tad faster on P4, +# but exhibits up to 10% improvement on other cores. +# +# Second version is "monolithic" replacement for aes_core.c, which in +# addition to AES_[de|en]crypt implements AES_set_[de|en]cryption_key. +# This made it possible to implement little-endian variant of the +# algorithm without modifying the base C code. Motivating factor for +# the undertaken effort was that it appeared that in tight IA-32 +# register window little-endian flavor could achieve slightly higher +# Instruction Level Parallelism, and it indeed resulted in up to 15% +# better performance on most recent µ-archs... +# +# Third version adds AES_cbc_encrypt implementation, which resulted in +# up to 40% performance imrovement of CBC benchmark results. 40% was +# observed on P4 core, where "overall" imrovement coefficient, i.e. if +# compared to PIC generated by GCC and in CBC mode, was observed to be +# as large as 4x:-) CBC performance is virtually identical to ECB now +# and on some platforms even better, e.g. 17.6 "small" cycles/byte on +# Opteron, because certain function prologues and epilogues are +# effectively taken out of the loop... +# +# Version 3.2 implements compressed tables and prefetch of these tables +# in CBC[!] mode. Former means that 3/4 of table references are now +# misaligned, which unfortunately has negative impact on elder IA-32 +# implementations, Pentium suffered 30% penalty, PIII - 10%. +# +# Version 3.3 avoids L1 cache aliasing between stack frame and +# S-boxes, and 3.4 - L1 cache aliasing even between key schedule. The +# latter is achieved by copying the key schedule to controlled place in +# stack. This unfortunately has rather strong impact on small block CBC +# performance, ~2x deterioration on 16-byte block if compared to 3.3. +# +# Version 3.5 checks if there is L1 cache aliasing between user-supplied +# key schedule and S-boxes and abstains from copying the former if +# there is no. This allows end-user to consciously retain small block +# performance by aligning key schedule in specific manner. +# +# Version 3.6 compresses Td4 to 256 bytes and prefetches it in ECB. +# +# Current ECB performance numbers for 128-bit key in CPU cycles per +# processed byte [measure commonly used by AES benchmarkers] are: +# +# small footprint fully unrolled +# P4 24 22 +# AMD K8 20 19 +# PIII 25 23 +# Pentium 81 78 +# +# Version 3.7 reimplements outer rounds as "compact." Meaning that +# first and last rounds reference compact 256 bytes S-box. This means +# that first round consumes a lot more CPU cycles and that encrypt +# and decrypt performance becomes asymmetric. Encrypt performance +# drops by 10-12%, while decrypt - by 20-25%:-( 256 bytes S-box is +# aggressively pre-fetched. +# +# Version 4.0 effectively rolls back to 3.6 and instead implements +# additional set of functions, _[x86|sse]_AES_[en|de]crypt_compact, +# which use exclusively 256 byte S-box. These functions are to be +# called in modes not concealing plain text, such as ECB, or when +# we're asked to process smaller amount of data [or unconditionally +# on hyper-threading CPU]. Currently it's called unconditionally from +# AES_[en|de]crypt, which affects all modes, but CBC. CBC routine +# still needs to be modified to switch between slower and faster +# mode when appropriate... But in either case benchmark landscape +# changes dramatically and below numbers are CPU cycles per processed +# byte for 128-bit key. +# +# ECB encrypt ECB decrypt CBC large chunk +# P4 52[54] 83[95] 23 +# AMD K8 46[41] 66[70] 18 +# PIII 41[50] 60[77] 24 +# Core 2 31[36] 45[64] 18.5 +# Atom 76[100] 96[138] 60 +# Pentium 115 150 77 +# +# Version 4.1 switches to compact S-box even in key schedule setup. +# +# Version 4.2 prefetches compact S-box in every SSE round or in other +# words every cache-line is *guaranteed* to be accessed within ~50 +# cycles window. Why just SSE? Because it's needed on hyper-threading +# CPU! Which is also why it's prefetched with 64 byte stride. Best +# part is that it has no negative effect on performance:-) +# +# Version 4.3 implements switch between compact and non-compact block +# functions in AES_cbc_encrypt depending on how much data was asked +# to be processed in one stroke. +# +###################################################################### +# Timing attacks are classified in two classes: synchronous when +# attacker consciously initiates cryptographic operation and collects +# timing data of various character afterwards, and asynchronous when +# malicious code is executed on same CPU simultaneously with AES, +# instruments itself and performs statistical analysis of this data. +# +# As far as synchronous attacks go the root to the AES timing +# vulnerability is twofold. Firstly, of 256 S-box elements at most 160 +# are referred to in single 128-bit block operation. Well, in C +# implementation with 4 distinct tables it's actually as little as 40 +# references per 256 elements table, but anyway... Secondly, even +# though S-box elements are clustered into smaller amount of cache- +# lines, smaller than 160 and even 40, it turned out that for certain +# plain-text pattern[s] or simply put chosen plain-text and given key +# few cache-lines remain unaccessed during block operation. Now, if +# attacker can figure out this access pattern, he can deduct the key +# [or at least part of it]. The natural way to mitigate this kind of +# attacks is to minimize the amount of cache-lines in S-box and/or +# prefetch them to ensure that every one is accessed for more uniform +# timing. But note that *if* plain-text was concealed in such way that +# input to block function is distributed *uniformly*, then attack +# wouldn't apply. Now note that some encryption modes, most notably +# CBC, do mask the plain-text in this exact way [secure cipher output +# is distributed uniformly]. Yes, one still might find input that +# would reveal the information about given key, but if amount of +# candidate inputs to be tried is larger than amount of possible key +# combinations then attack becomes infeasible. This is why revised +# AES_cbc_encrypt "dares" to switch to larger S-box when larger chunk +# of data is to be processed in one stroke. The current size limit of +# 512 bytes is chosen to provide same [diminishigly low] probability +# for cache-line to remain untouched in large chunk operation with +# large S-box as for single block operation with compact S-box and +# surely needs more careful consideration... +# +# As for asynchronous attacks. There are two flavours: attacker code +# being interleaved with AES on hyper-threading CPU at *instruction* +# level, and two processes time sharing single core. As for latter. +# Two vectors. 1. Given that attacker process has higher priority, +# yield execution to process performing AES just before timer fires +# off the scheduler, immediately regain control of CPU and analyze the +# cache state. For this attack to be efficient attacker would have to +# effectively slow down the operation by several *orders* of magnitute, +# by ratio of time slice to duration of handful of AES rounds, which +# unlikely to remain unnoticed. Not to mention that this also means +# that he would spend correspondigly more time to collect enough +# statistical data to mount the attack. It's probably appropriate to +# say that if adeversary reckons that this attack is beneficial and +# risks to be noticed, you probably have larger problems having him +# mere opportunity. In other words suggested code design expects you +# to preclude/mitigate this attack by overall system security design. +# 2. Attacker manages to make his code interrupt driven. In order for +# this kind of attack to be feasible, interrupt rate has to be high +# enough, again comparable to duration of handful of AES rounds. But +# is there interrupt source of such rate? Hardly, not even 1Gbps NIC +# generates interrupts at such raging rate... +# +# And now back to the former, hyper-threading CPU or more specifically +# Intel P4. Recall that asynchronous attack implies that malicious +# code instruments itself. And naturally instrumentation granularity +# has be noticeably lower than duration of codepath accessing S-box. +# Given that all cache-lines are accessed during that time that is. +# Current implementation accesses *all* cache-lines within ~50 cycles +# window, which is actually *less* than RDTSC latency on Intel P4! + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],"aes-586.pl",$x86only = $ARGV[$#ARGV] eq "386"); +&static_label("AES_Te"); +&static_label("AES_Td"); + +$s0="eax"; +$s1="ebx"; +$s2="ecx"; +$s3="edx"; +$key="edi"; +$acc="esi"; +$tbl="ebp"; + +# stack frame layout in _[x86|sse]_AES_* routines, frame is allocated +# by caller +$__ra=&DWP(0,"esp"); # return address +$__s0=&DWP(4,"esp"); # s0 backing store +$__s1=&DWP(8,"esp"); # s1 backing store +$__s2=&DWP(12,"esp"); # s2 backing store +$__s3=&DWP(16,"esp"); # s3 backing store +$__key=&DWP(20,"esp"); # pointer to key schedule +$__end=&DWP(24,"esp"); # pointer to end of key schedule +$__tbl=&DWP(28,"esp"); # %ebp backing store + +# stack frame layout in AES_[en|crypt] routines, which differs from +# above by 4 and overlaps by %ebp backing store +$_tbl=&DWP(24,"esp"); +$_esp=&DWP(28,"esp"); + +sub _data_word() { my $i; while(defined($i=shift)) { &data_word($i,$i); } } + +$speed_limit=512; # chunks smaller than $speed_limit are + # processed with compact routine in CBC mode +$small_footprint=1; # $small_footprint=1 code is ~5% slower [on + # recent µ-archs], but ~5 times smaller! + # I favor compact code to minimize cache + # contention and in hope to "collect" 5% back + # in real-life applications... + +$vertical_spin=0; # shift "verticaly" defaults to 0, because of + # its proof-of-concept status... +# Note that there is no decvert(), as well as last encryption round is +# performed with "horizontal" shifts. This is because this "vertical" +# implementation [one which groups shifts on a given $s[i] to form a +# "column," unlike "horizontal" one, which groups shifts on different +# $s[i] to form a "row"] is work in progress. It was observed to run +# few percents faster on Intel cores, but not AMD. On AMD K8 core it's +# whole 12% slower:-( So we face a trade-off... Shall it be resolved +# some day? Till then the code is considered experimental and by +# default remains dormant... + +sub encvert() +{ my ($te,@s) = @_; + my ($v0,$v1) = ($acc,$key); + + &mov ($v0,$s[3]); # copy s3 + &mov (&DWP(4,"esp"),$s[2]); # save s2 + &mov ($v1,$s[0]); # copy s0 + &mov (&DWP(8,"esp"),$s[1]); # save s1 + + &movz ($s[2],&HB($s[0])); + &and ($s[0],0xFF); + &mov ($s[0],&DWP(0,$te,$s[0],8)); # s0>>0 + &shr ($v1,16); + &mov ($s[3],&DWP(3,$te,$s[2],8)); # s0>>8 + &movz ($s[1],&HB($v1)); + &and ($v1,0xFF); + &mov ($s[2],&DWP(2,$te,$v1,8)); # s0>>16 + &mov ($v1,$v0); + &mov ($s[1],&DWP(1,$te,$s[1],8)); # s0>>24 + + &and ($v0,0xFF); + &xor ($s[3],&DWP(0,$te,$v0,8)); # s3>>0 + &movz ($v0,&HB($v1)); + &shr ($v1,16); + &xor ($s[2],&DWP(3,$te,$v0,8)); # s3>>8 + &movz ($v0,&HB($v1)); + &and ($v1,0xFF); + &xor ($s[1],&DWP(2,$te,$v1,8)); # s3>>16 + &mov ($v1,&DWP(4,"esp")); # restore s2 + &xor ($s[0],&DWP(1,$te,$v0,8)); # s3>>24 + + &mov ($v0,$v1); + &and ($v1,0xFF); + &xor ($s[2],&DWP(0,$te,$v1,8)); # s2>>0 + &movz ($v1,&HB($v0)); + &shr ($v0,16); + &xor ($s[1],&DWP(3,$te,$v1,8)); # s2>>8 + &movz ($v1,&HB($v0)); + &and ($v0,0xFF); + &xor ($s[0],&DWP(2,$te,$v0,8)); # s2>>16 + &mov ($v0,&DWP(8,"esp")); # restore s1 + &xor ($s[3],&DWP(1,$te,$v1,8)); # s2>>24 + + &mov ($v1,$v0); + &and ($v0,0xFF); + &xor ($s[1],&DWP(0,$te,$v0,8)); # s1>>0 + &movz ($v0,&HB($v1)); + &shr ($v1,16); + &xor ($s[0],&DWP(3,$te,$v0,8)); # s1>>8 + &movz ($v0,&HB($v1)); + &and ($v1,0xFF); + &xor ($s[3],&DWP(2,$te,$v1,8)); # s1>>16 + &mov ($key,$__key); # reincarnate v1 as key + &xor ($s[2],&DWP(1,$te,$v0,8)); # s1>>24 +} + +# Another experimental routine, which features "horizontal spin," but +# eliminates one reference to stack. Strangely enough runs slower... +sub enchoriz() +{ my ($v0,$v1) = ($key,$acc); + + &movz ($v0,&LB($s0)); # 3, 2, 1, 0* + &rotr ($s2,8); # 8,11,10, 9 + &mov ($v1,&DWP(0,$te,$v0,8)); # 0 + &movz ($v0,&HB($s1)); # 7, 6, 5*, 4 + &rotr ($s3,16); # 13,12,15,14 + &xor ($v1,&DWP(3,$te,$v0,8)); # 5 + &movz ($v0,&HB($s2)); # 8,11,10*, 9 + &rotr ($s0,16); # 1, 0, 3, 2 + &xor ($v1,&DWP(2,$te,$v0,8)); # 10 + &movz ($v0,&HB($s3)); # 13,12,15*,14 + &xor ($v1,&DWP(1,$te,$v0,8)); # 15, t[0] collected + &mov ($__s0,$v1); # t[0] saved + + &movz ($v0,&LB($s1)); # 7, 6, 5, 4* + &shr ($s1,16); # -, -, 7, 6 + &mov ($v1,&DWP(0,$te,$v0,8)); # 4 + &movz ($v0,&LB($s3)); # 13,12,15,14* + &xor ($v1,&DWP(2,$te,$v0,8)); # 14 + &movz ($v0,&HB($s0)); # 1, 0, 3*, 2 + &and ($s3,0xffff0000); # 13,12, -, - + &xor ($v1,&DWP(1,$te,$v0,8)); # 3 + &movz ($v0,&LB($s2)); # 8,11,10, 9* + &or ($s3,$s1); # 13,12, 7, 6 + &xor ($v1,&DWP(3,$te,$v0,8)); # 9, t[1] collected + &mov ($s1,$v1); # s[1]=t[1] + + &movz ($v0,&LB($s0)); # 1, 0, 3, 2* + &shr ($s2,16); # -, -, 8,11 + &mov ($v1,&DWP(2,$te,$v0,8)); # 2 + &movz ($v0,&HB($s3)); # 13,12, 7*, 6 + &xor ($v1,&DWP(1,$te,$v0,8)); # 7 + &movz ($v0,&HB($s2)); # -, -, 8*,11 + &xor ($v1,&DWP(0,$te,$v0,8)); # 8 + &mov ($v0,$s3); + &shr ($v0,24); # 13 + &xor ($v1,&DWP(3,$te,$v0,8)); # 13, t[2] collected + + &movz ($v0,&LB($s2)); # -, -, 8,11* + &shr ($s0,24); # 1* + &mov ($s2,&DWP(1,$te,$v0,8)); # 11 + &xor ($s2,&DWP(3,$te,$s0,8)); # 1 + &mov ($s0,$__s0); # s[0]=t[0] + &movz ($v0,&LB($s3)); # 13,12, 7, 6* + &shr ($s3,16); # , ,13,12 + &xor ($s2,&DWP(2,$te,$v0,8)); # 6 + &mov ($key,$__key); # reincarnate v0 as key + &and ($s3,0xff); # , ,13,12* + &mov ($s3,&DWP(0,$te,$s3,8)); # 12 + &xor ($s3,$s2); # s[2]=t[3] collected + &mov ($s2,$v1); # s[2]=t[2] +} + +# More experimental code... SSE one... Even though this one eliminates +# *all* references to stack, it's not faster... +sub sse_encbody() +{ + &movz ($acc,&LB("eax")); # 0 + &mov ("ecx",&DWP(0,$tbl,$acc,8)); # 0 + &pshufw ("mm2","mm0",0x0d); # 7, 6, 3, 2 + &movz ("edx",&HB("eax")); # 1 + &mov ("edx",&DWP(3,$tbl,"edx",8)); # 1 + &shr ("eax",16); # 5, 4 + + &movz ($acc,&LB("ebx")); # 10 + &xor ("ecx",&DWP(2,$tbl,$acc,8)); # 10 + &pshufw ("mm6","mm4",0x08); # 13,12, 9, 8 + &movz ($acc,&HB("ebx")); # 11 + &xor ("edx",&DWP(1,$tbl,$acc,8)); # 11 + &shr ("ebx",16); # 15,14 + + &movz ($acc,&HB("eax")); # 5 + &xor ("ecx",&DWP(3,$tbl,$acc,8)); # 5 + &movq ("mm3",QWP(16,$key)); + &movz ($acc,&HB("ebx")); # 15 + &xor ("ecx",&DWP(1,$tbl,$acc,8)); # 15 + &movd ("mm0","ecx"); # t[0] collected + + &movz ($acc,&LB("eax")); # 4 + &mov ("ecx",&DWP(0,$tbl,$acc,8)); # 4 + &movd ("eax","mm2"); # 7, 6, 3, 2 + &movz ($acc,&LB("ebx")); # 14 + &xor ("ecx",&DWP(2,$tbl,$acc,8)); # 14 + &movd ("ebx","mm6"); # 13,12, 9, 8 + + &movz ($acc,&HB("eax")); # 3 + &xor ("ecx",&DWP(1,$tbl,$acc,8)); # 3 + &movz ($acc,&HB("ebx")); # 9 + &xor ("ecx",&DWP(3,$tbl,$acc,8)); # 9 + &movd ("mm1","ecx"); # t[1] collected + + &movz ($acc,&LB("eax")); # 2 + &mov ("ecx",&DWP(2,$tbl,$acc,8)); # 2 + &shr ("eax",16); # 7, 6 + &punpckldq ("mm0","mm1"); # t[0,1] collected + &movz ($acc,&LB("ebx")); # 8 + &xor ("ecx",&DWP(0,$tbl,$acc,8)); # 8 + &shr ("ebx",16); # 13,12 + + &movz ($acc,&HB("eax")); # 7 + &xor ("ecx",&DWP(1,$tbl,$acc,8)); # 7 + &pxor ("mm0","mm3"); + &movz ("eax",&LB("eax")); # 6 + &xor ("edx",&DWP(2,$tbl,"eax",8)); # 6 + &pshufw ("mm1","mm0",0x08); # 5, 4, 1, 0 + &movz ($acc,&HB("ebx")); # 13 + &xor ("ecx",&DWP(3,$tbl,$acc,8)); # 13 + &xor ("ecx",&DWP(24,$key)); # t[2] + &movd ("mm4","ecx"); # t[2] collected + &movz ("ebx",&LB("ebx")); # 12 + &xor ("edx",&DWP(0,$tbl,"ebx",8)); # 12 + &shr ("ecx",16); + &movd ("eax","mm1"); # 5, 4, 1, 0 + &mov ("ebx",&DWP(28,$key)); # t[3] + &xor ("ebx","edx"); + &movd ("mm5","ebx"); # t[3] collected + &and ("ebx",0xffff0000); + &or ("ebx","ecx"); + + &punpckldq ("mm4","mm5"); # t[2,3] collected +} + +###################################################################### +# "Compact" block function +###################################################################### + +sub enccompact() +{ my $Fn = \&mov; + while ($#_>5) { pop(@_); $Fn=sub{}; } + my ($i,$te,@s)=@_; + my $tmp = $key; + my $out = $i==3?$s[0]:$acc; + + # $Fn is used in first compact round and its purpose is to + # void restoration of some values from stack, so that after + # 4xenccompact with extra argument $key value is left there... + if ($i==3) { &$Fn ($key,$__key); }##%edx + else { &mov ($out,$s[0]); } + &and ($out,0xFF); + if ($i==1) { &shr ($s[0],16); }#%ebx[1] + if ($i==2) { &shr ($s[0],24); }#%ecx[2] + &movz ($out,&BP(-128,$te,$out,1)); + + if ($i==3) { $tmp=$s[1]; }##%eax + &movz ($tmp,&HB($s[1])); + &movz ($tmp,&BP(-128,$te,$tmp,1)); + &shl ($tmp,8); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[2]; &mov ($s[1],$__s0); }##%ebx + else { &mov ($tmp,$s[2]); + &shr ($tmp,16); } + if ($i==2) { &and ($s[1],0xFF); }#%edx[2] + &and ($tmp,0xFF); + &movz ($tmp,&BP(-128,$te,$tmp,1)); + &shl ($tmp,16); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); }##%ecx + elsif($i==2){ &movz ($tmp,&HB($s[3])); }#%ebx[2] + else { &mov ($tmp,$s[3]); + &shr ($tmp,24); } + &movz ($tmp,&BP(-128,$te,$tmp,1)); + &shl ($tmp,24); + &xor ($out,$tmp); + if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); } + if ($i==3) { &mov ($s[3],$acc); } + &comment(); +} + +sub enctransform() +{ my @s = ($s0,$s1,$s2,$s3); + my $i = shift; + my $tmp = $tbl; + my $r2 = $key ; + + &and ($tmp,$s[$i]); + &lea ($r2,&DWP(0,$s[$i],$s[$i])); + &mov ($acc,$tmp); + &shr ($tmp,7); + &and ($r2,0xfefefefe); + &sub ($acc,$tmp); + &mov ($tmp,$s[$i]); + &and ($acc,0x1b1b1b1b); + &rotr ($tmp,16); + &xor ($acc,$r2); # r2 + &mov ($r2,$s[$i]); + + &xor ($s[$i],$acc); # r0 ^ r2 + &rotr ($r2,16+8); + &xor ($acc,$tmp); + &rotl ($s[$i],24); + &xor ($acc,$r2); + &mov ($tmp,0x80808080) if ($i!=1); + &xor ($s[$i],$acc); # ROTATE(r2^r0,24) ^ r2 +} + +&function_begin_B("_x86_AES_encrypt_compact"); + # note that caller is expected to allocate stack frame for me! + &mov ($__key,$key); # save key + + &xor ($s0,&DWP(0,$key)); # xor with key + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &mov ($acc,&DWP(240,$key)); # load key->rounds + &lea ($acc,&DWP(-2,$acc,$acc)); + &lea ($acc,&DWP(0,$key,$acc,8)); + &mov ($__end,$acc); # end of key schedule + + # prefetch Te4 + &mov ($key,&DWP(0-128,$tbl)); + &mov ($acc,&DWP(32-128,$tbl)); + &mov ($key,&DWP(64-128,$tbl)); + &mov ($acc,&DWP(96-128,$tbl)); + &mov ($key,&DWP(128-128,$tbl)); + &mov ($acc,&DWP(160-128,$tbl)); + &mov ($key,&DWP(192-128,$tbl)); + &mov ($acc,&DWP(224-128,$tbl)); + + &set_label("loop",16); + + &enccompact(0,$tbl,$s0,$s1,$s2,$s3,1); + &enccompact(1,$tbl,$s1,$s2,$s3,$s0,1); + &enccompact(2,$tbl,$s2,$s3,$s0,$s1,1); + &enccompact(3,$tbl,$s3,$s0,$s1,$s2,1); + &mov ($tbl,0x80808080); + &enctransform(2); + &enctransform(3); + &enctransform(0); + &enctransform(1); + &mov ($key,$__key); + &mov ($tbl,$__tbl); + &add ($key,16); # advance rd_key + &xor ($s0,&DWP(0,$key)); + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &cmp ($key,$__end); + &mov ($__key,$key); + &jb (&label("loop")); + + &enccompact(0,$tbl,$s0,$s1,$s2,$s3); + &enccompact(1,$tbl,$s1,$s2,$s3,$s0); + &enccompact(2,$tbl,$s2,$s3,$s0,$s1); + &enccompact(3,$tbl,$s3,$s0,$s1,$s2); + + &xor ($s0,&DWP(16,$key)); + &xor ($s1,&DWP(20,$key)); + &xor ($s2,&DWP(24,$key)); + &xor ($s3,&DWP(28,$key)); + + &ret (); +&function_end_B("_x86_AES_encrypt_compact"); + +###################################################################### +# "Compact" SSE block function. +###################################################################### +# +# Performance is not actually extraordinary in comparison to pure +# x86 code. In particular encrypt performance is virtually the same. +# Decrypt performance on the other hand is 15-20% better on newer +# µ-archs [but we're thankful for *any* improvement here], and ~50% +# better on PIII:-) And additionally on the pros side this code +# eliminates redundant references to stack and thus relieves/ +# minimizes the pressure on the memory bus. +# +# MMX register layout lsb +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | mm4 | mm0 | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# | s3 | s2 | s1 | s0 | +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| +# +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ +# +# Indexes translate as s[N/4]>>(8*(N%4)), e.g. 5 means s1>>8. +# In this terms encryption and decryption "compact" permutation +# matrices can be depicted as following: +# +# encryption lsb # decryption lsb +# +----++----+----+----+----+ # +----++----+----+----+----+ +# | t0 || 15 | 10 | 5 | 0 | # | t0 || 7 | 10 | 13 | 0 | +# +----++----+----+----+----+ # +----++----+----+----+----+ +# | t1 || 3 | 14 | 9 | 4 | # | t1 || 11 | 14 | 1 | 4 | +# +----++----+----+----+----+ # +----++----+----+----+----+ +# | t2 || 7 | 2 | 13 | 8 | # | t2 || 15 | 2 | 5 | 8 | +# +----++----+----+----+----+ # +----++----+----+----+----+ +# | t3 || 11 | 6 | 1 | 12 | # | t3 || 3 | 6 | 9 | 12 | +# +----++----+----+----+----+ # +----++----+----+----+----+ +# +###################################################################### +# Why not xmm registers? Short answer. It was actually tested and +# was not any faster, but *contrary*, most notably on Intel CPUs. +# Longer answer. Main advantage of using mm registers is that movd +# latency is lower, especially on Intel P4. While arithmetic +# instructions are twice as many, they can be scheduled every cycle +# and not every second one when they are operating on xmm register, +# so that "arithmetic throughput" remains virtually the same. And +# finally the code can be executed even on elder SSE-only CPUs:-) + +sub sse_enccompact() +{ + &pshufw ("mm1","mm0",0x08); # 5, 4, 1, 0 + &pshufw ("mm5","mm4",0x0d); # 15,14,11,10 + &movd ("eax","mm1"); # 5, 4, 1, 0 + &movd ("ebx","mm5"); # 15,14,11,10 + &mov ($__key,$key); + + &movz ($acc,&LB("eax")); # 0 + &movz ("edx",&HB("eax")); # 1 + &pshufw ("mm2","mm0",0x0d); # 7, 6, 3, 2 + &movz ("ecx",&BP(-128,$tbl,$acc,1)); # 0 + &movz ($key,&LB("ebx")); # 10 + &movz ("edx",&BP(-128,$tbl,"edx",1)); # 1 + &shr ("eax",16); # 5, 4 + &shl ("edx",8); # 1 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 10 + &movz ($key,&HB("ebx")); # 11 + &shl ($acc,16); # 10 + &pshufw ("mm6","mm4",0x08); # 13,12, 9, 8 + &or ("ecx",$acc); # 10 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 11 + &movz ($key,&HB("eax")); # 5 + &shl ($acc,24); # 11 + &shr ("ebx",16); # 15,14 + &or ("edx",$acc); # 11 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 5 + &movz ($key,&HB("ebx")); # 15 + &shl ($acc,8); # 5 + &or ("ecx",$acc); # 5 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 15 + &movz ($key,&LB("eax")); # 4 + &shl ($acc,24); # 15 + &or ("ecx",$acc); # 15 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 4 + &movz ($key,&LB("ebx")); # 14 + &movd ("eax","mm2"); # 7, 6, 3, 2 + &movd ("mm0","ecx"); # t[0] collected + &movz ("ecx",&BP(-128,$tbl,$key,1)); # 14 + &movz ($key,&HB("eax")); # 3 + &shl ("ecx",16); # 14 + &movd ("ebx","mm6"); # 13,12, 9, 8 + &or ("ecx",$acc); # 14 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 3 + &movz ($key,&HB("ebx")); # 9 + &shl ($acc,24); # 3 + &or ("ecx",$acc); # 3 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 9 + &movz ($key,&LB("ebx")); # 8 + &shl ($acc,8); # 9 + &shr ("ebx",16); # 13,12 + &or ("ecx",$acc); # 9 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 8 + &movz ($key,&LB("eax")); # 2 + &shr ("eax",16); # 7, 6 + &movd ("mm1","ecx"); # t[1] collected + &movz ("ecx",&BP(-128,$tbl,$key,1)); # 2 + &movz ($key,&HB("eax")); # 7 + &shl ("ecx",16); # 2 + &and ("eax",0xff); # 6 + &or ("ecx",$acc); # 2 + + &punpckldq ("mm0","mm1"); # t[0,1] collected + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 7 + &movz ($key,&HB("ebx")); # 13 + &shl ($acc,24); # 7 + &and ("ebx",0xff); # 12 + &movz ("eax",&BP(-128,$tbl,"eax",1)); # 6 + &or ("ecx",$acc); # 7 + &shl ("eax",16); # 6 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 13 + &or ("edx","eax"); # 6 + &shl ($acc,8); # 13 + &movz ("ebx",&BP(-128,$tbl,"ebx",1)); # 12 + &or ("ecx",$acc); # 13 + &or ("edx","ebx"); # 12 + &mov ($key,$__key); + &movd ("mm4","ecx"); # t[2] collected + &movd ("mm5","edx"); # t[3] collected + + &punpckldq ("mm4","mm5"); # t[2,3] collected +} + + if (!$x86only) { +&function_begin_B("_sse_AES_encrypt_compact"); + &pxor ("mm0",&QWP(0,$key)); # 7, 6, 5, 4, 3, 2, 1, 0 + &pxor ("mm4",&QWP(8,$key)); # 15,14,13,12,11,10, 9, 8 + + # note that caller is expected to allocate stack frame for me! + &mov ($acc,&DWP(240,$key)); # load key->rounds + &lea ($acc,&DWP(-2,$acc,$acc)); + &lea ($acc,&DWP(0,$key,$acc,8)); + &mov ($__end,$acc); # end of key schedule + + &mov ($s0,0x1b1b1b1b); # magic constant + &mov (&DWP(8,"esp"),$s0); + &mov (&DWP(12,"esp"),$s0); + + # prefetch Te4 + &mov ($s0,&DWP(0-128,$tbl)); + &mov ($s1,&DWP(32-128,$tbl)); + &mov ($s2,&DWP(64-128,$tbl)); + &mov ($s3,&DWP(96-128,$tbl)); + &mov ($s0,&DWP(128-128,$tbl)); + &mov ($s1,&DWP(160-128,$tbl)); + &mov ($s2,&DWP(192-128,$tbl)); + &mov ($s3,&DWP(224-128,$tbl)); + + &set_label("loop",16); + &sse_enccompact(); + &add ($key,16); + &cmp ($key,$__end); + &ja (&label("out")); + + &movq ("mm2",&QWP(8,"esp")); + &pxor ("mm3","mm3"); &pxor ("mm7","mm7"); + &movq ("mm1","mm0"); &movq ("mm5","mm4"); # r0 + &pcmpgtb("mm3","mm0"); &pcmpgtb("mm7","mm4"); + &pand ("mm3","mm2"); &pand ("mm7","mm2"); + &pshufw ("mm2","mm0",0xb1); &pshufw ("mm6","mm4",0xb1);# ROTATE(r0,16) + &paddb ("mm0","mm0"); &paddb ("mm4","mm4"); + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # = r2 + &pshufw ("mm3","mm2",0xb1); &pshufw ("mm7","mm6",0xb1);# r0 + &pxor ("mm1","mm0"); &pxor ("mm5","mm4"); # r0^r2 + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= ROTATE(r0,16) + + &movq ("mm2","mm3"); &movq ("mm6","mm7"); + &pslld ("mm3",8); &pslld ("mm7",8); + &psrld ("mm2",24); &psrld ("mm6",24); + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= r0<<8 + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= r0>>24 + + &movq ("mm3","mm1"); &movq ("mm7","mm5"); + &movq ("mm2",&QWP(0,$key)); &movq ("mm6",&QWP(8,$key)); + &psrld ("mm1",8); &psrld ("mm5",8); + &mov ($s0,&DWP(0-128,$tbl)); + &pslld ("mm3",24); &pslld ("mm7",24); + &mov ($s1,&DWP(64-128,$tbl)); + &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= (r2^r0)<<8 + &mov ($s2,&DWP(128-128,$tbl)); + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= (r2^r0)>>24 + &mov ($s3,&DWP(192-128,$tbl)); + + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); + &jmp (&label("loop")); + + &set_label("out",16); + &pxor ("mm0",&QWP(0,$key)); + &pxor ("mm4",&QWP(8,$key)); + + &ret (); +&function_end_B("_sse_AES_encrypt_compact"); + } + +###################################################################### +# Vanilla block function. +###################################################################### + +sub encstep() +{ my ($i,$te,@s) = @_; + my $tmp = $key; + my $out = $i==3?$s[0]:$acc; + + # lines marked with #%e?x[i] denote "reordered" instructions... + if ($i==3) { &mov ($key,$__key); }##%edx + else { &mov ($out,$s[0]); + &and ($out,0xFF); } + if ($i==1) { &shr ($s[0],16); }#%ebx[1] + if ($i==2) { &shr ($s[0],24); }#%ecx[2] + &mov ($out,&DWP(0,$te,$out,8)); + + if ($i==3) { $tmp=$s[1]; }##%eax + &movz ($tmp,&HB($s[1])); + &xor ($out,&DWP(3,$te,$tmp,8)); + + if ($i==3) { $tmp=$s[2]; &mov ($s[1],$__s0); }##%ebx + else { &mov ($tmp,$s[2]); + &shr ($tmp,16); } + if ($i==2) { &and ($s[1],0xFF); }#%edx[2] + &and ($tmp,0xFF); + &xor ($out,&DWP(2,$te,$tmp,8)); + + if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); }##%ecx + elsif($i==2){ &movz ($tmp,&HB($s[3])); }#%ebx[2] + else { &mov ($tmp,$s[3]); + &shr ($tmp,24) } + &xor ($out,&DWP(1,$te,$tmp,8)); + if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); } + if ($i==3) { &mov ($s[3],$acc); } + &comment(); +} + +sub enclast() +{ my ($i,$te,@s)=@_; + my $tmp = $key; + my $out = $i==3?$s[0]:$acc; + + if ($i==3) { &mov ($key,$__key); }##%edx + else { &mov ($out,$s[0]); } + &and ($out,0xFF); + if ($i==1) { &shr ($s[0],16); }#%ebx[1] + if ($i==2) { &shr ($s[0],24); }#%ecx[2] + &mov ($out,&DWP(2,$te,$out,8)); + &and ($out,0x000000ff); + + if ($i==3) { $tmp=$s[1]; }##%eax + &movz ($tmp,&HB($s[1])); + &mov ($tmp,&DWP(0,$te,$tmp,8)); + &and ($tmp,0x0000ff00); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[2]; &mov ($s[1],$__s0); }##%ebx + else { &mov ($tmp,$s[2]); + &shr ($tmp,16); } + if ($i==2) { &and ($s[1],0xFF); }#%edx[2] + &and ($tmp,0xFF); + &mov ($tmp,&DWP(0,$te,$tmp,8)); + &and ($tmp,0x00ff0000); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); }##%ecx + elsif($i==2){ &movz ($tmp,&HB($s[3])); }#%ebx[2] + else { &mov ($tmp,$s[3]); + &shr ($tmp,24); } + &mov ($tmp,&DWP(2,$te,$tmp,8)); + &and ($tmp,0xff000000); + &xor ($out,$tmp); + if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); } + if ($i==3) { &mov ($s[3],$acc); } +} + +&function_begin_B("_x86_AES_encrypt"); + if ($vertical_spin) { + # I need high parts of volatile registers to be accessible... + &exch ($s1="edi",$key="ebx"); + &mov ($s2="esi",$acc="ecx"); + } + + # note that caller is expected to allocate stack frame for me! + &mov ($__key,$key); # save key + + &xor ($s0,&DWP(0,$key)); # xor with key + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &mov ($acc,&DWP(240,$key)); # load key->rounds + + if ($small_footprint) { + &lea ($acc,&DWP(-2,$acc,$acc)); + &lea ($acc,&DWP(0,$key,$acc,8)); + &mov ($__end,$acc); # end of key schedule + + &set_label("loop",16); + if ($vertical_spin) { + &encvert($tbl,$s0,$s1,$s2,$s3); + } else { + &encstep(0,$tbl,$s0,$s1,$s2,$s3); + &encstep(1,$tbl,$s1,$s2,$s3,$s0); + &encstep(2,$tbl,$s2,$s3,$s0,$s1); + &encstep(3,$tbl,$s3,$s0,$s1,$s2); + } + &add ($key,16); # advance rd_key + &xor ($s0,&DWP(0,$key)); + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + &cmp ($key,$__end); + &mov ($__key,$key); + &jb (&label("loop")); + } + else { + &cmp ($acc,10); + &jle (&label("10rounds")); + &cmp ($acc,12); + &jle (&label("12rounds")); + + &set_label("14rounds",4); + for ($i=1;$i<3;$i++) { + if ($vertical_spin) { + &encvert($tbl,$s0,$s1,$s2,$s3); + } else { + &encstep(0,$tbl,$s0,$s1,$s2,$s3); + &encstep(1,$tbl,$s1,$s2,$s3,$s0); + &encstep(2,$tbl,$s2,$s3,$s0,$s1); + &encstep(3,$tbl,$s3,$s0,$s1,$s2); + } + &xor ($s0,&DWP(16*$i+0,$key)); + &xor ($s1,&DWP(16*$i+4,$key)); + &xor ($s2,&DWP(16*$i+8,$key)); + &xor ($s3,&DWP(16*$i+12,$key)); + } + &add ($key,32); + &mov ($__key,$key); # advance rd_key + &set_label("12rounds",4); + for ($i=1;$i<3;$i++) { + if ($vertical_spin) { + &encvert($tbl,$s0,$s1,$s2,$s3); + } else { + &encstep(0,$tbl,$s0,$s1,$s2,$s3); + &encstep(1,$tbl,$s1,$s2,$s3,$s0); + &encstep(2,$tbl,$s2,$s3,$s0,$s1); + &encstep(3,$tbl,$s3,$s0,$s1,$s2); + } + &xor ($s0,&DWP(16*$i+0,$key)); + &xor ($s1,&DWP(16*$i+4,$key)); + &xor ($s2,&DWP(16*$i+8,$key)); + &xor ($s3,&DWP(16*$i+12,$key)); + } + &add ($key,32); + &mov ($__key,$key); # advance rd_key + &set_label("10rounds",4); + for ($i=1;$i<10;$i++) { + if ($vertical_spin) { + &encvert($tbl,$s0,$s1,$s2,$s3); + } else { + &encstep(0,$tbl,$s0,$s1,$s2,$s3); + &encstep(1,$tbl,$s1,$s2,$s3,$s0); + &encstep(2,$tbl,$s2,$s3,$s0,$s1); + &encstep(3,$tbl,$s3,$s0,$s1,$s2); + } + &xor ($s0,&DWP(16*$i+0,$key)); + &xor ($s1,&DWP(16*$i+4,$key)); + &xor ($s2,&DWP(16*$i+8,$key)); + &xor ($s3,&DWP(16*$i+12,$key)); + } + } + + if ($vertical_spin) { + # "reincarnate" some registers for "horizontal" spin... + &mov ($s1="ebx",$key="edi"); + &mov ($s2="ecx",$acc="esi"); + } + &enclast(0,$tbl,$s0,$s1,$s2,$s3); + &enclast(1,$tbl,$s1,$s2,$s3,$s0); + &enclast(2,$tbl,$s2,$s3,$s0,$s1); + &enclast(3,$tbl,$s3,$s0,$s1,$s2); + + &add ($key,$small_footprint?16:160); + &xor ($s0,&DWP(0,$key)); + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &ret (); + +&set_label("AES_Te",64); # Yes! I keep it in the code segment! + &_data_word(0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6); + &_data_word(0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591); + &_data_word(0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56); + &_data_word(0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec); + &_data_word(0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa); + &_data_word(0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb); + &_data_word(0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45); + &_data_word(0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b); + &_data_word(0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c); + &_data_word(0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83); + &_data_word(0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9); + &_data_word(0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a); + &_data_word(0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d); + &_data_word(0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f); + &_data_word(0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df); + &_data_word(0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea); + &_data_word(0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34); + &_data_word(0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b); + &_data_word(0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d); + &_data_word(0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413); + &_data_word(0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1); + &_data_word(0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6); + &_data_word(0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972); + &_data_word(0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85); + &_data_word(0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed); + &_data_word(0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511); + &_data_word(0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe); + &_data_word(0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b); + &_data_word(0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05); + &_data_word(0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1); + &_data_word(0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142); + &_data_word(0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf); + &_data_word(0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3); + &_data_word(0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e); + &_data_word(0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a); + &_data_word(0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6); + &_data_word(0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3); + &_data_word(0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b); + &_data_word(0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428); + &_data_word(0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad); + &_data_word(0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14); + &_data_word(0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8); + &_data_word(0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4); + &_data_word(0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2); + &_data_word(0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda); + &_data_word(0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949); + &_data_word(0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf); + &_data_word(0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810); + &_data_word(0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c); + &_data_word(0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697); + &_data_word(0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e); + &_data_word(0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f); + &_data_word(0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc); + &_data_word(0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c); + &_data_word(0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969); + &_data_word(0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27); + &_data_word(0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122); + &_data_word(0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433); + &_data_word(0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9); + &_data_word(0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5); + &_data_word(0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a); + &_data_word(0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0); + &_data_word(0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e); + &_data_word(0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c); + +#Te4 # four copies of Te4 to choose from to avoid L1 aliasing + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); + + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); + + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); + + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); +#rcon: + &data_word(0x00000001, 0x00000002, 0x00000004, 0x00000008); + &data_word(0x00000010, 0x00000020, 0x00000040, 0x00000080); + &data_word(0x0000001b, 0x00000036, 0x00000000, 0x00000000); + &data_word(0x00000000, 0x00000000, 0x00000000, 0x00000000); +&function_end_B("_x86_AES_encrypt"); + +# void asm_AES_encrypt (const void *inp,void *out,const AES_KEY *key); +&function_begin("asm_AES_encrypt"); + &mov ($acc,&wparam(0)); # load inp + &mov ($key,&wparam(2)); # load key + + &mov ($s0,"esp"); + &sub ("esp",36); + &and ("esp",-64); # align to cache-line + + # place stack frame just "above" the key schedule + &lea ($s1,&DWP(-64-63,$key)); + &sub ($s1,"esp"); + &neg ($s1); + &and ($s1,0x3C0); # modulo 1024, but aligned to cache-line + &sub ("esp",$s1); + &add ("esp",4); # 4 is reserved for caller's return address + &mov ($_esp,$s0); # save stack pointer + + &call (&label("pic_point")); # make it PIC! + &set_label("pic_point"); + &blindpop($tbl); + &picmeup($s0,"OPENSSL_ia32cap_P",$tbl,&label("pic_point")) if (!$x86only); + &lea ($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl)); + + # pick Te4 copy which can't "overlap" with stack frame or key schedule + &lea ($s1,&DWP(768-4,"esp")); + &sub ($s1,$tbl); + &and ($s1,0x300); + &lea ($tbl,&DWP(2048+128,$tbl,$s1)); + + if (!$x86only) { + &bt (&DWP(0,$s0),25); # check for SSE bit + &jnc (&label("x86")); + + &movq ("mm0",&QWP(0,$acc)); + &movq ("mm4",&QWP(8,$acc)); + &call ("_sse_AES_encrypt_compact"); + &mov ("esp",$_esp); # restore stack pointer + &mov ($acc,&wparam(1)); # load out + &movq (&QWP(0,$acc),"mm0"); # write output data + &movq (&QWP(8,$acc),"mm4"); + &emms (); + &function_end_A(); + } + &set_label("x86",16); + &mov ($_tbl,$tbl); + &mov ($s0,&DWP(0,$acc)); # load input data + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + &call ("_x86_AES_encrypt_compact"); + &mov ("esp",$_esp); # restore stack pointer + &mov ($acc,&wparam(1)); # load out + &mov (&DWP(0,$acc),$s0); # write output data + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); +&function_end("asm_AES_encrypt"); + +#--------------------------------------------------------------------# + +###################################################################### +# "Compact" block function +###################################################################### + +sub deccompact() +{ my $Fn = \&mov; + while ($#_>5) { pop(@_); $Fn=sub{}; } + my ($i,$td,@s)=@_; + my $tmp = $key; + my $out = $i==3?$s[0]:$acc; + + # $Fn is used in first compact round and its purpose is to + # void restoration of some values from stack, so that after + # 4xdeccompact with extra argument $key, $s0 and $s1 values + # are left there... + if($i==3) { &$Fn ($key,$__key); } + else { &mov ($out,$s[0]); } + &and ($out,0xFF); + &movz ($out,&BP(-128,$td,$out,1)); + + if ($i==3) { $tmp=$s[1]; } + &movz ($tmp,&HB($s[1])); + &movz ($tmp,&BP(-128,$td,$tmp,1)); + &shl ($tmp,8); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[2]; &mov ($s[1],$acc); } + else { mov ($tmp,$s[2]); } + &shr ($tmp,16); + &and ($tmp,0xFF); + &movz ($tmp,&BP(-128,$td,$tmp,1)); + &shl ($tmp,16); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[3]; &$Fn ($s[2],$__s1); } + else { &mov ($tmp,$s[3]); } + &shr ($tmp,24); + &movz ($tmp,&BP(-128,$td,$tmp,1)); + &shl ($tmp,24); + &xor ($out,$tmp); + if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); } + if ($i==3) { &$Fn ($s[3],$__s0); } +} + +# must be called with 2,3,0,1 as argument sequence!!! +sub dectransform() +{ my @s = ($s0,$s1,$s2,$s3); + my $i = shift; + my $tmp = $key; + my $tp2 = @s[($i+2)%4]; $tp2 = @s[2] if ($i==1); + my $tp4 = @s[($i+3)%4]; $tp4 = @s[3] if ($i==1); + my $tp8 = $tbl; + + &mov ($tmp,0x80808080); + &and ($tmp,$s[$i]); + &mov ($acc,$tmp); + &shr ($tmp,7); + &lea ($tp2,&DWP(0,$s[$i],$s[$i])); + &sub ($acc,$tmp); + &and ($tp2,0xfefefefe); + &and ($acc,0x1b1b1b1b); + &xor ($tp2,$acc); + &mov ($tmp,0x80808080); + + &and ($tmp,$tp2); + &mov ($acc,$tmp); + &shr ($tmp,7); + &lea ($tp4,&DWP(0,$tp2,$tp2)); + &sub ($acc,$tmp); + &and ($tp4,0xfefefefe); + &and ($acc,0x1b1b1b1b); + &xor ($tp2,$s[$i]); # tp2^tp1 + &xor ($tp4,$acc); + &mov ($tmp,0x80808080); + + &and ($tmp,$tp4); + &mov ($acc,$tmp); + &shr ($tmp,7); + &lea ($tp8,&DWP(0,$tp4,$tp4)); + &sub ($acc,$tmp); + &and ($tp8,0xfefefefe); + &and ($acc,0x1b1b1b1b); + &xor ($tp4,$s[$i]); # tp4^tp1 + &rotl ($s[$i],8); # = ROTATE(tp1,8) + &xor ($tp8,$acc); + + &xor ($s[$i],$tp2); + &xor ($tp2,$tp8); + &xor ($s[$i],$tp4); + &xor ($tp4,$tp8); + &rotl ($tp2,24); + &xor ($s[$i],$tp8); # ^= tp8^(tp4^tp1)^(tp2^tp1) + &rotl ($tp4,16); + &xor ($s[$i],$tp2); # ^= ROTATE(tp8^tp2^tp1,24) + &rotl ($tp8,8); + &xor ($s[$i],$tp4); # ^= ROTATE(tp8^tp4^tp1,16) + &mov ($s[0],$__s0) if($i==2); #prefetch $s0 + &mov ($s[1],$__s1) if($i==3); #prefetch $s1 + &mov ($s[2],$__s2) if($i==1); + &xor ($s[$i],$tp8); # ^= ROTATE(tp8,8) + + &mov ($s[3],$__s3) if($i==1); + &mov (&DWP(4+4*$i,"esp"),$s[$i]) if($i>=2); +} + +&function_begin_B("_x86_AES_decrypt_compact"); + # note that caller is expected to allocate stack frame for me! + &mov ($__key,$key); # save key + + &xor ($s0,&DWP(0,$key)); # xor with key + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &mov ($acc,&DWP(240,$key)); # load key->rounds + + &lea ($acc,&DWP(-2,$acc,$acc)); + &lea ($acc,&DWP(0,$key,$acc,8)); + &mov ($__end,$acc); # end of key schedule + + # prefetch Td4 + &mov ($key,&DWP(0-128,$tbl)); + &mov ($acc,&DWP(32-128,$tbl)); + &mov ($key,&DWP(64-128,$tbl)); + &mov ($acc,&DWP(96-128,$tbl)); + &mov ($key,&DWP(128-128,$tbl)); + &mov ($acc,&DWP(160-128,$tbl)); + &mov ($key,&DWP(192-128,$tbl)); + &mov ($acc,&DWP(224-128,$tbl)); + + &set_label("loop",16); + + &deccompact(0,$tbl,$s0,$s3,$s2,$s1,1); + &deccompact(1,$tbl,$s1,$s0,$s3,$s2,1); + &deccompact(2,$tbl,$s2,$s1,$s0,$s3,1); + &deccompact(3,$tbl,$s3,$s2,$s1,$s0,1); + &dectransform(2); + &dectransform(3); + &dectransform(0); + &dectransform(1); + &mov ($key,$__key); + &mov ($tbl,$__tbl); + &add ($key,16); # advance rd_key + &xor ($s0,&DWP(0,$key)); + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &cmp ($key,$__end); + &mov ($__key,$key); + &jb (&label("loop")); + + &deccompact(0,$tbl,$s0,$s3,$s2,$s1); + &deccompact(1,$tbl,$s1,$s0,$s3,$s2); + &deccompact(2,$tbl,$s2,$s1,$s0,$s3); + &deccompact(3,$tbl,$s3,$s2,$s1,$s0); + + &xor ($s0,&DWP(16,$key)); + &xor ($s1,&DWP(20,$key)); + &xor ($s2,&DWP(24,$key)); + &xor ($s3,&DWP(28,$key)); + + &ret (); +&function_end_B("_x86_AES_decrypt_compact"); + +###################################################################### +# "Compact" SSE block function. +###################################################################### + +sub sse_deccompact() +{ + &pshufw ("mm1","mm0",0x0c); # 7, 6, 1, 0 + &pshufw ("mm5","mm4",0x09); # 13,12,11,10 + &movd ("eax","mm1"); # 7, 6, 1, 0 + &movd ("ebx","mm5"); # 13,12,11,10 + &mov ($__key,$key); + + &movz ($acc,&LB("eax")); # 0 + &movz ("edx",&HB("eax")); # 1 + &pshufw ("mm2","mm0",0x06); # 3, 2, 5, 4 + &movz ("ecx",&BP(-128,$tbl,$acc,1)); # 0 + &movz ($key,&LB("ebx")); # 10 + &movz ("edx",&BP(-128,$tbl,"edx",1)); # 1 + &shr ("eax",16); # 7, 6 + &shl ("edx",8); # 1 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 10 + &movz ($key,&HB("ebx")); # 11 + &shl ($acc,16); # 10 + &pshufw ("mm6","mm4",0x03); # 9, 8,15,14 + &or ("ecx",$acc); # 10 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 11 + &movz ($key,&HB("eax")); # 7 + &shl ($acc,24); # 11 + &shr ("ebx",16); # 13,12 + &or ("edx",$acc); # 11 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 7 + &movz ($key,&HB("ebx")); # 13 + &shl ($acc,24); # 7 + &or ("ecx",$acc); # 7 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 13 + &movz ($key,&LB("eax")); # 6 + &shl ($acc,8); # 13 + &movd ("eax","mm2"); # 3, 2, 5, 4 + &or ("ecx",$acc); # 13 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 6 + &movz ($key,&LB("ebx")); # 12 + &shl ($acc,16); # 6 + &movd ("ebx","mm6"); # 9, 8,15,14 + &movd ("mm0","ecx"); # t[0] collected + &movz ("ecx",&BP(-128,$tbl,$key,1)); # 12 + &movz ($key,&LB("eax")); # 4 + &or ("ecx",$acc); # 12 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 4 + &movz ($key,&LB("ebx")); # 14 + &or ("edx",$acc); # 4 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 14 + &movz ($key,&HB("eax")); # 5 + &shl ($acc,16); # 14 + &shr ("eax",16); # 3, 2 + &or ("edx",$acc); # 14 + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 5 + &movz ($key,&HB("ebx")); # 15 + &shr ("ebx",16); # 9, 8 + &shl ($acc,8); # 5 + &movd ("mm1","edx"); # t[1] collected + &movz ("edx",&BP(-128,$tbl,$key,1)); # 15 + &movz ($key,&HB("ebx")); # 9 + &shl ("edx",24); # 15 + &and ("ebx",0xff); # 8 + &or ("edx",$acc); # 15 + + &punpckldq ("mm0","mm1"); # t[0,1] collected + + &movz ($acc,&BP(-128,$tbl,$key,1)); # 9 + &movz ($key,&LB("eax")); # 2 + &shl ($acc,8); # 9 + &movz ("eax",&HB("eax")); # 3 + &movz ("ebx",&BP(-128,$tbl,"ebx",1)); # 8 + &or ("ecx",$acc); # 9 + &movz ($acc,&BP(-128,$tbl,$key,1)); # 2 + &or ("edx","ebx"); # 8 + &shl ($acc,16); # 2 + &movz ("eax",&BP(-128,$tbl,"eax",1)); # 3 + &or ("edx",$acc); # 2 + &shl ("eax",24); # 3 + &or ("ecx","eax"); # 3 + &mov ($key,$__key); + &movd ("mm4","edx"); # t[2] collected + &movd ("mm5","ecx"); # t[3] collected + + &punpckldq ("mm4","mm5"); # t[2,3] collected +} + + if (!$x86only) { +&function_begin_B("_sse_AES_decrypt_compact"); + &pxor ("mm0",&QWP(0,$key)); # 7, 6, 5, 4, 3, 2, 1, 0 + &pxor ("mm4",&QWP(8,$key)); # 15,14,13,12,11,10, 9, 8 + + # note that caller is expected to allocate stack frame for me! + &mov ($acc,&DWP(240,$key)); # load key->rounds + &lea ($acc,&DWP(-2,$acc,$acc)); + &lea ($acc,&DWP(0,$key,$acc,8)); + &mov ($__end,$acc); # end of key schedule + + &mov ($s0,0x1b1b1b1b); # magic constant + &mov (&DWP(8,"esp"),$s0); + &mov (&DWP(12,"esp"),$s0); + + # prefetch Td4 + &mov ($s0,&DWP(0-128,$tbl)); + &mov ($s1,&DWP(32-128,$tbl)); + &mov ($s2,&DWP(64-128,$tbl)); + &mov ($s3,&DWP(96-128,$tbl)); + &mov ($s0,&DWP(128-128,$tbl)); + &mov ($s1,&DWP(160-128,$tbl)); + &mov ($s2,&DWP(192-128,$tbl)); + &mov ($s3,&DWP(224-128,$tbl)); + + &set_label("loop",16); + &sse_deccompact(); + &add ($key,16); + &cmp ($key,$__end); + &ja (&label("out")); + + # ROTATE(x^y,N) == ROTATE(x,N)^ROTATE(y,N) + &movq ("mm3","mm0"); &movq ("mm7","mm4"); + &movq ("mm2","mm0",1); &movq ("mm6","mm4",1); + &movq ("mm1","mm0"); &movq ("mm5","mm4"); + &pshufw ("mm0","mm0",0xb1); &pshufw ("mm4","mm4",0xb1);# = ROTATE(tp0,16) + &pslld ("mm2",8); &pslld ("mm6",8); + &psrld ("mm3",8); &psrld ("mm7",8); + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= tp0<<8 + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp0>>8 + &pslld ("mm2",16); &pslld ("mm6",16); + &psrld ("mm3",16); &psrld ("mm7",16); + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= tp0<<24 + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp0>>24 + + &movq ("mm3",&QWP(8,"esp")); + &pxor ("mm2","mm2"); &pxor ("mm6","mm6"); + &pcmpgtb("mm2","mm1"); &pcmpgtb("mm6","mm5"); + &pand ("mm2","mm3"); &pand ("mm6","mm3"); + &paddb ("mm1","mm1"); &paddb ("mm5","mm5"); + &pxor ("mm1","mm2"); &pxor ("mm5","mm6"); # tp2 + &movq ("mm3","mm1"); &movq ("mm7","mm5"); + &movq ("mm2","mm1"); &movq ("mm6","mm5"); + &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp2 + &pslld ("mm3",24); &pslld ("mm7",24); + &psrld ("mm2",8); &psrld ("mm6",8); + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp2<<24 + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= tp2>>8 + + &movq ("mm2",&QWP(8,"esp")); + &pxor ("mm3","mm3"); &pxor ("mm7","mm7"); + &pcmpgtb("mm3","mm1"); &pcmpgtb("mm7","mm5"); + &pand ("mm3","mm2"); &pand ("mm7","mm2"); + &paddb ("mm1","mm1"); &paddb ("mm5","mm5"); + &pxor ("mm1","mm3"); &pxor ("mm5","mm7"); # tp4 + &pshufw ("mm3","mm1",0xb1); &pshufw ("mm7","mm5",0xb1); + &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp4 + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= ROTATE(tp4,16) + + &pxor ("mm3","mm3"); &pxor ("mm7","mm7"); + &pcmpgtb("mm3","mm1"); &pcmpgtb("mm7","mm5"); + &pand ("mm3","mm2"); &pand ("mm7","mm2"); + &paddb ("mm1","mm1"); &paddb ("mm5","mm5"); + &pxor ("mm1","mm3"); &pxor ("mm5","mm7"); # tp8 + &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp8 + &movq ("mm3","mm1"); &movq ("mm7","mm5"); + &pshufw ("mm2","mm1",0xb1); &pshufw ("mm6","mm5",0xb1); + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); # ^= ROTATE(tp8,16) + &pslld ("mm1",8); &pslld ("mm5",8); + &psrld ("mm3",8); &psrld ("mm7",8); + &movq ("mm2",&QWP(0,$key)); &movq ("mm6",&QWP(8,$key)); + &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp8<<8 + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp8>>8 + &mov ($s0,&DWP(0-128,$tbl)); + &pslld ("mm1",16); &pslld ("mm5",16); + &mov ($s1,&DWP(64-128,$tbl)); + &psrld ("mm3",16); &psrld ("mm7",16); + &mov ($s2,&DWP(128-128,$tbl)); + &pxor ("mm0","mm1"); &pxor ("mm4","mm5"); # ^= tp8<<24 + &mov ($s3,&DWP(192-128,$tbl)); + &pxor ("mm0","mm3"); &pxor ("mm4","mm7"); # ^= tp8>>24 + + &pxor ("mm0","mm2"); &pxor ("mm4","mm6"); + &jmp (&label("loop")); + + &set_label("out",16); + &pxor ("mm0",&QWP(0,$key)); + &pxor ("mm4",&QWP(8,$key)); + + &ret (); +&function_end_B("_sse_AES_decrypt_compact"); + } + +###################################################################### +# Vanilla block function. +###################################################################### + +sub decstep() +{ my ($i,$td,@s) = @_; + my $tmp = $key; + my $out = $i==3?$s[0]:$acc; + + # no instructions are reordered, as performance appears + # optimal... or rather that all attempts to reorder didn't + # result in better performance [which by the way is not a + # bit lower than ecryption]. + if($i==3) { &mov ($key,$__key); } + else { &mov ($out,$s[0]); } + &and ($out,0xFF); + &mov ($out,&DWP(0,$td,$out,8)); + + if ($i==3) { $tmp=$s[1]; } + &movz ($tmp,&HB($s[1])); + &xor ($out,&DWP(3,$td,$tmp,8)); + + if ($i==3) { $tmp=$s[2]; &mov ($s[1],$acc); } + else { &mov ($tmp,$s[2]); } + &shr ($tmp,16); + &and ($tmp,0xFF); + &xor ($out,&DWP(2,$td,$tmp,8)); + + if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); } + else { &mov ($tmp,$s[3]); } + &shr ($tmp,24); + &xor ($out,&DWP(1,$td,$tmp,8)); + if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); } + if ($i==3) { &mov ($s[3],$__s0); } + &comment(); +} + +sub declast() +{ my ($i,$td,@s)=@_; + my $tmp = $key; + my $out = $i==3?$s[0]:$acc; + + if($i==0) { &lea ($td,&DWP(2048+128,$td)); + &mov ($tmp,&DWP(0-128,$td)); + &mov ($acc,&DWP(32-128,$td)); + &mov ($tmp,&DWP(64-128,$td)); + &mov ($acc,&DWP(96-128,$td)); + &mov ($tmp,&DWP(128-128,$td)); + &mov ($acc,&DWP(160-128,$td)); + &mov ($tmp,&DWP(192-128,$td)); + &mov ($acc,&DWP(224-128,$td)); + &lea ($td,&DWP(-128,$td)); } + if($i==3) { &mov ($key,$__key); } + else { &mov ($out,$s[0]); } + &and ($out,0xFF); + &movz ($out,&BP(0,$td,$out,1)); + + if ($i==3) { $tmp=$s[1]; } + &movz ($tmp,&HB($s[1])); + &movz ($tmp,&BP(0,$td,$tmp,1)); + &shl ($tmp,8); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[2]; &mov ($s[1],$acc); } + else { mov ($tmp,$s[2]); } + &shr ($tmp,16); + &and ($tmp,0xFF); + &movz ($tmp,&BP(0,$td,$tmp,1)); + &shl ($tmp,16); + &xor ($out,$tmp); + + if ($i==3) { $tmp=$s[3]; &mov ($s[2],$__s1); } + else { &mov ($tmp,$s[3]); } + &shr ($tmp,24); + &movz ($tmp,&BP(0,$td,$tmp,1)); + &shl ($tmp,24); + &xor ($out,$tmp); + if ($i<2) { &mov (&DWP(4+4*$i,"esp"),$out); } + if ($i==3) { &mov ($s[3],$__s0); + &lea ($td,&DWP(-2048,$td)); } +} + +&function_begin_B("_x86_AES_decrypt"); + # note that caller is expected to allocate stack frame for me! + &mov ($__key,$key); # save key + + &xor ($s0,&DWP(0,$key)); # xor with key + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &mov ($acc,&DWP(240,$key)); # load key->rounds + + if ($small_footprint) { + &lea ($acc,&DWP(-2,$acc,$acc)); + &lea ($acc,&DWP(0,$key,$acc,8)); + &mov ($__end,$acc); # end of key schedule + &set_label("loop",16); + &decstep(0,$tbl,$s0,$s3,$s2,$s1); + &decstep(1,$tbl,$s1,$s0,$s3,$s2); + &decstep(2,$tbl,$s2,$s1,$s0,$s3); + &decstep(3,$tbl,$s3,$s2,$s1,$s0); + &add ($key,16); # advance rd_key + &xor ($s0,&DWP(0,$key)); + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + &cmp ($key,$__end); + &mov ($__key,$key); + &jb (&label("loop")); + } + else { + &cmp ($acc,10); + &jle (&label("10rounds")); + &cmp ($acc,12); + &jle (&label("12rounds")); + + &set_label("14rounds",4); + for ($i=1;$i<3;$i++) { + &decstep(0,$tbl,$s0,$s3,$s2,$s1); + &decstep(1,$tbl,$s1,$s0,$s3,$s2); + &decstep(2,$tbl,$s2,$s1,$s0,$s3); + &decstep(3,$tbl,$s3,$s2,$s1,$s0); + &xor ($s0,&DWP(16*$i+0,$key)); + &xor ($s1,&DWP(16*$i+4,$key)); + &xor ($s2,&DWP(16*$i+8,$key)); + &xor ($s3,&DWP(16*$i+12,$key)); + } + &add ($key,32); + &mov ($__key,$key); # advance rd_key + &set_label("12rounds",4); + for ($i=1;$i<3;$i++) { + &decstep(0,$tbl,$s0,$s3,$s2,$s1); + &decstep(1,$tbl,$s1,$s0,$s3,$s2); + &decstep(2,$tbl,$s2,$s1,$s0,$s3); + &decstep(3,$tbl,$s3,$s2,$s1,$s0); + &xor ($s0,&DWP(16*$i+0,$key)); + &xor ($s1,&DWP(16*$i+4,$key)); + &xor ($s2,&DWP(16*$i+8,$key)); + &xor ($s3,&DWP(16*$i+12,$key)); + } + &add ($key,32); + &mov ($__key,$key); # advance rd_key + &set_label("10rounds",4); + for ($i=1;$i<10;$i++) { + &decstep(0,$tbl,$s0,$s3,$s2,$s1); + &decstep(1,$tbl,$s1,$s0,$s3,$s2); + &decstep(2,$tbl,$s2,$s1,$s0,$s3); + &decstep(3,$tbl,$s3,$s2,$s1,$s0); + &xor ($s0,&DWP(16*$i+0,$key)); + &xor ($s1,&DWP(16*$i+4,$key)); + &xor ($s2,&DWP(16*$i+8,$key)); + &xor ($s3,&DWP(16*$i+12,$key)); + } + } + + &declast(0,$tbl,$s0,$s3,$s2,$s1); + &declast(1,$tbl,$s1,$s0,$s3,$s2); + &declast(2,$tbl,$s2,$s1,$s0,$s3); + &declast(3,$tbl,$s3,$s2,$s1,$s0); + + &add ($key,$small_footprint?16:160); + &xor ($s0,&DWP(0,$key)); + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &ret (); + +&set_label("AES_Td",64); # Yes! I keep it in the code segment! + &_data_word(0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a); + &_data_word(0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b); + &_data_word(0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5); + &_data_word(0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5); + &_data_word(0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d); + &_data_word(0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b); + &_data_word(0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295); + &_data_word(0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e); + &_data_word(0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927); + &_data_word(0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d); + &_data_word(0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362); + &_data_word(0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9); + &_data_word(0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52); + &_data_word(0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566); + &_data_word(0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3); + &_data_word(0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed); + &_data_word(0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e); + &_data_word(0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4); + &_data_word(0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4); + &_data_word(0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd); + &_data_word(0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d); + &_data_word(0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060); + &_data_word(0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967); + &_data_word(0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879); + &_data_word(0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000); + &_data_word(0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c); + &_data_word(0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36); + &_data_word(0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624); + &_data_word(0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b); + &_data_word(0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c); + &_data_word(0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12); + &_data_word(0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14); + &_data_word(0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3); + &_data_word(0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b); + &_data_word(0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8); + &_data_word(0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684); + &_data_word(0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7); + &_data_word(0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177); + &_data_word(0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947); + &_data_word(0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322); + &_data_word(0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498); + &_data_word(0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f); + &_data_word(0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54); + &_data_word(0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382); + &_data_word(0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf); + &_data_word(0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb); + &_data_word(0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83); + &_data_word(0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef); + &_data_word(0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029); + &_data_word(0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235); + &_data_word(0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733); + &_data_word(0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117); + &_data_word(0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4); + &_data_word(0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546); + &_data_word(0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb); + &_data_word(0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d); + &_data_word(0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb); + &_data_word(0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a); + &_data_word(0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773); + &_data_word(0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478); + &_data_word(0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2); + &_data_word(0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff); + &_data_word(0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664); + &_data_word(0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0); + +#Td4: # four copies of Td4 to choose from to avoid L1 aliasing + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); + + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); + + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); + + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); +&function_end_B("_x86_AES_decrypt"); + +# void asm_AES_decrypt (const void *inp,void *out,const AES_KEY *key); +&function_begin("asm_AES_decrypt"); + &mov ($acc,&wparam(0)); # load inp + &mov ($key,&wparam(2)); # load key + + &mov ($s0,"esp"); + &sub ("esp",36); + &and ("esp",-64); # align to cache-line + + # place stack frame just "above" the key schedule + &lea ($s1,&DWP(-64-63,$key)); + &sub ($s1,"esp"); + &neg ($s1); + &and ($s1,0x3C0); # modulo 1024, but aligned to cache-line + &sub ("esp",$s1); + &add ("esp",4); # 4 is reserved for caller's return address + &mov ($_esp,$s0); # save stack pointer + + &call (&label("pic_point")); # make it PIC! + &set_label("pic_point"); + &blindpop($tbl); + &picmeup($s0,"OPENSSL_ia32cap_P",$tbl,&label("pic_point")) if(!$x86only); + &lea ($tbl,&DWP(&label("AES_Td")."-".&label("pic_point"),$tbl)); + + # pick Td4 copy which can't "overlap" with stack frame or key schedule + &lea ($s1,&DWP(768-4,"esp")); + &sub ($s1,$tbl); + &and ($s1,0x300); + &lea ($tbl,&DWP(2048+128,$tbl,$s1)); + + if (!$x86only) { + &bt (&DWP(0,$s0),25); # check for SSE bit + &jnc (&label("x86")); + + &movq ("mm0",&QWP(0,$acc)); + &movq ("mm4",&QWP(8,$acc)); + &call ("_sse_AES_decrypt_compact"); + &mov ("esp",$_esp); # restore stack pointer + &mov ($acc,&wparam(1)); # load out + &movq (&QWP(0,$acc),"mm0"); # write output data + &movq (&QWP(8,$acc),"mm4"); + &emms (); + &function_end_A(); + } + &set_label("x86",16); + &mov ($_tbl,$tbl); + &mov ($s0,&DWP(0,$acc)); # load input data + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + &call ("_x86_AES_decrypt_compact"); + &mov ("esp",$_esp); # restore stack pointer + &mov ($acc,&wparam(1)); # load out + &mov (&DWP(0,$acc),$s0); # write output data + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); +&function_end("asm_AES_decrypt"); + +# void asm_AES_cbc_encrypt (const void char *inp, unsigned char *out, +# size_t length, const AES_KEY *key, +# unsigned char *ivp,const int enc); +{ +# stack frame layout +# -4(%esp) # return address 0(%esp) +# 0(%esp) # s0 backing store 4(%esp) +# 4(%esp) # s1 backing store 8(%esp) +# 8(%esp) # s2 backing store 12(%esp) +# 12(%esp) # s3 backing store 16(%esp) +# 16(%esp) # key backup 20(%esp) +# 20(%esp) # end of key schedule 24(%esp) +# 24(%esp) # %ebp backup 28(%esp) +# 28(%esp) # %esp backup +my $_inp=&DWP(32,"esp"); # copy of wparam(0) +my $_out=&DWP(36,"esp"); # copy of wparam(1) +my $_len=&DWP(40,"esp"); # copy of wparam(2) +my $_key=&DWP(44,"esp"); # copy of wparam(3) +my $_ivp=&DWP(48,"esp"); # copy of wparam(4) +my $_tmp=&DWP(52,"esp"); # volatile variable +# +my $ivec=&DWP(60,"esp"); # ivec[16] +my $aes_key=&DWP(76,"esp"); # copy of aes_key +my $mark=&DWP(76+240,"esp"); # copy of aes_key->rounds + +&function_begin("asm_AES_cbc_encrypt"); + &mov ($s2 eq "ecx"? $s2 : "",&wparam(2)); # load len + &cmp ($s2,0); + &je (&label("drop_out")); + + &call (&label("pic_point")); # make it PIC! + &set_label("pic_point"); + &blindpop($tbl); + &picmeup($s0,"OPENSSL_ia32cap_P",$tbl,&label("pic_point")) if(!$x86only); + + &cmp (&wparam(5),0); + &lea ($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl)); + &jne (&label("picked_te")); + &lea ($tbl,&DWP(&label("AES_Td")."-".&label("AES_Te"),$tbl)); + &set_label("picked_te"); + + # one can argue if this is required + &pushf (); + &cld (); + + &cmp ($s2,$speed_limit); + &jb (&label("slow_way")); + &test ($s2,15); + &jnz (&label("slow_way")); + if (!$x86only) { + &bt (&DWP(0,$s0),28); # check for hyper-threading bit + &jc (&label("slow_way")); + } + # pre-allocate aligned stack frame... + &lea ($acc,&DWP(-80-244,"esp")); + &and ($acc,-64); + + # ... and make sure it doesn't alias with $tbl modulo 4096 + &mov ($s0,$tbl); + &lea ($s1,&DWP(2048+256,$tbl)); + &mov ($s3,$acc); + &and ($s0,0xfff); # s = %ebp&0xfff + &and ($s1,0xfff); # e = (%ebp+2048+256)&0xfff + &and ($s3,0xfff); # p = %esp&0xfff + + &cmp ($s3,$s1); # if (p>=e) %esp =- (p-e); + &jb (&label("tbl_break_out")); + &sub ($s3,$s1); + &sub ($acc,$s3); + &jmp (&label("tbl_ok")); + &set_label("tbl_break_out",4); # else %esp -= (p-s)&0xfff + framesz; + &sub ($s3,$s0); + &and ($s3,0xfff); + &add ($s3,384); + &sub ($acc,$s3); + &set_label("tbl_ok",4); + + &lea ($s3,&wparam(0)); # obtain pointer to parameter block + &exch ("esp",$acc); # allocate stack frame + &add ("esp",4); # reserve for return address! + &mov ($_tbl,$tbl); # save %ebp + &mov ($_esp,$acc); # save %esp + + &mov ($s0,&DWP(0,$s3)); # load inp + &mov ($s1,&DWP(4,$s3)); # load out + #&mov ($s2,&DWP(8,$s3)); # load len + &mov ($key,&DWP(12,$s3)); # load key + &mov ($acc,&DWP(16,$s3)); # load ivp + &mov ($s3,&DWP(20,$s3)); # load enc flag + + &mov ($_inp,$s0); # save copy of inp + &mov ($_out,$s1); # save copy of out + &mov ($_len,$s2); # save copy of len + &mov ($_key,$key); # save copy of key + &mov ($_ivp,$acc); # save copy of ivp + + &mov ($mark,0); # copy of aes_key->rounds = 0; + # do we copy key schedule to stack? + &mov ($s1 eq "ebx" ? $s1 : "",$key); + &mov ($s2 eq "ecx" ? $s2 : "",244/4); + &sub ($s1,$tbl); + &mov ("esi",$key); + &and ($s1,0xfff); + &lea ("edi",$aes_key); + &cmp ($s1,2048+256); + &jb (&label("do_copy")); + &cmp ($s1,4096-244); + &jb (&label("skip_copy")); + &set_label("do_copy",4); + &mov ($_key,"edi"); + &data_word(0xA5F3F689); # rep movsd + &set_label("skip_copy"); + + &mov ($key,16); + &set_label("prefetch_tbl",4); + &mov ($s0,&DWP(0,$tbl)); + &mov ($s1,&DWP(32,$tbl)); + &mov ($s2,&DWP(64,$tbl)); + &mov ($acc,&DWP(96,$tbl)); + &lea ($tbl,&DWP(128,$tbl)); + &sub ($key,1); + &jnz (&label("prefetch_tbl")); + &sub ($tbl,2048); + + &mov ($acc,$_inp); + &mov ($key,$_ivp); + + &cmp ($s3,0); + &je (&label("fast_decrypt")); + +#----------------------------- ENCRYPT -----------------------------# + &mov ($s0,&DWP(0,$key)); # load iv + &mov ($s1,&DWP(4,$key)); + + &set_label("fast_enc_loop",16); + &mov ($s2,&DWP(8,$key)); + &mov ($s3,&DWP(12,$key)); + + &xor ($s0,&DWP(0,$acc)); # xor input data + &xor ($s1,&DWP(4,$acc)); + &xor ($s2,&DWP(8,$acc)); + &xor ($s3,&DWP(12,$acc)); + + &mov ($key,$_key); # load key + &call ("_x86_AES_encrypt"); + + &mov ($acc,$_inp); # load inp + &mov ($key,$_out); # load out + + &mov (&DWP(0,$key),$s0); # save output data + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &lea ($acc,&DWP(16,$acc)); # advance inp + &mov ($s2,$_len); # load len + &mov ($_inp,$acc); # save inp + &lea ($s3,&DWP(16,$key)); # advance out + &mov ($_out,$s3); # save out + &sub ($s2,16); # decrease len + &mov ($_len,$s2); # save len + &jnz (&label("fast_enc_loop")); + &mov ($acc,$_ivp); # load ivp + &mov ($s2,&DWP(8,$key)); # restore last 2 dwords + &mov ($s3,&DWP(12,$key)); + &mov (&DWP(0,$acc),$s0); # save ivec + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); + + &cmp ($mark,0); # was the key schedule copied? + &mov ("edi",$_key); + &je (&label("skip_ezero")); + # zero copy of key schedule + &mov ("ecx",240/4); + &xor ("eax","eax"); + &align (4); + &data_word(0xABF3F689); # rep stosd + &set_label("skip_ezero"); + &mov ("esp",$_esp); + &popf (); + &set_label("drop_out"); + &function_end_A(); + &pushf (); # kludge, never executed + +#----------------------------- DECRYPT -----------------------------# +&set_label("fast_decrypt",16); + + &cmp ($acc,$_out); + &je (&label("fast_dec_in_place")); # in-place processing... + + &mov ($_tmp,$key); + + &align (4); + &set_label("fast_dec_loop",16); + &mov ($s0,&DWP(0,$acc)); # read input + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + + &mov ($key,$_key); # load key + &call ("_x86_AES_decrypt"); + + &mov ($key,$_tmp); # load ivp + &mov ($acc,$_len); # load len + &xor ($s0,&DWP(0,$key)); # xor iv + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &mov ($key,$_out); # load out + &mov ($acc,$_inp); # load inp + + &mov (&DWP(0,$key),$s0); # write output + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &mov ($s2,$_len); # load len + &mov ($_tmp,$acc); # save ivp + &lea ($acc,&DWP(16,$acc)); # advance inp + &mov ($_inp,$acc); # save inp + &lea ($key,&DWP(16,$key)); # advance out + &mov ($_out,$key); # save out + &sub ($s2,16); # decrease len + &mov ($_len,$s2); # save len + &jnz (&label("fast_dec_loop")); + &mov ($key,$_tmp); # load temp ivp + &mov ($acc,$_ivp); # load user ivp + &mov ($s0,&DWP(0,$key)); # load iv + &mov ($s1,&DWP(4,$key)); + &mov ($s2,&DWP(8,$key)); + &mov ($s3,&DWP(12,$key)); + &mov (&DWP(0,$acc),$s0); # copy back to user + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); + &jmp (&label("fast_dec_out")); + + &set_label("fast_dec_in_place",16); + &set_label("fast_dec_in_place_loop"); + &mov ($s0,&DWP(0,$acc)); # read input + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + + &lea ($key,$ivec); + &mov (&DWP(0,$key),$s0); # copy to temp + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &mov ($key,$_key); # load key + &call ("_x86_AES_decrypt"); + + &mov ($key,$_ivp); # load ivp + &mov ($acc,$_out); # load out + &xor ($s0,&DWP(0,$key)); # xor iv + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &mov (&DWP(0,$acc),$s0); # write output + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); + + &lea ($acc,&DWP(16,$acc)); # advance out + &mov ($_out,$acc); # save out + + &lea ($acc,$ivec); + &mov ($s0,&DWP(0,$acc)); # read temp + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + + &mov (&DWP(0,$key),$s0); # copy iv + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &mov ($acc,$_inp); # load inp + &mov ($s2,$_len); # load len + &lea ($acc,&DWP(16,$acc)); # advance inp + &mov ($_inp,$acc); # save inp + &sub ($s2,16); # decrease len + &mov ($_len,$s2); # save len + &jnz (&label("fast_dec_in_place_loop")); + + &set_label("fast_dec_out",4); + &cmp ($mark,0); # was the key schedule copied? + &mov ("edi",$_key); + &je (&label("skip_dzero")); + # zero copy of key schedule + &mov ("ecx",240/4); + &xor ("eax","eax"); + &align (4); + &data_word(0xABF3F689); # rep stosd + &set_label("skip_dzero"); + &mov ("esp",$_esp); + &popf (); + &function_end_A(); + &pushf (); # kludge, never executed + +#--------------------------- SLOW ROUTINE ---------------------------# +&set_label("slow_way",16); + + &mov ($s0,&DWP(0,$s0)) if (!$x86only);# load OPENSSL_ia32cap + &mov ($key,&wparam(3)); # load key + + # pre-allocate aligned stack frame... + &lea ($acc,&DWP(-80,"esp")); + &and ($acc,-64); + + # ... and make sure it doesn't alias with $key modulo 1024 + &lea ($s1,&DWP(-80-63,$key)); + &sub ($s1,$acc); + &neg ($s1); + &and ($s1,0x3C0); # modulo 1024, but aligned to cache-line + &sub ($acc,$s1); + + # pick S-box copy which can't overlap with stack frame or $key + &lea ($s1,&DWP(768,$acc)); + &sub ($s1,$tbl); + &and ($s1,0x300); + &lea ($tbl,&DWP(2048+128,$tbl,$s1)); + + &lea ($s3,&wparam(0)); # pointer to parameter block + + &exch ("esp",$acc); + &add ("esp",4); # reserve for return address! + &mov ($_tbl,$tbl); # save %ebp + &mov ($_esp,$acc); # save %esp + &mov ($_tmp,$s0); # save OPENSSL_ia32cap + + &mov ($s0,&DWP(0,$s3)); # load inp + &mov ($s1,&DWP(4,$s3)); # load out + #&mov ($s2,&DWP(8,$s3)); # load len + #&mov ($key,&DWP(12,$s3)); # load key + &mov ($acc,&DWP(16,$s3)); # load ivp + &mov ($s3,&DWP(20,$s3)); # load enc flag + + &mov ($_inp,$s0); # save copy of inp + &mov ($_out,$s1); # save copy of out + &mov ($_len,$s2); # save copy of len + &mov ($_key,$key); # save copy of key + &mov ($_ivp,$acc); # save copy of ivp + + &mov ($key,$acc); + &mov ($acc,$s0); + + &cmp ($s3,0); + &je (&label("slow_decrypt")); + +#--------------------------- SLOW ENCRYPT ---------------------------# + &cmp ($s2,16); + &mov ($s3,$s1); + &jb (&label("slow_enc_tail")); + + if (!$x86only) { + &bt ($_tmp,25); # check for SSE bit + &jnc (&label("slow_enc_x86")); + + &movq ("mm0",&QWP(0,$key)); # load iv + &movq ("mm4",&QWP(8,$key)); + + &set_label("slow_enc_loop_sse",16); + &pxor ("mm0",&QWP(0,$acc)); # xor input data + &pxor ("mm4",&QWP(8,$acc)); + + &mov ($key,$_key); + &call ("_sse_AES_encrypt_compact"); + + &mov ($acc,$_inp); # load inp + &mov ($key,$_out); # load out + &mov ($s2,$_len); # load len + + &movq (&QWP(0,$key),"mm0"); # save output data + &movq (&QWP(8,$key),"mm4"); + + &lea ($acc,&DWP(16,$acc)); # advance inp + &mov ($_inp,$acc); # save inp + &lea ($s3,&DWP(16,$key)); # advance out + &mov ($_out,$s3); # save out + &sub ($s2,16); # decrease len + &cmp ($s2,16); + &mov ($_len,$s2); # save len + &jae (&label("slow_enc_loop_sse")); + &test ($s2,15); + &jnz (&label("slow_enc_tail")); + &mov ($acc,$_ivp); # load ivp + &movq (&QWP(0,$acc),"mm0"); # save ivec + &movq (&QWP(8,$acc),"mm4"); + &emms (); + &mov ("esp",$_esp); + &popf (); + &function_end_A(); + &pushf (); # kludge, never executed + } + &set_label("slow_enc_x86",16); + &mov ($s0,&DWP(0,$key)); # load iv + &mov ($s1,&DWP(4,$key)); + + &set_label("slow_enc_loop_x86",4); + &mov ($s2,&DWP(8,$key)); + &mov ($s3,&DWP(12,$key)); + + &xor ($s0,&DWP(0,$acc)); # xor input data + &xor ($s1,&DWP(4,$acc)); + &xor ($s2,&DWP(8,$acc)); + &xor ($s3,&DWP(12,$acc)); + + &mov ($key,$_key); # load key + &call ("_x86_AES_encrypt_compact"); + + &mov ($acc,$_inp); # load inp + &mov ($key,$_out); # load out + + &mov (&DWP(0,$key),$s0); # save output data + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &mov ($s2,$_len); # load len + &lea ($acc,&DWP(16,$acc)); # advance inp + &mov ($_inp,$acc); # save inp + &lea ($s3,&DWP(16,$key)); # advance out + &mov ($_out,$s3); # save out + &sub ($s2,16); # decrease len + &cmp ($s2,16); + &mov ($_len,$s2); # save len + &jae (&label("slow_enc_loop_x86")); + &test ($s2,15); + &jnz (&label("slow_enc_tail")); + &mov ($acc,$_ivp); # load ivp + &mov ($s2,&DWP(8,$key)); # restore last dwords + &mov ($s3,&DWP(12,$key)); + &mov (&DWP(0,$acc),$s0); # save ivec + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); + + &mov ("esp",$_esp); + &popf (); + &function_end_A(); + &pushf (); # kludge, never executed + + &set_label("slow_enc_tail",16); + &emms () if (!$x86only); + &mov ($key eq "edi"? $key:"",$s3); # load out to edi + &mov ($s1,16); + &sub ($s1,$s2); + &cmp ($key,$acc eq "esi"? $acc:""); # compare with inp + &je (&label("enc_in_place")); + &align (4); + &data_word(0xA4F3F689); # rep movsb # copy input + &jmp (&label("enc_skip_in_place")); + &set_label("enc_in_place"); + &lea ($key,&DWP(0,$key,$s2)); + &set_label("enc_skip_in_place"); + &mov ($s2,$s1); + &xor ($s0,$s0); + &align (4); + &data_word(0xAAF3F689); # rep stosb # zero tail + + &mov ($key,$_ivp); # restore ivp + &mov ($acc,$s3); # output as input + &mov ($s0,&DWP(0,$key)); + &mov ($s1,&DWP(4,$key)); + &mov ($_len,16); # len=16 + &jmp (&label("slow_enc_loop_x86")); # one more spin... + +#--------------------------- SLOW DECRYPT ---------------------------# +&set_label("slow_decrypt",16); + if (!$x86only) { + &bt ($_tmp,25); # check for SSE bit + &jnc (&label("slow_dec_loop_x86")); + + &set_label("slow_dec_loop_sse",4); + &movq ("mm0",&QWP(0,$acc)); # read input + &movq ("mm4",&QWP(8,$acc)); + + &mov ($key,$_key); + &call ("_sse_AES_decrypt_compact"); + + &mov ($acc,$_inp); # load inp + &lea ($s0,$ivec); + &mov ($s1,$_out); # load out + &mov ($s2,$_len); # load len + &mov ($key,$_ivp); # load ivp + + &movq ("mm1",&QWP(0,$acc)); # re-read input + &movq ("mm5",&QWP(8,$acc)); + + &pxor ("mm0",&QWP(0,$key)); # xor iv + &pxor ("mm4",&QWP(8,$key)); + + &movq (&QWP(0,$key),"mm1"); # copy input to iv + &movq (&QWP(8,$key),"mm5"); + + &sub ($s2,16); # decrease len + &jc (&label("slow_dec_partial_sse")); + + &movq (&QWP(0,$s1),"mm0"); # write output + &movq (&QWP(8,$s1),"mm4"); + + &lea ($s1,&DWP(16,$s1)); # advance out + &mov ($_out,$s1); # save out + &lea ($acc,&DWP(16,$acc)); # advance inp + &mov ($_inp,$acc); # save inp + &mov ($_len,$s2); # save len + &jnz (&label("slow_dec_loop_sse")); + &emms (); + &mov ("esp",$_esp); + &popf (); + &function_end_A(); + &pushf (); # kludge, never executed + + &set_label("slow_dec_partial_sse",16); + &movq (&QWP(0,$s0),"mm0"); # save output to temp + &movq (&QWP(8,$s0),"mm4"); + &emms (); + + &add ($s2 eq "ecx" ? "ecx":"",16); + &mov ("edi",$s1); # out + &mov ("esi",$s0); # temp + &align (4); + &data_word(0xA4F3F689); # rep movsb # copy partial output + + &mov ("esp",$_esp); + &popf (); + &function_end_A(); + &pushf (); # kludge, never executed + } + &set_label("slow_dec_loop_x86",16); + &mov ($s0,&DWP(0,$acc)); # read input + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + + &lea ($key,$ivec); + &mov (&DWP(0,$key),$s0); # copy to temp + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &mov ($key,$_key); # load key + &call ("_x86_AES_decrypt_compact"); + + &mov ($key,$_ivp); # load ivp + &mov ($acc,$_len); # load len + &xor ($s0,&DWP(0,$key)); # xor iv + &xor ($s1,&DWP(4,$key)); + &xor ($s2,&DWP(8,$key)); + &xor ($s3,&DWP(12,$key)); + + &sub ($acc,16); + &jc (&label("slow_dec_partial_x86")); + + &mov ($_len,$acc); # save len + &mov ($acc,$_out); # load out + + &mov (&DWP(0,$acc),$s0); # write output + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); + + &lea ($acc,&DWP(16,$acc)); # advance out + &mov ($_out,$acc); # save out + + &lea ($acc,$ivec); + &mov ($s0,&DWP(0,$acc)); # read temp + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + + &mov (&DWP(0,$key),$s0); # copy it to iv + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &mov ($acc,$_inp); # load inp + &lea ($acc,&DWP(16,$acc)); # advance inp + &mov ($_inp,$acc); # save inp + &jnz (&label("slow_dec_loop_x86")); + &mov ("esp",$_esp); + &popf (); + &function_end_A(); + &pushf (); # kludge, never executed + + &set_label("slow_dec_partial_x86",16); + &lea ($acc,$ivec); + &mov (&DWP(0,$acc),$s0); # save output to temp + &mov (&DWP(4,$acc),$s1); + &mov (&DWP(8,$acc),$s2); + &mov (&DWP(12,$acc),$s3); + + &mov ($acc,$_inp); + &mov ($s0,&DWP(0,$acc)); # re-read input + &mov ($s1,&DWP(4,$acc)); + &mov ($s2,&DWP(8,$acc)); + &mov ($s3,&DWP(12,$acc)); + + &mov (&DWP(0,$key),$s0); # copy it to iv + &mov (&DWP(4,$key),$s1); + &mov (&DWP(8,$key),$s2); + &mov (&DWP(12,$key),$s3); + + &mov ("ecx",$_len); + &mov ("edi",$_out); + &lea ("esi",$ivec); + &align (4); + &data_word(0xA4F3F689); # rep movsb # copy partial output + + &mov ("esp",$_esp); + &popf (); +&function_end("asm_AES_cbc_encrypt"); +} + +#------------------------------------------------------------------# + +sub enckey() +{ + &movz ("esi",&LB("edx")); # rk[i]>>0 + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &movz ("esi",&HB("edx")); # rk[i]>>8 + &shl ("ebx",24); + &xor ("eax","ebx"); + + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &shr ("edx",16); + &movz ("esi",&LB("edx")); # rk[i]>>16 + &xor ("eax","ebx"); + + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &movz ("esi",&HB("edx")); # rk[i]>>24 + &shl ("ebx",8); + &xor ("eax","ebx"); + + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &shl ("ebx",16); + &xor ("eax","ebx"); + + &xor ("eax",&DWP(1024-128,$tbl,"ecx",4)); # rcon +} + +&function_begin("_x86_AES_set_encrypt_key"); + &mov ("esi",&wparam(1)); # user supplied key + &mov ("edi",&wparam(3)); # private key schedule + + &test ("esi",-1); + &jz (&label("badpointer")); + &test ("edi",-1); + &jz (&label("badpointer")); + + &call (&label("pic_point")); + &set_label("pic_point"); + &blindpop($tbl); + &lea ($tbl,&DWP(&label("AES_Te")."-".&label("pic_point"),$tbl)); + &lea ($tbl,&DWP(2048+128,$tbl)); + + # prefetch Te4 + &mov ("eax",&DWP(0-128,$tbl)); + &mov ("ebx",&DWP(32-128,$tbl)); + &mov ("ecx",&DWP(64-128,$tbl)); + &mov ("edx",&DWP(96-128,$tbl)); + &mov ("eax",&DWP(128-128,$tbl)); + &mov ("ebx",&DWP(160-128,$tbl)); + &mov ("ecx",&DWP(192-128,$tbl)); + &mov ("edx",&DWP(224-128,$tbl)); + + &mov ("ecx",&wparam(2)); # number of bits in key + &cmp ("ecx",128); + &je (&label("10rounds")); + &cmp ("ecx",192); + &je (&label("12rounds")); + &cmp ("ecx",256); + &je (&label("14rounds")); + &mov ("eax",-2); # invalid number of bits + &jmp (&label("exit")); + + &set_label("10rounds"); + &mov ("eax",&DWP(0,"esi")); # copy first 4 dwords + &mov ("ebx",&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("edx",&DWP(12,"esi")); + &mov (&DWP(0,"edi"),"eax"); + &mov (&DWP(4,"edi"),"ebx"); + &mov (&DWP(8,"edi"),"ecx"); + &mov (&DWP(12,"edi"),"edx"); + + &xor ("ecx","ecx"); + &jmp (&label("10shortcut")); + + &align (4); + &set_label("10loop"); + &mov ("eax",&DWP(0,"edi")); # rk[0] + &mov ("edx",&DWP(12,"edi")); # rk[3] + &set_label("10shortcut"); + &enckey (); + + &mov (&DWP(16,"edi"),"eax"); # rk[4] + &xor ("eax",&DWP(4,"edi")); + &mov (&DWP(20,"edi"),"eax"); # rk[5] + &xor ("eax",&DWP(8,"edi")); + &mov (&DWP(24,"edi"),"eax"); # rk[6] + &xor ("eax",&DWP(12,"edi")); + &mov (&DWP(28,"edi"),"eax"); # rk[7] + &inc ("ecx"); + &add ("edi",16); + &cmp ("ecx",10); + &jl (&label("10loop")); + + &mov (&DWP(80,"edi"),10); # setup number of rounds + &xor ("eax","eax"); + &jmp (&label("exit")); + + &set_label("12rounds"); + &mov ("eax",&DWP(0,"esi")); # copy first 6 dwords + &mov ("ebx",&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("edx",&DWP(12,"esi")); + &mov (&DWP(0,"edi"),"eax"); + &mov (&DWP(4,"edi"),"ebx"); + &mov (&DWP(8,"edi"),"ecx"); + &mov (&DWP(12,"edi"),"edx"); + &mov ("ecx",&DWP(16,"esi")); + &mov ("edx",&DWP(20,"esi")); + &mov (&DWP(16,"edi"),"ecx"); + &mov (&DWP(20,"edi"),"edx"); + + &xor ("ecx","ecx"); + &jmp (&label("12shortcut")); + + &align (4); + &set_label("12loop"); + &mov ("eax",&DWP(0,"edi")); # rk[0] + &mov ("edx",&DWP(20,"edi")); # rk[5] + &set_label("12shortcut"); + &enckey (); + + &mov (&DWP(24,"edi"),"eax"); # rk[6] + &xor ("eax",&DWP(4,"edi")); + &mov (&DWP(28,"edi"),"eax"); # rk[7] + &xor ("eax",&DWP(8,"edi")); + &mov (&DWP(32,"edi"),"eax"); # rk[8] + &xor ("eax",&DWP(12,"edi")); + &mov (&DWP(36,"edi"),"eax"); # rk[9] + + &cmp ("ecx",7); + &je (&label("12break")); + &inc ("ecx"); + + &xor ("eax",&DWP(16,"edi")); + &mov (&DWP(40,"edi"),"eax"); # rk[10] + &xor ("eax",&DWP(20,"edi")); + &mov (&DWP(44,"edi"),"eax"); # rk[11] + + &add ("edi",24); + &jmp (&label("12loop")); + + &set_label("12break"); + &mov (&DWP(72,"edi"),12); # setup number of rounds + &xor ("eax","eax"); + &jmp (&label("exit")); + + &set_label("14rounds"); + &mov ("eax",&DWP(0,"esi")); # copy first 8 dwords + &mov ("ebx",&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("edx",&DWP(12,"esi")); + &mov (&DWP(0,"edi"),"eax"); + &mov (&DWP(4,"edi"),"ebx"); + &mov (&DWP(8,"edi"),"ecx"); + &mov (&DWP(12,"edi"),"edx"); + &mov ("eax",&DWP(16,"esi")); + &mov ("ebx",&DWP(20,"esi")); + &mov ("ecx",&DWP(24,"esi")); + &mov ("edx",&DWP(28,"esi")); + &mov (&DWP(16,"edi"),"eax"); + &mov (&DWP(20,"edi"),"ebx"); + &mov (&DWP(24,"edi"),"ecx"); + &mov (&DWP(28,"edi"),"edx"); + + &xor ("ecx","ecx"); + &jmp (&label("14shortcut")); + + &align (4); + &set_label("14loop"); + &mov ("edx",&DWP(28,"edi")); # rk[7] + &set_label("14shortcut"); + &mov ("eax",&DWP(0,"edi")); # rk[0] + + &enckey (); + + &mov (&DWP(32,"edi"),"eax"); # rk[8] + &xor ("eax",&DWP(4,"edi")); + &mov (&DWP(36,"edi"),"eax"); # rk[9] + &xor ("eax",&DWP(8,"edi")); + &mov (&DWP(40,"edi"),"eax"); # rk[10] + &xor ("eax",&DWP(12,"edi")); + &mov (&DWP(44,"edi"),"eax"); # rk[11] + + &cmp ("ecx",6); + &je (&label("14break")); + &inc ("ecx"); + + &mov ("edx","eax"); + &mov ("eax",&DWP(16,"edi")); # rk[4] + &movz ("esi",&LB("edx")); # rk[11]>>0 + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &movz ("esi",&HB("edx")); # rk[11]>>8 + &xor ("eax","ebx"); + + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &shr ("edx",16); + &shl ("ebx",8); + &movz ("esi",&LB("edx")); # rk[11]>>16 + &xor ("eax","ebx"); + + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &movz ("esi",&HB("edx")); # rk[11]>>24 + &shl ("ebx",16); + &xor ("eax","ebx"); + + &movz ("ebx",&BP(-128,$tbl,"esi",1)); + &shl ("ebx",24); + &xor ("eax","ebx"); + + &mov (&DWP(48,"edi"),"eax"); # rk[12] + &xor ("eax",&DWP(20,"edi")); + &mov (&DWP(52,"edi"),"eax"); # rk[13] + &xor ("eax",&DWP(24,"edi")); + &mov (&DWP(56,"edi"),"eax"); # rk[14] + &xor ("eax",&DWP(28,"edi")); + &mov (&DWP(60,"edi"),"eax"); # rk[15] + + &add ("edi",32); + &jmp (&label("14loop")); + + &set_label("14break"); + &mov (&DWP(48,"edi"),14); # setup number of rounds + &xor ("eax","eax"); + &jmp (&label("exit")); + + &set_label("badpointer"); + &mov ("eax",-1); + &set_label("exit"); +&function_end("_x86_AES_set_encrypt_key"); + +# int asm_AES_set_encrypt_key(const unsigned char *userKey, const int bits, +# AES_KEY *key) +&function_begin_B("asm_AES_set_encrypt_key"); + &call ("_x86_AES_set_encrypt_key"); + &ret (); +&function_end_B("asm_AES_set_encrypt_key"); + +sub deckey() +{ my ($i,$key,$tp1,$tp2,$tp4,$tp8) = @_; + my $tmp = $tbl; + + &mov ($tmp,0x80808080); + &and ($tmp,$tp1); + &lea ($tp2,&DWP(0,$tp1,$tp1)); + &mov ($acc,$tmp); + &shr ($tmp,7); + &sub ($acc,$tmp); + &and ($tp2,0xfefefefe); + &and ($acc,0x1b1b1b1b); + &xor ($tp2,$acc); + &mov ($tmp,0x80808080); + + &and ($tmp,$tp2); + &lea ($tp4,&DWP(0,$tp2,$tp2)); + &mov ($acc,$tmp); + &shr ($tmp,7); + &sub ($acc,$tmp); + &and ($tp4,0xfefefefe); + &and ($acc,0x1b1b1b1b); + &xor ($tp2,$tp1); # tp2^tp1 + &xor ($tp4,$acc); + &mov ($tmp,0x80808080); + + &and ($tmp,$tp4); + &lea ($tp8,&DWP(0,$tp4,$tp4)); + &mov ($acc,$tmp); + &shr ($tmp,7); + &xor ($tp4,$tp1); # tp4^tp1 + &sub ($acc,$tmp); + &and ($tp8,0xfefefefe); + &and ($acc,0x1b1b1b1b); + &rotl ($tp1,8); # = ROTATE(tp1,8) + &xor ($tp8,$acc); + + &mov ($tmp,&DWP(4*($i+1),$key)); # modulo-scheduled load + + &xor ($tp1,$tp2); + &xor ($tp2,$tp8); + &xor ($tp1,$tp4); + &rotl ($tp2,24); + &xor ($tp4,$tp8); + &xor ($tp1,$tp8); # ^= tp8^(tp4^tp1)^(tp2^tp1) + &rotl ($tp4,16); + &xor ($tp1,$tp2); # ^= ROTATE(tp8^tp2^tp1,24) + &rotl ($tp8,8); + &xor ($tp1,$tp4); # ^= ROTATE(tp8^tp4^tp1,16) + &mov ($tp2,$tmp); + &xor ($tp1,$tp8); # ^= ROTATE(tp8,8) + + &mov (&DWP(4*$i,$key),$tp1); +} + +# int asm_AES_set_decrypt_key(const unsigned char *userKey, const int bits, +# AES_KEY *key) +&function_begin_B("asm_AES_set_decrypt_key"); + &call ("_x86_AES_set_encrypt_key"); + &cmp ("eax",0); + &je (&label("proceed")); + &ret (); + + &set_label("proceed"); + &push ("ebp"); + &push ("ebx"); + &push ("esi"); + &push ("edi"); + + &mov ("esi",&wparam(2)); + &mov ("ecx",&DWP(240,"esi")); # pull number of rounds + &lea ("ecx",&DWP(0,"","ecx",4)); + &lea ("edi",&DWP(0,"esi","ecx",4)); # pointer to last chunk + + &set_label("invert",4); # invert order of chunks + &mov ("eax",&DWP(0,"esi")); + &mov ("ebx",&DWP(4,"esi")); + &mov ("ecx",&DWP(0,"edi")); + &mov ("edx",&DWP(4,"edi")); + &mov (&DWP(0,"edi"),"eax"); + &mov (&DWP(4,"edi"),"ebx"); + &mov (&DWP(0,"esi"),"ecx"); + &mov (&DWP(4,"esi"),"edx"); + &mov ("eax",&DWP(8,"esi")); + &mov ("ebx",&DWP(12,"esi")); + &mov ("ecx",&DWP(8,"edi")); + &mov ("edx",&DWP(12,"edi")); + &mov (&DWP(8,"edi"),"eax"); + &mov (&DWP(12,"edi"),"ebx"); + &mov (&DWP(8,"esi"),"ecx"); + &mov (&DWP(12,"esi"),"edx"); + &add ("esi",16); + &sub ("edi",16); + &cmp ("esi","edi"); + &jne (&label("invert")); + + &mov ($key,&wparam(2)); + &mov ($acc,&DWP(240,$key)); # pull number of rounds + &lea ($acc,&DWP(-2,$acc,$acc)); + &lea ($acc,&DWP(0,$key,$acc,8)); + &mov (&wparam(2),$acc); + + &mov ($s0,&DWP(16,$key)); # modulo-scheduled load + &set_label("permute",4); # permute the key schedule + &add ($key,16); + &deckey (0,$key,$s0,$s1,$s2,$s3); + &deckey (1,$key,$s1,$s2,$s3,$s0); + &deckey (2,$key,$s2,$s3,$s0,$s1); + &deckey (3,$key,$s3,$s0,$s1,$s2); + &cmp ($key,&wparam(2)); + &jb (&label("permute")); + + &xor ("eax","eax"); # return success +&function_end("asm_AES_set_decrypt_key"); +&asciz("AES for x86, CRYPTOGAMS by "); + +&asm_finish(); diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-armv4.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-armv4.pl new file mode 100644 index 00000000..36cd3b6d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-armv4.pl @@ -0,0 +1,1249 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# AES for ARMv4 + +# January 2007. +# +# Code uses single 1K S-box and is >2 times faster than code generated +# by gcc-3.4.1. This is thanks to unique feature of ARMv4 ISA, which +# allows to merge logical or arithmetic operation with shift or rotate +# in one instruction and emit combined result every cycle. The module +# is endian-neutral. The performance is ~42 cycles/byte for 128-bit +# key [on single-issue Xscale PXA250 core]. + +# May 2007. +# +# AES_set_[en|de]crypt_key is added. + +# July 2010. +# +# Rescheduling for dual-issue pipeline resulted in 12% improvement on +# Cortex A8 core and ~25 cycles per byte processed with 128-bit key. + +# February 2011. +# +# Profiler-assisted and platform-specific optimization resulted in 16% +# improvement on Cortex A8 core and ~21.5 cycles per byte. + +$flavour = shift; +if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } +else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} } + +if ($flavour && $flavour ne "void") { + $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; + ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or + ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or + die "can't locate arm-xlate.pl"; + + open STDOUT,"| \"$^X\" $xlate $flavour $output"; +} else { + open STDOUT,">$output"; +} + +$s0="r0"; +$s1="r1"; +$s2="r2"; +$s3="r3"; +$t1="r4"; +$t2="r5"; +$t3="r6"; +$i1="r7"; +$i2="r8"; +$i3="r9"; + +$tbl="r10"; +$key="r11"; +$rounds="r12"; + +$code=<<___; +#if defined(__arm__) +#ifndef __KERNEL__ +# include "arm_arch.h" +#else +# define __ARM_ARCH__ __LINUX_ARM_ARCH__ +#endif + +.text +#if __ARM_ARCH__<7 +.code 32 +#else +.syntax unified +# if defined(__thumb2__) && !defined(__APPLE__) +.thumb +# else +.code 32 +# endif +#endif + +.type AES_Te,%object +.align 5 +AES_Te: +.word 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d +.word 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554 +.word 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d +.word 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a +.word 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87 +.word 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b +.word 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea +.word 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b +.word 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a +.word 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f +.word 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108 +.word 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f +.word 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e +.word 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5 +.word 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d +.word 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f +.word 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e +.word 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb +.word 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce +.word 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497 +.word 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c +.word 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed +.word 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b +.word 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a +.word 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16 +.word 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594 +.word 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81 +.word 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3 +.word 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a +.word 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504 +.word 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163 +.word 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d +.word 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f +.word 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739 +.word 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47 +.word 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395 +.word 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f +.word 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883 +.word 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c +.word 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76 +.word 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e +.word 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4 +.word 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6 +.word 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b +.word 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7 +.word 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0 +.word 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25 +.word 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818 +.word 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72 +.word 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651 +.word 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21 +.word 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85 +.word 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa +.word 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12 +.word 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0 +.word 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9 +.word 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133 +.word 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7 +.word 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920 +.word 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a +.word 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17 +.word 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8 +.word 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11 +.word 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a +@ Te4[256] +.byte 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5 +.byte 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76 +.byte 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0 +.byte 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0 +.byte 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc +.byte 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15 +.byte 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a +.byte 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75 +.byte 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0 +.byte 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84 +.byte 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b +.byte 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf +.byte 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85 +.byte 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8 +.byte 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5 +.byte 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2 +.byte 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17 +.byte 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73 +.byte 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88 +.byte 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb +.byte 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c +.byte 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79 +.byte 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9 +.byte 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08 +.byte 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6 +.byte 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a +.byte 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e +.byte 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e +.byte 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94 +.byte 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf +.byte 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68 +.byte 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 +@ rcon[] +.word 0x01000000, 0x02000000, 0x04000000, 0x08000000 +.word 0x10000000, 0x20000000, 0x40000000, 0x80000000 +.word 0x1B000000, 0x36000000, 0, 0, 0, 0, 0, 0 +.size AES_Te,.-AES_Te + +@ void asm_AES_encrypt(const unsigned char *in, unsigned char *out, +@ const AES_KEY *key) { +.global asm_AES_encrypt +.hidden asm_AES_encrypt +.type asm_AES_encrypt,%function +.align 5 +asm_AES_encrypt: +#if __ARM_ARCH__<7 + sub r3,pc,#8 @ asm_AES_encrypt +#else + adr r3,asm_AES_encrypt +#endif + stmdb sp!,{r1,r4-r12,lr} +#ifdef __APPLE__ + adr $tbl,AES_Te +#else + sub $tbl,r3,#asm_AES_encrypt-AES_Te @ Te +#endif + mov $rounds,r0 @ inp + mov $key,r2 +#if __ARM_ARCH__<7 + ldrb $s0,[$rounds,#3] @ load input data in endian-neutral + ldrb $t1,[$rounds,#2] @ manner... + ldrb $t2,[$rounds,#1] + ldrb $t3,[$rounds,#0] + orr $s0,$s0,$t1,lsl#8 + ldrb $s1,[$rounds,#7] + orr $s0,$s0,$t2,lsl#16 + ldrb $t1,[$rounds,#6] + orr $s0,$s0,$t3,lsl#24 + ldrb $t2,[$rounds,#5] + ldrb $t3,[$rounds,#4] + orr $s1,$s1,$t1,lsl#8 + ldrb $s2,[$rounds,#11] + orr $s1,$s1,$t2,lsl#16 + ldrb $t1,[$rounds,#10] + orr $s1,$s1,$t3,lsl#24 + ldrb $t2,[$rounds,#9] + ldrb $t3,[$rounds,#8] + orr $s2,$s2,$t1,lsl#8 + ldrb $s3,[$rounds,#15] + orr $s2,$s2,$t2,lsl#16 + ldrb $t1,[$rounds,#14] + orr $s2,$s2,$t3,lsl#24 + ldrb $t2,[$rounds,#13] + ldrb $t3,[$rounds,#12] + orr $s3,$s3,$t1,lsl#8 + orr $s3,$s3,$t2,lsl#16 + orr $s3,$s3,$t3,lsl#24 +#else + ldr $s0,[$rounds,#0] + ldr $s1,[$rounds,#4] + ldr $s2,[$rounds,#8] + ldr $s3,[$rounds,#12] +#ifdef __ARMEL__ + rev $s0,$s0 + rev $s1,$s1 + rev $s2,$s2 + rev $s3,$s3 +#endif +#endif + bl _armv4_AES_encrypt + + ldr $rounds,[sp],#4 @ pop out +#if __ARM_ARCH__>=7 +#ifdef __ARMEL__ + rev $s0,$s0 + rev $s1,$s1 + rev $s2,$s2 + rev $s3,$s3 +#endif + str $s0,[$rounds,#0] + str $s1,[$rounds,#4] + str $s2,[$rounds,#8] + str $s3,[$rounds,#12] +#else + mov $t1,$s0,lsr#24 @ write output in endian-neutral + mov $t2,$s0,lsr#16 @ manner... + mov $t3,$s0,lsr#8 + strb $t1,[$rounds,#0] + strb $t2,[$rounds,#1] + mov $t1,$s1,lsr#24 + strb $t3,[$rounds,#2] + mov $t2,$s1,lsr#16 + strb $s0,[$rounds,#3] + mov $t3,$s1,lsr#8 + strb $t1,[$rounds,#4] + strb $t2,[$rounds,#5] + mov $t1,$s2,lsr#24 + strb $t3,[$rounds,#6] + mov $t2,$s2,lsr#16 + strb $s1,[$rounds,#7] + mov $t3,$s2,lsr#8 + strb $t1,[$rounds,#8] + strb $t2,[$rounds,#9] + mov $t1,$s3,lsr#24 + strb $t3,[$rounds,#10] + mov $t2,$s3,lsr#16 + strb $s2,[$rounds,#11] + mov $t3,$s3,lsr#8 + strb $t1,[$rounds,#12] + strb $t2,[$rounds,#13] + strb $t3,[$rounds,#14] + strb $s3,[$rounds,#15] +#endif +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r12,pc} +#else + ldmia sp!,{r4-r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size asm_AES_encrypt,.-asm_AES_encrypt + +.type _armv4_AES_encrypt,%function +.align 2 +_armv4_AES_encrypt: + str lr,[sp,#-4]! @ push lr + ldmia $key!,{$t1-$i1} + eor $s0,$s0,$t1 + ldr $rounds,[$key,#240-16] + eor $s1,$s1,$t2 + eor $s2,$s2,$t3 + eor $s3,$s3,$i1 + sub $rounds,$rounds,#1 + mov lr,#255 + + and $i1,lr,$s0 + and $i2,lr,$s0,lsr#8 + and $i3,lr,$s0,lsr#16 + mov $s0,$s0,lsr#24 +.Lenc_loop: + ldr $t1,[$tbl,$i1,lsl#2] @ Te3[s0>>0] + and $i1,lr,$s1,lsr#16 @ i0 + ldr $t2,[$tbl,$i2,lsl#2] @ Te2[s0>>8] + and $i2,lr,$s1 + ldr $t3,[$tbl,$i3,lsl#2] @ Te1[s0>>16] + and $i3,lr,$s1,lsr#8 + ldr $s0,[$tbl,$s0,lsl#2] @ Te0[s0>>24] + mov $s1,$s1,lsr#24 + + ldr $i1,[$tbl,$i1,lsl#2] @ Te1[s1>>16] + ldr $i2,[$tbl,$i2,lsl#2] @ Te3[s1>>0] + ldr $i3,[$tbl,$i3,lsl#2] @ Te2[s1>>8] + eor $s0,$s0,$i1,ror#8 + ldr $s1,[$tbl,$s1,lsl#2] @ Te0[s1>>24] + and $i1,lr,$s2,lsr#8 @ i0 + eor $t2,$t2,$i2,ror#8 + and $i2,lr,$s2,lsr#16 @ i1 + eor $t3,$t3,$i3,ror#8 + and $i3,lr,$s2 + ldr $i1,[$tbl,$i1,lsl#2] @ Te2[s2>>8] + eor $s1,$s1,$t1,ror#24 + ldr $i2,[$tbl,$i2,lsl#2] @ Te1[s2>>16] + mov $s2,$s2,lsr#24 + + ldr $i3,[$tbl,$i3,lsl#2] @ Te3[s2>>0] + eor $s0,$s0,$i1,ror#16 + ldr $s2,[$tbl,$s2,lsl#2] @ Te0[s2>>24] + and $i1,lr,$s3 @ i0 + eor $s1,$s1,$i2,ror#8 + and $i2,lr,$s3,lsr#8 @ i1 + eor $t3,$t3,$i3,ror#16 + and $i3,lr,$s3,lsr#16 @ i2 + ldr $i1,[$tbl,$i1,lsl#2] @ Te3[s3>>0] + eor $s2,$s2,$t2,ror#16 + ldr $i2,[$tbl,$i2,lsl#2] @ Te2[s3>>8] + mov $s3,$s3,lsr#24 + + ldr $i3,[$tbl,$i3,lsl#2] @ Te1[s3>>16] + eor $s0,$s0,$i1,ror#24 + ldr $i1,[$key],#16 + eor $s1,$s1,$i2,ror#16 + ldr $s3,[$tbl,$s3,lsl#2] @ Te0[s3>>24] + eor $s2,$s2,$i3,ror#8 + ldr $t1,[$key,#-12] + eor $s3,$s3,$t3,ror#8 + + ldr $t2,[$key,#-8] + eor $s0,$s0,$i1 + ldr $t3,[$key,#-4] + and $i1,lr,$s0 + eor $s1,$s1,$t1 + and $i2,lr,$s0,lsr#8 + eor $s2,$s2,$t2 + and $i3,lr,$s0,lsr#16 + eor $s3,$s3,$t3 + mov $s0,$s0,lsr#24 + + subs $rounds,$rounds,#1 + bne .Lenc_loop + + add $tbl,$tbl,#2 + + ldrb $t1,[$tbl,$i1,lsl#2] @ Te4[s0>>0] + and $i1,lr,$s1,lsr#16 @ i0 + ldrb $t2,[$tbl,$i2,lsl#2] @ Te4[s0>>8] + and $i2,lr,$s1 + ldrb $t3,[$tbl,$i3,lsl#2] @ Te4[s0>>16] + and $i3,lr,$s1,lsr#8 + ldrb $s0,[$tbl,$s0,lsl#2] @ Te4[s0>>24] + mov $s1,$s1,lsr#24 + + ldrb $i1,[$tbl,$i1,lsl#2] @ Te4[s1>>16] + ldrb $i2,[$tbl,$i2,lsl#2] @ Te4[s1>>0] + ldrb $i3,[$tbl,$i3,lsl#2] @ Te4[s1>>8] + eor $s0,$i1,$s0,lsl#8 + ldrb $s1,[$tbl,$s1,lsl#2] @ Te4[s1>>24] + and $i1,lr,$s2,lsr#8 @ i0 + eor $t2,$i2,$t2,lsl#8 + and $i2,lr,$s2,lsr#16 @ i1 + eor $t3,$i3,$t3,lsl#8 + and $i3,lr,$s2 + ldrb $i1,[$tbl,$i1,lsl#2] @ Te4[s2>>8] + eor $s1,$t1,$s1,lsl#24 + ldrb $i2,[$tbl,$i2,lsl#2] @ Te4[s2>>16] + mov $s2,$s2,lsr#24 + + ldrb $i3,[$tbl,$i3,lsl#2] @ Te4[s2>>0] + eor $s0,$i1,$s0,lsl#8 + ldrb $s2,[$tbl,$s2,lsl#2] @ Te4[s2>>24] + and $i1,lr,$s3 @ i0 + eor $s1,$s1,$i2,lsl#16 + and $i2,lr,$s3,lsr#8 @ i1 + eor $t3,$i3,$t3,lsl#8 + and $i3,lr,$s3,lsr#16 @ i2 + ldrb $i1,[$tbl,$i1,lsl#2] @ Te4[s3>>0] + eor $s2,$t2,$s2,lsl#24 + ldrb $i2,[$tbl,$i2,lsl#2] @ Te4[s3>>8] + mov $s3,$s3,lsr#24 + + ldrb $i3,[$tbl,$i3,lsl#2] @ Te4[s3>>16] + eor $s0,$i1,$s0,lsl#8 + ldr $i1,[$key,#0] + ldrb $s3,[$tbl,$s3,lsl#2] @ Te4[s3>>24] + eor $s1,$s1,$i2,lsl#8 + ldr $t1,[$key,#4] + eor $s2,$s2,$i3,lsl#16 + ldr $t2,[$key,#8] + eor $s3,$t3,$s3,lsl#24 + ldr $t3,[$key,#12] + + eor $s0,$s0,$i1 + eor $s1,$s1,$t1 + eor $s2,$s2,$t2 + eor $s3,$s3,$t3 + + sub $tbl,$tbl,#2 + ldr pc,[sp],#4 @ pop and return +.size _armv4_AES_encrypt,.-_armv4_AES_encrypt + +.global asm_AES_set_encrypt_key +.hidden asm_AES_set_encrypt_key +.type asm_AES_set_encrypt_key,%function +.align 5 +asm_AES_set_encrypt_key: +_armv4_AES_set_encrypt_key: +#if __ARM_ARCH__<7 + sub r3,pc,#8 @ asm_AES_set_encrypt_key +#else + adr r3,asm_AES_set_encrypt_key +#endif + teq r0,#0 +#if __ARM_ARCH__>=7 + itt eq @ Thumb2 thing, sanity check in ARM +#endif + moveq r0,#-1 + beq .Labrt + teq r2,#0 +#if __ARM_ARCH__>=7 + itt eq @ Thumb2 thing, sanity check in ARM +#endif + moveq r0,#-1 + beq .Labrt + + teq r1,#128 + beq .Lok + teq r1,#192 + beq .Lok + teq r1,#256 +#if __ARM_ARCH__>=7 + itt ne @ Thumb2 thing, sanity check in ARM +#endif + movne r0,#-1 + bne .Labrt + +.Lok: stmdb sp!,{r4-r12,lr} + mov $rounds,r0 @ inp + mov lr,r1 @ bits + mov $key,r2 @ key + +#ifdef __APPLE__ + adr $tbl,AES_Te+1024 @ Te4 +#else + sub $tbl,r3,#_armv4_AES_set_encrypt_key-AES_Te-1024 @ Te4 +#endif + +#if __ARM_ARCH__<7 + ldrb $s0,[$rounds,#3] @ load input data in endian-neutral + ldrb $t1,[$rounds,#2] @ manner... + ldrb $t2,[$rounds,#1] + ldrb $t3,[$rounds,#0] + orr $s0,$s0,$t1,lsl#8 + ldrb $s1,[$rounds,#7] + orr $s0,$s0,$t2,lsl#16 + ldrb $t1,[$rounds,#6] + orr $s0,$s0,$t3,lsl#24 + ldrb $t2,[$rounds,#5] + ldrb $t3,[$rounds,#4] + orr $s1,$s1,$t1,lsl#8 + ldrb $s2,[$rounds,#11] + orr $s1,$s1,$t2,lsl#16 + ldrb $t1,[$rounds,#10] + orr $s1,$s1,$t3,lsl#24 + ldrb $t2,[$rounds,#9] + ldrb $t3,[$rounds,#8] + orr $s2,$s2,$t1,lsl#8 + ldrb $s3,[$rounds,#15] + orr $s2,$s2,$t2,lsl#16 + ldrb $t1,[$rounds,#14] + orr $s2,$s2,$t3,lsl#24 + ldrb $t2,[$rounds,#13] + ldrb $t3,[$rounds,#12] + orr $s3,$s3,$t1,lsl#8 + str $s0,[$key],#16 + orr $s3,$s3,$t2,lsl#16 + str $s1,[$key,#-12] + orr $s3,$s3,$t3,lsl#24 + str $s2,[$key,#-8] + str $s3,[$key,#-4] +#else + ldr $s0,[$rounds,#0] + ldr $s1,[$rounds,#4] + ldr $s2,[$rounds,#8] + ldr $s3,[$rounds,#12] +#ifdef __ARMEL__ + rev $s0,$s0 + rev $s1,$s1 + rev $s2,$s2 + rev $s3,$s3 +#endif + str $s0,[$key],#16 + str $s1,[$key,#-12] + str $s2,[$key,#-8] + str $s3,[$key,#-4] +#endif + + teq lr,#128 + bne .Lnot128 + mov $rounds,#10 + str $rounds,[$key,#240-16] + add $t3,$tbl,#256 @ rcon + mov lr,#255 + +.L128_loop: + and $t2,lr,$s3,lsr#24 + and $i1,lr,$s3,lsr#16 + ldrb $t2,[$tbl,$t2] + and $i2,lr,$s3,lsr#8 + ldrb $i1,[$tbl,$i1] + and $i3,lr,$s3 + ldrb $i2,[$tbl,$i2] + orr $t2,$t2,$i1,lsl#24 + ldrb $i3,[$tbl,$i3] + orr $t2,$t2,$i2,lsl#16 + ldr $t1,[$t3],#4 @ rcon[i++] + orr $t2,$t2,$i3,lsl#8 + eor $t2,$t2,$t1 + eor $s0,$s0,$t2 @ rk[4]=rk[0]^... + eor $s1,$s1,$s0 @ rk[5]=rk[1]^rk[4] + str $s0,[$key],#16 + eor $s2,$s2,$s1 @ rk[6]=rk[2]^rk[5] + str $s1,[$key,#-12] + eor $s3,$s3,$s2 @ rk[7]=rk[3]^rk[6] + str $s2,[$key,#-8] + subs $rounds,$rounds,#1 + str $s3,[$key,#-4] + bne .L128_loop + sub r2,$key,#176 + b .Ldone + +.Lnot128: +#if __ARM_ARCH__<7 + ldrb $i2,[$rounds,#19] + ldrb $t1,[$rounds,#18] + ldrb $t2,[$rounds,#17] + ldrb $t3,[$rounds,#16] + orr $i2,$i2,$t1,lsl#8 + ldrb $i3,[$rounds,#23] + orr $i2,$i2,$t2,lsl#16 + ldrb $t1,[$rounds,#22] + orr $i2,$i2,$t3,lsl#24 + ldrb $t2,[$rounds,#21] + ldrb $t3,[$rounds,#20] + orr $i3,$i3,$t1,lsl#8 + orr $i3,$i3,$t2,lsl#16 + str $i2,[$key],#8 + orr $i3,$i3,$t3,lsl#24 + str $i3,[$key,#-4] +#else + ldr $i2,[$rounds,#16] + ldr $i3,[$rounds,#20] +#ifdef __ARMEL__ + rev $i2,$i2 + rev $i3,$i3 +#endif + str $i2,[$key],#8 + str $i3,[$key,#-4] +#endif + + teq lr,#192 + bne .Lnot192 + mov $rounds,#12 + str $rounds,[$key,#240-24] + add $t3,$tbl,#256 @ rcon + mov lr,#255 + mov $rounds,#8 + +.L192_loop: + and $t2,lr,$i3,lsr#24 + and $i1,lr,$i3,lsr#16 + ldrb $t2,[$tbl,$t2] + and $i2,lr,$i3,lsr#8 + ldrb $i1,[$tbl,$i1] + and $i3,lr,$i3 + ldrb $i2,[$tbl,$i2] + orr $t2,$t2,$i1,lsl#24 + ldrb $i3,[$tbl,$i3] + orr $t2,$t2,$i2,lsl#16 + ldr $t1,[$t3],#4 @ rcon[i++] + orr $t2,$t2,$i3,lsl#8 + eor $i3,$t2,$t1 + eor $s0,$s0,$i3 @ rk[6]=rk[0]^... + eor $s1,$s1,$s0 @ rk[7]=rk[1]^rk[6] + str $s0,[$key],#24 + eor $s2,$s2,$s1 @ rk[8]=rk[2]^rk[7] + str $s1,[$key,#-20] + eor $s3,$s3,$s2 @ rk[9]=rk[3]^rk[8] + str $s2,[$key,#-16] + subs $rounds,$rounds,#1 + str $s3,[$key,#-12] +#if __ARM_ARCH__>=7 + itt eq @ Thumb2 thing, sanity check in ARM +#endif + subeq r2,$key,#216 + beq .Ldone + + ldr $i1,[$key,#-32] + ldr $i2,[$key,#-28] + eor $i1,$i1,$s3 @ rk[10]=rk[4]^rk[9] + eor $i3,$i2,$i1 @ rk[11]=rk[5]^rk[10] + str $i1,[$key,#-8] + str $i3,[$key,#-4] + b .L192_loop + +.Lnot192: +#if __ARM_ARCH__<7 + ldrb $i2,[$rounds,#27] + ldrb $t1,[$rounds,#26] + ldrb $t2,[$rounds,#25] + ldrb $t3,[$rounds,#24] + orr $i2,$i2,$t1,lsl#8 + ldrb $i3,[$rounds,#31] + orr $i2,$i2,$t2,lsl#16 + ldrb $t1,[$rounds,#30] + orr $i2,$i2,$t3,lsl#24 + ldrb $t2,[$rounds,#29] + ldrb $t3,[$rounds,#28] + orr $i3,$i3,$t1,lsl#8 + orr $i3,$i3,$t2,lsl#16 + str $i2,[$key],#8 + orr $i3,$i3,$t3,lsl#24 + str $i3,[$key,#-4] +#else + ldr $i2,[$rounds,#24] + ldr $i3,[$rounds,#28] +#ifdef __ARMEL__ + rev $i2,$i2 + rev $i3,$i3 +#endif + str $i2,[$key],#8 + str $i3,[$key,#-4] +#endif + + mov $rounds,#14 + str $rounds,[$key,#240-32] + add $t3,$tbl,#256 @ rcon + mov lr,#255 + mov $rounds,#7 + +.L256_loop: + and $t2,lr,$i3,lsr#24 + and $i1,lr,$i3,lsr#16 + ldrb $t2,[$tbl,$t2] + and $i2,lr,$i3,lsr#8 + ldrb $i1,[$tbl,$i1] + and $i3,lr,$i3 + ldrb $i2,[$tbl,$i2] + orr $t2,$t2,$i1,lsl#24 + ldrb $i3,[$tbl,$i3] + orr $t2,$t2,$i2,lsl#16 + ldr $t1,[$t3],#4 @ rcon[i++] + orr $t2,$t2,$i3,lsl#8 + eor $i3,$t2,$t1 + eor $s0,$s0,$i3 @ rk[8]=rk[0]^... + eor $s1,$s1,$s0 @ rk[9]=rk[1]^rk[8] + str $s0,[$key],#32 + eor $s2,$s2,$s1 @ rk[10]=rk[2]^rk[9] + str $s1,[$key,#-28] + eor $s3,$s3,$s2 @ rk[11]=rk[3]^rk[10] + str $s2,[$key,#-24] + subs $rounds,$rounds,#1 + str $s3,[$key,#-20] +#if __ARM_ARCH__>=7 + itt eq @ Thumb2 thing, sanity check in ARM +#endif + subeq r2,$key,#256 + beq .Ldone + + and $t2,lr,$s3 + and $i1,lr,$s3,lsr#8 + ldrb $t2,[$tbl,$t2] + and $i2,lr,$s3,lsr#16 + ldrb $i1,[$tbl,$i1] + and $i3,lr,$s3,lsr#24 + ldrb $i2,[$tbl,$i2] + orr $t2,$t2,$i1,lsl#8 + ldrb $i3,[$tbl,$i3] + orr $t2,$t2,$i2,lsl#16 + ldr $t1,[$key,#-48] + orr $t2,$t2,$i3,lsl#24 + + ldr $i1,[$key,#-44] + ldr $i2,[$key,#-40] + eor $t1,$t1,$t2 @ rk[12]=rk[4]^... + ldr $i3,[$key,#-36] + eor $i1,$i1,$t1 @ rk[13]=rk[5]^rk[12] + str $t1,[$key,#-16] + eor $i2,$i2,$i1 @ rk[14]=rk[6]^rk[13] + str $i1,[$key,#-12] + eor $i3,$i3,$i2 @ rk[15]=rk[7]^rk[14] + str $i2,[$key,#-8] + str $i3,[$key,#-4] + b .L256_loop + +.align 2 +.Ldone: mov r0,#0 + ldmia sp!,{r4-r12,lr} +.Labrt: +#if __ARM_ARCH__>=5 + ret @ bx lr +#else + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size asm_AES_set_encrypt_key,.-asm_AES_set_encrypt_key + +.global asm_AES_set_decrypt_key +.hidden asm_AES_set_decrypt_key +.type asm_AES_set_decrypt_key,%function +.align 5 +asm_AES_set_decrypt_key: + str lr,[sp,#-4]! @ push lr + bl _armv4_AES_set_encrypt_key + teq r0,#0 + ldr lr,[sp],#4 @ pop lr + bne .Labrt + + mov r0,r2 @ asm_AES_set_encrypt_key preserves r2, + mov r1,r2 @ which is AES_KEY *key + b _armv4_AES_set_enc2dec_key +.size asm_AES_set_decrypt_key,.-asm_AES_set_decrypt_key + +@ void AES_set_enc2dec_key(const AES_KEY *inp,AES_KEY *out) +.global AES_set_enc2dec_key +.hidden AES_set_enc2dec_key +.type AES_set_enc2dec_key,%function +.align 5 +AES_set_enc2dec_key: +_armv4_AES_set_enc2dec_key: + stmdb sp!,{r4-r12,lr} + + ldr $rounds,[r0,#240] + mov $i1,r0 @ input + add $i2,r0,$rounds,lsl#4 + mov $key,r1 @ ouput + add $tbl,r1,$rounds,lsl#4 + str $rounds,[r1,#240] + +.Linv: ldr $s0,[$i1],#16 + ldr $s1,[$i1,#-12] + ldr $s2,[$i1,#-8] + ldr $s3,[$i1,#-4] + ldr $t1,[$i2],#-16 + ldr $t2,[$i2,#16+4] + ldr $t3,[$i2,#16+8] + ldr $i3,[$i2,#16+12] + str $s0,[$tbl],#-16 + str $s1,[$tbl,#16+4] + str $s2,[$tbl,#16+8] + str $s3,[$tbl,#16+12] + str $t1,[$key],#16 + str $t2,[$key,#-12] + str $t3,[$key,#-8] + str $i3,[$key,#-4] + teq $i1,$i2 + bne .Linv + + ldr $s0,[$i1] + ldr $s1,[$i1,#4] + ldr $s2,[$i1,#8] + ldr $s3,[$i1,#12] + str $s0,[$key] + str $s1,[$key,#4] + str $s2,[$key,#8] + str $s3,[$key,#12] + sub $key,$key,$rounds,lsl#3 +___ +$mask80=$i1; +$mask1b=$i2; +$mask7f=$i3; +$code.=<<___; + ldr $s0,[$key,#16]! @ prefetch tp1 + mov $mask80,#0x80 + mov $mask1b,#0x1b + orr $mask80,$mask80,#0x8000 + orr $mask1b,$mask1b,#0x1b00 + orr $mask80,$mask80,$mask80,lsl#16 + orr $mask1b,$mask1b,$mask1b,lsl#16 + sub $rounds,$rounds,#1 + mvn $mask7f,$mask80 + mov $rounds,$rounds,lsl#2 @ (rounds-1)*4 + +.Lmix: and $t1,$s0,$mask80 + and $s1,$s0,$mask7f + sub $t1,$t1,$t1,lsr#7 + and $t1,$t1,$mask1b + eor $s1,$t1,$s1,lsl#1 @ tp2 + + and $t1,$s1,$mask80 + and $s2,$s1,$mask7f + sub $t1,$t1,$t1,lsr#7 + and $t1,$t1,$mask1b + eor $s2,$t1,$s2,lsl#1 @ tp4 + + and $t1,$s2,$mask80 + and $s3,$s2,$mask7f + sub $t1,$t1,$t1,lsr#7 + and $t1,$t1,$mask1b + eor $s3,$t1,$s3,lsl#1 @ tp8 + + eor $t1,$s1,$s2 + eor $t2,$s0,$s3 @ tp9 + eor $t1,$t1,$s3 @ tpe + eor $t1,$t1,$s1,ror#24 + eor $t1,$t1,$t2,ror#24 @ ^= ROTATE(tpb=tp9^tp2,8) + eor $t1,$t1,$s2,ror#16 + eor $t1,$t1,$t2,ror#16 @ ^= ROTATE(tpd=tp9^tp4,16) + eor $t1,$t1,$t2,ror#8 @ ^= ROTATE(tp9,24) + + ldr $s0,[$key,#4] @ prefetch tp1 + str $t1,[$key],#4 + subs $rounds,$rounds,#1 + bne .Lmix + + mov r0,#0 +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r12,pc} +#else + ldmia sp!,{r4-r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size AES_set_enc2dec_key,.-AES_set_enc2dec_key + +.type AES_Td,%object +.align 5 +AES_Td: +.word 0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96 +.word 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393 +.word 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25 +.word 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f +.word 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1 +.word 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6 +.word 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da +.word 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844 +.word 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd +.word 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4 +.word 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45 +.word 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94 +.word 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7 +.word 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a +.word 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5 +.word 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c +.word 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1 +.word 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a +.word 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75 +.word 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051 +.word 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46 +.word 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff +.word 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77 +.word 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb +.word 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000 +.word 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e +.word 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927 +.word 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a +.word 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e +.word 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16 +.word 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d +.word 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8 +.word 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd +.word 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34 +.word 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163 +.word 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120 +.word 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d +.word 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0 +.word 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422 +.word 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef +.word 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36 +.word 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4 +.word 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662 +.word 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5 +.word 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3 +.word 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b +.word 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8 +.word 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6 +.word 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6 +.word 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0 +.word 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815 +.word 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f +.word 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df +.word 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f +.word 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e +.word 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713 +.word 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89 +.word 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c +.word 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf +.word 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86 +.word 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f +.word 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541 +.word 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190 +.word 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742 +@ Td4[256] +.byte 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38 +.byte 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb +.byte 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87 +.byte 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb +.byte 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d +.byte 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e +.byte 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2 +.byte 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 +.byte 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16 +.byte 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 +.byte 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda +.byte 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 +.byte 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a +.byte 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 +.byte 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02 +.byte 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b +.byte 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea +.byte 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 +.byte 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85 +.byte 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e +.byte 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89 +.byte 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b +.byte 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20 +.byte 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 +.byte 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31 +.byte 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f +.byte 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d +.byte 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef +.byte 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0 +.byte 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 +.byte 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26 +.byte 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d +.size AES_Td,.-AES_Td + +@ void asm_AES_decrypt(const unsigned char *in, unsigned char *out, +@ const AES_KEY *key) { +.global asm_AES_decrypt +.hidden asm_AES_decrypt +.type asm_AES_decrypt,%function +.align 5 +asm_AES_decrypt: +#if __ARM_ARCH__<7 + sub r3,pc,#8 @ asm_AES_decrypt +#else + adr r3,asm_AES_decrypt +#endif + stmdb sp!,{r1,r4-r12,lr} +#ifdef __APPLE__ + adr $tbl,AES_Td +#else + sub $tbl,r3,#asm_AES_decrypt-AES_Td @ Td +#endif + mov $rounds,r0 @ inp + mov $key,r2 +#if __ARM_ARCH__<7 + ldrb $s0,[$rounds,#3] @ load input data in endian-neutral + ldrb $t1,[$rounds,#2] @ manner... + ldrb $t2,[$rounds,#1] + ldrb $t3,[$rounds,#0] + orr $s0,$s0,$t1,lsl#8 + ldrb $s1,[$rounds,#7] + orr $s0,$s0,$t2,lsl#16 + ldrb $t1,[$rounds,#6] + orr $s0,$s0,$t3,lsl#24 + ldrb $t2,[$rounds,#5] + ldrb $t3,[$rounds,#4] + orr $s1,$s1,$t1,lsl#8 + ldrb $s2,[$rounds,#11] + orr $s1,$s1,$t2,lsl#16 + ldrb $t1,[$rounds,#10] + orr $s1,$s1,$t3,lsl#24 + ldrb $t2,[$rounds,#9] + ldrb $t3,[$rounds,#8] + orr $s2,$s2,$t1,lsl#8 + ldrb $s3,[$rounds,#15] + orr $s2,$s2,$t2,lsl#16 + ldrb $t1,[$rounds,#14] + orr $s2,$s2,$t3,lsl#24 + ldrb $t2,[$rounds,#13] + ldrb $t3,[$rounds,#12] + orr $s3,$s3,$t1,lsl#8 + orr $s3,$s3,$t2,lsl#16 + orr $s3,$s3,$t3,lsl#24 +#else + ldr $s0,[$rounds,#0] + ldr $s1,[$rounds,#4] + ldr $s2,[$rounds,#8] + ldr $s3,[$rounds,#12] +#ifdef __ARMEL__ + rev $s0,$s0 + rev $s1,$s1 + rev $s2,$s2 + rev $s3,$s3 +#endif +#endif + bl _armv4_AES_decrypt + + ldr $rounds,[sp],#4 @ pop out +#if __ARM_ARCH__>=7 +#ifdef __ARMEL__ + rev $s0,$s0 + rev $s1,$s1 + rev $s2,$s2 + rev $s3,$s3 +#endif + str $s0,[$rounds,#0] + str $s1,[$rounds,#4] + str $s2,[$rounds,#8] + str $s3,[$rounds,#12] +#else + mov $t1,$s0,lsr#24 @ write output in endian-neutral + mov $t2,$s0,lsr#16 @ manner... + mov $t3,$s0,lsr#8 + strb $t1,[$rounds,#0] + strb $t2,[$rounds,#1] + mov $t1,$s1,lsr#24 + strb $t3,[$rounds,#2] + mov $t2,$s1,lsr#16 + strb $s0,[$rounds,#3] + mov $t3,$s1,lsr#8 + strb $t1,[$rounds,#4] + strb $t2,[$rounds,#5] + mov $t1,$s2,lsr#24 + strb $t3,[$rounds,#6] + mov $t2,$s2,lsr#16 + strb $s1,[$rounds,#7] + mov $t3,$s2,lsr#8 + strb $t1,[$rounds,#8] + strb $t2,[$rounds,#9] + mov $t1,$s3,lsr#24 + strb $t3,[$rounds,#10] + mov $t2,$s3,lsr#16 + strb $s2,[$rounds,#11] + mov $t3,$s3,lsr#8 + strb $t1,[$rounds,#12] + strb $t2,[$rounds,#13] + strb $t3,[$rounds,#14] + strb $s3,[$rounds,#15] +#endif +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r12,pc} +#else + ldmia sp!,{r4-r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size asm_AES_decrypt,.-asm_AES_decrypt + +.type _armv4_AES_decrypt,%function +.align 2 +_armv4_AES_decrypt: + str lr,[sp,#-4]! @ push lr + ldmia $key!,{$t1-$i1} + eor $s0,$s0,$t1 + ldr $rounds,[$key,#240-16] + eor $s1,$s1,$t2 + eor $s2,$s2,$t3 + eor $s3,$s3,$i1 + sub $rounds,$rounds,#1 + mov lr,#255 + + and $i1,lr,$s0,lsr#16 + and $i2,lr,$s0,lsr#8 + and $i3,lr,$s0 + mov $s0,$s0,lsr#24 +.Ldec_loop: + ldr $t1,[$tbl,$i1,lsl#2] @ Td1[s0>>16] + and $i1,lr,$s1 @ i0 + ldr $t2,[$tbl,$i2,lsl#2] @ Td2[s0>>8] + and $i2,lr,$s1,lsr#16 + ldr $t3,[$tbl,$i3,lsl#2] @ Td3[s0>>0] + and $i3,lr,$s1,lsr#8 + ldr $s0,[$tbl,$s0,lsl#2] @ Td0[s0>>24] + mov $s1,$s1,lsr#24 + + ldr $i1,[$tbl,$i1,lsl#2] @ Td3[s1>>0] + ldr $i2,[$tbl,$i2,lsl#2] @ Td1[s1>>16] + ldr $i3,[$tbl,$i3,lsl#2] @ Td2[s1>>8] + eor $s0,$s0,$i1,ror#24 + ldr $s1,[$tbl,$s1,lsl#2] @ Td0[s1>>24] + and $i1,lr,$s2,lsr#8 @ i0 + eor $t2,$i2,$t2,ror#8 + and $i2,lr,$s2 @ i1 + eor $t3,$i3,$t3,ror#8 + and $i3,lr,$s2,lsr#16 + ldr $i1,[$tbl,$i1,lsl#2] @ Td2[s2>>8] + eor $s1,$s1,$t1,ror#8 + ldr $i2,[$tbl,$i2,lsl#2] @ Td3[s2>>0] + mov $s2,$s2,lsr#24 + + ldr $i3,[$tbl,$i3,lsl#2] @ Td1[s2>>16] + eor $s0,$s0,$i1,ror#16 + ldr $s2,[$tbl,$s2,lsl#2] @ Td0[s2>>24] + and $i1,lr,$s3,lsr#16 @ i0 + eor $s1,$s1,$i2,ror#24 + and $i2,lr,$s3,lsr#8 @ i1 + eor $t3,$i3,$t3,ror#8 + and $i3,lr,$s3 @ i2 + ldr $i1,[$tbl,$i1,lsl#2] @ Td1[s3>>16] + eor $s2,$s2,$t2,ror#8 + ldr $i2,[$tbl,$i2,lsl#2] @ Td2[s3>>8] + mov $s3,$s3,lsr#24 + + ldr $i3,[$tbl,$i3,lsl#2] @ Td3[s3>>0] + eor $s0,$s0,$i1,ror#8 + ldr $i1,[$key],#16 + eor $s1,$s1,$i2,ror#16 + ldr $s3,[$tbl,$s3,lsl#2] @ Td0[s3>>24] + eor $s2,$s2,$i3,ror#24 + + ldr $t1,[$key,#-12] + eor $s0,$s0,$i1 + ldr $t2,[$key,#-8] + eor $s3,$s3,$t3,ror#8 + ldr $t3,[$key,#-4] + and $i1,lr,$s0,lsr#16 + eor $s1,$s1,$t1 + and $i2,lr,$s0,lsr#8 + eor $s2,$s2,$t2 + and $i3,lr,$s0 + eor $s3,$s3,$t3 + mov $s0,$s0,lsr#24 + + subs $rounds,$rounds,#1 + bne .Ldec_loop + + add $tbl,$tbl,#1024 + + ldr $t2,[$tbl,#0] @ prefetch Td4 + ldr $t3,[$tbl,#32] + ldr $t1,[$tbl,#64] + ldr $t2,[$tbl,#96] + ldr $t3,[$tbl,#128] + ldr $t1,[$tbl,#160] + ldr $t2,[$tbl,#192] + ldr $t3,[$tbl,#224] + + ldrb $s0,[$tbl,$s0] @ Td4[s0>>24] + ldrb $t1,[$tbl,$i1] @ Td4[s0>>16] + and $i1,lr,$s1 @ i0 + ldrb $t2,[$tbl,$i2] @ Td4[s0>>8] + and $i2,lr,$s1,lsr#16 + ldrb $t3,[$tbl,$i3] @ Td4[s0>>0] + and $i3,lr,$s1,lsr#8 + + add $s1,$tbl,$s1,lsr#24 + ldrb $i1,[$tbl,$i1] @ Td4[s1>>0] + ldrb $s1,[$s1] @ Td4[s1>>24] + ldrb $i2,[$tbl,$i2] @ Td4[s1>>16] + eor $s0,$i1,$s0,lsl#24 + ldrb $i3,[$tbl,$i3] @ Td4[s1>>8] + eor $s1,$t1,$s1,lsl#8 + and $i1,lr,$s2,lsr#8 @ i0 + eor $t2,$t2,$i2,lsl#8 + and $i2,lr,$s2 @ i1 + ldrb $i1,[$tbl,$i1] @ Td4[s2>>8] + eor $t3,$t3,$i3,lsl#8 + ldrb $i2,[$tbl,$i2] @ Td4[s2>>0] + and $i3,lr,$s2,lsr#16 + + add $s2,$tbl,$s2,lsr#24 + ldrb $s2,[$s2] @ Td4[s2>>24] + eor $s0,$s0,$i1,lsl#8 + ldrb $i3,[$tbl,$i3] @ Td4[s2>>16] + eor $s1,$i2,$s1,lsl#16 + and $i1,lr,$s3,lsr#16 @ i0 + eor $s2,$t2,$s2,lsl#16 + and $i2,lr,$s3,lsr#8 @ i1 + ldrb $i1,[$tbl,$i1] @ Td4[s3>>16] + eor $t3,$t3,$i3,lsl#16 + ldrb $i2,[$tbl,$i2] @ Td4[s3>>8] + and $i3,lr,$s3 @ i2 + + add $s3,$tbl,$s3,lsr#24 + ldrb $i3,[$tbl,$i3] @ Td4[s3>>0] + ldrb $s3,[$s3] @ Td4[s3>>24] + eor $s0,$s0,$i1,lsl#16 + ldr $i1,[$key,#0] + eor $s1,$s1,$i2,lsl#8 + ldr $t1,[$key,#4] + eor $s2,$i3,$s2,lsl#8 + ldr $t2,[$key,#8] + eor $s3,$t3,$s3,lsl#24 + ldr $t3,[$key,#12] + + eor $s0,$s0,$i1 + eor $s1,$s1,$t1 + eor $s2,$s2,$t2 + eor $s3,$s3,$t3 + + sub $tbl,$tbl,#1024 + ldr pc,[sp],#4 @ pop and return +.size _armv4_AES_decrypt,.-_armv4_AES_decrypt +.asciz "AES for ARMv4, CRYPTOGAMS by " +.align 2 + +#endif +___ + +$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4 +$code =~ s/\bret\b/bx\tlr/gm; + +open SELF,$0; +while() { + next if (/^#!/); + last if (!s/^#/@/ and !/^$/); + print; +} +close SELF; + +print $code; +close STDOUT; # enforce flush diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-x86_64.pl new file mode 100644 index 00000000..4b6e1b44 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/aes-x86_64.pl @@ -0,0 +1,2805 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# Version 2.1. +# +# aes-*-cbc benchmarks are improved by >70% [compared to gcc 3.3.2 on +# Opteron 240 CPU] plus all the bells-n-whistles from 32-bit version +# [you'll notice a lot of resemblance], such as compressed S-boxes +# in little-endian byte order, prefetch of these tables in CBC mode, +# as well as avoiding L1 cache aliasing between stack frame and key +# schedule and already mentioned tables, compressed Td4... +# +# Performance in number of cycles per processed byte for 128-bit key: +# +# ECB encrypt ECB decrypt CBC large chunk +# AMD64 33 43 13.0 +# EM64T 38 56 18.6(*) +# Core 2 30 42 14.5(*) +# Atom 65 86 32.1(*) +# +# (*) with hyper-threading off + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$verticalspin=1; # unlike 32-bit version $verticalspin performs + # ~15% better on both AMD and Intel cores +$speed_limit=512; # see aes-586.pl for details + +$code=".text\n"; + +$s0="%eax"; +$s1="%ebx"; +$s2="%ecx"; +$s3="%edx"; +$acc0="%esi"; $mask80="%rsi"; +$acc1="%edi"; $maskfe="%rdi"; +$acc2="%ebp"; $mask1b="%rbp"; +$inp="%r8"; +$out="%r9"; +$t0="%r10d"; +$t1="%r11d"; +$t2="%r12d"; +$rnds="%r13d"; +$sbox="%r14"; +$key="%r15"; + +sub hi() { my $r=shift; $r =~ s/%[er]([a-d])x/%\1h/; $r; } +sub lo() { my $r=shift; $r =~ s/%[er]([a-d])x/%\1l/; + $r =~ s/%[er]([sd]i)/%\1l/; + $r =~ s/%(r[0-9]+)[d]?/%\1b/; $r; } +sub LO() { my $r=shift; $r =~ s/%r([a-z]+)/%e\1/; + $r =~ s/%r([0-9]+)/%r\1d/; $r; } +sub _data_word() +{ my $i; + while(defined($i=shift)) { $code.=sprintf".long\t0x%08x,0x%08x\n",$i,$i; } +} +sub data_word() +{ my $i; + my $last=pop(@_); + $code.=".long\t"; + while(defined($i=shift)) { $code.=sprintf"0x%08x,",$i; } + $code.=sprintf"0x%08x\n",$last; +} + +sub data_byte() +{ my $i; + my $last=pop(@_); + $code.=".byte\t"; + while(defined($i=shift)) { $code.=sprintf"0x%02x,",$i&0xff; } + $code.=sprintf"0x%02x\n",$last&0xff; +} + +sub encvert() +{ my $t3="%r8d"; # zaps $inp! + +$code.=<<___; + # favor 3-way issue Opteron pipeline... + movzb `&lo("$s0")`,$acc0 + movzb `&lo("$s1")`,$acc1 + movzb `&lo("$s2")`,$acc2 + mov 0($sbox,$acc0,8),$t0 + mov 0($sbox,$acc1,8),$t1 + mov 0($sbox,$acc2,8),$t2 + + movzb `&hi("$s1")`,$acc0 + movzb `&hi("$s2")`,$acc1 + movzb `&lo("$s3")`,$acc2 + xor 3($sbox,$acc0,8),$t0 + xor 3($sbox,$acc1,8),$t1 + mov 0($sbox,$acc2,8),$t3 + + movzb `&hi("$s3")`,$acc0 + shr \$16,$s2 + movzb `&hi("$s0")`,$acc2 + xor 3($sbox,$acc0,8),$t2 + shr \$16,$s3 + xor 3($sbox,$acc2,8),$t3 + + shr \$16,$s1 + lea 16($key),$key + shr \$16,$s0 + + movzb `&lo("$s2")`,$acc0 + movzb `&lo("$s3")`,$acc1 + movzb `&lo("$s0")`,$acc2 + xor 2($sbox,$acc0,8),$t0 + xor 2($sbox,$acc1,8),$t1 + xor 2($sbox,$acc2,8),$t2 + + movzb `&hi("$s3")`,$acc0 + movzb `&hi("$s0")`,$acc1 + movzb `&lo("$s1")`,$acc2 + xor 1($sbox,$acc0,8),$t0 + xor 1($sbox,$acc1,8),$t1 + xor 2($sbox,$acc2,8),$t3 + + mov 12($key),$s3 + movzb `&hi("$s1")`,$acc1 + movzb `&hi("$s2")`,$acc2 + mov 0($key),$s0 + xor 1($sbox,$acc1,8),$t2 + xor 1($sbox,$acc2,8),$t3 + + mov 4($key),$s1 + mov 8($key),$s2 + xor $t0,$s0 + xor $t1,$s1 + xor $t2,$s2 + xor $t3,$s3 +___ +} + +sub enclastvert() +{ my $t3="%r8d"; # zaps $inp! + +$code.=<<___; + movzb `&lo("$s0")`,$acc0 + movzb `&lo("$s1")`,$acc1 + movzb `&lo("$s2")`,$acc2 + movzb 2($sbox,$acc0,8),$t0 + movzb 2($sbox,$acc1,8),$t1 + movzb 2($sbox,$acc2,8),$t2 + + movzb `&lo("$s3")`,$acc0 + movzb `&hi("$s1")`,$acc1 + movzb `&hi("$s2")`,$acc2 + movzb 2($sbox,$acc0,8),$t3 + mov 0($sbox,$acc1,8),$acc1 #$t0 + mov 0($sbox,$acc2,8),$acc2 #$t1 + + and \$0x0000ff00,$acc1 + and \$0x0000ff00,$acc2 + + xor $acc1,$t0 + xor $acc2,$t1 + shr \$16,$s2 + + movzb `&hi("$s3")`,$acc0 + movzb `&hi("$s0")`,$acc1 + shr \$16,$s3 + mov 0($sbox,$acc0,8),$acc0 #$t2 + mov 0($sbox,$acc1,8),$acc1 #$t3 + + and \$0x0000ff00,$acc0 + and \$0x0000ff00,$acc1 + shr \$16,$s1 + xor $acc0,$t2 + xor $acc1,$t3 + shr \$16,$s0 + + movzb `&lo("$s2")`,$acc0 + movzb `&lo("$s3")`,$acc1 + movzb `&lo("$s0")`,$acc2 + mov 0($sbox,$acc0,8),$acc0 #$t0 + mov 0($sbox,$acc1,8),$acc1 #$t1 + mov 0($sbox,$acc2,8),$acc2 #$t2 + + and \$0x00ff0000,$acc0 + and \$0x00ff0000,$acc1 + and \$0x00ff0000,$acc2 + + xor $acc0,$t0 + xor $acc1,$t1 + xor $acc2,$t2 + + movzb `&lo("$s1")`,$acc0 + movzb `&hi("$s3")`,$acc1 + movzb `&hi("$s0")`,$acc2 + mov 0($sbox,$acc0,8),$acc0 #$t3 + mov 2($sbox,$acc1,8),$acc1 #$t0 + mov 2($sbox,$acc2,8),$acc2 #$t1 + + and \$0x00ff0000,$acc0 + and \$0xff000000,$acc1 + and \$0xff000000,$acc2 + + xor $acc0,$t3 + xor $acc1,$t0 + xor $acc2,$t1 + + movzb `&hi("$s1")`,$acc0 + movzb `&hi("$s2")`,$acc1 + mov 16+12($key),$s3 + mov 2($sbox,$acc0,8),$acc0 #$t2 + mov 2($sbox,$acc1,8),$acc1 #$t3 + mov 16+0($key),$s0 + + and \$0xff000000,$acc0 + and \$0xff000000,$acc1 + + xor $acc0,$t2 + xor $acc1,$t3 + + mov 16+4($key),$s1 + mov 16+8($key),$s2 + xor $t0,$s0 + xor $t1,$s1 + xor $t2,$s2 + xor $t3,$s3 +___ +} + +sub encstep() +{ my ($i,@s) = @_; + my $tmp0=$acc0; + my $tmp1=$acc1; + my $tmp2=$acc2; + my $out=($t0,$t1,$t2,$s[0])[$i]; + + if ($i==3) { + $tmp0=$s[1]; + $tmp1=$s[2]; + $tmp2=$s[3]; + } + $code.=" movzb ".&lo($s[0]).",$out\n"; + $code.=" mov $s[2],$tmp1\n" if ($i!=3); + $code.=" lea 16($key),$key\n" if ($i==0); + + $code.=" movzb ".&hi($s[1]).",$tmp0\n"; + $code.=" mov 0($sbox,$out,8),$out\n"; + + $code.=" shr \$16,$tmp1\n"; + $code.=" mov $s[3],$tmp2\n" if ($i!=3); + $code.=" xor 3($sbox,$tmp0,8),$out\n"; + + $code.=" movzb ".&lo($tmp1).",$tmp1\n"; + $code.=" shr \$24,$tmp2\n"; + $code.=" xor 4*$i($key),$out\n"; + + $code.=" xor 2($sbox,$tmp1,8),$out\n"; + $code.=" xor 1($sbox,$tmp2,8),$out\n"; + + $code.=" mov $t0,$s[1]\n" if ($i==3); + $code.=" mov $t1,$s[2]\n" if ($i==3); + $code.=" mov $t2,$s[3]\n" if ($i==3); + $code.="\n"; +} + +sub enclast() +{ my ($i,@s)=@_; + my $tmp0=$acc0; + my $tmp1=$acc1; + my $tmp2=$acc2; + my $out=($t0,$t1,$t2,$s[0])[$i]; + + if ($i==3) { + $tmp0=$s[1]; + $tmp1=$s[2]; + $tmp2=$s[3]; + } + $code.=" movzb ".&lo($s[0]).",$out\n"; + $code.=" mov $s[2],$tmp1\n" if ($i!=3); + + $code.=" mov 2($sbox,$out,8),$out\n"; + $code.=" shr \$16,$tmp1\n"; + $code.=" mov $s[3],$tmp2\n" if ($i!=3); + + $code.=" and \$0x000000ff,$out\n"; + $code.=" movzb ".&hi($s[1]).",$tmp0\n"; + $code.=" movzb ".&lo($tmp1).",$tmp1\n"; + $code.=" shr \$24,$tmp2\n"; + + $code.=" mov 0($sbox,$tmp0,8),$tmp0\n"; + $code.=" mov 0($sbox,$tmp1,8),$tmp1\n"; + $code.=" mov 2($sbox,$tmp2,8),$tmp2\n"; + + $code.=" and \$0x0000ff00,$tmp0\n"; + $code.=" and \$0x00ff0000,$tmp1\n"; + $code.=" and \$0xff000000,$tmp2\n"; + + $code.=" xor $tmp0,$out\n"; + $code.=" mov $t0,$s[1]\n" if ($i==3); + $code.=" xor $tmp1,$out\n"; + $code.=" mov $t1,$s[2]\n" if ($i==3); + $code.=" xor $tmp2,$out\n"; + $code.=" mov $t2,$s[3]\n" if ($i==3); + $code.="\n"; +} + +$code.=<<___; +.type _x86_64_AES_encrypt,\@abi-omnipotent +.align 16 +_x86_64_AES_encrypt: + xor 0($key),$s0 # xor with key + xor 4($key),$s1 + xor 8($key),$s2 + xor 12($key),$s3 + + mov 240($key),$rnds # load key->rounds + sub \$1,$rnds + jmp .Lenc_loop +.align 16 +.Lenc_loop: +___ + if ($verticalspin) { &encvert(); } + else { &encstep(0,$s0,$s1,$s2,$s3); + &encstep(1,$s1,$s2,$s3,$s0); + &encstep(2,$s2,$s3,$s0,$s1); + &encstep(3,$s3,$s0,$s1,$s2); + } +$code.=<<___; + sub \$1,$rnds + jnz .Lenc_loop +___ + if ($verticalspin) { &enclastvert(); } + else { &enclast(0,$s0,$s1,$s2,$s3); + &enclast(1,$s1,$s2,$s3,$s0); + &enclast(2,$s2,$s3,$s0,$s1); + &enclast(3,$s3,$s0,$s1,$s2); + $code.=<<___; + xor 16+0($key),$s0 # xor with key + xor 16+4($key),$s1 + xor 16+8($key),$s2 + xor 16+12($key),$s3 +___ + } +$code.=<<___; + .byte 0xf3,0xc3 # rep ret +.size _x86_64_AES_encrypt,.-_x86_64_AES_encrypt +___ + +# it's possible to implement this by shifting tN by 8, filling least +# significant byte with byte load and finally bswap-ing at the end, +# but such partial register load kills Core 2... +sub enccompactvert() +{ my ($t3,$t4,$t5)=("%r8d","%r9d","%r13d"); + +$code.=<<___; + movzb `&lo("$s0")`,$t0 + movzb `&lo("$s1")`,$t1 + movzb `&lo("$s2")`,$t2 + movzb `&lo("$s3")`,$t3 + movzb `&hi("$s1")`,$acc0 + movzb `&hi("$s2")`,$acc1 + shr \$16,$s2 + movzb `&hi("$s3")`,$acc2 + movzb ($sbox,$t0,1),$t0 + movzb ($sbox,$t1,1),$t1 + movzb ($sbox,$t2,1),$t2 + movzb ($sbox,$t3,1),$t3 + + movzb ($sbox,$acc0,1),$t4 #$t0 + movzb `&hi("$s0")`,$acc0 + movzb ($sbox,$acc1,1),$t5 #$t1 + movzb `&lo("$s2")`,$acc1 + movzb ($sbox,$acc2,1),$acc2 #$t2 + movzb ($sbox,$acc0,1),$acc0 #$t3 + + shl \$8,$t4 + shr \$16,$s3 + shl \$8,$t5 + xor $t4,$t0 + shr \$16,$s0 + movzb `&lo("$s3")`,$t4 + shr \$16,$s1 + xor $t5,$t1 + shl \$8,$acc2 + movzb `&lo("$s0")`,$t5 + movzb ($sbox,$acc1,1),$acc1 #$t0 + xor $acc2,$t2 + + shl \$8,$acc0 + movzb `&lo("$s1")`,$acc2 + shl \$16,$acc1 + xor $acc0,$t3 + movzb ($sbox,$t4,1),$t4 #$t1 + movzb `&hi("$s3")`,$acc0 + movzb ($sbox,$t5,1),$t5 #$t2 + xor $acc1,$t0 + + shr \$8,$s2 + movzb `&hi("$s0")`,$acc1 + shl \$16,$t4 + shr \$8,$s1 + shl \$16,$t5 + xor $t4,$t1 + movzb ($sbox,$acc2,1),$acc2 #$t3 + movzb ($sbox,$acc0,1),$acc0 #$t0 + movzb ($sbox,$acc1,1),$acc1 #$t1 + movzb ($sbox,$s2,1),$s3 #$t3 + movzb ($sbox,$s1,1),$s2 #$t2 + + shl \$16,$acc2 + xor $t5,$t2 + shl \$24,$acc0 + xor $acc2,$t3 + shl \$24,$acc1 + xor $acc0,$t0 + shl \$24,$s3 + xor $acc1,$t1 + shl \$24,$s2 + mov $t0,$s0 + mov $t1,$s1 + xor $t2,$s2 + xor $t3,$s3 +___ +} + +sub enctransform_ref() +{ my $sn = shift; + my ($acc,$r2,$tmp)=("%r8d","%r9d","%r13d"); + +$code.=<<___; + mov $sn,$acc + and \$0x80808080,$acc + mov $acc,$tmp + shr \$7,$tmp + lea ($sn,$sn),$r2 + sub $tmp,$acc + and \$0xfefefefe,$r2 + and \$0x1b1b1b1b,$acc + mov $sn,$tmp + xor $acc,$r2 + + xor $r2,$sn + rol \$24,$sn + xor $r2,$sn + ror \$16,$tmp + xor $tmp,$sn + ror \$8,$tmp + xor $tmp,$sn +___ +} + +# unlike decrypt case it does not pay off to parallelize enctransform +sub enctransform() +{ my ($t3,$r20,$r21)=($acc2,"%r8d","%r9d"); + +$code.=<<___; + mov \$0x80808080,$t0 + mov \$0x80808080,$t1 + and $s0,$t0 + and $s1,$t1 + mov $t0,$acc0 + mov $t1,$acc1 + shr \$7,$t0 + lea ($s0,$s0),$r20 + shr \$7,$t1 + lea ($s1,$s1),$r21 + sub $t0,$acc0 + sub $t1,$acc1 + and \$0xfefefefe,$r20 + and \$0xfefefefe,$r21 + and \$0x1b1b1b1b,$acc0 + and \$0x1b1b1b1b,$acc1 + mov $s0,$t0 + mov $s1,$t1 + xor $acc0,$r20 + xor $acc1,$r21 + + xor $r20,$s0 + xor $r21,$s1 + mov \$0x80808080,$t2 + rol \$24,$s0 + mov \$0x80808080,$t3 + rol \$24,$s1 + and $s2,$t2 + and $s3,$t3 + xor $r20,$s0 + xor $r21,$s1 + mov $t2,$acc0 + ror \$16,$t0 + mov $t3,$acc1 + ror \$16,$t1 + lea ($s2,$s2),$r20 + shr \$7,$t2 + xor $t0,$s0 + shr \$7,$t3 + xor $t1,$s1 + ror \$8,$t0 + lea ($s3,$s3),$r21 + ror \$8,$t1 + sub $t2,$acc0 + sub $t3,$acc1 + xor $t0,$s0 + xor $t1,$s1 + + and \$0xfefefefe,$r20 + and \$0xfefefefe,$r21 + and \$0x1b1b1b1b,$acc0 + and \$0x1b1b1b1b,$acc1 + mov $s2,$t2 + mov $s3,$t3 + xor $acc0,$r20 + xor $acc1,$r21 + + ror \$16,$t2 + xor $r20,$s2 + ror \$16,$t3 + xor $r21,$s3 + rol \$24,$s2 + mov 0($sbox),$acc0 # prefetch Te4 + rol \$24,$s3 + xor $r20,$s2 + mov 64($sbox),$acc1 + xor $r21,$s3 + mov 128($sbox),$r20 + xor $t2,$s2 + ror \$8,$t2 + xor $t3,$s3 + ror \$8,$t3 + xor $t2,$s2 + mov 192($sbox),$r21 + xor $t3,$s3 +___ +} + +$code.=<<___; +.type _x86_64_AES_encrypt_compact,\@abi-omnipotent +.align 16 +_x86_64_AES_encrypt_compact: + lea 128($sbox),$inp # size optimization + mov 0-128($inp),$acc1 # prefetch Te4 + mov 32-128($inp),$acc2 + mov 64-128($inp),$t0 + mov 96-128($inp),$t1 + mov 128-128($inp),$acc1 + mov 160-128($inp),$acc2 + mov 192-128($inp),$t0 + mov 224-128($inp),$t1 + jmp .Lenc_loop_compact +.align 16 +.Lenc_loop_compact: + xor 0($key),$s0 # xor with key + xor 4($key),$s1 + xor 8($key),$s2 + xor 12($key),$s3 + lea 16($key),$key +___ + &enccompactvert(); +$code.=<<___; + cmp 16(%rsp),$key + je .Lenc_compact_done +___ + &enctransform(); +$code.=<<___; + jmp .Lenc_loop_compact +.align 16 +.Lenc_compact_done: + xor 0($key),$s0 + xor 4($key),$s1 + xor 8($key),$s2 + xor 12($key),$s3 + .byte 0xf3,0xc3 # rep ret +.size _x86_64_AES_encrypt_compact,.-_x86_64_AES_encrypt_compact +___ + +# void asm_AES_encrypt (const void *inp,void *out,const AES_KEY *key); +$code.=<<___; +.align 16 +.globl asm_AES_encrypt +.type asm_AES_encrypt,\@function,3 +.hidden asm_AES_encrypt +asm_AES_encrypt: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + # allocate frame "above" key schedule + mov %rsp,%r10 + lea -63(%rdx),%rcx # %rdx is key argument + and \$-64,%rsp + sub %rsp,%rcx + neg %rcx + and \$0x3c0,%rcx + sub %rcx,%rsp + sub \$32,%rsp + + mov %rsi,16(%rsp) # save out + mov %r10,24(%rsp) # save real stack pointer +.Lenc_prologue: + + mov %rdx,$key + mov 240($key),$rnds # load rounds + + mov 0(%rdi),$s0 # load input vector + mov 4(%rdi),$s1 + mov 8(%rdi),$s2 + mov 12(%rdi),$s3 + + shl \$4,$rnds + lea ($key,$rnds),%rbp + mov $key,(%rsp) # key schedule + mov %rbp,8(%rsp) # end of key schedule + + # pick Te4 copy which can't "overlap" with stack frame or key schedule + lea .LAES_Te+2048(%rip),$sbox + lea 768(%rsp),%rbp + sub $sbox,%rbp + and \$0x300,%rbp + lea ($sbox,%rbp),$sbox + + call _x86_64_AES_encrypt_compact + + mov 16(%rsp),$out # restore out + mov 24(%rsp),%rsi # restore saved stack pointer + mov $s0,0($out) # write output vector + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lenc_epilogue: + ret +.size asm_AES_encrypt,.-asm_AES_encrypt +___ + +#------------------------------------------------------------------# + +sub decvert() +{ my $t3="%r8d"; # zaps $inp! + +$code.=<<___; + # favor 3-way issue Opteron pipeline... + movzb `&lo("$s0")`,$acc0 + movzb `&lo("$s1")`,$acc1 + movzb `&lo("$s2")`,$acc2 + mov 0($sbox,$acc0,8),$t0 + mov 0($sbox,$acc1,8),$t1 + mov 0($sbox,$acc2,8),$t2 + + movzb `&hi("$s3")`,$acc0 + movzb `&hi("$s0")`,$acc1 + movzb `&lo("$s3")`,$acc2 + xor 3($sbox,$acc0,8),$t0 + xor 3($sbox,$acc1,8),$t1 + mov 0($sbox,$acc2,8),$t3 + + movzb `&hi("$s1")`,$acc0 + shr \$16,$s0 + movzb `&hi("$s2")`,$acc2 + xor 3($sbox,$acc0,8),$t2 + shr \$16,$s3 + xor 3($sbox,$acc2,8),$t3 + + shr \$16,$s1 + lea 16($key),$key + shr \$16,$s2 + + movzb `&lo("$s2")`,$acc0 + movzb `&lo("$s3")`,$acc1 + movzb `&lo("$s0")`,$acc2 + xor 2($sbox,$acc0,8),$t0 + xor 2($sbox,$acc1,8),$t1 + xor 2($sbox,$acc2,8),$t2 + + movzb `&hi("$s1")`,$acc0 + movzb `&hi("$s2")`,$acc1 + movzb `&lo("$s1")`,$acc2 + xor 1($sbox,$acc0,8),$t0 + xor 1($sbox,$acc1,8),$t1 + xor 2($sbox,$acc2,8),$t3 + + movzb `&hi("$s3")`,$acc0 + mov 12($key),$s3 + movzb `&hi("$s0")`,$acc2 + xor 1($sbox,$acc0,8),$t2 + mov 0($key),$s0 + xor 1($sbox,$acc2,8),$t3 + + xor $t0,$s0 + mov 4($key),$s1 + mov 8($key),$s2 + xor $t2,$s2 + xor $t1,$s1 + xor $t3,$s3 +___ +} + +sub declastvert() +{ my $t3="%r8d"; # zaps $inp! + +$code.=<<___; + lea 2048($sbox),$sbox # size optimization + movzb `&lo("$s0")`,$acc0 + movzb `&lo("$s1")`,$acc1 + movzb `&lo("$s2")`,$acc2 + movzb ($sbox,$acc0,1),$t0 + movzb ($sbox,$acc1,1),$t1 + movzb ($sbox,$acc2,1),$t2 + + movzb `&lo("$s3")`,$acc0 + movzb `&hi("$s3")`,$acc1 + movzb `&hi("$s0")`,$acc2 + movzb ($sbox,$acc0,1),$t3 + movzb ($sbox,$acc1,1),$acc1 #$t0 + movzb ($sbox,$acc2,1),$acc2 #$t1 + + shl \$8,$acc1 + shl \$8,$acc2 + + xor $acc1,$t0 + xor $acc2,$t1 + shr \$16,$s3 + + movzb `&hi("$s1")`,$acc0 + movzb `&hi("$s2")`,$acc1 + shr \$16,$s0 + movzb ($sbox,$acc0,1),$acc0 #$t2 + movzb ($sbox,$acc1,1),$acc1 #$t3 + + shl \$8,$acc0 + shl \$8,$acc1 + shr \$16,$s1 + xor $acc0,$t2 + xor $acc1,$t3 + shr \$16,$s2 + + movzb `&lo("$s2")`,$acc0 + movzb `&lo("$s3")`,$acc1 + movzb `&lo("$s0")`,$acc2 + movzb ($sbox,$acc0,1),$acc0 #$t0 + movzb ($sbox,$acc1,1),$acc1 #$t1 + movzb ($sbox,$acc2,1),$acc2 #$t2 + + shl \$16,$acc0 + shl \$16,$acc1 + shl \$16,$acc2 + + xor $acc0,$t0 + xor $acc1,$t1 + xor $acc2,$t2 + + movzb `&lo("$s1")`,$acc0 + movzb `&hi("$s1")`,$acc1 + movzb `&hi("$s2")`,$acc2 + movzb ($sbox,$acc0,1),$acc0 #$t3 + movzb ($sbox,$acc1,1),$acc1 #$t0 + movzb ($sbox,$acc2,1),$acc2 #$t1 + + shl \$16,$acc0 + shl \$24,$acc1 + shl \$24,$acc2 + + xor $acc0,$t3 + xor $acc1,$t0 + xor $acc2,$t1 + + movzb `&hi("$s3")`,$acc0 + movzb `&hi("$s0")`,$acc1 + mov 16+12($key),$s3 + movzb ($sbox,$acc0,1),$acc0 #$t2 + movzb ($sbox,$acc1,1),$acc1 #$t3 + mov 16+0($key),$s0 + + shl \$24,$acc0 + shl \$24,$acc1 + + xor $acc0,$t2 + xor $acc1,$t3 + + mov 16+4($key),$s1 + mov 16+8($key),$s2 + lea -2048($sbox),$sbox + xor $t0,$s0 + xor $t1,$s1 + xor $t2,$s2 + xor $t3,$s3 +___ +} + +sub decstep() +{ my ($i,@s) = @_; + my $tmp0=$acc0; + my $tmp1=$acc1; + my $tmp2=$acc2; + my $out=($t0,$t1,$t2,$s[0])[$i]; + + $code.=" mov $s[0],$out\n" if ($i!=3); + $tmp1=$s[2] if ($i==3); + $code.=" mov $s[2],$tmp1\n" if ($i!=3); + $code.=" and \$0xFF,$out\n"; + + $code.=" mov 0($sbox,$out,8),$out\n"; + $code.=" shr \$16,$tmp1\n"; + $tmp2=$s[3] if ($i==3); + $code.=" mov $s[3],$tmp2\n" if ($i!=3); + + $tmp0=$s[1] if ($i==3); + $code.=" movzb ".&hi($s[1]).",$tmp0\n"; + $code.=" and \$0xFF,$tmp1\n"; + $code.=" shr \$24,$tmp2\n"; + + $code.=" xor 3($sbox,$tmp0,8),$out\n"; + $code.=" xor 2($sbox,$tmp1,8),$out\n"; + $code.=" xor 1($sbox,$tmp2,8),$out\n"; + + $code.=" mov $t2,$s[1]\n" if ($i==3); + $code.=" mov $t1,$s[2]\n" if ($i==3); + $code.=" mov $t0,$s[3]\n" if ($i==3); + $code.="\n"; +} + +sub declast() +{ my ($i,@s)=@_; + my $tmp0=$acc0; + my $tmp1=$acc1; + my $tmp2=$acc2; + my $out=($t0,$t1,$t2,$s[0])[$i]; + + $code.=" mov $s[0],$out\n" if ($i!=3); + $tmp1=$s[2] if ($i==3); + $code.=" mov $s[2],$tmp1\n" if ($i!=3); + $code.=" and \$0xFF,$out\n"; + + $code.=" movzb 2048($sbox,$out,1),$out\n"; + $code.=" shr \$16,$tmp1\n"; + $tmp2=$s[3] if ($i==3); + $code.=" mov $s[3],$tmp2\n" if ($i!=3); + + $tmp0=$s[1] if ($i==3); + $code.=" movzb ".&hi($s[1]).",$tmp0\n"; + $code.=" and \$0xFF,$tmp1\n"; + $code.=" shr \$24,$tmp2\n"; + + $code.=" movzb 2048($sbox,$tmp0,1),$tmp0\n"; + $code.=" movzb 2048($sbox,$tmp1,1),$tmp1\n"; + $code.=" movzb 2048($sbox,$tmp2,1),$tmp2\n"; + + $code.=" shl \$8,$tmp0\n"; + $code.=" shl \$16,$tmp1\n"; + $code.=" shl \$24,$tmp2\n"; + + $code.=" xor $tmp0,$out\n"; + $code.=" mov $t2,$s[1]\n" if ($i==3); + $code.=" xor $tmp1,$out\n"; + $code.=" mov $t1,$s[2]\n" if ($i==3); + $code.=" xor $tmp2,$out\n"; + $code.=" mov $t0,$s[3]\n" if ($i==3); + $code.="\n"; +} + +$code.=<<___; +.type _x86_64_AES_decrypt,\@abi-omnipotent +.align 16 +_x86_64_AES_decrypt: + xor 0($key),$s0 # xor with key + xor 4($key),$s1 + xor 8($key),$s2 + xor 12($key),$s3 + + mov 240($key),$rnds # load key->rounds + sub \$1,$rnds + jmp .Ldec_loop +.align 16 +.Ldec_loop: +___ + if ($verticalspin) { &decvert(); } + else { &decstep(0,$s0,$s3,$s2,$s1); + &decstep(1,$s1,$s0,$s3,$s2); + &decstep(2,$s2,$s1,$s0,$s3); + &decstep(3,$s3,$s2,$s1,$s0); + $code.=<<___; + lea 16($key),$key + xor 0($key),$s0 # xor with key + xor 4($key),$s1 + xor 8($key),$s2 + xor 12($key),$s3 +___ + } +$code.=<<___; + sub \$1,$rnds + jnz .Ldec_loop +___ + if ($verticalspin) { &declastvert(); } + else { &declast(0,$s0,$s3,$s2,$s1); + &declast(1,$s1,$s0,$s3,$s2); + &declast(2,$s2,$s1,$s0,$s3); + &declast(3,$s3,$s2,$s1,$s0); + $code.=<<___; + xor 16+0($key),$s0 # xor with key + xor 16+4($key),$s1 + xor 16+8($key),$s2 + xor 16+12($key),$s3 +___ + } +$code.=<<___; + .byte 0xf3,0xc3 # rep ret +.size _x86_64_AES_decrypt,.-_x86_64_AES_decrypt +___ + +sub deccompactvert() +{ my ($t3,$t4,$t5)=("%r8d","%r9d","%r13d"); + +$code.=<<___; + movzb `&lo("$s0")`,$t0 + movzb `&lo("$s1")`,$t1 + movzb `&lo("$s2")`,$t2 + movzb `&lo("$s3")`,$t3 + movzb `&hi("$s3")`,$acc0 + movzb `&hi("$s0")`,$acc1 + shr \$16,$s3 + movzb `&hi("$s1")`,$acc2 + movzb ($sbox,$t0,1),$t0 + movzb ($sbox,$t1,1),$t1 + movzb ($sbox,$t2,1),$t2 + movzb ($sbox,$t3,1),$t3 + + movzb ($sbox,$acc0,1),$t4 #$t0 + movzb `&hi("$s2")`,$acc0 + movzb ($sbox,$acc1,1),$t5 #$t1 + movzb ($sbox,$acc2,1),$acc2 #$t2 + movzb ($sbox,$acc0,1),$acc0 #$t3 + + shr \$16,$s2 + shl \$8,$t5 + shl \$8,$t4 + movzb `&lo("$s2")`,$acc1 + shr \$16,$s0 + xor $t4,$t0 + shr \$16,$s1 + movzb `&lo("$s3")`,$t4 + + shl \$8,$acc2 + xor $t5,$t1 + shl \$8,$acc0 + movzb `&lo("$s0")`,$t5 + movzb ($sbox,$acc1,1),$acc1 #$t0 + xor $acc2,$t2 + movzb `&lo("$s1")`,$acc2 + + shl \$16,$acc1 + xor $acc0,$t3 + movzb ($sbox,$t4,1),$t4 #$t1 + movzb `&hi("$s1")`,$acc0 + movzb ($sbox,$acc2,1),$acc2 #$t3 + xor $acc1,$t0 + movzb ($sbox,$t5,1),$t5 #$t2 + movzb `&hi("$s2")`,$acc1 + + shl \$16,$acc2 + shl \$16,$t4 + shl \$16,$t5 + xor $acc2,$t3 + movzb `&hi("$s3")`,$acc2 + xor $t4,$t1 + shr \$8,$s0 + xor $t5,$t2 + + movzb ($sbox,$acc0,1),$acc0 #$t0 + movzb ($sbox,$acc1,1),$s1 #$t1 + movzb ($sbox,$acc2,1),$s2 #$t2 + movzb ($sbox,$s0,1),$s3 #$t3 + + mov $t0,$s0 + shl \$24,$acc0 + shl \$24,$s1 + shl \$24,$s2 + xor $acc0,$s0 + shl \$24,$s3 + xor $t1,$s1 + xor $t2,$s2 + xor $t3,$s3 +___ +} + +# parallelized version! input is pair of 64-bit values: %rax=s1.s0 +# and %rcx=s3.s2, output is four 32-bit values in %eax=s0, %ebx=s1, +# %ecx=s2 and %edx=s3. +sub dectransform() +{ my ($tp10,$tp20,$tp40,$tp80,$acc0)=("%rax","%r8", "%r9", "%r10","%rbx"); + my ($tp18,$tp28,$tp48,$tp88,$acc8)=("%rcx","%r11","%r12","%r13","%rdx"); + my $prefetch = shift; + +$code.=<<___; + mov $mask80,$tp40 + mov $mask80,$tp48 + and $tp10,$tp40 + and $tp18,$tp48 + mov $tp40,$acc0 + mov $tp48,$acc8 + shr \$7,$tp40 + lea ($tp10,$tp10),$tp20 + shr \$7,$tp48 + lea ($tp18,$tp18),$tp28 + sub $tp40,$acc0 + sub $tp48,$acc8 + and $maskfe,$tp20 + and $maskfe,$tp28 + and $mask1b,$acc0 + and $mask1b,$acc8 + xor $acc0,$tp20 + xor $acc8,$tp28 + mov $mask80,$tp80 + mov $mask80,$tp88 + + and $tp20,$tp80 + and $tp28,$tp88 + mov $tp80,$acc0 + mov $tp88,$acc8 + shr \$7,$tp80 + lea ($tp20,$tp20),$tp40 + shr \$7,$tp88 + lea ($tp28,$tp28),$tp48 + sub $tp80,$acc0 + sub $tp88,$acc8 + and $maskfe,$tp40 + and $maskfe,$tp48 + and $mask1b,$acc0 + and $mask1b,$acc8 + xor $acc0,$tp40 + xor $acc8,$tp48 + mov $mask80,$tp80 + mov $mask80,$tp88 + + and $tp40,$tp80 + and $tp48,$tp88 + mov $tp80,$acc0 + mov $tp88,$acc8 + shr \$7,$tp80 + xor $tp10,$tp20 # tp2^=tp1 + shr \$7,$tp88 + xor $tp18,$tp28 # tp2^=tp1 + sub $tp80,$acc0 + sub $tp88,$acc8 + lea ($tp40,$tp40),$tp80 + lea ($tp48,$tp48),$tp88 + xor $tp10,$tp40 # tp4^=tp1 + xor $tp18,$tp48 # tp4^=tp1 + and $maskfe,$tp80 + and $maskfe,$tp88 + and $mask1b,$acc0 + and $mask1b,$acc8 + xor $acc0,$tp80 + xor $acc8,$tp88 + + xor $tp80,$tp10 # tp1^=tp8 + xor $tp88,$tp18 # tp1^=tp8 + xor $tp80,$tp20 # tp2^tp1^=tp8 + xor $tp88,$tp28 # tp2^tp1^=tp8 + mov $tp10,$acc0 + mov $tp18,$acc8 + xor $tp80,$tp40 # tp4^tp1^=tp8 + shr \$32,$acc0 + xor $tp88,$tp48 # tp4^tp1^=tp8 + shr \$32,$acc8 + xor $tp20,$tp80 # tp8^=tp8^tp2^tp1=tp2^tp1 + rol \$8,`&LO("$tp10")` # ROTATE(tp1^tp8,8) + xor $tp28,$tp88 # tp8^=tp8^tp2^tp1=tp2^tp1 + rol \$8,`&LO("$tp18")` # ROTATE(tp1^tp8,8) + xor $tp40,$tp80 # tp2^tp1^=tp8^tp4^tp1=tp8^tp4^tp2 + rol \$8,`&LO("$acc0")` # ROTATE(tp1^tp8,8) + xor $tp48,$tp88 # tp2^tp1^=tp8^tp4^tp1=tp8^tp4^tp2 + + rol \$8,`&LO("$acc8")` # ROTATE(tp1^tp8,8) + xor `&LO("$tp80")`,`&LO("$tp10")` + shr \$32,$tp80 + xor `&LO("$tp88")`,`&LO("$tp18")` + shr \$32,$tp88 + xor `&LO("$tp80")`,`&LO("$acc0")` + xor `&LO("$tp88")`,`&LO("$acc8")` + + mov $tp20,$tp80 + rol \$24,`&LO("$tp20")` # ROTATE(tp2^tp1^tp8,24) + mov $tp28,$tp88 + rol \$24,`&LO("$tp28")` # ROTATE(tp2^tp1^tp8,24) + shr \$32,$tp80 + xor `&LO("$tp20")`,`&LO("$tp10")` + shr \$32,$tp88 + xor `&LO("$tp28")`,`&LO("$tp18")` + rol \$24,`&LO("$tp80")` # ROTATE(tp2^tp1^tp8,24) + mov $tp40,$tp20 + rol \$24,`&LO("$tp88")` # ROTATE(tp2^tp1^tp8,24) + mov $tp48,$tp28 + shr \$32,$tp20 + xor `&LO("$tp80")`,`&LO("$acc0")` + shr \$32,$tp28 + xor `&LO("$tp88")`,`&LO("$acc8")` + + `"mov 0($sbox),$mask80" if ($prefetch)` + rol \$16,`&LO("$tp40")` # ROTATE(tp4^tp1^tp8,16) + `"mov 64($sbox),$maskfe" if ($prefetch)` + rol \$16,`&LO("$tp48")` # ROTATE(tp4^tp1^tp8,16) + `"mov 128($sbox),$mask1b" if ($prefetch)` + rol \$16,`&LO("$tp20")` # ROTATE(tp4^tp1^tp8,16) + `"mov 192($sbox),$tp80" if ($prefetch)` + xor `&LO("$tp40")`,`&LO("$tp10")` + rol \$16,`&LO("$tp28")` # ROTATE(tp4^tp1^tp8,16) + xor `&LO("$tp48")`,`&LO("$tp18")` + `"mov 256($sbox),$tp88" if ($prefetch)` + xor `&LO("$tp20")`,`&LO("$acc0")` + xor `&LO("$tp28")`,`&LO("$acc8")` +___ +} + +$code.=<<___; +.type _x86_64_AES_decrypt_compact,\@abi-omnipotent +.align 16 +_x86_64_AES_decrypt_compact: + lea 128($sbox),$inp # size optimization + mov 0-128($inp),$acc1 # prefetch Td4 + mov 32-128($inp),$acc2 + mov 64-128($inp),$t0 + mov 96-128($inp),$t1 + mov 128-128($inp),$acc1 + mov 160-128($inp),$acc2 + mov 192-128($inp),$t0 + mov 224-128($inp),$t1 + jmp .Ldec_loop_compact + +.align 16 +.Ldec_loop_compact: + xor 0($key),$s0 # xor with key + xor 4($key),$s1 + xor 8($key),$s2 + xor 12($key),$s3 + lea 16($key),$key +___ + &deccompactvert(); +$code.=<<___; + cmp 16(%rsp),$key + je .Ldec_compact_done + + mov 256+0($sbox),$mask80 + shl \$32,%rbx + shl \$32,%rdx + mov 256+8($sbox),$maskfe + or %rbx,%rax + or %rdx,%rcx + mov 256+16($sbox),$mask1b +___ + &dectransform(1); +$code.=<<___; + jmp .Ldec_loop_compact +.align 16 +.Ldec_compact_done: + xor 0($key),$s0 + xor 4($key),$s1 + xor 8($key),$s2 + xor 12($key),$s3 + .byte 0xf3,0xc3 # rep ret +.size _x86_64_AES_decrypt_compact,.-_x86_64_AES_decrypt_compact +___ + +# void asm_AES_decrypt (const void *inp,void *out,const AES_KEY *key); +$code.=<<___; +.align 16 +.globl asm_AES_decrypt +.type asm_AES_decrypt,\@function,3 +.hidden asm_AES_decrypt +asm_AES_decrypt: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + # allocate frame "above" key schedule + mov %rsp,%r10 + lea -63(%rdx),%rcx # %rdx is key argument + and \$-64,%rsp + sub %rsp,%rcx + neg %rcx + and \$0x3c0,%rcx + sub %rcx,%rsp + sub \$32,%rsp + + mov %rsi,16(%rsp) # save out + mov %r10,24(%rsp) # save real stack pointer +.Ldec_prologue: + + mov %rdx,$key + mov 240($key),$rnds # load rounds + + mov 0(%rdi),$s0 # load input vector + mov 4(%rdi),$s1 + mov 8(%rdi),$s2 + mov 12(%rdi),$s3 + + shl \$4,$rnds + lea ($key,$rnds),%rbp + mov $key,(%rsp) # key schedule + mov %rbp,8(%rsp) # end of key schedule + + # pick Td4 copy which can't "overlap" with stack frame or key schedule + lea .LAES_Td+2048(%rip),$sbox + lea 768(%rsp),%rbp + sub $sbox,%rbp + and \$0x300,%rbp + lea ($sbox,%rbp),$sbox + shr \$3,%rbp # recall "magic" constants! + add %rbp,$sbox + + call _x86_64_AES_decrypt_compact + + mov 16(%rsp),$out # restore out + mov 24(%rsp),%rsi # restore saved stack pointer + mov $s0,0($out) # write output vector + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Ldec_epilogue: + ret +.size asm_AES_decrypt,.-asm_AES_decrypt +___ +#------------------------------------------------------------------# + +sub enckey() +{ +$code.=<<___; + movz %dl,%esi # rk[i]>>0 + movzb -128(%rbp,%rsi),%ebx + movz %dh,%esi # rk[i]>>8 + shl \$24,%ebx + xor %ebx,%eax + + movzb -128(%rbp,%rsi),%ebx + shr \$16,%edx + movz %dl,%esi # rk[i]>>16 + xor %ebx,%eax + + movzb -128(%rbp,%rsi),%ebx + movz %dh,%esi # rk[i]>>24 + shl \$8,%ebx + xor %ebx,%eax + + movzb -128(%rbp,%rsi),%ebx + shl \$16,%ebx + xor %ebx,%eax + + xor 1024-128(%rbp,%rcx,4),%eax # rcon +___ +} + +# int asm_AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key) +$code.=<<___; +.align 16 +.globl asm_AES_set_encrypt_key +.type asm_AES_set_encrypt_key,\@function,3 +asm_AES_set_encrypt_key: + push %rbx + push %rbp + push %r12 # redundant, but allows to share + push %r13 # exception handler... + push %r14 + push %r15 + sub \$8,%rsp +.Lenc_key_prologue: + + call _x86_64_AES_set_encrypt_key + + mov 40(%rsp),%rbp + mov 48(%rsp),%rbx + add \$56,%rsp +.Lenc_key_epilogue: + ret +.size asm_AES_set_encrypt_key,.-asm_AES_set_encrypt_key + +.type _x86_64_AES_set_encrypt_key,\@abi-omnipotent +.align 16 +_x86_64_AES_set_encrypt_key: + mov %esi,%ecx # %ecx=bits + mov %rdi,%rsi # %rsi=userKey + mov %rdx,%rdi # %rdi=key + + test \$-1,%rsi + jz .Lbadpointer + test \$-1,%rdi + jz .Lbadpointer + + lea .LAES_Te(%rip),%rbp + lea 2048+128(%rbp),%rbp + + # prefetch Te4 + mov 0-128(%rbp),%eax + mov 32-128(%rbp),%ebx + mov 64-128(%rbp),%r8d + mov 96-128(%rbp),%edx + mov 128-128(%rbp),%eax + mov 160-128(%rbp),%ebx + mov 192-128(%rbp),%r8d + mov 224-128(%rbp),%edx + + cmp \$128,%ecx + je .L10rounds + cmp \$192,%ecx + je .L12rounds + cmp \$256,%ecx + je .L14rounds + mov \$-2,%rax # invalid number of bits + jmp .Lexit + +.L10rounds: + mov 0(%rsi),%rax # copy first 4 dwords + mov 8(%rsi),%rdx + mov %rax,0(%rdi) + mov %rdx,8(%rdi) + + shr \$32,%rdx + xor %ecx,%ecx + jmp .L10shortcut +.align 4 +.L10loop: + mov 0(%rdi),%eax # rk[0] + mov 12(%rdi),%edx # rk[3] +.L10shortcut: +___ + &enckey (); +$code.=<<___; + mov %eax,16(%rdi) # rk[4] + xor 4(%rdi),%eax + mov %eax,20(%rdi) # rk[5] + xor 8(%rdi),%eax + mov %eax,24(%rdi) # rk[6] + xor 12(%rdi),%eax + mov %eax,28(%rdi) # rk[7] + add \$1,%ecx + lea 16(%rdi),%rdi + cmp \$10,%ecx + jl .L10loop + + movl \$10,80(%rdi) # setup number of rounds + xor %rax,%rax + jmp .Lexit + +.L12rounds: + mov 0(%rsi),%rax # copy first 6 dwords + mov 8(%rsi),%rbx + mov 16(%rsi),%rdx + mov %rax,0(%rdi) + mov %rbx,8(%rdi) + mov %rdx,16(%rdi) + + shr \$32,%rdx + xor %ecx,%ecx + jmp .L12shortcut +.align 4 +.L12loop: + mov 0(%rdi),%eax # rk[0] + mov 20(%rdi),%edx # rk[5] +.L12shortcut: +___ + &enckey (); +$code.=<<___; + mov %eax,24(%rdi) # rk[6] + xor 4(%rdi),%eax + mov %eax,28(%rdi) # rk[7] + xor 8(%rdi),%eax + mov %eax,32(%rdi) # rk[8] + xor 12(%rdi),%eax + mov %eax,36(%rdi) # rk[9] + + cmp \$7,%ecx + je .L12break + add \$1,%ecx + + xor 16(%rdi),%eax + mov %eax,40(%rdi) # rk[10] + xor 20(%rdi),%eax + mov %eax,44(%rdi) # rk[11] + + lea 24(%rdi),%rdi + jmp .L12loop +.L12break: + movl \$12,72(%rdi) # setup number of rounds + xor %rax,%rax + jmp .Lexit + +.L14rounds: + mov 0(%rsi),%rax # copy first 8 dwords + mov 8(%rsi),%rbx + mov 16(%rsi),%rcx + mov 24(%rsi),%rdx + mov %rax,0(%rdi) + mov %rbx,8(%rdi) + mov %rcx,16(%rdi) + mov %rdx,24(%rdi) + + shr \$32,%rdx + xor %ecx,%ecx + jmp .L14shortcut +.align 4 +.L14loop: + mov 0(%rdi),%eax # rk[0] + mov 28(%rdi),%edx # rk[4] +.L14shortcut: +___ + &enckey (); +$code.=<<___; + mov %eax,32(%rdi) # rk[8] + xor 4(%rdi),%eax + mov %eax,36(%rdi) # rk[9] + xor 8(%rdi),%eax + mov %eax,40(%rdi) # rk[10] + xor 12(%rdi),%eax + mov %eax,44(%rdi) # rk[11] + + cmp \$6,%ecx + je .L14break + add \$1,%ecx + + mov %eax,%edx + mov 16(%rdi),%eax # rk[4] + movz %dl,%esi # rk[11]>>0 + movzb -128(%rbp,%rsi),%ebx + movz %dh,%esi # rk[11]>>8 + xor %ebx,%eax + + movzb -128(%rbp,%rsi),%ebx + shr \$16,%edx + shl \$8,%ebx + movz %dl,%esi # rk[11]>>16 + xor %ebx,%eax + + movzb -128(%rbp,%rsi),%ebx + movz %dh,%esi # rk[11]>>24 + shl \$16,%ebx + xor %ebx,%eax + + movzb -128(%rbp,%rsi),%ebx + shl \$24,%ebx + xor %ebx,%eax + + mov %eax,48(%rdi) # rk[12] + xor 20(%rdi),%eax + mov %eax,52(%rdi) # rk[13] + xor 24(%rdi),%eax + mov %eax,56(%rdi) # rk[14] + xor 28(%rdi),%eax + mov %eax,60(%rdi) # rk[15] + + lea 32(%rdi),%rdi + jmp .L14loop +.L14break: + movl \$14,48(%rdi) # setup number of rounds + xor %rax,%rax + jmp .Lexit + +.Lbadpointer: + mov \$-1,%rax +.Lexit: + .byte 0xf3,0xc3 # rep ret +.size _x86_64_AES_set_encrypt_key,.-_x86_64_AES_set_encrypt_key +___ + +sub deckey_ref() +{ my ($i,$ptr,$te,$td) = @_; + my ($tp1,$tp2,$tp4,$tp8,$acc)=("%eax","%ebx","%edi","%edx","%r8d"); +$code.=<<___; + mov $i($ptr),$tp1 + mov $tp1,$acc + and \$0x80808080,$acc + mov $acc,$tp4 + shr \$7,$tp4 + lea 0($tp1,$tp1),$tp2 + sub $tp4,$acc + and \$0xfefefefe,$tp2 + and \$0x1b1b1b1b,$acc + xor $tp2,$acc + mov $acc,$tp2 + + and \$0x80808080,$acc + mov $acc,$tp8 + shr \$7,$tp8 + lea 0($tp2,$tp2),$tp4 + sub $tp8,$acc + and \$0xfefefefe,$tp4 + and \$0x1b1b1b1b,$acc + xor $tp1,$tp2 # tp2^tp1 + xor $tp4,$acc + mov $acc,$tp4 + + and \$0x80808080,$acc + mov $acc,$tp8 + shr \$7,$tp8 + sub $tp8,$acc + lea 0($tp4,$tp4),$tp8 + xor $tp1,$tp4 # tp4^tp1 + and \$0xfefefefe,$tp8 + and \$0x1b1b1b1b,$acc + xor $acc,$tp8 + + xor $tp8,$tp1 # tp1^tp8 + rol \$8,$tp1 # ROTATE(tp1^tp8,8) + xor $tp8,$tp2 # tp2^tp1^tp8 + xor $tp8,$tp4 # tp4^tp1^tp8 + xor $tp2,$tp8 + xor $tp4,$tp8 # tp8^(tp8^tp4^tp1)^(tp8^tp2^tp1)=tp8^tp4^tp2 + + xor $tp8,$tp1 + rol \$24,$tp2 # ROTATE(tp2^tp1^tp8,24) + xor $tp2,$tp1 + rol \$16,$tp4 # ROTATE(tp4^tp1^tp8,16) + xor $tp4,$tp1 + + mov $tp1,$i($ptr) +___ +} + +# int asm_AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key) +$code.=<<___; +.align 16 +.globl asm_AES_set_decrypt_key +.type asm_AES_set_decrypt_key,\@function,3 +asm_AES_set_decrypt_key: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + push %rdx # save key schedule +.Ldec_key_prologue: + + call _x86_64_AES_set_encrypt_key + mov (%rsp),%r8 # restore key schedule + cmp \$0,%eax + jne .Labort + + mov 240(%r8),%r14d # pull number of rounds + xor %rdi,%rdi + lea (%rdi,%r14d,4),%rcx + mov %r8,%rsi + lea (%r8,%rcx,4),%rdi # pointer to last chunk +.align 4 +.Linvert: + mov 0(%rsi),%rax + mov 8(%rsi),%rbx + mov 0(%rdi),%rcx + mov 8(%rdi),%rdx + mov %rax,0(%rdi) + mov %rbx,8(%rdi) + mov %rcx,0(%rsi) + mov %rdx,8(%rsi) + lea 16(%rsi),%rsi + lea -16(%rdi),%rdi + cmp %rsi,%rdi + jne .Linvert + + lea .LAES_Te+2048+1024(%rip),%rax # rcon + + mov 40(%rax),$mask80 + mov 48(%rax),$maskfe + mov 56(%rax),$mask1b + + mov %r8,$key + sub \$1,%r14d +.align 4 +.Lpermute: + lea 16($key),$key + mov 0($key),%rax + mov 8($key),%rcx +___ + &dectransform (); +$code.=<<___; + mov %eax,0($key) + mov %ebx,4($key) + mov %ecx,8($key) + mov %edx,12($key) + sub \$1,%r14d + jnz .Lpermute + + xor %rax,%rax +.Labort: + mov 8(%rsp),%r15 + mov 16(%rsp),%r14 + mov 24(%rsp),%r13 + mov 32(%rsp),%r12 + mov 40(%rsp),%rbp + mov 48(%rsp),%rbx + add \$56,%rsp +.Ldec_key_epilogue: + ret +.size asm_AES_set_decrypt_key,.-asm_AES_set_decrypt_key +___ + +# void asm_AES_cbc_encrypt (const void char *inp, unsigned char *out, +# size_t length, const AES_KEY *key, +# unsigned char *ivp,const int enc); +{ +# stack frame layout +# -8(%rsp) return address +my $keyp="0(%rsp)"; # one to pass as $key +my $keyend="8(%rsp)"; # &(keyp->rd_key[4*keyp->rounds]) +my $_rsp="16(%rsp)"; # saved %rsp +my $_inp="24(%rsp)"; # copy of 1st parameter, inp +my $_out="32(%rsp)"; # copy of 2nd parameter, out +my $_len="40(%rsp)"; # copy of 3rd parameter, length +my $_key="48(%rsp)"; # copy of 4th parameter, key +my $_ivp="56(%rsp)"; # copy of 5th parameter, ivp +my $ivec="64(%rsp)"; # ivec[16] +my $aes_key="80(%rsp)"; # copy of aes_key +my $mark="80+240(%rsp)"; # copy of aes_key->rounds + +$code.=<<___; +.align 16 +.globl asm_AES_cbc_encrypt +.type asm_AES_cbc_encrypt,\@function,6 +.extern OPENSSL_ia32cap_P +.hidden asm_AES_cbc_encrypt +asm_AES_cbc_encrypt: + cmp \$0,%rdx # check length + je .Lcbc_epilogue + pushfq + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +.Lcbc_prologue: + + cld + mov %r9d,%r9d # clear upper half of enc + + lea .LAES_Te(%rip),$sbox + cmp \$0,%r9 + jne .Lcbc_picked_te + lea .LAES_Td(%rip),$sbox +.Lcbc_picked_te: + + mov OPENSSL_ia32cap_P(%rip),%r10d + cmp \$$speed_limit,%rdx + jb .Lcbc_slow_prologue + test \$15,%rdx + jnz .Lcbc_slow_prologue + bt \$28,%r10d + jc .Lcbc_slow_prologue + + # allocate aligned stack frame... + lea -88-248(%rsp),$key + and \$-64,$key + + # ... and make sure it doesn't alias with AES_T[ed] modulo 4096 + mov $sbox,%r10 + lea 2304($sbox),%r11 + mov $key,%r12 + and \$0xFFF,%r10 # s = $sbox&0xfff + and \$0xFFF,%r11 # e = ($sbox+2048)&0xfff + and \$0xFFF,%r12 # p = %rsp&0xfff + + cmp %r11,%r12 # if (p=>e) %rsp =- (p-e); + jb .Lcbc_te_break_out + sub %r11,%r12 + sub %r12,$key + jmp .Lcbc_te_ok +.Lcbc_te_break_out: # else %rsp -= (p-s)&0xfff + framesz + sub %r10,%r12 + and \$0xFFF,%r12 + add \$320,%r12 + sub %r12,$key +.align 4 +.Lcbc_te_ok: + + xchg %rsp,$key + #add \$8,%rsp # reserve for return address! + mov $key,$_rsp # save %rsp +.Lcbc_fast_body: + mov %rdi,$_inp # save copy of inp + mov %rsi,$_out # save copy of out + mov %rdx,$_len # save copy of len + mov %rcx,$_key # save copy of key + mov %r8,$_ivp # save copy of ivp + movl \$0,$mark # copy of aes_key->rounds = 0; + mov %r8,%rbp # rearrange input arguments + mov %r9,%rbx + mov %rsi,$out + mov %rdi,$inp + mov %rcx,$key + + mov 240($key),%eax # key->rounds + # do we copy key schedule to stack? + mov $key,%r10 + sub $sbox,%r10 + and \$0xfff,%r10 + cmp \$2304,%r10 + jb .Lcbc_do_ecopy + cmp \$4096-248,%r10 + jb .Lcbc_skip_ecopy +.align 4 +.Lcbc_do_ecopy: + mov $key,%rsi + lea $aes_key,%rdi + lea $aes_key,$key + mov \$240/8,%ecx + .long 0x90A548F3 # rep movsq + mov %eax,(%rdi) # copy aes_key->rounds +.Lcbc_skip_ecopy: + mov $key,$keyp # save key pointer + + mov \$18,%ecx +.align 4 +.Lcbc_prefetch_te: + mov 0($sbox),%r10 + mov 32($sbox),%r11 + mov 64($sbox),%r12 + mov 96($sbox),%r13 + lea 128($sbox),$sbox + sub \$1,%ecx + jnz .Lcbc_prefetch_te + lea -2304($sbox),$sbox + + cmp \$0,%rbx + je .LFAST_DECRYPT + +#----------------------------- ENCRYPT -----------------------------# + mov 0(%rbp),$s0 # load iv + mov 4(%rbp),$s1 + mov 8(%rbp),$s2 + mov 12(%rbp),$s3 + +.align 4 +.Lcbc_fast_enc_loop: + xor 0($inp),$s0 + xor 4($inp),$s1 + xor 8($inp),$s2 + xor 12($inp),$s3 + mov $keyp,$key # restore key + mov $inp,$_inp # if ($verticalspin) save inp + + call _x86_64_AES_encrypt + + mov $_inp,$inp # if ($verticalspin) restore inp + mov $_len,%r10 + mov $s0,0($out) + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + lea 16($inp),$inp + lea 16($out),$out + sub \$16,%r10 + test \$-16,%r10 + mov %r10,$_len + jnz .Lcbc_fast_enc_loop + mov $_ivp,%rbp # restore ivp + mov $s0,0(%rbp) # save ivec + mov $s1,4(%rbp) + mov $s2,8(%rbp) + mov $s3,12(%rbp) + + jmp .Lcbc_fast_cleanup + +#----------------------------- DECRYPT -----------------------------# +.align 16 +.LFAST_DECRYPT: + cmp $inp,$out + je .Lcbc_fast_dec_in_place + + mov %rbp,$ivec +.align 4 +.Lcbc_fast_dec_loop: + mov 0($inp),$s0 # read input + mov 4($inp),$s1 + mov 8($inp),$s2 + mov 12($inp),$s3 + mov $keyp,$key # restore key + mov $inp,$_inp # if ($verticalspin) save inp + + call _x86_64_AES_decrypt + + mov $ivec,%rbp # load ivp + mov $_inp,$inp # if ($verticalspin) restore inp + mov $_len,%r10 # load len + xor 0(%rbp),$s0 # xor iv + xor 4(%rbp),$s1 + xor 8(%rbp),$s2 + xor 12(%rbp),$s3 + mov $inp,%rbp # current input, next iv + + sub \$16,%r10 + mov %r10,$_len # update len + mov %rbp,$ivec # update ivp + + mov $s0,0($out) # write output + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + lea 16($inp),$inp + lea 16($out),$out + jnz .Lcbc_fast_dec_loop + mov $_ivp,%r12 # load user ivp + mov 0(%rbp),%r10 # load iv + mov 8(%rbp),%r11 + mov %r10,0(%r12) # copy back to user + mov %r11,8(%r12) + jmp .Lcbc_fast_cleanup + +.align 16 +.Lcbc_fast_dec_in_place: + mov 0(%rbp),%r10 # copy iv to stack + mov 8(%rbp),%r11 + mov %r10,0+$ivec + mov %r11,8+$ivec +.align 4 +.Lcbc_fast_dec_in_place_loop: + mov 0($inp),$s0 # load input + mov 4($inp),$s1 + mov 8($inp),$s2 + mov 12($inp),$s3 + mov $keyp,$key # restore key + mov $inp,$_inp # if ($verticalspin) save inp + + call _x86_64_AES_decrypt + + mov $_inp,$inp # if ($verticalspin) restore inp + mov $_len,%r10 + xor 0+$ivec,$s0 + xor 4+$ivec,$s1 + xor 8+$ivec,$s2 + xor 12+$ivec,$s3 + + mov 0($inp),%r11 # load input + mov 8($inp),%r12 + sub \$16,%r10 + jz .Lcbc_fast_dec_in_place_done + + mov %r11,0+$ivec # copy input to iv + mov %r12,8+$ivec + + mov $s0,0($out) # save output [zaps input] + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + lea 16($inp),$inp + lea 16($out),$out + mov %r10,$_len + jmp .Lcbc_fast_dec_in_place_loop +.Lcbc_fast_dec_in_place_done: + mov $_ivp,%rdi + mov %r11,0(%rdi) # copy iv back to user + mov %r12,8(%rdi) + + mov $s0,0($out) # save output [zaps input] + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + +.align 4 +.Lcbc_fast_cleanup: + cmpl \$0,$mark # was the key schedule copied? + lea $aes_key,%rdi + je .Lcbc_exit + mov \$240/8,%ecx + xor %rax,%rax + .long 0x90AB48F3 # rep stosq + + jmp .Lcbc_exit + +#--------------------------- SLOW ROUTINE ---------------------------# +.align 16 +.Lcbc_slow_prologue: + # allocate aligned stack frame... + lea -88(%rsp),%rbp + and \$-64,%rbp + # ... just "above" key schedule + lea -88-63(%rcx),%r10 + sub %rbp,%r10 + neg %r10 + and \$0x3c0,%r10 + sub %r10,%rbp + + xchg %rsp,%rbp + #add \$8,%rsp # reserve for return address! + mov %rbp,$_rsp # save %rsp +.Lcbc_slow_body: + #mov %rdi,$_inp # save copy of inp + #mov %rsi,$_out # save copy of out + #mov %rdx,$_len # save copy of len + #mov %rcx,$_key # save copy of key + mov %r8,$_ivp # save copy of ivp + mov %r8,%rbp # rearrange input arguments + mov %r9,%rbx + mov %rsi,$out + mov %rdi,$inp + mov %rcx,$key + mov %rdx,%r10 + + mov 240($key),%eax + mov $key,$keyp # save key pointer + shl \$4,%eax + lea ($key,%rax),%rax + mov %rax,$keyend + + # pick Te4 copy which can't "overlap" with stack frame or key scdedule + lea 2048($sbox),$sbox + lea 768-8(%rsp),%rax + sub $sbox,%rax + and \$0x300,%rax + lea ($sbox,%rax),$sbox + + cmp \$0,%rbx + je .LSLOW_DECRYPT + +#--------------------------- SLOW ENCRYPT ---------------------------# + test \$-16,%r10 # check upon length + mov 0(%rbp),$s0 # load iv + mov 4(%rbp),$s1 + mov 8(%rbp),$s2 + mov 12(%rbp),$s3 + jz .Lcbc_slow_enc_tail # short input... + +.align 4 +.Lcbc_slow_enc_loop: + xor 0($inp),$s0 + xor 4($inp),$s1 + xor 8($inp),$s2 + xor 12($inp),$s3 + mov $keyp,$key # restore key + mov $inp,$_inp # save inp + mov $out,$_out # save out + mov %r10,$_len # save len + + call _x86_64_AES_encrypt_compact + + mov $_inp,$inp # restore inp + mov $_out,$out # restore out + mov $_len,%r10 # restore len + mov $s0,0($out) + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + lea 16($inp),$inp + lea 16($out),$out + sub \$16,%r10 + test \$-16,%r10 + jnz .Lcbc_slow_enc_loop + test \$15,%r10 + jnz .Lcbc_slow_enc_tail + mov $_ivp,%rbp # restore ivp + mov $s0,0(%rbp) # save ivec + mov $s1,4(%rbp) + mov $s2,8(%rbp) + mov $s3,12(%rbp) + + jmp .Lcbc_exit + +.align 4 +.Lcbc_slow_enc_tail: + mov %rax,%r11 + mov %rcx,%r12 + mov %r10,%rcx + mov $inp,%rsi + mov $out,%rdi + .long 0x9066A4F3 # rep movsb + mov \$16,%rcx # zero tail + sub %r10,%rcx + xor %rax,%rax + .long 0x9066AAF3 # rep stosb + mov $out,$inp # this is not a mistake! + mov \$16,%r10 # len=16 + mov %r11,%rax + mov %r12,%rcx + jmp .Lcbc_slow_enc_loop # one more spin... +#--------------------------- SLOW DECRYPT ---------------------------# +.align 16 +.LSLOW_DECRYPT: + shr \$3,%rax + add %rax,$sbox # recall "magic" constants! + + mov 0(%rbp),%r11 # copy iv to stack + mov 8(%rbp),%r12 + mov %r11,0+$ivec + mov %r12,8+$ivec + +.align 4 +.Lcbc_slow_dec_loop: + mov 0($inp),$s0 # load input + mov 4($inp),$s1 + mov 8($inp),$s2 + mov 12($inp),$s3 + mov $keyp,$key # restore key + mov $inp,$_inp # save inp + mov $out,$_out # save out + mov %r10,$_len # save len + + call _x86_64_AES_decrypt_compact + + mov $_inp,$inp # restore inp + mov $_out,$out # restore out + mov $_len,%r10 + xor 0+$ivec,$s0 + xor 4+$ivec,$s1 + xor 8+$ivec,$s2 + xor 12+$ivec,$s3 + + mov 0($inp),%r11 # load input + mov 8($inp),%r12 + sub \$16,%r10 + jc .Lcbc_slow_dec_partial + jz .Lcbc_slow_dec_done + + mov %r11,0+$ivec # copy input to iv + mov %r12,8+$ivec + + mov $s0,0($out) # save output [can zap input] + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + lea 16($inp),$inp + lea 16($out),$out + jmp .Lcbc_slow_dec_loop +.Lcbc_slow_dec_done: + mov $_ivp,%rdi + mov %r11,0(%rdi) # copy iv back to user + mov %r12,8(%rdi) + + mov $s0,0($out) # save output [can zap input] + mov $s1,4($out) + mov $s2,8($out) + mov $s3,12($out) + + jmp .Lcbc_exit + +.align 4 +.Lcbc_slow_dec_partial: + mov $_ivp,%rdi + mov %r11,0(%rdi) # copy iv back to user + mov %r12,8(%rdi) + + mov $s0,0+$ivec # save output to stack + mov $s1,4+$ivec + mov $s2,8+$ivec + mov $s3,12+$ivec + + mov $out,%rdi + lea $ivec,%rsi + lea 16(%r10),%rcx + .long 0x9066A4F3 # rep movsb + jmp .Lcbc_exit + +.align 16 +.Lcbc_exit: + mov $_rsp,%rsi + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lcbc_popfq: + popfq +.Lcbc_epilogue: + ret +.size asm_AES_cbc_encrypt,.-asm_AES_cbc_encrypt +___ +} + +$code.=<<___; +.align 64 +.LAES_Te: +___ + &_data_word(0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6); + &_data_word(0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591); + &_data_word(0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56); + &_data_word(0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec); + &_data_word(0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa); + &_data_word(0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb); + &_data_word(0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45); + &_data_word(0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b); + &_data_word(0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c); + &_data_word(0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83); + &_data_word(0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9); + &_data_word(0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a); + &_data_word(0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d); + &_data_word(0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f); + &_data_word(0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df); + &_data_word(0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea); + &_data_word(0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34); + &_data_word(0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b); + &_data_word(0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d); + &_data_word(0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413); + &_data_word(0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1); + &_data_word(0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6); + &_data_word(0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972); + &_data_word(0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85); + &_data_word(0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed); + &_data_word(0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511); + &_data_word(0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe); + &_data_word(0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b); + &_data_word(0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05); + &_data_word(0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1); + &_data_word(0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142); + &_data_word(0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf); + &_data_word(0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3); + &_data_word(0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e); + &_data_word(0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a); + &_data_word(0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6); + &_data_word(0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3); + &_data_word(0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b); + &_data_word(0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428); + &_data_word(0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad); + &_data_word(0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14); + &_data_word(0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8); + &_data_word(0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4); + &_data_word(0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2); + &_data_word(0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda); + &_data_word(0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949); + &_data_word(0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf); + &_data_word(0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810); + &_data_word(0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c); + &_data_word(0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697); + &_data_word(0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e); + &_data_word(0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f); + &_data_word(0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc); + &_data_word(0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c); + &_data_word(0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969); + &_data_word(0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27); + &_data_word(0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122); + &_data_word(0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433); + &_data_word(0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9); + &_data_word(0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5); + &_data_word(0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a); + &_data_word(0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0); + &_data_word(0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e); + &_data_word(0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c); + +#Te4 # four copies of Te4 to choose from to avoid L1 aliasing + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); + + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); + + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); + + &data_byte(0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5); + &data_byte(0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76); + &data_byte(0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0); + &data_byte(0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0); + &data_byte(0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc); + &data_byte(0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15); + &data_byte(0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a); + &data_byte(0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75); + &data_byte(0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0); + &data_byte(0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84); + &data_byte(0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b); + &data_byte(0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf); + &data_byte(0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85); + &data_byte(0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8); + &data_byte(0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5); + &data_byte(0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2); + &data_byte(0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17); + &data_byte(0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73); + &data_byte(0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88); + &data_byte(0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb); + &data_byte(0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c); + &data_byte(0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79); + &data_byte(0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9); + &data_byte(0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08); + &data_byte(0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6); + &data_byte(0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a); + &data_byte(0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e); + &data_byte(0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e); + &data_byte(0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94); + &data_byte(0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf); + &data_byte(0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68); + &data_byte(0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16); +#rcon: +$code.=<<___; + .long 0x00000001, 0x00000002, 0x00000004, 0x00000008 + .long 0x00000010, 0x00000020, 0x00000040, 0x00000080 + .long 0x0000001b, 0x00000036, 0x80808080, 0x80808080 + .long 0xfefefefe, 0xfefefefe, 0x1b1b1b1b, 0x1b1b1b1b +___ +$code.=<<___; +.align 64 +.LAES_Td: +___ + &_data_word(0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a); + &_data_word(0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b); + &_data_word(0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5); + &_data_word(0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5); + &_data_word(0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d); + &_data_word(0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b); + &_data_word(0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295); + &_data_word(0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e); + &_data_word(0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927); + &_data_word(0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d); + &_data_word(0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362); + &_data_word(0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9); + &_data_word(0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52); + &_data_word(0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566); + &_data_word(0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3); + &_data_word(0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed); + &_data_word(0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e); + &_data_word(0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4); + &_data_word(0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4); + &_data_word(0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd); + &_data_word(0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d); + &_data_word(0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060); + &_data_word(0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967); + &_data_word(0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879); + &_data_word(0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000); + &_data_word(0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c); + &_data_word(0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36); + &_data_word(0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624); + &_data_word(0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b); + &_data_word(0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c); + &_data_word(0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12); + &_data_word(0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14); + &_data_word(0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3); + &_data_word(0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b); + &_data_word(0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8); + &_data_word(0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684); + &_data_word(0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7); + &_data_word(0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177); + &_data_word(0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947); + &_data_word(0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322); + &_data_word(0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498); + &_data_word(0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f); + &_data_word(0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54); + &_data_word(0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382); + &_data_word(0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf); + &_data_word(0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb); + &_data_word(0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83); + &_data_word(0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef); + &_data_word(0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029); + &_data_word(0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235); + &_data_word(0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733); + &_data_word(0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117); + &_data_word(0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4); + &_data_word(0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546); + &_data_word(0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb); + &_data_word(0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d); + &_data_word(0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb); + &_data_word(0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a); + &_data_word(0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773); + &_data_word(0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478); + &_data_word(0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2); + &_data_word(0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff); + &_data_word(0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664); + &_data_word(0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0); + +#Td4: # four copies of Td4 to choose from to avoid L1 aliasing + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); +$code.=<<___; + .long 0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe + .long 0x1b1b1b1b, 0x1b1b1b1b, 0, 0 +___ + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); +$code.=<<___; + .long 0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe + .long 0x1b1b1b1b, 0x1b1b1b1b, 0, 0 +___ + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); +$code.=<<___; + .long 0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe + .long 0x1b1b1b1b, 0x1b1b1b1b, 0, 0 +___ + &data_byte(0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38); + &data_byte(0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb); + &data_byte(0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87); + &data_byte(0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb); + &data_byte(0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d); + &data_byte(0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e); + &data_byte(0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2); + &data_byte(0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25); + &data_byte(0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16); + &data_byte(0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92); + &data_byte(0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda); + &data_byte(0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84); + &data_byte(0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a); + &data_byte(0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06); + &data_byte(0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02); + &data_byte(0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b); + &data_byte(0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea); + &data_byte(0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73); + &data_byte(0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85); + &data_byte(0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e); + &data_byte(0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89); + &data_byte(0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b); + &data_byte(0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20); + &data_byte(0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4); + &data_byte(0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31); + &data_byte(0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f); + &data_byte(0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d); + &data_byte(0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef); + &data_byte(0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0); + &data_byte(0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61); + &data_byte(0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26); + &data_byte(0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d); +$code.=<<___; + .long 0x80808080, 0x80808080, 0xfefefefe, 0xfefefefe + .long 0x1b1b1b1b, 0x1b1b1b1b, 0, 0 +.asciz "AES for x86_64, CRYPTOGAMS by " +.align 64 +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type block_se_handler,\@abi-omnipotent +.align 16 +block_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lin_block_prologue + + mov 24(%rax),%rax # pull saved real stack pointer + lea 48(%rax),%rax # adjust... + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov -48(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lin_block_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + jmp .Lcommon_seh_exit +.size block_se_handler,.-block_se_handler + +.type key_se_handler,\@abi-omnipotent +.align 16 +key_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lin_key_prologue + + lea 56(%rax),%rax + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov -48(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lin_key_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + jmp .Lcommon_seh_exit +.size key_se_handler,.-key_se_handler + +.type cbc_se_handler,\@abi-omnipotent +.align 16 +cbc_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + lea .Lcbc_prologue(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lcbc_prologue + jb .Lin_cbc_prologue + + lea .Lcbc_fast_body(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lcbc_fast_body + jb .Lin_cbc_frame_setup + + lea .Lcbc_slow_prologue(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lcbc_slow_prologue + jb .Lin_cbc_body + + lea .Lcbc_slow_body(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lcbc_slow_body + jb .Lin_cbc_frame_setup + +.Lin_cbc_body: + mov 152($context),%rax # pull context->Rsp + + lea .Lcbc_epilogue(%rip),%r10 + cmp %r10,%rbx # context->Rip>=.Lcbc_epilogue + jae .Lin_cbc_prologue + + lea 8(%rax),%rax + + lea .Lcbc_popfq(%rip),%r10 + cmp %r10,%rbx # context->Rip>=.Lcbc_popfq + jae .Lin_cbc_prologue + + mov `16-8`(%rax),%rax # biased $_rsp + lea 56(%rax),%rax + +.Lin_cbc_frame_setup: + mov -16(%rax),%rbx + mov -24(%rax),%rbp + mov -32(%rax),%r12 + mov -40(%rax),%r13 + mov -48(%rax),%r14 + mov -56(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lin_cbc_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + +.Lcommon_seh_exit: + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$`1232/8`,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size cbc_se_handler,.-cbc_se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_asm_AES_encrypt + .rva .LSEH_end_asm_AES_encrypt + .rva .LSEH_info_asm_AES_encrypt + + .rva .LSEH_begin_asm_AES_decrypt + .rva .LSEH_end_asm_AES_decrypt + .rva .LSEH_info_asm_AES_decrypt + + .rva .LSEH_begin_asm_AES_set_encrypt_key + .rva .LSEH_end_asm_AES_set_encrypt_key + .rva .LSEH_info_asm_AES_set_encrypt_key + + .rva .LSEH_begin_asm_AES_set_decrypt_key + .rva .LSEH_end_asm_AES_set_decrypt_key + .rva .LSEH_info_asm_AES_set_decrypt_key + + .rva .LSEH_begin_asm_AES_cbc_encrypt + .rva .LSEH_end_asm_AES_cbc_encrypt + .rva .LSEH_info_asm_AES_cbc_encrypt + +.section .xdata +.align 8 +.LSEH_info_asm_AES_encrypt: + .byte 9,0,0,0 + .rva block_se_handler + .rva .Lenc_prologue,.Lenc_epilogue # HandlerData[] +.LSEH_info_asm_AES_decrypt: + .byte 9,0,0,0 + .rva block_se_handler + .rva .Ldec_prologue,.Ldec_epilogue # HandlerData[] +.LSEH_info_asm_AES_set_encrypt_key: + .byte 9,0,0,0 + .rva key_se_handler + .rva .Lenc_key_prologue,.Lenc_key_epilogue # HandlerData[] +.LSEH_info_asm_AES_set_decrypt_key: + .byte 9,0,0,0 + .rva key_se_handler + .rva .Ldec_key_prologue,.Ldec_key_epilogue # HandlerData[] +.LSEH_info_asm_AES_cbc_encrypt: + .byte 9,0,0,0 + .rva cbc_se_handler +___ +} + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/aesni-x86.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/aesni-x86.pl new file mode 100644 index 00000000..f67df8cf --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/aesni-x86.pl @@ -0,0 +1,2525 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# This module implements support for Intel AES-NI extension. In +# OpenSSL context it's used with Intel engine, but can also be used as +# drop-in replacement for crypto/aes/asm/aes-586.pl [see below for +# details]. +# +# Performance. +# +# To start with see corresponding paragraph in aesni-x86_64.pl... +# Instead of filling table similar to one found there I've chosen to +# summarize *comparison* results for raw ECB, CTR and CBC benchmarks. +# The simplified table below represents 32-bit performance relative +# to 64-bit one in every given point. Ratios vary for different +# encryption modes, therefore interval values. +# +# 16-byte 64-byte 256-byte 1-KB 8-KB +# 53-67% 67-84% 91-94% 95-98% 97-99.5% +# +# Lower ratios for smaller block sizes are perfectly understandable, +# because function call overhead is higher in 32-bit mode. Largest +# 8-KB block performance is virtually same: 32-bit code is less than +# 1% slower for ECB, CBC and CCM, and ~3% slower otherwise. + +# January 2011 +# +# See aesni-x86_64.pl for details. Unlike x86_64 version this module +# interleaves at most 6 aes[enc|dec] instructions, because there are +# not enough registers for 8x interleave [which should be optimal for +# Sandy Bridge]. Actually, performance results for 6x interleave +# factor presented in aesni-x86_64.pl (except for CTR) are for this +# module. + +# April 2011 +# +# Add aesni_xts_[en|de]crypt. Westmere spends 1.50 cycles processing +# one byte out of 8KB with 128-bit key, Sandy Bridge - 1.09. + +###################################################################### +# Current large-block performance in cycles per byte processed with +# 128-bit key (less is better). +# +# CBC en-/decrypt CTR XTS ECB +# Westmere 3.77/1.37 1.37 1.52 1.27 +# * Bridge 5.07/0.98 0.99 1.09 0.91 +# Haswell 4.44/0.80 0.97 1.03 0.72 +# Silvermont 5.77/3.56 3.67 4.03 3.46 +# Bulldozer 5.80/0.98 1.05 1.24 0.93 + +$PREFIX="aesni"; # if $PREFIX is set to "AES", the script + # generates drop-in replacement for + # crypto/aes/asm/aes-586.pl:-) +$inline=1; # inline _aesni_[en|de]crypt + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],$0); + +&external_label("OPENSSL_ia32cap_P"); +&static_label("key_const"); + +if ($PREFIX eq "aesni") { $movekey=\&movups; } +else { $movekey=\&movups; } + +$len="eax"; +$rounds="ecx"; +$key="edx"; +$inp="esi"; +$out="edi"; +$rounds_="ebx"; # backup copy for $rounds +$key_="ebp"; # backup copy for $key + +$rndkey0="xmm0"; +$rndkey1="xmm1"; +$inout0="xmm2"; +$inout1="xmm3"; +$inout2="xmm4"; +$inout3="xmm5"; $in1="xmm5"; +$inout4="xmm6"; $in0="xmm6"; +$inout5="xmm7"; $ivec="xmm7"; + +# AESNI extenstion +sub aeskeygenassist +{ my($dst,$src,$imm)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &data_byte(0x66,0x0f,0x3a,0xdf,0xc0|($1<<3)|$2,$imm); } +} +sub aescommon +{ my($opcodelet,$dst,$src)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &data_byte(0x66,0x0f,0x38,$opcodelet,0xc0|($1<<3)|$2);} +} +sub aesimc { aescommon(0xdb,@_); } +sub aesenc { aescommon(0xdc,@_); } +sub aesenclast { aescommon(0xdd,@_); } +sub aesdec { aescommon(0xde,@_); } +sub aesdeclast { aescommon(0xdf,@_); } + +# Inline version of internal aesni_[en|de]crypt1 +{ my $sn; +sub aesni_inline_generate1 +{ my ($p,$inout,$ivec)=@_; $inout=$inout0 if (!defined($inout)); + $sn++; + + &$movekey ($rndkey0,&QWP(0,$key)); + &$movekey ($rndkey1,&QWP(16,$key)); + &xorps ($ivec,$rndkey0) if (defined($ivec)); + &lea ($key,&DWP(32,$key)); + &xorps ($inout,$ivec) if (defined($ivec)); + &xorps ($inout,$rndkey0) if (!defined($ivec)); + &set_label("${p}1_loop_$sn"); + eval"&aes${p} ($inout,$rndkey1)"; + &dec ($rounds); + &$movekey ($rndkey1,&QWP(0,$key)); + &lea ($key,&DWP(16,$key)); + &jnz (&label("${p}1_loop_$sn")); + eval"&aes${p}last ($inout,$rndkey1)"; +}} + +sub aesni_generate1 # fully unrolled loop +{ my ($p,$inout)=@_; $inout=$inout0 if (!defined($inout)); + + &function_begin_B("_aesni_${p}rypt1"); + &movups ($rndkey0,&QWP(0,$key)); + &$movekey ($rndkey1,&QWP(0x10,$key)); + &xorps ($inout,$rndkey0); + &$movekey ($rndkey0,&QWP(0x20,$key)); + &lea ($key,&DWP(0x30,$key)); + &cmp ($rounds,11); + &jb (&label("${p}128")); + &lea ($key,&DWP(0x20,$key)); + &je (&label("${p}192")); + &lea ($key,&DWP(0x20,$key)); + eval"&aes${p} ($inout,$rndkey1)"; + &$movekey ($rndkey1,&QWP(-0x40,$key)); + eval"&aes${p} ($inout,$rndkey0)"; + &$movekey ($rndkey0,&QWP(-0x30,$key)); + &set_label("${p}192"); + eval"&aes${p} ($inout,$rndkey1)"; + &$movekey ($rndkey1,&QWP(-0x20,$key)); + eval"&aes${p} ($inout,$rndkey0)"; + &$movekey ($rndkey0,&QWP(-0x10,$key)); + &set_label("${p}128"); + eval"&aes${p} ($inout,$rndkey1)"; + &$movekey ($rndkey1,&QWP(0,$key)); + eval"&aes${p} ($inout,$rndkey0)"; + &$movekey ($rndkey0,&QWP(0x10,$key)); + eval"&aes${p} ($inout,$rndkey1)"; + &$movekey ($rndkey1,&QWP(0x20,$key)); + eval"&aes${p} ($inout,$rndkey0)"; + &$movekey ($rndkey0,&QWP(0x30,$key)); + eval"&aes${p} ($inout,$rndkey1)"; + &$movekey ($rndkey1,&QWP(0x40,$key)); + eval"&aes${p} ($inout,$rndkey0)"; + &$movekey ($rndkey0,&QWP(0x50,$key)); + eval"&aes${p} ($inout,$rndkey1)"; + &$movekey ($rndkey1,&QWP(0x60,$key)); + eval"&aes${p} ($inout,$rndkey0)"; + &$movekey ($rndkey0,&QWP(0x70,$key)); + eval"&aes${p} ($inout,$rndkey1)"; + eval"&aes${p}last ($inout,$rndkey0)"; + &ret(); + &function_end_B("_aesni_${p}rypt1"); +} + +# void $PREFIX_encrypt (const void *inp,void *out,const AES_KEY *key); +&aesni_generate1("enc") if (!$inline); +&function_begin_B("${PREFIX}_encrypt"); + &mov ("eax",&wparam(0)); + &mov ($key,&wparam(2)); + &movups ($inout0,&QWP(0,"eax")); + &mov ($rounds,&DWP(240,$key)); + &mov ("eax",&wparam(1)); + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + &pxor ($rndkey0,$rndkey0); # clear register bank + &pxor ($rndkey1,$rndkey1); + &movups (&QWP(0,"eax"),$inout0); + &pxor ($inout0,$inout0); + &ret (); +&function_end_B("${PREFIX}_encrypt"); + +# void $PREFIX_decrypt (const void *inp,void *out,const AES_KEY *key); +&aesni_generate1("dec") if(!$inline); +&function_begin_B("${PREFIX}_decrypt"); + &mov ("eax",&wparam(0)); + &mov ($key,&wparam(2)); + &movups ($inout0,&QWP(0,"eax")); + &mov ($rounds,&DWP(240,$key)); + &mov ("eax",&wparam(1)); + if ($inline) + { &aesni_inline_generate1("dec"); } + else + { &call ("_aesni_decrypt1"); } + &pxor ($rndkey0,$rndkey0); # clear register bank + &pxor ($rndkey1,$rndkey1); + &movups (&QWP(0,"eax"),$inout0); + &pxor ($inout0,$inout0); + &ret (); +&function_end_B("${PREFIX}_decrypt"); + +# _aesni_[en|de]cryptN are private interfaces, N denotes interleave +# factor. Why 3x subroutine were originally used in loops? Even though +# aes[enc|dec] latency was originally 6, it could be scheduled only +# every *2nd* cycle. Thus 3x interleave was the one providing optimal +# utilization, i.e. when subroutine's throughput is virtually same as +# of non-interleaved subroutine [for number of input blocks up to 3]. +# This is why it originally made no sense to implement 2x subroutine. +# But times change and it became appropriate to spend extra 192 bytes +# on 2x subroutine on Atom Silvermont account. For processors that +# can schedule aes[enc|dec] every cycle optimal interleave factor +# equals to corresponding instructions latency. 8x is optimal for +# * Bridge, but it's unfeasible to accommodate such implementation +# in XMM registers addreassable in 32-bit mode and therefore maximum +# of 6x is used instead... + +sub aesni_generate2 +{ my $p=shift; + + &function_begin_B("_aesni_${p}rypt2"); + &$movekey ($rndkey0,&QWP(0,$key)); + &shl ($rounds,4); + &$movekey ($rndkey1,&QWP(16,$key)); + &xorps ($inout0,$rndkey0); + &pxor ($inout1,$rndkey0); + &$movekey ($rndkey0,&QWP(32,$key)); + &lea ($key,&DWP(32,$key,$rounds)); + &neg ($rounds); + &add ($rounds,16); + + &set_label("${p}2_loop"); + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + &$movekey ($rndkey1,&QWP(0,$key,$rounds)); + &add ($rounds,32); + eval"&aes${p} ($inout0,$rndkey0)"; + eval"&aes${p} ($inout1,$rndkey0)"; + &$movekey ($rndkey0,&QWP(-16,$key,$rounds)); + &jnz (&label("${p}2_loop")); + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + eval"&aes${p}last ($inout0,$rndkey0)"; + eval"&aes${p}last ($inout1,$rndkey0)"; + &ret(); + &function_end_B("_aesni_${p}rypt2"); +} + +sub aesni_generate3 +{ my $p=shift; + + &function_begin_B("_aesni_${p}rypt3"); + &$movekey ($rndkey0,&QWP(0,$key)); + &shl ($rounds,4); + &$movekey ($rndkey1,&QWP(16,$key)); + &xorps ($inout0,$rndkey0); + &pxor ($inout1,$rndkey0); + &pxor ($inout2,$rndkey0); + &$movekey ($rndkey0,&QWP(32,$key)); + &lea ($key,&DWP(32,$key,$rounds)); + &neg ($rounds); + &add ($rounds,16); + + &set_label("${p}3_loop"); + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + eval"&aes${p} ($inout2,$rndkey1)"; + &$movekey ($rndkey1,&QWP(0,$key,$rounds)); + &add ($rounds,32); + eval"&aes${p} ($inout0,$rndkey0)"; + eval"&aes${p} ($inout1,$rndkey0)"; + eval"&aes${p} ($inout2,$rndkey0)"; + &$movekey ($rndkey0,&QWP(-16,$key,$rounds)); + &jnz (&label("${p}3_loop")); + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + eval"&aes${p} ($inout2,$rndkey1)"; + eval"&aes${p}last ($inout0,$rndkey0)"; + eval"&aes${p}last ($inout1,$rndkey0)"; + eval"&aes${p}last ($inout2,$rndkey0)"; + &ret(); + &function_end_B("_aesni_${p}rypt3"); +} + +# 4x interleave is implemented to improve small block performance, +# most notably [and naturally] 4 block by ~30%. One can argue that one +# should have implemented 5x as well, but improvement would be <20%, +# so it's not worth it... +sub aesni_generate4 +{ my $p=shift; + + &function_begin_B("_aesni_${p}rypt4"); + &$movekey ($rndkey0,&QWP(0,$key)); + &$movekey ($rndkey1,&QWP(16,$key)); + &shl ($rounds,4); + &xorps ($inout0,$rndkey0); + &pxor ($inout1,$rndkey0); + &pxor ($inout2,$rndkey0); + &pxor ($inout3,$rndkey0); + &$movekey ($rndkey0,&QWP(32,$key)); + &lea ($key,&DWP(32,$key,$rounds)); + &neg ($rounds); + &data_byte (0x0f,0x1f,0x40,0x00); + &add ($rounds,16); + + &set_label("${p}4_loop"); + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + eval"&aes${p} ($inout2,$rndkey1)"; + eval"&aes${p} ($inout3,$rndkey1)"; + &$movekey ($rndkey1,&QWP(0,$key,$rounds)); + &add ($rounds,32); + eval"&aes${p} ($inout0,$rndkey0)"; + eval"&aes${p} ($inout1,$rndkey0)"; + eval"&aes${p} ($inout2,$rndkey0)"; + eval"&aes${p} ($inout3,$rndkey0)"; + &$movekey ($rndkey0,&QWP(-16,$key,$rounds)); + &jnz (&label("${p}4_loop")); + + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + eval"&aes${p} ($inout2,$rndkey1)"; + eval"&aes${p} ($inout3,$rndkey1)"; + eval"&aes${p}last ($inout0,$rndkey0)"; + eval"&aes${p}last ($inout1,$rndkey0)"; + eval"&aes${p}last ($inout2,$rndkey0)"; + eval"&aes${p}last ($inout3,$rndkey0)"; + &ret(); + &function_end_B("_aesni_${p}rypt4"); +} + +sub aesni_generate6 +{ my $p=shift; + + &function_begin_B("_aesni_${p}rypt6"); + &static_label("_aesni_${p}rypt6_enter"); + &$movekey ($rndkey0,&QWP(0,$key)); + &shl ($rounds,4); + &$movekey ($rndkey1,&QWP(16,$key)); + &xorps ($inout0,$rndkey0); + &pxor ($inout1,$rndkey0); # pxor does better here + &pxor ($inout2,$rndkey0); + eval"&aes${p} ($inout0,$rndkey1)"; + &pxor ($inout3,$rndkey0); + &pxor ($inout4,$rndkey0); + eval"&aes${p} ($inout1,$rndkey1)"; + &lea ($key,&DWP(32,$key,$rounds)); + &neg ($rounds); + eval"&aes${p} ($inout2,$rndkey1)"; + &pxor ($inout5,$rndkey0); + &$movekey ($rndkey0,&QWP(0,$key,$rounds)); + &add ($rounds,16); + &jmp (&label("_aesni_${p}rypt6_inner")); + + &set_label("${p}6_loop",16); + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + eval"&aes${p} ($inout2,$rndkey1)"; + &set_label("_aesni_${p}rypt6_inner"); + eval"&aes${p} ($inout3,$rndkey1)"; + eval"&aes${p} ($inout4,$rndkey1)"; + eval"&aes${p} ($inout5,$rndkey1)"; + &set_label("_aesni_${p}rypt6_enter"); + &$movekey ($rndkey1,&QWP(0,$key,$rounds)); + &add ($rounds,32); + eval"&aes${p} ($inout0,$rndkey0)"; + eval"&aes${p} ($inout1,$rndkey0)"; + eval"&aes${p} ($inout2,$rndkey0)"; + eval"&aes${p} ($inout3,$rndkey0)"; + eval"&aes${p} ($inout4,$rndkey0)"; + eval"&aes${p} ($inout5,$rndkey0)"; + &$movekey ($rndkey0,&QWP(-16,$key,$rounds)); + &jnz (&label("${p}6_loop")); + + eval"&aes${p} ($inout0,$rndkey1)"; + eval"&aes${p} ($inout1,$rndkey1)"; + eval"&aes${p} ($inout2,$rndkey1)"; + eval"&aes${p} ($inout3,$rndkey1)"; + eval"&aes${p} ($inout4,$rndkey1)"; + eval"&aes${p} ($inout5,$rndkey1)"; + eval"&aes${p}last ($inout0,$rndkey0)"; + eval"&aes${p}last ($inout1,$rndkey0)"; + eval"&aes${p}last ($inout2,$rndkey0)"; + eval"&aes${p}last ($inout3,$rndkey0)"; + eval"&aes${p}last ($inout4,$rndkey0)"; + eval"&aes${p}last ($inout5,$rndkey0)"; + &ret(); + &function_end_B("_aesni_${p}rypt6"); +} +&aesni_generate2("enc") if ($PREFIX eq "aesni"); +&aesni_generate2("dec"); +&aesni_generate3("enc") if ($PREFIX eq "aesni"); +&aesni_generate3("dec"); +&aesni_generate4("enc") if ($PREFIX eq "aesni"); +&aesni_generate4("dec"); +&aesni_generate6("enc") if ($PREFIX eq "aesni"); +&aesni_generate6("dec"); + +if ($PREFIX eq "aesni") { +###################################################################### +# void aesni_ecb_encrypt (const void *in, void *out, +# size_t length, const AES_KEY *key, +# int enc); +&function_begin("aesni_ecb_encrypt"); + &mov ($inp,&wparam(0)); + &mov ($out,&wparam(1)); + &mov ($len,&wparam(2)); + &mov ($key,&wparam(3)); + &mov ($rounds_,&wparam(4)); + &and ($len,-16); + &jz (&label("ecb_ret")); + &mov ($rounds,&DWP(240,$key)); + &test ($rounds_,$rounds_); + &jz (&label("ecb_decrypt")); + + &mov ($key_,$key); # backup $key + &mov ($rounds_,$rounds); # backup $rounds + &cmp ($len,0x60); + &jb (&label("ecb_enc_tail")); + + &movdqu ($inout0,&QWP(0,$inp)); + &movdqu ($inout1,&QWP(0x10,$inp)); + &movdqu ($inout2,&QWP(0x20,$inp)); + &movdqu ($inout3,&QWP(0x30,$inp)); + &movdqu ($inout4,&QWP(0x40,$inp)); + &movdqu ($inout5,&QWP(0x50,$inp)); + &lea ($inp,&DWP(0x60,$inp)); + &sub ($len,0x60); + &jmp (&label("ecb_enc_loop6_enter")); + +&set_label("ecb_enc_loop6",16); + &movups (&QWP(0,$out),$inout0); + &movdqu ($inout0,&QWP(0,$inp)); + &movups (&QWP(0x10,$out),$inout1); + &movdqu ($inout1,&QWP(0x10,$inp)); + &movups (&QWP(0x20,$out),$inout2); + &movdqu ($inout2,&QWP(0x20,$inp)); + &movups (&QWP(0x30,$out),$inout3); + &movdqu ($inout3,&QWP(0x30,$inp)); + &movups (&QWP(0x40,$out),$inout4); + &movdqu ($inout4,&QWP(0x40,$inp)); + &movups (&QWP(0x50,$out),$inout5); + &lea ($out,&DWP(0x60,$out)); + &movdqu ($inout5,&QWP(0x50,$inp)); + &lea ($inp,&DWP(0x60,$inp)); +&set_label("ecb_enc_loop6_enter"); + + &call ("_aesni_encrypt6"); + + &mov ($key,$key_); # restore $key + &mov ($rounds,$rounds_); # restore $rounds + &sub ($len,0x60); + &jnc (&label("ecb_enc_loop6")); + + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + &movups (&QWP(0x40,$out),$inout4); + &movups (&QWP(0x50,$out),$inout5); + &lea ($out,&DWP(0x60,$out)); + &add ($len,0x60); + &jz (&label("ecb_ret")); + +&set_label("ecb_enc_tail"); + &movups ($inout0,&QWP(0,$inp)); + &cmp ($len,0x20); + &jb (&label("ecb_enc_one")); + &movups ($inout1,&QWP(0x10,$inp)); + &je (&label("ecb_enc_two")); + &movups ($inout2,&QWP(0x20,$inp)); + &cmp ($len,0x40); + &jb (&label("ecb_enc_three")); + &movups ($inout3,&QWP(0x30,$inp)); + &je (&label("ecb_enc_four")); + &movups ($inout4,&QWP(0x40,$inp)); + &xorps ($inout5,$inout5); + &call ("_aesni_encrypt6"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + &movups (&QWP(0x40,$out),$inout4); + jmp (&label("ecb_ret")); + +&set_label("ecb_enc_one",16); + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + &movups (&QWP(0,$out),$inout0); + &jmp (&label("ecb_ret")); + +&set_label("ecb_enc_two",16); + &call ("_aesni_encrypt2"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &jmp (&label("ecb_ret")); + +&set_label("ecb_enc_three",16); + &call ("_aesni_encrypt3"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &jmp (&label("ecb_ret")); + +&set_label("ecb_enc_four",16); + &call ("_aesni_encrypt4"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + &jmp (&label("ecb_ret")); +###################################################################### +&set_label("ecb_decrypt",16); + &mov ($key_,$key); # backup $key + &mov ($rounds_,$rounds); # backup $rounds + &cmp ($len,0x60); + &jb (&label("ecb_dec_tail")); + + &movdqu ($inout0,&QWP(0,$inp)); + &movdqu ($inout1,&QWP(0x10,$inp)); + &movdqu ($inout2,&QWP(0x20,$inp)); + &movdqu ($inout3,&QWP(0x30,$inp)); + &movdqu ($inout4,&QWP(0x40,$inp)); + &movdqu ($inout5,&QWP(0x50,$inp)); + &lea ($inp,&DWP(0x60,$inp)); + &sub ($len,0x60); + &jmp (&label("ecb_dec_loop6_enter")); + +&set_label("ecb_dec_loop6",16); + &movups (&QWP(0,$out),$inout0); + &movdqu ($inout0,&QWP(0,$inp)); + &movups (&QWP(0x10,$out),$inout1); + &movdqu ($inout1,&QWP(0x10,$inp)); + &movups (&QWP(0x20,$out),$inout2); + &movdqu ($inout2,&QWP(0x20,$inp)); + &movups (&QWP(0x30,$out),$inout3); + &movdqu ($inout3,&QWP(0x30,$inp)); + &movups (&QWP(0x40,$out),$inout4); + &movdqu ($inout4,&QWP(0x40,$inp)); + &movups (&QWP(0x50,$out),$inout5); + &lea ($out,&DWP(0x60,$out)); + &movdqu ($inout5,&QWP(0x50,$inp)); + &lea ($inp,&DWP(0x60,$inp)); +&set_label("ecb_dec_loop6_enter"); + + &call ("_aesni_decrypt6"); + + &mov ($key,$key_); # restore $key + &mov ($rounds,$rounds_); # restore $rounds + &sub ($len,0x60); + &jnc (&label("ecb_dec_loop6")); + + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + &movups (&QWP(0x40,$out),$inout4); + &movups (&QWP(0x50,$out),$inout5); + &lea ($out,&DWP(0x60,$out)); + &add ($len,0x60); + &jz (&label("ecb_ret")); + +&set_label("ecb_dec_tail"); + &movups ($inout0,&QWP(0,$inp)); + &cmp ($len,0x20); + &jb (&label("ecb_dec_one")); + &movups ($inout1,&QWP(0x10,$inp)); + &je (&label("ecb_dec_two")); + &movups ($inout2,&QWP(0x20,$inp)); + &cmp ($len,0x40); + &jb (&label("ecb_dec_three")); + &movups ($inout3,&QWP(0x30,$inp)); + &je (&label("ecb_dec_four")); + &movups ($inout4,&QWP(0x40,$inp)); + &xorps ($inout5,$inout5); + &call ("_aesni_decrypt6"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + &movups (&QWP(0x40,$out),$inout4); + &jmp (&label("ecb_ret")); + +&set_label("ecb_dec_one",16); + if ($inline) + { &aesni_inline_generate1("dec"); } + else + { &call ("_aesni_decrypt1"); } + &movups (&QWP(0,$out),$inout0); + &jmp (&label("ecb_ret")); + +&set_label("ecb_dec_two",16); + &call ("_aesni_decrypt2"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &jmp (&label("ecb_ret")); + +&set_label("ecb_dec_three",16); + &call ("_aesni_decrypt3"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &jmp (&label("ecb_ret")); + +&set_label("ecb_dec_four",16); + &call ("_aesni_decrypt4"); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + +&set_label("ecb_ret"); + &pxor ("xmm0","xmm0"); # clear register bank + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &pxor ("xmm3","xmm3"); + &pxor ("xmm4","xmm4"); + &pxor ("xmm5","xmm5"); + &pxor ("xmm6","xmm6"); + &pxor ("xmm7","xmm7"); +&function_end("aesni_ecb_encrypt"); + +###################################################################### +# void aesni_ccm64_[en|de]crypt_blocks (const void *in, void *out, +# size_t blocks, const AES_KEY *key, +# const char *ivec,char *cmac); +# +# Handles only complete blocks, operates on 64-bit counter and +# does not update *ivec! Nor does it finalize CMAC value +# (see engine/eng_aesni.c for details) +# +{ my $cmac=$inout1; +&function_begin("aesni_ccm64_encrypt_blocks"); + &mov ($inp,&wparam(0)); + &mov ($out,&wparam(1)); + &mov ($len,&wparam(2)); + &mov ($key,&wparam(3)); + &mov ($rounds_,&wparam(4)); + &mov ($rounds,&wparam(5)); + &mov ($key_,"esp"); + &sub ("esp",60); + &and ("esp",-16); # align stack + &mov (&DWP(48,"esp"),$key_); + + &movdqu ($ivec,&QWP(0,$rounds_)); # load ivec + &movdqu ($cmac,&QWP(0,$rounds)); # load cmac + &mov ($rounds,&DWP(240,$key)); + + # compose byte-swap control mask for pshufb on stack + &mov (&DWP(0,"esp"),0x0c0d0e0f); + &mov (&DWP(4,"esp"),0x08090a0b); + &mov (&DWP(8,"esp"),0x04050607); + &mov (&DWP(12,"esp"),0x00010203); + + # compose counter increment vector on stack + &mov ($rounds_,1); + &xor ($key_,$key_); + &mov (&DWP(16,"esp"),$rounds_); + &mov (&DWP(20,"esp"),$key_); + &mov (&DWP(24,"esp"),$key_); + &mov (&DWP(28,"esp"),$key_); + + &shl ($rounds,4); + &mov ($rounds_,16); + &lea ($key_,&DWP(0,$key)); + &movdqa ($inout3,&QWP(0,"esp")); + &movdqa ($inout0,$ivec); + &lea ($key,&DWP(32,$key,$rounds)); + &sub ($rounds_,$rounds); + &pshufb ($ivec,$inout3); + +&set_label("ccm64_enc_outer"); + &$movekey ($rndkey0,&QWP(0,$key_)); + &mov ($rounds,$rounds_); + &movups ($in0,&QWP(0,$inp)); + + &xorps ($inout0,$rndkey0); + &$movekey ($rndkey1,&QWP(16,$key_)); + &xorps ($rndkey0,$in0); + &xorps ($cmac,$rndkey0); # cmac^=inp + &$movekey ($rndkey0,&QWP(32,$key_)); + +&set_label("ccm64_enc2_loop"); + &aesenc ($inout0,$rndkey1); + &aesenc ($cmac,$rndkey1); + &$movekey ($rndkey1,&QWP(0,$key,$rounds)); + &add ($rounds,32); + &aesenc ($inout0,$rndkey0); + &aesenc ($cmac,$rndkey0); + &$movekey ($rndkey0,&QWP(-16,$key,$rounds)); + &jnz (&label("ccm64_enc2_loop")); + &aesenc ($inout0,$rndkey1); + &aesenc ($cmac,$rndkey1); + &paddq ($ivec,&QWP(16,"esp")); + &dec ($len); + &aesenclast ($inout0,$rndkey0); + &aesenclast ($cmac,$rndkey0); + + &lea ($inp,&DWP(16,$inp)); + &xorps ($in0,$inout0); # inp^=E(ivec) + &movdqa ($inout0,$ivec); + &movups (&QWP(0,$out),$in0); # save output + &pshufb ($inout0,$inout3); + &lea ($out,&DWP(16,$out)); + &jnz (&label("ccm64_enc_outer")); + + &mov ("esp",&DWP(48,"esp")); + &mov ($out,&wparam(5)); + &movups (&QWP(0,$out),$cmac); + + &pxor ("xmm0","xmm0"); # clear register bank + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &pxor ("xmm3","xmm3"); + &pxor ("xmm4","xmm4"); + &pxor ("xmm5","xmm5"); + &pxor ("xmm6","xmm6"); + &pxor ("xmm7","xmm7"); +&function_end("aesni_ccm64_encrypt_blocks"); + +&function_begin("aesni_ccm64_decrypt_blocks"); + &mov ($inp,&wparam(0)); + &mov ($out,&wparam(1)); + &mov ($len,&wparam(2)); + &mov ($key,&wparam(3)); + &mov ($rounds_,&wparam(4)); + &mov ($rounds,&wparam(5)); + &mov ($key_,"esp"); + &sub ("esp",60); + &and ("esp",-16); # align stack + &mov (&DWP(48,"esp"),$key_); + + &movdqu ($ivec,&QWP(0,$rounds_)); # load ivec + &movdqu ($cmac,&QWP(0,$rounds)); # load cmac + &mov ($rounds,&DWP(240,$key)); + + # compose byte-swap control mask for pshufb on stack + &mov (&DWP(0,"esp"),0x0c0d0e0f); + &mov (&DWP(4,"esp"),0x08090a0b); + &mov (&DWP(8,"esp"),0x04050607); + &mov (&DWP(12,"esp"),0x00010203); + + # compose counter increment vector on stack + &mov ($rounds_,1); + &xor ($key_,$key_); + &mov (&DWP(16,"esp"),$rounds_); + &mov (&DWP(20,"esp"),$key_); + &mov (&DWP(24,"esp"),$key_); + &mov (&DWP(28,"esp"),$key_); + + &movdqa ($inout3,&QWP(0,"esp")); # bswap mask + &movdqa ($inout0,$ivec); + + &mov ($key_,$key); + &mov ($rounds_,$rounds); + + &pshufb ($ivec,$inout3); + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + &shl ($rounds_,4); + &mov ($rounds,16); + &movups ($in0,&QWP(0,$inp)); # load inp + &paddq ($ivec,&QWP(16,"esp")); + &lea ($inp,&QWP(16,$inp)); + &sub ($rounds,$rounds_); + &lea ($key,&DWP(32,$key_,$rounds_)); + &mov ($rounds_,$rounds); + &jmp (&label("ccm64_dec_outer")); + +&set_label("ccm64_dec_outer",16); + &xorps ($in0,$inout0); # inp ^= E(ivec) + &movdqa ($inout0,$ivec); + &movups (&QWP(0,$out),$in0); # save output + &lea ($out,&DWP(16,$out)); + &pshufb ($inout0,$inout3); + + &sub ($len,1); + &jz (&label("ccm64_dec_break")); + + &$movekey ($rndkey0,&QWP(0,$key_)); + &mov ($rounds,$rounds_); + &$movekey ($rndkey1,&QWP(16,$key_)); + &xorps ($in0,$rndkey0); + &xorps ($inout0,$rndkey0); + &xorps ($cmac,$in0); # cmac^=out + &$movekey ($rndkey0,&QWP(32,$key_)); + +&set_label("ccm64_dec2_loop"); + &aesenc ($inout0,$rndkey1); + &aesenc ($cmac,$rndkey1); + &$movekey ($rndkey1,&QWP(0,$key,$rounds)); + &add ($rounds,32); + &aesenc ($inout0,$rndkey0); + &aesenc ($cmac,$rndkey0); + &$movekey ($rndkey0,&QWP(-16,$key,$rounds)); + &jnz (&label("ccm64_dec2_loop")); + &movups ($in0,&QWP(0,$inp)); # load inp + &paddq ($ivec,&QWP(16,"esp")); + &aesenc ($inout0,$rndkey1); + &aesenc ($cmac,$rndkey1); + &aesenclast ($inout0,$rndkey0); + &aesenclast ($cmac,$rndkey0); + &lea ($inp,&QWP(16,$inp)); + &jmp (&label("ccm64_dec_outer")); + +&set_label("ccm64_dec_break",16); + &mov ($rounds,&DWP(240,$key_)); + &mov ($key,$key_); + if ($inline) + { &aesni_inline_generate1("enc",$cmac,$in0); } + else + { &call ("_aesni_encrypt1",$cmac); } + + &mov ("esp",&DWP(48,"esp")); + &mov ($out,&wparam(5)); + &movups (&QWP(0,$out),$cmac); + + &pxor ("xmm0","xmm0"); # clear register bank + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &pxor ("xmm3","xmm3"); + &pxor ("xmm4","xmm4"); + &pxor ("xmm5","xmm5"); + &pxor ("xmm6","xmm6"); + &pxor ("xmm7","xmm7"); +&function_end("aesni_ccm64_decrypt_blocks"); +} + +###################################################################### +# void aesni_ctr32_encrypt_blocks (const void *in, void *out, +# size_t blocks, const AES_KEY *key, +# const char *ivec); +# +# Handles only complete blocks, operates on 32-bit counter and +# does not update *ivec! (see crypto/modes/ctr128.c for details) +# +# stack layout: +# 0 pshufb mask +# 16 vector addend: 0,6,6,6 +# 32 counter-less ivec +# 48 1st triplet of counter vector +# 64 2nd triplet of counter vector +# 80 saved %esp + +&function_begin("aesni_ctr32_encrypt_blocks"); + &mov ($inp,&wparam(0)); + &mov ($out,&wparam(1)); + &mov ($len,&wparam(2)); + &mov ($key,&wparam(3)); + &mov ($rounds_,&wparam(4)); + &mov ($key_,"esp"); + &sub ("esp",88); + &and ("esp",-16); # align stack + &mov (&DWP(80,"esp"),$key_); + + &cmp ($len,1); + &je (&label("ctr32_one_shortcut")); + + &movdqu ($inout5,&QWP(0,$rounds_)); # load ivec + + # compose byte-swap control mask for pshufb on stack + &mov (&DWP(0,"esp"),0x0c0d0e0f); + &mov (&DWP(4,"esp"),0x08090a0b); + &mov (&DWP(8,"esp"),0x04050607); + &mov (&DWP(12,"esp"),0x00010203); + + # compose counter increment vector on stack + &mov ($rounds,6); + &xor ($key_,$key_); + &mov (&DWP(16,"esp"),$rounds); + &mov (&DWP(20,"esp"),$rounds); + &mov (&DWP(24,"esp"),$rounds); + &mov (&DWP(28,"esp"),$key_); + + &pextrd ($rounds_,$inout5,3); # pull 32-bit counter + &pinsrd ($inout5,$key_,3); # wipe 32-bit counter + + &mov ($rounds,&DWP(240,$key)); # key->rounds + + # compose 2 vectors of 3x32-bit counters + &bswap ($rounds_); + &pxor ($rndkey0,$rndkey0); + &pxor ($rndkey1,$rndkey1); + &movdqa ($inout0,&QWP(0,"esp")); # load byte-swap mask + &pinsrd ($rndkey0,$rounds_,0); + &lea ($key_,&DWP(3,$rounds_)); + &pinsrd ($rndkey1,$key_,0); + &inc ($rounds_); + &pinsrd ($rndkey0,$rounds_,1); + &inc ($key_); + &pinsrd ($rndkey1,$key_,1); + &inc ($rounds_); + &pinsrd ($rndkey0,$rounds_,2); + &inc ($key_); + &pinsrd ($rndkey1,$key_,2); + &movdqa (&QWP(48,"esp"),$rndkey0); # save 1st triplet + &pshufb ($rndkey0,$inout0); # byte swap + &movdqu ($inout4,&QWP(0,$key)); # key[0] + &movdqa (&QWP(64,"esp"),$rndkey1); # save 2nd triplet + &pshufb ($rndkey1,$inout0); # byte swap + + &pshufd ($inout0,$rndkey0,3<<6); # place counter to upper dword + &pshufd ($inout1,$rndkey0,2<<6); + &cmp ($len,6); + &jb (&label("ctr32_tail")); + &pxor ($inout5,$inout4); # counter-less ivec^key[0] + &shl ($rounds,4); + &mov ($rounds_,16); + &movdqa (&QWP(32,"esp"),$inout5); # save counter-less ivec^key[0] + &mov ($key_,$key); # backup $key + &sub ($rounds_,$rounds); # backup twisted $rounds + &lea ($key,&DWP(32,$key,$rounds)); + &sub ($len,6); + &jmp (&label("ctr32_loop6")); + +&set_label("ctr32_loop6",16); + # inlining _aesni_encrypt6's prologue gives ~6% improvement... + &pshufd ($inout2,$rndkey0,1<<6); + &movdqa ($rndkey0,&QWP(32,"esp")); # pull counter-less ivec + &pshufd ($inout3,$rndkey1,3<<6); + &pxor ($inout0,$rndkey0); # merge counter-less ivec + &pshufd ($inout4,$rndkey1,2<<6); + &pxor ($inout1,$rndkey0); + &pshufd ($inout5,$rndkey1,1<<6); + &$movekey ($rndkey1,&QWP(16,$key_)); + &pxor ($inout2,$rndkey0); + &pxor ($inout3,$rndkey0); + &aesenc ($inout0,$rndkey1); + &pxor ($inout4,$rndkey0); + &pxor ($inout5,$rndkey0); + &aesenc ($inout1,$rndkey1); + &$movekey ($rndkey0,&QWP(32,$key_)); + &mov ($rounds,$rounds_); + &aesenc ($inout2,$rndkey1); + &aesenc ($inout3,$rndkey1); + &aesenc ($inout4,$rndkey1); + &aesenc ($inout5,$rndkey1); + + &call (&label("_aesni_encrypt6_enter")); + + &movups ($rndkey1,&QWP(0,$inp)); + &movups ($rndkey0,&QWP(0x10,$inp)); + &xorps ($inout0,$rndkey1); + &movups ($rndkey1,&QWP(0x20,$inp)); + &xorps ($inout1,$rndkey0); + &movups (&QWP(0,$out),$inout0); + &movdqa ($rndkey0,&QWP(16,"esp")); # load increment + &xorps ($inout2,$rndkey1); + &movdqa ($rndkey1,&QWP(64,"esp")); # load 2nd triplet + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + + &paddd ($rndkey1,$rndkey0); # 2nd triplet increment + &paddd ($rndkey0,&QWP(48,"esp")); # 1st triplet increment + &movdqa ($inout0,&QWP(0,"esp")); # load byte swap mask + + &movups ($inout1,&QWP(0x30,$inp)); + &movups ($inout2,&QWP(0x40,$inp)); + &xorps ($inout3,$inout1); + &movups ($inout1,&QWP(0x50,$inp)); + &lea ($inp,&DWP(0x60,$inp)); + &movdqa (&QWP(48,"esp"),$rndkey0); # save 1st triplet + &pshufb ($rndkey0,$inout0); # byte swap + &xorps ($inout4,$inout2); + &movups (&QWP(0x30,$out),$inout3); + &xorps ($inout5,$inout1); + &movdqa (&QWP(64,"esp"),$rndkey1); # save 2nd triplet + &pshufb ($rndkey1,$inout0); # byte swap + &movups (&QWP(0x40,$out),$inout4); + &pshufd ($inout0,$rndkey0,3<<6); + &movups (&QWP(0x50,$out),$inout5); + &lea ($out,&DWP(0x60,$out)); + + &pshufd ($inout1,$rndkey0,2<<6); + &sub ($len,6); + &jnc (&label("ctr32_loop6")); + + &add ($len,6); + &jz (&label("ctr32_ret")); + &movdqu ($inout5,&QWP(0,$key_)); + &mov ($key,$key_); + &pxor ($inout5,&QWP(32,"esp")); # restore count-less ivec + &mov ($rounds,&DWP(240,$key_)); # restore $rounds + +&set_label("ctr32_tail"); + &por ($inout0,$inout5); + &cmp ($len,2); + &jb (&label("ctr32_one")); + + &pshufd ($inout2,$rndkey0,1<<6); + &por ($inout1,$inout5); + &je (&label("ctr32_two")); + + &pshufd ($inout3,$rndkey1,3<<6); + &por ($inout2,$inout5); + &cmp ($len,4); + &jb (&label("ctr32_three")); + + &pshufd ($inout4,$rndkey1,2<<6); + &por ($inout3,$inout5); + &je (&label("ctr32_four")); + + &por ($inout4,$inout5); + &call ("_aesni_encrypt6"); + &movups ($rndkey1,&QWP(0,$inp)); + &movups ($rndkey0,&QWP(0x10,$inp)); + &xorps ($inout0,$rndkey1); + &movups ($rndkey1,&QWP(0x20,$inp)); + &xorps ($inout1,$rndkey0); + &movups ($rndkey0,&QWP(0x30,$inp)); + &xorps ($inout2,$rndkey1); + &movups ($rndkey1,&QWP(0x40,$inp)); + &xorps ($inout3,$rndkey0); + &movups (&QWP(0,$out),$inout0); + &xorps ($inout4,$rndkey1); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + &movups (&QWP(0x40,$out),$inout4); + &jmp (&label("ctr32_ret")); + +&set_label("ctr32_one_shortcut",16); + &movups ($inout0,&QWP(0,$rounds_)); # load ivec + &mov ($rounds,&DWP(240,$key)); + +&set_label("ctr32_one"); + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + &movups ($in0,&QWP(0,$inp)); + &xorps ($in0,$inout0); + &movups (&QWP(0,$out),$in0); + &jmp (&label("ctr32_ret")); + +&set_label("ctr32_two",16); + &call ("_aesni_encrypt2"); + &movups ($inout3,&QWP(0,$inp)); + &movups ($inout4,&QWP(0x10,$inp)); + &xorps ($inout0,$inout3); + &xorps ($inout1,$inout4); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &jmp (&label("ctr32_ret")); + +&set_label("ctr32_three",16); + &call ("_aesni_encrypt3"); + &movups ($inout3,&QWP(0,$inp)); + &movups ($inout4,&QWP(0x10,$inp)); + &xorps ($inout0,$inout3); + &movups ($inout5,&QWP(0x20,$inp)); + &xorps ($inout1,$inout4); + &movups (&QWP(0,$out),$inout0); + &xorps ($inout2,$inout5); + &movups (&QWP(0x10,$out),$inout1); + &movups (&QWP(0x20,$out),$inout2); + &jmp (&label("ctr32_ret")); + +&set_label("ctr32_four",16); + &call ("_aesni_encrypt4"); + &movups ($inout4,&QWP(0,$inp)); + &movups ($inout5,&QWP(0x10,$inp)); + &movups ($rndkey1,&QWP(0x20,$inp)); + &xorps ($inout0,$inout4); + &movups ($rndkey0,&QWP(0x30,$inp)); + &xorps ($inout1,$inout5); + &movups (&QWP(0,$out),$inout0); + &xorps ($inout2,$rndkey1); + &movups (&QWP(0x10,$out),$inout1); + &xorps ($inout3,$rndkey0); + &movups (&QWP(0x20,$out),$inout2); + &movups (&QWP(0x30,$out),$inout3); + +&set_label("ctr32_ret"); + &pxor ("xmm0","xmm0"); # clear register bank + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &pxor ("xmm3","xmm3"); + &pxor ("xmm4","xmm4"); + &movdqa (&QWP(32,"esp"),"xmm0"); # clear stack + &pxor ("xmm5","xmm5"); + &movdqa (&QWP(48,"esp"),"xmm0"); + &pxor ("xmm6","xmm6"); + &movdqa (&QWP(64,"esp"),"xmm0"); + &pxor ("xmm7","xmm7"); + &mov ("esp",&DWP(80,"esp")); +&function_end("aesni_ctr32_encrypt_blocks"); + +###################################################################### +# void aesni_xts_[en|de]crypt(const char *inp,char *out,size_t len, +# const AES_KEY *key1, const AES_KEY *key2 +# const unsigned char iv[16]); +# +{ my ($tweak,$twtmp,$twres,$twmask)=($rndkey1,$rndkey0,$inout0,$inout1); + +&function_begin("aesni_xts_encrypt"); + &mov ($key,&wparam(4)); # key2 + &mov ($inp,&wparam(5)); # clear-text tweak + + &mov ($rounds,&DWP(240,$key)); # key2->rounds + &movups ($inout0,&QWP(0,$inp)); + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + + &mov ($inp,&wparam(0)); + &mov ($out,&wparam(1)); + &mov ($len,&wparam(2)); + &mov ($key,&wparam(3)); # key1 + + &mov ($key_,"esp"); + &sub ("esp",16*7+8); + &mov ($rounds,&DWP(240,$key)); # key1->rounds + &and ("esp",-16); # align stack + + &mov (&DWP(16*6+0,"esp"),0x87); # compose the magic constant + &mov (&DWP(16*6+4,"esp"),0); + &mov (&DWP(16*6+8,"esp"),1); + &mov (&DWP(16*6+12,"esp"),0); + &mov (&DWP(16*7+0,"esp"),$len); # save original $len + &mov (&DWP(16*7+4,"esp"),$key_); # save original %esp + + &movdqa ($tweak,$inout0); + &pxor ($twtmp,$twtmp); + &movdqa ($twmask,&QWP(6*16,"esp")); # 0x0...010...87 + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + + &and ($len,-16); + &mov ($key_,$key); # backup $key + &mov ($rounds_,$rounds); # backup $rounds + &sub ($len,16*6); + &jc (&label("xts_enc_short")); + + &shl ($rounds,4); + &mov ($rounds_,16); + &sub ($rounds_,$rounds); + &lea ($key,&DWP(32,$key,$rounds)); + &jmp (&label("xts_enc_loop6")); + +&set_label("xts_enc_loop6",16); + for ($i=0;$i<4;$i++) { + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &movdqa (&QWP(16*$i,"esp"),$tweak); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd ($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + } + &pshufd ($inout5,$twtmp,0x13); + &movdqa (&QWP(16*$i++,"esp"),$tweak); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &$movekey ($rndkey0,&QWP(0,$key_)); + &pand ($inout5,$twmask); # isolate carry and residue + &movups ($inout0,&QWP(0,$inp)); # load input + &pxor ($inout5,$tweak); + + # inline _aesni_encrypt6 prologue and flip xor with tweak and key[0] + &mov ($rounds,$rounds_); # restore $rounds + &movdqu ($inout1,&QWP(16*1,$inp)); + &xorps ($inout0,$rndkey0); # input^=rndkey[0] + &movdqu ($inout2,&QWP(16*2,$inp)); + &pxor ($inout1,$rndkey0); + &movdqu ($inout3,&QWP(16*3,$inp)); + &pxor ($inout2,$rndkey0); + &movdqu ($inout4,&QWP(16*4,$inp)); + &pxor ($inout3,$rndkey0); + &movdqu ($rndkey1,&QWP(16*5,$inp)); + &pxor ($inout4,$rndkey0); + &lea ($inp,&DWP(16*6,$inp)); + &pxor ($inout0,&QWP(16*0,"esp")); # input^=tweak + &movdqa (&QWP(16*$i,"esp"),$inout5); # save last tweak + &pxor ($inout5,$rndkey1); + + &$movekey ($rndkey1,&QWP(16,$key_)); + &pxor ($inout1,&QWP(16*1,"esp")); + &pxor ($inout2,&QWP(16*2,"esp")); + &aesenc ($inout0,$rndkey1); + &pxor ($inout3,&QWP(16*3,"esp")); + &pxor ($inout4,&QWP(16*4,"esp")); + &aesenc ($inout1,$rndkey1); + &pxor ($inout5,$rndkey0); + &$movekey ($rndkey0,&QWP(32,$key_)); + &aesenc ($inout2,$rndkey1); + &aesenc ($inout3,$rndkey1); + &aesenc ($inout4,$rndkey1); + &aesenc ($inout5,$rndkey1); + &call (&label("_aesni_encrypt6_enter")); + + &movdqa ($tweak,&QWP(16*5,"esp")); # last tweak + &pxor ($twtmp,$twtmp); + &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak + &pcmpgtd ($twtmp,$tweak); # broadcast upper bits + &xorps ($inout1,&QWP(16*1,"esp")); + &movups (&QWP(16*0,$out),$inout0); # write output + &xorps ($inout2,&QWP(16*2,"esp")); + &movups (&QWP(16*1,$out),$inout1); + &xorps ($inout3,&QWP(16*3,"esp")); + &movups (&QWP(16*2,$out),$inout2); + &xorps ($inout4,&QWP(16*4,"esp")); + &movups (&QWP(16*3,$out),$inout3); + &xorps ($inout5,$tweak); + &movups (&QWP(16*4,$out),$inout4); + &pshufd ($twres,$twtmp,0x13); + &movups (&QWP(16*5,$out),$inout5); + &lea ($out,&DWP(16*6,$out)); + &movdqa ($twmask,&QWP(16*6,"esp")); # 0x0...010...87 + + &pxor ($twtmp,$twtmp); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + + &sub ($len,16*6); + &jnc (&label("xts_enc_loop6")); + + &mov ($rounds,&DWP(240,$key_)); # restore $rounds + &mov ($key,$key_); # restore $key + &mov ($rounds_,$rounds); + +&set_label("xts_enc_short"); + &add ($len,16*6); + &jz (&label("xts_enc_done6x")); + + &movdqa ($inout3,$tweak); # put aside previous tweak + &cmp ($len,0x20); + &jb (&label("xts_enc_one")); + + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + &je (&label("xts_enc_two")); + + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &movdqa ($inout4,$tweak); # put aside previous tweak + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + &cmp ($len,0x40); + &jb (&label("xts_enc_three")); + + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &movdqa ($inout5,$tweak); # put aside previous tweak + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + &movdqa (&QWP(16*0,"esp"),$inout3); + &movdqa (&QWP(16*1,"esp"),$inout4); + &je (&label("xts_enc_four")); + + &movdqa (&QWP(16*2,"esp"),$inout5); + &pshufd ($inout5,$twtmp,0x13); + &movdqa (&QWP(16*3,"esp"),$tweak); + &paddq ($tweak,$tweak); # &psllq($inout0,1); + &pand ($inout5,$twmask); # isolate carry and residue + &pxor ($inout5,$tweak); + + &movdqu ($inout0,&QWP(16*0,$inp)); # load input + &movdqu ($inout1,&QWP(16*1,$inp)); + &movdqu ($inout2,&QWP(16*2,$inp)); + &pxor ($inout0,&QWP(16*0,"esp")); # input^=tweak + &movdqu ($inout3,&QWP(16*3,$inp)); + &pxor ($inout1,&QWP(16*1,"esp")); + &movdqu ($inout4,&QWP(16*4,$inp)); + &pxor ($inout2,&QWP(16*2,"esp")); + &lea ($inp,&DWP(16*5,$inp)); + &pxor ($inout3,&QWP(16*3,"esp")); + &movdqa (&QWP(16*4,"esp"),$inout5); # save last tweak + &pxor ($inout4,$inout5); + + &call ("_aesni_encrypt6"); + + &movaps ($tweak,&QWP(16*4,"esp")); # last tweak + &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak + &xorps ($inout1,&QWP(16*1,"esp")); + &xorps ($inout2,&QWP(16*2,"esp")); + &movups (&QWP(16*0,$out),$inout0); # write output + &xorps ($inout3,&QWP(16*3,"esp")); + &movups (&QWP(16*1,$out),$inout1); + &xorps ($inout4,$tweak); + &movups (&QWP(16*2,$out),$inout2); + &movups (&QWP(16*3,$out),$inout3); + &movups (&QWP(16*4,$out),$inout4); + &lea ($out,&DWP(16*5,$out)); + &jmp (&label("xts_enc_done")); + +&set_label("xts_enc_one",16); + &movups ($inout0,&QWP(16*0,$inp)); # load input + &lea ($inp,&DWP(16*1,$inp)); + &xorps ($inout0,$inout3); # input^=tweak + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + &xorps ($inout0,$inout3); # output^=tweak + &movups (&QWP(16*0,$out),$inout0); # write output + &lea ($out,&DWP(16*1,$out)); + + &movdqa ($tweak,$inout3); # last tweak + &jmp (&label("xts_enc_done")); + +&set_label("xts_enc_two",16); + &movaps ($inout4,$tweak); # put aside last tweak + + &movups ($inout0,&QWP(16*0,$inp)); # load input + &movups ($inout1,&QWP(16*1,$inp)); + &lea ($inp,&DWP(16*2,$inp)); + &xorps ($inout0,$inout3); # input^=tweak + &xorps ($inout1,$inout4); + + &call ("_aesni_encrypt2"); + + &xorps ($inout0,$inout3); # output^=tweak + &xorps ($inout1,$inout4); + &movups (&QWP(16*0,$out),$inout0); # write output + &movups (&QWP(16*1,$out),$inout1); + &lea ($out,&DWP(16*2,$out)); + + &movdqa ($tweak,$inout4); # last tweak + &jmp (&label("xts_enc_done")); + +&set_label("xts_enc_three",16); + &movaps ($inout5,$tweak); # put aside last tweak + &movups ($inout0,&QWP(16*0,$inp)); # load input + &movups ($inout1,&QWP(16*1,$inp)); + &movups ($inout2,&QWP(16*2,$inp)); + &lea ($inp,&DWP(16*3,$inp)); + &xorps ($inout0,$inout3); # input^=tweak + &xorps ($inout1,$inout4); + &xorps ($inout2,$inout5); + + &call ("_aesni_encrypt3"); + + &xorps ($inout0,$inout3); # output^=tweak + &xorps ($inout1,$inout4); + &xorps ($inout2,$inout5); + &movups (&QWP(16*0,$out),$inout0); # write output + &movups (&QWP(16*1,$out),$inout1); + &movups (&QWP(16*2,$out),$inout2); + &lea ($out,&DWP(16*3,$out)); + + &movdqa ($tweak,$inout5); # last tweak + &jmp (&label("xts_enc_done")); + +&set_label("xts_enc_four",16); + &movaps ($inout4,$tweak); # put aside last tweak + + &movups ($inout0,&QWP(16*0,$inp)); # load input + &movups ($inout1,&QWP(16*1,$inp)); + &movups ($inout2,&QWP(16*2,$inp)); + &xorps ($inout0,&QWP(16*0,"esp")); # input^=tweak + &movups ($inout3,&QWP(16*3,$inp)); + &lea ($inp,&DWP(16*4,$inp)); + &xorps ($inout1,&QWP(16*1,"esp")); + &xorps ($inout2,$inout5); + &xorps ($inout3,$inout4); + + &call ("_aesni_encrypt4"); + + &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak + &xorps ($inout1,&QWP(16*1,"esp")); + &xorps ($inout2,$inout5); + &movups (&QWP(16*0,$out),$inout0); # write output + &xorps ($inout3,$inout4); + &movups (&QWP(16*1,$out),$inout1); + &movups (&QWP(16*2,$out),$inout2); + &movups (&QWP(16*3,$out),$inout3); + &lea ($out,&DWP(16*4,$out)); + + &movdqa ($tweak,$inout4); # last tweak + &jmp (&label("xts_enc_done")); + +&set_label("xts_enc_done6x",16); # $tweak is pre-calculated + &mov ($len,&DWP(16*7+0,"esp")); # restore original $len + &and ($len,15); + &jz (&label("xts_enc_ret")); + &movdqa ($inout3,$tweak); + &mov (&DWP(16*7+0,"esp"),$len); # save $len%16 + &jmp (&label("xts_enc_steal")); + +&set_label("xts_enc_done",16); + &mov ($len,&DWP(16*7+0,"esp")); # restore original $len + &pxor ($twtmp,$twtmp); + &and ($len,15); + &jz (&label("xts_enc_ret")); + + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &mov (&DWP(16*7+0,"esp"),$len); # save $len%16 + &pshufd ($inout3,$twtmp,0x13); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($inout3,&QWP(16*6,"esp")); # isolate carry and residue + &pxor ($inout3,$tweak); + +&set_label("xts_enc_steal"); + &movz ($rounds,&BP(0,$inp)); + &movz ($key,&BP(-16,$out)); + &lea ($inp,&DWP(1,$inp)); + &mov (&BP(-16,$out),&LB($rounds)); + &mov (&BP(0,$out),&LB($key)); + &lea ($out,&DWP(1,$out)); + &sub ($len,1); + &jnz (&label("xts_enc_steal")); + + &sub ($out,&DWP(16*7+0,"esp")); # rewind $out + &mov ($key,$key_); # restore $key + &mov ($rounds,$rounds_); # restore $rounds + + &movups ($inout0,&QWP(-16,$out)); # load input + &xorps ($inout0,$inout3); # input^=tweak + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + &xorps ($inout0,$inout3); # output^=tweak + &movups (&QWP(-16,$out),$inout0); # write output + +&set_label("xts_enc_ret"); + &pxor ("xmm0","xmm0"); # clear register bank + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &movdqa (&QWP(16*0,"esp"),"xmm0"); # clear stack + &pxor ("xmm3","xmm3"); + &movdqa (&QWP(16*1,"esp"),"xmm0"); + &pxor ("xmm4","xmm4"); + &movdqa (&QWP(16*2,"esp"),"xmm0"); + &pxor ("xmm5","xmm5"); + &movdqa (&QWP(16*3,"esp"),"xmm0"); + &pxor ("xmm6","xmm6"); + &movdqa (&QWP(16*4,"esp"),"xmm0"); + &pxor ("xmm7","xmm7"); + &movdqa (&QWP(16*5,"esp"),"xmm0"); + &mov ("esp",&DWP(16*7+4,"esp")); # restore %esp +&function_end("aesni_xts_encrypt"); + +&function_begin("aesni_xts_decrypt"); + &mov ($key,&wparam(4)); # key2 + &mov ($inp,&wparam(5)); # clear-text tweak + + &mov ($rounds,&DWP(240,$key)); # key2->rounds + &movups ($inout0,&QWP(0,$inp)); + if ($inline) + { &aesni_inline_generate1("enc"); } + else + { &call ("_aesni_encrypt1"); } + + &mov ($inp,&wparam(0)); + &mov ($out,&wparam(1)); + &mov ($len,&wparam(2)); + &mov ($key,&wparam(3)); # key1 + + &mov ($key_,"esp"); + &sub ("esp",16*7+8); + &and ("esp",-16); # align stack + + &xor ($rounds_,$rounds_); # if(len%16) len-=16; + &test ($len,15); + &setnz (&LB($rounds_)); + &shl ($rounds_,4); + &sub ($len,$rounds_); + + &mov (&DWP(16*6+0,"esp"),0x87); # compose the magic constant + &mov (&DWP(16*6+4,"esp"),0); + &mov (&DWP(16*6+8,"esp"),1); + &mov (&DWP(16*6+12,"esp"),0); + &mov (&DWP(16*7+0,"esp"),$len); # save original $len + &mov (&DWP(16*7+4,"esp"),$key_); # save original %esp + + &mov ($rounds,&DWP(240,$key)); # key1->rounds + &mov ($key_,$key); # backup $key + &mov ($rounds_,$rounds); # backup $rounds + + &movdqa ($tweak,$inout0); + &pxor ($twtmp,$twtmp); + &movdqa ($twmask,&QWP(6*16,"esp")); # 0x0...010...87 + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + + &and ($len,-16); + &sub ($len,16*6); + &jc (&label("xts_dec_short")); + + &shl ($rounds,4); + &mov ($rounds_,16); + &sub ($rounds_,$rounds); + &lea ($key,&DWP(32,$key,$rounds)); + &jmp (&label("xts_dec_loop6")); + +&set_label("xts_dec_loop6",16); + for ($i=0;$i<4;$i++) { + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &movdqa (&QWP(16*$i,"esp"),$tweak); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd ($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + } + &pshufd ($inout5,$twtmp,0x13); + &movdqa (&QWP(16*$i++,"esp"),$tweak); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &$movekey ($rndkey0,&QWP(0,$key_)); + &pand ($inout5,$twmask); # isolate carry and residue + &movups ($inout0,&QWP(0,$inp)); # load input + &pxor ($inout5,$tweak); + + # inline _aesni_encrypt6 prologue and flip xor with tweak and key[0] + &mov ($rounds,$rounds_); + &movdqu ($inout1,&QWP(16*1,$inp)); + &xorps ($inout0,$rndkey0); # input^=rndkey[0] + &movdqu ($inout2,&QWP(16*2,$inp)); + &pxor ($inout1,$rndkey0); + &movdqu ($inout3,&QWP(16*3,$inp)); + &pxor ($inout2,$rndkey0); + &movdqu ($inout4,&QWP(16*4,$inp)); + &pxor ($inout3,$rndkey0); + &movdqu ($rndkey1,&QWP(16*5,$inp)); + &pxor ($inout4,$rndkey0); + &lea ($inp,&DWP(16*6,$inp)); + &pxor ($inout0,&QWP(16*0,"esp")); # input^=tweak + &movdqa (&QWP(16*$i,"esp"),$inout5); # save last tweak + &pxor ($inout5,$rndkey1); + + &$movekey ($rndkey1,&QWP(16,$key_)); + &pxor ($inout1,&QWP(16*1,"esp")); + &pxor ($inout2,&QWP(16*2,"esp")); + &aesdec ($inout0,$rndkey1); + &pxor ($inout3,&QWP(16*3,"esp")); + &pxor ($inout4,&QWP(16*4,"esp")); + &aesdec ($inout1,$rndkey1); + &pxor ($inout5,$rndkey0); + &$movekey ($rndkey0,&QWP(32,$key_)); + &aesdec ($inout2,$rndkey1); + &aesdec ($inout3,$rndkey1); + &aesdec ($inout4,$rndkey1); + &aesdec ($inout5,$rndkey1); + &call (&label("_aesni_decrypt6_enter")); + + &movdqa ($tweak,&QWP(16*5,"esp")); # last tweak + &pxor ($twtmp,$twtmp); + &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak + &pcmpgtd ($twtmp,$tweak); # broadcast upper bits + &xorps ($inout1,&QWP(16*1,"esp")); + &movups (&QWP(16*0,$out),$inout0); # write output + &xorps ($inout2,&QWP(16*2,"esp")); + &movups (&QWP(16*1,$out),$inout1); + &xorps ($inout3,&QWP(16*3,"esp")); + &movups (&QWP(16*2,$out),$inout2); + &xorps ($inout4,&QWP(16*4,"esp")); + &movups (&QWP(16*3,$out),$inout3); + &xorps ($inout5,$tweak); + &movups (&QWP(16*4,$out),$inout4); + &pshufd ($twres,$twtmp,0x13); + &movups (&QWP(16*5,$out),$inout5); + &lea ($out,&DWP(16*6,$out)); + &movdqa ($twmask,&QWP(16*6,"esp")); # 0x0...010...87 + + &pxor ($twtmp,$twtmp); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + + &sub ($len,16*6); + &jnc (&label("xts_dec_loop6")); + + &mov ($rounds,&DWP(240,$key_)); # restore $rounds + &mov ($key,$key_); # restore $key + &mov ($rounds_,$rounds); + +&set_label("xts_dec_short"); + &add ($len,16*6); + &jz (&label("xts_dec_done6x")); + + &movdqa ($inout3,$tweak); # put aside previous tweak + &cmp ($len,0x20); + &jb (&label("xts_dec_one")); + + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + &je (&label("xts_dec_two")); + + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &movdqa ($inout4,$tweak); # put aside previous tweak + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + &cmp ($len,0x40); + &jb (&label("xts_dec_three")); + + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &movdqa ($inout5,$tweak); # put aside previous tweak + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + &movdqa (&QWP(16*0,"esp"),$inout3); + &movdqa (&QWP(16*1,"esp"),$inout4); + &je (&label("xts_dec_four")); + + &movdqa (&QWP(16*2,"esp"),$inout5); + &pshufd ($inout5,$twtmp,0x13); + &movdqa (&QWP(16*3,"esp"),$tweak); + &paddq ($tweak,$tweak); # &psllq($inout0,1); + &pand ($inout5,$twmask); # isolate carry and residue + &pxor ($inout5,$tweak); + + &movdqu ($inout0,&QWP(16*0,$inp)); # load input + &movdqu ($inout1,&QWP(16*1,$inp)); + &movdqu ($inout2,&QWP(16*2,$inp)); + &pxor ($inout0,&QWP(16*0,"esp")); # input^=tweak + &movdqu ($inout3,&QWP(16*3,$inp)); + &pxor ($inout1,&QWP(16*1,"esp")); + &movdqu ($inout4,&QWP(16*4,$inp)); + &pxor ($inout2,&QWP(16*2,"esp")); + &lea ($inp,&DWP(16*5,$inp)); + &pxor ($inout3,&QWP(16*3,"esp")); + &movdqa (&QWP(16*4,"esp"),$inout5); # save last tweak + &pxor ($inout4,$inout5); + + &call ("_aesni_decrypt6"); + + &movaps ($tweak,&QWP(16*4,"esp")); # last tweak + &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak + &xorps ($inout1,&QWP(16*1,"esp")); + &xorps ($inout2,&QWP(16*2,"esp")); + &movups (&QWP(16*0,$out),$inout0); # write output + &xorps ($inout3,&QWP(16*3,"esp")); + &movups (&QWP(16*1,$out),$inout1); + &xorps ($inout4,$tweak); + &movups (&QWP(16*2,$out),$inout2); + &movups (&QWP(16*3,$out),$inout3); + &movups (&QWP(16*4,$out),$inout4); + &lea ($out,&DWP(16*5,$out)); + &jmp (&label("xts_dec_done")); + +&set_label("xts_dec_one",16); + &movups ($inout0,&QWP(16*0,$inp)); # load input + &lea ($inp,&DWP(16*1,$inp)); + &xorps ($inout0,$inout3); # input^=tweak + if ($inline) + { &aesni_inline_generate1("dec"); } + else + { &call ("_aesni_decrypt1"); } + &xorps ($inout0,$inout3); # output^=tweak + &movups (&QWP(16*0,$out),$inout0); # write output + &lea ($out,&DWP(16*1,$out)); + + &movdqa ($tweak,$inout3); # last tweak + &jmp (&label("xts_dec_done")); + +&set_label("xts_dec_two",16); + &movaps ($inout4,$tweak); # put aside last tweak + + &movups ($inout0,&QWP(16*0,$inp)); # load input + &movups ($inout1,&QWP(16*1,$inp)); + &lea ($inp,&DWP(16*2,$inp)); + &xorps ($inout0,$inout3); # input^=tweak + &xorps ($inout1,$inout4); + + &call ("_aesni_decrypt2"); + + &xorps ($inout0,$inout3); # output^=tweak + &xorps ($inout1,$inout4); + &movups (&QWP(16*0,$out),$inout0); # write output + &movups (&QWP(16*1,$out),$inout1); + &lea ($out,&DWP(16*2,$out)); + + &movdqa ($tweak,$inout4); # last tweak + &jmp (&label("xts_dec_done")); + +&set_label("xts_dec_three",16); + &movaps ($inout5,$tweak); # put aside last tweak + &movups ($inout0,&QWP(16*0,$inp)); # load input + &movups ($inout1,&QWP(16*1,$inp)); + &movups ($inout2,&QWP(16*2,$inp)); + &lea ($inp,&DWP(16*3,$inp)); + &xorps ($inout0,$inout3); # input^=tweak + &xorps ($inout1,$inout4); + &xorps ($inout2,$inout5); + + &call ("_aesni_decrypt3"); + + &xorps ($inout0,$inout3); # output^=tweak + &xorps ($inout1,$inout4); + &xorps ($inout2,$inout5); + &movups (&QWP(16*0,$out),$inout0); # write output + &movups (&QWP(16*1,$out),$inout1); + &movups (&QWP(16*2,$out),$inout2); + &lea ($out,&DWP(16*3,$out)); + + &movdqa ($tweak,$inout5); # last tweak + &jmp (&label("xts_dec_done")); + +&set_label("xts_dec_four",16); + &movaps ($inout4,$tweak); # put aside last tweak + + &movups ($inout0,&QWP(16*0,$inp)); # load input + &movups ($inout1,&QWP(16*1,$inp)); + &movups ($inout2,&QWP(16*2,$inp)); + &xorps ($inout0,&QWP(16*0,"esp")); # input^=tweak + &movups ($inout3,&QWP(16*3,$inp)); + &lea ($inp,&DWP(16*4,$inp)); + &xorps ($inout1,&QWP(16*1,"esp")); + &xorps ($inout2,$inout5); + &xorps ($inout3,$inout4); + + &call ("_aesni_decrypt4"); + + &xorps ($inout0,&QWP(16*0,"esp")); # output^=tweak + &xorps ($inout1,&QWP(16*1,"esp")); + &xorps ($inout2,$inout5); + &movups (&QWP(16*0,$out),$inout0); # write output + &xorps ($inout3,$inout4); + &movups (&QWP(16*1,$out),$inout1); + &movups (&QWP(16*2,$out),$inout2); + &movups (&QWP(16*3,$out),$inout3); + &lea ($out,&DWP(16*4,$out)); + + &movdqa ($tweak,$inout4); # last tweak + &jmp (&label("xts_dec_done")); + +&set_label("xts_dec_done6x",16); # $tweak is pre-calculated + &mov ($len,&DWP(16*7+0,"esp")); # restore original $len + &and ($len,15); + &jz (&label("xts_dec_ret")); + &mov (&DWP(16*7+0,"esp"),$len); # save $len%16 + &jmp (&label("xts_dec_only_one_more")); + +&set_label("xts_dec_done",16); + &mov ($len,&DWP(16*7+0,"esp")); # restore original $len + &pxor ($twtmp,$twtmp); + &and ($len,15); + &jz (&label("xts_dec_ret")); + + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &mov (&DWP(16*7+0,"esp"),$len); # save $len%16 + &pshufd ($twres,$twtmp,0x13); + &pxor ($twtmp,$twtmp); + &movdqa ($twmask,&QWP(16*6,"esp")); + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($twres,$twmask); # isolate carry and residue + &pcmpgtd($twtmp,$tweak); # broadcast upper bits + &pxor ($tweak,$twres); + +&set_label("xts_dec_only_one_more"); + &pshufd ($inout3,$twtmp,0x13); + &movdqa ($inout4,$tweak); # put aside previous tweak + &paddq ($tweak,$tweak); # &psllq($tweak,1); + &pand ($inout3,$twmask); # isolate carry and residue + &pxor ($inout3,$tweak); + + &mov ($key,$key_); # restore $key + &mov ($rounds,$rounds_); # restore $rounds + + &movups ($inout0,&QWP(0,$inp)); # load input + &xorps ($inout0,$inout3); # input^=tweak + if ($inline) + { &aesni_inline_generate1("dec"); } + else + { &call ("_aesni_decrypt1"); } + &xorps ($inout0,$inout3); # output^=tweak + &movups (&QWP(0,$out),$inout0); # write output + +&set_label("xts_dec_steal"); + &movz ($rounds,&BP(16,$inp)); + &movz ($key,&BP(0,$out)); + &lea ($inp,&DWP(1,$inp)); + &mov (&BP(0,$out),&LB($rounds)); + &mov (&BP(16,$out),&LB($key)); + &lea ($out,&DWP(1,$out)); + &sub ($len,1); + &jnz (&label("xts_dec_steal")); + + &sub ($out,&DWP(16*7+0,"esp")); # rewind $out + &mov ($key,$key_); # restore $key + &mov ($rounds,$rounds_); # restore $rounds + + &movups ($inout0,&QWP(0,$out)); # load input + &xorps ($inout0,$inout4); # input^=tweak + if ($inline) + { &aesni_inline_generate1("dec"); } + else + { &call ("_aesni_decrypt1"); } + &xorps ($inout0,$inout4); # output^=tweak + &movups (&QWP(0,$out),$inout0); # write output + +&set_label("xts_dec_ret"); + &pxor ("xmm0","xmm0"); # clear register bank + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &movdqa (&QWP(16*0,"esp"),"xmm0"); # clear stack + &pxor ("xmm3","xmm3"); + &movdqa (&QWP(16*1,"esp"),"xmm0"); + &pxor ("xmm4","xmm4"); + &movdqa (&QWP(16*2,"esp"),"xmm0"); + &pxor ("xmm5","xmm5"); + &movdqa (&QWP(16*3,"esp"),"xmm0"); + &pxor ("xmm6","xmm6"); + &movdqa (&QWP(16*4,"esp"),"xmm0"); + &pxor ("xmm7","xmm7"); + &movdqa (&QWP(16*5,"esp"),"xmm0"); + &mov ("esp",&DWP(16*7+4,"esp")); # restore %esp +&function_end("aesni_xts_decrypt"); +} +} + +###################################################################### +# void $PREFIX_cbc_encrypt (const void *inp, void *out, +# size_t length, const AES_KEY *key, +# unsigned char *ivp,const int enc); +&function_begin("${PREFIX}_cbc_encrypt"); + &mov ($inp,&wparam(0)); + &mov ($rounds_,"esp"); + &mov ($out,&wparam(1)); + &sub ($rounds_,24); + &mov ($len,&wparam(2)); + &and ($rounds_,-16); + &mov ($key,&wparam(3)); + &mov ($key_,&wparam(4)); + &test ($len,$len); + &jz (&label("cbc_abort")); + + &cmp (&wparam(5),0); + &xchg ($rounds_,"esp"); # alloca + &movups ($ivec,&QWP(0,$key_)); # load IV + &mov ($rounds,&DWP(240,$key)); + &mov ($key_,$key); # backup $key + &mov (&DWP(16,"esp"),$rounds_); # save original %esp + &mov ($rounds_,$rounds); # backup $rounds + &je (&label("cbc_decrypt")); + + &movaps ($inout0,$ivec); + &cmp ($len,16); + &jb (&label("cbc_enc_tail")); + &sub ($len,16); + &jmp (&label("cbc_enc_loop")); + +&set_label("cbc_enc_loop",16); + &movups ($ivec,&QWP(0,$inp)); # input actually + &lea ($inp,&DWP(16,$inp)); + if ($inline) + { &aesni_inline_generate1("enc",$inout0,$ivec); } + else + { &xorps($inout0,$ivec); &call("_aesni_encrypt1"); } + &mov ($rounds,$rounds_); # restore $rounds + &mov ($key,$key_); # restore $key + &movups (&QWP(0,$out),$inout0); # store output + &lea ($out,&DWP(16,$out)); + &sub ($len,16); + &jnc (&label("cbc_enc_loop")); + &add ($len,16); + &jnz (&label("cbc_enc_tail")); + &movaps ($ivec,$inout0); + &pxor ($inout0,$inout0); + &jmp (&label("cbc_ret")); + +&set_label("cbc_enc_tail"); + &mov ("ecx",$len); # zaps $rounds + &data_word(0xA4F3F689); # rep movsb + &mov ("ecx",16); # zero tail + &sub ("ecx",$len); + &xor ("eax","eax"); # zaps $len + &data_word(0xAAF3F689); # rep stosb + &lea ($out,&DWP(-16,$out)); # rewind $out by 1 block + &mov ($rounds,$rounds_); # restore $rounds + &mov ($inp,$out); # $inp and $out are the same + &mov ($key,$key_); # restore $key + &jmp (&label("cbc_enc_loop")); +###################################################################### +&set_label("cbc_decrypt",16); + &cmp ($len,0x50); + &jbe (&label("cbc_dec_tail")); + &movaps (&QWP(0,"esp"),$ivec); # save IV + &sub ($len,0x50); + &jmp (&label("cbc_dec_loop6_enter")); + +&set_label("cbc_dec_loop6",16); + &movaps (&QWP(0,"esp"),$rndkey0); # save IV + &movups (&QWP(0,$out),$inout5); + &lea ($out,&DWP(0x10,$out)); +&set_label("cbc_dec_loop6_enter"); + &movdqu ($inout0,&QWP(0,$inp)); + &movdqu ($inout1,&QWP(0x10,$inp)); + &movdqu ($inout2,&QWP(0x20,$inp)); + &movdqu ($inout3,&QWP(0x30,$inp)); + &movdqu ($inout4,&QWP(0x40,$inp)); + &movdqu ($inout5,&QWP(0x50,$inp)); + + &call ("_aesni_decrypt6"); + + &movups ($rndkey1,&QWP(0,$inp)); + &movups ($rndkey0,&QWP(0x10,$inp)); + &xorps ($inout0,&QWP(0,"esp")); # ^=IV + &xorps ($inout1,$rndkey1); + &movups ($rndkey1,&QWP(0x20,$inp)); + &xorps ($inout2,$rndkey0); + &movups ($rndkey0,&QWP(0x30,$inp)); + &xorps ($inout3,$rndkey1); + &movups ($rndkey1,&QWP(0x40,$inp)); + &xorps ($inout4,$rndkey0); + &movups ($rndkey0,&QWP(0x50,$inp)); # IV + &xorps ($inout5,$rndkey1); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &lea ($inp,&DWP(0x60,$inp)); + &movups (&QWP(0x20,$out),$inout2); + &mov ($rounds,$rounds_); # restore $rounds + &movups (&QWP(0x30,$out),$inout3); + &mov ($key,$key_); # restore $key + &movups (&QWP(0x40,$out),$inout4); + &lea ($out,&DWP(0x50,$out)); + &sub ($len,0x60); + &ja (&label("cbc_dec_loop6")); + + &movaps ($inout0,$inout5); + &movaps ($ivec,$rndkey0); + &add ($len,0x50); + &jle (&label("cbc_dec_clear_tail_collected")); + &movups (&QWP(0,$out),$inout0); + &lea ($out,&DWP(0x10,$out)); +&set_label("cbc_dec_tail"); + &movups ($inout0,&QWP(0,$inp)); + &movaps ($in0,$inout0); + &cmp ($len,0x10); + &jbe (&label("cbc_dec_one")); + + &movups ($inout1,&QWP(0x10,$inp)); + &movaps ($in1,$inout1); + &cmp ($len,0x20); + &jbe (&label("cbc_dec_two")); + + &movups ($inout2,&QWP(0x20,$inp)); + &cmp ($len,0x30); + &jbe (&label("cbc_dec_three")); + + &movups ($inout3,&QWP(0x30,$inp)); + &cmp ($len,0x40); + &jbe (&label("cbc_dec_four")); + + &movups ($inout4,&QWP(0x40,$inp)); + &movaps (&QWP(0,"esp"),$ivec); # save IV + &movups ($inout0,&QWP(0,$inp)); + &xorps ($inout5,$inout5); + &call ("_aesni_decrypt6"); + &movups ($rndkey1,&QWP(0,$inp)); + &movups ($rndkey0,&QWP(0x10,$inp)); + &xorps ($inout0,&QWP(0,"esp")); # ^= IV + &xorps ($inout1,$rndkey1); + &movups ($rndkey1,&QWP(0x20,$inp)); + &xorps ($inout2,$rndkey0); + &movups ($rndkey0,&QWP(0x30,$inp)); + &xorps ($inout3,$rndkey1); + &movups ($ivec,&QWP(0x40,$inp)); # IV + &xorps ($inout4,$rndkey0); + &movups (&QWP(0,$out),$inout0); + &movups (&QWP(0x10,$out),$inout1); + &pxor ($inout1,$inout1); + &movups (&QWP(0x20,$out),$inout2); + &pxor ($inout2,$inout2); + &movups (&QWP(0x30,$out),$inout3); + &pxor ($inout3,$inout3); + &lea ($out,&DWP(0x40,$out)); + &movaps ($inout0,$inout4); + &pxor ($inout4,$inout4); + &sub ($len,0x50); + &jmp (&label("cbc_dec_tail_collected")); + +&set_label("cbc_dec_one",16); + if ($inline) + { &aesni_inline_generate1("dec"); } + else + { &call ("_aesni_decrypt1"); } + &xorps ($inout0,$ivec); + &movaps ($ivec,$in0); + &sub ($len,0x10); + &jmp (&label("cbc_dec_tail_collected")); + +&set_label("cbc_dec_two",16); + &call ("_aesni_decrypt2"); + &xorps ($inout0,$ivec); + &xorps ($inout1,$in0); + &movups (&QWP(0,$out),$inout0); + &movaps ($inout0,$inout1); + &pxor ($inout1,$inout1); + &lea ($out,&DWP(0x10,$out)); + &movaps ($ivec,$in1); + &sub ($len,0x20); + &jmp (&label("cbc_dec_tail_collected")); + +&set_label("cbc_dec_three",16); + &call ("_aesni_decrypt3"); + &xorps ($inout0,$ivec); + &xorps ($inout1,$in0); + &xorps ($inout2,$in1); + &movups (&QWP(0,$out),$inout0); + &movaps ($inout0,$inout2); + &pxor ($inout2,$inout2); + &movups (&QWP(0x10,$out),$inout1); + &pxor ($inout1,$inout1); + &lea ($out,&DWP(0x20,$out)); + &movups ($ivec,&QWP(0x20,$inp)); + &sub ($len,0x30); + &jmp (&label("cbc_dec_tail_collected")); + +&set_label("cbc_dec_four",16); + &call ("_aesni_decrypt4"); + &movups ($rndkey1,&QWP(0x10,$inp)); + &movups ($rndkey0,&QWP(0x20,$inp)); + &xorps ($inout0,$ivec); + &movups ($ivec,&QWP(0x30,$inp)); + &xorps ($inout1,$in0); + &movups (&QWP(0,$out),$inout0); + &xorps ($inout2,$rndkey1); + &movups (&QWP(0x10,$out),$inout1); + &pxor ($inout1,$inout1); + &xorps ($inout3,$rndkey0); + &movups (&QWP(0x20,$out),$inout2); + &pxor ($inout2,$inout2); + &lea ($out,&DWP(0x30,$out)); + &movaps ($inout0,$inout3); + &pxor ($inout3,$inout3); + &sub ($len,0x40); + &jmp (&label("cbc_dec_tail_collected")); + +&set_label("cbc_dec_clear_tail_collected",16); + &pxor ($inout1,$inout1); + &pxor ($inout2,$inout2); + &pxor ($inout3,$inout3); + &pxor ($inout4,$inout4); +&set_label("cbc_dec_tail_collected"); + &and ($len,15); + &jnz (&label("cbc_dec_tail_partial")); + &movups (&QWP(0,$out),$inout0); + &pxor ($rndkey0,$rndkey0); + &jmp (&label("cbc_ret")); + +&set_label("cbc_dec_tail_partial",16); + &movaps (&QWP(0,"esp"),$inout0); + &pxor ($rndkey0,$rndkey0); + &mov ("ecx",16); + &mov ($inp,"esp"); + &sub ("ecx",$len); + &data_word(0xA4F3F689); # rep movsb + &movdqa (&QWP(0,"esp"),$inout0); + +&set_label("cbc_ret"); + &mov ("esp",&DWP(16,"esp")); # pull original %esp + &mov ($key_,&wparam(4)); + &pxor ($inout0,$inout0); + &pxor ($rndkey1,$rndkey1); + &movups (&QWP(0,$key_),$ivec); # output IV + &pxor ($ivec,$ivec); +&set_label("cbc_abort"); +&function_end("${PREFIX}_cbc_encrypt"); + +###################################################################### +# Mechanical port from aesni-x86_64.pl. +# +# _aesni_set_encrypt_key is private interface, +# input: +# "eax" const unsigned char *userKey +# $rounds int bits +# $key AES_KEY *key +# output: +# "eax" return code +# $round rounds + +&function_begin_B("_aesni_set_encrypt_key"); + &push ("ebp"); + &push ("ebx"); + &test ("eax","eax"); + &jz (&label("bad_pointer")); + &test ($key,$key); + &jz (&label("bad_pointer")); + + &call (&label("pic")); +&set_label("pic"); + &blindpop("ebx"); + &lea ("ebx",&DWP(&label("key_const")."-".&label("pic"),"ebx")); + + &picmeup("ebp","OPENSSL_ia32cap_P","ebx",&label("key_const")); + &movups ("xmm0",&QWP(0,"eax")); # pull first 128 bits of *userKey + &xorps ("xmm4","xmm4"); # low dword of xmm4 is assumed 0 + &mov ("ebp",&DWP(4,"ebp")); + &lea ($key,&DWP(16,$key)); + &and ("ebp",1<<28|1<<11); # AVX and XOP bits + &cmp ($rounds,256); + &je (&label("14rounds")); + &cmp ($rounds,192); + &je (&label("12rounds")); + &cmp ($rounds,128); + &jne (&label("bad_keybits")); + +&set_label("10rounds",16); + &cmp ("ebp",1<<28); + &je (&label("10rounds_alt")); + + &mov ($rounds,9); + &$movekey (&QWP(-16,$key),"xmm0"); # round 0 + &aeskeygenassist("xmm1","xmm0",0x01); # round 1 + &call (&label("key_128_cold")); + &aeskeygenassist("xmm1","xmm0",0x2); # round 2 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x04); # round 3 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x08); # round 4 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x10); # round 5 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x20); # round 6 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x40); # round 7 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x80); # round 8 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x1b); # round 9 + &call (&label("key_128")); + &aeskeygenassist("xmm1","xmm0",0x36); # round 10 + &call (&label("key_128")); + &$movekey (&QWP(0,$key),"xmm0"); + &mov (&DWP(80,$key),$rounds); + + &jmp (&label("good_key")); + +&set_label("key_128",16); + &$movekey (&QWP(0,$key),"xmm0"); + &lea ($key,&DWP(16,$key)); +&set_label("key_128_cold"); + &shufps ("xmm4","xmm0",0b00010000); + &xorps ("xmm0","xmm4"); + &shufps ("xmm4","xmm0",0b10001100); + &xorps ("xmm0","xmm4"); + &shufps ("xmm1","xmm1",0b11111111); # critical path + &xorps ("xmm0","xmm1"); + &ret(); + +&set_label("10rounds_alt",16); + &movdqa ("xmm5",&QWP(0x00,"ebx")); + &mov ($rounds,8); + &movdqa ("xmm4",&QWP(0x20,"ebx")); + &movdqa ("xmm2","xmm0"); + &movdqu (&QWP(-16,$key),"xmm0"); + +&set_label("loop_key128"); + &pshufb ("xmm0","xmm5"); + &aesenclast ("xmm0","xmm4"); + &pslld ("xmm4",1); + &lea ($key,&DWP(16,$key)); + + &movdqa ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm2","xmm3"); + + &pxor ("xmm0","xmm2"); + &movdqu (&QWP(-16,$key),"xmm0"); + &movdqa ("xmm2","xmm0"); + + &dec ($rounds); + &jnz (&label("loop_key128")); + + &movdqa ("xmm4",&QWP(0x30,"ebx")); + + &pshufb ("xmm0","xmm5"); + &aesenclast ("xmm0","xmm4"); + &pslld ("xmm4",1); + + &movdqa ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm2","xmm3"); + + &pxor ("xmm0","xmm2"); + &movdqu (&QWP(0,$key),"xmm0"); + + &movdqa ("xmm2","xmm0"); + &pshufb ("xmm0","xmm5"); + &aesenclast ("xmm0","xmm4"); + + &movdqa ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm3","xmm2"); + &pslldq ("xmm2",4); + &pxor ("xmm2","xmm3"); + + &pxor ("xmm0","xmm2"); + &movdqu (&QWP(16,$key),"xmm0"); + + &mov ($rounds,9); + &mov (&DWP(96,$key),$rounds); + + &jmp (&label("good_key")); + +&set_label("12rounds",16); + &movq ("xmm2",&QWP(16,"eax")); # remaining 1/3 of *userKey + &cmp ("ebp",1<<28); + &je (&label("12rounds_alt")); + + &mov ($rounds,11); + &$movekey (&QWP(-16,$key),"xmm0"); # round 0 + &aeskeygenassist("xmm1","xmm2",0x01); # round 1,2 + &call (&label("key_192a_cold")); + &aeskeygenassist("xmm1","xmm2",0x02); # round 2,3 + &call (&label("key_192b")); + &aeskeygenassist("xmm1","xmm2",0x04); # round 4,5 + &call (&label("key_192a")); + &aeskeygenassist("xmm1","xmm2",0x08); # round 5,6 + &call (&label("key_192b")); + &aeskeygenassist("xmm1","xmm2",0x10); # round 7,8 + &call (&label("key_192a")); + &aeskeygenassist("xmm1","xmm2",0x20); # round 8,9 + &call (&label("key_192b")); + &aeskeygenassist("xmm1","xmm2",0x40); # round 10,11 + &call (&label("key_192a")); + &aeskeygenassist("xmm1","xmm2",0x80); # round 11,12 + &call (&label("key_192b")); + &$movekey (&QWP(0,$key),"xmm0"); + &mov (&DWP(48,$key),$rounds); + + &jmp (&label("good_key")); + +&set_label("key_192a",16); + &$movekey (&QWP(0,$key),"xmm0"); + &lea ($key,&DWP(16,$key)); +&set_label("key_192a_cold",16); + &movaps ("xmm5","xmm2"); +&set_label("key_192b_warm"); + &shufps ("xmm4","xmm0",0b00010000); + &movdqa ("xmm3","xmm2"); + &xorps ("xmm0","xmm4"); + &shufps ("xmm4","xmm0",0b10001100); + &pslldq ("xmm3",4); + &xorps ("xmm0","xmm4"); + &pshufd ("xmm1","xmm1",0b01010101); # critical path + &pxor ("xmm2","xmm3"); + &pxor ("xmm0","xmm1"); + &pshufd ("xmm3","xmm0",0b11111111); + &pxor ("xmm2","xmm3"); + &ret(); + +&set_label("key_192b",16); + &movaps ("xmm3","xmm0"); + &shufps ("xmm5","xmm0",0b01000100); + &$movekey (&QWP(0,$key),"xmm5"); + &shufps ("xmm3","xmm2",0b01001110); + &$movekey (&QWP(16,$key),"xmm3"); + &lea ($key,&DWP(32,$key)); + &jmp (&label("key_192b_warm")); + +&set_label("12rounds_alt",16); + &movdqa ("xmm5",&QWP(0x10,"ebx")); + &movdqa ("xmm4",&QWP(0x20,"ebx")); + &mov ($rounds,8); + &movdqu (&QWP(-16,$key),"xmm0"); + +&set_label("loop_key192"); + &movq (&QWP(0,$key),"xmm2"); + &movdqa ("xmm1","xmm2"); + &pshufb ("xmm2","xmm5"); + &aesenclast ("xmm2","xmm4"); + &pslld ("xmm4",1); + &lea ($key,&DWP(24,$key)); + + &movdqa ("xmm3","xmm0"); + &pslldq ("xmm0",4); + &pxor ("xmm3","xmm0"); + &pslldq ("xmm0",4); + &pxor ("xmm3","xmm0"); + &pslldq ("xmm0",4); + &pxor ("xmm0","xmm3"); + + &pshufd ("xmm3","xmm0",0xff); + &pxor ("xmm3","xmm1"); + &pslldq ("xmm1",4); + &pxor ("xmm3","xmm1"); + + &pxor ("xmm0","xmm2"); + &pxor ("xmm2","xmm3"); + &movdqu (&QWP(-16,$key),"xmm0"); + + &dec ($rounds); + &jnz (&label("loop_key192")); + + &mov ($rounds,11); + &mov (&DWP(32,$key),$rounds); + + &jmp (&label("good_key")); + +&set_label("14rounds",16); + &movups ("xmm2",&QWP(16,"eax")); # remaining half of *userKey + &lea ($key,&DWP(16,$key)); + &cmp ("ebp",1<<28); + &je (&label("14rounds_alt")); + + &mov ($rounds,13); + &$movekey (&QWP(-32,$key),"xmm0"); # round 0 + &$movekey (&QWP(-16,$key),"xmm2"); # round 1 + &aeskeygenassist("xmm1","xmm2",0x01); # round 2 + &call (&label("key_256a_cold")); + &aeskeygenassist("xmm1","xmm0",0x01); # round 3 + &call (&label("key_256b")); + &aeskeygenassist("xmm1","xmm2",0x02); # round 4 + &call (&label("key_256a")); + &aeskeygenassist("xmm1","xmm0",0x02); # round 5 + &call (&label("key_256b")); + &aeskeygenassist("xmm1","xmm2",0x04); # round 6 + &call (&label("key_256a")); + &aeskeygenassist("xmm1","xmm0",0x04); # round 7 + &call (&label("key_256b")); + &aeskeygenassist("xmm1","xmm2",0x08); # round 8 + &call (&label("key_256a")); + &aeskeygenassist("xmm1","xmm0",0x08); # round 9 + &call (&label("key_256b")); + &aeskeygenassist("xmm1","xmm2",0x10); # round 10 + &call (&label("key_256a")); + &aeskeygenassist("xmm1","xmm0",0x10); # round 11 + &call (&label("key_256b")); + &aeskeygenassist("xmm1","xmm2",0x20); # round 12 + &call (&label("key_256a")); + &aeskeygenassist("xmm1","xmm0",0x20); # round 13 + &call (&label("key_256b")); + &aeskeygenassist("xmm1","xmm2",0x40); # round 14 + &call (&label("key_256a")); + &$movekey (&QWP(0,$key),"xmm0"); + &mov (&DWP(16,$key),$rounds); + &xor ("eax","eax"); + + &jmp (&label("good_key")); + +&set_label("key_256a",16); + &$movekey (&QWP(0,$key),"xmm2"); + &lea ($key,&DWP(16,$key)); +&set_label("key_256a_cold"); + &shufps ("xmm4","xmm0",0b00010000); + &xorps ("xmm0","xmm4"); + &shufps ("xmm4","xmm0",0b10001100); + &xorps ("xmm0","xmm4"); + &shufps ("xmm1","xmm1",0b11111111); # critical path + &xorps ("xmm0","xmm1"); + &ret(); + +&set_label("key_256b",16); + &$movekey (&QWP(0,$key),"xmm0"); + &lea ($key,&DWP(16,$key)); + + &shufps ("xmm4","xmm2",0b00010000); + &xorps ("xmm2","xmm4"); + &shufps ("xmm4","xmm2",0b10001100); + &xorps ("xmm2","xmm4"); + &shufps ("xmm1","xmm1",0b10101010); # critical path + &xorps ("xmm2","xmm1"); + &ret(); + +&set_label("14rounds_alt",16); + &movdqa ("xmm5",&QWP(0x00,"ebx")); + &movdqa ("xmm4",&QWP(0x20,"ebx")); + &mov ($rounds,7); + &movdqu (&QWP(-32,$key),"xmm0"); + &movdqa ("xmm1","xmm2"); + &movdqu (&QWP(-16,$key),"xmm2"); + +&set_label("loop_key256"); + &pshufb ("xmm2","xmm5"); + &aesenclast ("xmm2","xmm4"); + + &movdqa ("xmm3","xmm0"); + &pslldq ("xmm0",4); + &pxor ("xmm3","xmm0"); + &pslldq ("xmm0",4); + &pxor ("xmm3","xmm0"); + &pslldq ("xmm0",4); + &pxor ("xmm0","xmm3"); + &pslld ("xmm4",1); + + &pxor ("xmm0","xmm2"); + &movdqu (&QWP(0,$key),"xmm0"); + + &dec ($rounds); + &jz (&label("done_key256")); + + &pshufd ("xmm2","xmm0",0xff); + &pxor ("xmm3","xmm3"); + &aesenclast ("xmm2","xmm3"); + + &movdqa ("xmm3","xmm1") + &pslldq ("xmm1",4); + &pxor ("xmm3","xmm1"); + &pslldq ("xmm1",4); + &pxor ("xmm3","xmm1"); + &pslldq ("xmm1",4); + &pxor ("xmm1","xmm3"); + + &pxor ("xmm2","xmm1"); + &movdqu (&QWP(16,$key),"xmm2"); + &lea ($key,&DWP(32,$key)); + &movdqa ("xmm1","xmm2"); + &jmp (&label("loop_key256")); + +&set_label("done_key256"); + &mov ($rounds,13); + &mov (&DWP(16,$key),$rounds); + +&set_label("good_key"); + &pxor ("xmm0","xmm0"); + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &pxor ("xmm3","xmm3"); + &pxor ("xmm4","xmm4"); + &pxor ("xmm5","xmm5"); + &xor ("eax","eax"); + &pop ("ebx"); + &pop ("ebp"); + &ret (); + +&set_label("bad_pointer",4); + &mov ("eax",-1); + &pop ("ebx"); + &pop ("ebp"); + &ret (); +&set_label("bad_keybits",4); + &pxor ("xmm0","xmm0"); + &mov ("eax",-2); + &pop ("ebx"); + &pop ("ebp"); + &ret (); +&function_end_B("_aesni_set_encrypt_key"); + +# int $PREFIX_set_encrypt_key (const unsigned char *userKey, int bits, +# AES_KEY *key) +&function_begin_B("${PREFIX}_set_encrypt_key"); + &mov ("eax",&wparam(0)); + &mov ($rounds,&wparam(1)); + &mov ($key,&wparam(2)); + &call ("_aesni_set_encrypt_key"); + &ret (); +&function_end_B("${PREFIX}_set_encrypt_key"); + +# int $PREFIX_set_decrypt_key (const unsigned char *userKey, int bits, +# AES_KEY *key) +&function_begin_B("${PREFIX}_set_decrypt_key"); + &mov ("eax",&wparam(0)); + &mov ($rounds,&wparam(1)); + &mov ($key,&wparam(2)); + &call ("_aesni_set_encrypt_key"); + &mov ($key,&wparam(2)); + &shl ($rounds,4); # rounds-1 after _aesni_set_encrypt_key + &test ("eax","eax"); + &jnz (&label("dec_key_ret")); + &lea ("eax",&DWP(16,$key,$rounds)); # end of key schedule + + &$movekey ("xmm0",&QWP(0,$key)); # just swap + &$movekey ("xmm1",&QWP(0,"eax")); + &$movekey (&QWP(0,"eax"),"xmm0"); + &$movekey (&QWP(0,$key),"xmm1"); + &lea ($key,&DWP(16,$key)); + &lea ("eax",&DWP(-16,"eax")); + +&set_label("dec_key_inverse"); + &$movekey ("xmm0",&QWP(0,$key)); # swap and inverse + &$movekey ("xmm1",&QWP(0,"eax")); + &aesimc ("xmm0","xmm0"); + &aesimc ("xmm1","xmm1"); + &lea ($key,&DWP(16,$key)); + &lea ("eax",&DWP(-16,"eax")); + &$movekey (&QWP(16,"eax"),"xmm0"); + &$movekey (&QWP(-16,$key),"xmm1"); + &cmp ("eax",$key); + &ja (&label("dec_key_inverse")); + + &$movekey ("xmm0",&QWP(0,$key)); # inverse middle + &aesimc ("xmm0","xmm0"); + &$movekey (&QWP(0,$key),"xmm0"); + + &pxor ("xmm0","xmm0"); + &pxor ("xmm1","xmm1"); + &xor ("eax","eax"); # return success +&set_label("dec_key_ret"); + &ret (); +&function_end_B("${PREFIX}_set_decrypt_key"); + +&set_label("key_const",64); +&data_word(0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d); +&data_word(0x04070605,0x04070605,0x04070605,0x04070605); +&data_word(1,1,1,1); +&data_word(0x1b,0x1b,0x1b,0x1b); +&asciz("AES for Intel AES-NI, CRYPTOGAMS by "); + +&asm_finish(); diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/aesni-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/aesni-x86_64.pl new file mode 100644 index 00000000..25ca574f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/aesni-x86_64.pl @@ -0,0 +1,4048 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# This module implements support for Intel AES-NI extension. In +# OpenSSL context it's used with Intel engine, but can also be used as +# drop-in replacement for crypto/aes/asm/aes-x86_64.pl [see below for +# details]. +# +# Performance. +# +# Given aes(enc|dec) instructions' latency asymptotic performance for +# non-parallelizable modes such as CBC encrypt is 3.75 cycles per byte +# processed with 128-bit key. And given their throughput asymptotic +# performance for parallelizable modes is 1.25 cycles per byte. Being +# asymptotic limit it's not something you commonly achieve in reality, +# but how close does one get? Below are results collected for +# different modes and block sized. Pairs of numbers are for en-/ +# decryption. +# +# 16-byte 64-byte 256-byte 1-KB 8-KB +# ECB 4.25/4.25 1.38/1.38 1.28/1.28 1.26/1.26 1.26/1.26 +# CTR 5.42/5.42 1.92/1.92 1.44/1.44 1.28/1.28 1.26/1.26 +# CBC 4.38/4.43 4.15/1.43 4.07/1.32 4.07/1.29 4.06/1.28 +# CCM 5.66/9.42 4.42/5.41 4.16/4.40 4.09/4.15 4.06/4.07 +# OFB 5.42/5.42 4.64/4.64 4.44/4.44 4.39/4.39 4.38/4.38 +# CFB 5.73/5.85 5.56/5.62 5.48/5.56 5.47/5.55 5.47/5.55 +# +# ECB, CTR, CBC and CCM results are free from EVP overhead. This means +# that otherwise used 'openssl speed -evp aes-128-??? -engine aesni +# [-decrypt]' will exhibit 10-15% worse results for smaller blocks. +# The results were collected with specially crafted speed.c benchmark +# in order to compare them with results reported in "Intel Advanced +# Encryption Standard (AES) New Instruction Set" White Paper Revision +# 3.0 dated May 2010. All above results are consistently better. This +# module also provides better performance for block sizes smaller than +# 128 bytes in points *not* represented in the above table. +# +# Looking at the results for 8-KB buffer. +# +# CFB and OFB results are far from the limit, because implementation +# uses "generic" CRYPTO_[c|o]fb128_encrypt interfaces relying on +# single-block aesni_encrypt, which is not the most optimal way to go. +# CBC encrypt result is unexpectedly high and there is no documented +# explanation for it. Seemingly there is a small penalty for feeding +# the result back to AES unit the way it's done in CBC mode. There is +# nothing one can do and the result appears optimal. CCM result is +# identical to CBC, because CBC-MAC is essentially CBC encrypt without +# saving output. CCM CTR "stays invisible," because it's neatly +# interleaved wih CBC-MAC. This provides ~30% improvement over +# "straghtforward" CCM implementation with CTR and CBC-MAC performed +# disjointly. Parallelizable modes practically achieve the theoretical +# limit. +# +# Looking at how results vary with buffer size. +# +# Curves are practically saturated at 1-KB buffer size. In most cases +# "256-byte" performance is >95%, and "64-byte" is ~90% of "8-KB" one. +# CTR curve doesn't follow this pattern and is "slowest" changing one +# with "256-byte" result being 87% of "8-KB." This is because overhead +# in CTR mode is most computationally intensive. Small-block CCM +# decrypt is slower than encrypt, because first CTR and last CBC-MAC +# iterations can't be interleaved. +# +# Results for 192- and 256-bit keys. +# +# EVP-free results were observed to scale perfectly with number of +# rounds for larger block sizes, i.e. 192-bit result being 10/12 times +# lower and 256-bit one - 10/14. Well, in CBC encrypt case differences +# are a tad smaller, because the above mentioned penalty biases all +# results by same constant value. In similar way function call +# overhead affects small-block performance, as well as OFB and CFB +# results. Differences are not large, most common coefficients are +# 10/11.7 and 10/13.4 (as opposite to 10/12.0 and 10/14.0), but one +# observe even 10/11.2 and 10/12.4 (CTR, OFB, CFB)... + +# January 2011 +# +# While Westmere processor features 6 cycles latency for aes[enc|dec] +# instructions, which can be scheduled every second cycle, Sandy +# Bridge spends 8 cycles per instruction, but it can schedule them +# every cycle. This means that code targeting Westmere would perform +# suboptimally on Sandy Bridge. Therefore this update. +# +# In addition, non-parallelizable CBC encrypt (as well as CCM) is +# optimized. Relative improvement might appear modest, 8% on Westmere, +# but in absolute terms it's 3.77 cycles per byte encrypted with +# 128-bit key on Westmere, and 5.07 - on Sandy Bridge. These numbers +# should be compared to asymptotic limits of 3.75 for Westmere and +# 5.00 for Sandy Bridge. Actually, the fact that they get this close +# to asymptotic limits is quite amazing. Indeed, the limit is +# calculated as latency times number of rounds, 10 for 128-bit key, +# and divided by 16, the number of bytes in block, or in other words +# it accounts *solely* for aesenc instructions. But there are extra +# instructions, and numbers so close to the asymptotic limits mean +# that it's as if it takes as little as *one* additional cycle to +# execute all of them. How is it possible? It is possible thanks to +# out-of-order execution logic, which manages to overlap post- +# processing of previous block, things like saving the output, with +# actual encryption of current block, as well as pre-processing of +# current block, things like fetching input and xor-ing it with +# 0-round element of the key schedule, with actual encryption of +# previous block. Keep this in mind... +# +# For parallelizable modes, such as ECB, CBC decrypt, CTR, higher +# performance is achieved by interleaving instructions working on +# independent blocks. In which case asymptotic limit for such modes +# can be obtained by dividing above mentioned numbers by AES +# instructions' interleave factor. Westmere can execute at most 3 +# instructions at a time, meaning that optimal interleave factor is 3, +# and that's where the "magic" number of 1.25 come from. "Optimal +# interleave factor" means that increase of interleave factor does +# not improve performance. The formula has proven to reflect reality +# pretty well on Westmere... Sandy Bridge on the other hand can +# execute up to 8 AES instructions at a time, so how does varying +# interleave factor affect the performance? Here is table for ECB +# (numbers are cycles per byte processed with 128-bit key): +# +# instruction interleave factor 3x 6x 8x +# theoretical asymptotic limit 1.67 0.83 0.625 +# measured performance for 8KB block 1.05 0.86 0.84 +# +# "as if" interleave factor 4.7x 5.8x 6.0x +# +# Further data for other parallelizable modes: +# +# CBC decrypt 1.16 0.93 0.74 +# CTR 1.14 0.91 0.74 +# +# Well, given 3x column it's probably inappropriate to call the limit +# asymptotic, if it can be surpassed, isn't it? What happens there? +# Rewind to CBC paragraph for the answer. Yes, out-of-order execution +# magic is responsible for this. Processor overlaps not only the +# additional instructions with AES ones, but even AES instuctions +# processing adjacent triplets of independent blocks. In the 6x case +# additional instructions still claim disproportionally small amount +# of additional cycles, but in 8x case number of instructions must be +# a tad too high for out-of-order logic to cope with, and AES unit +# remains underutilized... As you can see 8x interleave is hardly +# justifiable, so there no need to feel bad that 32-bit aesni-x86.pl +# utilizies 6x interleave because of limited register bank capacity. +# +# Higher interleave factors do have negative impact on Westmere +# performance. While for ECB mode it's negligible ~1.5%, other +# parallelizables perform ~5% worse, which is outweighed by ~25% +# improvement on Sandy Bridge. To balance regression on Westmere +# CTR mode was implemented with 6x aesenc interleave factor. + +# April 2011 +# +# Add aesni_xts_[en|de]crypt. Westmere spends 1.25 cycles processing +# one byte out of 8KB with 128-bit key, Sandy Bridge - 0.90. Just like +# in CTR mode AES instruction interleave factor was chosen to be 6x. + +###################################################################### +# Current large-block performance in cycles per byte processed with +# 128-bit key (less is better). +# +# CBC en-/decrypt CTR XTS ECB +# Westmere 3.77/1.25 1.25 1.25 1.26 +# * Bridge 5.07/0.74 0.75 0.90 0.85 +# Haswell 4.44/0.63 0.63 0.73 0.63 +# Silvermont 5.75/3.54 3.56 4.12 3.87(*) +# Bulldozer 5.77/0.70 0.72 0.90 0.70 +# +# (*) Atom Silvermont ECB result is suboptimal because of penalties +# incurred by operations on %xmm8-15. As ECB is not considered +# critical, nothing was done to mitigate the problem. + +$PREFIX="aesni"; # if $PREFIX is set to "AES", the script + # generates drop-in replacement for + # crypto/aes/asm/aes-x86_64.pl:-) + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$movkey = $PREFIX eq "aesni" ? "movups" : "movups"; +@_4args=$win64? ("%rcx","%rdx","%r8", "%r9") : # Win64 order + ("%rdi","%rsi","%rdx","%rcx"); # Unix order + +$code=".text\n"; +$code.=".extern OPENSSL_ia32cap_P\n"; + +$rounds="%eax"; # input to and changed by aesni_[en|de]cryptN !!! +# this is natural Unix argument order for public $PREFIX_[ecb|cbc]_encrypt ... +$inp="%rdi"; +$out="%rsi"; +$len="%rdx"; +$key="%rcx"; # input to and changed by aesni_[en|de]cryptN !!! +$ivp="%r8"; # cbc, ctr, ... + +$rnds_="%r10d"; # backup copy for $rounds +$key_="%r11"; # backup copy for $key + +# %xmm register layout +$rndkey0="%xmm0"; $rndkey1="%xmm1"; +$inout0="%xmm2"; $inout1="%xmm3"; +$inout2="%xmm4"; $inout3="%xmm5"; +$inout4="%xmm6"; $inout5="%xmm7"; +$inout6="%xmm8"; $inout7="%xmm9"; + +$in2="%xmm6"; $in1="%xmm7"; # used in CBC decrypt, CTR, ... +$in0="%xmm8"; $iv="%xmm9"; + +# Inline version of internal aesni_[en|de]crypt1. +# +# Why folded loop? Because aes[enc|dec] is slow enough to accommodate +# cycles which take care of loop variables... +{ my $sn; +sub aesni_generate1 { +my ($p,$key,$rounds,$inout,$ivec)=@_; $inout=$inout0 if (!defined($inout)); +++$sn; +$code.=<<___; + $movkey ($key),$rndkey0 + $movkey 16($key),$rndkey1 +___ +$code.=<<___ if (defined($ivec)); + xorps $rndkey0,$ivec + lea 32($key),$key + xorps $ivec,$inout +___ +$code.=<<___ if (!defined($ivec)); + lea 32($key),$key + xorps $rndkey0,$inout +___ +$code.=<<___; +.Loop_${p}1_$sn: + aes${p} $rndkey1,$inout + dec $rounds + $movkey ($key),$rndkey1 + lea 16($key),$key + jnz .Loop_${p}1_$sn # loop body is 16 bytes + aes${p}last $rndkey1,$inout +___ +}} +# void $PREFIX_[en|de]crypt (const void *inp,void *out,const AES_KEY *key); +# +{ my ($inp,$out,$key) = @_4args; + +$code.=<<___; +.globl ${PREFIX}_encrypt +.type ${PREFIX}_encrypt,\@abi-omnipotent +.align 16 +${PREFIX}_encrypt: + movups ($inp),$inout0 # load input + mov 240($key),$rounds # key->rounds +___ + &aesni_generate1("enc",$key,$rounds); +$code.=<<___; + pxor $rndkey0,$rndkey0 # clear register bank + pxor $rndkey1,$rndkey1 + movups $inout0,($out) # output + pxor $inout0,$inout0 + ret +.size ${PREFIX}_encrypt,.-${PREFIX}_encrypt + +.globl ${PREFIX}_decrypt +.type ${PREFIX}_decrypt,\@abi-omnipotent +.align 16 +${PREFIX}_decrypt: + movups ($inp),$inout0 # load input + mov 240($key),$rounds # key->rounds +___ + &aesni_generate1("dec",$key,$rounds); +$code.=<<___; + pxor $rndkey0,$rndkey0 # clear register bank + pxor $rndkey1,$rndkey1 + movups $inout0,($out) # output + pxor $inout0,$inout0 + ret +.size ${PREFIX}_decrypt, .-${PREFIX}_decrypt +___ +} + +# _aesni_[en|de]cryptN are private interfaces, N denotes interleave +# factor. Why 3x subroutine were originally used in loops? Even though +# aes[enc|dec] latency was originally 6, it could be scheduled only +# every *2nd* cycle. Thus 3x interleave was the one providing optimal +# utilization, i.e. when subroutine's throughput is virtually same as +# of non-interleaved subroutine [for number of input blocks up to 3]. +# This is why it originally made no sense to implement 2x subroutine. +# But times change and it became appropriate to spend extra 192 bytes +# on 2x subroutine on Atom Silvermont account. For processors that +# can schedule aes[enc|dec] every cycle optimal interleave factor +# equals to corresponding instructions latency. 8x is optimal for +# * Bridge and "super-optimal" for other Intel CPUs... + +sub aesni_generate2 { +my $dir=shift; +# As already mentioned it takes in $key and $rounds, which are *not* +# preserved. $inout[0-1] is cipher/clear text... +$code.=<<___; +.type _aesni_${dir}rypt2,\@abi-omnipotent +.align 16 +_aesni_${dir}rypt2: + $movkey ($key),$rndkey0 + shl \$4,$rounds + $movkey 16($key),$rndkey1 + xorps $rndkey0,$inout0 + xorps $rndkey0,$inout1 + $movkey 32($key),$rndkey0 + lea 32($key,$rounds),$key + neg %rax # $rounds + add \$16,%rax + +.L${dir}_loop2: + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + $movkey ($key,%rax),$rndkey1 + add \$32,%rax + aes${dir} $rndkey0,$inout0 + aes${dir} $rndkey0,$inout1 + $movkey -16($key,%rax),$rndkey0 + jnz .L${dir}_loop2 + + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir}last $rndkey0,$inout0 + aes${dir}last $rndkey0,$inout1 + ret +.size _aesni_${dir}rypt2,.-_aesni_${dir}rypt2 +___ +} +sub aesni_generate3 { +my $dir=shift; +# As already mentioned it takes in $key and $rounds, which are *not* +# preserved. $inout[0-2] is cipher/clear text... +$code.=<<___; +.type _aesni_${dir}rypt3,\@abi-omnipotent +.align 16 +_aesni_${dir}rypt3: + $movkey ($key),$rndkey0 + shl \$4,$rounds + $movkey 16($key),$rndkey1 + xorps $rndkey0,$inout0 + xorps $rndkey0,$inout1 + xorps $rndkey0,$inout2 + $movkey 32($key),$rndkey0 + lea 32($key,$rounds),$key + neg %rax # $rounds + add \$16,%rax + +.L${dir}_loop3: + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir} $rndkey1,$inout2 + $movkey ($key,%rax),$rndkey1 + add \$32,%rax + aes${dir} $rndkey0,$inout0 + aes${dir} $rndkey0,$inout1 + aes${dir} $rndkey0,$inout2 + $movkey -16($key,%rax),$rndkey0 + jnz .L${dir}_loop3 + + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir} $rndkey1,$inout2 + aes${dir}last $rndkey0,$inout0 + aes${dir}last $rndkey0,$inout1 + aes${dir}last $rndkey0,$inout2 + ret +.size _aesni_${dir}rypt3,.-_aesni_${dir}rypt3 +___ +} +# 4x interleave is implemented to improve small block performance, +# most notably [and naturally] 4 block by ~30%. One can argue that one +# should have implemented 5x as well, but improvement would be <20%, +# so it's not worth it... +sub aesni_generate4 { +my $dir=shift; +# As already mentioned it takes in $key and $rounds, which are *not* +# preserved. $inout[0-3] is cipher/clear text... +$code.=<<___; +.type _aesni_${dir}rypt4,\@abi-omnipotent +.align 16 +_aesni_${dir}rypt4: + $movkey ($key),$rndkey0 + shl \$4,$rounds + $movkey 16($key),$rndkey1 + xorps $rndkey0,$inout0 + xorps $rndkey0,$inout1 + xorps $rndkey0,$inout2 + xorps $rndkey0,$inout3 + $movkey 32($key),$rndkey0 + lea 32($key,$rounds),$key + neg %rax # $rounds + .byte 0x0f,0x1f,0x00 + add \$16,%rax + +.L${dir}_loop4: + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir} $rndkey1,$inout2 + aes${dir} $rndkey1,$inout3 + $movkey ($key,%rax),$rndkey1 + add \$32,%rax + aes${dir} $rndkey0,$inout0 + aes${dir} $rndkey0,$inout1 + aes${dir} $rndkey0,$inout2 + aes${dir} $rndkey0,$inout3 + $movkey -16($key,%rax),$rndkey0 + jnz .L${dir}_loop4 + + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir} $rndkey1,$inout2 + aes${dir} $rndkey1,$inout3 + aes${dir}last $rndkey0,$inout0 + aes${dir}last $rndkey0,$inout1 + aes${dir}last $rndkey0,$inout2 + aes${dir}last $rndkey0,$inout3 + ret +.size _aesni_${dir}rypt4,.-_aesni_${dir}rypt4 +___ +} +sub aesni_generate6 { +my $dir=shift; +# As already mentioned it takes in $key and $rounds, which are *not* +# preserved. $inout[0-5] is cipher/clear text... +$code.=<<___; +.type _aesni_${dir}rypt6,\@abi-omnipotent +.align 16 +_aesni_${dir}rypt6: + $movkey ($key),$rndkey0 + shl \$4,$rounds + $movkey 16($key),$rndkey1 + xorps $rndkey0,$inout0 + pxor $rndkey0,$inout1 + pxor $rndkey0,$inout2 + aes${dir} $rndkey1,$inout0 + lea 32($key,$rounds),$key + neg %rax # $rounds + aes${dir} $rndkey1,$inout1 + pxor $rndkey0,$inout3 + pxor $rndkey0,$inout4 + aes${dir} $rndkey1,$inout2 + pxor $rndkey0,$inout5 + $movkey ($key,%rax),$rndkey0 + add \$16,%rax + jmp .L${dir}_loop6_enter +.align 16 +.L${dir}_loop6: + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir} $rndkey1,$inout2 +.L${dir}_loop6_enter: + aes${dir} $rndkey1,$inout3 + aes${dir} $rndkey1,$inout4 + aes${dir} $rndkey1,$inout5 + $movkey ($key,%rax),$rndkey1 + add \$32,%rax + aes${dir} $rndkey0,$inout0 + aes${dir} $rndkey0,$inout1 + aes${dir} $rndkey0,$inout2 + aes${dir} $rndkey0,$inout3 + aes${dir} $rndkey0,$inout4 + aes${dir} $rndkey0,$inout5 + $movkey -16($key,%rax),$rndkey0 + jnz .L${dir}_loop6 + + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir} $rndkey1,$inout2 + aes${dir} $rndkey1,$inout3 + aes${dir} $rndkey1,$inout4 + aes${dir} $rndkey1,$inout5 + aes${dir}last $rndkey0,$inout0 + aes${dir}last $rndkey0,$inout1 + aes${dir}last $rndkey0,$inout2 + aes${dir}last $rndkey0,$inout3 + aes${dir}last $rndkey0,$inout4 + aes${dir}last $rndkey0,$inout5 + ret +.size _aesni_${dir}rypt6,.-_aesni_${dir}rypt6 +___ +} +sub aesni_generate8 { +my $dir=shift; +# As already mentioned it takes in $key and $rounds, which are *not* +# preserved. $inout[0-7] is cipher/clear text... +$code.=<<___; +.type _aesni_${dir}rypt8,\@abi-omnipotent +.align 16 +_aesni_${dir}rypt8: + $movkey ($key),$rndkey0 + shl \$4,$rounds + $movkey 16($key),$rndkey1 + xorps $rndkey0,$inout0 + xorps $rndkey0,$inout1 + pxor $rndkey0,$inout2 + pxor $rndkey0,$inout3 + pxor $rndkey0,$inout4 + lea 32($key,$rounds),$key + neg %rax # $rounds + aes${dir} $rndkey1,$inout0 + pxor $rndkey0,$inout5 + pxor $rndkey0,$inout6 + aes${dir} $rndkey1,$inout1 + pxor $rndkey0,$inout7 + $movkey ($key,%rax),$rndkey0 + add \$16,%rax + jmp .L${dir}_loop8_inner +.align 16 +.L${dir}_loop8: + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 +.L${dir}_loop8_inner: + aes${dir} $rndkey1,$inout2 + aes${dir} $rndkey1,$inout3 + aes${dir} $rndkey1,$inout4 + aes${dir} $rndkey1,$inout5 + aes${dir} $rndkey1,$inout6 + aes${dir} $rndkey1,$inout7 +.L${dir}_loop8_enter: + $movkey ($key,%rax),$rndkey1 + add \$32,%rax + aes${dir} $rndkey0,$inout0 + aes${dir} $rndkey0,$inout1 + aes${dir} $rndkey0,$inout2 + aes${dir} $rndkey0,$inout3 + aes${dir} $rndkey0,$inout4 + aes${dir} $rndkey0,$inout5 + aes${dir} $rndkey0,$inout6 + aes${dir} $rndkey0,$inout7 + $movkey -16($key,%rax),$rndkey0 + jnz .L${dir}_loop8 + + aes${dir} $rndkey1,$inout0 + aes${dir} $rndkey1,$inout1 + aes${dir} $rndkey1,$inout2 + aes${dir} $rndkey1,$inout3 + aes${dir} $rndkey1,$inout4 + aes${dir} $rndkey1,$inout5 + aes${dir} $rndkey1,$inout6 + aes${dir} $rndkey1,$inout7 + aes${dir}last $rndkey0,$inout0 + aes${dir}last $rndkey0,$inout1 + aes${dir}last $rndkey0,$inout2 + aes${dir}last $rndkey0,$inout3 + aes${dir}last $rndkey0,$inout4 + aes${dir}last $rndkey0,$inout5 + aes${dir}last $rndkey0,$inout6 + aes${dir}last $rndkey0,$inout7 + ret +.size _aesni_${dir}rypt8,.-_aesni_${dir}rypt8 +___ +} +&aesni_generate2("enc") if ($PREFIX eq "aesni"); +&aesni_generate2("dec"); +&aesni_generate3("enc") if ($PREFIX eq "aesni"); +&aesni_generate3("dec"); +&aesni_generate4("enc") if ($PREFIX eq "aesni"); +&aesni_generate4("dec"); +&aesni_generate6("enc") if ($PREFIX eq "aesni"); +&aesni_generate6("dec"); +&aesni_generate8("enc") if ($PREFIX eq "aesni"); +&aesni_generate8("dec"); + +if ($PREFIX eq "aesni") { +######################################################################## +# void aesni_ecb_encrypt (const void *in, void *out, +# size_t length, const AES_KEY *key, +# int enc); +$code.=<<___; +.globl aesni_ecb_encrypt +.type aesni_ecb_encrypt,\@function,5 +.align 16 +aesni_ecb_encrypt: +___ +$code.=<<___ if ($win64); + lea -0x58(%rsp),%rsp + movaps %xmm6,(%rsp) # offload $inout4..7 + movaps %xmm7,0x10(%rsp) + movaps %xmm8,0x20(%rsp) + movaps %xmm9,0x30(%rsp) +.Lecb_enc_body: +___ +$code.=<<___; + and \$-16,$len # if ($len<16) + jz .Lecb_ret # return + + mov 240($key),$rounds # key->rounds + $movkey ($key),$rndkey0 + mov $key,$key_ # backup $key + mov $rounds,$rnds_ # backup $rounds + test %r8d,%r8d # 5th argument + jz .Lecb_decrypt +#--------------------------- ECB ENCRYPT ------------------------------# + cmp \$0x80,$len # if ($len<8*16) + jb .Lecb_enc_tail # short input + + movdqu ($inp),$inout0 # load 8 input blocks + movdqu 0x10($inp),$inout1 + movdqu 0x20($inp),$inout2 + movdqu 0x30($inp),$inout3 + movdqu 0x40($inp),$inout4 + movdqu 0x50($inp),$inout5 + movdqu 0x60($inp),$inout6 + movdqu 0x70($inp),$inout7 + lea 0x80($inp),$inp # $inp+=8*16 + sub \$0x80,$len # $len-=8*16 (can be zero) + jmp .Lecb_enc_loop8_enter +.align 16 +.Lecb_enc_loop8: + movups $inout0,($out) # store 8 output blocks + mov $key_,$key # restore $key + movdqu ($inp),$inout0 # load 8 input blocks + mov $rnds_,$rounds # restore $rounds + movups $inout1,0x10($out) + movdqu 0x10($inp),$inout1 + movups $inout2,0x20($out) + movdqu 0x20($inp),$inout2 + movups $inout3,0x30($out) + movdqu 0x30($inp),$inout3 + movups $inout4,0x40($out) + movdqu 0x40($inp),$inout4 + movups $inout5,0x50($out) + movdqu 0x50($inp),$inout5 + movups $inout6,0x60($out) + movdqu 0x60($inp),$inout6 + movups $inout7,0x70($out) + lea 0x80($out),$out # $out+=8*16 + movdqu 0x70($inp),$inout7 + lea 0x80($inp),$inp # $inp+=8*16 +.Lecb_enc_loop8_enter: + + call _aesni_encrypt8 + + sub \$0x80,$len + jnc .Lecb_enc_loop8 # loop if $len-=8*16 didn't borrow + + movups $inout0,($out) # store 8 output blocks + mov $key_,$key # restore $key + movups $inout1,0x10($out) + mov $rnds_,$rounds # restore $rounds + movups $inout2,0x20($out) + movups $inout3,0x30($out) + movups $inout4,0x40($out) + movups $inout5,0x50($out) + movups $inout6,0x60($out) + movups $inout7,0x70($out) + lea 0x80($out),$out # $out+=8*16 + add \$0x80,$len # restore real remaining $len + jz .Lecb_ret # done if ($len==0) + +.Lecb_enc_tail: # $len is less than 8*16 + movups ($inp),$inout0 + cmp \$0x20,$len + jb .Lecb_enc_one + movups 0x10($inp),$inout1 + je .Lecb_enc_two + movups 0x20($inp),$inout2 + cmp \$0x40,$len + jb .Lecb_enc_three + movups 0x30($inp),$inout3 + je .Lecb_enc_four + movups 0x40($inp),$inout4 + cmp \$0x60,$len + jb .Lecb_enc_five + movups 0x50($inp),$inout5 + je .Lecb_enc_six + movdqu 0x60($inp),$inout6 + xorps $inout7,$inout7 + call _aesni_encrypt8 + movups $inout0,($out) # store 7 output blocks + movups $inout1,0x10($out) + movups $inout2,0x20($out) + movups $inout3,0x30($out) + movups $inout4,0x40($out) + movups $inout5,0x50($out) + movups $inout6,0x60($out) + jmp .Lecb_ret +.align 16 +.Lecb_enc_one: +___ + &aesni_generate1("enc",$key,$rounds); +$code.=<<___; + movups $inout0,($out) # store one output block + jmp .Lecb_ret +.align 16 +.Lecb_enc_two: + call _aesni_encrypt2 + movups $inout0,($out) # store 2 output blocks + movups $inout1,0x10($out) + jmp .Lecb_ret +.align 16 +.Lecb_enc_three: + call _aesni_encrypt3 + movups $inout0,($out) # store 3 output blocks + movups $inout1,0x10($out) + movups $inout2,0x20($out) + jmp .Lecb_ret +.align 16 +.Lecb_enc_four: + call _aesni_encrypt4 + movups $inout0,($out) # store 4 output blocks + movups $inout1,0x10($out) + movups $inout2,0x20($out) + movups $inout3,0x30($out) + jmp .Lecb_ret +.align 16 +.Lecb_enc_five: + xorps $inout5,$inout5 + call _aesni_encrypt6 + movups $inout0,($out) # store 5 output blocks + movups $inout1,0x10($out) + movups $inout2,0x20($out) + movups $inout3,0x30($out) + movups $inout4,0x40($out) + jmp .Lecb_ret +.align 16 +.Lecb_enc_six: + call _aesni_encrypt6 + movups $inout0,($out) # store 6 output blocks + movups $inout1,0x10($out) + movups $inout2,0x20($out) + movups $inout3,0x30($out) + movups $inout4,0x40($out) + movups $inout5,0x50($out) + jmp .Lecb_ret + #--------------------------- ECB DECRYPT ------------------------------# +.align 16 +.Lecb_decrypt: + cmp \$0x80,$len # if ($len<8*16) + jb .Lecb_dec_tail # short input + + movdqu ($inp),$inout0 # load 8 input blocks + movdqu 0x10($inp),$inout1 + movdqu 0x20($inp),$inout2 + movdqu 0x30($inp),$inout3 + movdqu 0x40($inp),$inout4 + movdqu 0x50($inp),$inout5 + movdqu 0x60($inp),$inout6 + movdqu 0x70($inp),$inout7 + lea 0x80($inp),$inp # $inp+=8*16 + sub \$0x80,$len # $len-=8*16 (can be zero) + jmp .Lecb_dec_loop8_enter +.align 16 +.Lecb_dec_loop8: + movups $inout0,($out) # store 8 output blocks + mov $key_,$key # restore $key + movdqu ($inp),$inout0 # load 8 input blocks + mov $rnds_,$rounds # restore $rounds + movups $inout1,0x10($out) + movdqu 0x10($inp),$inout1 + movups $inout2,0x20($out) + movdqu 0x20($inp),$inout2 + movups $inout3,0x30($out) + movdqu 0x30($inp),$inout3 + movups $inout4,0x40($out) + movdqu 0x40($inp),$inout4 + movups $inout5,0x50($out) + movdqu 0x50($inp),$inout5 + movups $inout6,0x60($out) + movdqu 0x60($inp),$inout6 + movups $inout7,0x70($out) + lea 0x80($out),$out # $out+=8*16 + movdqu 0x70($inp),$inout7 + lea 0x80($inp),$inp # $inp+=8*16 +.Lecb_dec_loop8_enter: + + call _aesni_decrypt8 + + $movkey ($key_),$rndkey0 + sub \$0x80,$len + jnc .Lecb_dec_loop8 # loop if $len-=8*16 didn't borrow + + movups $inout0,($out) # store 8 output blocks + pxor $inout0,$inout0 # clear register bank + mov $key_,$key # restore $key + movups $inout1,0x10($out) + pxor $inout1,$inout1 + mov $rnds_,$rounds # restore $rounds + movups $inout2,0x20($out) + pxor $inout2,$inout2 + movups $inout3,0x30($out) + pxor $inout3,$inout3 + movups $inout4,0x40($out) + pxor $inout4,$inout4 + movups $inout5,0x50($out) + pxor $inout5,$inout5 + movups $inout6,0x60($out) + pxor $inout6,$inout6 + movups $inout7,0x70($out) + pxor $inout7,$inout7 + lea 0x80($out),$out # $out+=8*16 + add \$0x80,$len # restore real remaining $len + jz .Lecb_ret # done if ($len==0) + +.Lecb_dec_tail: + movups ($inp),$inout0 + cmp \$0x20,$len + jb .Lecb_dec_one + movups 0x10($inp),$inout1 + je .Lecb_dec_two + movups 0x20($inp),$inout2 + cmp \$0x40,$len + jb .Lecb_dec_three + movups 0x30($inp),$inout3 + je .Lecb_dec_four + movups 0x40($inp),$inout4 + cmp \$0x60,$len + jb .Lecb_dec_five + movups 0x50($inp),$inout5 + je .Lecb_dec_six + movups 0x60($inp),$inout6 + $movkey ($key),$rndkey0 + xorps $inout7,$inout7 + call _aesni_decrypt8 + movups $inout0,($out) # store 7 output blocks + pxor $inout0,$inout0 # clear register bank + movups $inout1,0x10($out) + pxor $inout1,$inout1 + movups $inout2,0x20($out) + pxor $inout2,$inout2 + movups $inout3,0x30($out) + pxor $inout3,$inout3 + movups $inout4,0x40($out) + pxor $inout4,$inout4 + movups $inout5,0x50($out) + pxor $inout5,$inout5 + movups $inout6,0x60($out) + pxor $inout6,$inout6 + pxor $inout7,$inout7 + jmp .Lecb_ret +.align 16 +.Lecb_dec_one: +___ + &aesni_generate1("dec",$key,$rounds); +$code.=<<___; + movups $inout0,($out) # store one output block + pxor $inout0,$inout0 # clear register bank + jmp .Lecb_ret +.align 16 +.Lecb_dec_two: + call _aesni_decrypt2 + movups $inout0,($out) # store 2 output blocks + pxor $inout0,$inout0 # clear register bank + movups $inout1,0x10($out) + pxor $inout1,$inout1 + jmp .Lecb_ret +.align 16 +.Lecb_dec_three: + call _aesni_decrypt3 + movups $inout0,($out) # store 3 output blocks + pxor $inout0,$inout0 # clear register bank + movups $inout1,0x10($out) + pxor $inout1,$inout1 + movups $inout2,0x20($out) + pxor $inout2,$inout2 + jmp .Lecb_ret +.align 16 +.Lecb_dec_four: + call _aesni_decrypt4 + movups $inout0,($out) # store 4 output blocks + pxor $inout0,$inout0 # clear register bank + movups $inout1,0x10($out) + pxor $inout1,$inout1 + movups $inout2,0x20($out) + pxor $inout2,$inout2 + movups $inout3,0x30($out) + pxor $inout3,$inout3 + jmp .Lecb_ret +.align 16 +.Lecb_dec_five: + xorps $inout5,$inout5 + call _aesni_decrypt6 + movups $inout0,($out) # store 5 output blocks + pxor $inout0,$inout0 # clear register bank + movups $inout1,0x10($out) + pxor $inout1,$inout1 + movups $inout2,0x20($out) + pxor $inout2,$inout2 + movups $inout3,0x30($out) + pxor $inout3,$inout3 + movups $inout4,0x40($out) + pxor $inout4,$inout4 + pxor $inout5,$inout5 + jmp .Lecb_ret +.align 16 +.Lecb_dec_six: + call _aesni_decrypt6 + movups $inout0,($out) # store 6 output blocks + pxor $inout0,$inout0 # clear register bank + movups $inout1,0x10($out) + pxor $inout1,$inout1 + movups $inout2,0x20($out) + pxor $inout2,$inout2 + movups $inout3,0x30($out) + pxor $inout3,$inout3 + movups $inout4,0x40($out) + pxor $inout4,$inout4 + movups $inout5,0x50($out) + pxor $inout5,$inout5 + +.Lecb_ret: + xorps $rndkey0,$rndkey0 # %xmm0 + pxor $rndkey1,$rndkey1 +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + movaps %xmm0,(%rsp) # clear stack + movaps 0x10(%rsp),%xmm7 + movaps %xmm0,0x10(%rsp) + movaps 0x20(%rsp),%xmm8 + movaps %xmm0,0x20(%rsp) + movaps 0x30(%rsp),%xmm9 + movaps %xmm0,0x30(%rsp) + lea 0x58(%rsp),%rsp +.Lecb_enc_ret: +___ +$code.=<<___; + ret +.size aesni_ecb_encrypt,.-aesni_ecb_encrypt +___ + +{ +###################################################################### +# void aesni_ccm64_[en|de]crypt_blocks (const void *in, void *out, +# size_t blocks, const AES_KEY *key, +# const char *ivec,char *cmac); +# +# Handles only complete blocks, operates on 64-bit counter and +# does not update *ivec! Nor does it finalize CMAC value +# (see engine/eng_aesni.c for details) +# +{ +my $cmac="%r9"; # 6th argument + +my $increment="%xmm9"; +my $iv="%xmm6"; +my $bswap_mask="%xmm7"; + +$code.=<<___; +.globl aesni_ccm64_encrypt_blocks +.type aesni_ccm64_encrypt_blocks,\@function,6 +.align 16 +aesni_ccm64_encrypt_blocks: +___ +$code.=<<___ if ($win64); + lea -0x58(%rsp),%rsp + movaps %xmm6,(%rsp) # $iv + movaps %xmm7,0x10(%rsp) # $bswap_mask + movaps %xmm8,0x20(%rsp) # $in0 + movaps %xmm9,0x30(%rsp) # $increment +.Lccm64_enc_body: +___ +$code.=<<___; + mov 240($key),$rounds # key->rounds + movdqu ($ivp),$iv + movdqa .Lincrement64(%rip),$increment + movdqa .Lbswap_mask(%rip),$bswap_mask + + shl \$4,$rounds + mov \$16,$rnds_ + lea 0($key),$key_ + movdqu ($cmac),$inout1 + movdqa $iv,$inout0 + lea 32($key,$rounds),$key # end of key schedule + pshufb $bswap_mask,$iv + sub %rax,%r10 # twisted $rounds + jmp .Lccm64_enc_outer +.align 16 +.Lccm64_enc_outer: + $movkey ($key_),$rndkey0 + mov %r10,%rax + movups ($inp),$in0 # load inp + + xorps $rndkey0,$inout0 # counter + $movkey 16($key_),$rndkey1 + xorps $in0,$rndkey0 + xorps $rndkey0,$inout1 # cmac^=inp + $movkey 32($key_),$rndkey0 + +.Lccm64_enc2_loop: + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + $movkey ($key,%rax),$rndkey1 + add \$32,%rax + aesenc $rndkey0,$inout0 + aesenc $rndkey0,$inout1 + $movkey -16($key,%rax),$rndkey0 + jnz .Lccm64_enc2_loop + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + paddq $increment,$iv + dec $len # $len-- ($len is in blocks) + aesenclast $rndkey0,$inout0 + aesenclast $rndkey0,$inout1 + + lea 16($inp),$inp + xorps $inout0,$in0 # inp ^= E(iv) + movdqa $iv,$inout0 + movups $in0,($out) # save output + pshufb $bswap_mask,$inout0 + lea 16($out),$out # $out+=16 + jnz .Lccm64_enc_outer # loop if ($len!=0) + + pxor $rndkey0,$rndkey0 # clear register bank + pxor $rndkey1,$rndkey1 + pxor $inout0,$inout0 + movups $inout1,($cmac) # store resulting mac + pxor $inout1,$inout1 + pxor $in0,$in0 + pxor $iv,$iv +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + movaps %xmm0,(%rsp) # clear stack + movaps 0x10(%rsp),%xmm7 + movaps %xmm0,0x10(%rsp) + movaps 0x20(%rsp),%xmm8 + movaps %xmm0,0x20(%rsp) + movaps 0x30(%rsp),%xmm9 + movaps %xmm0,0x30(%rsp) + lea 0x58(%rsp),%rsp +.Lccm64_enc_ret: +___ +$code.=<<___; + ret +.size aesni_ccm64_encrypt_blocks,.-aesni_ccm64_encrypt_blocks +___ +###################################################################### +$code.=<<___; +.globl aesni_ccm64_decrypt_blocks +.type aesni_ccm64_decrypt_blocks,\@function,6 +.align 16 +aesni_ccm64_decrypt_blocks: +___ +$code.=<<___ if ($win64); + lea -0x58(%rsp),%rsp + movaps %xmm6,(%rsp) # $iv + movaps %xmm7,0x10(%rsp) # $bswap_mask + movaps %xmm8,0x20(%rsp) # $in8 + movaps %xmm9,0x30(%rsp) # $increment +.Lccm64_dec_body: +___ +$code.=<<___; + mov 240($key),$rounds # key->rounds + movups ($ivp),$iv + movdqu ($cmac),$inout1 + movdqa .Lincrement64(%rip),$increment + movdqa .Lbswap_mask(%rip),$bswap_mask + + movaps $iv,$inout0 + mov $rounds,$rnds_ + mov $key,$key_ + pshufb $bswap_mask,$iv +___ + &aesni_generate1("enc",$key,$rounds); +$code.=<<___; + shl \$4,$rnds_ + mov \$16,$rounds + movups ($inp),$in0 # load inp + paddq $increment,$iv + lea 16($inp),$inp # $inp+=16 + sub %r10,%rax # twisted $rounds + lea 32($key_,$rnds_),$key # end of key schedule + mov %rax,%r10 + jmp .Lccm64_dec_outer +.align 16 +.Lccm64_dec_outer: + xorps $inout0,$in0 # inp ^= E(iv) + movdqa $iv,$inout0 + movups $in0,($out) # save output + lea 16($out),$out # $out+=16 + pshufb $bswap_mask,$inout0 + + sub \$1,$len # $len-- ($len is in blocks) + jz .Lccm64_dec_break # if ($len==0) break + + $movkey ($key_),$rndkey0 + mov %r10,%rax + $movkey 16($key_),$rndkey1 + xorps $rndkey0,$in0 + xorps $rndkey0,$inout0 + xorps $in0,$inout1 # cmac^=out + $movkey 32($key_),$rndkey0 + jmp .Lccm64_dec2_loop +.align 16 +.Lccm64_dec2_loop: + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + $movkey ($key,%rax),$rndkey1 + add \$32,%rax + aesenc $rndkey0,$inout0 + aesenc $rndkey0,$inout1 + $movkey -16($key,%rax),$rndkey0 + jnz .Lccm64_dec2_loop + movups ($inp),$in0 # load input + paddq $increment,$iv + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + aesenclast $rndkey0,$inout0 + aesenclast $rndkey0,$inout1 + lea 16($inp),$inp # $inp+=16 + jmp .Lccm64_dec_outer + +.align 16 +.Lccm64_dec_break: + #xorps $in0,$inout1 # cmac^=out + mov 240($key_),$rounds +___ + &aesni_generate1("enc",$key_,$rounds,$inout1,$in0); +$code.=<<___; + pxor $rndkey0,$rndkey0 # clear register bank + pxor $rndkey1,$rndkey1 + pxor $inout0,$inout0 + movups $inout1,($cmac) # store resulting mac + pxor $inout1,$inout1 + pxor $in0,$in0 + pxor $iv,$iv +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + movaps %xmm0,(%rsp) # clear stack + movaps 0x10(%rsp),%xmm7 + movaps %xmm0,0x10(%rsp) + movaps 0x20(%rsp),%xmm8 + movaps %xmm0,0x20(%rsp) + movaps 0x30(%rsp),%xmm9 + movaps %xmm0,0x30(%rsp) + lea 0x58(%rsp),%rsp +.Lccm64_dec_ret: +___ +$code.=<<___; + ret +.size aesni_ccm64_decrypt_blocks,.-aesni_ccm64_decrypt_blocks +___ +} +###################################################################### +# void aesni_ctr32_encrypt_blocks (const void *in, void *out, +# size_t blocks, const AES_KEY *key, +# const char *ivec); +# +# Handles only complete blocks, operates on 32-bit counter and +# does not update *ivec! (see crypto/modes/ctr128.c for details) +# +# Overhaul based on suggestions from Shay Gueron and Vlad Krasnov, +# http://rt.openssl.org/Ticket/Display.html?id=3021&user=guest&pass=guest. +# Keywords are full unroll and modulo-schedule counter calculations +# with zero-round key xor. +{ +my ($in0,$in1,$in2,$in3,$in4,$in5)=map("%xmm$_",(10..15)); +my ($key0,$ctr)=("${key_}d","${ivp}d"); +my $frame_size = 0x80 + ($win64?160:0); + +$code.=<<___; +.globl aesni_ctr32_encrypt_blocks +.type aesni_ctr32_encrypt_blocks,\@function,5 +.align 16 +aesni_ctr32_encrypt_blocks: + cmp \$1,$len + jne .Lctr32_bulk + + # handle single block without allocating stack frame, + # useful when handling edges + movups ($ivp),$inout0 + movups ($inp),$inout1 + mov 240($key),%edx # key->rounds +___ + &aesni_generate1("enc",$key,"%edx"); +$code.=<<___; + pxor $rndkey0,$rndkey0 # clear register bank + pxor $rndkey1,$rndkey1 + xorps $inout1,$inout0 + pxor $inout1,$inout1 + movups $inout0,($out) + xorps $inout0,$inout0 + jmp .Lctr32_epilogue + +.align 16 +.Lctr32_bulk: + lea (%rsp),%rax + push %rbp + sub \$$frame_size,%rsp + and \$-16,%rsp # Linux kernel stack can be incorrectly seeded +___ +$code.=<<___ if ($win64); + movaps %xmm6,-0xa8(%rax) # offload everything + movaps %xmm7,-0x98(%rax) + movaps %xmm8,-0x88(%rax) + movaps %xmm9,-0x78(%rax) + movaps %xmm10,-0x68(%rax) + movaps %xmm11,-0x58(%rax) + movaps %xmm12,-0x48(%rax) + movaps %xmm13,-0x38(%rax) + movaps %xmm14,-0x28(%rax) + movaps %xmm15,-0x18(%rax) +.Lctr32_body: +___ +$code.=<<___; + lea -8(%rax),%rbp + + # 8 16-byte words on top of stack are counter values + # xor-ed with zero-round key + + movdqu ($ivp),$inout0 + movdqu ($key),$rndkey0 + mov 12($ivp),$ctr # counter LSB + pxor $rndkey0,$inout0 + mov 12($key),$key0 # 0-round key LSB + movdqa $inout0,0x00(%rsp) # populate counter block + bswap $ctr + movdqa $inout0,$inout1 + movdqa $inout0,$inout2 + movdqa $inout0,$inout3 + movdqa $inout0,0x40(%rsp) + movdqa $inout0,0x50(%rsp) + movdqa $inout0,0x60(%rsp) + mov %rdx,%r10 # about to borrow %rdx + movdqa $inout0,0x70(%rsp) + + lea 1($ctr),%rax + lea 2($ctr),%rdx + bswap %eax + bswap %edx + xor $key0,%eax + xor $key0,%edx + pinsrd \$3,%eax,$inout1 + lea 3($ctr),%rax + movdqa $inout1,0x10(%rsp) + pinsrd \$3,%edx,$inout2 + bswap %eax + mov %r10,%rdx # restore %rdx + lea 4($ctr),%r10 + movdqa $inout2,0x20(%rsp) + xor $key0,%eax + bswap %r10d + pinsrd \$3,%eax,$inout3 + xor $key0,%r10d + movdqa $inout3,0x30(%rsp) + lea 5($ctr),%r9 + mov %r10d,0x40+12(%rsp) + bswap %r9d + lea 6($ctr),%r10 + mov 240($key),$rounds # key->rounds + xor $key0,%r9d + bswap %r10d + mov %r9d,0x50+12(%rsp) + xor $key0,%r10d + lea 7($ctr),%r9 + mov %r10d,0x60+12(%rsp) + bswap %r9d + mov OPENSSL_ia32cap_P+4(%rip),%r10d + xor $key0,%r9d + and \$`1<<26|1<<22`,%r10d # isolate XSAVE+MOVBE + mov %r9d,0x70+12(%rsp) + + $movkey 0x10($key),$rndkey1 + + movdqa 0x40(%rsp),$inout4 + movdqa 0x50(%rsp),$inout5 + + cmp \$8,$len # $len is in blocks + jb .Lctr32_tail # short input if ($len<8) + + sub \$6,$len # $len is biased by -6 + cmp \$`1<<22`,%r10d # check for MOVBE without XSAVE + je .Lctr32_6x # [which denotes Atom Silvermont] + + lea 0x80($key),$key # size optimization + sub \$2,$len # $len is biased by -8 + jmp .Lctr32_loop8 + +.align 16 +.Lctr32_6x: + shl \$4,$rounds + mov \$48,$rnds_ + bswap $key0 + lea 32($key,$rounds),$key # end of key schedule + sub %rax,%r10 # twisted $rounds + jmp .Lctr32_loop6 + +.align 16 +.Lctr32_loop6: + add \$6,$ctr # next counter value + $movkey -48($key,$rnds_),$rndkey0 + aesenc $rndkey1,$inout0 + mov $ctr,%eax + xor $key0,%eax + aesenc $rndkey1,$inout1 + movbe %eax,`0x00+12`(%rsp) # store next counter value + lea 1($ctr),%eax + aesenc $rndkey1,$inout2 + xor $key0,%eax + movbe %eax,`0x10+12`(%rsp) + aesenc $rndkey1,$inout3 + lea 2($ctr),%eax + xor $key0,%eax + aesenc $rndkey1,$inout4 + movbe %eax,`0x20+12`(%rsp) + lea 3($ctr),%eax + aesenc $rndkey1,$inout5 + $movkey -32($key,$rnds_),$rndkey1 + xor $key0,%eax + + aesenc $rndkey0,$inout0 + movbe %eax,`0x30+12`(%rsp) + lea 4($ctr),%eax + aesenc $rndkey0,$inout1 + xor $key0,%eax + movbe %eax,`0x40+12`(%rsp) + aesenc $rndkey0,$inout2 + lea 5($ctr),%eax + xor $key0,%eax + aesenc $rndkey0,$inout3 + movbe %eax,`0x50+12`(%rsp) + mov %r10,%rax # mov $rnds_,$rounds + aesenc $rndkey0,$inout4 + aesenc $rndkey0,$inout5 + $movkey -16($key,$rnds_),$rndkey0 + + call .Lenc_loop6 + + movdqu ($inp),$inout6 # load 6 input blocks + movdqu 0x10($inp),$inout7 + movdqu 0x20($inp),$in0 + movdqu 0x30($inp),$in1 + movdqu 0x40($inp),$in2 + movdqu 0x50($inp),$in3 + lea 0x60($inp),$inp # $inp+=6*16 + $movkey -64($key,$rnds_),$rndkey1 + pxor $inout0,$inout6 # inp^=E(ctr) + movaps 0x00(%rsp),$inout0 # load next counter [xor-ed with 0 round] + pxor $inout1,$inout7 + movaps 0x10(%rsp),$inout1 + pxor $inout2,$in0 + movaps 0x20(%rsp),$inout2 + pxor $inout3,$in1 + movaps 0x30(%rsp),$inout3 + pxor $inout4,$in2 + movaps 0x40(%rsp),$inout4 + pxor $inout5,$in3 + movaps 0x50(%rsp),$inout5 + movdqu $inout6,($out) # store 6 output blocks + movdqu $inout7,0x10($out) + movdqu $in0,0x20($out) + movdqu $in1,0x30($out) + movdqu $in2,0x40($out) + movdqu $in3,0x50($out) + lea 0x60($out),$out # $out+=6*16 + + sub \$6,$len + jnc .Lctr32_loop6 # loop if $len-=6 didn't borrow + + add \$6,$len # restore real remaining $len + jz .Lctr32_done # done if ($len==0) + + lea -48($rnds_),$rounds + lea -80($key,$rnds_),$key # restore $key + neg $rounds + shr \$4,$rounds # restore $rounds + jmp .Lctr32_tail + +.align 32 +.Lctr32_loop8: + add \$8,$ctr # next counter value + movdqa 0x60(%rsp),$inout6 + aesenc $rndkey1,$inout0 + mov $ctr,%r9d + movdqa 0x70(%rsp),$inout7 + aesenc $rndkey1,$inout1 + bswap %r9d + $movkey 0x20-0x80($key),$rndkey0 + aesenc $rndkey1,$inout2 + xor $key0,%r9d + nop + aesenc $rndkey1,$inout3 + mov %r9d,0x00+12(%rsp) # store next counter value + lea 1($ctr),%r9 + aesenc $rndkey1,$inout4 + aesenc $rndkey1,$inout5 + aesenc $rndkey1,$inout6 + aesenc $rndkey1,$inout7 + $movkey 0x30-0x80($key),$rndkey1 +___ +for($i=2;$i<8;$i++) { +my $rndkeyx = ($i&1)?$rndkey1:$rndkey0; +$code.=<<___; + bswap %r9d + aesenc $rndkeyx,$inout0 + aesenc $rndkeyx,$inout1 + xor $key0,%r9d + .byte 0x66,0x90 + aesenc $rndkeyx,$inout2 + aesenc $rndkeyx,$inout3 + mov %r9d,`0x10*($i-1)`+12(%rsp) + lea $i($ctr),%r9 + aesenc $rndkeyx,$inout4 + aesenc $rndkeyx,$inout5 + aesenc $rndkeyx,$inout6 + aesenc $rndkeyx,$inout7 + $movkey `0x20+0x10*$i`-0x80($key),$rndkeyx +___ +} +$code.=<<___; + bswap %r9d + aesenc $rndkey0,$inout0 + aesenc $rndkey0,$inout1 + aesenc $rndkey0,$inout2 + xor $key0,%r9d + movdqu 0x00($inp),$in0 # start loading input + aesenc $rndkey0,$inout3 + mov %r9d,0x70+12(%rsp) + cmp \$11,$rounds + aesenc $rndkey0,$inout4 + aesenc $rndkey0,$inout5 + aesenc $rndkey0,$inout6 + aesenc $rndkey0,$inout7 + $movkey 0xa0-0x80($key),$rndkey0 + + jb .Lctr32_enc_done + + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + aesenc $rndkey1,$inout4 + aesenc $rndkey1,$inout5 + aesenc $rndkey1,$inout6 + aesenc $rndkey1,$inout7 + $movkey 0xb0-0x80($key),$rndkey1 + + aesenc $rndkey0,$inout0 + aesenc $rndkey0,$inout1 + aesenc $rndkey0,$inout2 + aesenc $rndkey0,$inout3 + aesenc $rndkey0,$inout4 + aesenc $rndkey0,$inout5 + aesenc $rndkey0,$inout6 + aesenc $rndkey0,$inout7 + $movkey 0xc0-0x80($key),$rndkey0 + je .Lctr32_enc_done + + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + aesenc $rndkey1,$inout4 + aesenc $rndkey1,$inout5 + aesenc $rndkey1,$inout6 + aesenc $rndkey1,$inout7 + $movkey 0xd0-0x80($key),$rndkey1 + + aesenc $rndkey0,$inout0 + aesenc $rndkey0,$inout1 + aesenc $rndkey0,$inout2 + aesenc $rndkey0,$inout3 + aesenc $rndkey0,$inout4 + aesenc $rndkey0,$inout5 + aesenc $rndkey0,$inout6 + aesenc $rndkey0,$inout7 + $movkey 0xe0-0x80($key),$rndkey0 + jmp .Lctr32_enc_done + +.align 16 +.Lctr32_enc_done: + movdqu 0x10($inp),$in1 + pxor $rndkey0,$in0 # input^=round[last] + movdqu 0x20($inp),$in2 + pxor $rndkey0,$in1 + movdqu 0x30($inp),$in3 + pxor $rndkey0,$in2 + movdqu 0x40($inp),$in4 + pxor $rndkey0,$in3 + movdqu 0x50($inp),$in5 + pxor $rndkey0,$in4 + pxor $rndkey0,$in5 + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + aesenc $rndkey1,$inout4 + aesenc $rndkey1,$inout5 + aesenc $rndkey1,$inout6 + aesenc $rndkey1,$inout7 + movdqu 0x60($inp),$rndkey1 # borrow $rndkey1 for inp[6] + lea 0x80($inp),$inp # $inp+=8*16 + + aesenclast $in0,$inout0 # $inN is inp[N]^round[last] + pxor $rndkey0,$rndkey1 # borrowed $rndkey + movdqu 0x70-0x80($inp),$in0 + aesenclast $in1,$inout1 + pxor $rndkey0,$in0 + movdqa 0x00(%rsp),$in1 # load next counter block + aesenclast $in2,$inout2 + aesenclast $in3,$inout3 + movdqa 0x10(%rsp),$in2 + movdqa 0x20(%rsp),$in3 + aesenclast $in4,$inout4 + aesenclast $in5,$inout5 + movdqa 0x30(%rsp),$in4 + movdqa 0x40(%rsp),$in5 + aesenclast $rndkey1,$inout6 + movdqa 0x50(%rsp),$rndkey0 + $movkey 0x10-0x80($key),$rndkey1#real 1st-round key + aesenclast $in0,$inout7 + + movups $inout0,($out) # store 8 output blocks + movdqa $in1,$inout0 + movups $inout1,0x10($out) + movdqa $in2,$inout1 + movups $inout2,0x20($out) + movdqa $in3,$inout2 + movups $inout3,0x30($out) + movdqa $in4,$inout3 + movups $inout4,0x40($out) + movdqa $in5,$inout4 + movups $inout5,0x50($out) + movdqa $rndkey0,$inout5 + movups $inout6,0x60($out) + movups $inout7,0x70($out) + lea 0x80($out),$out # $out+=8*16 + + sub \$8,$len + jnc .Lctr32_loop8 # loop if $len-=8 didn't borrow + + add \$8,$len # restore real remainig $len + jz .Lctr32_done # done if ($len==0) + lea -0x80($key),$key + +.Lctr32_tail: + # note that at this point $inout0..5 are populated with + # counter values xor-ed with 0-round key + lea 16($key),$key + cmp \$4,$len + jb .Lctr32_loop3 + je .Lctr32_loop4 + + # if ($len>4) compute 7 E(counter) + shl \$4,$rounds + movdqa 0x60(%rsp),$inout6 + pxor $inout7,$inout7 + + $movkey 16($key),$rndkey0 + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + lea 32-16($key,$rounds),$key# prepare for .Lenc_loop8_enter + neg %rax + aesenc $rndkey1,$inout2 + add \$16,%rax # prepare for .Lenc_loop8_enter + movups ($inp),$in0 + aesenc $rndkey1,$inout3 + aesenc $rndkey1,$inout4 + movups 0x10($inp),$in1 # pre-load input + movups 0x20($inp),$in2 + aesenc $rndkey1,$inout5 + aesenc $rndkey1,$inout6 + + call .Lenc_loop8_enter + + movdqu 0x30($inp),$in3 + pxor $in0,$inout0 + movdqu 0x40($inp),$in0 + pxor $in1,$inout1 + movdqu $inout0,($out) # store output + pxor $in2,$inout2 + movdqu $inout1,0x10($out) + pxor $in3,$inout3 + movdqu $inout2,0x20($out) + pxor $in0,$inout4 + movdqu $inout3,0x30($out) + movdqu $inout4,0x40($out) + cmp \$6,$len + jb .Lctr32_done # $len was 5, stop store + + movups 0x50($inp),$in1 + xorps $in1,$inout5 + movups $inout5,0x50($out) + je .Lctr32_done # $len was 6, stop store + + movups 0x60($inp),$in2 + xorps $in2,$inout6 + movups $inout6,0x60($out) + jmp .Lctr32_done # $len was 7, stop store + +.align 32 +.Lctr32_loop4: + aesenc $rndkey1,$inout0 + lea 16($key),$key + dec $rounds + aesenc $rndkey1,$inout1 + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + $movkey ($key),$rndkey1 + jnz .Lctr32_loop4 + aesenclast $rndkey1,$inout0 + aesenclast $rndkey1,$inout1 + movups ($inp),$in0 # load input + movups 0x10($inp),$in1 + aesenclast $rndkey1,$inout2 + aesenclast $rndkey1,$inout3 + movups 0x20($inp),$in2 + movups 0x30($inp),$in3 + + xorps $in0,$inout0 + movups $inout0,($out) # store output + xorps $in1,$inout1 + movups $inout1,0x10($out) + pxor $in2,$inout2 + movdqu $inout2,0x20($out) + pxor $in3,$inout3 + movdqu $inout3,0x30($out) + jmp .Lctr32_done # $len was 4, stop store + +.align 32 +.Lctr32_loop3: + aesenc $rndkey1,$inout0 + lea 16($key),$key + dec $rounds + aesenc $rndkey1,$inout1 + aesenc $rndkey1,$inout2 + $movkey ($key),$rndkey1 + jnz .Lctr32_loop3 + aesenclast $rndkey1,$inout0 + aesenclast $rndkey1,$inout1 + aesenclast $rndkey1,$inout2 + + movups ($inp),$in0 # load input + xorps $in0,$inout0 + movups $inout0,($out) # store output + cmp \$2,$len + jb .Lctr32_done # $len was 1, stop store + + movups 0x10($inp),$in1 + xorps $in1,$inout1 + movups $inout1,0x10($out) + je .Lctr32_done # $len was 2, stop store + + movups 0x20($inp),$in2 + xorps $in2,$inout2 + movups $inout2,0x20($out) # $len was 3, stop store + +.Lctr32_done: + xorps %xmm0,%xmm0 # clear regiser bank + xor $key0,$key0 + pxor %xmm1,%xmm1 + pxor %xmm2,%xmm2 + pxor %xmm3,%xmm3 + pxor %xmm4,%xmm4 + pxor %xmm5,%xmm5 +___ +$code.=<<___ if (!$win64); + pxor %xmm6,%xmm6 + pxor %xmm7,%xmm7 + movaps %xmm0,0x00(%rsp) # clear stack + pxor %xmm8,%xmm8 + movaps %xmm0,0x10(%rsp) + pxor %xmm9,%xmm9 + movaps %xmm0,0x20(%rsp) + pxor %xmm10,%xmm10 + movaps %xmm0,0x30(%rsp) + pxor %xmm11,%xmm11 + movaps %xmm0,0x40(%rsp) + pxor %xmm12,%xmm12 + movaps %xmm0,0x50(%rsp) + pxor %xmm13,%xmm13 + movaps %xmm0,0x60(%rsp) + pxor %xmm14,%xmm14 + movaps %xmm0,0x70(%rsp) + pxor %xmm15,%xmm15 +___ +$code.=<<___ if ($win64); + movaps -0xa0(%rbp),%xmm6 + movaps %xmm0,-0xa0(%rbp) # clear stack + movaps -0x90(%rbp),%xmm7 + movaps %xmm0,-0x90(%rbp) + movaps -0x80(%rbp),%xmm8 + movaps %xmm0,-0x80(%rbp) + movaps -0x70(%rbp),%xmm9 + movaps %xmm0,-0x70(%rbp) + movaps -0x60(%rbp),%xmm10 + movaps %xmm0,-0x60(%rbp) + movaps -0x50(%rbp),%xmm11 + movaps %xmm0,-0x50(%rbp) + movaps -0x40(%rbp),%xmm12 + movaps %xmm0,-0x40(%rbp) + movaps -0x30(%rbp),%xmm13 + movaps %xmm0,-0x30(%rbp) + movaps -0x20(%rbp),%xmm14 + movaps %xmm0,-0x20(%rbp) + movaps -0x10(%rbp),%xmm15 + movaps %xmm0,-0x10(%rbp) + movaps %xmm0,0x00(%rsp) + movaps %xmm0,0x10(%rsp) + movaps %xmm0,0x20(%rsp) + movaps %xmm0,0x30(%rsp) + movaps %xmm0,0x40(%rsp) + movaps %xmm0,0x50(%rsp) + movaps %xmm0,0x60(%rsp) + movaps %xmm0,0x70(%rsp) +___ +$code.=<<___; + lea (%rbp),%rsp + pop %rbp +.Lctr32_epilogue: + ret +.size aesni_ctr32_encrypt_blocks,.-aesni_ctr32_encrypt_blocks +___ +} + +###################################################################### +# void aesni_xts_[en|de]crypt(const char *inp,char *out,size_t len, +# const AES_KEY *key1, const AES_KEY *key2 +# const unsigned char iv[16]); +# +{ +my @tweak=map("%xmm$_",(10..15)); +my ($twmask,$twres,$twtmp)=("%xmm8","%xmm9",@tweak[4]); +my ($key2,$ivp,$len_)=("%r8","%r9","%r9"); +my $frame_size = 0x70 + ($win64?160:0); + +$code.=<<___; +.globl aesni_xts_encrypt +.type aesni_xts_encrypt,\@function,6 +.align 16 +aesni_xts_encrypt: + lea (%rsp),%rax + push %rbp + sub \$$frame_size,%rsp + and \$-16,%rsp # Linux kernel stack can be incorrectly seeded +___ +$code.=<<___ if ($win64); + movaps %xmm6,-0xa8(%rax) # offload everything + movaps %xmm7,-0x98(%rax) + movaps %xmm8,-0x88(%rax) + movaps %xmm9,-0x78(%rax) + movaps %xmm10,-0x68(%rax) + movaps %xmm11,-0x58(%rax) + movaps %xmm12,-0x48(%rax) + movaps %xmm13,-0x38(%rax) + movaps %xmm14,-0x28(%rax) + movaps %xmm15,-0x18(%rax) +.Lxts_enc_body: +___ +$code.=<<___; + lea -8(%rax),%rbp + movups ($ivp),$inout0 # load clear-text tweak + mov 240(%r8),$rounds # key2->rounds + mov 240($key),$rnds_ # key1->rounds +___ + # generate the tweak + &aesni_generate1("enc",$key2,$rounds,$inout0); +$code.=<<___; + $movkey ($key),$rndkey0 # zero round key + mov $key,$key_ # backup $key + mov $rnds_,$rounds # backup $rounds + shl \$4,$rnds_ + mov $len,$len_ # backup $len + and \$-16,$len + + $movkey 16($key,$rnds_),$rndkey1 # last round key + + movdqa .Lxts_magic(%rip),$twmask + movdqa $inout0,@tweak[5] + pshufd \$0x5f,$inout0,$twres + pxor $rndkey0,$rndkey1 +___ + # alternative tweak calculation algorithm is based on suggestions + # by Shay Gueron. psrad doesn't conflict with AES-NI instructions + # and should help in the future... + for ($i=0;$i<4;$i++) { + $code.=<<___; + movdqa $twres,$twtmp + paddd $twres,$twres + movdqa @tweak[5],@tweak[$i] + psrad \$31,$twtmp # broadcast upper bits + paddq @tweak[5],@tweak[5] + pand $twmask,$twtmp + pxor $rndkey0,@tweak[$i] + pxor $twtmp,@tweak[5] +___ + } +$code.=<<___; + movdqa @tweak[5],@tweak[4] + psrad \$31,$twres + paddq @tweak[5],@tweak[5] + pand $twmask,$twres + pxor $rndkey0,@tweak[4] + pxor $twres,@tweak[5] + movaps $rndkey1,0x60(%rsp) # save round[0]^round[last] + + sub \$16*6,$len + jc .Lxts_enc_short # if $len-=6*16 borrowed + + mov \$16+96,$rounds + lea 32($key_,$rnds_),$key # end of key schedule + sub %r10,%rax # twisted $rounds + $movkey 16($key_),$rndkey1 + mov %rax,%r10 # backup twisted $rounds + lea .Lxts_magic(%rip),%r8 + jmp .Lxts_enc_grandloop + +.align 32 +.Lxts_enc_grandloop: + movdqu `16*0`($inp),$inout0 # load input + movdqa $rndkey0,$twmask + movdqu `16*1`($inp),$inout1 + pxor @tweak[0],$inout0 # input^=tweak^round[0] + movdqu `16*2`($inp),$inout2 + pxor @tweak[1],$inout1 + aesenc $rndkey1,$inout0 + movdqu `16*3`($inp),$inout3 + pxor @tweak[2],$inout2 + aesenc $rndkey1,$inout1 + movdqu `16*4`($inp),$inout4 + pxor @tweak[3],$inout3 + aesenc $rndkey1,$inout2 + movdqu `16*5`($inp),$inout5 + pxor @tweak[5],$twmask # round[0]^=tweak[5] + movdqa 0x60(%rsp),$twres # load round[0]^round[last] + pxor @tweak[4],$inout4 + aesenc $rndkey1,$inout3 + $movkey 32($key_),$rndkey0 + lea `16*6`($inp),$inp + pxor $twmask,$inout5 + + pxor $twres,@tweak[0] # calclulate tweaks^round[last] + aesenc $rndkey1,$inout4 + pxor $twres,@tweak[1] + movdqa @tweak[0],`16*0`(%rsp) # put aside tweaks^round[last] + aesenc $rndkey1,$inout5 + $movkey 48($key_),$rndkey1 + pxor $twres,@tweak[2] + + aesenc $rndkey0,$inout0 + pxor $twres,@tweak[3] + movdqa @tweak[1],`16*1`(%rsp) + aesenc $rndkey0,$inout1 + pxor $twres,@tweak[4] + movdqa @tweak[2],`16*2`(%rsp) + aesenc $rndkey0,$inout2 + aesenc $rndkey0,$inout3 + pxor $twres,$twmask + movdqa @tweak[4],`16*4`(%rsp) + aesenc $rndkey0,$inout4 + aesenc $rndkey0,$inout5 + $movkey 64($key_),$rndkey0 + movdqa $twmask,`16*5`(%rsp) + pshufd \$0x5f,@tweak[5],$twres + jmp .Lxts_enc_loop6 +.align 32 +.Lxts_enc_loop6: + aesenc $rndkey1,$inout0 + aesenc $rndkey1,$inout1 + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + aesenc $rndkey1,$inout4 + aesenc $rndkey1,$inout5 + $movkey -64($key,%rax),$rndkey1 + add \$32,%rax + + aesenc $rndkey0,$inout0 + aesenc $rndkey0,$inout1 + aesenc $rndkey0,$inout2 + aesenc $rndkey0,$inout3 + aesenc $rndkey0,$inout4 + aesenc $rndkey0,$inout5 + $movkey -80($key,%rax),$rndkey0 + jnz .Lxts_enc_loop6 + + movdqa (%r8),$twmask # start calculating next tweak + movdqa $twres,$twtmp + paddd $twres,$twres + aesenc $rndkey1,$inout0 + paddq @tweak[5],@tweak[5] + psrad \$31,$twtmp + aesenc $rndkey1,$inout1 + pand $twmask,$twtmp + $movkey ($key_),@tweak[0] # load round[0] + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + aesenc $rndkey1,$inout4 + pxor $twtmp,@tweak[5] + movaps @tweak[0],@tweak[1] # copy round[0] + aesenc $rndkey1,$inout5 + $movkey -64($key),$rndkey1 + + movdqa $twres,$twtmp + aesenc $rndkey0,$inout0 + paddd $twres,$twres + pxor @tweak[5],@tweak[0] + aesenc $rndkey0,$inout1 + psrad \$31,$twtmp + paddq @tweak[5],@tweak[5] + aesenc $rndkey0,$inout2 + aesenc $rndkey0,$inout3 + pand $twmask,$twtmp + movaps @tweak[1],@tweak[2] + aesenc $rndkey0,$inout4 + pxor $twtmp,@tweak[5] + movdqa $twres,$twtmp + aesenc $rndkey0,$inout5 + $movkey -48($key),$rndkey0 + + paddd $twres,$twres + aesenc $rndkey1,$inout0 + pxor @tweak[5],@tweak[1] + psrad \$31,$twtmp + aesenc $rndkey1,$inout1 + paddq @tweak[5],@tweak[5] + pand $twmask,$twtmp + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + movdqa @tweak[3],`16*3`(%rsp) + pxor $twtmp,@tweak[5] + aesenc $rndkey1,$inout4 + movaps @tweak[2],@tweak[3] + movdqa $twres,$twtmp + aesenc $rndkey1,$inout5 + $movkey -32($key),$rndkey1 + + paddd $twres,$twres + aesenc $rndkey0,$inout0 + pxor @tweak[5],@tweak[2] + psrad \$31,$twtmp + aesenc $rndkey0,$inout1 + paddq @tweak[5],@tweak[5] + pand $twmask,$twtmp + aesenc $rndkey0,$inout2 + aesenc $rndkey0,$inout3 + aesenc $rndkey0,$inout4 + pxor $twtmp,@tweak[5] + movaps @tweak[3],@tweak[4] + aesenc $rndkey0,$inout5 + + movdqa $twres,$rndkey0 + paddd $twres,$twres + aesenc $rndkey1,$inout0 + pxor @tweak[5],@tweak[3] + psrad \$31,$rndkey0 + aesenc $rndkey1,$inout1 + paddq @tweak[5],@tweak[5] + pand $twmask,$rndkey0 + aesenc $rndkey1,$inout2 + aesenc $rndkey1,$inout3 + pxor $rndkey0,@tweak[5] + $movkey ($key_),$rndkey0 + aesenc $rndkey1,$inout4 + aesenc $rndkey1,$inout5 + $movkey 16($key_),$rndkey1 + + pxor @tweak[5],@tweak[4] + aesenclast `16*0`(%rsp),$inout0 + psrad \$31,$twres + paddq @tweak[5],@tweak[5] + aesenclast `16*1`(%rsp),$inout1 + aesenclast `16*2`(%rsp),$inout2 + pand $twmask,$twres + mov %r10,%rax # restore $rounds + aesenclast `16*3`(%rsp),$inout3 + aesenclast `16*4`(%rsp),$inout4 + aesenclast `16*5`(%rsp),$inout5 + pxor $twres,@tweak[5] + + lea `16*6`($out),$out # $out+=6*16 + movups $inout0,`-16*6`($out) # store 6 output blocks + movups $inout1,`-16*5`($out) + movups $inout2,`-16*4`($out) + movups $inout3,`-16*3`($out) + movups $inout4,`-16*2`($out) + movups $inout5,`-16*1`($out) + sub \$16*6,$len + jnc .Lxts_enc_grandloop # loop if $len-=6*16 didn't borrow + + mov \$16+96,$rounds + sub $rnds_,$rounds + mov $key_,$key # restore $key + shr \$4,$rounds # restore original value + +.Lxts_enc_short: + # at the point @tweak[0..5] are populated with tweak values + mov $rounds,$rnds_ # backup $rounds + pxor $rndkey0,@tweak[0] + add \$16*6,$len # restore real remaining $len + jz .Lxts_enc_done # done if ($len==0) + + pxor $rndkey0,@tweak[1] + cmp \$0x20,$len + jb .Lxts_enc_one # $len is 1*16 + pxor $rndkey0,@tweak[2] + je .Lxts_enc_two # $len is 2*16 + + pxor $rndkey0,@tweak[3] + cmp \$0x40,$len + jb .Lxts_enc_three # $len is 3*16 + pxor $rndkey0,@tweak[4] + je .Lxts_enc_four # $len is 4*16 + + movdqu ($inp),$inout0 # $len is 5*16 + movdqu 16*1($inp),$inout1 + movdqu 16*2($inp),$inout2 + pxor @tweak[0],$inout0 + movdqu 16*3($inp),$inout3 + pxor @tweak[1],$inout1 + movdqu 16*4($inp),$inout4 + lea 16*5($inp),$inp # $inp+=5*16 + pxor @tweak[2],$inout2 + pxor @tweak[3],$inout3 + pxor @tweak[4],$inout4 + pxor $inout5,$inout5 + + call _aesni_encrypt6 + + xorps @tweak[0],$inout0 + movdqa @tweak[5],@tweak[0] + xorps @tweak[1],$inout1 + xorps @tweak[2],$inout2 + movdqu $inout0,($out) # store 5 output blocks + xorps @tweak[3],$inout3 + movdqu $inout1,16*1($out) + xorps @tweak[4],$inout4 + movdqu $inout2,16*2($out) + movdqu $inout3,16*3($out) + movdqu $inout4,16*4($out) + lea 16*5($out),$out # $out+=5*16 + jmp .Lxts_enc_done + +.align 16 +.Lxts_enc_one: + movups ($inp),$inout0 + lea 16*1($inp),$inp # inp+=1*16 + xorps @tweak[0],$inout0 +___ + &aesni_generate1("enc",$key,$rounds); +$code.=<<___; + xorps @tweak[0],$inout0 + movdqa @tweak[1],@tweak[0] + movups $inout0,($out) # store one output block + lea 16*1($out),$out # $out+=1*16 + jmp .Lxts_enc_done + +.align 16 +.Lxts_enc_two: + movups ($inp),$inout0 + movups 16($inp),$inout1 + lea 32($inp),$inp # $inp+=2*16 + xorps @tweak[0],$inout0 + xorps @tweak[1],$inout1 + + call _aesni_encrypt2 + + xorps @tweak[0],$inout0 + movdqa @tweak[2],@tweak[0] + xorps @tweak[1],$inout1 + movups $inout0,($out) # store 2 output blocks + movups $inout1,16*1($out) + lea 16*2($out),$out # $out+=2*16 + jmp .Lxts_enc_done + +.align 16 +.Lxts_enc_three: + movups ($inp),$inout0 + movups 16*1($inp),$inout1 + movups 16*2($inp),$inout2 + lea 16*3($inp),$inp # $inp+=3*16 + xorps @tweak[0],$inout0 + xorps @tweak[1],$inout1 + xorps @tweak[2],$inout2 + + call _aesni_encrypt3 + + xorps @tweak[0],$inout0 + movdqa @tweak[3],@tweak[0] + xorps @tweak[1],$inout1 + xorps @tweak[2],$inout2 + movups $inout0,($out) # store 3 output blocks + movups $inout1,16*1($out) + movups $inout2,16*2($out) + lea 16*3($out),$out # $out+=3*16 + jmp .Lxts_enc_done + +.align 16 +.Lxts_enc_four: + movups ($inp),$inout0 + movups 16*1($inp),$inout1 + movups 16*2($inp),$inout2 + xorps @tweak[0],$inout0 + movups 16*3($inp),$inout3 + lea 16*4($inp),$inp # $inp+=4*16 + xorps @tweak[1],$inout1 + xorps @tweak[2],$inout2 + xorps @tweak[3],$inout3 + + call _aesni_encrypt4 + + pxor @tweak[0],$inout0 + movdqa @tweak[4],@tweak[0] + pxor @tweak[1],$inout1 + pxor @tweak[2],$inout2 + movdqu $inout0,($out) # store 4 output blocks + pxor @tweak[3],$inout3 + movdqu $inout1,16*1($out) + movdqu $inout2,16*2($out) + movdqu $inout3,16*3($out) + lea 16*4($out),$out # $out+=4*16 + jmp .Lxts_enc_done + +.align 16 +.Lxts_enc_done: + and \$15,$len_ # see if $len%16 is 0 + jz .Lxts_enc_ret + mov $len_,$len + +.Lxts_enc_steal: + movzb ($inp),%eax # borrow $rounds ... + movzb -16($out),%ecx # ... and $key + lea 1($inp),$inp + mov %al,-16($out) + mov %cl,0($out) + lea 1($out),$out + sub \$1,$len + jnz .Lxts_enc_steal + + sub $len_,$out # rewind $out + mov $key_,$key # restore $key + mov $rnds_,$rounds # restore $rounds + + movups -16($out),$inout0 + xorps @tweak[0],$inout0 +___ + &aesni_generate1("enc",$key,$rounds); +$code.=<<___; + xorps @tweak[0],$inout0 + movups $inout0,-16($out) + +.Lxts_enc_ret: + xorps %xmm0,%xmm0 # clear register bank + pxor %xmm1,%xmm1 + pxor %xmm2,%xmm2 + pxor %xmm3,%xmm3 + pxor %xmm4,%xmm4 + pxor %xmm5,%xmm5 +___ +$code.=<<___ if (!$win64); + pxor %xmm6,%xmm6 + pxor %xmm7,%xmm7 + movaps %xmm0,0x00(%rsp) # clear stack + pxor %xmm8,%xmm8 + movaps %xmm0,0x10(%rsp) + pxor %xmm9,%xmm9 + movaps %xmm0,0x20(%rsp) + pxor %xmm10,%xmm10 + movaps %xmm0,0x30(%rsp) + pxor %xmm11,%xmm11 + movaps %xmm0,0x40(%rsp) + pxor %xmm12,%xmm12 + movaps %xmm0,0x50(%rsp) + pxor %xmm13,%xmm13 + movaps %xmm0,0x60(%rsp) + pxor %xmm14,%xmm14 + pxor %xmm15,%xmm15 +___ +$code.=<<___ if ($win64); + movaps -0xa0(%rbp),%xmm6 + movaps %xmm0,-0xa0(%rbp) # clear stack + movaps -0x90(%rbp),%xmm7 + movaps %xmm0,-0x90(%rbp) + movaps -0x80(%rbp),%xmm8 + movaps %xmm0,-0x80(%rbp) + movaps -0x70(%rbp),%xmm9 + movaps %xmm0,-0x70(%rbp) + movaps -0x60(%rbp),%xmm10 + movaps %xmm0,-0x60(%rbp) + movaps -0x50(%rbp),%xmm11 + movaps %xmm0,-0x50(%rbp) + movaps -0x40(%rbp),%xmm12 + movaps %xmm0,-0x40(%rbp) + movaps -0x30(%rbp),%xmm13 + movaps %xmm0,-0x30(%rbp) + movaps -0x20(%rbp),%xmm14 + movaps %xmm0,-0x20(%rbp) + movaps -0x10(%rbp),%xmm15 + movaps %xmm0,-0x10(%rbp) + movaps %xmm0,0x00(%rsp) + movaps %xmm0,0x10(%rsp) + movaps %xmm0,0x20(%rsp) + movaps %xmm0,0x30(%rsp) + movaps %xmm0,0x40(%rsp) + movaps %xmm0,0x50(%rsp) + movaps %xmm0,0x60(%rsp) +___ +$code.=<<___; + lea (%rbp),%rsp + pop %rbp +.Lxts_enc_epilogue: + ret +.size aesni_xts_encrypt,.-aesni_xts_encrypt +___ + +$code.=<<___; +.globl aesni_xts_decrypt +.type aesni_xts_decrypt,\@function,6 +.align 16 +aesni_xts_decrypt: + lea (%rsp),%rax + push %rbp + sub \$$frame_size,%rsp + and \$-16,%rsp # Linux kernel stack can be incorrectly seeded +___ +$code.=<<___ if ($win64); + movaps %xmm6,-0xa8(%rax) # offload everything + movaps %xmm7,-0x98(%rax) + movaps %xmm8,-0x88(%rax) + movaps %xmm9,-0x78(%rax) + movaps %xmm10,-0x68(%rax) + movaps %xmm11,-0x58(%rax) + movaps %xmm12,-0x48(%rax) + movaps %xmm13,-0x38(%rax) + movaps %xmm14,-0x28(%rax) + movaps %xmm15,-0x18(%rax) +.Lxts_dec_body: +___ +$code.=<<___; + lea -8(%rax),%rbp + movups ($ivp),$inout0 # load clear-text tweak + mov 240($key2),$rounds # key2->rounds + mov 240($key),$rnds_ # key1->rounds +___ + # generate the tweak + &aesni_generate1("enc",$key2,$rounds,$inout0); +$code.=<<___; + xor %eax,%eax # if ($len%16) len-=16; + test \$15,$len + setnz %al + shl \$4,%rax + sub %rax,$len + + $movkey ($key),$rndkey0 # zero round key + mov $key,$key_ # backup $key + mov $rnds_,$rounds # backup $rounds + shl \$4,$rnds_ + mov $len,$len_ # backup $len + and \$-16,$len + + $movkey 16($key,$rnds_),$rndkey1 # last round key + + movdqa .Lxts_magic(%rip),$twmask + movdqa $inout0,@tweak[5] + pshufd \$0x5f,$inout0,$twres + pxor $rndkey0,$rndkey1 +___ + for ($i=0;$i<4;$i++) { + $code.=<<___; + movdqa $twres,$twtmp + paddd $twres,$twres + movdqa @tweak[5],@tweak[$i] + psrad \$31,$twtmp # broadcast upper bits + paddq @tweak[5],@tweak[5] + pand $twmask,$twtmp + pxor $rndkey0,@tweak[$i] + pxor $twtmp,@tweak[5] +___ + } +$code.=<<___; + movdqa @tweak[5],@tweak[4] + psrad \$31,$twres + paddq @tweak[5],@tweak[5] + pand $twmask,$twres + pxor $rndkey0,@tweak[4] + pxor $twres,@tweak[5] + movaps $rndkey1,0x60(%rsp) # save round[0]^round[last] + + sub \$16*6,$len + jc .Lxts_dec_short # if $len-=6*16 borrowed + + mov \$16+96,$rounds + lea 32($key_,$rnds_),$key # end of key schedule + sub %r10,%rax # twisted $rounds + $movkey 16($key_),$rndkey1 + mov %rax,%r10 # backup twisted $rounds + lea .Lxts_magic(%rip),%r8 + jmp .Lxts_dec_grandloop + +.align 32 +.Lxts_dec_grandloop: + movdqu `16*0`($inp),$inout0 # load input + movdqa $rndkey0,$twmask + movdqu `16*1`($inp),$inout1 + pxor @tweak[0],$inout0 # intput^=tweak^round[0] + movdqu `16*2`($inp),$inout2 + pxor @tweak[1],$inout1 + aesdec $rndkey1,$inout0 + movdqu `16*3`($inp),$inout3 + pxor @tweak[2],$inout2 + aesdec $rndkey1,$inout1 + movdqu `16*4`($inp),$inout4 + pxor @tweak[3],$inout3 + aesdec $rndkey1,$inout2 + movdqu `16*5`($inp),$inout5 + pxor @tweak[5],$twmask # round[0]^=tweak[5] + movdqa 0x60(%rsp),$twres # load round[0]^round[last] + pxor @tweak[4],$inout4 + aesdec $rndkey1,$inout3 + $movkey 32($key_),$rndkey0 + lea `16*6`($inp),$inp + pxor $twmask,$inout5 + + pxor $twres,@tweak[0] # calclulate tweaks^round[last] + aesdec $rndkey1,$inout4 + pxor $twres,@tweak[1] + movdqa @tweak[0],`16*0`(%rsp) # put aside tweaks^last round key + aesdec $rndkey1,$inout5 + $movkey 48($key_),$rndkey1 + pxor $twres,@tweak[2] + + aesdec $rndkey0,$inout0 + pxor $twres,@tweak[3] + movdqa @tweak[1],`16*1`(%rsp) + aesdec $rndkey0,$inout1 + pxor $twres,@tweak[4] + movdqa @tweak[2],`16*2`(%rsp) + aesdec $rndkey0,$inout2 + aesdec $rndkey0,$inout3 + pxor $twres,$twmask + movdqa @tweak[4],`16*4`(%rsp) + aesdec $rndkey0,$inout4 + aesdec $rndkey0,$inout5 + $movkey 64($key_),$rndkey0 + movdqa $twmask,`16*5`(%rsp) + pshufd \$0x5f,@tweak[5],$twres + jmp .Lxts_dec_loop6 +.align 32 +.Lxts_dec_loop6: + aesdec $rndkey1,$inout0 + aesdec $rndkey1,$inout1 + aesdec $rndkey1,$inout2 + aesdec $rndkey1,$inout3 + aesdec $rndkey1,$inout4 + aesdec $rndkey1,$inout5 + $movkey -64($key,%rax),$rndkey1 + add \$32,%rax + + aesdec $rndkey0,$inout0 + aesdec $rndkey0,$inout1 + aesdec $rndkey0,$inout2 + aesdec $rndkey0,$inout3 + aesdec $rndkey0,$inout4 + aesdec $rndkey0,$inout5 + $movkey -80($key,%rax),$rndkey0 + jnz .Lxts_dec_loop6 + + movdqa (%r8),$twmask # start calculating next tweak + movdqa $twres,$twtmp + paddd $twres,$twres + aesdec $rndkey1,$inout0 + paddq @tweak[5],@tweak[5] + psrad \$31,$twtmp + aesdec $rndkey1,$inout1 + pand $twmask,$twtmp + $movkey ($key_),@tweak[0] # load round[0] + aesdec $rndkey1,$inout2 + aesdec $rndkey1,$inout3 + aesdec $rndkey1,$inout4 + pxor $twtmp,@tweak[5] + movaps @tweak[0],@tweak[1] # copy round[0] + aesdec $rndkey1,$inout5 + $movkey -64($key),$rndkey1 + + movdqa $twres,$twtmp + aesdec $rndkey0,$inout0 + paddd $twres,$twres + pxor @tweak[5],@tweak[0] + aesdec $rndkey0,$inout1 + psrad \$31,$twtmp + paddq @tweak[5],@tweak[5] + aesdec $rndkey0,$inout2 + aesdec $rndkey0,$inout3 + pand $twmask,$twtmp + movaps @tweak[1],@tweak[2] + aesdec $rndkey0,$inout4 + pxor $twtmp,@tweak[5] + movdqa $twres,$twtmp + aesdec $rndkey0,$inout5 + $movkey -48($key),$rndkey0 + + paddd $twres,$twres + aesdec $rndkey1,$inout0 + pxor @tweak[5],@tweak[1] + psrad \$31,$twtmp + aesdec $rndkey1,$inout1 + paddq @tweak[5],@tweak[5] + pand $twmask,$twtmp + aesdec $rndkey1,$inout2 + aesdec $rndkey1,$inout3 + movdqa @tweak[3],`16*3`(%rsp) + pxor $twtmp,@tweak[5] + aesdec $rndkey1,$inout4 + movaps @tweak[2],@tweak[3] + movdqa $twres,$twtmp + aesdec $rndkey1,$inout5 + $movkey -32($key),$rndkey1 + + paddd $twres,$twres + aesdec $rndkey0,$inout0 + pxor @tweak[5],@tweak[2] + psrad \$31,$twtmp + aesdec $rndkey0,$inout1 + paddq @tweak[5],@tweak[5] + pand $twmask,$twtmp + aesdec $rndkey0,$inout2 + aesdec $rndkey0,$inout3 + aesdec $rndkey0,$inout4 + pxor $twtmp,@tweak[5] + movaps @tweak[3],@tweak[4] + aesdec $rndkey0,$inout5 + + movdqa $twres,$rndkey0 + paddd $twres,$twres + aesdec $rndkey1,$inout0 + pxor @tweak[5],@tweak[3] + psrad \$31,$rndkey0 + aesdec $rndkey1,$inout1 + paddq @tweak[5],@tweak[5] + pand $twmask,$rndkey0 + aesdec $rndkey1,$inout2 + aesdec $rndkey1,$inout3 + pxor $rndkey0,@tweak[5] + $movkey ($key_),$rndkey0 + aesdec $rndkey1,$inout4 + aesdec $rndkey1,$inout5 + $movkey 16($key_),$rndkey1 + + pxor @tweak[5],@tweak[4] + aesdeclast `16*0`(%rsp),$inout0 + psrad \$31,$twres + paddq @tweak[5],@tweak[5] + aesdeclast `16*1`(%rsp),$inout1 + aesdeclast `16*2`(%rsp),$inout2 + pand $twmask,$twres + mov %r10,%rax # restore $rounds + aesdeclast `16*3`(%rsp),$inout3 + aesdeclast `16*4`(%rsp),$inout4 + aesdeclast `16*5`(%rsp),$inout5 + pxor $twres,@tweak[5] + + lea `16*6`($out),$out # $out+=6*16 + movups $inout0,`-16*6`($out) # store 6 output blocks + movups $inout1,`-16*5`($out) + movups $inout2,`-16*4`($out) + movups $inout3,`-16*3`($out) + movups $inout4,`-16*2`($out) + movups $inout5,`-16*1`($out) + sub \$16*6,$len + jnc .Lxts_dec_grandloop # loop if $len-=6*16 didn't borrow + + mov \$16+96,$rounds + sub $rnds_,$rounds + mov $key_,$key # restore $key + shr \$4,$rounds # restore original value + +.Lxts_dec_short: + # at the point @tweak[0..5] are populated with tweak values + mov $rounds,$rnds_ # backup $rounds + pxor $rndkey0,@tweak[0] + pxor $rndkey0,@tweak[1] + add \$16*6,$len # restore real remaining $len + jz .Lxts_dec_done # done if ($len==0) + + pxor $rndkey0,@tweak[2] + cmp \$0x20,$len + jb .Lxts_dec_one # $len is 1*16 + pxor $rndkey0,@tweak[3] + je .Lxts_dec_two # $len is 2*16 + + pxor $rndkey0,@tweak[4] + cmp \$0x40,$len + jb .Lxts_dec_three # $len is 3*16 + je .Lxts_dec_four # $len is 4*16 + + movdqu ($inp),$inout0 # $len is 5*16 + movdqu 16*1($inp),$inout1 + movdqu 16*2($inp),$inout2 + pxor @tweak[0],$inout0 + movdqu 16*3($inp),$inout3 + pxor @tweak[1],$inout1 + movdqu 16*4($inp),$inout4 + lea 16*5($inp),$inp # $inp+=5*16 + pxor @tweak[2],$inout2 + pxor @tweak[3],$inout3 + pxor @tweak[4],$inout4 + + call _aesni_decrypt6 + + xorps @tweak[0],$inout0 + xorps @tweak[1],$inout1 + xorps @tweak[2],$inout2 + movdqu $inout0,($out) # store 5 output blocks + xorps @tweak[3],$inout3 + movdqu $inout1,16*1($out) + xorps @tweak[4],$inout4 + movdqu $inout2,16*2($out) + pxor $twtmp,$twtmp + movdqu $inout3,16*3($out) + pcmpgtd @tweak[5],$twtmp + movdqu $inout4,16*4($out) + lea 16*5($out),$out # $out+=5*16 + pshufd \$0x13,$twtmp,@tweak[1] # $twres + and \$15,$len_ + jz .Lxts_dec_ret + + movdqa @tweak[5],@tweak[0] + paddq @tweak[5],@tweak[5] # psllq 1,$tweak + pand $twmask,@tweak[1] # isolate carry and residue + pxor @tweak[5],@tweak[1] + jmp .Lxts_dec_done2 + +.align 16 +.Lxts_dec_one: + movups ($inp),$inout0 + lea 16*1($inp),$inp # $inp+=1*16 + xorps @tweak[0],$inout0 +___ + &aesni_generate1("dec",$key,$rounds); +$code.=<<___; + xorps @tweak[0],$inout0 + movdqa @tweak[1],@tweak[0] + movups $inout0,($out) # store one output block + movdqa @tweak[2],@tweak[1] + lea 16*1($out),$out # $out+=1*16 + jmp .Lxts_dec_done + +.align 16 +.Lxts_dec_two: + movups ($inp),$inout0 + movups 16($inp),$inout1 + lea 32($inp),$inp # $inp+=2*16 + xorps @tweak[0],$inout0 + xorps @tweak[1],$inout1 + + call _aesni_decrypt2 + + xorps @tweak[0],$inout0 + movdqa @tweak[2],@tweak[0] + xorps @tweak[1],$inout1 + movdqa @tweak[3],@tweak[1] + movups $inout0,($out) # store 2 output blocks + movups $inout1,16*1($out) + lea 16*2($out),$out # $out+=2*16 + jmp .Lxts_dec_done + +.align 16 +.Lxts_dec_three: + movups ($inp),$inout0 + movups 16*1($inp),$inout1 + movups 16*2($inp),$inout2 + lea 16*3($inp),$inp # $inp+=3*16 + xorps @tweak[0],$inout0 + xorps @tweak[1],$inout1 + xorps @tweak[2],$inout2 + + call _aesni_decrypt3 + + xorps @tweak[0],$inout0 + movdqa @tweak[3],@tweak[0] + xorps @tweak[1],$inout1 + movdqa @tweak[4],@tweak[1] + xorps @tweak[2],$inout2 + movups $inout0,($out) # store 3 output blocks + movups $inout1,16*1($out) + movups $inout2,16*2($out) + lea 16*3($out),$out # $out+=3*16 + jmp .Lxts_dec_done + +.align 16 +.Lxts_dec_four: + movups ($inp),$inout0 + movups 16*1($inp),$inout1 + movups 16*2($inp),$inout2 + xorps @tweak[0],$inout0 + movups 16*3($inp),$inout3 + lea 16*4($inp),$inp # $inp+=4*16 + xorps @tweak[1],$inout1 + xorps @tweak[2],$inout2 + xorps @tweak[3],$inout3 + + call _aesni_decrypt4 + + pxor @tweak[0],$inout0 + movdqa @tweak[4],@tweak[0] + pxor @tweak[1],$inout1 + movdqa @tweak[5],@tweak[1] + pxor @tweak[2],$inout2 + movdqu $inout0,($out) # store 4 output blocks + pxor @tweak[3],$inout3 + movdqu $inout1,16*1($out) + movdqu $inout2,16*2($out) + movdqu $inout3,16*3($out) + lea 16*4($out),$out # $out+=4*16 + jmp .Lxts_dec_done + +.align 16 +.Lxts_dec_done: + and \$15,$len_ # see if $len%16 is 0 + jz .Lxts_dec_ret +.Lxts_dec_done2: + mov $len_,$len + mov $key_,$key # restore $key + mov $rnds_,$rounds # restore $rounds + + movups ($inp),$inout0 + xorps @tweak[1],$inout0 +___ + &aesni_generate1("dec",$key,$rounds); +$code.=<<___; + xorps @tweak[1],$inout0 + movups $inout0,($out) + +.Lxts_dec_steal: + movzb 16($inp),%eax # borrow $rounds ... + movzb ($out),%ecx # ... and $key + lea 1($inp),$inp + mov %al,($out) + mov %cl,16($out) + lea 1($out),$out + sub \$1,$len + jnz .Lxts_dec_steal + + sub $len_,$out # rewind $out + mov $key_,$key # restore $key + mov $rnds_,$rounds # restore $rounds + + movups ($out),$inout0 + xorps @tweak[0],$inout0 +___ + &aesni_generate1("dec",$key,$rounds); +$code.=<<___; + xorps @tweak[0],$inout0 + movups $inout0,($out) + +.Lxts_dec_ret: + xorps %xmm0,%xmm0 # clear register bank + pxor %xmm1,%xmm1 + pxor %xmm2,%xmm2 + pxor %xmm3,%xmm3 + pxor %xmm4,%xmm4 + pxor %xmm5,%xmm5 +___ +$code.=<<___ if (!$win64); + pxor %xmm6,%xmm6 + pxor %xmm7,%xmm7 + movaps %xmm0,0x00(%rsp) # clear stack + pxor %xmm8,%xmm8 + movaps %xmm0,0x10(%rsp) + pxor %xmm9,%xmm9 + movaps %xmm0,0x20(%rsp) + pxor %xmm10,%xmm10 + movaps %xmm0,0x30(%rsp) + pxor %xmm11,%xmm11 + movaps %xmm0,0x40(%rsp) + pxor %xmm12,%xmm12 + movaps %xmm0,0x50(%rsp) + pxor %xmm13,%xmm13 + movaps %xmm0,0x60(%rsp) + pxor %xmm14,%xmm14 + pxor %xmm15,%xmm15 +___ +$code.=<<___ if ($win64); + movaps -0xa0(%rbp),%xmm6 + movaps %xmm0,-0xa0(%rbp) # clear stack + movaps -0x90(%rbp),%xmm7 + movaps %xmm0,-0x90(%rbp) + movaps -0x80(%rbp),%xmm8 + movaps %xmm0,-0x80(%rbp) + movaps -0x70(%rbp),%xmm9 + movaps %xmm0,-0x70(%rbp) + movaps -0x60(%rbp),%xmm10 + movaps %xmm0,-0x60(%rbp) + movaps -0x50(%rbp),%xmm11 + movaps %xmm0,-0x50(%rbp) + movaps -0x40(%rbp),%xmm12 + movaps %xmm0,-0x40(%rbp) + movaps -0x30(%rbp),%xmm13 + movaps %xmm0,-0x30(%rbp) + movaps -0x20(%rbp),%xmm14 + movaps %xmm0,-0x20(%rbp) + movaps -0x10(%rbp),%xmm15 + movaps %xmm0,-0x10(%rbp) + movaps %xmm0,0x00(%rsp) + movaps %xmm0,0x10(%rsp) + movaps %xmm0,0x20(%rsp) + movaps %xmm0,0x30(%rsp) + movaps %xmm0,0x40(%rsp) + movaps %xmm0,0x50(%rsp) + movaps %xmm0,0x60(%rsp) +___ +$code.=<<___; + lea (%rbp),%rsp + pop %rbp +.Lxts_dec_epilogue: + ret +.size aesni_xts_decrypt,.-aesni_xts_decrypt +___ +} }} + +######################################################################## +# void $PREFIX_cbc_encrypt (const void *inp, void *out, +# size_t length, const AES_KEY *key, +# unsigned char *ivp,const int enc); +{ +my $frame_size = 0x10 + ($win64?0xa0:0); # used in decrypt +my ($iv,$in0,$in1,$in2,$in3,$in4)=map("%xmm$_",(10..15)); +my $inp_=$key_; + +$code.=<<___; +.globl ${PREFIX}_cbc_encrypt +.type ${PREFIX}_cbc_encrypt,\@function,6 +.align 16 +${PREFIX}_cbc_encrypt: + test $len,$len # check length + jz .Lcbc_ret + + mov 240($key),$rnds_ # key->rounds + mov $key,$key_ # backup $key + test %r9d,%r9d # 6th argument + jz .Lcbc_decrypt +#--------------------------- CBC ENCRYPT ------------------------------# + movups ($ivp),$inout0 # load iv as initial state + mov $rnds_,$rounds + cmp \$16,$len + jb .Lcbc_enc_tail + sub \$16,$len + jmp .Lcbc_enc_loop +.align 16 +.Lcbc_enc_loop: + movups ($inp),$inout1 # load input + lea 16($inp),$inp + #xorps $inout1,$inout0 +___ + &aesni_generate1("enc",$key,$rounds,$inout0,$inout1); +$code.=<<___; + mov $rnds_,$rounds # restore $rounds + mov $key_,$key # restore $key + movups $inout0,0($out) # store output + lea 16($out),$out + sub \$16,$len + jnc .Lcbc_enc_loop + add \$16,$len + jnz .Lcbc_enc_tail + pxor $rndkey0,$rndkey0 # clear register bank + pxor $rndkey1,$rndkey1 + movups $inout0,($ivp) + pxor $inout0,$inout0 + pxor $inout1,$inout1 + jmp .Lcbc_ret + +.Lcbc_enc_tail: + mov $len,%rcx # zaps $key + xchg $inp,$out # $inp is %rsi and $out is %rdi now + .long 0x9066A4F3 # rep movsb + mov \$16,%ecx # zero tail + sub $len,%rcx + xor %eax,%eax + .long 0x9066AAF3 # rep stosb + lea -16(%rdi),%rdi # rewind $out by 1 block + mov $rnds_,$rounds # restore $rounds + mov %rdi,%rsi # $inp and $out are the same + mov $key_,$key # restore $key + xor $len,$len # len=16 + jmp .Lcbc_enc_loop # one more spin + #--------------------------- CBC DECRYPT ------------------------------# +.align 16 +.Lcbc_decrypt: + cmp \$16,$len + jne .Lcbc_decrypt_bulk + + # handle single block without allocating stack frame, + # useful in ciphertext stealing mode + movdqu ($inp),$inout0 # load input + movdqu ($ivp),$inout1 # load iv + movdqa $inout0,$inout2 # future iv +___ + &aesni_generate1("dec",$key,$rnds_); +$code.=<<___; + pxor $rndkey0,$rndkey0 # clear register bank + pxor $rndkey1,$rndkey1 + movdqu $inout2,($ivp) # store iv + xorps $inout1,$inout0 # ^=iv + pxor $inout1,$inout1 + movups $inout0,($out) # store output + pxor $inout0,$inout0 + jmp .Lcbc_ret +.align 16 +.Lcbc_decrypt_bulk: + lea (%rsp),%rax + push %rbp + sub \$$frame_size,%rsp + and \$-16,%rsp # Linux kernel stack can be incorrectly seeded +___ +$code.=<<___ if ($win64); + movaps %xmm6,0x10(%rsp) + movaps %xmm7,0x20(%rsp) + movaps %xmm8,0x30(%rsp) + movaps %xmm9,0x40(%rsp) + movaps %xmm10,0x50(%rsp) + movaps %xmm11,0x60(%rsp) + movaps %xmm12,0x70(%rsp) + movaps %xmm13,0x80(%rsp) + movaps %xmm14,0x90(%rsp) + movaps %xmm15,0xa0(%rsp) +.Lcbc_decrypt_body: +___ +$code.=<<___; + lea -8(%rax),%rbp + movups ($ivp),$iv + mov $rnds_,$rounds + cmp \$0x50,$len + jbe .Lcbc_dec_tail + + $movkey ($key),$rndkey0 + movdqu 0x00($inp),$inout0 # load input + movdqu 0x10($inp),$inout1 + movdqa $inout0,$in0 + movdqu 0x20($inp),$inout2 + movdqa $inout1,$in1 + movdqu 0x30($inp),$inout3 + movdqa $inout2,$in2 + movdqu 0x40($inp),$inout4 + movdqa $inout3,$in3 + movdqu 0x50($inp),$inout5 + movdqa $inout4,$in4 + mov OPENSSL_ia32cap_P+4(%rip),%r9d + cmp \$0x70,$len + jbe .Lcbc_dec_six_or_seven + + and \$`1<<26|1<<22`,%r9d # isolate XSAVE+MOVBE + sub \$0x50,$len # $len is biased by -5*16 + cmp \$`1<<22`,%r9d # check for MOVBE without XSAVE + je .Lcbc_dec_loop6_enter # [which denotes Atom Silvermont] + sub \$0x20,$len # $len is biased by -7*16 + lea 0x70($key),$key # size optimization + jmp .Lcbc_dec_loop8_enter +.align 16 +.Lcbc_dec_loop8: + movups $inout7,($out) + lea 0x10($out),$out +.Lcbc_dec_loop8_enter: + movdqu 0x60($inp),$inout6 + pxor $rndkey0,$inout0 + movdqu 0x70($inp),$inout7 + pxor $rndkey0,$inout1 + $movkey 0x10-0x70($key),$rndkey1 + pxor $rndkey0,$inout2 + xor $inp_,$inp_ + cmp \$0x70,$len # is there at least 0x60 bytes ahead? + pxor $rndkey0,$inout3 + pxor $rndkey0,$inout4 + pxor $rndkey0,$inout5 + pxor $rndkey0,$inout6 + + aesdec $rndkey1,$inout0 + pxor $rndkey0,$inout7 + $movkey 0x20-0x70($key),$rndkey0 + aesdec $rndkey1,$inout1 + aesdec $rndkey1,$inout2 + aesdec $rndkey1,$inout3 + aesdec $rndkey1,$inout4 + aesdec $rndkey1,$inout5 + aesdec $rndkey1,$inout6 + setnc ${inp_}b + shl \$7,$inp_ + aesdec $rndkey1,$inout7 + add $inp,$inp_ + $movkey 0x30-0x70($key),$rndkey1 +___ +for($i=1;$i<12;$i++) { +my $rndkeyx = ($i&1)?$rndkey0:$rndkey1; +$code.=<<___ if ($i==7); + cmp \$11,$rounds +___ +$code.=<<___; + aesdec $rndkeyx,$inout0 + aesdec $rndkeyx,$inout1 + aesdec $rndkeyx,$inout2 + aesdec $rndkeyx,$inout3 + aesdec $rndkeyx,$inout4 + aesdec $rndkeyx,$inout5 + aesdec $rndkeyx,$inout6 + aesdec $rndkeyx,$inout7 + $movkey `0x30+0x10*$i`-0x70($key),$rndkeyx +___ +$code.=<<___ if ($i<6 || (!($i&1) && $i>7)); + nop +___ +$code.=<<___ if ($i==7); + jb .Lcbc_dec_done +___ +$code.=<<___ if ($i==9); + je .Lcbc_dec_done +___ +$code.=<<___ if ($i==11); + jmp .Lcbc_dec_done +___ +} +$code.=<<___; +.align 16 +.Lcbc_dec_done: + aesdec $rndkey1,$inout0 + aesdec $rndkey1,$inout1 + pxor $rndkey0,$iv + pxor $rndkey0,$in0 + aesdec $rndkey1,$inout2 + aesdec $rndkey1,$inout3 + pxor $rndkey0,$in1 + pxor $rndkey0,$in2 + aesdec $rndkey1,$inout4 + aesdec $rndkey1,$inout5 + pxor $rndkey0,$in3 + pxor $rndkey0,$in4 + aesdec $rndkey1,$inout6 + aesdec $rndkey1,$inout7 + movdqu 0x50($inp),$rndkey1 + + aesdeclast $iv,$inout0 + movdqu 0x60($inp),$iv # borrow $iv + pxor $rndkey0,$rndkey1 + aesdeclast $in0,$inout1 + pxor $rndkey0,$iv + movdqu 0x70($inp),$rndkey0 # next IV + aesdeclast $in1,$inout2 + lea 0x80($inp),$inp + movdqu 0x00($inp_),$in0 + aesdeclast $in2,$inout3 + aesdeclast $in3,$inout4 + movdqu 0x10($inp_),$in1 + movdqu 0x20($inp_),$in2 + aesdeclast $in4,$inout5 + aesdeclast $rndkey1,$inout6 + movdqu 0x30($inp_),$in3 + movdqu 0x40($inp_),$in4 + aesdeclast $iv,$inout7 + movdqa $rndkey0,$iv # return $iv + movdqu 0x50($inp_),$rndkey1 + $movkey -0x70($key),$rndkey0 + + movups $inout0,($out) # store output + movdqa $in0,$inout0 + movups $inout1,0x10($out) + movdqa $in1,$inout1 + movups $inout2,0x20($out) + movdqa $in2,$inout2 + movups $inout3,0x30($out) + movdqa $in3,$inout3 + movups $inout4,0x40($out) + movdqa $in4,$inout4 + movups $inout5,0x50($out) + movdqa $rndkey1,$inout5 + movups $inout6,0x60($out) + lea 0x70($out),$out + + sub \$0x80,$len + ja .Lcbc_dec_loop8 + + movaps $inout7,$inout0 + lea -0x70($key),$key + add \$0x70,$len + jle .Lcbc_dec_clear_tail_collected + movups $inout7,($out) + lea 0x10($out),$out + cmp \$0x50,$len + jbe .Lcbc_dec_tail + + movaps $in0,$inout0 +.Lcbc_dec_six_or_seven: + cmp \$0x60,$len + ja .Lcbc_dec_seven + + movaps $inout5,$inout6 + call _aesni_decrypt6 + pxor $iv,$inout0 # ^= IV + movaps $inout6,$iv + pxor $in0,$inout1 + movdqu $inout0,($out) + pxor $in1,$inout2 + movdqu $inout1,0x10($out) + pxor $inout1,$inout1 # clear register bank + pxor $in2,$inout3 + movdqu $inout2,0x20($out) + pxor $inout2,$inout2 + pxor $in3,$inout4 + movdqu $inout3,0x30($out) + pxor $inout3,$inout3 + pxor $in4,$inout5 + movdqu $inout4,0x40($out) + pxor $inout4,$inout4 + lea 0x50($out),$out + movdqa $inout5,$inout0 + pxor $inout5,$inout5 + jmp .Lcbc_dec_tail_collected + +.align 16 +.Lcbc_dec_seven: + movups 0x60($inp),$inout6 + xorps $inout7,$inout7 + call _aesni_decrypt8 + movups 0x50($inp),$inout7 + pxor $iv,$inout0 # ^= IV + movups 0x60($inp),$iv + pxor $in0,$inout1 + movdqu $inout0,($out) + pxor $in1,$inout2 + movdqu $inout1,0x10($out) + pxor $inout1,$inout1 # clear register bank + pxor $in2,$inout3 + movdqu $inout2,0x20($out) + pxor $inout2,$inout2 + pxor $in3,$inout4 + movdqu $inout3,0x30($out) + pxor $inout3,$inout3 + pxor $in4,$inout5 + movdqu $inout4,0x40($out) + pxor $inout4,$inout4 + pxor $inout7,$inout6 + movdqu $inout5,0x50($out) + pxor $inout5,$inout5 + lea 0x60($out),$out + movdqa $inout6,$inout0 + pxor $inout6,$inout6 + pxor $inout7,$inout7 + jmp .Lcbc_dec_tail_collected + +.align 16 +.Lcbc_dec_loop6: + movups $inout5,($out) + lea 0x10($out),$out + movdqu 0x00($inp),$inout0 # load input + movdqu 0x10($inp),$inout1 + movdqa $inout0,$in0 + movdqu 0x20($inp),$inout2 + movdqa $inout1,$in1 + movdqu 0x30($inp),$inout3 + movdqa $inout2,$in2 + movdqu 0x40($inp),$inout4 + movdqa $inout3,$in3 + movdqu 0x50($inp),$inout5 + movdqa $inout4,$in4 +.Lcbc_dec_loop6_enter: + lea 0x60($inp),$inp + movdqa $inout5,$inout6 + + call _aesni_decrypt6 + + pxor $iv,$inout0 # ^= IV + movdqa $inout6,$iv + pxor $in0,$inout1 + movdqu $inout0,($out) + pxor $in1,$inout2 + movdqu $inout1,0x10($out) + pxor $in2,$inout3 + movdqu $inout2,0x20($out) + pxor $in3,$inout4 + mov $key_,$key + movdqu $inout3,0x30($out) + pxor $in4,$inout5 + mov $rnds_,$rounds + movdqu $inout4,0x40($out) + lea 0x50($out),$out + sub \$0x60,$len + ja .Lcbc_dec_loop6 + + movdqa $inout5,$inout0 + add \$0x50,$len + jle .Lcbc_dec_clear_tail_collected + movups $inout5,($out) + lea 0x10($out),$out + +.Lcbc_dec_tail: + movups ($inp),$inout0 + sub \$0x10,$len + jbe .Lcbc_dec_one # $len is 1*16 or less + + movups 0x10($inp),$inout1 + movaps $inout0,$in0 + sub \$0x10,$len + jbe .Lcbc_dec_two # $len is 2*16 or less + + movups 0x20($inp),$inout2 + movaps $inout1,$in1 + sub \$0x10,$len + jbe .Lcbc_dec_three # $len is 3*16 or less + + movups 0x30($inp),$inout3 + movaps $inout2,$in2 + sub \$0x10,$len + jbe .Lcbc_dec_four # $len is 4*16 or less + + movups 0x40($inp),$inout4 # $len is 5*16 or less + movaps $inout3,$in3 + movaps $inout4,$in4 + xorps $inout5,$inout5 + call _aesni_decrypt6 + pxor $iv,$inout0 + movaps $in4,$iv + pxor $in0,$inout1 + movdqu $inout0,($out) + pxor $in1,$inout2 + movdqu $inout1,0x10($out) + pxor $inout1,$inout1 # clear register bank + pxor $in2,$inout3 + movdqu $inout2,0x20($out) + pxor $inout2,$inout2 + pxor $in3,$inout4 + movdqu $inout3,0x30($out) + pxor $inout3,$inout3 + lea 0x40($out),$out + movdqa $inout4,$inout0 + pxor $inout4,$inout4 + pxor $inout5,$inout5 + sub \$0x10,$len + jmp .Lcbc_dec_tail_collected + +.align 16 +.Lcbc_dec_one: + movaps $inout0,$in0 +___ + &aesni_generate1("dec",$key,$rounds); +$code.=<<___; + xorps $iv,$inout0 + movaps $in0,$iv + jmp .Lcbc_dec_tail_collected +.align 16 +.Lcbc_dec_two: + movaps $inout1,$in1 + call _aesni_decrypt2 + pxor $iv,$inout0 + movaps $in1,$iv + pxor $in0,$inout1 + movdqu $inout0,($out) + movdqa $inout1,$inout0 + pxor $inout1,$inout1 # clear register bank + lea 0x10($out),$out + jmp .Lcbc_dec_tail_collected +.align 16 +.Lcbc_dec_three: + movaps $inout2,$in2 + call _aesni_decrypt3 + pxor $iv,$inout0 + movaps $in2,$iv + pxor $in0,$inout1 + movdqu $inout0,($out) + pxor $in1,$inout2 + movdqu $inout1,0x10($out) + pxor $inout1,$inout1 # clear register bank + movdqa $inout2,$inout0 + pxor $inout2,$inout2 + lea 0x20($out),$out + jmp .Lcbc_dec_tail_collected +.align 16 +.Lcbc_dec_four: + movaps $inout3,$in3 + call _aesni_decrypt4 + pxor $iv,$inout0 + movaps $in3,$iv + pxor $in0,$inout1 + movdqu $inout0,($out) + pxor $in1,$inout2 + movdqu $inout1,0x10($out) + pxor $inout1,$inout1 # clear register bank + pxor $in2,$inout3 + movdqu $inout2,0x20($out) + pxor $inout2,$inout2 + movdqa $inout3,$inout0 + pxor $inout3,$inout3 + lea 0x30($out),$out + jmp .Lcbc_dec_tail_collected + +.align 16 +.Lcbc_dec_clear_tail_collected: + pxor $inout1,$inout1 # clear register bank + pxor $inout2,$inout2 + pxor $inout3,$inout3 +___ +$code.=<<___ if (!$win64); + pxor $inout4,$inout4 # %xmm6..9 + pxor $inout5,$inout5 + pxor $inout6,$inout6 + pxor $inout7,$inout7 +___ +$code.=<<___; +.Lcbc_dec_tail_collected: + movups $iv,($ivp) + and \$15,$len + jnz .Lcbc_dec_tail_partial + movups $inout0,($out) + pxor $inout0,$inout0 + jmp .Lcbc_dec_ret +.align 16 +.Lcbc_dec_tail_partial: + movaps $inout0,(%rsp) + pxor $inout0,$inout0 + mov \$16,%rcx + mov $out,%rdi + sub $len,%rcx + lea (%rsp),%rsi + .long 0x9066A4F3 # rep movsb + movdqa $inout0,(%rsp) + +.Lcbc_dec_ret: + xorps $rndkey0,$rndkey0 # %xmm0 + pxor $rndkey1,$rndkey1 +___ +$code.=<<___ if ($win64); + movaps 0x10(%rsp),%xmm6 + movaps %xmm0,0x10(%rsp) # clear stack + movaps 0x20(%rsp),%xmm7 + movaps %xmm0,0x20(%rsp) + movaps 0x30(%rsp),%xmm8 + movaps %xmm0,0x30(%rsp) + movaps 0x40(%rsp),%xmm9 + movaps %xmm0,0x40(%rsp) + movaps 0x50(%rsp),%xmm10 + movaps %xmm0,0x50(%rsp) + movaps 0x60(%rsp),%xmm11 + movaps %xmm0,0x60(%rsp) + movaps 0x70(%rsp),%xmm12 + movaps %xmm0,0x70(%rsp) + movaps 0x80(%rsp),%xmm13 + movaps %xmm0,0x80(%rsp) + movaps 0x90(%rsp),%xmm14 + movaps %xmm0,0x90(%rsp) + movaps 0xa0(%rsp),%xmm15 + movaps %xmm0,0xa0(%rsp) +___ +$code.=<<___; + lea (%rbp),%rsp + pop %rbp +.Lcbc_ret: + ret +.size ${PREFIX}_cbc_encrypt,.-${PREFIX}_cbc_encrypt +___ +} +# int ${PREFIX}_set_decrypt_key(const unsigned char *inp, +# int bits, AES_KEY *key) +# +# input: $inp user-supplied key +# $bits $inp length in bits +# $key pointer to key schedule +# output: %eax 0 denoting success, -1 or -2 - failure (see C) +# *$key key schedule +# +{ my ($inp,$bits,$key) = @_4args; + $bits =~ s/%r/%e/; + +$code.=<<___; +.globl ${PREFIX}_set_decrypt_key +.type ${PREFIX}_set_decrypt_key,\@abi-omnipotent +.align 16 +${PREFIX}_set_decrypt_key: + .byte 0x48,0x83,0xEC,0x08 # sub rsp,8 + call __aesni_set_encrypt_key + shl \$4,$bits # rounds-1 after _aesni_set_encrypt_key + test %eax,%eax + jnz .Ldec_key_ret + lea 16($key,$bits),$inp # points at the end of key schedule + + $movkey ($key),%xmm0 # just swap + $movkey ($inp),%xmm1 + $movkey %xmm0,($inp) + $movkey %xmm1,($key) + lea 16($key),$key + lea -16($inp),$inp + +.Ldec_key_inverse: + $movkey ($key),%xmm0 # swap and inverse + $movkey ($inp),%xmm1 + aesimc %xmm0,%xmm0 + aesimc %xmm1,%xmm1 + lea 16($key),$key + lea -16($inp),$inp + $movkey %xmm0,16($inp) + $movkey %xmm1,-16($key) + cmp $key,$inp + ja .Ldec_key_inverse + + $movkey ($key),%xmm0 # inverse middle + aesimc %xmm0,%xmm0 + pxor %xmm1,%xmm1 + $movkey %xmm0,($inp) + pxor %xmm0,%xmm0 +.Ldec_key_ret: + add \$8,%rsp + ret +.LSEH_end_set_decrypt_key: +.size ${PREFIX}_set_decrypt_key,.-${PREFIX}_set_decrypt_key +___ + +# This is based on submission by +# +# Huang Ying +# Vinodh Gopal +# Kahraman Akdemir +# +# Agressively optimized in respect to aeskeygenassist's critical path +# and is contained in %xmm0-5 to meet Win64 ABI requirement. +# +# int ${PREFIX}_set_encrypt_key(const unsigned char *inp, +# int bits, AES_KEY * const key); +# +# input: $inp user-supplied key +# $bits $inp length in bits +# $key pointer to key schedule +# output: %eax 0 denoting success, -1 or -2 - failure (see C) +# $bits rounds-1 (used in aesni_set_decrypt_key) +# *$key key schedule +# $key pointer to key schedule (used in +# aesni_set_decrypt_key) +# +# Subroutine is frame-less, which means that only volatile registers +# are used. Note that it's declared "abi-omnipotent", which means that +# amount of volatile registers is smaller on Windows. +# +$code.=<<___; +.globl ${PREFIX}_set_encrypt_key +.type ${PREFIX}_set_encrypt_key,\@abi-omnipotent +.align 16 +${PREFIX}_set_encrypt_key: +__aesni_set_encrypt_key: + .byte 0x48,0x83,0xEC,0x08 # sub rsp,8 + mov \$-1,%rax + test $inp,$inp + jz .Lenc_key_ret + test $key,$key + jz .Lenc_key_ret + + mov \$`1<<28|1<<11`,%r10d # AVX and XOP bits + movups ($inp),%xmm0 # pull first 128 bits of *userKey + xorps %xmm4,%xmm4 # low dword of xmm4 is assumed 0 + and OPENSSL_ia32cap_P+4(%rip),%r10d + lea 16($key),%rax # %rax is used as modifiable copy of $key + cmp \$256,$bits + je .L14rounds + cmp \$192,$bits + je .L12rounds + cmp \$128,$bits + jne .Lbad_keybits + +.L10rounds: + mov \$9,$bits # 10 rounds for 128-bit key + cmp \$`1<<28`,%r10d # AVX, bit no XOP + je .L10rounds_alt + + $movkey %xmm0,($key) # round 0 + aeskeygenassist \$0x1,%xmm0,%xmm1 # round 1 + call .Lkey_expansion_128_cold + aeskeygenassist \$0x2,%xmm0,%xmm1 # round 2 + call .Lkey_expansion_128 + aeskeygenassist \$0x4,%xmm0,%xmm1 # round 3 + call .Lkey_expansion_128 + aeskeygenassist \$0x8,%xmm0,%xmm1 # round 4 + call .Lkey_expansion_128 + aeskeygenassist \$0x10,%xmm0,%xmm1 # round 5 + call .Lkey_expansion_128 + aeskeygenassist \$0x20,%xmm0,%xmm1 # round 6 + call .Lkey_expansion_128 + aeskeygenassist \$0x40,%xmm0,%xmm1 # round 7 + call .Lkey_expansion_128 + aeskeygenassist \$0x80,%xmm0,%xmm1 # round 8 + call .Lkey_expansion_128 + aeskeygenassist \$0x1b,%xmm0,%xmm1 # round 9 + call .Lkey_expansion_128 + aeskeygenassist \$0x36,%xmm0,%xmm1 # round 10 + call .Lkey_expansion_128 + $movkey %xmm0,(%rax) + mov $bits,80(%rax) # 240(%rdx) + xor %eax,%eax + jmp .Lenc_key_ret + +.align 16 +.L10rounds_alt: + movdqa .Lkey_rotate(%rip),%xmm5 + mov \$8,%r10d + movdqa .Lkey_rcon1(%rip),%xmm4 + movdqa %xmm0,%xmm2 + movdqu %xmm0,($key) + jmp .Loop_key128 + +.align 16 +.Loop_key128: + pshufb %xmm5,%xmm0 + aesenclast %xmm4,%xmm0 + pslld \$1,%xmm4 + lea 16(%rax),%rax + + movdqa %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm3,%xmm2 + + pxor %xmm2,%xmm0 + movdqu %xmm0,-16(%rax) + movdqa %xmm0,%xmm2 + + dec %r10d + jnz .Loop_key128 + + movdqa .Lkey_rcon1b(%rip),%xmm4 + + pshufb %xmm5,%xmm0 + aesenclast %xmm4,%xmm0 + pslld \$1,%xmm4 + + movdqa %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm3,%xmm2 + + pxor %xmm2,%xmm0 + movdqu %xmm0,(%rax) + + movdqa %xmm0,%xmm2 + pshufb %xmm5,%xmm0 + aesenclast %xmm4,%xmm0 + + movdqa %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm2,%xmm3 + pslldq \$4,%xmm2 + pxor %xmm3,%xmm2 + + pxor %xmm2,%xmm0 + movdqu %xmm0,16(%rax) + + mov $bits,96(%rax) # 240($key) + xor %eax,%eax + jmp .Lenc_key_ret + +.align 16 +.L12rounds: + movq 16($inp),%xmm2 # remaining 1/3 of *userKey + mov \$11,$bits # 12 rounds for 192 + cmp \$`1<<28`,%r10d # AVX, but no XOP + je .L12rounds_alt + + $movkey %xmm0,($key) # round 0 + aeskeygenassist \$0x1,%xmm2,%xmm1 # round 1,2 + call .Lkey_expansion_192a_cold + aeskeygenassist \$0x2,%xmm2,%xmm1 # round 2,3 + call .Lkey_expansion_192b + aeskeygenassist \$0x4,%xmm2,%xmm1 # round 4,5 + call .Lkey_expansion_192a + aeskeygenassist \$0x8,%xmm2,%xmm1 # round 5,6 + call .Lkey_expansion_192b + aeskeygenassist \$0x10,%xmm2,%xmm1 # round 7,8 + call .Lkey_expansion_192a + aeskeygenassist \$0x20,%xmm2,%xmm1 # round 8,9 + call .Lkey_expansion_192b + aeskeygenassist \$0x40,%xmm2,%xmm1 # round 10,11 + call .Lkey_expansion_192a + aeskeygenassist \$0x80,%xmm2,%xmm1 # round 11,12 + call .Lkey_expansion_192b + $movkey %xmm0,(%rax) + mov $bits,48(%rax) # 240(%rdx) + xor %rax, %rax + jmp .Lenc_key_ret + +.align 16 +.L12rounds_alt: + movdqa .Lkey_rotate192(%rip),%xmm5 + movdqa .Lkey_rcon1(%rip),%xmm4 + mov \$8,%r10d + movdqu %xmm0,($key) + jmp .Loop_key192 + +.align 16 +.Loop_key192: + movq %xmm2,0(%rax) + movdqa %xmm2,%xmm1 + pshufb %xmm5,%xmm2 + aesenclast %xmm4,%xmm2 + pslld \$1, %xmm4 + lea 24(%rax),%rax + + movdqa %xmm0,%xmm3 + pslldq \$4,%xmm0 + pxor %xmm0,%xmm3 + pslldq \$4,%xmm0 + pxor %xmm0,%xmm3 + pslldq \$4,%xmm0 + pxor %xmm3,%xmm0 + + pshufd \$0xff,%xmm0,%xmm3 + pxor %xmm1,%xmm3 + pslldq \$4,%xmm1 + pxor %xmm1,%xmm3 + + pxor %xmm2,%xmm0 + pxor %xmm3,%xmm2 + movdqu %xmm0,-16(%rax) + + dec %r10d + jnz .Loop_key192 + + mov $bits,32(%rax) # 240($key) + xor %eax,%eax + jmp .Lenc_key_ret + +.align 16 +.L14rounds: + movups 16($inp),%xmm2 # remaning half of *userKey + mov \$13,$bits # 14 rounds for 256 + lea 16(%rax),%rax + cmp \$`1<<28`,%r10d # AVX, but no XOP + je .L14rounds_alt + + $movkey %xmm0,($key) # round 0 + $movkey %xmm2,16($key) # round 1 + aeskeygenassist \$0x1,%xmm2,%xmm1 # round 2 + call .Lkey_expansion_256a_cold + aeskeygenassist \$0x1,%xmm0,%xmm1 # round 3 + call .Lkey_expansion_256b + aeskeygenassist \$0x2,%xmm2,%xmm1 # round 4 + call .Lkey_expansion_256a + aeskeygenassist \$0x2,%xmm0,%xmm1 # round 5 + call .Lkey_expansion_256b + aeskeygenassist \$0x4,%xmm2,%xmm1 # round 6 + call .Lkey_expansion_256a + aeskeygenassist \$0x4,%xmm0,%xmm1 # round 7 + call .Lkey_expansion_256b + aeskeygenassist \$0x8,%xmm2,%xmm1 # round 8 + call .Lkey_expansion_256a + aeskeygenassist \$0x8,%xmm0,%xmm1 # round 9 + call .Lkey_expansion_256b + aeskeygenassist \$0x10,%xmm2,%xmm1 # round 10 + call .Lkey_expansion_256a + aeskeygenassist \$0x10,%xmm0,%xmm1 # round 11 + call .Lkey_expansion_256b + aeskeygenassist \$0x20,%xmm2,%xmm1 # round 12 + call .Lkey_expansion_256a + aeskeygenassist \$0x20,%xmm0,%xmm1 # round 13 + call .Lkey_expansion_256b + aeskeygenassist \$0x40,%xmm2,%xmm1 # round 14 + call .Lkey_expansion_256a + $movkey %xmm0,(%rax) + mov $bits,16(%rax) # 240(%rdx) + xor %rax,%rax + jmp .Lenc_key_ret + +.align 16 +.L14rounds_alt: + movdqa .Lkey_rotate(%rip),%xmm5 + movdqa .Lkey_rcon1(%rip),%xmm4 + mov \$7,%r10d + movdqu %xmm0,0($key) + movdqa %xmm2,%xmm1 + movdqu %xmm2,16($key) + jmp .Loop_key256 + +.align 16 +.Loop_key256: + pshufb %xmm5,%xmm2 + aesenclast %xmm4,%xmm2 + + movdqa %xmm0,%xmm3 + pslldq \$4,%xmm0 + pxor %xmm0,%xmm3 + pslldq \$4,%xmm0 + pxor %xmm0,%xmm3 + pslldq \$4,%xmm0 + pxor %xmm3,%xmm0 + pslld \$1,%xmm4 + + pxor %xmm2,%xmm0 + movdqu %xmm0,(%rax) + + dec %r10d + jz .Ldone_key256 + + pshufd \$0xff,%xmm0,%xmm2 + pxor %xmm3,%xmm3 + aesenclast %xmm3,%xmm2 + + movdqa %xmm1,%xmm3 + pslldq \$4,%xmm1 + pxor %xmm1,%xmm3 + pslldq \$4,%xmm1 + pxor %xmm1,%xmm3 + pslldq \$4,%xmm1 + pxor %xmm3,%xmm1 + + pxor %xmm1,%xmm2 + movdqu %xmm2,16(%rax) + lea 32(%rax),%rax + movdqa %xmm2,%xmm1 + + jmp .Loop_key256 + +.Ldone_key256: + mov $bits,16(%rax) # 240($key) + xor %eax,%eax + jmp .Lenc_key_ret + +.align 16 +.Lbad_keybits: + mov \$-2,%rax +.Lenc_key_ret: + pxor %xmm0,%xmm0 + pxor %xmm1,%xmm1 + pxor %xmm2,%xmm2 + pxor %xmm3,%xmm3 + pxor %xmm4,%xmm4 + pxor %xmm5,%xmm5 + add \$8,%rsp + ret +.LSEH_end_set_encrypt_key: + +.align 16 +.Lkey_expansion_128: + $movkey %xmm0,(%rax) + lea 16(%rax),%rax +.Lkey_expansion_128_cold: + shufps \$0b00010000,%xmm0,%xmm4 + xorps %xmm4, %xmm0 + shufps \$0b10001100,%xmm0,%xmm4 + xorps %xmm4, %xmm0 + shufps \$0b11111111,%xmm1,%xmm1 # critical path + xorps %xmm1,%xmm0 + ret + +.align 16 +.Lkey_expansion_192a: + $movkey %xmm0,(%rax) + lea 16(%rax),%rax +.Lkey_expansion_192a_cold: + movaps %xmm2, %xmm5 +.Lkey_expansion_192b_warm: + shufps \$0b00010000,%xmm0,%xmm4 + movdqa %xmm2,%xmm3 + xorps %xmm4,%xmm0 + shufps \$0b10001100,%xmm0,%xmm4 + pslldq \$4,%xmm3 + xorps %xmm4,%xmm0 + pshufd \$0b01010101,%xmm1,%xmm1 # critical path + pxor %xmm3,%xmm2 + pxor %xmm1,%xmm0 + pshufd \$0b11111111,%xmm0,%xmm3 + pxor %xmm3,%xmm2 + ret + +.align 16 +.Lkey_expansion_192b: + movaps %xmm0,%xmm3 + shufps \$0b01000100,%xmm0,%xmm5 + $movkey %xmm5,(%rax) + shufps \$0b01001110,%xmm2,%xmm3 + $movkey %xmm3,16(%rax) + lea 32(%rax),%rax + jmp .Lkey_expansion_192b_warm + +.align 16 +.Lkey_expansion_256a: + $movkey %xmm2,(%rax) + lea 16(%rax),%rax +.Lkey_expansion_256a_cold: + shufps \$0b00010000,%xmm0,%xmm4 + xorps %xmm4,%xmm0 + shufps \$0b10001100,%xmm0,%xmm4 + xorps %xmm4,%xmm0 + shufps \$0b11111111,%xmm1,%xmm1 # critical path + xorps %xmm1,%xmm0 + ret + +.align 16 +.Lkey_expansion_256b: + $movkey %xmm0,(%rax) + lea 16(%rax),%rax + + shufps \$0b00010000,%xmm2,%xmm4 + xorps %xmm4,%xmm2 + shufps \$0b10001100,%xmm2,%xmm4 + xorps %xmm4,%xmm2 + shufps \$0b10101010,%xmm1,%xmm1 # critical path + xorps %xmm1,%xmm2 + ret +.size ${PREFIX}_set_encrypt_key,.-${PREFIX}_set_encrypt_key +.size __aesni_set_encrypt_key,.-__aesni_set_encrypt_key +___ +} + +$code.=<<___; +.align 64 +.Lbswap_mask: + .byte 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 +.Lincrement32: + .long 6,6,6,0 +.Lincrement64: + .long 1,0,0,0 +.Lxts_magic: + .long 0x87,0,1,0 +.Lincrement1: + .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 +.Lkey_rotate: + .long 0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d +.Lkey_rotate192: + .long 0x04070605,0x04070605,0x04070605,0x04070605 +.Lkey_rcon1: + .long 1,1,1,1 +.Lkey_rcon1b: + .long 0x1b,0x1b,0x1b,0x1b + +.asciz "AES for Intel AES-NI, CRYPTOGAMS by " +.align 64 +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +___ +$code.=<<___ if ($PREFIX eq "aesni"); +.type ecb_ccm64_se_handler,\@abi-omnipotent +.align 16 +ecb_ccm64_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + lea 0(%rax),%rsi # %xmm save area + lea 512($context),%rdi # &context.Xmm6 + mov \$8,%ecx # 4*sizeof(%xmm0)/sizeof(%rax) + .long 0xa548f3fc # cld; rep movsq + lea 0x58(%rax),%rax # adjust stack pointer + + jmp .Lcommon_seh_tail +.size ecb_ccm64_se_handler,.-ecb_ccm64_se_handler + +.type ctr_xts_se_handler,\@abi-omnipotent +.align 16 +ctr_xts_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue lable + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + mov 160($context),%rax # pull context->Rbp + lea -0xa0(%rax),%rsi # %xmm save area + lea 512($context),%rdi # & context.Xmm6 + mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax) + .long 0xa548f3fc # cld; rep movsq + + jmp .Lcommon_rbp_tail +.size ctr_xts_se_handler,.-ctr_xts_se_handler +___ +$code.=<<___; +.type cbc_se_handler,\@abi-omnipotent +.align 16 +cbc_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 152($context),%rax # pull context->Rsp + mov 248($context),%rbx # pull context->Rip + + lea .Lcbc_decrypt_bulk(%rip),%r10 + cmp %r10,%rbx # context->Rip<"prologue" label + jb .Lcommon_seh_tail + + lea .Lcbc_decrypt_body(%rip),%r10 + cmp %r10,%rbx # context->RipRip>="epilogue" label + jae .Lcommon_seh_tail + + lea 16(%rax),%rsi # %xmm save area + lea 512($context),%rdi # &context.Xmm6 + mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax) + .long 0xa548f3fc # cld; rep movsq + +.Lcommon_rbp_tail: + mov 160($context),%rax # pull context->Rbp + mov (%rax),%rbp # restore saved %rbp + lea 8(%rax),%rax # adjust stack pointer + mov %rbp,160($context) # restore context->Rbp + jmp .Lcommon_seh_tail + +.Lrestore_cbc_rax: + mov 120($context),%rax + +.Lcommon_seh_tail: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size cbc_se_handler,.-cbc_se_handler + +.section .pdata +.align 4 +___ +$code.=<<___ if ($PREFIX eq "aesni"); + .rva .LSEH_begin_aesni_ecb_encrypt + .rva .LSEH_end_aesni_ecb_encrypt + .rva .LSEH_info_ecb + + .rva .LSEH_begin_aesni_ccm64_encrypt_blocks + .rva .LSEH_end_aesni_ccm64_encrypt_blocks + .rva .LSEH_info_ccm64_enc + + .rva .LSEH_begin_aesni_ccm64_decrypt_blocks + .rva .LSEH_end_aesni_ccm64_decrypt_blocks + .rva .LSEH_info_ccm64_dec + + .rva .LSEH_begin_aesni_ctr32_encrypt_blocks + .rva .LSEH_end_aesni_ctr32_encrypt_blocks + .rva .LSEH_info_ctr32 + + .rva .LSEH_begin_aesni_xts_encrypt + .rva .LSEH_end_aesni_xts_encrypt + .rva .LSEH_info_xts_enc + + .rva .LSEH_begin_aesni_xts_decrypt + .rva .LSEH_end_aesni_xts_decrypt + .rva .LSEH_info_xts_dec +___ +$code.=<<___; + .rva .LSEH_begin_${PREFIX}_cbc_encrypt + .rva .LSEH_end_${PREFIX}_cbc_encrypt + .rva .LSEH_info_cbc + + .rva ${PREFIX}_set_decrypt_key + .rva .LSEH_end_set_decrypt_key + .rva .LSEH_info_key + + .rva ${PREFIX}_set_encrypt_key + .rva .LSEH_end_set_encrypt_key + .rva .LSEH_info_key +.section .xdata +.align 8 +___ +$code.=<<___ if ($PREFIX eq "aesni"); +.LSEH_info_ecb: + .byte 9,0,0,0 + .rva ecb_ccm64_se_handler + .rva .Lecb_enc_body,.Lecb_enc_ret # HandlerData[] +.LSEH_info_ccm64_enc: + .byte 9,0,0,0 + .rva ecb_ccm64_se_handler + .rva .Lccm64_enc_body,.Lccm64_enc_ret # HandlerData[] +.LSEH_info_ccm64_dec: + .byte 9,0,0,0 + .rva ecb_ccm64_se_handler + .rva .Lccm64_dec_body,.Lccm64_dec_ret # HandlerData[] +.LSEH_info_ctr32: + .byte 9,0,0,0 + .rva ctr_xts_se_handler + .rva .Lctr32_body,.Lctr32_epilogue # HandlerData[] +.LSEH_info_xts_enc: + .byte 9,0,0,0 + .rva ctr_xts_se_handler + .rva .Lxts_enc_body,.Lxts_enc_epilogue # HandlerData[] +.LSEH_info_xts_dec: + .byte 9,0,0,0 + .rva ctr_xts_se_handler + .rva .Lxts_dec_body,.Lxts_dec_epilogue # HandlerData[] +___ +$code.=<<___; +.LSEH_info_cbc: + .byte 9,0,0,0 + .rva cbc_se_handler +.LSEH_info_key: + .byte 0x01,0x04,0x01,0x00 + .byte 0x04,0x02,0x00,0x00 # sub rsp,8 +___ +} + +sub rex { + local *opcode=shift; + my ($dst,$src)=@_; + my $rex=0; + + $rex|=0x04 if($dst>=8); + $rex|=0x01 if($src>=8); + push @opcode,$rex|0x40 if($rex); +} + +sub aesni { + my $line=shift; + my @opcode=(0x66); + + if ($line=~/(aeskeygenassist)\s+\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) { + rex(\@opcode,$4,$3); + push @opcode,0x0f,0x3a,0xdf; + push @opcode,0xc0|($3&7)|(($4&7)<<3); # ModR/M + my $c=$2; + push @opcode,$c=~/^0/?oct($c):$c; + return ".byte\t".join(',',@opcode); + } + elsif ($line=~/(aes[a-z]+)\s+%xmm([0-9]+),\s*%xmm([0-9]+)/) { + my %opcodelet = ( + "aesimc" => 0xdb, + "aesenc" => 0xdc, "aesenclast" => 0xdd, + "aesdec" => 0xde, "aesdeclast" => 0xdf + ); + return undef if (!defined($opcodelet{$1})); + rex(\@opcode,$3,$2); + push @opcode,0x0f,0x38,$opcodelet{$1}; + push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M + return ".byte\t".join(',',@opcode); + } + elsif ($line=~/(aes[a-z]+)\s+([0x1-9a-fA-F]*)\(%rsp\),\s*%xmm([0-9]+)/) { + my %opcodelet = ( + "aesenc" => 0xdc, "aesenclast" => 0xdd, + "aesdec" => 0xde, "aesdeclast" => 0xdf + ); + return undef if (!defined($opcodelet{$1})); + my $off = $2; + push @opcode,0x44 if ($3>=8); + push @opcode,0x0f,0x38,$opcodelet{$1}; + push @opcode,0x44|(($3&7)<<3),0x24; # ModR/M + push @opcode,($off=~/^0/?oct($off):$off)&0xff; + return ".byte\t".join(',',@opcode); + } + return $line; +} + +sub movbe { + ".byte 0x0f,0x38,0xf1,0x44,0x24,".shift; +} + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; +$code =~ s/\b(aes.*%xmm[0-9]+).*$/aesni($1)/gem; +#$code =~ s/\bmovbe\s+%eax/bswap %eax; mov %eax/gm; # debugging artefact +$code =~ s/\bmovbe\s+%eax,\s*([0-9]+)\(%rsp\)/movbe($1)/gem; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/aesv8-armx.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/aesv8-armx.pl new file mode 100644 index 00000000..b0916f66 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/aesv8-armx.pl @@ -0,0 +1,1001 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# This module implements support for ARMv8 AES instructions. The +# module is endian-agnostic in sense that it supports both big- and +# little-endian cases. As does it support both 32- and 64-bit modes +# of operation. Latter is achieved by limiting amount of utilized +# registers to 16, which implies additional NEON load and integer +# instructions. This has no effect on mighty Apple A7, where results +# are literally equal to the theoretical estimates based on AES +# instruction latencies and issue rates. On Cortex-A53, an in-order +# execution core, this costs up to 10-15%, which is partially +# compensated by implementing dedicated code path for 128-bit +# CBC encrypt case. On Cortex-A57 parallelizable mode performance +# seems to be limited by sheer amount of NEON instructions... +# +# Performance in cycles per byte processed with 128-bit key: +# +# CBC enc CBC dec CTR +# Apple A7 2.39 1.20 1.20 +# Cortex-A53 1.32 1.29 1.46 +# Cortex-A57(*) 1.95 0.85 0.93 +# Denver 1.96 0.86 0.80 +# +# (*) original 3.64/1.34/1.32 results were for r0p0 revision +# and are still same even for updated module; + +$flavour = shift; +$output = shift; + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or +die "can't locate arm-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$prefix="aes_v8"; + +$code=<<___; +#include "arm_arch.h" + +#if __ARM_MAX_ARCH__>=7 +.text +___ +$code.=<<___ if ($flavour =~ /64/); +#if !defined(__clang__) +.arch armv8-a+crypto +#endif +___ +$code.=".arch armv7-a\n.fpu neon\n.code 32\n" if ($flavour !~ /64/); + #^^^^^^ this is done to simplify adoption by not depending + # on latest binutils. + +# Assembler mnemonics are an eclectic mix of 32- and 64-bit syntax, +# NEON is mostly 32-bit mnemonics, integer - mostly 64. Goal is to +# maintain both 32- and 64-bit codes within single module and +# transliterate common code to either flavour with regex vodoo. +# +{{{ +my ($inp,$bits,$out,$ptr,$rounds)=("x0","w1","x2","x3","w12"); +my ($zero,$rcon,$mask,$in0,$in1,$tmp,$key)= + $flavour=~/64/? map("q$_",(0..6)) : map("q$_",(0..3,8..10)); + + +$code.=<<___; +.align 5 +.Lrcon: +.long 0x01,0x01,0x01,0x01 +.long 0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d,0x0c0f0e0d // rotate-n-splat +.long 0x1b,0x1b,0x1b,0x1b + +.globl ${prefix}_set_encrypt_key +.type ${prefix}_set_encrypt_key,%function +.align 5 +${prefix}_set_encrypt_key: +.Lenc_key: +___ +$code.=<<___ if ($flavour =~ /64/); + stp x29,x30,[sp,#-16]! + add x29,sp,#0 +___ +$code.=<<___; + mov $ptr,#-1 + cmp $inp,#0 + b.eq .Lenc_key_abort + cmp $out,#0 + b.eq .Lenc_key_abort + mov $ptr,#-2 + cmp $bits,#128 + b.lt .Lenc_key_abort + cmp $bits,#256 + b.gt .Lenc_key_abort + tst $bits,#0x3f + b.ne .Lenc_key_abort + + adr $ptr,.Lrcon + cmp $bits,#192 + + veor $zero,$zero,$zero + vld1.8 {$in0},[$inp],#16 + mov $bits,#8 // reuse $bits + vld1.32 {$rcon,$mask},[$ptr],#32 + + b.lt .Loop128 + b.eq .L192 + b .L256 + +.align 4 +.Loop128: + vtbl.8 $key,{$in0},$mask + vext.8 $tmp,$zero,$in0,#12 + vst1.32 {$in0},[$out],#16 + aese $key,$zero + subs $bits,$bits,#1 + + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $key,$key,$rcon + veor $in0,$in0,$tmp + vshl.u8 $rcon,$rcon,#1 + veor $in0,$in0,$key + b.ne .Loop128 + + vld1.32 {$rcon},[$ptr] + + vtbl.8 $key,{$in0},$mask + vext.8 $tmp,$zero,$in0,#12 + vst1.32 {$in0},[$out],#16 + aese $key,$zero + + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $key,$key,$rcon + veor $in0,$in0,$tmp + vshl.u8 $rcon,$rcon,#1 + veor $in0,$in0,$key + + vtbl.8 $key,{$in0},$mask + vext.8 $tmp,$zero,$in0,#12 + vst1.32 {$in0},[$out],#16 + aese $key,$zero + + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $key,$key,$rcon + veor $in0,$in0,$tmp + veor $in0,$in0,$key + vst1.32 {$in0},[$out] + add $out,$out,#0x50 + + mov $rounds,#10 + b .Ldone + +.align 4 +.L192: + vld1.8 {$in1},[$inp],#8 + vmov.i8 $key,#8 // borrow $key + vst1.32 {$in0},[$out],#16 + vsub.i8 $mask,$mask,$key // adjust the mask + +.Loop192: + vtbl.8 $key,{$in1},$mask + vext.8 $tmp,$zero,$in0,#12 + vst1.32 {$in1},[$out],#8 + aese $key,$zero + subs $bits,$bits,#1 + + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in0,$in0,$tmp + + vdup.32 $tmp,${in0}[3] + veor $tmp,$tmp,$in1 + veor $key,$key,$rcon + vext.8 $in1,$zero,$in1,#12 + vshl.u8 $rcon,$rcon,#1 + veor $in1,$in1,$tmp + veor $in0,$in0,$key + veor $in1,$in1,$key + vst1.32 {$in0},[$out],#16 + b.ne .Loop192 + + mov $rounds,#12 + add $out,$out,#0x20 + b .Ldone + +.align 4 +.L256: + vld1.8 {$in1},[$inp] + mov $bits,#7 + mov $rounds,#14 + vst1.32 {$in0},[$out],#16 + +.Loop256: + vtbl.8 $key,{$in1},$mask + vext.8 $tmp,$zero,$in0,#12 + vst1.32 {$in1},[$out],#16 + aese $key,$zero + subs $bits,$bits,#1 + + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in0,$in0,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $key,$key,$rcon + veor $in0,$in0,$tmp + vshl.u8 $rcon,$rcon,#1 + veor $in0,$in0,$key + vst1.32 {$in0},[$out],#16 + b.eq .Ldone + + vdup.32 $key,${in0}[3] // just splat + vext.8 $tmp,$zero,$in1,#12 + aese $key,$zero + + veor $in1,$in1,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in1,$in1,$tmp + vext.8 $tmp,$zero,$tmp,#12 + veor $in1,$in1,$tmp + + veor $in1,$in1,$key + b .Loop256 + +.Ldone: + str $rounds,[$out] + mov $ptr,#0 + +.Lenc_key_abort: + mov x0,$ptr // return value + `"ldr x29,[sp],#16" if ($flavour =~ /64/)` + ret +.size ${prefix}_set_encrypt_key,.-${prefix}_set_encrypt_key + +.globl ${prefix}_set_decrypt_key +.type ${prefix}_set_decrypt_key,%function +.align 5 +${prefix}_set_decrypt_key: +___ +$code.=<<___ if ($flavour =~ /64/); + stp x29,x30,[sp,#-16]! + add x29,sp,#0 +___ +$code.=<<___ if ($flavour !~ /64/); + stmdb sp!,{r4,lr} +___ +$code.=<<___; + bl .Lenc_key + + cmp x0,#0 + b.ne .Ldec_key_abort + + sub $out,$out,#240 // restore original $out + mov x4,#-16 + add $inp,$out,x12,lsl#4 // end of key schedule + + vld1.32 {v0.16b},[$out] + vld1.32 {v1.16b},[$inp] + vst1.32 {v0.16b},[$inp],x4 + vst1.32 {v1.16b},[$out],#16 + +.Loop_imc: + vld1.32 {v0.16b},[$out] + vld1.32 {v1.16b},[$inp] + aesimc v0.16b,v0.16b + aesimc v1.16b,v1.16b + vst1.32 {v0.16b},[$inp],x4 + vst1.32 {v1.16b},[$out],#16 + cmp $inp,$out + b.hi .Loop_imc + + vld1.32 {v0.16b},[$out] + aesimc v0.16b,v0.16b + vst1.32 {v0.16b},[$inp] + + eor x0,x0,x0 // return value +.Ldec_key_abort: +___ +$code.=<<___ if ($flavour !~ /64/); + ldmia sp!,{r4,pc} +___ +$code.=<<___ if ($flavour =~ /64/); + ldp x29,x30,[sp],#16 + ret +___ +$code.=<<___; +.size ${prefix}_set_decrypt_key,.-${prefix}_set_decrypt_key +___ +}}} +{{{ +sub gen_block () { +my $dir = shift; +my ($e,$mc) = $dir eq "en" ? ("e","mc") : ("d","imc"); +my ($inp,$out,$key)=map("x$_",(0..2)); +my $rounds="w3"; +my ($rndkey0,$rndkey1,$inout)=map("q$_",(0..3)); + +$code.=<<___; +.globl ${prefix}_${dir}crypt +.type ${prefix}_${dir}crypt,%function +.align 5 +${prefix}_${dir}crypt: + ldr $rounds,[$key,#240] + vld1.32 {$rndkey0},[$key],#16 + vld1.8 {$inout},[$inp] + sub $rounds,$rounds,#2 + vld1.32 {$rndkey1},[$key],#16 + +.Loop_${dir}c: + aes$e $inout,$rndkey0 + aes$mc $inout,$inout + vld1.32 {$rndkey0},[$key],#16 + subs $rounds,$rounds,#2 + aes$e $inout,$rndkey1 + aes$mc $inout,$inout + vld1.32 {$rndkey1},[$key],#16 + b.gt .Loop_${dir}c + + aes$e $inout,$rndkey0 + aes$mc $inout,$inout + vld1.32 {$rndkey0},[$key] + aes$e $inout,$rndkey1 + veor $inout,$inout,$rndkey0 + + vst1.8 {$inout},[$out] + ret +.size ${prefix}_${dir}crypt,.-${prefix}_${dir}crypt +___ +} +&gen_block("en"); +&gen_block("de"); +}}} +{{{ +my ($inp,$out,$len,$key,$ivp)=map("x$_",(0..4)); my $enc="w5"; +my ($rounds,$cnt,$key_,$step,$step1)=($enc,"w6","x7","x8","x12"); +my ($dat0,$dat1,$in0,$in1,$tmp0,$tmp1,$ivec,$rndlast)=map("q$_",(0..7)); + +my ($dat,$tmp,$rndzero_n_last)=($dat0,$tmp0,$tmp1); +my ($key4,$key5,$key6,$key7)=("x6","x12","x14",$key); + +### q8-q15 preloaded key schedule + +$code.=<<___; +.globl ${prefix}_cbc_encrypt +.type ${prefix}_cbc_encrypt,%function +.align 5 +${prefix}_cbc_encrypt: +___ +$code.=<<___ if ($flavour =~ /64/); + stp x29,x30,[sp,#-16]! + add x29,sp,#0 +___ +$code.=<<___ if ($flavour !~ /64/); + mov ip,sp + stmdb sp!,{r4-r8,lr} + vstmdb sp!,{d8-d15} @ ABI specification says so + ldmia ip,{r4-r5} @ load remaining args +___ +$code.=<<___; + subs $len,$len,#16 + mov $step,#16 + b.lo .Lcbc_abort + cclr $step,eq + + cmp $enc,#0 // en- or decrypting? + ldr $rounds,[$key,#240] + and $len,$len,#-16 + vld1.8 {$ivec},[$ivp] + vld1.8 {$dat},[$inp],$step + + vld1.32 {q8-q9},[$key] // load key schedule... + sub $rounds,$rounds,#6 + add $key_,$key,x5,lsl#4 // pointer to last 7 round keys + sub $rounds,$rounds,#2 + vld1.32 {q10-q11},[$key_],#32 + vld1.32 {q12-q13},[$key_],#32 + vld1.32 {q14-q15},[$key_],#32 + vld1.32 {$rndlast},[$key_] + + add $key_,$key,#32 + mov $cnt,$rounds + b.eq .Lcbc_dec + + cmp $rounds,#2 + veor $dat,$dat,$ivec + veor $rndzero_n_last,q8,$rndlast + b.eq .Lcbc_enc128 + + vld1.32 {$in0-$in1},[$key_] + add $key_,$key,#16 + add $key4,$key,#16*4 + add $key5,$key,#16*5 + aese $dat,q8 + aesmc $dat,$dat + add $key6,$key,#16*6 + add $key7,$key,#16*7 + b .Lenter_cbc_enc + +.align 4 +.Loop_cbc_enc: + aese $dat,q8 + aesmc $dat,$dat + vst1.8 {$ivec},[$out],#16 +.Lenter_cbc_enc: + aese $dat,q9 + aesmc $dat,$dat + aese $dat,$in0 + aesmc $dat,$dat + vld1.32 {q8},[$key4] + cmp $rounds,#4 + aese $dat,$in1 + aesmc $dat,$dat + vld1.32 {q9},[$key5] + b.eq .Lcbc_enc192 + + aese $dat,q8 + aesmc $dat,$dat + vld1.32 {q8},[$key6] + aese $dat,q9 + aesmc $dat,$dat + vld1.32 {q9},[$key7] + nop + +.Lcbc_enc192: + aese $dat,q8 + aesmc $dat,$dat + subs $len,$len,#16 + aese $dat,q9 + aesmc $dat,$dat + cclr $step,eq + aese $dat,q10 + aesmc $dat,$dat + aese $dat,q11 + aesmc $dat,$dat + vld1.8 {q8},[$inp],$step + aese $dat,q12 + aesmc $dat,$dat + veor q8,q8,$rndzero_n_last + aese $dat,q13 + aesmc $dat,$dat + vld1.32 {q9},[$key_] // re-pre-load rndkey[1] + aese $dat,q14 + aesmc $dat,$dat + aese $dat,q15 + veor $ivec,$dat,$rndlast + b.hs .Loop_cbc_enc + + vst1.8 {$ivec},[$out],#16 + b .Lcbc_done + +.align 5 +.Lcbc_enc128: + vld1.32 {$in0-$in1},[$key_] + aese $dat,q8 + aesmc $dat,$dat + b .Lenter_cbc_enc128 +.Loop_cbc_enc128: + aese $dat,q8 + aesmc $dat,$dat + vst1.8 {$ivec},[$out],#16 +.Lenter_cbc_enc128: + aese $dat,q9 + aesmc $dat,$dat + subs $len,$len,#16 + aese $dat,$in0 + aesmc $dat,$dat + cclr $step,eq + aese $dat,$in1 + aesmc $dat,$dat + aese $dat,q10 + aesmc $dat,$dat + aese $dat,q11 + aesmc $dat,$dat + vld1.8 {q8},[$inp],$step + aese $dat,q12 + aesmc $dat,$dat + aese $dat,q13 + aesmc $dat,$dat + aese $dat,q14 + aesmc $dat,$dat + veor q8,q8,$rndzero_n_last + aese $dat,q15 + veor $ivec,$dat,$rndlast + b.hs .Loop_cbc_enc128 + + vst1.8 {$ivec},[$out],#16 + b .Lcbc_done +___ +{ +my ($dat2,$in2,$tmp2)=map("q$_",(10,11,9)); +$code.=<<___; +.align 5 +.Lcbc_dec: + vld1.8 {$dat2},[$inp],#16 + subs $len,$len,#32 // bias + add $cnt,$rounds,#2 + vorr $in1,$dat,$dat + vorr $dat1,$dat,$dat + vorr $in2,$dat2,$dat2 + b.lo .Lcbc_dec_tail + + vorr $dat1,$dat2,$dat2 + vld1.8 {$dat2},[$inp],#16 + vorr $in0,$dat,$dat + vorr $in1,$dat1,$dat1 + vorr $in2,$dat2,$dat2 + +.Loop3x_cbc_dec: + aesd $dat0,q8 + aesimc $dat0,$dat0 + aesd $dat1,q8 + aesimc $dat1,$dat1 + aesd $dat2,q8 + aesimc $dat2,$dat2 + vld1.32 {q8},[$key_],#16 + subs $cnt,$cnt,#2 + aesd $dat0,q9 + aesimc $dat0,$dat0 + aesd $dat1,q9 + aesimc $dat1,$dat1 + aesd $dat2,q9 + aesimc $dat2,$dat2 + vld1.32 {q9},[$key_],#16 + b.gt .Loop3x_cbc_dec + + aesd $dat0,q8 + aesimc $dat0,$dat0 + aesd $dat1,q8 + aesimc $dat1,$dat1 + aesd $dat2,q8 + aesimc $dat2,$dat2 + veor $tmp0,$ivec,$rndlast + subs $len,$len,#0x30 + veor $tmp1,$in0,$rndlast + mov.lo x6,$len // x6, $cnt, is zero at this point + aesd $dat0,q9 + aesimc $dat0,$dat0 + aesd $dat1,q9 + aesimc $dat1,$dat1 + aesd $dat2,q9 + aesimc $dat2,$dat2 + veor $tmp2,$in1,$rndlast + add $inp,$inp,x6 // $inp is adjusted in such way that + // at exit from the loop $dat1-$dat2 + // are loaded with last "words" + vorr $ivec,$in2,$in2 + mov $key_,$key + aesd $dat0,q12 + aesimc $dat0,$dat0 + aesd $dat1,q12 + aesimc $dat1,$dat1 + aesd $dat2,q12 + aesimc $dat2,$dat2 + vld1.8 {$in0},[$inp],#16 + aesd $dat0,q13 + aesimc $dat0,$dat0 + aesd $dat1,q13 + aesimc $dat1,$dat1 + aesd $dat2,q13 + aesimc $dat2,$dat2 + vld1.8 {$in1},[$inp],#16 + aesd $dat0,q14 + aesimc $dat0,$dat0 + aesd $dat1,q14 + aesimc $dat1,$dat1 + aesd $dat2,q14 + aesimc $dat2,$dat2 + vld1.8 {$in2},[$inp],#16 + aesd $dat0,q15 + aesd $dat1,q15 + aesd $dat2,q15 + vld1.32 {q8},[$key_],#16 // re-pre-load rndkey[0] + add $cnt,$rounds,#2 + veor $tmp0,$tmp0,$dat0 + veor $tmp1,$tmp1,$dat1 + veor $dat2,$dat2,$tmp2 + vld1.32 {q9},[$key_],#16 // re-pre-load rndkey[1] + vst1.8 {$tmp0},[$out],#16 + vorr $dat0,$in0,$in0 + vst1.8 {$tmp1},[$out],#16 + vorr $dat1,$in1,$in1 + vst1.8 {$dat2},[$out],#16 + vorr $dat2,$in2,$in2 + b.hs .Loop3x_cbc_dec + + cmn $len,#0x30 + b.eq .Lcbc_done + nop + +.Lcbc_dec_tail: + aesd $dat1,q8 + aesimc $dat1,$dat1 + aesd $dat2,q8 + aesimc $dat2,$dat2 + vld1.32 {q8},[$key_],#16 + subs $cnt,$cnt,#2 + aesd $dat1,q9 + aesimc $dat1,$dat1 + aesd $dat2,q9 + aesimc $dat2,$dat2 + vld1.32 {q9},[$key_],#16 + b.gt .Lcbc_dec_tail + + aesd $dat1,q8 + aesimc $dat1,$dat1 + aesd $dat2,q8 + aesimc $dat2,$dat2 + aesd $dat1,q9 + aesimc $dat1,$dat1 + aesd $dat2,q9 + aesimc $dat2,$dat2 + aesd $dat1,q12 + aesimc $dat1,$dat1 + aesd $dat2,q12 + aesimc $dat2,$dat2 + cmn $len,#0x20 + aesd $dat1,q13 + aesimc $dat1,$dat1 + aesd $dat2,q13 + aesimc $dat2,$dat2 + veor $tmp1,$ivec,$rndlast + aesd $dat1,q14 + aesimc $dat1,$dat1 + aesd $dat2,q14 + aesimc $dat2,$dat2 + veor $tmp2,$in1,$rndlast + aesd $dat1,q15 + aesd $dat2,q15 + b.eq .Lcbc_dec_one + veor $tmp1,$tmp1,$dat1 + veor $tmp2,$tmp2,$dat2 + vorr $ivec,$in2,$in2 + vst1.8 {$tmp1},[$out],#16 + vst1.8 {$tmp2},[$out],#16 + b .Lcbc_done + +.Lcbc_dec_one: + veor $tmp1,$tmp1,$dat2 + vorr $ivec,$in2,$in2 + vst1.8 {$tmp1},[$out],#16 + +.Lcbc_done: + vst1.8 {$ivec},[$ivp] +.Lcbc_abort: +___ +} +$code.=<<___ if ($flavour !~ /64/); + vldmia sp!,{d8-d15} + ldmia sp!,{r4-r8,pc} +___ +$code.=<<___ if ($flavour =~ /64/); + ldr x29,[sp],#16 + ret +___ +$code.=<<___; +.size ${prefix}_cbc_encrypt,.-${prefix}_cbc_encrypt +___ +}}} +{{{ +my ($inp,$out,$len,$key,$ivp)=map("x$_",(0..4)); +my ($rounds,$cnt,$key_)=("w5","w6","x7"); +my ($ctr,$tctr0,$tctr1,$tctr2)=map("w$_",(8..10,12)); +my $step="x12"; # aliases with $tctr2 + +my ($dat0,$dat1,$in0,$in1,$tmp0,$tmp1,$ivec,$rndlast)=map("q$_",(0..7)); +my ($dat2,$in2,$tmp2)=map("q$_",(10,11,9)); + +my ($dat,$tmp)=($dat0,$tmp0); + +### q8-q15 preloaded key schedule + +$code.=<<___; +.globl ${prefix}_ctr32_encrypt_blocks +.type ${prefix}_ctr32_encrypt_blocks,%function +.align 5 +${prefix}_ctr32_encrypt_blocks: +___ +$code.=<<___ if ($flavour =~ /64/); + stp x29,x30,[sp,#-16]! + add x29,sp,#0 +___ +$code.=<<___ if ($flavour !~ /64/); + mov ip,sp + stmdb sp!,{r4-r10,lr} + vstmdb sp!,{d8-d15} @ ABI specification says so + ldr r4, [ip] @ load remaining arg +___ +$code.=<<___; + ldr $rounds,[$key,#240] + + ldr $ctr, [$ivp, #12] + vld1.32 {$dat0},[$ivp] + + vld1.32 {q8-q9},[$key] // load key schedule... + sub $rounds,$rounds,#4 + mov $step,#16 + cmp $len,#2 + add $key_,$key,x5,lsl#4 // pointer to last 5 round keys + sub $rounds,$rounds,#2 + vld1.32 {q12-q13},[$key_],#32 + vld1.32 {q14-q15},[$key_],#32 + vld1.32 {$rndlast},[$key_] + add $key_,$key,#32 + mov $cnt,$rounds + cclr $step,lo +#ifndef __ARMEB__ + rev $ctr, $ctr +#endif + vorr $dat1,$dat0,$dat0 + add $tctr1, $ctr, #1 + vorr $dat2,$dat0,$dat0 + add $ctr, $ctr, #2 + vorr $ivec,$dat0,$dat0 + rev $tctr1, $tctr1 + vmov.32 ${dat1}[3],$tctr1 + b.ls .Lctr32_tail + rev $tctr2, $ctr + sub $len,$len,#3 // bias + vmov.32 ${dat2}[3],$tctr2 + b .Loop3x_ctr32 + +.align 4 +.Loop3x_ctr32: + aese $dat0,q8 + aesmc $dat0,$dat0 + aese $dat1,q8 + aesmc $dat1,$dat1 + aese $dat2,q8 + aesmc $dat2,$dat2 + vld1.32 {q8},[$key_],#16 + subs $cnt,$cnt,#2 + aese $dat0,q9 + aesmc $dat0,$dat0 + aese $dat1,q9 + aesmc $dat1,$dat1 + aese $dat2,q9 + aesmc $dat2,$dat2 + vld1.32 {q9},[$key_],#16 + b.gt .Loop3x_ctr32 + + aese $dat0,q8 + aesmc $tmp0,$dat0 + aese $dat1,q8 + aesmc $tmp1,$dat1 + vld1.8 {$in0},[$inp],#16 + vorr $dat0,$ivec,$ivec + aese $dat2,q8 + aesmc $dat2,$dat2 + vld1.8 {$in1},[$inp],#16 + vorr $dat1,$ivec,$ivec + aese $tmp0,q9 + aesmc $tmp0,$tmp0 + aese $tmp1,q9 + aesmc $tmp1,$tmp1 + vld1.8 {$in2},[$inp],#16 + mov $key_,$key + aese $dat2,q9 + aesmc $tmp2,$dat2 + vorr $dat2,$ivec,$ivec + add $tctr0,$ctr,#1 + aese $tmp0,q12 + aesmc $tmp0,$tmp0 + aese $tmp1,q12 + aesmc $tmp1,$tmp1 + veor $in0,$in0,$rndlast + add $tctr1,$ctr,#2 + aese $tmp2,q12 + aesmc $tmp2,$tmp2 + veor $in1,$in1,$rndlast + add $ctr,$ctr,#3 + aese $tmp0,q13 + aesmc $tmp0,$tmp0 + aese $tmp1,q13 + aesmc $tmp1,$tmp1 + veor $in2,$in2,$rndlast + rev $tctr0,$tctr0 + aese $tmp2,q13 + aesmc $tmp2,$tmp2 + vmov.32 ${dat0}[3], $tctr0 + rev $tctr1,$tctr1 + aese $tmp0,q14 + aesmc $tmp0,$tmp0 + aese $tmp1,q14 + aesmc $tmp1,$tmp1 + vmov.32 ${dat1}[3], $tctr1 + rev $tctr2,$ctr + aese $tmp2,q14 + aesmc $tmp2,$tmp2 + vmov.32 ${dat2}[3], $tctr2 + subs $len,$len,#3 + aese $tmp0,q15 + aese $tmp1,q15 + aese $tmp2,q15 + + veor $in0,$in0,$tmp0 + vld1.32 {q8},[$key_],#16 // re-pre-load rndkey[0] + vst1.8 {$in0},[$out],#16 + veor $in1,$in1,$tmp1 + mov $cnt,$rounds + vst1.8 {$in1},[$out],#16 + veor $in2,$in2,$tmp2 + vld1.32 {q9},[$key_],#16 // re-pre-load rndkey[1] + vst1.8 {$in2},[$out],#16 + b.hs .Loop3x_ctr32 + + adds $len,$len,#3 + b.eq .Lctr32_done + cmp $len,#1 + mov $step,#16 + cclr $step,eq + +.Lctr32_tail: + aese $dat0,q8 + aesmc $dat0,$dat0 + aese $dat1,q8 + aesmc $dat1,$dat1 + vld1.32 {q8},[$key_],#16 + subs $cnt,$cnt,#2 + aese $dat0,q9 + aesmc $dat0,$dat0 + aese $dat1,q9 + aesmc $dat1,$dat1 + vld1.32 {q9},[$key_],#16 + b.gt .Lctr32_tail + + aese $dat0,q8 + aesmc $dat0,$dat0 + aese $dat1,q8 + aesmc $dat1,$dat1 + aese $dat0,q9 + aesmc $dat0,$dat0 + aese $dat1,q9 + aesmc $dat1,$dat1 + vld1.8 {$in0},[$inp],$step + aese $dat0,q12 + aesmc $dat0,$dat0 + aese $dat1,q12 + aesmc $dat1,$dat1 + vld1.8 {$in1},[$inp] + aese $dat0,q13 + aesmc $dat0,$dat0 + aese $dat1,q13 + aesmc $dat1,$dat1 + veor $in0,$in0,$rndlast + aese $dat0,q14 + aesmc $dat0,$dat0 + aese $dat1,q14 + aesmc $dat1,$dat1 + veor $in1,$in1,$rndlast + aese $dat0,q15 + aese $dat1,q15 + + cmp $len,#1 + veor $in0,$in0,$dat0 + veor $in1,$in1,$dat1 + vst1.8 {$in0},[$out],#16 + b.eq .Lctr32_done + vst1.8 {$in1},[$out] + +.Lctr32_done: +___ +$code.=<<___ if ($flavour !~ /64/); + vldmia sp!,{d8-d15} + ldmia sp!,{r4-r10,pc} +___ +$code.=<<___ if ($flavour =~ /64/); + ldr x29,[sp],#16 + ret +___ +$code.=<<___; +.size ${prefix}_ctr32_encrypt_blocks,.-${prefix}_ctr32_encrypt_blocks +___ +}}} +$code.=<<___; +#endif +___ +######################################## +if ($flavour =~ /64/) { ######## 64-bit code + my %opcode = ( + "aesd" => 0x4e285800, "aese" => 0x4e284800, + "aesimc"=> 0x4e287800, "aesmc" => 0x4e286800 ); + + local *unaes = sub { + my ($mnemonic,$arg)=@_; + + $arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)/o && + sprintf ".inst\t0x%08x\t//%s %s", + $opcode{$mnemonic}|$1|($2<<5), + $mnemonic,$arg; + }; + + foreach(split("\n",$code)) { + s/\`([^\`]*)\`/eval($1)/geo; + + s/\bq([0-9]+)\b/"v".($1<8?$1:$1+8).".16b"/geo; # old->new registers + s/@\s/\/\//o; # old->new style commentary + + #s/[v]?(aes\w+)\s+([qv].*)/unaes($1,$2)/geo or + s/cclr\s+([wx])([^,]+),\s*([a-z]+)/csel $1$2,$1zr,$1$2,$3/o or + s/mov\.([a-z]+)\s+([wx][0-9]+),\s*([wx][0-9]+)/csel $2,$3,$2,$1/o or + s/vmov\.i8/movi/o or # fix up legacy mnemonics + s/vext\.8/ext/o or + s/vrev32\.8/rev32/o or + s/vtst\.8/cmtst/o or + s/vshr/ushr/o or + s/^(\s+)v/$1/o or # strip off v prefix + s/\bbx\s+lr\b/ret/o; + + # fix up remainig legacy suffixes + s/\.[ui]?8//o; + m/\],#8/o and s/\.16b/\.8b/go; + s/\.[ui]?32//o and s/\.16b/\.4s/go; + s/\.[ui]?64//o and s/\.16b/\.2d/go; + s/\.[42]([sd])\[([0-3])\]/\.$1\[$2\]/o; + + print $_,"\n"; + } +} else { ######## 32-bit code + my %opcode = ( + "aesd" => 0xf3b00340, "aese" => 0xf3b00300, + "aesimc"=> 0xf3b003c0, "aesmc" => 0xf3b00380 ); + + local *unaes = sub { + my ($mnemonic,$arg)=@_; + + if ($arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)/o) { + my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19) + |(($2&7)<<1) |(($2&8)<<2); + # since ARMv7 instructions are always encoded little-endian. + # correct solution is to use .inst directive, but older + # assemblers don't implement it:-( + sprintf ".byte\t0x%02x,0x%02x,0x%02x,0x%02x\t@ %s %s", + $word&0xff,($word>>8)&0xff, + ($word>>16)&0xff,($word>>24)&0xff, + $mnemonic,$arg; + } + }; + + sub unvtbl { + my $arg=shift; + + $arg =~ m/q([0-9]+),\s*\{q([0-9]+)\},\s*q([0-9]+)/o && + sprintf "vtbl.8 d%d,{q%d},d%d\n\t". + "vtbl.8 d%d,{q%d},d%d", 2*$1,$2,2*$3, 2*$1+1,$2,2*$3+1; + } + + sub unvdup32 { + my $arg=shift; + + $arg =~ m/q([0-9]+),\s*q([0-9]+)\[([0-3])\]/o && + sprintf "vdup.32 q%d,d%d[%d]",$1,2*$2+($3>>1),$3&1; + } + + sub unvmov32 { + my $arg=shift; + + $arg =~ m/q([0-9]+)\[([0-3])\],(.*)/o && + sprintf "vmov.32 d%d[%d],%s",2*$1+($2>>1),$2&1,$3; + } + + foreach(split("\n",$code)) { + s/\`([^\`]*)\`/eval($1)/geo; + + s/\b[wx]([0-9]+)\b/r$1/go; # new->old registers + s/\bv([0-9])\.[12468]+[bsd]\b/q$1/go; # new->old registers + s/\/\/\s?/@ /o; # new->old style commentary + + # fix up remainig new-style suffixes + s/\{q([0-9]+)\},\s*\[(.+)\],#8/sprintf "{d%d},[$2]!",2*$1/eo or + s/\],#[0-9]+/]!/o; + + s/[v]?(aes\w+)\s+([qv].*)/unaes($1,$2)/geo or + s/cclr\s+([^,]+),\s*([a-z]+)/mov$2 $1,#0/o or + s/vtbl\.8\s+(.*)/unvtbl($1)/geo or + s/vdup\.32\s+(.*)/unvdup32($1)/geo or + s/vmov\.32\s+(.*)/unvmov32($1)/geo or + s/^(\s+)b\./$1b/o or + s/^(\s+)mov\./$1mov/o or + s/^(\s+)ret/$1bx\tlr/o; + + print $_,"\n"; + } +} + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/bsaes-armv7.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/bsaes-armv7.pl new file mode 100644 index 00000000..273f0b9e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/bsaes-armv7.pl @@ -0,0 +1,2515 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# +# Specific modes and adaptation for Linux kernel by Ard Biesheuvel +# . Permission to use under GPL terms is +# granted. +# ==================================================================== + +# Bit-sliced AES for ARM NEON +# +# February 2012. +# +# This implementation is direct adaptation of bsaes-x86_64 module for +# ARM NEON. Except that this module is endian-neutral [in sense that +# it can be compiled for either endianness] by courtesy of vld1.8's +# neutrality. Initial version doesn't implement interface to OpenSSL, +# only low-level primitives and unsupported entry points, just enough +# to collect performance results, which for Cortex-A8 core are: +# +# encrypt 19.5 cycles per byte processed with 128-bit key +# decrypt 22.1 cycles per byte processed with 128-bit key +# key conv. 440 cycles per 128-bit key/0.18 of 8x block +# +# Snapdragon S4 encrypts byte in 17.6 cycles and decrypts in 19.7, +# which is [much] worse than anticipated (for further details see +# http://www.openssl.org/~appro/Snapdragon-S4.html). +# +# Cortex-A15 manages in 14.2/16.1 cycles [when integer-only code +# manages in 20.0 cycles]. +# +# When comparing to x86_64 results keep in mind that NEON unit is +# [mostly] single-issue and thus can't [fully] benefit from +# instruction-level parallelism. And when comparing to aes-armv4 +# results keep in mind key schedule conversion overhead (see +# bsaes-x86_64.pl for further details)... +# +# + +# April-August 2013 +# +# Add CBC, CTR and XTS subroutines, adapt for kernel use. +# +# + +$flavour = shift; +if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } +else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} } + +if ($flavour && $flavour ne "void") { + $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; + ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or + ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or + die "can't locate arm-xlate.pl"; + + open STDOUT,"| \"$^X\" $xlate $flavour $output"; +} else { + open STDOUT,">$output"; +} + +my ($inp,$out,$len,$key)=("r0","r1","r2","r3"); +my @XMM=map("q$_",(0..15)); + +{ +my ($key,$rounds,$const)=("r4","r5","r6"); + +sub Dlo() { shift=~m|q([1]?[0-9])|?"d".($1*2):""; } +sub Dhi() { shift=~m|q([1]?[0-9])|?"d".($1*2+1):""; } + +sub Sbox { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b0, b1, b4, b6, b3, b7, b2, b5] < msb +my @b=@_[0..7]; +my @t=@_[8..11]; +my @s=@_[12..15]; + &InBasisChange (@b); + &Inv_GF256 (@b[6,5,0,3,7,1,4,2],@t,@s); + &OutBasisChange (@b[7,1,4,2,6,5,0,3]); +} + +sub InBasisChange { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb +my @b=@_[0..7]; +$code.=<<___; + veor @b[2], @b[2], @b[1] + veor @b[5], @b[5], @b[6] + veor @b[3], @b[3], @b[0] + veor @b[6], @b[6], @b[2] + veor @b[5], @b[5], @b[0] + + veor @b[6], @b[6], @b[3] + veor @b[3], @b[3], @b[7] + veor @b[7], @b[7], @b[5] + veor @b[3], @b[3], @b[4] + veor @b[4], @b[4], @b[5] + + veor @b[2], @b[2], @b[7] + veor @b[3], @b[3], @b[1] + veor @b[1], @b[1], @b[5] +___ +} + +sub OutBasisChange { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b6, b1, b2, b4, b7, b0, b3, b5] < msb +my @b=@_[0..7]; +$code.=<<___; + veor @b[0], @b[0], @b[6] + veor @b[1], @b[1], @b[4] + veor @b[4], @b[4], @b[6] + veor @b[2], @b[2], @b[0] + veor @b[6], @b[6], @b[1] + + veor @b[1], @b[1], @b[5] + veor @b[5], @b[5], @b[3] + veor @b[3], @b[3], @b[7] + veor @b[7], @b[7], @b[5] + veor @b[2], @b[2], @b[5] + + veor @b[4], @b[4], @b[7] +___ +} + +sub InvSbox { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b0, b1, b6, b4, b2, b7, b3, b5] < msb +my @b=@_[0..7]; +my @t=@_[8..11]; +my @s=@_[12..15]; + &InvInBasisChange (@b); + &Inv_GF256 (@b[5,1,2,6,3,7,0,4],@t,@s); + &InvOutBasisChange (@b[3,7,0,4,5,1,2,6]); +} + +sub InvInBasisChange { # OutBasisChange in reverse (with twist) +my @b=@_[5,1,2,6,3,7,0,4]; +$code.=<<___ + veor @b[1], @b[1], @b[7] + veor @b[4], @b[4], @b[7] + + veor @b[7], @b[7], @b[5] + veor @b[1], @b[1], @b[3] + veor @b[2], @b[2], @b[5] + veor @b[3], @b[3], @b[7] + + veor @b[6], @b[6], @b[1] + veor @b[2], @b[2], @b[0] + veor @b[5], @b[5], @b[3] + veor @b[4], @b[4], @b[6] + veor @b[0], @b[0], @b[6] + veor @b[1], @b[1], @b[4] +___ +} + +sub InvOutBasisChange { # InBasisChange in reverse +my @b=@_[2,5,7,3,6,1,0,4]; +$code.=<<___; + veor @b[1], @b[1], @b[5] + veor @b[2], @b[2], @b[7] + + veor @b[3], @b[3], @b[1] + veor @b[4], @b[4], @b[5] + veor @b[7], @b[7], @b[5] + veor @b[3], @b[3], @b[4] + veor @b[5], @b[5], @b[0] + veor @b[3], @b[3], @b[7] + veor @b[6], @b[6], @b[2] + veor @b[2], @b[2], @b[1] + veor @b[6], @b[6], @b[3] + + veor @b[3], @b[3], @b[0] + veor @b[5], @b[5], @b[6] +___ +} + +sub Mul_GF4 { +#;************************************************************* +#;* Mul_GF4: Input x0-x1,y0-y1 Output x0-x1 Temp t0 (8) * +#;************************************************************* +my ($x0,$x1,$y0,$y1,$t0,$t1)=@_; +$code.=<<___; + veor $t0, $y0, $y1 + vand $t0, $t0, $x0 + veor $x0, $x0, $x1 + vand $t1, $x1, $y0 + vand $x0, $x0, $y1 + veor $x1, $t1, $t0 + veor $x0, $x0, $t1 +___ +} + +sub Mul_GF4_N { # not used, see next subroutine +# multiply and scale by N +my ($x0,$x1,$y0,$y1,$t0)=@_; +$code.=<<___; + veor $t0, $y0, $y1 + vand $t0, $t0, $x0 + veor $x0, $x0, $x1 + vand $x1, $x1, $y0 + vand $x0, $x0, $y1 + veor $x1, $x1, $x0 + veor $x0, $x0, $t0 +___ +} + +sub Mul_GF4_N_GF4 { +# interleaved Mul_GF4_N and Mul_GF4 +my ($x0,$x1,$y0,$y1,$t0, + $x2,$x3,$y2,$y3,$t1)=@_; +$code.=<<___; + veor $t0, $y0, $y1 + veor $t1, $y2, $y3 + vand $t0, $t0, $x0 + vand $t1, $t1, $x2 + veor $x0, $x0, $x1 + veor $x2, $x2, $x3 + vand $x1, $x1, $y0 + vand $x3, $x3, $y2 + vand $x0, $x0, $y1 + vand $x2, $x2, $y3 + veor $x1, $x1, $x0 + veor $x2, $x2, $x3 + veor $x0, $x0, $t0 + veor $x3, $x3, $t1 +___ +} +sub Mul_GF16_2 { +my @x=@_[0..7]; +my @y=@_[8..11]; +my @t=@_[12..15]; +$code.=<<___; + veor @t[0], @x[0], @x[2] + veor @t[1], @x[1], @x[3] +___ + &Mul_GF4 (@x[0], @x[1], @y[0], @y[1], @t[2..3]); +$code.=<<___; + veor @y[0], @y[0], @y[2] + veor @y[1], @y[1], @y[3] +___ + Mul_GF4_N_GF4 (@t[0], @t[1], @y[0], @y[1], @t[3], + @x[2], @x[3], @y[2], @y[3], @t[2]); +$code.=<<___; + veor @x[0], @x[0], @t[0] + veor @x[2], @x[2], @t[0] + veor @x[1], @x[1], @t[1] + veor @x[3], @x[3], @t[1] + + veor @t[0], @x[4], @x[6] + veor @t[1], @x[5], @x[7] +___ + &Mul_GF4_N_GF4 (@t[0], @t[1], @y[0], @y[1], @t[3], + @x[6], @x[7], @y[2], @y[3], @t[2]); +$code.=<<___; + veor @y[0], @y[0], @y[2] + veor @y[1], @y[1], @y[3] +___ + &Mul_GF4 (@x[4], @x[5], @y[0], @y[1], @t[2..3]); +$code.=<<___; + veor @x[4], @x[4], @t[0] + veor @x[6], @x[6], @t[0] + veor @x[5], @x[5], @t[1] + veor @x[7], @x[7], @t[1] +___ +} +sub Inv_GF256 { +#;******************************************************************** +#;* Inv_GF256: Input x0-x7 Output x0-x7 Temp t0-t3,s0-s3 (144) * +#;******************************************************************** +my @x=@_[0..7]; +my @t=@_[8..11]; +my @s=@_[12..15]; +# direct optimizations from hardware +$code.=<<___; + veor @t[3], @x[4], @x[6] + veor @t[2], @x[5], @x[7] + veor @t[1], @x[1], @x[3] + veor @s[1], @x[7], @x[6] + vmov @t[0], @t[2] + veor @s[0], @x[0], @x[2] + + vorr @t[2], @t[2], @t[1] + veor @s[3], @t[3], @t[0] + vand @s[2], @t[3], @s[0] + vorr @t[3], @t[3], @s[0] + veor @s[0], @s[0], @t[1] + vand @t[0], @t[0], @t[1] + veor @t[1], @x[3], @x[2] + vand @s[3], @s[3], @s[0] + vand @s[1], @s[1], @t[1] + veor @t[1], @x[4], @x[5] + veor @s[0], @x[1], @x[0] + veor @t[3], @t[3], @s[1] + veor @t[2], @t[2], @s[1] + vand @s[1], @t[1], @s[0] + vorr @t[1], @t[1], @s[0] + veor @t[3], @t[3], @s[3] + veor @t[0], @t[0], @s[1] + veor @t[2], @t[2], @s[2] + veor @t[1], @t[1], @s[3] + veor @t[0], @t[0], @s[2] + vand @s[0], @x[7], @x[3] + veor @t[1], @t[1], @s[2] + vand @s[1], @x[6], @x[2] + vand @s[2], @x[5], @x[1] + vorr @s[3], @x[4], @x[0] + veor @t[3], @t[3], @s[0] + veor @t[1], @t[1], @s[2] + veor @t[0], @t[0], @s[3] + veor @t[2], @t[2], @s[1] + + @ Inv_GF16 \t0, \t1, \t2, \t3, \s0, \s1, \s2, \s3 + + @ new smaller inversion + + vand @s[2], @t[3], @t[1] + vmov @s[0], @t[0] + + veor @s[1], @t[2], @s[2] + veor @s[3], @t[0], @s[2] + veor @s[2], @t[0], @s[2] @ @s[2]=@s[3] + + vbsl @s[1], @t[1], @t[0] + vbsl @s[3], @t[3], @t[2] + veor @t[3], @t[3], @t[2] + + vbsl @s[0], @s[1], @s[2] + vbsl @t[0], @s[2], @s[1] + + vand @s[2], @s[0], @s[3] + veor @t[1], @t[1], @t[0] + + veor @s[2], @s[2], @t[3] +___ +# output in s3, s2, s1, t1 + +# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \t2, \t3, \t0, \t1, \s0, \s1, \s2, \s3 + +# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \s3, \s2, \s1, \t1, \s0, \t0, \t2, \t3 + &Mul_GF16_2(@x,@s[3,2,1],@t[1],@s[0],@t[0,2,3]); + +### output msb > [x3,x2,x1,x0,x7,x6,x5,x4] < lsb +} + +# AES linear components + +sub ShiftRows { +my @x=@_[0..7]; +my @t=@_[8..11]; +my $mask=pop; +$code.=<<___; + vldmia $key!, {@t[0]-@t[3]} + veor @t[0], @t[0], @x[0] + veor @t[1], @t[1], @x[1] + vtbl.8 `&Dlo(@x[0])`, {@t[0]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[0])`, {@t[0]}, `&Dhi($mask)` + vldmia $key!, {@t[0]} + veor @t[2], @t[2], @x[2] + vtbl.8 `&Dlo(@x[1])`, {@t[1]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[1])`, {@t[1]}, `&Dhi($mask)` + vldmia $key!, {@t[1]} + veor @t[3], @t[3], @x[3] + vtbl.8 `&Dlo(@x[2])`, {@t[2]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[2])`, {@t[2]}, `&Dhi($mask)` + vldmia $key!, {@t[2]} + vtbl.8 `&Dlo(@x[3])`, {@t[3]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[3])`, {@t[3]}, `&Dhi($mask)` + vldmia $key!, {@t[3]} + veor @t[0], @t[0], @x[4] + veor @t[1], @t[1], @x[5] + vtbl.8 `&Dlo(@x[4])`, {@t[0]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[4])`, {@t[0]}, `&Dhi($mask)` + veor @t[2], @t[2], @x[6] + vtbl.8 `&Dlo(@x[5])`, {@t[1]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[5])`, {@t[1]}, `&Dhi($mask)` + veor @t[3], @t[3], @x[7] + vtbl.8 `&Dlo(@x[6])`, {@t[2]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[6])`, {@t[2]}, `&Dhi($mask)` + vtbl.8 `&Dlo(@x[7])`, {@t[3]}, `&Dlo($mask)` + vtbl.8 `&Dhi(@x[7])`, {@t[3]}, `&Dhi($mask)` +___ +} + +sub MixColumns { +# modified to emit output in order suitable for feeding back to aesenc[last] +my @x=@_[0..7]; +my @t=@_[8..15]; +my $inv=@_[16]; # optional +$code.=<<___; + vext.8 @t[0], @x[0], @x[0], #12 @ x0 <<< 32 + vext.8 @t[1], @x[1], @x[1], #12 + veor @x[0], @x[0], @t[0] @ x0 ^ (x0 <<< 32) + vext.8 @t[2], @x[2], @x[2], #12 + veor @x[1], @x[1], @t[1] + vext.8 @t[3], @x[3], @x[3], #12 + veor @x[2], @x[2], @t[2] + vext.8 @t[4], @x[4], @x[4], #12 + veor @x[3], @x[3], @t[3] + vext.8 @t[5], @x[5], @x[5], #12 + veor @x[4], @x[4], @t[4] + vext.8 @t[6], @x[6], @x[6], #12 + veor @x[5], @x[5], @t[5] + vext.8 @t[7], @x[7], @x[7], #12 + veor @x[6], @x[6], @t[6] + + veor @t[1], @t[1], @x[0] + veor @x[7], @x[7], @t[7] + vext.8 @x[0], @x[0], @x[0], #8 @ (x0 ^ (x0 <<< 32)) <<< 64) + veor @t[2], @t[2], @x[1] + veor @t[0], @t[0], @x[7] + veor @t[1], @t[1], @x[7] + vext.8 @x[1], @x[1], @x[1], #8 + veor @t[5], @t[5], @x[4] + veor @x[0], @x[0], @t[0] + veor @t[6], @t[6], @x[5] + veor @x[1], @x[1], @t[1] + vext.8 @t[0], @x[4], @x[4], #8 + veor @t[4], @t[4], @x[3] + vext.8 @t[1], @x[5], @x[5], #8 + veor @t[7], @t[7], @x[6] + vext.8 @x[4], @x[3], @x[3], #8 + veor @t[3], @t[3], @x[2] + vext.8 @x[5], @x[7], @x[7], #8 + veor @t[4], @t[4], @x[7] + vext.8 @x[3], @x[6], @x[6], #8 + veor @t[3], @t[3], @x[7] + vext.8 @x[6], @x[2], @x[2], #8 + veor @x[7], @t[1], @t[5] +___ +$code.=<<___ if (!$inv); + veor @x[2], @t[0], @t[4] + veor @x[4], @x[4], @t[3] + veor @x[5], @x[5], @t[7] + veor @x[3], @x[3], @t[6] + @ vmov @x[2], @t[0] + veor @x[6], @x[6], @t[2] + @ vmov @x[7], @t[1] +___ +$code.=<<___ if ($inv); + veor @t[3], @t[3], @x[4] + veor @x[5], @x[5], @t[7] + veor @x[2], @x[3], @t[6] + veor @x[3], @t[0], @t[4] + veor @x[4], @x[6], @t[2] + vmov @x[6], @t[3] + @ vmov @x[7], @t[1] +___ +} + +sub InvMixColumns_orig { +my @x=@_[0..7]; +my @t=@_[8..15]; + +$code.=<<___; + @ multiplication by 0x0e + vext.8 @t[7], @x[7], @x[7], #12 + vmov @t[2], @x[2] + veor @x[2], @x[2], @x[5] @ 2 5 + veor @x[7], @x[7], @x[5] @ 7 5 + vext.8 @t[0], @x[0], @x[0], #12 + vmov @t[5], @x[5] + veor @x[5], @x[5], @x[0] @ 5 0 [1] + veor @x[0], @x[0], @x[1] @ 0 1 + vext.8 @t[1], @x[1], @x[1], #12 + veor @x[1], @x[1], @x[2] @ 1 25 + veor @x[0], @x[0], @x[6] @ 01 6 [2] + vext.8 @t[3], @x[3], @x[3], #12 + veor @x[1], @x[1], @x[3] @ 125 3 [4] + veor @x[2], @x[2], @x[0] @ 25 016 [3] + veor @x[3], @x[3], @x[7] @ 3 75 + veor @x[7], @x[7], @x[6] @ 75 6 [0] + vext.8 @t[6], @x[6], @x[6], #12 + vmov @t[4], @x[4] + veor @x[6], @x[6], @x[4] @ 6 4 + veor @x[4], @x[4], @x[3] @ 4 375 [6] + veor @x[3], @x[3], @x[7] @ 375 756=36 + veor @x[6], @x[6], @t[5] @ 64 5 [7] + veor @x[3], @x[3], @t[2] @ 36 2 + vext.8 @t[5], @t[5], @t[5], #12 + veor @x[3], @x[3], @t[4] @ 362 4 [5] +___ + my @y = @x[7,5,0,2,1,3,4,6]; +$code.=<<___; + @ multiplication by 0x0b + veor @y[1], @y[1], @y[0] + veor @y[0], @y[0], @t[0] + vext.8 @t[2], @t[2], @t[2], #12 + veor @y[1], @y[1], @t[1] + veor @y[0], @y[0], @t[5] + vext.8 @t[4], @t[4], @t[4], #12 + veor @y[1], @y[1], @t[6] + veor @y[0], @y[0], @t[7] + veor @t[7], @t[7], @t[6] @ clobber t[7] + + veor @y[3], @y[3], @t[0] + veor @y[1], @y[1], @y[0] + vext.8 @t[0], @t[0], @t[0], #12 + veor @y[2], @y[2], @t[1] + veor @y[4], @y[4], @t[1] + vext.8 @t[1], @t[1], @t[1], #12 + veor @y[2], @y[2], @t[2] + veor @y[3], @y[3], @t[2] + veor @y[5], @y[5], @t[2] + veor @y[2], @y[2], @t[7] + vext.8 @t[2], @t[2], @t[2], #12 + veor @y[3], @y[3], @t[3] + veor @y[6], @y[6], @t[3] + veor @y[4], @y[4], @t[3] + veor @y[7], @y[7], @t[4] + vext.8 @t[3], @t[3], @t[3], #12 + veor @y[5], @y[5], @t[4] + veor @y[7], @y[7], @t[7] + veor @t[7], @t[7], @t[5] @ clobber t[7] even more + veor @y[3], @y[3], @t[5] + veor @y[4], @y[4], @t[4] + + veor @y[5], @y[5], @t[7] + vext.8 @t[4], @t[4], @t[4], #12 + veor @y[6], @y[6], @t[7] + veor @y[4], @y[4], @t[7] + + veor @t[7], @t[7], @t[5] + vext.8 @t[5], @t[5], @t[5], #12 + + @ multiplication by 0x0d + veor @y[4], @y[4], @y[7] + veor @t[7], @t[7], @t[6] @ restore t[7] + veor @y[7], @y[7], @t[4] + vext.8 @t[6], @t[6], @t[6], #12 + veor @y[2], @y[2], @t[0] + veor @y[7], @y[7], @t[5] + vext.8 @t[7], @t[7], @t[7], #12 + veor @y[2], @y[2], @t[2] + + veor @y[3], @y[3], @y[1] + veor @y[1], @y[1], @t[1] + veor @y[0], @y[0], @t[0] + veor @y[3], @y[3], @t[0] + veor @y[1], @y[1], @t[5] + veor @y[0], @y[0], @t[5] + vext.8 @t[0], @t[0], @t[0], #12 + veor @y[1], @y[1], @t[7] + veor @y[0], @y[0], @t[6] + veor @y[3], @y[3], @y[1] + veor @y[4], @y[4], @t[1] + vext.8 @t[1], @t[1], @t[1], #12 + + veor @y[7], @y[7], @t[7] + veor @y[4], @y[4], @t[2] + veor @y[5], @y[5], @t[2] + veor @y[2], @y[2], @t[6] + veor @t[6], @t[6], @t[3] @ clobber t[6] + vext.8 @t[2], @t[2], @t[2], #12 + veor @y[4], @y[4], @y[7] + veor @y[3], @y[3], @t[6] + + veor @y[6], @y[6], @t[6] + veor @y[5], @y[5], @t[5] + vext.8 @t[5], @t[5], @t[5], #12 + veor @y[6], @y[6], @t[4] + vext.8 @t[4], @t[4], @t[4], #12 + veor @y[5], @y[5], @t[6] + veor @y[6], @y[6], @t[7] + vext.8 @t[7], @t[7], @t[7], #12 + veor @t[6], @t[6], @t[3] @ restore t[6] + vext.8 @t[3], @t[3], @t[3], #12 + + @ multiplication by 0x09 + veor @y[4], @y[4], @y[1] + veor @t[1], @t[1], @y[1] @ t[1]=y[1] + veor @t[0], @t[0], @t[5] @ clobber t[0] + vext.8 @t[6], @t[6], @t[6], #12 + veor @t[1], @t[1], @t[5] + veor @y[3], @y[3], @t[0] + veor @t[0], @t[0], @y[0] @ t[0]=y[0] + veor @t[1], @t[1], @t[6] + veor @t[6], @t[6], @t[7] @ clobber t[6] + veor @y[4], @y[4], @t[1] + veor @y[7], @y[7], @t[4] + veor @y[6], @y[6], @t[3] + veor @y[5], @y[5], @t[2] + veor @t[4], @t[4], @y[4] @ t[4]=y[4] + veor @t[3], @t[3], @y[3] @ t[3]=y[3] + veor @t[5], @t[5], @y[5] @ t[5]=y[5] + veor @t[2], @t[2], @y[2] @ t[2]=y[2] + veor @t[3], @t[3], @t[7] + veor @XMM[5], @t[5], @t[6] + veor @XMM[6], @t[6], @y[6] @ t[6]=y[6] + veor @XMM[2], @t[2], @t[6] + veor @XMM[7], @t[7], @y[7] @ t[7]=y[7] + + vmov @XMM[0], @t[0] + vmov @XMM[1], @t[1] + @ vmov @XMM[2], @t[2] + vmov @XMM[3], @t[3] + vmov @XMM[4], @t[4] + @ vmov @XMM[5], @t[5] + @ vmov @XMM[6], @t[6] + @ vmov @XMM[7], @t[7] +___ +} + +sub InvMixColumns { +my @x=@_[0..7]; +my @t=@_[8..15]; + +# Thanks to Jussi Kivilinna for providing pointer to +# +# | 0e 0b 0d 09 | | 02 03 01 01 | | 05 00 04 00 | +# | 09 0e 0b 0d | = | 01 02 03 01 | x | 00 05 00 04 | +# | 0d 09 0e 0b | | 01 01 02 03 | | 04 00 05 00 | +# | 0b 0d 09 0e | | 03 01 01 02 | | 00 04 00 05 | + +$code.=<<___; + @ multiplication by 0x05-0x00-0x04-0x00 + vext.8 @t[0], @x[0], @x[0], #8 + vext.8 @t[6], @x[6], @x[6], #8 + vext.8 @t[7], @x[7], @x[7], #8 + veor @t[0], @t[0], @x[0] + vext.8 @t[1], @x[1], @x[1], #8 + veor @t[6], @t[6], @x[6] + vext.8 @t[2], @x[2], @x[2], #8 + veor @t[7], @t[7], @x[7] + vext.8 @t[3], @x[3], @x[3], #8 + veor @t[1], @t[1], @x[1] + vext.8 @t[4], @x[4], @x[4], #8 + veor @t[2], @t[2], @x[2] + vext.8 @t[5], @x[5], @x[5], #8 + veor @t[3], @t[3], @x[3] + veor @t[4], @t[4], @x[4] + veor @t[5], @t[5], @x[5] + + veor @x[0], @x[0], @t[6] + veor @x[1], @x[1], @t[6] + veor @x[2], @x[2], @t[0] + veor @x[4], @x[4], @t[2] + veor @x[3], @x[3], @t[1] + veor @x[1], @x[1], @t[7] + veor @x[2], @x[2], @t[7] + veor @x[4], @x[4], @t[6] + veor @x[5], @x[5], @t[3] + veor @x[3], @x[3], @t[6] + veor @x[6], @x[6], @t[4] + veor @x[4], @x[4], @t[7] + veor @x[5], @x[5], @t[7] + veor @x[7], @x[7], @t[5] +___ + &MixColumns (@x,@t,1); # flipped 2<->3 and 4<->6 +} + +sub swapmove { +my ($a,$b,$n,$mask,$t)=@_; +$code.=<<___; + vshr.u64 $t, $b, #$n + veor $t, $t, $a + vand $t, $t, $mask + veor $a, $a, $t + vshl.u64 $t, $t, #$n + veor $b, $b, $t +___ +} +sub swapmove2x { +my ($a0,$b0,$a1,$b1,$n,$mask,$t0,$t1)=@_; +$code.=<<___; + vshr.u64 $t0, $b0, #$n + vshr.u64 $t1, $b1, #$n + veor $t0, $t0, $a0 + veor $t1, $t1, $a1 + vand $t0, $t0, $mask + vand $t1, $t1, $mask + veor $a0, $a0, $t0 + vshl.u64 $t0, $t0, #$n + veor $a1, $a1, $t1 + vshl.u64 $t1, $t1, #$n + veor $b0, $b0, $t0 + veor $b1, $b1, $t1 +___ +} + +sub bitslice { +my @x=reverse(@_[0..7]); +my ($t0,$t1,$t2,$t3)=@_[8..11]; +$code.=<<___; + vmov.i8 $t0,#0x55 @ compose .LBS0 + vmov.i8 $t1,#0x33 @ compose .LBS1 +___ + &swapmove2x(@x[0,1,2,3],1,$t0,$t2,$t3); + &swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3); +$code.=<<___; + vmov.i8 $t0,#0x0f @ compose .LBS2 +___ + &swapmove2x(@x[0,2,1,3],2,$t1,$t2,$t3); + &swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3); + + &swapmove2x(@x[0,4,1,5],4,$t0,$t2,$t3); + &swapmove2x(@x[2,6,3,7],4,$t0,$t2,$t3); +} + +$code.=<<___; +#if defined(__arm__) +#ifndef __KERNEL__ +# include "arm_arch.h" + +# define VFP_ABI_PUSH vstmdb sp!,{d8-d15} +# define VFP_ABI_POP vldmia sp!,{d8-d15} +# define VFP_ABI_FRAME 0x40 +#else +# define VFP_ABI_PUSH +# define VFP_ABI_POP +# define VFP_ABI_FRAME 0 +# define BSAES_ASM_EXTENDED_KEY +# define XTS_CHAIN_TWEAK +# define __ARM_ARCH__ __LINUX_ARM_ARCH__ +# define __ARM_MAX_ARCH__ 7 +#endif + +#ifdef __thumb__ +# define adrl adr +#endif + +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.text +.syntax unified @ ARMv7-capable assembler is expected to handle this +#if defined(__thumb2__) && !defined(__APPLE__) +.thumb +#else +.code 32 +#endif + +.type _bsaes_decrypt8,%function +.align 4 +_bsaes_decrypt8: + adr $const,_bsaes_decrypt8 + vldmia $key!, {@XMM[9]} @ round 0 key +#ifdef __APPLE__ + adr $const,.LM0ISR +#else + add $const,$const,#.LM0ISR-_bsaes_decrypt8 +#endif + + vldmia $const!, {@XMM[8]} @ .LM0ISR + veor @XMM[10], @XMM[0], @XMM[9] @ xor with round0 key + veor @XMM[11], @XMM[1], @XMM[9] + vtbl.8 `&Dlo(@XMM[0])`, {@XMM[10]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[0])`, {@XMM[10]}, `&Dhi(@XMM[8])` + veor @XMM[12], @XMM[2], @XMM[9] + vtbl.8 `&Dlo(@XMM[1])`, {@XMM[11]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[1])`, {@XMM[11]}, `&Dhi(@XMM[8])` + veor @XMM[13], @XMM[3], @XMM[9] + vtbl.8 `&Dlo(@XMM[2])`, {@XMM[12]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[2])`, {@XMM[12]}, `&Dhi(@XMM[8])` + veor @XMM[14], @XMM[4], @XMM[9] + vtbl.8 `&Dlo(@XMM[3])`, {@XMM[13]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[3])`, {@XMM[13]}, `&Dhi(@XMM[8])` + veor @XMM[15], @XMM[5], @XMM[9] + vtbl.8 `&Dlo(@XMM[4])`, {@XMM[14]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[4])`, {@XMM[14]}, `&Dhi(@XMM[8])` + veor @XMM[10], @XMM[6], @XMM[9] + vtbl.8 `&Dlo(@XMM[5])`, {@XMM[15]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[5])`, {@XMM[15]}, `&Dhi(@XMM[8])` + veor @XMM[11], @XMM[7], @XMM[9] + vtbl.8 `&Dlo(@XMM[6])`, {@XMM[10]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[6])`, {@XMM[10]}, `&Dhi(@XMM[8])` + vtbl.8 `&Dlo(@XMM[7])`, {@XMM[11]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[7])`, {@XMM[11]}, `&Dhi(@XMM[8])` +___ + &bitslice (@XMM[0..7, 8..11]); +$code.=<<___; + sub $rounds,$rounds,#1 + b .Ldec_sbox +.align 4 +.Ldec_loop: +___ + &ShiftRows (@XMM[0..7, 8..12]); +$code.=".Ldec_sbox:\n"; + &InvSbox (@XMM[0..7, 8..15]); +$code.=<<___; + subs $rounds,$rounds,#1 + bcc .Ldec_done +___ + &InvMixColumns (@XMM[0,1,6,4,2,7,3,5, 8..15]); +$code.=<<___; + vldmia $const, {@XMM[12]} @ .LISR + ite eq @ Thumb2 thing, sanity check in ARM + addeq $const,$const,#0x10 + bne .Ldec_loop + vldmia $const, {@XMM[12]} @ .LISRM0 + b .Ldec_loop +.align 4 +.Ldec_done: +___ + &bitslice (@XMM[0,1,6,4,2,7,3,5, 8..11]); +$code.=<<___; + vldmia $key, {@XMM[8]} @ last round key + veor @XMM[6], @XMM[6], @XMM[8] + veor @XMM[4], @XMM[4], @XMM[8] + veor @XMM[2], @XMM[2], @XMM[8] + veor @XMM[7], @XMM[7], @XMM[8] + veor @XMM[3], @XMM[3], @XMM[8] + veor @XMM[5], @XMM[5], @XMM[8] + veor @XMM[0], @XMM[0], @XMM[8] + veor @XMM[1], @XMM[1], @XMM[8] + bx lr +.size _bsaes_decrypt8,.-_bsaes_decrypt8 + +.type _bsaes_const,%object +.align 6 +_bsaes_const: +.LM0ISR: @ InvShiftRows constants + .quad 0x0a0e0206070b0f03, 0x0004080c0d010509 +.LISR: + .quad 0x0504070602010003, 0x0f0e0d0c080b0a09 +.LISRM0: + .quad 0x01040b0e0205080f, 0x0306090c00070a0d +.LM0SR: @ ShiftRows constants + .quad 0x0a0e02060f03070b, 0x0004080c05090d01 +.LSR: + .quad 0x0504070600030201, 0x0f0e0d0c0a09080b +.LSRM0: + .quad 0x0304090e00050a0f, 0x01060b0c0207080d +.LM0: + .quad 0x02060a0e03070b0f, 0x0004080c0105090d +.LREVM0SR: + .quad 0x090d01050c000408, 0x03070b0f060a0e02 +.asciz "Bit-sliced AES for NEON, CRYPTOGAMS by " +.align 6 +.size _bsaes_const,.-_bsaes_const + +.type _bsaes_encrypt8,%function +.align 4 +_bsaes_encrypt8: + adr $const,_bsaes_encrypt8 + vldmia $key!, {@XMM[9]} @ round 0 key +#ifdef __APPLE__ + adr $const,.LM0SR +#else + sub $const,$const,#_bsaes_encrypt8-.LM0SR +#endif + + vldmia $const!, {@XMM[8]} @ .LM0SR +_bsaes_encrypt8_alt: + veor @XMM[10], @XMM[0], @XMM[9] @ xor with round0 key + veor @XMM[11], @XMM[1], @XMM[9] + vtbl.8 `&Dlo(@XMM[0])`, {@XMM[10]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[0])`, {@XMM[10]}, `&Dhi(@XMM[8])` + veor @XMM[12], @XMM[2], @XMM[9] + vtbl.8 `&Dlo(@XMM[1])`, {@XMM[11]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[1])`, {@XMM[11]}, `&Dhi(@XMM[8])` + veor @XMM[13], @XMM[3], @XMM[9] + vtbl.8 `&Dlo(@XMM[2])`, {@XMM[12]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[2])`, {@XMM[12]}, `&Dhi(@XMM[8])` + veor @XMM[14], @XMM[4], @XMM[9] + vtbl.8 `&Dlo(@XMM[3])`, {@XMM[13]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[3])`, {@XMM[13]}, `&Dhi(@XMM[8])` + veor @XMM[15], @XMM[5], @XMM[9] + vtbl.8 `&Dlo(@XMM[4])`, {@XMM[14]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[4])`, {@XMM[14]}, `&Dhi(@XMM[8])` + veor @XMM[10], @XMM[6], @XMM[9] + vtbl.8 `&Dlo(@XMM[5])`, {@XMM[15]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[5])`, {@XMM[15]}, `&Dhi(@XMM[8])` + veor @XMM[11], @XMM[7], @XMM[9] + vtbl.8 `&Dlo(@XMM[6])`, {@XMM[10]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[6])`, {@XMM[10]}, `&Dhi(@XMM[8])` + vtbl.8 `&Dlo(@XMM[7])`, {@XMM[11]}, `&Dlo(@XMM[8])` + vtbl.8 `&Dhi(@XMM[7])`, {@XMM[11]}, `&Dhi(@XMM[8])` +_bsaes_encrypt8_bitslice: +___ + &bitslice (@XMM[0..7, 8..11]); +$code.=<<___; + sub $rounds,$rounds,#1 + b .Lenc_sbox +.align 4 +.Lenc_loop: +___ + &ShiftRows (@XMM[0..7, 8..12]); +$code.=".Lenc_sbox:\n"; + &Sbox (@XMM[0..7, 8..15]); +$code.=<<___; + subs $rounds,$rounds,#1 + bcc .Lenc_done +___ + &MixColumns (@XMM[0,1,4,6,3,7,2,5, 8..15]); +$code.=<<___; + vldmia $const, {@XMM[12]} @ .LSR + ite eq @ Thumb2 thing, samity check in ARM + addeq $const,$const,#0x10 + bne .Lenc_loop + vldmia $const, {@XMM[12]} @ .LSRM0 + b .Lenc_loop +.align 4 +.Lenc_done: +___ + # output in lsb > [t0, t1, t4, t6, t3, t7, t2, t5] < msb + &bitslice (@XMM[0,1,4,6,3,7,2,5, 8..11]); +$code.=<<___; + vldmia $key, {@XMM[8]} @ last round key + veor @XMM[4], @XMM[4], @XMM[8] + veor @XMM[6], @XMM[6], @XMM[8] + veor @XMM[3], @XMM[3], @XMM[8] + veor @XMM[7], @XMM[7], @XMM[8] + veor @XMM[2], @XMM[2], @XMM[8] + veor @XMM[5], @XMM[5], @XMM[8] + veor @XMM[0], @XMM[0], @XMM[8] + veor @XMM[1], @XMM[1], @XMM[8] + bx lr +.size _bsaes_encrypt8,.-_bsaes_encrypt8 +___ +} +{ +my ($out,$inp,$rounds,$const)=("r12","r4","r5","r6"); + +sub bitslice_key { +my @x=reverse(@_[0..7]); +my ($bs0,$bs1,$bs2,$t2,$t3)=@_[8..12]; + + &swapmove (@x[0,1],1,$bs0,$t2,$t3); +$code.=<<___; + @ &swapmove(@x[2,3],1,$t0,$t2,$t3); + vmov @x[2], @x[0] + vmov @x[3], @x[1] +___ + #&swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3); + + &swapmove2x (@x[0,2,1,3],2,$bs1,$t2,$t3); +$code.=<<___; + @ &swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3); + vmov @x[4], @x[0] + vmov @x[6], @x[2] + vmov @x[5], @x[1] + vmov @x[7], @x[3] +___ + &swapmove2x (@x[0,4,1,5],4,$bs2,$t2,$t3); + &swapmove2x (@x[2,6,3,7],4,$bs2,$t2,$t3); +} + +$code.=<<___; +.type _bsaes_key_convert,%function +.align 4 +_bsaes_key_convert: + adr $const,_bsaes_key_convert + vld1.8 {@XMM[7]}, [$inp]! @ load round 0 key +#ifdef __APPLE__ + adr $const,.LM0 +#else + sub $const,$const,#_bsaes_key_convert-.LM0 +#endif + vld1.8 {@XMM[15]}, [$inp]! @ load round 1 key + + vmov.i8 @XMM[8], #0x01 @ bit masks + vmov.i8 @XMM[9], #0x02 + vmov.i8 @XMM[10], #0x04 + vmov.i8 @XMM[11], #0x08 + vmov.i8 @XMM[12], #0x10 + vmov.i8 @XMM[13], #0x20 + vldmia $const, {@XMM[14]} @ .LM0 + +#ifdef __ARMEL__ + vrev32.8 @XMM[7], @XMM[7] + vrev32.8 @XMM[15], @XMM[15] +#endif + sub $rounds,$rounds,#1 + vstmia $out!, {@XMM[7]} @ save round 0 key + b .Lkey_loop + +.align 4 +.Lkey_loop: + vtbl.8 `&Dlo(@XMM[7])`,{@XMM[15]},`&Dlo(@XMM[14])` + vtbl.8 `&Dhi(@XMM[7])`,{@XMM[15]},`&Dhi(@XMM[14])` + vmov.i8 @XMM[6], #0x40 + vmov.i8 @XMM[15], #0x80 + + vtst.8 @XMM[0], @XMM[7], @XMM[8] + vtst.8 @XMM[1], @XMM[7], @XMM[9] + vtst.8 @XMM[2], @XMM[7], @XMM[10] + vtst.8 @XMM[3], @XMM[7], @XMM[11] + vtst.8 @XMM[4], @XMM[7], @XMM[12] + vtst.8 @XMM[5], @XMM[7], @XMM[13] + vtst.8 @XMM[6], @XMM[7], @XMM[6] + vtst.8 @XMM[7], @XMM[7], @XMM[15] + vld1.8 {@XMM[15]}, [$inp]! @ load next round key + vmvn @XMM[0], @XMM[0] @ "pnot" + vmvn @XMM[1], @XMM[1] + vmvn @XMM[5], @XMM[5] + vmvn @XMM[6], @XMM[6] +#ifdef __ARMEL__ + vrev32.8 @XMM[15], @XMM[15] +#endif + subs $rounds,$rounds,#1 + vstmia $out!,{@XMM[0]-@XMM[7]} @ write bit-sliced round key + bne .Lkey_loop + + vmov.i8 @XMM[7],#0x63 @ compose .L63 + @ don't save last round key + bx lr +.size _bsaes_key_convert,.-_bsaes_key_convert +___ +} + +if (0) { # following four functions are unsupported interface + # used for benchmarking... +$code.=<<___; +.globl bsaes_enc_key_convert +.hidden bsaes_enc_key_convert +.type bsaes_enc_key_convert,%function +.align 4 +bsaes_enc_key_convert: + stmdb sp!,{r4-r6,lr} + vstmdb sp!,{d8-d15} @ ABI specification says so + + ldr r5,[$inp,#240] @ pass rounds + mov r4,$inp @ pass key + mov r12,$out @ pass key schedule + bl _bsaes_key_convert + veor @XMM[7],@XMM[7],@XMM[15] @ fix up last round key + vstmia r12, {@XMM[7]} @ save last round key + + vldmia sp!,{d8-d15} + ldmia sp!,{r4-r6,pc} +.size bsaes_enc_key_convert,.-bsaes_enc_key_convert + +.globl bsaes_encrypt_128 +.hidden bsaes_encrypt_128 +.type bsaes_encrypt_128,%function +.align 4 +bsaes_encrypt_128: + stmdb sp!,{r4-r6,lr} + vstmdb sp!,{d8-d15} @ ABI specification says so +.Lenc128_loop: + vld1.8 {@XMM[0]-@XMM[1]}, [$inp]! @ load input + vld1.8 {@XMM[2]-@XMM[3]}, [$inp]! + mov r4,$key @ pass the key + vld1.8 {@XMM[4]-@XMM[5]}, [$inp]! + mov r5,#10 @ pass rounds + vld1.8 {@XMM[6]-@XMM[7]}, [$inp]! + + bl _bsaes_encrypt8 + + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + vst1.8 {@XMM[4]}, [$out]! + vst1.8 {@XMM[6]}, [$out]! + vst1.8 {@XMM[3]}, [$out]! + vst1.8 {@XMM[7]}, [$out]! + vst1.8 {@XMM[2]}, [$out]! + subs $len,$len,#0x80 + vst1.8 {@XMM[5]}, [$out]! + bhi .Lenc128_loop + + vldmia sp!,{d8-d15} + ldmia sp!,{r4-r6,pc} +.size bsaes_encrypt_128,.-bsaes_encrypt_128 + +.globl bsaes_dec_key_convert +.hidden bsaes_dec_key_convert +.type bsaes_dec_key_convert,%function +.align 4 +bsaes_dec_key_convert: + stmdb sp!,{r4-r6,lr} + vstmdb sp!,{d8-d15} @ ABI specification says so + + ldr r5,[$inp,#240] @ pass rounds + mov r4,$inp @ pass key + mov r12,$out @ pass key schedule + bl _bsaes_key_convert + vldmia $out, {@XMM[6]} + vstmia r12, {@XMM[15]} @ save last round key + veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key + vstmia $out, {@XMM[7]} + + vldmia sp!,{d8-d15} + ldmia sp!,{r4-r6,pc} +.size bsaes_dec_key_convert,.-bsaes_dec_key_convert + +.globl bsaes_decrypt_128 +.hidden bsaes_decrypt_128 +.type bsaes_decrypt_128,%function +.align 4 +bsaes_decrypt_128: + stmdb sp!,{r4-r6,lr} + vstmdb sp!,{d8-d15} @ ABI specification says so +.Ldec128_loop: + vld1.8 {@XMM[0]-@XMM[1]}, [$inp]! @ load input + vld1.8 {@XMM[2]-@XMM[3]}, [$inp]! + mov r4,$key @ pass the key + vld1.8 {@XMM[4]-@XMM[5]}, [$inp]! + mov r5,#10 @ pass rounds + vld1.8 {@XMM[6]-@XMM[7]}, [$inp]! + + bl _bsaes_decrypt8 + + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + vst1.8 {@XMM[6]}, [$out]! + vst1.8 {@XMM[4]}, [$out]! + vst1.8 {@XMM[2]}, [$out]! + vst1.8 {@XMM[7]}, [$out]! + vst1.8 {@XMM[3]}, [$out]! + subs $len,$len,#0x80 + vst1.8 {@XMM[5]}, [$out]! + bhi .Ldec128_loop + + vldmia sp!,{d8-d15} + ldmia sp!,{r4-r6,pc} +.size bsaes_decrypt_128,.-bsaes_decrypt_128 +___ +} +{ +my ($inp,$out,$len,$key, $ivp,$fp,$rounds)=map("r$_",(0..3,8..10)); +my ($keysched)=("sp"); + +$code.=<<___; +.extern AES_cbc_encrypt +.extern AES_decrypt + +.global bsaes_cbc_encrypt +.hidden bsaes_cbc_encrypt +.type bsaes_cbc_encrypt,%function +.align 5 +bsaes_cbc_encrypt: +#ifndef __KERNEL__ + cmp $len, #128 +#ifndef __thumb__ + blo AES_cbc_encrypt +#else + bhs 1f + b AES_cbc_encrypt +1: +#endif +#endif + + @ it is up to the caller to make sure we are called with enc == 0 + + mov ip, sp + stmdb sp!, {r4-r10, lr} + VFP_ABI_PUSH + ldr $ivp, [ip] @ IV is 1st arg on the stack + mov $len, $len, lsr#4 @ len in 16 byte blocks + sub sp, #0x10 @ scratch space to carry over the IV + mov $fp, sp @ save sp + + ldr $rounds, [$key, #240] @ get # of rounds +#ifndef BSAES_ASM_EXTENDED_KEY + @ allocate the key schedule on the stack + sub r12, sp, $rounds, lsl#7 @ 128 bytes per inner round key + add r12, #`128-32` @ sifze of bit-slices key schedule + + @ populate the key schedule + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + mov sp, r12 @ sp is $keysched + bl _bsaes_key_convert + vldmia $keysched, {@XMM[6]} + vstmia r12, {@XMM[15]} @ save last round key + veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key + vstmia $keysched, {@XMM[7]} +#else + ldr r12, [$key, #244] + eors r12, #1 + beq 0f + + @ populate the key schedule + str r12, [$key, #244] + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + add r12, $key, #248 @ pass key schedule + bl _bsaes_key_convert + add r4, $key, #248 + vldmia r4, {@XMM[6]} + vstmia r12, {@XMM[15]} @ save last round key + veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key + vstmia r4, {@XMM[7]} + +.align 2 +0: +#endif + + vld1.8 {@XMM[15]}, [$ivp] @ load IV + b .Lcbc_dec_loop + +.align 4 +.Lcbc_dec_loop: + subs $len, $len, #0x8 + bmi .Lcbc_dec_loop_finish + + vld1.8 {@XMM[0]-@XMM[1]}, [$inp]! @ load input + vld1.8 {@XMM[2]-@XMM[3]}, [$inp]! +#ifndef BSAES_ASM_EXTENDED_KEY + mov r4, $keysched @ pass the key +#else + add r4, $key, #248 +#endif + vld1.8 {@XMM[4]-@XMM[5]}, [$inp]! + mov r5, $rounds + vld1.8 {@XMM[6]-@XMM[7]}, [$inp] + sub $inp, $inp, #0x60 + vstmia $fp, {@XMM[15]} @ put aside IV + + bl _bsaes_decrypt8 + + vldmia $fp, {@XMM[14]} @ reload IV + vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input + veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV + vld1.8 {@XMM[10]-@XMM[11]}, [$inp]! + veor @XMM[1], @XMM[1], @XMM[8] + veor @XMM[6], @XMM[6], @XMM[9] + vld1.8 {@XMM[12]-@XMM[13]}, [$inp]! + veor @XMM[4], @XMM[4], @XMM[10] + veor @XMM[2], @XMM[2], @XMM[11] + vld1.8 {@XMM[14]-@XMM[15]}, [$inp]! + veor @XMM[7], @XMM[7], @XMM[12] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + veor @XMM[3], @XMM[3], @XMM[13] + vst1.8 {@XMM[6]}, [$out]! + veor @XMM[5], @XMM[5], @XMM[14] + vst1.8 {@XMM[4]}, [$out]! + vst1.8 {@XMM[2]}, [$out]! + vst1.8 {@XMM[7]}, [$out]! + vst1.8 {@XMM[3]}, [$out]! + vst1.8 {@XMM[5]}, [$out]! + + b .Lcbc_dec_loop + +.Lcbc_dec_loop_finish: + adds $len, $len, #8 + beq .Lcbc_dec_done + + vld1.8 {@XMM[0]}, [$inp]! @ load input + cmp $len, #2 + blo .Lcbc_dec_one + vld1.8 {@XMM[1]}, [$inp]! +#ifndef BSAES_ASM_EXTENDED_KEY + mov r4, $keysched @ pass the key +#else + add r4, $key, #248 +#endif + mov r5, $rounds + vstmia $fp, {@XMM[15]} @ put aside IV + beq .Lcbc_dec_two + vld1.8 {@XMM[2]}, [$inp]! + cmp $len, #4 + blo .Lcbc_dec_three + vld1.8 {@XMM[3]}, [$inp]! + beq .Lcbc_dec_four + vld1.8 {@XMM[4]}, [$inp]! + cmp $len, #6 + blo .Lcbc_dec_five + vld1.8 {@XMM[5]}, [$inp]! + beq .Lcbc_dec_six + vld1.8 {@XMM[6]}, [$inp]! + sub $inp, $inp, #0x70 + + bl _bsaes_decrypt8 + + vldmia $fp, {@XMM[14]} @ reload IV + vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input + veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV + vld1.8 {@XMM[10]-@XMM[11]}, [$inp]! + veor @XMM[1], @XMM[1], @XMM[8] + veor @XMM[6], @XMM[6], @XMM[9] + vld1.8 {@XMM[12]-@XMM[13]}, [$inp]! + veor @XMM[4], @XMM[4], @XMM[10] + veor @XMM[2], @XMM[2], @XMM[11] + vld1.8 {@XMM[15]}, [$inp]! + veor @XMM[7], @XMM[7], @XMM[12] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + veor @XMM[3], @XMM[3], @XMM[13] + vst1.8 {@XMM[6]}, [$out]! + vst1.8 {@XMM[4]}, [$out]! + vst1.8 {@XMM[2]}, [$out]! + vst1.8 {@XMM[7]}, [$out]! + vst1.8 {@XMM[3]}, [$out]! + b .Lcbc_dec_done +.align 4 +.Lcbc_dec_six: + sub $inp, $inp, #0x60 + bl _bsaes_decrypt8 + vldmia $fp,{@XMM[14]} @ reload IV + vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input + veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV + vld1.8 {@XMM[10]-@XMM[11]}, [$inp]! + veor @XMM[1], @XMM[1], @XMM[8] + veor @XMM[6], @XMM[6], @XMM[9] + vld1.8 {@XMM[12]}, [$inp]! + veor @XMM[4], @XMM[4], @XMM[10] + veor @XMM[2], @XMM[2], @XMM[11] + vld1.8 {@XMM[15]}, [$inp]! + veor @XMM[7], @XMM[7], @XMM[12] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + vst1.8 {@XMM[6]}, [$out]! + vst1.8 {@XMM[4]}, [$out]! + vst1.8 {@XMM[2]}, [$out]! + vst1.8 {@XMM[7]}, [$out]! + b .Lcbc_dec_done +.align 4 +.Lcbc_dec_five: + sub $inp, $inp, #0x50 + bl _bsaes_decrypt8 + vldmia $fp, {@XMM[14]} @ reload IV + vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input + veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV + vld1.8 {@XMM[10]-@XMM[11]}, [$inp]! + veor @XMM[1], @XMM[1], @XMM[8] + veor @XMM[6], @XMM[6], @XMM[9] + vld1.8 {@XMM[15]}, [$inp]! + veor @XMM[4], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + veor @XMM[2], @XMM[2], @XMM[11] + vst1.8 {@XMM[6]}, [$out]! + vst1.8 {@XMM[4]}, [$out]! + vst1.8 {@XMM[2]}, [$out]! + b .Lcbc_dec_done +.align 4 +.Lcbc_dec_four: + sub $inp, $inp, #0x40 + bl _bsaes_decrypt8 + vldmia $fp, {@XMM[14]} @ reload IV + vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input + veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV + vld1.8 {@XMM[10]}, [$inp]! + veor @XMM[1], @XMM[1], @XMM[8] + veor @XMM[6], @XMM[6], @XMM[9] + vld1.8 {@XMM[15]}, [$inp]! + veor @XMM[4], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + vst1.8 {@XMM[6]}, [$out]! + vst1.8 {@XMM[4]}, [$out]! + b .Lcbc_dec_done +.align 4 +.Lcbc_dec_three: + sub $inp, $inp, #0x30 + bl _bsaes_decrypt8 + vldmia $fp, {@XMM[14]} @ reload IV + vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ reload input + veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV + vld1.8 {@XMM[15]}, [$inp]! + veor @XMM[1], @XMM[1], @XMM[8] + veor @XMM[6], @XMM[6], @XMM[9] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + vst1.8 {@XMM[6]}, [$out]! + b .Lcbc_dec_done +.align 4 +.Lcbc_dec_two: + sub $inp, $inp, #0x20 + bl _bsaes_decrypt8 + vldmia $fp, {@XMM[14]} @ reload IV + vld1.8 {@XMM[8]}, [$inp]! @ reload input + veor @XMM[0], @XMM[0], @XMM[14] @ ^= IV + vld1.8 {@XMM[15]}, [$inp]! @ reload input + veor @XMM[1], @XMM[1], @XMM[8] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + b .Lcbc_dec_done +.align 4 +.Lcbc_dec_one: + sub $inp, $inp, #0x10 + mov $rounds, $out @ save original out pointer + mov $out, $fp @ use the iv scratch space as out buffer + mov r2, $key + vmov @XMM[4],@XMM[15] @ just in case ensure that IV + vmov @XMM[5],@XMM[0] @ and input are preserved + bl AES_decrypt + vld1.8 {@XMM[0]}, [$fp,:64] @ load result + veor @XMM[0], @XMM[0], @XMM[4] @ ^= IV + vmov @XMM[15], @XMM[5] @ @XMM[5] holds input + vst1.8 {@XMM[0]}, [$rounds] @ write output + +.Lcbc_dec_done: +#ifndef BSAES_ASM_EXTENDED_KEY + vmov.i32 q0, #0 + vmov.i32 q1, #0 +.Lcbc_dec_bzero: @ wipe key schedule [if any] + vstmia $keysched!, {q0-q1} + cmp $keysched, $fp + bne .Lcbc_dec_bzero +#endif + + mov sp, $fp + add sp, #0x10 @ add sp,$fp,#0x10 is no good for thumb + vst1.8 {@XMM[15]}, [$ivp] @ return IV + VFP_ABI_POP + ldmia sp!, {r4-r10, pc} +.size bsaes_cbc_encrypt,.-bsaes_cbc_encrypt +___ +} +{ +my ($inp,$out,$len,$key, $ctr,$fp,$rounds)=(map("r$_",(0..3,8..10))); +my $const = "r6"; # shared with _bsaes_encrypt8_alt +my $keysched = "sp"; + +$code.=<<___; +.extern AES_encrypt +.global bsaes_ctr32_encrypt_blocks +.hidden bsaes_ctr32_encrypt_blocks +.type bsaes_ctr32_encrypt_blocks,%function +.align 5 +bsaes_ctr32_encrypt_blocks: + cmp $len, #8 @ use plain AES for + blo .Lctr_enc_short @ small sizes + + mov ip, sp + stmdb sp!, {r4-r10, lr} + VFP_ABI_PUSH + ldr $ctr, [ip] @ ctr is 1st arg on the stack + sub sp, sp, #0x10 @ scratch space to carry over the ctr + mov $fp, sp @ save sp + + ldr $rounds, [$key, #240] @ get # of rounds +#ifndef BSAES_ASM_EXTENDED_KEY + @ allocate the key schedule on the stack + sub r12, sp, $rounds, lsl#7 @ 128 bytes per inner round key + add r12, #`128-32` @ size of bit-sliced key schedule + + @ populate the key schedule + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + mov sp, r12 @ sp is $keysched + bl _bsaes_key_convert + veor @XMM[7],@XMM[7],@XMM[15] @ fix up last round key + vstmia r12, {@XMM[7]} @ save last round key + + vld1.8 {@XMM[0]}, [$ctr] @ load counter +#ifdef __APPLE__ + mov $ctr, #:lower16:(.LREVM0SR-.LM0) + add $ctr, $const, $ctr +#else + add $ctr, $const, #.LREVM0SR-.LM0 @ borrow $ctr +#endif + vldmia $keysched, {@XMM[4]} @ load round0 key +#else + ldr r12, [$key, #244] + eors r12, #1 + beq 0f + + @ populate the key schedule + str r12, [$key, #244] + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + add r12, $key, #248 @ pass key schedule + bl _bsaes_key_convert + veor @XMM[7],@XMM[7],@XMM[15] @ fix up last round key + vstmia r12, {@XMM[7]} @ save last round key + +.align 2 +0: add r12, $key, #248 + vld1.8 {@XMM[0]}, [$ctr] @ load counter + adrl $ctr, .LREVM0SR @ borrow $ctr + vldmia r12, {@XMM[4]} @ load round0 key + sub sp, #0x10 @ place for adjusted round0 key +#endif + + vmov.i32 @XMM[8],#1 @ compose 1<<96 + veor @XMM[9],@XMM[9],@XMM[9] + vrev32.8 @XMM[0],@XMM[0] + vext.8 @XMM[8],@XMM[9],@XMM[8],#4 + vrev32.8 @XMM[4],@XMM[4] + vadd.u32 @XMM[9],@XMM[8],@XMM[8] @ compose 2<<96 + vstmia $keysched, {@XMM[4]} @ save adjusted round0 key + b .Lctr_enc_loop + +.align 4 +.Lctr_enc_loop: + vadd.u32 @XMM[10], @XMM[8], @XMM[9] @ compose 3<<96 + vadd.u32 @XMM[1], @XMM[0], @XMM[8] @ +1 + vadd.u32 @XMM[2], @XMM[0], @XMM[9] @ +2 + vadd.u32 @XMM[3], @XMM[0], @XMM[10] @ +3 + vadd.u32 @XMM[4], @XMM[1], @XMM[10] + vadd.u32 @XMM[5], @XMM[2], @XMM[10] + vadd.u32 @XMM[6], @XMM[3], @XMM[10] + vadd.u32 @XMM[7], @XMM[4], @XMM[10] + vadd.u32 @XMM[10], @XMM[5], @XMM[10] @ next counter + + @ Borrow prologue from _bsaes_encrypt8 to use the opportunity + @ to flip byte order in 32-bit counter + + vldmia $keysched, {@XMM[9]} @ load round0 key +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, $keysched, #0x10 @ pass next round key +#else + add r4, $key, #`248+16` +#endif + vldmia $ctr, {@XMM[8]} @ .LREVM0SR + mov r5, $rounds @ pass rounds + vstmia $fp, {@XMM[10]} @ save next counter +#ifdef __APPLE__ + mov $const, #:lower16:(.LREVM0SR-.LSR) + sub $const, $ctr, $const +#else + sub $const, $ctr, #.LREVM0SR-.LSR @ pass constants +#endif + + bl _bsaes_encrypt8_alt + + subs $len, $len, #8 + blo .Lctr_enc_loop_done + + vld1.8 {@XMM[8]-@XMM[9]}, [$inp]! @ load input + vld1.8 {@XMM[10]-@XMM[11]}, [$inp]! + veor @XMM[0], @XMM[8] + veor @XMM[1], @XMM[9] + vld1.8 {@XMM[12]-@XMM[13]}, [$inp]! + veor @XMM[4], @XMM[10] + veor @XMM[6], @XMM[11] + vld1.8 {@XMM[14]-@XMM[15]}, [$inp]! + veor @XMM[3], @XMM[12] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! @ write output + veor @XMM[7], @XMM[13] + veor @XMM[2], @XMM[14] + vst1.8 {@XMM[4]}, [$out]! + veor @XMM[5], @XMM[15] + vst1.8 {@XMM[6]}, [$out]! + vmov.i32 @XMM[8], #1 @ compose 1<<96 + vst1.8 {@XMM[3]}, [$out]! + veor @XMM[9], @XMM[9], @XMM[9] + vst1.8 {@XMM[7]}, [$out]! + vext.8 @XMM[8], @XMM[9], @XMM[8], #4 + vst1.8 {@XMM[2]}, [$out]! + vadd.u32 @XMM[9],@XMM[8],@XMM[8] @ compose 2<<96 + vst1.8 {@XMM[5]}, [$out]! + vldmia $fp, {@XMM[0]} @ load counter + + bne .Lctr_enc_loop + b .Lctr_enc_done + +.align 4 +.Lctr_enc_loop_done: + add $len, $len, #8 + vld1.8 {@XMM[8]}, [$inp]! @ load input + veor @XMM[0], @XMM[8] + vst1.8 {@XMM[0]}, [$out]! @ write output + cmp $len, #2 + blo .Lctr_enc_done + vld1.8 {@XMM[9]}, [$inp]! + veor @XMM[1], @XMM[9] + vst1.8 {@XMM[1]}, [$out]! + beq .Lctr_enc_done + vld1.8 {@XMM[10]}, [$inp]! + veor @XMM[4], @XMM[10] + vst1.8 {@XMM[4]}, [$out]! + cmp $len, #4 + blo .Lctr_enc_done + vld1.8 {@XMM[11]}, [$inp]! + veor @XMM[6], @XMM[11] + vst1.8 {@XMM[6]}, [$out]! + beq .Lctr_enc_done + vld1.8 {@XMM[12]}, [$inp]! + veor @XMM[3], @XMM[12] + vst1.8 {@XMM[3]}, [$out]! + cmp $len, #6 + blo .Lctr_enc_done + vld1.8 {@XMM[13]}, [$inp]! + veor @XMM[7], @XMM[13] + vst1.8 {@XMM[7]}, [$out]! + beq .Lctr_enc_done + vld1.8 {@XMM[14]}, [$inp] + veor @XMM[2], @XMM[14] + vst1.8 {@XMM[2]}, [$out]! + +.Lctr_enc_done: + vmov.i32 q0, #0 + vmov.i32 q1, #0 +#ifndef BSAES_ASM_EXTENDED_KEY +.Lctr_enc_bzero: @ wipe key schedule [if any] + vstmia $keysched!, {q0-q1} + cmp $keysched, $fp + bne .Lctr_enc_bzero +#else + vstmia $keysched, {q0-q1} +#endif + + mov sp, $fp + add sp, #0x10 @ add sp,$fp,#0x10 is no good for thumb + VFP_ABI_POP + ldmia sp!, {r4-r10, pc} @ return + +.align 4 +.Lctr_enc_short: + ldr ip, [sp] @ ctr pointer is passed on stack + stmdb sp!, {r4-r8, lr} + + mov r4, $inp @ copy arguments + mov r5, $out + mov r6, $len + mov r7, $key + ldr r8, [ip, #12] @ load counter LSW + vld1.8 {@XMM[1]}, [ip] @ load whole counter value +#ifdef __ARMEL__ + rev r8, r8 +#endif + sub sp, sp, #0x10 + vst1.8 {@XMM[1]}, [sp] @ copy counter value + sub sp, sp, #0x10 + +.Lctr_enc_short_loop: + add r0, sp, #0x10 @ input counter value + mov r1, sp @ output on the stack + mov r2, r7 @ key + + bl AES_encrypt + + vld1.8 {@XMM[0]}, [r4]! @ load input + vld1.8 {@XMM[1]}, [sp] @ load encrypted counter + add r8, r8, #1 +#ifdef __ARMEL__ + rev r0, r8 + str r0, [sp, #0x1c] @ next counter value +#else + str r8, [sp, #0x1c] @ next counter value +#endif + veor @XMM[0],@XMM[0],@XMM[1] + vst1.8 {@XMM[0]}, [r5]! @ store output + subs r6, r6, #1 + bne .Lctr_enc_short_loop + + vmov.i32 q0, #0 + vmov.i32 q1, #0 + vstmia sp!, {q0-q1} + + ldmia sp!, {r4-r8, pc} +.size bsaes_ctr32_encrypt_blocks,.-bsaes_ctr32_encrypt_blocks +___ +} +{ +###################################################################### +# void bsaes_xts_[en|de]crypt(const char *inp,char *out,size_t len, +# const AES_KEY *key1, const AES_KEY *key2, +# const unsigned char iv[16]); +# +my ($inp,$out,$len,$key,$rounds,$magic,$fp)=(map("r$_",(7..10,1..3))); +my $const="r6"; # returned by _bsaes_key_convert +my $twmask=@XMM[5]; +my @T=@XMM[6..7]; + +$code.=<<___; +.globl bsaes_xts_encrypt +.hidden bsaes_xts_encrypt +.type bsaes_xts_encrypt,%function +.align 4 +bsaes_xts_encrypt: + mov ip, sp + stmdb sp!, {r4-r10, lr} @ 0x20 + VFP_ABI_PUSH + mov r6, sp @ future $fp + + mov $inp, r0 + mov $out, r1 + mov $len, r2 + mov $key, r3 + + sub r0, sp, #0x10 @ 0x10 + bic r0, #0xf @ align at 16 bytes + mov sp, r0 + +#ifdef XTS_CHAIN_TWEAK + ldr r0, [ip] @ pointer to input tweak +#else + @ generate initial tweak + ldr r0, [ip, #4] @ iv[] + mov r1, sp + ldr r2, [ip, #0] @ key2 + bl AES_encrypt + mov r0,sp @ pointer to initial tweak +#endif + + ldr $rounds, [$key, #240] @ get # of rounds + mov $fp, r6 +#ifndef BSAES_ASM_EXTENDED_KEY + @ allocate the key schedule on the stack + sub r12, sp, $rounds, lsl#7 @ 128 bytes per inner round key + @ add r12, #`128-32` @ size of bit-sliced key schedule + sub r12, #`32+16` @ place for tweak[9] + + @ populate the key schedule + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + mov sp, r12 + add r12, #0x90 @ pass key schedule + bl _bsaes_key_convert + veor @XMM[7], @XMM[7], @XMM[15] @ fix up last round key + vstmia r12, {@XMM[7]} @ save last round key +#else + ldr r12, [$key, #244] + eors r12, #1 + beq 0f + + str r12, [$key, #244] + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + add r12, $key, #248 @ pass key schedule + bl _bsaes_key_convert + veor @XMM[7], @XMM[7], @XMM[15] @ fix up last round key + vstmia r12, {@XMM[7]} + +.align 2 +0: sub sp, #0x90 @ place for tweak[9] +#endif + + vld1.8 {@XMM[8]}, [r0] @ initial tweak + adr $magic, .Lxts_magic + + subs $len, #0x80 + blo .Lxts_enc_short + b .Lxts_enc_loop + +.align 4 +.Lxts_enc_loop: + vldmia $magic, {$twmask} @ load XTS magic + vshr.s64 @T[0], @XMM[8], #63 + mov r0, sp + vand @T[0], @T[0], $twmask +___ +for($i=9;$i<16;$i++) { +$code.=<<___; + vadd.u64 @XMM[$i], @XMM[$i-1], @XMM[$i-1] + vst1.64 {@XMM[$i-1]}, [r0,:128]! + vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")` + vshr.s64 @T[1], @XMM[$i], #63 + veor @XMM[$i], @XMM[$i], @T[0] + vand @T[1], @T[1], $twmask +___ + @T=reverse(@T); + +$code.=<<___ if ($i>=10); + vld1.8 {@XMM[$i-10]}, [$inp]! +___ +$code.=<<___ if ($i>=11); + veor @XMM[$i-11], @XMM[$i-11], @XMM[$i-3] +___ +} +$code.=<<___; + vadd.u64 @XMM[8], @XMM[15], @XMM[15] + vst1.64 {@XMM[15]}, [r0,:128]! + vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")` + veor @XMM[8], @XMM[8], @T[0] + vst1.64 {@XMM[8]}, [r0,:128] @ next round tweak + + vld1.8 {@XMM[6]-@XMM[7]}, [$inp]! + veor @XMM[5], @XMM[5], @XMM[13] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[6], @XMM[6], @XMM[14] + mov r5, $rounds @ pass rounds + veor @XMM[7], @XMM[7], @XMM[15] + mov r0, sp + + bl _bsaes_encrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[6], @XMM[11] + vld1.64 {@XMM[14]-@XMM[15]}, [r0,:128]! + veor @XMM[10], @XMM[3], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + veor @XMM[11], @XMM[7], @XMM[13] + veor @XMM[12], @XMM[2], @XMM[14] + vst1.8 {@XMM[10]-@XMM[11]}, [$out]! + veor @XMM[13], @XMM[5], @XMM[15] + vst1.8 {@XMM[12]-@XMM[13]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + + subs $len, #0x80 + bpl .Lxts_enc_loop + +.Lxts_enc_short: + adds $len, #0x70 + bmi .Lxts_enc_done + + vldmia $magic, {$twmask} @ load XTS magic + vshr.s64 @T[0], @XMM[8], #63 + mov r0, sp + vand @T[0], @T[0], $twmask +___ +for($i=9;$i<16;$i++) { +$code.=<<___; + vadd.u64 @XMM[$i], @XMM[$i-1], @XMM[$i-1] + vst1.64 {@XMM[$i-1]}, [r0,:128]! + vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")` + vshr.s64 @T[1], @XMM[$i], #63 + veor @XMM[$i], @XMM[$i], @T[0] + vand @T[1], @T[1], $twmask +___ + @T=reverse(@T); + +$code.=<<___ if ($i>=10); + vld1.8 {@XMM[$i-10]}, [$inp]! + subs $len, #0x10 + bmi .Lxts_enc_`$i-9` +___ +$code.=<<___ if ($i>=11); + veor @XMM[$i-11], @XMM[$i-11], @XMM[$i-3] +___ +} +$code.=<<___; + sub $len, #0x10 + vst1.64 {@XMM[15]}, [r0,:128] @ next round tweak + + vld1.8 {@XMM[6]}, [$inp]! + veor @XMM[5], @XMM[5], @XMM[13] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[6], @XMM[6], @XMM[14] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_encrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[6], @XMM[11] + vld1.64 {@XMM[14]}, [r0,:128]! + veor @XMM[10], @XMM[3], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + veor @XMM[11], @XMM[7], @XMM[13] + veor @XMM[12], @XMM[2], @XMM[14] + vst1.8 {@XMM[10]-@XMM[11]}, [$out]! + vst1.8 {@XMM[12]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_enc_done +.align 4 +.Lxts_enc_6: + vst1.64 {@XMM[14]}, [r0,:128] @ next round tweak + + veor @XMM[4], @XMM[4], @XMM[12] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[5], @XMM[5], @XMM[13] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_encrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[6], @XMM[11] + veor @XMM[10], @XMM[3], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + veor @XMM[11], @XMM[7], @XMM[13] + vst1.8 {@XMM[10]-@XMM[11]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_enc_done + +@ put this in range for both ARM and Thumb mode adr instructions +.align 5 +.Lxts_magic: + .quad 1, 0x87 + +.align 5 +.Lxts_enc_5: + vst1.64 {@XMM[13]}, [r0,:128] @ next round tweak + + veor @XMM[3], @XMM[3], @XMM[11] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[4], @XMM[4], @XMM[12] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_encrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[6], @XMM[11] + veor @XMM[10], @XMM[3], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + vst1.8 {@XMM[10]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_enc_done +.align 4 +.Lxts_enc_4: + vst1.64 {@XMM[12]}, [r0,:128] @ next round tweak + + veor @XMM[2], @XMM[2], @XMM[10] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[3], @XMM[3], @XMM[11] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_encrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[6], @XMM[11] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_enc_done +.align 4 +.Lxts_enc_3: + vst1.64 {@XMM[11]}, [r0,:128] @ next round tweak + + veor @XMM[1], @XMM[1], @XMM[9] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[2], @XMM[2], @XMM[10] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_encrypt8 + + vld1.64 {@XMM[8]-@XMM[9]}, [r0,:128]! + vld1.64 {@XMM[10]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[4], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + vst1.8 {@XMM[8]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_enc_done +.align 4 +.Lxts_enc_2: + vst1.64 {@XMM[10]}, [r0,:128] @ next round tweak + + veor @XMM[0], @XMM[0], @XMM[8] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[1], @XMM[1], @XMM[9] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_encrypt8 + + vld1.64 {@XMM[8]-@XMM[9]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + veor @XMM[1], @XMM[1], @XMM[ 9] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_enc_done +.align 4 +.Lxts_enc_1: + mov r0, sp + veor @XMM[0], @XMM[8] + mov r1, sp + vst1.8 {@XMM[0]}, [sp,:128] + mov r2, $key + mov r4, $fp @ preserve fp + + bl AES_encrypt + + vld1.8 {@XMM[0]}, [sp,:128] + veor @XMM[0], @XMM[0], @XMM[8] + vst1.8 {@XMM[0]}, [$out]! + mov $fp, r4 + + vmov @XMM[8], @XMM[9] @ next round tweak + +.Lxts_enc_done: +#ifndef XTS_CHAIN_TWEAK + adds $len, #0x10 + beq .Lxts_enc_ret + sub r6, $out, #0x10 + +.Lxts_enc_steal: + ldrb r0, [$inp], #1 + ldrb r1, [$out, #-0x10] + strb r0, [$out, #-0x10] + strb r1, [$out], #1 + + subs $len, #1 + bhi .Lxts_enc_steal + + vld1.8 {@XMM[0]}, [r6] + mov r0, sp + veor @XMM[0], @XMM[0], @XMM[8] + mov r1, sp + vst1.8 {@XMM[0]}, [sp,:128] + mov r2, $key + mov r4, $fp @ preserve fp + + bl AES_encrypt + + vld1.8 {@XMM[0]}, [sp,:128] + veor @XMM[0], @XMM[0], @XMM[8] + vst1.8 {@XMM[0]}, [r6] + mov $fp, r4 +#endif + +.Lxts_enc_ret: + bic r0, $fp, #0xf + vmov.i32 q0, #0 + vmov.i32 q1, #0 +#ifdef XTS_CHAIN_TWEAK + ldr r1, [$fp, #0x20+VFP_ABI_FRAME] @ chain tweak +#endif +.Lxts_enc_bzero: @ wipe key schedule [if any] + vstmia sp!, {q0-q1} + cmp sp, r0 + bne .Lxts_enc_bzero + + mov sp, $fp +#ifdef XTS_CHAIN_TWEAK + vst1.8 {@XMM[8]}, [r1] +#endif + VFP_ABI_POP + ldmia sp!, {r4-r10, pc} @ return + +.size bsaes_xts_encrypt,.-bsaes_xts_encrypt + +.globl bsaes_xts_decrypt +.hidden bsaes_xts_decrypt +.type bsaes_xts_decrypt,%function +.align 4 +bsaes_xts_decrypt: + mov ip, sp + stmdb sp!, {r4-r10, lr} @ 0x20 + VFP_ABI_PUSH + mov r6, sp @ future $fp + + mov $inp, r0 + mov $out, r1 + mov $len, r2 + mov $key, r3 + + sub r0, sp, #0x10 @ 0x10 + bic r0, #0xf @ align at 16 bytes + mov sp, r0 + +#ifdef XTS_CHAIN_TWEAK + ldr r0, [ip] @ pointer to input tweak +#else + @ generate initial tweak + ldr r0, [ip, #4] @ iv[] + mov r1, sp + ldr r2, [ip, #0] @ key2 + bl AES_encrypt + mov r0, sp @ pointer to initial tweak +#endif + + ldr $rounds, [$key, #240] @ get # of rounds + mov $fp, r6 +#ifndef BSAES_ASM_EXTENDED_KEY + @ allocate the key schedule on the stack + sub r12, sp, $rounds, lsl#7 @ 128 bytes per inner round key + @ add r12, #`128-32` @ size of bit-sliced key schedule + sub r12, #`32+16` @ place for tweak[9] + + @ populate the key schedule + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + mov sp, r12 + add r12, #0x90 @ pass key schedule + bl _bsaes_key_convert + add r4, sp, #0x90 + vldmia r4, {@XMM[6]} + vstmia r12, {@XMM[15]} @ save last round key + veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key + vstmia r4, {@XMM[7]} +#else + ldr r12, [$key, #244] + eors r12, #1 + beq 0f + + str r12, [$key, #244] + mov r4, $key @ pass key + mov r5, $rounds @ pass # of rounds + add r12, $key, #248 @ pass key schedule + bl _bsaes_key_convert + add r4, $key, #248 + vldmia r4, {@XMM[6]} + vstmia r12, {@XMM[15]} @ save last round key + veor @XMM[7], @XMM[7], @XMM[6] @ fix up round 0 key + vstmia r4, {@XMM[7]} + +.align 2 +0: sub sp, #0x90 @ place for tweak[9] +#endif + vld1.8 {@XMM[8]}, [r0] @ initial tweak + adr $magic, .Lxts_magic + +#ifndef XTS_CHAIN_TWEAK + tst $len, #0xf @ if not multiple of 16 + it ne @ Thumb2 thing, sanity check in ARM + subne $len, #0x10 @ subtract another 16 bytes +#endif + subs $len, #0x80 + + blo .Lxts_dec_short + b .Lxts_dec_loop + +.align 4 +.Lxts_dec_loop: + vldmia $magic, {$twmask} @ load XTS magic + vshr.s64 @T[0], @XMM[8], #63 + mov r0, sp + vand @T[0], @T[0], $twmask +___ +for($i=9;$i<16;$i++) { +$code.=<<___; + vadd.u64 @XMM[$i], @XMM[$i-1], @XMM[$i-1] + vst1.64 {@XMM[$i-1]}, [r0,:128]! + vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")` + vshr.s64 @T[1], @XMM[$i], #63 + veor @XMM[$i], @XMM[$i], @T[0] + vand @T[1], @T[1], $twmask +___ + @T=reverse(@T); + +$code.=<<___ if ($i>=10); + vld1.8 {@XMM[$i-10]}, [$inp]! +___ +$code.=<<___ if ($i>=11); + veor @XMM[$i-11], @XMM[$i-11], @XMM[$i-3] +___ +} +$code.=<<___; + vadd.u64 @XMM[8], @XMM[15], @XMM[15] + vst1.64 {@XMM[15]}, [r0,:128]! + vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")` + veor @XMM[8], @XMM[8], @T[0] + vst1.64 {@XMM[8]}, [r0,:128] @ next round tweak + + vld1.8 {@XMM[6]-@XMM[7]}, [$inp]! + veor @XMM[5], @XMM[5], @XMM[13] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[6], @XMM[6], @XMM[14] + mov r5, $rounds @ pass rounds + veor @XMM[7], @XMM[7], @XMM[15] + mov r0, sp + + bl _bsaes_decrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[6], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[4], @XMM[11] + vld1.64 {@XMM[14]-@XMM[15]}, [r0,:128]! + veor @XMM[10], @XMM[2], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + veor @XMM[11], @XMM[7], @XMM[13] + veor @XMM[12], @XMM[3], @XMM[14] + vst1.8 {@XMM[10]-@XMM[11]}, [$out]! + veor @XMM[13], @XMM[5], @XMM[15] + vst1.8 {@XMM[12]-@XMM[13]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + + subs $len, #0x80 + bpl .Lxts_dec_loop + +.Lxts_dec_short: + adds $len, #0x70 + bmi .Lxts_dec_done + + vldmia $magic, {$twmask} @ load XTS magic + vshr.s64 @T[0], @XMM[8], #63 + mov r0, sp + vand @T[0], @T[0], $twmask +___ +for($i=9;$i<16;$i++) { +$code.=<<___; + vadd.u64 @XMM[$i], @XMM[$i-1], @XMM[$i-1] + vst1.64 {@XMM[$i-1]}, [r0,:128]! + vswp `&Dhi("@T[0]")`,`&Dlo("@T[0]")` + vshr.s64 @T[1], @XMM[$i], #63 + veor @XMM[$i], @XMM[$i], @T[0] + vand @T[1], @T[1], $twmask +___ + @T=reverse(@T); + +$code.=<<___ if ($i>=10); + vld1.8 {@XMM[$i-10]}, [$inp]! + subs $len, #0x10 + bmi .Lxts_dec_`$i-9` +___ +$code.=<<___ if ($i>=11); + veor @XMM[$i-11], @XMM[$i-11], @XMM[$i-3] +___ +} +$code.=<<___; + sub $len, #0x10 + vst1.64 {@XMM[15]}, [r0,:128] @ next round tweak + + vld1.8 {@XMM[6]}, [$inp]! + veor @XMM[5], @XMM[5], @XMM[13] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[6], @XMM[6], @XMM[14] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_decrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[6], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[4], @XMM[11] + vld1.64 {@XMM[14]}, [r0,:128]! + veor @XMM[10], @XMM[2], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + veor @XMM[11], @XMM[7], @XMM[13] + veor @XMM[12], @XMM[3], @XMM[14] + vst1.8 {@XMM[10]-@XMM[11]}, [$out]! + vst1.8 {@XMM[12]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_dec_done +.align 4 +.Lxts_dec_6: + vst1.64 {@XMM[14]}, [r0,:128] @ next round tweak + + veor @XMM[4], @XMM[4], @XMM[12] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[5], @XMM[5], @XMM[13] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_decrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]-@XMM[13]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[6], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[4], @XMM[11] + veor @XMM[10], @XMM[2], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + veor @XMM[11], @XMM[7], @XMM[13] + vst1.8 {@XMM[10]-@XMM[11]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_dec_done +.align 4 +.Lxts_dec_5: + vst1.64 {@XMM[13]}, [r0,:128] @ next round tweak + + veor @XMM[3], @XMM[3], @XMM[11] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[4], @XMM[4], @XMM[12] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_decrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + vld1.64 {@XMM[12]}, [r0,:128]! + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[6], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[4], @XMM[11] + veor @XMM[10], @XMM[2], @XMM[12] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + vst1.8 {@XMM[10]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_dec_done +.align 4 +.Lxts_dec_4: + vst1.64 {@XMM[12]}, [r0,:128] @ next round tweak + + veor @XMM[2], @XMM[2], @XMM[10] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[3], @XMM[3], @XMM[11] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_decrypt8 + + vld1.64 {@XMM[ 8]-@XMM[ 9]}, [r0,:128]! + vld1.64 {@XMM[10]-@XMM[11]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[6], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + veor @XMM[9], @XMM[4], @XMM[11] + vst1.8 {@XMM[8]-@XMM[9]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_dec_done +.align 4 +.Lxts_dec_3: + vst1.64 {@XMM[11]}, [r0,:128] @ next round tweak + + veor @XMM[1], @XMM[1], @XMM[9] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[2], @XMM[2], @XMM[10] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_decrypt8 + + vld1.64 {@XMM[8]-@XMM[9]}, [r0,:128]! + vld1.64 {@XMM[10]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + veor @XMM[1], @XMM[1], @XMM[ 9] + veor @XMM[8], @XMM[6], @XMM[10] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + vst1.8 {@XMM[8]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_dec_done +.align 4 +.Lxts_dec_2: + vst1.64 {@XMM[10]}, [r0,:128] @ next round tweak + + veor @XMM[0], @XMM[0], @XMM[8] +#ifndef BSAES_ASM_EXTENDED_KEY + add r4, sp, #0x90 @ pass key schedule +#else + add r4, $key, #248 @ pass key schedule +#endif + veor @XMM[1], @XMM[1], @XMM[9] + mov r5, $rounds @ pass rounds + mov r0, sp + + bl _bsaes_decrypt8 + + vld1.64 {@XMM[8]-@XMM[9]}, [r0,:128]! + veor @XMM[0], @XMM[0], @XMM[ 8] + veor @XMM[1], @XMM[1], @XMM[ 9] + vst1.8 {@XMM[0]-@XMM[1]}, [$out]! + + vld1.64 {@XMM[8]}, [r0,:128] @ next round tweak + b .Lxts_dec_done +.align 4 +.Lxts_dec_1: + mov r0, sp + veor @XMM[0], @XMM[8] + mov r1, sp + vst1.8 {@XMM[0]}, [sp,:128] + mov r2, $key + mov r4, $fp @ preserve fp + mov r5, $magic @ preserve magic + + bl AES_decrypt + + vld1.8 {@XMM[0]}, [sp,:128] + veor @XMM[0], @XMM[0], @XMM[8] + vst1.8 {@XMM[0]}, [$out]! + mov $fp, r4 + mov $magic, r5 + + vmov @XMM[8], @XMM[9] @ next round tweak + +.Lxts_dec_done: +#ifndef XTS_CHAIN_TWEAK + adds $len, #0x10 + beq .Lxts_dec_ret + + @ calculate one round of extra tweak for the stolen ciphertext + vldmia $magic, {$twmask} + vshr.s64 @XMM[6], @XMM[8], #63 + vand @XMM[6], @XMM[6], $twmask + vadd.u64 @XMM[9], @XMM[8], @XMM[8] + vswp `&Dhi("@XMM[6]")`,`&Dlo("@XMM[6]")` + veor @XMM[9], @XMM[9], @XMM[6] + + @ perform the final decryption with the last tweak value + vld1.8 {@XMM[0]}, [$inp]! + mov r0, sp + veor @XMM[0], @XMM[0], @XMM[9] + mov r1, sp + vst1.8 {@XMM[0]}, [sp,:128] + mov r2, $key + mov r4, $fp @ preserve fp + + bl AES_decrypt + + vld1.8 {@XMM[0]}, [sp,:128] + veor @XMM[0], @XMM[0], @XMM[9] + vst1.8 {@XMM[0]}, [$out] + + mov r6, $out +.Lxts_dec_steal: + ldrb r1, [$out] + ldrb r0, [$inp], #1 + strb r1, [$out, #0x10] + strb r0, [$out], #1 + + subs $len, #1 + bhi .Lxts_dec_steal + + vld1.8 {@XMM[0]}, [r6] + mov r0, sp + veor @XMM[0], @XMM[8] + mov r1, sp + vst1.8 {@XMM[0]}, [sp,:128] + mov r2, $key + + bl AES_decrypt + + vld1.8 {@XMM[0]}, [sp,:128] + veor @XMM[0], @XMM[0], @XMM[8] + vst1.8 {@XMM[0]}, [r6] + mov $fp, r4 +#endif + +.Lxts_dec_ret: + bic r0, $fp, #0xf + vmov.i32 q0, #0 + vmov.i32 q1, #0 +#ifdef XTS_CHAIN_TWEAK + ldr r1, [$fp, #0x20+VFP_ABI_FRAME] @ chain tweak +#endif +.Lxts_dec_bzero: @ wipe key schedule [if any] + vstmia sp!, {q0-q1} + cmp sp, r0 + bne .Lxts_dec_bzero + + mov sp, $fp +#ifdef XTS_CHAIN_TWEAK + vst1.8 {@XMM[8]}, [r1] +#endif + VFP_ABI_POP + ldmia sp!, {r4-r10, pc} @ return + +.size bsaes_xts_decrypt,.-bsaes_xts_decrypt +___ +} +$code.=<<___; +#endif +#endif +___ + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +open SELF,$0; +while() { + next if (/^#!/); + last if (!s/^#/@/ and !/^$/); + print; +} +close SELF; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/bsaes-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/bsaes-x86_64.pl new file mode 100644 index 00000000..3f7d33c4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/bsaes-x86_64.pl @@ -0,0 +1,3102 @@ +#!/usr/bin/env perl + +################################################################### +### AES-128 [originally in CTR mode] ### +### bitsliced implementation for Intel Core 2 processors ### +### requires support of SSE extensions up to SSSE3 ### +### Author: Emilia Käsper and Peter Schwabe ### +### Date: 2009-03-19 ### +### Public domain ### +### ### +### See http://homes.esat.kuleuven.be/~ekasper/#software for ### +### further information. ### +################################################################### +# +# September 2011. +# +# Started as transliteration to "perlasm" the original code has +# undergone following changes: +# +# - code was made position-independent; +# - rounds were folded into a loop resulting in >5x size reduction +# from 12.5KB to 2.2KB; +# - above was possibile thanks to mixcolumns() modification that +# allowed to feed its output back to aesenc[last], this was +# achieved at cost of two additional inter-registers moves; +# - some instruction reordering and interleaving; +# - this module doesn't implement key setup subroutine, instead it +# relies on conversion of "conventional" key schedule as returned +# by AES_set_encrypt_key (see discussion below); +# - first and last round keys are treated differently, which allowed +# to skip one shiftrows(), reduce bit-sliced key schedule and +# speed-up conversion by 22%; +# - support for 192- and 256-bit keys was added; +# +# Resulting performance in CPU cycles spent to encrypt one byte out +# of 4096-byte buffer with 128-bit key is: +# +# Emilia's this(*) difference +# +# Core 2 9.30 8.69 +7% +# Nehalem(**) 7.63 6.88 +11% +# Atom 17.1 16.4 +4% +# Silvermont - 12.9 +# +# (*) Comparison is not completely fair, because "this" is ECB, +# i.e. no extra processing such as counter values calculation +# and xor-ing input as in Emilia's CTR implementation is +# performed. However, the CTR calculations stand for not more +# than 1% of total time, so comparison is *rather* fair. +# +# (**) Results were collected on Westmere, which is considered to +# be equivalent to Nehalem for this code. +# +# As for key schedule conversion subroutine. Interface to OpenSSL +# relies on per-invocation on-the-fly conversion. This naturally +# has impact on performance, especially for short inputs. Conversion +# time in CPU cycles and its ratio to CPU cycles spent in 8x block +# function is: +# +# conversion conversion/8x block +# Core 2 240 0.22 +# Nehalem 180 0.20 +# Atom 430 0.20 +# +# The ratio values mean that 128-byte blocks will be processed +# 16-18% slower, 256-byte blocks - 9-10%, 384-byte blocks - 6-7%, +# etc. Then keep in mind that input sizes not divisible by 128 are +# *effectively* slower, especially shortest ones, e.g. consecutive +# 144-byte blocks are processed 44% slower than one would expect, +# 272 - 29%, 400 - 22%, etc. Yet, despite all these "shortcomings" +# it's still faster than ["hyper-threading-safe" code path in] +# aes-x86_64.pl on all lengths above 64 bytes... +# +# October 2011. +# +# Add decryption procedure. Performance in CPU cycles spent to decrypt +# one byte out of 4096-byte buffer with 128-bit key is: +# +# Core 2 9.98 +# Nehalem 7.80 +# Atom 17.9 +# Silvermont 14.0 +# +# November 2011. +# +# Add bsaes_xts_[en|de]crypt. Less-than-80-bytes-block performance is +# suboptimal, but XTS is meant to be used with larger blocks... +# +# + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +my ($inp,$out,$len,$key,$ivp)=("%rdi","%rsi","%rdx","%rcx"); +my @XMM=map("%xmm$_",(15,0..14)); # best on Atom, +10% over (0..15) +my $ecb=0; # suppress unreferenced ECB subroutines, spare some space... + +{ +my ($key,$rounds,$const)=("%rax","%r10d","%r11"); + +sub Sbox { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b0, b1, b4, b6, b3, b7, b2, b5] < msb +my @b=@_[0..7]; +my @t=@_[8..11]; +my @s=@_[12..15]; + &InBasisChange (@b); + &Inv_GF256 (@b[6,5,0,3,7,1,4,2],@t,@s); + &OutBasisChange (@b[7,1,4,2,6,5,0,3]); +} + +sub InBasisChange { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b6, b5, b0, b3, b7, b1, b4, b2] < msb +my @b=@_[0..7]; +$code.=<<___; + pxor @b[6], @b[5] + pxor @b[1], @b[2] + pxor @b[0], @b[3] + pxor @b[2], @b[6] + pxor @b[0], @b[5] + + pxor @b[3], @b[6] + pxor @b[7], @b[3] + pxor @b[5], @b[7] + pxor @b[4], @b[3] + pxor @b[5], @b[4] + pxor @b[1], @b[3] + + pxor @b[7], @b[2] + pxor @b[5], @b[1] +___ +} + +sub OutBasisChange { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b6, b1, b2, b4, b7, b0, b3, b5] < msb +my @b=@_[0..7]; +$code.=<<___; + pxor @b[6], @b[0] + pxor @b[4], @b[1] + pxor @b[0], @b[2] + pxor @b[6], @b[4] + pxor @b[1], @b[6] + + pxor @b[5], @b[1] + pxor @b[3], @b[5] + pxor @b[7], @b[3] + pxor @b[5], @b[7] + pxor @b[5], @b[2] + + pxor @b[7], @b[4] +___ +} + +sub InvSbox { +# input in lsb > [b0, b1, b2, b3, b4, b5, b6, b7] < msb +# output in lsb > [b0, b1, b6, b4, b2, b7, b3, b5] < msb +my @b=@_[0..7]; +my @t=@_[8..11]; +my @s=@_[12..15]; + &InvInBasisChange (@b); + &Inv_GF256 (@b[5,1,2,6,3,7,0,4],@t,@s); + &InvOutBasisChange (@b[3,7,0,4,5,1,2,6]); +} + +sub InvInBasisChange { # OutBasisChange in reverse +my @b=@_[5,1,2,6,3,7,0,4]; +$code.=<<___ + pxor @b[7], @b[4] + + pxor @b[5], @b[7] + pxor @b[5], @b[2] + pxor @b[7], @b[3] + pxor @b[3], @b[5] + pxor @b[5], @b[1] + + pxor @b[1], @b[6] + pxor @b[0], @b[2] + pxor @b[6], @b[4] + pxor @b[6], @b[0] + pxor @b[4], @b[1] +___ +} + +sub InvOutBasisChange { # InBasisChange in reverse +my @b=@_[2,5,7,3,6,1,0,4]; +$code.=<<___; + pxor @b[5], @b[1] + pxor @b[7], @b[2] + + pxor @b[1], @b[3] + pxor @b[5], @b[4] + pxor @b[5], @b[7] + pxor @b[4], @b[3] + pxor @b[0], @b[5] + pxor @b[7], @b[3] + pxor @b[2], @b[6] + pxor @b[1], @b[2] + pxor @b[3], @b[6] + + pxor @b[0], @b[3] + pxor @b[6], @b[5] +___ +} + +sub Mul_GF4 { +#;************************************************************* +#;* Mul_GF4: Input x0-x1,y0-y1 Output x0-x1 Temp t0 (8) * +#;************************************************************* +my ($x0,$x1,$y0,$y1,$t0)=@_; +$code.=<<___; + movdqa $y0, $t0 + pxor $y1, $t0 + pand $x0, $t0 + pxor $x1, $x0 + pand $y0, $x1 + pand $y1, $x0 + pxor $x1, $x0 + pxor $t0, $x1 +___ +} + +sub Mul_GF4_N { # not used, see next subroutine +# multiply and scale by N +my ($x0,$x1,$y0,$y1,$t0)=@_; +$code.=<<___; + movdqa $y0, $t0 + pxor $y1, $t0 + pand $x0, $t0 + pxor $x1, $x0 + pand $y0, $x1 + pand $y1, $x0 + pxor $x0, $x1 + pxor $t0, $x0 +___ +} + +sub Mul_GF4_N_GF4 { +# interleaved Mul_GF4_N and Mul_GF4 +my ($x0,$x1,$y0,$y1,$t0, + $x2,$x3,$y2,$y3,$t1)=@_; +$code.=<<___; + movdqa $y0, $t0 + movdqa $y2, $t1 + pxor $y1, $t0 + pxor $y3, $t1 + pand $x0, $t0 + pand $x2, $t1 + pxor $x1, $x0 + pxor $x3, $x2 + pand $y0, $x1 + pand $y2, $x3 + pand $y1, $x0 + pand $y3, $x2 + pxor $x0, $x1 + pxor $x3, $x2 + pxor $t0, $x0 + pxor $t1, $x3 +___ +} +sub Mul_GF16_2 { +my @x=@_[0..7]; +my @y=@_[8..11]; +my @t=@_[12..15]; +$code.=<<___; + movdqa @x[0], @t[0] + movdqa @x[1], @t[1] +___ + &Mul_GF4 (@x[0], @x[1], @y[0], @y[1], @t[2]); +$code.=<<___; + pxor @x[2], @t[0] + pxor @x[3], @t[1] + pxor @y[2], @y[0] + pxor @y[3], @y[1] +___ + Mul_GF4_N_GF4 (@t[0], @t[1], @y[0], @y[1], @t[3], + @x[2], @x[3], @y[2], @y[3], @t[2]); +$code.=<<___; + pxor @t[0], @x[0] + pxor @t[0], @x[2] + pxor @t[1], @x[1] + pxor @t[1], @x[3] + + movdqa @x[4], @t[0] + movdqa @x[5], @t[1] + pxor @x[6], @t[0] + pxor @x[7], @t[1] +___ + &Mul_GF4_N_GF4 (@t[0], @t[1], @y[0], @y[1], @t[3], + @x[6], @x[7], @y[2], @y[3], @t[2]); +$code.=<<___; + pxor @y[2], @y[0] + pxor @y[3], @y[1] +___ + &Mul_GF4 (@x[4], @x[5], @y[0], @y[1], @t[3]); +$code.=<<___; + pxor @t[0], @x[4] + pxor @t[0], @x[6] + pxor @t[1], @x[5] + pxor @t[1], @x[7] +___ +} +sub Inv_GF256 { +#;******************************************************************** +#;* Inv_GF256: Input x0-x7 Output x0-x7 Temp t0-t3,s0-s3 (144) * +#;******************************************************************** +my @x=@_[0..7]; +my @t=@_[8..11]; +my @s=@_[12..15]; +# direct optimizations from hardware +$code.=<<___; + movdqa @x[4], @t[3] + movdqa @x[5], @t[2] + movdqa @x[1], @t[1] + movdqa @x[7], @s[1] + movdqa @x[0], @s[0] + + pxor @x[6], @t[3] + pxor @x[7], @t[2] + pxor @x[3], @t[1] + movdqa @t[3], @s[2] + pxor @x[6], @s[1] + movdqa @t[2], @t[0] + pxor @x[2], @s[0] + movdqa @t[3], @s[3] + + por @t[1], @t[2] + por @s[0], @t[3] + pxor @t[0], @s[3] + pand @s[0], @s[2] + pxor @t[1], @s[0] + pand @t[1], @t[0] + pand @s[0], @s[3] + movdqa @x[3], @s[0] + pxor @x[2], @s[0] + pand @s[0], @s[1] + pxor @s[1], @t[3] + pxor @s[1], @t[2] + movdqa @x[4], @s[1] + movdqa @x[1], @s[0] + pxor @x[5], @s[1] + pxor @x[0], @s[0] + movdqa @s[1], @t[1] + pand @s[0], @s[1] + por @s[0], @t[1] + pxor @s[1], @t[0] + pxor @s[3], @t[3] + pxor @s[2], @t[2] + pxor @s[3], @t[1] + movdqa @x[7], @s[0] + pxor @s[2], @t[0] + movdqa @x[6], @s[1] + pxor @s[2], @t[1] + movdqa @x[5], @s[2] + pand @x[3], @s[0] + movdqa @x[4], @s[3] + pand @x[2], @s[1] + pand @x[1], @s[2] + por @x[0], @s[3] + pxor @s[0], @t[3] + pxor @s[1], @t[2] + pxor @s[2], @t[1] + pxor @s[3], @t[0] + + #Inv_GF16 \t0, \t1, \t2, \t3, \s0, \s1, \s2, \s3 + + # new smaller inversion + + movdqa @t[3], @s[0] + pand @t[1], @t[3] + pxor @t[2], @s[0] + + movdqa @t[0], @s[2] + movdqa @s[0], @s[3] + pxor @t[3], @s[2] + pand @s[2], @s[3] + + movdqa @t[1], @s[1] + pxor @t[2], @s[3] + pxor @t[0], @s[1] + + pxor @t[2], @t[3] + + pand @t[3], @s[1] + + movdqa @s[2], @t[2] + pxor @t[0], @s[1] + + pxor @s[1], @t[2] + pxor @s[1], @t[1] + + pand @t[0], @t[2] + + pxor @t[2], @s[2] + pxor @t[2], @t[1] + + pand @s[3], @s[2] + + pxor @s[0], @s[2] +___ +# output in s3, s2, s1, t1 + +# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \t2, \t3, \t0, \t1, \s0, \s1, \s2, \s3 + +# Mul_GF16_2 \x0, \x1, \x2, \x3, \x4, \x5, \x6, \x7, \s3, \s2, \s1, \t1, \s0, \t0, \t2, \t3 + &Mul_GF16_2(@x,@s[3,2,1],@t[1],@s[0],@t[0,2,3]); + +### output msb > [x3,x2,x1,x0,x7,x6,x5,x4] < lsb +} + +# AES linear components + +sub ShiftRows { +my @x=@_[0..7]; +my $mask=pop; +$code.=<<___; + pxor 0x00($key),@x[0] + pxor 0x10($key),@x[1] + pxor 0x20($key),@x[2] + pxor 0x30($key),@x[3] + pshufb $mask,@x[0] + pshufb $mask,@x[1] + pxor 0x40($key),@x[4] + pxor 0x50($key),@x[5] + pshufb $mask,@x[2] + pshufb $mask,@x[3] + pxor 0x60($key),@x[6] + pxor 0x70($key),@x[7] + pshufb $mask,@x[4] + pshufb $mask,@x[5] + pshufb $mask,@x[6] + pshufb $mask,@x[7] + lea 0x80($key),$key +___ +} + +sub MixColumns { +# modified to emit output in order suitable for feeding back to aesenc[last] +my @x=@_[0..7]; +my @t=@_[8..15]; +my $inv=@_[16]; # optional +$code.=<<___; + pshufd \$0x93, @x[0], @t[0] # x0 <<< 32 + pshufd \$0x93, @x[1], @t[1] + pxor @t[0], @x[0] # x0 ^ (x0 <<< 32) + pshufd \$0x93, @x[2], @t[2] + pxor @t[1], @x[1] + pshufd \$0x93, @x[3], @t[3] + pxor @t[2], @x[2] + pshufd \$0x93, @x[4], @t[4] + pxor @t[3], @x[3] + pshufd \$0x93, @x[5], @t[5] + pxor @t[4], @x[4] + pshufd \$0x93, @x[6], @t[6] + pxor @t[5], @x[5] + pshufd \$0x93, @x[7], @t[7] + pxor @t[6], @x[6] + pxor @t[7], @x[7] + + pxor @x[0], @t[1] + pxor @x[7], @t[0] + pxor @x[7], @t[1] + pshufd \$0x4E, @x[0], @x[0] # (x0 ^ (x0 <<< 32)) <<< 64) + pxor @x[1], @t[2] + pshufd \$0x4E, @x[1], @x[1] + pxor @x[4], @t[5] + pxor @t[0], @x[0] + pxor @x[5], @t[6] + pxor @t[1], @x[1] + pxor @x[3], @t[4] + pshufd \$0x4E, @x[4], @t[0] + pxor @x[6], @t[7] + pshufd \$0x4E, @x[5], @t[1] + pxor @x[2], @t[3] + pshufd \$0x4E, @x[3], @x[4] + pxor @x[7], @t[3] + pshufd \$0x4E, @x[7], @x[5] + pxor @x[7], @t[4] + pshufd \$0x4E, @x[6], @x[3] + pxor @t[4], @t[0] + pshufd \$0x4E, @x[2], @x[6] + pxor @t[5], @t[1] +___ +$code.=<<___ if (!$inv); + pxor @t[3], @x[4] + pxor @t[7], @x[5] + pxor @t[6], @x[3] + movdqa @t[0], @x[2] + pxor @t[2], @x[6] + movdqa @t[1], @x[7] +___ +$code.=<<___ if ($inv); + pxor @x[4], @t[3] + pxor @t[7], @x[5] + pxor @x[3], @t[6] + movdqa @t[0], @x[3] + pxor @t[2], @x[6] + movdqa @t[6], @x[2] + movdqa @t[1], @x[7] + movdqa @x[6], @x[4] + movdqa @t[3], @x[6] +___ +} + +sub InvMixColumns_orig { +my @x=@_[0..7]; +my @t=@_[8..15]; + +$code.=<<___; + # multiplication by 0x0e + pshufd \$0x93, @x[7], @t[7] + movdqa @x[2], @t[2] + pxor @x[5], @x[7] # 7 5 + pxor @x[5], @x[2] # 2 5 + pshufd \$0x93, @x[0], @t[0] + movdqa @x[5], @t[5] + pxor @x[0], @x[5] # 5 0 [1] + pxor @x[1], @x[0] # 0 1 + pshufd \$0x93, @x[1], @t[1] + pxor @x[2], @x[1] # 1 25 + pxor @x[6], @x[0] # 01 6 [2] + pxor @x[3], @x[1] # 125 3 [4] + pshufd \$0x93, @x[3], @t[3] + pxor @x[0], @x[2] # 25 016 [3] + pxor @x[7], @x[3] # 3 75 + pxor @x[6], @x[7] # 75 6 [0] + pshufd \$0x93, @x[6], @t[6] + movdqa @x[4], @t[4] + pxor @x[4], @x[6] # 6 4 + pxor @x[3], @x[4] # 4 375 [6] + pxor @x[7], @x[3] # 375 756=36 + pxor @t[5], @x[6] # 64 5 [7] + pxor @t[2], @x[3] # 36 2 + pxor @t[4], @x[3] # 362 4 [5] + pshufd \$0x93, @t[5], @t[5] +___ + my @y = @x[7,5,0,2,1,3,4,6]; +$code.=<<___; + # multiplication by 0x0b + pxor @y[0], @y[1] + pxor @t[0], @y[0] + pxor @t[1], @y[1] + pshufd \$0x93, @t[2], @t[2] + pxor @t[5], @y[0] + pxor @t[6], @y[1] + pxor @t[7], @y[0] + pshufd \$0x93, @t[4], @t[4] + pxor @t[6], @t[7] # clobber t[7] + pxor @y[0], @y[1] + + pxor @t[0], @y[3] + pshufd \$0x93, @t[0], @t[0] + pxor @t[1], @y[2] + pxor @t[1], @y[4] + pxor @t[2], @y[2] + pshufd \$0x93, @t[1], @t[1] + pxor @t[2], @y[3] + pxor @t[2], @y[5] + pxor @t[7], @y[2] + pshufd \$0x93, @t[2], @t[2] + pxor @t[3], @y[3] + pxor @t[3], @y[6] + pxor @t[3], @y[4] + pshufd \$0x93, @t[3], @t[3] + pxor @t[4], @y[7] + pxor @t[4], @y[5] + pxor @t[7], @y[7] + pxor @t[5], @y[3] + pxor @t[4], @y[4] + pxor @t[5], @t[7] # clobber t[7] even more + + pxor @t[7], @y[5] + pshufd \$0x93, @t[4], @t[4] + pxor @t[7], @y[6] + pxor @t[7], @y[4] + + pxor @t[5], @t[7] + pshufd \$0x93, @t[5], @t[5] + pxor @t[6], @t[7] # restore t[7] + + # multiplication by 0x0d + pxor @y[7], @y[4] + pxor @t[4], @y[7] + pshufd \$0x93, @t[6], @t[6] + pxor @t[0], @y[2] + pxor @t[5], @y[7] + pxor @t[2], @y[2] + pshufd \$0x93, @t[7], @t[7] + + pxor @y[1], @y[3] + pxor @t[1], @y[1] + pxor @t[0], @y[0] + pxor @t[0], @y[3] + pxor @t[5], @y[1] + pxor @t[5], @y[0] + pxor @t[7], @y[1] + pshufd \$0x93, @t[0], @t[0] + pxor @t[6], @y[0] + pxor @y[1], @y[3] + pxor @t[1], @y[4] + pshufd \$0x93, @t[1], @t[1] + + pxor @t[7], @y[7] + pxor @t[2], @y[4] + pxor @t[2], @y[5] + pshufd \$0x93, @t[2], @t[2] + pxor @t[6], @y[2] + pxor @t[3], @t[6] # clobber t[6] + pxor @y[7], @y[4] + pxor @t[6], @y[3] + + pxor @t[6], @y[6] + pxor @t[5], @y[5] + pxor @t[4], @y[6] + pshufd \$0x93, @t[4], @t[4] + pxor @t[6], @y[5] + pxor @t[7], @y[6] + pxor @t[3], @t[6] # restore t[6] + + pshufd \$0x93, @t[5], @t[5] + pshufd \$0x93, @t[6], @t[6] + pshufd \$0x93, @t[7], @t[7] + pshufd \$0x93, @t[3], @t[3] + + # multiplication by 0x09 + pxor @y[1], @y[4] + pxor @y[1], @t[1] # t[1]=y[1] + pxor @t[5], @t[0] # clobber t[0] + pxor @t[5], @t[1] + pxor @t[0], @y[3] + pxor @y[0], @t[0] # t[0]=y[0] + pxor @t[6], @t[1] + pxor @t[7], @t[6] # clobber t[6] + pxor @t[1], @y[4] + pxor @t[4], @y[7] + pxor @y[4], @t[4] # t[4]=y[4] + pxor @t[3], @y[6] + pxor @y[3], @t[3] # t[3]=y[3] + pxor @t[2], @y[5] + pxor @y[2], @t[2] # t[2]=y[2] + pxor @t[7], @t[3] + pxor @y[5], @t[5] # t[5]=y[5] + pxor @t[6], @t[2] + pxor @t[6], @t[5] + pxor @y[6], @t[6] # t[6]=y[6] + pxor @y[7], @t[7] # t[7]=y[7] + + movdqa @t[0],@XMM[0] + movdqa @t[1],@XMM[1] + movdqa @t[2],@XMM[2] + movdqa @t[3],@XMM[3] + movdqa @t[4],@XMM[4] + movdqa @t[5],@XMM[5] + movdqa @t[6],@XMM[6] + movdqa @t[7],@XMM[7] +___ +} + +sub InvMixColumns { +my @x=@_[0..7]; +my @t=@_[8..15]; + +# Thanks to Jussi Kivilinna for providing pointer to +# +# | 0e 0b 0d 09 | | 02 03 01 01 | | 05 00 04 00 | +# | 09 0e 0b 0d | = | 01 02 03 01 | x | 00 05 00 04 | +# | 0d 09 0e 0b | | 01 01 02 03 | | 04 00 05 00 | +# | 0b 0d 09 0e | | 03 01 01 02 | | 00 04 00 05 | + +$code.=<<___; + # multiplication by 0x05-0x00-0x04-0x00 + pshufd \$0x4E, @x[0], @t[0] + pshufd \$0x4E, @x[6], @t[6] + pxor @x[0], @t[0] + pshufd \$0x4E, @x[7], @t[7] + pxor @x[6], @t[6] + pshufd \$0x4E, @x[1], @t[1] + pxor @x[7], @t[7] + pshufd \$0x4E, @x[2], @t[2] + pxor @x[1], @t[1] + pshufd \$0x4E, @x[3], @t[3] + pxor @x[2], @t[2] + pxor @t[6], @x[0] + pxor @t[6], @x[1] + pshufd \$0x4E, @x[4], @t[4] + pxor @x[3], @t[3] + pxor @t[0], @x[2] + pxor @t[1], @x[3] + pshufd \$0x4E, @x[5], @t[5] + pxor @x[4], @t[4] + pxor @t[7], @x[1] + pxor @t[2], @x[4] + pxor @x[5], @t[5] + + pxor @t[7], @x[2] + pxor @t[6], @x[3] + pxor @t[6], @x[4] + pxor @t[3], @x[5] + pxor @t[4], @x[6] + pxor @t[7], @x[4] + pxor @t[7], @x[5] + pxor @t[5], @x[7] +___ + &MixColumns (@x,@t,1); # flipped 2<->3 and 4<->6 +} + +sub aesenc { # not used +my @b=@_[0..7]; +my @t=@_[8..15]; +$code.=<<___; + movdqa 0x30($const),@t[0] # .LSR +___ + &ShiftRows (@b,@t[0]); + &Sbox (@b,@t); + &MixColumns (@b[0,1,4,6,3,7,2,5],@t); +} + +sub aesenclast { # not used +my @b=@_[0..7]; +my @t=@_[8..15]; +$code.=<<___; + movdqa 0x40($const),@t[0] # .LSRM0 +___ + &ShiftRows (@b,@t[0]); + &Sbox (@b,@t); +$code.=<<___ + pxor 0x00($key),@b[0] + pxor 0x10($key),@b[1] + pxor 0x20($key),@b[4] + pxor 0x30($key),@b[6] + pxor 0x40($key),@b[3] + pxor 0x50($key),@b[7] + pxor 0x60($key),@b[2] + pxor 0x70($key),@b[5] +___ +} + +sub swapmove { +my ($a,$b,$n,$mask,$t)=@_; +$code.=<<___; + movdqa $b,$t + psrlq \$$n,$b + pxor $a,$b + pand $mask,$b + pxor $b,$a + psllq \$$n,$b + pxor $t,$b +___ +} +sub swapmove2x { +my ($a0,$b0,$a1,$b1,$n,$mask,$t0,$t1)=@_; +$code.=<<___; + movdqa $b0,$t0 + psrlq \$$n,$b0 + movdqa $b1,$t1 + psrlq \$$n,$b1 + pxor $a0,$b0 + pxor $a1,$b1 + pand $mask,$b0 + pand $mask,$b1 + pxor $b0,$a0 + psllq \$$n,$b0 + pxor $b1,$a1 + psllq \$$n,$b1 + pxor $t0,$b0 + pxor $t1,$b1 +___ +} + +sub bitslice { +my @x=reverse(@_[0..7]); +my ($t0,$t1,$t2,$t3)=@_[8..11]; +$code.=<<___; + movdqa 0x00($const),$t0 # .LBS0 + movdqa 0x10($const),$t1 # .LBS1 +___ + &swapmove2x(@x[0,1,2,3],1,$t0,$t2,$t3); + &swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3); +$code.=<<___; + movdqa 0x20($const),$t0 # .LBS2 +___ + &swapmove2x(@x[0,2,1,3],2,$t1,$t2,$t3); + &swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3); + + &swapmove2x(@x[0,4,1,5],4,$t0,$t2,$t3); + &swapmove2x(@x[2,6,3,7],4,$t0,$t2,$t3); +} + +$code.=<<___; +.text + +.extern asm_AES_encrypt +.extern asm_AES_decrypt + +.type _bsaes_encrypt8,\@abi-omnipotent +.align 64 +_bsaes_encrypt8: + lea .LBS0(%rip), $const # constants table + + movdqa ($key), @XMM[9] # round 0 key + lea 0x10($key), $key + movdqa 0x50($const), @XMM[8] # .LM0SR + pxor @XMM[9], @XMM[0] # xor with round0 key + pxor @XMM[9], @XMM[1] + pxor @XMM[9], @XMM[2] + pxor @XMM[9], @XMM[3] + pshufb @XMM[8], @XMM[0] + pshufb @XMM[8], @XMM[1] + pxor @XMM[9], @XMM[4] + pxor @XMM[9], @XMM[5] + pshufb @XMM[8], @XMM[2] + pshufb @XMM[8], @XMM[3] + pxor @XMM[9], @XMM[6] + pxor @XMM[9], @XMM[7] + pshufb @XMM[8], @XMM[4] + pshufb @XMM[8], @XMM[5] + pshufb @XMM[8], @XMM[6] + pshufb @XMM[8], @XMM[7] +_bsaes_encrypt8_bitslice: +___ + &bitslice (@XMM[0..7, 8..11]); +$code.=<<___; + dec $rounds + jmp .Lenc_sbox +.align 16 +.Lenc_loop: +___ + &ShiftRows (@XMM[0..7, 8]); +$code.=".Lenc_sbox:\n"; + &Sbox (@XMM[0..7, 8..15]); +$code.=<<___; + dec $rounds + jl .Lenc_done +___ + &MixColumns (@XMM[0,1,4,6,3,7,2,5, 8..15]); +$code.=<<___; + movdqa 0x30($const), @XMM[8] # .LSR + jnz .Lenc_loop + movdqa 0x40($const), @XMM[8] # .LSRM0 + jmp .Lenc_loop +.align 16 +.Lenc_done: +___ + # output in lsb > [t0, t1, t4, t6, t3, t7, t2, t5] < msb + &bitslice (@XMM[0,1,4,6,3,7,2,5, 8..11]); +$code.=<<___; + movdqa ($key), @XMM[8] # last round key + pxor @XMM[8], @XMM[4] + pxor @XMM[8], @XMM[6] + pxor @XMM[8], @XMM[3] + pxor @XMM[8], @XMM[7] + pxor @XMM[8], @XMM[2] + pxor @XMM[8], @XMM[5] + pxor @XMM[8], @XMM[0] + pxor @XMM[8], @XMM[1] + ret +.size _bsaes_encrypt8,.-_bsaes_encrypt8 + +.type _bsaes_decrypt8,\@abi-omnipotent +.align 64 +_bsaes_decrypt8: + lea .LBS0(%rip), $const # constants table + + movdqa ($key), @XMM[9] # round 0 key + lea 0x10($key), $key + movdqa -0x30($const), @XMM[8] # .LM0ISR + pxor @XMM[9], @XMM[0] # xor with round0 key + pxor @XMM[9], @XMM[1] + pxor @XMM[9], @XMM[2] + pxor @XMM[9], @XMM[3] + pshufb @XMM[8], @XMM[0] + pshufb @XMM[8], @XMM[1] + pxor @XMM[9], @XMM[4] + pxor @XMM[9], @XMM[5] + pshufb @XMM[8], @XMM[2] + pshufb @XMM[8], @XMM[3] + pxor @XMM[9], @XMM[6] + pxor @XMM[9], @XMM[7] + pshufb @XMM[8], @XMM[4] + pshufb @XMM[8], @XMM[5] + pshufb @XMM[8], @XMM[6] + pshufb @XMM[8], @XMM[7] +___ + &bitslice (@XMM[0..7, 8..11]); +$code.=<<___; + dec $rounds + jmp .Ldec_sbox +.align 16 +.Ldec_loop: +___ + &ShiftRows (@XMM[0..7, 8]); +$code.=".Ldec_sbox:\n"; + &InvSbox (@XMM[0..7, 8..15]); +$code.=<<___; + dec $rounds + jl .Ldec_done +___ + &InvMixColumns (@XMM[0,1,6,4,2,7,3,5, 8..15]); +$code.=<<___; + movdqa -0x10($const), @XMM[8] # .LISR + jnz .Ldec_loop + movdqa -0x20($const), @XMM[8] # .LISRM0 + jmp .Ldec_loop +.align 16 +.Ldec_done: +___ + &bitslice (@XMM[0,1,6,4,2,7,3,5, 8..11]); +$code.=<<___; + movdqa ($key), @XMM[8] # last round key + pxor @XMM[8], @XMM[6] + pxor @XMM[8], @XMM[4] + pxor @XMM[8], @XMM[2] + pxor @XMM[8], @XMM[7] + pxor @XMM[8], @XMM[3] + pxor @XMM[8], @XMM[5] + pxor @XMM[8], @XMM[0] + pxor @XMM[8], @XMM[1] + ret +.size _bsaes_decrypt8,.-_bsaes_decrypt8 +___ +} +{ +my ($out,$inp,$rounds,$const)=("%rax","%rcx","%r10d","%r11"); + +sub bitslice_key { +my @x=reverse(@_[0..7]); +my ($bs0,$bs1,$bs2,$t2,$t3)=@_[8..12]; + + &swapmove (@x[0,1],1,$bs0,$t2,$t3); +$code.=<<___; + #&swapmove(@x[2,3],1,$t0,$t2,$t3); + movdqa @x[0], @x[2] + movdqa @x[1], @x[3] +___ + #&swapmove2x(@x[4,5,6,7],1,$t0,$t2,$t3); + + &swapmove2x (@x[0,2,1,3],2,$bs1,$t2,$t3); +$code.=<<___; + #&swapmove2x(@x[4,6,5,7],2,$t1,$t2,$t3); + movdqa @x[0], @x[4] + movdqa @x[2], @x[6] + movdqa @x[1], @x[5] + movdqa @x[3], @x[7] +___ + &swapmove2x (@x[0,4,1,5],4,$bs2,$t2,$t3); + &swapmove2x (@x[2,6,3,7],4,$bs2,$t2,$t3); +} + +$code.=<<___; +.type _bsaes_key_convert,\@abi-omnipotent +.align 16 +_bsaes_key_convert: + lea .Lmasks(%rip), $const + movdqu ($inp), %xmm7 # load round 0 key + lea 0x10($inp), $inp + movdqa 0x00($const), %xmm0 # 0x01... + movdqa 0x10($const), %xmm1 # 0x02... + movdqa 0x20($const), %xmm2 # 0x04... + movdqa 0x30($const), %xmm3 # 0x08... + movdqa 0x40($const), %xmm4 # .LM0 + pcmpeqd %xmm5, %xmm5 # .LNOT + + movdqu ($inp), %xmm6 # load round 1 key + movdqa %xmm7, ($out) # save round 0 key + lea 0x10($out), $out + dec $rounds + jmp .Lkey_loop +.align 16 +.Lkey_loop: + pshufb %xmm4, %xmm6 # .LM0 + + movdqa %xmm0, %xmm8 + movdqa %xmm1, %xmm9 + + pand %xmm6, %xmm8 + pand %xmm6, %xmm9 + movdqa %xmm2, %xmm10 + pcmpeqb %xmm0, %xmm8 + psllq \$4, %xmm0 # 0x10... + movdqa %xmm3, %xmm11 + pcmpeqb %xmm1, %xmm9 + psllq \$4, %xmm1 # 0x20... + + pand %xmm6, %xmm10 + pand %xmm6, %xmm11 + movdqa %xmm0, %xmm12 + pcmpeqb %xmm2, %xmm10 + psllq \$4, %xmm2 # 0x40... + movdqa %xmm1, %xmm13 + pcmpeqb %xmm3, %xmm11 + psllq \$4, %xmm3 # 0x80... + + movdqa %xmm2, %xmm14 + movdqa %xmm3, %xmm15 + pxor %xmm5, %xmm8 # "pnot" + pxor %xmm5, %xmm9 + + pand %xmm6, %xmm12 + pand %xmm6, %xmm13 + movdqa %xmm8, 0x00($out) # write bit-sliced round key + pcmpeqb %xmm0, %xmm12 + psrlq \$4, %xmm0 # 0x01... + movdqa %xmm9, 0x10($out) + pcmpeqb %xmm1, %xmm13 + psrlq \$4, %xmm1 # 0x02... + lea 0x10($inp), $inp + + pand %xmm6, %xmm14 + pand %xmm6, %xmm15 + movdqa %xmm10, 0x20($out) + pcmpeqb %xmm2, %xmm14 + psrlq \$4, %xmm2 # 0x04... + movdqa %xmm11, 0x30($out) + pcmpeqb %xmm3, %xmm15 + psrlq \$4, %xmm3 # 0x08... + movdqu ($inp), %xmm6 # load next round key + + pxor %xmm5, %xmm13 # "pnot" + pxor %xmm5, %xmm14 + movdqa %xmm12, 0x40($out) + movdqa %xmm13, 0x50($out) + movdqa %xmm14, 0x60($out) + movdqa %xmm15, 0x70($out) + lea 0x80($out),$out + dec $rounds + jnz .Lkey_loop + + movdqa 0x50($const), %xmm7 # .L63 + #movdqa %xmm6, ($out) # don't save last round key + ret +.size _bsaes_key_convert,.-_bsaes_key_convert +___ +} + +if (0 && !$win64) { # following four functions are unsupported interface + # used for benchmarking... +$code.=<<___; +.globl bsaes_enc_key_convert +.type bsaes_enc_key_convert,\@function,2 +.align 16 +bsaes_enc_key_convert: + mov 240($inp),%r10d # pass rounds + mov $inp,%rcx # pass key + mov $out,%rax # pass key schedule + call _bsaes_key_convert + pxor %xmm6,%xmm7 # fix up last round key + movdqa %xmm7,(%rax) # save last round key + ret +.size bsaes_enc_key_convert,.-bsaes_enc_key_convert + +.globl bsaes_encrypt_128 +.type bsaes_encrypt_128,\@function,4 +.align 16 +bsaes_encrypt_128: +.Lenc128_loop: + movdqu 0x00($inp), @XMM[0] # load input + movdqu 0x10($inp), @XMM[1] + movdqu 0x20($inp), @XMM[2] + movdqu 0x30($inp), @XMM[3] + movdqu 0x40($inp), @XMM[4] + movdqu 0x50($inp), @XMM[5] + movdqu 0x60($inp), @XMM[6] + movdqu 0x70($inp), @XMM[7] + mov $key, %rax # pass the $key + lea 0x80($inp), $inp + mov \$10,%r10d + + call _bsaes_encrypt8 + + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + movdqu @XMM[6], 0x30($out) + movdqu @XMM[3], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[2], 0x60($out) + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + sub \$0x80,$len + ja .Lenc128_loop + ret +.size bsaes_encrypt_128,.-bsaes_encrypt_128 + +.globl bsaes_dec_key_convert +.type bsaes_dec_key_convert,\@function,2 +.align 16 +bsaes_dec_key_convert: + mov 240($inp),%r10d # pass rounds + mov $inp,%rcx # pass key + mov $out,%rax # pass key schedule + call _bsaes_key_convert + pxor ($out),%xmm7 # fix up round 0 key + movdqa %xmm6,(%rax) # save last round key + movdqa %xmm7,($out) + ret +.size bsaes_dec_key_convert,.-bsaes_dec_key_convert + +.globl bsaes_decrypt_128 +.type bsaes_decrypt_128,\@function,4 +.align 16 +bsaes_decrypt_128: +.Ldec128_loop: + movdqu 0x00($inp), @XMM[0] # load input + movdqu 0x10($inp), @XMM[1] + movdqu 0x20($inp), @XMM[2] + movdqu 0x30($inp), @XMM[3] + movdqu 0x40($inp), @XMM[4] + movdqu 0x50($inp), @XMM[5] + movdqu 0x60($inp), @XMM[6] + movdqu 0x70($inp), @XMM[7] + mov $key, %rax # pass the $key + lea 0x80($inp), $inp + mov \$10,%r10d + + call _bsaes_decrypt8 + + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[3], 0x60($out) + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + sub \$0x80,$len + ja .Ldec128_loop + ret +.size bsaes_decrypt_128,.-bsaes_decrypt_128 +___ +} +{ +###################################################################### +# +# OpenSSL interface +# +my ($arg1,$arg2,$arg3,$arg4,$arg5,$arg6)=$win64 ? ("%rcx","%rdx","%r8","%r9","%r10","%r11d") + : ("%rdi","%rsi","%rdx","%rcx","%r8","%r9d"); +my ($inp,$out,$len,$key)=("%r12","%r13","%r14","%r15"); + +if ($ecb) { +$code.=<<___; +.globl bsaes_ecb_encrypt_blocks +.type bsaes_ecb_encrypt_blocks,\@abi-omnipotent +.align 16 +bsaes_ecb_encrypt_blocks: + mov %rsp, %rax +.Lecb_enc_prologue: + push %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + lea -0x48(%rsp),%rsp +___ +$code.=<<___ if ($win64); + lea -0xa0(%rsp), %rsp + movaps %xmm6, 0x40(%rsp) + movaps %xmm7, 0x50(%rsp) + movaps %xmm8, 0x60(%rsp) + movaps %xmm9, 0x70(%rsp) + movaps %xmm10, 0x80(%rsp) + movaps %xmm11, 0x90(%rsp) + movaps %xmm12, 0xa0(%rsp) + movaps %xmm13, 0xb0(%rsp) + movaps %xmm14, 0xc0(%rsp) + movaps %xmm15, 0xd0(%rsp) +.Lecb_enc_body: +___ +$code.=<<___; + mov %rsp,%rbp # backup %rsp + mov 240($arg4),%eax # rounds + mov $arg1,$inp # backup arguments + mov $arg2,$out + mov $arg3,$len + mov $arg4,$key + cmp \$8,$arg3 + jb .Lecb_enc_short + + mov %eax,%ebx # backup rounds + shl \$7,%rax # 128 bytes per inner round key + sub \$`128-32`,%rax # size of bit-sliced key schedule + sub %rax,%rsp + mov %rsp,%rax # pass key schedule + mov $key,%rcx # pass key + mov %ebx,%r10d # pass rounds + call _bsaes_key_convert + pxor %xmm6,%xmm7 # fix up last round key + movdqa %xmm7,(%rax) # save last round key + + sub \$8,$len +.Lecb_enc_loop: + movdqu 0x00($inp), @XMM[0] # load input + movdqu 0x10($inp), @XMM[1] + movdqu 0x20($inp), @XMM[2] + movdqu 0x30($inp), @XMM[3] + movdqu 0x40($inp), @XMM[4] + movdqu 0x50($inp), @XMM[5] + mov %rsp, %rax # pass key schedule + movdqu 0x60($inp), @XMM[6] + mov %ebx,%r10d # pass rounds + movdqu 0x70($inp), @XMM[7] + lea 0x80($inp), $inp + + call _bsaes_encrypt8 + + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + movdqu @XMM[6], 0x30($out) + movdqu @XMM[3], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[2], 0x60($out) + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + sub \$8,$len + jnc .Lecb_enc_loop + + add \$8,$len + jz .Lecb_enc_done + + movdqu 0x00($inp), @XMM[0] # load input + mov %rsp, %rax # pass key schedule + mov %ebx,%r10d # pass rounds + cmp \$2,$len + jb .Lecb_enc_one + movdqu 0x10($inp), @XMM[1] + je .Lecb_enc_two + movdqu 0x20($inp), @XMM[2] + cmp \$4,$len + jb .Lecb_enc_three + movdqu 0x30($inp), @XMM[3] + je .Lecb_enc_four + movdqu 0x40($inp), @XMM[4] + cmp \$6,$len + jb .Lecb_enc_five + movdqu 0x50($inp), @XMM[5] + je .Lecb_enc_six + movdqu 0x60($inp), @XMM[6] + call _bsaes_encrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + movdqu @XMM[6], 0x30($out) + movdqu @XMM[3], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[2], 0x60($out) + jmp .Lecb_enc_done +.align 16 +.Lecb_enc_six: + call _bsaes_encrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + movdqu @XMM[6], 0x30($out) + movdqu @XMM[3], 0x40($out) + movdqu @XMM[7], 0x50($out) + jmp .Lecb_enc_done +.align 16 +.Lecb_enc_five: + call _bsaes_encrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + movdqu @XMM[6], 0x30($out) + movdqu @XMM[3], 0x40($out) + jmp .Lecb_enc_done +.align 16 +.Lecb_enc_four: + call _bsaes_encrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + movdqu @XMM[6], 0x30($out) + jmp .Lecb_enc_done +.align 16 +.Lecb_enc_three: + call _bsaes_encrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + jmp .Lecb_enc_done +.align 16 +.Lecb_enc_two: + call _bsaes_encrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + jmp .Lecb_enc_done +.align 16 +.Lecb_enc_one: + call _bsaes_encrypt8 + movdqu @XMM[0], 0x00($out) # write output + jmp .Lecb_enc_done +.align 16 +.Lecb_enc_short: + lea ($inp), $arg1 + lea ($out), $arg2 + lea ($key), $arg3 + call asm_AES_encrypt + lea 16($inp), $inp + lea 16($out), $out + dec $len + jnz .Lecb_enc_short + +.Lecb_enc_done: + lea (%rsp),%rax + pxor %xmm0, %xmm0 +.Lecb_enc_bzero: # wipe key schedule [if any] + movdqa %xmm0, 0x00(%rax) + movdqa %xmm0, 0x10(%rax) + lea 0x20(%rax), %rax + cmp %rax, %rbp + jb .Lecb_enc_bzero + + lea (%rbp),%rsp # restore %rsp +___ +$code.=<<___ if ($win64); + movaps 0x40(%rbp), %xmm6 + movaps 0x50(%rbp), %xmm7 + movaps 0x60(%rbp), %xmm8 + movaps 0x70(%rbp), %xmm9 + movaps 0x80(%rbp), %xmm10 + movaps 0x90(%rbp), %xmm11 + movaps 0xa0(%rbp), %xmm12 + movaps 0xb0(%rbp), %xmm13 + movaps 0xc0(%rbp), %xmm14 + movaps 0xd0(%rbp), %xmm15 + lea 0xa0(%rbp), %rsp +___ +$code.=<<___; + mov 0x48(%rsp), %r15 + mov 0x50(%rsp), %r14 + mov 0x58(%rsp), %r13 + mov 0x60(%rsp), %r12 + mov 0x68(%rsp), %rbx + mov 0x70(%rsp), %rax + lea 0x78(%rsp), %rsp + mov %rax, %rbp +.Lecb_enc_epilogue: + ret +.size bsaes_ecb_encrypt_blocks,.-bsaes_ecb_encrypt_blocks + +.globl bsaes_ecb_decrypt_blocks +.type bsaes_ecb_decrypt_blocks,\@abi-omnipotent +.align 16 +bsaes_ecb_decrypt_blocks: + mov %rsp, %rax +.Lecb_dec_prologue: + push %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + lea -0x48(%rsp),%rsp +___ +$code.=<<___ if ($win64); + lea -0xa0(%rsp), %rsp + movaps %xmm6, 0x40(%rsp) + movaps %xmm7, 0x50(%rsp) + movaps %xmm8, 0x60(%rsp) + movaps %xmm9, 0x70(%rsp) + movaps %xmm10, 0x80(%rsp) + movaps %xmm11, 0x90(%rsp) + movaps %xmm12, 0xa0(%rsp) + movaps %xmm13, 0xb0(%rsp) + movaps %xmm14, 0xc0(%rsp) + movaps %xmm15, 0xd0(%rsp) +.Lecb_dec_body: +___ +$code.=<<___; + mov %rsp,%rbp # backup %rsp + mov 240($arg4),%eax # rounds + mov $arg1,$inp # backup arguments + mov $arg2,$out + mov $arg3,$len + mov $arg4,$key + cmp \$8,$arg3 + jb .Lecb_dec_short + + mov %eax,%ebx # backup rounds + shl \$7,%rax # 128 bytes per inner round key + sub \$`128-32`,%rax # size of bit-sliced key schedule + sub %rax,%rsp + mov %rsp,%rax # pass key schedule + mov $key,%rcx # pass key + mov %ebx,%r10d # pass rounds + call _bsaes_key_convert + pxor (%rsp),%xmm7 # fix up 0 round key + movdqa %xmm6,(%rax) # save last round key + movdqa %xmm7,(%rsp) + + sub \$8,$len +.Lecb_dec_loop: + movdqu 0x00($inp), @XMM[0] # load input + movdqu 0x10($inp), @XMM[1] + movdqu 0x20($inp), @XMM[2] + movdqu 0x30($inp), @XMM[3] + movdqu 0x40($inp), @XMM[4] + movdqu 0x50($inp), @XMM[5] + mov %rsp, %rax # pass key schedule + movdqu 0x60($inp), @XMM[6] + mov %ebx,%r10d # pass rounds + movdqu 0x70($inp), @XMM[7] + lea 0x80($inp), $inp + + call _bsaes_decrypt8 + + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[3], 0x60($out) + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + sub \$8,$len + jnc .Lecb_dec_loop + + add \$8,$len + jz .Lecb_dec_done + + movdqu 0x00($inp), @XMM[0] # load input + mov %rsp, %rax # pass key schedule + mov %ebx,%r10d # pass rounds + cmp \$2,$len + jb .Lecb_dec_one + movdqu 0x10($inp), @XMM[1] + je .Lecb_dec_two + movdqu 0x20($inp), @XMM[2] + cmp \$4,$len + jb .Lecb_dec_three + movdqu 0x30($inp), @XMM[3] + je .Lecb_dec_four + movdqu 0x40($inp), @XMM[4] + cmp \$6,$len + jb .Lecb_dec_five + movdqu 0x50($inp), @XMM[5] + je .Lecb_dec_six + movdqu 0x60($inp), @XMM[6] + call _bsaes_decrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[3], 0x60($out) + jmp .Lecb_dec_done +.align 16 +.Lecb_dec_six: + call _bsaes_decrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + jmp .Lecb_dec_done +.align 16 +.Lecb_dec_five: + call _bsaes_decrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + jmp .Lecb_dec_done +.align 16 +.Lecb_dec_four: + call _bsaes_decrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + jmp .Lecb_dec_done +.align 16 +.Lecb_dec_three: + call _bsaes_decrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + jmp .Lecb_dec_done +.align 16 +.Lecb_dec_two: + call _bsaes_decrypt8 + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + jmp .Lecb_dec_done +.align 16 +.Lecb_dec_one: + call _bsaes_decrypt8 + movdqu @XMM[0], 0x00($out) # write output + jmp .Lecb_dec_done +.align 16 +.Lecb_dec_short: + lea ($inp), $arg1 + lea ($out), $arg2 + lea ($key), $arg3 + call asm_AES_decrypt + lea 16($inp), $inp + lea 16($out), $out + dec $len + jnz .Lecb_dec_short + +.Lecb_dec_done: + lea (%rsp),%rax + pxor %xmm0, %xmm0 +.Lecb_dec_bzero: # wipe key schedule [if any] + movdqa %xmm0, 0x00(%rax) + movdqa %xmm0, 0x10(%rax) + lea 0x20(%rax), %rax + cmp %rax, %rbp + jb .Lecb_dec_bzero + + lea (%rbp),%rsp # restore %rsp +___ +$code.=<<___ if ($win64); + movaps 0x40(%rbp), %xmm6 + movaps 0x50(%rbp), %xmm7 + movaps 0x60(%rbp), %xmm8 + movaps 0x70(%rbp), %xmm9 + movaps 0x80(%rbp), %xmm10 + movaps 0x90(%rbp), %xmm11 + movaps 0xa0(%rbp), %xmm12 + movaps 0xb0(%rbp), %xmm13 + movaps 0xc0(%rbp), %xmm14 + movaps 0xd0(%rbp), %xmm15 + lea 0xa0(%rbp), %rsp +___ +$code.=<<___; + mov 0x48(%rsp), %r15 + mov 0x50(%rsp), %r14 + mov 0x58(%rsp), %r13 + mov 0x60(%rsp), %r12 + mov 0x68(%rsp), %rbx + mov 0x70(%rsp), %rax + lea 0x78(%rsp), %rsp + mov %rax, %rbp +.Lecb_dec_epilogue: + ret +.size bsaes_ecb_decrypt_blocks,.-bsaes_ecb_decrypt_blocks +___ +} +$code.=<<___; +.extern asm_AES_cbc_encrypt +.globl bsaes_cbc_encrypt +.type bsaes_cbc_encrypt,\@abi-omnipotent +.align 16 +bsaes_cbc_encrypt: +___ +$code.=<<___ if ($win64); + mov 48(%rsp),$arg6 # pull direction flag +___ +$code.=<<___; + cmp \$0,$arg6 + jne asm_AES_cbc_encrypt + cmp \$128,$arg3 + jb asm_AES_cbc_encrypt + + mov %rsp, %rax +.Lcbc_dec_prologue: + push %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + lea -0x48(%rsp), %rsp +___ +$code.=<<___ if ($win64); + mov 0xa0(%rsp),$arg5 # pull ivp + lea -0xa0(%rsp), %rsp + movaps %xmm6, 0x40(%rsp) + movaps %xmm7, 0x50(%rsp) + movaps %xmm8, 0x60(%rsp) + movaps %xmm9, 0x70(%rsp) + movaps %xmm10, 0x80(%rsp) + movaps %xmm11, 0x90(%rsp) + movaps %xmm12, 0xa0(%rsp) + movaps %xmm13, 0xb0(%rsp) + movaps %xmm14, 0xc0(%rsp) + movaps %xmm15, 0xd0(%rsp) +.Lcbc_dec_body: +___ +$code.=<<___; + mov %rsp, %rbp # backup %rsp + mov 240($arg4), %eax # rounds + mov $arg1, $inp # backup arguments + mov $arg2, $out + mov $arg3, $len + mov $arg4, $key + mov $arg5, %rbx + shr \$4, $len # bytes to blocks + + mov %eax, %edx # rounds + shl \$7, %rax # 128 bytes per inner round key + sub \$`128-32`, %rax # size of bit-sliced key schedule + sub %rax, %rsp + + mov %rsp, %rax # pass key schedule + mov $key, %rcx # pass key + mov %edx, %r10d # pass rounds + call _bsaes_key_convert + pxor (%rsp),%xmm7 # fix up 0 round key + movdqa %xmm6,(%rax) # save last round key + movdqa %xmm7,(%rsp) + + movdqu (%rbx), @XMM[15] # load IV + sub \$8,$len +.Lcbc_dec_loop: + movdqu 0x00($inp), @XMM[0] # load input + movdqu 0x10($inp), @XMM[1] + movdqu 0x20($inp), @XMM[2] + movdqu 0x30($inp), @XMM[3] + movdqu 0x40($inp), @XMM[4] + movdqu 0x50($inp), @XMM[5] + mov %rsp, %rax # pass key schedule + movdqu 0x60($inp), @XMM[6] + mov %edx,%r10d # pass rounds + movdqu 0x70($inp), @XMM[7] + movdqa @XMM[15], 0x20(%rbp) # put aside IV + + call _bsaes_decrypt8 + + pxor 0x20(%rbp), @XMM[0] # ^= IV + movdqu 0x00($inp), @XMM[8] # re-load input + movdqu 0x10($inp), @XMM[9] + pxor @XMM[8], @XMM[1] + movdqu 0x20($inp), @XMM[10] + pxor @XMM[9], @XMM[6] + movdqu 0x30($inp), @XMM[11] + pxor @XMM[10], @XMM[4] + movdqu 0x40($inp), @XMM[12] + pxor @XMM[11], @XMM[2] + movdqu 0x50($inp), @XMM[13] + pxor @XMM[12], @XMM[7] + movdqu 0x60($inp), @XMM[14] + pxor @XMM[13], @XMM[3] + movdqu 0x70($inp), @XMM[15] # IV + pxor @XMM[14], @XMM[5] + movdqu @XMM[0], 0x00($out) # write output + lea 0x80($inp), $inp + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[3], 0x60($out) + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + sub \$8,$len + jnc .Lcbc_dec_loop + + add \$8,$len + jz .Lcbc_dec_done + + movdqu 0x00($inp), @XMM[0] # load input + mov %rsp, %rax # pass key schedule + mov %edx, %r10d # pass rounds + cmp \$2,$len + jb .Lcbc_dec_one + movdqu 0x10($inp), @XMM[1] + je .Lcbc_dec_two + movdqu 0x20($inp), @XMM[2] + cmp \$4,$len + jb .Lcbc_dec_three + movdqu 0x30($inp), @XMM[3] + je .Lcbc_dec_four + movdqu 0x40($inp), @XMM[4] + cmp \$6,$len + jb .Lcbc_dec_five + movdqu 0x50($inp), @XMM[5] + je .Lcbc_dec_six + movdqu 0x60($inp), @XMM[6] + movdqa @XMM[15], 0x20(%rbp) # put aside IV + call _bsaes_decrypt8 + pxor 0x20(%rbp), @XMM[0] # ^= IV + movdqu 0x00($inp), @XMM[8] # re-load input + movdqu 0x10($inp), @XMM[9] + pxor @XMM[8], @XMM[1] + movdqu 0x20($inp), @XMM[10] + pxor @XMM[9], @XMM[6] + movdqu 0x30($inp), @XMM[11] + pxor @XMM[10], @XMM[4] + movdqu 0x40($inp), @XMM[12] + pxor @XMM[11], @XMM[2] + movdqu 0x50($inp), @XMM[13] + pxor @XMM[12], @XMM[7] + movdqu 0x60($inp), @XMM[15] # IV + pxor @XMM[13], @XMM[3] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + movdqu @XMM[3], 0x60($out) + jmp .Lcbc_dec_done +.align 16 +.Lcbc_dec_six: + movdqa @XMM[15], 0x20(%rbp) # put aside IV + call _bsaes_decrypt8 + pxor 0x20(%rbp), @XMM[0] # ^= IV + movdqu 0x00($inp), @XMM[8] # re-load input + movdqu 0x10($inp), @XMM[9] + pxor @XMM[8], @XMM[1] + movdqu 0x20($inp), @XMM[10] + pxor @XMM[9], @XMM[6] + movdqu 0x30($inp), @XMM[11] + pxor @XMM[10], @XMM[4] + movdqu 0x40($inp), @XMM[12] + pxor @XMM[11], @XMM[2] + movdqu 0x50($inp), @XMM[15] # IV + pxor @XMM[12], @XMM[7] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + jmp .Lcbc_dec_done +.align 16 +.Lcbc_dec_five: + movdqa @XMM[15], 0x20(%rbp) # put aside IV + call _bsaes_decrypt8 + pxor 0x20(%rbp), @XMM[0] # ^= IV + movdqu 0x00($inp), @XMM[8] # re-load input + movdqu 0x10($inp), @XMM[9] + pxor @XMM[8], @XMM[1] + movdqu 0x20($inp), @XMM[10] + pxor @XMM[9], @XMM[6] + movdqu 0x30($inp), @XMM[11] + pxor @XMM[10], @XMM[4] + movdqu 0x40($inp), @XMM[15] # IV + pxor @XMM[11], @XMM[2] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + jmp .Lcbc_dec_done +.align 16 +.Lcbc_dec_four: + movdqa @XMM[15], 0x20(%rbp) # put aside IV + call _bsaes_decrypt8 + pxor 0x20(%rbp), @XMM[0] # ^= IV + movdqu 0x00($inp), @XMM[8] # re-load input + movdqu 0x10($inp), @XMM[9] + pxor @XMM[8], @XMM[1] + movdqu 0x20($inp), @XMM[10] + pxor @XMM[9], @XMM[6] + movdqu 0x30($inp), @XMM[15] # IV + pxor @XMM[10], @XMM[4] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + jmp .Lcbc_dec_done +.align 16 +.Lcbc_dec_three: + movdqa @XMM[15], 0x20(%rbp) # put aside IV + call _bsaes_decrypt8 + pxor 0x20(%rbp), @XMM[0] # ^= IV + movdqu 0x00($inp), @XMM[8] # re-load input + movdqu 0x10($inp), @XMM[9] + pxor @XMM[8], @XMM[1] + movdqu 0x20($inp), @XMM[15] # IV + pxor @XMM[9], @XMM[6] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + jmp .Lcbc_dec_done +.align 16 +.Lcbc_dec_two: + movdqa @XMM[15], 0x20(%rbp) # put aside IV + call _bsaes_decrypt8 + pxor 0x20(%rbp), @XMM[0] # ^= IV + movdqu 0x00($inp), @XMM[8] # re-load input + movdqu 0x10($inp), @XMM[15] # IV + pxor @XMM[8], @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + jmp .Lcbc_dec_done +.align 16 +.Lcbc_dec_one: + lea ($inp), $arg1 + lea 0x20(%rbp), $arg2 # buffer output + lea ($key), $arg3 + call asm_AES_decrypt # doesn't touch %xmm + pxor 0x20(%rbp), @XMM[15] # ^= IV + movdqu @XMM[15], ($out) # write output + movdqa @XMM[0], @XMM[15] # IV + +.Lcbc_dec_done: + movdqu @XMM[15], (%rbx) # return IV + lea (%rsp), %rax + pxor %xmm0, %xmm0 +.Lcbc_dec_bzero: # wipe key schedule [if any] + movdqa %xmm0, 0x00(%rax) + movdqa %xmm0, 0x10(%rax) + lea 0x20(%rax), %rax + cmp %rax, %rbp + ja .Lcbc_dec_bzero + + lea (%rbp),%rsp # restore %rsp +___ +$code.=<<___ if ($win64); + movaps 0x40(%rbp), %xmm6 + movaps 0x50(%rbp), %xmm7 + movaps 0x60(%rbp), %xmm8 + movaps 0x70(%rbp), %xmm9 + movaps 0x80(%rbp), %xmm10 + movaps 0x90(%rbp), %xmm11 + movaps 0xa0(%rbp), %xmm12 + movaps 0xb0(%rbp), %xmm13 + movaps 0xc0(%rbp), %xmm14 + movaps 0xd0(%rbp), %xmm15 + lea 0xa0(%rbp), %rsp +___ +$code.=<<___; + mov 0x48(%rsp), %r15 + mov 0x50(%rsp), %r14 + mov 0x58(%rsp), %r13 + mov 0x60(%rsp), %r12 + mov 0x68(%rsp), %rbx + mov 0x70(%rsp), %rax + lea 0x78(%rsp), %rsp + mov %rax, %rbp +.Lcbc_dec_epilogue: + ret +.size bsaes_cbc_encrypt,.-bsaes_cbc_encrypt + +.globl bsaes_ctr32_encrypt_blocks +.type bsaes_ctr32_encrypt_blocks,\@abi-omnipotent +.align 16 +bsaes_ctr32_encrypt_blocks: + mov %rsp, %rax +.Lctr_enc_prologue: + push %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + lea -0x48(%rsp), %rsp +___ +$code.=<<___ if ($win64); + mov 0xa0(%rsp),$arg5 # pull ivp + lea -0xa0(%rsp), %rsp + movaps %xmm6, 0x40(%rsp) + movaps %xmm7, 0x50(%rsp) + movaps %xmm8, 0x60(%rsp) + movaps %xmm9, 0x70(%rsp) + movaps %xmm10, 0x80(%rsp) + movaps %xmm11, 0x90(%rsp) + movaps %xmm12, 0xa0(%rsp) + movaps %xmm13, 0xb0(%rsp) + movaps %xmm14, 0xc0(%rsp) + movaps %xmm15, 0xd0(%rsp) +.Lctr_enc_body: +___ +$code.=<<___; + mov %rsp, %rbp # backup %rsp + movdqu ($arg5), %xmm0 # load counter + mov 240($arg4), %eax # rounds + mov $arg1, $inp # backup arguments + mov $arg2, $out + mov $arg3, $len + mov $arg4, $key + movdqa %xmm0, 0x20(%rbp) # copy counter + cmp \$8, $arg3 + jb .Lctr_enc_short + + mov %eax, %ebx # rounds + shl \$7, %rax # 128 bytes per inner round key + sub \$`128-32`, %rax # size of bit-sliced key schedule + sub %rax, %rsp + + mov %rsp, %rax # pass key schedule + mov $key, %rcx # pass key + mov %ebx, %r10d # pass rounds + call _bsaes_key_convert + pxor %xmm6,%xmm7 # fix up last round key + movdqa %xmm7,(%rax) # save last round key + + movdqa (%rsp), @XMM[9] # load round0 key + lea .LADD1(%rip), %r11 + movdqa 0x20(%rbp), @XMM[0] # counter copy + movdqa -0x20(%r11), @XMM[8] # .LSWPUP + pshufb @XMM[8], @XMM[9] # byte swap upper part + pshufb @XMM[8], @XMM[0] + movdqa @XMM[9], (%rsp) # save adjusted round0 key + jmp .Lctr_enc_loop +.align 16 +.Lctr_enc_loop: + movdqa @XMM[0], 0x20(%rbp) # save counter + movdqa @XMM[0], @XMM[1] # prepare 8 counter values + movdqa @XMM[0], @XMM[2] + paddd 0x00(%r11), @XMM[1] # .LADD1 + movdqa @XMM[0], @XMM[3] + paddd 0x10(%r11), @XMM[2] # .LADD2 + movdqa @XMM[0], @XMM[4] + paddd 0x20(%r11), @XMM[3] # .LADD3 + movdqa @XMM[0], @XMM[5] + paddd 0x30(%r11), @XMM[4] # .LADD4 + movdqa @XMM[0], @XMM[6] + paddd 0x40(%r11), @XMM[5] # .LADD5 + movdqa @XMM[0], @XMM[7] + paddd 0x50(%r11), @XMM[6] # .LADD6 + paddd 0x60(%r11), @XMM[7] # .LADD7 + + # Borrow prologue from _bsaes_encrypt8 to use the opportunity + # to flip byte order in 32-bit counter + movdqa (%rsp), @XMM[9] # round 0 key + lea 0x10(%rsp), %rax # pass key schedule + movdqa -0x10(%r11), @XMM[8] # .LSWPUPM0SR + pxor @XMM[9], @XMM[0] # xor with round0 key + pxor @XMM[9], @XMM[1] + pxor @XMM[9], @XMM[2] + pxor @XMM[9], @XMM[3] + pshufb @XMM[8], @XMM[0] + pshufb @XMM[8], @XMM[1] + pxor @XMM[9], @XMM[4] + pxor @XMM[9], @XMM[5] + pshufb @XMM[8], @XMM[2] + pshufb @XMM[8], @XMM[3] + pxor @XMM[9], @XMM[6] + pxor @XMM[9], @XMM[7] + pshufb @XMM[8], @XMM[4] + pshufb @XMM[8], @XMM[5] + pshufb @XMM[8], @XMM[6] + pshufb @XMM[8], @XMM[7] + lea .LBS0(%rip), %r11 # constants table + mov %ebx,%r10d # pass rounds + + call _bsaes_encrypt8_bitslice + + sub \$8,$len + jc .Lctr_enc_loop_done + + movdqu 0x00($inp), @XMM[8] # load input + movdqu 0x10($inp), @XMM[9] + movdqu 0x20($inp), @XMM[10] + movdqu 0x30($inp), @XMM[11] + movdqu 0x40($inp), @XMM[12] + movdqu 0x50($inp), @XMM[13] + movdqu 0x60($inp), @XMM[14] + movdqu 0x70($inp), @XMM[15] + lea 0x80($inp),$inp + pxor @XMM[0], @XMM[8] + movdqa 0x20(%rbp), @XMM[0] # load counter + pxor @XMM[9], @XMM[1] + movdqu @XMM[8], 0x00($out) # write output + pxor @XMM[10], @XMM[4] + movdqu @XMM[1], 0x10($out) + pxor @XMM[11], @XMM[6] + movdqu @XMM[4], 0x20($out) + pxor @XMM[12], @XMM[3] + movdqu @XMM[6], 0x30($out) + pxor @XMM[13], @XMM[7] + movdqu @XMM[3], 0x40($out) + pxor @XMM[14], @XMM[2] + movdqu @XMM[7], 0x50($out) + pxor @XMM[15], @XMM[5] + movdqu @XMM[2], 0x60($out) + lea .LADD1(%rip), %r11 + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + paddd 0x70(%r11), @XMM[0] # .LADD8 + jnz .Lctr_enc_loop + + jmp .Lctr_enc_done +.align 16 +.Lctr_enc_loop_done: + add \$8, $len + movdqu 0x00($inp), @XMM[8] # load input + pxor @XMM[8], @XMM[0] + movdqu @XMM[0], 0x00($out) # write output + cmp \$2,$len + jb .Lctr_enc_done + movdqu 0x10($inp), @XMM[9] + pxor @XMM[9], @XMM[1] + movdqu @XMM[1], 0x10($out) + je .Lctr_enc_done + movdqu 0x20($inp), @XMM[10] + pxor @XMM[10], @XMM[4] + movdqu @XMM[4], 0x20($out) + cmp \$4,$len + jb .Lctr_enc_done + movdqu 0x30($inp), @XMM[11] + pxor @XMM[11], @XMM[6] + movdqu @XMM[6], 0x30($out) + je .Lctr_enc_done + movdqu 0x40($inp), @XMM[12] + pxor @XMM[12], @XMM[3] + movdqu @XMM[3], 0x40($out) + cmp \$6,$len + jb .Lctr_enc_done + movdqu 0x50($inp), @XMM[13] + pxor @XMM[13], @XMM[7] + movdqu @XMM[7], 0x50($out) + je .Lctr_enc_done + movdqu 0x60($inp), @XMM[14] + pxor @XMM[14], @XMM[2] + movdqu @XMM[2], 0x60($out) + jmp .Lctr_enc_done + +.align 16 +.Lctr_enc_short: + lea 0x20(%rbp), $arg1 + lea 0x30(%rbp), $arg2 + lea ($key), $arg3 + call asm_AES_encrypt + movdqu ($inp), @XMM[1] + lea 16($inp), $inp + mov 0x2c(%rbp), %eax # load 32-bit counter + bswap %eax + pxor 0x30(%rbp), @XMM[1] + inc %eax # increment + movdqu @XMM[1], ($out) + bswap %eax + lea 16($out), $out + mov %eax, 0x2c(%rsp) # save 32-bit counter + dec $len + jnz .Lctr_enc_short + +.Lctr_enc_done: + lea (%rsp), %rax + pxor %xmm0, %xmm0 +.Lctr_enc_bzero: # wipe key schedule [if any] + movdqa %xmm0, 0x00(%rax) + movdqa %xmm0, 0x10(%rax) + lea 0x20(%rax), %rax + cmp %rax, %rbp + ja .Lctr_enc_bzero + + lea (%rbp),%rsp # restore %rsp +___ +$code.=<<___ if ($win64); + movaps 0x40(%rbp), %xmm6 + movaps 0x50(%rbp), %xmm7 + movaps 0x60(%rbp), %xmm8 + movaps 0x70(%rbp), %xmm9 + movaps 0x80(%rbp), %xmm10 + movaps 0x90(%rbp), %xmm11 + movaps 0xa0(%rbp), %xmm12 + movaps 0xb0(%rbp), %xmm13 + movaps 0xc0(%rbp), %xmm14 + movaps 0xd0(%rbp), %xmm15 + lea 0xa0(%rbp), %rsp +___ +$code.=<<___; + mov 0x48(%rsp), %r15 + mov 0x50(%rsp), %r14 + mov 0x58(%rsp), %r13 + mov 0x60(%rsp), %r12 + mov 0x68(%rsp), %rbx + mov 0x70(%rsp), %rax + lea 0x78(%rsp), %rsp + mov %rax, %rbp +.Lctr_enc_epilogue: + ret +.size bsaes_ctr32_encrypt_blocks,.-bsaes_ctr32_encrypt_blocks +___ +###################################################################### +# void bsaes_xts_[en|de]crypt(const char *inp,char *out,size_t len, +# const AES_KEY *key1, const AES_KEY *key2, +# const unsigned char iv[16]); +# +my ($twmask,$twres,$twtmp)=@XMM[13..15]; +$arg6=~s/d$//; + +$code.=<<___; +.globl bsaes_xts_encrypt +.type bsaes_xts_encrypt,\@abi-omnipotent +.align 16 +bsaes_xts_encrypt: + mov %rsp, %rax +.Lxts_enc_prologue: + push %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + lea -0x48(%rsp), %rsp +___ +$code.=<<___ if ($win64); + mov 0xa0(%rsp),$arg5 # pull key2 + mov 0xa8(%rsp),$arg6 # pull ivp + lea -0xa0(%rsp), %rsp + movaps %xmm6, 0x40(%rsp) + movaps %xmm7, 0x50(%rsp) + movaps %xmm8, 0x60(%rsp) + movaps %xmm9, 0x70(%rsp) + movaps %xmm10, 0x80(%rsp) + movaps %xmm11, 0x90(%rsp) + movaps %xmm12, 0xa0(%rsp) + movaps %xmm13, 0xb0(%rsp) + movaps %xmm14, 0xc0(%rsp) + movaps %xmm15, 0xd0(%rsp) +.Lxts_enc_body: +___ +$code.=<<___; + mov %rsp, %rbp # backup %rsp + mov $arg1, $inp # backup arguments + mov $arg2, $out + mov $arg3, $len + mov $arg4, $key + + lea ($arg6), $arg1 + lea 0x20(%rbp), $arg2 + lea ($arg5), $arg3 + call asm_AES_encrypt # generate initial tweak + + mov 240($key), %eax # rounds + mov $len, %rbx # backup $len + + mov %eax, %edx # rounds + shl \$7, %rax # 128 bytes per inner round key + sub \$`128-32`, %rax # size of bit-sliced key schedule + sub %rax, %rsp + + mov %rsp, %rax # pass key schedule + mov $key, %rcx # pass key + mov %edx, %r10d # pass rounds + call _bsaes_key_convert + pxor %xmm6, %xmm7 # fix up last round key + movdqa %xmm7, (%rax) # save last round key + + and \$-16, $len + sub \$0x80, %rsp # place for tweak[8] + movdqa 0x20(%rbp), @XMM[7] # initial tweak + + pxor $twtmp, $twtmp + movdqa .Lxts_magic(%rip), $twmask + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + + sub \$0x80, $len + jc .Lxts_enc_short + jmp .Lxts_enc_loop + +.align 16 +.Lxts_enc_loop: +___ + for ($i=0;$i<7;$i++) { + $code.=<<___; + pshufd \$0x13, $twtmp, $twres + pxor $twtmp, $twtmp + movdqa @XMM[7], @XMM[$i] + movdqa @XMM[7], `0x10*$i`(%rsp)# save tweak[$i] + paddq @XMM[7], @XMM[7] # psllq 1,$tweak + pand $twmask, $twres # isolate carry and residue + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + pxor $twres, @XMM[7] +___ + $code.=<<___ if ($i>=1); + movdqu `0x10*($i-1)`($inp), @XMM[8+$i-1] +___ + $code.=<<___ if ($i>=2); + pxor @XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[] +___ + } +$code.=<<___; + movdqu 0x60($inp), @XMM[8+6] + pxor @XMM[8+5], @XMM[5] + movdqu 0x70($inp), @XMM[8+7] + lea 0x80($inp), $inp + movdqa @XMM[7], 0x70(%rsp) + pxor @XMM[8+6], @XMM[6] + lea 0x80(%rsp), %rax # pass key schedule + pxor @XMM[8+7], @XMM[7] + mov %edx, %r10d # pass rounds + + call _bsaes_encrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[4] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[6] + movdqu @XMM[4], 0x20($out) + pxor 0x40(%rsp), @XMM[3] + movdqu @XMM[6], 0x30($out) + pxor 0x50(%rsp), @XMM[7] + movdqu @XMM[3], 0x40($out) + pxor 0x60(%rsp), @XMM[2] + movdqu @XMM[7], 0x50($out) + pxor 0x70(%rsp), @XMM[5] + movdqu @XMM[2], 0x60($out) + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + + movdqa 0x70(%rsp), @XMM[7] # prepare next iteration tweak + pxor $twtmp, $twtmp + movdqa .Lxts_magic(%rip), $twmask + pcmpgtd @XMM[7], $twtmp + pshufd \$0x13, $twtmp, $twres + pxor $twtmp, $twtmp + paddq @XMM[7], @XMM[7] # psllq 1,$tweak + pand $twmask, $twres # isolate carry and residue + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + pxor $twres, @XMM[7] + + sub \$0x80,$len + jnc .Lxts_enc_loop + +.Lxts_enc_short: + add \$0x80, $len + jz .Lxts_enc_done +___ + for ($i=0;$i<7;$i++) { + $code.=<<___; + pshufd \$0x13, $twtmp, $twres + pxor $twtmp, $twtmp + movdqa @XMM[7], @XMM[$i] + movdqa @XMM[7], `0x10*$i`(%rsp)# save tweak[$i] + paddq @XMM[7], @XMM[7] # psllq 1,$tweak + pand $twmask, $twres # isolate carry and residue + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + pxor $twres, @XMM[7] +___ + $code.=<<___ if ($i>=1); + movdqu `0x10*($i-1)`($inp), @XMM[8+$i-1] + cmp \$`0x10*$i`,$len + je .Lxts_enc_$i +___ + $code.=<<___ if ($i>=2); + pxor @XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[] +___ + } +$code.=<<___; + movdqu 0x60($inp), @XMM[8+6] + pxor @XMM[8+5], @XMM[5] + movdqa @XMM[7], 0x70(%rsp) + lea 0x70($inp), $inp + pxor @XMM[8+6], @XMM[6] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_encrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[4] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[6] + movdqu @XMM[4], 0x20($out) + pxor 0x40(%rsp), @XMM[3] + movdqu @XMM[6], 0x30($out) + pxor 0x50(%rsp), @XMM[7] + movdqu @XMM[3], 0x40($out) + pxor 0x60(%rsp), @XMM[2] + movdqu @XMM[7], 0x50($out) + movdqu @XMM[2], 0x60($out) + lea 0x70($out), $out + + movdqa 0x70(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_enc_done +.align 16 +.Lxts_enc_6: + pxor @XMM[8+4], @XMM[4] + lea 0x60($inp), $inp + pxor @XMM[8+5], @XMM[5] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_encrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[4] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[6] + movdqu @XMM[4], 0x20($out) + pxor 0x40(%rsp), @XMM[3] + movdqu @XMM[6], 0x30($out) + pxor 0x50(%rsp), @XMM[7] + movdqu @XMM[3], 0x40($out) + movdqu @XMM[7], 0x50($out) + lea 0x60($out), $out + + movdqa 0x60(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_enc_done +.align 16 +.Lxts_enc_5: + pxor @XMM[8+3], @XMM[3] + lea 0x50($inp), $inp + pxor @XMM[8+4], @XMM[4] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_encrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[4] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[6] + movdqu @XMM[4], 0x20($out) + pxor 0x40(%rsp), @XMM[3] + movdqu @XMM[6], 0x30($out) + movdqu @XMM[3], 0x40($out) + lea 0x50($out), $out + + movdqa 0x50(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_enc_done +.align 16 +.Lxts_enc_4: + pxor @XMM[8+2], @XMM[2] + lea 0x40($inp), $inp + pxor @XMM[8+3], @XMM[3] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_encrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[4] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[6] + movdqu @XMM[4], 0x20($out) + movdqu @XMM[6], 0x30($out) + lea 0x40($out), $out + + movdqa 0x40(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_enc_done +.align 16 +.Lxts_enc_3: + pxor @XMM[8+1], @XMM[1] + lea 0x30($inp), $inp + pxor @XMM[8+2], @XMM[2] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_encrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[4] + movdqu @XMM[1], 0x10($out) + movdqu @XMM[4], 0x20($out) + lea 0x30($out), $out + + movdqa 0x30(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_enc_done +.align 16 +.Lxts_enc_2: + pxor @XMM[8+0], @XMM[0] + lea 0x20($inp), $inp + pxor @XMM[8+1], @XMM[1] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_encrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + lea 0x20($out), $out + + movdqa 0x20(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_enc_done +.align 16 +.Lxts_enc_1: + pxor @XMM[0], @XMM[8] + lea 0x10($inp), $inp + movdqa @XMM[8], 0x20(%rbp) + lea 0x20(%rbp), $arg1 + lea 0x20(%rbp), $arg2 + lea ($key), $arg3 + call asm_AES_encrypt # doesn't touch %xmm + pxor 0x20(%rbp), @XMM[0] # ^= tweak[] + #pxor @XMM[8], @XMM[0] + #lea 0x80(%rsp), %rax # pass key schedule + #mov %edx, %r10d # pass rounds + #call _bsaes_encrypt8 + #pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + movdqu @XMM[0], 0x00($out) # write output + lea 0x10($out), $out + + movdqa 0x10(%rsp), @XMM[7] # next iteration tweak + +.Lxts_enc_done: + and \$15, %ebx + jz .Lxts_enc_ret + mov $out, %rdx + +.Lxts_enc_steal: + movzb ($inp), %eax + movzb -16(%rdx), %ecx + lea 1($inp), $inp + mov %al, -16(%rdx) + mov %cl, 0(%rdx) + lea 1(%rdx), %rdx + sub \$1,%ebx + jnz .Lxts_enc_steal + + movdqu -16($out), @XMM[0] + lea 0x20(%rbp), $arg1 + pxor @XMM[7], @XMM[0] + lea 0x20(%rbp), $arg2 + movdqa @XMM[0], 0x20(%rbp) + lea ($key), $arg3 + call asm_AES_encrypt # doesn't touch %xmm + pxor 0x20(%rbp), @XMM[7] + movdqu @XMM[7], -16($out) + +.Lxts_enc_ret: + lea (%rsp), %rax + pxor %xmm0, %xmm0 +.Lxts_enc_bzero: # wipe key schedule [if any] + movdqa %xmm0, 0x00(%rax) + movdqa %xmm0, 0x10(%rax) + lea 0x20(%rax), %rax + cmp %rax, %rbp + ja .Lxts_enc_bzero + + lea (%rbp),%rsp # restore %rsp +___ +$code.=<<___ if ($win64); + movaps 0x40(%rbp), %xmm6 + movaps 0x50(%rbp), %xmm7 + movaps 0x60(%rbp), %xmm8 + movaps 0x70(%rbp), %xmm9 + movaps 0x80(%rbp), %xmm10 + movaps 0x90(%rbp), %xmm11 + movaps 0xa0(%rbp), %xmm12 + movaps 0xb0(%rbp), %xmm13 + movaps 0xc0(%rbp), %xmm14 + movaps 0xd0(%rbp), %xmm15 + lea 0xa0(%rbp), %rsp +___ +$code.=<<___; + mov 0x48(%rsp), %r15 + mov 0x50(%rsp), %r14 + mov 0x58(%rsp), %r13 + mov 0x60(%rsp), %r12 + mov 0x68(%rsp), %rbx + mov 0x70(%rsp), %rax + lea 0x78(%rsp), %rsp + mov %rax, %rbp +.Lxts_enc_epilogue: + ret +.size bsaes_xts_encrypt,.-bsaes_xts_encrypt + +.globl bsaes_xts_decrypt +.type bsaes_xts_decrypt,\@abi-omnipotent +.align 16 +bsaes_xts_decrypt: + mov %rsp, %rax +.Lxts_dec_prologue: + push %rbp + push %rbx + push %r12 + push %r13 + push %r14 + push %r15 + lea -0x48(%rsp), %rsp +___ +$code.=<<___ if ($win64); + mov 0xa0(%rsp),$arg5 # pull key2 + mov 0xa8(%rsp),$arg6 # pull ivp + lea -0xa0(%rsp), %rsp + movaps %xmm6, 0x40(%rsp) + movaps %xmm7, 0x50(%rsp) + movaps %xmm8, 0x60(%rsp) + movaps %xmm9, 0x70(%rsp) + movaps %xmm10, 0x80(%rsp) + movaps %xmm11, 0x90(%rsp) + movaps %xmm12, 0xa0(%rsp) + movaps %xmm13, 0xb0(%rsp) + movaps %xmm14, 0xc0(%rsp) + movaps %xmm15, 0xd0(%rsp) +.Lxts_dec_body: +___ +$code.=<<___; + mov %rsp, %rbp # backup %rsp + mov $arg1, $inp # backup arguments + mov $arg2, $out + mov $arg3, $len + mov $arg4, $key + + lea ($arg6), $arg1 + lea 0x20(%rbp), $arg2 + lea ($arg5), $arg3 + call asm_AES_encrypt # generate initial tweak + + mov 240($key), %eax # rounds + mov $len, %rbx # backup $len + + mov %eax, %edx # rounds + shl \$7, %rax # 128 bytes per inner round key + sub \$`128-32`, %rax # size of bit-sliced key schedule + sub %rax, %rsp + + mov %rsp, %rax # pass key schedule + mov $key, %rcx # pass key + mov %edx, %r10d # pass rounds + call _bsaes_key_convert + pxor (%rsp), %xmm7 # fix up round 0 key + movdqa %xmm6, (%rax) # save last round key + movdqa %xmm7, (%rsp) + + xor %eax, %eax # if ($len%16) len-=16; + and \$-16, $len + test \$15, %ebx + setnz %al + shl \$4, %rax + sub %rax, $len + + sub \$0x80, %rsp # place for tweak[8] + movdqa 0x20(%rbp), @XMM[7] # initial tweak + + pxor $twtmp, $twtmp + movdqa .Lxts_magic(%rip), $twmask + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + + sub \$0x80, $len + jc .Lxts_dec_short + jmp .Lxts_dec_loop + +.align 16 +.Lxts_dec_loop: +___ + for ($i=0;$i<7;$i++) { + $code.=<<___; + pshufd \$0x13, $twtmp, $twres + pxor $twtmp, $twtmp + movdqa @XMM[7], @XMM[$i] + movdqa @XMM[7], `0x10*$i`(%rsp)# save tweak[$i] + paddq @XMM[7], @XMM[7] # psllq 1,$tweak + pand $twmask, $twres # isolate carry and residue + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + pxor $twres, @XMM[7] +___ + $code.=<<___ if ($i>=1); + movdqu `0x10*($i-1)`($inp), @XMM[8+$i-1] +___ + $code.=<<___ if ($i>=2); + pxor @XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[] +___ + } +$code.=<<___; + movdqu 0x60($inp), @XMM[8+6] + pxor @XMM[8+5], @XMM[5] + movdqu 0x70($inp), @XMM[8+7] + lea 0x80($inp), $inp + movdqa @XMM[7], 0x70(%rsp) + pxor @XMM[8+6], @XMM[6] + lea 0x80(%rsp), %rax # pass key schedule + pxor @XMM[8+7], @XMM[7] + mov %edx, %r10d # pass rounds + + call _bsaes_decrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[6] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[4] + movdqu @XMM[6], 0x20($out) + pxor 0x40(%rsp), @XMM[2] + movdqu @XMM[4], 0x30($out) + pxor 0x50(%rsp), @XMM[7] + movdqu @XMM[2], 0x40($out) + pxor 0x60(%rsp), @XMM[3] + movdqu @XMM[7], 0x50($out) + pxor 0x70(%rsp), @XMM[5] + movdqu @XMM[3], 0x60($out) + movdqu @XMM[5], 0x70($out) + lea 0x80($out), $out + + movdqa 0x70(%rsp), @XMM[7] # prepare next iteration tweak + pxor $twtmp, $twtmp + movdqa .Lxts_magic(%rip), $twmask + pcmpgtd @XMM[7], $twtmp + pshufd \$0x13, $twtmp, $twres + pxor $twtmp, $twtmp + paddq @XMM[7], @XMM[7] # psllq 1,$tweak + pand $twmask, $twres # isolate carry and residue + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + pxor $twres, @XMM[7] + + sub \$0x80,$len + jnc .Lxts_dec_loop + +.Lxts_dec_short: + add \$0x80, $len + jz .Lxts_dec_done +___ + for ($i=0;$i<7;$i++) { + $code.=<<___; + pshufd \$0x13, $twtmp, $twres + pxor $twtmp, $twtmp + movdqa @XMM[7], @XMM[$i] + movdqa @XMM[7], `0x10*$i`(%rsp)# save tweak[$i] + paddq @XMM[7], @XMM[7] # psllq 1,$tweak + pand $twmask, $twres # isolate carry and residue + pcmpgtd @XMM[7], $twtmp # broadcast upper bits + pxor $twres, @XMM[7] +___ + $code.=<<___ if ($i>=1); + movdqu `0x10*($i-1)`($inp), @XMM[8+$i-1] + cmp \$`0x10*$i`,$len + je .Lxts_dec_$i +___ + $code.=<<___ if ($i>=2); + pxor @XMM[8+$i-2], @XMM[$i-2]# input[] ^ tweak[] +___ + } +$code.=<<___; + movdqu 0x60($inp), @XMM[8+6] + pxor @XMM[8+5], @XMM[5] + movdqa @XMM[7], 0x70(%rsp) + lea 0x70($inp), $inp + pxor @XMM[8+6], @XMM[6] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_decrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[6] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[4] + movdqu @XMM[6], 0x20($out) + pxor 0x40(%rsp), @XMM[2] + movdqu @XMM[4], 0x30($out) + pxor 0x50(%rsp), @XMM[7] + movdqu @XMM[2], 0x40($out) + pxor 0x60(%rsp), @XMM[3] + movdqu @XMM[7], 0x50($out) + movdqu @XMM[3], 0x60($out) + lea 0x70($out), $out + + movdqa 0x70(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_dec_done +.align 16 +.Lxts_dec_6: + pxor @XMM[8+4], @XMM[4] + lea 0x60($inp), $inp + pxor @XMM[8+5], @XMM[5] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_decrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[6] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[4] + movdqu @XMM[6], 0x20($out) + pxor 0x40(%rsp), @XMM[2] + movdqu @XMM[4], 0x30($out) + pxor 0x50(%rsp), @XMM[7] + movdqu @XMM[2], 0x40($out) + movdqu @XMM[7], 0x50($out) + lea 0x60($out), $out + + movdqa 0x60(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_dec_done +.align 16 +.Lxts_dec_5: + pxor @XMM[8+3], @XMM[3] + lea 0x50($inp), $inp + pxor @XMM[8+4], @XMM[4] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_decrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[6] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[4] + movdqu @XMM[6], 0x20($out) + pxor 0x40(%rsp), @XMM[2] + movdqu @XMM[4], 0x30($out) + movdqu @XMM[2], 0x40($out) + lea 0x50($out), $out + + movdqa 0x50(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_dec_done +.align 16 +.Lxts_dec_4: + pxor @XMM[8+2], @XMM[2] + lea 0x40($inp), $inp + pxor @XMM[8+3], @XMM[3] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_decrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[6] + movdqu @XMM[1], 0x10($out) + pxor 0x30(%rsp), @XMM[4] + movdqu @XMM[6], 0x20($out) + movdqu @XMM[4], 0x30($out) + lea 0x40($out), $out + + movdqa 0x40(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_dec_done +.align 16 +.Lxts_dec_3: + pxor @XMM[8+1], @XMM[1] + lea 0x30($inp), $inp + pxor @XMM[8+2], @XMM[2] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_decrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + pxor 0x20(%rsp), @XMM[6] + movdqu @XMM[1], 0x10($out) + movdqu @XMM[6], 0x20($out) + lea 0x30($out), $out + + movdqa 0x30(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_dec_done +.align 16 +.Lxts_dec_2: + pxor @XMM[8+0], @XMM[0] + lea 0x20($inp), $inp + pxor @XMM[8+1], @XMM[1] + lea 0x80(%rsp), %rax # pass key schedule + mov %edx, %r10d # pass rounds + + call _bsaes_decrypt8 + + pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + pxor 0x10(%rsp), @XMM[1] + movdqu @XMM[0], 0x00($out) # write output + movdqu @XMM[1], 0x10($out) + lea 0x20($out), $out + + movdqa 0x20(%rsp), @XMM[7] # next iteration tweak + jmp .Lxts_dec_done +.align 16 +.Lxts_dec_1: + pxor @XMM[0], @XMM[8] + lea 0x10($inp), $inp + movdqa @XMM[8], 0x20(%rbp) + lea 0x20(%rbp), $arg1 + lea 0x20(%rbp), $arg2 + lea ($key), $arg3 + call asm_AES_decrypt # doesn't touch %xmm + pxor 0x20(%rbp), @XMM[0] # ^= tweak[] + #pxor @XMM[8], @XMM[0] + #lea 0x80(%rsp), %rax # pass key schedule + #mov %edx, %r10d # pass rounds + #call _bsaes_decrypt8 + #pxor 0x00(%rsp), @XMM[0] # ^= tweak[] + movdqu @XMM[0], 0x00($out) # write output + lea 0x10($out), $out + + movdqa 0x10(%rsp), @XMM[7] # next iteration tweak + +.Lxts_dec_done: + and \$15, %ebx + jz .Lxts_dec_ret + + pxor $twtmp, $twtmp + movdqa .Lxts_magic(%rip), $twmask + pcmpgtd @XMM[7], $twtmp + pshufd \$0x13, $twtmp, $twres + movdqa @XMM[7], @XMM[6] + paddq @XMM[7], @XMM[7] # psllq 1,$tweak + pand $twmask, $twres # isolate carry and residue + movdqu ($inp), @XMM[0] + pxor $twres, @XMM[7] + + lea 0x20(%rbp), $arg1 + pxor @XMM[7], @XMM[0] + lea 0x20(%rbp), $arg2 + movdqa @XMM[0], 0x20(%rbp) + lea ($key), $arg3 + call asm_AES_decrypt # doesn't touch %xmm + pxor 0x20(%rbp), @XMM[7] + mov $out, %rdx + movdqu @XMM[7], ($out) + +.Lxts_dec_steal: + movzb 16($inp), %eax + movzb (%rdx), %ecx + lea 1($inp), $inp + mov %al, (%rdx) + mov %cl, 16(%rdx) + lea 1(%rdx), %rdx + sub \$1,%ebx + jnz .Lxts_dec_steal + + movdqu ($out), @XMM[0] + lea 0x20(%rbp), $arg1 + pxor @XMM[6], @XMM[0] + lea 0x20(%rbp), $arg2 + movdqa @XMM[0], 0x20(%rbp) + lea ($key), $arg3 + call asm_AES_decrypt # doesn't touch %xmm + pxor 0x20(%rbp), @XMM[6] + movdqu @XMM[6], ($out) + +.Lxts_dec_ret: + lea (%rsp), %rax + pxor %xmm0, %xmm0 +.Lxts_dec_bzero: # wipe key schedule [if any] + movdqa %xmm0, 0x00(%rax) + movdqa %xmm0, 0x10(%rax) + lea 0x20(%rax), %rax + cmp %rax, %rbp + ja .Lxts_dec_bzero + + lea (%rbp),%rsp # restore %rsp +___ +$code.=<<___ if ($win64); + movaps 0x40(%rbp), %xmm6 + movaps 0x50(%rbp), %xmm7 + movaps 0x60(%rbp), %xmm8 + movaps 0x70(%rbp), %xmm9 + movaps 0x80(%rbp), %xmm10 + movaps 0x90(%rbp), %xmm11 + movaps 0xa0(%rbp), %xmm12 + movaps 0xb0(%rbp), %xmm13 + movaps 0xc0(%rbp), %xmm14 + movaps 0xd0(%rbp), %xmm15 + lea 0xa0(%rbp), %rsp +___ +$code.=<<___; + mov 0x48(%rsp), %r15 + mov 0x50(%rsp), %r14 + mov 0x58(%rsp), %r13 + mov 0x60(%rsp), %r12 + mov 0x68(%rsp), %rbx + mov 0x70(%rsp), %rax + lea 0x78(%rsp), %rsp + mov %rax, %rbp +.Lxts_dec_epilogue: + ret +.size bsaes_xts_decrypt,.-bsaes_xts_decrypt +___ +} +$code.=<<___; +.type _bsaes_const,\@object +.align 64 +_bsaes_const: +.LM0ISR: # InvShiftRows constants + .quad 0x0a0e0206070b0f03, 0x0004080c0d010509 +.LISRM0: + .quad 0x01040b0e0205080f, 0x0306090c00070a0d +.LISR: + .quad 0x0504070602010003, 0x0f0e0d0c080b0a09 +.LBS0: # bit-slice constants + .quad 0x5555555555555555, 0x5555555555555555 +.LBS1: + .quad 0x3333333333333333, 0x3333333333333333 +.LBS2: + .quad 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f +.LSR: # shiftrows constants + .quad 0x0504070600030201, 0x0f0e0d0c0a09080b +.LSRM0: + .quad 0x0304090e00050a0f, 0x01060b0c0207080d +.LM0SR: + .quad 0x0a0e02060f03070b, 0x0004080c05090d01 +.LSWPUP: # byte-swap upper dword + .quad 0x0706050403020100, 0x0c0d0e0f0b0a0908 +.LSWPUPM0SR: + .quad 0x0a0d02060c03070b, 0x0004080f05090e01 +.LADD1: # counter increment constants + .quad 0x0000000000000000, 0x0000000100000000 +.LADD2: + .quad 0x0000000000000000, 0x0000000200000000 +.LADD3: + .quad 0x0000000000000000, 0x0000000300000000 +.LADD4: + .quad 0x0000000000000000, 0x0000000400000000 +.LADD5: + .quad 0x0000000000000000, 0x0000000500000000 +.LADD6: + .quad 0x0000000000000000, 0x0000000600000000 +.LADD7: + .quad 0x0000000000000000, 0x0000000700000000 +.LADD8: + .quad 0x0000000000000000, 0x0000000800000000 +.Lxts_magic: + .long 0x87,0,1,0 +.Lmasks: + .quad 0x0101010101010101, 0x0101010101010101 + .quad 0x0202020202020202, 0x0202020202020202 + .quad 0x0404040404040404, 0x0404040404040404 + .quad 0x0808080808080808, 0x0808080808080808 +.LM0: + .quad 0x02060a0e03070b0f, 0x0004080c0105090d +.L63: + .quad 0x6363636363636363, 0x6363636363636363 +.asciz "Bit-sliced AES for x86_64/SSSE3, Emilia Käsper, Peter Schwabe, Andy Polyakov" +.align 64 +.size _bsaes_const,.-_bsaes_const +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lin_prologue + + mov 160($context),%rax # pull context->Rbp + + lea 0x40(%rax),%rsi # %xmm save area + lea 512($context),%rdi # &context.Xmm6 + mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax) + .long 0xa548f3fc # cld; rep movsq + lea 0xa0(%rax),%rax # adjust stack pointer + + mov 0x70(%rax),%rbp + mov 0x68(%rax),%rbx + mov 0x60(%rax),%r12 + mov 0x58(%rax),%r13 + mov 0x50(%rax),%r14 + mov 0x48(%rax),%r15 + lea 0x78(%rax),%rax # adjust stack pointer + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lin_prologue: + mov %rax,152($context) # restore context->Rsp + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$`1232/8`,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size se_handler,.-se_handler + +.section .pdata +.align 4 +___ +$code.=<<___ if ($ecb); + .rva .Lecb_enc_prologue + .rva .Lecb_enc_epilogue + .rva .Lecb_enc_info + + .rva .Lecb_dec_prologue + .rva .Lecb_dec_epilogue + .rva .Lecb_dec_info +___ +$code.=<<___; + .rva .Lcbc_dec_prologue + .rva .Lcbc_dec_epilogue + .rva .Lcbc_dec_info + + .rva .Lctr_enc_prologue + .rva .Lctr_enc_epilogue + .rva .Lctr_enc_info + + .rva .Lxts_enc_prologue + .rva .Lxts_enc_epilogue + .rva .Lxts_enc_info + + .rva .Lxts_dec_prologue + .rva .Lxts_dec_epilogue + .rva .Lxts_dec_info + +.section .xdata +.align 8 +___ +$code.=<<___ if ($ecb); +.Lecb_enc_info: + .byte 9,0,0,0 + .rva se_handler + .rva .Lecb_enc_body,.Lecb_enc_epilogue # HandlerData[] +.Lecb_dec_info: + .byte 9,0,0,0 + .rva se_handler + .rva .Lecb_dec_body,.Lecb_dec_epilogue # HandlerData[] +___ +$code.=<<___; +.Lcbc_dec_info: + .byte 9,0,0,0 + .rva se_handler + .rva .Lcbc_dec_body,.Lcbc_dec_epilogue # HandlerData[] +.Lctr_enc_info: + .byte 9,0,0,0 + .rva se_handler + .rva .Lctr_enc_body,.Lctr_enc_epilogue # HandlerData[] +.Lxts_enc_info: + .byte 9,0,0,0 + .rva se_handler + .rva .Lxts_enc_body,.Lxts_enc_epilogue # HandlerData[] +.Lxts_dec_info: + .byte 9,0,0,0 + .rva se_handler + .rva .Lxts_dec_body,.Lxts_dec_epilogue # HandlerData[] +___ +} + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/vpaes-x86.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/vpaes-x86.pl new file mode 100644 index 00000000..2ba149c3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/vpaes-x86.pl @@ -0,0 +1,903 @@ +#!/usr/bin/env perl + +###################################################################### +## Constant-time SSSE3 AES core implementation. +## version 0.1 +## +## By Mike Hamburg (Stanford University), 2009 +## Public domain. +## +## For details see http://shiftleft.org/papers/vector_aes/ and +## http://crypto.stanford.edu/vpaes/. + +###################################################################### +# September 2011. +# +# Port vpaes-x86_64.pl as 32-bit "almost" drop-in replacement for +# aes-586.pl. "Almost" refers to the fact that AES_cbc_encrypt +# doesn't handle partial vectors (doesn't have to if called from +# EVP only). "Drop-in" implies that this module doesn't share key +# schedule structure with the original nor does it make assumption +# about its alignment... +# +# Performance summary. aes-586.pl column lists large-block CBC +# encrypt/decrypt/with-hyper-threading-off(*) results in cycles per +# byte processed with 128-bit key, and vpaes-x86.pl column - [also +# large-block CBC] encrypt/decrypt. +# +# aes-586.pl vpaes-x86.pl +# +# Core 2(**) 28.1/41.4/18.3 21.9/25.2(***) +# Nehalem 27.9/40.4/18.1 10.2/11.9 +# Atom 70.7/92.1/60.1 61.1/75.4(***) +# Silvermont 45.4/62.9/24.1 49.2/61.1(***) +# +# (*) "Hyper-threading" in the context refers rather to cache shared +# among multiple cores, than to specifically Intel HTT. As vast +# majority of contemporary cores share cache, slower code path +# is common place. In other words "with-hyper-threading-off" +# results are presented mostly for reference purposes. +# +# (**) "Core 2" refers to initial 65nm design, a.k.a. Conroe. +# +# (***) Less impressive improvement on Core 2 and Atom is due to slow +# pshufb, yet it's respectable +28%/64% improvement on Core 2 +# and +15% on Atom (as implied, over "hyper-threading-safe" +# code path). +# +# + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],"vpaes-x86.pl",$x86only = $ARGV[$#ARGV] eq "386"); + +$PREFIX="vpaes"; + +my ($round, $base, $magic, $key, $const, $inp, $out)= + ("eax", "ebx", "ecx", "edx","ebp", "esi","edi"); + +&static_label("_vpaes_consts"); +&static_label("_vpaes_schedule_low_round"); + +&set_label("_vpaes_consts",64); +$k_inv=-0x30; # inv, inva + &data_word(0x0D080180,0x0E05060F,0x0A0B0C02,0x04070309); + &data_word(0x0F0B0780,0x01040A06,0x02050809,0x030D0E0C); + +$k_s0F=-0x10; # s0F + &data_word(0x0F0F0F0F,0x0F0F0F0F,0x0F0F0F0F,0x0F0F0F0F); + +$k_ipt=0x00; # input transform (lo, hi) + &data_word(0x5A2A7000,0xC2B2E898,0x52227808,0xCABAE090); + &data_word(0x317C4D00,0x4C01307D,0xB0FDCC81,0xCD80B1FC); + +$k_sb1=0x20; # sb1u, sb1t + &data_word(0xCB503E00,0xB19BE18F,0x142AF544,0xA5DF7A6E); + &data_word(0xFAE22300,0x3618D415,0x0D2ED9EF,0x3BF7CCC1); +$k_sb2=0x40; # sb2u, sb2t + &data_word(0x0B712400,0xE27A93C6,0xBC982FCD,0x5EB7E955); + &data_word(0x0AE12900,0x69EB8840,0xAB82234A,0xC2A163C8); +$k_sbo=0x60; # sbou, sbot + &data_word(0x6FBDC700,0xD0D26D17,0xC502A878,0x15AABF7A); + &data_word(0x5FBB6A00,0xCFE474A5,0x412B35FA,0x8E1E90D1); + +$k_mc_forward=0x80; # mc_forward + &data_word(0x00030201,0x04070605,0x080B0A09,0x0C0F0E0D); + &data_word(0x04070605,0x080B0A09,0x0C0F0E0D,0x00030201); + &data_word(0x080B0A09,0x0C0F0E0D,0x00030201,0x04070605); + &data_word(0x0C0F0E0D,0x00030201,0x04070605,0x080B0A09); + +$k_mc_backward=0xc0; # mc_backward + &data_word(0x02010003,0x06050407,0x0A09080B,0x0E0D0C0F); + &data_word(0x0E0D0C0F,0x02010003,0x06050407,0x0A09080B); + &data_word(0x0A09080B,0x0E0D0C0F,0x02010003,0x06050407); + &data_word(0x06050407,0x0A09080B,0x0E0D0C0F,0x02010003); + +$k_sr=0x100; # sr + &data_word(0x03020100,0x07060504,0x0B0A0908,0x0F0E0D0C); + &data_word(0x0F0A0500,0x030E0904,0x07020D08,0x0B06010C); + &data_word(0x0B020900,0x0F060D04,0x030A0108,0x070E050C); + &data_word(0x070A0D00,0x0B0E0104,0x0F020508,0x0306090C); + +$k_rcon=0x140; # rcon + &data_word(0xAF9DEEB6,0x1F8391B9,0x4D7C7D81,0x702A9808); + +$k_s63=0x150; # s63: all equal to 0x63 transformed + &data_word(0x5B5B5B5B,0x5B5B5B5B,0x5B5B5B5B,0x5B5B5B5B); + +$k_opt=0x160; # output transform + &data_word(0xD6B66000,0xFF9F4929,0xDEBE6808,0xF7974121); + &data_word(0x50BCEC00,0x01EDBD51,0xB05C0CE0,0xE10D5DB1); + +$k_deskew=0x180; # deskew tables: inverts the sbox's "skew" + &data_word(0x47A4E300,0x07E4A340,0x5DBEF91A,0x1DFEB95A); + &data_word(0x83EA6900,0x5F36B5DC,0xF49D1E77,0x2841C2AB); +## +## Decryption stuff +## Key schedule constants +## +$k_dksd=0x1a0; # decryption key schedule: invskew x*D + &data_word(0xA3E44700,0xFEB91A5D,0x5A1DBEF9,0x0740E3A4); + &data_word(0xB5368300,0x41C277F4,0xAB289D1E,0x5FDC69EA); +$k_dksb=0x1c0; # decryption key schedule: invskew x*B + &data_word(0x8550D500,0x9A4FCA1F,0x1CC94C99,0x03D65386); + &data_word(0xB6FC4A00,0x115BEDA7,0x7E3482C8,0xD993256F); +$k_dkse=0x1e0; # decryption key schedule: invskew x*E + 0x63 + &data_word(0x1FC9D600,0xD5031CCA,0x994F5086,0x53859A4C); + &data_word(0x4FDC7BE8,0xA2319605,0x20B31487,0xCD5EF96A); +$k_dks9=0x200; # decryption key schedule: invskew x*9 + &data_word(0x7ED9A700,0xB6116FC8,0x82255BFC,0x4AED9334); + &data_word(0x27143300,0x45765162,0xE9DAFDCE,0x8BB89FAC); + +## +## Decryption stuff +## Round function constants +## +$k_dipt=0x220; # decryption input transform + &data_word(0x0B545F00,0x0F505B04,0x114E451A,0x154A411E); + &data_word(0x60056500,0x86E383E6,0xF491F194,0x12771772); + +$k_dsb9=0x240; # decryption sbox output *9*u, *9*t + &data_word(0x9A86D600,0x851C0353,0x4F994CC9,0xCAD51F50); + &data_word(0xECD74900,0xC03B1789,0xB2FBA565,0x725E2C9E); +$k_dsbd=0x260; # decryption sbox output *D*u, *D*t + &data_word(0xE6B1A200,0x7D57CCDF,0x882A4439,0xF56E9B13); + &data_word(0x24C6CB00,0x3CE2FAF7,0x15DEEFD3,0x2931180D); +$k_dsbb=0x280; # decryption sbox output *B*u, *B*t + &data_word(0x96B44200,0xD0226492,0xB0F2D404,0x602646F6); + &data_word(0xCD596700,0xC19498A6,0x3255AA6B,0xF3FF0C3E); +$k_dsbe=0x2a0; # decryption sbox output *E*u, *E*t + &data_word(0x26D4D000,0x46F29296,0x64B4F6B0,0x22426004); + &data_word(0xFFAAC100,0x0C55A6CD,0x98593E32,0x9467F36B); +$k_dsbo=0x2c0; # decryption sbox final output + &data_word(0x7EF94000,0x1387EA53,0xD4943E2D,0xC7AA6DB9); + &data_word(0x93441D00,0x12D7560F,0xD8C58E9C,0xCA4B8159); +&asciz ("Vector Permutation AES for x86/SSSE3, Mike Hamburg (Stanford University)"); +&align (64); + +&function_begin_B("_vpaes_preheat"); + &add ($const,&DWP(0,"esp")); + &movdqa ("xmm7",&QWP($k_inv,$const)); + &movdqa ("xmm6",&QWP($k_s0F,$const)); + &ret (); +&function_end_B("_vpaes_preheat"); + +## +## _aes_encrypt_core +## +## AES-encrypt %xmm0. +## +## Inputs: +## %xmm0 = input +## %xmm6-%xmm7 as in _vpaes_preheat +## (%edx) = scheduled keys +## +## Output in %xmm0 +## Clobbers %xmm1-%xmm5, %eax, %ebx, %ecx, %edx +## +## +&function_begin_B("_vpaes_encrypt_core"); + &mov ($magic,16); + &mov ($round,&DWP(240,$key)); + &movdqa ("xmm1","xmm6") + &movdqa ("xmm2",&QWP($k_ipt,$const)); + &pandn ("xmm1","xmm0"); + &pand ("xmm0","xmm6"); + &movdqu ("xmm5",&QWP(0,$key)); + &pshufb ("xmm2","xmm0"); + &movdqa ("xmm0",&QWP($k_ipt+16,$const)); + &pxor ("xmm2","xmm5"); + &psrld ("xmm1",4); + &add ($key,16); + &pshufb ("xmm0","xmm1"); + &lea ($base,&DWP($k_mc_backward,$const)); + &pxor ("xmm0","xmm2"); + &jmp (&label("enc_entry")); + + +&set_label("enc_loop",16); + # middle of middle round + &movdqa ("xmm4",&QWP($k_sb1,$const)); # 4 : sb1u + &movdqa ("xmm0",&QWP($k_sb1+16,$const));# 0 : sb1t + &pshufb ("xmm4","xmm2"); # 4 = sb1u + &pshufb ("xmm0","xmm3"); # 0 = sb1t + &pxor ("xmm4","xmm5"); # 4 = sb1u + k + &movdqa ("xmm5",&QWP($k_sb2,$const)); # 4 : sb2u + &pxor ("xmm0","xmm4"); # 0 = A + &movdqa ("xmm1",&QWP(-0x40,$base,$magic));# .Lk_mc_forward[] + &pshufb ("xmm5","xmm2"); # 4 = sb2u + &movdqa ("xmm2",&QWP($k_sb2+16,$const));# 2 : sb2t + &movdqa ("xmm4",&QWP(0,$base,$magic)); # .Lk_mc_backward[] + &pshufb ("xmm2","xmm3"); # 2 = sb2t + &movdqa ("xmm3","xmm0"); # 3 = A + &pxor ("xmm2","xmm5"); # 2 = 2A + &pshufb ("xmm0","xmm1"); # 0 = B + &add ($key,16); # next key + &pxor ("xmm0","xmm2"); # 0 = 2A+B + &pshufb ("xmm3","xmm4"); # 3 = D + &add ($magic,16); # next mc + &pxor ("xmm3","xmm0"); # 3 = 2A+B+D + &pshufb ("xmm0","xmm1"); # 0 = 2B+C + &and ($magic,0x30); # ... mod 4 + &sub ($round,1); # nr-- + &pxor ("xmm0","xmm3"); # 0 = 2A+3B+C+D + +&set_label("enc_entry"); + # top of round + &movdqa ("xmm1","xmm6"); # 1 : i + &movdqa ("xmm5",&QWP($k_inv+16,$const));# 2 : a/k + &pandn ("xmm1","xmm0"); # 1 = i<<4 + &psrld ("xmm1",4); # 1 = i + &pand ("xmm0","xmm6"); # 0 = k + &pshufb ("xmm5","xmm0"); # 2 = a/k + &movdqa ("xmm3","xmm7"); # 3 : 1/i + &pxor ("xmm0","xmm1"); # 0 = j + &pshufb ("xmm3","xmm1"); # 3 = 1/i + &movdqa ("xmm4","xmm7"); # 4 : 1/j + &pxor ("xmm3","xmm5"); # 3 = iak = 1/i + a/k + &pshufb ("xmm4","xmm0"); # 4 = 1/j + &movdqa ("xmm2","xmm7"); # 2 : 1/iak + &pxor ("xmm4","xmm5"); # 4 = jak = 1/j + a/k + &pshufb ("xmm2","xmm3"); # 2 = 1/iak + &movdqa ("xmm3","xmm7"); # 3 : 1/jak + &pxor ("xmm2","xmm0"); # 2 = io + &pshufb ("xmm3","xmm4"); # 3 = 1/jak + &movdqu ("xmm5",&QWP(0,$key)); + &pxor ("xmm3","xmm1"); # 3 = jo + &jnz (&label("enc_loop")); + + # middle of last round + &movdqa ("xmm4",&QWP($k_sbo,$const)); # 3 : sbou .Lk_sbo + &movdqa ("xmm0",&QWP($k_sbo+16,$const));# 3 : sbot .Lk_sbo+16 + &pshufb ("xmm4","xmm2"); # 4 = sbou + &pxor ("xmm4","xmm5"); # 4 = sb1u + k + &pshufb ("xmm0","xmm3"); # 0 = sb1t + &movdqa ("xmm1",&QWP(0x40,$base,$magic));# .Lk_sr[] + &pxor ("xmm0","xmm4"); # 0 = A + &pshufb ("xmm0","xmm1"); + &ret (); +&function_end_B("_vpaes_encrypt_core"); + +## +## Decryption core +## +## Same API as encryption core. +## +&function_begin_B("_vpaes_decrypt_core"); + &lea ($base,&DWP($k_dsbd,$const)); + &mov ($round,&DWP(240,$key)); + &movdqa ("xmm1","xmm6"); + &movdqa ("xmm2",&QWP($k_dipt-$k_dsbd,$base)); + &pandn ("xmm1","xmm0"); + &mov ($magic,$round); + &psrld ("xmm1",4) + &movdqu ("xmm5",&QWP(0,$key)); + &shl ($magic,4); + &pand ("xmm0","xmm6"); + &pshufb ("xmm2","xmm0"); + &movdqa ("xmm0",&QWP($k_dipt-$k_dsbd+16,$base)); + &xor ($magic,0x30); + &pshufb ("xmm0","xmm1"); + &and ($magic,0x30); + &pxor ("xmm2","xmm5"); + &movdqa ("xmm5",&QWP($k_mc_forward+48,$const)); + &pxor ("xmm0","xmm2"); + &add ($key,16); + &lea ($magic,&DWP($k_sr-$k_dsbd,$base,$magic)); + &jmp (&label("dec_entry")); + +&set_label("dec_loop",16); +## +## Inverse mix columns +## + &movdqa ("xmm4",&QWP(-0x20,$base)); # 4 : sb9u + &movdqa ("xmm1",&QWP(-0x10,$base)); # 0 : sb9t + &pshufb ("xmm4","xmm2"); # 4 = sb9u + &pshufb ("xmm1","xmm3"); # 0 = sb9t + &pxor ("xmm0","xmm4"); + &movdqa ("xmm4",&QWP(0,$base)); # 4 : sbdu + &pxor ("xmm0","xmm1"); # 0 = ch + &movdqa ("xmm1",&QWP(0x10,$base)); # 0 : sbdt + + &pshufb ("xmm4","xmm2"); # 4 = sbdu + &pshufb ("xmm0","xmm5"); # MC ch + &pshufb ("xmm1","xmm3"); # 0 = sbdt + &pxor ("xmm0","xmm4"); # 4 = ch + &movdqa ("xmm4",&QWP(0x20,$base)); # 4 : sbbu + &pxor ("xmm0","xmm1"); # 0 = ch + &movdqa ("xmm1",&QWP(0x30,$base)); # 0 : sbbt + + &pshufb ("xmm4","xmm2"); # 4 = sbbu + &pshufb ("xmm0","xmm5"); # MC ch + &pshufb ("xmm1","xmm3"); # 0 = sbbt + &pxor ("xmm0","xmm4"); # 4 = ch + &movdqa ("xmm4",&QWP(0x40,$base)); # 4 : sbeu + &pxor ("xmm0","xmm1"); # 0 = ch + &movdqa ("xmm1",&QWP(0x50,$base)); # 0 : sbet + + &pshufb ("xmm4","xmm2"); # 4 = sbeu + &pshufb ("xmm0","xmm5"); # MC ch + &pshufb ("xmm1","xmm3"); # 0 = sbet + &pxor ("xmm0","xmm4"); # 4 = ch + &add ($key,16); # next round key + &palignr("xmm5","xmm5",12); + &pxor ("xmm0","xmm1"); # 0 = ch + &sub ($round,1); # nr-- + +&set_label("dec_entry"); + # top of round + &movdqa ("xmm1","xmm6"); # 1 : i + &movdqa ("xmm2",&QWP($k_inv+16,$const));# 2 : a/k + &pandn ("xmm1","xmm0"); # 1 = i<<4 + &pand ("xmm0","xmm6"); # 0 = k + &psrld ("xmm1",4); # 1 = i + &pshufb ("xmm2","xmm0"); # 2 = a/k + &movdqa ("xmm3","xmm7"); # 3 : 1/i + &pxor ("xmm0","xmm1"); # 0 = j + &pshufb ("xmm3","xmm1"); # 3 = 1/i + &movdqa ("xmm4","xmm7"); # 4 : 1/j + &pxor ("xmm3","xmm2"); # 3 = iak = 1/i + a/k + &pshufb ("xmm4","xmm0"); # 4 = 1/j + &pxor ("xmm4","xmm2"); # 4 = jak = 1/j + a/k + &movdqa ("xmm2","xmm7"); # 2 : 1/iak + &pshufb ("xmm2","xmm3"); # 2 = 1/iak + &movdqa ("xmm3","xmm7"); # 3 : 1/jak + &pxor ("xmm2","xmm0"); # 2 = io + &pshufb ("xmm3","xmm4"); # 3 = 1/jak + &movdqu ("xmm0",&QWP(0,$key)); + &pxor ("xmm3","xmm1"); # 3 = jo + &jnz (&label("dec_loop")); + + # middle of last round + &movdqa ("xmm4",&QWP(0x60,$base)); # 3 : sbou + &pshufb ("xmm4","xmm2"); # 4 = sbou + &pxor ("xmm4","xmm0"); # 4 = sb1u + k + &movdqa ("xmm0",&QWP(0x70,$base)); # 0 : sbot + &movdqa ("xmm2",&QWP(0,$magic)); + &pshufb ("xmm0","xmm3"); # 0 = sb1t + &pxor ("xmm0","xmm4"); # 0 = A + &pshufb ("xmm0","xmm2"); + &ret (); +&function_end_B("_vpaes_decrypt_core"); + +######################################################## +## ## +## AES key schedule ## +## ## +######################################################## +&function_begin_B("_vpaes_schedule_core"); + &add ($const,&DWP(0,"esp")); + &movdqu ("xmm0",&QWP(0,$inp)); # load key (unaligned) + &movdqa ("xmm2",&QWP($k_rcon,$const)); # load rcon + + # input transform + &movdqa ("xmm3","xmm0"); + &lea ($base,&DWP($k_ipt,$const)); + &movdqa (&QWP(4,"esp"),"xmm2"); # xmm8 + &call ("_vpaes_schedule_transform"); + &movdqa ("xmm7","xmm0"); + + &test ($out,$out); + &jnz (&label("schedule_am_decrypting")); + + # encrypting, output zeroth round key after transform + &movdqu (&QWP(0,$key),"xmm0"); + &jmp (&label("schedule_go")); + +&set_label("schedule_am_decrypting"); + # decrypting, output zeroth round key after shiftrows + &movdqa ("xmm1",&QWP($k_sr,$const,$magic)); + &pshufb ("xmm3","xmm1"); + &movdqu (&QWP(0,$key),"xmm3"); + &xor ($magic,0x30); + +&set_label("schedule_go"); + &cmp ($round,192); + &ja (&label("schedule_256")); + &je (&label("schedule_192")); + # 128: fall though + +## +## .schedule_128 +## +## 128-bit specific part of key schedule. +## +## This schedule is really simple, because all its parts +## are accomplished by the subroutines. +## +&set_label("schedule_128"); + &mov ($round,10); + +&set_label("loop_schedule_128"); + &call ("_vpaes_schedule_round"); + &dec ($round); + &jz (&label("schedule_mangle_last")); + &call ("_vpaes_schedule_mangle"); # write output + &jmp (&label("loop_schedule_128")); + +## +## .aes_schedule_192 +## +## 192-bit specific part of key schedule. +## +## The main body of this schedule is the same as the 128-bit +## schedule, but with more smearing. The long, high side is +## stored in %xmm7 as before, and the short, low side is in +## the high bits of %xmm6. +## +## This schedule is somewhat nastier, however, because each +## round produces 192 bits of key material, or 1.5 round keys. +## Therefore, on each cycle we do 2 rounds and produce 3 round +## keys. +## +&set_label("schedule_192",16); + &movdqu ("xmm0",&QWP(8,$inp)); # load key part 2 (very unaligned) + &call ("_vpaes_schedule_transform"); # input transform + &movdqa ("xmm6","xmm0"); # save short part + &pxor ("xmm4","xmm4"); # clear 4 + &movhlps("xmm6","xmm4"); # clobber low side with zeros + &mov ($round,4); + +&set_label("loop_schedule_192"); + &call ("_vpaes_schedule_round"); + &palignr("xmm0","xmm6",8); + &call ("_vpaes_schedule_mangle"); # save key n + &call ("_vpaes_schedule_192_smear"); + &call ("_vpaes_schedule_mangle"); # save key n+1 + &call ("_vpaes_schedule_round"); + &dec ($round); + &jz (&label("schedule_mangle_last")); + &call ("_vpaes_schedule_mangle"); # save key n+2 + &call ("_vpaes_schedule_192_smear"); + &jmp (&label("loop_schedule_192")); + +## +## .aes_schedule_256 +## +## 256-bit specific part of key schedule. +## +## The structure here is very similar to the 128-bit +## schedule, but with an additional "low side" in +## %xmm6. The low side's rounds are the same as the +## high side's, except no rcon and no rotation. +## +&set_label("schedule_256",16); + &movdqu ("xmm0",&QWP(16,$inp)); # load key part 2 (unaligned) + &call ("_vpaes_schedule_transform"); # input transform + &mov ($round,7); + +&set_label("loop_schedule_256"); + &call ("_vpaes_schedule_mangle"); # output low result + &movdqa ("xmm6","xmm0"); # save cur_lo in xmm6 + + # high round + &call ("_vpaes_schedule_round"); + &dec ($round); + &jz (&label("schedule_mangle_last")); + &call ("_vpaes_schedule_mangle"); + + # low round. swap xmm7 and xmm6 + &pshufd ("xmm0","xmm0",0xFF); + &movdqa (&QWP(20,"esp"),"xmm7"); + &movdqa ("xmm7","xmm6"); + &call ("_vpaes_schedule_low_round"); + &movdqa ("xmm7",&QWP(20,"esp")); + + &jmp (&label("loop_schedule_256")); + +## +## .aes_schedule_mangle_last +## +## Mangler for last round of key schedule +## Mangles %xmm0 +## when encrypting, outputs out(%xmm0) ^ 63 +## when decrypting, outputs unskew(%xmm0) +## +## Always called right before return... jumps to cleanup and exits +## +&set_label("schedule_mangle_last",16); + # schedule last round key from xmm0 + &lea ($base,&DWP($k_deskew,$const)); + &test ($out,$out); + &jnz (&label("schedule_mangle_last_dec")); + + # encrypting + &movdqa ("xmm1",&QWP($k_sr,$const,$magic)); + &pshufb ("xmm0","xmm1"); # output permute + &lea ($base,&DWP($k_opt,$const)); # prepare to output transform + &add ($key,32); + +&set_label("schedule_mangle_last_dec"); + &add ($key,-16); + &pxor ("xmm0",&QWP($k_s63,$const)); + &call ("_vpaes_schedule_transform"); # output transform + &movdqu (&QWP(0,$key),"xmm0"); # save last key + + # cleanup + &pxor ("xmm0","xmm0"); + &pxor ("xmm1","xmm1"); + &pxor ("xmm2","xmm2"); + &pxor ("xmm3","xmm3"); + &pxor ("xmm4","xmm4"); + &pxor ("xmm5","xmm5"); + &pxor ("xmm6","xmm6"); + &pxor ("xmm7","xmm7"); + &ret (); +&function_end_B("_vpaes_schedule_core"); + +## +## .aes_schedule_192_smear +## +## Smear the short, low side in the 192-bit key schedule. +## +## Inputs: +## %xmm7: high side, b a x y +## %xmm6: low side, d c 0 0 +## %xmm13: 0 +## +## Outputs: +## %xmm6: b+c+d b+c 0 0 +## %xmm0: b+c+d b+c b a +## +&function_begin_B("_vpaes_schedule_192_smear"); + &pshufd ("xmm1","xmm6",0x80); # d c 0 0 -> c 0 0 0 + &pshufd ("xmm0","xmm7",0xFE); # b a _ _ -> b b b a + &pxor ("xmm6","xmm1"); # -> c+d c 0 0 + &pxor ("xmm1","xmm1"); + &pxor ("xmm6","xmm0"); # -> b+c+d b+c b a + &movdqa ("xmm0","xmm6"); + &movhlps("xmm6","xmm1"); # clobber low side with zeros + &ret (); +&function_end_B("_vpaes_schedule_192_smear"); + +## +## .aes_schedule_round +## +## Runs one main round of the key schedule on %xmm0, %xmm7 +## +## Specifically, runs subbytes on the high dword of %xmm0 +## then rotates it by one byte and xors into the low dword of +## %xmm7. +## +## Adds rcon from low byte of %xmm8, then rotates %xmm8 for +## next rcon. +## +## Smears the dwords of %xmm7 by xoring the low into the +## second low, result into third, result into highest. +## +## Returns results in %xmm7 = %xmm0. +## Clobbers %xmm1-%xmm5. +## +&function_begin_B("_vpaes_schedule_round"); + # extract rcon from xmm8 + &movdqa ("xmm2",&QWP(8,"esp")); # xmm8 + &pxor ("xmm1","xmm1"); + &palignr("xmm1","xmm2",15); + &palignr("xmm2","xmm2",15); + &pxor ("xmm7","xmm1"); + + # rotate + &pshufd ("xmm0","xmm0",0xFF); + &palignr("xmm0","xmm0",1); + + # fall through... + &movdqa (&QWP(8,"esp"),"xmm2"); # xmm8 + + # low round: same as high round, but no rotation and no rcon. +&set_label("_vpaes_schedule_low_round"); + # smear xmm7 + &movdqa ("xmm1","xmm7"); + &pslldq ("xmm7",4); + &pxor ("xmm7","xmm1"); + &movdqa ("xmm1","xmm7"); + &pslldq ("xmm7",8); + &pxor ("xmm7","xmm1"); + &pxor ("xmm7",&QWP($k_s63,$const)); + + # subbyte + &movdqa ("xmm4",&QWP($k_s0F,$const)); + &movdqa ("xmm5",&QWP($k_inv,$const)); # 4 : 1/j + &movdqa ("xmm1","xmm4"); + &pandn ("xmm1","xmm0"); + &psrld ("xmm1",4); # 1 = i + &pand ("xmm0","xmm4"); # 0 = k + &movdqa ("xmm2",&QWP($k_inv+16,$const));# 2 : a/k + &pshufb ("xmm2","xmm0"); # 2 = a/k + &pxor ("xmm0","xmm1"); # 0 = j + &movdqa ("xmm3","xmm5"); # 3 : 1/i + &pshufb ("xmm3","xmm1"); # 3 = 1/i + &pxor ("xmm3","xmm2"); # 3 = iak = 1/i + a/k + &movdqa ("xmm4","xmm5"); # 4 : 1/j + &pshufb ("xmm4","xmm0"); # 4 = 1/j + &pxor ("xmm4","xmm2"); # 4 = jak = 1/j + a/k + &movdqa ("xmm2","xmm5"); # 2 : 1/iak + &pshufb ("xmm2","xmm3"); # 2 = 1/iak + &pxor ("xmm2","xmm0"); # 2 = io + &movdqa ("xmm3","xmm5"); # 3 : 1/jak + &pshufb ("xmm3","xmm4"); # 3 = 1/jak + &pxor ("xmm3","xmm1"); # 3 = jo + &movdqa ("xmm4",&QWP($k_sb1,$const)); # 4 : sbou + &pshufb ("xmm4","xmm2"); # 4 = sbou + &movdqa ("xmm0",&QWP($k_sb1+16,$const));# 0 : sbot + &pshufb ("xmm0","xmm3"); # 0 = sb1t + &pxor ("xmm0","xmm4"); # 0 = sbox output + + # add in smeared stuff + &pxor ("xmm0","xmm7"); + &movdqa ("xmm7","xmm0"); + &ret (); +&function_end_B("_vpaes_schedule_round"); + +## +## .aes_schedule_transform +## +## Linear-transform %xmm0 according to tables at (%ebx) +## +## Output in %xmm0 +## Clobbers %xmm1, %xmm2 +## +&function_begin_B("_vpaes_schedule_transform"); + &movdqa ("xmm2",&QWP($k_s0F,$const)); + &movdqa ("xmm1","xmm2"); + &pandn ("xmm1","xmm0"); + &psrld ("xmm1",4); + &pand ("xmm0","xmm2"); + &movdqa ("xmm2",&QWP(0,$base)); + &pshufb ("xmm2","xmm0"); + &movdqa ("xmm0",&QWP(16,$base)); + &pshufb ("xmm0","xmm1"); + &pxor ("xmm0","xmm2"); + &ret (); +&function_end_B("_vpaes_schedule_transform"); + +## +## .aes_schedule_mangle +## +## Mangle xmm0 from (basis-transformed) standard version +## to our version. +## +## On encrypt, +## xor with 0x63 +## multiply by circulant 0,1,1,1 +## apply shiftrows transform +## +## On decrypt, +## xor with 0x63 +## multiply by "inverse mixcolumns" circulant E,B,D,9 +## deskew +## apply shiftrows transform +## +## +## Writes out to (%edx), and increments or decrements it +## Keeps track of round number mod 4 in %ecx +## Preserves xmm0 +## Clobbers xmm1-xmm5 +## +&function_begin_B("_vpaes_schedule_mangle"); + &movdqa ("xmm4","xmm0"); # save xmm0 for later + &movdqa ("xmm5",&QWP($k_mc_forward,$const)); + &test ($out,$out); + &jnz (&label("schedule_mangle_dec")); + + # encrypting + &add ($key,16); + &pxor ("xmm4",&QWP($k_s63,$const)); + &pshufb ("xmm4","xmm5"); + &movdqa ("xmm3","xmm4"); + &pshufb ("xmm4","xmm5"); + &pxor ("xmm3","xmm4"); + &pshufb ("xmm4","xmm5"); + &pxor ("xmm3","xmm4"); + + &jmp (&label("schedule_mangle_both")); + +&set_label("schedule_mangle_dec",16); + # inverse mix columns + &movdqa ("xmm2",&QWP($k_s0F,$const)); + &lea ($inp,&DWP($k_dksd,$const)); + &movdqa ("xmm1","xmm2"); + &pandn ("xmm1","xmm4"); + &psrld ("xmm1",4); # 1 = hi + &pand ("xmm4","xmm2"); # 4 = lo + + &movdqa ("xmm2",&QWP(0,$inp)); + &pshufb ("xmm2","xmm4"); + &movdqa ("xmm3",&QWP(0x10,$inp)); + &pshufb ("xmm3","xmm1"); + &pxor ("xmm3","xmm2"); + &pshufb ("xmm3","xmm5"); + + &movdqa ("xmm2",&QWP(0x20,$inp)); + &pshufb ("xmm2","xmm4"); + &pxor ("xmm2","xmm3"); + &movdqa ("xmm3",&QWP(0x30,$inp)); + &pshufb ("xmm3","xmm1"); + &pxor ("xmm3","xmm2"); + &pshufb ("xmm3","xmm5"); + + &movdqa ("xmm2",&QWP(0x40,$inp)); + &pshufb ("xmm2","xmm4"); + &pxor ("xmm2","xmm3"); + &movdqa ("xmm3",&QWP(0x50,$inp)); + &pshufb ("xmm3","xmm1"); + &pxor ("xmm3","xmm2"); + &pshufb ("xmm3","xmm5"); + + &movdqa ("xmm2",&QWP(0x60,$inp)); + &pshufb ("xmm2","xmm4"); + &pxor ("xmm2","xmm3"); + &movdqa ("xmm3",&QWP(0x70,$inp)); + &pshufb ("xmm3","xmm1"); + &pxor ("xmm3","xmm2"); + + &add ($key,-16); + +&set_label("schedule_mangle_both"); + &movdqa ("xmm1",&QWP($k_sr,$const,$magic)); + &pshufb ("xmm3","xmm1"); + &add ($magic,-16); + &and ($magic,0x30); + &movdqu (&QWP(0,$key),"xmm3"); + &ret (); +&function_end_B("_vpaes_schedule_mangle"); + +# +# Interface to OpenSSL +# +&function_begin("${PREFIX}_set_encrypt_key"); + &mov ($inp,&wparam(0)); # inp + &lea ($base,&DWP(-56,"esp")); + &mov ($round,&wparam(1)); # bits + &and ($base,-16); + &mov ($key,&wparam(2)); # key + &xchg ($base,"esp"); # alloca + &mov (&DWP(48,"esp"),$base); + + &mov ($base,$round); + &shr ($base,5); + &add ($base,5); + &mov (&DWP(240,$key),$base); # AES_KEY->rounds = nbits/32+5; + &mov ($magic,0x30); + &mov ($out,0); + + &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); + &call ("_vpaes_schedule_core"); +&set_label("pic_point"); + + &mov ("esp",&DWP(48,"esp")); + &xor ("eax","eax"); +&function_end("${PREFIX}_set_encrypt_key"); + +&function_begin("${PREFIX}_set_decrypt_key"); + &mov ($inp,&wparam(0)); # inp + &lea ($base,&DWP(-56,"esp")); + &mov ($round,&wparam(1)); # bits + &and ($base,-16); + &mov ($key,&wparam(2)); # key + &xchg ($base,"esp"); # alloca + &mov (&DWP(48,"esp"),$base); + + &mov ($base,$round); + &shr ($base,5); + &add ($base,5); + &mov (&DWP(240,$key),$base); # AES_KEY->rounds = nbits/32+5; + &shl ($base,4); + &lea ($key,&DWP(16,$key,$base)); + + &mov ($out,1); + &mov ($magic,$round); + &shr ($magic,1); + &and ($magic,32); + &xor ($magic,32); # nbist==192?0:32; + + &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); + &call ("_vpaes_schedule_core"); +&set_label("pic_point"); + + &mov ("esp",&DWP(48,"esp")); + &xor ("eax","eax"); +&function_end("${PREFIX}_set_decrypt_key"); + +&function_begin("${PREFIX}_encrypt"); + &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); + &call ("_vpaes_preheat"); +&set_label("pic_point"); + &mov ($inp,&wparam(0)); # inp + &lea ($base,&DWP(-56,"esp")); + &mov ($out,&wparam(1)); # out + &and ($base,-16); + &mov ($key,&wparam(2)); # key + &xchg ($base,"esp"); # alloca + &mov (&DWP(48,"esp"),$base); + + &movdqu ("xmm0",&QWP(0,$inp)); + &call ("_vpaes_encrypt_core"); + &movdqu (&QWP(0,$out),"xmm0"); + + &mov ("esp",&DWP(48,"esp")); +&function_end("${PREFIX}_encrypt"); + +&function_begin("${PREFIX}_decrypt"); + &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); + &call ("_vpaes_preheat"); +&set_label("pic_point"); + &mov ($inp,&wparam(0)); # inp + &lea ($base,&DWP(-56,"esp")); + &mov ($out,&wparam(1)); # out + &and ($base,-16); + &mov ($key,&wparam(2)); # key + &xchg ($base,"esp"); # alloca + &mov (&DWP(48,"esp"),$base); + + &movdqu ("xmm0",&QWP(0,$inp)); + &call ("_vpaes_decrypt_core"); + &movdqu (&QWP(0,$out),"xmm0"); + + &mov ("esp",&DWP(48,"esp")); +&function_end("${PREFIX}_decrypt"); + +&function_begin("${PREFIX}_cbc_encrypt"); + &mov ($inp,&wparam(0)); # inp + &mov ($out,&wparam(1)); # out + &mov ($round,&wparam(2)); # len + &mov ($key,&wparam(3)); # key + &sub ($round,16); + &jc (&label("cbc_abort")); + &lea ($base,&DWP(-56,"esp")); + &mov ($const,&wparam(4)); # ivp + &and ($base,-16); + &mov ($magic,&wparam(5)); # enc + &xchg ($base,"esp"); # alloca + &movdqu ("xmm1",&QWP(0,$const)); # load IV + &sub ($out,$inp); + &mov (&DWP(48,"esp"),$base); + + &mov (&DWP(0,"esp"),$out); # save out + &mov (&DWP(4,"esp"),$key) # save key + &mov (&DWP(8,"esp"),$const); # save ivp + &mov ($out,$round); # $out works as $len + + &lea ($const,&DWP(&label("_vpaes_consts")."+0x30-".&label("pic_point"))); + &call ("_vpaes_preheat"); +&set_label("pic_point"); + &cmp ($magic,0); + &je (&label("cbc_dec_loop")); + &jmp (&label("cbc_enc_loop")); + +&set_label("cbc_enc_loop",16); + &movdqu ("xmm0",&QWP(0,$inp)); # load input + &pxor ("xmm0","xmm1"); # inp^=iv + &call ("_vpaes_encrypt_core"); + &mov ($base,&DWP(0,"esp")); # restore out + &mov ($key,&DWP(4,"esp")); # restore key + &movdqa ("xmm1","xmm0"); + &movdqu (&QWP(0,$base,$inp),"xmm0"); # write output + &lea ($inp,&DWP(16,$inp)); + &sub ($out,16); + &jnc (&label("cbc_enc_loop")); + &jmp (&label("cbc_done")); + +&set_label("cbc_dec_loop",16); + &movdqu ("xmm0",&QWP(0,$inp)); # load input + &movdqa (&QWP(16,"esp"),"xmm1"); # save IV + &movdqa (&QWP(32,"esp"),"xmm0"); # save future IV + &call ("_vpaes_decrypt_core"); + &mov ($base,&DWP(0,"esp")); # restore out + &mov ($key,&DWP(4,"esp")); # restore key + &pxor ("xmm0",&QWP(16,"esp")); # out^=iv + &movdqa ("xmm1",&QWP(32,"esp")); # load next IV + &movdqu (&QWP(0,$base,$inp),"xmm0"); # write output + &lea ($inp,&DWP(16,$inp)); + &sub ($out,16); + &jnc (&label("cbc_dec_loop")); + +&set_label("cbc_done"); + &mov ($base,&DWP(8,"esp")); # restore ivp + &mov ("esp",&DWP(48,"esp")); + &movdqu (&QWP(0,$base),"xmm1"); # write IV +&set_label("cbc_abort"); +&function_end("${PREFIX}_cbc_encrypt"); + +&asm_finish(); diff --git a/TMessagesProj/jni/boringssl/crypto/aes/asm/vpaes-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/aes/asm/vpaes-x86_64.pl new file mode 100644 index 00000000..f2ef318f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/asm/vpaes-x86_64.pl @@ -0,0 +1,1207 @@ +#!/usr/bin/env perl + +###################################################################### +## Constant-time SSSE3 AES core implementation. +## version 0.1 +## +## By Mike Hamburg (Stanford University), 2009 +## Public domain. +## +## For details see http://shiftleft.org/papers/vector_aes/ and +## http://crypto.stanford.edu/vpaes/. + +###################################################################### +# September 2011. +# +# Interface to OpenSSL as "almost" drop-in replacement for +# aes-x86_64.pl. "Almost" refers to the fact that AES_cbc_encrypt +# doesn't handle partial vectors (doesn't have to if called from +# EVP only). "Drop-in" implies that this module doesn't share key +# schedule structure with the original nor does it make assumption +# about its alignment... +# +# Performance summary. aes-x86_64.pl column lists large-block CBC +# encrypt/decrypt/with-hyper-threading-off(*) results in cycles per +# byte processed with 128-bit key, and vpaes-x86_64.pl column - +# [also large-block CBC] encrypt/decrypt. +# +# aes-x86_64.pl vpaes-x86_64.pl +# +# Core 2(**) 29.6/41.1/14.3 21.9/25.2(***) +# Nehalem 29.6/40.3/14.6 10.0/11.8 +# Atom 57.3/74.2/32.1 60.9/77.2(***) +# Silvermont 52.7/64.0/19.5 48.8/60.8(***) +# +# (*) "Hyper-threading" in the context refers rather to cache shared +# among multiple cores, than to specifically Intel HTT. As vast +# majority of contemporary cores share cache, slower code path +# is common place. In other words "with-hyper-threading-off" +# results are presented mostly for reference purposes. +# +# (**) "Core 2" refers to initial 65nm design, a.k.a. Conroe. +# +# (***) Less impressive improvement on Core 2 and Atom is due to slow +# pshufb, yet it's respectable +36%/62% improvement on Core 2 +# (as implied, over "hyper-threading-safe" code path). +# +# + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$PREFIX="vpaes"; + +$code.=<<___; +.text + +## +## _aes_encrypt_core +## +## AES-encrypt %xmm0. +## +## Inputs: +## %xmm0 = input +## %xmm9-%xmm15 as in _vpaes_preheat +## (%rdx) = scheduled keys +## +## Output in %xmm0 +## Clobbers %xmm1-%xmm5, %r9, %r10, %r11, %rax +## Preserves %xmm6 - %xmm8 so you get some local vectors +## +## +.type _vpaes_encrypt_core,\@abi-omnipotent +.align 16 +_vpaes_encrypt_core: + mov %rdx, %r9 + mov \$16, %r11 + mov 240(%rdx),%eax + movdqa %xmm9, %xmm1 + movdqa .Lk_ipt(%rip), %xmm2 # iptlo + pandn %xmm0, %xmm1 + movdqu (%r9), %xmm5 # round0 key + psrld \$4, %xmm1 + pand %xmm9, %xmm0 + pshufb %xmm0, %xmm2 + movdqa .Lk_ipt+16(%rip), %xmm0 # ipthi + pshufb %xmm1, %xmm0 + pxor %xmm5, %xmm2 + add \$16, %r9 + pxor %xmm2, %xmm0 + lea .Lk_mc_backward(%rip),%r10 + jmp .Lenc_entry + +.align 16 +.Lenc_loop: + # middle of middle round + movdqa %xmm13, %xmm4 # 4 : sb1u + movdqa %xmm12, %xmm0 # 0 : sb1t + pshufb %xmm2, %xmm4 # 4 = sb1u + pshufb %xmm3, %xmm0 # 0 = sb1t + pxor %xmm5, %xmm4 # 4 = sb1u + k + movdqa %xmm15, %xmm5 # 4 : sb2u + pxor %xmm4, %xmm0 # 0 = A + movdqa -0x40(%r11,%r10), %xmm1 # .Lk_mc_forward[] + pshufb %xmm2, %xmm5 # 4 = sb2u + movdqa (%r11,%r10), %xmm4 # .Lk_mc_backward[] + movdqa %xmm14, %xmm2 # 2 : sb2t + pshufb %xmm3, %xmm2 # 2 = sb2t + movdqa %xmm0, %xmm3 # 3 = A + pxor %xmm5, %xmm2 # 2 = 2A + pshufb %xmm1, %xmm0 # 0 = B + add \$16, %r9 # next key + pxor %xmm2, %xmm0 # 0 = 2A+B + pshufb %xmm4, %xmm3 # 3 = D + add \$16, %r11 # next mc + pxor %xmm0, %xmm3 # 3 = 2A+B+D + pshufb %xmm1, %xmm0 # 0 = 2B+C + and \$0x30, %r11 # ... mod 4 + sub \$1,%rax # nr-- + pxor %xmm3, %xmm0 # 0 = 2A+3B+C+D + +.Lenc_entry: + # top of round + movdqa %xmm9, %xmm1 # 1 : i + movdqa %xmm11, %xmm5 # 2 : a/k + pandn %xmm0, %xmm1 # 1 = i<<4 + psrld \$4, %xmm1 # 1 = i + pand %xmm9, %xmm0 # 0 = k + pshufb %xmm0, %xmm5 # 2 = a/k + movdqa %xmm10, %xmm3 # 3 : 1/i + pxor %xmm1, %xmm0 # 0 = j + pshufb %xmm1, %xmm3 # 3 = 1/i + movdqa %xmm10, %xmm4 # 4 : 1/j + pxor %xmm5, %xmm3 # 3 = iak = 1/i + a/k + pshufb %xmm0, %xmm4 # 4 = 1/j + movdqa %xmm10, %xmm2 # 2 : 1/iak + pxor %xmm5, %xmm4 # 4 = jak = 1/j + a/k + pshufb %xmm3, %xmm2 # 2 = 1/iak + movdqa %xmm10, %xmm3 # 3 : 1/jak + pxor %xmm0, %xmm2 # 2 = io + pshufb %xmm4, %xmm3 # 3 = 1/jak + movdqu (%r9), %xmm5 + pxor %xmm1, %xmm3 # 3 = jo + jnz .Lenc_loop + + # middle of last round + movdqa -0x60(%r10), %xmm4 # 3 : sbou .Lk_sbo + movdqa -0x50(%r10), %xmm0 # 0 : sbot .Lk_sbo+16 + pshufb %xmm2, %xmm4 # 4 = sbou + pxor %xmm5, %xmm4 # 4 = sb1u + k + pshufb %xmm3, %xmm0 # 0 = sb1t + movdqa 0x40(%r11,%r10), %xmm1 # .Lk_sr[] + pxor %xmm4, %xmm0 # 0 = A + pshufb %xmm1, %xmm0 + ret +.size _vpaes_encrypt_core,.-_vpaes_encrypt_core + +## +## Decryption core +## +## Same API as encryption core. +## +.type _vpaes_decrypt_core,\@abi-omnipotent +.align 16 +_vpaes_decrypt_core: + mov %rdx, %r9 # load key + mov 240(%rdx),%eax + movdqa %xmm9, %xmm1 + movdqa .Lk_dipt(%rip), %xmm2 # iptlo + pandn %xmm0, %xmm1 + mov %rax, %r11 + psrld \$4, %xmm1 + movdqu (%r9), %xmm5 # round0 key + shl \$4, %r11 + pand %xmm9, %xmm0 + pshufb %xmm0, %xmm2 + movdqa .Lk_dipt+16(%rip), %xmm0 # ipthi + xor \$0x30, %r11 + lea .Lk_dsbd(%rip),%r10 + pshufb %xmm1, %xmm0 + and \$0x30, %r11 + pxor %xmm5, %xmm2 + movdqa .Lk_mc_forward+48(%rip), %xmm5 + pxor %xmm2, %xmm0 + add \$16, %r9 + add %r10, %r11 + jmp .Ldec_entry + +.align 16 +.Ldec_loop: +## +## Inverse mix columns +## + movdqa -0x20(%r10),%xmm4 # 4 : sb9u + movdqa -0x10(%r10),%xmm1 # 0 : sb9t + pshufb %xmm2, %xmm4 # 4 = sb9u + pshufb %xmm3, %xmm1 # 0 = sb9t + pxor %xmm4, %xmm0 + movdqa 0x00(%r10),%xmm4 # 4 : sbdu + pxor %xmm1, %xmm0 # 0 = ch + movdqa 0x10(%r10),%xmm1 # 0 : sbdt + + pshufb %xmm2, %xmm4 # 4 = sbdu + pshufb %xmm5, %xmm0 # MC ch + pshufb %xmm3, %xmm1 # 0 = sbdt + pxor %xmm4, %xmm0 # 4 = ch + movdqa 0x20(%r10),%xmm4 # 4 : sbbu + pxor %xmm1, %xmm0 # 0 = ch + movdqa 0x30(%r10),%xmm1 # 0 : sbbt + + pshufb %xmm2, %xmm4 # 4 = sbbu + pshufb %xmm5, %xmm0 # MC ch + pshufb %xmm3, %xmm1 # 0 = sbbt + pxor %xmm4, %xmm0 # 4 = ch + movdqa 0x40(%r10),%xmm4 # 4 : sbeu + pxor %xmm1, %xmm0 # 0 = ch + movdqa 0x50(%r10),%xmm1 # 0 : sbet + + pshufb %xmm2, %xmm4 # 4 = sbeu + pshufb %xmm5, %xmm0 # MC ch + pshufb %xmm3, %xmm1 # 0 = sbet + pxor %xmm4, %xmm0 # 4 = ch + add \$16, %r9 # next round key + palignr \$12, %xmm5, %xmm5 + pxor %xmm1, %xmm0 # 0 = ch + sub \$1,%rax # nr-- + +.Ldec_entry: + # top of round + movdqa %xmm9, %xmm1 # 1 : i + pandn %xmm0, %xmm1 # 1 = i<<4 + movdqa %xmm11, %xmm2 # 2 : a/k + psrld \$4, %xmm1 # 1 = i + pand %xmm9, %xmm0 # 0 = k + pshufb %xmm0, %xmm2 # 2 = a/k + movdqa %xmm10, %xmm3 # 3 : 1/i + pxor %xmm1, %xmm0 # 0 = j + pshufb %xmm1, %xmm3 # 3 = 1/i + movdqa %xmm10, %xmm4 # 4 : 1/j + pxor %xmm2, %xmm3 # 3 = iak = 1/i + a/k + pshufb %xmm0, %xmm4 # 4 = 1/j + pxor %xmm2, %xmm4 # 4 = jak = 1/j + a/k + movdqa %xmm10, %xmm2 # 2 : 1/iak + pshufb %xmm3, %xmm2 # 2 = 1/iak + movdqa %xmm10, %xmm3 # 3 : 1/jak + pxor %xmm0, %xmm2 # 2 = io + pshufb %xmm4, %xmm3 # 3 = 1/jak + movdqu (%r9), %xmm0 + pxor %xmm1, %xmm3 # 3 = jo + jnz .Ldec_loop + + # middle of last round + movdqa 0x60(%r10), %xmm4 # 3 : sbou + pshufb %xmm2, %xmm4 # 4 = sbou + pxor %xmm0, %xmm4 # 4 = sb1u + k + movdqa 0x70(%r10), %xmm0 # 0 : sbot + movdqa -0x160(%r11), %xmm2 # .Lk_sr-.Lk_dsbd=-0x160 + pshufb %xmm3, %xmm0 # 0 = sb1t + pxor %xmm4, %xmm0 # 0 = A + pshufb %xmm2, %xmm0 + ret +.size _vpaes_decrypt_core,.-_vpaes_decrypt_core + +######################################################## +## ## +## AES key schedule ## +## ## +######################################################## +.type _vpaes_schedule_core,\@abi-omnipotent +.align 16 +_vpaes_schedule_core: + # rdi = key + # rsi = size in bits + # rdx = buffer + # rcx = direction. 0=encrypt, 1=decrypt + + call _vpaes_preheat # load the tables + movdqa .Lk_rcon(%rip), %xmm8 # load rcon + movdqu (%rdi), %xmm0 # load key (unaligned) + + # input transform + movdqa %xmm0, %xmm3 + lea .Lk_ipt(%rip), %r11 + call _vpaes_schedule_transform + movdqa %xmm0, %xmm7 + + lea .Lk_sr(%rip),%r10 + test %rcx, %rcx + jnz .Lschedule_am_decrypting + + # encrypting, output zeroth round key after transform + movdqu %xmm0, (%rdx) + jmp .Lschedule_go + +.Lschedule_am_decrypting: + # decrypting, output zeroth round key after shiftrows + movdqa (%r8,%r10),%xmm1 + pshufb %xmm1, %xmm3 + movdqu %xmm3, (%rdx) + xor \$0x30, %r8 + +.Lschedule_go: + cmp \$192, %esi + ja .Lschedule_256 + je .Lschedule_192 + # 128: fall though + +## +## .schedule_128 +## +## 128-bit specific part of key schedule. +## +## This schedule is really simple, because all its parts +## are accomplished by the subroutines. +## +.Lschedule_128: + mov \$10, %esi + +.Loop_schedule_128: + call _vpaes_schedule_round + dec %rsi + jz .Lschedule_mangle_last + call _vpaes_schedule_mangle # write output + jmp .Loop_schedule_128 + +## +## .aes_schedule_192 +## +## 192-bit specific part of key schedule. +## +## The main body of this schedule is the same as the 128-bit +## schedule, but with more smearing. The long, high side is +## stored in %xmm7 as before, and the short, low side is in +## the high bits of %xmm6. +## +## This schedule is somewhat nastier, however, because each +## round produces 192 bits of key material, or 1.5 round keys. +## Therefore, on each cycle we do 2 rounds and produce 3 round +## keys. +## +.align 16 +.Lschedule_192: + movdqu 8(%rdi),%xmm0 # load key part 2 (very unaligned) + call _vpaes_schedule_transform # input transform + movdqa %xmm0, %xmm6 # save short part + pxor %xmm4, %xmm4 # clear 4 + movhlps %xmm4, %xmm6 # clobber low side with zeros + mov \$4, %esi + +.Loop_schedule_192: + call _vpaes_schedule_round + palignr \$8,%xmm6,%xmm0 + call _vpaes_schedule_mangle # save key n + call _vpaes_schedule_192_smear + call _vpaes_schedule_mangle # save key n+1 + call _vpaes_schedule_round + dec %rsi + jz .Lschedule_mangle_last + call _vpaes_schedule_mangle # save key n+2 + call _vpaes_schedule_192_smear + jmp .Loop_schedule_192 + +## +## .aes_schedule_256 +## +## 256-bit specific part of key schedule. +## +## The structure here is very similar to the 128-bit +## schedule, but with an additional "low side" in +## %xmm6. The low side's rounds are the same as the +## high side's, except no rcon and no rotation. +## +.align 16 +.Lschedule_256: + movdqu 16(%rdi),%xmm0 # load key part 2 (unaligned) + call _vpaes_schedule_transform # input transform + mov \$7, %esi + +.Loop_schedule_256: + call _vpaes_schedule_mangle # output low result + movdqa %xmm0, %xmm6 # save cur_lo in xmm6 + + # high round + call _vpaes_schedule_round + dec %rsi + jz .Lschedule_mangle_last + call _vpaes_schedule_mangle + + # low round. swap xmm7 and xmm6 + pshufd \$0xFF, %xmm0, %xmm0 + movdqa %xmm7, %xmm5 + movdqa %xmm6, %xmm7 + call _vpaes_schedule_low_round + movdqa %xmm5, %xmm7 + + jmp .Loop_schedule_256 + + +## +## .aes_schedule_mangle_last +## +## Mangler for last round of key schedule +## Mangles %xmm0 +## when encrypting, outputs out(%xmm0) ^ 63 +## when decrypting, outputs unskew(%xmm0) +## +## Always called right before return... jumps to cleanup and exits +## +.align 16 +.Lschedule_mangle_last: + # schedule last round key from xmm0 + lea .Lk_deskew(%rip),%r11 # prepare to deskew + test %rcx, %rcx + jnz .Lschedule_mangle_last_dec + + # encrypting + movdqa (%r8,%r10),%xmm1 + pshufb %xmm1, %xmm0 # output permute + lea .Lk_opt(%rip), %r11 # prepare to output transform + add \$32, %rdx + +.Lschedule_mangle_last_dec: + add \$-16, %rdx + pxor .Lk_s63(%rip), %xmm0 + call _vpaes_schedule_transform # output transform + movdqu %xmm0, (%rdx) # save last key + + # cleanup + pxor %xmm0, %xmm0 + pxor %xmm1, %xmm1 + pxor %xmm2, %xmm2 + pxor %xmm3, %xmm3 + pxor %xmm4, %xmm4 + pxor %xmm5, %xmm5 + pxor %xmm6, %xmm6 + pxor %xmm7, %xmm7 + ret +.size _vpaes_schedule_core,.-_vpaes_schedule_core + +## +## .aes_schedule_192_smear +## +## Smear the short, low side in the 192-bit key schedule. +## +## Inputs: +## %xmm7: high side, b a x y +## %xmm6: low side, d c 0 0 +## %xmm13: 0 +## +## Outputs: +## %xmm6: b+c+d b+c 0 0 +## %xmm0: b+c+d b+c b a +## +.type _vpaes_schedule_192_smear,\@abi-omnipotent +.align 16 +_vpaes_schedule_192_smear: + pshufd \$0x80, %xmm6, %xmm1 # d c 0 0 -> c 0 0 0 + pshufd \$0xFE, %xmm7, %xmm0 # b a _ _ -> b b b a + pxor %xmm1, %xmm6 # -> c+d c 0 0 + pxor %xmm1, %xmm1 + pxor %xmm0, %xmm6 # -> b+c+d b+c b a + movdqa %xmm6, %xmm0 + movhlps %xmm1, %xmm6 # clobber low side with zeros + ret +.size _vpaes_schedule_192_smear,.-_vpaes_schedule_192_smear + +## +## .aes_schedule_round +## +## Runs one main round of the key schedule on %xmm0, %xmm7 +## +## Specifically, runs subbytes on the high dword of %xmm0 +## then rotates it by one byte and xors into the low dword of +## %xmm7. +## +## Adds rcon from low byte of %xmm8, then rotates %xmm8 for +## next rcon. +## +## Smears the dwords of %xmm7 by xoring the low into the +## second low, result into third, result into highest. +## +## Returns results in %xmm7 = %xmm0. +## Clobbers %xmm1-%xmm4, %r11. +## +.type _vpaes_schedule_round,\@abi-omnipotent +.align 16 +_vpaes_schedule_round: + # extract rcon from xmm8 + pxor %xmm1, %xmm1 + palignr \$15, %xmm8, %xmm1 + palignr \$15, %xmm8, %xmm8 + pxor %xmm1, %xmm7 + + # rotate + pshufd \$0xFF, %xmm0, %xmm0 + palignr \$1, %xmm0, %xmm0 + + # fall through... + + # low round: same as high round, but no rotation and no rcon. +_vpaes_schedule_low_round: + # smear xmm7 + movdqa %xmm7, %xmm1 + pslldq \$4, %xmm7 + pxor %xmm1, %xmm7 + movdqa %xmm7, %xmm1 + pslldq \$8, %xmm7 + pxor %xmm1, %xmm7 + pxor .Lk_s63(%rip), %xmm7 + + # subbytes + movdqa %xmm9, %xmm1 + pandn %xmm0, %xmm1 + psrld \$4, %xmm1 # 1 = i + pand %xmm9, %xmm0 # 0 = k + movdqa %xmm11, %xmm2 # 2 : a/k + pshufb %xmm0, %xmm2 # 2 = a/k + pxor %xmm1, %xmm0 # 0 = j + movdqa %xmm10, %xmm3 # 3 : 1/i + pshufb %xmm1, %xmm3 # 3 = 1/i + pxor %xmm2, %xmm3 # 3 = iak = 1/i + a/k + movdqa %xmm10, %xmm4 # 4 : 1/j + pshufb %xmm0, %xmm4 # 4 = 1/j + pxor %xmm2, %xmm4 # 4 = jak = 1/j + a/k + movdqa %xmm10, %xmm2 # 2 : 1/iak + pshufb %xmm3, %xmm2 # 2 = 1/iak + pxor %xmm0, %xmm2 # 2 = io + movdqa %xmm10, %xmm3 # 3 : 1/jak + pshufb %xmm4, %xmm3 # 3 = 1/jak + pxor %xmm1, %xmm3 # 3 = jo + movdqa %xmm13, %xmm4 # 4 : sbou + pshufb %xmm2, %xmm4 # 4 = sbou + movdqa %xmm12, %xmm0 # 0 : sbot + pshufb %xmm3, %xmm0 # 0 = sb1t + pxor %xmm4, %xmm0 # 0 = sbox output + + # add in smeared stuff + pxor %xmm7, %xmm0 + movdqa %xmm0, %xmm7 + ret +.size _vpaes_schedule_round,.-_vpaes_schedule_round + +## +## .aes_schedule_transform +## +## Linear-transform %xmm0 according to tables at (%r11) +## +## Requires that %xmm9 = 0x0F0F... as in preheat +## Output in %xmm0 +## Clobbers %xmm1, %xmm2 +## +.type _vpaes_schedule_transform,\@abi-omnipotent +.align 16 +_vpaes_schedule_transform: + movdqa %xmm9, %xmm1 + pandn %xmm0, %xmm1 + psrld \$4, %xmm1 + pand %xmm9, %xmm0 + movdqa (%r11), %xmm2 # lo + pshufb %xmm0, %xmm2 + movdqa 16(%r11), %xmm0 # hi + pshufb %xmm1, %xmm0 + pxor %xmm2, %xmm0 + ret +.size _vpaes_schedule_transform,.-_vpaes_schedule_transform + +## +## .aes_schedule_mangle +## +## Mangle xmm0 from (basis-transformed) standard version +## to our version. +## +## On encrypt, +## xor with 0x63 +## multiply by circulant 0,1,1,1 +## apply shiftrows transform +## +## On decrypt, +## xor with 0x63 +## multiply by "inverse mixcolumns" circulant E,B,D,9 +## deskew +## apply shiftrows transform +## +## +## Writes out to (%rdx), and increments or decrements it +## Keeps track of round number mod 4 in %r8 +## Preserves xmm0 +## Clobbers xmm1-xmm5 +## +.type _vpaes_schedule_mangle,\@abi-omnipotent +.align 16 +_vpaes_schedule_mangle: + movdqa %xmm0, %xmm4 # save xmm0 for later + movdqa .Lk_mc_forward(%rip),%xmm5 + test %rcx, %rcx + jnz .Lschedule_mangle_dec + + # encrypting + add \$16, %rdx + pxor .Lk_s63(%rip),%xmm4 + pshufb %xmm5, %xmm4 + movdqa %xmm4, %xmm3 + pshufb %xmm5, %xmm4 + pxor %xmm4, %xmm3 + pshufb %xmm5, %xmm4 + pxor %xmm4, %xmm3 + + jmp .Lschedule_mangle_both +.align 16 +.Lschedule_mangle_dec: + # inverse mix columns + lea .Lk_dksd(%rip),%r11 + movdqa %xmm9, %xmm1 + pandn %xmm4, %xmm1 + psrld \$4, %xmm1 # 1 = hi + pand %xmm9, %xmm4 # 4 = lo + + movdqa 0x00(%r11), %xmm2 + pshufb %xmm4, %xmm2 + movdqa 0x10(%r11), %xmm3 + pshufb %xmm1, %xmm3 + pxor %xmm2, %xmm3 + pshufb %xmm5, %xmm3 + + movdqa 0x20(%r11), %xmm2 + pshufb %xmm4, %xmm2 + pxor %xmm3, %xmm2 + movdqa 0x30(%r11), %xmm3 + pshufb %xmm1, %xmm3 + pxor %xmm2, %xmm3 + pshufb %xmm5, %xmm3 + + movdqa 0x40(%r11), %xmm2 + pshufb %xmm4, %xmm2 + pxor %xmm3, %xmm2 + movdqa 0x50(%r11), %xmm3 + pshufb %xmm1, %xmm3 + pxor %xmm2, %xmm3 + pshufb %xmm5, %xmm3 + + movdqa 0x60(%r11), %xmm2 + pshufb %xmm4, %xmm2 + pxor %xmm3, %xmm2 + movdqa 0x70(%r11), %xmm3 + pshufb %xmm1, %xmm3 + pxor %xmm2, %xmm3 + + add \$-16, %rdx + +.Lschedule_mangle_both: + movdqa (%r8,%r10),%xmm1 + pshufb %xmm1,%xmm3 + add \$-16, %r8 + and \$0x30, %r8 + movdqu %xmm3, (%rdx) + ret +.size _vpaes_schedule_mangle,.-_vpaes_schedule_mangle + +# +# Interface to OpenSSL +# +.globl ${PREFIX}_set_encrypt_key +.type ${PREFIX}_set_encrypt_key,\@function,3 +.align 16 +${PREFIX}_set_encrypt_key: +___ +$code.=<<___ if ($win64); + lea -0xb8(%rsp),%rsp + movaps %xmm6,0x10(%rsp) + movaps %xmm7,0x20(%rsp) + movaps %xmm8,0x30(%rsp) + movaps %xmm9,0x40(%rsp) + movaps %xmm10,0x50(%rsp) + movaps %xmm11,0x60(%rsp) + movaps %xmm12,0x70(%rsp) + movaps %xmm13,0x80(%rsp) + movaps %xmm14,0x90(%rsp) + movaps %xmm15,0xa0(%rsp) +.Lenc_key_body: +___ +$code.=<<___; + mov %esi,%eax + shr \$5,%eax + add \$5,%eax + mov %eax,240(%rdx) # AES_KEY->rounds = nbits/32+5; + + mov \$0,%ecx + mov \$0x30,%r8d + call _vpaes_schedule_core +___ +$code.=<<___ if ($win64); + movaps 0x10(%rsp),%xmm6 + movaps 0x20(%rsp),%xmm7 + movaps 0x30(%rsp),%xmm8 + movaps 0x40(%rsp),%xmm9 + movaps 0x50(%rsp),%xmm10 + movaps 0x60(%rsp),%xmm11 + movaps 0x70(%rsp),%xmm12 + movaps 0x80(%rsp),%xmm13 + movaps 0x90(%rsp),%xmm14 + movaps 0xa0(%rsp),%xmm15 + lea 0xb8(%rsp),%rsp +.Lenc_key_epilogue: +___ +$code.=<<___; + xor %eax,%eax + ret +.size ${PREFIX}_set_encrypt_key,.-${PREFIX}_set_encrypt_key + +.globl ${PREFIX}_set_decrypt_key +.type ${PREFIX}_set_decrypt_key,\@function,3 +.align 16 +${PREFIX}_set_decrypt_key: +___ +$code.=<<___ if ($win64); + lea -0xb8(%rsp),%rsp + movaps %xmm6,0x10(%rsp) + movaps %xmm7,0x20(%rsp) + movaps %xmm8,0x30(%rsp) + movaps %xmm9,0x40(%rsp) + movaps %xmm10,0x50(%rsp) + movaps %xmm11,0x60(%rsp) + movaps %xmm12,0x70(%rsp) + movaps %xmm13,0x80(%rsp) + movaps %xmm14,0x90(%rsp) + movaps %xmm15,0xa0(%rsp) +.Ldec_key_body: +___ +$code.=<<___; + mov %esi,%eax + shr \$5,%eax + add \$5,%eax + mov %eax,240(%rdx) # AES_KEY->rounds = nbits/32+5; + shl \$4,%eax + lea 16(%rdx,%rax),%rdx + + mov \$1,%ecx + mov %esi,%r8d + shr \$1,%r8d + and \$32,%r8d + xor \$32,%r8d # nbits==192?0:32 + call _vpaes_schedule_core +___ +$code.=<<___ if ($win64); + movaps 0x10(%rsp),%xmm6 + movaps 0x20(%rsp),%xmm7 + movaps 0x30(%rsp),%xmm8 + movaps 0x40(%rsp),%xmm9 + movaps 0x50(%rsp),%xmm10 + movaps 0x60(%rsp),%xmm11 + movaps 0x70(%rsp),%xmm12 + movaps 0x80(%rsp),%xmm13 + movaps 0x90(%rsp),%xmm14 + movaps 0xa0(%rsp),%xmm15 + lea 0xb8(%rsp),%rsp +.Ldec_key_epilogue: +___ +$code.=<<___; + xor %eax,%eax + ret +.size ${PREFIX}_set_decrypt_key,.-${PREFIX}_set_decrypt_key + +.globl ${PREFIX}_encrypt +.type ${PREFIX}_encrypt,\@function,3 +.align 16 +${PREFIX}_encrypt: +___ +$code.=<<___ if ($win64); + lea -0xb8(%rsp),%rsp + movaps %xmm6,0x10(%rsp) + movaps %xmm7,0x20(%rsp) + movaps %xmm8,0x30(%rsp) + movaps %xmm9,0x40(%rsp) + movaps %xmm10,0x50(%rsp) + movaps %xmm11,0x60(%rsp) + movaps %xmm12,0x70(%rsp) + movaps %xmm13,0x80(%rsp) + movaps %xmm14,0x90(%rsp) + movaps %xmm15,0xa0(%rsp) +.Lenc_body: +___ +$code.=<<___; + movdqu (%rdi),%xmm0 + call _vpaes_preheat + call _vpaes_encrypt_core + movdqu %xmm0,(%rsi) +___ +$code.=<<___ if ($win64); + movaps 0x10(%rsp),%xmm6 + movaps 0x20(%rsp),%xmm7 + movaps 0x30(%rsp),%xmm8 + movaps 0x40(%rsp),%xmm9 + movaps 0x50(%rsp),%xmm10 + movaps 0x60(%rsp),%xmm11 + movaps 0x70(%rsp),%xmm12 + movaps 0x80(%rsp),%xmm13 + movaps 0x90(%rsp),%xmm14 + movaps 0xa0(%rsp),%xmm15 + lea 0xb8(%rsp),%rsp +.Lenc_epilogue: +___ +$code.=<<___; + ret +.size ${PREFIX}_encrypt,.-${PREFIX}_encrypt + +.globl ${PREFIX}_decrypt +.type ${PREFIX}_decrypt,\@function,3 +.align 16 +${PREFIX}_decrypt: +___ +$code.=<<___ if ($win64); + lea -0xb8(%rsp),%rsp + movaps %xmm6,0x10(%rsp) + movaps %xmm7,0x20(%rsp) + movaps %xmm8,0x30(%rsp) + movaps %xmm9,0x40(%rsp) + movaps %xmm10,0x50(%rsp) + movaps %xmm11,0x60(%rsp) + movaps %xmm12,0x70(%rsp) + movaps %xmm13,0x80(%rsp) + movaps %xmm14,0x90(%rsp) + movaps %xmm15,0xa0(%rsp) +.Ldec_body: +___ +$code.=<<___; + movdqu (%rdi),%xmm0 + call _vpaes_preheat + call _vpaes_decrypt_core + movdqu %xmm0,(%rsi) +___ +$code.=<<___ if ($win64); + movaps 0x10(%rsp),%xmm6 + movaps 0x20(%rsp),%xmm7 + movaps 0x30(%rsp),%xmm8 + movaps 0x40(%rsp),%xmm9 + movaps 0x50(%rsp),%xmm10 + movaps 0x60(%rsp),%xmm11 + movaps 0x70(%rsp),%xmm12 + movaps 0x80(%rsp),%xmm13 + movaps 0x90(%rsp),%xmm14 + movaps 0xa0(%rsp),%xmm15 + lea 0xb8(%rsp),%rsp +.Ldec_epilogue: +___ +$code.=<<___; + ret +.size ${PREFIX}_decrypt,.-${PREFIX}_decrypt +___ +{ +my ($inp,$out,$len,$key,$ivp,$enc)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9"); +# void AES_cbc_encrypt (const void char *inp, unsigned char *out, +# size_t length, const AES_KEY *key, +# unsigned char *ivp,const int enc); +$code.=<<___; +.globl ${PREFIX}_cbc_encrypt +.type ${PREFIX}_cbc_encrypt,\@function,6 +.align 16 +${PREFIX}_cbc_encrypt: + xchg $key,$len +___ +($len,$key)=($key,$len); +$code.=<<___; + sub \$16,$len + jc .Lcbc_abort +___ +$code.=<<___ if ($win64); + lea -0xb8(%rsp),%rsp + movaps %xmm6,0x10(%rsp) + movaps %xmm7,0x20(%rsp) + movaps %xmm8,0x30(%rsp) + movaps %xmm9,0x40(%rsp) + movaps %xmm10,0x50(%rsp) + movaps %xmm11,0x60(%rsp) + movaps %xmm12,0x70(%rsp) + movaps %xmm13,0x80(%rsp) + movaps %xmm14,0x90(%rsp) + movaps %xmm15,0xa0(%rsp) +.Lcbc_body: +___ +$code.=<<___; + movdqu ($ivp),%xmm6 # load IV + sub $inp,$out + call _vpaes_preheat + cmp \$0,${enc}d + je .Lcbc_dec_loop + jmp .Lcbc_enc_loop +.align 16 +.Lcbc_enc_loop: + movdqu ($inp),%xmm0 + pxor %xmm6,%xmm0 + call _vpaes_encrypt_core + movdqa %xmm0,%xmm6 + movdqu %xmm0,($out,$inp) + lea 16($inp),$inp + sub \$16,$len + jnc .Lcbc_enc_loop + jmp .Lcbc_done +.align 16 +.Lcbc_dec_loop: + movdqu ($inp),%xmm0 + movdqa %xmm0,%xmm7 + call _vpaes_decrypt_core + pxor %xmm6,%xmm0 + movdqa %xmm7,%xmm6 + movdqu %xmm0,($out,$inp) + lea 16($inp),$inp + sub \$16,$len + jnc .Lcbc_dec_loop +.Lcbc_done: + movdqu %xmm6,($ivp) # save IV +___ +$code.=<<___ if ($win64); + movaps 0x10(%rsp),%xmm6 + movaps 0x20(%rsp),%xmm7 + movaps 0x30(%rsp),%xmm8 + movaps 0x40(%rsp),%xmm9 + movaps 0x50(%rsp),%xmm10 + movaps 0x60(%rsp),%xmm11 + movaps 0x70(%rsp),%xmm12 + movaps 0x80(%rsp),%xmm13 + movaps 0x90(%rsp),%xmm14 + movaps 0xa0(%rsp),%xmm15 + lea 0xb8(%rsp),%rsp +.Lcbc_epilogue: +___ +$code.=<<___; +.Lcbc_abort: + ret +.size ${PREFIX}_cbc_encrypt,.-${PREFIX}_cbc_encrypt +___ +} +$code.=<<___; +## +## _aes_preheat +## +## Fills register %r10 -> .aes_consts (so you can -fPIC) +## and %xmm9-%xmm15 as specified below. +## +.type _vpaes_preheat,\@abi-omnipotent +.align 16 +_vpaes_preheat: + lea .Lk_s0F(%rip), %r10 + movdqa -0x20(%r10), %xmm10 # .Lk_inv + movdqa -0x10(%r10), %xmm11 # .Lk_inv+16 + movdqa 0x00(%r10), %xmm9 # .Lk_s0F + movdqa 0x30(%r10), %xmm13 # .Lk_sb1 + movdqa 0x40(%r10), %xmm12 # .Lk_sb1+16 + movdqa 0x50(%r10), %xmm15 # .Lk_sb2 + movdqa 0x60(%r10), %xmm14 # .Lk_sb2+16 + ret +.size _vpaes_preheat,.-_vpaes_preheat +######################################################## +## ## +## Constants ## +## ## +######################################################## +.type _vpaes_consts,\@object +.align 64 +_vpaes_consts: +.Lk_inv: # inv, inva + .quad 0x0E05060F0D080180, 0x040703090A0B0C02 + .quad 0x01040A060F0B0780, 0x030D0E0C02050809 + +.Lk_s0F: # s0F + .quad 0x0F0F0F0F0F0F0F0F, 0x0F0F0F0F0F0F0F0F + +.Lk_ipt: # input transform (lo, hi) + .quad 0xC2B2E8985A2A7000, 0xCABAE09052227808 + .quad 0x4C01307D317C4D00, 0xCD80B1FCB0FDCC81 + +.Lk_sb1: # sb1u, sb1t + .quad 0xB19BE18FCB503E00, 0xA5DF7A6E142AF544 + .quad 0x3618D415FAE22300, 0x3BF7CCC10D2ED9EF +.Lk_sb2: # sb2u, sb2t + .quad 0xE27A93C60B712400, 0x5EB7E955BC982FCD + .quad 0x69EB88400AE12900, 0xC2A163C8AB82234A +.Lk_sbo: # sbou, sbot + .quad 0xD0D26D176FBDC700, 0x15AABF7AC502A878 + .quad 0xCFE474A55FBB6A00, 0x8E1E90D1412B35FA + +.Lk_mc_forward: # mc_forward + .quad 0x0407060500030201, 0x0C0F0E0D080B0A09 + .quad 0x080B0A0904070605, 0x000302010C0F0E0D + .quad 0x0C0F0E0D080B0A09, 0x0407060500030201 + .quad 0x000302010C0F0E0D, 0x080B0A0904070605 + +.Lk_mc_backward:# mc_backward + .quad 0x0605040702010003, 0x0E0D0C0F0A09080B + .quad 0x020100030E0D0C0F, 0x0A09080B06050407 + .quad 0x0E0D0C0F0A09080B, 0x0605040702010003 + .quad 0x0A09080B06050407, 0x020100030E0D0C0F + +.Lk_sr: # sr + .quad 0x0706050403020100, 0x0F0E0D0C0B0A0908 + .quad 0x030E09040F0A0500, 0x0B06010C07020D08 + .quad 0x0F060D040B020900, 0x070E050C030A0108 + .quad 0x0B0E0104070A0D00, 0x0306090C0F020508 + +.Lk_rcon: # rcon + .quad 0x1F8391B9AF9DEEB6, 0x702A98084D7C7D81 + +.Lk_s63: # s63: all equal to 0x63 transformed + .quad 0x5B5B5B5B5B5B5B5B, 0x5B5B5B5B5B5B5B5B + +.Lk_opt: # output transform + .quad 0xFF9F4929D6B66000, 0xF7974121DEBE6808 + .quad 0x01EDBD5150BCEC00, 0xE10D5DB1B05C0CE0 + +.Lk_deskew: # deskew tables: inverts the sbox's "skew" + .quad 0x07E4A34047A4E300, 0x1DFEB95A5DBEF91A + .quad 0x5F36B5DC83EA6900, 0x2841C2ABF49D1E77 + +## +## Decryption stuff +## Key schedule constants +## +.Lk_dksd: # decryption key schedule: invskew x*D + .quad 0xFEB91A5DA3E44700, 0x0740E3A45A1DBEF9 + .quad 0x41C277F4B5368300, 0x5FDC69EAAB289D1E +.Lk_dksb: # decryption key schedule: invskew x*B + .quad 0x9A4FCA1F8550D500, 0x03D653861CC94C99 + .quad 0x115BEDA7B6FC4A00, 0xD993256F7E3482C8 +.Lk_dkse: # decryption key schedule: invskew x*E + 0x63 + .quad 0xD5031CCA1FC9D600, 0x53859A4C994F5086 + .quad 0xA23196054FDC7BE8, 0xCD5EF96A20B31487 +.Lk_dks9: # decryption key schedule: invskew x*9 + .quad 0xB6116FC87ED9A700, 0x4AED933482255BFC + .quad 0x4576516227143300, 0x8BB89FACE9DAFDCE + +## +## Decryption stuff +## Round function constants +## +.Lk_dipt: # decryption input transform + .quad 0x0F505B040B545F00, 0x154A411E114E451A + .quad 0x86E383E660056500, 0x12771772F491F194 + +.Lk_dsb9: # decryption sbox output *9*u, *9*t + .quad 0x851C03539A86D600, 0xCAD51F504F994CC9 + .quad 0xC03B1789ECD74900, 0x725E2C9EB2FBA565 +.Lk_dsbd: # decryption sbox output *D*u, *D*t + .quad 0x7D57CCDFE6B1A200, 0xF56E9B13882A4439 + .quad 0x3CE2FAF724C6CB00, 0x2931180D15DEEFD3 +.Lk_dsbb: # decryption sbox output *B*u, *B*t + .quad 0xD022649296B44200, 0x602646F6B0F2D404 + .quad 0xC19498A6CD596700, 0xF3FF0C3E3255AA6B +.Lk_dsbe: # decryption sbox output *E*u, *E*t + .quad 0x46F2929626D4D000, 0x2242600464B4F6B0 + .quad 0x0C55A6CDFFAAC100, 0x9467F36B98593E32 +.Lk_dsbo: # decryption sbox final output + .quad 0x1387EA537EF94000, 0xC7AA6DB9D4943E2D + .quad 0x12D7560F93441D00, 0xCA4B8159D8C58E9C +.asciz "Vector Permutation AES for x86_64/SSSE3, Mike Hamburg (Stanford University)" +.align 64 +.size _vpaes_consts,.-_vpaes_consts +___ + +if ($win64) { +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lin_prologue + + lea 16(%rax),%rsi # %xmm save area + lea 512($context),%rdi # &context.Xmm6 + mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax) + .long 0xa548f3fc # cld; rep movsq + lea 0xb8(%rax),%rax # adjust stack pointer + +.Lin_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$`1232/8`,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size se_handler,.-se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_${PREFIX}_set_encrypt_key + .rva .LSEH_end_${PREFIX}_set_encrypt_key + .rva .LSEH_info_${PREFIX}_set_encrypt_key + + .rva .LSEH_begin_${PREFIX}_set_decrypt_key + .rva .LSEH_end_${PREFIX}_set_decrypt_key + .rva .LSEH_info_${PREFIX}_set_decrypt_key + + .rva .LSEH_begin_${PREFIX}_encrypt + .rva .LSEH_end_${PREFIX}_encrypt + .rva .LSEH_info_${PREFIX}_encrypt + + .rva .LSEH_begin_${PREFIX}_decrypt + .rva .LSEH_end_${PREFIX}_decrypt + .rva .LSEH_info_${PREFIX}_decrypt + + .rva .LSEH_begin_${PREFIX}_cbc_encrypt + .rva .LSEH_end_${PREFIX}_cbc_encrypt + .rva .LSEH_info_${PREFIX}_cbc_encrypt + +.section .xdata +.align 8 +.LSEH_info_${PREFIX}_set_encrypt_key: + .byte 9,0,0,0 + .rva se_handler + .rva .Lenc_key_body,.Lenc_key_epilogue # HandlerData[] +.LSEH_info_${PREFIX}_set_decrypt_key: + .byte 9,0,0,0 + .rva se_handler + .rva .Ldec_key_body,.Ldec_key_epilogue # HandlerData[] +.LSEH_info_${PREFIX}_encrypt: + .byte 9,0,0,0 + .rva se_handler + .rva .Lenc_body,.Lenc_epilogue # HandlerData[] +.LSEH_info_${PREFIX}_decrypt: + .byte 9,0,0,0 + .rva se_handler + .rva .Ldec_body,.Ldec_epilogue # HandlerData[] +.LSEH_info_${PREFIX}_cbc_encrypt: + .byte 9,0,0,0 + .rva se_handler + .rva .Lcbc_body,.Lcbc_epilogue # HandlerData[] +___ +} + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/aes/internal.h b/TMessagesProj/jni/boringssl/crypto/aes/internal.h new file mode 100644 index 00000000..3dc5c637 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/internal.h @@ -0,0 +1,87 @@ +/* ==================================================================== + * Copyright (c) 2002-2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== */ + +#ifndef OPENSSL_HEADER_AES_INTERNAL_H +#define OPENSSL_HEADER_AES_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#if defined(_MSC_VER) && \ + (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64)) +#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00) +#define GETU32(p) SWAP(*((uint32_t *)(p))) +#define PUTU32(ct, st) \ + { *((uint32_t *)(ct)) = SWAP((st)); } +#else +#define GETU32(pt) \ + (((uint32_t)(pt)[0] << 24) ^ ((uint32_t)(pt)[1] << 16) ^ \ + ((uint32_t)(pt)[2] << 8) ^ ((uint32_t)(pt)[3])) +#define PUTU32(ct, st) \ + { \ + (ct)[0] = (uint8_t)((st) >> 24); \ + (ct)[1] = (uint8_t)((st) >> 16); \ + (ct)[2] = (uint8_t)((st) >> 8); \ + (ct)[3] = (uint8_t)(st); \ + } +#endif + +#define MAXKC (256 / 32) +#define MAXKB (256 / 8) +#define MAXNR 14 + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_AES_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/aes/mode_wrappers.c b/TMessagesProj/jni/boringssl/crypto/aes/mode_wrappers.c new file mode 100644 index 00000000..c706896d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/aes/mode_wrappers.c @@ -0,0 +1,108 @@ +/* ==================================================================== + * Copyright (c) 2002-2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== */ + +#include + +#include "assert.h" + +#include + + +void AES_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, uint8_t ivec[AES_BLOCK_SIZE], + uint8_t ecount_buf[AES_BLOCK_SIZE], unsigned int *num) { + CRYPTO_ctr128_encrypt(in, out, len, key, ivec, ecount_buf, num, + (block128_f)AES_encrypt); +} + +void AES_ecb_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key, + const int enc) { + assert(in && out && key); + assert((AES_ENCRYPT == enc) || (AES_DECRYPT == enc)); + + if (AES_ENCRYPT == enc) { + AES_encrypt(in, out, key); + } else { + AES_decrypt(in, out, key); + } +} + +#if defined(OPENSSL_NO_ASM) || \ + (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) +void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, uint8_t *ivec, const int enc) { + + if (enc) { + CRYPTO_cbc128_encrypt(in, out, len, key, ivec, (block128_f)AES_encrypt); + } else { + CRYPTO_cbc128_decrypt(in, out, len, key, ivec, (block128_f)AES_decrypt); + } +} +#else + +void asm_AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, uint8_t *ivec, const int enc); +void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, uint8_t *ivec, const int enc) { + asm_AES_cbc_encrypt(in, out, len, key, ivec, enc); +} + +#endif /* OPENSSL_NO_ASM || (!OPENSSL_X86_64 && !OPENSSL_X86) */ + +void AES_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, int *num) { + CRYPTO_ofb128_encrypt(in, out, length, key, ivec, num, + (block128_f)AES_encrypt); +} + +void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, int *num, + int enc) { + CRYPTO_cfb128_encrypt(in, out, length, key, ivec, num, enc, + (block128_f)AES_encrypt); +} diff --git a/TMessagesProj/jni/boringssl/crypto/arm_arch.h b/TMessagesProj/jni/boringssl/crypto/arm_arch.h new file mode 100644 index 00000000..0600fbb1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/arm_arch.h @@ -0,0 +1,136 @@ +/* ==================================================================== + * Copyright (c) 1998-2011 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_ARM_ARCH_H +#define OPENSSL_HEADER_ARM_ARCH_H + +#if !defined(__ARM_ARCH__) +# if defined(__CC_ARM) +# define __ARM_ARCH__ __TARGET_ARCH_ARM +# if defined(__BIG_ENDIAN) +# define __ARMEB__ +# else +# define __ARMEL__ +# endif +# elif defined(__GNUC__) +# if defined(__aarch64__) +# define __ARM_ARCH__ 8 +# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define __ARMEB__ +# else +# define __ARMEL__ +# endif + /* Why doesn't gcc define __ARM_ARCH__? Instead it defines + * bunch of below macros. See all_architectires[] table in + * gcc/config/arm/arm.c. On a side note it defines + * __ARMEL__/__ARMEB__ for little-/big-endian. */ +# elif defined(__ARM_ARCH) +# define __ARM_ARCH__ __ARM_ARCH +# elif defined(__ARM_ARCH_8A__) +# define __ARM_ARCH__ 8 +# elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || \ + defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__) || \ + defined(__ARM_ARCH_7EM__) +# define __ARM_ARCH__ 7 +# elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \ + defined(__ARM_ARCH_6K__)|| defined(__ARM_ARCH_6M__) || \ + defined(__ARM_ARCH_6Z__)|| defined(__ARM_ARCH_6ZK__) || \ + defined(__ARM_ARCH_6T2__) +# define __ARM_ARCH__ 6 +# elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || \ + defined(__ARM_ARCH_5E__)|| defined(__ARM_ARCH_5TE__) || \ + defined(__ARM_ARCH_5TEJ__) +# define __ARM_ARCH__ 5 +# elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) +# define __ARM_ARCH__ 4 +# else +# error "unsupported ARM architecture" +# endif +# endif +#endif + +/* Even when building for 32-bit ARM, support for aarch64 crypto instructions + * will be included. */ +#define __ARM_MAX_ARCH__ 8 + +#if !__ASSEMBLER__ + +/* OPENSSL_armcap_P contains flags describing the capabilities of the CPU and + * is easy for assembly code to acesss. For C code, see the functions in + * |cpu.h|. */ +extern uint32_t OPENSSL_armcap_P; + +#endif /* !__ASSEMBLER__ */ + +/* ARMV7_NEON is true when a NEON unit is present in the current CPU. */ +#define ARMV7_NEON (1 << 0) + +/* ARMV7_NEON_FUNCTIONAL is true when the NEON unit doesn't contain subtle bugs. + * The Poly1305 NEON code is known to trigger bugs in the NEON units of some + * phones. If this bit isn't set then the Poly1305 NEON code won't be used. + * See https://code.google.com/p/chromium/issues/detail?id=341598. */ +#define ARMV7_NEON_FUNCTIONAL (1 << 10) + +/* ARMV8_AES indicates support for hardware AES instructions. */ +#define ARMV8_AES (1 << 2) + +/* ARMV8_SHA1 indicates support for hardware SHA-1 instructions. */ +#define ARMV8_SHA1 (1 << 3) + +/* ARMV8_SHA256 indicates support for hardware SHA-256 instructions. */ +#define ARMV8_SHA256 (1 << 4) + +/* ARMV8_PMULL indicates support for carryless multiplication. */ +#define ARMV8_PMULL (1 << 5) + + +#endif /* OPENSSL_HEADER_THREAD_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/asn1/CMakeLists.txt new file mode 100644 index 00000000..283636e2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/CMakeLists.txt @@ -0,0 +1,45 @@ +include_directories(. .. ../../include) + +add_library( + asn1 + + OBJECT + + a_bitstr.c + a_bool.c + a_bytes.c + a_d2i_fp.c + a_dup.c + a_enum.c + a_gentm.c + a_i2d_fp.c + a_int.c + a_mbstr.c + a_object.c + a_octet.c + a_print.c + a_strnid.c + a_time.c + a_type.c + a_utctm.c + a_utf8.c + asn1_lib.c + asn1_par.c + asn_pack.c + bio_asn1.c + bio_ndef.c + f_enum.c + f_int.c + f_string.c + t_bitst.c + t_pkey.c + tasn_dec.c + tasn_enc.c + tasn_fre.c + tasn_new.c + tasn_prn.c + tasn_typ.c + tasn_utl.c + x_bignum.c + x_long.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_bitstr.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_bitstr.c new file mode 100644 index 00000000..8bad3394 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_bitstr.c @@ -0,0 +1,255 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include + + +int ASN1_BIT_STRING_set(ASN1_BIT_STRING *x, unsigned char *d, int len) +{ return M_ASN1_BIT_STRING_set(x, d, len); } + +int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a, unsigned char **pp) + { + int ret,j,bits,len; + unsigned char *p,*d; + + if (a == NULL) return(0); + + len=a->length; + + if (len > 0) + { + if (a->flags & ASN1_STRING_FLAG_BITS_LEFT) + { + bits=(int)a->flags&0x07; + } + else + { + for ( ; len > 0; len--) + { + if (a->data[len-1]) break; + } + j=a->data[len-1]; + if (j & 0x01) bits=0; + else if (j & 0x02) bits=1; + else if (j & 0x04) bits=2; + else if (j & 0x08) bits=3; + else if (j & 0x10) bits=4; + else if (j & 0x20) bits=5; + else if (j & 0x40) bits=6; + else if (j & 0x80) bits=7; + else bits=0; /* should not happen */ + } + } + else + bits=0; + + ret=1+len; + if (pp == NULL) return(ret); + + p= *pp; + + *(p++)=(unsigned char)bits; + d=a->data; + memcpy(p,d,len); + p+=len; + if (len > 0) p[-1]&=(0xff< 7) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_BIT_STRING_BITS_LEFT); + goto err; + } + + /* We do this to preserve the settings. If we modify + * the settings, via the _set_bit function, we will recalculate + * on output */ + ret->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear */ + ret->flags|=(ASN1_STRING_FLAG_BITS_LEFT|padding); /* set */ + + if (len-- > 1) /* using one because of the bits left byte */ + { + s=(unsigned char *)OPENSSL_malloc((int)len); + if (s == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + memcpy(s,p,(int)len); + s[len-1]&=(0xff<length=(int)len; + if (ret->data != NULL) OPENSSL_free(ret->data); + ret->data=s; + ret->type=V_ASN1_BIT_STRING; + if (a != NULL) (*a)=ret; + *pp=p; + return(ret); +err: + if ((ret != NULL) && ((a == NULL) || (*a != ret))) + M_ASN1_BIT_STRING_free(ret); + return(NULL); + } + +/* These next 2 functions from Goetz Babin-Ebell + */ +int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value) + { + int w,v,iv; + unsigned char *c; + + w=n/8; + v=1<<(7-(n&0x07)); + iv= ~v; + if (!value) v=0; + + if (a == NULL) + return 0; + + a->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); /* clear, set on write */ + + if ((a->length < (w+1)) || (a->data == NULL)) + { + if (!value) return(1); /* Don't need to set */ + if (a->data == NULL) + c=(unsigned char *)OPENSSL_malloc(w+1); + else + c=(unsigned char *)OPENSSL_realloc_clean(a->data, + a->length, + w+1); + if (c == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return 0; + } + if (w+1-a->length > 0) memset(c+a->length, 0, w+1-a->length); + a->data=c; + a->length=w+1; + } + a->data[w]=((a->data[w])&iv)|v; + while ((a->length > 0) && (a->data[a->length-1] == 0)) + a->length--; + return(1); + } + +int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n) + { + int w,v; + + w=n/8; + v=1<<(7-(n&0x07)); + if ((a == NULL) || (a->length < (w+1)) || (a->data == NULL)) + return(0); + return((a->data[w]&v) != 0); + } + +/* + * Checks if the given bit string contains only bits specified by + * the flags vector. Returns 0 if there is at least one bit set in 'a' + * which is not specified in 'flags', 1 otherwise. + * 'len' is the length of 'flags'. + */ +int ASN1_BIT_STRING_check(ASN1_BIT_STRING *a, + unsigned char *flags, int flags_len) + { + int i, ok; + /* Check if there is one bit set at all. */ + if (!a || !a->data) return 1; + + /* Check each byte of the internal representation of the bit string. */ + ok = 1; + for (i = 0; i < a->length && ok; ++i) + { + unsigned char mask = i < flags_len ? ~flags[i] : 0xff; + /* We are done if there is an unneeded bit set. */ + ok = (a->data[i] & mask) == 0; + } + return ok; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_bool.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_bool.c new file mode 100644 index 00000000..826bcf43 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_bool.c @@ -0,0 +1,112 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +int i2d_ASN1_BOOLEAN(int a, unsigned char **pp) + { + int r; + unsigned char *p; + + r=ASN1_object_size(0,1,V_ASN1_BOOLEAN); + if (pp == NULL) return(r); + p= *pp; + + ASN1_put_object(&p,0,1,V_ASN1_BOOLEAN,V_ASN1_UNIVERSAL); + *(p++)= (unsigned char)a; + *pp=p; + return(r); + } + +int d2i_ASN1_BOOLEAN(int *a, const unsigned char **pp, long length) + { + int ret= -1; + const unsigned char *p; + long len; + int inf,tag,xclass; + int i=0; + + p= *pp; + inf=ASN1_get_object(&p,&len,&tag,&xclass,length); + if (inf & 0x80) + { + i=ASN1_R_BAD_OBJECT_HEADER; + goto err; + } + + if (tag != V_ASN1_BOOLEAN) + { + i=ASN1_R_EXPECTING_A_BOOLEAN; + goto err; + } + + if (len != 1) + { + i=ASN1_R_BOOLEAN_IS_WRONG_LENGTH; + goto err; + } + ret= (int)*(p++); + if (a != NULL) (*a)=ret; + *pp=p; + return(ret); +err: + OPENSSL_PUT_ERROR(ASN1, i); + return(ret); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_bytes.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_bytes.c new file mode 100644 index 00000000..19043755 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_bytes.c @@ -0,0 +1,317 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include + + +static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c); +/* type is a 'bitmap' of acceptable string types. + */ +ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a, const unsigned char **pp, + long length, int type) + { + ASN1_STRING *ret=NULL; + const unsigned char *p; + unsigned char *s; + long len; + int inf,tag,xclass; + int i=0; + + p= *pp; + inf=ASN1_get_object(&p,&len,&tag,&xclass,length); + if (inf & 0x80) goto err; + + if (tag >= 32) + { + i=ASN1_R_TAG_VALUE_TOO_HIGH; + goto err; + } + if (!(ASN1_tag2bit(tag) & type)) + { + i=ASN1_R_WRONG_TYPE; + goto err; + } + + /* If a bit-string, exit early */ + if (tag == V_ASN1_BIT_STRING) + return(d2i_ASN1_BIT_STRING(a,pp,length)); + + if ((a == NULL) || ((*a) == NULL)) + { + if ((ret=ASN1_STRING_new()) == NULL) return(NULL); + } + else + ret=(*a); + + if (len != 0) + { + s=(unsigned char *)OPENSSL_malloc((int)len+1); + if (s == NULL) + { + i=ERR_R_MALLOC_FAILURE; + goto err; + } + memcpy(s,p,(int)len); + s[len]='\0'; + p+=len; + } + else + s=NULL; + + if (ret->data != NULL) OPENSSL_free(ret->data); + ret->length=(int)len; + ret->data=s; + ret->type=tag; + if (a != NULL) (*a)=ret; + *pp=p; + return(ret); +err: + OPENSSL_PUT_ERROR(ASN1, i); + if ((ret != NULL) && ((a == NULL) || (*a != ret))) + ASN1_STRING_free(ret); + return(NULL); + } + +int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass) + { + int ret,r,constructed; + unsigned char *p; + + if (a == NULL) return(0); + + if (tag == V_ASN1_BIT_STRING) + return(i2d_ASN1_BIT_STRING(a,pp)); + + ret=a->length; + r=ASN1_object_size(0,ret,tag); + if (pp == NULL) return(r); + p= *pp; + + if ((tag == V_ASN1_SEQUENCE) || (tag == V_ASN1_SET)) + constructed=1; + else + constructed=0; + ASN1_put_object(&p,constructed,ret,tag,xclass); + memcpy(p,a->data,a->length); + p+=a->length; + *pp= p; + return(r); + } + +ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp, + long length, int Ptag, int Pclass) + { + ASN1_STRING *ret=NULL; + const unsigned char *p; + unsigned char *s; + long len; + int inf,tag,xclass; + int i=0; + + if ((a == NULL) || ((*a) == NULL)) + { + if ((ret=ASN1_STRING_new()) == NULL) return(NULL); + } + else + ret=(*a); + + p= *pp; + inf=ASN1_get_object(&p,&len,&tag,&xclass,length); + if (inf & 0x80) + { + i=ASN1_R_BAD_OBJECT_HEADER; + goto err; + } + + if (tag != Ptag) + { + i=ASN1_R_WRONG_TAG; + goto err; + } + + if (inf & V_ASN1_CONSTRUCTED) + { + ASN1_const_CTX c; + + c.pp=pp; + c.p=p; + c.inf=inf; + c.slen=len; + c.tag=Ptag; + c.xclass=Pclass; + c.max=(length == 0)?0:(p+length); + if (!asn1_collate_primitive(ret,&c)) + goto err; + else + { + p=c.p; + } + } + else + { + if (len != 0) + { + if ((ret->length < len) || (ret->data == NULL)) + { + if (ret->data != NULL) OPENSSL_free(ret->data); + s=(unsigned char *)OPENSSL_malloc((int)len + 1); + if (s == NULL) + { + i=ERR_R_MALLOC_FAILURE; + goto err; + } + } + else + s=ret->data; + memcpy(s,p,(int)len); + s[len] = '\0'; + p+=len; + } + else + { + s=NULL; + if (ret->data != NULL) OPENSSL_free(ret->data); + } + + ret->length=(int)len; + ret->data=s; + ret->type=Ptag; + } + + if (a != NULL) (*a)=ret; + *pp=p; + return(ret); +err: + if ((ret != NULL) && ((a == NULL) || (*a != ret))) + ASN1_STRING_free(ret); + OPENSSL_PUT_ERROR(ASN1, i); + return(NULL); + } + + +/* We are about to parse 0..n d2i_ASN1_bytes objects, we are to collapse + * them into the one structure that is then returned */ +/* There have been a few bug fixes for this function from + * Paul Keogh , many thanks to him */ +static int asn1_collate_primitive(ASN1_STRING *a, ASN1_const_CTX *c) + { + ASN1_STRING *os=NULL; + BUF_MEM b; + int num; + + b.length=0; + b.max=0; + b.data=NULL; + + if (a == NULL) + { + c->error=ERR_R_PASSED_NULL_PARAMETER; + goto err; + } + + num=0; + for (;;) + { + if (c->inf & 1) + { + c->eos=ASN1_const_check_infinite_end(&c->p, + (long)(c->max-c->p)); + if (c->eos) break; + } + else + { + if (c->slen <= 0) break; + } + + c->q=c->p; + if (d2i_ASN1_bytes(&os,&c->p,c->max-c->p,c->tag,c->xclass) + == NULL) + { + c->error=ERR_R_ASN1_LIB; + goto err; + } + + if (!BUF_MEM_grow_clean(&b,num+os->length)) + { + c->error=ERR_R_BUF_LIB; + goto err; + } + memcpy(&(b.data[num]),os->data,os->length); + if (!(c->inf & 1)) + c->slen-=(c->p-c->q); + num+=os->length; + } + + if (!asn1_const_Finish(c)) goto err; + + a->length=num; + if (a->data != NULL) OPENSSL_free(a->data); + a->data=(unsigned char *)b.data; + if (os != NULL) ASN1_STRING_free(os); + return(1); +err: + OPENSSL_PUT_ERROR(ASN1, c->error); + if (os != NULL) ASN1_STRING_free(os); + if (b.data != NULL) OPENSSL_free(b.data); + return(0); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_d2i_fp.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_d2i_fp.c new file mode 100644 index 00000000..97ec75b5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_d2i_fp.c @@ -0,0 +1,286 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include + + +static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb); + +#ifndef NO_OLD_ASN1 +#ifndef OPENSSL_NO_FP_API + +void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x) + { + BIO *b; + void *ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB); + return(NULL); + } + BIO_set_fp(b,in,BIO_NOCLOSE); + ret=ASN1_d2i_bio(xnew,d2i,b,x); + BIO_free(b); + return(ret); + } +#endif + +void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x) + { + BUF_MEM *b = NULL; + const unsigned char *p; + void *ret=NULL; + int len; + + len = asn1_d2i_read_bio(in, &b); + if(len < 0) goto err; + + p=(unsigned char *)b->data; + ret=d2i(x,&p,len); +err: + if (b != NULL) BUF_MEM_free(b); + return(ret); + } + +#endif + +void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x) + { + BUF_MEM *b = NULL; + const unsigned char *p; + void *ret=NULL; + int len; + + len = asn1_d2i_read_bio(in, &b); + if(len < 0) goto err; + + p=(const unsigned char *)b->data; + ret=ASN1_item_d2i(x,&p,len, it); +err: + if (b != NULL) BUF_MEM_free(b); + return(ret); + } + +#ifndef OPENSSL_NO_FP_API +void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x) + { + BIO *b; + char *ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB); + return(NULL); + } + BIO_set_fp(b,in,BIO_NOCLOSE); + ret=ASN1_item_d2i_bio(it,b,x); + BIO_free(b); + return(ret); + } +#endif + +#define HEADER_SIZE 8 +static int asn1_d2i_read_bio(BIO *in, BUF_MEM **pb) + { + BUF_MEM *b; + unsigned char *p; + int i; + ASN1_const_CTX c; + size_t want=HEADER_SIZE; + int eos=0; + size_t off=0; + size_t len=0; + + b=BUF_MEM_new(); + if (b == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return -1; + } + + ERR_clear_error(); + for (;;) + { + if (want >= (len-off)) + { + want-=(len-off); + + if (len + want < len || !BUF_MEM_grow_clean(b,len+want)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + i=BIO_read(in,&(b->data[len]),want); + if ((i < 0) && ((len-off) == 0)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA); + goto err; + } + if (i > 0) + { + if (len+i < len) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); + goto err; + } + len+=i; + } + } + /* else data already loaded */ + + p=(unsigned char *)&(b->data[off]); + c.p=p; + c.inf=ASN1_get_object(&(c.p),&(c.slen),&(c.tag),&(c.xclass), + len-off); + if (c.inf & 0x80) + { + uint32_t e; + + e=ERR_GET_REASON(ERR_peek_error()); + if (e != ASN1_R_TOO_LONG) + goto err; + else + ERR_clear_error(); /* clear error */ + } + i=c.p-p;/* header length */ + off+=i; /* end of data */ + + if (c.inf & 1) + { + /* no data body so go round again */ + eos++; + if (eos < 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_HEADER_TOO_LONG); + goto err; + } + want=HEADER_SIZE; + } + else if (eos && (c.slen == 0) && (c.tag == V_ASN1_EOC)) + { + /* eos value, so go back and read another header */ + eos--; + if (eos <= 0) + break; + else + want=HEADER_SIZE; + } + else + { + /* suck in c.slen bytes of data */ + want=c.slen; + if (want > (len-off)) + { + want-=(len-off); + if (want > INT_MAX /* BIO_read takes an int length */ || + len+want < len) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); + goto err; + } + if (!BUF_MEM_grow_clean(b,len+want)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + while (want > 0) + { + i=BIO_read(in,&(b->data[len]),want); + if (i <= 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ENOUGH_DATA); + goto err; + } + /* This can't overflow because + * |len+want| didn't overflow. */ + len+=i; + want-=i; + } + } + if (off + c.slen < off) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); + goto err; + } + off+=c.slen; + if (eos <= 0) + { + break; + } + else + want=HEADER_SIZE; + } + } + + if (off > INT_MAX) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); + goto err; + } + + *pb = b; + return off; +err: + if (b != NULL) BUF_MEM_free(b); + return -1; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_dup.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_dup.c new file mode 100644 index 00000000..5e87457c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_dup.c @@ -0,0 +1,103 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x) + { + unsigned char *b,*p; + const unsigned char *p2; + int i; + char *ret; + + if (x == NULL) return(NULL); + + i=i2d(x,NULL); + b=OPENSSL_malloc(i+10); + if (b == NULL) + { OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); return(NULL); } + p= b; + i=i2d(x,&p); + p2= b; + ret=d2i(NULL,&p2,i); + OPENSSL_free(b); + return(ret); + } + +/* ASN1_ITEM version of dup: this follows the model above except we don't need + * to allocate the buffer. At some point this could be rewritten to directly dup + * the underlying structure instead of doing and encode and decode. */ +void *ASN1_item_dup(const ASN1_ITEM *it, void *x) + { + unsigned char *b = NULL; + const unsigned char *p; + long i; + void *ret; + + if (x == NULL) return(NULL); + + i=ASN1_item_i2d(x,&b,it); + if (b == NULL) + { OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); return(NULL); } + p= b; + ret=ASN1_item_d2i(NULL,&p,i, it); + OPENSSL_free(b); + return(ret); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_enum.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_enum.c new file mode 100644 index 00000000..579dafd3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_enum.c @@ -0,0 +1,183 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include + + +/* + * Code for ENUMERATED type: identical to INTEGER apart from a different tag. + * for comments on encoding see a_int.c + */ + +int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v) + { + int j,k; + unsigned int i; + unsigned char buf[sizeof(long)+1]; + long d; + + a->type=V_ASN1_ENUMERATED; + if (a->length < (int)(sizeof(long)+1)) + { + if (a->data != NULL) + OPENSSL_free(a->data); + if ((a->data=(unsigned char *)OPENSSL_malloc(sizeof(long)+1)) != NULL) + memset((char *)a->data,0,sizeof(long)+1); + } + if (a->data == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return(0); + } + d=v; + if (d < 0) + { + d= -d; + a->type=V_ASN1_NEG_ENUMERATED; + } + + for (i=0; i>=8; + } + j=0; + for (k=i-1; k >=0; k--) + a->data[j++]=buf[k]; + a->length=j; + return(1); + } + +long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a) + { + int neg=0,i; + long r=0; + + if (a == NULL) return(0L); + i=a->type; + if (i == V_ASN1_NEG_ENUMERATED) + neg=1; + else if (i != V_ASN1_ENUMERATED) + return -1; + + if (a->length > (int)sizeof(long)) + { + /* hmm... a bit ugly */ + return(0xffffffffL); + } + if (a->data == NULL) + return 0; + + for (i=0; ilength; i++) + { + r<<=8; + r|=(unsigned char)a->data[i]; + } + if (neg) r= -r; + return(r); + } + +ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai) + { + ASN1_ENUMERATED *ret; + int len,j; + + if (ai == NULL) + ret=M_ASN1_ENUMERATED_new(); + else + ret=ai; + if (ret == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + if(BN_is_negative(bn)) ret->type = V_ASN1_NEG_ENUMERATED; + else ret->type=V_ASN1_ENUMERATED; + j=BN_num_bits(bn); + len=((j == 0)?0:((j/8)+1)); + if (ret->length < len+4) + { + unsigned char *new_data=OPENSSL_realloc(ret->data, len+4); + if (!new_data) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + ret->data=new_data; + } + + ret->length=BN_bn2bin(bn,ret->data); + return(ret); +err: + if (ret != ai) M_ASN1_ENUMERATED_free(ret); + return(NULL); + } + +BIGNUM *ASN1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai, BIGNUM *bn) + { + BIGNUM *ret; + + if ((ret=BN_bin2bn(ai->data,ai->length,bn)) == NULL) + OPENSSL_PUT_ERROR(ASN1, ASN1_R_BN_LIB); + else if(ai->type == V_ASN1_NEG_ENUMERATED) BN_set_negative(ret,1); + return(ret); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_gentm.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_gentm.c new file mode 100644 index 00000000..7cb18a95 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_gentm.c @@ -0,0 +1,255 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + + +int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d) + { + static const int min[9]={ 0, 0, 1, 1, 0, 0, 0, 0, 0}; + static const int max[9]={99, 99,12,31,23,59,59,12,59}; + char *a; + int n,i,l,o; + + if (d->type != V_ASN1_GENERALIZEDTIME) return(0); + l=d->length; + a=(char *)d->data; + o=0; + /* GENERALIZEDTIME is similar to UTCTIME except the year is + * represented as YYYY. This stuff treats everything as a two digit + * field so make first two fields 00 to 99 + */ + if (l < 13) goto err; + for (i=0; i<7; i++) + { + if ((i == 6) && ((a[o] == 'Z') || + (a[o] == '+') || (a[o] == '-'))) + { + i++; + if (tm) + tm->tm_sec = 0; + break; + } + if ((a[o] < '0') || (a[o] > '9')) goto err; + n= a[o]-'0'; + if (++o > l) goto err; + + if ((a[o] < '0') || (a[o] > '9')) goto err; + n=(n*10)+ a[o]-'0'; + if (++o > l) goto err; + + if ((n < min[i]) || (n > max[i])) goto err; + if (tm) + { + switch(i) + { + case 0: + tm->tm_year = n * 100 - 1900; + break; + case 1: + tm->tm_year += n; + break; + case 2: + tm->tm_mon = n - 1; + break; + case 3: + tm->tm_mday = n; + break; + case 4: + tm->tm_hour = n; + break; + case 5: + tm->tm_min = n; + break; + case 6: + tm->tm_sec = n; + break; + } + } + } + /* Optional fractional seconds: decimal point followed by one + * or more digits. + */ + if (a[o] == '.') + { + if (++o > l) goto err; + i = o; + while ((a[o] >= '0') && (a[o] <= '9') && (o <= l)) + o++; + /* Must have at least one digit after decimal point */ + if (i == o) goto err; + } + + if (a[o] == 'Z') + o++; + else if ((a[o] == '+') || (a[o] == '-')) + { + int offsign = a[o] == '-' ? -1 : 1, offset = 0; + o++; + if (o+4 > l) goto err; + for (i=7; i<9; i++) + { + if ((a[o] < '0') || (a[o] > '9')) goto err; + n= a[o]-'0'; + o++; + if ((a[o] < '0') || (a[o] > '9')) goto err; + n=(n*10)+ a[o]-'0'; + if ((n < min[i]) || (n > max[i])) goto err; + if (tm) + { + if (i == 7) + offset = n * 3600; + else if (i == 8) + offset += n * 60; + } + o++; + } + if (offset && !OPENSSL_gmtime_adj(tm, 0, offset * offsign)) + return 0; + } + else if (a[o]) + { + /* Missing time zone information. */ + goto err; + } + return(o == l); +err: + return(0); + } + +int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *d) + { + return asn1_generalizedtime_to_tm(NULL, d); + } + +int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str) + { + ASN1_GENERALIZEDTIME t; + + t.type=V_ASN1_GENERALIZEDTIME; + t.length=strlen(str); + t.data=(unsigned char *)str; + if (ASN1_GENERALIZEDTIME_check(&t)) + { + if (s != NULL) + { + if (!ASN1_STRING_set((ASN1_STRING *)s, + (unsigned char *)str,t.length)) + return 0; + s->type=V_ASN1_GENERALIZEDTIME; + } + return(1); + } + else + return(0); + } + +ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s, + time_t t) + { + return ASN1_GENERALIZEDTIME_adj(s, t, 0, 0); + } + +ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, + time_t t, int offset_day, long offset_sec) + { + char *p; + struct tm *ts; + struct tm data; + size_t len = 20; + + if (s == NULL) + s=M_ASN1_GENERALIZEDTIME_new(); + if (s == NULL) + return(NULL); + + ts=OPENSSL_gmtime(&t, &data); + if (ts == NULL) + return(NULL); + + if (offset_day || offset_sec) + { + if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec)) + return NULL; + } + + p=(char *)s->data; + if ((p == NULL) || ((size_t)s->length < len)) + { + p=OPENSSL_malloc(len); + if (p == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return(NULL); + } + if (s->data != NULL) + OPENSSL_free(s->data); + s->data=(unsigned char *)p; + } + + BIO_snprintf(p,len,"%04d%02d%02d%02d%02d%02dZ",ts->tm_year + 1900, + ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec); + s->length=strlen(p); + s->type=V_ASN1_GENERALIZEDTIME; + return(s); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_i2d_fp.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_i2d_fp.c new file mode 100644 index 00000000..8a6ce256 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_i2d_fp.c @@ -0,0 +1,154 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +int ASN1_i2d_fp(i2d_of_void *i2d, FILE *out, void *x) + { + BIO *b; + int ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,out,BIO_NOCLOSE); + ret=ASN1_i2d_bio(i2d,b,x); + BIO_free(b); + return(ret); + } + +int ASN1_i2d_bio(i2d_of_void *i2d, BIO *out, unsigned char *x) + { + char *b; + unsigned char *p; + int i,j=0,n,ret=1; + + n=i2d(x,NULL); + b=(char *)OPENSSL_malloc(n); + if (b == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return(0); + } + + p=(unsigned char *)b; + i2d(x,&p); + + for (;;) + { + i=BIO_write(out,&(b[j]),n); + if (i == n) break; + if (i <= 0) + { + ret=0; + break; + } + j+=i; + n-=i; + } + OPENSSL_free(b); + return(ret); + } + +int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x) + { + BIO *b; + int ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,out,BIO_NOCLOSE); + ret=ASN1_item_i2d_bio(it,b,x); + BIO_free(b); + return(ret); + } + +int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x) + { + unsigned char *b = NULL; + int i,j=0,n,ret=1; + + n = ASN1_item_i2d(x, &b, it); + if (b == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return(0); + } + + for (;;) + { + i=BIO_write(out,&(b[j]),n); + if (i == n) break; + if (i <= 0) + { + ret=0; + break; + } + j+=i; + n-=i; + } + OPENSSL_free(b); + return(ret); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_int.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_int.c new file mode 100644 index 00000000..9a565343 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_int.c @@ -0,0 +1,456 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include + + +ASN1_INTEGER *ASN1_INTEGER_dup(const ASN1_INTEGER *x) +{ return M_ASN1_INTEGER_dup(x);} + +int ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y) + { + int neg, ret; + /* Compare signs */ + neg = x->type & V_ASN1_NEG; + if (neg != (y->type & V_ASN1_NEG)) + { + if (neg) + return -1; + else + return 1; + } + + ret = ASN1_STRING_cmp(x, y); + + if (neg) + return -ret; + else + return ret; + } + + +/* + * This converts an ASN1 INTEGER into its content encoding. + * The internal representation is an ASN1_STRING whose data is a big endian + * representation of the value, ignoring the sign. The sign is determined by + * the type: V_ASN1_INTEGER for positive and V_ASN1_NEG_INTEGER for negative. + * + * Positive integers are no problem: they are almost the same as the DER + * encoding, except if the first byte is >= 0x80 we need to add a zero pad. + * + * Negative integers are a bit trickier... + * The DER representation of negative integers is in 2s complement form. + * The internal form is converted by complementing each octet and finally + * adding one to the result. This can be done less messily with a little trick. + * If the internal form has trailing zeroes then they will become FF by the + * complement and 0 by the add one (due to carry) so just copy as many trailing + * zeros to the destination as there are in the source. The carry will add one + * to the last none zero octet: so complement this octet and add one and finally + * complement any left over until you get to the start of the string. + * + * Padding is a little trickier too. If the first bytes is > 0x80 then we pad + * with 0xff. However if the first byte is 0x80 and one of the following bytes + * is non-zero we pad with 0xff. The reason for this distinction is that 0x80 + * followed by optional zeros isn't padded. + */ + +int i2c_ASN1_INTEGER(ASN1_INTEGER *a, unsigned char **pp) + { + int pad=0,ret,i,neg; + unsigned char *p,*n,pb=0; + + if (a == NULL) return(0); + neg=a->type & V_ASN1_NEG; + if (a->length == 0) + ret=1; + else + { + ret=a->length; + i=a->data[0]; + if (!neg && (i > 127)) { + pad=1; + pb=0; + } else if(neg) { + if(i>128) { + pad=1; + pb=0xFF; + } else if(i == 128) { + /* + * Special case: if any other bytes non zero we pad: + * otherwise we don't. + */ + for(i = 1; i < a->length; i++) if(a->data[i]) { + pad=1; + pb=0xFF; + break; + } + } + } + ret+=pad; + } + if (pp == NULL) return(ret); + p= *pp; + + if (pad) *(p++)=pb; + if (a->length == 0) *(p++)=0; + else if (!neg) memcpy(p,a->data,(unsigned int)a->length); + else { + /* Begin at the end of the encoding */ + n=a->data + a->length - 1; + p += a->length - 1; + i = a->length; + /* Copy zeros to destination as long as source is zero */ + while(!*n) { + *(p--) = 0; + n--; + i--; + } + /* Complement and increment next octet */ + *(p--) = ((*(n--)) ^ 0xff) + 1; + i--; + /* Complement any octets left */ + for(;i > 0; i--) *(p--) = *(n--) ^ 0xff; + } + + *pp+=ret; + return(ret); + } + +/* Convert just ASN1 INTEGER content octets to ASN1_INTEGER structure */ + +ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a, const unsigned char **pp, + long len) + { + ASN1_INTEGER *ret=NULL; + const unsigned char *p, *pend; + unsigned char *to,*s; + int i; + + if ((a == NULL) || ((*a) == NULL)) + { + if ((ret=M_ASN1_INTEGER_new()) == NULL) return(NULL); + ret->type=V_ASN1_INTEGER; + } + else + ret=(*a); + + p= *pp; + pend = p + len; + + /* We must OPENSSL_malloc stuff, even for 0 bytes otherwise it + * signifies a missing NULL parameter. */ + s=(unsigned char *)OPENSSL_malloc((int)len+1); + if (s == NULL) + { + i=ERR_R_MALLOC_FAILURE; + goto err; + } + to=s; + if(!len) { + /* Strictly speaking this is an illegal INTEGER but we + * tolerate it. + */ + ret->type=V_ASN1_INTEGER; + } else if (*p & 0x80) /* a negative number */ + { + ret->type=V_ASN1_NEG_INTEGER; + if ((*p == 0xff) && (len != 1)) { + p++; + len--; + } + i = len; + p += i - 1; + to += i - 1; + while((!*p) && i) { + *(to--) = 0; + i--; + p--; + } + /* Special case: if all zeros then the number will be of + * the form FF followed by n zero bytes: this corresponds to + * 1 followed by n zero bytes. We've already written n zeros + * so we just append an extra one and set the first byte to + * a 1. This is treated separately because it is the only case + * where the number of bytes is larger than len. + */ + if(!i) { + *s = 1; + s[len] = 0; + len++; + } else { + *(to--) = (*(p--) ^ 0xff) + 1; + i--; + for(;i > 0; i--) *(to--) = *(p--) ^ 0xff; + } + } else { + ret->type=V_ASN1_INTEGER; + if ((*p == 0) && (len != 1)) + { + p++; + len--; + } + memcpy(s,p,(int)len); + } + + if (ret->data != NULL) OPENSSL_free(ret->data); + ret->data=s; + ret->length=(int)len; + if (a != NULL) (*a)=ret; + *pp=pend; + return(ret); +err: + OPENSSL_PUT_ERROR(ASN1, i); + if ((ret != NULL) && ((a == NULL) || (*a != ret))) + M_ASN1_INTEGER_free(ret); + return(NULL); + } + + +/* This is a version of d2i_ASN1_INTEGER that ignores the sign bit of + * ASN1 integers: some broken software can encode a positive INTEGER + * with its MSB set as negative (it doesn't add a padding zero). + */ + +ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a, const unsigned char **pp, + long length) + { + ASN1_INTEGER *ret=NULL; + const unsigned char *p; + unsigned char *s; + long len; + int inf,tag,xclass; + int i; + + if ((a == NULL) || ((*a) == NULL)) + { + if ((ret=M_ASN1_INTEGER_new()) == NULL) return(NULL); + ret->type=V_ASN1_INTEGER; + } + else + ret=(*a); + + p= *pp; + inf=ASN1_get_object(&p,&len,&tag,&xclass,length); + if (inf & 0x80) + { + i=ASN1_R_BAD_OBJECT_HEADER; + goto err; + } + + if (tag != V_ASN1_INTEGER) + { + i=ASN1_R_EXPECTING_AN_INTEGER; + goto err; + } + + /* We must OPENSSL_malloc stuff, even for 0 bytes otherwise it + * signifies a missing NULL parameter. */ + s=(unsigned char *)OPENSSL_malloc((int)len+1); + if (s == NULL) + { + i=ERR_R_MALLOC_FAILURE; + goto err; + } + ret->type=V_ASN1_INTEGER; + if(len) { + if ((*p == 0) && (len != 1)) + { + p++; + len--; + } + memcpy(s,p,(int)len); + p+=len; + } + + if (ret->data != NULL) OPENSSL_free(ret->data); + ret->data=s; + ret->length=(int)len; + if (a != NULL) (*a)=ret; + *pp=p; + return(ret); +err: + OPENSSL_PUT_ERROR(ASN1, i); + if ((ret != NULL) && ((a == NULL) || (*a != ret))) + M_ASN1_INTEGER_free(ret); + return(NULL); + } + +int ASN1_INTEGER_set(ASN1_INTEGER *a, long v) + { + int j,k; + unsigned int i; + unsigned char buf[sizeof(long)+1]; + long d; + + a->type=V_ASN1_INTEGER; + if (a->length < (int)(sizeof(long)+1)) + { + if (a->data != NULL) + OPENSSL_free(a->data); + if ((a->data=(unsigned char *)OPENSSL_malloc(sizeof(long)+1)) != NULL) + memset((char *)a->data,0,sizeof(long)+1); + } + if (a->data == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return(0); + } + d=v; + if (d < 0) + { + d= -d; + a->type=V_ASN1_NEG_INTEGER; + } + + for (i=0; i>=8; + } + j=0; + for (k=i-1; k >=0; k--) + a->data[j++]=buf[k]; + a->length=j; + return(1); + } + +long ASN1_INTEGER_get(const ASN1_INTEGER *a) + { + int neg=0,i; + long r=0; + + if (a == NULL) return(0L); + i=a->type; + if (i == V_ASN1_NEG_INTEGER) + neg=1; + else if (i != V_ASN1_INTEGER) + return -1; + + if (a->length > (int)sizeof(long)) + { + /* hmm... a bit ugly, return all ones */ + return -1; + } + if (a->data == NULL) + return 0; + + for (i=0; ilength; i++) + { + r<<=8; + r|=(unsigned char)a->data[i]; + } + if (neg) r= -r; + return(r); + } + +ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai) + { + ASN1_INTEGER *ret; + int len,j; + + if (ai == NULL) + ret=M_ASN1_INTEGER_new(); + else + ret=ai; + if (ret == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + if (BN_is_negative(bn) && !BN_is_zero(bn)) + ret->type = V_ASN1_NEG_INTEGER; + else ret->type=V_ASN1_INTEGER; + j=BN_num_bits(bn); + len=((j == 0)?0:((j/8)+1)); + if (ret->length < len+4) + { + unsigned char *new_data=OPENSSL_realloc(ret->data, len+4); + if (!new_data) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + ret->data=new_data; + } + ret->length=BN_bn2bin(bn,ret->data); + /* Correct zero case */ + if(!ret->length) + { + ret->data[0] = 0; + ret->length = 1; + } + return(ret); +err: + if (ret != ai) M_ASN1_INTEGER_free(ret); + return(NULL); + } + +BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai, BIGNUM *bn) + { + BIGNUM *ret; + + if ((ret=BN_bin2bn(ai->data,ai->length,bn)) == NULL) + OPENSSL_PUT_ERROR(ASN1, ASN1_R_BN_LIB); + else if(ai->type == V_ASN1_NEG_INTEGER) + BN_set_negative(ret, 1); + return(ret); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_mbstr.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_mbstr.c new file mode 100644 index 00000000..42806d1a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_mbstr.c @@ -0,0 +1,390 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include + + +static int traverse_string(const unsigned char *p, int len, int inform, + int (*rfunc)(unsigned long value, void *in), void *arg); +static int in_utf8(unsigned long value, void *arg); +static int out_utf8(unsigned long value, void *arg); +static int type_str(unsigned long value, void *arg); +static int cpy_asc(unsigned long value, void *arg); +static int cpy_bmp(unsigned long value, void *arg); +static int cpy_univ(unsigned long value, void *arg); +static int cpy_utf8(unsigned long value, void *arg); +static int is_printable(unsigned long value); + +/* These functions take a string in UTF8, ASCII or multibyte form and + * a mask of permissible ASN1 string types. It then works out the minimal + * type (using the order Printable < IA5 < T61 < BMP < Universal < UTF8) + * and creates a string of the correct type with the supplied data. + * Yes this is horrible: it has to be :-( + * The 'ncopy' form checks minimum and maximum size limits too. + */ + +int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len, + int inform, unsigned long mask) +{ + return ASN1_mbstring_ncopy(out, in, len, inform, mask, 0, 0); +} + +int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, + int inform, unsigned long mask, + long minsize, long maxsize) +{ + int str_type; + int ret; + char free_out; + int outform, outlen = 0; + ASN1_STRING *dest; + unsigned char *p; + int nchar; + char strbuf[32]; + int (*cpyfunc)(unsigned long,void *) = NULL; + if(len == -1) len = strlen((const char *)in); + if(!mask) mask = DIRSTRING_TYPE; + + /* First do a string check and work out the number of characters */ + switch(inform) { + + case MBSTRING_BMP: + if(len & 1) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_BMPSTRING_LENGTH); + return -1; + } + nchar = len >> 1; + break; + + case MBSTRING_UNIV: + if(len & 3) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_UNIVERSALSTRING_LENGTH); + return -1; + } + nchar = len >> 2; + break; + + case MBSTRING_UTF8: + nchar = 0; + /* This counts the characters and does utf8 syntax checking */ + ret = traverse_string(in, len, MBSTRING_UTF8, in_utf8, &nchar); + if(ret < 0) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_UTF8STRING); + return -1; + } + break; + + case MBSTRING_ASC: + nchar = len; + break; + + default: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_FORMAT); + return -1; + } + + if((minsize > 0) && (nchar < minsize)) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_SHORT); + BIO_snprintf(strbuf, sizeof strbuf, "%ld", minsize); + ERR_add_error_data(2, "minsize=", strbuf); + return -1; + } + + if((maxsize > 0) && (nchar > maxsize)) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_LONG); + BIO_snprintf(strbuf, sizeof strbuf, "%ld", maxsize); + ERR_add_error_data(2, "maxsize=", strbuf); + return -1; + } + + /* Now work out minimal type (if any) */ + if(traverse_string(in, len, inform, type_str, &mask) < 0) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS); + return -1; + } + + + /* Now work out output format and string type */ + outform = MBSTRING_ASC; + if(mask & B_ASN1_PRINTABLESTRING) str_type = V_ASN1_PRINTABLESTRING; + else if(mask & B_ASN1_IA5STRING) str_type = V_ASN1_IA5STRING; + else if(mask & B_ASN1_T61STRING) str_type = V_ASN1_T61STRING; + else if(mask & B_ASN1_BMPSTRING) { + str_type = V_ASN1_BMPSTRING; + outform = MBSTRING_BMP; + } else if(mask & B_ASN1_UNIVERSALSTRING) { + str_type = V_ASN1_UNIVERSALSTRING; + outform = MBSTRING_UNIV; + } else { + str_type = V_ASN1_UTF8STRING; + outform = MBSTRING_UTF8; + } + if(!out) return str_type; + if(*out) { + free_out = 0; + dest = *out; + if(dest->data) { + dest->length = 0; + OPENSSL_free(dest->data); + dest->data = NULL; + } + dest->type = str_type; + } else { + free_out = 1; + dest = ASN1_STRING_type_new(str_type); + if(!dest) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return -1; + } + *out = dest; + } + /* If both the same type just copy across */ + if(inform == outform) { + if(!ASN1_STRING_set(dest, in, len)) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return -1; + } + return str_type; + } + + /* Work out how much space the destination will need */ + switch(outform) { + case MBSTRING_ASC: + outlen = nchar; + cpyfunc = cpy_asc; + break; + + case MBSTRING_BMP: + outlen = nchar << 1; + cpyfunc = cpy_bmp; + break; + + case MBSTRING_UNIV: + outlen = nchar << 2; + cpyfunc = cpy_univ; + break; + + case MBSTRING_UTF8: + outlen = 0; + traverse_string(in, len, inform, out_utf8, &outlen); + cpyfunc = cpy_utf8; + break; + } + if(!(p = OPENSSL_malloc(outlen + 1))) { + if(free_out) ASN1_STRING_free(dest); + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return -1; + } + dest->length = outlen; + dest->data = p; + p[outlen] = 0; + traverse_string(in, len, inform, cpyfunc, &p); + return str_type; +} + +/* This function traverses a string and passes the value of each character + * to an optional function along with a void * argument. + */ + +static int traverse_string(const unsigned char *p, int len, int inform, + int (*rfunc)(unsigned long value, void *in), void *arg) +{ + unsigned long value; + int ret; + while(len) { + if(inform == MBSTRING_ASC) { + value = *p++; + len--; + } else if(inform == MBSTRING_BMP) { + value = *p++ << 8; + value |= *p++; + len -= 2; + } else if(inform == MBSTRING_UNIV) { + value = ((unsigned long)*p++) << 24; + value |= ((unsigned long)*p++) << 16; + value |= *p++ << 8; + value |= *p++; + len -= 4; + } else { + ret = UTF8_getc(p, len, &value); + if(ret < 0) return -1; + len -= ret; + p += ret; + } + if(rfunc) { + ret = rfunc(value, arg); + if(ret <= 0) return ret; + } + } + return 1; +} + +/* Various utility functions for traverse_string */ + +/* Just count number of characters */ + +static int in_utf8(unsigned long value, void *arg) +{ + int *nchar; + nchar = arg; + (*nchar)++; + return 1; +} + +/* Determine size of output as a UTF8 String */ + +static int out_utf8(unsigned long value, void *arg) +{ + int *outlen; + outlen = arg; + *outlen += UTF8_putc(NULL, -1, value); + return 1; +} + +/* Determine the "type" of a string: check each character against a + * supplied "mask". + */ + +static int type_str(unsigned long value, void *arg) +{ + unsigned long types; + types = *((unsigned long *)arg); + if((types & B_ASN1_PRINTABLESTRING) && !is_printable(value)) + types &= ~B_ASN1_PRINTABLESTRING; + if((types & B_ASN1_IA5STRING) && (value > 127)) + types &= ~B_ASN1_IA5STRING; + if((types & B_ASN1_T61STRING) && (value > 0xff)) + types &= ~B_ASN1_T61STRING; + if((types & B_ASN1_BMPSTRING) && (value > 0xffff)) + types &= ~B_ASN1_BMPSTRING; + if(!types) return -1; + *((unsigned long *)arg) = types; + return 1; +} + +/* Copy one byte per character ASCII like strings */ + +static int cpy_asc(unsigned long value, void *arg) +{ + unsigned char **p, *q; + p = arg; + q = *p; + *q = (unsigned char) value; + (*p)++; + return 1; +} + +/* Copy two byte per character BMPStrings */ + +static int cpy_bmp(unsigned long value, void *arg) +{ + unsigned char **p, *q; + p = arg; + q = *p; + *q++ = (unsigned char) ((value >> 8) & 0xff); + *q = (unsigned char) (value & 0xff); + *p += 2; + return 1; +} + +/* Copy four byte per character UniversalStrings */ + +static int cpy_univ(unsigned long value, void *arg) +{ + unsigned char **p, *q; + p = arg; + q = *p; + *q++ = (unsigned char) ((value >> 24) & 0xff); + *q++ = (unsigned char) ((value >> 16) & 0xff); + *q++ = (unsigned char) ((value >> 8) & 0xff); + *q = (unsigned char) (value & 0xff); + *p += 4; + return 1; +} + +/* Copy to a UTF8String */ + +static int cpy_utf8(unsigned long value, void *arg) +{ + unsigned char **p; + int ret; + p = arg; + /* We already know there is enough room so pass 0xff as the length */ + ret = UTF8_putc(*p, 0xff, value); + *p += ret; + return 1; +} + +/* Return 1 if the character is permitted in a PrintableString */ +static int is_printable(unsigned long value) +{ + int ch; + if(value > 0x7f) return 0; + ch = (int) value; + /* Note: we can't use 'isalnum' because certain accented + * characters may count as alphanumeric in some environments. + */ + if((ch >= 'a') && (ch <= 'z')) return 1; + if((ch >= 'A') && (ch <= 'Z')) return 1; + if((ch >= '0') && (ch <= '9')) return 1; + if ((ch == ' ') || strchr("'()+,-./:=?", ch)) return 1; + return 0; +} diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_object.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_object.c new file mode 100644 index 00000000..6ddfca92 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_object.c @@ -0,0 +1,412 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + + +int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp) + { + unsigned char *p; + int objsize; + + if ((a == NULL) || (a->data == NULL)) return(0); + + objsize = ASN1_object_size(0,a->length,V_ASN1_OBJECT); + if (pp == NULL) return objsize; + + p= *pp; + ASN1_put_object(&p,0,a->length,V_ASN1_OBJECT,V_ASN1_UNIVERSAL); + memcpy(p,a->data,a->length); + p+=a->length; + + *pp=p; + return(objsize); + } + +int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num) + { + int i,first,len=0,c, use_bn; + char ftmp[24], *tmp = ftmp; + int tmpsize = sizeof ftmp; + const char *p; + unsigned long l; + BIGNUM *bl = NULL; + + if (num == 0) + return(0); + else if (num == -1) + num=strlen(buf); + + p=buf; + c= *(p++); + num--; + if ((c >= '0') && (c <= '2')) + { + first= c-'0'; + } + else + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_FIRST_NUM_TOO_LARGE); + goto err; + } + + if (num <= 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_SECOND_NUMBER); + goto err; + } + c= *(p++); + num--; + for (;;) + { + if (num <= 0) break; + if ((c != '.') && (c != ' ')) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_SEPARATOR); + goto err; + } + l=0; + use_bn = 0; + for (;;) + { + if (num <= 0) break; + num--; + c= *(p++); + if ((c == ' ') || (c == '.')) + break; + if ((c < '0') || (c > '9')) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_DIGIT); + goto err; + } + if (!use_bn && l >= ((ULONG_MAX - 80) / 10L)) + { + use_bn = 1; + if (!bl) + bl = BN_new(); + if (!bl || !BN_set_word(bl, l)) + goto err; + } + if (use_bn) + { + if (!BN_mul_word(bl, 10L) + || !BN_add_word(bl, c-'0')) + goto err; + } + else + l=l*10L+(long)(c-'0'); + } + if (len == 0) + { + if ((first < 2) && (l >= 40)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_SECOND_NUMBER_TOO_LARGE); + goto err; + } + if (use_bn) + { + if (!BN_add_word(bl, first * 40)) + goto err; + } + else + l+=(long)first*40; + } + i=0; + if (use_bn) + { + int blsize; + blsize = BN_num_bits(bl); + blsize = (blsize + 6)/7; + if (blsize > tmpsize) + { + if (tmp != ftmp) + OPENSSL_free(tmp); + tmpsize = blsize + 32; + tmp = OPENSSL_malloc(tmpsize); + if (!tmp) + goto err; + } + while(blsize--) + tmp[i++] = (unsigned char)BN_div_word(bl, 0x80L); + } + else + { + + for (;;) + { + tmp[i++]=(unsigned char)l&0x7f; + l>>=7L; + if (l == 0L) break; + } + + } + if (out != NULL) + { + if (len+i > olen) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL); + goto err; + } + while (--i > 0) + out[len++]=tmp[i]|0x80; + out[len++]=tmp[0]; + } + else + len+=i; + } + if (tmp != ftmp) + OPENSSL_free(tmp); + if (bl) + BN_free(bl); + return(len); +err: + if (tmp != ftmp) + OPENSSL_free(tmp); + if (bl) + BN_free(bl); + return(0); + } + +int i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *a) +{ + return OBJ_obj2txt(buf, buf_len, a, 0); +} + +int i2a_ASN1_OBJECT(BIO *bp, ASN1_OBJECT *a) + { + char buf[80], *p = buf; + int i; + + if ((a == NULL) || (a->data == NULL)) + return(BIO_write(bp,"NULL",4)); + i=i2t_ASN1_OBJECT(buf,sizeof buf,a); + if (i > (int)(sizeof(buf) - 1)) + { + p = OPENSSL_malloc(i + 1); + if (!p) + return -1; + i2t_ASN1_OBJECT(p,i + 1,a); + } + if (i <= 0) + return BIO_write(bp, "", 9); + BIO_write(bp,p,i); + if (p != buf) + OPENSSL_free(p); + return(i); + } + +ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp, + long length) +{ + const unsigned char *p; + long len; + int tag,xclass; + int inf,i; + ASN1_OBJECT *ret = NULL; + p= *pp; + inf=ASN1_get_object(&p,&len,&tag,&xclass,length); + if (inf & 0x80) + { + i=ASN1_R_BAD_OBJECT_HEADER; + goto err; + } + + if (tag != V_ASN1_OBJECT) + { + i=ASN1_R_EXPECTING_AN_OBJECT; + goto err; + } + ret = c2i_ASN1_OBJECT(a, &p, len); + if(ret) *pp = p; + return ret; +err: + OPENSSL_PUT_ERROR(ASN1, i); + return(NULL); +} + +ASN1_OBJECT *c2i_ASN1_OBJECT(ASN1_OBJECT **a, const unsigned char **pp, + long len) + { + ASN1_OBJECT *ret=NULL; + const unsigned char *p; + unsigned char *data; + int i, length; + + /* Sanity check OID encoding. + * Need at least one content octet. + * MSB must be clear in the last octet. + * can't have leading 0x80 in subidentifiers, see: X.690 8.19.2 + */ + if (len <= 0 || len > INT_MAX || pp == NULL || (p = *pp) == NULL || + p[len - 1] & 0x80) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_OBJECT_ENCODING); + return NULL; + } + /* Now 0 < len <= INT_MAX, so the cast is safe. */ + length = (int)len; + for (i = 0; i < length; i++, p++) + { + if (*p == 0x80 && (!i || !(p[-1] & 0x80))) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_OBJECT_ENCODING); + return NULL; + } + } + + /* only the ASN1_OBJECTs from the 'table' will have values + * for ->sn or ->ln */ + if ((a == NULL) || ((*a) == NULL) || + !((*a)->flags & ASN1_OBJECT_FLAG_DYNAMIC)) + { + if ((ret=ASN1_OBJECT_new()) == NULL) return(NULL); + } + else ret=(*a); + + p= *pp; + /* detach data from object */ + data = (unsigned char *)ret->data; + ret->data = NULL; + /* once detached we can change it */ + if ((data == NULL) || (ret->length < length)) + { + ret->length=0; + if (data != NULL) OPENSSL_free(data); + data=(unsigned char *)OPENSSL_malloc(length); + if (data == NULL) + { i=ERR_R_MALLOC_FAILURE; goto err; } + ret->flags|=ASN1_OBJECT_FLAG_DYNAMIC_DATA; + } + memcpy(data,p,length); + /* reattach data to object, after which it remains const */ + ret->data =data; + ret->length=length; + ret->sn=NULL; + ret->ln=NULL; + /* ret->flags=ASN1_OBJECT_FLAG_DYNAMIC; we know it is dynamic */ + p+=length; + + if (a != NULL) (*a)=ret; + *pp=p; + return(ret); +err: + OPENSSL_PUT_ERROR(ASN1, i); + if ((ret != NULL) && ((a == NULL) || (*a != ret))) + ASN1_OBJECT_free(ret); + return(NULL); + } + +ASN1_OBJECT *ASN1_OBJECT_new(void) + { + ASN1_OBJECT *ret; + + ret=(ASN1_OBJECT *)OPENSSL_malloc(sizeof(ASN1_OBJECT)); + if (ret == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return(NULL); + } + ret->length=0; + ret->data=NULL; + ret->nid=0; + ret->sn=NULL; + ret->ln=NULL; + ret->flags=ASN1_OBJECT_FLAG_DYNAMIC; + return(ret); + } + +void ASN1_OBJECT_free(ASN1_OBJECT *a) + { + if (a == NULL) return; + if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_STRINGS) + { +#ifndef CONST_STRICT /* disable purely for compile-time strict const checking. Doing this on a "real" compile will cause memory leaks */ + if (a->sn != NULL) OPENSSL_free((void *)a->sn); + if (a->ln != NULL) OPENSSL_free((void *)a->ln); +#endif + a->sn=a->ln=NULL; + } + if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC_DATA) + { + if (a->data != NULL) OPENSSL_free((void *)a->data); + a->data=NULL; + a->length=0; + } + if (a->flags & ASN1_OBJECT_FLAG_DYNAMIC) + OPENSSL_free(a); + } + +ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data, int len, + const char *sn, const char *ln) + { + ASN1_OBJECT o; + + o.sn=sn; + o.ln=ln; + o.data=data; + o.nid=nid; + o.length=len; + o.flags=ASN1_OBJECT_FLAG_DYNAMIC|ASN1_OBJECT_FLAG_DYNAMIC_STRINGS| + ASN1_OBJECT_FLAG_DYNAMIC_DATA; + return(OBJ_dup(&o)); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_octet.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_octet.c new file mode 100644 index 00000000..583c9e9d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_octet.c @@ -0,0 +1,70 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +ASN1_OCTET_STRING *ASN1_OCTET_STRING_dup(const ASN1_OCTET_STRING *x) +{ return M_ASN1_OCTET_STRING_dup(x); } + +int ASN1_OCTET_STRING_cmp(const ASN1_OCTET_STRING *a, const ASN1_OCTET_STRING *b) +{ return M_ASN1_OCTET_STRING_cmp(a, b); } + +int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *x, const unsigned char *d, int len) +{ return M_ASN1_OCTET_STRING_set(x, d, len); } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_print.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_print.c new file mode 100644 index 00000000..3b6be10b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_print.c @@ -0,0 +1,119 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +int ASN1_PRINTABLE_type(const unsigned char *s, int len) + { + int c; + int ia5=0; + int t61=0; + + if (len <= 0) len= -1; + if (s == NULL) return(V_ASN1_PRINTABLESTRING); + + while ((*s) && (len-- != 0)) + { + c= *(s++); + if (!( ((c >= 'a') && (c <= 'z')) || + ((c >= 'A') && (c <= 'Z')) || + (c == ' ') || + ((c >= '0') && (c <= '9')) || + (c == ' ') || (c == '\'') || + (c == '(') || (c == ')') || + (c == '+') || (c == ',') || + (c == '-') || (c == '.') || + (c == '/') || (c == ':') || + (c == '=') || (c == '?'))) + ia5=1; + if (c&0x80) + t61=1; + } + if (t61) return(V_ASN1_T61STRING); + if (ia5) return(V_ASN1_IA5STRING); + return(V_ASN1_PRINTABLESTRING); + } + +int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s) + { + int i; + unsigned char *p; + + if (s->type != V_ASN1_UNIVERSALSTRING) return(0); + if ((s->length%4) != 0) return(0); + p=s->data; + for (i=0; ilength; i+=4) + { + if ((p[0] != '\0') || (p[1] != '\0') || (p[2] != '\0')) + break; + else + p+=4; + } + if (i < s->length) return(0); + p=s->data; + for (i=3; ilength; i+=4) + { + *(p++)=s->data[i]; + } + *(p)='\0'; + s->length/=4; + s->type=ASN1_PRINTABLE_type(s->data,s->length); + return(1); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_strnid.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_strnid.c new file mode 100644 index 00000000..d4316f72 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_strnid.c @@ -0,0 +1,286 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include /* For bsearch */ +#include + +#include +#include +#include + + +static STACK_OF(ASN1_STRING_TABLE) *stable = NULL; +static void st_free(ASN1_STRING_TABLE *tbl); + +/* This is the global mask for the mbstring functions: this is use to + * mask out certain types (such as BMPString and UTF8String) because + * certain software (e.g. Netscape) has problems with them. + */ + +static unsigned long global_mask = B_ASN1_UTF8STRING; + +void ASN1_STRING_set_default_mask(unsigned long mask) +{ + global_mask = mask; +} + +unsigned long ASN1_STRING_get_default_mask(void) +{ + return global_mask; +} + +/* This function sets the default to various "flavours" of configuration. + * based on an ASCII string. Currently this is: + * MASK:XXXX : a numerical mask value. + * nobmp : Don't use BMPStrings (just Printable, T61). + * pkix : PKIX recommendation in RFC2459. + * utf8only : only use UTF8Strings (RFC2459 recommendation for 2004). + * default: the default value, Printable, T61, BMP. + */ + +int ASN1_STRING_set_default_mask_asc(const char *p) +{ + unsigned long mask; + char *end; + if(!strncmp(p, "MASK:", 5)) { + if(!p[5]) return 0; + mask = strtoul(p + 5, &end, 0); + if(*end) return 0; + } else if(!strcmp(p, "nombstr")) + mask = ~((unsigned long)(B_ASN1_BMPSTRING|B_ASN1_UTF8STRING)); + else if(!strcmp(p, "pkix")) + mask = ~((unsigned long)B_ASN1_T61STRING); + else if(!strcmp(p, "utf8only")) mask = B_ASN1_UTF8STRING; + else if(!strcmp(p, "default")) + mask = 0xFFFFFFFFL; + else return 0; + ASN1_STRING_set_default_mask(mask); + return 1; +} + +/* The following function generates an ASN1_STRING based on limits in a table. + * Frequently the types and length of an ASN1_STRING are restricted by a + * corresponding OID. For example certificates and certificate requests. + */ + +ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in, + int inlen, int inform, int nid) +{ + ASN1_STRING_TABLE *tbl; + ASN1_STRING *str = NULL; + unsigned long mask; + int ret; + if(!out) out = &str; + tbl = ASN1_STRING_TABLE_get(nid); + if(tbl) { + mask = tbl->mask; + if(!(tbl->flags & STABLE_NO_MASK)) mask &= global_mask; + ret = ASN1_mbstring_ncopy(out, in, inlen, inform, mask, + tbl->minsize, tbl->maxsize); + } else ret = ASN1_mbstring_copy(out, in, inlen, inform, DIRSTRING_TYPE & global_mask); + if(ret <= 0) return NULL; + return *out; +} + +/* Now the tables and helper functions for the string table: + */ + +/* size limits: this stuff is taken straight from RFC3280 */ + +#define ub_name 32768 +#define ub_common_name 64 +#define ub_locality_name 128 +#define ub_state_name 128 +#define ub_organization_name 64 +#define ub_organization_unit_name 64 +#define ub_title 64 +#define ub_email_address 128 +#define ub_serial_number 64 + + +/* This table must be kept in NID order */ + +static const ASN1_STRING_TABLE tbl_standard[] = { +{NID_commonName, 1, ub_common_name, DIRSTRING_TYPE, 0}, +{NID_countryName, 2, 2, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK}, +{NID_localityName, 1, ub_locality_name, DIRSTRING_TYPE, 0}, +{NID_stateOrProvinceName, 1, ub_state_name, DIRSTRING_TYPE, 0}, +{NID_organizationName, 1, ub_organization_name, DIRSTRING_TYPE, 0}, +{NID_organizationalUnitName, 1, ub_organization_unit_name, DIRSTRING_TYPE, 0}, +{NID_pkcs9_emailAddress, 1, ub_email_address, B_ASN1_IA5STRING, STABLE_NO_MASK}, +{NID_pkcs9_unstructuredName, 1, -1, PKCS9STRING_TYPE, 0}, +{NID_pkcs9_challengePassword, 1, -1, PKCS9STRING_TYPE, 0}, +{NID_pkcs9_unstructuredAddress, 1, -1, DIRSTRING_TYPE, 0}, +{NID_givenName, 1, ub_name, DIRSTRING_TYPE, 0}, +{NID_surname, 1, ub_name, DIRSTRING_TYPE, 0}, +{NID_initials, 1, ub_name, DIRSTRING_TYPE, 0}, +{NID_serialNumber, 1, ub_serial_number, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK}, +{NID_friendlyName, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK}, +{NID_name, 1, ub_name, DIRSTRING_TYPE, 0}, +{NID_dnQualifier, -1, -1, B_ASN1_PRINTABLESTRING, STABLE_NO_MASK}, +{NID_domainComponent, 1, -1, B_ASN1_IA5STRING, STABLE_NO_MASK}, +{NID_ms_csp_name, -1, -1, B_ASN1_BMPSTRING, STABLE_NO_MASK} +}; + +static int sk_table_cmp(const ASN1_STRING_TABLE **a, + const ASN1_STRING_TABLE **b) +{ + return (*a)->nid - (*b)->nid; +} + +static int table_cmp(const void *in_a, const void *in_b) +{ + const ASN1_STRING_TABLE *a = in_a; + const ASN1_STRING_TABLE *b = in_b; + return a->nid - b->nid; +} + +ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid) +{ + int found; + size_t idx; + ASN1_STRING_TABLE *ttmp; + ASN1_STRING_TABLE fnd; + fnd.nid = nid; + + ttmp = bsearch(&fnd, tbl_standard, sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE), sizeof(ASN1_STRING_TABLE), table_cmp); + if(ttmp) return ttmp; + if(!stable) return NULL; + found = sk_ASN1_STRING_TABLE_find(stable, &idx, &fnd); + if (!found) return NULL; + return sk_ASN1_STRING_TABLE_value(stable, idx); +} + +int ASN1_STRING_TABLE_add(int nid, + long minsize, long maxsize, unsigned long mask, + unsigned long flags) +{ + ASN1_STRING_TABLE *tmp; + char new_nid = 0; + flags &= ~STABLE_FLAGS_MALLOC; + if(!stable) stable = sk_ASN1_STRING_TABLE_new(sk_table_cmp); + if(!stable) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return 0; + } + if(!(tmp = ASN1_STRING_TABLE_get(nid))) { + tmp = OPENSSL_malloc(sizeof(ASN1_STRING_TABLE)); + if(!tmp) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return 0; + } + tmp->flags = flags | STABLE_FLAGS_MALLOC; + tmp->nid = nid; + new_nid = 1; + } else tmp->flags = (tmp->flags & STABLE_FLAGS_MALLOC) | flags; + if(minsize != -1) tmp->minsize = minsize; + if(maxsize != -1) tmp->maxsize = maxsize; + tmp->mask = mask; + if(new_nid) sk_ASN1_STRING_TABLE_push(stable, tmp); + return 1; +} + +void ASN1_STRING_TABLE_cleanup(void) +{ + STACK_OF(ASN1_STRING_TABLE) *tmp; + tmp = stable; + if(!tmp) return; + stable = NULL; + sk_ASN1_STRING_TABLE_pop_free(tmp, st_free); +} + +static void st_free(ASN1_STRING_TABLE *tbl) +{ + if(tbl->flags & STABLE_FLAGS_MALLOC) OPENSSL_free(tbl); +} + + +#ifdef STRING_TABLE_TEST + +int +main(void) +{ + ASN1_STRING_TABLE *tmp; + int i, last_nid = -1; + + for (tmp = tbl_standard, i = 0; + i < sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE); i++, tmp++) + { + if (tmp->nid < last_nid) + { + last_nid = 0; + break; + } + last_nid = tmp->nid; + } + + if (last_nid != 0) + { + printf("Table order OK\n"); + exit(0); + } + + for (tmp = tbl_standard, i = 0; + i < sizeof(tbl_standard)/sizeof(ASN1_STRING_TABLE); i++, tmp++) + printf("Index %d, NID %d, Name=%s\n", i, tmp->nid, + OBJ_nid2ln(tmp->nid)); + + return 0; +} + +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_time.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_time.c new file mode 100644 index 00000000..ac2cb485 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_time.c @@ -0,0 +1,221 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "asn1_locl.h" + + +/* This is an implementation of the ASN1 Time structure which is: + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + * written by Steve Henson. + */ + +IMPLEMENT_ASN1_MSTRING(ASN1_TIME, B_ASN1_TIME) + +IMPLEMENT_ASN1_FUNCTIONS(ASN1_TIME) + +#if 0 +int i2d_ASN1_TIME(ASN1_TIME *a, unsigned char **pp) + { + if(a->type == V_ASN1_UTCTIME || a->type == V_ASN1_GENERALIZEDTIME) + return(i2d_ASN1_bytes((ASN1_STRING *)a,pp, + a->type ,V_ASN1_UNIVERSAL)); + OPENSSL_PUT_ERROR(ASN1, ASN1_R_EXPECTING_A_TIME); + return -1; + } +#endif + + +ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s, time_t t) + { + return ASN1_TIME_adj(s, t, 0, 0); + } + +ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s, time_t t, + int offset_day, long offset_sec) + { + struct tm *ts; + struct tm data; + + ts=OPENSSL_gmtime(&t,&data); + if (ts == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ERROR_GETTING_TIME); + return NULL; + } + if (offset_day || offset_sec) + { + if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec)) + return NULL; + } + if((ts->tm_year >= 50) && (ts->tm_year < 150)) + return ASN1_UTCTIME_adj(s, t, offset_day, offset_sec); + return ASN1_GENERALIZEDTIME_adj(s, t, offset_day, offset_sec); + } + +int ASN1_TIME_check(ASN1_TIME *t) + { + if (t->type == V_ASN1_GENERALIZEDTIME) + return ASN1_GENERALIZEDTIME_check(t); + else if (t->type == V_ASN1_UTCTIME) + return ASN1_UTCTIME_check(t); + return 0; + } + +/* Convert an ASN1_TIME structure to GeneralizedTime */ +ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out) + { + ASN1_GENERALIZEDTIME *ret; + char *str; + int newlen; + + if (!ASN1_TIME_check(t)) return NULL; + + if (!out || !*out) + { + if (!(ret = ASN1_GENERALIZEDTIME_new ())) + return NULL; + if (out) *out = ret; + } + else ret = *out; + + /* If already GeneralizedTime just copy across */ + if (t->type == V_ASN1_GENERALIZEDTIME) + { + if(!ASN1_STRING_set(ret, t->data, t->length)) + return NULL; + return ret; + } + + /* grow the string */ + if (!ASN1_STRING_set(ret, NULL, t->length + 2)) + return NULL; + /* ASN1_STRING_set() allocated 'len + 1' bytes. */ + newlen = t->length + 2 + 1; + str = (char *)ret->data; + /* Work out the century and prepend */ + if (t->data[0] >= '5') BUF_strlcpy(str, "19", newlen); + else BUF_strlcpy(str, "20", newlen); + + BUF_strlcat(str, (char *)t->data, newlen); + + return ret; + } + +int ASN1_TIME_set_string(ASN1_TIME *s, const char *str) + { + ASN1_TIME t; + + t.length = strlen(str); + t.data = (unsigned char *)str; + t.flags = 0; + + t.type = V_ASN1_UTCTIME; + + if (!ASN1_TIME_check(&t)) + { + t.type = V_ASN1_GENERALIZEDTIME; + if (!ASN1_TIME_check(&t)) + return 0; + } + + if (s && !ASN1_STRING_copy((ASN1_STRING *)s, (ASN1_STRING *)&t)) + return 0; + + return 1; + } + +static int asn1_time_to_tm(struct tm *tm, const ASN1_TIME *t) + { + if (t == NULL) + { + time_t now_t; + time(&now_t); + if (OPENSSL_gmtime(&now_t, tm)) + return 1; + return 0; + } + + if (t->type == V_ASN1_UTCTIME) + return asn1_utctime_to_tm(tm, t); + else if (t->type == V_ASN1_GENERALIZEDTIME) + return asn1_generalizedtime_to_tm(tm, t); + + return 0; + } + +int ASN1_TIME_diff(int *pday, int *psec, + const ASN1_TIME *from, const ASN1_TIME *to) + { + struct tm tm_from, tm_to; + if (!asn1_time_to_tm(&tm_from, from)) + return 0; + if (!asn1_time_to_tm(&tm_to, to)) + return 0; + return OPENSSL_gmtime_diff(pday, psec, &tm_from, &tm_to); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_type.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_type.c new file mode 100644 index 00000000..fd3d5b11 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_type.c @@ -0,0 +1,160 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include + + +int ASN1_TYPE_get(ASN1_TYPE *a) + { + if ((a->value.ptr != NULL) || (a->type == V_ASN1_NULL)) + return(a->type); + else + return(0); + } + +void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value) + { + if (a->value.ptr != NULL) + { + ASN1_TYPE **tmp_a = &a; + ASN1_primitive_free((ASN1_VALUE **)tmp_a, NULL); + } + a->type=type; + if (type == V_ASN1_BOOLEAN) + a->value.boolean = value ? 0xff : 0; + else + a->value.ptr=value; + } + +int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value) + { + if (!value || (type == V_ASN1_BOOLEAN)) + { + void *p = (void *)value; + ASN1_TYPE_set(a, type, p); + } + else if (type == V_ASN1_OBJECT) + { + ASN1_OBJECT *odup; + odup = OBJ_dup(value); + if (!odup) + return 0; + ASN1_TYPE_set(a, type, odup); + } + else + { + ASN1_STRING *sdup; + sdup = ASN1_STRING_dup(value); + if (!sdup) + return 0; + ASN1_TYPE_set(a, type, sdup); + } + return 1; + } + +/* Returns 0 if they are equal, != 0 otherwise. */ +int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b) + { + int result = -1; + + if (!a || !b || a->type != b->type) return -1; + + switch (a->type) + { + case V_ASN1_OBJECT: + result = OBJ_cmp(a->value.object, b->value.object); + break; + case V_ASN1_NULL: + result = 0; /* They do not have content. */ + break; + case V_ASN1_BOOLEAN: + result = a->value.boolean - b->value.boolean; + break; + case V_ASN1_INTEGER: + case V_ASN1_NEG_INTEGER: + case V_ASN1_ENUMERATED: + case V_ASN1_NEG_ENUMERATED: + case V_ASN1_BIT_STRING: + case V_ASN1_OCTET_STRING: + case V_ASN1_SEQUENCE: + case V_ASN1_SET: + case V_ASN1_NUMERICSTRING: + case V_ASN1_PRINTABLESTRING: + case V_ASN1_T61STRING: + case V_ASN1_VIDEOTEXSTRING: + case V_ASN1_IA5STRING: + case V_ASN1_UTCTIME: + case V_ASN1_GENERALIZEDTIME: + case V_ASN1_GRAPHICSTRING: + case V_ASN1_VISIBLESTRING: + case V_ASN1_GENERALSTRING: + case V_ASN1_UNIVERSALSTRING: + case V_ASN1_BMPSTRING: + case V_ASN1_UTF8STRING: + case V_ASN1_OTHER: + default: + result = ASN1_STRING_cmp((ASN1_STRING *) a->value.ptr, + (ASN1_STRING *) b->value.ptr); + break; + } + + return result; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_utctm.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_utctm.c new file mode 100644 index 00000000..dbbbecb4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_utctm.c @@ -0,0 +1,342 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + + +#if 0 +int i2d_ASN1_UTCTIME(ASN1_UTCTIME *a, unsigned char **pp) + { + return(i2d_ASN1_bytes((ASN1_STRING *)a,pp, + V_ASN1_UTCTIME,V_ASN1_UNIVERSAL)); + } + + +ASN1_UTCTIME *d2i_ASN1_UTCTIME(ASN1_UTCTIME **a, unsigned char **pp, + long length) + { + ASN1_UTCTIME *ret=NULL; + + ret=(ASN1_UTCTIME *)d2i_ASN1_bytes((ASN1_STRING **)a,pp,length, + V_ASN1_UTCTIME,V_ASN1_UNIVERSAL); + if (ret == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_NESTED_ASN1_ERROR); + return(NULL); + } + if (!ASN1_UTCTIME_check(ret)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_TIME_FORMAT); + goto err; + } + + return(ret); +err: + if ((ret != NULL) && ((a == NULL) || (*a != ret))) + M_ASN1_UTCTIME_free(ret); + return(NULL); + } + +#endif + +int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d) + { + static const int min[8]={ 0, 1, 1, 0, 0, 0, 0, 0}; + static const int max[8]={99,12,31,23,59,59,12,59}; + char *a; + int n,i,l,o; + + if (d->type != V_ASN1_UTCTIME) return(0); + l=d->length; + a=(char *)d->data; + o=0; + + if (l < 11) goto err; + for (i=0; i<6; i++) + { + if ((i == 5) && ((a[o] == 'Z') || + (a[o] == '+') || (a[o] == '-'))) + { + i++; + if (tm) + tm->tm_sec = 0; + break; + } + if ((a[o] < '0') || (a[o] > '9')) goto err; + n= a[o]-'0'; + if (++o > l) goto err; + + if ((a[o] < '0') || (a[o] > '9')) goto err; + n=(n*10)+ a[o]-'0'; + if (++o > l) goto err; + + if ((n < min[i]) || (n > max[i])) goto err; + if (tm) + { + switch(i) + { + case 0: + tm->tm_year = n < 50 ? n + 100 : n; + break; + case 1: + tm->tm_mon = n - 1; + break; + case 2: + tm->tm_mday = n; + break; + case 3: + tm->tm_hour = n; + break; + case 4: + tm->tm_min = n; + break; + case 5: + tm->tm_sec = n; + break; + } + } + } + if (a[o] == 'Z') + o++; + else if ((a[o] == '+') || (a[o] == '-')) + { + int offsign = a[o] == '-' ? -1 : 1, offset = 0; + o++; + if (o+4 > l) goto err; + for (i=6; i<8; i++) + { + if ((a[o] < '0') || (a[o] > '9')) goto err; + n= a[o]-'0'; + o++; + if ((a[o] < '0') || (a[o] > '9')) goto err; + n=(n*10)+ a[o]-'0'; + if ((n < min[i]) || (n > max[i])) goto err; + if (tm) + { + if (i == 6) + offset = n * 3600; + else if (i == 7) + offset += n * 60; + } + o++; + } + if (offset && !OPENSSL_gmtime_adj(tm, 0, offset * offsign)) + return 0; + } + return o == l; +err: + return 0; + } + +int ASN1_UTCTIME_check(const ASN1_UTCTIME *d) + { + return asn1_utctime_to_tm(NULL, d); + } + +int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str) + { + ASN1_UTCTIME t; + + t.type=V_ASN1_UTCTIME; + t.length=strlen(str); + t.data=(unsigned char *)str; + if (ASN1_UTCTIME_check(&t)) + { + if (s != NULL) + { + if (!ASN1_STRING_set((ASN1_STRING *)s, + (unsigned char *)str,t.length)) + return 0; + s->type = V_ASN1_UTCTIME; + } + return(1); + } + else + return(0); + } + +ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t) + { + return ASN1_UTCTIME_adj(s, t, 0, 0); + } + +ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, + int offset_day, long offset_sec) + { + char *p; + struct tm *ts; + struct tm data; + size_t len = 20; + int free_s = 0; + + if (s == NULL) + { + free_s = 1; + s=M_ASN1_UTCTIME_new(); + } + if (s == NULL) + goto err; + + + ts=OPENSSL_gmtime(&t, &data); + if (ts == NULL) + goto err; + + if (offset_day || offset_sec) + { + if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec)) + goto err; + } + + if((ts->tm_year < 50) || (ts->tm_year >= 150)) + goto err; + + p=(char *)s->data; + if ((p == NULL) || ((size_t)s->length < len)) + { + p=OPENSSL_malloc(len); + if (p == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + if (s->data != NULL) + OPENSSL_free(s->data); + s->data=(unsigned char *)p; + } + + BIO_snprintf(p,len,"%02d%02d%02d%02d%02d%02dZ",ts->tm_year%100, + ts->tm_mon+1,ts->tm_mday,ts->tm_hour,ts->tm_min,ts->tm_sec); + s->length=strlen(p); + s->type=V_ASN1_UTCTIME; + return(s); + err: + if (free_s && s) + M_ASN1_UTCTIME_free(s); + return NULL; + } + + +int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t) + { + struct tm stm, ttm; + int day, sec; + + if (!asn1_utctime_to_tm(&stm, s)) + return -2; + + if (!OPENSSL_gmtime(&t, &ttm)) + return -2; + + if (!OPENSSL_gmtime_diff(&day, &sec, &ttm, &stm)) + return -2; + + if (day > 0) + return 1; + if (day < 0) + return -1; + if (sec > 0) + return 1; + if (sec < 0) + return -1; + return 0; + } + + +#if 0 +time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s) + { + struct tm tm; + int offset; + + memset(&tm,'\0',sizeof tm); + +#define g2(p) (((p)[0]-'0')*10+(p)[1]-'0') + tm.tm_year=g2(s->data); + if(tm.tm_year < 50) + tm.tm_year+=100; + tm.tm_mon=g2(s->data+2)-1; + tm.tm_mday=g2(s->data+4); + tm.tm_hour=g2(s->data+6); + tm.tm_min=g2(s->data+8); + tm.tm_sec=g2(s->data+10); + if(s->data[12] == 'Z') + offset=0; + else + { + offset=g2(s->data+13)*60+g2(s->data+15); + if(s->data[12] == '-') + offset= -offset; + } +#undef g2 + + return mktime(&tm)-offset*60; /* FIXME: mktime assumes the current timezone + * instead of UTC, and unless we rewrite OpenSSL + * in Lisp we cannot locally change the timezone + * without possibly interfering with other parts + * of the program. timegm, which uses UTC, is + * non-standard. + * Also time_t is inappropriate for general + * UTC times because it may a 32 bit type. */ + } +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/a_utf8.c b/TMessagesProj/jni/boringssl/crypto/asn1/a_utf8.c new file mode 100644 index 00000000..ed6e98d3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/a_utf8.c @@ -0,0 +1,210 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +/* UTF8 utilities */ + +/* This parses a UTF8 string one character at a time. It is passed a pointer + * to the string and the length of the string. It sets 'value' to the value of + * the current character. It returns the number of characters read or a + * negative error code: + * -1 = string too short + * -2 = illegal character + * -3 = subsequent characters not of the form 10xxxxxx + * -4 = character encoded incorrectly (not minimal length). + */ + +int UTF8_getc(const unsigned char *str, int len, unsigned long *val) +{ + const unsigned char *p; + unsigned long value; + int ret; + if(len <= 0) return 0; + p = str; + + /* Check syntax and work out the encoded value (if correct) */ + if((*p & 0x80) == 0) { + value = *p++ & 0x7f; + ret = 1; + } else if((*p & 0xe0) == 0xc0) { + if(len < 2) return -1; + if((p[1] & 0xc0) != 0x80) return -3; + value = (*p++ & 0x1f) << 6; + value |= *p++ & 0x3f; + if(value < 0x80) return -4; + ret = 2; + } else if((*p & 0xf0) == 0xe0) { + if(len < 3) return -1; + if( ((p[1] & 0xc0) != 0x80) + || ((p[2] & 0xc0) != 0x80) ) return -3; + value = (*p++ & 0xf) << 12; + value |= (*p++ & 0x3f) << 6; + value |= *p++ & 0x3f; + if(value < 0x800) return -4; + ret = 3; + } else if((*p & 0xf8) == 0xf0) { + if(len < 4) return -1; + if( ((p[1] & 0xc0) != 0x80) + || ((p[2] & 0xc0) != 0x80) + || ((p[3] & 0xc0) != 0x80) ) return -3; + value = ((unsigned long)(*p++ & 0x7)) << 18; + value |= (*p++ & 0x3f) << 12; + value |= (*p++ & 0x3f) << 6; + value |= *p++ & 0x3f; + if(value < 0x10000) return -4; + ret = 4; + } else if((*p & 0xfc) == 0xf8) { + if(len < 5) return -1; + if( ((p[1] & 0xc0) != 0x80) + || ((p[2] & 0xc0) != 0x80) + || ((p[3] & 0xc0) != 0x80) + || ((p[4] & 0xc0) != 0x80) ) return -3; + value = ((unsigned long)(*p++ & 0x3)) << 24; + value |= ((unsigned long)(*p++ & 0x3f)) << 18; + value |= ((unsigned long)(*p++ & 0x3f)) << 12; + value |= (*p++ & 0x3f) << 6; + value |= *p++ & 0x3f; + if(value < 0x200000) return -4; + ret = 5; + } else if((*p & 0xfe) == 0xfc) { + if(len < 6) return -1; + if( ((p[1] & 0xc0) != 0x80) + || ((p[2] & 0xc0) != 0x80) + || ((p[3] & 0xc0) != 0x80) + || ((p[4] & 0xc0) != 0x80) + || ((p[5] & 0xc0) != 0x80) ) return -3; + value = ((unsigned long)(*p++ & 0x1)) << 30; + value |= ((unsigned long)(*p++ & 0x3f)) << 24; + value |= ((unsigned long)(*p++ & 0x3f)) << 18; + value |= ((unsigned long)(*p++ & 0x3f)) << 12; + value |= (*p++ & 0x3f) << 6; + value |= *p++ & 0x3f; + if(value < 0x4000000) return -4; + ret = 6; + } else return -2; + *val = value; + return ret; +} + +/* This takes a character 'value' and writes the UTF8 encoded value in + * 'str' where 'str' is a buffer containing 'len' characters. Returns + * the number of characters written or -1 if 'len' is too small. 'str' can + * be set to NULL in which case it just returns the number of characters. + * It will need at most 6 characters. + */ + +int UTF8_putc(unsigned char *str, int len, unsigned long value) +{ + if(!str) len = 6; /* Maximum we will need */ + else if(len <= 0) return -1; + if(value < 0x80) { + if(str) *str = (unsigned char)value; + return 1; + } + if(value < 0x800) { + if(len < 2) return -1; + if(str) { + *str++ = (unsigned char)(((value >> 6) & 0x1f) | 0xc0); + *str = (unsigned char)((value & 0x3f) | 0x80); + } + return 2; + } + if(value < 0x10000) { + if(len < 3) return -1; + if(str) { + *str++ = (unsigned char)(((value >> 12) & 0xf) | 0xe0); + *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80); + *str = (unsigned char)((value & 0x3f) | 0x80); + } + return 3; + } + if(value < 0x200000) { + if(len < 4) return -1; + if(str) { + *str++ = (unsigned char)(((value >> 18) & 0x7) | 0xf0); + *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80); + *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80); + *str = (unsigned char)((value & 0x3f) | 0x80); + } + return 4; + } + if(value < 0x4000000) { + if(len < 5) return -1; + if(str) { + *str++ = (unsigned char)(((value >> 24) & 0x3) | 0xf8); + *str++ = (unsigned char)(((value >> 18) & 0x3f) | 0x80); + *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80); + *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80); + *str = (unsigned char)((value & 0x3f) | 0x80); + } + return 5; + } + if(len < 6) return -1; + if(str) { + *str++ = (unsigned char)(((value >> 30) & 0x1) | 0xfc); + *str++ = (unsigned char)(((value >> 24) & 0x3f) | 0x80); + *str++ = (unsigned char)(((value >> 18) & 0x3f) | 0x80); + *str++ = (unsigned char)(((value >> 12) & 0x3f) | 0x80); + *str++ = (unsigned char)(((value >> 6) & 0x3f) | 0x80); + *str = (unsigned char)((value & 0x3f) | 0x80); + } + return 6; +} diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/asn1_lib.c b/TMessagesProj/jni/boringssl/crypto/asn1/asn1_lib.c new file mode 100644 index 00000000..a109749f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/asn1_lib.c @@ -0,0 +1,510 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + + +/* Used in asn1_mac.h. + * TODO(davidben): Remove this once asn1_mac.h is gone or trimmed. */ +OPENSSL_DECLARE_ERROR_REASON(ASN1, MALLOC_FAILURE); + +/* Cross-module errors from crypto/x509/i2d_pr.c */ +OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_PUBLIC_KEY_TYPE); + +/* Cross-module errors from crypto/x509/asn1_gen.c. + * TODO(davidben): Remove these once asn1_gen.c is gone. */ +OPENSSL_DECLARE_ERROR_REASON(ASN1, DEPTH_EXCEEDED); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BITSTRING_FORMAT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_BOOLEAN); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_FORMAT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_HEX); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_IMPLICIT_TAG); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_INTEGER); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NESTED_TAGGING); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_NULL_VALUE); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_OBJECT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, ILLEGAL_TIME_VALUE); +OPENSSL_DECLARE_ERROR_REASON(ASN1, INTEGER_NOT_ASCII_FORMAT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_MODIFIER); +OPENSSL_DECLARE_ERROR_REASON(ASN1, INVALID_NUMBER); +OPENSSL_DECLARE_ERROR_REASON(ASN1, LIST_ERROR); +OPENSSL_DECLARE_ERROR_REASON(ASN1, MISSING_VALUE); +OPENSSL_DECLARE_ERROR_REASON(ASN1, NOT_ASCII_FORMAT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, OBJECT_NOT_ASCII_FORMAT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, SEQUENCE_OR_SET_NEEDS_CONFIG); +OPENSSL_DECLARE_ERROR_REASON(ASN1, TIME_NOT_ASCII_FORMAT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_FORMAT); +OPENSSL_DECLARE_ERROR_REASON(ASN1, UNKNOWN_TAG); +OPENSSL_DECLARE_ERROR_REASON(ASN1, UNSUPPORTED_TYPE); + +static int asn1_get_length(const unsigned char **pp,int *inf,long *rl,int max); +static void asn1_put_length(unsigned char **pp, int length); + +static int _asn1_check_infinite_end(const unsigned char **p, long len) + { + /* If there is 0 or 1 byte left, the length check should pick + * things up */ + if (len <= 0) + return(1); + else if ((len >= 2) && ((*p)[0] == 0) && ((*p)[1] == 0)) + { + (*p)+=2; + return(1); + } + return(0); + } + +int ASN1_check_infinite_end(unsigned char **p, long len) + { + return _asn1_check_infinite_end((const unsigned char **)p, len); + } + +int ASN1_const_check_infinite_end(const unsigned char **p, long len) + { + return _asn1_check_infinite_end(p, len); + } + + +int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, + int *pclass, long omax) + { + int i,ret; + long l; + const unsigned char *p= *pp; + int tag,xclass,inf; + long max=omax; + + if (!max) goto err; + ret=(*p&V_ASN1_CONSTRUCTED); + xclass=(*p&V_ASN1_PRIVATE); + i= *p&V_ASN1_PRIMITIVE_TAG; + if (i == V_ASN1_PRIMITIVE_TAG) + { /* high-tag */ + p++; + if (--max == 0) goto err; + l=0; + while (*p&0x80) + { + l<<=7L; + l|= *(p++)&0x7f; + if (--max == 0) goto err; + if (l > (INT_MAX >> 7L)) goto err; + } + l<<=7L; + l|= *(p++)&0x7f; + tag=(int)l; + if (--max == 0) goto err; + } + else + { + tag=i; + p++; + if (--max == 0) goto err; + } + *ptag=tag; + *pclass=xclass; + if (!asn1_get_length(&p,&inf,plength,(int)max)) goto err; + + if (inf && !(ret & V_ASN1_CONSTRUCTED)) + goto err; + +#if 0 + fprintf(stderr,"p=%d + *plength=%ld > omax=%ld + *pp=%d (%d > %d)\n", + (int)p,*plength,omax,(int)*pp,(int)(p+ *plength), + (int)(omax+ *pp)); + +#endif + if (*plength > (omax - (p - *pp))) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); + /* Set this so that even if things are not long enough + * the values are set correctly */ + ret|=0x80; + } + *pp=p; + return(ret|inf); +err: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_HEADER_TOO_LONG); + return(0x80); + } + +static int asn1_get_length(const unsigned char **pp, int *inf, long *rl, int max) + { + const unsigned char *p= *pp; + unsigned long ret=0; + unsigned int i; + + if (max-- < 1) return(0); + if (*p == 0x80) + { + *inf=1; + ret=0; + p++; + } + else + { + *inf=0; + i= *p&0x7f; + if (*(p++) & 0x80) + { + if (i > sizeof(long)) + return 0; + if (max-- == 0) return(0); + while (i-- > 0) + { + ret<<=8L; + ret|= *(p++); + if (max-- == 0) return(0); + } + } + else + ret=i; + } + if (ret > LONG_MAX) + return 0; + *pp=p; + *rl=(long)ret; + return(1); + } + +/* class 0 is constructed + * constructed == 2 for indefinite length constructed */ +void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag, + int xclass) + { + unsigned char *p= *pp; + int i, ttag; + + i=(constructed)?V_ASN1_CONSTRUCTED:0; + i|=(xclass&V_ASN1_PRIVATE); + if (tag < 31) + *(p++)=i|(tag&V_ASN1_PRIMITIVE_TAG); + else + { + *(p++)=i|V_ASN1_PRIMITIVE_TAG; + for(i = 0, ttag = tag; ttag > 0; i++) ttag >>=7; + ttag = i; + while(i-- > 0) + { + p[i] = tag & 0x7f; + if(i != (ttag - 1)) p[i] |= 0x80; + tag >>= 7; + } + p += ttag; + } + if (constructed == 2) + *(p++)=0x80; + else + asn1_put_length(&p,length); + *pp=p; + } + +int ASN1_put_eoc(unsigned char **pp) + { + unsigned char *p = *pp; + *p++ = 0; + *p++ = 0; + *pp = p; + return 2; + } + +static void asn1_put_length(unsigned char **pp, int length) + { + unsigned char *p= *pp; + int i,l; + if (length <= 127) + *(p++)=(unsigned char)length; + else + { + l=length; + for (i=0; l > 0; i++) + l>>=8; + *(p++)=i|0x80; + l=i; + while (i-- > 0) + { + p[i]=length&0xff; + length>>=8; + } + p+=l; + } + *pp=p; + } + +int ASN1_object_size(int constructed, int length, int tag) + { + int ret; + + ret=length; + ret++; + if (tag >= 31) + { + while (tag > 0) + { + tag>>=7; + ret++; + } + } + if (constructed == 2) + return ret + 3; + ret++; + if (length > 127) + { + while (length > 0) + { + length>>=8; + ret++; + } + } + return(ret); + } + +static int _asn1_Finish(ASN1_const_CTX *c) + { + if ((c->inf == (1|V_ASN1_CONSTRUCTED)) && (!c->eos)) + { + if (!ASN1_const_check_infinite_end(&c->p,c->slen)) + { + c->error=ASN1_R_MISSING_ASN1_EOS; + return(0); + } + } + if ( ((c->slen != 0) && !(c->inf & 1)) || + ((c->slen < 0) && (c->inf & 1))) + { + c->error=ASN1_R_ASN1_LENGTH_MISMATCH; + return(0); + } + return(1); + } + +int asn1_Finish(ASN1_CTX *c) + { + return _asn1_Finish((ASN1_const_CTX *)c); + } + +int asn1_const_Finish(ASN1_const_CTX *c) + { + return _asn1_Finish(c); + } + +int asn1_GetSequence(ASN1_const_CTX *c, long *length) + { + const unsigned char *q; + + q=c->p; + c->inf=ASN1_get_object(&(c->p),&(c->slen),&(c->tag),&(c->xclass), + *length); + if (c->inf & 0x80) + { + c->error=ASN1_R_BAD_GET_ASN1_OBJECT_CALL; + return(0); + } + if (c->tag != V_ASN1_SEQUENCE) + { + c->error=ASN1_R_EXPECTING_AN_ASN1_SEQUENCE; + return(0); + } + (*length)-=(c->p-q); + if (c->max && (*length < 0)) + { + c->error=ASN1_R_ASN1_LENGTH_MISMATCH; + return(0); + } + if (c->inf == (1|V_ASN1_CONSTRUCTED)) + c->slen= *length+ *(c->pp)-c->p; + c->eos=0; + return(1); + } + +int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str) + { + if (str == NULL) + return 0; + dst->type = str->type; + if (!ASN1_STRING_set(dst,str->data,str->length)) + return 0; + dst->flags = str->flags; + return 1; + } + +ASN1_STRING *ASN1_STRING_dup(const ASN1_STRING *str) + { + ASN1_STRING *ret; + if (!str) + return NULL; + ret=ASN1_STRING_new(); + if (!ret) + return NULL; + if (!ASN1_STRING_copy(ret,str)) + { + ASN1_STRING_free(ret); + return NULL; + } + return ret; + } + +int ASN1_STRING_set(ASN1_STRING *str, const void *_data, int len) + { + unsigned char *c; + const char *data=_data; + + if (len < 0) + { + if (data == NULL) + return(0); + else + len=strlen(data); + } + if ((str->length < len) || (str->data == NULL)) + { + c=str->data; + if (c == NULL) + str->data=OPENSSL_malloc(len+1); + else + str->data=OPENSSL_realloc(c,len+1); + + if (str->data == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + str->data=c; + return(0); + } + } + str->length=len; + if (data != NULL) + { + memcpy(str->data,data,len); + /* an allowance for strings :-) */ + str->data[len]='\0'; + } + return(1); + } + +void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len) + { + if (str->data) + OPENSSL_free(str->data); + str->data = data; + str->length = len; + } + +ASN1_STRING *ASN1_STRING_new(void) + { + return(ASN1_STRING_type_new(V_ASN1_OCTET_STRING)); + } + + +ASN1_STRING *ASN1_STRING_type_new(int type) + { + ASN1_STRING *ret; + + ret=(ASN1_STRING *)OPENSSL_malloc(sizeof(ASN1_STRING)); + if (ret == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return(NULL); + } + ret->length=0; + ret->type=type; + ret->data=NULL; + ret->flags=0; + return(ret); + } + +void ASN1_STRING_free(ASN1_STRING *a) + { + if (a == NULL) return; + if (a->data && !(a->flags & ASN1_STRING_FLAG_NDEF)) + OPENSSL_free(a->data); + OPENSSL_free(a); + } + +int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b) + { + int i; + + i=(a->length-b->length); + if (i == 0) + { + i=memcmp(a->data,b->data,a->length); + if (i == 0) + return(a->type-b->type); + else + return(i); + } + else + return(i); + } + +int ASN1_STRING_length(const ASN1_STRING *x) +{ return M_ASN1_STRING_length(x); } + +void ASN1_STRING_length_set(ASN1_STRING *x, int len) +{ M_ASN1_STRING_length_set(x, len); return; } + +int ASN1_STRING_type(ASN1_STRING *x) +{ return M_ASN1_STRING_type(x); } + +unsigned char * ASN1_STRING_data(ASN1_STRING *x) +{ return M_ASN1_STRING_data(x); } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/asn1_locl.h b/TMessagesProj/jni/boringssl/crypto/asn1/asn1_locl.h new file mode 100644 index 00000000..ca5f6120 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/asn1_locl.h @@ -0,0 +1,73 @@ +/* asn1t.h */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006. + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* Internal ASN1 structures and functions: not for application use */ + +int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d); +int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d); + +/* ASN1 print context structure */ + +struct asn1_pctx_st + { + unsigned long flags; + unsigned long nm_flags; + unsigned long cert_flags; + unsigned long oid_flags; + unsigned long str_flags; + } /* ASN1_PCTX */; diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/asn1_par.c b/TMessagesProj/jni/boringssl/crypto/asn1/asn1_par.c new file mode 100644 index 00000000..aff3e2b7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/asn1_par.c @@ -0,0 +1,435 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + + +static int asn1_print_info(BIO *bp, int tag, int xclass,int constructed, + int indent); +static int asn1_parse2(BIO *bp, const unsigned char **pp, long length, + int offset, int depth, int indent, int dump); +static int asn1_print_info(BIO *bp, int tag, int xclass, int constructed, + int indent) + { + static const char fmt[]="%-18s"; + char str[128]; + const char *p; + + if (constructed & V_ASN1_CONSTRUCTED) + p="cons: "; + else + p="prim: "; + if (BIO_write(bp,p,6) < 6) goto err; + BIO_indent(bp,indent,128); + + p=str; + if ((xclass & V_ASN1_PRIVATE) == V_ASN1_PRIVATE) + BIO_snprintf(str,sizeof str,"priv [ %d ] ",tag); + else if ((xclass & V_ASN1_CONTEXT_SPECIFIC) == V_ASN1_CONTEXT_SPECIFIC) + BIO_snprintf(str,sizeof str,"cont [ %d ]",tag); + else if ((xclass & V_ASN1_APPLICATION) == V_ASN1_APPLICATION) + BIO_snprintf(str,sizeof str,"appl [ %d ]",tag); + else if (tag > 30) + BIO_snprintf(str,sizeof str,"",tag); + else + p = ASN1_tag2str(tag); + + if (BIO_printf(bp,fmt,p) <= 0) + goto err; + return(1); +err: + return(0); + } + +int ASN1_parse(BIO *bp, const unsigned char *pp, long len, int indent) + { + return(asn1_parse2(bp,&pp,len,0,0,indent,0)); + } + +int ASN1_parse_dump(BIO *bp, const unsigned char *pp, long len, int indent, int dump) + { + return(asn1_parse2(bp,&pp,len,0,0,indent,dump)); + } + +static int asn1_parse2(BIO *bp, const unsigned char **pp, long length, int offset, + int depth, int indent, int dump) + { + const unsigned char *p,*ep,*tot,*op,*opp; + long len; + int tag,xclass,ret=0; + int nl,hl,j,r; + ASN1_OBJECT *o=NULL; + ASN1_OCTET_STRING *os=NULL; + /* ASN1_BMPSTRING *bmp=NULL;*/ + int dump_indent; + +#if 0 + dump_indent = indent; +#else + dump_indent = 6; /* Because we know BIO_dump_indent() */ +#endif + p= *pp; + tot=p+length; + op=p-1; + while ((p < tot) && (op < p)) + { + op=p; + j=ASN1_get_object(&p,&len,&tag,&xclass,length); +#ifdef LINT + j=j; +#endif + if (j & 0x80) + { + if (BIO_puts(bp, "Error in encoding\n") <= 0) + goto end; + ret=0; + goto end; + } + hl=(p-op); + length-=hl; + /* if j == 0x21 it is a constructed indefinite length object */ + if (BIO_printf(bp,"%5ld:",(long)offset+(long)(op- *pp)) + <= 0) goto end; + + if (j != (V_ASN1_CONSTRUCTED | 1)) + { + if (BIO_printf(bp,"d=%-2d hl=%ld l=%4ld ", + depth,(long)hl,len) <= 0) + goto end; + } + else + { + if (BIO_printf(bp,"d=%-2d hl=%ld l=inf ", + depth,(long)hl) <= 0) + goto end; + } + if (!asn1_print_info(bp,tag,xclass,j,(indent)?depth:0)) + goto end; + if (j & V_ASN1_CONSTRUCTED) + { + ep=p+len; + if (BIO_puts(bp, "\n") <= 0) goto end; + if (len > length) + { + BIO_printf(bp, + "length is greater than %ld\n",length); + ret=0; + goto end; + } + if ((j == 0x21) && (len == 0)) + { + for (;;) + { + r=asn1_parse2(bp,&p,(long)(tot-p), + offset+(p - *pp),depth+1, + indent,dump); + if (r == 0) { ret=0; goto end; } + if ((r == 2) || (p >= tot)) break; + } + } + else + while (p < ep) + { + r=asn1_parse2(bp,&p,(long)len, + offset+(p - *pp),depth+1, + indent,dump); + if (r == 0) { ret=0; goto end; } + } + } + else if (xclass != 0) + { + p+=len; + if (BIO_puts(bp, "\n") <= 0) goto end; + } + else + { + nl=0; + if ( (tag == V_ASN1_PRINTABLESTRING) || + (tag == V_ASN1_T61STRING) || + (tag == V_ASN1_IA5STRING) || + (tag == V_ASN1_VISIBLESTRING) || + (tag == V_ASN1_NUMERICSTRING) || + (tag == V_ASN1_UTF8STRING) || + (tag == V_ASN1_UTCTIME) || + (tag == V_ASN1_GENERALIZEDTIME)) + { + if (BIO_puts(bp, ":") <= 0) goto end; + if ((len > 0) && + BIO_write(bp,(const char *)p,(int)len) + != (int)len) + goto end; + } + else if (tag == V_ASN1_OBJECT) + { + opp=op; + if (d2i_ASN1_OBJECT(&o,&opp,len+hl) != NULL) + { + if (BIO_puts(bp, ":") <= 0) goto end; + i2a_ASN1_OBJECT(bp,o); + } + else + { + if (BIO_puts(bp, ":BAD OBJECT") <= 0) + goto end; + } + } + else if (tag == V_ASN1_BOOLEAN) + { + int ii; + + opp=op; + ii=d2i_ASN1_BOOLEAN(NULL,&opp,len+hl); + if (ii < 0) + { + if (BIO_puts(bp, "Bad boolean\n") <= 0) + goto end; + } + BIO_printf(bp,":%d",ii); + } + else if (tag == V_ASN1_BMPSTRING) + { + /* do the BMP thang */ + } + else if (tag == V_ASN1_OCTET_STRING) + { + int i,printable=1; + + opp=op; + os=d2i_ASN1_OCTET_STRING(NULL,&opp,len+hl); + if (os != NULL && os->length > 0) + { + opp = os->data; + /* testing whether the octet string is + * printable */ + for (i=0; ilength; i++) + { + if (( (opp[i] < ' ') && + (opp[i] != '\n') && + (opp[i] != '\r') && + (opp[i] != '\t')) || + (opp[i] > '~')) + { + printable=0; + break; + } + } + if (printable) + /* printable string */ + { + if (BIO_puts(bp, ":") <= 0) + goto end; + if (BIO_write(bp,(const char *)opp, + os->length) <= 0) + goto end; + } + else if (!dump) + /* not printable => print octet string + * as hex dump */ + { + if (BIO_puts(bp, "[HEX DUMP]:") <= 0) + goto end; + for (i=0; ilength; i++) + { + if (BIO_printf(bp,"%02X" + , opp[i]) <= 0) + goto end; + } + } + else + /* print the normal dump */ + { + if (!nl) + { + if (BIO_puts(bp, "\n") <= 0) + goto end; + } + if (!BIO_hexdump(bp, opp, + ((dump == -1 || dump > + os->length)?os->length:dump), + dump_indent)) + goto end; + nl=1; + } + } + if (os != NULL) + { + M_ASN1_OCTET_STRING_free(os); + os=NULL; + } + } + else if (tag == V_ASN1_INTEGER) + { + ASN1_INTEGER *bs; + int i; + + opp=op; + bs=d2i_ASN1_INTEGER(NULL,&opp,len+hl); + if (bs != NULL) + { + if (BIO_puts(bp, ":") <= 0) goto end; + if (bs->type == V_ASN1_NEG_INTEGER) + if (BIO_puts(bp, "-") <= 0) + goto end; + for (i=0; ilength; i++) + { + if (BIO_printf(bp,"%02X", + bs->data[i]) <= 0) + goto end; + } + if (bs->length == 0) + { + if (BIO_puts(bp, "00") <= 0) + goto end; + } + } + else + { + if (BIO_puts(bp, "BAD INTEGER") <= 0) + goto end; + } + M_ASN1_INTEGER_free(bs); + } + else if (tag == V_ASN1_ENUMERATED) + { + ASN1_ENUMERATED *bs; + int i; + + opp=op; + bs=d2i_ASN1_ENUMERATED(NULL,&opp,len+hl); + if (bs != NULL) + { + if (BIO_puts(bp, ":") <= 0) goto end; + if (bs->type == V_ASN1_NEG_ENUMERATED) + if (BIO_puts(bp, "-") <= 0) + goto end; + for (i=0; ilength; i++) + { + if (BIO_printf(bp,"%02X", + bs->data[i]) <= 0) + goto end; + } + if (bs->length == 0) + { + if (BIO_puts(bp, "00") <= 0) + goto end; + } + } + else + { + if (BIO_puts(bp, "BAD ENUMERATED") <= 0) + goto end; + } + M_ASN1_ENUMERATED_free(bs); + } + else if (len > 0 && dump) + { + if (!nl) + { + if (BIO_puts(bp, "\n") <= 0) + goto end; + } + if (!BIO_hexdump(bp,p, + ((dump == -1 || dump > len)?len:dump), + dump_indent)) + goto end; + nl=1; + } + + if (!nl) + { + if (BIO_puts(bp, "\n") <= 0) goto end; + } + p+=len; + if ((tag == V_ASN1_EOC) && (xclass == 0)) + { + ret=2; /* End of sequence */ + goto end; + } + } + length-=len; + } + ret=1; +end: + if (o != NULL) ASN1_OBJECT_free(o); + if (os != NULL) M_ASN1_OCTET_STRING_free(os); + *pp=p; + return(ret); + } + +const char *ASN1_tag2str(int tag) +{ + static const char * const tag2str[] = { + "EOC", "BOOLEAN", "INTEGER", "BIT STRING", "OCTET STRING", /* 0-4 */ + "NULL", "OBJECT", "OBJECT DESCRIPTOR", "EXTERNAL", "REAL", /* 5-9 */ + "ENUMERATED", "", "UTF8STRING", "", /* 10-13 */ + "", "", "SEQUENCE", "SET", /* 15-17 */ + "NUMERICSTRING", "PRINTABLESTRING", "T61STRING", /* 18-20 */ + "VIDEOTEXSTRING", "IA5STRING", "UTCTIME","GENERALIZEDTIME", /* 21-24 */ + "GRAPHICSTRING", "VISIBLESTRING", "GENERALSTRING", /* 25-27 */ + "UNIVERSALSTRING", "", "BMPSTRING" /* 28-30 */ + }; + + if((tag == V_ASN1_NEG_INTEGER) || (tag == V_ASN1_NEG_ENUMERATED)) + tag &= ~0x100; + + if(tag < 0 || tag > 30) return "(unknown)"; + return tag2str[tag]; +} + diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/asn_pack.c b/TMessagesProj/jni/boringssl/crypto/asn1/asn_pack.c new file mode 100644 index 00000000..e842a10d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/asn_pack.c @@ -0,0 +1,104 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +/* ASN1_ITEM versions of the above */ + +ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_STRING **oct) +{ + ASN1_STRING *octmp; + + if (!oct || !*oct) { + if (!(octmp = ASN1_STRING_new ())) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return NULL; + } + if (oct) *oct = octmp; + } else octmp = *oct; + + if(octmp->data) { + OPENSSL_free(octmp->data); + octmp->data = NULL; + } + + if (!(octmp->length = ASN1_item_i2d(obj, &octmp->data, it))) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ENCODE_ERROR); + return NULL; + } + if (!octmp->data) { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return NULL; + } + return octmp; +} + +/* Extract an ASN1 object from an ASN1_STRING */ + +void *ASN1_item_unpack(ASN1_STRING *oct, const ASN1_ITEM *it) +{ + const unsigned char *p; + void *ret; + + p = oct->data; + if(!(ret = ASN1_item_d2i(NULL, &p, oct->length, it))) + OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/bio_asn1.c b/TMessagesProj/jni/boringssl/crypto/asn1/bio_asn1.c new file mode 100644 index 00000000..15f233be --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/bio_asn1.c @@ -0,0 +1,496 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include + + +/* Must be large enough for biggest tag+length */ +#define DEFAULT_ASN1_BUF_SIZE 20 + +typedef enum + { + ASN1_STATE_START, + ASN1_STATE_PRE_COPY, + ASN1_STATE_HEADER, + ASN1_STATE_HEADER_COPY, + ASN1_STATE_DATA_COPY, + ASN1_STATE_POST_COPY, + ASN1_STATE_DONE + } asn1_bio_state_t; + +typedef struct BIO_ASN1_EX_FUNCS_st + { + asn1_ps_func *ex_func; + asn1_ps_func *ex_free_func; + } BIO_ASN1_EX_FUNCS; + +typedef struct BIO_ASN1_BUF_CTX_t + { + /* Internal state */ + asn1_bio_state_t state; + /* Internal buffer */ + unsigned char *buf; + /* Size of buffer */ + int bufsize; + /* Current position in buffer */ + int bufpos; + /* Current buffer length */ + int buflen; + /* Amount of data to copy */ + int copylen; + /* Class and tag to use */ + int asn1_class, asn1_tag; + asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free; + /* Extra buffer for prefix and suffix data */ + unsigned char *ex_buf; + int ex_len; + int ex_pos; + void *ex_arg; + } BIO_ASN1_BUF_CTX; + + +static int asn1_bio_write(BIO *h, const char *buf,int num); +static int asn1_bio_read(BIO *h, char *buf, int size); +static int asn1_bio_puts(BIO *h, const char *str); +static int asn1_bio_gets(BIO *h, char *str, int size); +static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int asn1_bio_new(BIO *h); +static int asn1_bio_free(BIO *data); +static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb fp); + +static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size); +static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, + asn1_ps_func *cleanup, asn1_bio_state_t next); +static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, + asn1_ps_func *setup, + asn1_bio_state_t ex_state, + asn1_bio_state_t other_state); + +static const BIO_METHOD methods_asn1= + { + BIO_TYPE_ASN1, + "asn1", + asn1_bio_write, + asn1_bio_read, + asn1_bio_puts, + asn1_bio_gets, + asn1_bio_ctrl, + asn1_bio_new, + asn1_bio_free, + asn1_bio_callback_ctrl, + }; + +const BIO_METHOD *BIO_f_asn1(void) + { + return(&methods_asn1); + } + + +static int asn1_bio_new(BIO *b) + { + BIO_ASN1_BUF_CTX *ctx; + ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX)); + if (!ctx) + return 0; + if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) + { + OPENSSL_free(ctx); + return 0; + } + b->init = 1; + b->ptr = (char *)ctx; + b->flags = 0; + return 1; + } + +static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size) + { + ctx->buf = OPENSSL_malloc(size); + if (!ctx->buf) + return 0; + ctx->bufsize = size; + ctx->bufpos = 0; + ctx->buflen = 0; + ctx->copylen = 0; + ctx->asn1_class = V_ASN1_UNIVERSAL; + ctx->asn1_tag = V_ASN1_OCTET_STRING; + ctx->ex_buf = 0; + ctx->ex_pos = 0; + ctx->ex_len = 0; + ctx->state = ASN1_STATE_START; + return 1; + } + +static int asn1_bio_free(BIO *b) + { + BIO_ASN1_BUF_CTX *ctx; + ctx = (BIO_ASN1_BUF_CTX *) b->ptr; + if (ctx == NULL) + return 0; + if (ctx->buf) + OPENSSL_free(ctx->buf); + OPENSSL_free(ctx); + b->init = 0; + b->ptr = NULL; + b->flags = 0; + return 1; + } + +static int asn1_bio_write(BIO *b, const char *in , int inl) + { + BIO_ASN1_BUF_CTX *ctx; + int wrmax, wrlen, ret; + unsigned char *p; + if (!in || (inl < 0) || (b->next_bio == NULL)) + return 0; + ctx = (BIO_ASN1_BUF_CTX *) b->ptr; + if (ctx == NULL) + return 0; + + wrlen = 0; + ret = -1; + + for(;;) + { + switch (ctx->state) + { + + /* Setup prefix data, call it */ + case ASN1_STATE_START: + if (!asn1_bio_setup_ex(b, ctx, ctx->prefix, + ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER)) + return 0; + break; + + /* Copy any pre data first */ + case ASN1_STATE_PRE_COPY: + + ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free, + ASN1_STATE_HEADER); + + if (ret <= 0) + goto done; + + break; + + case ASN1_STATE_HEADER: + ctx->buflen = + ASN1_object_size(0, inl, ctx->asn1_tag) - inl; + assert(ctx->buflen <= ctx->bufsize); + p = ctx->buf; + ASN1_put_object(&p, 0, inl, + ctx->asn1_tag, ctx->asn1_class); + ctx->copylen = inl; + ctx->state = ASN1_STATE_HEADER_COPY; + + break; + + case ASN1_STATE_HEADER_COPY: + ret = BIO_write(b->next_bio, + ctx->buf + ctx->bufpos, ctx->buflen); + if (ret <= 0) + goto done; + + ctx->buflen -= ret; + if (ctx->buflen) + ctx->bufpos += ret; + else + { + ctx->bufpos = 0; + ctx->state = ASN1_STATE_DATA_COPY; + } + + break; + + case ASN1_STATE_DATA_COPY: + + if (inl > ctx->copylen) + wrmax = ctx->copylen; + else + wrmax = inl; + ret = BIO_write(b->next_bio, in, wrmax); + if (ret <= 0) + break; + wrlen += ret; + ctx->copylen -= ret; + in += ret; + inl -= ret; + + if (ctx->copylen == 0) + ctx->state = ASN1_STATE_HEADER; + + if (inl == 0) + goto done; + + break; + + default: + BIO_clear_retry_flags(b); + return 0; + + } + + } + + done: + BIO_clear_retry_flags(b); + BIO_copy_next_retry(b); + + return (wrlen > 0) ? wrlen : ret; + + } + +static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, + asn1_ps_func *cleanup, asn1_bio_state_t next) + { + int ret; + if (ctx->ex_len <= 0) + return 1; + for(;;) + { + ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos, + ctx->ex_len); + if (ret <= 0) + break; + ctx->ex_len -= ret; + if (ctx->ex_len > 0) + ctx->ex_pos += ret; + else + { + if(cleanup) + cleanup(b, &ctx->ex_buf, &ctx->ex_len, + &ctx->ex_arg); + ctx->state = next; + ctx->ex_pos = 0; + break; + } + } + return ret; + } + +static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, + asn1_ps_func *setup, + asn1_bio_state_t ex_state, + asn1_bio_state_t other_state) + { + if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) + { + BIO_clear_retry_flags(b); + return 0; + } + if (ctx->ex_len > 0) + ctx->state = ex_state; + else + ctx->state = other_state; + return 1; + } + +static int asn1_bio_read(BIO *b, char *in , int inl) + { + if (!b->next_bio) + return 0; + return BIO_read(b->next_bio, in , inl); + } + +static int asn1_bio_puts(BIO *b, const char *str) + { + return asn1_bio_write(b, str, strlen(str)); + } + +static int asn1_bio_gets(BIO *b, char *str, int size) + { + if (!b->next_bio) + return 0; + return BIO_gets(b->next_bio, str , size); + } + +static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) + { + if (b->next_bio == NULL) return(0); + return BIO_callback_ctrl(b->next_bio,cmd,fp); + } + +static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2) + { + BIO_ASN1_BUF_CTX *ctx; + BIO_ASN1_EX_FUNCS *ex_func; + long ret = 1; + ctx = (BIO_ASN1_BUF_CTX *) b->ptr; + if (ctx == NULL) + return 0; + switch(cmd) + { + + case BIO_C_SET_PREFIX: + ex_func = arg2; + ctx->prefix = ex_func->ex_func; + ctx->prefix_free = ex_func->ex_free_func; + break; + + case BIO_C_GET_PREFIX: + ex_func = arg2; + ex_func->ex_func = ctx->prefix; + ex_func->ex_free_func = ctx->prefix_free; + break; + + case BIO_C_SET_SUFFIX: + ex_func = arg2; + ctx->suffix = ex_func->ex_func; + ctx->suffix_free = ex_func->ex_free_func; + break; + + case BIO_C_GET_SUFFIX: + ex_func = arg2; + ex_func->ex_func = ctx->suffix; + ex_func->ex_free_func = ctx->suffix_free; + break; + + case BIO_C_SET_EX_ARG: + ctx->ex_arg = arg2; + break; + + case BIO_C_GET_EX_ARG: + *(void **)arg2 = ctx->ex_arg; + break; + + case BIO_CTRL_FLUSH: + if (!b->next_bio) + return 0; + + /* Call post function if possible */ + if (ctx->state == ASN1_STATE_HEADER) + { + if (!asn1_bio_setup_ex(b, ctx, ctx->suffix, + ASN1_STATE_POST_COPY, ASN1_STATE_DONE)) + return 0; + } + + if (ctx->state == ASN1_STATE_POST_COPY) + { + ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free, + ASN1_STATE_DONE); + if (ret <= 0) + return ret; + } + + if (ctx->state == ASN1_STATE_DONE) + return BIO_ctrl(b->next_bio, cmd, arg1, arg2); + else + { + BIO_clear_retry_flags(b); + return 0; + } + break; + + + default: + if (!b->next_bio) + return 0; + return BIO_ctrl(b->next_bio, cmd, arg1, arg2); + + } + + return ret; + } + +static int asn1_bio_set_ex(BIO *b, int cmd, + asn1_ps_func *ex_func, asn1_ps_func *ex_free_func) + { + BIO_ASN1_EX_FUNCS extmp; + extmp.ex_func = ex_func; + extmp.ex_free_func = ex_free_func; + return BIO_ctrl(b, cmd, 0, &extmp); + } + +static int asn1_bio_get_ex(BIO *b, int cmd, + asn1_ps_func **ex_func, asn1_ps_func **ex_free_func) + { + BIO_ASN1_EX_FUNCS extmp; + int ret; + ret = BIO_ctrl(b, cmd, 0, &extmp); + if (ret > 0) + { + *ex_func = extmp.ex_func; + *ex_free_func = extmp.ex_free_func; + } + return ret; + } + +int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free) + { + return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free); + } + +int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free) + { + return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free); + } + +int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, asn1_ps_func *suffix_free) + { + return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free); + } + +int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_func **psuffix_free) + { + return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free); + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/bio_ndef.c b/TMessagesProj/jni/boringssl/crypto/asn1/bio_ndef.c new file mode 100644 index 00000000..f07d3de7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/bio_ndef.c @@ -0,0 +1,254 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + + +/* Experimental NDEF ASN1 BIO support routines */ + +/* The usage is quite simple, initialize an ASN1 structure, + * get a BIO from it then any data written through the BIO + * will end up translated to approptiate format on the fly. + * The data is streamed out and does *not* need to be + * all held in memory at once. + * + * When the BIO is flushed the output is finalized and any + * signatures etc written out. + * + * The BIO is a 'proper' BIO and can handle non blocking I/O + * correctly. + * + * The usage is simple. The implementation is *not*... + */ + +/* BIO support data stored in the ASN1 BIO ex_arg */ + +typedef struct ndef_aux_st + { + /* ASN1 structure this BIO refers to */ + ASN1_VALUE *val; + const ASN1_ITEM *it; + /* Top of the BIO chain */ + BIO *ndef_bio; + /* Output BIO */ + BIO *out; + /* Boundary where content is inserted */ + unsigned char **boundary; + /* DER buffer start */ + unsigned char *derbuf; + } NDEF_SUPPORT; + +static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg); +static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg); +static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg); +static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg); + +BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it) + { + NDEF_SUPPORT *ndef_aux = NULL; + BIO *asn_bio = NULL; + const ASN1_AUX *aux = it->funcs; + ASN1_STREAM_ARG sarg; + + if (!aux || !aux->asn1_cb) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_STREAMING_NOT_SUPPORTED); + return NULL; + } + ndef_aux = OPENSSL_malloc(sizeof(NDEF_SUPPORT)); + asn_bio = BIO_new(BIO_f_asn1()); + + /* ASN1 bio needs to be next to output BIO */ + + out = BIO_push(asn_bio, out); + + if (!ndef_aux || !asn_bio || !out) + goto err; + + BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free); + BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free); + + /* Now let callback prepend any digest, cipher etc BIOs + * ASN1 structure needs. + */ + + sarg.out = out; + sarg.ndef_bio = NULL; + sarg.boundary = NULL; + + if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0) + goto err; + + ndef_aux->val = val; + ndef_aux->it = it; + ndef_aux->ndef_bio = sarg.ndef_bio; + ndef_aux->boundary = sarg.boundary; + ndef_aux->out = out; + + BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux); + + return sarg.ndef_bio; + + err: + if (asn_bio) + BIO_free(asn_bio); + if (ndef_aux) + OPENSSL_free(ndef_aux); + return NULL; + } + +static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg) + { + NDEF_SUPPORT *ndef_aux; + unsigned char *p; + int derlen; + + if (!parg) + return 0; + + ndef_aux = *(NDEF_SUPPORT **)parg; + + derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it); + p = OPENSSL_malloc(derlen); + if (p == NULL) + return 0; + + ndef_aux->derbuf = p; + *pbuf = p; + derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it); + + if (!*ndef_aux->boundary) + return 0; + + *plen = *ndef_aux->boundary - *pbuf; + + return 1; + } + +static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg) + { + NDEF_SUPPORT *ndef_aux; + + if (!parg) + return 0; + + ndef_aux = *(NDEF_SUPPORT **)parg; + + if (ndef_aux->derbuf) + OPENSSL_free(ndef_aux->derbuf); + + ndef_aux->derbuf = NULL; + *pbuf = NULL; + *plen = 0; + return 1; + } + +static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg) + { + NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg; + if (!ndef_prefix_free(b, pbuf, plen, parg)) + return 0; + OPENSSL_free(*pndef_aux); + *pndef_aux = NULL; + return 1; + } + +static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg) + { + NDEF_SUPPORT *ndef_aux; + unsigned char *p; + int derlen; + const ASN1_AUX *aux; + ASN1_STREAM_ARG sarg; + + if (!parg) + return 0; + + ndef_aux = *(NDEF_SUPPORT **)parg; + + aux = ndef_aux->it->funcs; + + /* Finalize structures */ + sarg.ndef_bio = ndef_aux->ndef_bio; + sarg.out = ndef_aux->out; + sarg.boundary = ndef_aux->boundary; + if (aux->asn1_cb(ASN1_OP_STREAM_POST, + &ndef_aux->val, ndef_aux->it, &sarg) <= 0) + return 0; + + derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it); + p = OPENSSL_malloc(derlen); + if (p == NULL) + return 0; + + ndef_aux->derbuf = p; + *pbuf = p; + derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it); + + if (!*ndef_aux->boundary) + return 0; + *pbuf = *ndef_aux->boundary; + *plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf); + + return 1; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/charmap.pl b/TMessagesProj/jni/boringssl/crypto/asn1/charmap.pl new file mode 100644 index 00000000..71bc7b8b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/charmap.pl @@ -0,0 +1,135 @@ +#!/usr/local/bin/perl -w + +# Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project +# 2000. +# +# ==================================================================== +# Copyright (c) 2000 The OpenSSL Project. 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. All advertising materials mentioning features or use of this +# software must display the following acknowledgment: +# "This product includes software developed by the OpenSSL Project +# for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" +# +# 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to +# endorse or promote products derived from this software without +# prior written permission. For written permission, please contact +# licensing@OpenSSL.org. +# +# 5. Products derived from this software may not be called "OpenSSL" +# nor may "OpenSSL" appear in their names without prior written +# permission of the OpenSSL Project. +# +# 6. Redistributions of any form whatsoever must retain the following +# acknowledgment: +# "This product includes software developed by the OpenSSL Project +# for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" +# +# THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young +# (eay@cryptsoft.com). This product includes software written by Tim +# Hudson (tjh@cryptsoft.com). + +use strict; + +my ($i, @arr); + +# Set up an array with the type of ASCII characters +# Each set bit represents a character property. + +# RFC2253 character properties +my $RFC2253_ESC = 1; # Character escaped with \ +my $ESC_CTRL = 2; # Escaped control character +# These are used with RFC1779 quoting using " +my $NOESC_QUOTE = 8; # Not escaped if quoted +my $PSTRING_CHAR = 0x10; # Valid PrintableString character +my $RFC2253_FIRST_ESC = 0x20; # Escaped with \ if first character +my $RFC2253_LAST_ESC = 0x40; # Escaped with \ if last character + +for($i = 0; $i < 128; $i++) { + # Set the RFC2253 escape characters (control) + $arr[$i] = 0; + if(($i < 32) || ($i > 126)) { + $arr[$i] |= $ESC_CTRL; + } + + # Some PrintableString characters + if( ( ( $i >= ord("a")) && ( $i <= ord("z")) ) + || ( ( $i >= ord("A")) && ( $i <= ord("Z")) ) + || ( ( $i >= ord("0")) && ( $i <= ord("9")) ) ) { + $arr[$i] |= $PSTRING_CHAR; + } +} + +# Now setup the rest + +# Remaining RFC2253 escaped characters + +$arr[ord(" ")] |= $NOESC_QUOTE | $RFC2253_FIRST_ESC | $RFC2253_LAST_ESC; +$arr[ord("#")] |= $NOESC_QUOTE | $RFC2253_FIRST_ESC; + +$arr[ord(",")] |= $NOESC_QUOTE | $RFC2253_ESC; +$arr[ord("+")] |= $NOESC_QUOTE | $RFC2253_ESC; +$arr[ord("\"")] |= $RFC2253_ESC; +$arr[ord("\\")] |= $RFC2253_ESC; +$arr[ord("<")] |= $NOESC_QUOTE | $RFC2253_ESC; +$arr[ord(">")] |= $NOESC_QUOTE | $RFC2253_ESC; +$arr[ord(";")] |= $NOESC_QUOTE | $RFC2253_ESC; + +# Remaining PrintableString characters + +$arr[ord(" ")] |= $PSTRING_CHAR; +$arr[ord("'")] |= $PSTRING_CHAR; +$arr[ord("(")] |= $PSTRING_CHAR; +$arr[ord(")")] |= $PSTRING_CHAR; +$arr[ord("+")] |= $PSTRING_CHAR; +$arr[ord(",")] |= $PSTRING_CHAR; +$arr[ord("-")] |= $PSTRING_CHAR; +$arr[ord(".")] |= $PSTRING_CHAR; +$arr[ord("/")] |= $PSTRING_CHAR; +$arr[ord(":")] |= $PSTRING_CHAR; +$arr[ord("=")] |= $PSTRING_CHAR; +$arr[ord("?")] |= $PSTRING_CHAR; + +# Now generate the C code + +print < + +#include +#include + +/* Based on a_int.c: equivalent ENUMERATED functions */ + +int i2a_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *a) + { + int i,n=0; + static const char *h="0123456789ABCDEF"; + char buf[2]; + + if (a == NULL) return(0); + + if (a->length == 0) + { + if (BIO_write(bp,"00",2) != 2) goto err; + n=2; + } + else + { + for (i=0; ilength; i++) + { + if ((i != 0) && (i%35 == 0)) + { + if (BIO_write(bp,"\\\n",2) != 2) goto err; + n+=2; + } + buf[0]=h[((unsigned char)a->data[i]>>4)&0x0f]; + buf[1]=h[((unsigned char)a->data[i] )&0x0f]; + if (BIO_write(bp,buf,2) != 2) goto err; + n+=2; + } + } + return(n); +err: + return(-1); + } + +int a2i_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *bs, char *buf, int size) + { + int ret=0; + int i,j,k,m,n,again,bufsize; + unsigned char *s=NULL,*sp; + unsigned char *bufp; + int num=0,slen=0,first=1; + + bs->type=V_ASN1_ENUMERATED; + + bufsize=BIO_gets(bp,buf,size); + for (;;) + { + if (bufsize < 1) goto err_sl; + i=bufsize; + if (buf[i-1] == '\n') buf[--i]='\0'; + if (i == 0) goto err_sl; + if (buf[i-1] == '\r') buf[--i]='\0'; + if (i == 0) goto err_sl; + again=(buf[i-1] == '\\'); + + for (j=0; j= '0') && (buf[j] <= '9')) || + ((buf[j] >= 'a') && (buf[j] <= 'f')) || + ((buf[j] >= 'A') && (buf[j] <= 'F')))) + { + i=j; + break; + } + } + buf[i]='\0'; + /* We have now cleared all the crap off the end of the + * line */ + if (i < 2) goto err_sl; + + bufp=(unsigned char *)buf; + if (first) + { + first=0; + if ((bufp[0] == '0') && (buf[1] == '0')) + { + bufp+=2; + i-=2; + } + } + k=0; + i-=again; + if (i%2 != 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS); + goto err; + } + i/=2; + if (num+i > slen) + { + if (s == NULL) + sp=(unsigned char *)OPENSSL_malloc( + (unsigned int)num+i*2); + else + sp=(unsigned char *)OPENSSL_realloc(s, + (unsigned int)num+i*2); + if (sp == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + s=sp; + slen=num+i*2; + } + for (j=0; j= '0') && (m <= '9')) + m-='0'; + else if ((m >= 'a') && (m <= 'f')) + m=m-'a'+10; + else if ((m >= 'A') && (m <= 'F')) + m=m-'A'+10; + else + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS); + goto err; + } + s[num+j]<<=4; + s[num+j]|=m; + } + } + num+=i; + if (again) + bufsize=BIO_gets(bp,buf,size); + else + break; + } + bs->length=num; + bs->data=s; + ret=1; +err: + if (0) + { +err_sl: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE); + } + if (s != NULL) + OPENSSL_free(s); + return(ret); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/f_int.c b/TMessagesProj/jni/boringssl/crypto/asn1/f_int.c new file mode 100644 index 00000000..5186304b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/f_int.c @@ -0,0 +1,210 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a) + { + int i,n=0; + static const char *h="0123456789ABCDEF"; + char buf[2]; + + if (a == NULL) return(0); + + if (a->type & V_ASN1_NEG) + { + if (BIO_write(bp, "-", 1) != 1) goto err; + n = 1; + } + + if (a->length == 0) + { + if (BIO_write(bp,"00",2) != 2) goto err; + n += 2; + } + else + { + for (i=0; ilength; i++) + { + if ((i != 0) && (i%35 == 0)) + { + if (BIO_write(bp,"\\\n",2) != 2) goto err; + n+=2; + } + buf[0]=h[((unsigned char)a->data[i]>>4)&0x0f]; + buf[1]=h[((unsigned char)a->data[i] )&0x0f]; + if (BIO_write(bp,buf,2) != 2) goto err; + n+=2; + } + } + return(n); +err: + return(-1); + } + +int a2i_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *bs, char *buf, int size) + { + int ret=0; + int i,j,k,m,n,again,bufsize; + unsigned char *s=NULL,*sp; + unsigned char *bufp; + int num=0,slen=0,first=1; + + bs->type=V_ASN1_INTEGER; + + bufsize=BIO_gets(bp,buf,size); + for (;;) + { + if (bufsize < 1) goto err_sl; + i=bufsize; + if (buf[i-1] == '\n') buf[--i]='\0'; + if (i == 0) goto err_sl; + if (buf[i-1] == '\r') buf[--i]='\0'; + if (i == 0) goto err_sl; + again=(buf[i-1] == '\\'); + + for (j=0; j= '0') && (buf[j] <= '9')) || + ((buf[j] >= 'a') && (buf[j] <= 'f')) || + ((buf[j] >= 'A') && (buf[j] <= 'F')))) + { + i=j; + break; + } + } + buf[i]='\0'; + /* We have now cleared all the crap off the end of the + * line */ + if (i < 2) goto err_sl; + + bufp=(unsigned char *)buf; + if (first) + { + first=0; + if ((bufp[0] == '0') && (buf[1] == '0')) + { + bufp+=2; + i-=2; + } + } + k=0; + i-=again; + if (i%2 != 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS); + goto err; + } + i/=2; + if (num+i > slen) + { + if (s == NULL) + sp=(unsigned char *)OPENSSL_malloc( + (unsigned int)num+i*2); + else + sp=OPENSSL_realloc_clean(s,slen,num+i*2); + if (sp == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + s=sp; + slen=num+i*2; + } + for (j=0; j= '0') && (m <= '9')) + m-='0'; + else if ((m >= 'a') && (m <= 'f')) + m=m-'a'+10; + else if ((m >= 'A') && (m <= 'F')) + m=m-'A'+10; + else + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS); + goto err; + } + s[num+j]<<=4; + s[num+j]|=m; + } + } + num+=i; + if (again) + bufsize=BIO_gets(bp,buf,size); + else + break; + } + bs->length=num; + bs->data=s; + ret=1; +err: + if (0) + { +err_sl: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE); + } + if (s != NULL) + OPENSSL_free(s); + return(ret); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/f_string.c b/TMessagesProj/jni/boringssl/crypto/asn1/f_string.c new file mode 100644 index 00000000..5a7fe36a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/f_string.c @@ -0,0 +1,204 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + + +int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type) + { + int i,n=0; + static const char *h="0123456789ABCDEF"; + char buf[2]; + + if (a == NULL) return(0); + + if (a->length == 0) + { + if (BIO_write(bp,"0",1) != 1) goto err; + n=1; + } + else + { + for (i=0; ilength; i++) + { + if ((i != 0) && (i%35 == 0)) + { + if (BIO_write(bp,"\\\n",2) != 2) goto err; + n+=2; + } + buf[0]=h[((unsigned char)a->data[i]>>4)&0x0f]; + buf[1]=h[((unsigned char)a->data[i] )&0x0f]; + if (BIO_write(bp,buf,2) != 2) goto err; + n+=2; + } + } + return(n); +err: + return(-1); + } + +int a2i_ASN1_STRING(BIO *bp, ASN1_STRING *bs, char *buf, int size) + { + int ret=0; + int i,j,k,m,n,again,bufsize; + unsigned char *s=NULL,*sp; + unsigned char *bufp; + int num=0,slen=0,first=1; + + bufsize=BIO_gets(bp,buf,size); + for (;;) + { + if (bufsize < 1) + { + if (first) + break; + else + goto err_sl; + } + first=0; + + i=bufsize; + if (buf[i-1] == '\n') buf[--i]='\0'; + if (i == 0) goto err_sl; + if (buf[i-1] == '\r') buf[--i]='\0'; + if (i == 0) goto err_sl; + again=(buf[i-1] == '\\'); + + for (j=i-1; j>0; j--) + { + if (!( ((buf[j] >= '0') && (buf[j] <= '9')) || + ((buf[j] >= 'a') && (buf[j] <= 'f')) || + ((buf[j] >= 'A') && (buf[j] <= 'F')))) + { + i=j; + break; + } + } + buf[i]='\0'; + /* We have now cleared all the crap off the end of the + * line */ + if (i < 2) goto err_sl; + + bufp=(unsigned char *)buf; + + k=0; + i-=again; + if (i%2 != 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ODD_NUMBER_OF_CHARS); + goto err; + } + i/=2; + if (num+i > slen) + { + if (s == NULL) + sp=(unsigned char *)OPENSSL_malloc( + (unsigned int)num+i*2); + else + sp=(unsigned char *)OPENSSL_realloc(s, + (unsigned int)num+i*2); + if (sp == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + s=sp; + slen=num+i*2; + } + for (j=0; j= '0') && (m <= '9')) + m-='0'; + else if ((m >= 'a') && (m <= 'f')) + m=m-'a'+10; + else if ((m >= 'A') && (m <= 'F')) + m=m-'A'+10; + else + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NON_HEX_CHARACTERS); + goto err; + } + s[num+j]<<=4; + s[num+j]|=m; + } + } + num+=i; + if (again) + bufsize=BIO_gets(bp,buf,size); + else + break; + } + bs->length=num; + bs->data=s; + ret=1; +err: + if (0) + { +err_sl: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_SHORT_LINE); + } + if (s != NULL) + OPENSSL_free(s); + return(ret); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/t_bitst.c b/TMessagesProj/jni/boringssl/crypto/asn1/t_bitst.c new file mode 100644 index 00000000..1ca6e089 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/t_bitst.c @@ -0,0 +1,102 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + + +int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs, + BIT_STRING_BITNAME *tbl, int indent) +{ + BIT_STRING_BITNAME *bnam; + char first = 1; + BIO_printf(out, "%*s", indent, ""); + for(bnam = tbl; bnam->lname; bnam++) { + if(ASN1_BIT_STRING_get_bit(bs, bnam->bitnum)) { + if(!first) BIO_puts(out, ", "); + BIO_puts(out, bnam->lname); + first = 0; + } + } + BIO_puts(out, "\n"); + return 1; +} + +int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, char *name, int value, + BIT_STRING_BITNAME *tbl) +{ + int bitnum; + bitnum = ASN1_BIT_STRING_num_asc(name, tbl); + if(bitnum < 0) return 0; + if(bs) { + if(!ASN1_BIT_STRING_set_bit(bs, bitnum, value)) + return 0; + } + return 1; +} + +int ASN1_BIT_STRING_num_asc(char *name, BIT_STRING_BITNAME *tbl) +{ + BIT_STRING_BITNAME *bnam; + for(bnam = tbl; bnam->lname; bnam++) { + if(!strcmp(bnam->sname, name) || + !strcmp(bnam->lname, name) ) return bnam->bitnum; + } + return -1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/t_pkey.c b/TMessagesProj/jni/boringssl/crypto/asn1/t_pkey.c new file mode 100644 index 00000000..6ac9b3d6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/t_pkey.c @@ -0,0 +1,112 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num, + unsigned char *buf, int off) + { + int n,i; + const char *neg; + + if (num == NULL) return(1); + neg = (BN_is_negative(num))?"-":""; + if(!BIO_indent(bp,off,128)) + return 0; + if (BN_is_zero(num)) + { + if (BIO_printf(bp, "%s 0\n", number) <= 0) + return 0; + return 1; + } + + if (BN_num_bytes(num) <= sizeof(long)) + { + if (BIO_printf(bp,"%s %s%lu (%s0x%lx)\n",number,neg, + (unsigned long)num->d[0],neg,(unsigned long)num->d[0]) + <= 0) return(0); + } + else + { + buf[0]=0; + if (BIO_printf(bp,"%s%s",number, + (neg[0] == '-')?" (Negative)":"") <= 0) + return(0); + n=BN_bn2bin(num,&buf[1]); + + if (buf[1] & 0x80) + n++; + else buf++; + + for (i=0; i + +#include + +#include +#include +#include +#include + +#include "../internal.h" + + +static int asn1_check_eoc(const unsigned char **in, long len); +static int asn1_find_end(const unsigned char **in, long len, char inf); + +static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, + char inf, int tag, int aclass, int depth); + +static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen); + +static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, + char *inf, char *cst, + const unsigned char **in, long len, + int exptag, int expclass, char opt, + ASN1_TLC *ctx); + +static int asn1_template_ex_d2i(ASN1_VALUE **pval, + const unsigned char **in, long len, + const ASN1_TEMPLATE *tt, char opt, + ASN1_TLC *ctx); +static int asn1_template_noexp_d2i(ASN1_VALUE **val, + const unsigned char **in, long len, + const ASN1_TEMPLATE *tt, char opt, + ASN1_TLC *ctx); +static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, + const unsigned char **in, long len, + const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx); + +/* Table to convert tags to bit values, used for MSTRING type */ +static const unsigned long tag2bit[32] = { +0, 0, 0, B_ASN1_BIT_STRING, /* tags 0 - 3 */ +B_ASN1_OCTET_STRING, 0, 0, B_ASN1_UNKNOWN,/* tags 4- 7 */ +B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN, B_ASN1_UNKNOWN,/* tags 8-11 */ +B_ASN1_UTF8STRING,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,B_ASN1_UNKNOWN,/* tags 12-15 */ +B_ASN1_SEQUENCE,0,B_ASN1_NUMERICSTRING,B_ASN1_PRINTABLESTRING, /* tags 16-19 */ +B_ASN1_T61STRING,B_ASN1_VIDEOTEXSTRING,B_ASN1_IA5STRING, /* tags 20-22 */ +B_ASN1_UTCTIME, B_ASN1_GENERALIZEDTIME, /* tags 23-24 */ +B_ASN1_GRAPHICSTRING,B_ASN1_ISO64STRING,B_ASN1_GENERALSTRING, /* tags 25-27 */ +B_ASN1_UNIVERSALSTRING,B_ASN1_UNKNOWN,B_ASN1_BMPSTRING,B_ASN1_UNKNOWN, /* tags 28-31 */ + }; + +unsigned long ASN1_tag2bit(int tag) + { + if ((tag < 0) || (tag > 30)) return 0; + return tag2bit[tag]; + } + +/* Macro to initialize and invalidate the cache */ + +#define asn1_tlc_clear(c) if (c) (c)->valid = 0 +/* Version to avoid compiler warning about 'c' always non-NULL */ +#define asn1_tlc_clear_nc(c) (c)->valid = 0 + +/* Decode an ASN1 item, this currently behaves just + * like a standard 'd2i' function. 'in' points to + * a buffer to read the data from, in future we will + * have more advanced versions that can input data + * a piece at a time and this will simply be a special + * case. + */ + +ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **pval, + const unsigned char **in, long len, const ASN1_ITEM *it) + { + ASN1_TLC c; + ASN1_VALUE *ptmpval = NULL; + if (!pval) + pval = &ptmpval; + asn1_tlc_clear_nc(&c); + if (ASN1_item_ex_d2i(pval, in, len, it, -1, 0, 0, &c) > 0) + return *pval; + return NULL; + } + +int ASN1_template_d2i(ASN1_VALUE **pval, + const unsigned char **in, long len, const ASN1_TEMPLATE *tt) + { + ASN1_TLC c; + asn1_tlc_clear_nc(&c); + return asn1_template_ex_d2i(pval, in, len, tt, 0, &c); + } + + +/* Decode an item, taking care of IMPLICIT tagging, if any. + * If 'opt' set and tag mismatch return -1 to handle OPTIONAL + */ + +int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, + const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx) + { + const ASN1_TEMPLATE *tt, *errtt = NULL; + const ASN1_COMPAT_FUNCS *cf; + const ASN1_EXTERN_FUNCS *ef; + const ASN1_AUX *aux = it->funcs; + ASN1_aux_cb *asn1_cb; + const unsigned char *p = NULL, *q; + unsigned char *wp=NULL; /* BIG FAT WARNING! BREAKS CONST WHERE USED */ + unsigned char imphack = 0, oclass; + char seq_eoc, seq_nolen, cst, isopt; + long tmplen; + int i; + int otag; + int ret = 0; + ASN1_VALUE **pchptr, *ptmpval; + if (!pval) + return 0; + if (aux && aux->asn1_cb) + asn1_cb = aux->asn1_cb; + else asn1_cb = 0; + + switch(it->itype) + { + case ASN1_ITYPE_PRIMITIVE: + if (it->templates) + { + /* tagging or OPTIONAL is currently illegal on an item + * template because the flags can't get passed down. + * In practice this isn't a problem: we include the + * relevant flags from the item template in the + * template itself. + */ + if ((tag != -1) || opt) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE); + goto err; + } + return asn1_template_ex_d2i(pval, in, len, + it->templates, opt, ctx); + } + return asn1_d2i_ex_primitive(pval, in, len, it, + tag, aclass, opt, ctx); + break; + + case ASN1_ITYPE_MSTRING: + p = *in; + /* Just read in tag and class */ + ret = asn1_check_tlen(NULL, &otag, &oclass, NULL, NULL, + &p, len, -1, 0, 1, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + + /* Must be UNIVERSAL class */ + if (oclass != V_ASN1_UNIVERSAL) + { + /* If OPTIONAL, assume this is OK */ + if (opt) return -1; + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MSTRING_NOT_UNIVERSAL); + goto err; + } + /* Check tag matches bit map */ + if (!(ASN1_tag2bit(otag) & it->utype)) + { + /* If OPTIONAL, assume this is OK */ + if (opt) + return -1; + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MSTRING_WRONG_TAG); + goto err; + } + return asn1_d2i_ex_primitive(pval, in, len, + it, otag, 0, 0, ctx); + + case ASN1_ITYPE_EXTERN: + /* Use new style d2i */ + ef = it->funcs; + return ef->asn1_ex_d2i(pval, in, len, + it, tag, aclass, opt, ctx); + + case ASN1_ITYPE_COMPAT: + /* we must resort to old style evil hackery */ + cf = it->funcs; + + /* If OPTIONAL see if it is there */ + if (opt) + { + int exptag; + p = *in; + if (tag == -1) + exptag = it->utype; + else exptag = tag; + /* Don't care about anything other than presence + * of expected tag */ + + ret = asn1_check_tlen(NULL, NULL, NULL, NULL, NULL, + &p, len, exptag, aclass, 1, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + if (ret == -1) + return -1; + } + + /* This is the old style evil hack IMPLICIT handling: + * since the underlying code is expecting a tag and + * class other than the one present we change the + * buffer temporarily then change it back afterwards. + * This doesn't and never did work for tags > 30. + * + * Yes this is *horrible* but it is only needed for + * old style d2i which will hopefully not be around + * for much longer. + * FIXME: should copy the buffer then modify it so + * the input buffer can be const: we should *always* + * copy because the old style d2i might modify the + * buffer. + */ + + if (tag != -1) + { + wp = *(unsigned char **)in; + imphack = *wp; + if (p == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + *wp = (unsigned char)((*p & V_ASN1_CONSTRUCTED) + | it->utype); + } + + ptmpval = cf->asn1_d2i(pval, in, len); + + if (tag != -1) + *wp = imphack; + + if (ptmpval) + return 1; + + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + + + case ASN1_ITYPE_CHOICE: + if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) + goto auxerr; + + if (*pval) + { + /* Free up and zero CHOICE value if initialised */ + i = asn1_get_choice_selector(pval, it); + if ((i >= 0) && (i < it->tcount)) + { + tt = it->templates + i; + pchptr = asn1_get_field_ptr(pval, tt); + ASN1_template_free(pchptr, tt); + asn1_set_choice_selector(pval, -1, it); + } + } + else if (!ASN1_item_ex_new(pval, it)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + /* CHOICE type, try each possibility in turn */ + p = *in; + for (i = 0, tt=it->templates; i < it->tcount; i++, tt++) + { + pchptr = asn1_get_field_ptr(pval, tt); + /* We mark field as OPTIONAL so its absence + * can be recognised. + */ + ret = asn1_template_ex_d2i(pchptr, &p, len, tt, 1, ctx); + /* If field not present, try the next one */ + if (ret == -1) + continue; + /* If positive return, read OK, break loop */ + if (ret > 0) + break; + /* Otherwise must be an ASN1 parsing error */ + errtt = tt; + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + + /* Did we fall off the end without reading anything? */ + if (i == it->tcount) + { + /* If OPTIONAL, this is OK */ + if (opt) + { + /* Free and zero it */ + ASN1_item_ex_free(pval, it); + return -1; + } + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NO_MATCHING_CHOICE_TYPE); + goto err; + } + + asn1_set_choice_selector(pval, i, it); + *in = p; + if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL)) + goto auxerr; + return 1; + + case ASN1_ITYPE_NDEF_SEQUENCE: + case ASN1_ITYPE_SEQUENCE: + p = *in; + tmplen = len; + + /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ + if (tag == -1) + { + tag = V_ASN1_SEQUENCE; + aclass = V_ASN1_UNIVERSAL; + } + /* Get SEQUENCE length and update len, p */ + ret = asn1_check_tlen(&len, NULL, NULL, &seq_eoc, &cst, + &p, len, tag, aclass, opt, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + else if (ret == -1) + return -1; + if (aux && (aux->flags & ASN1_AFLG_BROKEN)) + { + len = tmplen - (p - *in); + seq_nolen = 1; + } + /* If indefinite we don't do a length check */ + else seq_nolen = seq_eoc; + if (!cst) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_SEQUENCE_NOT_CONSTRUCTED); + goto err; + } + + if (!*pval && !ASN1_item_ex_new(pval, it)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + + if (asn1_cb && !asn1_cb(ASN1_OP_D2I_PRE, pval, it, NULL)) + goto auxerr; + + /* Free up and zero any ADB found */ + for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) + { + if (tt->flags & ASN1_TFLG_ADB_MASK) + { + const ASN1_TEMPLATE *seqtt; + ASN1_VALUE **pseqval; + seqtt = asn1_do_adb(pval, tt, 1); + pseqval = asn1_get_field_ptr(pval, seqtt); + ASN1_template_free(pseqval, seqtt); + } + } + + /* Get each field entry */ + for (i = 0, tt = it->templates; i < it->tcount; i++, tt++) + { + const ASN1_TEMPLATE *seqtt; + ASN1_VALUE **pseqval; + seqtt = asn1_do_adb(pval, tt, 1); + if (!seqtt) + goto err; + pseqval = asn1_get_field_ptr(pval, seqtt); + /* Have we ran out of data? */ + if (!len) + break; + q = p; + if (asn1_check_eoc(&p, len)) + { + if (!seq_eoc) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNEXPECTED_EOC); + goto err; + } + len -= p - q; + seq_eoc = 0; + q = p; + break; + } + /* This determines the OPTIONAL flag value. The field + * cannot be omitted if it is the last of a SEQUENCE + * and there is still data to be read. This isn't + * strictly necessary but it increases efficiency in + * some cases. + */ + if (i == (it->tcount - 1)) + isopt = 0; + else isopt = (char)(seqtt->flags & ASN1_TFLG_OPTIONAL); + /* attempt to read in field, allowing each to be + * OPTIONAL */ + + ret = asn1_template_ex_d2i(pseqval, &p, len, + seqtt, isopt, ctx); + if (!ret) + { + errtt = seqtt; + goto err; + } + else if (ret == -1) + { + /* OPTIONAL component absent. + * Free and zero the field. + */ + ASN1_template_free(pseqval, seqtt); + continue; + } + /* Update length */ + len -= p - q; + } + + /* Check for EOC if expecting one */ + if (seq_eoc && !asn1_check_eoc(&p, len)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC); + goto err; + } + /* Check all data read */ + if (!seq_nolen && len) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_SEQUENCE_LENGTH_MISMATCH); + goto err; + } + + /* If we get here we've got no more data in the SEQUENCE, + * however we may not have read all fields so check all + * remaining are OPTIONAL and clear any that are. + */ + for (; i < it->tcount; tt++, i++) + { + const ASN1_TEMPLATE *seqtt; + seqtt = asn1_do_adb(pval, tt, 1); + if (!seqtt) + goto err; + if (seqtt->flags & ASN1_TFLG_OPTIONAL) + { + ASN1_VALUE **pseqval; + pseqval = asn1_get_field_ptr(pval, seqtt); + ASN1_template_free(pseqval, seqtt); + } + else + { + errtt = seqtt; + OPENSSL_PUT_ERROR(ASN1, ASN1_R_FIELD_MISSING); + goto err; + } + } + /* Save encoding */ + if (!asn1_enc_save(pval, *in, p - *in, it)) + goto auxerr; + *in = p; + if (asn1_cb && !asn1_cb(ASN1_OP_D2I_POST, pval, it, NULL)) + goto auxerr; + return 1; + + default: + return 0; + } + auxerr: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_AUX_ERROR); + err: + ASN1_item_ex_free(pval, it); + if (errtt) + ERR_add_error_data(4, "Field=", errtt->field_name, + ", Type=", it->sname); + else + ERR_add_error_data(2, "Type=", it->sname); + return 0; + } + +/* Templates are handled with two separate functions. + * One handles any EXPLICIT tag and the other handles the rest. + */ + +static int asn1_template_ex_d2i(ASN1_VALUE **val, + const unsigned char **in, long inlen, + const ASN1_TEMPLATE *tt, char opt, + ASN1_TLC *ctx) + { + int flags, aclass; + int ret; + long len; + const unsigned char *p, *q; + char exp_eoc; + if (!val) + return 0; + flags = tt->flags; + aclass = flags & ASN1_TFLG_TAG_CLASS; + + p = *in; + + /* Check if EXPLICIT tag expected */ + if (flags & ASN1_TFLG_EXPTAG) + { + char cst; + /* Need to work out amount of data available to the inner + * content and where it starts: so read in EXPLICIT header to + * get the info. + */ + ret = asn1_check_tlen(&len, NULL, NULL, &exp_eoc, &cst, + &p, inlen, tt->tag, aclass, opt, ctx); + q = p; + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + return 0; + } + else if (ret == -1) + return -1; + if (!cst) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED); + return 0; + } + /* We've found the field so it can't be OPTIONAL now */ + ret = asn1_template_noexp_d2i(val, &p, len, tt, 0, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + return 0; + } + /* We read the field in OK so update length */ + len -= p - q; + if (exp_eoc) + { + /* If NDEF we must have an EOC here */ + if (!asn1_check_eoc(&p, len)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC); + goto err; + } + } + else + { + /* Otherwise we must hit the EXPLICIT tag end or its + * an error */ + if (len) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_EXPLICIT_LENGTH_MISMATCH); + goto err; + } + } + } + else + return asn1_template_noexp_d2i(val, in, inlen, + tt, opt, ctx); + + *in = p; + return 1; + + err: + ASN1_template_free(val, tt); + return 0; + } + +static int asn1_template_noexp_d2i(ASN1_VALUE **val, + const unsigned char **in, long len, + const ASN1_TEMPLATE *tt, char opt, + ASN1_TLC *ctx) + { + int flags, aclass; + int ret; + const unsigned char *p; + if (!val) + return 0; + flags = tt->flags; + aclass = flags & ASN1_TFLG_TAG_CLASS; + + p = *in; + + if (flags & ASN1_TFLG_SK_MASK) + { + /* SET OF, SEQUENCE OF */ + int sktag, skaclass; + char sk_eoc; + /* First work out expected inner tag value */ + if (flags & ASN1_TFLG_IMPTAG) + { + sktag = tt->tag; + skaclass = aclass; + } + else + { + skaclass = V_ASN1_UNIVERSAL; + if (flags & ASN1_TFLG_SET_OF) + sktag = V_ASN1_SET; + else + sktag = V_ASN1_SEQUENCE; + } + /* Get the tag */ + ret = asn1_check_tlen(&len, NULL, NULL, &sk_eoc, NULL, + &p, len, sktag, skaclass, opt, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + return 0; + } + else if (ret == -1) + return -1; + if (!*val) + *val = (ASN1_VALUE *)sk_new_null(); + else + { + /* We've got a valid STACK: free up any items present */ + STACK_OF(ASN1_VALUE) *sktmp + = (STACK_OF(ASN1_VALUE) *)*val; + ASN1_VALUE *vtmp; + while(sk_ASN1_VALUE_num(sktmp) > 0) + { + vtmp = sk_ASN1_VALUE_pop(sktmp); + ASN1_item_ex_free(&vtmp, + ASN1_ITEM_ptr(tt->item)); + } + } + + if (!*val) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Read as many items as we can */ + while(len > 0) + { + ASN1_VALUE *skfield; + const unsigned char *q = p; + /* See if EOC found */ + if (asn1_check_eoc(&p, len)) + { + if (!sk_eoc) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNEXPECTED_EOC); + goto err; + } + len -= p - q; + sk_eoc = 0; + break; + } + skfield = NULL; + if (!ASN1_item_ex_d2i(&skfield, &p, len, + ASN1_ITEM_ptr(tt->item), + -1, 0, 0, ctx)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + len -= p - q; + if (!sk_ASN1_VALUE_push((STACK_OF(ASN1_VALUE) *)*val, + skfield)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + } + if (sk_eoc) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC); + goto err; + } + } + else if (flags & ASN1_TFLG_IMPTAG) + { + /* IMPLICIT tagging */ + ret = ASN1_item_ex_d2i(val, &p, len, + ASN1_ITEM_ptr(tt->item), tt->tag, aclass, opt, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + else if (ret == -1) + return -1; + } + else + { + /* Nothing special */ + ret = ASN1_item_ex_d2i(val, &p, len, ASN1_ITEM_ptr(tt->item), + -1, 0, opt, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + goto err; + } + else if (ret == -1) + return -1; + } + + *in = p; + return 1; + + err: + ASN1_template_free(val, tt); + return 0; + } + +static int asn1_d2i_ex_primitive(ASN1_VALUE **pval, + const unsigned char **in, long inlen, + const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx) + OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS + { + int ret = 0, utype; + long plen; + char cst, inf, free_cont = 0; + const unsigned char *p; + BUF_MEM buf; + const unsigned char *cont = NULL; + long len; + if (!pval) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_NULL); + return 0; /* Should never happen */ + } + + if (it->itype == ASN1_ITYPE_MSTRING) + { + utype = tag; + tag = -1; + } + else + utype = it->utype; + + if (utype == V_ASN1_ANY) + { + /* If type is ANY need to figure out type from tag */ + unsigned char oclass; + if (tag >= 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_TAGGED_ANY); + return 0; + } + if (opt) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_OPTIONAL_ANY); + return 0; + } + p = *in; + ret = asn1_check_tlen(NULL, &utype, &oclass, NULL, NULL, + &p, inlen, -1, 0, 0, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + return 0; + } + if (oclass != V_ASN1_UNIVERSAL) + utype = V_ASN1_OTHER; + } + if (tag == -1) + { + tag = utype; + aclass = V_ASN1_UNIVERSAL; + } + p = *in; + /* Check header */ + ret = asn1_check_tlen(&plen, NULL, NULL, &inf, &cst, + &p, inlen, tag, aclass, opt, ctx); + if (!ret) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + return 0; + } + else if (ret == -1) + return -1; + ret = 0; + /* SEQUENCE, SET and "OTHER" are left in encoded form */ + if ((utype == V_ASN1_SEQUENCE) + || (utype == V_ASN1_SET) || (utype == V_ASN1_OTHER)) + { + /* Clear context cache for type OTHER because the auto clear + * when we have a exact match wont work + */ + if (utype == V_ASN1_OTHER) + { + asn1_tlc_clear(ctx); + } + /* SEQUENCE and SET must be constructed */ + else if (!cst) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TYPE_NOT_CONSTRUCTED); + return 0; + } + + cont = *in; + /* If indefinite length constructed find the real end */ + if (inf) + { + if (!asn1_find_end(&p, plen, inf)) + goto err; + len = p - cont; + } + else + { + len = p - cont + plen; + p += plen; + buf.data = NULL; + } + } + else if (cst) + { + if (utype == V_ASN1_NULL || utype == V_ASN1_BOOLEAN + || utype == V_ASN1_OBJECT || utype == V_ASN1_INTEGER + || utype == V_ASN1_ENUMERATED) + { + /* These types only have primitive encodings. */ + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TYPE_NOT_PRIMITIVE); + return 0; + } + + buf.length = 0; + buf.max = 0; + buf.data = NULL; + /* Should really check the internal tags are correct but + * some things may get this wrong. The relevant specs + * say that constructed string types should be OCTET STRINGs + * internally irrespective of the type. So instead just check + * for UNIVERSAL class and ignore the tag. + */ + if (!asn1_collect(&buf, &p, plen, inf, -1, V_ASN1_UNIVERSAL, 0)) + { + free_cont = 1; + goto err; + } + len = buf.length; + /* Append a final null to string */ + if (!BUF_MEM_grow_clean(&buf, len + 1)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return 0; + } + buf.data[len] = 0; + cont = (const unsigned char *)buf.data; + free_cont = 1; + } + else + { + cont = p; + len = plen; + p += plen; + } + + /* We now have content length and type: translate into a structure */ + if (!asn1_ex_c2i(pval, cont, len, utype, &free_cont, it)) + goto err; + + *in = p; + ret = 1; + err: + if (free_cont && buf.data) OPENSSL_free(buf.data); + return ret; + } + +/* Translate ASN1 content octets into a structure */ + +int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, + int utype, char *free_cont, const ASN1_ITEM *it) + { + ASN1_VALUE **opval = NULL; + ASN1_STRING *stmp; + ASN1_TYPE *typ = NULL; + int ret = 0; + const ASN1_PRIMITIVE_FUNCS *pf; + ASN1_INTEGER **tint; + pf = it->funcs; + + if (pf && pf->prim_c2i) + return pf->prim_c2i(pval, cont, len, utype, free_cont, it); + /* If ANY type clear type and set pointer to internal value */ + if (it->utype == V_ASN1_ANY) + { + if (!*pval) + { + typ = ASN1_TYPE_new(); + if (typ == NULL) + goto err; + *pval = (ASN1_VALUE *)typ; + } + else + typ = (ASN1_TYPE *)*pval; + + if (utype != typ->type) + ASN1_TYPE_set(typ, utype, NULL); + opval = pval; + pval = &typ->value.asn1_value; + } + switch(utype) + { + case V_ASN1_OBJECT: + if (!c2i_ASN1_OBJECT((ASN1_OBJECT **)pval, &cont, len)) + goto err; + break; + + case V_ASN1_NULL: + if (len) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NULL_IS_WRONG_LENGTH); + goto err; + } + *pval = (ASN1_VALUE *)1; + break; + + case V_ASN1_BOOLEAN: + if (len != 1) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_BOOLEAN_IS_WRONG_LENGTH); + goto err; + } + else + { + ASN1_BOOLEAN *tbool; + tbool = (ASN1_BOOLEAN *)pval; + *tbool = *cont; + } + break; + + case V_ASN1_BIT_STRING: + if (!c2i_ASN1_BIT_STRING((ASN1_BIT_STRING **)pval, &cont, len)) + goto err; + break; + + case V_ASN1_INTEGER: + case V_ASN1_NEG_INTEGER: + case V_ASN1_ENUMERATED: + case V_ASN1_NEG_ENUMERATED: + tint = (ASN1_INTEGER **)pval; + if (!c2i_ASN1_INTEGER(tint, &cont, len)) + goto err; + /* Fixup type to match the expected form */ + (*tint)->type = utype | ((*tint)->type & V_ASN1_NEG); + break; + + case V_ASN1_OCTET_STRING: + case V_ASN1_NUMERICSTRING: + case V_ASN1_PRINTABLESTRING: + case V_ASN1_T61STRING: + case V_ASN1_VIDEOTEXSTRING: + case V_ASN1_IA5STRING: + case V_ASN1_UTCTIME: + case V_ASN1_GENERALIZEDTIME: + case V_ASN1_GRAPHICSTRING: + case V_ASN1_VISIBLESTRING: + case V_ASN1_GENERALSTRING: + case V_ASN1_UNIVERSALSTRING: + case V_ASN1_BMPSTRING: + case V_ASN1_UTF8STRING: + case V_ASN1_OTHER: + case V_ASN1_SET: + case V_ASN1_SEQUENCE: + default: + if (utype == V_ASN1_BMPSTRING && (len & 1)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_BMPSTRING_IS_WRONG_LENGTH); + goto err; + } + if (utype == V_ASN1_UNIVERSALSTRING && (len & 3)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH); + goto err; + } + /* All based on ASN1_STRING and handled the same */ + if (!*pval) + { + stmp = ASN1_STRING_type_new(utype); + if (!stmp) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto err; + } + *pval = (ASN1_VALUE *)stmp; + } + else + { + stmp = (ASN1_STRING *)*pval; + stmp->type = utype; + } + /* If we've already allocated a buffer use it */ + if (*free_cont) + { + if (stmp->data) + OPENSSL_free(stmp->data); + stmp->data = (unsigned char *)cont; /* UGLY CAST! RL */ + stmp->length = len; + *free_cont = 0; + } + else + { + if (!ASN1_STRING_set(stmp, cont, len)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + ASN1_STRING_free(stmp); + *pval = NULL; + goto err; + } + } + break; + } + /* If ASN1_ANY and NULL type fix up value */ + if (typ && (utype == V_ASN1_NULL)) + typ->value.ptr = NULL; + + ret = 1; + err: + if (!ret) + { + ASN1_TYPE_free(typ); + if (opval) + *opval = NULL; + } + return ret; + } + + +/* This function finds the end of an ASN1 structure when passed its maximum + * length, whether it is indefinite length and a pointer to the content. + * This is more efficient than calling asn1_collect because it does not + * recurse on each indefinite length header. + */ + +static int asn1_find_end(const unsigned char **in, long len, char inf) + { + int expected_eoc; + long plen; + const unsigned char *p = *in, *q; + /* If not indefinite length constructed just add length */ + if (inf == 0) + { + *in += len; + return 1; + } + expected_eoc = 1; + /* Indefinite length constructed form. Find the end when enough EOCs + * are found. If more indefinite length constructed headers + * are encountered increment the expected eoc count otherwise just + * skip to the end of the data. + */ + while (len > 0) + { + if(asn1_check_eoc(&p, len)) + { + expected_eoc--; + if (expected_eoc == 0) + break; + len -= 2; + continue; + } + q = p; + /* Just read in a header: only care about the length */ + if(!asn1_check_tlen(&plen, NULL, NULL, &inf, NULL, &p, len, + -1, 0, 0, NULL)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + return 0; + } + if (inf) + expected_eoc++; + else + p += plen; + len -= p - q; + } + if (expected_eoc) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC); + return 0; + } + *in = p; + return 1; + } +/* This function collects the asn1 data from a constructred string + * type into a buffer. The values of 'in' and 'len' should refer + * to the contents of the constructed type and 'inf' should be set + * if it is indefinite length. + */ + +#ifndef ASN1_MAX_STRING_NEST +/* This determines how many levels of recursion are permitted in ASN1 + * string types. If it is not limited stack overflows can occur. If set + * to zero no recursion is allowed at all. Although zero should be adequate + * examples exist that require a value of 1. So 5 should be more than enough. + */ +#define ASN1_MAX_STRING_NEST 5 +#endif + + +static int asn1_collect(BUF_MEM *buf, const unsigned char **in, long len, + char inf, int tag, int aclass, int depth) + { + const unsigned char *p, *q; + long plen; + char cst, ininf; + p = *in; + inf &= 1; + /* If no buffer and not indefinite length constructed just pass over + * the encoded data */ + if (!buf && !inf) + { + *in += len; + return 1; + } + while(len > 0) + { + q = p; + /* Check for EOC */ + if (asn1_check_eoc(&p, len)) + { + /* EOC is illegal outside indefinite length + * constructed form */ + if (!inf) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNEXPECTED_EOC); + return 0; + } + inf = 0; + break; + } + + if (!asn1_check_tlen(&plen, NULL, NULL, &ininf, &cst, &p, + len, tag, aclass, 0, NULL)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_ERROR); + return 0; + } + + /* If indefinite length constructed update max length */ + if (cst) + { + if (depth >= ASN1_MAX_STRING_NEST) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NESTED_ASN1_STRING); + return 0; + } + if (!asn1_collect(buf, &p, plen, ininf, tag, aclass, + depth + 1)) + return 0; + } + else if (plen && !collect_data(buf, &p, plen)) + return 0; + len -= p - q; + } + if (inf) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_EOC); + return 0; + } + *in = p; + return 1; + } + +static int collect_data(BUF_MEM *buf, const unsigned char **p, long plen) + { + int len; + if (buf) + { + len = buf->length; + if (!BUF_MEM_grow_clean(buf, len + plen)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return 0; + } + memcpy(buf->data + len, *p, plen); + } + *p += plen; + return 1; + } + +/* Check for ASN1 EOC and swallow it if found */ + +static int asn1_check_eoc(const unsigned char **in, long len) + { + const unsigned char *p; + if (len < 2) return 0; + p = *in; + if (!p[0] && !p[1]) + { + *in += 2; + return 1; + } + return 0; + } + +/* Check an ASN1 tag and length: a bit like ASN1_get_object + * but it sets the length for indefinite length constructed + * form, we don't know the exact length but we can set an + * upper bound to the amount of data available minus the + * header length just read. + */ + +static int asn1_check_tlen(long *olen, int *otag, unsigned char *oclass, + char *inf, char *cst, + const unsigned char **in, long len, + int exptag, int expclass, char opt, + ASN1_TLC *ctx) + { + int i; + int ptag, pclass; + long plen; + const unsigned char *p, *q; + p = *in; + q = p; + + if (ctx && ctx->valid) + { + i = ctx->ret; + plen = ctx->plen; + pclass = ctx->pclass; + ptag = ctx->ptag; + p += ctx->hdrlen; + } + else + { + i = ASN1_get_object(&p, &plen, &ptag, &pclass, len); + if (ctx) + { + ctx->ret = i; + ctx->plen = plen; + ctx->pclass = pclass; + ctx->ptag = ptag; + ctx->hdrlen = p - q; + ctx->valid = 1; + /* If definite length, and no error, length + + * header can't exceed total amount of data available. + */ + if (!(i & 0x81) && ((plen + ctx->hdrlen) > len)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TOO_LONG); + asn1_tlc_clear(ctx); + return 0; + } + } + } + + if (i & 0x80) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_BAD_OBJECT_HEADER); + asn1_tlc_clear(ctx); + return 0; + } + if (exptag >= 0) + { + if ((exptag != ptag) || (expclass != pclass)) + { + /* If type is OPTIONAL, not an error: + * indicate missing type. + */ + if (opt) return -1; + asn1_tlc_clear(ctx); + OPENSSL_PUT_ERROR(ASN1, ASN1_R_WRONG_TAG); + return 0; + } + /* We have a tag and class match: + * assume we are going to do something with it */ + asn1_tlc_clear(ctx); + } + + if (i & 1) + plen = len - (p - q); + + if (inf) + *inf = i & 1; + + if (cst) + *cst = i & V_ASN1_CONSTRUCTED; + + if (olen) + *olen = plen; + + if (oclass) + *oclass = pclass; + + if (otag) + *otag = ptag; + + *in = p; + return 1; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/tasn_enc.c b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_enc.c new file mode 100644 index 00000000..38e14d2a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_enc.c @@ -0,0 +1,695 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include + + +static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, + const ASN1_ITEM *it, + int tag, int aclass); +static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, + int skcontlen, const ASN1_ITEM *item, + int do_sort, int iclass); +static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, + const ASN1_TEMPLATE *tt, + int tag, int aclass); +static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, + const ASN1_ITEM *it, int flags); + +/* Top level i2d equivalents: the 'ndef' variant instructs the encoder + * to use indefinite length constructed encoding, where appropriate + */ + +int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, + const ASN1_ITEM *it) + { + return asn1_item_flags_i2d(val, out, it, ASN1_TFLG_NDEF); + } + +int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it) + { + return asn1_item_flags_i2d(val, out, it, 0); + } + +/* Encode an ASN1 item, this is use by the + * standard 'i2d' function. 'out' points to + * a buffer to output the data to. + * + * The new i2d has one additional feature. If the output + * buffer is NULL (i.e. *out == NULL) then a buffer is + * allocated and populated with the encoding. + */ + +static int asn1_item_flags_i2d(ASN1_VALUE *val, unsigned char **out, + const ASN1_ITEM *it, int flags) + { + if (out && !*out) + { + unsigned char *p, *buf; + int len; + len = ASN1_item_ex_i2d(&val, NULL, it, -1, flags); + if (len <= 0) + return len; + buf = OPENSSL_malloc(len); + if (!buf) + return -1; + p = buf; + ASN1_item_ex_i2d(&val, &p, it, -1, flags); + *out = buf; + return len; + } + + return ASN1_item_ex_i2d(&val, out, it, -1, flags); + } + +/* Encode an item, taking care of IMPLICIT tagging (if any). + * This function performs the normal item handling: it can be + * used in external types. + */ + +int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, + const ASN1_ITEM *it, int tag, int aclass) + { + const ASN1_TEMPLATE *tt = NULL; + unsigned char *p = NULL; + int i, seqcontlen, seqlen, ndef = 1; + const ASN1_COMPAT_FUNCS *cf; + const ASN1_EXTERN_FUNCS *ef; + const ASN1_AUX *aux = it->funcs; + ASN1_aux_cb *asn1_cb = 0; + + if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) + return 0; + + if (aux && aux->asn1_cb) + asn1_cb = aux->asn1_cb; + + switch(it->itype) + { + + case ASN1_ITYPE_PRIMITIVE: + if (it->templates) + return asn1_template_ex_i2d(pval, out, it->templates, + tag, aclass); + return asn1_i2d_ex_primitive(pval, out, it, tag, aclass); + break; + + case ASN1_ITYPE_MSTRING: + return asn1_i2d_ex_primitive(pval, out, it, -1, aclass); + + case ASN1_ITYPE_CHOICE: + if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) + return 0; + i = asn1_get_choice_selector(pval, it); + if ((i >= 0) && (i < it->tcount)) + { + ASN1_VALUE **pchval; + const ASN1_TEMPLATE *chtt; + chtt = it->templates + i; + pchval = asn1_get_field_ptr(pval, chtt); + return asn1_template_ex_i2d(pchval, out, chtt, + -1, aclass); + } + /* Fixme: error condition if selector out of range */ + if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL)) + return 0; + break; + + case ASN1_ITYPE_EXTERN: + /* If new style i2d it does all the work */ + ef = it->funcs; + return ef->asn1_ex_i2d(pval, out, it, tag, aclass); + + case ASN1_ITYPE_COMPAT: + /* old style hackery... */ + cf = it->funcs; + if (out) + p = *out; + i = cf->asn1_i2d(*pval, out); + /* Fixup for IMPLICIT tag: note this messes up for tags > 30, + * but so did the old code. Tags > 30 are very rare anyway. + */ + if (out && (tag != -1)) + *p = aclass | tag | (*p & V_ASN1_CONSTRUCTED); + return i; + + case ASN1_ITYPE_NDEF_SEQUENCE: + /* Use indefinite length constructed if requested */ + if (aclass & ASN1_TFLG_NDEF) ndef = 2; + /* fall through */ + + case ASN1_ITYPE_SEQUENCE: + i = asn1_enc_restore(&seqcontlen, out, pval, it); + /* An error occurred */ + if (i < 0) + return 0; + /* We have a valid cached encoding... */ + if (i > 0) + return seqcontlen; + /* Otherwise carry on */ + seqcontlen = 0; + /* If no IMPLICIT tagging set to SEQUENCE, UNIVERSAL */ + if (tag == -1) + { + tag = V_ASN1_SEQUENCE; + /* Retain any other flags in aclass */ + aclass = (aclass & ~ASN1_TFLG_TAG_CLASS) + | V_ASN1_UNIVERSAL; + } + if (asn1_cb && !asn1_cb(ASN1_OP_I2D_PRE, pval, it, NULL)) + return 0; + /* First work out sequence content length */ + for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) + { + const ASN1_TEMPLATE *seqtt; + ASN1_VALUE **pseqval; + seqtt = asn1_do_adb(pval, tt, 1); + if (!seqtt) + return 0; + pseqval = asn1_get_field_ptr(pval, seqtt); + /* FIXME: check for errors in enhanced version */ + seqcontlen += asn1_template_ex_i2d(pseqval, NULL, seqtt, + -1, aclass); + } + + seqlen = ASN1_object_size(ndef, seqcontlen, tag); + if (!out) + return seqlen; + /* Output SEQUENCE header */ + ASN1_put_object(out, ndef, seqcontlen, tag, aclass); + for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) + { + const ASN1_TEMPLATE *seqtt; + ASN1_VALUE **pseqval; + seqtt = asn1_do_adb(pval, tt, 1); + if (!seqtt) + return 0; + pseqval = asn1_get_field_ptr(pval, seqtt); + /* FIXME: check for errors in enhanced version */ + asn1_template_ex_i2d(pseqval, out, seqtt, -1, aclass); + } + if (ndef == 2) + ASN1_put_eoc(out); + if (asn1_cb && !asn1_cb(ASN1_OP_I2D_POST, pval, it, NULL)) + return 0; + return seqlen; + + default: + return 0; + + } + return 0; + } + +int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, + const ASN1_TEMPLATE *tt) + { + return asn1_template_ex_i2d(pval, out, tt, -1, 0); + } + +static int asn1_template_ex_i2d(ASN1_VALUE **pval, unsigned char **out, + const ASN1_TEMPLATE *tt, int tag, int iclass) + { + int i, ret, flags, ttag, tclass, ndef; + size_t j; + flags = tt->flags; + /* Work out tag and class to use: tagging may come + * either from the template or the arguments, not both + * because this would create ambiguity. Additionally + * the iclass argument may contain some additional flags + * which should be noted and passed down to other levels. + */ + if (flags & ASN1_TFLG_TAG_MASK) + { + /* Error if argument and template tagging */ + if (tag != -1) + /* FIXME: error code here */ + return -1; + /* Get tagging from template */ + ttag = tt->tag; + tclass = flags & ASN1_TFLG_TAG_CLASS; + } + else if (tag != -1) + { + /* No template tagging, get from arguments */ + ttag = tag; + tclass = iclass & ASN1_TFLG_TAG_CLASS; + } + else + { + ttag = -1; + tclass = 0; + } + /* + * Remove any class mask from iflag. + */ + iclass &= ~ASN1_TFLG_TAG_CLASS; + + /* At this point 'ttag' contains the outer tag to use, + * 'tclass' is the class and iclass is any flags passed + * to this function. + */ + + /* if template and arguments require ndef, use it */ + if ((flags & ASN1_TFLG_NDEF) && (iclass & ASN1_TFLG_NDEF)) + ndef = 2; + else ndef = 1; + + if (flags & ASN1_TFLG_SK_MASK) + { + /* SET OF, SEQUENCE OF */ + STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval; + int isset, sktag, skaclass; + int skcontlen, sklen; + ASN1_VALUE *skitem; + + if (!*pval) + return 0; + + if (flags & ASN1_TFLG_SET_OF) + { + isset = 1; + /* 2 means we reorder */ + if (flags & ASN1_TFLG_SEQUENCE_OF) + isset = 2; + } + else isset = 0; + + /* Work out inner tag value: if EXPLICIT + * or no tagging use underlying type. + */ + if ((ttag != -1) && !(flags & ASN1_TFLG_EXPTAG)) + { + sktag = ttag; + skaclass = tclass; + } + else + { + skaclass = V_ASN1_UNIVERSAL; + if (isset) + sktag = V_ASN1_SET; + else sktag = V_ASN1_SEQUENCE; + } + + /* Determine total length of items */ + skcontlen = 0; + for (j = 0; j < sk_ASN1_VALUE_num(sk); j++) + { + skitem = sk_ASN1_VALUE_value(sk, j); + skcontlen += ASN1_item_ex_i2d(&skitem, NULL, + ASN1_ITEM_ptr(tt->item), + -1, iclass); + } + sklen = ASN1_object_size(ndef, skcontlen, sktag); + /* If EXPLICIT need length of surrounding tag */ + if (flags & ASN1_TFLG_EXPTAG) + ret = ASN1_object_size(ndef, sklen, ttag); + else ret = sklen; + + if (!out) + return ret; + + /* Now encode this lot... */ + /* EXPLICIT tag */ + if (flags & ASN1_TFLG_EXPTAG) + ASN1_put_object(out, ndef, sklen, ttag, tclass); + /* SET or SEQUENCE and IMPLICIT tag */ + ASN1_put_object(out, ndef, skcontlen, sktag, skaclass); + /* And the stuff itself */ + asn1_set_seq_out(sk, out, skcontlen, ASN1_ITEM_ptr(tt->item), + isset, iclass); + if (ndef == 2) + { + ASN1_put_eoc(out); + if (flags & ASN1_TFLG_EXPTAG) + ASN1_put_eoc(out); + } + + return ret; + } + + if (flags & ASN1_TFLG_EXPTAG) + { + /* EXPLICIT tagging */ + /* Find length of tagged item */ + i = ASN1_item_ex_i2d(pval, NULL, ASN1_ITEM_ptr(tt->item), + -1, iclass); + if (!i) + return 0; + /* Find length of EXPLICIT tag */ + ret = ASN1_object_size(ndef, i, ttag); + if (out) + { + /* Output tag and item */ + ASN1_put_object(out, ndef, i, ttag, tclass); + ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), + -1, iclass); + if (ndef == 2) + ASN1_put_eoc(out); + } + return ret; + } + + /* Either normal or IMPLICIT tagging: combine class and flags */ + return ASN1_item_ex_i2d(pval, out, ASN1_ITEM_ptr(tt->item), + ttag, tclass | iclass); + +} + +/* Temporary structure used to hold DER encoding of items for SET OF */ + +typedef struct { + unsigned char *data; + int length; + ASN1_VALUE *field; +} DER_ENC; + +static int der_cmp(const void *a, const void *b) + { + const DER_ENC *d1 = a, *d2 = b; + int cmplen, i; + cmplen = (d1->length < d2->length) ? d1->length : d2->length; + i = memcmp(d1->data, d2->data, cmplen); + if (i) + return i; + return d1->length - d2->length; + } + +/* Output the content octets of SET OF or SEQUENCE OF */ + +static int asn1_set_seq_out(STACK_OF(ASN1_VALUE) *sk, unsigned char **out, + int skcontlen, const ASN1_ITEM *item, + int do_sort, int iclass) + { + size_t i; + ASN1_VALUE *skitem; + unsigned char *tmpdat = NULL, *p = NULL; + DER_ENC *derlst = NULL, *tder; + if (do_sort) + { + /* Don't need to sort less than 2 items */ + if (sk_ASN1_VALUE_num(sk) < 2) + do_sort = 0; + else + { + derlst = OPENSSL_malloc(sk_ASN1_VALUE_num(sk) + * sizeof(*derlst)); + if (!derlst) + return 0; + tmpdat = OPENSSL_malloc(skcontlen); + if (!tmpdat) + { + OPENSSL_free(derlst); + return 0; + } + } + } + /* If not sorting just output each item */ + if (!do_sort) + { + for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) + { + skitem = sk_ASN1_VALUE_value(sk, i); + ASN1_item_ex_i2d(&skitem, out, item, -1, iclass); + } + return 1; + } + p = tmpdat; + + /* Doing sort: build up a list of each member's DER encoding */ + for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) + { + skitem = sk_ASN1_VALUE_value(sk, i); + tder->data = p; + tder->length = ASN1_item_ex_i2d(&skitem, &p, item, -1, iclass); + tder->field = skitem; + } + + /* Now sort them */ + qsort(derlst, sk_ASN1_VALUE_num(sk), sizeof(*derlst), der_cmp); + /* Output sorted DER encoding */ + p = *out; + for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); i++, tder++) + { + memcpy(p, tder->data, tder->length); + p += tder->length; + } + *out = p; + /* If do_sort is 2 then reorder the STACK */ + if (do_sort == 2) + { + for (i = 0, tder = derlst; i < sk_ASN1_VALUE_num(sk); + i++, tder++) + (void)sk_ASN1_VALUE_set(sk, i, tder->field); + } + OPENSSL_free(derlst); + OPENSSL_free(tmpdat); + return 1; + } + +static int asn1_i2d_ex_primitive(ASN1_VALUE **pval, unsigned char **out, + const ASN1_ITEM *it, int tag, int aclass) + { + int len; + int utype; + int usetag; + int ndef = 0; + + utype = it->utype; + + /* Get length of content octets and maybe find + * out the underlying type. + */ + + len = asn1_ex_i2c(pval, NULL, &utype, it); + + /* If SEQUENCE, SET or OTHER then header is + * included in pseudo content octets so don't + * include tag+length. We need to check here + * because the call to asn1_ex_i2c() could change + * utype. + */ + if ((utype == V_ASN1_SEQUENCE) || (utype == V_ASN1_SET) || + (utype == V_ASN1_OTHER)) + usetag = 0; + else usetag = 1; + + /* -1 means omit type */ + + if (len == -1) + return 0; + + /* -2 return is special meaning use ndef */ + if (len == -2) + { + ndef = 2; + len = 0; + } + + /* If not implicitly tagged get tag from underlying type */ + if (tag == -1) tag = utype; + + /* Output tag+length followed by content octets */ + if (out) + { + if (usetag) + ASN1_put_object(out, ndef, len, tag, aclass); + asn1_ex_i2c(pval, *out, &utype, it); + if (ndef) + ASN1_put_eoc(out); + else + *out += len; + } + + if (usetag) + return ASN1_object_size(ndef, len, tag); + return len; + } + +/* Produce content octets from a structure */ + +int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype, + const ASN1_ITEM *it) + { + ASN1_BOOLEAN *tbool = NULL; + ASN1_STRING *strtmp; + ASN1_OBJECT *otmp; + int utype; + const unsigned char *cont; + unsigned char c; + int len; + const ASN1_PRIMITIVE_FUNCS *pf; + pf = it->funcs; + if (pf && pf->prim_i2c) + return pf->prim_i2c(pval, cout, putype, it); + + /* Should type be omitted? */ + if ((it->itype != ASN1_ITYPE_PRIMITIVE) + || (it->utype != V_ASN1_BOOLEAN)) + { + if (!*pval) return -1; + } + + if (it->itype == ASN1_ITYPE_MSTRING) + { + /* If MSTRING type set the underlying type */ + strtmp = (ASN1_STRING *)*pval; + utype = strtmp->type; + *putype = utype; + } + else if (it->utype == V_ASN1_ANY) + { + /* If ANY set type and pointer to value */ + ASN1_TYPE *typ; + typ = (ASN1_TYPE *)*pval; + utype = typ->type; + *putype = utype; + pval = &typ->value.asn1_value; + } + else utype = *putype; + + switch(utype) + { + case V_ASN1_OBJECT: + otmp = (ASN1_OBJECT *)*pval; + cont = otmp->data; + len = otmp->length; + break; + + case V_ASN1_NULL: + cont = NULL; + len = 0; + break; + + case V_ASN1_BOOLEAN: + tbool = (ASN1_BOOLEAN *)pval; + if (*tbool == -1) + return -1; + if (it->utype != V_ASN1_ANY) + { + /* Default handling if value == size field then omit */ + if (*tbool && (it->size > 0)) + return -1; + if (!*tbool && !it->size) + return -1; + } + c = (unsigned char)*tbool; + cont = &c; + len = 1; + break; + + case V_ASN1_BIT_STRING: + return i2c_ASN1_BIT_STRING((ASN1_BIT_STRING *)*pval, + cout ? &cout : NULL); + break; + + case V_ASN1_INTEGER: + case V_ASN1_NEG_INTEGER: + case V_ASN1_ENUMERATED: + case V_ASN1_NEG_ENUMERATED: + /* These are all have the same content format + * as ASN1_INTEGER + */ + return i2c_ASN1_INTEGER((ASN1_INTEGER *)*pval, + cout ? &cout : NULL); + break; + + case V_ASN1_OCTET_STRING: + case V_ASN1_NUMERICSTRING: + case V_ASN1_PRINTABLESTRING: + case V_ASN1_T61STRING: + case V_ASN1_VIDEOTEXSTRING: + case V_ASN1_IA5STRING: + case V_ASN1_UTCTIME: + case V_ASN1_GENERALIZEDTIME: + case V_ASN1_GRAPHICSTRING: + case V_ASN1_VISIBLESTRING: + case V_ASN1_GENERALSTRING: + case V_ASN1_UNIVERSALSTRING: + case V_ASN1_BMPSTRING: + case V_ASN1_UTF8STRING: + case V_ASN1_SEQUENCE: + case V_ASN1_SET: + default: + /* All based on ASN1_STRING and handled the same */ + strtmp = (ASN1_STRING *)*pval; + /* Special handling for NDEF */ + if ((it->size == ASN1_TFLG_NDEF) + && (strtmp->flags & ASN1_STRING_FLAG_NDEF)) + { + if (cout) + { + strtmp->data = cout; + strtmp->length = 0; + } + /* Special return code */ + return -2; + } + cont = strtmp->data; + len = strtmp->length; + + break; + + } + if (cout && len) + memcpy(cout, cont, len); + return len; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/tasn_fre.c b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_fre.c new file mode 100644 index 00000000..d1317ae4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_fre.c @@ -0,0 +1,264 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int combine); + +/* Free up an ASN1 structure */ + +void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it) + { + asn1_item_combine_free(&val, it, 0); + } + +void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it) + { + asn1_item_combine_free(pval, it, 0); + } + +static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int combine) + { + const ASN1_TEMPLATE *tt = NULL, *seqtt; + const ASN1_EXTERN_FUNCS *ef; + const ASN1_COMPAT_FUNCS *cf; + const ASN1_AUX *aux = it->funcs; + ASN1_aux_cb *asn1_cb; + int i; + if (!pval) + return; + if ((it->itype != ASN1_ITYPE_PRIMITIVE) && !*pval) + return; + if (aux && aux->asn1_cb) + asn1_cb = aux->asn1_cb; + else + asn1_cb = 0; + + switch(it->itype) + { + + case ASN1_ITYPE_PRIMITIVE: + if (it->templates) + ASN1_template_free(pval, it->templates); + else + ASN1_primitive_free(pval, it); + break; + + case ASN1_ITYPE_MSTRING: + ASN1_primitive_free(pval, it); + break; + + case ASN1_ITYPE_CHOICE: + if (asn1_cb) + { + i = asn1_cb(ASN1_OP_FREE_PRE, pval, it, NULL); + if (i == 2) + return; + } + i = asn1_get_choice_selector(pval, it); + if ((i >= 0) && (i < it->tcount)) + { + ASN1_VALUE **pchval; + tt = it->templates + i; + pchval = asn1_get_field_ptr(pval, tt); + ASN1_template_free(pchval, tt); + } + if (asn1_cb) + asn1_cb(ASN1_OP_FREE_POST, pval, it, NULL); + if (!combine) + { + OPENSSL_free(*pval); + *pval = NULL; + } + break; + + case ASN1_ITYPE_COMPAT: + cf = it->funcs; + if (cf && cf->asn1_free) + cf->asn1_free(*pval); + break; + + case ASN1_ITYPE_EXTERN: + ef = it->funcs; + if (ef && ef->asn1_ex_free) + ef->asn1_ex_free(pval, it); + break; + + case ASN1_ITYPE_NDEF_SEQUENCE: + case ASN1_ITYPE_SEQUENCE: + if (!asn1_refcount_dec_and_test_zero(pval, it)) + return; + if (asn1_cb) + { + i = asn1_cb(ASN1_OP_FREE_PRE, pval, it, NULL); + if (i == 2) + return; + } + asn1_enc_free(pval, it); + /* If we free up as normal we will invalidate any + * ANY DEFINED BY field and we wont be able to + * determine the type of the field it defines. So + * free up in reverse order. + */ + tt = it->templates + it->tcount - 1; + for (i = 0; i < it->tcount; tt--, i++) + { + ASN1_VALUE **pseqval; + seqtt = asn1_do_adb(pval, tt, 0); + if (!seqtt) + continue; + pseqval = asn1_get_field_ptr(pval, seqtt); + ASN1_template_free(pseqval, seqtt); + } + if (asn1_cb) + asn1_cb(ASN1_OP_FREE_POST, pval, it, NULL); + if (!combine) + { + OPENSSL_free(*pval); + *pval = NULL; + } + break; + } + } + +void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) + { + size_t i; + if (tt->flags & ASN1_TFLG_SK_MASK) + { + STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval; + for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) + { + ASN1_VALUE *vtmp; + vtmp = sk_ASN1_VALUE_value(sk, i); + asn1_item_combine_free(&vtmp, ASN1_ITEM_ptr(tt->item), + 0); + } + sk_ASN1_VALUE_free(sk); + *pval = NULL; + } + else + asn1_item_combine_free(pval, ASN1_ITEM_ptr(tt->item), + tt->flags & ASN1_TFLG_COMBINE); + } + +void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it) + { + int utype; + if (it) + { + const ASN1_PRIMITIVE_FUNCS *pf; + pf = it->funcs; + if (pf && pf->prim_free) + { + pf->prim_free(pval, it); + return; + } + } + /* Special case: if 'it' is NULL free contents of ASN1_TYPE */ + if (!it) + { + ASN1_TYPE *typ = (ASN1_TYPE *)*pval; + utype = typ->type; + pval = &typ->value.asn1_value; + if (!*pval) + return; + } + else if (it->itype == ASN1_ITYPE_MSTRING) + { + utype = -1; + if (!*pval) + return; + } + else + { + utype = it->utype; + if ((utype != V_ASN1_BOOLEAN) && !*pval) + return; + } + + switch(utype) + { + case V_ASN1_OBJECT: + ASN1_OBJECT_free((ASN1_OBJECT *)*pval); + break; + + case V_ASN1_BOOLEAN: + if (it) + *(ASN1_BOOLEAN *)pval = it->size; + else + *(ASN1_BOOLEAN *)pval = -1; + return; + + case V_ASN1_NULL: + break; + + case V_ASN1_ANY: + ASN1_primitive_free(pval, NULL); + OPENSSL_free(*pval); + break; + + default: + ASN1_STRING_free((ASN1_STRING *)*pval); + *pval = NULL; + break; + } + *pval = NULL; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/tasn_new.c b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_new.c new file mode 100644 index 00000000..c68fe066 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_new.c @@ -0,0 +1,398 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + + +static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it, + int combine); +static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it); +static void asn1_template_clear(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); +static void asn1_primitive_clear(ASN1_VALUE **pval, const ASN1_ITEM *it); + +ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it) + { + ASN1_VALUE *ret = NULL; + if (ASN1_item_ex_new(&ret, it) > 0) + return ret; + return NULL; + } + +/* Allocate an ASN1 structure */ + +int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it) + { + return asn1_item_ex_combine_new(pval, it, 0); + } + +static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it, + int combine) + { + const ASN1_TEMPLATE *tt = NULL; + const ASN1_COMPAT_FUNCS *cf; + const ASN1_EXTERN_FUNCS *ef; + const ASN1_AUX *aux = it->funcs; + ASN1_aux_cb *asn1_cb; + ASN1_VALUE **pseqval; + int i; + if (aux && aux->asn1_cb) + asn1_cb = aux->asn1_cb; + else + asn1_cb = 0; + +#ifdef CRYPTO_MDEBUG + if (it->sname) + CRYPTO_push_info(it->sname); +#endif + + switch(it->itype) + { + + case ASN1_ITYPE_EXTERN: + ef = it->funcs; + if (ef && ef->asn1_ex_new) + { + if (!ef->asn1_ex_new(pval, it)) + goto memerr; + } + break; + + case ASN1_ITYPE_COMPAT: + cf = it->funcs; + if (cf && cf->asn1_new) { + *pval = cf->asn1_new(); + if (!*pval) + goto memerr; + } + break; + + case ASN1_ITYPE_PRIMITIVE: + if (it->templates) + { + if (!ASN1_template_new(pval, it->templates)) + goto memerr; + } + else if (!ASN1_primitive_new(pval, it)) + goto memerr; + break; + + case ASN1_ITYPE_MSTRING: + if (!ASN1_primitive_new(pval, it)) + goto memerr; + break; + + case ASN1_ITYPE_CHOICE: + if (asn1_cb) + { + i = asn1_cb(ASN1_OP_NEW_PRE, pval, it, NULL); + if (!i) + goto auxerr; + if (i==2) + { +#ifdef CRYPTO_MDEBUG + if (it->sname) + CRYPTO_pop_info(); +#endif + return 1; + } + } + if (!combine) + { + *pval = OPENSSL_malloc(it->size); + if (!*pval) + goto memerr; + memset(*pval, 0, it->size); + } + asn1_set_choice_selector(pval, -1, it); + if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL)) + goto auxerr; + break; + + case ASN1_ITYPE_NDEF_SEQUENCE: + case ASN1_ITYPE_SEQUENCE: + if (asn1_cb) + { + i = asn1_cb(ASN1_OP_NEW_PRE, pval, it, NULL); + if (!i) + goto auxerr; + if (i==2) + { +#ifdef CRYPTO_MDEBUG + if (it->sname) + CRYPTO_pop_info(); +#endif + return 1; + } + } + if (!combine) + { + *pval = OPENSSL_malloc(it->size); + if (!*pval) + goto memerr; + memset(*pval, 0, it->size); + asn1_refcount_set_one(pval, it); + asn1_enc_init(pval, it); + } + for (i = 0, tt = it->templates; i < it->tcount; tt++, i++) + { + pseqval = asn1_get_field_ptr(pval, tt); + if (!ASN1_template_new(pseqval, tt)) + goto memerr; + } + if (asn1_cb && !asn1_cb(ASN1_OP_NEW_POST, pval, it, NULL)) + goto auxerr; + break; + } +#ifdef CRYPTO_MDEBUG + if (it->sname) CRYPTO_pop_info(); +#endif + return 1; + + memerr: + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + ASN1_item_ex_free(pval, it); +#ifdef CRYPTO_MDEBUG + if (it->sname) CRYPTO_pop_info(); +#endif + return 0; + + auxerr: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_AUX_ERROR); + ASN1_item_ex_free(pval, it); +#ifdef CRYPTO_MDEBUG + if (it->sname) CRYPTO_pop_info(); +#endif + return 0; + + } + +static void asn1_item_clear(ASN1_VALUE **pval, const ASN1_ITEM *it) + { + const ASN1_EXTERN_FUNCS *ef; + + switch(it->itype) + { + + case ASN1_ITYPE_EXTERN: + ef = it->funcs; + if (ef && ef->asn1_ex_clear) + ef->asn1_ex_clear(pval, it); + else *pval = NULL; + break; + + + case ASN1_ITYPE_PRIMITIVE: + if (it->templates) + asn1_template_clear(pval, it->templates); + else + asn1_primitive_clear(pval, it); + break; + + case ASN1_ITYPE_MSTRING: + asn1_primitive_clear(pval, it); + break; + + case ASN1_ITYPE_COMPAT: + case ASN1_ITYPE_CHOICE: + case ASN1_ITYPE_SEQUENCE: + case ASN1_ITYPE_NDEF_SEQUENCE: + *pval = NULL; + break; + } + } + + +int ASN1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) + { + const ASN1_ITEM *it = ASN1_ITEM_ptr(tt->item); + int ret; + if (tt->flags & ASN1_TFLG_OPTIONAL) + { + asn1_template_clear(pval, tt); + return 1; + } + /* If ANY DEFINED BY nothing to do */ + + if (tt->flags & ASN1_TFLG_ADB_MASK) + { + *pval = NULL; + return 1; + } +#ifdef CRYPTO_MDEBUG + if (tt->field_name) + CRYPTO_push_info(tt->field_name); +#endif + /* If SET OF or SEQUENCE OF, its a STACK */ + if (tt->flags & ASN1_TFLG_SK_MASK) + { + STACK_OF(ASN1_VALUE) *skval; + skval = sk_ASN1_VALUE_new_null(); + if (!skval) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + ret = 0; + goto done; + } + *pval = (ASN1_VALUE *)skval; + ret = 1; + goto done; + } + /* Otherwise pass it back to the item routine */ + ret = asn1_item_ex_combine_new(pval, it, tt->flags & ASN1_TFLG_COMBINE); + done: +#ifdef CRYPTO_MDEBUG + if (it->sname) + CRYPTO_pop_info(); +#endif + return ret; + } + +static void asn1_template_clear(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) + { + /* If ADB or STACK just NULL the field */ + if (tt->flags & (ASN1_TFLG_ADB_MASK|ASN1_TFLG_SK_MASK)) + *pval = NULL; + else + asn1_item_clear(pval, ASN1_ITEM_ptr(tt->item)); + } + + +/* NB: could probably combine most of the real XXX_new() behaviour and junk + * all the old functions. + */ + +int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it) + { + ASN1_TYPE *typ; + ASN1_STRING *str; + int utype; + + if (!it) + return 0; + + if (it->funcs) + { + const ASN1_PRIMITIVE_FUNCS *pf = it->funcs; + if (pf->prim_new) + return pf->prim_new(pval, it); + } + + if (it->itype == ASN1_ITYPE_MSTRING) + utype = -1; + else + utype = it->utype; + switch(utype) + { + case V_ASN1_OBJECT: + *pval = (ASN1_VALUE *)OBJ_nid2obj(NID_undef); + return 1; + + case V_ASN1_BOOLEAN: + *(ASN1_BOOLEAN *)pval = it->size; + return 1; + + case V_ASN1_NULL: + *pval = (ASN1_VALUE *)1; + return 1; + + case V_ASN1_ANY: + typ = OPENSSL_malloc(sizeof(ASN1_TYPE)); + if (!typ) + return 0; + typ->value.ptr = NULL; + typ->type = -1; + *pval = (ASN1_VALUE *)typ; + break; + + default: + str = ASN1_STRING_type_new(utype); + if (it->itype == ASN1_ITYPE_MSTRING && str) + str->flags |= ASN1_STRING_FLAG_MSTRING; + *pval = (ASN1_VALUE *)str; + break; + } + if (*pval) + return 1; + return 0; + } + +static void asn1_primitive_clear(ASN1_VALUE **pval, const ASN1_ITEM *it) + { + int utype; + if (it && it->funcs) + { + const ASN1_PRIMITIVE_FUNCS *pf = it->funcs; + if (pf->prim_clear) + pf->prim_clear(pval, it); + else + *pval = NULL; + return; + } + if (!it || (it->itype == ASN1_ITYPE_MSTRING)) + utype = -1; + else + utype = it->utype; + if (utype == V_ASN1_BOOLEAN) + *(ASN1_BOOLEAN *)pval = it->size; + else *pval = NULL; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/tasn_prn.c b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_prn.c new file mode 100644 index 00000000..6a097a18 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_prn.c @@ -0,0 +1,642 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + +#include "asn1_locl.h" + + + +/* Print routines. + */ + +/* ASN1_PCTX routines */ + +ASN1_PCTX default_pctx = + { + ASN1_PCTX_FLAGS_SHOW_ABSENT, /* flags */ + 0, /* nm_flags */ + 0, /* cert_flags */ + 0, /* oid_flags */ + 0 /* str_flags */ + }; + + +ASN1_PCTX *ASN1_PCTX_new(void) + { + ASN1_PCTX *ret; + ret = OPENSSL_malloc(sizeof(ASN1_PCTX)); + if (ret == NULL) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return NULL; + } + ret->flags = 0; + ret->nm_flags = 0; + ret->cert_flags = 0; + ret->oid_flags = 0; + ret->str_flags = 0; + return ret; + } + +void ASN1_PCTX_free(ASN1_PCTX *p) + { + OPENSSL_free(p); + } + +unsigned long ASN1_PCTX_get_flags(ASN1_PCTX *p) + { + return p->flags; + } + +void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags) + { + p->flags = flags; + } + +unsigned long ASN1_PCTX_get_nm_flags(ASN1_PCTX *p) + { + return p->nm_flags; + } + +void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags) + { + p->nm_flags = flags; + } + +unsigned long ASN1_PCTX_get_cert_flags(ASN1_PCTX *p) + { + return p->cert_flags; + } + +void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags) + { + p->cert_flags = flags; + } + +unsigned long ASN1_PCTX_get_oid_flags(ASN1_PCTX *p) + { + return p->oid_flags; + } + +void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags) + { + p->oid_flags = flags; + } + +unsigned long ASN1_PCTX_get_str_flags(ASN1_PCTX *p) + { + return p->str_flags; + } + +void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags) + { + p->str_flags = flags; + } + +/* Main print routines */ + +static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent, + const ASN1_ITEM *it, + const char *fname, const char *sname, + int nohdr, const ASN1_PCTX *pctx); + +int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent, + const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx); + +static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld, + const ASN1_ITEM *it, int indent, + const char *fname, const char *sname, + const ASN1_PCTX *pctx); + +static int asn1_print_fsname(BIO *out, int indent, + const char *fname, const char *sname, + const ASN1_PCTX *pctx); + +int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent, + const ASN1_ITEM *it, const ASN1_PCTX *pctx) + { + const char *sname; + if (pctx == NULL) + pctx = &default_pctx; + if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME) + sname = NULL; + else + sname = it->sname; + return asn1_item_print_ctx(out, &ifld, indent, it, + NULL, sname, 0, pctx); + } + +static int asn1_item_print_ctx(BIO *out, ASN1_VALUE **fld, int indent, + const ASN1_ITEM *it, + const char *fname, const char *sname, + int nohdr, const ASN1_PCTX *pctx) + { + const ASN1_TEMPLATE *tt; + const ASN1_EXTERN_FUNCS *ef; + ASN1_VALUE **tmpfld; + const ASN1_AUX *aux = it->funcs; + ASN1_aux_cb *asn1_cb; + ASN1_PRINT_ARG parg; + int i; + if (aux && aux->asn1_cb) + { + parg.out = out; + parg.indent = indent; + parg.pctx = pctx; + asn1_cb = aux->asn1_cb; + } + else asn1_cb = 0; + + if(*fld == NULL) + { + if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_ABSENT) + { + if (!nohdr && !asn1_print_fsname(out, indent, + fname, sname, pctx)) + return 0; + if (BIO_puts(out, "\n") <= 0) + return 0; + } + return 1; + } + + switch(it->itype) + { + case ASN1_ITYPE_PRIMITIVE: + if(it->templates) + { + if (!asn1_template_print_ctx(out, fld, indent, + it->templates, pctx)) + return 0; + break; + } + /* fall thru */ + case ASN1_ITYPE_MSTRING: + if (!asn1_primitive_print(out, fld, it, + indent, fname, sname,pctx)) + return 0; + break; + + case ASN1_ITYPE_EXTERN: + if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx)) + return 0; + /* Use new style print routine if possible */ + ef = it->funcs; + if (ef && ef->asn1_ex_print) + { + i = ef->asn1_ex_print(out, fld, indent, "", pctx); + if (!i) + return 0; + if ((i == 2) && (BIO_puts(out, "\n") <= 0)) + return 0; + return 1; + } + else if (sname && + BIO_printf(out, ":EXTERNAL TYPE %s\n", sname) <= 0) + return 0; + break; + + case ASN1_ITYPE_CHOICE: +#if 0 + if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx)) + return 0; +#endif + /* CHOICE type, get selector */ + i = asn1_get_choice_selector(fld, it); + /* This should never happen... */ + if((i < 0) || (i >= it->tcount)) + { + if (BIO_printf(out, + "ERROR: selector [%d] invalid\n", i) <= 0) + return 0; + return 1; + } + tt = it->templates + i; + tmpfld = asn1_get_field_ptr(fld, tt); + if (!asn1_template_print_ctx(out, tmpfld, indent, tt, pctx)) + return 0; + break; + + case ASN1_ITYPE_SEQUENCE: + case ASN1_ITYPE_NDEF_SEQUENCE: + if (!nohdr && !asn1_print_fsname(out, indent, fname, sname, pctx)) + return 0; + if (fname || sname) + { + if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) + { + if (BIO_puts(out, " {\n") <= 0) + return 0; + } + else + { + if (BIO_puts(out, "\n") <= 0) + return 0; + } + } + + if (asn1_cb) + { + i = asn1_cb(ASN1_OP_PRINT_PRE, fld, it, &parg); + if (i == 0) + return 0; + if (i == 2) + return 1; + } + + /* Print each field entry */ + for(i = 0, tt = it->templates; i < it->tcount; i++, tt++) + { + const ASN1_TEMPLATE *seqtt; + seqtt = asn1_do_adb(fld, tt, 1); + if (!seqtt) + return 0; + tmpfld = asn1_get_field_ptr(fld, seqtt); + if (!asn1_template_print_ctx(out, tmpfld, + indent + 2, seqtt, pctx)) + return 0; + } + if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) + { + if (BIO_printf(out, "%*s}\n", indent, "") < 0) + return 0; + } + + if (asn1_cb) + { + i = asn1_cb(ASN1_OP_PRINT_POST, fld, it, &parg); + if (i == 0) + return 0; + } + break; + + default: + BIO_printf(out, "Unprocessed type %d\n", it->itype); + return 0; + } + + return 1; + } + +int asn1_template_print_ctx(BIO *out, ASN1_VALUE **fld, int indent, + const ASN1_TEMPLATE *tt, const ASN1_PCTX *pctx) + { + int flags; + size_t i; + const char *sname, *fname; + flags = tt->flags; + if(pctx->flags & ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME) + sname = ASN1_ITEM_ptr(tt->item)->sname; + else + sname = NULL; + if(pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME) + fname = NULL; + else + fname = tt->field_name; + if(flags & ASN1_TFLG_SK_MASK) + { + const char *tname; + ASN1_VALUE *skitem; + STACK_OF(ASN1_VALUE) *stack; + + /* SET OF, SEQUENCE OF */ + if (fname) + { + if(pctx->flags & ASN1_PCTX_FLAGS_SHOW_SSOF) + { + if(flags & ASN1_TFLG_SET_OF) + tname = "SET"; + else + tname = "SEQUENCE"; + if (BIO_printf(out, "%*s%s OF %s {\n", + indent, "", tname, tt->field_name) <= 0) + return 0; + } + else if (BIO_printf(out, "%*s%s:\n", indent, "", + fname) <= 0) + return 0; + } + stack = (STACK_OF(ASN1_VALUE) *)*fld; + for(i = 0; i < sk_ASN1_VALUE_num(stack); i++) + { + if ((i > 0) && (BIO_puts(out, "\n") <= 0)) + return 0; + + skitem = sk_ASN1_VALUE_value(stack, i); + if (!asn1_item_print_ctx(out, &skitem, indent + 2, + ASN1_ITEM_ptr(tt->item), NULL, NULL, 1, pctx)) + return 0; + } + if (!i && BIO_printf(out, "%*s\n", indent + 2, "") <= 0) + return 0; + if(pctx->flags & ASN1_PCTX_FLAGS_SHOW_SEQUENCE) + { + if (BIO_printf(out, "%*s}\n", indent, "") <= 0) + return 0; + } + return 1; + } + return asn1_item_print_ctx(out, fld, indent, ASN1_ITEM_ptr(tt->item), + fname, sname, 0, pctx); + } + +static int asn1_print_fsname(BIO *out, int indent, + const char *fname, const char *sname, + const ASN1_PCTX *pctx) + { + static char spaces[] = " "; + const int nspaces = sizeof(spaces) - 1; + +#if 0 + if (!sname && !fname) + return 1; +#endif + + while (indent > nspaces) + { + if (BIO_write(out, spaces, nspaces) != nspaces) + return 0; + indent -= nspaces; + } + if (BIO_write(out, spaces, indent) != indent) + return 0; + if (pctx->flags & ASN1_PCTX_FLAGS_NO_STRUCT_NAME) + sname = NULL; + if (pctx->flags & ASN1_PCTX_FLAGS_NO_FIELD_NAME) + fname = NULL; + if (!sname && !fname) + return 1; + if (fname) + { + if (BIO_puts(out, fname) <= 0) + return 0; + } + if (sname) + { + if (fname) + { + if (BIO_printf(out, " (%s)", sname) <= 0) + return 0; + } + else + { + if (BIO_puts(out, sname) <= 0) + return 0; + } + } + if (BIO_write(out, ": ", 2) != 2) + return 0; + return 1; + } + +static int asn1_print_boolean_ctx(BIO *out, int boolval, + const ASN1_PCTX *pctx) + { + const char *str; + switch (boolval) + { + case -1: + str = "BOOL ABSENT"; + break; + + case 0: + str = "FALSE"; + break; + + default: + str = "TRUE"; + break; + + } + + if (BIO_puts(out, str) <= 0) + return 0; + return 1; + + } + +static int asn1_print_integer_ctx(BIO *out, ASN1_INTEGER *str, + const ASN1_PCTX *pctx) + { + BIGNUM *bn = NULL; + char *s = NULL; + int ret = 1; + + bn = ASN1_INTEGER_to_BN(str, NULL); + if (bn == NULL) { + return 0; + } + s = BN_bn2dec(bn); + BN_free(bn); + if (s == NULL) { + return 0; + } + + if (BIO_puts(out, s) <= 0) { + ret = 0; + } + OPENSSL_free(s); + return ret; + } + +static int asn1_print_oid_ctx(BIO *out, const ASN1_OBJECT *oid, + const ASN1_PCTX *pctx) + { + char objbuf[80]; + const char *ln; + ln = OBJ_nid2ln(OBJ_obj2nid(oid)); + if(!ln) + ln = ""; + OBJ_obj2txt(objbuf, sizeof objbuf, oid, 1); + if (BIO_printf(out, "%s (%s)", ln, objbuf) <= 0) + return 0; + return 1; + } + +static int asn1_print_obstring_ctx(BIO *out, ASN1_STRING *str, int indent, + const ASN1_PCTX *pctx) + { + if (str->type == V_ASN1_BIT_STRING) + { + if (BIO_printf(out, " (%ld unused bits)\n", + str->flags & 0x7) <= 0) + return 0; + } + else if (BIO_puts(out, "\n") <= 0) + return 0; + if (str->length > 0 && !BIO_hexdump(out, str->data, str->length, indent + 2)) { + return 0; + } + return 1; + } + +static int asn1_primitive_print(BIO *out, ASN1_VALUE **fld, + const ASN1_ITEM *it, int indent, + const char *fname, const char *sname, + const ASN1_PCTX *pctx) + { + long utype; + ASN1_STRING *str; + int ret = 1, needlf = 1; + const char *pname; + const ASN1_PRIMITIVE_FUNCS *pf; + pf = it->funcs; + if (!asn1_print_fsname(out, indent, fname, sname, pctx)) + return 0; + if (pf && pf->prim_print) + return pf->prim_print(out, fld, it, indent, pctx); + str = (ASN1_STRING *)*fld; + if (it->itype == ASN1_ITYPE_MSTRING) + utype = str->type & ~V_ASN1_NEG; + else + utype = it->utype; + if (utype == V_ASN1_ANY) + { + ASN1_TYPE *atype = (ASN1_TYPE *)*fld; + utype = atype->type; + fld = &atype->value.asn1_value; + str = (ASN1_STRING *)*fld; + if (pctx->flags & ASN1_PCTX_FLAGS_NO_ANY_TYPE) + pname = NULL; + else + pname = ASN1_tag2str(utype); + } + else + { + if (pctx->flags & ASN1_PCTX_FLAGS_SHOW_TYPE) + pname = ASN1_tag2str(utype); + else + pname = NULL; + } + + if (utype == V_ASN1_NULL) + { + if (BIO_puts(out, "NULL\n") <= 0) + return 0; + return 1; + } + + if (pname) + { + if (BIO_puts(out, pname) <= 0) + return 0; + if (BIO_puts(out, ":") <= 0) + return 0; + } + + switch (utype) + { + case V_ASN1_BOOLEAN: + { + int boolval = *(int *)fld; + if (boolval == -1) + boolval = it->size; + ret = asn1_print_boolean_ctx(out, boolval, pctx); + } + break; + + case V_ASN1_INTEGER: + case V_ASN1_ENUMERATED: + ret = asn1_print_integer_ctx(out, str, pctx); + break; + + case V_ASN1_UTCTIME: + ret = ASN1_UTCTIME_print(out, str); + break; + + case V_ASN1_GENERALIZEDTIME: + ret = ASN1_GENERALIZEDTIME_print(out, str); + break; + + case V_ASN1_OBJECT: + ret = asn1_print_oid_ctx(out, (const ASN1_OBJECT *)*fld, pctx); + break; + + case V_ASN1_OCTET_STRING: + case V_ASN1_BIT_STRING: + ret = asn1_print_obstring_ctx(out, str, indent, pctx); + needlf = 0; + break; + + case V_ASN1_SEQUENCE: + case V_ASN1_SET: + case V_ASN1_OTHER: + if (BIO_puts(out, "\n") <= 0) + return 0; + if (ASN1_parse_dump(out, str->data, str->length, + indent, 0) <= 0) + ret = 0; + needlf = 0; + break; + + default: + ret = ASN1_STRING_print_ex(out, str, pctx->str_flags); + + } + if (!ret) + return 0; + if (needlf && BIO_puts(out, "\n") <= 0) + return 0; + return 1; + } diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/tasn_typ.c b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_typ.c new file mode 100644 index 00000000..f004b0dc --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_typ.c @@ -0,0 +1,137 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + + +/* Declarations for string types */ + +#define IMPLEMENT_ASN1_STRING_FUNCTIONS(sname) \ + IMPLEMENT_ASN1_TYPE(sname) \ + IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(sname, sname, sname) \ + sname *sname##_new(void) \ + { \ + return ASN1_STRING_type_new(V_##sname); \ + } \ + void sname##_free(sname *x) \ + { \ + ASN1_STRING_free(x); \ + } + +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_OCTET_STRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_INTEGER) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_ENUMERATED) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_BIT_STRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_UTF8STRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_PRINTABLESTRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_T61STRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_IA5STRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_GENERALSTRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_UTCTIME) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_GENERALIZEDTIME) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_VISIBLESTRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_UNIVERSALSTRING) +IMPLEMENT_ASN1_STRING_FUNCTIONS(ASN1_BMPSTRING) + +IMPLEMENT_ASN1_TYPE(ASN1_NULL); +IMPLEMENT_ASN1_FUNCTIONS(ASN1_NULL); + +IMPLEMENT_ASN1_TYPE(ASN1_OBJECT); + +IMPLEMENT_ASN1_TYPE(ASN1_ANY); + +/* Just swallow an ASN1_SEQUENCE in an ASN1_STRING */; +IMPLEMENT_ASN1_TYPE(ASN1_SEQUENCE); + +IMPLEMENT_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE); + +/* Multistring types */; + +IMPLEMENT_ASN1_MSTRING(ASN1_PRINTABLE, B_ASN1_PRINTABLE); +IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE); + +IMPLEMENT_ASN1_MSTRING(DISPLAYTEXT, B_ASN1_DISPLAYTEXT); +IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT); + +IMPLEMENT_ASN1_MSTRING(DIRECTORYSTRING, B_ASN1_DIRECTORYSTRING); +IMPLEMENT_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING); + +/* Three separate BOOLEAN type: normal, DEFAULT TRUE and DEFAULT FALSE */; +IMPLEMENT_ASN1_TYPE_ex(ASN1_BOOLEAN, ASN1_BOOLEAN, -1); +IMPLEMENT_ASN1_TYPE_ex(ASN1_TBOOLEAN, ASN1_BOOLEAN, 1); +IMPLEMENT_ASN1_TYPE_ex(ASN1_FBOOLEAN, ASN1_BOOLEAN, 0); + +/* Special, OCTET STRING with indefinite length constructed support */; + +IMPLEMENT_ASN1_TYPE_ex(ASN1_OCTET_STRING_NDEF, ASN1_OCTET_STRING, + ASN1_TFLG_NDEF); + +ASN1_ITEM_TEMPLATE(ASN1_SEQUENCE_ANY) = ASN1_EX_TEMPLATE_TYPE( + ASN1_TFLG_SEQUENCE_OF, 0, ASN1_SEQUENCE_ANY, ASN1_ANY); +ASN1_ITEM_TEMPLATE_END(ASN1_SEQUENCE_ANY); + +ASN1_ITEM_TEMPLATE(ASN1_SET_ANY) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0, + ASN1_SET_ANY, + ASN1_ANY); +ASN1_ITEM_TEMPLATE_END(ASN1_SET_ANY); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, + ASN1_SEQUENCE_ANY, + ASN1_SEQUENCE_ANY); +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(ASN1_SEQUENCE_ANY, ASN1_SET_ANY, + ASN1_SET_ANY); diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/tasn_utl.c b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_utl.c new file mode 100644 index 00000000..960cdbb7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/tasn_utl.c @@ -0,0 +1,266 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "../internal.h" + + +/* Utility functions for manipulating fields and offsets */ + +/* Add 'offset' to 'addr' */ +#define offset2ptr(addr, offset) (void *)(((char *) addr) + offset) + +/* Given an ASN1_ITEM CHOICE type return the selector value */ +int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it) { + int *sel = offset2ptr(*pval, it->utype); + return *sel; +} + +/* Given an ASN1_ITEM CHOICE type set the selector value, return old value. */ +int asn1_set_choice_selector(ASN1_VALUE **pval, int value, + const ASN1_ITEM *it) { + int *sel, ret; + sel = offset2ptr(*pval, it->utype); + ret = *sel; + *sel = value; + return ret; +} + +static CRYPTO_refcount_t *asn1_get_references(ASN1_VALUE **pval, + const ASN1_ITEM *it) { + if (it->itype != ASN1_ITYPE_SEQUENCE && + it->itype != ASN1_ITYPE_NDEF_SEQUENCE) { + return NULL; + } + const ASN1_AUX *aux = it->funcs; + if (!aux || !(aux->flags & ASN1_AFLG_REFCOUNT)) { + return NULL; + } + return offset2ptr(*pval, aux->ref_offset); +} + +void asn1_refcount_set_one(ASN1_VALUE **pval, const ASN1_ITEM *it) { + CRYPTO_refcount_t *references = asn1_get_references(pval, it); + if (references != NULL) { + *references = 1; + } +} + +int asn1_refcount_dec_and_test_zero(ASN1_VALUE **pval, const ASN1_ITEM *it) { + CRYPTO_refcount_t *references = asn1_get_references(pval, it); + if (references != NULL) { + return CRYPTO_refcount_dec_and_test_zero(references); + } + return 1; +} + +static ASN1_ENCODING *asn1_get_enc_ptr(ASN1_VALUE **pval, const ASN1_ITEM *it) { + const ASN1_AUX *aux; + if (!pval || !*pval) { + return NULL; + } + aux = it->funcs; + if (!aux || !(aux->flags & ASN1_AFLG_ENCODING)) { + return NULL; + } + return offset2ptr(*pval, aux->enc_offset); +} + +void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it) { + ASN1_ENCODING *enc; + enc = asn1_get_enc_ptr(pval, it); + if (enc) { + enc->enc = NULL; + enc->len = 0; + enc->modified = 1; + } +} + +void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it) { + ASN1_ENCODING *enc; + enc = asn1_get_enc_ptr(pval, it); + if (enc) { + if (enc->enc) { + OPENSSL_free(enc->enc); + } + enc->enc = NULL; + enc->len = 0; + enc->modified = 1; + } +} + +int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen, + const ASN1_ITEM *it) { + ASN1_ENCODING *enc; + enc = asn1_get_enc_ptr(pval, it); + if (!enc) { + return 1; + } + + if (enc->enc) { + OPENSSL_free(enc->enc); + } + enc->enc = OPENSSL_malloc(inlen); + if (!enc->enc) { + return 0; + } + memcpy(enc->enc, in, inlen); + enc->len = inlen; + enc->modified = 0; + + return 1; +} + +int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval, + const ASN1_ITEM *it) { + ASN1_ENCODING *enc; + enc = asn1_get_enc_ptr(pval, it); + if (!enc || enc->modified) { + return 0; + } + if (out) { + memcpy(*out, enc->enc, enc->len); + *out += enc->len; + } + if (len) { + *len = enc->len; + } + return 1; +} + +/* Given an ASN1_TEMPLATE get a pointer to a field */ +ASN1_VALUE **asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) { + ASN1_VALUE **pvaltmp; + if (tt->flags & ASN1_TFLG_COMBINE) { + return pval; + } + pvaltmp = offset2ptr(*pval, tt->offset); + /* NOTE for BOOLEAN types the field is just a plain int so we can't return + * int **, so settle for (int *). */ + return pvaltmp; +} + +/* Handle ANY DEFINED BY template, find the selector, look up the relevant + * ASN1_TEMPLATE in the table and return it. */ +const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt, + int nullerr) { + const ASN1_ADB *adb; + const ASN1_ADB_TABLE *atbl; + long selector; + ASN1_VALUE **sfld; + int i; + if (!(tt->flags & ASN1_TFLG_ADB_MASK)) { + return tt; + } + + /* Else ANY DEFINED BY ... get the table */ + adb = ASN1_ADB_ptr(tt->item); + + /* Get the selector field */ + sfld = offset2ptr(*pval, adb->offset); + + /* Check if NULL */ + if (!sfld) { + if (!adb->null_tt) { + goto err; + } + return adb->null_tt; + } + + /* Convert type to a long: + * NB: don't check for NID_undef here because it + * might be a legitimate value in the table */ + if (tt->flags & ASN1_TFLG_ADB_OID) { + selector = OBJ_obj2nid((ASN1_OBJECT *)*sfld); + } else { + selector = ASN1_INTEGER_get((ASN1_INTEGER *)*sfld); + } + + /* Try to find matching entry in table Maybe should check application types + * first to allow application override? Might also be useful to have a flag + * which indicates table is sorted and we can do a binary search. For now + * stick to a linear search. */ + + for (atbl = adb->tbl, i = 0; i < adb->tblcount; i++, atbl++) { + if (atbl->value == selector) { + return &atbl->tt; + } + } + + /* FIXME: need to search application table too */ + + /* No match, return default type */ + if (!adb->default_tt) { + goto err; + } + return adb->default_tt; + +err: + /* FIXME: should log the value or OID of unsupported type */ + if (nullerr) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE); + } + return NULL; +} diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/x_bignum.c b/TMessagesProj/jni/boringssl/crypto/asn1/x_bignum.c new file mode 100644 index 00000000..f8c62fd8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/x_bignum.c @@ -0,0 +1,142 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +/* Custom primitive type for BIGNUM handling. This reads in an ASN1_INTEGER as a + * BIGNUM directly. Currently it ignores the sign which isn't a problem since all + * BIGNUMs used are non negative and anything that looks negative is normally due + * to an encoding error. + */ + +#define BN_SENSITIVE 1 + +static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it); +static void bn_free(ASN1_VALUE **pval, const ASN1_ITEM *it); + +static int bn_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it); +static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it); + +static const ASN1_PRIMITIVE_FUNCS bignum_pf = { + NULL, 0, + bn_new, + bn_free, + 0, + bn_c2i, + bn_i2c +}; + +ASN1_ITEM_start(BIGNUM) + ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &bignum_pf, 0, "BIGNUM" +ASN1_ITEM_end(BIGNUM) + +ASN1_ITEM_start(CBIGNUM) + ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &bignum_pf, BN_SENSITIVE, "BIGNUM" +ASN1_ITEM_end(CBIGNUM) + +static int bn_new(ASN1_VALUE **pval, const ASN1_ITEM *it) +{ + *pval = (ASN1_VALUE *)BN_new(); + if(*pval) return 1; + else return 0; +} + +static void bn_free(ASN1_VALUE **pval, const ASN1_ITEM *it) +{ + if(!*pval) return; + if(it->size & BN_SENSITIVE) BN_clear_free((BIGNUM *)*pval); + else BN_free((BIGNUM *)*pval); + *pval = NULL; +} + +static int bn_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it) +{ + BIGNUM *bn; + int pad; + if(!*pval) return -1; + bn = (BIGNUM *)*pval; + /* If MSB set in an octet we need a padding byte */ + if(BN_num_bits(bn) & 0x7) pad = 0; + else pad = 1; + if(cont) { + if(pad) *cont++ = 0; + BN_bn2bin(bn, cont); + } + return pad + BN_num_bytes(bn); +} + +static int bn_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, + int utype, char *free_cont, const ASN1_ITEM *it) +{ + BIGNUM *bn; + if(!*pval) + { + if (!bn_new(pval, it)) + { + return 0; + } + } + bn = (BIGNUM *)*pval; + if(!BN_bin2bn(cont, len, bn)) { + bn_free(pval, it); + return 0; + } + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/asn1/x_long.c b/TMessagesProj/jni/boringssl/crypto/asn1/x_long.c new file mode 100644 index 00000000..7b1a6fe8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/asn1/x_long.c @@ -0,0 +1,182 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + + +/* Custom primitive type for long handling. This converts between an ASN1_INTEGER + * and a long directly. + */ + + +static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it); +static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it); + +static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it); +static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it); +static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it, int indent, const ASN1_PCTX *pctx); + +static const ASN1_PRIMITIVE_FUNCS long_pf = { + NULL, 0, + long_new, + long_free, + long_free, /* Clear should set to initial value */ + long_c2i, + long_i2c, + long_print +}; + +ASN1_ITEM_start(LONG) + ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, ASN1_LONG_UNDEF, "LONG" +ASN1_ITEM_end(LONG) + +ASN1_ITEM_start(ZLONG) + ASN1_ITYPE_PRIMITIVE, V_ASN1_INTEGER, NULL, 0, &long_pf, 0, "ZLONG" +ASN1_ITEM_end(ZLONG) + +static int long_new(ASN1_VALUE **pval, const ASN1_ITEM *it) +{ + *(long *)pval = it->size; + return 1; +} + +static void long_free(ASN1_VALUE **pval, const ASN1_ITEM *it) +{ + *(long *)pval = it->size; +} + +static int long_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it) +{ + long ltmp; + unsigned long utmp; + int clen, pad, i; + /* this exists to bypass broken gcc optimization */ + char *cp = (char *)pval; + + /* use memcpy, because we may not be long aligned */ + memcpy(<mp, cp, sizeof(long)); + + if(ltmp == it->size) return -1; + /* Convert the long to positive: we subtract one if negative so + * we can cleanly handle the padding if only the MSB of the leading + * octet is set. + */ + if(ltmp < 0) utmp = -ltmp - 1; + else utmp = ltmp; + clen = BN_num_bits_word(utmp); + /* If MSB of leading octet set we need to pad */ + if(!(clen & 0x7)) pad = 1; + else pad = 0; + + /* Convert number of bits to number of octets */ + clen = (clen + 7) >> 3; + + if(cont) { + if(pad) *cont++ = (ltmp < 0) ? 0xff : 0; + for(i = clen - 1; i >= 0; i--) { + cont[i] = (unsigned char)(utmp & 0xff); + if(ltmp < 0) cont[i] ^= 0xff; + utmp >>= 8; + } + } + return clen + pad; +} + +static int long_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, + int utype, char *free_cont, const ASN1_ITEM *it) +{ + int neg, i; + long ltmp; + unsigned long utmp = 0; + char *cp = (char *)pval; + if(len > (int)sizeof(long)) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG); + return 0; + } + /* Is it negative? */ + if(len && (cont[0] & 0x80)) neg = 1; + else neg = 0; + utmp = 0; + for(i = 0; i < len; i++) { + utmp <<= 8; + if(neg) utmp |= cont[i] ^ 0xff; + else utmp |= cont[i]; + } + ltmp = (long)utmp; + if(neg) { + ltmp++; + ltmp = -ltmp; + } + if(ltmp == it->size) { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_TOO_LARGE_FOR_LONG); + return 0; + } + memcpy(cp, <mp, sizeof(long)); + return 1; +} + +static int long_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it, + int indent, const ASN1_PCTX *pctx) + { + return BIO_printf(out, "%ld\n", *(long *)pval); + } diff --git a/TMessagesProj/jni/boringssl/crypto/base64/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/base64/CMakeLists.txt new file mode 100644 index 00000000..9c38cc55 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/base64/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + base64 + + OBJECT + + base64.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/base64/base64.c b/TMessagesProj/jni/boringssl/crypto/base64/base64.c new file mode 100644 index 00000000..4822fb89 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/base64/base64.c @@ -0,0 +1,478 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + + +static const unsigned char data_bin2ascii[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +#define conv_bin2ascii(a) (data_bin2ascii[(a) & 0x3f]) + +/* 64 char lines + * pad input with 0 + * left over chars are set to = + * 1 byte => xx== + * 2 bytes => xxx= + * 3 bytes => xxxx + */ +#define BIN_PER_LINE (64/4*3) +#define CHUNKS_PER_LINE (64/4) +#define CHAR_PER_LINE (64+1) + +/* 0xF0 is a EOLN + * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing). + * 0xF2 is EOF + * 0xE0 is ignore at start of line. + * 0xFF is error */ + +#define B64_EOLN 0xF0 +#define B64_CR 0xF1 +#define B64_EOF 0xF2 +#define B64_WS 0xE0 +#define B64_ERROR 0xFF +#define B64_NOT_BASE64(a) (((a) | 0x13) == 0xF3) + +static const uint8_t data_ascii2bin[128] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xF0, 0xFF, + 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, + 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, + 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static uint8_t conv_ascii2bin(uint8_t a) { + if (a >= 128) { + return 0xFF; + } + return data_ascii2bin[a]; +} + +void EVP_EncodeInit(EVP_ENCODE_CTX *ctx) { + ctx->length = 48; + ctx->num = 0; + ctx->line_num = 0; +} + +void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len, + const uint8_t *in, size_t in_len) { + unsigned i, j; + unsigned total = 0; + + *out_len = 0; + if (in_len == 0) { + return; + } + + assert(ctx->length <= sizeof(ctx->enc_data)); + + if (ctx->num + in_len < ctx->length) { + memcpy(&ctx->enc_data[ctx->num], in, in_len); + ctx->num += in_len; + return; + } + if (ctx->num != 0) { + i = ctx->length - ctx->num; + memcpy(&ctx->enc_data[ctx->num], in, i); + in += i; + in_len -= i; + j = EVP_EncodeBlock(out, ctx->enc_data, ctx->length); + ctx->num = 0; + out += j; + *(out++) = '\n'; + *out = '\0'; + total = j + 1; + } + while (in_len >= ctx->length) { + j = EVP_EncodeBlock(out, in, ctx->length); + in += ctx->length; + in_len -= ctx->length; + out += j; + *(out++) = '\n'; + *out = '\0'; + total += j + 1; + } + if (in_len != 0) { + memcpy(&ctx->enc_data[0], in, in_len); + } + ctx->num = in_len; + *out_len = total; +} + +void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len) { + unsigned ret = 0; + + if (ctx->num != 0) { + ret = EVP_EncodeBlock(out, ctx->enc_data, ctx->num); + out[ret++] = '\n'; + out[ret] = '\0'; + ctx->num = 0; + } + *out_len = ret; +} + +size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) { + uint32_t l; + size_t remaining = src_len, ret = 0; + + while (remaining) { + if (remaining >= 3) { + l = (((uint32_t)src[0]) << 16L) | (((uint32_t)src[1]) << 8L) | src[2]; + *(dst++) = conv_bin2ascii(l >> 18L); + *(dst++) = conv_bin2ascii(l >> 12L); + *(dst++) = conv_bin2ascii(l >> 6L); + *(dst++) = conv_bin2ascii(l); + remaining -= 3; + } else { + l = ((uint32_t)src[0]) << 16L; + if (remaining == 2) { + l |= ((uint32_t)src[1] << 8L); + } + + *(dst++) = conv_bin2ascii(l >> 18L); + *(dst++) = conv_bin2ascii(l >> 12L); + *(dst++) = (remaining == 1) ? '=' : conv_bin2ascii(l >> 6L); + *(dst++) = '='; + remaining = 0; + } + ret += 4; + src += 3; + } + + *dst = '\0'; + return ret; +} + +int EVP_DecodedLength(size_t *out_len, size_t len) { + if (len % 4 != 0) { + return 0; + } + *out_len = (len / 4) * 3; + return 1; +} + +int EVP_DecodeBase64(uint8_t *out, size_t *out_len, size_t max_out, + const uint8_t *in, size_t in_len) { + uint8_t a, b, c, d; + size_t pad_len = 0, len = 0, max_len, i; + uint32_t l; + + if (!EVP_DecodedLength(&max_len, in_len) || max_out < max_len) { + return 0; + } + + for (i = 0; i < in_len; i += 4) { + a = conv_ascii2bin(*(in++)); + b = conv_ascii2bin(*(in++)); + if (i + 4 == in_len && in[1] == '=') { + if (in[0] == '=') { + pad_len = 2; + } else { + pad_len = 1; + } + } + if (pad_len < 2) { + c = conv_ascii2bin(*(in++)); + } else { + c = 0; + } + if (pad_len < 1) { + d = conv_ascii2bin(*(in++)); + } else { + d = 0; + } + if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80)) { + return 0; + } + l = ((((uint32_t)a) << 18L) | (((uint32_t)b) << 12L) | + (((uint32_t)c) << 6L) | (((uint32_t)d))); + *(out++) = (uint8_t)(l >> 16L) & 0xff; + if (pad_len < 2) { + *(out++) = (uint8_t)(l >> 8L) & 0xff; + } + if (pad_len < 1) { + *(out++) = (uint8_t)(l) & 0xff; + } + len += 3 - pad_len; + } + *out_len = len; + return 1; +} + +void EVP_DecodeInit(EVP_ENCODE_CTX *ctx) { + ctx->length = 30; + ctx->num = 0; + ctx->line_num = 0; + ctx->expect_nl = 0; +} + +int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, int *out_len, + const uint8_t *in, size_t in_len) { + int seof = -1, eof = 0, rv = -1, v, tmp, exp_nl; + uint8_t *d; + unsigned i, n, ln, ret = 0; + + n = ctx->num; + d = ctx->enc_data; + ln = ctx->line_num; + exp_nl = ctx->expect_nl; + + /* last line of input. */ + if (in_len == 0 || (n == 0 && conv_ascii2bin(in[0]) == B64_EOF)) { + rv = 0; + goto end; + } + + /* We parse the input data */ + for (i = 0; i < in_len; i++) { + /* If the current line is > 80 characters, scream alot */ + if (ln >= 80) { + rv = -1; + goto end; + } + + /* Get char and put it into the buffer */ + tmp = *(in++); + v = conv_ascii2bin(tmp); + /* only save the good data :-) */ + if (!B64_NOT_BASE64(v)) { + assert(n < sizeof(ctx->enc_data)); + d[n++] = tmp; + ln++; + } else if (v == B64_ERROR) { + rv = -1; + goto end; + } + + /* have we seen a '=' which is 'definitly' the last + * input line. seof will point to the character that + * holds it. and eof will hold how many characters to + * chop off. */ + if (tmp == '=') { + if (seof == -1) { + seof = n; + } + eof++; + if (eof > 2) { + /* There are, at most, two equals signs at the end of base64 data. */ + rv = -1; + goto end; + } + } + + if (v == B64_CR) { + ln = 0; + if (exp_nl) { + continue; + } + } + + /* eoln */ + if (v == B64_EOLN) { + ln = 0; + if (exp_nl) { + exp_nl = 0; + continue; + } + } + exp_nl = 0; + + /* If we are at the end of input and it looks like a + * line, process it. */ + if ((i + 1) == in_len && (((n & 3) == 0) || eof)) { + v = B64_EOF; + /* In case things were given us in really small + records (so two '=' were given in separate + updates), eof may contain the incorrect number + of ending bytes to skip, so let's redo the count */ + eof = 0; + if (d[n - 1] == '=') { + eof++; + } + if (d[n - 2] == '=') { + eof++; + } + /* There will never be more than two '=' */ + } + + if ((v == B64_EOF && (n & 3) == 0) || n >= 64) { + /* This is needed to work correctly on 64 byte input + * lines. We process the line and then need to + * accept the '\n' */ + if (v != B64_EOF && n >= 64) { + exp_nl = 1; + } + if (n > 0) { + /* TODO(davidben): Switch this to EVP_DecodeBase64. */ + v = EVP_DecodeBlock(out, d, n); + n = 0; + if (v < 0) { + rv = 0; + goto end; + } + if (eof > v) { + rv = -1; + goto end; + } + ret += (v - eof); + } else { + eof = 1; + v = 0; + } + + /* This is the case where we have had a short + * but valid input line */ + if (v < (int)ctx->length && eof) { + rv = 0; + goto end; + } else { + ctx->length = v; + } + + if (seof >= 0) { + rv = 0; + goto end; + } + out += v; + } + } + rv = 1; + +end: + *out_len = ret; + ctx->num = n; + ctx->line_num = ln; + ctx->expect_nl = exp_nl; + return rv; +} + +int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, int *outl) { + int i; + + *outl = 0; + if (ctx->num != 0) { + /* TODO(davidben): Switch this to EVP_DecodeBase64. */ + i = EVP_DecodeBlock(out, ctx->enc_data, ctx->num); + if (i < 0) { + return -1; + } + ctx->num = 0; + *outl = i; + return 1; + } else { + return 1; + } +} + +int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, size_t src_len) { + size_t dst_len; + + /* trim white space from the start of the line. */ + while (conv_ascii2bin(*src) == B64_WS && src_len > 0) { + src++; + src_len--; + } + + /* strip off stuff at the end of the line + * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF */ + while (src_len > 3 && B64_NOT_BASE64(conv_ascii2bin(src[src_len - 1]))) { + src_len--; + } + + if (!EVP_DecodedLength(&dst_len, src_len) || dst_len > INT_MAX) { + return -1; + } + if (!EVP_DecodeBase64(dst, &dst_len, dst_len, src, src_len)) { + return -1; + } + + /* EVP_DecodeBlock does not take padding into account, so put the + * NULs back in... so the caller can strip them back out. */ + while (dst_len % 3 != 0) { + dst[dst_len++] = '\0'; + } + assert(dst_len <= INT_MAX); + + return dst_len; +} + +int EVP_EncodedLength(size_t *out_len, size_t len) { + if (len + 2 < len) { + return 0; + } + len += 2; + len /= 3; + if (((len << 2) >> 2) != len) { + return 0; + } + len <<= 2; + if (len + 1 < len) { + return 0; + } + len++; + *out_len = len; + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/bio/CMakeLists.txt new file mode 100644 index 00000000..dbf8fe5b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/CMakeLists.txt @@ -0,0 +1,19 @@ +include_directories(. .. ../../include) + +add_library( + bio + + OBJECT + + bio.c + bio_mem.c + buffer.c + connect.c + fd.c + file.c + hexdump.c + pair.c + printf.c + socket.c + socket_helper.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/bio/bio.c b/TMessagesProj/jni/boringssl/crypto/bio/bio.c new file mode 100644 index 00000000..4bc98ba3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/bio.c @@ -0,0 +1,606 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "../internal.h" + + +/* BIO_set initialises a BIO structure to have the given type and sets the + * reference count to one. It returns one on success or zero on error. */ +static int bio_set(BIO *bio, const BIO_METHOD *method) { + /* This function can be called with a stack allocated |BIO| so we have to + * assume that the contents of |BIO| are arbitary. This also means that it'll + * leak memory if you call |BIO_set| twice on the same BIO. */ + memset(bio, 0, sizeof(BIO)); + + bio->method = method; + bio->shutdown = 1; + bio->references = 1; + + if (method->create != NULL && !method->create(bio)) { + return 0; + } + + return 1; +} + +BIO *BIO_new(const BIO_METHOD *method) { + BIO *ret = OPENSSL_malloc(sizeof(BIO)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if (!bio_set(ret, method)) { + OPENSSL_free(ret); + ret = NULL; + } + + return ret; +} + +int BIO_free(BIO *bio) { + BIO *next_bio; + + for (; bio != NULL; bio = next_bio) { + if (!CRYPTO_refcount_dec_and_test_zero(&bio->references)) { + return 0; + } + + if (bio->callback != NULL) { + int i = (int)bio->callback(bio, BIO_CB_FREE, NULL, 0, 0, 1); + if (i <= 0) { + return i; + } + } + + next_bio = BIO_pop(bio); + + if (bio->method != NULL && bio->method->destroy != NULL) { + bio->method->destroy(bio); + } + + OPENSSL_free(bio); + } + return 1; +} + +BIO *BIO_up_ref(BIO *bio) { + CRYPTO_refcount_inc(&bio->references); + return bio; +} + +void BIO_vfree(BIO *bio) { + BIO_free(bio); +} + +void BIO_free_all(BIO *bio) { + BIO_free(bio); +} + +static int bio_io(BIO *bio, void *buf, int len, size_t method_offset, + int callback_flags, size_t *num) { + int i; + typedef int (*io_func_t)(BIO *, char *, int); + io_func_t io_func = NULL; + + if (bio != NULL && bio->method != NULL) { + io_func = + *((const io_func_t *)(((const uint8_t *)bio->method) + method_offset)); + } + + if (io_func == NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if (bio->callback != NULL) { + i = (int) bio->callback(bio, callback_flags, buf, len, 0L, 1L); + if (i <= 0) { + return i; + } + } + + if (!bio->init) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); + return -2; + } + + i = 0; + if (buf != NULL && len > 0) { + i = io_func(bio, buf, len); + } + + if (i > 0) { + *num += i; + } + + if (bio->callback != NULL) { + i = (int)(bio->callback(bio, callback_flags | BIO_CB_RETURN, buf, len, 0L, + (long)i)); + } + + return i; +} + +int BIO_read(BIO *bio, void *buf, int len) { + return bio_io(bio, buf, len, offsetof(BIO_METHOD, bread), BIO_CB_READ, + &bio->num_read); +} + +int BIO_gets(BIO *bio, char *buf, int len) { + return bio_io(bio, buf, len, offsetof(BIO_METHOD, bgets), BIO_CB_GETS, + &bio->num_read); +} + +int BIO_write(BIO *bio, const void *in, int inl) { + return bio_io(bio, (char *)in, inl, offsetof(BIO_METHOD, bwrite), + BIO_CB_WRITE, &bio->num_write); +} + +int BIO_puts(BIO *bio, const char *in) { + return BIO_write(bio, in, strlen(in)); +} + +int BIO_flush(BIO *bio) { + return BIO_ctrl(bio, BIO_CTRL_FLUSH, 0, NULL); +} + +long BIO_ctrl(BIO *bio, int cmd, long larg, void *parg) { + long ret; + + if (bio == NULL) { + return 0; + } + + if (bio->method == NULL || bio->method->ctrl == NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if (bio->callback != NULL) { + ret = bio->callback(bio, BIO_CB_CTRL, parg, cmd, larg, 1); + if (ret <= 0) { + return ret; + } + } + + ret = bio->method->ctrl(bio, cmd, larg, parg); + + if (bio->callback != NULL) { + ret = bio->callback(bio, BIO_CB_CTRL | BIO_CB_RETURN, parg, cmd, larg, ret); + } + + return ret; +} + +char *BIO_ptr_ctrl(BIO *b, int cmd, long larg) { + char *p = NULL; + + if (BIO_ctrl(b, cmd, larg, (void *)&p) <= 0) { + return NULL; + } + + return p; +} + +long BIO_int_ctrl(BIO *b, int cmd, long larg, int iarg) { + int i = iarg; + + return BIO_ctrl(b, cmd, larg, (void *)&i); +} + +int BIO_reset(BIO *bio) { + return BIO_ctrl(bio, BIO_CTRL_RESET, 0, NULL); +} + +void BIO_set_flags(BIO *bio, int flags) { + bio->flags |= flags; +} + +int BIO_test_flags(const BIO *bio, int flags) { + return bio->flags & flags; +} + +int BIO_should_read(const BIO *bio) { + return BIO_test_flags(bio, BIO_FLAGS_READ); +} + +int BIO_should_write(const BIO *bio) { + return BIO_test_flags(bio, BIO_FLAGS_WRITE); +} + +int BIO_should_retry(const BIO *bio) { + return BIO_test_flags(bio, BIO_FLAGS_SHOULD_RETRY); +} + +int BIO_should_io_special(const BIO *bio) { + return BIO_test_flags(bio, BIO_FLAGS_IO_SPECIAL); +} + +int BIO_get_retry_reason(const BIO *bio) { return bio->retry_reason; } + +void BIO_clear_flags(BIO *bio, int flags) { + bio->flags &= ~flags; +} + +void BIO_set_retry_read(BIO *bio) { + bio->flags |= BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY; +} + +void BIO_set_retry_write(BIO *bio) { + bio->flags |= BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY; +} + +static const int kRetryFlags = BIO_FLAGS_RWS | BIO_FLAGS_SHOULD_RETRY; + +int BIO_get_retry_flags(BIO *bio) { + return bio->flags & kRetryFlags; +} + +void BIO_clear_retry_flags(BIO *bio) { + bio->flags &= ~kRetryFlags; + bio->retry_reason = 0; +} + +int BIO_method_type(const BIO *bio) { return bio->method->type; } + +void BIO_copy_next_retry(BIO *bio) { + BIO_clear_retry_flags(bio); + BIO_set_flags(bio, BIO_get_retry_flags(bio->next_bio)); + bio->retry_reason = bio->next_bio->retry_reason; +} + +long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { + long ret; + bio_info_cb cb; + + if (bio == NULL) { + return 0; + } + + if (bio->method == NULL || bio->method->callback_ctrl == NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + cb = bio->callback; + + if (cb != NULL) { + ret = cb(bio, BIO_CB_CTRL, (void *)&fp, cmd, 0, 1L); + if (ret <= 0) { + return ret; + } + } + + ret = bio->method->callback_ctrl(bio, cmd, fp); + + if (cb != NULL) { + ret = cb(bio, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, cmd, 0, ret); + } + + return ret; +} + +size_t BIO_pending(const BIO *bio) { + return BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL); +} + +size_t BIO_ctrl_pending(const BIO *bio) { + return BIO_pending(bio); +} + +size_t BIO_wpending(const BIO *bio) { + return BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL); +} + +int BIO_set_close(BIO *bio, int close_flag) { + return BIO_ctrl(bio, BIO_CTRL_SET_CLOSE, close_flag, NULL); +} + +void BIO_set_callback(BIO *bio, bio_info_cb callback_func) { + bio->callback = callback_func; +} + +void BIO_set_callback_arg(BIO *bio, char *arg) { + bio->cb_arg = arg; +} + +char *BIO_get_callback_arg(const BIO *bio) { + return bio->cb_arg; +} + +OPENSSL_EXPORT size_t BIO_number_read(const BIO *bio) { + return bio->num_read; +} + +OPENSSL_EXPORT size_t BIO_number_written(const BIO *bio) { + return bio->num_write; +} + +BIO *BIO_push(BIO *bio, BIO *appended_bio) { + BIO *last_bio; + + if (bio == NULL) { + return bio; + } + + last_bio = bio; + while (last_bio->next_bio != NULL) { + last_bio = last_bio->next_bio; + } + + last_bio->next_bio = appended_bio; + return bio; +} + +BIO *BIO_pop(BIO *bio) { + BIO *ret; + + if (bio == NULL) { + return NULL; + } + ret = bio->next_bio; + bio->next_bio = NULL; + return ret; +} + +BIO *BIO_next(BIO *bio) { + if (!bio) { + return NULL; + } + return bio->next_bio; +} + +BIO *BIO_find_type(BIO *bio, int type) { + int method_type, mask; + + if (!bio) { + return NULL; + } + mask = type & 0xff; + + do { + if (bio->method != NULL) { + method_type = bio->method->type; + + if (!mask) { + if (method_type & type) { + return bio; + } + } else if (method_type == type) { + return bio; + } + } + bio = bio->next_bio; + } while (bio != NULL); + + return NULL; +} + +int BIO_indent(BIO *bio, unsigned indent, unsigned max_indent) { + if (indent > max_indent) { + indent = max_indent; + } + + while (indent--) { + if (BIO_puts(bio, " ") != 1) { + return 0; + } + } + return 1; +} + +static int print_bio(const char *str, size_t len, void *bio) { + return BIO_write((BIO *)bio, str, len); +} + +void BIO_print_errors(BIO *bio) { + ERR_print_errors_cb(print_bio, bio); +} + +void ERR_print_errors(BIO *bio) { + BIO_print_errors(bio); +} + +/* bio_read_all reads everything from |bio| and prepends |prefix| to it. On + * success, |*out| is set to an allocated buffer (which should be freed with + * |OPENSSL_free|), |*out_len| is set to its length and one is returned. The + * buffer will contain |prefix| followed by the contents of |bio|. On failure, + * zero is returned. + * + * The function will fail if the size of the output would equal or exceed + * |max_len|. */ +static int bio_read_all(BIO *bio, uint8_t **out, size_t *out_len, + const uint8_t *prefix, size_t prefix_len, + size_t max_len) { + static const size_t kChunkSize = 4096; + + size_t len = prefix_len + kChunkSize; + if (len > max_len) { + len = max_len; + } + if (len < prefix_len) { + return 0; + } + *out = OPENSSL_malloc(len); + if (*out == NULL) { + return 0; + } + memcpy(*out, prefix, prefix_len); + size_t done = prefix_len; + + for (;;) { + if (done == len) { + OPENSSL_free(*out); + return 0; + } + const size_t todo = len - done; + assert(todo < INT_MAX); + const int n = BIO_read(bio, *out + done, todo); + if (n == 0) { + *out_len = done; + return 1; + } else if (n == -1) { + OPENSSL_free(*out); + return 0; + } + + done += n; + if (len < max_len && len - done < kChunkSize / 2) { + len += kChunkSize; + if (len < kChunkSize || len > max_len) { + len = max_len; + } + uint8_t *new_buf = OPENSSL_realloc(*out, len); + if (new_buf == NULL) { + OPENSSL_free(*out); + return 0; + } + *out = new_buf; + } + } +} + +int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, size_t max_len) { + uint8_t header[6]; + + static const size_t kInitialHeaderLen = 2; + if (BIO_read(bio, header, kInitialHeaderLen) != kInitialHeaderLen) { + return 0; + } + + const uint8_t tag = header[0]; + const uint8_t length_byte = header[1]; + + if ((tag & 0x1f) == 0x1f) { + /* Long form tags are not supported. */ + return 0; + } + + size_t len, header_len; + if ((length_byte & 0x80) == 0) { + /* Short form length. */ + len = length_byte; + header_len = kInitialHeaderLen; + } else { + const size_t num_bytes = length_byte & 0x7f; + + if ((tag & 0x20 /* constructed */) != 0 && num_bytes == 0) { + /* indefinite length. */ + return bio_read_all(bio, out, out_len, header, kInitialHeaderLen, + max_len); + } + + if (num_bytes == 0 || num_bytes > 4) { + return 0; + } + + if (BIO_read(bio, header + kInitialHeaderLen, num_bytes) != num_bytes) { + return 0; + } + header_len = kInitialHeaderLen + num_bytes; + + uint32_t len32 = 0; + unsigned i; + for (i = 0; i < num_bytes; i++) { + len32 <<= 8; + len32 |= header[kInitialHeaderLen + i]; + } + + if (len32 < 128) { + /* Length should have used short-form encoding. */ + return 0; + } + + if ((len32 >> ((num_bytes-1)*8)) == 0) { + /* Length should have been at least one byte shorter. */ + return 0; + } + + len = len32; + } + + if (len + header_len < len || + len + header_len > max_len) { + return 0; + } + len += header_len; + *out_len = len; + + *out = OPENSSL_malloc(len); + if (*out == NULL) { + return 0; + } + memcpy(*out, header, header_len); + if (BIO_read(bio, (*out) + header_len, len - header_len) != + len - header_len) { + OPENSSL_free(*out); + return 0; + } + + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/bio_mem.c b/TMessagesProj/jni/boringssl/crypto/bio/bio_mem.c new file mode 100644 index 00000000..ef56111b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/bio_mem.c @@ -0,0 +1,327 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + + +BIO *BIO_new_mem_buf(void *buf, int len) { + BIO *ret; + BUF_MEM *b; + const size_t size = len < 0 ? strlen((char *)buf) : (size_t)len; + + if (!buf && len != 0) { + OPENSSL_PUT_ERROR(BIO, BIO_R_NULL_PARAMETER); + return NULL; + } + + ret = BIO_new(BIO_s_mem()); + if (ret == NULL) { + return NULL; + } + + b = (BUF_MEM *)ret->ptr; + b->data = buf; + b->length = size; + b->max = size; + + ret->flags |= BIO_FLAGS_MEM_RDONLY; + + /* |num| is used to store the value that this BIO will return when it runs + * out of data. If it's negative then the retry flags will also be set. Since + * this is static data, retrying wont help */ + ret->num = 0; + + return ret; +} + +static int mem_new(BIO *bio) { + BUF_MEM *b; + + b = BUF_MEM_new(); + if (b == NULL) { + return 0; + } + + /* |shutdown| is used to store the close flag: whether the BIO has ownership + * of the BUF_MEM. */ + bio->shutdown = 1; + bio->init = 1; + bio->num = -1; + bio->ptr = (char *)b; + + return 1; +} + +static int mem_free(BIO *bio) { + BUF_MEM *b; + + if (bio == NULL) { + return 0; + } + + if (!bio->shutdown || !bio->init || bio->ptr == NULL) { + return 1; + } + + b = (BUF_MEM *)bio->ptr; + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + b->data = NULL; + } + BUF_MEM_free(b); + bio->ptr = NULL; + return 1; +} + +static int mem_read(BIO *bio, char *out, int outl) { + int ret; + BUF_MEM *b = (BUF_MEM*) bio->ptr; + + BIO_clear_retry_flags(bio); + ret = outl; + if (b->length < INT_MAX && ret > (int)b->length) { + ret = b->length; + } + + if (ret > 0) { + memcpy(out, b->data, ret); + b->length -= ret; + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + b->data += ret; + } else { + memmove(b->data, &b->data[ret], b->length); + } + } else if (b->length == 0) { + ret = bio->num; + if (ret != 0) { + BIO_set_retry_read(bio); + } + } + return ret; +} + +static int mem_write(BIO *bio, const char *in, int inl) { + int ret = -1; + int blen; + BUF_MEM *b; + + b = (BUF_MEM *)bio->ptr; + + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + OPENSSL_PUT_ERROR(BIO, BIO_R_WRITE_TO_READ_ONLY_BIO); + goto err; + } + + BIO_clear_retry_flags(bio); + blen = b->length; + if (INT_MAX - blen < inl) { + goto err; + } + if (BUF_MEM_grow_clean(b, blen + inl) != (blen + inl)) { + goto err; + } + memcpy(&b->data[blen], in, inl); + ret = inl; + +err: + return ret; +} + +static int mem_puts(BIO *bp, const char *str) { + return mem_write(bp, str, strlen(str)); +} + +static int mem_gets(BIO *bio, char *buf, int size) { + int i, j; + char *p; + BUF_MEM *b = (BUF_MEM *)bio->ptr; + + BIO_clear_retry_flags(bio); + j = b->length; + if (size - 1 < j) { + j = size - 1; + } + if (j <= 0) { + if (size > 0) { + *buf = 0; + } + return 0; + } + + p = b->data; + for (i = 0; i < j; i++) { + if (p[i] == '\n') { + i++; + break; + } + } + + /* i is now the max num of bytes to copy, either j or up to and including the + * first newline */ + + i = mem_read(bio, buf, i); + if (i > 0) { + buf[i] = '\0'; + } + return i; +} + +static long mem_ctrl(BIO *bio, int cmd, long num, void *ptr) { + long ret = 1; + char **pptr; + + BUF_MEM *b = (BUF_MEM *)bio->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + if (b->data != NULL) { + /* For read only case reset to the start again */ + if (bio->flags & BIO_FLAGS_MEM_RDONLY) { + b->data -= b->max - b->length; + b->length = b->max; + } else { + memset(b->data, 0, b->max); + b->length = 0; + } + } + break; + case BIO_CTRL_EOF: + ret = (long)(b->length == 0); + break; + case BIO_C_SET_BUF_MEM_EOF_RETURN: + bio->num = (int)num; + break; + case BIO_CTRL_INFO: + ret = (long)b->length; + if (ptr != NULL) { + pptr = (char **)ptr; + *pptr = (char *)&b->data[0]; + } + break; + case BIO_C_SET_BUF_MEM: + mem_free(bio); + bio->shutdown = (int)num; + bio->ptr = ptr; + break; + case BIO_C_GET_BUF_MEM_PTR: + if (ptr != NULL) { + pptr = (char **)ptr; + *pptr = (char *)b; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = (long)bio->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + bio->shutdown = (int)num; + break; + + case BIO_CTRL_WPENDING: + ret = 0L; + break; + case BIO_CTRL_PENDING: + ret = (long)b->length; + break; + case BIO_CTRL_FLUSH: + ret = 1; + break; + default: + ret = 0; + break; + } + return ret; +} + +static const BIO_METHOD mem_method = { + BIO_TYPE_MEM, "memory buffer", mem_write, mem_read, mem_puts, + mem_gets, mem_ctrl, mem_new, mem_free, NULL, }; + +const BIO_METHOD *BIO_s_mem(void) { return &mem_method; } + +int BIO_mem_contents(const BIO *bio, const uint8_t **out_contents, + size_t *out_len) { + const BUF_MEM *b; + if (bio->method != &mem_method) { + return 0; + } + + b = (BUF_MEM *)bio->ptr; + *out_contents = (uint8_t *)b->data; + *out_len = b->length; + return 1; +} + +long BIO_get_mem_data(BIO *bio, char **contents) { + return BIO_ctrl(bio, BIO_CTRL_INFO, 0, (char *) contents); +} + +int BIO_get_mem_ptr(BIO *bio, BUF_MEM **out) { + return BIO_ctrl(bio, BIO_C_GET_BUF_MEM_PTR, 0, (char *) out); +} + +int BIO_set_mem_buf(BIO *bio, BUF_MEM *b, int take_ownership) { + return BIO_ctrl(bio, BIO_C_SET_BUF_MEM, take_ownership, (char *) b); +} + +int BIO_set_mem_eof_return(BIO *bio, int eof_value) { + return BIO_ctrl(bio, BIO_C_SET_BUF_MEM_EOF_RETURN, eof_value, NULL); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/buffer.c b/TMessagesProj/jni/boringssl/crypto/bio/buffer.c new file mode 100644 index 00000000..9d0cb3c0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/buffer.c @@ -0,0 +1,496 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include + + +#define DEFAULT_BUFFER_SIZE 4096 + +typedef struct bio_f_buffer_ctx_struct { + /* Buffers are setup like this: + * + * <---------------------- size -----------------------> + * +---------------------------------------------------+ + * | consumed | remaining | free space | + * +---------------------------------------------------+ + * <-- off --><------- len -------> + */ + + int ibuf_size; /* how big is the input buffer */ + int obuf_size; /* how big is the output buffer */ + + char *ibuf; /* the char array */ + int ibuf_len; /* how many bytes are in it */ + int ibuf_off; /* write/read offset */ + + char *obuf; /* the char array */ + int obuf_len; /* how many bytes are in it */ + int obuf_off; /* write/read offset */ +} BIO_F_BUFFER_CTX; + +static int buffer_new(BIO *bio) { + BIO_F_BUFFER_CTX *ctx; + + ctx = OPENSSL_malloc(sizeof(BIO_F_BUFFER_CTX)); + if (ctx == NULL) { + return 0; + } + memset(ctx, 0, sizeof(BIO_F_BUFFER_CTX)); + + ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); + if (ctx->ibuf == NULL) { + goto err1; + } + ctx->obuf = (char *)OPENSSL_malloc(DEFAULT_BUFFER_SIZE); + if (ctx->obuf == NULL) { + goto err2; + } + ctx->ibuf_size = DEFAULT_BUFFER_SIZE; + ctx->obuf_size = DEFAULT_BUFFER_SIZE; + + bio->init = 1; + bio->ptr = (char *)ctx; + return 1; + +err2: + OPENSSL_free(ctx->ibuf); + +err1: + OPENSSL_free(ctx); + return 0; +} + +static int buffer_free(BIO *bio) { + BIO_F_BUFFER_CTX *ctx; + + if (bio == NULL || bio->ptr == NULL) { + return 0; + } + + ctx = (BIO_F_BUFFER_CTX *)bio->ptr; + OPENSSL_free(ctx->ibuf); + OPENSSL_free(ctx->obuf); + OPENSSL_free(bio->ptr); + + bio->ptr = NULL; + bio->init = 0; + bio->flags = 0; + + return 1; +} + +static int buffer_read(BIO *bio, char *out, int outl) { + int i, num = 0; + BIO_F_BUFFER_CTX *ctx; + + ctx = (BIO_F_BUFFER_CTX *)bio->ptr; + + if (ctx == NULL || bio->next_bio == NULL) { + return 0; + } + + num = 0; + BIO_clear_retry_flags(bio); + + for (;;) { + i = ctx->ibuf_len; + /* If there is stuff left over, grab it */ + if (i != 0) { + if (i > outl) { + i = outl; + } + memcpy(out, &ctx->ibuf[ctx->ibuf_off], i); + ctx->ibuf_off += i; + ctx->ibuf_len -= i; + num += i; + if (outl == i) { + return num; + } + outl -= i; + out += i; + } + + /* We may have done a partial read. Try to do more. We have nothing in the + * buffer. If we get an error and have read some data, just return it and + * let them retry to get the error again. Copy direct to parent address + * space */ + if (outl > ctx->ibuf_size) { + for (;;) { + i = BIO_read(bio->next_bio, out, outl); + if (i <= 0) { + BIO_copy_next_retry(bio); + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + num += i; + if (outl == i) { + return num; + } + out += i; + outl -= i; + } + } + /* else */ + + /* we are going to be doing some buffering */ + i = BIO_read(bio->next_bio, ctx->ibuf, ctx->ibuf_size); + if (i <= 0) { + BIO_copy_next_retry(bio); + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + ctx->ibuf_off = 0; + ctx->ibuf_len = i; + } +} + +static int buffer_write(BIO *b, const char *in, int inl) { + int i, num = 0; + BIO_F_BUFFER_CTX *ctx; + + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + if (ctx == NULL || b->next_bio == NULL) { + return 0; + } + + BIO_clear_retry_flags(b); + + for (;;) { + i = ctx->obuf_size - (ctx->obuf_off + ctx->obuf_len); + /* add to buffer and return */ + if (i >= inl) { + memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, inl); + ctx->obuf_len += inl; + return num + inl; + } + /* else */ + /* stuff already in buffer, so add to it first, then flush */ + if (ctx->obuf_len != 0) { + if (i > 0) { + memcpy(&ctx->obuf[ctx->obuf_off + ctx->obuf_len], in, i); + in += i; + inl -= i; + num += i; + ctx->obuf_len += i; + } + + /* we now have a full buffer needing flushing */ + for (;;) { + i = BIO_write(b->next_bio, &ctx->obuf[ctx->obuf_off], ctx->obuf_len); + if (i <= 0) { + BIO_copy_next_retry(b); + + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + ctx->obuf_off += i; + ctx->obuf_len -= i; + if (ctx->obuf_len == 0) { + break; + } + } + } + + /* we only get here if the buffer has been flushed and we + * still have stuff to write */ + ctx->obuf_off = 0; + + /* we now have inl bytes to write */ + while (inl >= ctx->obuf_size) { + i = BIO_write(b->next_bio, in, inl); + if (i <= 0) { + BIO_copy_next_retry(b); + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + num += i; + in += i; + inl -= i; + if (inl == 0) { + return num; + } + } + + /* copy the rest into the buffer since we have only a small + * amount left */ + } +} + +static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) { + BIO_F_BUFFER_CTX *ctx; + long ret = 1; + char *p1, *p2; + int r, *ip; + int ibs, obs; + + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + ctx->ibuf_off = 0; + ctx->ibuf_len = 0; + ctx->obuf_off = 0; + ctx->obuf_len = 0; + if (b->next_bio == NULL) { + return 0; + } + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + + case BIO_CTRL_INFO: + ret = ctx->obuf_len; + break; + + case BIO_CTRL_WPENDING: + ret = (long)ctx->obuf_len; + if (ret == 0) { + if (b->next_bio == NULL) { + return 0; + } + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + } + break; + + case BIO_CTRL_PENDING: + ret = (long)ctx->ibuf_len; + if (ret == 0) { + if (b->next_bio == NULL) { + return 0; + } + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + } + break; + + case BIO_C_SET_BUFF_SIZE: + ip = (int *)ptr; + if (*ip == 0) { + ibs = (int)num; + obs = ctx->obuf_size; + } else /* if (*ip == 1) */ { + ibs = ctx->ibuf_size; + obs = (int)num; + } + p1 = ctx->ibuf; + p2 = ctx->obuf; + if (ibs > DEFAULT_BUFFER_SIZE && ibs != ctx->ibuf_size) { + p1 = (char *)OPENSSL_malloc(ibs); + if (p1 == NULL) { + goto malloc_error; + } + } + if (obs > DEFAULT_BUFFER_SIZE && obs != ctx->obuf_size) { + p2 = (char *)OPENSSL_malloc(obs); + if (p2 == NULL) { + if (p1 != ctx->ibuf) { + OPENSSL_free(p1); + } + goto malloc_error; + } + } + + if (ctx->ibuf != p1) { + OPENSSL_free(ctx->ibuf); + ctx->ibuf = p1; + ctx->ibuf_size = ibs; + } + ctx->ibuf_off = 0; + ctx->ibuf_len = 0; + + if (ctx->obuf != p2) { + OPENSSL_free(ctx->obuf); + ctx->obuf = p2; + ctx->obuf_size = obs; + } + ctx->obuf_off = 0; + ctx->obuf_len = 0; + break; + + case BIO_CTRL_FLUSH: + if (b->next_bio == NULL) { + return 0; + } + + while (ctx->obuf_len > 0) { + BIO_clear_retry_flags(b); + r = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]), + ctx->obuf_len); + BIO_copy_next_retry(b); + if (r <= 0) { + return r; + } + ctx->obuf_off += r; + ctx->obuf_len -= r; + } + + ctx->obuf_len = 0; + ctx->obuf_off = 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + + default: + if (b->next_bio == NULL) { + return 0; + } + BIO_clear_retry_flags(b); + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + BIO_copy_next_retry(b); + break; + } + return ret; + +malloc_error: + OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); + return 0; +} + +static long buffer_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) { + long ret = 1; + + if (b->next_bio == NULL) { + return 0; + } + + switch (cmd) { + default: + ret = BIO_callback_ctrl(b->next_bio, cmd, fp); + break; + } + return ret; +} + +static int buffer_gets(BIO *b, char *buf, int size) { + BIO_F_BUFFER_CTX *ctx; + int num = 0, i, flag; + char *p; + + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + if (buf == NULL || size <= 0) { + return 0; + } + + size--; /* reserve space for a '\0' */ + BIO_clear_retry_flags(b); + + for (;;) { + if (ctx->ibuf_len > 0) { + p = &ctx->ibuf[ctx->ibuf_off]; + flag = 0; + for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) { + *(buf++) = p[i]; + if (p[i] == '\n') { + flag = 1; + i++; + break; + } + } + num += i; + size -= i; + ctx->ibuf_len -= i; + ctx->ibuf_off += i; + if (flag || size == 0) { + *buf = '\0'; + return num; + } + } else /* read another chunk */ + { + i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); + if (i <= 0) { + BIO_copy_next_retry(b); + *buf = '\0'; + if (i < 0) { + return (num > 0) ? num : i; + } + return num; + } + ctx->ibuf_len = i; + ctx->ibuf_off = 0; + } + } +} + +static int buffer_puts(BIO *b, const char *str) { + return buffer_write(b, str, strlen(str)); +} + +static const BIO_METHOD methods_buffer = { + BIO_TYPE_BUFFER, "buffer", buffer_write, buffer_read, + buffer_puts, buffer_gets, buffer_ctrl, buffer_new, + buffer_free, buffer_callback_ctrl, +}; + +const BIO_METHOD *BIO_f_buffer(void) { return &methods_buffer; } + +int BIO_set_read_buffer_size(BIO *bio, int buffer_size) { + return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 0); +} + +int BIO_set_write_buffer_size(BIO *bio, int buffer_size) { + return BIO_int_ctrl(bio, BIO_C_SET_BUFF_SIZE, buffer_size, 1); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/connect.c b/TMessagesProj/jni/boringssl/crypto/bio/connect.c new file mode 100644 index 00000000..2ed2def1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/connect.c @@ -0,0 +1,538 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include + +#if !defined(OPENSSL_WINDOWS) +#include +#include +#include +#include +#else +#pragma warning(push, 3) +#include +#include +#pragma warning(pop) +#endif + +#include +#include +#include + +#include "internal.h" + + +enum { + BIO_CONN_S_BEFORE, + BIO_CONN_S_BLOCKED_CONNECT, + BIO_CONN_S_OK, +}; + +typedef struct bio_connect_st { + int state; + + char *param_hostname; + char *param_port; + int nbio; + + uint8_t ip[4]; + unsigned short port; + + struct sockaddr_storage them; + socklen_t them_length; + + /* the file descriptor is kept in bio->num in order to match the socket + * BIO. */ + + /* info_callback is called when the connection is initially made + * callback(BIO,state,ret); The callback should return 'ret', state is for + * compatibility with the SSL info_callback. */ + int (*info_callback)(const BIO *bio, int state, int ret); +} BIO_CONNECT; + +#if !defined(OPENSSL_WINDOWS) +static int closesocket(int sock) { + return close(sock); +} +#endif + +/* maybe_copy_ipv4_address sets |*ipv4| to the IPv4 address from |ss| (in + * big-endian order), if |ss| contains an IPv4 socket address. */ +static void maybe_copy_ipv4_address(uint8_t *ipv4, + const struct sockaddr_storage *ss) { + const struct sockaddr_in *sin; + + if (ss->ss_family != AF_INET) { + return; + } + + sin = (const struct sockaddr_in*) ss; + memcpy(ipv4, &sin->sin_addr, 4); +} + +static int conn_state(BIO *bio, BIO_CONNECT *c) { + int ret = -1, i; + char *p, *q; + int (*cb)(const BIO *, int, int) = NULL; + + if (c->info_callback != NULL) { + cb = c->info_callback; + } + + for (;;) { + switch (c->state) { + case BIO_CONN_S_BEFORE: + p = c->param_hostname; + if (p == NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_R_NO_HOSTNAME_SPECIFIED); + goto exit_loop; + } + for (; *p != 0; p++) { + if (*p == ':' || *p == '/') { + break; + } + } + + i = *p; + if (i == ':' || i == '/') { + *(p++) = 0; + if (i == ':') { + for (q = p; *q; q++) { + if (*q == '/') { + *q = 0; + break; + } + } + OPENSSL_free(c->param_port); + c->param_port = BUF_strdup(p); + } + } + + if (c->param_port == NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_R_NO_PORT_SPECIFIED); + ERR_add_error_data(2, "host=", c->param_hostname); + goto exit_loop; + } + + if (!bio_ip_and_port_to_socket_and_addr( + &bio->num, &c->them, &c->them_length, c->param_hostname, + c->param_port)) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNABLE_TO_CREATE_SOCKET); + ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port); + goto exit_loop; + } + + memset(c->ip, 0, 4); + maybe_copy_ipv4_address(c->ip, &c->them); + + if (c->nbio) { + if (!bio_socket_nbio(bio->num, 1)) { + OPENSSL_PUT_ERROR(BIO, BIO_R_ERROR_SETTING_NBIO); + ERR_add_error_data(4, "host=", c->param_hostname, ":", + c->param_port); + goto exit_loop; + } + } + + i = 1; + ret = setsockopt(bio->num, SOL_SOCKET, SO_KEEPALIVE, (char *)&i, + sizeof(i)); + if (ret < 0) { + OPENSSL_PUT_SYSTEM_ERROR(setsockopt); + OPENSSL_PUT_ERROR(BIO, BIO_R_KEEPALIVE); + ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port); + goto exit_loop; + } + + BIO_clear_retry_flags(bio); + ret = connect(bio->num, (struct sockaddr*) &c->them, c->them_length); + if (ret < 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_flags(bio, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY)); + c->state = BIO_CONN_S_BLOCKED_CONNECT; + bio->retry_reason = BIO_RR_CONNECT; + } else { + OPENSSL_PUT_SYSTEM_ERROR(connect); + OPENSSL_PUT_ERROR(BIO, BIO_R_CONNECT_ERROR); + ERR_add_error_data(4, "host=", c->param_hostname, ":", + c->param_port); + } + goto exit_loop; + } else { + c->state = BIO_CONN_S_OK; + } + break; + + case BIO_CONN_S_BLOCKED_CONNECT: + i = bio_sock_error(bio->num); + if (i) { + if (bio_fd_should_retry(ret)) { + BIO_set_flags(bio, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY)); + c->state = BIO_CONN_S_BLOCKED_CONNECT; + bio->retry_reason = BIO_RR_CONNECT; + ret = -1; + } else { + BIO_clear_retry_flags(bio); + OPENSSL_PUT_SYSTEM_ERROR(connect); + OPENSSL_PUT_ERROR(BIO, BIO_R_NBIO_CONNECT_ERROR); + ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port); + ret = 0; + } + goto exit_loop; + } else { + c->state = BIO_CONN_S_OK; + } + break; + + case BIO_CONN_S_OK: + ret = 1; + goto exit_loop; + default: + assert(0); + goto exit_loop; + } + + if (cb != NULL) { + ret = cb((BIO *)bio, c->state, ret); + if (ret == 0) { + goto end; + } + } + } + +exit_loop: + if (cb != NULL) { + ret = cb((BIO *)bio, c->state, ret); + } + +end: + return ret; +} + +static BIO_CONNECT *BIO_CONNECT_new(void) { + BIO_CONNECT *ret = OPENSSL_malloc(sizeof(BIO_CONNECT)); + + if (ret == NULL) { + return NULL; + } + memset(ret, 0, sizeof(BIO_CONNECT)); + + ret->state = BIO_CONN_S_BEFORE; + return ret; +} + +static void BIO_CONNECT_free(BIO_CONNECT *c) { + if (c == NULL) { + return; + } + + OPENSSL_free(c->param_hostname); + OPENSSL_free(c->param_port); + OPENSSL_free(c); +} + +static int conn_new(BIO *bio) { + bio->init = 0; + bio->num = -1; + bio->flags = 0; + bio->ptr = (char *)BIO_CONNECT_new(); + return bio->ptr != NULL; +} + +static void conn_close_socket(BIO *bio) { + BIO_CONNECT *c = (BIO_CONNECT *) bio->ptr; + + if (bio->num == -1) { + return; + } + + /* Only do a shutdown if things were established */ + if (c->state == BIO_CONN_S_OK) { + shutdown(bio->num, 2); + } + closesocket(bio->num); + bio->num = -1; +} + +static int conn_free(BIO *bio) { + if (bio == NULL) { + return 0; + } + + if (bio->shutdown) { + conn_close_socket(bio); + } + + BIO_CONNECT_free((BIO_CONNECT*) bio->ptr); + + return 1; +} + +static int conn_read(BIO *bio, char *out, int out_len) { + int ret = 0; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)bio->ptr; + if (data->state != BIO_CONN_S_OK) { + ret = conn_state(bio, data); + if (ret <= 0) { + return ret; + } + } + + bio_clear_socket_error(); + ret = recv(bio->num, out, out_len, 0); + BIO_clear_retry_flags(bio); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_read(bio); + } + } + + return ret; +} + +static int conn_write(BIO *bio, const char *in, int in_len) { + int ret; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)bio->ptr; + if (data->state != BIO_CONN_S_OK) { + ret = conn_state(bio, data); + if (ret <= 0) { + return ret; + } + } + + bio_clear_socket_error(); + ret = send(bio->num, in, in_len, 0); + BIO_clear_retry_flags(bio); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_write(bio); + } + } + + return ret; +} + +static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) { + int *ip; + const char **pptr; + long ret = 1; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)bio->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + ret = 0; + data->state = BIO_CONN_S_BEFORE; + conn_close_socket(bio); + bio->flags = 0; + break; + case BIO_C_DO_STATE_MACHINE: + /* use this one to start the connection */ + if (data->state != BIO_CONN_S_OK) { + ret = (long)conn_state(bio, data); + } else { + ret = 1; + } + break; + case BIO_C_GET_CONNECT: + /* TODO(fork): can this be removed? (Or maybe this whole file). */ + if (ptr != NULL) { + pptr = (const char **)ptr; + if (num == 0) { + *pptr = data->param_hostname; + } else if (num == 1) { + *pptr = data->param_port; + } else if (num == 2) { + *pptr = (char *) &data->ip[0]; + } else if (num == 3) { + *((int *)ptr) = data->port; + } + if (!bio->init) { + *pptr = "not initialized"; + } + ret = 1; + } + break; + case BIO_C_SET_CONNECT: + if (ptr != NULL) { + bio->init = 1; + if (num == 0) { + OPENSSL_free(data->param_hostname); + data->param_hostname = BUF_strdup(ptr); + if (data->param_hostname == NULL) { + ret = 0; + } + } else if (num == 1) { + OPENSSL_free(data->param_port); + data->param_port = BUF_strdup(ptr); + if (data->param_port == NULL) { + ret = 0; + } + } else { + ret = 0; + } + } + break; + case BIO_C_SET_NBIO: + data->nbio = (int)num; + break; + case BIO_C_GET_FD: + if (bio->init) { + ip = (int *)ptr; + if (ip != NULL) { + *ip = bio->num; + } + ret = 1; + } else { + ret = 0; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = bio->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + bio->shutdown = (int)num; + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_FLUSH: + break; + case BIO_CTRL_SET_CALLBACK: { +#if 0 /* FIXME: Should this be used? -- Richard Levitte */ + OPENSSL_PUT_ERROR(BIO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + ret = -1; +#else + ret = 0; +#endif + } break; + case BIO_CTRL_GET_CALLBACK: { + int (**fptr)(const BIO *bio, int state, int xret); + fptr = (int (**)(const BIO *bio, int state, int xret))ptr; + *fptr = data->info_callback; + } break; + default: + ret = 0; + break; + } + return (ret); +} + +static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) { + long ret = 1; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)bio->ptr; + + switch (cmd) { + case BIO_CTRL_SET_CALLBACK: { + data->info_callback = (int (*)(const struct bio_st *, int, int))fp; + } break; + default: + ret = 0; + break; + } + return ret; +} + +static int conn_puts(BIO *bp, const char *str) { + return conn_write(bp, str, strlen(str)); +} + +BIO *BIO_new_connect(const char *hostname) { + BIO *ret; + + ret = BIO_new(BIO_s_connect()); + if (ret == NULL) { + return NULL; + } + if (!BIO_set_conn_hostname(ret, hostname)) { + BIO_free(ret); + return NULL; + } + return ret; +} + +static const BIO_METHOD methods_connectp = { + BIO_TYPE_CONNECT, "socket connect", conn_write, conn_read, + conn_puts, NULL /* connect_gets, */, conn_ctrl, conn_new, + conn_free, conn_callback_ctrl, +}; + +const BIO_METHOD *BIO_s_connect(void) { return &methods_connectp; } + +int BIO_set_conn_hostname(BIO *bio, const char *name) { + return BIO_ctrl(bio, BIO_C_SET_CONNECT, 0, (void*) name); +} + +int BIO_set_conn_port(BIO *bio, const char *port_str) { + return BIO_ctrl(bio, BIO_C_SET_CONNECT, 1, (void*) port_str); +} + +int BIO_set_nbio(BIO *bio, int on) { + return BIO_ctrl(bio, BIO_C_SET_NBIO, on, NULL); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/fd.c b/TMessagesProj/jni/boringssl/crypto/bio/fd.c new file mode 100644 index 00000000..0b5baca9 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/fd.c @@ -0,0 +1,270 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#if !defined(OPENSSL_WINDOWS) +#include +#else +#include +#pragma warning(push, 3) +#include +#pragma warning(pop) +#endif + +#include +#include +#include + + +static int bio_fd_non_fatal_error(int err) { + if ( +#ifdef EWOULDBLOCK + err == EWOULDBLOCK || +#endif +#ifdef WSAEWOULDBLOCK + err == WSAEWOULDBLOCK || +#endif +#ifdef ENOTCONN + err == ENOTCONN || +#endif +#ifdef EINTR + err == EINTR || +#endif +#ifdef EAGAIN + err == EAGAIN || +#endif +#ifdef EPROTO + err == EPROTO || +#endif +#ifdef EINPROGRESS + err == EINPROGRESS || +#endif +#ifdef EALREADY + err == EALREADY || +#endif + 0) { + return 1; + } + return 0; +} + +#if defined(OPENSSL_WINDOWS) +int bio_fd_should_retry(int i) { + if (i == -1) { + return bio_fd_non_fatal_error((int)GetLastError()); + } + return 0; +} +#else +int bio_fd_should_retry(int i) { + if (i == -1) { + return bio_fd_non_fatal_error(errno); + } + return 0; +} +#endif + +BIO *BIO_new_fd(int fd, int close_flag) { + BIO *ret = BIO_new(BIO_s_fd()); + if (ret == NULL) { + return NULL; + } + BIO_set_fd(ret, fd, close_flag); + return ret; +} + +static int fd_new(BIO *bio) { + /* num is used to store the file descriptor. */ + bio->num = -1; + return 1; +} + +static int fd_free(BIO *bio) { + if (bio == NULL) { + return 0; + } + + if (bio->shutdown) { + if (bio->init) { + close(bio->num); + } + bio->init = 0; + } + return 1; +} + +static int fd_read(BIO *b, char *out, int outl) { + int ret = 0; + + ret = read(b->num, out, outl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_read(b); + } + } + + return ret; +} + +static int fd_write(BIO *b, const char *in, int inl) { + int ret = write(b->num, in, inl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_write(b); + } + } + + return ret; +} + +static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) { + long ret = 1; + int *ip; + + switch (cmd) { + case BIO_CTRL_RESET: + num = 0; + case BIO_C_FILE_SEEK: + ret = 0; + if (b->init) { + ret = (long)lseek(b->num, num, SEEK_SET); + } + break; + case BIO_C_FILE_TELL: + case BIO_CTRL_INFO: + ret = 0; + if (b->init) { + ret = (long)lseek(b->num, 0, SEEK_CUR); + } + break; + case BIO_C_SET_FD: + fd_free(b); + b->num = *((int *)ptr); + b->shutdown = (int)num; + b->init = 1; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) { + *ip = b->num; + } + return 1; + } else { + ret = 0; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_FLUSH: + ret = 1; + break; + default: + ret = 0; + break; + } + + return ret; +} + +static int fd_puts(BIO *bp, const char *str) { + return fd_write(bp, str, strlen(str)); +} + +static int fd_gets(BIO *bp, char *buf, int size) { + char *ptr = buf; + char *end = buf + size - 1; + + if (size <= 0) { + return 0; + } + + while (ptr < end && fd_read(bp, ptr, 1) > 0 && ptr[0] != '\n') { + ptr++; + } + + ptr[0] = '\0'; + + return ptr - buf; +} + +static const BIO_METHOD methods_fdp = { + BIO_TYPE_FD, "file descriptor", fd_write, fd_read, fd_puts, + fd_gets, fd_ctrl, fd_new, fd_free, NULL, }; + +const BIO_METHOD *BIO_s_fd(void) { return &methods_fdp; } + +int BIO_set_fd(BIO *bio, int fd, int close_flag) { + return BIO_int_ctrl(bio, BIO_C_SET_FD, close_flag, fd); +} + +int BIO_get_fd(BIO *bio, int *out_fd) { + return BIO_ctrl(bio, BIO_C_GET_FD, 0, (char *) out_fd); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/file.c b/TMessagesProj/jni/boringssl/crypto/bio/file.c new file mode 100644 index 00000000..cef33b66 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/file.c @@ -0,0 +1,350 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#if defined(__linux) || defined(__sun) || defined(__hpux) +/* Following definition aliases fopen to fopen64 on above mentioned + * platforms. This makes it possible to open and sequentially access + * files larger than 2GB from 32-bit application. It does not allow to + * traverse them beyond 2GB with fseek/ftell, but on the other hand *no* + * 32-bit platform permits that, not with fseek/ftell. Not to mention + * that breaking 2GB limit for seeking would require surgery to *our* + * API. But sequential access suffices for practical cases when you + * can run into large files, such as fingerprinting, so we can let API + * alone. For reference, the list of 32-bit platforms which allow for + * sequential access of large files without extra "magic" comprise *BSD, + * Darwin, IRIX... + */ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#endif + +#include + +#include +#include +#include + +#include +#include +#include + + +#define BIO_FP_READ 0x02 +#define BIO_FP_WRITE 0x04 +#define BIO_FP_APPEND 0x08 + +static FILE *open_file(const char *filename, const char *mode) { +#if defined(OPENSSL_WINDOWS) && defined(CP_UTF8) + int sz, len_0 = (int)strlen(filename) + 1; + DWORD flags; + + /* Basically there are three cases to cover: a) filename is pure ASCII + * string; b) actual UTF-8 encoded string and c) locale-ized string, i.e. one + * containing 8-bit characters that are meaningful in current system locale. + * If filename is pure ASCII or real UTF-8 encoded string, + * MultiByteToWideChar succeeds and _wfopen works. If filename is locale-ized + * string, chances are that MultiByteToWideChar fails reporting + * ERROR_NO_UNICODE_TRANSLATION, in which case we fall back to fopen... */ + if ((sz = MultiByteToWideChar(CP_UTF8, (flags = MB_ERR_INVALID_CHARS), + filename, len_0, NULL, 0)) > 0 || + (GetLastError() == ERROR_INVALID_FLAGS && + (sz = MultiByteToWideChar(CP_UTF8, (flags = 0), filename, len_0, NULL, + 0)) > 0)) { + WCHAR wmode[8]; + WCHAR *wfilename = _alloca(sz * sizeof(WCHAR)); + + if (MultiByteToWideChar(CP_UTF8, flags, filename, len_0, wfilename, sz) && + MultiByteToWideChar(CP_UTF8, 0, mode, strlen(mode) + 1, wmode, + sizeof(wmode) / sizeof(wmode[0])) && + (file = _wfopen(wfilename, wmode)) == NULL && + (errno == ENOENT || + errno == EBADF)) /* UTF-8 decode succeeded, but no file, filename + * could still have been locale-ized... */ + return fopen(filename, mode); + } else if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) { + return fopen(filename, mode); + } +#else + return fopen(filename, mode); +#endif +} + +BIO *BIO_new_file(const char *filename, const char *mode) { + BIO *ret; + FILE *file; + + file = open_file(filename, mode); + if (file == NULL) { + OPENSSL_PUT_SYSTEM_ERROR(fopen); + + ERR_add_error_data(5, "fopen('", filename, "','", mode, "')"); + if (errno == ENOENT) { + OPENSSL_PUT_ERROR(BIO, BIO_R_NO_SUCH_FILE); + } else { + OPENSSL_PUT_ERROR(BIO, BIO_R_SYS_LIB); + } + return NULL; + } + + ret = BIO_new(BIO_s_file()); + if (ret == NULL) { + fclose(file); + return NULL; + } + + BIO_set_fp(ret, file, BIO_CLOSE); + return ret; +} + +BIO *BIO_new_fp(FILE *stream, int close_flag) { + BIO *ret = BIO_new(BIO_s_file()); + + if (ret == NULL) { + return NULL; + } + + BIO_set_fp(ret, stream, close_flag); + return ret; +} + +static int file_new(BIO *bio) { return 1; } + +static int file_free(BIO *bio) { + if (bio == NULL) { + return 0; + } + + if (!bio->shutdown) { + return 1; + } + + if (bio->init && bio->ptr != NULL) { + fclose(bio->ptr); + bio->ptr = NULL; + } + bio->init = 0; + + return 1; +} + +static int file_read(BIO *b, char *out, int outl) { + int ret = 0; + + if (!b->init) { + return 0; + } + + ret = fread(out, 1, outl, (FILE *)b->ptr); + if (ret == 0 && ferror((FILE *)b->ptr)) { + OPENSSL_PUT_SYSTEM_ERROR(fread); + OPENSSL_PUT_ERROR(BIO, ERR_R_SYS_LIB); + ret = -1; + } + + return ret; +} + +static int file_write(BIO *b, const char *in, int inl) { + int ret = 0; + + if (!b->init) { + return 0; + } + + ret = fwrite(in, inl, 1, (FILE *)b->ptr); + if (ret > 0) { + ret = inl; + } + return ret; +} + +static long file_ctrl(BIO *b, int cmd, long num, void *ptr) { + long ret = 1; + FILE *fp = (FILE *)b->ptr; + FILE **fpp; + char p[4]; + + switch (cmd) { + case BIO_CTRL_RESET: + num = 0; + case BIO_C_FILE_SEEK: + ret = (long)fseek(fp, num, 0); + break; + case BIO_CTRL_EOF: + ret = (long)feof(fp); + break; + case BIO_C_FILE_TELL: + case BIO_CTRL_INFO: + ret = ftell(fp); + break; + case BIO_C_SET_FILE_PTR: + file_free(b); + b->shutdown = (int)num & BIO_CLOSE; + b->ptr = ptr; + b->init = 1; + break; + case BIO_C_SET_FILENAME: + file_free(b); + b->shutdown = (int)num & BIO_CLOSE; + if (num & BIO_FP_APPEND) { + if (num & BIO_FP_READ) { + BUF_strlcpy(p, "a+", sizeof(p)); + } else { + BUF_strlcpy(p, "a", sizeof(p)); + } + } else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE)) { + BUF_strlcpy(p, "r+", sizeof(p)); + } else if (num & BIO_FP_WRITE) { + BUF_strlcpy(p, "w", sizeof(p)); + } else if (num & BIO_FP_READ) { + BUF_strlcpy(p, "r", sizeof(p)); + } else { + OPENSSL_PUT_ERROR(BIO, BIO_R_BAD_FOPEN_MODE); + ret = 0; + break; + } + fp = open_file(ptr, p); + if (fp == NULL) { + OPENSSL_PUT_SYSTEM_ERROR(fopen); + ERR_add_error_data(5, "fopen('", ptr, "','", p, "')"); + OPENSSL_PUT_ERROR(BIO, ERR_R_SYS_LIB); + ret = 0; + break; + } + b->ptr = fp; + b->init = 1; + break; + case BIO_C_GET_FILE_PTR: + /* the ptr parameter is actually a FILE ** in this case. */ + if (ptr != NULL) { + fpp = (FILE **)ptr; + *fpp = (FILE *)b->ptr; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = (long)b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_FLUSH: + ret = 0 == fflush((FILE *)b->ptr); + break; + case BIO_CTRL_WPENDING: + case BIO_CTRL_PENDING: + default: + ret = 0; + break; + } + return ret; +} + +static int file_gets(BIO *bp, char *buf, int size) { + int ret = 0; + + if (size == 0) { + return 0; + } + + if (!fgets(buf, size, (FILE *)bp->ptr)) { + buf[0] = 0; + goto err; + } + ret = strlen(buf); + +err: + return ret; +} + +static int file_puts(BIO *bp, const char *str) { + return file_write(bp, str, strlen(str)); +} + +static const BIO_METHOD methods_filep = { + BIO_TYPE_FILE, "FILE pointer", file_write, file_read, file_puts, + file_gets, file_ctrl, file_new, file_free, NULL, }; + +const BIO_METHOD *BIO_s_file(void) { return &methods_filep; } + + +int BIO_get_fp(BIO *bio, FILE **out_file) { + return BIO_ctrl(bio, BIO_C_GET_FILE_PTR, 0, (char*) out_file); +} + +int BIO_set_fp(BIO *bio, FILE *file, int close_flag) { + return BIO_ctrl(bio, BIO_C_SET_FILE_PTR, close_flag, (char *) file); +} + +int BIO_read_filename(BIO *bio, const char *filename) { + return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_READ, + (char *)filename); +} + +int BIO_write_filename(BIO *bio, const char *filename) { + return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_WRITE, + (char *)filename); +} + +int BIO_append_filename(BIO *bio, const char *filename) { + return BIO_ctrl(bio, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_APPEND, + (char *)filename); +} + +int BIO_rw_filename(BIO *bio, const char *filename) { + return BIO_ctrl(bio, BIO_C_SET_FILENAME, + BIO_CLOSE | BIO_FP_READ | BIO_FP_WRITE, (char *)filename); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/hexdump.c b/TMessagesProj/jni/boringssl/crypto/bio/hexdump.c new file mode 100644 index 00000000..17f55183 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/hexdump.c @@ -0,0 +1,192 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +/* hexdump_ctx contains the state of a hexdump. */ +struct hexdump_ctx { + BIO *bio; + char right_chars[18]; /* the contents of the right-hand side, ASCII dump. */ + unsigned used; /* number of bytes in the current line. */ + size_t n; /* number of bytes total. */ + unsigned indent; +}; + +static void hexbyte(char *out, uint8_t b) { + static const char hextable[] = "0123456789abcdef"; + out[0] = hextable[b>>4]; + out[1] = hextable[b&0x0f]; +} + +static char to_char(uint8_t b) { + if (b < 32 || b > 126) { + return '.'; + } + return b; +} + +/* hexdump_write adds |len| bytes of |data| to the current hex dump described by + * |ctx|. */ +static int hexdump_write(struct hexdump_ctx *ctx, const uint8_t *data, + size_t len) { + size_t i; + char buf[10]; + unsigned l; + + /* Output lines look like: + * 00000010 2e 2f 30 31 32 33 34 35 36 37 38 ... 3c 3d // |./0123456789:;<=| + * ^ offset ^ extra space ^ ASCII of line + */ + + for (i = 0; i < len; i++) { + if (ctx->used == 0) { + /* The beginning of a line. */ + BIO_indent(ctx->bio, ctx->indent, UINT_MAX); + + hexbyte(&buf[0], ctx->n >> 24); + hexbyte(&buf[2], ctx->n >> 16); + hexbyte(&buf[4], ctx->n >> 8); + hexbyte(&buf[6], ctx->n); + buf[8] = buf[9] = ' '; + if (BIO_write(ctx->bio, buf, 10) < 0) { + return 0; + } + } + + hexbyte(buf, data[i]); + buf[2] = ' '; + l = 3; + if (ctx->used == 7) { + /* There's an additional space after the 8th byte. */ + buf[3] = ' '; + l = 4; + } else if (ctx->used == 15) { + /* At the end of the line there's an extra space and the bar for the + * right column. */ + buf[3] = ' '; + buf[4] = '|'; + l = 5; + } + + if (BIO_write(ctx->bio, buf, l) < 0) { + return 0; + } + ctx->right_chars[ctx->used] = to_char(data[i]); + ctx->used++; + ctx->n++; + if (ctx->used == 16) { + ctx->right_chars[16] = '|'; + ctx->right_chars[17] = '\n'; + if (BIO_write(ctx->bio, ctx->right_chars, sizeof(ctx->right_chars)) < 0) { + return 0; + } + ctx->used = 0; + } + } + + return 1; +} + +/* finish flushes any buffered data in |ctx|. */ +static int finish(struct hexdump_ctx *ctx) { + /* See the comments in |hexdump| for the details of this format. */ + const unsigned n_bytes = ctx->used; + unsigned l; + char buf[5]; + + if (n_bytes == 0) { + return 1; + } + + memset(buf, ' ', 4); + buf[4] = '|'; + + for (; ctx->used < 16; ctx->used++) { + l = 3; + if (ctx->used == 7) { + l = 4; + } else if (ctx->used == 15) { + l = 5; + } + if (BIO_write(ctx->bio, buf, l) < 0) { + return 0; + } + } + + ctx->right_chars[n_bytes] = '|'; + ctx->right_chars[n_bytes + 1] = '\n'; + if (BIO_write(ctx->bio, ctx->right_chars, n_bytes + 2) < 0) { + return 0; + } + return 1; +} + +int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, unsigned indent) { + struct hexdump_ctx ctx; + memset(&ctx, 0, sizeof(ctx)); + ctx.bio = bio; + ctx.indent = indent; + + if (!hexdump_write(&ctx, data, len) || !finish(&ctx)) { + return 0; + } + + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/internal.h b/TMessagesProj/jni/boringssl/crypto/bio/internal.h new file mode 100644 index 00000000..d9a34f18 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/internal.h @@ -0,0 +1,108 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BIO_INTERNAL_H +#define OPENSSL_HEADER_BIO_INTERNAL_H + +#include + +#if !defined(OPENSSL_WINDOWS) +#if defined(OPENSSL_PNACL) +/* newlib uses u_short in socket.h without defining it. */ +typedef unsigned short u_short; +#endif +#include +#include +#else +typedef int socklen_t; +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* BIO_ip_and_port_to_socket_and_addr creates a socket and fills in |*out_addr| + * and |*out_addr_length| with the correct values for connecting to |hostname| + * on |port_str|. It returns one on success or zero on error. */ +int bio_ip_and_port_to_socket_and_addr(int *out_sock, + struct sockaddr_storage *out_addr, + socklen_t *out_addr_length, + const char *hostname, + const char *port_str); + +/* BIO_socket_nbio sets whether |sock| is non-blocking. It returns one on + * success and zero otherwise. */ +int bio_socket_nbio(int sock, int on); + +/* BIO_clear_socket_error clears the last system socket error. + * + * TODO(fork): remove all callers of this. */ +void bio_clear_socket_error(void); + +/* BIO_sock_error returns the last socket error on |sock|. */ +int bio_sock_error(int sock); + +/* BIO_fd_should_retry returns non-zero if |return_value| indicates an error + * and |errno| indicates that it's non-fatal. */ +int bio_fd_should_retry(int return_value); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BIO_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/bio/pair.c b/TMessagesProj/jni/boringssl/crypto/bio/pair.c new file mode 100644 index 00000000..6f788903 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/pair.c @@ -0,0 +1,803 @@ +/* ==================================================================== + * Copyright (c) 1998-2003 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include +#include +#include + + +struct bio_bio_st { + BIO *peer; /* NULL if buf == NULL. + * If peer != NULL, then peer->ptr is also a bio_bio_st, + * and its "peer" member points back to us. + * peer != NULL iff init != 0 in the BIO. */ + + /* This is for what we write (i.e. reading uses peer's struct): */ + int closed; /* valid iff peer != NULL */ + size_t len; /* valid iff buf != NULL; 0 if peer == NULL */ + size_t offset; /* valid iff buf != NULL; 0 if len == 0 */ + size_t size; + uint8_t *buf; /* "size" elements (if != NULL) */ + char buf_externally_allocated; /* true iff buf was externally allocated. */ + + char zero_copy_read_lock; /* true iff a zero copy read operation + * is in progress. */ + char zero_copy_write_lock; /* true iff a zero copy write operation + * is in progress. */ + + size_t request; /* valid iff peer != NULL; 0 if len != 0, + * otherwise set by peer to number of bytes + * it (unsuccessfully) tried to read, + * never more than buffer space (size-len) warrants. */ +}; + +static int bio_new(BIO *bio) { + struct bio_bio_st *b; + + b = OPENSSL_malloc(sizeof *b); + if (b == NULL) { + return 0; + } + memset(b, 0, sizeof(struct bio_bio_st)); + + b->size = 17 * 1024; /* enough for one TLS record (just a default) */ + bio->ptr = b; + return 1; +} + +static void bio_destroy_pair(BIO *bio) { + struct bio_bio_st *b = bio->ptr; + BIO *peer_bio; + struct bio_bio_st *peer_b; + + if (b == NULL) { + return; + } + + peer_bio = b->peer; + if (peer_bio == NULL) { + return; + } + + peer_b = peer_bio->ptr; + + assert(peer_b != NULL); + assert(peer_b->peer == bio); + + peer_b->peer = NULL; + peer_bio->init = 0; + assert(peer_b->buf != NULL); + peer_b->len = 0; + peer_b->offset = 0; + + b->peer = NULL; + bio->init = 0; + assert(b->buf != NULL); + b->len = 0; + b->offset = 0; +} + +static int bio_free(BIO *bio) { + struct bio_bio_st *b; + + if (bio == NULL) { + return 0; + } + b = bio->ptr; + + assert(b != NULL); + + if (b->peer) { + bio_destroy_pair(bio); + } + + if (!b->buf_externally_allocated) { + OPENSSL_free(b->buf); + } + + OPENSSL_free(b); + + return 1; +} + +static size_t bio_zero_copy_get_read_buf(struct bio_bio_st* peer_b, + uint8_t** out_read_buf, + size_t* out_buf_offset) { + size_t max_available; + if (peer_b->len > peer_b->size - peer_b->offset) { + /* Only the first half of the ring buffer can be read. */ + max_available = peer_b->size - peer_b->offset; + } else { + max_available = peer_b->len; + } + + *out_read_buf = peer_b->buf; + *out_buf_offset = peer_b->offset; + return max_available; +} + +int BIO_zero_copy_get_read_buf(BIO* bio, uint8_t** out_read_buf, + size_t* out_buf_offset, + size_t* out_available_bytes) { + struct bio_bio_st* b; + struct bio_bio_st* peer_b; + size_t max_available; + *out_available_bytes = 0; + + BIO_clear_retry_flags(bio); + + if (!bio->init) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); + return 0; + } + + b = bio->ptr; + + if (!b || !b->peer) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + peer_b = b->peer->ptr; + if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + if (peer_b->zero_copy_read_lock) { + OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); + return 0; + } + + peer_b->request = 0; /* Is not used by zero-copy API. */ + + max_available = + bio_zero_copy_get_read_buf(peer_b, out_read_buf, out_buf_offset); + + assert(peer_b->buf != NULL); + if (max_available > 0) { + peer_b->zero_copy_read_lock = 1; + } + + *out_available_bytes = max_available; + return 1; +} + +int BIO_zero_copy_get_read_buf_done(BIO* bio, size_t bytes_read) { + struct bio_bio_st* b; + struct bio_bio_st* peer_b; + size_t max_available; + size_t dummy_read_offset; + uint8_t* dummy_read_buf; + + assert(BIO_get_retry_flags(bio) == 0); + + if (!bio->init) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); + return 0; + } + + b = bio->ptr; + + if (!b || !b->peer) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + peer_b = b->peer->ptr; + if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + if (!peer_b->zero_copy_read_lock) { + OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); + return 0; + } + + max_available = + bio_zero_copy_get_read_buf(peer_b, &dummy_read_buf, &dummy_read_offset); + if (bytes_read > max_available) { + OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); + return 0; + } + + peer_b->len -= bytes_read; + assert(peer_b->len >= 0); + assert(peer_b->offset + bytes_read <= peer_b->size); + + /* Move read offset. If zero_copy_write_lock == 1 we must advance the + * offset even if buffer becomes empty, to make sure + * write_offset = (offset + len) mod size does not change. */ + if (peer_b->offset + bytes_read == peer_b->size || + (!peer_b->zero_copy_write_lock && peer_b->len == 0)) { + peer_b->offset = 0; + } else { + peer_b->offset += bytes_read; + } + + bio->num_read += bytes_read; + peer_b->zero_copy_read_lock = 0; + return 1; +} + +static size_t bio_zero_copy_get_write_buf(struct bio_bio_st* b, + uint8_t** out_write_buf, + size_t* out_buf_offset) { + size_t write_offset; + size_t max_available; + + assert(b->len <= b->size); + + write_offset = b->offset + b->len; + + if (write_offset >= b->size) { + /* Only the first half of the ring buffer can be written to. */ + write_offset -= b->size; + /* write up to the start of the ring buffer. */ + max_available = b->offset - write_offset; + } else { + /* write up to the end the buffer. */ + max_available = b->size - write_offset; + } + + *out_write_buf = b->buf; + *out_buf_offset = write_offset; + return max_available; +} + +int BIO_zero_copy_get_write_buf(BIO* bio, uint8_t** out_write_buf, + size_t* out_buf_offset, + size_t* out_available_bytes) { + struct bio_bio_st* b; + struct bio_bio_st* peer_b; + size_t max_available; + + *out_available_bytes = 0; + BIO_clear_retry_flags(bio); + + if (!bio->init) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); + return 0; + } + + b = bio->ptr; + + if (!b || !b->buf || !b->peer) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + peer_b = b->peer->ptr; + if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + assert(b->buf != NULL); + + if (b->zero_copy_write_lock) { + OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); + return 0; + } + + b->request = 0; + if (b->closed) { + /* Bio is already closed. */ + OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE); + return 0; + } + + max_available = bio_zero_copy_get_write_buf(b, out_write_buf, out_buf_offset); + + if (max_available > 0) { + b->zero_copy_write_lock = 1; + } + + *out_available_bytes = max_available; + return 1; +} + +int BIO_zero_copy_get_write_buf_done(BIO* bio, size_t bytes_written) { + struct bio_bio_st* b; + struct bio_bio_st* peer_b; + + size_t rest; + size_t dummy_write_offset; + uint8_t* dummy_write_buf; + + if (!bio->init) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); + return 0; + } + + b = bio->ptr; + + if (!b || !b->buf || !b->peer) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + peer_b = b->peer->ptr; + if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { + OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); + return 0; + } + + b->request = 0; + if (b->closed) { + /* BIO is already closed. */ + OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE); + return 0; + } + + if (!b->zero_copy_write_lock) { + OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); + return 0; + } + + rest = bio_zero_copy_get_write_buf(b, &dummy_write_buf, &dummy_write_offset); + + if (bytes_written > rest) { + OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); + return 0; + } + + bio->num_write += bytes_written; + /* Move write offset. */ + b->len += bytes_written; + b->zero_copy_write_lock = 0; + return 1; +} + +static int bio_read(BIO *bio, char *buf, int size_) { + size_t size = size_; + size_t rest; + struct bio_bio_st *b, *peer_b; + + BIO_clear_retry_flags(bio); + + if (!bio->init) { + return 0; + } + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + peer_b = b->peer->ptr; + assert(peer_b != NULL); + assert(peer_b->buf != NULL); + + peer_b->request = 0; /* will be set in "retry_read" situation */ + + if (buf == NULL || size == 0 || peer_b->zero_copy_read_lock) { + return 0; + } + + if (peer_b->len == 0) { + if (peer_b->closed) { + return 0; /* writer has closed, and no data is left */ + } else { + BIO_set_retry_read(bio); /* buffer is empty */ + if (size <= peer_b->size) { + peer_b->request = size; + } else { + /* don't ask for more than the peer can + * deliver in one write */ + peer_b->request = peer_b->size; + } + return -1; + } + } + + /* we can read */ + if (peer_b->len < size) { + size = peer_b->len; + } + + /* now read "size" bytes */ + rest = size; + + assert(rest > 0); + /* one or two iterations */ + do { + size_t chunk; + + assert(rest <= peer_b->len); + if (peer_b->offset + rest <= peer_b->size) { + chunk = rest; + } else { + /* wrap around ring buffer */ + chunk = peer_b->size - peer_b->offset; + } + assert(peer_b->offset + chunk <= peer_b->size); + + memcpy(buf, peer_b->buf + peer_b->offset, chunk); + + peer_b->len -= chunk; + /* If zero_copy_write_lock == 1 we must advance the offset even if buffer + * becomes empty, to make sure write_offset = (offset + len) % size + * does not change. */ + if (peer_b->len || peer_b->zero_copy_write_lock) { + peer_b->offset += chunk; + assert(peer_b->offset <= peer_b->size); + if (peer_b->offset == peer_b->size) { + peer_b->offset = 0; + } + buf += chunk; + } else { + /* buffer now empty, no need to advance "buf" */ + assert(chunk == rest); + peer_b->offset = 0; + } + rest -= chunk; + } while (rest); + + return size; +} + +static int bio_write(BIO *bio, const char *buf, int num_) { + size_t num = num_; + size_t rest; + struct bio_bio_st *b; + + BIO_clear_retry_flags(bio); + + if (!bio->init || buf == NULL || num == 0) { + return 0; + } + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + assert(b->buf != NULL); + + if (b->zero_copy_write_lock) { + return 0; + } + + b->request = 0; + if (b->closed) { + /* we already closed */ + OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE); + return -1; + } + + assert(b->len <= b->size); + + if (b->len == b->size) { + BIO_set_retry_write(bio); /* buffer is full */ + return -1; + } + + /* we can write */ + if (num > b->size - b->len) { + num = b->size - b->len; + } + + /* now write "num" bytes */ + rest = num; + + assert(rest > 0); + /* one or two iterations */ + do { + size_t write_offset; + size_t chunk; + + assert(b->len + rest <= b->size); + + write_offset = b->offset + b->len; + if (write_offset >= b->size) { + write_offset -= b->size; + } + /* b->buf[write_offset] is the first byte we can write to. */ + + if (write_offset + rest <= b->size) { + chunk = rest; + } else { + /* wrap around ring buffer */ + chunk = b->size - write_offset; + } + + memcpy(b->buf + write_offset, buf, chunk); + + b->len += chunk; + + assert(b->len <= b->size); + + rest -= chunk; + buf += chunk; + } while (rest); + + return num; +} + +static int bio_make_pair(BIO* bio1, BIO* bio2, + size_t writebuf1_len, uint8_t* ext_writebuf1, + size_t writebuf2_len, uint8_t* ext_writebuf2) { + struct bio_bio_st *b1, *b2; + + assert(bio1 != NULL); + assert(bio2 != NULL); + + b1 = bio1->ptr; + b2 = bio2->ptr; + + if (b1->peer != NULL || b2->peer != NULL) { + OPENSSL_PUT_ERROR(BIO, BIO_R_IN_USE); + return 0; + } + + assert(b1->buf_externally_allocated == 0); + assert(b2->buf_externally_allocated == 0); + + if (b1->buf == NULL) { + if (writebuf1_len) { + b1->size = writebuf1_len; + } + if (!ext_writebuf1) { + b1->buf_externally_allocated = 0; + b1->buf = OPENSSL_malloc(b1->size); + if (b1->buf == NULL) { + OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + b1->buf = ext_writebuf1; + b1->buf_externally_allocated = 1; + } + b1->len = 0; + b1->offset = 0; + } + + if (b2->buf == NULL) { + if (writebuf2_len) { + b2->size = writebuf2_len; + } + if (!ext_writebuf2) { + b2->buf_externally_allocated = 0; + b2->buf = OPENSSL_malloc(b2->size); + if (b2->buf == NULL) { + OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + b2->buf = ext_writebuf2; + b2->buf_externally_allocated = 1; + } + b2->len = 0; + b2->offset = 0; + } + + b1->peer = bio2; + b1->closed = 0; + b1->request = 0; + b1->zero_copy_read_lock = 0; + b1->zero_copy_write_lock = 0; + b2->peer = bio1; + b2->closed = 0; + b2->request = 0; + b2->zero_copy_read_lock = 0; + b2->zero_copy_write_lock = 0; + + bio1->init = 1; + bio2->init = 1; + + return 1; +} + +static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) { + long ret; + struct bio_bio_st *b = bio->ptr; + + assert(b != NULL); + + switch (cmd) { + /* specific CTRL codes */ + + case BIO_C_GET_WRITE_BUF_SIZE: + ret = (long)b->size; + break; + + case BIO_C_GET_WRITE_GUARANTEE: + /* How many bytes can the caller feed to the next write + * without having to keep any? */ + if (b->peer == NULL || b->closed) { + ret = 0; + } else { + ret = (long)b->size - b->len; + } + break; + + case BIO_C_GET_READ_REQUEST: + /* If the peer unsuccessfully tried to read, how many bytes + * were requested? (As with BIO_CTRL_PENDING, that number + * can usually be treated as boolean.) */ + ret = (long)b->request; + break; + + case BIO_C_RESET_READ_REQUEST: + /* Reset request. (Can be useful after read attempts + * at the other side that are meant to be non-blocking, + * e.g. when probing SSL_read to see if any data is + * available.) */ + b->request = 0; + ret = 1; + break; + + case BIO_C_SHUTDOWN_WR: + /* similar to shutdown(..., SHUT_WR) */ + b->closed = 1; + ret = 1; + break; + + /* standard CTRL codes follow */ + + case BIO_CTRL_GET_CLOSE: + ret = bio->shutdown; + break; + + case BIO_CTRL_SET_CLOSE: + bio->shutdown = (int)num; + ret = 1; + break; + + case BIO_CTRL_PENDING: + if (b->peer != NULL) { + struct bio_bio_st *peer_b = b->peer->ptr; + ret = (long)peer_b->len; + } else { + ret = 0; + } + break; + + case BIO_CTRL_WPENDING: + ret = 0; + if (b->buf != NULL) { + ret = (long)b->len; + } + break; + + case BIO_CTRL_FLUSH: + ret = 1; + break; + + case BIO_CTRL_EOF: { + BIO *other_bio = ptr; + + if (other_bio) { + struct bio_bio_st *other_b = other_bio->ptr; + assert(other_b != NULL); + ret = other_b->len == 0 && other_b->closed; + } else { + ret = 1; + } + } break; + + default: + ret = 0; + } + return ret; +} + +static int bio_puts(BIO *bio, const char *str) { + return bio_write(bio, str, strlen(str)); +} + +static const BIO_METHOD methods_biop = { + BIO_TYPE_BIO, "BIO pair", bio_write, bio_read, + bio_puts, NULL /* no bio_gets */, bio_ctrl, bio_new, + bio_free, NULL /* no bio_callback_ctrl */ +}; + +const BIO_METHOD *bio_s_bio(void) { return &methods_biop; } + +int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1, + BIO** bio2_p, size_t writebuf2) { + return BIO_new_bio_pair_external_buf(bio1_p, writebuf1, NULL, bio2_p, + writebuf2, NULL); +} + +int BIO_new_bio_pair_external_buf(BIO** bio1_p, size_t writebuf1_len, + uint8_t* ext_writebuf1, + BIO** bio2_p, size_t writebuf2_len, + uint8_t* ext_writebuf2) { + BIO *bio1 = NULL, *bio2 = NULL; + int ret = 0; + + /* External buffers must have sizes greater than 0. */ + if ((ext_writebuf1 && !writebuf1_len) || (ext_writebuf2 && !writebuf2_len)) { + goto err; + } + + bio1 = BIO_new(bio_s_bio()); + if (bio1 == NULL) { + goto err; + } + bio2 = BIO_new(bio_s_bio()); + if (bio2 == NULL) { + goto err; + } + + if (!bio_make_pair(bio1, bio2, writebuf1_len, ext_writebuf1, writebuf2_len, + ext_writebuf2)) { + goto err; + } + ret = 1; + +err: + if (ret == 0) { + BIO_free(bio1); + bio1 = NULL; + BIO_free(bio2); + bio2 = NULL; + } + + *bio1_p = bio1; + *bio2_p = bio2; + return ret; +} + +size_t BIO_ctrl_get_read_request(BIO *bio) { + return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL); +} + +size_t BIO_ctrl_get_write_guarantee(BIO *bio) { + return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL); +} + +int BIO_shutdown_wr(BIO *bio) { + return BIO_ctrl(bio, BIO_C_SHUTDOWN_WR, 0, NULL); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/printf.c b/TMessagesProj/jni/boringssl/crypto/bio/printf.c new file mode 100644 index 00000000..2f5ae4a3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/printf.c @@ -0,0 +1,115 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 201410L /* for snprintf, vprintf etc */ +#endif + +#include + +#include +#include +#include + +#include +#include + +int BIO_printf(BIO *bio, const char *format, ...) { + va_list args; + char buf[256], *out, out_malloced = 0; + int out_len, ret; + + va_start(args, format); + out_len = vsnprintf(buf, sizeof(buf), format, args); + va_end(args); + +#if defined(OPENSSL_WINDOWS) + /* On Windows, vsnprintf returns -1 rather than the requested length on + * truncation */ + if (out_len < 0) { + va_start(args, format); + out_len = _vscprintf(format, args); + va_end(args); + assert(out_len >= sizeof(buf)); + } +#endif + + if (out_len >= sizeof(buf)) { + const int requested_len = out_len; + /* The output was truncated. Note that vsnprintf's return value + * does not include a trailing NUL, but the buffer must be sized + * for it. */ + out = OPENSSL_malloc(requested_len + 1); + out_malloced = 1; + if (out == NULL) { + OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); + return -1; + } + va_start(args, format); + out_len = vsnprintf(out, requested_len + 1, format, args); + va_end(args); + assert(out_len == requested_len); + } else { + out = buf; + } + + ret = BIO_write(bio, out, out_len); + if (out_malloced) { + OPENSSL_free(out); + } + + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/socket.c b/TMessagesProj/jni/boringssl/crypto/bio/socket.c new file mode 100644 index 00000000..98f32a62 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/socket.c @@ -0,0 +1,195 @@ +/* crypto/bio/bss_sock.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#if !defined(OPENSSL_WINDOWS) +#include +#else +#pragma warning(push, 3) +#include +#pragma warning(pop) + +#pragma comment(lib, "Ws2_32.lib") +#endif + +#include "internal.h" + + +#if !defined(OPENSSL_WINDOWS) +static int closesocket(int sock) { + return close(sock); +} +#endif + +static int sock_new(BIO *bio) { + bio->init = 0; + bio->num = 0; + bio->ptr = NULL; + bio->flags = 0; + return 1; +} + +static int sock_free(BIO *bio) { + if (bio == NULL) { + return 0; + } + + if (bio->shutdown) { + if (bio->init) { + closesocket(bio->num); + } + bio->init = 0; + bio->flags = 0; + } + return 1; +} + +static int sock_read(BIO *b, char *out, int outl) { + int ret = 0; + + if (out == NULL) { + return 0; + } + + bio_clear_socket_error(); + ret = recv(b->num, out, outl, 0); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_read(b); + } + } + return ret; +} + +static int sock_write(BIO *b, const char *in, int inl) { + int ret; + + bio_clear_socket_error(); + ret = send(b->num, in, inl, 0); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (bio_fd_should_retry(ret)) { + BIO_set_retry_write(b); + } + } + return ret; +} + +static int sock_puts(BIO *bp, const char *str) { + return sock_write(bp, str, strlen(str)); +} + +static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) { + long ret = 1; + int *ip; + + switch (cmd) { + case BIO_C_SET_FD: + sock_free(b); + b->num = *((int *)ptr); + b->shutdown = (int)num; + b->init = 1; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) { + *ip = b->num; + } + ret = b->num; + } else { + ret = -1; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_FLUSH: + ret = 1; + break; + default: + ret = 0; + break; + } + return ret; +} + +static const BIO_METHOD methods_sockp = { + BIO_TYPE_SOCKET, "socket", sock_write, sock_read, sock_puts, + NULL /* gets, */, sock_ctrl, sock_new, sock_free, NULL, +}; + +const BIO_METHOD *BIO_s_socket(void) { return &methods_sockp; } + +BIO *BIO_new_socket(int fd, int close_flag) { + BIO *ret; + + ret = BIO_new(BIO_s_socket()); + if (ret == NULL) { + return NULL; + } + BIO_set_fd(ret, fd, close_flag); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bio/socket_helper.c b/TMessagesProj/jni/boringssl/crypto/bio/socket_helper.c new file mode 100644 index 00000000..01f635eb --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bio/socket_helper.c @@ -0,0 +1,113 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#undef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 200112L + +#include +#include + +#include +#include +#include + +#if !defined(OPENSSL_WINDOWS) +#include +#include +#else +#pragma warning(push, 3) +#include +#include +#pragma warning(pop) +#endif + +#include "internal.h" + + +int bio_ip_and_port_to_socket_and_addr(int *out_sock, + struct sockaddr_storage *out_addr, + socklen_t *out_addr_length, + const char *hostname, + const char *port_str) { + struct addrinfo hint, *result, *cur; + int ret; + + *out_sock = -1; + + memset(&hint, 0, sizeof(hint)); + hint.ai_family = AF_UNSPEC; + hint.ai_socktype = SOCK_STREAM; + + ret = getaddrinfo(hostname, port_str, &hint, &result); + if (ret != 0) { + OPENSSL_PUT_ERROR(SYS, 0); + ERR_add_error_data(1, gai_strerror(ret)); + return 0; + } + + ret = 0; + + for (cur = result; cur; cur = cur->ai_next) { + if (cur->ai_addrlen > sizeof(struct sockaddr_storage)) { + continue; + } + memset(out_addr, 0, sizeof(struct sockaddr_storage)); + memcpy(out_addr, cur->ai_addr, cur->ai_addrlen); + *out_addr_length = cur->ai_addrlen; + + *out_sock = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol); + if (*out_sock < 0) { + OPENSSL_PUT_SYSTEM_ERROR(socket); + goto out; + } + + ret = 1; + break; + } + +out: + freeaddrinfo(result); + return ret; +} + +int bio_socket_nbio(int sock, int on) { +#if defined(OPENSSL_WINDOWS) + u_long arg = on; + + return 0 == ioctlsocket(sock, FIONBIO, &arg); +#else + int flags = fcntl(sock, F_GETFL, 0); + if (flags < 0) { + return 0; + } + if (!on) { + flags &= ~O_NONBLOCK; + } else { + flags |= O_NONBLOCK; + } + return fcntl(sock, F_SETFL, flags) == 0; +#endif +} + +void bio_clear_socket_error(void) {} + +int bio_sock_error(int sock) { + int error; + socklen_t error_size = sizeof(error); + + if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&error, &error_size) < 0) { + return 1; + } + return error; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/bn/CMakeLists.txt new file mode 100644 index 00000000..af3bcb35 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/CMakeLists.txt @@ -0,0 +1,68 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "x86_64") + set( + BN_ARCH_SOURCES + + x86_64-mont.${ASM_EXT} + x86_64-mont5.${ASM_EXT} + rsaz-x86_64.${ASM_EXT} + rsaz-avx2.${ASM_EXT} + + rsaz_exp.c + ) +endif() + +if (${ARCH} STREQUAL "x86") + set( + BN_ARCH_SOURCES + + bn-586.${ASM_EXT} + co-586.${ASM_EXT} + x86-mont.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "arm") + set( + BN_ARCH_SOURCES + + armv4-mont.${ASM_EXT} + ) +endif() + +add_library( + bn + + OBJECT + + add.c + asm/x86_64-gcc.c + bn.c + bn_asn1.c + cmp.c + convert.c + ctx.c + div.c + exponentiation.c + generic.c + gcd.c + kronecker.c + montgomery.c + mul.c + prime.c + random.c + shift.c + sqrt.c + + ${BN_ARCH_SOURCES} +) + +perlasm(x86_64-mont.${ASM_EXT} asm/x86_64-mont.pl) +perlasm(x86_64-mont5.${ASM_EXT} asm/x86_64-mont5.pl) +perlasm(rsaz-x86_64.${ASM_EXT} asm/rsaz-x86_64.pl) +perlasm(rsaz-avx2.${ASM_EXT} asm/rsaz-avx2.pl) +perlasm(bn-586.${ASM_EXT} asm/bn-586.pl) +perlasm(co-586.${ASM_EXT} asm/co-586.pl) +perlasm(x86-mont.${ASM_EXT} asm/x86-mont.pl) +perlasm(armv4-mont.${ASM_EXT} asm/armv4-mont.pl) diff --git a/TMessagesProj/jni/boringssl/crypto/bn/add.c b/TMessagesProj/jni/boringssl/crypto/bn/add.c new file mode 100644 index 00000000..a043d838 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/add.c @@ -0,0 +1,394 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include "internal.h" + + +int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { + const BIGNUM *tmp; + int a_neg = a->neg, ret; + + /* a + b a+b + * a + -b a-b + * -a + b b-a + * -a + -b -(a+b) + */ + if (a_neg ^ b->neg) { + /* only one is negative */ + if (a_neg) { + tmp = a; + a = b; + b = tmp; + } + + /* we are now a - b */ + if (BN_ucmp(a, b) < 0) { + if (!BN_usub(r, b, a)) { + return 0; + } + r->neg = 1; + } else { + if (!BN_usub(r, a, b)) { + return 0; + } + r->neg = 0; + } + return 1; + } + + ret = BN_uadd(r, a, b); + r->neg = a_neg; + return ret; +} + +int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { + int max, min, dif; + BN_ULONG *ap, *bp, *rp, carry, t1, t2; + const BIGNUM *tmp; + + if (a->top < b->top) { + tmp = a; + a = b; + b = tmp; + } + max = a->top; + min = b->top; + dif = max - min; + + if (bn_wexpand(r, max + 1) == NULL) { + return 0; + } + + r->top = max; + + ap = a->d; + bp = b->d; + rp = r->d; + + carry = bn_add_words(rp, ap, bp, min); + rp += min; + ap += min; + bp += min; + + if (carry) { + while (dif) { + dif--; + t1 = *(ap++); + t2 = (t1 + 1) & BN_MASK2; + *(rp++) = t2; + if (t2) { + carry = 0; + break; + } + } + if (carry) { + /* carry != 0 => dif == 0 */ + *rp = 1; + r->top++; + } + } + + if (dif && rp != ap) { + while (dif--) { + /* copy remaining words if ap != rp */ + *(rp++) = *(ap++); + } + } + + r->neg = 0; + return 1; +} + +int BN_add_word(BIGNUM *a, BN_ULONG w) { + BN_ULONG l; + int i; + + w &= BN_MASK2; + + /* degenerate case: w is zero */ + if (!w) { + return 1; + } + + /* degenerate case: a is zero */ + if (BN_is_zero(a)) { + return BN_set_word(a, w); + } + + /* handle 'a' when negative */ + if (a->neg) { + a->neg = 0; + i = BN_sub_word(a, w); + if (!BN_is_zero(a)) { + a->neg = !(a->neg); + } + return i; + } + + for (i = 0; w != 0 && i < a->top; i++) { + a->d[i] = l = (a->d[i] + w) & BN_MASK2; + w = (w > l) ? 1 : 0; + } + + if (w && i == a->top) { + if (bn_wexpand(a, a->top + 1) == NULL) { + return 0; + } + a->top++; + a->d[i] = w; + } + + return 1; +} + +int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { + int max; + int add = 0, neg = 0; + const BIGNUM *tmp; + + /* a - b a-b + * a - -b a+b + * -a - b -(a+b) + * -a - -b b-a + */ + if (a->neg) { + if (b->neg) { + tmp = a; + a = b; + b = tmp; + } else { + add = 1; + neg = 1; + } + } else { + if (b->neg) { + add = 1; + neg = 0; + } + } + + if (add) { + if (!BN_uadd(r, a, b)) { + return 0; + } + + r->neg = neg; + return 1; + } + + /* We are actually doing a - b :-) */ + + max = (a->top > b->top) ? a->top : b->top; + if (bn_wexpand(r, max) == NULL) { + return 0; + } + + if (BN_ucmp(a, b) < 0) { + if (!BN_usub(r, b, a)) { + return 0; + } + r->neg = 1; + } else { + if (!BN_usub(r, a, b)) { + return 0; + } + r->neg = 0; + } + + return 1; +} + +int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { + int max, min, dif; + register BN_ULONG t1, t2, *ap, *bp, *rp; + int i, carry; + + max = a->top; + min = b->top; + dif = max - min; + + if (dif < 0) /* hmm... should not be happening */ + { + OPENSSL_PUT_ERROR(BN, BN_R_ARG2_LT_ARG3); + return 0; + } + + if (bn_wexpand(r, max) == NULL) { + return 0; + } + + ap = a->d; + bp = b->d; + rp = r->d; + + carry = 0; + for (i = min; i != 0; i--) { + t1 = *(ap++); + t2 = *(bp++); + if (carry) { + carry = (t1 <= t2); + t1 = (t1 - t2 - 1) & BN_MASK2; + } else { + carry = (t1 < t2); + t1 = (t1 - t2) & BN_MASK2; + } + *(rp++) = t1 & BN_MASK2; + } + + if (carry) /* subtracted */ + { + if (!dif) { + /* error: a < b */ + return 0; + } + + while (dif) { + dif--; + t1 = *(ap++); + t2 = (t1 - 1) & BN_MASK2; + *(rp++) = t2; + if (t1) { + break; + } + } + } + + if (rp != ap) { + for (;;) { + if (!dif--) { + break; + } + rp[0] = ap[0]; + if (!dif--) { + break; + } + rp[1] = ap[1]; + if (!dif--) { + break; + } + rp[2] = ap[2]; + if (!dif--) { + break; + } + rp[3] = ap[3]; + rp += 4; + ap += 4; + } + } + + r->top = max; + r->neg = 0; + bn_correct_top(r); + + return 1; +} + +int BN_sub_word(BIGNUM *a, BN_ULONG w) { + int i; + + w &= BN_MASK2; + + /* degenerate case: w is zero */ + if (!w) { + return 1; + } + + /* degenerate case: a is zero */ + if (BN_is_zero(a)) { + i = BN_set_word(a, w); + if (i != 0) { + BN_set_negative(a, 1); + } + return i; + } + + /* handle 'a' when negative */ + if (a->neg) { + a->neg = 0; + i = BN_add_word(a, w); + a->neg = 1; + return i; + } + + if ((a->top == 1) && (a->d[0] < w)) { + a->d[0] = w - a->d[0]; + a->neg = 1; + return 1; + } + + i = 0; + for (;;) { + if (a->d[i] >= w) { + a->d[i] -= w; + break; + } else { + a->d[i] = (a->d[i] - w) & BN_MASK2; + i++; + w = 1; + } + } + + if ((a->d[i] == 0) && (i == (a->top - 1))) { + a->top--; + } + + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/armv4-mont.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/armv4-mont.pl new file mode 100644 index 00000000..0f1b6a90 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/armv4-mont.pl @@ -0,0 +1,694 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# January 2007. + +# Montgomery multiplication for ARMv4. +# +# Performance improvement naturally varies among CPU implementations +# and compilers. The code was observed to provide +65-35% improvement +# [depending on key length, less for longer keys] on ARM920T, and +# +115-80% on Intel IXP425. This is compared to pre-bn_mul_mont code +# base and compiler generated code with in-lined umull and even umlal +# instructions. The latter means that this code didn't really have an +# "advantage" of utilizing some "secret" instruction. +# +# The code is interoperable with Thumb ISA and is rather compact, less +# than 1/2KB. Windows CE port would be trivial, as it's exclusively +# about decorations, ABI and instruction syntax are identical. + +# November 2013 +# +# Add NEON code path, which handles lengths divisible by 8. RSA/DSA +# performance improvement on Cortex-A8 is ~45-100% depending on key +# length, more for longer keys. On Cortex-A15 the span is ~10-105%. +# On Snapdragon S4 improvement was measured to vary from ~70% to +# incredible ~380%, yes, 4.8x faster, for RSA4096 sign. But this is +# rather because original integer-only code seems to perform +# suboptimally on S4. Situation on Cortex-A9 is unfortunately +# different. It's being looked into, but the trouble is that +# performance for vectors longer than 256 bits is actually couple +# of percent worse than for integer-only code. The code is chosen +# for execution on all NEON-capable processors, because gain on +# others outweighs the marginal loss on Cortex-A9. + +$flavour = shift; +if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } +else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} } + +if ($flavour && $flavour ne "void") { + $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; + ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or + ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or + die "can't locate arm-xlate.pl"; + + open STDOUT,"| \"$^X\" $xlate $flavour $output"; +} else { + open STDOUT,">$output"; +} + +$num="r0"; # starts as num argument, but holds &tp[num-1] +$ap="r1"; +$bp="r2"; $bi="r2"; $rp="r2"; +$np="r3"; +$tp="r4"; +$aj="r5"; +$nj="r6"; +$tj="r7"; +$n0="r8"; +########### # r9 is reserved by ELF as platform specific, e.g. TLS pointer +$alo="r10"; # sl, gcc uses it to keep @GOT +$ahi="r11"; # fp +$nlo="r12"; # ip +########### # r13 is stack pointer +$nhi="r14"; # lr +########### # r15 is program counter + +#### argument block layout relative to &tp[num-1], a.k.a. $num +$_rp="$num,#12*4"; +# ap permanently resides in r1 +$_bp="$num,#13*4"; +# np permanently resides in r3 +$_n0="$num,#14*4"; +$_num="$num,#15*4"; $_bpend=$_num; + +$code=<<___; +#include "arm_arch.h" + +.text +.code 32 + +#if __ARM_MAX_ARCH__>=7 +.align 5 +.LOPENSSL_armcap: +.word OPENSSL_armcap_P-.Lbn_mul_mont +#endif + +.global bn_mul_mont +.hidden bn_mul_mont +.type bn_mul_mont,%function + +.align 5 +bn_mul_mont: +.Lbn_mul_mont: + ldr ip,[sp,#4] @ load num + stmdb sp!,{r0,r2} @ sp points at argument block +#if __ARM_MAX_ARCH__>=7 + tst ip,#7 + bne .Lialu + adr r0,bn_mul_mont + ldr r2,.LOPENSSL_armcap + ldr r0,[r0,r2] +#ifdef __APPLE__ + ldr r0,[r0] +#endif + tst r0,#1 @ NEON available? + ldmia sp, {r0,r2} + beq .Lialu + add sp,sp,#8 + b bn_mul8x_mont_neon +.align 4 +.Lialu: +#endif + cmp ip,#2 + mov $num,ip @ load num + movlt r0,#0 + addlt sp,sp,#2*4 + blt .Labrt + + stmdb sp!,{r4-r12,lr} @ save 10 registers + + mov $num,$num,lsl#2 @ rescale $num for byte count + sub sp,sp,$num @ alloca(4*num) + sub sp,sp,#4 @ +extra dword + sub $num,$num,#4 @ "num=num-1" + add $tp,$bp,$num @ &bp[num-1] + + add $num,sp,$num @ $num to point at &tp[num-1] + ldr $n0,[$_n0] @ &n0 + ldr $bi,[$bp] @ bp[0] + ldr $aj,[$ap],#4 @ ap[0],ap++ + ldr $nj,[$np],#4 @ np[0],np++ + ldr $n0,[$n0] @ *n0 + str $tp,[$_bpend] @ save &bp[num] + + umull $alo,$ahi,$aj,$bi @ ap[0]*bp[0] + str $n0,[$_n0] @ save n0 value + mul $n0,$alo,$n0 @ "tp[0]"*n0 + mov $nlo,#0 + umlal $alo,$nlo,$nj,$n0 @ np[0]*n0+"t[0]" + mov $tp,sp + +.L1st: + ldr $aj,[$ap],#4 @ ap[j],ap++ + mov $alo,$ahi + ldr $nj,[$np],#4 @ np[j],np++ + mov $ahi,#0 + umlal $alo,$ahi,$aj,$bi @ ap[j]*bp[0] + mov $nhi,#0 + umlal $nlo,$nhi,$nj,$n0 @ np[j]*n0 + adds $nlo,$nlo,$alo + str $nlo,[$tp],#4 @ tp[j-1]=,tp++ + adc $nlo,$nhi,#0 + cmp $tp,$num + bne .L1st + + adds $nlo,$nlo,$ahi + ldr $tp,[$_bp] @ restore bp + mov $nhi,#0 + ldr $n0,[$_n0] @ restore n0 + adc $nhi,$nhi,#0 + str $nlo,[$num] @ tp[num-1]= + str $nhi,[$num,#4] @ tp[num]= + +.Louter: + sub $tj,$num,sp @ "original" $num-1 value + sub $ap,$ap,$tj @ "rewind" ap to &ap[1] + ldr $bi,[$tp,#4]! @ *(++bp) + sub $np,$np,$tj @ "rewind" np to &np[1] + ldr $aj,[$ap,#-4] @ ap[0] + ldr $alo,[sp] @ tp[0] + ldr $nj,[$np,#-4] @ np[0] + ldr $tj,[sp,#4] @ tp[1] + + mov $ahi,#0 + umlal $alo,$ahi,$aj,$bi @ ap[0]*bp[i]+tp[0] + str $tp,[$_bp] @ save bp + mul $n0,$alo,$n0 + mov $nlo,#0 + umlal $alo,$nlo,$nj,$n0 @ np[0]*n0+"tp[0]" + mov $tp,sp + +.Linner: + ldr $aj,[$ap],#4 @ ap[j],ap++ + adds $alo,$ahi,$tj @ +=tp[j] + ldr $nj,[$np],#4 @ np[j],np++ + mov $ahi,#0 + umlal $alo,$ahi,$aj,$bi @ ap[j]*bp[i] + mov $nhi,#0 + umlal $nlo,$nhi,$nj,$n0 @ np[j]*n0 + adc $ahi,$ahi,#0 + ldr $tj,[$tp,#8] @ tp[j+1] + adds $nlo,$nlo,$alo + str $nlo,[$tp],#4 @ tp[j-1]=,tp++ + adc $nlo,$nhi,#0 + cmp $tp,$num + bne .Linner + + adds $nlo,$nlo,$ahi + mov $nhi,#0 + ldr $tp,[$_bp] @ restore bp + adc $nhi,$nhi,#0 + ldr $n0,[$_n0] @ restore n0 + adds $nlo,$nlo,$tj + ldr $tj,[$_bpend] @ restore &bp[num] + adc $nhi,$nhi,#0 + str $nlo,[$num] @ tp[num-1]= + str $nhi,[$num,#4] @ tp[num]= + + cmp $tp,$tj + bne .Louter + + ldr $rp,[$_rp] @ pull rp + add $num,$num,#4 @ $num to point at &tp[num] + sub $aj,$num,sp @ "original" num value + mov $tp,sp @ "rewind" $tp + mov $ap,$tp @ "borrow" $ap + sub $np,$np,$aj @ "rewind" $np to &np[0] + + subs $tj,$tj,$tj @ "clear" carry flag +.Lsub: ldr $tj,[$tp],#4 + ldr $nj,[$np],#4 + sbcs $tj,$tj,$nj @ tp[j]-np[j] + str $tj,[$rp],#4 @ rp[j]= + teq $tp,$num @ preserve carry + bne .Lsub + sbcs $nhi,$nhi,#0 @ upmost carry + mov $tp,sp @ "rewind" $tp + sub $rp,$rp,$aj @ "rewind" $rp + + and $ap,$tp,$nhi + bic $np,$rp,$nhi + orr $ap,$ap,$np @ ap=borrow?tp:rp + +.Lcopy: ldr $tj,[$ap],#4 @ copy or in-place refresh + str sp,[$tp],#4 @ zap tp + str $tj,[$rp],#4 + cmp $tp,$num + bne .Lcopy + + add sp,$num,#4 @ skip over tp[num+1] + ldmia sp!,{r4-r12,lr} @ restore registers + add sp,sp,#2*4 @ skip over {r0,r2} + mov r0,#1 +.Labrt: +#if __ARM_ARCH__>=5 + ret @ bx lr +#else + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size bn_mul_mont,.-bn_mul_mont +___ +{ +sub Dlo() { shift=~m|q([1]?[0-9])|?"d".($1*2):""; } +sub Dhi() { shift=~m|q([1]?[0-9])|?"d".($1*2+1):""; } + +my ($A0,$A1,$A2,$A3)=map("d$_",(0..3)); +my ($N0,$N1,$N2,$N3)=map("d$_",(4..7)); +my ($Z,$Temp)=("q4","q5"); +my ($A0xB,$A1xB,$A2xB,$A3xB,$A4xB,$A5xB,$A6xB,$A7xB)=map("q$_",(6..13)); +my ($Bi,$Ni,$M0)=map("d$_",(28..31)); +my $zero=&Dlo($Z); +my $temp=&Dlo($Temp); + +my ($rptr,$aptr,$bptr,$nptr,$n0,$num)=map("r$_",(0..5)); +my ($tinptr,$toutptr,$inner,$outer)=map("r$_",(6..9)); + +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.type bn_mul8x_mont_neon,%function +.align 5 +bn_mul8x_mont_neon: + mov ip,sp + stmdb sp!,{r4-r11} + vstmdb sp!,{d8-d15} @ ABI specification says so + ldmia ip,{r4-r5} @ load rest of parameter block + + sub $toutptr,sp,#16 + vld1.32 {${Bi}[0]}, [$bptr,:32]! + sub $toutptr,$toutptr,$num,lsl#4 + vld1.32 {$A0-$A3}, [$aptr]! @ can't specify :32 :-( + and $toutptr,$toutptr,#-64 + vld1.32 {${M0}[0]}, [$n0,:32] + mov sp,$toutptr @ alloca + veor $zero,$zero,$zero + subs $inner,$num,#8 + vzip.16 $Bi,$zero + + vmull.u32 $A0xB,$Bi,${A0}[0] + vmull.u32 $A1xB,$Bi,${A0}[1] + vmull.u32 $A2xB,$Bi,${A1}[0] + vshl.i64 $temp,`&Dhi("$A0xB")`,#16 + vmull.u32 $A3xB,$Bi,${A1}[1] + + vadd.u64 $temp,$temp,`&Dlo("$A0xB")` + veor $zero,$zero,$zero + vmul.u32 $Ni,$temp,$M0 + + vmull.u32 $A4xB,$Bi,${A2}[0] + vld1.32 {$N0-$N3}, [$nptr]! + vmull.u32 $A5xB,$Bi,${A2}[1] + vmull.u32 $A6xB,$Bi,${A3}[0] + vzip.16 $Ni,$zero + vmull.u32 $A7xB,$Bi,${A3}[1] + + bne .LNEON_1st + + @ special case for num=8, everything is in register bank... + + vmlal.u32 $A0xB,$Ni,${N0}[0] + sub $outer,$num,#1 + vmlal.u32 $A1xB,$Ni,${N0}[1] + vmlal.u32 $A2xB,$Ni,${N1}[0] + vmlal.u32 $A3xB,$Ni,${N1}[1] + + vmlal.u32 $A4xB,$Ni,${N2}[0] + vmov $Temp,$A0xB + vmlal.u32 $A5xB,$Ni,${N2}[1] + vmov $A0xB,$A1xB + vmlal.u32 $A6xB,$Ni,${N3}[0] + vmov $A1xB,$A2xB + vmlal.u32 $A7xB,$Ni,${N3}[1] + vmov $A2xB,$A3xB + vmov $A3xB,$A4xB + vshr.u64 $temp,$temp,#16 + vmov $A4xB,$A5xB + vmov $A5xB,$A6xB + vadd.u64 $temp,$temp,`&Dhi("$Temp")` + vmov $A6xB,$A7xB + veor $A7xB,$A7xB + vshr.u64 $temp,$temp,#16 + + b .LNEON_outer8 + +.align 4 +.LNEON_outer8: + vld1.32 {${Bi}[0]}, [$bptr,:32]! + veor $zero,$zero,$zero + vzip.16 $Bi,$zero + vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp + + vmlal.u32 $A0xB,$Bi,${A0}[0] + vmlal.u32 $A1xB,$Bi,${A0}[1] + vmlal.u32 $A2xB,$Bi,${A1}[0] + vshl.i64 $temp,`&Dhi("$A0xB")`,#16 + vmlal.u32 $A3xB,$Bi,${A1}[1] + + vadd.u64 $temp,$temp,`&Dlo("$A0xB")` + veor $zero,$zero,$zero + subs $outer,$outer,#1 + vmul.u32 $Ni,$temp,$M0 + + vmlal.u32 $A4xB,$Bi,${A2}[0] + vmlal.u32 $A5xB,$Bi,${A2}[1] + vmlal.u32 $A6xB,$Bi,${A3}[0] + vzip.16 $Ni,$zero + vmlal.u32 $A7xB,$Bi,${A3}[1] + + vmlal.u32 $A0xB,$Ni,${N0}[0] + vmlal.u32 $A1xB,$Ni,${N0}[1] + vmlal.u32 $A2xB,$Ni,${N1}[0] + vmlal.u32 $A3xB,$Ni,${N1}[1] + + vmlal.u32 $A4xB,$Ni,${N2}[0] + vmov $Temp,$A0xB + vmlal.u32 $A5xB,$Ni,${N2}[1] + vmov $A0xB,$A1xB + vmlal.u32 $A6xB,$Ni,${N3}[0] + vmov $A1xB,$A2xB + vmlal.u32 $A7xB,$Ni,${N3}[1] + vmov $A2xB,$A3xB + vmov $A3xB,$A4xB + vshr.u64 $temp,$temp,#16 + vmov $A4xB,$A5xB + vmov $A5xB,$A6xB + vadd.u64 $temp,$temp,`&Dhi("$Temp")` + vmov $A6xB,$A7xB + veor $A7xB,$A7xB + vshr.u64 $temp,$temp,#16 + + bne .LNEON_outer8 + + vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp + mov $toutptr,sp + vshr.u64 $temp,`&Dlo("$A0xB")`,#16 + mov $inner,$num + vadd.u64 `&Dhi("$A0xB")`,`&Dhi("$A0xB")`,$temp + add $tinptr,sp,#16 + vshr.u64 $temp,`&Dhi("$A0xB")`,#16 + vzip.16 `&Dlo("$A0xB")`,`&Dhi("$A0xB")` + + b .LNEON_tail2 + +.align 4 +.LNEON_1st: + vmlal.u32 $A0xB,$Ni,${N0}[0] + vld1.32 {$A0-$A3}, [$aptr]! + vmlal.u32 $A1xB,$Ni,${N0}[1] + subs $inner,$inner,#8 + vmlal.u32 $A2xB,$Ni,${N1}[0] + vmlal.u32 $A3xB,$Ni,${N1}[1] + + vmlal.u32 $A4xB,$Ni,${N2}[0] + vld1.32 {$N0-$N1}, [$nptr]! + vmlal.u32 $A5xB,$Ni,${N2}[1] + vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]! + vmlal.u32 $A6xB,$Ni,${N3}[0] + vmlal.u32 $A7xB,$Ni,${N3}[1] + vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]! + + vmull.u32 $A0xB,$Bi,${A0}[0] + vld1.32 {$N2-$N3}, [$nptr]! + vmull.u32 $A1xB,$Bi,${A0}[1] + vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]! + vmull.u32 $A2xB,$Bi,${A1}[0] + vmull.u32 $A3xB,$Bi,${A1}[1] + vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]! + + vmull.u32 $A4xB,$Bi,${A2}[0] + vmull.u32 $A5xB,$Bi,${A2}[1] + vmull.u32 $A6xB,$Bi,${A3}[0] + vmull.u32 $A7xB,$Bi,${A3}[1] + + bne .LNEON_1st + + vmlal.u32 $A0xB,$Ni,${N0}[0] + add $tinptr,sp,#16 + vmlal.u32 $A1xB,$Ni,${N0}[1] + sub $aptr,$aptr,$num,lsl#2 @ rewind $aptr + vmlal.u32 $A2xB,$Ni,${N1}[0] + vld1.64 {$Temp}, [sp,:128] + vmlal.u32 $A3xB,$Ni,${N1}[1] + sub $outer,$num,#1 + + vmlal.u32 $A4xB,$Ni,${N2}[0] + vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]! + vmlal.u32 $A5xB,$Ni,${N2}[1] + vshr.u64 $temp,$temp,#16 + vld1.64 {$A0xB}, [$tinptr, :128]! + vmlal.u32 $A6xB,$Ni,${N3}[0] + vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]! + vmlal.u32 $A7xB,$Ni,${N3}[1] + + vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]! + vadd.u64 $temp,$temp,`&Dhi("$Temp")` + veor $Z,$Z,$Z + vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]! + vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]! + vst1.64 {$Z}, [$toutptr,:128] + vshr.u64 $temp,$temp,#16 + + b .LNEON_outer + +.align 4 +.LNEON_outer: + vld1.32 {${Bi}[0]}, [$bptr,:32]! + sub $nptr,$nptr,$num,lsl#2 @ rewind $nptr + vld1.32 {$A0-$A3}, [$aptr]! + veor $zero,$zero,$zero + mov $toutptr,sp + vzip.16 $Bi,$zero + sub $inner,$num,#8 + vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp + + vmlal.u32 $A0xB,$Bi,${A0}[0] + vld1.64 {$A3xB-$A4xB},[$tinptr,:256]! + vmlal.u32 $A1xB,$Bi,${A0}[1] + vmlal.u32 $A2xB,$Bi,${A1}[0] + vld1.64 {$A5xB-$A6xB},[$tinptr,:256]! + vmlal.u32 $A3xB,$Bi,${A1}[1] + + vshl.i64 $temp,`&Dhi("$A0xB")`,#16 + veor $zero,$zero,$zero + vadd.u64 $temp,$temp,`&Dlo("$A0xB")` + vld1.64 {$A7xB},[$tinptr,:128]! + vmul.u32 $Ni,$temp,$M0 + + vmlal.u32 $A4xB,$Bi,${A2}[0] + vld1.32 {$N0-$N3}, [$nptr]! + vmlal.u32 $A5xB,$Bi,${A2}[1] + vmlal.u32 $A6xB,$Bi,${A3}[0] + vzip.16 $Ni,$zero + vmlal.u32 $A7xB,$Bi,${A3}[1] + +.LNEON_inner: + vmlal.u32 $A0xB,$Ni,${N0}[0] + vld1.32 {$A0-$A3}, [$aptr]! + vmlal.u32 $A1xB,$Ni,${N0}[1] + subs $inner,$inner,#8 + vmlal.u32 $A2xB,$Ni,${N1}[0] + vmlal.u32 $A3xB,$Ni,${N1}[1] + vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]! + + vmlal.u32 $A4xB,$Ni,${N2}[0] + vld1.64 {$A0xB}, [$tinptr, :128]! + vmlal.u32 $A5xB,$Ni,${N2}[1] + vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]! + vmlal.u32 $A6xB,$Ni,${N3}[0] + vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]! + vmlal.u32 $A7xB,$Ni,${N3}[1] + vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]! + + vmlal.u32 $A0xB,$Bi,${A0}[0] + vld1.64 {$A3xB-$A4xB}, [$tinptr, :256]! + vmlal.u32 $A1xB,$Bi,${A0}[1] + vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]! + vmlal.u32 $A2xB,$Bi,${A1}[0] + vld1.64 {$A5xB-$A6xB}, [$tinptr, :256]! + vmlal.u32 $A3xB,$Bi,${A1}[1] + vld1.32 {$N0-$N3}, [$nptr]! + + vmlal.u32 $A4xB,$Bi,${A2}[0] + vld1.64 {$A7xB}, [$tinptr, :128]! + vmlal.u32 $A5xB,$Bi,${A2}[1] + vmlal.u32 $A6xB,$Bi,${A3}[0] + vmlal.u32 $A7xB,$Bi,${A3}[1] + + bne .LNEON_inner + + vmlal.u32 $A0xB,$Ni,${N0}[0] + add $tinptr,sp,#16 + vmlal.u32 $A1xB,$Ni,${N0}[1] + sub $aptr,$aptr,$num,lsl#2 @ rewind $aptr + vmlal.u32 $A2xB,$Ni,${N1}[0] + vld1.64 {$Temp}, [sp,:128] + vmlal.u32 $A3xB,$Ni,${N1}[1] + subs $outer,$outer,#1 + + vmlal.u32 $A4xB,$Ni,${N2}[0] + vst1.64 {$A0xB-$A1xB}, [$toutptr,:256]! + vmlal.u32 $A5xB,$Ni,${N2}[1] + vld1.64 {$A0xB}, [$tinptr, :128]! + vshr.u64 $temp,$temp,#16 + vst1.64 {$A2xB-$A3xB}, [$toutptr,:256]! + vmlal.u32 $A6xB,$Ni,${N3}[0] + vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]! + vmlal.u32 $A7xB,$Ni,${N3}[1] + + vst1.64 {$A4xB-$A5xB}, [$toutptr,:256]! + vadd.u64 $temp,$temp,`&Dhi("$Temp")` + vst1.64 {$A6xB-$A7xB}, [$toutptr,:256]! + vshr.u64 $temp,$temp,#16 + + bne .LNEON_outer + + mov $toutptr,sp + mov $inner,$num + +.LNEON_tail: + vadd.u64 `&Dlo("$A0xB")`,`&Dlo("$A0xB")`,$temp + vld1.64 {$A3xB-$A4xB}, [$tinptr, :256]! + vshr.u64 $temp,`&Dlo("$A0xB")`,#16 + vadd.u64 `&Dhi("$A0xB")`,`&Dhi("$A0xB")`,$temp + vld1.64 {$A5xB-$A6xB}, [$tinptr, :256]! + vshr.u64 $temp,`&Dhi("$A0xB")`,#16 + vld1.64 {$A7xB}, [$tinptr, :128]! + vzip.16 `&Dlo("$A0xB")`,`&Dhi("$A0xB")` + +.LNEON_tail2: + vadd.u64 `&Dlo("$A1xB")`,`&Dlo("$A1xB")`,$temp + vst1.32 {`&Dlo("$A0xB")`[0]}, [$toutptr, :32]! + vshr.u64 $temp,`&Dlo("$A1xB")`,#16 + vadd.u64 `&Dhi("$A1xB")`,`&Dhi("$A1xB")`,$temp + vshr.u64 $temp,`&Dhi("$A1xB")`,#16 + vzip.16 `&Dlo("$A1xB")`,`&Dhi("$A1xB")` + + vadd.u64 `&Dlo("$A2xB")`,`&Dlo("$A2xB")`,$temp + vst1.32 {`&Dlo("$A1xB")`[0]}, [$toutptr, :32]! + vshr.u64 $temp,`&Dlo("$A2xB")`,#16 + vadd.u64 `&Dhi("$A2xB")`,`&Dhi("$A2xB")`,$temp + vshr.u64 $temp,`&Dhi("$A2xB")`,#16 + vzip.16 `&Dlo("$A2xB")`,`&Dhi("$A2xB")` + + vadd.u64 `&Dlo("$A3xB")`,`&Dlo("$A3xB")`,$temp + vst1.32 {`&Dlo("$A2xB")`[0]}, [$toutptr, :32]! + vshr.u64 $temp,`&Dlo("$A3xB")`,#16 + vadd.u64 `&Dhi("$A3xB")`,`&Dhi("$A3xB")`,$temp + vshr.u64 $temp,`&Dhi("$A3xB")`,#16 + vzip.16 `&Dlo("$A3xB")`,`&Dhi("$A3xB")` + + vadd.u64 `&Dlo("$A4xB")`,`&Dlo("$A4xB")`,$temp + vst1.32 {`&Dlo("$A3xB")`[0]}, [$toutptr, :32]! + vshr.u64 $temp,`&Dlo("$A4xB")`,#16 + vadd.u64 `&Dhi("$A4xB")`,`&Dhi("$A4xB")`,$temp + vshr.u64 $temp,`&Dhi("$A4xB")`,#16 + vzip.16 `&Dlo("$A4xB")`,`&Dhi("$A4xB")` + + vadd.u64 `&Dlo("$A5xB")`,`&Dlo("$A5xB")`,$temp + vst1.32 {`&Dlo("$A4xB")`[0]}, [$toutptr, :32]! + vshr.u64 $temp,`&Dlo("$A5xB")`,#16 + vadd.u64 `&Dhi("$A5xB")`,`&Dhi("$A5xB")`,$temp + vshr.u64 $temp,`&Dhi("$A5xB")`,#16 + vzip.16 `&Dlo("$A5xB")`,`&Dhi("$A5xB")` + + vadd.u64 `&Dlo("$A6xB")`,`&Dlo("$A6xB")`,$temp + vst1.32 {`&Dlo("$A5xB")`[0]}, [$toutptr, :32]! + vshr.u64 $temp,`&Dlo("$A6xB")`,#16 + vadd.u64 `&Dhi("$A6xB")`,`&Dhi("$A6xB")`,$temp + vld1.64 {$A0xB}, [$tinptr, :128]! + vshr.u64 $temp,`&Dhi("$A6xB")`,#16 + vzip.16 `&Dlo("$A6xB")`,`&Dhi("$A6xB")` + + vadd.u64 `&Dlo("$A7xB")`,`&Dlo("$A7xB")`,$temp + vst1.32 {`&Dlo("$A6xB")`[0]}, [$toutptr, :32]! + vshr.u64 $temp,`&Dlo("$A7xB")`,#16 + vadd.u64 `&Dhi("$A7xB")`,`&Dhi("$A7xB")`,$temp + vld1.64 {$A1xB-$A2xB}, [$tinptr, :256]! + vshr.u64 $temp,`&Dhi("$A7xB")`,#16 + vzip.16 `&Dlo("$A7xB")`,`&Dhi("$A7xB")` + subs $inner,$inner,#8 + vst1.32 {`&Dlo("$A7xB")`[0]}, [$toutptr, :32]! + + bne .LNEON_tail + + vst1.32 {${temp}[0]}, [$toutptr, :32] @ top-most bit + sub $nptr,$nptr,$num,lsl#2 @ rewind $nptr + subs $aptr,sp,#0 @ clear carry flag + add $bptr,sp,$num,lsl#2 + +.LNEON_sub: + ldmia $aptr!, {r4-r7} + ldmia $nptr!, {r8-r11} + sbcs r8, r4,r8 + sbcs r9, r5,r9 + sbcs r10,r6,r10 + sbcs r11,r7,r11 + teq $aptr,$bptr @ preserves carry + stmia $rptr!, {r8-r11} + bne .LNEON_sub + + ldr r10, [$aptr] @ load top-most bit + veor q0,q0,q0 + sub r11,$bptr,sp @ this is num*4 + veor q1,q1,q1 + mov $aptr,sp + sub $rptr,$rptr,r11 @ rewind $rptr + mov $nptr,$bptr @ second 3/4th of frame + sbcs r10,r10,#0 @ result is carry flag + +.LNEON_copy_n_zap: + ldmia $aptr!, {r4-r7} + ldmia $rptr, {r8-r11} + movcc r8, r4 + vst1.64 {q0-q1}, [$nptr,:256]! @ wipe + movcc r9, r5 + movcc r10,r6 + vst1.64 {q0-q1}, [$nptr,:256]! @ wipe + movcc r11,r7 + ldmia $aptr, {r4-r7} + stmia $rptr!, {r8-r11} + sub $aptr,$aptr,#16 + ldmia $rptr, {r8-r11} + movcc r8, r4 + vst1.64 {q0-q1}, [$aptr,:256]! @ wipe + movcc r9, r5 + movcc r10,r6 + vst1.64 {q0-q1}, [$nptr,:256]! @ wipe + movcc r11,r7 + teq $aptr,$bptr @ preserves carry + stmia $rptr!, {r8-r11} + bne .LNEON_copy_n_zap + + sub sp,ip,#96 + vldmia sp!,{d8-d15} + ldmia sp!,{r4-r11} + ret @ bx lr +.size bn_mul8x_mont_neon,.-bn_mul8x_mont_neon +#endif +___ +} +$code.=<<___; +.asciz "Montgomery multiplication for ARMv4/NEON, CRYPTOGAMS by " +.align 2 +#if __ARM_MAX_ARCH__>=7 +.comm OPENSSL_armcap_P,4,4 +.hidden OPENSSL_armcap_P +#endif +___ + +$code =~ s/\`([^\`]*)\`/eval $1/gem; +$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4 +$code =~ s/\bret\b/bx lr/gm; +print $code; +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/bn-586.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/bn-586.pl new file mode 100644 index 00000000..26d9bcbb --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/bn-586.pl @@ -0,0 +1,774 @@ +#!/usr/bin/env perl + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],$0); + +$sse2=0; +for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } + +&external_label("OPENSSL_ia32cap_P") if ($sse2); + +&bn_mul_add_words("bn_mul_add_words"); +&bn_mul_words("bn_mul_words"); +&bn_sqr_words("bn_sqr_words"); +&bn_div_words("bn_div_words"); +&bn_add_words("bn_add_words"); +&bn_sub_words("bn_sub_words"); +&bn_sub_part_words("bn_sub_part_words"); + +&asm_finish(); + +sub bn_mul_add_words + { + local($name)=@_; + + &function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":""); + + $r="eax"; + $a="edx"; + $c="ecx"; + + if ($sse2) { + &picmeup("eax","OPENSSL_ia32cap_P"); + &bt(&DWP(0,"eax"),26); + &jnc(&label("maw_non_sse2")); + + &mov($r,&wparam(0)); + &mov($a,&wparam(1)); + &mov($c,&wparam(2)); + &movd("mm0",&wparam(3)); # mm0 = w + &pxor("mm1","mm1"); # mm1 = carry_in + &jmp(&label("maw_sse2_entry")); + + &set_label("maw_sse2_unrolled",16); + &movd("mm3",&DWP(0,$r,"",0)); # mm3 = r[0] + &paddq("mm1","mm3"); # mm1 = carry_in + r[0] + &movd("mm2",&DWP(0,$a,"",0)); # mm2 = a[0] + &pmuludq("mm2","mm0"); # mm2 = w*a[0] + &movd("mm4",&DWP(4,$a,"",0)); # mm4 = a[1] + &pmuludq("mm4","mm0"); # mm4 = w*a[1] + &movd("mm6",&DWP(8,$a,"",0)); # mm6 = a[2] + &pmuludq("mm6","mm0"); # mm6 = w*a[2] + &movd("mm7",&DWP(12,$a,"",0)); # mm7 = a[3] + &pmuludq("mm7","mm0"); # mm7 = w*a[3] + &paddq("mm1","mm2"); # mm1 = carry_in + r[0] + w*a[0] + &movd("mm3",&DWP(4,$r,"",0)); # mm3 = r[1] + &paddq("mm3","mm4"); # mm3 = r[1] + w*a[1] + &movd("mm5",&DWP(8,$r,"",0)); # mm5 = r[2] + &paddq("mm5","mm6"); # mm5 = r[2] + w*a[2] + &movd("mm4",&DWP(12,$r,"",0)); # mm4 = r[3] + &paddq("mm7","mm4"); # mm7 = r[3] + w*a[3] + &movd(&DWP(0,$r,"",0),"mm1"); + &movd("mm2",&DWP(16,$a,"",0)); # mm2 = a[4] + &pmuludq("mm2","mm0"); # mm2 = w*a[4] + &psrlq("mm1",32); # mm1 = carry0 + &movd("mm4",&DWP(20,$a,"",0)); # mm4 = a[5] + &pmuludq("mm4","mm0"); # mm4 = w*a[5] + &paddq("mm1","mm3"); # mm1 = carry0 + r[1] + w*a[1] + &movd("mm6",&DWP(24,$a,"",0)); # mm6 = a[6] + &pmuludq("mm6","mm0"); # mm6 = w*a[6] + &movd(&DWP(4,$r,"",0),"mm1"); + &psrlq("mm1",32); # mm1 = carry1 + &movd("mm3",&DWP(28,$a,"",0)); # mm3 = a[7] + &add($a,32); + &pmuludq("mm3","mm0"); # mm3 = w*a[7] + &paddq("mm1","mm5"); # mm1 = carry1 + r[2] + w*a[2] + &movd("mm5",&DWP(16,$r,"",0)); # mm5 = r[4] + &paddq("mm2","mm5"); # mm2 = r[4] + w*a[4] + &movd(&DWP(8,$r,"",0),"mm1"); + &psrlq("mm1",32); # mm1 = carry2 + &paddq("mm1","mm7"); # mm1 = carry2 + r[3] + w*a[3] + &movd("mm5",&DWP(20,$r,"",0)); # mm5 = r[5] + &paddq("mm4","mm5"); # mm4 = r[5] + w*a[5] + &movd(&DWP(12,$r,"",0),"mm1"); + &psrlq("mm1",32); # mm1 = carry3 + &paddq("mm1","mm2"); # mm1 = carry3 + r[4] + w*a[4] + &movd("mm5",&DWP(24,$r,"",0)); # mm5 = r[6] + &paddq("mm6","mm5"); # mm6 = r[6] + w*a[6] + &movd(&DWP(16,$r,"",0),"mm1"); + &psrlq("mm1",32); # mm1 = carry4 + &paddq("mm1","mm4"); # mm1 = carry4 + r[5] + w*a[5] + &movd("mm5",&DWP(28,$r,"",0)); # mm5 = r[7] + &paddq("mm3","mm5"); # mm3 = r[7] + w*a[7] + &movd(&DWP(20,$r,"",0),"mm1"); + &psrlq("mm1",32); # mm1 = carry5 + &paddq("mm1","mm6"); # mm1 = carry5 + r[6] + w*a[6] + &movd(&DWP(24,$r,"",0),"mm1"); + &psrlq("mm1",32); # mm1 = carry6 + &paddq("mm1","mm3"); # mm1 = carry6 + r[7] + w*a[7] + &movd(&DWP(28,$r,"",0),"mm1"); + &lea($r,&DWP(32,$r)); + &psrlq("mm1",32); # mm1 = carry_out + + &sub($c,8); + &jz(&label("maw_sse2_exit")); + &set_label("maw_sse2_entry"); + &test($c,0xfffffff8); + &jnz(&label("maw_sse2_unrolled")); + + &set_label("maw_sse2_loop",4); + &movd("mm2",&DWP(0,$a)); # mm2 = a[i] + &movd("mm3",&DWP(0,$r)); # mm3 = r[i] + &pmuludq("mm2","mm0"); # a[i] *= w + &lea($a,&DWP(4,$a)); + &paddq("mm1","mm3"); # carry += r[i] + &paddq("mm1","mm2"); # carry += a[i]*w + &movd(&DWP(0,$r),"mm1"); # r[i] = carry_low + &sub($c,1); + &psrlq("mm1",32); # carry = carry_high + &lea($r,&DWP(4,$r)); + &jnz(&label("maw_sse2_loop")); + &set_label("maw_sse2_exit"); + &movd("eax","mm1"); # c = carry_out + &emms(); + &ret(); + + &set_label("maw_non_sse2",16); + } + + # function_begin prologue + &push("ebp"); + &push("ebx"); + &push("esi"); + &push("edi"); + + &comment(""); + $Low="eax"; + $High="edx"; + $a="ebx"; + $w="ebp"; + $r="edi"; + $c="esi"; + + &xor($c,$c); # clear carry + &mov($r,&wparam(0)); # + + &mov("ecx",&wparam(2)); # + &mov($a,&wparam(1)); # + + &and("ecx",0xfffffff8); # num / 8 + &mov($w,&wparam(3)); # + + &push("ecx"); # Up the stack for a tmp variable + + &jz(&label("maw_finish")); + + &set_label("maw_loop",16); + + for ($i=0; $i<32; $i+=4) + { + &comment("Round $i"); + + &mov("eax",&DWP($i,$a)); # *a + &mul($w); # *a * w + &add("eax",$c); # L(t)+= c + &adc("edx",0); # H(t)+=carry + &add("eax",&DWP($i,$r)); # L(t)+= *r + &adc("edx",0); # H(t)+=carry + &mov(&DWP($i,$r),"eax"); # *r= L(t); + &mov($c,"edx"); # c= H(t); + } + + &comment(""); + &sub("ecx",8); + &lea($a,&DWP(32,$a)); + &lea($r,&DWP(32,$r)); + &jnz(&label("maw_loop")); + + &set_label("maw_finish",0); + &mov("ecx",&wparam(2)); # get num + &and("ecx",7); + &jnz(&label("maw_finish2")); # helps branch prediction + &jmp(&label("maw_end")); + + &set_label("maw_finish2",1); + for ($i=0; $i<7; $i++) + { + &comment("Tail Round $i"); + &mov("eax",&DWP($i*4,$a)); # *a + &mul($w); # *a * w + &add("eax",$c); # L(t)+=c + &adc("edx",0); # H(t)+=carry + &add("eax",&DWP($i*4,$r)); # L(t)+= *r + &adc("edx",0); # H(t)+=carry + &dec("ecx") if ($i != 7-1); + &mov(&DWP($i*4,$r),"eax"); # *r= L(t); + &mov($c,"edx"); # c= H(t); + &jz(&label("maw_end")) if ($i != 7-1); + } + &set_label("maw_end",0); + &mov("eax",$c); + + &pop("ecx"); # clear variable from + + &function_end($name); + } + +sub bn_mul_words + { + local($name)=@_; + + &function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":""); + + $r="eax"; + $a="edx"; + $c="ecx"; + + if ($sse2) { + &picmeup("eax","OPENSSL_ia32cap_P"); + &bt(&DWP(0,"eax"),26); + &jnc(&label("mw_non_sse2")); + + &mov($r,&wparam(0)); + &mov($a,&wparam(1)); + &mov($c,&wparam(2)); + &movd("mm0",&wparam(3)); # mm0 = w + &pxor("mm1","mm1"); # mm1 = carry = 0 + + &set_label("mw_sse2_loop",16); + &movd("mm2",&DWP(0,$a)); # mm2 = a[i] + &pmuludq("mm2","mm0"); # a[i] *= w + &lea($a,&DWP(4,$a)); + &paddq("mm1","mm2"); # carry += a[i]*w + &movd(&DWP(0,$r),"mm1"); # r[i] = carry_low + &sub($c,1); + &psrlq("mm1",32); # carry = carry_high + &lea($r,&DWP(4,$r)); + &jnz(&label("mw_sse2_loop")); + + &movd("eax","mm1"); # return carry + &emms(); + &ret(); + &set_label("mw_non_sse2",16); + } + + # function_begin prologue + &push("ebp"); + &push("ebx"); + &push("esi"); + &push("edi"); + + &comment(""); + $Low="eax"; + $High="edx"; + $a="ebx"; + $w="ecx"; + $r="edi"; + $c="esi"; + $num="ebp"; + + &xor($c,$c); # clear carry + &mov($r,&wparam(0)); # + &mov($a,&wparam(1)); # + &mov($num,&wparam(2)); # + &mov($w,&wparam(3)); # + + &and($num,0xfffffff8); # num / 8 + &jz(&label("mw_finish")); + + &set_label("mw_loop",0); + for ($i=0; $i<32; $i+=4) + { + &comment("Round $i"); + + &mov("eax",&DWP($i,$a,"",0)); # *a + &mul($w); # *a * w + &add("eax",$c); # L(t)+=c + # XXX + + &adc("edx",0); # H(t)+=carry + &mov(&DWP($i,$r,"",0),"eax"); # *r= L(t); + + &mov($c,"edx"); # c= H(t); + } + + &comment(""); + &add($a,32); + &add($r,32); + &sub($num,8); + &jz(&label("mw_finish")); + &jmp(&label("mw_loop")); + + &set_label("mw_finish",0); + &mov($num,&wparam(2)); # get num + &and($num,7); + &jnz(&label("mw_finish2")); + &jmp(&label("mw_end")); + + &set_label("mw_finish2",1); + for ($i=0; $i<7; $i++) + { + &comment("Tail Round $i"); + &mov("eax",&DWP($i*4,$a,"",0));# *a + &mul($w); # *a * w + &add("eax",$c); # L(t)+=c + # XXX + &adc("edx",0); # H(t)+=carry + &mov(&DWP($i*4,$r,"",0),"eax");# *r= L(t); + &mov($c,"edx"); # c= H(t); + &dec($num) if ($i != 7-1); + &jz(&label("mw_end")) if ($i != 7-1); + } + &set_label("mw_end",0); + &mov("eax",$c); + + &function_end($name); + } + +sub bn_sqr_words + { + local($name)=@_; + + &function_begin_B($name,$sse2?"EXTRN\t_OPENSSL_ia32cap_P:DWORD":""); + + $r="eax"; + $a="edx"; + $c="ecx"; + + if ($sse2) { + &picmeup("eax","OPENSSL_ia32cap_P"); + &bt(&DWP(0,"eax"),26); + &jnc(&label("sqr_non_sse2")); + + &mov($r,&wparam(0)); + &mov($a,&wparam(1)); + &mov($c,&wparam(2)); + + &set_label("sqr_sse2_loop",16); + &movd("mm0",&DWP(0,$a)); # mm0 = a[i] + &pmuludq("mm0","mm0"); # a[i] *= a[i] + &lea($a,&DWP(4,$a)); # a++ + &movq(&QWP(0,$r),"mm0"); # r[i] = a[i]*a[i] + &sub($c,1); + &lea($r,&DWP(8,$r)); # r += 2 + &jnz(&label("sqr_sse2_loop")); + + &emms(); + &ret(); + &set_label("sqr_non_sse2",16); + } + + # function_begin prologue + &push("ebp"); + &push("ebx"); + &push("esi"); + &push("edi"); + + &comment(""); + $r="esi"; + $a="edi"; + $num="ebx"; + + &mov($r,&wparam(0)); # + &mov($a,&wparam(1)); # + &mov($num,&wparam(2)); # + + &and($num,0xfffffff8); # num / 8 + &jz(&label("sw_finish")); + + &set_label("sw_loop",0); + for ($i=0; $i<32; $i+=4) + { + &comment("Round $i"); + &mov("eax",&DWP($i,$a,"",0)); # *a + # XXX + &mul("eax"); # *a * *a + &mov(&DWP($i*2,$r,"",0),"eax"); # + &mov(&DWP($i*2+4,$r,"",0),"edx");# + } + + &comment(""); + &add($a,32); + &add($r,64); + &sub($num,8); + &jnz(&label("sw_loop")); + + &set_label("sw_finish",0); + &mov($num,&wparam(2)); # get num + &and($num,7); + &jz(&label("sw_end")); + + for ($i=0; $i<7; $i++) + { + &comment("Tail Round $i"); + &mov("eax",&DWP($i*4,$a,"",0)); # *a + # XXX + &mul("eax"); # *a * *a + &mov(&DWP($i*8,$r,"",0),"eax"); # + &dec($num) if ($i != 7-1); + &mov(&DWP($i*8+4,$r,"",0),"edx"); + &jz(&label("sw_end")) if ($i != 7-1); + } + &set_label("sw_end",0); + + &function_end($name); + } + +sub bn_div_words + { + local($name)=@_; + + &function_begin_B($name,""); + &mov("edx",&wparam(0)); # + &mov("eax",&wparam(1)); # + &mov("ecx",&wparam(2)); # + &div("ecx"); + &ret(); + &function_end_B($name); + } + +sub bn_add_words + { + local($name)=@_; + + &function_begin($name,""); + + &comment(""); + $a="esi"; + $b="edi"; + $c="eax"; + $r="ebx"; + $tmp1="ecx"; + $tmp2="edx"; + $num="ebp"; + + &mov($r,&wparam(0)); # get r + &mov($a,&wparam(1)); # get a + &mov($b,&wparam(2)); # get b + &mov($num,&wparam(3)); # get num + &xor($c,$c); # clear carry + &and($num,0xfffffff8); # num / 8 + + &jz(&label("aw_finish")); + + &set_label("aw_loop",0); + for ($i=0; $i<8; $i++) + { + &comment("Round $i"); + + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &mov($tmp2,&DWP($i*4,$b,"",0)); # *b + &add($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &add($tmp1,$tmp2); + &adc($c,0); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + } + + &comment(""); + &add($a,32); + &add($b,32); + &add($r,32); + &sub($num,8); + &jnz(&label("aw_loop")); + + &set_label("aw_finish",0); + &mov($num,&wparam(3)); # get num + &and($num,7); + &jz(&label("aw_end")); + + for ($i=0; $i<7; $i++) + { + &comment("Tail Round $i"); + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &mov($tmp2,&DWP($i*4,$b,"",0));# *b + &add($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &add($tmp1,$tmp2); + &adc($c,0); + &dec($num) if ($i != 6); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + &jz(&label("aw_end")) if ($i != 6); + } + &set_label("aw_end",0); + +# &mov("eax",$c); # $c is "eax" + + &function_end($name); + } + +sub bn_sub_words + { + local($name)=@_; + + &function_begin($name,""); + + &comment(""); + $a="esi"; + $b="edi"; + $c="eax"; + $r="ebx"; + $tmp1="ecx"; + $tmp2="edx"; + $num="ebp"; + + &mov($r,&wparam(0)); # get r + &mov($a,&wparam(1)); # get a + &mov($b,&wparam(2)); # get b + &mov($num,&wparam(3)); # get num + &xor($c,$c); # clear carry + &and($num,0xfffffff8); # num / 8 + + &jz(&label("aw_finish")); + + &set_label("aw_loop",0); + for ($i=0; $i<8; $i++) + { + &comment("Round $i"); + + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &mov($tmp2,&DWP($i*4,$b,"",0)); # *b + &sub($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &sub($tmp1,$tmp2); + &adc($c,0); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + } + + &comment(""); + &add($a,32); + &add($b,32); + &add($r,32); + &sub($num,8); + &jnz(&label("aw_loop")); + + &set_label("aw_finish",0); + &mov($num,&wparam(3)); # get num + &and($num,7); + &jz(&label("aw_end")); + + for ($i=0; $i<7; $i++) + { + &comment("Tail Round $i"); + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &mov($tmp2,&DWP($i*4,$b,"",0));# *b + &sub($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &sub($tmp1,$tmp2); + &adc($c,0); + &dec($num) if ($i != 6); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + &jz(&label("aw_end")) if ($i != 6); + } + &set_label("aw_end",0); + +# &mov("eax",$c); # $c is "eax" + + &function_end($name); + } + +sub bn_sub_part_words + { + local($name)=@_; + + &function_begin($name,""); + + &comment(""); + $a="esi"; + $b="edi"; + $c="eax"; + $r="ebx"; + $tmp1="ecx"; + $tmp2="edx"; + $num="ebp"; + + &mov($r,&wparam(0)); # get r + &mov($a,&wparam(1)); # get a + &mov($b,&wparam(2)); # get b + &mov($num,&wparam(3)); # get num + &xor($c,$c); # clear carry + &and($num,0xfffffff8); # num / 8 + + &jz(&label("aw_finish")); + + &set_label("aw_loop",0); + for ($i=0; $i<8; $i++) + { + &comment("Round $i"); + + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &mov($tmp2,&DWP($i*4,$b,"",0)); # *b + &sub($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &sub($tmp1,$tmp2); + &adc($c,0); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + } + + &comment(""); + &add($a,32); + &add($b,32); + &add($r,32); + &sub($num,8); + &jnz(&label("aw_loop")); + + &set_label("aw_finish",0); + &mov($num,&wparam(3)); # get num + &and($num,7); + &jz(&label("aw_end")); + + for ($i=0; $i<7; $i++) + { + &comment("Tail Round $i"); + &mov($tmp1,&DWP(0,$a,"",0)); # *a + &mov($tmp2,&DWP(0,$b,"",0));# *b + &sub($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &sub($tmp1,$tmp2); + &adc($c,0); + &mov(&DWP(0,$r,"",0),$tmp1); # *r + &add($a, 4); + &add($b, 4); + &add($r, 4); + &dec($num) if ($i != 6); + &jz(&label("aw_end")) if ($i != 6); + } + &set_label("aw_end",0); + + &cmp(&wparam(4),0); + &je(&label("pw_end")); + + &mov($num,&wparam(4)); # get dl + &cmp($num,0); + &je(&label("pw_end")); + &jge(&label("pw_pos")); + + &comment("pw_neg"); + &mov($tmp2,0); + &sub($tmp2,$num); + &mov($num,$tmp2); + &and($num,0xfffffff8); # num / 8 + &jz(&label("pw_neg_finish")); + + &set_label("pw_neg_loop",0); + for ($i=0; $i<8; $i++) + { + &comment("dl<0 Round $i"); + + &mov($tmp1,0); + &mov($tmp2,&DWP($i*4,$b,"",0)); # *b + &sub($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &sub($tmp1,$tmp2); + &adc($c,0); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + } + + &comment(""); + &add($b,32); + &add($r,32); + &sub($num,8); + &jnz(&label("pw_neg_loop")); + + &set_label("pw_neg_finish",0); + &mov($tmp2,&wparam(4)); # get dl + &mov($num,0); + &sub($num,$tmp2); + &and($num,7); + &jz(&label("pw_end")); + + for ($i=0; $i<7; $i++) + { + &comment("dl<0 Tail Round $i"); + &mov($tmp1,0); + &mov($tmp2,&DWP($i*4,$b,"",0));# *b + &sub($tmp1,$c); + &mov($c,0); + &adc($c,$c); + &sub($tmp1,$tmp2); + &adc($c,0); + &dec($num) if ($i != 6); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + &jz(&label("pw_end")) if ($i != 6); + } + + &jmp(&label("pw_end")); + + &set_label("pw_pos",0); + + &and($num,0xfffffff8); # num / 8 + &jz(&label("pw_pos_finish")); + + &set_label("pw_pos_loop",0); + + for ($i=0; $i<8; $i++) + { + &comment("dl>0 Round $i"); + + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &sub($tmp1,$c); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + &jnc(&label("pw_nc".$i)); + } + + &comment(""); + &add($a,32); + &add($r,32); + &sub($num,8); + &jnz(&label("pw_pos_loop")); + + &set_label("pw_pos_finish",0); + &mov($num,&wparam(4)); # get dl + &and($num,7); + &jz(&label("pw_end")); + + for ($i=0; $i<7; $i++) + { + &comment("dl>0 Tail Round $i"); + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &sub($tmp1,$c); + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + &jnc(&label("pw_tail_nc".$i)); + &dec($num) if ($i != 6); + &jz(&label("pw_end")) if ($i != 6); + } + &mov($c,1); + &jmp(&label("pw_end")); + + &set_label("pw_nc_loop",0); + for ($i=0; $i<8; $i++) + { + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + &set_label("pw_nc".$i,0); + } + + &comment(""); + &add($a,32); + &add($r,32); + &sub($num,8); + &jnz(&label("pw_nc_loop")); + + &mov($num,&wparam(4)); # get dl + &and($num,7); + &jz(&label("pw_nc_end")); + + for ($i=0; $i<7; $i++) + { + &mov($tmp1,&DWP($i*4,$a,"",0)); # *a + &mov(&DWP($i*4,$r,"",0),$tmp1); # *r + &set_label("pw_tail_nc".$i,0); + &dec($num) if ($i != 6); + &jz(&label("pw_nc_end")) if ($i != 6); + } + + &set_label("pw_nc_end",0); + &mov($c,0); + + &set_label("pw_end",0); + +# &mov("eax",$c); # $c is "eax" + + &function_end($name); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/co-586.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/co-586.pl new file mode 100644 index 00000000..57101a6b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/co-586.pl @@ -0,0 +1,287 @@ +#!/usr/local/bin/perl + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],$0); + +&bn_mul_comba("bn_mul_comba8",8); +&bn_mul_comba("bn_mul_comba4",4); +&bn_sqr_comba("bn_sqr_comba8",8); +&bn_sqr_comba("bn_sqr_comba4",4); + +&asm_finish(); + +sub mul_add_c + { + local($a,$ai,$b,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_; + + # pos == -1 if eax and edx are pre-loaded, 0 to load from next + # words, and 1 if load return value + + &comment("mul a[$ai]*b[$bi]"); + + # "eax" and "edx" will always be pre-loaded. + # &mov("eax",&DWP($ai*4,$a,"",0)) ; + # &mov("edx",&DWP($bi*4,$b,"",0)); + + &mul("edx"); + &add($c0,"eax"); + &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # laod next a + &mov("eax",&wparam(0)) if $pos > 0; # load r[] + ### + &adc($c1,"edx"); + &mov("edx",&DWP(($nb)*4,$b,"",0)) if $pos == 0; # laod next b + &mov("edx",&DWP(($nb)*4,$b,"",0)) if $pos == 1; # laod next b + ### + &adc($c2,0); + # is pos > 1, it means it is the last loop + &mov(&DWP($i*4,"eax","",0),$c0) if $pos > 0; # save r[]; + &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # laod next a + } + +sub sqr_add_c + { + local($r,$a,$ai,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_; + + # pos == -1 if eax and edx are pre-loaded, 0 to load from next + # words, and 1 if load return value + + &comment("sqr a[$ai]*a[$bi]"); + + # "eax" and "edx" will always be pre-loaded. + # &mov("eax",&DWP($ai*4,$a,"",0)) ; + # &mov("edx",&DWP($bi*4,$b,"",0)); + + if ($ai == $bi) + { &mul("eax");} + else + { &mul("edx");} + &add($c0,"eax"); + &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # load next a + ### + &adc($c1,"edx"); + &mov("edx",&DWP(($nb)*4,$a,"",0)) if ($pos == 1) && ($na != $nb); + ### + &adc($c2,0); + # is pos > 1, it means it is the last loop + &mov(&DWP($i*4,$r,"",0),$c0) if $pos > 0; # save r[]; + &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # load next b + } + +sub sqr_add_c2 + { + local($r,$a,$ai,$bi,$c0,$c1,$c2,$pos,$i,$na,$nb)=@_; + + # pos == -1 if eax and edx are pre-loaded, 0 to load from next + # words, and 1 if load return value + + &comment("sqr a[$ai]*a[$bi]"); + + # "eax" and "edx" will always be pre-loaded. + # &mov("eax",&DWP($ai*4,$a,"",0)) ; + # &mov("edx",&DWP($bi*4,$a,"",0)); + + if ($ai == $bi) + { &mul("eax");} + else + { &mul("edx");} + &add("eax","eax"); + ### + &adc("edx","edx"); + ### + &adc($c2,0); + &add($c0,"eax"); + &adc($c1,"edx"); + &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 0; # load next a + &mov("eax",&DWP(($na)*4,$a,"",0)) if $pos == 1; # load next b + &adc($c2,0); + &mov(&DWP($i*4,$r,"",0),$c0) if $pos > 0; # save r[]; + &mov("edx",&DWP(($nb)*4,$a,"",0)) if ($pos <= 1) && ($na != $nb); + ### + } + +sub bn_mul_comba + { + local($name,$num)=@_; + local($a,$b,$c0,$c1,$c2); + local($i,$as,$ae,$bs,$be,$ai,$bi); + local($tot,$end); + + &function_begin_B($name,""); + + $c0="ebx"; + $c1="ecx"; + $c2="ebp"; + $a="esi"; + $b="edi"; + + $as=0; + $ae=0; + $bs=0; + $be=0; + $tot=$num+$num-1; + + &push("esi"); + &mov($a,&wparam(1)); + &push("edi"); + &mov($b,&wparam(2)); + &push("ebp"); + &push("ebx"); + + &xor($c0,$c0); + &mov("eax",&DWP(0,$a,"",0)); # load the first word + &xor($c1,$c1); + &mov("edx",&DWP(0,$b,"",0)); # load the first second + + for ($i=0; $i<$tot; $i++) + { + $ai=$as; + $bi=$bs; + $end=$be+1; + + &comment("################## Calculate word $i"); + + for ($j=$bs; $j<$end; $j++) + { + &xor($c2,$c2) if ($j == $bs); + if (($j+1) == $end) + { + $v=1; + $v=2 if (($i+1) == $tot); + } + else + { $v=0; } + if (($j+1) != $end) + { + $na=($ai-1); + $nb=($bi+1); + } + else + { + $na=$as+($i < ($num-1)); + $nb=$bs+($i >= ($num-1)); + } +#printf STDERR "[$ai,$bi] -> [$na,$nb]\n"; + &mul_add_c($a,$ai,$b,$bi,$c0,$c1,$c2,$v,$i,$na,$nb); + if ($v) + { + &comment("saved r[$i]"); + # &mov("eax",&wparam(0)); + # &mov(&DWP($i*4,"eax","",0),$c0); + ($c0,$c1,$c2)=($c1,$c2,$c0); + } + $ai--; + $bi++; + } + $as++ if ($i < ($num-1)); + $ae++ if ($i >= ($num-1)); + + $bs++ if ($i >= ($num-1)); + $be++ if ($i < ($num-1)); + } + &comment("save r[$i]"); + # &mov("eax",&wparam(0)); + &mov(&DWP($i*4,"eax","",0),$c0); + + &pop("ebx"); + &pop("ebp"); + &pop("edi"); + &pop("esi"); + &ret(); + &function_end_B($name); + } + +sub bn_sqr_comba + { + local($name,$num)=@_; + local($r,$a,$c0,$c1,$c2)=@_; + local($i,$as,$ae,$bs,$be,$ai,$bi); + local($b,$tot,$end,$half); + + &function_begin_B($name,""); + + $c0="ebx"; + $c1="ecx"; + $c2="ebp"; + $a="esi"; + $r="edi"; + + &push("esi"); + &push("edi"); + &push("ebp"); + &push("ebx"); + &mov($r,&wparam(0)); + &mov($a,&wparam(1)); + &xor($c0,$c0); + &xor($c1,$c1); + &mov("eax",&DWP(0,$a,"",0)); # load the first word + + $as=0; + $ae=0; + $bs=0; + $be=0; + $tot=$num+$num-1; + + for ($i=0; $i<$tot; $i++) + { + $ai=$as; + $bi=$bs; + $end=$be+1; + + &comment("############### Calculate word $i"); + for ($j=$bs; $j<$end; $j++) + { + &xor($c2,$c2) if ($j == $bs); + if (($ai-1) < ($bi+1)) + { + $v=1; + $v=2 if ($i+1) == $tot; + } + else + { $v=0; } + if (!$v) + { + $na=$ai-1; + $nb=$bi+1; + } + else + { + $na=$as+($i < ($num-1)); + $nb=$bs+($i >= ($num-1)); + } + if ($ai == $bi) + { + &sqr_add_c($r,$a,$ai,$bi, + $c0,$c1,$c2,$v,$i,$na,$nb); + } + else + { + &sqr_add_c2($r,$a,$ai,$bi, + $c0,$c1,$c2,$v,$i,$na,$nb); + } + if ($v) + { + &comment("saved r[$i]"); + #&mov(&DWP($i*4,$r,"",0),$c0); + ($c0,$c1,$c2)=($c1,$c2,$c0); + last; + } + $ai--; + $bi++; + } + $as++ if ($i < ($num-1)); + $ae++ if ($i >= ($num-1)); + + $bs++ if ($i >= ($num-1)); + $be++ if ($i < ($num-1)); + } + &mov(&DWP($i*4,$r,"",0),$c0); + &pop("ebx"); + &pop("ebp"); + &pop("edi"); + &pop("esi"); + &ret(); + &function_end_B($name); + } diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/rsaz-avx2.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/rsaz-avx2.pl new file mode 100644 index 00000000..3b6ccf83 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/rsaz-avx2.pl @@ -0,0 +1,1898 @@ +#!/usr/bin/env perl + +############################################################################## +# # +# Copyright (c) 2012, Intel Corporation # +# # +# All rights reserved. # +# # +# Redistribution and use in source and binary forms, with or without # +# modification, are permitted provided that the following conditions are # +# met: # +# # +# * Redistributions of source code must retain the above copyright # +# notice, this list of conditions and the following disclaimer. # +# # +# * 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. # +# # +# * Neither the name of the Intel Corporation nor the names of its # +# contributors may be used to endorse or promote products derived from # +# this software without specific prior written permission. # +# # +# # +# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY # +# EXPRESS 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 INTEL CORPORATION OR # +# 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. # +# # +############################################################################## +# Developers and authors: # +# Shay Gueron (1, 2), and Vlad Krasnov (1) # +# (1) Intel Corporation, Israel Development Center, Haifa, Israel # +# (2) University of Haifa, Israel # +############################################################################## +# Reference: # +# [1] S. Gueron, V. Krasnov: "Software Implementation of Modular # +# Exponentiation, Using Advanced Vector Instructions Architectures", # +# F. Ozbudak and F. Rodriguez-Henriquez (Eds.): WAIFI 2012, LNCS 7369, # +# pp. 119?135, 2012. Springer-Verlag Berlin Heidelberg 2012 # +# [2] S. Gueron: "Efficient Software Implementations of Modular # +# Exponentiation", Journal of Cryptographic Engineering 2:31-43 (2012). # +# [3] S. Gueron, V. Krasnov: "Speeding up Big-numbers Squaring",IEEE # +# Proceedings of 9th International Conference on Information Technology: # +# New Generations (ITNG 2012), pp.821-823 (2012) # +# [4] S. Gueron, V. Krasnov: "[PATCH] Efficient and side channel analysis # +# resistant 1024-bit modular exponentiation, for optimizing RSA2048 # +# on AVX2 capable x86_64 platforms", # +# http://rt.openssl.org/Ticket/Display.html?id=2850&user=guest&pass=guest# +############################################################################## +# +# +13% improvement over original submission by +# +# rsa2048 sign/sec OpenSSL 1.0.1 scalar(*) this +# 2.3GHz Haswell 621 765/+23% 1113/+79% +# 2.3GHz Broadwell(**) 688 1200(***)/+74% 1120/+63% +# +# (*) if system doesn't support AVX2, for reference purposes; +# (**) scaled to 2.3GHz to simplify comparison; +# (***) scalar AD*X code is faster than AVX2 and is preferred code +# path for Broadwell; + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.19) + ($1>=2.22); + $addx = ($1>=2.23); +} + +if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.09) + ($1>=2.10); + $addx = ($1>=2.10); +} + +if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $avx = ($1>=10) + ($1>=11); + $addx = ($1>=11); +} + +if (!$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9])\.([0-9]+)/) { + my $ver = $2 + $3/100.0; # 3.1->3.01, 3.10->3.10 + $avx = ($ver>=3.0) + ($ver>=3.01); + $addx = ($ver>=3.03); +} + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT = *OUT; + +if ($avx>1) {{{ +{ # void AMS_WW( +my $rp="%rdi"; # BN_ULONG *rp, +my $ap="%rsi"; # const BN_ULONG *ap, +my $np="%rdx"; # const BN_ULONG *np, +my $n0="%ecx"; # const BN_ULONG n0, +my $rep="%r8d"; # int repeat); + +# The registers that hold the accumulated redundant result +# The AMM works on 1024 bit operands, and redundant word size is 29 +# Therefore: ceil(1024/29)/4 = 9 +my $ACC0="%ymm0"; +my $ACC1="%ymm1"; +my $ACC2="%ymm2"; +my $ACC3="%ymm3"; +my $ACC4="%ymm4"; +my $ACC5="%ymm5"; +my $ACC6="%ymm6"; +my $ACC7="%ymm7"; +my $ACC8="%ymm8"; +my $ACC9="%ymm9"; +# Registers that hold the broadcasted words of bp, currently used +my $B1="%ymm10"; +my $B2="%ymm11"; +# Registers that hold the broadcasted words of Y, currently used +my $Y1="%ymm12"; +my $Y2="%ymm13"; +# Helper registers +my $TEMP1="%ymm14"; +my $AND_MASK="%ymm15"; +# alu registers that hold the first words of the ACC +my $r0="%r9"; +my $r1="%r10"; +my $r2="%r11"; +my $r3="%r12"; + +my $i="%r14d"; # loop counter +my $tmp = "%r15"; + +my $FrameSize=32*18+32*8; # place for A^2 and 2*A + +my $aap=$r0; +my $tp0="%rbx"; +my $tp1=$r3; +my $tpa=$tmp; + +$np="%r13"; # reassigned argument + +$code.=<<___; +.text + +.globl rsaz_1024_sqr_avx2 +.type rsaz_1024_sqr_avx2,\@function,5 +.align 64 +rsaz_1024_sqr_avx2: # 702 cycles, 14% faster than rsaz_1024_mul_avx2 + lea (%rsp), %rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + vzeroupper +___ +$code.=<<___ if ($win64); + lea -0xa8(%rsp),%rsp + vmovaps %xmm6,-0xd8(%rax) + vmovaps %xmm7,-0xc8(%rax) + vmovaps %xmm8,-0xb8(%rax) + vmovaps %xmm9,-0xa8(%rax) + vmovaps %xmm10,-0x98(%rax) + vmovaps %xmm11,-0x88(%rax) + vmovaps %xmm12,-0x78(%rax) + vmovaps %xmm13,-0x68(%rax) + vmovaps %xmm14,-0x58(%rax) + vmovaps %xmm15,-0x48(%rax) +.Lsqr_1024_body: +___ +$code.=<<___; + mov %rax,%rbp + mov %rdx, $np # reassigned argument + sub \$$FrameSize, %rsp + mov $np, $tmp + sub \$-128, $rp # size optimization + sub \$-128, $ap + sub \$-128, $np + + and \$4095, $tmp # see if $np crosses page + add \$32*10, $tmp + shr \$12, $tmp + vpxor $ACC9,$ACC9,$ACC9 + jz .Lsqr_1024_no_n_copy + + # unaligned 256-bit load that crosses page boundary can + # cause >2x performance degradation here, so if $np does + # cross page boundary, copy it to stack and make sure stack + # frame doesn't... + sub \$32*10,%rsp + vmovdqu 32*0-128($np), $ACC0 + and \$-2048, %rsp + vmovdqu 32*1-128($np), $ACC1 + vmovdqu 32*2-128($np), $ACC2 + vmovdqu 32*3-128($np), $ACC3 + vmovdqu 32*4-128($np), $ACC4 + vmovdqu 32*5-128($np), $ACC5 + vmovdqu 32*6-128($np), $ACC6 + vmovdqu 32*7-128($np), $ACC7 + vmovdqu 32*8-128($np), $ACC8 + lea $FrameSize+128(%rsp),$np + vmovdqu $ACC0, 32*0-128($np) + vmovdqu $ACC1, 32*1-128($np) + vmovdqu $ACC2, 32*2-128($np) + vmovdqu $ACC3, 32*3-128($np) + vmovdqu $ACC4, 32*4-128($np) + vmovdqu $ACC5, 32*5-128($np) + vmovdqu $ACC6, 32*6-128($np) + vmovdqu $ACC7, 32*7-128($np) + vmovdqu $ACC8, 32*8-128($np) + vmovdqu $ACC9, 32*9-128($np) # $ACC9 is zero + +.Lsqr_1024_no_n_copy: + and \$-1024, %rsp + + vmovdqu 32*1-128($ap), $ACC1 + vmovdqu 32*2-128($ap), $ACC2 + vmovdqu 32*3-128($ap), $ACC3 + vmovdqu 32*4-128($ap), $ACC4 + vmovdqu 32*5-128($ap), $ACC5 + vmovdqu 32*6-128($ap), $ACC6 + vmovdqu 32*7-128($ap), $ACC7 + vmovdqu 32*8-128($ap), $ACC8 + + lea 192(%rsp), $tp0 # 64+128=192 + vpbroadcastq .Land_mask(%rip), $AND_MASK + jmp .LOOP_GRANDE_SQR_1024 + +.align 32 +.LOOP_GRANDE_SQR_1024: + lea 32*18+128(%rsp), $aap # size optimization + lea 448(%rsp), $tp1 # 64+128+256=448 + + # the squaring is performed as described in Variant B of + # "Speeding up Big-Number Squaring", so start by calculating + # the A*2=A+A vector + vpaddq $ACC1, $ACC1, $ACC1 + vpbroadcastq 32*0-128($ap), $B1 + vpaddq $ACC2, $ACC2, $ACC2 + vmovdqa $ACC1, 32*0-128($aap) + vpaddq $ACC3, $ACC3, $ACC3 + vmovdqa $ACC2, 32*1-128($aap) + vpaddq $ACC4, $ACC4, $ACC4 + vmovdqa $ACC3, 32*2-128($aap) + vpaddq $ACC5, $ACC5, $ACC5 + vmovdqa $ACC4, 32*3-128($aap) + vpaddq $ACC6, $ACC6, $ACC6 + vmovdqa $ACC5, 32*4-128($aap) + vpaddq $ACC7, $ACC7, $ACC7 + vmovdqa $ACC6, 32*5-128($aap) + vpaddq $ACC8, $ACC8, $ACC8 + vmovdqa $ACC7, 32*6-128($aap) + vpxor $ACC9, $ACC9, $ACC9 + vmovdqa $ACC8, 32*7-128($aap) + + vpmuludq 32*0-128($ap), $B1, $ACC0 + vpbroadcastq 32*1-128($ap), $B2 + vmovdqu $ACC9, 32*9-192($tp0) # zero upper half + vpmuludq $B1, $ACC1, $ACC1 + vmovdqu $ACC9, 32*10-448($tp1) + vpmuludq $B1, $ACC2, $ACC2 + vmovdqu $ACC9, 32*11-448($tp1) + vpmuludq $B1, $ACC3, $ACC3 + vmovdqu $ACC9, 32*12-448($tp1) + vpmuludq $B1, $ACC4, $ACC4 + vmovdqu $ACC9, 32*13-448($tp1) + vpmuludq $B1, $ACC5, $ACC5 + vmovdqu $ACC9, 32*14-448($tp1) + vpmuludq $B1, $ACC6, $ACC6 + vmovdqu $ACC9, 32*15-448($tp1) + vpmuludq $B1, $ACC7, $ACC7 + vmovdqu $ACC9, 32*16-448($tp1) + vpmuludq $B1, $ACC8, $ACC8 + vpbroadcastq 32*2-128($ap), $B1 + vmovdqu $ACC9, 32*17-448($tp1) + + mov $ap, $tpa + mov \$4, $i + jmp .Lsqr_entry_1024 +___ +$TEMP0=$Y1; +$TEMP2=$Y2; +$code.=<<___; +.align 32 +.LOOP_SQR_1024: + vpbroadcastq 32*1-128($tpa), $B2 + vpmuludq 32*0-128($ap), $B1, $ACC0 + vpaddq 32*0-192($tp0), $ACC0, $ACC0 + vpmuludq 32*0-128($aap), $B1, $ACC1 + vpaddq 32*1-192($tp0), $ACC1, $ACC1 + vpmuludq 32*1-128($aap), $B1, $ACC2 + vpaddq 32*2-192($tp0), $ACC2, $ACC2 + vpmuludq 32*2-128($aap), $B1, $ACC3 + vpaddq 32*3-192($tp0), $ACC3, $ACC3 + vpmuludq 32*3-128($aap), $B1, $ACC4 + vpaddq 32*4-192($tp0), $ACC4, $ACC4 + vpmuludq 32*4-128($aap), $B1, $ACC5 + vpaddq 32*5-192($tp0), $ACC5, $ACC5 + vpmuludq 32*5-128($aap), $B1, $ACC6 + vpaddq 32*6-192($tp0), $ACC6, $ACC6 + vpmuludq 32*6-128($aap), $B1, $ACC7 + vpaddq 32*7-192($tp0), $ACC7, $ACC7 + vpmuludq 32*7-128($aap), $B1, $ACC8 + vpbroadcastq 32*2-128($tpa), $B1 + vpaddq 32*8-192($tp0), $ACC8, $ACC8 +.Lsqr_entry_1024: + vmovdqu $ACC0, 32*0-192($tp0) + vmovdqu $ACC1, 32*1-192($tp0) + + vpmuludq 32*1-128($ap), $B2, $TEMP0 + vpaddq $TEMP0, $ACC2, $ACC2 + vpmuludq 32*1-128($aap), $B2, $TEMP1 + vpaddq $TEMP1, $ACC3, $ACC3 + vpmuludq 32*2-128($aap), $B2, $TEMP2 + vpaddq $TEMP2, $ACC4, $ACC4 + vpmuludq 32*3-128($aap), $B2, $TEMP0 + vpaddq $TEMP0, $ACC5, $ACC5 + vpmuludq 32*4-128($aap), $B2, $TEMP1 + vpaddq $TEMP1, $ACC6, $ACC6 + vpmuludq 32*5-128($aap), $B2, $TEMP2 + vpaddq $TEMP2, $ACC7, $ACC7 + vpmuludq 32*6-128($aap), $B2, $TEMP0 + vpaddq $TEMP0, $ACC8, $ACC8 + vpmuludq 32*7-128($aap), $B2, $ACC0 + vpbroadcastq 32*3-128($tpa), $B2 + vpaddq 32*9-192($tp0), $ACC0, $ACC0 + + vmovdqu $ACC2, 32*2-192($tp0) + vmovdqu $ACC3, 32*3-192($tp0) + + vpmuludq 32*2-128($ap), $B1, $TEMP2 + vpaddq $TEMP2, $ACC4, $ACC4 + vpmuludq 32*2-128($aap), $B1, $TEMP0 + vpaddq $TEMP0, $ACC5, $ACC5 + vpmuludq 32*3-128($aap), $B1, $TEMP1 + vpaddq $TEMP1, $ACC6, $ACC6 + vpmuludq 32*4-128($aap), $B1, $TEMP2 + vpaddq $TEMP2, $ACC7, $ACC7 + vpmuludq 32*5-128($aap), $B1, $TEMP0 + vpaddq $TEMP0, $ACC8, $ACC8 + vpmuludq 32*6-128($aap), $B1, $TEMP1 + vpaddq $TEMP1, $ACC0, $ACC0 + vpmuludq 32*7-128($aap), $B1, $ACC1 + vpbroadcastq 32*4-128($tpa), $B1 + vpaddq 32*10-448($tp1), $ACC1, $ACC1 + + vmovdqu $ACC4, 32*4-192($tp0) + vmovdqu $ACC5, 32*5-192($tp0) + + vpmuludq 32*3-128($ap), $B2, $TEMP0 + vpaddq $TEMP0, $ACC6, $ACC6 + vpmuludq 32*3-128($aap), $B2, $TEMP1 + vpaddq $TEMP1, $ACC7, $ACC7 + vpmuludq 32*4-128($aap), $B2, $TEMP2 + vpaddq $TEMP2, $ACC8, $ACC8 + vpmuludq 32*5-128($aap), $B2, $TEMP0 + vpaddq $TEMP0, $ACC0, $ACC0 + vpmuludq 32*6-128($aap), $B2, $TEMP1 + vpaddq $TEMP1, $ACC1, $ACC1 + vpmuludq 32*7-128($aap), $B2, $ACC2 + vpbroadcastq 32*5-128($tpa), $B2 + vpaddq 32*11-448($tp1), $ACC2, $ACC2 + + vmovdqu $ACC6, 32*6-192($tp0) + vmovdqu $ACC7, 32*7-192($tp0) + + vpmuludq 32*4-128($ap), $B1, $TEMP0 + vpaddq $TEMP0, $ACC8, $ACC8 + vpmuludq 32*4-128($aap), $B1, $TEMP1 + vpaddq $TEMP1, $ACC0, $ACC0 + vpmuludq 32*5-128($aap), $B1, $TEMP2 + vpaddq $TEMP2, $ACC1, $ACC1 + vpmuludq 32*6-128($aap), $B1, $TEMP0 + vpaddq $TEMP0, $ACC2, $ACC2 + vpmuludq 32*7-128($aap), $B1, $ACC3 + vpbroadcastq 32*6-128($tpa), $B1 + vpaddq 32*12-448($tp1), $ACC3, $ACC3 + + vmovdqu $ACC8, 32*8-192($tp0) + vmovdqu $ACC0, 32*9-192($tp0) + lea 8($tp0), $tp0 + + vpmuludq 32*5-128($ap), $B2, $TEMP2 + vpaddq $TEMP2, $ACC1, $ACC1 + vpmuludq 32*5-128($aap), $B2, $TEMP0 + vpaddq $TEMP0, $ACC2, $ACC2 + vpmuludq 32*6-128($aap), $B2, $TEMP1 + vpaddq $TEMP1, $ACC3, $ACC3 + vpmuludq 32*7-128($aap), $B2, $ACC4 + vpbroadcastq 32*7-128($tpa), $B2 + vpaddq 32*13-448($tp1), $ACC4, $ACC4 + + vmovdqu $ACC1, 32*10-448($tp1) + vmovdqu $ACC2, 32*11-448($tp1) + + vpmuludq 32*6-128($ap), $B1, $TEMP0 + vpaddq $TEMP0, $ACC3, $ACC3 + vpmuludq 32*6-128($aap), $B1, $TEMP1 + vpbroadcastq 32*8-128($tpa), $ACC0 # borrow $ACC0 for $B1 + vpaddq $TEMP1, $ACC4, $ACC4 + vpmuludq 32*7-128($aap), $B1, $ACC5 + vpbroadcastq 32*0+8-128($tpa), $B1 # for next iteration + vpaddq 32*14-448($tp1), $ACC5, $ACC5 + + vmovdqu $ACC3, 32*12-448($tp1) + vmovdqu $ACC4, 32*13-448($tp1) + lea 8($tpa), $tpa + + vpmuludq 32*7-128($ap), $B2, $TEMP0 + vpaddq $TEMP0, $ACC5, $ACC5 + vpmuludq 32*7-128($aap), $B2, $ACC6 + vpaddq 32*15-448($tp1), $ACC6, $ACC6 + + vpmuludq 32*8-128($ap), $ACC0, $ACC7 + vmovdqu $ACC5, 32*14-448($tp1) + vpaddq 32*16-448($tp1), $ACC7, $ACC7 + vmovdqu $ACC6, 32*15-448($tp1) + vmovdqu $ACC7, 32*16-448($tp1) + lea 8($tp1), $tp1 + + dec $i + jnz .LOOP_SQR_1024 +___ +$ZERO = $ACC9; +$TEMP0 = $B1; +$TEMP2 = $B2; +$TEMP3 = $Y1; +$TEMP4 = $Y2; +$code.=<<___; + #we need to fix indexes 32-39 to avoid overflow + vmovdqu 32*8(%rsp), $ACC8 # 32*8-192($tp0), + vmovdqu 32*9(%rsp), $ACC1 # 32*9-192($tp0) + vmovdqu 32*10(%rsp), $ACC2 # 32*10-192($tp0) + lea 192(%rsp), $tp0 # 64+128=192 + + vpsrlq \$29, $ACC8, $TEMP1 + vpand $AND_MASK, $ACC8, $ACC8 + vpsrlq \$29, $ACC1, $TEMP2 + vpand $AND_MASK, $ACC1, $ACC1 + + vpermq \$0x93, $TEMP1, $TEMP1 + vpxor $ZERO, $ZERO, $ZERO + vpermq \$0x93, $TEMP2, $TEMP2 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC8, $ACC8 + vpblendd \$3, $TEMP2, $ZERO, $TEMP2 + vpaddq $TEMP1, $ACC1, $ACC1 + vpaddq $TEMP2, $ACC2, $ACC2 + vmovdqu $ACC1, 32*9-192($tp0) + vmovdqu $ACC2, 32*10-192($tp0) + + mov (%rsp), %rax + mov 8(%rsp), $r1 + mov 16(%rsp), $r2 + mov 24(%rsp), $r3 + vmovdqu 32*1(%rsp), $ACC1 + vmovdqu 32*2-192($tp0), $ACC2 + vmovdqu 32*3-192($tp0), $ACC3 + vmovdqu 32*4-192($tp0), $ACC4 + vmovdqu 32*5-192($tp0), $ACC5 + vmovdqu 32*6-192($tp0), $ACC6 + vmovdqu 32*7-192($tp0), $ACC7 + + mov %rax, $r0 + imull $n0, %eax + and \$0x1fffffff, %eax + vmovd %eax, $Y1 + + mov %rax, %rdx + imulq -128($np), %rax + vpbroadcastq $Y1, $Y1 + add %rax, $r0 + mov %rdx, %rax + imulq 8-128($np), %rax + shr \$29, $r0 + add %rax, $r1 + mov %rdx, %rax + imulq 16-128($np), %rax + add $r0, $r1 + add %rax, $r2 + imulq 24-128($np), %rdx + add %rdx, $r3 + + mov $r1, %rax + imull $n0, %eax + and \$0x1fffffff, %eax + + mov \$9, $i + jmp .LOOP_REDUCE_1024 + +.align 32 +.LOOP_REDUCE_1024: + vmovd %eax, $Y2 + vpbroadcastq $Y2, $Y2 + + vpmuludq 32*1-128($np), $Y1, $TEMP0 + mov %rax, %rdx + imulq -128($np), %rax + vpaddq $TEMP0, $ACC1, $ACC1 + add %rax, $r1 + vpmuludq 32*2-128($np), $Y1, $TEMP1 + mov %rdx, %rax + imulq 8-128($np), %rax + vpaddq $TEMP1, $ACC2, $ACC2 + vpmuludq 32*3-128($np), $Y1, $TEMP2 + .byte 0x67 + add %rax, $r2 + .byte 0x67 + mov %rdx, %rax + imulq 16-128($np), %rax + shr \$29, $r1 + vpaddq $TEMP2, $ACC3, $ACC3 + vpmuludq 32*4-128($np), $Y1, $TEMP0 + add %rax, $r3 + add $r1, $r2 + vpaddq $TEMP0, $ACC4, $ACC4 + vpmuludq 32*5-128($np), $Y1, $TEMP1 + mov $r2, %rax + imull $n0, %eax + vpaddq $TEMP1, $ACC5, $ACC5 + vpmuludq 32*6-128($np), $Y1, $TEMP2 + and \$0x1fffffff, %eax + vpaddq $TEMP2, $ACC6, $ACC6 + vpmuludq 32*7-128($np), $Y1, $TEMP0 + vpaddq $TEMP0, $ACC7, $ACC7 + vpmuludq 32*8-128($np), $Y1, $TEMP1 + vmovd %eax, $Y1 + #vmovdqu 32*1-8-128($np), $TEMP2 # moved below + vpaddq $TEMP1, $ACC8, $ACC8 + #vmovdqu 32*2-8-128($np), $TEMP0 # moved below + vpbroadcastq $Y1, $Y1 + + vpmuludq 32*1-8-128($np), $Y2, $TEMP2 # see above + vmovdqu 32*3-8-128($np), $TEMP1 + mov %rax, %rdx + imulq -128($np), %rax + vpaddq $TEMP2, $ACC1, $ACC1 + vpmuludq 32*2-8-128($np), $Y2, $TEMP0 # see above + vmovdqu 32*4-8-128($np), $TEMP2 + add %rax, $r2 + mov %rdx, %rax + imulq 8-128($np), %rax + vpaddq $TEMP0, $ACC2, $ACC2 + add $r3, %rax + shr \$29, $r2 + vpmuludq $Y2, $TEMP1, $TEMP1 + vmovdqu 32*5-8-128($np), $TEMP0 + add $r2, %rax + vpaddq $TEMP1, $ACC3, $ACC3 + vpmuludq $Y2, $TEMP2, $TEMP2 + vmovdqu 32*6-8-128($np), $TEMP1 + .byte 0x67 + mov %rax, $r3 + imull $n0, %eax + vpaddq $TEMP2, $ACC4, $ACC4 + vpmuludq $Y2, $TEMP0, $TEMP0 + .byte 0xc4,0x41,0x7e,0x6f,0x9d,0x58,0x00,0x00,0x00 # vmovdqu 32*7-8-128($np), $TEMP2 + and \$0x1fffffff, %eax + vpaddq $TEMP0, $ACC5, $ACC5 + vpmuludq $Y2, $TEMP1, $TEMP1 + vmovdqu 32*8-8-128($np), $TEMP0 + vpaddq $TEMP1, $ACC6, $ACC6 + vpmuludq $Y2, $TEMP2, $TEMP2 + vmovdqu 32*9-8-128($np), $ACC9 + vmovd %eax, $ACC0 # borrow ACC0 for Y2 + imulq -128($np), %rax + vpaddq $TEMP2, $ACC7, $ACC7 + vpmuludq $Y2, $TEMP0, $TEMP0 + vmovdqu 32*1-16-128($np), $TEMP1 + vpbroadcastq $ACC0, $ACC0 + vpaddq $TEMP0, $ACC8, $ACC8 + vpmuludq $Y2, $ACC9, $ACC9 + vmovdqu 32*2-16-128($np), $TEMP2 + add %rax, $r3 + +___ +($ACC0,$Y2)=($Y2,$ACC0); +$code.=<<___; + vmovdqu 32*1-24-128($np), $ACC0 + vpmuludq $Y1, $TEMP1, $TEMP1 + vmovdqu 32*3-16-128($np), $TEMP0 + vpaddq $TEMP1, $ACC1, $ACC1 + vpmuludq $Y2, $ACC0, $ACC0 + vpmuludq $Y1, $TEMP2, $TEMP2 + .byte 0xc4,0x41,0x7e,0x6f,0xb5,0xf0,0xff,0xff,0xff # vmovdqu 32*4-16-128($np), $TEMP1 + vpaddq $ACC1, $ACC0, $ACC0 + vpaddq $TEMP2, $ACC2, $ACC2 + vpmuludq $Y1, $TEMP0, $TEMP0 + vmovdqu 32*5-16-128($np), $TEMP2 + .byte 0x67 + vmovq $ACC0, %rax + vmovdqu $ACC0, (%rsp) # transfer $r0-$r3 + vpaddq $TEMP0, $ACC3, $ACC3 + vpmuludq $Y1, $TEMP1, $TEMP1 + vmovdqu 32*6-16-128($np), $TEMP0 + vpaddq $TEMP1, $ACC4, $ACC4 + vpmuludq $Y1, $TEMP2, $TEMP2 + vmovdqu 32*7-16-128($np), $TEMP1 + vpaddq $TEMP2, $ACC5, $ACC5 + vpmuludq $Y1, $TEMP0, $TEMP0 + vmovdqu 32*8-16-128($np), $TEMP2 + vpaddq $TEMP0, $ACC6, $ACC6 + vpmuludq $Y1, $TEMP1, $TEMP1 + shr \$29, $r3 + vmovdqu 32*9-16-128($np), $TEMP0 + add $r3, %rax + vpaddq $TEMP1, $ACC7, $ACC7 + vpmuludq $Y1, $TEMP2, $TEMP2 + #vmovdqu 32*2-24-128($np), $TEMP1 # moved below + mov %rax, $r0 + imull $n0, %eax + vpaddq $TEMP2, $ACC8, $ACC8 + vpmuludq $Y1, $TEMP0, $TEMP0 + and \$0x1fffffff, %eax + vmovd %eax, $Y1 + vmovdqu 32*3-24-128($np), $TEMP2 + .byte 0x67 + vpaddq $TEMP0, $ACC9, $ACC9 + vpbroadcastq $Y1, $Y1 + + vpmuludq 32*2-24-128($np), $Y2, $TEMP1 # see above + vmovdqu 32*4-24-128($np), $TEMP0 + mov %rax, %rdx + imulq -128($np), %rax + mov 8(%rsp), $r1 + vpaddq $TEMP1, $ACC2, $ACC1 + vpmuludq $Y2, $TEMP2, $TEMP2 + vmovdqu 32*5-24-128($np), $TEMP1 + add %rax, $r0 + mov %rdx, %rax + imulq 8-128($np), %rax + .byte 0x67 + shr \$29, $r0 + mov 16(%rsp), $r2 + vpaddq $TEMP2, $ACC3, $ACC2 + vpmuludq $Y2, $TEMP0, $TEMP0 + vmovdqu 32*6-24-128($np), $TEMP2 + add %rax, $r1 + mov %rdx, %rax + imulq 16-128($np), %rax + vpaddq $TEMP0, $ACC4, $ACC3 + vpmuludq $Y2, $TEMP1, $TEMP1 + vmovdqu 32*7-24-128($np), $TEMP0 + imulq 24-128($np), %rdx # future $r3 + add %rax, $r2 + lea ($r0,$r1), %rax + vpaddq $TEMP1, $ACC5, $ACC4 + vpmuludq $Y2, $TEMP2, $TEMP2 + vmovdqu 32*8-24-128($np), $TEMP1 + mov %rax, $r1 + imull $n0, %eax + vpmuludq $Y2, $TEMP0, $TEMP0 + vpaddq $TEMP2, $ACC6, $ACC5 + vmovdqu 32*9-24-128($np), $TEMP2 + and \$0x1fffffff, %eax + vpaddq $TEMP0, $ACC7, $ACC6 + vpmuludq $Y2, $TEMP1, $TEMP1 + add 24(%rsp), %rdx + vpaddq $TEMP1, $ACC8, $ACC7 + vpmuludq $Y2, $TEMP2, $TEMP2 + vpaddq $TEMP2, $ACC9, $ACC8 + vmovq $r3, $ACC9 + mov %rdx, $r3 + + dec $i + jnz .LOOP_REDUCE_1024 +___ +($ACC0,$Y2)=($Y2,$ACC0); +$code.=<<___; + lea 448(%rsp), $tp1 # size optimization + vpaddq $ACC9, $Y2, $ACC0 + vpxor $ZERO, $ZERO, $ZERO + + vpaddq 32*9-192($tp0), $ACC0, $ACC0 + vpaddq 32*10-448($tp1), $ACC1, $ACC1 + vpaddq 32*11-448($tp1), $ACC2, $ACC2 + vpaddq 32*12-448($tp1), $ACC3, $ACC3 + vpaddq 32*13-448($tp1), $ACC4, $ACC4 + vpaddq 32*14-448($tp1), $ACC5, $ACC5 + vpaddq 32*15-448($tp1), $ACC6, $ACC6 + vpaddq 32*16-448($tp1), $ACC7, $ACC7 + vpaddq 32*17-448($tp1), $ACC8, $ACC8 + + vpsrlq \$29, $ACC0, $TEMP1 + vpand $AND_MASK, $ACC0, $ACC0 + vpsrlq \$29, $ACC1, $TEMP2 + vpand $AND_MASK, $ACC1, $ACC1 + vpsrlq \$29, $ACC2, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC2, $ACC2 + vpsrlq \$29, $ACC3, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC3, $ACC3 + vpermq \$0x93, $TEMP3, $TEMP3 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP4, $TEMP4 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC0, $ACC0 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC1, $ACC1 + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC2, $ACC2 + vpblendd \$3, $TEMP4, $ZERO, $TEMP4 + vpaddq $TEMP3, $ACC3, $ACC3 + vpaddq $TEMP4, $ACC4, $ACC4 + + vpsrlq \$29, $ACC0, $TEMP1 + vpand $AND_MASK, $ACC0, $ACC0 + vpsrlq \$29, $ACC1, $TEMP2 + vpand $AND_MASK, $ACC1, $ACC1 + vpsrlq \$29, $ACC2, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC2, $ACC2 + vpsrlq \$29, $ACC3, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC3, $ACC3 + vpermq \$0x93, $TEMP3, $TEMP3 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP4, $TEMP4 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC0, $ACC0 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC1, $ACC1 + vmovdqu $ACC0, 32*0-128($rp) + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC2, $ACC2 + vmovdqu $ACC1, 32*1-128($rp) + vpblendd \$3, $TEMP4, $ZERO, $TEMP4 + vpaddq $TEMP3, $ACC3, $ACC3 + vmovdqu $ACC2, 32*2-128($rp) + vpaddq $TEMP4, $ACC4, $ACC4 + vmovdqu $ACC3, 32*3-128($rp) +___ +$TEMP5=$ACC0; +$code.=<<___; + vpsrlq \$29, $ACC4, $TEMP1 + vpand $AND_MASK, $ACC4, $ACC4 + vpsrlq \$29, $ACC5, $TEMP2 + vpand $AND_MASK, $ACC5, $ACC5 + vpsrlq \$29, $ACC6, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC6, $ACC6 + vpsrlq \$29, $ACC7, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC7, $ACC7 + vpsrlq \$29, $ACC8, $TEMP5 + vpermq \$0x93, $TEMP3, $TEMP3 + vpand $AND_MASK, $ACC8, $ACC8 + vpermq \$0x93, $TEMP4, $TEMP4 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP5, $TEMP5 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC4, $ACC4 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC5, $ACC5 + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC6, $ACC6 + vpblendd \$3, $TEMP4, $TEMP5, $TEMP4 + vpaddq $TEMP3, $ACC7, $ACC7 + vpaddq $TEMP4, $ACC8, $ACC8 + + vpsrlq \$29, $ACC4, $TEMP1 + vpand $AND_MASK, $ACC4, $ACC4 + vpsrlq \$29, $ACC5, $TEMP2 + vpand $AND_MASK, $ACC5, $ACC5 + vpsrlq \$29, $ACC6, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC6, $ACC6 + vpsrlq \$29, $ACC7, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC7, $ACC7 + vpsrlq \$29, $ACC8, $TEMP5 + vpermq \$0x93, $TEMP3, $TEMP3 + vpand $AND_MASK, $ACC8, $ACC8 + vpermq \$0x93, $TEMP4, $TEMP4 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP5, $TEMP5 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC4, $ACC4 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC5, $ACC5 + vmovdqu $ACC4, 32*4-128($rp) + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC6, $ACC6 + vmovdqu $ACC5, 32*5-128($rp) + vpblendd \$3, $TEMP4, $TEMP5, $TEMP4 + vpaddq $TEMP3, $ACC7, $ACC7 + vmovdqu $ACC6, 32*6-128($rp) + vpaddq $TEMP4, $ACC8, $ACC8 + vmovdqu $ACC7, 32*7-128($rp) + vmovdqu $ACC8, 32*8-128($rp) + + mov $rp, $ap + dec $rep + jne .LOOP_GRANDE_SQR_1024 + + vzeroall + mov %rbp, %rax +___ +$code.=<<___ if ($win64); + movaps -0xd8(%rax),%xmm6 + movaps -0xc8(%rax),%xmm7 + movaps -0xb8(%rax),%xmm8 + movaps -0xa8(%rax),%xmm9 + movaps -0x98(%rax),%xmm10 + movaps -0x88(%rax),%xmm11 + movaps -0x78(%rax),%xmm12 + movaps -0x68(%rax),%xmm13 + movaps -0x58(%rax),%xmm14 + movaps -0x48(%rax),%xmm15 +___ +$code.=<<___; + mov -48(%rax),%r15 + mov -40(%rax),%r14 + mov -32(%rax),%r13 + mov -24(%rax),%r12 + mov -16(%rax),%rbp + mov -8(%rax),%rbx + lea (%rax),%rsp # restore %rsp +.Lsqr_1024_epilogue: + ret +.size rsaz_1024_sqr_avx2,.-rsaz_1024_sqr_avx2 +___ +} + +{ # void AMM_WW( +my $rp="%rdi"; # BN_ULONG *rp, +my $ap="%rsi"; # const BN_ULONG *ap, +my $bp="%rdx"; # const BN_ULONG *bp, +my $np="%rcx"; # const BN_ULONG *np, +my $n0="%r8d"; # unsigned int n0); + +# The registers that hold the accumulated redundant result +# The AMM works on 1024 bit operands, and redundant word size is 29 +# Therefore: ceil(1024/29)/4 = 9 +my $ACC0="%ymm0"; +my $ACC1="%ymm1"; +my $ACC2="%ymm2"; +my $ACC3="%ymm3"; +my $ACC4="%ymm4"; +my $ACC5="%ymm5"; +my $ACC6="%ymm6"; +my $ACC7="%ymm7"; +my $ACC8="%ymm8"; +my $ACC9="%ymm9"; + +# Registers that hold the broadcasted words of multiplier, currently used +my $Bi="%ymm10"; +my $Yi="%ymm11"; + +# Helper registers +my $TEMP0=$ACC0; +my $TEMP1="%ymm12"; +my $TEMP2="%ymm13"; +my $ZERO="%ymm14"; +my $AND_MASK="%ymm15"; + +# alu registers that hold the first words of the ACC +my $r0="%r9"; +my $r1="%r10"; +my $r2="%r11"; +my $r3="%r12"; + +my $i="%r14d"; +my $tmp="%r15"; + +$bp="%r13"; # reassigned argument + +$code.=<<___; +.globl rsaz_1024_mul_avx2 +.type rsaz_1024_mul_avx2,\@function,5 +.align 64 +rsaz_1024_mul_avx2: + lea (%rsp), %rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + vzeroupper + lea -0xa8(%rsp),%rsp + vmovaps %xmm6,-0xd8(%rax) + vmovaps %xmm7,-0xc8(%rax) + vmovaps %xmm8,-0xb8(%rax) + vmovaps %xmm9,-0xa8(%rax) + vmovaps %xmm10,-0x98(%rax) + vmovaps %xmm11,-0x88(%rax) + vmovaps %xmm12,-0x78(%rax) + vmovaps %xmm13,-0x68(%rax) + vmovaps %xmm14,-0x58(%rax) + vmovaps %xmm15,-0x48(%rax) +.Lmul_1024_body: +___ +$code.=<<___; + mov %rax,%rbp + vzeroall + mov %rdx, $bp # reassigned argument + sub \$64,%rsp + + # unaligned 256-bit load that crosses page boundary can + # cause severe performance degradation here, so if $ap does + # cross page boundary, swap it with $bp [meaning that caller + # is advised to lay down $ap and $bp next to each other, so + # that only one can cross page boundary]. + .byte 0x67,0x67 + mov $ap, $tmp + and \$4095, $tmp + add \$32*10, $tmp + shr \$12, $tmp + mov $ap, $tmp + cmovnz $bp, $ap + cmovnz $tmp, $bp + + mov $np, $tmp + sub \$-128,$ap # size optimization + sub \$-128,$np + sub \$-128,$rp + + and \$4095, $tmp # see if $np crosses page + add \$32*10, $tmp + .byte 0x67,0x67 + shr \$12, $tmp + jz .Lmul_1024_no_n_copy + + # unaligned 256-bit load that crosses page boundary can + # cause severe performance degradation here, so if $np does + # cross page boundary, copy it to stack and make sure stack + # frame doesn't... + sub \$32*10,%rsp + vmovdqu 32*0-128($np), $ACC0 + and \$-512, %rsp + vmovdqu 32*1-128($np), $ACC1 + vmovdqu 32*2-128($np), $ACC2 + vmovdqu 32*3-128($np), $ACC3 + vmovdqu 32*4-128($np), $ACC4 + vmovdqu 32*5-128($np), $ACC5 + vmovdqu 32*6-128($np), $ACC6 + vmovdqu 32*7-128($np), $ACC7 + vmovdqu 32*8-128($np), $ACC8 + lea 64+128(%rsp),$np + vmovdqu $ACC0, 32*0-128($np) + vpxor $ACC0, $ACC0, $ACC0 + vmovdqu $ACC1, 32*1-128($np) + vpxor $ACC1, $ACC1, $ACC1 + vmovdqu $ACC2, 32*2-128($np) + vpxor $ACC2, $ACC2, $ACC2 + vmovdqu $ACC3, 32*3-128($np) + vpxor $ACC3, $ACC3, $ACC3 + vmovdqu $ACC4, 32*4-128($np) + vpxor $ACC4, $ACC4, $ACC4 + vmovdqu $ACC5, 32*5-128($np) + vpxor $ACC5, $ACC5, $ACC5 + vmovdqu $ACC6, 32*6-128($np) + vpxor $ACC6, $ACC6, $ACC6 + vmovdqu $ACC7, 32*7-128($np) + vpxor $ACC7, $ACC7, $ACC7 + vmovdqu $ACC8, 32*8-128($np) + vmovdqa $ACC0, $ACC8 + vmovdqu $ACC9, 32*9-128($np) # $ACC9 is zero after vzeroall +.Lmul_1024_no_n_copy: + and \$-64,%rsp + + mov ($bp), %rbx + vpbroadcastq ($bp), $Bi + vmovdqu $ACC0, (%rsp) # clear top of stack + xor $r0, $r0 + .byte 0x67 + xor $r1, $r1 + xor $r2, $r2 + xor $r3, $r3 + + vmovdqu .Land_mask(%rip), $AND_MASK + mov \$9, $i + vmovdqu $ACC9, 32*9-128($rp) # $ACC9 is zero after vzeroall + jmp .Loop_mul_1024 + +.align 32 +.Loop_mul_1024: + vpsrlq \$29, $ACC3, $ACC9 # correct $ACC3(*) + mov %rbx, %rax + imulq -128($ap), %rax + add $r0, %rax + mov %rbx, $r1 + imulq 8-128($ap), $r1 + add 8(%rsp), $r1 + + mov %rax, $r0 + imull $n0, %eax + and \$0x1fffffff, %eax + + mov %rbx, $r2 + imulq 16-128($ap), $r2 + add 16(%rsp), $r2 + + mov %rbx, $r3 + imulq 24-128($ap), $r3 + add 24(%rsp), $r3 + vpmuludq 32*1-128($ap),$Bi,$TEMP0 + vmovd %eax, $Yi + vpaddq $TEMP0,$ACC1,$ACC1 + vpmuludq 32*2-128($ap),$Bi,$TEMP1 + vpbroadcastq $Yi, $Yi + vpaddq $TEMP1,$ACC2,$ACC2 + vpmuludq 32*3-128($ap),$Bi,$TEMP2 + vpand $AND_MASK, $ACC3, $ACC3 # correct $ACC3 + vpaddq $TEMP2,$ACC3,$ACC3 + vpmuludq 32*4-128($ap),$Bi,$TEMP0 + vpaddq $TEMP0,$ACC4,$ACC4 + vpmuludq 32*5-128($ap),$Bi,$TEMP1 + vpaddq $TEMP1,$ACC5,$ACC5 + vpmuludq 32*6-128($ap),$Bi,$TEMP2 + vpaddq $TEMP2,$ACC6,$ACC6 + vpmuludq 32*7-128($ap),$Bi,$TEMP0 + vpermq \$0x93, $ACC9, $ACC9 # correct $ACC3 + vpaddq $TEMP0,$ACC7,$ACC7 + vpmuludq 32*8-128($ap),$Bi,$TEMP1 + vpbroadcastq 8($bp), $Bi + vpaddq $TEMP1,$ACC8,$ACC8 + + mov %rax,%rdx + imulq -128($np),%rax + add %rax,$r0 + mov %rdx,%rax + imulq 8-128($np),%rax + add %rax,$r1 + mov %rdx,%rax + imulq 16-128($np),%rax + add %rax,$r2 + shr \$29, $r0 + imulq 24-128($np),%rdx + add %rdx,$r3 + add $r0, $r1 + + vpmuludq 32*1-128($np),$Yi,$TEMP2 + vmovq $Bi, %rbx + vpaddq $TEMP2,$ACC1,$ACC1 + vpmuludq 32*2-128($np),$Yi,$TEMP0 + vpaddq $TEMP0,$ACC2,$ACC2 + vpmuludq 32*3-128($np),$Yi,$TEMP1 + vpaddq $TEMP1,$ACC3,$ACC3 + vpmuludq 32*4-128($np),$Yi,$TEMP2 + vpaddq $TEMP2,$ACC4,$ACC4 + vpmuludq 32*5-128($np),$Yi,$TEMP0 + vpaddq $TEMP0,$ACC5,$ACC5 + vpmuludq 32*6-128($np),$Yi,$TEMP1 + vpaddq $TEMP1,$ACC6,$ACC6 + vpmuludq 32*7-128($np),$Yi,$TEMP2 + vpblendd \$3, $ZERO, $ACC9, $ACC9 # correct $ACC3 + vpaddq $TEMP2,$ACC7,$ACC7 + vpmuludq 32*8-128($np),$Yi,$TEMP0 + vpaddq $ACC9, $ACC3, $ACC3 # correct $ACC3 + vpaddq $TEMP0,$ACC8,$ACC8 + + mov %rbx, %rax + imulq -128($ap),%rax + add %rax,$r1 + vmovdqu -8+32*1-128($ap),$TEMP1 + mov %rbx, %rax + imulq 8-128($ap),%rax + add %rax,$r2 + vmovdqu -8+32*2-128($ap),$TEMP2 + + mov $r1, %rax + imull $n0, %eax + and \$0x1fffffff, %eax + + imulq 16-128($ap),%rbx + add %rbx,$r3 + vpmuludq $Bi,$TEMP1,$TEMP1 + vmovd %eax, $Yi + vmovdqu -8+32*3-128($ap),$TEMP0 + vpaddq $TEMP1,$ACC1,$ACC1 + vpmuludq $Bi,$TEMP2,$TEMP2 + vpbroadcastq $Yi, $Yi + vmovdqu -8+32*4-128($ap),$TEMP1 + vpaddq $TEMP2,$ACC2,$ACC2 + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovdqu -8+32*5-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC3,$ACC3 + vpmuludq $Bi,$TEMP1,$TEMP1 + vmovdqu -8+32*6-128($ap),$TEMP0 + vpaddq $TEMP1,$ACC4,$ACC4 + vpmuludq $Bi,$TEMP2,$TEMP2 + vmovdqu -8+32*7-128($ap),$TEMP1 + vpaddq $TEMP2,$ACC5,$ACC5 + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovdqu -8+32*8-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC6,$ACC6 + vpmuludq $Bi,$TEMP1,$TEMP1 + vmovdqu -8+32*9-128($ap),$ACC9 + vpaddq $TEMP1,$ACC7,$ACC7 + vpmuludq $Bi,$TEMP2,$TEMP2 + vpaddq $TEMP2,$ACC8,$ACC8 + vpmuludq $Bi,$ACC9,$ACC9 + vpbroadcastq 16($bp), $Bi + + mov %rax,%rdx + imulq -128($np),%rax + add %rax,$r1 + vmovdqu -8+32*1-128($np),$TEMP0 + mov %rdx,%rax + imulq 8-128($np),%rax + add %rax,$r2 + vmovdqu -8+32*2-128($np),$TEMP1 + shr \$29, $r1 + imulq 16-128($np),%rdx + add %rdx,$r3 + add $r1, $r2 + + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovq $Bi, %rbx + vmovdqu -8+32*3-128($np),$TEMP2 + vpaddq $TEMP0,$ACC1,$ACC1 + vpmuludq $Yi,$TEMP1,$TEMP1 + vmovdqu -8+32*4-128($np),$TEMP0 + vpaddq $TEMP1,$ACC2,$ACC2 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovdqu -8+32*5-128($np),$TEMP1 + vpaddq $TEMP2,$ACC3,$ACC3 + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovdqu -8+32*6-128($np),$TEMP2 + vpaddq $TEMP0,$ACC4,$ACC4 + vpmuludq $Yi,$TEMP1,$TEMP1 + vmovdqu -8+32*7-128($np),$TEMP0 + vpaddq $TEMP1,$ACC5,$ACC5 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovdqu -8+32*8-128($np),$TEMP1 + vpaddq $TEMP2,$ACC6,$ACC6 + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovdqu -8+32*9-128($np),$TEMP2 + vpaddq $TEMP0,$ACC7,$ACC7 + vpmuludq $Yi,$TEMP1,$TEMP1 + vpaddq $TEMP1,$ACC8,$ACC8 + vpmuludq $Yi,$TEMP2,$TEMP2 + vpaddq $TEMP2,$ACC9,$ACC9 + + vmovdqu -16+32*1-128($ap),$TEMP0 + mov %rbx,%rax + imulq -128($ap),%rax + add $r2,%rax + + vmovdqu -16+32*2-128($ap),$TEMP1 + mov %rax,$r2 + imull $n0, %eax + and \$0x1fffffff, %eax + + imulq 8-128($ap),%rbx + add %rbx,$r3 + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovd %eax, $Yi + vmovdqu -16+32*3-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC1,$ACC1 + vpmuludq $Bi,$TEMP1,$TEMP1 + vpbroadcastq $Yi, $Yi + vmovdqu -16+32*4-128($ap),$TEMP0 + vpaddq $TEMP1,$ACC2,$ACC2 + vpmuludq $Bi,$TEMP2,$TEMP2 + vmovdqu -16+32*5-128($ap),$TEMP1 + vpaddq $TEMP2,$ACC3,$ACC3 + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovdqu -16+32*6-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC4,$ACC4 + vpmuludq $Bi,$TEMP1,$TEMP1 + vmovdqu -16+32*7-128($ap),$TEMP0 + vpaddq $TEMP1,$ACC5,$ACC5 + vpmuludq $Bi,$TEMP2,$TEMP2 + vmovdqu -16+32*8-128($ap),$TEMP1 + vpaddq $TEMP2,$ACC6,$ACC6 + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovdqu -16+32*9-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC7,$ACC7 + vpmuludq $Bi,$TEMP1,$TEMP1 + vpaddq $TEMP1,$ACC8,$ACC8 + vpmuludq $Bi,$TEMP2,$TEMP2 + vpbroadcastq 24($bp), $Bi + vpaddq $TEMP2,$ACC9,$ACC9 + + vmovdqu -16+32*1-128($np),$TEMP0 + mov %rax,%rdx + imulq -128($np),%rax + add %rax,$r2 + vmovdqu -16+32*2-128($np),$TEMP1 + imulq 8-128($np),%rdx + add %rdx,$r3 + shr \$29, $r2 + + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovq $Bi, %rbx + vmovdqu -16+32*3-128($np),$TEMP2 + vpaddq $TEMP0,$ACC1,$ACC1 + vpmuludq $Yi,$TEMP1,$TEMP1 + vmovdqu -16+32*4-128($np),$TEMP0 + vpaddq $TEMP1,$ACC2,$ACC2 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovdqu -16+32*5-128($np),$TEMP1 + vpaddq $TEMP2,$ACC3,$ACC3 + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovdqu -16+32*6-128($np),$TEMP2 + vpaddq $TEMP0,$ACC4,$ACC4 + vpmuludq $Yi,$TEMP1,$TEMP1 + vmovdqu -16+32*7-128($np),$TEMP0 + vpaddq $TEMP1,$ACC5,$ACC5 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovdqu -16+32*8-128($np),$TEMP1 + vpaddq $TEMP2,$ACC6,$ACC6 + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovdqu -16+32*9-128($np),$TEMP2 + vpaddq $TEMP0,$ACC7,$ACC7 + vpmuludq $Yi,$TEMP1,$TEMP1 + vmovdqu -24+32*1-128($ap),$TEMP0 + vpaddq $TEMP1,$ACC8,$ACC8 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovdqu -24+32*2-128($ap),$TEMP1 + vpaddq $TEMP2,$ACC9,$ACC9 + + add $r2, $r3 + imulq -128($ap),%rbx + add %rbx,$r3 + + mov $r3, %rax + imull $n0, %eax + and \$0x1fffffff, %eax + + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovd %eax, $Yi + vmovdqu -24+32*3-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC1,$ACC1 + vpmuludq $Bi,$TEMP1,$TEMP1 + vpbroadcastq $Yi, $Yi + vmovdqu -24+32*4-128($ap),$TEMP0 + vpaddq $TEMP1,$ACC2,$ACC2 + vpmuludq $Bi,$TEMP2,$TEMP2 + vmovdqu -24+32*5-128($ap),$TEMP1 + vpaddq $TEMP2,$ACC3,$ACC3 + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovdqu -24+32*6-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC4,$ACC4 + vpmuludq $Bi,$TEMP1,$TEMP1 + vmovdqu -24+32*7-128($ap),$TEMP0 + vpaddq $TEMP1,$ACC5,$ACC5 + vpmuludq $Bi,$TEMP2,$TEMP2 + vmovdqu -24+32*8-128($ap),$TEMP1 + vpaddq $TEMP2,$ACC6,$ACC6 + vpmuludq $Bi,$TEMP0,$TEMP0 + vmovdqu -24+32*9-128($ap),$TEMP2 + vpaddq $TEMP0,$ACC7,$ACC7 + vpmuludq $Bi,$TEMP1,$TEMP1 + vpaddq $TEMP1,$ACC8,$ACC8 + vpmuludq $Bi,$TEMP2,$TEMP2 + vpbroadcastq 32($bp), $Bi + vpaddq $TEMP2,$ACC9,$ACC9 + add \$32, $bp # $bp++ + + vmovdqu -24+32*1-128($np),$TEMP0 + imulq -128($np),%rax + add %rax,$r3 + shr \$29, $r3 + + vmovdqu -24+32*2-128($np),$TEMP1 + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovq $Bi, %rbx + vmovdqu -24+32*3-128($np),$TEMP2 + vpaddq $TEMP0,$ACC1,$ACC0 # $ACC0==$TEMP0 + vpmuludq $Yi,$TEMP1,$TEMP1 + vmovdqu $ACC0, (%rsp) # transfer $r0-$r3 + vpaddq $TEMP1,$ACC2,$ACC1 + vmovdqu -24+32*4-128($np),$TEMP0 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovdqu -24+32*5-128($np),$TEMP1 + vpaddq $TEMP2,$ACC3,$ACC2 + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovdqu -24+32*6-128($np),$TEMP2 + vpaddq $TEMP0,$ACC4,$ACC3 + vpmuludq $Yi,$TEMP1,$TEMP1 + vmovdqu -24+32*7-128($np),$TEMP0 + vpaddq $TEMP1,$ACC5,$ACC4 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovdqu -24+32*8-128($np),$TEMP1 + vpaddq $TEMP2,$ACC6,$ACC5 + vpmuludq $Yi,$TEMP0,$TEMP0 + vmovdqu -24+32*9-128($np),$TEMP2 + mov $r3, $r0 + vpaddq $TEMP0,$ACC7,$ACC6 + vpmuludq $Yi,$TEMP1,$TEMP1 + add (%rsp), $r0 + vpaddq $TEMP1,$ACC8,$ACC7 + vpmuludq $Yi,$TEMP2,$TEMP2 + vmovq $r3, $TEMP1 + vpaddq $TEMP2,$ACC9,$ACC8 + + dec $i + jnz .Loop_mul_1024 +___ + +# (*) Original implementation was correcting ACC1-ACC3 for overflow +# after 7 loop runs, or after 28 iterations, or 56 additions. +# But as we underutilize resources, it's possible to correct in +# each iteration with marginal performance loss. But then, as +# we do it in each iteration, we can correct less digits, and +# avoid performance penalties completely. Also note that we +# correct only three digits out of four. This works because +# most significant digit is subjected to less additions. + +$TEMP0 = $ACC9; +$TEMP3 = $Bi; +$TEMP4 = $Yi; +$code.=<<___; + vpermq \$0, $AND_MASK, $AND_MASK + vpaddq (%rsp), $TEMP1, $ACC0 + + vpsrlq \$29, $ACC0, $TEMP1 + vpand $AND_MASK, $ACC0, $ACC0 + vpsrlq \$29, $ACC1, $TEMP2 + vpand $AND_MASK, $ACC1, $ACC1 + vpsrlq \$29, $ACC2, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC2, $ACC2 + vpsrlq \$29, $ACC3, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC3, $ACC3 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP3, $TEMP3 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpermq \$0x93, $TEMP4, $TEMP4 + vpaddq $TEMP0, $ACC0, $ACC0 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC1, $ACC1 + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC2, $ACC2 + vpblendd \$3, $TEMP4, $ZERO, $TEMP4 + vpaddq $TEMP3, $ACC3, $ACC3 + vpaddq $TEMP4, $ACC4, $ACC4 + + vpsrlq \$29, $ACC0, $TEMP1 + vpand $AND_MASK, $ACC0, $ACC0 + vpsrlq \$29, $ACC1, $TEMP2 + vpand $AND_MASK, $ACC1, $ACC1 + vpsrlq \$29, $ACC2, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC2, $ACC2 + vpsrlq \$29, $ACC3, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC3, $ACC3 + vpermq \$0x93, $TEMP3, $TEMP3 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP4, $TEMP4 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC0, $ACC0 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC1, $ACC1 + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC2, $ACC2 + vpblendd \$3, $TEMP4, $ZERO, $TEMP4 + vpaddq $TEMP3, $ACC3, $ACC3 + vpaddq $TEMP4, $ACC4, $ACC4 + + vmovdqu $ACC0, 0-128($rp) + vmovdqu $ACC1, 32-128($rp) + vmovdqu $ACC2, 64-128($rp) + vmovdqu $ACC3, 96-128($rp) +___ + +$TEMP5=$ACC0; +$code.=<<___; + vpsrlq \$29, $ACC4, $TEMP1 + vpand $AND_MASK, $ACC4, $ACC4 + vpsrlq \$29, $ACC5, $TEMP2 + vpand $AND_MASK, $ACC5, $ACC5 + vpsrlq \$29, $ACC6, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC6, $ACC6 + vpsrlq \$29, $ACC7, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC7, $ACC7 + vpsrlq \$29, $ACC8, $TEMP5 + vpermq \$0x93, $TEMP3, $TEMP3 + vpand $AND_MASK, $ACC8, $ACC8 + vpermq \$0x93, $TEMP4, $TEMP4 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP5, $TEMP5 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC4, $ACC4 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC5, $ACC5 + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC6, $ACC6 + vpblendd \$3, $TEMP4, $TEMP5, $TEMP4 + vpaddq $TEMP3, $ACC7, $ACC7 + vpaddq $TEMP4, $ACC8, $ACC8 + + vpsrlq \$29, $ACC4, $TEMP1 + vpand $AND_MASK, $ACC4, $ACC4 + vpsrlq \$29, $ACC5, $TEMP2 + vpand $AND_MASK, $ACC5, $ACC5 + vpsrlq \$29, $ACC6, $TEMP3 + vpermq \$0x93, $TEMP1, $TEMP1 + vpand $AND_MASK, $ACC6, $ACC6 + vpsrlq \$29, $ACC7, $TEMP4 + vpermq \$0x93, $TEMP2, $TEMP2 + vpand $AND_MASK, $ACC7, $ACC7 + vpsrlq \$29, $ACC8, $TEMP5 + vpermq \$0x93, $TEMP3, $TEMP3 + vpand $AND_MASK, $ACC8, $ACC8 + vpermq \$0x93, $TEMP4, $TEMP4 + + vpblendd \$3, $ZERO, $TEMP1, $TEMP0 + vpermq \$0x93, $TEMP5, $TEMP5 + vpblendd \$3, $TEMP1, $TEMP2, $TEMP1 + vpaddq $TEMP0, $ACC4, $ACC4 + vpblendd \$3, $TEMP2, $TEMP3, $TEMP2 + vpaddq $TEMP1, $ACC5, $ACC5 + vpblendd \$3, $TEMP3, $TEMP4, $TEMP3 + vpaddq $TEMP2, $ACC6, $ACC6 + vpblendd \$3, $TEMP4, $TEMP5, $TEMP4 + vpaddq $TEMP3, $ACC7, $ACC7 + vpaddq $TEMP4, $ACC8, $ACC8 + + vmovdqu $ACC4, 128-128($rp) + vmovdqu $ACC5, 160-128($rp) + vmovdqu $ACC6, 192-128($rp) + vmovdqu $ACC7, 224-128($rp) + vmovdqu $ACC8, 256-128($rp) + vzeroupper + + mov %rbp, %rax +___ +$code.=<<___ if ($win64); + movaps -0xd8(%rax),%xmm6 + movaps -0xc8(%rax),%xmm7 + movaps -0xb8(%rax),%xmm8 + movaps -0xa8(%rax),%xmm9 + movaps -0x98(%rax),%xmm10 + movaps -0x88(%rax),%xmm11 + movaps -0x78(%rax),%xmm12 + movaps -0x68(%rax),%xmm13 + movaps -0x58(%rax),%xmm14 + movaps -0x48(%rax),%xmm15 +___ +$code.=<<___; + mov -48(%rax),%r15 + mov -40(%rax),%r14 + mov -32(%rax),%r13 + mov -24(%rax),%r12 + mov -16(%rax),%rbp + mov -8(%rax),%rbx + lea (%rax),%rsp # restore %rsp +.Lmul_1024_epilogue: + ret +.size rsaz_1024_mul_avx2,.-rsaz_1024_mul_avx2 +___ +} +{ +my ($out,$inp) = $win64 ? ("%rcx","%rdx") : ("%rdi","%rsi"); +my @T = map("%r$_",(8..11)); + +$code.=<<___; +.globl rsaz_1024_red2norm_avx2 +.type rsaz_1024_red2norm_avx2,\@abi-omnipotent +.align 32 +rsaz_1024_red2norm_avx2: + sub \$-128,$inp # size optimization + xor %rax,%rax +___ + +for ($j=0,$i=0; $i<16; $i++) { + my $k=0; + while (29*$j<64*($i+1)) { # load data till boundary + $code.=" mov `8*$j-128`($inp), @T[0]\n"; + $j++; $k++; push(@T,shift(@T)); + } + $l=$k; + while ($k>1) { # shift loaded data but last value + $code.=" shl \$`29*($j-$k)`,@T[-$k]\n"; + $k--; + } + $code.=<<___; # shift last value + mov @T[-1], @T[0] + shl \$`29*($j-1)`, @T[-1] + shr \$`-29*($j-1)`, @T[0] +___ + while ($l) { # accumulate all values + $code.=" add @T[-$l], %rax\n"; + $l--; + } + $code.=<<___; + adc \$0, @T[0] # consume eventual carry + mov %rax, 8*$i($out) + mov @T[0], %rax +___ + push(@T,shift(@T)); +} +$code.=<<___; + ret +.size rsaz_1024_red2norm_avx2,.-rsaz_1024_red2norm_avx2 + +.globl rsaz_1024_norm2red_avx2 +.type rsaz_1024_norm2red_avx2,\@abi-omnipotent +.align 32 +rsaz_1024_norm2red_avx2: + sub \$-128,$out # size optimization + mov ($inp),@T[0] + mov \$0x1fffffff,%eax +___ +for ($j=0,$i=0; $i<16; $i++) { + $code.=" mov `8*($i+1)`($inp),@T[1]\n" if ($i<15); + $code.=" xor @T[1],@T[1]\n" if ($i==15); + my $k=1; + while (29*($j+1)<64*($i+1)) { + $code.=<<___; + mov @T[0],@T[-$k] + shr \$`29*$j`,@T[-$k] + and %rax,@T[-$k] # &0x1fffffff + mov @T[-$k],`8*$j-128`($out) +___ + $j++; $k++; + } + $code.=<<___; + shrd \$`29*$j`,@T[1],@T[0] + and %rax,@T[0] + mov @T[0],`8*$j-128`($out) +___ + $j++; + push(@T,shift(@T)); +} +$code.=<<___; + mov @T[0],`8*$j-128`($out) # zero + mov @T[0],`8*($j+1)-128`($out) + mov @T[0],`8*($j+2)-128`($out) + mov @T[0],`8*($j+3)-128`($out) + ret +.size rsaz_1024_norm2red_avx2,.-rsaz_1024_norm2red_avx2 +___ +} +{ +my ($out,$inp,$power) = $win64 ? ("%rcx","%rdx","%r8d") : ("%rdi","%rsi","%edx"); + +$code.=<<___; +.globl rsaz_1024_scatter5_avx2 +.type rsaz_1024_scatter5_avx2,\@abi-omnipotent +.align 32 +rsaz_1024_scatter5_avx2: + vzeroupper + vmovdqu .Lscatter_permd(%rip),%ymm5 + shl \$4,$power + lea ($out,$power),$out + mov \$9,%eax + jmp .Loop_scatter_1024 + +.align 32 +.Loop_scatter_1024: + vmovdqu ($inp),%ymm0 + lea 32($inp),$inp + vpermd %ymm0,%ymm5,%ymm0 + vmovdqu %xmm0,($out) + lea 16*32($out),$out + dec %eax + jnz .Loop_scatter_1024 + + vzeroupper + ret +.size rsaz_1024_scatter5_avx2,.-rsaz_1024_scatter5_avx2 + +.globl rsaz_1024_gather5_avx2 +.type rsaz_1024_gather5_avx2,\@abi-omnipotent +.align 32 +rsaz_1024_gather5_avx2: +___ +$code.=<<___ if ($win64); + lea -0x88(%rsp),%rax + vzeroupper +.LSEH_begin_rsaz_1024_gather5: + # I can't trust assembler to use specific encoding:-( + .byte 0x48,0x8d,0x60,0xe0 #lea -0x20(%rax),%rsp + .byte 0xc5,0xf8,0x29,0x70,0xe0 #vmovaps %xmm6,-0x20(%rax) + .byte 0xc5,0xf8,0x29,0x78,0xf0 #vmovaps %xmm7,-0x10(%rax) + .byte 0xc5,0x78,0x29,0x40,0x00 #vmovaps %xmm8,0(%rax) + .byte 0xc5,0x78,0x29,0x48,0x10 #vmovaps %xmm9,0x10(%rax) + .byte 0xc5,0x78,0x29,0x50,0x20 #vmovaps %xmm10,0x20(%rax) + .byte 0xc5,0x78,0x29,0x58,0x30 #vmovaps %xmm11,0x30(%rax) + .byte 0xc5,0x78,0x29,0x60,0x40 #vmovaps %xmm12,0x40(%rax) + .byte 0xc5,0x78,0x29,0x68,0x50 #vmovaps %xmm13,0x50(%rax) + .byte 0xc5,0x78,0x29,0x70,0x60 #vmovaps %xmm14,0x60(%rax) + .byte 0xc5,0x78,0x29,0x78,0x70 #vmovaps %xmm15,0x70(%rax) +___ +$code.=<<___; + lea .Lgather_table(%rip),%r11 + mov $power,%eax + and \$3,$power + shr \$2,%eax # cache line number + shl \$4,$power # offset within cache line + + vmovdqu -32(%r11),%ymm7 # .Lgather_permd + vpbroadcastb 8(%r11,%rax), %xmm8 + vpbroadcastb 7(%r11,%rax), %xmm9 + vpbroadcastb 6(%r11,%rax), %xmm10 + vpbroadcastb 5(%r11,%rax), %xmm11 + vpbroadcastb 4(%r11,%rax), %xmm12 + vpbroadcastb 3(%r11,%rax), %xmm13 + vpbroadcastb 2(%r11,%rax), %xmm14 + vpbroadcastb 1(%r11,%rax), %xmm15 + + lea 64($inp,$power),$inp + mov \$64,%r11 # size optimization + mov \$9,%eax + jmp .Loop_gather_1024 + +.align 32 +.Loop_gather_1024: + vpand -64($inp), %xmm8,%xmm0 + vpand ($inp), %xmm9,%xmm1 + vpand 64($inp), %xmm10,%xmm2 + vpand ($inp,%r11,2), %xmm11,%xmm3 + vpor %xmm0,%xmm1,%xmm1 + vpand 64($inp,%r11,2), %xmm12,%xmm4 + vpor %xmm2,%xmm3,%xmm3 + vpand ($inp,%r11,4), %xmm13,%xmm5 + vpor %xmm1,%xmm3,%xmm3 + vpand 64($inp,%r11,4), %xmm14,%xmm6 + vpor %xmm4,%xmm5,%xmm5 + vpand -128($inp,%r11,8), %xmm15,%xmm2 + lea ($inp,%r11,8),$inp + vpor %xmm3,%xmm5,%xmm5 + vpor %xmm2,%xmm6,%xmm6 + vpor %xmm5,%xmm6,%xmm6 + vpermd %ymm6,%ymm7,%ymm6 + vmovdqu %ymm6,($out) + lea 32($out),$out + dec %eax + jnz .Loop_gather_1024 + + vpxor %ymm0,%ymm0,%ymm0 + vmovdqu %ymm0,($out) + vzeroupper +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + movaps 0x10(%rsp),%xmm7 + movaps 0x20(%rsp),%xmm8 + movaps 0x30(%rsp),%xmm9 + movaps 0x40(%rsp),%xmm10 + movaps 0x50(%rsp),%xmm11 + movaps 0x60(%rsp),%xmm12 + movaps 0x70(%rsp),%xmm13 + movaps 0x80(%rsp),%xmm14 + movaps 0x90(%rsp),%xmm15 + lea 0xa8(%rsp),%rsp +.LSEH_end_rsaz_1024_gather5: +___ +$code.=<<___; + ret +.size rsaz_1024_gather5_avx2,.-rsaz_1024_gather5_avx2 +___ +} + +$code.=<<___; +.extern OPENSSL_ia32cap_P +.globl rsaz_avx2_eligible +.type rsaz_avx2_eligible,\@abi-omnipotent +.align 32 +rsaz_avx2_eligible: + mov OPENSSL_ia32cap_P+8(%rip),%eax +___ +$code.=<<___ if ($addx); + mov \$`1<<8|1<<19`,%ecx + mov \$0,%edx + and %eax,%ecx + cmp \$`1<<8|1<<19`,%ecx # check for BMI2+AD*X + cmove %edx,%eax +___ +$code.=<<___; + and \$`1<<5`,%eax + shr \$5,%eax + ret +.size rsaz_avx2_eligible,.-rsaz_avx2_eligible + +.align 64 +.Land_mask: + .quad 0x1fffffff,0x1fffffff,0x1fffffff,-1 +.Lscatter_permd: + .long 0,2,4,6,7,7,7,7 +.Lgather_permd: + .long 0,7,1,7,2,7,3,7 +.Lgather_table: + .byte 0,0,0,0,0,0,0,0, 0xff,0,0,0,0,0,0,0 +.align 64 +___ + +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___ +.extern __imp_RtlVirtualUnwind +.type rsaz_se_handler,\@abi-omnipotent +.align 16 +rsaz_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + mov 160($context),%rax # pull context->Rbp + + mov -48(%rax),%r15 + mov -40(%rax),%r14 + mov -32(%rax),%r13 + mov -24(%rax),%r12 + mov -16(%rax),%rbp + mov -8(%rax),%rbx + mov %r15,240($context) + mov %r14,232($context) + mov %r13,224($context) + mov %r12,216($context) + mov %rbp,160($context) + mov %rbx,144($context) + + lea -0xd8(%rax),%rsi # %xmm save area + lea 512($context),%rdi # & context.Xmm6 + mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax) + .long 0xa548f3fc # cld; rep movsq + +.Lcommon_seh_tail: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size rsaz_se_handler,.-rsaz_se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_rsaz_1024_sqr_avx2 + .rva .LSEH_end_rsaz_1024_sqr_avx2 + .rva .LSEH_info_rsaz_1024_sqr_avx2 + + .rva .LSEH_begin_rsaz_1024_mul_avx2 + .rva .LSEH_end_rsaz_1024_mul_avx2 + .rva .LSEH_info_rsaz_1024_mul_avx2 + + .rva .LSEH_begin_rsaz_1024_gather5 + .rva .LSEH_end_rsaz_1024_gather5 + .rva .LSEH_info_rsaz_1024_gather5 +.section .xdata +.align 8 +.LSEH_info_rsaz_1024_sqr_avx2: + .byte 9,0,0,0 + .rva rsaz_se_handler + .rva .Lsqr_1024_body,.Lsqr_1024_epilogue +.LSEH_info_rsaz_1024_mul_avx2: + .byte 9,0,0,0 + .rva rsaz_se_handler + .rva .Lmul_1024_body,.Lmul_1024_epilogue +.LSEH_info_rsaz_1024_gather5: + .byte 0x01,0x33,0x16,0x00 + .byte 0x36,0xf8,0x09,0x00 #vmovaps 0x90(rsp),xmm15 + .byte 0x31,0xe8,0x08,0x00 #vmovaps 0x80(rsp),xmm14 + .byte 0x2c,0xd8,0x07,0x00 #vmovaps 0x70(rsp),xmm13 + .byte 0x27,0xc8,0x06,0x00 #vmovaps 0x60(rsp),xmm12 + .byte 0x22,0xb8,0x05,0x00 #vmovaps 0x50(rsp),xmm11 + .byte 0x1d,0xa8,0x04,0x00 #vmovaps 0x40(rsp),xmm10 + .byte 0x18,0x98,0x03,0x00 #vmovaps 0x30(rsp),xmm9 + .byte 0x13,0x88,0x02,0x00 #vmovaps 0x20(rsp),xmm8 + .byte 0x0e,0x78,0x01,0x00 #vmovaps 0x10(rsp),xmm7 + .byte 0x09,0x68,0x00,0x00 #vmovaps 0x00(rsp),xmm6 + .byte 0x04,0x01,0x15,0x00 #sub rsp,0xa8 +___ +} + +foreach (split("\n",$code)) { + s/\`([^\`]*)\`/eval($1)/ge; + + s/\b(sh[rl]d?\s+\$)(-?[0-9]+)/$1.$2%64/ge or + + s/\b(vmov[dq])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go or + s/\b(vmovdqu)\b(.+)%x%ymm([0-9]+)/$1$2%xmm$3/go or + s/\b(vpinsr[qd])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go or + s/\b(vpextr[qd])\b(.+)%ymm([0-9]+)/$1$2%xmm$3/go or + s/\b(vpbroadcast[qd]\s+)%ymm([0-9]+)/$1%xmm$2/go; + print $_,"\n"; +} + +}}} else {{{ +print <<___; # assembler is too old +.text + +.globl rsaz_avx2_eligible +.type rsaz_avx2_eligible,\@abi-omnipotent +rsaz_avx2_eligible: + xor %eax,%eax + ret +.size rsaz_avx2_eligible,.-rsaz_avx2_eligible + +.globl rsaz_1024_sqr_avx2 +.globl rsaz_1024_mul_avx2 +.globl rsaz_1024_norm2red_avx2 +.globl rsaz_1024_red2norm_avx2 +.globl rsaz_1024_scatter5_avx2 +.globl rsaz_1024_gather5_avx2 +.type rsaz_1024_sqr_avx2,\@abi-omnipotent +rsaz_1024_sqr_avx2: +rsaz_1024_mul_avx2: +rsaz_1024_norm2red_avx2: +rsaz_1024_red2norm_avx2: +rsaz_1024_scatter5_avx2: +rsaz_1024_gather5_avx2: + .byte 0x0f,0x0b # ud2 + ret +.size rsaz_1024_sqr_avx2,.-rsaz_1024_sqr_avx2 +___ +}}} + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/rsaz-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/rsaz-x86_64.pl new file mode 100644 index 00000000..3bd45dba --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/rsaz-x86_64.pl @@ -0,0 +1,2144 @@ +#!/usr/bin/env perl + +############################################################################## +# # +# Copyright (c) 2012, Intel Corporation # +# # +# All rights reserved. # +# # +# Redistribution and use in source and binary forms, with or without # +# modification, are permitted provided that the following conditions are # +# met: # +# # +# * Redistributions of source code must retain the above copyright # +# notice, this list of conditions and the following disclaimer. # +# # +# * 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. # +# # +# * Neither the name of the Intel Corporation nor the names of its # +# contributors may be used to endorse or promote products derived from # +# this software without specific prior written permission. # +# # +# # +# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY # +# EXPRESS 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 INTEL CORPORATION OR # +# 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. # +# # +############################################################################## +# Developers and authors: # +# Shay Gueron (1, 2), and Vlad Krasnov (1) # +# (1) Intel Architecture Group, Microprocessor and Chipset Development, # +# Israel Development Center, Haifa, Israel # +# (2) University of Haifa # +############################################################################## +# Reference: # +# [1] S. Gueron, "Efficient Software Implementations of Modular # +# Exponentiation", http://eprint.iacr.org/2011/239 # +# [2] S. Gueron, V. Krasnov. "Speeding up Big-Numbers Squaring". # +# IEEE Proceedings of 9th International Conference on Information # +# Technology: New Generations (ITNG 2012), 821-823 (2012). # +# [3] S. Gueron, Efficient Software Implementations of Modular Exponentiation# +# Journal of Cryptographic Engineering 2:31-43 (2012). # +# [4] S. Gueron, V. Krasnov: "[PATCH] Efficient and side channel analysis # +# resistant 512-bit and 1024-bit modular exponentiation for optimizing # +# RSA1024 and RSA2048 on x86_64 platforms", # +# http://rt.openssl.org/Ticket/Display.html?id=2582&user=guest&pass=guest# +############################################################################## + +# While original submission covers 512- and 1024-bit exponentiation, +# this module is limited to 512-bit version only (and as such +# accelerates RSA1024 sign). This is because improvement for longer +# keys is not high enough to justify the effort, highest measured +# was ~5% on Westmere. [This is relative to OpenSSL 1.0.2, upcoming +# for the moment of this writing!] Nor does this module implement +# "monolithic" complete exponentiation jumbo-subroutine, but adheres +# to more modular mixture of C and assembly. And it's optimized even +# for processors other than Intel Core family (see table below for +# improvement coefficients). +# +# +# RSA1024 sign/sec this/original |this/rsax(*) this/fips(*) +# ----------------+--------------------------- +# Opteron +13% |+5% +20% +# Bulldozer -0% |-1% +10% +# P4 +11% |+7% +8% +# Westmere +5% |+14% +17% +# Sandy Bridge +2% |+12% +29% +# Ivy Bridge +1% |+11% +35% +# Haswell(**) -0% |+12% +39% +# Atom +13% |+11% +4% +# VIA Nano +70% |+9% +25% +# +# (*) rsax engine and fips numbers are presented for reference +# purposes; +# (**) MULX was attempted, but found to give only marginal improvement; + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $addx = ($1>=2.23); +} + +if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $addx = ($1>=2.10); +} + +if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $addx = ($1>=12); +} + +if (!$addx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9])\.([0-9]+)/) { + my $ver = $2 + $3/100.0; # 3.1->3.01, 3.10->3.10 + $addx = ($ver>=3.03); +} + +($out, $inp, $mod) = ("%rdi", "%rsi", "%rbp"); # common internal API +{ +my ($out,$inp,$mod,$n0,$times) = ("%rdi","%rsi","%rdx","%rcx","%r8d"); + +$code.=<<___; +.text + +.extern OPENSSL_ia32cap_P + +.globl rsaz_512_sqr +.type rsaz_512_sqr,\@function,5 +.align 32 +rsaz_512_sqr: # 25-29% faster than rsaz_512_mul + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + subq \$128+24, %rsp +.Lsqr_body: + movq $mod, %rbp # common argument + movq ($inp), %rdx + movq 8($inp), %rax + movq $n0, 128(%rsp) +___ +$code.=<<___ if ($addx); + movl \$0x80100,%r11d + andl OPENSSL_ia32cap_P+8(%rip),%r11d + cmpl \$0x80100,%r11d # check for MULX and ADO/CX + je .Loop_sqrx +___ +$code.=<<___; + jmp .Loop_sqr + +.align 32 +.Loop_sqr: + movl $times,128+8(%rsp) +#first iteration + movq %rdx, %rbx + mulq %rdx + movq %rax, %r8 + movq 16($inp), %rax + movq %rdx, %r9 + + mulq %rbx + addq %rax, %r9 + movq 24($inp), %rax + movq %rdx, %r10 + adcq \$0, %r10 + + mulq %rbx + addq %rax, %r10 + movq 32($inp), %rax + movq %rdx, %r11 + adcq \$0, %r11 + + mulq %rbx + addq %rax, %r11 + movq 40($inp), %rax + movq %rdx, %r12 + adcq \$0, %r12 + + mulq %rbx + addq %rax, %r12 + movq 48($inp), %rax + movq %rdx, %r13 + adcq \$0, %r13 + + mulq %rbx + addq %rax, %r13 + movq 56($inp), %rax + movq %rdx, %r14 + adcq \$0, %r14 + + mulq %rbx + addq %rax, %r14 + movq %rbx, %rax + movq %rdx, %r15 + adcq \$0, %r15 + + addq %r8, %r8 #shlq \$1, %r8 + movq %r9, %rcx + adcq %r9, %r9 #shld \$1, %r8, %r9 + + mulq %rax + movq %rax, (%rsp) + addq %rdx, %r8 + adcq \$0, %r9 + + movq %r8, 8(%rsp) + shrq \$63, %rcx + +#second iteration + movq 8($inp), %r8 + movq 16($inp), %rax + mulq %r8 + addq %rax, %r10 + movq 24($inp), %rax + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r8 + addq %rax, %r11 + movq 32($inp), %rax + adcq \$0, %rdx + addq %rbx, %r11 + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r8 + addq %rax, %r12 + movq 40($inp), %rax + adcq \$0, %rdx + addq %rbx, %r12 + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r8 + addq %rax, %r13 + movq 48($inp), %rax + adcq \$0, %rdx + addq %rbx, %r13 + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r8 + addq %rax, %r14 + movq 56($inp), %rax + adcq \$0, %rdx + addq %rbx, %r14 + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r8 + addq %rax, %r15 + movq %r8, %rax + adcq \$0, %rdx + addq %rbx, %r15 + movq %rdx, %r8 + movq %r10, %rdx + adcq \$0, %r8 + + add %rdx, %rdx + lea (%rcx,%r10,2), %r10 #shld \$1, %rcx, %r10 + movq %r11, %rbx + adcq %r11, %r11 #shld \$1, %r10, %r11 + + mulq %rax + addq %rax, %r9 + adcq %rdx, %r10 + adcq \$0, %r11 + + movq %r9, 16(%rsp) + movq %r10, 24(%rsp) + shrq \$63, %rbx + +#third iteration + movq 16($inp), %r9 + movq 24($inp), %rax + mulq %r9 + addq %rax, %r12 + movq 32($inp), %rax + movq %rdx, %rcx + adcq \$0, %rcx + + mulq %r9 + addq %rax, %r13 + movq 40($inp), %rax + adcq \$0, %rdx + addq %rcx, %r13 + movq %rdx, %rcx + adcq \$0, %rcx + + mulq %r9 + addq %rax, %r14 + movq 48($inp), %rax + adcq \$0, %rdx + addq %rcx, %r14 + movq %rdx, %rcx + adcq \$0, %rcx + + mulq %r9 + movq %r12, %r10 + lea (%rbx,%r12,2), %r12 #shld \$1, %rbx, %r12 + addq %rax, %r15 + movq 56($inp), %rax + adcq \$0, %rdx + addq %rcx, %r15 + movq %rdx, %rcx + adcq \$0, %rcx + + mulq %r9 + shrq \$63, %r10 + addq %rax, %r8 + movq %r9, %rax + adcq \$0, %rdx + addq %rcx, %r8 + movq %rdx, %r9 + adcq \$0, %r9 + + movq %r13, %rcx + leaq (%r10,%r13,2), %r13 #shld \$1, %r12, %r13 + + mulq %rax + addq %rax, %r11 + adcq %rdx, %r12 + adcq \$0, %r13 + + movq %r11, 32(%rsp) + movq %r12, 40(%rsp) + shrq \$63, %rcx + +#fourth iteration + movq 24($inp), %r10 + movq 32($inp), %rax + mulq %r10 + addq %rax, %r14 + movq 40($inp), %rax + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r10 + addq %rax, %r15 + movq 48($inp), %rax + adcq \$0, %rdx + addq %rbx, %r15 + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r10 + movq %r14, %r12 + leaq (%rcx,%r14,2), %r14 #shld \$1, %rcx, %r14 + addq %rax, %r8 + movq 56($inp), %rax + adcq \$0, %rdx + addq %rbx, %r8 + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r10 + shrq \$63, %r12 + addq %rax, %r9 + movq %r10, %rax + adcq \$0, %rdx + addq %rbx, %r9 + movq %rdx, %r10 + adcq \$0, %r10 + + movq %r15, %rbx + leaq (%r12,%r15,2),%r15 #shld \$1, %r14, %r15 + + mulq %rax + addq %rax, %r13 + adcq %rdx, %r14 + adcq \$0, %r15 + + movq %r13, 48(%rsp) + movq %r14, 56(%rsp) + shrq \$63, %rbx + +#fifth iteration + movq 32($inp), %r11 + movq 40($inp), %rax + mulq %r11 + addq %rax, %r8 + movq 48($inp), %rax + movq %rdx, %rcx + adcq \$0, %rcx + + mulq %r11 + addq %rax, %r9 + movq 56($inp), %rax + adcq \$0, %rdx + movq %r8, %r12 + leaq (%rbx,%r8,2), %r8 #shld \$1, %rbx, %r8 + addq %rcx, %r9 + movq %rdx, %rcx + adcq \$0, %rcx + + mulq %r11 + shrq \$63, %r12 + addq %rax, %r10 + movq %r11, %rax + adcq \$0, %rdx + addq %rcx, %r10 + movq %rdx, %r11 + adcq \$0, %r11 + + movq %r9, %rcx + leaq (%r12,%r9,2), %r9 #shld \$1, %r8, %r9 + + mulq %rax + addq %rax, %r15 + adcq %rdx, %r8 + adcq \$0, %r9 + + movq %r15, 64(%rsp) + movq %r8, 72(%rsp) + shrq \$63, %rcx + +#sixth iteration + movq 40($inp), %r12 + movq 48($inp), %rax + mulq %r12 + addq %rax, %r10 + movq 56($inp), %rax + movq %rdx, %rbx + adcq \$0, %rbx + + mulq %r12 + addq %rax, %r11 + movq %r12, %rax + movq %r10, %r15 + leaq (%rcx,%r10,2), %r10 #shld \$1, %rcx, %r10 + adcq \$0, %rdx + shrq \$63, %r15 + addq %rbx, %r11 + movq %rdx, %r12 + adcq \$0, %r12 + + movq %r11, %rbx + leaq (%r15,%r11,2), %r11 #shld \$1, %r10, %r11 + + mulq %rax + addq %rax, %r9 + adcq %rdx, %r10 + adcq \$0, %r11 + + movq %r9, 80(%rsp) + movq %r10, 88(%rsp) + +#seventh iteration + movq 48($inp), %r13 + movq 56($inp), %rax + mulq %r13 + addq %rax, %r12 + movq %r13, %rax + movq %rdx, %r13 + adcq \$0, %r13 + + xorq %r14, %r14 + shlq \$1, %rbx + adcq %r12, %r12 #shld \$1, %rbx, %r12 + adcq %r13, %r13 #shld \$1, %r12, %r13 + adcq %r14, %r14 #shld \$1, %r13, %r14 + + mulq %rax + addq %rax, %r11 + adcq %rdx, %r12 + adcq \$0, %r13 + + movq %r11, 96(%rsp) + movq %r12, 104(%rsp) + +#eighth iteration + movq 56($inp), %rax + mulq %rax + addq %rax, %r13 + adcq \$0, %rdx + + addq %rdx, %r14 + + movq %r13, 112(%rsp) + movq %r14, 120(%rsp) + + movq (%rsp), %r8 + movq 8(%rsp), %r9 + movq 16(%rsp), %r10 + movq 24(%rsp), %r11 + movq 32(%rsp), %r12 + movq 40(%rsp), %r13 + movq 48(%rsp), %r14 + movq 56(%rsp), %r15 + + call __rsaz_512_reduce + + addq 64(%rsp), %r8 + adcq 72(%rsp), %r9 + adcq 80(%rsp), %r10 + adcq 88(%rsp), %r11 + adcq 96(%rsp), %r12 + adcq 104(%rsp), %r13 + adcq 112(%rsp), %r14 + adcq 120(%rsp), %r15 + sbbq %rcx, %rcx + + call __rsaz_512_subtract + + movq %r8, %rdx + movq %r9, %rax + movl 128+8(%rsp), $times + movq $out, $inp + + decl $times + jnz .Loop_sqr +___ +if ($addx) { +$code.=<<___; + jmp .Lsqr_tail + +.align 32 +.Loop_sqrx: + movl $times,128+8(%rsp) + movq $out, %xmm0 # off-load + movq %rbp, %xmm1 # off-load +#first iteration + mulx %rax, %r8, %r9 + + mulx 16($inp), %rcx, %r10 + xor %rbp, %rbp # cf=0, of=0 + + mulx 24($inp), %rax, %r11 + adcx %rcx, %r9 + + mulx 32($inp), %rcx, %r12 + adcx %rax, %r10 + + mulx 40($inp), %rax, %r13 + adcx %rcx, %r11 + + .byte 0xc4,0x62,0xf3,0xf6,0xb6,0x30,0x00,0x00,0x00 # mulx 48($inp), %rcx, %r14 + adcx %rax, %r12 + adcx %rcx, %r13 + + .byte 0xc4,0x62,0xfb,0xf6,0xbe,0x38,0x00,0x00,0x00 # mulx 56($inp), %rax, %r15 + adcx %rax, %r14 + adcx %rbp, %r15 # %rbp is 0 + + mov %r9, %rcx + shld \$1, %r8, %r9 + shl \$1, %r8 + + xor %ebp, %ebp + mulx %rdx, %rax, %rdx + adcx %rdx, %r8 + mov 8($inp), %rdx + adcx %rbp, %r9 + + mov %rax, (%rsp) + mov %r8, 8(%rsp) + +#second iteration + mulx 16($inp), %rax, %rbx + adox %rax, %r10 + adcx %rbx, %r11 + + .byte 0xc4,0x62,0xc3,0xf6,0x86,0x18,0x00,0x00,0x00 # mulx 24($inp), $out, %r8 + adox $out, %r11 + adcx %r8, %r12 + + mulx 32($inp), %rax, %rbx + adox %rax, %r12 + adcx %rbx, %r13 + + mulx 40($inp), $out, %r8 + adox $out, %r13 + adcx %r8, %r14 + + .byte 0xc4,0xe2,0xfb,0xf6,0x9e,0x30,0x00,0x00,0x00 # mulx 48($inp), %rax, %rbx + adox %rax, %r14 + adcx %rbx, %r15 + + .byte 0xc4,0x62,0xc3,0xf6,0x86,0x38,0x00,0x00,0x00 # mulx 56($inp), $out, %r8 + adox $out, %r15 + adcx %rbp, %r8 + adox %rbp, %r8 + + mov %r11, %rbx + shld \$1, %r10, %r11 + shld \$1, %rcx, %r10 + + xor %ebp,%ebp + mulx %rdx, %rax, %rcx + mov 16($inp), %rdx + adcx %rax, %r9 + adcx %rcx, %r10 + adcx %rbp, %r11 + + mov %r9, 16(%rsp) + .byte 0x4c,0x89,0x94,0x24,0x18,0x00,0x00,0x00 # mov %r10, 24(%rsp) + +#third iteration + .byte 0xc4,0x62,0xc3,0xf6,0x8e,0x18,0x00,0x00,0x00 # mulx 24($inp), $out, %r9 + adox $out, %r12 + adcx %r9, %r13 + + mulx 32($inp), %rax, %rcx + adox %rax, %r13 + adcx %rcx, %r14 + + mulx 40($inp), $out, %r9 + adox $out, %r14 + adcx %r9, %r15 + + .byte 0xc4,0xe2,0xfb,0xf6,0x8e,0x30,0x00,0x00,0x00 # mulx 48($inp), %rax, %rcx + adox %rax, %r15 + adcx %rcx, %r8 + + .byte 0xc4,0x62,0xc3,0xf6,0x8e,0x38,0x00,0x00,0x00 # mulx 56($inp), $out, %r9 + adox $out, %r8 + adcx %rbp, %r9 + adox %rbp, %r9 + + mov %r13, %rcx + shld \$1, %r12, %r13 + shld \$1, %rbx, %r12 + + xor %ebp, %ebp + mulx %rdx, %rax, %rdx + adcx %rax, %r11 + adcx %rdx, %r12 + mov 24($inp), %rdx + adcx %rbp, %r13 + + mov %r11, 32(%rsp) + .byte 0x4c,0x89,0xa4,0x24,0x28,0x00,0x00,0x00 # mov %r12, 40(%rsp) + +#fourth iteration + .byte 0xc4,0xe2,0xfb,0xf6,0x9e,0x20,0x00,0x00,0x00 # mulx 32($inp), %rax, %rbx + adox %rax, %r14 + adcx %rbx, %r15 + + mulx 40($inp), $out, %r10 + adox $out, %r15 + adcx %r10, %r8 + + mulx 48($inp), %rax, %rbx + adox %rax, %r8 + adcx %rbx, %r9 + + mulx 56($inp), $out, %r10 + adox $out, %r9 + adcx %rbp, %r10 + adox %rbp, %r10 + + .byte 0x66 + mov %r15, %rbx + shld \$1, %r14, %r15 + shld \$1, %rcx, %r14 + + xor %ebp, %ebp + mulx %rdx, %rax, %rdx + adcx %rax, %r13 + adcx %rdx, %r14 + mov 32($inp), %rdx + adcx %rbp, %r15 + + mov %r13, 48(%rsp) + mov %r14, 56(%rsp) + +#fifth iteration + .byte 0xc4,0x62,0xc3,0xf6,0x9e,0x28,0x00,0x00,0x00 # mulx 40($inp), $out, %r11 + adox $out, %r8 + adcx %r11, %r9 + + mulx 48($inp), %rax, %rcx + adox %rax, %r9 + adcx %rcx, %r10 + + mulx 56($inp), $out, %r11 + adox $out, %r10 + adcx %rbp, %r11 + adox %rbp, %r11 + + mov %r9, %rcx + shld \$1, %r8, %r9 + shld \$1, %rbx, %r8 + + xor %ebp, %ebp + mulx %rdx, %rax, %rdx + adcx %rax, %r15 + adcx %rdx, %r8 + mov 40($inp), %rdx + adcx %rbp, %r9 + + mov %r15, 64(%rsp) + mov %r8, 72(%rsp) + +#sixth iteration + .byte 0xc4,0xe2,0xfb,0xf6,0x9e,0x30,0x00,0x00,0x00 # mulx 48($inp), %rax, %rbx + adox %rax, %r10 + adcx %rbx, %r11 + + .byte 0xc4,0x62,0xc3,0xf6,0xa6,0x38,0x00,0x00,0x00 # mulx 56($inp), $out, %r12 + adox $out, %r11 + adcx %rbp, %r12 + adox %rbp, %r12 + + mov %r11, %rbx + shld \$1, %r10, %r11 + shld \$1, %rcx, %r10 + + xor %ebp, %ebp + mulx %rdx, %rax, %rdx + adcx %rax, %r9 + adcx %rdx, %r10 + mov 48($inp), %rdx + adcx %rbp, %r11 + + mov %r9, 80(%rsp) + mov %r10, 88(%rsp) + +#seventh iteration + .byte 0xc4,0x62,0xfb,0xf6,0xae,0x38,0x00,0x00,0x00 # mulx 56($inp), %rax, %r13 + adox %rax, %r12 + adox %rbp, %r13 + + xor %r14, %r14 + shld \$1, %r13, %r14 + shld \$1, %r12, %r13 + shld \$1, %rbx, %r12 + + xor %ebp, %ebp + mulx %rdx, %rax, %rdx + adcx %rax, %r11 + adcx %rdx, %r12 + mov 56($inp), %rdx + adcx %rbp, %r13 + + .byte 0x4c,0x89,0x9c,0x24,0x60,0x00,0x00,0x00 # mov %r11, 96(%rsp) + .byte 0x4c,0x89,0xa4,0x24,0x68,0x00,0x00,0x00 # mov %r12, 104(%rsp) + +#eighth iteration + mulx %rdx, %rax, %rdx + adox %rax, %r13 + adox %rbp, %rdx + + .byte 0x66 + add %rdx, %r14 + + movq %r13, 112(%rsp) + movq %r14, 120(%rsp) + movq %xmm0, $out + movq %xmm1, %rbp + + movq 128(%rsp), %rdx # pull $n0 + movq (%rsp), %r8 + movq 8(%rsp), %r9 + movq 16(%rsp), %r10 + movq 24(%rsp), %r11 + movq 32(%rsp), %r12 + movq 40(%rsp), %r13 + movq 48(%rsp), %r14 + movq 56(%rsp), %r15 + + call __rsaz_512_reducex + + addq 64(%rsp), %r8 + adcq 72(%rsp), %r9 + adcq 80(%rsp), %r10 + adcq 88(%rsp), %r11 + adcq 96(%rsp), %r12 + adcq 104(%rsp), %r13 + adcq 112(%rsp), %r14 + adcq 120(%rsp), %r15 + sbbq %rcx, %rcx + + call __rsaz_512_subtract + + movq %r8, %rdx + movq %r9, %rax + movl 128+8(%rsp), $times + movq $out, $inp + + decl $times + jnz .Loop_sqrx + +.Lsqr_tail: +___ +} +$code.=<<___; + + leaq 128+24+48(%rsp), %rax + movq -48(%rax), %r15 + movq -40(%rax), %r14 + movq -32(%rax), %r13 + movq -24(%rax), %r12 + movq -16(%rax), %rbp + movq -8(%rax), %rbx + leaq (%rax), %rsp +.Lsqr_epilogue: + ret +.size rsaz_512_sqr,.-rsaz_512_sqr +___ +} +{ +my ($out,$ap,$bp,$mod,$n0) = ("%rdi","%rsi","%rdx","%rcx","%r8"); +$code.=<<___; +.globl rsaz_512_mul +.type rsaz_512_mul,\@function,5 +.align 32 +rsaz_512_mul: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + subq \$128+24, %rsp +.Lmul_body: + movq $out, %xmm0 # off-load arguments + movq $mod, %xmm1 + movq $n0, 128(%rsp) +___ +$code.=<<___ if ($addx); + movl \$0x80100,%r11d + andl OPENSSL_ia32cap_P+8(%rip),%r11d + cmpl \$0x80100,%r11d # check for MULX and ADO/CX + je .Lmulx +___ +$code.=<<___; + movq ($bp), %rbx # pass b[0] + movq $bp, %rbp # pass argument + call __rsaz_512_mul + + movq %xmm0, $out + movq %xmm1, %rbp + + movq (%rsp), %r8 + movq 8(%rsp), %r9 + movq 16(%rsp), %r10 + movq 24(%rsp), %r11 + movq 32(%rsp), %r12 + movq 40(%rsp), %r13 + movq 48(%rsp), %r14 + movq 56(%rsp), %r15 + + call __rsaz_512_reduce +___ +$code.=<<___ if ($addx); + jmp .Lmul_tail + +.align 32 +.Lmulx: + movq $bp, %rbp # pass argument + movq ($bp), %rdx # pass b[0] + call __rsaz_512_mulx + + movq %xmm0, $out + movq %xmm1, %rbp + + movq 128(%rsp), %rdx # pull $n0 + movq (%rsp), %r8 + movq 8(%rsp), %r9 + movq 16(%rsp), %r10 + movq 24(%rsp), %r11 + movq 32(%rsp), %r12 + movq 40(%rsp), %r13 + movq 48(%rsp), %r14 + movq 56(%rsp), %r15 + + call __rsaz_512_reducex +.Lmul_tail: +___ +$code.=<<___; + addq 64(%rsp), %r8 + adcq 72(%rsp), %r9 + adcq 80(%rsp), %r10 + adcq 88(%rsp), %r11 + adcq 96(%rsp), %r12 + adcq 104(%rsp), %r13 + adcq 112(%rsp), %r14 + adcq 120(%rsp), %r15 + sbbq %rcx, %rcx + + call __rsaz_512_subtract + + leaq 128+24+48(%rsp), %rax + movq -48(%rax), %r15 + movq -40(%rax), %r14 + movq -32(%rax), %r13 + movq -24(%rax), %r12 + movq -16(%rax), %rbp + movq -8(%rax), %rbx + leaq (%rax), %rsp +.Lmul_epilogue: + ret +.size rsaz_512_mul,.-rsaz_512_mul +___ +} +{ +my ($out,$ap,$bp,$mod,$n0,$pwr) = ("%rdi","%rsi","%rdx","%rcx","%r8","%r9d"); +$code.=<<___; +.globl rsaz_512_mul_gather4 +.type rsaz_512_mul_gather4,\@function,6 +.align 32 +rsaz_512_mul_gather4: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + mov $pwr, $pwr + subq \$128+24, %rsp +.Lmul_gather4_body: +___ +$code.=<<___ if ($addx); + movl \$0x80100,%r11d + andl OPENSSL_ia32cap_P+8(%rip),%r11d + cmpl \$0x80100,%r11d # check for MULX and ADO/CX + je .Lmulx_gather +___ +$code.=<<___; + movl 64($bp,$pwr,4), %eax + movq $out, %xmm0 # off-load arguments + movl ($bp,$pwr,4), %ebx + movq $mod, %xmm1 + movq $n0, 128(%rsp) + + shlq \$32, %rax + or %rax, %rbx + movq ($ap), %rax + movq 8($ap), %rcx + leaq 128($bp,$pwr,4), %rbp + mulq %rbx # 0 iteration + movq %rax, (%rsp) + movq %rcx, %rax + movq %rdx, %r8 + + mulq %rbx + movd (%rbp), %xmm4 + addq %rax, %r8 + movq 16($ap), %rax + movq %rdx, %r9 + adcq \$0, %r9 + + mulq %rbx + movd 64(%rbp), %xmm5 + addq %rax, %r9 + movq 24($ap), %rax + movq %rdx, %r10 + adcq \$0, %r10 + + mulq %rbx + pslldq \$4, %xmm5 + addq %rax, %r10 + movq 32($ap), %rax + movq %rdx, %r11 + adcq \$0, %r11 + + mulq %rbx + por %xmm5, %xmm4 + addq %rax, %r11 + movq 40($ap), %rax + movq %rdx, %r12 + adcq \$0, %r12 + + mulq %rbx + addq %rax, %r12 + movq 48($ap), %rax + movq %rdx, %r13 + adcq \$0, %r13 + + mulq %rbx + leaq 128(%rbp), %rbp + addq %rax, %r13 + movq 56($ap), %rax + movq %rdx, %r14 + adcq \$0, %r14 + + mulq %rbx + movq %xmm4, %rbx + addq %rax, %r14 + movq ($ap), %rax + movq %rdx, %r15 + adcq \$0, %r15 + + leaq 8(%rsp), %rdi + movl \$7, %ecx + jmp .Loop_mul_gather + +.align 32 +.Loop_mul_gather: + mulq %rbx + addq %rax, %r8 + movq 8($ap), %rax + movq %r8, (%rdi) + movq %rdx, %r8 + adcq \$0, %r8 + + mulq %rbx + movd (%rbp), %xmm4 + addq %rax, %r9 + movq 16($ap), %rax + adcq \$0, %rdx + addq %r9, %r8 + movq %rdx, %r9 + adcq \$0, %r9 + + mulq %rbx + movd 64(%rbp), %xmm5 + addq %rax, %r10 + movq 24($ap), %rax + adcq \$0, %rdx + addq %r10, %r9 + movq %rdx, %r10 + adcq \$0, %r10 + + mulq %rbx + pslldq \$4, %xmm5 + addq %rax, %r11 + movq 32($ap), %rax + adcq \$0, %rdx + addq %r11, %r10 + movq %rdx, %r11 + adcq \$0, %r11 + + mulq %rbx + por %xmm5, %xmm4 + addq %rax, %r12 + movq 40($ap), %rax + adcq \$0, %rdx + addq %r12, %r11 + movq %rdx, %r12 + adcq \$0, %r12 + + mulq %rbx + addq %rax, %r13 + movq 48($ap), %rax + adcq \$0, %rdx + addq %r13, %r12 + movq %rdx, %r13 + adcq \$0, %r13 + + mulq %rbx + addq %rax, %r14 + movq 56($ap), %rax + adcq \$0, %rdx + addq %r14, %r13 + movq %rdx, %r14 + adcq \$0, %r14 + + mulq %rbx + movq %xmm4, %rbx + addq %rax, %r15 + movq ($ap), %rax + adcq \$0, %rdx + addq %r15, %r14 + movq %rdx, %r15 + adcq \$0, %r15 + + leaq 128(%rbp), %rbp + leaq 8(%rdi), %rdi + + decl %ecx + jnz .Loop_mul_gather + + movq %r8, (%rdi) + movq %r9, 8(%rdi) + movq %r10, 16(%rdi) + movq %r11, 24(%rdi) + movq %r12, 32(%rdi) + movq %r13, 40(%rdi) + movq %r14, 48(%rdi) + movq %r15, 56(%rdi) + + movq %xmm0, $out + movq %xmm1, %rbp + + movq (%rsp), %r8 + movq 8(%rsp), %r9 + movq 16(%rsp), %r10 + movq 24(%rsp), %r11 + movq 32(%rsp), %r12 + movq 40(%rsp), %r13 + movq 48(%rsp), %r14 + movq 56(%rsp), %r15 + + call __rsaz_512_reduce +___ +$code.=<<___ if ($addx); + jmp .Lmul_gather_tail + +.align 32 +.Lmulx_gather: + mov 64($bp,$pwr,4), %eax + movq $out, %xmm0 # off-load arguments + lea 128($bp,$pwr,4), %rbp + mov ($bp,$pwr,4), %edx + movq $mod, %xmm1 + mov $n0, 128(%rsp) + + shl \$32, %rax + or %rax, %rdx + mulx ($ap), %rbx, %r8 # 0 iteration + mov %rbx, (%rsp) + xor %edi, %edi # cf=0, of=0 + + mulx 8($ap), %rax, %r9 + movd (%rbp), %xmm4 + + mulx 16($ap), %rbx, %r10 + movd 64(%rbp), %xmm5 + adcx %rax, %r8 + + mulx 24($ap), %rax, %r11 + pslldq \$4, %xmm5 + adcx %rbx, %r9 + + mulx 32($ap), %rbx, %r12 + por %xmm5, %xmm4 + adcx %rax, %r10 + + mulx 40($ap), %rax, %r13 + adcx %rbx, %r11 + + mulx 48($ap), %rbx, %r14 + lea 128(%rbp), %rbp + adcx %rax, %r12 + + mulx 56($ap), %rax, %r15 + movq %xmm4, %rdx + adcx %rbx, %r13 + adcx %rax, %r14 + mov %r8, %rbx + adcx %rdi, %r15 # %rdi is 0 + + mov \$-7, %rcx + jmp .Loop_mulx_gather + +.align 32 +.Loop_mulx_gather: + mulx ($ap), %rax, %r8 + adcx %rax, %rbx + adox %r9, %r8 + + mulx 8($ap), %rax, %r9 + .byte 0x66,0x0f,0x6e,0xa5,0x00,0x00,0x00,0x00 # movd (%rbp), %xmm4 + adcx %rax, %r8 + adox %r10, %r9 + + mulx 16($ap), %rax, %r10 + movd 64(%rbp), %xmm5 + lea 128(%rbp), %rbp + adcx %rax, %r9 + adox %r11, %r10 + + .byte 0xc4,0x62,0xfb,0xf6,0x9e,0x18,0x00,0x00,0x00 # mulx 24($ap), %rax, %r11 + pslldq \$4, %xmm5 + por %xmm5, %xmm4 + adcx %rax, %r10 + adox %r12, %r11 + + mulx 32($ap), %rax, %r12 + adcx %rax, %r11 + adox %r13, %r12 + + mulx 40($ap), %rax, %r13 + adcx %rax, %r12 + adox %r14, %r13 + + .byte 0xc4,0x62,0xfb,0xf6,0xb6,0x30,0x00,0x00,0x00 # mulx 48($ap), %rax, %r14 + adcx %rax, %r13 + adox %r15, %r14 + + mulx 56($ap), %rax, %r15 + movq %xmm4, %rdx + mov %rbx, 64(%rsp,%rcx,8) + adcx %rax, %r14 + adox %rdi, %r15 + mov %r8, %rbx + adcx %rdi, %r15 # cf=0 + + inc %rcx # of=0 + jnz .Loop_mulx_gather + + mov %r8, 64(%rsp) + mov %r9, 64+8(%rsp) + mov %r10, 64+16(%rsp) + mov %r11, 64+24(%rsp) + mov %r12, 64+32(%rsp) + mov %r13, 64+40(%rsp) + mov %r14, 64+48(%rsp) + mov %r15, 64+56(%rsp) + + movq %xmm0, $out + movq %xmm1, %rbp + + mov 128(%rsp), %rdx # pull $n0 + mov (%rsp), %r8 + mov 8(%rsp), %r9 + mov 16(%rsp), %r10 + mov 24(%rsp), %r11 + mov 32(%rsp), %r12 + mov 40(%rsp), %r13 + mov 48(%rsp), %r14 + mov 56(%rsp), %r15 + + call __rsaz_512_reducex + +.Lmul_gather_tail: +___ +$code.=<<___; + addq 64(%rsp), %r8 + adcq 72(%rsp), %r9 + adcq 80(%rsp), %r10 + adcq 88(%rsp), %r11 + adcq 96(%rsp), %r12 + adcq 104(%rsp), %r13 + adcq 112(%rsp), %r14 + adcq 120(%rsp), %r15 + sbbq %rcx, %rcx + + call __rsaz_512_subtract + + leaq 128+24+48(%rsp), %rax + movq -48(%rax), %r15 + movq -40(%rax), %r14 + movq -32(%rax), %r13 + movq -24(%rax), %r12 + movq -16(%rax), %rbp + movq -8(%rax), %rbx + leaq (%rax), %rsp +.Lmul_gather4_epilogue: + ret +.size rsaz_512_mul_gather4,.-rsaz_512_mul_gather4 +___ +} +{ +my ($out,$ap,$mod,$n0,$tbl,$pwr) = ("%rdi","%rsi","%rdx","%rcx","%r8","%r9d"); +$code.=<<___; +.globl rsaz_512_mul_scatter4 +.type rsaz_512_mul_scatter4,\@function,6 +.align 32 +rsaz_512_mul_scatter4: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + mov $pwr, $pwr + subq \$128+24, %rsp +.Lmul_scatter4_body: + leaq ($tbl,$pwr,4), $tbl + movq $out, %xmm0 # off-load arguments + movq $mod, %xmm1 + movq $tbl, %xmm2 + movq $n0, 128(%rsp) + + movq $out, %rbp +___ +$code.=<<___ if ($addx); + movl \$0x80100,%r11d + andl OPENSSL_ia32cap_P+8(%rip),%r11d + cmpl \$0x80100,%r11d # check for MULX and ADO/CX + je .Lmulx_scatter +___ +$code.=<<___; + movq ($out),%rbx # pass b[0] + call __rsaz_512_mul + + movq %xmm0, $out + movq %xmm1, %rbp + + movq (%rsp), %r8 + movq 8(%rsp), %r9 + movq 16(%rsp), %r10 + movq 24(%rsp), %r11 + movq 32(%rsp), %r12 + movq 40(%rsp), %r13 + movq 48(%rsp), %r14 + movq 56(%rsp), %r15 + + call __rsaz_512_reduce +___ +$code.=<<___ if ($addx); + jmp .Lmul_scatter_tail + +.align 32 +.Lmulx_scatter: + movq ($out), %rdx # pass b[0] + call __rsaz_512_mulx + + movq %xmm0, $out + movq %xmm1, %rbp + + movq 128(%rsp), %rdx # pull $n0 + movq (%rsp), %r8 + movq 8(%rsp), %r9 + movq 16(%rsp), %r10 + movq 24(%rsp), %r11 + movq 32(%rsp), %r12 + movq 40(%rsp), %r13 + movq 48(%rsp), %r14 + movq 56(%rsp), %r15 + + call __rsaz_512_reducex + +.Lmul_scatter_tail: +___ +$code.=<<___; + addq 64(%rsp), %r8 + adcq 72(%rsp), %r9 + adcq 80(%rsp), %r10 + adcq 88(%rsp), %r11 + adcq 96(%rsp), %r12 + adcq 104(%rsp), %r13 + adcq 112(%rsp), %r14 + adcq 120(%rsp), %r15 + movq %xmm2, $inp + sbbq %rcx, %rcx + + call __rsaz_512_subtract + + movl %r8d, 64*0($inp) # scatter + shrq \$32, %r8 + movl %r9d, 64*2($inp) + shrq \$32, %r9 + movl %r10d, 64*4($inp) + shrq \$32, %r10 + movl %r11d, 64*6($inp) + shrq \$32, %r11 + movl %r12d, 64*8($inp) + shrq \$32, %r12 + movl %r13d, 64*10($inp) + shrq \$32, %r13 + movl %r14d, 64*12($inp) + shrq \$32, %r14 + movl %r15d, 64*14($inp) + shrq \$32, %r15 + movl %r8d, 64*1($inp) + movl %r9d, 64*3($inp) + movl %r10d, 64*5($inp) + movl %r11d, 64*7($inp) + movl %r12d, 64*9($inp) + movl %r13d, 64*11($inp) + movl %r14d, 64*13($inp) + movl %r15d, 64*15($inp) + + leaq 128+24+48(%rsp), %rax + movq -48(%rax), %r15 + movq -40(%rax), %r14 + movq -32(%rax), %r13 + movq -24(%rax), %r12 + movq -16(%rax), %rbp + movq -8(%rax), %rbx + leaq (%rax), %rsp +.Lmul_scatter4_epilogue: + ret +.size rsaz_512_mul_scatter4,.-rsaz_512_mul_scatter4 +___ +} +{ +my ($out,$inp,$mod,$n0) = ("%rdi","%rsi","%rdx","%rcx"); +$code.=<<___; +.globl rsaz_512_mul_by_one +.type rsaz_512_mul_by_one,\@function,4 +.align 32 +rsaz_512_mul_by_one: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + subq \$128+24, %rsp +.Lmul_by_one_body: +___ +$code.=<<___ if ($addx); + movl OPENSSL_ia32cap_P+8(%rip),%eax +___ +$code.=<<___; + movq $mod, %rbp # reassign argument + movq $n0, 128(%rsp) + + movq ($inp), %r8 + pxor %xmm0, %xmm0 + movq 8($inp), %r9 + movq 16($inp), %r10 + movq 24($inp), %r11 + movq 32($inp), %r12 + movq 40($inp), %r13 + movq 48($inp), %r14 + movq 56($inp), %r15 + + movdqa %xmm0, (%rsp) + movdqa %xmm0, 16(%rsp) + movdqa %xmm0, 32(%rsp) + movdqa %xmm0, 48(%rsp) + movdqa %xmm0, 64(%rsp) + movdqa %xmm0, 80(%rsp) + movdqa %xmm0, 96(%rsp) +___ +$code.=<<___ if ($addx); + andl \$0x80100,%eax + cmpl \$0x80100,%eax # check for MULX and ADO/CX + je .Lby_one_callx +___ +$code.=<<___; + call __rsaz_512_reduce +___ +$code.=<<___ if ($addx); + jmp .Lby_one_tail +.align 32 +.Lby_one_callx: + movq 128(%rsp), %rdx # pull $n0 + call __rsaz_512_reducex +.Lby_one_tail: +___ +$code.=<<___; + movq %r8, ($out) + movq %r9, 8($out) + movq %r10, 16($out) + movq %r11, 24($out) + movq %r12, 32($out) + movq %r13, 40($out) + movq %r14, 48($out) + movq %r15, 56($out) + + leaq 128+24+48(%rsp), %rax + movq -48(%rax), %r15 + movq -40(%rax), %r14 + movq -32(%rax), %r13 + movq -24(%rax), %r12 + movq -16(%rax), %rbp + movq -8(%rax), %rbx + leaq (%rax), %rsp +.Lmul_by_one_epilogue: + ret +.size rsaz_512_mul_by_one,.-rsaz_512_mul_by_one +___ +} +{ # __rsaz_512_reduce + # + # input: %r8-%r15, %rbp - mod, 128(%rsp) - n0 + # output: %r8-%r15 + # clobbers: everything except %rbp and %rdi +$code.=<<___; +.type __rsaz_512_reduce,\@abi-omnipotent +.align 32 +__rsaz_512_reduce: + movq %r8, %rbx + imulq 128+8(%rsp), %rbx + movq 0(%rbp), %rax + movl \$8, %ecx + jmp .Lreduction_loop + +.align 32 +.Lreduction_loop: + mulq %rbx + movq 8(%rbp), %rax + negq %r8 + movq %rdx, %r8 + adcq \$0, %r8 + + mulq %rbx + addq %rax, %r9 + movq 16(%rbp), %rax + adcq \$0, %rdx + addq %r9, %r8 + movq %rdx, %r9 + adcq \$0, %r9 + + mulq %rbx + addq %rax, %r10 + movq 24(%rbp), %rax + adcq \$0, %rdx + addq %r10, %r9 + movq %rdx, %r10 + adcq \$0, %r10 + + mulq %rbx + addq %rax, %r11 + movq 32(%rbp), %rax + adcq \$0, %rdx + addq %r11, %r10 + movq 128+8(%rsp), %rsi + #movq %rdx, %r11 + #adcq \$0, %r11 + adcq \$0, %rdx + movq %rdx, %r11 + + mulq %rbx + addq %rax, %r12 + movq 40(%rbp), %rax + adcq \$0, %rdx + imulq %r8, %rsi + addq %r12, %r11 + movq %rdx, %r12 + adcq \$0, %r12 + + mulq %rbx + addq %rax, %r13 + movq 48(%rbp), %rax + adcq \$0, %rdx + addq %r13, %r12 + movq %rdx, %r13 + adcq \$0, %r13 + + mulq %rbx + addq %rax, %r14 + movq 56(%rbp), %rax + adcq \$0, %rdx + addq %r14, %r13 + movq %rdx, %r14 + adcq \$0, %r14 + + mulq %rbx + movq %rsi, %rbx + addq %rax, %r15 + movq 0(%rbp), %rax + adcq \$0, %rdx + addq %r15, %r14 + movq %rdx, %r15 + adcq \$0, %r15 + + decl %ecx + jne .Lreduction_loop + + ret +.size __rsaz_512_reduce,.-__rsaz_512_reduce +___ +} +if ($addx) { + # __rsaz_512_reducex + # + # input: %r8-%r15, %rbp - mod, 128(%rsp) - n0 + # output: %r8-%r15 + # clobbers: everything except %rbp and %rdi +$code.=<<___; +.type __rsaz_512_reducex,\@abi-omnipotent +.align 32 +__rsaz_512_reducex: + #movq 128+8(%rsp), %rdx # pull $n0 + imulq %r8, %rdx + xorq %rsi, %rsi # cf=0,of=0 + movl \$8, %ecx + jmp .Lreduction_loopx + +.align 32 +.Lreduction_loopx: + mov %r8, %rbx + mulx 0(%rbp), %rax, %r8 + adcx %rbx, %rax + adox %r9, %r8 + + mulx 8(%rbp), %rax, %r9 + adcx %rax, %r8 + adox %r10, %r9 + + mulx 16(%rbp), %rbx, %r10 + adcx %rbx, %r9 + adox %r11, %r10 + + mulx 24(%rbp), %rbx, %r11 + adcx %rbx, %r10 + adox %r12, %r11 + + .byte 0xc4,0x62,0xe3,0xf6,0xa5,0x20,0x00,0x00,0x00 # mulx 32(%rbp), %rbx, %r12 + mov %rdx, %rax + mov %r8, %rdx + adcx %rbx, %r11 + adox %r13, %r12 + + mulx 128+8(%rsp), %rbx, %rdx + mov %rax, %rdx + + mulx 40(%rbp), %rax, %r13 + adcx %rax, %r12 + adox %r14, %r13 + + .byte 0xc4,0x62,0xfb,0xf6,0xb5,0x30,0x00,0x00,0x00 # mulx 48(%rbp), %rax, %r14 + adcx %rax, %r13 + adox %r15, %r14 + + mulx 56(%rbp), %rax, %r15 + mov %rbx, %rdx + adcx %rax, %r14 + adox %rsi, %r15 # %rsi is 0 + adcx %rsi, %r15 # cf=0 + + decl %ecx # of=0 + jne .Lreduction_loopx + + ret +.size __rsaz_512_reducex,.-__rsaz_512_reducex +___ +} +{ # __rsaz_512_subtract + # input: %r8-%r15, %rdi - $out, %rbp - $mod, %rcx - mask + # output: + # clobbers: everything but %rdi, %rsi and %rbp +$code.=<<___; +.type __rsaz_512_subtract,\@abi-omnipotent +.align 32 +__rsaz_512_subtract: + movq %r8, ($out) + movq %r9, 8($out) + movq %r10, 16($out) + movq %r11, 24($out) + movq %r12, 32($out) + movq %r13, 40($out) + movq %r14, 48($out) + movq %r15, 56($out) + + movq 0($mod), %r8 + movq 8($mod), %r9 + negq %r8 + notq %r9 + andq %rcx, %r8 + movq 16($mod), %r10 + andq %rcx, %r9 + notq %r10 + movq 24($mod), %r11 + andq %rcx, %r10 + notq %r11 + movq 32($mod), %r12 + andq %rcx, %r11 + notq %r12 + movq 40($mod), %r13 + andq %rcx, %r12 + notq %r13 + movq 48($mod), %r14 + andq %rcx, %r13 + notq %r14 + movq 56($mod), %r15 + andq %rcx, %r14 + notq %r15 + andq %rcx, %r15 + + addq ($out), %r8 + adcq 8($out), %r9 + adcq 16($out), %r10 + adcq 24($out), %r11 + adcq 32($out), %r12 + adcq 40($out), %r13 + adcq 48($out), %r14 + adcq 56($out), %r15 + + movq %r8, ($out) + movq %r9, 8($out) + movq %r10, 16($out) + movq %r11, 24($out) + movq %r12, 32($out) + movq %r13, 40($out) + movq %r14, 48($out) + movq %r15, 56($out) + + ret +.size __rsaz_512_subtract,.-__rsaz_512_subtract +___ +} +{ # __rsaz_512_mul + # + # input: %rsi - ap, %rbp - bp + # ouput: + # clobbers: everything +my ($ap,$bp) = ("%rsi","%rbp"); +$code.=<<___; +.type __rsaz_512_mul,\@abi-omnipotent +.align 32 +__rsaz_512_mul: + leaq 8(%rsp), %rdi + + movq ($ap), %rax + mulq %rbx + movq %rax, (%rdi) + movq 8($ap), %rax + movq %rdx, %r8 + + mulq %rbx + addq %rax, %r8 + movq 16($ap), %rax + movq %rdx, %r9 + adcq \$0, %r9 + + mulq %rbx + addq %rax, %r9 + movq 24($ap), %rax + movq %rdx, %r10 + adcq \$0, %r10 + + mulq %rbx + addq %rax, %r10 + movq 32($ap), %rax + movq %rdx, %r11 + adcq \$0, %r11 + + mulq %rbx + addq %rax, %r11 + movq 40($ap), %rax + movq %rdx, %r12 + adcq \$0, %r12 + + mulq %rbx + addq %rax, %r12 + movq 48($ap), %rax + movq %rdx, %r13 + adcq \$0, %r13 + + mulq %rbx + addq %rax, %r13 + movq 56($ap), %rax + movq %rdx, %r14 + adcq \$0, %r14 + + mulq %rbx + addq %rax, %r14 + movq ($ap), %rax + movq %rdx, %r15 + adcq \$0, %r15 + + leaq 8($bp), $bp + leaq 8(%rdi), %rdi + + movl \$7, %ecx + jmp .Loop_mul + +.align 32 +.Loop_mul: + movq ($bp), %rbx + mulq %rbx + addq %rax, %r8 + movq 8($ap), %rax + movq %r8, (%rdi) + movq %rdx, %r8 + adcq \$0, %r8 + + mulq %rbx + addq %rax, %r9 + movq 16($ap), %rax + adcq \$0, %rdx + addq %r9, %r8 + movq %rdx, %r9 + adcq \$0, %r9 + + mulq %rbx + addq %rax, %r10 + movq 24($ap), %rax + adcq \$0, %rdx + addq %r10, %r9 + movq %rdx, %r10 + adcq \$0, %r10 + + mulq %rbx + addq %rax, %r11 + movq 32($ap), %rax + adcq \$0, %rdx + addq %r11, %r10 + movq %rdx, %r11 + adcq \$0, %r11 + + mulq %rbx + addq %rax, %r12 + movq 40($ap), %rax + adcq \$0, %rdx + addq %r12, %r11 + movq %rdx, %r12 + adcq \$0, %r12 + + mulq %rbx + addq %rax, %r13 + movq 48($ap), %rax + adcq \$0, %rdx + addq %r13, %r12 + movq %rdx, %r13 + adcq \$0, %r13 + + mulq %rbx + addq %rax, %r14 + movq 56($ap), %rax + adcq \$0, %rdx + addq %r14, %r13 + movq %rdx, %r14 + leaq 8($bp), $bp + adcq \$0, %r14 + + mulq %rbx + addq %rax, %r15 + movq ($ap), %rax + adcq \$0, %rdx + addq %r15, %r14 + movq %rdx, %r15 + adcq \$0, %r15 + + leaq 8(%rdi), %rdi + + decl %ecx + jnz .Loop_mul + + movq %r8, (%rdi) + movq %r9, 8(%rdi) + movq %r10, 16(%rdi) + movq %r11, 24(%rdi) + movq %r12, 32(%rdi) + movq %r13, 40(%rdi) + movq %r14, 48(%rdi) + movq %r15, 56(%rdi) + + ret +.size __rsaz_512_mul,.-__rsaz_512_mul +___ +} +if ($addx) { + # __rsaz_512_mulx + # + # input: %rsi - ap, %rbp - bp + # ouput: + # clobbers: everything +my ($ap,$bp,$zero) = ("%rsi","%rbp","%rdi"); +$code.=<<___; +.type __rsaz_512_mulx,\@abi-omnipotent +.align 32 +__rsaz_512_mulx: + mulx ($ap), %rbx, %r8 # initial %rdx preloaded by caller + mov \$-6, %rcx + + mulx 8($ap), %rax, %r9 + movq %rbx, 8(%rsp) + + mulx 16($ap), %rbx, %r10 + adc %rax, %r8 + + mulx 24($ap), %rax, %r11 + adc %rbx, %r9 + + mulx 32($ap), %rbx, %r12 + adc %rax, %r10 + + mulx 40($ap), %rax, %r13 + adc %rbx, %r11 + + mulx 48($ap), %rbx, %r14 + adc %rax, %r12 + + mulx 56($ap), %rax, %r15 + mov 8($bp), %rdx + adc %rbx, %r13 + adc %rax, %r14 + adc \$0, %r15 + + xor $zero, $zero # cf=0,of=0 + jmp .Loop_mulx + +.align 32 +.Loop_mulx: + movq %r8, %rbx + mulx ($ap), %rax, %r8 + adcx %rax, %rbx + adox %r9, %r8 + + mulx 8($ap), %rax, %r9 + adcx %rax, %r8 + adox %r10, %r9 + + mulx 16($ap), %rax, %r10 + adcx %rax, %r9 + adox %r11, %r10 + + mulx 24($ap), %rax, %r11 + adcx %rax, %r10 + adox %r12, %r11 + + .byte 0x3e,0xc4,0x62,0xfb,0xf6,0xa6,0x20,0x00,0x00,0x00 # mulx 32($ap), %rax, %r12 + adcx %rax, %r11 + adox %r13, %r12 + + mulx 40($ap), %rax, %r13 + adcx %rax, %r12 + adox %r14, %r13 + + mulx 48($ap), %rax, %r14 + adcx %rax, %r13 + adox %r15, %r14 + + mulx 56($ap), %rax, %r15 + movq 64($bp,%rcx,8), %rdx + movq %rbx, 8+64-8(%rsp,%rcx,8) + adcx %rax, %r14 + adox $zero, %r15 + adcx $zero, %r15 # cf=0 + + inc %rcx # of=0 + jnz .Loop_mulx + + movq %r8, %rbx + mulx ($ap), %rax, %r8 + adcx %rax, %rbx + adox %r9, %r8 + + .byte 0xc4,0x62,0xfb,0xf6,0x8e,0x08,0x00,0x00,0x00 # mulx 8($ap), %rax, %r9 + adcx %rax, %r8 + adox %r10, %r9 + + .byte 0xc4,0x62,0xfb,0xf6,0x96,0x10,0x00,0x00,0x00 # mulx 16($ap), %rax, %r10 + adcx %rax, %r9 + adox %r11, %r10 + + mulx 24($ap), %rax, %r11 + adcx %rax, %r10 + adox %r12, %r11 + + mulx 32($ap), %rax, %r12 + adcx %rax, %r11 + adox %r13, %r12 + + mulx 40($ap), %rax, %r13 + adcx %rax, %r12 + adox %r14, %r13 + + .byte 0xc4,0x62,0xfb,0xf6,0xb6,0x30,0x00,0x00,0x00 # mulx 48($ap), %rax, %r14 + adcx %rax, %r13 + adox %r15, %r14 + + .byte 0xc4,0x62,0xfb,0xf6,0xbe,0x38,0x00,0x00,0x00 # mulx 56($ap), %rax, %r15 + adcx %rax, %r14 + adox $zero, %r15 + adcx $zero, %r15 + + mov %rbx, 8+64-8(%rsp) + mov %r8, 8+64(%rsp) + mov %r9, 8+64+8(%rsp) + mov %r10, 8+64+16(%rsp) + mov %r11, 8+64+24(%rsp) + mov %r12, 8+64+32(%rsp) + mov %r13, 8+64+40(%rsp) + mov %r14, 8+64+48(%rsp) + mov %r15, 8+64+56(%rsp) + + ret +.size __rsaz_512_mulx,.-__rsaz_512_mulx +___ +} +{ +my ($out,$inp,$power)= $win64 ? ("%rcx","%rdx","%r8d") : ("%rdi","%rsi","%edx"); +$code.=<<___; +.globl rsaz_512_scatter4 +.type rsaz_512_scatter4,\@abi-omnipotent +.align 16 +rsaz_512_scatter4: + leaq ($out,$power,4), $out + movl \$8, %r9d + jmp .Loop_scatter +.align 16 +.Loop_scatter: + movq ($inp), %rax + leaq 8($inp), $inp + movl %eax, ($out) + shrq \$32, %rax + movl %eax, 64($out) + leaq 128($out), $out + decl %r9d + jnz .Loop_scatter + ret +.size rsaz_512_scatter4,.-rsaz_512_scatter4 + +.globl rsaz_512_gather4 +.type rsaz_512_gather4,\@abi-omnipotent +.align 16 +rsaz_512_gather4: + leaq ($inp,$power,4), $inp + movl \$8, %r9d + jmp .Loop_gather +.align 16 +.Loop_gather: + movl ($inp), %eax + movl 64($inp), %r8d + leaq 128($inp), $inp + shlq \$32, %r8 + or %r8, %rax + movq %rax, ($out) + leaq 8($out), $out + decl %r9d + jnz .Loop_gather + ret +.size rsaz_512_gather4,.-rsaz_512_gather4 +___ +} + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # end of prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + lea 128+24+48(%rax),%rax + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov -48(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lcommon_seh_tail: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size sqr_handler,.-sqr_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_rsaz_512_sqr + .rva .LSEH_end_rsaz_512_sqr + .rva .LSEH_info_rsaz_512_sqr + + .rva .LSEH_begin_rsaz_512_mul + .rva .LSEH_end_rsaz_512_mul + .rva .LSEH_info_rsaz_512_mul + + .rva .LSEH_begin_rsaz_512_mul_gather4 + .rva .LSEH_end_rsaz_512_mul_gather4 + .rva .LSEH_info_rsaz_512_mul_gather4 + + .rva .LSEH_begin_rsaz_512_mul_scatter4 + .rva .LSEH_end_rsaz_512_mul_scatter4 + .rva .LSEH_info_rsaz_512_mul_scatter4 + + .rva .LSEH_begin_rsaz_512_mul_by_one + .rva .LSEH_end_rsaz_512_mul_by_one + .rva .LSEH_info_rsaz_512_mul_by_one + +.section .xdata +.align 8 +.LSEH_info_rsaz_512_sqr: + .byte 9,0,0,0 + .rva se_handler + .rva .Lsqr_body,.Lsqr_epilogue # HandlerData[] +.LSEH_info_rsaz_512_mul: + .byte 9,0,0,0 + .rva se_handler + .rva .Lmul_body,.Lmul_epilogue # HandlerData[] +.LSEH_info_rsaz_512_mul_gather4: + .byte 9,0,0,0 + .rva se_handler + .rva .Lmul_gather4_body,.Lmul_gather4_epilogue # HandlerData[] +.LSEH_info_rsaz_512_mul_scatter4: + .byte 9,0,0,0 + .rva se_handler + .rva .Lmul_scatter4_body,.Lmul_scatter4_epilogue # HandlerData[] +.LSEH_info_rsaz_512_mul_by_one: + .byte 9,0,0,0 + .rva se_handler + .rva .Lmul_by_one_body,.Lmul_by_one_epilogue # HandlerData[] +___ +} + +$code =~ s/\`([^\`]*)\`/eval $1/gem; +print $code; +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/x86-mont.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86-mont.pl new file mode 100644 index 00000000..0626b487 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86-mont.pl @@ -0,0 +1,592 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# October 2005 +# +# This is a "teaser" code, as it can be improved in several ways... +# First of all non-SSE2 path should be implemented (yes, for now it +# performs Montgomery multiplication/convolution only on SSE2-capable +# CPUs such as P4, others fall down to original code). Then inner loop +# can be unrolled and modulo-scheduled to improve ILP and possibly +# moved to 128-bit XMM register bank (though it would require input +# rearrangement and/or increase bus bandwidth utilization). Dedicated +# squaring procedure should give further performance improvement... +# Yet, for being draft, the code improves rsa512 *sign* benchmark by +# 110%(!), rsa1024 one - by 70% and rsa4096 - by 20%:-) + +# December 2006 +# +# Modulo-scheduling SSE2 loops results in further 15-20% improvement. +# Integer-only code [being equipped with dedicated squaring procedure] +# gives ~40% on rsa512 sign benchmark... + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],$0); + +$sse2=0; +for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } + +&external_label("OPENSSL_ia32cap_P") if ($sse2); + +&function_begin("bn_mul_mont"); + +$i="edx"; +$j="ecx"; +$ap="esi"; $tp="esi"; # overlapping variables!!! +$rp="edi"; $bp="edi"; # overlapping variables!!! +$np="ebp"; +$num="ebx"; + +$_num=&DWP(4*0,"esp"); # stack top layout +$_rp=&DWP(4*1,"esp"); +$_ap=&DWP(4*2,"esp"); +$_bp=&DWP(4*3,"esp"); +$_np=&DWP(4*4,"esp"); +$_n0=&DWP(4*5,"esp"); $_n0q=&QWP(4*5,"esp"); +$_sp=&DWP(4*6,"esp"); +$_bpend=&DWP(4*7,"esp"); +$frame=32; # size of above frame rounded up to 16n + + &xor ("eax","eax"); + &mov ("edi",&wparam(5)); # int num + &cmp ("edi",4); + &jl (&label("just_leave")); + + &lea ("esi",&wparam(0)); # put aside pointer to argument block + &lea ("edx",&wparam(1)); # load ap + &mov ("ebp","esp"); # saved stack pointer! + &add ("edi",2); # extra two words on top of tp + &neg ("edi"); + &lea ("esp",&DWP(-$frame,"esp","edi",4)); # alloca($frame+4*(num+2)) + &neg ("edi"); + + # minimize cache contention by arraning 2K window between stack + # pointer and ap argument [np is also position sensitive vector, + # but it's assumed to be near ap, as it's allocated at ~same + # time]. + &mov ("eax","esp"); + &sub ("eax","edx"); + &and ("eax",2047); + &sub ("esp","eax"); # this aligns sp and ap modulo 2048 + + &xor ("edx","esp"); + &and ("edx",2048); + &xor ("edx",2048); + &sub ("esp","edx"); # this splits them apart modulo 4096 + + &and ("esp",-64); # align to cache line + + ################################# load argument block... + &mov ("eax",&DWP(0*4,"esi"));# BN_ULONG *rp + &mov ("ebx",&DWP(1*4,"esi"));# const BN_ULONG *ap + &mov ("ecx",&DWP(2*4,"esi"));# const BN_ULONG *bp + &mov ("edx",&DWP(3*4,"esi"));# const BN_ULONG *np + &mov ("esi",&DWP(4*4,"esi"));# const BN_ULONG *n0 + #&mov ("edi",&DWP(5*4,"esi"));# int num + + &mov ("esi",&DWP(0,"esi")); # pull n0[0] + &mov ($_rp,"eax"); # ... save a copy of argument block + &mov ($_ap,"ebx"); + &mov ($_bp,"ecx"); + &mov ($_np,"edx"); + &mov ($_n0,"esi"); + &lea ($num,&DWP(-3,"edi")); # num=num-1 to assist modulo-scheduling + #&mov ($_num,$num); # redundant as $num is not reused + &mov ($_sp,"ebp"); # saved stack pointer! + +if($sse2) { +$acc0="mm0"; # mmx register bank layout +$acc1="mm1"; +$car0="mm2"; +$car1="mm3"; +$mul0="mm4"; +$mul1="mm5"; +$temp="mm6"; +$mask="mm7"; + + &picmeup("eax","OPENSSL_ia32cap_P"); + &bt (&DWP(0,"eax"),26); + &jnc (&label("non_sse2")); + + &mov ("eax",-1); + &movd ($mask,"eax"); # mask 32 lower bits + + &mov ($ap,$_ap); # load input pointers + &mov ($bp,$_bp); + &mov ($np,$_np); + + &xor ($i,$i); # i=0 + &xor ($j,$j); # j=0 + + &movd ($mul0,&DWP(0,$bp)); # bp[0] + &movd ($mul1,&DWP(0,$ap)); # ap[0] + &movd ($car1,&DWP(0,$np)); # np[0] + + &pmuludq($mul1,$mul0); # ap[0]*bp[0] + &movq ($car0,$mul1); + &movq ($acc0,$mul1); # I wish movd worked for + &pand ($acc0,$mask); # inter-register transfers + + &pmuludq($mul1,$_n0q); # *=n0 + + &pmuludq($car1,$mul1); # "t[0]"*np[0]*n0 + &paddq ($car1,$acc0); + + &movd ($acc1,&DWP(4,$np)); # np[1] + &movd ($acc0,&DWP(4,$ap)); # ap[1] + + &psrlq ($car0,32); + &psrlq ($car1,32); + + &inc ($j); # j++ +&set_label("1st",16); + &pmuludq($acc0,$mul0); # ap[j]*bp[0] + &pmuludq($acc1,$mul1); # np[j]*m1 + &paddq ($car0,$acc0); # +=c0 + &paddq ($car1,$acc1); # +=c1 + + &movq ($acc0,$car0); + &pand ($acc0,$mask); + &movd ($acc1,&DWP(4,$np,$j,4)); # np[j+1] + &paddq ($car1,$acc0); # +=ap[j]*bp[0]; + &movd ($acc0,&DWP(4,$ap,$j,4)); # ap[j+1] + &psrlq ($car0,32); + &movd (&DWP($frame-4,"esp",$j,4),$car1); # tp[j-1]= + &psrlq ($car1,32); + + &lea ($j,&DWP(1,$j)); + &cmp ($j,$num); + &jl (&label("1st")); + + &pmuludq($acc0,$mul0); # ap[num-1]*bp[0] + &pmuludq($acc1,$mul1); # np[num-1]*m1 + &paddq ($car0,$acc0); # +=c0 + &paddq ($car1,$acc1); # +=c1 + + &movq ($acc0,$car0); + &pand ($acc0,$mask); + &paddq ($car1,$acc0); # +=ap[num-1]*bp[0]; + &movd (&DWP($frame-4,"esp",$j,4),$car1); # tp[num-2]= + + &psrlq ($car0,32); + &psrlq ($car1,32); + + &paddq ($car1,$car0); + &movq (&QWP($frame,"esp",$num,4),$car1); # tp[num].tp[num-1] + + &inc ($i); # i++ +&set_label("outer"); + &xor ($j,$j); # j=0 + + &movd ($mul0,&DWP(0,$bp,$i,4)); # bp[i] + &movd ($mul1,&DWP(0,$ap)); # ap[0] + &movd ($temp,&DWP($frame,"esp")); # tp[0] + &movd ($car1,&DWP(0,$np)); # np[0] + &pmuludq($mul1,$mul0); # ap[0]*bp[i] + + &paddq ($mul1,$temp); # +=tp[0] + &movq ($acc0,$mul1); + &movq ($car0,$mul1); + &pand ($acc0,$mask); + + &pmuludq($mul1,$_n0q); # *=n0 + + &pmuludq($car1,$mul1); + &paddq ($car1,$acc0); + + &movd ($temp,&DWP($frame+4,"esp")); # tp[1] + &movd ($acc1,&DWP(4,$np)); # np[1] + &movd ($acc0,&DWP(4,$ap)); # ap[1] + + &psrlq ($car0,32); + &psrlq ($car1,32); + &paddq ($car0,$temp); # +=tp[1] + + &inc ($j); # j++ + &dec ($num); +&set_label("inner"); + &pmuludq($acc0,$mul0); # ap[j]*bp[i] + &pmuludq($acc1,$mul1); # np[j]*m1 + &paddq ($car0,$acc0); # +=c0 + &paddq ($car1,$acc1); # +=c1 + + &movq ($acc0,$car0); + &movd ($temp,&DWP($frame+4,"esp",$j,4));# tp[j+1] + &pand ($acc0,$mask); + &movd ($acc1,&DWP(4,$np,$j,4)); # np[j+1] + &paddq ($car1,$acc0); # +=ap[j]*bp[i]+tp[j] + &movd ($acc0,&DWP(4,$ap,$j,4)); # ap[j+1] + &psrlq ($car0,32); + &movd (&DWP($frame-4,"esp",$j,4),$car1);# tp[j-1]= + &psrlq ($car1,32); + &paddq ($car0,$temp); # +=tp[j+1] + + &dec ($num); + &lea ($j,&DWP(1,$j)); # j++ + &jnz (&label("inner")); + + &mov ($num,$j); + &pmuludq($acc0,$mul0); # ap[num-1]*bp[i] + &pmuludq($acc1,$mul1); # np[num-1]*m1 + &paddq ($car0,$acc0); # +=c0 + &paddq ($car1,$acc1); # +=c1 + + &movq ($acc0,$car0); + &pand ($acc0,$mask); + &paddq ($car1,$acc0); # +=ap[num-1]*bp[i]+tp[num-1] + &movd (&DWP($frame-4,"esp",$j,4),$car1); # tp[num-2]= + &psrlq ($car0,32); + &psrlq ($car1,32); + + &movd ($temp,&DWP($frame+4,"esp",$num,4)); # += tp[num] + &paddq ($car1,$car0); + &paddq ($car1,$temp); + &movq (&QWP($frame,"esp",$num,4),$car1); # tp[num].tp[num-1] + + &lea ($i,&DWP(1,$i)); # i++ + &cmp ($i,$num); + &jle (&label("outer")); + + &emms (); # done with mmx bank + &jmp (&label("common_tail")); + +&set_label("non_sse2",16); +} + +if (0) { + &mov ("esp",$_sp); + &xor ("eax","eax"); # signal "not fast enough [yet]" + &jmp (&label("just_leave")); + # While the below code provides competitive performance for + # all key lengthes on modern Intel cores, it's still more + # than 10% slower for 4096-bit key elsewhere:-( "Competitive" + # means compared to the original integer-only assembler. + # 512-bit RSA sign is better by ~40%, but that's about all + # one can say about all CPUs... +} else { +$inp="esi"; # integer path uses these registers differently +$word="edi"; +$carry="ebp"; + + &mov ($inp,$_ap); + &lea ($carry,&DWP(1,$num)); + &mov ($word,$_bp); + &xor ($j,$j); # j=0 + &mov ("edx",$inp); + &and ($carry,1); # see if num is even + &sub ("edx",$word); # see if ap==bp + &lea ("eax",&DWP(4,$word,$num,4)); # &bp[num] + &or ($carry,"edx"); + &mov ($word,&DWP(0,$word)); # bp[0] + &jz (&label("bn_sqr_mont")); + &mov ($_bpend,"eax"); + &mov ("eax",&DWP(0,$inp)); + &xor ("edx","edx"); + +&set_label("mull",16); + &mov ($carry,"edx"); + &mul ($word); # ap[j]*bp[0] + &add ($carry,"eax"); + &lea ($j,&DWP(1,$j)); + &adc ("edx",0); + &mov ("eax",&DWP(0,$inp,$j,4)); # ap[j+1] + &cmp ($j,$num); + &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j]= + &jl (&label("mull")); + + &mov ($carry,"edx"); + &mul ($word); # ap[num-1]*bp[0] + &mov ($word,$_n0); + &add ("eax",$carry); + &mov ($inp,$_np); + &adc ("edx",0); + &imul ($word,&DWP($frame,"esp")); # n0*tp[0] + + &mov (&DWP($frame,"esp",$num,4),"eax"); # tp[num-1]= + &xor ($j,$j); + &mov (&DWP($frame+4,"esp",$num,4),"edx"); # tp[num]= + &mov (&DWP($frame+8,"esp",$num,4),$j); # tp[num+1]= + + &mov ("eax",&DWP(0,$inp)); # np[0] + &mul ($word); # np[0]*m + &add ("eax",&DWP($frame,"esp")); # +=tp[0] + &mov ("eax",&DWP(4,$inp)); # np[1] + &adc ("edx",0); + &inc ($j); + + &jmp (&label("2ndmadd")); + +&set_label("1stmadd",16); + &mov ($carry,"edx"); + &mul ($word); # ap[j]*bp[i] + &add ($carry,&DWP($frame,"esp",$j,4)); # +=tp[j] + &lea ($j,&DWP(1,$j)); + &adc ("edx",0); + &add ($carry,"eax"); + &mov ("eax",&DWP(0,$inp,$j,4)); # ap[j+1] + &adc ("edx",0); + &cmp ($j,$num); + &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j]= + &jl (&label("1stmadd")); + + &mov ($carry,"edx"); + &mul ($word); # ap[num-1]*bp[i] + &add ("eax",&DWP($frame,"esp",$num,4)); # +=tp[num-1] + &mov ($word,$_n0); + &adc ("edx",0); + &mov ($inp,$_np); + &add ($carry,"eax"); + &adc ("edx",0); + &imul ($word,&DWP($frame,"esp")); # n0*tp[0] + + &xor ($j,$j); + &add ("edx",&DWP($frame+4,"esp",$num,4)); # carry+=tp[num] + &mov (&DWP($frame,"esp",$num,4),$carry); # tp[num-1]= + &adc ($j,0); + &mov ("eax",&DWP(0,$inp)); # np[0] + &mov (&DWP($frame+4,"esp",$num,4),"edx"); # tp[num]= + &mov (&DWP($frame+8,"esp",$num,4),$j); # tp[num+1]= + + &mul ($word); # np[0]*m + &add ("eax",&DWP($frame,"esp")); # +=tp[0] + &mov ("eax",&DWP(4,$inp)); # np[1] + &adc ("edx",0); + &mov ($j,1); + +&set_label("2ndmadd",16); + &mov ($carry,"edx"); + &mul ($word); # np[j]*m + &add ($carry,&DWP($frame,"esp",$j,4)); # +=tp[j] + &lea ($j,&DWP(1,$j)); + &adc ("edx",0); + &add ($carry,"eax"); + &mov ("eax",&DWP(0,$inp,$j,4)); # np[j+1] + &adc ("edx",0); + &cmp ($j,$num); + &mov (&DWP($frame-8,"esp",$j,4),$carry); # tp[j-1]= + &jl (&label("2ndmadd")); + + &mov ($carry,"edx"); + &mul ($word); # np[j]*m + &add ($carry,&DWP($frame,"esp",$num,4)); # +=tp[num-1] + &adc ("edx",0); + &add ($carry,"eax"); + &adc ("edx",0); + &mov (&DWP($frame-4,"esp",$num,4),$carry); # tp[num-2]= + + &xor ("eax","eax"); + &mov ($j,$_bp); # &bp[i] + &add ("edx",&DWP($frame+4,"esp",$num,4)); # carry+=tp[num] + &adc ("eax",&DWP($frame+8,"esp",$num,4)); # +=tp[num+1] + &lea ($j,&DWP(4,$j)); + &mov (&DWP($frame,"esp",$num,4),"edx"); # tp[num-1]= + &cmp ($j,$_bpend); + &mov (&DWP($frame+4,"esp",$num,4),"eax"); # tp[num]= + &je (&label("common_tail")); + + &mov ($word,&DWP(0,$j)); # bp[i+1] + &mov ($inp,$_ap); + &mov ($_bp,$j); # &bp[++i] + &xor ($j,$j); + &xor ("edx","edx"); + &mov ("eax",&DWP(0,$inp)); + &jmp (&label("1stmadd")); + +&set_label("bn_sqr_mont",16); +$sbit=$num; + &mov ($_num,$num); + &mov ($_bp,$j); # i=0 + + &mov ("eax",$word); # ap[0] + &mul ($word); # ap[0]*ap[0] + &mov (&DWP($frame,"esp"),"eax"); # tp[0]= + &mov ($sbit,"edx"); + &shr ("edx",1); + &and ($sbit,1); + &inc ($j); +&set_label("sqr",16); + &mov ("eax",&DWP(0,$inp,$j,4)); # ap[j] + &mov ($carry,"edx"); + &mul ($word); # ap[j]*ap[0] + &add ("eax",$carry); + &lea ($j,&DWP(1,$j)); + &adc ("edx",0); + &lea ($carry,&DWP(0,$sbit,"eax",2)); + &shr ("eax",31); + &cmp ($j,$_num); + &mov ($sbit,"eax"); + &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j]= + &jl (&label("sqr")); + + &mov ("eax",&DWP(0,$inp,$j,4)); # ap[num-1] + &mov ($carry,"edx"); + &mul ($word); # ap[num-1]*ap[0] + &add ("eax",$carry); + &mov ($word,$_n0); + &adc ("edx",0); + &mov ($inp,$_np); + &lea ($carry,&DWP(0,$sbit,"eax",2)); + &imul ($word,&DWP($frame,"esp")); # n0*tp[0] + &shr ("eax",31); + &mov (&DWP($frame,"esp",$j,4),$carry); # tp[num-1]= + + &lea ($carry,&DWP(0,"eax","edx",2)); + &mov ("eax",&DWP(0,$inp)); # np[0] + &shr ("edx",31); + &mov (&DWP($frame+4,"esp",$j,4),$carry); # tp[num]= + &mov (&DWP($frame+8,"esp",$j,4),"edx"); # tp[num+1]= + + &mul ($word); # np[0]*m + &add ("eax",&DWP($frame,"esp")); # +=tp[0] + &mov ($num,$j); + &adc ("edx",0); + &mov ("eax",&DWP(4,$inp)); # np[1] + &mov ($j,1); + +&set_label("3rdmadd",16); + &mov ($carry,"edx"); + &mul ($word); # np[j]*m + &add ($carry,&DWP($frame,"esp",$j,4)); # +=tp[j] + &adc ("edx",0); + &add ($carry,"eax"); + &mov ("eax",&DWP(4,$inp,$j,4)); # np[j+1] + &adc ("edx",0); + &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j-1]= + + &mov ($carry,"edx"); + &mul ($word); # np[j+1]*m + &add ($carry,&DWP($frame+4,"esp",$j,4)); # +=tp[j+1] + &lea ($j,&DWP(2,$j)); + &adc ("edx",0); + &add ($carry,"eax"); + &mov ("eax",&DWP(0,$inp,$j,4)); # np[j+2] + &adc ("edx",0); + &cmp ($j,$num); + &mov (&DWP($frame-8,"esp",$j,4),$carry); # tp[j]= + &jl (&label("3rdmadd")); + + &mov ($carry,"edx"); + &mul ($word); # np[j]*m + &add ($carry,&DWP($frame,"esp",$num,4)); # +=tp[num-1] + &adc ("edx",0); + &add ($carry,"eax"); + &adc ("edx",0); + &mov (&DWP($frame-4,"esp",$num,4),$carry); # tp[num-2]= + + &mov ($j,$_bp); # i + &xor ("eax","eax"); + &mov ($inp,$_ap); + &add ("edx",&DWP($frame+4,"esp",$num,4)); # carry+=tp[num] + &adc ("eax",&DWP($frame+8,"esp",$num,4)); # +=tp[num+1] + &mov (&DWP($frame,"esp",$num,4),"edx"); # tp[num-1]= + &cmp ($j,$num); + &mov (&DWP($frame+4,"esp",$num,4),"eax"); # tp[num]= + &je (&label("common_tail")); + + &mov ($word,&DWP(4,$inp,$j,4)); # ap[i] + &lea ($j,&DWP(1,$j)); + &mov ("eax",$word); + &mov ($_bp,$j); # ++i + &mul ($word); # ap[i]*ap[i] + &add ("eax",&DWP($frame,"esp",$j,4)); # +=tp[i] + &adc ("edx",0); + &mov (&DWP($frame,"esp",$j,4),"eax"); # tp[i]= + &xor ($carry,$carry); + &cmp ($j,$num); + &lea ($j,&DWP(1,$j)); + &je (&label("sqrlast")); + + &mov ($sbit,"edx"); # zaps $num + &shr ("edx",1); + &and ($sbit,1); +&set_label("sqradd",16); + &mov ("eax",&DWP(0,$inp,$j,4)); # ap[j] + &mov ($carry,"edx"); + &mul ($word); # ap[j]*ap[i] + &add ("eax",$carry); + &lea ($carry,&DWP(0,"eax","eax")); + &adc ("edx",0); + &shr ("eax",31); + &add ($carry,&DWP($frame,"esp",$j,4)); # +=tp[j] + &lea ($j,&DWP(1,$j)); + &adc ("eax",0); + &add ($carry,$sbit); + &adc ("eax",0); + &cmp ($j,$_num); + &mov (&DWP($frame-4,"esp",$j,4),$carry); # tp[j]= + &mov ($sbit,"eax"); + &jle (&label("sqradd")); + + &mov ($carry,"edx"); + &add ("edx","edx"); + &shr ($carry,31); + &add ("edx",$sbit); + &adc ($carry,0); +&set_label("sqrlast"); + &mov ($word,$_n0); + &mov ($inp,$_np); + &imul ($word,&DWP($frame,"esp")); # n0*tp[0] + + &add ("edx",&DWP($frame,"esp",$j,4)); # +=tp[num] + &mov ("eax",&DWP(0,$inp)); # np[0] + &adc ($carry,0); + &mov (&DWP($frame,"esp",$j,4),"edx"); # tp[num]= + &mov (&DWP($frame+4,"esp",$j,4),$carry); # tp[num+1]= + + &mul ($word); # np[0]*m + &add ("eax",&DWP($frame,"esp")); # +=tp[0] + &lea ($num,&DWP(-1,$j)); + &adc ("edx",0); + &mov ($j,1); + &mov ("eax",&DWP(4,$inp)); # np[1] + + &jmp (&label("3rdmadd")); +} + +&set_label("common_tail",16); + &mov ($np,$_np); # load modulus pointer + &mov ($rp,$_rp); # load result pointer + &lea ($tp,&DWP($frame,"esp")); # [$ap and $bp are zapped] + + &mov ("eax",&DWP(0,$tp)); # tp[0] + &mov ($j,$num); # j=num-1 + &xor ($i,$i); # i=0 and clear CF! + +&set_label("sub",16); + &sbb ("eax",&DWP(0,$np,$i,4)); + &mov (&DWP(0,$rp,$i,4),"eax"); # rp[i]=tp[i]-np[i] + &dec ($j); # doesn't affect CF! + &mov ("eax",&DWP(4,$tp,$i,4)); # tp[i+1] + &lea ($i,&DWP(1,$i)); # i++ + &jge (&label("sub")); + + &sbb ("eax",0); # handle upmost overflow bit + +&set_label("copy",16); # copy or in-place refresh + &mov ("edx",&DWP(0,$tp,$num,4)); + &mov ($np,&DWP(0,$rp,$num,4)); + &xor ("edx",$np); # conditional select + &and ("edx","eax"); + &xor ("edx",$np); + &mov (&DWP(0,$tp,$num,4),$j) # zap temporary vector + &mov (&DWP(0,$rp,$num,4),"edx"); # rp[i]=tp[i] + &dec ($num); + &jge (&label("copy")); + + &mov ("esp",$_sp); # pull saved stack pointer + &mov ("eax",1); +&set_label("just_leave"); +&function_end("bn_mul_mont"); + +&asciz("Montgomery Multiplication for x86, CRYPTOGAMS by "); + +&asm_finish(); diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-gcc.c b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-gcc.c new file mode 100644 index 00000000..0496b959 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-gcc.c @@ -0,0 +1,599 @@ +#include + +#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && !defined(OPENSSL_WINDOWS) + +#include "../internal.h" + +/* x86_64 BIGNUM accelerator version 0.1, December 2002. + * + * Implemented by Andy Polyakov for the OpenSSL + * project. + * + * Rights for redistribution and usage in source and binary forms are + * granted according to the OpenSSL license. Warranty of any kind is + * disclaimed. + * + * Q. Version 0.1? It doesn't sound like Andy, he used to assign real + * versions, like 1.0... + * A. Well, that's because this code is basically a quick-n-dirty + * proof-of-concept hack. As you can see it's implemented with + * inline assembler, which means that you're bound to GCC and that + * there might be enough room for further improvement. + * + * Q. Why inline assembler? + * A. x86_64 features own ABI which I'm not familiar with. This is + * why I decided to let the compiler take care of subroutine + * prologue/epilogue as well as register allocation. For reference. + * Win64 implements different ABI for AMD64, different from Linux. + * + * Q. How much faster does it get? + * A. 'apps/openssl speed rsa dsa' output with no-asm: + * + * sign verify sign/s verify/s + * rsa 512 bits 0.0006s 0.0001s 1683.8 18456.2 + * rsa 1024 bits 0.0028s 0.0002s 356.0 6407.0 + * rsa 2048 bits 0.0172s 0.0005s 58.0 1957.8 + * rsa 4096 bits 0.1155s 0.0018s 8.7 555.6 + * sign verify sign/s verify/s + * dsa 512 bits 0.0005s 0.0006s 2100.8 1768.3 + * dsa 1024 bits 0.0014s 0.0018s 692.3 559.2 + * dsa 2048 bits 0.0049s 0.0061s 204.7 165.0 + * + * 'apps/openssl speed rsa dsa' output with this module: + * + * sign verify sign/s verify/s + * rsa 512 bits 0.0004s 0.0000s 2767.1 33297.9 + * rsa 1024 bits 0.0012s 0.0001s 867.4 14674.7 + * rsa 2048 bits 0.0061s 0.0002s 164.0 5270.0 + * rsa 4096 bits 0.0384s 0.0006s 26.1 1650.8 + * sign verify sign/s verify/s + * dsa 512 bits 0.0002s 0.0003s 4442.2 3786.3 + * dsa 1024 bits 0.0005s 0.0007s 1835.1 1497.4 + * dsa 2048 bits 0.0016s 0.0020s 620.4 504.6 + * + * For the reference. IA-32 assembler implementation performs + * very much like 64-bit code compiled with no-asm on the same + * machine. + */ + + /* TODO(davidben): Get this file working on Windows x64. */ + +#undef mul +#undef mul_add + +#define asm __asm__ + +/* + * "m"(a), "+m"(r) is the way to favor DirectPath µ-code; + * "g"(0) let the compiler to decide where does it + * want to keep the value of zero; + */ +#define mul_add(r, a, word, carry) \ + do { \ + register BN_ULONG high, low; \ + asm("mulq %3" : "=a"(low), "=d"(high) : "a"(word), "m"(a) : "cc"); \ + asm("addq %2,%0; adcq %3,%1" \ + : "+r"(carry), "+d"(high) \ + : "a"(low), "g"(0) \ + : "cc"); \ + asm("addq %2,%0; adcq %3,%1" \ + : "+m"(r), "+d"(high) \ + : "r"(carry), "g"(0) \ + : "cc"); \ + carry = high; \ + } while (0) + +#define mul(r, a, word, carry) \ + do { \ + register BN_ULONG high, low; \ + asm("mulq %3" : "=a"(low), "=d"(high) : "a"(word), "g"(a) : "cc"); \ + asm("addq %2,%0; adcq %3,%1" \ + : "+r"(carry), "+d"(high) \ + : "a"(low), "g"(0) \ + : "cc"); \ + (r) = carry, carry = high; \ + } while (0) +#undef sqr +#define sqr(r0, r1, a) asm("mulq %2" : "=a"(r0), "=d"(r1) : "a"(a) : "cc"); + +BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, + BN_ULONG w) { + BN_ULONG c1 = 0; + + if (num <= 0) { + return (c1); + } + + while (num & ~3) { + mul_add(rp[0], ap[0], w, c1); + mul_add(rp[1], ap[1], w, c1); + mul_add(rp[2], ap[2], w, c1); + mul_add(rp[3], ap[3], w, c1); + ap += 4; + rp += 4; + num -= 4; + } + if (num) { + mul_add(rp[0], ap[0], w, c1); + if (--num == 0) { + return c1; + } + mul_add(rp[1], ap[1], w, c1); + if (--num == 0) { + return c1; + } + mul_add(rp[2], ap[2], w, c1); + return c1; + } + + return c1; +} + +BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w) { + BN_ULONG c1 = 0; + + if (num <= 0) { + return c1; + } + + while (num & ~3) { + mul(rp[0], ap[0], w, c1); + mul(rp[1], ap[1], w, c1); + mul(rp[2], ap[2], w, c1); + mul(rp[3], ap[3], w, c1); + ap += 4; + rp += 4; + num -= 4; + } + if (num) { + mul(rp[0], ap[0], w, c1); + if (--num == 0) { + return c1; + } + mul(rp[1], ap[1], w, c1); + if (--num == 0) { + return c1; + } + mul(rp[2], ap[2], w, c1); + } + return c1; +} + +void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) { + if (n <= 0) { + return; + } + + while (n & ~3) { + sqr(r[0], r[1], a[0]); + sqr(r[2], r[3], a[1]); + sqr(r[4], r[5], a[2]); + sqr(r[6], r[7], a[3]); + a += 4; + r += 8; + n -= 4; + } + if (n) { + sqr(r[0], r[1], a[0]); + if (--n == 0) { + return; + } + sqr(r[2], r[3], a[1]); + if (--n == 0) { + return; + } + sqr(r[4], r[5], a[2]); + } +} + +BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) { + BN_ULONG ret, waste; + + asm("divq %4" : "=a"(ret), "=d"(waste) : "a"(l), "d"(h), "g"(d) : "cc"); + + return ret; +} + +BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, + int n) { + BN_ULONG ret; + size_t i = 0; + + if (n <= 0) { + return 0; + } + + asm volatile ( + " subq %0,%0 \n" /* clear carry */ + " jmp 1f \n" + ".p2align 4 \n" + "1: movq (%4,%2,8),%0 \n" + " adcq (%5,%2,8),%0 \n" + " movq %0,(%3,%2,8) \n" + " lea 1(%2),%2 \n" + " loop 1b \n" + " sbbq %0,%0 \n" + : "=&r"(ret), "+c"(n), "+r"(i) + : "r"(rp), "r"(ap), "r"(bp) + : "cc", "memory"); + + return ret & 1; +} + +#ifndef SIMICS +BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, + int n) { + BN_ULONG ret; + size_t i = 0; + + if (n <= 0) { + return 0; + } + + asm volatile ( + " subq %0,%0 \n" /* clear borrow */ + " jmp 1f \n" + ".p2align 4 \n" + "1: movq (%4,%2,8),%0 \n" + " sbbq (%5,%2,8),%0 \n" + " movq %0,(%3,%2,8) \n" + " lea 1(%2),%2 \n" + " loop 1b \n" + " sbbq %0,%0 \n" + : "=&r"(ret), "+c"(n), "+r"(i) + : "r"(rp), "r"(ap), "r"(bp) + : "cc", "memory"); + + return ret & 1; +} +#else +/* Simics 1.4<7 has buggy sbbq:-( */ +#define BN_MASK2 0xffffffffffffffffL +BN_ULONG bn_sub_words(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n) { + BN_ULONG t1, t2; + int c = 0; + + if (n <= 0) { + return (BN_ULONG)0; + } + + for (;;) { + t1 = a[0]; + t2 = b[0]; + r[0] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + if (--n <= 0) { + break; + } + + t1 = a[1]; + t2 = b[1]; + r[1] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + if (--n <= 0) { + break; + } + + t1 = a[2]; + t2 = b[2]; + r[2] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + if (--n <= 0) { + break; + } + + t1 = a[3]; + t2 = b[3]; + r[3] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + if (--n <= 0) { + break; + } + + a += 4; + b += 4; + r += 4; + } + return c; +} +#endif + +/* mul_add_c(a,b,c0,c1,c2) -- c+=a*b for three word number c=(c2,c1,c0) */ +/* mul_add_c2(a,b,c0,c1,c2) -- c+=2*a*b for three word number c=(c2,c1,c0) */ +/* sqr_add_c(a,i,c0,c1,c2) -- c+=a[i]^2 for three word number c=(c2,c1,c0) */ +/* sqr_add_c2(a,i,c0,c1,c2) -- c+=2*a[i]*a[j] for three word number c=(c2,c1,c0) + */ + +/* Keep in mind that carrying into high part of multiplication result can not + * overflow, because it cannot be all-ones. */ +#define mul_add_c(a, b, c0, c1, c2) \ + do { \ + BN_ULONG t1, t2; \ + asm("mulq %3" : "=a"(t1), "=d"(t2) : "a"(a), "m"(b) : "cc"); \ + asm("addq %3,%0; adcq %4,%1; adcq %5,%2" \ + : "+r"(c0), "+r"(c1), "+r"(c2) \ + : "r"(t1), "r"(t2), "g"(0) \ + : "cc"); \ + } while (0) + +#define sqr_add_c(a, i, c0, c1, c2) \ + do { \ + BN_ULONG t1, t2; \ + asm("mulq %2" : "=a"(t1), "=d"(t2) : "a"(a[i]) : "cc"); \ + asm("addq %3,%0; adcq %4,%1; adcq %5,%2" \ + : "+r"(c0), "+r"(c1), "+r"(c2) \ + : "r"(t1), "r"(t2), "g"(0) \ + : "cc"); \ + } while (0) + +#define mul_add_c2(a, b, c0, c1, c2) \ + do { \ + BN_ULONG t1, t2; \ + asm("mulq %3" : "=a"(t1), "=d"(t2) : "a"(a), "m"(b) : "cc"); \ + asm("addq %3,%0; adcq %4,%1; adcq %5,%2" \ + : "+r"(c0), "+r"(c1), "+r"(c2) \ + : "r"(t1), "r"(t2), "g"(0) \ + : "cc"); \ + asm("addq %3,%0; adcq %4,%1; adcq %5,%2" \ + : "+r"(c0), "+r"(c1), "+r"(c2) \ + : "r"(t1), "r"(t2), "g"(0) \ + : "cc"); \ + } while (0) + +#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2) + +void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + mul_add_c(a[0], b[0], c1, c2, c3); + r[0] = c1; + c1 = 0; + mul_add_c(a[0], b[1], c2, c3, c1); + mul_add_c(a[1], b[0], c2, c3, c1); + r[1] = c2; + c2 = 0; + mul_add_c(a[2], b[0], c3, c1, c2); + mul_add_c(a[1], b[1], c3, c1, c2); + mul_add_c(a[0], b[2], c3, c1, c2); + r[2] = c3; + c3 = 0; + mul_add_c(a[0], b[3], c1, c2, c3); + mul_add_c(a[1], b[2], c1, c2, c3); + mul_add_c(a[2], b[1], c1, c2, c3); + mul_add_c(a[3], b[0], c1, c2, c3); + r[3] = c1; + c1 = 0; + mul_add_c(a[4], b[0], c2, c3, c1); + mul_add_c(a[3], b[1], c2, c3, c1); + mul_add_c(a[2], b[2], c2, c3, c1); + mul_add_c(a[1], b[3], c2, c3, c1); + mul_add_c(a[0], b[4], c2, c3, c1); + r[4] = c2; + c2 = 0; + mul_add_c(a[0], b[5], c3, c1, c2); + mul_add_c(a[1], b[4], c3, c1, c2); + mul_add_c(a[2], b[3], c3, c1, c2); + mul_add_c(a[3], b[2], c3, c1, c2); + mul_add_c(a[4], b[1], c3, c1, c2); + mul_add_c(a[5], b[0], c3, c1, c2); + r[5] = c3; + c3 = 0; + mul_add_c(a[6], b[0], c1, c2, c3); + mul_add_c(a[5], b[1], c1, c2, c3); + mul_add_c(a[4], b[2], c1, c2, c3); + mul_add_c(a[3], b[3], c1, c2, c3); + mul_add_c(a[2], b[4], c1, c2, c3); + mul_add_c(a[1], b[5], c1, c2, c3); + mul_add_c(a[0], b[6], c1, c2, c3); + r[6] = c1; + c1 = 0; + mul_add_c(a[0], b[7], c2, c3, c1); + mul_add_c(a[1], b[6], c2, c3, c1); + mul_add_c(a[2], b[5], c2, c3, c1); + mul_add_c(a[3], b[4], c2, c3, c1); + mul_add_c(a[4], b[3], c2, c3, c1); + mul_add_c(a[5], b[2], c2, c3, c1); + mul_add_c(a[6], b[1], c2, c3, c1); + mul_add_c(a[7], b[0], c2, c3, c1); + r[7] = c2; + c2 = 0; + mul_add_c(a[7], b[1], c3, c1, c2); + mul_add_c(a[6], b[2], c3, c1, c2); + mul_add_c(a[5], b[3], c3, c1, c2); + mul_add_c(a[4], b[4], c3, c1, c2); + mul_add_c(a[3], b[5], c3, c1, c2); + mul_add_c(a[2], b[6], c3, c1, c2); + mul_add_c(a[1], b[7], c3, c1, c2); + r[8] = c3; + c3 = 0; + mul_add_c(a[2], b[7], c1, c2, c3); + mul_add_c(a[3], b[6], c1, c2, c3); + mul_add_c(a[4], b[5], c1, c2, c3); + mul_add_c(a[5], b[4], c1, c2, c3); + mul_add_c(a[6], b[3], c1, c2, c3); + mul_add_c(a[7], b[2], c1, c2, c3); + r[9] = c1; + c1 = 0; + mul_add_c(a[7], b[3], c2, c3, c1); + mul_add_c(a[6], b[4], c2, c3, c1); + mul_add_c(a[5], b[5], c2, c3, c1); + mul_add_c(a[4], b[6], c2, c3, c1); + mul_add_c(a[3], b[7], c2, c3, c1); + r[10] = c2; + c2 = 0; + mul_add_c(a[4], b[7], c3, c1, c2); + mul_add_c(a[5], b[6], c3, c1, c2); + mul_add_c(a[6], b[5], c3, c1, c2); + mul_add_c(a[7], b[4], c3, c1, c2); + r[11] = c3; + c3 = 0; + mul_add_c(a[7], b[5], c1, c2, c3); + mul_add_c(a[6], b[6], c1, c2, c3); + mul_add_c(a[5], b[7], c1, c2, c3); + r[12] = c1; + c1 = 0; + mul_add_c(a[6], b[7], c2, c3, c1); + mul_add_c(a[7], b[6], c2, c3, c1); + r[13] = c2; + c2 = 0; + mul_add_c(a[7], b[7], c3, c1, c2); + r[14] = c3; + r[15] = c1; +} + +void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + mul_add_c(a[0], b[0], c1, c2, c3); + r[0] = c1; + c1 = 0; + mul_add_c(a[0], b[1], c2, c3, c1); + mul_add_c(a[1], b[0], c2, c3, c1); + r[1] = c2; + c2 = 0; + mul_add_c(a[2], b[0], c3, c1, c2); + mul_add_c(a[1], b[1], c3, c1, c2); + mul_add_c(a[0], b[2], c3, c1, c2); + r[2] = c3; + c3 = 0; + mul_add_c(a[0], b[3], c1, c2, c3); + mul_add_c(a[1], b[2], c1, c2, c3); + mul_add_c(a[2], b[1], c1, c2, c3); + mul_add_c(a[3], b[0], c1, c2, c3); + r[3] = c1; + c1 = 0; + mul_add_c(a[3], b[1], c2, c3, c1); + mul_add_c(a[2], b[2], c2, c3, c1); + mul_add_c(a[1], b[3], c2, c3, c1); + r[4] = c2; + c2 = 0; + mul_add_c(a[2], b[3], c3, c1, c2); + mul_add_c(a[3], b[2], c3, c1, c2); + r[5] = c3; + c3 = 0; + mul_add_c(a[3], b[3], c1, c2, c3); + r[6] = c1; + r[7] = c2; +} + +void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + sqr_add_c(a, 0, c1, c2, c3); + r[0] = c1; + c1 = 0; + sqr_add_c2(a, 1, 0, c2, c3, c1); + r[1] = c2; + c2 = 0; + sqr_add_c(a, 1, c3, c1, c2); + sqr_add_c2(a, 2, 0, c3, c1, c2); + r[2] = c3; + c3 = 0; + sqr_add_c2(a, 3, 0, c1, c2, c3); + sqr_add_c2(a, 2, 1, c1, c2, c3); + r[3] = c1; + c1 = 0; + sqr_add_c(a, 2, c2, c3, c1); + sqr_add_c2(a, 3, 1, c2, c3, c1); + sqr_add_c2(a, 4, 0, c2, c3, c1); + r[4] = c2; + c2 = 0; + sqr_add_c2(a, 5, 0, c3, c1, c2); + sqr_add_c2(a, 4, 1, c3, c1, c2); + sqr_add_c2(a, 3, 2, c3, c1, c2); + r[5] = c3; + c3 = 0; + sqr_add_c(a, 3, c1, c2, c3); + sqr_add_c2(a, 4, 2, c1, c2, c3); + sqr_add_c2(a, 5, 1, c1, c2, c3); + sqr_add_c2(a, 6, 0, c1, c2, c3); + r[6] = c1; + c1 = 0; + sqr_add_c2(a, 7, 0, c2, c3, c1); + sqr_add_c2(a, 6, 1, c2, c3, c1); + sqr_add_c2(a, 5, 2, c2, c3, c1); + sqr_add_c2(a, 4, 3, c2, c3, c1); + r[7] = c2; + c2 = 0; + sqr_add_c(a, 4, c3, c1, c2); + sqr_add_c2(a, 5, 3, c3, c1, c2); + sqr_add_c2(a, 6, 2, c3, c1, c2); + sqr_add_c2(a, 7, 1, c3, c1, c2); + r[8] = c3; + c3 = 0; + sqr_add_c2(a, 7, 2, c1, c2, c3); + sqr_add_c2(a, 6, 3, c1, c2, c3); + sqr_add_c2(a, 5, 4, c1, c2, c3); + r[9] = c1; + c1 = 0; + sqr_add_c(a, 5, c2, c3, c1); + sqr_add_c2(a, 6, 4, c2, c3, c1); + sqr_add_c2(a, 7, 3, c2, c3, c1); + r[10] = c2; + c2 = 0; + sqr_add_c2(a, 7, 4, c3, c1, c2); + sqr_add_c2(a, 6, 5, c3, c1, c2); + r[11] = c3; + c3 = 0; + sqr_add_c(a, 6, c1, c2, c3); + sqr_add_c2(a, 7, 5, c1, c2, c3); + r[12] = c1; + c1 = 0; + sqr_add_c2(a, 7, 6, c2, c3, c1); + r[13] = c2; + c2 = 0; + sqr_add_c(a, 7, c3, c1, c2); + r[14] = c3; + r[15] = c1; +} + +void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + sqr_add_c(a, 0, c1, c2, c3); + r[0] = c1; + c1 = 0; + sqr_add_c2(a, 1, 0, c2, c3, c1); + r[1] = c2; + c2 = 0; + sqr_add_c(a, 1, c3, c1, c2); + sqr_add_c2(a, 2, 0, c3, c1, c2); + r[2] = c3; + c3 = 0; + sqr_add_c2(a, 3, 0, c1, c2, c3); + sqr_add_c2(a, 2, 1, c1, c2, c3); + r[3] = c1; + c1 = 0; + sqr_add_c(a, 2, c2, c3, c1); + sqr_add_c2(a, 3, 1, c2, c3, c1); + r[4] = c2; + c2 = 0; + sqr_add_c2(a, 3, 2, c3, c1, c2); + r[5] = c3; + c3 = 0; + sqr_add_c(a, 3, c1, c2, c3); + r[6] = c1; + r[7] = c2; +} + +#endif /* !NO_ASM && X86_64 && !WINDOWS */ diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-mont.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-mont.pl new file mode 100644 index 00000000..39476ab0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-mont.pl @@ -0,0 +1,1401 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# October 2005. +# +# Montgomery multiplication routine for x86_64. While it gives modest +# 9% improvement of rsa4096 sign on Opteron, rsa512 sign runs more +# than twice, >2x, as fast. Most common rsa1024 sign is improved by +# respectful 50%. It remains to be seen if loop unrolling and +# dedicated squaring routine can provide further improvement... + +# July 2011. +# +# Add dedicated squaring procedure. Performance improvement varies +# from platform to platform, but in average it's ~5%/15%/25%/33% +# for 512-/1024-/2048-/4096-bit RSA *sign* benchmarks respectively. + +# August 2011. +# +# Unroll and modulo-schedule inner loops in such manner that they +# are "fallen through" for input lengths of 8, which is critical for +# 1024-bit RSA *sign*. Average performance improvement in comparison +# to *initial* version of this module from 2005 is ~0%/30%/40%/45% +# for 512-/1024-/2048-/4096-bit RSA *sign* benchmarks respectively. + +# June 2013. +# +# Optimize reduction in squaring procedure and improve 1024+-bit RSA +# sign performance by 10-16% on Intel Sandy Bridge and later +# (virtually same on non-Intel processors). + +# August 2013. +# +# Add MULX/ADOX/ADCX code path. + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $addx = ($1>=2.23); +} + +if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $addx = ($1>=2.10); +} + +if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $addx = ($1>=12); +} + +# int bn_mul_mont( +$rp="%rdi"; # BN_ULONG *rp, +$ap="%rsi"; # const BN_ULONG *ap, +$bp="%rdx"; # const BN_ULONG *bp, +$np="%rcx"; # const BN_ULONG *np, +$n0="%r8"; # const BN_ULONG *n0, +$num="%r9"; # int num); +$lo0="%r10"; +$hi0="%r11"; +$hi1="%r13"; +$i="%r14"; +$j="%r15"; +$m0="%rbx"; +$m1="%rbp"; + +$code=<<___; +.text + +.extern OPENSSL_ia32cap_P + +.globl bn_mul_mont +.type bn_mul_mont,\@function,6 +.align 16 +bn_mul_mont: + test \$3,${num}d + jnz .Lmul_enter + cmp \$8,${num}d + jb .Lmul_enter +___ +$code.=<<___ if ($addx); + mov OPENSSL_ia32cap_P+8(%rip),%r11d +___ +$code.=<<___; + cmp $ap,$bp + jne .Lmul4x_enter + test \$7,${num}d + jz .Lsqr8x_enter + jmp .Lmul4x_enter + +.align 16 +.Lmul_enter: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + mov ${num}d,${num}d + lea 2($num),%r10 + mov %rsp,%r11 + neg %r10 + lea (%rsp,%r10,8),%rsp # tp=alloca(8*(num+2)) + and \$-1024,%rsp # minimize TLB usage + + mov %r11,8(%rsp,$num,8) # tp[num+1]=%rsp +.Lmul_body: + mov $bp,%r12 # reassign $bp +___ + $bp="%r12"; +$code.=<<___; + mov ($n0),$n0 # pull n0[0] value + mov ($bp),$m0 # m0=bp[0] + mov ($ap),%rax + + xor $i,$i # i=0 + xor $j,$j # j=0 + + mov $n0,$m1 + mulq $m0 # ap[0]*bp[0] + mov %rax,$lo0 + mov ($np),%rax + + imulq $lo0,$m1 # "tp[0]"*n0 + mov %rdx,$hi0 + + mulq $m1 # np[0]*m1 + add %rax,$lo0 # discarded + mov 8($ap),%rax + adc \$0,%rdx + mov %rdx,$hi1 + + lea 1($j),$j # j++ + jmp .L1st_enter + +.align 16 +.L1st: + add %rax,$hi1 + mov ($ap,$j,8),%rax + adc \$0,%rdx + add $hi0,$hi1 # np[j]*m1+ap[j]*bp[0] + mov $lo0,$hi0 + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + +.L1st_enter: + mulq $m0 # ap[j]*bp[0] + add %rax,$hi0 + mov ($np,$j,8),%rax + adc \$0,%rdx + lea 1($j),$j # j++ + mov %rdx,$lo0 + + mulq $m1 # np[j]*m1 + cmp $num,$j + jne .L1st + + add %rax,$hi1 + mov ($ap),%rax # ap[0] + adc \$0,%rdx + add $hi0,$hi1 # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + mov $lo0,$hi0 + + xor %rdx,%rdx + add $hi0,$hi1 + adc \$0,%rdx + mov $hi1,-8(%rsp,$num,8) + mov %rdx,(%rsp,$num,8) # store upmost overflow bit + + lea 1($i),$i # i++ + jmp .Louter +.align 16 +.Louter: + mov ($bp,$i,8),$m0 # m0=bp[i] + xor $j,$j # j=0 + mov $n0,$m1 + mov (%rsp),$lo0 + mulq $m0 # ap[0]*bp[i] + add %rax,$lo0 # ap[0]*bp[i]+tp[0] + mov ($np),%rax + adc \$0,%rdx + + imulq $lo0,$m1 # tp[0]*n0 + mov %rdx,$hi0 + + mulq $m1 # np[0]*m1 + add %rax,$lo0 # discarded + mov 8($ap),%rax + adc \$0,%rdx + mov 8(%rsp),$lo0 # tp[1] + mov %rdx,$hi1 + + lea 1($j),$j # j++ + jmp .Linner_enter + +.align 16 +.Linner: + add %rax,$hi1 + mov ($ap,$j,8),%rax + adc \$0,%rdx + add $lo0,$hi1 # np[j]*m1+ap[j]*bp[i]+tp[j] + mov (%rsp,$j,8),$lo0 + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + +.Linner_enter: + mulq $m0 # ap[j]*bp[i] + add %rax,$hi0 + mov ($np,$j,8),%rax + adc \$0,%rdx + add $hi0,$lo0 # ap[j]*bp[i]+tp[j] + mov %rdx,$hi0 + adc \$0,$hi0 + lea 1($j),$j # j++ + + mulq $m1 # np[j]*m1 + cmp $num,$j + jne .Linner + + add %rax,$hi1 + mov ($ap),%rax # ap[0] + adc \$0,%rdx + add $lo0,$hi1 # np[j]*m1+ap[j]*bp[i]+tp[j] + mov (%rsp,$j,8),$lo0 + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + + xor %rdx,%rdx + add $hi0,$hi1 + adc \$0,%rdx + add $lo0,$hi1 # pull upmost overflow bit + adc \$0,%rdx + mov $hi1,-8(%rsp,$num,8) + mov %rdx,(%rsp,$num,8) # store upmost overflow bit + + lea 1($i),$i # i++ + cmp $num,$i + jb .Louter + + xor $i,$i # i=0 and clear CF! + mov (%rsp),%rax # tp[0] + lea (%rsp),$ap # borrow ap for tp + mov $num,$j # j=num + jmp .Lsub +.align 16 +.Lsub: sbb ($np,$i,8),%rax + mov %rax,($rp,$i,8) # rp[i]=tp[i]-np[i] + mov 8($ap,$i,8),%rax # tp[i+1] + lea 1($i),$i # i++ + dec $j # doesn't affect CF! + jnz .Lsub + + sbb \$0,%rax # handle upmost overflow bit + xor $i,$i + mov $num,$j # j=num +.align 16 +.Lcopy: # copy or in-place refresh + mov (%rsp,$i,8),$ap + mov ($rp,$i,8),$np + xor $np,$ap # conditional select: + and %rax,$ap # ((ap ^ np) & %rax) ^ np + xor $np,$ap # ap = borrow?tp:rp + mov $i,(%rsp,$i,8) # zap temporary vector + mov $ap,($rp,$i,8) # rp[i]=tp[i] + lea 1($i),$i + sub \$1,$j + jnz .Lcopy + + mov 8(%rsp,$num,8),%rsi # restore %rsp + mov \$1,%rax + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lmul_epilogue: + ret +.size bn_mul_mont,.-bn_mul_mont +___ +{{{ +my @A=("%r10","%r11"); +my @N=("%r13","%rdi"); +$code.=<<___; +.type bn_mul4x_mont,\@function,6 +.align 16 +bn_mul4x_mont: +.Lmul4x_enter: +___ +$code.=<<___ if ($addx); + and \$0x80100,%r11d + cmp \$0x80100,%r11d + je .Lmulx4x_enter +___ +$code.=<<___; + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + mov ${num}d,${num}d + lea 4($num),%r10 + mov %rsp,%r11 + neg %r10 + lea (%rsp,%r10,8),%rsp # tp=alloca(8*(num+4)) + and \$-1024,%rsp # minimize TLB usage + + mov %r11,8(%rsp,$num,8) # tp[num+1]=%rsp +.Lmul4x_body: + mov $rp,16(%rsp,$num,8) # tp[num+2]=$rp + mov %rdx,%r12 # reassign $bp +___ + $bp="%r12"; +$code.=<<___; + mov ($n0),$n0 # pull n0[0] value + mov ($bp),$m0 # m0=bp[0] + mov ($ap),%rax + + xor $i,$i # i=0 + xor $j,$j # j=0 + + mov $n0,$m1 + mulq $m0 # ap[0]*bp[0] + mov %rax,$A[0] + mov ($np),%rax + + imulq $A[0],$m1 # "tp[0]"*n0 + mov %rdx,$A[1] + + mulq $m1 # np[0]*m1 + add %rax,$A[0] # discarded + mov 8($ap),%rax + adc \$0,%rdx + mov %rdx,$N[1] + + mulq $m0 + add %rax,$A[1] + mov 8($np),%rax + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 + add %rax,$N[1] + mov 16($ap),%rax + adc \$0,%rdx + add $A[1],$N[1] + lea 4($j),$j # j++ + adc \$0,%rdx + mov $N[1],(%rsp) + mov %rdx,$N[0] + jmp .L1st4x +.align 16 +.L1st4x: + mulq $m0 # ap[j]*bp[0] + add %rax,$A[0] + mov -16($np,$j,8),%rax + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap,$j,8),%rax + adc \$0,%rdx + add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[0],-24(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[1] + mov -8($np,$j,8),%rax + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap,$j,8),%rax + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[1],-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[0] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[0] + mov ($np,$j,8),%rax + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov 8($ap,$j,8),%rax + adc \$0,%rdx + add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[0],-8(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[1] + mov 8($np,$j,8),%rax + adc \$0,%rdx + lea 4($j),$j # j++ + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov -16($ap,$j,8),%rax + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[1],-32(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[0] + cmp $num,$j + jb .L1st4x + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[0] + mov -16($np,$j,8),%rax + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap,$j,8),%rax + adc \$0,%rdx + add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[0],-24(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[1] + mov -8($np,$j,8),%rax + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap),%rax # ap[0] + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[1],-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[0] + + xor $N[1],$N[1] + add $A[0],$N[0] + adc \$0,$N[1] + mov $N[0],-8(%rsp,$j,8) + mov $N[1],(%rsp,$j,8) # store upmost overflow bit + + lea 1($i),$i # i++ +.align 4 +.Louter4x: + mov ($bp,$i,8),$m0 # m0=bp[i] + xor $j,$j # j=0 + mov (%rsp),$A[0] + mov $n0,$m1 + mulq $m0 # ap[0]*bp[i] + add %rax,$A[0] # ap[0]*bp[i]+tp[0] + mov ($np),%rax + adc \$0,%rdx + + imulq $A[0],$m1 # tp[0]*n0 + mov %rdx,$A[1] + + mulq $m1 # np[0]*m1 + add %rax,$A[0] # "$N[0]", discarded + mov 8($ap),%rax + adc \$0,%rdx + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov 8($np),%rax + adc \$0,%rdx + add 8(%rsp),$A[1] # +tp[1] + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov 16($ap),%rax + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[i]+tp[j] + lea 4($j),$j # j+=2 + adc \$0,%rdx + mov $N[1],(%rsp) # tp[j-1] + mov %rdx,$N[0] + jmp .Linner4x +.align 16 +.Linner4x: + mulq $m0 # ap[j]*bp[i] + add %rax,$A[0] + mov -16($np,$j,8),%rax + adc \$0,%rdx + add -16(%rsp,$j,8),$A[0] # ap[j]*bp[i]+tp[j] + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap,$j,8),%rax + adc \$0,%rdx + add $A[0],$N[0] + adc \$0,%rdx + mov $N[0],-24(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov -8($np,$j,8),%rax + adc \$0,%rdx + add -8(%rsp,$j,8),$A[1] + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap,$j,8),%rax + adc \$0,%rdx + add $A[1],$N[1] + adc \$0,%rdx + mov $N[1],-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[0] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[0] + mov ($np,$j,8),%rax + adc \$0,%rdx + add (%rsp,$j,8),$A[0] # ap[j]*bp[i]+tp[j] + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov 8($ap,$j,8),%rax + adc \$0,%rdx + add $A[0],$N[0] + adc \$0,%rdx + mov $N[0],-8(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov 8($np,$j,8),%rax + adc \$0,%rdx + add 8(%rsp,$j,8),$A[1] + adc \$0,%rdx + lea 4($j),$j # j++ + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov -16($ap,$j,8),%rax + adc \$0,%rdx + add $A[1],$N[1] + adc \$0,%rdx + mov $N[1],-32(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[0] + cmp $num,$j + jb .Linner4x + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[0] + mov -16($np,$j,8),%rax + adc \$0,%rdx + add -16(%rsp,$j,8),$A[0] # ap[j]*bp[i]+tp[j] + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap,$j,8),%rax + adc \$0,%rdx + add $A[0],$N[0] + adc \$0,%rdx + mov $N[0],-24(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov -8($np,$j,8),%rax + adc \$0,%rdx + add -8(%rsp,$j,8),$A[1] + adc \$0,%rdx + lea 1($i),$i # i++ + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap),%rax # ap[0] + adc \$0,%rdx + add $A[1],$N[1] + adc \$0,%rdx + mov $N[1],-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$N[0] + + xor $N[1],$N[1] + add $A[0],$N[0] + adc \$0,$N[1] + add (%rsp,$num,8),$N[0] # pull upmost overflow bit + adc \$0,$N[1] + mov $N[0],-8(%rsp,$j,8) + mov $N[1],(%rsp,$j,8) # store upmost overflow bit + + cmp $num,$i + jb .Louter4x +___ +{ +my @ri=("%rax","%rdx",$m0,$m1); +$code.=<<___; + mov 16(%rsp,$num,8),$rp # restore $rp + mov 0(%rsp),@ri[0] # tp[0] + mov 8(%rsp),@ri[1] # tp[1] + shr \$2,$num # num/=4 + lea (%rsp),$ap # borrow ap for tp + xor $i,$i # i=0 and clear CF! + + sub 0($np),@ri[0] + mov 16($ap),@ri[2] # tp[2] + mov 24($ap),@ri[3] # tp[3] + sbb 8($np),@ri[1] + lea -1($num),$j # j=num/4-1 + jmp .Lsub4x +.align 16 +.Lsub4x: + mov @ri[0],0($rp,$i,8) # rp[i]=tp[i]-np[i] + mov @ri[1],8($rp,$i,8) # rp[i]=tp[i]-np[i] + sbb 16($np,$i,8),@ri[2] + mov 32($ap,$i,8),@ri[0] # tp[i+1] + mov 40($ap,$i,8),@ri[1] + sbb 24($np,$i,8),@ri[3] + mov @ri[2],16($rp,$i,8) # rp[i]=tp[i]-np[i] + mov @ri[3],24($rp,$i,8) # rp[i]=tp[i]-np[i] + sbb 32($np,$i,8),@ri[0] + mov 48($ap,$i,8),@ri[2] + mov 56($ap,$i,8),@ri[3] + sbb 40($np,$i,8),@ri[1] + lea 4($i),$i # i++ + dec $j # doesnn't affect CF! + jnz .Lsub4x + + mov @ri[0],0($rp,$i,8) # rp[i]=tp[i]-np[i] + mov 32($ap,$i,8),@ri[0] # load overflow bit + sbb 16($np,$i,8),@ri[2] + mov @ri[1],8($rp,$i,8) # rp[i]=tp[i]-np[i] + sbb 24($np,$i,8),@ri[3] + mov @ri[2],16($rp,$i,8) # rp[i]=tp[i]-np[i] + + sbb \$0,@ri[0] # handle upmost overflow bit + mov @ri[0],%xmm0 + punpcklqdq %xmm0,%xmm0 # extend mask to 128 bits + mov @ri[3],24($rp,$i,8) # rp[i]=tp[i]-np[i] + xor $i,$i # i=0 + + mov $num,$j + pxor %xmm5,%xmm5 + jmp .Lcopy4x +.align 16 +.Lcopy4x: # copy or in-place refresh + movdqu (%rsp,$i),%xmm2 + movdqu 16(%rsp,$i),%xmm4 + movdqu ($rp,$i),%xmm1 + movdqu 16($rp,$i),%xmm3 + pxor %xmm1,%xmm2 # conditional select + pxor %xmm3,%xmm4 + pand %xmm0,%xmm2 + pand %xmm0,%xmm4 + pxor %xmm1,%xmm2 + pxor %xmm3,%xmm4 + movdqu %xmm2,($rp,$i) + movdqu %xmm4,16($rp,$i) + movdqa %xmm5,(%rsp,$i) # zap temporary vectors + movdqa %xmm5,16(%rsp,$i) + + lea 32($i),$i + dec $j + jnz .Lcopy4x + + shl \$2,$num +___ +} +$code.=<<___; + mov 8(%rsp,$num,8),%rsi # restore %rsp + mov \$1,%rax + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lmul4x_epilogue: + ret +.size bn_mul4x_mont,.-bn_mul4x_mont +___ +}}} + {{{ +###################################################################### +# void bn_sqr8x_mont( +my $rptr="%rdi"; # const BN_ULONG *rptr, +my $aptr="%rsi"; # const BN_ULONG *aptr, +my $bptr="%rdx"; # not used +my $nptr="%rcx"; # const BN_ULONG *nptr, +my $n0 ="%r8"; # const BN_ULONG *n0); +my $num ="%r9"; # int num, has to be divisible by 8 + +my ($i,$j,$tptr)=("%rbp","%rcx",$rptr); +my @A0=("%r10","%r11"); +my @A1=("%r12","%r13"); +my ($a0,$a1,$ai)=("%r14","%r15","%rbx"); + +$code.=<<___ if ($addx); +.extern bn_sqrx8x_internal # see x86_64-mont5 module +___ +$code.=<<___; +.extern bn_sqr8x_internal # see x86_64-mont5 module + +.type bn_sqr8x_mont,\@function,6 +.align 32 +bn_sqr8x_mont: +.Lsqr8x_enter: + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + mov ${num}d,%r10d + shl \$3,${num}d # convert $num to bytes + shl \$3+2,%r10 # 4*$num + neg $num + + ############################################################## + # ensure that stack frame doesn't alias with $aptr modulo + # 4096. this is done to allow memory disambiguation logic + # do its job. + # + lea -64(%rsp,$num,4),%r11 + mov ($n0),$n0 # *n0 + sub $aptr,%r11 + and \$4095,%r11 + cmp %r11,%r10 + jb .Lsqr8x_sp_alt + sub %r11,%rsp # align with $aptr + lea -64(%rsp,$num,4),%rsp # alloca(frame+4*$num) + jmp .Lsqr8x_sp_done + +.align 32 +.Lsqr8x_sp_alt: + lea 4096-64(,$num,4),%r10 # 4096-frame-4*$num + lea -64(%rsp,$num,4),%rsp # alloca(frame+4*$num) + sub %r10,%r11 + mov \$0,%r10 + cmovc %r10,%r11 + sub %r11,%rsp +.Lsqr8x_sp_done: + and \$-64,%rsp + mov $num,%r10 + neg $num + + lea 64(%rsp,$num,2),%r11 # copy of modulus + mov $n0, 32(%rsp) + mov %rax, 40(%rsp) # save original %rsp +.Lsqr8x_body: + + mov $num,$i + movq %r11, %xmm2 # save pointer to modulus copy + shr \$3+2,$i + mov OPENSSL_ia32cap_P+8(%rip),%eax + jmp .Lsqr8x_copy_n + +.align 32 +.Lsqr8x_copy_n: + movq 8*0($nptr),%xmm0 + movq 8*1($nptr),%xmm1 + movq 8*2($nptr),%xmm3 + movq 8*3($nptr),%xmm4 + lea 8*4($nptr),$nptr + movdqa %xmm0,16*0(%r11) + movdqa %xmm1,16*1(%r11) + movdqa %xmm3,16*2(%r11) + movdqa %xmm4,16*3(%r11) + lea 16*4(%r11),%r11 + dec $i + jnz .Lsqr8x_copy_n + + pxor %xmm0,%xmm0 + movq $rptr,%xmm1 # save $rptr + movq %r10, %xmm3 # -$num +___ +$code.=<<___ if ($addx); + and \$0x80100,%eax + cmp \$0x80100,%eax + jne .Lsqr8x_nox + + call bn_sqrx8x_internal # see x86_64-mont5 module + + pxor %xmm0,%xmm0 + lea 48(%rsp),%rax + lea 64(%rsp,$num,2),%rdx + shr \$3+2,$num + mov 40(%rsp),%rsi # restore %rsp + jmp .Lsqr8x_zero + +.align 32 +.Lsqr8x_nox: +___ +$code.=<<___; + call bn_sqr8x_internal # see x86_64-mont5 module + + pxor %xmm0,%xmm0 + lea 48(%rsp),%rax + lea 64(%rsp,$num,2),%rdx + shr \$3+2,$num + mov 40(%rsp),%rsi # restore %rsp + jmp .Lsqr8x_zero + +.align 32 +.Lsqr8x_zero: + movdqa %xmm0,16*0(%rax) # wipe t + movdqa %xmm0,16*1(%rax) + movdqa %xmm0,16*2(%rax) + movdqa %xmm0,16*3(%rax) + lea 16*4(%rax),%rax + movdqa %xmm0,16*0(%rdx) # wipe n + movdqa %xmm0,16*1(%rdx) + movdqa %xmm0,16*2(%rdx) + movdqa %xmm0,16*3(%rdx) + lea 16*4(%rdx),%rdx + dec $num + jnz .Lsqr8x_zero + + mov \$1,%rax + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lsqr8x_epilogue: + ret +.size bn_sqr8x_mont,.-bn_sqr8x_mont +___ +}}} + +if ($addx) {{{ +my $bp="%rdx"; # original value + +$code.=<<___; +.type bn_mulx4x_mont,\@function,6 +.align 32 +bn_mulx4x_mont: +.Lmulx4x_enter: + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + + shl \$3,${num}d # convert $num to bytes + .byte 0x67 + xor %r10,%r10 + sub $num,%r10 # -$num + mov ($n0),$n0 # *n0 + lea -72(%rsp,%r10),%rsp # alloca(frame+$num+8) + lea ($bp,$num),%r10 + and \$-128,%rsp + ############################################################## + # Stack layout + # +0 num + # +8 off-loaded &b[i] + # +16 end of b[num] + # +24 saved n0 + # +32 saved rp + # +40 saved %rsp + # +48 inner counter + # +56 + # +64 tmp[num+1] + # + mov $num,0(%rsp) # save $num + shr \$5,$num + mov %r10,16(%rsp) # end of b[num] + sub \$1,$num + mov $n0, 24(%rsp) # save *n0 + mov $rp, 32(%rsp) # save $rp + mov %rax,40(%rsp) # save original %rsp + mov $num,48(%rsp) # inner counter + jmp .Lmulx4x_body + +.align 32 +.Lmulx4x_body: +___ +my ($aptr, $bptr, $nptr, $tptr, $mi, $bi, $zero, $num)= + ("%rsi","%rdi","%rcx","%rbx","%r8","%r9","%rbp","%rax"); +my $rptr=$bptr; +$code.=<<___; + lea 8($bp),$bptr + mov ($bp),%rdx # b[0], $bp==%rdx actually + lea 64+32(%rsp),$tptr + mov %rdx,$bi + + mulx 0*8($aptr),$mi,%rax # a[0]*b[0] + mulx 1*8($aptr),%r11,%r14 # a[1]*b[0] + add %rax,%r11 + mov $bptr,8(%rsp) # off-load &b[i] + mulx 2*8($aptr),%r12,%r13 # ... + adc %r14,%r12 + adc \$0,%r13 + + mov $mi,$bptr # borrow $bptr + imulq 24(%rsp),$mi # "t[0]"*n0 + xor $zero,$zero # cf=0, of=0 + + mulx 3*8($aptr),%rax,%r14 + mov $mi,%rdx + lea 4*8($aptr),$aptr + adcx %rax,%r13 + adcx $zero,%r14 # cf=0 + + mulx 0*8($nptr),%rax,%r10 + adcx %rax,$bptr # discarded + adox %r11,%r10 + mulx 1*8($nptr),%rax,%r11 + adcx %rax,%r10 + adox %r12,%r11 + .byte 0xc4,0x62,0xfb,0xf6,0xa1,0x10,0x00,0x00,0x00 # mulx 2*8($nptr),%rax,%r12 + mov 48(%rsp),$bptr # counter value + mov %r10,-4*8($tptr) + adcx %rax,%r11 + adox %r13,%r12 + mulx 3*8($nptr),%rax,%r15 + mov $bi,%rdx + mov %r11,-3*8($tptr) + adcx %rax,%r12 + adox $zero,%r15 # of=0 + lea 4*8($nptr),$nptr + mov %r12,-2*8($tptr) + + jmp .Lmulx4x_1st + +.align 32 +.Lmulx4x_1st: + adcx $zero,%r15 # cf=0, modulo-scheduled + mulx 0*8($aptr),%r10,%rax # a[4]*b[0] + adcx %r14,%r10 + mulx 1*8($aptr),%r11,%r14 # a[5]*b[0] + adcx %rax,%r11 + mulx 2*8($aptr),%r12,%rax # ... + adcx %r14,%r12 + mulx 3*8($aptr),%r13,%r14 + .byte 0x67,0x67 + mov $mi,%rdx + adcx %rax,%r13 + adcx $zero,%r14 # cf=0 + lea 4*8($aptr),$aptr + lea 4*8($tptr),$tptr + + adox %r15,%r10 + mulx 0*8($nptr),%rax,%r15 + adcx %rax,%r10 + adox %r15,%r11 + mulx 1*8($nptr),%rax,%r15 + adcx %rax,%r11 + adox %r15,%r12 + mulx 2*8($nptr),%rax,%r15 + mov %r10,-5*8($tptr) + adcx %rax,%r12 + mov %r11,-4*8($tptr) + adox %r15,%r13 + mulx 3*8($nptr),%rax,%r15 + mov $bi,%rdx + mov %r12,-3*8($tptr) + adcx %rax,%r13 + adox $zero,%r15 + lea 4*8($nptr),$nptr + mov %r13,-2*8($tptr) + + dec $bptr # of=0, pass cf + jnz .Lmulx4x_1st + + mov 0(%rsp),$num # load num + mov 8(%rsp),$bptr # re-load &b[i] + adc $zero,%r15 # modulo-scheduled + add %r15,%r14 + sbb %r15,%r15 # top-most carry + mov %r14,-1*8($tptr) + jmp .Lmulx4x_outer + +.align 32 +.Lmulx4x_outer: + mov ($bptr),%rdx # b[i] + lea 8($bptr),$bptr # b++ + sub $num,$aptr # rewind $aptr + mov %r15,($tptr) # save top-most carry + lea 64+4*8(%rsp),$tptr + sub $num,$nptr # rewind $nptr + + mulx 0*8($aptr),$mi,%r11 # a[0]*b[i] + xor %ebp,%ebp # xor $zero,$zero # cf=0, of=0 + mov %rdx,$bi + mulx 1*8($aptr),%r14,%r12 # a[1]*b[i] + adox -4*8($tptr),$mi + adcx %r14,%r11 + mulx 2*8($aptr),%r15,%r13 # ... + adox -3*8($tptr),%r11 + adcx %r15,%r12 + adox $zero,%r12 + adcx $zero,%r13 + + mov $bptr,8(%rsp) # off-load &b[i] + .byte 0x67 + mov $mi,%r15 + imulq 24(%rsp),$mi # "t[0]"*n0 + xor %ebp,%ebp # xor $zero,$zero # cf=0, of=0 + + mulx 3*8($aptr),%rax,%r14 + mov $mi,%rdx + adox -2*8($tptr),%r12 + adcx %rax,%r13 + adox -1*8($tptr),%r13 + adcx $zero,%r14 + lea 4*8($aptr),$aptr + adox $zero,%r14 + + mulx 0*8($nptr),%rax,%r10 + adcx %rax,%r15 # discarded + adox %r11,%r10 + mulx 1*8($nptr),%rax,%r11 + adcx %rax,%r10 + adox %r12,%r11 + mulx 2*8($nptr),%rax,%r12 + mov %r10,-4*8($tptr) + adcx %rax,%r11 + adox %r13,%r12 + mulx 3*8($nptr),%rax,%r15 + mov $bi,%rdx + mov %r11,-3*8($tptr) + lea 4*8($nptr),$nptr + adcx %rax,%r12 + adox $zero,%r15 # of=0 + mov 48(%rsp),$bptr # counter value + mov %r12,-2*8($tptr) + + jmp .Lmulx4x_inner + +.align 32 +.Lmulx4x_inner: + mulx 0*8($aptr),%r10,%rax # a[4]*b[i] + adcx $zero,%r15 # cf=0, modulo-scheduled + adox %r14,%r10 + mulx 1*8($aptr),%r11,%r14 # a[5]*b[i] + adcx 0*8($tptr),%r10 + adox %rax,%r11 + mulx 2*8($aptr),%r12,%rax # ... + adcx 1*8($tptr),%r11 + adox %r14,%r12 + mulx 3*8($aptr),%r13,%r14 + mov $mi,%rdx + adcx 2*8($tptr),%r12 + adox %rax,%r13 + adcx 3*8($tptr),%r13 + adox $zero,%r14 # of=0 + lea 4*8($aptr),$aptr + lea 4*8($tptr),$tptr + adcx $zero,%r14 # cf=0 + + adox %r15,%r10 + mulx 0*8($nptr),%rax,%r15 + adcx %rax,%r10 + adox %r15,%r11 + mulx 1*8($nptr),%rax,%r15 + adcx %rax,%r11 + adox %r15,%r12 + mulx 2*8($nptr),%rax,%r15 + mov %r10,-5*8($tptr) + adcx %rax,%r12 + adox %r15,%r13 + mulx 3*8($nptr),%rax,%r15 + mov $bi,%rdx + mov %r11,-4*8($tptr) + mov %r12,-3*8($tptr) + adcx %rax,%r13 + adox $zero,%r15 + lea 4*8($nptr),$nptr + mov %r13,-2*8($tptr) + + dec $bptr # of=0, pass cf + jnz .Lmulx4x_inner + + mov 0(%rsp),$num # load num + mov 8(%rsp),$bptr # re-load &b[i] + adc $zero,%r15 # modulo-scheduled + sub 0*8($tptr),$zero # pull top-most carry + adc %r15,%r14 + mov -8($nptr),$mi + sbb %r15,%r15 # top-most carry + mov %r14,-1*8($tptr) + + cmp 16(%rsp),$bptr + jne .Lmulx4x_outer + + sub %r14,$mi # compare top-most words + sbb $mi,$mi + or $mi,%r15 + + neg $num + xor %rdx,%rdx + mov 32(%rsp),$rptr # restore rp + lea 64(%rsp),$tptr + + pxor %xmm0,%xmm0 + mov 0*8($nptr,$num),%r8 + mov 1*8($nptr,$num),%r9 + neg %r8 + jmp .Lmulx4x_sub_entry + +.align 32 +.Lmulx4x_sub: + mov 0*8($nptr,$num),%r8 + mov 1*8($nptr,$num),%r9 + not %r8 +.Lmulx4x_sub_entry: + mov 2*8($nptr,$num),%r10 + not %r9 + and %r15,%r8 + mov 3*8($nptr,$num),%r11 + not %r10 + and %r15,%r9 + not %r11 + and %r15,%r10 + and %r15,%r11 + + neg %rdx # mov %rdx,%cf + adc 0*8($tptr),%r8 + adc 1*8($tptr),%r9 + movdqa %xmm0,($tptr) + adc 2*8($tptr),%r10 + adc 3*8($tptr),%r11 + movdqa %xmm0,16($tptr) + lea 4*8($tptr),$tptr + sbb %rdx,%rdx # mov %cf,%rdx + + mov %r8,0*8($rptr) + mov %r9,1*8($rptr) + mov %r10,2*8($rptr) + mov %r11,3*8($rptr) + lea 4*8($rptr),$rptr + + add \$32,$num + jnz .Lmulx4x_sub + + mov 40(%rsp),%rsi # restore %rsp + mov \$1,%rax + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lmulx4x_epilogue: + ret +.size bn_mulx4x_mont,.-bn_mulx4x_mont +___ +}}} +$code.=<<___; +.asciz "Montgomery Multiplication for x86_64, CRYPTOGAMS by " +.align 16 +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type mul_handler,\@abi-omnipotent +.align 16 +mul_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # end of prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + mov 192($context),%r10 # pull $num + mov 8(%rax,%r10,8),%rax # pull saved stack pointer + lea 48(%rax),%rax + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov -48(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + + jmp .Lcommon_seh_tail +.size mul_handler,.-mul_handler + +.type sqr_handler,\@abi-omnipotent +.align 16 +sqr_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # end of prologue label + cmp %r10,%rbx # context->Rip<.Lsqr_body + jb .Lcommon_seh_tail + + mov 152($context),%rax # pull context->Rsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=.Lsqr_epilogue + jae .Lcommon_seh_tail + + mov 40(%rax),%rax # pull saved stack pointer + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov -48(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lcommon_seh_tail: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size sqr_handler,.-sqr_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_bn_mul_mont + .rva .LSEH_end_bn_mul_mont + .rva .LSEH_info_bn_mul_mont + + .rva .LSEH_begin_bn_mul4x_mont + .rva .LSEH_end_bn_mul4x_mont + .rva .LSEH_info_bn_mul4x_mont + + .rva .LSEH_begin_bn_sqr8x_mont + .rva .LSEH_end_bn_sqr8x_mont + .rva .LSEH_info_bn_sqr8x_mont +___ +$code.=<<___ if ($addx); + .rva .LSEH_begin_bn_mulx4x_mont + .rva .LSEH_end_bn_mulx4x_mont + .rva .LSEH_info_bn_mulx4x_mont +___ +$code.=<<___; +.section .xdata +.align 8 +.LSEH_info_bn_mul_mont: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lmul_body,.Lmul_epilogue # HandlerData[] +.LSEH_info_bn_mul4x_mont: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lmul4x_body,.Lmul4x_epilogue # HandlerData[] +.LSEH_info_bn_sqr8x_mont: + .byte 9,0,0,0 + .rva sqr_handler + .rva .Lsqr8x_body,.Lsqr8x_epilogue # HandlerData[] +___ +$code.=<<___ if ($addx); +.LSEH_info_bn_mulx4x_mont: + .byte 9,0,0,0 + .rva sqr_handler + .rva .Lmulx4x_body,.Lmulx4x_epilogue # HandlerData[] +___ +} + +print $code; +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-mont5.pl b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-mont5.pl new file mode 100644 index 00000000..80e91268 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/asm/x86_64-mont5.pl @@ -0,0 +1,3499 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# August 2011. +# +# Companion to x86_64-mont.pl that optimizes cache-timing attack +# countermeasures. The subroutines are produced by replacing bp[i] +# references in their x86_64-mont.pl counterparts with cache-neutral +# references to powers table computed in BN_mod_exp_mont_consttime. +# In addition subroutine that scatters elements of the powers table +# is implemented, so that scatter-/gathering can be tuned without +# bn_exp.c modifications. + +# August 2013. +# +# Add MULX/AD*X code paths and additional interfaces to optimize for +# branch prediction unit. For input lengths that are multiples of 8 +# the np argument is not just modulus value, but one interleaved +# with 0. This is to optimize post-condition... + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $addx = ($1>=2.23); +} + +if (!$addx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $addx = ($1>=2.10); +} + +if (!$addx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $addx = ($1>=12); +} + +# int bn_mul_mont_gather5( +$rp="%rdi"; # BN_ULONG *rp, +$ap="%rsi"; # const BN_ULONG *ap, +$bp="%rdx"; # const BN_ULONG *bp, +$np="%rcx"; # const BN_ULONG *np, +$n0="%r8"; # const BN_ULONG *n0, +$num="%r9"; # int num, + # int idx); # 0 to 2^5-1, "index" in $bp holding + # pre-computed powers of a', interlaced + # in such manner that b[0] is $bp[idx], + # b[1] is [2^5+idx], etc. +$lo0="%r10"; +$hi0="%r11"; +$hi1="%r13"; +$i="%r14"; +$j="%r15"; +$m0="%rbx"; +$m1="%rbp"; + +$code=<<___; +.text + +.extern OPENSSL_ia32cap_P + +.globl bn_mul_mont_gather5 +.type bn_mul_mont_gather5,\@function,6 +.align 64 +bn_mul_mont_gather5: + test \$7,${num}d + jnz .Lmul_enter +___ +$code.=<<___ if ($addx); + mov OPENSSL_ia32cap_P+8(%rip),%r11d +___ +$code.=<<___; + jmp .Lmul4x_enter + +.align 16 +.Lmul_enter: + mov ${num}d,${num}d + mov %rsp,%rax + mov `($win64?56:8)`(%rsp),%r10d # load 7th argument + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0x28(%rsp),%rsp + movaps %xmm6,(%rsp) + movaps %xmm7,0x10(%rsp) +___ +$code.=<<___; + lea 2($num),%r11 + neg %r11 + lea (%rsp,%r11,8),%rsp # tp=alloca(8*(num+2)) + and \$-1024,%rsp # minimize TLB usage + + mov %rax,8(%rsp,$num,8) # tp[num+1]=%rsp +.Lmul_body: + mov $bp,%r12 # reassign $bp +___ + $bp="%r12"; + $STRIDE=2**5*8; # 5 is "window size" + $N=$STRIDE/4; # should match cache line size +$code.=<<___; + mov %r10,%r11 + shr \$`log($N/8)/log(2)`,%r10 + and \$`$N/8-1`,%r11 + not %r10 + lea .Lmagic_masks(%rip),%rax + and \$`2**5/($N/8)-1`,%r10 # 5 is "window size" + lea 96($bp,%r11,8),$bp # pointer within 1st cache line + movq 0(%rax,%r10,8),%xmm4 # set of masks denoting which + movq 8(%rax,%r10,8),%xmm5 # cache line contains element + movq 16(%rax,%r10,8),%xmm6 # denoted by 7th argument + movq 24(%rax,%r10,8),%xmm7 + + movq `0*$STRIDE/4-96`($bp),%xmm0 + movq `1*$STRIDE/4-96`($bp),%xmm1 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-96`($bp),%xmm2 + pand %xmm5,%xmm1 + movq `3*$STRIDE/4-96`($bp),%xmm3 + pand %xmm6,%xmm2 + por %xmm1,%xmm0 + pand %xmm7,%xmm3 + por %xmm2,%xmm0 + lea $STRIDE($bp),$bp + por %xmm3,%xmm0 + + movq %xmm0,$m0 # m0=bp[0] + + mov ($n0),$n0 # pull n0[0] value + mov ($ap),%rax + + xor $i,$i # i=0 + xor $j,$j # j=0 + + movq `0*$STRIDE/4-96`($bp),%xmm0 + movq `1*$STRIDE/4-96`($bp),%xmm1 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-96`($bp),%xmm2 + pand %xmm5,%xmm1 + + mov $n0,$m1 + mulq $m0 # ap[0]*bp[0] + mov %rax,$lo0 + mov ($np),%rax + + movq `3*$STRIDE/4-96`($bp),%xmm3 + pand %xmm6,%xmm2 + por %xmm1,%xmm0 + pand %xmm7,%xmm3 + + imulq $lo0,$m1 # "tp[0]"*n0 + mov %rdx,$hi0 + + por %xmm2,%xmm0 + lea $STRIDE($bp),$bp + por %xmm3,%xmm0 + + mulq $m1 # np[0]*m1 + add %rax,$lo0 # discarded + mov 8($ap),%rax + adc \$0,%rdx + mov %rdx,$hi1 + + lea 1($j),$j # j++ + jmp .L1st_enter + +.align 16 +.L1st: + add %rax,$hi1 + mov ($ap,$j,8),%rax + adc \$0,%rdx + add $hi0,$hi1 # np[j]*m1+ap[j]*bp[0] + mov $lo0,$hi0 + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + +.L1st_enter: + mulq $m0 # ap[j]*bp[0] + add %rax,$hi0 + mov ($np,$j,8),%rax + adc \$0,%rdx + lea 1($j),$j # j++ + mov %rdx,$lo0 + + mulq $m1 # np[j]*m1 + cmp $num,$j + jne .L1st + + movq %xmm0,$m0 # bp[1] + + add %rax,$hi1 + mov ($ap),%rax # ap[0] + adc \$0,%rdx + add $hi0,$hi1 # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + mov $lo0,$hi0 + + xor %rdx,%rdx + add $hi0,$hi1 + adc \$0,%rdx + mov $hi1,-8(%rsp,$num,8) + mov %rdx,(%rsp,$num,8) # store upmost overflow bit + + lea 1($i),$i # i++ + jmp .Louter +.align 16 +.Louter: + xor $j,$j # j=0 + mov $n0,$m1 + mov (%rsp),$lo0 + + movq `0*$STRIDE/4-96`($bp),%xmm0 + movq `1*$STRIDE/4-96`($bp),%xmm1 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-96`($bp),%xmm2 + pand %xmm5,%xmm1 + + mulq $m0 # ap[0]*bp[i] + add %rax,$lo0 # ap[0]*bp[i]+tp[0] + mov ($np),%rax + adc \$0,%rdx + + movq `3*$STRIDE/4-96`($bp),%xmm3 + pand %xmm6,%xmm2 + por %xmm1,%xmm0 + pand %xmm7,%xmm3 + + imulq $lo0,$m1 # tp[0]*n0 + mov %rdx,$hi0 + + por %xmm2,%xmm0 + lea $STRIDE($bp),$bp + por %xmm3,%xmm0 + + mulq $m1 # np[0]*m1 + add %rax,$lo0 # discarded + mov 8($ap),%rax + adc \$0,%rdx + mov 8(%rsp),$lo0 # tp[1] + mov %rdx,$hi1 + + lea 1($j),$j # j++ + jmp .Linner_enter + +.align 16 +.Linner: + add %rax,$hi1 + mov ($ap,$j,8),%rax + adc \$0,%rdx + add $lo0,$hi1 # np[j]*m1+ap[j]*bp[i]+tp[j] + mov (%rsp,$j,8),$lo0 + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + +.Linner_enter: + mulq $m0 # ap[j]*bp[i] + add %rax,$hi0 + mov ($np,$j,8),%rax + adc \$0,%rdx + add $hi0,$lo0 # ap[j]*bp[i]+tp[j] + mov %rdx,$hi0 + adc \$0,$hi0 + lea 1($j),$j # j++ + + mulq $m1 # np[j]*m1 + cmp $num,$j + jne .Linner + + movq %xmm0,$m0 # bp[i+1] + + add %rax,$hi1 + mov ($ap),%rax # ap[0] + adc \$0,%rdx + add $lo0,$hi1 # np[j]*m1+ap[j]*bp[i]+tp[j] + mov (%rsp,$j,8),$lo0 + adc \$0,%rdx + mov $hi1,-16(%rsp,$j,8) # tp[j-1] + mov %rdx,$hi1 + + xor %rdx,%rdx + add $hi0,$hi1 + adc \$0,%rdx + add $lo0,$hi1 # pull upmost overflow bit + adc \$0,%rdx + mov $hi1,-8(%rsp,$num,8) + mov %rdx,(%rsp,$num,8) # store upmost overflow bit + + lea 1($i),$i # i++ + cmp $num,$i + jb .Louter + + xor $i,$i # i=0 and clear CF! + mov (%rsp),%rax # tp[0] + lea (%rsp),$ap # borrow ap for tp + mov $num,$j # j=num + jmp .Lsub +.align 16 +.Lsub: sbb ($np,$i,8),%rax + mov %rax,($rp,$i,8) # rp[i]=tp[i]-np[i] + mov 8($ap,$i,8),%rax # tp[i+1] + lea 1($i),$i # i++ + dec $j # doesnn't affect CF! + jnz .Lsub + + sbb \$0,%rax # handle upmost overflow bit + xor $i,$i + mov $num,$j # j=num +.align 16 +.Lcopy: # copy or in-place refresh + mov (%rsp,$i,8),$ap + mov ($rp,$i,8),$np + xor $np,$ap # conditional select: + and %rax,$ap # ((ap ^ np) & %rax) ^ np + xor $np,$ap # ap = borrow?tp:rp + mov $i,(%rsp,$i,8) # zap temporary vector + mov $ap,($rp,$i,8) # rp[i]=tp[i] + lea 1($i),$i + sub \$1,$j + jnz .Lcopy + + mov 8(%rsp,$num,8),%rsi # restore %rsp + mov \$1,%rax +___ +$code.=<<___ if ($win64); + movaps -88(%rsi),%xmm6 + movaps -72(%rsi),%xmm7 +___ +$code.=<<___; + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lmul_epilogue: + ret +.size bn_mul_mont_gather5,.-bn_mul_mont_gather5 +___ +{{{ +my @A=("%r10","%r11"); +my @N=("%r13","%rdi"); +$code.=<<___; +.type bn_mul4x_mont_gather5,\@function,6 +.align 32 +bn_mul4x_mont_gather5: +.Lmul4x_enter: +___ +$code.=<<___ if ($addx); + and \$0x80100,%r11d + cmp \$0x80100,%r11d + je .Lmulx4x_enter +___ +$code.=<<___; + .byte 0x67 + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0x28(%rsp),%rsp + movaps %xmm6,(%rsp) + movaps %xmm7,0x10(%rsp) +___ +$code.=<<___; + .byte 0x67 + mov ${num}d,%r10d + shl \$3,${num}d + shl \$3+2,%r10d # 4*$num + neg $num # -$num + + ############################################################## + # ensure that stack frame doesn't alias with $aptr+4*$num + # modulo 4096, which covers ret[num], am[num] and n[2*num] + # (see bn_exp.c). this is done to allow memory disambiguation + # logic do its magic. [excessive frame is allocated in order + # to allow bn_from_mont8x to clear it.] + # + lea -64(%rsp,$num,2),%r11 + sub $ap,%r11 + and \$4095,%r11 + cmp %r11,%r10 + jb .Lmul4xsp_alt + sub %r11,%rsp # align with $ap + lea -64(%rsp,$num,2),%rsp # alloca(128+num*8) + jmp .Lmul4xsp_done + +.align 32 +.Lmul4xsp_alt: + lea 4096-64(,$num,2),%r10 + lea -64(%rsp,$num,2),%rsp # alloca(128+num*8) + sub %r10,%r11 + mov \$0,%r10 + cmovc %r10,%r11 + sub %r11,%rsp +.Lmul4xsp_done: + and \$-64,%rsp + neg $num + + mov %rax,40(%rsp) +.Lmul4x_body: + + call mul4x_internal + + mov 40(%rsp),%rsi # restore %rsp + mov \$1,%rax +___ +$code.=<<___ if ($win64); + movaps -88(%rsi),%xmm6 + movaps -72(%rsi),%xmm7 +___ +$code.=<<___; + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lmul4x_epilogue: + ret +.size bn_mul4x_mont_gather5,.-bn_mul4x_mont_gather5 + +.type mul4x_internal,\@abi-omnipotent +.align 32 +mul4x_internal: + shl \$5,$num + mov `($win64?56:8)`(%rax),%r10d # load 7th argument + lea 256(%rdx,$num),%r13 + shr \$5,$num # restore $num +___ + $bp="%r12"; + $STRIDE=2**5*8; # 5 is "window size" + $N=$STRIDE/4; # should match cache line size + $tp=$i; +$code.=<<___; + mov %r10,%r11 + shr \$`log($N/8)/log(2)`,%r10 + and \$`$N/8-1`,%r11 + not %r10 + lea .Lmagic_masks(%rip),%rax + and \$`2**5/($N/8)-1`,%r10 # 5 is "window size" + lea 96(%rdx,%r11,8),$bp # pointer within 1st cache line + movq 0(%rax,%r10,8),%xmm4 # set of masks denoting which + movq 8(%rax,%r10,8),%xmm5 # cache line contains element + add \$7,%r11 + movq 16(%rax,%r10,8),%xmm6 # denoted by 7th argument + movq 24(%rax,%r10,8),%xmm7 + and \$7,%r11 + + movq `0*$STRIDE/4-96`($bp),%xmm0 + lea $STRIDE($bp),$tp # borrow $tp + movq `1*$STRIDE/4-96`($bp),%xmm1 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-96`($bp),%xmm2 + pand %xmm5,%xmm1 + movq `3*$STRIDE/4-96`($bp),%xmm3 + pand %xmm6,%xmm2 + .byte 0x67 + por %xmm1,%xmm0 + movq `0*$STRIDE/4-96`($tp),%xmm1 + .byte 0x67 + pand %xmm7,%xmm3 + .byte 0x67 + por %xmm2,%xmm0 + movq `1*$STRIDE/4-96`($tp),%xmm2 + .byte 0x67 + pand %xmm4,%xmm1 + .byte 0x67 + por %xmm3,%xmm0 + movq `2*$STRIDE/4-96`($tp),%xmm3 + + movq %xmm0,$m0 # m0=bp[0] + movq `3*$STRIDE/4-96`($tp),%xmm0 + mov %r13,16+8(%rsp) # save end of b[num] + mov $rp, 56+8(%rsp) # save $rp + + mov ($n0),$n0 # pull n0[0] value + mov ($ap),%rax + lea ($ap,$num),$ap # end of a[num] + neg $num + + mov $n0,$m1 + mulq $m0 # ap[0]*bp[0] + mov %rax,$A[0] + mov ($np),%rax + + pand %xmm5,%xmm2 + pand %xmm6,%xmm3 + por %xmm2,%xmm1 + + imulq $A[0],$m1 # "tp[0]"*n0 + ############################################################## + # $tp is chosen so that writing to top-most element of the + # vector occurs just "above" references to powers table, + # "above" modulo cache-line size, which effectively precludes + # possibility of memory disambiguation logic failure when + # accessing the table. + # + lea 64+8(%rsp,%r11,8),$tp + mov %rdx,$A[1] + + pand %xmm7,%xmm0 + por %xmm3,%xmm1 + lea 2*$STRIDE($bp),$bp + por %xmm1,%xmm0 + + mulq $m1 # np[0]*m1 + add %rax,$A[0] # discarded + mov 8($ap,$num),%rax + adc \$0,%rdx + mov %rdx,$N[1] + + mulq $m0 + add %rax,$A[1] + mov 16*1($np),%rax # interleaved with 0, therefore 16*n + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 + add %rax,$N[1] + mov 16($ap,$num),%rax + adc \$0,%rdx + add $A[1],$N[1] + lea 4*8($num),$j # j=4 + lea 16*4($np),$np + adc \$0,%rdx + mov $N[1],($tp) + mov %rdx,$N[0] + jmp .L1st4x + +.align 32 +.L1st4x: + mulq $m0 # ap[j]*bp[0] + add %rax,$A[0] + mov -16*2($np),%rax + lea 32($tp),$tp + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap,$j),%rax + adc \$0,%rdx + add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[0],-24($tp) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[1] + mov -16*1($np),%rax + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap,$j),%rax + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[1],-16($tp) # tp[j-1] + mov %rdx,$N[0] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[0] + mov 16*0($np),%rax + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov 8($ap,$j),%rax + adc \$0,%rdx + add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[0],-8($tp) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[1] + mov 16*1($np),%rax + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov 16($ap,$j),%rax + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0] + lea 16*4($np),$np + adc \$0,%rdx + mov $N[1],($tp) # tp[j-1] + mov %rdx,$N[0] + + add \$32,$j # j+=4 + jnz .L1st4x + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[0] + mov -16*2($np),%rax + lea 32($tp),$tp + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap),%rax + adc \$0,%rdx + add $A[0],$N[0] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[0],-24($tp) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[0] + add %rax,$A[1] + mov -16*1($np),%rax + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap,$num),%rax # ap[0] + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[0] + adc \$0,%rdx + mov $N[1],-16($tp) # tp[j-1] + mov %rdx,$N[0] + + movq %xmm0,$m0 # bp[1] + lea ($np,$num,2),$np # rewind $np + + xor $N[1],$N[1] + add $A[0],$N[0] + adc \$0,$N[1] + mov $N[0],-8($tp) + + jmp .Louter4x + +.align 32 +.Louter4x: + mov ($tp,$num),$A[0] + mov $n0,$m1 + mulq $m0 # ap[0]*bp[i] + add %rax,$A[0] # ap[0]*bp[i]+tp[0] + mov ($np),%rax + adc \$0,%rdx + + movq `0*$STRIDE/4-96`($bp),%xmm0 + movq `1*$STRIDE/4-96`($bp),%xmm1 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-96`($bp),%xmm2 + pand %xmm5,%xmm1 + movq `3*$STRIDE/4-96`($bp),%xmm3 + + imulq $A[0],$m1 # tp[0]*n0 + .byte 0x67 + mov %rdx,$A[1] + mov $N[1],($tp) # store upmost overflow bit + + pand %xmm6,%xmm2 + por %xmm1,%xmm0 + pand %xmm7,%xmm3 + por %xmm2,%xmm0 + lea ($tp,$num),$tp # rewind $tp + lea $STRIDE($bp),$bp + por %xmm3,%xmm0 + + mulq $m1 # np[0]*m1 + add %rax,$A[0] # "$N[0]", discarded + mov 8($ap,$num),%rax + adc \$0,%rdx + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov 16*1($np),%rax # interleaved with 0, therefore 16*n + adc \$0,%rdx + add 8($tp),$A[1] # +tp[1] + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov 16($ap,$num),%rax + adc \$0,%rdx + add $A[1],$N[1] # np[j]*m1+ap[j]*bp[i]+tp[j] + lea 4*8($num),$j # j=4 + lea 16*4($np),$np + adc \$0,%rdx + mov %rdx,$N[0] + jmp .Linner4x + +.align 32 +.Linner4x: + mulq $m0 # ap[j]*bp[i] + add %rax,$A[0] + mov -16*2($np),%rax + adc \$0,%rdx + add 16($tp),$A[0] # ap[j]*bp[i]+tp[j] + lea 32($tp),$tp + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap,$j),%rax + adc \$0,%rdx + add $A[0],$N[0] + adc \$0,%rdx + mov $N[1],-32($tp) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov -16*1($np),%rax + adc \$0,%rdx + add -8($tp),$A[1] + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap,$j),%rax + adc \$0,%rdx + add $A[1],$N[1] + adc \$0,%rdx + mov $N[0],-24($tp) # tp[j-1] + mov %rdx,$N[0] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[0] + mov 16*0($np),%rax + adc \$0,%rdx + add ($tp),$A[0] # ap[j]*bp[i]+tp[j] + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov 8($ap,$j),%rax + adc \$0,%rdx + add $A[0],$N[0] + adc \$0,%rdx + mov $N[1],-16($tp) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov 16*1($np),%rax + adc \$0,%rdx + add 8($tp),$A[1] + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov 16($ap,$j),%rax + adc \$0,%rdx + add $A[1],$N[1] + lea 16*4($np),$np + adc \$0,%rdx + mov $N[0],-8($tp) # tp[j-1] + mov %rdx,$N[0] + + add \$32,$j # j+=4 + jnz .Linner4x + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[0] + mov -16*2($np),%rax + adc \$0,%rdx + add 16($tp),$A[0] # ap[j]*bp[i]+tp[j] + lea 32($tp),$tp + adc \$0,%rdx + mov %rdx,$A[1] + + mulq $m1 # np[j]*m1 + add %rax,$N[0] + mov -8($ap),%rax + adc \$0,%rdx + add $A[0],$N[0] + adc \$0,%rdx + mov $N[1],-32($tp) # tp[j-1] + mov %rdx,$N[1] + + mulq $m0 # ap[j]*bp[i] + add %rax,$A[1] + mov $m1,%rax + mov -16*1($np),$m1 + adc \$0,%rdx + add -8($tp),$A[1] + adc \$0,%rdx + mov %rdx,$A[0] + + mulq $m1 # np[j]*m1 + add %rax,$N[1] + mov ($ap,$num),%rax # ap[0] + adc \$0,%rdx + add $A[1],$N[1] + adc \$0,%rdx + mov $N[0],-24($tp) # tp[j-1] + mov %rdx,$N[0] + + movq %xmm0,$m0 # bp[i+1] + mov $N[1],-16($tp) # tp[j-1] + lea ($np,$num,2),$np # rewind $np + + xor $N[1],$N[1] + add $A[0],$N[0] + adc \$0,$N[1] + add ($tp),$N[0] # pull upmost overflow bit + adc \$0,$N[1] # upmost overflow bit + mov $N[0],-8($tp) + + cmp 16+8(%rsp),$bp + jb .Louter4x +___ +if (1) { +$code.=<<___; + sub $N[0],$m1 # compare top-most words + adc $j,$j # $j is zero + or $j,$N[1] + xor \$1,$N[1] + lea ($tp,$num),%rbx # tptr in .sqr4x_sub + lea ($np,$N[1],8),%rbp # nptr in .sqr4x_sub + mov %r9,%rcx + sar \$3+2,%rcx # cf=0 + mov 56+8(%rsp),%rdi # rptr in .sqr4x_sub + jmp .Lsqr4x_sub +___ +} else { +my @ri=("%rax",$bp,$m0,$m1); +my $rp="%rdx"; +$code.=<<___ + xor \$1,$N[1] + lea ($tp,$num),$tp # rewind $tp + sar \$5,$num # cf=0 + lea ($np,$N[1],8),$np + mov 56+8(%rsp),$rp # restore $rp + jmp .Lsub4x + +.align 32 +.Lsub4x: + .byte 0x66 + mov 8*0($tp),@ri[0] + mov 8*1($tp),@ri[1] + .byte 0x66 + sbb 16*0($np),@ri[0] + mov 8*2($tp),@ri[2] + sbb 16*1($np),@ri[1] + mov 3*8($tp),@ri[3] + lea 4*8($tp),$tp + sbb 16*2($np),@ri[2] + mov @ri[0],8*0($rp) + sbb 16*3($np),@ri[3] + lea 16*4($np),$np + mov @ri[1],8*1($rp) + mov @ri[2],8*2($rp) + mov @ri[3],8*3($rp) + lea 8*4($rp),$rp + + inc $num + jnz .Lsub4x + + ret +___ +} +$code.=<<___; +.size mul4x_internal,.-mul4x_internal +___ +}}} + {{{ +###################################################################### +# void bn_power5( +my $rptr="%rdi"; # BN_ULONG *rptr, +my $aptr="%rsi"; # const BN_ULONG *aptr, +my $bptr="%rdx"; # const void *table, +my $nptr="%rcx"; # const BN_ULONG *nptr, +my $n0 ="%r8"; # const BN_ULONG *n0); +my $num ="%r9"; # int num, has to be divisible by 8 + # int pwr + +my ($i,$j,$tptr)=("%rbp","%rcx",$rptr); +my @A0=("%r10","%r11"); +my @A1=("%r12","%r13"); +my ($a0,$a1,$ai)=("%r14","%r15","%rbx"); + +$code.=<<___; +.globl bn_power5 +.type bn_power5,\@function,6 +.align 32 +bn_power5: +___ +$code.=<<___ if ($addx); + mov OPENSSL_ia32cap_P+8(%rip),%r11d + and \$0x80100,%r11d + cmp \$0x80100,%r11d + je .Lpowerx5_enter +___ +$code.=<<___; + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0x28(%rsp),%rsp + movaps %xmm6,(%rsp) + movaps %xmm7,0x10(%rsp) +___ +$code.=<<___; + mov ${num}d,%r10d + shl \$3,${num}d # convert $num to bytes + shl \$3+2,%r10d # 4*$num + neg $num + mov ($n0),$n0 # *n0 + + ############################################################## + # ensure that stack frame doesn't alias with $aptr+4*$num + # modulo 4096, which covers ret[num], am[num] and n[2*num] + # (see bn_exp.c). this is done to allow memory disambiguation + # logic do its magic. + # + lea -64(%rsp,$num,2),%r11 + sub $aptr,%r11 + and \$4095,%r11 + cmp %r11,%r10 + jb .Lpwr_sp_alt + sub %r11,%rsp # align with $aptr + lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num) + jmp .Lpwr_sp_done + +.align 32 +.Lpwr_sp_alt: + lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num + lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num) + sub %r10,%r11 + mov \$0,%r10 + cmovc %r10,%r11 + sub %r11,%rsp +.Lpwr_sp_done: + and \$-64,%rsp + mov $num,%r10 + neg $num + + ############################################################## + # Stack layout + # + # +0 saved $num, used in reduction section + # +8 &t[2*$num], used in reduction section + # +32 saved *n0 + # +40 saved %rsp + # +48 t[2*$num] + # + mov $n0, 32(%rsp) + mov %rax, 40(%rsp) # save original %rsp +.Lpower5_body: + movq $rptr,%xmm1 # save $rptr + movq $nptr,%xmm2 # save $nptr + movq %r10, %xmm3 # -$num + movq $bptr,%xmm4 + + call __bn_sqr8x_internal + call __bn_sqr8x_internal + call __bn_sqr8x_internal + call __bn_sqr8x_internal + call __bn_sqr8x_internal + + movq %xmm2,$nptr + movq %xmm4,$bptr + mov $aptr,$rptr + mov 40(%rsp),%rax + lea 32(%rsp),$n0 + + call mul4x_internal + + mov 40(%rsp),%rsi # restore %rsp + mov \$1,%rax + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lpower5_epilogue: + ret +.size bn_power5,.-bn_power5 + +.globl bn_sqr8x_internal +.hidden bn_sqr8x_internal +.type bn_sqr8x_internal,\@abi-omnipotent +.align 32 +bn_sqr8x_internal: +__bn_sqr8x_internal: + ############################################################## + # Squaring part: + # + # a) multiply-n-add everything but a[i]*a[i]; + # b) shift result of a) by 1 to the left and accumulate + # a[i]*a[i] products; + # + ############################################################## + # a[1]a[0] + # a[2]a[0] + # a[3]a[0] + # a[2]a[1] + # a[4]a[0] + # a[3]a[1] + # a[5]a[0] + # a[4]a[1] + # a[3]a[2] + # a[6]a[0] + # a[5]a[1] + # a[4]a[2] + # a[7]a[0] + # a[6]a[1] + # a[5]a[2] + # a[4]a[3] + # a[7]a[1] + # a[6]a[2] + # a[5]a[3] + # a[7]a[2] + # a[6]a[3] + # a[5]a[4] + # a[7]a[3] + # a[6]a[4] + # a[7]a[4] + # a[6]a[5] + # a[7]a[5] + # a[7]a[6] + # a[1]a[0] + # a[2]a[0] + # a[3]a[0] + # a[4]a[0] + # a[5]a[0] + # a[6]a[0] + # a[7]a[0] + # a[2]a[1] + # a[3]a[1] + # a[4]a[1] + # a[5]a[1] + # a[6]a[1] + # a[7]a[1] + # a[3]a[2] + # a[4]a[2] + # a[5]a[2] + # a[6]a[2] + # a[7]a[2] + # a[4]a[3] + # a[5]a[3] + # a[6]a[3] + # a[7]a[3] + # a[5]a[4] + # a[6]a[4] + # a[7]a[4] + # a[6]a[5] + # a[7]a[5] + # a[7]a[6] + # a[0]a[0] + # a[1]a[1] + # a[2]a[2] + # a[3]a[3] + # a[4]a[4] + # a[5]a[5] + # a[6]a[6] + # a[7]a[7] + + lea 32(%r10),$i # $i=-($num-32) + lea ($aptr,$num),$aptr # end of a[] buffer, ($aptr,$i)=&ap[2] + + mov $num,$j # $j=$num + + # comments apply to $num==8 case + mov -32($aptr,$i),$a0 # a[0] + lea 48+8(%rsp,$num,2),$tptr # end of tp[] buffer, &tp[2*$num] + mov -24($aptr,$i),%rax # a[1] + lea -32($tptr,$i),$tptr # end of tp[] window, &tp[2*$num-"$i"] + mov -16($aptr,$i),$ai # a[2] + mov %rax,$a1 + + mul $a0 # a[1]*a[0] + mov %rax,$A0[0] # a[1]*a[0] + mov $ai,%rax # a[2] + mov %rdx,$A0[1] + mov $A0[0],-24($tptr,$i) # t[1] + + mul $a0 # a[2]*a[0] + add %rax,$A0[1] + mov $ai,%rax + adc \$0,%rdx + mov $A0[1],-16($tptr,$i) # t[2] + mov %rdx,$A0[0] + + + mov -8($aptr,$i),$ai # a[3] + mul $a1 # a[2]*a[1] + mov %rax,$A1[0] # a[2]*a[1]+t[3] + mov $ai,%rax + mov %rdx,$A1[1] + + lea ($i),$j + mul $a0 # a[3]*a[0] + add %rax,$A0[0] # a[3]*a[0]+a[2]*a[1]+t[3] + mov $ai,%rax + mov %rdx,$A0[1] + adc \$0,$A0[1] + add $A1[0],$A0[0] + adc \$0,$A0[1] + mov $A0[0],-8($tptr,$j) # t[3] + jmp .Lsqr4x_1st + +.align 32 +.Lsqr4x_1st: + mov ($aptr,$j),$ai # a[4] + mul $a1 # a[3]*a[1] + add %rax,$A1[1] # a[3]*a[1]+t[4] + mov $ai,%rax + mov %rdx,$A1[0] + adc \$0,$A1[0] + + mul $a0 # a[4]*a[0] + add %rax,$A0[1] # a[4]*a[0]+a[3]*a[1]+t[4] + mov $ai,%rax # a[3] + mov 8($aptr,$j),$ai # a[5] + mov %rdx,$A0[0] + adc \$0,$A0[0] + add $A1[1],$A0[1] + adc \$0,$A0[0] + + + mul $a1 # a[4]*a[3] + add %rax,$A1[0] # a[4]*a[3]+t[5] + mov $ai,%rax + mov $A0[1],($tptr,$j) # t[4] + mov %rdx,$A1[1] + adc \$0,$A1[1] + + mul $a0 # a[5]*a[2] + add %rax,$A0[0] # a[5]*a[2]+a[4]*a[3]+t[5] + mov $ai,%rax + mov 16($aptr,$j),$ai # a[6] + mov %rdx,$A0[1] + adc \$0,$A0[1] + add $A1[0],$A0[0] + adc \$0,$A0[1] + + mul $a1 # a[5]*a[3] + add %rax,$A1[1] # a[5]*a[3]+t[6] + mov $ai,%rax + mov $A0[0],8($tptr,$j) # t[5] + mov %rdx,$A1[0] + adc \$0,$A1[0] + + mul $a0 # a[6]*a[2] + add %rax,$A0[1] # a[6]*a[2]+a[5]*a[3]+t[6] + mov $ai,%rax # a[3] + mov 24($aptr,$j),$ai # a[7] + mov %rdx,$A0[0] + adc \$0,$A0[0] + add $A1[1],$A0[1] + adc \$0,$A0[0] + + + mul $a1 # a[6]*a[5] + add %rax,$A1[0] # a[6]*a[5]+t[7] + mov $ai,%rax + mov $A0[1],16($tptr,$j) # t[6] + mov %rdx,$A1[1] + adc \$0,$A1[1] + lea 32($j),$j + + mul $a0 # a[7]*a[4] + add %rax,$A0[0] # a[7]*a[4]+a[6]*a[5]+t[6] + mov $ai,%rax + mov %rdx,$A0[1] + adc \$0,$A0[1] + add $A1[0],$A0[0] + adc \$0,$A0[1] + mov $A0[0],-8($tptr,$j) # t[7] + + cmp \$0,$j + jne .Lsqr4x_1st + + mul $a1 # a[7]*a[5] + add %rax,$A1[1] + lea 16($i),$i + adc \$0,%rdx + add $A0[1],$A1[1] + adc \$0,%rdx + + mov $A1[1],($tptr) # t[8] + mov %rdx,$A1[0] + mov %rdx,8($tptr) # t[9] + jmp .Lsqr4x_outer + +.align 32 +.Lsqr4x_outer: # comments apply to $num==6 case + mov -32($aptr,$i),$a0 # a[0] + lea 48+8(%rsp,$num,2),$tptr # end of tp[] buffer, &tp[2*$num] + mov -24($aptr,$i),%rax # a[1] + lea -32($tptr,$i),$tptr # end of tp[] window, &tp[2*$num-"$i"] + mov -16($aptr,$i),$ai # a[2] + mov %rax,$a1 + + mul $a0 # a[1]*a[0] + mov -24($tptr,$i),$A0[0] # t[1] + add %rax,$A0[0] # a[1]*a[0]+t[1] + mov $ai,%rax # a[2] + adc \$0,%rdx + mov $A0[0],-24($tptr,$i) # t[1] + mov %rdx,$A0[1] + + mul $a0 # a[2]*a[0] + add %rax,$A0[1] + mov $ai,%rax + adc \$0,%rdx + add -16($tptr,$i),$A0[1] # a[2]*a[0]+t[2] + mov %rdx,$A0[0] + adc \$0,$A0[0] + mov $A0[1],-16($tptr,$i) # t[2] + + xor $A1[0],$A1[0] + + mov -8($aptr,$i),$ai # a[3] + mul $a1 # a[2]*a[1] + add %rax,$A1[0] # a[2]*a[1]+t[3] + mov $ai,%rax + adc \$0,%rdx + add -8($tptr,$i),$A1[0] + mov %rdx,$A1[1] + adc \$0,$A1[1] + + mul $a0 # a[3]*a[0] + add %rax,$A0[0] # a[3]*a[0]+a[2]*a[1]+t[3] + mov $ai,%rax + adc \$0,%rdx + add $A1[0],$A0[0] + mov %rdx,$A0[1] + adc \$0,$A0[1] + mov $A0[0],-8($tptr,$i) # t[3] + + lea ($i),$j + jmp .Lsqr4x_inner + +.align 32 +.Lsqr4x_inner: + mov ($aptr,$j),$ai # a[4] + mul $a1 # a[3]*a[1] + add %rax,$A1[1] # a[3]*a[1]+t[4] + mov $ai,%rax + mov %rdx,$A1[0] + adc \$0,$A1[0] + add ($tptr,$j),$A1[1] + adc \$0,$A1[0] + + .byte 0x67 + mul $a0 # a[4]*a[0] + add %rax,$A0[1] # a[4]*a[0]+a[3]*a[1]+t[4] + mov $ai,%rax # a[3] + mov 8($aptr,$j),$ai # a[5] + mov %rdx,$A0[0] + adc \$0,$A0[0] + add $A1[1],$A0[1] + adc \$0,$A0[0] + + mul $a1 # a[4]*a[3] + add %rax,$A1[0] # a[4]*a[3]+t[5] + mov $A0[1],($tptr,$j) # t[4] + mov $ai,%rax + mov %rdx,$A1[1] + adc \$0,$A1[1] + add 8($tptr,$j),$A1[0] + lea 16($j),$j # j++ + adc \$0,$A1[1] + + mul $a0 # a[5]*a[2] + add %rax,$A0[0] # a[5]*a[2]+a[4]*a[3]+t[5] + mov $ai,%rax + adc \$0,%rdx + add $A1[0],$A0[0] + mov %rdx,$A0[1] + adc \$0,$A0[1] + mov $A0[0],-8($tptr,$j) # t[5], "preloaded t[1]" below + + cmp \$0,$j + jne .Lsqr4x_inner + + .byte 0x67 + mul $a1 # a[5]*a[3] + add %rax,$A1[1] + adc \$0,%rdx + add $A0[1],$A1[1] + adc \$0,%rdx + + mov $A1[1],($tptr) # t[6], "preloaded t[2]" below + mov %rdx,$A1[0] + mov %rdx,8($tptr) # t[7], "preloaded t[3]" below + + add \$16,$i + jnz .Lsqr4x_outer + + # comments apply to $num==4 case + mov -32($aptr),$a0 # a[0] + lea 48+8(%rsp,$num,2),$tptr # end of tp[] buffer, &tp[2*$num] + mov -24($aptr),%rax # a[1] + lea -32($tptr,$i),$tptr # end of tp[] window, &tp[2*$num-"$i"] + mov -16($aptr),$ai # a[2] + mov %rax,$a1 + + mul $a0 # a[1]*a[0] + add %rax,$A0[0] # a[1]*a[0]+t[1], preloaded t[1] + mov $ai,%rax # a[2] + mov %rdx,$A0[1] + adc \$0,$A0[1] + + mul $a0 # a[2]*a[0] + add %rax,$A0[1] + mov $ai,%rax + mov $A0[0],-24($tptr) # t[1] + mov %rdx,$A0[0] + adc \$0,$A0[0] + add $A1[1],$A0[1] # a[2]*a[0]+t[2], preloaded t[2] + mov -8($aptr),$ai # a[3] + adc \$0,$A0[0] + + mul $a1 # a[2]*a[1] + add %rax,$A1[0] # a[2]*a[1]+t[3], preloaded t[3] + mov $ai,%rax + mov $A0[1],-16($tptr) # t[2] + mov %rdx,$A1[1] + adc \$0,$A1[1] + + mul $a0 # a[3]*a[0] + add %rax,$A0[0] # a[3]*a[0]+a[2]*a[1]+t[3] + mov $ai,%rax + mov %rdx,$A0[1] + adc \$0,$A0[1] + add $A1[0],$A0[0] + adc \$0,$A0[1] + mov $A0[0],-8($tptr) # t[3] + + mul $a1 # a[3]*a[1] + add %rax,$A1[1] + mov -16($aptr),%rax # a[2] + adc \$0,%rdx + add $A0[1],$A1[1] + adc \$0,%rdx + + mov $A1[1],($tptr) # t[4] + mov %rdx,$A1[0] + mov %rdx,8($tptr) # t[5] + + mul $ai # a[2]*a[3] +___ +{ +my ($shift,$carry)=($a0,$a1); +my @S=(@A1,$ai,$n0); +$code.=<<___; + add \$16,$i + xor $shift,$shift + sub $num,$i # $i=16-$num + xor $carry,$carry + + add $A1[0],%rax # t[5] + adc \$0,%rdx + mov %rax,8($tptr) # t[5] + mov %rdx,16($tptr) # t[6] + mov $carry,24($tptr) # t[7] + + mov -16($aptr,$i),%rax # a[0] + lea 48+8(%rsp),$tptr + xor $A0[0],$A0[0] # t[0] + mov 8($tptr),$A0[1] # t[1] + + lea ($shift,$A0[0],2),$S[0] # t[2*i]<<1 | shift + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[1] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[1] # | t[2*i]>>63 + mov 16($tptr),$A0[0] # t[2*i+2] # prefetch + mov $A0[1],$shift # shift=t[2*i+1]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + mov 24($tptr),$A0[1] # t[2*i+2+1] # prefetch + adc %rax,$S[0] + mov -8($aptr,$i),%rax # a[i+1] # prefetch + mov $S[0],($tptr) + adc %rdx,$S[1] + + lea ($shift,$A0[0],2),$S[2] # t[2*i]<<1 | shift + mov $S[1],8($tptr) + sbb $carry,$carry # mov cf,$carry + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[3] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[3] # | t[2*i]>>63 + mov 32($tptr),$A0[0] # t[2*i+2] # prefetch + mov $A0[1],$shift # shift=t[2*i+1]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + mov 40($tptr),$A0[1] # t[2*i+2+1] # prefetch + adc %rax,$S[2] + mov 0($aptr,$i),%rax # a[i+1] # prefetch + mov $S[2],16($tptr) + adc %rdx,$S[3] + lea 16($i),$i + mov $S[3],24($tptr) + sbb $carry,$carry # mov cf,$carry + lea 64($tptr),$tptr + jmp .Lsqr4x_shift_n_add + +.align 32 +.Lsqr4x_shift_n_add: + lea ($shift,$A0[0],2),$S[0] # t[2*i]<<1 | shift + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[1] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[1] # | t[2*i]>>63 + mov -16($tptr),$A0[0] # t[2*i+2] # prefetch + mov $A0[1],$shift # shift=t[2*i+1]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + mov -8($tptr),$A0[1] # t[2*i+2+1] # prefetch + adc %rax,$S[0] + mov -8($aptr,$i),%rax # a[i+1] # prefetch + mov $S[0],-32($tptr) + adc %rdx,$S[1] + + lea ($shift,$A0[0],2),$S[2] # t[2*i]<<1 | shift + mov $S[1],-24($tptr) + sbb $carry,$carry # mov cf,$carry + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[3] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[3] # | t[2*i]>>63 + mov 0($tptr),$A0[0] # t[2*i+2] # prefetch + mov $A0[1],$shift # shift=t[2*i+1]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + mov 8($tptr),$A0[1] # t[2*i+2+1] # prefetch + adc %rax,$S[2] + mov 0($aptr,$i),%rax # a[i+1] # prefetch + mov $S[2],-16($tptr) + adc %rdx,$S[3] + + lea ($shift,$A0[0],2),$S[0] # t[2*i]<<1 | shift + mov $S[3],-8($tptr) + sbb $carry,$carry # mov cf,$carry + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[1] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[1] # | t[2*i]>>63 + mov 16($tptr),$A0[0] # t[2*i+2] # prefetch + mov $A0[1],$shift # shift=t[2*i+1]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + mov 24($tptr),$A0[1] # t[2*i+2+1] # prefetch + adc %rax,$S[0] + mov 8($aptr,$i),%rax # a[i+1] # prefetch + mov $S[0],0($tptr) + adc %rdx,$S[1] + + lea ($shift,$A0[0],2),$S[2] # t[2*i]<<1 | shift + mov $S[1],8($tptr) + sbb $carry,$carry # mov cf,$carry + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[3] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[3] # | t[2*i]>>63 + mov 32($tptr),$A0[0] # t[2*i+2] # prefetch + mov $A0[1],$shift # shift=t[2*i+1]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + mov 40($tptr),$A0[1] # t[2*i+2+1] # prefetch + adc %rax,$S[2] + mov 16($aptr,$i),%rax # a[i+1] # prefetch + mov $S[2],16($tptr) + adc %rdx,$S[3] + mov $S[3],24($tptr) + sbb $carry,$carry # mov cf,$carry + lea 64($tptr),$tptr + add \$32,$i + jnz .Lsqr4x_shift_n_add + + lea ($shift,$A0[0],2),$S[0] # t[2*i]<<1 | shift + .byte 0x67 + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[1] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[1] # | t[2*i]>>63 + mov -16($tptr),$A0[0] # t[2*i+2] # prefetch + mov $A0[1],$shift # shift=t[2*i+1]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + mov -8($tptr),$A0[1] # t[2*i+2+1] # prefetch + adc %rax,$S[0] + mov -8($aptr),%rax # a[i+1] # prefetch + mov $S[0],-32($tptr) + adc %rdx,$S[1] + + lea ($shift,$A0[0],2),$S[2] # t[2*i]<<1|shift + mov $S[1],-24($tptr) + sbb $carry,$carry # mov cf,$carry + shr \$63,$A0[0] + lea ($j,$A0[1],2),$S[3] # t[2*i+1]<<1 | + shr \$63,$A0[1] + or $A0[0],$S[3] # | t[2*i]>>63 + mul %rax # a[i]*a[i] + neg $carry # mov $carry,cf + adc %rax,$S[2] + adc %rdx,$S[3] + mov $S[2],-16($tptr) + mov $S[3],-8($tptr) +___ +} +###################################################################### +# Montgomery reduction part, "word-by-word" algorithm. +# +# This new path is inspired by multiple submissions from Intel, by +# Shay Gueron, Vlad Krasnov, Erdinc Ozturk, James Guilford, +# Vinodh Gopal... +{ +my ($nptr,$tptr,$carry,$m0)=("%rbp","%rdi","%rsi","%rbx"); + +$code.=<<___; + movq %xmm2,$nptr +sqr8x_reduction: + xor %rax,%rax + lea ($nptr,$num,2),%rcx # end of n[] + lea 48+8(%rsp,$num,2),%rdx # end of t[] buffer + mov %rcx,0+8(%rsp) + lea 48+8(%rsp,$num),$tptr # end of initial t[] window + mov %rdx,8+8(%rsp) + neg $num + jmp .L8x_reduction_loop + +.align 32 +.L8x_reduction_loop: + lea ($tptr,$num),$tptr # start of current t[] window + .byte 0x66 + mov 8*0($tptr),$m0 + mov 8*1($tptr),%r9 + mov 8*2($tptr),%r10 + mov 8*3($tptr),%r11 + mov 8*4($tptr),%r12 + mov 8*5($tptr),%r13 + mov 8*6($tptr),%r14 + mov 8*7($tptr),%r15 + mov %rax,(%rdx) # store top-most carry bit + lea 8*8($tptr),$tptr + + .byte 0x67 + mov $m0,%r8 + imulq 32+8(%rsp),$m0 # n0*a[0] + mov 16*0($nptr),%rax # n[0] + mov \$8,%ecx + jmp .L8x_reduce + +.align 32 +.L8x_reduce: + mulq $m0 + mov 16*1($nptr),%rax # n[1] + neg %r8 + mov %rdx,%r8 + adc \$0,%r8 + + mulq $m0 + add %rax,%r9 + mov 16*2($nptr),%rax + adc \$0,%rdx + add %r9,%r8 + mov $m0,48-8+8(%rsp,%rcx,8) # put aside n0*a[i] + mov %rdx,%r9 + adc \$0,%r9 + + mulq $m0 + add %rax,%r10 + mov 16*3($nptr),%rax + adc \$0,%rdx + add %r10,%r9 + mov 32+8(%rsp),$carry # pull n0, borrow $carry + mov %rdx,%r10 + adc \$0,%r10 + + mulq $m0 + add %rax,%r11 + mov 16*4($nptr),%rax + adc \$0,%rdx + imulq %r8,$carry # modulo-scheduled + add %r11,%r10 + mov %rdx,%r11 + adc \$0,%r11 + + mulq $m0 + add %rax,%r12 + mov 16*5($nptr),%rax + adc \$0,%rdx + add %r12,%r11 + mov %rdx,%r12 + adc \$0,%r12 + + mulq $m0 + add %rax,%r13 + mov 16*6($nptr),%rax + adc \$0,%rdx + add %r13,%r12 + mov %rdx,%r13 + adc \$0,%r13 + + mulq $m0 + add %rax,%r14 + mov 16*7($nptr),%rax + adc \$0,%rdx + add %r14,%r13 + mov %rdx,%r14 + adc \$0,%r14 + + mulq $m0 + mov $carry,$m0 # n0*a[i] + add %rax,%r15 + mov 16*0($nptr),%rax # n[0] + adc \$0,%rdx + add %r15,%r14 + mov %rdx,%r15 + adc \$0,%r15 + + dec %ecx + jnz .L8x_reduce + + lea 16*8($nptr),$nptr + xor %rax,%rax + mov 8+8(%rsp),%rdx # pull end of t[] + cmp 0+8(%rsp),$nptr # end of n[]? + jae .L8x_no_tail + + .byte 0x66 + add 8*0($tptr),%r8 + adc 8*1($tptr),%r9 + adc 8*2($tptr),%r10 + adc 8*3($tptr),%r11 + adc 8*4($tptr),%r12 + adc 8*5($tptr),%r13 + adc 8*6($tptr),%r14 + adc 8*7($tptr),%r15 + sbb $carry,$carry # top carry + + mov 48+56+8(%rsp),$m0 # pull n0*a[0] + mov \$8,%ecx + mov 16*0($nptr),%rax + jmp .L8x_tail + +.align 32 +.L8x_tail: + mulq $m0 + add %rax,%r8 + mov 16*1($nptr),%rax + mov %r8,($tptr) # save result + mov %rdx,%r8 + adc \$0,%r8 + + mulq $m0 + add %rax,%r9 + mov 16*2($nptr),%rax + adc \$0,%rdx + add %r9,%r8 + lea 8($tptr),$tptr # $tptr++ + mov %rdx,%r9 + adc \$0,%r9 + + mulq $m0 + add %rax,%r10 + mov 16*3($nptr),%rax + adc \$0,%rdx + add %r10,%r9 + mov %rdx,%r10 + adc \$0,%r10 + + mulq $m0 + add %rax,%r11 + mov 16*4($nptr),%rax + adc \$0,%rdx + add %r11,%r10 + mov %rdx,%r11 + adc \$0,%r11 + + mulq $m0 + add %rax,%r12 + mov 16*5($nptr),%rax + adc \$0,%rdx + add %r12,%r11 + mov %rdx,%r12 + adc \$0,%r12 + + mulq $m0 + add %rax,%r13 + mov 16*6($nptr),%rax + adc \$0,%rdx + add %r13,%r12 + mov %rdx,%r13 + adc \$0,%r13 + + mulq $m0 + add %rax,%r14 + mov 16*7($nptr),%rax + adc \$0,%rdx + add %r14,%r13 + mov %rdx,%r14 + adc \$0,%r14 + + mulq $m0 + mov 48-16+8(%rsp,%rcx,8),$m0# pull n0*a[i] + add %rax,%r15 + adc \$0,%rdx + add %r15,%r14 + mov 16*0($nptr),%rax # pull n[0] + mov %rdx,%r15 + adc \$0,%r15 + + dec %ecx + jnz .L8x_tail + + lea 16*8($nptr),$nptr + mov 8+8(%rsp),%rdx # pull end of t[] + cmp 0+8(%rsp),$nptr # end of n[]? + jae .L8x_tail_done # break out of loop + + mov 48+56+8(%rsp),$m0 # pull n0*a[0] + neg $carry + mov 8*0($nptr),%rax # pull n[0] + adc 8*0($tptr),%r8 + adc 8*1($tptr),%r9 + adc 8*2($tptr),%r10 + adc 8*3($tptr),%r11 + adc 8*4($tptr),%r12 + adc 8*5($tptr),%r13 + adc 8*6($tptr),%r14 + adc 8*7($tptr),%r15 + sbb $carry,$carry # top carry + + mov \$8,%ecx + jmp .L8x_tail + +.align 32 +.L8x_tail_done: + add (%rdx),%r8 # can this overflow? + xor %rax,%rax + + neg $carry +.L8x_no_tail: + adc 8*0($tptr),%r8 + adc 8*1($tptr),%r9 + adc 8*2($tptr),%r10 + adc 8*3($tptr),%r11 + adc 8*4($tptr),%r12 + adc 8*5($tptr),%r13 + adc 8*6($tptr),%r14 + adc 8*7($tptr),%r15 + adc \$0,%rax # top-most carry + mov -16($nptr),%rcx # np[num-1] + xor $carry,$carry + + movq %xmm2,$nptr # restore $nptr + + mov %r8,8*0($tptr) # store top 512 bits + mov %r9,8*1($tptr) + movq %xmm3,$num # $num is %r9, can't be moved upwards + mov %r10,8*2($tptr) + mov %r11,8*3($tptr) + mov %r12,8*4($tptr) + mov %r13,8*5($tptr) + mov %r14,8*6($tptr) + mov %r15,8*7($tptr) + lea 8*8($tptr),$tptr + + cmp %rdx,$tptr # end of t[]? + jb .L8x_reduction_loop +___ +} +############################################################## +# Post-condition, 4x unrolled +# +{ +my ($tptr,$nptr)=("%rbx","%rbp"); +$code.=<<___; + #xor %rsi,%rsi # %rsi was $carry above + sub %r15,%rcx # compare top-most words + lea (%rdi,$num),$tptr # %rdi was $tptr above + adc %rsi,%rsi + mov $num,%rcx + or %rsi,%rax + movq %xmm1,$rptr # restore $rptr + xor \$1,%rax + movq %xmm1,$aptr # prepare for back-to-back call + lea ($nptr,%rax,8),$nptr + sar \$3+2,%rcx # cf=0 + jmp .Lsqr4x_sub + +.align 32 +.Lsqr4x_sub: + .byte 0x66 + mov 8*0($tptr),%r12 + mov 8*1($tptr),%r13 + sbb 16*0($nptr),%r12 + mov 8*2($tptr),%r14 + sbb 16*1($nptr),%r13 + mov 8*3($tptr),%r15 + lea 8*4($tptr),$tptr + sbb 16*2($nptr),%r14 + mov %r12,8*0($rptr) + sbb 16*3($nptr),%r15 + lea 16*4($nptr),$nptr + mov %r13,8*1($rptr) + mov %r14,8*2($rptr) + mov %r15,8*3($rptr) + lea 8*4($rptr),$rptr + + inc %rcx # pass %cf + jnz .Lsqr4x_sub +___ +} +$code.=<<___; + mov $num,%r10 # prepare for back-to-back call + neg $num # restore $num + ret +.size bn_sqr8x_internal,.-bn_sqr8x_internal +___ +{ +$code.=<<___; +.globl bn_from_montgomery +.type bn_from_montgomery,\@abi-omnipotent +.align 32 +bn_from_montgomery: + testl \$7,`($win64?"48(%rsp)":"%r9d")` + jz bn_from_mont8x + xor %eax,%eax + ret +.size bn_from_montgomery,.-bn_from_montgomery + +.type bn_from_mont8x,\@function,6 +.align 32 +bn_from_mont8x: + .byte 0x67 + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0x28(%rsp),%rsp + movaps %xmm6,(%rsp) + movaps %xmm7,0x10(%rsp) +___ +$code.=<<___; + .byte 0x67 + mov ${num}d,%r10d + shl \$3,${num}d # convert $num to bytes + shl \$3+2,%r10d # 4*$num + neg $num + mov ($n0),$n0 # *n0 + + ############################################################## + # ensure that stack frame doesn't alias with $aptr+4*$num + # modulo 4096, which covers ret[num], am[num] and n[2*num] + # (see bn_exp.c). this is done to allow memory disambiguation + # logic do its magic. + # + lea -64(%rsp,$num,2),%r11 + sub $aptr,%r11 + and \$4095,%r11 + cmp %r11,%r10 + jb .Lfrom_sp_alt + sub %r11,%rsp # align with $aptr + lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num) + jmp .Lfrom_sp_done + +.align 32 +.Lfrom_sp_alt: + lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num + lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num) + sub %r10,%r11 + mov \$0,%r10 + cmovc %r10,%r11 + sub %r11,%rsp +.Lfrom_sp_done: + and \$-64,%rsp + mov $num,%r10 + neg $num + + ############################################################## + # Stack layout + # + # +0 saved $num, used in reduction section + # +8 &t[2*$num], used in reduction section + # +32 saved *n0 + # +40 saved %rsp + # +48 t[2*$num] + # + mov $n0, 32(%rsp) + mov %rax, 40(%rsp) # save original %rsp +.Lfrom_body: + mov $num,%r11 + lea 48(%rsp),%rax + pxor %xmm0,%xmm0 + jmp .Lmul_by_1 + +.align 32 +.Lmul_by_1: + movdqu ($aptr),%xmm1 + movdqu 16($aptr),%xmm2 + movdqu 32($aptr),%xmm3 + movdqa %xmm0,(%rax,$num) + movdqu 48($aptr),%xmm4 + movdqa %xmm0,16(%rax,$num) + .byte 0x48,0x8d,0xb6,0x40,0x00,0x00,0x00 # lea 64($aptr),$aptr + movdqa %xmm1,(%rax) + movdqa %xmm0,32(%rax,$num) + movdqa %xmm2,16(%rax) + movdqa %xmm0,48(%rax,$num) + movdqa %xmm3,32(%rax) + movdqa %xmm4,48(%rax) + lea 64(%rax),%rax + sub \$64,%r11 + jnz .Lmul_by_1 + + movq $rptr,%xmm1 + movq $nptr,%xmm2 + .byte 0x67 + mov $nptr,%rbp + movq %r10, %xmm3 # -num +___ +$code.=<<___ if ($addx); + mov OPENSSL_ia32cap_P+8(%rip),%r11d + and \$0x80100,%r11d + cmp \$0x80100,%r11d + jne .Lfrom_mont_nox + + lea (%rax,$num),$rptr + call sqrx8x_reduction + + pxor %xmm0,%xmm0 + lea 48(%rsp),%rax + mov 40(%rsp),%rsi # restore %rsp + jmp .Lfrom_mont_zero + +.align 32 +.Lfrom_mont_nox: +___ +$code.=<<___; + call sqr8x_reduction + + pxor %xmm0,%xmm0 + lea 48(%rsp),%rax + mov 40(%rsp),%rsi # restore %rsp + jmp .Lfrom_mont_zero + +.align 32 +.Lfrom_mont_zero: + movdqa %xmm0,16*0(%rax) + movdqa %xmm0,16*1(%rax) + movdqa %xmm0,16*2(%rax) + movdqa %xmm0,16*3(%rax) + lea 16*4(%rax),%rax + sub \$32,$num + jnz .Lfrom_mont_zero + + mov \$1,%rax + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lfrom_epilogue: + ret +.size bn_from_mont8x,.-bn_from_mont8x +___ +} +}}} + +if ($addx) {{{ +my $bp="%rdx"; # restore original value + +$code.=<<___; +.type bn_mulx4x_mont_gather5,\@function,6 +.align 32 +bn_mulx4x_mont_gather5: +.Lmulx4x_enter: + .byte 0x67 + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0x28(%rsp),%rsp + movaps %xmm6,(%rsp) + movaps %xmm7,0x10(%rsp) +___ +$code.=<<___; + .byte 0x67 + mov ${num}d,%r10d + shl \$3,${num}d # convert $num to bytes + shl \$3+2,%r10d # 4*$num + neg $num # -$num + mov ($n0),$n0 # *n0 + + ############################################################## + # ensure that stack frame doesn't alias with $aptr+4*$num + # modulo 4096, which covers a[num], ret[num] and n[2*num] + # (see bn_exp.c). this is done to allow memory disambiguation + # logic do its magic. [excessive frame is allocated in order + # to allow bn_from_mont8x to clear it.] + # + lea -64(%rsp,$num,2),%r11 + sub $ap,%r11 + and \$4095,%r11 + cmp %r11,%r10 + jb .Lmulx4xsp_alt + sub %r11,%rsp # align with $aptr + lea -64(%rsp,$num,2),%rsp # alloca(frame+$num) + jmp .Lmulx4xsp_done + +.align 32 +.Lmulx4xsp_alt: + lea 4096-64(,$num,2),%r10 # 4096-frame-$num + lea -64(%rsp,$num,2),%rsp # alloca(frame+$num) + sub %r10,%r11 + mov \$0,%r10 + cmovc %r10,%r11 + sub %r11,%rsp +.Lmulx4xsp_done: + and \$-64,%rsp # ensure alignment + ############################################################## + # Stack layout + # +0 -num + # +8 off-loaded &b[i] + # +16 end of b[num] + # +24 inner counter + # +32 saved n0 + # +40 saved %rsp + # +48 + # +56 saved rp + # +64 tmp[num+1] + # + mov $n0, 32(%rsp) # save *n0 + mov %rax,40(%rsp) # save original %rsp +.Lmulx4x_body: + call mulx4x_internal + + mov 40(%rsp),%rsi # restore %rsp + mov \$1,%rax +___ +$code.=<<___ if ($win64); + movaps -88(%rsi),%xmm6 + movaps -72(%rsi),%xmm7 +___ +$code.=<<___; + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lmulx4x_epilogue: + ret +.size bn_mulx4x_mont_gather5,.-bn_mulx4x_mont_gather5 + +.type mulx4x_internal,\@abi-omnipotent +.align 32 +mulx4x_internal: + .byte 0x4c,0x89,0x8c,0x24,0x08,0x00,0x00,0x00 # mov $num,8(%rsp) # save -$num + .byte 0x67 + neg $num # restore $num + shl \$5,$num + lea 256($bp,$num),%r13 + shr \$5+5,$num + mov `($win64?56:8)`(%rax),%r10d # load 7th argument + sub \$1,$num + mov %r13,16+8(%rsp) # end of b[num] + mov $num,24+8(%rsp) # inner counter + mov $rp, 56+8(%rsp) # save $rp +___ +my ($aptr, $bptr, $nptr, $tptr, $mi, $bi, $zero, $num)= + ("%rsi","%rdi","%rcx","%rbx","%r8","%r9","%rbp","%rax"); +my $rptr=$bptr; +my $STRIDE=2**5*8; # 5 is "window size" +my $N=$STRIDE/4; # should match cache line size +$code.=<<___; + mov %r10,%r11 + shr \$`log($N/8)/log(2)`,%r10 + and \$`$N/8-1`,%r11 + not %r10 + lea .Lmagic_masks(%rip),%rax + and \$`2**5/($N/8)-1`,%r10 # 5 is "window size" + lea 96($bp,%r11,8),$bptr # pointer within 1st cache line + movq 0(%rax,%r10,8),%xmm4 # set of masks denoting which + movq 8(%rax,%r10,8),%xmm5 # cache line contains element + add \$7,%r11 + movq 16(%rax,%r10,8),%xmm6 # denoted by 7th argument + movq 24(%rax,%r10,8),%xmm7 + and \$7,%r11 + + movq `0*$STRIDE/4-96`($bptr),%xmm0 + lea $STRIDE($bptr),$tptr # borrow $tptr + movq `1*$STRIDE/4-96`($bptr),%xmm1 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-96`($bptr),%xmm2 + pand %xmm5,%xmm1 + movq `3*$STRIDE/4-96`($bptr),%xmm3 + pand %xmm6,%xmm2 + por %xmm1,%xmm0 + movq `0*$STRIDE/4-96`($tptr),%xmm1 + pand %xmm7,%xmm3 + por %xmm2,%xmm0 + movq `1*$STRIDE/4-96`($tptr),%xmm2 + por %xmm3,%xmm0 + .byte 0x67,0x67 + pand %xmm4,%xmm1 + movq `2*$STRIDE/4-96`($tptr),%xmm3 + + movq %xmm0,%rdx # bp[0] + movq `3*$STRIDE/4-96`($tptr),%xmm0 + lea 2*$STRIDE($bptr),$bptr # next &b[i] + pand %xmm5,%xmm2 + .byte 0x67,0x67 + pand %xmm6,%xmm3 + ############################################################## + # $tptr is chosen so that writing to top-most element of the + # vector occurs just "above" references to powers table, + # "above" modulo cache-line size, which effectively precludes + # possibility of memory disambiguation logic failure when + # accessing the table. + # + lea 64+8*4+8(%rsp,%r11,8),$tptr + + mov %rdx,$bi + mulx 0*8($aptr),$mi,%rax # a[0]*b[0] + mulx 1*8($aptr),%r11,%r12 # a[1]*b[0] + add %rax,%r11 + mulx 2*8($aptr),%rax,%r13 # ... + adc %rax,%r12 + adc \$0,%r13 + mulx 3*8($aptr),%rax,%r14 + + mov $mi,%r15 + imulq 32+8(%rsp),$mi # "t[0]"*n0 + xor $zero,$zero # cf=0, of=0 + mov $mi,%rdx + + por %xmm2,%xmm1 + pand %xmm7,%xmm0 + por %xmm3,%xmm1 + mov $bptr,8+8(%rsp) # off-load &b[i] + por %xmm1,%xmm0 + + .byte 0x48,0x8d,0xb6,0x20,0x00,0x00,0x00 # lea 4*8($aptr),$aptr + adcx %rax,%r13 + adcx $zero,%r14 # cf=0 + + mulx 0*16($nptr),%rax,%r10 + adcx %rax,%r15 # discarded + adox %r11,%r10 + mulx 1*16($nptr),%rax,%r11 + adcx %rax,%r10 + adox %r12,%r11 + mulx 2*16($nptr),%rax,%r12 + mov 24+8(%rsp),$bptr # counter value + .byte 0x66 + mov %r10,-8*4($tptr) + adcx %rax,%r11 + adox %r13,%r12 + mulx 3*16($nptr),%rax,%r15 + .byte 0x67,0x67 + mov $bi,%rdx + mov %r11,-8*3($tptr) + adcx %rax,%r12 + adox $zero,%r15 # of=0 + .byte 0x48,0x8d,0x89,0x40,0x00,0x00,0x00 # lea 4*16($nptr),$nptr + mov %r12,-8*2($tptr) + #jmp .Lmulx4x_1st + +.align 32 +.Lmulx4x_1st: + adcx $zero,%r15 # cf=0, modulo-scheduled + mulx 0*8($aptr),%r10,%rax # a[4]*b[0] + adcx %r14,%r10 + mulx 1*8($aptr),%r11,%r14 # a[5]*b[0] + adcx %rax,%r11 + mulx 2*8($aptr),%r12,%rax # ... + adcx %r14,%r12 + mulx 3*8($aptr),%r13,%r14 + .byte 0x67,0x67 + mov $mi,%rdx + adcx %rax,%r13 + adcx $zero,%r14 # cf=0 + lea 4*8($aptr),$aptr + lea 4*8($tptr),$tptr + + adox %r15,%r10 + mulx 0*16($nptr),%rax,%r15 + adcx %rax,%r10 + adox %r15,%r11 + mulx 1*16($nptr),%rax,%r15 + adcx %rax,%r11 + adox %r15,%r12 + mulx 2*16($nptr),%rax,%r15 + mov %r10,-5*8($tptr) + adcx %rax,%r12 + mov %r11,-4*8($tptr) + adox %r15,%r13 + mulx 3*16($nptr),%rax,%r15 + mov $bi,%rdx + mov %r12,-3*8($tptr) + adcx %rax,%r13 + adox $zero,%r15 + lea 4*16($nptr),$nptr + mov %r13,-2*8($tptr) + + dec $bptr # of=0, pass cf + jnz .Lmulx4x_1st + + mov 8(%rsp),$num # load -num + movq %xmm0,%rdx # bp[1] + adc $zero,%r15 # modulo-scheduled + lea ($aptr,$num),$aptr # rewind $aptr + add %r15,%r14 + mov 8+8(%rsp),$bptr # re-load &b[i] + adc $zero,$zero # top-most carry + mov %r14,-1*8($tptr) + jmp .Lmulx4x_outer + +.align 32 +.Lmulx4x_outer: + mov $zero,($tptr) # save top-most carry + lea 4*8($tptr,$num),$tptr # rewind $tptr + mulx 0*8($aptr),$mi,%r11 # a[0]*b[i] + xor $zero,$zero # cf=0, of=0 + mov %rdx,$bi + mulx 1*8($aptr),%r14,%r12 # a[1]*b[i] + adox -4*8($tptr),$mi # +t[0] + adcx %r14,%r11 + mulx 2*8($aptr),%r15,%r13 # ... + adox -3*8($tptr),%r11 + adcx %r15,%r12 + mulx 3*8($aptr),%rdx,%r14 + adox -2*8($tptr),%r12 + adcx %rdx,%r13 + lea ($nptr,$num,2),$nptr # rewind $nptr + lea 4*8($aptr),$aptr + adox -1*8($tptr),%r13 + adcx $zero,%r14 + adox $zero,%r14 + + .byte 0x67 + mov $mi,%r15 + imulq 32+8(%rsp),$mi # "t[0]"*n0 + + movq `0*$STRIDE/4-96`($bptr),%xmm0 + .byte 0x67,0x67 + mov $mi,%rdx + movq `1*$STRIDE/4-96`($bptr),%xmm1 + .byte 0x67 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-96`($bptr),%xmm2 + .byte 0x67 + pand %xmm5,%xmm1 + movq `3*$STRIDE/4-96`($bptr),%xmm3 + add \$$STRIDE,$bptr # next &b[i] + .byte 0x67 + pand %xmm6,%xmm2 + por %xmm1,%xmm0 + pand %xmm7,%xmm3 + xor $zero,$zero # cf=0, of=0 + mov $bptr,8+8(%rsp) # off-load &b[i] + + mulx 0*16($nptr),%rax,%r10 + adcx %rax,%r15 # discarded + adox %r11,%r10 + mulx 1*16($nptr),%rax,%r11 + adcx %rax,%r10 + adox %r12,%r11 + mulx 2*16($nptr),%rax,%r12 + adcx %rax,%r11 + adox %r13,%r12 + mulx 3*16($nptr),%rax,%r15 + mov $bi,%rdx + por %xmm2,%xmm0 + mov 24+8(%rsp),$bptr # counter value + mov %r10,-8*4($tptr) + por %xmm3,%xmm0 + adcx %rax,%r12 + mov %r11,-8*3($tptr) + adox $zero,%r15 # of=0 + mov %r12,-8*2($tptr) + lea 4*16($nptr),$nptr + jmp .Lmulx4x_inner + +.align 32 +.Lmulx4x_inner: + mulx 0*8($aptr),%r10,%rax # a[4]*b[i] + adcx $zero,%r15 # cf=0, modulo-scheduled + adox %r14,%r10 + mulx 1*8($aptr),%r11,%r14 # a[5]*b[i] + adcx 0*8($tptr),%r10 + adox %rax,%r11 + mulx 2*8($aptr),%r12,%rax # ... + adcx 1*8($tptr),%r11 + adox %r14,%r12 + mulx 3*8($aptr),%r13,%r14 + mov $mi,%rdx + adcx 2*8($tptr),%r12 + adox %rax,%r13 + adcx 3*8($tptr),%r13 + adox $zero,%r14 # of=0 + lea 4*8($aptr),$aptr + lea 4*8($tptr),$tptr + adcx $zero,%r14 # cf=0 + + adox %r15,%r10 + mulx 0*16($nptr),%rax,%r15 + adcx %rax,%r10 + adox %r15,%r11 + mulx 1*16($nptr),%rax,%r15 + adcx %rax,%r11 + adox %r15,%r12 + mulx 2*16($nptr),%rax,%r15 + mov %r10,-5*8($tptr) + adcx %rax,%r12 + adox %r15,%r13 + mov %r11,-4*8($tptr) + mulx 3*16($nptr),%rax,%r15 + mov $bi,%rdx + lea 4*16($nptr),$nptr + mov %r12,-3*8($tptr) + adcx %rax,%r13 + adox $zero,%r15 + mov %r13,-2*8($tptr) + + dec $bptr # of=0, pass cf + jnz .Lmulx4x_inner + + mov 0+8(%rsp),$num # load -num + movq %xmm0,%rdx # bp[i+1] + adc $zero,%r15 # modulo-scheduled + sub 0*8($tptr),$bptr # pull top-most carry to %cf + mov 8+8(%rsp),$bptr # re-load &b[i] + mov 16+8(%rsp),%r10 + adc %r15,%r14 + lea ($aptr,$num),$aptr # rewind $aptr + adc $zero,$zero # top-most carry + mov %r14,-1*8($tptr) + + cmp %r10,$bptr + jb .Lmulx4x_outer + + mov -16($nptr),%r10 + xor %r15,%r15 + sub %r14,%r10 # compare top-most words + adc %r15,%r15 + or %r15,$zero + xor \$1,$zero + lea ($tptr,$num),%rdi # rewind $tptr + lea ($nptr,$num,2),$nptr # rewind $nptr + .byte 0x67,0x67 + sar \$3+2,$num # cf=0 + lea ($nptr,$zero,8),%rbp + mov 56+8(%rsp),%rdx # restore rp + mov $num,%rcx + jmp .Lsqrx4x_sub # common post-condition +.size mulx4x_internal,.-mulx4x_internal +___ +} { +###################################################################### +# void bn_power5( +my $rptr="%rdi"; # BN_ULONG *rptr, +my $aptr="%rsi"; # const BN_ULONG *aptr, +my $bptr="%rdx"; # const void *table, +my $nptr="%rcx"; # const BN_ULONG *nptr, +my $n0 ="%r8"; # const BN_ULONG *n0); +my $num ="%r9"; # int num, has to be divisible by 8 + # int pwr); + +my ($i,$j,$tptr)=("%rbp","%rcx",$rptr); +my @A0=("%r10","%r11"); +my @A1=("%r12","%r13"); +my ($a0,$a1,$ai)=("%r14","%r15","%rbx"); + +$code.=<<___; +.type bn_powerx5,\@function,6 +.align 32 +bn_powerx5: +.Lpowerx5_enter: + .byte 0x67 + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0x28(%rsp),%rsp + movaps %xmm6,(%rsp) + movaps %xmm7,0x10(%rsp) +___ +$code.=<<___; + .byte 0x67 + mov ${num}d,%r10d + shl \$3,${num}d # convert $num to bytes + shl \$3+2,%r10d # 4*$num + neg $num + mov ($n0),$n0 # *n0 + + ############################################################## + # ensure that stack frame doesn't alias with $aptr+4*$num + # modulo 4096, which covers ret[num], am[num] and n[2*num] + # (see bn_exp.c). this is done to allow memory disambiguation + # logic do its magic. + # + lea -64(%rsp,$num,2),%r11 + sub $aptr,%r11 + and \$4095,%r11 + cmp %r11,%r10 + jb .Lpwrx_sp_alt + sub %r11,%rsp # align with $aptr + lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num) + jmp .Lpwrx_sp_done + +.align 32 +.Lpwrx_sp_alt: + lea 4096-64(,$num,2),%r10 # 4096-frame-2*$num + lea -64(%rsp,$num,2),%rsp # alloca(frame+2*$num) + sub %r10,%r11 + mov \$0,%r10 + cmovc %r10,%r11 + sub %r11,%rsp +.Lpwrx_sp_done: + and \$-64,%rsp + mov $num,%r10 + neg $num + + ############################################################## + # Stack layout + # + # +0 saved $num, used in reduction section + # +8 &t[2*$num], used in reduction section + # +16 intermediate carry bit + # +24 top-most carry bit, used in reduction section + # +32 saved *n0 + # +40 saved %rsp + # +48 t[2*$num] + # + pxor %xmm0,%xmm0 + movq $rptr,%xmm1 # save $rptr + movq $nptr,%xmm2 # save $nptr + movq %r10, %xmm3 # -$num + movq $bptr,%xmm4 + mov $n0, 32(%rsp) + mov %rax, 40(%rsp) # save original %rsp +.Lpowerx5_body: + + call __bn_sqrx8x_internal + call __bn_sqrx8x_internal + call __bn_sqrx8x_internal + call __bn_sqrx8x_internal + call __bn_sqrx8x_internal + + mov %r10,$num # -num + mov $aptr,$rptr + movq %xmm2,$nptr + movq %xmm4,$bptr + mov 40(%rsp),%rax + + call mulx4x_internal + + mov 40(%rsp),%rsi # restore %rsp + mov \$1,%rax +___ +$code.=<<___ if ($win64); + movaps -88(%rsi),%xmm6 + movaps -72(%rsi),%xmm7 +___ +$code.=<<___; + mov -48(%rsi),%r15 + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lpowerx5_epilogue: + ret +.size bn_powerx5,.-bn_powerx5 + +.globl bn_sqrx8x_internal +.hidden bn_sqrx8x_internal +.type bn_sqrx8x_internal,\@abi-omnipotent +.align 32 +bn_sqrx8x_internal: +__bn_sqrx8x_internal: + ################################################################## + # Squaring part: + # + # a) multiply-n-add everything but a[i]*a[i]; + # b) shift result of a) by 1 to the left and accumulate + # a[i]*a[i] products; + # + ################################################################## + # a[7]a[7]a[6]a[6]a[5]a[5]a[4]a[4]a[3]a[3]a[2]a[2]a[1]a[1]a[0]a[0] + # a[1]a[0] + # a[2]a[0] + # a[3]a[0] + # a[2]a[1] + # a[3]a[1] + # a[3]a[2] + # + # a[4]a[0] + # a[5]a[0] + # a[6]a[0] + # a[7]a[0] + # a[4]a[1] + # a[5]a[1] + # a[6]a[1] + # a[7]a[1] + # a[4]a[2] + # a[5]a[2] + # a[6]a[2] + # a[7]a[2] + # a[4]a[3] + # a[5]a[3] + # a[6]a[3] + # a[7]a[3] + # + # a[5]a[4] + # a[6]a[4] + # a[7]a[4] + # a[6]a[5] + # a[7]a[5] + # a[7]a[6] + # a[7]a[7]a[6]a[6]a[5]a[5]a[4]a[4]a[3]a[3]a[2]a[2]a[1]a[1]a[0]a[0] +___ +{ +my ($zero,$carry)=("%rbp","%rcx"); +my $aaptr=$zero; +$code.=<<___; + lea 48+8(%rsp),$tptr + lea ($aptr,$num),$aaptr + mov $num,0+8(%rsp) # save $num + mov $aaptr,8+8(%rsp) # save end of $aptr + jmp .Lsqr8x_zero_start + +.align 32 +.byte 0x66,0x66,0x66,0x2e,0x0f,0x1f,0x84,0x00,0x00,0x00,0x00,0x00 +.Lsqrx8x_zero: + .byte 0x3e + movdqa %xmm0,0*8($tptr) + movdqa %xmm0,2*8($tptr) + movdqa %xmm0,4*8($tptr) + movdqa %xmm0,6*8($tptr) +.Lsqr8x_zero_start: # aligned at 32 + movdqa %xmm0,8*8($tptr) + movdqa %xmm0,10*8($tptr) + movdqa %xmm0,12*8($tptr) + movdqa %xmm0,14*8($tptr) + lea 16*8($tptr),$tptr + sub \$64,$num + jnz .Lsqrx8x_zero + + mov 0*8($aptr),%rdx # a[0], modulo-scheduled + #xor %r9,%r9 # t[1], ex-$num, zero already + xor %r10,%r10 + xor %r11,%r11 + xor %r12,%r12 + xor %r13,%r13 + xor %r14,%r14 + xor %r15,%r15 + lea 48+8(%rsp),$tptr + xor $zero,$zero # cf=0, cf=0 + jmp .Lsqrx8x_outer_loop + +.align 32 +.Lsqrx8x_outer_loop: + mulx 1*8($aptr),%r8,%rax # a[1]*a[0] + adcx %r9,%r8 # a[1]*a[0]+=t[1] + adox %rax,%r10 + mulx 2*8($aptr),%r9,%rax # a[2]*a[0] + adcx %r10,%r9 + adox %rax,%r11 + .byte 0xc4,0xe2,0xab,0xf6,0x86,0x18,0x00,0x00,0x00 # mulx 3*8($aptr),%r10,%rax # ... + adcx %r11,%r10 + adox %rax,%r12 + .byte 0xc4,0xe2,0xa3,0xf6,0x86,0x20,0x00,0x00,0x00 # mulx 4*8($aptr),%r11,%rax + adcx %r12,%r11 + adox %rax,%r13 + mulx 5*8($aptr),%r12,%rax + adcx %r13,%r12 + adox %rax,%r14 + mulx 6*8($aptr),%r13,%rax + adcx %r14,%r13 + adox %r15,%rax + mulx 7*8($aptr),%r14,%r15 + mov 1*8($aptr),%rdx # a[1] + adcx %rax,%r14 + adox $zero,%r15 + adc 8*8($tptr),%r15 + mov %r8,1*8($tptr) # t[1] + mov %r9,2*8($tptr) # t[2] + sbb $carry,$carry # mov %cf,$carry + xor $zero,$zero # cf=0, of=0 + + + mulx 2*8($aptr),%r8,%rbx # a[2]*a[1] + mulx 3*8($aptr),%r9,%rax # a[3]*a[1] + adcx %r10,%r8 + adox %rbx,%r9 + mulx 4*8($aptr),%r10,%rbx # ... + adcx %r11,%r9 + adox %rax,%r10 + .byte 0xc4,0xe2,0xa3,0xf6,0x86,0x28,0x00,0x00,0x00 # mulx 5*8($aptr),%r11,%rax + adcx %r12,%r10 + adox %rbx,%r11 + .byte 0xc4,0xe2,0x9b,0xf6,0x9e,0x30,0x00,0x00,0x00 # mulx 6*8($aptr),%r12,%rbx + adcx %r13,%r11 + adox %r14,%r12 + .byte 0xc4,0x62,0x93,0xf6,0xb6,0x38,0x00,0x00,0x00 # mulx 7*8($aptr),%r13,%r14 + mov 2*8($aptr),%rdx # a[2] + adcx %rax,%r12 + adox %rbx,%r13 + adcx %r15,%r13 + adox $zero,%r14 # of=0 + adcx $zero,%r14 # cf=0 + + mov %r8,3*8($tptr) # t[3] + mov %r9,4*8($tptr) # t[4] + + mulx 3*8($aptr),%r8,%rbx # a[3]*a[2] + mulx 4*8($aptr),%r9,%rax # a[4]*a[2] + adcx %r10,%r8 + adox %rbx,%r9 + mulx 5*8($aptr),%r10,%rbx # ... + adcx %r11,%r9 + adox %rax,%r10 + .byte 0xc4,0xe2,0xa3,0xf6,0x86,0x30,0x00,0x00,0x00 # mulx 6*8($aptr),%r11,%rax + adcx %r12,%r10 + adox %r13,%r11 + .byte 0xc4,0x62,0x9b,0xf6,0xae,0x38,0x00,0x00,0x00 # mulx 7*8($aptr),%r12,%r13 + .byte 0x3e + mov 3*8($aptr),%rdx # a[3] + adcx %rbx,%r11 + adox %rax,%r12 + adcx %r14,%r12 + mov %r8,5*8($tptr) # t[5] + mov %r9,6*8($tptr) # t[6] + mulx 4*8($aptr),%r8,%rax # a[4]*a[3] + adox $zero,%r13 # of=0 + adcx $zero,%r13 # cf=0 + + mulx 5*8($aptr),%r9,%rbx # a[5]*a[3] + adcx %r10,%r8 + adox %rax,%r9 + mulx 6*8($aptr),%r10,%rax # ... + adcx %r11,%r9 + adox %r12,%r10 + mulx 7*8($aptr),%r11,%r12 + mov 4*8($aptr),%rdx # a[4] + mov 5*8($aptr),%r14 # a[5] + adcx %rbx,%r10 + adox %rax,%r11 + mov 6*8($aptr),%r15 # a[6] + adcx %r13,%r11 + adox $zero,%r12 # of=0 + adcx $zero,%r12 # cf=0 + + mov %r8,7*8($tptr) # t[7] + mov %r9,8*8($tptr) # t[8] + + mulx %r14,%r9,%rax # a[5]*a[4] + mov 7*8($aptr),%r8 # a[7] + adcx %r10,%r9 + mulx %r15,%r10,%rbx # a[6]*a[4] + adox %rax,%r10 + adcx %r11,%r10 + mulx %r8,%r11,%rax # a[7]*a[4] + mov %r14,%rdx # a[5] + adox %rbx,%r11 + adcx %r12,%r11 + #adox $zero,%rax # of=0 + adcx $zero,%rax # cf=0 + + mulx %r15,%r14,%rbx # a[6]*a[5] + mulx %r8,%r12,%r13 # a[7]*a[5] + mov %r15,%rdx # a[6] + lea 8*8($aptr),$aptr + adcx %r14,%r11 + adox %rbx,%r12 + adcx %rax,%r12 + adox $zero,%r13 + + .byte 0x67,0x67 + mulx %r8,%r8,%r14 # a[7]*a[6] + adcx %r8,%r13 + adcx $zero,%r14 + + cmp 8+8(%rsp),$aptr + je .Lsqrx8x_outer_break + + neg $carry # mov $carry,%cf + mov \$-8,%rcx + mov $zero,%r15 + mov 8*8($tptr),%r8 + adcx 9*8($tptr),%r9 # +=t[9] + adcx 10*8($tptr),%r10 # ... + adcx 11*8($tptr),%r11 + adc 12*8($tptr),%r12 + adc 13*8($tptr),%r13 + adc 14*8($tptr),%r14 + adc 15*8($tptr),%r15 + lea ($aptr),$aaptr + lea 2*64($tptr),$tptr + sbb %rax,%rax # mov %cf,$carry + + mov -64($aptr),%rdx # a[0] + mov %rax,16+8(%rsp) # offload $carry + mov $tptr,24+8(%rsp) + + #lea 8*8($tptr),$tptr # see 2*8*8($tptr) above + xor %eax,%eax # cf=0, of=0 + jmp .Lsqrx8x_loop + +.align 32 +.Lsqrx8x_loop: + mov %r8,%rbx + mulx 0*8($aaptr),%rax,%r8 # a[8]*a[i] + adcx %rax,%rbx # +=t[8] + adox %r9,%r8 + + mulx 1*8($aaptr),%rax,%r9 # ... + adcx %rax,%r8 + adox %r10,%r9 + + mulx 2*8($aaptr),%rax,%r10 + adcx %rax,%r9 + adox %r11,%r10 + + mulx 3*8($aaptr),%rax,%r11 + adcx %rax,%r10 + adox %r12,%r11 + + .byte 0xc4,0x62,0xfb,0xf6,0xa5,0x20,0x00,0x00,0x00 # mulx 4*8($aaptr),%rax,%r12 + adcx %rax,%r11 + adox %r13,%r12 + + mulx 5*8($aaptr),%rax,%r13 + adcx %rax,%r12 + adox %r14,%r13 + + mulx 6*8($aaptr),%rax,%r14 + mov %rbx,($tptr,%rcx,8) # store t[8+i] + mov \$0,%ebx + adcx %rax,%r13 + adox %r15,%r14 + + .byte 0xc4,0x62,0xfb,0xf6,0xbd,0x38,0x00,0x00,0x00 # mulx 7*8($aaptr),%rax,%r15 + mov 8($aptr,%rcx,8),%rdx # a[i] + adcx %rax,%r14 + adox %rbx,%r15 # %rbx is 0, of=0 + adcx %rbx,%r15 # cf=0 + + .byte 0x67 + inc %rcx # of=0 + jnz .Lsqrx8x_loop + + lea 8*8($aaptr),$aaptr + mov \$-8,%rcx + cmp 8+8(%rsp),$aaptr # done? + je .Lsqrx8x_break + + sub 16+8(%rsp),%rbx # mov 16(%rsp),%cf + .byte 0x66 + mov -64($aptr),%rdx + adcx 0*8($tptr),%r8 + adcx 1*8($tptr),%r9 + adc 2*8($tptr),%r10 + adc 3*8($tptr),%r11 + adc 4*8($tptr),%r12 + adc 5*8($tptr),%r13 + adc 6*8($tptr),%r14 + adc 7*8($tptr),%r15 + lea 8*8($tptr),$tptr + .byte 0x67 + sbb %rax,%rax # mov %cf,%rax + xor %ebx,%ebx # cf=0, of=0 + mov %rax,16+8(%rsp) # offload carry + jmp .Lsqrx8x_loop + +.align 32 +.Lsqrx8x_break: + sub 16+8(%rsp),%r8 # consume last carry + mov 24+8(%rsp),$carry # initial $tptr, borrow $carry + mov 0*8($aptr),%rdx # a[8], modulo-scheduled + xor %ebp,%ebp # xor $zero,$zero + mov %r8,0*8($tptr) + cmp $carry,$tptr # cf=0, of=0 + je .Lsqrx8x_outer_loop + + mov %r9,1*8($tptr) + mov 1*8($carry),%r9 + mov %r10,2*8($tptr) + mov 2*8($carry),%r10 + mov %r11,3*8($tptr) + mov 3*8($carry),%r11 + mov %r12,4*8($tptr) + mov 4*8($carry),%r12 + mov %r13,5*8($tptr) + mov 5*8($carry),%r13 + mov %r14,6*8($tptr) + mov 6*8($carry),%r14 + mov %r15,7*8($tptr) + mov 7*8($carry),%r15 + mov $carry,$tptr + jmp .Lsqrx8x_outer_loop + +.align 32 +.Lsqrx8x_outer_break: + mov %r9,9*8($tptr) # t[9] + movq %xmm3,%rcx # -$num + mov %r10,10*8($tptr) # ... + mov %r11,11*8($tptr) + mov %r12,12*8($tptr) + mov %r13,13*8($tptr) + mov %r14,14*8($tptr) +___ +} { +my $i="%rcx"; +$code.=<<___; + lea 48+8(%rsp),$tptr + mov ($aptr,$i),%rdx # a[0] + + mov 8($tptr),$A0[1] # t[1] + xor $A0[0],$A0[0] # t[0], of=0, cf=0 + mov 0+8(%rsp),$num # restore $num + adox $A0[1],$A0[1] + mov 16($tptr),$A1[0] # t[2] # prefetch + mov 24($tptr),$A1[1] # t[3] # prefetch + #jmp .Lsqrx4x_shift_n_add # happens to be aligned + +.align 32 +.Lsqrx4x_shift_n_add: + mulx %rdx,%rax,%rbx + adox $A1[0],$A1[0] + adcx $A0[0],%rax + .byte 0x48,0x8b,0x94,0x0e,0x08,0x00,0x00,0x00 # mov 8($aptr,$i),%rdx # a[i+1] # prefetch + .byte 0x4c,0x8b,0x97,0x20,0x00,0x00,0x00 # mov 32($tptr),$A0[0] # t[2*i+4] # prefetch + adox $A1[1],$A1[1] + adcx $A0[1],%rbx + mov 40($tptr),$A0[1] # t[2*i+4+1] # prefetch + mov %rax,0($tptr) + mov %rbx,8($tptr) + + mulx %rdx,%rax,%rbx + adox $A0[0],$A0[0] + adcx $A1[0],%rax + mov 16($aptr,$i),%rdx # a[i+2] # prefetch + mov 48($tptr),$A1[0] # t[2*i+6] # prefetch + adox $A0[1],$A0[1] + adcx $A1[1],%rbx + mov 56($tptr),$A1[1] # t[2*i+6+1] # prefetch + mov %rax,16($tptr) + mov %rbx,24($tptr) + + mulx %rdx,%rax,%rbx + adox $A1[0],$A1[0] + adcx $A0[0],%rax + mov 24($aptr,$i),%rdx # a[i+3] # prefetch + lea 32($i),$i + mov 64($tptr),$A0[0] # t[2*i+8] # prefetch + adox $A1[1],$A1[1] + adcx $A0[1],%rbx + mov 72($tptr),$A0[1] # t[2*i+8+1] # prefetch + mov %rax,32($tptr) + mov %rbx,40($tptr) + + mulx %rdx,%rax,%rbx + adox $A0[0],$A0[0] + adcx $A1[0],%rax + jrcxz .Lsqrx4x_shift_n_add_break + .byte 0x48,0x8b,0x94,0x0e,0x00,0x00,0x00,0x00 # mov 0($aptr,$i),%rdx # a[i+4] # prefetch + adox $A0[1],$A0[1] + adcx $A1[1],%rbx + mov 80($tptr),$A1[0] # t[2*i+10] # prefetch + mov 88($tptr),$A1[1] # t[2*i+10+1] # prefetch + mov %rax,48($tptr) + mov %rbx,56($tptr) + lea 64($tptr),$tptr + nop + jmp .Lsqrx4x_shift_n_add + +.align 32 +.Lsqrx4x_shift_n_add_break: + adcx $A1[1],%rbx + mov %rax,48($tptr) + mov %rbx,56($tptr) + lea 64($tptr),$tptr # end of t[] buffer +___ +} +###################################################################### +# Montgomery reduction part, "word-by-word" algorithm. +# +# This new path is inspired by multiple submissions from Intel, by +# Shay Gueron, Vlad Krasnov, Erdinc Ozturk, James Guilford, +# Vinodh Gopal... +{ +my ($nptr,$carry,$m0)=("%rbp","%rsi","%rdx"); + +$code.=<<___; + movq %xmm2,$nptr +sqrx8x_reduction: + xor %eax,%eax # initial top-most carry bit + mov 32+8(%rsp),%rbx # n0 + mov 48+8(%rsp),%rdx # "%r8", 8*0($tptr) + lea -128($nptr,$num,2),%rcx # end of n[] + #lea 48+8(%rsp,$num,2),$tptr # end of t[] buffer + mov %rcx, 0+8(%rsp) # save end of n[] + mov $tptr,8+8(%rsp) # save end of t[] + + lea 48+8(%rsp),$tptr # initial t[] window + jmp .Lsqrx8x_reduction_loop + +.align 32 +.Lsqrx8x_reduction_loop: + mov 8*1($tptr),%r9 + mov 8*2($tptr),%r10 + mov 8*3($tptr),%r11 + mov 8*4($tptr),%r12 + mov %rdx,%r8 + imulq %rbx,%rdx # n0*a[i] + mov 8*5($tptr),%r13 + mov 8*6($tptr),%r14 + mov 8*7($tptr),%r15 + mov %rax,24+8(%rsp) # store top-most carry bit + + lea 8*8($tptr),$tptr + xor $carry,$carry # cf=0,of=0 + mov \$-8,%rcx + jmp .Lsqrx8x_reduce + +.align 32 +.Lsqrx8x_reduce: + mov %r8, %rbx + mulx 16*0($nptr),%rax,%r8 # n[0] + adcx %rbx,%rax # discarded + adox %r9,%r8 + + mulx 16*1($nptr),%rbx,%r9 # n[1] + adcx %rbx,%r8 + adox %r10,%r9 + + mulx 16*2($nptr),%rbx,%r10 + adcx %rbx,%r9 + adox %r11,%r10 + + mulx 16*3($nptr),%rbx,%r11 + adcx %rbx,%r10 + adox %r12,%r11 + + .byte 0xc4,0x62,0xe3,0xf6,0xa5,0x40,0x00,0x00,0x00 # mulx 16*4($nptr),%rbx,%r12 + mov %rdx,%rax + mov %r8,%rdx + adcx %rbx,%r11 + adox %r13,%r12 + + mulx 32+8(%rsp),%rbx,%rdx # %rdx discarded + mov %rax,%rdx + mov %rax,64+48+8(%rsp,%rcx,8) # put aside n0*a[i] + + mulx 16*5($nptr),%rax,%r13 + adcx %rax,%r12 + adox %r14,%r13 + + mulx 16*6($nptr),%rax,%r14 + adcx %rax,%r13 + adox %r15,%r14 + + mulx 16*7($nptr),%rax,%r15 + mov %rbx,%rdx + adcx %rax,%r14 + adox $carry,%r15 # $carry is 0 + adcx $carry,%r15 # cf=0 + + .byte 0x67,0x67,0x67 + inc %rcx # of=0 + jnz .Lsqrx8x_reduce + + mov $carry,%rax # xor %rax,%rax + cmp 0+8(%rsp),$nptr # end of n[]? + jae .Lsqrx8x_no_tail + + mov 48+8(%rsp),%rdx # pull n0*a[0] + add 8*0($tptr),%r8 + lea 16*8($nptr),$nptr + mov \$-8,%rcx + adcx 8*1($tptr),%r9 + adcx 8*2($tptr),%r10 + adc 8*3($tptr),%r11 + adc 8*4($tptr),%r12 + adc 8*5($tptr),%r13 + adc 8*6($tptr),%r14 + adc 8*7($tptr),%r15 + lea 8*8($tptr),$tptr + sbb %rax,%rax # top carry + + xor $carry,$carry # of=0, cf=0 + mov %rax,16+8(%rsp) + jmp .Lsqrx8x_tail + +.align 32 +.Lsqrx8x_tail: + mov %r8,%rbx + mulx 16*0($nptr),%rax,%r8 + adcx %rax,%rbx + adox %r9,%r8 + + mulx 16*1($nptr),%rax,%r9 + adcx %rax,%r8 + adox %r10,%r9 + + mulx 16*2($nptr),%rax,%r10 + adcx %rax,%r9 + adox %r11,%r10 + + mulx 16*3($nptr),%rax,%r11 + adcx %rax,%r10 + adox %r12,%r11 + + .byte 0xc4,0x62,0xfb,0xf6,0xa5,0x40,0x00,0x00,0x00 # mulx 16*4($nptr),%rax,%r12 + adcx %rax,%r11 + adox %r13,%r12 + + mulx 16*5($nptr),%rax,%r13 + adcx %rax,%r12 + adox %r14,%r13 + + mulx 16*6($nptr),%rax,%r14 + adcx %rax,%r13 + adox %r15,%r14 + + mulx 16*7($nptr),%rax,%r15 + mov 72+48+8(%rsp,%rcx,8),%rdx # pull n0*a[i] + adcx %rax,%r14 + adox $carry,%r15 + mov %rbx,($tptr,%rcx,8) # save result + mov %r8,%rbx + adcx $carry,%r15 # cf=0 + + inc %rcx # of=0 + jnz .Lsqrx8x_tail + + cmp 0+8(%rsp),$nptr # end of n[]? + jae .Lsqrx8x_tail_done # break out of loop + + sub 16+8(%rsp),$carry # mov 16(%rsp),%cf + mov 48+8(%rsp),%rdx # pull n0*a[0] + lea 16*8($nptr),$nptr + adc 8*0($tptr),%r8 + adc 8*1($tptr),%r9 + adc 8*2($tptr),%r10 + adc 8*3($tptr),%r11 + adc 8*4($tptr),%r12 + adc 8*5($tptr),%r13 + adc 8*6($tptr),%r14 + adc 8*7($tptr),%r15 + lea 8*8($tptr),$tptr + sbb %rax,%rax + sub \$8,%rcx # mov \$-8,%rcx + + xor $carry,$carry # of=0, cf=0 + mov %rax,16+8(%rsp) + jmp .Lsqrx8x_tail + +.align 32 +.Lsqrx8x_tail_done: + add 24+8(%rsp),%r8 # can this overflow? + mov $carry,%rax # xor %rax,%rax + + sub 16+8(%rsp),$carry # mov 16(%rsp),%cf +.Lsqrx8x_no_tail: # %cf is 0 if jumped here + adc 8*0($tptr),%r8 + movq %xmm3,%rcx + adc 8*1($tptr),%r9 + mov 16*7($nptr),$carry + movq %xmm2,$nptr # restore $nptr + adc 8*2($tptr),%r10 + adc 8*3($tptr),%r11 + adc 8*4($tptr),%r12 + adc 8*5($tptr),%r13 + adc 8*6($tptr),%r14 + adc 8*7($tptr),%r15 + adc %rax,%rax # top-most carry + + mov 32+8(%rsp),%rbx # n0 + mov 8*8($tptr,%rcx),%rdx # modulo-scheduled "%r8" + + mov %r8,8*0($tptr) # store top 512 bits + lea 8*8($tptr),%r8 # borrow %r8 + mov %r9,8*1($tptr) + mov %r10,8*2($tptr) + mov %r11,8*3($tptr) + mov %r12,8*4($tptr) + mov %r13,8*5($tptr) + mov %r14,8*6($tptr) + mov %r15,8*7($tptr) + + lea 8*8($tptr,%rcx),$tptr # start of current t[] window + cmp 8+8(%rsp),%r8 # end of t[]? + jb .Lsqrx8x_reduction_loop +___ +} +############################################################## +# Post-condition, 4x unrolled +# +{ +my ($rptr,$nptr)=("%rdx","%rbp"); +my @ri=map("%r$_",(10..13)); +my @ni=map("%r$_",(14..15)); +$code.=<<___; + xor %rbx,%rbx + sub %r15,%rsi # compare top-most words + adc %rbx,%rbx + mov %rcx,%r10 # -$num + .byte 0x67 + or %rbx,%rax + .byte 0x67 + mov %rcx,%r9 # -$num + xor \$1,%rax + sar \$3+2,%rcx # cf=0 + #lea 48+8(%rsp,%r9),$tptr + lea ($nptr,%rax,8),$nptr + movq %xmm1,$rptr # restore $rptr + movq %xmm1,$aptr # prepare for back-to-back call + jmp .Lsqrx4x_sub + +.align 32 +.Lsqrx4x_sub: + .byte 0x66 + mov 8*0($tptr),%r12 + mov 8*1($tptr),%r13 + sbb 16*0($nptr),%r12 + mov 8*2($tptr),%r14 + sbb 16*1($nptr),%r13 + mov 8*3($tptr),%r15 + lea 8*4($tptr),$tptr + sbb 16*2($nptr),%r14 + mov %r12,8*0($rptr) + sbb 16*3($nptr),%r15 + lea 16*4($nptr),$nptr + mov %r13,8*1($rptr) + mov %r14,8*2($rptr) + mov %r15,8*3($rptr) + lea 8*4($rptr),$rptr + + inc %rcx + jnz .Lsqrx4x_sub +___ +} +$code.=<<___; + neg %r9 # restore $num + + ret +.size bn_sqrx8x_internal,.-bn_sqrx8x_internal +___ +}}} +{ +my ($inp,$num,$tbl,$idx)=$win64?("%rcx","%edx","%r8", "%r9d") : # Win64 order + ("%rdi","%esi","%rdx","%ecx"); # Unix order +my $out=$inp; +my $STRIDE=2**5*8; +my $N=$STRIDE/4; + +$code.=<<___; +.globl bn_scatter5 +.type bn_scatter5,\@abi-omnipotent +.align 16 +bn_scatter5: + cmp \$0, $num + jz .Lscatter_epilogue + lea ($tbl,$idx,8),$tbl +.Lscatter: + mov ($inp),%rax + lea 8($inp),$inp + mov %rax,($tbl) + lea 32*8($tbl),$tbl + sub \$1,$num + jnz .Lscatter +.Lscatter_epilogue: + ret +.size bn_scatter5,.-bn_scatter5 + +.globl bn_gather5 +.type bn_gather5,\@abi-omnipotent +.align 16 +bn_gather5: +___ +$code.=<<___ if ($win64); +.LSEH_begin_bn_gather5: + # I can't trust assembler to use specific encoding:-( + .byte 0x48,0x83,0xec,0x28 #sub \$0x28,%rsp + .byte 0x0f,0x29,0x34,0x24 #movaps %xmm6,(%rsp) + .byte 0x0f,0x29,0x7c,0x24,0x10 #movdqa %xmm7,0x10(%rsp) +___ +$code.=<<___; + mov $idx,%r11d + shr \$`log($N/8)/log(2)`,$idx + and \$`$N/8-1`,%r11 + not $idx + lea .Lmagic_masks(%rip),%rax + and \$`2**5/($N/8)-1`,$idx # 5 is "window size" + lea 128($tbl,%r11,8),$tbl # pointer within 1st cache line + movq 0(%rax,$idx,8),%xmm4 # set of masks denoting which + movq 8(%rax,$idx,8),%xmm5 # cache line contains element + movq 16(%rax,$idx,8),%xmm6 # denoted by 7th argument + movq 24(%rax,$idx,8),%xmm7 + jmp .Lgather +.align 16 +.Lgather: + movq `0*$STRIDE/4-128`($tbl),%xmm0 + movq `1*$STRIDE/4-128`($tbl),%xmm1 + pand %xmm4,%xmm0 + movq `2*$STRIDE/4-128`($tbl),%xmm2 + pand %xmm5,%xmm1 + movq `3*$STRIDE/4-128`($tbl),%xmm3 + pand %xmm6,%xmm2 + por %xmm1,%xmm0 + pand %xmm7,%xmm3 + .byte 0x67,0x67 + por %xmm2,%xmm0 + lea $STRIDE($tbl),$tbl + por %xmm3,%xmm0 + + movq %xmm0,($out) # m0=bp[0] + lea 8($out),$out + sub \$1,$num + jnz .Lgather +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + movaps 0x10(%rsp),%xmm7 + lea 0x28(%rsp),%rsp +___ +$code.=<<___; + ret +.LSEH_end_bn_gather5: +.size bn_gather5,.-bn_gather5 +___ +} +$code.=<<___; +.align 64 +.Lmagic_masks: + .long 0,0, 0,0, 0,0, -1,-1 + .long 0,0, 0,0, 0,0, 0,0 +.asciz "Montgomery Multiplication with scatter/gather for x86_64, CRYPTOGAMS by " +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type mul_handler,\@abi-omnipotent +.align 16 +mul_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # end of prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + lea .Lmul_epilogue(%rip),%r10 + cmp %r10,%rbx + jb .Lbody_40 + + mov 192($context),%r10 # pull $num + mov 8(%rax,%r10,8),%rax # pull saved stack pointer + jmp .Lbody_proceed + +.Lbody_40: + mov 40(%rax),%rax # pull saved stack pointer +.Lbody_proceed: + + movaps -88(%rax),%xmm0 + movaps -72(%rax),%xmm1 + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov -48(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + movups %xmm0,512($context) # restore context->Xmm6 + movups %xmm1,528($context) # restore context->Xmm7 + +.Lcommon_seh_tail: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size mul_handler,.-mul_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_bn_mul_mont_gather5 + .rva .LSEH_end_bn_mul_mont_gather5 + .rva .LSEH_info_bn_mul_mont_gather5 + + .rva .LSEH_begin_bn_mul4x_mont_gather5 + .rva .LSEH_end_bn_mul4x_mont_gather5 + .rva .LSEH_info_bn_mul4x_mont_gather5 + + .rva .LSEH_begin_bn_power5 + .rva .LSEH_end_bn_power5 + .rva .LSEH_info_bn_power5 + + .rva .LSEH_begin_bn_from_mont8x + .rva .LSEH_end_bn_from_mont8x + .rva .LSEH_info_bn_from_mont8x +___ +$code.=<<___ if ($addx); + .rva .LSEH_begin_bn_mulx4x_mont_gather5 + .rva .LSEH_end_bn_mulx4x_mont_gather5 + .rva .LSEH_info_bn_mulx4x_mont_gather5 + + .rva .LSEH_begin_bn_powerx5 + .rva .LSEH_end_bn_powerx5 + .rva .LSEH_info_bn_powerx5 +___ +$code.=<<___; + .rva .LSEH_begin_bn_gather5 + .rva .LSEH_end_bn_gather5 + .rva .LSEH_info_bn_gather5 + +.section .xdata +.align 8 +.LSEH_info_bn_mul_mont_gather5: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lmul_body,.Lmul_epilogue # HandlerData[] +.align 8 +.LSEH_info_bn_mul4x_mont_gather5: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lmul4x_body,.Lmul4x_epilogue # HandlerData[] +.align 8 +.LSEH_info_bn_power5: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lpower5_body,.Lpower5_epilogue # HandlerData[] +.align 8 +.LSEH_info_bn_from_mont8x: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lfrom_body,.Lfrom_epilogue # HandlerData[] +___ +$code.=<<___ if ($addx); +.align 8 +.LSEH_info_bn_mulx4x_mont_gather5: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lmulx4x_body,.Lmulx4x_epilogue # HandlerData[] +.align 8 +.LSEH_info_bn_powerx5: + .byte 9,0,0,0 + .rva mul_handler + .rva .Lpowerx5_body,.Lpowerx5_epilogue # HandlerData[] +___ +$code.=<<___; +.align 8 +.LSEH_info_bn_gather5: + .byte 0x01,0x0d,0x05,0x00 + .byte 0x0d,0x78,0x01,0x00 #movaps 0x10(rsp),xmm7 + .byte 0x08,0x68,0x00,0x00 #movaps (rsp),xmm6 + .byte 0x04,0x42,0x00,0x00 #sub rsp,0x28 +.align 8 +___ +} + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +print $code; +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/bn/bn.c b/TMessagesProj/jni/boringssl/crypto/bn/bn.c new file mode 100644 index 00000000..ad8190b1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/bn.c @@ -0,0 +1,338 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include + +#include "internal.h" + + +BIGNUM *BN_new(void) { + BIGNUM *bn = OPENSSL_malloc(sizeof(BIGNUM)); + + if (bn == NULL) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(bn, 0, sizeof(BIGNUM)); + bn->flags = BN_FLG_MALLOCED; + + return bn; +} + +void BN_init(BIGNUM *bn) { + memset(bn, 0, sizeof(BIGNUM)); +} + +void BN_free(BIGNUM *bn) { + if (bn == NULL) { + return; + } + + if ((bn->flags & BN_FLG_STATIC_DATA) == 0) { + OPENSSL_free(bn->d); + } + + if (bn->flags & BN_FLG_MALLOCED) { + OPENSSL_free(bn); + } else { + bn->d = NULL; + } +} + +void BN_clear_free(BIGNUM *bn) { + char should_free; + + if (bn == NULL) { + return; + } + + if (bn->d != NULL) { + OPENSSL_cleanse(bn->d, bn->dmax * sizeof(bn->d[0])); + if ((bn->flags & BN_FLG_STATIC_DATA) == 0) { + OPENSSL_free(bn->d); + } + } + + should_free = (bn->flags & BN_FLG_MALLOCED) != 0; + OPENSSL_cleanse(bn, sizeof(BIGNUM)); + if (should_free) { + OPENSSL_free(bn); + } +} + +BIGNUM *BN_dup(const BIGNUM *src) { + BIGNUM *copy; + + if (src == NULL) { + return NULL; + } + + copy = BN_new(); + if (copy == NULL) { + return NULL; + } + + if (!BN_copy(copy, src)) { + BN_free(copy); + return NULL; + } + + return copy; +} + +BIGNUM *BN_copy(BIGNUM *dest, const BIGNUM *src) { + if (src == dest) { + return dest; + } + + if (bn_wexpand(dest, src->top) == NULL) { + return NULL; + } + + memcpy(dest->d, src->d, sizeof(src->d[0]) * src->top); + + dest->top = src->top; + dest->neg = src->neg; + return dest; +} + +void BN_clear(BIGNUM *bn) { + if (bn->d != NULL) { + memset(bn->d, 0, bn->dmax * sizeof(bn->d[0])); + } + + bn->top = 0; + bn->neg = 0; +} + +const BIGNUM *BN_value_one(void) { + static const BN_ULONG data_one = 1; + static const BIGNUM const_one = {(BN_ULONG *)&data_one, 1, 1, 0, + BN_FLG_STATIC_DATA}; + + return &const_one; +} + +void BN_with_flags(BIGNUM *out, const BIGNUM *in, int flags) { + memcpy(out, in, sizeof(BIGNUM)); + out->flags &= ~BN_FLG_MALLOCED; + out->flags |= BN_FLG_STATIC_DATA | flags; +} + +/* BN_num_bits_word returns the minimum number of bits needed to represent the + * value in |l|. */ +unsigned BN_num_bits_word(BN_ULONG l) { + static const unsigned char bits[256] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}; + +#if defined(OPENSSL_64_BIT) + if (l & 0xffffffff00000000L) { + if (l & 0xffff000000000000L) { + if (l & 0xff00000000000000L) { + return (bits[(int)(l >> 56)] + 56); + } else { + return (bits[(int)(l >> 48)] + 48); + } + } else { + if (l & 0x0000ff0000000000L) { + return (bits[(int)(l >> 40)] + 40); + } else { + return (bits[(int)(l >> 32)] + 32); + } + } + } else +#endif + { + if (l & 0xffff0000L) { + if (l & 0xff000000L) { + return (bits[(int)(l >> 24L)] + 24); + } else { + return (bits[(int)(l >> 16L)] + 16); + } + } else { + if (l & 0xff00L) { + return (bits[(int)(l >> 8)] + 8); + } else { + return (bits[(int)(l)]); + } + } + } +} + +unsigned BN_num_bits(const BIGNUM *bn) { + const int max = bn->top - 1; + + if (BN_is_zero(bn)) { + return 0; + } + + return max*BN_BITS2 + BN_num_bits_word(bn->d[max]); +} + +unsigned BN_num_bytes(const BIGNUM *bn) { + return (BN_num_bits(bn) + 7) / 8; +} + +void BN_zero(BIGNUM *bn) { + bn->top = bn->neg = 0; +} + +int BN_one(BIGNUM *bn) { + return BN_set_word(bn, 1); +} + +int BN_set_word(BIGNUM *bn, BN_ULONG value) { + if (value == 0) { + BN_zero(bn); + return 1; + } + + if (bn_wexpand(bn, 1) == NULL) { + return 0; + } + + bn->neg = 0; + bn->d[0] = value; + bn->top = 1; + return 1; +} + +int BN_is_negative(const BIGNUM *bn) { + return bn->neg != 0; +} + +void BN_set_negative(BIGNUM *bn, int sign) { + if (sign && !BN_is_zero(bn)) { + bn->neg = 1; + } else { + bn->neg = 0; + } +} + +BIGNUM *bn_wexpand(BIGNUM *bn, unsigned words) { + BN_ULONG *a; + + if (words <= (unsigned) bn->dmax) { + return bn; + } + + if (words > (INT_MAX / (4 * BN_BITS2))) { + OPENSSL_PUT_ERROR(BN, BN_R_BIGNUM_TOO_LONG); + return NULL; + } + + if (bn->flags & BN_FLG_STATIC_DATA) { + OPENSSL_PUT_ERROR(BN, BN_R_EXPAND_ON_STATIC_BIGNUM_DATA); + return NULL; + } + + a = (BN_ULONG *)OPENSSL_malloc(sizeof(BN_ULONG) * words); + if (a == NULL) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memcpy(a, bn->d, sizeof(BN_ULONG) * bn->top); + + OPENSSL_free(bn->d); + bn->d = a; + bn->dmax = words; + + return bn; +} + +BIGNUM *bn_expand(BIGNUM *bn, unsigned bits) { + return bn_wexpand(bn, (bits+BN_BITS2-1)/BN_BITS2); +} + +void bn_correct_top(BIGNUM *bn) { + BN_ULONG *ftl; + int tmp_top = bn->top; + + if (tmp_top > 0) { + for (ftl = &(bn->d[tmp_top - 1]); tmp_top > 0; tmp_top--) { + if (*(ftl--)) { + break; + } + } + bn->top = tmp_top; + } +} + +int BN_get_flags(const BIGNUM *bn, int flags) { + return bn->flags & flags; +} + +void BN_set_flags(BIGNUM *bn, int flags) { + bn->flags |= flags; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/bn_asn1.c b/TMessagesProj/jni/boringssl/crypto/bn/bn_asn1.c new file mode 100644 index 00000000..5c47a061 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/bn_asn1.c @@ -0,0 +1,74 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + + +int BN_cbs2unsigned(CBS *cbs, BIGNUM *ret) { + CBS child; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_INTEGER) || + CBS_len(&child) == 0) { + OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING); + return 0; + } + if (CBS_data(&child)[0] & 0x80) { + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); + return 0; + } + /* INTEGERs must be minimal. */ + if (CBS_data(&child)[0] == 0x00 && + CBS_len(&child) > 1 && + !(CBS_data(&child)[1] & 0x80)) { + OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING); + return 0; + } + return BN_bin2bn(CBS_data(&child), CBS_len(&child), ret) != NULL; +} + +int BN_bn2cbb(CBB *cbb, const BIGNUM *bn) { + /* Negative numbers are unsupported. */ + if (BN_is_negative(bn)) { + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); + return 0; + } + + CBB child; + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER)) { + OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR); + return 0; + } + + /* The number must be padded with a leading zero if the high bit would + * otherwise be set (or |bn| is zero). */ + if (BN_num_bits(bn) % 8 == 0 && + !CBB_add_u8(&child, 0x00)) { + OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR); + return 0; + } + + uint8_t *out; + if (!CBB_add_space(&child, &out, BN_num_bytes(bn))) { + OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR); + return 0; + } + BN_bn2bin(bn, out); + if (!CBB_flush(cbb)) { + OPENSSL_PUT_ERROR(BN, BN_R_ENCODE_ERROR); + return 0; + } + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/cmp.c b/TMessagesProj/jni/boringssl/crypto/bn/cmp.c new file mode 100644 index 00000000..fce72339 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/cmp.c @@ -0,0 +1,200 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include "internal.h" + + +int BN_ucmp(const BIGNUM *a, const BIGNUM *b) { + int i; + BN_ULONG t1, t2, *ap, *bp; + + i = a->top - b->top; + if (i != 0) { + return i; + } + + ap = a->d; + bp = b->d; + for (i = a->top - 1; i >= 0; i--) { + t1 = ap[i]; + t2 = bp[i]; + if (t1 != t2) { + return (t1 > t2) ? 1 : -1; + } + } + + return 0; +} + +int BN_cmp(const BIGNUM *a, const BIGNUM *b) { + int i; + int gt, lt; + BN_ULONG t1, t2; + + if ((a == NULL) || (b == NULL)) { + if (a != NULL) { + return -1; + } else if (b != NULL) { + return 1; + } else { + return 0; + } + } + + if (a->neg != b->neg) { + if (a->neg) { + return -1; + } + return 1; + } + if (a->neg == 0) { + gt = 1; + lt = -1; + } else { + gt = -1; + lt = 1; + } + + if (a->top > b->top) { + return gt; + } + if (a->top < b->top) { + return lt; + } + + for (i = a->top - 1; i >= 0; i--) { + t1 = a->d[i]; + t2 = b->d[i]; + if (t1 > t2) { + return gt; + } if (t1 < t2) { + return lt; + } + } + + return 0; +} + +int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n) { + int i; + BN_ULONG aa, bb; + + aa = a[n - 1]; + bb = b[n - 1]; + if (aa != bb) { + return (aa > bb) ? 1 : -1; + } + + for (i = n - 2; i >= 0; i--) { + aa = a[i]; + bb = b[i]; + if (aa != bb) { + return (aa > bb) ? 1 : -1; + } + } + return 0; +} + +int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl) { + int n, i; + n = cl - 1; + + if (dl < 0) { + for (i = dl; i < 0; i++) { + if (b[n - i] != 0) { + return -1; /* a < b */ + } + } + } + if (dl > 0) { + for (i = dl; i > 0; i--) { + if (a[n + i] != 0) { + return 1; /* a > b */ + } + } + } + + return bn_cmp_words(a, b, cl); +} + +int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w) { + switch (bn->top) { + case 1: + return bn->d[0] == w; + case 0: + return w == 0; + default: + return 0; + } +} + +int BN_is_zero(const BIGNUM *bn) { + return bn->top == 0; +} + +int BN_is_one(const BIGNUM *bn) { + return bn->neg == 0 && BN_abs_is_word(bn, 1); +} + +int BN_is_word(const BIGNUM *bn, BN_ULONG w) { + return BN_abs_is_word(bn, w) && (w == 0 || bn->neg == 0); +} + +int BN_is_odd(const BIGNUM *bn) { + return bn->top > 0 && (bn->d[0] & 1) == 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/convert.c b/TMessagesProj/jni/boringssl/crypto/bn/convert.c new file mode 100644 index 00000000..4c707473 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/convert.c @@ -0,0 +1,501 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + +#include +#include +#include + +#include "internal.h" + +BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret) { + unsigned num_words, m; + BN_ULONG word = 0; + BIGNUM *bn = NULL; + + if (ret == NULL) { + ret = bn = BN_new(); + } + + if (ret == NULL) { + return NULL; + } + + if (len == 0) { + ret->top = 0; + return ret; + } + + num_words = ((len - 1) / BN_BYTES) + 1; + m = (len - 1) % BN_BYTES; + if (bn_wexpand(ret, num_words) == NULL) { + if (bn) { + BN_free(bn); + } + return NULL; + } + + ret->top = num_words; + ret->neg = 0; + + while (len--) { + word = (word << 8) | *(in++); + if (m-- == 0) { + ret->d[--num_words] = word; + word = 0; + m = BN_BYTES - 1; + } + } + + /* need to call this due to clear byte at top if avoiding having the top bit + * set (-ve number) */ + bn_correct_top(ret); + return ret; +} + +size_t BN_bn2bin(const BIGNUM *in, uint8_t *out) { + size_t n, i; + BN_ULONG l; + + n = i = BN_num_bytes(in); + while (i--) { + l = in->d[i / BN_BYTES]; + *(out++) = (unsigned char)(l >> (8 * (i % BN_BYTES))) & 0xff; + } + return n; +} + +/* constant_time_select_ulong returns |x| if |v| is 1 and |y| if |v| is 0. Its + * behavior is undefined if |v| takes any other value. */ +static BN_ULONG constant_time_select_ulong(int v, BN_ULONG x, BN_ULONG y) { + BN_ULONG mask = v; + mask--; + + return (~mask & x) | (mask & y); +} + +/* constant_time_le_size_t returns 1 if |x| <= |y| and 0 otherwise. |x| and |y| + * must not have their MSBs set. */ +static int constant_time_le_size_t(size_t x, size_t y) { + return ((x - y - 1) >> (sizeof(size_t) * 8 - 1)) & 1; +} + +/* read_word_padded returns the |i|'th word of |in|, if it is not out of + * bounds. Otherwise, it returns 0. It does so without branches on the size of + * |in|, however it necessarily does not have the same memory access pattern. If + * the access would be out of bounds, it reads the last word of |in|. |in| must + * not be zero. */ +static BN_ULONG read_word_padded(const BIGNUM *in, size_t i) { + /* Read |in->d[i]| if valid. Otherwise, read the last word. */ + BN_ULONG l = in->d[constant_time_select_ulong( + constant_time_le_size_t(in->dmax, i), in->dmax - 1, i)]; + + /* Clamp to zero if above |d->top|. */ + return constant_time_select_ulong(constant_time_le_size_t(in->top, i), 0, l); +} + +int BN_bn2bin_padded(uint8_t *out, size_t len, const BIGNUM *in) { + size_t i; + BN_ULONG l; + + /* Special case for |in| = 0. Just branch as the probability is negligible. */ + if (BN_is_zero(in)) { + memset(out, 0, len); + return 1; + } + + /* Check if the integer is too big. This case can exit early in non-constant + * time. */ + if ((size_t)in->top > (len + (BN_BYTES - 1)) / BN_BYTES) { + return 0; + } + if ((len % BN_BYTES) != 0) { + l = read_word_padded(in, len / BN_BYTES); + if (l >> (8 * (len % BN_BYTES)) != 0) { + return 0; + } + } + + /* Write the bytes out one by one. Serialization is done without branching on + * the bits of |in| or on |in->top|, but if the routine would otherwise read + * out of bounds, the memory access pattern can't be fixed. However, for an + * RSA key of size a multiple of the word size, the probability of BN_BYTES + * leading zero octets is low. + * + * See Falko Stenzke, "Manger's Attack revisited", ICICS 2010. */ + i = len; + while (i--) { + l = read_word_padded(in, i / BN_BYTES); + *(out++) = (uint8_t)(l >> (8 * (i % BN_BYTES))) & 0xff; + } + return 1; +} + +static const char hextable[] = "0123456789abcdef"; + +char *BN_bn2hex(const BIGNUM *bn) { + int i, j, v, z = 0; + char *buf; + char *p; + + buf = (char *)OPENSSL_malloc(bn->top * BN_BYTES * 2 + 2); + if (buf == NULL) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + return NULL; + } + + p = buf; + if (bn->neg) { + *(p++) = '-'; + } + + if (BN_is_zero(bn)) { + *(p++) = '0'; + } + + for (i = bn->top - 1; i >= 0; i--) { + for (j = BN_BITS2 - 8; j >= 0; j -= 8) { + /* strip leading zeros */ + v = ((int)(bn->d[i] >> (long)j)) & 0xff; + if (z || v != 0) { + *(p++) = hextable[v >> 4]; + *(p++) = hextable[v & 0x0f]; + z = 1; + } + } + } + *p = '\0'; + + return buf; +} + +/* decode_hex decodes |i| bytes of hex data from |in| and updates |bn|. */ +static void decode_hex(BIGNUM *bn, const char *in, int i) { + int h, m, j, k, c; + BN_ULONG l=0; + + j = i; /* least significant 'hex' */ + h = 0; + while (j > 0) { + m = ((BN_BYTES * 2) <= j) ? (BN_BYTES * 2) : j; + l = 0; + for (;;) { + c = in[j - m]; + if ((c >= '0') && (c <= '9')) { + k = c - '0'; + } else if ((c >= 'a') && (c <= 'f')) { + k = c - 'a' + 10; + } else if ((c >= 'A') && (c <= 'F')) { + k = c - 'A' + 10; + } else { + k = 0; /* paranoia */ + } + + l = (l << 4) | k; + + if (--m <= 0) { + bn->d[h++] = l; + break; + } + } + + j -= (BN_BYTES * 2); + } + + bn->top = h; +} + +/* decode_dec decodes |in_len| bytes of decimal data from |in| and updates |bn|. */ +static void decode_dec(BIGNUM *bn, const char *in, int in_len) { + int i, j; + BN_ULONG l = 0; + + j = BN_DEC_NUM - (in_len % BN_DEC_NUM); + if (j == BN_DEC_NUM) { + j = 0; + } + l = 0; + for (i = 0; i < in_len; i++) { + l *= 10; + l += in[i] - '0'; + if (++j == BN_DEC_NUM) { + BN_mul_word(bn, BN_DEC_CONV); + BN_add_word(bn, l); + l = 0; + j = 0; + } + } +} + +typedef void (*decode_func) (BIGNUM *bn, const char *in, int i); +typedef int (*char_test_func) (int c); + +static int bn_x2bn(BIGNUM **outp, const char *in, decode_func decode, char_test_func want_char) { + BIGNUM *ret = NULL; + int neg = 0, i; + int num; + + if (in == NULL || *in == 0) { + return 0; + } + + if (*in == '-') { + neg = 1; + in++; + } + + for (i = 0; want_char((unsigned char)in[i]); i++) {} + + num = i + neg; + if (outp == NULL) { + return num; + } + + /* in is the start of the hex digits, and it is 'i' long */ + if (*outp == NULL) { + ret = BN_new(); + if (ret == NULL) { + return 0; + } + } else { + ret = *outp; + BN_zero(ret); + } + + /* i is the number of hex digests; */ + if (bn_expand(ret, i * 4) == NULL) { + goto err; + } + + decode(ret, in, i); + + bn_correct_top(ret); + if (!BN_is_zero(ret)) { + ret->neg = neg; + } + + *outp = ret; + return num; + +err: + if (*outp == NULL) { + BN_free(ret); + } + + return 0; +} + +int BN_hex2bn(BIGNUM **outp, const char *in) { + return bn_x2bn(outp, in, decode_hex, isxdigit); +} + +char *BN_bn2dec(const BIGNUM *a) { + int i = 0, num, ok = 0; + char *buf = NULL; + char *p; + BIGNUM *t = NULL; + BN_ULONG *bn_data = NULL, *lp; + + /* get an upper bound for the length of the decimal integer + * num <= (BN_num_bits(a) + 1) * log(2) + * <= 3 * BN_num_bits(a) * 0.1001 + log(2) + 1 (rounding error) + * <= BN_num_bits(a)/10 + BN_num_bits/1000 + 1 + 1 + */ + i = BN_num_bits(a) * 3; + num = i / 10 + i / 1000 + 1 + 1; + bn_data = + (BN_ULONG *)OPENSSL_malloc((num / BN_DEC_NUM + 1) * sizeof(BN_ULONG)); + buf = (char *)OPENSSL_malloc(num + 3); + if ((buf == NULL) || (bn_data == NULL)) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + goto err; + } + t = BN_dup(a); + if (t == NULL) { + goto err; + } + +#define BUF_REMAIN (num + 3 - (size_t)(p - buf)) + p = buf; + lp = bn_data; + if (BN_is_zero(t)) { + *(p++) = '0'; + *(p++) = '\0'; + } else { + if (BN_is_negative(t)) { + *p++ = '-'; + } + + while (!BN_is_zero(t)) { + *lp = BN_div_word(t, BN_DEC_CONV); + lp++; + } + lp--; + /* We now have a series of blocks, BN_DEC_NUM chars + * in length, where the last one needs truncation. + * The blocks need to be reversed in order. */ + BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT1, *lp); + while (*p) { + p++; + } + while (lp != bn_data) { + lp--; + BIO_snprintf(p, BUF_REMAIN, BN_DEC_FMT2, *lp); + while (*p) { + p++; + } + } + } + ok = 1; + +err: + OPENSSL_free(bn_data); + BN_free(t); + if (!ok) { + OPENSSL_free(buf); + buf = NULL; + } + + return buf; +} + +int BN_dec2bn(BIGNUM **outp, const char *in) { + return bn_x2bn(outp, in, decode_dec, isdigit); +} + +int BN_asc2bn(BIGNUM **outp, const char *in) { + const char *const orig_in = in; + if (*in == '-') { + in++; + } + + if (in[0] == '0' && (in[1] == 'X' || in[1] == 'x')) { + if (!BN_hex2bn(outp, in+2)) { + return 0; + } + } else { + if (!BN_dec2bn(outp, in)) { + return 0; + } + } + + if (*orig_in == '-' && !BN_is_zero(*outp)) { + (*outp)->neg = 1; + } + + return 1; +} + +int BN_print(BIO *bp, const BIGNUM *a) { + int i, j, v, z = 0; + int ret = 0; + + if (a->neg && BIO_write(bp, "-", 1) != 1) { + goto end; + } + + if (BN_is_zero(a) && BIO_write(bp, "0", 1) != 1) { + goto end; + } + + for (i = a->top - 1; i >= 0; i--) { + for (j = BN_BITS2 - 4; j >= 0; j -= 4) { + /* strip leading zeros */ + v = ((int)(a->d[i] >> (long)j)) & 0x0f; + if (z || v != 0) { + if (BIO_write(bp, &hextable[v], 1) != 1) { + goto end; + } + z = 1; + } + } + } + ret = 1; + +end: + return ret; +} + +int BN_print_fp(FILE *fp, const BIGNUM *a) { + BIO *b; + int ret; + + b = BIO_new(BIO_s_file()); + if (b == NULL) { + return 0; + } + BIO_set_fp(b, fp, BIO_NOCLOSE); + ret = BN_print(b, a); + BIO_free(b); + + return ret; +} + +BN_ULONG BN_get_word(const BIGNUM *bn) { + switch (bn->top) { + case 0: + return 0; + case 1: + return bn->d[0]; + default: + return BN_MASK2; + } +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/ctx.c b/TMessagesProj/jni/boringssl/crypto/bn/ctx.c new file mode 100644 index 00000000..48d9adf6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/ctx.c @@ -0,0 +1,311 @@ +/* Written by Ulf Moeller for the OpenSSL project. */ +/* ==================================================================== + * Copyright (c) 1998-2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include + +#include + +#include +#include + + +/* How many bignums are in each "pool item"; */ +#define BN_CTX_POOL_SIZE 16 +/* The stack frame info is resizing, set a first-time expansion size; */ +#define BN_CTX_START_FRAMES 32 + +/* A bundle of bignums that can be linked with other bundles */ +typedef struct bignum_pool_item { + /* The bignum values */ + BIGNUM vals[BN_CTX_POOL_SIZE]; + /* Linked-list admin */ + struct bignum_pool_item *prev, *next; +} BN_POOL_ITEM; + + +typedef struct bignum_pool { + /* Linked-list admin */ + BN_POOL_ITEM *head, *current, *tail; + /* Stack depth and allocation size */ + unsigned used, size; +} BN_POOL; + +static void BN_POOL_init(BN_POOL *); +static void BN_POOL_finish(BN_POOL *); +static BIGNUM *BN_POOL_get(BN_POOL *); +static void BN_POOL_release(BN_POOL *, unsigned int); + +/************/ +/* BN_STACK */ +/************/ + +/* A wrapper to manage the "stack frames" */ +typedef struct bignum_ctx_stack { + /* Array of indexes into the bignum stack */ + unsigned int *indexes; + /* Number of stack frames, and the size of the allocated array */ + unsigned int depth, size; +} BN_STACK; + +static void BN_STACK_init(BN_STACK *); +static void BN_STACK_finish(BN_STACK *); +static int BN_STACK_push(BN_STACK *, unsigned int); +static unsigned int BN_STACK_pop(BN_STACK *); + +/**********/ +/* BN_CTX */ +/**********/ + +/* The opaque BN_CTX type */ +struct bignum_ctx { + /* The bignum bundles */ + BN_POOL pool; + /* The "stack frames", if you will */ + BN_STACK stack; + /* The number of bignums currently assigned */ + unsigned int used; + /* Depth of stack overflow */ + int err_stack; + /* Block "gets" until an "end" (compatibility behaviour) */ + int too_many; +}; + +BN_CTX *BN_CTX_new(void) { + BN_CTX *ret = OPENSSL_malloc(sizeof(BN_CTX)); + if (!ret) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + return NULL; + } + + /* Initialise the structure */ + BN_POOL_init(&ret->pool); + BN_STACK_init(&ret->stack); + ret->used = 0; + ret->err_stack = 0; + ret->too_many = 0; + return ret; +} + +void BN_CTX_free(BN_CTX *ctx) { + if (ctx == NULL) { + return; + } + + BN_STACK_finish(&ctx->stack); + BN_POOL_finish(&ctx->pool); + OPENSSL_free(ctx); +} + +void BN_CTX_start(BN_CTX *ctx) { + /* If we're already overflowing ... */ + if (ctx->err_stack || ctx->too_many) { + ctx->err_stack++; + } else if (!BN_STACK_push(&ctx->stack, ctx->used)) { + /* (Try to) get a new frame pointer */ + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_TEMPORARY_VARIABLES); + ctx->err_stack++; + } +} + +BIGNUM *BN_CTX_get(BN_CTX *ctx) { + BIGNUM *ret; + if (ctx->err_stack || ctx->too_many) { + return NULL; + } + + ret = BN_POOL_get(&ctx->pool); + if (ret == NULL) { + /* Setting too_many prevents repeated "get" attempts from + * cluttering the error stack. */ + ctx->too_many = 1; + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_TEMPORARY_VARIABLES); + return NULL; + } + + /* OK, make sure the returned bignum is "zero" */ + BN_zero(ret); + ctx->used++; + return ret; +} + +void BN_CTX_end(BN_CTX *ctx) { + if (ctx->err_stack) { + ctx->err_stack--; + } else { + unsigned int fp = BN_STACK_pop(&ctx->stack); + /* Does this stack frame have anything to release? */ + if (fp < ctx->used) { + BN_POOL_release(&ctx->pool, ctx->used - fp); + } + + ctx->used = fp; + /* Unjam "too_many" in case "get" had failed */ + ctx->too_many = 0; + } +} + +/************/ +/* BN_STACK */ +/************/ + +static void BN_STACK_init(BN_STACK *st) { + st->indexes = NULL; + st->depth = st->size = 0; +} + +static void BN_STACK_finish(BN_STACK *st) { + OPENSSL_free(st->indexes); +} + +static int BN_STACK_push(BN_STACK *st, unsigned int idx) { + if (st->depth == st->size) { + /* Need to expand */ + unsigned int newsize = + (st->size ? (st->size * 3 / 2) : BN_CTX_START_FRAMES); + unsigned int *newitems = OPENSSL_malloc(newsize * sizeof(unsigned int)); + if (!newitems) { + return 0; + } + if (st->depth) { + memcpy(newitems, st->indexes, st->depth * sizeof(unsigned int)); + } + OPENSSL_free(st->indexes); + st->indexes = newitems; + st->size = newsize; + } + + st->indexes[(st->depth)++] = idx; + return 1; +} + +static unsigned int BN_STACK_pop(BN_STACK *st) { + return st->indexes[--(st->depth)]; +} + +static void BN_POOL_init(BN_POOL *p) { + p->head = p->current = p->tail = NULL; + p->used = p->size = 0; +} + +static void BN_POOL_finish(BN_POOL *p) { + while (p->head) { + unsigned int loop = 0; + BIGNUM *bn = p->head->vals; + while (loop++ < BN_CTX_POOL_SIZE) { + if (bn->d) { + BN_clear_free(bn); + } + bn++; + } + + p->current = p->head->next; + OPENSSL_free(p->head); + p->head = p->current; + } +} + +static BIGNUM *BN_POOL_get(BN_POOL *p) { + if (p->used == p->size) { + BIGNUM *bn; + unsigned int loop = 0; + BN_POOL_ITEM *item = OPENSSL_malloc(sizeof(BN_POOL_ITEM)); + if (!item) { + return NULL; + } + + /* Initialise the structure */ + bn = item->vals; + while (loop++ < BN_CTX_POOL_SIZE) { + BN_init(bn++); + } + + item->prev = p->tail; + item->next = NULL; + /* Link it in */ + if (!p->head) { + p->head = p->current = p->tail = item; + } else { + p->tail->next = item; + p->tail = item; + p->current = item; + } + + p->size += BN_CTX_POOL_SIZE; + p->used++; + /* Return the first bignum from the new pool */ + return item->vals; + } + + if (!p->used) { + p->current = p->head; + } else if ((p->used % BN_CTX_POOL_SIZE) == 0) { + p->current = p->current->next; + } + + return p->current->vals + ((p->used++) % BN_CTX_POOL_SIZE); +} + +static void BN_POOL_release(BN_POOL *p, unsigned int num) { + unsigned int offset = (p->used - 1) % BN_CTX_POOL_SIZE; + p->used -= num; + + while (num--) { + if (!offset) { + offset = BN_CTX_POOL_SIZE - 1; + p->current = p->current->prev; + } else { + offset--; + } + } +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/div.c b/TMessagesProj/jni/boringssl/crypto/bn/div.c new file mode 100644 index 00000000..779dda2d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/div.c @@ -0,0 +1,625 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include "internal.h" + + +#define asm __asm__ + +#if !defined(OPENSSL_NO_ASM) +# if defined(__GNUC__) && __GNUC__>=2 +# if defined(OPENSSL_X86) + /* + * There were two reasons for implementing this template: + * - GNU C generates a call to a function (__udivdi3 to be exact) + * in reply to ((((BN_ULLONG)n0)< + */ +#undef div_asm +# define div_asm(n0,n1,d0) \ + ({ asm volatile ( \ + "divl %4" \ + : "=a"(q), "=d"(rem) \ + : "a"(n1), "d"(n0), "g"(d0) \ + : "cc"); \ + q; \ + }) +# define REMAINDER_IS_ALREADY_CALCULATED +# elif defined(OPENSSL_X86_64) + /* + * Same story here, but it's 128-bit by 64-bit division. Wow! + * + */ +# undef div_asm +# define div_asm(n0,n1,d0) \ + ({ asm volatile ( \ + "divq %4" \ + : "=a"(q), "=d"(rem) \ + : "a"(n1), "d"(n0), "g"(d0) \ + : "cc"); \ + q; \ + }) +# define REMAINDER_IS_ALREADY_CALCULATED +# endif /* __ */ +# endif /* __GNUC__ */ +#endif /* OPENSSL_NO_ASM */ + +/* BN_div computes dv := num / divisor, rounding towards + * zero, and sets up rm such that dv*divisor + rm = num holds. + * Thus: + * dv->neg == num->neg ^ divisor->neg (unless the result is zero) + * rm->neg == num->neg (unless the remainder is zero) + * If 'dv' or 'rm' is NULL, the respective value is not returned. */ +int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor, + BN_CTX *ctx) { + int norm_shift, i, loop; + BIGNUM *tmp, wnum, *snum, *sdiv, *res; + BN_ULONG *resp, *wnump; + BN_ULONG d0, d1; + int num_n, div_n; + int no_branch = 0; + + /* Invalid zero-padding would have particularly bad consequences + * so don't just rely on bn_check_top() here */ + if ((num->top > 0 && num->d[num->top - 1] == 0) || + (divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) { + OPENSSL_PUT_ERROR(BN, BN_R_NOT_INITIALIZED); + return 0; + } + + if ((num->flags & BN_FLG_CONSTTIME) != 0 || + (divisor->flags & BN_FLG_CONSTTIME) != 0) { + no_branch = 1; + } + + if (BN_is_zero(divisor)) { + OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO); + return 0; + } + + if (!no_branch && BN_ucmp(num, divisor) < 0) { + if (rm != NULL) { + if (BN_copy(rm, num) == NULL) { + return 0; + } + } + if (dv != NULL) { + BN_zero(dv); + } + return 1; + } + + BN_CTX_start(ctx); + tmp = BN_CTX_get(ctx); + snum = BN_CTX_get(ctx); + sdiv = BN_CTX_get(ctx); + if (dv == NULL) { + res = BN_CTX_get(ctx); + } else { + res = dv; + } + if (sdiv == NULL || res == NULL || tmp == NULL || snum == NULL) { + goto err; + } + + /* First we normalise the numbers */ + norm_shift = BN_BITS2 - ((BN_num_bits(divisor)) % BN_BITS2); + if (!(BN_lshift(sdiv, divisor, norm_shift))) { + goto err; + } + sdiv->neg = 0; + norm_shift += BN_BITS2; + if (!(BN_lshift(snum, num, norm_shift))) { + goto err; + } + snum->neg = 0; + + if (no_branch) { + /* Since we don't know whether snum is larger than sdiv, + * we pad snum with enough zeroes without changing its + * value. + */ + if (snum->top <= sdiv->top + 1) { + if (bn_wexpand(snum, sdiv->top + 2) == NULL) { + goto err; + } + for (i = snum->top; i < sdiv->top + 2; i++) { + snum->d[i] = 0; + } + snum->top = sdiv->top + 2; + } else { + if (bn_wexpand(snum, snum->top + 1) == NULL) { + goto err; + } + snum->d[snum->top] = 0; + snum->top++; + } + } + + div_n = sdiv->top; + num_n = snum->top; + loop = num_n - div_n; + /* Lets setup a 'window' into snum + * This is the part that corresponds to the current + * 'area' being divided */ + wnum.neg = 0; + wnum.d = &(snum->d[loop]); + wnum.top = div_n; + /* only needed when BN_ucmp messes up the values between top and max */ + wnum.dmax = snum->dmax - loop; /* so we don't step out of bounds */ + + /* Get the top 2 words of sdiv */ + /* div_n=sdiv->top; */ + d0 = sdiv->d[div_n - 1]; + d1 = (div_n == 1) ? 0 : sdiv->d[div_n - 2]; + + /* pointer to the 'top' of snum */ + wnump = &(snum->d[num_n - 1]); + + /* Setup to 'res' */ + res->neg = (num->neg ^ divisor->neg); + if (!bn_wexpand(res, (loop + 1))) { + goto err; + } + res->top = loop - no_branch; + resp = &(res->d[loop - 1]); + + /* space for temp */ + if (!bn_wexpand(tmp, (div_n + 1))) { + goto err; + } + + if (!no_branch) { + if (BN_ucmp(&wnum, sdiv) >= 0) { + bn_sub_words(wnum.d, wnum.d, sdiv->d, div_n); + *resp = 1; + } else { + res->top--; + } + } + + /* if res->top == 0 then clear the neg value otherwise decrease + * the resp pointer */ + if (res->top == 0) { + res->neg = 0; + } else { + resp--; + } + + for (i = 0; i < loop - 1; i++, wnump--, resp--) { + BN_ULONG q, l0; + /* the first part of the loop uses the top two words of snum and sdiv to + * calculate a BN_ULONG q such that | wnum - sdiv * q | < sdiv */ + BN_ULONG n0, n1, rem = 0; + + n0 = wnump[0]; + n1 = wnump[-1]; + if (n0 == d0) { + q = BN_MASK2; + } else { + /* n0 < d0 */ +#ifdef BN_LLONG + BN_ULLONG t2; + +#if defined(BN_LLONG) && !defined(div_asm) + q = (BN_ULONG)(((((BN_ULLONG)n0) << BN_BITS2) | n1) / d0); +#else + q = div_asm(n0, n1, d0); +#endif + +#ifndef REMAINDER_IS_ALREADY_CALCULATED + /* rem doesn't have to be BN_ULLONG. The least we know it's less that d0, + * isn't it? */ + rem = (n1 - q * d0) & BN_MASK2; +#endif + + t2 = (BN_ULLONG)d1 * q; + + for (;;) { + if (t2 <= ((((BN_ULLONG)rem) << BN_BITS2) | wnump[-2])) { + break; + } + q--; + rem += d0; + if (rem < d0) { + break; /* don't let rem overflow */ + } + t2 -= d1; + } +#else /* !BN_LLONG */ + BN_ULONG t2l, t2h; + +#if defined(div_asm) + q = div_asm(n0, n1, d0); +#else + q = bn_div_words(n0, n1, d0); +#endif + +#ifndef REMAINDER_IS_ALREADY_CALCULATED + rem = (n1 - q * d0) & BN_MASK2; +#endif + +#if defined(BN_UMULT_LOHI) + BN_UMULT_LOHI(t2l, t2h, d1, q); +#elif defined(BN_UMULT_HIGH) + t2l = d1 * q; + t2h = BN_UMULT_HIGH(d1, q); +#else + { + BN_ULONG ql, qh; + t2l = LBITS(d1); + t2h = HBITS(d1); + ql = LBITS(q); + qh = HBITS(q); + mul64(t2l, t2h, ql, qh); /* t2=(BN_ULLONG)d1*q; */ + } +#endif + + for (;;) { + if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2]))) { + break; + } + q--; + rem += d0; + if (rem < d0) { + break; /* don't let rem overflow */ + } + if (t2l < d1) { + t2h--; + } + t2l -= d1; + } +#endif /* !BN_LLONG */ + } + + l0 = bn_mul_words(tmp->d, sdiv->d, div_n, q); + tmp->d[div_n] = l0; + wnum.d--; + /* ingore top values of the bignums just sub the two + * BN_ULONG arrays with bn_sub_words */ + if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n + 1)) { + /* Note: As we have considered only the leading + * two BN_ULONGs in the calculation of q, sdiv * q + * might be greater than wnum (but then (q-1) * sdiv + * is less or equal than wnum) + */ + q--; + if (bn_add_words(wnum.d, wnum.d, sdiv->d, div_n)) { + /* we can't have an overflow here (assuming + * that q != 0, but if q == 0 then tmp is + * zero anyway) */ + (*wnump)++; + } + } + /* store part of the result */ + *resp = q; + } + bn_correct_top(snum); + if (rm != NULL) { + /* Keep a copy of the neg flag in num because if rm==num + * BN_rshift() will overwrite it. + */ + int neg = num->neg; + if (!BN_rshift(rm, snum, norm_shift)) { + goto err; + } + if (!BN_is_zero(rm)) { + rm->neg = neg; + } + } + if (no_branch) { + bn_correct_top(res); + } + BN_CTX_end(ctx); + return 1; + +err: + BN_CTX_end(ctx); + return 0; +} + +int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx) { + if (!(BN_mod(r, m, d, ctx))) { + return 0; + } + if (!r->neg) { + return 1; + } + + /* now -|d| < r < 0, so we have to set r := r + |d|. */ + return (d->neg ? BN_sub : BN_add)(r, r, d); +} + +int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, + BN_CTX *ctx) { + if (!BN_add(r, a, b)) { + return 0; + } + return BN_nnmod(r, r, m, ctx); +} + +int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m) { + if (!BN_uadd(r, a, b)) { + return 0; + } + if (BN_ucmp(r, m) >= 0) { + return BN_usub(r, r, m); + } + return 1; +} + +int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, + BN_CTX *ctx) { + if (!BN_sub(r, a, b)) { + return 0; + } + return BN_nnmod(r, r, m, ctx); +} + +/* BN_mod_sub variant that may be used if both a and b are non-negative + * and less than m */ +int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m) { + if (!BN_sub(r, a, b)) { + return 0; + } + if (r->neg) { + return BN_add(r, r, m); + } + return 1; +} + +int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m, + BN_CTX *ctx) { + BIGNUM *t; + int ret = 0; + + BN_CTX_start(ctx); + t = BN_CTX_get(ctx); + if (t == NULL) { + goto err; + } + + if (a == b) { + if (!BN_sqr(t, a, ctx)) { + goto err; + } + } else { + if (!BN_mul(t, a, b, ctx)) { + goto err; + } + } + + if (!BN_nnmod(r, t, m, ctx)) { + goto err; + } + + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx) { + if (!BN_sqr(r, a, ctx)) { + return 0; + } + + /* r->neg == 0, thus we don't need BN_nnmod */ + return BN_mod(r, r, m, ctx); +} + +int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m, + BN_CTX *ctx) { + BIGNUM *abs_m = NULL; + int ret; + + if (!BN_nnmod(r, a, m, ctx)) { + return 0; + } + + if (m->neg) { + abs_m = BN_dup(m); + if (abs_m == NULL) { + return 0; + } + abs_m->neg = 0; + } + + ret = BN_mod_lshift_quick(r, r, n, (abs_m ? abs_m : m)); + + BN_free(abs_m); + return ret; +} + +int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m) { + if (r != a) { + if (BN_copy(r, a) == NULL) { + return 0; + } + } + + while (n > 0) { + int max_shift; + + /* 0 < r < m */ + max_shift = BN_num_bits(m) - BN_num_bits(r); + /* max_shift >= 0 */ + + if (max_shift < 0) { + OPENSSL_PUT_ERROR(BN, BN_R_INPUT_NOT_REDUCED); + return 0; + } + + if (max_shift > n) { + max_shift = n; + } + + if (max_shift) { + if (!BN_lshift(r, r, max_shift)) { + return 0; + } + n -= max_shift; + } else { + if (!BN_lshift1(r, r)) { + return 0; + } + --n; + } + + /* BN_num_bits(r) <= BN_num_bits(m) */ + if (BN_cmp(r, m) >= 0) { + if (!BN_sub(r, r, m)) { + return 0; + } + } + } + + return 1; +} + +int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx) { + if (!BN_lshift1(r, a)) { + return 0; + } + + return BN_nnmod(r, r, m, ctx); +} + +int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m) { + if (!BN_lshift1(r, a)) { + return 0; + } + if (BN_cmp(r, m) >= 0) { + return BN_sub(r, r, m); + } + + return 1; +} + +BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) { + BN_ULONG ret = 0; + int i, j; + + w &= BN_MASK2; + + if (!w) { + /* actually this an error (division by zero) */ + return (BN_ULONG) - 1; + } + + if (a->top == 0) { + return 0; + } + + /* normalize input (so bn_div_words doesn't complain) */ + j = BN_BITS2 - BN_num_bits_word(w); + w <<= j; + if (!BN_lshift(a, a, j)) { + return (BN_ULONG) - 1; + } + + for (i = a->top - 1; i >= 0; i--) { + BN_ULONG l, d; + + l = a->d[i]; + d = bn_div_words(ret, l, w); + ret = (l - ((d * w) & BN_MASK2)) & BN_MASK2; + a->d[i] = d; + } + + if ((a->top > 0) && (a->d[a->top - 1] == 0)) { + a->top--; + } + + ret >>= j; + return ret; +} + +BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) { +#ifndef BN_LLONG + BN_ULONG ret = 0; +#else + BN_ULLONG ret = 0; +#endif + int i; + + if (w == 0) { + return (BN_ULONG) -1; + } + + w &= BN_MASK2; + for (i = a->top - 1; i >= 0; i--) { +#ifndef BN_LLONG + ret = ((ret << BN_BITS4) | ((a->d[i] >> BN_BITS4) & BN_MASK2l)) % w; + ret = ((ret << BN_BITS4) | (a->d[i] & BN_MASK2l)) % w; +#else + ret = (BN_ULLONG)(((ret << (BN_ULLONG)BN_BITS2) | a->d[i]) % (BN_ULLONG)w); +#endif + } + return (BN_ULONG)ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/exponentiation.c b/TMessagesProj/jni/boringssl/crypto/bn/exponentiation.c new file mode 100644 index 00000000..a829810a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/exponentiation.c @@ -0,0 +1,1559 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include +#include +#include + +#include "internal.h" + + +#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) +#define OPENSSL_BN_ASM_MONT5 +#define RSAZ_ENABLED + +#include "rsaz_exp.h" +#endif + +int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) { + int i, bits, ret = 0; + BIGNUM *v, *rr; + + if ((p->flags & BN_FLG_CONSTTIME) != 0) { + /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */ + OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + BN_CTX_start(ctx); + if (r == a || r == p) { + rr = BN_CTX_get(ctx); + } else { + rr = r; + } + + v = BN_CTX_get(ctx); + if (rr == NULL || v == NULL) { + goto err; + } + + if (BN_copy(v, a) == NULL) { + goto err; + } + bits = BN_num_bits(p); + + if (BN_is_odd(p)) { + if (BN_copy(rr, a) == NULL) { + goto err; + } + } else { + if (!BN_one(rr)) { + goto err; + } + } + + for (i = 1; i < bits; i++) { + if (!BN_sqr(v, v, ctx)) { + goto err; + } + if (BN_is_bit_set(p, i)) { + if (!BN_mul(rr, rr, v, ctx)) { + goto err; + } + } + } + + if (r != rr && !BN_copy(r, rr)) { + goto err; + } + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +/* maximum precomputation table size for *variable* sliding windows */ +#define TABLE_SIZE 32 + +typedef struct bn_recp_ctx_st { + BIGNUM N; /* the divisor */ + BIGNUM Nr; /* the reciprocal */ + int num_bits; + int shift; + int flags; +} BN_RECP_CTX; + +static void BN_RECP_CTX_init(BN_RECP_CTX *recp) { + BN_init(&recp->N); + BN_init(&recp->Nr); + recp->num_bits = 0; + recp->flags = 0; +} + +static void BN_RECP_CTX_free(BN_RECP_CTX *recp) { + if (recp == NULL) { + return; + } + + BN_free(&recp->N); + BN_free(&recp->Nr); +} + +static int BN_RECP_CTX_set(BN_RECP_CTX *recp, const BIGNUM *d, BN_CTX *ctx) { + if (!BN_copy(&(recp->N), d)) { + return 0; + } + BN_zero(&recp->Nr); + recp->num_bits = BN_num_bits(d); + recp->shift = 0; + + return 1; +} + +/* len is the expected size of the result We actually calculate with an extra + * word of precision, so we can do faster division if the remainder is not + * required. + * r := 2^len / m */ +static int BN_reciprocal(BIGNUM *r, const BIGNUM *m, int len, BN_CTX *ctx) { + int ret = -1; + BIGNUM *t; + + BN_CTX_start(ctx); + t = BN_CTX_get(ctx); + if (t == NULL) { + goto err; + } + + if (!BN_set_bit(t, len)) { + goto err; + } + + if (!BN_div(r, NULL, t, m, ctx)) { + goto err; + } + + ret = len; + +err: + BN_CTX_end(ctx); + return ret; +} + +static int BN_div_recp(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, + BN_RECP_CTX *recp, BN_CTX *ctx) { + int i, j, ret = 0; + BIGNUM *a, *b, *d, *r; + + BN_CTX_start(ctx); + a = BN_CTX_get(ctx); + b = BN_CTX_get(ctx); + if (dv != NULL) { + d = dv; + } else { + d = BN_CTX_get(ctx); + } + + if (rem != NULL) { + r = rem; + } else { + r = BN_CTX_get(ctx); + } + + if (a == NULL || b == NULL || d == NULL || r == NULL) { + goto err; + } + + if (BN_ucmp(m, &(recp->N)) < 0) { + BN_zero(d); + if (!BN_copy(r, m)) { + return 0; + } + BN_CTX_end(ctx); + return 1; + } + + /* We want the remainder + * Given input of ABCDEF / ab + * we need multiply ABCDEF by 3 digests of the reciprocal of ab */ + + /* i := max(BN_num_bits(m), 2*BN_num_bits(N)) */ + i = BN_num_bits(m); + j = recp->num_bits << 1; + if (j > i) { + i = j; + } + + /* Nr := round(2^i / N) */ + if (i != recp->shift) { + recp->shift = + BN_reciprocal(&(recp->Nr), &(recp->N), i, + ctx); /* BN_reciprocal returns i, or -1 for an error */ + } + + if (recp->shift == -1) { + goto err; + } + + /* d := |round(round(m / 2^BN_num_bits(N)) * recp->Nr / 2^(i - + * BN_num_bits(N)))| + * = |round(round(m / 2^BN_num_bits(N)) * round(2^i / N) / 2^(i - + * BN_num_bits(N)))| + * <= |(m / 2^BN_num_bits(N)) * (2^i / N) * (2^BN_num_bits(N) / 2^i)| + * = |m/N| */ + if (!BN_rshift(a, m, recp->num_bits)) { + goto err; + } + if (!BN_mul(b, a, &(recp->Nr), ctx)) { + goto err; + } + if (!BN_rshift(d, b, i - recp->num_bits)) { + goto err; + } + d->neg = 0; + + if (!BN_mul(b, &(recp->N), d, ctx)) { + goto err; + } + if (!BN_usub(r, m, b)) { + goto err; + } + r->neg = 0; + + j = 0; + while (BN_ucmp(r, &(recp->N)) >= 0) { + if (j++ > 2) { + OPENSSL_PUT_ERROR(BN, BN_R_BAD_RECIPROCAL); + goto err; + } + if (!BN_usub(r, r, &(recp->N))) { + goto err; + } + if (!BN_add_word(d, 1)) { + goto err; + } + } + + r->neg = BN_is_zero(r) ? 0 : m->neg; + d->neg = m->neg ^ recp->N.neg; + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +static int BN_mod_mul_reciprocal(BIGNUM *r, const BIGNUM *x, const BIGNUM *y, + BN_RECP_CTX *recp, BN_CTX *ctx) { + int ret = 0; + BIGNUM *a; + const BIGNUM *ca; + + BN_CTX_start(ctx); + a = BN_CTX_get(ctx); + if (a == NULL) { + goto err; + } + + if (y != NULL) { + if (x == y) { + if (!BN_sqr(a, x, ctx)) { + goto err; + } + } else { + if (!BN_mul(a, x, y, ctx)) { + goto err; + } + } + ca = a; + } else { + ca = x; /* Just do the mod */ + } + + ret = BN_div_recp(NULL, r, ca, recp, ctx); + +err: + BN_CTX_end(ctx); + return ret; +} + +/* BN_window_bits_for_exponent_size -- macro for sliding window mod_exp + * functions + * + * For window size 'w' (w >= 2) and a random 'b' bits exponent, the number of + * multiplications is a constant plus on average + * + * 2^(w-1) + (b-w)/(w+1); + * + * here 2^(w-1) is for precomputing the table (we actually need entries only + * for windows that have the lowest bit set), and (b-w)/(w+1) is an + * approximation for the expected number of w-bit windows, not counting the + * first one. + * + * Thus we should use + * + * w >= 6 if b > 671 + * w = 5 if 671 > b > 239 + * w = 4 if 239 > b > 79 + * w = 3 if 79 > b > 23 + * w <= 2 if 23 > b + * + * (with draws in between). Very small exponents are often selected + * with low Hamming weight, so we use w = 1 for b <= 23. */ +#define BN_window_bits_for_exponent_size(b) \ + ((b) > 671 ? 6 : \ + (b) > 239 ? 5 : \ + (b) > 79 ? 4 : \ + (b) > 23 ? 3 : 1) + +static int mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx) { + int i, j, bits, ret = 0, wstart, window; + int start = 1; + BIGNUM *aa; + /* Table of variables obtained from 'ctx' */ + BIGNUM *val[TABLE_SIZE]; + BN_RECP_CTX recp; + + if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) { + /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */ + OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + bits = BN_num_bits(p); + + if (bits == 0) { + ret = BN_one(r); + return ret; + } + + BN_CTX_start(ctx); + aa = BN_CTX_get(ctx); + val[0] = BN_CTX_get(ctx); + if (!aa || !val[0]) { + goto err; + } + + BN_RECP_CTX_init(&recp); + if (m->neg) { + /* ignore sign of 'm' */ + if (!BN_copy(aa, m)) { + goto err; + } + aa->neg = 0; + if (BN_RECP_CTX_set(&recp, aa, ctx) <= 0) { + goto err; + } + } else { + if (BN_RECP_CTX_set(&recp, m, ctx) <= 0) { + goto err; + } + } + + if (!BN_nnmod(val[0], a, m, ctx)) { + goto err; /* 1 */ + } + if (BN_is_zero(val[0])) { + BN_zero(r); + ret = 1; + goto err; + } + + window = BN_window_bits_for_exponent_size(bits); + if (window > 1) { + if (!BN_mod_mul_reciprocal(aa, val[0], val[0], &recp, ctx)) { + goto err; /* 2 */ + } + j = 1 << (window - 1); + for (i = 1; i < j; i++) { + if (((val[i] = BN_CTX_get(ctx)) == NULL) || + !BN_mod_mul_reciprocal(val[i], val[i - 1], aa, &recp, ctx)) { + goto err; + } + } + } + + start = 1; /* This is used to avoid multiplication etc + * when there is only the value '1' in the + * buffer. */ + wstart = bits - 1; /* The top bit of the window */ + + if (!BN_one(r)) { + goto err; + } + + for (;;) { + int wvalue; /* The 'value' of the window */ + int wend; /* The bottom bit of the window */ + + if (BN_is_bit_set(p, wstart) == 0) { + if (!start) { + if (!BN_mod_mul_reciprocal(r, r, r, &recp, ctx)) { + goto err; + } + } + if (wstart == 0) { + break; + } + wstart--; + continue; + } + + /* We now have wstart on a 'set' bit, we now need to work out + * how bit a window to do. To do this we need to scan + * forward until the last set bit before the end of the + * window */ + wvalue = 1; + wend = 0; + for (i = 1; i < window; i++) { + if (wstart - i < 0) { + break; + } + if (BN_is_bit_set(p, wstart - i)) { + wvalue <<= (i - wend); + wvalue |= 1; + wend = i; + } + } + + /* wend is the size of the current window */ + j = wend + 1; + /* add the 'bytes above' */ + if (!start) { + for (i = 0; i < j; i++) { + if (!BN_mod_mul_reciprocal(r, r, r, &recp, ctx)) { + goto err; + } + } + } + + /* wvalue will be an odd number < 2^window */ + if (!BN_mod_mul_reciprocal(r, r, val[wvalue >> 1], &recp, ctx)) { + goto err; + } + + /* move the 'window' down further */ + wstart -= wend + 1; + start = 0; + if (wstart < 0) { + break; + } + } + ret = 1; + +err: + BN_CTX_end(ctx); + BN_RECP_CTX_free(&recp); + return ret; +} + +int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m, + BN_CTX *ctx) { + /* For even modulus m = 2^k*m_odd, it might make sense to compute + * a^p mod m_odd and a^p mod 2^k separately (with Montgomery + * exponentiation for the odd part), using appropriate exponent + * reductions, and combine the results using the CRT. + * + * For now, we use Montgomery only if the modulus is odd; otherwise, + * exponentiation using the reciprocal-based quick remaindering + * algorithm is used. + * + * (Timing obtained with expspeed.c [computations a^p mod m + * where a, p, m are of the same length: 256, 512, 1024, 2048, + * 4096, 8192 bits], compared to the running time of the + * standard algorithm: + * + * BN_mod_exp_mont 33 .. 40 % [AMD K6-2, Linux, debug configuration] + * 55 .. 77 % [UltraSparc processor, but + * debug-solaris-sparcv8-gcc conf.] + * + * BN_mod_exp_recp 50 .. 70 % [AMD K6-2, Linux, debug configuration] + * 62 .. 118 % [UltraSparc, debug-solaris-sparcv8-gcc] + * + * On the Sparc, BN_mod_exp_recp was faster than BN_mod_exp_mont + * at 2048 and more bits, but at 512 and 1024 bits, it was + * slower even than the standard algorithm! + * + * "Real" timings [linux-elf, solaris-sparcv9-gcc configurations] + * should be obtained when the new Montgomery reduction code + * has been integrated into OpenSSL.) */ + + if (BN_is_odd(m)) { + if (a->top == 1 && !a->neg && BN_get_flags(p, BN_FLG_CONSTTIME) == 0) { + BN_ULONG A = a->d[0]; + return BN_mod_exp_mont_word(r, A, p, m, ctx, NULL); + } + + return BN_mod_exp_mont(r, a, p, m, ctx, NULL); + } + + return mod_exp_recp(r, a, p, m, ctx); +} + +int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont) { + int i, j, bits, ret = 0, wstart, window; + int start = 1; + BIGNUM *d, *r; + const BIGNUM *aa; + /* Table of variables obtained from 'ctx' */ + BIGNUM *val[TABLE_SIZE]; + BN_MONT_CTX *mont = NULL; + + if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) { + return BN_mod_exp_mont_consttime(rr, a, p, m, ctx, in_mont); + } + + if (!BN_is_odd(m)) { + OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); + return 0; + } + bits = BN_num_bits(p); + if (bits == 0) { + ret = BN_one(rr); + return ret; + } + + BN_CTX_start(ctx); + d = BN_CTX_get(ctx); + r = BN_CTX_get(ctx); + val[0] = BN_CTX_get(ctx); + if (!d || !r || !val[0]) { + goto err; + } + + /* If this is not done, things will break in the montgomery part */ + + if (in_mont != NULL) { + mont = in_mont; + } else { + mont = BN_MONT_CTX_new(); + if (mont == NULL) { + goto err; + } + if (!BN_MONT_CTX_set(mont, m, ctx)) { + goto err; + } + } + + if (a->neg || BN_ucmp(a, m) >= 0) { + if (!BN_nnmod(val[0], a, m, ctx)) { + goto err; + } + aa = val[0]; + } else { + aa = a; + } + + if (BN_is_zero(aa)) { + BN_zero(rr); + ret = 1; + goto err; + } + if (!BN_to_montgomery(val[0], aa, mont, ctx)) { + goto err; /* 1 */ + } + + window = BN_window_bits_for_exponent_size(bits); + if (window > 1) { + if (!BN_mod_mul_montgomery(d, val[0], val[0], mont, ctx)) { + goto err; /* 2 */ + } + j = 1 << (window - 1); + for (i = 1; i < j; i++) { + if (((val[i] = BN_CTX_get(ctx)) == NULL) || + !BN_mod_mul_montgomery(val[i], val[i - 1], d, mont, ctx)) { + goto err; + } + } + } + + start = 1; /* This is used to avoid multiplication etc + * when there is only the value '1' in the + * buffer. */ + wstart = bits - 1; /* The top bit of the window */ + + j = m->top; /* borrow j */ + if (m->d[j - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) { + if (bn_wexpand(r, j) == NULL) { + goto err; + } + /* 2^(top*BN_BITS2) - m */ + r->d[0] = (0 - m->d[0]) & BN_MASK2; + for (i = 1; i < j; i++) { + r->d[i] = (~m->d[i]) & BN_MASK2; + } + r->top = j; + /* Upper words will be zero if the corresponding words of 'm' + * were 0xfff[...], so decrement r->top accordingly. */ + bn_correct_top(r); + } else if (!BN_to_montgomery(r, BN_value_one(), mont, ctx)) { + goto err; + } + + for (;;) { + int wvalue; /* The 'value' of the window */ + int wend; /* The bottom bit of the window */ + + if (BN_is_bit_set(p, wstart) == 0) { + if (!start && !BN_mod_mul_montgomery(r, r, r, mont, ctx)) { + goto err; + } + if (wstart == 0) { + break; + } + wstart--; + continue; + } + + /* We now have wstart on a 'set' bit, we now need to work out how bit a + * window to do. To do this we need to scan forward until the last set bit + * before the end of the window */ + wvalue = 1; + wend = 0; + for (i = 1; i < window; i++) { + if (wstart - i < 0) { + break; + } + if (BN_is_bit_set(p, wstart - i)) { + wvalue <<= (i - wend); + wvalue |= 1; + wend = i; + } + } + + /* wend is the size of the current window */ + j = wend + 1; + /* add the 'bytes above' */ + if (!start) { + for (i = 0; i < j; i++) { + if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) { + goto err; + } + } + } + + /* wvalue will be an odd number < 2^window */ + if (!BN_mod_mul_montgomery(r, r, val[wvalue >> 1], mont, ctx)) { + goto err; + } + + /* move the 'window' down further */ + wstart -= wend + 1; + start = 0; + if (wstart < 0) { + break; + } + } + + if (!BN_from_montgomery(rr, r, mont, ctx)) { + goto err; + } + ret = 1; + +err: + if (in_mont == NULL) { + BN_MONT_CTX_free(mont); + } + BN_CTX_end(ctx); + return ret; +} + +/* BN_mod_exp_mont_consttime() stores the precomputed powers in a specific + * layout so that accessing any of these table values shows the same access + * pattern as far as cache lines are concerned. The following functions are + * used to transfer a BIGNUM from/to that table. */ +static int copy_to_prebuf(const BIGNUM *b, int top, unsigned char *buf, int idx, + int width) { + size_t i, j; + + if (top > b->top) { + top = b->top; /* this works because 'buf' is explicitly zeroed */ + } + for (i = 0, j = idx; i < top * sizeof b->d[0]; i++, j += width) { + buf[j] = ((unsigned char *)b->d)[i]; + } + + return 1; +} + +static int copy_from_prebuf(BIGNUM *b, int top, unsigned char *buf, int idx, + int width) { + size_t i, j; + + if (bn_wexpand(b, top) == NULL) { + return 0; + } + + for (i = 0, j = idx; i < top * sizeof b->d[0]; i++, j += width) { + ((unsigned char *)b->d)[i] = buf[j]; + } + + b->top = top; + bn_correct_top(b); + return 1; +} + +/* BN_mod_exp_mont_conttime is based on the assumption that the L1 data cache + * line width of the target processor is at least the following value. */ +#define MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH (64) +#define MOD_EXP_CTIME_MIN_CACHE_LINE_MASK \ + (MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH - 1) + +/* Window sizes optimized for fixed window size modular exponentiation + * algorithm (BN_mod_exp_mont_consttime). + * + * To achieve the security goals of BN_mode_exp_mont_consttime, the maximum + * size of the window must not exceed + * log_2(MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH). + * + * Window size thresholds are defined for cache line sizes of 32 and 64, cache + * line sizes where log_2(32)=5 and log_2(64)=6 respectively. A window size of + * 7 should only be used on processors that have a 128 byte or greater cache + * line size. */ +#if MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH == 64 + +#define BN_window_bits_for_ctime_exponent_size(b) \ + ((b) > 937 ? 6 : (b) > 306 ? 5 : (b) > 89 ? 4 : (b) > 22 ? 3 : 1) +#define BN_MAX_WINDOW_BITS_FOR_CTIME_EXPONENT_SIZE (6) + +#elif MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH == 32 + +#define BN_window_bits_for_ctime_exponent_size(b) \ + ((b) > 306 ? 5 : (b) > 89 ? 4 : (b) > 22 ? 3 : 1) +#define BN_MAX_WINDOW_BITS_FOR_CTIME_EXPONENT_SIZE (5) + +#endif + +/* Given a pointer value, compute the next address that is a cache line + * multiple. */ +#define MOD_EXP_CTIME_ALIGN(x_) \ + ((unsigned char *)(x_) + \ + (MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH - \ + (((size_t)(x_)) & (MOD_EXP_CTIME_MIN_CACHE_LINE_MASK)))) + +/* This variant of BN_mod_exp_mont() uses fixed windows and the special + * precomputation memory layout to limit data-dependency to a minimum + * to protect secret exponents (cf. the hyper-threading timing attacks + * pointed out by Colin Percival, + * http://www.daemonology.net/hyperthreading-considered-harmful/) + */ +int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *in_mont) { + int i, bits, ret = 0, window, wvalue; + int top; + BN_MONT_CTX *mont = NULL; + + int numPowers; + unsigned char *powerbufFree = NULL; + int powerbufLen = 0; + unsigned char *powerbuf = NULL; + BIGNUM tmp, am; + + top = m->top; + + if (!(m->d[0] & 1)) { + OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); + return 0; + } + bits = BN_num_bits(p); + if (bits == 0) { + ret = BN_one(rr); + return ret; + } + + BN_CTX_start(ctx); + + /* Allocate a montgomery context if it was not supplied by the caller. + * If this is not done, things will break in the montgomery part. */ + if (in_mont != NULL) { + mont = in_mont; + } else { + mont = BN_MONT_CTX_new(); + if (mont == NULL || !BN_MONT_CTX_set(mont, m, ctx)) { + goto err; + } + } + +#ifdef RSAZ_ENABLED + /* If the size of the operands allow it, perform the optimized + * RSAZ exponentiation. For further information see + * crypto/bn/rsaz_exp.c and accompanying assembly modules. */ + if ((16 == a->top) && (16 == p->top) && (BN_num_bits(m) == 1024) && + rsaz_avx2_eligible()) { + if (NULL == bn_wexpand(rr, 16)) { + goto err; + } + RSAZ_1024_mod_exp_avx2(rr->d, a->d, p->d, m->d, mont->RR.d, mont->n0[0]); + rr->top = 16; + rr->neg = 0; + bn_correct_top(rr); + ret = 1; + goto err; + } else if ((8 == a->top) && (8 == p->top) && (BN_num_bits(m) == 512)) { + if (NULL == bn_wexpand(rr, 8)) { + goto err; + } + RSAZ_512_mod_exp(rr->d, a->d, p->d, m->d, mont->n0[0], mont->RR.d); + rr->top = 8; + rr->neg = 0; + bn_correct_top(rr); + ret = 1; + goto err; + } +#endif + + /* Get the window size to use with size of p. */ + window = BN_window_bits_for_ctime_exponent_size(bits); +#if defined(OPENSSL_BN_ASM_MONT5) + if (window >= 5) { + window = 5; /* ~5% improvement for RSA2048 sign, and even for RSA4096 */ + if ((top & 7) == 0) { + powerbufLen += 2 * top * sizeof(m->d[0]); + } + } +#endif + + /* Allocate a buffer large enough to hold all of the pre-computed + * powers of am, am itself and tmp. + */ + numPowers = 1 << window; + powerbufLen += + sizeof(m->d[0]) * + (top * numPowers + ((2 * top) > numPowers ? (2 * top) : numPowers)); +#ifdef alloca + if (powerbufLen < 3072) { + powerbufFree = alloca(powerbufLen + MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH); + } else +#endif + { + if ((powerbufFree = (unsigned char *)OPENSSL_malloc( + powerbufLen + MOD_EXP_CTIME_MIN_CACHE_LINE_WIDTH)) == NULL) { + goto err; + } + } + + powerbuf = MOD_EXP_CTIME_ALIGN(powerbufFree); + memset(powerbuf, 0, powerbufLen); + +#ifdef alloca + if (powerbufLen < 3072) { + powerbufFree = NULL; + } +#endif + + /* lay down tmp and am right after powers table */ + tmp.d = (BN_ULONG *)(powerbuf + sizeof(m->d[0]) * top * numPowers); + am.d = tmp.d + top; + tmp.top = am.top = 0; + tmp.dmax = am.dmax = top; + tmp.neg = am.neg = 0; + tmp.flags = am.flags = BN_FLG_STATIC_DATA; + +/* prepare a^0 in Montgomery domain */ +/* by Shay Gueron's suggestion */ + if (m->d[top - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) { + /* 2^(top*BN_BITS2) - m */ + tmp.d[0] = (0 - m->d[0]) & BN_MASK2; + for (i = 1; i < top; i++) { + tmp.d[i] = (~m->d[i]) & BN_MASK2; + } + tmp.top = top; + } else if (!BN_to_montgomery(&tmp, BN_value_one(), mont, ctx)) { + goto err; + } + + /* prepare a^1 in Montgomery domain */ + if (a->neg || BN_ucmp(a, m) >= 0) { + if (!BN_mod(&am, a, m, ctx) || + !BN_to_montgomery(&am, &am, mont, ctx)) { + goto err; + } + } else if (!BN_to_montgomery(&am, a, mont, ctx)) { + goto err; + } + +#if defined(OPENSSL_BN_ASM_MONT5) + /* This optimization uses ideas from http://eprint.iacr.org/2011/239, + * specifically optimization of cache-timing attack countermeasures + * and pre-computation optimization. */ + + /* Dedicated window==4 case improves 512-bit RSA sign by ~15%, but as + * 512-bit RSA is hardly relevant, we omit it to spare size... */ + if (window == 5 && top > 1) { + void bn_mul_mont_gather5(BN_ULONG * rp, const BN_ULONG * ap, + const void * table, const BN_ULONG * np, + const BN_ULONG * n0, int num, int power); + void bn_scatter5(const BN_ULONG * inp, size_t num, void * table, + size_t power); + void bn_gather5(BN_ULONG * out, size_t num, void * table, size_t power); + void bn_power5(BN_ULONG * rp, const BN_ULONG * ap, const void * table, + const BN_ULONG * np, const BN_ULONG * n0, int num, + int power); + int bn_from_montgomery(BN_ULONG * rp, const BN_ULONG * ap, + const BN_ULONG * not_used, const BN_ULONG * np, + const BN_ULONG * n0, int num); + + BN_ULONG *np = mont->N.d, *n0 = mont->n0, *np2; + + /* BN_to_montgomery can contaminate words above .top + * [in BN_DEBUG[_DEBUG] build]... */ + for (i = am.top; i < top; i++) { + am.d[i] = 0; + } + for (i = tmp.top; i < top; i++) { + tmp.d[i] = 0; + } + + if (top & 7) { + np2 = np; + } else { + for (np2 = am.d + top, i = 0; i < top; i++) { + np2[2 * i] = np[i]; + } + } + + bn_scatter5(tmp.d, top, powerbuf, 0); + bn_scatter5(am.d, am.top, powerbuf, 1); + bn_mul_mont(tmp.d, am.d, am.d, np, n0, top); + bn_scatter5(tmp.d, top, powerbuf, 2); + + /* same as above, but uses squaring for 1/2 of operations */ + for (i = 4; i < 32; i *= 2) { + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_scatter5(tmp.d, top, powerbuf, i); + } + for (i = 3; i < 8; i += 2) { + int j; + bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1); + bn_scatter5(tmp.d, top, powerbuf, i); + for (j = 2 * i; j < 32; j *= 2) { + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_scatter5(tmp.d, top, powerbuf, j); + } + } + for (; i < 16; i += 2) { + bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1); + bn_scatter5(tmp.d, top, powerbuf, i); + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_scatter5(tmp.d, top, powerbuf, 2 * i); + } + for (; i < 32; i += 2) { + bn_mul_mont_gather5(tmp.d, am.d, powerbuf, np2, n0, top, i - 1); + bn_scatter5(tmp.d, top, powerbuf, i); + } + + bits--; + for (wvalue = 0, i = bits % 5; i >= 0; i--, bits--) { + wvalue = (wvalue << 1) + BN_is_bit_set(p, bits); + } + bn_gather5(tmp.d, top, powerbuf, wvalue); + + /* At this point |bits| is 4 mod 5 and at least -1. (|bits| is the first bit + * that has not been read yet.) */ + assert(bits >= -1 && (bits == -1 || bits % 5 == 4)); + + /* Scan the exponent one window at a time starting from the most + * significant bits. + */ + if (top & 7) { + while (bits >= 0) { + for (wvalue = 0, i = 0; i < 5; i++, bits--) { + wvalue = (wvalue << 1) + BN_is_bit_set(p, bits); + } + + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_mul_mont(tmp.d, tmp.d, tmp.d, np, n0, top); + bn_mul_mont_gather5(tmp.d, tmp.d, powerbuf, np, n0, top, wvalue); + } + } else { + const uint8_t *p_bytes = (const uint8_t *)p->d; + int max_bits = p->top * BN_BITS2; + assert(bits < max_bits); + /* |p = 0| has been handled as a special case, so |max_bits| is at least + * one word. */ + assert(max_bits >= 64); + + /* If the first bit to be read lands in the last byte, unroll the first + * iteration to avoid reading past the bounds of |p->d|. (After the first + * iteration, we are guaranteed to be past the last byte.) Note |bits| + * here is the top bit, inclusive. */ + if (bits - 4 >= max_bits - 8) { + /* Read five bits from |bits-4| through |bits|, inclusive. */ + wvalue = p_bytes[p->top * BN_BYTES - 1]; + wvalue >>= (bits - 4) & 7; + wvalue &= 0x1f; + bits -= 5; + bn_power5(tmp.d, tmp.d, powerbuf, np2, n0, top, wvalue); + } + while (bits >= 0) { + /* Read five bits from |bits-4| through |bits|, inclusive. */ + int first_bit = bits - 4; + wvalue = *(const uint16_t *) (p_bytes + (first_bit >> 3)); + wvalue >>= first_bit & 7; + wvalue &= 0x1f; + bits -= 5; + bn_power5(tmp.d, tmp.d, powerbuf, np2, n0, top, wvalue); + } + } + + ret = bn_from_montgomery(tmp.d, tmp.d, NULL, np2, n0, top); + tmp.top = top; + bn_correct_top(&tmp); + if (ret) { + if (!BN_copy(rr, &tmp)) { + ret = 0; + } + goto err; /* non-zero ret means it's not error */ + } + } else +#endif + { + if (!copy_to_prebuf(&tmp, top, powerbuf, 0, numPowers) || + !copy_to_prebuf(&am, top, powerbuf, 1, numPowers)) { + goto err; + } + + /* If the window size is greater than 1, then calculate + * val[i=2..2^winsize-1]. Powers are computed as a*a^(i-1) + * (even powers could instead be computed as (a^(i/2))^2 + * to use the slight performance advantage of sqr over mul). + */ + if (window > 1) { + if (!BN_mod_mul_montgomery(&tmp, &am, &am, mont, ctx) || + !copy_to_prebuf(&tmp, top, powerbuf, 2, numPowers)) { + goto err; + } + for (i = 3; i < numPowers; i++) { + /* Calculate a^i = a^(i-1) * a */ + if (!BN_mod_mul_montgomery(&tmp, &am, &tmp, mont, ctx) || + !copy_to_prebuf(&tmp, top, powerbuf, i, numPowers)) { + goto err; + } + } + } + + bits--; + for (wvalue = 0, i = bits % window; i >= 0; i--, bits--) { + wvalue = (wvalue << 1) + BN_is_bit_set(p, bits); + } + if (!copy_from_prebuf(&tmp, top, powerbuf, wvalue, numPowers)) { + goto err; + } + + /* Scan the exponent one window at a time starting from the most + * significant bits. + */ + while (bits >= 0) { + wvalue = 0; /* The 'value' of the window */ + + /* Scan the window, squaring the result as we go */ + for (i = 0; i < window; i++, bits--) { + if (!BN_mod_mul_montgomery(&tmp, &tmp, &tmp, mont, ctx)) { + goto err; + } + wvalue = (wvalue << 1) + BN_is_bit_set(p, bits); + } + + /* Fetch the appropriate pre-computed value from the pre-buf */ + if (!copy_from_prebuf(&am, top, powerbuf, wvalue, numPowers)) { + goto err; + } + + /* Multiply the result into the intermediate result */ + if (!BN_mod_mul_montgomery(&tmp, &tmp, &am, mont, ctx)) { + goto err; + } + } + } + + /* Convert the final result from montgomery to standard format */ + if (!BN_from_montgomery(rr, &tmp, mont, ctx)) { + goto err; + } + ret = 1; +err: + if (in_mont == NULL) { + BN_MONT_CTX_free(mont); + } + if (powerbuf != NULL) { + OPENSSL_cleanse(powerbuf, powerbufLen); + OPENSSL_free(powerbufFree); + } + BN_CTX_end(ctx); + return (ret); +} + +int BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont) { + BN_MONT_CTX *mont = NULL; + int b, bits, ret = 0; + int r_is_one; + BN_ULONG w, next_w; + BIGNUM *d, *r, *t; + BIGNUM *swap_tmp; +#define BN_MOD_MUL_WORD(r, w, m) \ + (BN_mul_word(r, (w)) && \ + (/* BN_ucmp(r, (m)) < 0 ? 1 :*/ \ + (BN_mod(t, r, m, ctx) && (swap_tmp = r, r = t, t = swap_tmp, 1)))) + /* BN_MOD_MUL_WORD is only used with 'w' large, so the BN_ucmp test is + * probably more overhead than always using BN_mod (which uses BN_copy if a + * similar test returns true). We can use BN_mod and do not need BN_nnmod + * because our accumulator is never negative (the result of BN_mod does not + * depend on the sign of the modulus). */ +#define BN_TO_MONTGOMERY_WORD(r, w, mont) \ + (BN_set_word(r, (w)) && BN_to_montgomery(r, r, (mont), ctx)) + + if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) { + /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */ + OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + if (!BN_is_odd(m)) { + OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); + return 0; + } + + if (m->top == 1) { + a %= m->d[0]; /* make sure that 'a' is reduced */ + } + + bits = BN_num_bits(p); + if (bits == 0) { + /* x**0 mod 1 is still zero. */ + if (BN_is_one(m)) { + ret = 1; + BN_zero(rr); + } else { + ret = BN_one(rr); + } + return ret; + } + if (a == 0) { + BN_zero(rr); + ret = 1; + return ret; + } + + BN_CTX_start(ctx); + d = BN_CTX_get(ctx); + r = BN_CTX_get(ctx); + t = BN_CTX_get(ctx); + if (d == NULL || r == NULL || t == NULL) { + goto err; + } + + if (in_mont != NULL) { + mont = in_mont; + } else { + mont = BN_MONT_CTX_new(); + if (mont == NULL || !BN_MONT_CTX_set(mont, m, ctx)) { + goto err; + } + } + + r_is_one = 1; /* except for Montgomery factor */ + + /* bits-1 >= 0 */ + + /* The result is accumulated in the product r*w. */ + w = a; /* bit 'bits-1' of 'p' is always set */ + for (b = bits - 2; b >= 0; b--) { + /* First, square r*w. */ + next_w = w * w; + if ((next_w / w) != w) { + /* overflow */ + if (r_is_one) { + if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) { + goto err; + } + r_is_one = 0; + } else { + if (!BN_MOD_MUL_WORD(r, w, m)) { + goto err; + } + } + next_w = 1; + } + + w = next_w; + if (!r_is_one) { + if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) { + goto err; + } + } + + /* Second, multiply r*w by 'a' if exponent bit is set. */ + if (BN_is_bit_set(p, b)) { + next_w = w * a; + if ((next_w / a) != w) { + /* overflow */ + if (r_is_one) { + if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) { + goto err; + } + r_is_one = 0; + } else { + if (!BN_MOD_MUL_WORD(r, w, m)) { + goto err; + } + } + next_w = a; + } + w = next_w; + } + } + + /* Finally, set r:=r*w. */ + if (w != 1) { + if (r_is_one) { + if (!BN_TO_MONTGOMERY_WORD(r, w, mont)) { + goto err; + } + r_is_one = 0; + } else { + if (!BN_MOD_MUL_WORD(r, w, m)) { + goto err; + } + } + } + + if (r_is_one) { + /* can happen only if a == 1*/ + if (!BN_one(rr)) { + goto err; + } + } else { + if (!BN_from_montgomery(rr, r, mont, ctx)) { + goto err; + } + } + ret = 1; + +err: + if (in_mont == NULL) { + BN_MONT_CTX_free(mont); + } + BN_CTX_end(ctx); + return ret; +} + +#define TABLE_SIZE 32 + +int BN_mod_exp2_mont(BIGNUM *rr, const BIGNUM *a1, const BIGNUM *p1, + const BIGNUM *a2, const BIGNUM *p2, const BIGNUM *m, + BN_CTX *ctx, BN_MONT_CTX *in_mont) { + int i, j, bits, b, bits1, bits2, ret = 0, wpos1, wpos2, window1, window2, + wvalue1, wvalue2; + int r_is_one = 1; + BIGNUM *d, *r; + const BIGNUM *a_mod_m; + /* Tables of variables obtained from 'ctx' */ + BIGNUM *val1[TABLE_SIZE], *val2[TABLE_SIZE]; + BN_MONT_CTX *mont = NULL; + + if (!(m->d[0] & 1)) { + OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS); + return 0; + } + bits1 = BN_num_bits(p1); + bits2 = BN_num_bits(p2); + if (bits1 == 0 && bits2 == 0) { + ret = BN_one(rr); + return ret; + } + + bits = (bits1 > bits2) ? bits1 : bits2; + + BN_CTX_start(ctx); + d = BN_CTX_get(ctx); + r = BN_CTX_get(ctx); + val1[0] = BN_CTX_get(ctx); + val2[0] = BN_CTX_get(ctx); + if (!d || !r || !val1[0] || !val2[0]) { + goto err; + } + + if (in_mont != NULL) { + mont = in_mont; + } else { + mont = BN_MONT_CTX_new(); + if (mont == NULL) { + goto err; + } + if (!BN_MONT_CTX_set(mont, m, ctx)) { + goto err; + } + } + + window1 = BN_window_bits_for_exponent_size(bits1); + window2 = BN_window_bits_for_exponent_size(bits2); + + /* Build table for a1: val1[i] := a1^(2*i + 1) mod m for i = 0 .. + * 2^(window1-1) */ + if (a1->neg || BN_ucmp(a1, m) >= 0) { + if (!BN_mod(val1[0], a1, m, ctx)) { + goto err; + } + a_mod_m = val1[0]; + } else { + a_mod_m = a1; + } + + if (BN_is_zero(a_mod_m)) { + BN_zero(rr); + ret = 1; + goto err; + } + + if (!BN_to_montgomery(val1[0], a_mod_m, mont, ctx)) { + goto err; + } + + if (window1 > 1) { + if (!BN_mod_mul_montgomery(d, val1[0], val1[0], mont, ctx)) { + goto err; + } + + j = 1 << (window1 - 1); + for (i = 1; i < j; i++) { + if (((val1[i] = BN_CTX_get(ctx)) == NULL) || + !BN_mod_mul_montgomery(val1[i], val1[i - 1], d, mont, ctx)) { + goto err; + } + } + } + + /* Build table for a2: val2[i] := a2^(2*i + 1) mod m for i = 0 .. + * 2^(window2-1) */ + if (a2->neg || BN_ucmp(a2, m) >= 0) { + if (!BN_mod(val2[0], a2, m, ctx)) { + goto err; + } + a_mod_m = val2[0]; + } else { + a_mod_m = a2; + } + + if (BN_is_zero(a_mod_m)) { + BN_zero(rr); + ret = 1; + goto err; + } + + if (!BN_to_montgomery(val2[0], a_mod_m, mont, ctx)) { + goto err; + } + + if (window2 > 1) { + if (!BN_mod_mul_montgomery(d, val2[0], val2[0], mont, ctx)) { + goto err; + } + + j = 1 << (window2 - 1); + for (i = 1; i < j; i++) { + if (((val2[i] = BN_CTX_get(ctx)) == NULL) || + !BN_mod_mul_montgomery(val2[i], val2[i - 1], d, mont, ctx)) { + goto err; + } + } + } + + /* Now compute the power product, using independent windows. */ + r_is_one = 1; + wvalue1 = 0; /* The 'value' of the first window */ + wvalue2 = 0; /* The 'value' of the second window */ + wpos1 = 0; /* If wvalue1 > 0, the bottom bit of the first window */ + wpos2 = 0; /* If wvalue2 > 0, the bottom bit of the second window */ + + if (!BN_to_montgomery(r, BN_value_one(), mont, ctx)) { + goto err; + } + + for (b = bits - 1; b >= 0; b--) { + if (!r_is_one) { + if (!BN_mod_mul_montgomery(r, r, r, mont, ctx)) { + goto err; + } + } + + if (!wvalue1 && BN_is_bit_set(p1, b)) { + /* consider bits b-window1+1 .. b for this window */ + i = b - window1 + 1; + /* works for i<0 */ + while (!BN_is_bit_set(p1, i)) { + i++; + } + wpos1 = i; + wvalue1 = 1; + for (i = b - 1; i >= wpos1; i--) { + wvalue1 <<= 1; + if (BN_is_bit_set(p1, i)) { + wvalue1++; + } + } + } + + if (!wvalue2 && BN_is_bit_set(p2, b)) { + /* consider bits b-window2+1 .. b for this window */ + i = b - window2 + 1; + while (!BN_is_bit_set(p2, i)) { + i++; + } + wpos2 = i; + wvalue2 = 1; + for (i = b - 1; i >= wpos2; i--) { + wvalue2 <<= 1; + if (BN_is_bit_set(p2, i)) { + wvalue2++; + } + } + } + + if (wvalue1 && b == wpos1) { + /* wvalue1 is odd and < 2^window1 */ + if (!BN_mod_mul_montgomery(r, r, val1[wvalue1 >> 1], mont, ctx)) { + goto err; + } + wvalue1 = 0; + r_is_one = 0; + } + + if (wvalue2 && b == wpos2) { + /* wvalue2 is odd and < 2^window2 */ + if (!BN_mod_mul_montgomery(r, r, val2[wvalue2 >> 1], mont, ctx)) { + goto err; + } + wvalue2 = 0; + r_is_one = 0; + } + } + + if (!BN_from_montgomery(rr, r, mont, ctx)) { + goto err; + } + ret = 1; + +err: + if (in_mont == NULL) { + BN_MONT_CTX_free(mont); + } + BN_CTX_end(ctx); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/gcd.c b/TMessagesProj/jni/boringssl/crypto/bn/gcd.c new file mode 100644 index 00000000..c33a3cd5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/gcd.c @@ -0,0 +1,697 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include "internal.h" + +static BIGNUM *euclid(BIGNUM *a, BIGNUM *b) { + BIGNUM *t; + int shifts = 0; + + /* 0 <= b <= a */ + while (!BN_is_zero(b)) { + /* 0 < b <= a */ + + if (BN_is_odd(a)) { + if (BN_is_odd(b)) { + if (!BN_sub(a, a, b)) { + goto err; + } + if (!BN_rshift1(a, a)) { + goto err; + } + if (BN_cmp(a, b) < 0) { + t = a; + a = b; + b = t; + } + } else { + /* a odd - b even */ + if (!BN_rshift1(b, b)) { + goto err; + } + if (BN_cmp(a, b) < 0) { + t = a; + a = b; + b = t; + } + } + } else { + /* a is even */ + if (BN_is_odd(b)) { + if (!BN_rshift1(a, a)) { + goto err; + } + if (BN_cmp(a, b) < 0) { + t = a; + a = b; + b = t; + } + } else { + /* a even - b even */ + if (!BN_rshift1(a, a)) { + goto err; + } + if (!BN_rshift1(b, b)) { + goto err; + } + shifts++; + } + } + /* 0 <= b <= a */ + } + + if (shifts) { + if (!BN_lshift(a, a, shifts)) { + goto err; + } + } + + return a; + +err: + return NULL; +} + +int BN_gcd(BIGNUM *r, const BIGNUM *in_a, const BIGNUM *in_b, BN_CTX *ctx) { + BIGNUM *a, *b, *t; + int ret = 0; + + BN_CTX_start(ctx); + a = BN_CTX_get(ctx); + b = BN_CTX_get(ctx); + + if (a == NULL || b == NULL) { + goto err; + } + if (BN_copy(a, in_a) == NULL) { + goto err; + } + if (BN_copy(b, in_b) == NULL) { + goto err; + } + + a->neg = 0; + b->neg = 0; + + if (BN_cmp(a, b) < 0) { + t = a; + a = b; + b = t; + } + t = euclid(a, b); + if (t == NULL) { + goto err; + } + + if (BN_copy(r, t) == NULL) { + goto err; + } + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +/* solves ax == 1 (mod n) */ +static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, const BIGNUM *a, + const BIGNUM *n, BN_CTX *ctx); + +BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, const BIGNUM *n, + BN_CTX *ctx) { + BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL; + BIGNUM *ret = NULL; + int sign; + + if ((a->flags & BN_FLG_CONSTTIME) != 0 || + (n->flags & BN_FLG_CONSTTIME) != 0) { + return BN_mod_inverse_no_branch(out, a, n, ctx); + } + + BN_CTX_start(ctx); + A = BN_CTX_get(ctx); + B = BN_CTX_get(ctx); + X = BN_CTX_get(ctx); + D = BN_CTX_get(ctx); + M = BN_CTX_get(ctx); + Y = BN_CTX_get(ctx); + T = BN_CTX_get(ctx); + if (T == NULL) { + goto err; + } + + if (out == NULL) { + R = BN_new(); + } else { + R = out; + } + if (R == NULL) { + goto err; + } + + BN_zero(Y); + if (!BN_one(X) || BN_copy(B, a) == NULL || BN_copy(A, n) == NULL) { + goto err; + } + A->neg = 0; + if (B->neg || (BN_ucmp(B, A) >= 0)) { + if (!BN_nnmod(B, B, A, ctx)) { + goto err; + } + } + sign = -1; + /* From B = a mod |n|, A = |n| it follows that + * + * 0 <= B < A, + * -sign*X*a == B (mod |n|), + * sign*Y*a == A (mod |n|). + */ + + if (BN_is_odd(n) && (BN_num_bits(n) <= (BN_BITS <= 32 ? 450 : 2048))) { + /* Binary inversion algorithm; requires odd modulus. + * This is faster than the general algorithm if the modulus + * is sufficiently small (about 400 .. 500 bits on 32-bit + * sytems, but much more on 64-bit systems) */ + int shift; + + while (!BN_is_zero(B)) { + /* 0 < B < |n|, + * 0 < A <= |n|, + * (1) -sign*X*a == B (mod |n|), + * (2) sign*Y*a == A (mod |n|) */ + + /* Now divide B by the maximum possible power of two in the integers, + * and divide X by the same value mod |n|. + * When we're done, (1) still holds. */ + shift = 0; + while (!BN_is_bit_set(B, shift)) { + /* note that 0 < B */ + shift++; + + if (BN_is_odd(X)) { + if (!BN_uadd(X, X, n)) { + goto err; + } + } + /* now X is even, so we can easily divide it by two */ + if (!BN_rshift1(X, X)) { + goto err; + } + } + if (shift > 0) { + if (!BN_rshift(B, B, shift)) { + goto err; + } + } + + /* Same for A and Y. Afterwards, (2) still holds. */ + shift = 0; + while (!BN_is_bit_set(A, shift)) { + /* note that 0 < A */ + shift++; + + if (BN_is_odd(Y)) { + if (!BN_uadd(Y, Y, n)) { + goto err; + } + } + /* now Y is even */ + if (!BN_rshift1(Y, Y)) { + goto err; + } + } + if (shift > 0) { + if (!BN_rshift(A, A, shift)) { + goto err; + } + } + + /* We still have (1) and (2). + * Both A and B are odd. + * The following computations ensure that + * + * 0 <= B < |n|, + * 0 < A < |n|, + * (1) -sign*X*a == B (mod |n|), + * (2) sign*Y*a == A (mod |n|), + * + * and that either A or B is even in the next iteration. */ + if (BN_ucmp(B, A) >= 0) { + /* -sign*(X + Y)*a == B - A (mod |n|) */ + if (!BN_uadd(X, X, Y)) { + goto err; + } + /* NB: we could use BN_mod_add_quick(X, X, Y, n), but that + * actually makes the algorithm slower */ + if (!BN_usub(B, B, A)) { + goto err; + } + } else { + /* sign*(X + Y)*a == A - B (mod |n|) */ + if (!BN_uadd(Y, Y, X)) { + goto err; + } + /* as above, BN_mod_add_quick(Y, Y, X, n) would slow things down */ + if (!BN_usub(A, A, B)) { + goto err; + } + } + } + } else { + /* general inversion algorithm */ + + while (!BN_is_zero(B)) { + BIGNUM *tmp; + + /* + * 0 < B < A, + * (*) -sign*X*a == B (mod |n|), + * sign*Y*a == A (mod |n|) */ + + /* (D, M) := (A/B, A%B) ... */ + if (BN_num_bits(A) == BN_num_bits(B)) { + if (!BN_one(D)) { + goto err; + } + if (!BN_sub(M, A, B)) { + goto err; + } + } else if (BN_num_bits(A) == BN_num_bits(B) + 1) { + /* A/B is 1, 2, or 3 */ + if (!BN_lshift1(T, B)) { + goto err; + } + if (BN_ucmp(A, T) < 0) { + /* A < 2*B, so D=1 */ + if (!BN_one(D)) { + goto err; + } + if (!BN_sub(M, A, B)) { + goto err; + } + } else { + /* A >= 2*B, so D=2 or D=3 */ + if (!BN_sub(M, A, T)) { + goto err; + } + if (!BN_add(D, T, B)) { + goto err; /* use D (:= 3*B) as temp */ + } + if (BN_ucmp(A, D) < 0) { + /* A < 3*B, so D=2 */ + if (!BN_set_word(D, 2)) { + goto err; + } + /* M (= A - 2*B) already has the correct value */ + } else { + /* only D=3 remains */ + if (!BN_set_word(D, 3)) { + goto err; + } + /* currently M = A - 2*B, but we need M = A - 3*B */ + if (!BN_sub(M, M, B)) { + goto err; + } + } + } + } else { + if (!BN_div(D, M, A, B, ctx)) { + goto err; + } + } + + /* Now + * A = D*B + M; + * thus we have + * (**) sign*Y*a == D*B + M (mod |n|). */ + + tmp = A; /* keep the BIGNUM object, the value does not matter */ + + /* (A, B) := (B, A mod B) ... */ + A = B; + B = M; + /* ... so we have 0 <= B < A again */ + + /* Since the former M is now B and the former B is now A, + * (**) translates into + * sign*Y*a == D*A + B (mod |n|), + * i.e. + * sign*Y*a - D*A == B (mod |n|). + * Similarly, (*) translates into + * -sign*X*a == A (mod |n|). + * + * Thus, + * sign*Y*a + D*sign*X*a == B (mod |n|), + * i.e. + * sign*(Y + D*X)*a == B (mod |n|). + * + * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at + * -sign*X*a == B (mod |n|), + * sign*Y*a == A (mod |n|). + * Note that X and Y stay non-negative all the time. */ + + /* most of the time D is very small, so we can optimize tmp := D*X+Y */ + if (BN_is_one(D)) { + if (!BN_add(tmp, X, Y)) { + goto err; + } + } else { + if (BN_is_word(D, 2)) { + if (!BN_lshift1(tmp, X)) { + goto err; + } + } else if (BN_is_word(D, 4)) { + if (!BN_lshift(tmp, X, 2)) { + goto err; + } + } else if (D->top == 1) { + if (!BN_copy(tmp, X)) { + goto err; + } + if (!BN_mul_word(tmp, D->d[0])) { + goto err; + } + } else { + if (!BN_mul(tmp, D, X, ctx)) { + goto err; + } + } + if (!BN_add(tmp, tmp, Y)) { + goto err; + } + } + + M = Y; /* keep the BIGNUM object, the value does not matter */ + Y = X; + X = tmp; + sign = -sign; + } + } + + /* The while loop (Euclid's algorithm) ends when + * A == gcd(a,n); + * we have + * sign*Y*a == A (mod |n|), + * where Y is non-negative. */ + + if (sign < 0) { + if (!BN_sub(Y, n, Y)) { + goto err; + } + } + /* Now Y*a == A (mod |n|). */ + + if (BN_is_one(A)) { + /* Y*a == 1 (mod |n|) */ + if (!Y->neg && BN_ucmp(Y, n) < 0) { + if (!BN_copy(R, Y)) { + goto err; + } + } else { + if (!BN_nnmod(R, Y, n, ctx)) { + goto err; + } + } + } else { + OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE); + goto err; + } + ret = R; + +err: + if (ret == NULL && out == NULL) { + BN_free(R); + } + BN_CTX_end(ctx); + return ret; +} + +/* BN_mod_inverse_no_branch is a special version of BN_mod_inverse. + * It does not contain branches that may leak sensitive information. */ +static BIGNUM *BN_mod_inverse_no_branch(BIGNUM *out, const BIGNUM *a, + const BIGNUM *n, BN_CTX *ctx) { + BIGNUM *A, *B, *X, *Y, *M, *D, *T, *R = NULL; + BIGNUM local_A, local_B; + BIGNUM *pA, *pB; + BIGNUM *ret = NULL; + int sign; + + BN_CTX_start(ctx); + A = BN_CTX_get(ctx); + B = BN_CTX_get(ctx); + X = BN_CTX_get(ctx); + D = BN_CTX_get(ctx); + M = BN_CTX_get(ctx); + Y = BN_CTX_get(ctx); + T = BN_CTX_get(ctx); + if (T == NULL) { + goto err; + } + + if (out == NULL) { + R = BN_new(); + } else { + R = out; + } + if (R == NULL) { + goto err; + } + + BN_zero(Y); + if (!BN_one(X) || BN_copy(B, a) == NULL || BN_copy(A, n) == NULL) { + goto err; + } + A->neg = 0; + + if (B->neg || (BN_ucmp(B, A) >= 0)) { + /* Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked, + * BN_div_no_branch will be called eventually. + */ + pB = &local_B; + BN_with_flags(pB, B, BN_FLG_CONSTTIME); + if (!BN_nnmod(B, pB, A, ctx)) { + goto err; + } + } + sign = -1; + /* From B = a mod |n|, A = |n| it follows that + * + * 0 <= B < A, + * -sign*X*a == B (mod |n|), + * sign*Y*a == A (mod |n|). + */ + + while (!BN_is_zero(B)) { + BIGNUM *tmp; + + /* + * 0 < B < A, + * (*) -sign*X*a == B (mod |n|), + * sign*Y*a == A (mod |n|) + */ + + /* Turn BN_FLG_CONSTTIME flag on, so that when BN_div is invoked, + * BN_div_no_branch will be called eventually. + */ + pA = &local_A; + BN_with_flags(pA, A, BN_FLG_CONSTTIME); + + /* (D, M) := (A/B, A%B) ... */ + if (!BN_div(D, M, pA, B, ctx)) { + goto err; + } + + /* Now + * A = D*B + M; + * thus we have + * (**) sign*Y*a == D*B + M (mod |n|). + */ + + tmp = A; /* keep the BIGNUM object, the value does not matter */ + + /* (A, B) := (B, A mod B) ... */ + A = B; + B = M; + /* ... so we have 0 <= B < A again */ + + /* Since the former M is now B and the former B is now A, + * (**) translates into + * sign*Y*a == D*A + B (mod |n|), + * i.e. + * sign*Y*a - D*A == B (mod |n|). + * Similarly, (*) translates into + * -sign*X*a == A (mod |n|). + * + * Thus, + * sign*Y*a + D*sign*X*a == B (mod |n|), + * i.e. + * sign*(Y + D*X)*a == B (mod |n|). + * + * So if we set (X, Y, sign) := (Y + D*X, X, -sign), we arrive back at + * -sign*X*a == B (mod |n|), + * sign*Y*a == A (mod |n|). + * Note that X and Y stay non-negative all the time. + */ + + if (!BN_mul(tmp, D, X, ctx)) { + goto err; + } + if (!BN_add(tmp, tmp, Y)) { + goto err; + } + + M = Y; /* keep the BIGNUM object, the value does not matter */ + Y = X; + X = tmp; + sign = -sign; + } + + /* + * The while loop (Euclid's algorithm) ends when + * A == gcd(a,n); + * we have + * sign*Y*a == A (mod |n|), + * where Y is non-negative. + */ + + if (sign < 0) { + if (!BN_sub(Y, n, Y)) { + goto err; + } + } + /* Now Y*a == A (mod |n|). */ + + if (BN_is_one(A)) { + /* Y*a == 1 (mod |n|) */ + if (!Y->neg && BN_ucmp(Y, n) < 0) { + if (!BN_copy(R, Y)) { + goto err; + } + } else { + if (!BN_nnmod(R, Y, n, ctx)) { + goto err; + } + } + } else { + OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE); + goto err; + } + ret = R; + +err: + if (ret == NULL && out == NULL) { + BN_free(R); + } + + BN_CTX_end(ctx); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/generic.c b/TMessagesProj/jni/boringssl/crypto/bn/generic.c new file mode 100644 index 00000000..0e7d867c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/generic.c @@ -0,0 +1,1131 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include "internal.h" + + +/* Generic implementations of most operations are needed for: + * - Configurations without inline assembly. + * - Architectures other than x86 or x86_64. + * - Windows x84_64; x86_64-gcc.c does not build on MSVC. */ +#if defined(OPENSSL_NO_ASM) || \ + (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) || \ + (defined(OPENSSL_X86_64) && defined(OPENSSL_WINDOWS)) + +#if defined(OPENSSL_WINDOWS) +#define alloca _alloca +#else +#include +#endif + +#ifdef BN_LLONG +#define mul_add(r, a, w, c) \ + { \ + BN_ULLONG t; \ + t = (BN_ULLONG)w * (a) + (r) + (c); \ + (r) = Lw(t); \ + (c) = Hw(t); \ + } + +#define mul(r, a, w, c) \ + { \ + BN_ULLONG t; \ + t = (BN_ULLONG)w * (a) + (c); \ + (r) = Lw(t); \ + (c) = Hw(t); \ + } + +#define sqr(r0, r1, a) \ + { \ + BN_ULLONG t; \ + t = (BN_ULLONG)(a) * (a); \ + (r0) = Lw(t); \ + (r1) = Hw(t); \ + } + +#elif defined(BN_UMULT_LOHI) +#define mul_add(r, a, w, c) \ + { \ + BN_ULONG high, low, ret, tmp = (a); \ + ret = (r); \ + BN_UMULT_LOHI(low, high, w, tmp); \ + ret += (c); \ + (c) = (ret < (c)) ? 1 : 0; \ + (c) += high; \ + ret += low; \ + (c) += (ret < low) ? 1 : 0; \ + (r) = ret; \ + } + +#define mul(r, a, w, c) \ + { \ + BN_ULONG high, low, ret, ta = (a); \ + BN_UMULT_LOHI(low, high, w, ta); \ + ret = low + (c); \ + (c) = high; \ + (c) += (ret < low) ? 1 : 0; \ + (r) = ret; \ + } + +#define sqr(r0, r1, a) \ + { \ + BN_ULONG tmp = (a); \ + BN_UMULT_LOHI(r0, r1, tmp, tmp); \ + } + +#else + +/************************************************************* + * No long long type + */ + +#define LBITS(a) ((a) & BN_MASK2l) +#define HBITS(a) (((a) >> BN_BITS4) & BN_MASK2l) +#define L2HBITS(a) (((a) << BN_BITS4) & BN_MASK2) + +#define LLBITS(a) ((a) & BN_MASKl) +#define LHBITS(a) (((a) >> BN_BITS2) & BN_MASKl) +#define LL2HBITS(a) ((BN_ULLONG)((a) & BN_MASKl) << BN_BITS2) + +#define mul64(l, h, bl, bh) \ + { \ + BN_ULONG m, m1, lt, ht; \ + \ + lt = l; \ + ht = h; \ + m = (bh) * (lt); \ + lt = (bl) * (lt); \ + m1 = (bl) * (ht); \ + ht = (bh) * (ht); \ + m = (m + m1) & BN_MASK2; \ + if (m < m1) \ + ht += L2HBITS((BN_ULONG)1); \ + ht += HBITS(m); \ + m1 = L2HBITS(m); \ + lt = (lt + m1) & BN_MASK2; \ + if (lt < m1) \ + ht++; \ + (l) = lt; \ + (h) = ht; \ + } + +#define sqr64(lo, ho, in) \ + { \ + BN_ULONG l, h, m; \ + \ + h = (in); \ + l = LBITS(h); \ + h = HBITS(h); \ + m = (l) * (h); \ + l *= l; \ + h *= h; \ + h += (m & BN_MASK2h1) >> (BN_BITS4 - 1); \ + m = (m & BN_MASK2l) << (BN_BITS4 + 1); \ + l = (l + m) & BN_MASK2; \ + if (l < m) \ + h++; \ + (lo) = l; \ + (ho) = h; \ + } + +#define mul_add(r, a, bl, bh, c) \ + { \ + BN_ULONG l, h; \ + \ + h = (a); \ + l = LBITS(h); \ + h = HBITS(h); \ + mul64(l, h, (bl), (bh)); \ + \ + /* non-multiply part */ \ + l = (l + (c)) & BN_MASK2; \ + if (l < (c)) \ + h++; \ + (c) = (r); \ + l = (l + (c)) & BN_MASK2; \ + if (l < (c)) \ + h++; \ + (c) = h & BN_MASK2; \ + (r) = l; \ + } + +#define mul(r, a, bl, bh, c) \ + { \ + BN_ULONG l, h; \ + \ + h = (a); \ + l = LBITS(h); \ + h = HBITS(h); \ + mul64(l, h, (bl), (bh)); \ + \ + /* non-multiply part */ \ + l += (c); \ + if ((l & BN_MASK2) < (c)) \ + h++; \ + (c) = h & BN_MASK2; \ + (r) = l & BN_MASK2; \ + } +#endif /* !BN_LLONG */ + +#if defined(BN_LLONG) || defined(BN_UMULT_HIGH) + +BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, + BN_ULONG w) { + BN_ULONG c1 = 0; + + assert(num >= 0); + if (num <= 0) { + return c1; + } + + while (num & ~3) { + mul_add(rp[0], ap[0], w, c1); + mul_add(rp[1], ap[1], w, c1); + mul_add(rp[2], ap[2], w, c1); + mul_add(rp[3], ap[3], w, c1); + ap += 4; + rp += 4; + num -= 4; + } + + while (num) { + mul_add(rp[0], ap[0], w, c1); + ap++; + rp++; + num--; + } + + return c1; +} + +BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w) { + BN_ULONG c1 = 0; + + assert(num >= 0); + if (num <= 0) { + return c1; + } + + while (num & ~3) { + mul(rp[0], ap[0], w, c1); + mul(rp[1], ap[1], w, c1); + mul(rp[2], ap[2], w, c1); + mul(rp[3], ap[3], w, c1); + ap += 4; + rp += 4; + num -= 4; + } + while (num) { + mul(rp[0], ap[0], w, c1); + ap++; + rp++; + num--; + } + return c1; +} + +void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) { + assert(n >= 0); + if (n <= 0) { + return; + } + + while (n & ~3) { + sqr(r[0], r[1], a[0]); + sqr(r[2], r[3], a[1]); + sqr(r[4], r[5], a[2]); + sqr(r[6], r[7], a[3]); + a += 4; + r += 8; + n -= 4; + } + while (n) { + sqr(r[0], r[1], a[0]); + a++; + r += 2; + n--; + } +} + +#else /* !(defined(BN_LLONG) || defined(BN_UMULT_HIGH)) */ + +BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, + BN_ULONG w) { + BN_ULONG c = 0; + BN_ULONG bl, bh; + + assert(num >= 0); + if (num <= 0) { + return (BN_ULONG)0; + } + + bl = LBITS(w); + bh = HBITS(w); + + while (num & ~3) { + mul_add(rp[0], ap[0], bl, bh, c); + mul_add(rp[1], ap[1], bl, bh, c); + mul_add(rp[2], ap[2], bl, bh, c); + mul_add(rp[3], ap[3], bl, bh, c); + ap += 4; + rp += 4; + num -= 4; + } + while (num) { + mul_add(rp[0], ap[0], bl, bh, c); + ap++; + rp++; + num--; + } + return c; +} + +BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w) { + BN_ULONG carry = 0; + BN_ULONG bl, bh; + + assert(num >= 0); + if (num <= 0) { + return (BN_ULONG)0; + } + + bl = LBITS(w); + bh = HBITS(w); + + while (num & ~3) { + mul(rp[0], ap[0], bl, bh, carry); + mul(rp[1], ap[1], bl, bh, carry); + mul(rp[2], ap[2], bl, bh, carry); + mul(rp[3], ap[3], bl, bh, carry); + ap += 4; + rp += 4; + num -= 4; + } + while (num) { + mul(rp[0], ap[0], bl, bh, carry); + ap++; + rp++; + num--; + } + return carry; +} + +void bn_sqr_words(BN_ULONG *r, const BN_ULONG *a, int n) { + assert(n >= 0); + if (n <= 0) { + return; + } + + while (n & ~3) { + sqr64(r[0], r[1], a[0]); + sqr64(r[2], r[3], a[1]); + sqr64(r[4], r[5], a[2]); + sqr64(r[6], r[7], a[3]); + a += 4; + r += 8; + n -= 4; + } + while (n) { + sqr64(r[0], r[1], a[0]); + a++; + r += 2; + n--; + } +} + +#endif /* !(defined(BN_LLONG) || defined(BN_UMULT_HIGH)) */ + +#if defined(BN_LLONG) + +BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) { + return (BN_ULONG)(((((BN_ULLONG)h) << BN_BITS2) | l) / (BN_ULLONG)d); +} + +#else + +/* Divide h,l by d and return the result. */ +BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) { + BN_ULONG dh, dl, q, ret = 0, th, tl, t; + int i, count = 2; + + if (d == 0) { + return BN_MASK2; + } + + i = BN_num_bits_word(d); + assert((i == BN_BITS2) || (h <= (BN_ULONG)1 << i)); + + i = BN_BITS2 - i; + if (h >= d) { + h -= d; + } + + if (i) { + d <<= i; + h = (h << i) | (l >> (BN_BITS2 - i)); + l <<= i; + } + dh = (d & BN_MASK2h) >> BN_BITS4; + dl = (d & BN_MASK2l); + for (;;) { + if ((h >> BN_BITS4) == dh) { + q = BN_MASK2l; + } else { + q = h / dh; + } + + th = q * dh; + tl = dl * q; + for (;;) { + t = h - th; + if ((t & BN_MASK2h) || + ((tl) <= ((t << BN_BITS4) | ((l & BN_MASK2h) >> BN_BITS4)))) { + break; + } + q--; + th -= dh; + tl -= dl; + } + t = (tl >> BN_BITS4); + tl = (tl << BN_BITS4) & BN_MASK2h; + th += t; + + if (l < tl) { + th++; + } + l -= tl; + if (h < th) { + h += d; + q--; + } + h -= th; + + if (--count == 0) { + break; + } + + ret = q << BN_BITS4; + h = ((h << BN_BITS4) | (l >> BN_BITS4)) & BN_MASK2; + l = (l & BN_MASK2l) << BN_BITS4; + } + + ret |= q; + return ret; +} + +#endif /* !defined(BN_LLONG) */ + +#ifdef BN_LLONG +BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, + int n) { + BN_ULLONG ll = 0; + + assert(n >= 0); + if (n <= 0) { + return (BN_ULONG)0; + } + + while (n & ~3) { + ll += (BN_ULLONG)a[0] + b[0]; + r[0] = (BN_ULONG)ll & BN_MASK2; + ll >>= BN_BITS2; + ll += (BN_ULLONG)a[1] + b[1]; + r[1] = (BN_ULONG)ll & BN_MASK2; + ll >>= BN_BITS2; + ll += (BN_ULLONG)a[2] + b[2]; + r[2] = (BN_ULONG)ll & BN_MASK2; + ll >>= BN_BITS2; + ll += (BN_ULLONG)a[3] + b[3]; + r[3] = (BN_ULONG)ll & BN_MASK2; + ll >>= BN_BITS2; + a += 4; + b += 4; + r += 4; + n -= 4; + } + while (n) { + ll += (BN_ULLONG)a[0] + b[0]; + r[0] = (BN_ULONG)ll & BN_MASK2; + ll >>= BN_BITS2; + a++; + b++; + r++; + n--; + } + return (BN_ULONG)ll; +} + +#else /* !BN_LLONG */ + +BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, + int n) { + BN_ULONG c, l, t; + + assert(n >= 0); + if (n <= 0) { + return (BN_ULONG)0; + } + + c = 0; + while (n & ~3) { + t = a[0]; + t = (t + c) & BN_MASK2; + c = (t < c); + l = (t + b[0]) & BN_MASK2; + c += (l < t); + r[0] = l; + t = a[1]; + t = (t + c) & BN_MASK2; + c = (t < c); + l = (t + b[1]) & BN_MASK2; + c += (l < t); + r[1] = l; + t = a[2]; + t = (t + c) & BN_MASK2; + c = (t < c); + l = (t + b[2]) & BN_MASK2; + c += (l < t); + r[2] = l; + t = a[3]; + t = (t + c) & BN_MASK2; + c = (t < c); + l = (t + b[3]) & BN_MASK2; + c += (l < t); + r[3] = l; + a += 4; + b += 4; + r += 4; + n -= 4; + } + while (n) { + t = a[0]; + t = (t + c) & BN_MASK2; + c = (t < c); + l = (t + b[0]) & BN_MASK2; + c += (l < t); + r[0] = l; + a++; + b++; + r++; + n--; + } + return (BN_ULONG)c; +} + +#endif /* !BN_LLONG */ + +BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, + int n) { + BN_ULONG t1, t2; + int c = 0; + + assert(n >= 0); + if (n <= 0) { + return (BN_ULONG)0; + } + + while (n & ~3) { + t1 = a[0]; + t2 = b[0]; + r[0] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + t1 = a[1]; + t2 = b[1]; + r[1] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + t1 = a[2]; + t2 = b[2]; + r[2] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + t1 = a[3]; + t2 = b[3]; + r[3] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + a += 4; + b += 4; + r += 4; + n -= 4; + } + while (n) { + t1 = a[0]; + t2 = b[0]; + r[0] = (t1 - t2 - c) & BN_MASK2; + if (t1 != t2) { + c = (t1 < t2); + } + a++; + b++; + r++; + n--; + } + return c; +} + +/* mul_add_c(a,b,c0,c1,c2) -- c+=a*b for three word number c=(c2,c1,c0) */ +/* mul_add_c2(a,b,c0,c1,c2) -- c+=2*a*b for three word number c=(c2,c1,c0) */ +/* sqr_add_c(a,i,c0,c1,c2) -- c+=a[i]^2 for three word number c=(c2,c1,c0) */ +/* sqr_add_c2(a,i,c0,c1,c2) -- c+=2*a[i]*a[j] for three word number c=(c2,c1,c0) */ + +#ifdef BN_LLONG + +/* Keep in mind that additions to multiplication result can not overflow, + * because its high half cannot be all-ones. */ +#define mul_add_c(a, b, c0, c1, c2) \ + do { \ + BN_ULONG hi; \ + BN_ULLONG t = (BN_ULLONG)(a) * (b); \ + t += c0; /* no carry */ \ + c0 = (BN_ULONG)Lw(t); \ + hi = (BN_ULONG)Hw(t); \ + c1 = (c1 + hi) & BN_MASK2; \ + if (c1 < hi) \ + c2++; \ + } while (0) + +#define mul_add_c2(a, b, c0, c1, c2) \ + do { \ + BN_ULONG hi; \ + BN_ULLONG t = (BN_ULLONG)(a) * (b); \ + BN_ULLONG tt = t + c0; /* no carry */ \ + c0 = (BN_ULONG)Lw(tt); \ + hi = (BN_ULONG)Hw(tt); \ + c1 = (c1 + hi) & BN_MASK2; \ + if (c1 < hi) \ + c2++; \ + t += c0; /* no carry */ \ + c0 = (BN_ULONG)Lw(t); \ + hi = (BN_ULONG)Hw(t); \ + c1 = (c1 + hi) & BN_MASK2; \ + if (c1 < hi) \ + c2++; \ + } while (0) + +#define sqr_add_c(a, i, c0, c1, c2) \ + do { \ + BN_ULONG hi; \ + BN_ULLONG t = (BN_ULLONG)a[i] * a[i]; \ + t += c0; /* no carry */ \ + c0 = (BN_ULONG)Lw(t); \ + hi = (BN_ULONG)Hw(t); \ + c1 = (c1 + hi) & BN_MASK2; \ + if (c1 < hi) \ + c2++; \ + } while (0) + +#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2) + +#elif defined(BN_UMULT_LOHI) + +/* Keep in mind that additions to hi can not overflow, because the high word of + * a multiplication result cannot be all-ones. */ +#define mul_add_c(a, b, c0, c1, c2) \ + do { \ + BN_ULONG ta = (a), tb = (b); \ + BN_ULONG lo, hi; \ + BN_UMULT_LOHI(lo, hi, ta, tb); \ + c0 += lo; \ + hi += (c0 < lo) ? 1 : 0; \ + c1 += hi; \ + c2 += (c1 < hi) ? 1 : 0; \ + } while (0) + +#define mul_add_c2(a, b, c0, c1, c2) \ + do { \ + BN_ULONG ta = (a), tb = (b); \ + BN_ULONG lo, hi, tt; \ + BN_UMULT_LOHI(lo, hi, ta, tb); \ + c0 += lo; \ + tt = hi + ((c0 < lo) ? 1 : 0); \ + c1 += tt; \ + c2 += (c1 < tt) ? 1 : 0; \ + c0 += lo; \ + hi += (c0 < lo) ? 1 : 0; \ + c1 += hi; \ + c2 += (c1 < hi) ? 1 : 0; \ + } while (0) + +#define sqr_add_c(a, i, c0, c1, c2) \ + do { \ + BN_ULONG ta = (a)[i]; \ + BN_ULONG lo, hi; \ + BN_UMULT_LOHI(lo, hi, ta, ta); \ + c0 += lo; \ + hi += (c0 < lo) ? 1 : 0; \ + c1 += hi; \ + c2 += (c1 < hi) ? 1 : 0; \ + } while (0) + +#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2) + +#else /* !BN_LLONG */ + +/* Keep in mind that additions to hi can not overflow, because + * the high word of a multiplication result cannot be all-ones. */ + +#define mul_add_c(a, b, c0, c1, c2) \ + do { \ + BN_ULONG lo = LBITS(a), hi = HBITS(a); \ + BN_ULONG bl = LBITS(b), bh = HBITS(b); \ + mul64(lo, hi, bl, bh); \ + c0 = (c0 + lo) & BN_MASK2; \ + if (c0 < lo) \ + hi++; \ + c1 = (c1 + hi) & BN_MASK2; \ + if (c1 < hi) \ + c2++; \ + } while (0) + +#define mul_add_c2(a, b, c0, c1, c2) \ + do { \ + BN_ULONG tt; \ + BN_ULONG lo = LBITS(a), hi = HBITS(a); \ + BN_ULONG bl = LBITS(b), bh = HBITS(b); \ + mul64(lo, hi, bl, bh); \ + tt = hi; \ + c0 = (c0 + lo) & BN_MASK2; \ + if (c0 < lo) \ + tt++; \ + c1 = (c1 + tt) & BN_MASK2; \ + if (c1 < tt) \ + c2++; \ + c0 = (c0 + lo) & BN_MASK2; \ + if (c0 < lo) \ + hi++; \ + c1 = (c1 + hi) & BN_MASK2; \ + if (c1 < hi) \ + c2++; \ + } while (0) + +#define sqr_add_c(a, i, c0, c1, c2) \ + do { \ + BN_ULONG lo, hi; \ + sqr64(lo, hi, (a)[i]); \ + c0 = (c0 + lo) & BN_MASK2; \ + if (c0 < lo) \ + hi++; \ + c1 = (c1 + hi) & BN_MASK2; \ + if (c1 < hi) \ + c2++; \ + } while (0) + +#define sqr_add_c2(a, i, j, c0, c1, c2) mul_add_c2((a)[i], (a)[j], c0, c1, c2) +#endif /* !BN_LLONG */ + +void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + mul_add_c(a[0], b[0], c1, c2, c3); + r[0] = c1; + c1 = 0; + mul_add_c(a[0], b[1], c2, c3, c1); + mul_add_c(a[1], b[0], c2, c3, c1); + r[1] = c2; + c2 = 0; + mul_add_c(a[2], b[0], c3, c1, c2); + mul_add_c(a[1], b[1], c3, c1, c2); + mul_add_c(a[0], b[2], c3, c1, c2); + r[2] = c3; + c3 = 0; + mul_add_c(a[0], b[3], c1, c2, c3); + mul_add_c(a[1], b[2], c1, c2, c3); + mul_add_c(a[2], b[1], c1, c2, c3); + mul_add_c(a[3], b[0], c1, c2, c3); + r[3] = c1; + c1 = 0; + mul_add_c(a[4], b[0], c2, c3, c1); + mul_add_c(a[3], b[1], c2, c3, c1); + mul_add_c(a[2], b[2], c2, c3, c1); + mul_add_c(a[1], b[3], c2, c3, c1); + mul_add_c(a[0], b[4], c2, c3, c1); + r[4] = c2; + c2 = 0; + mul_add_c(a[0], b[5], c3, c1, c2); + mul_add_c(a[1], b[4], c3, c1, c2); + mul_add_c(a[2], b[3], c3, c1, c2); + mul_add_c(a[3], b[2], c3, c1, c2); + mul_add_c(a[4], b[1], c3, c1, c2); + mul_add_c(a[5], b[0], c3, c1, c2); + r[5] = c3; + c3 = 0; + mul_add_c(a[6], b[0], c1, c2, c3); + mul_add_c(a[5], b[1], c1, c2, c3); + mul_add_c(a[4], b[2], c1, c2, c3); + mul_add_c(a[3], b[3], c1, c2, c3); + mul_add_c(a[2], b[4], c1, c2, c3); + mul_add_c(a[1], b[5], c1, c2, c3); + mul_add_c(a[0], b[6], c1, c2, c3); + r[6] = c1; + c1 = 0; + mul_add_c(a[0], b[7], c2, c3, c1); + mul_add_c(a[1], b[6], c2, c3, c1); + mul_add_c(a[2], b[5], c2, c3, c1); + mul_add_c(a[3], b[4], c2, c3, c1); + mul_add_c(a[4], b[3], c2, c3, c1); + mul_add_c(a[5], b[2], c2, c3, c1); + mul_add_c(a[6], b[1], c2, c3, c1); + mul_add_c(a[7], b[0], c2, c3, c1); + r[7] = c2; + c2 = 0; + mul_add_c(a[7], b[1], c3, c1, c2); + mul_add_c(a[6], b[2], c3, c1, c2); + mul_add_c(a[5], b[3], c3, c1, c2); + mul_add_c(a[4], b[4], c3, c1, c2); + mul_add_c(a[3], b[5], c3, c1, c2); + mul_add_c(a[2], b[6], c3, c1, c2); + mul_add_c(a[1], b[7], c3, c1, c2); + r[8] = c3; + c3 = 0; + mul_add_c(a[2], b[7], c1, c2, c3); + mul_add_c(a[3], b[6], c1, c2, c3); + mul_add_c(a[4], b[5], c1, c2, c3); + mul_add_c(a[5], b[4], c1, c2, c3); + mul_add_c(a[6], b[3], c1, c2, c3); + mul_add_c(a[7], b[2], c1, c2, c3); + r[9] = c1; + c1 = 0; + mul_add_c(a[7], b[3], c2, c3, c1); + mul_add_c(a[6], b[4], c2, c3, c1); + mul_add_c(a[5], b[5], c2, c3, c1); + mul_add_c(a[4], b[6], c2, c3, c1); + mul_add_c(a[3], b[7], c2, c3, c1); + r[10] = c2; + c2 = 0; + mul_add_c(a[4], b[7], c3, c1, c2); + mul_add_c(a[5], b[6], c3, c1, c2); + mul_add_c(a[6], b[5], c3, c1, c2); + mul_add_c(a[7], b[4], c3, c1, c2); + r[11] = c3; + c3 = 0; + mul_add_c(a[7], b[5], c1, c2, c3); + mul_add_c(a[6], b[6], c1, c2, c3); + mul_add_c(a[5], b[7], c1, c2, c3); + r[12] = c1; + c1 = 0; + mul_add_c(a[6], b[7], c2, c3, c1); + mul_add_c(a[7], b[6], c2, c3, c1); + r[13] = c2; + c2 = 0; + mul_add_c(a[7], b[7], c3, c1, c2); + r[14] = c3; + r[15] = c1; +} + +void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + mul_add_c(a[0], b[0], c1, c2, c3); + r[0] = c1; + c1 = 0; + mul_add_c(a[0], b[1], c2, c3, c1); + mul_add_c(a[1], b[0], c2, c3, c1); + r[1] = c2; + c2 = 0; + mul_add_c(a[2], b[0], c3, c1, c2); + mul_add_c(a[1], b[1], c3, c1, c2); + mul_add_c(a[0], b[2], c3, c1, c2); + r[2] = c3; + c3 = 0; + mul_add_c(a[0], b[3], c1, c2, c3); + mul_add_c(a[1], b[2], c1, c2, c3); + mul_add_c(a[2], b[1], c1, c2, c3); + mul_add_c(a[3], b[0], c1, c2, c3); + r[3] = c1; + c1 = 0; + mul_add_c(a[3], b[1], c2, c3, c1); + mul_add_c(a[2], b[2], c2, c3, c1); + mul_add_c(a[1], b[3], c2, c3, c1); + r[4] = c2; + c2 = 0; + mul_add_c(a[2], b[3], c3, c1, c2); + mul_add_c(a[3], b[2], c3, c1, c2); + r[5] = c3; + c3 = 0; + mul_add_c(a[3], b[3], c1, c2, c3); + r[6] = c1; + r[7] = c2; +} + +void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + sqr_add_c(a, 0, c1, c2, c3); + r[0] = c1; + c1 = 0; + sqr_add_c2(a, 1, 0, c2, c3, c1); + r[1] = c2; + c2 = 0; + sqr_add_c(a, 1, c3, c1, c2); + sqr_add_c2(a, 2, 0, c3, c1, c2); + r[2] = c3; + c3 = 0; + sqr_add_c2(a, 3, 0, c1, c2, c3); + sqr_add_c2(a, 2, 1, c1, c2, c3); + r[3] = c1; + c1 = 0; + sqr_add_c(a, 2, c2, c3, c1); + sqr_add_c2(a, 3, 1, c2, c3, c1); + sqr_add_c2(a, 4, 0, c2, c3, c1); + r[4] = c2; + c2 = 0; + sqr_add_c2(a, 5, 0, c3, c1, c2); + sqr_add_c2(a, 4, 1, c3, c1, c2); + sqr_add_c2(a, 3, 2, c3, c1, c2); + r[5] = c3; + c3 = 0; + sqr_add_c(a, 3, c1, c2, c3); + sqr_add_c2(a, 4, 2, c1, c2, c3); + sqr_add_c2(a, 5, 1, c1, c2, c3); + sqr_add_c2(a, 6, 0, c1, c2, c3); + r[6] = c1; + c1 = 0; + sqr_add_c2(a, 7, 0, c2, c3, c1); + sqr_add_c2(a, 6, 1, c2, c3, c1); + sqr_add_c2(a, 5, 2, c2, c3, c1); + sqr_add_c2(a, 4, 3, c2, c3, c1); + r[7] = c2; + c2 = 0; + sqr_add_c(a, 4, c3, c1, c2); + sqr_add_c2(a, 5, 3, c3, c1, c2); + sqr_add_c2(a, 6, 2, c3, c1, c2); + sqr_add_c2(a, 7, 1, c3, c1, c2); + r[8] = c3; + c3 = 0; + sqr_add_c2(a, 7, 2, c1, c2, c3); + sqr_add_c2(a, 6, 3, c1, c2, c3); + sqr_add_c2(a, 5, 4, c1, c2, c3); + r[9] = c1; + c1 = 0; + sqr_add_c(a, 5, c2, c3, c1); + sqr_add_c2(a, 6, 4, c2, c3, c1); + sqr_add_c2(a, 7, 3, c2, c3, c1); + r[10] = c2; + c2 = 0; + sqr_add_c2(a, 7, 4, c3, c1, c2); + sqr_add_c2(a, 6, 5, c3, c1, c2); + r[11] = c3; + c3 = 0; + sqr_add_c(a, 6, c1, c2, c3); + sqr_add_c2(a, 7, 5, c1, c2, c3); + r[12] = c1; + c1 = 0; + sqr_add_c2(a, 7, 6, c2, c3, c1); + r[13] = c2; + c2 = 0; + sqr_add_c(a, 7, c3, c1, c2); + r[14] = c3; + r[15] = c1; +} + +void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) { + BN_ULONG c1, c2, c3; + + c1 = 0; + c2 = 0; + c3 = 0; + sqr_add_c(a, 0, c1, c2, c3); + r[0] = c1; + c1 = 0; + sqr_add_c2(a, 1, 0, c2, c3, c1); + r[1] = c2; + c2 = 0; + sqr_add_c(a, 1, c3, c1, c2); + sqr_add_c2(a, 2, 0, c3, c1, c2); + r[2] = c3; + c3 = 0; + sqr_add_c2(a, 3, 0, c1, c2, c3); + sqr_add_c2(a, 2, 1, c1, c2, c3); + r[3] = c1; + c1 = 0; + sqr_add_c(a, 2, c2, c3, c1); + sqr_add_c2(a, 3, 1, c2, c3, c1); + r[4] = c2; + c2 = 0; + sqr_add_c2(a, 3, 2, c3, c1, c2); + r[5] = c3; + c3 = 0; + sqr_add_c(a, 3, c1, c2, c3); + r[6] = c1; + r[7] = c2; +} + +#if defined(OPENSSL_NO_ASM) || (!defined(OPENSSL_ARM) && !defined(OPENSSL_X86_64)) +/* This is essentially reference implementation, which may or may not + * result in performance improvement. E.g. on IA-32 this routine was + * observed to give 40% faster rsa1024 private key operations and 10% + * faster rsa4096 ones, while on AMD64 it improves rsa1024 sign only + * by 10% and *worsens* rsa4096 sign by 15%. Once again, it's a + * reference implementation, one to be used as starting point for + * platform-specific assembler. Mentioned numbers apply to compiler + * generated code compiled with and without -DOPENSSL_BN_ASM_MONT and + * can vary not only from platform to platform, but even for compiler + * versions. Assembler vs. assembler improvement coefficients can + * [and are known to] differ and are to be documented elsewhere. */ +int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, + const BN_ULONG *np, const BN_ULONG *n0p, int num) { + BN_ULONG c0, c1, ml, *tp, n0; +#ifdef mul64 + BN_ULONG mh; +#endif + volatile BN_ULONG *vp; + int i = 0, j; + +#if 0 /* template for platform-specific implementation */ + if (ap==bp) return bn_sqr_mont(rp,ap,np,n0p,num); +#endif + vp = tp = alloca((num + 2) * sizeof(BN_ULONG)); + + n0 = *n0p; + + c0 = 0; + ml = bp[0]; +#ifdef mul64 + mh = HBITS(ml); + ml = LBITS(ml); + for (j = 0; j < num; ++j) { + mul(tp[j], ap[j], ml, mh, c0); + } +#else + for (j = 0; j < num; ++j) { + mul(tp[j], ap[j], ml, c0); + } +#endif + + tp[num] = c0; + tp[num + 1] = 0; + goto enter; + + for (i = 0; i < num; i++) { + c0 = 0; + ml = bp[i]; +#ifdef mul64 + mh = HBITS(ml); + ml = LBITS(ml); + for (j = 0; j < num; ++j) { + mul_add(tp[j], ap[j], ml, mh, c0); + } +#else + for (j = 0; j < num; ++j) { + mul_add(tp[j], ap[j], ml, c0); + } +#endif + c1 = (tp[num] + c0) & BN_MASK2; + tp[num] = c1; + tp[num + 1] = (c1 < c0 ? 1 : 0); + enter: + c1 = tp[0]; + ml = (c1 * n0) & BN_MASK2; + c0 = 0; +#ifdef mul64 + mh = HBITS(ml); + ml = LBITS(ml); + mul_add(c1, np[0], ml, mh, c0); +#else + mul_add(c1, ml, np[0], c0); +#endif + for (j = 1; j < num; j++) { + c1 = tp[j]; +#ifdef mul64 + mul_add(c1, np[j], ml, mh, c0); +#else + mul_add(c1, ml, np[j], c0); +#endif + tp[j - 1] = c1 & BN_MASK2; + } + c1 = (tp[num] + c0) & BN_MASK2; + tp[num - 1] = c1; + tp[num] = tp[num + 1] + (c1 < c0 ? 1 : 0); + } + + if (tp[num] != 0 || tp[num - 1] >= np[num - 1]) { + c0 = bn_sub_words(rp, tp, np, num); + if (tp[num] != 0 || c0 == 0) { + for (i = 0; i < num + 2; i++) { + vp[i] = 0; + } + return 1; + } + } + for (i = 0; i < num; i++) { + rp[i] = tp[i], vp[i] = 0; + } + vp[num] = 0; + vp[num + 1] = 0; + return 1; +} +#endif + +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/bn/internal.h b/TMessagesProj/jni/boringssl/crypto/bn/internal.h new file mode 100644 index 00000000..2674b3cd --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/internal.h @@ -0,0 +1,291 @@ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the Eric Young open source + * license provided above. + * + * The binary polynomial arithmetic software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#ifndef OPENSSL_HEADER_BN_INTERNAL_H +#define OPENSSL_HEADER_BN_INTERNAL_H + +#include + +#if defined(OPENSSL_X86_64) && defined(_MSC_VER) && _MSC_VER >= 1400 +#pragma warning(push, 3) +#include +#pragma warning(pop) +#pragma intrinsic(__umulh, _umul128) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/* bn_expand acts the same as |BN_wexpand|, but takes a number of bits rather + * than a number of words. */ +BIGNUM *bn_expand(BIGNUM *bn, unsigned bits); + +#if defined(OPENSSL_64_BIT) + +#if !defined(_MSC_VER) +/* MSVC doesn't support two-word integers on 64-bit. */ +#define BN_LLONG __int128_t +#define BN_ULLONG __uint128_t +#endif + +#define BN_BITS 128 +#define BN_BITS2 64 +#define BN_BYTES 8 +#define BN_BITS4 32 +#define BN_MASK (0xffffffffffffffffffffffffffffffffLL) +#define BN_MASK2 (0xffffffffffffffffL) +#define BN_MASK2l (0xffffffffL) +#define BN_MASK2h (0xffffffff00000000L) +#define BN_MASK2h1 (0xffffffff80000000L) +#define BN_TBIT (0x8000000000000000L) +#define BN_DEC_CONV (10000000000000000000UL) +#define BN_DEC_NUM 19 + +#elif defined(OPENSSL_32_BIT) + +#define BN_LLONG int64_t +#define BN_ULLONG uint64_t +#define BN_MASK (0xffffffffffffffffLL) +#define BN_BITS 64 +#define BN_BITS2 32 +#define BN_BYTES 4 +#define BN_BITS4 16 +#define BN_MASK2 (0xffffffffL) +#define BN_MASK2l (0xffff) +#define BN_MASK2h1 (0xffff8000L) +#define BN_MASK2h (0xffff0000L) +#define BN_TBIT (0x80000000L) +#define BN_DEC_CONV (1000000000L) +#define BN_DEC_NUM 9 + +#else +#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT" +#endif + +/* Pentium pro 16,16,16,32,64 */ +/* Alpha 16,16,16,16.64 */ +#define BN_MULL_SIZE_NORMAL (16) /* 32 */ +#define BN_MUL_RECURSIVE_SIZE_NORMAL (16) /* 32 less than */ +#define BN_SQR_RECURSIVE_SIZE_NORMAL (16) /* 32 */ +#define BN_MUL_LOW_RECURSIVE_SIZE_NORMAL (32) /* 32 */ +#define BN_MONT_CTX_SET_SIZE_WORD (64) /* 32 */ + +#if defined(BN_LLONG) +#define Lw(t) (((BN_ULONG)(t))&BN_MASK2) +#define Hw(t) (((BN_ULONG)((t)>>BN_BITS2))&BN_MASK2) +#endif + +BN_ULONG bn_mul_add_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w); +BN_ULONG bn_mul_words(BN_ULONG *rp, const BN_ULONG *ap, int num, BN_ULONG w); +void bn_sqr_words(BN_ULONG *rp, const BN_ULONG *ap, int num); +BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d); +BN_ULONG bn_add_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num); +BN_ULONG bn_sub_words(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp,int num); + +void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b); +void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b); +void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a); +void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a); + +/* bn_cmp_words returns a value less than, equal to or greater than zero if + * the, length |n|, array |a| is less than, equal to or greater than |b|. */ +int bn_cmp_words(const BN_ULONG *a, const BN_ULONG *b, int n); + +/* bn_cmp_words returns a value less than, equal to or greater than zero if the + * array |a| is less than, equal to or greater than |b|. The arrays can be of + * different lengths: |cl| gives the minimum of the two lengths and |dl| gives + * the length of |a| minus the length of |b|. */ +int bn_cmp_part_words(const BN_ULONG *a, const BN_ULONG *b, int cl, int dl); + +int bn_mul_mont(BN_ULONG *rp, const BN_ULONG *ap, const BN_ULONG *bp, + const BN_ULONG *np, const BN_ULONG *n0, int num); + +#if !defined(BN_LLONG) + +#define LBITS(a) ((a) & BN_MASK2l) +#define HBITS(a) (((a) >> BN_BITS4) & BN_MASK2l) +#define L2HBITS(a) (((a) << BN_BITS4) & BN_MASK2) + +#define LLBITS(a) ((a) & BN_MASKl) +#define LHBITS(a) (((a) >> BN_BITS2) & BN_MASKl) +#define LL2HBITS(a) ((BN_ULLONG)((a) & BN_MASKl) << BN_BITS2) + +#define mul64(l, h, bl, bh) \ + { \ + BN_ULONG m, m1, lt, ht; \ + \ + lt = l; \ + ht = h; \ + m = (bh) * (lt); \ + lt = (bl) * (lt); \ + m1 = (bl) * (ht); \ + ht = (bh) * (ht); \ + m = (m + m1) & BN_MASK2; \ + if (m < m1) \ + ht += L2HBITS((BN_ULONG)1); \ + ht += HBITS(m); \ + m1 = L2HBITS(m); \ + lt = (lt + m1) & BN_MASK2; \ + if (lt < m1) \ + ht++; \ + (l) = lt; \ + (h) = ht; \ + } + +#endif /* !defined(BN_LLONG) */ + +#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) +# if defined(__GNUC__) && __GNUC__ >= 2 +# define BN_UMULT_HIGH(a,b) ({ \ + register BN_ULONG ret,discard; \ + __asm__ ("mulq %3" \ + : "=a"(discard),"=d"(ret) \ + : "a"(a), "g"(b) \ + : "cc"); \ + ret; }) +# define BN_UMULT_LOHI(low,high,a,b) \ + __asm__ ("mulq %3" \ + : "=a"(low),"=d"(high) \ + : "a"(a),"g"(b) \ + : "cc"); +# elif defined(_MSC_VER) && _MSC_VER >= 1400 +# define BN_UMULT_HIGH(a, b) __umulh((a), (b)) +# define BN_UMULT_LOHI(low, high, a, b) ((low) = _umul128((a), (b), &(high))) +# endif +#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_AARCH64) +# if defined(__GNUC__) && __GNUC__>=2 +# define BN_UMULT_HIGH(a,b) ({ \ + register BN_ULONG ret; \ + __asm__ ("umulh %0,%1,%2" \ + : "=r"(ret) \ + : "r"(a), "r"(b)); \ + ret; }) +# endif +#endif + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BN_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/bn/kronecker.c b/TMessagesProj/jni/boringssl/crypto/bn/kronecker.c new file mode 100644 index 00000000..23ef79af --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/kronecker.c @@ -0,0 +1,175 @@ +/* ==================================================================== + * Copyright (c) 1998-2000 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include "internal.h" + + +/* least significant word */ +#define BN_lsw(n) (((n)->top == 0) ? (BN_ULONG) 0 : (n)->d[0]) + +/* Returns -2 for errors because both -1 and 0 are valid results. */ +int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { + int i; + int ret = -2; + BIGNUM *A, *B, *tmp; + /* In 'tab', only odd-indexed entries are relevant: + * For any odd BIGNUM n, + * tab[BN_lsw(n) & 7] + * is $(-1)^{(n^2-1)/8}$ (using TeX notation). + * Note that the sign of n does not matter. */ + static const int tab[8] = {0, 1, 0, -1, 0, -1, 0, 1}; + + BN_CTX_start(ctx); + A = BN_CTX_get(ctx); + B = BN_CTX_get(ctx); + if (B == NULL) { + goto end; + } + + if (!BN_copy(A, a) || + !BN_copy(B, b)) { + goto end; + } + + /* Kronecker symbol, imlemented according to Henri Cohen, + * "A Course in Computational Algebraic Number Theory" + * (algorithm 1.4.10). */ + + /* Cohen's step 1: */ + + if (BN_is_zero(B)) { + ret = BN_abs_is_word(A, 1); + goto end; + } + + /* Cohen's step 2: */ + + if (!BN_is_odd(A) && !BN_is_odd(B)) { + ret = 0; + goto end; + } + + /* now B is non-zero */ + i = 0; + while (!BN_is_bit_set(B, i)) { + i++; + } + if (!BN_rshift(B, B, i)) { + goto end; + } + if (i & 1) { + /* i is odd */ + /* (thus B was even, thus A must be odd!) */ + + /* set 'ret' to $(-1)^{(A^2-1)/8}$ */ + ret = tab[BN_lsw(A) & 7]; + } else { + /* i is even */ + ret = 1; + } + + if (B->neg) { + B->neg = 0; + if (A->neg) { + ret = -ret; + } + } + + /* now B is positive and odd, so what remains to be done is to compute the + * Jacobi symbol (A/B) and multiply it by 'ret' */ + + while (1) { + /* Cohen's step 3: */ + + /* B is positive and odd */ + if (BN_is_zero(A)) { + ret = BN_is_one(B) ? ret : 0; + goto end; + } + + /* now A is non-zero */ + i = 0; + while (!BN_is_bit_set(A, i)) { + i++; + } + if (!BN_rshift(A, A, i)) { + goto end; + } + if (i & 1) { + /* i is odd */ + /* multiply 'ret' by $(-1)^{(B^2-1)/8}$ */ + ret = ret * tab[BN_lsw(B) & 7]; + } + + /* Cohen's step 4: */ + /* multiply 'ret' by $(-1)^{(A-1)(B-1)/4}$ */ + if ((A->neg ? ~BN_lsw(A) : BN_lsw(A)) & BN_lsw(B) & 2) { + ret = -ret; + } + + /* (A, B) := (B mod |A|, |A|) */ + if (!BN_nnmod(B, B, A, ctx)) { + ret = -2; + goto end; + } + tmp = A; + A = B; + B = tmp; + tmp->neg = 0; + } + +end: + BN_CTX_end(ctx); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/montgomery.c b/TMessagesProj/jni/boringssl/crypto/bn/montgomery.c new file mode 100644 index 00000000..152cf2d8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/montgomery.c @@ -0,0 +1,565 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include + +#include "internal.h" +#include "../internal.h" + + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) +#define OPENSSL_BN_ASM_MONT +#endif + +BN_MONT_CTX *BN_MONT_CTX_new(void) { + BN_MONT_CTX *ret = OPENSSL_malloc(sizeof(BN_MONT_CTX)); + + if (ret == NULL) { + return NULL; + } + + BN_MONT_CTX_init(ret); + ret->flags = BN_FLG_MALLOCED; + return ret; +} + +void BN_MONT_CTX_init(BN_MONT_CTX *mont) { + memset(mont, 0, sizeof(BN_MONT_CTX)); + BN_init(&mont->RR); + BN_init(&mont->N); + BN_init(&mont->Ni); +} + +void BN_MONT_CTX_free(BN_MONT_CTX *mont) { + if (mont == NULL) { + return; + } + + BN_free(&mont->RR); + BN_free(&mont->N); + BN_free(&mont->Ni); + if (mont->flags & BN_FLG_MALLOCED) { + OPENSSL_free(mont); + } +} + +BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, BN_MONT_CTX *from) { + if (to == from) { + return to; + } + + if (!BN_copy(&to->RR, &from->RR) || + !BN_copy(&to->N, &from->N) || + !BN_copy(&to->Ni, &from->Ni)) { + return NULL; + } + to->ri = from->ri; + to->n0[0] = from->n0[0]; + to->n0[1] = from->n0[1]; + return to; +} + +int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx) { + int ret = 0; + BIGNUM *Ri, *R; + BIGNUM tmod; + BN_ULONG buf[2]; + + BN_CTX_start(ctx); + Ri = BN_CTX_get(ctx); + if (Ri == NULL) { + goto err; + } + R = &mont->RR; /* grab RR as a temp */ + if (!BN_copy(&mont->N, mod)) { + goto err; /* Set N */ + } + mont->N.neg = 0; + + BN_init(&tmod); + tmod.d = buf; + tmod.dmax = 2; + tmod.neg = 0; + + mont->ri = (BN_num_bits(mod) + (BN_BITS2 - 1)) / BN_BITS2 * BN_BITS2; + +#if defined(OPENSSL_BN_ASM_MONT) && (BN_BITS2 <= 32) + /* Only certain BN_BITS2<=32 platforms actually make use of + * n0[1], and we could use the #else case (with a shorter R + * value) for the others. However, currently only the assembler + * files do know which is which. */ + + BN_zero(R); + if (!BN_set_bit(R, 2 * BN_BITS2)) { + goto err; + } + + tmod.top = 0; + if ((buf[0] = mod->d[0])) { + tmod.top = 1; + } + if ((buf[1] = mod->top > 1 ? mod->d[1] : 0)) { + tmod.top = 2; + } + + if (BN_mod_inverse(Ri, R, &tmod, ctx) == NULL) { + goto err; + } + if (!BN_lshift(Ri, Ri, 2 * BN_BITS2)) { + goto err; /* R*Ri */ + } + if (!BN_is_zero(Ri)) { + if (!BN_sub_word(Ri, 1)) { + goto err; + } + } else { + /* if N mod word size == 1 */ + if (bn_expand(Ri, (int)sizeof(BN_ULONG) * 2) == NULL) { + goto err; + } + /* Ri-- (mod double word size) */ + Ri->neg = 0; + Ri->d[0] = BN_MASK2; + Ri->d[1] = BN_MASK2; + Ri->top = 2; + } + + if (!BN_div(Ri, NULL, Ri, &tmod, ctx)) { + goto err; + } + /* Ni = (R*Ri-1)/N, + * keep only couple of least significant words: */ + mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0; + mont->n0[1] = (Ri->top > 1) ? Ri->d[1] : 0; +#else + BN_zero(R); + if (!BN_set_bit(R, BN_BITS2)) { + goto err; /* R */ + } + + buf[0] = mod->d[0]; /* tmod = N mod word size */ + buf[1] = 0; + tmod.top = buf[0] != 0 ? 1 : 0; + /* Ri = R^-1 mod N*/ + if (BN_mod_inverse(Ri, R, &tmod, ctx) == NULL) { + goto err; + } + if (!BN_lshift(Ri, Ri, BN_BITS2)) { + goto err; /* R*Ri */ + } + if (!BN_is_zero(Ri)) { + if (!BN_sub_word(Ri, 1)) { + goto err; + } + } else { + /* if N mod word size == 1 */ + if (!BN_set_word(Ri, BN_MASK2)) { + goto err; /* Ri-- (mod word size) */ + } + } + if (!BN_div(Ri, NULL, Ri, &tmod, ctx)) { + goto err; + } + /* Ni = (R*Ri-1)/N, + * keep only least significant word: */ + mont->n0[0] = (Ri->top > 0) ? Ri->d[0] : 0; + mont->n0[1] = 0; +#endif + + /* setup RR for conversions */ + BN_zero(&(mont->RR)); + if (!BN_set_bit(&(mont->RR), mont->ri * 2)) { + goto err; + } + if (!BN_mod(&(mont->RR), &(mont->RR), &(mont->N), ctx)) { + goto err; + } + + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock, + const BIGNUM *mod, BN_CTX *bn_ctx) { + CRYPTO_MUTEX_lock_read(lock); + BN_MONT_CTX *ctx = *pmont; + CRYPTO_MUTEX_unlock(lock); + + if (ctx) { + return ctx; + } + + CRYPTO_MUTEX_lock_write(lock); + ctx = *pmont; + if (ctx) { + goto out; + } + + ctx = BN_MONT_CTX_new(); + if (ctx == NULL) { + goto out; + } + if (!BN_MONT_CTX_set(ctx, mod, bn_ctx)) { + BN_MONT_CTX_free(ctx); + ctx = NULL; + goto out; + } + *pmont = ctx; + +out: + CRYPTO_MUTEX_unlock(lock); + return ctx; +} + +int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, const BN_MONT_CTX *mont, + BN_CTX *ctx) { + return BN_mod_mul_montgomery(ret, a, &mont->RR, mont, ctx); +} + +#if 0 +static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, + const BN_MONT_CTX *mont) { + const BIGNUM *n; + BN_ULONG *ap, *np, *rp, n0, v, carry; + int nl, max, i; + + n = &mont->N; + nl = n->top; + if (nl == 0) { + ret->top = 0; + return 1; + } + + max = (2 * nl); /* carry is stored separately */ + if (bn_wexpand(r, max) == NULL) { + return 0; + } + + r->neg ^= n->neg; + np = n->d; + rp = r->d; + + /* clear the top words of T */ + if (max > r->top) { + memset(&rp[r->top], 0, (max - r->top) * sizeof(BN_ULONG)); + } + + r->top = max; + n0 = mont->n0[0]; + + for (carry = 0, i = 0; i < nl; i++, rp++) { + v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2); + v = (v + carry + rp[nl]) & BN_MASK2; + carry |= (v != rp[nl]); + carry &= (v <= rp[nl]); + rp[nl] = v; + } + + if (bn_wexpand(ret, nl) == NULL) { + return 0; + } + ret->top = nl; + ret->neg = r->neg; + + rp = ret->d; + ap = &(r->d[nl]); + + { + BN_ULONG *nrp; + size_t m; + + v = bn_sub_words(rp, ap, np, nl) - carry; + /* if subtraction result is real, then trick unconditional memcpy below to + * perform in-place "refresh" instead of actual copy. */ + m = (0 - (size_t)v); + nrp = (BN_ULONG *)(((intptr_t)rp & ~m) | ((intptr_t)ap & m)); + + for (i = 0, nl -= 4; i < nl; i += 4) { + BN_ULONG t1, t2, t3, t4; + + t1 = nrp[i + 0]; + t2 = nrp[i + 1]; + t3 = nrp[i + 2]; + ap[i + 0] = 0; + t4 = nrp[i + 3]; + ap[i + 1] = 0; + rp[i + 0] = t1; + ap[i + 2] = 0; + rp[i + 1] = t2; + ap[i + 3] = 0; + rp[i + 2] = t3; + rp[i + 3] = t4; + } + + for (nl += 4; i < nl; i++) { + rp[i] = nrp[i], ap[i] = 0; + } + } + + bn_correct_top(r); + bn_correct_top(ret); + + return 1; +} +#endif + +#define PTR_SIZE_INT size_t + +static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, const BN_MONT_CTX *mont) + { + BIGNUM *n; + BN_ULONG *ap,*np,*rp,n0,v,carry; + int nl,max,i; + + n= (BIGNUM*) &(mont->N); + nl=n->top; + if (nl == 0) { ret->top=0; return(1); } + + max=(2*nl); /* carry is stored separately */ + if (bn_wexpand(r,max) == NULL) return(0); + + r->neg^=n->neg; + np=n->d; + rp=r->d; + + /* clear the top words of T */ +#if 1 + for (i=r->top; itop]),0,(max-r->top)*sizeof(BN_ULONG)); +#endif + + r->top=max; + n0=mont->n0[0]; + + for (carry=0, i=0; itop=nl; + ret->neg=r->neg; + + rp=ret->d; + ap=&(r->d[nl]); + + { + BN_ULONG *nrp; + size_t m; + + v=bn_sub_words(rp,ap,np,nl)-carry; + /* if subtraction result is real, then + * trick unconditional memcpy below to perform in-place + * "refresh" instead of actual copy. */ + m=(0-(size_t)v); + nrp=(BN_ULONG *)(((PTR_SIZE_INT)rp&~m)|((PTR_SIZE_INT)ap&m)); + + for (i=0,nl-=4; iN.top; + + if (num > 1 && a->top == num && b->top == num) { + if (bn_wexpand(r, num) == NULL) { + return 0; + } + if (bn_mul_mont(r->d, a->d, b->d, mont->N.d, mont->n0, num)) { + r->neg = a->neg ^ b->neg; + r->top = num; + bn_correct_top(r); + return 1; + } + } +#endif + + BN_CTX_start(ctx); + tmp = BN_CTX_get(ctx); + if (tmp == NULL) { + goto err; + } + + if (a == b) { + if (!BN_sqr(tmp, a, ctx)) { + goto err; + } + } else { + if (!BN_mul(tmp, a, b, ctx)) { + goto err; + } + } + + /* reduce from aRR to aR */ + if (!BN_from_montgomery_word(r, tmp, mont)) { + goto err; + } + + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/mul.c b/TMessagesProj/jni/boringssl/crypto/bn/mul.c new file mode 100644 index 00000000..029a59e2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/mul.c @@ -0,0 +1,888 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include "internal.h" + + +void bn_mul_normal(BN_ULONG *r, BN_ULONG *a, int na, BN_ULONG *b, int nb) { + BN_ULONG *rr; + + if (na < nb) { + int itmp; + BN_ULONG *ltmp; + + itmp = na; + na = nb; + nb = itmp; + ltmp = a; + a = b; + b = ltmp; + } + rr = &(r[na]); + if (nb <= 0) { + (void)bn_mul_words(r, a, na, 0); + return; + } else { + rr[0] = bn_mul_words(r, a, na, b[0]); + } + + for (;;) { + if (--nb <= 0) { + return; + } + rr[1] = bn_mul_add_words(&(r[1]), a, na, b[1]); + if (--nb <= 0) { + return; + } + rr[2] = bn_mul_add_words(&(r[2]), a, na, b[2]); + if (--nb <= 0) { + return; + } + rr[3] = bn_mul_add_words(&(r[3]), a, na, b[3]); + if (--nb <= 0) { + return; + } + rr[4] = bn_mul_add_words(&(r[4]), a, na, b[4]); + rr += 4; + r += 4; + b += 4; + } +} + +void bn_mul_low_normal(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n) { + bn_mul_words(r, a, n, b[0]); + + for (;;) { + if (--n <= 0) { + return; + } + bn_mul_add_words(&(r[1]), a, n, b[1]); + if (--n <= 0) { + return; + } + bn_mul_add_words(&(r[2]), a, n, b[2]); + if (--n <= 0) { + return; + } + bn_mul_add_words(&(r[3]), a, n, b[3]); + if (--n <= 0) { + return; + } + bn_mul_add_words(&(r[4]), a, n, b[4]); + r += 4; + b += 4; + } +} + +#if !defined(OPENSSL_X86) || defined(OPENSSL_NO_ASM) +/* Here follows specialised variants of bn_add_words() and bn_sub_words(). They + * have the property performing operations on arrays of different sizes. The + * sizes of those arrays is expressed through cl, which is the common length ( + * basicall, min(len(a),len(b)) ), and dl, which is the delta between the two + * lengths, calculated as len(a)-len(b). All lengths are the number of + * BN_ULONGs... For the operations that require a result array as parameter, + * it must have the length cl+abs(dl). These functions should probably end up + * in bn_asm.c as soon as there are assembler counterparts for the systems that + * use assembler files. */ + +static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, + const BN_ULONG *b, int cl, int dl) { + BN_ULONG c, t; + + assert(cl >= 0); + c = bn_sub_words(r, a, b, cl); + + if (dl == 0) { + return c; + } + + r += cl; + a += cl; + b += cl; + + if (dl < 0) { + for (;;) { + t = b[0]; + r[0] = (0 - t - c) & BN_MASK2; + if (t != 0) { + c = 1; + } + if (++dl >= 0) { + break; + } + + t = b[1]; + r[1] = (0 - t - c) & BN_MASK2; + if (t != 0) { + c = 1; + } + if (++dl >= 0) { + break; + } + + t = b[2]; + r[2] = (0 - t - c) & BN_MASK2; + if (t != 0) { + c = 1; + } + if (++dl >= 0) { + break; + } + + t = b[3]; + r[3] = (0 - t - c) & BN_MASK2; + if (t != 0) { + c = 1; + } + if (++dl >= 0) { + break; + } + + b += 4; + r += 4; + } + } else { + int save_dl = dl; + while (c) { + t = a[0]; + r[0] = (t - c) & BN_MASK2; + if (t != 0) { + c = 0; + } + if (--dl <= 0) { + break; + } + + t = a[1]; + r[1] = (t - c) & BN_MASK2; + if (t != 0) { + c = 0; + } + if (--dl <= 0) { + break; + } + + t = a[2]; + r[2] = (t - c) & BN_MASK2; + if (t != 0) { + c = 0; + } + if (--dl <= 0) { + break; + } + + t = a[3]; + r[3] = (t - c) & BN_MASK2; + if (t != 0) { + c = 0; + } + if (--dl <= 0) { + break; + } + + save_dl = dl; + a += 4; + r += 4; + } + if (dl > 0) { + if (save_dl > dl) { + switch (save_dl - dl) { + case 1: + r[1] = a[1]; + if (--dl <= 0) { + break; + } + case 2: + r[2] = a[2]; + if (--dl <= 0) { + break; + } + case 3: + r[3] = a[3]; + if (--dl <= 0) { + break; + } + } + a += 4; + r += 4; + } + } + + if (dl > 0) { + for (;;) { + r[0] = a[0]; + if (--dl <= 0) { + break; + } + r[1] = a[1]; + if (--dl <= 0) { + break; + } + r[2] = a[2]; + if (--dl <= 0) { + break; + } + r[3] = a[3]; + if (--dl <= 0) { + break; + } + + a += 4; + r += 4; + } + } + } + + return c; +} +#else +/* On other platforms the function is defined in asm. */ +BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, + int cl, int dl); +#endif + +/* Karatsuba recursive multiplication algorithm + * (cf. Knuth, The Art of Computer Programming, Vol. 2) */ + +/* r is 2*n2 words in size, + * a and b are both n2 words in size. + * n2 must be a power of 2. + * We multiply and return the result. + * t must be 2*n2 words in size + * We calculate + * a[0]*b[0] + * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0]) + * a[1]*b[1] + */ +/* dnX may not be positive, but n2/2+dnX has to be */ +static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2, + int dna, int dnb, BN_ULONG *t) { + int n = n2 / 2, c1, c2; + int tna = n + dna, tnb = n + dnb; + unsigned int neg, zero; + BN_ULONG ln, lo, *p; + + /* Only call bn_mul_comba 8 if n2 == 8 and the + * two arrays are complete [steve] + */ + if (n2 == 8 && dna == 0 && dnb == 0) { + bn_mul_comba8(r, a, b); + return; + } + + /* Else do normal multiply */ + if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) { + bn_mul_normal(r, a, n2 + dna, b, n2 + dnb); + if ((dna + dnb) < 0) { + memset(&r[2 * n2 + dna + dnb], 0, sizeof(BN_ULONG) * -(dna + dnb)); + } + return; + } + + /* r=(a[0]-a[1])*(b[1]-b[0]) */ + c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna); + c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n); + zero = neg = 0; + switch (c1 * 3 + c2) { + case -4: + bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */ + bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */ + break; + case -3: + zero = 1; + break; + case -2: + bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */ + bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */ + neg = 1; + break; + case -1: + case 0: + case 1: + zero = 1; + break; + case 2: + bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */ + bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */ + neg = 1; + break; + case 3: + zero = 1; + break; + case 4: + bn_sub_part_words(t, a, &(a[n]), tna, n - tna); + bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); + break; + } + + if (n == 4 && dna == 0 && dnb == 0) { + /* XXX: bn_mul_comba4 could take extra args to do this well */ + if (!zero) { + bn_mul_comba4(&(t[n2]), t, &(t[n])); + } else { + memset(&(t[n2]), 0, 8 * sizeof(BN_ULONG)); + } + + bn_mul_comba4(r, a, b); + bn_mul_comba4(&(r[n2]), &(a[n]), &(b[n])); + } else if (n == 8 && dna == 0 && dnb == 0) { + /* XXX: bn_mul_comba8 could take extra args to do this well */ + if (!zero) { + bn_mul_comba8(&(t[n2]), t, &(t[n])); + } else { + memset(&(t[n2]), 0, 16 * sizeof(BN_ULONG)); + } + + bn_mul_comba8(r, a, b); + bn_mul_comba8(&(r[n2]), &(a[n]), &(b[n])); + } else { + p = &(t[n2 * 2]); + if (!zero) { + bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p); + } else { + memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG)); + } + bn_mul_recursive(r, a, b, n, 0, 0, p); + bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), n, dna, dnb, p); + } + + /* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) */ + + c1 = (int)(bn_add_words(t, r, &(r[n2]), n2)); + + if (neg) { + /* if t[32] is negative */ + c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2)); + } else { + /* Might have a carry */ + c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2)); + } + + /* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1]) + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) + * c1 holds the carry bits */ + c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2)); + if (c1) { + p = &(r[n + n2]); + lo = *p; + ln = (lo + c1) & BN_MASK2; + *p = ln; + + /* The overflow will stop before we over write + * words we should not overwrite */ + if (ln < (BN_ULONG)c1) { + do { + p++; + lo = *p; + ln = (lo + 1) & BN_MASK2; + *p = ln; + } while (ln == 0); + } + } +} + +/* n+tn is the word length + * t needs to be n*4 is size, as does r */ +/* tnX may not be negative but less than n */ +static void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n, + int tna, int tnb, BN_ULONG *t) { + int i, j, n2 = n * 2; + int c1, c2, neg; + BN_ULONG ln, lo, *p; + + if (n < 8) { + bn_mul_normal(r, a, n + tna, b, n + tnb); + return; + } + + /* r=(a[0]-a[1])*(b[1]-b[0]) */ + c1 = bn_cmp_part_words(a, &(a[n]), tna, n - tna); + c2 = bn_cmp_part_words(&(b[n]), b, tnb, tnb - n); + neg = 0; + switch (c1 * 3 + c2) { + case -4: + bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */ + bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */ + break; + case -3: + /* break; */ + case -2: + bn_sub_part_words(t, &(a[n]), a, tna, tna - n); /* - */ + bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); /* + */ + neg = 1; + break; + case -1: + case 0: + case 1: + /* break; */ + case 2: + bn_sub_part_words(t, a, &(a[n]), tna, n - tna); /* + */ + bn_sub_part_words(&(t[n]), b, &(b[n]), tnb, n - tnb); /* - */ + neg = 1; + break; + case 3: + /* break; */ + case 4: + bn_sub_part_words(t, a, &(a[n]), tna, n - tna); + bn_sub_part_words(&(t[n]), &(b[n]), b, tnb, tnb - n); + break; + } + + if (n == 8) { + bn_mul_comba8(&(t[n2]), t, &(t[n])); + bn_mul_comba8(r, a, b); + bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb); + memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb)); + } else { + p = &(t[n2 * 2]); + bn_mul_recursive(&(t[n2]), t, &(t[n]), n, 0, 0, p); + bn_mul_recursive(r, a, b, n, 0, 0, p); + i = n / 2; + /* If there is only a bottom half to the number, + * just do it */ + if (tna > tnb) { + j = tna - i; + } else { + j = tnb - i; + } + + if (j == 0) { + bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, p); + memset(&(r[n2 + i * 2]), 0, sizeof(BN_ULONG) * (n2 - i * 2)); + } else if (j > 0) { + /* eg, n == 16, i == 8 and tn == 11 */ + bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, p); + memset(&(r[n2 + tna + tnb]), 0, sizeof(BN_ULONG) * (n2 - tna - tnb)); + } else { + /* (j < 0) eg, n == 16, i == 8 and tn == 5 */ + memset(&(r[n2]), 0, sizeof(BN_ULONG) * n2); + if (tna < BN_MUL_RECURSIVE_SIZE_NORMAL && + tnb < BN_MUL_RECURSIVE_SIZE_NORMAL) { + bn_mul_normal(&(r[n2]), &(a[n]), tna, &(b[n]), tnb); + } else { + for (;;) { + i /= 2; + /* these simplified conditions work + * exclusively because difference + * between tna and tnb is 1 or 0 */ + if (i < tna || i < tnb) { + bn_mul_part_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, + tnb - i, p); + break; + } else if (i == tna || i == tnb) { + bn_mul_recursive(&(r[n2]), &(a[n]), &(b[n]), i, tna - i, tnb - i, + p); + break; + } + } + } + } + } + + /* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) + */ + + c1 = (int)(bn_add_words(t, r, &(r[n2]), n2)); + + if (neg) { + /* if t[32] is negative */ + c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2)); + } else { + /* Might have a carry */ + c1 += (int)(bn_add_words(&(t[n2]), &(t[n2]), t, n2)); + } + + /* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1]) + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) + * c1 holds the carry bits */ + c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2)); + if (c1) { + p = &(r[n + n2]); + lo = *p; + ln = (lo + c1) & BN_MASK2; + *p = ln; + + /* The overflow will stop before we over write + * words we should not overwrite */ + if (ln < (BN_ULONG)c1) { + do { + p++; + lo = *p; + ln = (lo + 1) & BN_MASK2; + *p = ln; + } while (ln == 0); + } + } +} + +int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { + int ret = 0; + int top, al, bl; + BIGNUM *rr; + int i; + BIGNUM *t = NULL; + int j = 0, k; + + al = a->top; + bl = b->top; + + if ((al == 0) || (bl == 0)) { + BN_zero(r); + return 1; + } + top = al + bl; + + BN_CTX_start(ctx); + if ((r == a) || (r == b)) { + if ((rr = BN_CTX_get(ctx)) == NULL) { + goto err; + } + } else { + rr = r; + } + rr->neg = a->neg ^ b->neg; + + i = al - bl; + if (i == 0) { + if (al == 8) { + if (bn_wexpand(rr, 16) == NULL) { + goto err; + } + rr->top = 16; + bn_mul_comba8(rr->d, a->d, b->d); + goto end; + } + } + + if ((al >= BN_MULL_SIZE_NORMAL) && (bl >= BN_MULL_SIZE_NORMAL)) { + if (i >= -1 && i <= 1) { + /* Find out the power of two lower or equal + to the longest of the two numbers */ + if (i >= 0) { + j = BN_num_bits_word((BN_ULONG)al); + } + if (i == -1) { + j = BN_num_bits_word((BN_ULONG)bl); + } + j = 1 << (j - 1); + assert(j <= al || j <= bl); + k = j + j; + t = BN_CTX_get(ctx); + if (t == NULL) { + goto err; + } + if (al > j || bl > j) { + if (bn_wexpand(t, k * 4) == NULL) { + goto err; + } + if (bn_wexpand(rr, k * 4) == NULL) { + goto err; + } + bn_mul_part_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d); + } else { + /* al <= j || bl <= j */ + if (bn_wexpand(t, k * 2) == NULL) { + goto err; + } + if (bn_wexpand(rr, k * 2) == NULL) { + goto err; + } + bn_mul_recursive(rr->d, a->d, b->d, j, al - j, bl - j, t->d); + } + rr->top = top; + goto end; + } + } + + if (bn_wexpand(rr, top) == NULL) { + goto err; + } + rr->top = top; + bn_mul_normal(rr->d, a->d, al, b->d, bl); + +end: + bn_correct_top(rr); + if (r != rr && !BN_copy(r, rr)) { + goto err; + } + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +/* tmp must have 2*n words */ +static void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, int n, BN_ULONG *tmp) { + int i, j, max; + const BN_ULONG *ap; + BN_ULONG *rp; + + max = n * 2; + ap = a; + rp = r; + rp[0] = rp[max - 1] = 0; + rp++; + j = n; + + if (--j > 0) { + ap++; + rp[j] = bn_mul_words(rp, ap, j, ap[-1]); + rp += 2; + } + + for (i = n - 2; i > 0; i--) { + j--; + ap++; + rp[j] = bn_mul_add_words(rp, ap, j, ap[-1]); + rp += 2; + } + + bn_add_words(r, r, r, max); + + /* There will not be a carry */ + + bn_sqr_words(tmp, a, n); + + bn_add_words(r, r, tmp, max); +} + +/* r is 2*n words in size, + * a and b are both n words in size. (There's not actually a 'b' here ...) + * n must be a power of 2. + * We multiply and return the result. + * t must be 2*n words in size + * We calculate + * a[0]*b[0] + * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0]) + * a[1]*b[1] + */ +static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t) { + int n = n2 / 2; + int zero, c1; + BN_ULONG ln, lo, *p; + + if (n2 == 4) { + bn_sqr_comba4(r, a); + return; + } else if (n2 == 8) { + bn_sqr_comba8(r, a); + return; + } + if (n2 < BN_SQR_RECURSIVE_SIZE_NORMAL) { + bn_sqr_normal(r, a, n2, t); + return; + } + /* r=(a[0]-a[1])*(a[1]-a[0]) */ + c1 = bn_cmp_words(a, &(a[n]), n); + zero = 0; + if (c1 > 0) { + bn_sub_words(t, a, &(a[n]), n); + } else if (c1 < 0) { + bn_sub_words(t, &(a[n]), a, n); + } else { + zero = 1; + } + + /* The result will always be negative unless it is zero */ + p = &(t[n2 * 2]); + + if (!zero) { + bn_sqr_recursive(&(t[n2]), t, n, p); + } else { + memset(&(t[n2]), 0, n2 * sizeof(BN_ULONG)); + } + bn_sqr_recursive(r, a, n, p); + bn_sqr_recursive(&(r[n2]), &(a[n]), n, p); + + /* t[32] holds (a[0]-a[1])*(a[1]-a[0]), it is negative or zero + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) */ + + c1 = (int)(bn_add_words(t, r, &(r[n2]), n2)); + + /* t[32] is negative */ + c1 -= (int)(bn_sub_words(&(t[n2]), t, &(t[n2]), n2)); + + /* t[32] holds (a[0]-a[1])*(a[1]-a[0])+(a[0]*a[0])+(a[1]*a[1]) + * r[10] holds (a[0]*a[0]) + * r[32] holds (a[1]*a[1]) + * c1 holds the carry bits */ + c1 += (int)(bn_add_words(&(r[n]), &(r[n]), &(t[n2]), n2)); + if (c1) { + p = &(r[n + n2]); + lo = *p; + ln = (lo + c1) & BN_MASK2; + *p = ln; + + /* The overflow will stop before we over write + * words we should not overwrite */ + if (ln < (BN_ULONG)c1) { + do { + p++; + lo = *p; + ln = (lo + 1) & BN_MASK2; + *p = ln; + } while (ln == 0); + } + } +} + +int BN_mul_word(BIGNUM *bn, BN_ULONG w) { + BN_ULONG ll; + + w &= BN_MASK2; + if (!bn->top) { + return 1; + } + + if (w == 0) { + BN_zero(bn); + return 1; + } + + ll = bn_mul_words(bn->d, bn->d, bn->top, w); + if (ll) { + if (bn_wexpand(bn, bn->top + 1) == NULL) { + return 0; + } + bn->d[bn->top++] = ll; + } + + return 1; +} + +int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) { + int max, al; + int ret = 0; + BIGNUM *tmp, *rr; + + al = a->top; + if (al <= 0) { + r->top = 0; + r->neg = 0; + return 1; + } + + BN_CTX_start(ctx); + rr = (a != r) ? r : BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); + if (!rr || !tmp) { + goto err; + } + + max = 2 * al; /* Non-zero (from above) */ + if (bn_wexpand(rr, max) == NULL) { + goto err; + } + + if (al == 4) { + bn_sqr_comba4(rr->d, a->d); + } else if (al == 8) { + bn_sqr_comba8(rr->d, a->d); + } else { + if (al < BN_SQR_RECURSIVE_SIZE_NORMAL) { + BN_ULONG t[BN_SQR_RECURSIVE_SIZE_NORMAL * 2]; + bn_sqr_normal(rr->d, a->d, al, t); + } else { + int j, k; + + j = BN_num_bits_word((BN_ULONG)al); + j = 1 << (j - 1); + k = j + j; + if (al == j) { + if (bn_wexpand(tmp, k * 2) == NULL) { + goto err; + } + bn_sqr_recursive(rr->d, a->d, al, tmp->d); + } else { + if (bn_wexpand(tmp, max) == NULL) { + goto err; + } + bn_sqr_normal(rr->d, a->d, al, tmp->d); + } + } + } + + rr->neg = 0; + /* If the most-significant half of the top word of 'a' is zero, then + * the square of 'a' will max-1 words. */ + if (a->d[al - 1] == (a->d[al - 1] & BN_MASK2l)) { + rr->top = max - 1; + } else { + rr->top = max; + } + + if (rr != r && !BN_copy(r, rr)) { + goto err; + } + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/prime.c b/TMessagesProj/jni/boringssl/crypto/bn/prime.c new file mode 100644 index 00000000..bbb8fe0f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/prime.c @@ -0,0 +1,845 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include "internal.h" + +/* number of Miller-Rabin iterations for an error rate of less than 2^-80 + * for random 'b'-bit input, b >= 100 (taken from table 4.4 in the Handbook + * of Applied Cryptography [Menezes, van Oorschot, Vanstone; CRC Press 1996]; + * original paper: Damgaard, Landrock, Pomerance: Average case error estimates + * for the strong probable prime test. -- Math. Comp. 61 (1993) 177-194) */ +#define BN_prime_checks_for_size(b) ((b) >= 1300 ? 2 : \ + (b) >= 850 ? 3 : \ + (b) >= 650 ? 4 : \ + (b) >= 550 ? 5 : \ + (b) >= 450 ? 6 : \ + (b) >= 400 ? 7 : \ + (b) >= 350 ? 8 : \ + (b) >= 300 ? 9 : \ + (b) >= 250 ? 12 : \ + (b) >= 200 ? 15 : \ + (b) >= 150 ? 18 : \ + /* b >= 100 */ 27) + +/* The quick sieve algorithm approach to weeding out primes is Philip + * Zimmermann's, as implemented in PGP. I have had a read of his comments and + * implemented my own version. */ + +/* NUMPRIMES is the number of primes that fit into a uint16_t. */ +#define NUMPRIMES 2048 + +/* primes contains all the primes that fit into a uint16_t. */ +static const uint16_t primes[NUMPRIMES] = { + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, + 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, + 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, + 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, + 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, + 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, + 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, + 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, + 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, + 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, + 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, + 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, + 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, + 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, + 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, + 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, + 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, + 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, + 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, + 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, + 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, + 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, + 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, + 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, + 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, + 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, + 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, + 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, + 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, + 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, + 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, + 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, + 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, + 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, + 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, + 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, + 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, + 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, + 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, + 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, + 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, + 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, + 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, + 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, + 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, + 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, + 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, + 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, + 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, + 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, + 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, + 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, + 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, + 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, + 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, + 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, + 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, + 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, + 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, + 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, + 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, + 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, + 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, + 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, + 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, + 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, + 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, + 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, + 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, + 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, + 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, + 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, + 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, + 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, + 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, + 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, + 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, + 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, + 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, + 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, + 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, + 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, + 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, + 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, + 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, + 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, + 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, + 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, + 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919, 7927, + 7933, 7937, 7949, 7951, 7963, 7993, 8009, 8011, 8017, 8039, 8053, + 8059, 8069, 8081, 8087, 8089, 8093, 8101, 8111, 8117, 8123, 8147, + 8161, 8167, 8171, 8179, 8191, 8209, 8219, 8221, 8231, 8233, 8237, + 8243, 8263, 8269, 8273, 8287, 8291, 8293, 8297, 8311, 8317, 8329, + 8353, 8363, 8369, 8377, 8387, 8389, 8419, 8423, 8429, 8431, 8443, + 8447, 8461, 8467, 8501, 8513, 8521, 8527, 8537, 8539, 8543, 8563, + 8573, 8581, 8597, 8599, 8609, 8623, 8627, 8629, 8641, 8647, 8663, + 8669, 8677, 8681, 8689, 8693, 8699, 8707, 8713, 8719, 8731, 8737, + 8741, 8747, 8753, 8761, 8779, 8783, 8803, 8807, 8819, 8821, 8831, + 8837, 8839, 8849, 8861, 8863, 8867, 8887, 8893, 8923, 8929, 8933, + 8941, 8951, 8963, 8969, 8971, 8999, 9001, 9007, 9011, 9013, 9029, + 9041, 9043, 9049, 9059, 9067, 9091, 9103, 9109, 9127, 9133, 9137, + 9151, 9157, 9161, 9173, 9181, 9187, 9199, 9203, 9209, 9221, 9227, + 9239, 9241, 9257, 9277, 9281, 9283, 9293, 9311, 9319, 9323, 9337, + 9341, 9343, 9349, 9371, 9377, 9391, 9397, 9403, 9413, 9419, 9421, + 9431, 9433, 9437, 9439, 9461, 9463, 9467, 9473, 9479, 9491, 9497, + 9511, 9521, 9533, 9539, 9547, 9551, 9587, 9601, 9613, 9619, 9623, + 9629, 9631, 9643, 9649, 9661, 9677, 9679, 9689, 9697, 9719, 9721, + 9733, 9739, 9743, 9749, 9767, 9769, 9781, 9787, 9791, 9803, 9811, + 9817, 9829, 9833, 9839, 9851, 9857, 9859, 9871, 9883, 9887, 9901, + 9907, 9923, 9929, 9931, 9941, 9949, 9967, 9973, 10007, 10009, 10037, + 10039, 10061, 10067, 10069, 10079, 10091, 10093, 10099, 10103, 10111, 10133, + 10139, 10141, 10151, 10159, 10163, 10169, 10177, 10181, 10193, 10211, 10223, + 10243, 10247, 10253, 10259, 10267, 10271, 10273, 10289, 10301, 10303, 10313, + 10321, 10331, 10333, 10337, 10343, 10357, 10369, 10391, 10399, 10427, 10429, + 10433, 10453, 10457, 10459, 10463, 10477, 10487, 10499, 10501, 10513, 10529, + 10531, 10559, 10567, 10589, 10597, 10601, 10607, 10613, 10627, 10631, 10639, + 10651, 10657, 10663, 10667, 10687, 10691, 10709, 10711, 10723, 10729, 10733, + 10739, 10753, 10771, 10781, 10789, 10799, 10831, 10837, 10847, 10853, 10859, + 10861, 10867, 10883, 10889, 10891, 10903, 10909, 10937, 10939, 10949, 10957, + 10973, 10979, 10987, 10993, 11003, 11027, 11047, 11057, 11059, 11069, 11071, + 11083, 11087, 11093, 11113, 11117, 11119, 11131, 11149, 11159, 11161, 11171, + 11173, 11177, 11197, 11213, 11239, 11243, 11251, 11257, 11261, 11273, 11279, + 11287, 11299, 11311, 11317, 11321, 11329, 11351, 11353, 11369, 11383, 11393, + 11399, 11411, 11423, 11437, 11443, 11447, 11467, 11471, 11483, 11489, 11491, + 11497, 11503, 11519, 11527, 11549, 11551, 11579, 11587, 11593, 11597, 11617, + 11621, 11633, 11657, 11677, 11681, 11689, 11699, 11701, 11717, 11719, 11731, + 11743, 11777, 11779, 11783, 11789, 11801, 11807, 11813, 11821, 11827, 11831, + 11833, 11839, 11863, 11867, 11887, 11897, 11903, 11909, 11923, 11927, 11933, + 11939, 11941, 11953, 11959, 11969, 11971, 11981, 11987, 12007, 12011, 12037, + 12041, 12043, 12049, 12071, 12073, 12097, 12101, 12107, 12109, 12113, 12119, + 12143, 12149, 12157, 12161, 12163, 12197, 12203, 12211, 12227, 12239, 12241, + 12251, 12253, 12263, 12269, 12277, 12281, 12289, 12301, 12323, 12329, 12343, + 12347, 12373, 12377, 12379, 12391, 12401, 12409, 12413, 12421, 12433, 12437, + 12451, 12457, 12473, 12479, 12487, 12491, 12497, 12503, 12511, 12517, 12527, + 12539, 12541, 12547, 12553, 12569, 12577, 12583, 12589, 12601, 12611, 12613, + 12619, 12637, 12641, 12647, 12653, 12659, 12671, 12689, 12697, 12703, 12713, + 12721, 12739, 12743, 12757, 12763, 12781, 12791, 12799, 12809, 12821, 12823, + 12829, 12841, 12853, 12889, 12893, 12899, 12907, 12911, 12917, 12919, 12923, + 12941, 12953, 12959, 12967, 12973, 12979, 12983, 13001, 13003, 13007, 13009, + 13033, 13037, 13043, 13049, 13063, 13093, 13099, 13103, 13109, 13121, 13127, + 13147, 13151, 13159, 13163, 13171, 13177, 13183, 13187, 13217, 13219, 13229, + 13241, 13249, 13259, 13267, 13291, 13297, 13309, 13313, 13327, 13331, 13337, + 13339, 13367, 13381, 13397, 13399, 13411, 13417, 13421, 13441, 13451, 13457, + 13463, 13469, 13477, 13487, 13499, 13513, 13523, 13537, 13553, 13567, 13577, + 13591, 13597, 13613, 13619, 13627, 13633, 13649, 13669, 13679, 13681, 13687, + 13691, 13693, 13697, 13709, 13711, 13721, 13723, 13729, 13751, 13757, 13759, + 13763, 13781, 13789, 13799, 13807, 13829, 13831, 13841, 13859, 13873, 13877, + 13879, 13883, 13901, 13903, 13907, 13913, 13921, 13931, 13933, 13963, 13967, + 13997, 13999, 14009, 14011, 14029, 14033, 14051, 14057, 14071, 14081, 14083, + 14087, 14107, 14143, 14149, 14153, 14159, 14173, 14177, 14197, 14207, 14221, + 14243, 14249, 14251, 14281, 14293, 14303, 14321, 14323, 14327, 14341, 14347, + 14369, 14387, 14389, 14401, 14407, 14411, 14419, 14423, 14431, 14437, 14447, + 14449, 14461, 14479, 14489, 14503, 14519, 14533, 14537, 14543, 14549, 14551, + 14557, 14561, 14563, 14591, 14593, 14621, 14627, 14629, 14633, 14639, 14653, + 14657, 14669, 14683, 14699, 14713, 14717, 14723, 14731, 14737, 14741, 14747, + 14753, 14759, 14767, 14771, 14779, 14783, 14797, 14813, 14821, 14827, 14831, + 14843, 14851, 14867, 14869, 14879, 14887, 14891, 14897, 14923, 14929, 14939, + 14947, 14951, 14957, 14969, 14983, 15013, 15017, 15031, 15053, 15061, 15073, + 15077, 15083, 15091, 15101, 15107, 15121, 15131, 15137, 15139, 15149, 15161, + 15173, 15187, 15193, 15199, 15217, 15227, 15233, 15241, 15259, 15263, 15269, + 15271, 15277, 15287, 15289, 15299, 15307, 15313, 15319, 15329, 15331, 15349, + 15359, 15361, 15373, 15377, 15383, 15391, 15401, 15413, 15427, 15439, 15443, + 15451, 15461, 15467, 15473, 15493, 15497, 15511, 15527, 15541, 15551, 15559, + 15569, 15581, 15583, 15601, 15607, 15619, 15629, 15641, 15643, 15647, 15649, + 15661, 15667, 15671, 15679, 15683, 15727, 15731, 15733, 15737, 15739, 15749, + 15761, 15767, 15773, 15787, 15791, 15797, 15803, 15809, 15817, 15823, 15859, + 15877, 15881, 15887, 15889, 15901, 15907, 15913, 15919, 15923, 15937, 15959, + 15971, 15973, 15991, 16001, 16007, 16033, 16057, 16061, 16063, 16067, 16069, + 16073, 16087, 16091, 16097, 16103, 16111, 16127, 16139, 16141, 16183, 16187, + 16189, 16193, 16217, 16223, 16229, 16231, 16249, 16253, 16267, 16273, 16301, + 16319, 16333, 16339, 16349, 16361, 16363, 16369, 16381, 16411, 16417, 16421, + 16427, 16433, 16447, 16451, 16453, 16477, 16481, 16487, 16493, 16519, 16529, + 16547, 16553, 16561, 16567, 16573, 16603, 16607, 16619, 16631, 16633, 16649, + 16651, 16657, 16661, 16673, 16691, 16693, 16699, 16703, 16729, 16741, 16747, + 16759, 16763, 16787, 16811, 16823, 16829, 16831, 16843, 16871, 16879, 16883, + 16889, 16901, 16903, 16921, 16927, 16931, 16937, 16943, 16963, 16979, 16981, + 16987, 16993, 17011, 17021, 17027, 17029, 17033, 17041, 17047, 17053, 17077, + 17093, 17099, 17107, 17117, 17123, 17137, 17159, 17167, 17183, 17189, 17191, + 17203, 17207, 17209, 17231, 17239, 17257, 17291, 17293, 17299, 17317, 17321, + 17327, 17333, 17341, 17351, 17359, 17377, 17383, 17387, 17389, 17393, 17401, + 17417, 17419, 17431, 17443, 17449, 17467, 17471, 17477, 17483, 17489, 17491, + 17497, 17509, 17519, 17539, 17551, 17569, 17573, 17579, 17581, 17597, 17599, + 17609, 17623, 17627, 17657, 17659, 17669, 17681, 17683, 17707, 17713, 17729, + 17737, 17747, 17749, 17761, 17783, 17789, 17791, 17807, 17827, 17837, 17839, + 17851, 17863, +}; + +static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1, + const BIGNUM *a1_odd, int k, BN_CTX *ctx, BN_MONT_CTX *mont); +static int probable_prime(BIGNUM *rnd, int bits); +static int probable_prime_dh(BIGNUM *rnd, int bits, const BIGNUM *add, + const BIGNUM *rem, BN_CTX *ctx); +static int probable_prime_dh_safe(BIGNUM *rnd, int bits, const BIGNUM *add, + const BIGNUM *rem, BN_CTX *ctx); + +void BN_GENCB_set(BN_GENCB *callback, + int (*f)(int event, int n, struct bn_gencb_st *), + void *arg) { + callback->callback = f; + callback->arg = arg; +} + +int BN_GENCB_call(BN_GENCB *callback, int event, int n) { + if (!callback) { + return 1; + } + + return callback->callback(event, n, callback); +} + +int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe, const BIGNUM *add, + const BIGNUM *rem, BN_GENCB *cb) { + BIGNUM *t; + int found = 0; + int i, j, c1 = 0; + BN_CTX *ctx; + int checks = BN_prime_checks_for_size(bits); + + if (bits < 2) { + /* There are no prime numbers this small. */ + OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL); + return 0; + } else if (bits == 2 && safe) { + /* The smallest safe prime (7) is three bits. */ + OPENSSL_PUT_ERROR(BN, BN_R_BITS_TOO_SMALL); + return 0; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + t = BN_CTX_get(ctx); + if (!t) { + goto err; + } + +loop: + /* make a random number and set the top and bottom bits */ + if (add == NULL) { + if (!probable_prime(ret, bits)) { + goto err; + } + } else { + if (safe) { + if (!probable_prime_dh_safe(ret, bits, add, rem, ctx)) { + goto err; + } + } else { + if (!probable_prime_dh(ret, bits, add, rem, ctx)) { + goto err; + } + } + } + + if (!BN_GENCB_call(cb, BN_GENCB_GENERATED, c1++)) { + /* aborted */ + goto err; + } + + if (!safe) { + i = BN_is_prime_fasttest_ex(ret, checks, ctx, 0, cb); + if (i == -1) { + goto err; + } else if (i == 0) { + goto loop; + } + } else { + /* for "safe prime" generation, check that (p-1)/2 is prime. Since a prime + * is odd, We just need to divide by 2 */ + if (!BN_rshift1(t, ret)) { + goto err; + } + + for (i = 0; i < checks; i++) { + j = BN_is_prime_fasttest_ex(ret, 1, ctx, 0, NULL); + if (j == -1) { + goto err; + } else if (j == 0) { + goto loop; + } + + j = BN_is_prime_fasttest_ex(t, 1, ctx, 0, NULL); + if (j == -1) { + goto err; + } else if (j == 0) { + goto loop; + } + + if (!BN_GENCB_call(cb, i, c1 - 1)) { + goto err; + } + /* We have a safe prime test pass */ + } + } + + /* we have a prime :-) */ + found = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + + return found; +} + +int BN_primality_test(int *is_probably_prime, const BIGNUM *candidate, + int checks, BN_CTX *ctx, int do_trial_division, + BN_GENCB *cb) { + switch (BN_is_prime_fasttest_ex(candidate, checks, ctx, do_trial_division, cb)) { + case 1: + *is_probably_prime = 1; + return 1; + case 0: + *is_probably_prime = 0; + return 1; + default: + *is_probably_prime = 0; + return 0; + } +} + +int BN_is_prime_ex(const BIGNUM *candidate, int checks, BN_CTX *ctx, BN_GENCB *cb) { + return BN_is_prime_fasttest_ex(candidate, checks, ctx, 0, cb); +} + +int BN_is_prime_fasttest_ex(const BIGNUM *a, int checks, BN_CTX *ctx_passed, + int do_trial_division, BN_GENCB *cb) { + int i, j, ret = -1; + int k; + BN_CTX *ctx = NULL; + BIGNUM *A1, *A1_odd, *check; /* taken from ctx */ + BN_MONT_CTX *mont = NULL; + const BIGNUM *A = NULL; + + if (BN_cmp(a, BN_value_one()) <= 0) { + return 0; + } + + if (checks == BN_prime_checks) { + checks = BN_prime_checks_for_size(BN_num_bits(a)); + } + + /* first look for small factors */ + if (!BN_is_odd(a)) { + /* a is even => a is prime if and only if a == 2 */ + return BN_is_word(a, 2); + } + + if (do_trial_division) { + for (i = 1; i < NUMPRIMES; i++) { + if (BN_mod_word(a, primes[i]) == 0) { + return 0; + } + } + + if (!BN_GENCB_call(cb, 1, -1)) { + goto err; + } + } + + if (ctx_passed != NULL) { + ctx = ctx_passed; + } else if ((ctx = BN_CTX_new()) == NULL) { + goto err; + } + BN_CTX_start(ctx); + + /* A := abs(a) */ + if (a->neg) { + BIGNUM *t = BN_CTX_get(ctx); + if (t == NULL || !BN_copy(t, a)) { + goto err; + } + t->neg = 0; + A = t; + } else { + A = a; + } + + A1 = BN_CTX_get(ctx); + A1_odd = BN_CTX_get(ctx); + check = BN_CTX_get(ctx); + if (check == NULL) { + goto err; + } + + /* compute A1 := A - 1 */ + if (!BN_copy(A1, A)) { + goto err; + } + if (!BN_sub_word(A1, 1)) { + goto err; + } + if (BN_is_zero(A1)) { + ret = 0; + goto err; + } + + /* write A1 as A1_odd * 2^k */ + k = 1; + while (!BN_is_bit_set(A1, k)) { + k++; + } + if (!BN_rshift(A1_odd, A1, k)) { + goto err; + } + + /* Montgomery setup for computations mod A */ + mont = BN_MONT_CTX_new(); + if (mont == NULL) { + goto err; + } + if (!BN_MONT_CTX_set(mont, A, ctx)) { + goto err; + } + + for (i = 0; i < checks; i++) { + if (!BN_pseudo_rand_range(check, A1)) { + goto err; + } + if (!BN_add_word(check, 1)) { + goto err; + } + /* now 1 <= check < A */ + + j = witness(check, A, A1, A1_odd, k, ctx, mont); + if (j == -1) { + goto err; + } + if (j) { + ret = 0; + goto err; + } + if (!BN_GENCB_call(cb, 1, i)) { + goto err; + } + } + ret = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + if (ctx_passed == NULL) { + BN_CTX_free(ctx); + } + } + if (mont != NULL) { + BN_MONT_CTX_free(mont); + } + + return ret; +} + +static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1, + const BIGNUM *a1_odd, int k, BN_CTX *ctx, + BN_MONT_CTX *mont) { + if (!BN_mod_exp_mont(w, w, a1_odd, a, ctx, mont)) { /* w := w^a1_odd mod a */ + return -1; + } + if (BN_is_one(w)) { + return 0; /* probably prime */ + } + if (BN_cmp(w, a1) == 0) { + return 0; /* w == -1 (mod a), 'a' is probably prime */ + } + + while (--k) { + if (!BN_mod_mul(w, w, w, a, ctx)) { /* w := w^2 mod a */ + return -1; + } + + if (BN_is_one(w)) { + return 1; /* 'a' is composite, otherwise a previous 'w' would + * have been == -1 (mod 'a') */ + } + + if (BN_cmp(w, a1) == 0) { + return 0; /* w == -1 (mod a), 'a' is probably prime */ + } + } + + /* If we get here, 'w' is the (a-1)/2-th power of the original 'w', + * and it is neither -1 nor +1 -- so 'a' cannot be prime */ + return 1; +} + +static BN_ULONG get_word(const BIGNUM *bn) { + if (bn->top == 1) { + return bn->d[0]; + } + return 0; +} + +static int probable_prime(BIGNUM *rnd, int bits) { + int i; + uint16_t mods[NUMPRIMES]; + BN_ULONG delta; + BN_ULONG maxdelta = BN_MASK2 - primes[NUMPRIMES - 1]; + char is_single_word = bits <= BN_BITS2; + +again: + if (!BN_rand(rnd, bits, 1, 1)) { + return 0; + } + + /* we now have a random number 'rnd' to test. */ + for (i = 1; i < NUMPRIMES; i++) { + mods[i] = (uint16_t)BN_mod_word(rnd, (BN_ULONG)primes[i]); + } + /* If bits is so small that it fits into a single word then we + * additionally don't want to exceed that many bits. */ + if (is_single_word) { + BN_ULONG size_limit; + if (bits == BN_BITS2) { + /* Avoid undefined behavior. */ + size_limit = ~((BN_ULONG)0) - get_word(rnd); + } else { + size_limit = (((BN_ULONG)1) << bits) - get_word(rnd) - 1; + } + if (size_limit < maxdelta) { + maxdelta = size_limit; + } + } + delta = 0; + +loop: + if (is_single_word) { + BN_ULONG rnd_word = get_word(rnd); + + /* In the case that the candidate prime is a single word then + * we check that: + * 1) It's greater than primes[i] because we shouldn't reject + * 3 as being a prime number because it's a multiple of + * three. + * 2) That it's not a multiple of a known prime. We don't + * check that rnd-1 is also coprime to all the known + * primes because there aren't many small primes where + * that's true. */ + for (i = 1; i < NUMPRIMES && primes[i] < rnd_word; i++) { + if ((mods[i] + delta) % primes[i] == 0) { + delta += 2; + if (delta > maxdelta) { + goto again; + } + goto loop; + } + } + } else { + for (i = 1; i < NUMPRIMES; i++) { + /* check that rnd is not a prime and also + * that gcd(rnd-1,primes) == 1 (except for 2) */ + if (((mods[i] + delta) % primes[i]) <= 1) { + delta += 2; + if (delta > maxdelta) { + goto again; + } + goto loop; + } + } + } + + if (!BN_add_word(rnd, delta)) { + return 0; + } + if (BN_num_bits(rnd) != bits) { + goto again; + } + + return 1; +} + +static int probable_prime_dh(BIGNUM *rnd, int bits, const BIGNUM *add, + const BIGNUM *rem, BN_CTX *ctx) { + int i, ret = 0; + BIGNUM *t1; + + BN_CTX_start(ctx); + if ((t1 = BN_CTX_get(ctx)) == NULL) { + goto err; + } + + if (!BN_rand(rnd, bits, 0, 1)) { + goto err; + } + + /* we need ((rnd-rem) % add) == 0 */ + + if (!BN_mod(t1, rnd, add, ctx)) { + goto err; + } + if (!BN_sub(rnd, rnd, t1)) { + goto err; + } + if (rem == NULL) { + if (!BN_add_word(rnd, 1)) { + goto err; + } + } else { + if (!BN_add(rnd, rnd, rem)) { + goto err; + } + } + /* we now have a random number 'rand' to test. */ + +loop: + for (i = 1; i < NUMPRIMES; i++) { + /* check that rnd is a prime */ + if (BN_mod_word(rnd, (BN_ULONG)primes[i]) <= 1) { + if (!BN_add(rnd, rnd, add)) { + goto err; + } + goto loop; + } + } + + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +static int probable_prime_dh_safe(BIGNUM *p, int bits, const BIGNUM *padd, + const BIGNUM *rem, BN_CTX *ctx) { + int i, ret = 0; + BIGNUM *t1, *qadd, *q; + + bits--; + BN_CTX_start(ctx); + t1 = BN_CTX_get(ctx); + q = BN_CTX_get(ctx); + qadd = BN_CTX_get(ctx); + if (qadd == NULL) { + goto err; + } + + if (!BN_rshift1(qadd, padd)) { + goto err; + } + + if (!BN_rand(q, bits, 0, 1)) { + goto err; + } + + /* we need ((rnd-rem) % add) == 0 */ + if (!BN_mod(t1, q, qadd, ctx)) { + goto err; + } + + if (!BN_sub(q, q, t1)) { + goto err; + } + + if (rem == NULL) { + if (!BN_add_word(q, 1)) { + goto err; + } + } else { + if (!BN_rshift1(t1, rem)) { + goto err; + } + if (!BN_add(q, q, t1)) { + goto err; + } + } + + /* we now have a random number 'rand' to test. */ + if (!BN_lshift1(p, q)) { + goto err; + } + if (!BN_add_word(p, 1)) { + goto err; + } + +loop: + for (i = 1; i < NUMPRIMES; i++) { + /* check that p and q are prime */ + /* check that for p and q + * gcd(p-1,primes) == 1 (except for 2) */ + if ((BN_mod_word(p, (BN_ULONG)primes[i]) == 0) || + (BN_mod_word(q, (BN_ULONG)primes[i]) == 0)) { + if (!BN_add(p, p, padd)) { + goto err; + } + if (!BN_add(q, q, qadd)) { + goto err; + } + goto loop; + } + } + + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/random.c b/TMessagesProj/jni/boringssl/crypto/bn/random.c new file mode 100644 index 00000000..3116e547 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/random.c @@ -0,0 +1,326 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include +#include +#include + +int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) { + uint8_t *buf = NULL; + int ret = 0, bit, bytes, mask; + + if (rnd == NULL) { + return 0; + } + + if (bits == 0) { + BN_zero(rnd); + return 1; + } + + bytes = (bits + 7) / 8; + bit = (bits - 1) % 8; + mask = 0xff << (bit + 1); + + buf = OPENSSL_malloc(bytes); + if (buf == NULL) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* Make a random number and set the top and bottom bits. */ + if (!RAND_bytes(buf, bytes)) { + goto err; + } + + if (top != -1) { + if (top && bits > 1) { + if (bit == 0) { + buf[0] = 1; + buf[1] |= 0x80; + } else { + buf[0] |= (3 << (bit - 1)); + } + } else { + buf[0] |= (1 << bit); + } + } + + buf[0] &= ~mask; + + /* set bottom bit if requested */ + if (bottom) { + buf[bytes - 1] |= 1; + } + + if (!BN_bin2bn(buf, bytes, rnd)) { + goto err; + } + + ret = 1; + +err: + if (buf != NULL) { + OPENSSL_cleanse(buf, bytes); + OPENSSL_free(buf); + } + return (ret); +} + +int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom) { + return BN_rand(rnd, bits, top, bottom); +} + +int BN_rand_range(BIGNUM *r, const BIGNUM *range) { + unsigned n; + unsigned count = 100; + + if (range->neg || BN_is_zero(range)) { + OPENSSL_PUT_ERROR(BN, BN_R_INVALID_RANGE); + return 0; + } + + n = BN_num_bits(range); /* n > 0 */ + + /* BN_is_bit_set(range, n - 1) always holds */ + if (n == 1) { + BN_zero(r); + } else if (!BN_is_bit_set(range, n - 2) && !BN_is_bit_set(range, n - 3)) { + /* range = 100..._2, + * so 3*range (= 11..._2) is exactly one bit longer than range */ + do { + if (!BN_rand(r, n + 1, -1 /* don't set most significant bits */, + 0 /* don't set least significant bits */)) { + return 0; + } + + /* If r < 3*range, use r := r MOD range (which is either r, r - range, or + * r - 2*range). Otherwise, iterate again. Since 3*range = 11..._2, each + * iteration succeeds with probability >= .75. */ + if (BN_cmp(r, range) >= 0) { + if (!BN_sub(r, r, range)) { + return 0; + } + if (BN_cmp(r, range) >= 0) { + if (!BN_sub(r, r, range)) { + return 0; + } + } + } + + if (!--count) { + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS); + return 0; + } + } while (BN_cmp(r, range) >= 0); + } else { + do { + /* range = 11..._2 or range = 101..._2 */ + if (!BN_rand(r, n, -1, 0)) { + return 0; + } + + if (!--count) { + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS); + return 0; + } + } while (BN_cmp(r, range) >= 0); + } + + return 1; +} + +int BN_pseudo_rand_range(BIGNUM *r, const BIGNUM *range) { + return BN_rand_range(r, range); +} + +int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, const BIGNUM *priv, + const uint8_t *message, size_t message_len, + BN_CTX *ctx) { + SHA512_CTX sha; + /* We use 512 bits of random data per iteration to + * ensure that we have at least |range| bits of randomness. */ + uint8_t random_bytes[64]; + uint8_t digest[SHA512_DIGEST_LENGTH]; + size_t done, todo, attempt; + const unsigned num_k_bytes = BN_num_bytes(range); + const unsigned bits_to_mask = (8 - (BN_num_bits(range) % 8)) % 8; + uint8_t private_bytes[96]; + uint8_t *k_bytes = NULL; + int ret = 0; + + if (out == NULL) { + return 0; + } + + if (BN_is_zero(range)) { + OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO); + goto err; + } + + k_bytes = OPENSSL_malloc(num_k_bytes); + if (!k_bytes) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* We copy |priv| into a local buffer to avoid furthur exposing its + * length. */ + todo = sizeof(priv->d[0]) * priv->top; + if (todo > sizeof(private_bytes)) { + /* No reasonable DSA or ECDSA key should have a private key + * this large and we don't handle this case in order to avoid + * leaking the length of the private key. */ + OPENSSL_PUT_ERROR(BN, BN_R_PRIVATE_KEY_TOO_LARGE); + goto err; + } + memcpy(private_bytes, priv->d, todo); + memset(private_bytes + todo, 0, sizeof(private_bytes) - todo); + + for (attempt = 0;; attempt++) { + for (done = 0; done < num_k_bytes;) { + if (!RAND_bytes(random_bytes, sizeof(random_bytes))) { + goto err; + } + SHA512_Init(&sha); + SHA512_Update(&sha, &attempt, sizeof(attempt)); + SHA512_Update(&sha, &done, sizeof(done)); + SHA512_Update(&sha, private_bytes, sizeof(private_bytes)); + SHA512_Update(&sha, message, message_len); + SHA512_Update(&sha, random_bytes, sizeof(random_bytes)); + SHA512_Final(digest, &sha); + + todo = num_k_bytes - done; + if (todo > SHA512_DIGEST_LENGTH) { + todo = SHA512_DIGEST_LENGTH; + } + memcpy(k_bytes + done, digest, todo); + done += todo; + } + + k_bytes[0] &= 0xff >> bits_to_mask; + + if (!BN_bin2bn(k_bytes, num_k_bytes, out)) { + goto err; + } + if (BN_cmp(out, range) < 0) { + break; + } + } + + ret = 1; + +err: + OPENSSL_free(k_bytes); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/rsaz_exp.c b/TMessagesProj/jni/boringssl/crypto/bn/rsaz_exp.c new file mode 100644 index 00000000..c8027520 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/rsaz_exp.c @@ -0,0 +1,326 @@ +/***************************************************************************** +* * +* Copyright (c) 2012, Intel Corporation * +* * +* All rights reserved. * +* * +* Redistribution and use in source and binary forms, with or without * +* modification, are permitted provided that the following conditions are * +* met: * +* * +* * Redistributions of source code must retain the above copyright * +* notice, this list of conditions and the following disclaimer. * +* * +* * 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. * +* * +* * Neither the name of the Intel Corporation nor the names of its * +* contributors may be used to endorse or promote products derived from * +* this software without specific prior written permission. * +* * +* * +* THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY * +* EXPRESS 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 INTEL CORPORATION OR * +* 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. * +* * +****************************************************************************** +* Developers and authors: * +* Shay Gueron (1, 2), and Vlad Krasnov (1) * +* (1) Intel Corporation, Israel Development Center, Haifa, Israel * +* (2) University of Haifa, Israel * +*****************************************************************************/ + +#include + +#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) + +#include "rsaz_exp.h" + +#include + +/* + * See crypto/bn/asm/rsaz-avx2.pl for further details. + */ +void rsaz_1024_norm2red_avx2(void *red,const void *norm); +void rsaz_1024_mul_avx2(void *ret,const void *a,const void *b,const void *n,BN_ULONG k); +void rsaz_1024_sqr_avx2(void *ret,const void *a,const void *n,BN_ULONG k,int cnt); +void rsaz_1024_scatter5_avx2(void *tbl,const void *val,int i); +void rsaz_1024_gather5_avx2(void *val,const void *tbl,int i); +void rsaz_1024_red2norm_avx2(void *norm,const void *red); + +#if defined(__GNUC__) +# define ALIGN64 __attribute__((aligned(64))) +#elif defined(_MSC_VER) +# define ALIGN64 __declspec(align(64)) +#elif defined(__SUNPRO_C) +# define ALIGN64 +# pragma align 64(one,two80) +#else +# define ALIGN64 /* not fatal, might hurt performance a little */ +#endif + +ALIGN64 static const BN_ULONG one[40] = + {1,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +ALIGN64 static const BN_ULONG two80[40] = + {0,0,1<<22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + +void RSAZ_1024_mod_exp_avx2(BN_ULONG result_norm[16], + const BN_ULONG base_norm[16], const BN_ULONG exponent[16], + const BN_ULONG m_norm[16], const BN_ULONG RR[16], BN_ULONG k0) +{ + unsigned char storage[320*3+32*9*16+64]; /* 5.5KB */ + unsigned char *p_str = storage + (64-((size_t)storage%64)); + unsigned char *a_inv, *m, *result, + *table_s = p_str+320*3, + *R2 = table_s; /* borrow */ + int index; + int wvalue; + + if ((((size_t)p_str&4095)+320)>>12) { + result = p_str; + a_inv = p_str + 320; + m = p_str + 320*2; /* should not cross page */ + } else { + m = p_str; /* should not cross page */ + result = p_str + 320; + a_inv = p_str + 320*2; + } + + rsaz_1024_norm2red_avx2(m, m_norm); + rsaz_1024_norm2red_avx2(a_inv, base_norm); + rsaz_1024_norm2red_avx2(R2, RR); + + rsaz_1024_mul_avx2(R2, R2, R2, m, k0); + rsaz_1024_mul_avx2(R2, R2, two80, m, k0); + + /* table[0] = 1 */ + rsaz_1024_mul_avx2(result, R2, one, m, k0); + /* table[1] = a_inv^1 */ + rsaz_1024_mul_avx2(a_inv, a_inv, R2, m, k0); + + rsaz_1024_scatter5_avx2(table_s,result,0); + rsaz_1024_scatter5_avx2(table_s,a_inv,1); + + /* table[2] = a_inv^2 */ + rsaz_1024_sqr_avx2(result, a_inv, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,2); +#if 0 + /* this is almost 2x smaller and less than 1% slower */ + for (index=3; index<32; index++) { + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,index); + } +#else + /* table[4] = a_inv^4 */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,4); + /* table[8] = a_inv^8 */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,8); + /* table[16] = a_inv^16 */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,16); + /* table[17] = a_inv^17 */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,17); + + /* table[3] */ + rsaz_1024_gather5_avx2(result,table_s,2); + rsaz_1024_mul_avx2(result,result,a_inv,m,k0); + rsaz_1024_scatter5_avx2(table_s,result,3); + /* table[6] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,6); + /* table[12] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,12); + /* table[24] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,24); + /* table[25] */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,25); + + /* table[5] */ + rsaz_1024_gather5_avx2(result,table_s,4); + rsaz_1024_mul_avx2(result,result,a_inv,m,k0); + rsaz_1024_scatter5_avx2(table_s,result,5); + /* table[10] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,10); + /* table[20] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,20); + /* table[21] */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,21); + + /* table[7] */ + rsaz_1024_gather5_avx2(result,table_s,6); + rsaz_1024_mul_avx2(result,result,a_inv,m,k0); + rsaz_1024_scatter5_avx2(table_s,result,7); + /* table[14] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,14); + /* table[28] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,28); + /* table[29] */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,29); + + /* table[9] */ + rsaz_1024_gather5_avx2(result,table_s,8); + rsaz_1024_mul_avx2(result,result,a_inv,m,k0); + rsaz_1024_scatter5_avx2(table_s,result,9); + /* table[18] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,18); + /* table[19] */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,19); + + /* table[11] */ + rsaz_1024_gather5_avx2(result,table_s,10); + rsaz_1024_mul_avx2(result,result,a_inv,m,k0); + rsaz_1024_scatter5_avx2(table_s,result,11); + /* table[22] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,22); + /* table[23] */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,23); + + /* table[13] */ + rsaz_1024_gather5_avx2(result,table_s,12); + rsaz_1024_mul_avx2(result,result,a_inv,m,k0); + rsaz_1024_scatter5_avx2(table_s,result,13); + /* table[26] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,26); + /* table[27] */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,27); + + /* table[15] */ + rsaz_1024_gather5_avx2(result,table_s,14); + rsaz_1024_mul_avx2(result,result,a_inv,m,k0); + rsaz_1024_scatter5_avx2(table_s,result,15); + /* table[30] */ + rsaz_1024_sqr_avx2(result, result, m, k0, 1); + rsaz_1024_scatter5_avx2(table_s,result,30); + /* table[31] */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + rsaz_1024_scatter5_avx2(table_s,result,31); +#endif + + /* load first window */ + p_str = (unsigned char*)exponent; + wvalue = p_str[127] >> 3; + rsaz_1024_gather5_avx2(result,table_s,wvalue); + + index = 1014; + + while(index > -1) { /* loop for the remaining 127 windows */ + + rsaz_1024_sqr_avx2(result, result, m, k0, 5); + + wvalue = *((unsigned short*)&p_str[index/8]); + wvalue = (wvalue>> (index%8)) & 31; + index-=5; + + rsaz_1024_gather5_avx2(a_inv,table_s,wvalue); /* borrow a_inv */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + } + + /* square four times */ + rsaz_1024_sqr_avx2(result, result, m, k0, 4); + + wvalue = p_str[0] & 15; + + rsaz_1024_gather5_avx2(a_inv,table_s,wvalue); /* borrow a_inv */ + rsaz_1024_mul_avx2(result, result, a_inv, m, k0); + + /* from Montgomery */ + rsaz_1024_mul_avx2(result, result, one, m, k0); + + rsaz_1024_red2norm_avx2(result_norm, result); + + OPENSSL_cleanse(storage,sizeof(storage)); +} + +/* + * See crypto/bn/rsaz-x86_64.pl for further details. + */ +void rsaz_512_mul(void *ret,const void *a,const void *b,const void *n,BN_ULONG k); +void rsaz_512_mul_scatter4(void *ret,const void *a,const void *n,BN_ULONG k,const void *tbl,unsigned int power); +void rsaz_512_mul_gather4(void *ret,const void *a,const void *tbl,const void *n,BN_ULONG k,unsigned int power); +void rsaz_512_mul_by_one(void *ret,const void *a,const void *n,BN_ULONG k); +void rsaz_512_sqr(void *ret,const void *a,const void *n,BN_ULONG k,int cnt); +void rsaz_512_scatter4(void *tbl, const BN_ULONG *val, int power); +void rsaz_512_gather4(BN_ULONG *val, const void *tbl, int power); + +void RSAZ_512_mod_exp(BN_ULONG result[8], + const BN_ULONG base[8], const BN_ULONG exponent[8], + const BN_ULONG m[8], BN_ULONG k0, const BN_ULONG RR[8]) +{ + unsigned char storage[16*8*8+64*2+64]; /* 1.2KB */ + unsigned char *table = storage + (64-((size_t)storage%64)); + BN_ULONG *a_inv = (BN_ULONG *)(table+16*8*8), + *temp = (BN_ULONG *)(table+16*8*8+8*8); + unsigned char *p_str = (unsigned char*)exponent; + int index; + unsigned int wvalue; + + /* table[0] = 1_inv */ + temp[0] = 0-m[0]; temp[1] = ~m[1]; + temp[2] = ~m[2]; temp[3] = ~m[3]; + temp[4] = ~m[4]; temp[5] = ~m[5]; + temp[6] = ~m[6]; temp[7] = ~m[7]; + rsaz_512_scatter4(table, temp, 0); + + /* table [1] = a_inv^1 */ + rsaz_512_mul(a_inv, base, RR, m, k0); + rsaz_512_scatter4(table, a_inv, 1); + + /* table [2] = a_inv^2 */ + rsaz_512_sqr(temp, a_inv, m, k0, 1); + rsaz_512_scatter4(table, temp, 2); + + for (index=3; index<16; index++) + rsaz_512_mul_scatter4(temp, a_inv, m, k0, table, index); + + /* load first window */ + wvalue = p_str[63]; + + rsaz_512_gather4(temp, table, wvalue>>4); + rsaz_512_sqr(temp, temp, m, k0, 4); + rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue&0xf); + + for (index=62; index>=0; index--) { + wvalue = p_str[index]; + + rsaz_512_sqr(temp, temp, m, k0, 4); + rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue>>4); + + rsaz_512_sqr(temp, temp, m, k0, 4); + rsaz_512_mul_gather4(temp, temp, table, m, k0, wvalue&0x0f); + } + + /* from Montgomery */ + rsaz_512_mul_by_one(result, temp, m, k0); + + OPENSSL_cleanse(storage,sizeof(storage)); +} + +#endif /* OPENSSL_X86_64 */ diff --git a/TMessagesProj/jni/boringssl/crypto/bn/rsaz_exp.h b/TMessagesProj/jni/boringssl/crypto/bn/rsaz_exp.h new file mode 100644 index 00000000..c752b45f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/rsaz_exp.h @@ -0,0 +1,56 @@ +/***************************************************************************** +* * +* Copyright (c) 2012, Intel Corporation * +* * +* All rights reserved. * +* * +* Redistribution and use in source and binary forms, with or without * +* modification, are permitted provided that the following conditions are * +* met: * +* * +* * Redistributions of source code must retain the above copyright * +* notice, this list of conditions and the following disclaimer. * +* * +* * 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. * +* * +* * Neither the name of the Intel Corporation nor the names of its * +* contributors may be used to endorse or promote products derived from * +* this software without specific prior written permission. * +* * +* * +* THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY * +* EXPRESS 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 INTEL CORPORATION OR * +* 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. * +* * +****************************************************************************** +* Developers and authors: * +* Shay Gueron (1, 2), and Vlad Krasnov (1) * +* (1) Intel Corporation, Israel Development Center, Haifa, Israel * +* (2) University of Haifa, Israel * +*****************************************************************************/ + +#ifndef RSAZ_EXP_H +#define RSAZ_EXP_H + +#include + +void RSAZ_1024_mod_exp_avx2(BN_ULONG result[16], + const BN_ULONG base_norm[16], const BN_ULONG exponent[16], + const BN_ULONG m_norm[16], const BN_ULONG RR[16], BN_ULONG k0); +int rsaz_avx2_eligible(void); + +void RSAZ_512_mod_exp(BN_ULONG result[8], + const BN_ULONG base_norm[8], const BN_ULONG exponent[8], + const BN_ULONG m_norm[8], BN_ULONG k0, const BN_ULONG RR[8]); +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/bn/shift.c b/TMessagesProj/jni/boringssl/crypto/bn/shift.c new file mode 100644 index 00000000..defec929 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/shift.c @@ -0,0 +1,299 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + +#include "internal.h" + + +int BN_lshift(BIGNUM *r, const BIGNUM *a, int n) { + int i, nw, lb, rb; + BN_ULONG *t, *f; + BN_ULONG l; + + if (n < 0) { + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); + return 0; + } + + r->neg = a->neg; + nw = n / BN_BITS2; + if (bn_wexpand(r, a->top + nw + 1) == NULL) { + return 0; + } + lb = n % BN_BITS2; + rb = BN_BITS2 - lb; + f = a->d; + t = r->d; + t[a->top + nw] = 0; + if (lb == 0) { + for (i = a->top - 1; i >= 0; i--) { + t[nw + i] = f[i]; + } + } else { + for (i = a->top - 1; i >= 0; i--) { + l = f[i]; + t[nw + i + 1] |= (l >> rb) & BN_MASK2; + t[nw + i] = (l << lb) & BN_MASK2; + } + } + memset(t, 0, nw * sizeof(t[0])); + r->top = a->top + nw + 1; + bn_correct_top(r); + + return 1; +} + +int BN_lshift1(BIGNUM *r, const BIGNUM *a) { + BN_ULONG *ap, *rp, t, c; + int i; + + if (r != a) { + r->neg = a->neg; + if (bn_wexpand(r, a->top + 1) == NULL) { + return 0; + } + r->top = a->top; + } else { + if (bn_wexpand(r, a->top + 1) == NULL) { + return 0; + } + } + ap = a->d; + rp = r->d; + c = 0; + for (i = 0; i < a->top; i++) { + t = *(ap++); + *(rp++) = ((t << 1) | c) & BN_MASK2; + c = (t & BN_TBIT) ? 1 : 0; + } + if (c) { + *rp = 1; + r->top++; + } + + return 1; +} + +int BN_rshift(BIGNUM *r, const BIGNUM *a, int n) { + int i, j, nw, lb, rb; + BN_ULONG *t, *f; + BN_ULONG l, tmp; + + if (n < 0) { + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); + return 0; + } + + nw = n / BN_BITS2; + rb = n % BN_BITS2; + lb = BN_BITS2 - rb; + if (nw >= a->top || a->top == 0) { + BN_zero(r); + return 1; + } + i = (BN_num_bits(a) - n + (BN_BITS2 - 1)) / BN_BITS2; + if (r != a) { + r->neg = a->neg; + if (bn_wexpand(r, i) == NULL) { + return 0; + } + } else { + if (n == 0) { + return 1; /* or the copying loop will go berserk */ + } + } + + f = &(a->d[nw]); + t = r->d; + j = a->top - nw; + r->top = i; + + if (rb == 0) { + for (i = j; i != 0; i--) { + *(t++) = *(f++); + } + } else { + l = *(f++); + for (i = j - 1; i != 0; i--) { + tmp = (l >> rb) & BN_MASK2; + l = *(f++); + *(t++) = (tmp | (l << lb)) & BN_MASK2; + } + if ((l = (l >> rb) & BN_MASK2)) { + *(t) = l; + } + } + + return 1; +} + +int BN_rshift1(BIGNUM *r, const BIGNUM *a) { + BN_ULONG *ap, *rp, t, c; + int i, j; + + if (BN_is_zero(a)) { + BN_zero(r); + return 1; + } + i = a->top; + ap = a->d; + j = i - (ap[i - 1] == 1); + if (a != r) { + if (bn_wexpand(r, j) == NULL) { + return 0; + } + r->neg = a->neg; + } + rp = r->d; + t = ap[--i]; + c = (t & 1) ? BN_TBIT : 0; + if (t >>= 1) { + rp[i] = t; + } + while (i > 0) { + t = ap[--i]; + rp[i] = ((t >> 1) & BN_MASK2) | c; + c = (t & 1) ? BN_TBIT : 0; + } + r->top = j; + + return 1; +} + +int BN_set_bit(BIGNUM *a, int n) { + int i, j, k; + + if (n < 0) { + return 0; + } + + i = n / BN_BITS2; + j = n % BN_BITS2; + if (a->top <= i) { + if (bn_wexpand(a, i + 1) == NULL) { + return 0; + } + for (k = a->top; k < i + 1; k++) { + a->d[k] = 0; + } + a->top = i + 1; + } + + a->d[i] |= (((BN_ULONG)1) << j); + + return 1; +} + +int BN_clear_bit(BIGNUM *a, int n) { + int i, j; + + if (n < 0) { + return 0; + } + + i = n / BN_BITS2; + j = n % BN_BITS2; + if (a->top <= i) { + return 0; + } + + a->d[i] &= (~(((BN_ULONG)1) << j)); + bn_correct_top(a); + return 1; +} + +int BN_is_bit_set(const BIGNUM *a, int n) { + int i, j; + + if (n < 0) { + return 0; + } + i = n / BN_BITS2; + j = n % BN_BITS2; + if (a->top <= i) { + return 0; + } + + return (a->d[i]>>j)&1; +} + +int BN_mask_bits(BIGNUM *a, int n) { + int b, w; + + if (n < 0) { + return 0; + } + + w = n / BN_BITS2; + b = n % BN_BITS2; + if (w >= a->top) { + return 0; + } + if (b == 0) { + a->top = w; + } else { + a->top = w + 1; + a->d[w] &= ~(BN_MASK2 << b); + } + + bn_correct_top(a); + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bn/sqrt.c b/TMessagesProj/jni/boringssl/crypto/bn/sqrt.c new file mode 100644 index 00000000..2ed66c22 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bn/sqrt.c @@ -0,0 +1,505 @@ +/* Written by Lenka Fibikova + * and Bodo Moeller for the OpenSSL project. */ +/* ==================================================================== + * Copyright (c) 1998-2000 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + + +/* Returns 'ret' such that + * ret^2 == a (mod p), + * using the Tonelli/Shanks algorithm (cf. Henri Cohen, "A Course + * in Algebraic Computational Number Theory", algorithm 1.5.1). + * 'p' must be prime! */ +BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) { + BIGNUM *ret = in; + int err = 1; + int r; + BIGNUM *A, *b, *q, *t, *x, *y; + int e, i, j; + + if (!BN_is_odd(p) || BN_abs_is_word(p, 1)) { + if (BN_abs_is_word(p, 2)) { + if (ret == NULL) { + ret = BN_new(); + } + if (ret == NULL) { + goto end; + } + if (!BN_set_word(ret, BN_is_bit_set(a, 0))) { + if (ret != in) { + BN_free(ret); + } + return NULL; + } + return ret; + } + + OPENSSL_PUT_ERROR(BN, BN_R_P_IS_NOT_PRIME); + return (NULL); + } + + if (BN_is_zero(a) || BN_is_one(a)) { + if (ret == NULL) { + ret = BN_new(); + } + if (ret == NULL) { + goto end; + } + if (!BN_set_word(ret, BN_is_one(a))) { + if (ret != in) { + BN_free(ret); + } + return NULL; + } + return ret; + } + + BN_CTX_start(ctx); + A = BN_CTX_get(ctx); + b = BN_CTX_get(ctx); + q = BN_CTX_get(ctx); + t = BN_CTX_get(ctx); + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + if (y == NULL) { + goto end; + } + + if (ret == NULL) { + ret = BN_new(); + } + if (ret == NULL) { + goto end; + } + + /* A = a mod p */ + if (!BN_nnmod(A, a, p, ctx)) { + goto end; + } + + /* now write |p| - 1 as 2^e*q where q is odd */ + e = 1; + while (!BN_is_bit_set(p, e)) { + e++; + } + /* we'll set q later (if needed) */ + + if (e == 1) { + /* The easy case: (|p|-1)/2 is odd, so 2 has an inverse + * modulo (|p|-1)/2, and square roots can be computed + * directly by modular exponentiation. + * We have + * 2 * (|p|+1)/4 == 1 (mod (|p|-1)/2), + * so we can use exponent (|p|+1)/4, i.e. (|p|-3)/4 + 1. + */ + if (!BN_rshift(q, p, 2)) { + goto end; + } + q->neg = 0; + if (!BN_add_word(q, 1) || + !BN_mod_exp(ret, A, q, p, ctx)) { + goto end; + } + err = 0; + goto vrfy; + } + + if (e == 2) { + /* |p| == 5 (mod 8) + * + * In this case 2 is always a non-square since + * Legendre(2,p) = (-1)^((p^2-1)/8) for any odd prime. + * So if a really is a square, then 2*a is a non-square. + * Thus for + * b := (2*a)^((|p|-5)/8), + * i := (2*a)*b^2 + * we have + * i^2 = (2*a)^((1 + (|p|-5)/4)*2) + * = (2*a)^((p-1)/2) + * = -1; + * so if we set + * x := a*b*(i-1), + * then + * x^2 = a^2 * b^2 * (i^2 - 2*i + 1) + * = a^2 * b^2 * (-2*i) + * = a*(-i)*(2*a*b^2) + * = a*(-i)*i + * = a. + * + * (This is due to A.O.L. Atkin, + * , + * November 1992.) + */ + + /* t := 2*a */ + if (!BN_mod_lshift1_quick(t, A, p)) { + goto end; + } + + /* b := (2*a)^((|p|-5)/8) */ + if (!BN_rshift(q, p, 3)) { + goto end; + } + q->neg = 0; + if (!BN_mod_exp(b, t, q, p, ctx)) { + goto end; + } + + /* y := b^2 */ + if (!BN_mod_sqr(y, b, p, ctx)) { + goto end; + } + + /* t := (2*a)*b^2 - 1*/ + if (!BN_mod_mul(t, t, y, p, ctx) || + !BN_sub_word(t, 1)) { + goto end; + } + + /* x = a*b*t */ + if (!BN_mod_mul(x, A, b, p, ctx) || + !BN_mod_mul(x, x, t, p, ctx)) { + goto end; + } + + if (!BN_copy(ret, x)) { + goto end; + } + err = 0; + goto vrfy; + } + + /* e > 2, so we really have to use the Tonelli/Shanks algorithm. + * First, find some y that is not a square. */ + if (!BN_copy(q, p)) { + goto end; /* use 'q' as temp */ + } + q->neg = 0; + i = 2; + do { + /* For efficiency, try small numbers first; + * if this fails, try random numbers. + */ + if (i < 22) { + if (!BN_set_word(y, i)) { + goto end; + } + } else { + if (!BN_pseudo_rand(y, BN_num_bits(p), 0, 0)) { + goto end; + } + if (BN_ucmp(y, p) >= 0) { + if (!(p->neg ? BN_add : BN_sub)(y, y, p)) { + goto end; + } + } + /* now 0 <= y < |p| */ + if (BN_is_zero(y)) { + if (!BN_set_word(y, i)) { + goto end; + } + } + } + + r = BN_kronecker(y, q, ctx); /* here 'q' is |p| */ + if (r < -1) { + goto end; + } + if (r == 0) { + /* m divides p */ + OPENSSL_PUT_ERROR(BN, BN_R_P_IS_NOT_PRIME); + goto end; + } + } while (r == 1 && ++i < 82); + + if (r != -1) { + /* Many rounds and still no non-square -- this is more likely + * a bug than just bad luck. + * Even if p is not prime, we should have found some y + * such that r == -1. + */ + OPENSSL_PUT_ERROR(BN, BN_R_TOO_MANY_ITERATIONS); + goto end; + } + + /* Here's our actual 'q': */ + if (!BN_rshift(q, q, e)) { + goto end; + } + + /* Now that we have some non-square, we can find an element + * of order 2^e by computing its q'th power. */ + if (!BN_mod_exp(y, y, q, p, ctx)) { + goto end; + } + if (BN_is_one(y)) { + OPENSSL_PUT_ERROR(BN, BN_R_P_IS_NOT_PRIME); + goto end; + } + + /* Now we know that (if p is indeed prime) there is an integer + * k, 0 <= k < 2^e, such that + * + * a^q * y^k == 1 (mod p). + * + * As a^q is a square and y is not, k must be even. + * q+1 is even, too, so there is an element + * + * X := a^((q+1)/2) * y^(k/2), + * + * and it satisfies + * + * X^2 = a^q * a * y^k + * = a, + * + * so it is the square root that we are looking for. + */ + + /* t := (q-1)/2 (note that q is odd) */ + if (!BN_rshift1(t, q)) { + goto end; + } + + /* x := a^((q-1)/2) */ + if (BN_is_zero(t)) /* special case: p = 2^e + 1 */ + { + if (!BN_nnmod(t, A, p, ctx)) { + goto end; + } + if (BN_is_zero(t)) { + /* special case: a == 0 (mod p) */ + BN_zero(ret); + err = 0; + goto end; + } else if (!BN_one(x)) { + goto end; + } + } else { + if (!BN_mod_exp(x, A, t, p, ctx)) { + goto end; + } + if (BN_is_zero(x)) { + /* special case: a == 0 (mod p) */ + BN_zero(ret); + err = 0; + goto end; + } + } + + /* b := a*x^2 (= a^q) */ + if (!BN_mod_sqr(b, x, p, ctx) || + !BN_mod_mul(b, b, A, p, ctx)) { + goto end; + } + + /* x := a*x (= a^((q+1)/2)) */ + if (!BN_mod_mul(x, x, A, p, ctx)) { + goto end; + } + + while (1) { + /* Now b is a^q * y^k for some even k (0 <= k < 2^E + * where E refers to the original value of e, which we + * don't keep in a variable), and x is a^((q+1)/2) * y^(k/2). + * + * We have a*b = x^2, + * y^2^(e-1) = -1, + * b^2^(e-1) = 1. + */ + + if (BN_is_one(b)) { + if (!BN_copy(ret, x)) { + goto end; + } + err = 0; + goto vrfy; + } + + + /* find smallest i such that b^(2^i) = 1 */ + i = 1; + if (!BN_mod_sqr(t, b, p, ctx)) { + goto end; + } + while (!BN_is_one(t)) { + i++; + if (i == e) { + OPENSSL_PUT_ERROR(BN, BN_R_NOT_A_SQUARE); + goto end; + } + if (!BN_mod_mul(t, t, t, p, ctx)) { + goto end; + } + } + + + /* t := y^2^(e - i - 1) */ + if (!BN_copy(t, y)) { + goto end; + } + for (j = e - i - 1; j > 0; j--) { + if (!BN_mod_sqr(t, t, p, ctx)) { + goto end; + } + } + if (!BN_mod_mul(y, t, t, p, ctx) || + !BN_mod_mul(x, x, t, p, ctx) || + !BN_mod_mul(b, b, y, p, ctx)) { + goto end; + } + e = i; + } + +vrfy: + if (!err) { + /* verify the result -- the input might have been not a square + * (test added in 0.9.8) */ + + if (!BN_mod_sqr(x, ret, p, ctx)) { + err = 1; + } + + if (!err && 0 != BN_cmp(x, A)) { + OPENSSL_PUT_ERROR(BN, BN_R_NOT_A_SQUARE); + err = 1; + } + } + +end: + if (err) { + if (ret != in) { + BN_clear_free(ret); + } + ret = NULL; + } + BN_CTX_end(ctx); + return ret; +} + +int BN_sqrt(BIGNUM *out_sqrt, const BIGNUM *in, BN_CTX *ctx) { + BIGNUM *estimate, *tmp, *delta, *last_delta, *tmp2; + int ok = 0, last_delta_valid = 0; + + if (in->neg) { + OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); + return 0; + } + if (BN_is_zero(in)) { + BN_zero(out_sqrt); + return 1; + } + + BN_CTX_start(ctx); + if (out_sqrt == in) { + estimate = BN_CTX_get(ctx); + } else { + estimate = out_sqrt; + } + tmp = BN_CTX_get(ctx); + last_delta = BN_CTX_get(ctx); + delta = BN_CTX_get(ctx); + if (estimate == NULL || tmp == NULL || last_delta == NULL || delta == NULL) { + OPENSSL_PUT_ERROR(BN, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* We estimate that the square root of an n-bit number is 2^{n/2}. */ + BN_lshift(estimate, BN_value_one(), BN_num_bits(in)/2); + + /* This is Newton's method for finding a root of the equation |estimate|^2 - + * |in| = 0. */ + for (;;) { + /* |estimate| = 1/2 * (|estimate| + |in|/|estimate|) */ + if (!BN_div(tmp, NULL, in, estimate, ctx) || + !BN_add(tmp, tmp, estimate) || + !BN_rshift1(estimate, tmp) || + /* |tmp| = |estimate|^2 */ + !BN_sqr(tmp, estimate, ctx) || + /* |delta| = |in| - |tmp| */ + !BN_sub(delta, in, tmp)) { + OPENSSL_PUT_ERROR(BN, ERR_R_BN_LIB); + goto err; + } + + delta->neg = 0; + /* The difference between |in| and |estimate| squared is required to always + * decrease. This ensures that the loop always terminates, but I don't have + * a proof that it always finds the square root for a given square. */ + if (last_delta_valid && BN_cmp(delta, last_delta) >= 0) { + break; + } + + last_delta_valid = 1; + + tmp2 = last_delta; + last_delta = delta; + delta = tmp2; + } + + if (BN_cmp(tmp, in) != 0) { + OPENSSL_PUT_ERROR(BN, BN_R_NOT_A_SQUARE); + goto err; + } + + ok = 1; + +err: + if (ok && out_sqrt == in && !BN_copy(out_sqrt, estimate)) { + ok = 0; + } + BN_CTX_end(ctx); + return ok; +} diff --git a/TMessagesProj/jni/boringssl/crypto/buf/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/buf/CMakeLists.txt new file mode 100644 index 00000000..19edf7d5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/buf/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + buf + + OBJECT + + buf.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/buf/buf.c b/TMessagesProj/jni/boringssl/crypto/buf/buf.c new file mode 100644 index 00000000..13b5cebd --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/buf/buf.c @@ -0,0 +1,235 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include + + +BUF_MEM *BUF_MEM_new(void) { + BUF_MEM *ret; + + ret = OPENSSL_malloc(sizeof(BUF_MEM)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(ret, 0, sizeof(BUF_MEM)); + return ret; +} + +void BUF_MEM_free(BUF_MEM *buf) { + if (buf == NULL) { + return; + } + + if (buf->data != NULL) { + OPENSSL_cleanse(buf->data, buf->max); + OPENSSL_free(buf->data); + } + + OPENSSL_free(buf); +} + +static size_t buf_mem_grow(BUF_MEM *buf, size_t len, char clean) { + char *new_buf; + size_t n, alloc_size; + + if (buf->length >= len) { + buf->length = len; + return len; + } + if (buf->max >= len) { + memset(&buf->data[buf->length], 0, len - buf->length); + buf->length = len; + return len; + } + + n = len + 3; + if (n < len) { + /* overflow */ + OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); + return 0; + } + n = n / 3; + alloc_size = n * 4; + if (alloc_size / 4 != n) { + /* overflow */ + OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (buf->data == NULL) { + new_buf = OPENSSL_malloc(alloc_size); + } else { + if (clean) { + new_buf = OPENSSL_realloc_clean(buf->data, buf->max, alloc_size); + } else { + new_buf = OPENSSL_realloc(buf->data, alloc_size); + } + } + + if (new_buf == NULL) { + OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); + len = 0; + } else { + buf->data = new_buf; + buf->max = alloc_size; + memset(&buf->data[buf->length], 0, len - buf->length); + buf->length = len; + } + + return len; +} + +size_t BUF_MEM_grow(BUF_MEM *buf, size_t len) { + return buf_mem_grow(buf, len, 0 /* don't clear old buffer contents. */); +} + +size_t BUF_MEM_grow_clean(BUF_MEM *buf, size_t len) { + return buf_mem_grow(buf, len, 1 /* clear old buffer contents. */); +} + +char *BUF_strdup(const char *buf) { + if (buf == NULL) { + return NULL; + } + + return BUF_strndup(buf, strlen(buf)); +} + +size_t BUF_strnlen(const char *str, size_t max_len) { + size_t i; + + for (i = 0; i < max_len; i++) { + if (str[i] == 0) { + break; + } + } + + return i; +} + +char *BUF_strndup(const char *buf, size_t size) { + char *ret; + size_t alloc_size; + + if (buf == NULL) { + return NULL; + } + + size = BUF_strnlen(buf, size); + + alloc_size = size + 1; + if (alloc_size < size) { + /* overflow */ + OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); + return NULL; + } + ret = OPENSSL_malloc(alloc_size); + if (ret == NULL) { + OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memcpy(ret, buf, size); + ret[size] = '\0'; + return ret; +} + +size_t BUF_strlcpy(char *dst, const char *src, size_t dst_size) { + size_t l = 0; + + for (; dst_size > 1 && *src; dst_size--) { + *dst++ = *src++; + l++; + } + + if (dst_size) { + *dst = 0; + } + + return l + strlen(src); +} + +size_t BUF_strlcat(char *dst, const char *src, size_t dst_size) { + size_t l = 0; + for (; dst_size > 0 && *dst; dst_size--, dst++) { + l++; + } + return l + BUF_strlcpy(dst, src, dst_size); +} + +void *BUF_memdup(const void *data, size_t dst_size) { + void *ret; + + if (data == NULL) { + return NULL; + } + + ret = OPENSSL_malloc(dst_size); + if (ret == NULL) { + OPENSSL_PUT_ERROR(BUF, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memcpy(ret, data, dst_size); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bytestring/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/bytestring/CMakeLists.txt new file mode 100644 index 00000000..8326054b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bytestring/CMakeLists.txt @@ -0,0 +1,11 @@ +include_directories(. .. ../../include) + +add_library( + bytestring + + OBJECT + + ber.c + cbs.c + cbb.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/bytestring/ber.c b/TMessagesProj/jni/boringssl/crypto/bytestring/ber.c new file mode 100644 index 00000000..e3b150ca --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bytestring/ber.c @@ -0,0 +1,221 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include + +#include "internal.h" + + +/* kMaxDepth is a just a sanity limit. The code should be such that the length + * of the input being processes always decreases. None the less, a very large + * input could otherwise cause the stack to overflow. */ +static const unsigned kMaxDepth = 2048; + +/* cbs_find_ber walks an ASN.1 structure in |orig_in| and sets |*ber_found| + * depending on whether an indefinite length element was found. The value of + * |in| is not changed. It returns one on success (i.e. |*ber_found| was set) + * and zero on error. */ +static int cbs_find_ber(CBS *orig_in, char *ber_found, unsigned depth) { + CBS in; + + if (depth > kMaxDepth) { + return 0; + } + + CBS_init(&in, CBS_data(orig_in), CBS_len(orig_in)); + *ber_found = 0; + + while (CBS_len(&in) > 0) { + CBS contents; + unsigned tag; + size_t header_len; + + if (!CBS_get_any_ber_asn1_element(&in, &contents, &tag, &header_len)) { + return 0; + } + if (CBS_len(&contents) == header_len && + header_len > 0 && + CBS_data(&contents)[header_len-1] == 0x80) { + *ber_found = 1; + return 1; + } + if (tag & CBS_ASN1_CONSTRUCTED) { + if (!CBS_skip(&contents, header_len) || + !cbs_find_ber(&contents, ber_found, depth + 1)) { + return 0; + } + } + } + + return 1; +} + +/* is_primitive_type returns true if |tag| likely a primitive type. Normally + * one can just test the "constructed" bit in the tag but, in BER, even + * primitive tags can have the constructed bit if they have indefinite + * length. */ +static char is_primitive_type(unsigned tag) { + return (tag & 0xc0) == 0 && + (tag & 0x1f) != (CBS_ASN1_SEQUENCE & 0x1f) && + (tag & 0x1f) != (CBS_ASN1_SET & 0x1f); +} + +/* is_eoc returns true if |header_len| and |contents|, as returned by + * |CBS_get_any_ber_asn1_element|, indicate an "end of contents" (EOC) value. */ +static char is_eoc(size_t header_len, CBS *contents) { + return header_len == 2 && CBS_len(contents) == 2 && + memcmp(CBS_data(contents), "\x00\x00", 2) == 0; +} + +/* cbs_convert_ber reads BER data from |in| and writes DER data to |out|. If + * |squash_header| is set then the top-level of elements from |in| will not + * have their headers written. This is used when concatenating the fragments of + * an indefinite length, primitive value. If |looking_for_eoc| is set then any + * EOC elements found will cause the function to return after consuming it. + * It returns one on success and zero on error. */ +static int cbs_convert_ber(CBS *in, CBB *out, char squash_header, + char looking_for_eoc, unsigned depth) { + if (depth > kMaxDepth) { + return 0; + } + + while (CBS_len(in) > 0) { + CBS contents; + unsigned tag; + size_t header_len; + CBB *out_contents, out_contents_storage; + + if (!CBS_get_any_ber_asn1_element(in, &contents, &tag, &header_len)) { + return 0; + } + out_contents = out; + + if (CBS_len(&contents) == header_len) { + if (is_eoc(header_len, &contents)) { + return looking_for_eoc; + } + + if (header_len > 0 && CBS_data(&contents)[header_len - 1] == 0x80) { + /* This is an indefinite length element. If it's a SEQUENCE or SET then + * we just need to write the out the contents as normal, but with a + * concrete length prefix. + * + * If it's a something else then the contents will be a series of BER + * elements of the same type which need to be concatenated. */ + const char context_specific = (tag & 0xc0) == 0x80; + char squash_child_headers = is_primitive_type(tag); + + /* This is a hack, but it sufficies to handle NSS's output. If we find + * an indefinite length, context-specific tag with a definite, primtive + * tag inside it, then we assume that the context-specific tag is + * implicit and the tags within are fragments of a primitive type that + * need to be concatenated. */ + if (context_specific && (tag & CBS_ASN1_CONSTRUCTED)) { + CBS in_copy, inner_contents; + unsigned inner_tag; + size_t inner_header_len; + + CBS_init(&in_copy, CBS_data(in), CBS_len(in)); + if (!CBS_get_any_ber_asn1_element(&in_copy, &inner_contents, + &inner_tag, &inner_header_len)) { + return 0; + } + if (CBS_len(&inner_contents) > inner_header_len && + is_primitive_type(inner_tag)) { + squash_child_headers = 1; + } + } + + if (!squash_header) { + unsigned out_tag = tag; + if (squash_child_headers) { + out_tag &= ~CBS_ASN1_CONSTRUCTED; + } + if (!CBB_add_asn1(out, &out_contents_storage, out_tag)) { + return 0; + } + out_contents = &out_contents_storage; + } + + if (!cbs_convert_ber(in, out_contents, + squash_child_headers, + 1 /* looking for eoc */, depth + 1)) { + return 0; + } + if (out_contents != out && !CBB_flush(out)) { + return 0; + } + continue; + } + } + + if (!squash_header) { + if (!CBB_add_asn1(out, &out_contents_storage, tag)) { + return 0; + } + out_contents = &out_contents_storage; + } + + if (!CBS_skip(&contents, header_len)) { + return 0; + } + + if (tag & CBS_ASN1_CONSTRUCTED) { + if (!cbs_convert_ber(&contents, out_contents, 0 /* don't squash header */, + 0 /* not looking for eoc */, depth + 1)) { + return 0; + } + } else { + if (!CBB_add_bytes(out_contents, CBS_data(&contents), + CBS_len(&contents))) { + return 0; + } + } + + if (out_contents != out && !CBB_flush(out)) { + return 0; + } + } + + return looking_for_eoc == 0; +} + +int CBS_asn1_ber_to_der(CBS *in, uint8_t **out, size_t *out_len) { + CBB cbb; + + /* First, do a quick walk to find any indefinite-length elements. Most of the + * time we hope that there aren't any and thus we can quickly return. */ + char conversion_needed; + if (!cbs_find_ber(in, &conversion_needed, 0)) { + return 0; + } + + if (!conversion_needed) { + *out = NULL; + *out_len = 0; + return 1; + } + + if (!CBB_init(&cbb, CBS_len(in))) { + return 0; + } + if (!cbs_convert_ber(in, &cbb, 0, 0, 0)) { + CBB_cleanup(&cbb); + return 0; + } + + return CBB_finish(&cbb, out, out_len); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bytestring/cbb.c b/TMessagesProj/jni/boringssl/crypto/bytestring/cbb.c new file mode 100644 index 00000000..1da6a21e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bytestring/cbb.c @@ -0,0 +1,393 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + +#include + + +void CBB_zero(CBB *cbb) { + memset(cbb, 0, sizeof(CBB)); +} + +static int cbb_init(CBB *cbb, uint8_t *buf, size_t cap) { + struct cbb_buffer_st *base; + + base = OPENSSL_malloc(sizeof(struct cbb_buffer_st)); + if (base == NULL) { + return 0; + } + + base->buf = buf; + base->len = 0; + base->cap = cap; + base->can_resize = 1; + + memset(cbb, 0, sizeof(CBB)); + cbb->base = base; + cbb->is_top_level = 1; + return 1; +} + +int CBB_init(CBB *cbb, size_t initial_capacity) { + uint8_t *buf; + + buf = OPENSSL_malloc(initial_capacity); + if (initial_capacity > 0 && buf == NULL) { + return 0; + } + + if (!cbb_init(cbb, buf, initial_capacity)) { + OPENSSL_free(buf); + return 0; + } + + return 1; +} + +int CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len) { + if (!cbb_init(cbb, buf, len)) { + return 0; + } + + cbb->base->can_resize = 0; + return 1; +} + +void CBB_cleanup(CBB *cbb) { + if (cbb->base) { + if (cbb->base->can_resize) { + OPENSSL_free(cbb->base->buf); + } + OPENSSL_free(cbb->base); + } + cbb->base = NULL; +} + +static int cbb_buffer_add(struct cbb_buffer_st *base, uint8_t **out, + size_t len) { + size_t newlen; + + if (base == NULL) { + return 0; + } + + newlen = base->len + len; + if (newlen < base->len) { + /* Overflow */ + return 0; + } + + if (newlen > base->cap) { + size_t newcap = base->cap * 2; + uint8_t *newbuf; + + if (!base->can_resize) { + return 0; + } + + if (newcap < base->cap || newcap < newlen) { + newcap = newlen; + } + newbuf = OPENSSL_realloc(base->buf, newcap); + if (newbuf == NULL) { + return 0; + } + + base->buf = newbuf; + base->cap = newcap; + } + + if (out) { + *out = base->buf + base->len; + } + base->len = newlen; + return 1; +} + +static int cbb_buffer_add_u(struct cbb_buffer_st *base, uint32_t v, + size_t len_len) { + uint8_t *buf; + size_t i; + + if (len_len == 0) { + return 1; + } + if (!cbb_buffer_add(base, &buf, len_len)) { + return 0; + } + + for (i = len_len - 1; i < len_len; i--) { + buf[i] = v; + v >>= 8; + } + return 1; +} + +int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len) { + if (!cbb->is_top_level) { + return 0; + } + + if (!CBB_flush(cbb)) { + return 0; + } + + if (cbb->base->can_resize && (out_data == NULL || out_len == NULL)) { + /* |out_data| and |out_len| can only be NULL if the CBB is fixed. */ + return 0; + } + + if (out_data != NULL) { + *out_data = cbb->base->buf; + } + if (out_len != NULL) { + *out_len = cbb->base->len; + } + cbb->base->buf = NULL; + CBB_cleanup(cbb); + return 1; +} + +/* CBB_flush recurses and then writes out any pending length prefix. The + * current length of the underlying base is taken to be the length of the + * length-prefixed data. */ +int CBB_flush(CBB *cbb) { + size_t child_start, i, len; + + if (cbb->base == NULL) { + return 0; + } + + if (cbb->child == NULL || cbb->pending_len_len == 0) { + return 1; + } + + child_start = cbb->offset + cbb->pending_len_len; + + if (!CBB_flush(cbb->child) || + child_start < cbb->offset || + cbb->base->len < child_start) { + return 0; + } + + len = cbb->base->len - child_start; + + if (cbb->pending_is_asn1) { + /* For ASN.1 we assume that we'll only need a single byte for the length. + * If that turned out to be incorrect, we have to move the contents along + * in order to make space. */ + size_t len_len; + uint8_t initial_length_byte; + + assert (cbb->pending_len_len == 1); + + if (len > 0xfffffffe) { + /* Too large. */ + return 0; + } else if (len > 0xffffff) { + len_len = 5; + initial_length_byte = 0x80 | 4; + } else if (len > 0xffff) { + len_len = 4; + initial_length_byte = 0x80 | 3; + } else if (len > 0xff) { + len_len = 3; + initial_length_byte = 0x80 | 2; + } else if (len > 0x7f) { + len_len = 2; + initial_length_byte = 0x80 | 1; + } else { + len_len = 1; + initial_length_byte = len; + len = 0; + } + + if (len_len != 1) { + /* We need to move the contents along in order to make space. */ + size_t extra_bytes = len_len - 1; + if (!cbb_buffer_add(cbb->base, NULL, extra_bytes)) { + return 0; + } + memmove(cbb->base->buf + child_start + extra_bytes, + cbb->base->buf + child_start, len); + } + cbb->base->buf[cbb->offset++] = initial_length_byte; + cbb->pending_len_len = len_len - 1; + } + + for (i = cbb->pending_len_len - 1; i < cbb->pending_len_len; i--) { + cbb->base->buf[cbb->offset + i] = len; + len >>= 8; + } + if (len != 0) { + return 0; + } + + cbb->child->base = NULL; + cbb->child = NULL; + cbb->pending_len_len = 0; + cbb->pending_is_asn1 = 0; + cbb->offset = 0; + + return 1; +} + +size_t CBB_len(const CBB *cbb) { + assert(cbb->child == NULL); + + return cbb->base->len; +} + +static int cbb_add_length_prefixed(CBB *cbb, CBB *out_contents, + size_t len_len) { + uint8_t *prefix_bytes; + + if (!CBB_flush(cbb)) { + return 0; + } + + cbb->offset = cbb->base->len; + if (!cbb_buffer_add(cbb->base, &prefix_bytes, len_len)) { + return 0; + } + + memset(prefix_bytes, 0, len_len); + memset(out_contents, 0, sizeof(CBB)); + out_contents->base = cbb->base; + cbb->child = out_contents; + cbb->pending_len_len = len_len; + cbb->pending_is_asn1 = 0; + + return 1; +} + +int CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents) { + return cbb_add_length_prefixed(cbb, out_contents, 1); +} + +int CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents) { + return cbb_add_length_prefixed(cbb, out_contents, 2); +} + +int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) { + return cbb_add_length_prefixed(cbb, out_contents, 3); +} + +int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag) { + if ((tag & 0x1f) == 0x1f) { + /* Long form identifier octets are not supported. */ + return 0; + } + + if (!CBB_flush(cbb) || + !CBB_add_u8(cbb, tag)) { + return 0; + } + + cbb->offset = cbb->base->len; + if (!CBB_add_u8(cbb, 0)) { + return 0; + } + + memset(out_contents, 0, sizeof(CBB)); + out_contents->base = cbb->base; + cbb->child = out_contents; + cbb->pending_len_len = 1; + cbb->pending_is_asn1 = 1; + + return 1; +} + +int CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len) { + uint8_t *dest; + + if (!CBB_flush(cbb) || + !cbb_buffer_add(cbb->base, &dest, len)) { + return 0; + } + memcpy(dest, data, len); + return 1; +} + +int CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len) { + if (!CBB_flush(cbb) || + !cbb_buffer_add(cbb->base, out_data, len)) { + return 0; + } + return 1; +} + +int CBB_add_u8(CBB *cbb, uint8_t value) { + if (!CBB_flush(cbb)) { + return 0; + } + + return cbb_buffer_add_u(cbb->base, value, 1); +} + +int CBB_add_u16(CBB *cbb, uint16_t value) { + if (!CBB_flush(cbb)) { + return 0; + } + + return cbb_buffer_add_u(cbb->base, value, 2); +} + +int CBB_add_u24(CBB *cbb, uint32_t value) { + if (!CBB_flush(cbb)) { + return 0; + } + + return cbb_buffer_add_u(cbb->base, value, 3); +} + +int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) { + CBB child; + size_t i; + int started = 0; + + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER)) { + return 0; + } + + for (i = 0; i < 8; i++) { + uint8_t byte = (value >> 8*(7-i)) & 0xff; + if (!started) { + if (byte == 0) { + /* Don't encode leading zeros. */ + continue; + } + /* If the high bit is set, add a padding byte to make it + * unsigned. */ + if ((byte & 0x80) && !CBB_add_u8(&child, 0)) { + return 0; + } + started = 1; + } + if (!CBB_add_u8(&child, byte)) { + return 0; + } + } + + /* 0 is encoded as a single 0, not the empty string. */ + if (!started && !CBB_add_u8(&child, 0)) { + return 0; + } + + return CBB_flush(cbb); +} diff --git a/TMessagesProj/jni/boringssl/crypto/bytestring/cbs.c b/TMessagesProj/jni/boringssl/crypto/bytestring/cbs.c new file mode 100644 index 00000000..b8caedd5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bytestring/cbs.c @@ -0,0 +1,401 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include +#include +#include + +#include +#include + +#include "internal.h" + + +void CBS_init(CBS *cbs, const uint8_t *data, size_t len) { + cbs->data = data; + cbs->len = len; +} + +static int cbs_get(CBS *cbs, const uint8_t **p, size_t n) { + if (cbs->len < n) { + return 0; + } + + *p = cbs->data; + cbs->data += n; + cbs->len -= n; + return 1; +} + +int CBS_skip(CBS *cbs, size_t len) { + const uint8_t *dummy; + return cbs_get(cbs, &dummy, len); +} + +const uint8_t *CBS_data(const CBS *cbs) { + return cbs->data; +} + +size_t CBS_len(const CBS *cbs) { + return cbs->len; +} + +int CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len) { + OPENSSL_free(*out_ptr); + *out_ptr = NULL; + *out_len = 0; + + if (cbs->len == 0) { + return 1; + } + *out_ptr = BUF_memdup(cbs->data, cbs->len); + if (*out_ptr == NULL) { + return 0; + } + *out_len = cbs->len; + return 1; +} + +int CBS_strdup(const CBS *cbs, char **out_ptr) { + if (*out_ptr != NULL) { + OPENSSL_free(*out_ptr); + } + *out_ptr = BUF_strndup((const char*)cbs->data, cbs->len); + return (*out_ptr != NULL); +} + +int CBS_contains_zero_byte(const CBS *cbs) { + return memchr(cbs->data, 0, cbs->len) != NULL; +} + +int CBS_mem_equal(const CBS *cbs, const uint8_t *data, size_t len) { + if (len != cbs->len) { + return 0; + } + return CRYPTO_memcmp(cbs->data, data, len) == 0; +} + +static int cbs_get_u(CBS *cbs, uint32_t *out, size_t len) { + uint32_t result = 0; + size_t i; + const uint8_t *data; + + if (!cbs_get(cbs, &data, len)) { + return 0; + } + for (i = 0; i < len; i++) { + result <<= 8; + result |= data[i]; + } + *out = result; + return 1; +} + +int CBS_get_u8(CBS *cbs, uint8_t *out) { + const uint8_t *v; + if (!cbs_get(cbs, &v, 1)) { + return 0; + } + *out = *v; + return 1; +} + +int CBS_get_u16(CBS *cbs, uint16_t *out) { + uint32_t v; + if (!cbs_get_u(cbs, &v, 2)) { + return 0; + } + *out = v; + return 1; +} + +int CBS_get_u24(CBS *cbs, uint32_t *out) { + return cbs_get_u(cbs, out, 3); +} + +int CBS_get_u32(CBS *cbs, uint32_t *out) { + return cbs_get_u(cbs, out, 4); +} + +int CBS_get_bytes(CBS *cbs, CBS *out, size_t len) { + const uint8_t *v; + if (!cbs_get(cbs, &v, len)) { + return 0; + } + CBS_init(out, v, len); + return 1; +} + +static int cbs_get_length_prefixed(CBS *cbs, CBS *out, size_t len_len) { + uint32_t len; + if (!cbs_get_u(cbs, &len, len_len)) { + return 0; + } + return CBS_get_bytes(cbs, out, len); +} + +int CBS_get_u8_length_prefixed(CBS *cbs, CBS *out) { + return cbs_get_length_prefixed(cbs, out, 1); +} + +int CBS_get_u16_length_prefixed(CBS *cbs, CBS *out) { + return cbs_get_length_prefixed(cbs, out, 2); +} + +int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) { + return cbs_get_length_prefixed(cbs, out, 3); +} + +static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, + size_t *out_header_len, int ber_ok) { + uint8_t tag, length_byte; + CBS header = *cbs; + CBS throwaway; + + if (out == NULL) { + out = &throwaway; + } + + if (!CBS_get_u8(&header, &tag) || + !CBS_get_u8(&header, &length_byte)) { + return 0; + } + + if ((tag & 0x1f) == 0x1f) { + /* Long form tags are not supported. */ + return 0; + } + + if (out_tag != NULL) { + *out_tag = tag; + } + + size_t len; + if ((length_byte & 0x80) == 0) { + /* Short form length. */ + len = ((size_t) length_byte) + 2; + if (out_header_len != NULL) { + *out_header_len = 2; + } + } else { + /* Long form length. */ + const size_t num_bytes = length_byte & 0x7f; + uint32_t len32; + + if (ber_ok && (tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) { + /* indefinite length */ + if (out_header_len != NULL) { + *out_header_len = 2; + } + return CBS_get_bytes(cbs, out, 2); + } + + if (num_bytes == 0 || num_bytes > 4) { + return 0; + } + if (!cbs_get_u(&header, &len32, num_bytes)) { + return 0; + } + if (len32 < 128) { + /* Length should have used short-form encoding. */ + return 0; + } + if ((len32 >> ((num_bytes-1)*8)) == 0) { + /* Length should have been at least one byte shorter. */ + return 0; + } + len = len32; + if (len + 2 + num_bytes < len) { + /* Overflow. */ + return 0; + } + len += 2 + num_bytes; + if (out_header_len != NULL) { + *out_header_len = 2 + num_bytes; + } + } + + return CBS_get_bytes(cbs, out, len); +} + +int CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, + size_t *out_header_len) { + return cbs_get_any_asn1_element(cbs, out, out_tag, out_header_len, + 0 /* DER only */); +} + +int CBS_get_any_ber_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, + size_t *out_header_len) { + return cbs_get_any_asn1_element(cbs, out, out_tag, out_header_len, + 1 /* BER allowed */); +} + +static int cbs_get_asn1(CBS *cbs, CBS *out, unsigned tag_value, + int skip_header) { + size_t header_len; + unsigned tag; + CBS throwaway; + + if (out == NULL) { + out = &throwaway; + } + + if (!CBS_get_any_asn1_element(cbs, out, &tag, &header_len) || + tag != tag_value) { + return 0; + } + + if (skip_header && !CBS_skip(out, header_len)) { + assert(0); + return 0; + } + + return 1; +} + +int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value) { + return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */); +} + +int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value) { + return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */); +} + +int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value) { + if (CBS_len(cbs) < 1) { + return 0; + } + return CBS_data(cbs)[0] == tag_value; +} + +int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) { + CBS bytes; + const uint8_t *data; + size_t i, len; + + if (!CBS_get_asn1(cbs, &bytes, CBS_ASN1_INTEGER)) { + return 0; + } + + *out = 0; + data = CBS_data(&bytes); + len = CBS_len(&bytes); + + if (len == 0) { + /* An INTEGER is encoded with at least one octet. */ + return 0; + } + + if ((data[0] & 0x80) != 0) { + /* Negative number. */ + return 0; + } + + if (data[0] == 0 && len > 1 && (data[1] & 0x80) == 0) { + /* Extra leading zeros. */ + return 0; + } + + for (i = 0; i < len; i++) { + if ((*out >> 56) != 0) { + /* Too large to represent as a uint64_t. */ + return 0; + } + *out <<= 8; + *out |= data[i]; + } + + return 1; +} + +int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) { + if (CBS_peek_asn1_tag(cbs, tag)) { + if (!CBS_get_asn1(cbs, out, tag)) { + return 0; + } + *out_present = 1; + } else { + *out_present = 0; + } + return 1; +} + +int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present, + unsigned tag) { + CBS child; + int present; + if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { + return 0; + } + if (present) { + if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) || + CBS_len(&child) != 0) { + return 0; + } + } else { + CBS_init(out, NULL, 0); + } + if (out_present) { + *out_present = present; + } + return 1; +} + +int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag, + uint64_t default_value) { + CBS child; + int present; + if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { + return 0; + } + if (present) { + if (!CBS_get_asn1_uint64(&child, out) || + CBS_len(&child) != 0) { + return 0; + } + } else { + *out = default_value; + } + return 1; +} + +int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, + int default_value) { + CBS child, child2; + int present; + if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { + return 0; + } + if (present) { + uint8_t boolean; + + if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) || + CBS_len(&child2) != 1 || + CBS_len(&child) != 0) { + return 0; + } + + boolean = CBS_data(&child2)[0]; + if (boolean == 0) { + *out = 0; + } else if (boolean == 0xff) { + *out = 1; + } else { + return 0; + } + } else { + *out = default_value; + } + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/bytestring/internal.h b/TMessagesProj/jni/boringssl/crypto/bytestring/internal.h new file mode 100644 index 00000000..b4ea7e51 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/bytestring/internal.h @@ -0,0 +1,46 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_BYTESTRING_INTERNAL_H +#define OPENSSL_HEADER_BYTESTRING_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* CBS_asn1_ber_to_der reads an ASN.1 structure from |in|. If it finds + * indefinite-length elements then it attempts to convert the BER data to DER + * and sets |*out| and |*out_length| to describe a malloced buffer containing + * the DER data. Additionally, |*in| will be advanced over the ASN.1 data. + * + * If it doesn't find any indefinite-length elements then it sets |*out| to + * NULL and |*in| is unmodified. + * + * A sufficiently complex ASN.1 structure will break this function because it's + * not possible to generically convert BER to DER without knowledge of the + * structure itself. However, this sufficies to handle the PKCS#7 and #12 output + * from NSS. + * + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int CBS_asn1_ber_to_der(CBS *in, uint8_t **out, size_t *out_len); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BYTESTRING_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/chacha/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/chacha/CMakeLists.txt new file mode 100644 index 00000000..6c3f87ee --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/chacha/CMakeLists.txt @@ -0,0 +1,20 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "arm") + set( + CHACHA_ARCH_SOURCES + + chacha_vec_arm.S + ) +endif() + +add_library( + chacha + + OBJECT + + chacha_generic.c + chacha_vec.c + + ${CHACHA_ARCH_SOURCES} +) diff --git a/TMessagesProj/jni/boringssl/crypto/chacha/chacha_generic.c b/TMessagesProj/jni/boringssl/crypto/chacha/chacha_generic.c new file mode 100644 index 00000000..31cf4f02 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/chacha/chacha_generic.c @@ -0,0 +1,143 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* Adapted from the public domain, estream code by D. Bernstein. */ + +#include + +#include + +#include + + +#if defined(OPENSSL_WINDOWS) || (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) || !defined(__SSE2__) + +/* sigma contains the ChaCha constants, which happen to be an ASCII string. */ +static const uint8_t sigma[16] = { 'e', 'x', 'p', 'a', 'n', 'd', ' ', '3', + '2', '-', 'b', 'y', 't', 'e', ' ', 'k' }; + +#define ROTATE(v, n) (((v) << (n)) | ((v) >> (32 - (n)))) +#define XOR(v, w) ((v) ^ (w)) +#define PLUS(x, y) ((x) + (y)) +#define PLUSONE(v) (PLUS((v), 1)) + +#define U32TO8_LITTLE(p, v) \ + { \ + (p)[0] = (v >> 0) & 0xff; \ + (p)[1] = (v >> 8) & 0xff; \ + (p)[2] = (v >> 16) & 0xff; \ + (p)[3] = (v >> 24) & 0xff; \ + } + +#define U8TO32_LITTLE(p) \ + (((uint32_t)((p)[0])) | ((uint32_t)((p)[1]) << 8) | \ + ((uint32_t)((p)[2]) << 16) | ((uint32_t)((p)[3]) << 24)) + +/* QUARTERROUND updates a, b, c, d with a ChaCha "quarter" round. */ +#define QUARTERROUND(a,b,c,d) \ + x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]),16); \ + x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]),12); \ + x[a] = PLUS(x[a],x[b]); x[d] = ROTATE(XOR(x[d],x[a]), 8); \ + x[c] = PLUS(x[c],x[d]); x[b] = ROTATE(XOR(x[b],x[c]), 7); + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) +/* Defined in chacha_vec.c */ +void CRYPTO_chacha_20_neon(uint8_t *out, const uint8_t *in, size_t in_len, + const uint8_t key[32], const uint8_t nonce[8], + size_t counter); +#endif + +/* chacha_core performs 20 rounds of ChaCha on the input words in + * |input| and writes the 64 output bytes to |output|. */ +static void chacha_core(uint8_t output[64], const uint32_t input[16]) { + uint32_t x[16]; + int i; + + memcpy(x, input, sizeof(uint32_t) * 16); + for (i = 20; i > 0; i -= 2) { + QUARTERROUND(0, 4, 8, 12) + QUARTERROUND(1, 5, 9, 13) + QUARTERROUND(2, 6, 10, 14) + QUARTERROUND(3, 7, 11, 15) + QUARTERROUND(0, 5, 10, 15) + QUARTERROUND(1, 6, 11, 12) + QUARTERROUND(2, 7, 8, 13) + QUARTERROUND(3, 4, 9, 14) + } + + for (i = 0; i < 16; ++i) { + x[i] = PLUS(x[i], input[i]); + } + for (i = 0; i < 16; ++i) { + U32TO8_LITTLE(output + 4 * i, x[i]); + } +} + +void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, size_t in_len, + const uint8_t key[32], const uint8_t nonce[8], + size_t counter) { + uint32_t input[16]; + uint8_t buf[64]; + size_t todo, i; + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) + if (CRYPTO_is_NEON_capable()) { + CRYPTO_chacha_20_neon(out, in, in_len, key, nonce, counter); + return; + } +#endif + + input[0] = U8TO32_LITTLE(sigma + 0); + input[1] = U8TO32_LITTLE(sigma + 4); + input[2] = U8TO32_LITTLE(sigma + 8); + input[3] = U8TO32_LITTLE(sigma + 12); + + input[4] = U8TO32_LITTLE(key + 0); + input[5] = U8TO32_LITTLE(key + 4); + input[6] = U8TO32_LITTLE(key + 8); + input[7] = U8TO32_LITTLE(key + 12); + + input[8] = U8TO32_LITTLE(key + 16); + input[9] = U8TO32_LITTLE(key + 20); + input[10] = U8TO32_LITTLE(key + 24); + input[11] = U8TO32_LITTLE(key + 28); + + input[12] = counter; + input[13] = ((uint64_t)counter) >> 32; + input[14] = U8TO32_LITTLE(nonce + 0); + input[15] = U8TO32_LITTLE(nonce + 4); + + while (in_len > 0) { + todo = sizeof(buf); + if (in_len < todo) { + todo = in_len; + } + + chacha_core(buf, input); + for (i = 0; i < todo; i++) { + out[i] = in[i] ^ buf[i]; + } + + out += todo; + in += todo; + in_len -= todo; + + input[12]++; + if (input[12] == 0) { + input[13]++; + } + } +} + +#endif /* OPENSSL_WINDOWS || !OPENSSL_X86_64 && !OPENSSL_X86 || !__SSE2__ */ diff --git a/TMessagesProj/jni/boringssl/crypto/chacha/chacha_vec.c b/TMessagesProj/jni/boringssl/crypto/chacha/chacha_vec.c new file mode 100644 index 00000000..14b54a70 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/chacha/chacha_vec.c @@ -0,0 +1,327 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* ==================================================================== + * + * When updating this file, also update chacha_vec_arm.S + * + * ==================================================================== */ + + +/* This implementation is by Ted Krovetz and was submitted to SUPERCOP and + * marked as public domain. It was been altered to allow for non-aligned inputs + * and to allow the block counter to be passed in specifically. */ + +#include + +#if defined(ASM_GEN) || \ + !defined(OPENSSL_WINDOWS) && \ + (defined(OPENSSL_X86_64) || defined(OPENSSL_X86)) && defined(__SSE2__) + +#define CHACHA_RNDS 20 /* 8 (high speed), 20 (conservative), 12 (middle) */ + +/* Architecture-neutral way to specify 16-byte vector of ints */ +typedef unsigned vec __attribute__((vector_size(16))); + +/* This implementation is designed for Neon, SSE and AltiVec machines. The + * following specify how to do certain vector operations efficiently on + * each architecture, using intrinsics. + * This implementation supports parallel processing of multiple blocks, + * including potentially using general-purpose registers. */ +#if __ARM_NEON__ +#include +#include +#define GPR_TOO 1 +#define VBPI 2 +#define ONE (vec) vsetq_lane_u32(1, vdupq_n_u32(0), 0) +#define LOAD_ALIGNED(m) (vec)(*((vec *)(m))) +#define LOAD(m) ({ \ + memcpy(alignment_buffer, m, 16); \ + LOAD_ALIGNED(alignment_buffer); \ + }) +#define STORE(m, r) ({ \ + (*((vec *)(alignment_buffer))) = (r); \ + memcpy(m, alignment_buffer, 16); \ + }) +#define ROTV1(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 1) +#define ROTV2(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 2) +#define ROTV3(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 3) +#define ROTW16(x) (vec) vrev32q_u16((uint16x8_t)x) +#if __clang__ +#define ROTW7(x) (x << ((vec) {7, 7, 7, 7})) ^ (x >> ((vec) {25, 25, 25, 25})) +#define ROTW8(x) (x << ((vec) {8, 8, 8, 8})) ^ (x >> ((vec) {24, 24, 24, 24})) +#define ROTW12(x) \ + (x << ((vec) {12, 12, 12, 12})) ^ (x >> ((vec) {20, 20, 20, 20})) +#else +#define ROTW7(x) \ + (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 7), (uint32x4_t)x, 25) +#define ROTW8(x) \ + (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 8), (uint32x4_t)x, 24) +#define ROTW12(x) \ + (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 12), (uint32x4_t)x, 20) +#endif +#elif __SSE2__ +#include +#define GPR_TOO 0 +#if __clang__ +#define VBPI 4 +#else +#define VBPI 3 +#endif +#define ONE (vec) _mm_set_epi32(0, 0, 0, 1) +#define LOAD(m) (vec) _mm_loadu_si128((__m128i *)(m)) +#define LOAD_ALIGNED(m) (vec) _mm_load_si128((__m128i *)(m)) +#define STORE(m, r) _mm_storeu_si128((__m128i *)(m), (__m128i)(r)) +#define ROTV1(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(0, 3, 2, 1)) +#define ROTV2(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(1, 0, 3, 2)) +#define ROTV3(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(2, 1, 0, 3)) +#define ROTW7(x) \ + (vec)(_mm_slli_epi32((__m128i)x, 7) ^ _mm_srli_epi32((__m128i)x, 25)) +#define ROTW12(x) \ + (vec)(_mm_slli_epi32((__m128i)x, 12) ^ _mm_srli_epi32((__m128i)x, 20)) +#if __SSSE3__ +#include +#define ROTW8(x) \ + (vec) _mm_shuffle_epi8((__m128i)x, _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, \ + 11, 6, 5, 4, 7, 2, 1, 0, 3)) +#define ROTW16(x) \ + (vec) _mm_shuffle_epi8((__m128i)x, _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, \ + 10, 5, 4, 7, 6, 1, 0, 3, 2)) +#else +#define ROTW8(x) \ + (vec)(_mm_slli_epi32((__m128i)x, 8) ^ _mm_srli_epi32((__m128i)x, 24)) +#define ROTW16(x) \ + (vec)(_mm_slli_epi32((__m128i)x, 16) ^ _mm_srli_epi32((__m128i)x, 16)) +#endif +#else +#error-- Implementation supports only machines with neon or SSE2 +#endif + +#ifndef REVV_BE +#define REVV_BE(x) (x) +#endif + +#ifndef REVW_BE +#define REVW_BE(x) (x) +#endif + +#define BPI (VBPI + GPR_TOO) /* Blocks computed per loop iteration */ + +#define DQROUND_VECTORS(a,b,c,d) \ + a += b; d ^= a; d = ROTW16(d); \ + c += d; b ^= c; b = ROTW12(b); \ + a += b; d ^= a; d = ROTW8(d); \ + c += d; b ^= c; b = ROTW7(b); \ + b = ROTV1(b); c = ROTV2(c); d = ROTV3(d); \ + a += b; d ^= a; d = ROTW16(d); \ + c += d; b ^= c; b = ROTW12(b); \ + a += b; d ^= a; d = ROTW8(d); \ + c += d; b ^= c; b = ROTW7(b); \ + b = ROTV3(b); c = ROTV2(c); d = ROTV1(d); + +#define QROUND_WORDS(a,b,c,d) \ + a = a+b; d ^= a; d = d<<16 | d>>16; \ + c = c+d; b ^= c; b = b<<12 | b>>20; \ + a = a+b; d ^= a; d = d<< 8 | d>>24; \ + c = c+d; b ^= c; b = b<< 7 | b>>25; + +#define WRITE_XOR(in, op, d, v0, v1, v2, v3) \ + STORE(op + d + 0, LOAD(in + d + 0) ^ REVV_BE(v0)); \ + STORE(op + d + 4, LOAD(in + d + 4) ^ REVV_BE(v1)); \ + STORE(op + d + 8, LOAD(in + d + 8) ^ REVV_BE(v2)); \ + STORE(op + d +12, LOAD(in + d +12) ^ REVV_BE(v3)); + +#if __ARM_NEON__ +/* For ARM, we can't depend on NEON support, so this function is compiled with + * a different name, along with the generic code, and can be enabled at + * run-time. */ +void CRYPTO_chacha_20_neon( +#else +void CRYPTO_chacha_20( +#endif + uint8_t *out, + const uint8_t *in, + size_t inlen, + const uint8_t key[32], + const uint8_t nonce[8], + size_t counter) + { + unsigned iters, i, *op=(unsigned *)out, *ip=(unsigned *)in, *kp; +#if defined(__ARM_NEON__) + uint32_t np[2]; + uint8_t alignment_buffer[16] __attribute__((aligned(16))); +#endif + vec s0, s1, s2, s3; + __attribute__ ((aligned (16))) unsigned chacha_const[] = + {0x61707865,0x3320646E,0x79622D32,0x6B206574}; + kp = (unsigned *)key; +#if defined(__ARM_NEON__) + memcpy(np, nonce, 8); +#endif + s0 = LOAD_ALIGNED(chacha_const); + s1 = LOAD(&((vec*)kp)[0]); + s2 = LOAD(&((vec*)kp)[1]); + s3 = (vec){ + counter & 0xffffffff, +#if __ARM_NEON__ || defined(OPENSSL_X86) + 0, /* can't right-shift 32 bits on a 32-bit system. */ +#else + counter >> 32, +#endif + ((uint32_t*)nonce)[0], + ((uint32_t*)nonce)[1] + }; + + for (iters = 0; iters < inlen/(BPI*64); iters++) + { +#if GPR_TOO + register unsigned x0, x1, x2, x3, x4, x5, x6, x7, x8, + x9, x10, x11, x12, x13, x14, x15; +#endif +#if VBPI > 2 + vec v8,v9,v10,v11; +#endif +#if VBPI > 3 + vec v12,v13,v14,v15; +#endif + + vec v0,v1,v2,v3,v4,v5,v6,v7; + v4 = v0 = s0; v5 = v1 = s1; v6 = v2 = s2; v3 = s3; + v7 = v3 + ONE; +#if VBPI > 2 + v8 = v4; v9 = v5; v10 = v6; + v11 = v7 + ONE; +#endif +#if VBPI > 3 + v12 = v8; v13 = v9; v14 = v10; + v15 = v11 + ONE; +#endif +#if GPR_TOO + x0 = chacha_const[0]; x1 = chacha_const[1]; + x2 = chacha_const[2]; x3 = chacha_const[3]; + x4 = kp[0]; x5 = kp[1]; x6 = kp[2]; x7 = kp[3]; + x8 = kp[4]; x9 = kp[5]; x10 = kp[6]; x11 = kp[7]; + x12 = counter+BPI*iters+(BPI-1); x13 = 0; + x14 = np[0]; x15 = np[1]; +#endif + for (i = CHACHA_RNDS/2; i; i--) + { + DQROUND_VECTORS(v0,v1,v2,v3) + DQROUND_VECTORS(v4,v5,v6,v7) +#if VBPI > 2 + DQROUND_VECTORS(v8,v9,v10,v11) +#endif +#if VBPI > 3 + DQROUND_VECTORS(v12,v13,v14,v15) +#endif +#if GPR_TOO + QROUND_WORDS( x0, x4, x8,x12) + QROUND_WORDS( x1, x5, x9,x13) + QROUND_WORDS( x2, x6,x10,x14) + QROUND_WORDS( x3, x7,x11,x15) + QROUND_WORDS( x0, x5,x10,x15) + QROUND_WORDS( x1, x6,x11,x12) + QROUND_WORDS( x2, x7, x8,x13) + QROUND_WORDS( x3, x4, x9,x14) +#endif + } + + WRITE_XOR(ip, op, 0, v0+s0, v1+s1, v2+s2, v3+s3) + s3 += ONE; + WRITE_XOR(ip, op, 16, v4+s0, v5+s1, v6+s2, v7+s3) + s3 += ONE; +#if VBPI > 2 + WRITE_XOR(ip, op, 32, v8+s0, v9+s1, v10+s2, v11+s3) + s3 += ONE; +#endif +#if VBPI > 3 + WRITE_XOR(ip, op, 48, v12+s0, v13+s1, v14+s2, v15+s3) + s3 += ONE; +#endif + ip += VBPI*16; + op += VBPI*16; +#if GPR_TOO + op[0] = REVW_BE(REVW_BE(ip[0]) ^ (x0 + chacha_const[0])); + op[1] = REVW_BE(REVW_BE(ip[1]) ^ (x1 + chacha_const[1])); + op[2] = REVW_BE(REVW_BE(ip[2]) ^ (x2 + chacha_const[2])); + op[3] = REVW_BE(REVW_BE(ip[3]) ^ (x3 + chacha_const[3])); + op[4] = REVW_BE(REVW_BE(ip[4]) ^ (x4 + kp[0])); + op[5] = REVW_BE(REVW_BE(ip[5]) ^ (x5 + kp[1])); + op[6] = REVW_BE(REVW_BE(ip[6]) ^ (x6 + kp[2])); + op[7] = REVW_BE(REVW_BE(ip[7]) ^ (x7 + kp[3])); + op[8] = REVW_BE(REVW_BE(ip[8]) ^ (x8 + kp[4])); + op[9] = REVW_BE(REVW_BE(ip[9]) ^ (x9 + kp[5])); + op[10] = REVW_BE(REVW_BE(ip[10]) ^ (x10 + kp[6])); + op[11] = REVW_BE(REVW_BE(ip[11]) ^ (x11 + kp[7])); + op[12] = REVW_BE(REVW_BE(ip[12]) ^ (x12 + counter+BPI*iters+(BPI-1))); + op[13] = REVW_BE(REVW_BE(ip[13]) ^ (x13)); + op[14] = REVW_BE(REVW_BE(ip[14]) ^ (x14 + np[0])); + op[15] = REVW_BE(REVW_BE(ip[15]) ^ (x15 + np[1])); + s3 += ONE; + ip += 16; + op += 16; +#endif + } + + for (iters = inlen%(BPI*64)/64; iters != 0; iters--) + { + vec v0 = s0, v1 = s1, v2 = s2, v3 = s3; + for (i = CHACHA_RNDS/2; i; i--) + { + DQROUND_VECTORS(v0,v1,v2,v3); + } + WRITE_XOR(ip, op, 0, v0+s0, v1+s1, v2+s2, v3+s3) + s3 += ONE; + ip += 16; + op += 16; + } + + inlen = inlen % 64; + if (inlen) + { + __attribute__ ((aligned (16))) vec buf[4]; + vec v0,v1,v2,v3; + v0 = s0; v1 = s1; v2 = s2; v3 = s3; + for (i = CHACHA_RNDS/2; i; i--) + { + DQROUND_VECTORS(v0,v1,v2,v3); + } + + if (inlen >= 16) + { + STORE(op + 0, LOAD(ip + 0) ^ REVV_BE(v0 + s0)); + if (inlen >= 32) + { + STORE(op + 4, LOAD(ip + 4) ^ REVV_BE(v1 + s1)); + if (inlen >= 48) + { + STORE(op + 8, LOAD(ip + 8) ^ + REVV_BE(v2 + s2)); + buf[3] = REVV_BE(v3 + s3); + } + else + buf[2] = REVV_BE(v2 + s2); + } + else + buf[1] = REVV_BE(v1 + s1); + } + else + buf[0] = REVV_BE(v0 + s0); + + for (i=inlen & ~15; i 1 { + compiler = os.Args[1] + } + + args := []string{ + "-O3", + "-mcpu=cortex-a8", + "-mfpu=neon", + "-fpic", + "-DASM_GEN", + "-I", "../../include", + "-S", "chacha_vec.c", + "-o", "-", + } + + output, err := os.OpenFile("chacha_vec_arm.S", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644) + if err != nil { + panic(err) + } + defer output.Close() + + output.WriteString(preamble) + output.WriteString(compiler) + output.WriteString(" ") + output.WriteString(strings.Join(args, " ")) + output.WriteString("\n\n#if !defined(OPENSSL_NO_ASM)\n") + output.WriteString("#if defined(__arm__) || defined(__aarch64__)\n\n") + + cmd := exec.Command(compiler, args...) + cmd.Stderr = os.Stderr + asm, err := cmd.StdoutPipe() + if err != nil { + panic(err) + } + if err := cmd.Start(); err != nil { + panic(err) + } + + attr28 := []byte(".eabi_attribute 28,") + globalDirective := []byte(".global\t") + newLine := []byte("\n") + attr28Handled := false + + scanner := bufio.NewScanner(asm) + for scanner.Scan() { + line := scanner.Bytes() + + if bytes.Contains(line, attr28) { + output.WriteString(attr28Block) + attr28Handled = true + continue + } + + output.Write(line) + output.Write(newLine) + + if i := bytes.Index(line, globalDirective); i >= 0 { + output.Write(line[:i]) + output.WriteString(".hidden\t") + output.Write(line[i+len(globalDirective):]) + output.Write(newLine) + } + } + + if err := scanner.Err(); err != nil { + panic(err) + } + + if !attr28Handled { + panic("EABI attribute 28 not seen in processing") + } + + if err := cmd.Wait(); err != nil { + panic(err) + } + + output.WriteString(trailer) +} + +const preamble = `# Copyright (c) 2014, Google Inc. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# This file contains a pre-compiled version of chacha_vec.c for ARM. This is +# needed to support switching on NEON code at runtime. If the whole of OpenSSL +# were to be compiled with the needed flags to build chacha_vec.c, then it +# wouldn't be possible to run on non-NEON systems. +# +# This file was generated by chacha_vec_arm_generate.go using the following +# compiler command: +# +# ` + +const attr28Block = ` +# EABI attribute 28 sets whether VFP register arguments were used to build this +# file. If object files are inconsistent on this point, the linker will refuse +# to link them. Thus we report whatever the compiler expects since we don't use +# VFP arguments. + +#if defined(__ARM_PCS_VFP) + .eabi_attribute 28, 1 +#else + .eabi_attribute 28, 0 +#endif + +` + +const trailer = ` +#endif /* __arm__ || __aarch64__ */ +#endif /* !OPENSSL_NO_ASM */ +` diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/cipher/CMakeLists.txt new file mode 100644 index 00000000..f3c8bf15 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/CMakeLists.txt @@ -0,0 +1,22 @@ +include_directories(. .. ../../include) + +add_library( + cipher + + OBJECT + + cipher.c + derive_key.c + aead.c + + e_null.c + e_rc2.c + e_rc4.c + e_des.c + e_aes.c + e_chacha20poly1305.c + + tls_cbc.c + e_tls.c + e_ssl3.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/aead.c b/TMessagesProj/jni/boringssl/crypto/cipher/aead.c new file mode 100644 index 00000000..1b2f9212 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/aead.c @@ -0,0 +1,154 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include + +#include +#include + +#include "internal.h" + + +size_t EVP_AEAD_key_length(const EVP_AEAD *aead) { return aead->key_len; } + +size_t EVP_AEAD_nonce_length(const EVP_AEAD *aead) { return aead->nonce_len; } + +size_t EVP_AEAD_max_overhead(const EVP_AEAD *aead) { return aead->overhead; } + +size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead) { return aead->max_tag_len; } + +int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, + const uint8_t *key, size_t key_len, size_t tag_len, + ENGINE *impl) { + if (!aead->init) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_DIRECTION_SET); + ctx->aead = NULL; + return 0; + } + return EVP_AEAD_CTX_init_with_direction(ctx, aead, key, key_len, tag_len, + evp_aead_open); +} + +int EVP_AEAD_CTX_init_with_direction(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, + const uint8_t *key, size_t key_len, + size_t tag_len, + enum evp_aead_direction_t dir) { + if (key_len != aead->key_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_KEY_SIZE); + ctx->aead = NULL; + return 0; + } + + ctx->aead = aead; + + int ok; + if (aead->init) { + ok = aead->init(ctx, key, key_len, tag_len); + } else { + ok = aead->init_with_direction(ctx, key, key_len, tag_len, dir); + } + + if (!ok) { + ctx->aead = NULL; + } + + return ok; +} + +void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx) { + if (ctx->aead == NULL) { + return; + } + ctx->aead->cleanup(ctx); + ctx->aead = NULL; +} + +/* check_alias returns 0 if |out| points within the buffer determined by |in| + * and |in_len| and 1 otherwise. + * + * When processing, there's only an issue if |out| points within in[:in_len] + * and isn't equal to |in|. If that's the case then writing the output will + * stomp input that hasn't been read yet. + * + * This function checks for that case. */ +static int check_alias(const uint8_t *in, size_t in_len, const uint8_t *out) { + if (out <= in) { + return 1; + } else if (in + in_len <= out) { + return 1; + } + return 0; +} + +int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, + size_t max_out_len, const uint8_t *nonce, + size_t nonce_len, const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + size_t possible_out_len = in_len + ctx->aead->overhead; + + if (possible_out_len < in_len /* overflow */) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + goto error; + } + + if (!check_alias(in, in_len, out)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); + goto error; + } + + if (ctx->aead->seal(ctx, out, out_len, max_out_len, nonce, nonce_len, in, + in_len, ad, ad_len)) { + return 1; + } + +error: + /* In the event of an error, clear the output buffer so that a caller + * that doesn't check the return value doesn't send raw data. */ + memset(out, 0, max_out_len); + *out_len = 0; + return 0; +} + +int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, + size_t max_out_len, const uint8_t *nonce, + size_t nonce_len, const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + if (!check_alias(in, in_len, out)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_OUTPUT_ALIASES_INPUT); + goto error; + } + + if (ctx->aead->open(ctx, out, out_len, max_out_len, nonce, nonce_len, in, + in_len, ad, ad_len)) { + return 1; + } + +error: + /* In the event of an error, clear the output buffer so that a caller + * that doesn't check the return value doesn't try and process bad + * data. */ + memset(out, 0, max_out_len); + *out_len = 0; + return 0; +} + +int EVP_AEAD_CTX_get_rc4_state(const EVP_AEAD_CTX *ctx, const RC4_KEY **out_key) { + if (ctx->aead->get_rc4_state == NULL) { + return 0; + } + + return ctx->aead->get_rc4_state(ctx, out_key); +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/cipher.c b/TMessagesProj/jni/boringssl/crypto/cipher/cipher.c new file mode 100644 index 00000000..44018675 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/cipher.c @@ -0,0 +1,652 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + +#include "internal.h" + + +const EVP_CIPHER *EVP_get_cipherbynid(int nid) { + switch (nid) { + case NID_rc2_cbc: + return EVP_rc2_cbc(); + case NID_rc2_40_cbc: + return EVP_rc2_40_cbc(); + case NID_des_ede3_cbc: + return EVP_des_ede3_cbc(); + case NID_des_ede_cbc: + return EVP_des_cbc(); + case NID_aes_128_cbc: + return EVP_aes_128_cbc(); + case NID_aes_192_cbc: + return EVP_aes_192_cbc(); + case NID_aes_256_cbc: + return EVP_aes_256_cbc(); + default: + return NULL; + } +} + +void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx) { + memset(ctx, 0, sizeof(EVP_CIPHER_CTX)); +} + +EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void) { + EVP_CIPHER_CTX *ctx = OPENSSL_malloc(sizeof(EVP_CIPHER_CTX)); + if (ctx) { + EVP_CIPHER_CTX_init(ctx); + } + return ctx; +} + +int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c) { + if (c->cipher != NULL) { + if (c->cipher->cleanup) { + c->cipher->cleanup(c); + } + OPENSSL_cleanse(c->cipher_data, c->cipher->ctx_size); + } + OPENSSL_free(c->cipher_data); + + memset(c, 0, sizeof(EVP_CIPHER_CTX)); + return 1; +} + +void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) { + if (ctx) { + EVP_CIPHER_CTX_cleanup(ctx); + OPENSSL_free(ctx); + } +} + +int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in) { + if (in == NULL || in->cipher == NULL) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INPUT_NOT_INITIALIZED); + return 0; + } + + EVP_CIPHER_CTX_cleanup(out); + memcpy(out, in, sizeof(EVP_CIPHER_CTX)); + + if (in->cipher_data && in->cipher->ctx_size) { + out->cipher_data = OPENSSL_malloc(in->cipher->ctx_size); + if (!out->cipher_data) { + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size); + } + + if (in->cipher->flags & EVP_CIPH_CUSTOM_COPY) { + return in->cipher->ctrl((EVP_CIPHER_CTX *)in, EVP_CTRL_COPY, 0, out); + } + + return 1; +} + +int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + ENGINE *engine, const uint8_t *key, const uint8_t *iv, + int enc) { + if (enc == -1) { + enc = ctx->encrypt; + } else { + if (enc) { + enc = 1; + } + ctx->encrypt = enc; + } + + if (cipher) { + /* Ensure a context left from last time is cleared (the previous check + * attempted to avoid this if the same ENGINE and EVP_CIPHER could be + * used). */ + if (ctx->cipher) { + EVP_CIPHER_CTX_cleanup(ctx); + /* Restore encrypt and flags */ + ctx->encrypt = enc; + } + + ctx->cipher = cipher; + if (ctx->cipher->ctx_size) { + ctx->cipher_data = OPENSSL_malloc(ctx->cipher->ctx_size); + if (!ctx->cipher_data) { + ctx->cipher = NULL; + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + ctx->cipher_data = NULL; + } + + ctx->key_len = cipher->key_len; + ctx->flags = 0; + + if (ctx->cipher->flags & EVP_CIPH_CTRL_INIT) { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL)) { + ctx->cipher = NULL; + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INITIALIZATION_ERROR); + return 0; + } + } + } else if (!ctx->cipher) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_CIPHER_SET); + return 0; + } + + /* we assume block size is a power of 2 in *cryptUpdate */ + assert(ctx->cipher->block_size == 1 || ctx->cipher->block_size == 8 || + ctx->cipher->block_size == 16); + + if (!(EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_CUSTOM_IV)) { + switch (EVP_CIPHER_CTX_mode(ctx)) { + case EVP_CIPH_STREAM_CIPHER: + case EVP_CIPH_ECB_MODE: + break; + + case EVP_CIPH_CFB_MODE: + ctx->num = 0; + /* fall-through */ + + case EVP_CIPH_CBC_MODE: + assert(EVP_CIPHER_CTX_iv_length(ctx) <= sizeof(ctx->iv)); + if (iv) { + memcpy(ctx->oiv, iv, EVP_CIPHER_CTX_iv_length(ctx)); + } + memcpy(ctx->iv, ctx->oiv, EVP_CIPHER_CTX_iv_length(ctx)); + break; + + case EVP_CIPH_CTR_MODE: + case EVP_CIPH_OFB_MODE: + ctx->num = 0; + /* Don't reuse IV for CTR mode */ + if (iv) { + memcpy(ctx->iv, iv, EVP_CIPHER_CTX_iv_length(ctx)); + } + break; + + default: + return 0; + } + } + + if (key || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT)) { + if (!ctx->cipher->init(ctx, key, iv, enc)) { + return 0; + } + } + + ctx->buf_len = 0; + ctx->final_used = 0; + ctx->block_mask = ctx->cipher->block_size - 1; + return 1; +} + +int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + ENGINE *impl, const uint8_t *key, const uint8_t *iv) { + return EVP_CipherInit_ex(ctx, cipher, impl, key, iv, 1); +} + +int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + ENGINE *impl, const uint8_t *key, const uint8_t *iv) { + return EVP_CipherInit_ex(ctx, cipher, impl, key, iv, 0); +} + +int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len, + const uint8_t *in, int in_len) { + int i, j, bl; + + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { + i = ctx->cipher->cipher(ctx, out, in, in_len); + if (i < 0) { + return 0; + } else { + *out_len = i; + } + return 1; + } + + if (in_len <= 0) { + *out_len = 0; + return in_len == 0; + } + + if (ctx->buf_len == 0 && (in_len & ctx->block_mask) == 0) { + if (ctx->cipher->cipher(ctx, out, in, in_len)) { + *out_len = in_len; + return 1; + } else { + *out_len = 0; + return 0; + } + } + + i = ctx->buf_len; + bl = ctx->cipher->block_size; + assert(bl <= (int)sizeof(ctx->buf)); + if (i != 0) { + if (i + in_len < bl) { + memcpy(&ctx->buf[i], in, in_len); + ctx->buf_len += in_len; + *out_len = 0; + return 1; + } else { + j = bl - i; + memcpy(&ctx->buf[i], in, j); + if (!ctx->cipher->cipher(ctx, out, ctx->buf, bl)) { + return 0; + } + in_len -= j; + in += j; + out += bl; + *out_len = bl; + } + } else { + *out_len = 0; + } + + i = in_len & ctx->block_mask; + in_len -= i; + if (in_len > 0) { + if (!ctx->cipher->cipher(ctx, out, in, in_len)) { + return 0; + } + *out_len += in_len; + } + + if (i != 0) { + memcpy(ctx->buf, &in[in_len], i); + } + ctx->buf_len = i; + return 1; +} + +int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) { + int n, ret; + unsigned int i, b, bl; + + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { + ret = ctx->cipher->cipher(ctx, out, NULL, 0); + if (ret < 0) { + return 0; + } else { + *out_len = ret; + } + return 1; + } + + b = ctx->cipher->block_size; + assert(b <= sizeof(ctx->buf)); + if (b == 1) { + *out_len = 0; + return 1; + } + + bl = ctx->buf_len; + if (ctx->flags & EVP_CIPH_NO_PADDING) { + if (bl) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH); + return 0; + } + *out_len = 0; + return 1; + } + + n = b - bl; + for (i = bl; i < b; i++) { + ctx->buf[i] = n; + } + ret = ctx->cipher->cipher(ctx, out, ctx->buf, b); + + if (ret) { + *out_len = b; + } + + return ret; +} + +int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len, + const uint8_t *in, int in_len) { + int fix_len; + unsigned int b; + + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { + int r = ctx->cipher->cipher(ctx, out, in, in_len); + if (r < 0) { + *out_len = 0; + return 0; + } else { + *out_len = r; + } + return 1; + } + + if (in_len <= 0) { + *out_len = 0; + return in_len == 0; + } + + if (ctx->flags & EVP_CIPH_NO_PADDING) { + return EVP_EncryptUpdate(ctx, out, out_len, in, in_len); + } + + b = ctx->cipher->block_size; + assert(b <= sizeof(ctx->final)); + + if (ctx->final_used) { + memcpy(out, ctx->final, b); + out += b; + fix_len = 1; + } else { + fix_len = 0; + } + + if (!EVP_EncryptUpdate(ctx, out, out_len, in, in_len)) { + return 0; + } + + /* if we have 'decrypted' a multiple of block size, make sure + * we have a copy of this last block */ + if (b > 1 && !ctx->buf_len) { + *out_len -= b; + ctx->final_used = 1; + memcpy(ctx->final, &out[*out_len], b); + } else { + ctx->final_used = 0; + } + + if (fix_len) { + *out_len += b; + } + + return 1; +} + +int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) { + int i, n; + unsigned int b; + *out_len = 0; + + if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { + i = ctx->cipher->cipher(ctx, out, NULL, 0); + if (i < 0) { + return 0; + } else { + *out_len = i; + } + return 1; + } + + b = ctx->cipher->block_size; + if (ctx->flags & EVP_CIPH_NO_PADDING) { + if (ctx->buf_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH); + return 0; + } + *out_len = 0; + return 1; + } + + if (b > 1) { + if (ctx->buf_len || !ctx->final_used) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_WRONG_FINAL_BLOCK_LENGTH); + return 0; + } + assert(b <= sizeof(ctx->final)); + + /* The following assumes that the ciphertext has been authenticated. + * Otherwise it provides a padding oracle. */ + n = ctx->final[b - 1]; + if (n == 0 || n > (int)b) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + for (i = 0; i < n; i++) { + if (ctx->final[--b] != n) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + } + + n = ctx->cipher->block_size - n; + for (i = 0; i < n; i++) { + out[i] = ctx->final[i]; + } + *out_len = n; + } else { + *out_len = 0; + } + + return 1; +} + +int EVP_Cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t in_len) { + return ctx->cipher->cipher(ctx, out, in, in_len); +} + +int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len, + const uint8_t *in, int in_len) { + if (ctx->encrypt) { + return EVP_EncryptUpdate(ctx, out, out_len, in, in_len); + } else { + return EVP_DecryptUpdate(ctx, out, out_len, in, in_len); + } +} + +int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) { + if (ctx->encrypt) { + return EVP_EncryptFinal_ex(ctx, out, out_len); + } else { + return EVP_DecryptFinal_ex(ctx, out, out_len); + } +} + +const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *ctx) { + return ctx->cipher; +} + +int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx) { + return ctx->cipher->nid; +} + +unsigned EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx) { + return ctx->cipher->block_size; +} + +unsigned EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx) { + return ctx->key_len; +} + +unsigned EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx) { + return ctx->cipher->iv_len; +} + +void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx) { + return ctx->app_data; +} + +void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, void *data) { + ctx->app_data = data; +} + +uint32_t EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *ctx) { + return ctx->cipher->flags & ~EVP_CIPH_MODE_MASK; +} + +uint32_t EVP_CIPHER_CTX_mode(const EVP_CIPHER_CTX *ctx) { + return ctx->cipher->flags & EVP_CIPH_MODE_MASK; +} + +int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int command, int arg, void *ptr) { + int ret; + if (!ctx->cipher) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_NO_CIPHER_SET); + return 0; + } + + if (!ctx->cipher->ctrl) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_NOT_IMPLEMENTED); + return 0; + } + + ret = ctx->cipher->ctrl(ctx, command, arg, ptr); + if (ret == -1) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_CTRL_OPERATION_NOT_IMPLEMENTED); + return 0; + } + + return ret; +} + +int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad) { + if (pad) { + ctx->flags &= ~EVP_CIPH_NO_PADDING; + } else { + ctx->flags |= EVP_CIPH_NO_PADDING; + } + return 1; +} + +int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, unsigned key_len) { + if (c->key_len == key_len) { + return 1; + } + + if (key_len == 0 || !(c->cipher->flags & EVP_CIPH_VARIABLE_LENGTH)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_KEY_LENGTH); + return 0; + } + + c->key_len = key_len; + return 1; +} + +int EVP_CIPHER_nid(const EVP_CIPHER *cipher) { return cipher->nid; } + +unsigned EVP_CIPHER_block_size(const EVP_CIPHER *cipher) { + return cipher->block_size; +} + +unsigned EVP_CIPHER_key_length(const EVP_CIPHER *cipher) { + return cipher->key_len; +} + +unsigned EVP_CIPHER_iv_length(const EVP_CIPHER *cipher) { + return cipher->iv_len; +} + +uint32_t EVP_CIPHER_flags(const EVP_CIPHER *cipher) { + return cipher->flags & ~EVP_CIPH_MODE_MASK; +} + +uint32_t EVP_CIPHER_mode(const EVP_CIPHER *cipher) { + return cipher->flags & EVP_CIPH_MODE_MASK; +} + +int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const uint8_t *key, const uint8_t *iv, int enc) { + if (cipher) { + EVP_CIPHER_CTX_init(ctx); + } + return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc); +} + +int EVP_EncryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const uint8_t *key, const uint8_t *iv) { + return EVP_CipherInit(ctx, cipher, key, iv, 1); +} + +int EVP_DecryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const uint8_t *key, const uint8_t *iv) { + return EVP_CipherInit(ctx, cipher, key, iv, 0); +} + +int EVP_add_cipher_alias(const char *a, const char *b) { + return 1; +} + +const EVP_CIPHER *EVP_get_cipherbyname(const char *name) { + if (OPENSSL_strcasecmp(name, "rc4") == 0) { + return EVP_rc4(); + } else if (OPENSSL_strcasecmp(name, "des-cbc") == 0) { + return EVP_des_cbc(); + } else if (OPENSSL_strcasecmp(name, "des-ede3-cbc") == 0 || + OPENSSL_strcasecmp(name, "3des") == 0) { + return EVP_des_ede3_cbc(); + } else if (OPENSSL_strcasecmp(name, "aes-128-cbc") == 0) { + return EVP_aes_128_cbc(); + } else if (OPENSSL_strcasecmp(name, "aes-256-cbc") == 0) { + return EVP_aes_256_cbc(); + } else if (OPENSSL_strcasecmp(name, "aes-128-ctr") == 0) { + return EVP_aes_128_ctr(); + } else if (OPENSSL_strcasecmp(name, "aes-256-ctr") == 0) { + return EVP_aes_256_ctr(); + } else if (OPENSSL_strcasecmp(name, "aes-128-ecb") == 0) { + return EVP_aes_128_ecb(); + } else if (OPENSSL_strcasecmp(name, "aes-256-ecb") == 0) { + return EVP_aes_256_ecb(); + } + + return NULL; +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/derive_key.c b/TMessagesProj/jni/boringssl/crypto/cipher/derive_key.c new file mode 100644 index 00000000..9e1634ab --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/derive_key.c @@ -0,0 +1,154 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include + +#include "internal.h" + + +#define PKCS5_SALT_LEN 8 + +int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md, + const uint8_t *salt, const uint8_t *data, size_t data_len, + unsigned count, uint8_t *key, uint8_t *iv) { + EVP_MD_CTX c; + uint8_t md_buf[EVP_MAX_MD_SIZE]; + unsigned niv, nkey, addmd = 0; + unsigned mds = 0, i; + int rv = 0; + + nkey = type->key_len; + niv = type->iv_len; + + assert(nkey <= EVP_MAX_KEY_LENGTH); + assert(niv <= EVP_MAX_IV_LENGTH); + + if (data == NULL) { + return nkey; + } + + EVP_MD_CTX_init(&c); + for (;;) { + if (!EVP_DigestInit_ex(&c, md, NULL)) { + return 0; + } + if (addmd++) { + if (!EVP_DigestUpdate(&c, md_buf, mds)) { + goto err; + } + } + if (!EVP_DigestUpdate(&c, data, data_len)) { + goto err; + } + if (salt != NULL) { + if (!EVP_DigestUpdate(&c, salt, PKCS5_SALT_LEN)) { + goto err; + } + } + if (!EVP_DigestFinal_ex(&c, md_buf, &mds)) { + goto err; + } + + for (i = 1; i < count; i++) { + if (!EVP_DigestInit_ex(&c, md, NULL) || + !EVP_DigestUpdate(&c, md_buf, mds) || + !EVP_DigestFinal_ex(&c, md_buf, &mds)) { + goto err; + } + } + + i = 0; + if (nkey) { + for (;;) { + if (nkey == 0 || i == mds) { + break; + } + if (key != NULL) { + *(key++) = md_buf[i]; + } + nkey--; + i++; + } + } + + if (niv && i != mds) { + for (;;) { + if (niv == 0 || i == mds) { + break; + } + if (iv != NULL) { + *(iv++) = md_buf[i]; + } + niv--; + i++; + } + } + if (nkey == 0 && niv == 0) { + break; + } + } + rv = type->key_len; + +err: + EVP_MD_CTX_cleanup(&c); + OPENSSL_cleanse(md_buf, EVP_MAX_MD_SIZE); + return rv; +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_aes.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_aes.c new file mode 100644 index 00000000..24013dcb --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_aes.c @@ -0,0 +1,1760 @@ +/* ==================================================================== + * Copyright (c) 2001-2011 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" +#include "../modes/internal.h" + +#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) +#include "../arm_arch.h" +#endif + + +typedef struct { + union { + double align; + AES_KEY ks; + } ks; + block128_f block; + union { + cbc128_f cbc; + ctr128_f ctr; + } stream; +} EVP_AES_KEY; + +typedef struct { + union { + double align; + AES_KEY ks; + } ks; /* AES key schedule to use */ + int key_set; /* Set if key initialised */ + int iv_set; /* Set if an iv is set */ + GCM128_CONTEXT gcm; + uint8_t *iv; /* Temporary IV store */ + int ivlen; /* IV length */ + int taglen; + int iv_gen; /* It is OK to generate IVs */ + ctr128_f ctr; +} EVP_AES_GCM_CTX; + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86_64) || defined(OPENSSL_X86)) +#define VPAES +static char vpaes_capable(void) { + return (OPENSSL_ia32cap_P[1] & (1 << (41 - 32))) != 0; +} + +#if defined(OPENSSL_X86_64) +#define BSAES +static char bsaes_capable(void) { + return vpaes_capable(); +} +#endif + +#elif !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) +#include "../arm_arch.h" + +#if defined(OPENSSL_ARM) && __ARM_MAX_ARCH__ >= 7 +#define BSAES +static char bsaes_capable(void) { + return CRYPTO_is_NEON_capable(); +} +#endif + +#define HWAES +static char hwaes_capable(void) { + return (OPENSSL_armcap_P & ARMV8_AES) != 0; +} + +int aes_v8_set_encrypt_key(const uint8_t *user_key, const int bits, + AES_KEY *key); +int aes_v8_set_decrypt_key(const uint8_t *user_key, const int bits, + AES_KEY *key); +void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void aes_v8_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, const int enc); +void aes_v8_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, const uint8_t ivec[16]); + +#endif /* OPENSSL_ARM */ + +#if defined(BSAES) +/* On platforms where BSAES gets defined (just above), then these functions are + * provided by asm. */ +void bsaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t ivec[16], int enc); +void bsaes_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, const uint8_t ivec[16]); +#else +static char bsaes_capable(void) { + return 0; +} + +/* On other platforms, bsaes_capable() will always return false and so the + * following will never be called. */ +void bsaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t ivec[16], int enc) { + abort(); +} + +void bsaes_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, const uint8_t ivec[16]) { + abort(); +} +#endif + +#if defined(VPAES) +/* On platforms where VPAES gets defined (just above), then these functions are + * provided by asm. */ +int vpaes_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key); +int vpaes_set_decrypt_key(const uint8_t *userKey, int bits, AES_KEY *key); + +void vpaes_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void vpaes_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); + +void vpaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, int enc); +#else +static char vpaes_capable(void) { + return 0; +} + +/* On other platforms, vpaes_capable() will always return false and so the + * following will never be called. */ +int vpaes_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key) { + abort(); +} +int vpaes_set_decrypt_key(const uint8_t *userKey, int bits, AES_KEY *key) { + abort(); +} +void vpaes_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + abort(); +} +void vpaes_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + abort(); +} +void vpaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, int enc) { + abort(); +} +#endif + +#if !defined(HWAES) +/* If HWAES isn't defined then we provide dummy functions for each of the hwaes + * functions. */ +int hwaes_capable(void) { + return 0; +} + +int aes_v8_set_encrypt_key(const uint8_t *user_key, int bits, + AES_KEY *key) { + abort(); +} + +int aes_v8_set_decrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) { + abort(); +} + +void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + abort(); +} + +void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + abort(); +} + +void aes_v8_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, int enc) { + abort(); +} + +void aes_v8_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, const uint8_t ivec[16]) { + abort(); +} +#endif + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86_64) || defined(OPENSSL_X86)) +int aesni_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key); +int aesni_set_decrypt_key(const uint8_t *userKey, int bits, AES_KEY *key); + +void aesni_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void aesni_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); + +void aesni_ecb_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, int enc); +void aesni_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, int enc); + +void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks, + const void *key, const uint8_t *ivec); + +#if defined(OPENSSL_X86_64) +size_t aesni_gcm_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], uint64_t *Xi); +#define AES_gcm_encrypt aesni_gcm_encrypt +size_t aesni_gcm_decrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], uint64_t *Xi); +#define AES_gcm_decrypt aesni_gcm_decrypt +void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *in, + size_t len); +#define AES_GCM_ASM(gctx) \ + (gctx->ctr == aesni_ctr32_encrypt_blocks && gctx->gcm.ghash == gcm_ghash_avx) +#endif /* OPENSSL_X86_64 */ + +#else + +/* On other platforms, aesni_capable() will always return false and so the + * following will never be called. */ +void aesni_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { + abort(); +} +int aesni_set_encrypt_key(const uint8_t *userKey, int bits, AES_KEY *key) { + abort(); +} +void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks, + const void *key, const uint8_t *ivec) { + abort(); +} + +#endif + +static int aes_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) + OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS { + int ret, mode; + EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; + + mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK; + if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) { + if (hwaes_capable()) { + ret = aes_v8_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)aes_v8_decrypt; + dat->stream.cbc = NULL; + if (mode == EVP_CIPH_CBC_MODE) { + dat->stream.cbc = (cbc128_f)aes_v8_cbc_encrypt; + } + } else if (bsaes_capable() && mode == EVP_CIPH_CBC_MODE) { + ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)AES_decrypt; + dat->stream.cbc = (cbc128_f)bsaes_cbc_encrypt; + } else if (vpaes_capable()) { + ret = vpaes_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)vpaes_decrypt; + dat->stream.cbc = + mode == EVP_CIPH_CBC_MODE ? (cbc128_f)vpaes_cbc_encrypt : NULL; + } else { + ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)AES_decrypt; + dat->stream.cbc = + mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL; + } + } else if (hwaes_capable()) { + ret = aes_v8_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)aes_v8_encrypt; + dat->stream.cbc = NULL; + if (mode == EVP_CIPH_CBC_MODE) { + dat->stream.cbc = (cbc128_f)aes_v8_cbc_encrypt; + } else if (mode == EVP_CIPH_CTR_MODE) { + dat->stream.ctr = (ctr128_f)aes_v8_ctr32_encrypt_blocks; + } + } else if (bsaes_capable() && mode == EVP_CIPH_CTR_MODE) { + ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)AES_encrypt; + dat->stream.ctr = (ctr128_f)bsaes_ctr32_encrypt_blocks; + } else if (vpaes_capable()) { + ret = vpaes_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)vpaes_encrypt; + dat->stream.cbc = + mode == EVP_CIPH_CBC_MODE ? (cbc128_f)vpaes_cbc_encrypt : NULL; + } else { + ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)AES_encrypt; + dat->stream.cbc = + mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL; + } + + if (ret < 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED); + return 0; + } + + return 1; +} + +static int aes_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t len) { + EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; + + if (dat->stream.cbc) { + (*dat->stream.cbc)(in, out, len, &dat->ks, ctx->iv, ctx->encrypt); + } else if (ctx->encrypt) { + CRYPTO_cbc128_encrypt(in, out, len, &dat->ks, ctx->iv, dat->block); + } else { + CRYPTO_cbc128_decrypt(in, out, len, &dat->ks, ctx->iv, dat->block); + } + + return 1; +} + +static int aes_ecb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t len) { + size_t bl = ctx->cipher->block_size; + size_t i; + EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; + + if (len < bl) { + return 1; + } + + for (i = 0, len -= bl; i <= len; i += bl) { + (*dat->block)(in + i, out + i, &dat->ks); + } + + return 1; +} + +static int aes_ctr_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t len) { + unsigned int num = ctx->num; + EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; + + if (dat->stream.ctr) { + CRYPTO_ctr128_encrypt_ctr32(in, out, len, &dat->ks, ctx->iv, ctx->buf, &num, + dat->stream.ctr); + } else { + CRYPTO_ctr128_encrypt(in, out, len, &dat->ks, ctx->iv, ctx->buf, &num, + dat->block); + } + ctx->num = (size_t)num; + return 1; +} + +static int aes_ofb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t len) { + EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; + + CRYPTO_ofb128_encrypt(in, out, len, &dat->ks, ctx->iv, &ctx->num, dat->block); + return 1; +} + +static char aesni_capable(void); + +static ctr128_f aes_ctr_set_key(AES_KEY *aes_key, GCM128_CONTEXT *gcm_ctx, + block128_f *out_block, const uint8_t *key, + size_t key_len) + OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS { + if (aesni_capable()) { + aesni_set_encrypt_key(key, key_len * 8, aes_key); + if (gcm_ctx != NULL) { + CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)aesni_encrypt); + } + if (out_block) { + *out_block = (block128_f) aesni_encrypt; + } + return (ctr128_f)aesni_ctr32_encrypt_blocks; + } + + if (hwaes_capable()) { + aes_v8_set_encrypt_key(key, key_len * 8, aes_key); + if (gcm_ctx != NULL) { + CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)aes_v8_encrypt); + } + if (out_block) { + *out_block = (block128_f) aes_v8_encrypt; + } + return (ctr128_f)aes_v8_ctr32_encrypt_blocks; + } + + if (bsaes_capable()) { + AES_set_encrypt_key(key, key_len * 8, aes_key); + if (gcm_ctx != NULL) { + CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)AES_encrypt); + } + if (out_block) { + *out_block = (block128_f) AES_encrypt; + } + return (ctr128_f)bsaes_ctr32_encrypt_blocks; + } + + if (vpaes_capable()) { + vpaes_set_encrypt_key(key, key_len * 8, aes_key); + if (out_block) { + *out_block = (block128_f) vpaes_encrypt; + } + if (gcm_ctx != NULL) { + CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)vpaes_encrypt); + } + return NULL; + } + + AES_set_encrypt_key(key, key_len * 8, aes_key); + if (gcm_ctx != NULL) { + CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)AES_encrypt); + } + if (out_block) { + *out_block = (block128_f) AES_encrypt; + } + return NULL; +} + +static int aes_gcm_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + EVP_AES_GCM_CTX *gctx = ctx->cipher_data; + if (!iv && !key) { + return 1; + } + if (key) { + gctx->ctr = + aes_ctr_set_key(&gctx->ks.ks, &gctx->gcm, NULL, key, ctx->key_len); + /* If we have an iv can set it directly, otherwise use saved IV. */ + if (iv == NULL && gctx->iv_set) { + iv = gctx->iv; + } + if (iv) { + CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen); + gctx->iv_set = 1; + } + gctx->key_set = 1; + } else { + /* If key set use IV, otherwise copy */ + if (gctx->key_set) { + CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen); + } else { + memcpy(gctx->iv, iv, gctx->ivlen); + } + gctx->iv_set = 1; + gctx->iv_gen = 0; + } + return 1; +} + +static void aes_gcm_cleanup(EVP_CIPHER_CTX *c) { + EVP_AES_GCM_CTX *gctx = c->cipher_data; + OPENSSL_cleanse(&gctx->gcm, sizeof(gctx->gcm)); + if (gctx->iv != c->iv) { + OPENSSL_free(gctx->iv); + } +} + +/* increment counter (64-bit int) by 1 */ +static void ctr64_inc(uint8_t *counter) { + int n = 8; + uint8_t c; + + do { + --n; + c = counter[n]; + ++c; + counter[n] = c; + if (c) { + return; + } + } while (n); +} + +static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) { + EVP_AES_GCM_CTX *gctx = c->cipher_data; + switch (type) { + case EVP_CTRL_INIT: + gctx->key_set = 0; + gctx->iv_set = 0; + gctx->ivlen = c->cipher->iv_len; + gctx->iv = c->iv; + gctx->taglen = -1; + gctx->iv_gen = 0; + return 1; + + case EVP_CTRL_GCM_SET_IVLEN: + if (arg <= 0) { + return 0; + } + + /* Allocate memory for IV if needed */ + if (arg > EVP_MAX_IV_LENGTH && arg > gctx->ivlen) { + if (gctx->iv != c->iv) { + OPENSSL_free(gctx->iv); + } + gctx->iv = OPENSSL_malloc(arg); + if (!gctx->iv) { + return 0; + } + } + gctx->ivlen = arg; + return 1; + + case EVP_CTRL_GCM_SET_TAG: + if (arg <= 0 || arg > 16 || c->encrypt) { + return 0; + } + memcpy(c->buf, ptr, arg); + gctx->taglen = arg; + return 1; + + case EVP_CTRL_GCM_GET_TAG: + if (arg <= 0 || arg > 16 || !c->encrypt || gctx->taglen < 0) { + return 0; + } + memcpy(ptr, c->buf, arg); + return 1; + + case EVP_CTRL_GCM_SET_IV_FIXED: + /* Special case: -1 length restores whole IV */ + if (arg == -1) { + memcpy(gctx->iv, ptr, gctx->ivlen); + gctx->iv_gen = 1; + return 1; + } + /* Fixed field must be at least 4 bytes and invocation field + * at least 8. */ + if (arg < 4 || (gctx->ivlen - arg) < 8) { + return 0; + } + if (arg) { + memcpy(gctx->iv, ptr, arg); + } + if (c->encrypt && !RAND_bytes(gctx->iv + arg, gctx->ivlen - arg)) { + return 0; + } + gctx->iv_gen = 1; + return 1; + + case EVP_CTRL_GCM_IV_GEN: + if (gctx->iv_gen == 0 || gctx->key_set == 0) { + return 0; + } + CRYPTO_gcm128_setiv(&gctx->gcm, gctx->iv, gctx->ivlen); + if (arg <= 0 || arg > gctx->ivlen) { + arg = gctx->ivlen; + } + memcpy(ptr, gctx->iv + gctx->ivlen - arg, arg); + /* Invocation field will be at least 8 bytes in size and + * so no need to check wrap around or increment more than + * last 8 bytes. */ + ctr64_inc(gctx->iv + gctx->ivlen - 8); + gctx->iv_set = 1; + return 1; + + case EVP_CTRL_GCM_SET_IV_INV: + if (gctx->iv_gen == 0 || gctx->key_set == 0 || c->encrypt) { + return 0; + } + memcpy(gctx->iv + gctx->ivlen - arg, ptr, arg); + CRYPTO_gcm128_setiv(&gctx->gcm, gctx->iv, gctx->ivlen); + gctx->iv_set = 1; + return 1; + + case EVP_CTRL_COPY: { + EVP_CIPHER_CTX *out = ptr; + EVP_AES_GCM_CTX *gctx_out = out->cipher_data; + if (gctx->gcm.key) { + if (gctx->gcm.key != &gctx->ks) { + return 0; + } + gctx_out->gcm.key = &gctx_out->ks; + } + if (gctx->iv == c->iv) { + gctx_out->iv = out->iv; + } else { + gctx_out->iv = OPENSSL_malloc(gctx->ivlen); + if (!gctx_out->iv) { + return 0; + } + memcpy(gctx_out->iv, gctx->iv, gctx->ivlen); + } + return 1; + } + + default: + return -1; + } +} + +static int aes_gcm_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t len) { + EVP_AES_GCM_CTX *gctx = ctx->cipher_data; + + /* If not set up, return error */ + if (!gctx->key_set) { + return -1; + } + if (!gctx->iv_set) { + return -1; + } + + if (in) { + if (out == NULL) { + if (!CRYPTO_gcm128_aad(&gctx->gcm, in, len)) { + return -1; + } + } else if (ctx->encrypt) { + if (gctx->ctr) { + size_t bulk = 0; +#if defined(AES_GCM_ASM) + if (len >= 32 && AES_GCM_ASM(gctx)) { + size_t res = (16 - gctx->gcm.mres) % 16; + + if (!CRYPTO_gcm128_encrypt(&gctx->gcm, in, out, res)) { + return -1; + } + + bulk = AES_gcm_encrypt(in + res, out + res, len - res, gctx->gcm.key, + gctx->gcm.Yi.c, gctx->gcm.Xi.u); + gctx->gcm.len.u[1] += bulk; + bulk += res; + } +#endif + if (!CRYPTO_gcm128_encrypt_ctr32(&gctx->gcm, in + bulk, out + bulk, + len - bulk, gctx->ctr)) { + return -1; + } + } else { + size_t bulk = 0; + if (!CRYPTO_gcm128_encrypt(&gctx->gcm, in + bulk, out + bulk, + len - bulk)) { + return -1; + } + } + } else { + if (gctx->ctr) { + size_t bulk = 0; +#if defined(AES_GCM_ASM) + if (len >= 16 && AES_GCM_ASM(gctx)) { + size_t res = (16 - gctx->gcm.mres) % 16; + + if (!CRYPTO_gcm128_decrypt(&gctx->gcm, in, out, res)) { + return -1; + } + + bulk = AES_gcm_decrypt(in + res, out + res, len - res, gctx->gcm.key, + gctx->gcm.Yi.c, gctx->gcm.Xi.u); + gctx->gcm.len.u[1] += bulk; + bulk += res; + } +#endif + if (!CRYPTO_gcm128_decrypt_ctr32(&gctx->gcm, in + bulk, out + bulk, + len - bulk, gctx->ctr)) { + return -1; + } + } else { + size_t bulk = 0; + if (!CRYPTO_gcm128_decrypt(&gctx->gcm, in + bulk, out + bulk, + len - bulk)) { + return -1; + } + } + } + return len; + } else { + if (!ctx->encrypt) { + if (gctx->taglen < 0 || + !CRYPTO_gcm128_finish(&gctx->gcm, ctx->buf, gctx->taglen) != 0) { + return -1; + } + gctx->iv_set = 0; + return 0; + } + CRYPTO_gcm128_tag(&gctx->gcm, ctx->buf, 16); + gctx->taglen = 16; + /* Don't reuse the IV */ + gctx->iv_set = 0; + return 0; + } +} + +static const EVP_CIPHER aes_128_cbc = { + NID_aes_128_cbc, 16 /* block_size */, 16 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, aes_init_key, aes_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_128_ctr = { + NID_aes_128_ctr, 1 /* block_size */, 16 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE, + NULL /* app_data */, aes_init_key, aes_ctr_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_128_ecb = { + NID_aes_128_ecb, 16 /* block_size */, 16 /* key_size */, + 0 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE, + NULL /* app_data */, aes_init_key, aes_ecb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_128_ofb = { + NID_aes_128_ofb128, 1 /* block_size */, 16 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_OFB_MODE, + NULL /* app_data */, aes_init_key, aes_ofb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_128_gcm = { + NID_aes_128_gcm, 1 /* block_size */, 16 /* key_size */, 12 /* iv_len */, + sizeof(EVP_AES_GCM_CTX), + EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | + EVP_CIPH_FLAG_AEAD_CIPHER, + NULL /* app_data */, aes_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup, + aes_gcm_ctrl}; + + +static const EVP_CIPHER aes_192_cbc = { + NID_aes_192_cbc, 16 /* block_size */, 24 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, aes_init_key, aes_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_192_ctr = { + NID_aes_192_ctr, 1 /* block_size */, 24 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE, + NULL /* app_data */, aes_init_key, aes_ctr_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_192_ecb = { + NID_aes_192_ecb, 16 /* block_size */, 24 /* key_size */, + 0 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE, + NULL /* app_data */, aes_init_key, aes_ecb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_192_gcm = { + NID_aes_192_gcm, 1 /* block_size */, 24 /* key_size */, 12 /* iv_len */, + sizeof(EVP_AES_GCM_CTX), + EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | + EVP_CIPH_FLAG_AEAD_CIPHER, + NULL /* app_data */, aes_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup, + aes_gcm_ctrl}; + + +static const EVP_CIPHER aes_256_cbc = { + NID_aes_256_cbc, 16 /* block_size */, 32 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, aes_init_key, aes_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_256_ctr = { + NID_aes_256_ctr, 1 /* block_size */, 32 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE, + NULL /* app_data */, aes_init_key, aes_ctr_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_256_ecb = { + NID_aes_256_ecb, 16 /* block_size */, 32 /* key_size */, + 0 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE, + NULL /* app_data */, aes_init_key, aes_ecb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_256_ofb = { + NID_aes_256_ofb128, 1 /* block_size */, 32 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_OFB_MODE, + NULL /* app_data */, aes_init_key, aes_ofb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aes_256_gcm = { + NID_aes_256_gcm, 1 /* block_size */, 32 /* key_size */, 12 /* iv_len */, + sizeof(EVP_AES_GCM_CTX), + EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | + EVP_CIPH_FLAG_AEAD_CIPHER, + NULL /* app_data */, aes_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup, + aes_gcm_ctrl}; + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86_64) || defined(OPENSSL_X86)) + +/* AES-NI section. */ + +static char aesni_capable(void) { + return (OPENSSL_ia32cap_P[1] & (1 << (57 - 32))) != 0; +} + +static int aesni_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + int ret, mode; + EVP_AES_KEY *dat = (EVP_AES_KEY *)ctx->cipher_data; + + mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK; + if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) { + ret = aesni_set_decrypt_key(key, ctx->key_len * 8, ctx->cipher_data); + dat->block = (block128_f)aesni_decrypt; + dat->stream.cbc = + mode == EVP_CIPH_CBC_MODE ? (cbc128_f)aesni_cbc_encrypt : NULL; + } else { + ret = aesni_set_encrypt_key(key, ctx->key_len * 8, ctx->cipher_data); + dat->block = (block128_f)aesni_encrypt; + if (mode == EVP_CIPH_CBC_MODE) { + dat->stream.cbc = (cbc128_f)aesni_cbc_encrypt; + } else if (mode == EVP_CIPH_CTR_MODE) { + dat->stream.ctr = (ctr128_f)aesni_ctr32_encrypt_blocks; + } else { + dat->stream.cbc = NULL; + } + } + + if (ret < 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED); + return 0; + } + + return 1; +} + +static int aesni_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, + const uint8_t *in, size_t len) { + aesni_cbc_encrypt(in, out, len, ctx->cipher_data, ctx->iv, ctx->encrypt); + + return 1; +} + +static int aesni_ecb_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, + const uint8_t *in, size_t len) { + size_t bl = ctx->cipher->block_size; + + if (len < bl) { + return 1; + } + + aesni_ecb_encrypt(in, out, len, ctx->cipher_data, ctx->encrypt); + + return 1; +} + +static int aesni_gcm_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + EVP_AES_GCM_CTX *gctx = ctx->cipher_data; + if (!iv && !key) { + return 1; + } + if (key) { + aesni_set_encrypt_key(key, ctx->key_len * 8, &gctx->ks.ks); + CRYPTO_gcm128_init(&gctx->gcm, &gctx->ks, (block128_f)aesni_encrypt); + gctx->ctr = (ctr128_f)aesni_ctr32_encrypt_blocks; + /* If we have an iv can set it directly, otherwise use + * saved IV. */ + if (iv == NULL && gctx->iv_set) { + iv = gctx->iv; + } + if (iv) { + CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen); + gctx->iv_set = 1; + } + gctx->key_set = 1; + } else { + /* If key set use IV, otherwise copy */ + if (gctx->key_set) { + CRYPTO_gcm128_setiv(&gctx->gcm, iv, gctx->ivlen); + } else { + memcpy(gctx->iv, iv, gctx->ivlen); + } + gctx->iv_set = 1; + gctx->iv_gen = 0; + } + return 1; +} + +static const EVP_CIPHER aesni_128_cbc = { + NID_aes_128_cbc, 16 /* block_size */, 16 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, aesni_init_key, aesni_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_128_ctr = { + NID_aes_128_ctr, 1 /* block_size */, 16 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE, + NULL /* app_data */, aesni_init_key, aes_ctr_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_128_ecb = { + NID_aes_128_ecb, 16 /* block_size */, 16 /* key_size */, + 0 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE, + NULL /* app_data */, aesni_init_key, aesni_ecb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_128_ofb = { + NID_aes_128_ofb128, 1 /* block_size */, 16 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_OFB_MODE, + NULL /* app_data */, aesni_init_key, aes_ofb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_128_gcm = { + NID_aes_128_gcm, 1 /* block_size */, 16 /* key_size */, 12 /* iv_len */, + sizeof(EVP_AES_GCM_CTX), + EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | + EVP_CIPH_FLAG_AEAD_CIPHER, + NULL /* app_data */, aesni_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup, + aes_gcm_ctrl}; + + +static const EVP_CIPHER aesni_192_cbc = { + NID_aes_192_cbc, 16 /* block_size */, 24 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, aesni_init_key, aesni_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_192_ctr = { + NID_aes_192_ctr, 1 /* block_size */, 24 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE, + NULL /* app_data */, aesni_init_key, aes_ctr_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_192_ecb = { + NID_aes_192_ecb, 16 /* block_size */, 24 /* key_size */, + 0 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE, + NULL /* app_data */, aesni_init_key, aesni_ecb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_192_gcm = { + NID_aes_192_gcm, 1 /* block_size */, 24 /* key_size */, 12 /* iv_len */, + sizeof(EVP_AES_GCM_CTX), + EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | + EVP_CIPH_FLAG_AEAD_CIPHER, + NULL /* app_data */, aesni_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup, + aes_gcm_ctrl}; + + +static const EVP_CIPHER aesni_256_cbc = { + NID_aes_256_cbc, 16 /* block_size */, 32 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, aesni_init_key, aesni_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_256_ctr = { + NID_aes_256_ctr, 1 /* block_size */, 32 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_CTR_MODE, + NULL /* app_data */, aesni_init_key, aes_ctr_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_256_ecb = { + NID_aes_256_ecb, 16 /* block_size */, 32 /* key_size */, + 0 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_ECB_MODE, + NULL /* app_data */, aesni_init_key, aesni_ecb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_256_ofb = { + NID_aes_256_ofb128, 1 /* block_size */, 32 /* key_size */, + 16 /* iv_len */, sizeof(EVP_AES_KEY), EVP_CIPH_OFB_MODE, + NULL /* app_data */, aesni_init_key, aes_ofb_cipher, + NULL /* cleanup */, NULL /* ctrl */}; + +static const EVP_CIPHER aesni_256_gcm = { + NID_aes_256_gcm, 1 /* block_size */, 32 /* key_size */, 12 /* iv_len */, + sizeof(EVP_AES_GCM_CTX), + EVP_CIPH_GCM_MODE | EVP_CIPH_CUSTOM_IV | EVP_CIPH_FLAG_CUSTOM_CIPHER | + EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CTRL_INIT | EVP_CIPH_CUSTOM_COPY | + EVP_CIPH_FLAG_AEAD_CIPHER, + NULL /* app_data */, aesni_gcm_init_key, aes_gcm_cipher, aes_gcm_cleanup, + aes_gcm_ctrl}; + +#define EVP_CIPHER_FUNCTION(keybits, mode) \ + const EVP_CIPHER *EVP_aes_##keybits##_##mode(void) { \ + if (aesni_capable()) { \ + return &aesni_##keybits##_##mode; \ + } else { \ + return &aes_##keybits##_##mode; \ + } \ + } + +#else /* ^^^ OPENSSL_X86_64 || OPENSSL_X86 */ + +static char aesni_capable(void) { + return 0; +} + +#define EVP_CIPHER_FUNCTION(keybits, mode) \ + const EVP_CIPHER *EVP_aes_##keybits##_##mode(void) { \ + return &aes_##keybits##_##mode; \ + } + +#endif + +EVP_CIPHER_FUNCTION(128, cbc) +EVP_CIPHER_FUNCTION(128, ctr) +EVP_CIPHER_FUNCTION(128, ecb) +EVP_CIPHER_FUNCTION(128, ofb) +EVP_CIPHER_FUNCTION(128, gcm) + +EVP_CIPHER_FUNCTION(192, cbc) +EVP_CIPHER_FUNCTION(192, ctr) +EVP_CIPHER_FUNCTION(192, ecb) +EVP_CIPHER_FUNCTION(192, gcm) + +EVP_CIPHER_FUNCTION(256, cbc) +EVP_CIPHER_FUNCTION(256, ctr) +EVP_CIPHER_FUNCTION(256, ecb) +EVP_CIPHER_FUNCTION(256, ofb) +EVP_CIPHER_FUNCTION(256, gcm) + + +#define EVP_AEAD_AES_GCM_TAG_LEN 16 + +struct aead_aes_gcm_ctx { + union { + double align; + AES_KEY ks; + } ks; + GCM128_CONTEXT gcm; + ctr128_f ctr; + uint8_t tag_len; +}; + +static int aead_aes_gcm_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len) { + struct aead_aes_gcm_ctx *gcm_ctx; + const size_t key_bits = key_len * 8; + + if (key_bits != 128 && key_bits != 256) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; /* EVP_AEAD_CTX_init should catch this. */ + } + + if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) { + tag_len = EVP_AEAD_AES_GCM_TAG_LEN; + } + + if (tag_len > EVP_AEAD_AES_GCM_TAG_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TAG_TOO_LARGE); + return 0; + } + + gcm_ctx = OPENSSL_malloc(sizeof(struct aead_aes_gcm_ctx)); + if (gcm_ctx == NULL) { + return 0; + } + + gcm_ctx->ctr = + aes_ctr_set_key(&gcm_ctx->ks.ks, &gcm_ctx->gcm, NULL, key, key_len); + gcm_ctx->tag_len = tag_len; + ctx->aead_state = gcm_ctx; + + return 1; +} + +static void aead_aes_gcm_cleanup(EVP_AEAD_CTX *ctx) { + struct aead_aes_gcm_ctx *gcm_ctx = ctx->aead_state; + OPENSSL_cleanse(gcm_ctx, sizeof(struct aead_aes_gcm_ctx)); + OPENSSL_free(gcm_ctx); +} + +static int aead_aes_gcm_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + size_t bulk = 0; + const struct aead_aes_gcm_ctx *gcm_ctx = ctx->aead_state; + GCM128_CONTEXT gcm; + + if (in_len + gcm_ctx->tag_len < in_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + gcm_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + memcpy(&gcm, &gcm_ctx->gcm, sizeof(gcm)); + CRYPTO_gcm128_setiv(&gcm, nonce, nonce_len); + + if (ad_len > 0 && !CRYPTO_gcm128_aad(&gcm, ad, ad_len)) { + return 0; + } + + if (gcm_ctx->ctr) { + if (!CRYPTO_gcm128_encrypt_ctr32(&gcm, in + bulk, out + bulk, in_len - bulk, + gcm_ctx->ctr)) { + return 0; + } + } else { + if (!CRYPTO_gcm128_encrypt(&gcm, in + bulk, out + bulk, in_len - bulk)) { + return 0; + } + } + + CRYPTO_gcm128_tag(&gcm, out + in_len, gcm_ctx->tag_len); + *out_len = in_len + gcm_ctx->tag_len; + return 1; +} + +static int aead_aes_gcm_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + size_t bulk = 0; + const struct aead_aes_gcm_ctx *gcm_ctx = ctx->aead_state; + uint8_t tag[EVP_AEAD_AES_GCM_TAG_LEN]; + size_t plaintext_len; + GCM128_CONTEXT gcm; + + if (in_len < gcm_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + plaintext_len = in_len - gcm_ctx->tag_len; + + if (max_out_len < plaintext_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + memcpy(&gcm, &gcm_ctx->gcm, sizeof(gcm)); + CRYPTO_gcm128_setiv(&gcm, nonce, nonce_len); + + if (!CRYPTO_gcm128_aad(&gcm, ad, ad_len)) { + return 0; + } + + if (gcm_ctx->ctr) { + if (!CRYPTO_gcm128_decrypt_ctr32(&gcm, in + bulk, out + bulk, + in_len - bulk - gcm_ctx->tag_len, + gcm_ctx->ctr)) { + return 0; + } + } else { + if (!CRYPTO_gcm128_decrypt(&gcm, in + bulk, out + bulk, + in_len - bulk - gcm_ctx->tag_len)) { + return 0; + } + } + + CRYPTO_gcm128_tag(&gcm, tag, gcm_ctx->tag_len); + if (CRYPTO_memcmp(tag, in + plaintext_len, gcm_ctx->tag_len) != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + *out_len = plaintext_len; + return 1; +} + +static const EVP_AEAD aead_aes_128_gcm = { + 16, /* key len */ + 12, /* nonce len */ + EVP_AEAD_AES_GCM_TAG_LEN, /* overhead */ + EVP_AEAD_AES_GCM_TAG_LEN, /* max tag length */ + aead_aes_gcm_init, + NULL, /* init_with_direction */ + aead_aes_gcm_cleanup, + aead_aes_gcm_seal, + aead_aes_gcm_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_256_gcm = { + 32, /* key len */ + 12, /* nonce len */ + EVP_AEAD_AES_GCM_TAG_LEN, /* overhead */ + EVP_AEAD_AES_GCM_TAG_LEN, /* max tag length */ + aead_aes_gcm_init, + NULL, /* init_with_direction */ + aead_aes_gcm_cleanup, + aead_aes_gcm_seal, + aead_aes_gcm_open, + NULL, /* get_rc4_state */ +}; + +const EVP_AEAD *EVP_aead_aes_128_gcm(void) { return &aead_aes_128_gcm; } + +const EVP_AEAD *EVP_aead_aes_256_gcm(void) { return &aead_aes_256_gcm; } + + +/* AES Key Wrap is specified in + * http://csrc.nist.gov/groups/ST/toolkit/documents/kms/key-wrap.pdf + * or https://tools.ietf.org/html/rfc3394 */ + +struct aead_aes_key_wrap_ctx { + uint8_t key[32]; + unsigned key_bits; +}; + +static int aead_aes_key_wrap_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len) { + struct aead_aes_key_wrap_ctx *kw_ctx; + const size_t key_bits = key_len * 8; + + if (key_bits != 128 && key_bits != 256) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; /* EVP_AEAD_CTX_init should catch this. */ + } + + if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) { + tag_len = 8; + } + + if (tag_len != 8) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE); + return 0; + } + + kw_ctx = OPENSSL_malloc(sizeof(struct aead_aes_key_wrap_ctx)); + if (kw_ctx == NULL) { + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + + memcpy(kw_ctx->key, key, key_len); + kw_ctx->key_bits = key_bits; + + ctx->aead_state = kw_ctx; + return 1; +} + +static void aead_aes_key_wrap_cleanup(EVP_AEAD_CTX *ctx) { + struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state; + OPENSSL_cleanse(kw_ctx, sizeof(struct aead_aes_key_wrap_ctx)); + OPENSSL_free(kw_ctx); +} + +/* kDefaultAESKeyWrapNonce is the default nonce value given in 2.2.3.1. */ +static const uint8_t kDefaultAESKeyWrapNonce[8] = {0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6}; + + +static int aead_aes_key_wrap_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + const struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state; + union { + double align; + AES_KEY ks; + } ks; + /* Variables in this function match up with the variables in the second half + * of section 2.2.1. */ + unsigned i, j, n; + uint8_t A[AES_BLOCK_SIZE]; + + if (ad_len != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_AD_SIZE); + return 0; + } + + if (nonce_len == 0) { + nonce = kDefaultAESKeyWrapNonce; + nonce_len = sizeof(kDefaultAESKeyWrapNonce); + } + + if (nonce_len != 8) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); + return 0; + } + + if (in_len % 8 != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE); + return 0; + } + + /* The code below only handles a 32-bit |t| thus 6*|n| must be less than + * 2^32, where |n| is |in_len| / 8. So in_len < 4/3 * 2^32 and we + * conservatively cap it to 2^32-16 to stop 32-bit platforms complaining that + * a comparison is always true. */ + if (in_len > 0xfffffff0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + n = in_len / 8; + + if (n < 2) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE); + return 0; + } + + if (in_len + 8 < in_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + 8) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (AES_set_encrypt_key(kw_ctx->key, kw_ctx->key_bits, &ks.ks) < 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED); + return 0; + } + + memmove(out + 8, in, in_len); + memcpy(A, nonce, 8); + + for (j = 0; j < 6; j++) { + for (i = 1; i <= n; i++) { + uint32_t t; + + memcpy(A + 8, out + 8 * i, 8); + AES_encrypt(A, A, &ks.ks); + t = n * j + i; + A[7] ^= t & 0xff; + A[6] ^= (t >> 8) & 0xff; + A[5] ^= (t >> 16) & 0xff; + A[4] ^= (t >> 24) & 0xff; + memcpy(out + 8 * i, A + 8, 8); + } + } + + memcpy(out, A, 8); + *out_len = in_len + 8; + return 1; +} + +static int aead_aes_key_wrap_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + const struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state; + union { + double align; + AES_KEY ks; + } ks; + /* Variables in this function match up with the variables in the second half + * of section 2.2.1. */ + unsigned i, j, n; + uint8_t A[AES_BLOCK_SIZE]; + + if (ad_len != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_AD_SIZE); + return 0; + } + + if (nonce_len == 0) { + nonce = kDefaultAESKeyWrapNonce; + nonce_len = sizeof(kDefaultAESKeyWrapNonce); + } + + if (nonce_len != 8) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); + return 0; + } + + if (in_len % 8 != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE); + return 0; + } + + /* The code below only handles a 32-bit |t| thus 6*|n| must be less than + * 2^32, where |n| is |in_len| / 8. So in_len < 4/3 * 2^32 and we + * conservatively cap it to 2^32-8 to stop 32-bit platforms complaining that + * a comparison is always true. */ + if (in_len > 0xfffffff8) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (in_len < 24) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + n = (in_len / 8) - 1; + + if (max_out_len < in_len - 8) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (AES_set_decrypt_key(kw_ctx->key, kw_ctx->key_bits, &ks.ks) < 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED); + return 0; + } + + memcpy(A, in, 8); + memmove(out, in + 8, in_len - 8); + + for (j = 5; j < 6; j--) { + for (i = n; i > 0; i--) { + uint32_t t; + + t = n * j + i; + A[7] ^= t & 0xff; + A[6] ^= (t >> 8) & 0xff; + A[5] ^= (t >> 16) & 0xff; + A[4] ^= (t >> 24) & 0xff; + memcpy(A + 8, out + 8 * (i - 1), 8); + AES_decrypt(A, A, &ks.ks); + memcpy(out + 8 * (i - 1), A + 8, 8); + } + } + + if (CRYPTO_memcmp(A, nonce, 8) != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + *out_len = in_len - 8; + return 1; +} + +static const EVP_AEAD aead_aes_128_key_wrap = { + 16, /* key len */ + 8, /* nonce len */ + 8, /* overhead */ + 8, /* max tag length */ + aead_aes_key_wrap_init, + NULL, /* init_with_direction */ + aead_aes_key_wrap_cleanup, + aead_aes_key_wrap_seal, + aead_aes_key_wrap_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_256_key_wrap = { + 32, /* key len */ + 8, /* nonce len */ + 8, /* overhead */ + 8, /* max tag length */ + aead_aes_key_wrap_init, + NULL, /* init_with_direction */ + aead_aes_key_wrap_cleanup, + aead_aes_key_wrap_seal, + aead_aes_key_wrap_open, + NULL, /* get_rc4_state */ +}; + +const EVP_AEAD *EVP_aead_aes_128_key_wrap(void) { return &aead_aes_128_key_wrap; } + +const EVP_AEAD *EVP_aead_aes_256_key_wrap(void) { return &aead_aes_256_key_wrap; } + + +#define EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN SHA256_DIGEST_LENGTH +#define EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN 12 + +struct aead_aes_ctr_hmac_sha256_ctx { + union { + double align; + AES_KEY ks; + } ks; + ctr128_f ctr; + block128_f block; + SHA256_CTX inner_init_state; + SHA256_CTX outer_init_state; + uint8_t tag_len; +}; + +static void hmac_init(SHA256_CTX *out_inner, SHA256_CTX *out_outer, + const uint8_t hmac_key[32]) { + static const size_t hmac_key_len = 32; + uint8_t block[SHA256_CBLOCK]; + memcpy(block, hmac_key, hmac_key_len); + memset(block + hmac_key_len, 0x36, sizeof(block) - hmac_key_len); + + unsigned i; + for (i = 0; i < hmac_key_len; i++) { + block[i] ^= 0x36; + } + + SHA256_Init(out_inner); + SHA256_Update(out_inner, block, sizeof(block)); + + memset(block + hmac_key_len, 0x5c, sizeof(block) - hmac_key_len); + for (i = 0; i < hmac_key_len; i++) { + block[i] ^= (0x36 ^ 0x5c); + } + + SHA256_Init(out_outer); + SHA256_Update(out_outer, block, sizeof(block)); +} + +static int aead_aes_ctr_hmac_sha256_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len) { + struct aead_aes_ctr_hmac_sha256_ctx *aes_ctx; + static const size_t hmac_key_len = 32; + + if (key_len < hmac_key_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; /* EVP_AEAD_CTX_init should catch this. */ + } + + const size_t aes_key_len = key_len - hmac_key_len; + if (aes_key_len != 16 && aes_key_len != 32) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; /* EVP_AEAD_CTX_init should catch this. */ + } + + if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) { + tag_len = EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN; + } + + if (tag_len > EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TAG_TOO_LARGE); + return 0; + } + + aes_ctx = OPENSSL_malloc(sizeof(struct aead_aes_ctr_hmac_sha256_ctx)); + if (aes_ctx == NULL) { + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + + aes_ctx->ctr = + aes_ctr_set_key(&aes_ctx->ks.ks, NULL, &aes_ctx->block, key, aes_key_len); + aes_ctx->tag_len = tag_len; + hmac_init(&aes_ctx->inner_init_state, &aes_ctx->outer_init_state, + key + aes_key_len); + + ctx->aead_state = aes_ctx; + + return 1; +} + +static void aead_aes_ctr_hmac_sha256_cleanup(EVP_AEAD_CTX *ctx) { + struct aead_aes_ctr_hmac_sha256_ctx *aes_ctx = ctx->aead_state; + OPENSSL_cleanse(aes_ctx, sizeof(struct aead_aes_ctr_hmac_sha256_ctx)); + OPENSSL_free(aes_ctx); +} + +static void hmac_update_uint64(SHA256_CTX *sha256, uint64_t value) { + unsigned i; + uint8_t bytes[8]; + + for (i = 0; i < sizeof(bytes); i++) { + bytes[i] = value & 0xff; + value >>= 8; + } + SHA256_Update(sha256, bytes, sizeof(bytes)); +} + +static void hmac_calculate(uint8_t out[SHA256_DIGEST_LENGTH], + const SHA256_CTX *inner_init_state, + const SHA256_CTX *outer_init_state, + const uint8_t *ad, size_t ad_len, + const uint8_t *nonce, const uint8_t *ciphertext, + size_t ciphertext_len) { + SHA256_CTX sha256; + memcpy(&sha256, inner_init_state, sizeof(sha256)); + hmac_update_uint64(&sha256, ad_len); + hmac_update_uint64(&sha256, ciphertext_len); + SHA256_Update(&sha256, nonce, EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN); + SHA256_Update(&sha256, ad, ad_len); + + /* Pad with zeros to the end of the SHA-256 block. */ + const unsigned num_padding = + (SHA256_CBLOCK - ((sizeof(uint64_t)*2 + + EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN + ad_len) % + SHA256_CBLOCK)) % + SHA256_CBLOCK; + uint8_t padding[SHA256_CBLOCK]; + memset(padding, 0, num_padding); + SHA256_Update(&sha256, padding, num_padding); + + SHA256_Update(&sha256, ciphertext, ciphertext_len); + + uint8_t inner_digest[SHA256_DIGEST_LENGTH]; + SHA256_Final(inner_digest, &sha256); + + memcpy(&sha256, outer_init_state, sizeof(sha256)); + SHA256_Update(&sha256, inner_digest, sizeof(inner_digest)); + SHA256_Final(out, &sha256); +} + +static void aead_aes_ctr_hmac_sha256_crypt( + const struct aead_aes_ctr_hmac_sha256_ctx *aes_ctx, uint8_t *out, + const uint8_t *in, size_t len, const uint8_t *nonce) { + /* Since the AEAD operation is one-shot, keeping a buffer of unused keystream + * bytes is pointless. However, |CRYPTO_ctr128_encrypt| requires it. */ + uint8_t partial_block_buffer[AES_BLOCK_SIZE]; + unsigned partial_block_offset = 0; + memset(partial_block_buffer, 0, sizeof(partial_block_buffer)); + + uint8_t counter[AES_BLOCK_SIZE]; + memcpy(counter, nonce, EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN); + memset(counter + EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN, 0, 4); + + if (aes_ctx->ctr) { + CRYPTO_ctr128_encrypt_ctr32(in, out, len, &aes_ctx->ks.ks, counter, + partial_block_buffer, &partial_block_offset, + aes_ctx->ctr); + } else { + CRYPTO_ctr128_encrypt(in, out, len, &aes_ctx->ks.ks, counter, + partial_block_buffer, &partial_block_offset, + aes_ctx->block); + } +} + +static int aead_aes_ctr_hmac_sha256_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + const struct aead_aes_ctr_hmac_sha256_ctx *aes_ctx = ctx->aead_state; + const uint64_t in_len_64 = in_len; + + if (in_len + aes_ctx->tag_len < in_len || + /* This input is so large it would overflow the 32-bit block counter. */ + in_len_64 >= (OPENSSL_U64(1) << 32) * AES_BLOCK_SIZE) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + aes_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); + return 0; + } + + aead_aes_ctr_hmac_sha256_crypt(aes_ctx, out, in, in_len, nonce); + + uint8_t hmac_result[SHA256_DIGEST_LENGTH]; + hmac_calculate(hmac_result, &aes_ctx->inner_init_state, + &aes_ctx->outer_init_state, ad, ad_len, nonce, out, in_len); + memcpy(out + in_len, hmac_result, aes_ctx->tag_len); + *out_len = in_len + aes_ctx->tag_len; + + return 1; +} + +static int aead_aes_ctr_hmac_sha256_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + const struct aead_aes_ctr_hmac_sha256_ctx *aes_ctx = ctx->aead_state; + size_t plaintext_len; + + if (in_len < aes_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + plaintext_len = in_len - aes_ctx->tag_len; + + if (max_out_len < plaintext_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); + return 0; + } + + uint8_t hmac_result[SHA256_DIGEST_LENGTH]; + hmac_calculate(hmac_result, &aes_ctx->inner_init_state, + &aes_ctx->outer_init_state, ad, ad_len, nonce, in, + plaintext_len); + if (CRYPTO_memcmp(hmac_result, in + plaintext_len, aes_ctx->tag_len) != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + aead_aes_ctr_hmac_sha256_crypt(aes_ctx, out, in, plaintext_len, nonce); + + *out_len = plaintext_len; + return 1; +} + +static const EVP_AEAD aead_aes_128_ctr_hmac_sha256 = { + 16 /* AES key */ + 32 /* HMAC key */, + 12, /* nonce length */ + EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN, /* overhead */ + EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN, /* max tag length */ + + aead_aes_ctr_hmac_sha256_init, + NULL /* init_with_direction */, + aead_aes_ctr_hmac_sha256_cleanup, + aead_aes_ctr_hmac_sha256_seal, + aead_aes_ctr_hmac_sha256_open, + NULL /* get_rc4_state */, +}; + +static const EVP_AEAD aead_aes_256_ctr_hmac_sha256 = { + 32 /* AES key */ + 32 /* HMAC key */, + 12, /* nonce length */ + EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN, /* overhead */ + EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN, /* max tag length */ + + aead_aes_ctr_hmac_sha256_init, + NULL /* init_with_direction */, + aead_aes_ctr_hmac_sha256_cleanup, + aead_aes_ctr_hmac_sha256_seal, + aead_aes_ctr_hmac_sha256_open, + NULL /* get_rc4_state */, +}; + +const EVP_AEAD *EVP_aead_aes_128_ctr_hmac_sha256(void) { + return &aead_aes_128_ctr_hmac_sha256; +} + +const EVP_AEAD *EVP_aead_aes_256_ctr_hmac_sha256(void) { + return &aead_aes_256_ctr_hmac_sha256; +} + +int EVP_has_aes_hardware(void) { +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) + return aesni_capable() && crypto_gcm_clmul_enabled(); +#elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) + return hwaes_capable() && (OPENSSL_armcap_P & ARMV8_PMULL); +#else + return 0; +#endif +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_chacha20poly1305.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_chacha20poly1305.c new file mode 100644 index 00000000..9dda1b0c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_chacha20poly1305.c @@ -0,0 +1,220 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "internal.h" + + +#define POLY1305_TAG_LEN 16 +#define CHACHA20_NONCE_LEN 8 + +struct aead_chacha20_poly1305_ctx { + unsigned char key[32]; + unsigned char tag_len; +}; + +static int aead_chacha20_poly1305_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len) { + struct aead_chacha20_poly1305_ctx *c20_ctx; + + if (tag_len == 0) { + tag_len = POLY1305_TAG_LEN; + } + + if (tag_len > POLY1305_TAG_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (key_len != sizeof(c20_ctx->key)) { + return 0; /* internal error - EVP_AEAD_CTX_init should catch this. */ + } + + c20_ctx = OPENSSL_malloc(sizeof(struct aead_chacha20_poly1305_ctx)); + if (c20_ctx == NULL) { + return 0; + } + + memcpy(c20_ctx->key, key, key_len); + c20_ctx->tag_len = tag_len; + ctx->aead_state = c20_ctx; + + return 1; +} + +static void aead_chacha20_poly1305_cleanup(EVP_AEAD_CTX *ctx) { + struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; + OPENSSL_cleanse(c20_ctx->key, sizeof(c20_ctx->key)); + OPENSSL_free(c20_ctx); +} + +static void poly1305_update_with_length(poly1305_state *poly1305, + const uint8_t *data, size_t data_len) { + size_t j = data_len; + uint8_t length_bytes[8]; + unsigned i; + + for (i = 0; i < sizeof(length_bytes); i++) { + length_bytes[i] = j; + j >>= 8; + } + + CRYPTO_poly1305_update(poly1305, data, data_len); + CRYPTO_poly1305_update(poly1305, length_bytes, sizeof(length_bytes)); +} + +#if defined(__arm__) +#define ALIGNED __attribute__((aligned(16))) +#else +#define ALIGNED +#endif + +static int aead_chacha20_poly1305_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; + uint8_t poly1305_key[32] ALIGNED; + poly1305_state poly1305; + const uint64_t in_len_64 = in_len; + + /* The underlying ChaCha implementation may not overflow the block + * counter into the second counter word. Therefore we disallow + * individual operations that work on more than 256GB at a time. + * |in_len_64| is needed because, on 32-bit platforms, size_t is only + * 32-bits and this produces a warning because it's always false. + * Casting to uint64_t inside the conditional is not sufficient to stop + * the warning. */ + if (in_len_64 >= (1ull << 32) * 64 - 64) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (in_len + c20_ctx->tag_len < in_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + c20_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != CHACHA20_NONCE_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_IV_TOO_LARGE); + return 0; + } + + memset(poly1305_key, 0, sizeof(poly1305_key)); + CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), + c20_ctx->key, nonce, 0); + + CRYPTO_poly1305_init(&poly1305, poly1305_key); + poly1305_update_with_length(&poly1305, ad, ad_len); + CRYPTO_chacha_20(out, in, in_len, c20_ctx->key, nonce, 1); + poly1305_update_with_length(&poly1305, out, in_len); + + uint8_t tag[POLY1305_TAG_LEN] ALIGNED; + CRYPTO_poly1305_finish(&poly1305, tag); + memcpy(out + in_len, tag, c20_ctx->tag_len); + *out_len = in_len + c20_ctx->tag_len; + return 1; +} + +static int aead_chacha20_poly1305_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + const struct aead_chacha20_poly1305_ctx *c20_ctx = ctx->aead_state; + uint8_t mac[POLY1305_TAG_LEN]; + uint8_t poly1305_key[32] ALIGNED; + size_t plaintext_len; + poly1305_state poly1305; + const uint64_t in_len_64 = in_len; + + if (in_len < c20_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + /* The underlying ChaCha implementation may not overflow the block + * counter into the second counter word. Therefore we disallow + * individual operations that work on more than 256GB at a time. + * |in_len_64| is needed because, on 32-bit platforms, size_t is only + * 32-bits and this produces a warning because it's always false. + * Casting to uint64_t inside the conditional is not sufficient to stop + * the warning. */ + if (in_len_64 >= (1ull << 32) * 64 - 64) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (nonce_len != CHACHA20_NONCE_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_IV_TOO_LARGE); + return 0; + } + + plaintext_len = in_len - c20_ctx->tag_len; + + if (max_out_len < plaintext_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + memset(poly1305_key, 0, sizeof(poly1305_key)); + CRYPTO_chacha_20(poly1305_key, poly1305_key, sizeof(poly1305_key), + c20_ctx->key, nonce, 0); + + CRYPTO_poly1305_init(&poly1305, poly1305_key); + poly1305_update_with_length(&poly1305, ad, ad_len); + poly1305_update_with_length(&poly1305, in, plaintext_len); + CRYPTO_poly1305_finish(&poly1305, mac); + + if (CRYPTO_memcmp(mac, in + plaintext_len, c20_ctx->tag_len) != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + CRYPTO_chacha_20(out, in, plaintext_len, c20_ctx->key, nonce, 1); + *out_len = plaintext_len; + return 1; +} + +static const EVP_AEAD aead_chacha20_poly1305 = { + 32, /* key len */ + CHACHA20_NONCE_LEN, /* nonce len */ + POLY1305_TAG_LEN, /* overhead */ + POLY1305_TAG_LEN, /* max tag length */ + aead_chacha20_poly1305_init, + NULL, /* init_with_direction */ + aead_chacha20_poly1305_cleanup, + aead_chacha20_poly1305_seal, + aead_chacha20_poly1305_open, + NULL, /* get_rc4_state */ +}; + +const EVP_AEAD *EVP_aead_chacha20_poly1305(void) { + return &aead_chacha20_poly1305; +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_des.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_des.c new file mode 100644 index 00000000..4c09a81f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_des.c @@ -0,0 +1,135 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include + +#include "internal.h" + + +typedef struct { + union { + double align; + DES_key_schedule ks; + } ks; +} EVP_DES_KEY; + +static int des_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + DES_cblock *deskey = (DES_cblock *)key; + EVP_DES_KEY *dat = (EVP_DES_KEY *)ctx->cipher_data; + + DES_set_key(deskey, &dat->ks.ks); + return 1; +} + +static int des_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t in_len) { + EVP_DES_KEY *dat = (EVP_DES_KEY *)ctx->cipher_data; + + DES_ncbc_encrypt(in, out, in_len, &dat->ks.ks, (DES_cblock *)ctx->iv, + ctx->encrypt); + + return 1; +} + +static const EVP_CIPHER des_cbc = { + NID_des_cbc, 8 /* block_size */, 8 /* key_size */, + 8 /* iv_len */, sizeof(EVP_DES_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, des_init_key, des_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */, }; + +const EVP_CIPHER *EVP_des_cbc(void) { return &des_cbc; } + + +typedef struct { + union { + double align; + DES_key_schedule ks[3]; + } ks; +} DES_EDE_KEY; + + +static int des_ede3_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + DES_cblock *deskey = (DES_cblock *)key; + DES_EDE_KEY *dat = (DES_EDE_KEY*) ctx->cipher_data; + + DES_set_key(&deskey[0], &dat->ks.ks[0]); + DES_set_key(&deskey[1], &dat->ks.ks[1]); + DES_set_key(&deskey[2], &dat->ks.ks[2]); + + return 1; +} + +static int des_ede3_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, + const uint8_t *in, size_t in_len) { + DES_EDE_KEY *dat = (DES_EDE_KEY*) ctx->cipher_data; + + DES_ede3_cbc_encrypt(in, out, in_len, &dat->ks.ks[0], &dat->ks.ks[1], + &dat->ks.ks[2], (DES_cblock *)ctx->iv, ctx->encrypt); + + return 1; +} + +static const EVP_CIPHER des3_cbc = { + NID_des_ede3_cbc, 8 /* block_size */, 24 /* key_size */, + 8 /* iv_len */, sizeof(DES_EDE_KEY), EVP_CIPH_CBC_MODE, + NULL /* app_data */, des_ede3_init_key, des_ede3_cbc_cipher, + NULL /* cleanup */, NULL /* ctrl */, }; + +const EVP_CIPHER *EVP_des_ede3_cbc(void) { return &des3_cbc; } diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_null.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_null.c new file mode 100644 index 00000000..cfe1d1b2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_null.c @@ -0,0 +1,85 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + +#include "internal.h" + + +static int null_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + return 1; +} + +static int null_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, + const uint8_t *in, size_t in_len) { + if (in != out) { + memcpy(out, in, in_len); + } + return 1; +} + +static const EVP_CIPHER n_cipher = { + NID_undef, 1 /* block size */, 0 /* key_len */, 0 /* iv_len */, + 0 /* ctx_size */, 0 /* flags */, NULL /* app_data */, null_init_key, + null_cipher, NULL /* cleanup */, NULL /* ctrl */, +}; + +const EVP_CIPHER *EVP_enc_null(void) { return &n_cipher; } diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_rc2.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_rc2.c new file mode 100644 index 00000000..8ca7bba6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_rc2.c @@ -0,0 +1,443 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include + +#include "internal.h" + + +#define c2l(c, l) \ + (l = ((uint32_t)(*((c)++))), l |= ((uint32_t)(*((c)++))) << 8L, \ + l |= ((uint32_t)(*((c)++))) << 16L, \ + l |= ((uint32_t)(*((c)++))) << 24L) + +#define c2ln(c, l1, l2, n) \ + { \ + c += n; \ + l1 = l2 = 0; \ + switch (n) { \ + case 8: \ + l2 = ((uint32_t)(*(--(c)))) << 24L; \ + case 7: \ + l2 |= ((uint32_t)(*(--(c)))) << 16L; \ + case 6: \ + l2 |= ((uint32_t)(*(--(c)))) << 8L; \ + case 5: \ + l2 |= ((uint32_t)(*(--(c)))); \ + case 4: \ + l1 = ((uint32_t)(*(--(c)))) << 24L; \ + case 3: \ + l1 |= ((uint32_t)(*(--(c)))) << 16L; \ + case 2: \ + l1 |= ((uint32_t)(*(--(c)))) << 8L; \ + case 1: \ + l1 |= ((uint32_t)(*(--(c)))); \ + } \ + } + +#define l2c(l, c) \ + (*((c)++) = (uint8_t)(((l)) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 8L) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 16L) & 0xff), \ + *((c)++) = (uint8_t)(((l) >> 24L) & 0xff)) + +#define l2cn(l1, l2, c, n) \ + { \ + c += n; \ + switch (n) { \ + case 8: \ + *(--(c)) = (uint8_t)(((l2) >> 24L) & 0xff); \ + case 7: \ + *(--(c)) = (uint8_t)(((l2) >> 16L) & 0xff); \ + case 6: \ + *(--(c)) = (uint8_t)(((l2) >> 8L) & 0xff); \ + case 5: \ + *(--(c)) = (uint8_t)(((l2)) & 0xff); \ + case 4: \ + *(--(c)) = (uint8_t)(((l1) >> 24L) & 0xff); \ + case 3: \ + *(--(c)) = (uint8_t)(((l1) >> 16L) & 0xff); \ + case 2: \ + *(--(c)) = (uint8_t)(((l1) >> 8L) & 0xff); \ + case 1: \ + *(--(c)) = (uint8_t)(((l1)) & 0xff); \ + } \ + } + +typedef struct rc2_key_st { uint16_t data[64]; } RC2_KEY; + +static void RC2_encrypt(uint32_t *d, RC2_KEY *key) { + int i, n; + uint16_t *p0, *p1; + uint16_t x0, x1, x2, x3, t; + uint32_t l; + + l = d[0]; + x0 = (uint16_t)l & 0xffff; + x1 = (uint16_t)(l >> 16L); + l = d[1]; + x2 = (uint16_t)l & 0xffff; + x3 = (uint16_t)(l >> 16L); + + n = 3; + i = 5; + + p0 = p1 = &key->data[0]; + for (;;) { + t = (x0 + (x1 & ~x3) + (x2 & x3) + *(p0++)) & 0xffff; + x0 = (t << 1) | (t >> 15); + t = (x1 + (x2 & ~x0) + (x3 & x0) + *(p0++)) & 0xffff; + x1 = (t << 2) | (t >> 14); + t = (x2 + (x3 & ~x1) + (x0 & x1) + *(p0++)) & 0xffff; + x2 = (t << 3) | (t >> 13); + t = (x3 + (x0 & ~x2) + (x1 & x2) + *(p0++)) & 0xffff; + x3 = (t << 5) | (t >> 11); + + if (--i == 0) { + if (--n == 0) { + break; + } + i = (n == 2) ? 6 : 5; + + x0 += p1[x3 & 0x3f]; + x1 += p1[x0 & 0x3f]; + x2 += p1[x1 & 0x3f]; + x3 += p1[x2 & 0x3f]; + } + } + + d[0] = (uint32_t)(x0 & 0xffff) | ((uint32_t)(x1 & 0xffff) << 16L); + d[1] = (uint32_t)(x2 & 0xffff) | ((uint32_t)(x3 & 0xffff) << 16L); +} + +static void RC2_decrypt(uint32_t *d, RC2_KEY *key) { + int i, n; + uint16_t *p0, *p1; + uint16_t x0, x1, x2, x3, t; + uint32_t l; + + l = d[0]; + x0 = (uint16_t)l & 0xffff; + x1 = (uint16_t)(l >> 16L); + l = d[1]; + x2 = (uint16_t)l & 0xffff; + x3 = (uint16_t)(l >> 16L); + + n = 3; + i = 5; + + p0 = &key->data[63]; + p1 = &key->data[0]; + for (;;) { + t = ((x3 << 11) | (x3 >> 5)) & 0xffff; + x3 = (t - (x0 & ~x2) - (x1 & x2) - *(p0--)) & 0xffff; + t = ((x2 << 13) | (x2 >> 3)) & 0xffff; + x2 = (t - (x3 & ~x1) - (x0 & x1) - *(p0--)) & 0xffff; + t = ((x1 << 14) | (x1 >> 2)) & 0xffff; + x1 = (t - (x2 & ~x0) - (x3 & x0) - *(p0--)) & 0xffff; + t = ((x0 << 15) | (x0 >> 1)) & 0xffff; + x0 = (t - (x1 & ~x3) - (x2 & x3) - *(p0--)) & 0xffff; + + if (--i == 0) { + if (--n == 0) { + break; + } + i = (n == 2) ? 6 : 5; + + x3 = (x3 - p1[x2 & 0x3f]) & 0xffff; + x2 = (x2 - p1[x1 & 0x3f]) & 0xffff; + x1 = (x1 - p1[x0 & 0x3f]) & 0xffff; + x0 = (x0 - p1[x3 & 0x3f]) & 0xffff; + } + } + + d[0] = (uint32_t)(x0 & 0xffff) | ((uint32_t)(x1 & 0xffff) << 16L); + d[1] = (uint32_t)(x2 & 0xffff) | ((uint32_t)(x3 & 0xffff) << 16L); +} + +static void RC2_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + RC2_KEY *ks, uint8_t *iv, int encrypt) { + uint32_t tin0, tin1; + uint32_t tout0, tout1, xor0, xor1; + long l = length; + uint32_t tin[2]; + + if (encrypt) { + c2l(iv, tout0); + c2l(iv, tout1); + iv -= 8; + for (l -= 8; l >= 0; l -= 8) { + c2l(in, tin0); + c2l(in, tin1); + tin0 ^= tout0; + tin1 ^= tout1; + tin[0] = tin0; + tin[1] = tin1; + RC2_encrypt(tin, ks); + tout0 = tin[0]; + l2c(tout0, out); + tout1 = tin[1]; + l2c(tout1, out); + } + if (l != -8) { + c2ln(in, tin0, tin1, l + 8); + tin0 ^= tout0; + tin1 ^= tout1; + tin[0] = tin0; + tin[1] = tin1; + RC2_encrypt(tin, ks); + tout0 = tin[0]; + l2c(tout0, out); + tout1 = tin[1]; + l2c(tout1, out); + } + l2c(tout0, iv); + l2c(tout1, iv); + } else { + c2l(iv, xor0); + c2l(iv, xor1); + iv -= 8; + for (l -= 8; l >= 0; l -= 8) { + c2l(in, tin0); + tin[0] = tin0; + c2l(in, tin1); + tin[1] = tin1; + RC2_decrypt(tin, ks); + tout0 = tin[0] ^ xor0; + tout1 = tin[1] ^ xor1; + l2c(tout0, out); + l2c(tout1, out); + xor0 = tin0; + xor1 = tin1; + } + if (l != -8) { + c2l(in, tin0); + tin[0] = tin0; + c2l(in, tin1); + tin[1] = tin1; + RC2_decrypt(tin, ks); + tout0 = tin[0] ^ xor0; + tout1 = tin[1] ^ xor1; + l2cn(tout0, tout1, out, l + 8); + xor0 = tin0; + xor1 = tin1; + } + l2c(xor0, iv); + l2c(xor1, iv); + } + tin[0] = tin[1] = 0; +} + +static const uint8_t key_table[256] = { + 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, + 0x4a, 0xa0, 0xd8, 0x9d, 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, + 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, 0x17, 0x9a, 0x59, 0xf5, + 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32, + 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, + 0x5c, 0x6b, 0x4e, 0x82, 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, + 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc, 0x12, 0x75, 0xca, 0x1f, + 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26, + 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, + 0xbc, 0x94, 0x43, 0x03, 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, + 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, 0x08, 0xe8, 0xea, 0xde, + 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a, + 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, + 0x04, 0x18, 0xa4, 0xec, 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, + 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39, 0x99, 0x7c, 0x3a, 0x85, + 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31, + 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, + 0x67, 0x6c, 0xba, 0xc9, 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, + 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, 0x0d, 0x38, 0x34, 0x1b, + 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e, + 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, + 0xfe, 0x7f, 0xc1, 0xad, +}; + +static void RC2_set_key(RC2_KEY *key, int len, const uint8_t *data, int bits) { + int i, j; + uint8_t *k; + uint16_t *ki; + unsigned int c, d; + + k = (uint8_t *)&key->data[0]; + *k = 0; /* for if there is a zero length key */ + + if (len > 128) { + len = 128; + } + if (bits <= 0) { + bits = 1024; + } + if (bits > 1024) { + bits = 1024; + } + + for (i = 0; i < len; i++) { + k[i] = data[i]; + } + + /* expand table */ + d = k[len - 1]; + j = 0; + for (i = len; i < 128; i++, j++) { + d = key_table[(k[j] + d) & 0xff]; + k[i] = d; + } + + /* hmm.... key reduction to 'bits' bits */ + + j = (bits + 7) >> 3; + i = 128 - j; + c = (0xff >> (-bits & 0x07)); + + d = key_table[k[i] & c]; + k[i] = d; + while (i--) { + d = key_table[k[i + j] ^ d]; + k[i] = d; + } + + /* copy from bytes into uint16_t's */ + ki = &(key->data[63]); + for (i = 127; i >= 0; i -= 2) { + *(ki--) = ((k[i] << 8) | k[i - 1]) & 0xffff; + } +} + +typedef struct { + int key_bits; /* effective key bits */ + RC2_KEY ks; /* key schedule */ +} EVP_RC2_KEY; + +static int rc2_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + EVP_RC2_KEY *rc2_key = (EVP_RC2_KEY *)ctx->cipher_data; + RC2_set_key(&rc2_key->ks, EVP_CIPHER_CTX_key_length(ctx), key, + rc2_key->key_bits); + return 1; +} + +static int rc2_cbc_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t inl) { + EVP_RC2_KEY *key = (EVP_RC2_KEY *)ctx->cipher_data; + static const size_t kChunkSize = 0x10000; + + while (inl >= kChunkSize) { + RC2_cbc_encrypt(in, out, kChunkSize, &key->ks, ctx->iv, ctx->encrypt); + inl -= kChunkSize; + in += kChunkSize; + out += kChunkSize; + } + if (inl) { + RC2_cbc_encrypt(in, out, inl, &key->ks, ctx->iv, ctx->encrypt); + } + return 1; +} + +static int rc2_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) { + EVP_RC2_KEY *key = (EVP_RC2_KEY *)ctx->cipher_data; + + switch (type) { + case EVP_CTRL_INIT: + key->key_bits = EVP_CIPHER_CTX_key_length(ctx) * 8; + return 1; + case EVP_CTRL_SET_RC2_KEY_BITS: + /* Should be overridden by later call to |EVP_CTRL_INIT|, but + * people call it, so it may as well work. */ + key->key_bits = arg; + return 1; + + default: + return -1; + } +} + +static const EVP_CIPHER rc2_40_cbc = { + NID_rc2_40_cbc, + 8 /* block size */, + 5 /* 40 bit */, + 8 /* iv len */, + sizeof(EVP_RC2_KEY), + EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CTRL_INIT, + NULL /* app_data */, + rc2_init_key, + rc2_cbc_cipher, + NULL, + rc2_ctrl, +}; + +const EVP_CIPHER *EVP_rc2_40_cbc(void) { + return &rc2_40_cbc; +} + +static const EVP_CIPHER rc2_cbc = { + NID_rc2_cbc, + 8 /* block size */, + 16 /* 128 bit */, + 8 /* iv len */, + sizeof(EVP_RC2_KEY), + EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CTRL_INIT, + NULL /* app_data */, + rc2_init_key, + rc2_cbc_cipher, + NULL, + rc2_ctrl, +}; + +const EVP_CIPHER *EVP_rc2_cbc(void) { + return &rc2_cbc; +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_rc4.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_rc4.c new file mode 100644 index 00000000..e05b9fda --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_rc4.c @@ -0,0 +1,397 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +static int rc4_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, + const uint8_t *iv, int enc) { + RC4_KEY *rc4key = (RC4_KEY *)ctx->cipher_data; + + RC4_set_key(rc4key, EVP_CIPHER_CTX_key_length(ctx), key); + return 1; +} + +static int rc4_cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t in_len) { + RC4_KEY *rc4key = (RC4_KEY *)ctx->cipher_data; + + RC4(rc4key, in_len, in, out); + return 1; +} + +static const EVP_CIPHER rc4 = { + NID_rc4, 1 /* block_size */, 16 /* key_size */, + 0 /* iv_len */, sizeof(RC4_KEY), EVP_CIPH_VARIABLE_LENGTH, + NULL /* app_data */, rc4_init_key, rc4_cipher, + NULL /* cleanup */, NULL /* ctrl */, }; + +const EVP_CIPHER *EVP_rc4(void) { return &rc4; } + + +struct aead_rc4_md5_tls_ctx { + RC4_KEY rc4; + MD5_CTX head, tail, md; + size_t payload_length; + unsigned char tag_len; +}; + + +static int +aead_rc4_md5_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, + size_t tag_len) { + struct aead_rc4_md5_tls_ctx *rc4_ctx; + size_t i; + uint8_t hmac_key[MD5_CBLOCK]; + + if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) { + tag_len = MD5_DIGEST_LENGTH; + } + + if (tag_len > MD5_DIGEST_LENGTH) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + /* The keys consists of |MD5_DIGEST_LENGTH| bytes of HMAC(MD5) key followed + * by some number of bytes of RC4 key. */ + if (key_len <= MD5_DIGEST_LENGTH) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; + } + + rc4_ctx = OPENSSL_malloc(sizeof(struct aead_rc4_md5_tls_ctx)); + if (rc4_ctx == NULL) { + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + memset(rc4_ctx, 0, sizeof(struct aead_rc4_md5_tls_ctx)); + + RC4_set_key(&rc4_ctx->rc4, key_len - MD5_DIGEST_LENGTH, + key + MD5_DIGEST_LENGTH); + + memset(hmac_key, 0, sizeof(hmac_key)); + memcpy(hmac_key, key, MD5_DIGEST_LENGTH); + for (i = 0; i < sizeof(hmac_key); i++) { + hmac_key[i] ^= 0x36; + } + MD5_Init(&rc4_ctx->head); + MD5_Update(&rc4_ctx->head, hmac_key, sizeof(hmac_key)); + for (i = 0; i < sizeof(hmac_key); i++) { + hmac_key[i] ^= 0x36 ^ 0x5c; + } + MD5_Init(&rc4_ctx->tail); + MD5_Update(&rc4_ctx->tail, hmac_key, sizeof(hmac_key)); + + rc4_ctx->tag_len = tag_len; + ctx->aead_state = rc4_ctx; + + return 1; +} + +static void aead_rc4_md5_tls_cleanup(EVP_AEAD_CTX *ctx) { + struct aead_rc4_md5_tls_ctx *rc4_ctx = ctx->aead_state; + OPENSSL_cleanse(rc4_ctx, sizeof(struct aead_rc4_md5_tls_ctx)); + OPENSSL_free(rc4_ctx); +} + +#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) +#define STITCHED_CALL + +/* rc4_md5_enc is defined in rc4_md5-x86_64.pl */ +void rc4_md5_enc(RC4_KEY *key, const void *in0, void *out, MD5_CTX *ctx, + const void *inp, size_t blocks); +#endif + +static int aead_rc4_md5_tls_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + struct aead_rc4_md5_tls_ctx *rc4_ctx = ctx->aead_state; + MD5_CTX md; +#if defined(STITCHED_CALL) + size_t rc4_off, md5_off, blocks; +#else + const size_t rc4_off = 0; + const size_t md5_off = 0; +#endif + uint8_t digest[MD5_DIGEST_LENGTH]; + + if (in_len + rc4_ctx->tag_len < in_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (nonce_len != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_IV_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + rc4_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + memcpy(&md, &rc4_ctx->head, sizeof(MD5_CTX)); + /* The MAC's payload begins with the additional data. See + * https://tools.ietf.org/html/rfc5246#section-6.2.3.1 */ + MD5_Update(&md, ad, ad_len); + + /* To allow for CBC mode which changes cipher length, |ad| doesn't include the + * length for legacy ciphers. */ + uint8_t ad_extra[2]; + ad_extra[0] = (uint8_t)(in_len >> 8); + ad_extra[1] = (uint8_t)(in_len & 0xff); + MD5_Update(&md, ad_extra, sizeof(ad_extra)); + +#if defined(STITCHED_CALL) + /* 32 is $MOD from rc4_md5-x86_64.pl. */ + rc4_off = 32 - 1 - (rc4_ctx->rc4.x & (32 - 1)); + md5_off = MD5_CBLOCK - md.num; + /* Ensure RC4 is behind MD5. */ + if (rc4_off > md5_off) { + md5_off += MD5_CBLOCK; + } + assert(md5_off >= rc4_off); + + if (in_len > md5_off && (blocks = (in_len - md5_off) / MD5_CBLOCK) && + (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) { + /* Process the initial portions of the plaintext normally. */ + MD5_Update(&md, in, md5_off); + RC4(&rc4_ctx->rc4, rc4_off, in, out); + + /* Process the next |blocks| blocks of plaintext with stitched routines. */ + rc4_md5_enc(&rc4_ctx->rc4, in + rc4_off, out + rc4_off, &md, in + md5_off, + blocks); + blocks *= MD5_CBLOCK; + rc4_off += blocks; + md5_off += blocks; + md.Nh += blocks >> 29; + md.Nl += blocks <<= 3; + if (md.Nl < (unsigned int)blocks) { + md.Nh++; + } + } else { + rc4_off = 0; + md5_off = 0; + } +#endif + /* Finish computing the MAC. */ + MD5_Update(&md, in + md5_off, in_len - md5_off); + MD5_Final(digest, &md); + + memcpy(&md, &rc4_ctx->tail, sizeof(MD5_CTX)); + MD5_Update(&md, digest, sizeof(digest)); + if (rc4_ctx->tag_len == MD5_DIGEST_LENGTH) { + MD5_Final(out + in_len, &md); + } else { + MD5_Final(digest, &md); + memcpy(out + in_len, digest, rc4_ctx->tag_len); + } + + /* Encrypt the remainder of the plaintext and the MAC. */ + RC4(&rc4_ctx->rc4, in_len - rc4_off, in + rc4_off, out + rc4_off); + RC4(&rc4_ctx->rc4, MD5_DIGEST_LENGTH, out + in_len, out + in_len); + + *out_len = in_len + rc4_ctx->tag_len; + return 1; +} + +static int aead_rc4_md5_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + struct aead_rc4_md5_tls_ctx *rc4_ctx = ctx->aead_state; + MD5_CTX md; + size_t plaintext_len; +#if defined(STITCHED_CALL) + unsigned int l; + size_t rc4_off, md5_off, blocks; + extern unsigned int OPENSSL_ia32cap_P[]; +#else + const size_t rc4_off = 0; + const size_t md5_off = 0; +#endif + uint8_t digest[MD5_DIGEST_LENGTH]; + + if (in_len < rc4_ctx->tag_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + plaintext_len = in_len - rc4_ctx->tag_len; + + if (nonce_len != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len) { + /* This requires that the caller provide space for the MAC, even though it + * will always be removed on return. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + memcpy(&md, &rc4_ctx->head, sizeof(MD5_CTX)); + /* The MAC's payload begins with the additional data. See + * https://tools.ietf.org/html/rfc5246#section-6.2.3.1 */ + MD5_Update(&md, ad, ad_len); + + /* To allow for CBC mode which changes cipher length, |ad| doesn't include the + * length for legacy ciphers. */ + uint8_t ad_extra[2]; + ad_extra[0] = (uint8_t)(plaintext_len >> 8); + ad_extra[1] = (uint8_t)(plaintext_len & 0xff); + MD5_Update(&md, ad_extra, sizeof(ad_extra)); + +#if defined(STITCHED_CALL) + rc4_off = 32 - 1 - (rc4_ctx->rc4.x & (32 - 1)); + md5_off = MD5_CBLOCK - md.num; + /* Ensure MD5 is a full block behind RC4 so it has plaintext to operate on in + * both normal and stitched routines. */ + if (md5_off > rc4_off) { + rc4_off += 2 * MD5_CBLOCK; + } else { + rc4_off += MD5_CBLOCK; + } + + if (in_len > rc4_off && (blocks = (in_len - rc4_off) / MD5_CBLOCK) && + (OPENSSL_ia32cap_P[0] & (1 << 20)) == 0) { + /* Decrypt the initial portion of the ciphertext and digest the plaintext + * normally. */ + RC4(&rc4_ctx->rc4, rc4_off, in, out); + MD5_Update(&md, out, md5_off); + + /* Decrypt and digest the next |blocks| blocks of ciphertext with the + * stitched routines. */ + rc4_md5_enc(&rc4_ctx->rc4, in + rc4_off, out + rc4_off, &md, out + md5_off, + blocks); + blocks *= MD5_CBLOCK; + rc4_off += blocks; + md5_off += blocks; + l = (md.Nl + (blocks << 3)) & 0xffffffffU; + if (l < md.Nl) { + md.Nh++; + } + md.Nl = l; + md.Nh += blocks >> 29; + } else { + md5_off = 0; + rc4_off = 0; + } +#endif + + /* Process the remainder of the input. */ + RC4(&rc4_ctx->rc4, in_len - rc4_off, in + rc4_off, out + rc4_off); + MD5_Update(&md, out + md5_off, plaintext_len - md5_off); + MD5_Final(digest, &md); + + /* Calculate HMAC and verify it */ + memcpy(&md, &rc4_ctx->tail, sizeof(MD5_CTX)); + MD5_Update(&md, digest, MD5_DIGEST_LENGTH); + MD5_Final(digest, &md); + + if (CRYPTO_memcmp(out + plaintext_len, digest, rc4_ctx->tag_len)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + *out_len = plaintext_len; + return 1; +} + +static int aead_rc4_md5_tls_get_rc4_state(const EVP_AEAD_CTX *ctx, + const RC4_KEY **out_key) { + struct aead_rc4_md5_tls_ctx *rc4_ctx = ctx->aead_state; + *out_key = &rc4_ctx->rc4; + return 1; +} + +static const EVP_AEAD aead_rc4_md5_tls = { + 16 + MD5_DIGEST_LENGTH, /* key len (RC4 + MD5) */ + 0, /* nonce len */ + MD5_DIGEST_LENGTH, /* overhead */ + MD5_DIGEST_LENGTH, /* max tag length */ + aead_rc4_md5_tls_init, + NULL, /* init_with_direction */ + aead_rc4_md5_tls_cleanup, + aead_rc4_md5_tls_seal, + aead_rc4_md5_tls_open, + aead_rc4_md5_tls_get_rc4_state, +}; + +const EVP_AEAD *EVP_aead_rc4_md5_tls(void) { return &aead_rc4_md5_tls; } diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_ssl3.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_ssl3.c new file mode 100644 index 00000000..a4b55c90 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_ssl3.c @@ -0,0 +1,422 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +typedef struct { + EVP_CIPHER_CTX cipher_ctx; + EVP_MD_CTX md_ctx; +} AEAD_SSL3_CTX; + +static int ssl3_mac(AEAD_SSL3_CTX *ssl3_ctx, uint8_t *out, unsigned *out_len, + const uint8_t *ad, size_t ad_len, const uint8_t *in, + size_t in_len) { + size_t md_size = EVP_MD_CTX_size(&ssl3_ctx->md_ctx); + size_t pad_len = (md_size == 20) ? 40 : 48; + + /* To allow for CBC mode which changes cipher length, |ad| doesn't include the + * length for legacy ciphers. */ + uint8_t ad_extra[2]; + ad_extra[0] = (uint8_t)(in_len >> 8); + ad_extra[1] = (uint8_t)(in_len & 0xff); + + EVP_MD_CTX md_ctx; + EVP_MD_CTX_init(&md_ctx); + + uint8_t pad[48]; + uint8_t tmp[EVP_MAX_MD_SIZE]; + memset(pad, 0x36, pad_len); + if (!EVP_MD_CTX_copy_ex(&md_ctx, &ssl3_ctx->md_ctx) || + !EVP_DigestUpdate(&md_ctx, pad, pad_len) || + !EVP_DigestUpdate(&md_ctx, ad, ad_len) || + !EVP_DigestUpdate(&md_ctx, ad_extra, sizeof(ad_extra)) || + !EVP_DigestUpdate(&md_ctx, in, in_len) || + !EVP_DigestFinal_ex(&md_ctx, tmp, NULL)) { + EVP_MD_CTX_cleanup(&md_ctx); + return 0; + } + + memset(pad, 0x5c, pad_len); + if (!EVP_MD_CTX_copy_ex(&md_ctx, &ssl3_ctx->md_ctx) || + !EVP_DigestUpdate(&md_ctx, pad, pad_len) || + !EVP_DigestUpdate(&md_ctx, tmp, md_size) || + !EVP_DigestFinal_ex(&md_ctx, out, out_len)) { + EVP_MD_CTX_cleanup(&md_ctx); + return 0; + } + EVP_MD_CTX_cleanup(&md_ctx); + return 1; +} + +static void aead_ssl3_cleanup(EVP_AEAD_CTX *ctx) { + AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state; + EVP_CIPHER_CTX_cleanup(&ssl3_ctx->cipher_ctx); + EVP_MD_CTX_cleanup(&ssl3_ctx->md_ctx); + OPENSSL_free(ssl3_ctx); + ctx->aead_state = NULL; +} + +static int aead_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, + size_t tag_len, enum evp_aead_direction_t dir, + const EVP_CIPHER *cipher, const EVP_MD *md) { + if (tag_len != EVP_AEAD_DEFAULT_TAG_LENGTH && + tag_len != EVP_MD_size(md)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE); + return 0; + } + + if (key_len != EVP_AEAD_key_length(ctx->aead)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; + } + + size_t mac_key_len = EVP_MD_size(md); + size_t enc_key_len = EVP_CIPHER_key_length(cipher); + assert(mac_key_len + enc_key_len + EVP_CIPHER_iv_length(cipher) == key_len); + /* Although EVP_rc4() is a variable-length cipher, the default key size is + * correct for SSL3. */ + + AEAD_SSL3_CTX *ssl3_ctx = OPENSSL_malloc(sizeof(AEAD_SSL3_CTX)); + if (ssl3_ctx == NULL) { + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + EVP_CIPHER_CTX_init(&ssl3_ctx->cipher_ctx); + EVP_MD_CTX_init(&ssl3_ctx->md_ctx); + + ctx->aead_state = ssl3_ctx; + if (!EVP_CipherInit_ex(&ssl3_ctx->cipher_ctx, cipher, NULL, &key[mac_key_len], + &key[mac_key_len + enc_key_len], + dir == evp_aead_seal) || + !EVP_DigestInit_ex(&ssl3_ctx->md_ctx, md, NULL) || + !EVP_DigestUpdate(&ssl3_ctx->md_ctx, key, mac_key_len)) { + aead_ssl3_cleanup(ctx); + ctx->aead_state = NULL; + return 0; + } + EVP_CIPHER_CTX_set_padding(&ssl3_ctx->cipher_ctx, 0); + + return 1; +} + +static int aead_ssl3_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state; + size_t total = 0; + + if (!ssl3_ctx->cipher_ctx.encrypt) { + /* Unlike a normal AEAD, an SSL3 AEAD may only be used in one direction. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION); + return 0; + } + + if (in_len + EVP_AEAD_max_overhead(ctx->aead) < in_len || + in_len > INT_MAX) { + /* EVP_CIPHER takes int as input. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + EVP_AEAD_max_overhead(ctx->aead)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_IV_TOO_LARGE); + return 0; + } + + if (ad_len != 11 - 2 /* length bytes */) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE); + return 0; + } + + /* Compute the MAC. This must be first in case the operation is being done + * in-place. */ + uint8_t mac[EVP_MAX_MD_SIZE]; + unsigned mac_len; + if (!ssl3_mac(ssl3_ctx, mac, &mac_len, ad, ad_len, in, in_len)) { + return 0; + } + + /* Encrypt the input. */ + int len; + if (!EVP_EncryptUpdate(&ssl3_ctx->cipher_ctx, out, &len, in, + (int)in_len)) { + return 0; + } + total = len; + + /* Feed the MAC into the cipher. */ + if (!EVP_EncryptUpdate(&ssl3_ctx->cipher_ctx, out + total, &len, mac, + (int)mac_len)) { + return 0; + } + total += len; + + unsigned block_size = EVP_CIPHER_CTX_block_size(&ssl3_ctx->cipher_ctx); + if (block_size > 1) { + assert(block_size <= 256); + assert(EVP_CIPHER_CTX_mode(&ssl3_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE); + + /* Compute padding and feed that into the cipher. */ + uint8_t padding[256]; + unsigned padding_len = block_size - ((in_len + mac_len) % block_size); + memset(padding, 0, padding_len - 1); + padding[padding_len - 1] = padding_len - 1; + if (!EVP_EncryptUpdate(&ssl3_ctx->cipher_ctx, out + total, &len, padding, + (int)padding_len)) { + return 0; + } + total += len; + } + + if (!EVP_EncryptFinal_ex(&ssl3_ctx->cipher_ctx, out + total, &len)) { + return 0; + } + total += len; + + *out_len = total; + return 1; +} + +static int aead_ssl3_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state; + + if (ssl3_ctx->cipher_ctx.encrypt) { + /* Unlike a normal AEAD, an SSL3 AEAD may only be used in one direction. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION); + return 0; + } + + size_t mac_len = EVP_MD_CTX_size(&ssl3_ctx->md_ctx); + if (in_len < mac_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + if (max_out_len < in_len) { + /* This requires that the caller provide space for the MAC, even though it + * will always be removed on return. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (ad_len != 11 - 2 /* length bytes */) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE); + return 0; + } + + if (in_len > INT_MAX) { + /* EVP_CIPHER takes int as input. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + /* Decrypt to get the plaintext + MAC + padding. */ + size_t total = 0; + int len; + if (!EVP_DecryptUpdate(&ssl3_ctx->cipher_ctx, out, &len, in, (int)in_len)) { + return 0; + } + total += len; + if (!EVP_DecryptFinal_ex(&ssl3_ctx->cipher_ctx, out + total, &len)) { + return 0; + } + total += len; + assert(total == in_len); + + /* Remove CBC padding and MAC. This would normally be timing-sensitive, but SSLv3 CBC + * ciphers are already broken. Support will be removed eventually. + * https://www.openssl.org/~bodo/ssl-poodle.pdf */ + unsigned data_len; + if (EVP_CIPHER_CTX_mode(&ssl3_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE) { + unsigned padding_length = out[total - 1]; + if (total < padding_length + 1 + mac_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + /* The padding must be minimal. */ + if (padding_length + 1 > EVP_CIPHER_CTX_block_size(&ssl3_ctx->cipher_ctx)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + data_len = total - padding_length - 1 - mac_len; + } else { + data_len = total - mac_len; + } + + /* Compute the MAC and compare against the one in the record. */ + uint8_t mac[EVP_MAX_MD_SIZE]; + if (!ssl3_mac(ssl3_ctx, mac, NULL, ad, ad_len, out, data_len)) { + return 0; + } + if (CRYPTO_memcmp(&out[data_len], mac, mac_len) != 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + *out_len = data_len; + return 1; +} + +static int aead_ssl3_get_rc4_state(const EVP_AEAD_CTX *ctx, const RC4_KEY **out_key) { + AEAD_SSL3_CTX *ssl3_ctx = (AEAD_SSL3_CTX *)ctx->aead_state; + if (EVP_CIPHER_CTX_cipher(&ssl3_ctx->cipher_ctx) != EVP_rc4()) { + return 0; + } + + *out_key = (RC4_KEY*) ssl3_ctx->cipher_ctx.cipher_data; + return 1; +} + +static int aead_rc4_md5_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_rc4(), EVP_md5()); +} + +static int aead_rc4_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_rc4(), EVP_sha1()); +} + +static int aead_aes_128_cbc_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(), + EVP_sha1()); +} + +static int aead_aes_256_cbc_sha1_ssl3_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(), + EVP_sha1()); +} +static int aead_des_ede3_cbc_sha1_ssl3_init(EVP_AEAD_CTX *ctx, + const uint8_t *key, size_t key_len, + size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_ssl3_init(ctx, key, key_len, tag_len, dir, EVP_des_ede3_cbc(), + EVP_sha1()); +} + +static const EVP_AEAD aead_rc4_md5_ssl3 = { + MD5_DIGEST_LENGTH + 16, /* key len (MD5 + RC4) */ + 0, /* nonce len */ + MD5_DIGEST_LENGTH, /* overhead */ + MD5_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_rc4_md5_ssl3_init, + aead_ssl3_cleanup, + aead_ssl3_seal, + aead_ssl3_open, + aead_ssl3_get_rc4_state, +}; + +static const EVP_AEAD aead_rc4_sha1_ssl3 = { + SHA_DIGEST_LENGTH + 16, /* key len (SHA1 + RC4) */ + 0, /* nonce len */ + SHA_DIGEST_LENGTH, /* overhead */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_rc4_sha1_ssl3_init, + aead_ssl3_cleanup, + aead_ssl3_seal, + aead_ssl3_open, + aead_ssl3_get_rc4_state, +}; + +static const EVP_AEAD aead_aes_128_cbc_sha1_ssl3 = { + SHA_DIGEST_LENGTH + 16 + 16, /* key len (SHA1 + AES128 + IV) */ + 0, /* nonce len */ + 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_128_cbc_sha1_ssl3_init, + aead_ssl3_cleanup, + aead_ssl3_seal, + aead_ssl3_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_256_cbc_sha1_ssl3 = { + SHA_DIGEST_LENGTH + 32 + 16, /* key len (SHA1 + AES256 + IV) */ + 0, /* nonce len */ + 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_256_cbc_sha1_ssl3_init, + aead_ssl3_cleanup, + aead_ssl3_seal, + aead_ssl3_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_des_ede3_cbc_sha1_ssl3 = { + SHA_DIGEST_LENGTH + 24 + 8, /* key len (SHA1 + 3DES + IV) */ + 0, /* nonce len */ + 8 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_des_ede3_cbc_sha1_ssl3_init, + aead_ssl3_cleanup, + aead_ssl3_seal, + aead_ssl3_open, + NULL, /* get_rc4_state */ +}; + +const EVP_AEAD *EVP_aead_rc4_md5_ssl3(void) { return &aead_rc4_md5_ssl3; } + +const EVP_AEAD *EVP_aead_rc4_sha1_ssl3(void) { return &aead_rc4_sha1_ssl3; } + +const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_ssl3(void) { + return &aead_aes_128_cbc_sha1_ssl3; +} + +const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_ssl3(void) { + return &aead_aes_256_cbc_sha1_ssl3; +} + +const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_ssl3(void) { + return &aead_des_ede3_cbc_sha1_ssl3; +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/e_tls.c b/TMessagesProj/jni/boringssl/crypto/cipher/e_tls.c new file mode 100644 index 00000000..7938c36d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/e_tls.c @@ -0,0 +1,613 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../crypto/internal.h" +#include "internal.h" + + +typedef struct { + EVP_CIPHER_CTX cipher_ctx; + HMAC_CTX hmac_ctx; + /* mac_key is the portion of the key used for the MAC. It is retained + * separately for the constant-time CBC code. */ + uint8_t mac_key[EVP_MAX_MD_SIZE]; + uint8_t mac_key_len; + /* implicit_iv is one iff this is a pre-TLS-1.1 CBC cipher without an explicit + * IV. */ + char implicit_iv; +} AEAD_TLS_CTX; + +OPENSSL_COMPILE_ASSERT(EVP_MAX_MD_SIZE < 256, mac_key_len_fits_in_uint8_t); + +static void aead_tls_cleanup(EVP_AEAD_CTX *ctx) { + AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state; + EVP_CIPHER_CTX_cleanup(&tls_ctx->cipher_ctx); + HMAC_CTX_cleanup(&tls_ctx->hmac_ctx); + OPENSSL_cleanse(&tls_ctx->mac_key, sizeof(tls_ctx->mac_key)); + OPENSSL_free(tls_ctx); + ctx->aead_state = NULL; +} + +static int aead_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, + size_t tag_len, enum evp_aead_direction_t dir, + const EVP_CIPHER *cipher, const EVP_MD *md, + char implicit_iv) { + if (tag_len != EVP_AEAD_DEFAULT_TAG_LENGTH && + tag_len != EVP_MD_size(md)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE); + return 0; + } + + if (key_len != EVP_AEAD_key_length(ctx->aead)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); + return 0; + } + + size_t mac_key_len = EVP_MD_size(md); + size_t enc_key_len = EVP_CIPHER_key_length(cipher); + assert(mac_key_len + enc_key_len + + (implicit_iv ? EVP_CIPHER_iv_length(cipher) : 0) == key_len); + /* Although EVP_rc4() is a variable-length cipher, the default key size is + * correct for TLS. */ + + AEAD_TLS_CTX *tls_ctx = OPENSSL_malloc(sizeof(AEAD_TLS_CTX)); + if (tls_ctx == NULL) { + OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); + return 0; + } + EVP_CIPHER_CTX_init(&tls_ctx->cipher_ctx); + HMAC_CTX_init(&tls_ctx->hmac_ctx); + assert(mac_key_len <= EVP_MAX_MD_SIZE); + memcpy(tls_ctx->mac_key, key, mac_key_len); + tls_ctx->mac_key_len = (uint8_t)mac_key_len; + tls_ctx->implicit_iv = implicit_iv; + + ctx->aead_state = tls_ctx; + if (!EVP_CipherInit_ex(&tls_ctx->cipher_ctx, cipher, NULL, &key[mac_key_len], + implicit_iv ? &key[mac_key_len + enc_key_len] : NULL, + dir == evp_aead_seal) || + !HMAC_Init_ex(&tls_ctx->hmac_ctx, key, mac_key_len, md, NULL)) { + aead_tls_cleanup(ctx); + ctx->aead_state = NULL; + return 0; + } + EVP_CIPHER_CTX_set_padding(&tls_ctx->cipher_ctx, 0); + + return 1; +} + +static int aead_tls_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state; + size_t total = 0; + + if (!tls_ctx->cipher_ctx.encrypt) { + /* Unlike a normal AEAD, a TLS AEAD may only be used in one direction. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION); + return 0; + + } + + if (in_len + EVP_AEAD_max_overhead(ctx->aead) < in_len || + in_len > INT_MAX) { + /* EVP_CIPHER takes int as input. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + EVP_AEAD_max_overhead(ctx->aead)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE); + return 0; + } + + if (ad_len != 13 - 2 /* length bytes */) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE); + return 0; + } + + /* To allow for CBC mode which changes cipher length, |ad| doesn't include the + * length for legacy ciphers. */ + uint8_t ad_extra[2]; + ad_extra[0] = (uint8_t)(in_len >> 8); + ad_extra[1] = (uint8_t)(in_len & 0xff); + + /* Compute the MAC. This must be first in case the operation is being done + * in-place. */ + uint8_t mac[EVP_MAX_MD_SIZE]; + unsigned mac_len; + HMAC_CTX hmac_ctx; + HMAC_CTX_init(&hmac_ctx); + if (!HMAC_CTX_copy_ex(&hmac_ctx, &tls_ctx->hmac_ctx) || + !HMAC_Update(&hmac_ctx, ad, ad_len) || + !HMAC_Update(&hmac_ctx, ad_extra, sizeof(ad_extra)) || + !HMAC_Update(&hmac_ctx, in, in_len) || + !HMAC_Final(&hmac_ctx, mac, &mac_len)) { + HMAC_CTX_cleanup(&hmac_ctx); + return 0; + } + HMAC_CTX_cleanup(&hmac_ctx); + + /* Configure the explicit IV. */ + if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE && + !tls_ctx->implicit_iv && + !EVP_EncryptInit_ex(&tls_ctx->cipher_ctx, NULL, NULL, NULL, nonce)) { + return 0; + } + + /* Encrypt the input. */ + int len; + if (!EVP_EncryptUpdate(&tls_ctx->cipher_ctx, out, &len, in, + (int)in_len)) { + return 0; + } + total = len; + + /* Feed the MAC into the cipher. */ + if (!EVP_EncryptUpdate(&tls_ctx->cipher_ctx, out + total, &len, mac, + (int)mac_len)) { + return 0; + } + total += len; + + unsigned block_size = EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx); + if (block_size > 1) { + assert(block_size <= 256); + assert(EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE); + + /* Compute padding and feed that into the cipher. */ + uint8_t padding[256]; + unsigned padding_len = block_size - ((in_len + mac_len) % block_size); + memset(padding, padding_len - 1, padding_len); + if (!EVP_EncryptUpdate(&tls_ctx->cipher_ctx, out + total, &len, padding, + (int)padding_len)) { + return 0; + } + total += len; + } + + if (!EVP_EncryptFinal_ex(&tls_ctx->cipher_ctx, out + total, &len)) { + return 0; + } + total += len; + + *out_len = total; + return 1; +} + +static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX *)ctx->aead_state; + + if (tls_ctx->cipher_ctx.encrypt) { + /* Unlike a normal AEAD, a TLS AEAD may only be used in one direction. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_OPERATION); + return 0; + + } + + if (in_len < HMAC_size(&tls_ctx->hmac_ctx)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + if (max_out_len < in_len) { + /* This requires that the caller provide space for the MAC, even though it + * will always be removed on return. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != EVP_AEAD_nonce_length(ctx->aead)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_NONCE_SIZE); + return 0; + } + + if (ad_len != 13 - 2 /* length bytes */) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_INVALID_AD_SIZE); + return 0; + } + + if (in_len > INT_MAX) { + /* EVP_CIPHER takes int as input. */ + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + /* Configure the explicit IV. */ + if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE && + !tls_ctx->implicit_iv && + !EVP_DecryptInit_ex(&tls_ctx->cipher_ctx, NULL, NULL, NULL, nonce)) { + return 0; + } + + /* Decrypt to get the plaintext + MAC + padding. */ + size_t total = 0; + int len; + if (!EVP_DecryptUpdate(&tls_ctx->cipher_ctx, out, &len, in, (int)in_len)) { + return 0; + } + total += len; + if (!EVP_DecryptFinal_ex(&tls_ctx->cipher_ctx, out + total, &len)) { + return 0; + } + total += len; + assert(total == in_len); + + /* Remove CBC padding. Code from here on is timing-sensitive with respect to + * |padding_ok| and |data_plus_mac_len| for CBC ciphers. */ + int padding_ok; + unsigned data_plus_mac_len, data_len; + if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE) { + padding_ok = EVP_tls_cbc_remove_padding( + &data_plus_mac_len, out, total, + EVP_CIPHER_CTX_block_size(&tls_ctx->cipher_ctx), + (unsigned)HMAC_size(&tls_ctx->hmac_ctx)); + /* Publicly invalid. This can be rejected in non-constant time. */ + if (padding_ok == 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + } else { + padding_ok = 1; + data_plus_mac_len = total; + /* |data_plus_mac_len| = |total| = |in_len| at this point. |in_len| has + * already been checked against the MAC size at the top of the function. */ + assert(data_plus_mac_len >= HMAC_size(&tls_ctx->hmac_ctx)); + } + data_len = data_plus_mac_len - HMAC_size(&tls_ctx->hmac_ctx); + + /* At this point, |padding_ok| is 1 or -1. If 1, the padding is valid and the + * first |data_plus_mac_size| bytes after |out| are the plaintext and + * MAC. Either way, |data_plus_mac_size| is large enough to extract a MAC. */ + + /* To allow for CBC mode which changes cipher length, |ad| doesn't include the + * length for legacy ciphers. */ + uint8_t ad_fixed[13]; + memcpy(ad_fixed, ad, 11); + ad_fixed[11] = (uint8_t)(data_len >> 8); + ad_fixed[12] = (uint8_t)(data_len & 0xff); + ad_len += 2; + + /* Compute the MAC and extract the one in the record. */ + uint8_t mac[EVP_MAX_MD_SIZE]; + size_t mac_len; + uint8_t record_mac_tmp[EVP_MAX_MD_SIZE]; + uint8_t *record_mac; + if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE && + EVP_tls_cbc_record_digest_supported(tls_ctx->hmac_ctx.md)) { + if (!EVP_tls_cbc_digest_record(tls_ctx->hmac_ctx.md, mac, &mac_len, + ad_fixed, out, data_plus_mac_len, total, + tls_ctx->mac_key, tls_ctx->mac_key_len)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + assert(mac_len == HMAC_size(&tls_ctx->hmac_ctx)); + + record_mac = record_mac_tmp; + EVP_tls_cbc_copy_mac(record_mac, mac_len, out, data_plus_mac_len, total); + } else { + /* We should support the constant-time path for all CBC-mode ciphers + * implemented. */ + assert(EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) != EVP_CIPH_CBC_MODE); + + HMAC_CTX hmac_ctx; + HMAC_CTX_init(&hmac_ctx); + unsigned mac_len_u; + if (!HMAC_CTX_copy_ex(&hmac_ctx, &tls_ctx->hmac_ctx) || + !HMAC_Update(&hmac_ctx, ad_fixed, ad_len) || + !HMAC_Update(&hmac_ctx, out, data_len) || + !HMAC_Final(&hmac_ctx, mac, &mac_len_u)) { + HMAC_CTX_cleanup(&hmac_ctx); + return 0; + } + mac_len = mac_len_u; + HMAC_CTX_cleanup(&hmac_ctx); + + assert(mac_len == HMAC_size(&tls_ctx->hmac_ctx)); + record_mac = &out[data_len]; + } + + /* Perform the MAC check and the padding check in constant-time. It should be + * safe to simply perform the padding check first, but it would not be under a + * different choice of MAC location on padding failure. See + * EVP_tls_cbc_remove_padding. */ + unsigned good = constant_time_eq_int(CRYPTO_memcmp(record_mac, mac, mac_len), + 0); + good &= constant_time_eq_int(padding_ok, 1); + if (!good) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + /* End of timing-sensitive code. */ + + *out_len = data_len; + return 1; +} + +static int aead_rc4_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_rc4(), EVP_sha1(), + 0); +} + +static int aead_aes_128_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(), + EVP_sha1(), 0); +} + +static int aead_aes_128_cbc_sha1_tls_implicit_iv_init( + EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(), + EVP_sha1(), 1); +} + +static int aead_aes_128_cbc_sha256_tls_init(EVP_AEAD_CTX *ctx, + const uint8_t *key, size_t key_len, + size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_128_cbc(), + EVP_sha256(), 0); +} + +static int aead_aes_256_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(), + EVP_sha1(), 0); +} + +static int aead_aes_256_cbc_sha1_tls_implicit_iv_init( + EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(), + EVP_sha1(), 1); +} + +static int aead_aes_256_cbc_sha256_tls_init(EVP_AEAD_CTX *ctx, + const uint8_t *key, size_t key_len, + size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(), + EVP_sha256(), 0); +} + +static int aead_aes_256_cbc_sha384_tls_init(EVP_AEAD_CTX *ctx, + const uint8_t *key, size_t key_len, + size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_aes_256_cbc(), + EVP_sha384(), 0); +} + +static int aead_des_ede3_cbc_sha1_tls_init(EVP_AEAD_CTX *ctx, + const uint8_t *key, size_t key_len, + size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_des_ede3_cbc(), + EVP_sha1(), 0); +} + +static int aead_des_ede3_cbc_sha1_tls_implicit_iv_init( + EVP_AEAD_CTX *ctx, const uint8_t *key, size_t key_len, size_t tag_len, + enum evp_aead_direction_t dir) { + return aead_tls_init(ctx, key, key_len, tag_len, dir, EVP_des_ede3_cbc(), + EVP_sha1(), 1); +} + +static int aead_rc4_sha1_tls_get_rc4_state(const EVP_AEAD_CTX *ctx, + const RC4_KEY **out_key) { + const AEAD_TLS_CTX *tls_ctx = (AEAD_TLS_CTX*) ctx->aead_state; + if (EVP_CIPHER_CTX_cipher(&tls_ctx->cipher_ctx) != EVP_rc4()) { + return 0; + } + + *out_key = (const RC4_KEY*) tls_ctx->cipher_ctx.cipher_data; + return 1; +} + +static const EVP_AEAD aead_rc4_sha1_tls = { + SHA_DIGEST_LENGTH + 16, /* key len (SHA1 + RC4) */ + 0, /* nonce len */ + SHA_DIGEST_LENGTH, /* overhead */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_rc4_sha1_tls_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + aead_rc4_sha1_tls_get_rc4_state, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_128_cbc_sha1_tls = { + SHA_DIGEST_LENGTH + 16, /* key len (SHA1 + AES128) */ + 16, /* nonce len (IV) */ + 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_128_cbc_sha1_tls_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_128_cbc_sha1_tls_implicit_iv = { + SHA_DIGEST_LENGTH + 16 + 16, /* key len (SHA1 + AES128 + IV) */ + 0, /* nonce len */ + 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_128_cbc_sha1_tls_implicit_iv_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_128_cbc_sha256_tls = { + SHA256_DIGEST_LENGTH + 16, /* key len (SHA256 + AES128) */ + 16, /* nonce len (IV) */ + 16 + SHA256_DIGEST_LENGTH, /* overhead (padding + SHA256) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_128_cbc_sha256_tls_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_256_cbc_sha1_tls = { + SHA_DIGEST_LENGTH + 32, /* key len (SHA1 + AES256) */ + 16, /* nonce len (IV) */ + 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_256_cbc_sha1_tls_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_256_cbc_sha1_tls_implicit_iv = { + SHA_DIGEST_LENGTH + 32 + 16, /* key len (SHA1 + AES256 + IV) */ + 0, /* nonce len */ + 16 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_256_cbc_sha1_tls_implicit_iv_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_256_cbc_sha256_tls = { + SHA256_DIGEST_LENGTH + 32, /* key len (SHA256 + AES256) */ + 16, /* nonce len (IV) */ + 16 + SHA256_DIGEST_LENGTH, /* overhead (padding + SHA256) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_256_cbc_sha256_tls_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_aes_256_cbc_sha384_tls = { + SHA384_DIGEST_LENGTH + 32, /* key len (SHA384 + AES256) */ + 16, /* nonce len (IV) */ + 16 + SHA384_DIGEST_LENGTH, /* overhead (padding + SHA384) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_aes_256_cbc_sha384_tls_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_des_ede3_cbc_sha1_tls = { + SHA_DIGEST_LENGTH + 24, /* key len (SHA1 + 3DES) */ + 8, /* nonce len (IV) */ + 8 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_des_ede3_cbc_sha1_tls_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +static const EVP_AEAD aead_des_ede3_cbc_sha1_tls_implicit_iv = { + SHA_DIGEST_LENGTH + 24 + 8, /* key len (SHA1 + 3DES + IV) */ + 0, /* nonce len */ + 8 + SHA_DIGEST_LENGTH, /* overhead (padding + SHA1) */ + SHA_DIGEST_LENGTH, /* max tag length */ + NULL, /* init */ + aead_des_ede3_cbc_sha1_tls_implicit_iv_init, + aead_tls_cleanup, + aead_tls_seal, + aead_tls_open, + NULL, /* get_rc4_state */ +}; + +const EVP_AEAD *EVP_aead_rc4_sha1_tls(void) { return &aead_rc4_sha1_tls; } + +const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls(void) { + return &aead_aes_128_cbc_sha1_tls; +} + +const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls_implicit_iv(void) { + return &aead_aes_128_cbc_sha1_tls_implicit_iv; +} + +const EVP_AEAD *EVP_aead_aes_128_cbc_sha256_tls(void) { + return &aead_aes_128_cbc_sha256_tls; +} + +const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls(void) { + return &aead_aes_256_cbc_sha1_tls; +} + +const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls_implicit_iv(void) { + return &aead_aes_256_cbc_sha1_tls_implicit_iv; +} + +const EVP_AEAD *EVP_aead_aes_256_cbc_sha256_tls(void) { + return &aead_aes_256_cbc_sha256_tls; +} + +const EVP_AEAD *EVP_aead_aes_256_cbc_sha384_tls(void) { + return &aead_aes_256_cbc_sha384_tls; +} + +const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls(void) { + return &aead_des_ede3_cbc_sha1_tls; +} + +const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv(void) { + return &aead_des_ede3_cbc_sha1_tls_implicit_iv; +} diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/internal.h b/TMessagesProj/jni/boringssl/crypto/cipher/internal.h new file mode 100644 index 00000000..b2a94f44 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/internal.h @@ -0,0 +1,161 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_CIPHER_INTERNAL_H +#define OPENSSL_HEADER_CIPHER_INTERNAL_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* EVP_CIPH_MODE_MASK contains the bits of |flags| that represent the mode. */ +#define EVP_CIPH_MODE_MASK 0x3f + + +/* EVP_AEAD represents a specific AEAD algorithm. */ +struct evp_aead_st { + uint8_t key_len; + uint8_t nonce_len; + uint8_t overhead; + uint8_t max_tag_len; + + /* init initialises an |EVP_AEAD_CTX|. If this call returns zero then + * |cleanup| will not be called for that context. */ + int (*init)(EVP_AEAD_CTX *, const uint8_t *key, size_t key_len, + size_t tag_len); + int (*init_with_direction)(EVP_AEAD_CTX *, const uint8_t *key, size_t key_len, + size_t tag_len, enum evp_aead_direction_t dir); + void (*cleanup)(EVP_AEAD_CTX *); + + int (*seal)(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, + size_t max_out_len, const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, const uint8_t *ad, + size_t ad_len); + + int (*open)(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, + size_t max_out_len, const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, const uint8_t *ad, + size_t ad_len); + + int (*get_rc4_state)(const EVP_AEAD_CTX *ctx, const RC4_KEY **out_key); +}; + + +/* EVP_tls_cbc_get_padding determines the padding from the decrypted, TLS, CBC + * record in |in|. This decrypted record should not include any "decrypted" + * explicit IV. It sets |*out_len| to the length with the padding removed or + * |in_len| if invalid. + * + * block_size: the block size of the cipher used to encrypt the record. + * returns: + * 0: (in non-constant time) if the record is publicly invalid. + * 1: if the padding was valid + * -1: otherwise. */ +int EVP_tls_cbc_remove_padding(unsigned *out_len, + const uint8_t *in, unsigned in_len, + unsigned block_size, unsigned mac_size); + +/* EVP_tls_cbc_copy_mac copies |md_size| bytes from the end of the first + * |in_len| bytes of |in| to |out| in constant time (independent of the concrete + * value of |in_len|, which may vary within a 256-byte window). |in| must point + * to a buffer of |orig_len| bytes. + * + * On entry: + * orig_len >= in_len >= md_size + * md_size <= EVP_MAX_MD_SIZE */ +void EVP_tls_cbc_copy_mac(uint8_t *out, unsigned md_size, + const uint8_t *in, unsigned in_len, + unsigned orig_len); + +/* EVP_tls_cbc_record_digest_supported returns 1 iff |md| is a hash function + * which EVP_tls_cbc_digest_record supports. */ +int EVP_tls_cbc_record_digest_supported(const EVP_MD *md); + +/* EVP_tls_cbc_digest_record computes the MAC of a decrypted, padded TLS + * record. + * + * md: the hash function used in the HMAC. + * EVP_tls_cbc_record_digest_supported must return true for this hash. + * md_out: the digest output. At most EVP_MAX_MD_SIZE bytes will be written. + * md_out_size: the number of output bytes is written here. + * header: the 13-byte, TLS record header. + * data: the record data itself + * data_plus_mac_size: the secret, reported length of the data and MAC + * once the padding has been removed. + * data_plus_mac_plus_padding_size: the public length of the whole + * record, including padding. + * + * On entry: by virtue of having been through one of the remove_padding + * functions, above, we know that data_plus_mac_size is large enough to contain + * a padding byte and MAC. (If the padding was invalid, it might contain the + * padding too. ) */ +int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out, + size_t *md_out_size, const uint8_t header[13], + const uint8_t *data, size_t data_plus_mac_size, + size_t data_plus_mac_plus_padding_size, + const uint8_t *mac_secret, + unsigned mac_secret_length); + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CIPHER_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/cipher/tls_cbc.c b/TMessagesProj/jni/boringssl/crypto/cipher/tls_cbc.c new file mode 100644 index 00000000..8bca2f30 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cipher/tls_cbc.c @@ -0,0 +1,495 @@ +/* ==================================================================== + * Copyright (c) 2012 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include + +#include +#include +#include + +#include "../internal.h" + + +/* TODO(davidben): unsigned should be size_t. The various constant_time + * functions need to be switched to size_t. */ + +/* MAX_HASH_BIT_COUNT_BYTES is the maximum number of bytes in the hash's length + * field. (SHA-384/512 have 128-bit length.) */ +#define MAX_HASH_BIT_COUNT_BYTES 16 + +/* MAX_HASH_BLOCK_SIZE is the maximum hash block size that we'll support. + * Currently SHA-384/512 has a 128-byte block size and that's the largest + * supported by TLS.) */ +#define MAX_HASH_BLOCK_SIZE 128 + +int EVP_tls_cbc_remove_padding(unsigned *out_len, + const uint8_t *in, unsigned in_len, + unsigned block_size, unsigned mac_size) { + unsigned padding_length, good, to_check, i; + const unsigned overhead = 1 /* padding length byte */ + mac_size; + + /* These lengths are all public so we can test them in non-constant time. */ + if (overhead > in_len) { + return 0; + } + + padding_length = in[in_len - 1]; + + good = constant_time_ge(in_len, overhead + padding_length); + /* The padding consists of a length byte at the end of the record and + * then that many bytes of padding, all with the same value as the + * length byte. Thus, with the length byte included, there are i+1 + * bytes of padding. + * + * We can't check just |padding_length+1| bytes because that leaks + * decrypted information. Therefore we always have to check the maximum + * amount of padding possible. (Again, the length of the record is + * public information so we can use it.) */ + to_check = 256; /* maximum amount of padding, inc length byte. */ + if (to_check > in_len) { + to_check = in_len; + } + + for (i = 0; i < to_check; i++) { + uint8_t mask = constant_time_ge_8(padding_length, i); + uint8_t b = in[in_len - 1 - i]; + /* The final |padding_length+1| bytes should all have the value + * |padding_length|. Therefore the XOR should be zero. */ + good &= ~(mask & (padding_length ^ b)); + } + + /* If any of the final |padding_length+1| bytes had the wrong value, + * one or more of the lower eight bits of |good| will be cleared. */ + good = constant_time_eq(0xff, good & 0xff); + + /* Always treat |padding_length| as zero on error. If, assuming block size of + * 16, a padding of [<15 arbitrary bytes> 15] treated |padding_length| as 16 + * and returned -1, distinguishing good MAC and bad padding from bad MAC and + * bad padding would give POODLE's padding oracle. */ + padding_length = good & (padding_length + 1); + *out_len = in_len - padding_length; + + return constant_time_select_int(good, 1, -1); +} + +/* If CBC_MAC_ROTATE_IN_PLACE is defined then EVP_tls_cbc_copy_mac is performed + * with variable accesses in a 64-byte-aligned buffer. Assuming that this fits + * into a single or pair of cache-lines, then the variable memory accesses don't + * actually affect the timing. CPUs with smaller cache-lines [if any] are not + * multi-core and are not considered vulnerable to cache-timing attacks. */ +#define CBC_MAC_ROTATE_IN_PLACE + +void EVP_tls_cbc_copy_mac(uint8_t *out, unsigned md_size, + const uint8_t *in, unsigned in_len, + unsigned orig_len) { +#if defined(CBC_MAC_ROTATE_IN_PLACE) + uint8_t rotated_mac_buf[64 + EVP_MAX_MD_SIZE]; + uint8_t *rotated_mac; +#else + uint8_t rotated_mac[EVP_MAX_MD_SIZE]; +#endif + + /* mac_end is the index of |in| just after the end of the MAC. */ + unsigned mac_end = in_len; + unsigned mac_start = mac_end - md_size; + /* scan_start contains the number of bytes that we can ignore because + * the MAC's position can only vary by 255 bytes. */ + unsigned scan_start = 0; + unsigned i, j; + unsigned div_spoiler; + unsigned rotate_offset; + + assert(orig_len >= in_len); + assert(in_len >= md_size); + assert(md_size <= EVP_MAX_MD_SIZE); + +#if defined(CBC_MAC_ROTATE_IN_PLACE) + rotated_mac = rotated_mac_buf + ((0 - (size_t)rotated_mac_buf) & 63); +#endif + + /* This information is public so it's safe to branch based on it. */ + if (orig_len > md_size + 255 + 1) { + scan_start = orig_len - (md_size + 255 + 1); + } + /* div_spoiler contains a multiple of md_size that is used to cause the + * modulo operation to be constant time. Without this, the time varies + * based on the amount of padding when running on Intel chips at least. + * + * The aim of right-shifting md_size is so that the compiler doesn't + * figure out that it can remove div_spoiler as that would require it + * to prove that md_size is always even, which I hope is beyond it. */ + div_spoiler = md_size >> 1; + div_spoiler <<= (sizeof(div_spoiler) - 1) * 8; + rotate_offset = (div_spoiler + mac_start - scan_start) % md_size; + + memset(rotated_mac, 0, md_size); + for (i = scan_start, j = 0; i < orig_len; i++) { + uint8_t mac_started = constant_time_ge_8(i, mac_start); + uint8_t mac_ended = constant_time_ge_8(i, mac_end); + uint8_t b = in[i]; + rotated_mac[j++] |= b & mac_started & ~mac_ended; + j &= constant_time_lt(j, md_size); + } + +/* Now rotate the MAC */ +#if defined(CBC_MAC_ROTATE_IN_PLACE) + j = 0; + for (i = 0; i < md_size; i++) { + /* in case cache-line is 32 bytes, touch second line */ + ((volatile uint8_t *)rotated_mac)[rotate_offset ^ 32]; + out[j++] = rotated_mac[rotate_offset++]; + rotate_offset &= constant_time_lt(rotate_offset, md_size); + } +#else + memset(out, 0, md_size); + rotate_offset = md_size - rotate_offset; + rotate_offset &= constant_time_lt(rotate_offset, md_size); + for (i = 0; i < md_size; i++) { + for (j = 0; j < md_size; j++) { + out[j] |= rotated_mac[i] & constant_time_eq_8(j, rotate_offset); + } + rotate_offset++; + rotate_offset &= constant_time_lt(rotate_offset, md_size); + } +#endif +} + +/* u32toBE serialises an unsigned, 32-bit number (n) as four bytes at (p) in + * big-endian order. The value of p is advanced by four. */ +#define u32toBE(n, p) \ + (*((p)++)=(uint8_t)(n>>24), \ + *((p)++)=(uint8_t)(n>>16), \ + *((p)++)=(uint8_t)(n>>8), \ + *((p)++)=(uint8_t)(n)) + +/* u64toBE serialises an unsigned, 64-bit number (n) as eight bytes at (p) in + * big-endian order. The value of p is advanced by eight. */ +#define u64toBE(n, p) \ + (*((p)++)=(uint8_t)(n>>56), \ + *((p)++)=(uint8_t)(n>>48), \ + *((p)++)=(uint8_t)(n>>40), \ + *((p)++)=(uint8_t)(n>>32), \ + *((p)++)=(uint8_t)(n>>24), \ + *((p)++)=(uint8_t)(n>>16), \ + *((p)++)=(uint8_t)(n>>8), \ + *((p)++)=(uint8_t)(n)) + +/* These functions serialize the state of a hash and thus perform the standard + * "final" operation without adding the padding and length that such a function + * typically does. */ +static void tls1_sha1_final_raw(void *ctx, uint8_t *md_out) { + SHA_CTX *sha1 = ctx; + u32toBE(sha1->h0, md_out); + u32toBE(sha1->h1, md_out); + u32toBE(sha1->h2, md_out); + u32toBE(sha1->h3, md_out); + u32toBE(sha1->h4, md_out); +} +#define LARGEST_DIGEST_CTX SHA_CTX + +static void tls1_sha256_final_raw(void *ctx, uint8_t *md_out) { + SHA256_CTX *sha256 = ctx; + unsigned i; + + for (i = 0; i < 8; i++) { + u32toBE(sha256->h[i], md_out); + } +} +#undef LARGEST_DIGEST_CTX +#define LARGEST_DIGEST_CTX SHA256_CTX + +static void tls1_sha512_final_raw(void *ctx, uint8_t *md_out) { + SHA512_CTX *sha512 = ctx; + unsigned i; + + for (i = 0; i < 8; i++) { + u64toBE(sha512->h[i], md_out); + } +} +#undef LARGEST_DIGEST_CTX +#define LARGEST_DIGEST_CTX SHA512_CTX + +int EVP_tls_cbc_record_digest_supported(const EVP_MD *md) { + switch (EVP_MD_type(md)) { + case NID_sha1: + case NID_sha256: + case NID_sha384: + return 1; + + default: + return 0; + } +} + +int EVP_tls_cbc_digest_record(const EVP_MD *md, uint8_t *md_out, + size_t *md_out_size, const uint8_t header[13], + const uint8_t *data, size_t data_plus_mac_size, + size_t data_plus_mac_plus_padding_size, + const uint8_t *mac_secret, + unsigned mac_secret_length) { + union { + double align; + uint8_t c[sizeof(LARGEST_DIGEST_CTX)]; + } md_state; + void (*md_final_raw)(void *ctx, uint8_t *md_out); + void (*md_transform)(void *ctx, const uint8_t *block); + unsigned md_size, md_block_size = 64; + unsigned len, max_mac_bytes, num_blocks, num_starting_blocks, k, + mac_end_offset, c, index_a, index_b; + unsigned int bits; /* at most 18 bits */ + uint8_t length_bytes[MAX_HASH_BIT_COUNT_BYTES]; + /* hmac_pad is the masked HMAC key. */ + uint8_t hmac_pad[MAX_HASH_BLOCK_SIZE]; + uint8_t first_block[MAX_HASH_BLOCK_SIZE]; + uint8_t mac_out[EVP_MAX_MD_SIZE]; + unsigned i, j, md_out_size_u; + EVP_MD_CTX md_ctx; + /* mdLengthSize is the number of bytes in the length field that terminates + * the hash. */ + unsigned md_length_size = 8; + + /* This is a, hopefully redundant, check that allows us to forget about + * many possible overflows later in this function. */ + assert(data_plus_mac_plus_padding_size < 1024 * 1024); + + switch (EVP_MD_type(md)) { + case NID_sha1: + SHA1_Init((SHA_CTX *)md_state.c); + md_final_raw = tls1_sha1_final_raw; + md_transform = + (void (*)(void *ctx, const uint8_t *block))SHA1_Transform; + md_size = 20; + break; + + case NID_sha256: + SHA256_Init((SHA256_CTX *)md_state.c); + md_final_raw = tls1_sha256_final_raw; + md_transform = + (void (*)(void *ctx, const uint8_t *block))SHA256_Transform; + md_size = 32; + break; + + case NID_sha384: + SHA384_Init((SHA512_CTX *)md_state.c); + md_final_raw = tls1_sha512_final_raw; + md_transform = + (void (*)(void *ctx, const uint8_t *block))SHA512_Transform; + md_size = 384 / 8; + md_block_size = 128; + md_length_size = 16; + break; + + default: + /* EVP_tls_cbc_record_digest_supported should have been called first to + * check that the hash function is supported. */ + assert(0); + *md_out_size = 0; + return 0; + } + + assert(md_length_size <= MAX_HASH_BIT_COUNT_BYTES); + assert(md_block_size <= MAX_HASH_BLOCK_SIZE); + assert(md_size <= EVP_MAX_MD_SIZE); + + static const unsigned kHeaderLength = 13; + + /* kVarianceBlocks is the number of blocks of the hash that we have to + * calculate in constant time because they could be altered by the + * padding value. + * + * TLSv1 has MACs up to 48 bytes long (SHA-384) and the padding is not + * required to be minimal. Therefore we say that the final six blocks + * can vary based on the padding. */ + static const unsigned kVarianceBlocks = 6; + + /* From now on we're dealing with the MAC, which conceptually has 13 + * bytes of `header' before the start of the data. */ + len = data_plus_mac_plus_padding_size + kHeaderLength; + /* max_mac_bytes contains the maximum bytes of bytes in the MAC, including + * |header|, assuming that there's no padding. */ + max_mac_bytes = len - md_size - 1; + /* num_blocks is the maximum number of hash blocks. */ + num_blocks = + (max_mac_bytes + 1 + md_length_size + md_block_size - 1) / md_block_size; + /* In order to calculate the MAC in constant time we have to handle + * the final blocks specially because the padding value could cause the + * end to appear somewhere in the final |kVarianceBlocks| blocks and we + * can't leak where. However, |num_starting_blocks| worth of data can + * be hashed right away because no padding value can affect whether + * they are plaintext. */ + num_starting_blocks = 0; + /* k is the starting byte offset into the conceptual header||data where + * we start processing. */ + k = 0; + /* mac_end_offset is the index just past the end of the data to be + * MACed. */ + mac_end_offset = data_plus_mac_size + kHeaderLength - md_size; + /* c is the index of the 0x80 byte in the final hash block that + * contains application data. */ + c = mac_end_offset % md_block_size; + /* index_a is the hash block number that contains the 0x80 terminating + * value. */ + index_a = mac_end_offset / md_block_size; + /* index_b is the hash block number that contains the 64-bit hash + * length, in bits. */ + index_b = (mac_end_offset + md_length_size) / md_block_size; + /* bits is the hash-length in bits. It includes the additional hash + * block for the masked HMAC key. */ + + if (num_blocks > kVarianceBlocks) { + num_starting_blocks = num_blocks - kVarianceBlocks; + k = md_block_size * num_starting_blocks; + } + + bits = 8 * mac_end_offset; + + /* Compute the initial HMAC block. */ + bits += 8 * md_block_size; + memset(hmac_pad, 0, md_block_size); + assert(mac_secret_length <= sizeof(hmac_pad)); + memcpy(hmac_pad, mac_secret, mac_secret_length); + for (i = 0; i < md_block_size; i++) { + hmac_pad[i] ^= 0x36; + } + + md_transform(md_state.c, hmac_pad); + + memset(length_bytes, 0, md_length_size - 4); + length_bytes[md_length_size - 4] = (uint8_t)(bits >> 24); + length_bytes[md_length_size - 3] = (uint8_t)(bits >> 16); + length_bytes[md_length_size - 2] = (uint8_t)(bits >> 8); + length_bytes[md_length_size - 1] = (uint8_t)bits; + + if (k > 0) { + /* k is a multiple of md_block_size. */ + memcpy(first_block, header, 13); + memcpy(first_block + 13, data, md_block_size - 13); + md_transform(md_state.c, first_block); + for (i = 1; i < k / md_block_size; i++) { + md_transform(md_state.c, data + md_block_size * i - 13); + } + } + + memset(mac_out, 0, sizeof(mac_out)); + + /* We now process the final hash blocks. For each block, we construct + * it in constant time. If the |i==index_a| then we'll include the 0x80 + * bytes and zero pad etc. For each block we selectively copy it, in + * constant time, to |mac_out|. */ + for (i = num_starting_blocks; i <= num_starting_blocks + kVarianceBlocks; + i++) { + uint8_t block[MAX_HASH_BLOCK_SIZE]; + uint8_t is_block_a = constant_time_eq_8(i, index_a); + uint8_t is_block_b = constant_time_eq_8(i, index_b); + for (j = 0; j < md_block_size; j++) { + uint8_t b = 0, is_past_c, is_past_cp1; + if (k < kHeaderLength) { + b = header[k]; + } else if (k < data_plus_mac_plus_padding_size + kHeaderLength) { + b = data[k - kHeaderLength]; + } + k++; + + is_past_c = is_block_a & constant_time_ge_8(j, c); + is_past_cp1 = is_block_a & constant_time_ge_8(j, c + 1); + /* If this is the block containing the end of the + * application data, and we are at the offset for the + * 0x80 value, then overwrite b with 0x80. */ + b = constant_time_select_8(is_past_c, 0x80, b); + /* If this the the block containing the end of the + * application data and we're past the 0x80 value then + * just write zero. */ + b = b & ~is_past_cp1; + /* If this is index_b (the final block), but not + * index_a (the end of the data), then the 64-bit + * length didn't fit into index_a and we're having to + * add an extra block of zeros. */ + b &= ~is_block_b | is_block_a; + + /* The final bytes of one of the blocks contains the + * length. */ + if (j >= md_block_size - md_length_size) { + /* If this is index_b, write a length byte. */ + b = constant_time_select_8( + is_block_b, length_bytes[j - (md_block_size - md_length_size)], b); + } + block[j] = b; + } + + md_transform(md_state.c, block); + md_final_raw(md_state.c, block); + /* If this is index_b, copy the hash value to |mac_out|. */ + for (j = 0; j < md_size; j++) { + mac_out[j] |= block[j] & is_block_b; + } + } + + EVP_MD_CTX_init(&md_ctx); + if (!EVP_DigestInit_ex(&md_ctx, md, NULL /* engine */)) { + EVP_MD_CTX_cleanup(&md_ctx); + return 0; + } + + /* Complete the HMAC in the standard manner. */ + for (i = 0; i < md_block_size; i++) { + hmac_pad[i] ^= 0x6a; + } + + EVP_DigestUpdate(&md_ctx, hmac_pad, md_block_size); + EVP_DigestUpdate(&md_ctx, mac_out, md_size); + EVP_DigestFinal(&md_ctx, md_out, &md_out_size_u); + *md_out_size = md_out_size_u; + EVP_MD_CTX_cleanup(&md_ctx); + + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/cmac/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/cmac/CMakeLists.txt new file mode 100644 index 00000000..4629af60 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cmac/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + cmac + + OBJECT + + cmac.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/cmac/cmac.c b/TMessagesProj/jni/boringssl/crypto/cmac/cmac.c new file mode 100644 index 00000000..fa4c3c49 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cmac/cmac.c @@ -0,0 +1,239 @@ +/* ==================================================================== + * Copyright (c) 2010 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== */ + +#include + +#include +#include + +#include +#include +#include + + +struct cmac_ctx_st { + EVP_CIPHER_CTX cipher_ctx; + /* k1 and k2 are the CMAC subkeys. See + * https://tools.ietf.org/html/rfc4493#section-2.3 */ + uint8_t k1[AES_BLOCK_SIZE]; + uint8_t k2[AES_BLOCK_SIZE]; + /* Last (possibly partial) scratch */ + uint8_t block[AES_BLOCK_SIZE]; + /* block_used contains the number of valid bytes in |block|. */ + unsigned block_used; +}; + +static void CMAC_CTX_init(CMAC_CTX *ctx) { + EVP_CIPHER_CTX_init(&ctx->cipher_ctx); +} + +static void CMAC_CTX_cleanup(CMAC_CTX *ctx) { + EVP_CIPHER_CTX_cleanup(&ctx->cipher_ctx); + OPENSSL_cleanse(ctx->k1, sizeof(ctx->k1)); + OPENSSL_cleanse(ctx->k2, sizeof(ctx->k2)); + OPENSSL_cleanse(ctx->block, sizeof(ctx->block)); +} + +int AES_CMAC(uint8_t out[16], const uint8_t *key, size_t key_len, + const uint8_t *in, size_t in_len) { + const EVP_CIPHER *cipher; + switch (key_len) { + case 16: + cipher = EVP_aes_128_cbc(); + break; + case 32: + cipher = EVP_aes_256_cbc(); + break; + default: + return 0; + } + + size_t scratch_out_len; + CMAC_CTX ctx; + CMAC_CTX_init(&ctx); + + const int ok = CMAC_Init(&ctx, key, key_len, cipher, NULL /* engine */) && + CMAC_Update(&ctx, in, in_len) && + CMAC_Final(&ctx, out, &scratch_out_len); + + CMAC_CTX_cleanup(&ctx); + return ok; +} + +CMAC_CTX *CMAC_CTX_new(void) { + CMAC_CTX *ctx = OPENSSL_malloc(sizeof(*ctx)); + if (ctx != NULL) { + CMAC_CTX_init(ctx); + } + return ctx; +} + +void CMAC_CTX_free(CMAC_CTX *ctx) { + if (ctx == NULL) { + return; + } + + CMAC_CTX_cleanup(ctx); + OPENSSL_free(ctx); +} + +/* binary_field_mul_x treats the 128 bits at |in| as an element of GF(2¹²⁸) + * with a hard-coded reduction polynomial and sets |out| as x times the + * input. + * + * See https://tools.ietf.org/html/rfc4493#section-2.3 */ +static void binary_field_mul_x(uint8_t out[16], const uint8_t in[16]) { + unsigned i; + + /* Shift |in| to left, including carry. */ + for (i = 0; i < 15; i++) { + out[i] = (in[i] << 1) | (in[i+1] >> 7); + } + + /* If MSB set fixup with R. */ + const uint8_t carry = in[0] >> 7; + out[i] = (in[i] << 1) ^ ((0 - carry) & 0x87); +} + +static const uint8_t kZeroIV[AES_BLOCK_SIZE] = {0}; + +int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t key_len, + const EVP_CIPHER *cipher, ENGINE *engine) { + uint8_t scratch[AES_BLOCK_SIZE]; + + if (EVP_CIPHER_block_size(cipher) != AES_BLOCK_SIZE || + EVP_CIPHER_key_length(cipher) != key_len || + !EVP_EncryptInit_ex(&ctx->cipher_ctx, cipher, NULL, key, kZeroIV) || + !EVP_Cipher(&ctx->cipher_ctx, scratch, kZeroIV, AES_BLOCK_SIZE) || + /* Reset context again ready for first data. */ + !EVP_EncryptInit_ex(&ctx->cipher_ctx, NULL, NULL, NULL, kZeroIV)) { + return 0; + } + + binary_field_mul_x(ctx->k1, scratch); + binary_field_mul_x(ctx->k2, ctx->k1); + ctx->block_used = 0; + + return 1; +} + +int CMAC_Reset(CMAC_CTX *ctx) { + ctx->block_used = 0; + return EVP_EncryptInit_ex(&ctx->cipher_ctx, NULL, NULL, NULL, kZeroIV); +} + +int CMAC_Update(CMAC_CTX *ctx, const uint8_t *in, size_t in_len) { + uint8_t scratch[AES_BLOCK_SIZE]; + + if (ctx->block_used > 0) { + size_t todo = AES_BLOCK_SIZE - ctx->block_used; + if (in_len < todo) { + todo = in_len; + } + + memcpy(ctx->block + ctx->block_used, in, todo); + in += todo; + in_len -= todo; + ctx->block_used += todo; + + /* If |in_len| is zero then either |ctx->block_used| is less than + * |AES_BLOCK_SIZE|, in which case we can stop here, or |ctx->block_used| + * is exactly |AES_BLOCK_SIZE| but there's no more data to process. In the + * latter case we don't want to process this block now because it might be + * the last block and that block is treated specially. */ + if (in_len == 0) { + return 1; + } + + assert(ctx->block_used == AES_BLOCK_SIZE); + + if (!EVP_Cipher(&ctx->cipher_ctx, scratch, ctx->block, AES_BLOCK_SIZE)) { + return 0; + } + } + + /* Encrypt all but one of the remaining blocks. */ + while (in_len > AES_BLOCK_SIZE) { + if (!EVP_Cipher(&ctx->cipher_ctx, scratch, in, AES_BLOCK_SIZE)) { + return 0; + } + in += AES_BLOCK_SIZE; + in_len -= AES_BLOCK_SIZE; + } + + memcpy(ctx->block, in, in_len); + ctx->block_used = in_len; + + return 1; +} + +int CMAC_Final(CMAC_CTX *ctx, uint8_t *out, size_t *out_len) { + *out_len = AES_BLOCK_SIZE; + if (out == NULL) { + return 1; + } + + const uint8_t *mask = ctx->k1; + + if (ctx->block_used != AES_BLOCK_SIZE) { + /* If the last block is incomplete, terminate it with a single 'one' bit + * followed by zeros. */ + ctx->block[ctx->block_used] = 0x80; + memset(ctx->block + ctx->block_used + 1, 0, + AES_BLOCK_SIZE - (ctx->block_used + 1)); + + mask = ctx->k2; + } + + unsigned i; + for (i = 0; i < AES_BLOCK_SIZE; i++) { + out[i] = ctx->block[i] ^ mask[i]; + } + + return EVP_Cipher(&ctx->cipher_ctx, out, out, AES_BLOCK_SIZE); +} diff --git a/TMessagesProj/jni/boringssl/crypto/conf/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/conf/CMakeLists.txt new file mode 100644 index 00000000..8046bb84 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/conf/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + conf + + OBJECT + + conf.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/conf/conf.c b/TMessagesProj/jni/boringssl/crypto/conf/conf.c new file mode 100644 index 00000000..cd6b5652 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/conf/conf.c @@ -0,0 +1,774 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include "conf_def.h" + + +static uint32_t conf_value_hash(const CONF_VALUE *v) { + return (lh_strhash(v->section) << 2) ^ lh_strhash(v->name); +} + +static int conf_value_cmp(const CONF_VALUE *a, const CONF_VALUE *b) { + int i; + + if (a->section != b->section) { + i = strcmp(a->section, b->section); + if (i) { + return i; + } + } + + if (a->name != NULL && b->name != NULL) { + return strcmp(a->name, b->name); + } else if (a->name == b->name) { + return 0; + } else { + return (a->name == NULL) ? -1 : 1; + } +} + +CONF *NCONF_new(void *method) { + CONF *conf; + + if (method != NULL) { + return NULL; + } + + conf = OPENSSL_malloc(sizeof(CONF)); + if (conf == NULL) { + return NULL; + } + + conf->data = lh_CONF_VALUE_new(conf_value_hash, conf_value_cmp); + if (conf->data == NULL) { + OPENSSL_free(conf); + return NULL; + } + + return conf; +} + +static void value_free_contents(CONF_VALUE *value) { + if (value->section) { + OPENSSL_free(value->section); + } + if (value->name) { + OPENSSL_free(value->name); + if (value->value) { + OPENSSL_free(value->value); + } + } else { + if (value->value) { + sk_CONF_VALUE_free((STACK_OF(CONF_VALUE)*)value->value); + } + } +} + +static void value_free(CONF_VALUE *value) { + value_free_contents(value); + OPENSSL_free(value); +} + +void NCONF_free(CONF *conf) { + if (conf == NULL || conf->data == NULL) { + return; + } + + lh_CONF_VALUE_doall(conf->data, value_free_contents); + lh_CONF_VALUE_free(conf->data); + OPENSSL_free(conf); +} + +CONF_VALUE *NCONF_new_section(const CONF *conf, const char *section) { + STACK_OF(CONF_VALUE) *sk = NULL; + int ok = 0, i; + CONF_VALUE *v = NULL, *old_value; + + sk = sk_CONF_VALUE_new_null(); + v = OPENSSL_malloc(sizeof(CONF_VALUE)); + if (sk == NULL || v == NULL) { + goto err; + } + i = strlen(section) + 1; + v->section = OPENSSL_malloc(i); + if (v->section == NULL) { + goto err; + } + + memcpy(v->section, section, i); + v->section[i-1] = 0; + v->name = NULL; + v->value = (char *)sk; + + if (!lh_CONF_VALUE_insert(conf->data, &old_value, v)) { + goto err; + } + if (old_value) { + value_free(old_value); + } + ok = 1; + +err: + if (!ok) { + if (sk != NULL) { + sk_CONF_VALUE_free(sk); + } + if (v != NULL) { + OPENSSL_free(v); + } + v = NULL; + } + return v; +} + +static int str_copy(CONF *conf, char *section, char **pto, char *from) { + int q, r, rr = 0, to = 0, len = 0; + char *s, *e, *rp, *rrp, *np, *cp, v; + const char *p; + BUF_MEM *buf; + + buf = BUF_MEM_new(); + if (buf == NULL) { + return 0; + } + + len = strlen(from) + 1; + if (!BUF_MEM_grow(buf, len)) { + goto err; + } + + for (;;) { + if (IS_QUOTE(conf, *from)) { + q = *from; + from++; + while (!IS_EOF(conf, *from) && (*from != q)) { + if (IS_ESC(conf, *from)) { + from++; + if (IS_EOF(conf, *from)) { + break; + } + } + buf->data[to++] = *(from++); + } + if (*from == q) { + from++; + } + } else if (IS_DQUOTE(conf, *from)) { + q = *from; + from++; + while (!IS_EOF(conf, *from)) { + if (*from == q) { + if (*(from + 1) == q) { + from++; + } else { + break; + } + } + buf->data[to++] = *(from++); + } + if (*from == q) { + from++; + } + } else if (IS_ESC(conf, *from)) { + from++; + v = *(from++); + if (IS_EOF(conf, v)) { + break; + } else if (v == 'r') { + v = '\r'; + } else if (v == 'n') { + v = '\n'; + } else if (v == 'b') { + v = '\b'; + } else if (v == 't') { + v = '\t'; + } + buf->data[to++] = v; + } else if (IS_EOF(conf, *from)) { + break; + } else if (*from == '$') { + /* try to expand it */ + rrp = NULL; + s = &(from[1]); + if (*s == '{') { + q = '}'; + } else if (*s == '(') { + q = ')'; + } else { + q = 0; + } + + if (q) { + s++; + } + cp = section; + e = np = s; + while (IS_ALPHA_NUMERIC(conf, *e)) { + e++; + } + if (e[0] == ':' && e[1] == ':') { + cp = np; + rrp = e; + rr = *e; + *rrp = '\0'; + e += 2; + np = e; + while (IS_ALPHA_NUMERIC(conf, *e)) { + e++; + } + } + r = *e; + *e = '\0'; + rp = e; + if (q) { + if (r != q) { + OPENSSL_PUT_ERROR(CONF, CONF_R_NO_CLOSE_BRACE); + goto err; + } + e++; + } + /* So at this point we have + * np which is the start of the name string which is + * '\0' terminated. + * cp which is the start of the section string which is + * '\0' terminated. + * e is the 'next point after'. + * r and rr are the chars replaced by the '\0' + * rp and rrp is where 'r' and 'rr' came from. */ + p = NCONF_get_string(conf, cp, np); + if (rrp != NULL) { + *rrp = rr; + } + *rp = r; + if (p == NULL) { + OPENSSL_PUT_ERROR(CONF, CONF_R_VARIABLE_HAS_NO_VALUE); + goto err; + } + BUF_MEM_grow_clean(buf, (strlen(p) + buf->length - (e - from))); + while (*p) { + buf->data[to++] = *(p++); + } + + /* Since we change the pointer 'from', we also have + to change the perceived length of the string it + points at. /RL */ + len -= e - from; + from = e; + + /* In case there were no braces or parenthesis around + the variable reference, we have to put back the + character that was replaced with a '\0'. /RL */ + *rp = r; + } else { + buf->data[to++] = *(from++); + } + } + + buf->data[to] = '\0'; + if (*pto != NULL) { + OPENSSL_free(*pto); + } + *pto = buf->data; + OPENSSL_free(buf); + return 1; + +err: + if (buf != NULL) { + BUF_MEM_free(buf); + } + return 0; +} + +static CONF_VALUE *get_section(const CONF *conf, const char *section) { + CONF_VALUE template; + + memset(&template, 0, sizeof(template)); + template.section = (char *) section; + return lh_CONF_VALUE_retrieve(conf->data, &template); +} + +STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf, const char *section) { + CONF_VALUE *section_value = get_section(conf, section); + if (section_value == NULL) { + return NULL; + } + return (STACK_OF(CONF_VALUE)*) section_value->value; +} + +const char *NCONF_get_string(const CONF *conf, const char *section, + const char *name) { + CONF_VALUE template, *value; + + memset(&template, 0, sizeof(template)); + template.section = (char *) section; + template.name = (char *) name; + value = lh_CONF_VALUE_retrieve(conf->data, &template); + if (value == NULL) { + return NULL; + } + return value->value; +} + +int add_string(const CONF *conf, CONF_VALUE *section, CONF_VALUE *value) { + STACK_OF(CONF_VALUE) *section_stack = (STACK_OF(CONF_VALUE)*) section->value; + CONF_VALUE *old_value; + + value->section = section->section; + if (!sk_CONF_VALUE_push(section_stack, value)) { + return 0; + } + + if (!lh_CONF_VALUE_insert(conf->data, &old_value, value)) { + return 0; + } + if (old_value != NULL) { + (void)sk_CONF_VALUE_delete_ptr(section_stack, old_value); + value_free(old_value); + } + + return 1; +} + +static char *eat_ws(CONF *conf, char *p) { + while (IS_WS(conf, *p) && !IS_EOF(conf, *p)) { + p++; + } + return p; +} + +#define scan_esc(conf, p) (((IS_EOF((conf), (p)[1])) ? ((p) + 1) : ((p) + 2))) + +static char *eat_alpha_numeric(CONF *conf, char *p) { + for (;;) { + if (IS_ESC(conf, *p)) { + p = scan_esc(conf, p); + continue; + } + if (!IS_ALPHA_NUMERIC_PUNCT(conf, *p)) { + return p; + } + p++; + } +} + +static char *scan_quote(CONF *conf, char *p) { + int q = *p; + + p++; + while (!IS_EOF(conf, *p) && *p != q) { + if (IS_ESC(conf, *p)) { + p++; + if (IS_EOF(conf, *p)) { + return p; + } + } + p++; + } + if (*p == q) { + p++; + } + return p; +} + + +static char *scan_dquote(CONF *conf, char *p) { + int q = *p; + + p++; + while (!(IS_EOF(conf, *p))) { + if (*p == q) { + if (*(p + 1) == q) { + p++; + } else { + break; + } + } + p++; + } + if (*p == q) { + p++; + } + return p; +} + +static void clear_comments(CONF *conf, char *p) { + for (;;) { + if (IS_FCOMMENT(conf, *p)) { + *p = '\0'; + return; + } + if (!IS_WS(conf, *p)) { + break; + } + p++; + } + + for (;;) { + if (IS_COMMENT(conf, *p)) { + *p = '\0'; + return; + } + if (IS_DQUOTE(conf, *p)) { + p = scan_dquote(conf, p); + continue; + } + if (IS_QUOTE(conf, *p)) { + p = scan_quote(conf, p); + continue; + } + if (IS_ESC(conf, *p)) { + p = scan_esc(conf, p); + continue; + } + if (IS_EOF(conf, *p)) { + return; + } else { + p++; + } + } +} + +static int def_load_bio(CONF *conf, BIO *in, long *out_error_line) { + static const size_t CONFBUFSIZE = 512; + int bufnum = 0, i, ii; + BUF_MEM *buff = NULL; + char *s, *p, *end; + int again; + long eline = 0; + char btmp[DECIMAL_SIZE(eline) + 1]; + CONF_VALUE *v = NULL, *tv; + CONF_VALUE *sv = NULL; + char *section = NULL, *buf; + char *start, *psection, *pname; + + if ((buff = BUF_MEM_new()) == NULL) { + OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB); + goto err; + } + + section = (char *)OPENSSL_malloc(10); + if (section == NULL) { + OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE); + goto err; + } + BUF_strlcpy(section, "default", 10); + + sv = NCONF_new_section(conf, section); + if (sv == NULL) { + OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); + goto err; + } + + bufnum = 0; + again = 0; + for (;;) { + if (!BUF_MEM_grow(buff, bufnum + CONFBUFSIZE)) { + OPENSSL_PUT_ERROR(CONF, ERR_R_BUF_LIB); + goto err; + } + p = &(buff->data[bufnum]); + *p = '\0'; + BIO_gets(in, p, CONFBUFSIZE - 1); + p[CONFBUFSIZE - 1] = '\0'; + ii = i = strlen(p); + if (i == 0 && !again) { + break; + } + again = 0; + while (i > 0) { + if ((p[i - 1] != '\r') && (p[i - 1] != '\n')) { + break; + } else { + i--; + } + } + /* we removed some trailing stuff so there is a new + * line on the end. */ + if (ii && i == ii) { + again = 1; /* long line */ + } else { + p[i] = '\0'; + eline++; /* another input line */ + } + + /* we now have a line with trailing \r\n removed */ + + /* i is the number of bytes */ + bufnum += i; + + v = NULL; + /* check for line continuation */ + if (bufnum >= 1) { + /* If we have bytes and the last char '\\' and + * second last char is not '\\' */ + p = &(buff->data[bufnum - 1]); + if (IS_ESC(conf, p[0]) && ((bufnum <= 1) || !IS_ESC(conf, p[-1]))) { + bufnum--; + again = 1; + } + } + if (again) { + continue; + } + bufnum = 0; + buf = buff->data; + + clear_comments(conf, buf); + s = eat_ws(conf, buf); + if (IS_EOF(conf, *s)) { + continue; /* blank line */ + } + if (*s == '[') { + char *ss; + + s++; + start = eat_ws(conf, s); + ss = start; + again: + end = eat_alpha_numeric(conf, ss); + p = eat_ws(conf, end); + if (*p != ']') { + if (*p != '\0' && ss != p) { + ss = p; + goto again; + } + OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_CLOSE_SQUARE_BRACKET); + goto err; + } + *end = '\0'; + if (!str_copy(conf, NULL, §ion, start)) { + goto err; + } + if ((sv = get_section(conf, section)) == NULL) { + sv = NCONF_new_section(conf, section); + } + if (sv == NULL) { + OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); + goto err; + } + continue; + } else { + pname = s; + psection = NULL; + end = eat_alpha_numeric(conf, s); + if ((end[0] == ':') && (end[1] == ':')) { + *end = '\0'; + end += 2; + psection = pname; + pname = end; + end = eat_alpha_numeric(conf, end); + } + p = eat_ws(conf, end); + if (*p != '=') { + OPENSSL_PUT_ERROR(CONF, CONF_R_MISSING_EQUAL_SIGN); + goto err; + } + *end = '\0'; + p++; + start = eat_ws(conf, p); + while (!IS_EOF(conf, *p)) { + p++; + } + p--; + while ((p != start) && (IS_WS(conf, *p))) { + p--; + } + p++; + *p = '\0'; + + if (!(v = (CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE)))) { + OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE); + goto err; + } + if (psection == NULL) { + psection = section; + } + v->name = (char *)OPENSSL_malloc(strlen(pname) + 1); + v->value = NULL; + if (v->name == NULL) { + OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE); + goto err; + } + BUF_strlcpy(v->name, pname, strlen(pname) + 1); + if (!str_copy(conf, psection, &(v->value), start)) { + goto err; + } + + if (strcmp(psection, section) != 0) { + if ((tv = get_section(conf, psection)) == NULL) { + tv = NCONF_new_section(conf, psection); + } + if (tv == NULL) { + OPENSSL_PUT_ERROR(CONF, CONF_R_UNABLE_TO_CREATE_NEW_SECTION); + goto err; + } + } else { + tv = sv; + } + if (add_string(conf, tv, v) == 0) { + OPENSSL_PUT_ERROR(CONF, ERR_R_MALLOC_FAILURE); + goto err; + } + v = NULL; + } + } + if (buff != NULL) { + BUF_MEM_free(buff); + } + if (section != NULL) { + OPENSSL_free(section); + } + return 1; + +err: + if (buff != NULL) { + BUF_MEM_free(buff); + } + if (section != NULL) { + OPENSSL_free(section); + } + if (out_error_line != NULL) { + *out_error_line = eline; + } + BIO_snprintf(btmp, sizeof btmp, "%ld", eline); + ERR_add_error_data(2, "line ", btmp); + + if (v != NULL) { + if (v->name != NULL) { + OPENSSL_free(v->name); + } + if (v->value != NULL) { + OPENSSL_free(v->value); + } + if (v != NULL) { + OPENSSL_free(v); + } + } + return 0; +} + +int NCONF_load(CONF *conf, const char *filename, long *out_error_line) { + BIO *in = BIO_new_file(filename, "rb"); + int ret; + + if (in == NULL) { + OPENSSL_PUT_ERROR(CONF, ERR_R_SYS_LIB); + return 0; + } + + ret = def_load_bio(conf, in, out_error_line); + BIO_free(in); + + return ret; +} + +int NCONF_load_bio(CONF *conf, BIO *bio, long *out_error_line) { + return def_load_bio(conf, bio, out_error_line); +} + +int CONF_parse_list(const char *list, char sep, int remove_whitespace, + int (*list_cb)(const char *elem, int len, void *usr), + void *arg) { + int ret; + const char *lstart, *tmpend, *p; + + if (list == NULL) { + OPENSSL_PUT_ERROR(CONF, CONF_R_LIST_CANNOT_BE_NULL); + return 0; + } + + lstart = list; + for (;;) { + if (remove_whitespace) { + while (*lstart && isspace((unsigned char)*lstart)) { + lstart++; + } + } + p = strchr(lstart, sep); + if (p == lstart || !*lstart) { + ret = list_cb(NULL, 0, arg); + } else { + if (p) { + tmpend = p - 1; + } else { + tmpend = lstart + strlen(lstart) - 1; + } + if (remove_whitespace) { + while (isspace((unsigned char)*tmpend)) { + tmpend--; + } + } + ret = list_cb(lstart, tmpend - lstart + 1, arg); + } + if (ret <= 0) { + return ret; + } + if (p == NULL) { + return 1; + } + lstart = p + 1; + } +} diff --git a/TMessagesProj/jni/boringssl/crypto/conf/conf_def.h b/TMessagesProj/jni/boringssl/crypto/conf/conf_def.h new file mode 100644 index 00000000..b1e6ba63 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/conf/conf_def.h @@ -0,0 +1,127 @@ +/* crypto/conf/conf_def.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +/* THIS FILE WAS AUTOMAGICALLY GENERATED! + Please modify and use keysets.pl to regenerate it. */ + +#define CONF_NUMBER 1 +#define CONF_UPPER 2 +#define CONF_LOWER 4 +#define CONF_UNDER 256 +#define CONF_PUNCTUATION 512 +#define CONF_WS 16 +#define CONF_ESC 32 +#define CONF_QUOTE 64 +#define CONF_DQUOTE 1024 +#define CONF_COMMENT 128 +#define CONF_FCOMMENT 2048 +#define CONF_EOF 8 +#define CONF_HIGHBIT 4096 +#define CONF_ALPHA (CONF_UPPER|CONF_LOWER) +#define CONF_ALPHA_NUMERIC (CONF_ALPHA|CONF_NUMBER|CONF_UNDER) +#define CONF_ALPHA_NUMERIC_PUNCT (CONF_ALPHA|CONF_NUMBER|CONF_UNDER| \ + CONF_PUNCTUATION) + +#define KEYTYPES(c) CONF_type_default +#define IS_COMMENT(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_COMMENT) +#define IS_FCOMMENT(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_FCOMMENT) +#define IS_EOF(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_EOF) +#define IS_ESC(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_ESC) +#define IS_NUMBER(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_NUMBER) +#define IS_WS(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_WS) +#define IS_ALPHA_NUMERIC(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_ALPHA_NUMERIC) +#define IS_ALPHA_NUMERIC_PUNCT(c,a) \ + (KEYTYPES(c)[(a)&0xff]&CONF_ALPHA_NUMERIC_PUNCT) +#define IS_QUOTE(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_QUOTE) +#define IS_DQUOTE(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_DQUOTE) +#define IS_HIGHBIT(c,a) (KEYTYPES(c)[(a)&0xff]&CONF_HIGHBIT) + +static const unsigned short CONF_type_default[256]={ + 0x0008,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0010,0x0010,0x0000,0x0000,0x0010,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000, + 0x0010,0x0200,0x0040,0x0080,0x0000,0x0200,0x0200,0x0040, + 0x0000,0x0000,0x0200,0x0200,0x0200,0x0200,0x0200,0x0200, + 0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001,0x0001, + 0x0001,0x0001,0x0000,0x0200,0x0000,0x0000,0x0000,0x0200, + 0x0200,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002, + 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002, + 0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002,0x0002, + 0x0002,0x0002,0x0002,0x0000,0x0020,0x0000,0x0200,0x0100, + 0x0040,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004, + 0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004, + 0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004,0x0004, + 0x0004,0x0004,0x0004,0x0000,0x0200,0x0000,0x0200,0x0000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + 0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000,0x1000, + }; diff --git a/TMessagesProj/jni/boringssl/crypto/cpu-arm-asm.S b/TMessagesProj/jni/boringssl/crypto/cpu-arm-asm.S new file mode 100644 index 00000000..faf3ad89 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cpu-arm-asm.S @@ -0,0 +1,32 @@ +# Copyright (c) 2014, Google Inc. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#if !defined(OPENSSL_NO_ASM) && defined(__arm__) + +.syntax unified +.cpu cortex-a8 +.fpu neon +.text +.thumb +.align 2 +.global CRYPTO_arm_neon_probe +.hidden CRYPTO_arm_neon_probe +.type CRYPTO_arm_neon_probe, %function +.thumb_func +CRYPTO_arm_neon_probe: + vorr q1, q1, q1 + bx lr +.section .note.GNU-stack,"",%progbits + +#endif /* !OPENSSL_NO_ASM && __arm__ */ diff --git a/TMessagesProj/jni/boringssl/crypto/cpu-arm.c b/TMessagesProj/jni/boringssl/crypto/cpu-arm.c new file mode 100644 index 00000000..31b7de08 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cpu-arm.c @@ -0,0 +1,189 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) + +#include +#include + +#if !defined(OPENSSL_TRUSTY) +#include +#include +#endif + +#include "arm_arch.h" + + +/* We can't include because the Android SDK version against which + * Chromium builds is too old to have it. Instead we define all the constants + * that we need and have a weak pointer to getauxval. */ + +unsigned long getauxval(unsigned long type) __attribute__((weak)); + +char CRYPTO_is_NEON_capable(void) { + return (OPENSSL_armcap_P & ARMV7_NEON) != 0; +} + +static char g_set_neon_called = 0; + +void CRYPTO_set_NEON_capable(char neon_capable) { + g_set_neon_called = 1; + + if (neon_capable) { + OPENSSL_armcap_P |= ARMV7_NEON; + } else { + OPENSSL_armcap_P &= ~ARMV7_NEON; + } +} + +char CRYPTO_is_NEON_functional(void) { + static const uint32_t kWantFlags = ARMV7_NEON | ARMV7_NEON_FUNCTIONAL; + return (OPENSSL_armcap_P & kWantFlags) == kWantFlags; +} + +void CRYPTO_set_NEON_functional(char neon_functional) { + if (neon_functional) { + OPENSSL_armcap_P |= ARMV7_NEON_FUNCTIONAL; + } else { + OPENSSL_armcap_P &= ~ARMV7_NEON_FUNCTIONAL; + } +} + +#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_ARM) && !defined(OPENSSL_TRUSTY) + +static sigjmp_buf sigill_jmp; + +static void sigill_handler(int signal) { + siglongjmp(sigill_jmp, signal); +} + +void CRYPTO_arm_neon_probe(void); + +// probe_for_NEON returns 1 if a NEON instruction runs successfully. Because +// getauxval doesn't exist on Android until Jelly Bean, supporting NEON on +// older devices requires this. +static int probe_for_NEON(void) { + int supported = 0; + + sigset_t sigmask; + sigfillset(&sigmask); + sigdelset(&sigmask, SIGILL); + sigdelset(&sigmask, SIGTRAP); + sigdelset(&sigmask, SIGFPE); + sigdelset(&sigmask, SIGBUS); + sigdelset(&sigmask, SIGSEGV); + + struct sigaction sigill_original_action, sigill_action; + memset(&sigill_action, 0, sizeof(sigill_action)); + sigill_action.sa_handler = sigill_handler; + sigill_action.sa_mask = sigmask; + + sigset_t original_sigmask; + sigprocmask(SIG_SETMASK, &sigmask, &original_sigmask); + + if (sigsetjmp(sigill_jmp, 1 /* save signals */) == 0) { + sigaction(SIGILL, &sigill_action, &sigill_original_action); + + // This function cannot be inline asm because GCC will refuse to compile + // inline NEON instructions unless building with -mfpu=neon, which would + // defeat the point of probing for support at runtime. + CRYPTO_arm_neon_probe(); + supported = 1; + } + // Note that Android up to and including Lollipop doesn't restore the signal + // mask correctly after returning from a sigsetjmp. So that would need to be + // set again here if more probes were added. + // See https://android-review.googlesource.com/#/c/127624/ + + sigaction(SIGILL, &sigill_original_action, NULL); + sigprocmask(SIG_SETMASK, &original_sigmask, NULL); + + return supported; +} + +#else + +static int probe_for_NEON(void) { + return 0; +} + +#endif /* !OPENSSL_NO_ASM && OPENSSL_ARM && !OPENSSL_TRUSTY */ + +void OPENSSL_cpuid_setup(void) { + if (getauxval == NULL) { + // On ARM, but not AArch64, try a NEON instruction and see whether it works + // in order to probe for NEON support. + // + // Note that |CRYPTO_is_NEON_capable| can be true even if + // |CRYPTO_set_NEON_capable| has never been called if the code was compiled + // with NEON support enabled (e.g. -mfpu=neon). + if (!g_set_neon_called && !CRYPTO_is_NEON_capable() && probe_for_NEON()) { + OPENSSL_armcap_P |= ARMV7_NEON; + } + return; + } + + static const unsigned long AT_HWCAP = 16; + unsigned long hwcap = getauxval(AT_HWCAP); + +#if defined(OPENSSL_ARM) + static const unsigned long kNEON = 1 << 12; + if ((hwcap & kNEON) == 0) { + return; + } + + /* In 32-bit mode, the ARMv8 feature bits are in a different aux vector + * value. */ + static const unsigned long AT_HWCAP2 = 26; + hwcap = getauxval(AT_HWCAP2); + + /* See /usr/include/asm/hwcap.h on an ARM installation for the source of + * these values. */ + static const unsigned long kAES = 1 << 0; + static const unsigned long kPMULL = 1 << 1; + static const unsigned long kSHA1 = 1 << 2; + static const unsigned long kSHA256 = 1 << 3; +#elif defined(OPENSSL_AARCH64) + /* See /usr/include/asm/hwcap.h on an aarch64 installation for the source of + * these values. */ + static const unsigned long kNEON = 1 << 1; + static const unsigned long kAES = 1 << 3; + static const unsigned long kPMULL = 1 << 4; + static const unsigned long kSHA1 = 1 << 5; + static const unsigned long kSHA256 = 1 << 6; + + if ((hwcap & kNEON) == 0) { + return; + } +#endif + + OPENSSL_armcap_P |= ARMV7_NEON; + + if (hwcap & kAES) { + OPENSSL_armcap_P |= ARMV8_AES; + } + if (hwcap & kPMULL) { + OPENSSL_armcap_P |= ARMV8_PMULL; + } + if (hwcap & kSHA1) { + OPENSSL_armcap_P |= ARMV8_SHA1; + } + if (hwcap & kSHA256) { + OPENSSL_armcap_P |= ARMV8_SHA256; + } +} + +#endif /* defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) */ diff --git a/TMessagesProj/jni/boringssl/crypto/cpu-intel.c b/TMessagesProj/jni/boringssl/crypto/cpu-intel.c new file mode 100644 index 00000000..924bab04 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/cpu-intel.c @@ -0,0 +1,261 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#if !defined(__STDC_FORMAT_MACROS) +#define __STDC_FORMAT_MACROS +#endif + +#include + + +#if !defined(OPENSSL_NO_ASM) && (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) + +#include +#include +#include +#include + +#if defined(OPENSSL_WINDOWS) +#pragma warning(push, 3) +#include +#include +#pragma warning(pop) +#endif + + +/* OPENSSL_cpuid runs the cpuid instruction. |leaf| is passed in as EAX and ECX + * is set to zero. It writes EAX, EBX, ECX, and EDX to |*out_eax| through + * |*out_edx|. */ +static void OPENSSL_cpuid(uint32_t *out_eax, uint32_t *out_ebx, + uint32_t *out_ecx, uint32_t *out_edx, uint32_t leaf) { +#if defined(OPENSSL_WINDOWS) + int tmp[4]; + __cpuid(tmp, (int)leaf); + *out_eax = (uint32_t)tmp[0]; + *out_ebx = (uint32_t)tmp[1]; + *out_ecx = (uint32_t)tmp[2]; + *out_edx = (uint32_t)tmp[3]; +#elif defined(__pic__) && defined(OPENSSL_32_BIT) + /* Inline assembly may not clobber the PIC register. For 32-bit, this is EBX. + * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=47602. */ + __asm__ volatile ( + "xor %%ecx, %%ecx\n" + "mov %%ebx, %%edi\n" + "cpuid\n" + "xchg %%edi, %%ebx\n" + : "=a"(*out_eax), "=D"(*out_ebx), "=c"(*out_ecx), "=d"(*out_edx) + : "a"(leaf) + ); +#else + __asm__ volatile ( + "xor %%ecx, %%ecx\n" + "cpuid\n" + : "=a"(*out_eax), "=b"(*out_ebx), "=c"(*out_ecx), "=d"(*out_edx) + : "a"(leaf) + ); +#endif +} + +/* OPENSSL_xgetbv returns the value of an Intel Extended Control Register (XCR). + * Currently only XCR0 is defined by Intel so |xcr| should always be zero. */ +static uint64_t OPENSSL_xgetbv(uint32_t xcr) { +#if defined(OPENSSL_WINDOWS) + return (uint64_t)_xgetbv(xcr); +#else + uint32_t eax, edx; + __asm__ volatile ("xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr)); + return (((uint64_t)edx) << 32) | eax; +#endif +} + +/* handle_cpu_env applies the value from |in| to the CPUID values in |out[0]| + * and |out[1]|. See the comment in |OPENSSL_cpuid_setup| about this. */ +static void handle_cpu_env(uint32_t *out, const char *in) { + const int invert = in[0] == '~'; + uint64_t v; + + if (!sscanf(in + invert, "%" PRIi64, &v)) { + return; + } + + if (invert) { + out[0] &= ~v; + out[1] &= ~(v >> 32); + } else { + out[0] = v; + out[1] = v >> 32; + } +} + +void OPENSSL_cpuid_setup(void) { + /* Determine the vendor and maximum input value. */ + uint32_t eax, ebx, ecx, edx; + OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 0); + + uint32_t num_ids = eax; + + int is_intel = ebx == 0x756e6547 /* Genu */ && + edx == 0x49656e69 /* ineI */ && + ecx == 0x6c65746e /* ntel */; + int is_amd = ebx == 0x68747541 /* Auth */ && + edx == 0x69746e65 /* enti */ && + ecx == 0x444d4163 /* cAMD */; + + int has_amd_xop = 0; + if (is_amd) { + /* AMD-specific logic. + * See http://developer.amd.com/wordpress/media/2012/10/254811.pdf */ + OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 0x80000000); + uint32_t num_extended_ids = eax; + if (num_extended_ids >= 0x80000001) { + OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 0x80000001); + if (ecx & (1 << 11)) { + has_amd_xop = 1; + } + } + } + + uint32_t extended_features = 0; + if (num_ids >= 7) { + OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 7); + extended_features = ebx; + } + + /* Determine the number of cores sharing an L1 data cache to adjust the + * hyper-threading bit. */ + uint32_t cores_per_cache = 0; + if (is_amd) { + /* AMD CPUs never share an L1 data cache between threads but do set the HTT + * bit on multi-core CPUs. */ + cores_per_cache = 1; + } else if (num_ids >= 4) { + /* TODO(davidben): The Intel manual says this CPUID leaf enumerates all + * caches using ECX and doesn't say which is first. Does this matter? */ + OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 4); + cores_per_cache = 1 + ((eax >> 14) & 0xfff); + } + + OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 1); + + /* Adjust the hyper-threading bit. */ + if (edx & (1 << 28)) { + uint32_t num_logical_cores = (ebx >> 16) & 0xff; + if (cores_per_cache == 1 || num_logical_cores <= 1) { + edx &= ~(1 << 28); + } + } + + /* Reserved bit #20 was historically repurposed to control the in-memory + * representation of RC4 state. Always set it to zero. */ + edx &= ~(1 << 20); + + /* Reserved bit #30 is repurposed to signal an Intel CPU. */ + if (is_intel) { + edx |= (1 << 30); + } else { + edx &= ~(1 << 30); + } + + /* The SDBG bit is repurposed to denote AMD XOP support. */ + if (has_amd_xop) { + ecx |= (1 << 11); + } else { + ecx &= ~(1 << 11); + } + + uint64_t xcr0 = 0; + if (ecx & (1 << 27)) { + /* XCR0 may only be queried if the OSXSAVE bit is set. */ + xcr0 = OPENSSL_xgetbv(0); + } + /* See Intel manual, section 14.3. */ + if ((xcr0 & 6) != 6) { + /* YMM registers cannot be used. */ + ecx &= ~(1 << 28); /* AVX */ + ecx &= ~(1 << 12); /* FMA */ + ecx &= ~(1 << 11); /* AMD XOP */ + extended_features &= ~(1 << 5); /* AVX2 */ + } + + OPENSSL_ia32cap_P[0] = edx; + OPENSSL_ia32cap_P[1] = ecx; + OPENSSL_ia32cap_P[2] = extended_features; + OPENSSL_ia32cap_P[3] = 0; + + const char *env1, *env2; + env1 = getenv("OPENSSL_ia32cap"); + if (env1 == NULL) { + return; + } + + /* OPENSSL_ia32cap can contain zero, one or two values, separated with a ':'. + * Each value is a 64-bit, unsigned value which may start with "0x" to + * indicate a hex value. Prior to the 64-bit value, a '~' may be given. + * + * If '~' isn't present, then the value is taken as the result of the CPUID. + * Otherwise the value is inverted and ANDed with the probed CPUID result. + * + * The first value determines OPENSSL_ia32cap_P[0] and [1]. The second [2] + * and [3]. */ + + handle_cpu_env(&OPENSSL_ia32cap_P[0], env1); + env2 = strchr(env1, ':'); + if (env2 != NULL) { + handle_cpu_env(&OPENSSL_ia32cap_P[2], env2 + 1); + } +} + +#endif /* !OPENSSL_NO_ASM && (OPENSSL_X86 || OPENSSL_X86_64) */ diff --git a/TMessagesProj/jni/boringssl/crypto/crypto.c b/TMessagesProj/jni/boringssl/crypto/crypto.c new file mode 100644 index 00000000..d9bb07e9 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/crypto.c @@ -0,0 +1,112 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include "internal.h" + + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) +/* x86, x86_64 and the ARMs need to record the result of a cpuid call for the + * asm to work correctly, unless compiled without asm code. */ +#define NEED_CPUID + +#else + +/* Otherwise, don't emit a static initialiser. */ + +#if !defined(BORINGSSL_NO_STATIC_INITIALIZER) +#define BORINGSSL_NO_STATIC_INITIALIZER +#endif + +#endif /* !OPENSSL_NO_ASM && (OPENSSL_X86 || OPENSSL_X86_64 || + OPENSSL_ARM || OPENSSL_AARCH64) */ + + +/* The capability variables are defined in this file in order to work around a + * linker bug. When linking with a .a, if no symbols in a .o are referenced + * then the .o is discarded, even if it has constructor functions. + * + * This still means that any binaries that don't include some functionality + * that tests the capability values will still skip the constructor but, so + * far, the init constructor function only sets the capability variables. */ + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +/* This value must be explicitly initialised to zero in order to work around a + * bug in libtool or the linker on OS X. + * + * If not initialised then it becomes a "common symbol". When put into an + * archive, linking on OS X will fail to resolve common symbols. By + * initialising it to zero, it becomes a "data symbol", which isn't so + * affected. */ +uint32_t OPENSSL_ia32cap_P[4] = {0}; +#elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) + +#include "arm_arch.h" + +#if defined(__ARM_NEON__) +uint32_t OPENSSL_armcap_P = ARMV7_NEON | ARMV7_NEON_FUNCTIONAL; +#else +uint32_t OPENSSL_armcap_P = ARMV7_NEON_FUNCTIONAL; +#endif + +#endif + + +#if defined(OPENSSL_WINDOWS) +#define OPENSSL_CDECL __cdecl +#else +#define OPENSSL_CDECL +#endif + +#if !defined(BORINGSSL_NO_STATIC_INITIALIZER) +#if !defined(OPENSSL_WINDOWS) +static void do_library_init(void) __attribute__ ((constructor)); +#else +#pragma section(".CRT$XCU", read) +static void __cdecl do_library_init(void); +__declspec(allocate(".CRT$XCU")) void(*library_init_constructor)(void) = + do_library_init; +#endif +#endif /* !BORINGSSL_NO_STATIC_INITIALIZER */ + +/* do_library_init is the actual initialization function. If + * BORINGSSL_NO_STATIC_INITIALIZER isn't defined, this is set as a static + * initializer. Otherwise, it is called by CRYPTO_library_init. */ +static void OPENSSL_CDECL do_library_init(void) { + /* WARNING: this function may only configure the capability variables. See the + * note above about the linker bug. */ +#if defined(NEED_CPUID) + OPENSSL_cpuid_setup(); +#endif +} + +void CRYPTO_library_init(void) { + /* TODO(davidben): It would be tidier if this build knob could be replaced + * with an internal lazy-init mechanism that would handle things correctly + * in-library. */ +#if defined(BORINGSSL_NO_STATIC_INITIALIZER) + do_library_init(); +#endif +} + +const char *SSLeay_version(int unused) { + return "BoringSSL"; +} + +unsigned long SSLeay(void) { + return OPENSSL_VERSION_NUMBER; +} diff --git a/TMessagesProj/jni/boringssl/crypto/des/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/des/CMakeLists.txt new file mode 100644 index 00000000..7d49ff3c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/des/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + des + + OBJECT + + des.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/des/des.c b/TMessagesProj/jni/boringssl/crypto/des/des.c new file mode 100644 index 00000000..a5669a62 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/des/des.c @@ -0,0 +1,773 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include "internal.h" + + +static const uint32_t des_skb[8][64] = { + {/* for C bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ + 0x00000000L, 0x00000010L, 0x20000000L, 0x20000010L, 0x00010000L, + 0x00010010L, 0x20010000L, 0x20010010L, 0x00000800L, 0x00000810L, + 0x20000800L, 0x20000810L, 0x00010800L, 0x00010810L, 0x20010800L, + 0x20010810L, 0x00000020L, 0x00000030L, 0x20000020L, 0x20000030L, + 0x00010020L, 0x00010030L, 0x20010020L, 0x20010030L, 0x00000820L, + 0x00000830L, 0x20000820L, 0x20000830L, 0x00010820L, 0x00010830L, + 0x20010820L, 0x20010830L, 0x00080000L, 0x00080010L, 0x20080000L, + 0x20080010L, 0x00090000L, 0x00090010L, 0x20090000L, 0x20090010L, + 0x00080800L, 0x00080810L, 0x20080800L, 0x20080810L, 0x00090800L, + 0x00090810L, 0x20090800L, 0x20090810L, 0x00080020L, 0x00080030L, + 0x20080020L, 0x20080030L, 0x00090020L, 0x00090030L, 0x20090020L, + 0x20090030L, 0x00080820L, 0x00080830L, 0x20080820L, 0x20080830L, + 0x00090820L, 0x00090830L, 0x20090820L, 0x20090830L, }, + {/* for C bits (numbered as per FIPS 46) 7 8 10 11 12 13 */ + 0x00000000L, 0x02000000L, 0x00002000L, 0x02002000L, 0x00200000L, + 0x02200000L, 0x00202000L, 0x02202000L, 0x00000004L, 0x02000004L, + 0x00002004L, 0x02002004L, 0x00200004L, 0x02200004L, 0x00202004L, + 0x02202004L, 0x00000400L, 0x02000400L, 0x00002400L, 0x02002400L, + 0x00200400L, 0x02200400L, 0x00202400L, 0x02202400L, 0x00000404L, + 0x02000404L, 0x00002404L, 0x02002404L, 0x00200404L, 0x02200404L, + 0x00202404L, 0x02202404L, 0x10000000L, 0x12000000L, 0x10002000L, + 0x12002000L, 0x10200000L, 0x12200000L, 0x10202000L, 0x12202000L, + 0x10000004L, 0x12000004L, 0x10002004L, 0x12002004L, 0x10200004L, + 0x12200004L, 0x10202004L, 0x12202004L, 0x10000400L, 0x12000400L, + 0x10002400L, 0x12002400L, 0x10200400L, 0x12200400L, 0x10202400L, + 0x12202400L, 0x10000404L, 0x12000404L, 0x10002404L, 0x12002404L, + 0x10200404L, 0x12200404L, 0x10202404L, 0x12202404L, }, + {/* for C bits (numbered as per FIPS 46) 14 15 16 17 19 20 */ + 0x00000000L, 0x00000001L, 0x00040000L, 0x00040001L, 0x01000000L, + 0x01000001L, 0x01040000L, 0x01040001L, 0x00000002L, 0x00000003L, + 0x00040002L, 0x00040003L, 0x01000002L, 0x01000003L, 0x01040002L, + 0x01040003L, 0x00000200L, 0x00000201L, 0x00040200L, 0x00040201L, + 0x01000200L, 0x01000201L, 0x01040200L, 0x01040201L, 0x00000202L, + 0x00000203L, 0x00040202L, 0x00040203L, 0x01000202L, 0x01000203L, + 0x01040202L, 0x01040203L, 0x08000000L, 0x08000001L, 0x08040000L, + 0x08040001L, 0x09000000L, 0x09000001L, 0x09040000L, 0x09040001L, + 0x08000002L, 0x08000003L, 0x08040002L, 0x08040003L, 0x09000002L, + 0x09000003L, 0x09040002L, 0x09040003L, 0x08000200L, 0x08000201L, + 0x08040200L, 0x08040201L, 0x09000200L, 0x09000201L, 0x09040200L, + 0x09040201L, 0x08000202L, 0x08000203L, 0x08040202L, 0x08040203L, + 0x09000202L, 0x09000203L, 0x09040202L, 0x09040203L, }, + {/* for C bits (numbered as per FIPS 46) 21 23 24 26 27 28 */ + 0x00000000L, 0x00100000L, 0x00000100L, 0x00100100L, 0x00000008L, + 0x00100008L, 0x00000108L, 0x00100108L, 0x00001000L, 0x00101000L, + 0x00001100L, 0x00101100L, 0x00001008L, 0x00101008L, 0x00001108L, + 0x00101108L, 0x04000000L, 0x04100000L, 0x04000100L, 0x04100100L, + 0x04000008L, 0x04100008L, 0x04000108L, 0x04100108L, 0x04001000L, + 0x04101000L, 0x04001100L, 0x04101100L, 0x04001008L, 0x04101008L, + 0x04001108L, 0x04101108L, 0x00020000L, 0x00120000L, 0x00020100L, + 0x00120100L, 0x00020008L, 0x00120008L, 0x00020108L, 0x00120108L, + 0x00021000L, 0x00121000L, 0x00021100L, 0x00121100L, 0x00021008L, + 0x00121008L, 0x00021108L, 0x00121108L, 0x04020000L, 0x04120000L, + 0x04020100L, 0x04120100L, 0x04020008L, 0x04120008L, 0x04020108L, + 0x04120108L, 0x04021000L, 0x04121000L, 0x04021100L, 0x04121100L, + 0x04021008L, 0x04121008L, 0x04021108L, 0x04121108L, }, + {/* for D bits (numbered as per FIPS 46) 1 2 3 4 5 6 */ + 0x00000000L, 0x10000000L, 0x00010000L, 0x10010000L, 0x00000004L, + 0x10000004L, 0x00010004L, 0x10010004L, 0x20000000L, 0x30000000L, + 0x20010000L, 0x30010000L, 0x20000004L, 0x30000004L, 0x20010004L, + 0x30010004L, 0x00100000L, 0x10100000L, 0x00110000L, 0x10110000L, + 0x00100004L, 0x10100004L, 0x00110004L, 0x10110004L, 0x20100000L, + 0x30100000L, 0x20110000L, 0x30110000L, 0x20100004L, 0x30100004L, + 0x20110004L, 0x30110004L, 0x00001000L, 0x10001000L, 0x00011000L, + 0x10011000L, 0x00001004L, 0x10001004L, 0x00011004L, 0x10011004L, + 0x20001000L, 0x30001000L, 0x20011000L, 0x30011000L, 0x20001004L, + 0x30001004L, 0x20011004L, 0x30011004L, 0x00101000L, 0x10101000L, + 0x00111000L, 0x10111000L, 0x00101004L, 0x10101004L, 0x00111004L, + 0x10111004L, 0x20101000L, 0x30101000L, 0x20111000L, 0x30111000L, + 0x20101004L, 0x30101004L, 0x20111004L, 0x30111004L, }, + {/* for D bits (numbered as per FIPS 46) 8 9 11 12 13 14 */ + 0x00000000L, 0x08000000L, 0x00000008L, 0x08000008L, 0x00000400L, + 0x08000400L, 0x00000408L, 0x08000408L, 0x00020000L, 0x08020000L, + 0x00020008L, 0x08020008L, 0x00020400L, 0x08020400L, 0x00020408L, + 0x08020408L, 0x00000001L, 0x08000001L, 0x00000009L, 0x08000009L, + 0x00000401L, 0x08000401L, 0x00000409L, 0x08000409L, 0x00020001L, + 0x08020001L, 0x00020009L, 0x08020009L, 0x00020401L, 0x08020401L, + 0x00020409L, 0x08020409L, 0x02000000L, 0x0A000000L, 0x02000008L, + 0x0A000008L, 0x02000400L, 0x0A000400L, 0x02000408L, 0x0A000408L, + 0x02020000L, 0x0A020000L, 0x02020008L, 0x0A020008L, 0x02020400L, + 0x0A020400L, 0x02020408L, 0x0A020408L, 0x02000001L, 0x0A000001L, + 0x02000009L, 0x0A000009L, 0x02000401L, 0x0A000401L, 0x02000409L, + 0x0A000409L, 0x02020001L, 0x0A020001L, 0x02020009L, 0x0A020009L, + 0x02020401L, 0x0A020401L, 0x02020409L, 0x0A020409L, }, + {/* for D bits (numbered as per FIPS 46) 16 17 18 19 20 21 */ + 0x00000000L, 0x00000100L, 0x00080000L, 0x00080100L, 0x01000000L, + 0x01000100L, 0x01080000L, 0x01080100L, 0x00000010L, 0x00000110L, + 0x00080010L, 0x00080110L, 0x01000010L, 0x01000110L, 0x01080010L, + 0x01080110L, 0x00200000L, 0x00200100L, 0x00280000L, 0x00280100L, + 0x01200000L, 0x01200100L, 0x01280000L, 0x01280100L, 0x00200010L, + 0x00200110L, 0x00280010L, 0x00280110L, 0x01200010L, 0x01200110L, + 0x01280010L, 0x01280110L, 0x00000200L, 0x00000300L, 0x00080200L, + 0x00080300L, 0x01000200L, 0x01000300L, 0x01080200L, 0x01080300L, + 0x00000210L, 0x00000310L, 0x00080210L, 0x00080310L, 0x01000210L, + 0x01000310L, 0x01080210L, 0x01080310L, 0x00200200L, 0x00200300L, + 0x00280200L, 0x00280300L, 0x01200200L, 0x01200300L, 0x01280200L, + 0x01280300L, 0x00200210L, 0x00200310L, 0x00280210L, 0x00280310L, + 0x01200210L, 0x01200310L, 0x01280210L, 0x01280310L, }, + {/* for D bits (numbered as per FIPS 46) 22 23 24 25 27 28 */ + 0x00000000L, 0x04000000L, 0x00040000L, 0x04040000L, 0x00000002L, + 0x04000002L, 0x00040002L, 0x04040002L, 0x00002000L, 0x04002000L, + 0x00042000L, 0x04042000L, 0x00002002L, 0x04002002L, 0x00042002L, + 0x04042002L, 0x00000020L, 0x04000020L, 0x00040020L, 0x04040020L, + 0x00000022L, 0x04000022L, 0x00040022L, 0x04040022L, 0x00002020L, + 0x04002020L, 0x00042020L, 0x04042020L, 0x00002022L, 0x04002022L, + 0x00042022L, 0x04042022L, 0x00000800L, 0x04000800L, 0x00040800L, + 0x04040800L, 0x00000802L, 0x04000802L, 0x00040802L, 0x04040802L, + 0x00002800L, 0x04002800L, 0x00042800L, 0x04042800L, 0x00002802L, + 0x04002802L, 0x00042802L, 0x04042802L, 0x00000820L, 0x04000820L, + 0x00040820L, 0x04040820L, 0x00000822L, 0x04000822L, 0x00040822L, + 0x04040822L, 0x00002820L, 0x04002820L, 0x00042820L, 0x04042820L, + 0x00002822L, 0x04002822L, 0x00042822L, 0x04042822L, }}; + +static const uint32_t DES_SPtrans[8][64] = { + {/* nibble 0 */ + 0x02080800L, 0x00080000L, 0x02000002L, 0x02080802L, 0x02000000L, + 0x00080802L, 0x00080002L, 0x02000002L, 0x00080802L, 0x02080800L, + 0x02080000L, 0x00000802L, 0x02000802L, 0x02000000L, 0x00000000L, + 0x00080002L, 0x00080000L, 0x00000002L, 0x02000800L, 0x00080800L, + 0x02080802L, 0x02080000L, 0x00000802L, 0x02000800L, 0x00000002L, + 0x00000800L, 0x00080800L, 0x02080002L, 0x00000800L, 0x02000802L, + 0x02080002L, 0x00000000L, 0x00000000L, 0x02080802L, 0x02000800L, + 0x00080002L, 0x02080800L, 0x00080000L, 0x00000802L, 0x02000800L, + 0x02080002L, 0x00000800L, 0x00080800L, 0x02000002L, 0x00080802L, + 0x00000002L, 0x02000002L, 0x02080000L, 0x02080802L, 0x00080800L, + 0x02080000L, 0x02000802L, 0x02000000L, 0x00000802L, 0x00080002L, + 0x00000000L, 0x00080000L, 0x02000000L, 0x02000802L, 0x02080800L, + 0x00000002L, 0x02080002L, 0x00000800L, 0x00080802L, }, + {/* nibble 1 */ + 0x40108010L, 0x00000000L, 0x00108000L, 0x40100000L, 0x40000010L, + 0x00008010L, 0x40008000L, 0x00108000L, 0x00008000L, 0x40100010L, + 0x00000010L, 0x40008000L, 0x00100010L, 0x40108000L, 0x40100000L, + 0x00000010L, 0x00100000L, 0x40008010L, 0x40100010L, 0x00008000L, + 0x00108010L, 0x40000000L, 0x00000000L, 0x00100010L, 0x40008010L, + 0x00108010L, 0x40108000L, 0x40000010L, 0x40000000L, 0x00100000L, + 0x00008010L, 0x40108010L, 0x00100010L, 0x40108000L, 0x40008000L, + 0x00108010L, 0x40108010L, 0x00100010L, 0x40000010L, 0x00000000L, + 0x40000000L, 0x00008010L, 0x00100000L, 0x40100010L, 0x00008000L, + 0x40000000L, 0x00108010L, 0x40008010L, 0x40108000L, 0x00008000L, + 0x00000000L, 0x40000010L, 0x00000010L, 0x40108010L, 0x00108000L, + 0x40100000L, 0x40100010L, 0x00100000L, 0x00008010L, 0x40008000L, + 0x40008010L, 0x00000010L, 0x40100000L, 0x00108000L, }, + {/* nibble 2 */ + 0x04000001L, 0x04040100L, 0x00000100L, 0x04000101L, 0x00040001L, + 0x04000000L, 0x04000101L, 0x00040100L, 0x04000100L, 0x00040000L, + 0x04040000L, 0x00000001L, 0x04040101L, 0x00000101L, 0x00000001L, + 0x04040001L, 0x00000000L, 0x00040001L, 0x04040100L, 0x00000100L, + 0x00000101L, 0x04040101L, 0x00040000L, 0x04000001L, 0x04040001L, + 0x04000100L, 0x00040101L, 0x04040000L, 0x00040100L, 0x00000000L, + 0x04000000L, 0x00040101L, 0x04040100L, 0x00000100L, 0x00000001L, + 0x00040000L, 0x00000101L, 0x00040001L, 0x04040000L, 0x04000101L, + 0x00000000L, 0x04040100L, 0x00040100L, 0x04040001L, 0x00040001L, + 0x04000000L, 0x04040101L, 0x00000001L, 0x00040101L, 0x04000001L, + 0x04000000L, 0x04040101L, 0x00040000L, 0x04000100L, 0x04000101L, + 0x00040100L, 0x04000100L, 0x00000000L, 0x04040001L, 0x00000101L, + 0x04000001L, 0x00040101L, 0x00000100L, 0x04040000L, }, + {/* nibble 3 */ + 0x00401008L, 0x10001000L, 0x00000008L, 0x10401008L, 0x00000000L, + 0x10400000L, 0x10001008L, 0x00400008L, 0x10401000L, 0x10000008L, + 0x10000000L, 0x00001008L, 0x10000008L, 0x00401008L, 0x00400000L, + 0x10000000L, 0x10400008L, 0x00401000L, 0x00001000L, 0x00000008L, + 0x00401000L, 0x10001008L, 0x10400000L, 0x00001000L, 0x00001008L, + 0x00000000L, 0x00400008L, 0x10401000L, 0x10001000L, 0x10400008L, + 0x10401008L, 0x00400000L, 0x10400008L, 0x00001008L, 0x00400000L, + 0x10000008L, 0x00401000L, 0x10001000L, 0x00000008L, 0x10400000L, + 0x10001008L, 0x00000000L, 0x00001000L, 0x00400008L, 0x00000000L, + 0x10400008L, 0x10401000L, 0x00001000L, 0x10000000L, 0x10401008L, + 0x00401008L, 0x00400000L, 0x10401008L, 0x00000008L, 0x10001000L, + 0x00401008L, 0x00400008L, 0x00401000L, 0x10400000L, 0x10001008L, + 0x00001008L, 0x10000000L, 0x10000008L, 0x10401000L, }, + {/* nibble 4 */ + 0x08000000L, 0x00010000L, 0x00000400L, 0x08010420L, 0x08010020L, + 0x08000400L, 0x00010420L, 0x08010000L, 0x00010000L, 0x00000020L, + 0x08000020L, 0x00010400L, 0x08000420L, 0x08010020L, 0x08010400L, + 0x00000000L, 0x00010400L, 0x08000000L, 0x00010020L, 0x00000420L, + 0x08000400L, 0x00010420L, 0x00000000L, 0x08000020L, 0x00000020L, + 0x08000420L, 0x08010420L, 0x00010020L, 0x08010000L, 0x00000400L, + 0x00000420L, 0x08010400L, 0x08010400L, 0x08000420L, 0x00010020L, + 0x08010000L, 0x00010000L, 0x00000020L, 0x08000020L, 0x08000400L, + 0x08000000L, 0x00010400L, 0x08010420L, 0x00000000L, 0x00010420L, + 0x08000000L, 0x00000400L, 0x00010020L, 0x08000420L, 0x00000400L, + 0x00000000L, 0x08010420L, 0x08010020L, 0x08010400L, 0x00000420L, + 0x00010000L, 0x00010400L, 0x08010020L, 0x08000400L, 0x00000420L, + 0x00000020L, 0x00010420L, 0x08010000L, 0x08000020L, }, + {/* nibble 5 */ + 0x80000040L, 0x00200040L, 0x00000000L, 0x80202000L, 0x00200040L, + 0x00002000L, 0x80002040L, 0x00200000L, 0x00002040L, 0x80202040L, + 0x00202000L, 0x80000000L, 0x80002000L, 0x80000040L, 0x80200000L, + 0x00202040L, 0x00200000L, 0x80002040L, 0x80200040L, 0x00000000L, + 0x00002000L, 0x00000040L, 0x80202000L, 0x80200040L, 0x80202040L, + 0x80200000L, 0x80000000L, 0x00002040L, 0x00000040L, 0x00202000L, + 0x00202040L, 0x80002000L, 0x00002040L, 0x80000000L, 0x80002000L, + 0x00202040L, 0x80202000L, 0x00200040L, 0x00000000L, 0x80002000L, + 0x80000000L, 0x00002000L, 0x80200040L, 0x00200000L, 0x00200040L, + 0x80202040L, 0x00202000L, 0x00000040L, 0x80202040L, 0x00202000L, + 0x00200000L, 0x80002040L, 0x80000040L, 0x80200000L, 0x00202040L, + 0x00000000L, 0x00002000L, 0x80000040L, 0x80002040L, 0x80202000L, + 0x80200000L, 0x00002040L, 0x00000040L, 0x80200040L, }, + {/* nibble 6 */ + 0x00004000L, 0x00000200L, 0x01000200L, 0x01000004L, 0x01004204L, + 0x00004004L, 0x00004200L, 0x00000000L, 0x01000000L, 0x01000204L, + 0x00000204L, 0x01004000L, 0x00000004L, 0x01004200L, 0x01004000L, + 0x00000204L, 0x01000204L, 0x00004000L, 0x00004004L, 0x01004204L, + 0x00000000L, 0x01000200L, 0x01000004L, 0x00004200L, 0x01004004L, + 0x00004204L, 0x01004200L, 0x00000004L, 0x00004204L, 0x01004004L, + 0x00000200L, 0x01000000L, 0x00004204L, 0x01004000L, 0x01004004L, + 0x00000204L, 0x00004000L, 0x00000200L, 0x01000000L, 0x01004004L, + 0x01000204L, 0x00004204L, 0x00004200L, 0x00000000L, 0x00000200L, + 0x01000004L, 0x00000004L, 0x01000200L, 0x00000000L, 0x01000204L, + 0x01000200L, 0x00004200L, 0x00000204L, 0x00004000L, 0x01004204L, + 0x01000000L, 0x01004200L, 0x00000004L, 0x00004004L, 0x01004204L, + 0x01000004L, 0x01004200L, 0x01004000L, 0x00004004L, }, + {/* nibble 7 */ + 0x20800080L, 0x20820000L, 0x00020080L, 0x00000000L, 0x20020000L, + 0x00800080L, 0x20800000L, 0x20820080L, 0x00000080L, 0x20000000L, + 0x00820000L, 0x00020080L, 0x00820080L, 0x20020080L, 0x20000080L, + 0x20800000L, 0x00020000L, 0x00820080L, 0x00800080L, 0x20020000L, + 0x20820080L, 0x20000080L, 0x00000000L, 0x00820000L, 0x20000000L, + 0x00800000L, 0x20020080L, 0x20800080L, 0x00800000L, 0x00020000L, + 0x20820000L, 0x00000080L, 0x00800000L, 0x00020000L, 0x20000080L, + 0x20820080L, 0x00020080L, 0x20000000L, 0x00000000L, 0x00820000L, + 0x20800080L, 0x20020080L, 0x20020000L, 0x00800080L, 0x20820000L, + 0x00000080L, 0x00800080L, 0x20020000L, 0x20820080L, 0x00800000L, + 0x20800000L, 0x20000080L, 0x00820000L, 0x00020080L, 0x20020080L, + 0x20800000L, 0x00000080L, 0x20820000L, 0x00820080L, 0x00000000L, + 0x20000000L, 0x20800080L, 0x00020000L, 0x00820080L, }}; + +#define HPERM_OP(a, t, n, m) \ + ((t) = ((((a) << (16 - (n))) ^ (a)) & (m)), \ + (a) = (a) ^ (t) ^ (t >> (16 - (n)))) + +void DES_set_key(const DES_cblock *key, DES_key_schedule *schedule) { + static const int shifts2[16] = {0, 0, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 0}; + uint32_t c, d, t, s, t2; + const uint8_t *in; + int i; + + in = key->bytes; + + c2l(in, c); + c2l(in, d); + + /* do PC1 in 47 simple operations :-) + * Thanks to John Fletcher (john_fletcher@lccmail.ocf.llnl.gov) + * for the inspiration. :-) */ + PERM_OP(d, c, t, 4, 0x0f0f0f0fL); + HPERM_OP(c, t, -2, 0xcccc0000L); + HPERM_OP(d, t, -2, 0xcccc0000L); + PERM_OP(d, c, t, 1, 0x55555555L); + PERM_OP(c, d, t, 8, 0x00ff00ffL); + PERM_OP(d, c, t, 1, 0x55555555L); + d = (((d & 0x000000ffL) << 16L) | (d & 0x0000ff00L) | + ((d & 0x00ff0000L) >> 16L) | ((c & 0xf0000000L) >> 4L)); + c &= 0x0fffffffL; + + for (i = 0; i < ITERATIONS; i++) { + if (shifts2[i]) { + c = ((c >> 2L) | (c << 26L)); + d = ((d >> 2L) | (d << 26L)); + } else { + c = ((c >> 1L) | (c << 27L)); + d = ((d >> 1L) | (d << 27L)); + } + c &= 0x0fffffffL; + d &= 0x0fffffffL; + /* could be a few less shifts but I am to lazy at this + * point in time to investigate */ + s = des_skb[0][(c) & 0x3f] | + des_skb[1][((c >> 6L) & 0x03) | ((c >> 7L) & 0x3c)] | + des_skb[2][((c >> 13L) & 0x0f) | ((c >> 14L) & 0x30)] | + des_skb[3][((c >> 20L) & 0x01) | ((c >> 21L) & 0x06) | + ((c >> 22L) & 0x38)]; + t = des_skb[4][(d) & 0x3f] | + des_skb[5][((d >> 7L) & 0x03) | ((d >> 8L) & 0x3c)] | + des_skb[6][(d >> 15L) & 0x3f] | + des_skb[7][((d >> 21L) & 0x0f) | ((d >> 22L) & 0x30)]; + + /* table contained 0213 4657 */ + t2 = ((t << 16L) | (s & 0x0000ffffL)) & 0xffffffffL; + schedule->subkeys[i][0] = ROTATE(t2, 30) & 0xffffffffL; + + t2 = ((s >> 16L) | (t & 0xffff0000L)); + schedule->subkeys[i][1] = ROTATE(t2, 26) & 0xffffffffL; + } +} + +static const uint8_t kOddParity[256] = { + 1, 1, 2, 2, 4, 4, 7, 7, 8, 8, 11, 11, 13, 13, 14, + 14, 16, 16, 19, 19, 21, 21, 22, 22, 25, 25, 26, 26, 28, 28, + 31, 31, 32, 32, 35, 35, 37, 37, 38, 38, 41, 41, 42, 42, 44, + 44, 47, 47, 49, 49, 50, 50, 52, 52, 55, 55, 56, 56, 59, 59, + 61, 61, 62, 62, 64, 64, 67, 67, 69, 69, 70, 70, 73, 73, 74, + 74, 76, 76, 79, 79, 81, 81, 82, 82, 84, 84, 87, 87, 88, 88, + 91, 91, 93, 93, 94, 94, 97, 97, 98, 98, 100, 100, 103, 103, 104, + 104, 107, 107, 109, 109, 110, 110, 112, 112, 115, 115, 117, 117, 118, 118, + 121, 121, 122, 122, 124, 124, 127, 127, 128, 128, 131, 131, 133, 133, 134, + 134, 137, 137, 138, 138, 140, 140, 143, 143, 145, 145, 146, 146, 148, 148, + 151, 151, 152, 152, 155, 155, 157, 157, 158, 158, 161, 161, 162, 162, 164, + 164, 167, 167, 168, 168, 171, 171, 173, 173, 174, 174, 176, 176, 179, 179, + 181, 181, 182, 182, 185, 185, 186, 186, 188, 188, 191, 191, 193, 193, 194, + 194, 196, 196, 199, 199, 200, 200, 203, 203, 205, 205, 206, 206, 208, 208, + 211, 211, 213, 213, 214, 214, 217, 217, 218, 218, 220, 220, 223, 223, 224, + 224, 227, 227, 229, 229, 230, 230, 233, 233, 234, 234, 236, 236, 239, 239, + 241, 241, 242, 242, 244, 244, 247, 247, 248, 248, 251, 251, 253, 253, 254, + 254 +}; + +void DES_set_odd_parity(DES_cblock *key) { + unsigned i; + + for (i = 0; i < DES_KEY_SZ; i++) { + key->bytes[i] = kOddParity[key->bytes[i]]; + } +} + +static void DES_encrypt1(uint32_t *data, const DES_key_schedule *ks, int enc) { + uint32_t l, r, t, u; + + r = data[0]; + l = data[1]; + + IP(r, l); + /* Things have been modified so that the initial rotate is done outside + * the loop. This required the DES_SPtrans values in sp.h to be + * rotated 1 bit to the right. One perl script later and things have a + * 5% speed up on a sparc2. Thanks to Richard Outerbridge + * <71755.204@CompuServe.COM> for pointing this out. */ + /* clear the top bits on machines with 8byte longs */ + /* shift left by 2 */ + r = ROTATE(r, 29) & 0xffffffffL; + l = ROTATE(l, 29) & 0xffffffffL; + + /* I don't know if it is worth the effort of loop unrolling the + * inner loop */ + if (enc) { + D_ENCRYPT(ks, l, r, 0); + D_ENCRYPT(ks, r, l, 1); + D_ENCRYPT(ks, l, r, 2); + D_ENCRYPT(ks, r, l, 3); + D_ENCRYPT(ks, l, r, 4); + D_ENCRYPT(ks, r, l, 5); + D_ENCRYPT(ks, l, r, 6); + D_ENCRYPT(ks, r, l, 7); + D_ENCRYPT(ks, l, r, 8); + D_ENCRYPT(ks, r, l, 9); + D_ENCRYPT(ks, l, r, 10); + D_ENCRYPT(ks, r, l, 11); + D_ENCRYPT(ks, l, r, 12); + D_ENCRYPT(ks, r, l, 13); + D_ENCRYPT(ks, l, r, 14); + D_ENCRYPT(ks, r, l, 15); + } else { + D_ENCRYPT(ks, l, r, 15); + D_ENCRYPT(ks, r, l, 14); + D_ENCRYPT(ks, l, r, 13); + D_ENCRYPT(ks, r, l, 12); + D_ENCRYPT(ks, l, r, 11); + D_ENCRYPT(ks, r, l, 10); + D_ENCRYPT(ks, l, r, 9); + D_ENCRYPT(ks, r, l, 8); + D_ENCRYPT(ks, l, r, 7); + D_ENCRYPT(ks, r, l, 6); + D_ENCRYPT(ks, l, r, 5); + D_ENCRYPT(ks, r, l, 4); + D_ENCRYPT(ks, l, r, 3); + D_ENCRYPT(ks, r, l, 2); + D_ENCRYPT(ks, l, r, 1); + D_ENCRYPT(ks, r, l, 0); + } + + /* rotate and clear the top bits on machines with 8byte longs */ + l = ROTATE(l, 3) & 0xffffffffL; + r = ROTATE(r, 3) & 0xffffffffL; + + FP(r, l); + data[0] = l; + data[1] = r; +} + +static void DES_encrypt2(uint32_t *data, const DES_key_schedule *ks, int enc) { + uint32_t l, r, t, u; + + r = data[0]; + l = data[1]; + + /* Things have been modified so that the initial rotate is done outside the + * loop. This required the DES_SPtrans values in sp.h to be rotated 1 bit to + * the right. One perl script later and things have a 5% speed up on a + * sparc2. Thanks to Richard Outerbridge <71755.204@CompuServe.COM> for + * pointing this out. */ + /* clear the top bits on machines with 8byte longs */ + r = ROTATE(r, 29) & 0xffffffffL; + l = ROTATE(l, 29) & 0xffffffffL; + + /* I don't know if it is worth the effort of loop unrolling the + * inner loop */ + if (enc) { + D_ENCRYPT(ks, l, r, 0); + D_ENCRYPT(ks, r, l, 1); + D_ENCRYPT(ks, l, r, 2); + D_ENCRYPT(ks, r, l, 3); + D_ENCRYPT(ks, l, r, 4); + D_ENCRYPT(ks, r, l, 5); + D_ENCRYPT(ks, l, r, 6); + D_ENCRYPT(ks, r, l, 7); + D_ENCRYPT(ks, l, r, 8); + D_ENCRYPT(ks, r, l, 9); + D_ENCRYPT(ks, l, r, 10); + D_ENCRYPT(ks, r, l, 11); + D_ENCRYPT(ks, l, r, 12); + D_ENCRYPT(ks, r, l, 13); + D_ENCRYPT(ks, l, r, 14); + D_ENCRYPT(ks, r, l, 15); + } else { + D_ENCRYPT(ks, l, r, 15); + D_ENCRYPT(ks, r, l, 14); + D_ENCRYPT(ks, l, r, 13); + D_ENCRYPT(ks, r, l, 12); + D_ENCRYPT(ks, l, r, 11); + D_ENCRYPT(ks, r, l, 10); + D_ENCRYPT(ks, l, r, 9); + D_ENCRYPT(ks, r, l, 8); + D_ENCRYPT(ks, l, r, 7); + D_ENCRYPT(ks, r, l, 6); + D_ENCRYPT(ks, l, r, 5); + D_ENCRYPT(ks, r, l, 4); + D_ENCRYPT(ks, l, r, 3); + D_ENCRYPT(ks, r, l, 2); + D_ENCRYPT(ks, l, r, 1); + D_ENCRYPT(ks, r, l, 0); + } + /* rotate and clear the top bits on machines with 8byte longs */ + data[0] = ROTATE(l, 3) & 0xffffffffL; + data[1] = ROTATE(r, 3) & 0xffffffffL; +} + +/* DES_encrypt3 is not static because it's used in decrepit. */ +void DES_encrypt3(uint32_t *data, const DES_key_schedule *ks1, + const DES_key_schedule *ks2, const DES_key_schedule *ks3) { + uint32_t l, r; + + l = data[0]; + r = data[1]; + IP(l, r); + data[0] = l; + data[1] = r; + DES_encrypt2((uint32_t *)data, ks1, DES_ENCRYPT); + DES_encrypt2((uint32_t *)data, ks2, DES_DECRYPT); + DES_encrypt2((uint32_t *)data, ks3, DES_ENCRYPT); + l = data[0]; + r = data[1]; + FP(r, l); + data[0] = l; + data[1] = r; +} + +/* DES_decrypt3 is not static because it's used in decrepit. */ +void DES_decrypt3(uint32_t *data, const DES_key_schedule *ks1, + const DES_key_schedule *ks2, const DES_key_schedule *ks3) { + uint32_t l, r; + + l = data[0]; + r = data[1]; + IP(l, r); + data[0] = l; + data[1] = r; + DES_encrypt2((uint32_t *)data, ks3, DES_DECRYPT); + DES_encrypt2((uint32_t *)data, ks2, DES_ENCRYPT); + DES_encrypt2((uint32_t *)data, ks1, DES_DECRYPT); + l = data[0]; + r = data[1]; + FP(r, l); + data[0] = l; + data[1] = r; +} + +void DES_ecb_encrypt(const DES_cblock *in_block, DES_cblock *out_block, + const DES_key_schedule *schedule, int is_encrypt) { + uint32_t l; + uint32_t ll[2]; + const uint8_t *in = in_block->bytes; + uint8_t *out = out_block->bytes; + + c2l(in, l); + ll[0] = l; + c2l(in, l); + ll[1] = l; + DES_encrypt1(ll, schedule, is_encrypt); + l = ll[0]; + l2c(l, out); + l = ll[1]; + l2c(l, out); + ll[0] = ll[1] = 0; +} + +void DES_ncbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const DES_key_schedule *schedule, DES_cblock *ivec, + int enc) { + uint32_t tin0, tin1; + uint32_t tout0, tout1, xor0, xor1; + uint32_t tin[2]; + unsigned char *iv; + + iv = ivec->bytes; + + if (enc) { + c2l(iv, tout0); + c2l(iv, tout1); + for (; len >= 8; len -= 8) { + c2l(in, tin0); + c2l(in, tin1); + tin0 ^= tout0; + tin[0] = tin0; + tin1 ^= tout1; + tin[1] = tin1; + DES_encrypt1((uint32_t *)tin, schedule, DES_ENCRYPT); + tout0 = tin[0]; + l2c(tout0, out); + tout1 = tin[1]; + l2c(tout1, out); + } + if (len != 0) { + c2ln(in, tin0, tin1, len); + tin0 ^= tout0; + tin[0] = tin0; + tin1 ^= tout1; + tin[1] = tin1; + DES_encrypt1((uint32_t *)tin, schedule, DES_ENCRYPT); + tout0 = tin[0]; + l2c(tout0, out); + tout1 = tin[1]; + l2c(tout1, out); + } + iv = ivec->bytes; + l2c(tout0, iv); + l2c(tout1, iv); + } else { + c2l(iv, xor0); + c2l(iv, xor1); + for (; len >= 8; len -= 8) { + c2l(in, tin0); + tin[0] = tin0; + c2l(in, tin1); + tin[1] = tin1; + DES_encrypt1((uint32_t *)tin, schedule, DES_DECRYPT); + tout0 = tin[0] ^ xor0; + tout1 = tin[1] ^ xor1; + l2c(tout0, out); + l2c(tout1, out); + xor0 = tin0; + xor1 = tin1; + } + if (len != 0) { + c2l(in, tin0); + tin[0] = tin0; + c2l(in, tin1); + tin[1] = tin1; + DES_encrypt1((uint32_t *)tin, schedule, DES_DECRYPT); + tout0 = tin[0] ^ xor0; + tout1 = tin[1] ^ xor1; + l2cn(tout0, tout1, out, len); + xor0 = tin0; + xor1 = tin1; + } + iv = ivec->bytes; + l2c(xor0, iv); + l2c(xor1, iv); + } + tin[0] = tin[1] = 0; +} + +void DES_ecb3_encrypt(const DES_cblock *input, DES_cblock *output, + const DES_key_schedule *ks1, const DES_key_schedule *ks2, + const DES_key_schedule *ks3, int enc) { + uint32_t l0, l1; + uint32_t ll[2]; + const uint8_t *in = input->bytes; + uint8_t *out = output->bytes; + + c2l(in, l0); + c2l(in, l1); + ll[0] = l0; + ll[1] = l1; + if (enc) { + DES_encrypt3(ll, ks1, ks2, ks3); + } else { + DES_decrypt3(ll, ks1, ks2, ks3); + } + l0 = ll[0]; + l1 = ll[1]; + l2c(l0, out); + l2c(l1, out); +} + +void DES_ede3_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + const DES_key_schedule *ks3, DES_cblock *ivec, + int enc) { + uint32_t tin0, tin1; + uint32_t tout0, tout1, xor0, xor1; + uint32_t tin[2]; + uint8_t *iv; + + iv = ivec->bytes; + + if (enc) { + c2l(iv, tout0); + c2l(iv, tout1); + for (; len >= 8; len -= 8) { + c2l(in, tin0); + c2l(in, tin1); + tin0 ^= tout0; + tin1 ^= tout1; + + tin[0] = tin0; + tin[1] = tin1; + DES_encrypt3((uint32_t *)tin, ks1, ks2, ks3); + tout0 = tin[0]; + tout1 = tin[1]; + + l2c(tout0, out); + l2c(tout1, out); + } + if (len != 0) { + c2ln(in, tin0, tin1, len); + tin0 ^= tout0; + tin1 ^= tout1; + + tin[0] = tin0; + tin[1] = tin1; + DES_encrypt3((uint32_t *)tin, ks1, ks2, ks3); + tout0 = tin[0]; + tout1 = tin[1]; + + l2c(tout0, out); + l2c(tout1, out); + } + iv = ivec->bytes; + l2c(tout0, iv); + l2c(tout1, iv); + } else { + uint32_t t0, t1; + + c2l(iv, xor0); + c2l(iv, xor1); + for (; len >= 8; len -= 8) { + c2l(in, tin0); + c2l(in, tin1); + + t0 = tin0; + t1 = tin1; + + tin[0] = tin0; + tin[1] = tin1; + DES_decrypt3((uint32_t *)tin, ks1, ks2, ks3); + tout0 = tin[0]; + tout1 = tin[1]; + + tout0 ^= xor0; + tout1 ^= xor1; + l2c(tout0, out); + l2c(tout1, out); + xor0 = t0; + xor1 = t1; + } + if (len != 0) { + c2l(in, tin0); + c2l(in, tin1); + + t0 = tin0; + t1 = tin1; + + tin[0] = tin0; + tin[1] = tin1; + DES_decrypt3((uint32_t *)tin, ks1, ks2, ks3); + tout0 = tin[0]; + tout1 = tin[1]; + + tout0 ^= xor0; + tout1 ^= xor1; + l2cn(tout0, tout1, out, len); + xor0 = t0; + xor1 = t1; + } + + iv = ivec->bytes; + l2c(xor0, iv); + l2c(xor1, iv); + } + + tin[0] = tin[1] = 0; +} + +void DES_ede2_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + DES_cblock *ivec, + int enc) { + DES_ede3_cbc_encrypt(in, out, len, ks1, ks2, ks1, ivec, enc); +} + + +/* Deprecated functions. */ + +void DES_set_key_unchecked(const DES_cblock *key, DES_key_schedule *schedule) { + DES_set_key(key, schedule); +} diff --git a/TMessagesProj/jni/boringssl/crypto/des/internal.h b/TMessagesProj/jni/boringssl/crypto/des/internal.h new file mode 100644 index 00000000..91559ff4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/des/internal.h @@ -0,0 +1,229 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DES_INTERNAL_H +#define OPENSSL_HEADER_DES_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#define c2l(c, l) \ + (l = ((uint32_t)(*((c)++))), l |= ((uint32_t)(*((c)++))) << 8L, \ + l |= ((uint32_t)(*((c)++))) << 16L, l |= ((uint32_t)(*((c)++))) << 24L) + +#define l2c(l, c) \ + (*((c)++) = (unsigned char)(((l)) & 0xff), \ + *((c)++) = (unsigned char)(((l) >> 8L) & 0xff), \ + *((c)++) = (unsigned char)(((l) >> 16L) & 0xff), \ + *((c)++) = (unsigned char)(((l) >> 24L) & 0xff)) + +/* NOTE - c is not incremented as per c2l */ +#define c2ln(c, l1, l2, n) \ + { \ + c += n; \ + l1 = l2 = 0; \ + switch (n) { \ + case 8: \ + l2 = ((uint32_t)(*(--(c)))) << 24L; \ + case 7: \ + l2 |= ((uint32_t)(*(--(c)))) << 16L; \ + case 6: \ + l2 |= ((uint32_t)(*(--(c)))) << 8L; \ + case 5: \ + l2 |= ((uint32_t)(*(--(c)))); \ + case 4: \ + l1 = ((uint32_t)(*(--(c)))) << 24L; \ + case 3: \ + l1 |= ((uint32_t)(*(--(c)))) << 16L; \ + case 2: \ + l1 |= ((uint32_t)(*(--(c)))) << 8L; \ + case 1: \ + l1 |= ((uint32_t)(*(--(c)))); \ + } \ + } + +/* NOTE - c is not incremented as per l2c */ +#define l2cn(l1, l2, c, n) \ + { \ + c += n; \ + switch (n) { \ + case 8: \ + *(--(c)) = (unsigned char)(((l2) >> 24L) & 0xff); \ + case 7: \ + *(--(c)) = (unsigned char)(((l2) >> 16L) & 0xff); \ + case 6: \ + *(--(c)) = (unsigned char)(((l2) >> 8L) & 0xff); \ + case 5: \ + *(--(c)) = (unsigned char)(((l2)) & 0xff); \ + case 4: \ + *(--(c)) = (unsigned char)(((l1) >> 24L) & 0xff); \ + case 3: \ + *(--(c)) = (unsigned char)(((l1) >> 16L) & 0xff); \ + case 2: \ + *(--(c)) = (unsigned char)(((l1) >> 8L) & 0xff); \ + case 1: \ + *(--(c)) = (unsigned char)(((l1)) & 0xff); \ + } \ + } + +/* IP and FP + * The problem is more of a geometric problem that random bit fiddling. + 0 1 2 3 4 5 6 7 62 54 46 38 30 22 14 6 + 8 9 10 11 12 13 14 15 60 52 44 36 28 20 12 4 +16 17 18 19 20 21 22 23 58 50 42 34 26 18 10 2 +24 25 26 27 28 29 30 31 to 56 48 40 32 24 16 8 0 + +32 33 34 35 36 37 38 39 63 55 47 39 31 23 15 7 +40 41 42 43 44 45 46 47 61 53 45 37 29 21 13 5 +48 49 50 51 52 53 54 55 59 51 43 35 27 19 11 3 +56 57 58 59 60 61 62 63 57 49 41 33 25 17 9 1 + +The output has been subject to swaps of the form +0 1 -> 3 1 but the odd and even bits have been put into +2 3 2 0 +different words. The main trick is to remember that +t=((l>>size)^r)&(mask); +r^=t; +l^=(t<> (n)) ^ (b)) & (m)), (b) ^= (t), (a) ^= ((t) << (n))) + +#define IP(l, r) \ + { \ + uint32_t tt; \ + PERM_OP(r, l, tt, 4, 0x0f0f0f0fL); \ + PERM_OP(l, r, tt, 16, 0x0000ffffL); \ + PERM_OP(r, l, tt, 2, 0x33333333L); \ + PERM_OP(l, r, tt, 8, 0x00ff00ffL); \ + PERM_OP(r, l, tt, 1, 0x55555555L); \ + } + +#define FP(l, r) \ + { \ + uint32_t tt; \ + PERM_OP(l, r, tt, 1, 0x55555555L); \ + PERM_OP(r, l, tt, 8, 0x00ff00ffL); \ + PERM_OP(l, r, tt, 2, 0x33333333L); \ + PERM_OP(r, l, tt, 16, 0x0000ffffL); \ + PERM_OP(l, r, tt, 4, 0x0f0f0f0fL); \ + } + +#define LOAD_DATA(ks, R, S, u, t, E0, E1) \ + u = R ^ ks->subkeys[S][0]; \ + t = R ^ ks->subkeys[S][1] + +#define D_ENCRYPT(ks, LL, R, S) \ + { \ + LOAD_DATA(ks, R, S, u, t, E0, E1); \ + t = ROTATE(t, 4); \ + LL ^= \ + DES_SPtrans[0][(u >> 2L) & 0x3f] ^ DES_SPtrans[2][(u >> 10L) & 0x3f] ^ \ + DES_SPtrans[4][(u >> 18L) & 0x3f] ^ \ + DES_SPtrans[6][(u >> 26L) & 0x3f] ^ DES_SPtrans[1][(t >> 2L) & 0x3f] ^ \ + DES_SPtrans[3][(t >> 10L) & 0x3f] ^ \ + DES_SPtrans[5][(t >> 18L) & 0x3f] ^ DES_SPtrans[7][(t >> 26L) & 0x3f]; \ + } + +#define ITERATIONS 16 +#define HALF_ITERATIONS 8 + +#if defined(_MSC_VER) +#define ROTATE(a, n) (_lrotr(a, n)) +#elif defined(__ICC) +#define ROTATE(a, n) (_rotr(a, n)) +#elif defined(__GNUC__) && __GNUC__ >= 2 && !defined(OPENSSL_NO_ASM) && \ + !defined(__STRICT_ANSI__) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) +#define ROTATE(a, n) \ + ({ \ + unsigned int ret; \ + asm("rorl %1,%0" : "=r"(ret) : "I"(n), "0"(a) : "cc"); \ + ret; \ + }) +#endif + +#ifndef ROTATE +#define ROTATE(a, n) (((a) >> (n)) + ((a) << (32 - (n)))) +#endif + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_DES_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/dh/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/dh/CMakeLists.txt new file mode 100644 index 00000000..5054628e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dh/CMakeLists.txt @@ -0,0 +1,13 @@ +include_directories(. .. ../../include) + +add_library( + dh + + OBJECT + + dh.c + dh_impl.c + params.c + check.c + dh_asn1.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/dh/check.c b/TMessagesProj/jni/boringssl/crypto/dh/check.c new file mode 100644 index 00000000..06af6f25 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dh/check.c @@ -0,0 +1,180 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include "internal.h" + + +int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) { + int ok = 0; + BIGNUM q; + + *ret = 0; + BN_init(&q); + if (!BN_set_word(&q, 1)) { + goto err; + } + + if (BN_cmp(pub_key, &q) <= 0) { + *ret |= DH_CHECK_PUBKEY_TOO_SMALL; + } + if (!BN_copy(&q, dh->p) || + !BN_sub_word(&q, 1)) { + goto err; + } + if (BN_cmp(pub_key, &q) >= 0) { + *ret |= DH_CHECK_PUBKEY_TOO_LARGE; + } + + ok = 1; + +err: + BN_free(&q); + return ok; +} + + +int DH_check(const DH *dh, int *ret) { + /* Check that p is a safe prime and if g is 2, 3 or 5, check that it is a + * suitable generator where: + * for 2, p mod 24 == 11 + * for 3, p mod 12 == 5 + * for 5, p mod 10 == 3 or 7 + * should hold. + */ + int ok = 0; + BN_CTX *ctx = NULL; + BN_ULONG l; + BIGNUM *t1 = NULL, *t2 = NULL; + + *ret = 0; + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + t1 = BN_CTX_get(ctx); + if (t1 == NULL) { + goto err; + } + t2 = BN_CTX_get(ctx); + if (t2 == NULL) { + goto err; + } + + if (dh->q) { + if (BN_cmp(dh->g, BN_value_one()) <= 0) { + *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR; + } else if (BN_cmp(dh->g, dh->p) >= 0) { + *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR; + } else { + /* Check g^q == 1 mod p */ + if (!BN_mod_exp(t1, dh->g, dh->q, dh->p, ctx)) { + goto err; + } + if (!BN_is_one(t1)) { + *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR; + } + } + if (!BN_is_prime_ex(dh->q, BN_prime_checks, ctx, NULL)) { + *ret |= DH_CHECK_Q_NOT_PRIME; + } + /* Check p == 1 mod q i.e. q divides p - 1 */ + if (!BN_div(t1, t2, dh->p, dh->q, ctx)) { + goto err; + } + if (!BN_is_one(t2)) { + *ret |= DH_CHECK_INVALID_Q_VALUE; + } + if (dh->j && BN_cmp(dh->j, t1)) { + *ret |= DH_CHECK_INVALID_J_VALUE; + } + } else if (BN_is_word(dh->g, DH_GENERATOR_2)) { + l = BN_mod_word(dh->p, 24); + if (l != 11) { + *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR; + } + } else if (BN_is_word(dh->g, DH_GENERATOR_5)) { + l = BN_mod_word(dh->p, 10); + if (l != 3 && l != 7) { + *ret |= DH_CHECK_NOT_SUITABLE_GENERATOR; + } + } else { + *ret |= DH_CHECK_UNABLE_TO_CHECK_GENERATOR; + } + + if (!BN_is_prime_ex(dh->p, BN_prime_checks, ctx, NULL)) { + *ret |= DH_CHECK_P_NOT_PRIME; + } else if (!dh->q) { + if (!BN_rshift1(t1, dh->p)) { + goto err; + } + if (!BN_is_prime_ex(t1, BN_prime_checks, ctx, NULL)) { + *ret |= DH_CHECK_P_NOT_SAFE_PRIME; + } + } + ok = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + return ok; +} diff --git a/TMessagesProj/jni/boringssl/crypto/dh/dh.c b/TMessagesProj/jni/boringssl/crypto/dh/dh.c new file mode 100644 index 00000000..d25f3583 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dh/dh.c @@ -0,0 +1,252 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +extern const DH_METHOD DH_default_method; + +static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT; + +DH *DH_new(void) { return DH_new_method(NULL); } + +DH *DH_new_method(const ENGINE *engine) { + DH *dh = (DH *)OPENSSL_malloc(sizeof(DH)); + if (dh == NULL) { + OPENSSL_PUT_ERROR(DH, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(dh, 0, sizeof(DH)); + + if (engine) { + dh->meth = ENGINE_get_DH_method(engine); + } + + if (dh->meth == NULL) { + dh->meth = (DH_METHOD*) &DH_default_method; + } + METHOD_ref(dh->meth); + + CRYPTO_MUTEX_init(&dh->method_mont_p_lock); + + dh->references = 1; + if (!CRYPTO_new_ex_data(&g_ex_data_class, dh, &dh->ex_data)) { + OPENSSL_free(dh); + return NULL; + } + + if (dh->meth->init && !dh->meth->init(dh)) { + CRYPTO_free_ex_data(&g_ex_data_class, dh, &dh->ex_data); + METHOD_unref(dh->meth); + OPENSSL_free(dh); + return NULL; + } + + return dh; +} + +void DH_free(DH *dh) { + if (dh == NULL) { + return; + } + + if (!CRYPTO_refcount_dec_and_test_zero(&dh->references)) { + return; + } + + if (dh->meth->finish) { + dh->meth->finish(dh); + } + METHOD_unref(dh->meth); + + CRYPTO_free_ex_data(&g_ex_data_class, dh, &dh->ex_data); + + if (dh->method_mont_p) BN_MONT_CTX_free(dh->method_mont_p); + if (dh->p != NULL) BN_clear_free(dh->p); + if (dh->g != NULL) BN_clear_free(dh->g); + if (dh->q != NULL) BN_clear_free(dh->q); + if (dh->j != NULL) BN_clear_free(dh->j); + if (dh->seed) OPENSSL_free(dh->seed); + if (dh->counter != NULL) BN_clear_free(dh->counter); + if (dh->pub_key != NULL) BN_clear_free(dh->pub_key); + if (dh->priv_key != NULL) BN_clear_free(dh->priv_key); + CRYPTO_MUTEX_cleanup(&dh->method_mont_p_lock); + + OPENSSL_free(dh); +} + +int DH_generate_parameters_ex(DH *dh, int prime_bits, int generator, BN_GENCB *cb) { + if (dh->meth->generate_parameters) { + return dh->meth->generate_parameters(dh, prime_bits, generator, cb); + } + return DH_default_method.generate_parameters(dh, prime_bits, generator, cb); +} + +int DH_generate_key(DH *dh) { + if (dh->meth->generate_key) { + return dh->meth->generate_key(dh); + } + return DH_default_method.generate_key(dh); +} + +int DH_compute_key(unsigned char *out, const BIGNUM *peers_key, DH *dh) { + if (dh->meth->compute_key) { + return dh->meth->compute_key(dh, out, peers_key); + } + return DH_default_method.compute_key(dh, out, peers_key); +} + +int DH_size(const DH *dh) { return BN_num_bytes(dh->p); } + +unsigned DH_num_bits(const DH *dh) { return BN_num_bits(dh->p); } + +int DH_up_ref(DH *dh) { + CRYPTO_refcount_inc(&dh->references); + return 1; +} + +static int int_dh_bn_cpy(BIGNUM **dst, const BIGNUM *src) { + BIGNUM *a = NULL; + + if (src) { + a = BN_dup(src); + if (!a) { + return 0; + } + } + + BN_free(*dst); + *dst = a; + return 1; +} + +static int int_dh_param_copy(DH *to, const DH *from, int is_x942) { + if (is_x942 == -1) { + is_x942 = !!from->q; + } + if (!int_dh_bn_cpy(&to->p, from->p) || + !int_dh_bn_cpy(&to->g, from->g)) { + return 0; + } + + if (!is_x942) { + return 1; + } + + if (!int_dh_bn_cpy(&to->q, from->q) || + !int_dh_bn_cpy(&to->j, from->j)) { + return 0; + } + + OPENSSL_free(to->seed); + to->seed = NULL; + to->seedlen = 0; + + if (from->seed) { + to->seed = BUF_memdup(from->seed, from->seedlen); + if (!to->seed) { + return 0; + } + to->seedlen = from->seedlen; + } + + return 1; +} + +DH *DHparams_dup(const DH *dh) { + DH *ret = DH_new(); + if (!ret) { + return NULL; + } + + if (!int_dh_param_copy(ret, dh, -1)) { + DH_free(ret); + return NULL; + } + + return ret; +} + +int DH_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) { + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, new_func, + dup_func, free_func)) { + return -1; + } + return index; +} + +int DH_set_ex_data(DH *d, int idx, void *arg) { + return (CRYPTO_set_ex_data(&d->ex_data, idx, arg)); +} + +void *DH_get_ex_data(DH *d, int idx) { + return (CRYPTO_get_ex_data(&d->ex_data, idx)); +} diff --git a/TMessagesProj/jni/boringssl/crypto/dh/dh_asn1.c b/TMessagesProj/jni/boringssl/crypto/dh/dh_asn1.c new file mode 100644 index 00000000..73cd4df7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dh/dh_asn1.c @@ -0,0 +1,84 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 2000-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include "internal.h" + +/* Override the default free and new methods */ +static int dh_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) { + if (operation == ASN1_OP_NEW_PRE) { + *pval = (ASN1_VALUE *)DH_new(); + if (*pval) { + return 2; + } + return 0; + } else if (operation == ASN1_OP_FREE_PRE) { + DH_free((DH *)*pval); + *pval = NULL; + return 2; + } + return 1; +} + +ASN1_SEQUENCE_cb(DHparams, dh_cb) = { + ASN1_SIMPLE(DH, p, BIGNUM), ASN1_SIMPLE(DH, g, BIGNUM), + ASN1_OPT(DH, priv_length, ZLONG)} ASN1_SEQUENCE_END_cb(DH, DHparams); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DH, DHparams, DHparams) diff --git a/TMessagesProj/jni/boringssl/crypto/dh/dh_impl.c b/TMessagesProj/jni/boringssl/crypto/dh/dh_impl.c new file mode 100644 index 00000000..6cf0abb6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dh/dh_impl.c @@ -0,0 +1,326 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + +#include "internal.h" + + +#define OPENSSL_DH_MAX_MODULUS_BITS 10000 + +static int generate_parameters(DH *ret, int prime_bits, int generator, BN_GENCB *cb) { + /* We generate DH parameters as follows + * find a prime q which is prime_bits/2 bits long. + * p=(2*q)+1 or (p-1)/2 = q + * For this case, g is a generator if + * g^((p-1)/q) mod p != 1 for values of q which are the factors of p-1. + * Since the factors of p-1 are q and 2, we just need to check + * g^2 mod p != 1 and g^q mod p != 1. + * + * Having said all that, + * there is another special case method for the generators 2, 3 and 5. + * for 2, p mod 24 == 11 + * for 3, p mod 12 == 5 <<<<< does not work for safe primes. + * for 5, p mod 10 == 3 or 7 + * + * Thanks to Phil Karn for the pointers about the + * special generators and for answering some of my questions. + * + * I've implemented the second simple method :-). + * Since DH should be using a safe prime (both p and q are prime), + * this generator function can take a very very long time to run. + */ + + /* Actually there is no reason to insist that 'generator' be a generator. + * It's just as OK (and in some sense better) to use a generator of the + * order-q subgroup. + */ + + BIGNUM *t1, *t2; + int g, ok = 0; + BN_CTX *ctx = NULL; + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + t1 = BN_CTX_get(ctx); + t2 = BN_CTX_get(ctx); + if (t1 == NULL || t2 == NULL) { + goto err; + } + + /* Make sure 'ret' has the necessary elements */ + if (!ret->p && ((ret->p = BN_new()) == NULL)) { + goto err; + } + if (!ret->g && ((ret->g = BN_new()) == NULL)) { + goto err; + } + + if (generator <= 1) { + OPENSSL_PUT_ERROR(DH, DH_R_BAD_GENERATOR); + goto err; + } + if (generator == DH_GENERATOR_2) { + if (!BN_set_word(t1, 24)) { + goto err; + } + if (!BN_set_word(t2, 11)) { + goto err; + } + g = 2; + } else if (generator == DH_GENERATOR_5) { + if (!BN_set_word(t1, 10)) { + goto err; + } + if (!BN_set_word(t2, 3)) { + goto err; + } + /* BN_set_word(t3,7); just have to miss + * out on these ones :-( */ + g = 5; + } else { + /* in the general case, don't worry if 'generator' is a + * generator or not: since we are using safe primes, + * it will generate either an order-q or an order-2q group, + * which both is OK */ + if (!BN_set_word(t1, 2)) { + goto err; + } + if (!BN_set_word(t2, 1)) { + goto err; + } + g = generator; + } + + if (!BN_generate_prime_ex(ret->p, prime_bits, 1, t1, t2, cb)) { + goto err; + } + if (!BN_GENCB_call(cb, 3, 0)) { + goto err; + } + if (!BN_set_word(ret->g, g)) { + goto err; + } + ok = 1; + +err: + if (!ok) { + OPENSSL_PUT_ERROR(DH, ERR_R_BN_LIB); + } + + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + return ok; +} + +static int generate_key(DH *dh) { + int ok = 0; + int generate_new_key = 0; + unsigned l; + BN_CTX *ctx; + BN_MONT_CTX *mont = NULL; + BIGNUM *pub_key = NULL, *priv_key = NULL; + BIGNUM local_priv; + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + + if (dh->priv_key == NULL) { + priv_key = BN_new(); + if (priv_key == NULL) { + goto err; + } + generate_new_key = 1; + } else { + priv_key = dh->priv_key; + } + + if (dh->pub_key == NULL) { + pub_key = BN_new(); + if (pub_key == NULL) { + goto err; + } + } else { + pub_key = dh->pub_key; + } + + mont = BN_MONT_CTX_set_locked(&dh->method_mont_p, &dh->method_mont_p_lock, + dh->p, ctx); + if (!mont) { + goto err; + } + + if (generate_new_key) { + if (dh->q) { + do { + if (!BN_rand_range(priv_key, dh->q)) { + goto err; + } + } while (BN_is_zero(priv_key) || BN_is_one(priv_key)); + } else { + /* secret exponent length */ + DH_check_standard_parameters(dh); + l = dh->priv_length ? dh->priv_length : BN_num_bits(dh->p) - 1; + if (!BN_rand(priv_key, l, 0, 0)) { + goto err; + } + } + } + + BN_with_flags(&local_priv, priv_key, BN_FLG_CONSTTIME); + if (!BN_mod_exp_mont(pub_key, dh->g, &local_priv, dh->p, ctx, mont)) { + goto err; + } + + dh->pub_key = pub_key; + dh->priv_key = priv_key; + ok = 1; + +err: + if (ok != 1) { + OPENSSL_PUT_ERROR(DH, ERR_R_BN_LIB); + } + + if (dh->pub_key == NULL) { + BN_free(pub_key); + } + if (dh->priv_key == NULL) { + BN_free(priv_key); + } + BN_CTX_free(ctx); + return ok; +} + +static int compute_key(DH *dh, unsigned char *out, const BIGNUM *pub_key) { + BN_CTX *ctx = NULL; + BN_MONT_CTX *mont = NULL; + BIGNUM *shared_key; + int ret = -1; + int check_result; + BIGNUM local_priv; + + if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) { + OPENSSL_PUT_ERROR(DH, DH_R_MODULUS_TOO_LARGE); + goto err; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + shared_key = BN_CTX_get(ctx); + if (shared_key == NULL) { + goto err; + } + + if (dh->priv_key == NULL) { + OPENSSL_PUT_ERROR(DH, DH_R_NO_PRIVATE_VALUE); + goto err; + } + + mont = BN_MONT_CTX_set_locked(&dh->method_mont_p, &dh->method_mont_p_lock, + dh->p, ctx); + if (!mont) { + goto err; + } + + if (!DH_check_pub_key(dh, pub_key, &check_result) || check_result) { + OPENSSL_PUT_ERROR(DH, DH_R_INVALID_PUBKEY); + goto err; + } + + BN_with_flags(&local_priv, dh->priv_key, BN_FLG_CONSTTIME); + if (!BN_mod_exp_mont(shared_key, pub_key, &local_priv, dh->p, ctx, + mont)) { + OPENSSL_PUT_ERROR(DH, ERR_R_BN_LIB); + goto err; + } + + ret = BN_bn2bin(shared_key, out); + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + + return ret; +} + +const struct dh_method DH_default_method = { + { + 0 /* references */, + 1 /* is_static */, + }, + NULL /* app_data */, + NULL /* init */, + NULL /* finish */, + generate_parameters, + generate_key, + compute_key, +}; diff --git a/TMessagesProj/jni/boringssl/crypto/dh/internal.h b/TMessagesProj/jni/boringssl/crypto/dh/internal.h new file mode 100644 index 00000000..81b9c902 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dh/internal.h @@ -0,0 +1,80 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DH_INTERNAL_H +#define OPENSSL_HEADER_DH_INTERNAL_H + +#include + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* DH_check_standard_parameters checks if the parameters in |dh| are well + * known and safe. If so, it sets |dh->priv_length| to an appropriately smaller + * value than the default. */ +void DH_check_standard_parameters(DH *dh); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_DH_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/dh/params.c b/TMessagesProj/jni/boringssl/crypto/dh/params.c new file mode 100644 index 00000000..82d1d921 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dh/params.c @@ -0,0 +1,316 @@ +/* ==================================================================== + * Copyright (c) 2011 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include "internal.h" + + +#if BN_BITS2 == 32 +#define TOBN(lo, hi) lo, hi +#elif BN_BITS2 == 64 +#define TOBN(lo, hi) ((BN_ULONG)hi << 32 | lo) +#else +#error "unsupported BN_BITS2" +#endif + +static const BN_ULONG dh1024_160_p[] = { + TOBN(0x2E4A4371, 0xDF1FB2BC), TOBN(0x6D4DA708, 0xE68CFDA7), + TOBN(0x365C1A65, 0x45BF37DF), TOBN(0x0DC8B4BD, 0xA151AF5F), + TOBN(0xF55BCCC0, 0xFAA31A4F), TOBN(0xE5644738, 0x4EFFD6FA), + TOBN(0x219A7372, 0x98488E9C), TOBN(0x90C4BD70, 0xACCBDD7D), + TOBN(0xD49B83BF, 0x24975C3C), TOBN(0xA9061123, 0x13ECB4AE), + TOBN(0x2EE652C0, 0x9838EF1E), TOBN(0x75A23D18, 0x6073E286), + TOBN(0x52D23B61, 0x9A6A9DCA), TOBN(0xFB06A3C6, 0x52C99FBC), + TOBN(0xAE5D54EC, 0xDE92DE5E), TOBN(0xA080E01D, 0xB10B8F96), +}; +static const BN_ULONG dh1024_160_g[] = { + TOBN(0x22B3B2E5, 0x855E6EEB), TOBN(0xF97C2A24, 0x858F4DCE), + TOBN(0x18D08BC8, 0x2D779D59), TOBN(0x8E73AFA3, 0xD662A4D1), + TOBN(0x69B6A28A, 0x1DBF0A01), TOBN(0x7A091F53, 0xA6A24C08), + TOBN(0x63F80A76, 0x909D0D22), TOBN(0xB9A92EE1, 0xD7FBD7D3), + TOBN(0x9E2749F4, 0x5E91547F), TOBN(0xB01B886A, 0x160217B4), + TOBN(0x5504F213, 0x777E690F), TOBN(0x5C41564B, 0x266FEA1E), + TOBN(0x14266D31, 0xD6406CFF), TOBN(0x58AC507F, 0xF8104DD2), + TOBN(0xEFB99905, 0x6765A442), TOBN(0xC3FD3412, 0xA4D1CBD5), +}; +static const BN_ULONG dh1024_160_q[] = { + TOBN(0x49462353, 0x64B7CB9D), TOBN(0x8ABA4E7D, 0x81A8DF27), 0xF518AA87, +}; + +static const BN_ULONG dh2048_224_p[] = { + TOBN(0x0C10E64F, 0x0AC4DFFE), TOBN(0x4E71B81C, 0xCF9DE538), + TOBN(0xFFA31F71, 0x7EF363E2), TOBN(0x6B8E75B9, 0xE3FB73C1), + TOBN(0x4BA80A29, 0xC9B53DCF), TOBN(0x16E79763, 0x23F10B0E), + TOBN(0x13042E9B, 0xC52172E4), TOBN(0xC928B2B9, 0xBE60E69C), + TOBN(0xB9E587E8, 0x80CD86A1), TOBN(0x98C641A4, 0x315D75E1), + TOBN(0x44328387, 0xCDF93ACC), TOBN(0xDC0A486D, 0x15987D9A), + TOBN(0x1FD5A074, 0x7310F712), TOBN(0xDE31EFDC, 0x278273C7), + TOBN(0x415D9330, 0x1602E714), TOBN(0xBC8985DB, 0x81286130), + TOBN(0x70918836, 0xB3BF8A31), TOBN(0xB9C49708, 0x6A00E0A0), + TOBN(0x8BBC27BE, 0xC6BA0B2C), TOBN(0xED34DBF6, 0xC9F98D11), + TOBN(0xB6C12207, 0x7AD5B7D0), TOBN(0x55B7394B, 0xD91E8FEF), + TOBN(0xEFDA4DF8, 0x9037C9ED), TOBN(0xAD6AC212, 0x6D3F8152), + TOBN(0x1274A0A6, 0x1DE6B85A), TOBN(0x309C180E, 0xEB3D688A), + TOBN(0x7BA1DF15, 0xAF9A3C40), TOBN(0xF95A56DB, 0xE6FA141D), + TOBN(0xB61D0A75, 0xB54B1597), TOBN(0x683B9FD1, 0xA20D64E5), + TOBN(0x9559C51F, 0xD660FAA7), TOBN(0x9123A9D0, 0xAD107E1E), +}; + +static const BN_ULONG dh2048_224_g[] = { + TOBN(0x191F2BFA, 0x84B890D3), TOBN(0x2A7065B3, 0x81BC087F), + TOBN(0xF6EC0179, 0x19C418E1), TOBN(0x71CFFF4C, 0x7B5A0F1C), + TOBN(0x9B6AA4BD, 0xEDFE72FE), TOBN(0x94B30269, 0x81E1BCFE), + TOBN(0x8D6C0191, 0x566AFBB4), TOBN(0x409D13CD, 0xB539CCE3), + TOBN(0x5F2FF381, 0x6AA21E7F), TOBN(0x770589EF, 0xD9E263E4), + TOBN(0xD19963DD, 0x10E183ED), TOBN(0x150B8EEB, 0xB70A8137), + TOBN(0x28C8F8AC, 0x051AE3D4), TOBN(0x0C1AB15B, 0xBB77A86F), + TOBN(0x16A330EF, 0x6E3025E3), TOBN(0xD6F83456, 0x19529A45), + TOBN(0x118E98D1, 0xF180EB34), TOBN(0x50717CBE, 0xB5F6C6B2), + TOBN(0xDA7460CD, 0x09939D54), TOBN(0x22EA1ED4, 0xE2471504), + TOBN(0x521BC98A, 0xB8A762D0), TOBN(0x5AC1348B, 0xF4D02727), + TOBN(0x1999024A, 0xC1766910), TOBN(0xA8D66AD7, 0xBE5E9001), + TOBN(0x620A8652, 0xC57DB17C), TOBN(0x00C29F52, 0xAB739D77), + TOBN(0xA70C4AFA, 0xDD921F01), TOBN(0x10B9A6F0, 0xA6824A4E), + TOBN(0xCFE4FFE3, 0x74866A08), TOBN(0x89998CAF, 0x6CDEBE7B), + TOBN(0x8FFDAC50, 0x9DF30B5C), TOBN(0x4F2D9AE3, 0xAC4032EF), +}; + +static const BN_ULONG dh2048_224_q[] = { + TOBN(0xB36371EB, 0xBF389A99), TOBN(0x4738CEBC, 0x1F80535A), + TOBN(0x99717710, 0xC58D93FE), 0x801C0D34, +}; + +static const BN_ULONG dh2048_256_p[] = { + TOBN(0x1E1A1597, 0xDB094AE9), TOBN(0xD7EF09CA, 0x693877FA), + TOBN(0x6E11715F, 0x6116D227), TOBN(0xC198AF12, 0xA4B54330), + TOBN(0xD7014103, 0x75F26375), TOBN(0x54E710C3, 0xC3A3960A), + TOBN(0xBD0BE621, 0xDED4010A), TOBN(0x89962856, 0xC0B857F6), + TOBN(0x71506026, 0xB3CA3F79), TOBN(0xE6B486F6, 0x1CCACB83), + TOBN(0x14056425, 0x67E144E5), TOBN(0xA41825D9, 0xF6A167B5), + TOBN(0x96524D8E, 0x3AD83477), TOBN(0x51BFA4AB, 0xF13C6D9A), + TOBN(0x35488A0E, 0x2D525267), TOBN(0xCAA6B790, 0xB63ACAE1), + TOBN(0x81B23F76, 0x4FDB70C5), TOBN(0x12307F5C, 0xBC39A0BF), + TOBN(0xB1E59BB8, 0xB941F54E), TOBN(0xD45F9088, 0x6C5BFC11), + TOBN(0x4275BF7B, 0x22E0B1EF), TOBN(0x5B4758C0, 0x91F9E672), + TOBN(0x6BCF67ED, 0x5A8A9D30), TOBN(0x97517ABD, 0x209E0C64), + TOBN(0x830E9A7C, 0x3BF4296D), TOBN(0x34096FAA, 0x16C3D911), + TOBN(0x61B2AA30, 0xFAF7DF45), TOBN(0xD61957D4, 0xE00DF8F1), + TOBN(0x435E3B00, 0x5D2CEED4), TOBN(0x660DD0F2, 0x8CEEF608), + TOBN(0x65195999, 0xFFBBD19C), TOBN(0xB4B6663C, 0x87A8E61D), +}; +static const BN_ULONG dh2048_256_g[] = { + TOBN(0x6CC41659, 0x664B4C0F), TOBN(0xEF98C582, 0x5E2327CF), + TOBN(0xD4795451, 0xD647D148), TOBN(0x90F00EF8, 0x2F630784), + TOBN(0x1DB246C3, 0x184B523D), TOBN(0xCDC67EB6, 0xC7891428), + TOBN(0x0DF92B52, 0x7FD02837), TOBN(0x64E0EC37, 0xB3353BBB), + TOBN(0x57CD0915, 0xECD06E15), TOBN(0xDF016199, 0xB7D2BBD2), + TOBN(0x052588B9, 0xC8484B1E), TOBN(0x13D3FE14, 0xDB2A3B73), + TOBN(0xD182EA0A, 0xD052B985), TOBN(0xE83B9C80, 0xA4BD1BFF), + TOBN(0xFB3F2E55, 0xDFC967C1), TOBN(0x767164E1, 0xB5045AF2), + TOBN(0x6F2F9193, 0x1D14348F), TOBN(0x428EBC83, 0x64E67982), + TOBN(0x82D6ED38, 0x8AC376D2), TOBN(0xAAB8A862, 0x777DE62A), + TOBN(0xE9EC144B, 0xDDF463E5), TOBN(0xC77A57F2, 0x0196F931), + TOBN(0x41000A65, 0xA55AE313), TOBN(0xC28CBB18, 0x901228F8), + TOBN(0x7E8C6F62, 0xBC3773BF), TOBN(0x0C6B47B1, 0xBE3A6C1B), + TOBN(0xAC0BB555, 0xFF4FED4A), TOBN(0x77BE463F, 0x10DBC150), + TOBN(0x1A0BA125, 0x07F4793A), TOBN(0x21EF2054, 0x4CA7B18F), + TOBN(0x60EDBD48, 0x2E775066), TOBN(0x73134D0B, 0x3FB32C9B), +}; +static const BN_ULONG dh2048_256_q[] = { + TOBN(0x64F5FBD3, 0xA308B0FE), TOBN(0x1EB3750B, 0x99B1A47D), + TOBN(0x40129DA2, 0xB4479976), TOBN(0xA709A097, 0x8CF83642), +}; + +/* dh1024_safe_prime_1 is hard-coded in Apache httpd 2.2, + * modules/ssl/ssl_engine_dh.c. */ +static const BN_ULONG dh1024_safe_prime_1[] = { + TOBN(0x24218EB3, 0xE7393E0F), TOBN(0xE2BD68B0, 0x7DE0F4D6), + TOBN(0x88AEAA74, 0x07DD62DB), TOBN(0x9DDD3305, 0x10EA9FCC), + TOBN(0x74087D15, 0xA7DBCA78), TOBN(0x78045B07, 0xDAE88600), + TOBN(0x1AAD3B72, 0x33168A46), TOBN(0x7BEDDCFD, 0xFF590137), + TOBN(0x7A635E81, 0xFE324A46), TOBN(0x420B2A29, 0x5AC179BA), + TOBN(0x177E16D5, 0x13B4B4D7), TOBN(0x639C72FB, 0x849F912E), + TOBN(0x98BCE951, 0xB88174CB), TOBN(0xA45F520B, 0x0C84D239), + TOBN(0x4AFD0AD5, 0x36D693D3), TOBN(0xCBBBDC19, 0xD67DE440), +}; + +/* dh1024_safe_prime_2 is hard-coded in nginx, + * src/event/ngx_event_openssl.c. */ +static const BN_ULONG dh1024_safe_prime_2[] = { + TOBN(0xCFE16B9B, 0x071DF045), TOBN(0x146757DA, 0x88D0F65D), + TOBN(0x58FAFD49, 0x4A63AB1E), TOBN(0xEF9EA027, 0x35D8CECE), + TOBN(0x70CC9A50, 0x25ECE662), TOBN(0x81DC2CA7, 0xF29BA5DF), + TOBN(0xF7D36CC8, 0x8F68B076), TOBN(0xA757E304, 0x60E91A92), + TOBN(0x9BE67780, 0x87A2BC04), TOBN(0xA5FDF1D2, 0xBEECA565), + TOBN(0x922614C5, 0x5CCBBAA8), TOBN(0xE710800C, 0x6C030276), + TOBN(0x0FB3504C, 0x08EED4EB), TOBN(0x68B42D4B, 0xD958A3F5), + TOBN(0x80E9CFDB, 0x7C43FCF5), TOBN(0xD8467490, 0xBBBC2DCA), +}; + +/* dh1024_safe_prime_3 is offered as a parameter by several high-traffic sites, + * including mozilla.org, as of Jan 2015. */ +static const BN_ULONG dh1024_safe_prime_3[] = { + TOBN(0x349E721B, 0x671746AE), TOBN(0xD75E93B2, 0x258A0655), + TOBN(0x25592EB6, 0xD425E6FB), TOBN(0xBF7CDD9A, 0x0C46AB04), + TOBN(0x28968680, 0x0AD0BC99), TOBN(0xD0B7EB49, 0xF53907FB), + TOBN(0xEBC85C1D, 0x202EABB3), TOBN(0x364D8C71, 0x3129C693), + TOBN(0x2D46F195, 0x53728351), TOBN(0x8C76CC85, 0xDF326DD6), + TOBN(0x9188E24E, 0xF898B3F9), TOBN(0x2855DFD2, 0x95EFB13C), + TOBN(0x7B2241FE, 0x1F5DAC48), TOBN(0x99A13D9F, 0x117B6BF7), + TOBN(0x3A3468C7, 0x0F97CDDA), TOBN(0x74A8297B, 0xC9BBF5F7)}; + +/* dh1024_safe_prime_4 is hard-coded in Apache httpd 2.0, + * modules/ssl/ssl_engine_dh.c. */ +static const BN_ULONG dh1024_safe_prime_4[] = { + TOBN(0x0DD5C86B, 0x5085E21F), TOBN(0xD823C650, 0x871538DF), + TOBN(0x262E56A8, 0x125136F7), TOBN(0x839EB5DB, 0x974E9EF1), + TOBN(0x1B13A63C, 0xEA9BAD99), TOBN(0x3D76E05E, 0x6044CF02), + TOBN(0x1BAC9B5C, 0x611EBBBE), TOBN(0x4E5327DF, 0x3E371D79), + TOBN(0x061CBC05, 0x000E6EDD), TOBN(0x20129B48, 0x2F971F3C), + TOBN(0x3048D5A2, 0xA6EF09C4), TOBN(0xCBD523A6, 0xFA15A259), + TOBN(0x4A79A770, 0x2A206490), TOBN(0x51BB055E, 0x91B78182), + TOBN(0xBDD4798E, 0x7CF180C3), TOBN(0x495BE32C, 0xE6969D3D)}; + +static const BN_ULONG bn_two_data[] = {2}; + +#define STATIC_BIGNUM(x) \ + { \ + (BN_ULONG *) x, sizeof(x) / sizeof(BN_ULONG), \ + sizeof(x) / sizeof(BN_ULONG), 0, BN_FLG_STATIC_DATA \ + } + +struct standard_parameters { + BIGNUM p, q, g; +}; + +static const struct standard_parameters dh1024_160 = { + STATIC_BIGNUM(dh1024_160_p), + STATIC_BIGNUM(dh1024_160_q), + STATIC_BIGNUM(dh1024_160_g), +}; + +static const struct standard_parameters dh2048_224 = { + STATIC_BIGNUM(dh2048_224_p), + STATIC_BIGNUM(dh2048_224_q), + STATIC_BIGNUM(dh2048_224_g), +}; + +static const struct standard_parameters dh2048_256 = { + STATIC_BIGNUM(dh2048_256_p), + STATIC_BIGNUM(dh2048_256_q), + STATIC_BIGNUM(dh2048_256_g), +}; + +static const BIGNUM dh1024_safe_prime[] = { + STATIC_BIGNUM(dh1024_safe_prime_1), + STATIC_BIGNUM(dh1024_safe_prime_2), + STATIC_BIGNUM(dh1024_safe_prime_3), + STATIC_BIGNUM(dh1024_safe_prime_4) +}; + +BIGNUM bn_two = STATIC_BIGNUM(bn_two_data); + +static DH *get_standard_parameters(const struct standard_parameters *params, + const ENGINE *engine) { + DH *dh; + + dh = DH_new_method(engine); + if (!dh) { + return NULL; + } + + dh->p = BN_dup(¶ms->p); + dh->q = BN_dup(¶ms->q); + dh->g = BN_dup(¶ms->g); + if (!dh->p || !dh->q || !dh->g) { + DH_free(dh); + return NULL; + } + + return dh; +} + +DH *DH_get_1024_160(const ENGINE *engine) { + return get_standard_parameters(&dh1024_160, engine); +} + +DH *DH_get_2048_224(const ENGINE *engine) { + return get_standard_parameters(&dh2048_224, engine); +} + +DH *DH_get_2048_256(const ENGINE *engine) { + return get_standard_parameters(&dh2048_256, engine); +} + +void DH_check_standard_parameters(DH *dh) { + int i; + + if (dh->p == NULL || + dh->g == NULL || + BN_num_bytes(dh->p) != (1024 / 8) || + BN_cmp(dh->g, &bn_two) != 0) { + return; + } + + for (i = 0; i < sizeof(dh1024_safe_prime) / sizeof(dh1024_safe_prime[0]); + i++) { + if (BN_cmp(dh->p, &dh1024_safe_prime[i]) == 0) { + /* The well-known DH groups are known to have safe primes. In this case + * we can safely reduce the size of the private key. */ + dh->priv_length = 161; + break; + } + } +} diff --git a/TMessagesProj/jni/boringssl/crypto/digest/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/digest/CMakeLists.txt new file mode 100644 index 00000000..8c933925 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/digest/CMakeLists.txt @@ -0,0 +1,10 @@ +include_directories(. .. ../../include) + +add_library( + digest + + OBJECT + + digest.c + digests.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/digest/digest.c b/TMessagesProj/jni/boringssl/crypto/digest/digest.c new file mode 100644 index 00000000..7082c484 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/digest/digest.c @@ -0,0 +1,247 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + +#include "internal.h" + + +int EVP_MD_type(const EVP_MD *md) { return md->type; } + +uint32_t EVP_MD_flags(const EVP_MD *md) { return md->flags; } + +size_t EVP_MD_size(const EVP_MD *md) { return md->md_size; } + +size_t EVP_MD_block_size(const EVP_MD *md) { return md->block_size; } + + +void EVP_MD_CTX_init(EVP_MD_CTX *ctx) { memset(ctx, 0, sizeof(EVP_MD_CTX)); } + +EVP_MD_CTX *EVP_MD_CTX_create(void) { + EVP_MD_CTX *ctx = OPENSSL_malloc(sizeof(EVP_MD_CTX)); + + if (ctx) { + EVP_MD_CTX_init(ctx); + } + + return ctx; +} + +int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) { + if (ctx->digest && ctx->digest->ctx_size && ctx->md_data) { + OPENSSL_cleanse(ctx->md_data, ctx->digest->ctx_size); + OPENSSL_free(ctx->md_data); + } + + assert(ctx->pctx == NULL || ctx->pctx_ops != NULL); + if (ctx->pctx_ops) { + ctx->pctx_ops->free(ctx->pctx); + } + + EVP_MD_CTX_init(ctx); + + return 1; +} + +void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) { + if (!ctx) { + return; + } + + EVP_MD_CTX_cleanup(ctx); + OPENSSL_free(ctx); +} + +int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) { + uint8_t *tmp_buf = NULL; + + if (in == NULL || in->digest == NULL) { + OPENSSL_PUT_ERROR(DIGEST, DIGEST_R_INPUT_NOT_INITIALIZED); + return 0; + } + + if (out->digest == in->digest) { + /* |md_data| will be the correct size in this case so it's removed from + * |out| at this point so that |EVP_MD_CTX_cleanup| doesn't free it and + * then it's reused. */ + tmp_buf = out->md_data; + out->md_data = NULL; + } + + EVP_MD_CTX_cleanup(out); + memcpy(out, in, sizeof(EVP_MD_CTX)); + + if (in->md_data && in->digest->ctx_size) { + if (tmp_buf) { + out->md_data = tmp_buf; + } else { + out->md_data = OPENSSL_malloc(in->digest->ctx_size); + if (!out->md_data) { + OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE); + return 0; + } + } + memcpy(out->md_data, in->md_data, in->digest->ctx_size); + } + + assert(in->pctx == NULL || in->pctx_ops != NULL); + if (in->pctx && in->pctx_ops) { + out->pctx = in->pctx_ops->dup(in->pctx); + if (!out->pctx) { + EVP_MD_CTX_cleanup(out); + return 0; + } + } + + return 1; +} + +int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in) { + EVP_MD_CTX_init(out); + return EVP_MD_CTX_copy_ex(out, in); +} + +int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *engine) { + if (ctx->digest != type) { + if (ctx->digest && ctx->digest->ctx_size > 0) { + OPENSSL_free(ctx->md_data); + } + ctx->digest = type; + if (type->ctx_size > 0) { + ctx->md_data = OPENSSL_malloc(type->ctx_size); + if (ctx->md_data == NULL) { + OPENSSL_PUT_ERROR(DIGEST, ERR_R_MALLOC_FAILURE); + return 0; + } + } + } + + assert(ctx->pctx == NULL || ctx->pctx_ops != NULL); + + ctx->digest->init(ctx); + return 1; +} + +int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type) { + EVP_MD_CTX_init(ctx); + return EVP_DigestInit_ex(ctx, type, NULL); +} + +int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) { + ctx->digest->update(ctx, data, len); + return 1; +} + +int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, uint8_t *md_out, unsigned int *size) { + assert(ctx->digest->md_size <= EVP_MAX_MD_SIZE); + ctx->digest->final(ctx, md_out); + if (size != NULL) { + *size = ctx->digest->md_size; + } + OPENSSL_cleanse(ctx->md_data, ctx->digest->ctx_size); + return 1; +} + +int EVP_DigestFinal(EVP_MD_CTX *ctx, uint8_t *md, unsigned int *size) { + EVP_DigestFinal_ex(ctx, md, size); + EVP_MD_CTX_cleanup(ctx); + return 1; +} + +int EVP_Digest(const void *data, size_t count, uint8_t *out_md, + unsigned int *out_size, const EVP_MD *type, ENGINE *impl) { + EVP_MD_CTX ctx; + int ret; + + EVP_MD_CTX_init(&ctx); + ret = EVP_DigestInit_ex(&ctx, type, impl) && + EVP_DigestUpdate(&ctx, data, count) && + EVP_DigestFinal_ex(&ctx, out_md, out_size); + EVP_MD_CTX_cleanup(&ctx); + + return ret; +} + + +const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx) { + if (ctx == NULL) { + return NULL; + } + return ctx->digest; +} + +unsigned EVP_MD_CTX_size(const EVP_MD_CTX *ctx) { + return EVP_MD_size(EVP_MD_CTX_md(ctx)); +} + +unsigned EVP_MD_CTX_block_size(const EVP_MD_CTX *ctx) { + return EVP_MD_block_size(EVP_MD_CTX_md(ctx)); +} + +int EVP_MD_CTX_type(const EVP_MD_CTX *ctx) { + return EVP_MD_type(EVP_MD_CTX_md(ctx)); +} + +int EVP_add_digest(const EVP_MD *digest) { + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/digest/digests.c b/TMessagesProj/jni/boringssl/crypto/digest/digests.c new file mode 100644 index 00000000..9c0e3e1e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/digest/digests.c @@ -0,0 +1,298 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + +#include "internal.h" + +#if defined(NDEBUG) +#define CHECK(x) (void) (x) +#else +#define CHECK(x) assert(x) +#endif + +static void md5_init(EVP_MD_CTX *ctx) { + CHECK(MD5_Init(ctx->md_data)); +} + +static void md5_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + CHECK(MD5_Update(ctx->md_data, data, count)); +} + +static void md5_final(EVP_MD_CTX *ctx, uint8_t *out) { + CHECK(MD5_Final(out, ctx->md_data)); +} + +static const EVP_MD md5_md = { + NID_md5, MD5_DIGEST_LENGTH, 0 /* flags */, md5_init, + md5_update, md5_final, 64 /* block size */, sizeof(MD5_CTX), +}; + +const EVP_MD *EVP_md5(void) { return &md5_md; } + + +static void sha1_init(EVP_MD_CTX *ctx) { + CHECK(SHA1_Init(ctx->md_data)); +} + +static void sha1_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + CHECK(SHA1_Update(ctx->md_data, data, count)); +} + +static void sha1_final(EVP_MD_CTX *ctx, uint8_t *md) { + CHECK(SHA1_Final(md, ctx->md_data)); +} + +static const EVP_MD sha1_md = { + NID_sha1, SHA_DIGEST_LENGTH, 0 /* flags */, sha1_init, + sha1_update, sha1_final, 64 /* block size */, sizeof(SHA_CTX), +}; + +const EVP_MD *EVP_sha1(void) { return &sha1_md; } + + +static void sha224_init(EVP_MD_CTX *ctx) { + CHECK(SHA224_Init(ctx->md_data)); +} + +static void sha224_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + CHECK(SHA224_Update(ctx->md_data, data, count)); +} + +static void sha224_final(EVP_MD_CTX *ctx, uint8_t *md) { + CHECK(SHA224_Final(md, ctx->md_data)); +} + +static const EVP_MD sha224_md = { + NID_sha224, SHA224_DIGEST_LENGTH, 0 /* flags */, + sha224_init, sha224_update, sha224_final, + 64 /* block size */, sizeof(SHA256_CTX), +}; + +const EVP_MD *EVP_sha224(void) { return &sha224_md; } + + +static void sha256_init(EVP_MD_CTX *ctx) { + CHECK(SHA256_Init(ctx->md_data)); +} + +static void sha256_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + CHECK(SHA256_Update(ctx->md_data, data, count)); +} + +static void sha256_final(EVP_MD_CTX *ctx, uint8_t *md) { + CHECK(SHA256_Final(md, ctx->md_data)); +} + +static const EVP_MD sha256_md = { + NID_sha256, SHA256_DIGEST_LENGTH, 0 /* flags */, + sha256_init, sha256_update, sha256_final, + 64 /* block size */, sizeof(SHA256_CTX), +}; + +const EVP_MD *EVP_sha256(void) { return &sha256_md; } + + +static void sha384_init(EVP_MD_CTX *ctx) { + CHECK(SHA384_Init(ctx->md_data)); +} + +static void sha384_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + CHECK(SHA384_Update(ctx->md_data, data, count)); +} + +static void sha384_final(EVP_MD_CTX *ctx, uint8_t *md) { + CHECK(SHA384_Final(md, ctx->md_data)); +} + +static const EVP_MD sha384_md = { + NID_sha384, SHA384_DIGEST_LENGTH, 0 /* flags */, + sha384_init, sha384_update, sha384_final, + 128 /* block size */, sizeof(SHA512_CTX), +}; + +const EVP_MD *EVP_sha384(void) { return &sha384_md; } + + +static void sha512_init(EVP_MD_CTX *ctx) { + CHECK(SHA512_Init(ctx->md_data)); +} + +static void sha512_update(EVP_MD_CTX *ctx, const void *data, size_t count) { + CHECK(SHA512_Update(ctx->md_data, data, count)); +} + +static void sha512_final(EVP_MD_CTX *ctx, uint8_t *md) { + CHECK(SHA512_Final(md, ctx->md_data)); +} + +static const EVP_MD sha512_md = { + NID_sha512, SHA512_DIGEST_LENGTH, 0 /* flags */, + sha512_init, sha512_update, sha512_final, + 128 /* block size */, sizeof(SHA512_CTX), +}; + +const EVP_MD *EVP_sha512(void) { return &sha512_md; } + + +typedef struct { + MD5_CTX md5; + SHA_CTX sha1; +} MD5_SHA1_CTX; + +static void md5_sha1_init(EVP_MD_CTX *md_ctx) { + MD5_SHA1_CTX *ctx = md_ctx->md_data; + CHECK(MD5_Init(&ctx->md5) && SHA1_Init(&ctx->sha1)); +} + +static void md5_sha1_update(EVP_MD_CTX *md_ctx, const void *data, + size_t count) { + MD5_SHA1_CTX *ctx = md_ctx->md_data; + CHECK(MD5_Update(&ctx->md5, data, count) && + SHA1_Update(&ctx->sha1, data, count)); +} + +static void md5_sha1_final(EVP_MD_CTX *md_ctx, uint8_t *out) { + MD5_SHA1_CTX *ctx = md_ctx->md_data; + CHECK(MD5_Final(out, &ctx->md5) && + SHA1_Final(out + MD5_DIGEST_LENGTH, &ctx->sha1)); +} + +static const EVP_MD md5_sha1_md = { + NID_md5_sha1, + MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, + 0 /* flags */, + md5_sha1_init, + md5_sha1_update, + md5_sha1_final, + 64 /* block size */, + sizeof(MD5_SHA1_CTX), +}; + +const EVP_MD *EVP_md5_sha1(void) { return &md5_sha1_md; } + + +struct nid_to_digest { + int nid; + const EVP_MD* (*md_func)(void); + const char *short_name; + const char *long_name; +}; + +static const struct nid_to_digest nid_to_digest_mapping[] = { + { NID_md5, EVP_md5, SN_md5, LN_md5 }, + { NID_sha1, EVP_sha1, SN_sha1, LN_sha1 }, + { NID_sha224, EVP_sha224, SN_sha224, LN_sha224 }, + { NID_sha256, EVP_sha256, SN_sha256, LN_sha256 }, + { NID_sha384, EVP_sha384, SN_sha384, LN_sha384 }, + { NID_sha512, EVP_sha512, SN_sha512, LN_sha512 }, + { NID_md5_sha1, EVP_md5_sha1, SN_md5_sha1, LN_md5_sha1 }, + { NID_dsaWithSHA, EVP_sha1, SN_dsaWithSHA, LN_dsaWithSHA }, + { NID_dsaWithSHA1, EVP_sha1, SN_dsaWithSHA1, LN_dsaWithSHA1 }, + { NID_ecdsa_with_SHA1, EVP_sha1, SN_ecdsa_with_SHA1, NULL }, + { NID_md5WithRSAEncryption, EVP_md5, SN_md5WithRSAEncryption, + LN_md5WithRSAEncryption }, + { NID_sha1WithRSAEncryption, EVP_sha1, SN_sha1WithRSAEncryption, + LN_sha1WithRSAEncryption }, + { NID_sha224WithRSAEncryption, EVP_sha224, SN_sha224WithRSAEncryption, + LN_sha224WithRSAEncryption }, + { NID_sha256WithRSAEncryption, EVP_sha256, SN_sha256WithRSAEncryption, + LN_sha256WithRSAEncryption }, + { NID_sha384WithRSAEncryption, EVP_sha384, SN_sha384WithRSAEncryption, + LN_sha384WithRSAEncryption }, + { NID_sha512WithRSAEncryption, EVP_sha512, SN_sha512WithRSAEncryption, + LN_sha512WithRSAEncryption }, +}; + +const EVP_MD* EVP_get_digestbynid(int nid) { + unsigned i; + + for (i = 0; i < sizeof(nid_to_digest_mapping) / sizeof(struct nid_to_digest); + i++) { + if (nid_to_digest_mapping[i].nid == nid) { + return nid_to_digest_mapping[i].md_func(); + } + } + + return NULL; +} + +const EVP_MD* EVP_get_digestbyobj(const ASN1_OBJECT *obj) { + return EVP_get_digestbynid(OBJ_obj2nid(obj)); +} + +const EVP_MD *EVP_get_digestbyname(const char *name) { + unsigned i; + + for (i = 0; i < sizeof(nid_to_digest_mapping) / sizeof(struct nid_to_digest); + i++) { + const char *short_name = nid_to_digest_mapping[i].short_name; + const char *long_name = nid_to_digest_mapping[i].long_name; + if ((short_name && strcmp(short_name, name) == 0) || + (long_name && strcmp(long_name, name) == 0)) { + return nid_to_digest_mapping[i].md_func(); + } + } + + return NULL; +} diff --git a/TMessagesProj/jni/boringssl/crypto/digest/internal.h b/TMessagesProj/jni/boringssl/crypto/digest/internal.h new file mode 100644 index 00000000..e3d812ad --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/digest/internal.h @@ -0,0 +1,112 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DIGEST_INTERNAL_H +#define OPENSSL_HEADER_DIGEST_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +struct env_md_st { + /* type contains a NID identifing the digest function. (For example, + * NID_md5.) */ + int type; + + /* md_size contains the size, in bytes, of the resulting digest. */ + unsigned md_size; + + /* flags contains the OR of |EVP_MD_FLAG_*| values. */ + uint32_t flags; + + /* init initialises the state in |ctx->md_data|. */ + void (*init)(EVP_MD_CTX *ctx); + + /* update hashes |len| bytes of |data| into the state in |ctx->md_data|. */ + void (*update)(EVP_MD_CTX *ctx, const void *data, size_t count); + + /* final completes the hash and writes |md_size| bytes of digest to |out|. */ + void (*final)(EVP_MD_CTX *ctx, uint8_t *out); + + /* block_size contains the hash's native block size. */ + unsigned block_size; + + /* ctx_size contains the size, in bytes, of the state of the hash function. */ + unsigned ctx_size; +}; + +/* evp_md_pctx_ops contains function pointers to allow the |pctx| member of + * |EVP_MD_CTX| to be manipulated without breaking layering by calling EVP + * functions. */ +struct evp_md_pctx_ops { + /* free is called when an |EVP_MD_CTX| is being freed and the |pctx| also + * needs to be freed. */ + void (*free) (EVP_PKEY_CTX *pctx); + + /* dup is called when an |EVP_MD_CTX| is copied and so the |pctx| also needs + * to be copied. */ + EVP_PKEY_CTX* (*dup) (EVP_PKEY_CTX *pctx); +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_DIGEST_INTERNAL */ diff --git a/TMessagesProj/jni/boringssl/crypto/digest/md32_common.h b/TMessagesProj/jni/boringssl/crypto/digest/md32_common.h new file mode 100644 index 00000000..14607fba --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/digest/md32_common.h @@ -0,0 +1,350 @@ +/* ==================================================================== + * Copyright (c) 1999-2007 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== */ + +#ifndef OPENSSL_HEADER_MD32_COMMON_H +#define OPENSSL_HEADER_MD32_COMMON_H + +#include + + +#if defined(__cplusplus) +extern "C" { +#endif + +#define asm __asm__ + +/* This is a generic 32 bit "collector" for message digest algorithms. + * Whenever needed it collects input character stream into chunks of + * 32 bit values and invokes a block function that performs actual hash + * calculations. + * + * Porting guide. + * + * Obligatory macros: + * + * DATA_ORDER_IS_BIG_ENDIAN or DATA_ORDER_IS_LITTLE_ENDIAN + * this macro defines byte order of input stream. + * HASH_CBLOCK + * size of a unit chunk HASH_BLOCK operates on. + * HASH_LONG + * has to be at least 32 bit wide. + * HASH_CTX + * context structure that at least contains following + * members: + * typedef struct { + * ... + * HASH_LONG Nl,Nh; + * either { + * HASH_LONG data[HASH_LBLOCK]; + * unsigned char data[HASH_CBLOCK]; + * }; + * unsigned int num; + * ... + * } HASH_CTX; + * data[] vector is expected to be zeroed upon first call to + * HASH_UPDATE. + * HASH_UPDATE + * name of "Update" function, implemented here. + * HASH_TRANSFORM + * name of "Transform" function, implemented here. + * HASH_FINAL + * name of "Final" function, implemented here. + * HASH_BLOCK_DATA_ORDER + * name of "block" function capable of treating *unaligned* input + * message in original (data) byte order, implemented externally. + * HASH_MAKE_STRING + * macro convering context variables to an ASCII hash string. + * + * + */ + +#if !defined(DATA_ORDER_IS_BIG_ENDIAN) && !defined(DATA_ORDER_IS_LITTLE_ENDIAN) +#error "DATA_ORDER must be defined!" +#endif + +#ifndef HASH_CBLOCK +#error "HASH_CBLOCK must be defined!" +#endif +#ifndef HASH_LONG +#error "HASH_LONG must be defined!" +#endif +#ifndef HASH_CTX +#error "HASH_CTX must be defined!" +#endif + +#ifndef HASH_UPDATE +#error "HASH_UPDATE must be defined!" +#endif +#ifndef HASH_TRANSFORM +#error "HASH_TRANSFORM must be defined!" +#endif +#ifndef HASH_FINAL +#error "HASH_FINAL must be defined!" +#endif + +#ifndef HASH_BLOCK_DATA_ORDER +#error "HASH_BLOCK_DATA_ORDER must be defined!" +#endif + +/* + * Engage compiler specific rotate intrinsic function if available. + */ +#undef ROTATE +# if defined(_MSC_VER) +# define ROTATE(a,n) _lrotl(a,n) +# elif defined(__ICC) +# define ROTATE(a,n) _rotl(a,n) +# elif defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) + /* + * Some GNU C inline assembler templates. Note that these are + * rotates by *constant* number of bits! But that's exactly + * what we need here... + * + */ +# if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +# define ROTATE(a,n) ({ register uint32_t ret; \ + asm ( \ + "roll %1,%0" \ + : "=r"(ret) \ + : "I"(n), "0"((uint32_t)(a)) \ + : "cc"); \ + ret; \ + }) +# endif /* OPENSSL_X86 || OPENSSL_X86_64 */ +# endif /* COMPILER */ + +#ifndef ROTATE +#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n)))) +#endif + +#if defined(DATA_ORDER_IS_BIG_ENDIAN) + +#ifndef PEDANTIC +# if defined(__GNUC__) && __GNUC__>=2 && !defined(OPENSSL_NO_ASM) +# if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) + /* + * This gives ~30-40% performance improvement in SHA-256 compiled + * with gcc [on P4]. Well, first macro to be frank. We can pull + * this trick on x86* platforms only, because these CPUs can fetch + * unaligned data without raising an exception. + */ +# define HOST_c2l(c,l) ({ uint32_t r=*((const uint32_t *)(c)); \ + asm ("bswapl %0":"=r"(r):"0"(r)); \ + (c)+=4; (l)=r; }) +# define HOST_l2c(l,c) ({ uint32_t r=(l); \ + asm ("bswapl %0":"=r"(r):"0"(r)); \ + *((uint32_t *)(c))=r; (c)+=4; r; }) +# elif defined(__aarch64__) +# if defined(__BYTE_ORDER__) +# if defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__ +# define HOST_c2l(c,l) ({ uint32_t r; \ + asm ("rev %w0,%w1" \ + :"=r"(r) \ + :"r"(*((const uint32_t *)(c))));\ + (c)+=4; (l)=r; }) +# define HOST_l2c(l,c) ({ uint32_t r; \ + asm ("rev %w0,%w1" \ + :"=r"(r) \ + :"r"((uint32_t)(l))); \ + *((uint32_t *)(c))=r; (c)+=4; r; }) +# elif defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__==__ORDER_BIG_ENDIAN__ +# define HOST_c2l(c,l) (void)((l)=*((const uint32_t *)(c)), (c)+=4) +# define HOST_l2c(l,c) (*((uint32_t *)(c))=(l), (c)+=4, (l)) +# endif +# endif +# endif +# endif +#endif + +#ifndef HOST_c2l +#define HOST_c2l(c,l) (void)(l =(((uint32_t)(*((c)++)))<<24), \ + l|=(((uint32_t)(*((c)++)))<<16), \ + l|=(((uint32_t)(*((c)++)))<< 8), \ + l|=(((uint32_t)(*((c)++))) )) +#endif +#ifndef HOST_l2c +#define HOST_l2c(l,c) (*((c)++)=(uint8_t)(((l)>>24)&0xff), \ + *((c)++)=(uint8_t)(((l)>>16)&0xff), \ + *((c)++)=(uint8_t)(((l)>> 8)&0xff), \ + *((c)++)=(uint8_t)(((l) )&0xff), \ + l) +#endif + +#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN) + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) + /* See comment in DATA_ORDER_IS_BIG_ENDIAN section. */ +# define HOST_c2l(c,l) (void)((l)=*((const uint32_t *)(c)), (c)+=4) +# define HOST_l2c(l,c) (*((uint32_t *)(c))=(l), (c)+=4, l) +#endif + +#ifndef HOST_c2l +#define HOST_c2l(c,l) (void)(l =(((uint32_t)(*((c)++))) ), \ + l|=(((uint32_t)(*((c)++)))<< 8), \ + l|=(((uint32_t)(*((c)++)))<<16), \ + l|=(((uint32_t)(*((c)++)))<<24)) +#endif +#ifndef HOST_l2c +#define HOST_l2c(l,c) (*((c)++)=(uint8_t)(((l) )&0xff), \ + *((c)++)=(uint8_t)(((l)>> 8)&0xff), \ + *((c)++)=(uint8_t)(((l)>>16)&0xff), \ + *((c)++)=(uint8_t)(((l)>>24)&0xff), \ + l) +#endif + +#endif + +int HASH_UPDATE (HASH_CTX *c, const void *data_, size_t len) + { + const uint8_t *data=data_; + uint8_t *p; + HASH_LONG l; + size_t n; + + if (len==0) return 1; + + l=(c->Nl+(((HASH_LONG)len)<<3))&0xffffffffUL; + /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to + * Wei Dai for pointing it out. */ + if (l < c->Nl) /* overflow */ + c->Nh++; + c->Nh+=(HASH_LONG)(len>>29); /* might cause compiler warning on 16-bit */ + c->Nl=l; + + n = c->num; + if (n != 0) + { + p=(uint8_t *)c->data; + + if (len >= HASH_CBLOCK || len+n >= HASH_CBLOCK) + { + memcpy (p+n,data,HASH_CBLOCK-n); + HASH_BLOCK_DATA_ORDER (c,p,1); + n = HASH_CBLOCK-n; + data += n; + len -= n; + c->num = 0; + memset (p,0,HASH_CBLOCK); /* keep it zeroed */ + } + else + { + memcpy (p+n,data,len); + c->num += (unsigned int)len; + return 1; + } + } + + n = len/HASH_CBLOCK; + if (n > 0) + { + HASH_BLOCK_DATA_ORDER (c,data,n); + n *= HASH_CBLOCK; + data += n; + len -= n; + } + + if (len != 0) + { + p = (uint8_t *)c->data; + c->num = (unsigned int)len; + memcpy (p,data,len); + } + return 1; + } + + +void HASH_TRANSFORM (HASH_CTX *c, const uint8_t *data) + { + HASH_BLOCK_DATA_ORDER (c,data,1); + } + + +int HASH_FINAL (uint8_t *md, HASH_CTX *c) + { + uint8_t *p = (uint8_t *)c->data; + size_t n = c->num; + + p[n] = 0x80; /* there is always room for one */ + n++; + + if (n > (HASH_CBLOCK-8)) + { + memset (p+n,0,HASH_CBLOCK-n); + n=0; + HASH_BLOCK_DATA_ORDER (c,p,1); + } + memset (p+n,0,HASH_CBLOCK-8-n); + + p += HASH_CBLOCK-8; +#if defined(DATA_ORDER_IS_BIG_ENDIAN) + (void)HOST_l2c(c->Nh,p); + (void)HOST_l2c(c->Nl,p); +#elif defined(DATA_ORDER_IS_LITTLE_ENDIAN) + (void)HOST_l2c(c->Nl,p); + (void)HOST_l2c(c->Nh,p); +#endif + p -= HASH_CBLOCK; + HASH_BLOCK_DATA_ORDER (c,p,1); + c->num=0; + memset (p,0,HASH_CBLOCK); + +#ifndef HASH_MAKE_STRING +#error "HASH_MAKE_STRING must be defined!" +#else + HASH_MAKE_STRING(c,md); +#endif + + return 1; + } + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_MD32_COMMON_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/directory.h b/TMessagesProj/jni/boringssl/crypto/directory.h new file mode 100644 index 00000000..29123ea9 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/directory.h @@ -0,0 +1,66 @@ +/* Copied from Richard Levitte's (richard@levitte.org) LP library. All + * symbol names have been changed, with permission from the author. */ + +/* $LP: LPlib/source/LPdir.h,v 1.1 2004/06/14 08:56:04 _cvs_levitte Exp $ */ +/* + * Copyright (c) 2004, Richard Levitte + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS 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 REGENTS OR 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. + */ + +#ifndef OPENSSL_HEADER_DIRECTORY_H +#define OPENSSL_HEADER_DIRECTORY_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Directory functions abstract the O/S specific operations for opening and + * reading directories in the filesystem. */ + + +/* OPENSSL_dir_context_st is an opaque structure that represents an open + * directory and a position in that directory. */ +typedef struct OPENSSL_dir_context_st OPENSSL_DIR_CTX; + +/* OPENSSL_DIR_read reads a single filename from |ctx|. On the first call, + * |directory| must be given and |*ctx| must be NULL. Subsequent calls with the + * same |*ctx| will return subsequent file names until it returns NULL to + * indicate EOF. The strings returned reference a buffer internal to the + * |OPENSSL_DIR_CTX| and will be overridden by subsequent calls. */ +OPENSSL_EXPORT const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, + const char *directory); + +/* OPENSSL_DIR_end closes |*ctx|. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_DIRECTORY_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/directory_posix.c b/TMessagesProj/jni/boringssl/crypto/directory_posix.c new file mode 100644 index 00000000..b944b692 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/directory_posix.c @@ -0,0 +1,108 @@ +/* $LP: LPlib/source/LPdir_unix.c,v 1.11 2004/09/23 22:07:22 _cvs_levitte Exp $ */ +/* + * Copyright (c) 2004, Richard Levitte + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 201409 /* for readdir_r */ +#endif + +#include "directory.h" + + +#if !defined(OPENSSL_WINDOWS) + +#include +#include +#include +#include + +#if defined(OPENSSL_PNACL) +/* pnacl doesn't include readdir_r! So we do the best we can. */ +int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) { + errno = 0; + *result = readdir(dirp); + if (*result != NULL) { + return 0; + } + if (errno) { + return 1; + } + return 0; +} +#endif + +struct OPENSSL_dir_context_st { + DIR *dir; + struct dirent dirent; +}; + +const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, const char *directory) { + struct dirent *dirent; + + if (ctx == NULL || directory == NULL) { + errno = EINVAL; + return NULL; + } + + errno = 0; + if (*ctx == NULL) { + *ctx = malloc(sizeof(OPENSSL_DIR_CTX)); + if (*ctx == NULL) { + errno = ENOMEM; + return 0; + } + memset(*ctx, 0, sizeof(OPENSSL_DIR_CTX)); + + (*ctx)->dir = opendir(directory); + if ((*ctx)->dir == NULL) { + int save_errno = errno; /* Probably not needed, but I'm paranoid */ + free(*ctx); + *ctx = NULL; + errno = save_errno; + return 0; + } + } + + if (readdir_r((*ctx)->dir, &(*ctx)->dirent, &dirent) != 0 || + dirent == NULL) { + return 0; + } + + return (*ctx)->dirent.d_name; +} + +int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx) { + if (ctx != NULL && *ctx != NULL) { + int r = closedir((*ctx)->dir); + free(*ctx); + *ctx = NULL; + return r == 0; + } + + errno = EINVAL; + return 0; +} + +#endif /* !OPENSSL_WINDOWS */ diff --git a/TMessagesProj/jni/boringssl/crypto/directory_win.c b/TMessagesProj/jni/boringssl/crypto/directory_win.c new file mode 100644 index 00000000..4ebacf21 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/directory_win.c @@ -0,0 +1,144 @@ +/* $LP: LPlib/source/LPdir_win.c,v 1.10 2004/08/26 13:36:05 _cvs_levitte Exp $ */ +/* + * Copyright (c) 2004, Richard Levitte + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. + */ + +#include "directory.h" + + +#if defined(OPENSSL_WINDOWS) + +#pragma warning(push, 3) +#include +#pragma warning(pop) +#include +#include +#include + +#ifndef NAME_MAX +#define NAME_MAX 255 +#endif + +#include + + +struct OPENSSL_dir_context_st { + WIN32_FIND_DATA ctx; + HANDLE handle; + char entry_name[NAME_MAX + 1]; +}; + +const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, const char *directory) { + if (ctx == NULL || directory == NULL) { + errno = EINVAL; + return 0; + } + + errno = 0; + if (*ctx == NULL) { + *ctx = malloc(sizeof(OPENSSL_DIR_CTX)); + if (*ctx == NULL) { + errno = ENOMEM; + return 0; + } + memset(*ctx, 0, sizeof(OPENSSL_DIR_CTX)); + + if (sizeof(TCHAR) != sizeof(char)) { + TCHAR *wdir = NULL; + /* len_0 denotes string length *with* trailing 0 */ + size_t index = 0, len_0 = strlen(directory) + 1; + + wdir = (TCHAR *)malloc(len_0 * sizeof(TCHAR)); + if (wdir == NULL) { + free(*ctx); + *ctx = NULL; + errno = ENOMEM; + return 0; + } + + if (!MultiByteToWideChar(CP_ACP, 0, directory, len_0, (WCHAR *)wdir, + len_0)) { + for (index = 0; index < len_0; index++) { + wdir[index] = (TCHAR)directory[index]; + } + } + + (*ctx)->handle = FindFirstFile(wdir, &(*ctx)->ctx); + + free(wdir); + } else { + (*ctx)->handle = FindFirstFile((TCHAR *)directory, &(*ctx)->ctx); + } + + if ((*ctx)->handle == INVALID_HANDLE_VALUE) { + free(*ctx); + *ctx = NULL; + errno = EINVAL; + return 0; + } + } else { + if (FindNextFile((*ctx)->handle, &(*ctx)->ctx) == FALSE) { + return 0; + } + } + + if (sizeof(TCHAR) != sizeof(char)) { + TCHAR *wdir = (*ctx)->ctx.cFileName; + size_t index, len_0 = 0; + + while (wdir[len_0] && len_0 < (sizeof((*ctx)->entry_name) - 1)) { + len_0++; + } + len_0++; + + if (!WideCharToMultiByte(CP_ACP, 0, (WCHAR *)wdir, len_0, + (*ctx)->entry_name, sizeof((*ctx)->entry_name), + NULL, 0)) { + for (index = 0; index < len_0; index++) { + (*ctx)->entry_name[index] = (char)wdir[index]; + } + } + } else { + strncpy((*ctx)->entry_name, (const char *)(*ctx)->ctx.cFileName, + sizeof((*ctx)->entry_name) - 1); + } + + (*ctx)->entry_name[sizeof((*ctx)->entry_name) - 1] = '\0'; + + return (*ctx)->entry_name; +} + +int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx) { + if (ctx != NULL && *ctx != NULL) { + FindClose((*ctx)->handle); + free(*ctx); + *ctx = NULL; + return 1; + } + errno = EINVAL; + return 0; +} + +#endif /* OPENSSL_WINDOWS */ diff --git a/TMessagesProj/jni/boringssl/crypto/dsa/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/dsa/CMakeLists.txt new file mode 100644 index 00000000..6ef623a7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dsa/CMakeLists.txt @@ -0,0 +1,11 @@ +include_directories(. .. ../../include) + +add_library( + dsa + + OBJECT + + dsa.c + dsa_impl.c + dsa_asn1.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/dsa/dsa.c b/TMessagesProj/jni/boringssl/crypto/dsa/dsa.c new file mode 100644 index 00000000..3ff29c4f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dsa/dsa.c @@ -0,0 +1,348 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * The DSS routines are based on patches supplied by + * Steven Schoch . */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +extern const DSA_METHOD DSA_default_method; + +static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT; + +DSA *DSA_new(void) { return DSA_new_method(NULL); } + +DSA *DSA_new_method(const ENGINE *engine) { + DSA *dsa = (DSA *)OPENSSL_malloc(sizeof(DSA)); + if (dsa == NULL) { + OPENSSL_PUT_ERROR(DSA, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(dsa, 0, sizeof(DSA)); + + if (engine) { + dsa->meth = ENGINE_get_DSA_method(engine); + } + + if (dsa->meth == NULL) { + dsa->meth = (DSA_METHOD*) &DSA_default_method; + } + METHOD_ref(dsa->meth); + + dsa->write_params = 1; + dsa->references = 1; + + CRYPTO_MUTEX_init(&dsa->method_mont_p_lock); + + if (!CRYPTO_new_ex_data(&g_ex_data_class, dsa, &dsa->ex_data)) { + METHOD_unref(dsa->meth); + OPENSSL_free(dsa); + return NULL; + } + + if (dsa->meth->init && !dsa->meth->init(dsa)) { + CRYPTO_free_ex_data(&g_ex_data_class, dsa, &dsa->ex_data); + METHOD_unref(dsa->meth); + OPENSSL_free(dsa); + return NULL; + } + + return dsa; +} + +void DSA_free(DSA *dsa) { + if (dsa == NULL) { + return; + } + + if (!CRYPTO_refcount_dec_and_test_zero(&dsa->references)) { + return; + } + + if (dsa->meth->finish) { + dsa->meth->finish(dsa); + } + METHOD_unref(dsa->meth); + + CRYPTO_free_ex_data(&g_ex_data_class, dsa, &dsa->ex_data); + + BN_clear_free(dsa->p); + BN_clear_free(dsa->q); + BN_clear_free(dsa->g); + BN_clear_free(dsa->pub_key); + BN_clear_free(dsa->priv_key); + BN_clear_free(dsa->kinv); + BN_clear_free(dsa->r); + CRYPTO_MUTEX_cleanup(&dsa->method_mont_p_lock); + OPENSSL_free(dsa); +} + +int DSA_up_ref(DSA *dsa) { + CRYPTO_refcount_inc(&dsa->references); + return 1; +} + +int DSA_generate_parameters_ex(DSA *dsa, unsigned bits, const uint8_t *seed_in, + size_t seed_len, int *out_counter, + unsigned long *out_h, BN_GENCB *cb) { + if (dsa->meth->generate_parameters) { + return dsa->meth->generate_parameters(dsa, bits, seed_in, seed_len, + out_counter, out_h, cb); + } + return DSA_default_method.generate_parameters(dsa, bits, seed_in, seed_len, + out_counter, out_h, cb); +} + +int DSA_generate_key(DSA *dsa) { + if (dsa->meth->keygen) { + return dsa->meth->keygen(dsa); + } + return DSA_default_method.keygen(dsa); +} + +DSA_SIG *DSA_SIG_new(void) { + DSA_SIG *sig; + sig = OPENSSL_malloc(sizeof(DSA_SIG)); + if (!sig) { + return NULL; + } + sig->r = NULL; + sig->s = NULL; + return sig; +} + +void DSA_SIG_free(DSA_SIG *sig) { + if (!sig) { + return; + } + + BN_free(sig->r); + BN_free(sig->s); + OPENSSL_free(sig); +} + +DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, DSA *dsa) { + if (dsa->meth->sign) { + return dsa->meth->sign(digest, digest_len, dsa); + } + return DSA_default_method.sign(digest, digest_len, dsa); +} + +int DSA_do_verify(const uint8_t *digest, size_t digest_len, DSA_SIG *sig, + const DSA *dsa) { + int valid; + if (!DSA_do_check_signature(&valid, digest, digest_len, sig, dsa)) { + return -1; + } + return valid; +} + +int DSA_do_check_signature(int *out_valid, const uint8_t *digest, + size_t digest_len, DSA_SIG *sig, const DSA *dsa) { + if (dsa->meth->verify) { + return dsa->meth->verify(out_valid, digest, digest_len, sig, dsa); + } + + return DSA_default_method.verify(out_valid, digest, digest_len, sig, dsa); +} + +int DSA_sign(int type, const uint8_t *digest, size_t digest_len, + uint8_t *out_sig, unsigned int *out_siglen, DSA *dsa) { + DSA_SIG *s; + + s = DSA_do_sign(digest, digest_len, dsa); + if (s == NULL) { + *out_siglen = 0; + return 0; + } + + *out_siglen = i2d_DSA_SIG(s, &out_sig); + DSA_SIG_free(s); + return 1; +} + +int DSA_verify(int type, const uint8_t *digest, size_t digest_len, + const uint8_t *sig, size_t sig_len, const DSA *dsa) { + int valid; + if (!DSA_check_signature(&valid, digest, digest_len, sig, sig_len, dsa)) { + return -1; + } + return valid; +} + +int DSA_check_signature(int *out_valid, const uint8_t *digest, + size_t digest_len, const uint8_t *sig, size_t sig_len, + const DSA *dsa) { + DSA_SIG *s = NULL; + int ret = 0; + uint8_t *der = NULL; + + s = DSA_SIG_new(); + if (s == NULL) { + goto err; + } + + const uint8_t *sigp = sig; + if (d2i_DSA_SIG(&s, &sigp, sig_len) == NULL || sigp != sig + sig_len) { + goto err; + } + + /* Ensure that the signature uses DER and doesn't have trailing garbage. */ + int der_len = i2d_DSA_SIG(s, &der); + if (der_len < 0 || (size_t)der_len != sig_len || memcmp(sig, der, sig_len)) { + goto err; + } + + ret = DSA_do_check_signature(out_valid, digest, digest_len, s, dsa); + +err: + OPENSSL_free(der); + DSA_SIG_free(s); + return ret; +} + +int DSA_size(const DSA *dsa) { + int ret, i; + ASN1_INTEGER bs; + unsigned char buf[4]; /* 4 bytes looks really small. + However, i2d_ASN1_INTEGER() will not look + beyond the first byte, as long as the second + parameter is NULL. */ + + i = BN_num_bits(dsa->q); + bs.length = (i + 7) / 8; + bs.data = buf; + bs.type = V_ASN1_INTEGER; + /* If the top bit is set the asn1 encoding is 1 larger. */ + buf[0] = 0xff; + + i = i2d_ASN1_INTEGER(&bs, NULL); + i += i; /* r and s */ + ret = ASN1_object_size(1, i, V_ASN1_SEQUENCE); + return ret; +} + +int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx, BIGNUM **out_kinv, + BIGNUM **out_r) { + if (dsa->meth->sign_setup) { + return dsa->meth->sign_setup(dsa, ctx, out_kinv, out_r, NULL, 0); + } + + return DSA_default_method.sign_setup(dsa, ctx, out_kinv, out_r, NULL, 0); +} + +int DSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) { + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, new_func, + dup_func, free_func)) { + return -1; + } + return index; +} + +int DSA_set_ex_data(DSA *d, int idx, void *arg) { + return CRYPTO_set_ex_data(&d->ex_data, idx, arg); +} + +void *DSA_get_ex_data(const DSA *d, int idx) { + return CRYPTO_get_ex_data(&d->ex_data, idx); +} + +DH *DSA_dup_DH(const DSA *r) { + DH *ret = NULL; + + if (r == NULL) { + goto err; + } + ret = DH_new(); + if (ret == NULL) { + goto err; + } + if (r->q != NULL) { + ret->priv_length = BN_num_bits(r->q); + if ((ret->q = BN_dup(r->q)) == NULL) { + goto err; + } + } + if ((r->p != NULL && (ret->p = BN_dup(r->p)) == NULL) || + (r->g != NULL && (ret->g = BN_dup(r->g)) == NULL) || + (r->pub_key != NULL && (ret->pub_key = BN_dup(r->pub_key)) == NULL) || + (r->priv_key != NULL && (ret->priv_key = BN_dup(r->priv_key)) == NULL)) { + goto err; + } + + return ret; + +err: + DH_free(ret); + return NULL; +} diff --git a/TMessagesProj/jni/boringssl/crypto/dsa/dsa_asn1.c b/TMessagesProj/jni/boringssl/crypto/dsa/dsa_asn1.c new file mode 100644 index 00000000..b6b3fa4d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dsa/dsa_asn1.c @@ -0,0 +1,150 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. */ +/* ==================================================================== + * Copyright (c) 2000-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include +#include +#include + +#include "internal.h" + + +static int dsa_sig_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) { + if (operation != ASN1_OP_NEW_PRE) { + return 1; + } + + DSA_SIG *sig; + sig = OPENSSL_malloc(sizeof(DSA_SIG)); + if (!sig) { + OPENSSL_PUT_ERROR(DSA, ERR_R_MALLOC_FAILURE); + return 0; + } + + memset(sig, 0, sizeof(DSA_SIG)); + *pval = (ASN1_VALUE *)sig; + return 2; +} + +ASN1_SEQUENCE_cb(DSA_SIG, dsa_sig_cb) = { + ASN1_SIMPLE(DSA_SIG, r, CBIGNUM), + ASN1_SIMPLE(DSA_SIG, s, CBIGNUM)} ASN1_SEQUENCE_END_cb(DSA_SIG, DSA_SIG); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA_SIG, DSA_SIG, DSA_SIG); + + +static int dsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) { + switch (operation) { + case ASN1_OP_NEW_PRE: + *pval = (ASN1_VALUE *)DSA_new(); + if (*pval) { + return 2; + } + return 0; + + case ASN1_OP_FREE_PRE: + DSA_free((DSA *)*pval); + *pval = NULL; + return 2; + + default: + return 1; + } +} + +ASN1_SEQUENCE_cb(DSAPrivateKey, dsa_cb) = { + ASN1_SIMPLE(DSA, version, LONG), + ASN1_SIMPLE(DSA, p, BIGNUM), + ASN1_SIMPLE(DSA, q, BIGNUM), + ASN1_SIMPLE(DSA, g, BIGNUM), + ASN1_SIMPLE(DSA, pub_key, BIGNUM), + ASN1_SIMPLE(DSA, priv_key, BIGNUM)} ASN1_SEQUENCE_END_cb(DSA, + DSAPrivateKey); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAPrivateKey, DSAPrivateKey); + +ASN1_SEQUENCE_cb(DSAparams, dsa_cb) = { + ASN1_SIMPLE(DSA, p, BIGNUM), ASN1_SIMPLE(DSA, q, BIGNUM), + ASN1_SIMPLE(DSA, g, BIGNUM), } ASN1_SEQUENCE_END_cb(DSA, DSAparams); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAparams, DSAparams); + + +/* DSA public key is a bit trickier... its effectively a CHOICE type decided by + * a field called write_params which can either write out just the public key + * as an INTEGER or the parameters and public key in a SEQUENCE. */ + +ASN1_SEQUENCE(dsa_pub_internal) = { + ASN1_SIMPLE(DSA, pub_key, BIGNUM), + ASN1_SIMPLE(DSA, p, BIGNUM), + ASN1_SIMPLE(DSA, q, BIGNUM), + ASN1_SIMPLE(DSA, g, BIGNUM) +} ASN1_SEQUENCE_END_name(DSA, dsa_pub_internal); + +ASN1_CHOICE_cb(DSAPublicKey, dsa_cb) = { + ASN1_SIMPLE(DSA, pub_key, BIGNUM), + ASN1_EX_COMBINE(0, 0, dsa_pub_internal) +} ASN1_CHOICE_END_cb(DSA, DSAPublicKey, write_params); + +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(DSA, DSAPublicKey, DSAPublicKey); + +DSA *DSAparams_dup(const DSA *dsa) { + return ASN1_item_dup(ASN1_ITEM_rptr(DSAparams), (DSA*) dsa); +} diff --git a/TMessagesProj/jni/boringssl/crypto/dsa/dsa_impl.c b/TMessagesProj/jni/boringssl/crypto/dsa/dsa_impl.c new file mode 100644 index 00000000..e4984b4f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dsa/dsa_impl.c @@ -0,0 +1,750 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * The DSS routines are based on patches supplied by + * Steven Schoch . */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +#define OPENSSL_DSA_MAX_MODULUS_BITS 10000 + +/* Primality test according to FIPS PUB 186[-1], Appendix 2.1: 50 rounds of + * Rabin-Miller */ +#define DSS_prime_checks 50 + +static int sign_setup(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, + BIGNUM **rp, const uint8_t *digest, size_t digest_len) { + BN_CTX *ctx; + BIGNUM k, kq, *K, *kinv = NULL, *r = NULL; + int ret = 0; + + if (!dsa->p || !dsa->q || !dsa->g) { + OPENSSL_PUT_ERROR(DSA, DSA_R_MISSING_PARAMETERS); + return 0; + } + + BN_init(&k); + BN_init(&kq); + + ctx = ctx_in; + if (ctx == NULL) { + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + } + + r = BN_new(); + if (r == NULL) { + goto err; + } + + /* Get random k */ + do { + /* If possible, we'll include the private key and message digest in the k + * generation. The |digest| argument is only empty if |DSA_sign_setup| is + * being used. */ + int ok; + + if (digest_len > 0) { + ok = BN_generate_dsa_nonce(&k, dsa->q, dsa->priv_key, digest, digest_len, + ctx); + } else { + ok = BN_rand_range(&k, dsa->q); + } + if (!ok) { + goto err; + } + } while (BN_is_zero(&k)); + + BN_set_flags(&k, BN_FLG_CONSTTIME); + + if (BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p, + (CRYPTO_MUTEX *)&dsa->method_mont_p_lock, dsa->p, + ctx) == NULL) { + goto err; + } + + /* Compute r = (g^k mod p) mod q */ + if (!BN_copy(&kq, &k)) { + goto err; + } + + /* We do not want timing information to leak the length of k, + * so we compute g^k using an equivalent exponent of fixed length. + * + * (This is a kludge that we need because the BN_mod_exp_mont() + * does not let us specify the desired timing behaviour.) */ + + if (!BN_add(&kq, &kq, dsa->q)) { + goto err; + } + if (BN_num_bits(&kq) <= BN_num_bits(dsa->q) && !BN_add(&kq, &kq, dsa->q)) { + goto err; + } + + K = &kq; + + if (!BN_mod_exp_mont(r, dsa->g, K, dsa->p, ctx, dsa->method_mont_p)) { + goto err; + } + if (!BN_mod(r, r, dsa->q, ctx)) { + goto err; + } + + /* Compute part of 's = inv(k) (m + xr) mod q' */ + kinv = BN_mod_inverse(NULL, &k, dsa->q, ctx); + if (kinv == NULL) { + goto err; + } + + BN_clear_free(*kinvp); + *kinvp = kinv; + kinv = NULL; + BN_clear_free(*rp); + *rp = r; + ret = 1; + +err: + if (!ret) { + OPENSSL_PUT_ERROR(DSA, ERR_R_BN_LIB); + if (r != NULL) { + BN_clear_free(r); + } + } + + if (ctx_in == NULL) { + BN_CTX_free(ctx); + } + BN_clear_free(&k); + BN_clear_free(&kq); + return ret; +} + +static DSA_SIG *sign(const uint8_t *digest, size_t digest_len, DSA *dsa) { + BIGNUM *kinv = NULL, *r = NULL, *s = NULL; + BIGNUM m; + BIGNUM xr; + BN_CTX *ctx = NULL; + int reason = ERR_R_BN_LIB; + DSA_SIG *ret = NULL; + int noredo = 0; + + BN_init(&m); + BN_init(&xr); + + if (!dsa->p || !dsa->q || !dsa->g) { + reason = DSA_R_MISSING_PARAMETERS; + goto err; + } + + s = BN_new(); + if (s == NULL) { + goto err; + } + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + +redo: + if (dsa->kinv == NULL || dsa->r == NULL) { + if (!DSA_sign_setup(dsa, ctx, &kinv, &r)) { + goto err; + } + } else { + kinv = dsa->kinv; + dsa->kinv = NULL; + r = dsa->r; + dsa->r = NULL; + noredo = 1; + } + + if (digest_len > BN_num_bytes(dsa->q)) { + /* if the digest length is greater than the size of q use the + * BN_num_bits(dsa->q) leftmost bits of the digest, see + * fips 186-3, 4.2 */ + digest_len = BN_num_bytes(dsa->q); + } + + if (BN_bin2bn(digest, digest_len, &m) == NULL) { + goto err; + } + + /* Compute s = inv(k) (m + xr) mod q */ + if (!BN_mod_mul(&xr, dsa->priv_key, r, dsa->q, ctx)) { + goto err; /* s = xr */ + } + if (!BN_add(s, &xr, &m)) { + goto err; /* s = m + xr */ + } + if (BN_cmp(s, dsa->q) > 0) { + if (!BN_sub(s, s, dsa->q)) { + goto err; + } + } + if (!BN_mod_mul(s, s, kinv, dsa->q, ctx)) { + goto err; + } + + ret = DSA_SIG_new(); + if (ret == NULL) { + goto err; + } + /* Redo if r or s is zero as required by FIPS 186-3: this is + * very unlikely. */ + if (BN_is_zero(r) || BN_is_zero(s)) { + if (noredo) { + reason = DSA_R_NEED_NEW_SETUP_VALUES; + goto err; + } + goto redo; + } + ret->r = r; + ret->s = s; + +err: + if (!ret) { + OPENSSL_PUT_ERROR(DSA, reason); + BN_free(r); + BN_free(s); + } + BN_CTX_free(ctx); + BN_clear_free(&m); + BN_clear_free(&xr); + BN_clear_free(kinv); + + return ret; +} + +static int verify(int *out_valid, const uint8_t *dgst, size_t digest_len, + DSA_SIG *sig, const DSA *dsa) { + BN_CTX *ctx; + BIGNUM u1, u2, t1; + BN_MONT_CTX *mont = NULL; + int ret = 0; + unsigned i; + + *out_valid = 0; + + if (!dsa->p || !dsa->q || !dsa->g) { + OPENSSL_PUT_ERROR(DSA, DSA_R_MISSING_PARAMETERS); + return 0; + } + + i = BN_num_bits(dsa->q); + /* fips 186-3 allows only different sizes for q */ + if (i != 160 && i != 224 && i != 256) { + OPENSSL_PUT_ERROR(DSA, DSA_R_BAD_Q_VALUE); + return 0; + } + + if (BN_num_bits(dsa->p) > OPENSSL_DSA_MAX_MODULUS_BITS) { + OPENSSL_PUT_ERROR(DSA, DSA_R_MODULUS_TOO_LARGE); + return 0; + } + + BN_init(&u1); + BN_init(&u2); + BN_init(&t1); + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + + if (BN_is_zero(sig->r) || BN_is_negative(sig->r) || + BN_ucmp(sig->r, dsa->q) >= 0) { + ret = 1; + goto err; + } + if (BN_is_zero(sig->s) || BN_is_negative(sig->s) || + BN_ucmp(sig->s, dsa->q) >= 0) { + ret = 1; + goto err; + } + + /* Calculate W = inv(S) mod Q + * save W in u2 */ + if (BN_mod_inverse(&u2, sig->s, dsa->q, ctx) == NULL) { + goto err; + } + + /* save M in u1 */ + if (digest_len > (i >> 3)) { + /* if the digest length is greater than the size of q use the + * BN_num_bits(dsa->q) leftmost bits of the digest, see + * fips 186-3, 4.2 */ + digest_len = (i >> 3); + } + + if (BN_bin2bn(dgst, digest_len, &u1) == NULL) { + goto err; + } + + /* u1 = M * w mod q */ + if (!BN_mod_mul(&u1, &u1, &u2, dsa->q, ctx)) { + goto err; + } + + /* u2 = r * w mod q */ + if (!BN_mod_mul(&u2, sig->r, &u2, dsa->q, ctx)) { + goto err; + } + + mont = BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p, + (CRYPTO_MUTEX *)&dsa->method_mont_p_lock, + dsa->p, ctx); + if (!mont) { + goto err; + } + + if (!BN_mod_exp2_mont(&t1, dsa->g, &u1, dsa->pub_key, &u2, dsa->p, ctx, + mont)) { + goto err; + } + + /* BN_copy(&u1,&t1); */ + /* let u1 = u1 mod q */ + if (!BN_mod(&u1, &t1, dsa->q, ctx)) { + goto err; + } + + /* V is now in u1. If the signature is correct, it will be + * equal to R. */ + *out_valid = BN_ucmp(&u1, sig->r) == 0; + ret = 1; + +err: + if (ret != 1) { + OPENSSL_PUT_ERROR(DSA, ERR_R_BN_LIB); + } + BN_CTX_free(ctx); + BN_free(&u1); + BN_free(&u2); + BN_free(&t1); + + return ret; +} + +static int keygen(DSA *dsa) { + int ok = 0; + BN_CTX *ctx = NULL; + BIGNUM *pub_key = NULL, *priv_key = NULL; + BIGNUM prk; + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + + priv_key = dsa->priv_key; + if (priv_key == NULL) { + priv_key = BN_new(); + if (priv_key == NULL) { + goto err; + } + } + + do { + if (!BN_rand_range(priv_key, dsa->q)) { + goto err; + } + } while (BN_is_zero(priv_key)); + + pub_key = dsa->pub_key; + if (pub_key == NULL) { + pub_key = BN_new(); + if (pub_key == NULL) { + goto err; + } + } + + BN_init(&prk); + BN_with_flags(&prk, priv_key, BN_FLG_CONSTTIME); + + if (!BN_mod_exp(pub_key, dsa->g, &prk, dsa->p, ctx)) { + goto err; + } + + dsa->priv_key = priv_key; + dsa->pub_key = pub_key; + ok = 1; + +err: + if (dsa->pub_key == NULL) { + BN_free(pub_key); + } + if (dsa->priv_key == NULL) { + BN_free(priv_key); + } + BN_CTX_free(ctx); + + return ok; +} + +static int paramgen(DSA *ret, unsigned bits, const uint8_t *seed_in, + size_t seed_len, int *counter_ret, unsigned long *h_ret, + BN_GENCB *cb) { + int ok = 0; + unsigned char seed[SHA256_DIGEST_LENGTH]; + unsigned char md[SHA256_DIGEST_LENGTH]; + unsigned char buf[SHA256_DIGEST_LENGTH], buf2[SHA256_DIGEST_LENGTH]; + BIGNUM *r0, *W, *X, *c, *test; + BIGNUM *g = NULL, *q = NULL, *p = NULL; + BN_MONT_CTX *mont = NULL; + int k, n = 0, m = 0; + unsigned i; + int counter = 0; + int r = 0; + BN_CTX *ctx = NULL; + unsigned int h = 2; + unsigned qbits, qsize; + const EVP_MD *evpmd; + + if (bits >= 2048) { + qbits = 256; + evpmd = EVP_sha256(); + } else { + qbits = 160; + evpmd = EVP_sha1(); + } + qsize = qbits / 8; + + if (qsize != SHA_DIGEST_LENGTH && qsize != SHA224_DIGEST_LENGTH && + qsize != SHA256_DIGEST_LENGTH) { + /* invalid q size */ + return 0; + } + + if (bits < 512) { + bits = 512; + } + + bits = (bits + 63) / 64 * 64; + + /* NB: seed_len == 0 is special case: copy generated seed to + * seed_in if it is not NULL. */ + if (seed_len && (seed_len < (size_t)qsize)) { + seed_in = NULL; /* seed buffer too small -- ignore */ + } + if (seed_len > (size_t)qsize) { + seed_len = qsize; /* App. 2.2 of FIPS PUB 186 allows larger SEED, + * but our internal buffers are restricted to 160 bits*/ + } + if (seed_in != NULL) { + memcpy(seed, seed_in, seed_len); + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + + mont = BN_MONT_CTX_new(); + if (mont == NULL) { + goto err; + } + + r0 = BN_CTX_get(ctx); + g = BN_CTX_get(ctx); + W = BN_CTX_get(ctx); + q = BN_CTX_get(ctx); + X = BN_CTX_get(ctx); + c = BN_CTX_get(ctx); + p = BN_CTX_get(ctx); + test = BN_CTX_get(ctx); + + if (test == NULL || !BN_lshift(test, BN_value_one(), bits - 1)) { + goto err; + } + + for (;;) { + /* Find q. */ + for (;;) { + int seed_is_random; + + /* step 1 */ + if (!BN_GENCB_call(cb, 0, m++)) { + goto err; + } + + if (!seed_len) { + if (!RAND_bytes(seed, qsize)) { + goto err; + } + seed_is_random = 1; + } else { + seed_is_random = 0; + seed_len = 0; /* use random seed if 'seed_in' turns out to be bad*/ + } + memcpy(buf, seed, qsize); + memcpy(buf2, seed, qsize); + /* precompute "SEED + 1" for step 7: */ + for (i = qsize - 1; i < qsize; i--) { + buf[i]++; + if (buf[i] != 0) { + break; + } + } + + /* step 2 */ + if (!EVP_Digest(seed, qsize, md, NULL, evpmd, NULL) || + !EVP_Digest(buf, qsize, buf2, NULL, evpmd, NULL)) { + goto err; + } + for (i = 0; i < qsize; i++) { + md[i] ^= buf2[i]; + } + + /* step 3 */ + md[0] |= 0x80; + md[qsize - 1] |= 0x01; + if (!BN_bin2bn(md, qsize, q)) { + goto err; + } + + /* step 4 */ + r = BN_is_prime_fasttest_ex(q, DSS_prime_checks, ctx, seed_is_random, cb); + if (r > 0) { + break; + } + if (r != 0) { + goto err; + } + + /* do a callback call */ + /* step 5 */ + } + + if (!BN_GENCB_call(cb, 2, 0) || !BN_GENCB_call(cb, 3, 0)) { + goto err; + } + + /* step 6 */ + counter = 0; + /* "offset = 2" */ + + n = (bits - 1) / 160; + + for (;;) { + if ((counter != 0) && !BN_GENCB_call(cb, 0, counter)) { + goto err; + } + + /* step 7 */ + BN_zero(W); + /* now 'buf' contains "SEED + offset - 1" */ + for (k = 0; k <= n; k++) { + /* obtain "SEED + offset + k" by incrementing: */ + for (i = qsize - 1; i < qsize; i--) { + buf[i]++; + if (buf[i] != 0) { + break; + } + } + + if (!EVP_Digest(buf, qsize, md, NULL, evpmd, NULL)) { + goto err; + } + + /* step 8 */ + if (!BN_bin2bn(md, qsize, r0) || + !BN_lshift(r0, r0, (qsize << 3) * k) || + !BN_add(W, W, r0)) { + goto err; + } + } + + /* more of step 8 */ + if (!BN_mask_bits(W, bits - 1) || + !BN_copy(X, W) || + !BN_add(X, X, test)) { + goto err; + } + + /* step 9 */ + if (!BN_lshift1(r0, q) || + !BN_mod(c, X, r0, ctx) || + !BN_sub(r0, c, BN_value_one()) || + !BN_sub(p, X, r0)) { + goto err; + } + + /* step 10 */ + if (BN_cmp(p, test) >= 0) { + /* step 11 */ + r = BN_is_prime_fasttest_ex(p, DSS_prime_checks, ctx, 1, cb); + if (r > 0) { + goto end; /* found it */ + } + if (r != 0) { + goto err; + } + } + + /* step 13 */ + counter++; + /* "offset = offset + n + 1" */ + + /* step 14 */ + if (counter >= 4096) { + break; + } + } + } +end: + if (!BN_GENCB_call(cb, 2, 1)) { + goto err; + } + + /* We now need to generate g */ + /* Set r0=(p-1)/q */ + if (!BN_sub(test, p, BN_value_one()) || + !BN_div(r0, NULL, test, q, ctx)) { + goto err; + } + + if (!BN_set_word(test, h) || + !BN_MONT_CTX_set(mont, p, ctx)) { + goto err; + } + + for (;;) { + /* g=test^r0%p */ + if (!BN_mod_exp_mont(g, test, r0, p, ctx, mont)) { + goto err; + } + if (!BN_is_one(g)) { + break; + } + if (!BN_add(test, test, BN_value_one())) { + goto err; + } + h++; + } + + if (!BN_GENCB_call(cb, 3, 1)) { + goto err; + } + + ok = 1; + +err: + if (ok) { + BN_free(ret->p); + BN_free(ret->q); + BN_free(ret->g); + ret->p = BN_dup(p); + ret->q = BN_dup(q); + ret->g = BN_dup(g); + if (ret->p == NULL || ret->q == NULL || ret->g == NULL) { + ok = 0; + goto err; + } + if (counter_ret != NULL) { + *counter_ret = counter; + } + if (h_ret != NULL) { + *h_ret = h; + } + } + + if (ctx) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + + BN_MONT_CTX_free(mont); + + return ok; +} + +static int finish(DSA *dsa) { + BN_MONT_CTX_free(dsa->method_mont_p); + dsa->method_mont_p = NULL; + return 1; +} + +const struct dsa_method DSA_default_method = { + { + 0 /* references */, + 1 /* is_static */, + }, + NULL /* app_data */, + + NULL /* init */, + finish /* finish */, + + sign, + sign_setup, + verify, + + paramgen, + keygen, +}; diff --git a/TMessagesProj/jni/boringssl/crypto/dsa/internal.h b/TMessagesProj/jni/boringssl/crypto/dsa/internal.h new file mode 100644 index 00000000..ef991585 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/dsa/internal.h @@ -0,0 +1,78 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * The DSS routines are based on patches supplied by + * Steven Schoch . */ + +#ifndef OPENSSL_HEADER_DSA_INTERNAL_H +#define OPENSSL_HEADER_DSA_INTERNAL_H + +#include + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_DSA_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/ec/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/ec/CMakeLists.txt new file mode 100644 index 00000000..70c07f99 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/CMakeLists.txt @@ -0,0 +1,17 @@ +include_directories(. .. ../../include) + +add_library( + ec + + OBJECT + + ec.c + ec_asn1.c + ec_key.c + ec_montgomery.c + oct.c + p256-64.c + util-64.c + simple.c + wnaf.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/ec/ec.c b/TMessagesProj/jni/boringssl/crypto/ec/ec.c new file mode 100644 index 00000000..df0407c4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/ec.c @@ -0,0 +1,884 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#include + +#include + +#include +#include +#include +#include + +#include "internal.h" + + +static const struct curve_data P224 = { + "NIST P-224", + 28, + 1, + {/* p */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + /* a */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, + /* b */ + 0xB4, 0x05, 0x0A, 0x85, 0x0C, 0x04, 0xB3, 0xAB, 0xF5, 0x41, 0x32, 0x56, + 0x50, 0x44, 0xB0, 0xB7, 0xD7, 0xBF, 0xD8, 0xBA, 0x27, 0x0B, 0x39, 0x43, + 0x23, 0x55, 0xFF, 0xB4, + /* x */ + 0xB7, 0x0E, 0x0C, 0xBD, 0x6B, 0xB4, 0xBF, 0x7F, 0x32, 0x13, 0x90, 0xB9, + 0x4A, 0x03, 0xC1, 0xD3, 0x56, 0xC2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xD6, + 0x11, 0x5C, 0x1D, 0x21, + /* y */ + 0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6, + 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64, 0x44, 0xd5, 0x81, 0x99, + 0x85, 0x00, 0x7e, 0x34, + /* order */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x16, 0xA2, 0xE0, 0xB8, 0xF0, 0x3E, 0x13, 0xDD, 0x29, 0x45, + 0x5C, 0x5C, 0x2A, 0x3D, + }}; + +static const struct curve_data P256 = { + "NIST P-256", + 32, + 1, + {/* p */ + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /* a */ + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, + /* b */ + 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, 0xEB, 0xBD, 0x55, + 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6, + 0x3B, 0xCE, 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B, + /* x */ + 0x6B, 0x17, 0xD1, 0xF2, 0xE1, 0x2C, 0x42, 0x47, 0xF8, 0xBC, 0xE6, 0xE5, + 0x63, 0xA4, 0x40, 0xF2, 0x77, 0x03, 0x7D, 0x81, 0x2D, 0xEB, 0x33, 0xA0, + 0xF4, 0xA1, 0x39, 0x45, 0xD8, 0x98, 0xC2, 0x96, + /* y */ + 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, + 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, + 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5, + /* order */ + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17, 0x9E, 0x84, + 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x51}}; + +static const struct curve_data P384 = { + "NIST P-384", + 48, + 1, + {/* p */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + /* a */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, + /* b */ + 0xB3, 0x31, 0x2F, 0xA7, 0xE2, 0x3E, 0xE7, 0xE4, 0x98, 0x8E, 0x05, 0x6B, + 0xE3, 0xF8, 0x2D, 0x19, 0x18, 0x1D, 0x9C, 0x6E, 0xFE, 0x81, 0x41, 0x12, + 0x03, 0x14, 0x08, 0x8F, 0x50, 0x13, 0x87, 0x5A, 0xC6, 0x56, 0x39, 0x8D, + 0x8A, 0x2E, 0xD1, 0x9D, 0x2A, 0x85, 0xC8, 0xED, 0xD3, 0xEC, 0x2A, 0xEF, + /* x */ + 0xAA, 0x87, 0xCA, 0x22, 0xBE, 0x8B, 0x05, 0x37, 0x8E, 0xB1, 0xC7, 0x1E, + 0xF3, 0x20, 0xAD, 0x74, 0x6E, 0x1D, 0x3B, 0x62, 0x8B, 0xA7, 0x9B, 0x98, + 0x59, 0xF7, 0x41, 0xE0, 0x82, 0x54, 0x2A, 0x38, 0x55, 0x02, 0xF2, 0x5D, + 0xBF, 0x55, 0x29, 0x6C, 0x3A, 0x54, 0x5E, 0x38, 0x72, 0x76, 0x0A, 0xB7, + /* y */ + 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf, + 0x92, 0x92, 0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, + 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce, + 0x1d, 0x7e, 0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f, + /* order */ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC7, 0x63, 0x4D, 0x81, 0xF4, 0x37, 0x2D, 0xDF, 0x58, 0x1A, 0x0D, 0xB2, + 0x48, 0xB0, 0xA7, 0x7A, 0xEC, 0xEC, 0x19, 0x6A, 0xCC, 0xC5, 0x29, 0x73}}; + +static const struct curve_data P521 = { + "NIST P-521", + 66, + 1, + {/* p */ + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /* a */ + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, + /* b */ + 0x00, 0x51, 0x95, 0x3E, 0xB9, 0x61, 0x8E, 0x1C, 0x9A, 0x1F, 0x92, 0x9A, + 0x21, 0xA0, 0xB6, 0x85, 0x40, 0xEE, 0xA2, 0xDA, 0x72, 0x5B, 0x99, 0xB3, + 0x15, 0xF3, 0xB8, 0xB4, 0x89, 0x91, 0x8E, 0xF1, 0x09, 0xE1, 0x56, 0x19, + 0x39, 0x51, 0xEC, 0x7E, 0x93, 0x7B, 0x16, 0x52, 0xC0, 0xBD, 0x3B, 0xB1, + 0xBF, 0x07, 0x35, 0x73, 0xDF, 0x88, 0x3D, 0x2C, 0x34, 0xF1, 0xEF, 0x45, + 0x1F, 0xD4, 0x6B, 0x50, 0x3F, 0x00, + /* x */ + 0x00, 0xC6, 0x85, 0x8E, 0x06, 0xB7, 0x04, 0x04, 0xE9, 0xCD, 0x9E, 0x3E, + 0xCB, 0x66, 0x23, 0x95, 0xB4, 0x42, 0x9C, 0x64, 0x81, 0x39, 0x05, 0x3F, + 0xB5, 0x21, 0xF8, 0x28, 0xAF, 0x60, 0x6B, 0x4D, 0x3D, 0xBA, 0xA1, 0x4B, + 0x5E, 0x77, 0xEF, 0xE7, 0x59, 0x28, 0xFE, 0x1D, 0xC1, 0x27, 0xA2, 0xFF, + 0xA8, 0xDE, 0x33, 0x48, 0xB3, 0xC1, 0x85, 0x6A, 0x42, 0x9B, 0xF9, 0x7E, + 0x7E, 0x31, 0xC2, 0xE5, 0xBD, 0x66, + /* y */ + 0x01, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, 0xc0, 0x04, 0x5c, 0x8a, + 0x5f, 0xb4, 0x2c, 0x7d, 0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b, + 0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e, 0x66, 0x2c, 0x97, 0xee, + 0x72, 0x99, 0x5e, 0xf4, 0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad, + 0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72, 0xc2, 0x40, 0x88, 0xbe, + 0x94, 0x76, 0x9f, 0xd1, 0x66, 0x50, + /* order */ + 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x51, 0x86, + 0x87, 0x83, 0xBF, 0x2F, 0x96, 0x6B, 0x7F, 0xCC, 0x01, 0x48, 0xF7, 0x09, + 0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C, 0x47, 0xAE, 0xBB, 0x6F, + 0xB7, 0x1E, 0x91, 0x38, 0x64, 0x09}}; + +const struct built_in_curve OPENSSL_built_in_curves[] = { + {NID_secp224r1, &P224, 0}, + { + NID_X9_62_prime256v1, &P256, +#if defined(OPENSSL_64_BIT) && !defined(OPENSSL_WINDOWS) + EC_GFp_nistp256_method, +#else + 0, +#endif + }, + {NID_secp384r1, &P384, 0}, + {NID_secp521r1, &P521, 0}, + {NID_undef, 0, 0}, +}; + +EC_GROUP *ec_group_new(const EC_METHOD *meth) { + EC_GROUP *ret; + + if (meth == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_SLOT_FULL); + return NULL; + } + + if (meth->group_init == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return NULL; + } + + ret = OPENSSL_malloc(sizeof(EC_GROUP)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + memset(ret, 0, sizeof(EC_GROUP)); + + ret->meth = meth; + BN_init(&ret->order); + BN_init(&ret->cofactor); + + if (!meth->group_init(ret)) { + OPENSSL_free(ret); + return NULL; + } + + return ret; +} + +EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx) { + const EC_METHOD *meth = EC_GFp_mont_method(); + EC_GROUP *ret; + + ret = ec_group_new(meth); + if (ret == NULL) { + return NULL; + } + + if (ret->meth->group_set_curve == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (!ret->meth->group_set_curve(ret, p, a, b, ctx)) { + EC_GROUP_free(ret); + return NULL; + } + return ret; +} + +int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, + const BIGNUM *order, const BIGNUM *cofactor) { + if (group->curve_name != NID_undef) { + /* |EC_GROUP_set_generator| should only be used with |EC_GROUP|s returned + * by |EC_GROUP_new_curve_GFp|. */ + return 0; + } + + if (group->generator == NULL) { + group->generator = EC_POINT_new(group); + if (group->generator == NULL) { + return 0; + } + } + + if (!EC_POINT_copy(group->generator, generator)) { + return 0; + } + + if (order != NULL) { + if (!BN_copy(&group->order, order)) { + return 0; + } + } else { + BN_zero(&group->order); + } + + if (cofactor != NULL) { + if (!BN_copy(&group->cofactor, cofactor)) { + return 0; + } + } else { + BN_zero(&group->cofactor); + } + + return 1; +} + +static EC_GROUP *ec_group_new_from_data(const struct built_in_curve *curve) { + EC_GROUP *group = NULL; + EC_POINT *P = NULL; + BN_CTX *ctx = NULL; + BIGNUM *p = NULL, *a = NULL, *b = NULL, *x = NULL, *y = NULL; + int ok = 0; + unsigned param_len; + const EC_METHOD *meth; + const struct curve_data *data; + const uint8_t *params; + + if ((ctx = BN_CTX_new()) == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + data = curve->data; + param_len = data->param_len; + params = data->data; + + if (!(p = BN_bin2bn(params + 0 * param_len, param_len, NULL)) || + !(a = BN_bin2bn(params + 1 * param_len, param_len, NULL)) || + !(b = BN_bin2bn(params + 2 * param_len, param_len, NULL))) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + + if (curve->method != 0) { + meth = curve->method(); + if (((group = ec_group_new(meth)) == NULL) || + (!(group->meth->group_set_curve(group, p, a, b, ctx)))) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + } else { + if ((group = EC_GROUP_new_curve_GFp(p, a, b, ctx)) == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + } + + if ((P = EC_POINT_new(group)) == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + + if (!(x = BN_bin2bn(params + 3 * param_len, param_len, NULL)) || + !(y = BN_bin2bn(params + 4 * param_len, param_len, NULL))) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + + if (!EC_POINT_set_affine_coordinates_GFp(group, P, x, y, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + if (!BN_bin2bn(params + 5 * param_len, param_len, &group->order) || + !BN_set_word(&group->cofactor, (BN_ULONG)data->cofactor)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + + group->generator = P; + P = NULL; + ok = 1; + +err: + if (!ok) { + EC_GROUP_free(group); + group = NULL; + } + EC_POINT_free(P); + BN_CTX_free(ctx); + BN_free(p); + BN_free(a); + BN_free(b); + BN_free(x); + BN_free(y); + return group; +} + +EC_GROUP *EC_GROUP_new_by_curve_name(int nid) { + unsigned i; + const struct built_in_curve *curve; + EC_GROUP *ret = NULL; + + for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) { + curve = &OPENSSL_built_in_curves[i]; + if (curve->nid == nid) { + ret = ec_group_new_from_data(curve); + break; + } + } + + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP); + return NULL; + } + + ret->curve_name = nid; + return ret; +} + +void EC_GROUP_free(EC_GROUP *group) { + if (!group) { + return; + } + + if (group->meth->group_finish != 0) { + group->meth->group_finish(group); + } + + ec_pre_comp_free(group->pre_comp); + + EC_POINT_free(group->generator); + BN_free(&group->order); + BN_free(&group->cofactor); + + OPENSSL_free(group); +} + +int ec_group_copy(EC_GROUP *dest, const EC_GROUP *src) { + if (dest->meth->group_copy == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (dest->meth != src->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + if (dest == src) { + return 1; + } + + ec_pre_comp_free(dest->pre_comp); + dest->pre_comp = ec_pre_comp_dup(src->pre_comp); + + if (src->generator != NULL) { + if (dest->generator == NULL) { + dest->generator = EC_POINT_new(dest); + if (dest->generator == NULL) { + return 0; + } + } + if (!EC_POINT_copy(dest->generator, src->generator)) { + return 0; + } + } else { + /* src->generator == NULL */ + if (dest->generator != NULL) { + EC_POINT_clear_free(dest->generator); + dest->generator = NULL; + } + } + + if (!BN_copy(&dest->order, &src->order) || + !BN_copy(&dest->cofactor, &src->cofactor)) { + return 0; + } + + dest->curve_name = src->curve_name; + + return dest->meth->group_copy(dest, src); +} + +EC_GROUP *EC_GROUP_dup(const EC_GROUP *a) { + EC_GROUP *t = NULL; + int ok = 0; + + if (a == NULL) { + return NULL; + } + + t = ec_group_new(a->meth); + if (t == NULL) { + return NULL; + } + if (!ec_group_copy(t, a)) { + goto err; + } + + ok = 1; + +err: + if (!ok) { + EC_GROUP_free(t); + return NULL; + } else { + return t; + } +} + +int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ignored) { + return a->curve_name == NID_undef || + b->curve_name == NID_undef || + a->curve_name != b->curve_name; +} + +const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group) { + return group->generator; +} + +int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, BN_CTX *ctx) { + if (!BN_copy(order, &group->order)) { + return 0; + } + + return !BN_is_zero(order); +} + +int EC_GROUP_get_cofactor(const EC_GROUP *group, BIGNUM *cofactor, + BN_CTX *ctx) { + if (!BN_copy(cofactor, &group->cofactor)) { + return 0; + } + + return !BN_is_zero(&group->cofactor); +} + +int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *out_p, BIGNUM *out_a, + BIGNUM *out_b, BN_CTX *ctx) { + if (group->meth->group_get_curve == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + return group->meth->group_get_curve(group, out_p, out_a, out_b, ctx); +} + +int EC_GROUP_get_curve_name(const EC_GROUP *group) { return group->curve_name; } + +int EC_GROUP_get_degree(const EC_GROUP *group) { + if (group->meth->group_get_degree == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + return group->meth->group_get_degree(group); +} + +int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx) { + if (group->meth->mul == 0) { + /* use default */ + return ec_wNAF_precompute_mult(group, ctx); + } + + if (group->meth->precompute_mult != 0) { + return group->meth->precompute_mult(group, ctx); + } + + return 1; /* nothing to do, so report success */ +} + +int EC_GROUP_have_precompute_mult(const EC_GROUP *group) { + if (group->meth->mul == 0) { + /* use default */ + return ec_wNAF_have_precompute_mult(group); + } + + if (group->meth->have_precompute_mult != 0) { + return group->meth->have_precompute_mult(group); + } + + return 0; /* cannot tell whether precomputation has been performed */ +} + +EC_POINT *EC_POINT_new(const EC_GROUP *group) { + EC_POINT *ret; + + if (group == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + if (group->meth->point_init == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return NULL; + } + + ret = OPENSSL_malloc(sizeof *ret); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + + ret->meth = group->meth; + + if (!ret->meth->point_init(ret)) { + OPENSSL_free(ret); + return NULL; + } + + return ret; +} + +void EC_POINT_free(EC_POINT *point) { + if (!point) { + return; + } + + if (point->meth->point_finish != 0) { + point->meth->point_finish(point); + } + OPENSSL_free(point); +} + +void EC_POINT_clear_free(EC_POINT *point) { + if (!point) { + return; + } + + if (point->meth->point_clear_finish != 0) { + point->meth->point_clear_finish(point); + } else if (point->meth->point_finish != 0) { + point->meth->point_finish(point); + } + OPENSSL_cleanse(point, sizeof *point); + OPENSSL_free(point); +} + +int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src) { + if (dest->meth->point_copy == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (dest->meth != src->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + if (dest == src) { + return 1; + } + return dest->meth->point_copy(dest, src); +} + +EC_POINT *EC_POINT_dup(const EC_POINT *a, const EC_GROUP *group) { + EC_POINT *t; + int r; + + if (a == NULL) { + return NULL; + } + + t = EC_POINT_new(group); + if (t == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + r = EC_POINT_copy(t, a); + if (!r) { + EC_POINT_free(t); + return NULL; + } else { + return t; + } +} + +int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point) { + if (group->meth->point_set_to_infinity == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_set_to_infinity(group, point); +} + +int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) { + if (group->meth->is_at_infinity == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->is_at_infinity(group, point); +} + +int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point, + BN_CTX *ctx) { + if (group->meth->is_on_curve == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->is_on_curve(group, point, ctx); +} + +int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, + BN_CTX *ctx) { + if (group->meth->point_cmp == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return -1; + } + if ((group->meth != a->meth) || (a->meth != b->meth)) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return -1; + } + return group->meth->point_cmp(group, a, b, ctx); +} + +int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) { + if (group->meth->make_affine == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->make_affine(group, point, ctx); +} + +int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], + BN_CTX *ctx) { + size_t i; + + if (group->meth->points_make_affine == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + for (i = 0; i < num; i++) { + if (group->meth != points[i]->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + } + return group->meth->points_make_affine(group, num, points, ctx); +} + +int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, + const EC_POINT *point, BIGNUM *x, + BIGNUM *y, BN_CTX *ctx) { + if (group->meth->point_get_affine_coordinates == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_get_affine_coordinates(group, point, x, y, ctx); +} + +int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, + const BIGNUM *x, const BIGNUM *y, + BN_CTX *ctx) { + if (group->meth->point_set_affine_coordinates == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_set_affine_coordinates(group, point, x, y, ctx); +} + +int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, + const EC_POINT *b, BN_CTX *ctx) { + if (group->meth->add == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if ((group->meth != r->meth) || (r->meth != a->meth) || + (a->meth != b->meth)) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->add(group, r, a, b, ctx); +} + + +int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, + BN_CTX *ctx) { + if (group->meth->dbl == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if ((group->meth != r->meth) || (r->meth != a->meth)) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->dbl(group, r, a, ctx); +} + + +int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx) { + if (group->meth->invert == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != a->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->invert(group, a, ctx); +} + +int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, + const EC_POINT *point, const BIGNUM *p_scalar, BN_CTX *ctx) { + /* just a convenient interface to EC_POINTs_mul() */ + + const EC_POINT *points[1]; + const BIGNUM *scalars[1]; + + points[0] = point; + scalars[0] = p_scalar; + + return EC_POINTs_mul(group, r, g_scalar, (point != NULL && p_scalar != NULL), + points, scalars, ctx); +} + +int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, + size_t num, const EC_POINT *points[], const BIGNUM *scalars[], + BN_CTX *ctx) { + if (group->meth->mul == 0) { + /* use default. Warning, not constant-time. */ + return ec_wNAF_mul(group, r, scalar, num, points, scalars, ctx); + } + + return group->meth->mul(group, r, scalar, num, points, scalars, ctx); +} + +int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, + const BIGNUM *x, const BIGNUM *y, + const BIGNUM *z, BN_CTX *ctx) { + if (group->meth->point_set_Jprojective_coordinates_GFp == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + return group->meth->point_set_Jprojective_coordinates_GFp(group, point, x, y, + z, ctx); +} + +void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag) {} + +const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *group) { + return NULL; +} + +int EC_METHOD_get_field_type(const EC_METHOD *meth) { + return NID_X9_62_prime_field; +} + +void EC_GROUP_set_point_conversion_form(EC_GROUP *group, + point_conversion_form_t form) { + if (form != POINT_CONVERSION_UNCOMPRESSED) { + abort(); + } +} diff --git a/TMessagesProj/jni/boringssl/crypto/ec/ec_asn1.c b/TMessagesProj/jni/boringssl/crypto/ec/ec_asn1.c new file mode 100644 index 00000000..31d89448 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/ec_asn1.c @@ -0,0 +1,577 @@ +/* Written by Nils Larsch for the OpenSSL project. */ +/* ==================================================================== + * Copyright (c) 2000-2003 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +typedef struct x9_62_fieldid_st { + ASN1_OBJECT *fieldType; + union { + char *ptr; + /* NID_X9_62_prime_field */ + ASN1_INTEGER *prime; + /* anything else */ + ASN1_TYPE *other; + } p; +} X9_62_FIELDID; + +ASN1_ADB_TEMPLATE(fieldID_def) = ASN1_SIMPLE(X9_62_FIELDID, p.other, ASN1_ANY); + +ASN1_ADB(X9_62_FIELDID) = { + ADB_ENTRY(NID_X9_62_prime_field, ASN1_SIMPLE(X9_62_FIELDID, p.prime, ASN1_INTEGER)), +} ASN1_ADB_END(X9_62_FIELDID, 0, fieldType, 0, &fieldID_def_tt, NULL); + +ASN1_SEQUENCE(X9_62_FIELDID) = { + ASN1_SIMPLE(X9_62_FIELDID, fieldType, ASN1_OBJECT), + ASN1_ADB_OBJECT(X9_62_FIELDID) +} ASN1_SEQUENCE_END(X9_62_FIELDID); + +typedef struct x9_62_curve_st { + ASN1_OCTET_STRING *a; + ASN1_OCTET_STRING *b; + ASN1_BIT_STRING *seed; +} X9_62_CURVE; + +ASN1_SEQUENCE(X9_62_CURVE) = { + ASN1_SIMPLE(X9_62_CURVE, a, ASN1_OCTET_STRING), + ASN1_SIMPLE(X9_62_CURVE, b, ASN1_OCTET_STRING), + ASN1_OPT(X9_62_CURVE, seed, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END(X9_62_CURVE); + +typedef struct ec_parameters_st { + long version; + X9_62_FIELDID *fieldID; + X9_62_CURVE *curve; + ASN1_OCTET_STRING *base; + ASN1_INTEGER *order; + ASN1_INTEGER *cofactor; +} ECPARAMETERS; + +DECLARE_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS); + +ASN1_SEQUENCE(ECPARAMETERS) = { + ASN1_SIMPLE(ECPARAMETERS, version, LONG), + ASN1_SIMPLE(ECPARAMETERS, fieldID, X9_62_FIELDID), + ASN1_SIMPLE(ECPARAMETERS, curve, X9_62_CURVE), + ASN1_SIMPLE(ECPARAMETERS, base, ASN1_OCTET_STRING), + ASN1_SIMPLE(ECPARAMETERS, order, ASN1_INTEGER), + ASN1_OPT(ECPARAMETERS, cofactor, ASN1_INTEGER) +} ASN1_SEQUENCE_END(ECPARAMETERS); + +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(ECPARAMETERS); + +typedef struct ecpk_parameters_st { + int type; + union { + ASN1_OBJECT *named_curve; + ECPARAMETERS *parameters; + } value; +} ECPKPARAMETERS; + +/* SEC1 ECPrivateKey */ +typedef struct ec_privatekey_st { + long version; + ASN1_OCTET_STRING *privateKey; + ECPKPARAMETERS *parameters; + ASN1_BIT_STRING *publicKey; +} EC_PRIVATEKEY; + +DECLARE_ASN1_FUNCTIONS_const(ECPKPARAMETERS); +DECLARE_ASN1_ENCODE_FUNCTIONS_const(ECPKPARAMETERS, ECPKPARAMETERS); + +ASN1_CHOICE(ECPKPARAMETERS) = { + ASN1_SIMPLE(ECPKPARAMETERS, value.named_curve, ASN1_OBJECT), + ASN1_SIMPLE(ECPKPARAMETERS, value.parameters, ECPARAMETERS), +} ASN1_CHOICE_END(ECPKPARAMETERS); + +IMPLEMENT_ASN1_FUNCTIONS_const(ECPKPARAMETERS); + +DECLARE_ASN1_FUNCTIONS_const(EC_PRIVATEKEY); +DECLARE_ASN1_ENCODE_FUNCTIONS_const(EC_PRIVATEKEY, EC_PRIVATEKEY); + +ASN1_SEQUENCE(EC_PRIVATEKEY) = { + ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG), + ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING), + ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0), + ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1), +} ASN1_SEQUENCE_END(EC_PRIVATEKEY); + +IMPLEMENT_ASN1_FUNCTIONS_const(EC_PRIVATEKEY); + + +ECPKPARAMETERS *ec_asn1_group2pkparameters(const EC_GROUP *group, + ECPKPARAMETERS *params) { + int ok = 0, nid; + ECPKPARAMETERS *ret = params; + + if (ret == NULL) { + ret = ECPKPARAMETERS_new(); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + } else { + ASN1_OBJECT_free(ret->value.named_curve); + } + + /* use the ASN.1 OID to describe the the elliptic curve parameters. */ + nid = EC_GROUP_get_curve_name(group); + if (nid) { + ret->type = 0; + ret->value.named_curve = (ASN1_OBJECT*) OBJ_nid2obj(nid); + ok = ret->value.named_curve != NULL; + } + + if (!ok) { + ECPKPARAMETERS_free(ret); + return NULL; + } + + return ret; +} + +EC_GROUP *ec_asn1_pkparameters2group(const ECPKPARAMETERS *params) { + EC_GROUP *ret = NULL; + int nid = NID_undef; + + if (params == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS); + return NULL; + } + + if (params->type == 0) { + nid = OBJ_obj2nid(params->value.named_curve); + } else if (params->type == 1) { + /* We don't support arbitary curves so we attempt to recognise it from the + * group order. */ + const ECPARAMETERS *ecparams = params->value.parameters; + unsigned i; + const struct built_in_curve *curve; + + for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) { + curve = &OPENSSL_built_in_curves[i]; + const unsigned param_len = curve->data->param_len; + if (ecparams->order->length == param_len && + memcmp(ecparams->order->data, &curve->data->data[param_len * 5], + param_len) == 0) { + nid = curve->nid; + break; + } + } + } + + if (nid == NID_undef) { + OPENSSL_PUT_ERROR(EC, EC_R_NON_NAMED_CURVE); + return NULL; + } + + ret = EC_GROUP_new_by_curve_name(nid); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_EC_GROUP_NEW_BY_NAME_FAILURE); + return NULL; + } + + return ret; +} + +static EC_GROUP *d2i_ECPKParameters(EC_GROUP **groupp, const uint8_t **inp, + long len) { + EC_GROUP *group = NULL; + ECPKPARAMETERS *params = NULL; + + params = d2i_ECPKPARAMETERS(NULL, inp, len); + if (params == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_D2I_ECPKPARAMETERS_FAILURE); + ECPKPARAMETERS_free(params); + return NULL; + } + + group = ec_asn1_pkparameters2group(params); + if (group == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_PKPARAMETERS2GROUP_FAILURE); + ECPKPARAMETERS_free(params); + return NULL; + } + + if (groupp) { + EC_GROUP_free(*groupp); + *groupp = group; + } + + ECPKPARAMETERS_free(params); + return group; +} + +static int i2d_ECPKParameters(const EC_GROUP *group, uint8_t **outp) { + int ret = 0; + ECPKPARAMETERS *tmp = ec_asn1_group2pkparameters(group, NULL); + if (tmp == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_GROUP2PKPARAMETERS_FAILURE); + return 0; + } + ret = i2d_ECPKPARAMETERS(tmp, outp); + if (ret == 0) { + OPENSSL_PUT_ERROR(EC, EC_R_I2D_ECPKPARAMETERS_FAILURE); + ECPKPARAMETERS_free(tmp); + return 0; + } + ECPKPARAMETERS_free(tmp); + return ret; +} + +EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const uint8_t **in, long len) { + int ok = 0; + EC_KEY *ret = NULL; + EC_PRIVATEKEY *priv_key = NULL; + + priv_key = d2i_EC_PRIVATEKEY(NULL, in, len); + if (priv_key == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + return NULL; + } + + if (a == NULL || *a == NULL) { + ret = EC_KEY_new(); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + } else { + ret = *a; + } + + if (priv_key->parameters) { + EC_GROUP_free(ret->group); + ret->group = ec_asn1_pkparameters2group(priv_key->parameters); + } + + if (ret->group == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + + ret->version = priv_key->version; + + if (priv_key->privateKey) { + ret->priv_key = + BN_bin2bn(M_ASN1_STRING_data(priv_key->privateKey), + M_ASN1_STRING_length(priv_key->privateKey), ret->priv_key); + if (ret->priv_key == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + } else { + OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PRIVATE_KEY); + goto err; + } + + EC_POINT_free(ret->pub_key); + ret->pub_key = EC_POINT_new(ret->group); + if (ret->pub_key == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + + if (priv_key->publicKey) { + const uint8_t *pub_oct; + int pub_oct_len; + + pub_oct = M_ASN1_STRING_data(priv_key->publicKey); + pub_oct_len = M_ASN1_STRING_length(priv_key->publicKey); + /* The first byte (the point conversion form) must be present. */ + if (pub_oct_len <= 0) { + OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL); + goto err; + } + /* Save the point conversion form. */ + ret->conv_form = (point_conversion_form_t)(pub_oct[0] & ~0x01); + if (!EC_POINT_oct2point(ret->group, ret->pub_key, pub_oct, pub_oct_len, + NULL)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + } else { + if (!EC_POINT_mul(ret->group, ret->pub_key, ret->priv_key, NULL, NULL, + NULL)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + /* Remember the original private-key-only encoding. */ + ret->enc_flag |= EC_PKEY_NO_PUBKEY; + } + + if (a) { + *a = ret; + } + ok = 1; + +err: + if (!ok) { + if (a == NULL || *a != ret) { + EC_KEY_free(ret); + } + ret = NULL; + } + + EC_PRIVATEKEY_free(priv_key); + + return ret; +} + +int i2d_ECPrivateKey(const EC_KEY *key, uint8_t **outp) { + int ret = 0, ok = 0; + uint8_t *buffer = NULL; + size_t buf_len = 0, tmp_len; + EC_PRIVATEKEY *priv_key = NULL; + + if (key == NULL || key->group == NULL || key->priv_key == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + goto err; + } + + priv_key = EC_PRIVATEKEY_new(); + if (priv_key == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + priv_key->version = key->version; + + buf_len = BN_num_bytes(&key->group->order); + buffer = OPENSSL_malloc(buf_len); + if (buffer == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!BN_bn2bin_padded(buffer, buf_len, key->priv_key)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + + if (!M_ASN1_OCTET_STRING_set(priv_key->privateKey, buffer, buf_len)) { + OPENSSL_PUT_ERROR(EC, ERR_R_ASN1_LIB); + goto err; + } + + /* TODO(fork): replace this flexibility with key sensible default? */ + if (!(key->enc_flag & EC_PKEY_NO_PARAMETERS)) { + if ((priv_key->parameters = ec_asn1_group2pkparameters( + key->group, priv_key->parameters)) == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + } + + /* TODO(fork): replace this flexibility with key sensible default? */ + if (!(key->enc_flag & EC_PKEY_NO_PUBKEY) && key->pub_key != NULL) { + priv_key->publicKey = M_ASN1_BIT_STRING_new(); + if (priv_key->publicKey == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + tmp_len = EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, NULL, + 0, NULL); + + if (tmp_len > buf_len) { + uint8_t *tmp_buffer = OPENSSL_realloc(buffer, tmp_len); + if (!tmp_buffer) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + buffer = tmp_buffer; + buf_len = tmp_len; + } + + if (!EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, buffer, + buf_len, NULL)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + + priv_key->publicKey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); + priv_key->publicKey->flags |= ASN1_STRING_FLAG_BITS_LEFT; + if (!M_ASN1_BIT_STRING_set(priv_key->publicKey, buffer, buf_len)) { + OPENSSL_PUT_ERROR(EC, ERR_R_ASN1_LIB); + goto err; + } + } + + ret = i2d_EC_PRIVATEKEY(priv_key, outp); + if (ret == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + ok = 1; + +err: + OPENSSL_free(buffer); + EC_PRIVATEKEY_free(priv_key); + return (ok ? ret : 0); +} + +int i2d_ECParameters(const EC_KEY *key, uint8_t **outp) { + if (key == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + return i2d_ECPKParameters(key->group, outp); +} + +EC_KEY *d2i_ECParameters(EC_KEY **key, const uint8_t **inp, long len) { + EC_KEY *ret; + + if (inp == NULL || *inp == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + if (key == NULL || *key == NULL) { + ret = EC_KEY_new(); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + } else { + ret = *key; + } + + if (!d2i_ECPKParameters(&ret->group, inp, len)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + if (key == NULL || *key == NULL) { + EC_KEY_free(ret); + } + return NULL; + } + + if (key) { + *key = ret; + } + return ret; +} + +EC_KEY *o2i_ECPublicKey(EC_KEY **keyp, const uint8_t **inp, long len) { + EC_KEY *ret = NULL; + + if (keyp == NULL || *keyp == NULL || (*keyp)->group == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + ret = *keyp; + if (ret->pub_key == NULL && + (ret->pub_key = EC_POINT_new(ret->group)) == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return 0; + } + if (!EC_POINT_oct2point(ret->group, ret->pub_key, *inp, len, NULL)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + return 0; + } + /* save the point conversion form */ + ret->conv_form = (point_conversion_form_t)(*inp[0] & ~0x01); + *inp += len; + return ret; +} + +int i2o_ECPublicKey(const EC_KEY *key, uint8_t **outp) { + size_t buf_len = 0; + int new_buffer = 0; + + if (key == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + buf_len = EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, NULL, + 0, NULL); + + if (outp == NULL || buf_len == 0) { + /* out == NULL => just return the length of the octet string */ + return buf_len; + } + + if (*outp == NULL) { + *outp = OPENSSL_malloc(buf_len); + if (*outp == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return 0; + } + new_buffer = 1; + } + if (!EC_POINT_point2oct(key->group, key->pub_key, key->conv_form, *outp, + buf_len, NULL)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + if (new_buffer) { + OPENSSL_free(*outp); + *outp = NULL; + } + return 0; + } + + if (!new_buffer) { + *outp += buf_len; + } + return buf_len; +} diff --git a/TMessagesProj/jni/boringssl/crypto/ec/ec_key.c b/TMessagesProj/jni/boringssl/crypto/ec/ec_key.c new file mode 100644 index 00000000..0defa98a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/ec_key.c @@ -0,0 +1,503 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT; + +EC_KEY *EC_KEY_new(void) { return EC_KEY_new_method(NULL); } + +EC_KEY *EC_KEY_new_method(const ENGINE *engine) { + EC_KEY *ret = (EC_KEY *)OPENSSL_malloc(sizeof(EC_KEY)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(ret, 0, sizeof(EC_KEY)); + + if (engine) { + ret->ecdsa_meth = ENGINE_get_ECDSA_method(engine); + } + if (ret->ecdsa_meth) { + METHOD_ref(ret->ecdsa_meth); + } + + ret->version = 1; + ret->conv_form = POINT_CONVERSION_UNCOMPRESSED; + ret->references = 1; + + if (!CRYPTO_new_ex_data(&g_ex_data_class, ret, &ret->ex_data)) { + goto err1; + } + + if (ret->ecdsa_meth && ret->ecdsa_meth->init && !ret->ecdsa_meth->init(ret)) { + goto err2; + } + + return ret; + +err2: + CRYPTO_free_ex_data(&g_ex_data_class, ret, &ret->ex_data); +err1: + if (ret->ecdsa_meth) { + METHOD_unref(ret->ecdsa_meth); + } + OPENSSL_free(ret); + return NULL; +} + +EC_KEY *EC_KEY_new_by_curve_name(int nid) { + EC_KEY *ret = EC_KEY_new(); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return NULL; + } + ret->group = EC_GROUP_new_by_curve_name(nid); + if (ret->group == NULL) { + EC_KEY_free(ret); + return NULL; + } + return ret; +} + +void EC_KEY_free(EC_KEY *r) { + if (r == NULL) { + return; + } + + if (!CRYPTO_refcount_dec_and_test_zero(&r->references)) { + return; + } + + if (r->ecdsa_meth) { + if (r->ecdsa_meth->finish) { + r->ecdsa_meth->finish(r); + } + METHOD_unref(r->ecdsa_meth); + } + + EC_GROUP_free(r->group); + EC_POINT_free(r->pub_key); + BN_clear_free(r->priv_key); + + CRYPTO_free_ex_data(&g_ex_data_class, r, &r->ex_data); + + OPENSSL_cleanse((void *)r, sizeof(EC_KEY)); + OPENSSL_free(r); +} + +EC_KEY *EC_KEY_copy(EC_KEY *dest, const EC_KEY *src) { + if (dest == NULL || src == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + /* Copy the parameters. */ + if (src->group) { + /* TODO(fork): duplicating the group seems wasteful. */ + EC_GROUP_free(dest->group); + dest->group = EC_GROUP_dup(src->group); + if (dest->group == NULL) { + return NULL; + } + } + + /* Copy the public key. */ + if (src->pub_key && src->group) { + EC_POINT_free(dest->pub_key); + dest->pub_key = EC_POINT_dup(src->pub_key, src->group); + if (dest->pub_key == NULL) { + return NULL; + } + } + + /* copy the private key */ + if (src->priv_key) { + if (dest->priv_key == NULL) { + dest->priv_key = BN_new(); + if (dest->priv_key == NULL) { + return NULL; + } + } + if (!BN_copy(dest->priv_key, src->priv_key)) { + return NULL; + } + } + /* copy method/extra data */ + if (src->ecdsa_meth) { + METHOD_unref(dest->ecdsa_meth); + dest->ecdsa_meth = src->ecdsa_meth; + METHOD_ref(dest->ecdsa_meth); + } + CRYPTO_free_ex_data(&g_ex_data_class, dest, &dest->ex_data); + if (!CRYPTO_dup_ex_data(&g_ex_data_class, &dest->ex_data, + &src->ex_data)) { + return NULL; + } + + /* copy the rest */ + dest->enc_flag = src->enc_flag; + dest->conv_form = src->conv_form; + dest->version = src->version; + dest->flags = src->flags; + + return dest; +} + +EC_KEY *EC_KEY_dup(const EC_KEY *ec_key) { + EC_KEY *ret = EC_KEY_new(); + if (ret == NULL) { + return NULL; + } + if (EC_KEY_copy(ret, ec_key) == NULL) { + EC_KEY_free(ret); + return NULL; + } + return ret; +} + +int EC_KEY_up_ref(EC_KEY *r) { + CRYPTO_refcount_inc(&r->references); + return 1; +} + +int EC_KEY_is_opaque(const EC_KEY *key) { + return key->ecdsa_meth && (key->ecdsa_meth->flags & ECDSA_FLAG_OPAQUE); +} + +const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key) { return key->group; } + +int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group) { + EC_GROUP_free(key->group); + /* TODO(fork): duplicating the group seems wasteful but see + * |EC_KEY_set_conv_form|. */ + key->group = EC_GROUP_dup(group); + return (key->group == NULL) ? 0 : 1; +} + +const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key) { + return key->priv_key; +} + +int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key) { + BN_clear_free(key->priv_key); + key->priv_key = BN_dup(priv_key); + return (key->priv_key == NULL) ? 0 : 1; +} + +const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key) { + return key->pub_key; +} + +int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub_key) { + EC_POINT_free(key->pub_key); + key->pub_key = EC_POINT_dup(pub_key, key->group); + return (key->pub_key == NULL) ? 0 : 1; +} + +unsigned int EC_KEY_get_enc_flags(const EC_KEY *key) { return key->enc_flag; } + +void EC_KEY_set_enc_flags(EC_KEY *key, unsigned int flags) { + key->enc_flag = flags; +} + +point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key) { + return key->conv_form; +} + +void EC_KEY_set_conv_form(EC_KEY *key, point_conversion_form_t cform) { + key->conv_form = cform; +} + +int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx) { + if (key->group == NULL) { + return 0; + } + return EC_GROUP_precompute_mult(key->group, ctx); +} + +int EC_KEY_check_key(const EC_KEY *eckey) { + int ok = 0; + BN_CTX *ctx = NULL; + const BIGNUM *order = NULL; + EC_POINT *point = NULL; + + if (!eckey || !eckey->group || !eckey->pub_key) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (EC_POINT_is_at_infinity(eckey->group, eckey->pub_key)) { + OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY); + goto err; + } + + ctx = BN_CTX_new(); + point = EC_POINT_new(eckey->group); + + if (ctx == NULL || + point == NULL) { + goto err; + } + + /* testing whether the pub_key is on the elliptic curve */ + if (!EC_POINT_is_on_curve(eckey->group, eckey->pub_key, ctx)) { + OPENSSL_PUT_ERROR(EC, EC_R_POINT_IS_NOT_ON_CURVE); + goto err; + } + /* testing whether pub_key * order is the point at infinity */ + /* TODO(fork): can this be skipped if the cofactor is one or if we're about + * to check the private key, below? */ + order = &eckey->group->order; + if (BN_is_zero(order)) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_GROUP_ORDER); + goto err; + } + if (!EC_POINT_mul(eckey->group, point, NULL, eckey->pub_key, order, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + if (!EC_POINT_is_at_infinity(eckey->group, point)) { + OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER); + goto err; + } + /* in case the priv_key is present : + * check if generator * priv_key == pub_key + */ + if (eckey->priv_key) { + if (BN_cmp(eckey->priv_key, order) >= 0) { + OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER); + goto err; + } + if (!EC_POINT_mul(eckey->group, point, eckey->priv_key, NULL, NULL, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); + goto err; + } + if (EC_POINT_cmp(eckey->group, point, eckey->pub_key, ctx) != 0) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_PRIVATE_KEY); + goto err; + } + } + ok = 1; + +err: + BN_CTX_free(ctx); + EC_POINT_free(point); + return ok; +} + +int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, + BIGNUM *y) { + BN_CTX *ctx = NULL; + BIGNUM *tx, *ty; + EC_POINT *point = NULL; + int ok = 0; + + if (!key || !key->group || !x || !y) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + ctx = BN_CTX_new(); + point = EC_POINT_new(key->group); + + if (ctx == NULL || + point == NULL) { + goto err; + } + + tx = BN_CTX_get(ctx); + ty = BN_CTX_get(ctx); + + if (!EC_POINT_set_affine_coordinates_GFp(key->group, point, x, y, ctx) || + !EC_POINT_get_affine_coordinates_GFp(key->group, point, tx, ty, ctx)) { + goto err; + } + + /* Check if retrieved coordinates match originals: if not values + * are out of range. */ + if (BN_cmp(x, tx) || BN_cmp(y, ty)) { + OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE); + goto err; + } + + if (!EC_KEY_set_public_key(key, point)) { + goto err; + } + + if (EC_KEY_check_key(key) == 0) { + goto err; + } + + ok = 1; + +err: + BN_CTX_free(ctx); + EC_POINT_free(point); + return ok; +} + +int EC_KEY_generate_key(EC_KEY *eckey) { + int ok = 0; + BN_CTX *ctx = NULL; + BIGNUM *priv_key = NULL, *order = NULL; + EC_POINT *pub_key = NULL; + + if (!eckey || !eckey->group) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + order = BN_new(); + ctx = BN_CTX_new(); + + if (order == NULL || + ctx == NULL) { + goto err; + } + + if (eckey->priv_key == NULL) { + priv_key = BN_new(); + if (priv_key == NULL) { + goto err; + } + } else { + priv_key = eckey->priv_key; + } + + if (!EC_GROUP_get_order(eckey->group, order, ctx)) { + goto err; + } + + do { + if (!BN_rand_range(priv_key, order)) { + goto err; + } + } while (BN_is_zero(priv_key)); + + if (eckey->pub_key == NULL) { + pub_key = EC_POINT_new(eckey->group); + if (pub_key == NULL) { + goto err; + } + } else { + pub_key = eckey->pub_key; + } + + if (!EC_POINT_mul(eckey->group, pub_key, priv_key, NULL, NULL, ctx)) { + goto err; + } + + eckey->priv_key = priv_key; + eckey->pub_key = pub_key; + + ok = 1; + +err: + BN_free(order); + if (eckey->pub_key == NULL) { + EC_POINT_free(pub_key); + } + if (eckey->priv_key == NULL) { + BN_free(priv_key); + } + BN_CTX_free(ctx); + return ok; +} + +int EC_KEY_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func) { + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, new_func, + dup_func, free_func)) { + return -1; + } + return index; +} + +int EC_KEY_set_ex_data(EC_KEY *d, int idx, void *arg) { + return CRYPTO_set_ex_data(&d->ex_data, idx, arg); +} + +void *EC_KEY_get_ex_data(const EC_KEY *d, int idx) { + return CRYPTO_get_ex_data(&d->ex_data, idx); +} + +void EC_KEY_set_asn1_flag(EC_KEY *key, int flag) {} diff --git a/TMessagesProj/jni/boringssl/crypto/ec/ec_montgomery.c b/TMessagesProj/jni/boringssl/crypto/ec/ec_montgomery.c new file mode 100644 index 00000000..b897000b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/ec_montgomery.c @@ -0,0 +1,283 @@ +/* Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#include + +#include +#include +#include + +#include "internal.h" + + +const EC_METHOD *EC_GFp_mont_method(void) { + static const EC_METHOD ret = {EC_FLAGS_DEFAULT_OCT, + ec_GFp_mont_group_init, + ec_GFp_mont_group_finish, + ec_GFp_mont_group_clear_finish, + ec_GFp_mont_group_copy, + ec_GFp_mont_group_set_curve, + ec_GFp_simple_group_get_curve, + ec_GFp_simple_group_get_degree, + ec_GFp_simple_group_check_discriminant, + ec_GFp_simple_point_init, + ec_GFp_simple_point_finish, + ec_GFp_simple_point_clear_finish, + ec_GFp_simple_point_copy, + ec_GFp_simple_point_set_to_infinity, + ec_GFp_simple_set_Jprojective_coordinates_GFp, + ec_GFp_simple_get_Jprojective_coordinates_GFp, + ec_GFp_simple_point_set_affine_coordinates, + ec_GFp_simple_point_get_affine_coordinates, + 0, + 0, + 0, + ec_GFp_simple_add, + ec_GFp_simple_dbl, + ec_GFp_simple_invert, + ec_GFp_simple_is_at_infinity, + ec_GFp_simple_is_on_curve, + ec_GFp_simple_cmp, + ec_GFp_simple_make_affine, + ec_GFp_simple_points_make_affine, + 0 /* mul */, + 0 /* precompute_mult */, + 0 /* have_precompute_mult */, + ec_GFp_mont_field_mul, + ec_GFp_mont_field_sqr, + 0 /* field_div */, + ec_GFp_mont_field_encode, + ec_GFp_mont_field_decode, + ec_GFp_mont_field_set_to_one}; + + return &ret; +} + +int ec_GFp_mont_group_init(EC_GROUP *group) { + int ok; + + ok = ec_GFp_simple_group_init(group); + group->mont = NULL; + group->one = NULL; + return ok; +} + +void ec_GFp_mont_group_finish(EC_GROUP *group) { + BN_MONT_CTX_free(group->mont); + group->mont = NULL; + BN_free(group->one); + group->one = NULL; + ec_GFp_simple_group_finish(group); +} + +void ec_GFp_mont_group_clear_finish(EC_GROUP *group) { + BN_MONT_CTX_free(group->mont); + group->mont = NULL; + BN_clear_free(group->one); + group->one = NULL; + ec_GFp_simple_group_clear_finish(group); +} + +int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) { + BN_MONT_CTX_free(dest->mont); + dest->mont = NULL; + BN_clear_free(dest->one); + dest->one = NULL; + + if (!ec_GFp_simple_group_copy(dest, src)) { + return 0; + } + + if (src->mont != NULL) { + dest->mont = BN_MONT_CTX_new(); + if (dest->mont == NULL) { + return 0; + } + if (!BN_MONT_CTX_copy(dest->mont, src->mont)) { + goto err; + } + } + if (src->one != NULL) { + dest->one = BN_dup(src->one); + if (dest->one == NULL) { + goto err; + } + } + + return 1; + +err: + BN_MONT_CTX_free(dest->mont); + dest->mont = NULL; + return 0; +} + +int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p, + const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + BN_MONT_CTX *mont = NULL; + BIGNUM *one = NULL; + int ret = 0; + + BN_MONT_CTX_free(group->mont); + group->mont = NULL; + BN_free(group->one); + group->one = NULL; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + mont = BN_MONT_CTX_new(); + if (mont == NULL) { + goto err; + } + if (!BN_MONT_CTX_set(mont, p, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + one = BN_new(); + if (one == NULL || !BN_to_montgomery(one, BN_value_one(), mont, ctx)) { + goto err; + } + + group->mont = mont; + mont = NULL; + group->one = one; + one = NULL; + + ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx); + + if (!ret) { + BN_MONT_CTX_free(group->mont); + group->mont = NULL; + BN_free(group->one); + group->one = NULL; + } + +err: + BN_CTX_free(new_ctx); + BN_MONT_CTX_free(mont); + BN_free(one); + return ret; +} + +int ec_GFp_mont_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx) { + if (group->mont == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED); + return 0; + } + + return BN_mod_mul_montgomery(r, a, b, group->mont, ctx); +} + +int ec_GFp_mont_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, + BN_CTX *ctx) { + if (group->mont == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED); + return 0; + } + + return BN_mod_mul_montgomery(r, a, a, group->mont, ctx); +} + +int ec_GFp_mont_field_encode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, + BN_CTX *ctx) { + if (group->mont == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED); + return 0; + } + + return BN_to_montgomery(r, a, group->mont, ctx); +} + +int ec_GFp_mont_field_decode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, + BN_CTX *ctx) { + if (group->mont == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED); + return 0; + } + + return BN_from_montgomery(r, a, group->mont, ctx); +} + +int ec_GFp_mont_field_set_to_one(const EC_GROUP *group, BIGNUM *r, + BN_CTX *ctx) { + if (group->one == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_NOT_INITIALIZED); + return 0; + } + + if (!BN_copy(r, group->one)) { + return 0; + } + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/ec/example_mul.c b/TMessagesProj/jni/boringssl/crypto/ec/example_mul.c new file mode 100644 index 00000000..ebb724fa --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/example_mul.c @@ -0,0 +1,133 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#include + +#include +#include +#include +#include + + +int example_EC_POINT_mul(void) { + /* This example ensures that 10×∞ + G = G, in P-256. */ + EC_GROUP *group = NULL; + EC_POINT *p = NULL, *result = NULL; + BIGNUM *n = NULL; + int ret = 0; + const EC_POINT *generator; + + group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1); + p = EC_POINT_new(group); + result = EC_POINT_new(group); + n = BN_new(); + + if (p == NULL || + result == NULL || + group == NULL || + n == NULL || + !EC_POINT_set_to_infinity(group, p) || + !BN_set_word(n, 10)) { + goto err; + } + + /* First check that 10×∞ = ∞. */ + if (!EC_POINT_mul(group, result, NULL, p, n, NULL) || + !EC_POINT_is_at_infinity(group, result)) { + goto err; + } + + generator = EC_GROUP_get0_generator(group); + + /* Now check that 10×∞ + G = G. */ + if (!EC_POINT_mul(group, result, BN_value_one(), p, n, NULL) || + EC_POINT_cmp(group, result, generator, NULL) != 0) { + goto err; + } + + ret = 1; + +err: + BN_free(n); + EC_POINT_free(result); + EC_POINT_free(p); + EC_GROUP_free(group); + + return ret; +} + +int main(void) { + CRYPTO_library_init(); + + if (!example_EC_POINT_mul()) { + fprintf(stderr, "failed\n"); + return 1; + } + + printf("PASS\n"); + return 0; +} diff --git a/TMessagesProj/jni/boringssl/crypto/ec/internal.h b/TMessagesProj/jni/boringssl/crypto/ec/internal.h new file mode 100644 index 00000000..71062c16 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/internal.h @@ -0,0 +1,372 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#ifndef OPENSSL_HEADER_EC_INTERNAL_H +#define OPENSSL_HEADER_EC_INTERNAL_H + +#include + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Use default functions for poin2oct, oct2point and compressed coordinates */ +#define EC_FLAGS_DEFAULT_OCT 0x1 + +struct ec_method_st { + /* Various method flags */ + int flags; + + /* used by EC_GROUP_new, EC_GROUP_free, EC_GROUP_clear_free, EC_GROUP_copy: */ + int (*group_init)(EC_GROUP *); + void (*group_finish)(EC_GROUP *); + void (*group_clear_finish)(EC_GROUP *); + int (*group_copy)(EC_GROUP *, const EC_GROUP *); + + /* used by EC_GROUP_set_curve_GFp, EC_GROUP_get_curve_GFp, */ + /* EC_GROUP_set_curve_GF2m, and EC_GROUP_get_curve_GF2m: */ + int (*group_set_curve)(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, + const BIGNUM *b, BN_CTX *); + int (*group_get_curve)(const EC_GROUP *, BIGNUM *p, BIGNUM *a, BIGNUM *b, + BN_CTX *); + + /* used by EC_GROUP_get_degree: */ + int (*group_get_degree)(const EC_GROUP *); + + /* used by EC_GROUP_check: */ + int (*group_check_discriminant)(const EC_GROUP *, BN_CTX *); + + /* used by EC_POINT_new, EC_POINT_free, EC_POINT_clear_free, EC_POINT_copy: */ + int (*point_init)(EC_POINT *); + void (*point_finish)(EC_POINT *); + void (*point_clear_finish)(EC_POINT *); + int (*point_copy)(EC_POINT *, const EC_POINT *); + + /* used by EC_POINT_set_to_infinity, + * EC_POINT_set_Jprojective_coordinates_GFp, + * EC_POINT_get_Jprojective_coordinates_GFp, + * EC_POINT_set_affine_coordinates_GFp, ..._GF2m, + * EC_POINT_get_affine_coordinates_GFp, ..._GF2m, + * EC_POINT_set_compressed_coordinates_GFp, ..._GF2m: + */ + int (*point_set_to_infinity)(const EC_GROUP *, EC_POINT *); + int (*point_set_Jprojective_coordinates_GFp)(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, const BIGNUM *y, + const BIGNUM *z, BN_CTX *); + int (*point_get_Jprojective_coordinates_GFp)(const EC_GROUP *, + const EC_POINT *, BIGNUM *x, + BIGNUM *y, BIGNUM *z, BN_CTX *); + int (*point_set_affine_coordinates)(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, const BIGNUM *y, + BN_CTX *); + int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_POINT *, + BIGNUM *x, BIGNUM *y, BN_CTX *); + int (*point_set_compressed_coordinates)(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, int y_bit, BN_CTX *); + + /* used by EC_POINT_point2oct, EC_POINT_oct2point: */ + size_t (*point2oct)(const EC_GROUP *, const EC_POINT *, + point_conversion_form_t form, unsigned char *buf, + size_t len, BN_CTX *); + int (*oct2point)(const EC_GROUP *, EC_POINT *, const unsigned char *buf, + size_t len, BN_CTX *); + + /* used by EC_POINT_add, EC_POINT_dbl, ECP_POINT_invert: */ + int (*add)(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, + const EC_POINT *b, BN_CTX *); + int (*dbl)(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, BN_CTX *); + int (*invert)(const EC_GROUP *, EC_POINT *, BN_CTX *); + + /* used by EC_POINT_is_at_infinity, EC_POINT_is_on_curve, EC_POINT_cmp: */ + int (*is_at_infinity)(const EC_GROUP *, const EC_POINT *); + int (*is_on_curve)(const EC_GROUP *, const EC_POINT *, BN_CTX *); + int (*point_cmp)(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, + BN_CTX *); + + /* used by EC_POINT_make_affine, EC_POINTs_make_affine: */ + int (*make_affine)(const EC_GROUP *, EC_POINT *, BN_CTX *); + int (*points_make_affine)(const EC_GROUP *, size_t num, EC_POINT * [], + BN_CTX *); + + /* used by EC_POINTs_mul, EC_POINT_mul, EC_POINT_precompute_mult, + * EC_POINT_have_precompute_mult + * (default implementations are used if the 'mul' pointer is 0): */ + int (*mul)(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, + size_t num, const EC_POINT *points[], const BIGNUM *scalars[], + BN_CTX *); + int (*precompute_mult)(EC_GROUP *group, BN_CTX *); + int (*have_precompute_mult)(const EC_GROUP *group); + + + /* internal functions */ + + /* 'field_mul', 'field_sqr', and 'field_div' can be used by 'add' and 'dbl' + * so that the same implementations of point operations can be used with + * different optimized implementations of expensive field operations: */ + int (*field_mul)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); + int (*field_div)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, BN_CTX *); + + int (*field_encode)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + BN_CTX *); /* e.g. to Montgomery */ + int (*field_decode)(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + BN_CTX *); /* e.g. from Montgomery */ + int (*field_set_to_one)(const EC_GROUP *, BIGNUM *r, BN_CTX *); +} /* EC_METHOD */; + +const EC_METHOD* EC_GFp_mont_method(void); + +struct ec_pre_comp_st; +void ec_pre_comp_free(struct ec_pre_comp_st *pre_comp); +void *ec_pre_comp_dup(struct ec_pre_comp_st *pre_comp); + +struct ec_group_st { + const EC_METHOD *meth; + + EC_POINT *generator; /* optional */ + BIGNUM order, cofactor; + + int curve_name; /* optional NID for named curve */ + + struct ec_pre_comp_st *pre_comp; + + /* The following members are handled by the method functions, + * even if they appear generic */ + + BIGNUM field; /* For curves over GF(p), this is the modulus. */ + + BIGNUM a, b; /* Curve coefficients. */ + + int a_is_minus3; /* enable optimized point arithmetics for special case */ + + BN_MONT_CTX *mont; /* Montgomery structure. */ + BIGNUM *one; /* The value one */ +} /* EC_GROUP */; + +struct ec_point_st { + const EC_METHOD *meth; + + /* All members except 'meth' are handled by the method functions, + * even if they appear generic */ + + BIGNUM X; + BIGNUM Y; + BIGNUM Z; /* Jacobian projective coordinates: + * (X, Y, Z) represents (X/Z^2, Y/Z^3) if Z != 0 */ + int Z_is_one; /* enable optimized point arithmetics for special case */ +} /* EC_POINT */; + +EC_GROUP *ec_group_new(const EC_METHOD *meth); +int ec_group_copy(EC_GROUP *dest, const EC_GROUP *src); + +int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, + size_t num, const EC_POINT *points[], const BIGNUM *scalars[], + BN_CTX *); +int ec_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *); +int ec_wNAF_have_precompute_mult(const EC_GROUP *group); + +/* method functions in simple.c */ +int ec_GFp_simple_group_init(EC_GROUP *); +void ec_GFp_simple_group_finish(EC_GROUP *); +void ec_GFp_simple_group_clear_finish(EC_GROUP *); +int ec_GFp_simple_group_copy(EC_GROUP *, const EC_GROUP *); +int ec_GFp_simple_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, + const BIGNUM *b, BN_CTX *); +int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a, + BIGNUM *b, BN_CTX *); +int ec_GFp_simple_group_get_degree(const EC_GROUP *); +int ec_GFp_simple_group_check_discriminant(const EC_GROUP *, BN_CTX *); +int ec_GFp_simple_point_init(EC_POINT *); +void ec_GFp_simple_point_finish(EC_POINT *); +void ec_GFp_simple_point_clear_finish(EC_POINT *); +int ec_GFp_simple_point_copy(EC_POINT *, const EC_POINT *); +int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *); +int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, + const BIGNUM *y, + const BIGNUM *z, BN_CTX *); +int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *, + const EC_POINT *, BIGNUM *x, + BIGNUM *y, BIGNUM *z, + BN_CTX *); +int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, const BIGNUM *y, + BN_CTX *); +int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *, + const EC_POINT *, BIGNUM *x, + BIGNUM *y, BN_CTX *); +int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *, + const BIGNUM *x, int y_bit, + BN_CTX *); +int ec_GFp_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, + const EC_POINT *b, BN_CTX *); +int ec_GFp_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, + BN_CTX *); +int ec_GFp_simple_invert(const EC_GROUP *, EC_POINT *, BN_CTX *); +int ec_GFp_simple_is_at_infinity(const EC_GROUP *, const EC_POINT *); +int ec_GFp_simple_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *); +int ec_GFp_simple_cmp(const EC_GROUP *, const EC_POINT *a, const EC_POINT *b, + BN_CTX *); +int ec_GFp_simple_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *); +int ec_GFp_simple_points_make_affine(const EC_GROUP *, size_t num, + EC_POINT * [], BN_CTX *); +int ec_GFp_simple_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, BN_CTX *); +int ec_GFp_simple_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + BN_CTX *); + +/* method functions in montgomery.c */ +int ec_GFp_mont_group_init(EC_GROUP *); +int ec_GFp_mont_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, + const BIGNUM *b, BN_CTX *); +void ec_GFp_mont_group_finish(EC_GROUP *); +void ec_GFp_mont_group_clear_finish(EC_GROUP *); +int ec_GFp_mont_group_copy(EC_GROUP *, const EC_GROUP *); +int ec_GFp_mont_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, BN_CTX *); +int ec_GFp_mont_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + BN_CTX *); +int ec_GFp_mont_field_encode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + BN_CTX *); +int ec_GFp_mont_field_decode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, + BN_CTX *); +int ec_GFp_mont_field_set_to_one(const EC_GROUP *, BIGNUM *r, BN_CTX *); + +int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group, + EC_POINT *point, const BIGNUM *x, + const BIGNUM *y, const BIGNUM *z, + BN_CTX *ctx); + +void ec_GFp_nistp_points_make_affine_internal( + size_t num, void *point_array, size_t felem_size, void *tmp_felems, + void (*felem_one)(void *out), int (*felem_is_zero)(const void *in), + void (*felem_assign)(void *out, const void *in), + void (*felem_square)(void *out, const void *in), + void (*felem_mul)(void *out, const void *in1, const void *in2), + void (*felem_inv)(void *out, const void *in), + void (*felem_contract)(void *out, const void *in)); + +void ec_GFp_nistp_recode_scalar_bits(uint8_t *sign, uint8_t *digit, uint8_t in); + +const EC_METHOD *EC_GFp_nistp256_method(void); + +struct ec_key_st { + int version; + + EC_GROUP *group; + + EC_POINT *pub_key; + BIGNUM *priv_key; + + unsigned int enc_flag; + point_conversion_form_t conv_form; + + CRYPTO_refcount_t references; + int flags; + + ECDSA_METHOD *ecdsa_meth; + + CRYPTO_EX_DATA ex_data; +} /* EC_KEY */; + +/* curve_data contains data about a built-in elliptic curve. */ +struct curve_data { + /* comment is a human-readable string describing the curve. */ + const char *comment; + /* param_len is the number of bytes needed to store a field element. */ + uint8_t param_len; + /* cofactor is the cofactor of the group (i.e. the number of elements in the + * group divided by the size of the main subgroup. */ + uint8_t cofactor; /* promoted to BN_ULONG */ + /* data points to an array of 6*|param_len| bytes which hold the field + * elements of the following (in big-endian order): prime, a, b, generator x, + * generator y, order. */ + const uint8_t data[]; +}; + +struct built_in_curve { + int nid; + const struct curve_data *data; + const EC_METHOD *(*method)(void); +}; + +/* OPENSSL_built_in_curves is terminated with an entry where |nid| is + * |NID_undef|. */ +extern const struct built_in_curve OPENSSL_built_in_curves[]; + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_EC_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/ec/oct.c b/TMessagesProj/jni/boringssl/crypto/ec/oct.c new file mode 100644 index 00000000..cb50e172 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/oct.c @@ -0,0 +1,470 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#include + +#include +#include + +#include "internal.h" + + +static size_t ec_GFp_simple_point2oct(const EC_GROUP *group, + const EC_POINT *point, + point_conversion_form_t form, + uint8_t *buf, size_t len, BN_CTX *ctx) { + size_t ret; + BN_CTX *new_ctx = NULL; + int used_ctx = 0; + BIGNUM *x, *y; + size_t field_len, i; + + if ((form != POINT_CONVERSION_COMPRESSED) && + (form != POINT_CONVERSION_UNCOMPRESSED)) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FORM); + goto err; + } + + if (EC_POINT_is_at_infinity(group, point)) { + /* encodes to a single 0 octet */ + if (buf != NULL) { + if (len < 1) { + OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL); + return 0; + } + buf[0] = 0; + } + return 1; + } + + + /* ret := required output buffer length */ + field_len = BN_num_bytes(&group->field); + ret = + (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len; + + /* if 'buf' is NULL, just return required length */ + if (buf != NULL) { + if (len < ret) { + OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL); + goto err; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + used_ctx = 1; + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + if (y == NULL) { + goto err; + } + + if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx)) { + goto err; + } + + if ((form == POINT_CONVERSION_COMPRESSED) && + BN_is_odd(y)) { + buf[0] = form + 1; + } else { + buf[0] = form; + } + i = 1; + + if (!BN_bn2bin_padded(buf + i, field_len, x)) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + i += field_len; + + if (form == POINT_CONVERSION_UNCOMPRESSED) { + if (!BN_bn2bin_padded(buf + i, field_len, y)) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + i += field_len; + } + + if (i != ret) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + if (used_ctx) { + BN_CTX_end(ctx); + } + BN_CTX_free(new_ctx); + return ret; + +err: + if (used_ctx) { + BN_CTX_end(ctx); + } + BN_CTX_free(new_ctx); + return 0; +} + + +static int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point, + const uint8_t *buf, size_t len, + BN_CTX *ctx) { + point_conversion_form_t form; + int y_bit; + BN_CTX *new_ctx = NULL; + BIGNUM *x, *y; + size_t field_len, enc_len; + int ret = 0; + + if (len == 0) { + OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL); + return 0; + } + form = buf[0]; + y_bit = form & 1; + form = form & ~1U; + if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED) && + (form != POINT_CONVERSION_UNCOMPRESSED)) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING); + return 0; + } + if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING); + return 0; + } + + if (form == 0) { + if (len != 1) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING); + return 0; + } + + return EC_POINT_set_to_infinity(group, point); + } + + field_len = BN_num_bytes(&group->field); + enc_len = + (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len; + + if (len != enc_len) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING); + return 0; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + if (x == NULL || y == NULL) { + goto err; + } + + if (!BN_bin2bn(buf + 1, field_len, x)) { + goto err; + } + if (BN_ucmp(x, &group->field) >= 0) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING); + goto err; + } + + if (form == POINT_CONVERSION_COMPRESSED) { + if (!EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit, ctx)) { + goto err; + } + } else { + if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) { + goto err; + } + if (BN_ucmp(y, &group->field) >= 0) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING); + goto err; + } + + if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) { + goto err; + } + } + + /* test required by X9.62 */ + if (!EC_POINT_is_on_curve(group, point, ctx)) { + OPENSSL_PUT_ERROR(EC, EC_R_POINT_IS_NOT_ON_CURVE); + goto err; + } + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point, + const uint8_t *buf, size_t len, BN_CTX *ctx) { + if (group->meth->oct2point == 0 && + !(group->meth->flags & EC_FLAGS_DEFAULT_OCT)) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) { + return ec_GFp_simple_oct2point(group, point, buf, len, ctx); + } + + return group->meth->oct2point(group, point, buf, len, ctx); +} + +size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point, + point_conversion_form_t form, uint8_t *buf, + size_t len, BN_CTX *ctx) { + if (group->meth->point2oct == 0 && + !(group->meth->flags & EC_FLAGS_DEFAULT_OCT)) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) { + return ec_GFp_simple_point2oct(group, point, form, buf, len, ctx); + } + + return group->meth->point2oct(group, point, form, buf, len, ctx); +} + +int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, + EC_POINT *point, const BIGNUM *x_, + int y_bit, BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + BIGNUM *tmp1, *tmp2, *x, *y; + int ret = 0; + + ERR_clear_error(); + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + y_bit = (y_bit != 0); + + BN_CTX_start(ctx); + tmp1 = BN_CTX_get(ctx); + tmp2 = BN_CTX_get(ctx); + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + if (y == NULL) { + goto err; + } + + /* Recover y. We have a Weierstrass equation + * y^2 = x^3 + a*x + b, + * so y is one of the square roots of x^3 + a*x + b. */ + + /* tmp1 := x^3 */ + if (!BN_nnmod(x, x_, &group->field, ctx)) { + goto err; + } + + if (group->meth->field_decode == 0) { + /* field_{sqr,mul} work on standard representation */ + if (!group->meth->field_sqr(group, tmp2, x_, ctx) || + !group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) { + goto err; + } + } else { + if (!BN_mod_sqr(tmp2, x_, &group->field, ctx) || + !BN_mod_mul(tmp1, tmp2, x_, &group->field, ctx)) { + goto err; + } + } + + /* tmp1 := tmp1 + a*x */ + if (group->a_is_minus3) { + if (!BN_mod_lshift1_quick(tmp2, x, &group->field) || + !BN_mod_add_quick(tmp2, tmp2, x, &group->field) || + !BN_mod_sub_quick(tmp1, tmp1, tmp2, &group->field)) { + goto err; + } + } else { + if (group->meth->field_decode) { + if (!group->meth->field_decode(group, tmp2, &group->a, ctx) || + !BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) { + goto err; + } + } else { + /* field_mul works on standard representation */ + if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) { + goto err; + } + } + + if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) { + goto err; + } + } + + /* tmp1 := tmp1 + b */ + if (group->meth->field_decode) { + if (!group->meth->field_decode(group, tmp2, &group->b, ctx) || + !BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) { + goto err; + } + } else { + if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) { + goto err; + } + } + + if (!BN_mod_sqrt(y, tmp1, &group->field, ctx)) { + unsigned long err = ERR_peek_last_error(); + + if (ERR_GET_LIB(err) == ERR_LIB_BN && + ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) { + ERR_clear_error(); + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT); + } else { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + } + goto err; + } + + if (y_bit != BN_is_odd(y)) { + if (BN_is_zero(y)) { + int kron; + + kron = BN_kronecker(x, &group->field, ctx); + if (kron == -2) { + goto err; + } + + if (kron == 1) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSION_BIT); + } else { + /* BN_mod_sqrt() should have cought this error (not a square) */ + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT); + } + goto err; + } + if (!BN_usub(y, &group->field, y)) { + goto err; + } + } + if (y_bit != BN_is_odd(y)) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) { + goto err; + } + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, + EC_POINT *point, const BIGNUM *x, + int y_bit, BN_CTX *ctx) { + if (group->meth->point_set_compressed_coordinates == 0 && + !(group->meth->flags & EC_FLAGS_DEFAULT_OCT)) { + OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + if (group->meth != point->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + if (group->meth->flags & EC_FLAGS_DEFAULT_OCT) { + return ec_GFp_simple_set_compressed_coordinates(group, point, x, y_bit, + ctx); + } + return group->meth->point_set_compressed_coordinates(group, point, x, y_bit, + ctx); +} diff --git a/TMessagesProj/jni/boringssl/crypto/ec/p256-64.c b/TMessagesProj/jni/boringssl/crypto/ec/p256-64.c new file mode 100644 index 00000000..3946b298 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/p256-64.c @@ -0,0 +1,1931 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* A 64-bit implementation of the NIST P-256 elliptic curve point + * multiplication + * + * OpenSSL integration was taken from Emilia Kasper's work in ecp_nistp224.c. + * Otherwise based on Emilia's P224 work, which was inspired by my curve25519 + * work which got its smarts from Daniel J. Bernstein's work on the same. */ + +#include + +#if defined(OPENSSL_64_BIT) && !defined(OPENSSL_WINDOWS) + +#include +#include +#include +#include +#include + +#include + +#include "internal.h" + + +typedef uint8_t u8; +typedef uint64_t u64; +typedef int64_t s64; +typedef __uint128_t uint128_t; +typedef __int128_t int128_t; + +/* The underlying field. P256 operates over GF(2^256-2^224+2^192+2^96-1). We + * can serialise an element of this field into 32 bytes. We call this an + * felem_bytearray. */ +typedef u8 felem_bytearray[32]; + +/* These are the parameters of P256, taken from FIPS 186-3, page 86. These + * values are big-endian. */ +static const felem_bytearray nistp256_curve_params[5] = { + {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, /* p */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, + {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, /* a = -3 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfc}, /* b */ + {0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd, 0x55, + 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53, 0xb0, 0xf6, + 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b}, + {0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, /* x */ + 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, + 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96}, + {0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, /* y */ + 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, + 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5}}; + +/* The representation of field elements. + * ------------------------------------ + * + * We represent field elements with either four 128-bit values, eight 128-bit + * values, or four 64-bit values. The field element represented is: + * v[0]*2^0 + v[1]*2^64 + v[2]*2^128 + v[3]*2^192 (mod p) + * or: + * v[0]*2^0 + v[1]*2^64 + v[2]*2^128 + ... + v[8]*2^512 (mod p) + * + * 128-bit values are called 'limbs'. Since the limbs are spaced only 64 bits + * apart, but are 128-bits wide, the most significant bits of each limb overlap + * with the least significant bits of the next. + * + * A field element with four limbs is an 'felem'. One with eight limbs is a + * 'longfelem' + * + * A field element with four, 64-bit values is called a 'smallfelem'. Small + * values are used as intermediate values before multiplication. */ + +#define NLIMBS 4 + +typedef uint128_t limb; +typedef limb felem[NLIMBS]; +typedef limb longfelem[NLIMBS * 2]; +typedef u64 smallfelem[NLIMBS]; + +/* This is the value of the prime as four 64-bit words, little-endian. */ +static const u64 kPrime[4] = {0xfffffffffffffffful, 0xffffffff, 0, + 0xffffffff00000001ul}; +static const u64 bottom63bits = 0x7ffffffffffffffful; + +/* bin32_to_felem takes a little-endian byte array and converts it into felem + * form. This assumes that the CPU is little-endian. */ +static void bin32_to_felem(felem out, const u8 in[32]) { + out[0] = *((u64 *)&in[0]); + out[1] = *((u64 *)&in[8]); + out[2] = *((u64 *)&in[16]); + out[3] = *((u64 *)&in[24]); +} + +/* smallfelem_to_bin32 takes a smallfelem and serialises into a little endian, + * 32 byte array. This assumes that the CPU is little-endian. */ +static void smallfelem_to_bin32(u8 out[32], const smallfelem in) { + *((u64 *)&out[0]) = in[0]; + *((u64 *)&out[8]) = in[1]; + *((u64 *)&out[16]) = in[2]; + *((u64 *)&out[24]) = in[3]; +} + +/* To preserve endianness when using BN_bn2bin and BN_bin2bn. */ +static void flip_endian(u8 *out, const u8 *in, unsigned len) { + unsigned i; + for (i = 0; i < len; ++i) { + out[i] = in[len - 1 - i]; + } +} + +/* BN_to_felem converts an OpenSSL BIGNUM into an felem. */ +static int BN_to_felem(felem out, const BIGNUM *bn) { + if (BN_is_negative(bn)) { + OPENSSL_PUT_ERROR(EC, EC_R_BIGNUM_OUT_OF_RANGE); + return 0; + } + + felem_bytearray b_out; + /* BN_bn2bin eats leading zeroes */ + memset(b_out, 0, sizeof(b_out)); + unsigned num_bytes = BN_num_bytes(bn); + if (num_bytes > sizeof(b_out)) { + OPENSSL_PUT_ERROR(EC, EC_R_BIGNUM_OUT_OF_RANGE); + return 0; + } + + felem_bytearray b_in; + num_bytes = BN_bn2bin(bn, b_in); + flip_endian(b_out, b_in, num_bytes); + bin32_to_felem(out, b_out); + return 1; +} + +/* felem_to_BN converts an felem into an OpenSSL BIGNUM. */ +static BIGNUM *smallfelem_to_BN(BIGNUM *out, const smallfelem in) { + felem_bytearray b_in, b_out; + smallfelem_to_bin32(b_in, in); + flip_endian(b_out, b_in, sizeof(b_out)); + return BN_bin2bn(b_out, sizeof(b_out), out); +} + +/* Field operations. */ + +static void smallfelem_one(smallfelem out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; +} + +static void smallfelem_assign(smallfelem out, const smallfelem in) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; +} + +static void felem_assign(felem out, const felem in) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; +} + +/* felem_sum sets out = out + in. */ +static void felem_sum(felem out, const felem in) { + out[0] += in[0]; + out[1] += in[1]; + out[2] += in[2]; + out[3] += in[3]; +} + +/* felem_small_sum sets out = out + in. */ +static void felem_small_sum(felem out, const smallfelem in) { + out[0] += in[0]; + out[1] += in[1]; + out[2] += in[2]; + out[3] += in[3]; +} + +/* felem_scalar sets out = out * scalar */ +static void felem_scalar(felem out, const u64 scalar) { + out[0] *= scalar; + out[1] *= scalar; + out[2] *= scalar; + out[3] *= scalar; +} + +/* longfelem_scalar sets out = out * scalar */ +static void longfelem_scalar(longfelem out, const u64 scalar) { + out[0] *= scalar; + out[1] *= scalar; + out[2] *= scalar; + out[3] *= scalar; + out[4] *= scalar; + out[5] *= scalar; + out[6] *= scalar; + out[7] *= scalar; +} + +#define two105m41m9 (((limb)1) << 105) - (((limb)1) << 41) - (((limb)1) << 9) +#define two105 (((limb)1) << 105) +#define two105m41p9 (((limb)1) << 105) - (((limb)1) << 41) + (((limb)1) << 9) + +/* zero105 is 0 mod p */ +static const felem zero105 = {two105m41m9, two105, two105m41p9, two105m41p9}; + +/* smallfelem_neg sets |out| to |-small| + * On exit: + * out[i] < out[i] + 2^105 */ +static void smallfelem_neg(felem out, const smallfelem small) { + /* In order to prevent underflow, we subtract from 0 mod p. */ + out[0] = zero105[0] - small[0]; + out[1] = zero105[1] - small[1]; + out[2] = zero105[2] - small[2]; + out[3] = zero105[3] - small[3]; +} + +/* felem_diff subtracts |in| from |out| + * On entry: + * in[i] < 2^104 + * On exit: + * out[i] < out[i] + 2^105. */ +static void felem_diff(felem out, const felem in) { + /* In order to prevent underflow, we add 0 mod p before subtracting. */ + out[0] += zero105[0]; + out[1] += zero105[1]; + out[2] += zero105[2]; + out[3] += zero105[3]; + + out[0] -= in[0]; + out[1] -= in[1]; + out[2] -= in[2]; + out[3] -= in[3]; +} + +#define two107m43m11 (((limb)1) << 107) - (((limb)1) << 43) - (((limb)1) << 11) +#define two107 (((limb)1) << 107) +#define two107m43p11 (((limb)1) << 107) - (((limb)1) << 43) + (((limb)1) << 11) + +/* zero107 is 0 mod p */ +static const felem zero107 = {two107m43m11, two107, two107m43p11, two107m43p11}; + +/* An alternative felem_diff for larger inputs |in| + * felem_diff_zero107 subtracts |in| from |out| + * On entry: + * in[i] < 2^106 + * On exit: + * out[i] < out[i] + 2^107. */ +static void felem_diff_zero107(felem out, const felem in) { + /* In order to prevent underflow, we add 0 mod p before subtracting. */ + out[0] += zero107[0]; + out[1] += zero107[1]; + out[2] += zero107[2]; + out[3] += zero107[3]; + + out[0] -= in[0]; + out[1] -= in[1]; + out[2] -= in[2]; + out[3] -= in[3]; +} + +/* longfelem_diff subtracts |in| from |out| + * On entry: + * in[i] < 7*2^67 + * On exit: + * out[i] < out[i] + 2^70 + 2^40. */ +static void longfelem_diff(longfelem out, const longfelem in) { + static const limb two70m8p6 = + (((limb)1) << 70) - (((limb)1) << 8) + (((limb)1) << 6); + static const limb two70p40 = (((limb)1) << 70) + (((limb)1) << 40); + static const limb two70 = (((limb)1) << 70); + static const limb two70m40m38p6 = (((limb)1) << 70) - (((limb)1) << 40) - + (((limb)1) << 38) + (((limb)1) << 6); + static const limb two70m6 = (((limb)1) << 70) - (((limb)1) << 6); + + /* add 0 mod p to avoid underflow */ + out[0] += two70m8p6; + out[1] += two70p40; + out[2] += two70; + out[3] += two70m40m38p6; + out[4] += two70m6; + out[5] += two70m6; + out[6] += two70m6; + out[7] += two70m6; + + /* in[i] < 7*2^67 < 2^70 - 2^40 - 2^38 + 2^6 */ + out[0] -= in[0]; + out[1] -= in[1]; + out[2] -= in[2]; + out[3] -= in[3]; + out[4] -= in[4]; + out[5] -= in[5]; + out[6] -= in[6]; + out[7] -= in[7]; +} + +#define two64m0 (((limb)1) << 64) - 1 +#define two110p32m0 (((limb)1) << 110) + (((limb)1) << 32) - 1 +#define two64m46 (((limb)1) << 64) - (((limb)1) << 46) +#define two64m32 (((limb)1) << 64) - (((limb)1) << 32) + +/* zero110 is 0 mod p. */ +static const felem zero110 = {two64m0, two110p32m0, two64m46, two64m32}; + +/* felem_shrink converts an felem into a smallfelem. The result isn't quite + * minimal as the value may be greater than p. + * + * On entry: + * in[i] < 2^109 + * On exit: + * out[i] < 2^64. */ +static void felem_shrink(smallfelem out, const felem in) { + felem tmp; + u64 a, b, mask; + s64 high, low; + static const u64 kPrime3Test = 0x7fffffff00000001ul; /* 2^63 - 2^32 + 1 */ + + /* Carry 2->3 */ + tmp[3] = zero110[3] + in[3] + ((u64)(in[2] >> 64)); + /* tmp[3] < 2^110 */ + + tmp[2] = zero110[2] + (u64)in[2]; + tmp[0] = zero110[0] + in[0]; + tmp[1] = zero110[1] + in[1]; + /* tmp[0] < 2**110, tmp[1] < 2^111, tmp[2] < 2**65 */ + + /* We perform two partial reductions where we eliminate the high-word of + * tmp[3]. We don't update the other words till the end. */ + a = tmp[3] >> 64; /* a < 2^46 */ + tmp[3] = (u64)tmp[3]; + tmp[3] -= a; + tmp[3] += ((limb)a) << 32; + /* tmp[3] < 2^79 */ + + b = a; + a = tmp[3] >> 64; /* a < 2^15 */ + b += a; /* b < 2^46 + 2^15 < 2^47 */ + tmp[3] = (u64)tmp[3]; + tmp[3] -= a; + tmp[3] += ((limb)a) << 32; + /* tmp[3] < 2^64 + 2^47 */ + + /* This adjusts the other two words to complete the two partial + * reductions. */ + tmp[0] += b; + tmp[1] -= (((limb)b) << 32); + + /* In order to make space in tmp[3] for the carry from 2 -> 3, we + * conditionally subtract kPrime if tmp[3] is large enough. */ + high = tmp[3] >> 64; + /* As tmp[3] < 2^65, high is either 1 or 0 */ + high <<= 63; + high >>= 63; + /* high is: + * all ones if the high word of tmp[3] is 1 + * all zeros if the high word of tmp[3] if 0 */ + low = tmp[3]; + mask = low >> 63; + /* mask is: + * all ones if the MSB of low is 1 + * all zeros if the MSB of low if 0 */ + low &= bottom63bits; + low -= kPrime3Test; + /* if low was greater than kPrime3Test then the MSB is zero */ + low = ~low; + low >>= 63; + /* low is: + * all ones if low was > kPrime3Test + * all zeros if low was <= kPrime3Test */ + mask = (mask & low) | high; + tmp[0] -= mask & kPrime[0]; + tmp[1] -= mask & kPrime[1]; + /* kPrime[2] is zero, so omitted */ + tmp[3] -= mask & kPrime[3]; + /* tmp[3] < 2**64 - 2**32 + 1 */ + + tmp[1] += ((u64)(tmp[0] >> 64)); + tmp[0] = (u64)tmp[0]; + tmp[2] += ((u64)(tmp[1] >> 64)); + tmp[1] = (u64)tmp[1]; + tmp[3] += ((u64)(tmp[2] >> 64)); + tmp[2] = (u64)tmp[2]; + /* tmp[i] < 2^64 */ + + out[0] = tmp[0]; + out[1] = tmp[1]; + out[2] = tmp[2]; + out[3] = tmp[3]; +} + +/* smallfelem_expand converts a smallfelem to an felem */ +static void smallfelem_expand(felem out, const smallfelem in) { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = in[3]; +} + +/* smallfelem_square sets |out| = |small|^2 + * On entry: + * small[i] < 2^64 + * On exit: + * out[i] < 7 * 2^64 < 2^67 */ +static void smallfelem_square(longfelem out, const smallfelem small) { + limb a; + u64 high, low; + + a = ((uint128_t)small[0]) * small[0]; + low = a; + high = a >> 64; + out[0] = low; + out[1] = high; + + a = ((uint128_t)small[0]) * small[1]; + low = a; + high = a >> 64; + out[1] += low; + out[1] += low; + out[2] = high; + + a = ((uint128_t)small[0]) * small[2]; + low = a; + high = a >> 64; + out[2] += low; + out[2] *= 2; + out[3] = high; + + a = ((uint128_t)small[0]) * small[3]; + low = a; + high = a >> 64; + out[3] += low; + out[4] = high; + + a = ((uint128_t)small[1]) * small[2]; + low = a; + high = a >> 64; + out[3] += low; + out[3] *= 2; + out[4] += high; + + a = ((uint128_t)small[1]) * small[1]; + low = a; + high = a >> 64; + out[2] += low; + out[3] += high; + + a = ((uint128_t)small[1]) * small[3]; + low = a; + high = a >> 64; + out[4] += low; + out[4] *= 2; + out[5] = high; + + a = ((uint128_t)small[2]) * small[3]; + low = a; + high = a >> 64; + out[5] += low; + out[5] *= 2; + out[6] = high; + out[6] += high; + + a = ((uint128_t)small[2]) * small[2]; + low = a; + high = a >> 64; + out[4] += low; + out[5] += high; + + a = ((uint128_t)small[3]) * small[3]; + low = a; + high = a >> 64; + out[6] += low; + out[7] = high; +} + +/*felem_square sets |out| = |in|^2 + * On entry: + * in[i] < 2^109 + * On exit: + * out[i] < 7 * 2^64 < 2^67. */ +static void felem_square(longfelem out, const felem in) { + u64 small[4]; + felem_shrink(small, in); + smallfelem_square(out, small); +} + +/* smallfelem_mul sets |out| = |small1| * |small2| + * On entry: + * small1[i] < 2^64 + * small2[i] < 2^64 + * On exit: + * out[i] < 7 * 2^64 < 2^67. */ +static void smallfelem_mul(longfelem out, const smallfelem small1, + const smallfelem small2) { + limb a; + u64 high, low; + + a = ((uint128_t)small1[0]) * small2[0]; + low = a; + high = a >> 64; + out[0] = low; + out[1] = high; + + a = ((uint128_t)small1[0]) * small2[1]; + low = a; + high = a >> 64; + out[1] += low; + out[2] = high; + + a = ((uint128_t)small1[1]) * small2[0]; + low = a; + high = a >> 64; + out[1] += low; + out[2] += high; + + a = ((uint128_t)small1[0]) * small2[2]; + low = a; + high = a >> 64; + out[2] += low; + out[3] = high; + + a = ((uint128_t)small1[1]) * small2[1]; + low = a; + high = a >> 64; + out[2] += low; + out[3] += high; + + a = ((uint128_t)small1[2]) * small2[0]; + low = a; + high = a >> 64; + out[2] += low; + out[3] += high; + + a = ((uint128_t)small1[0]) * small2[3]; + low = a; + high = a >> 64; + out[3] += low; + out[4] = high; + + a = ((uint128_t)small1[1]) * small2[2]; + low = a; + high = a >> 64; + out[3] += low; + out[4] += high; + + a = ((uint128_t)small1[2]) * small2[1]; + low = a; + high = a >> 64; + out[3] += low; + out[4] += high; + + a = ((uint128_t)small1[3]) * small2[0]; + low = a; + high = a >> 64; + out[3] += low; + out[4] += high; + + a = ((uint128_t)small1[1]) * small2[3]; + low = a; + high = a >> 64; + out[4] += low; + out[5] = high; + + a = ((uint128_t)small1[2]) * small2[2]; + low = a; + high = a >> 64; + out[4] += low; + out[5] += high; + + a = ((uint128_t)small1[3]) * small2[1]; + low = a; + high = a >> 64; + out[4] += low; + out[5] += high; + + a = ((uint128_t)small1[2]) * small2[3]; + low = a; + high = a >> 64; + out[5] += low; + out[6] = high; + + a = ((uint128_t)small1[3]) * small2[2]; + low = a; + high = a >> 64; + out[5] += low; + out[6] += high; + + a = ((uint128_t)small1[3]) * small2[3]; + low = a; + high = a >> 64; + out[6] += low; + out[7] = high; +} + +/* felem_mul sets |out| = |in1| * |in2| + * On entry: + * in1[i] < 2^109 + * in2[i] < 2^109 + * On exit: + * out[i] < 7 * 2^64 < 2^67 */ +static void felem_mul(longfelem out, const felem in1, const felem in2) { + smallfelem small1, small2; + felem_shrink(small1, in1); + felem_shrink(small2, in2); + smallfelem_mul(out, small1, small2); +} + +/* felem_small_mul sets |out| = |small1| * |in2| + * On entry: + * small1[i] < 2^64 + * in2[i] < 2^109 + * On exit: + * out[i] < 7 * 2^64 < 2^67 */ +static void felem_small_mul(longfelem out, const smallfelem small1, + const felem in2) { + smallfelem small2; + felem_shrink(small2, in2); + smallfelem_mul(out, small1, small2); +} + +#define two100m36m4 (((limb)1) << 100) - (((limb)1) << 36) - (((limb)1) << 4) +#define two100 (((limb)1) << 100) +#define two100m36p4 (((limb)1) << 100) - (((limb)1) << 36) + (((limb)1) << 4) + +/* zero100 is 0 mod p */ +static const felem zero100 = {two100m36m4, two100, two100m36p4, two100m36p4}; + +/* Internal function for the different flavours of felem_reduce. + * felem_reduce_ reduces the higher coefficients in[4]-in[7]. + * On entry: + * out[0] >= in[6] + 2^32*in[6] + in[7] + 2^32*in[7] + * out[1] >= in[7] + 2^32*in[4] + * out[2] >= in[5] + 2^32*in[5] + * out[3] >= in[4] + 2^32*in[5] + 2^32*in[6] + * On exit: + * out[0] <= out[0] + in[4] + 2^32*in[5] + * out[1] <= out[1] + in[5] + 2^33*in[6] + * out[2] <= out[2] + in[7] + 2*in[6] + 2^33*in[7] + * out[3] <= out[3] + 2^32*in[4] + 3*in[7] */ +static void felem_reduce_(felem out, const longfelem in) { + int128_t c; + /* combine common terms from below */ + c = in[4] + (in[5] << 32); + out[0] += c; + out[3] -= c; + + c = in[5] - in[7]; + out[1] += c; + out[2] -= c; + + /* the remaining terms */ + /* 256: [(0,1),(96,-1),(192,-1),(224,1)] */ + out[1] -= (in[4] << 32); + out[3] += (in[4] << 32); + + /* 320: [(32,1),(64,1),(128,-1),(160,-1),(224,-1)] */ + out[2] -= (in[5] << 32); + + /* 384: [(0,-1),(32,-1),(96,2),(128,2),(224,-1)] */ + out[0] -= in[6]; + out[0] -= (in[6] << 32); + out[1] += (in[6] << 33); + out[2] += (in[6] * 2); + out[3] -= (in[6] << 32); + + /* 448: [(0,-1),(32,-1),(64,-1),(128,1),(160,2),(192,3)] */ + out[0] -= in[7]; + out[0] -= (in[7] << 32); + out[2] += (in[7] << 33); + out[3] += (in[7] * 3); +} + +/* felem_reduce converts a longfelem into an felem. + * To be called directly after felem_square or felem_mul. + * On entry: + * in[0] < 2^64, in[1] < 3*2^64, in[2] < 5*2^64, in[3] < 7*2^64 + * in[4] < 7*2^64, in[5] < 5*2^64, in[6] < 3*2^64, in[7] < 2*64 + * On exit: + * out[i] < 2^101 */ +static void felem_reduce(felem out, const longfelem in) { + out[0] = zero100[0] + in[0]; + out[1] = zero100[1] + in[1]; + out[2] = zero100[2] + in[2]; + out[3] = zero100[3] + in[3]; + + felem_reduce_(out, in); + + /* out[0] > 2^100 - 2^36 - 2^4 - 3*2^64 - 3*2^96 - 2^64 - 2^96 > 0 + * out[1] > 2^100 - 2^64 - 7*2^96 > 0 + * out[2] > 2^100 - 2^36 + 2^4 - 5*2^64 - 5*2^96 > 0 + * out[3] > 2^100 - 2^36 + 2^4 - 7*2^64 - 5*2^96 - 3*2^96 > 0 + * + * out[0] < 2^100 + 2^64 + 7*2^64 + 5*2^96 < 2^101 + * out[1] < 2^100 + 3*2^64 + 5*2^64 + 3*2^97 < 2^101 + * out[2] < 2^100 + 5*2^64 + 2^64 + 3*2^65 + 2^97 < 2^101 + * out[3] < 2^100 + 7*2^64 + 7*2^96 + 3*2^64 < 2^101 */ +} + +/* felem_reduce_zero105 converts a larger longfelem into an felem. + * On entry: + * in[0] < 2^71 + * On exit: + * out[i] < 2^106 */ +static void felem_reduce_zero105(felem out, const longfelem in) { + out[0] = zero105[0] + in[0]; + out[1] = zero105[1] + in[1]; + out[2] = zero105[2] + in[2]; + out[3] = zero105[3] + in[3]; + + felem_reduce_(out, in); + + /* out[0] > 2^105 - 2^41 - 2^9 - 2^71 - 2^103 - 2^71 - 2^103 > 0 + * out[1] > 2^105 - 2^71 - 2^103 > 0 + * out[2] > 2^105 - 2^41 + 2^9 - 2^71 - 2^103 > 0 + * out[3] > 2^105 - 2^41 + 2^9 - 2^71 - 2^103 - 2^103 > 0 + * + * out[0] < 2^105 + 2^71 + 2^71 + 2^103 < 2^106 + * out[1] < 2^105 + 2^71 + 2^71 + 2^103 < 2^106 + * out[2] < 2^105 + 2^71 + 2^71 + 2^71 + 2^103 < 2^106 + * out[3] < 2^105 + 2^71 + 2^103 + 2^71 < 2^106 */ +} + +/* subtract_u64 sets *result = *result - v and *carry to one if the + * subtraction underflowed. */ +static void subtract_u64(u64 *result, u64 *carry, u64 v) { + uint128_t r = *result; + r -= v; + *carry = (r >> 64) & 1; + *result = (u64)r; +} + +/* felem_contract converts |in| to its unique, minimal representation. On + * entry: in[i] < 2^109. */ +static void felem_contract(smallfelem out, const felem in) { + u64 all_equal_so_far = 0, result = 0; + + felem_shrink(out, in); + /* small is minimal except that the value might be > p */ + + all_equal_so_far--; + /* We are doing a constant time test if out >= kPrime. We need to compare + * each u64, from most-significant to least significant. For each one, if + * all words so far have been equal (m is all ones) then a non-equal + * result is the answer. Otherwise we continue. */ + unsigned i; + for (i = 3; i < 4; i--) { + u64 equal; + uint128_t a = ((uint128_t)kPrime[i]) - out[i]; + /* if out[i] > kPrime[i] then a will underflow and the high 64-bits + * will all be set. */ + result |= all_equal_so_far & ((u64)(a >> 64)); + + /* if kPrime[i] == out[i] then |equal| will be all zeros and the + * decrement will make it all ones. */ + equal = kPrime[i] ^ out[i]; + equal--; + equal &= equal << 32; + equal &= equal << 16; + equal &= equal << 8; + equal &= equal << 4; + equal &= equal << 2; + equal &= equal << 1; + equal = ((s64)equal) >> 63; + + all_equal_so_far &= equal; + } + + /* if all_equal_so_far is still all ones then the two values are equal + * and so out >= kPrime is true. */ + result |= all_equal_so_far; + + /* if out >= kPrime then we subtract kPrime. */ + u64 carry; + subtract_u64(&out[0], &carry, result & kPrime[0]); + subtract_u64(&out[1], &carry, carry); + subtract_u64(&out[2], &carry, carry); + subtract_u64(&out[3], &carry, carry); + + subtract_u64(&out[1], &carry, result & kPrime[1]); + subtract_u64(&out[2], &carry, carry); + subtract_u64(&out[3], &carry, carry); + + subtract_u64(&out[2], &carry, result & kPrime[2]); + subtract_u64(&out[3], &carry, carry); + + subtract_u64(&out[3], &carry, result & kPrime[3]); +} + +static void smallfelem_square_contract(smallfelem out, const smallfelem in) { + longfelem longtmp; + felem tmp; + + smallfelem_square(longtmp, in); + felem_reduce(tmp, longtmp); + felem_contract(out, tmp); +} + +static void smallfelem_mul_contract(smallfelem out, const smallfelem in1, + const smallfelem in2) { + longfelem longtmp; + felem tmp; + + smallfelem_mul(longtmp, in1, in2); + felem_reduce(tmp, longtmp); + felem_contract(out, tmp); +} + +/* felem_is_zero returns a limb with all bits set if |in| == 0 (mod p) and 0 + * otherwise. + * On entry: + * small[i] < 2^64 */ +static limb smallfelem_is_zero(const smallfelem small) { + limb result; + u64 is_p; + + u64 is_zero = small[0] | small[1] | small[2] | small[3]; + is_zero--; + is_zero &= is_zero << 32; + is_zero &= is_zero << 16; + is_zero &= is_zero << 8; + is_zero &= is_zero << 4; + is_zero &= is_zero << 2; + is_zero &= is_zero << 1; + is_zero = ((s64)is_zero) >> 63; + + is_p = (small[0] ^ kPrime[0]) | (small[1] ^ kPrime[1]) | + (small[2] ^ kPrime[2]) | (small[3] ^ kPrime[3]); + is_p--; + is_p &= is_p << 32; + is_p &= is_p << 16; + is_p &= is_p << 8; + is_p &= is_p << 4; + is_p &= is_p << 2; + is_p &= is_p << 1; + is_p = ((s64)is_p) >> 63; + + is_zero |= is_p; + + result = is_zero; + result |= ((limb)is_zero) << 64; + return result; +} + +static int smallfelem_is_zero_int(const smallfelem small) { + return (int)(smallfelem_is_zero(small) & ((limb)1)); +} + +/* felem_inv calculates |out| = |in|^{-1} + * + * Based on Fermat's Little Theorem: + * a^p = a (mod p) + * a^{p-1} = 1 (mod p) + * a^{p-2} = a^{-1} (mod p) */ +static void felem_inv(felem out, const felem in) { + felem ftmp, ftmp2; + /* each e_I will hold |in|^{2^I - 1} */ + felem e2, e4, e8, e16, e32, e64; + longfelem tmp; + unsigned i; + + felem_square(tmp, in); + felem_reduce(ftmp, tmp); /* 2^1 */ + felem_mul(tmp, in, ftmp); + felem_reduce(ftmp, tmp); /* 2^2 - 2^0 */ + felem_assign(e2, ftmp); + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); /* 2^3 - 2^1 */ + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); /* 2^4 - 2^2 */ + felem_mul(tmp, ftmp, e2); + felem_reduce(ftmp, tmp); /* 2^4 - 2^0 */ + felem_assign(e4, ftmp); + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); /* 2^5 - 2^1 */ + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); /* 2^6 - 2^2 */ + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); /* 2^7 - 2^3 */ + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); /* 2^8 - 2^4 */ + felem_mul(tmp, ftmp, e4); + felem_reduce(ftmp, tmp); /* 2^8 - 2^0 */ + felem_assign(e8, ftmp); + for (i = 0; i < 8; i++) { + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); + } /* 2^16 - 2^8 */ + felem_mul(tmp, ftmp, e8); + felem_reduce(ftmp, tmp); /* 2^16 - 2^0 */ + felem_assign(e16, ftmp); + for (i = 0; i < 16; i++) { + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); + } /* 2^32 - 2^16 */ + felem_mul(tmp, ftmp, e16); + felem_reduce(ftmp, tmp); /* 2^32 - 2^0 */ + felem_assign(e32, ftmp); + for (i = 0; i < 32; i++) { + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); + } /* 2^64 - 2^32 */ + felem_assign(e64, ftmp); + felem_mul(tmp, ftmp, in); + felem_reduce(ftmp, tmp); /* 2^64 - 2^32 + 2^0 */ + for (i = 0; i < 192; i++) { + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); + } /* 2^256 - 2^224 + 2^192 */ + + felem_mul(tmp, e64, e32); + felem_reduce(ftmp2, tmp); /* 2^64 - 2^0 */ + for (i = 0; i < 16; i++) { + felem_square(tmp, ftmp2); + felem_reduce(ftmp2, tmp); + } /* 2^80 - 2^16 */ + felem_mul(tmp, ftmp2, e16); + felem_reduce(ftmp2, tmp); /* 2^80 - 2^0 */ + for (i = 0; i < 8; i++) { + felem_square(tmp, ftmp2); + felem_reduce(ftmp2, tmp); + } /* 2^88 - 2^8 */ + felem_mul(tmp, ftmp2, e8); + felem_reduce(ftmp2, tmp); /* 2^88 - 2^0 */ + for (i = 0; i < 4; i++) { + felem_square(tmp, ftmp2); + felem_reduce(ftmp2, tmp); + } /* 2^92 - 2^4 */ + felem_mul(tmp, ftmp2, e4); + felem_reduce(ftmp2, tmp); /* 2^92 - 2^0 */ + felem_square(tmp, ftmp2); + felem_reduce(ftmp2, tmp); /* 2^93 - 2^1 */ + felem_square(tmp, ftmp2); + felem_reduce(ftmp2, tmp); /* 2^94 - 2^2 */ + felem_mul(tmp, ftmp2, e2); + felem_reduce(ftmp2, tmp); /* 2^94 - 2^0 */ + felem_square(tmp, ftmp2); + felem_reduce(ftmp2, tmp); /* 2^95 - 2^1 */ + felem_square(tmp, ftmp2); + felem_reduce(ftmp2, tmp); /* 2^96 - 2^2 */ + felem_mul(tmp, ftmp2, in); + felem_reduce(ftmp2, tmp); /* 2^96 - 3 */ + + felem_mul(tmp, ftmp2, ftmp); + felem_reduce(out, tmp); /* 2^256 - 2^224 + 2^192 + 2^96 - 3 */ +} + +static void smallfelem_inv_contract(smallfelem out, const smallfelem in) { + felem tmp; + + smallfelem_expand(tmp, in); + felem_inv(tmp, tmp); + felem_contract(out, tmp); +} + +/* Group operations + * ---------------- + * + * Building on top of the field operations we have the operations on the + * elliptic curve group itself. Points on the curve are represented in Jacobian + * coordinates. */ + +/* point_double calculates 2*(x_in, y_in, z_in) + * + * The method is taken from: + * http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b + * + * Outputs can equal corresponding inputs, i.e., x_out == x_in is allowed. + * while x_out == y_in is not (maybe this works, but it's not tested). */ +static void point_double(felem x_out, felem y_out, felem z_out, + const felem x_in, const felem y_in, const felem z_in) { + longfelem tmp, tmp2; + felem delta, gamma, beta, alpha, ftmp, ftmp2; + smallfelem small1, small2; + + felem_assign(ftmp, x_in); + /* ftmp[i] < 2^106 */ + felem_assign(ftmp2, x_in); + /* ftmp2[i] < 2^106 */ + + /* delta = z^2 */ + felem_square(tmp, z_in); + felem_reduce(delta, tmp); + /* delta[i] < 2^101 */ + + /* gamma = y^2 */ + felem_square(tmp, y_in); + felem_reduce(gamma, tmp); + /* gamma[i] < 2^101 */ + felem_shrink(small1, gamma); + + /* beta = x*gamma */ + felem_small_mul(tmp, small1, x_in); + felem_reduce(beta, tmp); + /* beta[i] < 2^101 */ + + /* alpha = 3*(x-delta)*(x+delta) */ + felem_diff(ftmp, delta); + /* ftmp[i] < 2^105 + 2^106 < 2^107 */ + felem_sum(ftmp2, delta); + /* ftmp2[i] < 2^105 + 2^106 < 2^107 */ + felem_scalar(ftmp2, 3); + /* ftmp2[i] < 3 * 2^107 < 2^109 */ + felem_mul(tmp, ftmp, ftmp2); + felem_reduce(alpha, tmp); + /* alpha[i] < 2^101 */ + felem_shrink(small2, alpha); + + /* x' = alpha^2 - 8*beta */ + smallfelem_square(tmp, small2); + felem_reduce(x_out, tmp); + felem_assign(ftmp, beta); + felem_scalar(ftmp, 8); + /* ftmp[i] < 8 * 2^101 = 2^104 */ + felem_diff(x_out, ftmp); + /* x_out[i] < 2^105 + 2^101 < 2^106 */ + + /* z' = (y + z)^2 - gamma - delta */ + felem_sum(delta, gamma); + /* delta[i] < 2^101 + 2^101 = 2^102 */ + felem_assign(ftmp, y_in); + felem_sum(ftmp, z_in); + /* ftmp[i] < 2^106 + 2^106 = 2^107 */ + felem_square(tmp, ftmp); + felem_reduce(z_out, tmp); + felem_diff(z_out, delta); + /* z_out[i] < 2^105 + 2^101 < 2^106 */ + + /* y' = alpha*(4*beta - x') - 8*gamma^2 */ + felem_scalar(beta, 4); + /* beta[i] < 4 * 2^101 = 2^103 */ + felem_diff_zero107(beta, x_out); + /* beta[i] < 2^107 + 2^103 < 2^108 */ + felem_small_mul(tmp, small2, beta); + /* tmp[i] < 7 * 2^64 < 2^67 */ + smallfelem_square(tmp2, small1); + /* tmp2[i] < 7 * 2^64 */ + longfelem_scalar(tmp2, 8); + /* tmp2[i] < 8 * 7 * 2^64 = 7 * 2^67 */ + longfelem_diff(tmp, tmp2); + /* tmp[i] < 2^67 + 2^70 + 2^40 < 2^71 */ + felem_reduce_zero105(y_out, tmp); + /* y_out[i] < 2^106 */ +} + +/* point_double_small is the same as point_double, except that it operates on + * smallfelems. */ +static void point_double_small(smallfelem x_out, smallfelem y_out, + smallfelem z_out, const smallfelem x_in, + const smallfelem y_in, const smallfelem z_in) { + felem felem_x_out, felem_y_out, felem_z_out; + felem felem_x_in, felem_y_in, felem_z_in; + + smallfelem_expand(felem_x_in, x_in); + smallfelem_expand(felem_y_in, y_in); + smallfelem_expand(felem_z_in, z_in); + point_double(felem_x_out, felem_y_out, felem_z_out, felem_x_in, felem_y_in, + felem_z_in); + felem_shrink(x_out, felem_x_out); + felem_shrink(y_out, felem_y_out); + felem_shrink(z_out, felem_z_out); +} + +/* copy_conditional copies in to out iff mask is all ones. */ +static void copy_conditional(felem out, const felem in, limb mask) { + unsigned i; + for (i = 0; i < NLIMBS; ++i) { + const limb tmp = mask & (in[i] ^ out[i]); + out[i] ^= tmp; + } +} + +/* copy_small_conditional copies in to out iff mask is all ones. */ +static void copy_small_conditional(felem out, const smallfelem in, limb mask) { + unsigned i; + const u64 mask64 = mask; + for (i = 0; i < NLIMBS; ++i) { + out[i] = ((limb)(in[i] & mask64)) | (out[i] & ~mask); + } +} + +/* point_add calcuates (x1, y1, z1) + (x2, y2, z2) + * + * The method is taken from: + * http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl, + * adapted for mixed addition (z2 = 1, or z2 = 0 for the point at infinity). + * + * This function includes a branch for checking whether the two input points + * are equal, (while not equal to the point at infinity). This case never + * happens during single point multiplication, so there is no timing leak for + * ECDH or ECDSA signing. */ +static void point_add(felem x3, felem y3, felem z3, const felem x1, + const felem y1, const felem z1, const int mixed, + const smallfelem x2, const smallfelem y2, + const smallfelem z2) { + felem ftmp, ftmp2, ftmp3, ftmp4, ftmp5, ftmp6, x_out, y_out, z_out; + longfelem tmp, tmp2; + smallfelem small1, small2, small3, small4, small5; + limb x_equal, y_equal, z1_is_zero, z2_is_zero; + + felem_shrink(small3, z1); + + z1_is_zero = smallfelem_is_zero(small3); + z2_is_zero = smallfelem_is_zero(z2); + + /* ftmp = z1z1 = z1**2 */ + smallfelem_square(tmp, small3); + felem_reduce(ftmp, tmp); + /* ftmp[i] < 2^101 */ + felem_shrink(small1, ftmp); + + if (!mixed) { + /* ftmp2 = z2z2 = z2**2 */ + smallfelem_square(tmp, z2); + felem_reduce(ftmp2, tmp); + /* ftmp2[i] < 2^101 */ + felem_shrink(small2, ftmp2); + + felem_shrink(small5, x1); + + /* u1 = ftmp3 = x1*z2z2 */ + smallfelem_mul(tmp, small5, small2); + felem_reduce(ftmp3, tmp); + /* ftmp3[i] < 2^101 */ + + /* ftmp5 = z1 + z2 */ + felem_assign(ftmp5, z1); + felem_small_sum(ftmp5, z2); + /* ftmp5[i] < 2^107 */ + + /* ftmp5 = (z1 + z2)**2 - (z1z1 + z2z2) = 2z1z2 */ + felem_square(tmp, ftmp5); + felem_reduce(ftmp5, tmp); + /* ftmp2 = z2z2 + z1z1 */ + felem_sum(ftmp2, ftmp); + /* ftmp2[i] < 2^101 + 2^101 = 2^102 */ + felem_diff(ftmp5, ftmp2); + /* ftmp5[i] < 2^105 + 2^101 < 2^106 */ + + /* ftmp2 = z2 * z2z2 */ + smallfelem_mul(tmp, small2, z2); + felem_reduce(ftmp2, tmp); + + /* s1 = ftmp2 = y1 * z2**3 */ + felem_mul(tmp, y1, ftmp2); + felem_reduce(ftmp6, tmp); + /* ftmp6[i] < 2^101 */ + } else { + /* We'll assume z2 = 1 (special case z2 = 0 is handled later). */ + + /* u1 = ftmp3 = x1*z2z2 */ + felem_assign(ftmp3, x1); + /* ftmp3[i] < 2^106 */ + + /* ftmp5 = 2z1z2 */ + felem_assign(ftmp5, z1); + felem_scalar(ftmp5, 2); + /* ftmp5[i] < 2*2^106 = 2^107 */ + + /* s1 = ftmp2 = y1 * z2**3 */ + felem_assign(ftmp6, y1); + /* ftmp6[i] < 2^106 */ + } + + /* u2 = x2*z1z1 */ + smallfelem_mul(tmp, x2, small1); + felem_reduce(ftmp4, tmp); + + /* h = ftmp4 = u2 - u1 */ + felem_diff_zero107(ftmp4, ftmp3); + /* ftmp4[i] < 2^107 + 2^101 < 2^108 */ + felem_shrink(small4, ftmp4); + + x_equal = smallfelem_is_zero(small4); + + /* z_out = ftmp5 * h */ + felem_small_mul(tmp, small4, ftmp5); + felem_reduce(z_out, tmp); + /* z_out[i] < 2^101 */ + + /* ftmp = z1 * z1z1 */ + smallfelem_mul(tmp, small1, small3); + felem_reduce(ftmp, tmp); + + /* s2 = tmp = y2 * z1**3 */ + felem_small_mul(tmp, y2, ftmp); + felem_reduce(ftmp5, tmp); + + /* r = ftmp5 = (s2 - s1)*2 */ + felem_diff_zero107(ftmp5, ftmp6); + /* ftmp5[i] < 2^107 + 2^107 = 2^108 */ + felem_scalar(ftmp5, 2); + /* ftmp5[i] < 2^109 */ + felem_shrink(small1, ftmp5); + y_equal = smallfelem_is_zero(small1); + + if (x_equal && y_equal && !z1_is_zero && !z2_is_zero) { + point_double(x3, y3, z3, x1, y1, z1); + return; + } + + /* I = ftmp = (2h)**2 */ + felem_assign(ftmp, ftmp4); + felem_scalar(ftmp, 2); + /* ftmp[i] < 2*2^108 = 2^109 */ + felem_square(tmp, ftmp); + felem_reduce(ftmp, tmp); + + /* J = ftmp2 = h * I */ + felem_mul(tmp, ftmp4, ftmp); + felem_reduce(ftmp2, tmp); + + /* V = ftmp4 = U1 * I */ + felem_mul(tmp, ftmp3, ftmp); + felem_reduce(ftmp4, tmp); + + /* x_out = r**2 - J - 2V */ + smallfelem_square(tmp, small1); + felem_reduce(x_out, tmp); + felem_assign(ftmp3, ftmp4); + felem_scalar(ftmp4, 2); + felem_sum(ftmp4, ftmp2); + /* ftmp4[i] < 2*2^101 + 2^101 < 2^103 */ + felem_diff(x_out, ftmp4); + /* x_out[i] < 2^105 + 2^101 */ + + /* y_out = r(V-x_out) - 2 * s1 * J */ + felem_diff_zero107(ftmp3, x_out); + /* ftmp3[i] < 2^107 + 2^101 < 2^108 */ + felem_small_mul(tmp, small1, ftmp3); + felem_mul(tmp2, ftmp6, ftmp2); + longfelem_scalar(tmp2, 2); + /* tmp2[i] < 2*2^67 = 2^68 */ + longfelem_diff(tmp, tmp2); + /* tmp[i] < 2^67 + 2^70 + 2^40 < 2^71 */ + felem_reduce_zero105(y_out, tmp); + /* y_out[i] < 2^106 */ + + copy_small_conditional(x_out, x2, z1_is_zero); + copy_conditional(x_out, x1, z2_is_zero); + copy_small_conditional(y_out, y2, z1_is_zero); + copy_conditional(y_out, y1, z2_is_zero); + copy_small_conditional(z_out, z2, z1_is_zero); + copy_conditional(z_out, z1, z2_is_zero); + felem_assign(x3, x_out); + felem_assign(y3, y_out); + felem_assign(z3, z_out); +} + +/* point_add_small is the same as point_add, except that it operates on + * smallfelems. */ +static void point_add_small(smallfelem x3, smallfelem y3, smallfelem z3, + smallfelem x1, smallfelem y1, smallfelem z1, + smallfelem x2, smallfelem y2, smallfelem z2) { + felem felem_x3, felem_y3, felem_z3; + felem felem_x1, felem_y1, felem_z1; + smallfelem_expand(felem_x1, x1); + smallfelem_expand(felem_y1, y1); + smallfelem_expand(felem_z1, z1); + point_add(felem_x3, felem_y3, felem_z3, felem_x1, felem_y1, felem_z1, 0, x2, + y2, z2); + felem_shrink(x3, felem_x3); + felem_shrink(y3, felem_y3); + felem_shrink(z3, felem_z3); +} + +/* Base point pre computation + * -------------------------- + * + * Two different sorts of precomputed tables are used in the following code. + * Each contain various points on the curve, where each point is three field + * elements (x, y, z). + * + * For the base point table, z is usually 1 (0 for the point at infinity). + * This table has 2 * 16 elements, starting with the following: + * index | bits | point + * ------+---------+------------------------------ + * 0 | 0 0 0 0 | 0G + * 1 | 0 0 0 1 | 1G + * 2 | 0 0 1 0 | 2^64G + * 3 | 0 0 1 1 | (2^64 + 1)G + * 4 | 0 1 0 0 | 2^128G + * 5 | 0 1 0 1 | (2^128 + 1)G + * 6 | 0 1 1 0 | (2^128 + 2^64)G + * 7 | 0 1 1 1 | (2^128 + 2^64 + 1)G + * 8 | 1 0 0 0 | 2^192G + * 9 | 1 0 0 1 | (2^192 + 1)G + * 10 | 1 0 1 0 | (2^192 + 2^64)G + * 11 | 1 0 1 1 | (2^192 + 2^64 + 1)G + * 12 | 1 1 0 0 | (2^192 + 2^128)G + * 13 | 1 1 0 1 | (2^192 + 2^128 + 1)G + * 14 | 1 1 1 0 | (2^192 + 2^128 + 2^64)G + * 15 | 1 1 1 1 | (2^192 + 2^128 + 2^64 + 1)G + * followed by a copy of this with each element multiplied by 2^32. + * + * The reason for this is so that we can clock bits into four different + * locations when doing simple scalar multiplies against the base point, + * and then another four locations using the second 16 elements. + * + * Tables for other points have table[i] = iG for i in 0 .. 16. */ + +/* gmul is the table of precomputed base points */ +static const smallfelem gmul[2][16][3] = { + {{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, + {{0xf4a13945d898c296, 0x77037d812deb33a0, 0xf8bce6e563a440f2, + 0x6b17d1f2e12c4247}, + {0xcbb6406837bf51f5, 0x2bce33576b315ece, 0x8ee7eb4a7c0f9e16, + 0x4fe342e2fe1a7f9b}, + {1, 0, 0, 0}}, + {{0x90e75cb48e14db63, 0x29493baaad651f7e, 0x8492592e326e25de, + 0x0fa822bc2811aaa5}, + {0xe41124545f462ee7, 0x34b1a65050fe82f5, 0x6f4ad4bcb3df188b, + 0xbff44ae8f5dba80d}, + {1, 0, 0, 0}}, + {{0x93391ce2097992af, 0xe96c98fd0d35f1fa, 0xb257c0de95e02789, + 0x300a4bbc89d6726f}, + {0xaa54a291c08127a0, 0x5bb1eeada9d806a5, 0x7f1ddb25ff1e3c6f, + 0x72aac7e0d09b4644}, + {1, 0, 0, 0}}, + {{0x57c84fc9d789bd85, 0xfc35ff7dc297eac3, 0xfb982fd588c6766e, + 0x447d739beedb5e67}, + {0x0c7e33c972e25b32, 0x3d349b95a7fae500, 0xe12e9d953a4aaff7, + 0x2d4825ab834131ee}, + {1, 0, 0, 0}}, + {{0x13949c932a1d367f, 0xef7fbd2b1a0a11b7, 0xddc6068bb91dfc60, + 0xef9519328a9c72ff}, + {0x196035a77376d8a8, 0x23183b0895ca1740, 0xc1ee9807022c219c, + 0x611e9fc37dbb2c9b}, + {1, 0, 0, 0}}, + {{0xcae2b1920b57f4bc, 0x2936df5ec6c9bc36, 0x7dea6482e11238bf, + 0x550663797b51f5d8}, + {0x44ffe216348a964c, 0x9fb3d576dbdefbe1, 0x0afa40018d9d50e5, + 0x157164848aecb851}, + {1, 0, 0, 0}}, + {{0xe48ecafffc5cde01, 0x7ccd84e70d715f26, 0xa2e8f483f43e4391, + 0xeb5d7745b21141ea}, + {0xcac917e2731a3479, 0x85f22cfe2844b645, 0x0990e6a158006cee, + 0xeafd72ebdbecc17b}, + {1, 0, 0, 0}}, + {{0x6cf20ffb313728be, 0x96439591a3c6b94a, 0x2736ff8344315fc5, + 0xa6d39677a7849276}, + {0xf2bab833c357f5f4, 0x824a920c2284059b, 0x66b8babd2d27ecdf, + 0x674f84749b0b8816}, + {1, 0, 0, 0}}, + {{0x2df48c04677c8a3e, 0x74e02f080203a56b, 0x31855f7db8c7fedb, + 0x4e769e7672c9ddad}, + {0xa4c36165b824bbb0, 0xfb9ae16f3b9122a5, 0x1ec0057206947281, + 0x42b99082de830663}, + {1, 0, 0, 0}}, + {{0x6ef95150dda868b9, 0xd1f89e799c0ce131, 0x7fdc1ca008a1c478, + 0x78878ef61c6ce04d}, + {0x9c62b9121fe0d976, 0x6ace570ebde08d4f, 0xde53142c12309def, + 0xb6cb3f5d7b72c321}, + {1, 0, 0, 0}}, + {{0x7f991ed2c31a3573, 0x5b82dd5bd54fb496, 0x595c5220812ffcae, + 0x0c88bc4d716b1287}, + {0x3a57bf635f48aca8, 0x7c8181f4df2564f3, 0x18d1b5b39c04e6aa, + 0xdd5ddea3f3901dc6}, + {1, 0, 0, 0}}, + {{0xe96a79fb3e72ad0c, 0x43a0a28c42ba792f, 0xefe0a423083e49f3, + 0x68f344af6b317466}, + {0xcdfe17db3fb24d4a, 0x668bfc2271f5c626, 0x604ed93c24d67ff3, + 0x31b9c405f8540a20}, + {1, 0, 0, 0}}, + {{0xd36b4789a2582e7f, 0x0d1a10144ec39c28, 0x663c62c3edbad7a0, + 0x4052bf4b6f461db9}, + {0x235a27c3188d25eb, 0xe724f33999bfcc5b, 0x862be6bd71d70cc8, + 0xfecf4d5190b0fc61}, + {1, 0, 0, 0}}, + {{0x74346c10a1d4cfac, 0xafdf5cc08526a7a4, 0x123202a8f62bff7a, + 0x1eddbae2c802e41a}, + {0x8fa0af2dd603f844, 0x36e06b7e4c701917, 0x0c45f45273db33a0, + 0x43104d86560ebcfc}, + {1, 0, 0, 0}}, + {{0x9615b5110d1d78e5, 0x66b0de3225c4744b, 0x0a4a46fb6aaf363a, + 0xb48e26b484f7a21c}, + {0x06ebb0f621a01b2d, 0xc004e4048b7b0f98, 0x64131bcdfed6f668, + 0xfac015404d4d3dab}, + {1, 0, 0, 0}}}, + {{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, + {{0x3a5a9e22185a5943, 0x1ab919365c65dfb6, 0x21656b32262c71da, + 0x7fe36b40af22af89}, + {0xd50d152c699ca101, 0x74b3d5867b8af212, 0x9f09f40407dca6f1, + 0xe697d45825b63624}, + {1, 0, 0, 0}}, + {{0xa84aa9397512218e, 0xe9a521b074ca0141, 0x57880b3a18a2e902, + 0x4a5b506612a677a6}, + {0x0beada7a4c4f3840, 0x626db15419e26d9d, 0xc42604fbe1627d40, + 0xeb13461ceac089f1}, + {1, 0, 0, 0}}, + {{0xf9faed0927a43281, 0x5e52c4144103ecbc, 0xc342967aa815c857, + 0x0781b8291c6a220a}, + {0x5a8343ceeac55f80, 0x88f80eeee54a05e3, 0x97b2a14f12916434, + 0x690cde8df0151593}, + {1, 0, 0, 0}}, + {{0xaee9c75df7f82f2a, 0x9e4c35874afdf43a, 0xf5622df437371326, + 0x8a535f566ec73617}, + {0xc5f9a0ac223094b7, 0xcde533864c8c7669, 0x37e02819085a92bf, + 0x0455c08468b08bd7}, + {1, 0, 0, 0}}, + {{0x0c0a6e2c9477b5d9, 0xf9a4bf62876dc444, 0x5050a949b6cdc279, + 0x06bada7ab77f8276}, + {0xc8b4aed1ea48dac9, 0xdebd8a4b7ea1070f, 0x427d49101366eb70, + 0x5b476dfd0e6cb18a}, + {1, 0, 0, 0}}, + {{0x7c5c3e44278c340a, 0x4d54606812d66f3b, 0x29a751b1ae23c5d8, + 0x3e29864e8a2ec908}, + {0x142d2a6626dbb850, 0xad1744c4765bd780, 0x1f150e68e322d1ed, + 0x239b90ea3dc31e7e}, + {1, 0, 0, 0}}, + {{0x78c416527a53322a, 0x305dde6709776f8e, 0xdbcab759f8862ed4, + 0x820f4dd949f72ff7}, + {0x6cc544a62b5debd4, 0x75be5d937b4e8cc4, 0x1b481b1b215c14d3, + 0x140406ec783a05ec}, + {1, 0, 0, 0}}, + {{0x6a703f10e895df07, 0xfd75f3fa01876bd8, 0xeb5b06e70ce08ffe, + 0x68f6b8542783dfee}, + {0x90c76f8a78712655, 0xcf5293d2f310bf7f, 0xfbc8044dfda45028, + 0xcbe1feba92e40ce6}, + {1, 0, 0, 0}}, + {{0xe998ceea4396e4c1, 0xfc82ef0b6acea274, 0x230f729f2250e927, + 0xd0b2f94d2f420109}, + {0x4305adddb38d4966, 0x10b838f8624c3b45, 0x7db2636658954e7a, + 0x971459828b0719e5}, + {1, 0, 0, 0}}, + {{0x4bd6b72623369fc9, 0x57f2929e53d0b876, 0xc2d5cba4f2340687, + 0x961610004a866aba}, + {0x49997bcd2e407a5e, 0x69ab197d92ddcb24, 0x2cf1f2438fe5131c, + 0x7acb9fadcee75e44}, + {1, 0, 0, 0}}, + {{0x254e839423d2d4c0, 0xf57f0c917aea685b, 0xa60d880f6f75aaea, + 0x24eb9acca333bf5b}, + {0xe3de4ccb1cda5dea, 0xfeef9341c51a6b4f, 0x743125f88bac4c4d, + 0x69f891c5acd079cc}, + {1, 0, 0, 0}}, + {{0xeee44b35702476b5, 0x7ed031a0e45c2258, 0xb422d1e7bd6f8514, + 0xe51f547c5972a107}, + {0xa25bcd6fc9cf343d, 0x8ca922ee097c184e, 0xa62f98b3a9fe9a06, + 0x1c309a2b25bb1387}, + {1, 0, 0, 0}}, + {{0x9295dbeb1967c459, 0xb00148833472c98e, 0xc504977708011828, + 0x20b87b8aa2c4e503}, + {0x3063175de057c277, 0x1bd539338fe582dd, 0x0d11adef5f69a044, + 0xf5c6fa49919776be}, + {1, 0, 0, 0}}, + {{0x8c944e760fd59e11, 0x3876cba1102fad5f, 0xa454c3fad83faa56, + 0x1ed7d1b9332010b9}, + {0xa1011a270024b889, 0x05e4d0dcac0cd344, 0x52b520f0eb6a2a24, + 0x3a2b03f03217257a}, + {1, 0, 0, 0}}, + {{0xf20fc2afdf1d043d, 0xf330240db58d5a62, 0xfc7d229ca0058c3b, + 0x15fee545c78dd9f6}, + {0x501e82885bc98cda, 0x41ef80e5d046ac04, 0x557d9f49461210fb, + 0x4ab5b6b2b8753f81}, + {1, 0, 0, 0}}}}; + +/* select_point selects the |idx|th point from a precomputation table and + * copies it to out. */ +static void select_point(const u64 idx, unsigned int size, + const smallfelem pre_comp[16][3], smallfelem out[3]) { + unsigned i, j; + u64 *outlimbs = &out[0][0]; + memset(outlimbs, 0, 3 * sizeof(smallfelem)); + + for (i = 0; i < size; i++) { + const u64 *inlimbs = (u64 *)&pre_comp[i][0][0]; + u64 mask = i ^ idx; + mask |= mask >> 4; + mask |= mask >> 2; + mask |= mask >> 1; + mask &= 1; + mask--; + for (j = 0; j < NLIMBS * 3; j++) { + outlimbs[j] |= inlimbs[j] & mask; + } + } +} + +/* get_bit returns the |i|th bit in |in| */ +static char get_bit(const felem_bytearray in, int i) { + if (i < 0 || i >= 256) { + return 0; + } + return (in[i >> 3] >> (i & 7)) & 1; +} + +/* Interleaved point multiplication using precomputed point multiples: The + * small point multiples 0*P, 1*P, ..., 17*P are in pre_comp[], the scalars + * in scalars[]. If g_scalar is non-NULL, we also add this multiple of the + * generator, using certain (large) precomputed multiples in g_pre_comp. + * Output point (X, Y, Z) is stored in x_out, y_out, z_out. */ +static void batch_mul(felem x_out, felem y_out, felem z_out, + const felem_bytearray scalars[], + const unsigned num_points, const u8 *g_scalar, + const int mixed, const smallfelem pre_comp[][17][3], + const smallfelem g_pre_comp[2][16][3]) { + int i, skip; + unsigned num, gen_mul = (g_scalar != NULL); + felem nq[3], ftmp; + smallfelem tmp[3]; + u64 bits; + u8 sign, digit; + + /* set nq to the point at infinity */ + memset(nq, 0, 3 * sizeof(felem)); + + /* Loop over all scalars msb-to-lsb, interleaving additions of multiples + * of the generator (two in each of the last 32 rounds) and additions of + * other points multiples (every 5th round). */ + + skip = 1; /* save two point operations in the first + * round */ + for (i = (num_points ? 255 : 31); i >= 0; --i) { + /* double */ + if (!skip) { + point_double(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2]); + } + + /* add multiples of the generator */ + if (gen_mul && i <= 31) { + /* first, look 32 bits upwards */ + bits = get_bit(g_scalar, i + 224) << 3; + bits |= get_bit(g_scalar, i + 160) << 2; + bits |= get_bit(g_scalar, i + 96) << 1; + bits |= get_bit(g_scalar, i + 32); + /* select the point to add, in constant time */ + select_point(bits, 16, g_pre_comp[1], tmp); + + if (!skip) { + /* Arg 1 below is for "mixed" */ + point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 1, tmp[0], tmp[1], + tmp[2]); + } else { + smallfelem_expand(nq[0], tmp[0]); + smallfelem_expand(nq[1], tmp[1]); + smallfelem_expand(nq[2], tmp[2]); + skip = 0; + } + + /* second, look at the current position */ + bits = get_bit(g_scalar, i + 192) << 3; + bits |= get_bit(g_scalar, i + 128) << 2; + bits |= get_bit(g_scalar, i + 64) << 1; + bits |= get_bit(g_scalar, i); + /* select the point to add, in constant time */ + select_point(bits, 16, g_pre_comp[0], tmp); + /* Arg 1 below is for "mixed" */ + point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], 1, tmp[0], tmp[1], + tmp[2]); + } + + /* do other additions every 5 doublings */ + if (num_points && (i % 5 == 0)) { + /* loop over all scalars */ + for (num = 0; num < num_points; ++num) { + bits = get_bit(scalars[num], i + 4) << 5; + bits |= get_bit(scalars[num], i + 3) << 4; + bits |= get_bit(scalars[num], i + 2) << 3; + bits |= get_bit(scalars[num], i + 1) << 2; + bits |= get_bit(scalars[num], i) << 1; + bits |= get_bit(scalars[num], i - 1); + ec_GFp_nistp_recode_scalar_bits(&sign, &digit, bits); + + /* select the point to add or subtract, in constant time. */ + select_point(digit, 17, pre_comp[num], tmp); + smallfelem_neg(ftmp, tmp[1]); /* (X, -Y, Z) is the negative + * point */ + copy_small_conditional(ftmp, tmp[1], (((limb)sign) - 1)); + felem_contract(tmp[1], ftmp); + + if (!skip) { + point_add(nq[0], nq[1], nq[2], nq[0], nq[1], nq[2], mixed, tmp[0], + tmp[1], tmp[2]); + } else { + smallfelem_expand(nq[0], tmp[0]); + smallfelem_expand(nq[1], tmp[1]); + smallfelem_expand(nq[2], tmp[2]); + skip = 0; + } + } + } + } + felem_assign(x_out, nq[0]); + felem_assign(y_out, nq[1]); + felem_assign(z_out, nq[2]); +} + +/* Precomputation for the group generator. */ +typedef struct { + smallfelem g_pre_comp[2][16][3]; +} NISTP256_PRE_COMP; + +/******************************************************************************/ +/* + * OPENSSL EC_METHOD FUNCTIONS + */ + +int ec_GFp_nistp256_group_init(EC_GROUP *group) { + int ret = ec_GFp_simple_group_init(group); + group->a_is_minus3 = 1; + return ret; +} + +int ec_GFp_nistp256_group_set_curve(EC_GROUP *group, const BIGNUM *p, + const BIGNUM *a, const BIGNUM *b, + BN_CTX *ctx) { + int ret = 0; + BN_CTX *new_ctx = NULL; + BIGNUM *curve_p, *curve_a, *curve_b; + + if (ctx == NULL) { + if ((ctx = new_ctx = BN_CTX_new()) == NULL) { + return 0; + } + } + BN_CTX_start(ctx); + if (((curve_p = BN_CTX_get(ctx)) == NULL) || + ((curve_a = BN_CTX_get(ctx)) == NULL) || + ((curve_b = BN_CTX_get(ctx)) == NULL)) { + goto err; + } + BN_bin2bn(nistp256_curve_params[0], sizeof(felem_bytearray), curve_p); + BN_bin2bn(nistp256_curve_params[1], sizeof(felem_bytearray), curve_a); + BN_bin2bn(nistp256_curve_params[2], sizeof(felem_bytearray), curve_b); + if (BN_cmp(curve_p, p) || + BN_cmp(curve_a, a) || + BN_cmp(curve_b, b)) { + OPENSSL_PUT_ERROR(EC, EC_R_WRONG_CURVE_PARAMETERS); + goto err; + } + ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx); + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +/* Takes the Jacobian coordinates (X, Y, Z) of a point and returns (X', Y') = + * (X/Z^2, Y/Z^3). */ +int ec_GFp_nistp256_point_get_affine_coordinates(const EC_GROUP *group, + const EC_POINT *point, + BIGNUM *x, BIGNUM *y, + BN_CTX *ctx) { + felem z1, z2, x_in, y_in; + smallfelem x_out, y_out; + longfelem tmp; + + if (EC_POINT_is_at_infinity(group, point)) { + OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY); + return 0; + } + if (!BN_to_felem(x_in, &point->X) || + !BN_to_felem(y_in, &point->Y) || + !BN_to_felem(z1, &point->Z)) { + return 0; + } + felem_inv(z2, z1); + felem_square(tmp, z2); + felem_reduce(z1, tmp); + felem_mul(tmp, x_in, z1); + felem_reduce(x_in, tmp); + felem_contract(x_out, x_in); + if (x != NULL && !smallfelem_to_BN(x, x_out)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + return 0; + } + felem_mul(tmp, z1, z2); + felem_reduce(z1, tmp); + felem_mul(tmp, y_in, z1); + felem_reduce(y_in, tmp); + felem_contract(y_out, y_in); + if (y != NULL && !smallfelem_to_BN(y, y_out)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + return 0; + } + return 1; +} + +/* points below is of size |num|, and tmp_smallfelems is of size |num+1| */ +static void make_points_affine(size_t num, smallfelem points[][3], + smallfelem tmp_smallfelems[]) { + /* Runs in constant time, unless an input is the point at infinity (which + * normally shouldn't happen). */ + ec_GFp_nistp_points_make_affine_internal( + num, points, sizeof(smallfelem), tmp_smallfelems, + (void (*)(void *))smallfelem_one, + (int (*)(const void *))smallfelem_is_zero_int, + (void (*)(void *, const void *))smallfelem_assign, + (void (*)(void *, const void *))smallfelem_square_contract, + (void (*)(void *, const void *, const void *))smallfelem_mul_contract, + (void (*)(void *, const void *))smallfelem_inv_contract, + /* nothing to contract */ + (void (*)(void *, const void *))smallfelem_assign); +} + +/* Computes scalar*generator + \sum scalars[i]*points[i], ignoring NULL + * values Result is stored in r (r can equal one of the inputs). */ +int ec_GFp_nistp256_points_mul(const EC_GROUP *group, EC_POINT *r, + const BIGNUM *scalar, size_t num, + const EC_POINT *points[], + const BIGNUM *scalars[], BN_CTX *ctx) { + int ret = 0; + int j; + int mixed = 0; + BN_CTX *new_ctx = NULL; + BIGNUM *x, *y, *z, *tmp_scalar; + felem_bytearray g_secret; + felem_bytearray *secrets = NULL; + smallfelem(*pre_comp)[17][3] = NULL; + smallfelem *tmp_smallfelems = NULL; + felem_bytearray tmp; + unsigned i, num_bytes; + int have_pre_comp = 0; + size_t num_points = num; + smallfelem x_in, y_in, z_in; + felem x_out, y_out, z_out; + const smallfelem(*g_pre_comp)[16][3] = NULL; + EC_POINT *generator = NULL; + const EC_POINT *p = NULL; + const BIGNUM *p_scalar = NULL; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + if ((x = BN_CTX_get(ctx)) == NULL || + (y = BN_CTX_get(ctx)) == NULL || + (z = BN_CTX_get(ctx)) == NULL || + (tmp_scalar = BN_CTX_get(ctx)) == NULL) { + goto err; + } + + if (scalar != NULL) { + /* try to use the standard precomputation */ + g_pre_comp = &gmul[0]; + generator = EC_POINT_new(group); + if (generator == NULL) { + goto err; + } + /* get the generator from precomputation */ + if (!smallfelem_to_BN(x, g_pre_comp[0][1][0]) || + !smallfelem_to_BN(y, g_pre_comp[0][1][1]) || + !smallfelem_to_BN(z, g_pre_comp[0][1][2])) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + if (!ec_point_set_Jprojective_coordinates_GFp(group, generator, x, y, z, + ctx)) { + goto err; + } + if (0 == EC_POINT_cmp(group, generator, group->generator, ctx)) { + /* precomputation matches generator */ + have_pre_comp = 1; + } else { + /* we don't have valid precomputation: treat the generator as a + * random point. */ + num_points++; + } + } + + if (num_points > 0) { + if (num_points >= 3) { + /* unless we precompute multiples for just one or two points, + * converting those into affine form is time well spent */ + mixed = 1; + } + secrets = OPENSSL_malloc(num_points * sizeof(felem_bytearray)); + pre_comp = OPENSSL_malloc(num_points * 17 * 3 * sizeof(smallfelem)); + if (mixed) { + tmp_smallfelems = + OPENSSL_malloc((num_points * 17 + 1) * sizeof(smallfelem)); + } + if (secrets == NULL || pre_comp == NULL || + (mixed && tmp_smallfelems == NULL)) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* we treat NULL scalars as 0, and NULL points as points at infinity, + * i.e., they contribute nothing to the linear combination. */ + memset(secrets, 0, num_points * sizeof(felem_bytearray)); + memset(pre_comp, 0, num_points * 17 * 3 * sizeof(smallfelem)); + for (i = 0; i < num_points; ++i) { + if (i == num) { + /* we didn't have a valid precomputation, so we pick the generator. */ + p = EC_GROUP_get0_generator(group); + p_scalar = scalar; + } else { + /* the i^th point */ + p = points[i]; + p_scalar = scalars[i]; + } + if (p_scalar != NULL && p != NULL) { + /* reduce scalar to 0 <= scalar < 2^256 */ + if (BN_num_bits(p_scalar) > 256 || BN_is_negative(p_scalar)) { + /* this is an unusual input, and we don't guarantee + * constant-timeness. */ + if (!BN_nnmod(tmp_scalar, p_scalar, &group->order, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + num_bytes = BN_bn2bin(tmp_scalar, tmp); + } else { + num_bytes = BN_bn2bin(p_scalar, tmp); + } + flip_endian(secrets[i], tmp, num_bytes); + /* precompute multiples */ + if (!BN_to_felem(x_out, &p->X) || + !BN_to_felem(y_out, &p->Y) || + !BN_to_felem(z_out, &p->Z)) { + goto err; + } + felem_shrink(pre_comp[i][1][0], x_out); + felem_shrink(pre_comp[i][1][1], y_out); + felem_shrink(pre_comp[i][1][2], z_out); + for (j = 2; j <= 16; ++j) { + if (j & 1) { + point_add_small(pre_comp[i][j][0], pre_comp[i][j][1], + pre_comp[i][j][2], pre_comp[i][1][0], + pre_comp[i][1][1], pre_comp[i][1][2], + pre_comp[i][j - 1][0], pre_comp[i][j - 1][1], + pre_comp[i][j - 1][2]); + } else { + point_double_small(pre_comp[i][j][0], pre_comp[i][j][1], + pre_comp[i][j][2], pre_comp[i][j / 2][0], + pre_comp[i][j / 2][1], pre_comp[i][j / 2][2]); + } + } + } + } + if (mixed) { + make_points_affine(num_points * 17, pre_comp[0], tmp_smallfelems); + } + } + + /* the scalar for the generator */ + if (scalar != NULL && have_pre_comp) { + memset(g_secret, 0, sizeof(g_secret)); + /* reduce scalar to 0 <= scalar < 2^256 */ + if (BN_num_bits(scalar) > 256 || BN_is_negative(scalar)) { + /* this is an unusual input, and we don't guarantee + * constant-timeness. */ + if (!BN_nnmod(tmp_scalar, scalar, &group->order, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + num_bytes = BN_bn2bin(tmp_scalar, tmp); + } else { + num_bytes = BN_bn2bin(scalar, tmp); + } + flip_endian(g_secret, tmp, num_bytes); + /* do the multiplication with generator precomputation */ + batch_mul(x_out, y_out, z_out, (const felem_bytearray(*))secrets, + num_points, g_secret, mixed, (const smallfelem(*)[17][3])pre_comp, + g_pre_comp); + } else { + /* do the multiplication without generator precomputation */ + batch_mul(x_out, y_out, z_out, (const felem_bytearray(*))secrets, + num_points, NULL, mixed, (const smallfelem(*)[17][3])pre_comp, + NULL); + } + + /* reduce the output to its unique minimal representation */ + felem_contract(x_in, x_out); + felem_contract(y_in, y_out); + felem_contract(z_in, z_out); + if (!smallfelem_to_BN(x, x_in) || + !smallfelem_to_BN(y, y_in) || + !smallfelem_to_BN(z, z_in)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + ret = ec_point_set_Jprojective_coordinates_GFp(group, r, x, y, z, ctx); + +err: + BN_CTX_end(ctx); + EC_POINT_free(generator); + BN_CTX_free(new_ctx); + OPENSSL_free(secrets); + OPENSSL_free(pre_comp); + OPENSSL_free(tmp_smallfelems); + return ret; +} + +const EC_METHOD *EC_GFp_nistp256_method(void) { + static const EC_METHOD ret = { + EC_FLAGS_DEFAULT_OCT, + ec_GFp_nistp256_group_init, + ec_GFp_simple_group_finish, + ec_GFp_simple_group_clear_finish, + ec_GFp_simple_group_copy, ec_GFp_nistp256_group_set_curve, + ec_GFp_simple_group_get_curve, ec_GFp_simple_group_get_degree, + ec_GFp_simple_group_check_discriminant, ec_GFp_simple_point_init, + ec_GFp_simple_point_finish, ec_GFp_simple_point_clear_finish, + ec_GFp_simple_point_copy, ec_GFp_simple_point_set_to_infinity, + ec_GFp_simple_set_Jprojective_coordinates_GFp, + ec_GFp_simple_get_Jprojective_coordinates_GFp, + ec_GFp_simple_point_set_affine_coordinates, + ec_GFp_nistp256_point_get_affine_coordinates, + 0 /* point_set_compressed_coordinates */, 0 /* point2oct */, + 0 /* oct2point */, ec_GFp_simple_add, ec_GFp_simple_dbl, + ec_GFp_simple_invert, ec_GFp_simple_is_at_infinity, + ec_GFp_simple_is_on_curve, ec_GFp_simple_cmp, ec_GFp_simple_make_affine, + ec_GFp_simple_points_make_affine, ec_GFp_nistp256_points_mul, + 0 /* precompute_mult */, 0 /* have_precompute_mult */, + ec_GFp_simple_field_mul, ec_GFp_simple_field_sqr, 0 /* field_div */, + 0 /* field_encode */, 0 /* field_decode */, 0 /* field_set_to_one */ + }; + + return &ret; +} + +#endif /* 64_BIT && !WINDOWS */ diff --git a/TMessagesProj/jni/boringssl/crypto/ec/simple.c b/TMessagesProj/jni/boringssl/crypto/ec/simple.c new file mode 100644 index 00000000..c62199c1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/simple.c @@ -0,0 +1,1357 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#include + +#include + +#include +#include +#include + +#include "internal.h" + + +const EC_METHOD *EC_GFp_simple_method(void) { + static const EC_METHOD ret = {EC_FLAGS_DEFAULT_OCT, + ec_GFp_simple_group_init, + ec_GFp_simple_group_finish, + ec_GFp_simple_group_clear_finish, + ec_GFp_simple_group_copy, + ec_GFp_simple_group_set_curve, + ec_GFp_simple_group_get_curve, + ec_GFp_simple_group_get_degree, + ec_GFp_simple_group_check_discriminant, + ec_GFp_simple_point_init, + ec_GFp_simple_point_finish, + ec_GFp_simple_point_clear_finish, + ec_GFp_simple_point_copy, + ec_GFp_simple_point_set_to_infinity, + ec_GFp_simple_set_Jprojective_coordinates_GFp, + ec_GFp_simple_get_Jprojective_coordinates_GFp, + ec_GFp_simple_point_set_affine_coordinates, + ec_GFp_simple_point_get_affine_coordinates, + 0, + 0, + 0, + ec_GFp_simple_add, + ec_GFp_simple_dbl, + ec_GFp_simple_invert, + ec_GFp_simple_is_at_infinity, + ec_GFp_simple_is_on_curve, + ec_GFp_simple_cmp, + ec_GFp_simple_make_affine, + ec_GFp_simple_points_make_affine, + 0 /* mul */, + 0 /* precompute_mult */, + 0 /* have_precompute_mult */, + ec_GFp_simple_field_mul, + ec_GFp_simple_field_sqr, + 0 /* field_div */, + 0 /* field_encode */, + 0 /* field_decode */, + 0 /* field_set_to_one */}; + + return &ret; +} + + +/* Most method functions in this file are designed to work with non-trivial + * representations of field elements if necessary (see ecp_mont.c): while + * standard modular addition and subtraction are used, the field_mul and + * field_sqr methods will be used for multiplication, and field_encode and + * field_decode (if defined) will be used for converting between + * representations. + + * Functions ec_GFp_simple_points_make_affine() and + * ec_GFp_simple_point_get_affine_coordinates() specifically assume that if a + * non-trivial representation is used, it is a Montgomery representation (i.e. + * 'encoding' means multiplying by some factor R). */ + +int ec_GFp_simple_group_init(EC_GROUP *group) { + BN_init(&group->field); + BN_init(&group->a); + BN_init(&group->b); + group->a_is_minus3 = 0; + return 1; +} + +void ec_GFp_simple_group_finish(EC_GROUP *group) { + BN_free(&group->field); + BN_free(&group->a); + BN_free(&group->b); +} + +void ec_GFp_simple_group_clear_finish(EC_GROUP *group) { + BN_clear_free(&group->field); + BN_clear_free(&group->a); + BN_clear_free(&group->b); +} + +int ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src) { + if (!BN_copy(&dest->field, &src->field) || + !BN_copy(&dest->a, &src->a) || + !BN_copy(&dest->b, &src->b)) { + return 0; + } + + dest->a_is_minus3 = src->a_is_minus3; + return 1; +} + +int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p, + const BIGNUM *a, const BIGNUM *b, + BN_CTX *ctx) { + int ret = 0; + BN_CTX *new_ctx = NULL; + BIGNUM *tmp_a; + + /* p must be a prime > 3 */ + if (BN_num_bits(p) <= 2 || !BN_is_odd(p)) { + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FIELD); + return 0; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + tmp_a = BN_CTX_get(ctx); + if (tmp_a == NULL) { + goto err; + } + + /* group->field */ + if (!BN_copy(&group->field, p)) { + goto err; + } + BN_set_negative(&group->field, 0); + + /* group->a */ + if (!BN_nnmod(tmp_a, a, p, ctx)) { + goto err; + } + if (group->meth->field_encode) { + if (!group->meth->field_encode(group, &group->a, tmp_a, ctx)) { + goto err; + } + } else if (!BN_copy(&group->a, tmp_a)) { + goto err; + } + + /* group->b */ + if (!BN_nnmod(&group->b, b, p, ctx)) { + goto err; + } + if (group->meth->field_encode && + !group->meth->field_encode(group, &group->b, &group->b, ctx)) { + goto err; + } + + /* group->a_is_minus3 */ + if (!BN_add_word(tmp_a, 3)) { + goto err; + } + group->a_is_minus3 = (0 == BN_cmp(tmp_a, &group->field)); + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p, BIGNUM *a, + BIGNUM *b, BN_CTX *ctx) { + int ret = 0; + BN_CTX *new_ctx = NULL; + + if (p != NULL && !BN_copy(p, &group->field)) { + return 0; + } + + if (a != NULL || b != NULL) { + if (group->meth->field_decode) { + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + if (a != NULL && !group->meth->field_decode(group, a, &group->a, ctx)) { + goto err; + } + if (b != NULL && !group->meth->field_decode(group, b, &group->b, ctx)) { + goto err; + } + } else { + if (a != NULL && !BN_copy(a, &group->a)) { + goto err; + } + if (b != NULL && !BN_copy(b, &group->b)) { + goto err; + } + } + } + + ret = 1; + +err: + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_group_get_degree(const EC_GROUP *group) { + return BN_num_bits(&group->field); +} + +int ec_GFp_simple_group_check_discriminant(const EC_GROUP *group, BN_CTX *ctx) { + int ret = 0; + BIGNUM *a, *b, *order, *tmp_1, *tmp_2; + const BIGNUM *p = &group->field; + BN_CTX *new_ctx = NULL; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + } + BN_CTX_start(ctx); + a = BN_CTX_get(ctx); + b = BN_CTX_get(ctx); + tmp_1 = BN_CTX_get(ctx); + tmp_2 = BN_CTX_get(ctx); + order = BN_CTX_get(ctx); + if (order == NULL) { + goto err; + } + + if (group->meth->field_decode) { + if (!group->meth->field_decode(group, a, &group->a, ctx) || + !group->meth->field_decode(group, b, &group->b, ctx)) { + goto err; + } + } else { + if (!BN_copy(a, &group->a) || !BN_copy(b, &group->b)) { + goto err; + } + } + + /* check the discriminant: + * y^2 = x^3 + a*x + b is an elliptic curve <=> 4*a^3 + 27*b^2 != 0 (mod p) + * 0 =< a, b < p */ + if (BN_is_zero(a)) { + if (BN_is_zero(b)) { + goto err; + } + } else if (!BN_is_zero(b)) { + if (!BN_mod_sqr(tmp_1, a, p, ctx) || + !BN_mod_mul(tmp_2, tmp_1, a, p, ctx) || + !BN_lshift(tmp_1, tmp_2, 2)) { + goto err; + } + /* tmp_1 = 4*a^3 */ + + if (!BN_mod_sqr(tmp_2, b, p, ctx) || + !BN_mul_word(tmp_2, 27)) { + goto err; + } + /* tmp_2 = 27*b^2 */ + + if (!BN_mod_add(a, tmp_1, tmp_2, p, ctx) || + BN_is_zero(a)) { + goto err; + } + } + ret = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + } + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_point_init(EC_POINT *point) { + BN_init(&point->X); + BN_init(&point->Y); + BN_init(&point->Z); + point->Z_is_one = 0; + + return 1; +} + +void ec_GFp_simple_point_finish(EC_POINT *point) { + BN_free(&point->X); + BN_free(&point->Y); + BN_free(&point->Z); +} + +void ec_GFp_simple_point_clear_finish(EC_POINT *point) { + BN_clear_free(&point->X); + BN_clear_free(&point->Y); + BN_clear_free(&point->Z); + point->Z_is_one = 0; +} + +int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) { + if (!BN_copy(&dest->X, &src->X) || + !BN_copy(&dest->Y, &src->Y) || + !BN_copy(&dest->Z, &src->Z)) { + return 0; + } + dest->Z_is_one = src->Z_is_one; + + return 1; +} + +int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *group, + EC_POINT *point) { + point->Z_is_one = 0; + BN_zero(&point->Z); + return 1; +} + +int ec_GFp_simple_set_Jprojective_coordinates_GFp( + const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, const BIGNUM *y, + const BIGNUM *z, BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + int ret = 0; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + if (x != NULL) { + if (!BN_nnmod(&point->X, x, &group->field, ctx)) { + goto err; + } + if (group->meth->field_encode && + !group->meth->field_encode(group, &point->X, &point->X, ctx)) { + goto err; + } + } + + if (y != NULL) { + if (!BN_nnmod(&point->Y, y, &group->field, ctx)) { + goto err; + } + if (group->meth->field_encode && + !group->meth->field_encode(group, &point->Y, &point->Y, ctx)) { + goto err; + } + } + + if (z != NULL) { + int Z_is_one; + + if (!BN_nnmod(&point->Z, z, &group->field, ctx)) { + goto err; + } + Z_is_one = BN_is_one(&point->Z); + if (group->meth->field_encode) { + if (Z_is_one && (group->meth->field_set_to_one != 0)) { + if (!group->meth->field_set_to_one(group, &point->Z, ctx)) { + goto err; + } + } else if (!group->meth->field_encode(group, &point->Z, &point->Z, ctx)) { + goto err; + } + } + point->Z_is_one = Z_is_one; + } + + ret = 1; + +err: + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_get_Jprojective_coordinates_GFp(const EC_GROUP *group, + const EC_POINT *point, + BIGNUM *x, BIGNUM *y, + BIGNUM *z, BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + int ret = 0; + + if (group->meth->field_decode != 0) { + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + if (x != NULL && !group->meth->field_decode(group, x, &point->X, ctx)) { + goto err; + } + if (y != NULL && !group->meth->field_decode(group, y, &point->Y, ctx)) { + goto err; + } + if (z != NULL && !group->meth->field_decode(group, z, &point->Z, ctx)) { + goto err; + } + } else { + if (x != NULL && !BN_copy(x, &point->X)) { + goto err; + } + if (y != NULL && !BN_copy(y, &point->Y)) { + goto err; + } + if (z != NULL && !BN_copy(z, &point->Z)) { + goto err; + } + } + + ret = 1; + +err: + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group, + EC_POINT *point, const BIGNUM *x, + const BIGNUM *y, BN_CTX *ctx) { + if (x == NULL || y == NULL) { + /* unlike for projective coordinates, we do not tolerate this */ + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + return ec_point_set_Jprojective_coordinates_GFp(group, point, x, y, + BN_value_one(), ctx); +} + +int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group, + const EC_POINT *point, BIGNUM *x, + BIGNUM *y, BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + BIGNUM *Z, *Z_1, *Z_2, *Z_3; + const BIGNUM *Z_; + int ret = 0; + + if (EC_POINT_is_at_infinity(group, point)) { + OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY); + return 0; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + Z = BN_CTX_get(ctx); + Z_1 = BN_CTX_get(ctx); + Z_2 = BN_CTX_get(ctx); + Z_3 = BN_CTX_get(ctx); + if (Z == NULL || Z_1 == NULL || Z_2 == NULL || Z_3 == NULL) { + goto err; + } + + /* transform (X, Y, Z) into (x, y) := (X/Z^2, Y/Z^3) */ + + if (group->meth->field_decode) { + if (!group->meth->field_decode(group, Z, &point->Z, ctx)) { + goto err; + } + Z_ = Z; + } else { + Z_ = &point->Z; + } + + if (BN_is_one(Z_)) { + if (group->meth->field_decode) { + if (x != NULL && !group->meth->field_decode(group, x, &point->X, ctx)) { + goto err; + } + if (y != NULL && !group->meth->field_decode(group, y, &point->Y, ctx)) { + goto err; + } + } else { + if (x != NULL && !BN_copy(x, &point->X)) { + goto err; + } + if (y != NULL && !BN_copy(y, &point->Y)) { + goto err; + } + } + } else { + if (!BN_mod_inverse(Z_1, Z_, &group->field, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + + if (group->meth->field_encode == 0) { + /* field_sqr works on standard representation */ + if (!group->meth->field_sqr(group, Z_2, Z_1, ctx)) { + goto err; + } + } else if (!BN_mod_sqr(Z_2, Z_1, &group->field, ctx)) { + goto err; + } + + /* in the Montgomery case, field_mul will cancel out Montgomery factor in + * X: */ + if (x != NULL && !group->meth->field_mul(group, x, &point->X, Z_2, ctx)) { + goto err; + } + + if (y != NULL) { + if (group->meth->field_encode == 0) { + /* field_mul works on standard representation */ + if (!group->meth->field_mul(group, Z_3, Z_2, Z_1, ctx)) { + goto err; + } + } else if (!BN_mod_mul(Z_3, Z_2, Z_1, &group->field, ctx)) { + goto err; + } + + /* in the Montgomery case, field_mul will cancel out Montgomery factor in + * Y: */ + if (!group->meth->field_mul(group, y, &point->Y, Z_3, ctx)) { + goto err; + } + } + } + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, + const EC_POINT *b, BN_CTX *ctx) { + int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, + BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); + const BIGNUM *p; + BN_CTX *new_ctx = NULL; + BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6; + int ret = 0; + + if (a == b) { + return EC_POINT_dbl(group, r, a, ctx); + } + if (EC_POINT_is_at_infinity(group, a)) { + return EC_POINT_copy(r, b); + } + if (EC_POINT_is_at_infinity(group, b)) { + return EC_POINT_copy(r, a); + } + + field_mul = group->meth->field_mul; + field_sqr = group->meth->field_sqr; + p = &group->field; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + n0 = BN_CTX_get(ctx); + n1 = BN_CTX_get(ctx); + n2 = BN_CTX_get(ctx); + n3 = BN_CTX_get(ctx); + n4 = BN_CTX_get(ctx); + n5 = BN_CTX_get(ctx); + n6 = BN_CTX_get(ctx); + if (n6 == NULL) { + goto end; + } + + /* Note that in this function we must not read components of 'a' or 'b' + * once we have written the corresponding components of 'r'. + * ('r' might be one of 'a' or 'b'.) + */ + + /* n1, n2 */ + if (b->Z_is_one) { + if (!BN_copy(n1, &a->X) || !BN_copy(n2, &a->Y)) { + goto end; + } + /* n1 = X_a */ + /* n2 = Y_a */ + } else { + if (!field_sqr(group, n0, &b->Z, ctx) || + !field_mul(group, n1, &a->X, n0, ctx)) { + goto end; + } + /* n1 = X_a * Z_b^2 */ + + if (!field_mul(group, n0, n0, &b->Z, ctx) || + !field_mul(group, n2, &a->Y, n0, ctx)) { + goto end; + } + /* n2 = Y_a * Z_b^3 */ + } + + /* n3, n4 */ + if (a->Z_is_one) { + if (!BN_copy(n3, &b->X) || !BN_copy(n4, &b->Y)) { + goto end; + } + /* n3 = X_b */ + /* n4 = Y_b */ + } else { + if (!field_sqr(group, n0, &a->Z, ctx) || + !field_mul(group, n3, &b->X, n0, ctx)) { + goto end; + } + /* n3 = X_b * Z_a^2 */ + + if (!field_mul(group, n0, n0, &a->Z, ctx) || + !field_mul(group, n4, &b->Y, n0, ctx)) { + goto end; + } + /* n4 = Y_b * Z_a^3 */ + } + + /* n5, n6 */ + if (!BN_mod_sub_quick(n5, n1, n3, p) || + !BN_mod_sub_quick(n6, n2, n4, p)) { + goto end; + } + /* n5 = n1 - n3 */ + /* n6 = n2 - n4 */ + + if (BN_is_zero(n5)) { + if (BN_is_zero(n6)) { + /* a is the same point as b */ + BN_CTX_end(ctx); + ret = EC_POINT_dbl(group, r, a, ctx); + ctx = NULL; + goto end; + } else { + /* a is the inverse of b */ + BN_zero(&r->Z); + r->Z_is_one = 0; + ret = 1; + goto end; + } + } + + /* 'n7', 'n8' */ + if (!BN_mod_add_quick(n1, n1, n3, p) || + !BN_mod_add_quick(n2, n2, n4, p)) { + goto end; + } + /* 'n7' = n1 + n3 */ + /* 'n8' = n2 + n4 */ + + /* Z_r */ + if (a->Z_is_one && b->Z_is_one) { + if (!BN_copy(&r->Z, n5)) { + goto end; + } + } else { + if (a->Z_is_one) { + if (!BN_copy(n0, &b->Z)) { + goto end; + } + } else if (b->Z_is_one) { + if (!BN_copy(n0, &a->Z)) { + goto end; + } + } else if (!field_mul(group, n0, &a->Z, &b->Z, ctx)) { + goto end; + } + if (!field_mul(group, &r->Z, n0, n5, ctx)) { + goto end; + } + } + r->Z_is_one = 0; + /* Z_r = Z_a * Z_b * n5 */ + + /* X_r */ + if (!field_sqr(group, n0, n6, ctx) || + !field_sqr(group, n4, n5, ctx) || + !field_mul(group, n3, n1, n4, ctx) || + !BN_mod_sub_quick(&r->X, n0, n3, p)) { + goto end; + } + /* X_r = n6^2 - n5^2 * 'n7' */ + + /* 'n9' */ + if (!BN_mod_lshift1_quick(n0, &r->X, p) || + !BN_mod_sub_quick(n0, n3, n0, p)) { + goto end; + } + /* n9 = n5^2 * 'n7' - 2 * X_r */ + + /* Y_r */ + if (!field_mul(group, n0, n0, n6, ctx) || + !field_mul(group, n5, n4, n5, ctx)) { + goto end; /* now n5 is n5^3 */ + } + if (!field_mul(group, n1, n2, n5, ctx) || + !BN_mod_sub_quick(n0, n0, n1, p)) { + goto end; + } + if (BN_is_odd(n0) && !BN_add(n0, n0, p)) { + goto end; + } + /* now 0 <= n0 < 2*p, and n0 is even */ + if (!BN_rshift1(&r->Y, n0)) { + goto end; + } + /* Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 */ + + ret = 1; + +end: + if (ctx) { + /* otherwise we already called BN_CTX_end */ + BN_CTX_end(ctx); + } + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, + BN_CTX *ctx) { + int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, + BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); + const BIGNUM *p; + BN_CTX *new_ctx = NULL; + BIGNUM *n0, *n1, *n2, *n3; + int ret = 0; + + if (EC_POINT_is_at_infinity(group, a)) { + BN_zero(&r->Z); + r->Z_is_one = 0; + return 1; + } + + field_mul = group->meth->field_mul; + field_sqr = group->meth->field_sqr; + p = &group->field; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + n0 = BN_CTX_get(ctx); + n1 = BN_CTX_get(ctx); + n2 = BN_CTX_get(ctx); + n3 = BN_CTX_get(ctx); + if (n3 == NULL) { + goto err; + } + + /* Note that in this function we must not read components of 'a' + * once we have written the corresponding components of 'r'. + * ('r' might the same as 'a'.) + */ + + /* n1 */ + if (a->Z_is_one) { + if (!field_sqr(group, n0, &a->X, ctx) || + !BN_mod_lshift1_quick(n1, n0, p) || + !BN_mod_add_quick(n0, n0, n1, p) || + !BN_mod_add_quick(n1, n0, &group->a, p)) { + goto err; + } + /* n1 = 3 * X_a^2 + a_curve */ + } else if (group->a_is_minus3) { + if (!field_sqr(group, n1, &a->Z, ctx) || + !BN_mod_add_quick(n0, &a->X, n1, p) || + !BN_mod_sub_quick(n2, &a->X, n1, p) || + !field_mul(group, n1, n0, n2, ctx) || + !BN_mod_lshift1_quick(n0, n1, p) || + !BN_mod_add_quick(n1, n0, n1, p)) { + goto err; + } + /* n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2) + * = 3 * X_a^2 - 3 * Z_a^4 */ + } else { + if (!field_sqr(group, n0, &a->X, ctx) || + !BN_mod_lshift1_quick(n1, n0, p) || + !BN_mod_add_quick(n0, n0, n1, p) || + !field_sqr(group, n1, &a->Z, ctx) || + !field_sqr(group, n1, n1, ctx) || + !field_mul(group, n1, n1, &group->a, ctx) || + !BN_mod_add_quick(n1, n1, n0, p)) { + goto err; + } + /* n1 = 3 * X_a^2 + a_curve * Z_a^4 */ + } + + /* Z_r */ + if (a->Z_is_one) { + if (!BN_copy(n0, &a->Y)) { + goto err; + } + } else if (!field_mul(group, n0, &a->Y, &a->Z, ctx)) { + goto err; + } + if (!BN_mod_lshift1_quick(&r->Z, n0, p)) { + goto err; + } + r->Z_is_one = 0; + /* Z_r = 2 * Y_a * Z_a */ + + /* n2 */ + if (!field_sqr(group, n3, &a->Y, ctx) || + !field_mul(group, n2, &a->X, n3, ctx) || + !BN_mod_lshift_quick(n2, n2, 2, p)) { + goto err; + } + /* n2 = 4 * X_a * Y_a^2 */ + + /* X_r */ + if (!BN_mod_lshift1_quick(n0, n2, p) || + !field_sqr(group, &r->X, n1, ctx) || + !BN_mod_sub_quick(&r->X, &r->X, n0, p)) { + goto err; + } + /* X_r = n1^2 - 2 * n2 */ + + /* n3 */ + if (!field_sqr(group, n0, n3, ctx) || + !BN_mod_lshift_quick(n3, n0, 3, p)) { + goto err; + } + /* n3 = 8 * Y_a^4 */ + + /* Y_r */ + if (!BN_mod_sub_quick(n0, n2, &r->X, p) || + !field_mul(group, n0, n1, n0, ctx) || + !BN_mod_sub_quick(&r->Y, n0, n3, p)) { + goto err; + } + /* Y_r = n1 * (n2 - X_r) - n3 */ + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) { + if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(&point->Y)) { + /* point is its own inverse */ + return 1; + } + + return BN_usub(&point->Y, &group->field, &point->Y); +} + +int ec_GFp_simple_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) { + return !point->Z_is_one && BN_is_zero(&point->Z); +} + +int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, + BN_CTX *ctx) { + int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, + BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); + const BIGNUM *p; + BN_CTX *new_ctx = NULL; + BIGNUM *rh, *tmp, *Z4, *Z6; + int ret = -1; + + if (EC_POINT_is_at_infinity(group, point)) { + return 1; + } + + field_mul = group->meth->field_mul; + field_sqr = group->meth->field_sqr; + p = &group->field; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return -1; + } + } + + BN_CTX_start(ctx); + rh = BN_CTX_get(ctx); + tmp = BN_CTX_get(ctx); + Z4 = BN_CTX_get(ctx); + Z6 = BN_CTX_get(ctx); + if (Z6 == NULL) { + goto err; + } + + /* We have a curve defined by a Weierstrass equation + * y^2 = x^3 + a*x + b. + * The point to consider is given in Jacobian projective coordinates + * where (X, Y, Z) represents (x, y) = (X/Z^2, Y/Z^3). + * Substituting this and multiplying by Z^6 transforms the above equation + * into + * Y^2 = X^3 + a*X*Z^4 + b*Z^6. + * To test this, we add up the right-hand side in 'rh'. + */ + + /* rh := X^2 */ + if (!field_sqr(group, rh, &point->X, ctx)) { + goto err; + } + + if (!point->Z_is_one) { + if (!field_sqr(group, tmp, &point->Z, ctx) || + !field_sqr(group, Z4, tmp, ctx) || + !field_mul(group, Z6, Z4, tmp, ctx)) { + goto err; + } + + /* rh := (rh + a*Z^4)*X */ + if (group->a_is_minus3) { + if (!BN_mod_lshift1_quick(tmp, Z4, p) || + !BN_mod_add_quick(tmp, tmp, Z4, p) || + !BN_mod_sub_quick(rh, rh, tmp, p) || + !field_mul(group, rh, rh, &point->X, ctx)) { + goto err; + } + } else { + if (!field_mul(group, tmp, Z4, &group->a, ctx) || + !BN_mod_add_quick(rh, rh, tmp, p) || + !field_mul(group, rh, rh, &point->X, ctx)) { + goto err; + } + } + + /* rh := rh + b*Z^6 */ + if (!field_mul(group, tmp, &group->b, Z6, ctx) || + !BN_mod_add_quick(rh, rh, tmp, p)) { + goto err; + } + } else { + /* point->Z_is_one */ + + /* rh := (rh + a)*X */ + if (!BN_mod_add_quick(rh, rh, &group->a, p) || + !field_mul(group, rh, rh, &point->X, ctx)) { + goto err; + } + /* rh := rh + b */ + if (!BN_mod_add_quick(rh, rh, &group->b, p)) { + goto err; + } + } + + /* 'lh' := Y^2 */ + if (!field_sqr(group, tmp, &point->Y, ctx)) { + goto err; + } + + ret = (0 == BN_ucmp(tmp, rh)); + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, + const EC_POINT *b, BN_CTX *ctx) { + /* return values: + * -1 error + * 0 equal (in affine coordinates) + * 1 not equal + */ + + int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, + BN_CTX *); + int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); + BN_CTX *new_ctx = NULL; + BIGNUM *tmp1, *tmp2, *Za23, *Zb23; + const BIGNUM *tmp1_, *tmp2_; + int ret = -1; + + if (EC_POINT_is_at_infinity(group, a)) { + return EC_POINT_is_at_infinity(group, b) ? 0 : 1; + } + + if (EC_POINT_is_at_infinity(group, b)) { + return 1; + } + + if (a->Z_is_one && b->Z_is_one) { + return ((BN_cmp(&a->X, &b->X) == 0) && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1; + } + + field_mul = group->meth->field_mul; + field_sqr = group->meth->field_sqr; + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return -1; + } + } + + BN_CTX_start(ctx); + tmp1 = BN_CTX_get(ctx); + tmp2 = BN_CTX_get(ctx); + Za23 = BN_CTX_get(ctx); + Zb23 = BN_CTX_get(ctx); + if (Zb23 == NULL) { + goto end; + } + + /* We have to decide whether + * (X_a/Z_a^2, Y_a/Z_a^3) = (X_b/Z_b^2, Y_b/Z_b^3), + * or equivalently, whether + * (X_a*Z_b^2, Y_a*Z_b^3) = (X_b*Z_a^2, Y_b*Z_a^3). + */ + + if (!b->Z_is_one) { + if (!field_sqr(group, Zb23, &b->Z, ctx) || + !field_mul(group, tmp1, &a->X, Zb23, ctx)) { + goto end; + } + tmp1_ = tmp1; + } else { + tmp1_ = &a->X; + } + if (!a->Z_is_one) { + if (!field_sqr(group, Za23, &a->Z, ctx) || + !field_mul(group, tmp2, &b->X, Za23, ctx)) { + goto end; + } + tmp2_ = tmp2; + } else { + tmp2_ = &b->X; + } + + /* compare X_a*Z_b^2 with X_b*Z_a^2 */ + if (BN_cmp(tmp1_, tmp2_) != 0) { + ret = 1; /* points differ */ + goto end; + } + + + if (!b->Z_is_one) { + if (!field_mul(group, Zb23, Zb23, &b->Z, ctx) || + !field_mul(group, tmp1, &a->Y, Zb23, ctx)) { + goto end; + } + /* tmp1_ = tmp1 */ + } else { + tmp1_ = &a->Y; + } + if (!a->Z_is_one) { + if (!field_mul(group, Za23, Za23, &a->Z, ctx) || + !field_mul(group, tmp2, &b->Y, Za23, ctx)) { + goto end; + } + /* tmp2_ = tmp2 */ + } else { + tmp2_ = &b->Y; + } + + /* compare Y_a*Z_b^3 with Y_b*Z_a^3 */ + if (BN_cmp(tmp1_, tmp2_) != 0) { + ret = 1; /* points differ */ + goto end; + } + + /* points are equal */ + ret = 0; + +end: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_make_affine(const EC_GROUP *group, EC_POINT *point, + BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + BIGNUM *x, *y; + int ret = 0; + + if (point->Z_is_one || EC_POINT_is_at_infinity(group, point)) { + return 1; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + if (y == NULL) { + goto err; + } + + if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx) || + !EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) { + goto err; + } + if (!point->Z_is_one) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + return ret; +} + +int ec_GFp_simple_points_make_affine(const EC_GROUP *group, size_t num, + EC_POINT *points[], BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + BIGNUM *tmp, *tmp_Z; + BIGNUM **prod_Z = NULL; + size_t i; + int ret = 0; + + if (num == 0) { + return 1; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } + + BN_CTX_start(ctx); + tmp = BN_CTX_get(ctx); + tmp_Z = BN_CTX_get(ctx); + if (tmp == NULL || tmp_Z == NULL) { + goto err; + } + + prod_Z = OPENSSL_malloc(num * sizeof(prod_Z[0])); + if (prod_Z == NULL) { + goto err; + } + memset(prod_Z, 0, num * sizeof(prod_Z[0])); + for (i = 0; i < num; i++) { + prod_Z[i] = BN_new(); + if (prod_Z[i] == NULL) { + goto err; + } + } + + /* Set each prod_Z[i] to the product of points[0]->Z .. points[i]->Z, + * skipping any zero-valued inputs (pretend that they're 1). */ + + if (!BN_is_zero(&points[0]->Z)) { + if (!BN_copy(prod_Z[0], &points[0]->Z)) { + goto err; + } + } else { + if (group->meth->field_set_to_one != 0) { + if (!group->meth->field_set_to_one(group, prod_Z[0], ctx)) { + goto err; + } + } else { + if (!BN_one(prod_Z[0])) { + goto err; + } + } + } + + for (i = 1; i < num; i++) { + if (!BN_is_zero(&points[i]->Z)) { + if (!group->meth->field_mul(group, prod_Z[i], prod_Z[i - 1], + &points[i]->Z, ctx)) { + goto err; + } + } else { + if (!BN_copy(prod_Z[i], prod_Z[i - 1])) { + goto err; + } + } + } + + /* Now use a single explicit inversion to replace every + * non-zero points[i]->Z by its inverse. */ + + if (!BN_mod_inverse(tmp, prod_Z[num - 1], &group->field, ctx)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + goto err; + } + + if (group->meth->field_encode != NULL) { + /* In the Montgomery case, we just turned R*H (representing H) + * into 1/(R*H), but we need R*(1/H) (representing 1/H); + * i.e. we need to multiply by the Montgomery factor twice. */ + if (!group->meth->field_encode(group, tmp, tmp, ctx) || + !group->meth->field_encode(group, tmp, tmp, ctx)) { + goto err; + } + } + + for (i = num - 1; i > 0; --i) { + /* Loop invariant: tmp is the product of the inverses of + * points[0]->Z .. points[i]->Z (zero-valued inputs skipped). */ + if (BN_is_zero(&points[i]->Z)) { + continue; + } + + /* Set tmp_Z to the inverse of points[i]->Z (as product + * of Z inverses 0 .. i, Z values 0 .. i - 1). */ + if (!group->meth->field_mul(group, tmp_Z, prod_Z[i - 1], tmp, ctx) || + /* Update tmp to satisfy the loop invariant for i - 1. */ + !group->meth->field_mul(group, tmp, tmp, &points[i]->Z, ctx) || + /* Replace points[i]->Z by its inverse. */ + !BN_copy(&points[i]->Z, tmp_Z)) { + goto err; + } + } + + /* Replace points[0]->Z by its inverse. */ + if (!BN_is_zero(&points[0]->Z) && !BN_copy(&points[0]->Z, tmp)) { + goto err; + } + + /* Finally, fix up the X and Y coordinates for all points. */ + for (i = 0; i < num; i++) { + EC_POINT *p = points[i]; + + if (!BN_is_zero(&p->Z)) { + /* turn (X, Y, 1/Z) into (X/Z^2, Y/Z^3, 1). */ + if (!group->meth->field_sqr(group, tmp, &p->Z, ctx) || + !group->meth->field_mul(group, &p->X, &p->X, tmp, ctx) || + !group->meth->field_mul(group, tmp, tmp, &p->Z, ctx) || + !group->meth->field_mul(group, &p->Y, &p->Y, tmp, ctx)) { + goto err; + } + + if (group->meth->field_set_to_one != NULL) { + if (!group->meth->field_set_to_one(group, &p->Z, ctx)) { + goto err; + } + } else { + if (!BN_one(&p->Z)) { + goto err; + } + } + p->Z_is_one = 1; + } + } + + ret = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(new_ctx); + if (prod_Z != NULL) { + for (i = 0; i < num; i++) { + if (prod_Z[i] == NULL) { + break; + } + BN_clear_free(prod_Z[i]); + } + OPENSSL_free(prod_Z); + } + + return ret; +} + +int ec_GFp_simple_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx) { + return BN_mod_mul(r, a, b, &group->field, ctx); +} + +int ec_GFp_simple_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, + BN_CTX *ctx) { + return BN_mod_sqr(r, a, &group->field, ctx); +} diff --git a/TMessagesProj/jni/boringssl/crypto/ec/util-64.c b/TMessagesProj/jni/boringssl/crypto/ec/util-64.c new file mode 100644 index 00000000..171b0631 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/util-64.c @@ -0,0 +1,183 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + + +#if defined(OPENSSL_64_BIT) && !defined(OPENSSL_WINDOWS) + +#include + +#include "internal.h" + +/* Convert an array of points into affine coordinates. (If the point at + * infinity is found (Z = 0), it remains unchanged.) This function is + * essentially an equivalent to EC_POINTs_make_affine(), but works with the + * internal representation of points as used by ecp_nistp###.c rather than + * with (BIGNUM-based) EC_POINT data structures. point_array is the + * input/output buffer ('num' points in projective form, i.e. three + * coordinates each), based on an internal representation of field elements + * of size 'felem_size'. tmp_felems needs to point to a temporary array of + * 'num'+1 field elements for storage of intermediate values. */ +void ec_GFp_nistp_points_make_affine_internal( + size_t num, void *point_array, size_t felem_size, void *tmp_felems, + void (*felem_one)(void *out), int (*felem_is_zero)(const void *in), + void (*felem_assign)(void *out, const void *in), + void (*felem_square)(void *out, const void *in), + void (*felem_mul)(void *out, const void *in1, const void *in2), + void (*felem_inv)(void *out, const void *in), + void (*felem_contract)(void *out, const void *in)) { + int i = 0; + +#define tmp_felem(I) (&((char *)tmp_felems)[(I)*felem_size]) +#define X(I) (&((char *)point_array)[3 * (I)*felem_size]) +#define Y(I) (&((char *)point_array)[(3 * (I) + 1) * felem_size]) +#define Z(I) (&((char *)point_array)[(3 * (I) + 2) * felem_size]) + + if (!felem_is_zero(Z(0))) { + felem_assign(tmp_felem(0), Z(0)); + } else { + felem_one(tmp_felem(0)); + } + + for (i = 1; i < (int)num; i++) { + if (!felem_is_zero(Z(i))) { + felem_mul(tmp_felem(i), tmp_felem(i - 1), Z(i)); + } else { + felem_assign(tmp_felem(i), tmp_felem(i - 1)); + } + } + /* Now each tmp_felem(i) is the product of Z(0) .. Z(i), skipping any + * zero-valued factors: if Z(i) = 0, we essentially pretend that Z(i) = 1. */ + + felem_inv(tmp_felem(num - 1), tmp_felem(num - 1)); + for (i = num - 1; i >= 0; i--) { + if (i > 0) { + /* tmp_felem(i-1) is the product of Z(0) .. Z(i-1), tmp_felem(i) + * is the inverse of the product of Z(0) .. Z(i). */ + /* 1/Z(i) */ + felem_mul(tmp_felem(num), tmp_felem(i - 1), tmp_felem(i)); + } else { + felem_assign(tmp_felem(num), tmp_felem(0)); /* 1/Z(0) */ + } + + if (!felem_is_zero(Z(i))) { + if (i > 0) { + /* For next iteration, replace tmp_felem(i-1) by its inverse. */ + felem_mul(tmp_felem(i - 1), tmp_felem(i), Z(i)); + } + + /* Convert point (X, Y, Z) into affine form (X/(Z^2), Y/(Z^3), 1). */ + felem_square(Z(i), tmp_felem(num)); /* 1/(Z^2) */ + felem_mul(X(i), X(i), Z(i)); /* X/(Z^2) */ + felem_mul(Z(i), Z(i), tmp_felem(num)); /* 1/(Z^3) */ + felem_mul(Y(i), Y(i), Z(i)); /* Y/(Z^3) */ + felem_contract(X(i), X(i)); + felem_contract(Y(i), Y(i)); + felem_one(Z(i)); + } else { + if (i > 0) { + /* For next iteration, replace tmp_felem(i-1) by its inverse. */ + felem_assign(tmp_felem(i - 1), tmp_felem(i)); + } + } + } +} + +/* This function looks at 5+1 scalar bits (5 current, 1 adjacent less + * significant bit), and recodes them into a signed digit for use in fast point + * multiplication: the use of signed rather than unsigned digits means that + * fewer points need to be precomputed, given that point inversion is easy (a + * precomputed point dP makes -dP available as well). + * + * BACKGROUND: + * + * Signed digits for multiplication were introduced by Booth ("A signed binary + * multiplication technique", Quart. Journ. Mech. and Applied Math., vol. IV, + * pt. 2 (1951), pp. 236-240), in that case for multiplication of integers. + * Booth's original encoding did not generally improve the density of nonzero + * digits over the binary representation, and was merely meant to simplify the + * handling of signed factors given in two's complement; but it has since been + * shown to be the basis of various signed-digit representations that do have + * further advantages, including the wNAF, using the following general + * approach: + * + * (1) Given a binary representation + * + * b_k ... b_2 b_1 b_0, + * + * of a nonnegative integer (b_k in {0, 1}), rewrite it in digits 0, 1, -1 + * by using bit-wise subtraction as follows: + * + * b_k b_(k-1) ... b_2 b_1 b_0 + * - b_k ... b_3 b_2 b_1 b_0 + * ------------------------------------- + * s_k b_(k-1) ... s_3 s_2 s_1 s_0 + * + * A left-shift followed by subtraction of the original value yields a new + * representation of the same value, using signed bits s_i = b_(i+1) - b_i. + * This representation from Booth's paper has since appeared in the + * literature under a variety of different names including "reversed binary + * form", "alternating greedy expansion", "mutual opposite form", and + * "sign-alternating {+-1}-representation". + * + * An interesting property is that among the nonzero bits, values 1 and -1 + * strictly alternate. + * + * (2) Various window schemes can be applied to the Booth representation of + * integers: for example, right-to-left sliding windows yield the wNAF + * (a signed-digit encoding independently discovered by various researchers + * in the 1990s), and left-to-right sliding windows yield a left-to-right + * equivalent of the wNAF (independently discovered by various researchers + * around 2004). + * + * To prevent leaking information through side channels in point multiplication, + * we need to recode the given integer into a regular pattern: sliding windows + * as in wNAFs won't do, we need their fixed-window equivalent -- which is a few + * decades older: we'll be using the so-called "modified Booth encoding" due to + * MacSorley ("High-speed arithmetic in binary computers", Proc. IRE, vol. 49 + * (1961), pp. 67-91), in a radix-2^5 setting. That is, we always combine five + * signed bits into a signed digit: + * + * s_(4j + 4) s_(4j + 3) s_(4j + 2) s_(4j + 1) s_(4j) + * + * The sign-alternating property implies that the resulting digit values are + * integers from -16 to 16. + * + * Of course, we don't actually need to compute the signed digits s_i as an + * intermediate step (that's just a nice way to see how this scheme relates + * to the wNAF): a direct computation obtains the recoded digit from the + * six bits b_(4j + 4) ... b_(4j - 1). + * + * This function takes those five bits as an integer (0 .. 63), writing the + * recoded digit to *sign (0 for positive, 1 for negative) and *digit (absolute + * value, in the range 0 .. 8). Note that this integer essentially provides the + * input bits "shifted to the left" by one position: for example, the input to + * compute the least significant recoded digit, given that there's no bit b_-1, + * has to be b_4 b_3 b_2 b_1 b_0 0. */ +void ec_GFp_nistp_recode_scalar_bits(uint8_t *sign, uint8_t *digit, + uint8_t in) { + uint8_t s, d; + + s = ~((in >> 5) - 1); /* sets all bits to MSB(in), 'in' seen as + * 6-bit value */ + d = (1 << 6) - in - 1; + d = (d & s) | (in & ~s); + d = (d >> 1) + (d & 1); + + *sign = s & 1; + *digit = d; +} + +#endif /* 64_BIT && !WINDOWS */ diff --git a/TMessagesProj/jni/boringssl/crypto/ec/wnaf.c b/TMessagesProj/jni/boringssl/crypto/ec/wnaf.c new file mode 100644 index 00000000..7fa0e1bf --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ec/wnaf.c @@ -0,0 +1,853 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#include + +#include + +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +/* This file implements the wNAF-based interleaving multi-exponentation method + * (); + * for multiplication with precomputation, we use wNAF splitting + * (). + * */ + +/* structure for precomputed multiples of the generator */ +typedef struct ec_pre_comp_st { + size_t blocksize; /* block size for wNAF splitting */ + size_t numblocks; /* max. number of blocks for which we have precomputation */ + size_t w; /* window size */ + EC_POINT **points; /* array with pre-calculated multiples of generator: + * 'num' pointers to EC_POINT objects followed by a NULL */ + size_t num; /* numblocks * 2^(w-1) */ + CRYPTO_refcount_t references; +} EC_PRE_COMP; + +static EC_PRE_COMP *ec_pre_comp_new(void) { + EC_PRE_COMP *ret = NULL; + + ret = (EC_PRE_COMP *)OPENSSL_malloc(sizeof(EC_PRE_COMP)); + if (!ret) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + return ret; + } + ret->blocksize = 8; /* default */ + ret->numblocks = 0; + ret->w = 4; /* default */ + ret->points = NULL; + ret->num = 0; + ret->references = 1; + return ret; +} + +void *ec_pre_comp_dup(EC_PRE_COMP *pre_comp) { + if (pre_comp == NULL) { + return NULL; + } + + CRYPTO_refcount_inc(&pre_comp->references); + return pre_comp; +} + +void ec_pre_comp_free(EC_PRE_COMP *pre_comp) { + if (pre_comp == NULL || + !CRYPTO_refcount_dec_and_test_zero(&pre_comp->references)) { + return; + } + + if (pre_comp->points) { + EC_POINT **p; + + for (p = pre_comp->points; *p != NULL; p++) { + EC_POINT_free(*p); + } + OPENSSL_free(pre_comp->points); + } + OPENSSL_free(pre_comp); +} + + +/* Determine the modified width-(w+1) Non-Adjacent Form (wNAF) of 'scalar'. + * This is an array r[] of values that are either zero or odd with an + * absolute value less than 2^w satisfying + * scalar = \sum_j r[j]*2^j + * where at most one of any w+1 consecutive digits is non-zero + * with the exception that the most significant digit may be only + * w-1 zeros away from that next non-zero digit. + */ +static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) { + int window_val; + int ok = 0; + signed char *r = NULL; + int sign = 1; + int bit, next_bit, mask; + size_t len = 0, j; + + if (BN_is_zero(scalar)) { + r = OPENSSL_malloc(1); + if (!r) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + r[0] = 0; + *ret_len = 1; + return r; + } + + if (w <= 0 || w > 7) /* 'signed char' can represent integers with absolute + values less than 2^7 */ + { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + bit = 1 << w; /* at most 128 */ + next_bit = bit << 1; /* at most 256 */ + mask = next_bit - 1; /* at most 255 */ + + if (BN_is_negative(scalar)) { + sign = -1; + } + + if (scalar->d == NULL || scalar->top == 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + + len = BN_num_bits(scalar); + r = OPENSSL_malloc( + len + + 1); /* modified wNAF may be one digit longer than binary representation + * (*ret_len will be set to the actual length, i.e. at most + * BN_num_bits(scalar) + 1) */ + if (r == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + window_val = scalar->d[0] & mask; + j = 0; + while ((window_val != 0) || + (j + w + 1 < len)) /* if j+w+1 >= len, window_val will not increase */ + { + int digit = 0; + + /* 0 <= window_val <= 2^(w+1) */ + + if (window_val & 1) { + /* 0 < window_val < 2^(w+1) */ + + if (window_val & bit) { + digit = window_val - next_bit; /* -2^w < digit < 0 */ + +#if 1 /* modified wNAF */ + if (j + w + 1 >= len) { + /* special case for generating modified wNAFs: + * no new bits will be added into window_val, + * so using a positive digit here will decrease + * the total length of the representation */ + + digit = window_val & (mask >> 1); /* 0 < digit < 2^w */ + } +#endif + } else { + digit = window_val; /* 0 < digit < 2^w */ + } + + if (digit <= -bit || digit >= bit || !(digit & 1)) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + + window_val -= digit; + + /* now window_val is 0 or 2^(w+1) in standard wNAF generation; + * for modified window NAFs, it may also be 2^w + */ + if (window_val != 0 && window_val != next_bit && window_val != bit) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + r[j++] = sign * digit; + + window_val >>= 1; + window_val += bit * BN_is_bit_set(scalar, j + w); + + if (window_val > next_bit) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + } + + if (j > len + 1) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + len = j; + ok = 1; + +err: + if (!ok) { + OPENSSL_free(r); + r = NULL; + } + if (ok) { + *ret_len = len; + } + return r; +} + + +/* TODO: table should be optimised for the wNAF-based implementation, + * sometimes smaller windows will give better performance + * (thus the boundaries should be increased) + */ +#define EC_window_bits_for_scalar_size(b) \ + ((size_t)((b) >= 2000 ? 6 : (b) >= 800 ? 5 : (b) >= 300 \ + ? 4 \ + : (b) >= 70 ? 3 : (b) >= 20 \ + ? 2 \ + : 1)) + +/* Compute + * \sum scalars[i]*points[i], + * also including + * scalar*generator + * in the addition if scalar != NULL + */ +int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *scalar, + size_t num, const EC_POINT *points[], const BIGNUM *scalars[], + BN_CTX *ctx) { + BN_CTX *new_ctx = NULL; + const EC_POINT *generator = NULL; + EC_POINT *tmp = NULL; + size_t totalnum; + size_t blocksize = 0, numblocks = 0; /* for wNAF splitting */ + size_t pre_points_per_block = 0; + size_t i, j; + int k; + int r_is_inverted = 0; + int r_is_at_infinity = 1; + size_t *wsize = NULL; /* individual window sizes */ + signed char **wNAF = NULL; /* individual wNAFs */ + size_t *wNAF_len = NULL; + size_t max_len = 0; + size_t num_val; + EC_POINT **val = NULL; /* precomputation */ + EC_POINT **v; + EC_POINT ***val_sub = + NULL; /* pointers to sub-arrays of 'val' or 'pre_comp->points' */ + const EC_PRE_COMP *pre_comp = NULL; + int num_scalar = 0; /* flag: will be set to 1 if 'scalar' must be treated like + * other scalars, + * i.e. precomputation is not available */ + int ret = 0; + + if (group->meth != r->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + + if ((scalar == NULL) && (num == 0)) { + return EC_POINT_set_to_infinity(group, r); + } + + for (i = 0; i < num; i++) { + if (group->meth != points[i]->meth) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + } + + if (scalar != NULL) { + generator = EC_GROUP_get0_generator(group); + if (generator == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_UNDEFINED_GENERATOR); + goto err; + } + + /* look if we can use precomputed multiples of generator */ + + pre_comp = group->pre_comp; + + if (pre_comp && pre_comp->numblocks && + (EC_POINT_cmp(group, generator, pre_comp->points[0], ctx) == 0)) { + blocksize = pre_comp->blocksize; + + /* determine maximum number of blocks that wNAF splitting may yield + * (NB: maximum wNAF length is bit length plus one) */ + numblocks = (BN_num_bits(scalar) / blocksize) + 1; + + /* we cannot use more blocks than we have precomputation for */ + if (numblocks > pre_comp->numblocks) { + numblocks = pre_comp->numblocks; + } + + pre_points_per_block = (size_t)1 << (pre_comp->w - 1); + + /* check that pre_comp looks sane */ + if (pre_comp->num != (pre_comp->numblocks * pre_points_per_block)) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + } else { + /* can't use precomputation */ + pre_comp = NULL; + numblocks = 1; + num_scalar = 1; /* treat 'scalar' like 'num'-th element of 'scalars' */ + } + } + + totalnum = num + numblocks; + + wsize = OPENSSL_malloc(totalnum * sizeof wsize[0]); + wNAF_len = OPENSSL_malloc(totalnum * sizeof wNAF_len[0]); + wNAF = OPENSSL_malloc((totalnum + 1) * + sizeof wNAF[0]); /* includes space for pivot */ + val_sub = OPENSSL_malloc(totalnum * sizeof val_sub[0]); + + /* Ensure wNAF is initialised in case we end up going to err. */ + if (wNAF) { + wNAF[0] = NULL; /* preliminary pivot */ + } + + if (!wsize || !wNAF_len || !wNAF || !val_sub) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* num_val will be the total number of temporarily precomputed points */ + num_val = 0; + + for (i = 0; i < num + num_scalar; i++) { + size_t bits; + + bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(scalar); + wsize[i] = EC_window_bits_for_scalar_size(bits); + num_val += (size_t)1 << (wsize[i] - 1); + wNAF[i + 1] = NULL; /* make sure we always have a pivot */ + wNAF[i] = + compute_wNAF((i < num ? scalars[i] : scalar), wsize[i], &wNAF_len[i]); + if (wNAF[i] == NULL) { + goto err; + } + if (wNAF_len[i] > max_len) { + max_len = wNAF_len[i]; + } + } + + if (numblocks) { + /* we go here iff scalar != NULL */ + + if (pre_comp == NULL) { + if (num_scalar != 1) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + /* we have already generated a wNAF for 'scalar' */ + } else { + signed char *tmp_wNAF = NULL; + size_t tmp_len = 0; + + if (num_scalar != 0) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* use the window size for which we have precomputation */ + wsize[num] = pre_comp->w; + tmp_wNAF = compute_wNAF(scalar, wsize[num], &tmp_len); + if (!tmp_wNAF) { + goto err; + } + + if (tmp_len <= max_len) { + /* One of the other wNAFs is at least as long + * as the wNAF belonging to the generator, + * so wNAF splitting will not buy us anything. */ + + numblocks = 1; /* don't use wNAF splitting */ + totalnum = num + numblocks; + wNAF[num] = tmp_wNAF; + wNAF[num + 1] = NULL; + wNAF_len[num] = tmp_len; + /* pre_comp->points starts with the points that we need here: */ + val_sub[num] = pre_comp->points; + } else { + /* don't include tmp_wNAF directly into wNAF array + * - use wNAF splitting and include the blocks */ + + signed char *pp; + EC_POINT **tmp_points; + + if (tmp_len < numblocks * blocksize) { + /* possibly we can do with fewer blocks than estimated */ + numblocks = (tmp_len + blocksize - 1) / blocksize; + if (numblocks > pre_comp->numblocks) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + OPENSSL_free(tmp_wNAF); + goto err; + } + totalnum = num + numblocks; + } + + /* split wNAF in 'numblocks' parts */ + pp = tmp_wNAF; + tmp_points = pre_comp->points; + + for (i = num; i < totalnum; i++) { + if (i < totalnum - 1) { + wNAF_len[i] = blocksize; + if (tmp_len < blocksize) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + OPENSSL_free(tmp_wNAF); + goto err; + } + tmp_len -= blocksize; + } else { + /* last block gets whatever is left + * (this could be more or less than 'blocksize'!) */ + wNAF_len[i] = tmp_len; + } + + wNAF[i + 1] = NULL; + wNAF[i] = OPENSSL_malloc(wNAF_len[i]); + if (wNAF[i] == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + OPENSSL_free(tmp_wNAF); + goto err; + } + memcpy(wNAF[i], pp, wNAF_len[i]); + if (wNAF_len[i] > max_len) { + max_len = wNAF_len[i]; + } + + if (*tmp_points == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + OPENSSL_free(tmp_wNAF); + goto err; + } + val_sub[i] = tmp_points; + tmp_points += pre_points_per_block; + pp += blocksize; + } + OPENSSL_free(tmp_wNAF); + } + } + } + + /* All points we precompute now go into a single array 'val'. + * 'val_sub[i]' is a pointer to the subarray for the i-th point, + * or to a subarray of 'pre_comp->points' if we already have precomputation. + */ + val = OPENSSL_malloc((num_val + 1) * sizeof val[0]); + if (val == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + val[num_val] = NULL; /* pivot element */ + + /* allocate points for precomputation */ + v = val; + for (i = 0; i < num + num_scalar; i++) { + val_sub[i] = v; + for (j = 0; j < ((size_t)1 << (wsize[i] - 1)); j++) { + *v = EC_POINT_new(group); + if (*v == NULL) { + goto err; + } + v++; + } + } + if (!(v == val + num_val)) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!(tmp = EC_POINT_new(group))) { + goto err; + } + + /* prepare precomputed values: + * val_sub[i][0] := points[i] + * val_sub[i][1] := 3 * points[i] + * val_sub[i][2] := 5 * points[i] + * ... + */ + for (i = 0; i < num + num_scalar; i++) { + if (i < num) { + if (!EC_POINT_copy(val_sub[i][0], points[i])) { + goto err; + } + } else if (!EC_POINT_copy(val_sub[i][0], generator)) { + goto err; + } + + if (wsize[i] > 1) { + if (!EC_POINT_dbl(group, tmp, val_sub[i][0], ctx)) { + goto err; + } + for (j = 1; j < ((size_t)1 << (wsize[i] - 1)); j++) { + if (!EC_POINT_add(group, val_sub[i][j], val_sub[i][j - 1], tmp, ctx)) { + goto err; + } + } + } + } + +#if 1 /* optional; EC_window_bits_for_scalar_size assumes we do this step */ + if (!EC_POINTs_make_affine(group, num_val, val, ctx)) { + goto err; + } +#endif + + r_is_at_infinity = 1; + + for (k = max_len - 1; k >= 0; k--) { + if (!r_is_at_infinity && !EC_POINT_dbl(group, r, r, ctx)) { + goto err; + } + + for (i = 0; i < totalnum; i++) { + if (wNAF_len[i] > (size_t)k) { + int digit = wNAF[i][k]; + int is_neg; + + if (digit) { + is_neg = digit < 0; + + if (is_neg) { + digit = -digit; + } + + if (is_neg != r_is_inverted) { + if (!r_is_at_infinity && !EC_POINT_invert(group, r, ctx)) { + goto err; + } + r_is_inverted = !r_is_inverted; + } + + /* digit > 0 */ + + if (r_is_at_infinity) { + if (!EC_POINT_copy(r, val_sub[i][digit >> 1])) { + goto err; + } + r_is_at_infinity = 0; + } else { + if (!EC_POINT_add(group, r, r, val_sub[i][digit >> 1], ctx)) { + goto err; + } + } + } + } + } + } + + if (r_is_at_infinity) { + if (!EC_POINT_set_to_infinity(group, r)) { + goto err; + } + } else if (r_is_inverted && !EC_POINT_invert(group, r, ctx)) { + goto err; + } + + ret = 1; + +err: + BN_CTX_free(new_ctx); + EC_POINT_free(tmp); + OPENSSL_free(wsize); + OPENSSL_free(wNAF_len); + if (wNAF != NULL) { + signed char **w; + + for (w = wNAF; *w != NULL; w++) { + OPENSSL_free(*w); + } + + OPENSSL_free(wNAF); + } + if (val != NULL) { + for (v = val; *v != NULL; v++) { + EC_POINT_clear_free(*v); + } + + OPENSSL_free(val); + } + OPENSSL_free(val_sub); + return ret; +} + + +/* ec_wNAF_precompute_mult() + * creates an EC_PRE_COMP object with preprecomputed multiples of the generator + * for use with wNAF splitting as implemented in ec_wNAF_mul(). + * + * 'pre_comp->points' is an array of multiples of the generator + * of the following form: + * points[0] = generator; + * points[1] = 3 * generator; + * ... + * points[2^(w-1)-1] = (2^(w-1)-1) * generator; + * points[2^(w-1)] = 2^blocksize * generator; + * points[2^(w-1)+1] = 3 * 2^blocksize * generator; + * ... + * points[2^(w-1)*(numblocks-1)-1] = (2^(w-1)) * 2^(blocksize*(numblocks-2)) * + *generator + * points[2^(w-1)*(numblocks-1)] = 2^(blocksize*(numblocks-1)) * + *generator + * ... + * points[2^(w-1)*numblocks-1] = (2^(w-1)) * 2^(blocksize*(numblocks-1)) * + *generator + * points[2^(w-1)*numblocks] = NULL + */ +int ec_wNAF_precompute_mult(EC_GROUP *group, BN_CTX *ctx) { + const EC_POINT *generator; + EC_POINT *tmp_point = NULL, *base = NULL, **var; + BN_CTX *new_ctx = NULL; + BIGNUM *order; + size_t i, bits, w, pre_points_per_block, blocksize, numblocks, num; + EC_POINT **points = NULL; + EC_PRE_COMP *pre_comp; + int ret = 0; + + /* if there is an old EC_PRE_COMP object, throw it away */ + ec_pre_comp_free(group->pre_comp); + group->pre_comp = NULL; + + generator = EC_GROUP_get0_generator(group); + if (generator == NULL) { + OPENSSL_PUT_ERROR(EC, EC_R_UNDEFINED_GENERATOR); + return 0; + } + + pre_comp = ec_pre_comp_new(); + if (pre_comp == NULL) { + return 0; + } + + if (ctx == NULL) { + ctx = new_ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + } + + BN_CTX_start(ctx); + order = BN_CTX_get(ctx); + if (order == NULL) { + goto err; + } + + if (!EC_GROUP_get_order(group, order, ctx)) { + goto err; + } + if (BN_is_zero(order)) { + OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_ORDER); + goto err; + } + + bits = BN_num_bits(order); + /* The following parameters mean we precompute (approximately) + * one point per bit. + * + * TBD: The combination 8, 4 is perfect for 160 bits; for other + * bit lengths, other parameter combinations might provide better + * efficiency. + */ + blocksize = 8; + w = 4; + if (EC_window_bits_for_scalar_size(bits) > w) { + /* let's not make the window too small ... */ + w = EC_window_bits_for_scalar_size(bits); + } + + numblocks = (bits + blocksize - 1) / + blocksize; /* max. number of blocks to use for wNAF splitting */ + + pre_points_per_block = (size_t)1 << (w - 1); + num = pre_points_per_block * + numblocks; /* number of points to compute and store */ + + points = OPENSSL_malloc(sizeof(EC_POINT *) * (num + 1)); + if (!points) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + var = points; + var[num] = NULL; /* pivot */ + for (i = 0; i < num; i++) { + if ((var[i] = EC_POINT_new(group)) == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (!(tmp_point = EC_POINT_new(group)) || !(base = EC_POINT_new(group))) { + OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EC_POINT_copy(base, generator)) { + goto err; + } + + /* do the precomputation */ + for (i = 0; i < numblocks; i++) { + size_t j; + + if (!EC_POINT_dbl(group, tmp_point, base, ctx)) { + goto err; + } + + if (!EC_POINT_copy(*var++, base)) { + goto err; + } + + for (j = 1; j < pre_points_per_block; j++, var++) { + /* calculate odd multiples of the current base point */ + if (!EC_POINT_add(group, *var, tmp_point, *(var - 1), ctx)) { + goto err; + } + } + + if (i < numblocks - 1) { + /* get the next base (multiply current one by 2^blocksize) */ + size_t k; + + if (blocksize <= 2) { + OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (!EC_POINT_dbl(group, base, tmp_point, ctx)) { + goto err; + } + for (k = 2; k < blocksize; k++) { + if (!EC_POINT_dbl(group, base, base, ctx)) { + goto err; + } + } + } + } + + if (!EC_POINTs_make_affine(group, num, points, ctx)) { + goto err; + } + + pre_comp->blocksize = blocksize; + pre_comp->numblocks = numblocks; + pre_comp->w = w; + pre_comp->points = points; + points = NULL; + pre_comp->num = num; + + group->pre_comp = pre_comp; + pre_comp = NULL; + + ret = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + } + BN_CTX_free(new_ctx); + ec_pre_comp_free(pre_comp); + if (points) { + EC_POINT **p; + + for (p = points; *p != NULL; p++) { + EC_POINT_free(*p); + } + OPENSSL_free(points); + } + EC_POINT_free(tmp_point); + EC_POINT_free(base); + return ret; +} + + +int ec_wNAF_have_precompute_mult(const EC_GROUP *group) { + return group->pre_comp != NULL; +} diff --git a/TMessagesProj/jni/boringssl/crypto/ecdh/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/ecdh/CMakeLists.txt new file mode 100644 index 00000000..346e72d8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ecdh/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + ecdh + + OBJECT + + ecdh.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/ecdh/ecdh.c b/TMessagesProj/jni/boringssl/crypto/ecdh/ecdh.c new file mode 100644 index 00000000..14856db0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ecdh/ecdh.c @@ -0,0 +1,161 @@ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * The Elliptic Curve Public-Key Crypto Library (ECC Code) included + * herein is developed by SUN MICROSYSTEMS, INC., and is contributed + * to the OpenSSL project. + * + * The ECC Code is licensed pursuant to the OpenSSL open source + * license provided below. + * + * The ECDH software is originally written by Douglas Stebila of + * Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright (c) 2000-2002 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include +#include +#include + + +int ECDH_compute_key(void *out, size_t outlen, const EC_POINT *pub_key, + EC_KEY *priv_key, void *(*KDF)(const void *in, size_t inlen, + void *out, size_t *outlen)) { + BN_CTX *ctx; + EC_POINT *tmp = NULL; + BIGNUM *x = NULL, *y = NULL; + const BIGNUM *priv; + const EC_GROUP *group; + int ret = -1; + size_t buflen; + uint8_t *buf = NULL; + + if ((ctx = BN_CTX_new()) == NULL) { + goto err; + } + BN_CTX_start(ctx); + x = BN_CTX_get(ctx); + y = BN_CTX_get(ctx); + + priv = EC_KEY_get0_private_key(priv_key); + if (priv == NULL) { + OPENSSL_PUT_ERROR(ECDH, ECDH_R_NO_PRIVATE_VALUE); + goto err; + } + + group = EC_KEY_get0_group(priv_key); + + tmp = EC_POINT_new(group); + if (tmp == NULL) { + OPENSSL_PUT_ERROR(ECDH, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EC_POINT_mul(group, tmp, NULL, pub_key, priv, ctx)) { + OPENSSL_PUT_ERROR(ECDH, ECDH_R_POINT_ARITHMETIC_FAILURE); + goto err; + } + + if (!EC_POINT_get_affine_coordinates_GFp(group, tmp, x, y, ctx)) { + OPENSSL_PUT_ERROR(ECDH, ECDH_R_POINT_ARITHMETIC_FAILURE); + goto err; + } + + buflen = (EC_GROUP_get_degree(group) + 7) / 8; + buf = OPENSSL_malloc(buflen); + if (buf == NULL) { + OPENSSL_PUT_ERROR(ECDH, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!BN_bn2bin_padded(buf, buflen, x)) { + OPENSSL_PUT_ERROR(ECDH, ERR_R_INTERNAL_ERROR); + goto err; + } + + if (KDF != 0) { + if (KDF(buf, buflen, out, &outlen) == NULL) { + OPENSSL_PUT_ERROR(ECDH, ECDH_R_KDF_FAILED); + goto err; + } + ret = outlen; + } else { + /* no KDF, just copy as much as we can */ + if (outlen > buflen) { + outlen = buflen; + } + memcpy(out, buf, outlen); + ret = outlen; + } + +err: + if (tmp) { + EC_POINT_free(tmp); + } + if (ctx) { + BN_CTX_end(ctx); + } + if (ctx) { + BN_CTX_free(ctx); + } + if (buf) { + OPENSSL_free(buf); + } + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/ecdsa/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/ecdsa/CMakeLists.txt new file mode 100644 index 00000000..9ed50ddc --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ecdsa/CMakeLists.txt @@ -0,0 +1,10 @@ +include_directories(. .. ../../include) + +add_library( + ecdsa + + OBJECT + + ecdsa.c + ecdsa_asn1.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/ecdsa/ecdsa.c b/TMessagesProj/jni/boringssl/crypto/ecdsa/ecdsa.c new file mode 100644 index 00000000..8403d60e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ecdsa/ecdsa.c @@ -0,0 +1,493 @@ +/* ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include "../ec/internal.h" + + +int ECDSA_sign(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig, + unsigned int *sig_len, EC_KEY *eckey) { + if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) { + return eckey->ecdsa_meth->sign(digest, digest_len, sig, sig_len, eckey); + } + + return ECDSA_sign_ex(type, digest, digest_len, sig, sig_len, NULL, NULL, + eckey); +} + +int ECDSA_verify(int type, const uint8_t *digest, size_t digest_len, + const uint8_t *sig, size_t sig_len, EC_KEY *eckey) { + ECDSA_SIG *s; + int ret = 0; + uint8_t *der = NULL; + + if (eckey->ecdsa_meth && eckey->ecdsa_meth->verify) { + return eckey->ecdsa_meth->verify(digest, digest_len, sig, sig_len, eckey); + } + + /* Decode the ECDSA signature. */ + s = ECDSA_SIG_from_bytes(sig, sig_len); + if (s == NULL) { + goto err; + } + + /* Defend against potential laxness in the DER parser. */ + size_t der_len; + if (!ECDSA_SIG_to_bytes(&der, &der_len, s) || + der_len != sig_len || memcmp(sig, der, sig_len) != 0) { + /* This should never happen. crypto/bytestring is strictly DER. */ + OPENSSL_PUT_ERROR(ECDSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + ret = ECDSA_do_verify(digest, digest_len, s, eckey); + +err: + OPENSSL_free(der); + ECDSA_SIG_free(s); + return ret; +} + +/* digest_to_bn interprets |digest_len| bytes from |digest| as a big-endian + * number and sets |out| to that value. It then truncates |out| so that it's, + * at most, as long as |order|. It returns one on success and zero otherwise. */ +static int digest_to_bn(BIGNUM *out, const uint8_t *digest, size_t digest_len, + const BIGNUM *order) { + size_t num_bits; + + num_bits = BN_num_bits(order); + /* Need to truncate digest if it is too long: first truncate whole + * bytes. */ + if (8 * digest_len > num_bits) { + digest_len = (num_bits + 7) / 8; + } + if (!BN_bin2bn(digest, digest_len, out)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + return 0; + } + + /* If still too long truncate remaining bits with a shift */ + if ((8 * digest_len > num_bits) && + !BN_rshift(out, out, 8 - (num_bits & 0x7))) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + return 0; + } + + return 1; +} + +ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len, + EC_KEY *key) { + return ECDSA_do_sign_ex(digest, digest_len, NULL, NULL, key); +} + +int ECDSA_do_verify(const uint8_t *digest, size_t digest_len, + const ECDSA_SIG *sig, EC_KEY *eckey) { + int ret = 0; + BN_CTX *ctx; + BIGNUM *order, *u1, *u2, *m, *X; + EC_POINT *point = NULL; + const EC_GROUP *group; + const EC_POINT *pub_key; + + if (eckey->ecdsa_meth && eckey->ecdsa_meth->verify) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED); + return 0; + } + + /* check input values */ + if ((group = EC_KEY_get0_group(eckey)) == NULL || + (pub_key = EC_KEY_get0_public_key(eckey)) == NULL || + sig == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_MISSING_PARAMETERS); + return 0; + } + + ctx = BN_CTX_new(); + if (!ctx) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); + return 0; + } + BN_CTX_start(ctx); + order = BN_CTX_get(ctx); + u1 = BN_CTX_get(ctx); + u2 = BN_CTX_get(ctx); + m = BN_CTX_get(ctx); + X = BN_CTX_get(ctx); + if (order == NULL || u1 == NULL || u2 == NULL || m == NULL || X == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + + if (!EC_GROUP_get_order(group, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + + if (BN_is_zero(sig->r) || BN_is_negative(sig->r) || + BN_ucmp(sig->r, order) >= 0 || BN_is_zero(sig->s) || + BN_is_negative(sig->s) || BN_ucmp(sig->s, order) >= 0) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE); + ret = 0; /* signature is invalid */ + goto err; + } + /* calculate tmp1 = inv(S) mod order */ + if (!BN_mod_inverse(u2, sig->s, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + if (!digest_to_bn(m, digest, digest_len, order)) { + goto err; + } + /* u1 = m * tmp mod order */ + if (!BN_mod_mul(u1, m, u2, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + /* u2 = r * w mod q */ + if (!BN_mod_mul(u2, sig->r, u2, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + + point = EC_POINT_new(group); + if (point == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!EC_POINT_mul(group, point, u1, pub_key, u2, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + if (!EC_POINT_get_affine_coordinates_GFp(group, point, X, NULL, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + if (!BN_nnmod(u1, X, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + /* if the signature is correct u1 is equal to sig->r */ + ret = (BN_ucmp(u1, sig->r) == 0); + +err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + EC_POINT_free(point); + return ret; +} + +static int ecdsa_sign_setup(EC_KEY *eckey, BN_CTX *ctx_in, BIGNUM **kinvp, + BIGNUM **rp, const uint8_t *digest, + size_t digest_len) { + BN_CTX *ctx = NULL; + BIGNUM *k = NULL, *r = NULL, *order = NULL, *X = NULL; + EC_POINT *tmp_point = NULL; + const EC_GROUP *group; + int ret = 0; + + if (eckey == NULL || (group = EC_KEY_get0_group(eckey)) == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (ctx_in == NULL) { + if ((ctx = BN_CTX_new()) == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); + return 0; + } + } else { + ctx = ctx_in; + } + + k = BN_new(); /* this value is later returned in *kinvp */ + r = BN_new(); /* this value is later returned in *rp */ + order = BN_new(); + X = BN_new(); + if (!k || !r || !order || !X) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); + goto err; + } + tmp_point = EC_POINT_new(group); + if (tmp_point == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + if (!EC_GROUP_get_order(group, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + + do { + /* If possible, we'll include the private key and message digest in the k + * generation. The |digest| argument is only empty if |ECDSA_sign_setup| is + * being used. */ + do { + int ok; + + if (digest_len > 0) { + ok = BN_generate_dsa_nonce(k, order, EC_KEY_get0_private_key(eckey), + digest, digest_len, ctx); + } else { + ok = BN_rand_range(k, order); + } + if (!ok) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED); + goto err; + } + } while (BN_is_zero(k)); + + /* We do not want timing information to leak the length of k, + * so we compute G*k using an equivalent scalar of fixed + * bit-length. */ + + if (!BN_add(k, k, order)) { + goto err; + } + if (BN_num_bits(k) <= BN_num_bits(order)) { + if (!BN_add(k, k, order)) { + goto err; + } + } + + /* compute r the x-coordinate of generator * k */ + if (!EC_POINT_mul(group, tmp_point, k, NULL, NULL, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + if (!EC_POINT_get_affine_coordinates_GFp(group, tmp_point, X, NULL, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + + if (!BN_nnmod(r, X, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + } while (BN_is_zero(r)); + + /* compute the inverse of k */ + if (!BN_mod_inverse(k, k, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + /* clear old values if necessary */ + BN_clear_free(*rp); + BN_clear_free(*kinvp); + + /* save the pre-computed values */ + *rp = r; + *kinvp = k; + ret = 1; + +err: + if (!ret) { + BN_clear_free(k); + BN_clear_free(r); + } + if (ctx_in == NULL) { + BN_CTX_free(ctx); + } + BN_free(order); + EC_POINT_free(tmp_point); + BN_clear_free(X); + return ret; +} + +int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, BIGNUM **rp) { + return ecdsa_sign_setup(eckey, ctx, kinv, rp, NULL, 0); +} + +ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, size_t digest_len, + const BIGNUM *in_kinv, const BIGNUM *in_r, + EC_KEY *eckey) { + int ok = 0; + BIGNUM *kinv = NULL, *s, *m = NULL, *tmp = NULL, *order = NULL; + const BIGNUM *ckinv; + BN_CTX *ctx = NULL; + const EC_GROUP *group; + ECDSA_SIG *ret; + const BIGNUM *priv_key; + + if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED); + return NULL; + } + + group = EC_KEY_get0_group(eckey); + priv_key = EC_KEY_get0_private_key(eckey); + + if (group == NULL || priv_key == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + + ret = ECDSA_SIG_new(); + if (!ret) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); + return NULL; + } + s = ret->s; + + if ((ctx = BN_CTX_new()) == NULL || (order = BN_new()) == NULL || + (tmp = BN_new()) == NULL || (m = BN_new()) == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EC_GROUP_get_order(group, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_EC_LIB); + goto err; + } + if (!digest_to_bn(m, digest, digest_len, order)) { + goto err; + } + for (;;) { + if (in_kinv == NULL || in_r == NULL) { + if (!ecdsa_sign_setup(eckey, ctx, &kinv, &ret->r, digest, digest_len)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_ECDSA_LIB); + goto err; + } + ckinv = kinv; + } else { + ckinv = in_kinv; + if (BN_copy(ret->r, in_r) == NULL) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (!BN_mod_mul(tmp, priv_key, ret->r, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + if (!BN_mod_add_quick(s, tmp, m, order)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + if (!BN_mod_mul(s, s, ckinv, order, ctx)) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_BN_LIB); + goto err; + } + if (BN_is_zero(s)) { + /* if kinv and r have been supplied by the caller + * don't to generate new kinv and r values */ + if (in_kinv != NULL && in_r != NULL) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NEED_NEW_SETUP_VALUES); + goto err; + } + } else { + /* s != 0 => we have a valid signature */ + break; + } + } + + ok = 1; + +err: + if (!ok) { + ECDSA_SIG_free(ret); + ret = NULL; + } + BN_CTX_free(ctx); + BN_clear_free(m); + BN_clear_free(tmp); + BN_free(order); + BN_clear_free(kinv); + return ret; +} + +int ECDSA_sign_ex(int type, const uint8_t *digest, size_t digest_len, + uint8_t *sig, unsigned int *sig_len, const BIGNUM *kinv, + const BIGNUM *r, EC_KEY *eckey) { + int ret = 0; + ECDSA_SIG *s = NULL; + + if (eckey->ecdsa_meth && eckey->ecdsa_meth->sign) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_NOT_IMPLEMENTED); + *sig_len = 0; + goto err; + } + + s = ECDSA_do_sign_ex(digest, digest_len, kinv, r, eckey); + if (s == NULL) { + *sig_len = 0; + goto err; + } + + CBB cbb; + CBB_zero(&cbb); + size_t len; + if (!CBB_init_fixed(&cbb, sig, ECDSA_size(eckey)) || + !ECDSA_SIG_marshal(&cbb, s) || + !CBB_finish(&cbb, NULL, &len)) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR); + CBB_cleanup(&cbb); + *sig_len = 0; + goto err; + } + *sig_len = (unsigned)len; + ret = 1; + +err: + ECDSA_SIG_free(s); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/ecdsa/ecdsa_asn1.c b/TMessagesProj/jni/boringssl/crypto/ecdsa/ecdsa_asn1.c new file mode 100644 index 00000000..f2d7c363 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ecdsa/ecdsa_asn1.c @@ -0,0 +1,250 @@ +/* ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "../ec/internal.h" + + +size_t ECDSA_size(const EC_KEY *key) { + if (key == NULL) { + return 0; + } + + size_t group_order_size; + if (key->ecdsa_meth && key->ecdsa_meth->group_order_size) { + group_order_size = key->ecdsa_meth->group_order_size(key); + } else { + const EC_GROUP *group = EC_KEY_get0_group(key); + if (group == NULL) { + return 0; + } + + BIGNUM *order = BN_new(); + if (order == NULL) { + return 0; + } + if (!EC_GROUP_get_order(group, order, NULL)) { + BN_clear_free(order); + return 0; + } + + group_order_size = BN_num_bytes(order); + BN_clear_free(order); + } + + return ECDSA_SIG_max_len(group_order_size); +} + +ECDSA_SIG *ECDSA_SIG_new(void) { + ECDSA_SIG *sig = OPENSSL_malloc(sizeof(ECDSA_SIG)); + if (sig == NULL) { + return NULL; + } + sig->r = BN_new(); + sig->s = BN_new(); + if (sig->r == NULL || sig->s == NULL) { + ECDSA_SIG_free(sig); + return NULL; + } + return sig; +} + +void ECDSA_SIG_free(ECDSA_SIG *sig) { + if (sig == NULL) { + return; + } + + BN_free(sig->r); + BN_free(sig->s); + OPENSSL_free(sig); +} + +ECDSA_SIG *ECDSA_SIG_parse(CBS *cbs) { + ECDSA_SIG *ret = ECDSA_SIG_new(); + if (ret == NULL) { + return NULL; + } + CBS child; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || + !BN_cbs2unsigned(&child, ret->r) || + !BN_cbs2unsigned(&child, ret->s) || + CBS_len(&child) != 0) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE); + ECDSA_SIG_free(ret); + return NULL; + } + return ret; +} + +ECDSA_SIG *ECDSA_SIG_from_bytes(const uint8_t *in, size_t in_len) { + CBS cbs; + CBS_init(&cbs, in, in_len); + ECDSA_SIG *ret = ECDSA_SIG_parse(&cbs); + if (ret == NULL || CBS_len(&cbs) != 0) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_BAD_SIGNATURE); + ECDSA_SIG_free(ret); + return NULL; + } + return ret; +} + +int ECDSA_SIG_marshal(CBB *cbb, const ECDSA_SIG *sig) { + CBB child; + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) || + !BN_bn2cbb(&child, sig->r) || + !BN_bn2cbb(&child, sig->s) || + !CBB_flush(cbb)) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR); + return 0; + } + return 1; +} + +int ECDSA_SIG_to_bytes(uint8_t **out_bytes, size_t *out_len, + const ECDSA_SIG *sig) { + CBB cbb; + CBB_zero(&cbb); + if (!CBB_init(&cbb, 0) || + !ECDSA_SIG_marshal(&cbb, sig) || + !CBB_finish(&cbb, out_bytes, out_len)) { + OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR); + CBB_cleanup(&cbb); + return 0; + } + return 1; +} + +/* der_len_len returns the number of bytes needed to represent a length of |len| + * in DER. */ +static size_t der_len_len(size_t len) { + if (len < 0x80) { + return 1; + } + size_t ret = 1; + while (len > 0) { + ret++; + len >>= 8; + } + return ret; +} + +size_t ECDSA_SIG_max_len(size_t order_len) { + /* Compute the maximum length of an |order_len| byte integer. Defensively + * assume that the leading 0x00 is included. */ + size_t integer_len = 1 /* tag */ + der_len_len(order_len + 1) + 1 + order_len; + if (integer_len < order_len) { + return 0; + } + /* An ECDSA signature is two INTEGERs. */ + size_t value_len = 2 * integer_len; + if (value_len < integer_len) { + return 0; + } + /* Add the header. */ + size_t ret = 1 /* tag */ + der_len_len(value_len) + value_len; + if (ret < value_len) { + return 0; + } + return ret; +} + +ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **out, const uint8_t **inp, long len) { + if (len < 0) { + return NULL; + } + CBS cbs; + CBS_init(&cbs, *inp, (size_t)len); + ECDSA_SIG *ret = ECDSA_SIG_parse(&cbs); + if (ret == NULL) { + return NULL; + } + if (out != NULL) { + ECDSA_SIG_free(*out); + *out = ret; + } + *inp += (size_t)len - CBS_len(&cbs); + return ret; +} + +int i2d_ECDSA_SIG(const ECDSA_SIG *sig, uint8_t **outp) { + uint8_t *der; + size_t der_len; + if (!ECDSA_SIG_to_bytes(&der, &der_len, sig)) { + return -1; + } + if (der_len > INT_MAX) { + OPENSSL_PUT_ERROR(ECDSA, ERR_R_OVERFLOW); + OPENSSL_free(der); + return -1; + } + if (outp != NULL) { + if (*outp == NULL) { + *outp = der; + der = NULL; + } else { + memcpy(*outp, der, der_len); + *outp += der_len; + } + } + OPENSSL_free(der); + return (int)der_len; +} diff --git a/TMessagesProj/jni/boringssl/crypto/engine/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/engine/CMakeLists.txt new file mode 100644 index 00000000..e03650e3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/engine/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + engine + + OBJECT + + engine.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/engine/engine.c b/TMessagesProj/jni/boringssl/crypto/engine/engine.c new file mode 100644 index 00000000..6c3300d3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/engine/engine.c @@ -0,0 +1,120 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +struct engine_st { + DH_METHOD *dh_method; + DSA_METHOD *dsa_method; + RSA_METHOD *rsa_method; + ECDSA_METHOD *ecdsa_method; +}; + +ENGINE *ENGINE_new(void) { + ENGINE *engine = OPENSSL_malloc(sizeof(ENGINE)); + if (engine == NULL) { + return NULL; + } + + memset(engine, 0, sizeof(ENGINE)); + return engine; +} + +void ENGINE_free(ENGINE *engine) { + /* Methods are currently required to be static so are not unref'ed. */ + OPENSSL_free(engine); +} + +/* set_method takes a pointer to a method and its given size and sets + * |*out_member| to point to it. This function might want to be extended in the + * future to support making a copy of the method so that a stable ABI for + * ENGINEs can be supported. But, for the moment, all *_METHODS must be + * static. */ +static int set_method(void **out_member, const void *method, size_t method_size, + size_t compiled_size) { + const struct openssl_method_common_st *common = method; + if (method_size != compiled_size || !common->is_static) { + return 0; + } + + *out_member = (void*) method; + return 1; +} + +int ENGINE_set_DH_method(ENGINE *engine, const DH_METHOD *method, + size_t method_size) { + return set_method((void **)&engine->dh_method, method, method_size, + sizeof(DH_METHOD)); +} + +DH_METHOD *ENGINE_get_DH_method(const ENGINE *engine) { + return engine->dh_method; +} + +int ENGINE_set_DSA_method(ENGINE *engine, const DSA_METHOD *method, + size_t method_size) { + return set_method((void **)&engine->dsa_method, method, method_size, + sizeof(DSA_METHOD)); +} + +DSA_METHOD *ENGINE_get_DSA_method(const ENGINE *engine) { + return engine->dsa_method; +} + +int ENGINE_set_RSA_method(ENGINE *engine, const RSA_METHOD *method, + size_t method_size) { + return set_method((void **)&engine->rsa_method, method, method_size, + sizeof(RSA_METHOD)); +} + +RSA_METHOD *ENGINE_get_RSA_method(const ENGINE *engine) { + return engine->rsa_method; +} + +int ENGINE_set_ECDSA_method(ENGINE *engine, const ECDSA_METHOD *method, + size_t method_size) { + return set_method((void **)&engine->ecdsa_method, method, method_size, + sizeof(ECDSA_METHOD)); +} + +ECDSA_METHOD *ENGINE_get_ECDSA_method(const ENGINE *engine) { + return engine->ecdsa_method; +} + +void METHOD_ref(void *method_in) { + assert(((struct openssl_method_common_st*) method_in)->is_static); +} + +void METHOD_unref(void *method_in) { + struct openssl_method_common_st *method = method_in; + + if (method == NULL) { + return; + } + assert(method->is_static); +} + +OPENSSL_DECLARE_ERROR_REASON(ENGINE, OPERATION_NOT_SUPPORTED); diff --git a/TMessagesProj/jni/boringssl/crypto/err/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/err/CMakeLists.txt new file mode 100644 index 00000000..0a617b7b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/CMakeLists.txt @@ -0,0 +1,40 @@ +include_directories(. .. ../../include) + +add_custom_command( + OUTPUT err_data.c + COMMAND ${GO_EXECUTABLE} run err_data_generate.go > ${CMAKE_CURRENT_BINARY_DIR}/err_data.c + DEPENDS + err_data_generate.go + asn1.errordata + bio.errordata + bn.errordata + cipher.errordata + conf.errordata + dh.errordata + digest.errordata + dsa.errordata + ecdh.errordata + ecdsa.errordata + ec.errordata + engine.errordata + evp.errordata + hkdf.errordata + obj.errordata + pem.errordata + pkcs8.errordata + rsa.errordata + ssl.errordata + x509.errordata + x509v3.errordata + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_library( + err + + OBJECT + + err.c + err_data.c +) + diff --git a/TMessagesProj/jni/boringssl/crypto/err/asn1.errordata b/TMessagesProj/jni/boringssl/crypto/err/asn1.errordata new file mode 100644 index 00000000..55342a09 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/asn1.errordata @@ -0,0 +1,88 @@ +ASN1,100,ASN1_LENGTH_MISMATCH +ASN1,101,AUX_ERROR +ASN1,102,BAD_GET_ASN1_OBJECT_CALL +ASN1,103,BAD_OBJECT_HEADER +ASN1,104,BMPSTRING_IS_WRONG_LENGTH +ASN1,105,BN_LIB +ASN1,106,BOOLEAN_IS_WRONG_LENGTH +ASN1,107,BUFFER_TOO_SMALL +ASN1,108,DECODE_ERROR +ASN1,109,DEPTH_EXCEEDED +ASN1,110,ENCODE_ERROR +ASN1,111,ERROR_GETTING_TIME +ASN1,112,EXPECTING_AN_ASN1_SEQUENCE +ASN1,113,EXPECTING_AN_INTEGER +ASN1,114,EXPECTING_AN_OBJECT +ASN1,115,EXPECTING_A_BOOLEAN +ASN1,116,EXPECTING_A_TIME +ASN1,117,EXPLICIT_LENGTH_MISMATCH +ASN1,118,EXPLICIT_TAG_NOT_CONSTRUCTED +ASN1,119,FIELD_MISSING +ASN1,120,FIRST_NUM_TOO_LARGE +ASN1,121,HEADER_TOO_LONG +ASN1,122,ILLEGAL_BITSTRING_FORMAT +ASN1,123,ILLEGAL_BOOLEAN +ASN1,124,ILLEGAL_CHARACTERS +ASN1,125,ILLEGAL_FORMAT +ASN1,126,ILLEGAL_HEX +ASN1,127,ILLEGAL_IMPLICIT_TAG +ASN1,128,ILLEGAL_INTEGER +ASN1,129,ILLEGAL_NESTED_TAGGING +ASN1,130,ILLEGAL_NULL +ASN1,131,ILLEGAL_NULL_VALUE +ASN1,132,ILLEGAL_OBJECT +ASN1,133,ILLEGAL_OPTIONAL_ANY +ASN1,134,ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE +ASN1,135,ILLEGAL_TAGGED_ANY +ASN1,136,ILLEGAL_TIME_VALUE +ASN1,137,INTEGER_NOT_ASCII_FORMAT +ASN1,138,INTEGER_TOO_LARGE_FOR_LONG +ASN1,139,INVALID_BIT_STRING_BITS_LEFT +ASN1,140,INVALID_BMPSTRING_LENGTH +ASN1,141,INVALID_DIGIT +ASN1,142,INVALID_MODIFIER +ASN1,143,INVALID_NUMBER +ASN1,144,INVALID_OBJECT_ENCODING +ASN1,145,INVALID_SEPARATOR +ASN1,146,INVALID_TIME_FORMAT +ASN1,147,INVALID_UNIVERSALSTRING_LENGTH +ASN1,148,INVALID_UTF8STRING +ASN1,149,LIST_ERROR +ASN1,150,MALLOC_FAILURE +ASN1,151,MISSING_ASN1_EOS +ASN1,152,MISSING_EOC +ASN1,153,MISSING_SECOND_NUMBER +ASN1,154,MISSING_VALUE +ASN1,155,MSTRING_NOT_UNIVERSAL +ASN1,156,MSTRING_WRONG_TAG +ASN1,157,NESTED_ASN1_ERROR +ASN1,158,NESTED_ASN1_STRING +ASN1,159,NON_HEX_CHARACTERS +ASN1,160,NOT_ASCII_FORMAT +ASN1,161,NOT_ENOUGH_DATA +ASN1,162,NO_MATCHING_CHOICE_TYPE +ASN1,163,NULL_IS_WRONG_LENGTH +ASN1,164,OBJECT_NOT_ASCII_FORMAT +ASN1,165,ODD_NUMBER_OF_CHARS +ASN1,166,SECOND_NUMBER_TOO_LARGE +ASN1,167,SEQUENCE_LENGTH_MISMATCH +ASN1,168,SEQUENCE_NOT_CONSTRUCTED +ASN1,169,SEQUENCE_OR_SET_NEEDS_CONFIG +ASN1,170,SHORT_LINE +ASN1,171,STREAMING_NOT_SUPPORTED +ASN1,172,STRING_TOO_LONG +ASN1,173,STRING_TOO_SHORT +ASN1,174,TAG_VALUE_TOO_HIGH +ASN1,175,TIME_NOT_ASCII_FORMAT +ASN1,176,TOO_LONG +ASN1,177,TYPE_NOT_CONSTRUCTED +ASN1,178,TYPE_NOT_PRIMITIVE +ASN1,179,UNEXPECTED_EOC +ASN1,180,UNIVERSALSTRING_IS_WRONG_LENGTH +ASN1,181,UNKNOWN_FORMAT +ASN1,182,UNKNOWN_TAG +ASN1,183,UNSUPPORTED_ANY_DEFINED_BY_TYPE +ASN1,184,UNSUPPORTED_PUBLIC_KEY_TYPE +ASN1,185,UNSUPPORTED_TYPE +ASN1,186,WRONG_TAG +ASN1,187,WRONG_TYPE diff --git a/TMessagesProj/jni/boringssl/crypto/err/bio.errordata b/TMessagesProj/jni/boringssl/crypto/err/bio.errordata new file mode 100644 index 00000000..94b3c971 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/bio.errordata @@ -0,0 +1,17 @@ +BIO,100,BAD_FOPEN_MODE +BIO,101,BROKEN_PIPE +BIO,102,CONNECT_ERROR +BIO,103,ERROR_SETTING_NBIO +BIO,104,INVALID_ARGUMENT +BIO,105,IN_USE +BIO,106,KEEPALIVE +BIO,107,NBIO_CONNECT_ERROR +BIO,108,NO_HOSTNAME_SPECIFIED +BIO,109,NO_PORT_SPECIFIED +BIO,110,NO_SUCH_FILE +BIO,111,NULL_PARAMETER +BIO,112,SYS_LIB +BIO,113,UNABLE_TO_CREATE_SOCKET +BIO,114,UNINITIALIZED +BIO,115,UNSUPPORTED_METHOD +BIO,116,WRITE_TO_READ_ONLY_BIO diff --git a/TMessagesProj/jni/boringssl/crypto/err/bn.errordata b/TMessagesProj/jni/boringssl/crypto/err/bn.errordata new file mode 100644 index 00000000..76b63925 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/bn.errordata @@ -0,0 +1,19 @@ +BN,100,ARG2_LT_ARG3 +BN,117,BAD_ENCODING +BN,101,BAD_RECIPROCAL +BN,102,BIGNUM_TOO_LONG +BN,103,BITS_TOO_SMALL +BN,104,CALLED_WITH_EVEN_MODULUS +BN,105,DIV_BY_ZERO +BN,118,ENCODE_ERROR +BN,106,EXPAND_ON_STATIC_BIGNUM_DATA +BN,107,INPUT_NOT_REDUCED +BN,108,INVALID_RANGE +BN,109,NEGATIVE_NUMBER +BN,110,NOT_A_SQUARE +BN,111,NOT_INITIALIZED +BN,112,NO_INVERSE +BN,113,PRIVATE_KEY_TOO_LARGE +BN,114,P_IS_NOT_PRIME +BN,115,TOO_MANY_ITERATIONS +BN,116,TOO_MANY_TEMPORARY_VARIABLES diff --git a/TMessagesProj/jni/boringssl/crypto/err/cipher.errordata b/TMessagesProj/jni/boringssl/crypto/err/cipher.errordata new file mode 100644 index 00000000..10375055 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/cipher.errordata @@ -0,0 +1,25 @@ +CIPHER,100,AES_KEY_SETUP_FAILED +CIPHER,101,BAD_DECRYPT +CIPHER,102,BAD_KEY_LENGTH +CIPHER,103,BUFFER_TOO_SMALL +CIPHER,104,CTRL_NOT_IMPLEMENTED +CIPHER,105,CTRL_OPERATION_NOT_IMPLEMENTED +CIPHER,106,DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH +CIPHER,107,INITIALIZATION_ERROR +CIPHER,108,INPUT_NOT_INITIALIZED +CIPHER,109,INVALID_AD_SIZE +CIPHER,110,INVALID_KEY_LENGTH +CIPHER,111,INVALID_NONCE_SIZE +CIPHER,112,INVALID_OPERATION +CIPHER,113,IV_TOO_LARGE +CIPHER,114,NO_CIPHER_SET +CIPHER,124,NO_DIRECTION_SET +CIPHER,115,OUTPUT_ALIASES_INPUT +CIPHER,116,TAG_TOO_LARGE +CIPHER,117,TOO_LARGE +CIPHER,118,UNSUPPORTED_AD_SIZE +CIPHER,119,UNSUPPORTED_INPUT_SIZE +CIPHER,120,UNSUPPORTED_KEY_SIZE +CIPHER,121,UNSUPPORTED_NONCE_SIZE +CIPHER,122,UNSUPPORTED_TAG_SIZE +CIPHER,123,WRONG_FINAL_BLOCK_LENGTH diff --git a/TMessagesProj/jni/boringssl/crypto/err/conf.errordata b/TMessagesProj/jni/boringssl/crypto/err/conf.errordata new file mode 100644 index 00000000..651fabe1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/conf.errordata @@ -0,0 +1,6 @@ +CONF,100,LIST_CANNOT_BE_NULL +CONF,101,MISSING_CLOSE_SQUARE_BRACKET +CONF,102,MISSING_EQUAL_SIGN +CONF,103,NO_CLOSE_BRACE +CONF,104,UNABLE_TO_CREATE_NEW_SECTION +CONF,105,VARIABLE_HAS_NO_VALUE diff --git a/TMessagesProj/jni/boringssl/crypto/err/dh.errordata b/TMessagesProj/jni/boringssl/crypto/err/dh.errordata new file mode 100644 index 00000000..571e218a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/dh.errordata @@ -0,0 +1,4 @@ +DH,100,BAD_GENERATOR +DH,101,INVALID_PUBKEY +DH,102,MODULUS_TOO_LARGE +DH,103,NO_PRIVATE_VALUE diff --git a/TMessagesProj/jni/boringssl/crypto/err/digest.errordata b/TMessagesProj/jni/boringssl/crypto/err/digest.errordata new file mode 100644 index 00000000..411e778b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/digest.errordata @@ -0,0 +1 @@ +DIGEST,100,INPUT_NOT_INITIALIZED diff --git a/TMessagesProj/jni/boringssl/crypto/err/dsa.errordata b/TMessagesProj/jni/boringssl/crypto/err/dsa.errordata new file mode 100644 index 00000000..3c5764a1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/dsa.errordata @@ -0,0 +1,4 @@ +DSA,100,BAD_Q_VALUE +DSA,101,MISSING_PARAMETERS +DSA,102,MODULUS_TOO_LARGE +DSA,103,NEED_NEW_SETUP_VALUES diff --git a/TMessagesProj/jni/boringssl/crypto/err/ec.errordata b/TMessagesProj/jni/boringssl/crypto/err/ec.errordata new file mode 100644 index 00000000..e7b41756 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/ec.errordata @@ -0,0 +1,28 @@ +EC,126,BIGNUM_OUT_OF_RANGE +EC,100,BUFFER_TOO_SMALL +EC,101,COORDINATES_OUT_OF_RANGE +EC,102,D2I_ECPKPARAMETERS_FAILURE +EC,103,EC_GROUP_NEW_BY_NAME_FAILURE +EC,104,GROUP2PKPARAMETERS_FAILURE +EC,105,I2D_ECPKPARAMETERS_FAILURE +EC,106,INCOMPATIBLE_OBJECTS +EC,107,INVALID_COMPRESSED_POINT +EC,108,INVALID_COMPRESSION_BIT +EC,109,INVALID_ENCODING +EC,110,INVALID_FIELD +EC,111,INVALID_FORM +EC,112,INVALID_GROUP_ORDER +EC,113,INVALID_PRIVATE_KEY +EC,114,MISSING_PARAMETERS +EC,115,MISSING_PRIVATE_KEY +EC,116,NON_NAMED_CURVE +EC,117,NOT_INITIALIZED +EC,118,PKPARAMETERS2GROUP_FAILURE +EC,119,POINT_AT_INFINITY +EC,120,POINT_IS_NOT_ON_CURVE +EC,121,SLOT_FULL +EC,122,UNDEFINED_GENERATOR +EC,123,UNKNOWN_GROUP +EC,124,UNKNOWN_ORDER +EC,127,WRONG_CURVE_PARAMETERS +EC,125,WRONG_ORDER diff --git a/TMessagesProj/jni/boringssl/crypto/err/ecdh.errordata b/TMessagesProj/jni/boringssl/crypto/err/ecdh.errordata new file mode 100644 index 00000000..f714c304 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/ecdh.errordata @@ -0,0 +1,3 @@ +ECDH,100,KDF_FAILED +ECDH,101,NO_PRIVATE_VALUE +ECDH,102,POINT_ARITHMETIC_FAILURE diff --git a/TMessagesProj/jni/boringssl/crypto/err/ecdsa.errordata b/TMessagesProj/jni/boringssl/crypto/err/ecdsa.errordata new file mode 100644 index 00000000..58ba591f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/ecdsa.errordata @@ -0,0 +1,6 @@ +ECDSA,100,BAD_SIGNATURE +ECDSA,105,ENCODE_ERROR +ECDSA,101,MISSING_PARAMETERS +ECDSA,102,NEED_NEW_SETUP_VALUES +ECDSA,103,NOT_IMPLEMENTED +ECDSA,104,RANDOM_NUMBER_GENERATION_FAILED diff --git a/TMessagesProj/jni/boringssl/crypto/err/engine.errordata b/TMessagesProj/jni/boringssl/crypto/err/engine.errordata new file mode 100644 index 00000000..edbd7b97 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/engine.errordata @@ -0,0 +1 @@ +ENGINE,100,OPERATION_NOT_SUPPORTED diff --git a/TMessagesProj/jni/boringssl/crypto/err/err.c b/TMessagesProj/jni/boringssl/crypto/err/err.c new file mode 100644 index 00000000..24824e83 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/err.c @@ -0,0 +1,775 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include + +#if defined(OPENSSL_WINDOWS) +#pragma warning(push, 3) +#include +#pragma warning(pop) +#endif + +#include +#include + +#include "../internal.h" + + +extern const uint32_t kOpenSSLReasonValues[]; +extern const size_t kOpenSSLReasonValuesLen; +extern const char kOpenSSLReasonStringData[]; + +/* err_clear_data frees the optional |data| member of the given error. */ +static void err_clear_data(struct err_error_st *error) { + if ((error->flags & ERR_FLAG_MALLOCED) != 0) { + OPENSSL_free(error->data); + } + error->data = NULL; + error->flags &= ~ERR_FLAG_MALLOCED; +} + +/* err_clear clears the given queued error. */ +static void err_clear(struct err_error_st *error) { + err_clear_data(error); + memset(error, 0, sizeof(struct err_error_st)); +} + +/* global_next_library contains the next custom library value to return. */ +static int global_next_library = ERR_NUM_LIBS; + +/* global_next_library_mutex protects |global_next_library| from concurrent + * updates. */ +static struct CRYPTO_STATIC_MUTEX global_next_library_mutex = + CRYPTO_STATIC_MUTEX_INIT; + +static void err_state_free(void *statep) { + ERR_STATE *state = statep; + + if (state == NULL) { + return; + } + + unsigned i; + for (i = 0; i < ERR_NUM_ERRORS; i++) { + err_clear(&state->errors[i]); + } + OPENSSL_free(state->to_free); + OPENSSL_free(state); +} + +/* err_get_state gets the ERR_STATE object for the current thread. */ +static ERR_STATE *err_get_state(void) { + ERR_STATE *state = CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_ERR); + if (state == NULL) { + state = OPENSSL_malloc(sizeof(ERR_STATE)); + if (state == NULL) { + return NULL; + } + memset(state, 0, sizeof(ERR_STATE)); + if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_ERR, state, + err_state_free)) { + return NULL; + } + } + + return state; +} + +static uint32_t get_error_values(int inc, int top, const char **file, int *line, + const char **data, int *flags) { + unsigned i = 0; + ERR_STATE *state; + struct err_error_st *error; + uint32_t ret; + + state = err_get_state(); + if (state == NULL || state->bottom == state->top) { + return 0; + } + + if (top) { + assert(!inc); + /* last error */ + i = state->top; + } else { + i = (state->bottom + 1) % ERR_NUM_ERRORS; + } + + error = &state->errors[i]; + ret = error->packed; + + if (file != NULL && line != NULL) { + if (error->file == NULL) { + *file = "NA"; + *line = 0; + } else { + *file = error->file; + *line = error->line; + } + } + + if (data != NULL) { + if (error->data == NULL) { + *data = ""; + if (flags != NULL) { + *flags = 0; + } + } else { + *data = error->data; + if (flags != NULL) { + *flags = error->flags & ERR_FLAG_PUBLIC_MASK; + } + /* If this error is being removed, take ownership of data from + * the error. The semantics are such that the caller doesn't + * take ownership either. Instead the error system takes + * ownership and retains it until the next call that affects the + * error queue. */ + if (inc) { + if (error->flags & ERR_FLAG_MALLOCED) { + OPENSSL_free(state->to_free); + state->to_free = error->data; + } + error->data = NULL; + error->flags = 0; + } + } + } + + if (inc) { + assert(!top); + err_clear(error); + state->bottom = i; + } + + return ret; +} + +uint32_t ERR_get_error(void) { + return get_error_values(1 /* inc */, 0 /* bottom */, NULL, NULL, NULL, NULL); +} + +uint32_t ERR_get_error_line(const char **file, int *line) { + return get_error_values(1 /* inc */, 0 /* bottom */, file, line, NULL, NULL); +} + +uint32_t ERR_get_error_line_data(const char **file, int *line, + const char **data, int *flags) { + return get_error_values(1 /* inc */, 0 /* bottom */, file, line, data, flags); +} + +uint32_t ERR_peek_error(void) { + return get_error_values(0 /* peek */, 0 /* bottom */, NULL, NULL, NULL, NULL); +} + +uint32_t ERR_peek_error_line(const char **file, int *line) { + return get_error_values(0 /* peek */, 0 /* bottom */, file, line, NULL, NULL); +} + +uint32_t ERR_peek_error_line_data(const char **file, int *line, + const char **data, int *flags) { + return get_error_values(0 /* peek */, 0 /* bottom */, file, line, data, + flags); +} + +const char *ERR_peek_function(void) { + ERR_STATE *state = err_get_state(); + if (state == NULL || state->bottom == state->top) { + return NULL; + } + return state->errors[(state->bottom + 1) % ERR_NUM_ERRORS].function; +} + +uint32_t ERR_peek_last_error(void) { + return get_error_values(0 /* peek */, 1 /* top */, NULL, NULL, NULL, NULL); +} + +uint32_t ERR_peek_last_error_line(const char **file, int *line) { + return get_error_values(0 /* peek */, 1 /* top */, file, line, NULL, NULL); +} + +uint32_t ERR_peek_last_error_line_data(const char **file, int *line, + const char **data, int *flags) { + return get_error_values(0 /* peek */, 1 /* top */, file, line, data, flags); +} + +void ERR_clear_error(void) { + ERR_STATE *const state = err_get_state(); + unsigned i; + + if (state == NULL) { + return; + } + + for (i = 0; i < ERR_NUM_ERRORS; i++) { + err_clear(&state->errors[i]); + } + OPENSSL_free(state->to_free); + state->to_free = NULL; + + state->top = state->bottom = 0; +} + +void ERR_remove_thread_state(const CRYPTO_THREADID *tid) { + if (tid != NULL) { + assert(0); + return; + } + + ERR_clear_error(); +} + +int ERR_get_next_error_library(void) { + int ret; + + CRYPTO_STATIC_MUTEX_lock_write(&global_next_library_mutex); + ret = global_next_library++; + CRYPTO_STATIC_MUTEX_unlock(&global_next_library_mutex); + + return ret; +} + +void ERR_remove_state(unsigned long pid) { + ERR_clear_error(); +} + +void ERR_clear_system_error(void) { + errno = 0; +} + +static void err_error_string(uint32_t packed_error, const char *func_str, + char *buf, size_t len) { + char lib_buf[64], reason_buf[64]; + const char *lib_str, *reason_str; + unsigned lib, reason; + + if (len == 0) { + return; + } + + lib = ERR_GET_LIB(packed_error); + reason = ERR_GET_REASON(packed_error); + + lib_str = ERR_lib_error_string(packed_error); + reason_str = ERR_reason_error_string(packed_error); + + if (lib_str == NULL) { + BIO_snprintf(lib_buf, sizeof(lib_buf), "lib(%u)", lib); + lib_str = lib_buf; + } + + if (func_str == NULL) { + func_str = "OPENSSL_internal"; + } + + if (reason_str == NULL) { + BIO_snprintf(reason_buf, sizeof(reason_buf), "reason(%u)", reason); + reason_str = reason_buf; + } + + BIO_snprintf(buf, len, "error:%08" PRIx32 ":%s:%s:%s", + packed_error, lib_str, func_str, reason_str); + + if (strlen(buf) == len - 1) { + /* output may be truncated; make sure we always have 5 colon-separated + * fields, i.e. 4 colons. */ + static const unsigned num_colons = 4; + unsigned i; + char *s = buf; + + if (len <= num_colons) { + /* In this situation it's not possible to ensure that the correct number + * of colons are included in the output. */ + return; + } + + for (i = 0; i < num_colons; i++) { + char *colon = strchr(s, ':'); + char *last_pos = &buf[len - 1] - num_colons + i; + + if (colon == NULL || colon > last_pos) { + /* set colon |i| at last possible position (buf[len-1] is the + * terminating 0). If we're setting this colon, then all whole of the + * rest of the string must be colons in order to have the correct + * number. */ + memset(last_pos, ':', num_colons - i); + break; + } + + s = colon + 1; + } + } +} + +char *ERR_error_string(uint32_t packed_error, char *ret) { + static char buf[ERR_ERROR_STRING_BUF_LEN]; + + if (ret == NULL) { + /* TODO(fork): remove this. */ + ret = buf; + } + +#if !defined(NDEBUG) + /* This is aimed to help catch callers who don't provide + * |ERR_ERROR_STRING_BUF_LEN| bytes of space. */ + memset(ret, 0, ERR_ERROR_STRING_BUF_LEN); +#endif + + ERR_error_string_n(packed_error, ret, ERR_ERROR_STRING_BUF_LEN); + + return ret; +} + +void ERR_error_string_n(uint32_t packed_error, char *buf, size_t len) { + err_error_string(packed_error, NULL, buf, len); +} + +// err_string_cmp is a compare function for searching error values with +// |bsearch| in |err_string_lookup|. +static int err_string_cmp(const void *a, const void *b) { + const uint32_t a_key = *((const uint32_t*) a) >> 15; + const uint32_t b_key = *((const uint32_t*) b) >> 15; + + if (a_key < b_key) { + return -1; + } else if (a_key > b_key) { + return 1; + } else { + return 0; + } +} + +/* err_string_lookup looks up the string associated with |lib| and |key| in + * |values| and |string_data|. It returns the string or NULL if not found. */ +static const char *err_string_lookup(uint32_t lib, uint32_t key, + const uint32_t *values, + size_t num_values, + const char *string_data) { + /* |values| points to data in err_data.h, which is generated by + * err_data_generate.go. It's an array of uint32_t values. Each value has the + * following structure: + * | lib | key | offset | + * |6 bits| 11 bits | 15 bits | + * + * The |lib| value is a library identifier: one of the |ERR_LIB_*| values. + * The |key| is either a function or a reason code, depending on the context. + * The |offset| is the number of bytes from the start of |string_data| where + * the (NUL terminated) string for this value can be found. + * + * Values are sorted based on treating the |lib| and |key| part as an + * unsigned integer. */ + if (lib >= (1 << 6) || key >= (1 << 11)) { + return NULL; + } + uint32_t search_key = lib << 26 | key << 15; + const uint32_t *result = bsearch(&search_key, values, num_values, + sizeof(uint32_t), err_string_cmp); + if (result == NULL) { + return NULL; + } + + return &string_data[(*result) & 0x7fff]; +} + +static const char *const kLibraryNames[ERR_NUM_LIBS] = { + "invalid library (0)", + "unknown library", /* ERR_LIB_NONE */ + "system library", /* ERR_LIB_SYS */ + "bignum routines", /* ERR_LIB_BN */ + "RSA routines", /* ERR_LIB_RSA */ + "Diffie-Hellman routines", /* ERR_LIB_DH */ + "public key routines", /* ERR_LIB_EVP */ + "memory buffer routines", /* ERR_LIB_BUF */ + "object identifier routines", /* ERR_LIB_OBJ */ + "PEM routines", /* ERR_LIB_PEM */ + "DSA routines", /* ERR_LIB_DSA */ + "X.509 certificate routines", /* ERR_LIB_X509 */ + "ASN.1 encoding routines", /* ERR_LIB_ASN1 */ + "configuration file routines", /* ERR_LIB_CONF */ + "common libcrypto routines", /* ERR_LIB_CRYPTO */ + "elliptic curve routines", /* ERR_LIB_EC */ + "SSL routines", /* ERR_LIB_SSL */ + "BIO routines", /* ERR_LIB_BIO */ + "PKCS7 routines", /* ERR_LIB_PKCS7 */ + "PKCS8 routines", /* ERR_LIB_PKCS8 */ + "X509 V3 routines", /* ERR_LIB_X509V3 */ + "random number generator", /* ERR_LIB_RAND */ + "ENGINE routines", /* ERR_LIB_ENGINE */ + "OCSP routines", /* ERR_LIB_OCSP */ + "UI routines", /* ERR_LIB_UI */ + "COMP routines", /* ERR_LIB_COMP */ + "ECDSA routines", /* ERR_LIB_ECDSA */ + "ECDH routines", /* ERR_LIB_ECDH */ + "HMAC routines", /* ERR_LIB_HMAC */ + "Digest functions", /* ERR_LIB_DIGEST */ + "Cipher functions", /* ERR_LIB_CIPHER */ + "HKDF functions", /* ERR_LIB_HKDF */ + "User defined functions", /* ERR_LIB_USER */ +}; + +const char *ERR_lib_error_string(uint32_t packed_error) { + const uint32_t lib = ERR_GET_LIB(packed_error); + + if (lib >= ERR_NUM_LIBS) { + return NULL; + } + return kLibraryNames[lib]; +} + +const char *ERR_func_error_string(uint32_t packed_error) { + return "OPENSSL_internal"; +} + +const char *ERR_reason_error_string(uint32_t packed_error) { + const uint32_t lib = ERR_GET_LIB(packed_error); + const uint32_t reason = ERR_GET_REASON(packed_error); + + if (lib == ERR_LIB_SYS) { + if (reason < 127) { + return strerror(reason); + } + return NULL; + } + + if (reason < ERR_NUM_LIBS) { + return kLibraryNames[reason]; + } + + if (reason < 100) { + switch (reason) { + case ERR_R_MALLOC_FAILURE: + return "malloc failure"; + case ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED: + return "function should not have been called"; + case ERR_R_PASSED_NULL_PARAMETER: + return "passed a null parameter"; + case ERR_R_INTERNAL_ERROR: + return "internal error"; + case ERR_R_OVERFLOW: + return "overflow"; + default: + return NULL; + } + } + + return err_string_lookup(lib, reason, kOpenSSLReasonValues, + kOpenSSLReasonValuesLen, kOpenSSLReasonStringData); +} + +void ERR_print_errors_cb(ERR_print_errors_callback_t callback, void *ctx) { + char buf[ERR_ERROR_STRING_BUF_LEN]; + char buf2[1024]; + const char *file, *data; + int line, flags; + uint32_t packed_error; + + /* thread_hash is the least-significant bits of the |ERR_STATE| pointer value + * for this thread. */ + const unsigned long thread_hash = (uintptr_t) err_get_state(); + + for (;;) { + const char *function = ERR_peek_function(); + packed_error = ERR_get_error_line_data(&file, &line, &data, &flags); + if (packed_error == 0) { + break; + } + + err_error_string(packed_error, function, buf, sizeof(buf)); + BIO_snprintf(buf2, sizeof(buf2), "%lu:%s:%s:%d:%s\n", thread_hash, buf, + file, line, (flags & ERR_FLAG_STRING) ? data : ""); + if (callback(buf2, strlen(buf2), ctx) <= 0) { + break; + } + } +} + +static int print_errors_to_file(const char* msg, size_t msg_len, void* ctx) { + assert(msg[msg_len] == '\0'); + FILE* fp = ctx; + int res = fputs(msg, fp); + return res < 0 ? 0 : 1; +} + +void ERR_print_errors_fp(FILE *file) { + ERR_print_errors_cb(print_errors_to_file, file); +} + +/* err_set_error_data sets the data on the most recent error. The |flags| + * argument is a combination of the |ERR_FLAG_*| values. */ +static void err_set_error_data(char *data, int flags) { + ERR_STATE *const state = err_get_state(); + struct err_error_st *error; + + if (state == NULL || state->top == state->bottom) { + if (flags & ERR_FLAG_MALLOCED) { + OPENSSL_free(data); + } + return; + } + + error = &state->errors[state->top]; + + err_clear_data(error); + error->data = data; + error->flags = flags; +} + +void ERR_put_error(int library, int reason, const char *function, + const char *file, unsigned line) { + ERR_STATE *const state = err_get_state(); + struct err_error_st *error; + + if (state == NULL) { + return; + } + + if (library == ERR_LIB_SYS && reason == 0) { +#if defined(OPENSSL_WINDOWS) + reason = GetLastError(); +#else + reason = errno; +#endif + } + + state->top = (state->top + 1) % ERR_NUM_ERRORS; + if (state->top == state->bottom) { + state->bottom = (state->bottom + 1) % ERR_NUM_ERRORS; + } + + error = &state->errors[state->top]; + err_clear(error); + error->function = function; + error->file = file; + error->line = line; + error->packed = ERR_PACK(library, reason); +} + +/* ERR_add_error_data_vdata takes a variable number of const char* pointers, + * concatenates them and sets the result as the data on the most recent + * error. */ +static void err_add_error_vdata(unsigned num, va_list args) { + size_t alloced, new_len, len = 0, substr_len; + char *buf; + const char *substr; + unsigned i; + + alloced = 80; + buf = OPENSSL_malloc(alloced + 1); + if (buf == NULL) { + return; + } + + for (i = 0; i < num; i++) { + substr = va_arg(args, const char *); + if (substr == NULL) { + continue; + } + + substr_len = strlen(substr); + new_len = len + substr_len; + if (new_len > alloced) { + char *new_buf; + + if (alloced + 20 + 1 < alloced) { + /* overflow. */ + OPENSSL_free(buf); + return; + } + + alloced = new_len + 20; + new_buf = OPENSSL_realloc(buf, alloced + 1); + if (new_buf == NULL) { + OPENSSL_free(buf); + return; + } + buf = new_buf; + } + + memcpy(buf + len, substr, substr_len); + len = new_len; + } + + buf[len] = 0; + err_set_error_data(buf, ERR_FLAG_MALLOCED | ERR_FLAG_STRING); +} + +void ERR_add_error_data(unsigned count, ...) { + va_list args; + va_start(args, count); + err_add_error_vdata(count, args); + va_end(args); +} + +void ERR_add_error_dataf(const char *format, ...) { + va_list ap; + char *buf; + static const unsigned buf_len = 256; + + /* A fixed-size buffer is used because va_copy (which would be needed in + * order to call vsnprintf twice and measure the buffer) wasn't defined until + * C99. */ + buf = OPENSSL_malloc(buf_len + 1); + if (buf == NULL) { + return; + } + + va_start(ap, format); + BIO_vsnprintf(buf, buf_len, format, ap); + buf[buf_len] = 0; + va_end(ap); + + err_set_error_data(buf, ERR_FLAG_MALLOCED | ERR_FLAG_STRING); +} + +int ERR_set_mark(void) { + ERR_STATE *const state = err_get_state(); + + if (state == NULL || state->bottom == state->top) { + return 0; + } + state->errors[state->top].flags |= ERR_FLAG_MARK; + return 1; +} + +int ERR_pop_to_mark(void) { + ERR_STATE *const state = err_get_state(); + + if (state == NULL) { + return 0; + } + + while (state->bottom != state->top) { + struct err_error_st *error = &state->errors[state->top]; + + if ((error->flags & ERR_FLAG_MARK) != 0) { + error->flags &= ~ERR_FLAG_MARK; + return 1; + } + + err_clear(error); + if (state->top == 0) { + state->top = ERR_NUM_ERRORS - 1; + } else { + state->top--; + } + } + + return 0; +} + +void ERR_load_crypto_strings(void) {} + +void ERR_free_strings(void) {} + +void ERR_load_BIO_strings(void) {} + +void ERR_load_ERR_strings(void) {} diff --git a/TMessagesProj/jni/boringssl/crypto/err/err_data_generate.go b/TMessagesProj/jni/boringssl/crypto/err/err_data_generate.go new file mode 100644 index 00000000..24e0d66f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/err_data_generate.go @@ -0,0 +1,277 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +package main + +import ( + "bufio" + "bytes" + "errors" + "fmt" + "io" + "os" + "sort" + "strconv" + "strings" +) + +// libraryNames must be kept in sync with the enum in err.h. The generated code +// will contain static assertions to enforce this. +var libraryNames = []string{ + "NONE", + "SYS", + "BN", + "RSA", + "DH", + "EVP", + "BUF", + "OBJ", + "PEM", + "DSA", + "X509", + "ASN1", + "CONF", + "CRYPTO", + "EC", + "SSL", + "BIO", + "PKCS7", + "PKCS8", + "X509V3", + "RAND", + "ENGINE", + "OCSP", + "UI", + "COMP", + "ECDSA", + "ECDH", + "HMAC", + "DIGEST", + "CIPHER", + "HKDF", + "USER", +} + +// stringList is a map from uint32 -> string which can output data for a sorted +// list as C literals. +type stringList struct { + // entries is an array of keys and offsets into |stringData|. The + // offsets are in the bottom 15 bits of each uint32 and the key is the + // top 17 bits. + entries []uint32 + // internedStrings contains the same strings as are in |stringData|, + // but allows for easy deduplication. It maps a string to its offset in + // |stringData|. + internedStrings map[string]uint32 + stringData []byte +} + +func newStringList() *stringList { + return &stringList{ + internedStrings: make(map[string]uint32), + } +} + +// offsetMask is the bottom 15 bits. It's a mask that selects the offset from a +// uint32 in entries. +const offsetMask = 0x7fff + +func (st *stringList) Add(key uint32, value string) error { + if key&offsetMask != 0 { + return errors.New("need bottom 15 bits of the key for the offset") + } + offset, ok := st.internedStrings[value] + if !ok { + offset = uint32(len(st.stringData)) + if offset&offsetMask != offset { + return errors.New("stringList overflow") + } + st.stringData = append(st.stringData, []byte(value)...) + st.stringData = append(st.stringData, 0) + st.internedStrings[value] = offset + } + + for _, existing := range st.entries { + if existing>>15 == key>>15 { + panic("duplicate entry") + } + } + st.entries = append(st.entries, key|offset) + return nil +} + +// keySlice is a type that implements sorting of entries values. +type keySlice []uint32 + +func (ks keySlice) Len() int { + return len(ks) +} + +func (ks keySlice) Less(i, j int) bool { + return (ks[i] >> 15) < (ks[j] >> 15) +} + +func (ks keySlice) Swap(i, j int) { + ks[i], ks[j] = ks[j], ks[i] +} + +func (st *stringList) buildList() []uint32 { + sort.Sort(keySlice(st.entries)) + return st.entries +} + +type stringWriter interface { + io.Writer + WriteString(string) (int, error) +} + +func (st *stringList) WriteTo(out stringWriter, name string) { + list := st.buildList() + fmt.Fprintf(os.Stderr, "%s: %d bytes of list and %d bytes of string data.\n", name, 4*len(list), len(st.stringData)) + + values := "kOpenSSL" + name + "Values" + out.WriteString("const uint32_t " + values + "[] = {\n") + for _, v := range list { + fmt.Fprintf(out, " 0x%x,\n", v) + } + out.WriteString("};\n\n") + out.WriteString("const size_t " + values + "Len = sizeof(" + values + ") / sizeof(" + values + "[0]);\n\n") + + stringData := "kOpenSSL" + name + "StringData" + out.WriteString("const char " + stringData + "[] =\n \"") + for i, c := range st.stringData { + if c == 0 { + out.WriteString("\\0\"\n \"") + continue + } + out.Write(st.stringData[i : i+1]) + } + out.WriteString("\";\n\n") +} + +type errorData struct { + reasons *stringList + libraryMap map[string]uint32 +} + +func (e *errorData) readErrorDataFile(filename string) error { + inFile, err := os.Open(filename) + if err != nil { + return err + } + defer inFile.Close() + + scanner := bufio.NewScanner(inFile) + comma := []byte(",") + + lineNo := 0 + for scanner.Scan() { + lineNo++ + + line := scanner.Bytes() + if len(line) == 0 { + continue + } + parts := bytes.Split(line, comma) + if len(parts) != 3 { + return fmt.Errorf("bad line %d in %s: found %d values but want 3", lineNo, filename, len(parts)) + } + libNum, ok := e.libraryMap[string(parts[0])] + if !ok { + return fmt.Errorf("bad line %d in %s: unknown library", lineNo, filename) + } + if libNum >= 64 { + return fmt.Errorf("bad line %d in %s: library value too large", lineNo, filename) + } + key, err := strconv.ParseUint(string(parts[1]), 10 /* base */, 32 /* bit size */) + if err != nil { + return fmt.Errorf("bad line %d in %s: %s", lineNo, filename, err) + } + if key >= 2048 { + return fmt.Errorf("bad line %d in %s: key too large", lineNo, filename) + } + value := string(parts[2]) + + listKey := libNum<<26 | uint32(key)<<15 + + err = e.reasons.Add(listKey, value) + if err != nil { + return err + } + } + + return scanner.Err() +} + +func main() { + e := &errorData{ + reasons: newStringList(), + libraryMap: make(map[string]uint32), + } + for i, name := range libraryNames { + e.libraryMap[name] = uint32(i) + 1 + } + + cwd, err := os.Open(".") + if err != nil { + panic(err) + } + names, err := cwd.Readdirnames(-1) + if err != nil { + panic(err) + } + + sort.Strings(names) + for _, name := range names { + if !strings.HasSuffix(name, ".errordata") { + continue + } + if err := e.readErrorDataFile(name); err != nil { + panic(err) + } + } + + out := os.Stdout + + out.WriteString(`/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + + /* This file was generated by err_data_generate.go. */ + +#include +#include +#include + + +`) + + for i, name := range libraryNames { + fmt.Fprintf(out, "OPENSSL_COMPILE_ASSERT(ERR_LIB_%s == %d, library_values_changed_%d);\n", name, i+1, i+1) + } + fmt.Fprintf(out, "OPENSSL_COMPILE_ASSERT(ERR_NUM_LIBS == %d, library_values_changed_num);\n", len(libraryNames)+1) + out.WriteString("\n") + + e.reasons.WriteTo(out, "Reason") +} diff --git a/TMessagesProj/jni/boringssl/crypto/err/evp.errordata b/TMessagesProj/jni/boringssl/crypto/err/evp.errordata new file mode 100644 index 00000000..8f8dd483 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/evp.errordata @@ -0,0 +1,46 @@ +EVP,151,BN_DECODE_ERROR +EVP,100,BUFFER_TOO_SMALL +EVP,101,COMMAND_NOT_SUPPORTED +EVP,146,CONTEXT_NOT_INITIALISED +EVP,143,DECODE_ERROR +EVP,104,DIFFERENT_KEY_TYPES +EVP,105,DIFFERENT_PARAMETERS +EVP,147,DIGEST_AND_KEY_TYPE_NOT_SUPPORTED +EVP,107,EXPECTING_AN_EC_KEY_KEY +EVP,141,EXPECTING_AN_RSA_KEY +EVP,109,EXPECTING_A_DH_KEY +EVP,110,EXPECTING_A_DSA_KEY +EVP,111,ILLEGAL_OR_UNSUPPORTED_PADDING_MODE +EVP,112,INVALID_CURVE +EVP,113,INVALID_DIGEST_LENGTH +EVP,114,INVALID_DIGEST_TYPE +EVP,115,INVALID_KEYBITS +EVP,116,INVALID_MGF1_MD +EVP,142,INVALID_OPERATION +EVP,118,INVALID_PADDING_MODE +EVP,119,INVALID_PSS_PARAMETERS +EVP,144,INVALID_PSS_SALTLEN +EVP,121,INVALID_SALT_LENGTH +EVP,122,INVALID_TRAILER +EVP,123,KEYS_NOT_SET +EVP,124,MISSING_PARAMETERS +EVP,125,NO_DEFAULT_DIGEST +EVP,126,NO_KEY_SET +EVP,127,NO_MDC2_SUPPORT +EVP,128,NO_NID_FOR_CURVE +EVP,129,NO_OPERATION_SET +EVP,130,NO_PARAMETERS_SET +EVP,131,OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE +EVP,132,OPERATON_NOT_INITIALIZED +EVP,152,PARAMETER_ENCODING_ERROR +EVP,133,UNKNOWN_DIGEST +EVP,134,UNKNOWN_MASK_DIGEST +EVP,150,UNKNOWN_MESSAGE_DIGEST_ALGORITHM +EVP,145,UNKNOWN_PUBLIC_KEY_TYPE +EVP,149,UNKNOWN_SIGNATURE_ALGORITHM +EVP,138,UNSUPPORTED_ALGORITHM +EVP,139,UNSUPPORTED_MASK_ALGORITHM +EVP,140,UNSUPPORTED_MASK_PARAMETER +EVP,153,UNSUPPORTED_PUBLIC_KEY_TYPE +EVP,154,UNSUPPORTED_SIGNATURE_TYPE +EVP,148,WRONG_PUBLIC_KEY_TYPE diff --git a/TMessagesProj/jni/boringssl/crypto/err/hkdf.errordata b/TMessagesProj/jni/boringssl/crypto/err/hkdf.errordata new file mode 100644 index 00000000..84866dee --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/hkdf.errordata @@ -0,0 +1 @@ +HKDF,100,OUTPUT_TOO_LARGE diff --git a/TMessagesProj/jni/boringssl/crypto/err/obj.errordata b/TMessagesProj/jni/boringssl/crypto/err/obj.errordata new file mode 100644 index 00000000..c54435ea --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/obj.errordata @@ -0,0 +1 @@ +OBJ,100,UNKNOWN_NID diff --git a/TMessagesProj/jni/boringssl/crypto/err/pem.errordata b/TMessagesProj/jni/boringssl/crypto/err/pem.errordata new file mode 100644 index 00000000..2a4b73af --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/pem.errordata @@ -0,0 +1,15 @@ +PEM,100,BAD_BASE64_DECODE +PEM,101,BAD_DECRYPT +PEM,102,BAD_END_LINE +PEM,103,BAD_IV_CHARS +PEM,104,BAD_PASSWORD_READ +PEM,105,CIPHER_IS_NULL +PEM,106,ERROR_CONVERTING_PRIVATE_KEY +PEM,107,NOT_DEK_INFO +PEM,108,NOT_ENCRYPTED +PEM,109,NOT_PROC_TYPE +PEM,110,NO_START_LINE +PEM,111,READ_KEY +PEM,112,SHORT_HEADER +PEM,113,UNSUPPORTED_CIPHER +PEM,114,UNSUPPORTED_ENCRYPTION diff --git a/TMessagesProj/jni/boringssl/crypto/err/pkcs8.errordata b/TMessagesProj/jni/boringssl/crypto/err/pkcs8.errordata new file mode 100644 index 00000000..0eb5083b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/pkcs8.errordata @@ -0,0 +1,25 @@ +PKCS8,100,BAD_PKCS12_DATA +PKCS8,101,BAD_PKCS12_VERSION +PKCS8,102,CIPHER_HAS_NO_OBJECT_IDENTIFIER +PKCS8,103,CRYPT_ERROR +PKCS8,104,DECODE_ERROR +PKCS8,105,ENCODE_ERROR +PKCS8,106,ENCRYPT_ERROR +PKCS8,107,ERROR_SETTING_CIPHER_PARAMS +PKCS8,108,INCORRECT_PASSWORD +PKCS8,109,KEYGEN_FAILURE +PKCS8,110,KEY_GEN_ERROR +PKCS8,111,METHOD_NOT_SUPPORTED +PKCS8,112,MISSING_MAC +PKCS8,113,MULTIPLE_PRIVATE_KEYS_IN_PKCS12 +PKCS8,114,PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED +PKCS8,115,PKCS12_TOO_DEEPLY_NESTED +PKCS8,116,PRIVATE_KEY_DECODE_ERROR +PKCS8,117,PRIVATE_KEY_ENCODE_ERROR +PKCS8,118,TOO_LONG +PKCS8,119,UNKNOWN_ALGORITHM +PKCS8,120,UNKNOWN_CIPHER +PKCS8,121,UNKNOWN_CIPHER_ALGORITHM +PKCS8,122,UNKNOWN_DIGEST +PKCS8,123,UNKNOWN_HASH +PKCS8,124,UNSUPPORTED_PRIVATE_KEY_ALGORITHM diff --git a/TMessagesProj/jni/boringssl/crypto/err/rsa.errordata b/TMessagesProj/jni/boringssl/crypto/err/rsa.errordata new file mode 100644 index 00000000..c19f73c7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/rsa.errordata @@ -0,0 +1,46 @@ +RSA,143,BAD_ENCODING +RSA,100,BAD_E_VALUE +RSA,101,BAD_FIXED_HEADER_DECRYPT +RSA,102,BAD_PAD_BYTE_COUNT +RSA,103,BAD_RSA_PARAMETERS +RSA,104,BAD_SIGNATURE +RSA,145,BAD_VERSION +RSA,105,BLOCK_TYPE_IS_NOT_01 +RSA,106,BN_NOT_INITIALIZED +RSA,142,CANNOT_RECOVER_MULTI_PRIME_KEY +RSA,107,CRT_PARAMS_ALREADY_GIVEN +RSA,108,CRT_VALUES_INCORRECT +RSA,109,DATA_LEN_NOT_EQUAL_TO_MOD_LEN +RSA,110,DATA_TOO_LARGE +RSA,111,DATA_TOO_LARGE_FOR_KEY_SIZE +RSA,112,DATA_TOO_LARGE_FOR_MODULUS +RSA,113,DATA_TOO_SMALL +RSA,114,DATA_TOO_SMALL_FOR_KEY_SIZE +RSA,115,DIGEST_TOO_BIG_FOR_RSA_KEY +RSA,116,D_E_NOT_CONGRUENT_TO_1 +RSA,117,EMPTY_PUBLIC_KEY +RSA,144,ENCODE_ERROR +RSA,118,FIRST_OCTET_INVALID +RSA,119,INCONSISTENT_SET_OF_CRT_VALUES +RSA,120,INTERNAL_ERROR +RSA,121,INVALID_MESSAGE_LENGTH +RSA,122,KEY_SIZE_TOO_SMALL +RSA,123,LAST_OCTET_INVALID +RSA,124,MODULUS_TOO_LARGE +RSA,141,MUST_HAVE_AT_LEAST_TWO_PRIMES +RSA,125,NO_PUBLIC_EXPONENT +RSA,126,NULL_BEFORE_BLOCK_MISSING +RSA,127,N_NOT_EQUAL_P_Q +RSA,128,OAEP_DECODING_ERROR +RSA,129,ONLY_ONE_OF_P_Q_GIVEN +RSA,130,OUTPUT_BUFFER_TOO_SMALL +RSA,131,PADDING_CHECK_FAILED +RSA,132,PKCS_DECODING_ERROR +RSA,133,SLEN_CHECK_FAILED +RSA,134,SLEN_RECOVERY_FAILED +RSA,135,TOO_LONG +RSA,136,TOO_MANY_ITERATIONS +RSA,137,UNKNOWN_ALGORITHM_TYPE +RSA,138,UNKNOWN_PADDING_TYPE +RSA,139,VALUE_MISSING +RSA,140,WRONG_SIGNATURE_LENGTH diff --git a/TMessagesProj/jni/boringssl/crypto/err/ssl.errordata b/TMessagesProj/jni/boringssl/crypto/err/ssl.errordata new file mode 100644 index 00000000..7825cce1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/ssl.errordata @@ -0,0 +1,216 @@ +SSL,100,APP_DATA_IN_HANDSHAKE +SSL,101,ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT +SSL,102,BAD_ALERT +SSL,103,BAD_CHANGE_CIPHER_SPEC +SSL,104,BAD_DATA_RETURNED_BY_CALLBACK +SSL,105,BAD_DH_P_LENGTH +SSL,106,BAD_DIGEST_LENGTH +SSL,107,BAD_ECC_CERT +SSL,108,BAD_ECPOINT +SSL,109,BAD_HANDSHAKE_LENGTH +SSL,110,BAD_HANDSHAKE_RECORD +SSL,111,BAD_HELLO_REQUEST +SSL,112,BAD_LENGTH +SSL,113,BAD_PACKET_LENGTH +SSL,114,BAD_RSA_ENCRYPT +SSL,115,BAD_SIGNATURE +SSL,116,BAD_SRTP_MKI_VALUE +SSL,117,BAD_SRTP_PROTECTION_PROFILE_LIST +SSL,118,BAD_SSL_FILETYPE +SSL,119,BAD_WRITE_RETRY +SSL,120,BIO_NOT_SET +SSL,121,BN_LIB +SSL,272,BUFFER_TOO_SMALL +SSL,122,CANNOT_SERIALIZE_PUBLIC_KEY +SSL,123,CA_DN_LENGTH_MISMATCH +SSL,124,CA_DN_TOO_LONG +SSL,125,CCS_RECEIVED_EARLY +SSL,126,CERTIFICATE_VERIFY_FAILED +SSL,127,CERT_CB_ERROR +SSL,128,CERT_LENGTH_MISMATCH +SSL,129,CHANNEL_ID_NOT_P256 +SSL,130,CHANNEL_ID_SIGNATURE_INVALID +SSL,131,CIPHER_CODE_WRONG_LENGTH +SSL,132,CIPHER_OR_HASH_UNAVAILABLE +SSL,133,CLIENTHELLO_PARSE_FAILED +SSL,134,CLIENTHELLO_TLSEXT +SSL,135,CONNECTION_REJECTED +SSL,136,CONNECTION_TYPE_NOT_SET +SSL,137,COOKIE_MISMATCH +SSL,284,CUSTOM_EXTENSION_CONTENTS_TOO_LARGE +SSL,285,CUSTOM_EXTENSION_ERROR +SSL,138,D2I_ECDSA_SIG +SSL,139,DATA_BETWEEN_CCS_AND_FINISHED +SSL,140,DATA_LENGTH_TOO_LONG +SSL,141,DECODE_ERROR +SSL,142,DECRYPTION_FAILED +SSL,143,DECRYPTION_FAILED_OR_BAD_RECORD_MAC +SSL,144,DH_PUBLIC_VALUE_LENGTH_IS_WRONG +SSL,145,DIGEST_CHECK_FAILED +SSL,146,DTLS_MESSAGE_TOO_BIG +SSL,147,ECC_CERT_NOT_FOR_SIGNING +SSL,148,EMPTY_SRTP_PROTECTION_PROFILE_LIST +SSL,276,EMS_STATE_INCONSISTENT +SSL,149,ENCRYPTED_LENGTH_TOO_LONG +SSL,281,ERROR_ADDING_EXTENSION +SSL,150,ERROR_IN_RECEIVED_CIPHER_LIST +SSL,282,ERROR_PARSING_EXTENSION +SSL,151,EVP_DIGESTSIGNFINAL_FAILED +SSL,152,EVP_DIGESTSIGNINIT_FAILED +SSL,153,EXCESSIVE_MESSAGE_SIZE +SSL,154,EXTRA_DATA_IN_MESSAGE +SSL,271,FRAGMENT_MISMATCH +SSL,155,GOT_A_FIN_BEFORE_A_CCS +SSL,156,GOT_CHANNEL_ID_BEFORE_A_CCS +SSL,157,GOT_NEXT_PROTO_BEFORE_A_CCS +SSL,158,GOT_NEXT_PROTO_WITHOUT_EXTENSION +SSL,159,HANDSHAKE_FAILURE_ON_CLIENT_HELLO +SSL,160,HANDSHAKE_RECORD_BEFORE_CCS +SSL,161,HTTPS_PROXY_REQUEST +SSL,162,HTTP_REQUEST +SSL,163,INAPPROPRIATE_FALLBACK +SSL,164,INVALID_COMMAND +SSL,165,INVALID_MESSAGE +SSL,166,INVALID_SSL_SESSION +SSL,167,INVALID_TICKET_KEYS_LENGTH +SSL,168,LENGTH_MISMATCH +SSL,169,LIBRARY_HAS_NO_CIPHERS +SSL,170,MISSING_DH_KEY +SSL,171,MISSING_ECDSA_SIGNING_CERT +SSL,283,MISSING_EXTENSION +SSL,172,MISSING_RSA_CERTIFICATE +SSL,173,MISSING_RSA_ENCRYPTING_CERT +SSL,174,MISSING_RSA_SIGNING_CERT +SSL,175,MISSING_TMP_DH_KEY +SSL,176,MISSING_TMP_ECDH_KEY +SSL,177,MIXED_SPECIAL_OPERATOR_WITH_GROUPS +SSL,178,MTU_TOO_SMALL +SSL,179,NESTED_GROUP +SSL,180,NO_CERTIFICATES_RETURNED +SSL,181,NO_CERTIFICATE_ASSIGNED +SSL,182,NO_CERTIFICATE_SET +SSL,183,NO_CIPHERS_AVAILABLE +SSL,184,NO_CIPHERS_PASSED +SSL,185,NO_CIPHERS_SPECIFIED +SSL,186,NO_CIPHER_MATCH +SSL,187,NO_COMPRESSION_SPECIFIED +SSL,188,NO_METHOD_SPECIFIED +SSL,189,NO_P256_SUPPORT +SSL,190,NO_PRIVATE_KEY_ASSIGNED +SSL,191,NO_RENEGOTIATION +SSL,192,NO_REQUIRED_DIGEST +SSL,193,NO_SHARED_CIPHER +SSL,194,NO_SHARED_SIGATURE_ALGORITHMS +SSL,195,NO_SRTP_PROFILES +SSL,196,NULL_SSL_CTX +SSL,197,NULL_SSL_METHOD_PASSED +SSL,198,OLD_SESSION_CIPHER_NOT_RETURNED +SSL,273,OLD_SESSION_VERSION_NOT_RETURNED +SSL,274,OUTPUT_ALIASES_INPUT +SSL,199,PACKET_LENGTH_TOO_LONG +SSL,200,PARSE_TLSEXT +SSL,201,PATH_TOO_LONG +SSL,202,PEER_DID_NOT_RETURN_A_CERTIFICATE +SSL,203,PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE +SSL,204,PROTOCOL_IS_SHUTDOWN +SSL,205,PSK_IDENTITY_NOT_FOUND +SSL,206,PSK_NO_CLIENT_CB +SSL,207,PSK_NO_SERVER_CB +SSL,208,READ_BIO_NOT_SET +SSL,209,READ_TIMEOUT_EXPIRED +SSL,210,RECORD_LENGTH_MISMATCH +SSL,211,RECORD_TOO_LARGE +SSL,212,RENEGOTIATE_EXT_TOO_LONG +SSL,213,RENEGOTIATION_ENCODING_ERR +SSL,214,RENEGOTIATION_MISMATCH +SSL,215,REQUIRED_CIPHER_MISSING +SSL,275,RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION +SSL,277,RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION +SSL,216,SCSV_RECEIVED_WHEN_RENEGOTIATING +SSL,217,SERVERHELLO_TLSEXT +SSL,218,SESSION_ID_CONTEXT_UNINITIALIZED +SSL,219,SESSION_MAY_NOT_BE_CREATED +SSL,220,SIGNATURE_ALGORITHMS_ERROR +SSL,280,SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER +SSL,221,SRTP_COULD_NOT_ALLOCATE_PROFILES +SSL,222,SRTP_PROTECTION_PROFILE_LIST_TOO_LONG +SSL,223,SRTP_UNKNOWN_PROTECTION_PROFILE +SSL,224,SSL3_EXT_INVALID_SERVERNAME +SSL,225,SSL3_EXT_INVALID_SERVERNAME_TYPE +SSL,1042,SSLV3_ALERT_BAD_CERTIFICATE +SSL,1020,SSLV3_ALERT_BAD_RECORD_MAC +SSL,1045,SSLV3_ALERT_CERTIFICATE_EXPIRED +SSL,1044,SSLV3_ALERT_CERTIFICATE_REVOKED +SSL,1046,SSLV3_ALERT_CERTIFICATE_UNKNOWN +SSL,1000,SSLV3_ALERT_CLOSE_NOTIFY +SSL,1030,SSLV3_ALERT_DECOMPRESSION_FAILURE +SSL,1040,SSLV3_ALERT_HANDSHAKE_FAILURE +SSL,1047,SSLV3_ALERT_ILLEGAL_PARAMETER +SSL,1041,SSLV3_ALERT_NO_CERTIFICATE +SSL,1010,SSLV3_ALERT_UNEXPECTED_MESSAGE +SSL,1043,SSLV3_ALERT_UNSUPPORTED_CERTIFICATE +SSL,226,SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION +SSL,227,SSL_HANDSHAKE_FAILURE +SSL,228,SSL_SESSION_ID_CALLBACK_FAILED +SSL,229,SSL_SESSION_ID_CONFLICT +SSL,230,SSL_SESSION_ID_CONTEXT_TOO_LONG +SSL,231,SSL_SESSION_ID_HAS_BAD_LENGTH +SSL,1049,TLSV1_ALERT_ACCESS_DENIED +SSL,1050,TLSV1_ALERT_DECODE_ERROR +SSL,1021,TLSV1_ALERT_DECRYPTION_FAILED +SSL,1051,TLSV1_ALERT_DECRYPT_ERROR +SSL,1060,TLSV1_ALERT_EXPORT_RESTRICTION +SSL,1086,TLSV1_ALERT_INAPPROPRIATE_FALLBACK +SSL,1071,TLSV1_ALERT_INSUFFICIENT_SECURITY +SSL,1080,TLSV1_ALERT_INTERNAL_ERROR +SSL,1100,TLSV1_ALERT_NO_RENEGOTIATION +SSL,1070,TLSV1_ALERT_PROTOCOL_VERSION +SSL,1022,TLSV1_ALERT_RECORD_OVERFLOW +SSL,1048,TLSV1_ALERT_UNKNOWN_CA +SSL,1090,TLSV1_ALERT_USER_CANCELLED +SSL,1114,TLSV1_BAD_CERTIFICATE_HASH_VALUE +SSL,1113,TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE +SSL,1111,TLSV1_CERTIFICATE_UNOBTAINABLE +SSL,1112,TLSV1_UNRECOGNIZED_NAME +SSL,1110,TLSV1_UNSUPPORTED_EXTENSION +SSL,232,TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER +SSL,233,TLS_ILLEGAL_EXPORTER_LABEL +SSL,234,TLS_INVALID_ECPOINTFORMAT_LIST +SSL,235,TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST +SSL,236,TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG +SSL,237,TOO_MANY_EMPTY_FRAGMENTS +SSL,278,TOO_MANY_WARNING_ALERTS +SSL,238,UNABLE_TO_FIND_ECDH_PARAMETERS +SSL,239,UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS +SSL,279,UNEXPECTED_EXTENSION +SSL,240,UNEXPECTED_GROUP_CLOSE +SSL,241,UNEXPECTED_MESSAGE +SSL,242,UNEXPECTED_OPERATOR_IN_GROUP +SSL,243,UNEXPECTED_RECORD +SSL,244,UNINITIALIZED +SSL,245,UNKNOWN_ALERT_TYPE +SSL,246,UNKNOWN_CERTIFICATE_TYPE +SSL,247,UNKNOWN_CIPHER_RETURNED +SSL,248,UNKNOWN_CIPHER_TYPE +SSL,249,UNKNOWN_DIGEST +SSL,250,UNKNOWN_KEY_EXCHANGE_TYPE +SSL,251,UNKNOWN_PROTOCOL +SSL,252,UNKNOWN_SSL_VERSION +SSL,253,UNKNOWN_STATE +SSL,254,UNPROCESSED_HANDSHAKE_DATA +SSL,255,UNSAFE_LEGACY_RENEGOTIATION_DISABLED +SSL,256,UNSUPPORTED_CIPHER +SSL,257,UNSUPPORTED_COMPRESSION_ALGORITHM +SSL,258,UNSUPPORTED_ELLIPTIC_CURVE +SSL,259,UNSUPPORTED_PROTOCOL +SSL,260,UNSUPPORTED_SSL_VERSION +SSL,261,USE_SRTP_NOT_NEGOTIATED +SSL,262,WRONG_CERTIFICATE_TYPE +SSL,263,WRONG_CIPHER_RETURNED +SSL,264,WRONG_CURVE +SSL,265,WRONG_MESSAGE_TYPE +SSL,266,WRONG_SIGNATURE_TYPE +SSL,267,WRONG_SSL_VERSION +SSL,268,WRONG_VERSION_NUMBER +SSL,269,X509_LIB +SSL,270,X509_VERIFICATION_SETUP_PROBLEMS diff --git a/TMessagesProj/jni/boringssl/crypto/err/x509.errordata b/TMessagesProj/jni/boringssl/crypto/err/x509.errordata new file mode 100644 index 00000000..f4828ce8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/x509.errordata @@ -0,0 +1,37 @@ +X509,100,AKID_MISMATCH +X509,101,BAD_PKCS7_VERSION +X509,102,BAD_X509_FILETYPE +X509,103,BASE64_DECODE_ERROR +X509,104,CANT_CHECK_DH_KEY +X509,105,CERT_ALREADY_IN_HASH_TABLE +X509,106,CRL_ALREADY_DELTA +X509,107,CRL_VERIFY_FAILURE +X509,108,IDP_MISMATCH +X509,109,INVALID_BIT_STRING_BITS_LEFT +X509,110,INVALID_DIRECTORY +X509,111,INVALID_FIELD_NAME +X509,112,INVALID_TRUST +X509,113,ISSUER_MISMATCH +X509,114,KEY_TYPE_MISMATCH +X509,115,KEY_VALUES_MISMATCH +X509,116,LOADING_CERT_DIR +X509,117,LOADING_DEFAULTS +X509,118,METHOD_NOT_SUPPORTED +X509,119,NEWER_CRL_NOT_NEWER +X509,120,NOT_PKCS7_SIGNED_DATA +X509,121,NO_CERTIFICATES_INCLUDED +X509,122,NO_CERT_SET_FOR_US_TO_VERIFY +X509,136,NO_CRLS_INCLUDED +X509,123,NO_CRL_NUMBER +X509,124,PUBLIC_KEY_DECODE_ERROR +X509,125,PUBLIC_KEY_ENCODE_ERROR +X509,126,SHOULD_RETRY +X509,127,UNABLE_TO_FIND_PARAMETERS_IN_CHAIN +X509,128,UNABLE_TO_GET_CERTS_PUBLIC_KEY +X509,129,UNKNOWN_KEY_TYPE +X509,130,UNKNOWN_NID +X509,131,UNKNOWN_PURPOSE_ID +X509,132,UNKNOWN_TRUST_ID +X509,133,UNSUPPORTED_ALGORITHM +X509,134,WRONG_LOOKUP_TYPE +X509,135,WRONG_TYPE diff --git a/TMessagesProj/jni/boringssl/crypto/err/x509v3.errordata b/TMessagesProj/jni/boringssl/crypto/err/x509v3.errordata new file mode 100644 index 00000000..e53b7800 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/err/x509v3.errordata @@ -0,0 +1,63 @@ +X509V3,100,BAD_IP_ADDRESS +X509V3,101,BAD_OBJECT +X509V3,102,BN_DEC2BN_ERROR +X509V3,103,BN_TO_ASN1_INTEGER_ERROR +X509V3,104,CANNOT_FIND_FREE_FUNCTION +X509V3,105,DIRNAME_ERROR +X509V3,106,DISTPOINT_ALREADY_SET +X509V3,107,DUPLICATE_ZONE_ID +X509V3,108,ERROR_CONVERTING_ZONE +X509V3,109,ERROR_CREATING_EXTENSION +X509V3,110,ERROR_IN_EXTENSION +X509V3,111,EXPECTED_A_SECTION_NAME +X509V3,112,EXTENSION_EXISTS +X509V3,113,EXTENSION_NAME_ERROR +X509V3,114,EXTENSION_NOT_FOUND +X509V3,115,EXTENSION_SETTING_NOT_SUPPORTED +X509V3,116,EXTENSION_VALUE_ERROR +X509V3,117,ILLEGAL_EMPTY_EXTENSION +X509V3,118,ILLEGAL_HEX_DIGIT +X509V3,119,INCORRECT_POLICY_SYNTAX_TAG +X509V3,120,INVALID_BOOLEAN_STRING +X509V3,121,INVALID_EXTENSION_STRING +X509V3,122,INVALID_MULTIPLE_RDNS +X509V3,123,INVALID_NAME +X509V3,124,INVALID_NULL_ARGUMENT +X509V3,125,INVALID_NULL_NAME +X509V3,126,INVALID_NULL_VALUE +X509V3,127,INVALID_NUMBER +X509V3,128,INVALID_NUMBERS +X509V3,129,INVALID_OBJECT_IDENTIFIER +X509V3,130,INVALID_OPTION +X509V3,131,INVALID_POLICY_IDENTIFIER +X509V3,132,INVALID_PROXY_POLICY_SETTING +X509V3,133,INVALID_PURPOSE +X509V3,134,INVALID_SECTION +X509V3,135,INVALID_SYNTAX +X509V3,136,ISSUER_DECODE_ERROR +X509V3,137,MISSING_VALUE +X509V3,138,NEED_ORGANIZATION_AND_NUMBERS +X509V3,139,NO_CONFIG_DATABASE +X509V3,140,NO_ISSUER_CERTIFICATE +X509V3,141,NO_ISSUER_DETAILS +X509V3,142,NO_POLICY_IDENTIFIER +X509V3,143,NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED +X509V3,144,NO_PUBLIC_KEY +X509V3,145,NO_SUBJECT_DETAILS +X509V3,146,ODD_NUMBER_OF_DIGITS +X509V3,147,OPERATION_NOT_DEFINED +X509V3,148,OTHERNAME_ERROR +X509V3,149,POLICY_LANGUAGE_ALREADY_DEFINED +X509V3,150,POLICY_PATH_LENGTH +X509V3,151,POLICY_PATH_LENGTH_ALREADY_DEFINED +X509V3,152,POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY +X509V3,153,SECTION_NOT_FOUND +X509V3,154,UNABLE_TO_GET_ISSUER_DETAILS +X509V3,155,UNABLE_TO_GET_ISSUER_KEYID +X509V3,156,UNKNOWN_BIT_STRING_ARGUMENT +X509V3,157,UNKNOWN_EXTENSION +X509V3,158,UNKNOWN_EXTENSION_NAME +X509V3,159,UNKNOWN_OPTION +X509V3,160,UNSUPPORTED_OPTION +X509V3,161,UNSUPPORTED_TYPE +X509V3,162,USER_TOO_LONG diff --git a/TMessagesProj/jni/boringssl/crypto/evp/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/evp/CMakeLists.txt new file mode 100644 index 00000000..a81d9320 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/CMakeLists.txt @@ -0,0 +1,20 @@ +include_directories(. .. ../../include) + +add_library( + evp + + OBJECT + + algorithm.c + digestsign.c + evp.c + evp_asn1.c + evp_ctx.c + p_dsa_asn1.c + p_ec.c + p_ec_asn1.c + p_rsa.c + p_rsa_asn1.c + pbkdf.c + sign.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/evp/algorithm.c b/TMessagesProj/jni/boringssl/crypto/evp/algorithm.c new file mode 100644 index 00000000..63bc77af --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/algorithm.c @@ -0,0 +1,153 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + +#include "internal.h" + + +int EVP_DigestSignAlgorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor) { + const EVP_MD *digest; + EVP_PKEY *pkey; + int sign_nid, paramtype; + + digest = EVP_MD_CTX_md(ctx); + pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx); + if (!digest || !pkey) { + OPENSSL_PUT_ERROR(EVP, EVP_R_CONTEXT_NOT_INITIALISED); + return 0; + } + + if (pkey->ameth->digest_sign_algorithm) { + switch (pkey->ameth->digest_sign_algorithm(ctx, algor)) { + case EVP_DIGEST_SIGN_ALGORITHM_ERROR: + return 0; + case EVP_DIGEST_SIGN_ALGORITHM_SUCCESS: + return 1; + case EVP_DIGEST_SIGN_ALGORITHM_DEFAULT: + /* Use default behavior. */ + break; + default: + assert(0); + } + } + + /* Default behavior: look up the OID for the algorithm/hash pair and encode + * that. */ + if (!OBJ_find_sigid_by_algs(&sign_nid, EVP_MD_type(digest), + pkey->ameth->pkey_id)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED); + return 0; + } + + if (pkey->ameth->pkey_flags & ASN1_PKEY_SIGPARAM_NULL) { + paramtype = V_ASN1_NULL; + } else { + paramtype = V_ASN1_UNDEF; + } + + X509_ALGOR_set0(algor, OBJ_nid2obj(sign_nid), paramtype, NULL); + return 1; +} + +int EVP_DigestVerifyInitFromAlgorithm(EVP_MD_CTX *ctx, + X509_ALGOR *algor, + EVP_PKEY *pkey) { + int digest_nid, pkey_nid; + const EVP_PKEY_ASN1_METHOD *ameth; + const EVP_MD *digest; + + /* Convert signature OID into digest and public key OIDs */ + if (!OBJ_find_sigid_algs(OBJ_obj2nid(algor->algorithm), &digest_nid, + &pkey_nid)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_SIGNATURE_ALGORITHM); + return 0; + } + + /* Check public key OID matches public key type */ + ameth = EVP_PKEY_asn1_find(NULL, pkey_nid); + if (ameth == NULL || ameth->pkey_id != pkey->ameth->pkey_id) { + OPENSSL_PUT_ERROR(EVP, EVP_R_WRONG_PUBLIC_KEY_TYPE); + return 0; + } + + /* NID_undef signals that there are custom parameters to set. */ + if (digest_nid == NID_undef) { + if (!pkey->ameth || !pkey->ameth->digest_verify_init_from_algorithm) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_SIGNATURE_ALGORITHM); + return 0; + } + + return pkey->ameth->digest_verify_init_from_algorithm(ctx, algor, pkey); + } + + /* Otherwise, initialize with the digest from the OID. */ + digest = EVP_get_digestbynid(digest_nid); + if (digest == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM); + return 0; + } + + return EVP_DigestVerifyInit(ctx, NULL, digest, NULL, pkey); +} + diff --git a/TMessagesProj/jni/boringssl/crypto/evp/digestsign.c b/TMessagesProj/jni/boringssl/crypto/evp/digestsign.c new file mode 100644 index 00000000..ccb4de4f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/digestsign.c @@ -0,0 +1,164 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006. + */ +/* ==================================================================== + * Copyright (c) 2006,2007 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include "internal.h" +#include "../digest/internal.h" + + +static const struct evp_md_pctx_ops md_pctx_ops = { + EVP_PKEY_CTX_free, + EVP_PKEY_CTX_dup, +}; + +static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey, + int is_verify) { + if (ctx->pctx == NULL) { + ctx->pctx = EVP_PKEY_CTX_new(pkey, e); + } + if (ctx->pctx == NULL) { + return 0; + } + ctx->pctx_ops = &md_pctx_ops; + + if (type == NULL) { + type = EVP_sha1(); + } + + if (type == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_DEFAULT_DIGEST); + return 0; + } + + if (is_verify) { + if (!EVP_PKEY_verify_init(ctx->pctx)) { + return 0; + } + } else { + if (!EVP_PKEY_sign_init(ctx->pctx)) { + return 0; + } + } + if (!EVP_PKEY_CTX_set_signature_md(ctx->pctx, type)) { + return 0; + } + if (pctx) { + *pctx = ctx->pctx; + } + if (!EVP_DigestInit_ex(ctx, type, e)) { + return 0; + } + return 1; +} + +int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, + ENGINE *e, EVP_PKEY *pkey) { + return do_sigver_init(ctx, pctx, type, e, pkey, 0); +} + +int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey) { + return do_sigver_init(ctx, pctx, type, e, pkey, 1); +} + +int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) { + return EVP_DigestUpdate(ctx, data, len); +} + +int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) { + return EVP_DigestUpdate(ctx, data, len); +} + +int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig, + size_t *out_sig_len) { + if (out_sig) { + EVP_MD_CTX tmp_ctx; + int ret; + uint8_t md[EVP_MAX_MD_SIZE]; + unsigned int mdlen; + + EVP_MD_CTX_init(&tmp_ctx); + ret = EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) && + EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen) && + EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen); + EVP_MD_CTX_cleanup(&tmp_ctx); + + return ret; + } else { + size_t s = EVP_MD_size(ctx->digest); + return EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, NULL, s); + } +} + +int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, + size_t sig_len) { + EVP_MD_CTX tmp_ctx; + int ret; + uint8_t md[EVP_MAX_MD_SIZE]; + unsigned int mdlen; + + EVP_MD_CTX_init(&tmp_ctx); + ret = EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) && + EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen) && + EVP_PKEY_verify(ctx->pctx, sig, sig_len, md, mdlen); + EVP_MD_CTX_cleanup(&tmp_ctx); + + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/evp/evp.c b/TMessagesProj/jni/boringssl/crypto/evp/evp.c new file mode 100644 index 00000000..a8116aad --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/evp.c @@ -0,0 +1,414 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +extern const EVP_PKEY_ASN1_METHOD dsa_asn1_meth; +extern const EVP_PKEY_ASN1_METHOD ec_asn1_meth; +extern const EVP_PKEY_ASN1_METHOD rsa_asn1_meth; + +EVP_PKEY *EVP_PKEY_new(void) { + EVP_PKEY *ret; + + ret = OPENSSL_malloc(sizeof(EVP_PKEY)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(ret, 0, sizeof(EVP_PKEY)); + ret->type = EVP_PKEY_NONE; + ret->references = 1; + + return ret; +} + +static void free_it(EVP_PKEY *pkey) { + if (pkey->ameth && pkey->ameth->pkey_free) { + pkey->ameth->pkey_free(pkey); + pkey->pkey.ptr = NULL; + pkey->type = EVP_PKEY_NONE; + } +} + +void EVP_PKEY_free(EVP_PKEY *pkey) { + if (pkey == NULL) { + return; + } + + if (!CRYPTO_refcount_dec_and_test_zero(&pkey->references)) { + return; + } + + free_it(pkey); + OPENSSL_free(pkey); +} + +EVP_PKEY *EVP_PKEY_up_ref(EVP_PKEY *pkey) { + CRYPTO_refcount_inc(&pkey->references); + return pkey; +} + +int EVP_PKEY_is_opaque(const EVP_PKEY *pkey) { + if (pkey->ameth && pkey->ameth->pkey_opaque) { + return pkey->ameth->pkey_opaque(pkey); + } + return 0; +} + +int EVP_PKEY_supports_digest(const EVP_PKEY *pkey, const EVP_MD *md) { + if (pkey->ameth && pkey->ameth->pkey_supports_digest) { + return pkey->ameth->pkey_supports_digest(pkey, md); + } + return 1; +} + +int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { + if (a->type != b->type) { + return -1; + } + + if (a->ameth) { + int ret; + /* Compare parameters if the algorithm has them */ + if (a->ameth->param_cmp) { + ret = a->ameth->param_cmp(a, b); + if (ret <= 0) { + return ret; + } + } + + if (a->ameth->pub_cmp) { + return a->ameth->pub_cmp(a, b); + } + } + + return -2; +} + +int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) { + if (to->type != from->type) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES); + goto err; + } + + if (EVP_PKEY_missing_parameters(from)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS); + goto err; + } + + if (from->ameth && from->ameth->param_copy) { + return from->ameth->param_copy(to, from); + } + +err: + return 0; +} + +int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey) { + if (pkey->ameth && pkey->ameth->param_missing) { + return pkey->ameth->param_missing(pkey); + } + return 0; +} + +int EVP_PKEY_size(const EVP_PKEY *pkey) { + if (pkey && pkey->ameth && pkey->ameth->pkey_size) { + return pkey->ameth->pkey_size(pkey); + } + return 0; +} + +int EVP_PKEY_bits(EVP_PKEY *pkey) { + if (pkey && pkey->ameth && pkey->ameth->pkey_bits) { + return pkey->ameth->pkey_bits(pkey); + } + return 0; +} + +int EVP_PKEY_id(const EVP_PKEY *pkey) { + return pkey->type; +} + +/* TODO(fork): remove the first argument. */ +const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pengine, int nid) { + switch (nid) { + case EVP_PKEY_RSA: + case EVP_PKEY_RSA2: + return &rsa_asn1_meth; + case EVP_PKEY_EC: + return &ec_asn1_meth; + case EVP_PKEY_DSA: + return &dsa_asn1_meth; + default: + return NULL; + } +} + +int EVP_PKEY_type(int nid) { + const EVP_PKEY_ASN1_METHOD *meth = EVP_PKEY_asn1_find(NULL, nid); + if (meth == NULL) { + return NID_undef; + } + return meth->pkey_id; +} + +int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key) { + if (EVP_PKEY_assign_RSA(pkey, key)) { + RSA_up_ref(key); + return 1; + } + return 0; +} + +int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key) { + return EVP_PKEY_assign(pkey, EVP_PKEY_RSA, key); +} + +RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey) { + if (pkey->type != EVP_PKEY_RSA) { + OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_AN_RSA_KEY); + return NULL; + } + RSA_up_ref(pkey->pkey.rsa); + return pkey->pkey.rsa; +} + +int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, DSA *key) { + if (EVP_PKEY_assign_DSA(pkey, key)) { + DSA_up_ref(key); + return 1; + } + return 0; +} + +int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key) { + return EVP_PKEY_assign(pkey, EVP_PKEY_DSA, key); +} + +DSA *EVP_PKEY_get1_DSA(EVP_PKEY *pkey) { + if (pkey->type != EVP_PKEY_DSA) { + OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_A_DSA_KEY); + return NULL; + } + DSA_up_ref(pkey->pkey.dsa); + return pkey->pkey.dsa; +} + +int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) { + if (EVP_PKEY_assign_EC_KEY(pkey, key)) { + EC_KEY_up_ref(key); + return 1; + } + return 0; +} + +int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key) { + return EVP_PKEY_assign(pkey, EVP_PKEY_EC, key); +} + +EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey) { + if (pkey->type != EVP_PKEY_EC) { + OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_AN_EC_KEY_KEY); + return NULL; + } + EC_KEY_up_ref(pkey->pkey.ec); + return pkey->pkey.ec; +} + +int EVP_PKEY_set1_DH(EVP_PKEY *pkey, DH *key) { + if (EVP_PKEY_assign_DH(pkey, key)) { + DH_up_ref(key); + return 1; + } + return 0; +} + +int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key) { + return EVP_PKEY_assign(pkey, EVP_PKEY_DH, key); +} + +DH *EVP_PKEY_get1_DH(EVP_PKEY *pkey) { + if (pkey->type != EVP_PKEY_DH) { + OPENSSL_PUT_ERROR(EVP, EVP_R_EXPECTING_A_DH_KEY); + return NULL; + } + DH_up_ref(pkey->pkey.dh); + return pkey->pkey.dh; +} + +int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key) { + if (!EVP_PKEY_set_type(pkey, type)) { + return 0; + } + pkey->pkey.ptr = key; + return key != NULL; +} + +const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str(ENGINE **pengine, + const char *name, + size_t len) { + if (len == 3 && memcmp(name, "RSA", 3) == 0) { + return &rsa_asn1_meth; + } if (len == 2 && memcmp(name, "EC", 2) == 0) { + return &ec_asn1_meth; + } + return NULL; +} + +int EVP_PKEY_set_type(EVP_PKEY *pkey, int type) { + const EVP_PKEY_ASN1_METHOD *ameth; + + if (pkey && pkey->pkey.ptr) { + free_it(pkey); + } + + ameth = EVP_PKEY_asn1_find(NULL, type); + if (ameth == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); + ERR_add_error_dataf("algorithm %d (%s)", type, OBJ_nid2sn(type)); + return 0; + } + + if (pkey) { + pkey->ameth = ameth; + pkey->type = pkey->ameth->pkey_id; + } + + return 1; +} + + + +int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) { + if (a->type != b->type) { + return -1; + } + if (a->ameth && a->ameth->param_cmp) { + return a->ameth->param_cmp(a, b); + } + return -2; +} + +static int print_unsupported(BIO *out, const EVP_PKEY *pkey, int indent, + const char *kstr) { + BIO_indent(out, indent, 128); + BIO_printf(out, "%s algorithm \"%s\" unsupported\n", kstr, + OBJ_nid2ln(pkey->type)); + return 1; +} + +int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) { + if (pkey->ameth && pkey->ameth->pub_print) { + return pkey->ameth->pub_print(out, pkey, indent, pctx); + } + + return print_unsupported(out, pkey, indent, "Public Key"); +} + +int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) { + if (pkey->ameth && pkey->ameth->priv_print) { + return pkey->ameth->priv_print(out, pkey, indent, pctx); + } + + return print_unsupported(out, pkey, indent, "Private Key"); +} + +int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx) { + if (pkey->ameth && pkey->ameth->param_print) { + return pkey->ameth->param_print(out, pkey, indent, pctx); + } + + return print_unsupported(out, pkey, indent, "Parameters"); +} + +int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) { + return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, 0, + (void *)md); +} + +int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) { + return EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_GET_MD, + 0, (void *)out_md); +} + +void OpenSSL_add_all_algorithms(void) {} + +void OpenSSL_add_all_ciphers(void) {} + +void OpenSSL_add_all_digests(void) {} + +void EVP_cleanup(void) {} diff --git a/TMessagesProj/jni/boringssl/crypto/evp/evp_asn1.c b/TMessagesProj/jni/boringssl/crypto/evp/evp_asn1.c new file mode 100644 index 00000000..356c62b8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/evp_asn1.c @@ -0,0 +1,166 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include + +#include "internal.h" + + +EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, const uint8_t **inp, + long len) { + EVP_PKEY *ret; + + if (out == NULL || *out == NULL) { + ret = EVP_PKEY_new(); + if (ret == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB); + return NULL; + } + } else { + ret = *out; + } + + if (!EVP_PKEY_set_type(ret, type)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_PUBLIC_KEY_TYPE); + goto err; + } + + if (!ret->ameth->old_priv_decode || + !ret->ameth->old_priv_decode(ret, inp, len)) { + if (ret->ameth->priv_decode) { + PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, inp, len); + if (!p8) { + goto err; + } + EVP_PKEY_free(ret); + ret = EVP_PKCS82PKEY(p8); + PKCS8_PRIV_KEY_INFO_free(p8); + } else { + OPENSSL_PUT_ERROR(EVP, ERR_R_ASN1_LIB); + goto err; + } + } + + if (out != NULL) { + *out = ret; + } + return ret; + +err: + if (out == NULL || *out != ret) { + EVP_PKEY_free(ret); + } + return NULL; +} + +EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, long len) { + STACK_OF(ASN1_TYPE) *inkey; + const uint8_t *p; + int keytype; + p = *inp; + + /* Dirty trick: read in the ASN1 data into out STACK_OF(ASN1_TYPE): + * by analyzing it we can determine the passed structure: this + * assumes the input is surrounded by an ASN1 SEQUENCE. */ + inkey = d2i_ASN1_SEQUENCE_ANY(NULL, &p, len); + /* Since we only need to discern "traditional format" RSA and DSA + * keys we can just count the elements. */ + if (sk_ASN1_TYPE_num(inkey) == 6) { + keytype = EVP_PKEY_DSA; + } else if (sk_ASN1_TYPE_num(inkey) == 4) { + keytype = EVP_PKEY_EC; + } else if (sk_ASN1_TYPE_num(inkey) == 3) { + /* This seems to be PKCS8, not traditional format */ + PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, inp, len); + EVP_PKEY *ret; + + sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free); + if (!p8) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE); + return NULL; + } + ret = EVP_PKCS82PKEY(p8); + PKCS8_PRIV_KEY_INFO_free(p8); + if (out) { + *out = ret; + } + return ret; + } else { + keytype = EVP_PKEY_RSA; + } + + sk_ASN1_TYPE_pop_free(inkey, ASN1_TYPE_free); + return d2i_PrivateKey(keytype, out, inp, len); +} + +int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp) { + switch (key->type) { + case EVP_PKEY_RSA: + return i2d_RSAPublicKey(key->pkey.rsa, outp); + case EVP_PKEY_DSA: + return i2d_DSAPublicKey(key->pkey.dsa, outp); + case EVP_PKEY_EC: + return i2o_ECPublicKey(key->pkey.ec, outp); + default: + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE); + return -1; + } +} diff --git a/TMessagesProj/jni/boringssl/crypto/evp/evp_ctx.c b/TMessagesProj/jni/boringssl/crypto/evp/evp_ctx.c new file mode 100644 index 00000000..a8e71fea --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/evp_ctx.c @@ -0,0 +1,480 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include + +#include "internal.h" + + +extern const EVP_PKEY_METHOD rsa_pkey_meth; +extern const EVP_PKEY_METHOD ec_pkey_meth; + +static const EVP_PKEY_METHOD *const evp_methods[] = { + &rsa_pkey_meth, + &ec_pkey_meth, +}; + +static const EVP_PKEY_METHOD *evp_pkey_meth_find(int type) { + unsigned i; + + for (i = 0; i < sizeof(evp_methods)/sizeof(EVP_PKEY_METHOD*); i++) { + if (evp_methods[i]->pkey_id == type) { + return evp_methods[i]; + } + } + + return NULL; +} + +static EVP_PKEY_CTX *evp_pkey_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id) { + EVP_PKEY_CTX *ret; + const EVP_PKEY_METHOD *pmeth; + + if (id == -1) { + if (!pkey || !pkey->ameth) { + return NULL; + } + id = pkey->ameth->pkey_id; + } + + pmeth = evp_pkey_meth_find(id); + + if (pmeth == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM); + const char *name = OBJ_nid2sn(id); + ERR_add_error_dataf("algorithm %d (%s)", id, name); + return NULL; + } + + ret = OPENSSL_malloc(sizeof(EVP_PKEY_CTX)); + if (!ret) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + return NULL; + } + memset(ret, 0, sizeof(EVP_PKEY_CTX)); + + ret->engine = e; + ret->pmeth = pmeth; + ret->operation = EVP_PKEY_OP_UNDEFINED; + + if (pkey) { + ret->pkey = EVP_PKEY_up_ref(pkey); + } + + if (pmeth->init) { + if (pmeth->init(ret) <= 0) { + EVP_PKEY_free(ret->pkey); + OPENSSL_free(ret); + return NULL; + } + } + + return ret; +} + +EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e) { + return evp_pkey_ctx_new(pkey, e, -1); +} + +EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e) { + return evp_pkey_ctx_new(NULL, e, id); +} + +void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx) { + if (ctx == NULL) { + return; + } + if (ctx->pmeth && ctx->pmeth->cleanup) { + ctx->pmeth->cleanup(ctx); + } + EVP_PKEY_free(ctx->pkey); + EVP_PKEY_free(ctx->peerkey); + OPENSSL_free(ctx); +} + +EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *pctx) { + EVP_PKEY_CTX *rctx; + + if (!pctx->pmeth || !pctx->pmeth->copy) { + return NULL; + } + + rctx = OPENSSL_malloc(sizeof(EVP_PKEY_CTX)); + if (!rctx) { + return NULL; + } + + memset(rctx, 0, sizeof(EVP_PKEY_CTX)); + + rctx->pmeth = pctx->pmeth; + rctx->engine = pctx->engine; + rctx->operation = pctx->operation; + + if (pctx->pkey) { + rctx->pkey = EVP_PKEY_up_ref(pctx->pkey); + if (rctx->pkey == NULL) { + goto err; + } + } + + if (pctx->peerkey) { + rctx->peerkey = EVP_PKEY_up_ref(pctx->peerkey); + if (rctx->peerkey == NULL) { + goto err; + } + } + + if (pctx->pmeth->copy(rctx, pctx) > 0) { + return rctx; + } + +err: + EVP_PKEY_CTX_free(rctx); + OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP); + return NULL; +} + +EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx) { return ctx->pkey; } + +void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data) { + ctx->app_data = data; +} + +void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx) { return ctx->app_data; } + +int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, int cmd, + int p1, void *p2) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->ctrl) { + OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return 0; + } + if (keytype != -1 && ctx->pmeth->pkey_id != keytype) { + return 0; + } + + if (ctx->operation == EVP_PKEY_OP_UNDEFINED) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_OPERATION_SET); + return 0; + } + + if (optype != -1 && !(ctx->operation & optype)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_OPERATION); + return 0; + } + + return ctx->pmeth->ctrl(ctx, cmd, p1, p2); +} + +int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + + ctx->operation = EVP_PKEY_OP_SIGN; + if (!ctx->pmeth->sign_init) { + return 1; + } + + if (!ctx->pmeth->sign_init(ctx)) { + ctx->operation = EVP_PKEY_OP_UNDEFINED; + return 0; + } + + return 1; +} + +int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *sig_len, + const uint8_t *data, size_t data_len) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (ctx->operation != EVP_PKEY_OP_SIGN) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + return ctx->pmeth->sign(ctx, sig, sig_len, data, data_len); +} + +int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + ctx->operation = EVP_PKEY_OP_VERIFY; + if (!ctx->pmeth->verify_init) { + return 1; + } + if (!ctx->pmeth->verify_init(ctx)) { + ctx->operation = EVP_PKEY_OP_UNDEFINED; + return 0; + } + + return 1; +} + +int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t sig_len, + const uint8_t *data, size_t data_len) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->verify) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (ctx->operation != EVP_PKEY_OP_VERIFY) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + return ctx->pmeth->verify(ctx, sig, sig_len, data, data_len); +} + +int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + ctx->operation = EVP_PKEY_OP_ENCRYPT; + if (!ctx->pmeth->encrypt_init) { + return 1; + } + if (!ctx->pmeth->encrypt_init(ctx)) { + ctx->operation = EVP_PKEY_OP_UNDEFINED; + return 0; + } + return 1; +} + +int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen, + const uint8_t *in, size_t inlen) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->encrypt) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (ctx->operation != EVP_PKEY_OP_ENCRYPT) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + return ctx->pmeth->encrypt(ctx, out, outlen, in, inlen); +} + +int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + ctx->operation = EVP_PKEY_OP_DECRYPT; + if (!ctx->pmeth->decrypt_init) { + return 1; + } + if (!ctx->pmeth->decrypt_init(ctx)) { + ctx->operation = EVP_PKEY_OP_UNDEFINED; + return 0; + } + return 1; +} + +int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen, + const uint8_t *in, size_t inlen) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->decrypt) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (ctx->operation != EVP_PKEY_OP_DECRYPT) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + return ctx->pmeth->decrypt(ctx, out, outlen, in, inlen); +} + +int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + ctx->operation = EVP_PKEY_OP_DERIVE; + if (!ctx->pmeth->derive_init) { + return 1; + } + if (!ctx->pmeth->derive_init(ctx)) { + ctx->operation = EVP_PKEY_OP_UNDEFINED; + return 0; + } + return 1; +} + +int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer) { + int ret; + if (!ctx || !ctx->pmeth || + !(ctx->pmeth->derive || ctx->pmeth->encrypt || ctx->pmeth->decrypt) || + !ctx->pmeth->ctrl) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (ctx->operation != EVP_PKEY_OP_DERIVE && + ctx->operation != EVP_PKEY_OP_ENCRYPT && + ctx->operation != EVP_PKEY_OP_DECRYPT) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + + ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 0, peer); + + if (ret <= 0) { + return 0; + } + + if (ret == 2) { + return 1; + } + + if (!ctx->pkey) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_KEY_SET); + return 0; + } + + if (ctx->pkey->type != peer->type) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_KEY_TYPES); + return 0; + } + + /* ran@cryptocom.ru: For clarity. The error is if parameters in peer are + * present (!missing) but don't match. EVP_PKEY_cmp_parameters may return + * 1 (match), 0 (don't match) and -2 (comparison is not defined). -1 + * (different key types) is impossible here because it is checked earlier. + * -2 is OK for us here, as well as 1, so we can check for 0 only. */ + if (!EVP_PKEY_missing_parameters(peer) && + !EVP_PKEY_cmp_parameters(ctx->pkey, peer)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DIFFERENT_PARAMETERS); + return 0; + } + + EVP_PKEY_free(ctx->peerkey); + ctx->peerkey = peer; + + ret = ctx->pmeth->ctrl(ctx, EVP_PKEY_CTRL_PEER_KEY, 1, peer); + + if (ret <= 0) { + ctx->peerkey = NULL; + return 0; + } + + EVP_PKEY_up_ref(peer); + return 1; +} + +int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, uint8_t *key, size_t *out_key_len) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->derive) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (ctx->operation != EVP_PKEY_OP_DERIVE) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + return ctx->pmeth->derive(ctx, key, out_key_len); +} + +int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + ctx->operation = EVP_PKEY_OP_KEYGEN; + if (!ctx->pmeth->keygen_init) { + return 1; + } + if (!ctx->pmeth->keygen_init(ctx)) { + ctx->operation = EVP_PKEY_OP_UNDEFINED; + return 0; + } + return 1; +} + +int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey) { + if (!ctx || !ctx->pmeth || !ctx->pmeth->keygen) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); + return 0; + } + if (ctx->operation != EVP_PKEY_OP_KEYGEN) { + OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATON_NOT_INITIALIZED); + return 0; + } + + if (!ppkey) { + return 0; + } + + if (!*ppkey) { + *ppkey = EVP_PKEY_new(); + if (!*ppkey) { + OPENSSL_PUT_ERROR(EVP, ERR_LIB_EVP); + return 0; + } + } + + if (!ctx->pmeth->keygen(ctx, *ppkey)) { + EVP_PKEY_free(*ppkey); + *ppkey = NULL; + return 0; + } + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/evp/internal.h b/TMessagesProj/jni/boringssl/crypto/evp/internal.h new file mode 100644 index 00000000..60881e3b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/internal.h @@ -0,0 +1,271 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_EVP_INTERNAL_H +#define OPENSSL_HEADER_EVP_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* These values are flags for EVP_PKEY_ASN1_METHOD.flags. */ + +/* ASN1_PKEY_SIGPARAM_NULL controls whether the default behavior of + * EVP_DigestSignAlgorithm writes an explicit NULL parameter in the + * AlgorithmIdentifier. */ +#define ASN1_PKEY_SIGPARAM_NULL 0x1 + +/* evp_digest_sign_algorithm_result_t is the return value of the + * digest_sign_algorithm function in EVP_PKEY_ASN1_METHOD. */ +typedef enum { + /* EVP_DIGEST_SIGN_ALGORITHM_ERROR signals an error. */ + EVP_DIGEST_SIGN_ALGORITHM_ERROR = 0, + /* EVP_DIGEST_SIGN_ALGORITHM_SUCCESS signals that the parameters were + * serialized in the AlgorithmIdentifier. */ + EVP_DIGEST_SIGN_ALGORITHM_SUCCESS = 1, + /* EVP_DIGEST_SIGN_ALGORITHM_DEFAULT signals that the parameters are + * serialized using the default behavior. */ + EVP_DIGEST_SIGN_ALGORITHM_DEFAULT = 2, +} evp_digest_sign_algorithm_result_t; + +struct evp_pkey_asn1_method_st { + int pkey_id; + int pkey_base_id; + unsigned long pkey_flags; + + const char *pem_str; + + int (*pub_decode)(EVP_PKEY *pk, X509_PUBKEY *pub); + int (*pub_encode)(X509_PUBKEY *pub, const EVP_PKEY *pk); + int (*pub_cmp)(const EVP_PKEY *a, const EVP_PKEY *b); + int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx); + + int (*priv_decode)(EVP_PKEY *pk, PKCS8_PRIV_KEY_INFO *p8inf); + int (*priv_encode)(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk); + int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx); + + /* pkey_opaque returns 1 if the |pk| is opaque. Opaque keys are backed by + * custom implementations which do not expose key material and parameters.*/ + int (*pkey_opaque)(const EVP_PKEY *pk); + + /* pkey_supports_digest returns one if |pkey| supports digests of + * type |md|. This is intended for use with EVP_PKEYs backing custom + * implementations which can't sign all digests. If null, it is + * assumed that all digests are supported. */ + int (*pkey_supports_digest)(const EVP_PKEY *pkey, const EVP_MD *md); + + int (*pkey_size)(const EVP_PKEY *pk); + int (*pkey_bits)(const EVP_PKEY *pk); + + int (*param_decode)(EVP_PKEY *pkey, const uint8_t **pder, int derlen); + int (*param_encode)(const EVP_PKEY *pkey, uint8_t **pder); + int (*param_missing)(const EVP_PKEY *pk); + int (*param_copy)(EVP_PKEY *to, const EVP_PKEY *from); + int (*param_cmp)(const EVP_PKEY *a, const EVP_PKEY *b); + int (*param_print)(BIO *out, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *pctx); + int (*sig_print)(BIO *out, const X509_ALGOR *sigalg, const ASN1_STRING *sig, + int indent, ASN1_PCTX *pctx); + + + void (*pkey_free)(EVP_PKEY *pkey); + + /* Legacy functions for old PEM */ + + int (*old_priv_decode)(EVP_PKEY *pkey, const uint8_t **pder, + int derlen); + int (*old_priv_encode)(const EVP_PKEY *pkey, uint8_t **pder); + + /* Converting parameters to/from AlgorithmIdentifier (X509_ALGOR). */ + int (*digest_verify_init_from_algorithm)(EVP_MD_CTX *ctx, + X509_ALGOR *algor, + EVP_PKEY *pkey); + evp_digest_sign_algorithm_result_t (*digest_sign_algorithm)( + EVP_MD_CTX *ctx, + X509_ALGOR *algor); + +} /* EVP_PKEY_ASN1_METHOD */; + + +typedef int EVP_PKEY_gen_cb(EVP_PKEY_CTX *ctx); + +#define EVP_PKEY_OP_UNDEFINED 0 +#define EVP_PKEY_OP_PARAMGEN (1 << 1) +#define EVP_PKEY_OP_KEYGEN (1 << 2) +#define EVP_PKEY_OP_SIGN (1 << 3) +#define EVP_PKEY_OP_VERIFY (1 << 4) +#define EVP_PKEY_OP_VERIFYRECOVER (1 << 5) +#define EVP_PKEY_OP_ENCRYPT (1 << 6) +#define EVP_PKEY_OP_DECRYPT (1 << 7) +#define EVP_PKEY_OP_DERIVE (1 << 8) + +#define EVP_PKEY_OP_TYPE_SIG \ + (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY | EVP_PKEY_OP_VERIFYRECOVER) + +#define EVP_PKEY_OP_TYPE_CRYPT (EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT) + +#define EVP_PKEY_OP_TYPE_NOGEN \ + (EVP_PKEY_OP_SIG | EVP_PKEY_OP_CRYPT | EVP_PKEY_OP_DERIVE) + +#define EVP_PKEY_OP_TYPE_GEN (EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN) + +/* EVP_PKEY_CTX_ctrl performs |cmd| on |ctx|. The |keytype| and |optype| + * arguments can be -1 to specify that any type and operation are acceptable, + * otherwise |keytype| must match the type of |ctx| and the bits of |optype| + * must intersect the operation flags set on |ctx|. + * + * The |p1| and |p2| arguments depend on the value of |cmd|. + * + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_ctrl(EVP_PKEY_CTX *ctx, int keytype, int optype, + int cmd, int p1, void *p2); + +#define EVP_PKEY_CTRL_MD 1 +#define EVP_PKEY_CTRL_GET_MD 2 + +/* EVP_PKEY_CTRL_PEER_KEY is called with different values of |p1|: + * 0: Is called from |EVP_PKEY_derive_set_peer| and |p2| contains a peer key. + * If the return value is <= 0, the key is rejected. + * 1: Is called at the end of |EVP_PKEY_derive_set_peer| and |p2| contains a + * peer key. If the return value is <= 0, the key is rejected. + * 2: Is called with |p2| == NULL to test whether the peer's key was used. + * (EC)DH always return one in this case. + * 3: Is called with |p2| == NULL to set whether the peer's key was used. + * (EC)DH always return one in this case. This was only used for GOST. */ +#define EVP_PKEY_CTRL_PEER_KEY 3 + +/* EVP_PKEY_ALG_CTRL is the base value from which key-type specific ctrl + * commands are numbered. */ +#define EVP_PKEY_ALG_CTRL 0x1000 + +#define EVP_PKEY_CTRL_RSA_PADDING (EVP_PKEY_ALG_CTRL + 1) +#define EVP_PKEY_CTRL_GET_RSA_PADDING (EVP_PKEY_ALG_CTRL + 2) +#define EVP_PKEY_CTRL_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 3) +#define EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN (EVP_PKEY_ALG_CTRL + 4) +#define EVP_PKEY_CTRL_RSA_KEYGEN_BITS (EVP_PKEY_ALG_CTRL + 5) +#define EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP (EVP_PKEY_ALG_CTRL + 6) +#define EVP_PKEY_CTRL_RSA_OAEP_MD (EVP_PKEY_ALG_CTRL + 7) +#define EVP_PKEY_CTRL_GET_RSA_OAEP_MD (EVP_PKEY_ALG_CTRL + 8) +#define EVP_PKEY_CTRL_RSA_MGF1_MD (EVP_PKEY_ALG_CTRL + 9) +#define EVP_PKEY_CTRL_GET_RSA_MGF1_MD (EVP_PKEY_ALG_CTRL + 10) +#define EVP_PKEY_CTRL_RSA_OAEP_LABEL (EVP_PKEY_ALG_CTRL + 11) +#define EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL (EVP_PKEY_ALG_CTRL + 12) + +#define EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID (EVP_PKEY_ALG_CTRL + 1) + +struct evp_pkey_ctx_st { + /* Method associated with this operation */ + const EVP_PKEY_METHOD *pmeth; + /* Engine that implements this method or NULL if builtin */ + ENGINE *engine; + /* Key: may be NULL */ + EVP_PKEY *pkey; + /* Peer key for key agreement, may be NULL */ + EVP_PKEY *peerkey; + /* operation contains one of the |EVP_PKEY_OP_*| values. */ + int operation; + /* Algorithm specific data */ + void *data; + /* Application specific data */ + void *app_data; +} /* EVP_PKEY_CTX */; + +struct evp_pkey_method_st { + int pkey_id; + int flags; + + int (*init)(EVP_PKEY_CTX *ctx); + int (*copy)(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src); + void (*cleanup)(EVP_PKEY_CTX *ctx); + + int (*paramgen_init)(EVP_PKEY_CTX *ctx); + int (*paramgen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey); + + int (*keygen_init)(EVP_PKEY_CTX *ctx); + int (*keygen)(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey); + + int (*sign_init)(EVP_PKEY_CTX *ctx); + int (*sign)(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen, + const uint8_t *tbs, size_t tbslen); + + int (*verify_init)(EVP_PKEY_CTX *ctx); + int (*verify)(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen, + const uint8_t *tbs, size_t tbslen); + + int (*encrypt_init)(EVP_PKEY_CTX *ctx); + int (*encrypt)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen, + const uint8_t *in, size_t inlen); + + int (*decrypt_init)(EVP_PKEY_CTX *ctx); + int (*decrypt)(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen, + const uint8_t *in, size_t inlen); + + int (*derive_init)(EVP_PKEY_CTX *ctx); + int (*derive)(EVP_PKEY_CTX *ctx, uint8_t *key, size_t *keylen); + + int (*ctrl)(EVP_PKEY_CTX *ctx, int type, int p1, void *p2); +} /* EVP_PKEY_METHOD */; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_EVP_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/evp/p_dsa_asn1.c b/TMessagesProj/jni/boringssl/crypto/evp/p_dsa_asn1.c new file mode 100644 index 00000000..4790cf62 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/p_dsa_asn1.c @@ -0,0 +1,585 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project + * 2006. + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../dsa/internal.h" +#include "internal.h" + + +static int dsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) { + const uint8_t *p, *pm; + int pklen, pmlen; + int ptype; + void *pval; + ASN1_STRING *pstr; + X509_ALGOR *palg; + ASN1_INTEGER *public_key = NULL; + + DSA *dsa = NULL; + + if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) { + return 0; + } + X509_ALGOR_get0(NULL, &ptype, &pval, palg); + + if (ptype == V_ASN1_SEQUENCE) { + pstr = pval; + pm = pstr->data; + pmlen = pstr->length; + + dsa = d2i_DSAparams(NULL, &pm, pmlen); + if (dsa == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + goto err; + } + } else if (ptype == V_ASN1_NULL || ptype == V_ASN1_UNDEF) { + dsa = DSA_new(); + if (dsa == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + } else { + OPENSSL_PUT_ERROR(EVP, EVP_R_PARAMETER_ENCODING_ERROR); + goto err; + } + + public_key = d2i_ASN1_INTEGER(NULL, &p, pklen); + if (public_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + goto err; + } + + dsa->pub_key = ASN1_INTEGER_to_BN(public_key, NULL); + if (dsa->pub_key == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BN_DECODE_ERROR); + goto err; + } + + ASN1_INTEGER_free(public_key); + EVP_PKEY_assign_DSA(pkey, dsa); + return 1; + +err: + ASN1_INTEGER_free(public_key); + DSA_free(dsa); + return 0; +} + +static int dsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) { + DSA *dsa; + ASN1_STRING *pval = NULL; + uint8_t *penc = NULL; + int penclen; + + dsa = pkey->pkey.dsa; + dsa->write_params = 0; + + int ptype; + if (dsa->p && dsa->q && dsa->g) { + pval = ASN1_STRING_new(); + if (!pval) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + pval->length = i2d_DSAparams(dsa, &pval->data); + if (pval->length <= 0) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + ptype = V_ASN1_SEQUENCE; + } else { + ptype = V_ASN1_UNDEF; + } + + penclen = i2d_DSAPublicKey(dsa, &penc); + if (penclen <= 0) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_DSA), ptype, pval, + penc, penclen)) { + return 1; + } + +err: + OPENSSL_free(penc); + ASN1_STRING_free(pval); + + return 0; +} + +static int dsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) { + const uint8_t *p, *pm; + int pklen, pmlen; + int ptype; + void *pval; + ASN1_STRING *pstr; + X509_ALGOR *palg; + ASN1_INTEGER *privkey = NULL; + BN_CTX *ctx = NULL; + + /* In PKCS#8 DSA: you just get a private key integer and parameters in the + * AlgorithmIdentifier the pubkey must be recalculated. */ + + STACK_OF(ASN1_TYPE) *ndsa = NULL; + DSA *dsa = NULL; + + if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8)) { + return 0; + } + X509_ALGOR_get0(NULL, &ptype, &pval, palg); + + /* Check for broken DSA PKCS#8, UGH! */ + if (*p == (V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED)) { + ASN1_TYPE *t1, *t2; + ndsa = d2i_ASN1_SEQUENCE_ANY(NULL, &p, pklen); + if (ndsa == NULL) { + goto decerr; + } + if (sk_ASN1_TYPE_num(ndsa) != 2) { + goto decerr; + } + + /* Handle Two broken types: + * SEQUENCE {parameters, priv_key} + * SEQUENCE {pub_key, priv_key}. */ + + t1 = sk_ASN1_TYPE_value(ndsa, 0); + t2 = sk_ASN1_TYPE_value(ndsa, 1); + if (t1->type == V_ASN1_SEQUENCE) { + p8->broken = PKCS8_EMBEDDED_PARAM; + pval = t1->value.ptr; + } else if (ptype == V_ASN1_SEQUENCE) { + p8->broken = PKCS8_NS_DB; + } else { + goto decerr; + } + + if (t2->type != V_ASN1_INTEGER) { + goto decerr; + } + + privkey = t2->value.integer; + } else { + const uint8_t *q = p; + privkey = d2i_ASN1_INTEGER(NULL, &p, pklen); + if (privkey == NULL) { + goto decerr; + } + if (privkey->type == V_ASN1_NEG_INTEGER) { + p8->broken = PKCS8_NEG_PRIVKEY; + ASN1_INTEGER_free(privkey); + privkey = d2i_ASN1_UINTEGER(NULL, &q, pklen); + if (privkey == NULL) { + goto decerr; + } + } + if (ptype != V_ASN1_SEQUENCE) { + goto decerr; + } + } + + pstr = pval; + pm = pstr->data; + pmlen = pstr->length; + dsa = d2i_DSAparams(NULL, &pm, pmlen); + if (dsa == NULL) { + goto decerr; + } + /* We have parameters. Now set private key */ + dsa->priv_key = ASN1_INTEGER_to_BN(privkey, NULL); + if (dsa->priv_key == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_LIB_BN); + goto dsaerr; + } + /* Calculate public key. */ + dsa->pub_key = BN_new(); + if (dsa->pub_key == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto dsaerr; + } + ctx = BN_CTX_new(); + if (ctx == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto dsaerr; + } + + if (!BN_mod_exp(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx)) { + OPENSSL_PUT_ERROR(EVP, ERR_LIB_BN); + goto dsaerr; + } + + EVP_PKEY_assign_DSA(pkey, dsa); + BN_CTX_free(ctx); + sk_ASN1_TYPE_pop_free(ndsa, ASN1_TYPE_free); + ASN1_INTEGER_free(privkey); + + return 1; + +decerr: + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + +dsaerr: + BN_CTX_free(ctx); + ASN1_INTEGER_free(privkey); + sk_ASN1_TYPE_pop_free(ndsa, ASN1_TYPE_free); + DSA_free(dsa); + return 0; +} + +static int dsa_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) { + ASN1_STRING *params = NULL; + ASN1_INTEGER *prkey = NULL; + uint8_t *dp = NULL; + int dplen; + + if (!pkey->pkey.dsa || !pkey->pkey.dsa->priv_key) { + OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS); + goto err; + } + + params = ASN1_STRING_new(); + if (!params) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + + params->length = i2d_DSAparams(pkey->pkey.dsa, ¶ms->data); + if (params->length <= 0) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + params->type = V_ASN1_SEQUENCE; + + /* Get private key into integer. */ + prkey = BN_to_ASN1_INTEGER(pkey->pkey.dsa->priv_key, NULL); + + if (!prkey) { + OPENSSL_PUT_ERROR(EVP, ERR_LIB_BN); + goto err; + } + + dplen = i2d_ASN1_INTEGER(prkey, &dp); + + ASN1_INTEGER_free(prkey); + prkey = NULL; + + if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_dsa), 0, + V_ASN1_SEQUENCE, params, dp, dplen)) { + goto err; + } + + return 1; + +err: + OPENSSL_free(dp); + ASN1_STRING_free(params); + ASN1_INTEGER_free(prkey); + return 0; +} + +static int int_dsa_size(const EVP_PKEY *pkey) { + return DSA_size(pkey->pkey.dsa); +} + +static int dsa_bits(const EVP_PKEY *pkey) { + return BN_num_bits(pkey->pkey.dsa->p); +} + +static int dsa_missing_parameters(const EVP_PKEY *pkey) { + DSA *dsa; + dsa = pkey->pkey.dsa; + if (dsa->p == NULL || dsa->q == NULL || dsa->g == NULL) { + return 1; + } + return 0; +} + +static int dup_bn_into(BIGNUM **out, BIGNUM *src) { + BIGNUM *a; + + a = BN_dup(src); + if (a == NULL) { + return 0; + } + BN_free(*out); + *out = a; + + return 1; +} + +static int dsa_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) { + if (!dup_bn_into(&to->pkey.dsa->p, from->pkey.dsa->p) || + !dup_bn_into(&to->pkey.dsa->q, from->pkey.dsa->q) || + !dup_bn_into(&to->pkey.dsa->g, from->pkey.dsa->g)) { + return 0; + } + + return 1; +} + +static int dsa_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) { + return BN_cmp(a->pkey.dsa->p, b->pkey.dsa->p) == 0 && + BN_cmp(a->pkey.dsa->q, b->pkey.dsa->q) == 0 && + BN_cmp(a->pkey.dsa->g, b->pkey.dsa->g) == 0; +} + +static int dsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { + return BN_cmp(b->pkey.dsa->pub_key, a->pkey.dsa->pub_key) == 0; +} + +static void int_dsa_free(EVP_PKEY *pkey) { DSA_free(pkey->pkey.dsa); } + +static void update_buflen(const BIGNUM *b, size_t *pbuflen) { + size_t i; + + if (!b) { + return; + } + i = BN_num_bytes(b); + if (*pbuflen < i) { + *pbuflen = i; + } +} + +static int do_dsa_print(BIO *bp, const DSA *x, int off, int ptype) { + uint8_t *m = NULL; + int ret = 0; + size_t buf_len = 0; + const char *ktype = NULL; + + const BIGNUM *priv_key, *pub_key; + + priv_key = NULL; + if (ptype == 2) { + priv_key = x->priv_key; + } + + pub_key = NULL; + if (ptype > 0) { + pub_key = x->pub_key; + } + + ktype = "DSA-Parameters"; + if (ptype == 2) { + ktype = "Private-Key"; + } else if (ptype == 1) { + ktype = "Public-Key"; + } + + update_buflen(x->p, &buf_len); + update_buflen(x->q, &buf_len); + update_buflen(x->g, &buf_len); + update_buflen(priv_key, &buf_len); + update_buflen(pub_key, &buf_len); + + m = (uint8_t *)OPENSSL_malloc(buf_len + 10); + if (m == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (priv_key) { + if (!BIO_indent(bp, off, 128) || + BIO_printf(bp, "%s: (%d bit)\n", ktype, BN_num_bits(x->p)) <= 0) { + goto err; + } + } + + if (!ASN1_bn_print(bp, "priv:", priv_key, m, off) || + !ASN1_bn_print(bp, "pub: ", pub_key, m, off) || + !ASN1_bn_print(bp, "P: ", x->p, m, off) || + !ASN1_bn_print(bp, "Q: ", x->q, m, off) || + !ASN1_bn_print(bp, "G: ", x->g, m, off)) { + goto err; + } + ret = 1; + +err: + OPENSSL_free(m); + return ret; +} + +static int dsa_param_decode(EVP_PKEY *pkey, const uint8_t **pder, int derlen) { + DSA *dsa; + dsa = d2i_DSAparams(NULL, pder, derlen); + if (dsa == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_DSA_LIB); + return 0; + } + EVP_PKEY_assign_DSA(pkey, dsa); + return 1; +} + +static int dsa_param_encode(const EVP_PKEY *pkey, uint8_t **pder) { + return i2d_DSAparams(pkey->pkey.dsa, pder); +} + +static int dsa_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_dsa_print(bp, pkey->pkey.dsa, indent, 0); +} + +static int dsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_dsa_print(bp, pkey->pkey.dsa, indent, 1); +} + +static int dsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_dsa_print(bp, pkey->pkey.dsa, indent, 2); +} + +static int old_dsa_priv_decode(EVP_PKEY *pkey, const uint8_t **pder, + int derlen) { + DSA *dsa; + dsa = d2i_DSAPrivateKey(NULL, pder, derlen); + if (dsa == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_DSA_LIB); + return 0; + } + EVP_PKEY_assign_DSA(pkey, dsa); + return 1; +} + +static int old_dsa_priv_encode(const EVP_PKEY *pkey, uint8_t **pder) { + return i2d_DSAPrivateKey(pkey->pkey.dsa, pder); +} + +static int dsa_sig_print(BIO *bp, const X509_ALGOR *sigalg, + const ASN1_STRING *sig, int indent, ASN1_PCTX *pctx) { + DSA_SIG *dsa_sig; + const uint8_t *p; + + if (!sig) { + return BIO_puts(bp, "\n") > 0; + } + + p = sig->data; + dsa_sig = d2i_DSA_SIG(NULL, &p, sig->length); + if (dsa_sig == NULL) { + return X509_signature_dump(bp, sig, indent); + } + + int rv = 0; + size_t buf_len = 0; + uint8_t *m = NULL; + + update_buflen(dsa_sig->r, &buf_len); + update_buflen(dsa_sig->s, &buf_len); + m = OPENSSL_malloc(buf_len + 10); + if (m == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (BIO_write(bp, "\n", 1) != 1 || + !ASN1_bn_print(bp, "r: ", dsa_sig->r, m, indent) || + !ASN1_bn_print(bp, "s: ", dsa_sig->s, m, indent)) { + goto err; + } + rv = 1; + +err: + OPENSSL_free(m); + DSA_SIG_free(dsa_sig); + return rv; +} + +const EVP_PKEY_ASN1_METHOD dsa_asn1_meth = { + EVP_PKEY_DSA, + EVP_PKEY_DSA, + 0, + + "DSA", + + dsa_pub_decode, + dsa_pub_encode, + dsa_pub_cmp, + dsa_pub_print, + + dsa_priv_decode, + dsa_priv_encode, + dsa_priv_print, + + NULL /* pkey_opaque */, + NULL /* pkey_supports_digest */, + + int_dsa_size, + dsa_bits, + + dsa_param_decode, + dsa_param_encode, + dsa_missing_parameters, + dsa_copy_parameters, + dsa_cmp_parameters, + dsa_param_print, + dsa_sig_print, + + int_dsa_free, + old_dsa_priv_decode, + old_dsa_priv_encode, +}; diff --git a/TMessagesProj/jni/boringssl/crypto/evp/p_ec.c b/TMessagesProj/jni/boringssl/crypto/evp/p_ec.c new file mode 100644 index 00000000..f0249600 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/p_ec.c @@ -0,0 +1,299 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006. + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../ec/internal.h" + + +typedef struct { + /* Key and paramgen group */ + EC_GROUP *gen_group; + /* message digest */ + const EVP_MD *md; +} EC_PKEY_CTX; + + +static int pkey_ec_init(EVP_PKEY_CTX *ctx) { + EC_PKEY_CTX *dctx; + dctx = OPENSSL_malloc(sizeof(EC_PKEY_CTX)); + if (!dctx) { + return 0; + } + memset(dctx, 0, sizeof(EC_PKEY_CTX)); + + ctx->data = dctx; + + return 1; +} + +static int pkey_ec_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { + EC_PKEY_CTX *dctx, *sctx; + if (!pkey_ec_init(dst)) { + return 0; + } + sctx = src->data; + dctx = dst->data; + + if (sctx->gen_group) { + dctx->gen_group = EC_GROUP_dup(sctx->gen_group); + if (!dctx->gen_group) { + return 0; + } + } + dctx->md = sctx->md; + + return 1; +} + +static void pkey_ec_cleanup(EVP_PKEY_CTX *ctx) { + EC_PKEY_CTX *dctx = ctx->data; + if (!dctx) { + return; + } + + EC_GROUP_free(dctx->gen_group); + OPENSSL_free(dctx); +} + +static int pkey_ec_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen, + const uint8_t *tbs, size_t tbslen) { + int type; + unsigned int sltmp; + EC_PKEY_CTX *dctx = ctx->data; + EC_KEY *ec = ctx->pkey->pkey.ec; + + if (!sig) { + *siglen = ECDSA_size(ec); + return 1; + } else if (*siglen < (size_t)ECDSA_size(ec)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + type = NID_sha1; + if (dctx->md) { + type = EVP_MD_type(dctx->md); + } + + if (!ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec)) { + return 0; + } + *siglen = (size_t)sltmp; + return 1; +} + +static int pkey_ec_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, size_t siglen, + const uint8_t *tbs, size_t tbslen) { + int type; + EC_PKEY_CTX *dctx = ctx->data; + EC_KEY *ec = ctx->pkey->pkey.ec; + + type = NID_sha1; + if (dctx->md) { + type = EVP_MD_type(dctx->md); + } + + return ECDSA_verify(type, tbs, tbslen, sig, siglen, ec); +} + +static int pkey_ec_derive(EVP_PKEY_CTX *ctx, uint8_t *key, + size_t *keylen) { + int ret; + size_t outlen; + const EC_POINT *pubkey = NULL; + EC_KEY *eckey; + + if (!ctx->pkey || !ctx->peerkey) { + OPENSSL_PUT_ERROR(EVP, EVP_R_KEYS_NOT_SET); + return 0; + } + + eckey = ctx->pkey->pkey.ec; + + if (!key) { + const EC_GROUP *group; + group = EC_KEY_get0_group(eckey); + *keylen = (EC_GROUP_get_degree(group) + 7) / 8; + return 1; + } + pubkey = EC_KEY_get0_public_key(ctx->peerkey->pkey.ec); + + /* NB: unlike PKCS#3 DH, if *outlen is less than maximum size this is + * not an error, the result is truncated. */ + + outlen = *keylen; + + ret = ECDH_compute_key(key, outlen, pubkey, eckey, 0); + if (ret < 0) { + return 0; + } + *keylen = ret; + return 1; +} + +static int pkey_ec_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) { + EC_PKEY_CTX *dctx = ctx->data; + EC_GROUP *group; + + switch (type) { + case EVP_PKEY_CTRL_EC_PARAMGEN_CURVE_NID: + group = EC_GROUP_new_by_curve_name(p1); + if (group == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_CURVE); + return 0; + } + EC_GROUP_free(dctx->gen_group); + dctx->gen_group = group; + return 1; + + case EVP_PKEY_CTRL_MD: + if (EVP_MD_type((const EVP_MD *)p2) != NID_sha1 && + EVP_MD_type((const EVP_MD *)p2) != NID_ecdsa_with_SHA1 && + EVP_MD_type((const EVP_MD *)p2) != NID_sha224 && + EVP_MD_type((const EVP_MD *)p2) != NID_sha256 && + EVP_MD_type((const EVP_MD *)p2) != NID_sha384 && + EVP_MD_type((const EVP_MD *)p2) != NID_sha512) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_TYPE); + return 0; + } + dctx->md = p2; + return 1; + + case EVP_PKEY_CTRL_GET_MD: + *(const EVP_MD **)p2 = dctx->md; + return 1; + + case EVP_PKEY_CTRL_PEER_KEY: + /* Default behaviour is OK */ + return 1; + + default: + OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return 0; + } +} + +static int pkey_ec_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { + EC_KEY *ec = NULL; + EC_PKEY_CTX *dctx = ctx->data; + int ret = 0; + + if (dctx->gen_group == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + ec = EC_KEY_new(); + if (!ec) { + return 0; + } + ret = EC_KEY_set_group(ec, dctx->gen_group); + if (ret) { + EVP_PKEY_assign_EC_KEY(pkey, ec); + } else { + EC_KEY_free(ec); + } + return ret; +} + +static int pkey_ec_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { + EC_KEY *ec = NULL; + EC_PKEY_CTX *dctx = ctx->data; + if (ctx->pkey == NULL && dctx->gen_group == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_PARAMETERS_SET); + return 0; + } + ec = EC_KEY_new(); + if (!ec) { + return 0; + } + EVP_PKEY_assign_EC_KEY(pkey, ec); + if (ctx->pkey) { + /* Note: if error return, pkey is freed by parent routine */ + if (!EVP_PKEY_copy_parameters(pkey, ctx->pkey)) { + return 0; + } + } else { + if (!EC_KEY_set_group(ec, dctx->gen_group)) { + return 0; + } + } + return EC_KEY_generate_key(pkey->pkey.ec); +} + +const EVP_PKEY_METHOD ec_pkey_meth = { + EVP_PKEY_EC, 0 /* flags */, pkey_ec_init, + pkey_ec_copy, pkey_ec_cleanup, 0 /* paramgen_init */, + pkey_ec_paramgen, 0 /* keygen_init */, pkey_ec_keygen, + 0 /* sign_init */, pkey_ec_sign, 0 /* verify_init */, + pkey_ec_verify, 0 /* encrypt_init */, 0 /* encrypt */, + 0 /* decrypt_init */, 0 /* decrypt */, 0 /* derive_init */, + pkey_ec_derive, pkey_ec_ctrl, +}; diff --git a/TMessagesProj/jni/boringssl/crypto/evp/p_ec_asn1.c b/TMessagesProj/jni/boringssl/crypto/evp/p_ec_asn1.c new file mode 100644 index 00000000..98679479 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/p_ec_asn1.c @@ -0,0 +1,573 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006. + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +static int eckey_param2type(int *pptype, void **ppval, EC_KEY *ec_key) { + const EC_GROUP *group; + int nid; + + if (ec_key == NULL || (group = EC_KEY_get0_group(ec_key)) == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS); + return 0; + } + + nid = EC_GROUP_get_curve_name(group); + if (nid == NID_undef) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_NID_FOR_CURVE); + return 0; + } + + *ppval = (void*) OBJ_nid2obj(nid); + *pptype = V_ASN1_OBJECT; + return 1; +} + +static int eckey_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) { + EC_KEY *ec_key = pkey->pkey.ec; + void *pval = NULL; + int ptype; + uint8_t *penc = NULL, *p; + int penclen; + + if (!eckey_param2type(&ptype, &pval, ec_key)) { + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + return 0; + } + penclen = i2o_ECPublicKey(ec_key, NULL); + if (penclen <= 0) { + goto err; + } + penc = OPENSSL_malloc(penclen); + if (!penc) { + goto err; + } + p = penc; + penclen = i2o_ECPublicKey(ec_key, &p); + if (penclen <= 0) { + goto err; + } + if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_EC), ptype, pval, penc, + penclen)) { + return 1; + } + +err: + if (ptype == V_ASN1_OBJECT) { + ASN1_OBJECT_free(pval); + } else { + ASN1_STRING_free(pval); + } + if (penc) { + OPENSSL_free(penc); + } + return 0; +} + +static EC_KEY *eckey_type2param(int ptype, void *pval) { + EC_KEY *eckey = NULL; + + if (ptype == V_ASN1_SEQUENCE) { + ASN1_STRING *pstr = pval; + const uint8_t *pm = pstr->data; + int pmlen = pstr->length; + + eckey = d2i_ECParameters(NULL, &pm, pmlen); + if (eckey == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + goto err; + } + } else if (ptype == V_ASN1_OBJECT) { + ASN1_OBJECT *poid = pval; + + /* type == V_ASN1_OBJECT => the parameters are given + * by an asn1 OID */ + eckey = EC_KEY_new_by_curve_name(OBJ_obj2nid(poid)); + if (eckey == NULL) { + goto err; + } + } else { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + goto err; + } + + return eckey; + +err: + if (eckey) { + EC_KEY_free(eckey); + } + return NULL; +} + +static int eckey_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) { + const uint8_t *p = NULL; + void *pval; + int ptype, pklen; + EC_KEY *eckey = NULL; + X509_ALGOR *palg; + + if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey)) { + return 0; + } + X509_ALGOR_get0(NULL, &ptype, &pval, palg); + + eckey = eckey_type2param(ptype, pval); + if (!eckey) { + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + return 0; + } + + /* We have parameters now set public key */ + if (!o2i_ECPublicKey(&eckey, &p, pklen)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + goto err; + } + + EVP_PKEY_assign_EC_KEY(pkey, eckey); + return 1; + +err: + if (eckey) { + EC_KEY_free(eckey); + } + return 0; +} + +static int eckey_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { + int r; + const EC_GROUP *group = EC_KEY_get0_group(b->pkey.ec); + const EC_POINT *pa = EC_KEY_get0_public_key(a->pkey.ec), + *pb = EC_KEY_get0_public_key(b->pkey.ec); + r = EC_POINT_cmp(group, pa, pb, NULL); + if (r == 0) { + return 1; + } else if (r == 1) { + return 0; + } else { + return -2; + } +} + +static int eckey_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) { + const uint8_t *p = NULL; + void *pval; + int ptype, pklen; + EC_KEY *eckey = NULL; + X509_ALGOR *palg; + + if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8)) { + return 0; + } + X509_ALGOR_get0(NULL, &ptype, &pval, palg); + + eckey = eckey_type2param(ptype, pval); + + if (!eckey) { + goto ecliberr; + } + + /* We have parameters now set private key */ + if (!d2i_ECPrivateKey(&eckey, &p, pklen)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + goto ecerr; + } + + /* calculate public key (if necessary) */ + if (EC_KEY_get0_public_key(eckey) == NULL) { + const BIGNUM *priv_key; + const EC_GROUP *group; + EC_POINT *pub_key; + /* the public key was not included in the SEC1 private + * key => calculate the public key */ + group = EC_KEY_get0_group(eckey); + pub_key = EC_POINT_new(group); + if (pub_key == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + goto ecliberr; + } + if (!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))) { + EC_POINT_free(pub_key); + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + goto ecliberr; + } + priv_key = EC_KEY_get0_private_key(eckey); + if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL)) { + EC_POINT_free(pub_key); + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + goto ecliberr; + } + if (EC_KEY_set_public_key(eckey, pub_key) == 0) { + EC_POINT_free(pub_key); + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + goto ecliberr; + } + EC_POINT_free(pub_key); + } + + EVP_PKEY_assign_EC_KEY(pkey, eckey); + return 1; + +ecliberr: + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); +ecerr: + if (eckey) { + EC_KEY_free(eckey); + } + return 0; +} + +static int eckey_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) { + EC_KEY *ec_key; + uint8_t *ep, *p; + int eplen, ptype; + void *pval; + unsigned int tmp_flags, old_flags; + + ec_key = pkey->pkey.ec; + + if (!eckey_param2type(&ptype, &pval, ec_key)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + + /* set the private key */ + + /* do not include the parameters in the SEC1 private key + * see PKCS#11 12.11 */ + old_flags = EC_KEY_get_enc_flags(ec_key); + tmp_flags = old_flags | EC_PKEY_NO_PARAMETERS; + EC_KEY_set_enc_flags(ec_key, tmp_flags); + eplen = i2d_ECPrivateKey(ec_key, NULL); + if (!eplen) { + EC_KEY_set_enc_flags(ec_key, old_flags); + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + return 0; + } + ep = (uint8_t *)OPENSSL_malloc(eplen); + if (!ep) { + EC_KEY_set_enc_flags(ec_key, old_flags); + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + p = ep; + if (!i2d_ECPrivateKey(ec_key, &p)) { + EC_KEY_set_enc_flags(ec_key, old_flags); + OPENSSL_free(ep); + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + return 0; + } + /* restore old encoding flags */ + EC_KEY_set_enc_flags(ec_key, old_flags); + + if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_X9_62_id_ecPublicKey), + 0, ptype, pval, ep, eplen)) { + OPENSSL_free(ep); + return 0; + } + + return 1; +} + +static int int_ec_size(const EVP_PKEY *pkey) { + return ECDSA_size(pkey->pkey.ec); +} + +static int ec_bits(const EVP_PKEY *pkey) { + BIGNUM *order = BN_new(); + const EC_GROUP *group; + int ret; + + if (!order) { + ERR_clear_error(); + return 0; + } + group = EC_KEY_get0_group(pkey->pkey.ec); + if (!EC_GROUP_get_order(group, order, NULL)) { + ERR_clear_error(); + return 0; + } + + ret = BN_num_bits(order); + BN_free(order); + return ret; +} + +static int ec_missing_parameters(const EVP_PKEY *pkey) { + return EC_KEY_get0_group(pkey->pkey.ec) == NULL; +} + +static int ec_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from) { + EC_GROUP *group = EC_GROUP_dup(EC_KEY_get0_group(from->pkey.ec)); + if (group == NULL || + EC_KEY_set_group(to->pkey.ec, group) == 0) { + return 0; + } + EC_GROUP_free(group); + return 1; +} + +static int ec_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b) { + const EC_GROUP *group_a = EC_KEY_get0_group(a->pkey.ec), + *group_b = EC_KEY_get0_group(b->pkey.ec); + if (EC_GROUP_cmp(group_a, group_b, NULL) != 0) { + /* mismatch */ + return 0; + } + return 1; +} + +static void int_ec_free(EVP_PKEY *pkey) { EC_KEY_free(pkey->pkey.ec); } + +static int do_EC_KEY_print(BIO *bp, const EC_KEY *x, int off, int ktype) { + uint8_t *buffer = NULL; + const char *ecstr; + size_t buf_len = 0, i; + int ret = 0, reason = ERR_R_BIO_LIB; + BIGNUM *order = NULL; + BN_CTX *ctx = NULL; + const EC_GROUP *group; + const EC_POINT *public_key; + const BIGNUM *priv_key; + uint8_t *pub_key_bytes = NULL; + size_t pub_key_bytes_len = 0; + + if (x == NULL || (group = EC_KEY_get0_group(x)) == NULL) { + reason = ERR_R_PASSED_NULL_PARAMETER; + goto err; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + + if (ktype > 0) { + public_key = EC_KEY_get0_public_key(x); + if (public_key != NULL) { + pub_key_bytes_len = EC_POINT_point2oct( + group, public_key, EC_KEY_get_conv_form(x), NULL, 0, ctx); + if (pub_key_bytes_len == 0) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + pub_key_bytes = OPENSSL_malloc(pub_key_bytes_len); + if (pub_key_bytes == NULL) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + pub_key_bytes_len = + EC_POINT_point2oct(group, public_key, EC_KEY_get_conv_form(x), + pub_key_bytes, pub_key_bytes_len, ctx); + if (pub_key_bytes_len == 0) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + buf_len = pub_key_bytes_len; + } + } + + if (ktype == 2) { + priv_key = EC_KEY_get0_private_key(x); + if (priv_key && (i = (size_t)BN_num_bytes(priv_key)) > buf_len) { + buf_len = i; + } + } else { + priv_key = NULL; + } + + if (ktype > 0) { + buf_len += 10; + if ((buffer = OPENSSL_malloc(buf_len)) == NULL) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + } + if (ktype == 2) { + ecstr = "Private-Key"; + } else if (ktype == 1) { + ecstr = "Public-Key"; + } else { + ecstr = "ECDSA-Parameters"; + } + + if (!BIO_indent(bp, off, 128)) { + goto err; + } + order = BN_new(); + if (order == NULL || !EC_GROUP_get_order(group, order, NULL) || + BIO_printf(bp, "%s: (%d bit)\n", ecstr, BN_num_bits(order)) <= 0) { + goto err; + } + + if ((priv_key != NULL) && + !ASN1_bn_print(bp, "priv:", priv_key, buffer, off)) { + goto err; + } + if (pub_key_bytes != NULL) { + BIO_hexdump(bp, pub_key_bytes, pub_key_bytes_len, off); + } + /* TODO(fork): implement */ + /* + if (!ECPKParameters_print(bp, group, off)) + goto err; */ + ret = 1; + +err: + if (!ret) { + OPENSSL_PUT_ERROR(EVP, reason); + } + OPENSSL_free(pub_key_bytes); + BN_free(order); + BN_CTX_free(ctx); + OPENSSL_free(buffer); + return ret; +} + +static int eckey_param_decode(EVP_PKEY *pkey, const uint8_t **pder, + int derlen) { + EC_KEY *eckey; + if (!(eckey = d2i_ECParameters(NULL, pder, derlen))) { + OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB); + return 0; + } + EVP_PKEY_assign_EC_KEY(pkey, eckey); + return 1; +} + +static int eckey_param_encode(const EVP_PKEY *pkey, uint8_t **pder) { + return i2d_ECParameters(pkey->pkey.ec, pder); +} + +static int eckey_param_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 0); +} + +static int eckey_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 1); +} + + +static int eckey_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_EC_KEY_print(bp, pkey->pkey.ec, indent, 2); +} + +static int eckey_opaque(const EVP_PKEY *pkey) { + return EC_KEY_is_opaque(pkey->pkey.ec); +} + +static int old_ec_priv_decode(EVP_PKEY *pkey, const uint8_t **pder, + int derlen) { + EC_KEY *ec; + if (!(ec = d2i_ECPrivateKey(NULL, pder, derlen))) { + OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); + return 0; + } + EVP_PKEY_assign_EC_KEY(pkey, ec); + return 1; +} + +static int old_ec_priv_encode(const EVP_PKEY *pkey, uint8_t **pder) { + return i2d_ECPrivateKey(pkey->pkey.ec, pder); +} + +const EVP_PKEY_ASN1_METHOD ec_asn1_meth = { + EVP_PKEY_EC, + EVP_PKEY_EC, + 0, + "EC", + + eckey_pub_decode, + eckey_pub_encode, + eckey_pub_cmp, + eckey_pub_print, + + eckey_priv_decode, + eckey_priv_encode, + eckey_priv_print, + + eckey_opaque, + 0 /* pkey_supports_digest */, + + int_ec_size, + ec_bits, + + eckey_param_decode, + eckey_param_encode, + ec_missing_parameters, + ec_copy_parameters, + ec_cmp_parameters, + eckey_param_print, + 0, + + int_ec_free, + old_ec_priv_decode, + old_ec_priv_encode +}; diff --git a/TMessagesProj/jni/boringssl/crypto/evp/p_rsa.c b/TMessagesProj/jni/boringssl/crypto/evp/p_rsa.c new file mode 100644 index 00000000..cfecbfd0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/p_rsa.c @@ -0,0 +1,596 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006. + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../rsa/internal.h" +#include "internal.h" + + +typedef struct { + /* Key gen parameters */ + int nbits; + BIGNUM *pub_exp; + /* RSA padding mode */ + int pad_mode; + /* message digest */ + const EVP_MD *md; + /* message digest for MGF1 */ + const EVP_MD *mgf1md; + /* PSS salt length */ + int saltlen; + /* tbuf is a buffer which is either NULL, or is the size of the RSA modulus. + * It's used to store the output of RSA operations. */ + uint8_t *tbuf; + /* OAEP label */ + uint8_t *oaep_label; + size_t oaep_labellen; +} RSA_PKEY_CTX; + +static int pkey_rsa_init(EVP_PKEY_CTX *ctx) { + RSA_PKEY_CTX *rctx; + rctx = OPENSSL_malloc(sizeof(RSA_PKEY_CTX)); + if (!rctx) { + return 0; + } + memset(rctx, 0, sizeof(RSA_PKEY_CTX)); + + rctx->nbits = 2048; + rctx->pad_mode = RSA_PKCS1_PADDING; + rctx->saltlen = -2; + + ctx->data = rctx; + + return 1; +} + +static int pkey_rsa_copy(EVP_PKEY_CTX *dst, EVP_PKEY_CTX *src) { + RSA_PKEY_CTX *dctx, *sctx; + if (!pkey_rsa_init(dst)) { + return 0; + } + sctx = src->data; + dctx = dst->data; + dctx->nbits = sctx->nbits; + if (sctx->pub_exp) { + dctx->pub_exp = BN_dup(sctx->pub_exp); + if (!dctx->pub_exp) { + return 0; + } + } + + dctx->pad_mode = sctx->pad_mode; + dctx->md = sctx->md; + dctx->mgf1md = sctx->mgf1md; + if (sctx->oaep_label) { + OPENSSL_free(dctx->oaep_label); + dctx->oaep_label = BUF_memdup(sctx->oaep_label, sctx->oaep_labellen); + if (!dctx->oaep_label) { + return 0; + } + dctx->oaep_labellen = sctx->oaep_labellen; + } + + return 1; +} + +static void pkey_rsa_cleanup(EVP_PKEY_CTX *ctx) { + RSA_PKEY_CTX *rctx = ctx->data; + + if (rctx == NULL) { + return; + } + + BN_free(rctx->pub_exp); + OPENSSL_free(rctx->tbuf); + OPENSSL_free(rctx->oaep_label); + OPENSSL_free(rctx); +} + +static int setup_tbuf(RSA_PKEY_CTX *ctx, EVP_PKEY_CTX *pk) { + if (ctx->tbuf) { + return 1; + } + ctx->tbuf = OPENSSL_malloc(EVP_PKEY_size(pk->pkey)); + if (!ctx->tbuf) { + return 0; + } + return 1; +} + +static int pkey_rsa_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, size_t *siglen, + const uint8_t *tbs, size_t tbslen) { + RSA_PKEY_CTX *rctx = ctx->data; + RSA *rsa = ctx->pkey->pkey.rsa; + const size_t key_len = EVP_PKEY_size(ctx->pkey); + + if (!sig) { + *siglen = key_len; + return 1; + } + + if (*siglen < key_len) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + if (rctx->md) { + unsigned int out_len; + + if (tbslen != EVP_MD_size(rctx->md)) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_LENGTH); + return 0; + } + + if (EVP_MD_type(rctx->md) == NID_mdc2) { + OPENSSL_PUT_ERROR(EVP, EVP_R_NO_MDC2_SUPPORT); + return 0; + } + + switch (rctx->pad_mode) { + case RSA_PKCS1_PADDING: + if (!RSA_sign(EVP_MD_type(rctx->md), tbs, tbslen, sig, &out_len, rsa)) { + return 0; + } + *siglen = out_len; + return 1; + + case RSA_PKCS1_PSS_PADDING: + if (!setup_tbuf(rctx, ctx) || + !RSA_padding_add_PKCS1_PSS_mgf1(rsa, rctx->tbuf, tbs, rctx->md, + rctx->mgf1md, rctx->saltlen) || + !RSA_sign_raw(rsa, siglen, sig, *siglen, rctx->tbuf, key_len, + RSA_NO_PADDING)) { + return 0; + } + return 1; + + default: + return 0; + } + } + + return RSA_sign_raw(rsa, siglen, sig, *siglen, tbs, tbslen, rctx->pad_mode); +} + +static int pkey_rsa_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, + size_t siglen, const uint8_t *tbs, + size_t tbslen) { + RSA_PKEY_CTX *rctx = ctx->data; + RSA *rsa = ctx->pkey->pkey.rsa; + size_t rslen; + const size_t key_len = EVP_PKEY_size(ctx->pkey); + + if (rctx->md) { + switch (rctx->pad_mode) { + case RSA_PKCS1_PADDING: + return RSA_verify(EVP_MD_type(rctx->md), tbs, tbslen, sig, siglen, rsa); + + case RSA_PKCS1_PSS_PADDING: + if (!setup_tbuf(rctx, ctx) || + !RSA_verify_raw(rsa, &rslen, rctx->tbuf, key_len, sig, siglen, + RSA_NO_PADDING) || + !RSA_verify_PKCS1_PSS_mgf1(rsa, tbs, rctx->md, rctx->mgf1md, + rctx->tbuf, rctx->saltlen)) { + return 0; + } + return 1; + + default: + return 0; + } + } + + if (!setup_tbuf(rctx, ctx) || + !RSA_verify_raw(rsa, &rslen, rctx->tbuf, key_len, sig, siglen, + rctx->pad_mode) || + rslen != tbslen || + CRYPTO_memcmp(tbs, rctx->tbuf, rslen) != 0) { + return 0; + } + + return 1; +} + +static int pkey_rsa_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, size_t *outlen, + const uint8_t *in, size_t inlen) { + RSA_PKEY_CTX *rctx = ctx->data; + RSA *rsa = ctx->pkey->pkey.rsa; + const size_t key_len = EVP_PKEY_size(ctx->pkey); + + if (!out) { + *outlen = key_len; + return 1; + } + + if (*outlen < key_len) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) { + if (!setup_tbuf(rctx, ctx) || + !RSA_padding_add_PKCS1_OAEP_mgf1(rctx->tbuf, key_len, in, inlen, + rctx->oaep_label, rctx->oaep_labellen, + rctx->md, rctx->mgf1md) || + !RSA_encrypt(rsa, outlen, out, *outlen, rctx->tbuf, key_len, + RSA_NO_PADDING)) { + return 0; + } + return 1; + } + + return RSA_encrypt(rsa, outlen, out, *outlen, in, inlen, rctx->pad_mode); +} + +static int pkey_rsa_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out, + size_t *outlen, const uint8_t *in, + size_t inlen) { + RSA_PKEY_CTX *rctx = ctx->data; + RSA *rsa = ctx->pkey->pkey.rsa; + const size_t key_len = EVP_PKEY_size(ctx->pkey); + + if (!out) { + *outlen = key_len; + return 1; + } + + if (*outlen < key_len) { + OPENSSL_PUT_ERROR(EVP, EVP_R_BUFFER_TOO_SMALL); + return 0; + } + + if (rctx->pad_mode == RSA_PKCS1_OAEP_PADDING) { + size_t plaintext_len; + int message_len; + + if (!setup_tbuf(rctx, ctx) || + !RSA_decrypt(rsa, &plaintext_len, rctx->tbuf, key_len, in, inlen, + RSA_NO_PADDING)) { + return 0; + } + + message_len = RSA_padding_check_PKCS1_OAEP_mgf1( + out, key_len, rctx->tbuf, plaintext_len, rctx->oaep_label, + rctx->oaep_labellen, rctx->md, rctx->mgf1md); + if (message_len < 0) { + return 0; + } + *outlen = message_len; + return 1; + } + + return RSA_decrypt(rsa, outlen, out, key_len, in, inlen, rctx->pad_mode); +} + +static int check_padding_md(const EVP_MD *md, int padding) { + if (!md) { + return 1; + } + + if (padding == RSA_NO_PADDING) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE); + return 0; + } + + return 1; +} + +static int is_known_padding(int padding_mode) { + switch (padding_mode) { + case RSA_PKCS1_PADDING: + case RSA_NO_PADDING: + case RSA_PKCS1_OAEP_PADDING: + case RSA_PKCS1_PSS_PADDING: + return 1; + default: + return 0; + } +} + +static int pkey_rsa_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) { + RSA_PKEY_CTX *rctx = ctx->data; + switch (type) { + case EVP_PKEY_CTRL_RSA_PADDING: + if (!is_known_padding(p1) || !check_padding_md(rctx->md, p1) || + (p1 == RSA_PKCS1_PSS_PADDING && + 0 == (ctx->operation & (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY))) || + (p1 == RSA_PKCS1_OAEP_PADDING && + 0 == (ctx->operation & EVP_PKEY_OP_TYPE_CRYPT))) { + OPENSSL_PUT_ERROR(EVP, EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE); + return 0; + } + if ((p1 == RSA_PKCS1_PSS_PADDING || p1 == RSA_PKCS1_OAEP_PADDING) && + rctx->md == NULL) { + rctx->md = EVP_sha1(); + } + rctx->pad_mode = p1; + return 1; + + case EVP_PKEY_CTRL_GET_RSA_PADDING: + *(int *)p2 = rctx->pad_mode; + return 1; + + case EVP_PKEY_CTRL_RSA_PSS_SALTLEN: + case EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN: + if (rctx->pad_mode != RSA_PKCS1_PSS_PADDING) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PSS_SALTLEN); + return 0; + } + if (type == EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN) { + *(int *)p2 = rctx->saltlen; + } else { + if (p1 < -2) { + return 0; + } + rctx->saltlen = p1; + } + return 1; + + case EVP_PKEY_CTRL_RSA_KEYGEN_BITS: + if (p1 < 256) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_KEYBITS); + return 0; + } + rctx->nbits = p1; + return 1; + + case EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP: + if (!p2) { + return 0; + } + BN_free(rctx->pub_exp); + rctx->pub_exp = p2; + return 1; + + case EVP_PKEY_CTRL_RSA_OAEP_MD: + case EVP_PKEY_CTRL_GET_RSA_OAEP_MD: + if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE); + return 0; + } + if (type == EVP_PKEY_CTRL_GET_RSA_OAEP_MD) { + *(const EVP_MD **)p2 = rctx->md; + } else { + rctx->md = p2; + } + return 1; + + case EVP_PKEY_CTRL_MD: + if (!check_padding_md(p2, rctx->pad_mode)) { + return 0; + } + rctx->md = p2; + return 1; + + case EVP_PKEY_CTRL_GET_MD: + *(const EVP_MD **)p2 = rctx->md; + return 1; + + case EVP_PKEY_CTRL_RSA_MGF1_MD: + case EVP_PKEY_CTRL_GET_RSA_MGF1_MD: + if (rctx->pad_mode != RSA_PKCS1_PSS_PADDING && + rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_MGF1_MD); + return 0; + } + if (type == EVP_PKEY_CTRL_GET_RSA_MGF1_MD) { + if (rctx->mgf1md) { + *(const EVP_MD **)p2 = rctx->mgf1md; + } else { + *(const EVP_MD **)p2 = rctx->md; + } + } else { + rctx->mgf1md = p2; + } + return 1; + + case EVP_PKEY_CTRL_RSA_OAEP_LABEL: + if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE); + return 0; + } + OPENSSL_free(rctx->oaep_label); + if (p2 && p1 > 0) { + /* TODO(fork): this seems wrong. Shouldn't it take a copy of the + * buffer? */ + rctx->oaep_label = p2; + rctx->oaep_labellen = p1; + } else { + rctx->oaep_label = NULL; + rctx->oaep_labellen = 0; + } + return 1; + + case EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL: + if (rctx->pad_mode != RSA_PKCS1_OAEP_PADDING) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PADDING_MODE); + return 0; + } + CBS_init((CBS *)p2, rctx->oaep_label, rctx->oaep_labellen); + return 1; + + default: + OPENSSL_PUT_ERROR(EVP, EVP_R_COMMAND_NOT_SUPPORTED); + return 0; + } +} + +static int pkey_rsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { + RSA *rsa = NULL; + RSA_PKEY_CTX *rctx = ctx->data; + + if (!rctx->pub_exp) { + rctx->pub_exp = BN_new(); + if (!rctx->pub_exp || !BN_set_word(rctx->pub_exp, RSA_F4)) { + return 0; + } + } + rsa = RSA_new(); + if (!rsa) { + return 0; + } + + if (!RSA_generate_key_ex(rsa, rctx->nbits, rctx->pub_exp, NULL)) { + RSA_free(rsa); + return 0; + } + + EVP_PKEY_assign_RSA(pkey, rsa); + return 1; +} + +const EVP_PKEY_METHOD rsa_pkey_meth = { + EVP_PKEY_RSA, 0 /* flags */, pkey_rsa_init, + pkey_rsa_copy, pkey_rsa_cleanup, 0 /* paramgen_init */, + 0 /* paramgen */, 0 /* keygen_init */, pkey_rsa_keygen, + 0 /* sign_init */, pkey_rsa_sign, 0 /* verify_init */, + pkey_rsa_verify, 0 /* encrypt_init */, pkey_rsa_encrypt, + 0 /* decrypt_init */, pkey_rsa_decrypt, 0 /* derive_init */, + 0 /* derive */, pkey_rsa_ctrl, +}; + +int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int padding) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_RSA_PADDING, + padding, NULL); +} + +int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, int *out_padding) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_GET_RSA_PADDING, + 0, out_padding); +} + +int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int salt_len) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, + (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY), + EVP_PKEY_CTRL_RSA_PSS_SALTLEN, salt_len, NULL); +} + +int EVP_PKEY_CTX_get_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, int *out_salt_len) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, + (EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY), + EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN, 0, out_salt_len); +} + +int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, int bits) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, + EVP_PKEY_CTRL_RSA_KEYGEN_BITS, bits, NULL); +} + +int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, BIGNUM *e) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_KEYGEN, + EVP_PKEY_CTRL_RSA_KEYGEN_PUBEXP, 0, e); +} + +int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)md); +} + +int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_GET_RSA_OAEP_MD, 0, (void*) out_md); +} + +int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, + EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void*) md); +} + +int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **out_md) { + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, + EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_GET_RSA_MGF1_MD, 0, (void*) out_md); +} + +int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, const uint8_t *label, + size_t label_len) { + int label_len_int = label_len; + if (((size_t) label_len_int) != label_len) { + return 0; + } + + return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_OAEP_LABEL, label_len, + (void *)label); +} + +int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx, + const uint8_t **out_label) { + CBS label; + if (!EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_GET_RSA_OAEP_LABEL, 0, &label)) { + return -1; + } + if (CBS_len(&label) > INT_MAX) { + OPENSSL_PUT_ERROR(EVP, ERR_R_OVERFLOW); + return -1; + } + *out_label = CBS_data(&label); + return (int)CBS_len(&label); +} diff --git a/TMessagesProj/jni/boringssl/crypto/evp/p_rsa_asn1.c b/TMessagesProj/jni/boringssl/crypto/evp/p_rsa_asn1.c new file mode 100644 index 00000000..544ff1b8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/p_rsa_asn1.c @@ -0,0 +1,727 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2006. + */ +/* ==================================================================== + * Copyright (c) 2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../rsa/internal.h" +#include "internal.h" + + +static int rsa_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey) { + uint8_t *encoded; + size_t encoded_len; + if (!RSA_public_key_to_bytes(&encoded, &encoded_len, pkey->pkey.rsa)) { + return 0; + } + + if (!X509_PUBKEY_set0_param(pk, OBJ_nid2obj(EVP_PKEY_RSA), V_ASN1_NULL, NULL, + encoded, encoded_len)) { + OPENSSL_free(encoded); + return 0; + } + + return 1; +} + +static int rsa_pub_decode(EVP_PKEY *pkey, X509_PUBKEY *pubkey) { + const uint8_t *p; + int pklen; + RSA *rsa; + + if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, NULL, pubkey)) { + return 0; + } + rsa = RSA_public_key_from_bytes(p, pklen); + if (rsa == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_RSA_LIB); + return 0; + } + EVP_PKEY_assign_RSA(pkey, rsa); + return 1; +} + +static int rsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { + return BN_cmp(b->pkey.rsa->n, a->pkey.rsa->n) == 0 && + BN_cmp(b->pkey.rsa->e, a->pkey.rsa->e) == 0; +} + +static int rsa_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) { + uint8_t *encoded; + size_t encoded_len; + if (!RSA_private_key_to_bytes(&encoded, &encoded_len, pkey->pkey.rsa)) { + return 0; + } + + /* TODO(fork): const correctness in next line. */ + if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_rsaEncryption), 0, + V_ASN1_NULL, NULL, encoded, encoded_len)) { + OPENSSL_free(encoded); + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + + return 1; +} + +static int rsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) { + const uint8_t *p; + int pklen; + if (!PKCS8_pkey_get0(NULL, &p, &pklen, NULL, p8)) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + return 0; + } + + RSA *rsa = RSA_private_key_from_bytes(p, pklen); + if (rsa == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_RSA_LIB); + return 0; + } + + EVP_PKEY_assign_RSA(pkey, rsa); + return 1; +} + +static int rsa_opaque(const EVP_PKEY *pkey) { + return RSA_is_opaque(pkey->pkey.rsa); +} + +static int rsa_supports_digest(const EVP_PKEY *pkey, const EVP_MD *md) { + return RSA_supports_digest(pkey->pkey.rsa, md); +} + +static int int_rsa_size(const EVP_PKEY *pkey) { + return RSA_size(pkey->pkey.rsa); +} + +static int rsa_bits(const EVP_PKEY *pkey) { + return BN_num_bits(pkey->pkey.rsa->n); +} + +static void int_rsa_free(EVP_PKEY *pkey) { RSA_free(pkey->pkey.rsa); } + +static void update_buflen(const BIGNUM *b, size_t *pbuflen) { + size_t i; + + if (!b) { + return; + } + + i = BN_num_bytes(b); + if (*pbuflen < i) { + *pbuflen = i; + } +} + +static int do_rsa_print(BIO *out, const RSA *rsa, int off, + int include_private) { + char *str; + const char *s; + uint8_t *m = NULL; + int ret = 0, mod_len = 0; + size_t buf_len = 0; + + update_buflen(rsa->n, &buf_len); + update_buflen(rsa->e, &buf_len); + + if (include_private) { + update_buflen(rsa->d, &buf_len); + update_buflen(rsa->p, &buf_len); + update_buflen(rsa->q, &buf_len); + update_buflen(rsa->dmp1, &buf_len); + update_buflen(rsa->dmq1, &buf_len); + update_buflen(rsa->iqmp, &buf_len); + + if (rsa->additional_primes != NULL) { + size_t i; + + for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); + i++) { + const RSA_additional_prime *ap = + sk_RSA_additional_prime_value(rsa->additional_primes, i); + update_buflen(ap->prime, &buf_len); + update_buflen(ap->exp, &buf_len); + update_buflen(ap->coeff, &buf_len); + } + } + } + + m = (uint8_t *)OPENSSL_malloc(buf_len + 10); + if (m == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (rsa->n != NULL) { + mod_len = BN_num_bits(rsa->n); + } + + if (!BIO_indent(out, off, 128)) { + goto err; + } + + if (include_private && rsa->d) { + if (BIO_printf(out, "Private-Key: (%d bit)\n", mod_len) <= 0) { + goto err; + } + str = "modulus:"; + s = "publicExponent:"; + } else { + if (BIO_printf(out, "Public-Key: (%d bit)\n", mod_len) <= 0) { + goto err; + } + str = "Modulus:"; + s = "Exponent:"; + } + if (!ASN1_bn_print(out, str, rsa->n, m, off) || + !ASN1_bn_print(out, s, rsa->e, m, off)) { + goto err; + } + + if (include_private) { + if (!ASN1_bn_print(out, "privateExponent:", rsa->d, m, off) || + !ASN1_bn_print(out, "prime1:", rsa->p, m, off) || + !ASN1_bn_print(out, "prime2:", rsa->q, m, off) || + !ASN1_bn_print(out, "exponent1:", rsa->dmp1, m, off) || + !ASN1_bn_print(out, "exponent2:", rsa->dmq1, m, off) || + !ASN1_bn_print(out, "coefficient:", rsa->iqmp, m, off)) { + goto err; + } + + if (rsa->additional_primes != NULL && + sk_RSA_additional_prime_num(rsa->additional_primes) > 0) { + size_t i; + + if (BIO_printf(out, "otherPrimeInfos:\n") <= 0) { + goto err; + } + for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); + i++) { + const RSA_additional_prime *ap = + sk_RSA_additional_prime_value(rsa->additional_primes, i); + + if (BIO_printf(out, "otherPrimeInfo (prime %u):\n", + (unsigned)(i + 3)) <= 0 || + !ASN1_bn_print(out, "prime:", ap->prime, m, off) || + !ASN1_bn_print(out, "exponent:", ap->exp, m, off) || + !ASN1_bn_print(out, "coeff:", ap->coeff, m, off)) { + goto err; + } + } + } + } + ret = 1; + +err: + OPENSSL_free(m); + return ret; +} + +static int rsa_pub_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_rsa_print(bp, pkey->pkey.rsa, indent, 0); +} + + +static int rsa_priv_print(BIO *bp, const EVP_PKEY *pkey, int indent, + ASN1_PCTX *ctx) { + return do_rsa_print(bp, pkey->pkey.rsa, indent, 1); +} + +/* Given an MGF1 Algorithm ID decode to an Algorithm Identifier */ +static X509_ALGOR *rsa_mgf1_decode(X509_ALGOR *alg) { + const uint8_t *p; + int plen; + + if (alg == NULL || + OBJ_obj2nid(alg->algorithm) != NID_mgf1 || + alg->parameter->type != V_ASN1_SEQUENCE) { + return NULL; + } + + p = alg->parameter->value.sequence->data; + plen = alg->parameter->value.sequence->length; + return d2i_X509_ALGOR(NULL, &p, plen); +} + +static RSA_PSS_PARAMS *rsa_pss_decode(const X509_ALGOR *alg, + X509_ALGOR **pmaskHash) { + const uint8_t *p; + int plen; + RSA_PSS_PARAMS *pss; + + *pmaskHash = NULL; + + if (!alg->parameter || alg->parameter->type != V_ASN1_SEQUENCE) { + return NULL; + } + p = alg->parameter->value.sequence->data; + plen = alg->parameter->value.sequence->length; + pss = d2i_RSA_PSS_PARAMS(NULL, &p, plen); + + if (!pss) { + return NULL; + } + + *pmaskHash = rsa_mgf1_decode(pss->maskGenAlgorithm); + + return pss; +} + +static int rsa_pss_param_print(BIO *bp, RSA_PSS_PARAMS *pss, + X509_ALGOR *maskHash, int indent) { + int rv = 0; + + if (!pss) { + if (BIO_puts(bp, " (INVALID PSS PARAMETERS)\n") <= 0) { + return 0; + } + return 1; + } + + if (BIO_puts(bp, "\n") <= 0 || + !BIO_indent(bp, indent, 128) || + BIO_puts(bp, "Hash Algorithm: ") <= 0) { + goto err; + } + + if (pss->hashAlgorithm) { + if (i2a_ASN1_OBJECT(bp, pss->hashAlgorithm->algorithm) <= 0) { + goto err; + } + } else if (BIO_puts(bp, "sha1 (default)") <= 0) { + goto err; + } + + if (BIO_puts(bp, "\n") <= 0 || + !BIO_indent(bp, indent, 128) || + BIO_puts(bp, "Mask Algorithm: ") <= 0) { + goto err; + } + + if (pss->maskGenAlgorithm) { + if (i2a_ASN1_OBJECT(bp, pss->maskGenAlgorithm->algorithm) <= 0 || + BIO_puts(bp, " with ") <= 0) { + goto err; + } + + if (maskHash) { + if (i2a_ASN1_OBJECT(bp, maskHash->algorithm) <= 0) { + goto err; + } + } else if (BIO_puts(bp, "INVALID") <= 0) { + goto err; + } + } else if (BIO_puts(bp, "mgf1 with sha1 (default)") <= 0) { + goto err; + } + BIO_puts(bp, "\n"); + + if (!BIO_indent(bp, indent, 128) || + BIO_puts(bp, "Salt Length: 0x") <= 0) { + goto err; + } + + if (pss->saltLength) { + if (i2a_ASN1_INTEGER(bp, pss->saltLength) <= 0) { + goto err; + } + } else if (BIO_puts(bp, "14 (default)") <= 0) { + goto err; + } + BIO_puts(bp, "\n"); + + if (!BIO_indent(bp, indent, 128) || + BIO_puts(bp, "Trailer Field: 0x") <= 0) { + goto err; + } + + if (pss->trailerField) { + if (i2a_ASN1_INTEGER(bp, pss->trailerField) <= 0) { + goto err; + } + } else if (BIO_puts(bp, "BC (default)") <= 0) { + goto err; + } + BIO_puts(bp, "\n"); + + rv = 1; + +err: + return rv; +} + +static int rsa_sig_print(BIO *bp, const X509_ALGOR *sigalg, + const ASN1_STRING *sig, int indent, ASN1_PCTX *pctx) { + if (OBJ_obj2nid(sigalg->algorithm) == NID_rsassaPss) { + int rv; + RSA_PSS_PARAMS *pss; + X509_ALGOR *maskHash; + + pss = rsa_pss_decode(sigalg, &maskHash); + rv = rsa_pss_param_print(bp, pss, maskHash, indent); + RSA_PSS_PARAMS_free(pss); + X509_ALGOR_free(maskHash); + if (!rv) { + return 0; + } + } else if (!sig && BIO_puts(bp, "\n") <= 0) { + return 0; + } + + if (sig) { + return X509_signature_dump(bp, sig, indent); + } + return 1; +} + +static int old_rsa_priv_decode(EVP_PKEY *pkey, const uint8_t **pder, + int derlen) { + RSA *rsa = d2i_RSAPrivateKey(NULL, pder, derlen); + if (rsa == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_RSA_LIB); + return 0; + } + EVP_PKEY_assign_RSA(pkey, rsa); + return 1; +} + +static int old_rsa_priv_encode(const EVP_PKEY *pkey, uint8_t **pder) { + return i2d_RSAPrivateKey(pkey->pkey.rsa, pder); +} + +/* allocate and set algorithm ID from EVP_MD, default SHA1 */ +static int rsa_md_to_algor(X509_ALGOR **palg, const EVP_MD *md) { + if (EVP_MD_type(md) == NID_sha1) { + return 1; + } + *palg = X509_ALGOR_new(); + if (!*palg) { + return 0; + } + X509_ALGOR_set_md(*palg, md); + return 1; +} + +/* Allocate and set MGF1 algorithm ID from EVP_MD */ +static int rsa_md_to_mgf1(X509_ALGOR **palg, const EVP_MD *mgf1md) { + X509_ALGOR *algtmp = NULL; + ASN1_STRING *stmp = NULL; + *palg = NULL; + + if (EVP_MD_type(mgf1md) == NID_sha1) { + return 1; + } + /* need to embed algorithm ID inside another */ + if (!rsa_md_to_algor(&algtmp, mgf1md) || + !ASN1_item_pack(algtmp, ASN1_ITEM_rptr(X509_ALGOR), &stmp)) { + goto err; + } + *palg = X509_ALGOR_new(); + if (!*palg) { + goto err; + } + X509_ALGOR_set0(*palg, OBJ_nid2obj(NID_mgf1), V_ASN1_SEQUENCE, stmp); + stmp = NULL; + +err: + ASN1_STRING_free(stmp); + X509_ALGOR_free(algtmp); + if (*palg) { + return 1; + } + + return 0; +} + +/* convert algorithm ID to EVP_MD, default SHA1 */ +static const EVP_MD *rsa_algor_to_md(X509_ALGOR *alg) { + const EVP_MD *md; + if (!alg) { + return EVP_sha1(); + } + md = EVP_get_digestbyobj(alg->algorithm); + if (md == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_DIGEST); + } + return md; +} + +/* convert MGF1 algorithm ID to EVP_MD, default SHA1 */ +static const EVP_MD *rsa_mgf1_to_md(X509_ALGOR *alg, X509_ALGOR *maskHash) { + const EVP_MD *md; + if (!alg) { + return EVP_sha1(); + } + /* Check mask and lookup mask hash algorithm */ + if (OBJ_obj2nid(alg->algorithm) != NID_mgf1) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_MASK_ALGORITHM); + return NULL; + } + if (!maskHash) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_MASK_PARAMETER); + return NULL; + } + md = EVP_get_digestbyobj(maskHash->algorithm); + if (md == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNKNOWN_MASK_DIGEST); + return NULL; + } + return md; +} + +/* rsa_ctx_to_pss converts EVP_PKEY_CTX in PSS mode into corresponding + * algorithm parameter, suitable for setting as an AlgorithmIdentifier. */ +static ASN1_STRING *rsa_ctx_to_pss(EVP_PKEY_CTX *pkctx) { + const EVP_MD *sigmd, *mgf1md; + RSA_PSS_PARAMS *pss = NULL; + ASN1_STRING *os = NULL; + EVP_PKEY *pk = EVP_PKEY_CTX_get0_pkey(pkctx); + int saltlen, rv = 0; + + if (!EVP_PKEY_CTX_get_signature_md(pkctx, &sigmd) || + !EVP_PKEY_CTX_get_rsa_mgf1_md(pkctx, &mgf1md) || + !EVP_PKEY_CTX_get_rsa_pss_saltlen(pkctx, &saltlen)) { + goto err; + } + + if (saltlen == -1) { + saltlen = EVP_MD_size(sigmd); + } else if (saltlen == -2) { + saltlen = EVP_PKEY_size(pk) - EVP_MD_size(sigmd) - 2; + if (((EVP_PKEY_bits(pk) - 1) & 0x7) == 0) { + saltlen--; + } + } else { + goto err; + } + + pss = RSA_PSS_PARAMS_new(); + if (!pss) { + goto err; + } + + if (saltlen != 20) { + pss->saltLength = ASN1_INTEGER_new(); + if (!pss->saltLength || + !ASN1_INTEGER_set(pss->saltLength, saltlen)) { + goto err; + } + } + + if (!rsa_md_to_algor(&pss->hashAlgorithm, sigmd) || + !rsa_md_to_mgf1(&pss->maskGenAlgorithm, mgf1md)) { + goto err; + } + + /* Finally create string with pss parameter encoding. */ + if (!ASN1_item_pack(pss, ASN1_ITEM_rptr(RSA_PSS_PARAMS), &os)) { + goto err; + } + rv = 1; + +err: + if (pss) { + RSA_PSS_PARAMS_free(pss); + } + if (rv) { + return os; + } + if (os) { + ASN1_STRING_free(os); + } + return NULL; +} + +/* From PSS AlgorithmIdentifier set public key parameters. */ +static int rsa_pss_to_ctx(EVP_MD_CTX *ctx, X509_ALGOR *sigalg, EVP_PKEY *pkey) { + int ret = 0; + int saltlen; + const EVP_MD *mgf1md = NULL, *md = NULL; + RSA_PSS_PARAMS *pss; + X509_ALGOR *maskHash; + EVP_PKEY_CTX *pkctx; + + /* Sanity check: make sure it is PSS */ + if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_SIGNATURE_TYPE); + return 0; + } + /* Decode PSS parameters */ + pss = rsa_pss_decode(sigalg, &maskHash); + if (pss == NULL) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_PSS_PARAMETERS); + goto err; + } + + mgf1md = rsa_mgf1_to_md(pss->maskGenAlgorithm, maskHash); + if (!mgf1md) { + goto err; + } + md = rsa_algor_to_md(pss->hashAlgorithm); + if (!md) { + goto err; + } + + saltlen = 20; + if (pss->saltLength) { + saltlen = ASN1_INTEGER_get(pss->saltLength); + + /* Could perform more salt length sanity checks but the main + * RSA routines will trap other invalid values anyway. */ + if (saltlen < 0) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_SALT_LENGTH); + goto err; + } + } + + /* low-level routines support only trailer field 0xbc (value 1) + * and PKCS#1 says we should reject any other value anyway. */ + if (pss->trailerField && ASN1_INTEGER_get(pss->trailerField) != 1) { + OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_TRAILER); + goto err; + } + + if (!EVP_DigestVerifyInit(ctx, &pkctx, md, NULL, pkey) || + !EVP_PKEY_CTX_set_rsa_padding(pkctx, RSA_PKCS1_PSS_PADDING) || + !EVP_PKEY_CTX_set_rsa_pss_saltlen(pkctx, saltlen) || + !EVP_PKEY_CTX_set_rsa_mgf1_md(pkctx, mgf1md)) { + goto err; + } + + ret = 1; + +err: + RSA_PSS_PARAMS_free(pss); + if (maskHash) { + X509_ALGOR_free(maskHash); + } + return ret; +} + +/* Customised RSA AlgorithmIdentifier handling. This is called when a signature + * is encountered requiring special handling. We currently only handle PSS. */ +static int rsa_digest_verify_init_from_algorithm(EVP_MD_CTX *ctx, + X509_ALGOR *sigalg, + EVP_PKEY *pkey) { + /* Sanity check: make sure it is PSS */ + if (OBJ_obj2nid(sigalg->algorithm) != NID_rsassaPss) { + OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_SIGNATURE_TYPE); + return 0; + } + return rsa_pss_to_ctx(ctx, sigalg, pkey); +} + +static evp_digest_sign_algorithm_result_t rsa_digest_sign_algorithm( + EVP_MD_CTX *ctx, X509_ALGOR *sigalg) { + int pad_mode; + EVP_PKEY_CTX *pkctx = ctx->pctx; + if (!EVP_PKEY_CTX_get_rsa_padding(pkctx, &pad_mode)) { + return EVP_DIGEST_SIGN_ALGORITHM_ERROR; + } + if (pad_mode == RSA_PKCS1_PSS_PADDING) { + ASN1_STRING *os1 = rsa_ctx_to_pss(pkctx); + if (!os1) { + return EVP_DIGEST_SIGN_ALGORITHM_ERROR; + } + X509_ALGOR_set0(sigalg, OBJ_nid2obj(NID_rsassaPss), V_ASN1_SEQUENCE, os1); + return EVP_DIGEST_SIGN_ALGORITHM_SUCCESS; + } + + /* Other padding schemes use the default behavior. */ + return EVP_DIGEST_SIGN_ALGORITHM_DEFAULT; +} + +const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = { + EVP_PKEY_RSA, + EVP_PKEY_RSA, + ASN1_PKEY_SIGPARAM_NULL, + + "RSA", + + rsa_pub_decode, + rsa_pub_encode, + rsa_pub_cmp, + rsa_pub_print, + + rsa_priv_decode, + rsa_priv_encode, + rsa_priv_print, + + rsa_opaque, + rsa_supports_digest, + + int_rsa_size, + rsa_bits, + + 0,0,0,0,0,0, + + rsa_sig_print, + int_rsa_free, + + old_rsa_priv_decode, + old_rsa_priv_encode, + + rsa_digest_verify_init_from_algorithm, + rsa_digest_sign_algorithm, +}; diff --git a/TMessagesProj/jni/boringssl/crypto/evp/pbkdf.c b/TMessagesProj/jni/boringssl/crypto/evp/pbkdf.c new file mode 100644 index 00000000..be6ed86a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/pbkdf.c @@ -0,0 +1,135 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include + + +int PKCS5_PBKDF2_HMAC(const char *password, size_t password_len, + const uint8_t *salt, size_t salt_len, unsigned iterations, + const EVP_MD *digest, size_t key_len, uint8_t *out_key) { + uint8_t digest_tmp[EVP_MAX_MD_SIZE], *p, itmp[4]; + size_t cplen, mdlen, tkeylen, k; + unsigned j; + uint32_t i = 1; + HMAC_CTX hctx_tpl, hctx; + + mdlen = EVP_MD_size(digest); + HMAC_CTX_init(&hctx_tpl); + p = out_key; + tkeylen = key_len; + if (!HMAC_Init_ex(&hctx_tpl, password, password_len, digest, NULL)) { + HMAC_CTX_cleanup(&hctx_tpl); + return 0; + } + while (tkeylen) { + if (tkeylen > mdlen) { + cplen = mdlen; + } else { + cplen = tkeylen; + } + /* We are unlikely to ever use more than 256 blocks (5120 bits!) + * but just in case... */ + itmp[0] = (uint8_t)((i >> 24) & 0xff); + itmp[1] = (uint8_t)((i >> 16) & 0xff); + itmp[2] = (uint8_t)((i >> 8) & 0xff); + itmp[3] = (uint8_t)(i & 0xff); + if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) { + HMAC_CTX_cleanup(&hctx_tpl); + return 0; + } + if (!HMAC_Update(&hctx, salt, salt_len) || + !HMAC_Update(&hctx, itmp, 4) || + !HMAC_Final(&hctx, digest_tmp, NULL)) { + HMAC_CTX_cleanup(&hctx_tpl); + HMAC_CTX_cleanup(&hctx); + return 0; + } + HMAC_CTX_cleanup(&hctx); + memcpy(p, digest_tmp, cplen); + for (j = 1; j < iterations; j++) { + if (!HMAC_CTX_copy(&hctx, &hctx_tpl)) { + HMAC_CTX_cleanup(&hctx_tpl); + return 0; + } + if (!HMAC_Update(&hctx, digest_tmp, mdlen) || + !HMAC_Final(&hctx, digest_tmp, NULL)) { + HMAC_CTX_cleanup(&hctx_tpl); + HMAC_CTX_cleanup(&hctx); + return 0; + } + HMAC_CTX_cleanup(&hctx); + for (k = 0; k < cplen; k++) { + p[k] ^= digest_tmp[k]; + } + } + tkeylen -= cplen; + i++; + p += cplen; + } + HMAC_CTX_cleanup(&hctx_tpl); + return 1; +} + +int PKCS5_PBKDF2_HMAC_SHA1(const char *password, size_t password_len, + const uint8_t *salt, size_t salt_len, + unsigned iterations, size_t key_len, + uint8_t *out_key) { + return PKCS5_PBKDF2_HMAC(password, password_len, salt, salt_len, iterations, + EVP_sha1(), key_len, out_key); +} diff --git a/TMessagesProj/jni/boringssl/crypto/evp/sign.c b/TMessagesProj/jni/boringssl/crypto/evp/sign.c new file mode 100644 index 00000000..ced86bdf --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/evp/sign.c @@ -0,0 +1,151 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include "internal.h" + + +int EVP_SignInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) { + return EVP_DigestInit_ex(ctx, type, impl); +} + +int EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type) { + return EVP_DigestInit(ctx, type); +} + +int EVP_SignUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) { + return EVP_DigestUpdate(ctx, data, len); +} + +int EVP_SignFinal(const EVP_MD_CTX *ctx, uint8_t *sig, + unsigned int *out_sig_len, EVP_PKEY *pkey) { + uint8_t m[EVP_MAX_MD_SIZE]; + unsigned int m_len; + int ret = 0; + EVP_MD_CTX tmp_ctx; + EVP_PKEY_CTX *pkctx = NULL; + size_t sig_len = EVP_PKEY_size(pkey); + + *out_sig_len = 0; + EVP_MD_CTX_init(&tmp_ctx); + if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) || + !EVP_DigestFinal_ex(&tmp_ctx, m, &m_len)) { + goto out; + } + EVP_MD_CTX_cleanup(&tmp_ctx); + + pkctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!pkctx || !EVP_PKEY_sign_init(pkctx) || + !EVP_PKEY_CTX_set_signature_md(pkctx, ctx->digest) || + !EVP_PKEY_sign(pkctx, sig, &sig_len, m, m_len)) { + goto out; + } + *out_sig_len = sig_len; + ret = 1; + +out: + if (pkctx) { + EVP_PKEY_CTX_free(pkctx); + } + + return ret; +} + +int EVP_VerifyInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) { + return EVP_DigestInit_ex(ctx, type, impl); +} + +int EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type) { + return EVP_DigestInit(ctx, type); +} + +int EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *data, size_t len) { + return EVP_DigestUpdate(ctx, data, len); +} + +int EVP_VerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len, + EVP_PKEY *pkey) { + uint8_t m[EVP_MAX_MD_SIZE]; + unsigned int m_len; + int ret = 0; + EVP_MD_CTX tmp_ctx; + EVP_PKEY_CTX *pkctx = NULL; + + EVP_MD_CTX_init(&tmp_ctx); + if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) || + !EVP_DigestFinal_ex(&tmp_ctx, m, &m_len)) { + EVP_MD_CTX_cleanup(&tmp_ctx); + goto out; + } + EVP_MD_CTX_cleanup(&tmp_ctx); + + pkctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!pkctx || + !EVP_PKEY_verify_init(pkctx) || + !EVP_PKEY_CTX_set_signature_md(pkctx, ctx->digest)) { + goto out; + } + ret = EVP_PKEY_verify(pkctx, sig, sig_len, m, m_len); + +out: + EVP_PKEY_CTX_free(pkctx); + return ret; +} + diff --git a/TMessagesProj/jni/boringssl/crypto/ex_data.c b/TMessagesProj/jni/boringssl/crypto/ex_data.c new file mode 100644 index 00000000..f562f17b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/ex_data.c @@ -0,0 +1,314 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +struct crypto_ex_data_func_st { + long argl; /* Arbitary long */ + void *argp; /* Arbitary void pointer */ + CRYPTO_EX_new *new_func; + CRYPTO_EX_free *free_func; + CRYPTO_EX_dup *dup_func; +}; + +int CRYPTO_get_ex_new_index(CRYPTO_EX_DATA_CLASS *ex_data_class, int *out_index, + long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func) { + CRYPTO_EX_DATA_FUNCS *funcs; + int ret = 0; + + funcs = OPENSSL_malloc(sizeof(CRYPTO_EX_DATA_FUNCS)); + if (funcs == NULL) { + OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE); + return 0; + } + + funcs->argl = argl; + funcs->argp = argp; + funcs->new_func = new_func; + funcs->dup_func = dup_func; + funcs->free_func = free_func; + + CRYPTO_STATIC_MUTEX_lock_write(&ex_data_class->lock); + + if (ex_data_class->meth == NULL) { + ex_data_class->meth = sk_CRYPTO_EX_DATA_FUNCS_new_null(); + } + + if (ex_data_class->meth == NULL || + !sk_CRYPTO_EX_DATA_FUNCS_push(ex_data_class->meth, funcs)) { + OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE); + OPENSSL_free(funcs); + goto err; + } + + *out_index = sk_CRYPTO_EX_DATA_FUNCS_num(ex_data_class->meth) - 1 + + ex_data_class->num_reserved; + ret = 1; + +err: + CRYPTO_STATIC_MUTEX_unlock(&ex_data_class->lock); + return ret; +} + +int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int index, void *val) { + int n, i; + + if (ad->sk == NULL) { + ad->sk = sk_void_new_null(); + if (ad->sk == NULL) { + OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE); + return 0; + } + } + + n = sk_void_num(ad->sk); + + /* Add NULL values until the stack is long enough. */ + for (i = n; i <= index; i++) { + if (!sk_void_push(ad->sk, NULL)) { + OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE); + return 0; + } + } + + sk_void_set(ad->sk, index, val); + return 1; +} + +void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int idx) { + if (ad->sk == NULL || idx < 0 || (size_t)idx >= sk_void_num(ad->sk)) { + return NULL; + } + return sk_void_value(ad->sk, idx); +} + +/* get_func_pointers takes a copy of the CRYPTO_EX_DATA_FUNCS pointers, if any, + * for the given class. If there are some pointers, it sets |*out| to point to + * a fresh stack of them. Otherwise it sets |*out| to NULL. It returns one on + * success or zero on error. */ +static int get_func_pointers(STACK_OF(CRYPTO_EX_DATA_FUNCS) **out, + CRYPTO_EX_DATA_CLASS *ex_data_class) { + size_t n; + + *out = NULL; + + /* CRYPTO_EX_DATA_FUNCS structures are static once set, so we can take a + * shallow copy of the list under lock and then use the structures without + * the lock held. */ + CRYPTO_STATIC_MUTEX_lock_read(&ex_data_class->lock); + n = sk_CRYPTO_EX_DATA_FUNCS_num(ex_data_class->meth); + if (n > 0) { + *out = sk_CRYPTO_EX_DATA_FUNCS_dup(ex_data_class->meth); + } + CRYPTO_STATIC_MUTEX_unlock(&ex_data_class->lock); + + if (n > 0 && *out == NULL) { + OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE); + return 0; + } + + return 1; +} + +int CRYPTO_new_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, void *obj, + CRYPTO_EX_DATA *ad) { + STACK_OF(CRYPTO_EX_DATA_FUNCS) *func_pointers; + size_t i; + + ad->sk = NULL; + + if (!get_func_pointers(&func_pointers, ex_data_class)) { + return 0; + } + + for (i = 0; i < sk_CRYPTO_EX_DATA_FUNCS_num(func_pointers); i++) { + CRYPTO_EX_DATA_FUNCS *func_pointer = + sk_CRYPTO_EX_DATA_FUNCS_value(func_pointers, i); + if (func_pointer->new_func) { + func_pointer->new_func(obj, NULL, ad, i + ex_data_class->num_reserved, + func_pointer->argl, func_pointer->argp); + } + } + + sk_CRYPTO_EX_DATA_FUNCS_free(func_pointers); + + return 1; +} + +int CRYPTO_dup_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, CRYPTO_EX_DATA *to, + const CRYPTO_EX_DATA *from) { + STACK_OF(CRYPTO_EX_DATA_FUNCS) *func_pointers; + size_t i; + + if (!from->sk) { + /* In this case, |from| is blank, which is also the initial state of |to|, + * so there's nothing to do. */ + return 1; + } + + if (!get_func_pointers(&func_pointers, ex_data_class)) { + return 0; + } + + for (i = 0; i < sk_CRYPTO_EX_DATA_FUNCS_num(func_pointers); i++) { + CRYPTO_EX_DATA_FUNCS *func_pointer = + sk_CRYPTO_EX_DATA_FUNCS_value(func_pointers, i); + void *ptr = CRYPTO_get_ex_data(from, i + ex_data_class->num_reserved); + if (func_pointer->dup_func) { + func_pointer->dup_func(to, from, &ptr, i + ex_data_class->num_reserved, + func_pointer->argl, func_pointer->argp); + } + CRYPTO_set_ex_data(to, i + ex_data_class->num_reserved, ptr); + } + + sk_CRYPTO_EX_DATA_FUNCS_free(func_pointers); + + return 1; +} + +void CRYPTO_free_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, void *obj, + CRYPTO_EX_DATA *ad) { + STACK_OF(CRYPTO_EX_DATA_FUNCS) *func_pointers; + size_t i; + + if (!get_func_pointers(&func_pointers, ex_data_class)) { + return; + } + + for (i = 0; i < sk_CRYPTO_EX_DATA_FUNCS_num(func_pointers); i++) { + CRYPTO_EX_DATA_FUNCS *func_pointer = + sk_CRYPTO_EX_DATA_FUNCS_value(func_pointers, i); + if (func_pointer->free_func) { + void *ptr = CRYPTO_get_ex_data(ad, i + ex_data_class->num_reserved); + func_pointer->free_func(obj, ptr, ad, i + ex_data_class->num_reserved, + func_pointer->argl, func_pointer->argp); + } + } + + sk_CRYPTO_EX_DATA_FUNCS_free(func_pointers); + + sk_void_free(ad->sk); + ad->sk = NULL; +} + +void CRYPTO_cleanup_all_ex_data(void) {} diff --git a/TMessagesProj/jni/boringssl/crypto/header_removed.h b/TMessagesProj/jni/boringssl/crypto/header_removed.h new file mode 100644 index 00000000..49ee31a4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/header_removed.h @@ -0,0 +1,17 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is linked to under the names of several headers that have been + * removed. It's possible to put a #error in here in order to catch that an + * clean up older code. */ diff --git a/TMessagesProj/jni/boringssl/crypto/hkdf/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/hkdf/CMakeLists.txt new file mode 100644 index 00000000..39d64366 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/hkdf/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + hkdf + + OBJECT + + hkdf.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/hkdf/hkdf.c b/TMessagesProj/jni/boringssl/crypto/hkdf/hkdf.c new file mode 100644 index 00000000..f9cdcb0b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/hkdf/hkdf.c @@ -0,0 +1,89 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + +#include +#include + + +int HKDF(uint8_t *out_key, size_t out_len, + const EVP_MD *digest, + const uint8_t *secret, size_t secret_len, + const uint8_t *salt, size_t salt_len, + const uint8_t *info, size_t info_len) { + /* https://tools.ietf.org/html/rfc5869#section-2.2 */ + const size_t digest_len = EVP_MD_size(digest); + uint8_t prk[EVP_MAX_MD_SIZE], previous[EVP_MAX_MD_SIZE]; + size_t n, done = 0; + unsigned i, prk_len; + int ret = 0; + HMAC_CTX hmac; + + /* If salt is not given, HashLength zeros are used. However, HMAC does that + * internally already so we can ignore it.*/ + + /* Expand key material to desired length. */ + n = (out_len + digest_len - 1) / digest_len; + if (out_len + digest_len < out_len || n > 255) { + OPENSSL_PUT_ERROR(HKDF, HKDF_R_OUTPUT_TOO_LARGE); + return 0; + } + + HMAC_CTX_init(&hmac); + + /* Extract input keying material into pseudorandom key |prk|. */ + if (HMAC(digest, salt, salt_len, secret, secret_len, prk, &prk_len) == NULL) { + goto out; + } + assert(prk_len == digest_len); + + if (!HMAC_Init_ex(&hmac, prk, prk_len, digest, NULL)) { + goto out; + } + + for (i = 0; i < n; i++) { + uint8_t ctr = i + 1; + size_t todo; + + if (i != 0 && (!HMAC_Init_ex(&hmac, NULL, 0, NULL, NULL) || + !HMAC_Update(&hmac, previous, digest_len))) { + goto out; + } + if (!HMAC_Update(&hmac, info, info_len) || + !HMAC_Update(&hmac, &ctr, 1) || + !HMAC_Final(&hmac, previous, NULL)) { + goto out; + } + + todo = digest_len; + if (done + todo > out_len) { + todo = out_len - done; + } + memcpy(out_key + done, previous, todo); + done += todo; + } + + ret = 1; + +out: + HMAC_CTX_cleanup(&hmac); + if (ret != 1) { + OPENSSL_PUT_ERROR(HKDF, ERR_R_HMAC_LIB); + } + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/hmac/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/hmac/CMakeLists.txt new file mode 100644 index 00000000..cd034ae4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/hmac/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + hmac + + OBJECT + + hmac.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/hmac/hmac.c b/TMessagesProj/jni/boringssl/crypto/hmac/hmac.c new file mode 100644 index 00000000..d37a249f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/hmac/hmac.c @@ -0,0 +1,213 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include + + +uint8_t *HMAC(const EVP_MD *evp_md, const void *key, size_t key_len, + const uint8_t *data, size_t data_len, uint8_t *out, + unsigned int *out_len) { + HMAC_CTX ctx; + static uint8_t static_out_buffer[EVP_MAX_MD_SIZE]; + + /* OpenSSL has traditionally supported using a static buffer if |out| is + * NULL. We maintain that but don't document it. This behaviour should be + * considered to be deprecated. */ + if (out == NULL) { + out = static_out_buffer; + } + + HMAC_CTX_init(&ctx); + if (!HMAC_Init_ex(&ctx, key, key_len, evp_md, NULL) || + !HMAC_Update(&ctx, data, data_len) || + !HMAC_Final(&ctx, out, out_len)) { + out = NULL; + } + + HMAC_CTX_cleanup(&ctx); + return out; +} + +void HMAC_CTX_init(HMAC_CTX *ctx) { + ctx->md = NULL; + EVP_MD_CTX_init(&ctx->i_ctx); + EVP_MD_CTX_init(&ctx->o_ctx); + EVP_MD_CTX_init(&ctx->md_ctx); +} + +void HMAC_CTX_cleanup(HMAC_CTX *ctx) { + EVP_MD_CTX_cleanup(&ctx->i_ctx); + EVP_MD_CTX_cleanup(&ctx->o_ctx); + EVP_MD_CTX_cleanup(&ctx->md_ctx); + OPENSSL_cleanse(ctx, sizeof(HMAC_CTX)); +} + +int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len, + const EVP_MD *md, ENGINE *impl) { + if (md == NULL) { + md = ctx->md; + } + + /* If either |key| is non-NULL or |md| has changed, initialize with a new key + * rather than rewinding the previous one. + * + * TODO(davidben,eroman): Passing the previous |md| with a NULL |key| is + * ambiguous between using the empty key and reusing the previous key. There + * exist callers which intend the latter, but the former is an awkward edge + * case. Fix to API to avoid this. */ + if (md != ctx->md || key != NULL) { + size_t i; + uint8_t pad[HMAC_MAX_MD_CBLOCK]; + uint8_t key_block[HMAC_MAX_MD_CBLOCK]; + unsigned key_block_len; + + size_t block_size = EVP_MD_block_size(md); + assert(block_size <= sizeof(key_block)); + if (block_size < key_len) { + /* Long keys are hashed. */ + if (!EVP_DigestInit_ex(&ctx->md_ctx, md, impl) || + !EVP_DigestUpdate(&ctx->md_ctx, key, key_len) || + !EVP_DigestFinal_ex(&ctx->md_ctx, key_block, &key_block_len)) { + return 0; + } + } else { + assert(key_len >= 0 && key_len <= sizeof(key_block)); + memcpy(key_block, key, key_len); + key_block_len = (unsigned)key_len; + } + /* Keys are then padded with zeros. */ + if (key_block_len != HMAC_MAX_MD_CBLOCK) { + memset(&key_block[key_block_len], 0, sizeof(key_block) - key_block_len); + } + + for (i = 0; i < HMAC_MAX_MD_CBLOCK; i++) { + pad[i] = 0x36 ^ key_block[i]; + } + if (!EVP_DigestInit_ex(&ctx->i_ctx, md, impl) || + !EVP_DigestUpdate(&ctx->i_ctx, pad, EVP_MD_block_size(md))) { + return 0; + } + + for (i = 0; i < HMAC_MAX_MD_CBLOCK; i++) { + pad[i] = 0x5c ^ key_block[i]; + } + if (!EVP_DigestInit_ex(&ctx->o_ctx, md, impl) || + !EVP_DigestUpdate(&ctx->o_ctx, pad, EVP_MD_block_size(md))) { + return 0; + } + + ctx->md = md; + } + + if (!EVP_MD_CTX_copy_ex(&ctx->md_ctx, &ctx->i_ctx)) { + return 0; + } + + return 1; +} + +int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, size_t data_len) { + return EVP_DigestUpdate(&ctx->md_ctx, data, data_len); +} + +int HMAC_Final(HMAC_CTX *ctx, uint8_t *out, unsigned int *out_len) { + unsigned int i; + uint8_t buf[EVP_MAX_MD_SIZE]; + + /* TODO(davidben): The only thing that can officially fail here is + * |EVP_MD_CTX_copy_ex|, but even that should be impossible in this case. */ + if (!EVP_DigestFinal_ex(&ctx->md_ctx, buf, &i) || + !EVP_MD_CTX_copy_ex(&ctx->md_ctx, &ctx->o_ctx) || + !EVP_DigestUpdate(&ctx->md_ctx, buf, i) || + !EVP_DigestFinal_ex(&ctx->md_ctx, out, out_len)) { + *out_len = 0; + return 0; + } + + return 1; +} + +size_t HMAC_size(const HMAC_CTX *ctx) { + return EVP_MD_size(ctx->md); +} + +int HMAC_CTX_copy_ex(HMAC_CTX *dest, const HMAC_CTX *src) { + if (!EVP_MD_CTX_copy_ex(&dest->i_ctx, &src->i_ctx) || + !EVP_MD_CTX_copy_ex(&dest->o_ctx, &src->o_ctx) || + !EVP_MD_CTX_copy_ex(&dest->md_ctx, &src->md_ctx)) { + return 0; + } + + dest->md = src->md; + return 1; +} + +int HMAC_Init(HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md) { + if (key && md) { + HMAC_CTX_init(ctx); + } + return HMAC_Init_ex(ctx, key, key_len, md, NULL); +} + +int HMAC_CTX_copy(HMAC_CTX *dest, const HMAC_CTX *src) { + HMAC_CTX_init(dest); + return HMAC_CTX_copy_ex(dest, src); +} diff --git a/TMessagesProj/jni/boringssl/crypto/internal.h b/TMessagesProj/jni/boringssl/crypto/internal.h new file mode 100644 index 00000000..a502d20e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/internal.h @@ -0,0 +1,547 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_CRYPTO_INTERNAL_H +#define OPENSSL_HEADER_CRYPTO_INTERNAL_H + +#include +#include + +#if defined(OPENSSL_NO_THREADS) +#elif defined(OPENSSL_WINDOWS) +#pragma warning(push, 3) +#include +#pragma warning(pop) +#else +#include +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* MSVC's C4701 warning about the use of *potentially*--as opposed to + * *definitely*--uninitialized values sometimes has false positives. Usually + * the false positives can and should be worked around by simplifying the + * control flow. When that is not practical, annotate the function containing + * the code that triggers the warning with + * OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS after its parameters: + * + * void f() OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS { + * ... + * } + * + * Note that MSVC's control flow analysis seems to operate on a whole-function + * basis, so the annotation must be placed on the entire function, not just a + * block within the function. */ +#if defined(_MSC_VER) +#define OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS \ + __pragma(warning(suppress:4701)) +#else +#define OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS +#endif + +/* MSVC will sometimes correctly detect unreachable code and issue a warning, + * which breaks the build since we treat errors as warnings, in some rare cases + * where we want to allow the dead code to continue to exist. In these + * situations, annotate the function containing the unreachable code with + * OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS after its parameters: + * + * void f() OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS { + * ... + * } + * + * Note that MSVC's reachability analysis seems to operate on a whole-function + * basis, so the annotation must be placed on the entire function, not just a + * block within the function. */ +#if defined(_MSC_VER) +#define OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS \ + __pragma(warning(suppress:4702)) +#else +#define OPENSSL_SUPPRESS_UNREACHABLE_CODE_WARNINGS +#endif + + +#if defined(_MSC_VER) +#define OPENSSL_U64(x) x##UI64 +#else + +#if defined(OPENSSL_64_BIT) +#define OPENSSL_U64(x) x##UL +#else +#define OPENSSL_U64(x) x##ULL +#endif + +#endif /* defined(_MSC_VER) */ + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM) || \ + defined(OPENSSL_AARCH64) +/* OPENSSL_cpuid_setup initializes OPENSSL_ia32cap_P. */ +void OPENSSL_cpuid_setup(void); +#endif + +#if !defined(inline) +#define inline __inline +#endif + + +/* Constant-time utility functions. + * + * The following methods return a bitmask of all ones (0xff...f) for true and 0 + * for false. This is useful for choosing a value based on the result of a + * conditional in constant time. For example, + * + * if (a < b) { + * c = a; + * } else { + * c = b; + * } + * + * can be written as + * + * unsigned int lt = constant_time_lt(a, b); + * c = constant_time_select(lt, a, b); */ + +/* constant_time_msb returns the given value with the MSB copied to all the + * other bits. */ +static inline unsigned int constant_time_msb(unsigned int a) { + return (unsigned int)((int)(a) >> (sizeof(int) * 8 - 1)); +} + +/* constant_time_lt returns 0xff..f if a < b and 0 otherwise. */ +static inline unsigned int constant_time_lt(unsigned int a, unsigned int b) { + /* Consider the two cases of the problem: + * msb(a) == msb(b): a < b iff the MSB of a - b is set. + * msb(a) != msb(b): a < b iff the MSB of b is set. + * + * If msb(a) == msb(b) then the following evaluates as: + * msb(a^((a^b)|((a-b)^a))) == + * msb(a^((a-b) ^ a)) == (because msb(a^b) == 0) + * msb(a^a^(a-b)) == (rearranging) + * msb(a-b) (because ∀x. x^x == 0) + * + * Else, if msb(a) != msb(b) then the following evaluates as: + * msb(a^((a^b)|((a-b)^a))) == + * msb(a^(𝟙 | ((a-b)^a))) == (because msb(a^b) == 1 and 𝟙 + * represents a value s.t. msb(𝟙) = 1) + * msb(a^𝟙) == (because ORing with 1 results in 1) + * msb(b) + * + * + * Here is an SMT-LIB verification of this formula: + * + * (define-fun lt ((a (_ BitVec 32)) (b (_ BitVec 32))) (_ BitVec 32) + * (bvxor a (bvor (bvxor a b) (bvxor (bvsub a b) a))) + * ) + * + * (declare-fun a () (_ BitVec 32)) + * (declare-fun b () (_ BitVec 32)) + * + * (assert (not (= (= #x00000001 (bvlshr (lt a b) #x0000001f)) (bvult a b)))) + * (check-sat) + * (get-model) + */ + return constant_time_msb(a^((a^b)|((a-b)^a))); +} + +/* constant_time_lt_8 acts like |constant_time_lt| but returns an 8-bit mask. */ +static inline uint8_t constant_time_lt_8(unsigned int a, unsigned int b) { + return (uint8_t)(constant_time_lt(a, b)); +} + +/* constant_time_gt returns 0xff..f if a >= b and 0 otherwise. */ +static inline unsigned int constant_time_ge(unsigned int a, unsigned int b) { + return ~constant_time_lt(a, b); +} + +/* constant_time_ge_8 acts like |constant_time_ge| but returns an 8-bit mask. */ +static inline uint8_t constant_time_ge_8(unsigned int a, unsigned int b) { + return (uint8_t)(constant_time_ge(a, b)); +} + +/* constant_time_is_zero returns 0xff..f if a == 0 and 0 otherwise. */ +static inline unsigned int constant_time_is_zero(unsigned int a) { + /* Here is an SMT-LIB verification of this formula: + * + * (define-fun is_zero ((a (_ BitVec 32))) (_ BitVec 32) + * (bvand (bvnot a) (bvsub a #x00000001)) + * ) + * + * (declare-fun a () (_ BitVec 32)) + * + * (assert (not (= (= #x00000001 (bvlshr (is_zero a) #x0000001f)) (= a #x00000000)))) + * (check-sat) + * (get-model) + */ + return constant_time_msb(~a & (a - 1)); +} + +/* constant_time_is_zero_8 acts like constant_time_is_zero but returns an 8-bit + * mask. */ +static inline uint8_t constant_time_is_zero_8(unsigned int a) { + return (uint8_t)(constant_time_is_zero(a)); +} + +/* constant_time_eq returns 0xff..f if a == b and 0 otherwise. */ +static inline unsigned int constant_time_eq(unsigned int a, unsigned int b) { + return constant_time_is_zero(a ^ b); +} + +/* constant_time_eq_8 acts like |constant_time_eq| but returns an 8-bit mask. */ +static inline uint8_t constant_time_eq_8(unsigned int a, unsigned int b) { + return (uint8_t)(constant_time_eq(a, b)); +} + +/* constant_time_eq_int acts like |constant_time_eq| but works on int values. */ +static inline unsigned int constant_time_eq_int(int a, int b) { + return constant_time_eq((unsigned)(a), (unsigned)(b)); +} + +/* constant_time_eq_int_8 acts like |constant_time_eq_int| but returns an 8-bit + * mask. */ +static inline uint8_t constant_time_eq_int_8(int a, int b) { + return constant_time_eq_8((unsigned)(a), (unsigned)(b)); +} + +/* constant_time_select returns (mask & a) | (~mask & b). When |mask| is all 1s + * or all 0s (as returned by the methods above), the select methods return + * either |a| (if |mask| is nonzero) or |b| (if |mask| is zero). */ +static inline unsigned int constant_time_select(unsigned int mask, + unsigned int a, unsigned int b) { + return (mask & a) | (~mask & b); +} + +/* constant_time_select_8 acts like |constant_time_select| but operates on + * 8-bit values. */ +static inline uint8_t constant_time_select_8(uint8_t mask, uint8_t a, + uint8_t b) { + return (uint8_t)(constant_time_select(mask, a, b)); +} + +/* constant_time_select_int acts like |constant_time_select| but operates on + * ints. */ +static inline int constant_time_select_int(unsigned int mask, int a, int b) { + return (int)(constant_time_select(mask, (unsigned)(a), (unsigned)(b))); +} + + +/* Thread-safe initialisation. */ + +#if defined(OPENSSL_NO_THREADS) +typedef uint32_t CRYPTO_once_t; +#define CRYPTO_ONCE_INIT 0 +#elif defined(OPENSSL_WINDOWS) +typedef LONG CRYPTO_once_t; +#define CRYPTO_ONCE_INIT 0 +#else +typedef pthread_once_t CRYPTO_once_t; +#define CRYPTO_ONCE_INIT PTHREAD_ONCE_INIT +#endif + +/* CRYPTO_once calls |init| exactly once per process. This is thread-safe: if + * concurrent threads call |CRYPTO_once| with the same |CRYPTO_once_t| argument + * then they will block until |init| completes, but |init| will have only been + * called once. + * + * The |once| argument must be a |CRYPTO_once_t| that has been initialised with + * the value |CRYPTO_ONCE_INIT|. */ +OPENSSL_EXPORT void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)); + + +/* Reference counting. */ + +/* CRYPTO_REFCOUNT_MAX is the value at which the reference count saturates. */ +#define CRYPTO_REFCOUNT_MAX 0xffffffff + +/* CRYPTO_refcount_inc atomically increments the value at |*count| unless the + * value would overflow. It's safe for multiple threads to concurrently call + * this or |CRYPTO_refcount_dec_and_test_zero| on the same + * |CRYPTO_refcount_t|. */ +OPENSSL_EXPORT void CRYPTO_refcount_inc(CRYPTO_refcount_t *count); + +/* CRYPTO_refcount_dec_and_test_zero tests the value at |*count|: + * if it's zero, it crashes the address space. + * if it's the maximum value, it returns zero. + * otherwise, it atomically decrements it and returns one iff the resulting + * value is zero. + * + * It's safe for multiple threads to concurrently call this or + * |CRYPTO_refcount_inc| on the same |CRYPTO_refcount_t|. */ +OPENSSL_EXPORT int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *count); + + +/* Locks. + * + * Two types of locks are defined: |CRYPTO_MUTEX|, which can be used in + * structures as normal, and |struct CRYPTO_STATIC_MUTEX|, which can be used as + * a global lock. A global lock must be initialised to the value + * |CRYPTO_STATIC_MUTEX_INIT|. + * + * |CRYPTO_MUTEX| can appear in public structures and so is defined in + * thread.h. + * + * The global lock is a different type because there's no static initialiser + * value on Windows for locks, so global locks have to be coupled with a + * |CRYPTO_once_t| to ensure that the lock is setup before use. This is done + * automatically by |CRYPTO_STATIC_MUTEX_lock_*|. */ + +#if defined(OPENSSL_NO_THREADS) +struct CRYPTO_STATIC_MUTEX {}; +#define CRYPTO_STATIC_MUTEX_INIT {} +#elif defined(OPENSSL_WINDOWS) +struct CRYPTO_STATIC_MUTEX { + CRYPTO_once_t once; + CRITICAL_SECTION lock; +}; +#define CRYPTO_STATIC_MUTEX_INIT { CRYPTO_ONCE_INIT, { 0 } } +#else +struct CRYPTO_STATIC_MUTEX { + pthread_rwlock_t lock; +}; +#define CRYPTO_STATIC_MUTEX_INIT { PTHREAD_RWLOCK_INITIALIZER } +#endif + +/* CRYPTO_MUTEX_init initialises |lock|. If |lock| is a static variable, use a + * |CRYPTO_STATIC_MUTEX|. */ +OPENSSL_EXPORT void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock); + +/* CRYPTO_MUTEX_lock_read locks |lock| such that other threads may also have a + * read lock, but none may have a write lock. (On Windows, read locks are + * actually fully exclusive.) */ +OPENSSL_EXPORT void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock); + +/* CRYPTO_MUTEX_lock_write locks |lock| such that no other thread has any type + * of lock on it. */ +OPENSSL_EXPORT void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock); + +/* CRYPTO_MUTEX_unlock unlocks |lock|. */ +OPENSSL_EXPORT void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock); + +/* CRYPTO_MUTEX_cleanup releases all resources held by |lock|. */ +OPENSSL_EXPORT void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock); + +/* CRYPTO_STATIC_MUTEX_lock_read locks |lock| such that other threads may also + * have a read lock, but none may have a write lock. The |lock| variable does + * not need to be initialised by any function, but must have been statically + * initialised with |CRYPTO_STATIC_MUTEX_INIT|. */ +OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_lock_read( + struct CRYPTO_STATIC_MUTEX *lock); + +/* CRYPTO_STATIC_MUTEX_lock_write locks |lock| such that no other thread has + * any type of lock on it. The |lock| variable does not need to be initialised + * by any function, but must have been statically initialised with + * |CRYPTO_STATIC_MUTEX_INIT|. */ +OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_lock_write( + struct CRYPTO_STATIC_MUTEX *lock); + +/* CRYPTO_STATIC_MUTEX_unlock unlocks |lock|. */ +OPENSSL_EXPORT void CRYPTO_STATIC_MUTEX_unlock( + struct CRYPTO_STATIC_MUTEX *lock); + + +/* Thread local storage. */ + +/* thread_local_data_t enumerates the types of thread-local data that can be + * stored. */ +typedef enum { + OPENSSL_THREAD_LOCAL_ERR = 0, + OPENSSL_THREAD_LOCAL_RAND, + OPENSSL_THREAD_LOCAL_TEST, + NUM_OPENSSL_THREAD_LOCALS, +} thread_local_data_t; + +/* thread_local_destructor_t is the type of a destructor function that will be + * called when a thread exits and its thread-local storage needs to be freed. */ +typedef void (*thread_local_destructor_t)(void *); + +/* CRYPTO_get_thread_local gets the pointer value that is stored for the + * current thread for the given index, or NULL if none has been set. */ +OPENSSL_EXPORT void *CRYPTO_get_thread_local(thread_local_data_t value); + +/* CRYPTO_set_thread_local sets a pointer value for the current thread at the + * given index. This function should only be called once per thread for a given + * |index|: rather than update the pointer value itself, update the data that + * is pointed to. + * + * The destructor function will be called when a thread exits to free this + * thread-local data. All calls to |CRYPTO_set_thread_local| with the same + * |index| should have the same |destructor| argument. The destructor may be + * called with a NULL argument if a thread that never set a thread-local + * pointer for |index|, exits. The destructor may be called concurrently with + * different arguments. + * + * This function returns one on success or zero on error. If it returns zero + * then |destructor| has been called with |value| already. */ +OPENSSL_EXPORT int CRYPTO_set_thread_local( + thread_local_data_t index, void *value, + thread_local_destructor_t destructor); + + +/* ex_data */ + +typedef struct crypto_ex_data_func_st CRYPTO_EX_DATA_FUNCS; + +/* CRYPTO_EX_DATA_CLASS tracks the ex_indices registered for a type which + * supports ex_data. It should defined as a static global within the module + * which defines that type. */ +typedef struct { + struct CRYPTO_STATIC_MUTEX lock; + STACK_OF(CRYPTO_EX_DATA_FUNCS) *meth; + /* num_reserved is one if the ex_data index zero is reserved for legacy + * |TYPE_get_app_data| functions. */ + uint8_t num_reserved; +} CRYPTO_EX_DATA_CLASS; + +#define CRYPTO_EX_DATA_CLASS_INIT {CRYPTO_STATIC_MUTEX_INIT, NULL, 0} +#define CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA \ + {CRYPTO_STATIC_MUTEX_INIT, NULL, 1} + +/* CRYPTO_get_ex_new_index allocates a new index for |ex_data_class| and writes + * it to |*out_index|. Each class of object should provide a wrapper function + * that uses the correct |CRYPTO_EX_DATA_CLASS|. It returns one on success and + * zero otherwise. */ +OPENSSL_EXPORT int CRYPTO_get_ex_new_index(CRYPTO_EX_DATA_CLASS *ex_data_class, + int *out_index, long argl, + void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); + +/* CRYPTO_set_ex_data sets an extra data pointer on a given object. Each class + * of object should provide a wrapper function. */ +OPENSSL_EXPORT int CRYPTO_set_ex_data(CRYPTO_EX_DATA *ad, int index, void *val); + +/* CRYPTO_get_ex_data returns an extra data pointer for a given object, or NULL + * if no such index exists. Each class of object should provide a wrapper + * function. */ +OPENSSL_EXPORT void *CRYPTO_get_ex_data(const CRYPTO_EX_DATA *ad, int index); + +/* CRYPTO_new_ex_data initialises a newly allocated |CRYPTO_EX_DATA| which is + * embedded inside of |obj| which is of class |ex_data_class|. Returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int CRYPTO_new_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, + void *obj, CRYPTO_EX_DATA *ad); + +/* CRYPTO_dup_ex_data duplicates |from| into a freshly allocated + * |CRYPTO_EX_DATA|, |to|. Both of which are inside objects of the given + * class. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int CRYPTO_dup_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, + CRYPTO_EX_DATA *to, + const CRYPTO_EX_DATA *from); + +/* CRYPTO_free_ex_data frees |ad|, which is embedded inside |obj|, which is an + * object of the given class. */ +OPENSSL_EXPORT void CRYPTO_free_ex_data(CRYPTO_EX_DATA_CLASS *ex_data_class, + void *obj, CRYPTO_EX_DATA *ad); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CRYPTO_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/lhash/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/lhash/CMakeLists.txt new file mode 100644 index 00000000..593da769 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/lhash/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + lhash + + OBJECT + + lhash.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/lhash/lhash.c b/TMessagesProj/jni/boringssl/crypto/lhash/lhash.c new file mode 100644 index 00000000..257900ea --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/lhash/lhash.c @@ -0,0 +1,346 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + +#include + +/* kMinNumBuckets is the minimum size of the buckets array in an |_LHASH|. */ +static const size_t kMinNumBuckets = 16; + +/* kMaxAverageChainLength contains the maximum, average chain length. When the + * average chain length exceeds this value, the hash table will be resized. */ +static const size_t kMaxAverageChainLength = 2; +static const size_t kMinAverageChainLength = 1; + +_LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp) { + _LHASH *ret; + + ret = OPENSSL_malloc(sizeof(_LHASH)); + if (ret == NULL) { + return NULL; + } + memset(ret, 0, sizeof(_LHASH)); + + ret->num_buckets = kMinNumBuckets; + ret->buckets = OPENSSL_malloc(sizeof(LHASH_ITEM *) * ret->num_buckets); + if (ret->buckets == NULL) { + OPENSSL_free(ret); + return NULL; + } + memset(ret->buckets, 0, sizeof(LHASH_ITEM *) * ret->num_buckets); + + ret->comp = comp; + if (ret->comp == NULL) { + ret->comp = (lhash_cmp_func) strcmp; + } + ret->hash = hash; + if (ret->hash == NULL) { + ret->hash = (lhash_hash_func) lh_strhash; + } + + return ret; +} + +void lh_free(_LHASH *lh) { + size_t i; + LHASH_ITEM *n, *next; + + if (lh == NULL) { + return; + } + + for (i = 0; i < lh->num_buckets; i++) { + for (n = lh->buckets[i]; n != NULL; n = next) { + next = n->next; + OPENSSL_free(n); + } + } + + OPENSSL_free(lh->buckets); + OPENSSL_free(lh); +} + +size_t lh_num_items(const _LHASH *lh) { return lh->num_items; } + +/* get_next_ptr_and_hash returns a pointer to the pointer that points to the + * item equal to |data|. In other words, it searches for an item equal to |data| + * and, if it's at the start of a chain, then it returns a pointer to an + * element of |lh->buckets|, otherwise it returns a pointer to the |next| + * element of the previous item in the chain. If an element equal to |data| is + * not found, it returns a pointer that points to a NULL pointer. If |out_hash| + * is not NULL, then it also puts the hash value of |data| in |*out_hash|. */ +static LHASH_ITEM **get_next_ptr_and_hash(const _LHASH *lh, uint32_t *out_hash, + const void *data) { + const uint32_t hash = lh->hash(data); + LHASH_ITEM *cur, **ret; + + if (out_hash != NULL) { + *out_hash = hash; + } + + ret = &lh->buckets[hash % lh->num_buckets]; + for (cur = *ret; cur != NULL; cur = *ret) { + if (lh->comp(cur->data, data) == 0) { + break; + } + ret = &cur->next; + } + + return ret; +} + +void *lh_retrieve(const _LHASH *lh, const void *data) { + LHASH_ITEM **next_ptr; + + next_ptr = get_next_ptr_and_hash(lh, NULL, data); + + if (*next_ptr == NULL) { + return NULL; + } + + return (*next_ptr)->data; +} + +/* lh_rebucket allocates a new array of |new_num_buckets| pointers and + * redistributes the existing items into it before making it |lh->buckets| and + * freeing the old array. */ +static void lh_rebucket(_LHASH *lh, const size_t new_num_buckets) { + LHASH_ITEM **new_buckets, *cur, *next; + size_t i, alloc_size; + + alloc_size = sizeof(LHASH_ITEM *) * new_num_buckets; + if (alloc_size / sizeof(LHASH_ITEM*) != new_num_buckets) { + return; + } + + new_buckets = OPENSSL_malloc(alloc_size); + if (new_buckets == NULL) { + return; + } + memset(new_buckets, 0, alloc_size); + + for (i = 0; i < lh->num_buckets; i++) { + for (cur = lh->buckets[i]; cur != NULL; cur = next) { + const size_t new_bucket = cur->hash % new_num_buckets; + next = cur->next; + cur->next = new_buckets[new_bucket]; + new_buckets[new_bucket] = cur; + } + } + + OPENSSL_free(lh->buckets); + + lh->num_buckets = new_num_buckets; + lh->buckets = new_buckets; +} + +/* lh_maybe_resize resizes the |buckets| array if needed. */ +static void lh_maybe_resize(_LHASH *lh) { + size_t avg_chain_length; + + if (lh->callback_depth > 0) { + /* Don't resize the hash if we are currently iterating over it. */ + return; + } + + assert(lh->num_buckets >= kMinNumBuckets); + avg_chain_length = lh->num_items / lh->num_buckets; + + if (avg_chain_length > kMaxAverageChainLength) { + const size_t new_num_buckets = lh->num_buckets * 2; + + if (new_num_buckets > lh->num_buckets) { + lh_rebucket(lh, new_num_buckets); + } + } else if (avg_chain_length < kMinAverageChainLength && + lh->num_buckets > kMinNumBuckets) { + size_t new_num_buckets = lh->num_buckets / 2; + + if (new_num_buckets < kMinNumBuckets) { + new_num_buckets = kMinNumBuckets; + } + + lh_rebucket(lh, new_num_buckets); + } +} + +int lh_insert(_LHASH *lh, void **old_data, void *data) { + uint32_t hash; + LHASH_ITEM **next_ptr, *item; + + *old_data = NULL; + next_ptr = get_next_ptr_and_hash(lh, &hash, data); + + + if (*next_ptr != NULL) { + /* An element equal to |data| already exists in the hash table. It will be + * replaced. */ + *old_data = (*next_ptr)->data; + (*next_ptr)->data = data; + return 1; + } + + /* An element equal to |data| doesn't exist in the hash table yet. */ + item = OPENSSL_malloc(sizeof(LHASH_ITEM)); + if (item == NULL) { + return 0; + } + + item->data = data; + item->hash = hash; + item->next = NULL; + *next_ptr = item; + lh->num_items++; + lh_maybe_resize(lh); + + return 1; +} + +void *lh_delete(_LHASH *lh, const void *data) { + LHASH_ITEM **next_ptr, *item, *ret; + + next_ptr = get_next_ptr_and_hash(lh, NULL, data); + + if (*next_ptr == NULL) { + /* No such element. */ + return NULL; + } + + item = *next_ptr; + *next_ptr = item->next; + ret = item->data; + OPENSSL_free(item); + + lh->num_items--; + lh_maybe_resize(lh); + + return ret; +} + +static void lh_doall_internal(_LHASH *lh, void (*no_arg_func)(void *), + void (*arg_func)(void *, void *), void *arg) { + size_t i; + LHASH_ITEM *cur, *next; + + if (lh == NULL) { + return; + } + + if (lh->callback_depth < UINT_MAX) { + /* |callback_depth| is a saturating counter. */ + lh->callback_depth++; + } + + for (i = 0; i < lh->num_buckets; i++) { + for (cur = lh->buckets[i]; cur != NULL; cur = next) { + next = cur->next; + if (arg_func) { + arg_func(cur->data, arg); + } else { + no_arg_func(cur->data); + } + } + } + + if (lh->callback_depth < UINT_MAX) { + lh->callback_depth--; + } + + /* The callback may have added or removed elements and the non-zero value of + * |callback_depth| will have suppressed any resizing. Thus any needed + * resizing is done here. */ + lh_maybe_resize(lh); +} + +void lh_doall(_LHASH *lh, void (*func)(void *)) { + lh_doall_internal(lh, func, NULL, NULL); +} + +void lh_doall_arg(_LHASH *lh, void (*func)(void *, void *), void *arg) { + lh_doall_internal(lh, NULL, func, arg); +} + +uint32_t lh_strhash(const char *c) { + /* The following hash seems to work very well on normal text strings + * no collisions on /usr/dict/words and it distributes on %2^n quite + * well, not as good as MD5, but still good. */ + unsigned long ret = 0; + long n; + unsigned long v; + int r; + + if ((c == NULL) || (*c == '\0')) { + return (ret); + } + + n = 0x100; + while (*c) { + v = n | (*c); + n += 0x100; + r = (int)((v >> 2) ^ v) & 0x0f; + ret = (ret << r) | (ret >> (32 - r)); + ret &= 0xFFFFFFFFL; + ret ^= v * v; + c++; + } + + return ((ret >> 16) ^ ret); +} diff --git a/TMessagesProj/jni/boringssl/crypto/lhash/make_macros.sh b/TMessagesProj/jni/boringssl/crypto/lhash/make_macros.sh new file mode 100644 index 00000000..8a876af3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/lhash/make_macros.sh @@ -0,0 +1,67 @@ +#!/bin/sh + +include_dir=../../include/openssl +out=${include_dir}/lhash_macros.h + +cat > $out << EOF +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#if !defined(IN_LHASH_H) +#error "Don't include this file directly. Include lhash.h" +#endif + +EOF + +output_lhash () { + type=$1 + + cat >> $out << EOF +/* ${type} */ +#define lh_${type}_new(hash, comp)\\ +((LHASH_OF(${type})*) lh_new(CHECKED_CAST(lhash_hash_func, uint32_t (*) (const ${type} *), hash), CHECKED_CAST(lhash_cmp_func, int (*) (const ${type} *a, const ${type} *b), comp))) + +#define lh_${type}_free(lh)\\ + lh_free(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh)); + +#define lh_${type}_num_items(lh)\\ + lh_num_items(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh)) + +#define lh_${type}_retrieve(lh, data)\\ + ((${type}*) lh_retrieve(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void*, ${type}*, data))) + +#define lh_${type}_insert(lh, old_data, data)\\ + lh_insert(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void**, ${type}**, old_data), CHECKED_CAST(void*, ${type}*, data)) + +#define lh_${type}_delete(lh, data)\\ + ((${type}*) lh_delete(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void*, ${type}*, data))) + +#define lh_${type}_doall(lh, func)\\ + lh_doall(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void (*)(void*), void (*) (${type}*), func)); + +#define lh_${type}_doall_arg(lh, func, arg)\\ + lh_doall_arg(CHECKED_CAST(_LHASH*, LHASH_OF(${type})*, lh), CHECKED_CAST(void (*)(void*, void*), void (*) (${type}*, void*), func), arg); + + +EOF +} + +lhash_types=$(cat ${include_dir}/lhash.h | grep '^ \* LHASH_OF:' | sed -e 's/.*LHASH_OF://' -e 's/ .*//') + +for type in $lhash_types; do + echo Hash of ${type} + output_lhash "${type}" +done + +clang-format -i $out diff --git a/TMessagesProj/jni/boringssl/crypto/md5/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/md5/CMakeLists.txt new file mode 100644 index 00000000..6c5e80f1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/md5/CMakeLists.txt @@ -0,0 +1,30 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "x86_64") + set( + MD5_ARCH_SOURCES + + md5-x86_64.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "x86") + set( + MD5_ARCH_SOURCES + + md5-586.${ASM_EXT} + ) +endif() + +add_library( + md5 + + OBJECT + + md5.c + + ${MD5_ARCH_SOURCES} +) + +perlasm(md5-x86_64.${ASM_EXT} asm/md5-x86_64.pl) +perlasm(md5-586.${ASM_EXT} asm/md5-586.pl) diff --git a/TMessagesProj/jni/boringssl/crypto/md5/asm/md5-586.pl b/TMessagesProj/jni/boringssl/crypto/md5/asm/md5-586.pl new file mode 100644 index 00000000..6cb66bb4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/md5/asm/md5-586.pl @@ -0,0 +1,307 @@ +#!/usr/local/bin/perl + +# Normal is the +# md5_block_x86(MD5_CTX *c, ULONG *X); +# version, non-normal is the +# md5_block_x86(MD5_CTX *c, ULONG *X,int blocks); + +$normal=0; + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],$0); + +$A="eax"; +$B="ebx"; +$C="ecx"; +$D="edx"; +$tmp1="edi"; +$tmp2="ebp"; +$X="esi"; + +# What we need to load into $tmp for the next round +%Ltmp1=("R0",&Np($C), "R1",&Np($C), "R2",&Np($C), "R3",&Np($D)); +@xo=( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, # R0 + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, # R1 + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, # R2 + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9, # R3 + ); + +&md5_block("md5_block_asm_data_order"); +&asm_finish(); + +sub Np + { + local($p)=@_; + local(%n)=($A,$D,$B,$A,$C,$B,$D,$C); + return($n{$p}); + } + +sub R0 + { + local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_; + + &mov($tmp1,$C) if $pos < 0; + &mov($tmp2,&DWP($xo[$ki]*4,$K,"",0)) if $pos < 0; # very first one + + # body proper + + &comment("R0 $ki"); + &xor($tmp1,$d); # F function - part 2 + + &and($tmp1,$b); # F function - part 3 + &lea($a,&DWP($t,$a,$tmp2,1)); + + &xor($tmp1,$d); # F function - part 4 + + &add($a,$tmp1); + &mov($tmp1,&Np($c)) if $pos < 1; # next tmp1 for R0 + &mov($tmp1,&Np($c)) if $pos == 1; # next tmp1 for R1 + + &rotl($a,$s); + + &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2); + + &add($a,$b); + } + +sub R1 + { + local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_; + + &comment("R1 $ki"); + + &lea($a,&DWP($t,$a,$tmp2,1)); + + &xor($tmp1,$b); # G function - part 2 + &and($tmp1,$d); # G function - part 3 + + &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2); + &xor($tmp1,$c); # G function - part 4 + + &add($a,$tmp1); + &mov($tmp1,&Np($c)) if $pos < 1; # G function - part 1 + &mov($tmp1,&Np($c)) if $pos == 1; # G function - part 1 + + &rotl($a,$s); + + &add($a,$b); + } + +sub R2 + { + local($n,$pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_; + # This one is different, only 3 logical operations + +if (($n & 1) == 0) + { + &comment("R2 $ki"); + # make sure to do 'D' first, not 'B', else we clash with + # the last add from the previous round. + + &xor($tmp1,$d); # H function - part 2 + + &xor($tmp1,$b); # H function - part 3 + &lea($a,&DWP($t,$a,$tmp2,1)); + + &add($a,$tmp1); + + &rotl($a,$s); + + &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)); + &mov($tmp1,&Np($c)); + } +else + { + &comment("R2 $ki"); + # make sure to do 'D' first, not 'B', else we clash with + # the last add from the previous round. + + &lea($a,&DWP($t,$a,$tmp2,1)); + + &add($b,$c); # MOVED FORWARD + &xor($tmp1,$d); # H function - part 2 + + &xor($tmp1,$b); # H function - part 3 + &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if ($pos != 2); + + &add($a,$tmp1); + &mov($tmp1,&Np($c)) if $pos < 1; # H function - part 1 + &mov($tmp1,-1) if $pos == 1; # I function - part 1 + + &rotl($a,$s); + + &add($a,$b); + } + } + +sub R3 + { + local($pos,$a,$b,$c,$d,$K,$ki,$s,$t)=@_; + + &comment("R3 $ki"); + + # ¬($tmp1) + &xor($tmp1,$d) if $pos < 0; # I function - part 2 + + &or($tmp1,$b); # I function - part 3 + &lea($a,&DWP($t,$a,$tmp2,1)); + + &xor($tmp1,$c); # I function - part 4 + &mov($tmp2,&DWP($xo[$ki+1]*4,$K,"",0)) if $pos != 2; # load X/k value + &mov($tmp2,&wparam(0)) if $pos == 2; + + &add($a,$tmp1); + &mov($tmp1,-1) if $pos < 1; # H function - part 1 + &add($K,64) if $pos >=1 && !$normal; + + &rotl($a,$s); + + &xor($tmp1,&Np($d)) if $pos <= 0; # I function - part = first time + &mov($tmp1,&DWP( 0,$tmp2,"",0)) if $pos > 0; + &add($a,$b); + } + + +sub md5_block + { + local($name)=@_; + + &function_begin_B($name,"",3); + + # parameter 1 is the MD5_CTX structure. + # A 0 + # B 4 + # C 8 + # D 12 + + &push("esi"); + &push("edi"); + &mov($tmp1, &wparam(0)); # edi + &mov($X, &wparam(1)); # esi + &mov($C, &wparam(2)); + &push("ebp"); + &shl($C, 6); + &push("ebx"); + &add($C, $X); # offset we end at + &sub($C, 64); + &mov($A, &DWP( 0,$tmp1,"",0)); + &push($C); # Put on the TOS + &mov($B, &DWP( 4,$tmp1,"",0)); + &mov($C, &DWP( 8,$tmp1,"",0)); + &mov($D, &DWP(12,$tmp1,"",0)); + + &set_label("start") unless $normal; + &comment(""); + &comment("R0 section"); + + &R0(-2,$A,$B,$C,$D,$X, 0, 7,0xd76aa478); + &R0( 0,$D,$A,$B,$C,$X, 1,12,0xe8c7b756); + &R0( 0,$C,$D,$A,$B,$X, 2,17,0x242070db); + &R0( 0,$B,$C,$D,$A,$X, 3,22,0xc1bdceee); + &R0( 0,$A,$B,$C,$D,$X, 4, 7,0xf57c0faf); + &R0( 0,$D,$A,$B,$C,$X, 5,12,0x4787c62a); + &R0( 0,$C,$D,$A,$B,$X, 6,17,0xa8304613); + &R0( 0,$B,$C,$D,$A,$X, 7,22,0xfd469501); + &R0( 0,$A,$B,$C,$D,$X, 8, 7,0x698098d8); + &R0( 0,$D,$A,$B,$C,$X, 9,12,0x8b44f7af); + &R0( 0,$C,$D,$A,$B,$X,10,17,0xffff5bb1); + &R0( 0,$B,$C,$D,$A,$X,11,22,0x895cd7be); + &R0( 0,$A,$B,$C,$D,$X,12, 7,0x6b901122); + &R0( 0,$D,$A,$B,$C,$X,13,12,0xfd987193); + &R0( 0,$C,$D,$A,$B,$X,14,17,0xa679438e); + &R0( 1,$B,$C,$D,$A,$X,15,22,0x49b40821); + + &comment(""); + &comment("R1 section"); + &R1(-1,$A,$B,$C,$D,$X,16, 5,0xf61e2562); + &R1( 0,$D,$A,$B,$C,$X,17, 9,0xc040b340); + &R1( 0,$C,$D,$A,$B,$X,18,14,0x265e5a51); + &R1( 0,$B,$C,$D,$A,$X,19,20,0xe9b6c7aa); + &R1( 0,$A,$B,$C,$D,$X,20, 5,0xd62f105d); + &R1( 0,$D,$A,$B,$C,$X,21, 9,0x02441453); + &R1( 0,$C,$D,$A,$B,$X,22,14,0xd8a1e681); + &R1( 0,$B,$C,$D,$A,$X,23,20,0xe7d3fbc8); + &R1( 0,$A,$B,$C,$D,$X,24, 5,0x21e1cde6); + &R1( 0,$D,$A,$B,$C,$X,25, 9,0xc33707d6); + &R1( 0,$C,$D,$A,$B,$X,26,14,0xf4d50d87); + &R1( 0,$B,$C,$D,$A,$X,27,20,0x455a14ed); + &R1( 0,$A,$B,$C,$D,$X,28, 5,0xa9e3e905); + &R1( 0,$D,$A,$B,$C,$X,29, 9,0xfcefa3f8); + &R1( 0,$C,$D,$A,$B,$X,30,14,0x676f02d9); + &R1( 1,$B,$C,$D,$A,$X,31,20,0x8d2a4c8a); + + &comment(""); + &comment("R2 section"); + &R2( 0,-1,$A,$B,$C,$D,$X,32, 4,0xfffa3942); + &R2( 1, 0,$D,$A,$B,$C,$X,33,11,0x8771f681); + &R2( 2, 0,$C,$D,$A,$B,$X,34,16,0x6d9d6122); + &R2( 3, 0,$B,$C,$D,$A,$X,35,23,0xfde5380c); + &R2( 4, 0,$A,$B,$C,$D,$X,36, 4,0xa4beea44); + &R2( 5, 0,$D,$A,$B,$C,$X,37,11,0x4bdecfa9); + &R2( 6, 0,$C,$D,$A,$B,$X,38,16,0xf6bb4b60); + &R2( 7, 0,$B,$C,$D,$A,$X,39,23,0xbebfbc70); + &R2( 8, 0,$A,$B,$C,$D,$X,40, 4,0x289b7ec6); + &R2( 9, 0,$D,$A,$B,$C,$X,41,11,0xeaa127fa); + &R2(10, 0,$C,$D,$A,$B,$X,42,16,0xd4ef3085); + &R2(11, 0,$B,$C,$D,$A,$X,43,23,0x04881d05); + &R2(12, 0,$A,$B,$C,$D,$X,44, 4,0xd9d4d039); + &R2(13, 0,$D,$A,$B,$C,$X,45,11,0xe6db99e5); + &R2(14, 0,$C,$D,$A,$B,$X,46,16,0x1fa27cf8); + &R2(15, 1,$B,$C,$D,$A,$X,47,23,0xc4ac5665); + + &comment(""); + &comment("R3 section"); + &R3(-1,$A,$B,$C,$D,$X,48, 6,0xf4292244); + &R3( 0,$D,$A,$B,$C,$X,49,10,0x432aff97); + &R3( 0,$C,$D,$A,$B,$X,50,15,0xab9423a7); + &R3( 0,$B,$C,$D,$A,$X,51,21,0xfc93a039); + &R3( 0,$A,$B,$C,$D,$X,52, 6,0x655b59c3); + &R3( 0,$D,$A,$B,$C,$X,53,10,0x8f0ccc92); + &R3( 0,$C,$D,$A,$B,$X,54,15,0xffeff47d); + &R3( 0,$B,$C,$D,$A,$X,55,21,0x85845dd1); + &R3( 0,$A,$B,$C,$D,$X,56, 6,0x6fa87e4f); + &R3( 0,$D,$A,$B,$C,$X,57,10,0xfe2ce6e0); + &R3( 0,$C,$D,$A,$B,$X,58,15,0xa3014314); + &R3( 0,$B,$C,$D,$A,$X,59,21,0x4e0811a1); + &R3( 0,$A,$B,$C,$D,$X,60, 6,0xf7537e82); + &R3( 0,$D,$A,$B,$C,$X,61,10,0xbd3af235); + &R3( 0,$C,$D,$A,$B,$X,62,15,0x2ad7d2bb); + &R3( 2,$B,$C,$D,$A,$X,63,21,0xeb86d391); + + # &mov($tmp2,&wparam(0)); # done in the last R3 + # &mov($tmp1, &DWP( 0,$tmp2,"",0)); # done is the last R3 + + &add($A,$tmp1); + &mov($tmp1, &DWP( 4,$tmp2,"",0)); + + &add($B,$tmp1); + &mov($tmp1, &DWP( 8,$tmp2,"",0)); + + &add($C,$tmp1); + &mov($tmp1, &DWP(12,$tmp2,"",0)); + + &add($D,$tmp1); + &mov(&DWP( 0,$tmp2,"",0),$A); + + &mov(&DWP( 4,$tmp2,"",0),$B); + &mov($tmp1,&swtmp(0)) unless $normal; + + &mov(&DWP( 8,$tmp2,"",0),$C); + &mov(&DWP(12,$tmp2,"",0),$D); + + &cmp($tmp1,$X) unless $normal; # check count + &jae(&label("start")) unless $normal; + + &pop("eax"); # pop the temp variable off the stack + &pop("ebx"); + &pop("ebp"); + &pop("edi"); + &pop("esi"); + &ret(); + &function_end_B($name); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/md5/asm/md5-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/md5/asm/md5-x86_64.pl new file mode 100644 index 00000000..77a6e01d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/md5/asm/md5-x86_64.pl @@ -0,0 +1,370 @@ +#!/usr/bin/perl -w +# +# MD5 optimized for AMD64. +# +# Author: Marc Bevand +# Licence: I hereby disclaim the copyright on this code and place it +# in the public domain. +# + +use strict; + +my $code; + +# round1_step() does: +# dst = x + ((dst + F(x,y,z) + X[k] + T_i) <<< s) +# %r10d = X[k_next] +# %r11d = z' (copy of z for the next step) +# Each round1_step() takes about 5.3 clocks (9 instructions, 1.7 IPC) +sub round1_step +{ + my ($pos, $dst, $x, $y, $z, $k_next, $T_i, $s) = @_; + $code .= " mov 0*4(%rsi), %r10d /* (NEXT STEP) X[0] */\n" if ($pos == -1); + $code .= " mov %edx, %r11d /* (NEXT STEP) z' = %edx */\n" if ($pos == -1); + $code .= <A + mov 1*4(%rbp), %ebx # ebx = ctx->B + mov 2*4(%rbp), %ecx # ecx = ctx->C + mov 3*4(%rbp), %edx # edx = ctx->D + # end is 'rdi' + # ptr is 'rsi' + # A is 'eax' + # B is 'ebx' + # C is 'ecx' + # D is 'edx' + + cmp %rdi, %rsi # cmp end with ptr + je .Lend # jmp if ptr == end + + # BEGIN of loop over 16-word blocks +.Lloop: # save old values of A, B, C, D + mov %eax, %r8d + mov %ebx, %r9d + mov %ecx, %r14d + mov %edx, %r15d +EOF +round1_step(-1,'%eax','%ebx','%ecx','%edx', '1','0xd76aa478', '7'); +round1_step( 0,'%edx','%eax','%ebx','%ecx', '2','0xe8c7b756','12'); +round1_step( 0,'%ecx','%edx','%eax','%ebx', '3','0x242070db','17'); +round1_step( 0,'%ebx','%ecx','%edx','%eax', '4','0xc1bdceee','22'); +round1_step( 0,'%eax','%ebx','%ecx','%edx', '5','0xf57c0faf', '7'); +round1_step( 0,'%edx','%eax','%ebx','%ecx', '6','0x4787c62a','12'); +round1_step( 0,'%ecx','%edx','%eax','%ebx', '7','0xa8304613','17'); +round1_step( 0,'%ebx','%ecx','%edx','%eax', '8','0xfd469501','22'); +round1_step( 0,'%eax','%ebx','%ecx','%edx', '9','0x698098d8', '7'); +round1_step( 0,'%edx','%eax','%ebx','%ecx','10','0x8b44f7af','12'); +round1_step( 0,'%ecx','%edx','%eax','%ebx','11','0xffff5bb1','17'); +round1_step( 0,'%ebx','%ecx','%edx','%eax','12','0x895cd7be','22'); +round1_step( 0,'%eax','%ebx','%ecx','%edx','13','0x6b901122', '7'); +round1_step( 0,'%edx','%eax','%ebx','%ecx','14','0xfd987193','12'); +round1_step( 0,'%ecx','%edx','%eax','%ebx','15','0xa679438e','17'); +round1_step( 1,'%ebx','%ecx','%edx','%eax', '0','0x49b40821','22'); + +round2_step(-1,'%eax','%ebx','%ecx','%edx', '6','0xf61e2562', '5'); +round2_step( 0,'%edx','%eax','%ebx','%ecx','11','0xc040b340', '9'); +round2_step( 0,'%ecx','%edx','%eax','%ebx', '0','0x265e5a51','14'); +round2_step( 0,'%ebx','%ecx','%edx','%eax', '5','0xe9b6c7aa','20'); +round2_step( 0,'%eax','%ebx','%ecx','%edx','10','0xd62f105d', '5'); +round2_step( 0,'%edx','%eax','%ebx','%ecx','15', '0x2441453', '9'); +round2_step( 0,'%ecx','%edx','%eax','%ebx', '4','0xd8a1e681','14'); +round2_step( 0,'%ebx','%ecx','%edx','%eax', '9','0xe7d3fbc8','20'); +round2_step( 0,'%eax','%ebx','%ecx','%edx','14','0x21e1cde6', '5'); +round2_step( 0,'%edx','%eax','%ebx','%ecx', '3','0xc33707d6', '9'); +round2_step( 0,'%ecx','%edx','%eax','%ebx', '8','0xf4d50d87','14'); +round2_step( 0,'%ebx','%ecx','%edx','%eax','13','0x455a14ed','20'); +round2_step( 0,'%eax','%ebx','%ecx','%edx', '2','0xa9e3e905', '5'); +round2_step( 0,'%edx','%eax','%ebx','%ecx', '7','0xfcefa3f8', '9'); +round2_step( 0,'%ecx','%edx','%eax','%ebx','12','0x676f02d9','14'); +round2_step( 1,'%ebx','%ecx','%edx','%eax', '0','0x8d2a4c8a','20'); + +round3_step(-1,'%eax','%ebx','%ecx','%edx', '8','0xfffa3942', '4'); +round3_step( 0,'%edx','%eax','%ebx','%ecx','11','0x8771f681','11'); +round3_step( 0,'%ecx','%edx','%eax','%ebx','14','0x6d9d6122','16'); +round3_step( 0,'%ebx','%ecx','%edx','%eax', '1','0xfde5380c','23'); +round3_step( 0,'%eax','%ebx','%ecx','%edx', '4','0xa4beea44', '4'); +round3_step( 0,'%edx','%eax','%ebx','%ecx', '7','0x4bdecfa9','11'); +round3_step( 0,'%ecx','%edx','%eax','%ebx','10','0xf6bb4b60','16'); +round3_step( 0,'%ebx','%ecx','%edx','%eax','13','0xbebfbc70','23'); +round3_step( 0,'%eax','%ebx','%ecx','%edx', '0','0x289b7ec6', '4'); +round3_step( 0,'%edx','%eax','%ebx','%ecx', '3','0xeaa127fa','11'); +round3_step( 0,'%ecx','%edx','%eax','%ebx', '6','0xd4ef3085','16'); +round3_step( 0,'%ebx','%ecx','%edx','%eax', '9', '0x4881d05','23'); +round3_step( 0,'%eax','%ebx','%ecx','%edx','12','0xd9d4d039', '4'); +round3_step( 0,'%edx','%eax','%ebx','%ecx','15','0xe6db99e5','11'); +round3_step( 0,'%ecx','%edx','%eax','%ebx', '2','0x1fa27cf8','16'); +round3_step( 1,'%ebx','%ecx','%edx','%eax', '0','0xc4ac5665','23'); + +round4_step(-1,'%eax','%ebx','%ecx','%edx', '7','0xf4292244', '6'); +round4_step( 0,'%edx','%eax','%ebx','%ecx','14','0x432aff97','10'); +round4_step( 0,'%ecx','%edx','%eax','%ebx', '5','0xab9423a7','15'); +round4_step( 0,'%ebx','%ecx','%edx','%eax','12','0xfc93a039','21'); +round4_step( 0,'%eax','%ebx','%ecx','%edx', '3','0x655b59c3', '6'); +round4_step( 0,'%edx','%eax','%ebx','%ecx','10','0x8f0ccc92','10'); +round4_step( 0,'%ecx','%edx','%eax','%ebx', '1','0xffeff47d','15'); +round4_step( 0,'%ebx','%ecx','%edx','%eax', '8','0x85845dd1','21'); +round4_step( 0,'%eax','%ebx','%ecx','%edx','15','0x6fa87e4f', '6'); +round4_step( 0,'%edx','%eax','%ebx','%ecx', '6','0xfe2ce6e0','10'); +round4_step( 0,'%ecx','%edx','%eax','%ebx','13','0xa3014314','15'); +round4_step( 0,'%ebx','%ecx','%edx','%eax', '4','0x4e0811a1','21'); +round4_step( 0,'%eax','%ebx','%ecx','%edx','11','0xf7537e82', '6'); +round4_step( 0,'%edx','%eax','%ebx','%ecx', '2','0xbd3af235','10'); +round4_step( 0,'%ecx','%edx','%eax','%ebx', '9','0x2ad7d2bb','15'); +round4_step( 1,'%ebx','%ecx','%edx','%eax', '0','0xeb86d391','21'); +$code .= <A = A + mov %ebx, 1*4(%rbp) # ctx->B = B + mov %ecx, 2*4(%rbp) # ctx->C = C + mov %edx, 3*4(%rbp) # ctx->D = D + + mov (%rsp),%r15 + mov 8(%rsp),%r14 + mov 16(%rsp),%r12 + mov 24(%rsp),%rbx + mov 32(%rsp),%rbp + add \$40,%rsp +.Lepilogue: + ret +.size md5_block_asm_data_order,.-md5_block_asm_data_order +EOF + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +my $rec="%rcx"; +my $frame="%rdx"; +my $context="%r8"; +my $disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + lea .Lprologue(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lprologue + jb .Lin_prologue + + mov 152($context),%rax # pull context->Rsp + + lea .Lepilogue(%rip),%r10 + cmp %r10,%rbx # context->Rip>=.Lepilogue + jae .Lin_prologue + + lea 40(%rax),%rax + + mov -8(%rax),%rbp + mov -16(%rax),%rbx + mov -24(%rax),%r12 + mov -32(%rax),%r14 + mov -40(%rax),%r15 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lin_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size se_handler,.-se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_md5_block_asm_data_order + .rva .LSEH_end_md5_block_asm_data_order + .rva .LSEH_info_md5_block_asm_data_order + +.section .xdata +.align 8 +.LSEH_info_md5_block_asm_data_order: + .byte 9,0,0,0 + .rva se_handler +___ +} + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/md5/md5.c b/TMessagesProj/jni/boringssl/crypto/md5/md5.c new file mode 100644 index 00000000..6ad8d128 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/md5/md5.c @@ -0,0 +1,275 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + + +uint8_t *MD5(const uint8_t *data, size_t len, uint8_t *out) { + MD5_CTX ctx; + static uint8_t digest[MD5_DIGEST_LENGTH]; + + /* TODO(fork): remove this static buffer. */ + if (out == NULL) { + out = digest; + } + + MD5_Init(&ctx); + MD5_Update(&ctx, data, len); + MD5_Final(out, &ctx); + + return out; +} + +int MD5_Init(MD5_CTX *md5) { + memset(md5, 0, sizeof(MD5_CTX)); + md5->A = 0x67452301UL; + md5->B = 0xefcdab89UL; + md5->C = 0x98badcfeUL; + md5->D = 0x10325476UL; + return 1; +} + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86_64) || defined(OPENSSL_X86)) +#define MD5_ASM +#define md5_block_data_order md5_block_asm_data_order +#endif + + +void md5_block_data_order(MD5_CTX *md5, const void *p, size_t num); + +#define DATA_ORDER_IS_LITTLE_ENDIAN + +#define HASH_LONG uint32_t +#define HASH_CTX MD5_CTX +#define HASH_CBLOCK 64 +#define HASH_UPDATE MD5_Update +#define HASH_TRANSFORM MD5_Transform +#define HASH_FINAL MD5_Final +#define HASH_MAKE_STRING(c, s) \ + do { \ + uint32_t ll; \ + ll = (c)->A; \ + (void) HOST_l2c(ll, (s)); \ + ll = (c)->B; \ + (void) HOST_l2c(ll, (s)); \ + ll = (c)->C; \ + (void) HOST_l2c(ll, (s)); \ + ll = (c)->D; \ + (void) HOST_l2c(ll, (s)); \ + } while (0) +#define HASH_BLOCK_DATA_ORDER md5_block_data_order + +#include "../digest/md32_common.h" + +/* As pointed out by Wei Dai , the above can be + * simplified to the code below. Wei attributes these optimizations + * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel. + */ +#define F(b,c,d) ((((c) ^ (d)) & (b)) ^ (d)) +#define G(b,c,d) ((((b) ^ (c)) & (d)) ^ (c)) +#define H(b,c,d) ((b) ^ (c) ^ (d)) +#define I(b,c,d) (((~(d)) | (b)) ^ (c)) + +#define R0(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+F((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; };\ + +#define R1(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+G((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; + +#define R2(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+H((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; + +#define R3(a,b,c,d,k,s,t) { \ + a+=((k)+(t)+I((b),(c),(d))); \ + a=ROTATE(a,s); \ + a+=b; }; + +#ifndef md5_block_data_order +#ifdef X +#undef X +#endif +void md5_block_data_order(MD5_CTX *md5, const void *in_data, size_t num) { + const uint8_t *data = in_data; + uint32_t A, B, C, D, l; + uint32_t XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7, XX8, XX9, XX10, XX11, XX12, + XX13, XX14, XX15; +#define X(i) XX##i + + A = md5->A; + B = md5->B; + C = md5->C; + D = md5->D; + + for (; num--;) { + HOST_c2l(data, l); + X(0) = l; + HOST_c2l(data, l); + X(1) = l; + /* Round 0 */ + R0(A, B, C, D, X(0), 7, 0xd76aa478L); + HOST_c2l(data, l); + X(2) = l; + R0(D, A, B, C, X(1), 12, 0xe8c7b756L); + HOST_c2l(data, l); + X(3) = l; + R0(C, D, A, B, X(2), 17, 0x242070dbL); + HOST_c2l(data, l); + X(4) = l; + R0(B, C, D, A, X(3), 22, 0xc1bdceeeL); + HOST_c2l(data, l); + X(5) = l; + R0(A, B, C, D, X(4), 7, 0xf57c0fafL); + HOST_c2l(data, l); + X(6) = l; + R0(D, A, B, C, X(5), 12, 0x4787c62aL); + HOST_c2l(data, l); + X(7) = l; + R0(C, D, A, B, X(6), 17, 0xa8304613L); + HOST_c2l(data, l); + X(8) = l; + R0(B, C, D, A, X(7), 22, 0xfd469501L); + HOST_c2l(data, l); + X(9) = l; + R0(A, B, C, D, X(8), 7, 0x698098d8L); + HOST_c2l(data, l); + X(10) = l; + R0(D, A, B, C, X(9), 12, 0x8b44f7afL); + HOST_c2l(data, l); + X(11) = l; + R0(C, D, A, B, X(10), 17, 0xffff5bb1L); + HOST_c2l(data, l); + X(12) = l; + R0(B, C, D, A, X(11), 22, 0x895cd7beL); + HOST_c2l(data, l); + X(13) = l; + R0(A, B, C, D, X(12), 7, 0x6b901122L); + HOST_c2l(data, l); + X(14) = l; + R0(D, A, B, C, X(13), 12, 0xfd987193L); + HOST_c2l(data, l); + X(15) = l; + R0(C, D, A, B, X(14), 17, 0xa679438eL); + R0(B, C, D, A, X(15), 22, 0x49b40821L); + /* Round 1 */ + R1(A, B, C, D, X(1), 5, 0xf61e2562L); + R1(D, A, B, C, X(6), 9, 0xc040b340L); + R1(C, D, A, B, X(11), 14, 0x265e5a51L); + R1(B, C, D, A, X(0), 20, 0xe9b6c7aaL); + R1(A, B, C, D, X(5), 5, 0xd62f105dL); + R1(D, A, B, C, X(10), 9, 0x02441453L); + R1(C, D, A, B, X(15), 14, 0xd8a1e681L); + R1(B, C, D, A, X(4), 20, 0xe7d3fbc8L); + R1(A, B, C, D, X(9), 5, 0x21e1cde6L); + R1(D, A, B, C, X(14), 9, 0xc33707d6L); + R1(C, D, A, B, X(3), 14, 0xf4d50d87L); + R1(B, C, D, A, X(8), 20, 0x455a14edL); + R1(A, B, C, D, X(13), 5, 0xa9e3e905L); + R1(D, A, B, C, X(2), 9, 0xfcefa3f8L); + R1(C, D, A, B, X(7), 14, 0x676f02d9L); + R1(B, C, D, A, X(12), 20, 0x8d2a4c8aL); + /* Round 2 */ + R2(A, B, C, D, X(5), 4, 0xfffa3942L); + R2(D, A, B, C, X(8), 11, 0x8771f681L); + R2(C, D, A, B, X(11), 16, 0x6d9d6122L); + R2(B, C, D, A, X(14), 23, 0xfde5380cL); + R2(A, B, C, D, X(1), 4, 0xa4beea44L); + R2(D, A, B, C, X(4), 11, 0x4bdecfa9L); + R2(C, D, A, B, X(7), 16, 0xf6bb4b60L); + R2(B, C, D, A, X(10), 23, 0xbebfbc70L); + R2(A, B, C, D, X(13), 4, 0x289b7ec6L); + R2(D, A, B, C, X(0), 11, 0xeaa127faL); + R2(C, D, A, B, X(3), 16, 0xd4ef3085L); + R2(B, C, D, A, X(6), 23, 0x04881d05L); + R2(A, B, C, D, X(9), 4, 0xd9d4d039L); + R2(D, A, B, C, X(12), 11, 0xe6db99e5L); + R2(C, D, A, B, X(15), 16, 0x1fa27cf8L); + R2(B, C, D, A, X(2), 23, 0xc4ac5665L); + /* Round 3 */ + R3(A, B, C, D, X(0), 6, 0xf4292244L); + R3(D, A, B, C, X(7), 10, 0x432aff97L); + R3(C, D, A, B, X(14), 15, 0xab9423a7L); + R3(B, C, D, A, X(5), 21, 0xfc93a039L); + R3(A, B, C, D, X(12), 6, 0x655b59c3L); + R3(D, A, B, C, X(3), 10, 0x8f0ccc92L); + R3(C, D, A, B, X(10), 15, 0xffeff47dL); + R3(B, C, D, A, X(1), 21, 0x85845dd1L); + R3(A, B, C, D, X(8), 6, 0x6fa87e4fL); + R3(D, A, B, C, X(15), 10, 0xfe2ce6e0L); + R3(C, D, A, B, X(6), 15, 0xa3014314L); + R3(B, C, D, A, X(13), 21, 0x4e0811a1L); + R3(A, B, C, D, X(4), 6, 0xf7537e82L); + R3(D, A, B, C, X(11), 10, 0xbd3af235L); + R3(C, D, A, B, X(2), 15, 0x2ad7d2bbL); + R3(B, C, D, A, X(9), 21, 0xeb86d391L); + + A = md5->A += A; + B = md5->B += B; + C = md5->C += C; + D = md5->D += D; + } +} +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/mem.c b/TMessagesProj/jni/boringssl/crypto/mem.c new file mode 100644 index 00000000..edd14a81 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/mem.c @@ -0,0 +1,200 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 201410L /* needed for strdup, snprintf, vprintf etc */ +#endif + +#include + +#include +#include +#include +#include + +#if defined(OPENSSL_WINDOWS) +#pragma warning(push, 3) +#include +#pragma warning(pop) +#else +#include +#endif + + +void *OPENSSL_realloc_clean(void *ptr, size_t old_size, size_t new_size) { + void *ret = NULL; + + if (ptr == NULL) { + return OPENSSL_malloc(new_size); + } + + if (new_size == 0) { + return NULL; + } + + /* We don't support shrinking the buffer. Note the memcpy that copies + * |old_size| bytes to the new buffer, below. */ + if (new_size < old_size) { + return NULL; + } + + ret = OPENSSL_malloc(new_size); + if (ret == NULL) { + return NULL; + } + + memcpy(ret, ptr, old_size); + OPENSSL_cleanse(ptr, old_size); + OPENSSL_free(ptr); + return ret; +} + +void OPENSSL_cleanse(void *ptr, size_t len) { +#if defined(OPENSSL_WINDOWS) + SecureZeroMemory(ptr, len); +#else + memset(ptr, 0, len); + +#if !defined(OPENSSL_NO_ASM) + /* As best as we can tell, this is sufficient to break any optimisations that + might try to eliminate "superfluous" memsets. If there's an easy way to + detect memset_s, it would be better to use that. */ + __asm__ __volatile__("" : : "r"(ptr) : "memory"); +#endif +#endif /* !OPENSSL_NO_ASM */ +} + +int CRYPTO_memcmp(const void *in_a, const void *in_b, size_t len) { + size_t i; + const uint8_t *a = in_a; + const uint8_t *b = in_b; + uint8_t x = 0; + + for (i = 0; i < len; i++) { + x |= a[i] ^ b[i]; + } + + return x; +} + +uint32_t OPENSSL_hash32(const void *ptr, size_t len) { + /* These are the FNV-1a parameters for 32 bits. */ + static const uint32_t kPrime = 16777619u; + static const uint32_t kOffsetBasis = 2166136261u; + + const uint8_t *in = ptr; + size_t i; + uint32_t h = kOffsetBasis; + + for (i = 0; i < len; i++) { + h ^= in[i]; + h *= kPrime; + } + + return h; +} + +char *OPENSSL_strdup(const char *s) { return strdup(s); } + +size_t OPENSSL_strnlen(const char *s, size_t len) { + size_t i; + + for (i = 0; i < len; i++) { + if (s[i] == 0) { + return i; + } + } + + return len; +} + +#if defined(OPENSSL_WINDOWS) + +int OPENSSL_strcasecmp(const char *a, const char *b) { + return _stricmp(a, b); +} + +int OPENSSL_strncasecmp(const char *a, const char *b, size_t n) { + return _strnicmp(a, b, n); +} + +#else + +int OPENSSL_strcasecmp(const char *a, const char *b) { + return strcasecmp(a, b); +} + +int OPENSSL_strncasecmp(const char *a, const char *b, size_t n) { + return strncasecmp(a, b, n); +} + +#endif + +int BIO_snprintf(char *buf, size_t n, const char *format, ...) { + va_list args; + int ret; + + va_start(args, format); + + ret = BIO_vsnprintf(buf, n, format, args); + + va_end(args); + return ret; +} + +int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) { + return vsnprintf(buf, n, format, args); +} diff --git a/TMessagesProj/jni/boringssl/crypto/modes/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/modes/CMakeLists.txt new file mode 100644 index 00000000..9145c5c0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/CMakeLists.txt @@ -0,0 +1,55 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "x86_64") + set( + MODES_ARCH_SOURCES + + aesni-gcm-x86_64.${ASM_EXT} + ghash-x86_64.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "x86") + set( + MODES_ARCH_SOURCES + + ghash-x86.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "arm") + set( + MODES_ARCH_SOURCES + + ghash-armv4.${ASM_EXT} + ghashv8-armx.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "aarch64") + set( + MODES_ARCH_SOURCES + + ghashv8-armx.${ASM_EXT} + ) +endif() + +add_library( + modes + + OBJECT + + cbc.c + ctr.c + ofb.c + cfb.c + gcm.c + + ${MODES_ARCH_SOURCES} +) + +perlasm(aesni-gcm-x86_64.${ASM_EXT} asm/aesni-gcm-x86_64.pl) +perlasm(ghash-x86_64.${ASM_EXT} asm/ghash-x86_64.pl) +perlasm(ghash-x86.${ASM_EXT} asm/ghash-x86.pl) +perlasm(ghash-armv4.${ASM_EXT} asm/ghash-armv4.pl) +perlasm(ghashv8-armx.${ASM_EXT} asm/ghashv8-armx.pl) diff --git a/TMessagesProj/jni/boringssl/crypto/modes/asm/aesni-gcm-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/modes/asm/aesni-gcm-x86_64.pl new file mode 100644 index 00000000..7e4e04ea --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/asm/aesni-gcm-x86_64.pl @@ -0,0 +1,1057 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# +# AES-NI-CTR+GHASH stitch. +# +# February 2013 +# +# OpenSSL GCM implementation is organized in such way that its +# performance is rather close to the sum of its streamed components, +# in the context parallelized AES-NI CTR and modulo-scheduled +# PCLMULQDQ-enabled GHASH. Unfortunately, as no stitch implementation +# was observed to perform significantly better than the sum of the +# components on contemporary CPUs, the effort was deemed impossible to +# justify. This module is based on combination of Intel submissions, +# [1] and [2], with MOVBE twist suggested by Ilya Albrekht and Max +# Locktyukhin of Intel Corp. who verified that it reduces shuffles +# pressure with notable relative improvement, achieving 1.0 cycle per +# byte processed with 128-bit key on Haswell processor, and 0.74 - +# on Broadwell. [Mentioned results are raw profiled measurements for +# favourable packet size, one divisible by 96. Applications using the +# EVP interface will observe a few percent worse performance.] +# +# [1] http://rt.openssl.org/Ticket/Display.html?id=2900&user=guest&pass=guest +# [2] http://www.intel.com/content/dam/www/public/us/en/documents/software-support/enabling-high-performance-gcm.pdf + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.19) + ($1>=2.22); +} + +if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.09) + ($1>=2.10); +} + +if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $avx = ($1>=10) + ($1>=11); +} + +if (!$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/) { + $avx = ($2>=3.0) + ($2>3.0); +} + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +if ($avx>1) {{{ + +($inp,$out,$len,$key,$ivp,$Xip)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9"); + +($Ii,$T1,$T2,$Hkey, + $Z0,$Z1,$Z2,$Z3,$Xi) = map("%xmm$_",(0..8)); + +($inout0,$inout1,$inout2,$inout3,$inout4,$inout5,$rndkey) = map("%xmm$_",(9..15)); + +($counter,$rounds,$ret,$const,$in0,$end0)=("%ebx","%ebp","%r10","%r11","%r14","%r15"); + +$code=<<___; +.text + +.type _aesni_ctr32_ghash_6x,\@abi-omnipotent +.align 32 +_aesni_ctr32_ghash_6x: + vmovdqu 0x20($const),$T2 # borrow $T2, .Lone_msb + sub \$6,$len + vpxor $Z0,$Z0,$Z0 # $Z0 = 0 + vmovdqu 0x00-0x80($key),$rndkey + vpaddb $T2,$T1,$inout1 + vpaddb $T2,$inout1,$inout2 + vpaddb $T2,$inout2,$inout3 + vpaddb $T2,$inout3,$inout4 + vpaddb $T2,$inout4,$inout5 + vpxor $rndkey,$T1,$inout0 + vmovdqu $Z0,16+8(%rsp) # "$Z3" = 0 + jmp .Loop6x + +.align 32 +.Loop6x: + add \$`6<<24`,$counter + jc .Lhandle_ctr32 # discard $inout[1-5]? + vmovdqu 0x00-0x20($Xip),$Hkey # $Hkey^1 + vpaddb $T2,$inout5,$T1 # next counter value + vpxor $rndkey,$inout1,$inout1 + vpxor $rndkey,$inout2,$inout2 + +.Lresume_ctr32: + vmovdqu $T1,($ivp) # save next counter value + vpclmulqdq \$0x10,$Hkey,$Z3,$Z1 + vpxor $rndkey,$inout3,$inout3 + vmovups 0x10-0x80($key),$T2 # borrow $T2 for $rndkey + vpclmulqdq \$0x01,$Hkey,$Z3,$Z2 + xor %r12,%r12 + cmp $in0,$end0 + + vaesenc $T2,$inout0,$inout0 + vmovdqu 0x30+8(%rsp),$Ii # I[4] + vpxor $rndkey,$inout4,$inout4 + vpclmulqdq \$0x00,$Hkey,$Z3,$T1 + vaesenc $T2,$inout1,$inout1 + vpxor $rndkey,$inout5,$inout5 + setnc %r12b + vpclmulqdq \$0x11,$Hkey,$Z3,$Z3 + vaesenc $T2,$inout2,$inout2 + vmovdqu 0x10-0x20($Xip),$Hkey # $Hkey^2 + neg %r12 + vaesenc $T2,$inout3,$inout3 + vpxor $Z1,$Z2,$Z2 + vpclmulqdq \$0x00,$Hkey,$Ii,$Z1 + vpxor $Z0,$Xi,$Xi # modulo-scheduled + vaesenc $T2,$inout4,$inout4 + vpxor $Z1,$T1,$Z0 + and \$0x60,%r12 + vmovups 0x20-0x80($key),$rndkey + vpclmulqdq \$0x10,$Hkey,$Ii,$T1 + vaesenc $T2,$inout5,$inout5 + + vpclmulqdq \$0x01,$Hkey,$Ii,$T2 + lea ($in0,%r12),$in0 + vaesenc $rndkey,$inout0,$inout0 + vpxor 16+8(%rsp),$Xi,$Xi # modulo-scheduled [vpxor $Z3,$Xi,$Xi] + vpclmulqdq \$0x11,$Hkey,$Ii,$Hkey + vmovdqu 0x40+8(%rsp),$Ii # I[3] + vaesenc $rndkey,$inout1,$inout1 + movbe 0x58($in0),%r13 + vaesenc $rndkey,$inout2,$inout2 + movbe 0x50($in0),%r12 + vaesenc $rndkey,$inout3,$inout3 + mov %r13,0x20+8(%rsp) + vaesenc $rndkey,$inout4,$inout4 + mov %r12,0x28+8(%rsp) + vmovdqu 0x30-0x20($Xip),$Z1 # borrow $Z1 for $Hkey^3 + vaesenc $rndkey,$inout5,$inout5 + + vmovups 0x30-0x80($key),$rndkey + vpxor $T1,$Z2,$Z2 + vpclmulqdq \$0x00,$Z1,$Ii,$T1 + vaesenc $rndkey,$inout0,$inout0 + vpxor $T2,$Z2,$Z2 + vpclmulqdq \$0x10,$Z1,$Ii,$T2 + vaesenc $rndkey,$inout1,$inout1 + vpxor $Hkey,$Z3,$Z3 + vpclmulqdq \$0x01,$Z1,$Ii,$Hkey + vaesenc $rndkey,$inout2,$inout2 + vpclmulqdq \$0x11,$Z1,$Ii,$Z1 + vmovdqu 0x50+8(%rsp),$Ii # I[2] + vaesenc $rndkey,$inout3,$inout3 + vaesenc $rndkey,$inout4,$inout4 + vpxor $T1,$Z0,$Z0 + vmovdqu 0x40-0x20($Xip),$T1 # borrow $T1 for $Hkey^4 + vaesenc $rndkey,$inout5,$inout5 + + vmovups 0x40-0x80($key),$rndkey + vpxor $T2,$Z2,$Z2 + vpclmulqdq \$0x00,$T1,$Ii,$T2 + vaesenc $rndkey,$inout0,$inout0 + vpxor $Hkey,$Z2,$Z2 + vpclmulqdq \$0x10,$T1,$Ii,$Hkey + vaesenc $rndkey,$inout1,$inout1 + movbe 0x48($in0),%r13 + vpxor $Z1,$Z3,$Z3 + vpclmulqdq \$0x01,$T1,$Ii,$Z1 + vaesenc $rndkey,$inout2,$inout2 + movbe 0x40($in0),%r12 + vpclmulqdq \$0x11,$T1,$Ii,$T1 + vmovdqu 0x60+8(%rsp),$Ii # I[1] + vaesenc $rndkey,$inout3,$inout3 + mov %r13,0x30+8(%rsp) + vaesenc $rndkey,$inout4,$inout4 + mov %r12,0x38+8(%rsp) + vpxor $T2,$Z0,$Z0 + vmovdqu 0x60-0x20($Xip),$T2 # borrow $T2 for $Hkey^5 + vaesenc $rndkey,$inout5,$inout5 + + vmovups 0x50-0x80($key),$rndkey + vpxor $Hkey,$Z2,$Z2 + vpclmulqdq \$0x00,$T2,$Ii,$Hkey + vaesenc $rndkey,$inout0,$inout0 + vpxor $Z1,$Z2,$Z2 + vpclmulqdq \$0x10,$T2,$Ii,$Z1 + vaesenc $rndkey,$inout1,$inout1 + movbe 0x38($in0),%r13 + vpxor $T1,$Z3,$Z3 + vpclmulqdq \$0x01,$T2,$Ii,$T1 + vpxor 0x70+8(%rsp),$Xi,$Xi # accumulate I[0] + vaesenc $rndkey,$inout2,$inout2 + movbe 0x30($in0),%r12 + vpclmulqdq \$0x11,$T2,$Ii,$T2 + vaesenc $rndkey,$inout3,$inout3 + mov %r13,0x40+8(%rsp) + vaesenc $rndkey,$inout4,$inout4 + mov %r12,0x48+8(%rsp) + vpxor $Hkey,$Z0,$Z0 + vmovdqu 0x70-0x20($Xip),$Hkey # $Hkey^6 + vaesenc $rndkey,$inout5,$inout5 + + vmovups 0x60-0x80($key),$rndkey + vpxor $Z1,$Z2,$Z2 + vpclmulqdq \$0x10,$Hkey,$Xi,$Z1 + vaesenc $rndkey,$inout0,$inout0 + vpxor $T1,$Z2,$Z2 + vpclmulqdq \$0x01,$Hkey,$Xi,$T1 + vaesenc $rndkey,$inout1,$inout1 + movbe 0x28($in0),%r13 + vpxor $T2,$Z3,$Z3 + vpclmulqdq \$0x00,$Hkey,$Xi,$T2 + vaesenc $rndkey,$inout2,$inout2 + movbe 0x20($in0),%r12 + vpclmulqdq \$0x11,$Hkey,$Xi,$Xi + vaesenc $rndkey,$inout3,$inout3 + mov %r13,0x50+8(%rsp) + vaesenc $rndkey,$inout4,$inout4 + mov %r12,0x58+8(%rsp) + vpxor $Z1,$Z2,$Z2 + vaesenc $rndkey,$inout5,$inout5 + vpxor $T1,$Z2,$Z2 + + vmovups 0x70-0x80($key),$rndkey + vpslldq \$8,$Z2,$Z1 + vpxor $T2,$Z0,$Z0 + vmovdqu 0x10($const),$Hkey # .Lpoly + + vaesenc $rndkey,$inout0,$inout0 + vpxor $Xi,$Z3,$Z3 + vaesenc $rndkey,$inout1,$inout1 + vpxor $Z1,$Z0,$Z0 + movbe 0x18($in0),%r13 + vaesenc $rndkey,$inout2,$inout2 + movbe 0x10($in0),%r12 + vpalignr \$8,$Z0,$Z0,$Ii # 1st phase + vpclmulqdq \$0x10,$Hkey,$Z0,$Z0 + mov %r13,0x60+8(%rsp) + vaesenc $rndkey,$inout3,$inout3 + mov %r12,0x68+8(%rsp) + vaesenc $rndkey,$inout4,$inout4 + vmovups 0x80-0x80($key),$T1 # borrow $T1 for $rndkey + vaesenc $rndkey,$inout5,$inout5 + + vaesenc $T1,$inout0,$inout0 + vmovups 0x90-0x80($key),$rndkey + vaesenc $T1,$inout1,$inout1 + vpsrldq \$8,$Z2,$Z2 + vaesenc $T1,$inout2,$inout2 + vpxor $Z2,$Z3,$Z3 + vaesenc $T1,$inout3,$inout3 + vpxor $Ii,$Z0,$Z0 + movbe 0x08($in0),%r13 + vaesenc $T1,$inout4,$inout4 + movbe 0x00($in0),%r12 + vaesenc $T1,$inout5,$inout5 + vmovups 0xa0-0x80($key),$T1 + cmp \$11,$rounds + jb .Lenc_tail # 128-bit key + + vaesenc $rndkey,$inout0,$inout0 + vaesenc $rndkey,$inout1,$inout1 + vaesenc $rndkey,$inout2,$inout2 + vaesenc $rndkey,$inout3,$inout3 + vaesenc $rndkey,$inout4,$inout4 + vaesenc $rndkey,$inout5,$inout5 + + vaesenc $T1,$inout0,$inout0 + vaesenc $T1,$inout1,$inout1 + vaesenc $T1,$inout2,$inout2 + vaesenc $T1,$inout3,$inout3 + vaesenc $T1,$inout4,$inout4 + vmovups 0xb0-0x80($key),$rndkey + vaesenc $T1,$inout5,$inout5 + vmovups 0xc0-0x80($key),$T1 + je .Lenc_tail # 192-bit key + + vaesenc $rndkey,$inout0,$inout0 + vaesenc $rndkey,$inout1,$inout1 + vaesenc $rndkey,$inout2,$inout2 + vaesenc $rndkey,$inout3,$inout3 + vaesenc $rndkey,$inout4,$inout4 + vaesenc $rndkey,$inout5,$inout5 + + vaesenc $T1,$inout0,$inout0 + vaesenc $T1,$inout1,$inout1 + vaesenc $T1,$inout2,$inout2 + vaesenc $T1,$inout3,$inout3 + vaesenc $T1,$inout4,$inout4 + vmovups 0xd0-0x80($key),$rndkey + vaesenc $T1,$inout5,$inout5 + vmovups 0xe0-0x80($key),$T1 + jmp .Lenc_tail # 256-bit key + +.align 32 +.Lhandle_ctr32: + vmovdqu ($const),$Ii # borrow $Ii for .Lbswap_mask + vpshufb $Ii,$T1,$Z2 # byte-swap counter + vmovdqu 0x30($const),$Z1 # borrow $Z1, .Ltwo_lsb + vpaddd 0x40($const),$Z2,$inout1 # .Lone_lsb + vpaddd $Z1,$Z2,$inout2 + vmovdqu 0x00-0x20($Xip),$Hkey # $Hkey^1 + vpaddd $Z1,$inout1,$inout3 + vpshufb $Ii,$inout1,$inout1 + vpaddd $Z1,$inout2,$inout4 + vpshufb $Ii,$inout2,$inout2 + vpxor $rndkey,$inout1,$inout1 + vpaddd $Z1,$inout3,$inout5 + vpshufb $Ii,$inout3,$inout3 + vpxor $rndkey,$inout2,$inout2 + vpaddd $Z1,$inout4,$T1 # byte-swapped next counter value + vpshufb $Ii,$inout4,$inout4 + vpshufb $Ii,$inout5,$inout5 + vpshufb $Ii,$T1,$T1 # next counter value + jmp .Lresume_ctr32 + +.align 32 +.Lenc_tail: + vaesenc $rndkey,$inout0,$inout0 + vmovdqu $Z3,16+8(%rsp) # postpone vpxor $Z3,$Xi,$Xi + vpalignr \$8,$Z0,$Z0,$Xi # 2nd phase + vaesenc $rndkey,$inout1,$inout1 + vpclmulqdq \$0x10,$Hkey,$Z0,$Z0 + vpxor 0x00($inp),$T1,$T2 + vaesenc $rndkey,$inout2,$inout2 + vpxor 0x10($inp),$T1,$Ii + vaesenc $rndkey,$inout3,$inout3 + vpxor 0x20($inp),$T1,$Z1 + vaesenc $rndkey,$inout4,$inout4 + vpxor 0x30($inp),$T1,$Z2 + vaesenc $rndkey,$inout5,$inout5 + vpxor 0x40($inp),$T1,$Z3 + vpxor 0x50($inp),$T1,$Hkey + vmovdqu ($ivp),$T1 # load next counter value + + vaesenclast $T2,$inout0,$inout0 + vmovdqu 0x20($const),$T2 # borrow $T2, .Lone_msb + vaesenclast $Ii,$inout1,$inout1 + vpaddb $T2,$T1,$Ii + mov %r13,0x70+8(%rsp) + lea 0x60($inp),$inp + vaesenclast $Z1,$inout2,$inout2 + vpaddb $T2,$Ii,$Z1 + mov %r12,0x78+8(%rsp) + lea 0x60($out),$out + vmovdqu 0x00-0x80($key),$rndkey + vaesenclast $Z2,$inout3,$inout3 + vpaddb $T2,$Z1,$Z2 + vaesenclast $Z3, $inout4,$inout4 + vpaddb $T2,$Z2,$Z3 + vaesenclast $Hkey,$inout5,$inout5 + vpaddb $T2,$Z3,$Hkey + + add \$0x60,$ret + sub \$0x6,$len + jc .L6x_done + + vmovups $inout0,-0x60($out) # save output + vpxor $rndkey,$T1,$inout0 + vmovups $inout1,-0x50($out) + vmovdqa $Ii,$inout1 # 0 latency + vmovups $inout2,-0x40($out) + vmovdqa $Z1,$inout2 # 0 latency + vmovups $inout3,-0x30($out) + vmovdqa $Z2,$inout3 # 0 latency + vmovups $inout4,-0x20($out) + vmovdqa $Z3,$inout4 # 0 latency + vmovups $inout5,-0x10($out) + vmovdqa $Hkey,$inout5 # 0 latency + vmovdqu 0x20+8(%rsp),$Z3 # I[5] + jmp .Loop6x + +.L6x_done: + vpxor 16+8(%rsp),$Xi,$Xi # modulo-scheduled + vpxor $Z0,$Xi,$Xi # modulo-scheduled + + ret +.size _aesni_ctr32_ghash_6x,.-_aesni_ctr32_ghash_6x +___ +###################################################################### +# +# size_t aesni_gcm_[en|de]crypt(const void *inp, void *out, size_t len, +# const AES_KEY *key, unsigned char iv[16], +# struct { u128 Xi,H,Htbl[9]; } *Xip); +$code.=<<___; +.globl aesni_gcm_decrypt +.type aesni_gcm_decrypt,\@function,6 +.align 32 +aesni_gcm_decrypt: + xor $ret,$ret + cmp \$0x60,$len # minimal accepted length + jb .Lgcm_dec_abort + + lea (%rsp),%rax # save stack pointer + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0xa8(%rsp),%rsp + movaps %xmm6,-0xd8(%rax) + movaps %xmm7,-0xc8(%rax) + movaps %xmm8,-0xb8(%rax) + movaps %xmm9,-0xa8(%rax) + movaps %xmm10,-0x98(%rax) + movaps %xmm11,-0x88(%rax) + movaps %xmm12,-0x78(%rax) + movaps %xmm13,-0x68(%rax) + movaps %xmm14,-0x58(%rax) + movaps %xmm15,-0x48(%rax) +.Lgcm_dec_body: +___ +$code.=<<___; + vzeroupper + + vmovdqu ($ivp),$T1 # input counter value + add \$-128,%rsp + mov 12($ivp),$counter + lea .Lbswap_mask(%rip),$const + lea -0x80($key),$in0 # borrow $in0 + mov \$0xf80,$end0 # borrow $end0 + vmovdqu ($Xip),$Xi # load Xi + and \$-128,%rsp # ensure stack alignment + vmovdqu ($const),$Ii # borrow $Ii for .Lbswap_mask + lea 0x80($key),$key # size optimization + lea 0x20+0x20($Xip),$Xip # size optimization + mov 0xf0-0x80($key),$rounds + vpshufb $Ii,$Xi,$Xi + + and $end0,$in0 + and %rsp,$end0 + sub $in0,$end0 + jc .Ldec_no_key_aliasing + cmp \$768,$end0 + jnc .Ldec_no_key_aliasing + sub $end0,%rsp # avoid aliasing with key +.Ldec_no_key_aliasing: + + vmovdqu 0x50($inp),$Z3 # I[5] + lea ($inp),$in0 + vmovdqu 0x40($inp),$Z0 + lea -0xc0($inp,$len),$end0 + vmovdqu 0x30($inp),$Z1 + shr \$4,$len + xor $ret,$ret + vmovdqu 0x20($inp),$Z2 + vpshufb $Ii,$Z3,$Z3 # passed to _aesni_ctr32_ghash_6x + vmovdqu 0x10($inp),$T2 + vpshufb $Ii,$Z0,$Z0 + vmovdqu ($inp),$Hkey + vpshufb $Ii,$Z1,$Z1 + vmovdqu $Z0,0x30(%rsp) + vpshufb $Ii,$Z2,$Z2 + vmovdqu $Z1,0x40(%rsp) + vpshufb $Ii,$T2,$T2 + vmovdqu $Z2,0x50(%rsp) + vpshufb $Ii,$Hkey,$Hkey + vmovdqu $T2,0x60(%rsp) + vmovdqu $Hkey,0x70(%rsp) + + call _aesni_ctr32_ghash_6x + + vmovups $inout0,-0x60($out) # save output + vmovups $inout1,-0x50($out) + vmovups $inout2,-0x40($out) + vmovups $inout3,-0x30($out) + vmovups $inout4,-0x20($out) + vmovups $inout5,-0x10($out) + + vpshufb ($const),$Xi,$Xi # .Lbswap_mask + vmovdqu $Xi,-0x40($Xip) # output Xi + + vzeroupper +___ +$code.=<<___ if ($win64); + movaps -0xd8(%rax),%xmm6 + movaps -0xd8(%rax),%xmm7 + movaps -0xb8(%rax),%xmm8 + movaps -0xa8(%rax),%xmm9 + movaps -0x98(%rax),%xmm10 + movaps -0x88(%rax),%xmm11 + movaps -0x78(%rax),%xmm12 + movaps -0x68(%rax),%xmm13 + movaps -0x58(%rax),%xmm14 + movaps -0x48(%rax),%xmm15 +___ +$code.=<<___; + mov -48(%rax),%r15 + mov -40(%rax),%r14 + mov -32(%rax),%r13 + mov -24(%rax),%r12 + mov -16(%rax),%rbp + mov -8(%rax),%rbx + lea (%rax),%rsp # restore %rsp +.Lgcm_dec_abort: + mov $ret,%rax # return value + ret +.size aesni_gcm_decrypt,.-aesni_gcm_decrypt +___ + +$code.=<<___; +.type _aesni_ctr32_6x,\@abi-omnipotent +.align 32 +_aesni_ctr32_6x: + vmovdqu 0x00-0x80($key),$Z0 # borrow $Z0 for $rndkey + vmovdqu 0x20($const),$T2 # borrow $T2, .Lone_msb + lea -1($rounds),%r13 + vmovups 0x10-0x80($key),$rndkey + lea 0x20-0x80($key),%r12 + vpxor $Z0,$T1,$inout0 + add \$`6<<24`,$counter + jc .Lhandle_ctr32_2 + vpaddb $T2,$T1,$inout1 + vpaddb $T2,$inout1,$inout2 + vpxor $Z0,$inout1,$inout1 + vpaddb $T2,$inout2,$inout3 + vpxor $Z0,$inout2,$inout2 + vpaddb $T2,$inout3,$inout4 + vpxor $Z0,$inout3,$inout3 + vpaddb $T2,$inout4,$inout5 + vpxor $Z0,$inout4,$inout4 + vpaddb $T2,$inout5,$T1 + vpxor $Z0,$inout5,$inout5 + jmp .Loop_ctr32 + +.align 16 +.Loop_ctr32: + vaesenc $rndkey,$inout0,$inout0 + vaesenc $rndkey,$inout1,$inout1 + vaesenc $rndkey,$inout2,$inout2 + vaesenc $rndkey,$inout3,$inout3 + vaesenc $rndkey,$inout4,$inout4 + vaesenc $rndkey,$inout5,$inout5 + vmovups (%r12),$rndkey + lea 0x10(%r12),%r12 + dec %r13d + jnz .Loop_ctr32 + + vmovdqu (%r12),$Hkey # last round key + vaesenc $rndkey,$inout0,$inout0 + vpxor 0x00($inp),$Hkey,$Z0 + vaesenc $rndkey,$inout1,$inout1 + vpxor 0x10($inp),$Hkey,$Z1 + vaesenc $rndkey,$inout2,$inout2 + vpxor 0x20($inp),$Hkey,$Z2 + vaesenc $rndkey,$inout3,$inout3 + vpxor 0x30($inp),$Hkey,$Xi + vaesenc $rndkey,$inout4,$inout4 + vpxor 0x40($inp),$Hkey,$T2 + vaesenc $rndkey,$inout5,$inout5 + vpxor 0x50($inp),$Hkey,$Hkey + lea 0x60($inp),$inp + + vaesenclast $Z0,$inout0,$inout0 + vaesenclast $Z1,$inout1,$inout1 + vaesenclast $Z2,$inout2,$inout2 + vaesenclast $Xi,$inout3,$inout3 + vaesenclast $T2,$inout4,$inout4 + vaesenclast $Hkey,$inout5,$inout5 + vmovups $inout0,0x00($out) + vmovups $inout1,0x10($out) + vmovups $inout2,0x20($out) + vmovups $inout3,0x30($out) + vmovups $inout4,0x40($out) + vmovups $inout5,0x50($out) + lea 0x60($out),$out + + ret +.align 32 +.Lhandle_ctr32_2: + vpshufb $Ii,$T1,$Z2 # byte-swap counter + vmovdqu 0x30($const),$Z1 # borrow $Z1, .Ltwo_lsb + vpaddd 0x40($const),$Z2,$inout1 # .Lone_lsb + vpaddd $Z1,$Z2,$inout2 + vpaddd $Z1,$inout1,$inout3 + vpshufb $Ii,$inout1,$inout1 + vpaddd $Z1,$inout2,$inout4 + vpshufb $Ii,$inout2,$inout2 + vpxor $Z0,$inout1,$inout1 + vpaddd $Z1,$inout3,$inout5 + vpshufb $Ii,$inout3,$inout3 + vpxor $Z0,$inout2,$inout2 + vpaddd $Z1,$inout4,$T1 # byte-swapped next counter value + vpshufb $Ii,$inout4,$inout4 + vpxor $Z0,$inout3,$inout3 + vpshufb $Ii,$inout5,$inout5 + vpxor $Z0,$inout4,$inout4 + vpshufb $Ii,$T1,$T1 # next counter value + vpxor $Z0,$inout5,$inout5 + jmp .Loop_ctr32 +.size _aesni_ctr32_6x,.-_aesni_ctr32_6x + +.globl aesni_gcm_encrypt +.type aesni_gcm_encrypt,\@function,6 +.align 32 +aesni_gcm_encrypt: + xor $ret,$ret + cmp \$0x60*3,$len # minimal accepted length + jb .Lgcm_enc_abort + + lea (%rsp),%rax # save stack pointer + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 +___ +$code.=<<___ if ($win64); + lea -0xa8(%rsp),%rsp + movaps %xmm6,-0xd8(%rax) + movaps %xmm7,-0xc8(%rax) + movaps %xmm8,-0xb8(%rax) + movaps %xmm9,-0xa8(%rax) + movaps %xmm10,-0x98(%rax) + movaps %xmm11,-0x88(%rax) + movaps %xmm12,-0x78(%rax) + movaps %xmm13,-0x68(%rax) + movaps %xmm14,-0x58(%rax) + movaps %xmm15,-0x48(%rax) +.Lgcm_enc_body: +___ +$code.=<<___; + vzeroupper + + vmovdqu ($ivp),$T1 # input counter value + add \$-128,%rsp + mov 12($ivp),$counter + lea .Lbswap_mask(%rip),$const + lea -0x80($key),$in0 # borrow $in0 + mov \$0xf80,$end0 # borrow $end0 + lea 0x80($key),$key # size optimization + vmovdqu ($const),$Ii # borrow $Ii for .Lbswap_mask + and \$-128,%rsp # ensure stack alignment + mov 0xf0-0x80($key),$rounds + + and $end0,$in0 + and %rsp,$end0 + sub $in0,$end0 + jc .Lenc_no_key_aliasing + cmp \$768,$end0 + jnc .Lenc_no_key_aliasing + sub $end0,%rsp # avoid aliasing with key +.Lenc_no_key_aliasing: + + lea ($out),$in0 + lea -0xc0($out,$len),$end0 + shr \$4,$len + + call _aesni_ctr32_6x + vpshufb $Ii,$inout0,$Xi # save bswapped output on stack + vpshufb $Ii,$inout1,$T2 + vmovdqu $Xi,0x70(%rsp) + vpshufb $Ii,$inout2,$Z0 + vmovdqu $T2,0x60(%rsp) + vpshufb $Ii,$inout3,$Z1 + vmovdqu $Z0,0x50(%rsp) + vpshufb $Ii,$inout4,$Z2 + vmovdqu $Z1,0x40(%rsp) + vpshufb $Ii,$inout5,$Z3 # passed to _aesni_ctr32_ghash_6x + vmovdqu $Z2,0x30(%rsp) + + call _aesni_ctr32_6x + + vmovdqu ($Xip),$Xi # load Xi + lea 0x20+0x20($Xip),$Xip # size optimization + sub \$12,$len + mov \$0x60*2,$ret + vpshufb $Ii,$Xi,$Xi + + call _aesni_ctr32_ghash_6x + vmovdqu 0x20(%rsp),$Z3 # I[5] + vmovdqu ($const),$Ii # borrow $Ii for .Lbswap_mask + vmovdqu 0x00-0x20($Xip),$Hkey # $Hkey^1 + vpunpckhqdq $Z3,$Z3,$T1 + vmovdqu 0x20-0x20($Xip),$rndkey # borrow $rndkey for $HK + vmovups $inout0,-0x60($out) # save output + vpshufb $Ii,$inout0,$inout0 # but keep bswapped copy + vpxor $Z3,$T1,$T1 + vmovups $inout1,-0x50($out) + vpshufb $Ii,$inout1,$inout1 + vmovups $inout2,-0x40($out) + vpshufb $Ii,$inout2,$inout2 + vmovups $inout3,-0x30($out) + vpshufb $Ii,$inout3,$inout3 + vmovups $inout4,-0x20($out) + vpshufb $Ii,$inout4,$inout4 + vmovups $inout5,-0x10($out) + vpshufb $Ii,$inout5,$inout5 + vmovdqu $inout0,0x10(%rsp) # free $inout0 +___ +{ my ($HK,$T3)=($rndkey,$inout0); + +$code.=<<___; + vmovdqu 0x30(%rsp),$Z2 # I[4] + vmovdqu 0x10-0x20($Xip),$Ii # borrow $Ii for $Hkey^2 + vpunpckhqdq $Z2,$Z2,$T2 + vpclmulqdq \$0x00,$Hkey,$Z3,$Z1 + vpxor $Z2,$T2,$T2 + vpclmulqdq \$0x11,$Hkey,$Z3,$Z3 + vpclmulqdq \$0x00,$HK,$T1,$T1 + + vmovdqu 0x40(%rsp),$T3 # I[3] + vpclmulqdq \$0x00,$Ii,$Z2,$Z0 + vmovdqu 0x30-0x20($Xip),$Hkey # $Hkey^3 + vpxor $Z1,$Z0,$Z0 + vpunpckhqdq $T3,$T3,$Z1 + vpclmulqdq \$0x11,$Ii,$Z2,$Z2 + vpxor $T3,$Z1,$Z1 + vpxor $Z3,$Z2,$Z2 + vpclmulqdq \$0x10,$HK,$T2,$T2 + vmovdqu 0x50-0x20($Xip),$HK + vpxor $T1,$T2,$T2 + + vmovdqu 0x50(%rsp),$T1 # I[2] + vpclmulqdq \$0x00,$Hkey,$T3,$Z3 + vmovdqu 0x40-0x20($Xip),$Ii # borrow $Ii for $Hkey^4 + vpxor $Z0,$Z3,$Z3 + vpunpckhqdq $T1,$T1,$Z0 + vpclmulqdq \$0x11,$Hkey,$T3,$T3 + vpxor $T1,$Z0,$Z0 + vpxor $Z2,$T3,$T3 + vpclmulqdq \$0x00,$HK,$Z1,$Z1 + vpxor $T2,$Z1,$Z1 + + vmovdqu 0x60(%rsp),$T2 # I[1] + vpclmulqdq \$0x00,$Ii,$T1,$Z2 + vmovdqu 0x60-0x20($Xip),$Hkey # $Hkey^5 + vpxor $Z3,$Z2,$Z2 + vpunpckhqdq $T2,$T2,$Z3 + vpclmulqdq \$0x11,$Ii,$T1,$T1 + vpxor $T2,$Z3,$Z3 + vpxor $T3,$T1,$T1 + vpclmulqdq \$0x10,$HK,$Z0,$Z0 + vmovdqu 0x80-0x20($Xip),$HK + vpxor $Z1,$Z0,$Z0 + + vpxor 0x70(%rsp),$Xi,$Xi # accumulate I[0] + vpclmulqdq \$0x00,$Hkey,$T2,$Z1 + vmovdqu 0x70-0x20($Xip),$Ii # borrow $Ii for $Hkey^6 + vpunpckhqdq $Xi,$Xi,$T3 + vpxor $Z2,$Z1,$Z1 + vpclmulqdq \$0x11,$Hkey,$T2,$T2 + vpxor $Xi,$T3,$T3 + vpxor $T1,$T2,$T2 + vpclmulqdq \$0x00,$HK,$Z3,$Z3 + vpxor $Z0,$Z3,$Z0 + + vpclmulqdq \$0x00,$Ii,$Xi,$Z2 + vmovdqu 0x00-0x20($Xip),$Hkey # $Hkey^1 + vpunpckhqdq $inout5,$inout5,$T1 + vpclmulqdq \$0x11,$Ii,$Xi,$Xi + vpxor $inout5,$T1,$T1 + vpxor $Z1,$Z2,$Z1 + vpclmulqdq \$0x10,$HK,$T3,$T3 + vmovdqu 0x20-0x20($Xip),$HK + vpxor $T2,$Xi,$Z3 + vpxor $Z0,$T3,$Z2 + + vmovdqu 0x10-0x20($Xip),$Ii # borrow $Ii for $Hkey^2 + vpxor $Z1,$Z3,$T3 # aggregated Karatsuba post-processing + vpclmulqdq \$0x00,$Hkey,$inout5,$Z0 + vpxor $T3,$Z2,$Z2 + vpunpckhqdq $inout4,$inout4,$T2 + vpclmulqdq \$0x11,$Hkey,$inout5,$inout5 + vpxor $inout4,$T2,$T2 + vpslldq \$8,$Z2,$T3 + vpclmulqdq \$0x00,$HK,$T1,$T1 + vpxor $T3,$Z1,$Xi + vpsrldq \$8,$Z2,$Z2 + vpxor $Z2,$Z3,$Z3 + + vpclmulqdq \$0x00,$Ii,$inout4,$Z1 + vmovdqu 0x30-0x20($Xip),$Hkey # $Hkey^3 + vpxor $Z0,$Z1,$Z1 + vpunpckhqdq $inout3,$inout3,$T3 + vpclmulqdq \$0x11,$Ii,$inout4,$inout4 + vpxor $inout3,$T3,$T3 + vpxor $inout5,$inout4,$inout4 + vpalignr \$8,$Xi,$Xi,$inout5 # 1st phase + vpclmulqdq \$0x10,$HK,$T2,$T2 + vmovdqu 0x50-0x20($Xip),$HK + vpxor $T1,$T2,$T2 + + vpclmulqdq \$0x00,$Hkey,$inout3,$Z0 + vmovdqu 0x40-0x20($Xip),$Ii # borrow $Ii for $Hkey^4 + vpxor $Z1,$Z0,$Z0 + vpunpckhqdq $inout2,$inout2,$T1 + vpclmulqdq \$0x11,$Hkey,$inout3,$inout3 + vpxor $inout2,$T1,$T1 + vpxor $inout4,$inout3,$inout3 + vxorps 0x10(%rsp),$Z3,$Z3 # accumulate $inout0 + vpclmulqdq \$0x00,$HK,$T3,$T3 + vpxor $T2,$T3,$T3 + + vpclmulqdq \$0x10,0x10($const),$Xi,$Xi + vxorps $inout5,$Xi,$Xi + + vpclmulqdq \$0x00,$Ii,$inout2,$Z1 + vmovdqu 0x60-0x20($Xip),$Hkey # $Hkey^5 + vpxor $Z0,$Z1,$Z1 + vpunpckhqdq $inout1,$inout1,$T2 + vpclmulqdq \$0x11,$Ii,$inout2,$inout2 + vpxor $inout1,$T2,$T2 + vpalignr \$8,$Xi,$Xi,$inout5 # 2nd phase + vpxor $inout3,$inout2,$inout2 + vpclmulqdq \$0x10,$HK,$T1,$T1 + vmovdqu 0x80-0x20($Xip),$HK + vpxor $T3,$T1,$T1 + + vxorps $Z3,$inout5,$inout5 + vpclmulqdq \$0x10,0x10($const),$Xi,$Xi + vxorps $inout5,$Xi,$Xi + + vpclmulqdq \$0x00,$Hkey,$inout1,$Z0 + vmovdqu 0x70-0x20($Xip),$Ii # borrow $Ii for $Hkey^6 + vpxor $Z1,$Z0,$Z0 + vpunpckhqdq $Xi,$Xi,$T3 + vpclmulqdq \$0x11,$Hkey,$inout1,$inout1 + vpxor $Xi,$T3,$T3 + vpxor $inout2,$inout1,$inout1 + vpclmulqdq \$0x00,$HK,$T2,$T2 + vpxor $T1,$T2,$T2 + + vpclmulqdq \$0x00,$Ii,$Xi,$Z1 + vpclmulqdq \$0x11,$Ii,$Xi,$Z3 + vpxor $Z0,$Z1,$Z1 + vpclmulqdq \$0x10,$HK,$T3,$Z2 + vpxor $inout1,$Z3,$Z3 + vpxor $T2,$Z2,$Z2 + + vpxor $Z1,$Z3,$Z0 # aggregated Karatsuba post-processing + vpxor $Z0,$Z2,$Z2 + vpslldq \$8,$Z2,$T1 + vmovdqu 0x10($const),$Hkey # .Lpoly + vpsrldq \$8,$Z2,$Z2 + vpxor $T1,$Z1,$Xi + vpxor $Z2,$Z3,$Z3 + + vpalignr \$8,$Xi,$Xi,$T2 # 1st phase + vpclmulqdq \$0x10,$Hkey,$Xi,$Xi + vpxor $T2,$Xi,$Xi + + vpalignr \$8,$Xi,$Xi,$T2 # 2nd phase + vpclmulqdq \$0x10,$Hkey,$Xi,$Xi + vpxor $Z3,$T2,$T2 + vpxor $T2,$Xi,$Xi +___ +} +$code.=<<___; + vpshufb ($const),$Xi,$Xi # .Lbswap_mask + vmovdqu $Xi,-0x40($Xip) # output Xi + + vzeroupper +___ +$code.=<<___ if ($win64); + movaps -0xd8(%rax),%xmm6 + movaps -0xc8(%rax),%xmm7 + movaps -0xb8(%rax),%xmm8 + movaps -0xa8(%rax),%xmm9 + movaps -0x98(%rax),%xmm10 + movaps -0x88(%rax),%xmm11 + movaps -0x78(%rax),%xmm12 + movaps -0x68(%rax),%xmm13 + movaps -0x58(%rax),%xmm14 + movaps -0x48(%rax),%xmm15 +___ +$code.=<<___; + mov -48(%rax),%r15 + mov -40(%rax),%r14 + mov -32(%rax),%r13 + mov -24(%rax),%r12 + mov -16(%rax),%rbp + mov -8(%rax),%rbx + lea (%rax),%rsp # restore %rsp +.Lgcm_enc_abort: + mov $ret,%rax # return value + ret +.size aesni_gcm_encrypt,.-aesni_gcm_encrypt +___ + +$code.=<<___; +.align 64 +.Lbswap_mask: + .byte 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 +.Lpoly: + .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc2 +.Lone_msb: + .byte 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 +.Ltwo_lsb: + .byte 2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +.Lone_lsb: + .byte 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +.asciz "AES-NI GCM module for x86_64, CRYPTOGAMS by " +.align 64 +___ +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___ +.extern __imp_RtlVirtualUnwind +.type gcm_se_handler,\@abi-omnipotent +.align 16 +gcm_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + mov 120($context),%rax # pull context->Rax + + mov -48(%rax),%r15 + mov -40(%rax),%r14 + mov -32(%rax),%r13 + mov -24(%rax),%r12 + mov -16(%rax),%rbp + mov -8(%rax),%rbx + mov %r15,240($context) + mov %r14,232($context) + mov %r13,224($context) + mov %r12,216($context) + mov %rbp,160($context) + mov %rbx,144($context) + + lea -0xd8(%rax),%rsi # %xmm save area + lea 512($context),%rdi # & context.Xmm6 + mov \$20,%ecx # 10*sizeof(%xmm0)/sizeof(%rax) + .long 0xa548f3fc # cld; rep movsq + +.Lcommon_seh_tail: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size gcm_se_handler,.-gcm_se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_aesni_gcm_decrypt + .rva .LSEH_end_aesni_gcm_decrypt + .rva .LSEH_gcm_dec_info + + .rva .LSEH_begin_aesni_gcm_encrypt + .rva .LSEH_end_aesni_gcm_encrypt + .rva .LSEH_gcm_enc_info +.section .xdata +.align 8 +.LSEH_gcm_dec_info: + .byte 9,0,0,0 + .rva gcm_se_handler + .rva .Lgcm_dec_body,.Lgcm_dec_abort +.LSEH_gcm_enc_info: + .byte 9,0,0,0 + .rva gcm_se_handler + .rva .Lgcm_enc_body,.Lgcm_enc_abort +___ +} +}}} else {{{ +$code=<<___; # assembler is too old +.text + +.globl aesni_gcm_encrypt +.type aesni_gcm_encrypt,\@abi-omnipotent +aesni_gcm_encrypt: + xor %eax,%eax + ret +.size aesni_gcm_encrypt,.-aesni_gcm_encrypt + +.globl aesni_gcm_decrypt +.type aesni_gcm_decrypt,\@abi-omnipotent +aesni_gcm_decrypt: + xor %eax,%eax + ret +.size aesni_gcm_decrypt,.-aesni_gcm_decrypt +___ +}}} + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-armv4.pl b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-armv4.pl new file mode 100644 index 00000000..a0d04cec --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-armv4.pl @@ -0,0 +1,520 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# April 2010 +# +# The module implements "4-bit" GCM GHASH function and underlying +# single multiplication operation in GF(2^128). "4-bit" means that it +# uses 256 bytes per-key table [+32 bytes shared table]. There is no +# experimental performance data available yet. The only approximation +# that can be made at this point is based on code size. Inner loop is +# 32 instructions long and on single-issue core should execute in <40 +# cycles. Having verified that gcc 3.4 didn't unroll corresponding +# loop, this assembler loop body was found to be ~3x smaller than +# compiler-generated one... +# +# July 2010 +# +# Rescheduling for dual-issue pipeline resulted in 8.5% improvement on +# Cortex A8 core and ~25 cycles per processed byte (which was observed +# to be ~3 times faster than gcc-generated code:-) +# +# February 2011 +# +# Profiler-assisted and platform-specific optimization resulted in 7% +# improvement on Cortex A8 core and ~23.5 cycles per byte. +# +# March 2011 +# +# Add NEON implementation featuring polynomial multiplication, i.e. no +# lookup tables involved. On Cortex A8 it was measured to process one +# byte in 15 cycles or 55% faster than integer-only code. +# +# April 2014 +# +# Switch to multiplication algorithm suggested in paper referred +# below and combine it with reduction algorithm from x86 module. +# Performance improvement over previous version varies from 65% on +# Snapdragon S4 to 110% on Cortex A9. In absolute terms Cortex A8 +# processes one byte in 8.45 cycles, A9 - in 10.2, A15 - in 7.63, +# Snapdragon S4 - in 9.33. +# +# Câmara, D.; Gouvêa, C. P. L.; López, J. & Dahab, R.: Fast Software +# Polynomial Multiplication on ARM Processors using the NEON Engine. +# +# http://conradoplg.cryptoland.net/files/2010/12/mocrysen13.pdf + +# ==================================================================== +# Note about "528B" variant. In ARM case it makes lesser sense to +# implement it for following reasons: +# +# - performance improvement won't be anywhere near 50%, because 128- +# bit shift operation is neatly fused with 128-bit xor here, and +# "538B" variant would eliminate only 4-5 instructions out of 32 +# in the inner loop (meaning that estimated improvement is ~15%); +# - ARM-based systems are often embedded ones and extra memory +# consumption might be unappreciated (for so little improvement); +# +# Byte order [in]dependence. ========================================= +# +# Caller is expected to maintain specific *dword* order in Htable, +# namely with *least* significant dword of 128-bit value at *lower* +# address. This differs completely from C code and has everything to +# do with ldm instruction and order in which dwords are "consumed" by +# algorithm. *Byte* order within these dwords in turn is whatever +# *native* byte order on current platform. See gcm128.c for working +# example... + +$flavour = shift; +if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } +else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} } + +if ($flavour && $flavour ne "void") { + $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; + ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or + ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or + die "can't locate arm-xlate.pl"; + + open STDOUT,"| \"$^X\" $xlate $flavour $output"; +} else { + open STDOUT,">$output"; +} + +$Xi="r0"; # argument block +$Htbl="r1"; +$inp="r2"; +$len="r3"; + +$Zll="r4"; # variables +$Zlh="r5"; +$Zhl="r6"; +$Zhh="r7"; +$Tll="r8"; +$Tlh="r9"; +$Thl="r10"; +$Thh="r11"; +$nlo="r12"; +################# r13 is stack pointer +$nhi="r14"; +################# r15 is program counter + +$rem_4bit=$inp; # used in gcm_gmult_4bit +$cnt=$len; + +sub Zsmash() { + my $i=12; + my @args=@_; + for ($Zll,$Zlh,$Zhl,$Zhh) { + $code.=<<___; +#if __ARM_ARCH__>=7 && defined(__ARMEL__) + rev $_,$_ + str $_,[$Xi,#$i] +#elif defined(__ARMEB__) + str $_,[$Xi,#$i] +#else + mov $Tlh,$_,lsr#8 + strb $_,[$Xi,#$i+3] + mov $Thl,$_,lsr#16 + strb $Tlh,[$Xi,#$i+2] + mov $Thh,$_,lsr#24 + strb $Thl,[$Xi,#$i+1] + strb $Thh,[$Xi,#$i] +#endif +___ + $code.="\t".shift(@args)."\n"; + $i-=4; + } +} + +$code=<<___; +#if defined(__arm__) +#include "arm_arch.h" + +.syntax unified + +.text +.code 32 + +#ifdef __APPLE__ +#define ldrplb ldrbpl +#define ldrneb ldrbne +#endif + +.type rem_4bit,%object +.align 5 +rem_4bit: +.short 0x0000,0x1C20,0x3840,0x2460 +.short 0x7080,0x6CA0,0x48C0,0x54E0 +.short 0xE100,0xFD20,0xD940,0xC560 +.short 0x9180,0x8DA0,0xA9C0,0xB5E0 +.size rem_4bit,.-rem_4bit + +.type rem_4bit_get,%function +rem_4bit_get: + sub $rem_4bit,pc,#8 + sub $rem_4bit,$rem_4bit,#32 @ &rem_4bit + b .Lrem_4bit_got + nop +.size rem_4bit_get,.-rem_4bit_get + +.global gcm_ghash_4bit +.hidden gcm_ghash_4bit +.type gcm_ghash_4bit,%function +gcm_ghash_4bit: + sub r12,pc,#8 + add $len,$inp,$len @ $len to point at the end + stmdb sp!,{r3-r11,lr} @ save $len/end too + sub r12,r12,#48 @ &rem_4bit + + ldmia r12,{r4-r11} @ copy rem_4bit ... + stmdb sp!,{r4-r11} @ ... to stack + + ldrb $nlo,[$inp,#15] + ldrb $nhi,[$Xi,#15] +.Louter: + eor $nlo,$nlo,$nhi + and $nhi,$nlo,#0xf0 + and $nlo,$nlo,#0x0f + mov $cnt,#14 + + add $Zhh,$Htbl,$nlo,lsl#4 + ldmia $Zhh,{$Zll-$Zhh} @ load Htbl[nlo] + add $Thh,$Htbl,$nhi + ldrb $nlo,[$inp,#14] + + and $nhi,$Zll,#0xf @ rem + ldmia $Thh,{$Tll-$Thh} @ load Htbl[nhi] + add $nhi,$nhi,$nhi + eor $Zll,$Tll,$Zll,lsr#4 + ldrh $Tll,[sp,$nhi] @ rem_4bit[rem] + eor $Zll,$Zll,$Zlh,lsl#28 + ldrb $nhi,[$Xi,#14] + eor $Zlh,$Tlh,$Zlh,lsr#4 + eor $Zlh,$Zlh,$Zhl,lsl#28 + eor $Zhl,$Thl,$Zhl,lsr#4 + eor $Zhl,$Zhl,$Zhh,lsl#28 + eor $Zhh,$Thh,$Zhh,lsr#4 + eor $nlo,$nlo,$nhi + and $nhi,$nlo,#0xf0 + and $nlo,$nlo,#0x0f + eor $Zhh,$Zhh,$Tll,lsl#16 + +.Linner: + add $Thh,$Htbl,$nlo,lsl#4 + and $nlo,$Zll,#0xf @ rem + subs $cnt,$cnt,#1 + add $nlo,$nlo,$nlo + ldmia $Thh,{$Tll-$Thh} @ load Htbl[nlo] + eor $Zll,$Tll,$Zll,lsr#4 + eor $Zll,$Zll,$Zlh,lsl#28 + eor $Zlh,$Tlh,$Zlh,lsr#4 + eor $Zlh,$Zlh,$Zhl,lsl#28 + ldrh $Tll,[sp,$nlo] @ rem_4bit[rem] + eor $Zhl,$Thl,$Zhl,lsr#4 + ldrbpl $nlo,[$inp,$cnt] + eor $Zhl,$Zhl,$Zhh,lsl#28 + eor $Zhh,$Thh,$Zhh,lsr#4 + + add $Thh,$Htbl,$nhi + and $nhi,$Zll,#0xf @ rem + eor $Zhh,$Zhh,$Tll,lsl#16 @ ^= rem_4bit[rem] + add $nhi,$nhi,$nhi + ldmia $Thh,{$Tll-$Thh} @ load Htbl[nhi] + eor $Zll,$Tll,$Zll,lsr#4 + ldrbpl $Tll,[$Xi,$cnt] + eor $Zll,$Zll,$Zlh,lsl#28 + eor $Zlh,$Tlh,$Zlh,lsr#4 + ldrh $Tlh,[sp,$nhi] + eor $Zlh,$Zlh,$Zhl,lsl#28 + eor $Zhl,$Thl,$Zhl,lsr#4 + eor $Zhl,$Zhl,$Zhh,lsl#28 + eorpl $nlo,$nlo,$Tll + eor $Zhh,$Thh,$Zhh,lsr#4 + andpl $nhi,$nlo,#0xf0 + andpl $nlo,$nlo,#0x0f + eor $Zhh,$Zhh,$Tlh,lsl#16 @ ^= rem_4bit[rem] + bpl .Linner + + ldr $len,[sp,#32] @ re-load $len/end + add $inp,$inp,#16 + mov $nhi,$Zll +___ + &Zsmash("cmp\t$inp,$len","ldrbne\t$nlo,[$inp,#15]"); +$code.=<<___; + bne .Louter + + add sp,sp,#36 +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r11,pc} +#else + ldmia sp!,{r4-r11,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size gcm_ghash_4bit,.-gcm_ghash_4bit + +.global gcm_gmult_4bit +.hidden gcm_gmult_4bit +.type gcm_gmult_4bit,%function +gcm_gmult_4bit: + stmdb sp!,{r4-r11,lr} + ldrb $nlo,[$Xi,#15] + b rem_4bit_get +.Lrem_4bit_got: + and $nhi,$nlo,#0xf0 + and $nlo,$nlo,#0x0f + mov $cnt,#14 + + add $Zhh,$Htbl,$nlo,lsl#4 + ldmia $Zhh,{$Zll-$Zhh} @ load Htbl[nlo] + ldrb $nlo,[$Xi,#14] + + add $Thh,$Htbl,$nhi + and $nhi,$Zll,#0xf @ rem + ldmia $Thh,{$Tll-$Thh} @ load Htbl[nhi] + add $nhi,$nhi,$nhi + eor $Zll,$Tll,$Zll,lsr#4 + ldrh $Tll,[$rem_4bit,$nhi] @ rem_4bit[rem] + eor $Zll,$Zll,$Zlh,lsl#28 + eor $Zlh,$Tlh,$Zlh,lsr#4 + eor $Zlh,$Zlh,$Zhl,lsl#28 + eor $Zhl,$Thl,$Zhl,lsr#4 + eor $Zhl,$Zhl,$Zhh,lsl#28 + eor $Zhh,$Thh,$Zhh,lsr#4 + and $nhi,$nlo,#0xf0 + eor $Zhh,$Zhh,$Tll,lsl#16 + and $nlo,$nlo,#0x0f + +.Loop: + add $Thh,$Htbl,$nlo,lsl#4 + and $nlo,$Zll,#0xf @ rem + subs $cnt,$cnt,#1 + add $nlo,$nlo,$nlo + ldmia $Thh,{$Tll-$Thh} @ load Htbl[nlo] + eor $Zll,$Tll,$Zll,lsr#4 + eor $Zll,$Zll,$Zlh,lsl#28 + eor $Zlh,$Tlh,$Zlh,lsr#4 + eor $Zlh,$Zlh,$Zhl,lsl#28 + ldrh $Tll,[$rem_4bit,$nlo] @ rem_4bit[rem] + eor $Zhl,$Thl,$Zhl,lsr#4 + ldrbpl $nlo,[$Xi,$cnt] + eor $Zhl,$Zhl,$Zhh,lsl#28 + eor $Zhh,$Thh,$Zhh,lsr#4 + + add $Thh,$Htbl,$nhi + and $nhi,$Zll,#0xf @ rem + eor $Zhh,$Zhh,$Tll,lsl#16 @ ^= rem_4bit[rem] + add $nhi,$nhi,$nhi + ldmia $Thh,{$Tll-$Thh} @ load Htbl[nhi] + eor $Zll,$Tll,$Zll,lsr#4 + eor $Zll,$Zll,$Zlh,lsl#28 + eor $Zlh,$Tlh,$Zlh,lsr#4 + ldrh $Tll,[$rem_4bit,$nhi] @ rem_4bit[rem] + eor $Zlh,$Zlh,$Zhl,lsl#28 + eor $Zhl,$Thl,$Zhl,lsr#4 + eor $Zhl,$Zhl,$Zhh,lsl#28 + eor $Zhh,$Thh,$Zhh,lsr#4 + andpl $nhi,$nlo,#0xf0 + andpl $nlo,$nlo,#0x0f + eor $Zhh,$Zhh,$Tll,lsl#16 @ ^= rem_4bit[rem] + bpl .Loop +___ + &Zsmash(); +$code.=<<___; +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r11,pc} +#else + ldmia sp!,{r4-r11,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size gcm_gmult_4bit,.-gcm_gmult_4bit +___ +{ +my ($Xl,$Xm,$Xh,$IN)=map("q$_",(0..3)); +my ($t0,$t1,$t2,$t3)=map("q$_",(8..12)); +my ($Hlo,$Hhi,$Hhl,$k48,$k32,$k16)=map("d$_",(26..31)); + +sub clmul64x64 { +my ($r,$a,$b)=@_; +$code.=<<___; + vext.8 $t0#lo, $a, $a, #1 @ A1 + vmull.p8 $t0, $t0#lo, $b @ F = A1*B + vext.8 $r#lo, $b, $b, #1 @ B1 + vmull.p8 $r, $a, $r#lo @ E = A*B1 + vext.8 $t1#lo, $a, $a, #2 @ A2 + vmull.p8 $t1, $t1#lo, $b @ H = A2*B + vext.8 $t3#lo, $b, $b, #2 @ B2 + vmull.p8 $t3, $a, $t3#lo @ G = A*B2 + vext.8 $t2#lo, $a, $a, #3 @ A3 + veor $t0, $t0, $r @ L = E + F + vmull.p8 $t2, $t2#lo, $b @ J = A3*B + vext.8 $r#lo, $b, $b, #3 @ B3 + veor $t1, $t1, $t3 @ M = G + H + vmull.p8 $r, $a, $r#lo @ I = A*B3 + veor $t0#lo, $t0#lo, $t0#hi @ t0 = (L) (P0 + P1) << 8 + vand $t0#hi, $t0#hi, $k48 + vext.8 $t3#lo, $b, $b, #4 @ B4 + veor $t1#lo, $t1#lo, $t1#hi @ t1 = (M) (P2 + P3) << 16 + vand $t1#hi, $t1#hi, $k32 + vmull.p8 $t3, $a, $t3#lo @ K = A*B4 + veor $t2, $t2, $r @ N = I + J + veor $t0#lo, $t0#lo, $t0#hi + veor $t1#lo, $t1#lo, $t1#hi + veor $t2#lo, $t2#lo, $t2#hi @ t2 = (N) (P4 + P5) << 24 + vand $t2#hi, $t2#hi, $k16 + vext.8 $t0, $t0, $t0, #15 + veor $t3#lo, $t3#lo, $t3#hi @ t3 = (K) (P6 + P7) << 32 + vmov.i64 $t3#hi, #0 + vext.8 $t1, $t1, $t1, #14 + veor $t2#lo, $t2#lo, $t2#hi + vmull.p8 $r, $a, $b @ D = A*B + vext.8 $t3, $t3, $t3, #12 + vext.8 $t2, $t2, $t2, #13 + veor $t0, $t0, $t1 + veor $t2, $t2, $t3 + veor $r, $r, $t0 + veor $r, $r, $t2 +___ +} + +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.global gcm_init_neon +.hidden gcm_init_neon +.type gcm_init_neon,%function +.align 4 +gcm_init_neon: + vld1.64 $IN#hi,[r1]! @ load H + vmov.i8 $t0,#0xe1 + vld1.64 $IN#lo,[r1] + vshl.i64 $t0#hi,#57 + vshr.u64 $t0#lo,#63 @ t0=0xc2....01 + vdup.8 $t1,$IN#hi[7] + vshr.u64 $Hlo,$IN#lo,#63 + vshr.s8 $t1,#7 @ broadcast carry bit + vshl.i64 $IN,$IN,#1 + vand $t0,$t0,$t1 + vorr $IN#hi,$Hlo @ H<<<=1 + veor $IN,$IN,$t0 @ twisted H + vstmia r0,{$IN} + + ret @ bx lr +.size gcm_init_neon,.-gcm_init_neon + +.global gcm_gmult_neon +.hidden gcm_gmult_neon +.type gcm_gmult_neon,%function +.align 4 +gcm_gmult_neon: + vld1.64 $IN#hi,[$Xi]! @ load Xi + vld1.64 $IN#lo,[$Xi]! + vmov.i64 $k48,#0x0000ffffffffffff + vldmia $Htbl,{$Hlo-$Hhi} @ load twisted H + vmov.i64 $k32,#0x00000000ffffffff +#ifdef __ARMEL__ + vrev64.8 $IN,$IN +#endif + vmov.i64 $k16,#0x000000000000ffff + veor $Hhl,$Hlo,$Hhi @ Karatsuba pre-processing + mov $len,#16 + b .Lgmult_neon +.size gcm_gmult_neon,.-gcm_gmult_neon + +.global gcm_ghash_neon +.hidden gcm_ghash_neon +.type gcm_ghash_neon,%function +.align 4 +gcm_ghash_neon: + vld1.64 $Xl#hi,[$Xi]! @ load Xi + vld1.64 $Xl#lo,[$Xi]! + vmov.i64 $k48,#0x0000ffffffffffff + vldmia $Htbl,{$Hlo-$Hhi} @ load twisted H + vmov.i64 $k32,#0x00000000ffffffff +#ifdef __ARMEL__ + vrev64.8 $Xl,$Xl +#endif + vmov.i64 $k16,#0x000000000000ffff + veor $Hhl,$Hlo,$Hhi @ Karatsuba pre-processing + +.Loop_neon: + vld1.64 $IN#hi,[$inp]! @ load inp + vld1.64 $IN#lo,[$inp]! +#ifdef __ARMEL__ + vrev64.8 $IN,$IN +#endif + veor $IN,$Xl @ inp^=Xi +.Lgmult_neon: +___ + &clmul64x64 ($Xl,$Hlo,"$IN#lo"); # H.lo·Xi.lo +$code.=<<___; + veor $IN#lo,$IN#lo,$IN#hi @ Karatsuba pre-processing +___ + &clmul64x64 ($Xm,$Hhl,"$IN#lo"); # (H.lo+H.hi)·(Xi.lo+Xi.hi) + &clmul64x64 ($Xh,$Hhi,"$IN#hi"); # H.hi·Xi.hi +$code.=<<___; + veor $Xm,$Xm,$Xl @ Karatsuba post-processing + veor $Xm,$Xm,$Xh + veor $Xl#hi,$Xl#hi,$Xm#lo + veor $Xh#lo,$Xh#lo,$Xm#hi @ Xh|Xl - 256-bit result + + @ equivalent of reduction_avx from ghash-x86_64.pl + vshl.i64 $t1,$Xl,#57 @ 1st phase + vshl.i64 $t2,$Xl,#62 + veor $t2,$t2,$t1 @ + vshl.i64 $t1,$Xl,#63 + veor $t2, $t2, $t1 @ + veor $Xl#hi,$Xl#hi,$t2#lo @ + veor $Xh#lo,$Xh#lo,$t2#hi + + vshr.u64 $t2,$Xl,#1 @ 2nd phase + veor $Xh,$Xh,$Xl + veor $Xl,$Xl,$t2 @ + vshr.u64 $t2,$t2,#6 + vshr.u64 $Xl,$Xl,#1 @ + veor $Xl,$Xl,$Xh @ + veor $Xl,$Xl,$t2 @ + + subs $len,#16 + bne .Loop_neon + +#ifdef __ARMEL__ + vrev64.8 $Xl,$Xl +#endif + sub $Xi,#16 + vst1.64 $Xl#hi,[$Xi]! @ write out Xi + vst1.64 $Xl#lo,[$Xi] + + ret @ bx lr +.size gcm_ghash_neon,.-gcm_ghash_neon +#endif +___ +} +$code.=<<___; +.asciz "GHASH for ARMv4/NEON, CRYPTOGAMS by " +.align 2 + +#endif +___ + +foreach (split("\n",$code)) { + s/\`([^\`]*)\`/eval $1/geo; + + s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo or + s/\bret\b/bx lr/go or + s/\bbx\s+lr\b/.word\t0xe12fff1e/go; # make it possible to compile with -march=armv4 + + print $_,"\n"; +} +close STDOUT; # enforce flush diff --git a/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-x86.pl b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-x86.pl new file mode 100644 index 00000000..0269169f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-x86.pl @@ -0,0 +1,1393 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# March, May, June 2010 +# +# The module implements "4-bit" GCM GHASH function and underlying +# single multiplication operation in GF(2^128). "4-bit" means that it +# uses 256 bytes per-key table [+64/128 bytes fixed table]. It has two +# code paths: vanilla x86 and vanilla SSE. Former will be executed on +# 486 and Pentium, latter on all others. SSE GHASH features so called +# "528B" variant of "4-bit" method utilizing additional 256+16 bytes +# of per-key storage [+512 bytes shared table]. Performance results +# are for streamed GHASH subroutine and are expressed in cycles per +# processed byte, less is better: +# +# gcc 2.95.3(*) SSE assembler x86 assembler +# +# Pentium 105/111(**) - 50 +# PIII 68 /75 12.2 24 +# P4 125/125 17.8 84(***) +# Opteron 66 /70 10.1 30 +# Core2 54 /67 8.4 18 +# Atom 105/105 16.8 53 +# VIA Nano 69 /71 13.0 27 +# +# (*) gcc 3.4.x was observed to generate few percent slower code, +# which is one of reasons why 2.95.3 results were chosen, +# another reason is lack of 3.4.x results for older CPUs; +# comparison with SSE results is not completely fair, because C +# results are for vanilla "256B" implementation, while +# assembler results are for "528B";-) +# (**) second number is result for code compiled with -fPIC flag, +# which is actually more relevant, because assembler code is +# position-independent; +# (***) see comment in non-MMX routine for further details; +# +# To summarize, it's >2-5 times faster than gcc-generated code. To +# anchor it to something else SHA1 assembler processes one byte in +# ~7 cycles on contemporary x86 cores. As for choice of MMX/SSE +# in particular, see comment at the end of the file... + +# May 2010 +# +# Add PCLMULQDQ version performing at 2.10 cycles per processed byte. +# The question is how close is it to theoretical limit? The pclmulqdq +# instruction latency appears to be 14 cycles and there can't be more +# than 2 of them executing at any given time. This means that single +# Karatsuba multiplication would take 28 cycles *plus* few cycles for +# pre- and post-processing. Then multiplication has to be followed by +# modulo-reduction. Given that aggregated reduction method [see +# "Carry-less Multiplication and Its Usage for Computing the GCM Mode" +# white paper by Intel] allows you to perform reduction only once in +# a while we can assume that asymptotic performance can be estimated +# as (28+Tmod/Naggr)/16, where Tmod is time to perform reduction +# and Naggr is the aggregation factor. +# +# Before we proceed to this implementation let's have closer look at +# the best-performing code suggested by Intel in their white paper. +# By tracing inter-register dependencies Tmod is estimated as ~19 +# cycles and Naggr chosen by Intel is 4, resulting in 2.05 cycles per +# processed byte. As implied, this is quite optimistic estimate, +# because it does not account for Karatsuba pre- and post-processing, +# which for a single multiplication is ~5 cycles. Unfortunately Intel +# does not provide performance data for GHASH alone. But benchmarking +# AES_GCM_encrypt ripped out of Fig. 15 of the white paper with aadt +# alone resulted in 2.46 cycles per byte of out 16KB buffer. Note that +# the result accounts even for pre-computing of degrees of the hash +# key H, but its portion is negligible at 16KB buffer size. +# +# Moving on to the implementation in question. Tmod is estimated as +# ~13 cycles and Naggr is 2, giving asymptotic performance of ... +# 2.16. How is it possible that measured performance is better than +# optimistic theoretical estimate? There is one thing Intel failed +# to recognize. By serializing GHASH with CTR in same subroutine +# former's performance is really limited to above (Tmul + Tmod/Naggr) +# equation. But if GHASH procedure is detached, the modulo-reduction +# can be interleaved with Naggr-1 multiplications at instruction level +# and under ideal conditions even disappear from the equation. So that +# optimistic theoretical estimate for this implementation is ... +# 28/16=1.75, and not 2.16. Well, it's probably way too optimistic, +# at least for such small Naggr. I'd argue that (28+Tproc/Naggr), +# where Tproc is time required for Karatsuba pre- and post-processing, +# is more realistic estimate. In this case it gives ... 1.91 cycles. +# Or in other words, depending on how well we can interleave reduction +# and one of the two multiplications the performance should be betwen +# 1.91 and 2.16. As already mentioned, this implementation processes +# one byte out of 8KB buffer in 2.10 cycles, while x86_64 counterpart +# - in 2.02. x86_64 performance is better, because larger register +# bank allows to interleave reduction and multiplication better. +# +# Does it make sense to increase Naggr? To start with it's virtually +# impossible in 32-bit mode, because of limited register bank +# capacity. Otherwise improvement has to be weighed agiainst slower +# setup, as well as code size and complexity increase. As even +# optimistic estimate doesn't promise 30% performance improvement, +# there are currently no plans to increase Naggr. +# +# Special thanks to David Woodhouse for +# providing access to a Westmere-based system on behalf of Intel +# Open Source Technology Centre. + +# January 2010 +# +# Tweaked to optimize transitions between integer and FP operations +# on same XMM register, PCLMULQDQ subroutine was measured to process +# one byte in 2.07 cycles on Sandy Bridge, and in 2.12 - on Westmere. +# The minor regression on Westmere is outweighed by ~15% improvement +# on Sandy Bridge. Strangely enough attempt to modify 64-bit code in +# similar manner resulted in almost 20% degradation on Sandy Bridge, +# where original 64-bit code processes one byte in 1.95 cycles. + +##################################################################### +# For reference, AMD Bulldozer processes one byte in 1.98 cycles in +# 32-bit mode and 1.89 in 64-bit. + +# February 2013 +# +# Overhaul: aggregate Karatsuba post-processing, improve ILP in +# reduction_alg9. Resulting performance is 1.96 cycles per byte on +# Westmere, 1.95 - on Sandy/Ivy Bridge, 1.76 - on Bulldozer. + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],"ghash-x86.pl",$x86only = $ARGV[$#ARGV] eq "386"); + +$sse2=0; +for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } + +($Zhh,$Zhl,$Zlh,$Zll) = ("ebp","edx","ecx","ebx"); +$inp = "edi"; +$Htbl = "esi"; + +$unroll = 0; # Affects x86 loop. Folded loop performs ~7% worse + # than unrolled, which has to be weighted against + # 2.5x x86-specific code size reduction. + +sub x86_loop { + my $off = shift; + my $rem = "eax"; + + &mov ($Zhh,&DWP(4,$Htbl,$Zll)); + &mov ($Zhl,&DWP(0,$Htbl,$Zll)); + &mov ($Zlh,&DWP(12,$Htbl,$Zll)); + &mov ($Zll,&DWP(8,$Htbl,$Zll)); + &xor ($rem,$rem); # avoid partial register stalls on PIII + + # shrd practically kills P4, 2.5x deterioration, but P4 has + # MMX code-path to execute. shrd runs tad faster [than twice + # the shifts, move's and or's] on pre-MMX Pentium (as well as + # PIII and Core2), *but* minimizes code size, spares register + # and thus allows to fold the loop... + if (!$unroll) { + my $cnt = $inp; + &mov ($cnt,15); + &jmp (&label("x86_loop")); + &set_label("x86_loop",16); + for($i=1;$i<=2;$i++) { + &mov (&LB($rem),&LB($Zll)); + &shrd ($Zll,$Zlh,4); + &and (&LB($rem),0xf); + &shrd ($Zlh,$Zhl,4); + &shrd ($Zhl,$Zhh,4); + &shr ($Zhh,4); + &xor ($Zhh,&DWP($off+16,"esp",$rem,4)); + + &mov (&LB($rem),&BP($off,"esp",$cnt)); + if ($i&1) { + &and (&LB($rem),0xf0); + } else { + &shl (&LB($rem),4); + } + + &xor ($Zll,&DWP(8,$Htbl,$rem)); + &xor ($Zlh,&DWP(12,$Htbl,$rem)); + &xor ($Zhl,&DWP(0,$Htbl,$rem)); + &xor ($Zhh,&DWP(4,$Htbl,$rem)); + + if ($i&1) { + &dec ($cnt); + &js (&label("x86_break")); + } else { + &jmp (&label("x86_loop")); + } + } + &set_label("x86_break",16); + } else { + for($i=1;$i<32;$i++) { + &comment($i); + &mov (&LB($rem),&LB($Zll)); + &shrd ($Zll,$Zlh,4); + &and (&LB($rem),0xf); + &shrd ($Zlh,$Zhl,4); + &shrd ($Zhl,$Zhh,4); + &shr ($Zhh,4); + &xor ($Zhh,&DWP($off+16,"esp",$rem,4)); + + if ($i&1) { + &mov (&LB($rem),&BP($off+15-($i>>1),"esp")); + &and (&LB($rem),0xf0); + } else { + &mov (&LB($rem),&BP($off+15-($i>>1),"esp")); + &shl (&LB($rem),4); + } + + &xor ($Zll,&DWP(8,$Htbl,$rem)); + &xor ($Zlh,&DWP(12,$Htbl,$rem)); + &xor ($Zhl,&DWP(0,$Htbl,$rem)); + &xor ($Zhh,&DWP(4,$Htbl,$rem)); + } + } + &bswap ($Zll); + &bswap ($Zlh); + &bswap ($Zhl); + if (!$x86only) { + &bswap ($Zhh); + } else { + &mov ("eax",$Zhh); + &bswap ("eax"); + &mov ($Zhh,"eax"); + } +} + +if ($unroll) { + &function_begin_B("_x86_gmult_4bit_inner"); + &x86_loop(4); + &ret (); + &function_end_B("_x86_gmult_4bit_inner"); +} + +sub deposit_rem_4bit { + my $bias = shift; + + &mov (&DWP($bias+0, "esp"),0x0000<<16); + &mov (&DWP($bias+4, "esp"),0x1C20<<16); + &mov (&DWP($bias+8, "esp"),0x3840<<16); + &mov (&DWP($bias+12,"esp"),0x2460<<16); + &mov (&DWP($bias+16,"esp"),0x7080<<16); + &mov (&DWP($bias+20,"esp"),0x6CA0<<16); + &mov (&DWP($bias+24,"esp"),0x48C0<<16); + &mov (&DWP($bias+28,"esp"),0x54E0<<16); + &mov (&DWP($bias+32,"esp"),0xE100<<16); + &mov (&DWP($bias+36,"esp"),0xFD20<<16); + &mov (&DWP($bias+40,"esp"),0xD940<<16); + &mov (&DWP($bias+44,"esp"),0xC560<<16); + &mov (&DWP($bias+48,"esp"),0x9180<<16); + &mov (&DWP($bias+52,"esp"),0x8DA0<<16); + &mov (&DWP($bias+56,"esp"),0xA9C0<<16); + &mov (&DWP($bias+60,"esp"),0xB5E0<<16); +} + +$suffix = $x86only ? "" : "_x86"; + +&function_begin("gcm_gmult_4bit".$suffix); + &stack_push(16+4+1); # +1 for stack alignment + &mov ($inp,&wparam(0)); # load Xi + &mov ($Htbl,&wparam(1)); # load Htable + + &mov ($Zhh,&DWP(0,$inp)); # load Xi[16] + &mov ($Zhl,&DWP(4,$inp)); + &mov ($Zlh,&DWP(8,$inp)); + &mov ($Zll,&DWP(12,$inp)); + + &deposit_rem_4bit(16); + + &mov (&DWP(0,"esp"),$Zhh); # copy Xi[16] on stack + &mov (&DWP(4,"esp"),$Zhl); + &mov (&DWP(8,"esp"),$Zlh); + &mov (&DWP(12,"esp"),$Zll); + &shr ($Zll,20); + &and ($Zll,0xf0); + + if ($unroll) { + &call ("_x86_gmult_4bit_inner"); + } else { + &x86_loop(0); + &mov ($inp,&wparam(0)); + } + + &mov (&DWP(12,$inp),$Zll); + &mov (&DWP(8,$inp),$Zlh); + &mov (&DWP(4,$inp),$Zhl); + &mov (&DWP(0,$inp),$Zhh); + &stack_pop(16+4+1); +&function_end("gcm_gmult_4bit".$suffix); + +&function_begin("gcm_ghash_4bit".$suffix); + &stack_push(16+4+1); # +1 for 64-bit alignment + &mov ($Zll,&wparam(0)); # load Xi + &mov ($Htbl,&wparam(1)); # load Htable + &mov ($inp,&wparam(2)); # load in + &mov ("ecx",&wparam(3)); # load len + &add ("ecx",$inp); + &mov (&wparam(3),"ecx"); + + &mov ($Zhh,&DWP(0,$Zll)); # load Xi[16] + &mov ($Zhl,&DWP(4,$Zll)); + &mov ($Zlh,&DWP(8,$Zll)); + &mov ($Zll,&DWP(12,$Zll)); + + &deposit_rem_4bit(16); + + &set_label("x86_outer_loop",16); + &xor ($Zll,&DWP(12,$inp)); # xor with input + &xor ($Zlh,&DWP(8,$inp)); + &xor ($Zhl,&DWP(4,$inp)); + &xor ($Zhh,&DWP(0,$inp)); + &mov (&DWP(12,"esp"),$Zll); # dump it on stack + &mov (&DWP(8,"esp"),$Zlh); + &mov (&DWP(4,"esp"),$Zhl); + &mov (&DWP(0,"esp"),$Zhh); + + &shr ($Zll,20); + &and ($Zll,0xf0); + + if ($unroll) { + &call ("_x86_gmult_4bit_inner"); + } else { + &x86_loop(0); + &mov ($inp,&wparam(2)); + } + &lea ($inp,&DWP(16,$inp)); + &cmp ($inp,&wparam(3)); + &mov (&wparam(2),$inp) if (!$unroll); + &jb (&label("x86_outer_loop")); + + &mov ($inp,&wparam(0)); # load Xi + &mov (&DWP(12,$inp),$Zll); + &mov (&DWP(8,$inp),$Zlh); + &mov (&DWP(4,$inp),$Zhl); + &mov (&DWP(0,$inp),$Zhh); + &stack_pop(16+4+1); +&function_end("gcm_ghash_4bit".$suffix); + +if (!$x86only) {{{ + +&static_label("rem_4bit"); + +if (!$sse2) {{ # pure-MMX "May" version... + +$S=12; # shift factor for rem_4bit + +&function_begin_B("_mmx_gmult_4bit_inner"); +# MMX version performs 3.5 times better on P4 (see comment in non-MMX +# routine for further details), 100% better on Opteron, ~70% better +# on Core2 and PIII... In other words effort is considered to be well +# spent... Since initial release the loop was unrolled in order to +# "liberate" register previously used as loop counter. Instead it's +# used to optimize critical path in 'Z.hi ^= rem_4bit[Z.lo&0xf]'. +# The path involves move of Z.lo from MMX to integer register, +# effective address calculation and finally merge of value to Z.hi. +# Reference to rem_4bit is scheduled so late that I had to >>4 +# rem_4bit elements. This resulted in 20-45% procent improvement +# on contemporary µ-archs. +{ + my $cnt; + my $rem_4bit = "eax"; + my @rem = ($Zhh,$Zll); + my $nhi = $Zhl; + my $nlo = $Zlh; + + my ($Zlo,$Zhi) = ("mm0","mm1"); + my $tmp = "mm2"; + + &xor ($nlo,$nlo); # avoid partial register stalls on PIII + &mov ($nhi,$Zll); + &mov (&LB($nlo),&LB($nhi)); + &shl (&LB($nlo),4); + &and ($nhi,0xf0); + &movq ($Zlo,&QWP(8,$Htbl,$nlo)); + &movq ($Zhi,&QWP(0,$Htbl,$nlo)); + &movd ($rem[0],$Zlo); + + for ($cnt=28;$cnt>=-2;$cnt--) { + my $odd = $cnt&1; + my $nix = $odd ? $nlo : $nhi; + + &shl (&LB($nlo),4) if ($odd); + &psrlq ($Zlo,4); + &movq ($tmp,$Zhi); + &psrlq ($Zhi,4); + &pxor ($Zlo,&QWP(8,$Htbl,$nix)); + &mov (&LB($nlo),&BP($cnt/2,$inp)) if (!$odd && $cnt>=0); + &psllq ($tmp,60); + &and ($nhi,0xf0) if ($odd); + &pxor ($Zhi,&QWP(0,$rem_4bit,$rem[1],8)) if ($cnt<28); + &and ($rem[0],0xf); + &pxor ($Zhi,&QWP(0,$Htbl,$nix)); + &mov ($nhi,$nlo) if (!$odd && $cnt>=0); + &movd ($rem[1],$Zlo); + &pxor ($Zlo,$tmp); + + push (@rem,shift(@rem)); # "rotate" registers + } + + &mov ($inp,&DWP(4,$rem_4bit,$rem[1],8)); # last rem_4bit[rem] + + &psrlq ($Zlo,32); # lower part of Zlo is already there + &movd ($Zhl,$Zhi); + &psrlq ($Zhi,32); + &movd ($Zlh,$Zlo); + &movd ($Zhh,$Zhi); + &shl ($inp,4); # compensate for rem_4bit[i] being >>4 + + &bswap ($Zll); + &bswap ($Zhl); + &bswap ($Zlh); + &xor ($Zhh,$inp); + &bswap ($Zhh); + + &ret (); +} +&function_end_B("_mmx_gmult_4bit_inner"); + +&function_begin("gcm_gmult_4bit_mmx"); + &mov ($inp,&wparam(0)); # load Xi + &mov ($Htbl,&wparam(1)); # load Htable + + &call (&label("pic_point")); + &set_label("pic_point"); + &blindpop("eax"); + &lea ("eax",&DWP(&label("rem_4bit")."-".&label("pic_point"),"eax")); + + &movz ($Zll,&BP(15,$inp)); + + &call ("_mmx_gmult_4bit_inner"); + + &mov ($inp,&wparam(0)); # load Xi + &emms (); + &mov (&DWP(12,$inp),$Zll); + &mov (&DWP(4,$inp),$Zhl); + &mov (&DWP(8,$inp),$Zlh); + &mov (&DWP(0,$inp),$Zhh); +&function_end("gcm_gmult_4bit_mmx"); + +# Streamed version performs 20% better on P4, 7% on Opteron, +# 10% on Core2 and PIII... +&function_begin("gcm_ghash_4bit_mmx"); + &mov ($Zhh,&wparam(0)); # load Xi + &mov ($Htbl,&wparam(1)); # load Htable + &mov ($inp,&wparam(2)); # load in + &mov ($Zlh,&wparam(3)); # load len + + &call (&label("pic_point")); + &set_label("pic_point"); + &blindpop("eax"); + &lea ("eax",&DWP(&label("rem_4bit")."-".&label("pic_point"),"eax")); + + &add ($Zlh,$inp); + &mov (&wparam(3),$Zlh); # len to point at the end of input + &stack_push(4+1); # +1 for stack alignment + + &mov ($Zll,&DWP(12,$Zhh)); # load Xi[16] + &mov ($Zhl,&DWP(4,$Zhh)); + &mov ($Zlh,&DWP(8,$Zhh)); + &mov ($Zhh,&DWP(0,$Zhh)); + &jmp (&label("mmx_outer_loop")); + + &set_label("mmx_outer_loop",16); + &xor ($Zll,&DWP(12,$inp)); + &xor ($Zhl,&DWP(4,$inp)); + &xor ($Zlh,&DWP(8,$inp)); + &xor ($Zhh,&DWP(0,$inp)); + &mov (&wparam(2),$inp); + &mov (&DWP(12,"esp"),$Zll); + &mov (&DWP(4,"esp"),$Zhl); + &mov (&DWP(8,"esp"),$Zlh); + &mov (&DWP(0,"esp"),$Zhh); + + &mov ($inp,"esp"); + &shr ($Zll,24); + + &call ("_mmx_gmult_4bit_inner"); + + &mov ($inp,&wparam(2)); + &lea ($inp,&DWP(16,$inp)); + &cmp ($inp,&wparam(3)); + &jb (&label("mmx_outer_loop")); + + &mov ($inp,&wparam(0)); # load Xi + &emms (); + &mov (&DWP(12,$inp),$Zll); + &mov (&DWP(4,$inp),$Zhl); + &mov (&DWP(8,$inp),$Zlh); + &mov (&DWP(0,$inp),$Zhh); + + &stack_pop(4+1); +&function_end("gcm_ghash_4bit_mmx"); + +}} else {{ # "June" MMX version... + # ... has slower "April" gcm_gmult_4bit_mmx with folded + # loop. This is done to conserve code size... +$S=16; # shift factor for rem_4bit + +sub mmx_loop() { +# MMX version performs 2.8 times better on P4 (see comment in non-MMX +# routine for further details), 40% better on Opteron and Core2, 50% +# better on PIII... In other words effort is considered to be well +# spent... + my $inp = shift; + my $rem_4bit = shift; + my $cnt = $Zhh; + my $nhi = $Zhl; + my $nlo = $Zlh; + my $rem = $Zll; + + my ($Zlo,$Zhi) = ("mm0","mm1"); + my $tmp = "mm2"; + + &xor ($nlo,$nlo); # avoid partial register stalls on PIII + &mov ($nhi,$Zll); + &mov (&LB($nlo),&LB($nhi)); + &mov ($cnt,14); + &shl (&LB($nlo),4); + &and ($nhi,0xf0); + &movq ($Zlo,&QWP(8,$Htbl,$nlo)); + &movq ($Zhi,&QWP(0,$Htbl,$nlo)); + &movd ($rem,$Zlo); + &jmp (&label("mmx_loop")); + + &set_label("mmx_loop",16); + &psrlq ($Zlo,4); + &and ($rem,0xf); + &movq ($tmp,$Zhi); + &psrlq ($Zhi,4); + &pxor ($Zlo,&QWP(8,$Htbl,$nhi)); + &mov (&LB($nlo),&BP(0,$inp,$cnt)); + &psllq ($tmp,60); + &pxor ($Zhi,&QWP(0,$rem_4bit,$rem,8)); + &dec ($cnt); + &movd ($rem,$Zlo); + &pxor ($Zhi,&QWP(0,$Htbl,$nhi)); + &mov ($nhi,$nlo); + &pxor ($Zlo,$tmp); + &js (&label("mmx_break")); + + &shl (&LB($nlo),4); + &and ($rem,0xf); + &psrlq ($Zlo,4); + &and ($nhi,0xf0); + &movq ($tmp,$Zhi); + &psrlq ($Zhi,4); + &pxor ($Zlo,&QWP(8,$Htbl,$nlo)); + &psllq ($tmp,60); + &pxor ($Zhi,&QWP(0,$rem_4bit,$rem,8)); + &movd ($rem,$Zlo); + &pxor ($Zhi,&QWP(0,$Htbl,$nlo)); + &pxor ($Zlo,$tmp); + &jmp (&label("mmx_loop")); + + &set_label("mmx_break",16); + &shl (&LB($nlo),4); + &and ($rem,0xf); + &psrlq ($Zlo,4); + &and ($nhi,0xf0); + &movq ($tmp,$Zhi); + &psrlq ($Zhi,4); + &pxor ($Zlo,&QWP(8,$Htbl,$nlo)); + &psllq ($tmp,60); + &pxor ($Zhi,&QWP(0,$rem_4bit,$rem,8)); + &movd ($rem,$Zlo); + &pxor ($Zhi,&QWP(0,$Htbl,$nlo)); + &pxor ($Zlo,$tmp); + + &psrlq ($Zlo,4); + &and ($rem,0xf); + &movq ($tmp,$Zhi); + &psrlq ($Zhi,4); + &pxor ($Zlo,&QWP(8,$Htbl,$nhi)); + &psllq ($tmp,60); + &pxor ($Zhi,&QWP(0,$rem_4bit,$rem,8)); + &movd ($rem,$Zlo); + &pxor ($Zhi,&QWP(0,$Htbl,$nhi)); + &pxor ($Zlo,$tmp); + + &psrlq ($Zlo,32); # lower part of Zlo is already there + &movd ($Zhl,$Zhi); + &psrlq ($Zhi,32); + &movd ($Zlh,$Zlo); + &movd ($Zhh,$Zhi); + + &bswap ($Zll); + &bswap ($Zhl); + &bswap ($Zlh); + &bswap ($Zhh); +} + +&function_begin("gcm_gmult_4bit_mmx"); + &mov ($inp,&wparam(0)); # load Xi + &mov ($Htbl,&wparam(1)); # load Htable + + &call (&label("pic_point")); + &set_label("pic_point"); + &blindpop("eax"); + &lea ("eax",&DWP(&label("rem_4bit")."-".&label("pic_point"),"eax")); + + &movz ($Zll,&BP(15,$inp)); + + &mmx_loop($inp,"eax"); + + &emms (); + &mov (&DWP(12,$inp),$Zll); + &mov (&DWP(4,$inp),$Zhl); + &mov (&DWP(8,$inp),$Zlh); + &mov (&DWP(0,$inp),$Zhh); +&function_end("gcm_gmult_4bit_mmx"); + +###################################################################### +# Below subroutine is "528B" variant of "4-bit" GCM GHASH function +# (see gcm128.c for details). It provides further 20-40% performance +# improvement over above mentioned "May" version. + +&static_label("rem_8bit"); + +&function_begin("gcm_ghash_4bit_mmx"); +{ my ($Zlo,$Zhi) = ("mm7","mm6"); + my $rem_8bit = "esi"; + my $Htbl = "ebx"; + + # parameter block + &mov ("eax",&wparam(0)); # Xi + &mov ("ebx",&wparam(1)); # Htable + &mov ("ecx",&wparam(2)); # inp + &mov ("edx",&wparam(3)); # len + &mov ("ebp","esp"); # original %esp + &call (&label("pic_point")); + &set_label ("pic_point"); + &blindpop ($rem_8bit); + &lea ($rem_8bit,&DWP(&label("rem_8bit")."-".&label("pic_point"),$rem_8bit)); + + &sub ("esp",512+16+16); # allocate stack frame... + &and ("esp",-64); # ...and align it + &sub ("esp",16); # place for (u8)(H[]<<4) + + &add ("edx","ecx"); # pointer to the end of input + &mov (&DWP(528+16+0,"esp"),"eax"); # save Xi + &mov (&DWP(528+16+8,"esp"),"edx"); # save inp+len + &mov (&DWP(528+16+12,"esp"),"ebp"); # save original %esp + + { my @lo = ("mm0","mm1","mm2"); + my @hi = ("mm3","mm4","mm5"); + my @tmp = ("mm6","mm7"); + my ($off1,$off2,$i) = (0,0,); + + &add ($Htbl,128); # optimize for size + &lea ("edi",&DWP(16+128,"esp")); + &lea ("ebp",&DWP(16+256+128,"esp")); + + # decompose Htable (low and high parts are kept separately), + # generate Htable[]>>4, (u8)(Htable[]<<4), save to stack... + for ($i=0;$i<18;$i++) { + + &mov ("edx",&DWP(16*$i+8-128,$Htbl)) if ($i<16); + &movq ($lo[0],&QWP(16*$i+8-128,$Htbl)) if ($i<16); + &psllq ($tmp[1],60) if ($i>1); + &movq ($hi[0],&QWP(16*$i+0-128,$Htbl)) if ($i<16); + &por ($lo[2],$tmp[1]) if ($i>1); + &movq (&QWP($off1-128,"edi"),$lo[1]) if ($i>0 && $i<17); + &psrlq ($lo[1],4) if ($i>0 && $i<17); + &movq (&QWP($off1,"edi"),$hi[1]) if ($i>0 && $i<17); + &movq ($tmp[0],$hi[1]) if ($i>0 && $i<17); + &movq (&QWP($off2-128,"ebp"),$lo[2]) if ($i>1); + &psrlq ($hi[1],4) if ($i>0 && $i<17); + &movq (&QWP($off2,"ebp"),$hi[2]) if ($i>1); + &shl ("edx",4) if ($i<16); + &mov (&BP($i,"esp"),&LB("edx")) if ($i<16); + + unshift (@lo,pop(@lo)); # "rotate" registers + unshift (@hi,pop(@hi)); + unshift (@tmp,pop(@tmp)); + $off1 += 8 if ($i>0); + $off2 += 8 if ($i>1); + } + } + + &movq ($Zhi,&QWP(0,"eax")); + &mov ("ebx",&DWP(8,"eax")); + &mov ("edx",&DWP(12,"eax")); # load Xi + +&set_label("outer",16); + { my $nlo = "eax"; + my $dat = "edx"; + my @nhi = ("edi","ebp"); + my @rem = ("ebx","ecx"); + my @red = ("mm0","mm1","mm2"); + my $tmp = "mm3"; + + &xor ($dat,&DWP(12,"ecx")); # merge input data + &xor ("ebx",&DWP(8,"ecx")); + &pxor ($Zhi,&QWP(0,"ecx")); + &lea ("ecx",&DWP(16,"ecx")); # inp+=16 + #&mov (&DWP(528+12,"esp"),$dat); # save inp^Xi + &mov (&DWP(528+8,"esp"),"ebx"); + &movq (&QWP(528+0,"esp"),$Zhi); + &mov (&DWP(528+16+4,"esp"),"ecx"); # save inp + + &xor ($nlo,$nlo); + &rol ($dat,8); + &mov (&LB($nlo),&LB($dat)); + &mov ($nhi[1],$nlo); + &and (&LB($nlo),0x0f); + &shr ($nhi[1],4); + &pxor ($red[0],$red[0]); + &rol ($dat,8); # next byte + &pxor ($red[1],$red[1]); + &pxor ($red[2],$red[2]); + + # Just like in "May" verson modulo-schedule for critical path in + # 'Z.hi ^= rem_8bit[Z.lo&0xff^((u8)H[nhi]<<4)]<<48'. Final 'pxor' + # is scheduled so late that rem_8bit[] has to be shifted *right* + # by 16, which is why last argument to pinsrw is 2, which + # corresponds to <<32=<<48>>16... + for ($j=11,$i=0;$i<15;$i++) { + + if ($i>0) { + &pxor ($Zlo,&QWP(16,"esp",$nlo,8)); # Z^=H[nlo] + &rol ($dat,8); # next byte + &pxor ($Zhi,&QWP(16+128,"esp",$nlo,8)); + + &pxor ($Zlo,$tmp); + &pxor ($Zhi,&QWP(16+256+128,"esp",$nhi[0],8)); + &xor (&LB($rem[1]),&BP(0,"esp",$nhi[0])); # rem^(H[nhi]<<4) + } else { + &movq ($Zlo,&QWP(16,"esp",$nlo,8)); + &movq ($Zhi,&QWP(16+128,"esp",$nlo,8)); + } + + &mov (&LB($nlo),&LB($dat)); + &mov ($dat,&DWP(528+$j,"esp")) if (--$j%4==0); + + &movd ($rem[0],$Zlo); + &movz ($rem[1],&LB($rem[1])) if ($i>0); + &psrlq ($Zlo,8); # Z>>=8 + + &movq ($tmp,$Zhi); + &mov ($nhi[0],$nlo); + &psrlq ($Zhi,8); + + &pxor ($Zlo,&QWP(16+256+0,"esp",$nhi[1],8)); # Z^=H[nhi]>>4 + &and (&LB($nlo),0x0f); + &psllq ($tmp,56); + + &pxor ($Zhi,$red[1]) if ($i>1); + &shr ($nhi[0],4); + &pinsrw ($red[0],&WP(0,$rem_8bit,$rem[1],2),2) if ($i>0); + + unshift (@red,pop(@red)); # "rotate" registers + unshift (@rem,pop(@rem)); + unshift (@nhi,pop(@nhi)); + } + + &pxor ($Zlo,&QWP(16,"esp",$nlo,8)); # Z^=H[nlo] + &pxor ($Zhi,&QWP(16+128,"esp",$nlo,8)); + &xor (&LB($rem[1]),&BP(0,"esp",$nhi[0])); # rem^(H[nhi]<<4) + + &pxor ($Zlo,$tmp); + &pxor ($Zhi,&QWP(16+256+128,"esp",$nhi[0],8)); + &movz ($rem[1],&LB($rem[1])); + + &pxor ($red[2],$red[2]); # clear 2nd word + &psllq ($red[1],4); + + &movd ($rem[0],$Zlo); + &psrlq ($Zlo,4); # Z>>=4 + + &movq ($tmp,$Zhi); + &psrlq ($Zhi,4); + &shl ($rem[0],4); # rem<<4 + + &pxor ($Zlo,&QWP(16,"esp",$nhi[1],8)); # Z^=H[nhi] + &psllq ($tmp,60); + &movz ($rem[0],&LB($rem[0])); + + &pxor ($Zlo,$tmp); + &pxor ($Zhi,&QWP(16+128,"esp",$nhi[1],8)); + + &pinsrw ($red[0],&WP(0,$rem_8bit,$rem[1],2),2); + &pxor ($Zhi,$red[1]); + + &movd ($dat,$Zlo); + &pinsrw ($red[2],&WP(0,$rem_8bit,$rem[0],2),3); # last is <<48 + + &psllq ($red[0],12); # correct by <<16>>4 + &pxor ($Zhi,$red[0]); + &psrlq ($Zlo,32); + &pxor ($Zhi,$red[2]); + + &mov ("ecx",&DWP(528+16+4,"esp")); # restore inp + &movd ("ebx",$Zlo); + &movq ($tmp,$Zhi); # 01234567 + &psllw ($Zhi,8); # 1.3.5.7. + &psrlw ($tmp,8); # .0.2.4.6 + &por ($Zhi,$tmp); # 10325476 + &bswap ($dat); + &pshufw ($Zhi,$Zhi,0b00011011); # 76543210 + &bswap ("ebx"); + + &cmp ("ecx",&DWP(528+16+8,"esp")); # are we done? + &jne (&label("outer")); + } + + &mov ("eax",&DWP(528+16+0,"esp")); # restore Xi + &mov (&DWP(12,"eax"),"edx"); + &mov (&DWP(8,"eax"),"ebx"); + &movq (&QWP(0,"eax"),$Zhi); + + &mov ("esp",&DWP(528+16+12,"esp")); # restore original %esp + &emms (); +} +&function_end("gcm_ghash_4bit_mmx"); +}} + +if ($sse2) {{ +###################################################################### +# PCLMULQDQ version. + +$Xip="eax"; +$Htbl="edx"; +$const="ecx"; +$inp="esi"; +$len="ebx"; + +($Xi,$Xhi)=("xmm0","xmm1"); $Hkey="xmm2"; +($T1,$T2,$T3)=("xmm3","xmm4","xmm5"); +($Xn,$Xhn)=("xmm6","xmm7"); + +&static_label("bswap"); + +sub clmul64x64_T2 { # minimal "register" pressure +my ($Xhi,$Xi,$Hkey,$HK)=@_; + + &movdqa ($Xhi,$Xi); # + &pshufd ($T1,$Xi,0b01001110); + &pshufd ($T2,$Hkey,0b01001110) if (!defined($HK)); + &pxor ($T1,$Xi); # + &pxor ($T2,$Hkey) if (!defined($HK)); + $HK=$T2 if (!defined($HK)); + + &pclmulqdq ($Xi,$Hkey,0x00); ####### + &pclmulqdq ($Xhi,$Hkey,0x11); ####### + &pclmulqdq ($T1,$HK,0x00); ####### + &xorps ($T1,$Xi); # + &xorps ($T1,$Xhi); # + + &movdqa ($T2,$T1); # + &psrldq ($T1,8); + &pslldq ($T2,8); # + &pxor ($Xhi,$T1); + &pxor ($Xi,$T2); # +} + +sub clmul64x64_T3 { +# Even though this subroutine offers visually better ILP, it +# was empirically found to be a tad slower than above version. +# At least in gcm_ghash_clmul context. But it's just as well, +# because loop modulo-scheduling is possible only thanks to +# minimized "register" pressure... +my ($Xhi,$Xi,$Hkey)=@_; + + &movdqa ($T1,$Xi); # + &movdqa ($Xhi,$Xi); + &pclmulqdq ($Xi,$Hkey,0x00); ####### + &pclmulqdq ($Xhi,$Hkey,0x11); ####### + &pshufd ($T2,$T1,0b01001110); # + &pshufd ($T3,$Hkey,0b01001110); + &pxor ($T2,$T1); # + &pxor ($T3,$Hkey); + &pclmulqdq ($T2,$T3,0x00); ####### + &pxor ($T2,$Xi); # + &pxor ($T2,$Xhi); # + + &movdqa ($T3,$T2); # + &psrldq ($T2,8); + &pslldq ($T3,8); # + &pxor ($Xhi,$T2); + &pxor ($Xi,$T3); # +} + +if (1) { # Algorithm 9 with <<1 twist. + # Reduction is shorter and uses only two + # temporary registers, which makes it better + # candidate for interleaving with 64x64 + # multiplication. Pre-modulo-scheduled loop + # was found to be ~20% faster than Algorithm 5 + # below. Algorithm 9 was therefore chosen for + # further optimization... + +sub reduction_alg9 { # 17/11 times faster than Intel version +my ($Xhi,$Xi) = @_; + + # 1st phase + &movdqa ($T2,$Xi); # + &movdqa ($T1,$Xi); + &psllq ($Xi,5); + &pxor ($T1,$Xi); # + &psllq ($Xi,1); + &pxor ($Xi,$T1); # + &psllq ($Xi,57); # + &movdqa ($T1,$Xi); # + &pslldq ($Xi,8); + &psrldq ($T1,8); # + &pxor ($Xi,$T2); + &pxor ($Xhi,$T1); # + + # 2nd phase + &movdqa ($T2,$Xi); + &psrlq ($Xi,1); + &pxor ($Xhi,$T2); # + &pxor ($T2,$Xi); + &psrlq ($Xi,5); + &pxor ($Xi,$T2); # + &psrlq ($Xi,1); # + &pxor ($Xi,$Xhi) # +} + +&function_begin_B("gcm_init_clmul"); + &mov ($Htbl,&wparam(0)); + &mov ($Xip,&wparam(1)); + + &call (&label("pic")); +&set_label("pic"); + &blindpop ($const); + &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const)); + + &movdqu ($Hkey,&QWP(0,$Xip)); + &pshufd ($Hkey,$Hkey,0b01001110);# dword swap + + # <<1 twist + &pshufd ($T2,$Hkey,0b11111111); # broadcast uppermost dword + &movdqa ($T1,$Hkey); + &psllq ($Hkey,1); + &pxor ($T3,$T3); # + &psrlq ($T1,63); + &pcmpgtd ($T3,$T2); # broadcast carry bit + &pslldq ($T1,8); + &por ($Hkey,$T1); # H<<=1 + + # magic reduction + &pand ($T3,&QWP(16,$const)); # 0x1c2_polynomial + &pxor ($Hkey,$T3); # if(carry) H^=0x1c2_polynomial + + # calculate H^2 + &movdqa ($Xi,$Hkey); + &clmul64x64_T2 ($Xhi,$Xi,$Hkey); + &reduction_alg9 ($Xhi,$Xi); + + &pshufd ($T1,$Hkey,0b01001110); + &pshufd ($T2,$Xi,0b01001110); + &pxor ($T1,$Hkey); # Karatsuba pre-processing + &movdqu (&QWP(0,$Htbl),$Hkey); # save H + &pxor ($T2,$Xi); # Karatsuba pre-processing + &movdqu (&QWP(16,$Htbl),$Xi); # save H^2 + &palignr ($T2,$T1,8); # low part is H.lo^H.hi + &movdqu (&QWP(32,$Htbl),$T2); # save Karatsuba "salt" + + &ret (); +&function_end_B("gcm_init_clmul"); + +&function_begin_B("gcm_gmult_clmul"); + &mov ($Xip,&wparam(0)); + &mov ($Htbl,&wparam(1)); + + &call (&label("pic")); +&set_label("pic"); + &blindpop ($const); + &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const)); + + &movdqu ($Xi,&QWP(0,$Xip)); + &movdqa ($T3,&QWP(0,$const)); + &movups ($Hkey,&QWP(0,$Htbl)); + &pshufb ($Xi,$T3); + &movups ($T2,&QWP(32,$Htbl)); + + &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$T2); + &reduction_alg9 ($Xhi,$Xi); + + &pshufb ($Xi,$T3); + &movdqu (&QWP(0,$Xip),$Xi); + + &ret (); +&function_end_B("gcm_gmult_clmul"); + +&function_begin("gcm_ghash_clmul"); + &mov ($Xip,&wparam(0)); + &mov ($Htbl,&wparam(1)); + &mov ($inp,&wparam(2)); + &mov ($len,&wparam(3)); + + &call (&label("pic")); +&set_label("pic"); + &blindpop ($const); + &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const)); + + &movdqu ($Xi,&QWP(0,$Xip)); + &movdqa ($T3,&QWP(0,$const)); + &movdqu ($Hkey,&QWP(0,$Htbl)); + &pshufb ($Xi,$T3); + + &sub ($len,0x10); + &jz (&label("odd_tail")); + + ####### + # Xi+2 =[H*(Ii+1 + Xi+1)] mod P = + # [(H*Ii+1) + (H*Xi+1)] mod P = + # [(H*Ii+1) + H^2*(Ii+Xi)] mod P + # + &movdqu ($T1,&QWP(0,$inp)); # Ii + &movdqu ($Xn,&QWP(16,$inp)); # Ii+1 + &pshufb ($T1,$T3); + &pshufb ($Xn,$T3); + &movdqu ($T3,&QWP(32,$Htbl)); + &pxor ($Xi,$T1); # Ii+Xi + + &pshufd ($T1,$Xn,0b01001110); # H*Ii+1 + &movdqa ($Xhn,$Xn); + &pxor ($T1,$Xn); # + &lea ($inp,&DWP(32,$inp)); # i+=2 + + &pclmulqdq ($Xn,$Hkey,0x00); ####### + &pclmulqdq ($Xhn,$Hkey,0x11); ####### + &pclmulqdq ($T1,$T3,0x00); ####### + &movups ($Hkey,&QWP(16,$Htbl)); # load H^2 + &nop (); + + &sub ($len,0x20); + &jbe (&label("even_tail")); + &jmp (&label("mod_loop")); + +&set_label("mod_loop",32); + &pshufd ($T2,$Xi,0b01001110); # H^2*(Ii+Xi) + &movdqa ($Xhi,$Xi); + &pxor ($T2,$Xi); # + &nop (); + + &pclmulqdq ($Xi,$Hkey,0x00); ####### + &pclmulqdq ($Xhi,$Hkey,0x11); ####### + &pclmulqdq ($T2,$T3,0x10); ####### + &movups ($Hkey,&QWP(0,$Htbl)); # load H + + &xorps ($Xi,$Xn); # (H*Ii+1) + H^2*(Ii+Xi) + &movdqa ($T3,&QWP(0,$const)); + &xorps ($Xhi,$Xhn); + &movdqu ($Xhn,&QWP(0,$inp)); # Ii + &pxor ($T1,$Xi); # aggregated Karatsuba post-processing + &movdqu ($Xn,&QWP(16,$inp)); # Ii+1 + &pxor ($T1,$Xhi); # + + &pshufb ($Xhn,$T3); + &pxor ($T2,$T1); # + + &movdqa ($T1,$T2); # + &psrldq ($T2,8); + &pslldq ($T1,8); # + &pxor ($Xhi,$T2); + &pxor ($Xi,$T1); # + &pshufb ($Xn,$T3); + &pxor ($Xhi,$Xhn); # "Ii+Xi", consume early + + &movdqa ($Xhn,$Xn); #&clmul64x64_TX ($Xhn,$Xn,$Hkey); H*Ii+1 + &movdqa ($T2,$Xi); #&reduction_alg9($Xhi,$Xi); 1st phase + &movdqa ($T1,$Xi); + &psllq ($Xi,5); + &pxor ($T1,$Xi); # + &psllq ($Xi,1); + &pxor ($Xi,$T1); # + &pclmulqdq ($Xn,$Hkey,0x00); ####### + &movups ($T3,&QWP(32,$Htbl)); + &psllq ($Xi,57); # + &movdqa ($T1,$Xi); # + &pslldq ($Xi,8); + &psrldq ($T1,8); # + &pxor ($Xi,$T2); + &pxor ($Xhi,$T1); # + &pshufd ($T1,$Xhn,0b01001110); + &movdqa ($T2,$Xi); # 2nd phase + &psrlq ($Xi,1); + &pxor ($T1,$Xhn); + &pxor ($Xhi,$T2); # + &pclmulqdq ($Xhn,$Hkey,0x11); ####### + &movups ($Hkey,&QWP(16,$Htbl)); # load H^2 + &pxor ($T2,$Xi); + &psrlq ($Xi,5); + &pxor ($Xi,$T2); # + &psrlq ($Xi,1); # + &pxor ($Xi,$Xhi) # + &pclmulqdq ($T1,$T3,0x00); ####### + + &lea ($inp,&DWP(32,$inp)); + &sub ($len,0x20); + &ja (&label("mod_loop")); + +&set_label("even_tail"); + &pshufd ($T2,$Xi,0b01001110); # H^2*(Ii+Xi) + &movdqa ($Xhi,$Xi); + &pxor ($T2,$Xi); # + + &pclmulqdq ($Xi,$Hkey,0x00); ####### + &pclmulqdq ($Xhi,$Hkey,0x11); ####### + &pclmulqdq ($T2,$T3,0x10); ####### + &movdqa ($T3,&QWP(0,$const)); + + &xorps ($Xi,$Xn); # (H*Ii+1) + H^2*(Ii+Xi) + &xorps ($Xhi,$Xhn); + &pxor ($T1,$Xi); # aggregated Karatsuba post-processing + &pxor ($T1,$Xhi); # + + &pxor ($T2,$T1); # + + &movdqa ($T1,$T2); # + &psrldq ($T2,8); + &pslldq ($T1,8); # + &pxor ($Xhi,$T2); + &pxor ($Xi,$T1); # + + &reduction_alg9 ($Xhi,$Xi); + + &test ($len,$len); + &jnz (&label("done")); + + &movups ($Hkey,&QWP(0,$Htbl)); # load H +&set_label("odd_tail"); + &movdqu ($T1,&QWP(0,$inp)); # Ii + &pshufb ($T1,$T3); + &pxor ($Xi,$T1); # Ii+Xi + + &clmul64x64_T2 ($Xhi,$Xi,$Hkey); # H*(Ii+Xi) + &reduction_alg9 ($Xhi,$Xi); + +&set_label("done"); + &pshufb ($Xi,$T3); + &movdqu (&QWP(0,$Xip),$Xi); +&function_end("gcm_ghash_clmul"); + +} else { # Algorith 5. Kept for reference purposes. + +sub reduction_alg5 { # 19/16 times faster than Intel version +my ($Xhi,$Xi)=@_; + + # <<1 + &movdqa ($T1,$Xi); # + &movdqa ($T2,$Xhi); + &pslld ($Xi,1); + &pslld ($Xhi,1); # + &psrld ($T1,31); + &psrld ($T2,31); # + &movdqa ($T3,$T1); + &pslldq ($T1,4); + &psrldq ($T3,12); # + &pslldq ($T2,4); + &por ($Xhi,$T3); # + &por ($Xi,$T1); + &por ($Xhi,$T2); # + + # 1st phase + &movdqa ($T1,$Xi); + &movdqa ($T2,$Xi); + &movdqa ($T3,$Xi); # + &pslld ($T1,31); + &pslld ($T2,30); + &pslld ($Xi,25); # + &pxor ($T1,$T2); + &pxor ($T1,$Xi); # + &movdqa ($T2,$T1); # + &pslldq ($T1,12); + &psrldq ($T2,4); # + &pxor ($T3,$T1); + + # 2nd phase + &pxor ($Xhi,$T3); # + &movdqa ($Xi,$T3); + &movdqa ($T1,$T3); + &psrld ($Xi,1); # + &psrld ($T1,2); + &psrld ($T3,7); # + &pxor ($Xi,$T1); + &pxor ($Xhi,$T2); + &pxor ($Xi,$T3); # + &pxor ($Xi,$Xhi); # +} + +&function_begin_B("gcm_init_clmul"); + &mov ($Htbl,&wparam(0)); + &mov ($Xip,&wparam(1)); + + &call (&label("pic")); +&set_label("pic"); + &blindpop ($const); + &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const)); + + &movdqu ($Hkey,&QWP(0,$Xip)); + &pshufd ($Hkey,$Hkey,0b01001110);# dword swap + + # calculate H^2 + &movdqa ($Xi,$Hkey); + &clmul64x64_T3 ($Xhi,$Xi,$Hkey); + &reduction_alg5 ($Xhi,$Xi); + + &movdqu (&QWP(0,$Htbl),$Hkey); # save H + &movdqu (&QWP(16,$Htbl),$Xi); # save H^2 + + &ret (); +&function_end_B("gcm_init_clmul"); + +&function_begin_B("gcm_gmult_clmul"); + &mov ($Xip,&wparam(0)); + &mov ($Htbl,&wparam(1)); + + &call (&label("pic")); +&set_label("pic"); + &blindpop ($const); + &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const)); + + &movdqu ($Xi,&QWP(0,$Xip)); + &movdqa ($Xn,&QWP(0,$const)); + &movdqu ($Hkey,&QWP(0,$Htbl)); + &pshufb ($Xi,$Xn); + + &clmul64x64_T3 ($Xhi,$Xi,$Hkey); + &reduction_alg5 ($Xhi,$Xi); + + &pshufb ($Xi,$Xn); + &movdqu (&QWP(0,$Xip),$Xi); + + &ret (); +&function_end_B("gcm_gmult_clmul"); + +&function_begin("gcm_ghash_clmul"); + &mov ($Xip,&wparam(0)); + &mov ($Htbl,&wparam(1)); + &mov ($inp,&wparam(2)); + &mov ($len,&wparam(3)); + + &call (&label("pic")); +&set_label("pic"); + &blindpop ($const); + &lea ($const,&DWP(&label("bswap")."-".&label("pic"),$const)); + + &movdqu ($Xi,&QWP(0,$Xip)); + &movdqa ($T3,&QWP(0,$const)); + &movdqu ($Hkey,&QWP(0,$Htbl)); + &pshufb ($Xi,$T3); + + &sub ($len,0x10); + &jz (&label("odd_tail")); + + ####### + # Xi+2 =[H*(Ii+1 + Xi+1)] mod P = + # [(H*Ii+1) + (H*Xi+1)] mod P = + # [(H*Ii+1) + H^2*(Ii+Xi)] mod P + # + &movdqu ($T1,&QWP(0,$inp)); # Ii + &movdqu ($Xn,&QWP(16,$inp)); # Ii+1 + &pshufb ($T1,$T3); + &pshufb ($Xn,$T3); + &pxor ($Xi,$T1); # Ii+Xi + + &clmul64x64_T3 ($Xhn,$Xn,$Hkey); # H*Ii+1 + &movdqu ($Hkey,&QWP(16,$Htbl)); # load H^2 + + &sub ($len,0x20); + &lea ($inp,&DWP(32,$inp)); # i+=2 + &jbe (&label("even_tail")); + +&set_label("mod_loop"); + &clmul64x64_T3 ($Xhi,$Xi,$Hkey); # H^2*(Ii+Xi) + &movdqu ($Hkey,&QWP(0,$Htbl)); # load H + + &pxor ($Xi,$Xn); # (H*Ii+1) + H^2*(Ii+Xi) + &pxor ($Xhi,$Xhn); + + &reduction_alg5 ($Xhi,$Xi); + + ####### + &movdqa ($T3,&QWP(0,$const)); + &movdqu ($T1,&QWP(0,$inp)); # Ii + &movdqu ($Xn,&QWP(16,$inp)); # Ii+1 + &pshufb ($T1,$T3); + &pshufb ($Xn,$T3); + &pxor ($Xi,$T1); # Ii+Xi + + &clmul64x64_T3 ($Xhn,$Xn,$Hkey); # H*Ii+1 + &movdqu ($Hkey,&QWP(16,$Htbl)); # load H^2 + + &sub ($len,0x20); + &lea ($inp,&DWP(32,$inp)); + &ja (&label("mod_loop")); + +&set_label("even_tail"); + &clmul64x64_T3 ($Xhi,$Xi,$Hkey); # H^2*(Ii+Xi) + + &pxor ($Xi,$Xn); # (H*Ii+1) + H^2*(Ii+Xi) + &pxor ($Xhi,$Xhn); + + &reduction_alg5 ($Xhi,$Xi); + + &movdqa ($T3,&QWP(0,$const)); + &test ($len,$len); + &jnz (&label("done")); + + &movdqu ($Hkey,&QWP(0,$Htbl)); # load H +&set_label("odd_tail"); + &movdqu ($T1,&QWP(0,$inp)); # Ii + &pshufb ($T1,$T3); + &pxor ($Xi,$T1); # Ii+Xi + + &clmul64x64_T3 ($Xhi,$Xi,$Hkey); # H*(Ii+Xi) + &reduction_alg5 ($Xhi,$Xi); + + &movdqa ($T3,&QWP(0,$const)); +&set_label("done"); + &pshufb ($Xi,$T3); + &movdqu (&QWP(0,$Xip),$Xi); +&function_end("gcm_ghash_clmul"); + +} + +&set_label("bswap",64); + &data_byte(15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0); + &data_byte(1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc2); # 0x1c2_polynomial +&set_label("rem_8bit",64); + &data_short(0x0000,0x01C2,0x0384,0x0246,0x0708,0x06CA,0x048C,0x054E); + &data_short(0x0E10,0x0FD2,0x0D94,0x0C56,0x0918,0x08DA,0x0A9C,0x0B5E); + &data_short(0x1C20,0x1DE2,0x1FA4,0x1E66,0x1B28,0x1AEA,0x18AC,0x196E); + &data_short(0x1230,0x13F2,0x11B4,0x1076,0x1538,0x14FA,0x16BC,0x177E); + &data_short(0x3840,0x3982,0x3BC4,0x3A06,0x3F48,0x3E8A,0x3CCC,0x3D0E); + &data_short(0x3650,0x3792,0x35D4,0x3416,0x3158,0x309A,0x32DC,0x331E); + &data_short(0x2460,0x25A2,0x27E4,0x2626,0x2368,0x22AA,0x20EC,0x212E); + &data_short(0x2A70,0x2BB2,0x29F4,0x2836,0x2D78,0x2CBA,0x2EFC,0x2F3E); + &data_short(0x7080,0x7142,0x7304,0x72C6,0x7788,0x764A,0x740C,0x75CE); + &data_short(0x7E90,0x7F52,0x7D14,0x7CD6,0x7998,0x785A,0x7A1C,0x7BDE); + &data_short(0x6CA0,0x6D62,0x6F24,0x6EE6,0x6BA8,0x6A6A,0x682C,0x69EE); + &data_short(0x62B0,0x6372,0x6134,0x60F6,0x65B8,0x647A,0x663C,0x67FE); + &data_short(0x48C0,0x4902,0x4B44,0x4A86,0x4FC8,0x4E0A,0x4C4C,0x4D8E); + &data_short(0x46D0,0x4712,0x4554,0x4496,0x41D8,0x401A,0x425C,0x439E); + &data_short(0x54E0,0x5522,0x5764,0x56A6,0x53E8,0x522A,0x506C,0x51AE); + &data_short(0x5AF0,0x5B32,0x5974,0x58B6,0x5DF8,0x5C3A,0x5E7C,0x5FBE); + &data_short(0xE100,0xE0C2,0xE284,0xE346,0xE608,0xE7CA,0xE58C,0xE44E); + &data_short(0xEF10,0xEED2,0xEC94,0xED56,0xE818,0xE9DA,0xEB9C,0xEA5E); + &data_short(0xFD20,0xFCE2,0xFEA4,0xFF66,0xFA28,0xFBEA,0xF9AC,0xF86E); + &data_short(0xF330,0xF2F2,0xF0B4,0xF176,0xF438,0xF5FA,0xF7BC,0xF67E); + &data_short(0xD940,0xD882,0xDAC4,0xDB06,0xDE48,0xDF8A,0xDDCC,0xDC0E); + &data_short(0xD750,0xD692,0xD4D4,0xD516,0xD058,0xD19A,0xD3DC,0xD21E); + &data_short(0xC560,0xC4A2,0xC6E4,0xC726,0xC268,0xC3AA,0xC1EC,0xC02E); + &data_short(0xCB70,0xCAB2,0xC8F4,0xC936,0xCC78,0xCDBA,0xCFFC,0xCE3E); + &data_short(0x9180,0x9042,0x9204,0x93C6,0x9688,0x974A,0x950C,0x94CE); + &data_short(0x9F90,0x9E52,0x9C14,0x9DD6,0x9898,0x995A,0x9B1C,0x9ADE); + &data_short(0x8DA0,0x8C62,0x8E24,0x8FE6,0x8AA8,0x8B6A,0x892C,0x88EE); + &data_short(0x83B0,0x8272,0x8034,0x81F6,0x84B8,0x857A,0x873C,0x86FE); + &data_short(0xA9C0,0xA802,0xAA44,0xAB86,0xAEC8,0xAF0A,0xAD4C,0xAC8E); + &data_short(0xA7D0,0xA612,0xA454,0xA596,0xA0D8,0xA11A,0xA35C,0xA29E); + &data_short(0xB5E0,0xB422,0xB664,0xB7A6,0xB2E8,0xB32A,0xB16C,0xB0AE); + &data_short(0xBBF0,0xBA32,0xB874,0xB9B6,0xBCF8,0xBD3A,0xBF7C,0xBEBE); +}} # $sse2 + +&set_label("rem_4bit",64); + &data_word(0,0x0000<<$S,0,0x1C20<<$S,0,0x3840<<$S,0,0x2460<<$S); + &data_word(0,0x7080<<$S,0,0x6CA0<<$S,0,0x48C0<<$S,0,0x54E0<<$S); + &data_word(0,0xE100<<$S,0,0xFD20<<$S,0,0xD940<<$S,0,0xC560<<$S); + &data_word(0,0x9180<<$S,0,0x8DA0<<$S,0,0xA9C0<<$S,0,0xB5E0<<$S); +}}} # !$x86only + +&asciz("GHASH for x86, CRYPTOGAMS by "); +&asm_finish(); + +# A question was risen about choice of vanilla MMX. Or rather why wasn't +# SSE2 chosen instead? In addition to the fact that MMX runs on legacy +# CPUs such as PIII, "4-bit" MMX version was observed to provide better +# performance than *corresponding* SSE2 one even on contemporary CPUs. +# SSE2 results were provided by Peter-Michael Hager. He maintains SSE2 +# implementation featuring full range of lookup-table sizes, but with +# per-invocation lookup table setup. Latter means that table size is +# chosen depending on how much data is to be hashed in every given call, +# more data - larger table. Best reported result for Core2 is ~4 cycles +# per processed byte out of 64KB block. This number accounts even for +# 64KB table setup overhead. As discussed in gcm128.c we choose to be +# more conservative in respect to lookup table sizes, but how do the +# results compare? Minimalistic "256B" MMX version delivers ~11 cycles +# on same platform. As also discussed in gcm128.c, next in line "8-bit +# Shoup's" or "4KB" method should deliver twice the performance of +# "256B" one, in other words not worse than ~6 cycles per byte. It +# should be also be noted that in SSE2 case improvement can be "super- +# linear," i.e. more than twice, mostly because >>8 maps to single +# instruction on SSE2 register. This is unlike "4-bit" case when >>4 +# maps to same amount of instructions in both MMX and SSE2 cases. +# Bottom line is that switch to SSE2 is considered to be justifiable +# only in case we choose to implement "8-bit" method... diff --git a/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-x86_64.pl new file mode 100644 index 00000000..5a7ce394 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghash-x86_64.pl @@ -0,0 +1,1753 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# March, June 2010 +# +# The module implements "4-bit" GCM GHASH function and underlying +# single multiplication operation in GF(2^128). "4-bit" means that +# it uses 256 bytes per-key table [+128 bytes shared table]. GHASH +# function features so called "528B" variant utilizing additional +# 256+16 bytes of per-key storage [+512 bytes shared table]. +# Performance results are for this streamed GHASH subroutine and are +# expressed in cycles per processed byte, less is better: +# +# gcc 3.4.x(*) assembler +# +# P4 28.6 14.0 +100% +# Opteron 19.3 7.7 +150% +# Core2 17.8 8.1(**) +120% +# Atom 31.6 16.8 +88% +# VIA Nano 21.8 10.1 +115% +# +# (*) comparison is not completely fair, because C results are +# for vanilla "256B" implementation, while assembler results +# are for "528B";-) +# (**) it's mystery [to me] why Core2 result is not same as for +# Opteron; + +# May 2010 +# +# Add PCLMULQDQ version performing at 2.02 cycles per processed byte. +# See ghash-x86.pl for background information and details about coding +# techniques. +# +# Special thanks to David Woodhouse for +# providing access to a Westmere-based system on behalf of Intel +# Open Source Technology Centre. + +# December 2012 +# +# Overhaul: aggregate Karatsuba post-processing, improve ILP in +# reduction_alg9, increase reduction aggregate factor to 4x. As for +# the latter. ghash-x86.pl discusses that it makes lesser sense to +# increase aggregate factor. Then why increase here? Critical path +# consists of 3 independent pclmulqdq instructions, Karatsuba post- +# processing and reduction. "On top" of this we lay down aggregated +# multiplication operations, triplets of independent pclmulqdq's. As +# issue rate for pclmulqdq is limited, it makes lesser sense to +# aggregate more multiplications than it takes to perform remaining +# non-multiplication operations. 2x is near-optimal coefficient for +# contemporary Intel CPUs (therefore modest improvement coefficient), +# but not for Bulldozer. Latter is because logical SIMD operations +# are twice as slow in comparison to Intel, so that critical path is +# longer. A CPU with higher pclmulqdq issue rate would also benefit +# from higher aggregate factor... +# +# Westmere 1.78(+13%) +# Sandy Bridge 1.80(+8%) +# Ivy Bridge 1.80(+7%) +# Haswell 0.55(+93%) (if system doesn't support AVX) +# Broadwell 0.45(+110%)(if system doesn't support AVX) +# Bulldozer 1.49(+27%) +# Silvermont 2.88(+13%) + +# March 2013 +# +# ... 8x aggregate factor AVX code path is using reduction algorithm +# suggested by Shay Gueron[1]. Even though contemporary AVX-capable +# CPUs such as Sandy and Ivy Bridge can execute it, the code performs +# sub-optimally in comparison to above mentioned version. But thanks +# to Ilya Albrekht and Max Locktyukhin of Intel Corp. we knew that +# it performs in 0.41 cycles per byte on Haswell processor, and in +# 0.29 on Broadwell. +# +# [1] http://rt.openssl.org/Ticket/Display.html?id=2900&user=guest&pass=guest + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.19) + ($1>=2.22); +} + +if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.09) + ($1>=2.10); +} + +if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $avx = ($1>=10) + ($1>=11); +} + +if (!$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/) { + $avx = ($2>=3.0) + ($2>3.0); +} + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$do4xaggr=1; + +# common register layout +$nlo="%rax"; +$nhi="%rbx"; +$Zlo="%r8"; +$Zhi="%r9"; +$tmp="%r10"; +$rem_4bit = "%r11"; + +$Xi="%rdi"; +$Htbl="%rsi"; + +# per-function register layout +$cnt="%rcx"; +$rem="%rdx"; + +sub LB() { my $r=shift; $r =~ s/%[er]([a-d])x/%\1l/ or + $r =~ s/%[er]([sd]i)/%\1l/ or + $r =~ s/%[er](bp)/%\1l/ or + $r =~ s/%(r[0-9]+)[d]?/%\1b/; $r; } + +sub AUTOLOAD() # thunk [simplified] 32-bit style perlasm +{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; + my $arg = pop; + $arg = "\$$arg" if ($arg*1 eq $arg); + $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n"; +} + +{ my $N; + sub loop() { + my $inp = shift; + + $N++; +$code.=<<___; + xor $nlo,$nlo + xor $nhi,$nhi + mov `&LB("$Zlo")`,`&LB("$nlo")` + mov `&LB("$Zlo")`,`&LB("$nhi")` + shl \$4,`&LB("$nlo")` + mov \$14,$cnt + mov 8($Htbl,$nlo),$Zlo + mov ($Htbl,$nlo),$Zhi + and \$0xf0,`&LB("$nhi")` + mov $Zlo,$rem + jmp .Loop$N + +.align 16 +.Loop$N: + shr \$4,$Zlo + and \$0xf,$rem + mov $Zhi,$tmp + mov ($inp,$cnt),`&LB("$nlo")` + shr \$4,$Zhi + xor 8($Htbl,$nhi),$Zlo + shl \$60,$tmp + xor ($Htbl,$nhi),$Zhi + mov `&LB("$nlo")`,`&LB("$nhi")` + xor ($rem_4bit,$rem,8),$Zhi + mov $Zlo,$rem + shl \$4,`&LB("$nlo")` + xor $tmp,$Zlo + dec $cnt + js .Lbreak$N + + shr \$4,$Zlo + and \$0xf,$rem + mov $Zhi,$tmp + shr \$4,$Zhi + xor 8($Htbl,$nlo),$Zlo + shl \$60,$tmp + xor ($Htbl,$nlo),$Zhi + and \$0xf0,`&LB("$nhi")` + xor ($rem_4bit,$rem,8),$Zhi + mov $Zlo,$rem + xor $tmp,$Zlo + jmp .Loop$N + +.align 16 +.Lbreak$N: + shr \$4,$Zlo + and \$0xf,$rem + mov $Zhi,$tmp + shr \$4,$Zhi + xor 8($Htbl,$nlo),$Zlo + shl \$60,$tmp + xor ($Htbl,$nlo),$Zhi + and \$0xf0,`&LB("$nhi")` + xor ($rem_4bit,$rem,8),$Zhi + mov $Zlo,$rem + xor $tmp,$Zlo + + shr \$4,$Zlo + and \$0xf,$rem + mov $Zhi,$tmp + shr \$4,$Zhi + xor 8($Htbl,$nhi),$Zlo + shl \$60,$tmp + xor ($Htbl,$nhi),$Zhi + xor $tmp,$Zlo + xor ($rem_4bit,$rem,8),$Zhi + + bswap $Zlo + bswap $Zhi +___ +}} + +$code=<<___; +.text +.extern OPENSSL_ia32cap_P + +.globl gcm_gmult_4bit +.type gcm_gmult_4bit,\@function,2 +.align 16 +gcm_gmult_4bit: + push %rbx + push %rbp # %rbp and %r12 are pushed exclusively in + push %r12 # order to reuse Win64 exception handler... +.Lgmult_prologue: + + movzb 15($Xi),$Zlo + lea .Lrem_4bit(%rip),$rem_4bit +___ + &loop ($Xi); +$code.=<<___; + mov $Zlo,8($Xi) + mov $Zhi,($Xi) + + mov 16(%rsp),%rbx + lea 24(%rsp),%rsp +.Lgmult_epilogue: + ret +.size gcm_gmult_4bit,.-gcm_gmult_4bit +___ + +# per-function register layout +$inp="%rdx"; +$len="%rcx"; +$rem_8bit=$rem_4bit; + +$code.=<<___; +.globl gcm_ghash_4bit +.type gcm_ghash_4bit,\@function,4 +.align 16 +gcm_ghash_4bit: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + sub \$280,%rsp +.Lghash_prologue: + mov $inp,%r14 # reassign couple of args + mov $len,%r15 +___ +{ my $inp="%r14"; + my $dat="%edx"; + my $len="%r15"; + my @nhi=("%ebx","%ecx"); + my @rem=("%r12","%r13"); + my $Hshr4="%rbp"; + + &sub ($Htbl,-128); # size optimization + &lea ($Hshr4,"16+128(%rsp)"); + { my @lo =($nlo,$nhi); + my @hi =($Zlo,$Zhi); + + &xor ($dat,$dat); + for ($i=0,$j=-2;$i<18;$i++,$j++) { + &mov ("$j(%rsp)",&LB($dat)) if ($i>1); + &or ($lo[0],$tmp) if ($i>1); + &mov (&LB($dat),&LB($lo[1])) if ($i>0 && $i<17); + &shr ($lo[1],4) if ($i>0 && $i<17); + &mov ($tmp,$hi[1]) if ($i>0 && $i<17); + &shr ($hi[1],4) if ($i>0 && $i<17); + &mov ("8*$j($Hshr4)",$hi[0]) if ($i>1); + &mov ($hi[0],"16*$i+0-128($Htbl)") if ($i<16); + &shl (&LB($dat),4) if ($i>0 && $i<17); + &mov ("8*$j-128($Hshr4)",$lo[0]) if ($i>1); + &mov ($lo[0],"16*$i+8-128($Htbl)") if ($i<16); + &shl ($tmp,60) if ($i>0 && $i<17); + + push (@lo,shift(@lo)); + push (@hi,shift(@hi)); + } + } + &add ($Htbl,-128); + &mov ($Zlo,"8($Xi)"); + &mov ($Zhi,"0($Xi)"); + &add ($len,$inp); # pointer to the end of data + &lea ($rem_8bit,".Lrem_8bit(%rip)"); + &jmp (".Louter_loop"); + +$code.=".align 16\n.Louter_loop:\n"; + &xor ($Zhi,"($inp)"); + &mov ("%rdx","8($inp)"); + &lea ($inp,"16($inp)"); + &xor ("%rdx",$Zlo); + &mov ("($Xi)",$Zhi); + &mov ("8($Xi)","%rdx"); + &shr ("%rdx",32); + + &xor ($nlo,$nlo); + &rol ($dat,8); + &mov (&LB($nlo),&LB($dat)); + &movz ($nhi[0],&LB($dat)); + &shl (&LB($nlo),4); + &shr ($nhi[0],4); + + for ($j=11,$i=0;$i<15;$i++) { + &rol ($dat,8); + &xor ($Zlo,"8($Htbl,$nlo)") if ($i>0); + &xor ($Zhi,"($Htbl,$nlo)") if ($i>0); + &mov ($Zlo,"8($Htbl,$nlo)") if ($i==0); + &mov ($Zhi,"($Htbl,$nlo)") if ($i==0); + + &mov (&LB($nlo),&LB($dat)); + &xor ($Zlo,$tmp) if ($i>0); + &movzw ($rem[1],"($rem_8bit,$rem[1],2)") if ($i>0); + + &movz ($nhi[1],&LB($dat)); + &shl (&LB($nlo),4); + &movzb ($rem[0],"(%rsp,$nhi[0])"); + + &shr ($nhi[1],4) if ($i<14); + &and ($nhi[1],0xf0) if ($i==14); + &shl ($rem[1],48) if ($i>0); + &xor ($rem[0],$Zlo); + + &mov ($tmp,$Zhi); + &xor ($Zhi,$rem[1]) if ($i>0); + &shr ($Zlo,8); + + &movz ($rem[0],&LB($rem[0])); + &mov ($dat,"$j($Xi)") if (--$j%4==0); + &shr ($Zhi,8); + + &xor ($Zlo,"-128($Hshr4,$nhi[0],8)"); + &shl ($tmp,56); + &xor ($Zhi,"($Hshr4,$nhi[0],8)"); + + unshift (@nhi,pop(@nhi)); # "rotate" registers + unshift (@rem,pop(@rem)); + } + &movzw ($rem[1],"($rem_8bit,$rem[1],2)"); + &xor ($Zlo,"8($Htbl,$nlo)"); + &xor ($Zhi,"($Htbl,$nlo)"); + + &shl ($rem[1],48); + &xor ($Zlo,$tmp); + + &xor ($Zhi,$rem[1]); + &movz ($rem[0],&LB($Zlo)); + &shr ($Zlo,4); + + &mov ($tmp,$Zhi); + &shl (&LB($rem[0]),4); + &shr ($Zhi,4); + + &xor ($Zlo,"8($Htbl,$nhi[0])"); + &movzw ($rem[0],"($rem_8bit,$rem[0],2)"); + &shl ($tmp,60); + + &xor ($Zhi,"($Htbl,$nhi[0])"); + &xor ($Zlo,$tmp); + &shl ($rem[0],48); + + &bswap ($Zlo); + &xor ($Zhi,$rem[0]); + + &bswap ($Zhi); + &cmp ($inp,$len); + &jb (".Louter_loop"); +} +$code.=<<___; + mov $Zlo,8($Xi) + mov $Zhi,($Xi) + + lea 280(%rsp),%rsi + mov 0(%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lghash_epilogue: + ret +.size gcm_ghash_4bit,.-gcm_ghash_4bit +___ + +###################################################################### +# PCLMULQDQ version. + +@_4args=$win64? ("%rcx","%rdx","%r8", "%r9") : # Win64 order + ("%rdi","%rsi","%rdx","%rcx"); # Unix order + +($Xi,$Xhi)=("%xmm0","%xmm1"); $Hkey="%xmm2"; +($T1,$T2,$T3)=("%xmm3","%xmm4","%xmm5"); + +sub clmul64x64_T2 { # minimal register pressure +my ($Xhi,$Xi,$Hkey,$HK)=@_; + +if (!defined($HK)) { $HK = $T2; +$code.=<<___; + movdqa $Xi,$Xhi # + pshufd \$0b01001110,$Xi,$T1 + pshufd \$0b01001110,$Hkey,$T2 + pxor $Xi,$T1 # + pxor $Hkey,$T2 +___ +} else { +$code.=<<___; + movdqa $Xi,$Xhi # + pshufd \$0b01001110,$Xi,$T1 + pxor $Xi,$T1 # +___ +} +$code.=<<___; + pclmulqdq \$0x00,$Hkey,$Xi ####### + pclmulqdq \$0x11,$Hkey,$Xhi ####### + pclmulqdq \$0x00,$HK,$T1 ####### + pxor $Xi,$T1 # + pxor $Xhi,$T1 # + + movdqa $T1,$T2 # + psrldq \$8,$T1 + pslldq \$8,$T2 # + pxor $T1,$Xhi + pxor $T2,$Xi # +___ +} + +sub reduction_alg9 { # 17/11 times faster than Intel version +my ($Xhi,$Xi) = @_; + +$code.=<<___; + # 1st phase + movdqa $Xi,$T2 # + movdqa $Xi,$T1 + psllq \$5,$Xi + pxor $Xi,$T1 # + psllq \$1,$Xi + pxor $T1,$Xi # + psllq \$57,$Xi # + movdqa $Xi,$T1 # + pslldq \$8,$Xi + psrldq \$8,$T1 # + pxor $T2,$Xi + pxor $T1,$Xhi # + + # 2nd phase + movdqa $Xi,$T2 + psrlq \$1,$Xi + pxor $T2,$Xhi # + pxor $Xi,$T2 + psrlq \$5,$Xi + pxor $T2,$Xi # + psrlq \$1,$Xi # + pxor $Xhi,$Xi # +___ +} + +{ my ($Htbl,$Xip)=@_4args; + my $HK="%xmm6"; + +$code.=<<___; +.globl gcm_init_clmul +.type gcm_init_clmul,\@abi-omnipotent +.align 16 +gcm_init_clmul: +.L_init_clmul: +___ +$code.=<<___ if ($win64); +.LSEH_begin_gcm_init_clmul: + # I can't trust assembler to use specific encoding:-( + .byte 0x48,0x83,0xec,0x18 #sub $0x18,%rsp + .byte 0x0f,0x29,0x34,0x24 #movaps %xmm6,(%rsp) +___ +$code.=<<___; + movdqu ($Xip),$Hkey + pshufd \$0b01001110,$Hkey,$Hkey # dword swap + + # <<1 twist + pshufd \$0b11111111,$Hkey,$T2 # broadcast uppermost dword + movdqa $Hkey,$T1 + psllq \$1,$Hkey + pxor $T3,$T3 # + psrlq \$63,$T1 + pcmpgtd $T2,$T3 # broadcast carry bit + pslldq \$8,$T1 + por $T1,$Hkey # H<<=1 + + # magic reduction + pand .L0x1c2_polynomial(%rip),$T3 + pxor $T3,$Hkey # if(carry) H^=0x1c2_polynomial + + # calculate H^2 + pshufd \$0b01001110,$Hkey,$HK + movdqa $Hkey,$Xi + pxor $Hkey,$HK +___ + &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$HK); + &reduction_alg9 ($Xhi,$Xi); +$code.=<<___; + pshufd \$0b01001110,$Hkey,$T1 + pshufd \$0b01001110,$Xi,$T2 + pxor $Hkey,$T1 # Karatsuba pre-processing + movdqu $Hkey,0x00($Htbl) # save H + pxor $Xi,$T2 # Karatsuba pre-processing + movdqu $Xi,0x10($Htbl) # save H^2 + palignr \$8,$T1,$T2 # low part is H.lo^H.hi... + movdqu $T2,0x20($Htbl) # save Karatsuba "salt" +___ +if ($do4xaggr) { + &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$HK); # H^3 + &reduction_alg9 ($Xhi,$Xi); +$code.=<<___; + movdqa $Xi,$T3 +___ + &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$HK); # H^4 + &reduction_alg9 ($Xhi,$Xi); +$code.=<<___; + pshufd \$0b01001110,$T3,$T1 + pshufd \$0b01001110,$Xi,$T2 + pxor $T3,$T1 # Karatsuba pre-processing + movdqu $T3,0x30($Htbl) # save H^3 + pxor $Xi,$T2 # Karatsuba pre-processing + movdqu $Xi,0x40($Htbl) # save H^4 + palignr \$8,$T1,$T2 # low part is H^3.lo^H^3.hi... + movdqu $T2,0x50($Htbl) # save Karatsuba "salt" +___ +} +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + lea 0x18(%rsp),%rsp +.LSEH_end_gcm_init_clmul: +___ +$code.=<<___; + ret +.size gcm_init_clmul,.-gcm_init_clmul +___ +} + +{ my ($Xip,$Htbl)=@_4args; + +$code.=<<___; +.globl gcm_gmult_clmul +.type gcm_gmult_clmul,\@abi-omnipotent +.align 16 +gcm_gmult_clmul: +.L_gmult_clmul: + movdqu ($Xip),$Xi + movdqa .Lbswap_mask(%rip),$T3 + movdqu ($Htbl),$Hkey + movdqu 0x20($Htbl),$T2 + pshufb $T3,$Xi +___ + &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$T2); +$code.=<<___ if (0 || (&reduction_alg9($Xhi,$Xi)&&0)); + # experimental alternative. special thing about is that there + # no dependency between the two multiplications... + mov \$`0xE1<<1`,%eax + mov \$0xA040608020C0E000,%r10 # ((7..0)·0xE0)&0xff + mov \$0x07,%r11d + movq %rax,$T1 + movq %r10,$T2 + movq %r11,$T3 # borrow $T3 + pand $Xi,$T3 + pshufb $T3,$T2 # ($Xi&7)·0xE0 + movq %rax,$T3 + pclmulqdq \$0x00,$Xi,$T1 # ·(0xE1<<1) + pxor $Xi,$T2 + pslldq \$15,$T2 + paddd $T2,$T2 # <<(64+56+1) + pxor $T2,$Xi + pclmulqdq \$0x01,$T3,$Xi + movdqa .Lbswap_mask(%rip),$T3 # reload $T3 + psrldq \$1,$T1 + pxor $T1,$Xhi + pslldq \$7,$Xi + pxor $Xhi,$Xi +___ +$code.=<<___; + pshufb $T3,$Xi + movdqu $Xi,($Xip) + ret +.size gcm_gmult_clmul,.-gcm_gmult_clmul +___ +} + +{ my ($Xip,$Htbl,$inp,$len)=@_4args; + my ($Xln,$Xmn,$Xhn,$Hkey2,$HK) = map("%xmm$_",(3..7)); + my ($T1,$T2,$T3)=map("%xmm$_",(8..10)); + +$code.=<<___; +.globl gcm_ghash_clmul +.type gcm_ghash_clmul,\@abi-omnipotent +.align 32 +gcm_ghash_clmul: +.L_ghash_clmul: +___ +$code.=<<___ if ($win64); + lea -0x88(%rsp),%rax +.LSEH_begin_gcm_ghash_clmul: + # I can't trust assembler to use specific encoding:-( + .byte 0x48,0x8d,0x60,0xe0 #lea -0x20(%rax),%rsp + .byte 0x0f,0x29,0x70,0xe0 #movaps %xmm6,-0x20(%rax) + .byte 0x0f,0x29,0x78,0xf0 #movaps %xmm7,-0x10(%rax) + .byte 0x44,0x0f,0x29,0x00 #movaps %xmm8,0(%rax) + .byte 0x44,0x0f,0x29,0x48,0x10 #movaps %xmm9,0x10(%rax) + .byte 0x44,0x0f,0x29,0x50,0x20 #movaps %xmm10,0x20(%rax) + .byte 0x44,0x0f,0x29,0x58,0x30 #movaps %xmm11,0x30(%rax) + .byte 0x44,0x0f,0x29,0x60,0x40 #movaps %xmm12,0x40(%rax) + .byte 0x44,0x0f,0x29,0x68,0x50 #movaps %xmm13,0x50(%rax) + .byte 0x44,0x0f,0x29,0x70,0x60 #movaps %xmm14,0x60(%rax) + .byte 0x44,0x0f,0x29,0x78,0x70 #movaps %xmm15,0x70(%rax) +___ +$code.=<<___; + movdqa .Lbswap_mask(%rip),$T3 + + movdqu ($Xip),$Xi + movdqu ($Htbl),$Hkey + movdqu 0x20($Htbl),$HK + pshufb $T3,$Xi + + sub \$0x10,$len + jz .Lodd_tail + + movdqu 0x10($Htbl),$Hkey2 +___ +if ($do4xaggr) { +my ($Xl,$Xm,$Xh,$Hkey3,$Hkey4)=map("%xmm$_",(11..15)); + +$code.=<<___; + mov OPENSSL_ia32cap_P+4(%rip),%eax + cmp \$0x30,$len + jb .Lskip4x + + and \$`1<<26|1<<22`,%eax # isolate MOVBE+XSAVE + cmp \$`1<<22`,%eax # check for MOVBE without XSAVE + je .Lskip4x + + sub \$0x30,$len + mov \$0xA040608020C0E000,%rax # ((7..0)·0xE0)&0xff + movdqu 0x30($Htbl),$Hkey3 + movdqu 0x40($Htbl),$Hkey4 + + ####### + # Xi+4 =[(H*Ii+3) + (H^2*Ii+2) + (H^3*Ii+1) + H^4*(Ii+Xi)] mod P + # + movdqu 0x30($inp),$Xln + movdqu 0x20($inp),$Xl + pshufb $T3,$Xln + pshufb $T3,$Xl + movdqa $Xln,$Xhn + pshufd \$0b01001110,$Xln,$Xmn + pxor $Xln,$Xmn + pclmulqdq \$0x00,$Hkey,$Xln + pclmulqdq \$0x11,$Hkey,$Xhn + pclmulqdq \$0x00,$HK,$Xmn + + movdqa $Xl,$Xh + pshufd \$0b01001110,$Xl,$Xm + pxor $Xl,$Xm + pclmulqdq \$0x00,$Hkey2,$Xl + pclmulqdq \$0x11,$Hkey2,$Xh + pclmulqdq \$0x10,$HK,$Xm + xorps $Xl,$Xln + xorps $Xh,$Xhn + movups 0x50($Htbl),$HK + xorps $Xm,$Xmn + + movdqu 0x10($inp),$Xl + movdqu 0($inp),$T1 + pshufb $T3,$Xl + pshufb $T3,$T1 + movdqa $Xl,$Xh + pshufd \$0b01001110,$Xl,$Xm + pxor $T1,$Xi + pxor $Xl,$Xm + pclmulqdq \$0x00,$Hkey3,$Xl + movdqa $Xi,$Xhi + pshufd \$0b01001110,$Xi,$T1 + pxor $Xi,$T1 + pclmulqdq \$0x11,$Hkey3,$Xh + pclmulqdq \$0x00,$HK,$Xm + xorps $Xl,$Xln + xorps $Xh,$Xhn + + lea 0x40($inp),$inp + sub \$0x40,$len + jc .Ltail4x + + jmp .Lmod4_loop +.align 32 +.Lmod4_loop: + pclmulqdq \$0x00,$Hkey4,$Xi + xorps $Xm,$Xmn + movdqu 0x30($inp),$Xl + pshufb $T3,$Xl + pclmulqdq \$0x11,$Hkey4,$Xhi + xorps $Xln,$Xi + movdqu 0x20($inp),$Xln + movdqa $Xl,$Xh + pclmulqdq \$0x10,$HK,$T1 + pshufd \$0b01001110,$Xl,$Xm + xorps $Xhn,$Xhi + pxor $Xl,$Xm + pshufb $T3,$Xln + movups 0x20($Htbl),$HK + xorps $Xmn,$T1 + pclmulqdq \$0x00,$Hkey,$Xl + pshufd \$0b01001110,$Xln,$Xmn + + pxor $Xi,$T1 # aggregated Karatsuba post-processing + movdqa $Xln,$Xhn + pxor $Xhi,$T1 # + pxor $Xln,$Xmn + movdqa $T1,$T2 # + pclmulqdq \$0x11,$Hkey,$Xh + pslldq \$8,$T1 + psrldq \$8,$T2 # + pxor $T1,$Xi + movdqa .L7_mask(%rip),$T1 + pxor $T2,$Xhi # + movq %rax,$T2 + + pand $Xi,$T1 # 1st phase + pshufb $T1,$T2 # + pxor $Xi,$T2 # + pclmulqdq \$0x00,$HK,$Xm + psllq \$57,$T2 # + movdqa $T2,$T1 # + pslldq \$8,$T2 + pclmulqdq \$0x00,$Hkey2,$Xln + psrldq \$8,$T1 # + pxor $T2,$Xi + pxor $T1,$Xhi # + movdqu 0($inp),$T1 + + movdqa $Xi,$T2 # 2nd phase + psrlq \$1,$Xi + pclmulqdq \$0x11,$Hkey2,$Xhn + xorps $Xl,$Xln + movdqu 0x10($inp),$Xl + pshufb $T3,$Xl + pclmulqdq \$0x10,$HK,$Xmn + xorps $Xh,$Xhn + movups 0x50($Htbl),$HK + pshufb $T3,$T1 + pxor $T2,$Xhi # + pxor $Xi,$T2 + psrlq \$5,$Xi + + movdqa $Xl,$Xh + pxor $Xm,$Xmn + pshufd \$0b01001110,$Xl,$Xm + pxor $T2,$Xi # + pxor $T1,$Xhi + pxor $Xl,$Xm + pclmulqdq \$0x00,$Hkey3,$Xl + psrlq \$1,$Xi # + pxor $Xhi,$Xi # + movdqa $Xi,$Xhi + pclmulqdq \$0x11,$Hkey3,$Xh + xorps $Xl,$Xln + pshufd \$0b01001110,$Xi,$T1 + pxor $Xi,$T1 + + pclmulqdq \$0x00,$HK,$Xm + xorps $Xh,$Xhn + + lea 0x40($inp),$inp + sub \$0x40,$len + jnc .Lmod4_loop + +.Ltail4x: + pclmulqdq \$0x00,$Hkey4,$Xi + pclmulqdq \$0x11,$Hkey4,$Xhi + pclmulqdq \$0x10,$HK,$T1 + xorps $Xm,$Xmn + xorps $Xln,$Xi + xorps $Xhn,$Xhi + pxor $Xi,$Xhi # aggregated Karatsuba post-processing + pxor $Xmn,$T1 + + pxor $Xhi,$T1 # + pxor $Xi,$Xhi + + movdqa $T1,$T2 # + psrldq \$8,$T1 + pslldq \$8,$T2 # + pxor $T1,$Xhi + pxor $T2,$Xi # +___ + &reduction_alg9($Xhi,$Xi); +$code.=<<___; + add \$0x40,$len + jz .Ldone + movdqu 0x20($Htbl),$HK + sub \$0x10,$len + jz .Lodd_tail +.Lskip4x: +___ +} +$code.=<<___; + ####### + # Xi+2 =[H*(Ii+1 + Xi+1)] mod P = + # [(H*Ii+1) + (H*Xi+1)] mod P = + # [(H*Ii+1) + H^2*(Ii+Xi)] mod P + # + movdqu ($inp),$T1 # Ii + movdqu 16($inp),$Xln # Ii+1 + pshufb $T3,$T1 + pshufb $T3,$Xln + pxor $T1,$Xi # Ii+Xi + + movdqa $Xln,$Xhn + pshufd \$0b01001110,$Xln,$Xmn + pxor $Xln,$Xmn + pclmulqdq \$0x00,$Hkey,$Xln + pclmulqdq \$0x11,$Hkey,$Xhn + pclmulqdq \$0x00,$HK,$Xmn + + lea 32($inp),$inp # i+=2 + nop + sub \$0x20,$len + jbe .Leven_tail + nop + jmp .Lmod_loop + +.align 32 +.Lmod_loop: + movdqa $Xi,$Xhi + movdqa $Xmn,$T1 + pshufd \$0b01001110,$Xi,$Xmn # + pxor $Xi,$Xmn # + + pclmulqdq \$0x00,$Hkey2,$Xi + pclmulqdq \$0x11,$Hkey2,$Xhi + pclmulqdq \$0x10,$HK,$Xmn + + pxor $Xln,$Xi # (H*Ii+1) + H^2*(Ii+Xi) + pxor $Xhn,$Xhi + movdqu ($inp),$T2 # Ii + pxor $Xi,$T1 # aggregated Karatsuba post-processing + pshufb $T3,$T2 + movdqu 16($inp),$Xln # Ii+1 + + pxor $Xhi,$T1 + pxor $T2,$Xhi # "Ii+Xi", consume early + pxor $T1,$Xmn + pshufb $T3,$Xln + movdqa $Xmn,$T1 # + psrldq \$8,$T1 + pslldq \$8,$Xmn # + pxor $T1,$Xhi + pxor $Xmn,$Xi # + + movdqa $Xln,$Xhn # + + movdqa $Xi,$T2 # 1st phase + movdqa $Xi,$T1 + psllq \$5,$Xi + pxor $Xi,$T1 # + pclmulqdq \$0x00,$Hkey,$Xln ####### + psllq \$1,$Xi + pxor $T1,$Xi # + psllq \$57,$Xi # + movdqa $Xi,$T1 # + pslldq \$8,$Xi + psrldq \$8,$T1 # + pxor $T2,$Xi + pshufd \$0b01001110,$Xhn,$Xmn + pxor $T1,$Xhi # + pxor $Xhn,$Xmn # + + movdqa $Xi,$T2 # 2nd phase + psrlq \$1,$Xi + pclmulqdq \$0x11,$Hkey,$Xhn ####### + pxor $T2,$Xhi # + pxor $Xi,$T2 + psrlq \$5,$Xi + pxor $T2,$Xi # + lea 32($inp),$inp + psrlq \$1,$Xi # + pclmulqdq \$0x00,$HK,$Xmn ####### + pxor $Xhi,$Xi # + + sub \$0x20,$len + ja .Lmod_loop + +.Leven_tail: + movdqa $Xi,$Xhi + movdqa $Xmn,$T1 + pshufd \$0b01001110,$Xi,$Xmn # + pxor $Xi,$Xmn # + + pclmulqdq \$0x00,$Hkey2,$Xi + pclmulqdq \$0x11,$Hkey2,$Xhi + pclmulqdq \$0x10,$HK,$Xmn + + pxor $Xln,$Xi # (H*Ii+1) + H^2*(Ii+Xi) + pxor $Xhn,$Xhi + pxor $Xi,$T1 + pxor $Xhi,$T1 + pxor $T1,$Xmn + movdqa $Xmn,$T1 # + psrldq \$8,$T1 + pslldq \$8,$Xmn # + pxor $T1,$Xhi + pxor $Xmn,$Xi # +___ + &reduction_alg9 ($Xhi,$Xi); +$code.=<<___; + test $len,$len + jnz .Ldone + +.Lodd_tail: + movdqu ($inp),$T1 # Ii + pshufb $T3,$T1 + pxor $T1,$Xi # Ii+Xi +___ + &clmul64x64_T2 ($Xhi,$Xi,$Hkey,$HK); # H*(Ii+Xi) + &reduction_alg9 ($Xhi,$Xi); +$code.=<<___; +.Ldone: + pshufb $T3,$Xi + movdqu $Xi,($Xip) +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + movaps 0x10(%rsp),%xmm7 + movaps 0x20(%rsp),%xmm8 + movaps 0x30(%rsp),%xmm9 + movaps 0x40(%rsp),%xmm10 + movaps 0x50(%rsp),%xmm11 + movaps 0x60(%rsp),%xmm12 + movaps 0x70(%rsp),%xmm13 + movaps 0x80(%rsp),%xmm14 + movaps 0x90(%rsp),%xmm15 + lea 0xa8(%rsp),%rsp +.LSEH_end_gcm_ghash_clmul: +___ +$code.=<<___; + ret +.size gcm_ghash_clmul,.-gcm_ghash_clmul +___ +} + +$code.=<<___; +.globl gcm_init_avx +.type gcm_init_avx,\@abi-omnipotent +.align 32 +gcm_init_avx: +___ +if ($avx) { +my ($Htbl,$Xip)=@_4args; +my $HK="%xmm6"; + +$code.=<<___ if ($win64); +.LSEH_begin_gcm_init_avx: + # I can't trust assembler to use specific encoding:-( + .byte 0x48,0x83,0xec,0x18 #sub $0x18,%rsp + .byte 0x0f,0x29,0x34,0x24 #movaps %xmm6,(%rsp) +___ +$code.=<<___; + vzeroupper + + vmovdqu ($Xip),$Hkey + vpshufd \$0b01001110,$Hkey,$Hkey # dword swap + + # <<1 twist + vpshufd \$0b11111111,$Hkey,$T2 # broadcast uppermost dword + vpsrlq \$63,$Hkey,$T1 + vpsllq \$1,$Hkey,$Hkey + vpxor $T3,$T3,$T3 # + vpcmpgtd $T2,$T3,$T3 # broadcast carry bit + vpslldq \$8,$T1,$T1 + vpor $T1,$Hkey,$Hkey # H<<=1 + + # magic reduction + vpand .L0x1c2_polynomial(%rip),$T3,$T3 + vpxor $T3,$Hkey,$Hkey # if(carry) H^=0x1c2_polynomial + + vpunpckhqdq $Hkey,$Hkey,$HK + vmovdqa $Hkey,$Xi + vpxor $Hkey,$HK,$HK + mov \$4,%r10 # up to H^8 + jmp .Linit_start_avx +___ + +sub clmul64x64_avx { +my ($Xhi,$Xi,$Hkey,$HK)=@_; + +if (!defined($HK)) { $HK = $T2; +$code.=<<___; + vpunpckhqdq $Xi,$Xi,$T1 + vpunpckhqdq $Hkey,$Hkey,$T2 + vpxor $Xi,$T1,$T1 # + vpxor $Hkey,$T2,$T2 +___ +} else { +$code.=<<___; + vpunpckhqdq $Xi,$Xi,$T1 + vpxor $Xi,$T1,$T1 # +___ +} +$code.=<<___; + vpclmulqdq \$0x11,$Hkey,$Xi,$Xhi ####### + vpclmulqdq \$0x00,$Hkey,$Xi,$Xi ####### + vpclmulqdq \$0x00,$HK,$T1,$T1 ####### + vpxor $Xi,$Xhi,$T2 # + vpxor $T2,$T1,$T1 # + + vpslldq \$8,$T1,$T2 # + vpsrldq \$8,$T1,$T1 + vpxor $T2,$Xi,$Xi # + vpxor $T1,$Xhi,$Xhi +___ +} + +sub reduction_avx { +my ($Xhi,$Xi) = @_; + +$code.=<<___; + vpsllq \$57,$Xi,$T1 # 1st phase + vpsllq \$62,$Xi,$T2 + vpxor $T1,$T2,$T2 # + vpsllq \$63,$Xi,$T1 + vpxor $T1,$T2,$T2 # + vpslldq \$8,$T2,$T1 # + vpsrldq \$8,$T2,$T2 + vpxor $T1,$Xi,$Xi # + vpxor $T2,$Xhi,$Xhi + + vpsrlq \$1,$Xi,$T2 # 2nd phase + vpxor $Xi,$Xhi,$Xhi + vpxor $T2,$Xi,$Xi # + vpsrlq \$5,$T2,$T2 + vpxor $T2,$Xi,$Xi # + vpsrlq \$1,$Xi,$Xi # + vpxor $Xhi,$Xi,$Xi # +___ +} + +$code.=<<___; +.align 32 +.Linit_loop_avx: + vpalignr \$8,$T1,$T2,$T3 # low part is H.lo^H.hi... + vmovdqu $T3,-0x10($Htbl) # save Karatsuba "salt" +___ + &clmul64x64_avx ($Xhi,$Xi,$Hkey,$HK); # calculate H^3,5,7 + &reduction_avx ($Xhi,$Xi); +$code.=<<___; +.Linit_start_avx: + vmovdqa $Xi,$T3 +___ + &clmul64x64_avx ($Xhi,$Xi,$Hkey,$HK); # calculate H^2,4,6,8 + &reduction_avx ($Xhi,$Xi); +$code.=<<___; + vpshufd \$0b01001110,$T3,$T1 + vpshufd \$0b01001110,$Xi,$T2 + vpxor $T3,$T1,$T1 # Karatsuba pre-processing + vmovdqu $T3,0x00($Htbl) # save H^1,3,5,7 + vpxor $Xi,$T2,$T2 # Karatsuba pre-processing + vmovdqu $Xi,0x10($Htbl) # save H^2,4,6,8 + lea 0x30($Htbl),$Htbl + sub \$1,%r10 + jnz .Linit_loop_avx + + vpalignr \$8,$T2,$T1,$T3 # last "salt" is flipped + vmovdqu $T3,-0x10($Htbl) + + vzeroupper +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + lea 0x18(%rsp),%rsp +.LSEH_end_gcm_init_avx: +___ +$code.=<<___; + ret +.size gcm_init_avx,.-gcm_init_avx +___ +} else { +$code.=<<___; + jmp .L_init_clmul +.size gcm_init_avx,.-gcm_init_avx +___ +} + +$code.=<<___; +.globl gcm_gmult_avx +.type gcm_gmult_avx,\@abi-omnipotent +.align 32 +gcm_gmult_avx: + jmp .L_gmult_clmul +.size gcm_gmult_avx,.-gcm_gmult_avx +___ + +$code.=<<___; +.globl gcm_ghash_avx +.type gcm_ghash_avx,\@abi-omnipotent +.align 32 +gcm_ghash_avx: +___ +if ($avx) { +my ($Xip,$Htbl,$inp,$len)=@_4args; +my ($Xlo,$Xhi,$Xmi, + $Zlo,$Zhi,$Zmi, + $Hkey,$HK,$T1,$T2, + $Xi,$Xo,$Tred,$bswap,$Ii,$Ij) = map("%xmm$_",(0..15)); + +$code.=<<___ if ($win64); + lea -0x88(%rsp),%rax +.LSEH_begin_gcm_ghash_avx: + # I can't trust assembler to use specific encoding:-( + .byte 0x48,0x8d,0x60,0xe0 #lea -0x20(%rax),%rsp + .byte 0x0f,0x29,0x70,0xe0 #movaps %xmm6,-0x20(%rax) + .byte 0x0f,0x29,0x78,0xf0 #movaps %xmm7,-0x10(%rax) + .byte 0x44,0x0f,0x29,0x00 #movaps %xmm8,0(%rax) + .byte 0x44,0x0f,0x29,0x48,0x10 #movaps %xmm9,0x10(%rax) + .byte 0x44,0x0f,0x29,0x50,0x20 #movaps %xmm10,0x20(%rax) + .byte 0x44,0x0f,0x29,0x58,0x30 #movaps %xmm11,0x30(%rax) + .byte 0x44,0x0f,0x29,0x60,0x40 #movaps %xmm12,0x40(%rax) + .byte 0x44,0x0f,0x29,0x68,0x50 #movaps %xmm13,0x50(%rax) + .byte 0x44,0x0f,0x29,0x70,0x60 #movaps %xmm14,0x60(%rax) + .byte 0x44,0x0f,0x29,0x78,0x70 #movaps %xmm15,0x70(%rax) +___ +$code.=<<___; + vzeroupper + + vmovdqu ($Xip),$Xi # load $Xi + lea .L0x1c2_polynomial(%rip),%r10 + lea 0x40($Htbl),$Htbl # size optimization + vmovdqu .Lbswap_mask(%rip),$bswap + vpshufb $bswap,$Xi,$Xi + cmp \$0x80,$len + jb .Lshort_avx + sub \$0x80,$len + + vmovdqu 0x70($inp),$Ii # I[7] + vmovdqu 0x00-0x40($Htbl),$Hkey # $Hkey^1 + vpshufb $bswap,$Ii,$Ii + vmovdqu 0x20-0x40($Htbl),$HK + + vpunpckhqdq $Ii,$Ii,$T2 + vmovdqu 0x60($inp),$Ij # I[6] + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpxor $Ii,$T2,$T2 + vpshufb $bswap,$Ij,$Ij + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vmovdqu 0x10-0x40($Htbl),$Hkey # $Hkey^2 + vpunpckhqdq $Ij,$Ij,$T1 + vmovdqu 0x50($inp),$Ii # I[5] + vpclmulqdq \$0x00,$HK,$T2,$Xmi + vpxor $Ij,$T1,$T1 + + vpshufb $bswap,$Ii,$Ii + vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo + vpunpckhqdq $Ii,$Ii,$T2 + vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi + vmovdqu 0x30-0x40($Htbl),$Hkey # $Hkey^3 + vpxor $Ii,$T2,$T2 + vmovdqu 0x40($inp),$Ij # I[4] + vpclmulqdq \$0x10,$HK,$T1,$Zmi + vmovdqu 0x50-0x40($Htbl),$HK + + vpshufb $bswap,$Ij,$Ij + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpxor $Xhi,$Zhi,$Zhi + vpunpckhqdq $Ij,$Ij,$T1 + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vmovdqu 0x40-0x40($Htbl),$Hkey # $Hkey^4 + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T2,$Xmi + vpxor $Ij,$T1,$T1 + + vmovdqu 0x30($inp),$Ii # I[3] + vpxor $Zlo,$Xlo,$Xlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo + vpxor $Zhi,$Xhi,$Xhi + vpshufb $bswap,$Ii,$Ii + vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi + vmovdqu 0x60-0x40($Htbl),$Hkey # $Hkey^5 + vpxor $Zmi,$Xmi,$Xmi + vpunpckhqdq $Ii,$Ii,$T2 + vpclmulqdq \$0x10,$HK,$T1,$Zmi + vmovdqu 0x80-0x40($Htbl),$HK + vpxor $Ii,$T2,$T2 + + vmovdqu 0x20($inp),$Ij # I[2] + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpxor $Xhi,$Zhi,$Zhi + vpshufb $bswap,$Ij,$Ij + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vmovdqu 0x70-0x40($Htbl),$Hkey # $Hkey^6 + vpxor $Xmi,$Zmi,$Zmi + vpunpckhqdq $Ij,$Ij,$T1 + vpclmulqdq \$0x00,$HK,$T2,$Xmi + vpxor $Ij,$T1,$T1 + + vmovdqu 0x10($inp),$Ii # I[1] + vpxor $Zlo,$Xlo,$Xlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo + vpxor $Zhi,$Xhi,$Xhi + vpshufb $bswap,$Ii,$Ii + vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi + vmovdqu 0x90-0x40($Htbl),$Hkey # $Hkey^7 + vpxor $Zmi,$Xmi,$Xmi + vpunpckhqdq $Ii,$Ii,$T2 + vpclmulqdq \$0x10,$HK,$T1,$Zmi + vmovdqu 0xb0-0x40($Htbl),$HK + vpxor $Ii,$T2,$T2 + + vmovdqu ($inp),$Ij # I[0] + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpxor $Xhi,$Zhi,$Zhi + vpshufb $bswap,$Ij,$Ij + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vmovdqu 0xa0-0x40($Htbl),$Hkey # $Hkey^8 + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x10,$HK,$T2,$Xmi + + lea 0x80($inp),$inp + cmp \$0x80,$len + jb .Ltail_avx + + vpxor $Xi,$Ij,$Ij # accumulate $Xi + sub \$0x80,$len + jmp .Loop8x_avx + +.align 32 +.Loop8x_avx: + vpunpckhqdq $Ij,$Ij,$T1 + vmovdqu 0x70($inp),$Ii # I[7] + vpxor $Xlo,$Zlo,$Zlo + vpxor $Ij,$T1,$T1 + vpclmulqdq \$0x00,$Hkey,$Ij,$Xi + vpshufb $bswap,$Ii,$Ii + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xo + vmovdqu 0x00-0x40($Htbl),$Hkey # $Hkey^1 + vpunpckhqdq $Ii,$Ii,$T2 + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Tred + vmovdqu 0x20-0x40($Htbl),$HK + vpxor $Ii,$T2,$T2 + + vmovdqu 0x60($inp),$Ij # I[6] + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpxor $Zlo,$Xi,$Xi # collect result + vpshufb $bswap,$Ij,$Ij + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vxorps $Zhi,$Xo,$Xo + vmovdqu 0x10-0x40($Htbl),$Hkey # $Hkey^2 + vpunpckhqdq $Ij,$Ij,$T1 + vpclmulqdq \$0x00,$HK, $T2,$Xmi + vpxor $Zmi,$Tred,$Tred + vxorps $Ij,$T1,$T1 + + vmovdqu 0x50($inp),$Ii # I[5] + vpxor $Xi,$Tred,$Tred # aggregated Karatsuba post-processing + vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo + vpxor $Xo,$Tred,$Tred + vpslldq \$8,$Tred,$T2 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi + vpsrldq \$8,$Tred,$Tred + vpxor $T2, $Xi, $Xi + vmovdqu 0x30-0x40($Htbl),$Hkey # $Hkey^3 + vpshufb $bswap,$Ii,$Ii + vxorps $Tred,$Xo, $Xo + vpxor $Xhi,$Zhi,$Zhi + vpunpckhqdq $Ii,$Ii,$T2 + vpclmulqdq \$0x10,$HK, $T1,$Zmi + vmovdqu 0x50-0x40($Htbl),$HK + vpxor $Ii,$T2,$T2 + vpxor $Xmi,$Zmi,$Zmi + + vmovdqu 0x40($inp),$Ij # I[4] + vpalignr \$8,$Xi,$Xi,$Tred # 1st phase + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpshufb $bswap,$Ij,$Ij + vpxor $Zlo,$Xlo,$Xlo + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vmovdqu 0x40-0x40($Htbl),$Hkey # $Hkey^4 + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Zhi,$Xhi,$Xhi + vpclmulqdq \$0x00,$HK, $T2,$Xmi + vxorps $Ij,$T1,$T1 + vpxor $Zmi,$Xmi,$Xmi + + vmovdqu 0x30($inp),$Ii # I[3] + vpclmulqdq \$0x10,(%r10),$Xi,$Xi + vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo + vpshufb $bswap,$Ii,$Ii + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi + vmovdqu 0x60-0x40($Htbl),$Hkey # $Hkey^5 + vpunpckhqdq $Ii,$Ii,$T2 + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x10,$HK, $T1,$Zmi + vmovdqu 0x80-0x40($Htbl),$HK + vpxor $Ii,$T2,$T2 + vpxor $Xmi,$Zmi,$Zmi + + vmovdqu 0x20($inp),$Ij # I[2] + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpshufb $bswap,$Ij,$Ij + vpxor $Zlo,$Xlo,$Xlo + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vmovdqu 0x70-0x40($Htbl),$Hkey # $Hkey^6 + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Zhi,$Xhi,$Xhi + vpclmulqdq \$0x00,$HK, $T2,$Xmi + vpxor $Ij,$T1,$T1 + vpxor $Zmi,$Xmi,$Xmi + vxorps $Tred,$Xi,$Xi + + vmovdqu 0x10($inp),$Ii # I[1] + vpalignr \$8,$Xi,$Xi,$Tred # 2nd phase + vpclmulqdq \$0x00,$Hkey,$Ij,$Zlo + vpshufb $bswap,$Ii,$Ii + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x11,$Hkey,$Ij,$Zhi + vmovdqu 0x90-0x40($Htbl),$Hkey # $Hkey^7 + vpclmulqdq \$0x10,(%r10),$Xi,$Xi + vxorps $Xo,$Tred,$Tred + vpunpckhqdq $Ii,$Ii,$T2 + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x10,$HK, $T1,$Zmi + vmovdqu 0xb0-0x40($Htbl),$HK + vpxor $Ii,$T2,$T2 + vpxor $Xmi,$Zmi,$Zmi + + vmovdqu ($inp),$Ij # I[0] + vpclmulqdq \$0x00,$Hkey,$Ii,$Xlo + vpshufb $bswap,$Ij,$Ij + vpclmulqdq \$0x11,$Hkey,$Ii,$Xhi + vmovdqu 0xa0-0x40($Htbl),$Hkey # $Hkey^8 + vpxor $Tred,$Ij,$Ij + vpclmulqdq \$0x10,$HK, $T2,$Xmi + vpxor $Xi,$Ij,$Ij # accumulate $Xi + + lea 0x80($inp),$inp + sub \$0x80,$len + jnc .Loop8x_avx + + add \$0x80,$len + jmp .Ltail_no_xor_avx + +.align 32 +.Lshort_avx: + vmovdqu -0x10($inp,$len),$Ii # very last word + lea ($inp,$len),$inp + vmovdqu 0x00-0x40($Htbl),$Hkey # $Hkey^1 + vmovdqu 0x20-0x40($Htbl),$HK + vpshufb $bswap,$Ii,$Ij + + vmovdqa $Xlo,$Zlo # subtle way to zero $Zlo, + vmovdqa $Xhi,$Zhi # $Zhi and + vmovdqa $Xmi,$Zmi # $Zmi + sub \$0x10,$len + jz .Ltail_avx + + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo + vpxor $Ij,$T1,$T1 + vmovdqu -0x20($inp),$Ii + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi + vmovdqu 0x10-0x40($Htbl),$Hkey # $Hkey^2 + vpshufb $bswap,$Ii,$Ij + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Xmi + vpsrldq \$8,$HK,$HK + sub \$0x10,$len + jz .Ltail_avx + + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo + vpxor $Ij,$T1,$T1 + vmovdqu -0x30($inp),$Ii + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi + vmovdqu 0x30-0x40($Htbl),$Hkey # $Hkey^3 + vpshufb $bswap,$Ii,$Ij + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Xmi + vmovdqu 0x50-0x40($Htbl),$HK + sub \$0x10,$len + jz .Ltail_avx + + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo + vpxor $Ij,$T1,$T1 + vmovdqu -0x40($inp),$Ii + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi + vmovdqu 0x40-0x40($Htbl),$Hkey # $Hkey^4 + vpshufb $bswap,$Ii,$Ij + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Xmi + vpsrldq \$8,$HK,$HK + sub \$0x10,$len + jz .Ltail_avx + + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo + vpxor $Ij,$T1,$T1 + vmovdqu -0x50($inp),$Ii + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi + vmovdqu 0x60-0x40($Htbl),$Hkey # $Hkey^5 + vpshufb $bswap,$Ii,$Ij + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Xmi + vmovdqu 0x80-0x40($Htbl),$HK + sub \$0x10,$len + jz .Ltail_avx + + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo + vpxor $Ij,$T1,$T1 + vmovdqu -0x60($inp),$Ii + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi + vmovdqu 0x70-0x40($Htbl),$Hkey # $Hkey^6 + vpshufb $bswap,$Ii,$Ij + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Xmi + vpsrldq \$8,$HK,$HK + sub \$0x10,$len + jz .Ltail_avx + + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo + vpxor $Ij,$T1,$T1 + vmovdqu -0x70($inp),$Ii + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi + vmovdqu 0x90-0x40($Htbl),$Hkey # $Hkey^7 + vpshufb $bswap,$Ii,$Ij + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Xmi + vmovq 0xb8-0x40($Htbl),$HK + sub \$0x10,$len + jmp .Ltail_avx + +.align 32 +.Ltail_avx: + vpxor $Xi,$Ij,$Ij # accumulate $Xi +.Ltail_no_xor_avx: + vpunpckhqdq $Ij,$Ij,$T1 + vpxor $Xlo,$Zlo,$Zlo + vpclmulqdq \$0x00,$Hkey,$Ij,$Xlo + vpxor $Ij,$T1,$T1 + vpxor $Xhi,$Zhi,$Zhi + vpclmulqdq \$0x11,$Hkey,$Ij,$Xhi + vpxor $Xmi,$Zmi,$Zmi + vpclmulqdq \$0x00,$HK,$T1,$Xmi + + vmovdqu (%r10),$Tred + + vpxor $Xlo,$Zlo,$Xi + vpxor $Xhi,$Zhi,$Xo + vpxor $Xmi,$Zmi,$Zmi + + vpxor $Xi, $Zmi,$Zmi # aggregated Karatsuba post-processing + vpxor $Xo, $Zmi,$Zmi + vpslldq \$8, $Zmi,$T2 + vpsrldq \$8, $Zmi,$Zmi + vpxor $T2, $Xi, $Xi + vpxor $Zmi,$Xo, $Xo + + vpclmulqdq \$0x10,$Tred,$Xi,$T2 # 1st phase + vpalignr \$8,$Xi,$Xi,$Xi + vpxor $T2,$Xi,$Xi + + vpclmulqdq \$0x10,$Tred,$Xi,$T2 # 2nd phase + vpalignr \$8,$Xi,$Xi,$Xi + vpxor $Xo,$Xi,$Xi + vpxor $T2,$Xi,$Xi + + cmp \$0,$len + jne .Lshort_avx + + vpshufb $bswap,$Xi,$Xi + vmovdqu $Xi,($Xip) + vzeroupper +___ +$code.=<<___ if ($win64); + movaps (%rsp),%xmm6 + movaps 0x10(%rsp),%xmm7 + movaps 0x20(%rsp),%xmm8 + movaps 0x30(%rsp),%xmm9 + movaps 0x40(%rsp),%xmm10 + movaps 0x50(%rsp),%xmm11 + movaps 0x60(%rsp),%xmm12 + movaps 0x70(%rsp),%xmm13 + movaps 0x80(%rsp),%xmm14 + movaps 0x90(%rsp),%xmm15 + lea 0xa8(%rsp),%rsp +.LSEH_end_gcm_ghash_avx: +___ +$code.=<<___; + ret +.size gcm_ghash_avx,.-gcm_ghash_avx +___ +} else { +$code.=<<___; + jmp .L_ghash_clmul +.size gcm_ghash_avx,.-gcm_ghash_avx +___ +} + +$code.=<<___; +.align 64 +.Lbswap_mask: + .byte 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 +.L0x1c2_polynomial: + .byte 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xc2 +.L7_mask: + .long 7,0,7,0 +.L7_mask_poly: + .long 7,0,`0xE1<<1`,0 +.align 64 +.type .Lrem_4bit,\@object +.Lrem_4bit: + .long 0,`0x0000<<16`,0,`0x1C20<<16`,0,`0x3840<<16`,0,`0x2460<<16` + .long 0,`0x7080<<16`,0,`0x6CA0<<16`,0,`0x48C0<<16`,0,`0x54E0<<16` + .long 0,`0xE100<<16`,0,`0xFD20<<16`,0,`0xD940<<16`,0,`0xC560<<16` + .long 0,`0x9180<<16`,0,`0x8DA0<<16`,0,`0xA9C0<<16`,0,`0xB5E0<<16` +.type .Lrem_8bit,\@object +.Lrem_8bit: + .value 0x0000,0x01C2,0x0384,0x0246,0x0708,0x06CA,0x048C,0x054E + .value 0x0E10,0x0FD2,0x0D94,0x0C56,0x0918,0x08DA,0x0A9C,0x0B5E + .value 0x1C20,0x1DE2,0x1FA4,0x1E66,0x1B28,0x1AEA,0x18AC,0x196E + .value 0x1230,0x13F2,0x11B4,0x1076,0x1538,0x14FA,0x16BC,0x177E + .value 0x3840,0x3982,0x3BC4,0x3A06,0x3F48,0x3E8A,0x3CCC,0x3D0E + .value 0x3650,0x3792,0x35D4,0x3416,0x3158,0x309A,0x32DC,0x331E + .value 0x2460,0x25A2,0x27E4,0x2626,0x2368,0x22AA,0x20EC,0x212E + .value 0x2A70,0x2BB2,0x29F4,0x2836,0x2D78,0x2CBA,0x2EFC,0x2F3E + .value 0x7080,0x7142,0x7304,0x72C6,0x7788,0x764A,0x740C,0x75CE + .value 0x7E90,0x7F52,0x7D14,0x7CD6,0x7998,0x785A,0x7A1C,0x7BDE + .value 0x6CA0,0x6D62,0x6F24,0x6EE6,0x6BA8,0x6A6A,0x682C,0x69EE + .value 0x62B0,0x6372,0x6134,0x60F6,0x65B8,0x647A,0x663C,0x67FE + .value 0x48C0,0x4902,0x4B44,0x4A86,0x4FC8,0x4E0A,0x4C4C,0x4D8E + .value 0x46D0,0x4712,0x4554,0x4496,0x41D8,0x401A,0x425C,0x439E + .value 0x54E0,0x5522,0x5764,0x56A6,0x53E8,0x522A,0x506C,0x51AE + .value 0x5AF0,0x5B32,0x5974,0x58B6,0x5DF8,0x5C3A,0x5E7C,0x5FBE + .value 0xE100,0xE0C2,0xE284,0xE346,0xE608,0xE7CA,0xE58C,0xE44E + .value 0xEF10,0xEED2,0xEC94,0xED56,0xE818,0xE9DA,0xEB9C,0xEA5E + .value 0xFD20,0xFCE2,0xFEA4,0xFF66,0xFA28,0xFBEA,0xF9AC,0xF86E + .value 0xF330,0xF2F2,0xF0B4,0xF176,0xF438,0xF5FA,0xF7BC,0xF67E + .value 0xD940,0xD882,0xDAC4,0xDB06,0xDE48,0xDF8A,0xDDCC,0xDC0E + .value 0xD750,0xD692,0xD4D4,0xD516,0xD058,0xD19A,0xD3DC,0xD21E + .value 0xC560,0xC4A2,0xC6E4,0xC726,0xC268,0xC3AA,0xC1EC,0xC02E + .value 0xCB70,0xCAB2,0xC8F4,0xC936,0xCC78,0xCDBA,0xCFFC,0xCE3E + .value 0x9180,0x9042,0x9204,0x93C6,0x9688,0x974A,0x950C,0x94CE + .value 0x9F90,0x9E52,0x9C14,0x9DD6,0x9898,0x995A,0x9B1C,0x9ADE + .value 0x8DA0,0x8C62,0x8E24,0x8FE6,0x8AA8,0x8B6A,0x892C,0x88EE + .value 0x83B0,0x8272,0x8034,0x81F6,0x84B8,0x857A,0x873C,0x86FE + .value 0xA9C0,0xA802,0xAA44,0xAB86,0xAEC8,0xAF0A,0xAD4C,0xAC8E + .value 0xA7D0,0xA612,0xA454,0xA596,0xA0D8,0xA11A,0xA35C,0xA29E + .value 0xB5E0,0xB422,0xB664,0xB7A6,0xB2E8,0xB32A,0xB16C,0xB0AE + .value 0xBBF0,0xBA32,0xB874,0xB9B6,0xBCF8,0xBD3A,0xBF7C,0xBEBE + +.asciz "GHASH for x86_64, CRYPTOGAMS by " +.align 64 +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lin_prologue + + lea 24(%rax),%rax # adjust "rsp" + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + +.Lin_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$`1232/8`,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size se_handler,.-se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_gcm_gmult_4bit + .rva .LSEH_end_gcm_gmult_4bit + .rva .LSEH_info_gcm_gmult_4bit + + .rva .LSEH_begin_gcm_ghash_4bit + .rva .LSEH_end_gcm_ghash_4bit + .rva .LSEH_info_gcm_ghash_4bit + + .rva .LSEH_begin_gcm_init_clmul + .rva .LSEH_end_gcm_init_clmul + .rva .LSEH_info_gcm_init_clmul + + .rva .LSEH_begin_gcm_ghash_clmul + .rva .LSEH_end_gcm_ghash_clmul + .rva .LSEH_info_gcm_ghash_clmul +___ +$code.=<<___ if ($avx); + .rva .LSEH_begin_gcm_init_avx + .rva .LSEH_end_gcm_init_avx + .rva .LSEH_info_gcm_init_clmul + + .rva .LSEH_begin_gcm_ghash_avx + .rva .LSEH_end_gcm_ghash_avx + .rva .LSEH_info_gcm_ghash_clmul +___ +$code.=<<___; +.section .xdata +.align 8 +.LSEH_info_gcm_gmult_4bit: + .byte 9,0,0,0 + .rva se_handler + .rva .Lgmult_prologue,.Lgmult_epilogue # HandlerData +.LSEH_info_gcm_ghash_4bit: + .byte 9,0,0,0 + .rva se_handler + .rva .Lghash_prologue,.Lghash_epilogue # HandlerData +.LSEH_info_gcm_init_clmul: + .byte 0x01,0x08,0x03,0x00 + .byte 0x08,0x68,0x00,0x00 #movaps 0x00(rsp),xmm6 + .byte 0x04,0x22,0x00,0x00 #sub rsp,0x18 +.LSEH_info_gcm_ghash_clmul: + .byte 0x01,0x33,0x16,0x00 + .byte 0x33,0xf8,0x09,0x00 #movaps 0x90(rsp),xmm15 + .byte 0x2e,0xe8,0x08,0x00 #movaps 0x80(rsp),xmm14 + .byte 0x29,0xd8,0x07,0x00 #movaps 0x70(rsp),xmm13 + .byte 0x24,0xc8,0x06,0x00 #movaps 0x60(rsp),xmm12 + .byte 0x1f,0xb8,0x05,0x00 #movaps 0x50(rsp),xmm11 + .byte 0x1a,0xa8,0x04,0x00 #movaps 0x40(rsp),xmm10 + .byte 0x15,0x98,0x03,0x00 #movaps 0x30(rsp),xmm9 + .byte 0x10,0x88,0x02,0x00 #movaps 0x20(rsp),xmm8 + .byte 0x0c,0x78,0x01,0x00 #movaps 0x10(rsp),xmm7 + .byte 0x08,0x68,0x00,0x00 #movaps 0x00(rsp),xmm6 + .byte 0x04,0x01,0x15,0x00 #sub rsp,0xa8 +___ +} + +$code =~ s/\`([^\`]*)\`/eval($1)/gem; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/modes/asm/ghashv8-armx.pl b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghashv8-armx.pl new file mode 100644 index 00000000..5856c94a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/asm/ghashv8-armx.pl @@ -0,0 +1,422 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# GHASH for ARMv8 Crypto Extension, 64-bit polynomial multiplication. +# +# June 2014 +# +# Initial version was developed in tight cooperation with Ard +# Biesheuvel from bits-n-pieces from +# other assembly modules. Just like aesv8-armx.pl this module +# supports both AArch32 and AArch64 execution modes. +# +# July 2014 +# +# Implement 2x aggregated reduction [see ghash-x86.pl for background +# information]. +# +# Current performance in cycles per processed byte: +# +# PMULL[2] 32-bit NEON(*) +# Apple A7 0.92 5.62 +# Cortex-A53 1.01 8.39 +# Cortex-A57 1.17 7.61 +# Denver 0.71 6.02 +# +# (*) presented for reference/comparison purposes; + +$flavour = shift; +$output = shift; + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or +die "can't locate arm-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$Xi="x0"; # argument block +$Htbl="x1"; +$inp="x2"; +$len="x3"; + +$inc="x12"; + +{ +my ($Xl,$Xm,$Xh,$IN)=map("q$_",(0..3)); +my ($t0,$t1,$t2,$xC2,$H,$Hhl,$H2)=map("q$_",(8..14)); + +$code=<<___; +#include "arm_arch.h" + +.text +___ +$code.=<<___ if ($flavour =~ /64/); +#if !defined(__clang__) +.arch armv8-a+crypto +#endif +___ +$code.=".fpu neon\n.code 32\n" if ($flavour !~ /64/); + +################################################################################ +# void gcm_init_v8(u128 Htable[16],const u64 H[2]); +# +# input: 128-bit H - secret parameter E(K,0^128) +# output: precomputed table filled with degrees of twisted H; +# H is twisted to handle reverse bitness of GHASH; +# only few of 16 slots of Htable[16] are used; +# data is opaque to outside world (which allows to +# optimize the code independently); +# +$code.=<<___; +.global gcm_init_v8 +.type gcm_init_v8,%function +.align 4 +gcm_init_v8: + vld1.64 {$t1},[x1] @ load input H + vmov.i8 $xC2,#0xe1 + vshl.i64 $xC2,$xC2,#57 @ 0xc2.0 + vext.8 $IN,$t1,$t1,#8 + vshr.u64 $t2,$xC2,#63 + vdup.32 $t1,${t1}[1] + vext.8 $t0,$t2,$xC2,#8 @ t0=0xc2....01 + vshr.u64 $t2,$IN,#63 + vshr.s32 $t1,$t1,#31 @ broadcast carry bit + vand $t2,$t2,$t0 + vshl.i64 $IN,$IN,#1 + vext.8 $t2,$t2,$t2,#8 + vand $t0,$t0,$t1 + vorr $IN,$IN,$t2 @ H<<<=1 + veor $H,$IN,$t0 @ twisted H + vst1.64 {$H},[x0],#16 @ store Htable[0] + + @ calculate H^2 + vext.8 $t0,$H,$H,#8 @ Karatsuba pre-processing + vpmull.p64 $Xl,$H,$H + veor $t0,$t0,$H + vpmull2.p64 $Xh,$H,$H + vpmull.p64 $Xm,$t0,$t0 + + vext.8 $t1,$Xl,$Xh,#8 @ Karatsuba post-processing + veor $t2,$Xl,$Xh + veor $Xm,$Xm,$t1 + veor $Xm,$Xm,$t2 + vpmull.p64 $t2,$Xl,$xC2 @ 1st phase + + vmov $Xh#lo,$Xm#hi @ Xh|Xm - 256-bit result + vmov $Xm#hi,$Xl#lo @ Xm is rotated Xl + veor $Xl,$Xm,$t2 + + vext.8 $t2,$Xl,$Xl,#8 @ 2nd phase + vpmull.p64 $Xl,$Xl,$xC2 + veor $t2,$t2,$Xh + veor $H2,$Xl,$t2 + + vext.8 $t1,$H2,$H2,#8 @ Karatsuba pre-processing + veor $t1,$t1,$H2 + vext.8 $Hhl,$t0,$t1,#8 @ pack Karatsuba pre-processed + vst1.64 {$Hhl-$H2},[x0] @ store Htable[1..2] + + ret +.size gcm_init_v8,.-gcm_init_v8 +___ +################################################################################ +# void gcm_gmult_v8(u64 Xi[2],const u128 Htable[16]); +# +# input: Xi - current hash value; +# Htable - table precomputed in gcm_init_v8; +# output: Xi - next hash value Xi; +# +$code.=<<___; +.global gcm_gmult_v8 +.type gcm_gmult_v8,%function +.align 4 +gcm_gmult_v8: + vld1.64 {$t1},[$Xi] @ load Xi + vmov.i8 $xC2,#0xe1 + vld1.64 {$H-$Hhl},[$Htbl] @ load twisted H, ... + vshl.u64 $xC2,$xC2,#57 +#ifndef __ARMEB__ + vrev64.8 $t1,$t1 +#endif + vext.8 $IN,$t1,$t1,#8 + + vpmull.p64 $Xl,$H,$IN @ H.lo·Xi.lo + veor $t1,$t1,$IN @ Karatsuba pre-processing + vpmull2.p64 $Xh,$H,$IN @ H.hi·Xi.hi + vpmull.p64 $Xm,$Hhl,$t1 @ (H.lo+H.hi)·(Xi.lo+Xi.hi) + + vext.8 $t1,$Xl,$Xh,#8 @ Karatsuba post-processing + veor $t2,$Xl,$Xh + veor $Xm,$Xm,$t1 + veor $Xm,$Xm,$t2 + vpmull.p64 $t2,$Xl,$xC2 @ 1st phase of reduction + + vmov $Xh#lo,$Xm#hi @ Xh|Xm - 256-bit result + vmov $Xm#hi,$Xl#lo @ Xm is rotated Xl + veor $Xl,$Xm,$t2 + + vext.8 $t2,$Xl,$Xl,#8 @ 2nd phase of reduction + vpmull.p64 $Xl,$Xl,$xC2 + veor $t2,$t2,$Xh + veor $Xl,$Xl,$t2 + +#ifndef __ARMEB__ + vrev64.8 $Xl,$Xl +#endif + vext.8 $Xl,$Xl,$Xl,#8 + vst1.64 {$Xl},[$Xi] @ write out Xi + + ret +.size gcm_gmult_v8,.-gcm_gmult_v8 +___ +################################################################################ +# void gcm_ghash_v8(u64 Xi[2],const u128 Htable[16],const u8 *inp,size_t len); +# +# input: table precomputed in gcm_init_v8; +# current hash value Xi; +# pointer to input data; +# length of input data in bytes, but divisible by block size; +# output: next hash value Xi; +# +$code.=<<___; +.global gcm_ghash_v8 +.type gcm_ghash_v8,%function +.align 4 +gcm_ghash_v8: +___ +$code.=<<___ if ($flavour !~ /64/); + vstmdb sp!,{d8-d15} @ 32-bit ABI says so +___ +$code.=<<___; + vld1.64 {$Xl},[$Xi] @ load [rotated] Xi + @ "[rotated]" means that + @ loaded value would have + @ to be rotated in order to + @ make it appear as in + @ alorithm specification + subs $len,$len,#32 @ see if $len is 32 or larger + mov $inc,#16 @ $inc is used as post- + @ increment for input pointer; + @ as loop is modulo-scheduled + @ $inc is zeroed just in time + @ to preclude oversteping + @ inp[len], which means that + @ last block[s] are actually + @ loaded twice, but last + @ copy is not processed + vld1.64 {$H-$Hhl},[$Htbl],#32 @ load twisted H, ..., H^2 + vmov.i8 $xC2,#0xe1 + vld1.64 {$H2},[$Htbl] + cclr $inc,eq @ is it time to zero $inc? + vext.8 $Xl,$Xl,$Xl,#8 @ rotate Xi + vld1.64 {$t0},[$inp],#16 @ load [rotated] I[0] + vshl.u64 $xC2,$xC2,#57 @ compose 0xc2.0 constant +#ifndef __ARMEB__ + vrev64.8 $t0,$t0 + vrev64.8 $Xl,$Xl +#endif + vext.8 $IN,$t0,$t0,#8 @ rotate I[0] + b.lo .Lodd_tail_v8 @ $len was less than 32 +___ +{ my ($Xln,$Xmn,$Xhn,$In) = map("q$_",(4..7)); + ####### + # Xi+2 =[H*(Ii+1 + Xi+1)] mod P = + # [(H*Ii+1) + (H*Xi+1)] mod P = + # [(H*Ii+1) + H^2*(Ii+Xi)] mod P + # +$code.=<<___; + vld1.64 {$t1},[$inp],$inc @ load [rotated] I[1] +#ifndef __ARMEB__ + vrev64.8 $t1,$t1 +#endif + vext.8 $In,$t1,$t1,#8 + veor $IN,$IN,$Xl @ I[i]^=Xi + vpmull.p64 $Xln,$H,$In @ H·Ii+1 + veor $t1,$t1,$In @ Karatsuba pre-processing + vpmull2.p64 $Xhn,$H,$In + b .Loop_mod2x_v8 + +.align 4 +.Loop_mod2x_v8: + vext.8 $t2,$IN,$IN,#8 + subs $len,$len,#32 @ is there more data? + vpmull.p64 $Xl,$H2,$IN @ H^2.lo·Xi.lo + cclr $inc,lo @ is it time to zero $inc? + + vpmull.p64 $Xmn,$Hhl,$t1 + veor $t2,$t2,$IN @ Karatsuba pre-processing + vpmull2.p64 $Xh,$H2,$IN @ H^2.hi·Xi.hi + veor $Xl,$Xl,$Xln @ accumulate + vpmull2.p64 $Xm,$Hhl,$t2 @ (H^2.lo+H^2.hi)·(Xi.lo+Xi.hi) + vld1.64 {$t0},[$inp],$inc @ load [rotated] I[i+2] + + veor $Xh,$Xh,$Xhn + cclr $inc,eq @ is it time to zero $inc? + veor $Xm,$Xm,$Xmn + + vext.8 $t1,$Xl,$Xh,#8 @ Karatsuba post-processing + veor $t2,$Xl,$Xh + veor $Xm,$Xm,$t1 + vld1.64 {$t1},[$inp],$inc @ load [rotated] I[i+3] +#ifndef __ARMEB__ + vrev64.8 $t0,$t0 +#endif + veor $Xm,$Xm,$t2 + vpmull.p64 $t2,$Xl,$xC2 @ 1st phase of reduction + +#ifndef __ARMEB__ + vrev64.8 $t1,$t1 +#endif + vmov $Xh#lo,$Xm#hi @ Xh|Xm - 256-bit result + vmov $Xm#hi,$Xl#lo @ Xm is rotated Xl + vext.8 $In,$t1,$t1,#8 + vext.8 $IN,$t0,$t0,#8 + veor $Xl,$Xm,$t2 + vpmull.p64 $Xln,$H,$In @ H·Ii+1 + veor $IN,$IN,$Xh @ accumulate $IN early + + vext.8 $t2,$Xl,$Xl,#8 @ 2nd phase of reduction + vpmull.p64 $Xl,$Xl,$xC2 + veor $IN,$IN,$t2 + veor $t1,$t1,$In @ Karatsuba pre-processing + veor $IN,$IN,$Xl + vpmull2.p64 $Xhn,$H,$In + b.hs .Loop_mod2x_v8 @ there was at least 32 more bytes + + veor $Xh,$Xh,$t2 + vext.8 $IN,$t0,$t0,#8 @ re-construct $IN + adds $len,$len,#32 @ re-construct $len + veor $Xl,$Xl,$Xh @ re-construct $Xl + b.eq .Ldone_v8 @ is $len zero? +___ +} +$code.=<<___; +.Lodd_tail_v8: + vext.8 $t2,$Xl,$Xl,#8 + veor $IN,$IN,$Xl @ inp^=Xi + veor $t1,$t0,$t2 @ $t1 is rotated inp^Xi + + vpmull.p64 $Xl,$H,$IN @ H.lo·Xi.lo + veor $t1,$t1,$IN @ Karatsuba pre-processing + vpmull2.p64 $Xh,$H,$IN @ H.hi·Xi.hi + vpmull.p64 $Xm,$Hhl,$t1 @ (H.lo+H.hi)·(Xi.lo+Xi.hi) + + vext.8 $t1,$Xl,$Xh,#8 @ Karatsuba post-processing + veor $t2,$Xl,$Xh + veor $Xm,$Xm,$t1 + veor $Xm,$Xm,$t2 + vpmull.p64 $t2,$Xl,$xC2 @ 1st phase of reduction + + vmov $Xh#lo,$Xm#hi @ Xh|Xm - 256-bit result + vmov $Xm#hi,$Xl#lo @ Xm is rotated Xl + veor $Xl,$Xm,$t2 + + vext.8 $t2,$Xl,$Xl,#8 @ 2nd phase of reduction + vpmull.p64 $Xl,$Xl,$xC2 + veor $t2,$t2,$Xh + veor $Xl,$Xl,$t2 + +.Ldone_v8: +#ifndef __ARMEB__ + vrev64.8 $Xl,$Xl +#endif + vext.8 $Xl,$Xl,$Xl,#8 + vst1.64 {$Xl},[$Xi] @ write out Xi + +___ +$code.=<<___ if ($flavour !~ /64/); + vldmia sp!,{d8-d15} @ 32-bit ABI says so +___ +$code.=<<___; + ret +.size gcm_ghash_v8,.-gcm_ghash_v8 +___ +} +$code.=<<___; +.asciz "GHASH for ARMv8, CRYPTOGAMS by " +.align 2 +___ + +if ($flavour =~ /64/) { ######## 64-bit code + sub unvmov { + my $arg=shift; + + $arg =~ m/q([0-9]+)#(lo|hi),\s*q([0-9]+)#(lo|hi)/o && + sprintf "ins v%d.d[%d],v%d.d[%d]",$1,($2 eq "lo")?0:1,$3,($4 eq "lo")?0:1; + } + foreach(split("\n",$code)) { + s/cclr\s+([wx])([^,]+),\s*([a-z]+)/csel $1$2,$1zr,$1$2,$3/o or + s/vmov\.i8/movi/o or # fix up legacy mnemonics + s/vmov\s+(.*)/unvmov($1)/geo or + s/vext\.8/ext/o or + s/vshr\.s/sshr\.s/o or + s/vshr/ushr/o or + s/^(\s+)v/$1/o or # strip off v prefix + s/\bbx\s+lr\b/ret/o; + + s/\bq([0-9]+)\b/"v".($1<8?$1:$1+8).".16b"/geo; # old->new registers + s/@\s/\/\//o; # old->new style commentary + + # fix up remainig legacy suffixes + s/\.[ui]?8(\s)/$1/o; + s/\.[uis]?32//o and s/\.16b/\.4s/go; + m/\.p64/o and s/\.16b/\.1q/o; # 1st pmull argument + m/l\.p64/o and s/\.16b/\.1d/go; # 2nd and 3rd pmull arguments + s/\.[uisp]?64//o and s/\.16b/\.2d/go; + s/\.[42]([sd])\[([0-3])\]/\.$1\[$2\]/o; + + print $_,"\n"; + } +} else { ######## 32-bit code + sub unvdup32 { + my $arg=shift; + + $arg =~ m/q([0-9]+),\s*q([0-9]+)\[([0-3])\]/o && + sprintf "vdup.32 q%d,d%d[%d]",$1,2*$2+($3>>1),$3&1; + } + sub unvpmullp64 { + my ($mnemonic,$arg)=@_; + + if ($arg =~ m/q([0-9]+),\s*q([0-9]+),\s*q([0-9]+)/o) { + my $word = 0xf2a00e00|(($1&7)<<13)|(($1&8)<<19) + |(($2&7)<<17)|(($2&8)<<4) + |(($3&7)<<1) |(($3&8)<<2); + $word |= 0x00010001 if ($mnemonic =~ "2"); + # since ARMv7 instructions are always encoded little-endian. + # correct solution is to use .inst directive, but older + # assemblers don't implement it:-( + sprintf ".byte\t0x%02x,0x%02x,0x%02x,0x%02x\t@ %s %s", + $word&0xff,($word>>8)&0xff, + ($word>>16)&0xff,($word>>24)&0xff, + $mnemonic,$arg; + } + } + + foreach(split("\n",$code)) { + s/\b[wx]([0-9]+)\b/r$1/go; # new->old registers + s/\bv([0-9])\.[12468]+[bsd]\b/q$1/go; # new->old registers + s/\/\/\s?/@ /o; # new->old style commentary + + # fix up remainig new-style suffixes + s/\],#[0-9]+/]!/o; + + s/cclr\s+([^,]+),\s*([a-z]+)/mov$2 $1,#0/o or + s/vdup\.32\s+(.*)/unvdup32($1)/geo or + s/v?(pmull2?)\.p64\s+(.*)/unvpmullp64($1,$2)/geo or + s/\bq([0-9]+)#(lo|hi)/sprintf "d%d",2*$1+($2 eq "hi")/geo or + s/^(\s+)b\./$1b/o or + s/^(\s+)ret/$1bx\tlr/o; + + print $_,"\n"; + } +} + +close STDOUT; # enforce flush diff --git a/TMessagesProj/jni/boringssl/crypto/modes/cbc.c b/TMessagesProj/jni/boringssl/crypto/modes/cbc.c new file mode 100644 index 00000000..931b718d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/cbc.c @@ -0,0 +1,217 @@ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== */ +#include + +#include +#include + +#include "internal.h" + + +#ifndef STRICT_ALIGNMENT +# define STRICT_ALIGNMENT 0 +#endif + +void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], + block128_f block) { + size_t n; + const uint8_t *iv = ivec; + + assert(key != NULL && ivec != NULL); + assert(len == 0 || (in != NULL && out != NULL)); + + if (STRICT_ALIGNMENT && + ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + while (len >= 16) { + for (n = 0; n < 16; ++n) { + out[n] = in[n] ^ iv[n]; + } + (*block)(out, out, key); + iv = out; + len -= 16; + in += 16; + out += 16; + } + } else { + while (len >= 16) { + for (n = 0; n < 16; n += sizeof(size_t)) { + *(size_t *)(out + n) = *(size_t *)(in + n) ^ *(size_t *)(iv + n); + } + (*block)(out, out, key); + iv = out; + len -= 16; + in += 16; + out += 16; + } + } + + while (len) { + for (n = 0; n < 16 && n < len; ++n) { + out[n] = in[n] ^ iv[n]; + } + for (; n < 16; ++n) { + out[n] = iv[n]; + } + (*block)(out, out, key); + iv = out; + if (len <= 16) { + break; + } + len -= 16; + in += 16; + out += 16; + } + + memcpy(ivec, iv, 16); +} + +void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], + block128_f block) { + size_t n; + union { + size_t t[16 / sizeof(size_t)]; + uint8_t c[16]; + } tmp; + + assert(key != NULL && ivec != NULL); + assert(len == 0 || (in != NULL && out != NULL)); + + const uintptr_t inptr = (uintptr_t) in; + const uintptr_t outptr = (uintptr_t) out; + /* If |in| and |out| alias, |in| must be ahead. */ + assert(inptr >= outptr || inptr + len <= outptr); + + if ((inptr >= 32 && outptr <= inptr - 32) || inptr < outptr) { + /* If |out| is at least two blocks behind |in| or completely disjoint, there + * is no need to decrypt to a temporary block. */ + const uint8_t *iv = ivec; + + if (STRICT_ALIGNMENT && + ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + while (len >= 16) { + (*block)(in, out, key); + for (n = 0; n < 16; ++n) { + out[n] ^= iv[n]; + } + iv = in; + len -= 16; + in += 16; + out += 16; + } + } else if (16 % sizeof(size_t) == 0) { /* always true */ + while (len >= 16) { + size_t *out_t = (size_t *)out, *iv_t = (size_t *)iv; + + (*block)(in, out, key); + for (n = 0; n < 16 / sizeof(size_t); n++) { + out_t[n] ^= iv_t[n]; + } + iv = in; + len -= 16; + in += 16; + out += 16; + } + } + memcpy(ivec, iv, 16); + } else { + /* |out| is less than two blocks behind |in|. Decrypting an input block + * directly to |out| would overwrite a ciphertext block before it is used as + * the next block's IV. Decrypt to a temporary block instead. */ + if (STRICT_ALIGNMENT && + ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + uint8_t c; + while (len >= 16) { + (*block)(in, tmp.c, key); + for (n = 0; n < 16; ++n) { + c = in[n]; + out[n] = tmp.c[n] ^ ivec[n]; + ivec[n] = c; + } + len -= 16; + in += 16; + out += 16; + } + } else if (16 % sizeof(size_t) == 0) { /* always true */ + while (len >= 16) { + size_t c, *out_t = (size_t *)out, *ivec_t = (size_t *)ivec; + const size_t *in_t = (const size_t *)in; + + (*block)(in, tmp.c, key); + for (n = 0; n < 16 / sizeof(size_t); n++) { + c = in_t[n]; + out_t[n] = tmp.t[n] ^ ivec_t[n]; + ivec_t[n] = c; + } + len -= 16; + in += 16; + out += 16; + } + } + } + + while (len) { + uint8_t c; + (*block)(in, tmp.c, key); + for (n = 0; n < 16 && n < len; ++n) { + c = in[n]; + out[n] = tmp.c[n] ^ ivec[n]; + ivec[n] = c; + } + if (len <= 16) { + for (; n < 16; ++n) { + ivec[n] = in[n]; + } + break; + } + len -= 16; + in += 16; + out += 16; + } +} diff --git a/TMessagesProj/jni/boringssl/crypto/modes/cfb.c b/TMessagesProj/jni/boringssl/crypto/modes/cfb.c new file mode 100644 index 00000000..738a4380 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/cfb.c @@ -0,0 +1,230 @@ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== */ + +#include + +#include +#include + +#include "internal.h" + + +void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], int *num, int enc, + block128_f block) { + unsigned int n; + size_t l = 0; + + assert(in && out && key && ivec && num); + assert((16 % sizeof(size_t)) == 0); + + n = *num; + + if (enc) { + while (n && len) { + *(out++) = ivec[n] ^= *(in++); + --len; + n = (n + 1) % 16; + } +#if STRICT_ALIGNMENT + if (((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + while (l < len) { + if (n == 0) { + (*block)(ivec, ivec, key); + } + out[l] = ivec[n] ^= in[l]; + ++l; + n = (n + 1) % 16; + } + *num = n; + return; + } +#endif + while (len >= 16) { + (*block)(ivec, ivec, key); + for (; n < 16; n += sizeof(size_t)) { + *(size_t *)(out + n) = *(size_t *)(ivec + n) ^= *(size_t *)(in + n); + } + len -= 16; + out += 16; + in += 16; + n = 0; + } + if (len) { + (*block)(ivec, ivec, key); + while (len--) { + out[n] = ivec[n] ^= in[n]; + ++n; + } + } + *num = n; + return; + } else { + while (n && len) { + uint8_t c; + *(out++) = ivec[n] ^ (c = *(in++)); + ivec[n] = c; + --len; + n = (n + 1) % 16; + } + if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + while (l < len) { + unsigned char c; + if (n == 0) { + (*block)(ivec, ivec, key); + } + out[l] = ivec[n] ^ (c = in[l]); + ivec[n] = c; + ++l; + n = (n + 1) % 16; + } + *num = n; + return; + } + while (len >= 16) { + (*block)(ivec, ivec, key); + for (; n < 16; n += sizeof(size_t)) { + size_t t = *(size_t *)(in + n); + *(size_t *)(out + n) = *(size_t *)(ivec + n) ^ t; + *(size_t *)(ivec + n) = t; + } + len -= 16; + out += 16; + in += 16; + n = 0; + } + if (len) { + (*block)(ivec, ivec, key); + while (len--) { + uint8_t c; + out[n] = ivec[n] ^ (c = in[n]); + ivec[n] = c; + ++n; + } + } + *num = n; + return; + } +} + + +/* This expects a single block of size nbits for both in and out. Note that + it corrupts any extra bits in the last byte of out */ +static void cfbr_encrypt_block(const uint8_t *in, uint8_t *out, unsigned nbits, + const void *key, uint8_t ivec[16], int enc, + block128_f block) { + int n, rem, num; + uint8_t ovec[16 * 2 + 1]; /* +1 because we dererefence (but don't use) one + byte off the end */ + + if (nbits <= 0 || nbits > 128) { + return; + } + + /* fill in the first half of the new IV with the current IV */ + memcpy(ovec, ivec, 16); + /* construct the new IV */ + (*block)(ivec, ivec, key); + num = (nbits + 7) / 8; + if (enc) { + /* encrypt the input */ + for (n = 0; n < num; ++n) { + out[n] = (ovec[16 + n] = in[n] ^ ivec[n]); + } + } else { + /* decrypt the input */ + for (n = 0; n < num; ++n) { + out[n] = (ovec[16 + n] = in[n]) ^ ivec[n]; + } + } + /* shift ovec left... */ + rem = nbits % 8; + num = nbits / 8; + if (rem == 0) { + memcpy(ivec, ovec + num, 16); + } else { + for (n = 0; n < 16; ++n) { + ivec[n] = ovec[n + num] << rem | ovec[n + num + 1] >> (8 - rem); + } + } + + /* it is not necessary to cleanse ovec, since the IV is not secret */ +} + +/* N.B. This expects the input to be packed, MS bit first */ +void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits, + const void *key, uint8_t ivec[16], int *num, + int enc, block128_f block) { + size_t n; + uint8_t c[1], d[1]; + + assert(in && out && key && ivec && num); + assert(*num == 0); + + for (n = 0; n < bits; ++n) { + c[0] = (in[n / 8] & (1 << (7 - n % 8))) ? 0x80 : 0; + cfbr_encrypt_block(c, d, 1, key, ivec, enc, block); + out[n / 8] = (out[n / 8] & ~(1 << (unsigned int)(7 - n % 8))) | + ((d[0] & 0x80) >> (unsigned int)(n % 8)); + } +} + +void CRYPTO_cfb128_8_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const void *key, + unsigned char ivec[16], int *num, int enc, + block128_f block) { + size_t n; + + assert(in && out && key && ivec && num); + assert(*num == 0); + + for (n = 0; n < length; ++n) { + cfbr_encrypt_block(&in[n], &out[n], 8, key, ivec, enc, block); + } +} + diff --git a/TMessagesProj/jni/boringssl/crypto/modes/ctr.c b/TMessagesProj/jni/boringssl/crypto/modes/ctr.c new file mode 100644 index 00000000..64062b27 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/ctr.c @@ -0,0 +1,224 @@ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== */ +#include + +#include +#include + +#include "internal.h" + + +/* NOTE: the IV/counter CTR mode is big-endian. The code itself + * is endian-neutral. */ + +/* increment counter (128-bit int) by 1 */ +static void ctr128_inc(uint8_t *counter) { + uint32_t n = 16; + uint8_t c; + + do { + --n; + c = counter[n]; + ++c; + counter[n] = c; + if (c) { + return; + } + } while (n); +} + +/* The input encrypted as though 128bit counter mode is being used. The extra + * state information to record how much of the 128bit block we have used is + * contained in *num, and the encrypted counter is kept in ecount_buf. Both + * *num and ecount_buf must be initialised with zeros before the first call to + * CRYPTO_ctr128_encrypt(). + * + * This algorithm assumes that the counter is in the x lower bits of the IV + * (ivec), and that the application has full control over overflow and the rest + * of the IV. This implementation takes NO responsibility for checking that + * the counter doesn't overflow into the rest of the IV when incremented. */ +void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], + uint8_t ecount_buf[16], unsigned int *num, + block128_f block) { + unsigned int n; + + assert(key && ecount_buf && num); + assert(len == 0 || (in && out)); + assert(*num < 16); + assert((16 % sizeof(size_t)) == 0); + + n = *num; + + while (n && len) { + *(out++) = *(in++) ^ ecount_buf[n]; + --len; + n = (n + 1) % 16; + } + +#if STRICT_ALIGNMENT + if (((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + size_t l = 0; + while (l < len) { + if (n == 0) { + (*block)(ivec, ecount_buf, key); + ctr128_inc(ivec); + } + out[l] = in[l] ^ ecount_buf[n]; + ++l; + n = (n + 1) % 16; + } + + *num = n; + return; + } +#endif + + while (len >= 16) { + (*block)(ivec, ecount_buf, key); + ctr128_inc(ivec); + for (; n < 16; n += sizeof(size_t)) { + *(size_t *)(out + n) = *(size_t *)(in + n) ^ *(size_t *)(ecount_buf + n); + } + len -= 16; + out += 16; + in += 16; + n = 0; + } + if (len) { + (*block)(ivec, ecount_buf, key); + ctr128_inc(ivec); + while (len--) { + out[n] = in[n] ^ ecount_buf[n]; + ++n; + } + } + *num = n; +} + +/* increment upper 96 bits of 128-bit counter by 1 */ +static void ctr96_inc(uint8_t *counter) { + uint32_t n = 12; + uint8_t c; + + do { + --n; + c = counter[n]; + ++c; + counter[n] = c; + if (c) { + return; + } + } while (n); +} + +void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, + size_t len, const void *key, + uint8_t ivec[16], + uint8_t ecount_buf[16], + unsigned int *num, ctr128_f func) { + unsigned int n, ctr32; + + assert(key && ecount_buf && num); + assert(len == 0 || (in && out)); + assert(*num < 16); + + n = *num; + + while (n && len) { + *(out++) = *(in++) ^ ecount_buf[n]; + --len; + n = (n + 1) % 16; + } + + ctr32 = GETU32(ivec + 12); + while (len >= 16) { + size_t blocks = len / 16; + /* 1<<28 is just a not-so-small yet not-so-large number... + * Below condition is practically never met, but it has to + * be checked for code correctness. */ + if (sizeof(size_t) > sizeof(unsigned int) && blocks > (1U << 28)) { + blocks = (1U << 28); + } + /* As (*func) operates on 32-bit counter, caller + * has to handle overflow. 'if' below detects the + * overflow, which is then handled by limiting the + * amount of blocks to the exact overflow point... */ + ctr32 += (uint32_t)blocks; + if (ctr32 < blocks) { + blocks -= ctr32; + ctr32 = 0; + } + (*func)(in, out, blocks, key, ivec); + /* (*func) does not update ivec, caller does: */ + PUTU32(ivec + 12, ctr32); + /* ... overflow was detected, propogate carry. */ + if (ctr32 == 0) { + ctr96_inc(ivec); + } + blocks *= 16; + len -= blocks; + out += blocks; + in += blocks; + } + if (len) { + memset(ecount_buf, 0, 16); + (*func)(ecount_buf, ecount_buf, 1, key, ivec); + ++ctr32; + PUTU32(ivec + 12, ctr32); + if (ctr32 == 0) { + ctr96_inc(ivec); + } + while (len--) { + out[n] = in[n] ^ ecount_buf[n]; + ++n; + } + } + + *num = n; +} diff --git a/TMessagesProj/jni/boringssl/crypto/modes/gcm.c b/TMessagesProj/jni/boringssl/crypto/modes/gcm.c new file mode 100644 index 00000000..e7aa46e4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/gcm.c @@ -0,0 +1,1250 @@ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== */ + +#include + +#include +#include + +#include +#include + +#include "internal.h" +#include "../internal.h" + + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) +#define GHASH_ASM +#endif + +#if defined(BSWAP4) && STRICT_ALIGNMENT == 1 +/* redefine, because alignment is ensured */ +#undef GETU32 +#define GETU32(p) BSWAP4(*(const uint32_t *)(p)) +#undef PUTU32 +#define PUTU32(p, v) *(uint32_t *)(p) = BSWAP4(v) +#endif + +#define PACK(s) ((size_t)(s) << (sizeof(size_t) * 8 - 16)) +#define REDUCE1BIT(V) \ + do { \ + if (sizeof(size_t) == 8) { \ + uint64_t T = OPENSSL_U64(0xe100000000000000) & (0 - (V.lo & 1)); \ + V.lo = (V.hi << 63) | (V.lo >> 1); \ + V.hi = (V.hi >> 1) ^ T; \ + } else { \ + uint32_t T = 0xe1000000U & (0 - (uint32_t)(V.lo & 1)); \ + V.lo = (V.hi << 63) | (V.lo >> 1); \ + V.hi = (V.hi >> 1) ^ ((uint64_t)T << 32); \ + } \ + } while (0) + + +static void gcm_init_4bit(u128 Htable[16], uint64_t H[2]) { + u128 V; + + Htable[0].hi = 0; + Htable[0].lo = 0; + V.hi = H[0]; + V.lo = H[1]; + + Htable[8] = V; + REDUCE1BIT(V); + Htable[4] = V; + REDUCE1BIT(V); + Htable[2] = V; + REDUCE1BIT(V); + Htable[1] = V; + Htable[3].hi = V.hi ^ Htable[2].hi, Htable[3].lo = V.lo ^ Htable[2].lo; + V = Htable[4]; + Htable[5].hi = V.hi ^ Htable[1].hi, Htable[5].lo = V.lo ^ Htable[1].lo; + Htable[6].hi = V.hi ^ Htable[2].hi, Htable[6].lo = V.lo ^ Htable[2].lo; + Htable[7].hi = V.hi ^ Htable[3].hi, Htable[7].lo = V.lo ^ Htable[3].lo; + V = Htable[8]; + Htable[9].hi = V.hi ^ Htable[1].hi, Htable[9].lo = V.lo ^ Htable[1].lo; + Htable[10].hi = V.hi ^ Htable[2].hi, Htable[10].lo = V.lo ^ Htable[2].lo; + Htable[11].hi = V.hi ^ Htable[3].hi, Htable[11].lo = V.lo ^ Htable[3].lo; + Htable[12].hi = V.hi ^ Htable[4].hi, Htable[12].lo = V.lo ^ Htable[4].lo; + Htable[13].hi = V.hi ^ Htable[5].hi, Htable[13].lo = V.lo ^ Htable[5].lo; + Htable[14].hi = V.hi ^ Htable[6].hi, Htable[14].lo = V.lo ^ Htable[6].lo; + Htable[15].hi = V.hi ^ Htable[7].hi, Htable[15].lo = V.lo ^ Htable[7].lo; + +#if defined(GHASH_ASM) && defined(OPENSSL_ARM) + /* ARM assembler expects specific dword order in Htable. */ + { + int j; + const union { + long one; + char little; + } is_endian = {1}; + + if (is_endian.little) { + for (j = 0; j < 16; ++j) { + V = Htable[j]; + Htable[j].hi = V.lo; + Htable[j].lo = V.hi; + } + } else { + for (j = 0; j < 16; ++j) { + V = Htable[j]; + Htable[j].hi = V.lo << 32 | V.lo >> 32; + Htable[j].lo = V.hi << 32 | V.hi >> 32; + } + } + } +#endif +} + +#if !defined(GHASH_ASM) || defined(OPENSSL_AARCH64) +static const size_t rem_4bit[16] = { + PACK(0x0000), PACK(0x1C20), PACK(0x3840), PACK(0x2460), + PACK(0x7080), PACK(0x6CA0), PACK(0x48C0), PACK(0x54E0), + PACK(0xE100), PACK(0xFD20), PACK(0xD940), PACK(0xC560), + PACK(0x9180), PACK(0x8DA0), PACK(0xA9C0), PACK(0xB5E0)}; + +static void gcm_gmult_4bit(uint64_t Xi[2], const u128 Htable[16]) { + u128 Z; + int cnt = 15; + size_t rem, nlo, nhi; + const union { + long one; + char little; + } is_endian = {1}; + + nlo = ((const uint8_t *)Xi)[15]; + nhi = nlo >> 4; + nlo &= 0xf; + + Z.hi = Htable[nlo].hi; + Z.lo = Htable[nlo].lo; + + while (1) { + rem = (size_t)Z.lo & 0xf; + Z.lo = (Z.hi << 60) | (Z.lo >> 4); + Z.hi = (Z.hi >> 4); + if (sizeof(size_t) == 8) { + Z.hi ^= rem_4bit[rem]; + } else { + Z.hi ^= (uint64_t)rem_4bit[rem] << 32; + } + + Z.hi ^= Htable[nhi].hi; + Z.lo ^= Htable[nhi].lo; + + if (--cnt < 0) { + break; + } + + nlo = ((const uint8_t *)Xi)[cnt]; + nhi = nlo >> 4; + nlo &= 0xf; + + rem = (size_t)Z.lo & 0xf; + Z.lo = (Z.hi << 60) | (Z.lo >> 4); + Z.hi = (Z.hi >> 4); + if (sizeof(size_t) == 8) { + Z.hi ^= rem_4bit[rem]; + } else { + Z.hi ^= (uint64_t)rem_4bit[rem] << 32; + } + + Z.hi ^= Htable[nlo].hi; + Z.lo ^= Htable[nlo].lo; + } + + if (is_endian.little) { +#ifdef BSWAP8 + Xi[0] = BSWAP8(Z.hi); + Xi[1] = BSWAP8(Z.lo); +#else + uint8_t *p = (uint8_t *)Xi; + uint32_t v; + v = (uint32_t)(Z.hi >> 32); + PUTU32(p, v); + v = (uint32_t)(Z.hi); + PUTU32(p + 4, v); + v = (uint32_t)(Z.lo >> 32); + PUTU32(p + 8, v); + v = (uint32_t)(Z.lo); + PUTU32(p + 12, v); +#endif + } else { + Xi[0] = Z.hi; + Xi[1] = Z.lo; + } +} + +/* Streamed gcm_mult_4bit, see CRYPTO_gcm128_[en|de]crypt for + * details... Compiler-generated code doesn't seem to give any + * performance improvement, at least not on x86[_64]. It's here + * mostly as reference and a placeholder for possible future + * non-trivial optimization[s]... */ +static void gcm_ghash_4bit(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len) { + u128 Z; + int cnt; + size_t rem, nlo, nhi; + const union { + long one; + char little; + } is_endian = {1}; + + do { + cnt = 15; + nlo = ((const uint8_t *)Xi)[15]; + nlo ^= inp[15]; + nhi = nlo >> 4; + nlo &= 0xf; + + Z.hi = Htable[nlo].hi; + Z.lo = Htable[nlo].lo; + + while (1) { + rem = (size_t)Z.lo & 0xf; + Z.lo = (Z.hi << 60) | (Z.lo >> 4); + Z.hi = (Z.hi >> 4); + if (sizeof(size_t) == 8) { + Z.hi ^= rem_4bit[rem]; + } else { + Z.hi ^= (uint64_t)rem_4bit[rem] << 32; + } + + Z.hi ^= Htable[nhi].hi; + Z.lo ^= Htable[nhi].lo; + + if (--cnt < 0) { + break; + } + + nlo = ((const uint8_t *)Xi)[cnt]; + nlo ^= inp[cnt]; + nhi = nlo >> 4; + nlo &= 0xf; + + rem = (size_t)Z.lo & 0xf; + Z.lo = (Z.hi << 60) | (Z.lo >> 4); + Z.hi = (Z.hi >> 4); + if (sizeof(size_t) == 8) { + Z.hi ^= rem_4bit[rem]; + } else { + Z.hi ^= (uint64_t)rem_4bit[rem] << 32; + } + + Z.hi ^= Htable[nlo].hi; + Z.lo ^= Htable[nlo].lo; + } + + if (is_endian.little) { +#ifdef BSWAP8 + Xi[0] = BSWAP8(Z.hi); + Xi[1] = BSWAP8(Z.lo); +#else + uint8_t *p = (uint8_t *)Xi; + uint32_t v; + v = (uint32_t)(Z.hi >> 32); + PUTU32(p, v); + v = (uint32_t)(Z.hi); + PUTU32(p + 4, v); + v = (uint32_t)(Z.lo >> 32); + PUTU32(p + 8, v); + v = (uint32_t)(Z.lo); + PUTU32(p + 12, v); +#endif + } else { + Xi[0] = Z.hi; + Xi[1] = Z.lo; + } + } while (inp += 16, len -= 16); +} +#else /* GHASH_ASM */ +void gcm_gmult_4bit(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_4bit(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); +#endif + +#define GCM_MUL(ctx, Xi) gcm_gmult_4bit(ctx->Xi.u, ctx->Htable) +#if defined(GHASH_ASM) +#define GHASH(ctx, in, len) gcm_ghash_4bit((ctx)->Xi.u, (ctx)->Htable, in, len) +/* GHASH_CHUNK is "stride parameter" missioned to mitigate cache + * trashing effect. In other words idea is to hash data while it's + * still in L1 cache after encryption pass... */ +#define GHASH_CHUNK (3 * 1024) +#endif + + +#if defined(GHASH_ASM) +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +#define GHASH_ASM_X86_OR_64 +#define GCM_FUNCREF_4BIT +void gcm_init_clmul(u128 Htable[16], const uint64_t Xi[2]); +void gcm_gmult_clmul(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_clmul(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); + +#if defined(OPENSSL_X86) +#define gcm_init_avx gcm_init_clmul +#define gcm_gmult_avx gcm_gmult_clmul +#define gcm_ghash_avx gcm_ghash_clmul +#else +void gcm_init_avx(u128 Htable[16], const uint64_t Xi[2]); +void gcm_gmult_avx(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, size_t len); +#endif + +#if defined(OPENSSL_X86) +#define GHASH_ASM_X86 +void gcm_gmult_4bit_mmx(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_4bit_mmx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); + +void gcm_gmult_4bit_x86(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_4bit_x86(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); +#endif +#elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) +#include "../arm_arch.h" +#if __ARM_ARCH__ >= 7 +#define GHASH_ASM_ARM +#define GCM_FUNCREF_4BIT + +static int pmull_capable(void) { + return (OPENSSL_armcap_P & ARMV8_PMULL) != 0; +} + +void gcm_init_v8(u128 Htable[16], const uint64_t Xi[2]); +void gcm_gmult_v8(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_v8(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); + +#if defined(OPENSSL_ARM) +/* 32-bit ARM also has support for doing GCM with NEON instructions. */ +static int neon_capable(void) { + return CRYPTO_is_NEON_capable(); +} + +void gcm_init_neon(u128 Htable[16], const uint64_t Xi[2]); +void gcm_gmult_neon(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_neon(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); +#else +/* AArch64 only has the ARMv8 versions of functions. */ +static int neon_capable(void) { + return 0; +} +void gcm_init_neon(u128 Htable[16], const uint64_t Xi[2]) { + abort(); +} +void gcm_gmult_neon(uint64_t Xi[2], const u128 Htable[16]) { + abort(); +} +void gcm_ghash_neon(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len) { + abort(); +} +#endif + +#endif +#endif +#endif + +#ifdef GCM_FUNCREF_4BIT +#undef GCM_MUL +#define GCM_MUL(ctx, Xi) (*gcm_gmult_p)(ctx->Xi.u, ctx->Htable) +#ifdef GHASH +#undef GHASH +#define GHASH(ctx, in, len) (*gcm_ghash_p)(ctx->Xi.u, ctx->Htable, in, len) +#endif +#endif + +GCM128_CONTEXT *CRYPTO_gcm128_new(void *key, block128_f block) { + GCM128_CONTEXT *ret; + + ret = (GCM128_CONTEXT *)OPENSSL_malloc(sizeof(GCM128_CONTEXT)); + if (ret != NULL) { + CRYPTO_gcm128_init(ret, key, block); + } + + return ret; +} + +void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, void *key, block128_f block) { + const union { + long one; + char little; + } is_endian = {1}; + + memset(ctx, 0, sizeof(*ctx)); + ctx->block = block; + ctx->key = key; + + (*block)(ctx->H.c, ctx->H.c, key); + + if (is_endian.little) { +/* H is stored in host byte order */ +#ifdef BSWAP8 + ctx->H.u[0] = BSWAP8(ctx->H.u[0]); + ctx->H.u[1] = BSWAP8(ctx->H.u[1]); +#else + uint8_t *p = ctx->H.c; + uint64_t hi, lo; + hi = (uint64_t)GETU32(p) << 32 | GETU32(p + 4); + lo = (uint64_t)GETU32(p + 8) << 32 | GETU32(p + 12); + ctx->H.u[0] = hi; + ctx->H.u[1] = lo; +#endif + } + +#if defined(GHASH_ASM_X86_OR_64) + if (crypto_gcm_clmul_enabled()) { + if (((OPENSSL_ia32cap_P[1] >> 22) & 0x41) == 0x41) { /* AVX+MOVBE */ + gcm_init_avx(ctx->Htable, ctx->H.u); + ctx->gmult = gcm_gmult_avx; + ctx->ghash = gcm_ghash_avx; + } else { + gcm_init_clmul(ctx->Htable, ctx->H.u); + ctx->gmult = gcm_gmult_clmul; + ctx->ghash = gcm_ghash_clmul; + } + return; + } + gcm_init_4bit(ctx->Htable, ctx->H.u); +#if defined(GHASH_ASM_X86) /* x86 only */ + if (OPENSSL_ia32cap_P[0] & (1 << 25)) { /* check SSE bit */ + ctx->gmult = gcm_gmult_4bit_mmx; + ctx->ghash = gcm_ghash_4bit_mmx; + } else { + ctx->gmult = gcm_gmult_4bit_x86; + ctx->ghash = gcm_ghash_4bit_x86; + } +#else + ctx->gmult = gcm_gmult_4bit; + ctx->ghash = gcm_ghash_4bit; +#endif +#elif defined(GHASH_ASM_ARM) + if (pmull_capable()) { + gcm_init_v8(ctx->Htable, ctx->H.u); + ctx->gmult = gcm_gmult_v8; + ctx->ghash = gcm_ghash_v8; + } else if (neon_capable()) { + gcm_init_neon(ctx->Htable,ctx->H.u); + ctx->gmult = gcm_gmult_neon; + ctx->ghash = gcm_ghash_neon; + } else { + gcm_init_4bit(ctx->Htable, ctx->H.u); + ctx->gmult = gcm_gmult_4bit; + ctx->ghash = gcm_ghash_4bit; + } +#else + gcm_init_4bit(ctx->Htable, ctx->H.u); + ctx->gmult = gcm_gmult_4bit; + ctx->ghash = gcm_ghash_4bit; +#endif +} + +void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const uint8_t *iv, size_t len) { + const union { + long one; + char little; + } is_endian = {1}; + unsigned int ctr; +#ifdef GCM_FUNCREF_4BIT + void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; +#endif + + ctx->Yi.u[0] = 0; + ctx->Yi.u[1] = 0; + ctx->Xi.u[0] = 0; + ctx->Xi.u[1] = 0; + ctx->len.u[0] = 0; /* AAD length */ + ctx->len.u[1] = 0; /* message length */ + ctx->ares = 0; + ctx->mres = 0; + + if (len == 12) { + memcpy(ctx->Yi.c, iv, 12); + ctx->Yi.c[15] = 1; + ctr = 1; + } else { + size_t i; + uint64_t len0 = len; + + while (len >= 16) { + for (i = 0; i < 16; ++i) { + ctx->Yi.c[i] ^= iv[i]; + } + GCM_MUL(ctx, Yi); + iv += 16; + len -= 16; + } + if (len) { + for (i = 0; i < len; ++i) { + ctx->Yi.c[i] ^= iv[i]; + } + GCM_MUL(ctx, Yi); + } + len0 <<= 3; + if (is_endian.little) { +#ifdef BSWAP8 + ctx->Yi.u[1] ^= BSWAP8(len0); +#else + ctx->Yi.c[8] ^= (uint8_t)(len0 >> 56); + ctx->Yi.c[9] ^= (uint8_t)(len0 >> 48); + ctx->Yi.c[10] ^= (uint8_t)(len0 >> 40); + ctx->Yi.c[11] ^= (uint8_t)(len0 >> 32); + ctx->Yi.c[12] ^= (uint8_t)(len0 >> 24); + ctx->Yi.c[13] ^= (uint8_t)(len0 >> 16); + ctx->Yi.c[14] ^= (uint8_t)(len0 >> 8); + ctx->Yi.c[15] ^= (uint8_t)(len0); +#endif + } else { + ctx->Yi.u[1] ^= len0; + } + + GCM_MUL(ctx, Yi); + + if (is_endian.little) { + ctr = GETU32(ctx->Yi.c + 12); + } else { + ctr = ctx->Yi.d[3]; + } + } + + (*ctx->block)(ctx->Yi.c, ctx->EK0.c, ctx->key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } +} + +int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, size_t len) { + size_t i; + unsigned int n; + uint64_t alen = ctx->len.u[0]; +#ifdef GCM_FUNCREF_4BIT + void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; +#ifdef GHASH + void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len) = ctx->ghash; +#endif +#endif + + if (ctx->len.u[1]) { + return 0; + } + + alen += len; + if (alen > (OPENSSL_U64(1) << 61) || (sizeof(len) == 8 && alen < len)) { + return 0; + } + ctx->len.u[0] = alen; + + n = ctx->ares; + if (n) { + while (n && len) { + ctx->Xi.c[n] ^= *(aad++); + --len; + n = (n + 1) % 16; + } + if (n == 0) { + GCM_MUL(ctx, Xi); + } else { + ctx->ares = n; + return 1; + } + } + +#ifdef GHASH + if ((i = (len & (size_t) - 16))) { + GHASH(ctx, aad, i); + aad += i; + len -= i; + } +#else + while (len >= 16) { + for (i = 0; i < 16; ++i) { + ctx->Xi.c[i] ^= aad[i]; + } + GCM_MUL(ctx, Xi); + aad += 16; + len -= 16; + } +#endif + if (len) { + n = (unsigned int)len; + for (i = 0; i < len; ++i) { + ctx->Xi.c[i] ^= aad[i]; + } + } + + ctx->ares = n; + return 1; +} + +int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const unsigned char *in, + unsigned char *out, size_t len) { + const union { + long one; + char little; + } is_endian = {1}; + unsigned int n, ctr; + size_t i; + uint64_t mlen = ctx->len.u[1]; + block128_f block = ctx->block; + void *key = ctx->key; +#ifdef GCM_FUNCREF_4BIT + void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; +#ifdef GHASH + void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len) = ctx->ghash; +#endif +#endif + + mlen += len; + if (mlen > ((OPENSSL_U64(1) << 36) - 32) || + (sizeof(len) == 8 && mlen < len)) { + return 0; + } + ctx->len.u[1] = mlen; + + if (ctx->ares) { + /* First call to encrypt finalizes GHASH(AAD) */ + GCM_MUL(ctx, Xi); + ctx->ares = 0; + } + + if (is_endian.little) { + ctr = GETU32(ctx->Yi.c + 12); + } else { + ctr = ctx->Yi.d[3]; + } + + n = ctx->mres; + if (n) { + while (n && len) { + ctx->Xi.c[n] ^= *(out++) = *(in++) ^ ctx->EKi.c[n]; + --len; + n = (n + 1) % 16; + } + if (n == 0) { + GCM_MUL(ctx, Xi); + } else { + ctx->mres = n; + return 1; + } + } + if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out) % sizeof(size_t) != 0) { + for (i = 0; i < len; ++i) { + if (n == 0) { + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + } + ctx->Xi.c[n] ^= out[i] = in[i] ^ ctx->EKi.c[n]; + n = (n + 1) % 16; + if (n == 0) { + GCM_MUL(ctx, Xi); + } + } + + ctx->mres = n; + return 1; + } +#if defined(GHASH) && defined(GHASH_CHUNK) + while (len >= GHASH_CHUNK) { + size_t j = GHASH_CHUNK; + + while (j) { + size_t *out_t = (size_t *)out; + const size_t *in_t = (const size_t *)in; + + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + for (i = 0; i < 16 / sizeof(size_t); ++i) { + out_t[i] = in_t[i] ^ ctx->EKi.t[i]; + } + out += 16; + in += 16; + j -= 16; + } + GHASH(ctx, out - GHASH_CHUNK, GHASH_CHUNK); + len -= GHASH_CHUNK; + } + if ((i = (len & (size_t) - 16))) { + size_t j = i; + + while (len >= 16) { + size_t *out_t = (size_t *)out; + const size_t *in_t = (const size_t *)in; + + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + for (i = 0; i < 16 / sizeof(size_t); ++i) { + out_t[i] = in_t[i] ^ ctx->EKi.t[i]; + } + out += 16; + in += 16; + len -= 16; + } + GHASH(ctx, out - j, j); + } +#else + while (len >= 16) { + size_t *out_t = (size_t *)out; + const size_t *in_t = (const size_t *)in; + + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + for (i = 0; i < 16 / sizeof(size_t); ++i) { + ctx->Xi.t[i] ^= out_t[i] = in_t[i] ^ ctx->EKi.t[i]; + } + GCM_MUL(ctx, Xi); + out += 16; + in += 16; + len -= 16; + } +#endif + if (len) { + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + while (len--) { + ctx->Xi.c[n] ^= out[n] = in[n] ^ ctx->EKi.c[n]; + ++n; + } + } + + ctx->mres = n; + return 1; +} + +int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const unsigned char *in, + unsigned char *out, size_t len) { + const union { + long one; + char little; + } is_endian = {1}; + unsigned int n, ctr; + size_t i; + uint64_t mlen = ctx->len.u[1]; + block128_f block = ctx->block; + void *key = ctx->key; +#ifdef GCM_FUNCREF_4BIT + void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; +#ifdef GHASH + void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len) = ctx->ghash; +#endif +#endif + + mlen += len; + if (mlen > ((OPENSSL_U64(1) << 36) - 32) || + (sizeof(len) == 8 && mlen < len)) { + return 0; + } + ctx->len.u[1] = mlen; + + if (ctx->ares) { + /* First call to decrypt finalizes GHASH(AAD) */ + GCM_MUL(ctx, Xi); + ctx->ares = 0; + } + + if (is_endian.little) { + ctr = GETU32(ctx->Yi.c + 12); + } else { + ctr = ctx->Yi.d[3]; + } + + n = ctx->mres; + if (n) { + while (n && len) { + uint8_t c = *(in++); + *(out++) = c ^ ctx->EKi.c[n]; + ctx->Xi.c[n] ^= c; + --len; + n = (n + 1) % 16; + } + if (n == 0) { + GCM_MUL(ctx, Xi); + } else { + ctx->mres = n; + return 1; + } + } + if (STRICT_ALIGNMENT && ((size_t)in | (size_t)out) % sizeof(size_t) != 0) { + for (i = 0; i < len; ++i) { + uint8_t c; + if (n == 0) { + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + } + c = in[i]; + out[i] = c ^ ctx->EKi.c[n]; + ctx->Xi.c[n] ^= c; + n = (n + 1) % 16; + if (n == 0) { + GCM_MUL(ctx, Xi); + } + } + + ctx->mres = n; + return 1; + } +#if defined(GHASH) && defined(GHASH_CHUNK) + while (len >= GHASH_CHUNK) { + size_t j = GHASH_CHUNK; + + GHASH(ctx, in, GHASH_CHUNK); + while (j) { + size_t *out_t = (size_t *)out; + const size_t *in_t = (const size_t *)in; + + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + for (i = 0; i < 16 / sizeof(size_t); ++i) { + out_t[i] = in_t[i] ^ ctx->EKi.t[i]; + } + out += 16; + in += 16; + j -= 16; + } + len -= GHASH_CHUNK; + } + if ((i = (len & (size_t) - 16))) { + GHASH(ctx, in, i); + while (len >= 16) { + size_t *out_t = (size_t *)out; + const size_t *in_t = (const size_t *)in; + + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + for (i = 0; i < 16 / sizeof(size_t); ++i) { + out_t[i] = in_t[i] ^ ctx->EKi.t[i]; + } + out += 16; + in += 16; + len -= 16; + } + } +#else + while (len >= 16) { + size_t *out_t = (size_t *)out; + const size_t *in_t = (const size_t *)in; + + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + for (i = 0; i < 16 / sizeof(size_t); ++i) { + size_t c = in_t[i]; + out_t[i] = c ^ ctx->EKi.t[i]; + ctx->Xi.t[i] ^= c; + } + GCM_MUL(ctx, Xi); + out += 16; + in += 16; + len -= 16; + } +#endif + if (len) { + (*block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + while (len--) { + uint8_t c = in[n]; + ctx->Xi.c[n] ^= c; + out[n] = c ^ ctx->EKi.c[n]; + ++n; + } + } + + ctx->mres = n; + return 1; +} + +int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const uint8_t *in, + uint8_t *out, size_t len, ctr128_f stream) { + const union { + long one; + char little; + } is_endian = {1}; + unsigned int n, ctr; + size_t i; + uint64_t mlen = ctx->len.u[1]; + void *key = ctx->key; +#ifdef GCM_FUNCREF_4BIT + void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; +#ifdef GHASH + void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len) = ctx->ghash; +#endif +#endif + + mlen += len; + if (mlen > ((OPENSSL_U64(1) << 36) - 32) || + (sizeof(len) == 8 && mlen < len)) { + return 0; + } + ctx->len.u[1] = mlen; + + if (ctx->ares) { + /* First call to encrypt finalizes GHASH(AAD) */ + GCM_MUL(ctx, Xi); + ctx->ares = 0; + } + + if (is_endian.little) { + ctr = GETU32(ctx->Yi.c + 12); + } else { + ctr = ctx->Yi.d[3]; + } + + n = ctx->mres; + if (n) { + while (n && len) { + ctx->Xi.c[n] ^= *(out++) = *(in++) ^ ctx->EKi.c[n]; + --len; + n = (n + 1) % 16; + } + if (n == 0) { + GCM_MUL(ctx, Xi); + } else { + ctx->mres = n; + return 1; + } + } +#if defined(GHASH) + while (len >= GHASH_CHUNK) { + (*stream)(in, out, GHASH_CHUNK / 16, key, ctx->Yi.c); + ctr += GHASH_CHUNK / 16; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + GHASH(ctx, out, GHASH_CHUNK); + out += GHASH_CHUNK; + in += GHASH_CHUNK; + len -= GHASH_CHUNK; + } +#endif + if ((i = (len & (size_t) - 16))) { + size_t j = i / 16; + + (*stream)(in, out, j, key, ctx->Yi.c); + ctr += (unsigned int)j; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + in += i; + len -= i; +#if defined(GHASH) + GHASH(ctx, out, i); + out += i; +#else + while (j--) { + for (i = 0; i < 16; ++i) { + ctx->Xi.c[i] ^= out[i]; + } + GCM_MUL(ctx, Xi); + out += 16; + } +#endif + } + if (len) { + (*ctx->block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + while (len--) { + ctx->Xi.c[n] ^= out[n] = in[n] ^ ctx->EKi.c[n]; + ++n; + } + } + + ctx->mres = n; + return 1; +} + +int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const uint8_t *in, + uint8_t *out, size_t len, + ctr128_f stream) { + const union { + long one; + char little; + } is_endian = {1}; + unsigned int n, ctr; + size_t i; + uint64_t mlen = ctx->len.u[1]; + void *key = ctx->key; +#ifdef GCM_FUNCREF_4BIT + void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; +#ifdef GHASH + void (*gcm_ghash_p)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len) = ctx->ghash; +#endif +#endif + + mlen += len; + if (mlen > ((OPENSSL_U64(1) << 36) - 32) || + (sizeof(len) == 8 && mlen < len)) { + return 0; + } + ctx->len.u[1] = mlen; + + if (ctx->ares) { + /* First call to decrypt finalizes GHASH(AAD) */ + GCM_MUL(ctx, Xi); + ctx->ares = 0; + } + + if (is_endian.little) { + ctr = GETU32(ctx->Yi.c + 12); + } else { + ctr = ctx->Yi.d[3]; + } + + n = ctx->mres; + if (n) { + while (n && len) { + uint8_t c = *(in++); + *(out++) = c ^ ctx->EKi.c[n]; + ctx->Xi.c[n] ^= c; + --len; + n = (n + 1) % 16; + } + if (n == 0) { + GCM_MUL(ctx, Xi); + } else { + ctx->mres = n; + return 1; + } + } +#if defined(GHASH) + while (len >= GHASH_CHUNK) { + GHASH(ctx, in, GHASH_CHUNK); + (*stream)(in, out, GHASH_CHUNK / 16, key, ctx->Yi.c); + ctr += GHASH_CHUNK / 16; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + out += GHASH_CHUNK; + in += GHASH_CHUNK; + len -= GHASH_CHUNK; + } +#endif + if ((i = (len & (size_t) - 16))) { + size_t j = i / 16; + +#if defined(GHASH) + GHASH(ctx, in, i); +#else + while (j--) { + size_t k; + for (k = 0; k < 16; ++k) { + ctx->Xi.c[k] ^= in[k]; + } + GCM_MUL(ctx, Xi); + in += 16; + } + j = i / 16; + in -= i; +#endif + (*stream)(in, out, j, key, ctx->Yi.c); + ctr += (unsigned int)j; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + out += i; + in += i; + len -= i; + } + if (len) { + (*ctx->block)(ctx->Yi.c, ctx->EKi.c, key); + ++ctr; + if (is_endian.little) { + PUTU32(ctx->Yi.c + 12, ctr); + } else { + ctx->Yi.d[3] = ctr; + } + while (len--) { + uint8_t c = in[n]; + ctx->Xi.c[n] ^= c; + out[n] = c ^ ctx->EKi.c[n]; + ++n; + } + } + + ctx->mres = n; + return 1; +} + +int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const uint8_t *tag, size_t len) { + const union { + long one; + char little; + } is_endian = {1}; + uint64_t alen = ctx->len.u[0] << 3; + uint64_t clen = ctx->len.u[1] << 3; +#ifdef GCM_FUNCREF_4BIT + void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; +#endif + + if (ctx->mres || ctx->ares) { + GCM_MUL(ctx, Xi); + } + + if (is_endian.little) { +#ifdef BSWAP8 + alen = BSWAP8(alen); + clen = BSWAP8(clen); +#else + uint8_t *p = ctx->len.c; + + ctx->len.u[0] = alen; + ctx->len.u[1] = clen; + + alen = (uint64_t)GETU32(p) << 32 | GETU32(p + 4); + clen = (uint64_t)GETU32(p + 8) << 32 | GETU32(p + 12); +#endif + } + + ctx->Xi.u[0] ^= alen; + ctx->Xi.u[1] ^= clen; + GCM_MUL(ctx, Xi); + + ctx->Xi.u[0] ^= ctx->EK0.u[0]; + ctx->Xi.u[1] ^= ctx->EK0.u[1]; + + if (tag && len <= sizeof(ctx->Xi)) { + return CRYPTO_memcmp(ctx->Xi.c, tag, len) == 0; + } else { + return 0; + } +} + +void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, unsigned char *tag, size_t len) { + CRYPTO_gcm128_finish(ctx, NULL, 0); + memcpy(tag, ctx->Xi.c, len <= sizeof(ctx->Xi.c) ? len : sizeof(ctx->Xi.c)); +} + +void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx) { + if (ctx) { + OPENSSL_cleanse(ctx, sizeof(*ctx)); + OPENSSL_free(ctx); + } +} + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +int crypto_gcm_clmul_enabled(void) { +#ifdef GHASH_ASM + return OPENSSL_ia32cap_P[0] & (1 << 24) && /* check FXSR bit */ + OPENSSL_ia32cap_P[1] & (1 << 1); /* check PCLMULQDQ bit */ +#else + return 0; +#endif +} +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/modes/internal.h b/TMessagesProj/jni/boringssl/crypto/modes/internal.h new file mode 100644 index 00000000..d12405e6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/internal.h @@ -0,0 +1,202 @@ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== */ + +#ifndef OPENSSL_HEADER_MODES_INTERNAL_H +#define OPENSSL_HEADER_MODES_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#define asm __asm__ + +#define STRICT_ALIGNMENT 1 +#if defined(OPENSSL_X86_64) || defined(OPENSSL_X86) || defined(OPENSSL_AARCH64) +#undef STRICT_ALIGNMENT +#define STRICT_ALIGNMENT 0 +#endif + +#if !defined(PEDANTIC) && !defined(OPENSSL_NO_ASM) +#if defined(__GNUC__) && __GNUC__ >= 2 +#if defined(OPENSSL_X86_64) +#define BSWAP8(x) \ + ({ \ + uint64_t ret = (x); \ + asm("bswapq %0" : "+r"(ret)); \ + ret; \ + }) +#define BSWAP4(x) \ + ({ \ + uint32_t ret = (x); \ + asm("bswapl %0" : "+r"(ret)); \ + ret; \ + }) +#elif defined(OPENSSL_X86) +#define BSWAP8(x) \ + ({ \ + uint32_t lo = (uint64_t)(x) >> 32, hi = (x); \ + asm("bswapl %0; bswapl %1" : "+r"(hi), "+r"(lo)); \ + (uint64_t) hi << 32 | lo; \ + }) +#define BSWAP4(x) \ + ({ \ + uint32_t ret = (x); \ + asm("bswapl %0" : "+r"(ret)); \ + ret; \ + }) +#elif defined(OPENSSL_AARCH64) +#define BSWAP8(x) \ + ({ \ + uint64_t ret; \ + asm("rev %0,%1" : "=r"(ret) : "r"(x)); \ + ret; \ + }) +#define BSWAP4(x) \ + ({ \ + uint32_t ret; \ + asm("rev %w0,%w1" : "=r"(ret) : "r"(x)); \ + ret; \ + }) +#elif defined(OPENSSL_ARM) && !defined(STRICT_ALIGNMENT) +#define BSWAP8(x) \ + ({ \ + uint32_t lo = (uint64_t)(x) >> 32, hi = (x); \ + asm("rev %0,%0; rev %1,%1" : "+r"(hi), "+r"(lo)); \ + (uint64_t) hi << 32 | lo; \ + }) +#define BSWAP4(x) \ + ({ \ + uint32_t ret; \ + asm("rev %0,%1" : "=r"(ret) : "r"((uint32_t)(x))); \ + ret; \ + }) +#endif +#elif defined(_MSC_VER) +#if _MSC_VER >= 1300 +#pragma warning(push, 3) +#include +#pragma warning(pop) +#pragma intrinsic(_byteswap_uint64, _byteswap_ulong) +#define BSWAP8(x) _byteswap_uint64((uint64_t)(x)) +#define BSWAP4(x) _byteswap_ulong((uint32_t)(x)) +#elif defined(OPENSSL_X86) +__inline uint32_t _bswap4(uint32_t val) { + _asm mov eax, val + _asm bswap eax +} +#define BSWAP4(x) _bswap4(x) +#endif +#endif +#endif + +#if defined(BSWAP4) && !defined(STRICT_ALIGNMENT) +#define GETU32(p) BSWAP4(*(const uint32_t *)(p)) +#define PUTU32(p, v) *(uint32_t *)(p) = BSWAP4(v) +#else +#define GETU32(p) \ + ((uint32_t)(p)[0] << 24 | (uint32_t)(p)[1] << 16 | (uint32_t)(p)[2] << 8 | (uint32_t)(p)[3]) +#define PUTU32(p, v) \ + ((p)[0] = (uint8_t)((v) >> 24), (p)[1] = (uint8_t)((v) >> 16), \ + (p)[2] = (uint8_t)((v) >> 8), (p)[3] = (uint8_t)(v)) +#endif + + +/* GCM definitions */ +typedef struct { uint64_t hi,lo; } u128; + +struct gcm128_context { + /* Following 6 names follow names in GCM specification */ + union { + uint64_t u[2]; + uint32_t d[4]; + uint8_t c[16]; + size_t t[16 / sizeof(size_t)]; + } Yi, EKi, EK0, len, Xi, H; + + /* Relative position of Xi, H and pre-computed Htable is used in some + * assembler modules, i.e. don't change the order! */ + u128 Htable[16]; + void (*gmult)(uint64_t Xi[2], const u128 Htable[16]); + void (*ghash)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); + + unsigned int mres, ares; + block128_f block; + void *key; +}; + +struct xts128_context { + void *key1, *key2; + block128_f block1, block2; +}; + +struct ccm128_context { + union { + uint64_t u[2]; + uint8_t c[16]; + } nonce, cmac; + uint64_t blocks; + block128_f block; + void *key; +}; + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +/* crypto_gcm_clmul_enabled returns one if the CLMUL implementation of GCM is + * used. */ +int crypto_gcm_clmul_enabled(void); +#endif + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_MODES_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/modes/ofb.c b/TMessagesProj/jni/boringssl/crypto/modes/ofb.c new file mode 100644 index 00000000..5836a9f4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/modes/ofb.c @@ -0,0 +1,107 @@ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== */ + +#include + +#include + +#include "internal.h" + + +void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], int *num, + block128_f block) { + unsigned int n; + + assert(in && out && key && ivec && num); + assert((16 % sizeof(size_t)) == 0); + + n = *num; + + while (n && len) { + *(out++) = *(in++) ^ ivec[n]; + --len; + n = (n + 1) % 16; + } + +#if STRICT_ALIGNMENT + if (((size_t)in | (size_t)out | (size_t)ivec) % sizeof(size_t) != 0) { + size_t l = 0; + while (l < len) { + if (n == 0) { + (*block)(ivec, ivec, key); + } + out[l] = in[l] ^ ivec[n]; + ++l; + n = (n + 1) % 16; + } + + *num = n; + return; + } +#endif + + while (len >= 16) { + (*block)(ivec, ivec, key); + for (; n < 16; n += sizeof(size_t)) { + *(size_t *)(out + n) = *(size_t *)(in + n) ^ *(size_t *)(ivec + n); + } + len -= 16; + out += 16; + in += 16; + n = 0; + } + if (len) { + (*block)(ivec, ivec, key); + while (len--) { + out[n] = in[n] ^ ivec[n]; + ++n; + } + } + *num = n; +} diff --git a/TMessagesProj/jni/boringssl/crypto/pem/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/pem/CMakeLists.txt new file mode 100644 index 00000000..720ba2ff --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/CMakeLists.txt @@ -0,0 +1,16 @@ +include_directories(. .. ../../include) + +add_library( + pem + + OBJECT + + pem_all.c + pem_info.c + pem_lib.c + pem_oth.c + pem_pk8.c + pem_pkey.c + pem_x509.c + pem_xaux.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_all.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_all.c new file mode 100644 index 00000000..24ecc62a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_all.c @@ -0,0 +1,281 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2002 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include +/*#include */ +#include +#include + + +static RSA *pkey_get_rsa(EVP_PKEY *key, RSA **rsa); +static DSA *pkey_get_dsa(EVP_PKEY *key, DSA **dsa); +static EC_KEY *pkey_get_eckey(EVP_PKEY *key, EC_KEY **eckey); + + +IMPLEMENT_PEM_rw(X509_REQ, X509_REQ, PEM_STRING_X509_REQ, X509_REQ) + +IMPLEMENT_PEM_write(X509_REQ_NEW, X509_REQ, PEM_STRING_X509_REQ_OLD, X509_REQ) + +IMPLEMENT_PEM_rw(X509_CRL, X509_CRL, PEM_STRING_X509_CRL, X509_CRL) + + + +/* We treat RSA or DSA private keys as a special case. + * + * For private keys we read in an EVP_PKEY structure with + * PEM_read_bio_PrivateKey() and extract the relevant private + * key: this means can handle "traditional" and PKCS#8 formats + * transparently. + */ + +static RSA *pkey_get_rsa(EVP_PKEY *key, RSA **rsa) +{ + RSA *rtmp; + if(!key) return NULL; + rtmp = EVP_PKEY_get1_RSA(key); + EVP_PKEY_free(key); + if(!rtmp) return NULL; + if(rsa) { + RSA_free(*rsa); + *rsa = rtmp; + } + return rtmp; +} + +RSA *PEM_read_bio_RSAPrivateKey(BIO *bp, RSA **rsa, pem_password_cb *cb, + void *u) +{ + EVP_PKEY *pktmp; + pktmp = PEM_read_bio_PrivateKey(bp, NULL, cb, u); + return pkey_get_rsa(pktmp, rsa); +} + +#ifndef OPENSSL_NO_FP_API + +RSA *PEM_read_RSAPrivateKey(FILE *fp, RSA **rsa, pem_password_cb *cb, + void *u) +{ + EVP_PKEY *pktmp; + pktmp = PEM_read_PrivateKey(fp, NULL, cb, u); + return pkey_get_rsa(pktmp, rsa); +} + +#endif + +IMPLEMENT_PEM_write_cb_const(RSAPrivateKey, RSA, PEM_STRING_RSA, RSAPrivateKey) + +IMPLEMENT_PEM_rw_const(RSAPublicKey, RSA, PEM_STRING_RSA_PUBLIC, RSAPublicKey) +IMPLEMENT_PEM_rw(RSA_PUBKEY, RSA, PEM_STRING_PUBLIC, RSA_PUBKEY) + +#ifndef OPENSSL_NO_DSA + +static DSA *pkey_get_dsa(EVP_PKEY *key, DSA **dsa) +{ + DSA *dtmp; + if(!key) return NULL; + dtmp = EVP_PKEY_get1_DSA(key); + EVP_PKEY_free(key); + if(!dtmp) return NULL; + if(dsa) { + DSA_free(*dsa); + *dsa = dtmp; + } + return dtmp; +} + +DSA *PEM_read_bio_DSAPrivateKey(BIO *bp, DSA **dsa, pem_password_cb *cb, + void *u) +{ + EVP_PKEY *pktmp; + pktmp = PEM_read_bio_PrivateKey(bp, NULL, cb, u); + return pkey_get_dsa(pktmp, dsa); /* will free pktmp */ +} + + +IMPLEMENT_PEM_write_cb_const(DSAPrivateKey, DSA, PEM_STRING_DSA, DSAPrivateKey) + +IMPLEMENT_PEM_rw(DSA_PUBKEY, DSA, PEM_STRING_PUBLIC, DSA_PUBKEY) + +#ifndef OPENSSL_NO_FP_API + +DSA *PEM_read_DSAPrivateKey(FILE *fp, DSA **dsa, pem_password_cb *cb, + void *u) +{ + EVP_PKEY *pktmp; + pktmp = PEM_read_PrivateKey(fp, NULL, cb, u); + return pkey_get_dsa(pktmp, dsa); /* will free pktmp */ +} + +#endif + +IMPLEMENT_PEM_rw_const(DSAparams, DSA, PEM_STRING_DSAPARAMS, DSAparams) + +#endif + + +static EC_KEY *pkey_get_eckey(EVP_PKEY *key, EC_KEY **eckey) +{ + EC_KEY *dtmp; + if(!key) return NULL; + dtmp = EVP_PKEY_get1_EC_KEY(key); + EVP_PKEY_free(key); + if(!dtmp) return NULL; + if(eckey) + { + EC_KEY_free(*eckey); + *eckey = dtmp; + } + return dtmp; +} + +EC_KEY *PEM_read_bio_ECPrivateKey(BIO *bp, EC_KEY **key, pem_password_cb *cb, + void *u) +{ + EVP_PKEY *pktmp; + pktmp = PEM_read_bio_PrivateKey(bp, NULL, cb, u); + return pkey_get_eckey(pktmp, key); /* will free pktmp */ +} + +/* TODO(fork): remove this code? */ +/* IMPLEMENT_PEM_rw_const(ECPKParameters, EC_GROUP, PEM_STRING_ECPARAMETERS, ECPKParameters) */ + + + + +IMPLEMENT_PEM_write_cb(ECPrivateKey, EC_KEY, PEM_STRING_ECPRIVATEKEY, ECPrivateKey) + + +IMPLEMENT_PEM_rw(EC_PUBKEY, EC_KEY, PEM_STRING_PUBLIC, EC_PUBKEY) + +#ifndef OPENSSL_NO_FP_API + +EC_KEY *PEM_read_ECPrivateKey(FILE *fp, EC_KEY **eckey, pem_password_cb *cb, + void *u) +{ + EVP_PKEY *pktmp; + pktmp = PEM_read_PrivateKey(fp, NULL, cb, u); + return pkey_get_eckey(pktmp, eckey); /* will free pktmp */ +} + +#endif + + + +IMPLEMENT_PEM_write_const(DHparams, DH, PEM_STRING_DHPARAMS, DHparams) + +/* TODO(fork): remove this code? */ +/* IMPLEMENT_PEM_write_const(DHxparams, DH, PEM_STRING_DHXPARAMS, DHxparams) */ + + +IMPLEMENT_PEM_rw(PUBKEY, EVP_PKEY, PEM_STRING_PUBLIC, PUBKEY) diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_info.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_info.c new file mode 100644 index 00000000..b4ae8054 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_info.c @@ -0,0 +1,404 @@ +/* crypto/pem/pem_info.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifndef OPENSSL_NO_FP_API +STACK_OF(X509_INFO) *PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u) + { + BIO *b; + STACK_OF(X509_INFO) *ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=PEM_X509_INFO_read_bio(b,sk,cb,u); + BIO_free(b); + return(ret); + } +#endif + +STACK_OF(X509_INFO) *PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u) + { + X509_INFO *xi=NULL; + char *name=NULL,*header=NULL; + void *pp; + unsigned char *data=NULL; + const unsigned char *p; + long len,error=0; + int ok=0; + STACK_OF(X509_INFO) *ret=NULL; + unsigned int i,raw,ptype; + d2i_of_void *d2i = 0; + + if (sk == NULL) + { + if ((ret=sk_X509_INFO_new_null()) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + } + else + ret=sk; + + if ((xi=X509_INFO_new()) == NULL) goto err; + for (;;) + { + raw=0; + ptype = 0; + i=PEM_read_bio(bp,&name,&header,&data,&len); + if (i == 0) + { + error=ERR_GET_REASON(ERR_peek_last_error()); + if (error == PEM_R_NO_START_LINE) + { + ERR_clear_error(); + break; + } + goto err; + } +start: + if ( (strcmp(name,PEM_STRING_X509) == 0) || + (strcmp(name,PEM_STRING_X509_OLD) == 0)) + { + d2i=(D2I_OF(void))d2i_X509; + if (xi->x509 != NULL) + { + if (!sk_X509_INFO_push(ret,xi)) goto err; + if ((xi=X509_INFO_new()) == NULL) goto err; + goto start; + } + pp=&(xi->x509); + } + else if ((strcmp(name,PEM_STRING_X509_TRUSTED) == 0)) + { + d2i=(D2I_OF(void))d2i_X509_AUX; + if (xi->x509 != NULL) + { + if (!sk_X509_INFO_push(ret,xi)) goto err; + if ((xi=X509_INFO_new()) == NULL) goto err; + goto start; + } + pp=&(xi->x509); + } + else if (strcmp(name,PEM_STRING_X509_CRL) == 0) + { + d2i=(D2I_OF(void))d2i_X509_CRL; + if (xi->crl != NULL) + { + if (!sk_X509_INFO_push(ret,xi)) goto err; + if ((xi=X509_INFO_new()) == NULL) goto err; + goto start; + } + pp=&(xi->crl); + } + else + if (strcmp(name,PEM_STRING_RSA) == 0) + { + d2i=(D2I_OF(void))d2i_RSAPrivateKey; + if (xi->x_pkey != NULL) + { + if (!sk_X509_INFO_push(ret,xi)) goto err; + if ((xi=X509_INFO_new()) == NULL) goto err; + goto start; + } + + xi->enc_data=NULL; + xi->enc_len=0; + + xi->x_pkey=X509_PKEY_new(); + ptype=EVP_PKEY_RSA; + pp=&xi->x_pkey->dec_pkey; + if ((int)strlen(header) > 10) /* assume encrypted */ + raw=1; + } + else +#ifndef OPENSSL_NO_DSA + if (strcmp(name,PEM_STRING_DSA) == 0) + { + d2i=(D2I_OF(void))d2i_DSAPrivateKey; + if (xi->x_pkey != NULL) + { + if (!sk_X509_INFO_push(ret,xi)) goto err; + if ((xi=X509_INFO_new()) == NULL) goto err; + goto start; + } + + xi->enc_data=NULL; + xi->enc_len=0; + + xi->x_pkey=X509_PKEY_new(); + ptype = EVP_PKEY_DSA; + pp=&xi->x_pkey->dec_pkey; + if ((int)strlen(header) > 10) /* assume encrypted */ + raw=1; + } + else +#endif + if (strcmp(name,PEM_STRING_ECPRIVATEKEY) == 0) + { + d2i=(D2I_OF(void))d2i_ECPrivateKey; + if (xi->x_pkey != NULL) + { + if (!sk_X509_INFO_push(ret,xi)) goto err; + if ((xi=X509_INFO_new()) == NULL) goto err; + goto start; + } + + xi->enc_data=NULL; + xi->enc_len=0; + + xi->x_pkey=X509_PKEY_new(); + ptype = EVP_PKEY_EC; + pp=&xi->x_pkey->dec_pkey; + if ((int)strlen(header) > 10) /* assume encrypted */ + raw=1; + } + else + { + d2i=NULL; + pp=NULL; + } + + if (d2i != NULL) + { + if (!raw) + { + EVP_CIPHER_INFO cipher; + + if (!PEM_get_EVP_CIPHER_INFO(header,&cipher)) + goto err; + if (!PEM_do_header(&cipher,data,&len,cb,u)) + goto err; + p=data; + if (ptype) + { + if (!d2i_PrivateKey(ptype, pp, &p, len)) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + goto err; + } + } + else if (d2i(pp,&p,len) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + goto err; + } + } + else + { /* encrypted RSA data */ + if (!PEM_get_EVP_CIPHER_INFO(header, + &xi->enc_cipher)) goto err; + xi->enc_data=(char *)data; + xi->enc_len=(int)len; + data=NULL; + } + } + else { + /* unknown */ + } + if (name != NULL) OPENSSL_free(name); + if (header != NULL) OPENSSL_free(header); + if (data != NULL) OPENSSL_free(data); + name=NULL; + header=NULL; + data=NULL; + } + + /* if the last one hasn't been pushed yet and there is anything + * in it then add it to the stack ... + */ + if ((xi->x509 != NULL) || (xi->crl != NULL) || + (xi->x_pkey != NULL) || (xi->enc_data != NULL)) + { + if (!sk_X509_INFO_push(ret,xi)) goto err; + xi=NULL; + } + ok=1; +err: + if (xi != NULL) X509_INFO_free(xi); + if (!ok) + { + for (i=0; ((int)i)x_pkey!=NULL) + { + if ( (xi->enc_data!=NULL) && (xi->enc_len>0) ) + { + if (enc == NULL) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_CIPHER_IS_NULL); + goto err; + } + + /* copy from weirdo names into more normal things */ + iv=xi->enc_cipher.iv; + data=(unsigned char *)xi->enc_data; + i=xi->enc_len; + + /* we take the encryption data from the + * internal stuff rather than what the + * user has passed us ... as we have to + * match exactly for some strange reason + */ + objstr=OBJ_nid2sn( + EVP_CIPHER_nid(xi->enc_cipher.cipher)); + if (objstr == NULL) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_CIPHER); + goto err; + } + + /* create the right magic header stuff */ + assert(strlen(objstr)+23+2*iv_len+13 <= sizeof buf); + buf[0]='\0'; + PEM_proc_type(buf,PEM_TYPE_ENCRYPTED); + PEM_dek_info(buf,objstr,iv_len,(char *)iv); + + /* use the normal code to write things out */ + i=PEM_write_bio(bp,PEM_STRING_RSA,buf,data,i); + if (i <= 0) goto err; + } + else + { + /* Add DSA/DH */ + /* normal optionally encrypted stuff */ + if (PEM_write_bio_RSAPrivateKey(bp, + xi->x_pkey->dec_pkey->pkey.rsa, + enc,kstr,klen,cb,u)<=0) + goto err; + } + } + + /* if we have a certificate then write it out now */ + if ((xi->x509 != NULL) && (PEM_write_bio_X509(bp,xi->x509) <= 0)) + goto err; + + /* we are ignoring anything else that is loaded into the X509_INFO + * structure for the moment ... as I don't need it so I'm not + * coding it here and Eric can do it when this makes it into the + * base library --tjh + */ + + ret=1; + +err: + OPENSSL_cleanse((char *)&ctx,sizeof(ctx)); + OPENSSL_cleanse(buf,PEM_BUFSIZE); + return(ret); + } diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_lib.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_lib.c new file mode 100644 index 00000000..59156969 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_lib.c @@ -0,0 +1,835 @@ +/* crypto/pem/pem_lib.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../evp/internal.h" + + +#define MIN_LENGTH 4 + +static int load_iv(char **fromp,unsigned char *to, int num); +static int check_pem(const char *nm, const char *name); +int pem_check_suffix(const char *pem_str, const char *suffix); + +void PEM_proc_type(char *buf, int type) + { + const char *str; + + if (type == PEM_TYPE_ENCRYPTED) + str="ENCRYPTED"; + else if (type == PEM_TYPE_MIC_CLEAR) + str="MIC-CLEAR"; + else if (type == PEM_TYPE_MIC_ONLY) + str="MIC-ONLY"; + else + str="BAD-TYPE"; + + BUF_strlcat(buf,"Proc-Type: 4,",PEM_BUFSIZE); + BUF_strlcat(buf,str,PEM_BUFSIZE); + BUF_strlcat(buf,"\n",PEM_BUFSIZE); + } + +void PEM_dek_info(char *buf, const char *type, int len, char *str) + { + static const unsigned char map[17]="0123456789ABCDEF"; + long i; + int j; + + BUF_strlcat(buf,"DEK-Info: ",PEM_BUFSIZE); + BUF_strlcat(buf,type,PEM_BUFSIZE); + BUF_strlcat(buf,",",PEM_BUFSIZE); + j=strlen(buf); + if (j + (len * 2) + 1 > PEM_BUFSIZE) + return; + for (i=0; i>4)&0x0f]; + buf[j+i*2+1]=map[(str[i] )&0x0f]; + } + buf[j+i*2]='\n'; + buf[j+i*2+1]='\0'; + } + +#ifndef OPENSSL_NO_FP_API +void *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x, + pem_password_cb *cb, void *u) + { + BIO *b; + void *ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=PEM_ASN1_read_bio(d2i,name,b,x,cb,u); + BIO_free(b); + return(ret); + } +#endif + +static int check_pem(const char *nm, const char *name) +{ + /* Normal matching nm and name */ + if (!strcmp(nm,name)) return 1; + + /* Make PEM_STRING_EVP_PKEY match any private key */ + + if(!strcmp(name,PEM_STRING_EVP_PKEY)) + { + int slen; + const EVP_PKEY_ASN1_METHOD *ameth; + if(!strcmp(nm,PEM_STRING_PKCS8)) + return 1; + if(!strcmp(nm,PEM_STRING_PKCS8INF)) + return 1; + slen = pem_check_suffix(nm, "PRIVATE KEY"); + if (slen > 0) + { + /* NB: ENGINE implementations wont contain + * a deprecated old private key decode function + * so don't look for them. + */ + ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen); + if (ameth && ameth->old_priv_decode) + return 1; + } + return 0; + } + + if(!strcmp(name,PEM_STRING_PARAMETERS)) + { + int slen; + const EVP_PKEY_ASN1_METHOD *ameth; + slen = pem_check_suffix(nm, "PARAMETERS"); + if (slen > 0) + { + ENGINE *e; + ameth = EVP_PKEY_asn1_find_str(&e, nm, slen); + if (ameth) + { + int r; + if (ameth->param_decode) + r = 1; + else + r = 0; + return r; + } + } + return 0; + } + /* If reading DH parameters handle X9.42 DH format too */ + if(!strcmp(nm,PEM_STRING_DHXPARAMS) && + !strcmp(name,PEM_STRING_DHPARAMS)) return 1; + + /* Permit older strings */ + + if(!strcmp(nm,PEM_STRING_X509_OLD) && + !strcmp(name,PEM_STRING_X509)) return 1; + + if(!strcmp(nm,PEM_STRING_X509_REQ_OLD) && + !strcmp(name,PEM_STRING_X509_REQ)) return 1; + + /* Allow normal certs to be read as trusted certs */ + if(!strcmp(nm,PEM_STRING_X509) && + !strcmp(name,PEM_STRING_X509_TRUSTED)) return 1; + + if(!strcmp(nm,PEM_STRING_X509_OLD) && + !strcmp(name,PEM_STRING_X509_TRUSTED)) return 1; + + /* Some CAs use PKCS#7 with CERTIFICATE headers */ + if(!strcmp(nm, PEM_STRING_X509) && + !strcmp(name, PEM_STRING_PKCS7)) return 1; + + if(!strcmp(nm, PEM_STRING_PKCS7_SIGNED) && + !strcmp(name, PEM_STRING_PKCS7)) return 1; + +#ifndef OPENSSL_NO_CMS + if(!strcmp(nm, PEM_STRING_X509) && + !strcmp(name, PEM_STRING_CMS)) return 1; + /* Allow CMS to be read from PKCS#7 headers */ + if(!strcmp(nm, PEM_STRING_PKCS7) && + !strcmp(name, PEM_STRING_CMS)) return 1; +#endif + + return 0; +} + +int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, const char *name, BIO *bp, + pem_password_cb *cb, void *u) + { + EVP_CIPHER_INFO cipher; + char *nm=NULL,*header=NULL; + unsigned char *data=NULL; + long len; + int ret = 0; + + for (;;) + { + if (!PEM_read_bio(bp,&nm,&header,&data,&len)) { + if(ERR_GET_REASON(ERR_peek_error()) == + PEM_R_NO_START_LINE) + ERR_add_error_data(2, "Expecting: ", name); + return 0; + } + if(check_pem(nm, name)) break; + OPENSSL_free(nm); + OPENSSL_free(header); + OPENSSL_free(data); + } + if (!PEM_get_EVP_CIPHER_INFO(header,&cipher)) goto err; + if (!PEM_do_header(&cipher,data,&len,cb,u)) goto err; + + *pdata = data; + *plen = len; + + if (pnm) + *pnm = nm; + + ret = 1; + +err: + if (!ret || !pnm) OPENSSL_free(nm); + OPENSSL_free(header); + if (!ret) OPENSSL_free(data); + return ret; + } + +#ifndef OPENSSL_NO_FP_API +int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp, + void *x, const EVP_CIPHER *enc, unsigned char *kstr, + int klen, pem_password_cb *callback, void *u) + { + BIO *b; + int ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=PEM_ASN1_write_bio(i2d,name,b,x,enc,kstr,klen,callback,u); + BIO_free(b); + return(ret); + } +#endif + +int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, + void *x, const EVP_CIPHER *enc, unsigned char *kstr, + int klen, pem_password_cb *callback, void *u) + { + EVP_CIPHER_CTX ctx; + int dsize=0,i,j,ret=0; + unsigned char *p,*data=NULL; + const char *objstr=NULL; + char buf[PEM_BUFSIZE]; + unsigned char key[EVP_MAX_KEY_LENGTH]; + unsigned char iv[EVP_MAX_IV_LENGTH]; + + if (enc != NULL) + { + objstr=OBJ_nid2sn(EVP_CIPHER_nid(enc)); + if (objstr == NULL) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_CIPHER); + goto err; + } + } + + if ((dsize=i2d(x,NULL)) < 0) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + dsize=0; + goto err; + } + /* dzise + 8 bytes are needed */ + /* actually it needs the cipher block size extra... */ + data=(unsigned char *)OPENSSL_malloc((unsigned int)dsize+20); + if (data == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + p=data; + i=i2d(x,&p); + + if (enc != NULL) + { + const unsigned iv_len = EVP_CIPHER_iv_length(enc); + + if (kstr == NULL) + { + klen = 0; + if (!callback) + callback = PEM_def_callback; + klen=(*callback)(buf,PEM_BUFSIZE,1,u); + if (klen <= 0) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_READ_KEY); + goto err; + } + kstr=(unsigned char *)buf; + } + assert(iv_len <= (int)sizeof(iv)); + if (!RAND_bytes(iv, iv_len)) /* Generate a salt */ + goto err; + /* The 'iv' is used as the iv and as a salt. It is + * NOT taken from the BytesToKey function */ + if (!EVP_BytesToKey(enc,EVP_md5(),iv,kstr,klen,1,key,NULL)) + goto err; + + if (kstr == (unsigned char *)buf) OPENSSL_cleanse(buf,PEM_BUFSIZE); + + assert(strlen(objstr)+23+2*iv_len+13 <= sizeof buf); + + buf[0]='\0'; + PEM_proc_type(buf,PEM_TYPE_ENCRYPTED); + PEM_dek_info(buf,objstr,iv_len,(char *)iv); + /* k=strlen(buf); */ + + EVP_CIPHER_CTX_init(&ctx); + ret = 1; + if (!EVP_EncryptInit_ex(&ctx,enc,NULL,key,iv) + || !EVP_EncryptUpdate(&ctx,data,&j,data,i) + || !EVP_EncryptFinal_ex(&ctx,&(data[j]),&i)) + ret = 0; + else + i += j; + EVP_CIPHER_CTX_cleanup(&ctx); + if (ret == 0) + goto err; + } + else + { + ret=1; + buf[0]='\0'; + } + i=PEM_write_bio(bp,name,buf,data,i); + if (i <= 0) ret=0; +err: + OPENSSL_cleanse(key,sizeof(key)); + OPENSSL_cleanse(iv,sizeof(iv)); + OPENSSL_cleanse((char *)&ctx,sizeof(ctx)); + OPENSSL_cleanse(buf,PEM_BUFSIZE); + if (data != NULL) + { + OPENSSL_cleanse(data,(unsigned int)dsize); + OPENSSL_free(data); + } + return(ret); + } + +int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen, + pem_password_cb *callback,void *u) + { + int i=0,j,o,klen; + long len; + EVP_CIPHER_CTX ctx; + unsigned char key[EVP_MAX_KEY_LENGTH]; + char buf[PEM_BUFSIZE]; + + len= *plen; + + if (cipher->cipher == NULL) return(1); + + klen = 0; + if (!callback) callback = PEM_def_callback; + klen=callback(buf,PEM_BUFSIZE,0,u); + if (klen <= 0) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_PASSWORD_READ); + return(0); + } + + if (!EVP_BytesToKey(cipher->cipher,EVP_md5(),&(cipher->iv[0]), + (unsigned char *)buf,klen,1,key,NULL)) + return 0; + + j=(int)len; + EVP_CIPHER_CTX_init(&ctx); + o = EVP_DecryptInit_ex(&ctx,cipher->cipher,NULL, key,&(cipher->iv[0])); + if (o) + o = EVP_DecryptUpdate(&ctx,data,&i,data,j); + if (o) + o = EVP_DecryptFinal_ex(&ctx,&(data[i]),&j); + EVP_CIPHER_CTX_cleanup(&ctx); + OPENSSL_cleanse((char *)buf,sizeof(buf)); + OPENSSL_cleanse((char *)key,sizeof(key)); + if (!o) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_DECRYPT); + return(0); + } + j+=i; + *plen=j; + return(1); + } + +static const EVP_CIPHER* cipher_by_name(const char *name) { + /* This is similar to the (deprecated) function |EVP_get_cipherbyname|. */ + if (0 == strcmp(name, SN_rc4)) { + return EVP_rc4(); + } else if (0 == strcmp(name, SN_des_cbc)) { + return EVP_des_cbc(); + } else if (0 == strcmp(name, SN_des_ede3_cbc)) { + return EVP_des_ede3_cbc(); + } else if (0 == strcmp(name, SN_aes_128_cbc)) { + return EVP_aes_128_cbc(); + } else if (0 == strcmp(name, SN_aes_192_cbc)) { + return EVP_aes_192_cbc(); + } else if (0 == strcmp(name, SN_aes_256_cbc)) { + return EVP_aes_256_cbc(); + } else { + return NULL; + } +} + +int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher) + { + const EVP_CIPHER *enc=NULL; + char *p,c; + char **header_pp = &header; + + cipher->cipher=NULL; + if ((header == NULL) || (*header == '\0') || (*header == '\n')) + return(1); + if (strncmp(header,"Proc-Type: ",11) != 0) + { OPENSSL_PUT_ERROR(PEM, PEM_R_NOT_PROC_TYPE); return(0); } + header+=11; + if (*header != '4') return(0); header++; + if (*header != ',') return(0); header++; + if (strncmp(header,"ENCRYPTED",9) != 0) + { OPENSSL_PUT_ERROR(PEM, PEM_R_NOT_ENCRYPTED); return(0); } + for (; (*header != '\n') && (*header != '\0'); header++) + ; + if (*header == '\0') + { OPENSSL_PUT_ERROR(PEM, PEM_R_SHORT_HEADER); return(0); } + header++; + if (strncmp(header,"DEK-Info: ",10) != 0) + { OPENSSL_PUT_ERROR(PEM, PEM_R_NOT_DEK_INFO); return(0); } + header+=10; + + p=header; + for (;;) + { + c= *header; + if (!( ((c >= 'A') && (c <= 'Z')) || (c == '-') || + ((c >= '0') && (c <= '9')))) + break; + header++; + } + *header='\0'; + cipher->cipher=enc=cipher_by_name(p); + *header=c; + header++; + + if (enc == NULL) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_UNSUPPORTED_ENCRYPTION); + return(0); + } + if (!load_iv(header_pp,&(cipher->iv[0]),EVP_CIPHER_iv_length(enc))) + return(0); + + return(1); + } + +static int load_iv(char **fromp, unsigned char *to, int num) + { + int v,i; + char *from; + + from= *fromp; + for (i=0; i= '0') && (*from <= '9')) + v= *from-'0'; + else if ((*from >= 'A') && (*from <= 'F')) + v= *from-'A'+10; + else if ((*from >= 'a') && (*from <= 'f')) + v= *from-'a'+10; + else + { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_IV_CHARS); + return(0); + } + from++; + to[i/2]|=v<<(long)((!(i&1))*4); + } + + *fromp=from; + return(1); + } + +#ifndef OPENSSL_NO_FP_API +int PEM_write(FILE *fp, const char *name, const char *header, + const unsigned char *data, long len) + { + BIO *b; + int ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=PEM_write_bio(b, name, header, data,len); + BIO_free(b); + return(ret); + } +#endif + +int PEM_write_bio(BIO *bp, const char *name, const char *header, + const unsigned char *data, long len) + { + int nlen,n,i,j,outl; + unsigned char *buf = NULL; + EVP_ENCODE_CTX ctx; + int reason=ERR_R_BUF_LIB; + + EVP_EncodeInit(&ctx); + nlen=strlen(name); + + if ( (BIO_write(bp,"-----BEGIN ",11) != 11) || + (BIO_write(bp,name,nlen) != nlen) || + (BIO_write(bp,"-----\n",6) != 6)) + goto err; + + i=strlen(header); + if (i > 0) + { + if ( (BIO_write(bp,header,i) != i) || + (BIO_write(bp,"\n",1) != 1)) + goto err; + } + + buf = OPENSSL_malloc(PEM_BUFSIZE*8); + if (buf == NULL) + { + reason=ERR_R_MALLOC_FAILURE; + goto err; + } + + i=j=0; + while (len > 0) + { + n=(int)((len>(PEM_BUFSIZE*5))?(PEM_BUFSIZE*5):len); + EVP_EncodeUpdate(&ctx,buf,&outl,&(data[j]),n); + if ((outl) && (BIO_write(bp,(char *)buf,outl) != outl)) + goto err; + i+=outl; + len-=n; + j+=n; + } + EVP_EncodeFinal(&ctx,buf,&outl); + if ((outl > 0) && (BIO_write(bp,(char *)buf,outl) != outl)) goto err; + OPENSSL_cleanse(buf, PEM_BUFSIZE*8); + OPENSSL_free(buf); + buf = NULL; + if ( (BIO_write(bp,"-----END ",9) != 9) || + (BIO_write(bp,name,nlen) != nlen) || + (BIO_write(bp,"-----\n",6) != 6)) + goto err; + return(i+outl); +err: + if (buf) { + OPENSSL_cleanse(buf, PEM_BUFSIZE*8); + OPENSSL_free(buf); + } + OPENSSL_PUT_ERROR(PEM, reason); + return(0); + } + +#ifndef OPENSSL_NO_FP_API +int PEM_read(FILE *fp, char **name, char **header, unsigned char **data, + long *len) + { + BIO *b; + int ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=PEM_read_bio(b, name, header, data,len); + BIO_free(b); + return(ret); + } +#endif + +int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data, + long *len) + { + EVP_ENCODE_CTX ctx; + int end=0,i,k,bl=0,hl=0,nohead=0; + char buf[256]; + BUF_MEM *nameB; + BUF_MEM *headerB; + BUF_MEM *dataB,*tmpB; + + nameB=BUF_MEM_new(); + headerB=BUF_MEM_new(); + dataB=BUF_MEM_new(); + if ((nameB == NULL) || (headerB == NULL) || (dataB == NULL)) + { + BUF_MEM_free(nameB); + BUF_MEM_free(headerB); + BUF_MEM_free(dataB); + OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); + return(0); + } + + buf[254]='\0'; + for (;;) + { + i=BIO_gets(bp,buf,254); + + if (i <= 0) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_NO_START_LINE); + goto err; + } + + while ((i >= 0) && (buf[i] <= ' ')) i--; + buf[++i]='\n'; buf[++i]='\0'; + + if (strncmp(buf,"-----BEGIN ",11) == 0) + { + i=strlen(&(buf[11])); + + if (strncmp(&(buf[11+i-6]),"-----\n",6) != 0) + continue; + if (!BUF_MEM_grow(nameB,i+9)) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + memcpy(nameB->data,&(buf[11]),i-6); + nameB->data[i-6]='\0'; + break; + } + } + hl=0; + if (!BUF_MEM_grow(headerB,256)) + { OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); goto err; } + headerB->data[0]='\0'; + for (;;) + { + i=BIO_gets(bp,buf,254); + if (i <= 0) break; + + while ((i >= 0) && (buf[i] <= ' ')) i--; + buf[++i]='\n'; buf[++i]='\0'; + + if (buf[0] == '\n') break; + if (!BUF_MEM_grow(headerB,hl+i+9)) + { OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); goto err; } + if (strncmp(buf,"-----END ",9) == 0) + { + nohead=1; + break; + } + memcpy(&(headerB->data[hl]),buf,i); + headerB->data[hl+i]='\0'; + hl+=i; + } + + bl=0; + if (!BUF_MEM_grow(dataB,1024)) + { OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); goto err; } + dataB->data[0]='\0'; + if (!nohead) + { + for (;;) + { + i=BIO_gets(bp,buf,254); + if (i <= 0) break; + + while ((i >= 0) && (buf[i] <= ' ')) i--; + buf[++i]='\n'; buf[++i]='\0'; + + if (i != 65) end=1; + if (strncmp(buf,"-----END ",9) == 0) + break; + if (i > 65) break; + if (!BUF_MEM_grow_clean(dataB,i+bl+9)) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_MALLOC_FAILURE); + goto err; + } + memcpy(&(dataB->data[bl]),buf,i); + dataB->data[bl+i]='\0'; + bl+=i; + if (end) + { + buf[0]='\0'; + i=BIO_gets(bp,buf,254); + if (i <= 0) break; + + while ((i >= 0) && (buf[i] <= ' ')) i--; + buf[++i]='\n'; buf[++i]='\0'; + + break; + } + } + } + else + { + tmpB=headerB; + headerB=dataB; + dataB=tmpB; + bl=hl; + } + i=strlen(nameB->data); + if ( (strncmp(buf,"-----END ",9) != 0) || + (strncmp(nameB->data,&(buf[9]),i) != 0) || + (strncmp(&(buf[9+i]),"-----\n",6) != 0)) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_END_LINE); + goto err; + } + + EVP_DecodeInit(&ctx); + i=EVP_DecodeUpdate(&ctx, + (unsigned char *)dataB->data,&bl, + (unsigned char *)dataB->data,bl); + if (i < 0) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_BASE64_DECODE); + goto err; + } + i=EVP_DecodeFinal(&ctx,(unsigned char *)&(dataB->data[bl]),&k); + if (i < 0) + { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_BASE64_DECODE); + goto err; + } + bl+=k; + + if (bl == 0) goto err; + *name=nameB->data; + *header=headerB->data; + *data=(unsigned char *)dataB->data; + *len=bl; + OPENSSL_free(nameB); + OPENSSL_free(headerB); + OPENSSL_free(dataB); + return(1); +err: + BUF_MEM_free(nameB); + BUF_MEM_free(headerB); + BUF_MEM_free(dataB); + return(0); + } + +/* Check pem string and return prefix length. + * If for example the pem_str == "RSA PRIVATE KEY" and suffix = "PRIVATE KEY" + * the return value is 3 for the string "RSA". + */ + +int pem_check_suffix(const char *pem_str, const char *suffix) + { + int pem_len = strlen(pem_str); + int suffix_len = strlen(suffix); + const char *p; + if (suffix_len + 1 >= pem_len) + return 0; + p = pem_str + pem_len - suffix_len; + if (strcmp(p, suffix)) + return 0; + p--; + if (*p != ' ') + return 0; + return p - pem_str; + } + +int PEM_def_callback(char *buf, int size, int rwflag, void *userdata) + { + if (!buf || !userdata) + { + return 0; + } + size_t len = strlen((char *) userdata); + if (len >= (size_t) size) + { + return 0; + } + strcpy(buf, (char *) userdata); + return len; + } diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_oth.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_oth.c new file mode 100644 index 00000000..3e8f6bda --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_oth.c @@ -0,0 +1,89 @@ +/* crypto/pem/pem_oth.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + + +/* Handle 'other' PEMs: not private keys */ + +void *PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp, void **x, + pem_password_cb *cb, void *u) + { + const unsigned char *p=NULL; + unsigned char *data=NULL; + long len; + char *ret=NULL; + + if (!PEM_bytes_read_bio(&data, &len, NULL, name, bp, cb, u)) + return NULL; + p = data; + ret=d2i(x,&p,len); + if (ret == NULL) + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + OPENSSL_free(data); + return ret; + } diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_pk8.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_pk8.c new file mode 100644 index 00000000..08244772 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_pk8.c @@ -0,0 +1,244 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +static int do_pk8pkey(BIO *bp, EVP_PKEY *x, int isder, + int nid, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u); +static int do_pk8pkey_fp(FILE *bp, EVP_PKEY *x, int isder, + int nid, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u); + +/* These functions write a private key in PKCS#8 format: it is a "drop in" + * replacement for PEM_write_bio_PrivateKey() and friends. As usual if 'enc' + * is NULL then it uses the unencrypted private key form. The 'nid' versions + * uses PKCS#5 v1.5 PBE algorithms whereas the others use PKCS#5 v2.0. + */ + +int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey(bp, x, 0, nid, NULL, kstr, klen, cb, u); +} + +int PEM_write_bio_PKCS8PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey(bp, x, 0, -1, enc, kstr, klen, cb, u); +} + +int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey(bp, x, 1, -1, enc, kstr, klen, cb, u); +} + +int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey(bp, x, 1, nid, NULL, kstr, klen, cb, u); +} + +static int do_pk8pkey(BIO *bp, EVP_PKEY *x, int isder, int nid, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + X509_SIG *p8; + PKCS8_PRIV_KEY_INFO *p8inf; + char buf[PEM_BUFSIZE]; + int ret; + if(!(p8inf = EVP_PKEY2PKCS8(x))) { + OPENSSL_PUT_ERROR(PEM, PEM_R_ERROR_CONVERTING_PRIVATE_KEY); + return 0; + } + if(enc || (nid != -1)) { + if(!kstr) { + klen = 0; + if (!cb) cb = PEM_def_callback; + klen = cb(buf, PEM_BUFSIZE, 1, u); + if(klen <= 0) { + OPENSSL_PUT_ERROR(PEM, PEM_R_READ_KEY); + PKCS8_PRIV_KEY_INFO_free(p8inf); + return 0; + } + + kstr = buf; + } + p8 = PKCS8_encrypt(nid, enc, kstr, klen, NULL, 0, 0, p8inf); + if(kstr == buf) OPENSSL_cleanse(buf, klen); + PKCS8_PRIV_KEY_INFO_free(p8inf); + if(isder) ret = i2d_PKCS8_bio(bp, p8); + else ret = PEM_write_bio_PKCS8(bp, p8); + X509_SIG_free(p8); + return ret; + } else { + if(isder) ret = i2d_PKCS8_PRIV_KEY_INFO_bio(bp, p8inf); + else ret = PEM_write_bio_PKCS8_PRIV_KEY_INFO(bp, p8inf); + PKCS8_PRIV_KEY_INFO_free(p8inf); + return ret; + } +} + +EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u) +{ + PKCS8_PRIV_KEY_INFO *p8inf = NULL; + X509_SIG *p8 = NULL; + int klen; + EVP_PKEY *ret; + char psbuf[PEM_BUFSIZE]; + p8 = d2i_PKCS8_bio(bp, NULL); + if(!p8) return NULL; + + klen = 0; + if (!cb) cb = PEM_def_callback; + klen=cb(psbuf,PEM_BUFSIZE,0,u); + if (klen <= 0) { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_PASSWORD_READ); + X509_SIG_free(p8); + return NULL; + } + p8inf = PKCS8_decrypt(p8, psbuf, klen); + X509_SIG_free(p8); + if(!p8inf) return NULL; + ret = EVP_PKCS82PKEY(p8inf); + PKCS8_PRIV_KEY_INFO_free(p8inf); + if(!ret) return NULL; + if(x) { + if(*x) EVP_PKEY_free(*x); + *x = ret; + } + return ret; +} + +#ifndef OPENSSL_NO_FP_API + +int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey_fp(fp, x, 1, -1, enc, kstr, klen, cb, u); +} + +int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey_fp(fp, x, 1, nid, NULL, kstr, klen, cb, u); +} + +int PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + return do_pk8pkey_fp(fp, x, 0, nid, NULL, kstr, klen, cb, u); +} + +int PEM_write_PKCS8PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, + char *kstr, int klen, pem_password_cb *cb, void *u) +{ + return do_pk8pkey_fp(fp, x, 0, -1, enc, kstr, klen, cb, u); +} + +static int do_pk8pkey_fp(FILE *fp, EVP_PKEY *x, int isder, int nid, const EVP_CIPHER *enc, + char *kstr, int klen, + pem_password_cb *cb, void *u) +{ + BIO *bp; + int ret; + if(!(bp = BIO_new_fp(fp, BIO_NOCLOSE))) { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + ret = do_pk8pkey(bp, x, isder, nid, enc, kstr, klen, cb, u); + BIO_free(bp); + return ret; +} + +EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u) +{ + BIO *bp; + EVP_PKEY *ret; + if(!(bp = BIO_new_fp(fp, BIO_NOCLOSE))) { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return NULL; + } + ret = d2i_PKCS8PrivateKey_bio(bp, x, cb, u); + BIO_free(bp); + return ret; +} + +#endif + +IMPLEMENT_PEM_rw(PKCS8, X509_SIG, PEM_STRING_PKCS8, X509_SIG) +IMPLEMENT_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO, PEM_STRING_PKCS8INF, + PKCS8_PRIV_KEY_INFO) diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_pkey.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_pkey.c new file mode 100644 index 00000000..c4627275 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_pkey.c @@ -0,0 +1,312 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../evp/internal.h" + + +int pem_check_suffix(const char *pem_str, const char *suffix); + +EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u) + { + char *nm=NULL; + const unsigned char *p=NULL; + unsigned char *data=NULL; + long len; + int slen; + EVP_PKEY *ret=NULL; + + if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_EVP_PKEY, bp, cb, u)) + return NULL; + p = data; + + if (strcmp(nm,PEM_STRING_PKCS8INF) == 0) { + PKCS8_PRIV_KEY_INFO *p8inf; + p8inf=d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, len); + if(!p8inf) goto p8err; + ret = EVP_PKCS82PKEY(p8inf); + if(x) { + if(*x) EVP_PKEY_free((EVP_PKEY *)*x); + *x = ret; + } + PKCS8_PRIV_KEY_INFO_free(p8inf); + } else if (strcmp(nm,PEM_STRING_PKCS8) == 0) { + PKCS8_PRIV_KEY_INFO *p8inf; + X509_SIG *p8; + int klen; + char psbuf[PEM_BUFSIZE]; + p8 = d2i_X509_SIG(NULL, &p, len); + if(!p8) goto p8err; + + klen = 0; + if (!cb) cb = PEM_def_callback; + klen=cb(psbuf,PEM_BUFSIZE,0,u); + if (klen <= 0) { + OPENSSL_PUT_ERROR(PEM, PEM_R_BAD_PASSWORD_READ); + X509_SIG_free(p8); + goto err; + } + p8inf = PKCS8_decrypt(p8, psbuf, klen); + X509_SIG_free(p8); + if(!p8inf) goto p8err; + ret = EVP_PKCS82PKEY(p8inf); + if(x) { + if(*x) EVP_PKEY_free((EVP_PKEY *)*x); + *x = ret; + } + PKCS8_PRIV_KEY_INFO_free(p8inf); + } else if ((slen = pem_check_suffix(nm, "PRIVATE KEY")) > 0) + { + const EVP_PKEY_ASN1_METHOD *ameth; + ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen); + if (!ameth || !ameth->old_priv_decode) + goto p8err; + ret=d2i_PrivateKey(ameth->pkey_id,x,&p,len); + } +p8err: + if (ret == NULL) + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + +err: + OPENSSL_free(nm); + OPENSSL_cleanse(data, len); + OPENSSL_free(data); + return(ret); + } + +int PEM_write_bio_PrivateKey(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, + unsigned char *kstr, int klen, + pem_password_cb *cb, void *u) + { + char pem_str[80]; + if (!x->ameth || x->ameth->priv_encode) + return PEM_write_bio_PKCS8PrivateKey(bp, x, enc, + (char *)kstr, klen, + cb, u); + + BIO_snprintf(pem_str, 80, "%s PRIVATE KEY", x->ameth->pem_str); + return PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, + pem_str,bp,x,enc,kstr,klen,cb,u); + } + +static int public_key_type_from_str(const char *name, size_t len) { + if (len == 3 && memcmp(name, "RSA", 3) == 0) { + return EVP_PKEY_RSA; + } else if (len == 2 && memcmp(name, "DH", 2) == 0) { + return EVP_PKEY_DH; + } else if (len == 2 && memcmp(name, "EC", 2) == 0) { + return EVP_PKEY_EC; + } + return NID_undef; +} + +static int set_pkey_type_from_str(EVP_PKEY *pkey, const char *name, size_t len) { + int nid = public_key_type_from_str(name, len); + if (nid == NID_undef) { + return 0; + } + return EVP_PKEY_set_type(pkey, nid); +} + +EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x) + { + char *nm=NULL; + const unsigned char *p=NULL; + unsigned char *data=NULL; + long len; + int slen; + EVP_PKEY *ret=NULL; + + if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_PARAMETERS, + bp, 0, NULL)) + return NULL; + p = data; + + if ((slen = pem_check_suffix(nm, "PARAMETERS")) > 0) + { + ret = EVP_PKEY_new(); + if (!ret) + goto err; + if (!set_pkey_type_from_str(ret, nm, slen) + || !ret->ameth->param_decode + || !ret->ameth->param_decode(ret, &p, len)) + { + EVP_PKEY_free(ret); + ret = NULL; + goto err; + } + if(x) + { + if(*x) EVP_PKEY_free((EVP_PKEY *)*x); + *x = ret; + } + } +err: + if (ret == NULL) + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + OPENSSL_free(nm); + OPENSSL_free(data); + return(ret); + } + +int PEM_write_bio_Parameters(BIO *bp, EVP_PKEY *x) + { + char pem_str[80]; + if (!x->ameth || !x->ameth->param_encode) + return 0; + + BIO_snprintf(pem_str, 80, "%s PARAMETERS", x->ameth->pem_str); + return PEM_ASN1_write_bio( + (i2d_of_void *)x->ameth->param_encode, + pem_str,bp,x,NULL,NULL,0,0,NULL); + } + +#ifndef OPENSSL_NO_FP_API +EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u) + { + BIO *b; + EVP_PKEY *ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=PEM_read_bio_PrivateKey(b,x,cb,u); + BIO_free(b); + return(ret); + } + +int PEM_write_PrivateKey(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, + unsigned char *kstr, int klen, + pem_password_cb *cb, void *u) + { + BIO *b; + int ret; + + if ((b=BIO_new_fp(fp, BIO_NOCLOSE)) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return 0; + } + ret=PEM_write_bio_PrivateKey(b, x, enc, kstr, klen, cb, u); + BIO_free(b); + return ret; + } + +#endif + + +/* Transparently read in PKCS#3 or X9.42 DH parameters */ + +DH *PEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u) + { + char *nm=NULL; + const unsigned char *p=NULL; + unsigned char *data=NULL; + long len; + DH *ret=NULL; + + if (!PEM_bytes_read_bio(&data, &len, &nm, PEM_STRING_DHPARAMS, + bp, cb, u)) + return NULL; + p = data; + + /* TODO(fork): remove? */ + /*if (!strcmp(nm, PEM_STRING_DHXPARAMS)) + ret = d2i_DHxparams(x, &p, len); + else */ + ret = d2i_DHparams(x, &p, len); + + if (ret == NULL) + OPENSSL_PUT_ERROR(PEM, ERR_R_ASN1_LIB); + OPENSSL_free(nm); + OPENSSL_free(data); + return ret; + } + +#ifndef OPENSSL_NO_FP_API +DH *PEM_read_DHparams(FILE *fp, DH **x, pem_password_cb *cb, void *u) + { + BIO *b; + DH *ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(PEM, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=PEM_read_bio_DHparams(b,x,cb,u); + BIO_free(b); + return(ret); + } +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_x509.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_x509.c new file mode 100644 index 00000000..f4630472 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_x509.c @@ -0,0 +1,65 @@ +/* pem_x509.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2001. + */ +/* ==================================================================== + * Copyright (c) 2001 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include + + +IMPLEMENT_PEM_rw(X509, X509, PEM_STRING_X509, X509) diff --git a/TMessagesProj/jni/boringssl/crypto/pem/pem_xaux.c b/TMessagesProj/jni/boringssl/crypto/pem/pem_xaux.c new file mode 100644 index 00000000..8dabd41e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pem/pem_xaux.c @@ -0,0 +1,66 @@ +/* pem_xaux.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2001. + */ +/* ==================================================================== + * Copyright (c) 2001 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include + + +IMPLEMENT_PEM_rw(X509_AUX, X509, PEM_STRING_X509_TRUSTED, X509_AUX) +IMPLEMENT_PEM_rw(X509_CERT_PAIR, X509_CERT_PAIR, PEM_STRING_X509_PAIR, X509_CERT_PAIR) diff --git a/TMessagesProj/jni/boringssl/crypto/perlasm/arm-xlate.pl b/TMessagesProj/jni/boringssl/crypto/perlasm/arm-xlate.pl new file mode 100644 index 00000000..706fa708 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/perlasm/arm-xlate.pl @@ -0,0 +1,170 @@ +#!/usr/bin/env perl + +# ARM assembler distiller by . + +my $flavour = shift; +my $output = shift; +open STDOUT,">$output" || die "can't open $output: $!"; + +$flavour = "linux32" if (!$flavour or $flavour eq "void"); + +my %GLOBALS; +my $dotinlocallabels=($flavour=~/linux/)?1:0; + +################################################################ +# directives which need special treatment on different platforms +################################################################ +my $arch = sub { + if ($flavour =~ /linux/) { ".arch\t".join(',',@_); } + else { ""; } +}; +my $fpu = sub { + if ($flavour =~ /linux/) { ".fpu\t".join(',',@_); } + else { ""; } +}; +my $hidden = sub { + if ($flavour =~ /ios/) { ".private_extern\t".join(',',@_); } + else { ".hidden\t".join(',',@_); } +}; +my $comm = sub { + my @args = split(/,\s*/,shift); + my $name = @args[0]; + my $global = \$GLOBALS{$name}; + my $ret; + + if ($flavour =~ /ios32/) { + $ret = ".comm\t_$name,@args[1]\n"; + $ret .= ".non_lazy_symbol_pointer\n"; + $ret .= "$name:\n"; + $ret .= ".indirect_symbol\t_$name\n"; + $ret .= ".long\t0"; + $name = "_$name"; + } else { $ret = ".comm\t".join(',',@args); } + + $$global = $name; + $ret; +}; +my $globl = sub { + my $name = shift; + my $global = \$GLOBALS{$name}; + my $ret; + + SWITCH: for ($flavour) { + /ios/ && do { $name = "_$name"; + last; + }; + } + + $ret = ".globl $name" if (!$ret); + $$global = $name; + $ret; +}; +my $global = $globl; +my $extern = sub { + &$globl(@_); + return; # return nothing +}; +my $type = sub { + if ($flavour =~ /linux/) { ".type\t".join(',',@_); } + else { ""; } +}; +my $size = sub { + if ($flavour =~ /linux/) { ".size\t".join(',',@_); } + else { ""; } +}; +my $inst = sub { + if ($flavour =~ /linux/) { ".inst\t".join(',',@_); } + else { ".long\t".join(',',@_); } +}; +my $asciz = sub { + my $line = join(",",@_); + if ($line =~ /^"(.*)"$/) + { ".byte " . join(",",unpack("C*",$1),0) . "\n.align 2"; } + else + { ""; } +}; + +sub range { + my ($r,$sfx,$start,$end) = @_; + + join(",",map("$r$_$sfx",($start..$end))); +} + +sub expand_line { + my $line = shift; + my @ret = (); + + pos($line)=0; + + while ($line =~ m/\G[^@\/\{\"]*/g) { + if ($line =~ m/\G(@|\/\/|$)/gc) { + last; + } + elsif ($line =~ m/\G\{/gc) { + my $saved_pos = pos($line); + $line =~ s/\G([rdqv])([0-9]+)([^\-]*)\-\1([0-9]+)\3/range($1,$3,$2,$4)/e; + pos($line) = $saved_pos; + $line =~ m/\G[^\}]*\}/g; + } + elsif ($line =~ m/\G\"/gc) { + $line =~ m/\G[^\"]*\"/g; + } + } + + $line =~ s/\b(\w+)/$GLOBALS{$1} or $1/ge; + + return $line; +} + +print "#if defined(__arm__)\n" if ($flavour eq "linux32"); +print "#if defined(__aarch64__)\n" if ($flavour eq "linux64"); + +while($line=<>) { + + if ($line =~ m/^\s*(#|@|\/\/)/) { print $line; next; } + + $line =~ s|/\*.*\*/||; # get rid of C-style comments... + $line =~ s|^\s+||; # ... and skip white spaces in beginning... + $line =~ s|\s+$||; # ... and at the end + + { + $line =~ s|[\b\.]L(\w{2,})|L$1|g; # common denominator for Locallabel + $line =~ s|\bL(\w{2,})|\.L$1|g if ($dotinlocallabels); + } + + { + $line =~ s|(^[\.\w]+)\:\s*||; + my $label = $1; + if ($label) { + printf "%s:",($GLOBALS{$label} or $label); + } + } + + if ($line !~ m/^[#@]/) { + $line =~ s|^\s*(\.?)(\S+)\s*||; + my $c = $1; $c = "\t" if ($c eq ""); + my $mnemonic = $2; + my $opcode; + if ($mnemonic =~ m/([^\.]+)\.([^\.]+)/) { + $opcode = eval("\$$1_$2"); + } else { + $opcode = eval("\$$mnemonic"); + } + + my $arg=expand_line($line); + + if (ref($opcode) eq 'CODE') { + $line = &$opcode($arg); + } elsif ($mnemonic) { + $line = $c.$mnemonic; + $line.= "\t$arg" if ($arg ne ""); + } + } + + print $line if ($line); + print "\n"; +} + +print "#endif" if ($flavour eq "linux32" || $flavour eq "linux64"); + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/perlasm/cbc.pl b/TMessagesProj/jni/boringssl/crypto/perlasm/cbc.pl new file mode 100644 index 00000000..24561e75 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/perlasm/cbc.pl @@ -0,0 +1,349 @@ +#!/usr/local/bin/perl + +# void des_ncbc_encrypt(input, output, length, schedule, ivec, enc) +# des_cblock (*input); +# des_cblock (*output); +# long length; +# des_key_schedule schedule; +# des_cblock (*ivec); +# int enc; +# +# calls +# des_encrypt((DES_LONG *)tin,schedule,DES_ENCRYPT); +# + +#&cbc("des_ncbc_encrypt","des_encrypt",0); +#&cbc("BF_cbc_encrypt","BF_encrypt","BF_encrypt", +# 1,4,5,3,5,-1); +#&cbc("des_ncbc_encrypt","des_encrypt","des_encrypt", +# 0,4,5,3,5,-1); +#&cbc("des_ede3_cbc_encrypt","des_encrypt3","des_decrypt3", +# 0,6,7,3,4,5); +# +# When doing a cipher that needs bigendian order, +# for encrypt, the iv is kept in bigendian form, +# while for decrypt, it is kept in little endian. +sub cbc + { + local($name,$enc_func,$dec_func,$swap,$iv_off,$enc_off,$p1,$p2,$p3)=@_; + # name is the function name + # enc_func and dec_func and the functions to call for encrypt/decrypt + # swap is true if byte order needs to be reversed + # iv_off is parameter number for the iv + # enc_off is parameter number for the encrypt/decrypt flag + # p1,p2,p3 are the offsets for parameters to be passed to the + # underlying calls. + + &function_begin_B($name,""); + &comment(""); + + $in="esi"; + $out="edi"; + $count="ebp"; + + &push("ebp"); + &push("ebx"); + &push("esi"); + &push("edi"); + + $data_off=4; + $data_off+=4 if ($p1 > 0); + $data_off+=4 if ($p2 > 0); + $data_off+=4 if ($p3 > 0); + + &mov($count, &wparam(2)); # length + + &comment("getting iv ptr from parameter $iv_off"); + &mov("ebx", &wparam($iv_off)); # Get iv ptr + + &mov($in, &DWP(0,"ebx","",0));# iv[0] + &mov($out, &DWP(4,"ebx","",0));# iv[1] + + &push($out); + &push($in); + &push($out); # used in decrypt for iv[1] + &push($in); # used in decrypt for iv[0] + + &mov("ebx", "esp"); # This is the address of tin[2] + + &mov($in, &wparam(0)); # in + &mov($out, &wparam(1)); # out + + # We have loaded them all, how lets push things + &comment("getting encrypt flag from parameter $enc_off"); + &mov("ecx", &wparam($enc_off)); # Get enc flag + if ($p3 > 0) + { + &comment("get and push parameter $p3"); + if ($enc_off != $p3) + { &mov("eax", &wparam($p3)); &push("eax"); } + else { &push("ecx"); } + } + if ($p2 > 0) + { + &comment("get and push parameter $p2"); + if ($enc_off != $p2) + { &mov("eax", &wparam($p2)); &push("eax"); } + else { &push("ecx"); } + } + if ($p1 > 0) + { + &comment("get and push parameter $p1"); + if ($enc_off != $p1) + { &mov("eax", &wparam($p1)); &push("eax"); } + else { &push("ecx"); } + } + &push("ebx"); # push data/iv + + &cmp("ecx",0); + &jz(&label("decrypt")); + + &and($count,0xfffffff8); + &mov("eax", &DWP($data_off,"esp","",0)); # load iv[0] + &mov("ebx", &DWP($data_off+4,"esp","",0)); # load iv[1] + + &jz(&label("encrypt_finish")); + + ############################################################# + + &set_label("encrypt_loop"); + # encrypt start + # "eax" and "ebx" hold iv (or the last cipher text) + + &mov("ecx", &DWP(0,$in,"",0)); # load first 4 bytes + &mov("edx", &DWP(4,$in,"",0)); # second 4 bytes + + &xor("eax", "ecx"); + &xor("ebx", "edx"); + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call + &mov(&DWP($data_off+4,"esp","",0), "ebx"); # + + &call($enc_func); + + &mov("eax", &DWP($data_off,"esp","",0)); + &mov("ebx", &DWP($data_off+4,"esp","",0)); + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov(&DWP(0,$out,"",0),"eax"); + &mov(&DWP(4,$out,"",0),"ebx"); + + # eax and ebx are the next iv. + + &add($in, 8); + &add($out, 8); + + &sub($count, 8); + &jnz(&label("encrypt_loop")); + +###################################################################3 + &set_label("encrypt_finish"); + &mov($count, &wparam(2)); # length + &and($count, 7); + &jz(&label("finish")); + &call(&label("PIC_point")); +&set_label("PIC_point"); + &blindpop("edx"); + &lea("ecx",&DWP(&label("cbc_enc_jmp_table")."-".&label("PIC_point"),"edx")); + &mov($count,&DWP(0,"ecx",$count,4)); + &add($count,"edx"); + &xor("ecx","ecx"); + &xor("edx","edx"); + #&mov($count,&DWP(&label("cbc_enc_jmp_table"),"",$count,4)); + &jmp_ptr($count); + +&set_label("ej7"); + &movb(&HB("edx"), &BP(6,$in,"",0)); + &shl("edx",8); +&set_label("ej6"); + &movb(&HB("edx"), &BP(5,$in,"",0)); +&set_label("ej5"); + &movb(&LB("edx"), &BP(4,$in,"",0)); +&set_label("ej4"); + &mov("ecx", &DWP(0,$in,"",0)); + &jmp(&label("ejend")); +&set_label("ej3"); + &movb(&HB("ecx"), &BP(2,$in,"",0)); + &shl("ecx",8); +&set_label("ej2"); + &movb(&HB("ecx"), &BP(1,$in,"",0)); +&set_label("ej1"); + &movb(&LB("ecx"), &BP(0,$in,"",0)); +&set_label("ejend"); + + &xor("eax", "ecx"); + &xor("ebx", "edx"); + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov(&DWP($data_off,"esp","",0), "eax"); # put in array for call + &mov(&DWP($data_off+4,"esp","",0), "ebx"); # + + &call($enc_func); + + &mov("eax", &DWP($data_off,"esp","",0)); + &mov("ebx", &DWP($data_off+4,"esp","",0)); + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov(&DWP(0,$out,"",0),"eax"); + &mov(&DWP(4,$out,"",0),"ebx"); + + &jmp(&label("finish")); + + ############################################################# + ############################################################# + &set_label("decrypt",1); + # decrypt start + &and($count,0xfffffff8); + # The next 2 instructions are only for if the jz is taken + &mov("eax", &DWP($data_off+8,"esp","",0)); # get iv[0] + &mov("ebx", &DWP($data_off+12,"esp","",0)); # get iv[1] + &jz(&label("decrypt_finish")); + + &set_label("decrypt_loop"); + &mov("eax", &DWP(0,$in,"",0)); # load first 4 bytes + &mov("ebx", &DWP(4,$in,"",0)); # second 4 bytes + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov(&DWP($data_off,"esp","",0), "eax"); # put back + &mov(&DWP($data_off+4,"esp","",0), "ebx"); # + + &call($dec_func); + + &mov("eax", &DWP($data_off,"esp","",0)); # get return + &mov("ebx", &DWP($data_off+4,"esp","",0)); # + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov("ecx", &DWP($data_off+8,"esp","",0)); # get iv[0] + &mov("edx", &DWP($data_off+12,"esp","",0)); # get iv[1] + + &xor("ecx", "eax"); + &xor("edx", "ebx"); + + &mov("eax", &DWP(0,$in,"",0)); # get old cipher text, + &mov("ebx", &DWP(4,$in,"",0)); # next iv actually + + &mov(&DWP(0,$out,"",0),"ecx"); + &mov(&DWP(4,$out,"",0),"edx"); + + &mov(&DWP($data_off+8,"esp","",0), "eax"); # save iv + &mov(&DWP($data_off+12,"esp","",0), "ebx"); # + + &add($in, 8); + &add($out, 8); + + &sub($count, 8); + &jnz(&label("decrypt_loop")); +############################ ENDIT #######################3 + &set_label("decrypt_finish"); + &mov($count, &wparam(2)); # length + &and($count, 7); + &jz(&label("finish")); + + &mov("eax", &DWP(0,$in,"",0)); # load first 4 bytes + &mov("ebx", &DWP(4,$in,"",0)); # second 4 bytes + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov(&DWP($data_off,"esp","",0), "eax"); # put back + &mov(&DWP($data_off+4,"esp","",0), "ebx"); # + + &call($dec_func); + + &mov("eax", &DWP($data_off,"esp","",0)); # get return + &mov("ebx", &DWP($data_off+4,"esp","",0)); # + + &bswap("eax") if $swap; + &bswap("ebx") if $swap; + + &mov("ecx", &DWP($data_off+8,"esp","",0)); # get iv[0] + &mov("edx", &DWP($data_off+12,"esp","",0)); # get iv[1] + + &xor("ecx", "eax"); + &xor("edx", "ebx"); + + # this is for when we exit + &mov("eax", &DWP(0,$in,"",0)); # get old cipher text, + &mov("ebx", &DWP(4,$in,"",0)); # next iv actually + +&set_label("dj7"); + &rotr("edx", 16); + &movb(&BP(6,$out,"",0), &LB("edx")); + &shr("edx",16); +&set_label("dj6"); + &movb(&BP(5,$out,"",0), &HB("edx")); +&set_label("dj5"); + &movb(&BP(4,$out,"",0), &LB("edx")); +&set_label("dj4"); + &mov(&DWP(0,$out,"",0), "ecx"); + &jmp(&label("djend")); +&set_label("dj3"); + &rotr("ecx", 16); + &movb(&BP(2,$out,"",0), &LB("ecx")); + &shl("ecx",16); +&set_label("dj2"); + &movb(&BP(1,$in,"",0), &HB("ecx")); +&set_label("dj1"); + &movb(&BP(0,$in,"",0), &LB("ecx")); +&set_label("djend"); + + # final iv is still in eax:ebx + &jmp(&label("finish")); + + +############################ FINISH #######################3 + &set_label("finish",1); + &mov("ecx", &wparam($iv_off)); # Get iv ptr + + ################################################# + $total=16+4; + $total+=4 if ($p1 > 0); + $total+=4 if ($p2 > 0); + $total+=4 if ($p3 > 0); + &add("esp",$total); + + &mov(&DWP(0,"ecx","",0), "eax"); # save iv + &mov(&DWP(4,"ecx","",0), "ebx"); # save iv + + &function_end_A($name); + + &align(64); + &set_label("cbc_enc_jmp_table"); + &data_word("0"); + &data_word(&label("ej1")."-".&label("PIC_point")); + &data_word(&label("ej2")."-".&label("PIC_point")); + &data_word(&label("ej3")."-".&label("PIC_point")); + &data_word(&label("ej4")."-".&label("PIC_point")); + &data_word(&label("ej5")."-".&label("PIC_point")); + &data_word(&label("ej6")."-".&label("PIC_point")); + &data_word(&label("ej7")."-".&label("PIC_point")); + # not used + #&set_label("cbc_dec_jmp_table",1); + #&data_word("0"); + #&data_word(&label("dj1")."-".&label("PIC_point")); + #&data_word(&label("dj2")."-".&label("PIC_point")); + #&data_word(&label("dj3")."-".&label("PIC_point")); + #&data_word(&label("dj4")."-".&label("PIC_point")); + #&data_word(&label("dj5")."-".&label("PIC_point")); + #&data_word(&label("dj6")."-".&label("PIC_point")); + #&data_word(&label("dj7")."-".&label("PIC_point")); + &align(64); + + &function_end_B($name); + + } + +1; diff --git a/TMessagesProj/jni/boringssl/crypto/perlasm/readme b/TMessagesProj/jni/boringssl/crypto/perlasm/readme new file mode 100644 index 00000000..f02bbee7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/perlasm/readme @@ -0,0 +1,124 @@ +The perl scripts in this directory are my 'hack' to generate +multiple different assembler formats via the one origional script. + +The way to use this library is to start with adding the path to this directory +and then include it. + +push(@INC,"perlasm","../../perlasm"); +require "x86asm.pl"; + +The first thing we do is setup the file and type of assember + +&asm_init($ARGV[0],$0); + +The first argument is the 'type'. Currently +'cpp', 'sol', 'a.out', 'elf' or 'win32'. +Argument 2 is the file name. + +The reciprocal function is +&asm_finish() which should be called at the end. + +There are 2 main 'packages'. x86ms.pl, which is the microsoft assembler, +and x86unix.pl which is the unix (gas) version. + +Functions of interest are: +&external_label("des_SPtrans"); declare and external variable +&LB(reg); Low byte for a register +&HB(reg); High byte for a register +&BP(off,base,index,scale) Byte pointer addressing +&DWP(off,base,index,scale) Word pointer addressing +&stack_push(num) Basically a 'sub esp, num*4' with extra +&stack_pop(num) inverse of stack_push +&function_begin(name,extra) Start a function with pushing of + edi, esi, ebx and ebp. extra is extra win32 + external info that may be required. +&function_begin_B(name,extra) Same as norma function_begin but no pushing. +&function_end(name) Call at end of function. +&function_end_A(name) Standard pop and ret, for use inside functions +&function_end_B(name) Call at end but with poping or 'ret'. +&swtmp(num) Address on stack temp word. +&wparam(num) Parameter number num, that was push + in C convention. This all works over pushes + and pops. +&comment("hello there") Put in a comment. +&label("loop") Refer to a label, normally a jmp target. +&set_label("loop") Set a label at this point. +&data_word(word) Put in a word of data. + +So how does this all hold together? Given + +int calc(int len, int *data) + { + int i,j=0; + + for (i=0; i. +# +# Why AT&T to MASM and not vice versa? Several reasons. Because AT&T +# format is way easier to parse. Because it's simpler to "gear" from +# Unix ABI to Windows one [see cross-reference "card" at the end of +# file]. Because Linux targets were available first... +# +# In addition the script also "distills" code suitable for GNU +# assembler, so that it can be compiled with more rigid assemblers, +# such as Solaris /usr/ccs/bin/as. +# +# This translator is not designed to convert *arbitrary* assembler +# code from AT&T format to MASM one. It's designed to convert just +# enough to provide for dual-ABI OpenSSL modules development... +# There *are* limitations and you might have to modify your assembler +# code or this script to achieve the desired result... +# +# Currently recognized limitations: +# +# - can't use multiple ops per line; +# +# Dual-ABI styling rules. +# +# 1. Adhere to Unix register and stack layout [see cross-reference +# ABI "card" at the end for explanation]. +# 2. Forget about "red zone," stick to more traditional blended +# stack frame allocation. If volatile storage is actually required +# that is. If not, just leave the stack as is. +# 3. Functions tagged with ".type name,@function" get crafted with +# unified Win64 prologue and epilogue automatically. If you want +# to take care of ABI differences yourself, tag functions as +# ".type name,@abi-omnipotent" instead. +# 4. To optimize the Win64 prologue you can specify number of input +# arguments as ".type name,@function,N." Keep in mind that if N is +# larger than 6, then you *have to* write "abi-omnipotent" code, +# because >6 cases can't be addressed with unified prologue. +# 5. Name local labels as .L*, do *not* use dynamic labels such as 1: +# (sorry about latter). +# 6. Don't use [or hand-code with .byte] "rep ret." "ret" mnemonic is +# required to identify the spots, where to inject Win64 epilogue! +# But on the pros, it's then prefixed with rep automatically:-) +# 7. Stick to explicit ip-relative addressing. If you have to use +# GOTPCREL addressing, stick to mov symbol@GOTPCREL(%rip),%r??. +# Both are recognized and translated to proper Win64 addressing +# modes. To support legacy code a synthetic directive, .picmeup, +# is implemented. It puts address of the *next* instruction into +# target register, e.g.: +# +# .picmeup %rax +# lea .Label-.(%rax),%rax +# +# 8. In order to provide for structured exception handling unified +# Win64 prologue copies %rsp value to %rax. For further details +# see SEH paragraph at the end. +# 9. .init segment is allowed to contain calls to functions only. +# a. If function accepts more than 4 arguments *and* >4th argument +# is declared as non 64-bit value, do clear its upper part. + +my $flavour = shift; +my $output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +open STDOUT,">$output" || die "can't open $output: $!" + if (defined($output)); + +my $gas=1; $gas=0 if ($output =~ /\.asm$/); +my $elf=1; $elf=0 if (!$gas); +my $win64=0; +my $prefix=""; +my $decor=".L"; + +my $masmref=8 + 50727*2**-32; # 8.00.50727 shipped with VS2005 +my $masm=0; +my $PTR=" PTR"; + +my $nasmref=2.03; +my $nasm=0; + +if ($flavour eq "mingw64") { $gas=1; $elf=0; $win64=1; + $prefix=`echo __USER_LABEL_PREFIX__ | $ENV{CC} -E -P -`; + chomp($prefix); + } +elsif ($flavour eq "macosx") { $gas=1; $elf=0; $prefix="_"; $decor="L\$"; } +elsif ($flavour eq "masm") { $gas=0; $elf=0; $masm=$masmref; $win64=1; $decor="\$L\$"; } +elsif ($flavour eq "nasm") { $gas=0; $elf=0; $nasm=$nasmref; $win64=1; $decor="\$L\$"; $PTR=""; } +elsif (!$gas) +{ if ($ENV{ASM} =~ m/nasm/ && `nasm -v` =~ m/version ([0-9]+)\.([0-9]+)/i) + { $nasm = $1 + $2*0.01; $PTR=""; } + elsif (`ml64 2>&1` =~ m/Version ([0-9]+)\.([0-9]+)(\.([0-9]+))?/) + { $masm = $1 + $2*2**-16 + $4*2**-32; } + die "no assembler found on %PATH" if (!($nasm || $masm)); + $win64=1; + $elf=0; + $decor="\$L\$"; +} + +my $current_segment; +my $current_function; +my %globals; + +{ package opcode; # pick up opcodes + sub re { + my $self = shift; # single instance in enough... + local *line = shift; + undef $ret; + + if ($line =~ /^([a-z][a-z0-9]*)/i) { + $self->{op} = $1; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + + undef $self->{sz}; + if ($self->{op} =~ /^(movz)x?([bw]).*/) { # movz is pain... + $self->{op} = $1; + $self->{sz} = $2; + } elsif ($self->{op} =~ /call|jmp/) { + $self->{sz} = ""; + } elsif ($self->{op} =~ /^p/ && $' !~ /^(ush|op|insrw)/) { # SSEn + $self->{sz} = ""; + } elsif ($self->{op} =~ /^v/) { # VEX + $self->{sz} = ""; + } elsif ($self->{op} =~ /mov[dq]/ && $line =~ /%xmm/) { + $self->{sz} = ""; + } elsif ($self->{op} =~ /([a-z]{3,})([qlwb])$/) { + $self->{op} = $1; + $self->{sz} = $2; + } + } + $ret; + } + sub size { + my $self = shift; + my $sz = shift; + $self->{sz} = $sz if (defined($sz) && !defined($self->{sz})); + $self->{sz}; + } + sub out { + my $self = shift; + if ($gas) { + if ($self->{op} eq "movz") { # movz is pain... + sprintf "%s%s%s",$self->{op},$self->{sz},shift; + } elsif ($self->{op} =~ /^set/) { + "$self->{op}"; + } elsif ($self->{op} eq "ret") { + my $epilogue = ""; + if ($win64 && $current_function->{abi} eq "svr4") { + $epilogue = "movq 8(%rsp),%rdi\n\t" . + "movq 16(%rsp),%rsi\n\t"; + } + $epilogue . ".byte 0xf3,0xc3"; + } elsif ($self->{op} eq "call" && !$elf && $current_segment eq ".init") { + ".p2align\t3\n\t.quad"; + } else { + "$self->{op}$self->{sz}"; + } + } else { + $self->{op} =~ s/^movz/movzx/; + if ($self->{op} eq "ret") { + $self->{op} = ""; + if ($win64 && $current_function->{abi} eq "svr4") { + $self->{op} = "mov rdi,QWORD${PTR}[8+rsp]\t;WIN64 epilogue\n\t". + "mov rsi,QWORD${PTR}[16+rsp]\n\t"; + } + $self->{op} .= "DB\t0F3h,0C3h\t\t;repret"; + } elsif ($self->{op} =~ /^(pop|push)f/) { + $self->{op} .= $self->{sz}; + } elsif ($self->{op} eq "call" && $current_segment eq ".CRT\$XCU") { + $self->{op} = "\tDQ"; + } + $self->{op}; + } + } + sub mnemonic { + my $self=shift; + my $op=shift; + $self->{op}=$op if (defined($op)); + $self->{op}; + } +} +{ package const; # pick up constants, which start with $ + sub re { + my $self = shift; # single instance in enough... + local *line = shift; + undef $ret; + + if ($line =~ /^\$([^,]+)/) { + $self->{value} = $1; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + } + $ret; + } + sub out { + my $self = shift; + + if ($gas) { + # Solaris /usr/ccs/bin/as can't handle multiplications + # in $self->{value} + $self->{value} =~ s/(?{value} =~ s/([0-9]+\s*[\*\/\%]\s*[0-9]+)/eval($1)/eg; + sprintf "\$%s",$self->{value}; + } else { + $self->{value} =~ s/(0b[0-1]+)/oct($1)/eig; + $self->{value} =~ s/0x([0-9a-f]+)/0$1h/ig if ($masm); + sprintf "%s",$self->{value}; + } + } +} +{ package ea; # pick up effective addresses: expr(%reg,%reg,scale) + sub re { + my $self = shift; # single instance in enough... + local *line = shift; + undef $ret; + + # optional * ---vvv--- appears in indirect jmp/call + if ($line =~ /^(\*?)([^\(,]*)\(([%\w,]+)\)/) { + $self->{asterisk} = $1; + $self->{label} = $2; + ($self->{base},$self->{index},$self->{scale})=split(/,/,$3); + $self->{scale} = 1 if (!defined($self->{scale})); + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + + if ($win64 && $self->{label} =~ s/\@GOTPCREL//) { + die if (opcode->mnemonic() ne "mov"); + opcode->mnemonic("lea"); + } + $self->{base} =~ s/^%//; + $self->{index} =~ s/^%// if (defined($self->{index})); + } + $ret; + } + sub size {} + sub out { + my $self = shift; + my $sz = shift; + + $self->{label} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei; + $self->{label} =~ s/\.L/$decor/g; + + # Silently convert all EAs to 64-bit. This is required for + # elder GNU assembler and results in more compact code, + # *but* most importantly AES module depends on this feature! + $self->{index} =~ s/^[er](.?[0-9xpi])[d]?$/r\1/; + $self->{base} =~ s/^[er](.?[0-9xpi])[d]?$/r\1/; + + # Solaris /usr/ccs/bin/as can't handle multiplications + # in $self->{label}, new gas requires sign extension... + use integer; + $self->{label} =~ s/(?{label} =~ s/\b([0-9]+\s*[\*\/\%]\s*[0-9]+)\b/eval($1)/eg; + $self->{label} =~ s/\b([0-9]+)\b/$1<<32>>32/eg; + + if (!$self->{label} && $self->{index} && $self->{scale}==1 && + $self->{base} =~ /(rbp|r13)/) { + $self->{base} = $self->{index}; $self->{index} = $1; + } + + if ($gas) { + $self->{label} =~ s/^___imp_/__imp__/ if ($flavour eq "mingw64"); + + if (defined($self->{index})) { + sprintf "%s%s(%s,%%%s,%d)",$self->{asterisk}, + $self->{label}, + $self->{base}?"%$self->{base}":"", + $self->{index},$self->{scale}; + } else { + sprintf "%s%s(%%%s)", $self->{asterisk},$self->{label},$self->{base}; + } + } else { + %szmap = ( b=>"BYTE$PTR", w=>"WORD$PTR", + l=>"DWORD$PTR", d=>"DWORD$PTR", + q=>"QWORD$PTR", o=>"OWORD$PTR", + x=>"XMMWORD$PTR", y=>"YMMWORD$PTR", z=>"ZMMWORD$PTR" ); + + $self->{label} =~ s/\./\$/g; + $self->{label} =~ s/(?{label} = "($self->{label})" if ($self->{label} =~ /[\*\+\-\/]/); + + ($self->{asterisk}) && ($sz="q") || + (opcode->mnemonic() =~ /^v?mov([qd])$/) && ($sz=$1) || + (opcode->mnemonic() =~ /^v?pinsr([qdwb])$/) && ($sz=$1) || + (opcode->mnemonic() =~ /^vpbroadcast([qdwb])$/) && ($sz=$1) || + (opcode->mnemonic() =~ /^vinsert[fi]128$/) && ($sz="x"); + + if (defined($self->{index})) { + sprintf "%s[%s%s*%d%s]",$szmap{$sz}, + $self->{label}?"$self->{label}+":"", + $self->{index},$self->{scale}, + $self->{base}?"+$self->{base}":""; + } elsif ($self->{base} eq "rip") { + sprintf "%s[%s]",$szmap{$sz},$self->{label}; + } else { + sprintf "%s[%s%s]",$szmap{$sz}, + $self->{label}?"$self->{label}+":"", + $self->{base}; + } + } + } +} +{ package register; # pick up registers, which start with %. + sub re { + my $class = shift; # muliple instances... + my $self = {}; + local *line = shift; + undef $ret; + + # optional * ---vvv--- appears in indirect jmp/call + if ($line =~ /^(\*?)%(\w+)/) { + bless $self,$class; + $self->{asterisk} = $1; + $self->{value} = $2; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + } + $ret; + } + sub size { + my $self = shift; + undef $ret; + + if ($self->{value} =~ /^r[\d]+b$/i) { $ret="b"; } + elsif ($self->{value} =~ /^r[\d]+w$/i) { $ret="w"; } + elsif ($self->{value} =~ /^r[\d]+d$/i) { $ret="l"; } + elsif ($self->{value} =~ /^r[\w]+$/i) { $ret="q"; } + elsif ($self->{value} =~ /^[a-d][hl]$/i){ $ret="b"; } + elsif ($self->{value} =~ /^[\w]{2}l$/i) { $ret="b"; } + elsif ($self->{value} =~ /^[\w]{2}$/i) { $ret="w"; } + elsif ($self->{value} =~ /^e[a-z]{2}$/i){ $ret="l"; } + + $ret; + } + sub out { + my $self = shift; + if ($gas) { sprintf "%s%%%s",$self->{asterisk},$self->{value}; } + else { $self->{value}; } + } +} +{ package label; # pick up labels, which end with : + sub re { + my $self = shift; # single instance is enough... + local *line = shift; + undef $ret; + + if ($line =~ /(^[\.\w]+)\:/) { + $self->{value} = $1; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + + $self->{value} =~ s/^\.L/$decor/; + } + $ret; + } + sub out { + my $self = shift; + + if ($gas) { + my $func = ($globals{$self->{value}} or $self->{value}) . ":"; + if ($win64 && + $current_function->{name} eq $self->{value} && + $current_function->{abi} eq "svr4") { + $func .= "\n"; + $func .= " movq %rdi,8(%rsp)\n"; + $func .= " movq %rsi,16(%rsp)\n"; + $func .= " movq %rsp,%rax\n"; + $func .= "${decor}SEH_begin_$current_function->{name}:\n"; + my $narg = $current_function->{narg}; + $narg=6 if (!defined($narg)); + $func .= " movq %rcx,%rdi\n" if ($narg>0); + $func .= " movq %rdx,%rsi\n" if ($narg>1); + $func .= " movq %r8,%rdx\n" if ($narg>2); + $func .= " movq %r9,%rcx\n" if ($narg>3); + $func .= " movq 40(%rsp),%r8\n" if ($narg>4); + $func .= " movq 48(%rsp),%r9\n" if ($narg>5); + } + $func; + } elsif ($self->{value} ne "$current_function->{name}") { + $self->{value} .= ":" if ($masm && $ret!~m/^\$/); + $self->{value} . ":"; + } elsif ($win64 && $current_function->{abi} eq "svr4") { + my $func = "$current_function->{name}" . + ($nasm ? ":" : "\tPROC $current_function->{scope}") . + "\n"; + $func .= " mov QWORD${PTR}[8+rsp],rdi\t;WIN64 prologue\n"; + $func .= " mov QWORD${PTR}[16+rsp],rsi\n"; + $func .= " mov rax,rsp\n"; + $func .= "${decor}SEH_begin_$current_function->{name}:"; + $func .= ":" if ($masm); + $func .= "\n"; + my $narg = $current_function->{narg}; + $narg=6 if (!defined($narg)); + $func .= " mov rdi,rcx\n" if ($narg>0); + $func .= " mov rsi,rdx\n" if ($narg>1); + $func .= " mov rdx,r8\n" if ($narg>2); + $func .= " mov rcx,r9\n" if ($narg>3); + $func .= " mov r8,QWORD${PTR}[40+rsp]\n" if ($narg>4); + $func .= " mov r9,QWORD${PTR}[48+rsp]\n" if ($narg>5); + $func .= "\n"; + } else { + "$current_function->{name}". + ($nasm ? ":" : "\tPROC $current_function->{scope}"); + } + } +} +{ package expr; # pick up expressioins + sub re { + my $self = shift; # single instance is enough... + local *line = shift; + undef $ret; + + if ($line =~ /(^[^,]+)/) { + $self->{value} = $1; + $ret = $self; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + + $self->{value} =~ s/\@PLT// if (!$elf); + $self->{value} =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei; + $self->{value} =~ s/\.L/$decor/g; + } + $ret; + } + sub out { + my $self = shift; + if ($nasm && opcode->mnemonic()=~m/^j(?![re]cxz)/) { + "NEAR ".$self->{value}; + } else { + $self->{value}; + } + } +} +{ package directive; # pick up directives, which start with . + sub re { + my $self = shift; # single instance is enough... + local *line = shift; + undef $ret; + my $dir; + my %opcode = # lea 2f-1f(%rip),%dst; 1: nop; 2: + ( "%rax"=>0x01058d48, "%rcx"=>0x010d8d48, + "%rdx"=>0x01158d48, "%rbx"=>0x011d8d48, + "%rsp"=>0x01258d48, "%rbp"=>0x012d8d48, + "%rsi"=>0x01358d48, "%rdi"=>0x013d8d48, + "%r8" =>0x01058d4c, "%r9" =>0x010d8d4c, + "%r10"=>0x01158d4c, "%r11"=>0x011d8d4c, + "%r12"=>0x01258d4c, "%r13"=>0x012d8d4c, + "%r14"=>0x01358d4c, "%r15"=>0x013d8d4c ); + + if ($line =~ /^\s*(\.\w+)/) { + $dir = $1; + $ret = $self; + undef $self->{value}; + $line = substr($line,@+[0]); $line =~ s/^\s+//; + + SWITCH: for ($dir) { + /\.picmeup/ && do { if ($line =~ /(%r[\w]+)/i) { + $dir="\t.long"; + $line=sprintf "0x%x,0x90000000",$opcode{$1}; + } + last; + }; + /\.global|\.globl|\.extern/ + && do { $globals{$line} = $prefix . $line; + $line = $globals{$line} if ($prefix); + last; + }; + /\.type/ && do { ($sym,$type,$narg) = split(',',$line); + if ($type eq "\@function") { + undef $current_function; + $current_function->{name} = $sym; + $current_function->{abi} = "svr4"; + $current_function->{narg} = $narg; + $current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE"; + } elsif ($type eq "\@abi-omnipotent") { + undef $current_function; + $current_function->{name} = $sym; + $current_function->{scope} = defined($globals{$sym})?"PUBLIC":"PRIVATE"; + } + $line =~ s/\@abi\-omnipotent/\@function/; + $line =~ s/\@function.*/\@function/; + last; + }; + /\.asciz/ && do { if ($line =~ /^"(.*)"$/) { + $dir = ".byte"; + $line = join(",",unpack("C*",$1),0); + } + last; + }; + /\.rva|\.long|\.quad/ + && do { $line =~ s/([_a-z][_a-z0-9]*)/$globals{$1} or $1/gei; + $line =~ s/\.L/$decor/g; + last; + }; + } + + if ($gas) { + $self->{value} = $dir . "\t" . $line; + + if ($dir =~ /\.extern/) { + if ($flavour eq "elf") { + $self->{value} .= "\n.hidden $line"; + } else { + $self->{value} = ""; + } + } elsif (!$elf && $dir =~ /\.type/) { + $self->{value} = ""; + $self->{value} = ".def\t" . ($globals{$1} or $1) . ";\t" . + (defined($globals{$1})?".scl 2;":".scl 3;") . + "\t.type 32;\t.endef" + if ($win64 && $line =~ /([^,]+),\@function/); + } elsif (!$elf && $dir =~ /\.size/) { + $self->{value} = ""; + if (defined($current_function)) { + $self->{value} .= "${decor}SEH_end_$current_function->{name}:" + if ($win64 && $current_function->{abi} eq "svr4"); + undef $current_function; + } + } elsif (!$elf && $dir =~ /\.align/) { + $self->{value} = ".p2align\t" . (log($line)/log(2)); + } elsif ($dir eq ".section") { + $current_segment=$line; + if (!$elf && $current_segment eq ".init") { + if ($flavour eq "macosx") { $self->{value} = ".mod_init_func"; } + elsif ($flavour eq "mingw64") { $self->{value} = ".section\t.ctors"; } + } + } elsif ($dir =~ /\.(text|data)/) { + $current_segment=".$1"; + } elsif ($dir =~ /\.global|\.globl|\.extern/) { + if ($flavour eq "macosx") { + $self->{value} .= "\n.private_extern $line"; + } else { + $self->{value} .= "\n.hidden $line"; + } + } elsif ($dir =~ /\.hidden/) { + if ($flavour eq "macosx") { $self->{value} = ".private_extern\t$prefix$line"; } + elsif ($flavour eq "mingw64") { $self->{value} = ""; } + } elsif ($dir =~ /\.comm/) { + $self->{value} = "$dir\t$prefix$line"; + $self->{value} =~ s|,([0-9]+),([0-9]+)$|",$1,".log($2)/log(2)|e if ($flavour eq "macosx"); + } + $line = ""; + return $self; + } + + # non-gas case or nasm/masm + SWITCH: for ($dir) { + /\.text/ && do { my $v=undef; + if ($nasm) { + $v="section .text code align=64\n"; + } else { + $v="$current_segment\tENDS\n" if ($current_segment); + $current_segment = ".text\$"; + $v.="$current_segment\tSEGMENT "; + $v.=$masm>=$masmref ? "ALIGN(256)" : "PAGE"; + $v.=" 'CODE'"; + } + $self->{value} = $v; + last; + }; + /\.data/ && do { my $v=undef; + if ($nasm) { + $v="section .data data align=8\n"; + } else { + $v="$current_segment\tENDS\n" if ($current_segment); + $current_segment = "_DATA"; + $v.="$current_segment\tSEGMENT"; + } + $self->{value} = $v; + last; + }; + /\.section/ && do { my $v=undef; + $line =~ s/([^,]*).*/$1/; + $line = ".CRT\$XCU" if ($line eq ".init"); + if ($nasm) { + $v="section $line"; + if ($line=~/\.([px])data/) { + $v.=" rdata align="; + $v.=$1 eq "p"? 4 : 8; + } elsif ($line=~/\.CRT\$/i) { + $v.=" rdata align=8"; + } + } else { + $v="$current_segment\tENDS\n" if ($current_segment); + $v.="$line\tSEGMENT"; + if ($line=~/\.([px])data/) { + $v.=" READONLY"; + $v.=" ALIGN(".($1 eq "p" ? 4 : 8).")" if ($masm>=$masmref); + } elsif ($line=~/\.CRT\$/i) { + $v.=" READONLY "; + $v.=$masm>=$masmref ? "ALIGN(8)" : "DWORD"; + } + } + $current_segment = $line; + $self->{value} = $v; + last; + }; + /\.extern/ && do { $self->{value} = "EXTERN\t".$line; + $self->{value} .= ":NEAR" if ($masm); + last; + }; + /\.globl|.global/ + && do { $self->{value} = $masm?"PUBLIC":"global"; + $self->{value} .= "\t".$line; + last; + }; + /\.size/ && do { if (defined($current_function)) { + undef $self->{value}; + if ($current_function->{abi} eq "svr4") { + $self->{value}="${decor}SEH_end_$current_function->{name}:"; + $self->{value}.=":\n" if($masm); + } + $self->{value}.="$current_function->{name}\tENDP" if($masm && $current_function->{name}); + undef $current_function; + } + last; + }; + /\.align/ && do { $self->{value} = "ALIGN\t".$line; last; }; + /\.(value|long|rva|quad)/ + && do { my $sz = substr($1,0,1); + my @arr = split(/,\s*/,$line); + my $last = pop(@arr); + my $conv = sub { my $var=shift; + $var=~s/^(0b[0-1]+)/oct($1)/eig; + $var=~s/^0x([0-9a-f]+)/0$1h/ig if ($masm); + if ($sz eq "D" && ($current_segment=~/.[px]data/ || $dir eq ".rva")) + { $var=~s/([_a-z\$\@][_a-z0-9\$\@]*)/$nasm?"$1 wrt ..imagebase":"imagerel $1"/egi; } + $var; + }; + + $sz =~ tr/bvlrq/BWDDQ/; + $self->{value} = "\tD$sz\t"; + for (@arr) { $self->{value} .= &$conv($_).","; } + $self->{value} .= &$conv($last); + last; + }; + /\.byte/ && do { my @str=split(/,\s*/,$line); + map(s/(0b[0-1]+)/oct($1)/eig,@str); + map(s/0x([0-9a-f]+)/0$1h/ig,@str) if ($masm); + while ($#str>15) { + $self->{value}.="DB\t" + .join(",",@str[0..15])."\n"; + foreach (0..15) { shift @str; } + } + $self->{value}.="DB\t" + .join(",",@str) if (@str); + last; + }; + /\.comm/ && do { my @str=split(/,\s*/,$line); + my $v=undef; + if ($nasm) { + $v.="common $prefix@str[0] @str[1]"; + } else { + $v="$current_segment\tENDS\n" if ($current_segment); + $current_segment = "_DATA"; + $v.="$current_segment\tSEGMENT\n"; + $v.="COMM @str[0]:DWORD:".@str[1]/4; + } + $self->{value} = $v; + last; + }; + } + $line = ""; + } + + $ret; + } + sub out { + my $self = shift; + $self->{value}; + } +} + +sub rex { + local *opcode=shift; + my ($dst,$src,$rex)=@_; + + $rex|=0x04 if($dst>=8); + $rex|=0x01 if($src>=8); + push @opcode,($rex|0x40) if ($rex); +} + +# older gas and ml64 don't handle SSE>2 instructions +my %regrm = ( "%eax"=>0, "%ecx"=>1, "%edx"=>2, "%ebx"=>3, + "%esp"=>4, "%ebp"=>5, "%esi"=>6, "%edi"=>7 ); + +my $movq = sub { # elderly gas can't handle inter-register movq + my $arg = shift; + my @opcode=(0x66); + if ($arg =~ /%xmm([0-9]+),\s*%r(\w+)/) { + my ($src,$dst)=($1,$2); + if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; } + rex(\@opcode,$src,$dst,0x8); + push @opcode,0x0f,0x7e; + push @opcode,0xc0|(($src&7)<<3)|($dst&7); # ModR/M + @opcode; + } elsif ($arg =~ /%r(\w+),\s*%xmm([0-9]+)/) { + my ($src,$dst)=($2,$1); + if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; } + rex(\@opcode,$src,$dst,0x8); + push @opcode,0x0f,0x6e; + push @opcode,0xc0|(($src&7)<<3)|($dst&7); # ModR/M + @opcode; + } else { + (); + } +}; + +my $pextrd = sub { + if (shift =~ /\$([0-9]+),\s*%xmm([0-9]+),\s*(%\w+)/) { + my @opcode=(0x66); + $imm=$1; + $src=$2; + $dst=$3; + if ($dst =~ /%r([0-9]+)d/) { $dst = $1; } + elsif ($dst =~ /%e/) { $dst = $regrm{$dst}; } + rex(\@opcode,$src,$dst); + push @opcode,0x0f,0x3a,0x16; + push @opcode,0xc0|(($src&7)<<3)|($dst&7); # ModR/M + push @opcode,$imm; + @opcode; + } else { + (); + } +}; + +my $pinsrd = sub { + if (shift =~ /\$([0-9]+),\s*(%\w+),\s*%xmm([0-9]+)/) { + my @opcode=(0x66); + $imm=$1; + $src=$2; + $dst=$3; + if ($src =~ /%r([0-9]+)/) { $src = $1; } + elsif ($src =~ /%e/) { $src = $regrm{$src}; } + rex(\@opcode,$dst,$src); + push @opcode,0x0f,0x3a,0x22; + push @opcode,0xc0|(($dst&7)<<3)|($src&7); # ModR/M + push @opcode,$imm; + @opcode; + } else { + (); + } +}; + +my $pshufb = sub { + if (shift =~ /%xmm([0-9]+),\s*%xmm([0-9]+)/) { + my @opcode=(0x66); + rex(\@opcode,$2,$1); + push @opcode,0x0f,0x38,0x00; + push @opcode,0xc0|($1&7)|(($2&7)<<3); # ModR/M + @opcode; + } else { + (); + } +}; + +my $palignr = sub { + if (shift =~ /\$([0-9]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) { + my @opcode=(0x66); + rex(\@opcode,$3,$2); + push @opcode,0x0f,0x3a,0x0f; + push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M + push @opcode,$1; + @opcode; + } else { + (); + } +}; + +my $pclmulqdq = sub { + if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) { + my @opcode=(0x66); + rex(\@opcode,$3,$2); + push @opcode,0x0f,0x3a,0x44; + push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M + my $c=$1; + push @opcode,$c=~/^0/?oct($c):$c; + @opcode; + } else { + (); + } +}; + +my $rdrand = sub { + if (shift =~ /%[er](\w+)/) { + my @opcode=(); + my $dst=$1; + if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; } + rex(\@opcode,0,$1,8); + push @opcode,0x0f,0xc7,0xf0|($dst&7); + @opcode; + } else { + (); + } +}; + +my $rdseed = sub { + if (shift =~ /%[er](\w+)/) { + my @opcode=(); + my $dst=$1; + if ($dst !~ /[0-9]+/) { $dst = $regrm{"%e$dst"}; } + rex(\@opcode,0,$1,8); + push @opcode,0x0f,0xc7,0xf8|($dst&7); + @opcode; + } else { + (); + } +}; + +sub rxb { + local *opcode=shift; + my ($dst,$src1,$src2,$rxb)=@_; + + $rxb|=0x7<<5; + $rxb&=~(0x04<<5) if($dst>=8); + $rxb&=~(0x01<<5) if($src1>=8); + $rxb&=~(0x02<<5) if($src2>=8); + push @opcode,$rxb; +} + +my $vprotd = sub { + if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) { + my @opcode=(0x8f); + rxb(\@opcode,$3,$2,-1,0x08); + push @opcode,0x78,0xc2; + push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M + my $c=$1; + push @opcode,$c=~/^0/?oct($c):$c; + @opcode; + } else { + (); + } +}; + +my $vprotq = sub { + if (shift =~ /\$([x0-9a-f]+),\s*%xmm([0-9]+),\s*%xmm([0-9]+)/) { + my @opcode=(0x8f); + rxb(\@opcode,$3,$2,-1,0x08); + push @opcode,0x78,0xc3; + push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M + my $c=$1; + push @opcode,$c=~/^0/?oct($c):$c; + @opcode; + } else { + (); + } +}; + +if ($nasm) { + print <<___; +default rel +%define XMMWORD +%define YMMWORD +%define ZMMWORD +___ +} elsif ($masm) { + print <<___; +OPTION DOTNAME +___ +} + +print STDOUT "#if defined(__x86_64__)\n" if ($gas); + +while($line=<>) { + + chomp($line); + + $line =~ s|[#!].*$||; # get rid of asm-style comments... + $line =~ s|/\*.*\*/||; # ... and C-style comments... + $line =~ s|^\s+||; # ... and skip white spaces in beginning + $line =~ s|\s+$||; # ... and at the end + + undef $label; + undef $opcode; + undef @args; + + if ($label=label->re(\$line)) { print $label->out(); } + + if (directive->re(\$line)) { + printf "%s",directive->out(); + } elsif ($opcode=opcode->re(\$line)) { + my $asm = eval("\$".$opcode->mnemonic()); + undef @bytes; + + if ((ref($asm) eq 'CODE') && scalar(@bytes=&$asm($line))) { + print $gas?".byte\t":"DB\t",join(',',@bytes),"\n"; + next; + } + + ARGUMENT: while (1) { + my $arg; + + if ($arg=register->re(\$line)) { opcode->size($arg->size()); } + elsif ($arg=const->re(\$line)) { } + elsif ($arg=ea->re(\$line)) { } + elsif ($arg=expr->re(\$line)) { } + else { last ARGUMENT; } + + push @args,$arg; + + last ARGUMENT if ($line !~ /^,/); + + $line =~ s/^,\s*//; + } # ARGUMENT: + + if ($#args>=0) { + my $insn; + my $sz=opcode->size(); + + if ($gas) { + $insn = $opcode->out($#args>=1?$args[$#args]->size():$sz); + @args = map($_->out($sz),@args); + printf "\t%s\t%s",$insn,join(",",@args); + } else { + $insn = $opcode->out(); + foreach (@args) { + my $arg = $_->out(); + # $insn.=$sz compensates for movq, pinsrw, ... + if ($arg =~ /^xmm[0-9]+$/) { $insn.=$sz; $sz="x" if(!$sz); last; } + if ($arg =~ /^ymm[0-9]+$/) { $insn.=$sz; $sz="y" if(!$sz); last; } + if ($arg =~ /^zmm[0-9]+$/) { $insn.=$sz; $sz="z" if(!$sz); last; } + if ($arg =~ /^mm[0-9]+$/) { $insn.=$sz; $sz="q" if(!$sz); last; } + } + @args = reverse(@args); + undef $sz if ($nasm && $opcode->mnemonic() eq "lea"); + + if ($insn eq "movq" && $#args == 1 && $args[0]->out($sz) eq "xmm0" && $args[1]->out($sz) eq "rax") { + # I have no clue why MASM can't parse this instruction. + printf "DB 66h, 48h, 0fh, 6eh, 0c0h"; + } else { + printf "\t%s\t%s",$insn,join(",",map($_->out($sz),@args)); + } + } + } else { + printf "\t%s",$opcode->out(); + } + } + + print $line,"\n"; +} + +print "\n$current_segment\tENDS\n" if ($current_segment && $masm); +print "END\n" if ($masm); +print "#endif\n" if ($gas); + + +close STDOUT; + + ################################################# +# Cross-reference x86_64 ABI "card" +# +# Unix Win64 +# %rax * * +# %rbx - - +# %rcx #4 #1 +# %rdx #3 #2 +# %rsi #2 - +# %rdi #1 - +# %rbp - - +# %rsp - - +# %r8 #5 #3 +# %r9 #6 #4 +# %r10 * * +# %r11 * * +# %r12 - - +# %r13 - - +# %r14 - - +# %r15 - - +# +# (*) volatile register +# (-) preserved by callee +# (#) Nth argument, volatile +# +# In Unix terms top of stack is argument transfer area for arguments +# which could not be accomodated in registers. Or in other words 7th +# [integer] argument resides at 8(%rsp) upon function entry point. +# 128 bytes above %rsp constitute a "red zone" which is not touched +# by signal handlers and can be used as temporal storage without +# allocating a frame. +# +# In Win64 terms N*8 bytes on top of stack is argument transfer area, +# which belongs to/can be overwritten by callee. N is the number of +# arguments passed to callee, *but* not less than 4! This means that +# upon function entry point 5th argument resides at 40(%rsp), as well +# as that 32 bytes from 8(%rsp) can always be used as temporal +# storage [without allocating a frame]. One can actually argue that +# one can assume a "red zone" above stack pointer under Win64 as well. +# Point is that at apparently no occasion Windows kernel would alter +# the area above user stack pointer in true asynchronous manner... +# +# All the above means that if assembler programmer adheres to Unix +# register and stack layout, but disregards the "red zone" existense, +# it's possible to use following prologue and epilogue to "gear" from +# Unix to Win64 ABI in leaf functions with not more than 6 arguments. +# +# omnipotent_function: +# ifdef WIN64 +# movq %rdi,8(%rsp) +# movq %rsi,16(%rsp) +# movq %rcx,%rdi ; if 1st argument is actually present +# movq %rdx,%rsi ; if 2nd argument is actually ... +# movq %r8,%rdx ; if 3rd argument is ... +# movq %r9,%rcx ; if 4th argument ... +# movq 40(%rsp),%r8 ; if 5th ... +# movq 48(%rsp),%r9 ; if 6th ... +# endif +# ... +# ifdef WIN64 +# movq 8(%rsp),%rdi +# movq 16(%rsp),%rsi +# endif +# ret +# + ################################################# +# Win64 SEH, Structured Exception Handling. +# +# Unlike on Unix systems(*) lack of Win64 stack unwinding information +# has undesired side-effect at run-time: if an exception is raised in +# assembler subroutine such as those in question (basically we're +# referring to segmentation violations caused by malformed input +# parameters), the application is briskly terminated without invoking +# any exception handlers, most notably without generating memory dump +# or any user notification whatsoever. This poses a problem. It's +# possible to address it by registering custom language-specific +# handler that would restore processor context to the state at +# subroutine entry point and return "exception is not handled, keep +# unwinding" code. Writing such handler can be a challenge... But it's +# doable, though requires certain coding convention. Consider following +# snippet: +# +# .type function,@function +# function: +# movq %rsp,%rax # copy rsp to volatile register +# pushq %r15 # save non-volatile registers +# pushq %rbx +# pushq %rbp +# movq %rsp,%r11 +# subq %rdi,%r11 # prepare [variable] stack frame +# andq $-64,%r11 +# movq %rax,0(%r11) # check for exceptions +# movq %r11,%rsp # allocate [variable] stack frame +# movq %rax,0(%rsp) # save original rsp value +# magic_point: +# ... +# movq 0(%rsp),%rcx # pull original rsp value +# movq -24(%rcx),%rbp # restore non-volatile registers +# movq -16(%rcx),%rbx +# movq -8(%rcx),%r15 +# movq %rcx,%rsp # restore original rsp +# ret +# .size function,.-function +# +# The key is that up to magic_point copy of original rsp value remains +# in chosen volatile register and no non-volatile register, except for +# rsp, is modified. While past magic_point rsp remains constant till +# the very end of the function. In this case custom language-specific +# exception handler would look like this: +# +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +# { ULONG64 *rsp = (ULONG64 *)context->Rax; +# if (context->Rip >= magic_point) +# { rsp = ((ULONG64 **)context->Rsp)[0]; +# context->Rbp = rsp[-3]; +# context->Rbx = rsp[-2]; +# context->R15 = rsp[-1]; +# } +# context->Rsp = (ULONG64)rsp; +# context->Rdi = rsp[1]; +# context->Rsi = rsp[2]; +# +# memcpy (disp->ContextRecord,context,sizeof(CONTEXT)); +# RtlVirtualUnwind(UNW_FLAG_NHANDLER,disp->ImageBase, +# dips->ControlPc,disp->FunctionEntry,disp->ContextRecord, +# &disp->HandlerData,&disp->EstablisherFrame,NULL); +# return ExceptionContinueSearch; +# } +# +# It's appropriate to implement this handler in assembler, directly in +# function's module. In order to do that one has to know members' +# offsets in CONTEXT and DISPATCHER_CONTEXT structures and some constant +# values. Here they are: +# +# CONTEXT.Rax 120 +# CONTEXT.Rcx 128 +# CONTEXT.Rdx 136 +# CONTEXT.Rbx 144 +# CONTEXT.Rsp 152 +# CONTEXT.Rbp 160 +# CONTEXT.Rsi 168 +# CONTEXT.Rdi 176 +# CONTEXT.R8 184 +# CONTEXT.R9 192 +# CONTEXT.R10 200 +# CONTEXT.R11 208 +# CONTEXT.R12 216 +# CONTEXT.R13 224 +# CONTEXT.R14 232 +# CONTEXT.R15 240 +# CONTEXT.Rip 248 +# CONTEXT.Xmm6 512 +# sizeof(CONTEXT) 1232 +# DISPATCHER_CONTEXT.ControlPc 0 +# DISPATCHER_CONTEXT.ImageBase 8 +# DISPATCHER_CONTEXT.FunctionEntry 16 +# DISPATCHER_CONTEXT.EstablisherFrame 24 +# DISPATCHER_CONTEXT.TargetIp 32 +# DISPATCHER_CONTEXT.ContextRecord 40 +# DISPATCHER_CONTEXT.LanguageHandler 48 +# DISPATCHER_CONTEXT.HandlerData 56 +# UNW_FLAG_NHANDLER 0 +# ExceptionContinueSearch 1 +# +# In order to tie the handler to the function one has to compose +# couple of structures: one for .xdata segment and one for .pdata. +# +# UNWIND_INFO structure for .xdata segment would be +# +# function_unwind_info: +# .byte 9,0,0,0 +# .rva handler +# +# This structure designates exception handler for a function with +# zero-length prologue, no stack frame or frame register. +# +# To facilitate composing of .pdata structures, auto-generated "gear" +# prologue copies rsp value to rax and denotes next instruction with +# .LSEH_begin_{function_name} label. This essentially defines the SEH +# styling rule mentioned in the beginning. Position of this label is +# chosen in such manner that possible exceptions raised in the "gear" +# prologue would be accounted to caller and unwound from latter's frame. +# End of function is marked with respective .LSEH_end_{function_name} +# label. To summarize, .pdata segment would contain +# +# .rva .LSEH_begin_function +# .rva .LSEH_end_function +# .rva function_unwind_info +# +# Reference to functon_unwind_info from .xdata segment is the anchor. +# In case you wonder why references are 32-bit .rvas and not 64-bit +# .quads. References put into these two segments are required to be +# *relative* to the base address of the current binary module, a.k.a. +# image base. No Win64 module, be it .exe or .dll, can be larger than +# 2GB and thus such relative references can be and are accommodated in +# 32 bits. +# +# Having reviewed the example function code, one can argue that "movq +# %rsp,%rax" above is redundant. It is not! Keep in mind that on Unix +# rax would contain an undefined value. If this "offends" you, use +# another register and refrain from modifying rax till magic_point is +# reached, i.e. as if it was a non-volatile register. If more registers +# are required prior [variable] frame setup is completed, note that +# nobody says that you can have only one "magic point." You can +# "liberate" non-volatile registers by denoting last stack off-load +# instruction and reflecting it in finer grade unwind logic in handler. +# After all, isn't it why it's called *language-specific* handler... +# +# Attentive reader can notice that exceptions would be mishandled in +# auto-generated "gear" epilogue. Well, exception effectively can't +# occur there, because if memory area used by it was subject to +# segmentation violation, then it would be raised upon call to the +# function (and as already mentioned be accounted to caller, which is +# not a problem). If you're still not comfortable, then define tail +# "magic point" just prior ret instruction and have handler treat it... +# +# (*) Note that we're talking about run-time, not debug-time. Lack of +# unwind information makes debugging hard on both Windows and +# Unix. "Unlike" referes to the fact that on Unix signal handler +# will always be invoked, core dumped and appropriate exit code +# returned to parent (for user notification). diff --git a/TMessagesProj/jni/boringssl/crypto/perlasm/x86asm.pl b/TMessagesProj/jni/boringssl/crypto/perlasm/x86asm.pl new file mode 100644 index 00000000..3c7be40c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/perlasm/x86asm.pl @@ -0,0 +1,292 @@ +#!/usr/bin/env perl + +# require 'x86asm.pl'; +# &asm_init(,"des-586.pl"[,$i386only]); +# &function_begin("foo"); +# ... +# &function_end("foo"); +# &asm_finish + +$out=(); +$i386=0; + +# AUTOLOAD is this context has quite unpleasant side effect, namely +# that typos in function calls effectively go to assembler output, +# but on the pros side we don't have to implement one subroutine per +# each opcode... +sub ::AUTOLOAD +{ my $opcode = $AUTOLOAD; + + die "more than 4 arguments passed to $opcode" if ($#_>3); + + $opcode =~ s/.*:://; + if ($opcode =~ /^push/) { $stack+=4; } + elsif ($opcode =~ /^pop/) { $stack-=4; } + + &generic($opcode,@_) or die "undefined subroutine \&$AUTOLOAD"; +} + +sub ::emit +{ my $opcode=shift; + + if ($#_==-1) { push(@out,"\t$opcode\n"); } + else { push(@out,"\t$opcode\t".join(',',@_)."\n"); } +} + +sub ::LB +{ $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'low byte'"; + $1."l"; +} +sub ::HB +{ $_[0] =~ m/^e?([a-d])x$/o or die "$_[0] does not have a 'high byte'"; + $1."h"; +} +sub ::stack_push{ my $num=$_[0]*4; $stack+=$num; &sub("esp",$num); } +sub ::stack_pop { my $num=$_[0]*4; $stack-=$num; &add("esp",$num); } +sub ::blindpop { &pop($_[0]); $stack+=4; } +sub ::wparam { &DWP($stack+4*$_[0],"esp"); } +sub ::swtmp { &DWP(4*$_[0],"esp"); } + +sub ::bswap +{ if ($i386) # emulate bswap for i386 + { &comment("bswap @_"); + &xchg(&HB(@_),&LB(@_)); + &ror (@_,16); + &xchg(&HB(@_),&LB(@_)); + } + else + { &generic("bswap",@_); } +} +# These are made-up opcodes introduced over the years essentially +# by ignorance, just alias them to real ones... +sub ::movb { &mov(@_); } +sub ::xorb { &xor(@_); } +sub ::rotl { &rol(@_); } +sub ::rotr { &ror(@_); } +sub ::exch { &xchg(@_); } +sub ::halt { &hlt; } +sub ::movz { &movzx(@_); } +sub ::pushf { &pushfd; } +sub ::popf { &popfd; } + +# 3 argument instructions +sub ::movq +{ my($p1,$p2,$optimize)=@_; + + if ($optimize && $p1=~/^mm[0-7]$/ && $p2=~/^mm[0-7]$/) + # movq between mmx registers can sink Intel CPUs + { &::pshufw($p1,$p2,0xe4); } + else + { &::generic("movq",@_); } +} + +# SSE>2 instructions +my %regrm = ( "eax"=>0, "ecx"=>1, "edx"=>2, "ebx"=>3, + "esp"=>4, "ebp"=>5, "esi"=>6, "edi"=>7 ); +sub ::pextrd +{ my($dst,$src,$imm)=@_; + if ("$dst:$src" =~ /(e[a-dsd][ixp]):xmm([0-7])/) + { &::data_byte(0x66,0x0f,0x3a,0x16,0xc0|($2<<3)|$regrm{$1},$imm); } + else + { &::generic("pextrd",@_); } +} + +sub ::pinsrd +{ my($dst,$src,$imm)=@_; + if ("$dst:$src" =~ /xmm([0-7]):(e[a-dsd][ixp])/) + { &::data_byte(0x66,0x0f,0x3a,0x22,0xc0|($1<<3)|$regrm{$2},$imm); } + else + { &::generic("pinsrd",@_); } +} + +sub ::pshufb +{ my($dst,$src)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &data_byte(0x66,0x0f,0x38,0x00,0xc0|($1<<3)|$2); } + else + { &::generic("pshufb",@_); } +} + +sub ::palignr +{ my($dst,$src,$imm)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &::data_byte(0x66,0x0f,0x3a,0x0f,0xc0|($1<<3)|$2,$imm); } + else + { &::generic("palignr",@_); } +} + +sub ::pclmulqdq +{ my($dst,$src,$imm)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &::data_byte(0x66,0x0f,0x3a,0x44,0xc0|($1<<3)|$2,$imm); } + else + { &::generic("pclmulqdq",@_); } +} + +sub ::rdrand +{ my ($dst)=@_; + if ($dst =~ /(e[a-dsd][ixp])/) + { &::data_byte(0x0f,0xc7,0xf0|$regrm{$dst}); } + else + { &::generic("rdrand",@_); } +} + +sub rxb { + local *opcode=shift; + my ($dst,$src1,$src2,$rxb)=@_; + + $rxb|=0x7<<5; + $rxb&=~(0x04<<5) if($dst>=8); + $rxb&=~(0x01<<5) if($src1>=8); + $rxb&=~(0x02<<5) if($src2>=8); + push @opcode,$rxb; +} + +sub ::vprotd +{ my $args=join(',',@_); + if ($args =~ /xmm([0-7]),xmm([0-7]),([x0-9a-f]+)/) + { my @opcode=(0x8f); + rxb(\@opcode,$1,$2,-1,0x08); + push @opcode,0x78,0xc2; + push @opcode,0xc0|($2&7)|(($1&7)<<3); # ModR/M + my $c=$3; + push @opcode,$c=~/^0/?oct($c):$c; + &::data_byte(@opcode); + } + else + { &::generic("vprotd",@_); } +} + +# label management +$lbdecor="L"; # local label decoration, set by package +$label="000"; + +sub ::islabel # see is argument is a known label +{ my $i; + foreach $i (values %label) { return $i if ($i eq $_[0]); } + $label{$_[0]}; # can be undef +} + +sub ::label # instantiate a function-scope label +{ if (!defined($label{$_[0]})) + { $label{$_[0]}="${lbdecor}${label}${_[0]}"; $label++; } + $label{$_[0]}; +} + +sub ::LABEL # instantiate a file-scope label +{ $label{$_[0]}=$_[1] if (!defined($label{$_[0]})); + $label{$_[0]}; +} + +sub ::static_label { &::LABEL($_[0],$lbdecor.$_[0]); } + +sub ::set_label_B { push(@out,"@_:\n"); } +sub ::set_label +{ my $label=&::label($_[0]); + &::align($_[1]) if ($_[1]>1); + &::set_label_B($label); + $label; +} + +sub ::wipe_labels # wipes function-scope labels +{ foreach $i (keys %label) + { delete $label{$i} if ($label{$i} =~ /^\Q${lbdecor}\E[0-9]{3}/); } +} + +# subroutine management +sub ::function_begin +{ &function_begin_B(@_); + $stack=4; + &push("ebp"); + &push("ebx"); + &push("esi"); + &push("edi"); +} + +sub ::function_end +{ &pop("edi"); + &pop("esi"); + &pop("ebx"); + &pop("ebp"); + &ret(); + &function_end_B(@_); + $stack=0; + &wipe_labels(); +} + +sub ::function_end_A +{ &pop("edi"); + &pop("esi"); + &pop("ebx"); + &pop("ebp"); + &ret(); + $stack+=16; # readjust esp as if we didn't pop anything +} + +sub ::asciz +{ my @str=unpack("C*",shift); + push @str,0; + while ($#str>15) { + &data_byte(@str[0..15]); + foreach (0..15) { shift @str; } + } + &data_byte(@str) if (@str); +} + +sub ::asm_finish +{ &file_end(); + print "#if defined(__i386__)\n" unless $win32; + print @out; + print "#endif\n" unless $win32; +} + +sub ::asm_init +{ my ($type,$fn,$cpu)=@_; + + $filename=$fn; + $i386=$cpu; + + $elf=$cpp=$coff=$aout=$macosx=$win32=$netware=$mwerks=$android=0; + if (($type eq "elf")) + { $elf=1; require "x86gas.pl"; } + elsif (($type eq "elf-1")) + { $elf=-1; require "x86gas.pl"; } + elsif (($type eq "a\.out")) + { $aout=1; require "x86gas.pl"; } + elsif (($type eq "coff" or $type eq "gaswin")) + { $coff=1; require "x86gas.pl"; } + elsif (($type eq "win32n")) + { $win32=1; require "x86nasm.pl"; } + elsif (($type eq "nw-nasm")) + { $netware=1; require "x86nasm.pl"; } + #elsif (($type eq "nw-mwasm")) + #{ $netware=1; $mwerks=1; require "x86nasm.pl"; } + elsif (($type eq "win32")) + { $win32=1; require "x86masm.pl"; } + elsif (($type eq "macosx")) + { $aout=1; $macosx=1; require "x86gas.pl"; } + elsif (($type eq "android")) + { $elf=1; $android=1; require "x86gas.pl"; } + else + { print STDERR <<"EOF"; +Pick one target type from + elf - Linux, FreeBSD, Solaris x86, etc. + a.out - DJGPP, elder OpenBSD, etc. + coff - GAS/COFF such as Win32 targets + win32n - Windows 95/Windows NT NASM format + nw-nasm - NetWare NASM format + macosx - Mac OS X +EOF + exit(1); + } + + $pic=0; + for (@ARGV) { $pic=1 if (/\-[fK]PIC/i); } + + $filename =~ s/\.pl$//; + &file($filename); +} + +sub ::hidden {} + +1; diff --git a/TMessagesProj/jni/boringssl/crypto/perlasm/x86gas.pl b/TMessagesProj/jni/boringssl/crypto/perlasm/x86gas.pl new file mode 100644 index 00000000..99d7c1bd --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/perlasm/x86gas.pl @@ -0,0 +1,263 @@ +#!/usr/bin/env perl + +package x86gas; + +*out=\@::out; + +$::lbdecor=$::aout?"L":".L"; # local label decoration +$nmdecor=($::aout or $::coff)?"_":""; # external name decoration + +$initseg=""; + +$align=16; +$align=log($align)/log(2) if ($::aout); +$com_start="#" if ($::aout or $::coff); + +sub opsize() +{ my $reg=shift; + if ($reg =~ m/^%e/o) { "l"; } + elsif ($reg =~ m/^%[a-d][hl]$/o) { "b"; } + elsif ($reg =~ m/^%[xm]/o) { undef; } + else { "w"; } +} + +# swap arguments; +# expand opcode with size suffix; +# prefix numeric constants with $; +sub ::generic +{ my($opcode,@arg)=@_; + my($suffix,$dst,$src); + + @arg=reverse(@arg); + + for (@arg) + { s/^(\*?)(e?[a-dsixphl]{2})$/$1%$2/o; # gp registers + s/^([xy]?mm[0-7])$/%$1/o; # xmm/mmx registers + s/^(\-?[0-9]+)$/\$$1/o; # constants + s/^(\-?0x[0-9a-f]+)$/\$$1/o; # constants + } + + $dst = $arg[$#arg] if ($#arg>=0); + $src = $arg[$#arg-1] if ($#arg>=1); + if ($dst =~ m/^%/o) { $suffix=&opsize($dst); } + elsif ($src =~ m/^%/o) { $suffix=&opsize($src); } + else { $suffix="l"; } + undef $suffix if ($dst =~ m/^%[xm]/o || $src =~ m/^%[xm]/o); + + if ($#_==0) { &::emit($opcode); } + elsif ($#_==1 && $opcode =~ m/^(call|clflush|j|loop|set)/o) + { &::emit($opcode,@arg); } + else { &::emit($opcode.$suffix,@arg);} + + 1; +} +# +# opcodes not covered by ::generic above, mostly inconsistent namings... +# +sub ::movzx { &::movzb(@_); } +sub ::pushfd { &::pushfl; } +sub ::popfd { &::popfl; } +sub ::cpuid { &::emit(".byte\t0x0f,0xa2"); } +sub ::rdtsc { &::emit(".byte\t0x0f,0x31"); } + +sub ::call { &::emit("call",(&::islabel($_[0]) or "$nmdecor$_[0]")); } +sub ::call_ptr { &::generic("call","*$_[0]"); } +sub ::jmp_ptr { &::generic("jmp","*$_[0]"); } + +*::bswap = sub { &::emit("bswap","%$_[0]"); } if (!$::i386); + +sub ::DWP +{ my($addr,$reg1,$reg2,$idx)=@_; + my $ret=""; + + if (!defined($idx) && 1*$reg2) { $idx=$reg2; $reg2=$reg1; undef $reg1; } + + $addr =~ s/^\s+//; + # prepend global references with optional underscore + $addr =~ s/^([^\+\-0-9][^\+\-]*)/&::islabel($1) or "$nmdecor$1"/ige; + + $reg1 = "%$reg1" if ($reg1); + $reg2 = "%$reg2" if ($reg2); + + $ret .= $addr if (($addr ne "") && ($addr ne 0)); + + if ($reg2) + { $idx!= 0 or $idx=1; + $ret .= "($reg1,$reg2,$idx)"; + } + elsif ($reg1) + { $ret .= "($reg1)"; } + + $ret; +} +sub ::QWP { &::DWP(@_); } +sub ::BP { &::DWP(@_); } +sub ::WP { &::DWP(@_); } +sub ::BC { @_; } +sub ::DWC { @_; } + +sub ::file +{ push(@out,".file\t\"$_[0].S\"\n.text\n"); } + +sub ::function_begin_B +{ my $func=shift; + my $global=($func !~ /^_/); + my $begin="${::lbdecor}_${func}_begin"; + + &::LABEL($func,$global?"$begin":"$nmdecor$func"); + $func=$nmdecor.$func; + + push(@out,".globl\t$func\n") if ($global); + if ($::macosx) { + push(@out,".private_extern\t$func\n"); + } else { + push(@out,".hidden\t$func\n"); + } + if ($::coff) + { push(@out,".def\t$func;\t.scl\t".(3-$global).";\t.type\t32;\t.endef\n"); } + elsif (($::aout and !$::pic) or $::macosx) + { } + else + { push(@out,".type $func,\@function\n"); } + push(@out,".align\t$align\n"); + push(@out,"$func:\n"); + push(@out,"$begin:\n") if ($global); + $::stack=4; +} + +sub ::function_end_B +{ my $func=shift; + push(@out,".size\t$nmdecor$func,.-".&::LABEL($func)."\n") if ($::elf); + $::stack=0; + &::wipe_labels(); +} + +sub ::comment + { + if (!defined($com_start) or $::elf) + { # Regarding $::elf above... + # GNU and SVR4 as'es use different comment delimiters, + push(@out,"\n"); # so we just skip ELF comments... + return; + } + foreach (@_) + { + if (/^\s*$/) + { push(@out,"\n"); } + else + { push(@out,"\t$com_start $_ $com_end\n"); } + } + } + +sub ::external_label +{ foreach(@_) { &::LABEL($_,$nmdecor.$_); } } + +sub ::public_label +{ push(@out,".globl\t".&::LABEL($_[0],$nmdecor.$_[0])."\n"); } + +sub ::file_end +{ if ($::macosx) + { if (%non_lazy_ptr) + { push(@out,".section __IMPORT,__pointers,non_lazy_symbol_pointers\n"); + foreach $i (keys %non_lazy_ptr) + { push(@out,"$non_lazy_ptr{$i}:\n.indirect_symbol\t$i\n.long\t0\n"); } + } + } + if (0 && grep {/\b${nmdecor}OPENSSL_ia32cap_P\b/i} @out) { + my $tmp=".comm\t${nmdecor}OPENSSL_ia32cap_P,16"; + if ($::macosx) { push (@out,"$tmp,2\n"); } + elsif ($::elf) { push (@out,"$tmp,4\n"); } + else { push (@out,"$tmp\n"); } + } + push(@out,$initseg) if ($initseg); +} + +sub ::data_byte { push(@out,".byte\t".join(',',@_)."\n"); } +sub ::data_short{ push(@out,".value\t".join(',',@_)."\n"); } +sub ::data_word { push(@out,".long\t".join(',',@_)."\n"); } + +sub ::align +{ my $val=$_[0]; + if ($::aout) + { $val=int(log($val)/log(2)); + $val.=",0x90"; + } + push(@out,".align\t$val\n"); +} + +sub ::picmeup +{ my($dst,$sym,$base,$reflabel)=@_; + + if (($::pic && ($::elf || $::aout)) || $::macosx) + { if (!defined($base)) + { &::call(&::label("PIC_me_up")); + &::set_label("PIC_me_up"); + &::blindpop($dst); + $base=$dst; + $reflabel=&::label("PIC_me_up"); + } + if ($::macosx) + { my $indirect=&::static_label("$nmdecor$sym\$non_lazy_ptr"); + &::mov($dst,&::DWP("$indirect-$reflabel",$base)); + $non_lazy_ptr{"$nmdecor$sym"}=$indirect; + } + elsif ($sym eq "OPENSSL_ia32cap_P" && $::elf>0) + { &::lea($dst,&::DWP("$sym-$reflabel",$base)); } + else + { &::lea($dst,&::DWP("_GLOBAL_OFFSET_TABLE_+[.-$reflabel]", + $base)); + &::mov($dst,&::DWP("$sym\@GOT",$dst)); + } + } + else + { &::lea($dst,&::DWP($sym)); } +} + +sub ::initseg +{ my $f=$nmdecor.shift; + + if ($::android) + { $initseg.=<<___; +.section .init_array +.align 4 +.long $f +___ + } + elsif ($::elf) + { $initseg.=<<___; +.section .init + call $f +___ + } + elsif ($::coff) + { $initseg.=<<___; # applies to both Cygwin and Mingw +.section .ctors +.long $f +___ + } + elsif ($::macosx) + { $initseg.=<<___; +.mod_init_func +.align 2 +.long $f +___ + } + elsif ($::aout) + { my $ctor="${nmdecor}_GLOBAL_\$I\$$f"; + $initseg.=".text\n"; + $initseg.=".type $ctor,\@function\n" if ($::pic); + $initseg.=<<___; # OpenBSD way... +.globl $ctor +.align 2 +$ctor: + jmp $f +___ + } +} + +sub ::dataseg +{ push(@out,".data\n"); } + +*::hidden = sub { push(@out,".hidden\t$nmdecor$_[0]\n"); } if ($::elf); + +1; diff --git a/TMessagesProj/jni/boringssl/crypto/perlasm/x86masm.pl b/TMessagesProj/jni/boringssl/crypto/perlasm/x86masm.pl new file mode 100644 index 00000000..b7f49d1c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/perlasm/x86masm.pl @@ -0,0 +1,200 @@ +#!/usr/bin/env perl + +package x86masm; + +*out=\@::out; + +$::lbdecor="\$L"; # local label decoration +$nmdecor="_"; # external name decoration + +$initseg=""; +$segment=""; + +sub ::generic +{ my ($opcode,@arg)=@_; + + # fix hexadecimal constants + for (@arg) { s/(?= 0x02030000\n"); + push(@out,"safeseh ".&::LABEL($nm,$nmdecor.$nm)."\n"); + push(@out,"%endif\n"); +} + +1; diff --git a/TMessagesProj/jni/boringssl/crypto/pkcs8/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/pkcs8/CMakeLists.txt new file mode 100644 index 00000000..4bc2e9bd --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pkcs8/CMakeLists.txt @@ -0,0 +1,12 @@ +include_directories(. .. ../../include) + +add_library( + pkcs8 + + OBJECT + + pkcs8.c + p8_pkey.c + p5_pbe.c + p5_pbev2.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/pkcs8/internal.h b/TMessagesProj/jni/boringssl/crypto/pkcs8/internal.h new file mode 100644 index 00000000..44ca4f7b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pkcs8/internal.h @@ -0,0 +1,74 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_PKCS8_INTERNAL_H +#define OPENSSL_HEADER_PKCS8_INTERNAL_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#define PKCS5_DEFAULT_ITERATIONS 2048 +#define PKCS5_SALT_LEN 8 + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_PKCS8_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/pkcs8/p5_pbe.c b/TMessagesProj/jni/boringssl/crypto/pkcs8/p5_pbe.c new file mode 100644 index 00000000..653cabf3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pkcs8/p5_pbe.c @@ -0,0 +1,150 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include + +#include "internal.h" + + +/* PKCS#5 password based encryption structure */ + +ASN1_SEQUENCE(PBEPARAM) = { + ASN1_SIMPLE(PBEPARAM, salt, ASN1_OCTET_STRING), + ASN1_SIMPLE(PBEPARAM, iter, ASN1_INTEGER) +} ASN1_SEQUENCE_END(PBEPARAM) + +IMPLEMENT_ASN1_FUNCTIONS(PBEPARAM) + + +/* Set an algorithm identifier for a PKCS#5 PBE algorithm */ + +int PKCS5_pbe_set0_algor(X509_ALGOR *algor, int alg, int iter, + const unsigned char *salt, int saltlen) + { + PBEPARAM *pbe=NULL; + ASN1_STRING *pbe_str=NULL; + unsigned char *sstr; + + pbe = PBEPARAM_new(); + if (!pbe) + { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + goto err; + } + if(iter <= 0) + iter = PKCS5_DEFAULT_ITERATIONS; + if (!ASN1_INTEGER_set(pbe->iter, iter)) + { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!saltlen) + saltlen = PKCS5_SALT_LEN; + if (!ASN1_STRING_set(pbe->salt, NULL, saltlen)) + { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + goto err; + } + sstr = ASN1_STRING_data(pbe->salt); + if (salt) + memcpy(sstr, salt, saltlen); + else if (!RAND_bytes(sstr, saltlen)) + goto err; + + if(!ASN1_item_pack(pbe, ASN1_ITEM_rptr(PBEPARAM), &pbe_str)) + { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + goto err; + } + + PBEPARAM_free(pbe); + pbe = NULL; + + if (X509_ALGOR_set0(algor, OBJ_nid2obj(alg), V_ASN1_SEQUENCE, pbe_str)) + return 1; + +err: + if (pbe != NULL) + PBEPARAM_free(pbe); + if (pbe_str != NULL) + ASN1_STRING_free(pbe_str); + return 0; + } + +/* Return an algorithm identifier for a PKCS#5 PBE algorithm */ + +X509_ALGOR *PKCS5_pbe_set(int alg, int iter, + const unsigned char *salt, int saltlen) + { + X509_ALGOR *ret; + ret = X509_ALGOR_new(); + if (!ret) + { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if (PKCS5_pbe_set0_algor(ret, alg, iter, salt, saltlen)) + return ret; + + X509_ALGOR_free(ret); + return NULL; + } diff --git a/TMessagesProj/jni/boringssl/crypto/pkcs8/p5_pbev2.c b/TMessagesProj/jni/boringssl/crypto/pkcs8/p5_pbev2.c new file mode 100644 index 00000000..beeb3364 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pkcs8/p5_pbev2.c @@ -0,0 +1,303 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999-2004. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +/* PKCS#5 v2.0 password based encryption structures */ + +ASN1_SEQUENCE(PBE2PARAM) = { + ASN1_SIMPLE(PBE2PARAM, keyfunc, X509_ALGOR), + ASN1_SIMPLE(PBE2PARAM, encryption, X509_ALGOR) +} ASN1_SEQUENCE_END(PBE2PARAM) + +IMPLEMENT_ASN1_FUNCTIONS(PBE2PARAM) + +ASN1_SEQUENCE(PBKDF2PARAM) = { + ASN1_SIMPLE(PBKDF2PARAM, salt, ASN1_ANY), + ASN1_SIMPLE(PBKDF2PARAM, iter, ASN1_INTEGER), + ASN1_OPT(PBKDF2PARAM, keylength, ASN1_INTEGER), + ASN1_OPT(PBKDF2PARAM, prf, X509_ALGOR) +} ASN1_SEQUENCE_END(PBKDF2PARAM) + +IMPLEMENT_ASN1_FUNCTIONS(PBKDF2PARAM); + +static int ASN1_TYPE_set_octetstring(ASN1_TYPE *a, unsigned char *data, int len) + { + ASN1_STRING *os; + + if ((os=M_ASN1_OCTET_STRING_new()) == NULL) return(0); + if (!M_ASN1_OCTET_STRING_set(os,data,len)) + { + M_ASN1_OCTET_STRING_free(os); + return 0; + } + ASN1_TYPE_set(a,V_ASN1_OCTET_STRING,os); + return(1); + } + +static int param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type) + { + unsigned iv_len; + + iv_len = EVP_CIPHER_CTX_iv_length(c); + return ASN1_TYPE_set_octetstring(type, c->oiv, iv_len); + } + +/* Return an algorithm identifier for a PKCS#5 v2.0 PBE algorithm: + * yes I know this is horrible! + * + * Extended version to allow application supplied PRF NID and IV. */ + +X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter, + unsigned char *salt, int saltlen, + unsigned char *aiv, int prf_nid) +{ + X509_ALGOR *scheme = NULL, *kalg = NULL, *ret = NULL; + int alg_nid, keylen; + EVP_CIPHER_CTX ctx; + unsigned char iv[EVP_MAX_IV_LENGTH]; + PBE2PARAM *pbe2 = NULL; + const ASN1_OBJECT *obj; + + alg_nid = EVP_CIPHER_nid(cipher); + if(alg_nid == NID_undef) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER); + goto err; + } + obj = OBJ_nid2obj(alg_nid); + + if(!(pbe2 = PBE2PARAM_new())) goto merr; + + /* Setup the AlgorithmIdentifier for the encryption scheme */ + scheme = pbe2->encryption; + + scheme->algorithm = (ASN1_OBJECT*) obj; + if(!(scheme->parameter = ASN1_TYPE_new())) goto merr; + + /* Create random IV */ + if (EVP_CIPHER_iv_length(cipher)) + { + if (aiv) + memcpy(iv, aiv, EVP_CIPHER_iv_length(cipher)); + else if (!RAND_bytes(iv, EVP_CIPHER_iv_length(cipher))) + goto err; + } + + EVP_CIPHER_CTX_init(&ctx); + + /* Dummy cipherinit to just setup the IV, and PRF */ + if (!EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, iv, 0)) + goto err; + if(param_to_asn1(&ctx, scheme->parameter) < 0) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS); + EVP_CIPHER_CTX_cleanup(&ctx); + goto err; + } + /* If prf NID unspecified see if cipher has a preference. + * An error is OK here: just means use default PRF. + */ + if ((prf_nid == -1) && + EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_PBE_PRF_NID, 0, &prf_nid) <= 0) + { + ERR_clear_error(); + prf_nid = NID_hmacWithSHA1; + } + EVP_CIPHER_CTX_cleanup(&ctx); + + /* If its RC2 then we'd better setup the key length */ + + if(alg_nid == NID_rc2_cbc) + keylen = EVP_CIPHER_key_length(cipher); + else + keylen = -1; + + /* Setup keyfunc */ + + X509_ALGOR_free(pbe2->keyfunc); + + pbe2->keyfunc = PKCS5_pbkdf2_set(iter, salt, saltlen, prf_nid, keylen); + + if (!pbe2->keyfunc) + goto merr; + + /* Now set up top level AlgorithmIdentifier */ + + if(!(ret = X509_ALGOR_new())) goto merr; + if(!(ret->parameter = ASN1_TYPE_new())) goto merr; + + ret->algorithm = (ASN1_OBJECT*) OBJ_nid2obj(NID_pbes2); + + /* Encode PBE2PARAM into parameter */ + + if(!ASN1_item_pack(pbe2, ASN1_ITEM_rptr(PBE2PARAM), + &ret->parameter->value.sequence)) goto merr; + ret->parameter->type = V_ASN1_SEQUENCE; + + PBE2PARAM_free(pbe2); + pbe2 = NULL; + + return ret; + + merr: + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + + err: + PBE2PARAM_free(pbe2); + /* Note 'scheme' is freed as part of pbe2 */ + X509_ALGOR_free(kalg); + X509_ALGOR_free(ret); + + return NULL; + +} + +X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter, + unsigned char *salt, int saltlen) + { + return PKCS5_pbe2_set_iv(cipher, iter, salt, saltlen, NULL, -1); + } + +X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen, + int prf_nid, int keylen) + { + X509_ALGOR *keyfunc = NULL; + PBKDF2PARAM *kdf = NULL; + ASN1_OCTET_STRING *osalt = NULL; + + if(!(kdf = PBKDF2PARAM_new())) + goto merr; + if(!(osalt = M_ASN1_OCTET_STRING_new())) + goto merr; + + kdf->salt->value.octet_string = osalt; + kdf->salt->type = V_ASN1_OCTET_STRING; + + if (!saltlen) + saltlen = PKCS5_SALT_LEN; + if (!(osalt->data = OPENSSL_malloc (saltlen))) + goto merr; + + osalt->length = saltlen; + + if (salt) + memcpy (osalt->data, salt, saltlen); + else if (!RAND_bytes(osalt->data, saltlen)) + goto merr; + + if(iter <= 0) + iter = PKCS5_DEFAULT_ITERATIONS; + + if(!ASN1_INTEGER_set(kdf->iter, iter)) + goto merr; + + /* If have a key len set it up */ + + if(keylen > 0) + { + if(!(kdf->keylength = M_ASN1_INTEGER_new())) + goto merr; + if(!ASN1_INTEGER_set (kdf->keylength, keylen)) + goto merr; + } + + /* prf can stay NULL if we are using hmacWithSHA1 */ + if (prf_nid > 0 && prf_nid != NID_hmacWithSHA1) + { + kdf->prf = X509_ALGOR_new(); + if (!kdf->prf) + goto merr; + X509_ALGOR_set0(kdf->prf, OBJ_nid2obj(prf_nid), + V_ASN1_NULL, NULL); + } + + /* Finally setup the keyfunc structure */ + + keyfunc = X509_ALGOR_new(); + if (!keyfunc) + goto merr; + + keyfunc->algorithm = (ASN1_OBJECT*) OBJ_nid2obj(NID_id_pbkdf2); + + /* Encode PBKDF2PARAM into parameter of pbe2 */ + + if(!(keyfunc->parameter = ASN1_TYPE_new())) + goto merr; + + if(!ASN1_item_pack(kdf, ASN1_ITEM_rptr(PBKDF2PARAM), + &keyfunc->parameter->value.sequence)) + goto merr; + keyfunc->parameter->type = V_ASN1_SEQUENCE; + + PBKDF2PARAM_free(kdf); + return keyfunc; + + merr: + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + PBKDF2PARAM_free(kdf); + X509_ALGOR_free(keyfunc); + return NULL; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/pkcs8/p8_pkey.c b/TMessagesProj/jni/boringssl/crypto/pkcs8/p8_pkey.c new file mode 100644 index 00000000..bd9d30ca --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pkcs8/p8_pkey.c @@ -0,0 +1,85 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include + +#include +#include +#include + +/* Minor tweak to operation: zero private key data */ +static int pkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) { + /* Since the structure must still be valid use ASN1_OP_FREE_PRE */ + if (operation == ASN1_OP_FREE_PRE) { + PKCS8_PRIV_KEY_INFO *key = (PKCS8_PRIV_KEY_INFO *)*pval; + if (key->pkey && + key->pkey->value.octet_string) { + OPENSSL_cleanse(key->pkey->value.octet_string->data, + key->pkey->value.octet_string->length); + } + } + return 1; +} + +ASN1_SEQUENCE_cb(PKCS8_PRIV_KEY_INFO, pkey_cb) = { + ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, version, ASN1_INTEGER), + ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkeyalg, X509_ALGOR), + ASN1_SIMPLE(PKCS8_PRIV_KEY_INFO, pkey, ASN1_ANY), + ASN1_IMP_SET_OF_OPT(PKCS8_PRIV_KEY_INFO, attributes, X509_ATTRIBUTE, 0) +} ASN1_SEQUENCE_END_cb(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO); + +IMPLEMENT_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO); diff --git a/TMessagesProj/jni/boringssl/crypto/pkcs8/pkcs8.c b/TMessagesProj/jni/boringssl/crypto/pkcs8/pkcs8.c new file mode 100644 index 00000000..8ac203df --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/pkcs8/pkcs8.c @@ -0,0 +1,1141 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../bytestring/internal.h" +#include "../evp/internal.h" + + +#define PKCS12_KEY_ID 1 +#define PKCS12_IV_ID 2 +#define PKCS12_MAC_ID 3 + +static int ascii_to_ucs2(const char *ascii, size_t ascii_len, + uint8_t **out, size_t *out_len) { + uint8_t *unitmp; + size_t ulen, i; + + ulen = ascii_len * 2 + 2; + if (ulen < ascii_len) { + return 0; + } + unitmp = OPENSSL_malloc(ulen); + if (unitmp == NULL) { + return 0; + } + for (i = 0; i < ulen - 2; i += 2) { + unitmp[i] = 0; + unitmp[i + 1] = ascii[i >> 1]; + } + + /* Make result double null terminated */ + unitmp[ulen - 2] = 0; + unitmp[ulen - 1] = 0; + *out_len = ulen; + *out = unitmp; + return 1; +} + +static int pkcs12_key_gen_raw(const uint8_t *pass_raw, size_t pass_raw_len, + const uint8_t *salt, size_t salt_len, + int id, int iterations, + size_t out_len, uint8_t *out, + const EVP_MD *md_type) { + uint8_t *B, *D, *I, *p, *Ai; + int Slen, Plen, Ilen, Ijlen; + int i, j, v; + size_t u; + int ret = 0; + BIGNUM *Ij, *Bpl1; /* These hold Ij and B + 1 */ + EVP_MD_CTX ctx; + + EVP_MD_CTX_init(&ctx); + v = EVP_MD_block_size(md_type); + u = EVP_MD_size(md_type); + D = OPENSSL_malloc(v); + Ai = OPENSSL_malloc(u); + B = OPENSSL_malloc(v + 1); + Slen = v * ((salt_len + v - 1) / v); + if (pass_raw_len) { + Plen = v * ((pass_raw_len + v - 1) / v); + } else { + Plen = 0; + } + Ilen = Slen + Plen; + I = OPENSSL_malloc(Ilen); + Ij = BN_new(); + Bpl1 = BN_new(); + if (!D || !Ai || !B || !I || !Ij || !Bpl1) { + goto err; + } + for (i = 0; i < v; i++) { + D[i] = id; + } + p = I; + for (i = 0; i < Slen; i++) { + *p++ = salt[i % salt_len]; + } + for (i = 0; i < Plen; i++) { + *p++ = pass_raw[i % pass_raw_len]; + } + for (;;) { + if (!EVP_DigestInit_ex(&ctx, md_type, NULL) || + !EVP_DigestUpdate(&ctx, D, v) || + !EVP_DigestUpdate(&ctx, I, Ilen) || + !EVP_DigestFinal_ex(&ctx, Ai, NULL)) { + goto err; + } + for (j = 1; j < iterations; j++) { + if (!EVP_DigestInit_ex(&ctx, md_type, NULL) || + !EVP_DigestUpdate(&ctx, Ai, u) || + !EVP_DigestFinal_ex(&ctx, Ai, NULL)) { + goto err; + } + } + memcpy(out, Ai, out_len < u ? out_len : u); + if (u >= out_len) { + ret = 1; + goto end; + } + out_len -= u; + out += u; + for (j = 0; j < v; j++) { + B[j] = Ai[j % u]; + } + /* Work out B + 1 first then can use B as tmp space */ + if (!BN_bin2bn(B, v, Bpl1) || + !BN_add_word(Bpl1, 1)) { + goto err; + } + for (j = 0; j < Ilen; j += v) { + if (!BN_bin2bn(I + j, v, Ij) || + !BN_add(Ij, Ij, Bpl1) || + !BN_bn2bin(Ij, B)) { + goto err; + } + Ijlen = BN_num_bytes(Ij); + /* If more than 2^(v*8) - 1 cut off MSB */ + if (Ijlen > v) { + if (!BN_bn2bin(Ij, B)) { + goto err; + } + memcpy(I + j, B + 1, v); + /* If less than v bytes pad with zeroes */ + } else if (Ijlen < v) { + memset(I + j, 0, v - Ijlen); + if (!BN_bn2bin(Ij, I + j + v - Ijlen)) { + goto err; + } + } else if (!BN_bn2bin(Ij, I + j)) { + goto err; + } + } + } + +err: + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + +end: + OPENSSL_free(Ai); + OPENSSL_free(B); + OPENSSL_free(D); + OPENSSL_free(I); + BN_free(Ij); + BN_free(Bpl1); + EVP_MD_CTX_cleanup(&ctx); + + return ret; +} + +static int pkcs12_pbe_keyivgen(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw, + size_t pass_raw_len, ASN1_TYPE *param, + const EVP_CIPHER *cipher, const EVP_MD *md, + int is_encrypt) { + PBEPARAM *pbe; + int salt_len, iterations, ret; + uint8_t *salt; + const uint8_t *pbuf; + uint8_t key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH]; + + /* Extract useful info from parameter */ + if (param == NULL || param->type != V_ASN1_SEQUENCE || + param->value.sequence == NULL) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + return 0; + } + + pbuf = param->value.sequence->data; + pbe = d2i_PBEPARAM(NULL, &pbuf, param->value.sequence->length); + if (pbe == NULL) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + return 0; + } + + if (!pbe->iter) { + iterations = 1; + } else { + iterations = ASN1_INTEGER_get(pbe->iter); + } + salt = pbe->salt->data; + salt_len = pbe->salt->length; + if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt, salt_len, PKCS12_KEY_ID, + iterations, EVP_CIPHER_key_length(cipher), key, md)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEY_GEN_ERROR); + PBEPARAM_free(pbe); + return 0; + } + if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt, salt_len, PKCS12_IV_ID, + iterations, EVP_CIPHER_iv_length(cipher), iv, md)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEY_GEN_ERROR); + PBEPARAM_free(pbe); + return 0; + } + PBEPARAM_free(pbe); + ret = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, is_encrypt); + OPENSSL_cleanse(key, EVP_MAX_KEY_LENGTH); + OPENSSL_cleanse(iv, EVP_MAX_IV_LENGTH); + return ret; +} + +typedef int (*keygen_func)(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw, + size_t pass_raw_len, ASN1_TYPE *param, + const EVP_CIPHER *cipher, const EVP_MD *md, + int is_encrypt); + +struct pbe_suite { + int pbe_nid; + const EVP_CIPHER* (*cipher_func)(void); + const EVP_MD* (*md_func)(void); + keygen_func keygen; +}; + +static const struct pbe_suite kBuiltinPBE[] = { + { + NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc, EVP_sha1, pkcs12_pbe_keyivgen, + }, + { + NID_pbe_WithSHA1And128BitRC4, EVP_rc4, EVP_sha1, pkcs12_pbe_keyivgen, + }, + { + NID_pbe_WithSHA1And3_Key_TripleDES_CBC, EVP_des_ede3_cbc, EVP_sha1, + pkcs12_pbe_keyivgen, + }, +}; + +static int pbe_cipher_init(ASN1_OBJECT *pbe_obj, + const uint8_t *pass_raw, size_t pass_raw_len, + ASN1_TYPE *param, + EVP_CIPHER_CTX *ctx, int is_encrypt) { + const EVP_CIPHER *cipher; + const EVP_MD *md; + unsigned i; + + const struct pbe_suite *suite = NULL; + const int pbe_nid = OBJ_obj2nid(pbe_obj); + + for (i = 0; i < sizeof(kBuiltinPBE) / sizeof(struct pbe_suite); i++) { + if (kBuiltinPBE[i].pbe_nid == pbe_nid) { + suite = &kBuiltinPBE[i]; + break; + } + } + + if (suite == NULL) { + char obj_str[80]; + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_ALGORITHM); + if (!pbe_obj) { + strncpy(obj_str, "NULL", sizeof(obj_str)); + } else { + i2t_ASN1_OBJECT(obj_str, sizeof(obj_str), pbe_obj); + } + ERR_add_error_data(2, "TYPE=", obj_str); + return 0; + } + + if (suite->cipher_func == NULL) { + cipher = NULL; + } else { + cipher = suite->cipher_func(); + if (!cipher) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_CIPHER); + return 0; + } + } + + if (suite->md_func == NULL) { + md = NULL; + } else { + md = suite->md_func(); + if (!md) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_DIGEST); + return 0; + } + } + + if (!suite->keygen(ctx, pass_raw, pass_raw_len, param, cipher, md, + is_encrypt)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEYGEN_FAILURE); + return 0; + } + + return 1; +} + +static int pbe_crypt(const X509_ALGOR *algor, + const uint8_t *pass_raw, size_t pass_raw_len, + const uint8_t *in, size_t in_len, + uint8_t **out, size_t *out_len, + int is_encrypt) { + uint8_t *buf; + int n, ret = 0; + EVP_CIPHER_CTX ctx; + unsigned block_size; + + EVP_CIPHER_CTX_init(&ctx); + + if (!pbe_cipher_init(algor->algorithm, pass_raw, pass_raw_len, + algor->parameter, &ctx, is_encrypt)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_CIPHER_ALGORITHM); + return 0; + } + block_size = EVP_CIPHER_CTX_block_size(&ctx); + + if (in_len + block_size < in_len) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_TOO_LONG); + goto err; + } + + buf = OPENSSL_malloc(in_len + block_size); + if (buf == NULL) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EVP_CipherUpdate(&ctx, buf, &n, in, in_len)) { + OPENSSL_free(buf); + OPENSSL_PUT_ERROR(PKCS8, ERR_R_EVP_LIB); + goto err; + } + *out_len = n; + + if (!EVP_CipherFinal_ex(&ctx, buf + n, &n)) { + OPENSSL_free(buf); + OPENSSL_PUT_ERROR(PKCS8, ERR_R_EVP_LIB); + goto err; + } + *out_len += n; + *out = buf; + ret = 1; + +err: + EVP_CIPHER_CTX_cleanup(&ctx); + return ret; +} + +static void *pkcs12_item_decrypt_d2i(X509_ALGOR *algor, const ASN1_ITEM *it, + const uint8_t *pass_raw, + size_t pass_raw_len, + ASN1_OCTET_STRING *oct) { + uint8_t *out; + const uint8_t *p; + void *ret; + size_t out_len; + + if (!pbe_crypt(algor, pass_raw, pass_raw_len, oct->data, oct->length, + &out, &out_len, 0 /* decrypt */)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_CRYPT_ERROR); + return NULL; + } + p = out; + ret = ASN1_item_d2i(NULL, &p, out_len, it); + OPENSSL_cleanse(out, out_len); + if (!ret) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + } + OPENSSL_free(out); + return ret; +} + +PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, const char *pass, + int pass_len) { + uint8_t *pass_raw = NULL; + size_t pass_raw_len = 0; + PKCS8_PRIV_KEY_INFO *ret; + + if (pass) { + if (pass_len == -1) { + pass_len = strlen(pass); + } + if (!ascii_to_ucs2(pass, pass_len, &pass_raw, &pass_raw_len)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + return NULL; + } + } + + ret = PKCS8_decrypt_pbe(pkcs8, pass_raw, pass_raw_len); + + if (pass_raw) { + OPENSSL_cleanse(pass_raw, pass_raw_len); + OPENSSL_free(pass_raw); + } + return ret; +} + +PKCS8_PRIV_KEY_INFO *PKCS8_decrypt_pbe(X509_SIG *pkcs8, const uint8_t *pass_raw, + size_t pass_raw_len) { + return pkcs12_item_decrypt_d2i(pkcs8->algor, + ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), pass_raw, + pass_raw_len, pkcs8->digest); +} + +static ASN1_OCTET_STRING *pkcs12_item_i2d_encrypt(X509_ALGOR *algor, + const ASN1_ITEM *it, + const uint8_t *pass_raw, + size_t pass_raw_len, void *obj) { + ASN1_OCTET_STRING *oct; + uint8_t *in = NULL; + int in_len; + size_t crypt_len; + + oct = M_ASN1_OCTET_STRING_new(); + if (oct == NULL) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + return NULL; + } + in_len = ASN1_item_i2d(obj, &in, it); + if (!in) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCODE_ERROR); + return NULL; + } + if (!pbe_crypt(algor, pass_raw, pass_raw_len, in, in_len, &oct->data, &crypt_len, + 1 /* encrypt */)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCRYPT_ERROR); + OPENSSL_free(in); + return NULL; + } + oct->length = crypt_len; + OPENSSL_cleanse(in, in_len); + OPENSSL_free(in); + return oct; +} + +X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, const char *pass, + int pass_len, uint8_t *salt, size_t salt_len, + int iterations, PKCS8_PRIV_KEY_INFO *p8inf) { + uint8_t *pass_raw = NULL; + size_t pass_raw_len = 0; + X509_SIG *ret; + + if (pass) { + if (pass_len == -1) { + pass_len = strlen(pass); + } + if (!ascii_to_ucs2(pass, pass_len, &pass_raw, &pass_raw_len)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + return NULL; + } + } + + ret = PKCS8_encrypt_pbe(pbe_nid, pass_raw, pass_raw_len, + salt, salt_len, iterations, p8inf); + + if (pass_raw) { + OPENSSL_cleanse(pass_raw, pass_raw_len); + OPENSSL_free(pass_raw); + } + return ret; +} + +X509_SIG *PKCS8_encrypt_pbe(int pbe_nid, + const uint8_t *pass_raw, size_t pass_raw_len, + uint8_t *salt, size_t salt_len, + int iterations, PKCS8_PRIV_KEY_INFO *p8inf) { + X509_SIG *pkcs8 = NULL; + X509_ALGOR *pbe; + + pkcs8 = X509_SIG_new(); + if (pkcs8 == NULL) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + goto err; + } + + pbe = PKCS5_pbe_set(pbe_nid, iterations, salt, salt_len); + if (!pbe) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_ASN1_LIB); + goto err; + } + + X509_ALGOR_free(pkcs8->algor); + pkcs8->algor = pbe; + M_ASN1_OCTET_STRING_free(pkcs8->digest); + pkcs8->digest = pkcs12_item_i2d_encrypt( + pbe, ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), pass_raw, pass_raw_len, p8inf); + if (!pkcs8->digest) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCRYPT_ERROR); + goto err; + } + + return pkcs8; + +err: + X509_SIG_free(pkcs8); + return NULL; +} + +EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8) { + EVP_PKEY *pkey = NULL; + ASN1_OBJECT *algoid; + char obj_tmp[80]; + + if (!PKCS8_pkey_get0(&algoid, NULL, NULL, NULL, p8)) { + return NULL; + } + + pkey = EVP_PKEY_new(); + if (pkey == NULL) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(algoid))) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM); + i2t_ASN1_OBJECT(obj_tmp, 80, algoid); + ERR_add_error_data(2, "TYPE=", obj_tmp); + goto error; + } + + if (pkey->ameth->priv_decode) { + if (!pkey->ameth->priv_decode(pkey, p8)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PRIVATE_KEY_DECODE_ERROR); + goto error; + } + } else { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_METHOD_NOT_SUPPORTED); + goto error; + } + + return pkey; + +error: + EVP_PKEY_free(pkey); + return NULL; +} + +PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey) { + PKCS8_PRIV_KEY_INFO *p8; + + p8 = PKCS8_PRIV_KEY_INFO_new(); + if (p8 == NULL) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + return NULL; + } + p8->broken = PKCS8_OK; + + if (pkey->ameth) { + if (pkey->ameth->priv_encode) { + if (!pkey->ameth->priv_encode(p8, pkey)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PRIVATE_KEY_ENCODE_ERROR); + goto error; + } + } else { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_METHOD_NOT_SUPPORTED); + goto error; + } + } else { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM); + goto error; + } + return p8; + +error: + PKCS8_PRIV_KEY_INFO_free(p8); + return NULL; +} + +struct pkcs12_context { + EVP_PKEY **out_key; + STACK_OF(X509) *out_certs; + uint8_t *password; + size_t password_len; +}; + +static int PKCS12_handle_content_info(CBS *content_info, unsigned depth, + struct pkcs12_context *ctx); + +/* PKCS12_handle_content_infos parses a series of PKCS#7 ContentInfos in a + * SEQUENCE. */ +static int PKCS12_handle_content_infos(CBS *content_infos, + unsigned depth, + struct pkcs12_context *ctx) { + uint8_t *der_bytes = NULL; + size_t der_len; + CBS in; + int ret = 0; + + /* Generally we only expect depths 0 (the top level, with a + * pkcs7-encryptedData and a pkcs7-data) and depth 1 (the various PKCS#12 + * bags). */ + if (depth > 3) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PKCS12_TOO_DEEPLY_NESTED); + return 0; + } + + /* Although a BER->DER conversion is done at the beginning of |PKCS12_parse|, + * the ASN.1 data gets wrapped in OCTETSTRINGs and/or encrypted and the + * conversion cannot see through those wrappings. So each time we step + * through one we need to convert to DER again. */ + if (!CBS_asn1_ber_to_der(content_infos, &der_bytes, &der_len)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + return 0; + } + + if (der_bytes != NULL) { + CBS_init(&in, der_bytes, der_len); + } else { + CBS_init(&in, CBS_data(content_infos), CBS_len(content_infos)); + } + + if (!CBS_get_asn1(&in, &in, CBS_ASN1_SEQUENCE)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + while (CBS_len(&in) > 0) { + CBS content_info; + if (!CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + if (!PKCS12_handle_content_info(&content_info, depth + 1, ctx)) { + goto err; + } + } + + /* NSS includes additional data after the SEQUENCE, but it's an (unwrapped) + * copy of the same encrypted private key (with the same IV and + * ciphertext)! */ + + ret = 1; + +err: + OPENSSL_free(der_bytes); + return ret; +} + +/* PKCS12_handle_content_info parses a single PKCS#7 ContentInfo element in a + * PKCS#12 structure. */ +static int PKCS12_handle_content_info(CBS *content_info, unsigned depth, + struct pkcs12_context *ctx) { + CBS content_type, wrapped_contents, contents, content_infos; + int nid, ret = 0; + + if (!CBS_get_asn1(content_info, &content_type, CBS_ASN1_OBJECT) || + !CBS_get_asn1(content_info, &wrapped_contents, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + nid = OBJ_cbs2nid(&content_type); + if (nid == NID_pkcs7_encrypted) { + /* See https://tools.ietf.org/html/rfc2315#section-13. + * + * PKCS#7 encrypted data inside a PKCS#12 structure is generally an + * encrypted certificate bag and it's generally encrypted with 40-bit + * RC2-CBC. */ + CBS version_bytes, eci, contents_type, ai, encrypted_contents; + X509_ALGOR *algor = NULL; + const uint8_t *inp; + uint8_t *out; + size_t out_len; + + if (!CBS_get_asn1(&wrapped_contents, &contents, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&contents, &version_bytes, CBS_ASN1_INTEGER) || + /* EncryptedContentInfo, see + * https://tools.ietf.org/html/rfc2315#section-10.1 */ + !CBS_get_asn1(&contents, &eci, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&eci, &contents_type, CBS_ASN1_OBJECT) || + /* AlgorithmIdentifier, see + * https://tools.ietf.org/html/rfc5280#section-4.1.1.2 */ + !CBS_get_asn1_element(&eci, &ai, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&eci, &encrypted_contents, + CBS_ASN1_CONTEXT_SPECIFIC | 0)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + if (OBJ_cbs2nid(&contents_type) != NID_pkcs7_data) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + inp = CBS_data(&ai); + algor = d2i_X509_ALGOR(NULL, &inp, CBS_len(&ai)); + if (algor == NULL) { + goto err; + } + if (inp != CBS_data(&ai) + CBS_len(&ai)) { + X509_ALGOR_free(algor); + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + if (!pbe_crypt(algor, ctx->password, ctx->password_len, + CBS_data(&encrypted_contents), CBS_len(&encrypted_contents), + &out, &out_len, 0 /* decrypt */)) { + X509_ALGOR_free(algor); + goto err; + } + X509_ALGOR_free(algor); + + CBS_init(&content_infos, out, out_len); + ret = PKCS12_handle_content_infos(&content_infos, depth + 1, ctx); + OPENSSL_free(out); + } else if (nid == NID_pkcs7_data) { + CBS octet_string_contents; + + if (!CBS_get_asn1(&wrapped_contents, &octet_string_contents, + CBS_ASN1_OCTETSTRING)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + ret = PKCS12_handle_content_infos(&octet_string_contents, depth + 1, ctx); + } else if (nid == NID_pkcs8ShroudedKeyBag) { + /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section + * 4.2.2. */ + const uint8_t *inp = CBS_data(&wrapped_contents); + PKCS8_PRIV_KEY_INFO *pki = NULL; + X509_SIG *encrypted = NULL; + + if (*ctx->out_key) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12); + goto err; + } + + /* encrypted isn't actually an X.509 signature, but it has the same + * structure as one and so |X509_SIG| is reused to store it. */ + encrypted = d2i_X509_SIG(NULL, &inp, CBS_len(&wrapped_contents)); + if (encrypted == NULL) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + if (inp != CBS_data(&wrapped_contents) + CBS_len(&wrapped_contents)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + X509_SIG_free(encrypted); + goto err; + } + + pki = PKCS8_decrypt_pbe(encrypted, ctx->password, ctx->password_len); + X509_SIG_free(encrypted); + if (pki == NULL) { + goto err; + } + + *ctx->out_key = EVP_PKCS82PKEY(pki); + PKCS8_PRIV_KEY_INFO_free(pki); + + if (ctx->out_key == NULL) { + goto err; + } + ret = 1; + } else if (nid == NID_certBag) { + CBS cert_bag, cert_type, wrapped_cert, cert; + + if (!CBS_get_asn1(&wrapped_contents, &cert_bag, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&cert_bag, &cert_type, CBS_ASN1_OBJECT) || + !CBS_get_asn1(&cert_bag, &wrapped_cert, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || + !CBS_get_asn1(&wrapped_cert, &cert, CBS_ASN1_OCTETSTRING)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + if (OBJ_cbs2nid(&cert_type) == NID_x509Certificate) { + const uint8_t *inp = CBS_data(&cert); + X509 *x509 = d2i_X509(NULL, &inp, CBS_len(&cert)); + if (!x509) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + if (inp != CBS_data(&cert) + CBS_len(&cert)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + X509_free(x509); + goto err; + } + + if (0 == sk_X509_push(ctx->out_certs, x509)) { + X509_free(x509); + goto err; + } + } + ret = 1; + } else { + /* Unknown element type - ignore it. */ + ret = 1; + } + +err: + return ret; +} + +int PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs, + CBS *ber_in, const char *password) { + uint8_t *der_bytes = NULL; + size_t der_len; + CBS in, pfx, mac_data, authsafe, content_type, wrapped_authsafes, authsafes; + uint64_t version; + int ret = 0; + struct pkcs12_context ctx; + const size_t original_out_certs_len = sk_X509_num(out_certs); + + /* The input may be in BER format. */ + if (!CBS_asn1_ber_to_der(ber_in, &der_bytes, &der_len)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + return 0; + } + if (der_bytes != NULL) { + CBS_init(&in, der_bytes, der_len); + } else { + CBS_init(&in, CBS_data(ber_in), CBS_len(ber_in)); + } + + *out_key = NULL; + memset(&ctx, 0, sizeof(ctx)); + + /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section + * four. */ + if (!CBS_get_asn1(&in, &pfx, CBS_ASN1_SEQUENCE) || + CBS_len(&in) != 0 || + !CBS_get_asn1_uint64(&pfx, &version)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + if (version < 3) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_VERSION); + goto err; + } + + if (!CBS_get_asn1(&pfx, &authsafe, CBS_ASN1_SEQUENCE)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + if (CBS_len(&pfx) == 0) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_MISSING_MAC); + goto err; + } + + if (!CBS_get_asn1(&pfx, &mac_data, CBS_ASN1_SEQUENCE)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + /* authsafe is a PKCS#7 ContentInfo. See + * https://tools.ietf.org/html/rfc2315#section-7. */ + if (!CBS_get_asn1(&authsafe, &content_type, CBS_ASN1_OBJECT) || + !CBS_get_asn1(&authsafe, &wrapped_authsafes, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + /* The content type can either be |NID_pkcs7_data| or |NID_pkcs7_signed|. The + * latter indicates that it's signed by a public key, which isn't + * supported. */ + if (OBJ_cbs2nid(&content_type) != NID_pkcs7_data) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED); + goto err; + } + + if (!CBS_get_asn1(&wrapped_authsafes, &authsafes, CBS_ASN1_OCTETSTRING)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + ctx.out_key = out_key; + ctx.out_certs = out_certs; + if (!ascii_to_ucs2(password, strlen(password), &ctx.password, + &ctx.password_len)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + goto err; + } + + /* Verify the MAC. */ + { + CBS mac, hash_type_seq, hash_oid, salt, expected_mac; + uint64_t iterations; + int hash_nid; + const EVP_MD *md; + uint8_t hmac_key[EVP_MAX_MD_SIZE]; + uint8_t hmac[EVP_MAX_MD_SIZE]; + unsigned hmac_len; + + if (!CBS_get_asn1(&mac_data, &mac, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&mac, &hash_type_seq, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&hash_type_seq, &hash_oid, CBS_ASN1_OBJECT) || + !CBS_get_asn1(&mac, &expected_mac, CBS_ASN1_OCTETSTRING) || + !CBS_get_asn1(&mac_data, &salt, CBS_ASN1_OCTETSTRING)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + + /* The iteration count is optional and the default is one. */ + iterations = 1; + if (CBS_len(&mac_data) > 0) { + if (!CBS_get_asn1_uint64(&mac_data, &iterations) || + iterations > INT_MAX) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA); + goto err; + } + } + + hash_nid = OBJ_cbs2nid(&hash_oid); + if (hash_nid == NID_undef || + (md = EVP_get_digestbynid(hash_nid)) == NULL) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_HASH); + goto err; + } + + if (!pkcs12_key_gen_raw(ctx.password, ctx.password_len, CBS_data(&salt), + CBS_len(&salt), PKCS12_MAC_ID, iterations, + EVP_MD_size(md), hmac_key, md)) { + goto err; + } + + if (NULL == HMAC(md, hmac_key, EVP_MD_size(md), CBS_data(&authsafes), + CBS_len(&authsafes), hmac, &hmac_len)) { + goto err; + } + + if (!CBS_mem_equal(&expected_mac, hmac, hmac_len)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_INCORRECT_PASSWORD); + goto err; + } + } + + /* authsafes contains a series of PKCS#7 ContentInfos. */ + if (!PKCS12_handle_content_infos(&authsafes, 0, &ctx)) { + goto err; + } + + ret = 1; + +err: + OPENSSL_free(ctx.password); + OPENSSL_free(der_bytes); + if (!ret) { + EVP_PKEY_free(*out_key); + *out_key = NULL; + while (sk_X509_num(out_certs) > original_out_certs_len) { + X509 *x509 = sk_X509_pop(out_certs); + X509_free(x509); + } + } + + return ret; +} + +void PKCS12_PBE_add(void) {} + +struct pkcs12_st { + uint8_t *ber_bytes; + size_t ber_len; +}; + +PKCS12* d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes, size_t ber_len) { + PKCS12 *p12; + + /* out_p12 must be NULL because we don't export the PKCS12 structure. */ + assert(out_p12 == NULL); + + p12 = OPENSSL_malloc(sizeof(PKCS12)); + if (!p12) { + return NULL; + } + + p12->ber_bytes = OPENSSL_malloc(ber_len); + if (!p12->ber_bytes) { + OPENSSL_free(p12); + return NULL; + } + + memcpy(p12->ber_bytes, *ber_bytes, ber_len); + p12->ber_len = ber_len; + *ber_bytes += ber_len; + + return p12; +} + +PKCS12* d2i_PKCS12_bio(BIO *bio, PKCS12 **out_p12) { + size_t used = 0; + BUF_MEM *buf; + const uint8_t *dummy; + static const size_t kMaxSize = 256 * 1024; + PKCS12 *ret = NULL; + + buf = BUF_MEM_new(); + if (buf == NULL) { + return NULL; + } + if (BUF_MEM_grow(buf, 8192) == 0) { + goto out; + } + + for (;;) { + int n = BIO_read(bio, &buf->data[used], buf->length - used); + if (n < 0) { + goto out; + } + + if (n == 0) { + break; + } + used += n; + + if (used < buf->length) { + continue; + } + + if (buf->length > kMaxSize || + BUF_MEM_grow(buf, buf->length * 2) == 0) { + goto out; + } + } + + dummy = (uint8_t*) buf->data; + ret = d2i_PKCS12(out_p12, &dummy, used); + +out: + BUF_MEM_free(buf); + return ret; +} + +PKCS12* d2i_PKCS12_fp(FILE *fp, PKCS12 **out_p12) { + BIO *bio; + PKCS12 *ret; + + bio = BIO_new_fp(fp, 0 /* don't take ownership */); + if (!bio) { + return NULL; + } + + ret = d2i_PKCS12_bio(bio, out_p12); + BIO_free(bio); + return ret; +} + +int PKCS12_parse(const PKCS12 *p12, const char *password, EVP_PKEY **out_pkey, + X509 **out_cert, STACK_OF(X509) **out_ca_certs) { + CBS ber_bytes; + STACK_OF(X509) *ca_certs = NULL; + char ca_certs_alloced = 0; + + if (out_ca_certs != NULL && *out_ca_certs != NULL) { + ca_certs = *out_ca_certs; + } + + if (!ca_certs) { + ca_certs = sk_X509_new_null(); + if (ca_certs == NULL) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + return 0; + } + ca_certs_alloced = 1; + } + + CBS_init(&ber_bytes, p12->ber_bytes, p12->ber_len); + if (!PKCS12_get_key_and_certs(out_pkey, ca_certs, &ber_bytes, password)) { + if (ca_certs_alloced) { + sk_X509_free(ca_certs); + } + return 0; + } + + *out_cert = NULL; + if (sk_X509_num(ca_certs) > 0) { + *out_cert = sk_X509_shift(ca_certs); + } + + if (out_ca_certs) { + *out_ca_certs = ca_certs; + } else { + sk_X509_pop_free(ca_certs, X509_free); + } + + return 1; +} + +void PKCS12_free(PKCS12 *p12) { + OPENSSL_free(p12->ber_bytes); + OPENSSL_free(p12); +} diff --git a/TMessagesProj/jni/boringssl/crypto/poly1305/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/poly1305/CMakeLists.txt new file mode 100644 index 00000000..bb0c1e44 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/poly1305/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "arm") + set( + POLY1305_ARCH_SOURCES + + poly1305_arm_asm.S + ) +endif() + +add_library( + poly1305 + + OBJECT + + poly1305.c + poly1305_arm.c + poly1305_vec.c + + ${POLY1305_ARCH_SOURCES} +) diff --git a/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305.c b/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305.c new file mode 100644 index 00000000..5a49e2df --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305.c @@ -0,0 +1,331 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This implementation of poly1305 is by Andrew Moon + * (https://github.com/floodyberry/poly1305-donna) and released as public + * domain. */ + +#include + +#include + +#include + + +#if defined(OPENSSL_WINDOWS) || !defined(OPENSSL_X86_64) + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM) +/* We can assume little-endian. */ +static uint32_t U8TO32_LE(const uint8_t *m) { + uint32_t r; + memcpy(&r, m, sizeof(r)); + return r; +} + +static void U32TO8_LE(uint8_t *m, uint32_t v) { memcpy(m, &v, sizeof(v)); } +#else +static uint32_t U8TO32_LE(const uint8_t *m) { + return (uint32_t)m[0] | (uint32_t)m[1] << 8 | (uint32_t)m[2] << 16 | + (uint32_t)m[3] << 24; +} + +static void U32TO8_LE(uint8_t *m, uint32_t v) { + m[0] = v; + m[1] = v >> 8; + m[2] = v >> 16; + m[3] = v >> 24; +} +#endif + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) +void CRYPTO_poly1305_init_neon(poly1305_state *state, const uint8_t key[32]); + +void CRYPTO_poly1305_update_neon(poly1305_state *state, const uint8_t *in, + size_t in_len); + +void CRYPTO_poly1305_finish_neon(poly1305_state *state, uint8_t mac[16]); +#endif + +static uint64_t mul32x32_64(uint32_t a, uint32_t b) { return (uint64_t)a * b; } + +struct poly1305_state_st { + uint32_t r0, r1, r2, r3, r4; + uint32_t s1, s2, s3, s4; + uint32_t h0, h1, h2, h3, h4; + uint8_t buf[16]; + unsigned int buf_used; + uint8_t key[16]; +}; + +/* poly1305_blocks updates |state| given some amount of input data. This + * function may only be called with a |len| that is not a multiple of 16 at the + * end of the data. Otherwise the input must be buffered into 16 byte blocks. */ +static void poly1305_update(struct poly1305_state_st *state, const uint8_t *in, + size_t len) { + uint32_t t0, t1, t2, t3; + uint64_t t[5]; + uint32_t b; + uint64_t c; + size_t j; + uint8_t mp[16]; + + if (len < 16) { + goto poly1305_donna_atmost15bytes; + } + +poly1305_donna_16bytes: + t0 = U8TO32_LE(in); + t1 = U8TO32_LE(in + 4); + t2 = U8TO32_LE(in + 8); + t3 = U8TO32_LE(in + 12); + + in += 16; + len -= 16; + + state->h0 += t0 & 0x3ffffff; + state->h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + state->h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + state->h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + state->h4 += (t3 >> 8) | (1 << 24); + +poly1305_donna_mul: + t[0] = mul32x32_64(state->h0, state->r0) + mul32x32_64(state->h1, state->s4) + + mul32x32_64(state->h2, state->s3) + mul32x32_64(state->h3, state->s2) + + mul32x32_64(state->h4, state->s1); + t[1] = mul32x32_64(state->h0, state->r1) + mul32x32_64(state->h1, state->r0) + + mul32x32_64(state->h2, state->s4) + mul32x32_64(state->h3, state->s3) + + mul32x32_64(state->h4, state->s2); + t[2] = mul32x32_64(state->h0, state->r2) + mul32x32_64(state->h1, state->r1) + + mul32x32_64(state->h2, state->r0) + mul32x32_64(state->h3, state->s4) + + mul32x32_64(state->h4, state->s3); + t[3] = mul32x32_64(state->h0, state->r3) + mul32x32_64(state->h1, state->r2) + + mul32x32_64(state->h2, state->r1) + mul32x32_64(state->h3, state->r0) + + mul32x32_64(state->h4, state->s4); + t[4] = mul32x32_64(state->h0, state->r4) + mul32x32_64(state->h1, state->r3) + + mul32x32_64(state->h2, state->r2) + mul32x32_64(state->h3, state->r1) + + mul32x32_64(state->h4, state->r0); + + state->h0 = (uint32_t)t[0] & 0x3ffffff; + c = (t[0] >> 26); + t[1] += c; + state->h1 = (uint32_t)t[1] & 0x3ffffff; + b = (uint32_t)(t[1] >> 26); + t[2] += b; + state->h2 = (uint32_t)t[2] & 0x3ffffff; + b = (uint32_t)(t[2] >> 26); + t[3] += b; + state->h3 = (uint32_t)t[3] & 0x3ffffff; + b = (uint32_t)(t[3] >> 26); + t[4] += b; + state->h4 = (uint32_t)t[4] & 0x3ffffff; + b = (uint32_t)(t[4] >> 26); + state->h0 += b * 5; + + if (len >= 16) { + goto poly1305_donna_16bytes; + } + +/* final bytes */ +poly1305_donna_atmost15bytes: + if (!len) { + return; + } + + for (j = 0; j < len; j++) { + mp[j] = in[j]; + } + mp[j++] = 1; + for (; j < 16; j++) { + mp[j] = 0; + } + len = 0; + + t0 = U8TO32_LE(mp + 0); + t1 = U8TO32_LE(mp + 4); + t2 = U8TO32_LE(mp + 8); + t3 = U8TO32_LE(mp + 12); + + state->h0 += t0 & 0x3ffffff; + state->h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + state->h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + state->h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + state->h4 += (t3 >> 8); + + goto poly1305_donna_mul; +} + +void CRYPTO_poly1305_init(poly1305_state *statep, const uint8_t key[32]) { + struct poly1305_state_st *state = (struct poly1305_state_st *)statep; + uint32_t t0, t1, t2, t3; + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) + if (CRYPTO_is_NEON_functional()) { + CRYPTO_poly1305_init_neon(statep, key); + return; + } +#endif + + t0 = U8TO32_LE(key + 0); + t1 = U8TO32_LE(key + 4); + t2 = U8TO32_LE(key + 8); + t3 = U8TO32_LE(key + 12); + + /* precompute multipliers */ + state->r0 = t0 & 0x3ffffff; + t0 >>= 26; + t0 |= t1 << 6; + state->r1 = t0 & 0x3ffff03; + t1 >>= 20; + t1 |= t2 << 12; + state->r2 = t1 & 0x3ffc0ff; + t2 >>= 14; + t2 |= t3 << 18; + state->r3 = t2 & 0x3f03fff; + t3 >>= 8; + state->r4 = t3 & 0x00fffff; + + state->s1 = state->r1 * 5; + state->s2 = state->r2 * 5; + state->s3 = state->r3 * 5; + state->s4 = state->r4 * 5; + + /* init state */ + state->h0 = 0; + state->h1 = 0; + state->h2 = 0; + state->h3 = 0; + state->h4 = 0; + + state->buf_used = 0; + memcpy(state->key, key + 16, sizeof(state->key)); +} + +void CRYPTO_poly1305_update(poly1305_state *statep, const uint8_t *in, + size_t in_len) { + unsigned int i; + struct poly1305_state_st *state = (struct poly1305_state_st *)statep; + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) + if (CRYPTO_is_NEON_functional()) { + CRYPTO_poly1305_update_neon(statep, in, in_len); + return; + } +#endif + + if (state->buf_used) { + unsigned int todo = 16 - state->buf_used; + if (todo > in_len) { + todo = in_len; + } + for (i = 0; i < todo; i++) { + state->buf[state->buf_used + i] = in[i]; + } + state->buf_used += todo; + in_len -= todo; + in += todo; + + if (state->buf_used == 16) { + poly1305_update(state, state->buf, 16); + state->buf_used = 0; + } + } + + if (in_len >= 16) { + size_t todo = in_len & ~0xf; + poly1305_update(state, in, todo); + in += todo; + in_len &= 0xf; + } + + if (in_len) { + for (i = 0; i < in_len; i++) { + state->buf[i] = in[i]; + } + state->buf_used = in_len; + } +} + +void CRYPTO_poly1305_finish(poly1305_state *statep, uint8_t mac[16]) { + struct poly1305_state_st *state = (struct poly1305_state_st *)statep; + uint64_t f0, f1, f2, f3; + uint32_t g0, g1, g2, g3, g4; + uint32_t b, nb; + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) + if (CRYPTO_is_NEON_functional()) { + CRYPTO_poly1305_finish_neon(statep, mac); + return; + } +#endif + + if (state->buf_used) { + poly1305_update(state, state->buf, state->buf_used); + } + + b = state->h0 >> 26; + state->h0 = state->h0 & 0x3ffffff; + state->h1 += b; + b = state->h1 >> 26; + state->h1 = state->h1 & 0x3ffffff; + state->h2 += b; + b = state->h2 >> 26; + state->h2 = state->h2 & 0x3ffffff; + state->h3 += b; + b = state->h3 >> 26; + state->h3 = state->h3 & 0x3ffffff; + state->h4 += b; + b = state->h4 >> 26; + state->h4 = state->h4 & 0x3ffffff; + state->h0 += b * 5; + + g0 = state->h0 + 5; + b = g0 >> 26; + g0 &= 0x3ffffff; + g1 = state->h1 + b; + b = g1 >> 26; + g1 &= 0x3ffffff; + g2 = state->h2 + b; + b = g2 >> 26; + g2 &= 0x3ffffff; + g3 = state->h3 + b; + b = g3 >> 26; + g3 &= 0x3ffffff; + g4 = state->h4 + b - (1 << 26); + + b = (g4 >> 31) - 1; + nb = ~b; + state->h0 = (state->h0 & nb) | (g0 & b); + state->h1 = (state->h1 & nb) | (g1 & b); + state->h2 = (state->h2 & nb) | (g2 & b); + state->h3 = (state->h3 & nb) | (g3 & b); + state->h4 = (state->h4 & nb) | (g4 & b); + + f0 = ((state->h0) | (state->h1 << 26)) + (uint64_t)U8TO32_LE(&state->key[0]); + f1 = ((state->h1 >> 6) | (state->h2 << 20)) + + (uint64_t)U8TO32_LE(&state->key[4]); + f2 = ((state->h2 >> 12) | (state->h3 << 14)) + + (uint64_t)U8TO32_LE(&state->key[8]); + f3 = ((state->h3 >> 18) | (state->h4 << 8)) + + (uint64_t)U8TO32_LE(&state->key[12]); + + U32TO8_LE(&mac[0], f0); + f1 += (f0 >> 32); + U32TO8_LE(&mac[4], f1); + f2 += (f1 >> 32); + U32TO8_LE(&mac[8], f2); + f3 += (f2 >> 32); + U32TO8_LE(&mac[12], f3); +} + +#endif /* OPENSSL_WINDOWS || !OPENSSL_X86_64 */ diff --git a/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_arm.c b/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_arm.c new file mode 100644 index 00000000..c06ededd --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_arm.c @@ -0,0 +1,301 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This implementation was taken from the public domain, neon2 version in + * SUPERCOP by D. J. Bernstein and Peter Schwabe. */ + +#include + +#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM) + +#include + + +typedef struct { + uint32_t v[12]; /* for alignment; only using 10 */ +} fe1305x2; + +#define addmulmod openssl_poly1305_neon2_addmulmod +#define blocks openssl_poly1305_neon2_blocks + +extern void addmulmod(fe1305x2 *r, const fe1305x2 *x, const fe1305x2 *y, + const fe1305x2 *c); + +extern int blocks(fe1305x2 *h, const fe1305x2 *precomp, const uint8_t *in, + unsigned int inlen); + +static void freeze(fe1305x2 *r) { + int i; + + uint32_t x0 = r->v[0]; + uint32_t x1 = r->v[2]; + uint32_t x2 = r->v[4]; + uint32_t x3 = r->v[6]; + uint32_t x4 = r->v[8]; + uint32_t y0; + uint32_t y1; + uint32_t y2; + uint32_t y3; + uint32_t y4; + uint32_t swap; + + for (i = 0; i < 3; ++i) { + x1 += x0 >> 26; + x0 &= 0x3ffffff; + x2 += x1 >> 26; + x1 &= 0x3ffffff; + x3 += x2 >> 26; + x2 &= 0x3ffffff; + x4 += x3 >> 26; + x3 &= 0x3ffffff; + x0 += 5 * (x4 >> 26); + x4 &= 0x3ffffff; + } + + y0 = x0 + 5; + y1 = x1 + (y0 >> 26); + y0 &= 0x3ffffff; + y2 = x2 + (y1 >> 26); + y1 &= 0x3ffffff; + y3 = x3 + (y2 >> 26); + y2 &= 0x3ffffff; + y4 = x4 + (y3 >> 26); + y3 &= 0x3ffffff; + swap = -(y4 >> 26); + y4 &= 0x3ffffff; + + y0 ^= x0; + y1 ^= x1; + y2 ^= x2; + y3 ^= x3; + y4 ^= x4; + + y0 &= swap; + y1 &= swap; + y2 &= swap; + y3 &= swap; + y4 &= swap; + + y0 ^= x0; + y1 ^= x1; + y2 ^= x2; + y3 ^= x3; + y4 ^= x4; + + r->v[0] = y0; + r->v[2] = y1; + r->v[4] = y2; + r->v[6] = y3; + r->v[8] = y4; +} + +static void fe1305x2_tobytearray(uint8_t *r, fe1305x2 *x) { + uint32_t x0 = x->v[0]; + uint32_t x1 = x->v[2]; + uint32_t x2 = x->v[4]; + uint32_t x3 = x->v[6]; + uint32_t x4 = x->v[8]; + + x1 += x0 >> 26; + x0 &= 0x3ffffff; + x2 += x1 >> 26; + x1 &= 0x3ffffff; + x3 += x2 >> 26; + x2 &= 0x3ffffff; + x4 += x3 >> 26; + x3 &= 0x3ffffff; + + *(uint32_t *)r = x0 + (x1 << 26); + *(uint32_t *)(r + 4) = (x1 >> 6) + (x2 << 20); + *(uint32_t *)(r + 8) = (x2 >> 12) + (x3 << 14); + *(uint32_t *)(r + 12) = (x3 >> 18) + (x4 << 8); +} + +/* load32 exists to avoid breaking strict aliasing rules in + * fe1305x2_frombytearray. */ +static uint32_t load32(uint8_t *t) { + uint32_t tmp; + memcpy(&tmp, t, sizeof(tmp)); + return tmp; +} + +static void fe1305x2_frombytearray(fe1305x2 *r, const uint8_t *x, + unsigned long long xlen) { + int i; + uint8_t t[17]; + + for (i = 0; (i < 16) && (i < xlen); i++) { + t[i] = x[i]; + } + xlen -= i; + x += i; + t[i++] = 1; + for (; i < 17; i++) { + t[i] = 0; + } + + r->v[0] = 0x3ffffff & load32(t); + r->v[2] = 0x3ffffff & (load32(t + 3) >> 2); + r->v[4] = 0x3ffffff & (load32(t + 6) >> 4); + r->v[6] = 0x3ffffff & (load32(t + 9) >> 6); + r->v[8] = load32(t + 13); + + if (xlen) { + for (i = 0; (i < 16) && (i < xlen); i++) { + t[i] = x[i]; + } + t[i++] = 1; + for (; i < 17; i++) { + t[i] = 0; + } + + r->v[1] = 0x3ffffff & load32(t); + r->v[3] = 0x3ffffff & (load32(t + 3) >> 2); + r->v[5] = 0x3ffffff & (load32(t + 6) >> 4); + r->v[7] = 0x3ffffff & (load32(t + 9) >> 6); + r->v[9] = load32(t + 13); + } else { + r->v[1] = r->v[3] = r->v[5] = r->v[7] = r->v[9] = 0; + } +} + +static const fe1305x2 zero __attribute__((aligned(16))); + +struct poly1305_state_st { + uint8_t data[sizeof(fe1305x2[5]) + 128]; + uint8_t buf[32]; + unsigned int buf_used; + uint8_t key[16]; +}; + +void CRYPTO_poly1305_init_neon(poly1305_state *state, const uint8_t key[32]) { + struct poly1305_state_st *st = (struct poly1305_state_st *)(state); + fe1305x2 *const r = (fe1305x2 *)(st->data + (15 & (-(int)st->data))); + fe1305x2 *const h = r + 1; + fe1305x2 *const c = h + 1; + fe1305x2 *const precomp = c + 1; + unsigned int j; + + r->v[1] = r->v[0] = 0x3ffffff & *(uint32_t *)key; + r->v[3] = r->v[2] = 0x3ffff03 & ((*(uint32_t *)(key + 3)) >> 2); + r->v[5] = r->v[4] = 0x3ffc0ff & ((*(uint32_t *)(key + 6)) >> 4); + r->v[7] = r->v[6] = 0x3f03fff & ((*(uint32_t *)(key + 9)) >> 6); + r->v[9] = r->v[8] = 0x00fffff & ((*(uint32_t *)(key + 12)) >> 8); + + for (j = 0; j < 10; j++) { + h->v[j] = 0; /* XXX: should fast-forward a bit */ + } + + addmulmod(precomp, r, r, &zero); /* precompute r^2 */ + addmulmod(precomp + 1, precomp, precomp, &zero); /* precompute r^4 */ + + memcpy(st->key, key + 16, 16); + st->buf_used = 0; +} + +void CRYPTO_poly1305_update_neon(poly1305_state *state, const uint8_t *in, + size_t in_len) { + struct poly1305_state_st *st = (struct poly1305_state_st *)(state); + fe1305x2 *const r = (fe1305x2 *)(st->data + (15 & (-(int)st->data))); + fe1305x2 *const h = r + 1; + fe1305x2 *const c = h + 1; + fe1305x2 *const precomp = c + 1; + unsigned int i; + + if (st->buf_used) { + unsigned int todo = 32 - st->buf_used; + if (todo > in_len) { + todo = in_len; + } + for (i = 0; i < todo; i++) { + st->buf[st->buf_used + i] = in[i]; + } + st->buf_used += todo; + in_len -= todo; + in += todo; + + if (st->buf_used == sizeof(st->buf) && in_len) { + addmulmod(h, h, precomp, &zero); + fe1305x2_frombytearray(c, st->buf, sizeof(st->buf)); + for (i = 0; i < 10; i++) { + h->v[i] += c->v[i]; + } + st->buf_used = 0; + } + } + + while (in_len > 32) { + unsigned int tlen = 1048576; + if (in_len < tlen) { + tlen = in_len; + } + tlen -= blocks(h, precomp, in, tlen); + in_len -= tlen; + in += tlen; + } + + if (in_len) { + for (i = 0; i < in_len; i++) { + st->buf[i] = in[i]; + } + st->buf_used = in_len; + } +} + +void CRYPTO_poly1305_finish_neon(poly1305_state *state, uint8_t mac[16]) { + struct poly1305_state_st *st = (struct poly1305_state_st *)(state); + fe1305x2 *const r = (fe1305x2 *)(st->data + (15 & (-(int)st->data))); + fe1305x2 *const h = r + 1; + fe1305x2 *const c = h + 1; + fe1305x2 *const precomp = c + 1; + + addmulmod(h, h, precomp, &zero); + + if (st->buf_used > 16) { + fe1305x2_frombytearray(c, st->buf, st->buf_used); + precomp->v[1] = r->v[1]; + precomp->v[3] = r->v[3]; + precomp->v[5] = r->v[5]; + precomp->v[7] = r->v[7]; + precomp->v[9] = r->v[9]; + addmulmod(h, h, precomp, c); + } else if (st->buf_used > 0) { + fe1305x2_frombytearray(c, st->buf, st->buf_used); + r->v[1] = 1; + r->v[3] = 0; + r->v[5] = 0; + r->v[7] = 0; + r->v[9] = 0; + addmulmod(h, h, r, c); + } + + h->v[0] += h->v[1]; + h->v[2] += h->v[3]; + h->v[4] += h->v[5]; + h->v[6] += h->v[7]; + h->v[8] += h->v[9]; + freeze(h); + + fe1305x2_frombytearray(c, st->key, 16); + c->v[8] ^= (1 << 24); + + h->v[0] += c->v[0]; + h->v[2] += c->v[2]; + h->v[4] += c->v[4]; + h->v[6] += c->v[6]; + h->v[8] += c->v[8]; + fe1305x2_tobytearray(mac, h); +} + +#endif /* OPENSSL_ARM && !OPENSSL_NO_ASM */ diff --git a/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_arm_asm.S b/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_arm_asm.S new file mode 100644 index 00000000..e16f83bd --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/poly1305/poly1305_arm_asm.S @@ -0,0 +1,2015 @@ +#if defined(__arm__) && !defined(OPENSSL_NO_ASM) + +# This implementation was taken from the public domain, neon2 version in +# SUPERCOP by D. J. Bernstein and Peter Schwabe. + +# qhasm: int32 input_0 + +# qhasm: int32 input_1 + +# qhasm: int32 input_2 + +# qhasm: int32 input_3 + +# qhasm: stack32 input_4 + +# qhasm: stack32 input_5 + +# qhasm: stack32 input_6 + +# qhasm: stack32 input_7 + +# qhasm: int32 caller_r4 + +# qhasm: int32 caller_r5 + +# qhasm: int32 caller_r6 + +# qhasm: int32 caller_r7 + +# qhasm: int32 caller_r8 + +# qhasm: int32 caller_r9 + +# qhasm: int32 caller_r10 + +# qhasm: int32 caller_r11 + +# qhasm: int32 caller_r12 + +# qhasm: int32 caller_r14 + +# qhasm: reg128 caller_q4 + +# qhasm: reg128 caller_q5 + +# qhasm: reg128 caller_q6 + +# qhasm: reg128 caller_q7 + +# qhasm: startcode +.fpu neon +.text + +# qhasm: reg128 r0 + +# qhasm: reg128 r1 + +# qhasm: reg128 r2 + +# qhasm: reg128 r3 + +# qhasm: reg128 r4 + +# qhasm: reg128 x01 + +# qhasm: reg128 x23 + +# qhasm: reg128 x4 + +# qhasm: reg128 y0 + +# qhasm: reg128 y12 + +# qhasm: reg128 y34 + +# qhasm: reg128 5y12 + +# qhasm: reg128 5y34 + +# qhasm: stack128 y0_stack + +# qhasm: stack128 y12_stack + +# qhasm: stack128 y34_stack + +# qhasm: stack128 5y12_stack + +# qhasm: stack128 5y34_stack + +# qhasm: reg128 z0 + +# qhasm: reg128 z12 + +# qhasm: reg128 z34 + +# qhasm: reg128 5z12 + +# qhasm: reg128 5z34 + +# qhasm: stack128 z0_stack + +# qhasm: stack128 z12_stack + +# qhasm: stack128 z34_stack + +# qhasm: stack128 5z12_stack + +# qhasm: stack128 5z34_stack + +# qhasm: stack128 two24 + +# qhasm: int32 ptr + +# qhasm: reg128 c01 + +# qhasm: reg128 c23 + +# qhasm: reg128 d01 + +# qhasm: reg128 d23 + +# qhasm: reg128 t0 + +# qhasm: reg128 t1 + +# qhasm: reg128 t2 + +# qhasm: reg128 t3 + +# qhasm: reg128 t4 + +# qhasm: reg128 mask + +# qhasm: reg128 u0 + +# qhasm: reg128 u1 + +# qhasm: reg128 u2 + +# qhasm: reg128 u3 + +# qhasm: reg128 u4 + +# qhasm: reg128 v01 + +# qhasm: reg128 mid + +# qhasm: reg128 v23 + +# qhasm: reg128 v4 + +# qhasm: int32 len + +# qhasm: qpushenter crypto_onetimeauth_poly1305_neon2_blocks +.align 4 +.global openssl_poly1305_neon2_blocks +.hidden openssl_poly1305_neon2_blocks +.type openssl_poly1305_neon2_blocks STT_FUNC +openssl_poly1305_neon2_blocks: +vpush {q4,q5,q6,q7} +mov r12,sp +sub sp,sp,#192 +bic sp,sp,#31 + +# qhasm: len = input_3 +# asm 1: mov >len=int32#4,len=r3,y12=reg128#2%bot->y12=reg128#2%top},[y12=d2->y12=d3},[y34=reg128#3%bot->y34=reg128#3%top},[y34=d4->y34=d5},[input_1=int32#2,input_1=r1,z12=reg128#5%bot->z12=reg128#5%top},[z12=d8->z12=d9},[z34=reg128#6%bot->z34=reg128#6%top},[z34=d10->z34=d11},[mask=reg128#7,#0xffffffff +# asm 2: vmov.i64 >mask=q6,#0xffffffff +vmov.i64 q6,#0xffffffff + +# qhasm: 2x u4 = 0xff +# asm 1: vmov.i64 >u4=reg128#8,#0xff +# asm 2: vmov.i64 >u4=q7,#0xff +vmov.i64 q7,#0xff + +# qhasm: x01 aligned= mem128[input_0];input_0+=16 +# asm 1: vld1.8 {>x01=reg128#9%bot->x01=reg128#9%top},[x01=d16->x01=d17},[x23=reg128#10%bot->x23=reg128#10%top},[x23=d18->x23=d19},[input_0=int32#1,input_0=r0,>=6 +# asm 1: vshr.u64 >mask=reg128#7,mask=q6,>= 7 +# asm 1: vshr.u64 >u4=reg128#8,u4=q7,5y12=reg128#12,5y12=q11,5y34=reg128#13,5y34=q12,5y12=reg128#12,<5y12=reg128#12,5y12=q11,<5y12=q11,5y34=reg128#13,<5y34=reg128#13,5y34=q12,<5y34=q12,u4=reg128#8,u4=q7,5z12=reg128#14,5z12=q13,5z34=reg128#15,5z34=q14,5z12=reg128#14,<5z12=reg128#14,5z12=q13,<5z12=q13,5z34=reg128#15,<5z34=reg128#15,5z34=q14,<5z34=q14,ptr=int32#2,ptr=r1,r4=reg128#16,r4=q15,r0=reg128#8,r0=q7,ptr=int32#2,ptr=r1,ptr=int32#2,ptr=r1,ptr=int32#2,ptr=r1,ptr=int32#2,ptr=r1,ptr=int32#2,ptr=r1,ptr=int32#2,ptr=r1,ptr=int32#2,<5y12_stack=stack128#5 +# asm 2: lea >ptr=r1,<5y12_stack=[sp,#64] +add r1,sp,#64 + +# qhasm: mem128[ptr] aligned= 5y12 +# asm 1: vst1.8 {<5y12=reg128#12%bot-<5y12=reg128#12%top},[ptr=int32#2,<5y34_stack=stack128#6 +# asm 2: lea >ptr=r1,<5y34_stack=[sp,#80] +add r1,sp,#80 + +# qhasm: mem128[ptr] aligned= 5y34 +# asm 1: vst1.8 {<5y34=reg128#13%bot-<5y34=reg128#13%top},[ptr=int32#2,<5z12_stack=stack128#10 +# asm 2: lea >ptr=r1,<5z12_stack=[sp,#144] +add r1,sp,#144 + +# qhasm: mem128[ptr] aligned= 5z12 +# asm 1: vst1.8 {<5z12=reg128#14%bot-<5z12=reg128#14%top},[ptr=int32#2,<5z34_stack=stack128#11 +# asm 2: lea >ptr=r1,<5z34_stack=[sp,#160] +add r1,sp,#160 + +# qhasm: mem128[ptr] aligned= 5z34 +# asm 1: vst1.8 {<5z34=reg128#15%bot-<5z34=reg128#15%top},[? len - 64 +# asm 1: cmp +bls ._below64bytes + +# qhasm: input_2 += 32 +# asm 1: add >input_2=int32#2,input_2=r1,c01=reg128#1%bot->c01=reg128#1%top},[c01=d0->c01=d1},[c23=reg128#2%bot->c23=reg128#2%top},[c23=d2->c23=d3},[ptr=int32#3,ptr=r2,z12=reg128#3%bot->z12=reg128#3%top},[z12=d4->z12=d5},[ptr=int32#3,ptr=r2,z0=reg128#4%bot->z0=reg128#4%top},[z0=d6->z0=d7},[r3=reg128#5,r3=q4,input_2=int32#2,input_2=r1,ptr=int32#3,<5z34_stack=stack128#11 +# asm 2: lea >ptr=r2,<5z34_stack=[sp,#160] +add r2,sp,#160 + +# qhasm: 5z34 aligned= mem128[ptr] +# asm 1: vld1.8 {>5z34=reg128#6%bot->5z34=reg128#6%top},[5z34=d10->5z34=d11},[r0=reg128#8,r0=q7,r2=reg128#14,r2=q13,d01=reg128#12%bot->d01=reg128#12%top},[d01=d22->d01=d23},[r1=reg128#15,r1=q14,ptr=int32#3,<5z12_stack=stack128#10 +# asm 2: lea >ptr=r2,<5z12_stack=[sp,#144] +add r2,sp,#144 + +# qhasm: 5z12 aligned= mem128[ptr] +# asm 1: vld1.8 {>5z12=reg128#1%bot->5z12=reg128#1%top},[5z12=d0->5z12=d1},[d23=reg128#2%bot->d23=reg128#2%top},[d23=d2->d23=d3},[input_2=int32#2,input_2=r1,> 40 +# asm 1: vshr.u64 >v4=reg128#4,v4=q3,> 14; v23[3] = d23[2,3] unsigned>> 14 +# asm 1: vshrn.u64 > 26; v01[3] = d01[2,3] unsigned>> 26 +# asm 1: vshrn.u64 > 20; v23[1] = mid[2,3] unsigned>> 20 +# asm 1: vshrn.u64 ptr=int32#3,ptr=r2,y34=reg128#3%bot->y34=reg128#3%top},[y34=d4->y34=d5},[ptr=int32#3,ptr=r2,y12=reg128#2%bot->y12=reg128#2%top},[y12=d2->y12=d3},[ptr=int32#3,ptr=r2,y0=reg128#1%bot->y0=reg128#1%top},[y0=d0->y0=d1},[ptr=int32#3,<5y34_stack=stack128#6 +# asm 2: lea >ptr=r2,<5y34_stack=[sp,#80] +add r2,sp,#80 + +# qhasm: 5y34 aligned= mem128[ptr] +# asm 1: vld1.8 {>5y34=reg128#13%bot->5y34=reg128#13%top},[5y34=d24->5y34=d25},[ptr=int32#3,<5y12_stack=stack128#5 +# asm 2: lea >ptr=r2,<5y12_stack=[sp,#64] +add r2,sp,#64 + +# qhasm: 5y12 aligned= mem128[ptr] +# asm 1: vld1.8 {>5y12=reg128#12%bot->5y12=reg128#12%top},[5y12=d22->5y12=d23},[ptr=int32#3,ptr=r2,> 26 +# asm 1: vshr.u64 >t1=reg128#4,t1=q3,len=int32#4,len=r3,r0=reg128#6,r0=q5,r1=reg128#4,r1=q3,> 26 +# asm 1: vshr.u64 >t4=reg128#8,t4=q7,r3=reg128#5,r3=q4,x4=reg128#8,x4=q7,r4=reg128#16%bot->r4=reg128#16%top},[r4=d30->r4=d31},[> 26 +# asm 1: vshr.u64 >t2=reg128#9,t2=q8,r1=reg128#4,r1=q3,> 26 +# asm 1: vshr.u64 >t0=reg128#10,t0=q9,r2=reg128#9,r2=q8,x4=reg128#11,x4=q10,x01=reg128#6,x01=q5,r0=reg128#8%bot->r0=reg128#8%top},[r0=d14->r0=d15},[ptr=int32#3,ptr=r2,t0=reg128#10,t0=q9,> 26 +# asm 1: vshr.u64 >t3=reg128#14,t3=q13,x01=reg128#15,x01=q14,z34=reg128#6%bot->z34=reg128#6%top},[z34=d10->z34=d11},[x23=reg128#10,x23=q9,r3=reg128#5,r3=q4,input_2=int32#2,input_2=r1,> 26 +# asm 1: vshr.u64 >t1=reg128#14,t1=q13,x01=reg128#9,x01=q8,r1=reg128#4,r1=q3,> 26 +# asm 1: vshr.u64 >t4=reg128#14,t4=q13,r3=reg128#5,r3=q4,x4=reg128#11,x4=q10,? len - 64 +# asm 1: cmp +bhi ._mainloop2 + +# qhasm: input_2 -= 32 +# asm 1: sub >input_2=int32#3,input_2=r2,? len - 32 +# asm 1: cmp +bls ._end + +# qhasm: mainloop: +._mainloop: + +# qhasm: new r0 + +# qhasm: ptr = &two24 +# asm 1: lea >ptr=int32#2,ptr=r1,r4=reg128#5%bot->r4=reg128#5%top},[r4=d8->r4=d9},[u4=reg128#6%bot->u4=reg128#6%top},[u4=d10->u4=d11},[c01=reg128#8%bot->c01=reg128#8%top},[c01=d14->c01=d15},[c23=reg128#14%bot->c23=reg128#14%top},[c23=d26->c23=d27},[r0=reg128#4,r0=q3,r3=reg128#6,r3=q5,r1=reg128#14,r1=q13,r2=reg128#8,r2=q7,> 26 +# asm 1: vshr.u64 >t1=reg128#9,t1=q8,r0=reg128#4,r0=q3,r1=reg128#9,r1=q8,> 26 +# asm 1: vshr.u64 >t4=reg128#10,t4=q9,r3=reg128#6,r3=q5,r4=reg128#5,r4=q4,> 26 +# asm 1: vshr.u64 >t2=reg128#10,t2=q9,r1=reg128#11,r1=q10,> 26 +# asm 1: vshr.u64 >t0=reg128#9,t0=q8,r2=reg128#8,r2=q7,r4=reg128#5,r4=q4,r0=reg128#4,r0=q3,t0=reg128#9,t0=q8,> 26 +# asm 1: vshr.u64 >t3=reg128#14,t3=q13,r0=reg128#4,r0=q3,x23=reg128#10,x23=q9,r3=reg128#6,r3=q5,> 26 +# asm 1: vshr.u64 >t1=reg128#8,t1=q7,x01=reg128#9,x01=q8,r1=reg128#4,r1=q3,> 26 +# asm 1: vshr.u64 >t4=reg128#8,t4=q7,r3=reg128#6,r3=q5,x4=reg128#11,x4=q10,len=int32#4,len=r3,? len - 32 +# asm 1: cmp +bhi ._mainloop + +# qhasm: end: +._end: + +# qhasm: mem128[input_0] = x01;input_0+=16 +# asm 1: vst1.8 {len=int32#1,len=r0,mask=reg128#1,#0xffffffff +# asm 2: vmov.i64 >mask=q0,#0xffffffff +vmov.i64 q0,#0xffffffff + +# qhasm: y01 aligned= mem128[input_2];input_2+=16 +# asm 1: vld1.8 {>y01=reg128#2%bot->y01=reg128#2%top},[y01=d2->y01=d3},[_5y01=reg128#3,_5y01=q2,y23=reg128#4%bot->y23=reg128#4%top},[y23=d6->y23=d7},[_5y23=reg128#9,_5y23=q8,_5y4=reg128#11,_5y4=q10,x01=reg128#12%bot->x01=reg128#12%top},[x01=d22->x01=d23},[_5y01=reg128#3,<_5y01=reg128#3,_5y01=q2,<_5y01=q2,x23=reg128#13%bot->x23=reg128#13%top},[x23=d24->x23=d25},[_5y23=reg128#9,<_5y23=reg128#9,_5y23=q8,<_5y23=q8,_5y4=reg128#11,<_5y4=reg128#11,_5y4=q10,<_5y4=q10,c01=reg128#14%bot->c01=reg128#14%top},[c01=d26->c01=d27},[x01=reg128#12,x01=q11,c23=reg128#14%bot->c23=reg128#14%top},[c23=d26->c23=d27},[x23=reg128#13,x23=q12,>=6 +# asm 1: vshr.u64 >mask=reg128#1,mask=q0,x4=reg128#14,x4=q13,r0=reg128#15,r0=q14,r1=reg128#3,r1=q2,r2=reg128#16,r2=q15,r3=reg128#9,r3=q8,r4=reg128#10,r4=q9,> 26 +# asm 1: vshr.u64 >t1=reg128#2,t1=q1,r0=reg128#4,r0=q3,r1=reg128#2,r1=q1,> 26 +# asm 1: vshr.u64 >t4=reg128#3,t4=q2,r3=reg128#9,r3=q8,r4=reg128#3,r4=q2,> 26 +# asm 1: vshr.u64 >t2=reg128#10,t2=q9,r1=reg128#2,r1=q1,> 26 +# asm 1: vshr.u64 >t0=reg128#11,t0=q10,r2=reg128#10,r2=q9,r4=reg128#3,r4=q2,r0=reg128#4,r0=q3,t0=reg128#11,t0=q10,> 26 +# asm 1: vshr.u64 >t3=reg128#12,t3=q11,r0=reg128#4,r0=q3,x23=reg128#10,x23=q9,r3=reg128#9,r3=q8,> 26 +# asm 1: vshr.u64 >t1=reg128#11,t1=q10,x01=reg128#4,x01=q3,r1=reg128#2,r1=q1,> 26 +# asm 1: vshr.u64 >t4=reg128#11,t4=q10,r3=reg128#1,r3=q0,x4=reg128#3,x4=q2, + + +#if !defined(OPENSSL_WINDOWS) && defined(OPENSSL_X86_64) + +#include + +#define ALIGN(x) __attribute__((aligned(x))) +/* inline is not a keyword in C89. */ +#define INLINE +#define U8TO64_LE(m) (*(uint64_t *)(m)) +#define U8TO32_LE(m) (*(uint32_t *)(m)) +#define U64TO8_LE(m, v) (*(uint64_t *)(m)) = v + +typedef __m128i xmmi; +typedef unsigned __int128 uint128_t; + +static const uint32_t ALIGN(16) poly1305_x64_sse2_message_mask[4] = { + (1 << 26) - 1, 0, (1 << 26) - 1, 0}; +static const uint32_t ALIGN(16) poly1305_x64_sse2_5[4] = {5, 0, 5, 0}; +static const uint32_t ALIGN(16) poly1305_x64_sse2_1shl128[4] = {(1 << 24), 0, + (1 << 24), 0}; + +static uint128_t INLINE add128(uint128_t a, uint128_t b) { return a + b; } + +static uint128_t INLINE add128_64(uint128_t a, uint64_t b) { return a + b; } + +static uint128_t INLINE mul64x64_128(uint64_t a, uint64_t b) { + return (uint128_t)a * b; +} + +static uint64_t INLINE lo128(uint128_t a) { return (uint64_t)a; } + +static uint64_t INLINE shr128(uint128_t v, const int shift) { + return (uint64_t)(v >> shift); +} + +static uint64_t INLINE shr128_pair(uint64_t hi, uint64_t lo, const int shift) { + return (uint64_t)((((uint128_t)hi << 64) | lo) >> shift); +} + +typedef struct poly1305_power_t { + union { + xmmi v; + uint64_t u[2]; + uint32_t d[4]; + } R20, R21, R22, R23, R24, S21, S22, S23, S24; +} poly1305_power; + +typedef struct poly1305_state_internal_t { + poly1305_power P[2]; /* 288 bytes, top 32 bit halves unused = 144 + bytes of free storage */ + union { + xmmi H[5]; /* 80 bytes */ + uint64_t HH[10]; + }; + /* uint64_t r0,r1,r2; [24 bytes] */ + /* uint64_t pad0,pad1; [16 bytes] */ + uint64_t started; /* 8 bytes */ + uint64_t leftover; /* 8 bytes */ + uint8_t buffer[64]; /* 64 bytes */ +} poly1305_state_internal; /* 448 bytes total + 63 bytes for + alignment = 511 bytes raw */ + +static poly1305_state_internal INLINE *poly1305_aligned_state( + poly1305_state *state) { + return (poly1305_state_internal *)(((uint64_t)state + 63) & ~63); +} + +/* copy 0-63 bytes */ +static void INLINE +poly1305_block_copy(uint8_t *dst, const uint8_t *src, size_t bytes) { + size_t offset = src - dst; + if (bytes & 32) { + _mm_storeu_si128((xmmi *)(dst + 0), + _mm_loadu_si128((xmmi *)(dst + offset + 0))); + _mm_storeu_si128((xmmi *)(dst + 16), + _mm_loadu_si128((xmmi *)(dst + offset + 16))); + dst += 32; + } + if (bytes & 16) { + _mm_storeu_si128((xmmi *)dst, _mm_loadu_si128((xmmi *)(dst + offset))); + dst += 16; + } + if (bytes & 8) { + *(uint64_t *)dst = *(uint64_t *)(dst + offset); + dst += 8; + } + if (bytes & 4) { + *(uint32_t *)dst = *(uint32_t *)(dst + offset); + dst += 4; + } + if (bytes & 2) { + *(uint16_t *)dst = *(uint16_t *)(dst + offset); + dst += 2; + } + if (bytes & 1) { + *(uint8_t *)dst = *(uint8_t *)(dst + offset); + } +} + +/* zero 0-15 bytes */ +static void INLINE poly1305_block_zero(uint8_t *dst, size_t bytes) { + if (bytes & 8) { + *(uint64_t *)dst = 0; + dst += 8; + } + if (bytes & 4) { + *(uint32_t *)dst = 0; + dst += 4; + } + if (bytes & 2) { + *(uint16_t *)dst = 0; + dst += 2; + } + if (bytes & 1) { + *(uint8_t *)dst = 0; + } +} + +static size_t INLINE poly1305_min(size_t a, size_t b) { + return (a < b) ? a : b; +} + +void CRYPTO_poly1305_init(poly1305_state *state, const uint8_t key[32]) { + poly1305_state_internal *st = poly1305_aligned_state(state); + poly1305_power *p; + uint64_t r0, r1, r2; + uint64_t t0, t1; + + /* clamp key */ + t0 = U8TO64_LE(key + 0); + t1 = U8TO64_LE(key + 8); + r0 = t0 & 0xffc0fffffff; + t0 >>= 44; + t0 |= t1 << 20; + r1 = t0 & 0xfffffc0ffff; + t1 >>= 24; + r2 = t1 & 0x00ffffffc0f; + + /* store r in un-used space of st->P[1] */ + p = &st->P[1]; + p->R20.d[1] = (uint32_t)(r0); + p->R20.d[3] = (uint32_t)(r0 >> 32); + p->R21.d[1] = (uint32_t)(r1); + p->R21.d[3] = (uint32_t)(r1 >> 32); + p->R22.d[1] = (uint32_t)(r2); + p->R22.d[3] = (uint32_t)(r2 >> 32); + + /* store pad */ + p->R23.d[1] = U8TO32_LE(key + 16); + p->R23.d[3] = U8TO32_LE(key + 20); + p->R24.d[1] = U8TO32_LE(key + 24); + p->R24.d[3] = U8TO32_LE(key + 28); + + /* H = 0 */ + st->H[0] = _mm_setzero_si128(); + st->H[1] = _mm_setzero_si128(); + st->H[2] = _mm_setzero_si128(); + st->H[3] = _mm_setzero_si128(); + st->H[4] = _mm_setzero_si128(); + + st->started = 0; + st->leftover = 0; +} + +static void poly1305_first_block(poly1305_state_internal *st, + const uint8_t *m) { + const xmmi MMASK = _mm_load_si128((xmmi *)poly1305_x64_sse2_message_mask); + const xmmi FIVE = _mm_load_si128((xmmi *)poly1305_x64_sse2_5); + const xmmi HIBIT = _mm_load_si128((xmmi *)poly1305_x64_sse2_1shl128); + xmmi T5, T6; + poly1305_power *p; + uint128_t d[3]; + uint64_t r0, r1, r2; + uint64_t r20, r21, r22, s22; + uint64_t pad0, pad1; + uint64_t c; + uint64_t i; + + /* pull out stored info */ + p = &st->P[1]; + + r0 = ((uint64_t)p->R20.d[3] << 32) | (uint64_t)p->R20.d[1]; + r1 = ((uint64_t)p->R21.d[3] << 32) | (uint64_t)p->R21.d[1]; + r2 = ((uint64_t)p->R22.d[3] << 32) | (uint64_t)p->R22.d[1]; + pad0 = ((uint64_t)p->R23.d[3] << 32) | (uint64_t)p->R23.d[1]; + pad1 = ((uint64_t)p->R24.d[3] << 32) | (uint64_t)p->R24.d[1]; + + /* compute powers r^2,r^4 */ + r20 = r0; + r21 = r1; + r22 = r2; + for (i = 0; i < 2; i++) { + s22 = r22 * (5 << 2); + + d[0] = add128(mul64x64_128(r20, r20), mul64x64_128(r21 * 2, s22)); + d[1] = add128(mul64x64_128(r22, s22), mul64x64_128(r20 * 2, r21)); + d[2] = add128(mul64x64_128(r21, r21), mul64x64_128(r22 * 2, r20)); + + r20 = lo128(d[0]) & 0xfffffffffff; + c = shr128(d[0], 44); + d[1] = add128_64(d[1], c); + r21 = lo128(d[1]) & 0xfffffffffff; + c = shr128(d[1], 44); + d[2] = add128_64(d[2], c); + r22 = lo128(d[2]) & 0x3ffffffffff; + c = shr128(d[2], 42); + r20 += c * 5; + c = (r20 >> 44); + r20 = r20 & 0xfffffffffff; + r21 += c; + + p->R20.v = _mm_shuffle_epi32(_mm_cvtsi32_si128((uint32_t)(r20)&0x3ffffff), + _MM_SHUFFLE(1, 0, 1, 0)); + p->R21.v = _mm_shuffle_epi32( + _mm_cvtsi32_si128((uint32_t)((r20 >> 26) | (r21 << 18)) & 0x3ffffff), + _MM_SHUFFLE(1, 0, 1, 0)); + p->R22.v = + _mm_shuffle_epi32(_mm_cvtsi32_si128((uint32_t)((r21 >> 8)) & 0x3ffffff), + _MM_SHUFFLE(1, 0, 1, 0)); + p->R23.v = _mm_shuffle_epi32( + _mm_cvtsi32_si128((uint32_t)((r21 >> 34) | (r22 << 10)) & 0x3ffffff), + _MM_SHUFFLE(1, 0, 1, 0)); + p->R24.v = _mm_shuffle_epi32(_mm_cvtsi32_si128((uint32_t)((r22 >> 16))), + _MM_SHUFFLE(1, 0, 1, 0)); + p->S21.v = _mm_mul_epu32(p->R21.v, FIVE); + p->S22.v = _mm_mul_epu32(p->R22.v, FIVE); + p->S23.v = _mm_mul_epu32(p->R23.v, FIVE); + p->S24.v = _mm_mul_epu32(p->R24.v, FIVE); + p--; + } + + /* put saved info back */ + p = &st->P[1]; + p->R20.d[1] = (uint32_t)(r0); + p->R20.d[3] = (uint32_t)(r0 >> 32); + p->R21.d[1] = (uint32_t)(r1); + p->R21.d[3] = (uint32_t)(r1 >> 32); + p->R22.d[1] = (uint32_t)(r2); + p->R22.d[3] = (uint32_t)(r2 >> 32); + p->R23.d[1] = (uint32_t)(pad0); + p->R23.d[3] = (uint32_t)(pad0 >> 32); + p->R24.d[1] = (uint32_t)(pad1); + p->R24.d[3] = (uint32_t)(pad1 >> 32); + + /* H = [Mx,My] */ + T5 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 0)), + _mm_loadl_epi64((xmmi *)(m + 16))); + T6 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 8)), + _mm_loadl_epi64((xmmi *)(m + 24))); + st->H[0] = _mm_and_si128(MMASK, T5); + st->H[1] = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12)); + st->H[2] = _mm_and_si128(MMASK, T5); + st->H[3] = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + st->H[4] = _mm_or_si128(_mm_srli_epi64(T6, 40), HIBIT); +} + +static void poly1305_blocks(poly1305_state_internal *st, const uint8_t *m, + size_t bytes) { + const xmmi MMASK = _mm_load_si128((xmmi *)poly1305_x64_sse2_message_mask); + const xmmi FIVE = _mm_load_si128((xmmi *)poly1305_x64_sse2_5); + const xmmi HIBIT = _mm_load_si128((xmmi *)poly1305_x64_sse2_1shl128); + + poly1305_power *p; + xmmi H0, H1, H2, H3, H4; + xmmi T0, T1, T2, T3, T4, T5, T6; + xmmi M0, M1, M2, M3, M4; + xmmi C1, C2; + + H0 = st->H[0]; + H1 = st->H[1]; + H2 = st->H[2]; + H3 = st->H[3]; + H4 = st->H[4]; + + while (bytes >= 64) { + /* H *= [r^4,r^4] */ + p = &st->P[0]; + T0 = _mm_mul_epu32(H0, p->R20.v); + T1 = _mm_mul_epu32(H0, p->R21.v); + T2 = _mm_mul_epu32(H0, p->R22.v); + T3 = _mm_mul_epu32(H0, p->R23.v); + T4 = _mm_mul_epu32(H0, p->R24.v); + T5 = _mm_mul_epu32(H1, p->S24.v); + T6 = _mm_mul_epu32(H1, p->R20.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H2, p->S23.v); + T6 = _mm_mul_epu32(H2, p->S24.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H3, p->S22.v); + T6 = _mm_mul_epu32(H3, p->S23.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H4, p->S21.v); + T6 = _mm_mul_epu32(H4, p->S22.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H1, p->R21.v); + T6 = _mm_mul_epu32(H1, p->R22.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H2, p->R20.v); + T6 = _mm_mul_epu32(H2, p->R21.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H3, p->S24.v); + T6 = _mm_mul_epu32(H3, p->R20.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H4, p->S23.v); + T6 = _mm_mul_epu32(H4, p->S24.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H1, p->R23.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H2, p->R22.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H3, p->R21.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H4, p->R20.v); + T4 = _mm_add_epi64(T4, T5); + + /* H += [Mx,My]*[r^2,r^2] */ + T5 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 0)), + _mm_loadl_epi64((xmmi *)(m + 16))); + T6 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 8)), + _mm_loadl_epi64((xmmi *)(m + 24))); + M0 = _mm_and_si128(MMASK, T5); + M1 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12)); + M2 = _mm_and_si128(MMASK, T5); + M3 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + M4 = _mm_or_si128(_mm_srli_epi64(T6, 40), HIBIT); + + p = &st->P[1]; + T5 = _mm_mul_epu32(M0, p->R20.v); + T6 = _mm_mul_epu32(M0, p->R21.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(M1, p->S24.v); + T6 = _mm_mul_epu32(M1, p->R20.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(M2, p->S23.v); + T6 = _mm_mul_epu32(M2, p->S24.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(M3, p->S22.v); + T6 = _mm_mul_epu32(M3, p->S23.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(M4, p->S21.v); + T6 = _mm_mul_epu32(M4, p->S22.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(M0, p->R22.v); + T6 = _mm_mul_epu32(M0, p->R23.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(M1, p->R21.v); + T6 = _mm_mul_epu32(M1, p->R22.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(M2, p->R20.v); + T6 = _mm_mul_epu32(M2, p->R21.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(M3, p->S24.v); + T6 = _mm_mul_epu32(M3, p->R20.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(M4, p->S23.v); + T6 = _mm_mul_epu32(M4, p->S24.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(M0, p->R24.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(M1, p->R23.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(M2, p->R22.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(M3, p->R21.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(M4, p->R20.v); + T4 = _mm_add_epi64(T4, T5); + + /* H += [Mx,My] */ + T5 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 32)), + _mm_loadl_epi64((xmmi *)(m + 48))); + T6 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 40)), + _mm_loadl_epi64((xmmi *)(m + 56))); + M0 = _mm_and_si128(MMASK, T5); + M1 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12)); + M2 = _mm_and_si128(MMASK, T5); + M3 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + M4 = _mm_or_si128(_mm_srli_epi64(T6, 40), HIBIT); + + T0 = _mm_add_epi64(T0, M0); + T1 = _mm_add_epi64(T1, M1); + T2 = _mm_add_epi64(T2, M2); + T3 = _mm_add_epi64(T3, M3); + T4 = _mm_add_epi64(T4, M4); + + /* reduce */ + C1 = _mm_srli_epi64(T0, 26); + C2 = _mm_srli_epi64(T3, 26); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_and_si128(T3, MMASK); + T1 = _mm_add_epi64(T1, C1); + T4 = _mm_add_epi64(T4, C2); + C1 = _mm_srli_epi64(T1, 26); + C2 = _mm_srli_epi64(T4, 26); + T1 = _mm_and_si128(T1, MMASK); + T4 = _mm_and_si128(T4, MMASK); + T2 = _mm_add_epi64(T2, C1); + T0 = _mm_add_epi64(T0, _mm_mul_epu32(C2, FIVE)); + C1 = _mm_srli_epi64(T2, 26); + C2 = _mm_srli_epi64(T0, 26); + T2 = _mm_and_si128(T2, MMASK); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_add_epi64(T3, C1); + T1 = _mm_add_epi64(T1, C2); + C1 = _mm_srli_epi64(T3, 26); + T3 = _mm_and_si128(T3, MMASK); + T4 = _mm_add_epi64(T4, C1); + + /* H = (H*[r^4,r^4] + [Mx,My]*[r^2,r^2] + [Mx,My]) */ + H0 = T0; + H1 = T1; + H2 = T2; + H3 = T3; + H4 = T4; + + m += 64; + bytes -= 64; + } + + st->H[0] = H0; + st->H[1] = H1; + st->H[2] = H2; + st->H[3] = H3; + st->H[4] = H4; +} + +static size_t poly1305_combine(poly1305_state_internal *st, const uint8_t *m, + size_t bytes) { + const xmmi MMASK = _mm_load_si128((xmmi *)poly1305_x64_sse2_message_mask); + const xmmi HIBIT = _mm_load_si128((xmmi *)poly1305_x64_sse2_1shl128); + const xmmi FIVE = _mm_load_si128((xmmi *)poly1305_x64_sse2_5); + + poly1305_power *p; + xmmi H0, H1, H2, H3, H4; + xmmi M0, M1, M2, M3, M4; + xmmi T0, T1, T2, T3, T4, T5, T6; + xmmi C1, C2; + + uint64_t r0, r1, r2; + uint64_t t0, t1, t2, t3, t4; + uint64_t c; + size_t consumed = 0; + + H0 = st->H[0]; + H1 = st->H[1]; + H2 = st->H[2]; + H3 = st->H[3]; + H4 = st->H[4]; + + /* p = [r^2,r^2] */ + p = &st->P[1]; + + if (bytes >= 32) { + /* H *= [r^2,r^2] */ + T0 = _mm_mul_epu32(H0, p->R20.v); + T1 = _mm_mul_epu32(H0, p->R21.v); + T2 = _mm_mul_epu32(H0, p->R22.v); + T3 = _mm_mul_epu32(H0, p->R23.v); + T4 = _mm_mul_epu32(H0, p->R24.v); + T5 = _mm_mul_epu32(H1, p->S24.v); + T6 = _mm_mul_epu32(H1, p->R20.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H2, p->S23.v); + T6 = _mm_mul_epu32(H2, p->S24.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H3, p->S22.v); + T6 = _mm_mul_epu32(H3, p->S23.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H4, p->S21.v); + T6 = _mm_mul_epu32(H4, p->S22.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H1, p->R21.v); + T6 = _mm_mul_epu32(H1, p->R22.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H2, p->R20.v); + T6 = _mm_mul_epu32(H2, p->R21.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H3, p->S24.v); + T6 = _mm_mul_epu32(H3, p->R20.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H4, p->S23.v); + T6 = _mm_mul_epu32(H4, p->S24.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H1, p->R23.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H2, p->R22.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H3, p->R21.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H4, p->R20.v); + T4 = _mm_add_epi64(T4, T5); + + /* H += [Mx,My] */ + T5 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 0)), + _mm_loadl_epi64((xmmi *)(m + 16))); + T6 = _mm_unpacklo_epi64(_mm_loadl_epi64((xmmi *)(m + 8)), + _mm_loadl_epi64((xmmi *)(m + 24))); + M0 = _mm_and_si128(MMASK, T5); + M1 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + T5 = _mm_or_si128(_mm_srli_epi64(T5, 52), _mm_slli_epi64(T6, 12)); + M2 = _mm_and_si128(MMASK, T5); + M3 = _mm_and_si128(MMASK, _mm_srli_epi64(T5, 26)); + M4 = _mm_or_si128(_mm_srli_epi64(T6, 40), HIBIT); + + T0 = _mm_add_epi64(T0, M0); + T1 = _mm_add_epi64(T1, M1); + T2 = _mm_add_epi64(T2, M2); + T3 = _mm_add_epi64(T3, M3); + T4 = _mm_add_epi64(T4, M4); + + /* reduce */ + C1 = _mm_srli_epi64(T0, 26); + C2 = _mm_srli_epi64(T3, 26); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_and_si128(T3, MMASK); + T1 = _mm_add_epi64(T1, C1); + T4 = _mm_add_epi64(T4, C2); + C1 = _mm_srli_epi64(T1, 26); + C2 = _mm_srli_epi64(T4, 26); + T1 = _mm_and_si128(T1, MMASK); + T4 = _mm_and_si128(T4, MMASK); + T2 = _mm_add_epi64(T2, C1); + T0 = _mm_add_epi64(T0, _mm_mul_epu32(C2, FIVE)); + C1 = _mm_srli_epi64(T2, 26); + C2 = _mm_srli_epi64(T0, 26); + T2 = _mm_and_si128(T2, MMASK); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_add_epi64(T3, C1); + T1 = _mm_add_epi64(T1, C2); + C1 = _mm_srli_epi64(T3, 26); + T3 = _mm_and_si128(T3, MMASK); + T4 = _mm_add_epi64(T4, C1); + + /* H = (H*[r^2,r^2] + [Mx,My]) */ + H0 = T0; + H1 = T1; + H2 = T2; + H3 = T3; + H4 = T4; + + consumed = 32; + } + + /* finalize, H *= [r^2,r] */ + r0 = ((uint64_t)p->R20.d[3] << 32) | (uint64_t)p->R20.d[1]; + r1 = ((uint64_t)p->R21.d[3] << 32) | (uint64_t)p->R21.d[1]; + r2 = ((uint64_t)p->R22.d[3] << 32) | (uint64_t)p->R22.d[1]; + + p->R20.d[2] = (uint32_t)(r0)&0x3ffffff; + p->R21.d[2] = (uint32_t)((r0 >> 26) | (r1 << 18)) & 0x3ffffff; + p->R22.d[2] = (uint32_t)((r1 >> 8)) & 0x3ffffff; + p->R23.d[2] = (uint32_t)((r1 >> 34) | (r2 << 10)) & 0x3ffffff; + p->R24.d[2] = (uint32_t)((r2 >> 16)); + p->S21.d[2] = p->R21.d[2] * 5; + p->S22.d[2] = p->R22.d[2] * 5; + p->S23.d[2] = p->R23.d[2] * 5; + p->S24.d[2] = p->R24.d[2] * 5; + + /* H *= [r^2,r] */ + T0 = _mm_mul_epu32(H0, p->R20.v); + T1 = _mm_mul_epu32(H0, p->R21.v); + T2 = _mm_mul_epu32(H0, p->R22.v); + T3 = _mm_mul_epu32(H0, p->R23.v); + T4 = _mm_mul_epu32(H0, p->R24.v); + T5 = _mm_mul_epu32(H1, p->S24.v); + T6 = _mm_mul_epu32(H1, p->R20.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H2, p->S23.v); + T6 = _mm_mul_epu32(H2, p->S24.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H3, p->S22.v); + T6 = _mm_mul_epu32(H3, p->S23.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H4, p->S21.v); + T6 = _mm_mul_epu32(H4, p->S22.v); + T0 = _mm_add_epi64(T0, T5); + T1 = _mm_add_epi64(T1, T6); + T5 = _mm_mul_epu32(H1, p->R21.v); + T6 = _mm_mul_epu32(H1, p->R22.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H2, p->R20.v); + T6 = _mm_mul_epu32(H2, p->R21.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H3, p->S24.v); + T6 = _mm_mul_epu32(H3, p->R20.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H4, p->S23.v); + T6 = _mm_mul_epu32(H4, p->S24.v); + T2 = _mm_add_epi64(T2, T5); + T3 = _mm_add_epi64(T3, T6); + T5 = _mm_mul_epu32(H1, p->R23.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H2, p->R22.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H3, p->R21.v); + T4 = _mm_add_epi64(T4, T5); + T5 = _mm_mul_epu32(H4, p->R20.v); + T4 = _mm_add_epi64(T4, T5); + + C1 = _mm_srli_epi64(T0, 26); + C2 = _mm_srli_epi64(T3, 26); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_and_si128(T3, MMASK); + T1 = _mm_add_epi64(T1, C1); + T4 = _mm_add_epi64(T4, C2); + C1 = _mm_srli_epi64(T1, 26); + C2 = _mm_srli_epi64(T4, 26); + T1 = _mm_and_si128(T1, MMASK); + T4 = _mm_and_si128(T4, MMASK); + T2 = _mm_add_epi64(T2, C1); + T0 = _mm_add_epi64(T0, _mm_mul_epu32(C2, FIVE)); + C1 = _mm_srli_epi64(T2, 26); + C2 = _mm_srli_epi64(T0, 26); + T2 = _mm_and_si128(T2, MMASK); + T0 = _mm_and_si128(T0, MMASK); + T3 = _mm_add_epi64(T3, C1); + T1 = _mm_add_epi64(T1, C2); + C1 = _mm_srli_epi64(T3, 26); + T3 = _mm_and_si128(T3, MMASK); + T4 = _mm_add_epi64(T4, C1); + + /* H = H[0]+H[1] */ + H0 = _mm_add_epi64(T0, _mm_srli_si128(T0, 8)); + H1 = _mm_add_epi64(T1, _mm_srli_si128(T1, 8)); + H2 = _mm_add_epi64(T2, _mm_srli_si128(T2, 8)); + H3 = _mm_add_epi64(T3, _mm_srli_si128(T3, 8)); + H4 = _mm_add_epi64(T4, _mm_srli_si128(T4, 8)); + + t0 = _mm_cvtsi128_si32(H0); + c = (t0 >> 26); + t0 &= 0x3ffffff; + t1 = _mm_cvtsi128_si32(H1) + c; + c = (t1 >> 26); + t1 &= 0x3ffffff; + t2 = _mm_cvtsi128_si32(H2) + c; + c = (t2 >> 26); + t2 &= 0x3ffffff; + t3 = _mm_cvtsi128_si32(H3) + c; + c = (t3 >> 26); + t3 &= 0x3ffffff; + t4 = _mm_cvtsi128_si32(H4) + c; + c = (t4 >> 26); + t4 &= 0x3ffffff; + t0 = t0 + (c * 5); + c = (t0 >> 26); + t0 &= 0x3ffffff; + t1 = t1 + c; + + st->HH[0] = ((t0) | (t1 << 26)) & 0xfffffffffffull; + st->HH[1] = ((t1 >> 18) | (t2 << 8) | (t3 << 34)) & 0xfffffffffffull; + st->HH[2] = ((t3 >> 10) | (t4 << 16)) & 0x3ffffffffffull; + + return consumed; +} + +void CRYPTO_poly1305_update(poly1305_state *state, const uint8_t *m, + size_t bytes) { + poly1305_state_internal *st = poly1305_aligned_state(state); + size_t want; + + /* need at least 32 initial bytes to start the accelerated branch */ + if (!st->started) { + if ((st->leftover == 0) && (bytes > 32)) { + poly1305_first_block(st, m); + m += 32; + bytes -= 32; + } else { + want = poly1305_min(32 - st->leftover, bytes); + poly1305_block_copy(st->buffer + st->leftover, m, want); + bytes -= want; + m += want; + st->leftover += want; + if ((st->leftover < 32) || (bytes == 0)) { + return; + } + poly1305_first_block(st, st->buffer); + st->leftover = 0; + } + st->started = 1; + } + + /* handle leftover */ + if (st->leftover) { + want = poly1305_min(64 - st->leftover, bytes); + poly1305_block_copy(st->buffer + st->leftover, m, want); + bytes -= want; + m += want; + st->leftover += want; + if (st->leftover < 64) { + return; + } + poly1305_blocks(st, st->buffer, 64); + st->leftover = 0; + } + + /* process 64 byte blocks */ + if (bytes >= 64) { + want = (bytes & ~63); + poly1305_blocks(st, m, want); + m += want; + bytes -= want; + } + + if (bytes) { + poly1305_block_copy(st->buffer + st->leftover, m, bytes); + st->leftover += bytes; + } +} + +void CRYPTO_poly1305_finish(poly1305_state *state, uint8_t mac[16]) { + poly1305_state_internal *st = poly1305_aligned_state(state); + size_t leftover = st->leftover; + uint8_t *m = st->buffer; + uint128_t d[3]; + uint64_t h0, h1, h2; + uint64_t t0, t1; + uint64_t g0, g1, g2, c, nc; + uint64_t r0, r1, r2, s1, s2; + poly1305_power *p; + + if (st->started) { + size_t consumed = poly1305_combine(st, m, leftover); + leftover -= consumed; + m += consumed; + } + + /* st->HH will either be 0 or have the combined result */ + h0 = st->HH[0]; + h1 = st->HH[1]; + h2 = st->HH[2]; + + p = &st->P[1]; + r0 = ((uint64_t)p->R20.d[3] << 32) | (uint64_t)p->R20.d[1]; + r1 = ((uint64_t)p->R21.d[3] << 32) | (uint64_t)p->R21.d[1]; + r2 = ((uint64_t)p->R22.d[3] << 32) | (uint64_t)p->R22.d[1]; + s1 = r1 * (5 << 2); + s2 = r2 * (5 << 2); + + if (leftover < 16) { + goto poly1305_donna_atmost15bytes; + } + +poly1305_donna_atleast16bytes: + t0 = U8TO64_LE(m + 0); + t1 = U8TO64_LE(m + 8); + h0 += t0 & 0xfffffffffff; + t0 = shr128_pair(t1, t0, 44); + h1 += t0 & 0xfffffffffff; + h2 += (t1 >> 24) | ((uint64_t)1 << 40); + +poly1305_donna_mul: + d[0] = add128(add128(mul64x64_128(h0, r0), mul64x64_128(h1, s2)), + mul64x64_128(h2, s1)); + d[1] = add128(add128(mul64x64_128(h0, r1), mul64x64_128(h1, r0)), + mul64x64_128(h2, s2)); + d[2] = add128(add128(mul64x64_128(h0, r2), mul64x64_128(h1, r1)), + mul64x64_128(h2, r0)); + h0 = lo128(d[0]) & 0xfffffffffff; + c = shr128(d[0], 44); + d[1] = add128_64(d[1], c); + h1 = lo128(d[1]) & 0xfffffffffff; + c = shr128(d[1], 44); + d[2] = add128_64(d[2], c); + h2 = lo128(d[2]) & 0x3ffffffffff; + c = shr128(d[2], 42); + h0 += c * 5; + + m += 16; + leftover -= 16; + if (leftover >= 16) { + goto poly1305_donna_atleast16bytes; + } + +/* final bytes */ +poly1305_donna_atmost15bytes: + if (!leftover) { + goto poly1305_donna_finish; + } + + m[leftover++] = 1; + poly1305_block_zero(m + leftover, 16 - leftover); + leftover = 16; + + t0 = U8TO64_LE(m + 0); + t1 = U8TO64_LE(m + 8); + h0 += t0 & 0xfffffffffff; + t0 = shr128_pair(t1, t0, 44); + h1 += t0 & 0xfffffffffff; + h2 += (t1 >> 24); + + goto poly1305_donna_mul; + +poly1305_donna_finish: + c = (h0 >> 44); + h0 &= 0xfffffffffff; + h1 += c; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + h2 += c; + c = (h2 >> 42); + h2 &= 0x3ffffffffff; + h0 += c * 5; + + g0 = h0 + 5; + c = (g0 >> 44); + g0 &= 0xfffffffffff; + g1 = h1 + c; + c = (g1 >> 44); + g1 &= 0xfffffffffff; + g2 = h2 + c - ((uint64_t)1 << 42); + + c = (g2 >> 63) - 1; + nc = ~c; + h0 = (h0 & nc) | (g0 & c); + h1 = (h1 & nc) | (g1 & c); + h2 = (h2 & nc) | (g2 & c); + + /* pad */ + t0 = ((uint64_t)p->R23.d[3] << 32) | (uint64_t)p->R23.d[1]; + t1 = ((uint64_t)p->R24.d[3] << 32) | (uint64_t)p->R24.d[1]; + h0 += (t0 & 0xfffffffffff); + c = (h0 >> 44); + h0 &= 0xfffffffffff; + t0 = shr128_pair(t1, t0, 44); + h1 += (t0 & 0xfffffffffff) + c; + c = (h1 >> 44); + h1 &= 0xfffffffffff; + t1 = (t1 >> 24); + h2 += (t1)+c; + + U64TO8_LE(mac + 0, ((h0) | (h1 << 44))); + U64TO8_LE(mac + 8, ((h1 >> 20) | (h2 << 24))); +} + +#endif /* !OPENSSL_WINDOWS && OPENSSL_X86_64 */ diff --git a/TMessagesProj/jni/boringssl/crypto/rand/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/rand/CMakeLists.txt new file mode 100644 index 00000000..374d8f17 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rand/CMakeLists.txt @@ -0,0 +1,24 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "x86_64") + set( + RAND_ARCH_SOURCES + + rdrand-x86_64.${ASM_EXT} + ) +endif() + +add_library( + rand + + OBJECT + + rand.c + urandom.c + windows.c + hwrand.c + + ${RAND_ARCH_SOURCES} +) + +perlasm(rdrand-x86_64.${ASM_EXT} asm/rdrand-x86_64.pl) diff --git a/TMessagesProj/jni/boringssl/crypto/rand/asm/rdrand-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/rand/asm/rdrand-x86_64.pl new file mode 100644 index 00000000..c32a55c4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rand/asm/rdrand-x86_64.pl @@ -0,0 +1,75 @@ +#!/usr/bin/env perl + +# Copyright (c) 2015, Google Inc. +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +print<<___; +.text + +# CRYPTO_rdrand writes eight bytes of random data from the hardware RNG to +# |out|. It returns one on success or zero on hardware failure. +# int CRYPTO_rdrand(uint8_t out[8]); +.globl CRYPTO_rdrand +.type CRYPTO_rdrand,\@function,1 +.align 16 +CRYPTO_rdrand: + xorq %rax, %rax + # This is rdrand %rcx. It sets rcx to a random value and sets the carry + # flag on success. + .byte 0x48, 0x0f, 0xc7, 0xf1 + # An add-with-carry of zero effectively sets %rax to the carry flag. + adcq %rax, %rax + movq %rcx, 0(%rdi) + retq + +# CRYPTO_rdrand_multiple8_buf fills |len| bytes at |buf| with random data from +# the hardware RNG. The |len| argument must be a multiple of eight. It returns +# one on success and zero on hardware failure. +# int CRYPTO_rdrand_multiple8_buf(uint8_t *buf, size_t len); +.globl CRYPTO_rdrand_multiple8_buf +.type CRYPTO_rdrand_multiple8_buf,\@function,2 +.align 16 +CRYPTO_rdrand_multiple8_buf: + test %rsi, %rsi + jz .Lout + movq \$8, %rdx +.Lloop: + # This is rdrand %rcx. It sets rcx to a random value and sets the carry + # flag on success. + .byte 0x48, 0x0f, 0xc7, 0xf1 + jnc .Lerr + movq %rcx, 0(%rdi) + addq %rdx, %rdi + subq %rdx, %rsi + jnz .Lloop +.Lout: + movq \$1, %rax + retq +.Lerr: + xorq %rax, %rax + retq +___ + +close STDOUT; # flush diff --git a/TMessagesProj/jni/boringssl/crypto/rand/hwrand.c b/TMessagesProj/jni/boringssl/crypto/rand/hwrand.c new file mode 100644 index 00000000..f0bbccd2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rand/hwrand.c @@ -0,0 +1,65 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + +#include + +#include "internal.h" + + +#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM) + +/* These functions are defined in asm/rdrand-x86_64.pl */ +extern int CRYPTO_rdrand(uint8_t out[8]); +extern int CRYPTO_rdrand_multiple8_buf(uint8_t *buf, size_t len); + +static int have_rdrand(void) { + return (OPENSSL_ia32cap_P[1] & (1u << 30)) != 0; +} + +int CRYPTO_hwrand(uint8_t *buf, size_t len) { + if (!have_rdrand()) { + return 0; + } + + const size_t len_multiple8 = len & ~7; + if (!CRYPTO_rdrand_multiple8_buf(buf, len_multiple8)) { + return 0; + } + len -= len_multiple8; + + if (len != 0) { + assert(len < 8); + + uint8_t rand_buf[8]; + if (!CRYPTO_rdrand(rand_buf)) { + return 0; + } + memcpy(buf + len_multiple8, rand_buf, len); + } + + return 1; +} + +#else + +int CRYPTO_hwrand(uint8_t *buf, size_t len) { + return 0; +} + +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/rand/internal.h b/TMessagesProj/jni/boringssl/crypto/rand/internal.h new file mode 100644 index 00000000..f35abbbe --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rand/internal.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_CRYPTO_RAND_INTERNAL_H +#define OPENSSL_HEADER_CRYPTO_RAND_INTERNAL_H + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* CRYPTO_sysrand fills |len| bytes at |buf| with entropy from the operating + * system. */ +void CRYPTO_sysrand(uint8_t *buf, size_t len); + +/* CRYPTO_hwrand fills |len| bytes at |buf| with entropy from the hardware. It + * returns one on success or zero on hardware failure or if hardware support is + * unavailable. */ +int CRYPTO_hwrand(uint8_t *buf, size_t len); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CRYPTO_RAND_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/rand/rand.c b/TMessagesProj/jni/boringssl/crypto/rand/rand.c new file mode 100644 index 00000000..e76a120d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rand/rand.c @@ -0,0 +1,186 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include +#include + +#include +#include + +#include "internal.h" +#include "../internal.h" + + +/* It's assumed that the operating system always has an unfailing source of + * entropy which is accessed via |CRYPTO_sysrand|. (If the operating system + * entropy source fails, it's up to |CRYPTO_sysrand| to abort the process—we + * don't try to handle it.) + * + * In addition, the hardware may provide a low-latency RNG. Intel's rdrand + * instruction is the canonical example of this. When a hardware RNG is + * available we don't need to worry about an RNG failure arising from fork()ing + * the process or moving a VM, so we can keep thread-local RNG state and XOR + * the hardware entropy in. + * + * (We assume that the OS entropy is safe from fork()ing and VM duplication. + * This might be a bit of a leap of faith, esp on Windows, but there's nothing + * that we can do about it.) */ + +/* rand_thread_state contains the per-thread state for the RNG. This is only + * used if the system has support for a hardware RNG. */ +struct rand_thread_state { + uint8_t key[32]; + uint64_t calls_used; + size_t bytes_used; + uint8_t partial_block[64]; + unsigned partial_block_used; +}; + +/* kMaxCallsPerRefresh is the maximum number of |RAND_bytes| calls that we'll + * serve before reading a new key from the operating system. This only applies + * if we have a hardware RNG. */ +static const unsigned kMaxCallsPerRefresh = 1024; + +/* kMaxBytesPerRefresh is the maximum number of bytes that we'll return from + * |RAND_bytes| before reading a new key from the operating system. This only + * applies if we have a hardware RNG. */ +static const uint64_t kMaxBytesPerRefresh = 1024 * 1024; + +/* rand_thread_state_free frees a |rand_thread_state|. This is called when a + * thread exits. */ +static void rand_thread_state_free(void *state) { + if (state == NULL) { + return; + } + + OPENSSL_cleanse(state, sizeof(struct rand_thread_state)); + OPENSSL_free(state); +} + +int RAND_bytes(uint8_t *buf, size_t len) { + if (len == 0) { + return 1; + } + + if (!CRYPTO_hwrand(buf, len)) { + /* Without a hardware RNG to save us from address-space duplication, the OS + * entropy is used directly. */ + CRYPTO_sysrand(buf, len); + return 1; + } + + struct rand_thread_state *state = + CRYPTO_get_thread_local(OPENSSL_THREAD_LOCAL_RAND); + if (state == NULL) { + state = OPENSSL_malloc(sizeof(struct rand_thread_state)); + if (state == NULL || + !CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_RAND, state, + rand_thread_state_free)) { + CRYPTO_sysrand(buf, len); + return 1; + } + + memset(state->partial_block, 0, sizeof(state->partial_block)); + state->calls_used = kMaxCallsPerRefresh; + } + + if (state->calls_used >= kMaxCallsPerRefresh || + state->bytes_used >= kMaxBytesPerRefresh) { + CRYPTO_sysrand(state->key, sizeof(state->key)); + state->calls_used = 0; + state->bytes_used = 0; + state->partial_block_used = sizeof(state->partial_block); + } + + if (len >= sizeof(state->partial_block)) { + size_t remaining = len; + while (remaining > 0) { + // kMaxBytesPerCall is only 2GB, while ChaCha can handle 256GB. But this + // is sufficient and easier on 32-bit. + static const size_t kMaxBytesPerCall = 0x80000000; + size_t todo = remaining; + if (todo > kMaxBytesPerCall) { + todo = kMaxBytesPerCall; + } + CRYPTO_chacha_20(buf, buf, todo, state->key, + (uint8_t *)&state->calls_used, 0); + buf += todo; + remaining -= todo; + state->calls_used++; + } + } else { + if (sizeof(state->partial_block) - state->partial_block_used < len) { + CRYPTO_chacha_20(state->partial_block, state->partial_block, + sizeof(state->partial_block), state->key, + (uint8_t *)&state->calls_used, 0); + state->partial_block_used = 0; + } + + unsigned i; + for (i = 0; i < len; i++) { + buf[i] ^= state->partial_block[state->partial_block_used++]; + } + state->calls_used++; + } + state->bytes_used += len; + + return 1; +} + +int RAND_pseudo_bytes(uint8_t *buf, size_t len) { + return RAND_bytes(buf, len); +} + +void RAND_seed(const void *buf, int num) {} + +int RAND_load_file(const char *path, long num) { + if (num < 0) { /* read the "whole file" */ + return 1; + } else if (num <= INT_MAX) { + return (int) num; + } else { + return INT_MAX; + } +} + +void RAND_add(const void *buf, int num, double entropy) {} + +int RAND_egd(const char *path) { + return 255; +} + +int RAND_poll(void) { + return 1; +} + +int RAND_status(void) { + return 1; +} + +static const struct rand_meth_st kSSLeayMethod = { + RAND_seed, + RAND_bytes, + RAND_cleanup, + RAND_add, + RAND_pseudo_bytes, + RAND_status, +}; + +RAND_METHOD *RAND_SSLeay(void) { + return (RAND_METHOD*) &kSSLeayMethod; +} + +void RAND_set_rand_method(const RAND_METHOD *method) {} diff --git a/TMessagesProj/jni/boringssl/crypto/rand/urandom.c b/TMessagesProj/jni/boringssl/crypto/rand/urandom.c new file mode 100644 index 00000000..d7ed5c62 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rand/urandom.c @@ -0,0 +1,264 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#if !defined(OPENSSL_WINDOWS) + +#include +#include +#include +#include +#include + +#include +#include + +#include "internal.h" +#include "../internal.h" + + +/* This file implements a PRNG by reading from /dev/urandom, optionally with a + * fork-safe buffer. + * + * If buffering is enabled then it maintains a global, linked list of buffers. + * Threads which need random bytes grab a buffer from the list under a lock and + * copy out the bytes that they need. In the rare case that the buffer is + * empty, it's refilled from /dev/urandom outside of the lock. + * + * Large requests are always serviced from /dev/urandom directly. + * + * Each buffer contains the PID of the process that created it and it's tested + * against the current PID each time. Thus processes that fork will discard all + * the buffers filled by the parent process. There are two problems with this: + * + * 1) glibc maintains a cache of the current PID+PPID and, if this cache isn't + * correctly invalidated, the getpid() will continue to believe that + * it's the old process. Glibc depends on the glibc wrappers for fork, + * vfork and clone being used in order to invalidate the getpid() cache. + * + * 2) If a process forks, dies and then its child forks, it's possible that + * the third process will end up with the same PID as the original process. + * If the second process never used any random values then this will mean + * that the third process has stale, cached values and won't notice. + */ + +/* BUF_SIZE is intended to be a 4K allocation with malloc overhead. struct + * rand_buffer also fits in this space and the remainder is entropy. */ +#define BUF_SIZE (4096 - 16) + +/* rand_buffer contains unused, random bytes. These structures form a linked + * list via the |next| pointer, which is NULL in the final element. */ +struct rand_buffer { + size_t used; /* used contains the number of bytes of |rand| that have + been consumed. */ + struct rand_buffer *next; + pid_t pid; /* pid contains the pid at the time that the buffer was + created so that data is not duplicated after a fork. */ + pid_t ppid; /* ppid contains the parent pid in order to try and reduce + the possibility of duplicated PID confusing the + detection of a fork. */ + uint8_t rand[]; +}; + +/* rand_bytes_per_buf is the number of actual entropy bytes in a buffer. */ +static const size_t rand_bytes_per_buf = BUF_SIZE - sizeof(struct rand_buffer); + +static struct CRYPTO_STATIC_MUTEX global_lock = CRYPTO_STATIC_MUTEX_INIT; + +/* list_head is the start of a global, linked-list of rand_buffer objects. It's + * protected by |global_lock|. */ +static struct rand_buffer *list_head; + +/* urandom_fd is a file descriptor to /dev/urandom. It's protected by + * |global_lock|. */ +static int urandom_fd = -2; + +/* urandom_buffering controls whether buffering is enabled (1) or not (0). This + * is protected by |global_lock|. */ +static int urandom_buffering = 0; + +/* urandom_get_fd_locked returns a file descriptor to /dev/urandom. The caller + * of this function must hold |global_lock|. */ +static int urandom_get_fd_locked(void) { + if (urandom_fd != -2) { + return urandom_fd; + } + + do { + urandom_fd = open("/dev/urandom", O_RDONLY); + } while (urandom_fd == -1 && errno == EINTR); + return urandom_fd; +} + +/* RAND_cleanup frees all buffers, closes any cached file descriptor + * and resets the global state. */ +void RAND_cleanup(void) { + struct rand_buffer *cur; + + CRYPTO_STATIC_MUTEX_lock_write(&global_lock); + while ((cur = list_head)) { + list_head = cur->next; + OPENSSL_free(cur); + } + if (urandom_fd >= 0) { + close(urandom_fd); + } + urandom_fd = -2; + list_head = NULL; + CRYPTO_STATIC_MUTEX_unlock(&global_lock); +} + +void RAND_set_urandom_fd(int fd) { + CRYPTO_STATIC_MUTEX_lock_write(&global_lock); + if (urandom_fd != -2) { + /* |RAND_set_urandom_fd| may not be called after the RNG is used. */ + abort(); + } + do { + urandom_fd = dup(fd); + } while (urandom_fd == -1 && errno == EINTR); + if (urandom_fd < 0) { + abort(); + } + CRYPTO_STATIC_MUTEX_unlock(&global_lock); +} + +/* read_full reads exactly |len| bytes from |fd| into |out| and returns 1. In + * the case of an error it returns 0. */ +static char read_full(int fd, uint8_t *out, size_t len) { + ssize_t r; + + while (len > 0) { + do { + r = read(fd, out, len); + } while (r == -1 && errno == EINTR); + + if (r <= 0) { + return 0; + } + out += r; + len -= r; + } + + return 1; +} + +/* CRYPTO_sysrand puts |num| random bytes into |out|. */ +void CRYPTO_sysrand(uint8_t *out, size_t requested) { + int fd; + struct rand_buffer *buf; + size_t todo; + pid_t pid, ppid; + + if (requested == 0) { + return; + } + + CRYPTO_STATIC_MUTEX_lock_write(&global_lock); + fd = urandom_get_fd_locked(); + + if (fd < 0) { + CRYPTO_STATIC_MUTEX_unlock(&global_lock); + abort(); + return; + } + + /* If buffering is not enabled, or if the request is large, then the + * result comes directly from urandom. */ + if (!urandom_buffering || requested > BUF_SIZE / 2) { + CRYPTO_STATIC_MUTEX_unlock(&global_lock); + if (!read_full(fd, out, requested)) { + abort(); + } + return; + } + + pid = getpid(); + ppid = getppid(); + + for (;;) { + buf = list_head; + if (buf && buf->pid == pid && buf->ppid == ppid && + rand_bytes_per_buf - buf->used >= requested) { + memcpy(out, &buf->rand[buf->used], requested); + buf->used += requested; + CRYPTO_STATIC_MUTEX_unlock(&global_lock); + return; + } + + /* If we don't immediately have enough entropy with the correct + * PID, remove the buffer from the list in order to gain + * exclusive access and unlock. */ + if (buf) { + list_head = buf->next; + } + CRYPTO_STATIC_MUTEX_unlock(&global_lock); + + if (!buf) { + buf = (struct rand_buffer *)OPENSSL_malloc(BUF_SIZE); + if (!buf) { + abort(); + return; + } + /* The buffer doesn't contain any random bytes yet + * so we mark it as fully used so that it will be + * filled below. */ + buf->used = rand_bytes_per_buf; + buf->next = NULL; + buf->pid = pid; + buf->ppid = ppid; + } + + if (buf->pid == pid && buf->ppid == ppid) { + break; + } + + /* We have forked and so cannot use these bytes as they + * may have been used in another process. */ + OPENSSL_free(buf); + CRYPTO_STATIC_MUTEX_lock_write(&global_lock); + } + + while (requested > 0) { + todo = rand_bytes_per_buf - buf->used; + if (todo > requested) { + todo = requested; + } + memcpy(out, &buf->rand[buf->used], todo); + requested -= todo; + out += todo; + buf->used += todo; + + if (buf->used < rand_bytes_per_buf) { + break; + } + + if (!read_full(fd, buf->rand, rand_bytes_per_buf)) { + OPENSSL_free(buf); + abort(); + return; + } + + buf->used = 0; + } + + CRYPTO_STATIC_MUTEX_lock_write(&global_lock); + assert(list_head != buf); + buf->next = list_head; + list_head = buf; + CRYPTO_STATIC_MUTEX_unlock(&global_lock); +} + +#endif /* !OPENSSL_WINDOWS */ diff --git a/TMessagesProj/jni/boringssl/crypto/rand/windows.c b/TMessagesProj/jni/boringssl/crypto/rand/windows.c new file mode 100644 index 00000000..1a0cb8b0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rand/windows.c @@ -0,0 +1,56 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#if defined(OPENSSL_WINDOWS) + +#include +#include + +#pragma warning(push, 3) + +#include + +/* #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the + * "Community Additions" comment on MSDN here: + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx */ +#define SystemFunction036 NTAPI SystemFunction036 +#include +#undef SystemFunction036 + +#pragma warning(pop) + +#include "internal.h" + + +void RAND_cleanup(void) { +} + +void CRYPTO_sysrand(uint8_t *out, size_t requested) { + while (requested > 0) { + ULONG output_bytes_this_pass = ULONG_MAX; + if (requested < output_bytes_this_pass) { + output_bytes_this_pass = requested; + } + if (RtlGenRandom(out, output_bytes_this_pass) == FALSE) { + abort(); + } + requested -= output_bytes_this_pass; + out += output_bytes_this_pass; + } + return; +} + +#endif /* OPENSSL_WINDOWS */ diff --git a/TMessagesProj/jni/boringssl/crypto/rc4/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/rc4/CMakeLists.txt new file mode 100644 index 00000000..fe2d0c65 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rc4/CMakeLists.txt @@ -0,0 +1,31 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "x86_64") + set( + RC4_ARCH_SOURCES + + rc4-x86_64.${ASM_EXT} + rc4-md5-x86_64.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "x86") + set( + RC4_ARCH_SOURCES + + rc4-586.${ASM_EXT} + ) +endif() + +add_library( + rc4 + + OBJECT + + rc4.c + ${RC4_ARCH_SOURCES} +) + +perlasm(rc4-x86_64.${ASM_EXT} asm/rc4-x86_64.pl) +perlasm(rc4-md5-x86_64.${ASM_EXT} asm/rc4-md5-x86_64.pl) +perlasm(rc4-586.${ASM_EXT} asm/rc4-586.pl) diff --git a/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-586.pl b/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-586.pl new file mode 100644 index 00000000..fc860ae2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-586.pl @@ -0,0 +1,414 @@ +#!/usr/bin/env perl + +# ==================================================================== +# [Re]written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# At some point it became apparent that the original SSLeay RC4 +# assembler implementation performs suboptimally on latest IA-32 +# microarchitectures. After re-tuning performance has changed as +# following: +# +# Pentium -10% +# Pentium III +12% +# AMD +50%(*) +# P4 +250%(**) +# +# (*) This number is actually a trade-off:-) It's possible to +# achieve +72%, but at the cost of -48% off PIII performance. +# In other words code performing further 13% faster on AMD +# would perform almost 2 times slower on Intel PIII... +# For reference! This code delivers ~80% of rc4-amd64.pl +# performance on the same Opteron machine. +# (**) This number requires compressed key schedule set up by +# RC4_set_key [see commentary below for further details]. +# +# + +# May 2011 +# +# Optimize for Core2 and Westmere [and incidentally Opteron]. Current +# performance in cycles per processed byte (less is better) and +# improvement relative to previous version of this module is: +# +# Pentium 10.2 # original numbers +# Pentium III 7.8(*) +# Intel P4 7.5 +# +# Opteron 6.1/+20% # new MMX numbers +# Core2 5.3/+67%(**) +# Westmere 5.1/+94%(**) +# Sandy Bridge 5.0/+8% +# Atom 12.6/+6% +# +# (*) PIII can actually deliver 6.6 cycles per byte with MMX code, +# but this specific code performs poorly on Core2. And vice +# versa, below MMX/SSE code delivering 5.8/7.1 on Core2 performs +# poorly on PIII, at 8.0/14.5:-( As PIII is not a "hot" CPU +# [anymore], I chose to discard PIII-specific code path and opt +# for original IALU-only code, which is why MMX/SSE code path +# is guarded by SSE2 bit (see below), not MMX/SSE. +# (**) Performance vs. block size on Core2 and Westmere had a maximum +# at ... 64 bytes block size. And it was quite a maximum, 40-60% +# in comparison to largest 8KB block size. Above improvement +# coefficients are for the largest block size. + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],"rc4-586.pl",$x86only = $ARGV[$#ARGV] eq "386"); + +$xx="eax"; +$yy="ebx"; +$tx="ecx"; +$ty="edx"; +$inp="esi"; +$out="ebp"; +$dat="edi"; + +sub RC4_loop { + my $i=shift; + my $func = ($i==0)?*mov:*or; + + &add (&LB($yy),&LB($tx)); + &mov ($ty,&DWP(0,$dat,$yy,4)); + &mov (&DWP(0,$dat,$yy,4),$tx); + &mov (&DWP(0,$dat,$xx,4),$ty); + &add ($ty,$tx); + &inc (&LB($xx)); + &and ($ty,0xff); + &ror ($out,8) if ($i!=0); + if ($i<3) { + &mov ($tx,&DWP(0,$dat,$xx,4)); + } else { + &mov ($tx,&wparam(3)); # reload [re-biased] out + } + &$func ($out,&DWP(0,$dat,$ty,4)); +} + +if ($alt=0) { + # >20% faster on Atom and Sandy Bridge[!], 8% faster on Opteron, + # but ~40% slower on Core2 and Westmere... Attempt to add movz + # brings down Opteron by 25%, Atom and Sandy Bridge by 15%, yet + # on Core2 with movz it's almost 20% slower than below alternative + # code... Yes, it's a total mess... + my @XX=($xx,$out); + $RC4_loop_mmx = sub { # SSE actually... + my $i=shift; + my $j=$i<=0?0:$i>>1; + my $mm=$i<=0?"mm0":"mm".($i&1); + + &add (&LB($yy),&LB($tx)); + &lea (@XX[1],&DWP(1,@XX[0])); + &pxor ("mm2","mm0") if ($i==0); + &psllq ("mm1",8) if ($i==0); + &and (@XX[1],0xff); + &pxor ("mm0","mm0") if ($i<=0); + &mov ($ty,&DWP(0,$dat,$yy,4)); + &mov (&DWP(0,$dat,$yy,4),$tx); + &pxor ("mm1","mm2") if ($i==0); + &mov (&DWP(0,$dat,$XX[0],4),$ty); + &add (&LB($ty),&LB($tx)); + &movd (@XX[0],"mm7") if ($i==0); + &mov ($tx,&DWP(0,$dat,@XX[1],4)); + &pxor ("mm1","mm1") if ($i==1); + &movq ("mm2",&QWP(0,$inp)) if ($i==1); + &movq (&QWP(-8,(@XX[0],$inp)),"mm1") if ($i==0); + &pinsrw ($mm,&DWP(0,$dat,$ty,4),$j); + + push (@XX,shift(@XX)) if ($i>=0); + } +} else { + # Using pinsrw here improves performane on Intel CPUs by 2-3%, but + # brings down AMD by 7%... + $RC4_loop_mmx = sub { + my $i=shift; + + &add (&LB($yy),&LB($tx)); + &psllq ("mm1",8*(($i-1)&7)) if (abs($i)!=1); + &mov ($ty,&DWP(0,$dat,$yy,4)); + &mov (&DWP(0,$dat,$yy,4),$tx); + &mov (&DWP(0,$dat,$xx,4),$ty); + &inc ($xx); + &add ($ty,$tx); + &movz ($xx,&LB($xx)); # (*) + &movz ($ty,&LB($ty)); # (*) + &pxor ("mm2",$i==1?"mm0":"mm1") if ($i>=0); + &movq ("mm0",&QWP(0,$inp)) if ($i<=0); + &movq (&QWP(-8,($out,$inp)),"mm2") if ($i==0); + &mov ($tx,&DWP(0,$dat,$xx,4)); + &movd ($i>0?"mm1":"mm2",&DWP(0,$dat,$ty,4)); + + # (*) This is the key to Core2 and Westmere performance. + # Whithout movz out-of-order execution logic confuses + # itself and fails to reorder loads and stores. Problem + # appears to be fixed in Sandy Bridge... + } +} + +&external_label("OPENSSL_ia32cap_P"); + +# void asm_RC4(RC4_KEY *key,size_t len,const unsigned char *inp,unsigned char *out); +&function_begin("asm_RC4"); + &mov ($dat,&wparam(0)); # load key schedule pointer + &mov ($ty, &wparam(1)); # load len + &mov ($inp,&wparam(2)); # load inp + &mov ($out,&wparam(3)); # load out + + &xor ($xx,$xx); # avoid partial register stalls + &xor ($yy,$yy); + + &cmp ($ty,0); # safety net + &je (&label("abort")); + + &mov (&LB($xx),&BP(0,$dat)); # load key->x + &mov (&LB($yy),&BP(4,$dat)); # load key->y + &add ($dat,8); + + &lea ($tx,&DWP(0,$inp,$ty)); + &sub ($out,$inp); # re-bias out + &mov (&wparam(1),$tx); # save input+len + + &inc (&LB($xx)); + + # detect compressed key schedule... + &cmp (&DWP(256,$dat),-1); + &je (&label("RC4_CHAR")); + + &mov ($tx,&DWP(0,$dat,$xx,4)); + + &and ($ty,-4); # how many 4-byte chunks? + &jz (&label("loop1")); + + &mov (&wparam(3),$out); # $out as accumulator in these loops + if ($x86only) { + &jmp (&label("go4loop4")); + } else { + &test ($ty,-8); + &jz (&label("go4loop4")); + + &picmeup($out,"OPENSSL_ia32cap_P"); + &bt (&DWP(0,$out),26); # check SSE2 bit [could have been MMX] + &jnc (&label("go4loop4")); + + &mov ($out,&wparam(3)) if (!$alt); + &movd ("mm7",&wparam(3)) if ($alt); + &and ($ty,-8); + &lea ($ty,&DWP(-8,$inp,$ty)); + &mov (&DWP(-4,$dat),$ty); # save input+(len/8)*8-8 + + &$RC4_loop_mmx(-1); + &jmp(&label("loop_mmx_enter")); + + &set_label("loop_mmx",16); + &$RC4_loop_mmx(0); + &set_label("loop_mmx_enter"); + for ($i=1;$i<8;$i++) { &$RC4_loop_mmx($i); } + &mov ($ty,$yy); + &xor ($yy,$yy); # this is second key to Core2 + &mov (&LB($yy),&LB($ty)); # and Westmere performance... + &cmp ($inp,&DWP(-4,$dat)); + &lea ($inp,&DWP(8,$inp)); + &jb (&label("loop_mmx")); + + if ($alt) { + &movd ($out,"mm7"); + &pxor ("mm2","mm0"); + &psllq ("mm1",8); + &pxor ("mm1","mm2"); + &movq (&QWP(-8,$out,$inp),"mm1"); + } else { + &psllq ("mm1",56); + &pxor ("mm2","mm1"); + &movq (&QWP(-8,$out,$inp),"mm2"); + } + &emms (); + + &cmp ($inp,&wparam(1)); # compare to input+len + &je (&label("done")); + &jmp (&label("loop1")); + } + +&set_label("go4loop4",16); + &lea ($ty,&DWP(-4,$inp,$ty)); + &mov (&wparam(2),$ty); # save input+(len/4)*4-4 + + &set_label("loop4"); + for ($i=0;$i<4;$i++) { RC4_loop($i); } + &ror ($out,8); + &xor ($out,&DWP(0,$inp)); + &cmp ($inp,&wparam(2)); # compare to input+(len/4)*4-4 + &mov (&DWP(0,$tx,$inp),$out);# $tx holds re-biased out here + &lea ($inp,&DWP(4,$inp)); + &mov ($tx,&DWP(0,$dat,$xx,4)); + &jb (&label("loop4")); + + &cmp ($inp,&wparam(1)); # compare to input+len + &je (&label("done")); + &mov ($out,&wparam(3)); # restore $out + + &set_label("loop1",16); + &add (&LB($yy),&LB($tx)); + &mov ($ty,&DWP(0,$dat,$yy,4)); + &mov (&DWP(0,$dat,$yy,4),$tx); + &mov (&DWP(0,$dat,$xx,4),$ty); + &add ($ty,$tx); + &inc (&LB($xx)); + &and ($ty,0xff); + &mov ($ty,&DWP(0,$dat,$ty,4)); + &xor (&LB($ty),&BP(0,$inp)); + &lea ($inp,&DWP(1,$inp)); + &mov ($tx,&DWP(0,$dat,$xx,4)); + &cmp ($inp,&wparam(1)); # compare to input+len + &mov (&BP(-1,$out,$inp),&LB($ty)); + &jb (&label("loop1")); + + &jmp (&label("done")); + +# this is essentially Intel P4 specific codepath... +&set_label("RC4_CHAR",16); + &movz ($tx,&BP(0,$dat,$xx)); + # strangely enough unrolled loop performs over 20% slower... + &set_label("cloop1"); + &add (&LB($yy),&LB($tx)); + &movz ($ty,&BP(0,$dat,$yy)); + &mov (&BP(0,$dat,$yy),&LB($tx)); + &mov (&BP(0,$dat,$xx),&LB($ty)); + &add (&LB($ty),&LB($tx)); + &movz ($ty,&BP(0,$dat,$ty)); + &add (&LB($xx),1); + &xor (&LB($ty),&BP(0,$inp)); + &lea ($inp,&DWP(1,$inp)); + &movz ($tx,&BP(0,$dat,$xx)); + &cmp ($inp,&wparam(1)); + &mov (&BP(-1,$out,$inp),&LB($ty)); + &jb (&label("cloop1")); + +&set_label("done"); + &dec (&LB($xx)); + &mov (&DWP(-4,$dat),$yy); # save key->y + &mov (&BP(-8,$dat),&LB($xx)); # save key->x +&set_label("abort"); +&function_end("asm_RC4"); + +######################################################################## + +$inp="esi"; +$out="edi"; +$idi="ebp"; +$ido="ecx"; +$idx="edx"; + +# void asm_RC4_set_key(RC4_KEY *key,int len,const unsigned char *data); +&function_begin("asm_RC4_set_key"); + &mov ($out,&wparam(0)); # load key + &mov ($idi,&wparam(1)); # load len + &mov ($inp,&wparam(2)); # load data + &picmeup($idx,"OPENSSL_ia32cap_P"); + + &lea ($out,&DWP(2*4,$out)); # &key->data + &lea ($inp,&DWP(0,$inp,$idi)); # $inp to point at the end + &neg ($idi); + &xor ("eax","eax"); + &mov (&DWP(-4,$out),$idi); # borrow key->y + + &bt (&DWP(0,$idx),20); # check for bit#20 + &jc (&label("c1stloop")); + +&set_label("w1stloop",16); + &mov (&DWP(0,$out,"eax",4),"eax"); # key->data[i]=i; + &add (&LB("eax"),1); # i++; + &jnc (&label("w1stloop")); + + &xor ($ido,$ido); + &xor ($idx,$idx); + +&set_label("w2ndloop",16); + &mov ("eax",&DWP(0,$out,$ido,4)); + &add (&LB($idx),&BP(0,$inp,$idi)); + &add (&LB($idx),&LB("eax")); + &add ($idi,1); + &mov ("ebx",&DWP(0,$out,$idx,4)); + &jnz (&label("wnowrap")); + &mov ($idi,&DWP(-4,$out)); + &set_label("wnowrap"); + &mov (&DWP(0,$out,$idx,4),"eax"); + &mov (&DWP(0,$out,$ido,4),"ebx"); + &add (&LB($ido),1); + &jnc (&label("w2ndloop")); +&jmp (&label("exit")); + +# Unlike all other x86 [and x86_64] implementations, Intel P4 core +# [including EM64T] was found to perform poorly with above "32-bit" key +# schedule, a.k.a. RC4_INT. Performance improvement for IA-32 hand-coded +# assembler turned out to be 3.5x if re-coded for compressed 8-bit one, +# a.k.a. RC4_CHAR! It's however inappropriate to just switch to 8-bit +# schedule for x86[_64], because non-P4 implementations suffer from +# significant performance losses then, e.g. PIII exhibits >2x +# deterioration, and so does Opteron. In order to assure optimal +# all-round performance, we detect P4 at run-time and set up compressed +# key schedule, which is recognized by RC4 procedure. + +&set_label("c1stloop",16); + &mov (&BP(0,$out,"eax"),&LB("eax")); # key->data[i]=i; + &add (&LB("eax"),1); # i++; + &jnc (&label("c1stloop")); + + &xor ($ido,$ido); + &xor ($idx,$idx); + &xor ("ebx","ebx"); + +&set_label("c2ndloop",16); + &mov (&LB("eax"),&BP(0,$out,$ido)); + &add (&LB($idx),&BP(0,$inp,$idi)); + &add (&LB($idx),&LB("eax")); + &add ($idi,1); + &mov (&LB("ebx"),&BP(0,$out,$idx)); + &jnz (&label("cnowrap")); + &mov ($idi,&DWP(-4,$out)); + &set_label("cnowrap"); + &mov (&BP(0,$out,$idx),&LB("eax")); + &mov (&BP(0,$out,$ido),&LB("ebx")); + &add (&LB($ido),1); + &jnc (&label("c2ndloop")); + + &mov (&DWP(256,$out),-1); # mark schedule as compressed + +&set_label("exit"); + &xor ("eax","eax"); + &mov (&DWP(-8,$out),"eax"); # key->x=0; + &mov (&DWP(-4,$out),"eax"); # key->y=0; +&function_end("asm_RC4_set_key"); + +# const char *RC4_options(void); +&function_begin_B("RC4_options"); + &call (&label("pic_point")); +&set_label("pic_point"); + &blindpop("eax"); + &lea ("eax",&DWP(&label("opts")."-".&label("pic_point"),"eax")); + &picmeup("edx","OPENSSL_ia32cap_P"); + &mov ("edx",&DWP(0,"edx")); + &bt ("edx",20); + &jc (&label("1xchar")); + &bt ("edx",26); + &jnc (&label("ret")); + &add ("eax",25); + &ret (); +&set_label("1xchar"); + &add ("eax",12); +&set_label("ret"); + &ret (); +&set_label("opts",64); +&asciz ("rc4(4x,int)"); +&asciz ("rc4(1x,char)"); +&asciz ("rc4(8x,mmx)"); +&asciz ("RC4 for x86, CRYPTOGAMS by "); +&align (64); +&function_end_B("RC4_options"); + +&asm_finish(); + diff --git a/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-md5-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-md5-x86_64.pl new file mode 100644 index 00000000..272fa91e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-md5-x86_64.pl @@ -0,0 +1,632 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# June 2011 +# +# This is RC4+MD5 "stitch" implementation. The idea, as spelled in +# http://download.intel.com/design/intarch/papers/323686.pdf, is that +# since both algorithms exhibit instruction-level parallelism, ILP, +# below theoretical maximum, interleaving them would allow to utilize +# processor resources better and achieve better performance. RC4 +# instruction sequence is virtually identical to rc4-x86_64.pl, which +# is heavily based on submission by Maxim Perminov, Maxim Locktyukhin +# and Jim Guilford of Intel. MD5 is fresh implementation aiming to +# minimize register usage, which was used as "main thread" with RC4 +# weaved into it, one RC4 round per one MD5 round. In addition to the +# stiched subroutine the script can generate standalone replacement +# md5_block_asm_data_order and RC4. Below are performance numbers in +# cycles per processed byte, less is better, for these the standalone +# subroutines, sum of them, and stitched one: +# +# RC4 MD5 RC4+MD5 stitch gain +# Opteron 6.5(*) 5.4 11.9 7.0 +70%(*) +# Core2 6.5 5.8 12.3 7.7 +60% +# Westmere 4.3 5.2 9.5 7.0 +36% +# Sandy Bridge 4.2 5.5 9.7 6.8 +43% +# Atom 9.3 6.5 15.8 11.1 +42% +# +# (*) rc4-x86_64.pl delivers 5.3 on Opteron, so real improvement +# is +53%... + +my ($rc4,$md5)=(1,1); # what to generate? +my $D="#" if (!$md5); # if set to "#", MD5 is stitched into RC4(), + # but its result is discarded. Idea here is + # to be able to use 'openssl speed rc4' for + # benchmarking the stitched subroutine... + +my $flavour = shift; +my $output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +my $win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; my $dir=$1; my $xlate; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +my ($dat,$in0,$out,$ctx,$inp,$len, $func,$nargs); + +if ($rc4 && !$md5) { + ($dat,$len,$in0,$out) = ("%rdi","%rsi","%rdx","%rcx"); + $func="RC4"; $nargs=4; +} elsif ($md5 && !$rc4) { + ($ctx,$inp,$len) = ("%rdi","%rsi","%rdx"); + $func="md5_block_asm_data_order"; $nargs=3; +} else { + ($dat,$in0,$out,$ctx,$inp,$len) = ("%rdi","%rsi","%rdx","%rcx","%r8","%r9"); + $func="rc4_md5_enc"; $nargs=6; + # void rc4_md5_enc( + # RC4_KEY *key, # + # const void *in0, # RC4 input + # void *out, # RC4 output + # MD5_CTX *ctx, # + # const void *inp, # MD5 input + # size_t len); # number of 64-byte blocks +} + +my @K=( 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee, + 0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501, + 0x698098d8,0x8b44f7af,0xffff5bb1,0x895cd7be, + 0x6b901122,0xfd987193,0xa679438e,0x49b40821, + + 0xf61e2562,0xc040b340,0x265e5a51,0xe9b6c7aa, + 0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8, + 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed, + 0xa9e3e905,0xfcefa3f8,0x676f02d9,0x8d2a4c8a, + + 0xfffa3942,0x8771f681,0x6d9d6122,0xfde5380c, + 0xa4beea44,0x4bdecfa9,0xf6bb4b60,0xbebfbc70, + 0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05, + 0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665, + + 0xf4292244,0x432aff97,0xab9423a7,0xfc93a039, + 0x655b59c3,0x8f0ccc92,0xffeff47d,0x85845dd1, + 0x6fa87e4f,0xfe2ce6e0,0xa3014314,0x4e0811a1, + 0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391 ); + +my @V=("%r8d","%r9d","%r10d","%r11d"); # MD5 registers +my $tmp="%r12d"; + +my @XX=("%rbp","%rsi"); # RC4 registers +my @TX=("%rax","%rbx"); +my $YY="%rcx"; +my $TY="%rdx"; + +my $MOD=32; # 16, 32 or 64 + +$code.=<<___; +.text +.align 16 + +.globl $func +.type $func,\@function,$nargs +$func: + cmp \$0,$len + je .Labort + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + sub \$40,%rsp +.Lbody: +___ +if ($rc4) { +$code.=<<___; +$D#md5# mov $ctx,%r11 # reassign arguments + mov $len,%r12 + mov $in0,%r13 + mov $out,%r14 +$D#md5# mov $inp,%r15 +___ + $ctx="%r11" if ($md5); # reassign arguments + $len="%r12"; + $in0="%r13"; + $out="%r14"; + $inp="%r15" if ($md5); + $inp=$in0 if (!$md5); +$code.=<<___; + xor $XX[0],$XX[0] + xor $YY,$YY + + lea 8($dat),$dat + mov -8($dat),$XX[0]#b + mov -4($dat),$YY#b + + inc $XX[0]#b + sub $in0,$out + movl ($dat,$XX[0],4),$TX[0]#d +___ +$code.=<<___ if (!$md5); + xor $TX[1],$TX[1] + test \$-128,$len + jz .Loop1 + sub $XX[0],$TX[1] + and \$`$MOD-1`,$TX[1] + jz .Loop${MOD}_is_hot + sub $TX[1],$len +.Loop${MOD}_warmup: + add $TX[0]#b,$YY#b + movl ($dat,$YY,4),$TY#d + movl $TX[0]#d,($dat,$YY,4) + movl $TY#d,($dat,$XX[0],4) + add $TY#b,$TX[0]#b + inc $XX[0]#b + movl ($dat,$TX[0],4),$TY#d + movl ($dat,$XX[0],4),$TX[0]#d + xorb ($in0),$TY#b + movb $TY#b,($out,$in0) + lea 1($in0),$in0 + dec $TX[1] + jnz .Loop${MOD}_warmup + + mov $YY,$TX[1] + xor $YY,$YY + mov $TX[1]#b,$YY#b + +.Loop${MOD}_is_hot: + mov $len,32(%rsp) # save original $len + shr \$6,$len # number of 64-byte blocks +___ + if ($D && !$md5) { # stitch in dummy MD5 + $md5=1; + $ctx="%r11"; + $inp="%r15"; + $code.=<<___; + mov %rsp,$ctx + mov $in0,$inp +___ + } +} +$code.=<<___; +#rc4# add $TX[0]#b,$YY#b +#rc4# lea ($dat,$XX[0],4),$XX[1] + shl \$6,$len + add $inp,$len # pointer to the end of input + mov $len,16(%rsp) + +#md5# mov $ctx,24(%rsp) # save pointer to MD5_CTX +#md5# mov 0*4($ctx),$V[0] # load current hash value from MD5_CTX +#md5# mov 1*4($ctx),$V[1] +#md5# mov 2*4($ctx),$V[2] +#md5# mov 3*4($ctx),$V[3] + jmp .Loop + +.align 16 +.Loop: +#md5# mov $V[0],0*4(%rsp) # put aside current hash value +#md5# mov $V[1],1*4(%rsp) +#md5# mov $V[2],2*4(%rsp) +#md5# mov $V[3],$tmp # forward reference +#md5# mov $V[3],3*4(%rsp) +___ + +sub R0 { + my ($i,$a,$b,$c,$d)=@_; + my @rot0=(7,12,17,22); + my $j=$i%16; + my $k=$i%$MOD; + my $xmm="%xmm".($j&1); + $code.=" movdqu ($in0),%xmm2\n" if ($rc4 && $j==15); + $code.=" add \$$MOD,$XX[0]#b\n" if ($rc4 && $j==15 && $k==$MOD-1); + $code.=" pxor $xmm,$xmm\n" if ($rc4 && $j<=1); + $code.=<<___; +#rc4# movl ($dat,$YY,4),$TY#d +#md5# xor $c,$tmp +#rc4# movl $TX[0]#d,($dat,$YY,4) +#md5# and $b,$tmp +#md5# add 4*`$j`($inp),$a +#rc4# add $TY#b,$TX[0]#b +#rc4# movl `4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d +#md5# add \$$K[$i],$a +#md5# xor $d,$tmp +#rc4# movz $TX[0]#b,$TX[0]#d +#rc4# movl $TY#d,4*$k($XX[1]) +#md5# add $tmp,$a +#rc4# add $TX[1]#b,$YY#b +#md5# rol \$$rot0[$j%4],$a +#md5# mov `$j==15?"$b":"$c"`,$tmp # forward reference +#rc4# pinsrw \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n +#md5# add $b,$a +___ + $code.=<<___ if ($rc4 && $j==15 && $k==$MOD-1); + mov $YY,$XX[1] + xor $YY,$YY # keyword to partial register + mov $XX[1]#b,$YY#b + lea ($dat,$XX[0],4),$XX[1] +___ + $code.=<<___ if ($rc4 && $j==15); + psllq \$8,%xmm1 + pxor %xmm0,%xmm2 + pxor %xmm1,%xmm2 +___ +} +sub R1 { + my ($i,$a,$b,$c,$d)=@_; + my @rot1=(5,9,14,20); + my $j=$i%16; + my $k=$i%$MOD; + my $xmm="%xmm".($j&1); + $code.=" movdqu 16($in0),%xmm3\n" if ($rc4 && $j==15); + $code.=" add \$$MOD,$XX[0]#b\n" if ($rc4 && $j==15 && $k==$MOD-1); + $code.=" pxor $xmm,$xmm\n" if ($rc4 && $j<=1); + $code.=<<___; +#rc4# movl ($dat,$YY,4),$TY#d +#md5# xor $b,$tmp +#rc4# movl $TX[0]#d,($dat,$YY,4) +#md5# and $d,$tmp +#md5# add 4*`((1+5*$j)%16)`($inp),$a +#rc4# add $TY#b,$TX[0]#b +#rc4# movl `4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d +#md5# add \$$K[$i],$a +#md5# xor $c,$tmp +#rc4# movz $TX[0]#b,$TX[0]#d +#rc4# movl $TY#d,4*$k($XX[1]) +#md5# add $tmp,$a +#rc4# add $TX[1]#b,$YY#b +#md5# rol \$$rot1[$j%4],$a +#md5# mov `$j==15?"$c":"$b"`,$tmp # forward reference +#rc4# pinsrw \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n +#md5# add $b,$a +___ + $code.=<<___ if ($rc4 && $j==15 && $k==$MOD-1); + mov $YY,$XX[1] + xor $YY,$YY # keyword to partial register + mov $XX[1]#b,$YY#b + lea ($dat,$XX[0],4),$XX[1] +___ + $code.=<<___ if ($rc4 && $j==15); + psllq \$8,%xmm1 + pxor %xmm0,%xmm3 + pxor %xmm1,%xmm3 +___ +} +sub R2 { + my ($i,$a,$b,$c,$d)=@_; + my @rot2=(4,11,16,23); + my $j=$i%16; + my $k=$i%$MOD; + my $xmm="%xmm".($j&1); + $code.=" movdqu 32($in0),%xmm4\n" if ($rc4 && $j==15); + $code.=" add \$$MOD,$XX[0]#b\n" if ($rc4 && $j==15 && $k==$MOD-1); + $code.=" pxor $xmm,$xmm\n" if ($rc4 && $j<=1); + $code.=<<___; +#rc4# movl ($dat,$YY,4),$TY#d +#md5# xor $c,$tmp +#rc4# movl $TX[0]#d,($dat,$YY,4) +#md5# xor $b,$tmp +#md5# add 4*`((5+3*$j)%16)`($inp),$a +#rc4# add $TY#b,$TX[0]#b +#rc4# movl `4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d +#md5# add \$$K[$i],$a +#rc4# movz $TX[0]#b,$TX[0]#d +#md5# add $tmp,$a +#rc4# movl $TY#d,4*$k($XX[1]) +#rc4# add $TX[1]#b,$YY#b +#md5# rol \$$rot2[$j%4],$a +#md5# mov `$j==15?"\\\$-1":"$c"`,$tmp # forward reference +#rc4# pinsrw \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n +#md5# add $b,$a +___ + $code.=<<___ if ($rc4 && $j==15 && $k==$MOD-1); + mov $YY,$XX[1] + xor $YY,$YY # keyword to partial register + mov $XX[1]#b,$YY#b + lea ($dat,$XX[0],4),$XX[1] +___ + $code.=<<___ if ($rc4 && $j==15); + psllq \$8,%xmm1 + pxor %xmm0,%xmm4 + pxor %xmm1,%xmm4 +___ +} +sub R3 { + my ($i,$a,$b,$c,$d)=@_; + my @rot3=(6,10,15,21); + my $j=$i%16; + my $k=$i%$MOD; + my $xmm="%xmm".($j&1); + $code.=" movdqu 48($in0),%xmm5\n" if ($rc4 && $j==15); + $code.=" add \$$MOD,$XX[0]#b\n" if ($rc4 && $j==15 && $k==$MOD-1); + $code.=" pxor $xmm,$xmm\n" if ($rc4 && $j<=1); + $code.=<<___; +#rc4# movl ($dat,$YY,4),$TY#d +#md5# xor $d,$tmp +#rc4# movl $TX[0]#d,($dat,$YY,4) +#md5# or $b,$tmp +#md5# add 4*`((7*$j)%16)`($inp),$a +#rc4# add $TY#b,$TX[0]#b +#rc4# movl `4*(($k+1)%$MOD)`(`$k==$MOD-1?"$dat,$XX[0],4":"$XX[1]"`),$TX[1]#d +#md5# add \$$K[$i],$a +#rc4# movz $TX[0]#b,$TX[0]#d +#md5# xor $c,$tmp +#rc4# movl $TY#d,4*$k($XX[1]) +#md5# add $tmp,$a +#rc4# add $TX[1]#b,$YY#b +#md5# rol \$$rot3[$j%4],$a +#md5# mov \$-1,$tmp # forward reference +#rc4# pinsrw \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n +#md5# add $b,$a +___ + $code.=<<___ if ($rc4 && $j==15); + mov $XX[0],$XX[1] + xor $XX[0],$XX[0] # keyword to partial register + mov $XX[1]#b,$XX[0]#b + mov $YY,$XX[1] + xor $YY,$YY # keyword to partial register + mov $XX[1]#b,$YY#b + lea ($dat,$XX[0],4),$XX[1] + psllq \$8,%xmm1 + pxor %xmm0,%xmm5 + pxor %xmm1,%xmm5 +___ +} + +my $i=0; +for(;$i<16;$i++) { R0($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); } +for(;$i<32;$i++) { R1($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); } +for(;$i<48;$i++) { R2($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); } +for(;$i<64;$i++) { R3($i,@V); unshift(@V,pop(@V)); push(@TX,shift(@TX)); } + +$code.=<<___; +#md5# add 0*4(%rsp),$V[0] # accumulate hash value +#md5# add 1*4(%rsp),$V[1] +#md5# add 2*4(%rsp),$V[2] +#md5# add 3*4(%rsp),$V[3] + +#rc4# movdqu %xmm2,($out,$in0) # write RC4 output +#rc4# movdqu %xmm3,16($out,$in0) +#rc4# movdqu %xmm4,32($out,$in0) +#rc4# movdqu %xmm5,48($out,$in0) +#md5# lea 64($inp),$inp +#rc4# lea 64($in0),$in0 + cmp 16(%rsp),$inp # are we done? + jb .Loop + +#md5# mov 24(%rsp),$len # restore pointer to MD5_CTX +#rc4# sub $TX[0]#b,$YY#b # correct $YY +#md5# mov $V[0],0*4($len) # write MD5_CTX +#md5# mov $V[1],1*4($len) +#md5# mov $V[2],2*4($len) +#md5# mov $V[3],3*4($len) +___ +$code.=<<___ if ($rc4 && (!$md5 || $D)); + mov 32(%rsp),$len # restore original $len + and \$63,$len # remaining bytes + jnz .Loop1 + jmp .Ldone + +.align 16 +.Loop1: + add $TX[0]#b,$YY#b + movl ($dat,$YY,4),$TY#d + movl $TX[0]#d,($dat,$YY,4) + movl $TY#d,($dat,$XX[0],4) + add $TY#b,$TX[0]#b + inc $XX[0]#b + movl ($dat,$TX[0],4),$TY#d + movl ($dat,$XX[0],4),$TX[0]#d + xorb ($in0),$TY#b + movb $TY#b,($out,$in0) + lea 1($in0),$in0 + dec $len + jnz .Loop1 + +.Ldone: +___ +$code.=<<___; +#rc4# sub \$1,$XX[0]#b +#rc4# movl $XX[0]#d,-8($dat) +#rc4# movl $YY#d,-4($dat) + + mov 40(%rsp),%r15 + mov 48(%rsp),%r14 + mov 56(%rsp),%r13 + mov 64(%rsp),%r12 + mov 72(%rsp),%rbp + mov 80(%rsp),%rbx + lea 88(%rsp),%rsp +.Lepilogue: +.Labort: + ret +.size $func,.-$func +___ + +if ($rc4 && $D) { # sole purpose of this section is to provide + # option to use the generated module as drop-in + # replacement for rc4-x86_64.pl for debugging + # and testing purposes... +my ($idx,$ido)=("%r8","%r9"); +my ($dat,$len,$inp)=("%rdi","%rsi","%rdx"); + +$code.=<<___; +.globl RC4_set_key +.type RC4_set_key,\@function,3 +.align 16 +RC4_set_key: + lea 8($dat),$dat + lea ($inp,$len),$inp + neg $len + mov $len,%rcx + xor %eax,%eax + xor $ido,$ido + xor %r10,%r10 + xor %r11,%r11 + jmp .Lw1stloop + +.align 16 +.Lw1stloop: + mov %eax,($dat,%rax,4) + add \$1,%al + jnc .Lw1stloop + + xor $ido,$ido + xor $idx,$idx +.align 16 +.Lw2ndloop: + mov ($dat,$ido,4),%r10d + add ($inp,$len,1),$idx#b + add %r10b,$idx#b + add \$1,$len + mov ($dat,$idx,4),%r11d + cmovz %rcx,$len + mov %r10d,($dat,$idx,4) + mov %r11d,($dat,$ido,4) + add \$1,$ido#b + jnc .Lw2ndloop + + xor %eax,%eax + mov %eax,-8($dat) + mov %eax,-4($dat) + ret +.size RC4_set_key,.-RC4_set_key + +.globl RC4_options +.type RC4_options,\@abi-omnipotent +.align 16 +RC4_options: + lea .Lopts(%rip),%rax + ret +.align 64 +.Lopts: +.asciz "rc4(64x,int)" +.align 64 +.size RC4_options,.-RC4_options +___ +} +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +my $rec="%rcx"; +my $frame="%rdx"; +my $context="%r8"; +my $disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + lea .Lbody(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lbody + jb .Lin_prologue + + mov 152($context),%rax # pull context->Rsp + + lea .Lepilogue(%rip),%r10 + cmp %r10,%rbx # context->Rip>=.Lepilogue + jae .Lin_prologue + + mov 40(%rax),%r15 + mov 48(%rax),%r14 + mov 56(%rax),%r13 + mov 64(%rax),%r12 + mov 72(%rax),%rbp + mov 80(%rax),%rbx + lea 88(%rax),%rax + + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R12 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + +.Lin_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size se_handler,.-se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_$func + .rva .LSEH_end_$func + .rva .LSEH_info_$func + +.section .xdata +.align 8 +.LSEH_info_$func: + .byte 9,0,0,0 + .rva se_handler +___ +} + +sub reg_part { +my ($reg,$conv)=@_; + if ($reg =~ /%r[0-9]+/) { $reg .= $conv; } + elsif ($conv eq "b") { $reg =~ s/%[er]([^x]+)x?/%$1l/; } + elsif ($conv eq "w") { $reg =~ s/%[er](.+)/%$1/; } + elsif ($conv eq "d") { $reg =~ s/%[er](.+)/%e$1/; } + return $reg; +} + +$code =~ s/(%[a-z0-9]+)#([bwd])/reg_part($1,$2)/gem; +$code =~ s/\`([^\`]*)\`/eval $1/gem; +$code =~ s/pinsrw\s+\$0,/movd /gm; + +$code =~ s/#md5#//gm if ($md5); +$code =~ s/#rc4#//gm if ($rc4); + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-x86_64.pl new file mode 100644 index 00000000..cef62689 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rc4/asm/rc4-x86_64.pl @@ -0,0 +1,653 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# July 2004 +# +# 2.22x RC4 tune-up:-) It should be noted though that my hand [as in +# "hand-coded assembler"] doesn't stand for the whole improvement +# coefficient. It turned out that eliminating RC4_CHAR from config +# line results in ~40% improvement (yes, even for C implementation). +# Presumably it has everything to do with AMD cache architecture and +# RAW or whatever penalties. Once again! The module *requires* config +# line *without* RC4_CHAR! As for coding "secret," I bet on partial +# register arithmetics. For example instead of 'inc %r8; and $255,%r8' +# I simply 'inc %r8b'. Even though optimization manual discourages +# to operate on partial registers, it turned out to be the best bet. +# At least for AMD... How IA32E would perform remains to be seen... + +# November 2004 +# +# As was shown by Marc Bevand reordering of couple of load operations +# results in even higher performance gain of 3.3x:-) At least on +# Opteron... For reference, 1x in this case is RC4_CHAR C-code +# compiled with gcc 3.3.2, which performs at ~54MBps per 1GHz clock. +# Latter means that if you want to *estimate* what to expect from +# *your* Opteron, then multiply 54 by 3.3 and clock frequency in GHz. + +# November 2004 +# +# Intel P4 EM64T core was found to run the AMD64 code really slow... +# The only way to achieve comparable performance on P4 was to keep +# RC4_CHAR. Kind of ironic, huh? As it's apparently impossible to +# compose blended code, which would perform even within 30% marginal +# on either AMD and Intel platforms, I implement both cases. See +# rc4_skey.c for further details... + +# April 2005 +# +# P4 EM64T core appears to be "allergic" to 64-bit inc/dec. Replacing +# those with add/sub results in 50% performance improvement of folded +# loop... + +# May 2005 +# +# As was shown by Zou Nanhai loop unrolling can improve Intel EM64T +# performance by >30% [unlike P4 32-bit case that is]. But this is +# provided that loads are reordered even more aggressively! Both code +# pathes, AMD64 and EM64T, reorder loads in essentially same manner +# as my IA-64 implementation. On Opteron this resulted in modest 5% +# improvement [I had to test it], while final Intel P4 performance +# achieves respectful 432MBps on 2.8GHz processor now. For reference. +# If executed on Xeon, current RC4_CHAR code-path is 2.7x faster than +# RC4_INT code-path. While if executed on Opteron, it's only 25% +# slower than the RC4_INT one [meaning that if CPU µ-arch detection +# is not implemented, then this final RC4_CHAR code-path should be +# preferred, as it provides better *all-round* performance]. + +# March 2007 +# +# Intel Core2 was observed to perform poorly on both code paths:-( It +# apparently suffers from some kind of partial register stall, which +# occurs in 64-bit mode only [as virtually identical 32-bit loop was +# observed to outperform 64-bit one by almost 50%]. Adding two movzb to +# cloop1 boosts its performance by 80%! This loop appears to be optimal +# fit for Core2 and therefore the code was modified to skip cloop8 on +# this CPU. + +# May 2010 +# +# Intel Westmere was observed to perform suboptimally. Adding yet +# another movzb to cloop1 improved performance by almost 50%! Core2 +# performance is improved too, but nominally... + +# May 2011 +# +# The only code path that was not modified is P4-specific one. Non-P4 +# Intel code path optimization is heavily based on submission by Maxim +# Perminov, Maxim Locktyukhin and Jim Guilford of Intel. I've used +# some of the ideas even in attempt to optmize the original RC4_INT +# code path... Current performance in cycles per processed byte (less +# is better) and improvement coefficients relative to previous +# version of this module are: +# +# Opteron 5.3/+0%(*) +# P4 6.5 +# Core2 6.2/+15%(**) +# Westmere 4.2/+60% +# Sandy Bridge 4.2/+120% +# Atom 9.3/+80% +# +# (*) But corresponding loop has less instructions, which should have +# positive effect on upcoming Bulldozer, which has one less ALU. +# For reference, Intel code runs at 6.8 cpb rate on Opteron. +# (**) Note that Core2 result is ~15% lower than corresponding result +# for 32-bit code, meaning that it's possible to improve it, +# but more than likely at the cost of the others (see rc4-586.pl +# to get the idea)... + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$dat="%rdi"; # arg1 +$len="%rsi"; # arg2 +$inp="%rdx"; # arg3 +$out="%rcx"; # arg4 + +{ +$code=<<___; +.text +.extern OPENSSL_ia32cap_P + +.globl asm_RC4 +.type asm_RC4,\@function,4 +.align 16 +asm_RC4: + or $len,$len + jne .Lentry + ret +.Lentry: + push %rbx + push %r12 + push %r13 +.Lprologue: + mov $len,%r11 + mov $inp,%r12 + mov $out,%r13 +___ +my $len="%r11"; # reassign input arguments +my $inp="%r12"; +my $out="%r13"; + +my @XX=("%r10","%rsi"); +my @TX=("%rax","%rbx"); +my $YY="%rcx"; +my $TY="%rdx"; + +$code.=<<___; + xor $XX[0],$XX[0] + xor $YY,$YY + + lea 8($dat),$dat + mov -8($dat),$XX[0]#b + mov -4($dat),$YY#b + cmpl \$-1,256($dat) + je .LRC4_CHAR + mov OPENSSL_ia32cap_P(%rip),%r8d + xor $TX[1],$TX[1] + inc $XX[0]#b + sub $XX[0],$TX[1] + sub $inp,$out + movl ($dat,$XX[0],4),$TX[0]#d + test \$-16,$len + jz .Lloop1 + bt \$30,%r8d # Intel CPU? + jc .Lintel + and \$7,$TX[1] + lea 1($XX[0]),$XX[1] + jz .Loop8 + sub $TX[1],$len +.Loop8_warmup: + add $TX[0]#b,$YY#b + movl ($dat,$YY,4),$TY#d + movl $TX[0]#d,($dat,$YY,4) + movl $TY#d,($dat,$XX[0],4) + add $TY#b,$TX[0]#b + inc $XX[0]#b + movl ($dat,$TX[0],4),$TY#d + movl ($dat,$XX[0],4),$TX[0]#d + xorb ($inp),$TY#b + movb $TY#b,($out,$inp) + lea 1($inp),$inp + dec $TX[1] + jnz .Loop8_warmup + + lea 1($XX[0]),$XX[1] + jmp .Loop8 +.align 16 +.Loop8: +___ +for ($i=0;$i<8;$i++) { +$code.=<<___ if ($i==7); + add \$8,$XX[1]#b +___ +$code.=<<___; + add $TX[0]#b,$YY#b + movl ($dat,$YY,4),$TY#d + movl $TX[0]#d,($dat,$YY,4) + movl `4*($i==7?-1:$i)`($dat,$XX[1],4),$TX[1]#d + ror \$8,%r8 # ror is redundant when $i=0 + movl $TY#d,4*$i($dat,$XX[0],4) + add $TX[0]#b,$TY#b + movb ($dat,$TY,4),%r8b +___ +push(@TX,shift(@TX)); #push(@XX,shift(@XX)); # "rotate" registers +} +$code.=<<___; + add \$8,$XX[0]#b + ror \$8,%r8 + sub \$8,$len + + xor ($inp),%r8 + mov %r8,($out,$inp) + lea 8($inp),$inp + + test \$-8,$len + jnz .Loop8 + cmp \$0,$len + jne .Lloop1 + jmp .Lexit + +.align 16 +.Lintel: + test \$-32,$len + jz .Lloop1 + and \$15,$TX[1] + jz .Loop16_is_hot + sub $TX[1],$len +.Loop16_warmup: + add $TX[0]#b,$YY#b + movl ($dat,$YY,4),$TY#d + movl $TX[0]#d,($dat,$YY,4) + movl $TY#d,($dat,$XX[0],4) + add $TY#b,$TX[0]#b + inc $XX[0]#b + movl ($dat,$TX[0],4),$TY#d + movl ($dat,$XX[0],4),$TX[0]#d + xorb ($inp),$TY#b + movb $TY#b,($out,$inp) + lea 1($inp),$inp + dec $TX[1] + jnz .Loop16_warmup + + mov $YY,$TX[1] + xor $YY,$YY + mov $TX[1]#b,$YY#b + +.Loop16_is_hot: + lea ($dat,$XX[0],4),$XX[1] +___ +sub RC4_loop { + my $i=shift; + my $j=$i<0?0:$i; + my $xmm="%xmm".($j&1); + + $code.=" add \$16,$XX[0]#b\n" if ($i==15); + $code.=" movdqu ($inp),%xmm2\n" if ($i==15); + $code.=" add $TX[0]#b,$YY#b\n" if ($i<=0); + $code.=" movl ($dat,$YY,4),$TY#d\n"; + $code.=" pxor %xmm0,%xmm2\n" if ($i==0); + $code.=" psllq \$8,%xmm1\n" if ($i==0); + $code.=" pxor $xmm,$xmm\n" if ($i<=1); + $code.=" movl $TX[0]#d,($dat,$YY,4)\n"; + $code.=" add $TY#b,$TX[0]#b\n"; + $code.=" movl `4*($j+1)`($XX[1]),$TX[1]#d\n" if ($i<15); + $code.=" movz $TX[0]#b,$TX[0]#d\n"; + $code.=" movl $TY#d,4*$j($XX[1])\n"; + $code.=" pxor %xmm1,%xmm2\n" if ($i==0); + $code.=" lea ($dat,$XX[0],4),$XX[1]\n" if ($i==15); + $code.=" add $TX[1]#b,$YY#b\n" if ($i<15); + $code.=" pinsrw \$`($j>>1)&7`,($dat,$TX[0],4),$xmm\n"; + $code.=" movdqu %xmm2,($out,$inp)\n" if ($i==0); + $code.=" lea 16($inp),$inp\n" if ($i==0); + $code.=" movl ($XX[1]),$TX[1]#d\n" if ($i==15); +} + RC4_loop(-1); +$code.=<<___; + jmp .Loop16_enter +.align 16 +.Loop16: +___ + +for ($i=0;$i<16;$i++) { + $code.=".Loop16_enter:\n" if ($i==1); + RC4_loop($i); + push(@TX,shift(@TX)); # "rotate" registers +} +$code.=<<___; + mov $YY,$TX[1] + xor $YY,$YY # keyword to partial register + sub \$16,$len + mov $TX[1]#b,$YY#b + test \$-16,$len + jnz .Loop16 + + psllq \$8,%xmm1 + pxor %xmm0,%xmm2 + pxor %xmm1,%xmm2 + movdqu %xmm2,($out,$inp) + lea 16($inp),$inp + + cmp \$0,$len + jne .Lloop1 + jmp .Lexit + +.align 16 +.Lloop1: + add $TX[0]#b,$YY#b + movl ($dat,$YY,4),$TY#d + movl $TX[0]#d,($dat,$YY,4) + movl $TY#d,($dat,$XX[0],4) + add $TY#b,$TX[0]#b + inc $XX[0]#b + movl ($dat,$TX[0],4),$TY#d + movl ($dat,$XX[0],4),$TX[0]#d + xorb ($inp),$TY#b + movb $TY#b,($out,$inp) + lea 1($inp),$inp + dec $len + jnz .Lloop1 + jmp .Lexit + +.align 16 +.LRC4_CHAR: + add \$1,$XX[0]#b + movzb ($dat,$XX[0]),$TX[0]#d + test \$-8,$len + jz .Lcloop1 + jmp .Lcloop8 +.align 16 +.Lcloop8: + mov ($inp),%r8d + mov 4($inp),%r9d +___ +# unroll 2x4-wise, because 64-bit rotates kill Intel P4... +for ($i=0;$i<4;$i++) { +$code.=<<___; + add $TX[0]#b,$YY#b + lea 1($XX[0]),$XX[1] + movzb ($dat,$YY),$TY#d + movzb $XX[1]#b,$XX[1]#d + movzb ($dat,$XX[1]),$TX[1]#d + movb $TX[0]#b,($dat,$YY) + cmp $XX[1],$YY + movb $TY#b,($dat,$XX[0]) + jne .Lcmov$i # Intel cmov is sloooow... + mov $TX[0],$TX[1] +.Lcmov$i: + add $TX[0]#b,$TY#b + xor ($dat,$TY),%r8b + ror \$8,%r8d +___ +push(@TX,shift(@TX)); push(@XX,shift(@XX)); # "rotate" registers +} +for ($i=4;$i<8;$i++) { +$code.=<<___; + add $TX[0]#b,$YY#b + lea 1($XX[0]),$XX[1] + movzb ($dat,$YY),$TY#d + movzb $XX[1]#b,$XX[1]#d + movzb ($dat,$XX[1]),$TX[1]#d + movb $TX[0]#b,($dat,$YY) + cmp $XX[1],$YY + movb $TY#b,($dat,$XX[0]) + jne .Lcmov$i # Intel cmov is sloooow... + mov $TX[0],$TX[1] +.Lcmov$i: + add $TX[0]#b,$TY#b + xor ($dat,$TY),%r9b + ror \$8,%r9d +___ +push(@TX,shift(@TX)); push(@XX,shift(@XX)); # "rotate" registers +} +$code.=<<___; + lea -8($len),$len + mov %r8d,($out) + lea 8($inp),$inp + mov %r9d,4($out) + lea 8($out),$out + + test \$-8,$len + jnz .Lcloop8 + cmp \$0,$len + jne .Lcloop1 + jmp .Lexit +___ +$code.=<<___; +.align 16 +.Lcloop1: + add $TX[0]#b,$YY#b + movzb $YY#b,$YY#d + movzb ($dat,$YY),$TY#d + movb $TX[0]#b,($dat,$YY) + movb $TY#b,($dat,$XX[0]) + add $TX[0]#b,$TY#b + add \$1,$XX[0]#b + movzb $TY#b,$TY#d + movzb $XX[0]#b,$XX[0]#d + movzb ($dat,$TY),$TY#d + movzb ($dat,$XX[0]),$TX[0]#d + xorb ($inp),$TY#b + lea 1($inp),$inp + movb $TY#b,($out) + lea 1($out),$out + sub \$1,$len + jnz .Lcloop1 + jmp .Lexit + +.align 16 +.Lexit: + sub \$1,$XX[0]#b + movl $XX[0]#d,-8($dat) + movl $YY#d,-4($dat) + + mov (%rsp),%r13 + mov 8(%rsp),%r12 + mov 16(%rsp),%rbx + add \$24,%rsp +.Lepilogue: + ret +.size asm_RC4,.-asm_RC4 +___ +} + +$idx="%r8"; +$ido="%r9"; + +$code.=<<___; +.globl asm_RC4_set_key +.type asm_RC4_set_key,\@function,3 +.align 16 +asm_RC4_set_key: + lea 8($dat),$dat + lea ($inp,$len),$inp + neg $len + mov $len,%rcx + xor %eax,%eax + xor $ido,$ido + xor %r10,%r10 + xor %r11,%r11 + + mov OPENSSL_ia32cap_P(%rip),$idx#d + bt \$20,$idx#d # RC4_CHAR? + jc .Lc1stloop + jmp .Lw1stloop + +.align 16 +.Lw1stloop: + mov %eax,($dat,%rax,4) + add \$1,%al + jnc .Lw1stloop + + xor $ido,$ido + xor $idx,$idx +.align 16 +.Lw2ndloop: + mov ($dat,$ido,4),%r10d + add ($inp,$len,1),$idx#b + add %r10b,$idx#b + add \$1,$len + mov ($dat,$idx,4),%r11d + cmovz %rcx,$len + mov %r10d,($dat,$idx,4) + mov %r11d,($dat,$ido,4) + add \$1,$ido#b + jnc .Lw2ndloop + jmp .Lexit_key + +.align 16 +.Lc1stloop: + mov %al,($dat,%rax) + add \$1,%al + jnc .Lc1stloop + + xor $ido,$ido + xor $idx,$idx +.align 16 +.Lc2ndloop: + mov ($dat,$ido),%r10b + add ($inp,$len),$idx#b + add %r10b,$idx#b + add \$1,$len + mov ($dat,$idx),%r11b + jnz .Lcnowrap + mov %rcx,$len +.Lcnowrap: + mov %r10b,($dat,$idx) + mov %r11b,($dat,$ido) + add \$1,$ido#b + jnc .Lc2ndloop + movl \$-1,256($dat) + +.align 16 +.Lexit_key: + xor %eax,%eax + mov %eax,-8($dat) + mov %eax,-4($dat) + ret +.size asm_RC4_set_key,.-asm_RC4_set_key +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type stream_se_handler,\@abi-omnipotent +.align 16 +stream_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + lea .Lprologue(%rip),%r10 + cmp %r10,%rbx # context->RipRsp + + lea .Lepilogue(%rip),%r10 + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lin_prologue + + lea 24(%rax),%rax + + mov -8(%rax),%rbx + mov -16(%rax),%r12 + mov -24(%rax),%r13 + mov %rbx,144($context) # restore context->Rbx + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + +.Lin_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + jmp .Lcommon_seh_exit +.size stream_se_handler,.-stream_se_handler + +.type key_se_handler,\@abi-omnipotent +.align 16 +key_se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 152($context),%rax # pull context->Rsp + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + +.Lcommon_seh_exit: + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size key_se_handler,.-key_se_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_asm_RC4 + .rva .LSEH_end_asm_RC4 + .rva .LSEH_info_asm_RC4 + + .rva .LSEH_begin_asm_RC4_set_key + .rva .LSEH_end_asm_RC4_set_key + .rva .LSEH_info_asm_RC4_set_key + +.section .xdata +.align 8 +.LSEH_info_asm_RC4: + .byte 9,0,0,0 + .rva stream_se_handler +.LSEH_info_asm_RC4_set_key: + .byte 9,0,0,0 + .rva key_se_handler +___ +} + +sub reg_part { +my ($reg,$conv)=@_; + if ($reg =~ /%r[0-9]+/) { $reg .= $conv; } + elsif ($conv eq "b") { $reg =~ s/%[er]([^x]+)x?/%$1l/; } + elsif ($conv eq "w") { $reg =~ s/%[er](.+)/%$1/; } + elsif ($conv eq "d") { $reg =~ s/%[er](.+)/%e$1/; } + return $reg; +} + +$code =~ s/(%[a-z0-9]+)#([bwd])/reg_part($1,$2)/gem; +$code =~ s/\`([^\`]*)\`/eval $1/gem; + +print $code; + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/rc4/rc4.c b/TMessagesProj/jni/boringssl/crypto/rc4/rc4.c new file mode 100644 index 00000000..aa19dc28 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rc4/rc4.c @@ -0,0 +1,284 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#if defined(OPENSSL_NO_ASM) || \ + (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) + +#if defined(OPENSSL_64_BIT) +#define RC4_CHUNK uint64_t +#elif defined(OPENSSL_32_BIT) +#define RC4_CHUNK uint32_t +#else +#error "Unknown word size" +#endif + + +/* RC4 as implemented from a posting from + * Newsgroups: sci.crypt + * From: sterndark@netcom.com (David Sterndark) + * Subject: RC4 Algorithm revealed. + * Message-ID: + * Date: Wed, 14 Sep 1994 06:35:31 GMT */ + +void RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out) { + uint32_t *d; + uint32_t x, y, tx, ty; + size_t i; + + x = key->x; + y = key->y; + d = key->data; + +#define RC4_STEP \ + (x = (x + 1) & 0xff, tx = d[x], y = (tx + y) & 0xff, ty = d[y], d[y] = tx, \ + d[x] = ty, (RC4_CHUNK)d[(tx + ty) & 0xff]) + + if ((((size_t)in & (sizeof(RC4_CHUNK) - 1)) | + ((size_t)out & (sizeof(RC4_CHUNK) - 1))) == 0) { + RC4_CHUNK ichunk, otp; + const union { + long one; + char little; + } is_endian = {1}; + + /* I reckon we can afford to implement both endian + * cases and to decide which way to take at run-time + * because the machine code appears to be very compact + * and redundant 1-2KB is perfectly tolerable (i.e. + * in case the compiler fails to eliminate it:-). By + * suggestion from Terrel Larson + * who also stands for the is_endian union:-) + * + * Special notes. + * + * - is_endian is declared automatic as doing otherwise + * (declaring static) prevents gcc from eliminating + * the redundant code; + * - compilers (those I've tried) don't seem to have + * problems eliminating either the operators guarded + * by "if (sizeof(RC4_CHUNK)==8)" or the condition + * expressions themselves so I've got 'em to replace + * corresponding #ifdefs from the previous version; + * - I chose to let the redundant switch cases when + * sizeof(RC4_CHUNK)!=8 be (were also #ifdefed + * before); + * - in case you wonder "&(sizeof(RC4_CHUNK)*8-1)" in + * [LB]ESHFT guards against "shift is out of range" + * warnings when sizeof(RC4_CHUNK)!=8 + * + * */ + if (!is_endian.little) { /* BIG-ENDIAN CASE */ +#define BESHFT(c) \ + (((sizeof(RC4_CHUNK) - (c) - 1) * 8) & (sizeof(RC4_CHUNK) * 8 - 1)) + for (; len & (0 - sizeof(RC4_CHUNK)); len -= sizeof(RC4_CHUNK)) { + ichunk = *(RC4_CHUNK *)in; + otp = RC4_STEP << BESHFT(0); + otp |= RC4_STEP << BESHFT(1); + otp |= RC4_STEP << BESHFT(2); + otp |= RC4_STEP << BESHFT(3); +#if defined(OPENSSL_64_BIT) + otp |= RC4_STEP << BESHFT(4); + otp |= RC4_STEP << BESHFT(5); + otp |= RC4_STEP << BESHFT(6); + otp |= RC4_STEP << BESHFT(7); +#endif + *(RC4_CHUNK *)out = otp ^ ichunk; + in += sizeof(RC4_CHUNK); + out += sizeof(RC4_CHUNK); + } + } else { /* LITTLE-ENDIAN CASE */ +#define LESHFT(c) (((c) * 8) & (sizeof(RC4_CHUNK) * 8 - 1)) + for (; len & (0 - sizeof(RC4_CHUNK)); len -= sizeof(RC4_CHUNK)) { + ichunk = *(RC4_CHUNK *)in; + otp = RC4_STEP; + otp |= RC4_STEP << 8; + otp |= RC4_STEP << 16; + otp |= RC4_STEP << 24; +#if defined(OPENSSL_64_BIT) + otp |= RC4_STEP << LESHFT(4); + otp |= RC4_STEP << LESHFT(5); + otp |= RC4_STEP << LESHFT(6); + otp |= RC4_STEP << LESHFT(7); +#endif + *(RC4_CHUNK *)out = otp ^ ichunk; + in += sizeof(RC4_CHUNK); + out += sizeof(RC4_CHUNK); + } + } + } +#define LOOP(in, out) \ + x = ((x + 1) & 0xff); \ + tx = d[x]; \ + y = (tx + y) & 0xff; \ + d[x] = ty = d[y]; \ + d[y] = tx; \ + (out) = d[(tx + ty) & 0xff] ^ (in); + +#ifndef RC4_INDEX +#define RC4_LOOP(a, b, i) LOOP(*((a)++), *((b)++)) +#else +#define RC4_LOOP(a, b, i) LOOP(a[i], b[i]) +#endif + + i = len >> 3; + if (i) { + for (;;) { + RC4_LOOP(in, out, 0); + RC4_LOOP(in, out, 1); + RC4_LOOP(in, out, 2); + RC4_LOOP(in, out, 3); + RC4_LOOP(in, out, 4); + RC4_LOOP(in, out, 5); + RC4_LOOP(in, out, 6); + RC4_LOOP(in, out, 7); +#ifdef RC4_INDEX + in += 8; + out += 8; +#endif + if (--i == 0) { + break; + } + } + } + i = len & 0x07; + if (i) { + for (;;) { + RC4_LOOP(in, out, 0); + if (--i == 0) { + break; + } + RC4_LOOP(in, out, 1); + if (--i == 0) { + break; + } + RC4_LOOP(in, out, 2); + if (--i == 0) { + break; + } + RC4_LOOP(in, out, 3); + if (--i == 0) { + break; + } + RC4_LOOP(in, out, 4); + if (--i == 0) { + break; + } + RC4_LOOP(in, out, 5); + if (--i == 0) { + break; + } + RC4_LOOP(in, out, 6); + if (--i == 0) { + break; + } + } + } + key->x = x; + key->y = y; +} + +void RC4_set_key(RC4_KEY *rc4key, unsigned len, const uint8_t *key) { + uint32_t tmp; + int id1, id2; + uint32_t *d; + unsigned int i; + + d = &rc4key->data[0]; + rc4key->x = 0; + rc4key->y = 0; + id1 = id2 = 0; + +#define SK_LOOP(d, n) \ + { \ + tmp = d[(n)]; \ + id2 = (key[id1] + tmp + id2) & 0xff; \ + if (++id1 == len) \ + id1 = 0; \ + d[(n)] = d[id2]; \ + d[id2] = tmp; \ + } + + for (i = 0; i < 256; i++) { + d[i] = i; + } + for (i = 0; i < 256; i += 4) { + SK_LOOP(d, i + 0); + SK_LOOP(d, i + 1); + SK_LOOP(d, i + 2); + SK_LOOP(d, i + 3); + } +} + +#else + +/* In this case several functions are provided by asm code. However, one cannot + * control asm symbol visibility with command line flags and such so they are + * always hidden and wrapped by these C functions, which can be so + * controlled. */ + +void asm_RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out); +void RC4(RC4_KEY *key, size_t len, const uint8_t *in, uint8_t *out) { + asm_RC4(key, len, in, out); +} + +void asm_RC4_set_key(RC4_KEY *rc4key, unsigned len, const uint8_t *key); +void RC4_set_key(RC4_KEY *rc4key, unsigned len, const uint8_t *key) { + asm_RC4_set_key(rc4key, len, key); +} + +#endif /* OPENSSL_NO_ASM || (!OPENSSL_X86_64 && !OPENSSL_X86) */ diff --git a/TMessagesProj/jni/boringssl/crypto/refcount_c11.c b/TMessagesProj/jni/boringssl/crypto/refcount_c11.c new file mode 100644 index 00000000..fbc0343d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/refcount_c11.c @@ -0,0 +1,67 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include "internal.h" + + +#if defined(OPENSSL_C11_ATOMIC) + +#include +#include +#include +#include + +#include + + +/* See comment above the typedef of CRYPTO_refcount_t about these tests. */ +static_assert(alignof(CRYPTO_refcount_t) == alignof(_Atomic CRYPTO_refcount_t), + "_Atomic alters the needed alignment of a reference count"); +static_assert(sizeof(CRYPTO_refcount_t) == sizeof(_Atomic CRYPTO_refcount_t), + "_Atomic alters the size of a reference count"); + +static_assert((CRYPTO_refcount_t)-1 == CRYPTO_REFCOUNT_MAX, + "CRYPTO_REFCOUNT_MAX is incorrect"); + +void CRYPTO_refcount_inc(CRYPTO_refcount_t *in_count) { + _Atomic CRYPTO_refcount_t *count = (_Atomic CRYPTO_refcount_t *) in_count; + uint32_t expected = atomic_load(count); + + while (expected != CRYPTO_REFCOUNT_MAX) { + uint32_t new_value = expected + 1; + if (atomic_compare_exchange_weak(count, &expected, new_value)) { + break; + } + } +} + +int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *in_count) { + _Atomic CRYPTO_refcount_t *count = (_Atomic CRYPTO_refcount_t *)in_count; + uint32_t expected = atomic_load(count); + + for (;;) { + if (expected == 0) { + abort(); + } else if (expected == CRYPTO_REFCOUNT_MAX) { + return 0; + } else { + const uint32_t new_value = expected - 1; + if (atomic_compare_exchange_weak(count, &expected, new_value)) { + return new_value == 0; + } + } + } +} + +#endif /* OPENSSL_C11_ATOMIC */ diff --git a/TMessagesProj/jni/boringssl/crypto/refcount_lock.c b/TMessagesProj/jni/boringssl/crypto/refcount_lock.c new file mode 100644 index 00000000..bb8ef86b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/refcount_lock.c @@ -0,0 +1,53 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include "internal.h" + +#include + +#include + + +#if !defined(OPENSSL_C11_ATOMIC) + +OPENSSL_COMPILE_ASSERT((CRYPTO_refcount_t)-1 == CRYPTO_REFCOUNT_MAX, + CRYPTO_REFCOUNT_MAX_is_incorrect); + +static struct CRYPTO_STATIC_MUTEX g_refcount_lock = CRYPTO_STATIC_MUTEX_INIT; + +void CRYPTO_refcount_inc(CRYPTO_refcount_t *count) { + CRYPTO_STATIC_MUTEX_lock_write(&g_refcount_lock); + if (*count < CRYPTO_REFCOUNT_MAX) { + (*count)++; + } + CRYPTO_STATIC_MUTEX_unlock(&g_refcount_lock); +} + +int CRYPTO_refcount_dec_and_test_zero(CRYPTO_refcount_t *count) { + int ret; + + CRYPTO_STATIC_MUTEX_lock_write(&g_refcount_lock); + if (*count == 0) { + abort(); + } + if (*count < CRYPTO_REFCOUNT_MAX) { + (*count)--; + } + ret = (*count == 0); + CRYPTO_STATIC_MUTEX_unlock(&g_refcount_lock); + + return ret; +} + +#endif /* OPENSSL_C11_ATOMIC */ diff --git a/TMessagesProj/jni/boringssl/crypto/rsa/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/rsa/CMakeLists.txt new file mode 100644 index 00000000..bd18d2c4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rsa/CMakeLists.txt @@ -0,0 +1,13 @@ +include_directories(. .. ../../include) + +add_library( + rsa + + OBJECT + + rsa.c + rsa_impl.c + blinding.c + padding.c + rsa_asn1.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/rsa/blinding.c b/TMessagesProj/jni/boringssl/crypto/rsa/blinding.c new file mode 100644 index 00000000..75c34225 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rsa/blinding.c @@ -0,0 +1,460 @@ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + * Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + +#include "internal.h" + + +#define BN_BLINDING_COUNTER 32 + +struct bn_blinding_st { + BIGNUM *A; + BIGNUM *Ai; + BIGNUM *e; + BIGNUM *mod; /* just a reference */ + int counter; + unsigned long flags; + BN_MONT_CTX *m_ctx; + int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); +}; + +BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod) { + BN_BLINDING *ret = NULL; + + ret = (BN_BLINDING*) OPENSSL_malloc(sizeof(BN_BLINDING)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return NULL; + } + memset(ret, 0, sizeof(BN_BLINDING)); + if (A != NULL) { + ret->A = BN_dup(A); + if (ret->A == NULL) { + goto err; + } + } + if (Ai != NULL) { + ret->Ai = BN_dup(Ai); + if (ret->Ai == NULL) { + goto err; + } + } + + /* save a copy of mod in the BN_BLINDING structure */ + ret->mod = BN_dup(mod); + if (ret->mod == NULL) { + goto err; + } + if (BN_get_flags(mod, BN_FLG_CONSTTIME) != 0) { + BN_set_flags(ret->mod, BN_FLG_CONSTTIME); + } + + /* Set the counter to the special value -1 + * to indicate that this is never-used fresh blinding + * that does not need updating before first use. */ + ret->counter = -1; + return ret; + +err: + BN_BLINDING_free(ret); + return NULL; +} + +void BN_BLINDING_free(BN_BLINDING *r) { + if (r == NULL) { + return; + } + + BN_free(r->A); + BN_free(r->Ai); + BN_free(r->e); + BN_free(r->mod); + OPENSSL_free(r); +} + +int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx) { + int ret = 0; + + if (b->A == NULL || b->Ai == NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED); + goto err; + } + + if (b->counter == -1) { + b->counter = 0; + } + + if (++b->counter == BN_BLINDING_COUNTER && b->e != NULL && + !(b->flags & BN_BLINDING_NO_RECREATE)) { + /* re-create blinding parameters */ + if (!BN_BLINDING_create_param(b, NULL, NULL, ctx, NULL, NULL)) { + goto err; + } + } else if (!(b->flags & BN_BLINDING_NO_UPDATE)) { + if (!BN_mod_mul(b->A, b->A, b->A, b->mod, ctx)) { + goto err; + } + if (!BN_mod_mul(b->Ai, b->Ai, b->Ai, b->mod, ctx)) { + goto err; + } + } + + ret = 1; + +err: + if (b->counter == BN_BLINDING_COUNTER) { + b->counter = 0; + } + return ret; +} + +int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx) { + return BN_BLINDING_convert_ex(n, NULL, b, ctx); +} + +int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *ctx) { + int ret = 1; + + if (b->A == NULL || b->Ai == NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED); + return 0; + } + + if (b->counter == -1) { + /* Fresh blinding, doesn't need updating. */ + b->counter = 0; + } else if (!BN_BLINDING_update(b, ctx)) { + return 0; + } + + if (r != NULL) { + if (!BN_copy(r, b->Ai)) { + ret = 0; + } + } + + if (!BN_mod_mul(n, n, b->A, b->mod, ctx)) { + ret = 0; + } + + return ret; +} + +int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx) { + return BN_BLINDING_invert_ex(n, NULL, b, ctx); +} + +int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, + BN_CTX *ctx) { + int ret; + + if (r != NULL) { + ret = BN_mod_mul(n, n, r, b->mod, ctx); + } else { + if (b->Ai == NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED); + return 0; + } + ret = BN_mod_mul(n, n, b->Ai, b->mod, ctx); + } + + return ret; +} + +unsigned long BN_BLINDING_get_flags(const BN_BLINDING *b) { return b->flags; } + +void BN_BLINDING_set_flags(BN_BLINDING *b, unsigned long flags) { + b->flags = flags; +} + +BN_BLINDING *BN_BLINDING_create_param( + BN_BLINDING *b, const BIGNUM *e, BIGNUM *m, BN_CTX *ctx, + int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx), + BN_MONT_CTX *m_ctx) { + int retry_counter = 32; + BN_BLINDING *ret = NULL; + + if (b == NULL) { + ret = BN_BLINDING_new(NULL, NULL, m); + } else { + ret = b; + } + + if (ret == NULL) { + goto err; + } + + if (ret->A == NULL && (ret->A = BN_new()) == NULL) { + goto err; + } + if (ret->Ai == NULL && (ret->Ai = BN_new()) == NULL) { + goto err; + } + + if (e != NULL) { + BN_free(ret->e); + ret->e = BN_dup(e); + } + if (ret->e == NULL) { + goto err; + } + + if (bn_mod_exp != NULL) { + ret->bn_mod_exp = bn_mod_exp; + } + if (m_ctx != NULL) { + ret->m_ctx = m_ctx; + } + + do { + if (!BN_rand_range(ret->A, ret->mod)) { + goto err; + } + if (BN_mod_inverse(ret->Ai, ret->A, ret->mod, ctx) == NULL) { + /* this should almost never happen for good RSA keys */ + uint32_t error = ERR_peek_last_error(); + if (ERR_GET_REASON(error) == BN_R_NO_INVERSE) { + if (retry_counter-- == 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_MANY_ITERATIONS); + goto err; + } + ERR_clear_error(); + } else { + goto err; + } + } else { + break; + } + } while (1); + + if (ret->bn_mod_exp != NULL && ret->m_ctx != NULL) { + if (!ret->bn_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx, ret->m_ctx)) { + goto err; + } + } else { + if (!BN_mod_exp(ret->A, ret->A, ret->e, ret->mod, ctx)) { + goto err; + } + } + + return ret; + +err: + if (b == NULL) { + BN_BLINDING_free(ret); + ret = NULL; + } + + return ret; +} + +static BIGNUM *rsa_get_public_exp(const BIGNUM *d, const BIGNUM *p, + const BIGNUM *q, BN_CTX *ctx) { + BIGNUM *ret = NULL, *r0, *r1, *r2; + + if (d == NULL || p == NULL || q == NULL) { + return NULL; + } + + BN_CTX_start(ctx); + r0 = BN_CTX_get(ctx); + r1 = BN_CTX_get(ctx); + r2 = BN_CTX_get(ctx); + if (r2 == NULL) { + goto err; + } + + if (!BN_sub(r1, p, BN_value_one())) { + goto err; + } + if (!BN_sub(r2, q, BN_value_one())) { + goto err; + } + if (!BN_mul(r0, r1, r2, ctx)) { + goto err; + } + + ret = BN_mod_inverse(NULL, d, r0, ctx); + +err: + BN_CTX_end(ctx); + return ret; +} + +BN_BLINDING *rsa_setup_blinding(RSA *rsa, BN_CTX *in_ctx) { + BIGNUM local_n; + BIGNUM *e, *n; + BN_CTX *ctx; + BN_BLINDING *ret = NULL; + BN_MONT_CTX *mont_ctx = NULL; + + if (in_ctx == NULL) { + ctx = BN_CTX_new(); + if (ctx == NULL) { + return 0; + } + } else { + ctx = in_ctx; + } + + BN_CTX_start(ctx); + e = BN_CTX_get(ctx); + if (e == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (rsa->e == NULL) { + e = rsa_get_public_exp(rsa->d, rsa->p, rsa->q, ctx); + if (e == NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_NO_PUBLIC_EXPONENT); + goto err; + } + } else { + e = rsa->e; + } + + n = &local_n; + BN_with_flags(n, rsa->n, BN_FLG_CONSTTIME); + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { + mont_ctx = + BN_MONT_CTX_set_locked(&rsa->_method_mod_n, &rsa->lock, rsa->n, ctx); + if (mont_ctx == NULL) { + goto err; + } + } + + ret = BN_BLINDING_create_param(NULL, e, n, ctx, rsa->meth->bn_mod_exp, + mont_ctx); + if (ret == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB); + goto err; + } + +err: + BN_CTX_end(ctx); + if (in_ctx == NULL) { + BN_CTX_free(ctx); + } + if (rsa->e == NULL) { + BN_free(e); + } + + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/rsa/internal.h b/TMessagesProj/jni/boringssl/crypto/rsa/internal.h new file mode 100644 index 00000000..c0044c3d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rsa/internal.h @@ -0,0 +1,142 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_RSA_INTERNAL_H +#define OPENSSL_HEADER_RSA_INTERNAL_H + +#include + + +#if defined(__cplusplus) +extern "C" { +#endif + + +#define RSA_PKCS1_PADDING_SIZE 11 + + +/* BN_BLINDING flags */ +#define BN_BLINDING_NO_UPDATE 0x00000001 +#define BN_BLINDING_NO_RECREATE 0x00000002 + +BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod); +void BN_BLINDING_free(BN_BLINDING *b); +int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx); +int BN_BLINDING_convert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx); +int BN_BLINDING_invert(BIGNUM *n, BN_BLINDING *b, BN_CTX *ctx); +int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *); +int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b, BN_CTX *); +unsigned long BN_BLINDING_get_flags(const BN_BLINDING *); +void BN_BLINDING_set_flags(BN_BLINDING *, unsigned long); +BN_BLINDING *BN_BLINDING_create_param( + BN_BLINDING *b, const BIGNUM *e, BIGNUM *m, BN_CTX *ctx, + int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx), + BN_MONT_CTX *m_ctx); +BN_BLINDING *rsa_setup_blinding(RSA *rsa, BN_CTX *in_ctx); + + +int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned to_len, + const uint8_t *from, unsigned from_len); +int RSA_padding_check_PKCS1_type_1(uint8_t *to, unsigned to_len, + const uint8_t *from, unsigned from_len); +int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned to_len, + const uint8_t *from, unsigned from_len); +int RSA_padding_check_PKCS1_type_2(uint8_t *to, unsigned to_len, + const uint8_t *from, unsigned from_len); +int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len, + const uint8_t *from, unsigned from_len, + const uint8_t *param, unsigned plen, + const EVP_MD *md, const EVP_MD *mgf1md); +int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len, + const uint8_t *from, unsigned from_len, + const uint8_t *param, unsigned plen, + const EVP_MD *md, const EVP_MD *mgf1md); +int RSA_padding_add_none(uint8_t *to, unsigned to_len, const uint8_t *from, + unsigned from_len); + +/* RSA_private_transform calls either the method-specific |private_transform| + * function (if given) or the generic one. See the comment for + * |private_transform| in |rsa_meth_st|. */ +int RSA_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in, + size_t len); + + +/* RSA_additional_prime contains information about the third, forth etc prime + * in a multi-prime RSA key. */ +typedef struct RSA_additional_prime_st { + BIGNUM *prime; + /* exp is d^{prime-1} mod prime */ + BIGNUM *exp; + /* coeff is such that r×coeff ≡ 1 mod prime. */ + BIGNUM *coeff; + + /* Values below here are not in the ASN.1 serialisation. */ + + /* r is the product of all primes (including p and q) prior to this one. */ + BIGNUM *r; + /* method_mod is managed by the |RSA_METHOD|. */ + BN_MONT_CTX *method_mod; +} RSA_additional_prime; + +void RSA_additional_prime_free(RSA_additional_prime *ap); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_RSA_INTERNAL_H */ diff --git a/TMessagesProj/jni/boringssl/crypto/rsa/padding.c b/TMessagesProj/jni/boringssl/crypto/rsa/padding.c new file mode 100644 index 00000000..5a42e248 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rsa/padding.c @@ -0,0 +1,732 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2005. + */ +/* ==================================================================== + * Copyright (c) 2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "internal.h" + +/* TODO(fork): don't the check functions have to be constant time? */ + +int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned tlen, + const uint8_t *from, unsigned flen) { + unsigned j; + uint8_t *p; + + if (tlen < RSA_PKCS1_PADDING_SIZE) { + OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL); + return 0; + } + + if (flen > tlen - RSA_PKCS1_PADDING_SIZE) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + return 0; + } + + p = (uint8_t *)to; + + *(p++) = 0; + *(p++) = 1; /* Private Key BT (Block Type) */ + + /* pad out with 0xff data */ + j = tlen - 3 - flen; + memset(p, 0xff, j); + p += j; + *(p++) = 0; + memcpy(p, from, (unsigned int)flen); + return 1; +} + +int RSA_padding_check_PKCS1_type_1(uint8_t *to, unsigned tlen, + const uint8_t *from, unsigned flen) { + unsigned i, j; + const uint8_t *p; + + if (flen < 2) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_SMALL); + return -1; + } + + p = from; + if ((*(p++) != 0) || (*(p++) != 1)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BLOCK_TYPE_IS_NOT_01); + return -1; + } + + /* scan over padding data */ + j = flen - 2; /* one for leading 00, one for type. */ + for (i = 0; i < j; i++) { + /* should decrypt to 0xff */ + if (*p != 0xff) { + if (*p == 0) { + p++; + break; + } else { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_FIXED_HEADER_DECRYPT); + return -1; + } + } + p++; + } + + if (i == j) { + OPENSSL_PUT_ERROR(RSA, RSA_R_NULL_BEFORE_BLOCK_MISSING); + return -1; + } + + if (i < 8) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_PAD_BYTE_COUNT); + return -1; + } + i++; /* Skip over the '\0' */ + j -= i; + if (j > tlen) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE); + return -1; + } + memcpy(to, p, j); + + return j; +} + +int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned tlen, + const uint8_t *from, unsigned flen) { + unsigned i, j; + uint8_t *p; + + if (tlen < RSA_PKCS1_PADDING_SIZE) { + OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL); + return 0; + } + + if (flen > tlen - RSA_PKCS1_PADDING_SIZE) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + return 0; + } + + p = (unsigned char *)to; + + *(p++) = 0; + *(p++) = 2; /* Public Key BT (Block Type) */ + + /* pad out with non-zero random data */ + j = tlen - 3 - flen; + + if (!RAND_bytes(p, j)) { + return 0; + } + + for (i = 0; i < j; i++) { + while (*p == 0) { + if (!RAND_bytes(p, 1)) { + return 0; + } + } + p++; + } + + *(p++) = 0; + + memcpy(p, from, (unsigned int)flen); + return 1; +} + +/* constant_time_byte_eq returns 1 if |x| == |y| and 0 otherwise. */ +static int constant_time_byte_eq(unsigned char a, unsigned char b) { + unsigned char z = ~(a ^ b); + z &= z >> 4; + z &= z >> 2; + z &= z >> 1; + + return z; +} + +/* constant_time_select returns |x| if |v| is 1 and |y| if |v| is 0. + * Its behavior is undefined if |v| takes any other value. */ +static int constant_time_select(int v, int x, int y) { + return ((~(v - 1)) & x) | ((v - 1) & y); +} + +/* constant_time_le returns 1 if |x| <= |y| and 0 otherwise. + * |x| and |y| must be positive. */ +static int constant_time_le(int x, int y) { + return ((x - y - 1) >> (sizeof(int) * 8 - 1)) & 1; +} + +int RSA_message_index_PKCS1_type_2(const uint8_t *from, size_t from_len, + size_t *out_index) { + size_t i; + int first_byte_is_zero, second_byte_is_two, looking_for_index; + int valid_index, zero_index = 0; + + /* PKCS#1 v1.5 decryption. See "PKCS #1 v2.2: RSA Cryptography + * Standard", section 7.2.2. */ + if (from_len < RSA_PKCS1_PADDING_SIZE) { + /* |from| is zero-padded to the size of the RSA modulus, a public value, so + * this can be rejected in non-constant time. */ + *out_index = 0; + return 0; + } + + first_byte_is_zero = constant_time_byte_eq(from[0], 0); + second_byte_is_two = constant_time_byte_eq(from[1], 2); + + looking_for_index = 1; + for (i = 2; i < from_len; i++) { + int equals0 = constant_time_byte_eq(from[i], 0); + zero_index = + constant_time_select(looking_for_index & equals0, i, zero_index); + looking_for_index = constant_time_select(equals0, 0, looking_for_index); + } + + /* The input must begin with 00 02. */ + valid_index = first_byte_is_zero; + valid_index &= second_byte_is_two; + + /* We must have found the end of PS. */ + valid_index &= ~looking_for_index; + + /* PS must be at least 8 bytes long, and it starts two bytes into |from|. */ + valid_index &= constant_time_le(2 + 8, zero_index); + + /* Skip the zero byte. */ + zero_index++; + + *out_index = constant_time_select(valid_index, zero_index, 0); + return valid_index; +} + +int RSA_padding_check_PKCS1_type_2(uint8_t *to, unsigned tlen, + const uint8_t *from, unsigned flen) { + size_t msg_index, msg_len; + + if (flen == 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY); + return -1; + } + + /* NOTE: Although |RSA_message_index_PKCS1_type_2| itself is constant time, + * the API contracts of this function and |RSA_decrypt| with + * |RSA_PKCS1_PADDING| make it impossible to completely avoid Bleichenbacher's + * attack. */ + if (!RSA_message_index_PKCS1_type_2(from, flen, &msg_index)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_PKCS_DECODING_ERROR); + return -1; + } + + msg_len = flen - msg_index; + if (msg_len > tlen) { + /* This shouldn't happen because this function is always called with |tlen| + * the key size and |flen| is bounded by the key size. */ + OPENSSL_PUT_ERROR(RSA, RSA_R_PKCS_DECODING_ERROR); + return -1; + } + memcpy(to, &from[msg_index], msg_len); + return msg_len; +} + +int RSA_padding_add_none(uint8_t *to, unsigned tlen, const uint8_t *from, unsigned flen) { + if (flen > tlen) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + return 0; + } + + if (flen < tlen) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE); + return 0; + } + + memcpy(to, from, (unsigned int)flen); + return 1; +} + +int PKCS1_MGF1(uint8_t *mask, unsigned len, const uint8_t *seed, + unsigned seedlen, const EVP_MD *dgst) { + unsigned outlen = 0; + uint32_t i; + uint8_t cnt[4]; + EVP_MD_CTX c; + uint8_t md[EVP_MAX_MD_SIZE]; + unsigned mdlen; + int ret = -1; + + EVP_MD_CTX_init(&c); + mdlen = EVP_MD_size(dgst); + + for (i = 0; outlen < len; i++) { + cnt[0] = (uint8_t)((i >> 24) & 255); + cnt[1] = (uint8_t)((i >> 16) & 255); + cnt[2] = (uint8_t)((i >> 8)) & 255; + cnt[3] = (uint8_t)(i & 255); + if (!EVP_DigestInit_ex(&c, dgst, NULL) || + !EVP_DigestUpdate(&c, seed, seedlen) || !EVP_DigestUpdate(&c, cnt, 4)) { + goto err; + } + + if (outlen + mdlen <= len) { + if (!EVP_DigestFinal_ex(&c, mask + outlen, NULL)) { + goto err; + } + outlen += mdlen; + } else { + if (!EVP_DigestFinal_ex(&c, md, NULL)) { + goto err; + } + memcpy(mask + outlen, md, len - outlen); + outlen = len; + } + } + ret = 0; + +err: + EVP_MD_CTX_cleanup(&c); + return ret; +} + +int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned tlen, + const uint8_t *from, unsigned flen, + const uint8_t *param, unsigned plen, + const EVP_MD *md, const EVP_MD *mgf1md) { + unsigned i, emlen, mdlen; + uint8_t *db, *seed; + uint8_t *dbmask = NULL, seedmask[EVP_MAX_MD_SIZE]; + int ret = 0; + + if (md == NULL) { + md = EVP_sha1(); + } + if (mgf1md == NULL) { + mgf1md = md; + } + + mdlen = EVP_MD_size(md); + + if (tlen < 2 * mdlen + 2) { + OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL); + return 0; + } + + emlen = tlen - 1; + if (flen > emlen - 2 * mdlen - 1) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + return 0; + } + + if (emlen < 2 * mdlen + 1) { + OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL); + return 0; + } + + to[0] = 0; + seed = to + 1; + db = to + mdlen + 1; + + if (!EVP_Digest((void *)param, plen, db, NULL, md, NULL)) { + return 0; + } + memset(db + mdlen, 0, emlen - flen - 2 * mdlen - 1); + db[emlen - flen - mdlen - 1] = 0x01; + memcpy(db + emlen - flen - mdlen, from, flen); + if (!RAND_bytes(seed, mdlen)) { + return 0; + } + + dbmask = OPENSSL_malloc(emlen - mdlen); + if (dbmask == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md) < 0) { + goto out; + } + for (i = 0; i < emlen - mdlen; i++) { + db[i] ^= dbmask[i]; + } + + if (PKCS1_MGF1(seedmask, mdlen, db, emlen - mdlen, mgf1md) < 0) { + goto out; + } + for (i = 0; i < mdlen; i++) { + seed[i] ^= seedmask[i]; + } + ret = 1; + +out: + OPENSSL_free(dbmask); + return ret; +} + +int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *to, unsigned tlen, + const uint8_t *from, unsigned flen, + const uint8_t *param, unsigned plen, + const EVP_MD *md, const EVP_MD *mgf1md) { + unsigned i, dblen, mlen = -1, mdlen; + const uint8_t *maskeddb, *maskedseed; + uint8_t *db = NULL, seed[EVP_MAX_MD_SIZE], phash[EVP_MAX_MD_SIZE]; + int bad, looking_for_one_byte, one_index = 0; + + if (md == NULL) { + md = EVP_sha1(); + } + if (mgf1md == NULL) { + mgf1md = md; + } + + mdlen = EVP_MD_size(md); + + /* The encoded message is one byte smaller than the modulus to ensure that it + * doesn't end up greater than the modulus. Thus there's an extra "+1" here + * compared to https://tools.ietf.org/html/rfc2437#section-9.1.1.2. */ + if (flen < 1 + 2*mdlen + 1) { + /* 'flen' is the length of the modulus, i.e. does not depend on the + * particular ciphertext. */ + goto decoding_err; + } + + dblen = flen - mdlen - 1; + db = OPENSSL_malloc(dblen); + if (db == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + maskedseed = from + 1; + maskeddb = from + 1 + mdlen; + + if (PKCS1_MGF1(seed, mdlen, maskeddb, dblen, mgf1md)) { + goto err; + } + for (i = 0; i < mdlen; i++) { + seed[i] ^= maskedseed[i]; + } + + if (PKCS1_MGF1(db, dblen, seed, mdlen, mgf1md)) { + goto err; + } + for (i = 0; i < dblen; i++) { + db[i] ^= maskeddb[i]; + } + + if (!EVP_Digest((void *)param, plen, phash, NULL, md, NULL)) { + goto err; + } + + bad = CRYPTO_memcmp(db, phash, mdlen); + bad |= from[0]; + + looking_for_one_byte = 1; + for (i = mdlen; i < dblen; i++) { + int equals1 = constant_time_byte_eq(db[i], 1); + int equals0 = constant_time_byte_eq(db[i], 0); + one_index = + constant_time_select(looking_for_one_byte & equals1, i, one_index); + looking_for_one_byte = + constant_time_select(equals1, 0, looking_for_one_byte); + bad |= looking_for_one_byte & ~equals0; + } + + bad |= looking_for_one_byte; + + if (bad) { + goto decoding_err; + } + + one_index++; + mlen = dblen - one_index; + if (tlen < mlen) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE); + mlen = -1; + } else { + memcpy(to, db + one_index, mlen); + } + + OPENSSL_free(db); + return mlen; + +decoding_err: + /* to avoid chosen ciphertext attacks, the error message should not reveal + * which kind of decoding error happened */ + OPENSSL_PUT_ERROR(RSA, RSA_R_OAEP_DECODING_ERROR); + err: + OPENSSL_free(db); + return -1; +} + +static const unsigned char zeroes[] = {0,0,0,0,0,0,0,0}; + +int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash, + const EVP_MD *Hash, const EVP_MD *mgf1Hash, + const uint8_t *EM, int sLen) { + int i; + int ret = 0; + int maskedDBLen, MSBits, emLen; + size_t hLen; + const uint8_t *H; + uint8_t *DB = NULL; + EVP_MD_CTX ctx; + uint8_t H_[EVP_MAX_MD_SIZE]; + EVP_MD_CTX_init(&ctx); + + if (mgf1Hash == NULL) { + mgf1Hash = Hash; + } + + hLen = EVP_MD_size(Hash); + + /* Negative sLen has special meanings: + * -1 sLen == hLen + * -2 salt length is autorecovered from signature + * -N reserved */ + if (sLen == -1) { + sLen = hLen; + } else if (sLen == -2) { + sLen = -2; + } else if (sLen < -2) { + OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_CHECK_FAILED); + goto err; + } + + MSBits = (BN_num_bits(rsa->n) - 1) & 0x7; + emLen = RSA_size(rsa); + if (EM[0] & (0xFF << MSBits)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_FIRST_OCTET_INVALID); + goto err; + } + if (MSBits == 0) { + EM++; + emLen--; + } + if (emLen < ((int)hLen + sLen + 2)) { + /* sLen can be small negative */ + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE); + goto err; + } + if (EM[emLen - 1] != 0xbc) { + OPENSSL_PUT_ERROR(RSA, RSA_R_LAST_OCTET_INVALID); + goto err; + } + maskedDBLen = emLen - hLen - 1; + H = EM + maskedDBLen; + DB = OPENSSL_malloc(maskedDBLen); + if (!DB) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + if (PKCS1_MGF1(DB, maskedDBLen, H, hLen, mgf1Hash) < 0) { + goto err; + } + for (i = 0; i < maskedDBLen; i++) { + DB[i] ^= EM[i]; + } + if (MSBits) { + DB[0] &= 0xFF >> (8 - MSBits); + } + for (i = 0; DB[i] == 0 && i < (maskedDBLen - 1); i++) { + ; + } + if (DB[i++] != 0x1) { + OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_RECOVERY_FAILED); + goto err; + } + if (sLen >= 0 && (maskedDBLen - i) != sLen) { + OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_CHECK_FAILED); + goto err; + } + if (!EVP_DigestInit_ex(&ctx, Hash, NULL) || + !EVP_DigestUpdate(&ctx, zeroes, sizeof zeroes) || + !EVP_DigestUpdate(&ctx, mHash, hLen)) { + goto err; + } + if (maskedDBLen - i) { + if (!EVP_DigestUpdate(&ctx, DB + i, maskedDBLen - i)) { + goto err; + } + } + if (!EVP_DigestFinal_ex(&ctx, H_, NULL)) { + goto err; + } + if (memcmp(H_, H, hLen)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_SIGNATURE); + ret = 0; + } else { + ret = 1; + } + +err: + OPENSSL_free(DB); + EVP_MD_CTX_cleanup(&ctx); + + return ret; +} + +int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM, + const unsigned char *mHash, + const EVP_MD *Hash, const EVP_MD *mgf1Hash, + int sLen) { + int i; + int ret = 0; + size_t maskedDBLen, MSBits, emLen; + size_t hLen; + unsigned char *H, *salt = NULL, *p; + EVP_MD_CTX ctx; + + if (mgf1Hash == NULL) { + mgf1Hash = Hash; + } + + hLen = EVP_MD_size(Hash); + + /* Negative sLen has special meanings: + * -1 sLen == hLen + * -2 salt length is maximized + * -N reserved */ + if (sLen == -1) { + sLen = hLen; + } else if (sLen == -2) { + sLen = -2; + } else if (sLen < -2) { + OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_CHECK_FAILED); + goto err; + } + + if (BN_is_zero(rsa->n)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY); + goto err; + } + + MSBits = (BN_num_bits(rsa->n) - 1) & 0x7; + emLen = RSA_size(rsa); + if (MSBits == 0) { + assert(emLen >= 1); + *EM++ = 0; + emLen--; + } + if (sLen == -2) { + if (emLen < hLen + 2) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + goto err; + } + sLen = emLen - hLen - 2; + } else if (emLen < hLen + sLen + 2) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE); + goto err; + } + if (sLen > 0) { + salt = OPENSSL_malloc(sLen); + if (!salt) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!RAND_bytes(salt, sLen)) { + goto err; + } + } + maskedDBLen = emLen - hLen - 1; + H = EM + maskedDBLen; + EVP_MD_CTX_init(&ctx); + if (!EVP_DigestInit_ex(&ctx, Hash, NULL) || + !EVP_DigestUpdate(&ctx, zeroes, sizeof zeroes) || + !EVP_DigestUpdate(&ctx, mHash, hLen)) { + goto err; + } + if (sLen && !EVP_DigestUpdate(&ctx, salt, sLen)) { + goto err; + } + if (!EVP_DigestFinal_ex(&ctx, H, NULL)) { + goto err; + } + EVP_MD_CTX_cleanup(&ctx); + + /* Generate dbMask in place then perform XOR on it */ + if (PKCS1_MGF1(EM, maskedDBLen, H, hLen, mgf1Hash)) { + goto err; + } + + p = EM; + + /* Initial PS XORs with all zeroes which is a NOP so just update + * pointer. Note from a test above this value is guaranteed to + * be non-negative. */ + p += emLen - sLen - hLen - 2; + *p++ ^= 0x1; + if (sLen > 0) { + for (i = 0; i < sLen; i++) { + *p++ ^= salt[i]; + } + } + if (MSBits) { + EM[0] &= 0xFF >> (8 - MSBits); + } + + /* H is already in place so just set final 0xbc */ + + EM[emLen - 1] = 0xbc; + + ret = 1; + +err: + OPENSSL_free(salt); + + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/rsa/rsa.c b/TMessagesProj/jni/boringssl/crypto/rsa/rsa.c new file mode 100644 index 00000000..2f23165c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rsa/rsa.c @@ -0,0 +1,797 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +extern const RSA_METHOD RSA_default_method; + +static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT; + +RSA *RSA_new(void) { return RSA_new_method(NULL); } + +RSA *RSA_new_method(const ENGINE *engine) { + RSA *rsa = (RSA *)OPENSSL_malloc(sizeof(RSA)); + if (rsa == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return NULL; + } + + memset(rsa, 0, sizeof(RSA)); + + if (engine) { + rsa->meth = ENGINE_get_RSA_method(engine); + } + + if (rsa->meth == NULL) { + rsa->meth = (RSA_METHOD*) &RSA_default_method; + } + METHOD_ref(rsa->meth); + + rsa->references = 1; + rsa->flags = rsa->meth->flags; + CRYPTO_MUTEX_init(&rsa->lock); + + if (!CRYPTO_new_ex_data(&g_ex_data_class, rsa, &rsa->ex_data)) { + METHOD_unref(rsa->meth); + OPENSSL_free(rsa); + return NULL; + } + + if (rsa->meth->init && !rsa->meth->init(rsa)) { + CRYPTO_free_ex_data(&g_ex_data_class, rsa, &rsa->ex_data); + METHOD_unref(rsa->meth); + OPENSSL_free(rsa); + return NULL; + } + + return rsa; +} + +void RSA_additional_prime_free(RSA_additional_prime *ap) { + if (ap == NULL) { + return; + } + + BN_clear_free(ap->prime); + BN_clear_free(ap->exp); + BN_clear_free(ap->coeff); + BN_clear_free(ap->r); + OPENSSL_free(ap); +} + +void RSA_free(RSA *rsa) { + unsigned u; + + if (rsa == NULL) { + return; + } + + if (!CRYPTO_refcount_dec_and_test_zero(&rsa->references)) { + return; + } + + if (rsa->meth->finish) { + rsa->meth->finish(rsa); + } + METHOD_unref(rsa->meth); + + CRYPTO_free_ex_data(&g_ex_data_class, rsa, &rsa->ex_data); + + BN_clear_free(rsa->n); + BN_clear_free(rsa->e); + BN_clear_free(rsa->d); + BN_clear_free(rsa->p); + BN_clear_free(rsa->q); + BN_clear_free(rsa->dmp1); + BN_clear_free(rsa->dmq1); + BN_clear_free(rsa->iqmp); + for (u = 0; u < rsa->num_blindings; u++) { + BN_BLINDING_free(rsa->blindings[u]); + } + OPENSSL_free(rsa->blindings); + OPENSSL_free(rsa->blindings_inuse); + if (rsa->additional_primes != NULL) { + sk_RSA_additional_prime_pop_free(rsa->additional_primes, + RSA_additional_prime_free); + } + CRYPTO_MUTEX_cleanup(&rsa->lock); + OPENSSL_free(rsa); +} + +int RSA_up_ref(RSA *rsa) { + CRYPTO_refcount_inc(&rsa->references); + return 1; +} + +int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) { + if (rsa->meth->keygen) { + return rsa->meth->keygen(rsa, bits, e_value, cb); + } + + return RSA_default_method.keygen(rsa, bits, e_value, cb); +} + +int RSA_generate_multi_prime_key(RSA *rsa, int bits, int num_primes, + BIGNUM *e_value, BN_GENCB *cb) { + if (rsa->meth->multi_prime_keygen) { + return rsa->meth->multi_prime_keygen(rsa, bits, num_primes, e_value, cb); + } + + return RSA_default_method.multi_prime_keygen(rsa, bits, num_primes, e_value, + cb); +} + +int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + if (rsa->meth->encrypt) { + return rsa->meth->encrypt(rsa, out_len, out, max_out, in, in_len, padding); + } + + return RSA_default_method.encrypt(rsa, out_len, out, max_out, in, in_len, + padding); +} + +int RSA_public_encrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa, + int padding) { + size_t out_len; + + if (!RSA_encrypt(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) { + return -1; + } + + return out_len; +} + +int RSA_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + if (rsa->meth->sign_raw) { + return rsa->meth->sign_raw(rsa, out_len, out, max_out, in, in_len, padding); + } + + return RSA_default_method.sign_raw(rsa, out_len, out, max_out, in, in_len, + padding); +} + +int RSA_private_encrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa, + int padding) { + size_t out_len; + + if (!RSA_sign_raw(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) { + return -1; + } + + return out_len; +} + +int RSA_decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + if (rsa->meth->decrypt) { + return rsa->meth->decrypt(rsa, out_len, out, max_out, in, in_len, padding); + } + + return RSA_default_method.decrypt(rsa, out_len, out, max_out, in, in_len, + padding); +} + +int RSA_private_decrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa, + int padding) { + size_t out_len; + + if (!RSA_decrypt(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) { + return -1; + } + + return out_len; +} + +int RSA_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + if (rsa->meth->verify_raw) { + return rsa->meth->verify_raw(rsa, out_len, out, max_out, in, in_len, padding); + } + + return RSA_default_method.verify_raw(rsa, out_len, out, max_out, in, in_len, + padding); +} + +int RSA_public_decrypt(int flen, const uint8_t *from, uint8_t *to, RSA *rsa, + int padding) { + size_t out_len; + + if (!RSA_verify_raw(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) { + return -1; + } + + return out_len; +} + +unsigned RSA_size(const RSA *rsa) { + if (rsa->meth->size) { + return rsa->meth->size(rsa); + } + + return RSA_default_method.size(rsa); +} + +int RSA_is_opaque(const RSA *rsa) { + return rsa->meth && (rsa->meth->flags & RSA_FLAG_OPAQUE); +} + +int RSA_supports_digest(const RSA *rsa, const EVP_MD *md) { + if (rsa->meth && rsa->meth->supports_digest) { + return rsa->meth->supports_digest(rsa, md); + } + return 1; +} + +int RSA_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) { + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, new_func, + dup_func, free_func)) { + return -1; + } + return index; +} + +int RSA_set_ex_data(RSA *d, int idx, void *arg) { + return CRYPTO_set_ex_data(&d->ex_data, idx, arg); +} + +void *RSA_get_ex_data(const RSA *d, int idx) { + return CRYPTO_get_ex_data(&d->ex_data, idx); +} + +/* SSL_SIG_LENGTH is the size of an SSL/TLS (prior to TLS 1.2) signature: it's + * the length of an MD5 and SHA1 hash. */ +static const unsigned SSL_SIG_LENGTH = 36; + +/* pkcs1_sig_prefix contains the ASN.1, DER encoded prefix for a hash that is + * to be signed with PKCS#1. */ +struct pkcs1_sig_prefix { + /* nid identifies the hash function. */ + int nid; + /* len is the number of bytes of |bytes| which are valid. */ + uint8_t len; + /* bytes contains the DER bytes. */ + uint8_t bytes[19]; +}; + +/* kPKCS1SigPrefixes contains the ASN.1 prefixes for PKCS#1 signatures with + * different hash functions. */ +static const struct pkcs1_sig_prefix kPKCS1SigPrefixes[] = { + { + NID_md5, + 18, + {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x02, 0x05, 0x05, 0x00, 0x04, 0x10}, + }, + { + NID_sha1, + 15, + {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, + 0x00, 0x04, 0x14}, + }, + { + NID_sha224, + 19, + {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, + 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c}, + }, + { + NID_sha256, + 19, + {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, + 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20}, + }, + { + NID_sha384, + 19, + {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, + 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}, + }, + { + NID_sha512, + 19, + {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, + 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}, + }, + { + NID_undef, 0, {0}, + }, +}; + +int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len, + int *is_alloced, int hash_nid, const uint8_t *msg, + size_t msg_len) { + unsigned i; + + if (hash_nid == NID_md5_sha1) { + /* Special case: SSL signature, just check the length. */ + if (msg_len != SSL_SIG_LENGTH) { + OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH); + return 0; + } + + *out_msg = (uint8_t*) msg; + *out_msg_len = SSL_SIG_LENGTH; + *is_alloced = 0; + return 1; + } + + for (i = 0; kPKCS1SigPrefixes[i].nid != NID_undef; i++) { + const struct pkcs1_sig_prefix *sig_prefix = &kPKCS1SigPrefixes[i]; + if (sig_prefix->nid != hash_nid) { + continue; + } + + const uint8_t* prefix = sig_prefix->bytes; + unsigned prefix_len = sig_prefix->len; + unsigned signed_msg_len; + uint8_t *signed_msg; + + signed_msg_len = prefix_len + msg_len; + if (signed_msg_len < prefix_len) { + OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_LONG); + return 0; + } + + signed_msg = OPENSSL_malloc(signed_msg_len); + if (!signed_msg) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return 0; + } + + memcpy(signed_msg, prefix, prefix_len); + memcpy(signed_msg + prefix_len, msg, msg_len); + + *out_msg = signed_msg; + *out_msg_len = signed_msg_len; + *is_alloced = 1; + + return 1; + } + + OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE); + return 0; +} + +int RSA_sign(int hash_nid, const uint8_t *in, unsigned in_len, uint8_t *out, + unsigned *out_len, RSA *rsa) { + const unsigned rsa_size = RSA_size(rsa); + int ret = 0; + uint8_t *signed_msg; + size_t signed_msg_len; + int signed_msg_is_alloced = 0; + size_t size_t_out_len; + + if (rsa->meth->sign) { + return rsa->meth->sign(hash_nid, in, in_len, out, out_len, rsa); + } + + if (!RSA_add_pkcs1_prefix(&signed_msg, &signed_msg_len, + &signed_msg_is_alloced, hash_nid, in, in_len)) { + return 0; + } + + if (rsa_size < RSA_PKCS1_PADDING_SIZE || + signed_msg_len > rsa_size - RSA_PKCS1_PADDING_SIZE) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY); + goto finish; + } + + if (RSA_sign_raw(rsa, &size_t_out_len, out, rsa_size, signed_msg, + signed_msg_len, RSA_PKCS1_PADDING)) { + *out_len = size_t_out_len; + ret = 1; + } + +finish: + if (signed_msg_is_alloced) { + OPENSSL_free(signed_msg); + } + return ret; +} + +int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len, + const uint8_t *sig, size_t sig_len, RSA *rsa) { + const size_t rsa_size = RSA_size(rsa); + uint8_t *buf = NULL; + int ret = 0; + uint8_t *signed_msg = NULL; + size_t signed_msg_len, len; + int signed_msg_is_alloced = 0; + + if (rsa->meth->verify) { + return rsa->meth->verify(hash_nid, msg, msg_len, sig, sig_len, rsa); + } + + if (sig_len != rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_WRONG_SIGNATURE_LENGTH); + return 0; + } + + if (hash_nid == NID_md5_sha1 && msg_len != SSL_SIG_LENGTH) { + OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH); + return 0; + } + + buf = OPENSSL_malloc(rsa_size); + if (!buf) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return 0; + } + + if (!RSA_verify_raw(rsa, &len, buf, rsa_size, sig, sig_len, + RSA_PKCS1_PADDING)) { + goto out; + } + + if (!RSA_add_pkcs1_prefix(&signed_msg, &signed_msg_len, + &signed_msg_is_alloced, hash_nid, msg, msg_len)) { + goto out; + } + + if (len != signed_msg_len || CRYPTO_memcmp(buf, signed_msg, len) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_SIGNATURE); + goto out; + } + + ret = 1; + +out: + OPENSSL_free(buf); + if (signed_msg_is_alloced) { + OPENSSL_free(signed_msg); + } + return ret; +} + +static void bn_free_and_null(BIGNUM **bn) { + BN_free(*bn); + *bn = NULL; +} + +int RSA_check_key(const RSA *key) { + BIGNUM n, pm1, qm1, lcm, gcd, de, dmp1, dmq1, iqmp; + BN_CTX *ctx; + int ok = 0, has_crt_values; + + if (RSA_is_opaque(key)) { + /* Opaque keys can't be checked. */ + return 1; + } + + if ((key->p != NULL) != (key->q != NULL)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ONLY_ONE_OF_P_Q_GIVEN); + return 0; + } + + if (!key->n || !key->e) { + OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING); + return 0; + } + + if (!key->d || !key->p) { + /* For a public key, or without p and q, there's nothing that can be + * checked. */ + return 1; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return 0; + } + + BN_init(&n); + BN_init(&pm1); + BN_init(&qm1); + BN_init(&lcm); + BN_init(&gcd); + BN_init(&de); + BN_init(&dmp1); + BN_init(&dmq1); + BN_init(&iqmp); + + if (!BN_mul(&n, key->p, key->q, ctx) || + /* lcm = lcm(prime-1, for all primes) */ + !BN_sub(&pm1, key->p, BN_value_one()) || + !BN_sub(&qm1, key->q, BN_value_one()) || + !BN_mul(&lcm, &pm1, &qm1, ctx) || + !BN_gcd(&gcd, &pm1, &qm1, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); + goto out; + } + + size_t num_additional_primes = 0; + if (key->additional_primes != NULL) { + num_additional_primes = sk_RSA_additional_prime_num(key->additional_primes); + } + + size_t i; + for (i = 0; i < num_additional_primes; i++) { + const RSA_additional_prime *ap = + sk_RSA_additional_prime_value(key->additional_primes, i); + if (!BN_mul(&n, &n, ap->prime, ctx) || + !BN_sub(&pm1, ap->prime, BN_value_one()) || + !BN_mul(&lcm, &lcm, &pm1, ctx) || + !BN_gcd(&gcd, &gcd, &pm1, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); + goto out; + } + } + + if (!BN_div(&lcm, NULL, &lcm, &gcd, ctx) || + !BN_gcd(&gcd, &pm1, &qm1, ctx) || + /* de = d*e mod lcm(prime-1, for all primes). */ + !BN_mod_mul(&de, key->d, key->e, &lcm, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); + goto out; + } + + if (BN_cmp(&n, key->n) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_N_NOT_EQUAL_P_Q); + goto out; + } + + if (!BN_is_one(&de)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_D_E_NOT_CONGRUENT_TO_1); + goto out; + } + + has_crt_values = key->dmp1 != NULL; + if (has_crt_values != (key->dmq1 != NULL) || + has_crt_values != (key->iqmp != NULL)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_INCONSISTENT_SET_OF_CRT_VALUES); + goto out; + } + + if (has_crt_values && num_additional_primes == 0) { + if (/* dmp1 = d mod (p-1) */ + !BN_mod(&dmp1, key->d, &pm1, ctx) || + /* dmq1 = d mod (q-1) */ + !BN_mod(&dmq1, key->d, &qm1, ctx) || + /* iqmp = q^-1 mod p */ + !BN_mod_inverse(&iqmp, key->q, key->p, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); + goto out; + } + + if (BN_cmp(&dmp1, key->dmp1) != 0 || + BN_cmp(&dmq1, key->dmq1) != 0 || + BN_cmp(&iqmp, key->iqmp) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_CRT_VALUES_INCORRECT); + goto out; + } + } + + ok = 1; + +out: + BN_free(&n); + BN_free(&pm1); + BN_free(&qm1); + BN_free(&lcm); + BN_free(&gcd); + BN_free(&de); + BN_free(&dmp1); + BN_free(&dmq1); + BN_free(&iqmp); + BN_CTX_free(ctx); + + return ok; +} + +int RSA_recover_crt_params(RSA *rsa) { + BN_CTX *ctx; + BIGNUM *totient, *rem, *multiple, *p_plus_q, *p_minus_q; + int ok = 0; + + if (rsa->n == NULL || rsa->e == NULL || rsa->d == NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY); + return 0; + } + + if (rsa->p || rsa->q || rsa->dmp1 || rsa->dmq1 || rsa->iqmp) { + OPENSSL_PUT_ERROR(RSA, RSA_R_CRT_PARAMS_ALREADY_GIVEN); + return 0; + } + + if (rsa->additional_primes != NULL) { + OPENSSL_PUT_ERROR(RSA, RSA_R_CANNOT_RECOVER_MULTI_PRIME_KEY); + return 0; + } + + /* This uses the algorithm from section 9B of the RSA paper: + * http://people.csail.mit.edu/rivest/Rsapaper.pdf */ + + ctx = BN_CTX_new(); + if (ctx == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return 0; + } + + BN_CTX_start(ctx); + totient = BN_CTX_get(ctx); + rem = BN_CTX_get(ctx); + multiple = BN_CTX_get(ctx); + p_plus_q = BN_CTX_get(ctx); + p_minus_q = BN_CTX_get(ctx); + + if (totient == NULL || rem == NULL || multiple == NULL || p_plus_q == NULL || + p_minus_q == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* ed-1 is a small multiple of φ(n). */ + if (!BN_mul(totient, rsa->e, rsa->d, ctx) || + !BN_sub_word(totient, 1) || + /* φ(n) = + * pq - p - q + 1 = + * n - (p + q) + 1 + * + * Thus n is a reasonable estimate for φ(n). So, (ed-1)/n will be very + * close. But, when we calculate the quotient, we'll be truncating it + * because we discard the remainder. Thus (ed-1)/multiple will be >= n, + * which the totient cannot be. So we add one to the estimate. + * + * Consider ed-1 as: + * + * multiple * (n - (p+q) + 1) = + * multiple*n - multiple*(p+q) + multiple + * + * When we divide by n, the first term becomes multiple and, since + * multiple and p+q is tiny compared to n, the second and third terms can + * be ignored. Thus I claim that subtracting one from the estimate is + * sufficient. */ + !BN_div(multiple, NULL, totient, rsa->n, ctx) || + !BN_add_word(multiple, 1) || + !BN_div(totient, rem, totient, multiple, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB); + goto err; + } + + if (!BN_is_zero(rem)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_RSA_PARAMETERS); + goto err; + } + + rsa->p = BN_new(); + rsa->q = BN_new(); + rsa->dmp1 = BN_new(); + rsa->dmq1 = BN_new(); + rsa->iqmp = BN_new(); + if (rsa->p == NULL || rsa->q == NULL || rsa->dmp1 == NULL || rsa->dmq1 == + NULL || rsa->iqmp == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* φ(n) = n - (p + q) + 1 => + * n - totient + 1 = p + q */ + if (!BN_sub(p_plus_q, rsa->n, totient) || + !BN_add_word(p_plus_q, 1) || + /* p - q = sqrt((p+q)^2 - 4n) */ + !BN_sqr(rem, p_plus_q, ctx) || + !BN_lshift(multiple, rsa->n, 2) || + !BN_sub(rem, rem, multiple) || + !BN_sqrt(p_minus_q, rem, ctx) || + /* q is 1/2 (p+q)-(p-q) */ + !BN_sub(rsa->q, p_plus_q, p_minus_q) || + !BN_rshift1(rsa->q, rsa->q) || + !BN_div(rsa->p, NULL, rsa->n, rsa->q, ctx) || + !BN_mul(multiple, rsa->p, rsa->q, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB); + goto err; + } + + if (BN_cmp(multiple, rsa->n) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_INTERNAL_ERROR); + goto err; + } + + if (!BN_sub(rem, rsa->p, BN_value_one()) || + !BN_mod(rsa->dmp1, rsa->d, rem, ctx) || + !BN_sub(rem, rsa->q, BN_value_one()) || + !BN_mod(rsa->dmq1, rsa->d, rem, ctx) || + !BN_mod_inverse(rsa->iqmp, rsa->q, rsa->p, ctx)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB); + goto err; + } + + ok = 1; + +err: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + if (!ok) { + bn_free_and_null(&rsa->p); + bn_free_and_null(&rsa->q); + bn_free_and_null(&rsa->dmp1); + bn_free_and_null(&rsa->dmq1); + bn_free_and_null(&rsa->iqmp); + } + return ok; +} + +int RSA_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in, + size_t len) { + if (rsa->meth->private_transform) { + return rsa->meth->private_transform(rsa, out, in, len); + } + + return RSA_default_method.private_transform(rsa, out, in, len); +} + +int RSA_blinding_on(RSA *rsa, BN_CTX *ctx) { + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/rsa/rsa_asn1.c b/TMessagesProj/jni/boringssl/crypto/rsa/rsa_asn1.c new file mode 100644 index 00000000..c62bcf08 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rsa/rsa_asn1.c @@ -0,0 +1,447 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 2000-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "internal.h" + + +static int parse_integer(CBS *cbs, BIGNUM **out) { + assert(*out == NULL); + *out = BN_new(); + if (*out == NULL) { + return 0; + } + return BN_cbs2unsigned(cbs, *out); +} + +static int marshal_integer(CBB *cbb, BIGNUM *bn) { + if (bn == NULL) { + /* An RSA object may be missing some components. */ + OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING); + return 0; + } + return BN_bn2cbb(cbb, bn); +} + +RSA *RSA_parse_public_key(CBS *cbs) { + RSA *ret = RSA_new(); + if (ret == NULL) { + return NULL; + } + CBS child; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || + !parse_integer(&child, &ret->n) || + !parse_integer(&child, &ret->e) || + CBS_len(&child) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING); + RSA_free(ret); + return NULL; + } + return ret; +} + +RSA *RSA_public_key_from_bytes(const uint8_t *in, size_t in_len) { + CBS cbs; + CBS_init(&cbs, in, in_len); + RSA *ret = RSA_parse_public_key(&cbs); + if (ret == NULL || CBS_len(&cbs) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING); + RSA_free(ret); + return NULL; + } + return ret; +} + +int RSA_marshal_public_key(CBB *cbb, const RSA *rsa) { + CBB child; + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) || + !marshal_integer(&child, rsa->n) || + !marshal_integer(&child, rsa->e) || + !CBB_flush(cbb)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); + return 0; + } + return 1; +} + +int RSA_public_key_to_bytes(uint8_t **out_bytes, size_t *out_len, + const RSA *rsa) { + CBB cbb; + CBB_zero(&cbb); + if (!CBB_init(&cbb, 0) || + !RSA_marshal_public_key(&cbb, rsa) || + !CBB_finish(&cbb, out_bytes, out_len)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); + CBB_cleanup(&cbb); + return 0; + } + return 1; +} + +/* kVersionTwoPrime and kVersionMulti are the supported values of the version + * field of an RSAPrivateKey structure (RFC 3447). */ +static const uint64_t kVersionTwoPrime = 0; +static const uint64_t kVersionMulti = 1; + +/* rsa_parse_additional_prime parses a DER-encoded OtherPrimeInfo from |cbs| and + * advances |cbs|. It returns a newly-allocated |RSA_additional_prime| on + * success or NULL on error. The |r| and |method_mod| fields of the result are + * set to NULL. */ +static RSA_additional_prime *rsa_parse_additional_prime(CBS *cbs) { + RSA_additional_prime *ret = OPENSSL_malloc(sizeof(RSA_additional_prime)); + if (ret == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + return 0; + } + memset(ret, 0, sizeof(RSA_additional_prime)); + + CBS child; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || + !parse_integer(&child, &ret->prime) || + !parse_integer(&child, &ret->exp) || + !parse_integer(&child, &ret->coeff) || + CBS_len(&child) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING); + RSA_additional_prime_free(ret); + return NULL; + } + + return ret; +} + +RSA *RSA_parse_private_key(CBS *cbs) { + BN_CTX *ctx = NULL; + BIGNUM *product_of_primes_so_far = NULL; + RSA *ret = RSA_new(); + if (ret == NULL) { + return NULL; + } + + CBS child; + uint64_t version; + if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1_uint64(&child, &version) || + (version != kVersionTwoPrime && version != kVersionMulti) || + !parse_integer(&child, &ret->n) || + !parse_integer(&child, &ret->e) || + !parse_integer(&child, &ret->d) || + !parse_integer(&child, &ret->p) || + !parse_integer(&child, &ret->q) || + !parse_integer(&child, &ret->dmp1) || + !parse_integer(&child, &ret->dmq1) || + !parse_integer(&child, &ret->iqmp)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_VERSION); + goto err; + } + + /* Multi-prime RSA requires a newer version. */ + if (version == kVersionMulti && + CBS_peek_asn1_tag(&child, CBS_ASN1_SEQUENCE)) { + CBS other_prime_infos; + if (!CBS_get_asn1(&child, &other_prime_infos, CBS_ASN1_SEQUENCE) || + CBS_len(&other_prime_infos) == 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING); + goto err; + } + ret->additional_primes = sk_RSA_additional_prime_new_null(); + if (ret->additional_primes == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + ctx = BN_CTX_new(); + product_of_primes_so_far = BN_new(); + if (ctx == NULL || + product_of_primes_so_far == NULL || + !BN_mul(product_of_primes_so_far, ret->p, ret->q, ctx)) { + goto err; + } + + while (CBS_len(&other_prime_infos) > 0) { + RSA_additional_prime *ap = rsa_parse_additional_prime(&other_prime_infos); + if (ap == NULL) { + goto err; + } + if (!sk_RSA_additional_prime_push(ret->additional_primes, ap)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + RSA_additional_prime_free(ap); + goto err; + } + ap->r = BN_dup(product_of_primes_so_far); + if (ap->r == NULL || + !BN_mul(product_of_primes_so_far, product_of_primes_so_far, + ap->prime, ctx)) { + goto err; + } + } + } + + if (CBS_len(&child) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING); + goto err; + } + + BN_CTX_free(ctx); + BN_free(product_of_primes_so_far); + return ret; + +err: + BN_CTX_free(ctx); + BN_free(product_of_primes_so_far); + RSA_free(ret); + return NULL; +} + +RSA *RSA_private_key_from_bytes(const uint8_t *in, size_t in_len) { + CBS cbs; + CBS_init(&cbs, in, in_len); + RSA *ret = RSA_parse_private_key(&cbs); + if (ret == NULL || CBS_len(&cbs) != 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING); + RSA_free(ret); + return NULL; + } + return ret; +} + +int RSA_marshal_private_key(CBB *cbb, const RSA *rsa) { + const int is_multiprime = + sk_RSA_additional_prime_num(rsa->additional_primes) > 0; + + CBB child; + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1_uint64(&child, + is_multiprime ? kVersionMulti : kVersionTwoPrime) || + !marshal_integer(&child, rsa->n) || + !marshal_integer(&child, rsa->e) || + !marshal_integer(&child, rsa->d) || + !marshal_integer(&child, rsa->p) || + !marshal_integer(&child, rsa->q) || + !marshal_integer(&child, rsa->dmp1) || + !marshal_integer(&child, rsa->dmq1) || + !marshal_integer(&child, rsa->iqmp)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); + return 0; + } + + if (is_multiprime) { + CBB other_prime_infos; + if (!CBB_add_asn1(&child, &other_prime_infos, CBS_ASN1_SEQUENCE)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); + return 0; + } + size_t i; + for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); i++) { + RSA_additional_prime *ap = + sk_RSA_additional_prime_value(rsa->additional_primes, i); + CBB other_prime_info; + if (!CBB_add_asn1(&other_prime_infos, &other_prime_info, + CBS_ASN1_SEQUENCE) || + !marshal_integer(&other_prime_info, ap->prime) || + !marshal_integer(&other_prime_info, ap->exp) || + !marshal_integer(&other_prime_info, ap->coeff)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); + return 0; + } + } + } + + if (!CBB_flush(cbb)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); + return 0; + } + return 1; +} + +int RSA_private_key_to_bytes(uint8_t **out_bytes, size_t *out_len, + const RSA *rsa) { + CBB cbb; + CBB_zero(&cbb); + if (!CBB_init(&cbb, 0) || + !RSA_marshal_private_key(&cbb, rsa) || + !CBB_finish(&cbb, out_bytes, out_len)) { + OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); + CBB_cleanup(&cbb); + return 0; + } + return 1; +} + +RSA *d2i_RSAPublicKey(RSA **out, const uint8_t **inp, long len) { + if (len < 0) { + return NULL; + } + CBS cbs; + CBS_init(&cbs, *inp, (size_t)len); + RSA *ret = RSA_parse_public_key(&cbs); + if (ret == NULL) { + return NULL; + } + if (out != NULL) { + RSA_free(*out); + *out = ret; + } + *inp += (size_t)len - CBS_len(&cbs); + return ret; +} + +int i2d_RSAPublicKey(const RSA *in, uint8_t **outp) { + uint8_t *der; + size_t der_len; + if (!RSA_public_key_to_bytes(&der, &der_len, in)) { + return -1; + } + if (der_len > INT_MAX) { + OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW); + OPENSSL_free(der); + return -1; + } + if (outp != NULL) { + if (*outp == NULL) { + *outp = der; + der = NULL; + } else { + memcpy(*outp, der, der_len); + *outp += der_len; + } + } + OPENSSL_free(der); + return (int)der_len; +} + +RSA *d2i_RSAPrivateKey(RSA **out, const uint8_t **inp, long len) { + if (len < 0) { + return NULL; + } + CBS cbs; + CBS_init(&cbs, *inp, (size_t)len); + RSA *ret = RSA_parse_private_key(&cbs); + if (ret == NULL) { + return NULL; + } + if (out != NULL) { + RSA_free(*out); + *out = ret; + } + *inp += (size_t)len - CBS_len(&cbs); + return ret; +} + +int i2d_RSAPrivateKey(const RSA *in, uint8_t **outp) { + uint8_t *der; + size_t der_len; + if (!RSA_private_key_to_bytes(&der, &der_len, in)) { + return -1; + } + if (der_len > INT_MAX) { + OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW); + OPENSSL_free(der); + return -1; + } + if (outp != NULL) { + if (*outp == NULL) { + *outp = der; + der = NULL; + } else { + memcpy(*outp, der, der_len); + *outp += der_len; + } + } + OPENSSL_free(der); + return (int)der_len; +} + +ASN1_SEQUENCE(RSA_PSS_PARAMS) = { + ASN1_EXP_OPT(RSA_PSS_PARAMS, hashAlgorithm, X509_ALGOR,0), + ASN1_EXP_OPT(RSA_PSS_PARAMS, maskGenAlgorithm, X509_ALGOR,1), + ASN1_EXP_OPT(RSA_PSS_PARAMS, saltLength, ASN1_INTEGER,2), + ASN1_EXP_OPT(RSA_PSS_PARAMS, trailerField, ASN1_INTEGER,3), +} ASN1_SEQUENCE_END(RSA_PSS_PARAMS); + +IMPLEMENT_ASN1_FUNCTIONS(RSA_PSS_PARAMS); + +RSA *RSAPublicKey_dup(const RSA *rsa) { + uint8_t *der; + size_t der_len; + if (!RSA_public_key_to_bytes(&der, &der_len, rsa)) { + return NULL; + } + RSA *ret = RSA_public_key_from_bytes(der, der_len); + OPENSSL_free(der); + return ret; +} + +RSA *RSAPrivateKey_dup(const RSA *rsa) { + uint8_t *der; + size_t der_len; + if (!RSA_private_key_to_bytes(&der, &der_len, rsa)) { + return NULL; + } + RSA *ret = RSA_private_key_from_bytes(der, der_len); + OPENSSL_free(der); + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/rsa/rsa_impl.c b/TMessagesProj/jni/boringssl/crypto/rsa/rsa_impl.c new file mode 100644 index 00000000..aa1b70f0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/rsa/rsa_impl.c @@ -0,0 +1,1155 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + +#include "internal.h" +#include "../internal.h" + + +#define OPENSSL_RSA_MAX_MODULUS_BITS 16384 +#define OPENSSL_RSA_SMALL_MODULUS_BITS 3072 +#define OPENSSL_RSA_MAX_PUBEXP_BITS \ + 64 /* exponent limit enforced for "large" modulus only */ + + +static int finish(RSA *rsa) { + BN_MONT_CTX_free(rsa->_method_mod_n); + BN_MONT_CTX_free(rsa->_method_mod_p); + BN_MONT_CTX_free(rsa->_method_mod_q); + + if (rsa->additional_primes != NULL) { + size_t i; + for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); i++) { + RSA_additional_prime *ap = + sk_RSA_additional_prime_value(rsa->additional_primes, i); + BN_MONT_CTX_free(ap->method_mod); + } + } + + return 1; +} + +static size_t size(const RSA *rsa) { + return BN_num_bytes(rsa->n); +} + +static int encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + const unsigned rsa_size = RSA_size(rsa); + BIGNUM *f, *result; + uint8_t *buf = NULL; + BN_CTX *ctx = NULL; + int i, ret = 0; + + if (rsa_size > OPENSSL_RSA_MAX_MODULUS_BITS) { + OPENSSL_PUT_ERROR(RSA, RSA_R_MODULUS_TOO_LARGE); + return 0; + } + + if (max_out < rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (BN_ucmp(rsa->n, rsa->e) <= 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE); + return 0; + } + + /* for large moduli, enforce exponent limit */ + if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS && + BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE); + return 0; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + + BN_CTX_start(ctx); + f = BN_CTX_get(ctx); + result = BN_CTX_get(ctx); + buf = OPENSSL_malloc(rsa_size); + if (!f || !result || !buf) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + switch (padding) { + case RSA_PKCS1_PADDING: + i = RSA_padding_add_PKCS1_type_2(buf, rsa_size, in, in_len); + break; + case RSA_PKCS1_OAEP_PADDING: + /* Use the default parameters: SHA-1 for both hashes and no label. */ + i = RSA_padding_add_PKCS1_OAEP_mgf1(buf, rsa_size, in, in_len, + NULL, 0, NULL, NULL); + break; + case RSA_NO_PADDING: + i = RSA_padding_add_none(buf, rsa_size, in, in_len); + break; + default: + OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE); + goto err; + } + + if (i <= 0) { + goto err; + } + + if (BN_bin2bn(buf, rsa_size, f) == NULL) { + goto err; + } + + if (BN_ucmp(f, rsa->n) >= 0) { + /* usually the padding functions would catch this */ + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS); + goto err; + } + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { + if (BN_MONT_CTX_set_locked(&rsa->_method_mod_n, &rsa->lock, rsa->n, ctx) == + NULL) { + goto err; + } + } + + if (!rsa->meth->bn_mod_exp(result, f, rsa->e, rsa->n, ctx, + rsa->_method_mod_n)) { + goto err; + } + + /* put in leading 0 bytes if the number is less than the length of the + * modulus */ + if (!BN_bn2bin_padded(out, rsa_size, result)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + *out_len = rsa_size; + ret = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + if (buf != NULL) { + OPENSSL_cleanse(buf, rsa_size); + OPENSSL_free(buf); + } + + return ret; +} + +/* MAX_BLINDINGS_PER_RSA defines the maximum number of cached BN_BLINDINGs per + * RSA*. Then this limit is exceeded, BN_BLINDING objects will be created and + * destroyed as needed. */ +#define MAX_BLINDINGS_PER_RSA 1024 + +/* rsa_blinding_get returns a BN_BLINDING to use with |rsa|. It does this by + * allocating one of the cached BN_BLINDING objects in |rsa->blindings|. If + * none are free, the cache will be extended by a extra element and the new + * BN_BLINDING is returned. + * + * On success, the index of the assigned BN_BLINDING is written to + * |*index_used| and must be passed to |rsa_blinding_release| when finished. */ +static BN_BLINDING *rsa_blinding_get(RSA *rsa, unsigned *index_used, + BN_CTX *ctx) { + BN_BLINDING *ret = NULL; + BN_BLINDING **new_blindings; + uint8_t *new_blindings_inuse; + char overflow = 0; + + CRYPTO_MUTEX_lock_write(&rsa->lock); + + unsigned i; + for (i = 0; i < rsa->num_blindings; i++) { + if (rsa->blindings_inuse[i] == 0) { + rsa->blindings_inuse[i] = 1; + ret = rsa->blindings[i]; + *index_used = i; + break; + } + } + + if (ret != NULL) { + CRYPTO_MUTEX_unlock(&rsa->lock); + return ret; + } + + overflow = rsa->num_blindings >= MAX_BLINDINGS_PER_RSA; + + /* We didn't find a free BN_BLINDING to use so increase the length of + * the arrays by one and use the newly created element. */ + + CRYPTO_MUTEX_unlock(&rsa->lock); + ret = rsa_setup_blinding(rsa, ctx); + if (ret == NULL) { + return NULL; + } + + if (overflow) { + /* We cannot add any more cached BN_BLINDINGs so we use |ret| + * and mark it for destruction in |rsa_blinding_release|. */ + *index_used = MAX_BLINDINGS_PER_RSA; + return ret; + } + + CRYPTO_MUTEX_lock_write(&rsa->lock); + + new_blindings = + OPENSSL_malloc(sizeof(BN_BLINDING *) * (rsa->num_blindings + 1)); + if (new_blindings == NULL) { + goto err1; + } + memcpy(new_blindings, rsa->blindings, + sizeof(BN_BLINDING *) * rsa->num_blindings); + new_blindings[rsa->num_blindings] = ret; + + new_blindings_inuse = OPENSSL_malloc(rsa->num_blindings + 1); + if (new_blindings_inuse == NULL) { + goto err2; + } + memcpy(new_blindings_inuse, rsa->blindings_inuse, rsa->num_blindings); + new_blindings_inuse[rsa->num_blindings] = 1; + *index_used = rsa->num_blindings; + + OPENSSL_free(rsa->blindings); + rsa->blindings = new_blindings; + OPENSSL_free(rsa->blindings_inuse); + rsa->blindings_inuse = new_blindings_inuse; + rsa->num_blindings++; + + CRYPTO_MUTEX_unlock(&rsa->lock); + return ret; + +err2: + OPENSSL_free(new_blindings); + +err1: + CRYPTO_MUTEX_unlock(&rsa->lock); + BN_BLINDING_free(ret); + return NULL; +} + +/* rsa_blinding_release marks the cached BN_BLINDING at the given index as free + * for other threads to use. */ +static void rsa_blinding_release(RSA *rsa, BN_BLINDING *blinding, + unsigned blinding_index) { + if (blinding_index == MAX_BLINDINGS_PER_RSA) { + /* This blinding wasn't cached. */ + BN_BLINDING_free(blinding); + return; + } + + CRYPTO_MUTEX_lock_write(&rsa->lock); + rsa->blindings_inuse[blinding_index] = 0; + CRYPTO_MUTEX_unlock(&rsa->lock); +} + +/* signing */ +static int sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + const unsigned rsa_size = RSA_size(rsa); + uint8_t *buf = NULL; + int i, ret = 0; + + if (max_out < rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + buf = OPENSSL_malloc(rsa_size); + if (buf == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + switch (padding) { + case RSA_PKCS1_PADDING: + i = RSA_padding_add_PKCS1_type_1(buf, rsa_size, in, in_len); + break; + case RSA_NO_PADDING: + i = RSA_padding_add_none(buf, rsa_size, in, in_len); + break; + default: + OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE); + goto err; + } + + if (i <= 0) { + goto err; + } + + if (!RSA_private_transform(rsa, out, buf, rsa_size)) { + goto err; + } + + *out_len = rsa_size; + ret = 1; + +err: + if (buf != NULL) { + OPENSSL_cleanse(buf, rsa_size); + OPENSSL_free(buf); + } + + return ret; +} + +static int decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + const unsigned rsa_size = RSA_size(rsa); + int r = -1; + uint8_t *buf = NULL; + int ret = 0; + + if (max_out < rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + if (padding == RSA_NO_PADDING) { + buf = out; + } else { + /* Allocate a temporary buffer to hold the padded plaintext. */ + buf = OPENSSL_malloc(rsa_size); + if (buf == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (in_len != rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN); + goto err; + } + + if (!RSA_private_transform(rsa, buf, in, rsa_size)) { + goto err; + } + + switch (padding) { + case RSA_PKCS1_PADDING: + r = RSA_padding_check_PKCS1_type_2(out, rsa_size, buf, rsa_size); + break; + case RSA_PKCS1_OAEP_PADDING: + /* Use the default parameters: SHA-1 for both hashes and no label. */ + r = RSA_padding_check_PKCS1_OAEP_mgf1(out, rsa_size, buf, rsa_size, + NULL, 0, NULL, NULL); + break; + case RSA_NO_PADDING: + r = rsa_size; + break; + default: + OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE); + goto err; + } + + if (r < 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_PADDING_CHECK_FAILED); + } else { + *out_len = r; + ret = 1; + } + +err: + if (padding != RSA_NO_PADDING && buf != NULL) { + OPENSSL_cleanse(buf, rsa_size); + OPENSSL_free(buf); + } + + return ret; +} + +static int verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding) { + const unsigned rsa_size = RSA_size(rsa); + BIGNUM *f, *result; + int ret = 0; + int r = -1; + uint8_t *buf = NULL; + BN_CTX *ctx = NULL; + + if (BN_num_bits(rsa->n) > OPENSSL_RSA_MAX_MODULUS_BITS) { + OPENSSL_PUT_ERROR(RSA, RSA_R_MODULUS_TOO_LARGE); + return 0; + } + + if (BN_ucmp(rsa->n, rsa->e) <= 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE); + return 0; + } + + if (max_out < rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL); + return 0; + } + + /* for large moduli, enforce exponent limit */ + if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS && + BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS) { + OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE); + return 0; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + + BN_CTX_start(ctx); + f = BN_CTX_get(ctx); + result = BN_CTX_get(ctx); + if (padding == RSA_NO_PADDING) { + buf = out; + } else { + /* Allocate a temporary buffer to hold the padded plaintext. */ + buf = OPENSSL_malloc(rsa_size); + if (buf == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + } + if (!f || !result) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (in_len != rsa_size) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN); + goto err; + } + + if (BN_bin2bn(in, in_len, f) == NULL) { + goto err; + } + + if (BN_ucmp(f, rsa->n) >= 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS); + goto err; + } + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { + if (BN_MONT_CTX_set_locked(&rsa->_method_mod_n, &rsa->lock, rsa->n, ctx) == + NULL) { + goto err; + } + } + + if (!rsa->meth->bn_mod_exp(result, f, rsa->e, rsa->n, ctx, + rsa->_method_mod_n)) { + goto err; + } + + if (!BN_bn2bin_padded(buf, rsa_size, result)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + switch (padding) { + case RSA_PKCS1_PADDING: + r = RSA_padding_check_PKCS1_type_1(out, rsa_size, buf, rsa_size); + break; + case RSA_NO_PADDING: + r = rsa_size; + break; + default: + OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE); + goto err; + } + + if (r < 0) { + OPENSSL_PUT_ERROR(RSA, RSA_R_PADDING_CHECK_FAILED); + } else { + *out_len = r; + ret = 1; + } + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + if (padding != RSA_NO_PADDING && buf != NULL) { + OPENSSL_cleanse(buf, rsa_size); + OPENSSL_free(buf); + } + return ret; +} + +static int private_transform(RSA *rsa, uint8_t *out, const uint8_t *in, + size_t len) { + BIGNUM *f, *result; + BN_CTX *ctx = NULL; + unsigned blinding_index = 0; + BN_BLINDING *blinding = NULL; + int ret = 0; + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + f = BN_CTX_get(ctx); + result = BN_CTX_get(ctx); + + if (f == NULL || result == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (BN_bin2bn(in, len, f) == NULL) { + goto err; + } + + if (BN_ucmp(f, rsa->n) >= 0) { + /* Usually the padding functions would catch this. */ + OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS); + goto err; + } + + if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) { + blinding = rsa_blinding_get(rsa, &blinding_index, ctx); + if (blinding == NULL) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + if (!BN_BLINDING_convert_ex(f, NULL, blinding, ctx)) { + goto err; + } + } + + if ((rsa->flags & RSA_FLAG_EXT_PKEY) || + ((rsa->p != NULL) && (rsa->q != NULL) && (rsa->dmp1 != NULL) && + (rsa->dmq1 != NULL) && (rsa->iqmp != NULL))) { + if (!rsa->meth->mod_exp(result, f, rsa, ctx)) { + goto err; + } + } else { + BIGNUM local_d; + BIGNUM *d = NULL; + + BN_init(&local_d); + d = &local_d; + BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { + if (BN_MONT_CTX_set_locked(&rsa->_method_mod_n, &rsa->lock, rsa->n, + ctx) == NULL) { + goto err; + } + } + + if (!rsa->meth->bn_mod_exp(result, f, d, rsa->n, ctx, rsa->_method_mod_n)) { + goto err; + } + } + + if (blinding) { + if (!BN_BLINDING_invert_ex(result, NULL, blinding, ctx)) { + goto err; + } + } + + if (!BN_bn2bin_padded(out, len, result)) { + OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR); + goto err; + } + + ret = 1; + +err: + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + if (blinding != NULL) { + rsa_blinding_release(rsa, blinding, blinding_index); + } + + return ret; +} + +static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) { + BIGNUM *r1, *m1, *vrfy; + BIGNUM local_dmp1, local_dmq1, local_c, local_r1; + BIGNUM *dmp1, *dmq1, *c, *pr1; + int ret = 0; + size_t i, num_additional_primes = 0; + + if (rsa->additional_primes != NULL) { + num_additional_primes = sk_RSA_additional_prime_num(rsa->additional_primes); + } + + BN_CTX_start(ctx); + r1 = BN_CTX_get(ctx); + m1 = BN_CTX_get(ctx); + vrfy = BN_CTX_get(ctx); + + { + BIGNUM local_p, local_q; + BIGNUM *p = NULL, *q = NULL; + + /* Make sure BN_mod_inverse in Montgomery intialization uses the + * BN_FLG_CONSTTIME flag (unless RSA_FLAG_NO_CONSTTIME is set) */ + BN_init(&local_p); + p = &local_p; + BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME); + + BN_init(&local_q); + q = &local_q; + BN_with_flags(q, rsa->q, BN_FLG_CONSTTIME); + + if (rsa->flags & RSA_FLAG_CACHE_PRIVATE) { + if (BN_MONT_CTX_set_locked(&rsa->_method_mod_p, &rsa->lock, p, ctx) == + NULL) { + goto err; + } + if (BN_MONT_CTX_set_locked(&rsa->_method_mod_q, &rsa->lock, q, ctx) == + NULL) { + goto err; + } + } + } + + if (rsa->flags & RSA_FLAG_CACHE_PUBLIC) { + if (BN_MONT_CTX_set_locked(&rsa->_method_mod_n, &rsa->lock, rsa->n, ctx) == + NULL) { + goto err; + } + } + + /* compute I mod q */ + c = &local_c; + BN_with_flags(c, I, BN_FLG_CONSTTIME); + if (!BN_mod(r1, c, rsa->q, ctx)) { + goto err; + } + + /* compute r1^dmq1 mod q */ + dmq1 = &local_dmq1; + BN_with_flags(dmq1, rsa->dmq1, BN_FLG_CONSTTIME); + if (!rsa->meth->bn_mod_exp(m1, r1, dmq1, rsa->q, ctx, rsa->_method_mod_q)) { + goto err; + } + + /* compute I mod p */ + c = &local_c; + BN_with_flags(c, I, BN_FLG_CONSTTIME); + if (!BN_mod(r1, c, rsa->p, ctx)) { + goto err; + } + + /* compute r1^dmp1 mod p */ + dmp1 = &local_dmp1; + BN_with_flags(dmp1, rsa->dmp1, BN_FLG_CONSTTIME); + if (!rsa->meth->bn_mod_exp(r0, r1, dmp1, rsa->p, ctx, rsa->_method_mod_p)) { + goto err; + } + + if (!BN_sub(r0, r0, m1)) { + goto err; + } + /* This will help stop the size of r0 increasing, which does + * affect the multiply if it optimised for a power of 2 size */ + if (BN_is_negative(r0)) { + if (!BN_add(r0, r0, rsa->p)) { + goto err; + } + } + + if (!BN_mul(r1, r0, rsa->iqmp, ctx)) { + goto err; + } + + /* Turn BN_FLG_CONSTTIME flag on before division operation */ + pr1 = &local_r1; + BN_with_flags(pr1, r1, BN_FLG_CONSTTIME); + + if (!BN_mod(r0, pr1, rsa->p, ctx)) { + goto err; + } + + /* If p < q it is occasionally possible for the correction of + * adding 'p' if r0 is negative above to leave the result still + * negative. This can break the private key operations: the following + * second correction should *always* correct this rare occurrence. + * This will *never* happen with OpenSSL generated keys because + * they ensure p > q [steve] */ + if (BN_is_negative(r0)) { + if (!BN_add(r0, r0, rsa->p)) { + goto err; + } + } + if (!BN_mul(r1, r0, rsa->q, ctx)) { + goto err; + } + if (!BN_add(r0, r1, m1)) { + goto err; + } + + for (i = 0; i < num_additional_primes; i++) { + /* multi-prime RSA. */ + BIGNUM local_exp, local_prime; + BIGNUM *exp = &local_exp, *prime = &local_prime; + RSA_additional_prime *ap = + sk_RSA_additional_prime_value(rsa->additional_primes, i); + + BN_with_flags(exp, ap->exp, BN_FLG_CONSTTIME); + BN_with_flags(prime, ap->prime, BN_FLG_CONSTTIME); + + /* c will already point to a BIGNUM with the correct flags. */ + if (!BN_mod(r1, c, prime, ctx)) { + goto err; + } + + if ((rsa->flags & RSA_FLAG_CACHE_PRIVATE) && + !BN_MONT_CTX_set_locked(&ap->method_mod, &rsa->lock, prime, ctx)) { + goto err; + } + + if (!rsa->meth->bn_mod_exp(m1, r1, exp, prime, ctx, ap->method_mod)) { + goto err; + } + + BN_set_flags(m1, BN_FLG_CONSTTIME); + + if (!BN_sub(m1, m1, r0) || + !BN_mul(m1, m1, ap->coeff, ctx) || + !BN_mod(m1, m1, prime, ctx) || + (BN_is_negative(m1) && !BN_add(m1, m1, prime)) || + !BN_mul(m1, m1, ap->r, ctx) || + !BN_add(r0, r0, m1)) { + goto err; + } + } + + if (rsa->e && rsa->n) { + if (!rsa->meth->bn_mod_exp(vrfy, r0, rsa->e, rsa->n, ctx, + rsa->_method_mod_n)) { + goto err; + } + /* If 'I' was greater than (or equal to) rsa->n, the operation + * will be equivalent to using 'I mod n'. However, the result of + * the verify will *always* be less than 'n' so we don't check + * for absolute equality, just congruency. */ + if (!BN_sub(vrfy, vrfy, I)) { + goto err; + } + if (!BN_mod(vrfy, vrfy, rsa->n, ctx)) { + goto err; + } + if (BN_is_negative(vrfy)) { + if (!BN_add(vrfy, vrfy, rsa->n)) { + goto err; + } + } + if (!BN_is_zero(vrfy)) { + /* 'I' and 'vrfy' aren't congruent mod n. Don't leak + * miscalculated CRT output, just do a raw (slower) + * mod_exp and return that instead. */ + + BIGNUM local_d; + BIGNUM *d = NULL; + + d = &local_d; + BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); + if (!rsa->meth->bn_mod_exp(r0, I, d, rsa->n, ctx, rsa->_method_mod_n)) { + goto err; + } + } + } + ret = 1; + +err: + BN_CTX_end(ctx); + return ret; +} + +static int keygen_multiprime(RSA *rsa, int bits, int num_primes, + BIGNUM *e_value, BN_GENCB *cb) { + BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *r3 = NULL, *tmp; + BIGNUM local_r0, local_d, local_p; + BIGNUM *pr0, *d, *p; + int prime_bits, ok = -1, n = 0, i, j; + BN_CTX *ctx = NULL; + STACK_OF(RSA_additional_prime) *additional_primes = NULL; + + if (num_primes < 2) { + ok = 0; /* we set our own err */ + OPENSSL_PUT_ERROR(RSA, RSA_R_MUST_HAVE_AT_LEAST_TWO_PRIMES); + goto err; + } + + ctx = BN_CTX_new(); + if (ctx == NULL) { + goto err; + } + BN_CTX_start(ctx); + r0 = BN_CTX_get(ctx); + r1 = BN_CTX_get(ctx); + r2 = BN_CTX_get(ctx); + r3 = BN_CTX_get(ctx); + if (r0 == NULL || r1 == NULL || r2 == NULL || r3 == NULL) { + goto err; + } + + if (num_primes > 2) { + additional_primes = sk_RSA_additional_prime_new_null(); + if (additional_primes == NULL) { + goto err; + } + } + + for (i = 2; i < num_primes; i++) { + RSA_additional_prime *ap = OPENSSL_malloc(sizeof(RSA_additional_prime)); + if (ap == NULL) { + goto err; + } + memset(ap, 0, sizeof(RSA_additional_prime)); + ap->prime = BN_new(); + ap->exp = BN_new(); + ap->coeff = BN_new(); + ap->r = BN_new(); + if (ap->prime == NULL || + ap->exp == NULL || + ap->coeff == NULL || + ap->r == NULL || + !sk_RSA_additional_prime_push(additional_primes, ap)) { + RSA_additional_prime_free(ap); + goto err; + } + } + + /* We need the RSA components non-NULL */ + if (!rsa->n && ((rsa->n = BN_new()) == NULL)) { + goto err; + } + if (!rsa->d && ((rsa->d = BN_new()) == NULL)) { + goto err; + } + if (!rsa->e && ((rsa->e = BN_new()) == NULL)) { + goto err; + } + if (!rsa->p && ((rsa->p = BN_new()) == NULL)) { + goto err; + } + if (!rsa->q && ((rsa->q = BN_new()) == NULL)) { + goto err; + } + if (!rsa->dmp1 && ((rsa->dmp1 = BN_new()) == NULL)) { + goto err; + } + if (!rsa->dmq1 && ((rsa->dmq1 = BN_new()) == NULL)) { + goto err; + } + if (!rsa->iqmp && ((rsa->iqmp = BN_new()) == NULL)) { + goto err; + } + + if (!BN_copy(rsa->e, e_value)) { + goto err; + } + + /* generate p and q */ + prime_bits = (bits + (num_primes - 1)) / num_primes; + for (;;) { + if (!BN_generate_prime_ex(rsa->p, prime_bits, 0, NULL, NULL, cb) || + !BN_sub(r2, rsa->p, BN_value_one()) || + !BN_gcd(r1, r2, rsa->e, ctx)) { + goto err; + } + if (BN_is_one(r1)) { + break; + } + if (!BN_GENCB_call(cb, 2, n++)) { + goto err; + } + } + if (!BN_GENCB_call(cb, 3, 0)) { + goto err; + } + prime_bits = ((bits - prime_bits) + (num_primes - 2)) / (num_primes - 1); + for (;;) { + /* When generating ridiculously small keys, we can get stuck + * continually regenerating the same prime values. Check for + * this and bail if it happens 3 times. */ + unsigned int degenerate = 0; + do { + if (!BN_generate_prime_ex(rsa->q, prime_bits, 0, NULL, NULL, cb)) { + goto err; + } + } while ((BN_cmp(rsa->p, rsa->q) == 0) && (++degenerate < 3)); + if (degenerate == 3) { + ok = 0; /* we set our own err */ + OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL); + goto err; + } + if (!BN_sub(r2, rsa->q, BN_value_one()) || + !BN_gcd(r1, r2, rsa->e, ctx)) { + goto err; + } + if (BN_is_one(r1)) { + break; + } + if (!BN_GENCB_call(cb, 2, n++)) { + goto err; + } + } + + if (!BN_GENCB_call(cb, 3, 1) || + !BN_mul(rsa->n, rsa->p, rsa->q, ctx)) { + goto err; + } + + for (i = 2; i < num_primes; i++) { + RSA_additional_prime *ap = + sk_RSA_additional_prime_value(additional_primes, i - 2); + prime_bits = ((bits - BN_num_bits(rsa->n)) + (num_primes - (i + 1))) / + (num_primes - i); + + for (;;) { + if (!BN_generate_prime_ex(ap->prime, prime_bits, 0, NULL, NULL, cb)) { + goto err; + } + if (BN_cmp(rsa->p, ap->prime) == 0 || + BN_cmp(rsa->q, ap->prime) == 0) { + continue; + } + + for (j = 0; j < i - 2; j++) { + if (BN_cmp(sk_RSA_additional_prime_value(additional_primes, j)->prime, + ap->prime) == 0) { + break; + } + } + if (j != i - 2) { + continue; + } + + if (!BN_sub(r2, ap->prime, BN_value_one()) || + !BN_gcd(r1, r2, rsa->e, ctx)) { + goto err; + } + + if (!BN_is_one(r1)) { + continue; + } + if (i != num_primes - 1) { + break; + } + + /* For the last prime we'll check that it makes n large enough. In the + * two prime case this isn't a problem because we generate primes with + * the top two bits set and so the product is always of the expected + * size. In the multi prime case, this doesn't follow. */ + if (!BN_mul(r1, rsa->n, ap->prime, ctx)) { + goto err; + } + if (BN_num_bits(r1) == bits) { + break; + } + + if (!BN_GENCB_call(cb, 2, n++)) { + goto err; + } + } + + /* ap->r is is the product of all the primes prior to the current one + * (including p and q). */ + if (!BN_copy(ap->r, rsa->n)) { + goto err; + } + if (i == num_primes - 1) { + /* In the case of the last prime, we calculated n as |r1| in the loop + * above. */ + if (!BN_copy(rsa->n, r1)) { + goto err; + } + } else if (!BN_mul(rsa->n, rsa->n, ap->prime, ctx)) { + goto err; + } + + if (!BN_GENCB_call(cb, 3, 1)) { + goto err; + } + } + + if (BN_cmp(rsa->p, rsa->q) < 0) { + tmp = rsa->p; + rsa->p = rsa->q; + rsa->q = tmp; + } + + /* calculate d */ + if (!BN_sub(r1, rsa->p, BN_value_one())) { + goto err; /* p-1 */ + } + if (!BN_sub(r2, rsa->q, BN_value_one())) { + goto err; /* q-1 */ + } + if (!BN_mul(r0, r1, r2, ctx)) { + goto err; /* (p-1)(q-1) */ + } + for (i = 2; i < num_primes; i++) { + RSA_additional_prime *ap = + sk_RSA_additional_prime_value(additional_primes, i - 2); + if (!BN_sub(r3, ap->prime, BN_value_one()) || + !BN_mul(r0, r0, r3, ctx)) { + goto err; + } + } + pr0 = &local_r0; + BN_with_flags(pr0, r0, BN_FLG_CONSTTIME); + if (!BN_mod_inverse(rsa->d, rsa->e, pr0, ctx)) { + goto err; /* d */ + } + + /* set up d for correct BN_FLG_CONSTTIME flag */ + d = &local_d; + BN_with_flags(d, rsa->d, BN_FLG_CONSTTIME); + + /* calculate d mod (p-1) */ + if (!BN_mod(rsa->dmp1, d, r1, ctx)) { + goto err; + } + + /* calculate d mod (q-1) */ + if (!BN_mod(rsa->dmq1, d, r2, ctx)) { + goto err; + } + + /* calculate inverse of q mod p */ + p = &local_p; + BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME); + + if (!BN_mod_inverse(rsa->iqmp, rsa->q, p, ctx)) { + goto err; + } + + for (i = 2; i < num_primes; i++) { + RSA_additional_prime *ap = + sk_RSA_additional_prime_value(additional_primes, i - 2); + if (!BN_sub(ap->exp, ap->prime, BN_value_one()) || + !BN_mod(ap->exp, rsa->d, ap->exp, ctx) || + !BN_mod_inverse(ap->coeff, ap->r, ap->prime, ctx)) { + goto err; + } + } + + ok = 1; + rsa->additional_primes = additional_primes; + additional_primes = NULL; + +err: + if (ok == -1) { + OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN); + ok = 0; + } + if (ctx != NULL) { + BN_CTX_end(ctx); + BN_CTX_free(ctx); + } + sk_RSA_additional_prime_pop_free(additional_primes, + RSA_additional_prime_free); + return ok; +} + +static int keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) { + return keygen_multiprime(rsa, bits, 2 /* num primes */, e_value, cb); +} + +const struct rsa_meth_st RSA_default_method = { + { + 0 /* references */, + 1 /* is_static */, + }, + NULL /* app_data */, + + NULL /* init */, + finish, + + size, + + NULL /* sign */, + NULL /* verify */, + + encrypt, + sign_raw, + decrypt, + verify_raw, + + private_transform, + + mod_exp /* mod_exp */, + BN_mod_exp_mont /* bn_mod_exp */, + + RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE, + + keygen, + keygen_multiprime, +}; diff --git a/TMessagesProj/jni/boringssl/crypto/sha/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/sha/CMakeLists.txt new file mode 100644 index 00000000..5a10c851 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/CMakeLists.txt @@ -0,0 +1,66 @@ +include_directories(. .. ../../include) + +if (${ARCH} STREQUAL "x86_64") + set( + SHA_ARCH_SOURCES + + sha1-x86_64.${ASM_EXT} + sha256-x86_64.${ASM_EXT} + sha512-x86_64.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "x86") + set( + SHA_ARCH_SOURCES + + sha1-586.${ASM_EXT} + sha256-586.${ASM_EXT} + sha512-586.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "arm") + set( + SHA_ARCH_SOURCES + + sha1-armv4-large.${ASM_EXT} + sha256-armv4.${ASM_EXT} + sha512-armv4.${ASM_EXT} + ) +endif() + +if (${ARCH} STREQUAL "aarch64") + set( + SHA_ARCH_SOURCES + + sha1-armv8.${ASM_EXT} + sha256-armv8.${ASM_EXT} + sha512-armv8.${ASM_EXT} + ) +endif() + +add_library( + sha + + OBJECT + + sha1.c + sha256.c + sha512.c + + ${SHA_ARCH_SOURCES} +) + +perlasm(sha1-x86_64.${ASM_EXT} asm/sha1-x86_64.pl) +perlasm(sha256-x86_64.${ASM_EXT} asm/sha512-x86_64.pl sha256) +perlasm(sha512-x86_64.${ASM_EXT} asm/sha512-x86_64.pl sha512) +perlasm(sha1-586.${ASM_EXT} asm/sha1-586.pl) +perlasm(sha256-586.${ASM_EXT} asm/sha256-586.pl) +perlasm(sha512-586.${ASM_EXT} asm/sha512-586.pl) +perlasm(sha1-armv4-large.${ASM_EXT} asm/sha1-armv4-large.pl) +perlasm(sha256-armv4.${ASM_EXT} asm/sha256-armv4.pl) +perlasm(sha512-armv4.${ASM_EXT} asm/sha512-armv4.pl) +perlasm(sha1-armv8.${ASM_EXT} asm/sha1-armv8.pl) +perlasm(sha256-armv8.${ASM_EXT} asm/sha512-armv8.pl sha256) +perlasm(sha512-armv8.${ASM_EXT} asm/sha512-armv8.pl sha512) diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-586.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-586.pl new file mode 100644 index 00000000..e0b5d83b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-586.pl @@ -0,0 +1,1476 @@ +#!/usr/bin/env perl + +# ==================================================================== +# [Re]written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# "[Re]written" was achieved in two major overhauls. In 2004 BODY_* +# functions were re-implemented to address P4 performance issue [see +# commentary below], and in 2006 the rest was rewritten in order to +# gain freedom to liberate licensing terms. + +# January, September 2004. +# +# It was noted that Intel IA-32 C compiler generates code which +# performs ~30% *faster* on P4 CPU than original *hand-coded* +# SHA1 assembler implementation. To address this problem (and +# prove that humans are still better than machines:-), the +# original code was overhauled, which resulted in following +# performance changes: +# +# compared with original compared with Intel cc +# assembler impl. generated code +# Pentium -16% +48% +# PIII/AMD +8% +16% +# P4 +85%(!) +45% +# +# As you can see Pentium came out as looser:-( Yet I reckoned that +# improvement on P4 outweights the loss and incorporate this +# re-tuned code to 0.9.7 and later. +# ---------------------------------------------------------------- +# + +# August 2009. +# +# George Spelvin has tipped that F_40_59(b,c,d) can be rewritten as +# '(c&d) + (b&(c^d))', which allows to accumulate partial results +# and lighten "pressure" on scratch registers. This resulted in +# >12% performance improvement on contemporary AMD cores (with no +# degradation on other CPUs:-). Also, the code was revised to maximize +# "distance" between instructions producing input to 'lea' instruction +# and the 'lea' instruction itself, which is essential for Intel Atom +# core and resulted in ~15% improvement. + +# October 2010. +# +# Add SSSE3, Supplemental[!] SSE3, implementation. The idea behind it +# is to offload message schedule denoted by Wt in NIST specification, +# or Xupdate in OpenSSL source, to SIMD unit. The idea is not novel, +# and in SSE2 context was first explored by Dean Gaudet in 2004, see +# http://arctic.org/~dean/crypto/sha1.html. Since then several things +# have changed that made it interesting again: +# +# a) XMM units became faster and wider; +# b) instruction set became more versatile; +# c) an important observation was made by Max Locktykhin, which made +# it possible to reduce amount of instructions required to perform +# the operation in question, for further details see +# http://software.intel.com/en-us/articles/improving-the-performance-of-the-secure-hash-algorithm-1/. + +# April 2011. +# +# Add AVX code path, probably most controversial... The thing is that +# switch to AVX alone improves performance by as little as 4% in +# comparison to SSSE3 code path. But below result doesn't look like +# 4% improvement... Trouble is that Sandy Bridge decodes 'ro[rl]' as +# pair of µ-ops, and it's the additional µ-ops, two per round, that +# make it run slower than Core2 and Westmere. But 'sh[rl]d' is decoded +# as single µ-op by Sandy Bridge and it's replacing 'ro[rl]' with +# equivalent 'sh[rl]d' that is responsible for the impressive 5.1 +# cycles per processed byte. But 'sh[rl]d' is not something that used +# to be fast, nor does it appear to be fast in upcoming Bulldozer +# [according to its optimization manual]. Which is why AVX code path +# is guarded by *both* AVX and synthetic bit denoting Intel CPUs. +# One can argue that it's unfair to AMD, but without 'sh[rl]d' it +# makes no sense to keep the AVX code path. If somebody feels that +# strongly, it's probably more appropriate to discuss possibility of +# using vector rotate XOP on AMD... + +# March 2014. +# +# Add support for Intel SHA Extensions. + +###################################################################### +# Current performance is summarized in following table. Numbers are +# CPU clock cycles spent to process single byte (less is better). +# +# x86 SSSE3 AVX +# Pentium 15.7 - +# PIII 11.5 - +# P4 10.6 - +# AMD K8 7.1 - +# Core2 7.3 6.0/+22% - +# Westmere 7.3 5.5/+33% - +# Sandy Bridge 8.8 6.2/+40% 5.1(**)/+73% +# Ivy Bridge 7.2 4.8/+51% 4.7(**)/+53% +# Haswell 6.5 4.3/+51% 4.1(**)/+58% +# Bulldozer 11.6 6.0/+92% +# VIA Nano 10.6 7.5/+41% +# Atom 12.5 9.3(*)/+35% +# Silvermont 14.5 9.9(*)/+46% +# +# (*) Loop is 1056 instructions long and expected result is ~8.25. +# The discrepancy is because of front-end limitations, so +# called MS-ROM penalties, and on Silvermont even rotate's +# limited parallelism. +# +# (**) As per above comment, the result is for AVX *plus* sh[rl]d. + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],"sha1-586.pl",$ARGV[$#ARGV] eq "386"); + +$xmm=$ymm=0; +for (@ARGV) { $xmm=1 if (/-DOPENSSL_IA32_SSE2/); } + +$ymm=1 if ($xmm && + `$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/ && + $1>=2.19); # first version supporting AVX + +$ymm=1 if ($xmm && !$ymm && $ARGV[0] eq "win32n" && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/ && + $1>=2.03); # first version supporting AVX + +$ymm=1 if ($xmm && !$ymm && $ARGV[0] eq "win32" && + `ml 2>&1` =~ /Version ([0-9]+)\./ && + $1>=10); # first version supporting AVX + +$ymm=1 if ($xmm && !$ymm && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/ && + $2>=3.0); # first version supporting AVX + +$shaext=$xmm; ### set to zero if compiling for 1.0.1 + +&external_label("OPENSSL_ia32cap_P") if ($xmm); + + +$A="eax"; +$B="ebx"; +$C="ecx"; +$D="edx"; +$E="edi"; +$T="esi"; +$tmp1="ebp"; + +@V=($A,$B,$C,$D,$E,$T); + +$alt=0; # 1 denotes alternative IALU implementation, which performs + # 8% *worse* on P4, same on Westmere and Atom, 2% better on + # Sandy Bridge... + +sub BODY_00_15 + { + local($n,$a,$b,$c,$d,$e,$f)=@_; + + &comment("00_15 $n"); + + &mov($f,$c); # f to hold F_00_19(b,c,d) + if ($n==0) { &mov($tmp1,$a); } + else { &mov($a,$tmp1); } + &rotl($tmp1,5); # tmp1=ROTATE(a,5) + &xor($f,$d); + &add($tmp1,$e); # tmp1+=e; + &mov($e,&swtmp($n%16)); # e becomes volatile and is loaded + # with xi, also note that e becomes + # f in next round... + &and($f,$b); + &rotr($b,2); # b=ROTATE(b,30) + &xor($f,$d); # f holds F_00_19(b,c,d) + &lea($tmp1,&DWP(0x5a827999,$tmp1,$e)); # tmp1+=K_00_19+xi + + if ($n==15) { &mov($e,&swtmp(($n+1)%16));# pre-fetch f for next round + &add($f,$tmp1); } # f+=tmp1 + else { &add($tmp1,$f); } # f becomes a in next round + &mov($tmp1,$a) if ($alt && $n==15); + } + +sub BODY_16_19 + { + local($n,$a,$b,$c,$d,$e,$f)=@_; + + &comment("16_19 $n"); + +if ($alt) { + &xor($c,$d); + &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd) + &and($tmp1,$c); # tmp1 to hold F_00_19(b,c,d), b&=c^d + &xor($f,&swtmp(($n+8)%16)); + &xor($tmp1,$d); # tmp1=F_00_19(b,c,d) + &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd + &rotl($f,1); # f=ROTATE(f,1) + &add($e,$tmp1); # e+=F_00_19(b,c,d) + &xor($c,$d); # restore $c + &mov($tmp1,$a); # b in next round + &rotr($b,$n==16?2:7); # b=ROTATE(b,30) + &mov(&swtmp($n%16),$f); # xi=f + &rotl($a,5); # ROTATE(a,5) + &lea($f,&DWP(0x5a827999,$f,$e));# f+=F_00_19(b,c,d)+e + &mov($e,&swtmp(($n+1)%16)); # pre-fetch f for next round + &add($f,$a); # f+=ROTATE(a,5) +} else { + &mov($tmp1,$c); # tmp1 to hold F_00_19(b,c,d) + &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd) + &xor($tmp1,$d); + &xor($f,&swtmp(($n+8)%16)); + &and($tmp1,$b); + &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd + &rotl($f,1); # f=ROTATE(f,1) + &xor($tmp1,$d); # tmp1=F_00_19(b,c,d) + &add($e,$tmp1); # e+=F_00_19(b,c,d) + &mov($tmp1,$a); + &rotr($b,2); # b=ROTATE(b,30) + &mov(&swtmp($n%16),$f); # xi=f + &rotl($tmp1,5); # ROTATE(a,5) + &lea($f,&DWP(0x5a827999,$f,$e));# f+=F_00_19(b,c,d)+e + &mov($e,&swtmp(($n+1)%16)); # pre-fetch f for next round + &add($f,$tmp1); # f+=ROTATE(a,5) +} + } + +sub BODY_20_39 + { + local($n,$a,$b,$c,$d,$e,$f)=@_; + local $K=($n<40)?0x6ed9eba1:0xca62c1d6; + + &comment("20_39 $n"); + +if ($alt) { + &xor($tmp1,$c); # tmp1 to hold F_20_39(b,c,d), b^=c + &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd) + &xor($tmp1,$d); # tmp1 holds F_20_39(b,c,d) + &xor($f,&swtmp(($n+8)%16)); + &add($e,$tmp1); # e+=F_20_39(b,c,d) + &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd + &rotl($f,1); # f=ROTATE(f,1) + &mov($tmp1,$a); # b in next round + &rotr($b,7); # b=ROTATE(b,30) + &mov(&swtmp($n%16),$f) if($n<77);# xi=f + &rotl($a,5); # ROTATE(a,5) + &xor($b,$c) if($n==39);# warm up for BODY_40_59 + &and($tmp1,$b) if($n==39); + &lea($f,&DWP($K,$f,$e)); # f+=e+K_XX_YY + &mov($e,&swtmp(($n+1)%16)) if($n<79);# pre-fetch f for next round + &add($f,$a); # f+=ROTATE(a,5) + &rotr($a,5) if ($n==79); +} else { + &mov($tmp1,$b); # tmp1 to hold F_20_39(b,c,d) + &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd) + &xor($tmp1,$c); + &xor($f,&swtmp(($n+8)%16)); + &xor($tmp1,$d); # tmp1 holds F_20_39(b,c,d) + &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd + &rotl($f,1); # f=ROTATE(f,1) + &add($e,$tmp1); # e+=F_20_39(b,c,d) + &rotr($b,2); # b=ROTATE(b,30) + &mov($tmp1,$a); + &rotl($tmp1,5); # ROTATE(a,5) + &mov(&swtmp($n%16),$f) if($n<77);# xi=f + &lea($f,&DWP($K,$f,$e)); # f+=e+K_XX_YY + &mov($e,&swtmp(($n+1)%16)) if($n<79);# pre-fetch f for next round + &add($f,$tmp1); # f+=ROTATE(a,5) +} + } + +sub BODY_40_59 + { + local($n,$a,$b,$c,$d,$e,$f)=@_; + + &comment("40_59 $n"); + +if ($alt) { + &add($e,$tmp1); # e+=b&(c^d) + &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd) + &mov($tmp1,$d); + &xor($f,&swtmp(($n+8)%16)); + &xor($c,$d); # restore $c + &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd + &rotl($f,1); # f=ROTATE(f,1) + &and($tmp1,$c); + &rotr($b,7); # b=ROTATE(b,30) + &add($e,$tmp1); # e+=c&d + &mov($tmp1,$a); # b in next round + &mov(&swtmp($n%16),$f); # xi=f + &rotl($a,5); # ROTATE(a,5) + &xor($b,$c) if ($n<59); + &and($tmp1,$b) if ($n<59);# tmp1 to hold F_40_59(b,c,d) + &lea($f,&DWP(0x8f1bbcdc,$f,$e));# f+=K_40_59+e+(b&(c^d)) + &mov($e,&swtmp(($n+1)%16)); # pre-fetch f for next round + &add($f,$a); # f+=ROTATE(a,5) +} else { + &mov($tmp1,$c); # tmp1 to hold F_40_59(b,c,d) + &xor($f,&swtmp(($n+2)%16)); # f to hold Xupdate(xi,xa,xb,xc,xd) + &xor($tmp1,$d); + &xor($f,&swtmp(($n+8)%16)); + &and($tmp1,$b); + &xor($f,&swtmp(($n+13)%16)); # f holds xa^xb^xc^xd + &rotl($f,1); # f=ROTATE(f,1) + &add($tmp1,$e); # b&(c^d)+=e + &rotr($b,2); # b=ROTATE(b,30) + &mov($e,$a); # e becomes volatile + &rotl($e,5); # ROTATE(a,5) + &mov(&swtmp($n%16),$f); # xi=f + &lea($f,&DWP(0x8f1bbcdc,$f,$tmp1));# f+=K_40_59+e+(b&(c^d)) + &mov($tmp1,$c); + &add($f,$e); # f+=ROTATE(a,5) + &and($tmp1,$d); + &mov($e,&swtmp(($n+1)%16)); # pre-fetch f for next round + &add($f,$tmp1); # f+=c&d +} + } + +&function_begin("sha1_block_data_order"); +if ($xmm) { + &static_label("shaext_shortcut") if ($shaext); + &static_label("ssse3_shortcut"); + &static_label("avx_shortcut") if ($ymm); + &static_label("K_XX_XX"); + + &call (&label("pic_point")); # make it PIC! + &set_label("pic_point"); + &blindpop($tmp1); + &picmeup($T,"OPENSSL_ia32cap_P",$tmp1,&label("pic_point")); + &lea ($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1)); + + &mov ($A,&DWP(0,$T)); + &mov ($D,&DWP(4,$T)); + &test ($D,1<<9); # check SSSE3 bit + &jz (&label("x86")); + &mov ($C,&DWP(8,$T)); + &test ($A,1<<24); # check FXSR bit + &jz (&label("x86")); + if ($shaext) { + &test ($C,1<<29); # check SHA bit + &jnz (&label("shaext_shortcut")); + } + if ($ymm) { + &and ($D,1<<28); # mask AVX bit + &and ($A,1<<30); # mask "Intel CPU" bit + &or ($A,$D); + &cmp ($A,1<<28|1<<30); + &je (&label("avx_shortcut")); + } + &jmp (&label("ssse3_shortcut")); + &set_label("x86",16); +} + &mov($tmp1,&wparam(0)); # SHA_CTX *c + &mov($T,&wparam(1)); # const void *input + &mov($A,&wparam(2)); # size_t num + &stack_push(16+3); # allocate X[16] + &shl($A,6); + &add($A,$T); + &mov(&wparam(2),$A); # pointer beyond the end of input + &mov($E,&DWP(16,$tmp1));# pre-load E + &jmp(&label("loop")); + +&set_label("loop",16); + + # copy input chunk to X, but reversing byte order! + for ($i=0; $i<16; $i+=4) + { + &mov($A,&DWP(4*($i+0),$T)); + &mov($B,&DWP(4*($i+1),$T)); + &mov($C,&DWP(4*($i+2),$T)); + &mov($D,&DWP(4*($i+3),$T)); + &bswap($A); + &bswap($B); + &bswap($C); + &bswap($D); + &mov(&swtmp($i+0),$A); + &mov(&swtmp($i+1),$B); + &mov(&swtmp($i+2),$C); + &mov(&swtmp($i+3),$D); + } + &mov(&wparam(1),$T); # redundant in 1st spin + + &mov($A,&DWP(0,$tmp1)); # load SHA_CTX + &mov($B,&DWP(4,$tmp1)); + &mov($C,&DWP(8,$tmp1)); + &mov($D,&DWP(12,$tmp1)); + # E is pre-loaded + + for($i=0;$i<16;$i++) { &BODY_00_15($i,@V); unshift(@V,pop(@V)); } + for(;$i<20;$i++) { &BODY_16_19($i,@V); unshift(@V,pop(@V)); } + for(;$i<40;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); } + for(;$i<60;$i++) { &BODY_40_59($i,@V); unshift(@V,pop(@V)); } + for(;$i<80;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); } + + (($V[5] eq $D) and ($V[0] eq $E)) or die; # double-check + + &mov($tmp1,&wparam(0)); # re-load SHA_CTX* + &mov($D,&wparam(1)); # D is last "T" and is discarded + + &add($E,&DWP(0,$tmp1)); # E is last "A"... + &add($T,&DWP(4,$tmp1)); + &add($A,&DWP(8,$tmp1)); + &add($B,&DWP(12,$tmp1)); + &add($C,&DWP(16,$tmp1)); + + &mov(&DWP(0,$tmp1),$E); # update SHA_CTX + &add($D,64); # advance input pointer + &mov(&DWP(4,$tmp1),$T); + &cmp($D,&wparam(2)); # have we reached the end yet? + &mov(&DWP(8,$tmp1),$A); + &mov($E,$C); # C is last "E" which needs to be "pre-loaded" + &mov(&DWP(12,$tmp1),$B); + &mov($T,$D); # input pointer + &mov(&DWP(16,$tmp1),$C); + &jb(&label("loop")); + + &stack_pop(16+3); +&function_end("sha1_block_data_order"); + +if ($xmm) { +if ($shaext) { +###################################################################### +# Intel SHA Extensions implementation of SHA1 update function. +# +my ($ctx,$inp,$num)=("edi","esi","ecx"); +my ($ABCD,$E,$E_,$BSWAP)=map("xmm$_",(0..3)); +my @MSG=map("xmm$_",(4..7)); + +sub sha1rnds4 { + my ($dst,$src,$imm)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &data_byte(0x0f,0x3a,0xcc,0xc0|($1<<3)|$2,$imm); } +} +sub sha1op38 { + my ($opcodelet,$dst,$src)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &data_byte(0x0f,0x38,$opcodelet,0xc0|($1<<3)|$2); } +} +sub sha1nexte { sha1op38(0xc8,@_); } +sub sha1msg1 { sha1op38(0xc9,@_); } +sub sha1msg2 { sha1op38(0xca,@_); } + +&function_begin("_sha1_block_data_order_shaext"); + &call (&label("pic_point")); # make it PIC! + &set_label("pic_point"); + &blindpop($tmp1); + &lea ($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1)); +&set_label("shaext_shortcut"); + &mov ($ctx,&wparam(0)); + &mov ("ebx","esp"); + &mov ($inp,&wparam(1)); + &mov ($num,&wparam(2)); + &sub ("esp",32); + + &movdqu ($ABCD,&QWP(0,$ctx)); + &movd ($E,&DWP(16,$ctx)); + &and ("esp",-32); + &movdqa ($BSWAP,&QWP(0x50,$tmp1)); # byte-n-word swap + + &movdqu (@MSG[0],&QWP(0,$inp)); + &pshufd ($ABCD,$ABCD,0b00011011); # flip word order + &movdqu (@MSG[1],&QWP(0x10,$inp)); + &pshufd ($E,$E,0b00011011); # flip word order + &movdqu (@MSG[2],&QWP(0x20,$inp)); + &pshufb (@MSG[0],$BSWAP); + &movdqu (@MSG[3],&QWP(0x30,$inp)); + &pshufb (@MSG[1],$BSWAP); + &pshufb (@MSG[2],$BSWAP); + &pshufb (@MSG[3],$BSWAP); + &jmp (&label("loop_shaext")); + +&set_label("loop_shaext",16); + &dec ($num); + &lea ("eax",&DWP(0x40,$inp)); + &movdqa (&QWP(0,"esp"),$E); # offload $E + &paddd ($E,@MSG[0]); + &cmovne ($inp,"eax"); + &movdqa (&QWP(16,"esp"),$ABCD); # offload $ABCD + +for($i=0;$i<20-4;$i+=2) { + &sha1msg1 (@MSG[0],@MSG[1]); + &movdqa ($E_,$ABCD); + &sha1rnds4 ($ABCD,$E,int($i/5)); # 0-3... + &sha1nexte ($E_,@MSG[1]); + &pxor (@MSG[0],@MSG[2]); + &sha1msg1 (@MSG[1],@MSG[2]); + &sha1msg2 (@MSG[0],@MSG[3]); + + &movdqa ($E,$ABCD); + &sha1rnds4 ($ABCD,$E_,int(($i+1)/5)); + &sha1nexte ($E,@MSG[2]); + &pxor (@MSG[1],@MSG[3]); + &sha1msg2 (@MSG[1],@MSG[0]); + + push(@MSG,shift(@MSG)); push(@MSG,shift(@MSG)); +} + &movdqu (@MSG[0],&QWP(0,$inp)); + &movdqa ($E_,$ABCD); + &sha1rnds4 ($ABCD,$E,3); # 64-67 + &sha1nexte ($E_,@MSG[1]); + &movdqu (@MSG[1],&QWP(0x10,$inp)); + &pshufb (@MSG[0],$BSWAP); + + &movdqa ($E,$ABCD); + &sha1rnds4 ($ABCD,$E_,3); # 68-71 + &sha1nexte ($E,@MSG[2]); + &movdqu (@MSG[2],&QWP(0x20,$inp)); + &pshufb (@MSG[1],$BSWAP); + + &movdqa ($E_,$ABCD); + &sha1rnds4 ($ABCD,$E,3); # 72-75 + &sha1nexte ($E_,@MSG[3]); + &movdqu (@MSG[3],&QWP(0x30,$inp)); + &pshufb (@MSG[2],$BSWAP); + + &movdqa ($E,$ABCD); + &sha1rnds4 ($ABCD,$E_,3); # 76-79 + &movdqa ($E_,&QWP(0,"esp")); + &pshufb (@MSG[3],$BSWAP); + &sha1nexte ($E,$E_); + &paddd ($ABCD,&QWP(16,"esp")); + + &jnz (&label("loop_shaext")); + + &pshufd ($ABCD,$ABCD,0b00011011); + &pshufd ($E,$E,0b00011011); + &movdqu (&QWP(0,$ctx),$ABCD) + &movd (&DWP(16,$ctx),$E); + &mov ("esp","ebx"); +&function_end("_sha1_block_data_order_shaext"); +} +###################################################################### +# The SSSE3 implementation. +# +# %xmm[0-7] are used as ring @X[] buffer containing quadruples of last +# 32 elements of the message schedule or Xupdate outputs. First 4 +# quadruples are simply byte-swapped input, next 4 are calculated +# according to method originally suggested by Dean Gaudet (modulo +# being implemented in SSSE3). Once 8 quadruples or 32 elements are +# collected, it switches to routine proposed by Max Locktyukhin. +# +# Calculations inevitably require temporary reqisters, and there are +# no %xmm registers left to spare. For this reason part of the ring +# buffer, X[2..4] to be specific, is offloaded to 3 quadriples ring +# buffer on the stack. Keep in mind that X[2] is alias X[-6], X[3] - +# X[-5], and X[4] - X[-4]... +# +# Another notable optimization is aggressive stack frame compression +# aiming to minimize amount of 9-byte instructions... +# +# Yet another notable optimization is "jumping" $B variable. It means +# that there is no register permanently allocated for $B value. This +# allowed to eliminate one instruction from body_20_39... +# +my $Xi=4; # 4xSIMD Xupdate round, start pre-seeded +my @X=map("xmm$_",(4..7,0..3)); # pre-seeded for $Xi=4 +my @V=($A,$B,$C,$D,$E); +my $j=0; # hash round +my $rx=0; +my @T=($T,$tmp1); +my $inp; + +my $_rol=sub { &rol(@_) }; +my $_ror=sub { &ror(@_) }; + +&function_begin("_sha1_block_data_order_ssse3"); + &call (&label("pic_point")); # make it PIC! + &set_label("pic_point"); + &blindpop($tmp1); + &lea ($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1)); +&set_label("ssse3_shortcut"); + + &movdqa (@X[3],&QWP(0,$tmp1)); # K_00_19 + &movdqa (@X[4],&QWP(16,$tmp1)); # K_20_39 + &movdqa (@X[5],&QWP(32,$tmp1)); # K_40_59 + &movdqa (@X[6],&QWP(48,$tmp1)); # K_60_79 + &movdqa (@X[2],&QWP(64,$tmp1)); # pbswap mask + + &mov ($E,&wparam(0)); # load argument block + &mov ($inp=@T[1],&wparam(1)); + &mov ($D,&wparam(2)); + &mov (@T[0],"esp"); + + # stack frame layout + # + # +0 X[0]+K X[1]+K X[2]+K X[3]+K # XMM->IALU xfer area + # X[4]+K X[5]+K X[6]+K X[7]+K + # X[8]+K X[9]+K X[10]+K X[11]+K + # X[12]+K X[13]+K X[14]+K X[15]+K + # + # +64 X[0] X[1] X[2] X[3] # XMM->XMM backtrace area + # X[4] X[5] X[6] X[7] + # X[8] X[9] X[10] X[11] # even borrowed for K_00_19 + # + # +112 K_20_39 K_20_39 K_20_39 K_20_39 # constants + # K_40_59 K_40_59 K_40_59 K_40_59 + # K_60_79 K_60_79 K_60_79 K_60_79 + # K_00_19 K_00_19 K_00_19 K_00_19 + # pbswap mask + # + # +192 ctx # argument block + # +196 inp + # +200 end + # +204 esp + &sub ("esp",208); + &and ("esp",-64); + + &movdqa (&QWP(112+0,"esp"),@X[4]); # copy constants + &movdqa (&QWP(112+16,"esp"),@X[5]); + &movdqa (&QWP(112+32,"esp"),@X[6]); + &shl ($D,6); # len*64 + &movdqa (&QWP(112+48,"esp"),@X[3]); + &add ($D,$inp); # end of input + &movdqa (&QWP(112+64,"esp"),@X[2]); + &add ($inp,64); + &mov (&DWP(192+0,"esp"),$E); # save argument block + &mov (&DWP(192+4,"esp"),$inp); + &mov (&DWP(192+8,"esp"),$D); + &mov (&DWP(192+12,"esp"),@T[0]); # save original %esp + + &mov ($A,&DWP(0,$E)); # load context + &mov ($B,&DWP(4,$E)); + &mov ($C,&DWP(8,$E)); + &mov ($D,&DWP(12,$E)); + &mov ($E,&DWP(16,$E)); + &mov (@T[0],$B); # magic seed + + &movdqu (@X[-4&7],&QWP(-64,$inp)); # load input to %xmm[0-3] + &movdqu (@X[-3&7],&QWP(-48,$inp)); + &movdqu (@X[-2&7],&QWP(-32,$inp)); + &movdqu (@X[-1&7],&QWP(-16,$inp)); + &pshufb (@X[-4&7],@X[2]); # byte swap + &pshufb (@X[-3&7],@X[2]); + &pshufb (@X[-2&7],@X[2]); + &movdqa (&QWP(112-16,"esp"),@X[3]); # borrow last backtrace slot + &pshufb (@X[-1&7],@X[2]); + &paddd (@X[-4&7],@X[3]); # add K_00_19 + &paddd (@X[-3&7],@X[3]); + &paddd (@X[-2&7],@X[3]); + &movdqa (&QWP(0,"esp"),@X[-4&7]); # X[]+K xfer to IALU + &psubd (@X[-4&7],@X[3]); # restore X[] + &movdqa (&QWP(0+16,"esp"),@X[-3&7]); + &psubd (@X[-3&7],@X[3]); + &movdqa (&QWP(0+32,"esp"),@X[-2&7]); + &mov (@T[1],$C); + &psubd (@X[-2&7],@X[3]); + &xor (@T[1],$D); + &pshufd (@X[0],@X[-4&7],0xee); # was &movdqa (@X[0],@X[-3&7]); + &and (@T[0],@T[1]); + &jmp (&label("loop")); + +###################################################################### +# SSE instruction sequence is first broken to groups of indepentent +# instructions, independent in respect to their inputs and shifter +# (not all architectures have more than one). Then IALU instructions +# are "knitted in" between the SSE groups. Distance is maintained for +# SSE latency of 2 in hope that it fits better upcoming AMD Bulldozer +# [which allegedly also implements SSSE3]... +# +# Temporary registers usage. X[2] is volatile at the entry and at the +# end is restored from backtrace ring buffer. X[3] is expected to +# contain current K_XX_XX constant and is used to caclulate X[-1]+K +# from previous round, it becomes volatile the moment the value is +# saved to stack for transfer to IALU. X[4] becomes volatile whenever +# X[-4] is accumulated and offloaded to backtrace ring buffer, at the +# end it is loaded with next K_XX_XX [which becomes X[3] in next +# round]... +# +sub Xupdate_ssse3_16_31() # recall that $Xi starts wtih 4 +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 40 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); # ror + eval(shift(@insns)); + eval(shift(@insns)); + &punpcklqdq(@X[0],@X[-3&7]); # compose "X[-14]" in "X[0]", was &palignr(@X[0],@X[-4&7],8); + &movdqa (@X[2],@X[-1&7]); + eval(shift(@insns)); + eval(shift(@insns)); + + &paddd (@X[3],@X[-1&7]); + &movdqa (&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]);# save X[] to backtrace buffer + eval(shift(@insns)); # rol + eval(shift(@insns)); + &psrldq (@X[2],4); # "X[-3]", 3 dwords + eval(shift(@insns)); + eval(shift(@insns)); + &pxor (@X[0],@X[-4&7]); # "X[0]"^="X[-16]" + eval(shift(@insns)); + eval(shift(@insns)); # ror + + &pxor (@X[2],@X[-2&7]); # "X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &pxor (@X[0],@X[2]); # "X[0]"^="X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); # rol + &movdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + + &movdqa (@X[4],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + &movdqa (@X[2],@X[0]); + eval(shift(@insns)); + + &pslldq (@X[4],12); # "X[0]"<<96, extract one dword + &paddd (@X[0],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + + &psrld (@X[2],31); + eval(shift(@insns)); + eval(shift(@insns)); # rol + &movdqa (@X[3],@X[4]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &psrld (@X[4],30); + eval(shift(@insns)); + eval(shift(@insns)); # ror + &por (@X[0],@X[2]); # "X[0]"<<<=1 + eval(shift(@insns)); + &movdqa (@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if ($Xi>5); # restore X[] from backtrace buffer + eval(shift(@insns)); + eval(shift(@insns)); + + &pslld (@X[3],2); + eval(shift(@insns)); + eval(shift(@insns)); # rol + &pxor (@X[0],@X[4]); + &movdqa (@X[4],&QWP(112-16+16*(($Xi)/5),"esp")); # K_XX_XX + eval(shift(@insns)); + eval(shift(@insns)); + + &pxor (@X[0],@X[3]); # "X[0]"^=("X[0]"<<96)<<<2 + &pshufd (@X[1],@X[-3&7],0xee) if ($Xi<7); # was &movdqa (@X[1],@X[-2&7]) + &pshufd (@X[3],@X[-1&7],0xee) if ($Xi==7); + eval(shift(@insns)); + eval(shift(@insns)); + + foreach (@insns) { eval; } # remaining instructions [if any] + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xupdate_ssse3_32_79() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 to 44 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); # body_20_39 + &pxor (@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]" + &punpcklqdq(@X[2],@X[-1&7]); # compose "X[-6]", was &palignr(@X[2],@X[-2&7],8) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + + &pxor (@X[0],@X[-7&7]); # "X[0]"^="X[-28]" + &movdqa (&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]); # save X[] to backtrace buffer + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)) if (@insns[0] =~ /_rol/); + if ($Xi%5) { + &movdqa (@X[4],@X[3]); # "perpetuate" K_XX_XX... + } else { # ... or load next one + &movdqa (@X[4],&QWP(112-16+16*($Xi/5),"esp")); + } + eval(shift(@insns)); # ror + &paddd (@X[3],@X[-1&7]); + eval(shift(@insns)); + + &pxor (@X[0],@X[2]); # "X[0]"^="X[-6]" + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + + &movdqa (@X[2],@X[0]); + &movdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + eval(shift(@insns)); + eval(shift(@insns)) if (@insns[0] =~ /_rol/); + + &pslld (@X[0],2); + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + &psrld (@X[2],30); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + eval(shift(@insns)); + eval(shift(@insns)) if (@insns[1] =~ /_rol/); + eval(shift(@insns)) if (@insns[0] =~ /_rol/); + + &por (@X[0],@X[2]); # "X[0]"<<<=2 + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + &movdqa (@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if($Xi<19); # restore X[] from backtrace buffer + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + &pshufd (@X[3],@X[-1],0xee) if ($Xi<19); # was &movdqa (@X[3],@X[0]) + eval(shift(@insns)); + + foreach (@insns) { eval; } # remaining instructions + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xuplast_ssse3_80() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@X[3],@X[-1&7]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &movdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer IALU + + foreach (@insns) { eval; } # remaining instructions + + &mov ($inp=@T[1],&DWP(192+4,"esp")); + &cmp ($inp,&DWP(192+8,"esp")); + &je (&label("done")); + + &movdqa (@X[3],&QWP(112+48,"esp")); # K_00_19 + &movdqa (@X[2],&QWP(112+64,"esp")); # pbswap mask + &movdqu (@X[-4&7],&QWP(0,$inp)); # load input + &movdqu (@X[-3&7],&QWP(16,$inp)); + &movdqu (@X[-2&7],&QWP(32,$inp)); + &movdqu (@X[-1&7],&QWP(48,$inp)); + &add ($inp,64); + &pshufb (@X[-4&7],@X[2]); # byte swap + &mov (&DWP(192+4,"esp"),$inp); + &movdqa (&QWP(112-16,"esp"),@X[3]); # borrow last backtrace slot + + $Xi=0; +} + +sub Xloop_ssse3() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &pshufb (@X[($Xi-3)&7],@X[2]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@X[($Xi-4)&7],@X[3]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa (&QWP(0+16*$Xi,"esp"),@X[($Xi-4)&7]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &psubd (@X[($Xi-4)&7],@X[3]); + + foreach (@insns) { eval; } + $Xi++; +} + +sub Xtail_ssse3() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + foreach (@insns) { eval; } +} + +sub body_00_19 () { # ((c^d)&b)^d + # on start @T[0]=(c^d)&b + return &body_20_39() if ($rx==19); $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + '&$_ror ($b,$j?7:2);', # $b>>>2 + '&xor (@T[0],$d);', + '&mov (@T[1],$a);', # $b in next round + + '&add ($e,&DWP(4*($j&15),"esp"));', # X[]+K xfer + '&xor ($b,$c);', # $c^$d for next round + + '&$_rol ($a,5);', + '&add ($e,@T[0]);', + '&and (@T[1],$b);', # ($b&($c^$d)) for next round + + '&xor ($b,$c);', # restore $b + '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} + +sub body_20_39 () { # b^d^c + # on entry @T[0]=b^d + return &body_40_59() if ($rx==39); $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + '&add ($e,&DWP(4*($j&15),"esp"));', # X[]+K xfer + '&xor (@T[0],$d) if($j==19);'. + '&xor (@T[0],$c) if($j> 19);', # ($b^$d^$c) + '&mov (@T[1],$a);', # $b in next round + + '&$_rol ($a,5);', + '&add ($e,@T[0]);', + '&xor (@T[1],$c) if ($j< 79);', # $b^$d for next round + + '&$_ror ($b,7);', # $b>>>2 + '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} + +sub body_40_59 () { # ((b^c)&(c^d))^c + # on entry @T[0]=(b^c), (c^=d) + $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + '&add ($e,&DWP(4*($j&15),"esp"));', # X[]+K xfer + '&and (@T[0],$c) if ($j>=40);', # (b^c)&(c^d) + '&xor ($c,$d) if ($j>=40);', # restore $c + + '&$_ror ($b,7);', # $b>>>2 + '&mov (@T[1],$a);', # $b for next round + '&xor (@T[0],$c);', + + '&$_rol ($a,5);', + '&add ($e,@T[0]);', + '&xor (@T[1],$c) if ($j==59);'. + '&xor (@T[1],$b) if ($j< 59);', # b^c for next round + + '&xor ($b,$c) if ($j< 59);', # c^d for next round + '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} +###### +sub bodyx_00_19 () { # ((c^d)&b)^d + # on start @T[0]=(b&c)^(~b&d), $e+=X[]+K + return &bodyx_20_39() if ($rx==19); $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + + '&rorx ($b,$b,2) if ($j==0);'. # $b>>>2 + '&rorx ($b,@T[1],7) if ($j!=0);', # $b>>>2 + '&lea ($e,&DWP(0,$e,@T[0]));', + '&rorx (@T[0],$a,5);', + + '&andn (@T[1],$a,$c);', + '&and ($a,$b)', + '&add ($d,&DWP(4*(($j+1)&15),"esp"));', # X[]+K xfer + + '&xor (@T[1],$a)', + '&add ($e,@T[0]);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} + +sub bodyx_20_39 () { # b^d^c + # on start $b=b^c^d + return &bodyx_40_59() if ($rx==39); $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + + '&add ($e,($j==19?@T[0]:$b))', + '&rorx ($b,@T[1],7);', # $b>>>2 + '&rorx (@T[0],$a,5);', + + '&xor ($a,$b) if ($j<79);', + '&add ($d,&DWP(4*(($j+1)&15),"esp")) if ($j<79);', # X[]+K xfer + '&xor ($a,$c) if ($j<79);', + '&add ($e,@T[0]);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} + +sub bodyx_40_59 () { # ((b^c)&(c^d))^c + # on start $b=((b^c)&(c^d))^c + return &bodyx_20_39() if ($rx==59); $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + + '&rorx (@T[0],$a,5)', + '&lea ($e,&DWP(0,$e,$b))', + '&rorx ($b,@T[1],7)', # $b>>>2 + '&add ($d,&DWP(4*(($j+1)&15),"esp"))', # X[]+K xfer + + '&mov (@T[1],$c)', + '&xor ($a,$b)', # b^c for next round + '&xor (@T[1],$b)', # c^d for next round + + '&and ($a,@T[1])', + '&add ($e,@T[0])', + '&xor ($a,$b)' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} + +&set_label("loop",16); + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_32_79(\&body_00_19); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xuplast_ssse3_80(\&body_20_39); # can jump to "done" + + $saved_j=$j; @saved_V=@V; + + &Xloop_ssse3(\&body_20_39); + &Xloop_ssse3(\&body_20_39); + &Xloop_ssse3(\&body_20_39); + + &mov (@T[1],&DWP(192,"esp")); # update context + &add ($A,&DWP(0,@T[1])); + &add (@T[0],&DWP(4,@T[1])); # $b + &add ($C,&DWP(8,@T[1])); + &mov (&DWP(0,@T[1]),$A); + &add ($D,&DWP(12,@T[1])); + &mov (&DWP(4,@T[1]),@T[0]); + &add ($E,&DWP(16,@T[1])); + &mov (&DWP(8,@T[1]),$C); + &mov ($B,$C); + &mov (&DWP(12,@T[1]),$D); + &xor ($B,$D); + &mov (&DWP(16,@T[1]),$E); + &mov (@T[1],@T[0]); + &pshufd (@X[0],@X[-4&7],0xee); # was &movdqa (@X[0],@X[-3&7]); + &and (@T[0],$B); + &mov ($B,$T[1]); + + &jmp (&label("loop")); + +&set_label("done",16); $j=$saved_j; @V=@saved_V; + + &Xtail_ssse3(\&body_20_39); + &Xtail_ssse3(\&body_20_39); + &Xtail_ssse3(\&body_20_39); + + &mov (@T[1],&DWP(192,"esp")); # update context + &add ($A,&DWP(0,@T[1])); + &mov ("esp",&DWP(192+12,"esp")); # restore %esp + &add (@T[0],&DWP(4,@T[1])); # $b + &add ($C,&DWP(8,@T[1])); + &mov (&DWP(0,@T[1]),$A); + &add ($D,&DWP(12,@T[1])); + &mov (&DWP(4,@T[1]),@T[0]); + &add ($E,&DWP(16,@T[1])); + &mov (&DWP(8,@T[1]),$C); + &mov (&DWP(12,@T[1]),$D); + &mov (&DWP(16,@T[1]),$E); + +&function_end("_sha1_block_data_order_ssse3"); + +$rx=0; # reset + +if ($ymm) { +my $Xi=4; # 4xSIMD Xupdate round, start pre-seeded +my @X=map("xmm$_",(4..7,0..3)); # pre-seeded for $Xi=4 +my @V=($A,$B,$C,$D,$E); +my $j=0; # hash round +my @T=($T,$tmp1); +my $inp; + +my $_rol=sub { &shld(@_[0],@_) }; +my $_ror=sub { &shrd(@_[0],@_) }; + +&function_begin("_sha1_block_data_order_avx"); + &call (&label("pic_point")); # make it PIC! + &set_label("pic_point"); + &blindpop($tmp1); + &lea ($tmp1,&DWP(&label("K_XX_XX")."-".&label("pic_point"),$tmp1)); +&set_label("avx_shortcut"); + &vzeroall(); + + &vmovdqa(@X[3],&QWP(0,$tmp1)); # K_00_19 + &vmovdqa(@X[4],&QWP(16,$tmp1)); # K_20_39 + &vmovdqa(@X[5],&QWP(32,$tmp1)); # K_40_59 + &vmovdqa(@X[6],&QWP(48,$tmp1)); # K_60_79 + &vmovdqa(@X[2],&QWP(64,$tmp1)); # pbswap mask + + &mov ($E,&wparam(0)); # load argument block + &mov ($inp=@T[1],&wparam(1)); + &mov ($D,&wparam(2)); + &mov (@T[0],"esp"); + + # stack frame layout + # + # +0 X[0]+K X[1]+K X[2]+K X[3]+K # XMM->IALU xfer area + # X[4]+K X[5]+K X[6]+K X[7]+K + # X[8]+K X[9]+K X[10]+K X[11]+K + # X[12]+K X[13]+K X[14]+K X[15]+K + # + # +64 X[0] X[1] X[2] X[3] # XMM->XMM backtrace area + # X[4] X[5] X[6] X[7] + # X[8] X[9] X[10] X[11] # even borrowed for K_00_19 + # + # +112 K_20_39 K_20_39 K_20_39 K_20_39 # constants + # K_40_59 K_40_59 K_40_59 K_40_59 + # K_60_79 K_60_79 K_60_79 K_60_79 + # K_00_19 K_00_19 K_00_19 K_00_19 + # pbswap mask + # + # +192 ctx # argument block + # +196 inp + # +200 end + # +204 esp + &sub ("esp",208); + &and ("esp",-64); + + &vmovdqa(&QWP(112+0,"esp"),@X[4]); # copy constants + &vmovdqa(&QWP(112+16,"esp"),@X[5]); + &vmovdqa(&QWP(112+32,"esp"),@X[6]); + &shl ($D,6); # len*64 + &vmovdqa(&QWP(112+48,"esp"),@X[3]); + &add ($D,$inp); # end of input + &vmovdqa(&QWP(112+64,"esp"),@X[2]); + &add ($inp,64); + &mov (&DWP(192+0,"esp"),$E); # save argument block + &mov (&DWP(192+4,"esp"),$inp); + &mov (&DWP(192+8,"esp"),$D); + &mov (&DWP(192+12,"esp"),@T[0]); # save original %esp + + &mov ($A,&DWP(0,$E)); # load context + &mov ($B,&DWP(4,$E)); + &mov ($C,&DWP(8,$E)); + &mov ($D,&DWP(12,$E)); + &mov ($E,&DWP(16,$E)); + &mov (@T[0],$B); # magic seed + + &vmovdqu(@X[-4&7],&QWP(-64,$inp)); # load input to %xmm[0-3] + &vmovdqu(@X[-3&7],&QWP(-48,$inp)); + &vmovdqu(@X[-2&7],&QWP(-32,$inp)); + &vmovdqu(@X[-1&7],&QWP(-16,$inp)); + &vpshufb(@X[-4&7],@X[-4&7],@X[2]); # byte swap + &vpshufb(@X[-3&7],@X[-3&7],@X[2]); + &vpshufb(@X[-2&7],@X[-2&7],@X[2]); + &vmovdqa(&QWP(112-16,"esp"),@X[3]); # borrow last backtrace slot + &vpshufb(@X[-1&7],@X[-1&7],@X[2]); + &vpaddd (@X[0],@X[-4&7],@X[3]); # add K_00_19 + &vpaddd (@X[1],@X[-3&7],@X[3]); + &vpaddd (@X[2],@X[-2&7],@X[3]); + &vmovdqa(&QWP(0,"esp"),@X[0]); # X[]+K xfer to IALU + &mov (@T[1],$C); + &vmovdqa(&QWP(0+16,"esp"),@X[1]); + &xor (@T[1],$D); + &vmovdqa(&QWP(0+32,"esp"),@X[2]); + &and (@T[0],@T[1]); + &jmp (&label("loop")); + +sub Xupdate_avx_16_31() # recall that $Xi starts wtih 4 +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 40 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + &vpalignr(@X[0],@X[-3&7],@X[-4&7],8); # compose "X[-14]" in "X[0]" + eval(shift(@insns)); + eval(shift(@insns)); + + &vpaddd (@X[3],@X[3],@X[-1&7]); + &vmovdqa (&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]);# save X[] to backtrace buffer + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrldq(@X[2],@X[-1&7],4); # "X[-3]", 3 dwords + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"^="X[-16]" + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[2],@X[2],@X[-2&7]); # "X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + &vmovdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@X[2]); # "X[0]"^="X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrld (@X[2],@X[0],31); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpslldq(@X[4],@X[0],12); # "X[0]"<<96, extract one dword + &vpaddd (@X[0],@X[0],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrld (@X[3],@X[4],30); + &vpor (@X[0],@X[0],@X[2]); # "X[0]"<<<=1 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpslld (@X[4],@X[4],2); + &vmovdqa (@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if ($Xi>5); # restore X[] from backtrace buffer + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor (@X[0],@X[0],@X[3]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@X[4]); # "X[0]"^=("X[0]"<<96)<<<2 + eval(shift(@insns)); + eval(shift(@insns)); + &vmovdqa (@X[4],&QWP(112-16+16*(($Xi)/5),"esp")); # K_XX_XX + eval(shift(@insns)); + eval(shift(@insns)); + + foreach (@insns) { eval; } # remaining instructions [if any] + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xupdate_avx_32_79() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 to 44 instructions + my ($a,$b,$c,$d,$e); + + &vpalignr(@X[2],@X[-1&7],@X[-2&7],8); # compose "X[-6]" + &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]" + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + + &vpxor (@X[0],@X[0],@X[-7&7]); # "X[0]"^="X[-28]" + &vmovdqa (&QWP(64+16*(($Xi-4)%3),"esp"),@X[-4&7]); # save X[] to backtrace buffer + eval(shift(@insns)); + eval(shift(@insns)); + if ($Xi%5) { + &vmovdqa (@X[4],@X[3]); # "perpetuate" K_XX_XX... + } else { # ... or load next one + &vmovdqa (@X[4],&QWP(112-16+16*($Xi/5),"esp")); + } + &vpaddd (@X[3],@X[3],@X[-1&7]); + eval(shift(@insns)); # ror + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@X[2]); # "X[0]"^="X[-6]" + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + + &vpsrld (@X[2],@X[0],30); + &vmovdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + eval(shift(@insns)); + + &vpslld (@X[0],@X[0],2); + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + eval(shift(@insns)); + + &vpor (@X[0],@X[0],@X[2]); # "X[0]"<<<=2 + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + &vmovdqa (@X[2],&QWP(64+16*(($Xi-6)%3),"esp")) if($Xi<19); # restore X[] from backtrace buffer + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + eval(shift(@insns)); + + foreach (@insns) { eval; } # remaining instructions + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xuplast_avx_80() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + &vpaddd (@X[3],@X[3],@X[-1&7]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vmovdqa (&QWP(0+16*(($Xi-1)&3),"esp"),@X[3]); # X[]+K xfer IALU + + foreach (@insns) { eval; } # remaining instructions + + &mov ($inp=@T[1],&DWP(192+4,"esp")); + &cmp ($inp,&DWP(192+8,"esp")); + &je (&label("done")); + + &vmovdqa(@X[3],&QWP(112+48,"esp")); # K_00_19 + &vmovdqa(@X[2],&QWP(112+64,"esp")); # pbswap mask + &vmovdqu(@X[-4&7],&QWP(0,$inp)); # load input + &vmovdqu(@X[-3&7],&QWP(16,$inp)); + &vmovdqu(@X[-2&7],&QWP(32,$inp)); + &vmovdqu(@X[-1&7],&QWP(48,$inp)); + &add ($inp,64); + &vpshufb(@X[-4&7],@X[-4&7],@X[2]); # byte swap + &mov (&DWP(192+4,"esp"),$inp); + &vmovdqa(&QWP(112-16,"esp"),@X[3]); # borrow last backtrace slot + + $Xi=0; +} + +sub Xloop_avx() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + &vpshufb (@X[($Xi-3)&7],@X[($Xi-3)&7],@X[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddd (@X[$Xi&7],@X[($Xi-4)&7],@X[3]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vmovdqa (&QWP(0+16*$Xi,"esp"),@X[$Xi&7]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + + foreach (@insns) { eval; } + $Xi++; +} + +sub Xtail_avx() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + foreach (@insns) { eval; } +} + +&set_label("loop",16); + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_32_79(\&body_00_19); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_20_39); + &Xuplast_avx_80(\&body_20_39); # can jump to "done" + + $saved_j=$j; @saved_V=@V; + + &Xloop_avx(\&body_20_39); + &Xloop_avx(\&body_20_39); + &Xloop_avx(\&body_20_39); + + &mov (@T[1],&DWP(192,"esp")); # update context + &add ($A,&DWP(0,@T[1])); + &add (@T[0],&DWP(4,@T[1])); # $b + &add ($C,&DWP(8,@T[1])); + &mov (&DWP(0,@T[1]),$A); + &add ($D,&DWP(12,@T[1])); + &mov (&DWP(4,@T[1]),@T[0]); + &add ($E,&DWP(16,@T[1])); + &mov ($B,$C); + &mov (&DWP(8,@T[1]),$C); + &xor ($B,$D); + &mov (&DWP(12,@T[1]),$D); + &mov (&DWP(16,@T[1]),$E); + &mov (@T[1],@T[0]); + &and (@T[0],$B); + &mov ($B,@T[1]); + + &jmp (&label("loop")); + +&set_label("done",16); $j=$saved_j; @V=@saved_V; + + &Xtail_avx(\&body_20_39); + &Xtail_avx(\&body_20_39); + &Xtail_avx(\&body_20_39); + + &vzeroall(); + + &mov (@T[1],&DWP(192,"esp")); # update context + &add ($A,&DWP(0,@T[1])); + &mov ("esp",&DWP(192+12,"esp")); # restore %esp + &add (@T[0],&DWP(4,@T[1])); # $b + &add ($C,&DWP(8,@T[1])); + &mov (&DWP(0,@T[1]),$A); + &add ($D,&DWP(12,@T[1])); + &mov (&DWP(4,@T[1]),@T[0]); + &add ($E,&DWP(16,@T[1])); + &mov (&DWP(8,@T[1]),$C); + &mov (&DWP(12,@T[1]),$D); + &mov (&DWP(16,@T[1]),$E); +&function_end("_sha1_block_data_order_avx"); +} +&set_label("K_XX_XX",64); +&data_word(0x5a827999,0x5a827999,0x5a827999,0x5a827999); # K_00_19 +&data_word(0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1); # K_20_39 +&data_word(0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc); # K_40_59 +&data_word(0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6); # K_60_79 +&data_word(0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f); # pbswap mask +&data_byte(0xf,0xe,0xd,0xc,0xb,0xa,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0); +} +&asciz("SHA1 block transform for x86, CRYPTOGAMS by "); + +&asm_finish(); diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-armv4-large.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-armv4-large.pl new file mode 100644 index 00000000..a20d3368 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-armv4-large.pl @@ -0,0 +1,701 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== + +# sha1_block procedure for ARMv4. +# +# January 2007. + +# Size/performance trade-off +# ==================================================================== +# impl size in bytes comp cycles[*] measured performance +# ==================================================================== +# thumb 304 3212 4420 +# armv4-small 392/+29% 1958/+64% 2250/+96% +# armv4-compact 740/+89% 1552/+26% 1840/+22% +# armv4-large 1420/+92% 1307/+19% 1370/+34%[***] +# full unroll ~5100/+260% ~1260/+4% ~1300/+5% +# ==================================================================== +# thumb = same as 'small' but in Thumb instructions[**] and +# with recurring code in two private functions; +# small = detached Xload/update, loops are folded; +# compact = detached Xload/update, 5x unroll; +# large = interleaved Xload/update, 5x unroll; +# full unroll = interleaved Xload/update, full unroll, estimated[!]; +# +# [*] Manually counted instructions in "grand" loop body. Measured +# performance is affected by prologue and epilogue overhead, +# i-cache availability, branch penalties, etc. +# [**] While each Thumb instruction is twice smaller, they are not as +# diverse as ARM ones: e.g., there are only two arithmetic +# instructions with 3 arguments, no [fixed] rotate, addressing +# modes are limited. As result it takes more instructions to do +# the same job in Thumb, therefore the code is never twice as +# small and always slower. +# [***] which is also ~35% better than compiler generated code. Dual- +# issue Cortex A8 core was measured to process input block in +# ~990 cycles. + +# August 2010. +# +# Rescheduling for dual-issue pipeline resulted in 13% improvement on +# Cortex A8 core and in absolute terms ~870 cycles per input block +# [or 13.6 cycles per byte]. + +# February 2011. +# +# Profiler-assisted and platform-specific optimization resulted in 10% +# improvement on Cortex A8 core and 12.2 cycles per byte. + +# September 2013. +# +# Add NEON implementation (see sha1-586.pl for background info). On +# Cortex A8 it was measured to process one byte in 6.7 cycles or >80% +# faster than integer-only code. Because [fully unrolled] NEON code +# is ~2.5x larger and there are some redundant instructions executed +# when processing last block, improvement is not as big for smallest +# blocks, only ~30%. Snapdragon S4 is a tad faster, 6.4 cycles per +# byte, which is also >80% faster than integer-only code. Cortex-A15 +# is even faster spending 5.6 cycles per byte outperforming integer- +# only code by factor of 2. + +# May 2014. +# +# Add ARMv8 code path performing at 2.35 cpb on Apple A7. + +$flavour = shift; +if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } +else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} } + +if ($flavour && $flavour ne "void") { + $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; + ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or + ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or + die "can't locate arm-xlate.pl"; + + open STDOUT,"| \"$^X\" $xlate $flavour $output"; +} else { + open STDOUT,">$output"; +} + +$ctx="r0"; +$inp="r1"; +$len="r2"; +$a="r3"; +$b="r4"; +$c="r5"; +$d="r6"; +$e="r7"; +$K="r8"; +$t0="r9"; +$t1="r10"; +$t2="r11"; +$t3="r12"; +$Xi="r14"; +@V=($a,$b,$c,$d,$e); + +sub Xupdate { +my ($a,$b,$c,$d,$e,$opt1,$opt2)=@_; +$code.=<<___; + ldr $t0,[$Xi,#15*4] + ldr $t1,[$Xi,#13*4] + ldr $t2,[$Xi,#7*4] + add $e,$K,$e,ror#2 @ E+=K_xx_xx + ldr $t3,[$Xi,#2*4] + eor $t0,$t0,$t1 + eor $t2,$t2,$t3 @ 1 cycle stall + eor $t1,$c,$d @ F_xx_xx + mov $t0,$t0,ror#31 + add $e,$e,$a,ror#27 @ E+=ROR(A,27) + eor $t0,$t0,$t2,ror#31 + str $t0,[$Xi,#-4]! + $opt1 @ F_xx_xx + $opt2 @ F_xx_xx + add $e,$e,$t0 @ E+=X[i] +___ +} + +sub BODY_00_15 { +my ($a,$b,$c,$d,$e)=@_; +$code.=<<___; +#if __ARM_ARCH__<7 + ldrb $t1,[$inp,#2] + ldrb $t0,[$inp,#3] + ldrb $t2,[$inp,#1] + add $e,$K,$e,ror#2 @ E+=K_00_19 + ldrb $t3,[$inp],#4 + orr $t0,$t0,$t1,lsl#8 + eor $t1,$c,$d @ F_xx_xx + orr $t0,$t0,$t2,lsl#16 + add $e,$e,$a,ror#27 @ E+=ROR(A,27) + orr $t0,$t0,$t3,lsl#24 +#else + ldr $t0,[$inp],#4 @ handles unaligned + add $e,$K,$e,ror#2 @ E+=K_00_19 + eor $t1,$c,$d @ F_xx_xx + add $e,$e,$a,ror#27 @ E+=ROR(A,27) +#ifdef __ARMEL__ + rev $t0,$t0 @ byte swap +#endif +#endif + and $t1,$b,$t1,ror#2 + add $e,$e,$t0 @ E+=X[i] + eor $t1,$t1,$d,ror#2 @ F_00_19(B,C,D) + str $t0,[$Xi,#-4]! + add $e,$e,$t1 @ E+=F_00_19(B,C,D) +___ +} + +sub BODY_16_19 { +my ($a,$b,$c,$d,$e)=@_; + &Xupdate(@_,"and $t1,$b,$t1,ror#2"); +$code.=<<___; + eor $t1,$t1,$d,ror#2 @ F_00_19(B,C,D) + add $e,$e,$t1 @ E+=F_00_19(B,C,D) +___ +} + +sub BODY_20_39 { +my ($a,$b,$c,$d,$e)=@_; + &Xupdate(@_,"eor $t1,$b,$t1,ror#2"); +$code.=<<___; + add $e,$e,$t1 @ E+=F_20_39(B,C,D) +___ +} + +sub BODY_40_59 { +my ($a,$b,$c,$d,$e)=@_; + &Xupdate(@_,"and $t1,$b,$t1,ror#2","and $t2,$c,$d"); +$code.=<<___; + add $e,$e,$t1 @ E+=F_40_59(B,C,D) + add $e,$e,$t2,ror#2 +___ +} + +$code=<<___; +#include "arm_arch.h" + +.text +.code 32 + +.global sha1_block_data_order +.type sha1_block_data_order,%function + +.align 5 +sha1_block_data_order: +#if __ARM_MAX_ARCH__>=7 + sub r3,pc,#8 @ sha1_block_data_order + ldr r12,.LOPENSSL_armcap + ldr r12,[r3,r12] @ OPENSSL_armcap_P +#ifdef __APPLE__ + ldr r12,[r12] +#endif + tst r12,#ARMV8_SHA1 + bne .LARMv8 + tst r12,#ARMV7_NEON + bne .LNEON +#endif + stmdb sp!,{r4-r12,lr} + add $len,$inp,$len,lsl#6 @ $len to point at the end of $inp + ldmia $ctx,{$a,$b,$c,$d,$e} +.Lloop: + ldr $K,.LK_00_19 + mov $Xi,sp + sub sp,sp,#15*4 + mov $c,$c,ror#30 + mov $d,$d,ror#30 + mov $e,$e,ror#30 @ [6] +.L_00_15: +___ +for($i=0;$i<5;$i++) { + &BODY_00_15(@V); unshift(@V,pop(@V)); +} +$code.=<<___; + teq $Xi,sp + bne .L_00_15 @ [((11+4)*5+2)*3] + sub sp,sp,#25*4 +___ + &BODY_00_15(@V); unshift(@V,pop(@V)); + &BODY_16_19(@V); unshift(@V,pop(@V)); + &BODY_16_19(@V); unshift(@V,pop(@V)); + &BODY_16_19(@V); unshift(@V,pop(@V)); + &BODY_16_19(@V); unshift(@V,pop(@V)); +$code.=<<___; + + ldr $K,.LK_20_39 @ [+15+16*4] + cmn sp,#0 @ [+3], clear carry to denote 20_39 +.L_20_39_or_60_79: +___ +for($i=0;$i<5;$i++) { + &BODY_20_39(@V); unshift(@V,pop(@V)); +} +$code.=<<___; + teq $Xi,sp @ preserve carry + bne .L_20_39_or_60_79 @ [+((12+3)*5+2)*4] + bcs .L_done @ [+((12+3)*5+2)*4], spare 300 bytes + + ldr $K,.LK_40_59 + sub sp,sp,#20*4 @ [+2] +.L_40_59: +___ +for($i=0;$i<5;$i++) { + &BODY_40_59(@V); unshift(@V,pop(@V)); +} +$code.=<<___; + teq $Xi,sp + bne .L_40_59 @ [+((12+5)*5+2)*4] + + ldr $K,.LK_60_79 + sub sp,sp,#20*4 + cmp sp,#0 @ set carry to denote 60_79 + b .L_20_39_or_60_79 @ [+4], spare 300 bytes +.L_done: + add sp,sp,#80*4 @ "deallocate" stack frame + ldmia $ctx,{$K,$t0,$t1,$t2,$t3} + add $a,$K,$a + add $b,$t0,$b + add $c,$t1,$c,ror#2 + add $d,$t2,$d,ror#2 + add $e,$t3,$e,ror#2 + stmia $ctx,{$a,$b,$c,$d,$e} + teq $inp,$len + bne .Lloop @ [+18], total 1307 + +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r12,pc} +#else + ldmia sp!,{r4-r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size sha1_block_data_order,.-sha1_block_data_order + +.align 5 +.LK_00_19: .word 0x5a827999 +.LK_20_39: .word 0x6ed9eba1 +.LK_40_59: .word 0x8f1bbcdc +.LK_60_79: .word 0xca62c1d6 +#if __ARM_MAX_ARCH__>=7 +.LOPENSSL_armcap: +.word OPENSSL_armcap_P-sha1_block_data_order +#endif +.asciz "SHA1 block transform for ARMv4/NEON/ARMv8, CRYPTOGAMS by " +.align 5 +___ +##################################################################### +# NEON stuff +# +{{{ +my @V=($a,$b,$c,$d,$e); +my ($K_XX_XX,$Ki,$t0,$t1,$Xfer,$saved_sp)=map("r$_",(8..12,14)); +my $Xi=4; +my @X=map("q$_",(8..11,0..3)); +my @Tx=("q12","q13"); +my ($K,$zero)=("q14","q15"); +my $j=0; + +sub AUTOLOAD() # thunk [simplified] x86-style perlasm +{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./; + my $arg = pop; + $arg = "#$arg" if ($arg*1 eq $arg); + $code .= "\t$opcode\t".join(',',@_,$arg)."\n"; +} + +sub body_00_19 () { + ( + '($a,$b,$c,$d,$e)=@V;'. # '$code.="@ $j\n";'. + '&bic ($t0,$d,$b)', + '&add ($e,$e,$Ki)', # e+=X[i]+K + '&and ($t1,$c,$b)', + '&ldr ($Ki,sprintf "[sp,#%d]",4*(($j+1)&15))', + '&add ($e,$e,$a,"ror#27")', # e+=ROR(A,27) + '&eor ($t1,$t1,$t0)', # F_00_19 + '&mov ($b,$b,"ror#2")', # b=ROR(b,2) + '&add ($e,$e,$t1);'. # e+=F_00_19 + '$j++; unshift(@V,pop(@V));' + ) +} +sub body_20_39 () { + ( + '($a,$b,$c,$d,$e)=@V;'. # '$code.="@ $j\n";'. + '&eor ($t0,$b,$d)', + '&add ($e,$e,$Ki)', # e+=X[i]+K + '&ldr ($Ki,sprintf "[sp,#%d]",4*(($j+1)&15)) if ($j<79)', + '&eor ($t1,$t0,$c)', # F_20_39 + '&add ($e,$e,$a,"ror#27")', # e+=ROR(A,27) + '&mov ($b,$b,"ror#2")', # b=ROR(b,2) + '&add ($e,$e,$t1);'. # e+=F_20_39 + '$j++; unshift(@V,pop(@V));' + ) +} +sub body_40_59 () { + ( + '($a,$b,$c,$d,$e)=@V;'. # '$code.="@ $j\n";'. + '&add ($e,$e,$Ki)', # e+=X[i]+K + '&and ($t0,$c,$d)', + '&ldr ($Ki,sprintf "[sp,#%d]",4*(($j+1)&15))', + '&add ($e,$e,$a,"ror#27")', # e+=ROR(A,27) + '&eor ($t1,$c,$d)', + '&add ($e,$e,$t0)', + '&and ($t1,$t1,$b)', + '&mov ($b,$b,"ror#2")', # b=ROR(b,2) + '&add ($e,$e,$t1);'. # e+=F_40_59 + '$j++; unshift(@V,pop(@V));' + ) +} + +sub Xupdate_16_31 () +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); + my ($a,$b,$c,$d,$e); + + &vext_8 (@X[0],@X[-4&7],@X[-3&7],8); # compose "X[-14]" in "X[0]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (@Tx[1],@X[-1&7],$K); + eval(shift(@insns)); + &vld1_32 ("{$K\[]}","[$K_XX_XX,:32]!") if ($Xi%5==0); + eval(shift(@insns)); + &vext_8 (@Tx[0],@X[-1&7],$zero,4); # "X[-3]", 3 words + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &veor (@X[0],@X[0],@X[-4&7]); # "X[0]"^="X[-16]" + eval(shift(@insns)); + eval(shift(@insns)); + &veor (@Tx[0],@Tx[0],@X[-2&7]); # "X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + &veor (@Tx[0],@Tx[0],@X[0]); # "X[0]"^="X[-3]"^"X[-8] + eval(shift(@insns)); + eval(shift(@insns)); + &vst1_32 ("{@Tx[1]}","[$Xfer,:128]!"); # X[]+K xfer + &sub ($Xfer,$Xfer,64) if ($Xi%4==0); + eval(shift(@insns)); + eval(shift(@insns)); + &vext_8 (@Tx[1],$zero,@Tx[0],4); # "X[0]"<<96, extract one dword + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (@X[0],@Tx[0],@Tx[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vsri_32 (@X[0],@Tx[0],31); # "X[0]"<<<=1 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 (@Tx[0],@Tx[1],30); + eval(shift(@insns)); + eval(shift(@insns)); + &vshl_u32 (@Tx[1],@Tx[1],2); + eval(shift(@insns)); + eval(shift(@insns)); + &veor (@X[0],@X[0],@Tx[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &veor (@X[0],@X[0],@Tx[1]); # "X[0]"^=("X[0]">>96)<<<2 + + foreach (@insns) { eval; } # remaining instructions [if any] + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xupdate_32_79 () +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); + my ($a,$b,$c,$d,$e); + + &vext_8 (@Tx[0],@X[-2&7],@X[-1&7],8); # compose "X[-6]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &veor (@X[0],@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]" + eval(shift(@insns)); + eval(shift(@insns)); + &veor (@X[0],@X[0],@X[-7&7]); # "X[0]"^="X[-28]" + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (@Tx[1],@X[-1&7],$K); + eval(shift(@insns)); + &vld1_32 ("{$K\[]}","[$K_XX_XX,:32]!") if ($Xi%5==0); + eval(shift(@insns)); + &veor (@Tx[0],@Tx[0],@X[0]); # "X[-6]"^="X[0]" + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 (@X[0],@Tx[0],30); + eval(shift(@insns)); + eval(shift(@insns)); + &vst1_32 ("{@Tx[1]}","[$Xfer,:128]!"); # X[]+K xfer + &sub ($Xfer,$Xfer,64) if ($Xi%4==0); + eval(shift(@insns)); + eval(shift(@insns)); + &vsli_32 (@X[0],@Tx[0],2); # "X[0]"="X[-6]"<<<2 + + foreach (@insns) { eval; } # remaining instructions [if any] + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xuplast_80 () +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); + my ($a,$b,$c,$d,$e); + + &vadd_i32 (@Tx[1],@X[-1&7],$K); + eval(shift(@insns)); + eval(shift(@insns)); + &vst1_32 ("{@Tx[1]}","[$Xfer,:128]!"); + &sub ($Xfer,$Xfer,64); + + &teq ($inp,$len); + &sub ($K_XX_XX,$K_XX_XX,16); # rewind $K_XX_XX + &subeq ($inp,$inp,64); # reload last block to avoid SEGV + &vld1_8 ("{@X[-4&7]-@X[-3&7]}","[$inp]!"); + eval(shift(@insns)); + eval(shift(@insns)); + &vld1_8 ("{@X[-2&7]-@X[-1&7]}","[$inp]!"); + eval(shift(@insns)); + eval(shift(@insns)); + &vld1_32 ("{$K\[]}","[$K_XX_XX,:32]!"); # load K_00_19 + eval(shift(@insns)); + eval(shift(@insns)); + &vrev32_8 (@X[-4&7],@X[-4&7]); + + foreach (@insns) { eval; } # remaining instructions + + $Xi=0; +} + +sub Xloop() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); + my ($a,$b,$c,$d,$e); + + &vrev32_8 (@X[($Xi-3)&7],@X[($Xi-3)&7]); + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (@X[$Xi&7],@X[($Xi-4)&7],$K); + eval(shift(@insns)); + eval(shift(@insns)); + &vst1_32 ("{@X[$Xi&7]}","[$Xfer,:128]!");# X[]+K xfer to IALU + + foreach (@insns) { eval; } + + $Xi++; +} + +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.type sha1_block_data_order_neon,%function +.align 4 +sha1_block_data_order_neon: +.LNEON: + stmdb sp!,{r4-r12,lr} + add $len,$inp,$len,lsl#6 @ $len to point at the end of $inp + @ dmb @ errata #451034 on early Cortex A8 + @ vstmdb sp!,{d8-d15} @ ABI specification says so + mov $saved_sp,sp + sub sp,sp,#64 @ alloca + adr $K_XX_XX,.LK_00_19 + bic sp,sp,#15 @ align for 128-bit stores + + ldmia $ctx,{$a,$b,$c,$d,$e} @ load context + mov $Xfer,sp + + vld1.8 {@X[-4&7]-@X[-3&7]},[$inp]! @ handles unaligned + veor $zero,$zero,$zero + vld1.8 {@X[-2&7]-@X[-1&7]},[$inp]! + vld1.32 {${K}\[]},[$K_XX_XX,:32]! @ load K_00_19 + vrev32.8 @X[-4&7],@X[-4&7] @ yes, even on + vrev32.8 @X[-3&7],@X[-3&7] @ big-endian... + vrev32.8 @X[-2&7],@X[-2&7] + vadd.i32 @X[0],@X[-4&7],$K + vrev32.8 @X[-1&7],@X[-1&7] + vadd.i32 @X[1],@X[-3&7],$K + vst1.32 {@X[0]},[$Xfer,:128]! + vadd.i32 @X[2],@X[-2&7],$K + vst1.32 {@X[1]},[$Xfer,:128]! + vst1.32 {@X[2]},[$Xfer,:128]! + ldr $Ki,[sp] @ big RAW stall + +.Loop_neon: +___ + &Xupdate_16_31(\&body_00_19); + &Xupdate_16_31(\&body_00_19); + &Xupdate_16_31(\&body_00_19); + &Xupdate_16_31(\&body_00_19); + &Xupdate_32_79(\&body_00_19); + &Xupdate_32_79(\&body_20_39); + &Xupdate_32_79(\&body_20_39); + &Xupdate_32_79(\&body_20_39); + &Xupdate_32_79(\&body_20_39); + &Xupdate_32_79(\&body_20_39); + &Xupdate_32_79(\&body_40_59); + &Xupdate_32_79(\&body_40_59); + &Xupdate_32_79(\&body_40_59); + &Xupdate_32_79(\&body_40_59); + &Xupdate_32_79(\&body_40_59); + &Xupdate_32_79(\&body_20_39); + &Xuplast_80(\&body_20_39); + &Xloop(\&body_20_39); + &Xloop(\&body_20_39); + &Xloop(\&body_20_39); +$code.=<<___; + ldmia $ctx,{$Ki,$t0,$t1,$Xfer} @ accumulate context + add $a,$a,$Ki + ldr $Ki,[$ctx,#16] + add $b,$b,$t0 + add $c,$c,$t1 + add $d,$d,$Xfer + moveq sp,$saved_sp + add $e,$e,$Ki + ldrne $Ki,[sp] + stmia $ctx,{$a,$b,$c,$d,$e} + addne $Xfer,sp,#3*16 + bne .Loop_neon + + @ vldmia sp!,{d8-d15} + ldmia sp!,{r4-r12,pc} +.size sha1_block_data_order_neon,.-sha1_block_data_order_neon +#endif +___ +}}} +##################################################################### +# ARMv8 stuff +# +{{{ +my ($ABCD,$E,$E0,$E1)=map("q$_",(0..3)); +my @MSG=map("q$_",(4..7)); +my @Kxx=map("q$_",(8..11)); +my ($W0,$W1,$ABCD_SAVE)=map("q$_",(12..14)); + +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 +.type sha1_block_data_order_armv8,%function +.align 5 +sha1_block_data_order_armv8: +.LARMv8: + vstmdb sp!,{d8-d15} @ ABI specification says so + + veor $E,$E,$E + adr r3,.LK_00_19 + vld1.32 {$ABCD},[$ctx]! + vld1.32 {$E\[0]},[$ctx] + sub $ctx,$ctx,#16 + vld1.32 {@Kxx[0]\[]},[r3,:32]! + vld1.32 {@Kxx[1]\[]},[r3,:32]! + vld1.32 {@Kxx[2]\[]},[r3,:32]! + vld1.32 {@Kxx[3]\[]},[r3,:32] + +.Loop_v8: + vld1.8 {@MSG[0]-@MSG[1]},[$inp]! + vld1.8 {@MSG[2]-@MSG[3]},[$inp]! + vrev32.8 @MSG[0],@MSG[0] + vrev32.8 @MSG[1],@MSG[1] + + vadd.i32 $W0,@Kxx[0],@MSG[0] + vrev32.8 @MSG[2],@MSG[2] + vmov $ABCD_SAVE,$ABCD @ offload + subs $len,$len,#1 + + vadd.i32 $W1,@Kxx[0],@MSG[1] + vrev32.8 @MSG[3],@MSG[3] + sha1h $E1,$ABCD @ 0 + sha1c $ABCD,$E,$W0 + vadd.i32 $W0,@Kxx[$j],@MSG[2] + sha1su0 @MSG[0],@MSG[1],@MSG[2] +___ +for ($j=0,$i=1;$i<20-3;$i++) { +my $f=("c","p","m","p")[$i/5]; +$code.=<<___; + sha1h $E0,$ABCD @ $i + sha1$f $ABCD,$E1,$W1 + vadd.i32 $W1,@Kxx[$j],@MSG[3] + sha1su1 @MSG[0],@MSG[3] +___ +$code.=<<___ if ($i<20-4); + sha1su0 @MSG[1],@MSG[2],@MSG[3] +___ + ($E0,$E1)=($E1,$E0); ($W0,$W1)=($W1,$W0); + push(@MSG,shift(@MSG)); $j++ if ((($i+3)%5)==0); +} +$code.=<<___; + sha1h $E0,$ABCD @ $i + sha1p $ABCD,$E1,$W1 + vadd.i32 $W1,@Kxx[$j],@MSG[3] + + sha1h $E1,$ABCD @ 18 + sha1p $ABCD,$E0,$W0 + + sha1h $E0,$ABCD @ 19 + sha1p $ABCD,$E1,$W1 + + vadd.i32 $E,$E,$E0 + vadd.i32 $ABCD,$ABCD,$ABCD_SAVE + bne .Loop_v8 + + vst1.32 {$ABCD},[$ctx]! + vst1.32 {$E\[0]},[$ctx] + + vldmia sp!,{d8-d15} + ret @ bx lr +.size sha1_block_data_order_armv8,.-sha1_block_data_order_armv8 +#endif +___ +}}} +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 +.comm OPENSSL_armcap_P,4,4 +.hidden OPENSSL_armcap_P +#endif +___ + +{ my %opcode = ( + "sha1c" => 0xf2000c40, "sha1p" => 0xf2100c40, + "sha1m" => 0xf2200c40, "sha1su0" => 0xf2300c40, + "sha1h" => 0xf3b902c0, "sha1su1" => 0xf3ba0380 ); + + sub unsha1 { + my ($mnemonic,$arg)=@_; + + if ($arg =~ m/q([0-9]+)(?:,\s*q([0-9]+))?,\s*q([0-9]+)/o) { + my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19) + |(($2&7)<<17)|(($2&8)<<4) + |(($3&7)<<1) |(($3&8)<<2); + # since ARMv7 instructions are always encoded little-endian. + # correct solution is to use .inst directive, but older + # assemblers don't implement it:-( + sprintf ".byte\t0x%02x,0x%02x,0x%02x,0x%02x\t@ %s %s", + $word&0xff,($word>>8)&0xff, + ($word>>16)&0xff,($word>>24)&0xff, + $mnemonic,$arg; + } + } +} + +foreach (split($/,$code)) { + s/{q([0-9]+)\[\]}/sprintf "{d%d[],d%d[]}",2*$1,2*$1+1/eo or + s/{q([0-9]+)\[0\]}/sprintf "{d%d[0]}",2*$1/eo; + + s/\b(sha1\w+)\s+(q.*)/unsha1($1,$2)/geo; + + s/\bret\b/bx lr/o or + s/\bbx\s+lr\b/.word\t0xe12fff1e/o; # make it possible to compile with -march=armv4 + + print $_,$/; +} + +close STDOUT; # enforce flush diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-armv8.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-armv8.pl new file mode 100644 index 00000000..a8c08c27 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-armv8.pl @@ -0,0 +1,347 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# SHA1 for ARMv8. +# +# Performance in cycles per processed byte and improvement coefficient +# over code generated with "default" compiler: +# +# hardware-assisted software(*) +# Apple A7 2.31 4.13 (+14%) +# Cortex-A53 2.24 8.03 (+97%) +# Cortex-A57 2.35 7.88 (+74%) +# Denver 2.13 3.97 (+0%)(**) +# X-Gene 8.80 (+200%) +# +# (*) Software results are presented mostly for reference purposes. +# (**) Keep in mind that Denver relies on binary translation, which +# optimizes compiler output at run-time. + +$flavour = shift; +$output = shift; + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or +die "can't locate arm-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +($ctx,$inp,$num)=("x0","x1","x2"); +@Xw=map("w$_",(3..17,19)); +@Xx=map("x$_",(3..17,19)); +@V=($A,$B,$C,$D,$E)=map("w$_",(20..24)); +($t0,$t1,$t2,$K)=map("w$_",(25..28)); + + +sub BODY_00_19 { +my ($i,$a,$b,$c,$d,$e)=@_; +my $j=($i+2)&15; + +$code.=<<___ if ($i<15 && !($i&1)); + lsr @Xx[$i+1],@Xx[$i],#32 +___ +$code.=<<___ if ($i<14 && !($i&1)); + ldr @Xx[$i+2],[$inp,#`($i+2)*4-64`] +___ +$code.=<<___ if ($i<14 && ($i&1)); +#ifdef __ARMEB__ + ror @Xx[$i+1],@Xx[$i+1],#32 +#else + rev32 @Xx[$i+1],@Xx[$i+1] +#endif +___ +$code.=<<___ if ($i<14); + bic $t0,$d,$b + and $t1,$c,$b + ror $t2,$a,#27 + add $d,$d,$K // future e+=K + orr $t0,$t0,$t1 + add $e,$e,$t2 // e+=rot(a,5) + ror $b,$b,#2 + add $d,$d,@Xw[($i+1)&15] // future e+=X[i] + add $e,$e,$t0 // e+=F(b,c,d) +___ +$code.=<<___ if ($i==19); + movz $K,#0xeba1 + movk $K,#0x6ed9,lsl#16 +___ +$code.=<<___ if ($i>=14); + eor @Xw[$j],@Xw[$j],@Xw[($j+2)&15] + bic $t0,$d,$b + and $t1,$c,$b + ror $t2,$a,#27 + eor @Xw[$j],@Xw[$j],@Xw[($j+8)&15] + add $d,$d,$K // future e+=K + orr $t0,$t0,$t1 + add $e,$e,$t2 // e+=rot(a,5) + eor @Xw[$j],@Xw[$j],@Xw[($j+13)&15] + ror $b,$b,#2 + add $d,$d,@Xw[($i+1)&15] // future e+=X[i] + add $e,$e,$t0 // e+=F(b,c,d) + ror @Xw[$j],@Xw[$j],#31 +___ +} + +sub BODY_40_59 { +my ($i,$a,$b,$c,$d,$e)=@_; +my $j=($i+2)&15; + +$code.=<<___ if ($i==59); + movz $K,#0xc1d6 + movk $K,#0xca62,lsl#16 +___ +$code.=<<___; + orr $t0,$b,$c + and $t1,$b,$c + eor @Xw[$j],@Xw[$j],@Xw[($j+2)&15] + ror $t2,$a,#27 + and $t0,$t0,$d + add $d,$d,$K // future e+=K + eor @Xw[$j],@Xw[$j],@Xw[($j+8)&15] + add $e,$e,$t2 // e+=rot(a,5) + orr $t0,$t0,$t1 + ror $b,$b,#2 + eor @Xw[$j],@Xw[$j],@Xw[($j+13)&15] + add $d,$d,@Xw[($i+1)&15] // future e+=X[i] + add $e,$e,$t0 // e+=F(b,c,d) + ror @Xw[$j],@Xw[$j],#31 +___ +} + +sub BODY_20_39 { +my ($i,$a,$b,$c,$d,$e)=@_; +my $j=($i+2)&15; + +$code.=<<___ if ($i==39); + movz $K,#0xbcdc + movk $K,#0x8f1b,lsl#16 +___ +$code.=<<___ if ($i<78); + eor @Xw[$j],@Xw[$j],@Xw[($j+2)&15] + eor $t0,$d,$b + ror $t2,$a,#27 + add $d,$d,$K // future e+=K + eor @Xw[$j],@Xw[$j],@Xw[($j+8)&15] + eor $t0,$t0,$c + add $e,$e,$t2 // e+=rot(a,5) + ror $b,$b,#2 + eor @Xw[$j],@Xw[$j],@Xw[($j+13)&15] + add $d,$d,@Xw[($i+1)&15] // future e+=X[i] + add $e,$e,$t0 // e+=F(b,c,d) + ror @Xw[$j],@Xw[$j],#31 +___ +$code.=<<___ if ($i==78); + ldp @Xw[1],@Xw[2],[$ctx] + eor $t0,$d,$b + ror $t2,$a,#27 + add $d,$d,$K // future e+=K + eor $t0,$t0,$c + add $e,$e,$t2 // e+=rot(a,5) + ror $b,$b,#2 + add $d,$d,@Xw[($i+1)&15] // future e+=X[i] + add $e,$e,$t0 // e+=F(b,c,d) +___ +$code.=<<___ if ($i==79); + ldp @Xw[3],@Xw[4],[$ctx,#8] + eor $t0,$d,$b + ror $t2,$a,#27 + eor $t0,$t0,$c + add $e,$e,$t2 // e+=rot(a,5) + ror $b,$b,#2 + ldr @Xw[5],[$ctx,#16] + add $e,$e,$t0 // e+=F(b,c,d) +___ +} + +$code.=<<___; +#include "arm_arch.h" + +.text + +.extern OPENSSL_armcap_P +.globl sha1_block_data_order +.type sha1_block_data_order,%function +.align 6 +sha1_block_data_order: + ldr x16,.LOPENSSL_armcap_P + adr x17,.LOPENSSL_armcap_P + add x16,x16,x17 + ldr w16,[x16] + tst w16,#ARMV8_SHA1 + b.ne .Lv8_entry + + stp x29,x30,[sp,#-96]! + add x29,sp,#0 + stp x19,x20,[sp,#16] + stp x21,x22,[sp,#32] + stp x23,x24,[sp,#48] + stp x25,x26,[sp,#64] + stp x27,x28,[sp,#80] + + ldp $A,$B,[$ctx] + ldp $C,$D,[$ctx,#8] + ldr $E,[$ctx,#16] + +.Loop: + ldr @Xx[0],[$inp],#64 + movz $K,#0x7999 + sub $num,$num,#1 + movk $K,#0x5a82,lsl#16 +#ifdef __ARMEB__ + ror $Xx[0],@Xx[0],#32 +#else + rev32 @Xx[0],@Xx[0] +#endif + add $E,$E,$K // warm it up + add $E,$E,@Xw[0] +___ +for($i=0;$i<20;$i++) { &BODY_00_19($i,@V); unshift(@V,pop(@V)); } +for(;$i<40;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); } +for(;$i<60;$i++) { &BODY_40_59($i,@V); unshift(@V,pop(@V)); } +for(;$i<80;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); } +$code.=<<___; + add $B,$B,@Xw[2] + add $C,$C,@Xw[3] + add $A,$A,@Xw[1] + add $D,$D,@Xw[4] + add $E,$E,@Xw[5] + stp $A,$B,[$ctx] + stp $C,$D,[$ctx,#8] + str $E,[$ctx,#16] + cbnz $num,.Loop + + ldp x19,x20,[sp,#16] + ldp x21,x22,[sp,#32] + ldp x23,x24,[sp,#48] + ldp x25,x26,[sp,#64] + ldp x27,x28,[sp,#80] + ldr x29,[sp],#96 + ret +.size sha1_block_data_order,.-sha1_block_data_order +___ +{{{ +my ($ABCD,$E,$E0,$E1)=map("v$_.16b",(0..3)); +my @MSG=map("v$_.16b",(4..7)); +my @Kxx=map("v$_.4s",(16..19)); +my ($W0,$W1)=("v20.4s","v21.4s"); +my $ABCD_SAVE="v22.16b"; + +$code.=<<___; +.type sha1_block_armv8,%function +.align 6 +sha1_block_armv8: +.Lv8_entry: + stp x29,x30,[sp,#-16]! + add x29,sp,#0 + + adr x4,.Lconst + eor $E,$E,$E + ld1.32 {$ABCD},[$ctx],#16 + ld1.32 {$E}[0],[$ctx] + sub $ctx,$ctx,#16 + ld1.32 {@Kxx[0]-@Kxx[3]},[x4] + +.Loop_hw: + ld1 {@MSG[0]-@MSG[3]},[$inp],#64 + sub $num,$num,#1 + rev32 @MSG[0],@MSG[0] + rev32 @MSG[1],@MSG[1] + + add.i32 $W0,@Kxx[0],@MSG[0] + rev32 @MSG[2],@MSG[2] + orr $ABCD_SAVE,$ABCD,$ABCD // offload + + add.i32 $W1,@Kxx[0],@MSG[1] + rev32 @MSG[3],@MSG[3] + sha1h $E1,$ABCD + sha1c $ABCD,$E,$W0 // 0 + add.i32 $W0,@Kxx[$j],@MSG[2] + sha1su0 @MSG[0],@MSG[1],@MSG[2] +___ +for ($j=0,$i=1;$i<20-3;$i++) { +my $f=("c","p","m","p")[$i/5]; +$code.=<<___; + sha1h $E0,$ABCD // $i + sha1$f $ABCD,$E1,$W1 + add.i32 $W1,@Kxx[$j],@MSG[3] + sha1su1 @MSG[0],@MSG[3] +___ +$code.=<<___ if ($i<20-4); + sha1su0 @MSG[1],@MSG[2],@MSG[3] +___ + ($E0,$E1)=($E1,$E0); ($W0,$W1)=($W1,$W0); + push(@MSG,shift(@MSG)); $j++ if ((($i+3)%5)==0); +} +$code.=<<___; + sha1h $E0,$ABCD // $i + sha1p $ABCD,$E1,$W1 + add.i32 $W1,@Kxx[$j],@MSG[3] + + sha1h $E1,$ABCD // 18 + sha1p $ABCD,$E0,$W0 + + sha1h $E0,$ABCD // 19 + sha1p $ABCD,$E1,$W1 + + add.i32 $E,$E,$E0 + add.i32 $ABCD,$ABCD,$ABCD_SAVE + + cbnz $num,.Loop_hw + + st1.32 {$ABCD},[$ctx],#16 + st1.32 {$E}[0],[$ctx] + + ldr x29,[sp],#16 + ret +.size sha1_block_armv8,.-sha1_block_armv8 +.align 6 +.Lconst: +.long 0x5a827999,0x5a827999,0x5a827999,0x5a827999 //K_00_19 +.long 0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1 //K_20_39 +.long 0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc //K_40_59 +.long 0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6 //K_60_79 +.LOPENSSL_armcap_P: +.quad OPENSSL_armcap_P-. +.asciz "SHA1 block transform for ARMv8, CRYPTOGAMS by " +.align 2 +.comm OPENSSL_armcap_P,4,4 +___ +}}} + +{ my %opcode = ( + "sha1c" => 0x5e000000, "sha1p" => 0x5e001000, + "sha1m" => 0x5e002000, "sha1su0" => 0x5e003000, + "sha1h" => 0x5e280800, "sha1su1" => 0x5e281800 ); + + sub unsha1 { + my ($mnemonic,$arg)=@_; + + $arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)[^,]*(?:,\s*[qv]([0-9]+))?/o + && + sprintf ".inst\t0x%08x\t//%s %s", + $opcode{$mnemonic}|$1|($2<<5)|($3<<16), + $mnemonic,$arg; + } +} + +foreach(split("\n",$code)) { + + s/\`([^\`]*)\`/eval($1)/geo; + + s/\b(sha1\w+)\s+([qv].*)/unsha1($1,$2)/geo; + + s/\.\w?32\b//o and s/\.16b/\.4s/go; + m/(ld|st)1[^\[]+\[0\]/o and s/\.4s/\.s/go; + + print $_,"\n"; +} + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-x86_64.pl new file mode 100644 index 00000000..124034dc --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha1-x86_64.pl @@ -0,0 +1,2067 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# sha1_block procedure for x86_64. +# +# It was brought to my attention that on EM64T compiler-generated code +# was far behind 32-bit assembler implementation. This is unlike on +# Opteron where compiler-generated code was only 15% behind 32-bit +# assembler, which originally made it hard to motivate the effort. +# There was suggestion to mechanically translate 32-bit code, but I +# dismissed it, reasoning that x86_64 offers enough register bank +# capacity to fully utilize SHA-1 parallelism. Therefore this fresh +# implementation:-) However! While 64-bit code does perform better +# on Opteron, I failed to beat 32-bit assembler on EM64T core. Well, +# x86_64 does offer larger *addressable* bank, but out-of-order core +# reaches for even more registers through dynamic aliasing, and EM64T +# core must have managed to run-time optimize even 32-bit code just as +# good as 64-bit one. Performance improvement is summarized in the +# following table: +# +# gcc 3.4 32-bit asm cycles/byte +# Opteron +45% +20% 6.8 +# Xeon P4 +65% +0% 9.9 +# Core2 +60% +10% 7.0 + +# August 2009. +# +# The code was revised to minimize code size and to maximize +# "distance" between instructions producing input to 'lea' +# instruction and the 'lea' instruction itself, which is essential +# for Intel Atom core. + +# October 2010. +# +# Add SSSE3, Supplemental[!] SSE3, implementation. The idea behind it +# is to offload message schedule denoted by Wt in NIST specification, +# or Xupdate in OpenSSL source, to SIMD unit. See sha1-586.pl module +# for background and implementation details. The only difference from +# 32-bit code is that 64-bit code doesn't have to spill @X[] elements +# to free temporary registers. + +# April 2011. +# +# Add AVX code path. See sha1-586.pl for further information. + +# May 2013. +# +# Add AVX2+BMI code path. Initial attempt (utilizing BMI instructions +# and loading pair of consecutive blocks to 256-bit %ymm registers) +# did not provide impressive performance improvement till a crucial +# hint regarding the number of Xupdate iterations to pre-compute in +# advance was provided by Ilya Albrekht of Intel Corp. + +# March 2014. +# +# Add support for Intel SHA Extensions. + +###################################################################### +# Current performance is summarized in following table. Numbers are +# CPU clock cycles spent to process single byte (less is better). +# +# x86_64 SSSE3 AVX[2] +# P4 9.05 - +# Opteron 6.26 - +# Core2 6.55 6.05/+8% - +# Westmere 6.73 5.30/+27% - +# Sandy Bridge 7.70 6.10/+26% 4.99/+54% +# Ivy Bridge 6.06 4.67/+30% 4.60/+32% +# Haswell 5.45 4.15/+31% 3.57/+53% +# Bulldozer 9.11 5.95/+53% +# VIA Nano 9.32 7.15/+30% +# Atom 10.3 9.17/+12% +# Silvermont 13.1(*) 9.37/+40% +# +# (*) obviously suboptimal result, nothing was done about it, +# because SSSE3 code is compiled unconditionally; + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.19) + ($1>=2.22); +} + +if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.09) + ($1>=2.10); +} + +if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $avx = ($1>=10) + ($1>=11); +} + +if (!$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([2-9]\.[0-9]+)/) { + $avx = ($2>=3.0) + ($2>3.0); +} + +$shaext=0; ### set to zero if compiling for 1.0.1 +$avx=1 if (!$shaext && $avx); + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +$ctx="%rdi"; # 1st arg +$inp="%rsi"; # 2nd arg +$num="%rdx"; # 3rd arg + +# reassign arguments in order to produce more compact code +$ctx="%r8"; +$inp="%r9"; +$num="%r10"; + +$t0="%eax"; +$t1="%ebx"; +$t2="%ecx"; +@xi=("%edx","%ebp","%r14d"); +$A="%esi"; +$B="%edi"; +$C="%r11d"; +$D="%r12d"; +$E="%r13d"; + +@V=($A,$B,$C,$D,$E); + +sub BODY_00_19 { +my ($i,$a,$b,$c,$d,$e)=@_; +my $j=$i+1; +$code.=<<___ if ($i==0); + mov `4*$i`($inp),$xi[0] + bswap $xi[0] +___ +$code.=<<___ if ($i<15); + mov `4*$j`($inp),$xi[1] + mov $d,$t0 + mov $xi[0],`4*$i`(%rsp) + mov $a,$t2 + bswap $xi[1] + xor $c,$t0 + rol \$5,$t2 + and $b,$t0 + lea 0x5a827999($xi[0],$e),$e + add $t2,$e + xor $d,$t0 + rol \$30,$b + add $t0,$e +___ +$code.=<<___ if ($i>=15); + xor `4*($j%16)`(%rsp),$xi[1] + mov $d,$t0 + mov $xi[0],`4*($i%16)`(%rsp) + mov $a,$t2 + xor `4*(($j+2)%16)`(%rsp),$xi[1] + xor $c,$t0 + rol \$5,$t2 + xor `4*(($j+8)%16)`(%rsp),$xi[1] + and $b,$t0 + lea 0x5a827999($xi[0],$e),$e + rol \$30,$b + xor $d,$t0 + add $t2,$e + rol \$1,$xi[1] + add $t0,$e +___ +push(@xi,shift(@xi)); +} + +sub BODY_20_39 { +my ($i,$a,$b,$c,$d,$e)=@_; +my $j=$i+1; +my $K=($i<40)?0x6ed9eba1:0xca62c1d6; +$code.=<<___ if ($i<79); + xor `4*($j%16)`(%rsp),$xi[1] + mov $b,$t0 + `"mov $xi[0],".4*($i%16)."(%rsp)" if ($i<72)` + mov $a,$t2 + xor `4*(($j+2)%16)`(%rsp),$xi[1] + xor $d,$t0 + rol \$5,$t2 + xor `4*(($j+8)%16)`(%rsp),$xi[1] + lea $K($xi[0],$e),$e + xor $c,$t0 + add $t2,$e + rol \$30,$b + add $t0,$e + rol \$1,$xi[1] +___ +$code.=<<___ if ($i==79); + mov $b,$t0 + mov $a,$t2 + xor $d,$t0 + lea $K($xi[0],$e),$e + rol \$5,$t2 + xor $c,$t0 + add $t2,$e + rol \$30,$b + add $t0,$e +___ +push(@xi,shift(@xi)); +} + +sub BODY_40_59 { +my ($i,$a,$b,$c,$d,$e)=@_; +my $j=$i+1; +$code.=<<___; + xor `4*($j%16)`(%rsp),$xi[1] + mov $d,$t0 + mov $xi[0],`4*($i%16)`(%rsp) + mov $d,$t1 + xor `4*(($j+2)%16)`(%rsp),$xi[1] + and $c,$t0 + mov $a,$t2 + xor `4*(($j+8)%16)`(%rsp),$xi[1] + lea 0x8f1bbcdc($xi[0],$e),$e + xor $c,$t1 + rol \$5,$t2 + add $t0,$e + rol \$1,$xi[1] + and $b,$t1 + add $t2,$e + rol \$30,$b + add $t1,$e +___ +push(@xi,shift(@xi)); +} + +$code.=<<___; +.text +.extern OPENSSL_ia32cap_P + +.globl sha1_block_data_order +.type sha1_block_data_order,\@function,3 +.align 16 +sha1_block_data_order: + mov OPENSSL_ia32cap_P+0(%rip),%r9d + mov OPENSSL_ia32cap_P+4(%rip),%r8d + mov OPENSSL_ia32cap_P+8(%rip),%r10d + test \$`1<<9`,%r8d # check SSSE3 bit + jz .Lialu +___ +$code.=<<___ if ($shaext); + test \$`1<<29`,%r10d # check SHA bit + jnz _shaext_shortcut +___ +$code.=<<___ if ($avx>1); + and \$`1<<3|1<<5|1<<8`,%r10d # check AVX2+BMI1+BMI2 + cmp \$`1<<3|1<<5|1<<8`,%r10d + je _avx2_shortcut +___ +$code.=<<___ if ($avx); + and \$`1<<28`,%r8d # mask AVX bit + and \$`1<<30`,%r9d # mask "Intel CPU" bit + or %r9d,%r8d + cmp \$`1<<28|1<<30`,%r8d + je _avx_shortcut +___ +$code.=<<___; + jmp _ssse3_shortcut + +.align 16 +.Lialu: + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + mov %rdi,$ctx # reassigned argument + sub \$`8+16*4`,%rsp + mov %rsi,$inp # reassigned argument + and \$-64,%rsp + mov %rdx,$num # reassigned argument + mov %rax,`16*4`(%rsp) +.Lprologue: + + mov 0($ctx),$A + mov 4($ctx),$B + mov 8($ctx),$C + mov 12($ctx),$D + mov 16($ctx),$E + jmp .Lloop + +.align 16 +.Lloop: +___ +for($i=0;$i<20;$i++) { &BODY_00_19($i,@V); unshift(@V,pop(@V)); } +for(;$i<40;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); } +for(;$i<60;$i++) { &BODY_40_59($i,@V); unshift(@V,pop(@V)); } +for(;$i<80;$i++) { &BODY_20_39($i,@V); unshift(@V,pop(@V)); } +$code.=<<___; + add 0($ctx),$A + add 4($ctx),$B + add 8($ctx),$C + add 12($ctx),$D + add 16($ctx),$E + mov $A,0($ctx) + mov $B,4($ctx) + mov $C,8($ctx) + mov $D,12($ctx) + mov $E,16($ctx) + + sub \$1,$num + lea `16*4`($inp),$inp + jnz .Lloop + + mov `16*4`(%rsp),%rsi + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lepilogue: + ret +.size sha1_block_data_order,.-sha1_block_data_order +___ +if ($shaext) {{{ +###################################################################### +# Intel SHA Extensions implementation of SHA1 update function. +# +my ($ctx,$inp,$num)=("%rdi","%rsi","%rdx"); +my ($ABCD,$E,$E_,$BSWAP,$ABCD_SAVE,$E_SAVE)=map("%xmm$_",(0..3,8,9)); +my @MSG=map("%xmm$_",(4..7)); + +$code.=<<___; +.type sha1_block_data_order_shaext,\@function,3 +.align 32 +sha1_block_data_order_shaext: +_shaext_shortcut: +___ +$code.=<<___ if ($win64); + lea `-8-4*16`(%rsp),%rsp + movaps %xmm6,-8-4*16(%rax) + movaps %xmm7,-8-3*16(%rax) + movaps %xmm8,-8-2*16(%rax) + movaps %xmm9,-8-1*16(%rax) +.Lprologue_shaext: +___ +$code.=<<___; + movdqu ($ctx),$ABCD + movd 16($ctx),$E + movdqa K_XX_XX+0xa0(%rip),$BSWAP # byte-n-word swap + + movdqu ($inp),@MSG[0] + pshufd \$0b00011011,$ABCD,$ABCD # flip word order + movdqu 0x10($inp),@MSG[1] + pshufd \$0b00011011,$E,$E # flip word order + movdqu 0x20($inp),@MSG[2] + pshufb $BSWAP,@MSG[0] + movdqu 0x30($inp),@MSG[3] + pshufb $BSWAP,@MSG[1] + pshufb $BSWAP,@MSG[2] + movdqa $E,$E_SAVE # offload $E + pshufb $BSWAP,@MSG[3] + jmp .Loop_shaext + +.align 16 +.Loop_shaext: + dec $num + lea 0x40($inp),%rax # next input block + paddd @MSG[0],$E + cmovne %rax,$inp + movdqa $ABCD,$ABCD_SAVE # offload $ABCD +___ +for($i=0;$i<20-4;$i+=2) { +$code.=<<___; + sha1msg1 @MSG[1],@MSG[0] + movdqa $ABCD,$E_ + sha1rnds4 \$`int($i/5)`,$E,$ABCD # 0-3... + sha1nexte @MSG[1],$E_ + pxor @MSG[2],@MSG[0] + sha1msg1 @MSG[2],@MSG[1] + sha1msg2 @MSG[3],@MSG[0] + + movdqa $ABCD,$E + sha1rnds4 \$`int(($i+1)/5)`,$E_,$ABCD + sha1nexte @MSG[2],$E + pxor @MSG[3],@MSG[1] + sha1msg2 @MSG[0],@MSG[1] +___ + push(@MSG,shift(@MSG)); push(@MSG,shift(@MSG)); +} +$code.=<<___; + movdqu ($inp),@MSG[0] + movdqa $ABCD,$E_ + sha1rnds4 \$3,$E,$ABCD # 64-67 + sha1nexte @MSG[1],$E_ + movdqu 0x10($inp),@MSG[1] + pshufb $BSWAP,@MSG[0] + + movdqa $ABCD,$E + sha1rnds4 \$3,$E_,$ABCD # 68-71 + sha1nexte @MSG[2],$E + movdqu 0x20($inp),@MSG[2] + pshufb $BSWAP,@MSG[1] + + movdqa $ABCD,$E_ + sha1rnds4 \$3,$E,$ABCD # 72-75 + sha1nexte @MSG[3],$E_ + movdqu 0x30($inp),@MSG[3] + pshufb $BSWAP,@MSG[2] + + movdqa $ABCD,$E + sha1rnds4 \$3,$E_,$ABCD # 76-79 + sha1nexte $E_SAVE,$E + pshufb $BSWAP,@MSG[3] + + paddd $ABCD_SAVE,$ABCD + movdqa $E,$E_SAVE # offload $E + + jnz .Loop_shaext + + pshufd \$0b00011011,$ABCD,$ABCD + pshufd \$0b00011011,$E,$E + movdqu $ABCD,($ctx) + movd $E,16($ctx) +___ +$code.=<<___ if ($win64); + movaps -8-4*16(%rax),%xmm6 + movaps -8-3*16(%rax),%xmm7 + movaps -8-2*16(%rax),%xmm8 + movaps -8-1*16(%rax),%xmm9 + mov %rax,%rsp +.Lepilogue_shaext: +___ +$code.=<<___; + ret +.size sha1_block_data_order_shaext,.-sha1_block_data_order_shaext +___ +}}} +{{{ +my $Xi=4; +my @X=map("%xmm$_",(4..7,0..3)); +my @Tx=map("%xmm$_",(8..10)); +my $Kx="%xmm11"; +my @V=($A,$B,$C,$D,$E)=("%eax","%ebx","%ecx","%edx","%ebp"); # size optimization +my @T=("%esi","%edi"); +my $j=0; +my $rx=0; +my $K_XX_XX="%r11"; + +my $_rol=sub { &rol(@_) }; +my $_ror=sub { &ror(@_) }; + +{ my $sn; +sub align32() { + ++$sn; +$code.=<<___; + jmp .Lalign32_$sn # see "Decoded ICache" in manual +.align 32 +.Lalign32_$sn: +___ +} +} + +$code.=<<___; +.type sha1_block_data_order_ssse3,\@function,3 +.align 16 +sha1_block_data_order_ssse3: +_ssse3_shortcut: + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 # redundant, done to share Win64 SE handler + push %r14 + lea `-64-($win64?6*16:0)`(%rsp),%rsp +___ +$code.=<<___ if ($win64); + movaps %xmm6,-40-6*16(%rax) + movaps %xmm7,-40-5*16(%rax) + movaps %xmm8,-40-4*16(%rax) + movaps %xmm9,-40-3*16(%rax) + movaps %xmm10,-40-2*16(%rax) + movaps %xmm11,-40-1*16(%rax) +.Lprologue_ssse3: +___ +$code.=<<___; + mov %rax,%r14 # original %rsp + and \$-64,%rsp + mov %rdi,$ctx # reassigned argument + mov %rsi,$inp # reassigned argument + mov %rdx,$num # reassigned argument + + shl \$6,$num + add $inp,$num + lea K_XX_XX+64(%rip),$K_XX_XX + + mov 0($ctx),$A # load context + mov 4($ctx),$B + mov 8($ctx),$C + mov 12($ctx),$D + mov $B,@T[0] # magic seed + mov 16($ctx),$E + mov $C,@T[1] + xor $D,@T[1] + and @T[1],@T[0] + + movdqa 64($K_XX_XX),@X[2] # pbswap mask + movdqa -64($K_XX_XX),@Tx[1] # K_00_19 + movdqu 0($inp),@X[-4&7] # load input to %xmm[0-3] + movdqu 16($inp),@X[-3&7] + movdqu 32($inp),@X[-2&7] + movdqu 48($inp),@X[-1&7] + pshufb @X[2],@X[-4&7] # byte swap + pshufb @X[2],@X[-3&7] + pshufb @X[2],@X[-2&7] + add \$64,$inp + paddd @Tx[1],@X[-4&7] # add K_00_19 + pshufb @X[2],@X[-1&7] + paddd @Tx[1],@X[-3&7] + paddd @Tx[1],@X[-2&7] + movdqa @X[-4&7],0(%rsp) # X[]+K xfer to IALU + psubd @Tx[1],@X[-4&7] # restore X[] + movdqa @X[-3&7],16(%rsp) + psubd @Tx[1],@X[-3&7] + movdqa @X[-2&7],32(%rsp) + psubd @Tx[1],@X[-2&7] + jmp .Loop_ssse3 +___ + +sub AUTOLOAD() # thunk [simplified] 32-bit style perlasm +{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; + my $arg = pop; + $arg = "\$$arg" if ($arg*1 eq $arg); + $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n"; +} + +sub Xupdate_ssse3_16_31() # recall that $Xi starts wtih 4 +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 40 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); # ror + &pshufd (@X[0],@X[-4&7],0xee); # was &movdqa (@X[0],@X[-3&7]); + eval(shift(@insns)); + &movdqa (@Tx[0],@X[-1&7]); + &paddd (@Tx[1],@X[-1&7]); + eval(shift(@insns)); + eval(shift(@insns)); + + &punpcklqdq(@X[0],@X[-3&7]); # compose "X[-14]" in "X[0]", was &palignr(@X[0],@X[-4&7],8); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + &psrldq (@Tx[0],4); # "X[-3]", 3 dwords + eval(shift(@insns)); + eval(shift(@insns)); + + &pxor (@X[0],@X[-4&7]); # "X[0]"^="X[-16]" + eval(shift(@insns)); + eval(shift(@insns)); # ror + &pxor (@Tx[0],@X[-2&7]); # "X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &pxor (@X[0],@Tx[0]); # "X[0]"^="X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); # rol + &movdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + + &movdqa (@Tx[2],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + &movdqa (@Tx[0],@X[0]); + eval(shift(@insns)); + + &pslldq (@Tx[2],12); # "X[0]"<<96, extract one dword + &paddd (@X[0],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + + &psrld (@Tx[0],31); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + &movdqa (@Tx[1],@Tx[2]); + eval(shift(@insns)); + eval(shift(@insns)); + + &psrld (@Tx[2],30); + eval(shift(@insns)); + eval(shift(@insns)); # ror + &por (@X[0],@Tx[0]); # "X[0]"<<<=1 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &pslld (@Tx[1],2); + &pxor (@X[0],@Tx[2]); + eval(shift(@insns)); + &movdqa (@Tx[2],eval(2*16*(($Xi)/5)-64)."($K_XX_XX)"); # K_XX_XX + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + + &pxor (@X[0],@Tx[1]); # "X[0]"^=("X[0]">>96)<<<2 + &pshufd (@Tx[1],@X[-1&7],0xee) if ($Xi==7); # was &movdqa (@Tx[0],@X[-1&7]) in Xupdate_ssse3_32_79 + + foreach (@insns) { eval; } # remaining instructions [if any] + + $Xi++; push(@X,shift(@X)); # "rotate" X[] + push(@Tx,shift(@Tx)); +} + +sub Xupdate_ssse3_32_79() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 to 44 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)) if ($Xi==8); + &pxor (@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]" + eval(shift(@insns)) if ($Xi==8); + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)) if (@insns[1] =~ /_ror/); + eval(shift(@insns)) if (@insns[0] =~ /_ror/); + &punpcklqdq(@Tx[0],@X[-1&7]); # compose "X[-6]", was &palignr(@Tx[0],@X[-2&7],8); + eval(shift(@insns)); + eval(shift(@insns)); # rol + + &pxor (@X[0],@X[-7&7]); # "X[0]"^="X[-28]" + eval(shift(@insns)); + eval(shift(@insns)); + if ($Xi%5) { + &movdqa (@Tx[2],@Tx[1]);# "perpetuate" K_XX_XX... + } else { # ... or load next one + &movdqa (@Tx[2],eval(2*16*($Xi/5)-64)."($K_XX_XX)"); + } + eval(shift(@insns)); # ror + &paddd (@Tx[1],@X[-1&7]); + eval(shift(@insns)); + + &pxor (@X[0],@Tx[0]); # "X[0]"^="X[-6]" + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)) if (@insns[0] =~ /_ror/); + + &movdqa (@Tx[0],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU + eval(shift(@insns)); # ror + eval(shift(@insns)); + eval(shift(@insns)); # body_20_39 + + &pslld (@X[0],2); + eval(shift(@insns)); + eval(shift(@insns)); + &psrld (@Tx[0],30); + eval(shift(@insns)) if (@insns[0] =~ /_rol/);# rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + + &por (@X[0],@Tx[0]); # "X[0]"<<<=2 + eval(shift(@insns)); + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)) if (@insns[1] =~ /_rol/); + eval(shift(@insns)) if (@insns[0] =~ /_rol/); + &pshufd(@Tx[1],@X[-1&7],0xee) if ($Xi<19); # was &movdqa (@Tx[1],@X[0]) + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + + foreach (@insns) { eval; } # remaining instructions + + $Xi++; push(@X,shift(@X)); # "rotate" X[] + push(@Tx,shift(@Tx)); +} + +sub Xuplast_ssse3_80() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@Tx[1],@X[-1&7]); + eval(shift(@insns)); + eval(shift(@insns)); + + &movdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer IALU + + foreach (@insns) { eval; } # remaining instructions + + &cmp ($inp,$num); + &je (".Ldone_ssse3"); + + unshift(@Tx,pop(@Tx)); + + &movdqa (@X[2],"64($K_XX_XX)"); # pbswap mask + &movdqa (@Tx[1],"-64($K_XX_XX)"); # K_00_19 + &movdqu (@X[-4&7],"0($inp)"); # load input + &movdqu (@X[-3&7],"16($inp)"); + &movdqu (@X[-2&7],"32($inp)"); + &movdqu (@X[-1&7],"48($inp)"); + &pshufb (@X[-4&7],@X[2]); # byte swap + &add ($inp,64); + + $Xi=0; +} + +sub Xloop_ssse3() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &pshufb (@X[($Xi-3)&7],@X[2]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@X[($Xi-4)&7],@Tx[1]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa (eval(16*$Xi)."(%rsp)",@X[($Xi-4)&7]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &psubd (@X[($Xi-4)&7],@Tx[1]); + + foreach (@insns) { eval; } + $Xi++; +} + +sub Xtail_ssse3() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + foreach (@insns) { eval; } +} + +sub body_00_19 () { # ((c^d)&b)^d + # on start @T[0]=(c^d)&b + return &body_20_39() if ($rx==19); $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + '&$_ror ($b,$j?7:2)', # $b>>>2 + '&xor (@T[0],$d)', + '&mov (@T[1],$a)', # $b for next round + + '&add ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer + '&xor ($b,$c)', # $c^$d for next round + + '&$_rol ($a,5)', + '&add ($e,@T[0])', + '&and (@T[1],$b)', # ($b&($c^$d)) for next round + + '&xor ($b,$c)', # restore $b + '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} + +sub body_20_39 () { # b^d^c + # on entry @T[0]=b^d + return &body_40_59() if ($rx==39); $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + '&add ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer + '&xor (@T[0],$d) if($j==19);'. + '&xor (@T[0],$c) if($j> 19)', # ($b^$d^$c) + '&mov (@T[1],$a)', # $b for next round + + '&$_rol ($a,5)', + '&add ($e,@T[0])', + '&xor (@T[1],$c) if ($j< 79)', # $b^$d for next round + + '&$_ror ($b,7)', # $b>>>2 + '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} + +sub body_40_59 () { # ((b^c)&(c^d))^c + # on entry @T[0]=(b^c), (c^=d) + $rx++; + ( + '($a,$b,$c,$d,$e)=@V;'. + '&add ($e,eval(4*($j&15))."(%rsp)")', # X[]+K xfer + '&and (@T[0],$c) if ($j>=40)', # (b^c)&(c^d) + '&xor ($c,$d) if ($j>=40)', # restore $c + + '&$_ror ($b,7)', # $b>>>2 + '&mov (@T[1],$a)', # $b for next round + '&xor (@T[0],$c)', + + '&$_rol ($a,5)', + '&add ($e,@T[0])', + '&xor (@T[1],$c) if ($j==59);'. + '&xor (@T[1],$b) if ($j< 59)', # b^c for next round + + '&xor ($b,$c) if ($j< 59)', # c^d for next round + '&add ($e,$a);' .'$j++; unshift(@V,pop(@V)); unshift(@T,pop(@T));' + ); +} +$code.=<<___; +.align 16 +.Loop_ssse3: +___ + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_16_31(\&body_00_19); + &Xupdate_ssse3_32_79(\&body_00_19); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_40_59); + &Xupdate_ssse3_32_79(\&body_20_39); + &Xuplast_ssse3_80(\&body_20_39); # can jump to "done" + + $saved_j=$j; @saved_V=@V; + + &Xloop_ssse3(\&body_20_39); + &Xloop_ssse3(\&body_20_39); + &Xloop_ssse3(\&body_20_39); + +$code.=<<___; + add 0($ctx),$A # update context + add 4($ctx),@T[0] + add 8($ctx),$C + add 12($ctx),$D + mov $A,0($ctx) + add 16($ctx),$E + mov @T[0],4($ctx) + mov @T[0],$B # magic seed + mov $C,8($ctx) + mov $C,@T[1] + mov $D,12($ctx) + xor $D,@T[1] + mov $E,16($ctx) + and @T[1],@T[0] + jmp .Loop_ssse3 + +.align 16 +.Ldone_ssse3: +___ + $j=$saved_j; @V=@saved_V; + + &Xtail_ssse3(\&body_20_39); + &Xtail_ssse3(\&body_20_39); + &Xtail_ssse3(\&body_20_39); + +$code.=<<___; + add 0($ctx),$A # update context + add 4($ctx),@T[0] + add 8($ctx),$C + mov $A,0($ctx) + add 12($ctx),$D + mov @T[0],4($ctx) + add 16($ctx),$E + mov $C,8($ctx) + mov $D,12($ctx) + mov $E,16($ctx) +___ +$code.=<<___ if ($win64); + movaps -40-6*16(%r14),%xmm6 + movaps -40-5*16(%r14),%xmm7 + movaps -40-4*16(%r14),%xmm8 + movaps -40-3*16(%r14),%xmm9 + movaps -40-2*16(%r14),%xmm10 + movaps -40-1*16(%r14),%xmm11 +___ +$code.=<<___; + lea (%r14),%rsi + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lepilogue_ssse3: + ret +.size sha1_block_data_order_ssse3,.-sha1_block_data_order_ssse3 +___ + +if ($avx) { +$Xi=4; # reset variables +@X=map("%xmm$_",(4..7,0..3)); +@Tx=map("%xmm$_",(8..10)); +$j=0; +$rx=0; + +my $done_avx_label=".Ldone_avx"; + +my $_rol=sub { &shld(@_[0],@_) }; +my $_ror=sub { &shrd(@_[0],@_) }; + +$code.=<<___; +.type sha1_block_data_order_avx,\@function,3 +.align 16 +sha1_block_data_order_avx: +_avx_shortcut: + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 # redundant, done to share Win64 SE handler + push %r14 + lea `-64-($win64?6*16:0)`(%rsp),%rsp + vzeroupper +___ +$code.=<<___ if ($win64); + vmovaps %xmm6,-40-6*16(%rax) + vmovaps %xmm7,-40-5*16(%rax) + vmovaps %xmm8,-40-4*16(%rax) + vmovaps %xmm9,-40-3*16(%rax) + vmovaps %xmm10,-40-2*16(%rax) + vmovaps %xmm11,-40-1*16(%rax) +.Lprologue_avx: +___ +$code.=<<___; + mov %rax,%r14 # original %rsp + and \$-64,%rsp + mov %rdi,$ctx # reassigned argument + mov %rsi,$inp # reassigned argument + mov %rdx,$num # reassigned argument + + shl \$6,$num + add $inp,$num + lea K_XX_XX+64(%rip),$K_XX_XX + + mov 0($ctx),$A # load context + mov 4($ctx),$B + mov 8($ctx),$C + mov 12($ctx),$D + mov $B,@T[0] # magic seed + mov 16($ctx),$E + mov $C,@T[1] + xor $D,@T[1] + and @T[1],@T[0] + + vmovdqa 64($K_XX_XX),@X[2] # pbswap mask + vmovdqa -64($K_XX_XX),$Kx # K_00_19 + vmovdqu 0($inp),@X[-4&7] # load input to %xmm[0-3] + vmovdqu 16($inp),@X[-3&7] + vmovdqu 32($inp),@X[-2&7] + vmovdqu 48($inp),@X[-1&7] + vpshufb @X[2],@X[-4&7],@X[-4&7] # byte swap + add \$64,$inp + vpshufb @X[2],@X[-3&7],@X[-3&7] + vpshufb @X[2],@X[-2&7],@X[-2&7] + vpshufb @X[2],@X[-1&7],@X[-1&7] + vpaddd $Kx,@X[-4&7],@X[0] # add K_00_19 + vpaddd $Kx,@X[-3&7],@X[1] + vpaddd $Kx,@X[-2&7],@X[2] + vmovdqa @X[0],0(%rsp) # X[]+K xfer to IALU + vmovdqa @X[1],16(%rsp) + vmovdqa @X[2],32(%rsp) + jmp .Loop_avx +___ + +sub Xupdate_avx_16_31() # recall that $Xi starts wtih 4 +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 40 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + &vpalignr(@X[0],@X[-3&7],@X[-4&7],8); # compose "X[-14]" in "X[0]" + eval(shift(@insns)); + eval(shift(@insns)); + + &vpaddd (@Tx[1],$Kx,@X[-1&7]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrldq(@Tx[0],@X[-1&7],4); # "X[-3]", 3 dwords + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"^="X[-16]" + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@Tx[0],@Tx[0],@X[-2&7]); # "X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + &vmovdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrld (@Tx[0],@X[0],31); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpslldq(@Tx[2],@X[0],12); # "X[0]"<<96, extract one dword + &vpaddd (@X[0],@X[0],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrld (@Tx[1],@Tx[2],30); + &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=1 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpslld (@Tx[2],@Tx[2],2); + &vpxor (@X[0],@X[0],@Tx[1]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@Tx[2]); # "X[0]"^=("X[0]">>96)<<<2 + eval(shift(@insns)); + eval(shift(@insns)); + &vmovdqa ($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)") if ($Xi%5==0); # K_XX_XX + eval(shift(@insns)); + eval(shift(@insns)); + + + foreach (@insns) { eval; } # remaining instructions [if any] + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xupdate_avx_32_79() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 to 44 instructions + my ($a,$b,$c,$d,$e); + + &vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8); # compose "X[-6]" + &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]" + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + + &vpxor (@X[0],@X[0],@X[-7&7]); # "X[0]"^="X[-28]" + eval(shift(@insns)); + eval(shift(@insns)) if (@insns[0] !~ /&ro[rl]/); + &vpaddd (@Tx[1],$Kx,@X[-1&7]); + &vmovdqa ($Kx,eval(2*16*($Xi/5)-64)."($K_XX_XX)") if ($Xi%5==0); + eval(shift(@insns)); # ror + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-6]" + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + + &vpsrld (@Tx[0],@X[0],30); + &vmovdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + eval(shift(@insns)); + + &vpslld (@X[0],@X[0],2); + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # ror + eval(shift(@insns)); + + &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=2 + eval(shift(@insns)); # body_20_39 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # rol + eval(shift(@insns)); + + foreach (@insns) { eval; } # remaining instructions + + $Xi++; push(@X,shift(@X)); # "rotate" X[] +} + +sub Xuplast_avx_80() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + &vpaddd (@Tx[1],$Kx,@X[-1&7]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vmovdqa (eval(16*(($Xi-1)&3))."(%rsp)",@Tx[1]); # X[]+K xfer IALU + + foreach (@insns) { eval; } # remaining instructions + + &cmp ($inp,$num); + &je ($done_avx_label); + + &vmovdqa(@X[2],"64($K_XX_XX)"); # pbswap mask + &vmovdqa($Kx,"-64($K_XX_XX)"); # K_00_19 + &vmovdqu(@X[-4&7],"0($inp)"); # load input + &vmovdqu(@X[-3&7],"16($inp)"); + &vmovdqu(@X[-2&7],"32($inp)"); + &vmovdqu(@X[-1&7],"48($inp)"); + &vpshufb(@X[-4&7],@X[-4&7],@X[2]); # byte swap + &add ($inp,64); + + $Xi=0; +} + +sub Xloop_avx() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + eval(shift(@insns)); + eval(shift(@insns)); + &vpshufb(@X[($Xi-3)&7],@X[($Xi-3)&7],@X[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddd (@X[$Xi&7],@X[($Xi-4)&7],$Kx); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vmovdqa(eval(16*$Xi)."(%rsp)",@X[$Xi&7]); # X[]+K xfer to IALU + eval(shift(@insns)); + eval(shift(@insns)); + + foreach (@insns) { eval; } + $Xi++; +} + +sub Xtail_avx() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + foreach (@insns) { eval; } +} + +$code.=<<___; +.align 16 +.Loop_avx: +___ + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_16_31(\&body_00_19); + &Xupdate_avx_32_79(\&body_00_19); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_20_39); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_40_59); + &Xupdate_avx_32_79(\&body_20_39); + &Xuplast_avx_80(\&body_20_39); # can jump to "done" + + $saved_j=$j; @saved_V=@V; + + &Xloop_avx(\&body_20_39); + &Xloop_avx(\&body_20_39); + &Xloop_avx(\&body_20_39); + +$code.=<<___; + add 0($ctx),$A # update context + add 4($ctx),@T[0] + add 8($ctx),$C + add 12($ctx),$D + mov $A,0($ctx) + add 16($ctx),$E + mov @T[0],4($ctx) + mov @T[0],$B # magic seed + mov $C,8($ctx) + mov $C,@T[1] + mov $D,12($ctx) + xor $D,@T[1] + mov $E,16($ctx) + and @T[1],@T[0] + jmp .Loop_avx + +.align 16 +$done_avx_label: +___ + $j=$saved_j; @V=@saved_V; + + &Xtail_avx(\&body_20_39); + &Xtail_avx(\&body_20_39); + &Xtail_avx(\&body_20_39); + +$code.=<<___; + vzeroupper + + add 0($ctx),$A # update context + add 4($ctx),@T[0] + add 8($ctx),$C + mov $A,0($ctx) + add 12($ctx),$D + mov @T[0],4($ctx) + add 16($ctx),$E + mov $C,8($ctx) + mov $D,12($ctx) + mov $E,16($ctx) +___ +$code.=<<___ if ($win64); + movaps -40-6*16(%r14),%xmm6 + movaps -40-5*16(%r14),%xmm7 + movaps -40-4*16(%r14),%xmm8 + movaps -40-3*16(%r14),%xmm9 + movaps -40-2*16(%r14),%xmm10 + movaps -40-1*16(%r14),%xmm11 +___ +$code.=<<___; + lea (%r14),%rsi + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lepilogue_avx: + ret +.size sha1_block_data_order_avx,.-sha1_block_data_order_avx +___ + +if ($avx>1) { +use integer; +$Xi=4; # reset variables +@X=map("%ymm$_",(4..7,0..3)); +@Tx=map("%ymm$_",(8..10)); +$Kx="%ymm11"; +$j=0; + +my @ROTX=("%eax","%ebp","%ebx","%ecx","%edx","%esi"); +my ($a5,$t0)=("%r12d","%edi"); + +my ($A,$F,$B,$C,$D,$E)=@ROTX; +my $rx=0; +my $frame="%r13"; + +$code.=<<___; +.type sha1_block_data_order_avx2,\@function,3 +.align 16 +sha1_block_data_order_avx2: +_avx2_shortcut: + mov %rsp,%rax + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + vzeroupper +___ +$code.=<<___ if ($win64); + lea -6*16(%rsp),%rsp + vmovaps %xmm6,-40-6*16(%rax) + vmovaps %xmm7,-40-5*16(%rax) + vmovaps %xmm8,-40-4*16(%rax) + vmovaps %xmm9,-40-3*16(%rax) + vmovaps %xmm10,-40-2*16(%rax) + vmovaps %xmm11,-40-1*16(%rax) +.Lprologue_avx2: +___ +$code.=<<___; + mov %rax,%r14 # original %rsp + mov %rdi,$ctx # reassigned argument + mov %rsi,$inp # reassigned argument + mov %rdx,$num # reassigned argument + + lea -640(%rsp),%rsp + shl \$6,$num + lea 64($inp),$frame + and \$-128,%rsp + add $inp,$num + lea K_XX_XX+64(%rip),$K_XX_XX + + mov 0($ctx),$A # load context + cmp $num,$frame + cmovae $inp,$frame # next or same block + mov 4($ctx),$F + mov 8($ctx),$C + mov 12($ctx),$D + mov 16($ctx),$E + vmovdqu 64($K_XX_XX),@X[2] # pbswap mask + + vmovdqu ($inp),%xmm0 + vmovdqu 16($inp),%xmm1 + vmovdqu 32($inp),%xmm2 + vmovdqu 48($inp),%xmm3 + lea 64($inp),$inp + vinserti128 \$1,($frame),@X[-4&7],@X[-4&7] + vinserti128 \$1,16($frame),@X[-3&7],@X[-3&7] + vpshufb @X[2],@X[-4&7],@X[-4&7] + vinserti128 \$1,32($frame),@X[-2&7],@X[-2&7] + vpshufb @X[2],@X[-3&7],@X[-3&7] + vinserti128 \$1,48($frame),@X[-1&7],@X[-1&7] + vpshufb @X[2],@X[-2&7],@X[-2&7] + vmovdqu -64($K_XX_XX),$Kx # K_00_19 + vpshufb @X[2],@X[-1&7],@X[-1&7] + + vpaddd $Kx,@X[-4&7],@X[0] # add K_00_19 + vpaddd $Kx,@X[-3&7],@X[1] + vmovdqu @X[0],0(%rsp) # X[]+K xfer to IALU + vpaddd $Kx,@X[-2&7],@X[2] + vmovdqu @X[1],32(%rsp) + vpaddd $Kx,@X[-1&7],@X[3] + vmovdqu @X[2],64(%rsp) + vmovdqu @X[3],96(%rsp) +___ +for (;$Xi<8;$Xi++) { # Xupdate_avx2_16_31 + use integer; + + &vpalignr(@X[0],@X[-3&7],@X[-4&7],8); # compose "X[-14]" in "X[0]" + &vpsrldq(@Tx[0],@X[-1&7],4); # "X[-3]", 3 dwords + &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"^="X[-16]" + &vpxor (@Tx[0],@Tx[0],@X[-2&7]); # "X[-3]"^"X[-8]" + &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-3]"^"X[-8]" + &vpsrld (@Tx[0],@X[0],31); + &vmovdqu($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)") if ($Xi%5==0); # K_XX_XX + &vpslldq(@Tx[2],@X[0],12); # "X[0]"<<96, extract one dword + &vpaddd (@X[0],@X[0],@X[0]); + &vpsrld (@Tx[1],@Tx[2],30); + &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=1 + &vpslld (@Tx[2],@Tx[2],2); + &vpxor (@X[0],@X[0],@Tx[1]); + &vpxor (@X[0],@X[0],@Tx[2]); # "X[0]"^=("X[0]">>96)<<<2 + &vpaddd (@Tx[1],@X[0],$Kx); + &vmovdqu("32*$Xi(%rsp)",@Tx[1]); # X[]+K xfer to IALU + + push(@X,shift(@X)); # "rotate" X[] +} +$code.=<<___; + lea 128(%rsp),$frame + jmp .Loop_avx2 +.align 32 +.Loop_avx2: + rorx \$2,$F,$B + andn $D,$F,$t0 + and $C,$F + xor $t0,$F +___ +sub bodyx_00_19 () { # 8 instructions, 3 cycles critical path + # at start $f=(b&c)^(~b&d), $b>>>=2 + return &bodyx_20_39() if ($rx==19); $rx++; + ( + '($a,$f,$b,$c,$d,$e)=@ROTX;'. + + '&add ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'. # e+=X[i]+K + '&lea ($frame,"256($frame)") if ($j%32==31);', + '&andn ($t0,$a,$c)', # ~b&d for next round + + '&add ($e,$f)', # e+=(b&c)^(~b&d) + '&rorx ($a5,$a,27)', # a<<<5 + '&rorx ($f,$a,2)', # b>>>2 for next round + '&and ($a,$b)', # b&c for next round + + '&add ($e,$a5)', # e+=a<<<5 + '&xor ($a,$t0);'. # f=(b&c)^(~b&d) for next round + + 'unshift(@ROTX,pop(@ROTX)); $j++;' + ) +} + +sub bodyx_20_39 () { # 7 instructions, 2 cycles critical path + # on entry $f=b^c^d, $b>>>=2 + return &bodyx_40_59() if ($rx==39); $rx++; + ( + '($a,$f,$b,$c,$d,$e)=@ROTX;'. + + '&add ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'. # e+=X[i]+K + '&lea ($frame,"256($frame)") if ($j%32==31);', + + '&lea ($e,"($e,$f)")', # e+=b^c^d + '&rorx ($a5,$a,27)', # a<<<5 + '&rorx ($f,$a,2) if ($j<79)', # b>>>2 in next round + '&xor ($a,$b) if ($j<79)', # b^c for next round + + '&add ($e,$a5)', # e+=a<<<5 + '&xor ($a,$c) if ($j<79);'. # f=b^c^d for next round + + 'unshift(@ROTX,pop(@ROTX)); $j++;' + ) +} + +sub bodyx_40_59 () { # 10 instructions, 3 cycles critical path + # on entry $f=((b^c)&(c^d)), $b>>>=2 + $rx++; + ( + '($a,$f,$b,$c,$d,$e)=@ROTX;'. + + '&add ($e,((32*($j/4)+4*($j%4))%256-128)."($frame)");'. # e+=X[i]+K + '&lea ($frame,"256($frame)") if ($j%32==31);', + '&xor ($f,$c) if ($j>39)', # (b^c)&(c^d)^c + '&mov ($t0,$b) if ($j<59)', # count on zero latency + '&xor ($t0,$c) if ($j<59)', # c^d for next round + + '&lea ($e,"($e,$f)")', # e+=(b^c)&(c^d)^c + '&rorx ($a5,$a,27)', # a<<<5 + '&rorx ($f,$a,2)', # b>>>2 in next round + '&xor ($a,$b)', # b^c for next round + + '&add ($e,$a5)', # e+=a<<<5 + '&and ($a,$t0) if ($j< 59);'. # f=(b^c)&(c^d) for next round + '&xor ($a,$c) if ($j==59);'. # f=b^c^d for next round + + 'unshift(@ROTX,pop(@ROTX)); $j++;' + ) +} + +sub Xupdate_avx2_16_31() # recall that $Xi starts wtih 4 +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body,&$body); # 35 instructions + my ($a,$b,$c,$d,$e); + + &vpalignr(@X[0],@X[-3&7],@X[-4&7],8); # compose "X[-14]" in "X[0]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrldq(@Tx[0],@X[-1&7],4); # "X[-3]", 3 dwords + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"^="X[-16]" + &vpxor (@Tx[0],@Tx[0],@X[-2&7]); # "X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-3]"^"X[-8]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrld (@Tx[0],@X[0],31); + &vmovdqu($Kx,eval(2*16*(($Xi)/5)-64)."($K_XX_XX)") if ($Xi%5==0); # K_XX_XX + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpslldq(@Tx[2],@X[0],12); # "X[0]"<<96, extract one dword + &vpaddd (@X[0],@X[0],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrld (@Tx[1],@Tx[2],30); + &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=1 + eval(shift(@insns)); + eval(shift(@insns)); + + &vpslld (@Tx[2],@Tx[2],2); + &vpxor (@X[0],@X[0],@Tx[1]); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@Tx[2]); # "X[0]"^=("X[0]">>96)<<<2 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpaddd (@Tx[1],@X[0],$Kx); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vmovdqu(eval(32*($Xi))."(%rsp)",@Tx[1]); # X[]+K xfer to IALU + + foreach (@insns) { eval; } # remaining instructions [if any] + + $Xi++; + push(@X,shift(@X)); # "rotate" X[] +} + +sub Xupdate_avx2_32_79() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body,&$body); # 35 to 50 instructions + my ($a,$b,$c,$d,$e); + + &vpalignr(@Tx[0],@X[-1&7],@X[-2&7],8); # compose "X[-6]" + &vpxor (@X[0],@X[0],@X[-4&7]); # "X[0]"="X[-32]"^"X[-16]" + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@X[-7&7]); # "X[0]"^="X[-28]" + &vmovdqu($Kx,eval(2*16*($Xi/5)-64)."($K_XX_XX)") if ($Xi%5==0); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpxor (@X[0],@X[0],@Tx[0]); # "X[0]"^="X[-6]" + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpsrld (@Tx[0],@X[0],30); + &vpslld (@X[0],@X[0],2); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + #&vpslld (@X[0],@X[0],2); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpor (@X[0],@X[0],@Tx[0]); # "X[0]"<<<=2 + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vpaddd (@Tx[1],@X[0],$Kx); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + + &vmovdqu("32*$Xi(%rsp)",@Tx[1]); # X[]+K xfer to IALU + + foreach (@insns) { eval; } # remaining instructions + + $Xi++; + push(@X,shift(@X)); # "rotate" X[] +} + +sub Xloop_avx2() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body,&$body); # 32 instructions + my ($a,$b,$c,$d,$e); + + foreach (@insns) { eval; } +} + + &align32(); + &Xupdate_avx2_32_79(\&bodyx_00_19); + &Xupdate_avx2_32_79(\&bodyx_00_19); + &Xupdate_avx2_32_79(\&bodyx_00_19); + &Xupdate_avx2_32_79(\&bodyx_00_19); + + &Xupdate_avx2_32_79(\&bodyx_20_39); + &Xupdate_avx2_32_79(\&bodyx_20_39); + &Xupdate_avx2_32_79(\&bodyx_20_39); + &Xupdate_avx2_32_79(\&bodyx_20_39); + + &align32(); + &Xupdate_avx2_32_79(\&bodyx_40_59); + &Xupdate_avx2_32_79(\&bodyx_40_59); + &Xupdate_avx2_32_79(\&bodyx_40_59); + &Xupdate_avx2_32_79(\&bodyx_40_59); + + &Xloop_avx2(\&bodyx_20_39); + &Xloop_avx2(\&bodyx_20_39); + &Xloop_avx2(\&bodyx_20_39); + &Xloop_avx2(\&bodyx_20_39); + +$code.=<<___; + lea 128($inp),$frame + lea 128($inp),%rdi # borrow $t0 + cmp $num,$frame + cmovae $inp,$frame # next or previous block + + # output is d-e-[a]-f-b-c => A=d,F=e,C=f,D=b,E=c + add 0($ctx),@ROTX[0] # update context + add 4($ctx),@ROTX[1] + add 8($ctx),@ROTX[3] + mov @ROTX[0],0($ctx) + add 12($ctx),@ROTX[4] + mov @ROTX[1],4($ctx) + mov @ROTX[0],$A # A=d + add 16($ctx),@ROTX[5] + mov @ROTX[3],$a5 + mov @ROTX[3],8($ctx) + mov @ROTX[4],$D # D=b + #xchg @ROTX[5],$F # F=c, C=f + mov @ROTX[4],12($ctx) + mov @ROTX[1],$F # F=e + mov @ROTX[5],16($ctx) + #mov $F,16($ctx) + mov @ROTX[5],$E # E=c + mov $a5,$C # C=f + #xchg $F,$E # E=c, F=e + + cmp $num,$inp + je .Ldone_avx2 +___ + +$Xi=4; # reset variables +@X=map("%ymm$_",(4..7,0..3)); + +$code.=<<___; + vmovdqu 64($K_XX_XX),@X[2] # pbswap mask + cmp $num,%rdi # borrowed $t0 + ja .Last_avx2 + + vmovdqu -64(%rdi),%xmm0 # low part of @X[-4&7] + vmovdqu -48(%rdi),%xmm1 + vmovdqu -32(%rdi),%xmm2 + vmovdqu -16(%rdi),%xmm3 + vinserti128 \$1,0($frame),@X[-4&7],@X[-4&7] + vinserti128 \$1,16($frame),@X[-3&7],@X[-3&7] + vinserti128 \$1,32($frame),@X[-2&7],@X[-2&7] + vinserti128 \$1,48($frame),@X[-1&7],@X[-1&7] + jmp .Last_avx2 + +.align 32 +.Last_avx2: + lea 128+16(%rsp),$frame + rorx \$2,$F,$B + andn $D,$F,$t0 + and $C,$F + xor $t0,$F + sub \$-128,$inp +___ + $rx=$j=0; @ROTX=($A,$F,$B,$C,$D,$E); + + &Xloop_avx2 (\&bodyx_00_19); + &Xloop_avx2 (\&bodyx_00_19); + &Xloop_avx2 (\&bodyx_00_19); + &Xloop_avx2 (\&bodyx_00_19); + + &Xloop_avx2 (\&bodyx_20_39); + &vmovdqu ($Kx,"-64($K_XX_XX)"); # K_00_19 + &vpshufb (@X[-4&7],@X[-4&7],@X[2]); # byte swap + &Xloop_avx2 (\&bodyx_20_39); + &vpshufb (@X[-3&7],@X[-3&7],@X[2]); + &vpaddd (@Tx[0],@X[-4&7],$Kx); # add K_00_19 + &Xloop_avx2 (\&bodyx_20_39); + &vmovdqu ("0(%rsp)",@Tx[0]); + &vpshufb (@X[-2&7],@X[-2&7],@X[2]); + &vpaddd (@Tx[1],@X[-3&7],$Kx); + &Xloop_avx2 (\&bodyx_20_39); + &vmovdqu ("32(%rsp)",@Tx[1]); + &vpshufb (@X[-1&7],@X[-1&7],@X[2]); + &vpaddd (@X[2],@X[-2&7],$Kx); + + &Xloop_avx2 (\&bodyx_40_59); + &align32 (); + &vmovdqu ("64(%rsp)",@X[2]); + &vpaddd (@X[3],@X[-1&7],$Kx); + &Xloop_avx2 (\&bodyx_40_59); + &vmovdqu ("96(%rsp)",@X[3]); + &Xloop_avx2 (\&bodyx_40_59); + &Xupdate_avx2_16_31(\&bodyx_40_59); + + &Xupdate_avx2_16_31(\&bodyx_20_39); + &Xupdate_avx2_16_31(\&bodyx_20_39); + &Xupdate_avx2_16_31(\&bodyx_20_39); + &Xloop_avx2 (\&bodyx_20_39); + +$code.=<<___; + lea 128(%rsp),$frame + + # output is d-e-[a]-f-b-c => A=d,F=e,C=f,D=b,E=c + add 0($ctx),@ROTX[0] # update context + add 4($ctx),@ROTX[1] + add 8($ctx),@ROTX[3] + mov @ROTX[0],0($ctx) + add 12($ctx),@ROTX[4] + mov @ROTX[1],4($ctx) + mov @ROTX[0],$A # A=d + add 16($ctx),@ROTX[5] + mov @ROTX[3],$a5 + mov @ROTX[3],8($ctx) + mov @ROTX[4],$D # D=b + #xchg @ROTX[5],$F # F=c, C=f + mov @ROTX[4],12($ctx) + mov @ROTX[1],$F # F=e + mov @ROTX[5],16($ctx) + #mov $F,16($ctx) + mov @ROTX[5],$E # E=c + mov $a5,$C # C=f + #xchg $F,$E # E=c, F=e + + cmp $num,$inp + jbe .Loop_avx2 + +.Ldone_avx2: + vzeroupper +___ +$code.=<<___ if ($win64); + movaps -40-6*16(%r14),%xmm6 + movaps -40-5*16(%r14),%xmm7 + movaps -40-4*16(%r14),%xmm8 + movaps -40-3*16(%r14),%xmm9 + movaps -40-2*16(%r14),%xmm10 + movaps -40-1*16(%r14),%xmm11 +___ +$code.=<<___; + lea (%r14),%rsi + mov -40(%rsi),%r14 + mov -32(%rsi),%r13 + mov -24(%rsi),%r12 + mov -16(%rsi),%rbp + mov -8(%rsi),%rbx + lea (%rsi),%rsp +.Lepilogue_avx2: + ret +.size sha1_block_data_order_avx2,.-sha1_block_data_order_avx2 +___ +} +} +$code.=<<___; +.align 64 +K_XX_XX: +.long 0x5a827999,0x5a827999,0x5a827999,0x5a827999 # K_00_19 +.long 0x5a827999,0x5a827999,0x5a827999,0x5a827999 # K_00_19 +.long 0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1 # K_20_39 +.long 0x6ed9eba1,0x6ed9eba1,0x6ed9eba1,0x6ed9eba1 # K_20_39 +.long 0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc # K_40_59 +.long 0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc,0x8f1bbcdc # K_40_59 +.long 0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6 # K_60_79 +.long 0xca62c1d6,0xca62c1d6,0xca62c1d6,0xca62c1d6 # K_60_79 +.long 0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f # pbswap mask +.long 0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f # pbswap mask +.byte 0xf,0xe,0xd,0xc,0xb,0xa,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0 +___ +}}} +$code.=<<___; +.asciz "SHA1 block transform for x86_64, CRYPTOGAMS by " +.align 64 +___ + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + lea .Lprologue(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lprologue + jb .Lcommon_seh_tail + + mov 152($context),%rax # pull context->Rsp + + lea .Lepilogue(%rip),%r10 + cmp %r10,%rbx # context->Rip>=.Lepilogue + jae .Lcommon_seh_tail + + mov `16*4`(%rax),%rax # pull saved stack pointer + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + + jmp .Lcommon_seh_tail +.size se_handler,.-se_handler +___ + +$code.=<<___ if ($shaext); +.type shaext_handler,\@abi-omnipotent +.align 16 +shaext_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + lea .Lprologue_shaext(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lprologue + jb .Lcommon_seh_tail + + lea .Lepilogue_shaext(%rip),%r10 + cmp %r10,%rbx # context->Rip>=.Lepilogue + jae .Lcommon_seh_tail + + lea -8-4*16(%rax),%rsi + lea 512($context),%rdi # &context.Xmm6 + mov \$8,%ecx + .long 0xa548f3fc # cld; rep movsq + + jmp .Lcommon_seh_tail +.size shaext_handler,.-shaext_handler +___ + +$code.=<<___; +.type ssse3_handler,\@abi-omnipotent +.align 16 +ssse3_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HandlerData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lcommon_seh_tail + + mov 232($context),%rax # pull context->R14 + + lea -40-6*16(%rax),%rsi + lea 512($context),%rdi # &context.Xmm6 + mov \$12,%ecx + .long 0xa548f3fc # cld; rep movsq + + mov -8(%rax),%rbx + mov -16(%rax),%rbp + mov -24(%rax),%r12 + mov -32(%rax),%r13 + mov -40(%rax),%r14 + mov %rbx,144($context) # restore context->Rbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore cotnext->R12 + mov %r13,224($context) # restore cotnext->R13 + mov %r14,232($context) # restore cotnext->R14 + +.Lcommon_seh_tail: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size ssse3_handler,.-ssse3_handler + +.section .pdata +.align 4 + .rva .LSEH_begin_sha1_block_data_order + .rva .LSEH_end_sha1_block_data_order + .rva .LSEH_info_sha1_block_data_order +___ +$code.=<<___ if ($shaext); + .rva .LSEH_begin_sha1_block_data_order_shaext + .rva .LSEH_end_sha1_block_data_order_shaext + .rva .LSEH_info_sha1_block_data_order_shaext +___ +$code.=<<___; + .rva .LSEH_begin_sha1_block_data_order_ssse3 + .rva .LSEH_end_sha1_block_data_order_ssse3 + .rva .LSEH_info_sha1_block_data_order_ssse3 +___ +$code.=<<___ if ($avx); + .rva .LSEH_begin_sha1_block_data_order_avx + .rva .LSEH_end_sha1_block_data_order_avx + .rva .LSEH_info_sha1_block_data_order_avx +___ +$code.=<<___ if ($avx>1); + .rva .LSEH_begin_sha1_block_data_order_avx2 + .rva .LSEH_end_sha1_block_data_order_avx2 + .rva .LSEH_info_sha1_block_data_order_avx2 +___ +$code.=<<___; +.section .xdata +.align 8 +.LSEH_info_sha1_block_data_order: + .byte 9,0,0,0 + .rva se_handler +___ +$code.=<<___ if ($shaext); +.LSEH_info_sha1_block_data_order_shaext: + .byte 9,0,0,0 + .rva shaext_handler +___ +$code.=<<___; +.LSEH_info_sha1_block_data_order_ssse3: + .byte 9,0,0,0 + .rva ssse3_handler + .rva .Lprologue_ssse3,.Lepilogue_ssse3 # HandlerData[] +___ +$code.=<<___ if ($avx); +.LSEH_info_sha1_block_data_order_avx: + .byte 9,0,0,0 + .rva ssse3_handler + .rva .Lprologue_avx,.Lepilogue_avx # HandlerData[] +___ +$code.=<<___ if ($avx>1); +.LSEH_info_sha1_block_data_order_avx2: + .byte 9,0,0,0 + .rva ssse3_handler + .rva .Lprologue_avx2,.Lepilogue_avx2 # HandlerData[] +___ +} + +#################################################################### + +sub sha1rnds4 { + if (@_[0] =~ /\$([x0-9a-f]+),\s*%xmm([0-7]),\s*%xmm([0-7])/) { + my @opcode=(0x0f,0x3a,0xcc); + push @opcode,0xc0|($2&7)|(($3&7)<<3); # ModR/M + my $c=$1; + push @opcode,$c=~/^0/?oct($c):$c; + return ".byte\t".join(',',@opcode); + } else { + return "sha1rnds4\t".@_[0]; + } +} + +sub sha1op38 { + my $instr = shift; + my %opcodelet = ( + "sha1nexte" => 0xc8, + "sha1msg1" => 0xc9, + "sha1msg2" => 0xca ); + + if (defined($opcodelet{$instr}) && @_[0] =~ /%xmm([0-9]+),\s*%xmm([0-9]+)/) { + my @opcode=(0x0f,0x38); + my $rex=0; + $rex|=0x04 if ($2>=8); + $rex|=0x01 if ($1>=8); + unshift @opcode,0x40|$rex if ($rex); + push @opcode,$opcodelet{$instr}; + push @opcode,0xc0|($1&7)|(($2&7)<<3); # ModR/M + return ".byte\t".join(',',@opcode); + } else { + return $instr."\t".@_[0]; + } +} + +foreach (split("\n",$code)) { + s/\`([^\`]*)\`/eval $1/geo; + + s/\b(sha1rnds4)\s+(.*)/sha1rnds4($2)/geo or + s/\b(sha1[^\s]*)\s+(.*)/sha1op38($1,$2)/geo; + + print $_,"\n"; +} +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha256-586.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha256-586.pl new file mode 100644 index 00000000..e9077143 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha256-586.pl @@ -0,0 +1,1281 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# SHA256 block transform for x86. September 2007. +# +# Performance improvement over compiler generated code varies from +# 10% to 40% [see below]. Not very impressive on some µ-archs, but +# it's 5 times smaller and optimizies amount of writes. +# +# May 2012. +# +# Optimization including two of Pavel Semjanov's ideas, alternative +# Maj and full unroll, resulted in ~20-25% improvement on most CPUs, +# ~7% on Pentium, ~40% on Atom. As fully unrolled loop body is almost +# 15x larger, 8KB vs. 560B, it's fired only for longer inputs. But not +# on P4, where it kills performance, nor Sandy Bridge, where folded +# loop is approximately as fast... +# +# June 2012. +# +# Add AMD XOP-specific code path, >30% improvement on Bulldozer over +# May version, >60% over original. Add AVX+shrd code path, >25% +# improvement on Sandy Bridge over May version, 60% over original. +# +# May 2013. +# +# Replace AMD XOP code path with SSSE3 to cover more processors. +# (Biggest improvement coefficient is on upcoming Atom Silvermont, +# not shown.) Add AVX+BMI code path. +# +# March 2014. +# +# Add support for Intel SHA Extensions. +# +# Performance in clock cycles per processed byte (less is better): +# +# gcc icc x86 asm(*) SIMD x86_64 asm(**) +# Pentium 46 57 40/38 - - +# PIII 36 33 27/24 - - +# P4 41 38 28 - 17.3 +# AMD K8 27 25 19/15.5 - 14.9 +# Core2 26 23 18/15.6 14.3 13.8 +# Westmere 27 - 19/15.7 13.4 12.3 +# Sandy Bridge 25 - 15.9 12.4 11.6 +# Ivy Bridge 24 - 15.0 11.4 10.3 +# Haswell 22 - 13.9 9.46 7.80 +# Bulldozer 36 - 27/22 17.0 13.6 +# VIA Nano 36 - 25/22 16.8 16.5 +# Atom 50 - 30/25 21.9 18.9 +# Silvermont 40 - 34/31 22.9 20.6 +# +# (*) numbers after slash are for unrolled loop, where applicable; +# (**) x86_64 assembly performance is presented for reference +# purposes, results are best-available; + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],"sha512-586.pl",$ARGV[$#ARGV] eq "386"); + +$xmm=$avx=0; +for (@ARGV) { $xmm=1 if (/-DOPENSSL_IA32_SSE2/); } + +if ($xmm && `$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.19) + ($1>=2.22); +} + +if ($xmm && !$avx && $ARGV[0] eq "win32n" && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.03) + ($1>=2.10); +} + +if ($xmm && !$avx && $ARGV[0] eq "win32" && + `ml 2>&1` =~ /Version ([0-9]+)\./) { + $avx = ($1>=10) + ($1>=11); +} + +if ($xmm && !$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/) { + $avx = ($2>=3.0) + ($2>3.0); +} + +$shaext=$xmm; ### set to zero if compiling for 1.0.1 + +$unroll_after = 64*4; # If pre-evicted from L1P cache first spin of + # fully unrolled loop was measured to run about + # 3-4x slower. If slowdown coefficient is N and + # unrolled loop is m times faster, then you break + # even at (N-1)/(m-1) blocks. Then it needs to be + # adjusted for probability of code being evicted, + # code size/cache size=1/4. Typical m is 1.15... + +$A="eax"; +$E="edx"; +$T="ebx"; +$Aoff=&DWP(4,"esp"); +$Boff=&DWP(8,"esp"); +$Coff=&DWP(12,"esp"); +$Doff=&DWP(16,"esp"); +$Eoff=&DWP(20,"esp"); +$Foff=&DWP(24,"esp"); +$Goff=&DWP(28,"esp"); +$Hoff=&DWP(32,"esp"); +$Xoff=&DWP(36,"esp"); +$K256="ebp"; + +sub BODY_16_63() { + &mov ($T,"ecx"); # "ecx" is preloaded + &mov ("esi",&DWP(4*(9+15+16-14),"esp")); + &ror ("ecx",18-7); + &mov ("edi","esi"); + &ror ("esi",19-17); + &xor ("ecx",$T); + &shr ($T,3); + &ror ("ecx",7); + &xor ("esi","edi"); + &xor ($T,"ecx"); # T = sigma0(X[-15]) + &ror ("esi",17); + &add ($T,&DWP(4*(9+15+16),"esp")); # T += X[-16] + &shr ("edi",10); + &add ($T,&DWP(4*(9+15+16-9),"esp")); # T += X[-7] + #&xor ("edi","esi") # sigma1(X[-2]) + # &add ($T,"edi"); # T += sigma1(X[-2]) + # &mov (&DWP(4*(9+15),"esp"),$T); # save X[0] + + &BODY_00_15(1); +} +sub BODY_00_15() { + my $in_16_63=shift; + + &mov ("ecx",$E); + &xor ("edi","esi") if ($in_16_63); # sigma1(X[-2]) + &mov ("esi",$Foff); + &ror ("ecx",25-11); + &add ($T,"edi") if ($in_16_63); # T += sigma1(X[-2]) + &mov ("edi",$Goff); + &xor ("ecx",$E); + &xor ("esi","edi"); + &mov ($T,&DWP(4*(9+15),"esp")) if (!$in_16_63); + &mov (&DWP(4*(9+15),"esp"),$T) if ($in_16_63); # save X[0] + &ror ("ecx",11-6); + &and ("esi",$E); + &mov ($Eoff,$E); # modulo-scheduled + &xor ($E,"ecx"); + &add ($T,$Hoff); # T += h + &xor ("esi","edi"); # Ch(e,f,g) + &ror ($E,6); # Sigma1(e) + &mov ("ecx",$A); + &add ($T,"esi"); # T += Ch(e,f,g) + + &ror ("ecx",22-13); + &add ($T,$E); # T += Sigma1(e) + &mov ("edi",$Boff); + &xor ("ecx",$A); + &mov ($Aoff,$A); # modulo-scheduled + &lea ("esp",&DWP(-4,"esp")); + &ror ("ecx",13-2); + &mov ("esi",&DWP(0,$K256)); + &xor ("ecx",$A); + &mov ($E,$Eoff); # e in next iteration, d in this one + &xor ($A,"edi"); # a ^= b + &ror ("ecx",2); # Sigma0(a) + + &add ($T,"esi"); # T+= K[i] + &mov (&DWP(0,"esp"),$A); # (b^c) in next round + &add ($E,$T); # d += T + &and ($A,&DWP(4,"esp")); # a &= (b^c) + &add ($T,"ecx"); # T += Sigma0(a) + &xor ($A,"edi"); # h = Maj(a,b,c) = Ch(a^b,c,b) + &mov ("ecx",&DWP(4*(9+15+16-1),"esp")) if ($in_16_63); # preload T + &add ($K256,4); + &add ($A,$T); # h += T +} + +&external_label("OPENSSL_ia32cap_P") if (!$i386); + +&function_begin("sha256_block_data_order"); + &mov ("esi",wparam(0)); # ctx + &mov ("edi",wparam(1)); # inp + &mov ("eax",wparam(2)); # num + &mov ("ebx","esp"); # saved sp + + &call (&label("pic_point")); # make it PIC! +&set_label("pic_point"); + &blindpop($K256); + &lea ($K256,&DWP(&label("K256")."-".&label("pic_point"),$K256)); + + &sub ("esp",16); + &and ("esp",-64); + + &shl ("eax",6); + &add ("eax","edi"); + &mov (&DWP(0,"esp"),"esi"); # ctx + &mov (&DWP(4,"esp"),"edi"); # inp + &mov (&DWP(8,"esp"),"eax"); # inp+num*128 + &mov (&DWP(12,"esp"),"ebx"); # saved sp + if (!$i386 && $xmm) { + &picmeup("edx","OPENSSL_ia32cap_P",$K256,&label("K256")); + &mov ("ecx",&DWP(0,"edx")); + &mov ("ebx",&DWP(4,"edx")); + &test ("ecx",1<<20); # check for P4 + &jnz (&label("loop")); + &mov ("edx",&DWP(8,"edx")) if ($xmm); + &test ("ecx",1<<24); # check for FXSR + &jz ($unroll_after?&label("no_xmm"):&label("loop")); + &and ("ecx",1<<30); # mask "Intel CPU" bit + &and ("ebx",1<<28|1<<9); # mask AVX and SSSE3 bits + &test ("edx",1<<29) if ($shaext); # check for SHA + &jnz (&label("shaext")) if ($shaext); + &or ("ecx","ebx"); + &and ("ecx",1<<28|1<<30); + &cmp ("ecx",1<<28|1<<30); + if ($xmm) { + &je (&label("AVX")) if ($avx); + &test ("ebx",1<<9); # check for SSSE3 + &jnz (&label("SSSE3")); + } else { + &je (&label("loop_shrd")); + } + if ($unroll_after) { +&set_label("no_xmm"); + &sub ("eax","edi"); + &cmp ("eax",$unroll_after); + &jae (&label("unrolled")); + } } + &jmp (&label("loop")); + +sub COMPACT_LOOP() { +my $suffix=shift; + +&set_label("loop$suffix",$suffix?32:16); + # copy input block to stack reversing byte and dword order + for($i=0;$i<4;$i++) { + &mov ("eax",&DWP($i*16+0,"edi")); + &mov ("ebx",&DWP($i*16+4,"edi")); + &mov ("ecx",&DWP($i*16+8,"edi")); + &bswap ("eax"); + &mov ("edx",&DWP($i*16+12,"edi")); + &bswap ("ebx"); + &push ("eax"); + &bswap ("ecx"); + &push ("ebx"); + &bswap ("edx"); + &push ("ecx"); + &push ("edx"); + } + &add ("edi",64); + &lea ("esp",&DWP(-4*9,"esp"));# place for A,B,C,D,E,F,G,H + &mov (&DWP(4*(9+16)+4,"esp"),"edi"); + + # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack + &mov ($A,&DWP(0,"esi")); + &mov ("ebx",&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("edi",&DWP(12,"esi")); + # &mov ($Aoff,$A); + &mov ($Boff,"ebx"); + &xor ("ebx","ecx"); + &mov ($Coff,"ecx"); + &mov ($Doff,"edi"); + &mov (&DWP(0,"esp"),"ebx"); # magic + &mov ($E,&DWP(16,"esi")); + &mov ("ebx",&DWP(20,"esi")); + &mov ("ecx",&DWP(24,"esi")); + &mov ("edi",&DWP(28,"esi")); + # &mov ($Eoff,$E); + &mov ($Foff,"ebx"); + &mov ($Goff,"ecx"); + &mov ($Hoff,"edi"); + +&set_label("00_15$suffix",16); + + &BODY_00_15(); + + &cmp ("esi",0xc19bf174); + &jne (&label("00_15$suffix")); + + &mov ("ecx",&DWP(4*(9+15+16-1),"esp")); # preloaded in BODY_00_15(1) + &jmp (&label("16_63$suffix")); + +&set_label("16_63$suffix",16); + + &BODY_16_63(); + + &cmp ("esi",0xc67178f2); + &jne (&label("16_63$suffix")); + + &mov ("esi",&DWP(4*(9+16+64)+0,"esp"));#ctx + # &mov ($A,$Aoff); + &mov ("ebx",$Boff); + # &mov ("edi",$Coff); + &mov ("ecx",$Doff); + &add ($A,&DWP(0,"esi")); + &add ("ebx",&DWP(4,"esi")); + &add ("edi",&DWP(8,"esi")); + &add ("ecx",&DWP(12,"esi")); + &mov (&DWP(0,"esi"),$A); + &mov (&DWP(4,"esi"),"ebx"); + &mov (&DWP(8,"esi"),"edi"); + &mov (&DWP(12,"esi"),"ecx"); + # &mov ($E,$Eoff); + &mov ("eax",$Foff); + &mov ("ebx",$Goff); + &mov ("ecx",$Hoff); + &mov ("edi",&DWP(4*(9+16+64)+4,"esp"));#inp + &add ($E,&DWP(16,"esi")); + &add ("eax",&DWP(20,"esi")); + &add ("ebx",&DWP(24,"esi")); + &add ("ecx",&DWP(28,"esi")); + &mov (&DWP(16,"esi"),$E); + &mov (&DWP(20,"esi"),"eax"); + &mov (&DWP(24,"esi"),"ebx"); + &mov (&DWP(28,"esi"),"ecx"); + + &lea ("esp",&DWP(4*(9+16+64),"esp"));# destroy frame + &sub ($K256,4*64); # rewind K + + &cmp ("edi",&DWP(8,"esp")); # are we done yet? + &jb (&label("loop$suffix")); +} + &COMPACT_LOOP(); + &mov ("esp",&DWP(12,"esp")); # restore sp +&function_end_A(); + if (!$i386 && !$xmm) { + # ~20% improvement on Sandy Bridge + local *ror = sub { &shrd(@_[0],@_) }; + &COMPACT_LOOP("_shrd"); + &mov ("esp",&DWP(12,"esp")); # restore sp +&function_end_A(); + } + +&set_label("K256",64); # Yes! I keep it in the code segment! +@K256=( 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5, + 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3, + 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc, + 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7, + 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13, + 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3, + 0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5, + 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208, + 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 ); +&data_word(@K256); +&data_word(0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f); # byte swap mask +&asciz("SHA256 block transform for x86, CRYPTOGAMS by "); + +($a,$b,$c,$d,$e,$f,$g,$h)=(0..7); # offsets +sub off { &DWP(4*(((shift)-$i)&7),"esp"); } + +if (!$i386 && $unroll_after) { +my @AH=($A,$K256); + +&set_label("unrolled",16); + &lea ("esp",&DWP(-96,"esp")); + # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack + &mov ($AH[0],&DWP(0,"esi")); + &mov ($AH[1],&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("ebx",&DWP(12,"esi")); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"ecx"); # magic + &mov (&DWP(8,"esp"),"ecx"); + &mov (&DWP(12,"esp"),"ebx"); + &mov ($E,&DWP(16,"esi")); + &mov ("ebx",&DWP(20,"esi")); + &mov ("ecx",&DWP(24,"esi")); + &mov ("esi",&DWP(28,"esi")); + #&mov (&DWP(16,"esp"),$E); + &mov (&DWP(20,"esp"),"ebx"); + &mov (&DWP(24,"esp"),"ecx"); + &mov (&DWP(28,"esp"),"esi"); + &jmp (&label("grand_loop")); + +&set_label("grand_loop",16); + # copy input block to stack reversing byte order + for($i=0;$i<5;$i++) { + &mov ("ebx",&DWP(12*$i+0,"edi")); + &mov ("ecx",&DWP(12*$i+4,"edi")); + &bswap ("ebx"); + &mov ("esi",&DWP(12*$i+8,"edi")); + &bswap ("ecx"); + &mov (&DWP(32+12*$i+0,"esp"),"ebx"); + &bswap ("esi"); + &mov (&DWP(32+12*$i+4,"esp"),"ecx"); + &mov (&DWP(32+12*$i+8,"esp"),"esi"); + } + &mov ("ebx",&DWP($i*12,"edi")); + &add ("edi",64); + &bswap ("ebx"); + &mov (&DWP(96+4,"esp"),"edi"); + &mov (&DWP(32+12*$i,"esp"),"ebx"); + + my ($t1,$t2) = ("ecx","esi"); + + for ($i=0;$i<64;$i++) { + + if ($i>=16) { + &mov ($T,$t1); # $t1 is preloaded + # &mov ($t2,&DWP(32+4*(($i+14)&15),"esp")); + &ror ($t1,18-7); + &mov ("edi",$t2); + &ror ($t2,19-17); + &xor ($t1,$T); + &shr ($T,3); + &ror ($t1,7); + &xor ($t2,"edi"); + &xor ($T,$t1); # T = sigma0(X[-15]) + &ror ($t2,17); + &add ($T,&DWP(32+4*($i&15),"esp")); # T += X[-16] + &shr ("edi",10); + &add ($T,&DWP(32+4*(($i+9)&15),"esp")); # T += X[-7] + #&xor ("edi",$t2) # sigma1(X[-2]) + # &add ($T,"edi"); # T += sigma1(X[-2]) + # &mov (&DWP(4*(9+15),"esp"),$T); # save X[0] + } + &mov ($t1,$E); + &xor ("edi",$t2) if ($i>=16); # sigma1(X[-2]) + &mov ($t2,&off($f)); + &ror ($E,25-11); + &add ($T,"edi") if ($i>=16); # T += sigma1(X[-2]) + &mov ("edi",&off($g)); + &xor ($E,$t1); + &mov ($T,&DWP(32+4*($i&15),"esp")) if ($i<16); # X[i] + &mov (&DWP(32+4*($i&15),"esp"),$T) if ($i>=16 && $i<62); # save X[0] + &xor ($t2,"edi"); + &ror ($E,11-6); + &and ($t2,$t1); + &mov (&off($e),$t1); # save $E, modulo-scheduled + &xor ($E,$t1); + &add ($T,&off($h)); # T += h + &xor ("edi",$t2); # Ch(e,f,g) + &ror ($E,6); # Sigma1(e) + &mov ($t1,$AH[0]); + &add ($T,"edi"); # T += Ch(e,f,g) + + &ror ($t1,22-13); + &mov ($t2,$AH[0]); + &mov ("edi",&off($b)); + &xor ($t1,$AH[0]); + &mov (&off($a),$AH[0]); # save $A, modulo-scheduled + &xor ($AH[0],"edi"); # a ^= b, (b^c) in next round + &ror ($t1,13-2); + &and ($AH[1],$AH[0]); # (b^c) &= (a^b) + &lea ($E,&DWP(@K256[$i],$T,$E)); # T += Sigma1(1)+K[i] + &xor ($t1,$t2); + &xor ($AH[1],"edi"); # h = Maj(a,b,c) = Ch(a^b,c,b) + &mov ($t2,&DWP(32+4*(($i+2)&15),"esp")) if ($i>=15 && $i<63); + &ror ($t1,2); # Sigma0(a) + + &add ($AH[1],$E); # h += T + &add ($E,&off($d)); # d += T + &add ($AH[1],$t1); # h += Sigma0(a) + &mov ($t1,&DWP(32+4*(($i+15)&15),"esp")) if ($i>=15 && $i<63); + + @AH = reverse(@AH); # rotate(a,h) + ($t1,$t2) = ($t2,$t1); # rotate(t1,t2) + } + &mov ("esi",&DWP(96,"esp")); #ctx + #&mov ($AH[0],&DWP(0,"esp")); + &xor ($AH[1],"edi"); #&mov ($AH[1],&DWP(4,"esp")); + #&mov ("edi", &DWP(8,"esp")); + &mov ("ecx",&DWP(12,"esp")); + &add ($AH[0],&DWP(0,"esi")); + &add ($AH[1],&DWP(4,"esi")); + &add ("edi",&DWP(8,"esi")); + &add ("ecx",&DWP(12,"esi")); + &mov (&DWP(0,"esi"),$AH[0]); + &mov (&DWP(4,"esi"),$AH[1]); + &mov (&DWP(8,"esi"),"edi"); + &mov (&DWP(12,"esi"),"ecx"); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"edi"); # magic + &mov (&DWP(8,"esp"),"edi"); + &mov (&DWP(12,"esp"),"ecx"); + #&mov ($E,&DWP(16,"esp")); + &mov ("edi",&DWP(20,"esp")); + &mov ("ebx",&DWP(24,"esp")); + &mov ("ecx",&DWP(28,"esp")); + &add ($E,&DWP(16,"esi")); + &add ("edi",&DWP(20,"esi")); + &add ("ebx",&DWP(24,"esi")); + &add ("ecx",&DWP(28,"esi")); + &mov (&DWP(16,"esi"),$E); + &mov (&DWP(20,"esi"),"edi"); + &mov (&DWP(24,"esi"),"ebx"); + &mov (&DWP(28,"esi"),"ecx"); + #&mov (&DWP(16,"esp"),$E); + &mov (&DWP(20,"esp"),"edi"); + &mov ("edi",&DWP(96+4,"esp")); # inp + &mov (&DWP(24,"esp"),"ebx"); + &mov (&DWP(28,"esp"),"ecx"); + + &cmp ("edi",&DWP(96+8,"esp")); # are we done yet? + &jb (&label("grand_loop")); + + &mov ("esp",&DWP(96+12,"esp")); # restore sp +&function_end_A(); +} + if (!$i386 && $xmm) {{{ +if ($shaext) { +###################################################################### +# Intel SHA Extensions implementation of SHA256 update function. +# +my ($ctx,$inp,$end)=("esi","edi","eax"); +my ($Wi,$ABEF,$CDGH,$TMP)=map("xmm$_",(0..2,7)); +my @MSG=map("xmm$_",(3..6)); + +sub sha256op38 { + my ($opcodelet,$dst,$src)=@_; + if ("$dst:$src" =~ /xmm([0-7]):xmm([0-7])/) + { &data_byte(0x0f,0x38,$opcodelet,0xc0|($1<<3)|$2); } +} +sub sha256rnds2 { sha256op38(0xcb,@_); } +sub sha256msg1 { sha256op38(0xcc,@_); } +sub sha256msg2 { sha256op38(0xcd,@_); } + +&set_label("shaext",32); + &sub ("esp",32); + + &movdqu ($ABEF,&QWP(0,$ctx)); # DCBA + &lea ($K256,&DWP(0x80,$K256)); + &movdqu ($CDGH,&QWP(16,$ctx)); # HGFE + &movdqa ($TMP,&QWP(0x100-0x80,$K256)); # byte swap mask + + &pshufd ($Wi,$ABEF,0x1b); # ABCD + &pshufd ($ABEF,$ABEF,0xb1); # CDAB + &pshufd ($CDGH,$CDGH,0x1b); # EFGH + &palignr ($ABEF,$CDGH,8); # ABEF + &punpcklqdq ($CDGH,$Wi); # CDGH + &jmp (&label("loop_shaext")); + +&set_label("loop_shaext",16); + &movdqu (@MSG[0],&QWP(0,$inp)); + &movdqu (@MSG[1],&QWP(0x10,$inp)); + &movdqu (@MSG[2],&QWP(0x20,$inp)); + &pshufb (@MSG[0],$TMP); + &movdqu (@MSG[3],&QWP(0x30,$inp)); + &movdqa (&QWP(16,"esp"),$CDGH); # offload + + &movdqa ($Wi,&QWP(0*16-0x80,$K256)); + &paddd ($Wi,@MSG[0]); + &pshufb (@MSG[1],$TMP); + &sha256rnds2 ($CDGH,$ABEF); # 0-3 + &pshufd ($Wi,$Wi,0x0e); + &nop (); + &movdqa (&QWP(0,"esp"),$ABEF); # offload + &sha256rnds2 ($ABEF,$CDGH); + + &movdqa ($Wi,&QWP(1*16-0x80,$K256)); + &paddd ($Wi,@MSG[1]); + &pshufb (@MSG[2],$TMP); + &sha256rnds2 ($CDGH,$ABEF); # 4-7 + &pshufd ($Wi,$Wi,0x0e); + &lea ($inp,&DWP(0x40,$inp)); + &sha256msg1 (@MSG[0],@MSG[1]); + &sha256rnds2 ($ABEF,$CDGH); + + &movdqa ($Wi,&QWP(2*16-0x80,$K256)); + &paddd ($Wi,@MSG[2]); + &pshufb (@MSG[3],$TMP); + &sha256rnds2 ($CDGH,$ABEF); # 8-11 + &pshufd ($Wi,$Wi,0x0e); + &movdqa ($TMP,@MSG[3]); + &palignr ($TMP,@MSG[2],4); + &nop (); + &paddd (@MSG[0],$TMP); + &sha256msg1 (@MSG[1],@MSG[2]); + &sha256rnds2 ($ABEF,$CDGH); + + &movdqa ($Wi,&QWP(3*16-0x80,$K256)); + &paddd ($Wi,@MSG[3]); + &sha256msg2 (@MSG[0],@MSG[3]); + &sha256rnds2 ($CDGH,$ABEF); # 12-15 + &pshufd ($Wi,$Wi,0x0e); + &movdqa ($TMP,@MSG[0]); + &palignr ($TMP,@MSG[3],4); + &nop (); + &paddd (@MSG[1],$TMP); + &sha256msg1 (@MSG[2],@MSG[3]); + &sha256rnds2 ($ABEF,$CDGH); + +for($i=4;$i<16-3;$i++) { + &movdqa ($Wi,&QWP($i*16-0x80,$K256)); + &paddd ($Wi,@MSG[0]); + &sha256msg2 (@MSG[1],@MSG[0]); + &sha256rnds2 ($CDGH,$ABEF); # 16-19... + &pshufd ($Wi,$Wi,0x0e); + &movdqa ($TMP,@MSG[1]); + &palignr ($TMP,@MSG[0],4); + &nop (); + &paddd (@MSG[2],$TMP); + &sha256msg1 (@MSG[3],@MSG[0]); + &sha256rnds2 ($ABEF,$CDGH); + + push(@MSG,shift(@MSG)); +} + &movdqa ($Wi,&QWP(13*16-0x80,$K256)); + &paddd ($Wi,@MSG[0]); + &sha256msg2 (@MSG[1],@MSG[0]); + &sha256rnds2 ($CDGH,$ABEF); # 52-55 + &pshufd ($Wi,$Wi,0x0e); + &movdqa ($TMP,@MSG[1]) + &palignr ($TMP,@MSG[0],4); + &sha256rnds2 ($ABEF,$CDGH); + &paddd (@MSG[2],$TMP); + + &movdqa ($Wi,&QWP(14*16-0x80,$K256)); + &paddd ($Wi,@MSG[1]); + &sha256rnds2 ($CDGH,$ABEF); # 56-59 + &pshufd ($Wi,$Wi,0x0e); + &sha256msg2 (@MSG[2],@MSG[1]); + &movdqa ($TMP,&QWP(0x100-0x80,$K256)); # byte swap mask + &sha256rnds2 ($ABEF,$CDGH); + + &movdqa ($Wi,&QWP(15*16-0x80,$K256)); + &paddd ($Wi,@MSG[2]); + &nop (); + &sha256rnds2 ($CDGH,$ABEF); # 60-63 + &pshufd ($Wi,$Wi,0x0e); + &cmp ($end,$inp); + &nop (); + &sha256rnds2 ($ABEF,$CDGH); + + &paddd ($CDGH,&QWP(16,"esp")); + &paddd ($ABEF,&QWP(0,"esp")); + &jnz (&label("loop_shaext")); + + &pshufd ($CDGH,$CDGH,0xb1); # DCHG + &pshufd ($TMP,$ABEF,0x1b); # FEBA + &pshufd ($ABEF,$ABEF,0xb1); # BAFE + &punpckhqdq ($ABEF,$CDGH); # DCBA + &palignr ($CDGH,$TMP,8); # HGFE + + &mov ("esp",&DWP(32+12,"esp")); + &movdqu (&QWP(0,$ctx),$ABEF); + &movdqu (&QWP(16,$ctx),$CDGH); +&function_end_A(); +} + +my @X = map("xmm$_",(0..3)); +my ($t0,$t1,$t2,$t3) = map("xmm$_",(4..7)); +my @AH = ($A,$T); + +&set_label("SSSE3",32); + &lea ("esp",&DWP(-96,"esp")); + # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack + &mov ($AH[0],&DWP(0,"esi")); + &mov ($AH[1],&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("edi",&DWP(12,"esi")); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"ecx"); # magic + &mov (&DWP(8,"esp"),"ecx"); + &mov (&DWP(12,"esp"),"edi"); + &mov ($E,&DWP(16,"esi")); + &mov ("edi",&DWP(20,"esi")); + &mov ("ecx",&DWP(24,"esi")); + &mov ("esi",&DWP(28,"esi")); + #&mov (&DWP(16,"esp"),$E); + &mov (&DWP(20,"esp"),"edi"); + &mov ("edi",&DWP(96+4,"esp")); # inp + &mov (&DWP(24,"esp"),"ecx"); + &mov (&DWP(28,"esp"),"esi"); + &movdqa ($t3,&QWP(256,$K256)); + &jmp (&label("grand_ssse3")); + +&set_label("grand_ssse3",16); + # load input, reverse byte order, add K256[0..15], save to stack + &movdqu (@X[0],&QWP(0,"edi")); + &movdqu (@X[1],&QWP(16,"edi")); + &movdqu (@X[2],&QWP(32,"edi")); + &movdqu (@X[3],&QWP(48,"edi")); + &add ("edi",64); + &pshufb (@X[0],$t3); + &mov (&DWP(96+4,"esp"),"edi"); + &pshufb (@X[1],$t3); + &movdqa ($t0,&QWP(0,$K256)); + &pshufb (@X[2],$t3); + &movdqa ($t1,&QWP(16,$K256)); + &paddd ($t0,@X[0]); + &pshufb (@X[3],$t3); + &movdqa ($t2,&QWP(32,$K256)); + &paddd ($t1,@X[1]); + &movdqa ($t3,&QWP(48,$K256)); + &movdqa (&QWP(32+0,"esp"),$t0); + &paddd ($t2,@X[2]); + &movdqa (&QWP(32+16,"esp"),$t1); + &paddd ($t3,@X[3]); + &movdqa (&QWP(32+32,"esp"),$t2); + &movdqa (&QWP(32+48,"esp"),$t3); + &jmp (&label("ssse3_00_47")); + +&set_label("ssse3_00_47",16); + &add ($K256,64); + +sub SSSE3_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body,&$body,&$body); # 120 instructions + + eval(shift(@insns)); + &movdqa ($t0,@X[1]); + eval(shift(@insns)); # @ + eval(shift(@insns)); + &movdqa ($t3,@X[3]); + eval(shift(@insns)); + eval(shift(@insns)); + &palignr ($t0,@X[0],4); # X[1..4] + eval(shift(@insns)); + eval(shift(@insns)); # @ + eval(shift(@insns)); + &palignr ($t3,@X[2],4); # X[9..12] + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa ($t1,$t0); + eval(shift(@insns)); # @ + eval(shift(@insns)); + &movdqa ($t2,$t0); + eval(shift(@insns)); + eval(shift(@insns)); + &psrld ($t0,3); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &paddd (@X[0],$t3); # X[0..3] += X[9..12] + eval(shift(@insns)); + eval(shift(@insns)); + &psrld ($t2,7); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + eval(shift(@insns)); + &pshufd ($t3,@X[3],0b11111010); # X[14..15] + eval(shift(@insns)); + eval(shift(@insns)); + &pslld ($t1,32-18); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t0,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + &psrld ($t2,18-7); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t0,$t1); + eval(shift(@insns)); + eval(shift(@insns)); + &pslld ($t1,18-7); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t0,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa ($t2,$t3); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t0,$t1); # sigma0(X[1..4]) + eval(shift(@insns)); + eval(shift(@insns)); + &psrld ($t3,10); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &paddd (@X[0],$t0); # X[0..3] += sigma0(X[1..4]) + eval(shift(@insns)); + eval(shift(@insns)); + &psrlq ($t2,17); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + &psrlq ($t2,19-17); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + &pshufd ($t3,$t3,0b10000000); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + eval(shift(@insns)); + &psrldq ($t3,8); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@X[0],$t3); # X[0..1] += sigma1(X[14..15]) + eval(shift(@insns)); # @ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + eval(shift(@insns)); + &pshufd ($t3,@X[0],0b01010000); # X[16..17] + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa ($t2,$t3); + eval(shift(@insns)); # @ + &psrld ($t3,10); + eval(shift(@insns)); + &psrlq ($t2,17); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + &psrlq ($t2,19-17); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &pxor ($t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &pshufd ($t3,$t3,0b00001000); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &movdqa ($t2,&QWP(16*$j,$K256)); + eval(shift(@insns)); + eval(shift(@insns)); + &pslldq ($t3,8); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); # @ + &paddd (@X[0],$t3); # X[2..3] += sigma1(X[16..17]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd ($t2,@X[0]); + eval(shift(@insns)); # @ + + foreach (@insns) { eval; } # remaining instructions + + &movdqa (&QWP(32+16*$j,"esp"),$t2); +} + +sub body_00_15 () { + ( + '&mov ("ecx",$E);', + '&ror ($E,25-11);', + '&mov ("esi",&off($f));', + '&xor ($E,"ecx");', + '&mov ("edi",&off($g));', + '&xor ("esi","edi");', + '&ror ($E,11-6);', + '&and ("esi","ecx");', + '&mov (&off($e),"ecx");', # save $E, modulo-scheduled + '&xor ($E,"ecx");', + '&xor ("edi","esi");', # Ch(e,f,g) + '&ror ($E,6);', # T = Sigma1(e) + '&mov ("ecx",$AH[0]);', + '&add ($E,"edi");', # T += Ch(e,f,g) + '&mov ("edi",&off($b));', + '&mov ("esi",$AH[0]);', + + '&ror ("ecx",22-13);', + '&mov (&off($a),$AH[0]);', # save $A, modulo-scheduled + '&xor ("ecx",$AH[0]);', + '&xor ($AH[0],"edi");', # a ^= b, (b^c) in next round + '&add ($E,&off($h));', # T += h + '&ror ("ecx",13-2);', + '&and ($AH[1],$AH[0]);', # (b^c) &= (a^b) + '&xor ("ecx","esi");', + '&add ($E,&DWP(32+4*($i&15),"esp"));', # T += K[i]+X[i] + '&xor ($AH[1],"edi");', # h = Maj(a,b,c) = Ch(a^b,c,b) + '&ror ("ecx",2);', # Sigma0(a) + + '&add ($AH[1],$E);', # h += T + '&add ($E,&off($d));', # d += T + '&add ($AH[1],"ecx");'. # h += Sigma0(a) + + '@AH = reverse(@AH); $i++;' # rotate(a,h) + ); +} + + for ($i=0,$j=0; $j<4; $j++) { + &SSSE3_00_47($j,\&body_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmp (&DWP(16*$j,$K256),0x00010203); + &jne (&label("ssse3_00_47")); + + for ($i=0; $i<16; ) { + foreach(body_00_15()) { eval; } + } + + &mov ("esi",&DWP(96,"esp")); #ctx + #&mov ($AH[0],&DWP(0,"esp")); + &xor ($AH[1],"edi"); #&mov ($AH[1],&DWP(4,"esp")); + #&mov ("edi", &DWP(8,"esp")); + &mov ("ecx",&DWP(12,"esp")); + &add ($AH[0],&DWP(0,"esi")); + &add ($AH[1],&DWP(4,"esi")); + &add ("edi",&DWP(8,"esi")); + &add ("ecx",&DWP(12,"esi")); + &mov (&DWP(0,"esi"),$AH[0]); + &mov (&DWP(4,"esi"),$AH[1]); + &mov (&DWP(8,"esi"),"edi"); + &mov (&DWP(12,"esi"),"ecx"); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"edi"); # magic + &mov (&DWP(8,"esp"),"edi"); + &mov (&DWP(12,"esp"),"ecx"); + #&mov ($E,&DWP(16,"esp")); + &mov ("edi",&DWP(20,"esp")); + &mov ("ecx",&DWP(24,"esp")); + &add ($E,&DWP(16,"esi")); + &add ("edi",&DWP(20,"esi")); + &add ("ecx",&DWP(24,"esi")); + &mov (&DWP(16,"esi"),$E); + &mov (&DWP(20,"esi"),"edi"); + &mov (&DWP(20,"esp"),"edi"); + &mov ("edi",&DWP(28,"esp")); + &mov (&DWP(24,"esi"),"ecx"); + #&mov (&DWP(16,"esp"),$E); + &add ("edi",&DWP(28,"esi")); + &mov (&DWP(24,"esp"),"ecx"); + &mov (&DWP(28,"esi"),"edi"); + &mov (&DWP(28,"esp"),"edi"); + &mov ("edi",&DWP(96+4,"esp")); # inp + + &movdqa ($t3,&QWP(64,$K256)); + &sub ($K256,3*64); # rewind K + &cmp ("edi",&DWP(96+8,"esp")); # are we done yet? + &jb (&label("grand_ssse3")); + + &mov ("esp",&DWP(96+12,"esp")); # restore sp +&function_end_A(); + if ($avx) { +&set_label("AVX",32); + if ($avx>1) { + &and ("edx",1<<8|1<<3); # check for BMI2+BMI1 + &cmp ("edx",1<<8|1<<3); + &je (&label("AVX_BMI")); + } + &lea ("esp",&DWP(-96,"esp")); + &vzeroall (); + # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack + &mov ($AH[0],&DWP(0,"esi")); + &mov ($AH[1],&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("edi",&DWP(12,"esi")); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"ecx"); # magic + &mov (&DWP(8,"esp"),"ecx"); + &mov (&DWP(12,"esp"),"edi"); + &mov ($E,&DWP(16,"esi")); + &mov ("edi",&DWP(20,"esi")); + &mov ("ecx",&DWP(24,"esi")); + &mov ("esi",&DWP(28,"esi")); + #&mov (&DWP(16,"esp"),$E); + &mov (&DWP(20,"esp"),"edi"); + &mov ("edi",&DWP(96+4,"esp")); # inp + &mov (&DWP(24,"esp"),"ecx"); + &mov (&DWP(28,"esp"),"esi"); + &vmovdqa ($t3,&QWP(256,$K256)); + &jmp (&label("grand_avx")); + +&set_label("grand_avx",32); + # load input, reverse byte order, add K256[0..15], save to stack + &vmovdqu (@X[0],&QWP(0,"edi")); + &vmovdqu (@X[1],&QWP(16,"edi")); + &vmovdqu (@X[2],&QWP(32,"edi")); + &vmovdqu (@X[3],&QWP(48,"edi")); + &add ("edi",64); + &vpshufb (@X[0],@X[0],$t3); + &mov (&DWP(96+4,"esp"),"edi"); + &vpshufb (@X[1],@X[1],$t3); + &vpshufb (@X[2],@X[2],$t3); + &vpaddd ($t0,@X[0],&QWP(0,$K256)); + &vpshufb (@X[3],@X[3],$t3); + &vpaddd ($t1,@X[1],&QWP(16,$K256)); + &vpaddd ($t2,@X[2],&QWP(32,$K256)); + &vpaddd ($t3,@X[3],&QWP(48,$K256)); + &vmovdqa (&QWP(32+0,"esp"),$t0); + &vmovdqa (&QWP(32+16,"esp"),$t1); + &vmovdqa (&QWP(32+32,"esp"),$t2); + &vmovdqa (&QWP(32+48,"esp"),$t3); + &jmp (&label("avx_00_47")); + +&set_label("avx_00_47",16); + &add ($K256,64); + +sub Xupdate_AVX () { + ( + '&vpalignr ($t0,@X[1],@X[0],4);', # X[1..4] + '&vpalignr ($t3,@X[3],@X[2],4);', # X[9..12] + '&vpsrld ($t2,$t0,7);', + '&vpaddd (@X[0],@X[0],$t3);', # X[0..3] += X[9..16] + '&vpsrld ($t3,$t0,3);', + '&vpslld ($t1,$t0,14);', + '&vpxor ($t0,$t3,$t2);', + '&vpshufd ($t3,@X[3],0b11111010)',# X[14..15] + '&vpsrld ($t2,$t2,18-7);', + '&vpxor ($t0,$t0,$t1);', + '&vpslld ($t1,$t1,25-14);', + '&vpxor ($t0,$t0,$t2);', + '&vpsrld ($t2,$t3,10);', + '&vpxor ($t0,$t0,$t1);', # sigma0(X[1..4]) + '&vpsrlq ($t1,$t3,17);', + '&vpaddd (@X[0],@X[0],$t0);', # X[0..3] += sigma0(X[1..4]) + '&vpxor ($t2,$t2,$t1);', + '&vpsrlq ($t3,$t3,19);', + '&vpxor ($t2,$t2,$t3);', # sigma1(X[14..15] + '&vpshufd ($t3,$t2,0b10000100);', + '&vpsrldq ($t3,$t3,8);', + '&vpaddd (@X[0],@X[0],$t3);', # X[0..1] += sigma1(X[14..15]) + '&vpshufd ($t3,@X[0],0b01010000)',# X[16..17] + '&vpsrld ($t2,$t3,10);', + '&vpsrlq ($t1,$t3,17);', + '&vpxor ($t2,$t2,$t1);', + '&vpsrlq ($t3,$t3,19);', + '&vpxor ($t2,$t2,$t3);', # sigma1(X[16..17] + '&vpshufd ($t3,$t2,0b11101000);', + '&vpslldq ($t3,$t3,8);', + '&vpaddd (@X[0],@X[0],$t3);' # X[2..3] += sigma1(X[16..17]) + ); +} + +local *ror = sub { &shrd(@_[0],@_) }; +sub AVX_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body,&$body,&$body); # 120 instructions +my $insn; + + foreach (Xupdate_AVX()) { # 31 instructions + eval; + eval(shift(@insns)); + eval(shift(@insns)); + eval($insn = shift(@insns)); + eval(shift(@insns)) if ($insn =~ /rorx/ && @insns[0] =~ /rorx/); + } + &vpaddd ($t2,@X[0],&QWP(16*$j,$K256)); + foreach (@insns) { eval; } # remaining instructions + &vmovdqa (&QWP(32+16*$j,"esp"),$t2); +} + + for ($i=0,$j=0; $j<4; $j++) { + &AVX_00_47($j,\&body_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmp (&DWP(16*$j,$K256),0x00010203); + &jne (&label("avx_00_47")); + + for ($i=0; $i<16; ) { + foreach(body_00_15()) { eval; } + } + + &mov ("esi",&DWP(96,"esp")); #ctx + #&mov ($AH[0],&DWP(0,"esp")); + &xor ($AH[1],"edi"); #&mov ($AH[1],&DWP(4,"esp")); + #&mov ("edi", &DWP(8,"esp")); + &mov ("ecx",&DWP(12,"esp")); + &add ($AH[0],&DWP(0,"esi")); + &add ($AH[1],&DWP(4,"esi")); + &add ("edi",&DWP(8,"esi")); + &add ("ecx",&DWP(12,"esi")); + &mov (&DWP(0,"esi"),$AH[0]); + &mov (&DWP(4,"esi"),$AH[1]); + &mov (&DWP(8,"esi"),"edi"); + &mov (&DWP(12,"esi"),"ecx"); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"edi"); # magic + &mov (&DWP(8,"esp"),"edi"); + &mov (&DWP(12,"esp"),"ecx"); + #&mov ($E,&DWP(16,"esp")); + &mov ("edi",&DWP(20,"esp")); + &mov ("ecx",&DWP(24,"esp")); + &add ($E,&DWP(16,"esi")); + &add ("edi",&DWP(20,"esi")); + &add ("ecx",&DWP(24,"esi")); + &mov (&DWP(16,"esi"),$E); + &mov (&DWP(20,"esi"),"edi"); + &mov (&DWP(20,"esp"),"edi"); + &mov ("edi",&DWP(28,"esp")); + &mov (&DWP(24,"esi"),"ecx"); + #&mov (&DWP(16,"esp"),$E); + &add ("edi",&DWP(28,"esi")); + &mov (&DWP(24,"esp"),"ecx"); + &mov (&DWP(28,"esi"),"edi"); + &mov (&DWP(28,"esp"),"edi"); + &mov ("edi",&DWP(96+4,"esp")); # inp + + &vmovdqa ($t3,&QWP(64,$K256)); + &sub ($K256,3*64); # rewind K + &cmp ("edi",&DWP(96+8,"esp")); # are we done yet? + &jb (&label("grand_avx")); + + &mov ("esp",&DWP(96+12,"esp")); # restore sp + &vzeroall (); +&function_end_A(); + if ($avx>1) { +sub bodyx_00_15 () { # +10% + ( + '&rorx ("ecx",$E,6)', + '&rorx ("esi",$E,11)', + '&mov (&off($e),$E)', # save $E, modulo-scheduled + '&rorx ("edi",$E,25)', + '&xor ("ecx","esi")', + '&andn ("esi",$E,&off($g))', + '&xor ("ecx","edi")', # Sigma1(e) + '&and ($E,&off($f))', + '&mov (&off($a),$AH[0]);', # save $A, modulo-scheduled + '&or ($E,"esi")', # T = Ch(e,f,g) + + '&rorx ("edi",$AH[0],2)', + '&rorx ("esi",$AH[0],13)', + '&lea ($E,&DWP(0,$E,"ecx"))', # T += Sigma1(e) + '&rorx ("ecx",$AH[0],22)', + '&xor ("esi","edi")', + '&mov ("edi",&off($b))', + '&xor ("ecx","esi")', # Sigma0(a) + + '&xor ($AH[0],"edi")', # a ^= b, (b^c) in next round + '&add ($E,&off($h))', # T += h + '&and ($AH[1],$AH[0])', # (b^c) &= (a^b) + '&add ($E,&DWP(32+4*($i&15),"esp"))', # T += K[i]+X[i] + '&xor ($AH[1],"edi")', # h = Maj(a,b,c) = Ch(a^b,c,b) + + '&add ("ecx",$E)', # h += T + '&add ($E,&off($d))', # d += T + '&lea ($AH[1],&DWP(0,$AH[1],"ecx"));'. # h += Sigma0(a) + + '@AH = reverse(@AH); $i++;' # rotate(a,h) + ); +} + +&set_label("AVX_BMI",32); + &lea ("esp",&DWP(-96,"esp")); + &vzeroall (); + # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack + &mov ($AH[0],&DWP(0,"esi")); + &mov ($AH[1],&DWP(4,"esi")); + &mov ("ecx",&DWP(8,"esi")); + &mov ("edi",&DWP(12,"esi")); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"ecx"); # magic + &mov (&DWP(8,"esp"),"ecx"); + &mov (&DWP(12,"esp"),"edi"); + &mov ($E,&DWP(16,"esi")); + &mov ("edi",&DWP(20,"esi")); + &mov ("ecx",&DWP(24,"esi")); + &mov ("esi",&DWP(28,"esi")); + #&mov (&DWP(16,"esp"),$E); + &mov (&DWP(20,"esp"),"edi"); + &mov ("edi",&DWP(96+4,"esp")); # inp + &mov (&DWP(24,"esp"),"ecx"); + &mov (&DWP(28,"esp"),"esi"); + &vmovdqa ($t3,&QWP(256,$K256)); + &jmp (&label("grand_avx_bmi")); + +&set_label("grand_avx_bmi",32); + # load input, reverse byte order, add K256[0..15], save to stack + &vmovdqu (@X[0],&QWP(0,"edi")); + &vmovdqu (@X[1],&QWP(16,"edi")); + &vmovdqu (@X[2],&QWP(32,"edi")); + &vmovdqu (@X[3],&QWP(48,"edi")); + &add ("edi",64); + &vpshufb (@X[0],@X[0],$t3); + &mov (&DWP(96+4,"esp"),"edi"); + &vpshufb (@X[1],@X[1],$t3); + &vpshufb (@X[2],@X[2],$t3); + &vpaddd ($t0,@X[0],&QWP(0,$K256)); + &vpshufb (@X[3],@X[3],$t3); + &vpaddd ($t1,@X[1],&QWP(16,$K256)); + &vpaddd ($t2,@X[2],&QWP(32,$K256)); + &vpaddd ($t3,@X[3],&QWP(48,$K256)); + &vmovdqa (&QWP(32+0,"esp"),$t0); + &vmovdqa (&QWP(32+16,"esp"),$t1); + &vmovdqa (&QWP(32+32,"esp"),$t2); + &vmovdqa (&QWP(32+48,"esp"),$t3); + &jmp (&label("avx_bmi_00_47")); + +&set_label("avx_bmi_00_47",16); + &add ($K256,64); + + for ($i=0,$j=0; $j<4; $j++) { + &AVX_00_47($j,\&bodyx_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmp (&DWP(16*$j,$K256),0x00010203); + &jne (&label("avx_bmi_00_47")); + + for ($i=0; $i<16; ) { + foreach(bodyx_00_15()) { eval; } + } + + &mov ("esi",&DWP(96,"esp")); #ctx + #&mov ($AH[0],&DWP(0,"esp")); + &xor ($AH[1],"edi"); #&mov ($AH[1],&DWP(4,"esp")); + #&mov ("edi", &DWP(8,"esp")); + &mov ("ecx",&DWP(12,"esp")); + &add ($AH[0],&DWP(0,"esi")); + &add ($AH[1],&DWP(4,"esi")); + &add ("edi",&DWP(8,"esi")); + &add ("ecx",&DWP(12,"esi")); + &mov (&DWP(0,"esi"),$AH[0]); + &mov (&DWP(4,"esi"),$AH[1]); + &mov (&DWP(8,"esi"),"edi"); + &mov (&DWP(12,"esi"),"ecx"); + #&mov (&DWP(0,"esp"),$AH[0]); + &mov (&DWP(4,"esp"),$AH[1]); + &xor ($AH[1],"edi"); # magic + &mov (&DWP(8,"esp"),"edi"); + &mov (&DWP(12,"esp"),"ecx"); + #&mov ($E,&DWP(16,"esp")); + &mov ("edi",&DWP(20,"esp")); + &mov ("ecx",&DWP(24,"esp")); + &add ($E,&DWP(16,"esi")); + &add ("edi",&DWP(20,"esi")); + &add ("ecx",&DWP(24,"esi")); + &mov (&DWP(16,"esi"),$E); + &mov (&DWP(20,"esi"),"edi"); + &mov (&DWP(20,"esp"),"edi"); + &mov ("edi",&DWP(28,"esp")); + &mov (&DWP(24,"esi"),"ecx"); + #&mov (&DWP(16,"esp"),$E); + &add ("edi",&DWP(28,"esi")); + &mov (&DWP(24,"esp"),"ecx"); + &mov (&DWP(28,"esi"),"edi"); + &mov (&DWP(28,"esp"),"edi"); + &mov ("edi",&DWP(96+4,"esp")); # inp + + &vmovdqa ($t3,&QWP(64,$K256)); + &sub ($K256,3*64); # rewind K + &cmp ("edi",&DWP(96+8,"esp")); # are we done yet? + &jb (&label("grand_avx_bmi")); + + &mov ("esp",&DWP(96+12,"esp")); # restore sp + &vzeroall (); +&function_end_A(); + } + } + }}} +&function_end_B("sha256_block_data_order"); + +&asm_finish(); diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha256-armv4.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha256-armv4.pl new file mode 100644 index 00000000..df71676d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha256-armv4.pl @@ -0,0 +1,735 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# +# Permission to use under GPL terms is granted. +# ==================================================================== + +# SHA256 block procedure for ARMv4. May 2007. + +# Performance is ~2x better than gcc 3.4 generated code and in "abso- +# lute" terms is ~2250 cycles per 64-byte block or ~35 cycles per +# byte [on single-issue Xscale PXA250 core]. + +# July 2010. +# +# Rescheduling for dual-issue pipeline resulted in 22% improvement on +# Cortex A8 core and ~20 cycles per processed byte. + +# February 2011. +# +# Profiler-assisted and platform-specific optimization resulted in 16% +# improvement on Cortex A8 core and ~15.4 cycles per processed byte. + +# September 2013. +# +# Add NEON implementation. On Cortex A8 it was measured to process one +# byte in 12.5 cycles or 23% faster than integer-only code. Snapdragon +# S4 does it in 12.5 cycles too, but it's 50% faster than integer-only +# code (meaning that latter performs sub-optimally, nothing was done +# about it). + +# May 2014. +# +# Add ARMv8 code path performing at 2.0 cpb on Apple A7. + +$flavour = shift; +if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } +else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} } + +if ($flavour && $flavour ne "void") { + $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; + ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or + ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or + die "can't locate arm-xlate.pl"; + + open STDOUT,"| \"$^X\" $xlate $flavour $output"; +} else { + open STDOUT,">$output"; +} + +$ctx="r0"; $t0="r0"; +$inp="r1"; $t4="r1"; +$len="r2"; $t1="r2"; +$T1="r3"; $t3="r3"; +$A="r4"; +$B="r5"; +$C="r6"; +$D="r7"; +$E="r8"; +$F="r9"; +$G="r10"; +$H="r11"; +@V=($A,$B,$C,$D,$E,$F,$G,$H); +$t2="r12"; +$Ktbl="r14"; + +@Sigma0=( 2,13,22); +@Sigma1=( 6,11,25); +@sigma0=( 7,18, 3); +@sigma1=(17,19,10); + +sub BODY_00_15 { +my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_; + +$code.=<<___ if ($i<16); +#if __ARM_ARCH__>=7 + @ ldr $t1,[$inp],#4 @ $i +# if $i==15 + str $inp,[sp,#17*4] @ make room for $t4 +# endif + eor $t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]` + add $a,$a,$t2 @ h+=Maj(a,b,c) from the past + eor $t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]` @ Sigma1(e) +# ifndef __ARMEB__ + rev $t1,$t1 +# endif +#else + @ ldrb $t1,[$inp,#3] @ $i + add $a,$a,$t2 @ h+=Maj(a,b,c) from the past + ldrb $t2,[$inp,#2] + ldrb $t0,[$inp,#1] + orr $t1,$t1,$t2,lsl#8 + ldrb $t2,[$inp],#4 + orr $t1,$t1,$t0,lsl#16 +# if $i==15 + str $inp,[sp,#17*4] @ make room for $t4 +# endif + eor $t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]` + orr $t1,$t1,$t2,lsl#24 + eor $t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]` @ Sigma1(e) +#endif +___ +$code.=<<___; + ldr $t2,[$Ktbl],#4 @ *K256++ + add $h,$h,$t1 @ h+=X[i] + str $t1,[sp,#`$i%16`*4] + eor $t1,$f,$g + add $h,$h,$t0,ror#$Sigma1[0] @ h+=Sigma1(e) + and $t1,$t1,$e + add $h,$h,$t2 @ h+=K256[i] + eor $t1,$t1,$g @ Ch(e,f,g) + eor $t0,$a,$a,ror#`$Sigma0[1]-$Sigma0[0]` + add $h,$h,$t1 @ h+=Ch(e,f,g) +#if $i==31 + and $t2,$t2,#0xff + cmp $t2,#0xf2 @ done? +#endif +#if $i<15 +# if __ARM_ARCH__>=7 + ldr $t1,[$inp],#4 @ prefetch +# else + ldrb $t1,[$inp,#3] +# endif + eor $t2,$a,$b @ a^b, b^c in next round +#else + ldr $t1,[sp,#`($i+2)%16`*4] @ from future BODY_16_xx + eor $t2,$a,$b @ a^b, b^c in next round + ldr $t4,[sp,#`($i+15)%16`*4] @ from future BODY_16_xx +#endif + eor $t0,$t0,$a,ror#`$Sigma0[2]-$Sigma0[0]` @ Sigma0(a) + and $t3,$t3,$t2 @ (b^c)&=(a^b) + add $d,$d,$h @ d+=h + eor $t3,$t3,$b @ Maj(a,b,c) + add $h,$h,$t0,ror#$Sigma0[0] @ h+=Sigma0(a) + @ add $h,$h,$t3 @ h+=Maj(a,b,c) +___ + ($t2,$t3)=($t3,$t2); +} + +sub BODY_16_XX { +my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_; + +$code.=<<___; + @ ldr $t1,[sp,#`($i+1)%16`*4] @ $i + @ ldr $t4,[sp,#`($i+14)%16`*4] + mov $t0,$t1,ror#$sigma0[0] + add $a,$a,$t2 @ h+=Maj(a,b,c) from the past + mov $t2,$t4,ror#$sigma1[0] + eor $t0,$t0,$t1,ror#$sigma0[1] + eor $t2,$t2,$t4,ror#$sigma1[1] + eor $t0,$t0,$t1,lsr#$sigma0[2] @ sigma0(X[i+1]) + ldr $t1,[sp,#`($i+0)%16`*4] + eor $t2,$t2,$t4,lsr#$sigma1[2] @ sigma1(X[i+14]) + ldr $t4,[sp,#`($i+9)%16`*4] + + add $t2,$t2,$t0 + eor $t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]` @ from BODY_00_15 + add $t1,$t1,$t2 + eor $t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]` @ Sigma1(e) + add $t1,$t1,$t4 @ X[i] +___ + &BODY_00_15(@_); +} + +$code=<<___; +#ifndef __KERNEL__ +# include "arm_arch.h" +#else +# define __ARM_ARCH__ __LINUX_ARM_ARCH__ +# define __ARM_MAX_ARCH__ 7 +#endif + +.text +#if __ARM_ARCH__<7 +.code 32 +#else +.syntax unified +# if defined(__thumb2__) && !defined(__APPLE__) +# define adrl adr +.thumb +# else +.code 32 +# endif +#endif + +.type K256,%object +.align 5 +K256: +.word 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5 +.word 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5 +.word 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3 +.word 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174 +.word 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc +.word 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da +.word 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7 +.word 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967 +.word 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13 +.word 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85 +.word 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3 +.word 0xd192e819,0xd6990624,0xf40e3585,0x106aa070 +.word 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5 +.word 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3 +.word 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208 +.word 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 +.size K256,.-K256 +.word 0 @ terminator +#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) +.LOPENSSL_armcap: +.word OPENSSL_armcap_P-.Lsha256_block_data_order +#endif +.align 5 + +.global sha256_block_data_order +.type sha256_block_data_order,%function +sha256_block_data_order: +.Lsha256_block_data_order: +#if __ARM_ARCH__<7 + sub r3,pc,#8 @ sha256_block_data_order +#else + adr r3,sha256_block_data_order +#endif +#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) + ldr r12,.LOPENSSL_armcap + ldr r12,[r3,r12] @ OPENSSL_armcap_P +#ifdef __APPLE__ + ldr r12,[r12] +#endif + tst r12,#ARMV8_SHA256 + bne .LARMv8 + tst r12,#ARMV7_NEON + bne .LNEON +#endif + add $len,$inp,$len,lsl#6 @ len to point at the end of inp + stmdb sp!,{$ctx,$inp,$len,r4-r11,lr} + ldmia $ctx,{$A,$B,$C,$D,$E,$F,$G,$H} + sub $Ktbl,r3,#256+32 @ K256 + sub sp,sp,#16*4 @ alloca(X[16]) +.Loop: +# if __ARM_ARCH__>=7 + ldr $t1,[$inp],#4 +# else + ldrb $t1,[$inp,#3] +# endif + eor $t3,$B,$C @ magic + eor $t2,$t2,$t2 +___ +for($i=0;$i<16;$i++) { &BODY_00_15($i,@V); unshift(@V,pop(@V)); } +$code.=".Lrounds_16_xx:\n"; +for (;$i<32;$i++) { &BODY_16_XX($i,@V); unshift(@V,pop(@V)); } +$code.=<<___; +#if __ARM_ARCH__>=7 + ite eq @ Thumb2 thing, sanity check in ARM +#endif + ldreq $t3,[sp,#16*4] @ pull ctx + bne .Lrounds_16_xx + + add $A,$A,$t2 @ h+=Maj(a,b,c) from the past + ldr $t0,[$t3,#0] + ldr $t1,[$t3,#4] + ldr $t2,[$t3,#8] + add $A,$A,$t0 + ldr $t0,[$t3,#12] + add $B,$B,$t1 + ldr $t1,[$t3,#16] + add $C,$C,$t2 + ldr $t2,[$t3,#20] + add $D,$D,$t0 + ldr $t0,[$t3,#24] + add $E,$E,$t1 + ldr $t1,[$t3,#28] + add $F,$F,$t2 + ldr $inp,[sp,#17*4] @ pull inp + ldr $t2,[sp,#18*4] @ pull inp+len + add $G,$G,$t0 + add $H,$H,$t1 + stmia $t3,{$A,$B,$C,$D,$E,$F,$G,$H} + cmp $inp,$t2 + sub $Ktbl,$Ktbl,#256 @ rewind Ktbl + bne .Loop + + add sp,sp,#`16+3`*4 @ destroy frame +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r11,pc} +#else + ldmia sp!,{r4-r11,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size sha256_block_data_order,.-sha256_block_data_order +___ +###################################################################### +# NEON stuff +# +{{{ +my @X=map("q$_",(0..3)); +my ($T0,$T1,$T2,$T3,$T4,$T5)=("q8","q9","q10","q11","d24","d25"); +my $Xfer=$t4; +my $j=0; + +sub Dlo() { shift=~m|q([1]?[0-9])|?"d".($1*2):""; } +sub Dhi() { shift=~m|q([1]?[0-9])|?"d".($1*2+1):""; } + +sub AUTOLOAD() # thunk [simplified] x86-style perlasm +{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./; + my $arg = pop; + $arg = "#$arg" if ($arg*1 eq $arg); + $code .= "\t$opcode\t".join(',',@_,$arg)."\n"; +} + +sub Xupdate() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); + my ($a,$b,$c,$d,$e,$f,$g,$h); + + &vext_8 ($T0,@X[0],@X[1],4); # X[1..4] + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vext_8 ($T1,@X[2],@X[3],4); # X[9..12] + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T2,$T0,$sigma0[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (@X[0],@X[0],$T1); # X[0..3] += X[9..12] + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T1,$T0,$sigma0[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vsli_32 ($T2,$T0,32-$sigma0[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T3,$T0,$sigma0[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &veor ($T1,$T1,$T2); + eval(shift(@insns)); + eval(shift(@insns)); + &vsli_32 ($T3,$T0,32-$sigma0[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T4,&Dhi(@X[3]),$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &veor ($T1,$T1,$T3); # sigma0(X[1..4]) + eval(shift(@insns)); + eval(shift(@insns)); + &vsli_32 ($T4,&Dhi(@X[3]),32-$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T5,&Dhi(@X[3]),$sigma1[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (@X[0],@X[0],$T1); # X[0..3] += sigma0(X[1..4]) + eval(shift(@insns)); + eval(shift(@insns)); + &veor ($T5,$T5,$T4); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T4,&Dhi(@X[3]),$sigma1[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vsli_32 ($T4,&Dhi(@X[3]),32-$sigma1[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &veor ($T5,$T5,$T4); # sigma1(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (&Dlo(@X[0]),&Dlo(@X[0]),$T5);# X[0..1] += sigma1(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T4,&Dlo(@X[0]),$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vsli_32 ($T4,&Dlo(@X[0]),32-$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T5,&Dlo(@X[0]),$sigma1[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &veor ($T5,$T5,$T4); + eval(shift(@insns)); + eval(shift(@insns)); + &vshr_u32 ($T4,&Dlo(@X[0]),$sigma1[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vld1_32 ("{$T0}","[$Ktbl,:128]!"); + eval(shift(@insns)); + eval(shift(@insns)); + &vsli_32 ($T4,&Dlo(@X[0]),32-$sigma1[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &veor ($T5,$T5,$T4); # sigma1(X[16..17]) + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 (&Dhi(@X[0]),&Dhi(@X[0]),$T5);# X[2..3] += sigma1(X[16..17]) + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 ($T0,$T0,@X[0]); + while($#insns>=2) { eval(shift(@insns)); } + &vst1_32 ("{$T0}","[$Xfer,:128]!"); + eval(shift(@insns)); + eval(shift(@insns)); + + push(@X,shift(@X)); # "rotate" X[] +} + +sub Xpreload() +{ use integer; + my $body = shift; + my @insns = (&$body,&$body,&$body,&$body); + my ($a,$b,$c,$d,$e,$f,$g,$h); + + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vld1_32 ("{$T0}","[$Ktbl,:128]!"); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vrev32_8 (@X[0],@X[0]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vadd_i32 ($T0,$T0,@X[0]); + foreach (@insns) { eval; } # remaining instructions + &vst1_32 ("{$T0}","[$Xfer,:128]!"); + + push(@X,shift(@X)); # "rotate" X[] +} + +sub body_00_15 () { + ( + '($a,$b,$c,$d,$e,$f,$g,$h)=@V;'. + '&add ($h,$h,$t1)', # h+=X[i]+K[i] + '&eor ($t1,$f,$g)', + '&eor ($t0,$e,$e,"ror#".($Sigma1[1]-$Sigma1[0]))', + '&add ($a,$a,$t2)', # h+=Maj(a,b,c) from the past + '&and ($t1,$t1,$e)', + '&eor ($t2,$t0,$e,"ror#".($Sigma1[2]-$Sigma1[0]))', # Sigma1(e) + '&eor ($t0,$a,$a,"ror#".($Sigma0[1]-$Sigma0[0]))', + '&eor ($t1,$t1,$g)', # Ch(e,f,g) + '&add ($h,$h,$t2,"ror#$Sigma1[0]")', # h+=Sigma1(e) + '&eor ($t2,$a,$b)', # a^b, b^c in next round + '&eor ($t0,$t0,$a,"ror#".($Sigma0[2]-$Sigma0[0]))', # Sigma0(a) + '&add ($h,$h,$t1)', # h+=Ch(e,f,g) + '&ldr ($t1,sprintf "[sp,#%d]",4*(($j+1)&15)) if (($j&15)!=15);'. + '&ldr ($t1,"[$Ktbl]") if ($j==15);'. + '&ldr ($t1,"[sp,#64]") if ($j==31)', + '&and ($t3,$t3,$t2)', # (b^c)&=(a^b) + '&add ($d,$d,$h)', # d+=h + '&add ($h,$h,$t0,"ror#$Sigma0[0]");'. # h+=Sigma0(a) + '&eor ($t3,$t3,$b)', # Maj(a,b,c) + '$j++; unshift(@V,pop(@V)); ($t2,$t3)=($t3,$t2);' + ) +} + +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.global sha256_block_data_order_neon +.type sha256_block_data_order_neon,%function +.align 4 +sha256_block_data_order_neon: +.LNEON: + stmdb sp!,{r4-r12,lr} + + sub $H,sp,#16*4+16 + adrl $Ktbl,K256 + bic $H,$H,#15 @ align for 128-bit stores + mov $t2,sp + mov sp,$H @ alloca + add $len,$inp,$len,lsl#6 @ len to point at the end of inp + + vld1.8 {@X[0]},[$inp]! + vld1.8 {@X[1]},[$inp]! + vld1.8 {@X[2]},[$inp]! + vld1.8 {@X[3]},[$inp]! + vld1.32 {$T0},[$Ktbl,:128]! + vld1.32 {$T1},[$Ktbl,:128]! + vld1.32 {$T2},[$Ktbl,:128]! + vld1.32 {$T3},[$Ktbl,:128]! + vrev32.8 @X[0],@X[0] @ yes, even on + str $ctx,[sp,#64] + vrev32.8 @X[1],@X[1] @ big-endian + str $inp,[sp,#68] + mov $Xfer,sp + vrev32.8 @X[2],@X[2] + str $len,[sp,#72] + vrev32.8 @X[3],@X[3] + str $t2,[sp,#76] @ save original sp + vadd.i32 $T0,$T0,@X[0] + vadd.i32 $T1,$T1,@X[1] + vst1.32 {$T0},[$Xfer,:128]! + vadd.i32 $T2,$T2,@X[2] + vst1.32 {$T1},[$Xfer,:128]! + vadd.i32 $T3,$T3,@X[3] + vst1.32 {$T2},[$Xfer,:128]! + vst1.32 {$T3},[$Xfer,:128]! + + ldmia $ctx,{$A-$H} + sub $Xfer,$Xfer,#64 + ldr $t1,[sp,#0] + eor $t2,$t2,$t2 + eor $t3,$B,$C + b .L_00_48 + +.align 4 +.L_00_48: +___ + &Xupdate(\&body_00_15); + &Xupdate(\&body_00_15); + &Xupdate(\&body_00_15); + &Xupdate(\&body_00_15); +$code.=<<___; + teq $t1,#0 @ check for K256 terminator + ldr $t1,[sp,#0] + sub $Xfer,$Xfer,#64 + bne .L_00_48 + + ldr $inp,[sp,#68] + ldr $t0,[sp,#72] + sub $Ktbl,$Ktbl,#256 @ rewind $Ktbl + teq $inp,$t0 + it eq + subeq $inp,$inp,#64 @ avoid SEGV + vld1.8 {@X[0]},[$inp]! @ load next input block + vld1.8 {@X[1]},[$inp]! + vld1.8 {@X[2]},[$inp]! + vld1.8 {@X[3]},[$inp]! + it ne + strne $inp,[sp,#68] + mov $Xfer,sp +___ + &Xpreload(\&body_00_15); + &Xpreload(\&body_00_15); + &Xpreload(\&body_00_15); + &Xpreload(\&body_00_15); +$code.=<<___; + ldr $t0,[$t1,#0] + add $A,$A,$t2 @ h+=Maj(a,b,c) from the past + ldr $t2,[$t1,#4] + ldr $t3,[$t1,#8] + ldr $t4,[$t1,#12] + add $A,$A,$t0 @ accumulate + ldr $t0,[$t1,#16] + add $B,$B,$t2 + ldr $t2,[$t1,#20] + add $C,$C,$t3 + ldr $t3,[$t1,#24] + add $D,$D,$t4 + ldr $t4,[$t1,#28] + add $E,$E,$t0 + str $A,[$t1],#4 + add $F,$F,$t2 + str $B,[$t1],#4 + add $G,$G,$t3 + str $C,[$t1],#4 + add $H,$H,$t4 + str $D,[$t1],#4 + stmia $t1,{$E-$H} + + ittte ne + movne $Xfer,sp + ldrne $t1,[sp,#0] + eorne $t2,$t2,$t2 + ldreq sp,[sp,#76] @ restore original sp + itt ne + eorne $t3,$B,$C + bne .L_00_48 + + ldmia sp!,{r4-r12,pc} +.size sha256_block_data_order_neon,.-sha256_block_data_order_neon +#endif +___ +}}} +###################################################################### +# ARMv8 stuff +# +{{{ +my ($ABCD,$EFGH,$abcd)=map("q$_",(0..2)); +my @MSG=map("q$_",(8..11)); +my ($W0,$W1,$ABCD_SAVE,$EFGH_SAVE)=map("q$_",(12..15)); +my $Ktbl="r3"; + +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) + +# if defined(__thumb2__) && !defined(__APPLE__) +# define INST(a,b,c,d) .byte c,d|0xc,a,b +# else +# define INST(a,b,c,d) .byte a,b,c,d +# endif + +.type sha256_block_data_order_armv8,%function +.align 5 +sha256_block_data_order_armv8: +.LARMv8: + vld1.32 {$ABCD,$EFGH},[$ctx] +# ifdef __APPLE__ + sub $Ktbl,$Ktbl,#256+32 +# elif defined(__thumb2__) + adr $Ktbl,.LARMv8 + sub $Ktbl,$Ktbl,#.LARMv8-K256 +# else + adrl $Ktbl,K256 +# endif + add $len,$inp,$len,lsl#6 @ len to point at the end of inp + +.Loop_v8: + vld1.8 {@MSG[0]-@MSG[1]},[$inp]! + vld1.8 {@MSG[2]-@MSG[3]},[$inp]! + vld1.32 {$W0},[$Ktbl]! + vrev32.8 @MSG[0],@MSG[0] + vrev32.8 @MSG[1],@MSG[1] + vrev32.8 @MSG[2],@MSG[2] + vrev32.8 @MSG[3],@MSG[3] + vmov $ABCD_SAVE,$ABCD @ offload + vmov $EFGH_SAVE,$EFGH + teq $inp,$len +___ +for($i=0;$i<12;$i++) { +$code.=<<___; + vld1.32 {$W1},[$Ktbl]! + vadd.i32 $W0,$W0,@MSG[0] + sha256su0 @MSG[0],@MSG[1] + vmov $abcd,$ABCD + sha256h $ABCD,$EFGH,$W0 + sha256h2 $EFGH,$abcd,$W0 + sha256su1 @MSG[0],@MSG[2],@MSG[3] +___ + ($W0,$W1)=($W1,$W0); push(@MSG,shift(@MSG)); +} +$code.=<<___; + vld1.32 {$W1},[$Ktbl]! + vadd.i32 $W0,$W0,@MSG[0] + vmov $abcd,$ABCD + sha256h $ABCD,$EFGH,$W0 + sha256h2 $EFGH,$abcd,$W0 + + vld1.32 {$W0},[$Ktbl]! + vadd.i32 $W1,$W1,@MSG[1] + vmov $abcd,$ABCD + sha256h $ABCD,$EFGH,$W1 + sha256h2 $EFGH,$abcd,$W1 + + vld1.32 {$W1},[$Ktbl] + vadd.i32 $W0,$W0,@MSG[2] + sub $Ktbl,$Ktbl,#256-16 @ rewind + vmov $abcd,$ABCD + sha256h $ABCD,$EFGH,$W0 + sha256h2 $EFGH,$abcd,$W0 + + vadd.i32 $W1,$W1,@MSG[3] + vmov $abcd,$ABCD + sha256h $ABCD,$EFGH,$W1 + sha256h2 $EFGH,$abcd,$W1 + + vadd.i32 $ABCD,$ABCD,$ABCD_SAVE + vadd.i32 $EFGH,$EFGH,$EFGH_SAVE + it ne + bne .Loop_v8 + + vst1.32 {$ABCD,$EFGH},[$ctx] + + ret @ bx lr +.size sha256_block_data_order_armv8,.-sha256_block_data_order_armv8 +#endif +___ +}}} +$code.=<<___; +.asciz "SHA256 block transform for ARMv4/NEON/ARMv8, CRYPTOGAMS by " +.align 2 +#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) +.comm OPENSSL_armcap_P,4,4 +.hidden OPENSSL_armcap_P +#endif +___ + +open SELF,$0; +while() { + next if (/^#!/); + last if (!s/^#/@/ and !/^$/); + print; +} +close SELF; + +{ my %opcode = ( + "sha256h" => 0xf3000c40, "sha256h2" => 0xf3100c40, + "sha256su0" => 0xf3ba03c0, "sha256su1" => 0xf3200c40 ); + + sub unsha256 { + my ($mnemonic,$arg)=@_; + + if ($arg =~ m/q([0-9]+)(?:,\s*q([0-9]+))?,\s*q([0-9]+)/o) { + my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19) + |(($2&7)<<17)|(($2&8)<<4) + |(($3&7)<<1) |(($3&8)<<2); + # since ARMv7 instructions are always encoded little-endian. + # correct solution is to use .inst directive, but older + # assemblers don't implement it:-( + sprintf "INST(0x%02x,0x%02x,0x%02x,0x%02x)\t@ %s %s", + $word&0xff,($word>>8)&0xff, + ($word>>16)&0xff,($word>>24)&0xff, + $mnemonic,$arg; + } + } +} + +foreach (split($/,$code)) { + + s/\`([^\`]*)\`/eval $1/geo; + + s/\b(sha256\w+)\s+(q.*)/unsha256($1,$2)/geo; + + s/\bret\b/bx lr/go or + s/\bbx\s+lr\b/.word\t0xe12fff1e/go; # make it possible to compile with -march=armv4 + + print $_,"\n"; +} + +close STDOUT; # enforce flush diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-586.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-586.pl new file mode 100644 index 00000000..2f6a202c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-586.pl @@ -0,0 +1,911 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# SHA512 block transform for x86. September 2007. +# +# May 2013. +# +# Add SSSE3 code path, 20-25% improvement [over original SSE2 code]. +# +# Performance in clock cycles per processed byte (less is better): +# +# gcc icc x86 asm SIMD(*) x86_64(**) +# Pentium 100 97 61 - - +# PIII 75 77 56 - - +# P4 116 95 82 34.6 30.8 +# AMD K8 54 55 36 20.7 9.57 +# Core2 66 57 40 15.9 9.97 +# Westmere 70 - 38 12.2 9.58 +# Sandy Bridge 58 - 35 11.9 11.2 +# Ivy Bridge 50 - 33 11.5 8.17 +# Haswell 46 - 29 11.3 7.66 +# Bulldozer 121 - 50 14.0 13.5 +# VIA Nano 91 - 52 33 14.7 +# Atom 126 - 68 48(***) 14.7 +# Silvermont 97 - 58 42(***) 17.5 +# +# (*) whichever best applicable. +# (**) x86_64 assembler performance is presented for reference +# purposes, the results are for integer-only code. +# (***) paddq is increadibly slow on Atom. +# +# IALU code-path is optimized for elder Pentiums. On vanilla Pentium +# performance improvement over compiler generated code reaches ~60%, +# while on PIII - ~35%. On newer µ-archs improvement varies from 15% +# to 50%, but it's less important as they are expected to execute SSE2 +# code-path, which is commonly ~2-3x faster [than compiler generated +# code]. SSE2 code-path is as fast as original sha512-sse2.pl, even +# though it does not use 128-bit operations. The latter means that +# SSE2-aware kernel is no longer required to execute the code. Another +# difference is that new code optimizes amount of writes, but at the +# cost of increased data cache "footprint" by 1/2KB. + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +push(@INC,"${dir}","${dir}../../perlasm"); +require "x86asm.pl"; + +&asm_init($ARGV[0],"sha512-586.pl",$ARGV[$#ARGV] eq "386"); + +$sse2=0; +for (@ARGV) { $sse2=1 if (/-DOPENSSL_IA32_SSE2/); } + +&external_label("OPENSSL_ia32cap_P") if ($sse2); + +$Tlo=&DWP(0,"esp"); $Thi=&DWP(4,"esp"); +$Alo=&DWP(8,"esp"); $Ahi=&DWP(8+4,"esp"); +$Blo=&DWP(16,"esp"); $Bhi=&DWP(16+4,"esp"); +$Clo=&DWP(24,"esp"); $Chi=&DWP(24+4,"esp"); +$Dlo=&DWP(32,"esp"); $Dhi=&DWP(32+4,"esp"); +$Elo=&DWP(40,"esp"); $Ehi=&DWP(40+4,"esp"); +$Flo=&DWP(48,"esp"); $Fhi=&DWP(48+4,"esp"); +$Glo=&DWP(56,"esp"); $Ghi=&DWP(56+4,"esp"); +$Hlo=&DWP(64,"esp"); $Hhi=&DWP(64+4,"esp"); +$K512="ebp"; + +$Asse2=&QWP(0,"esp"); +$Bsse2=&QWP(8,"esp"); +$Csse2=&QWP(16,"esp"); +$Dsse2=&QWP(24,"esp"); +$Esse2=&QWP(32,"esp"); +$Fsse2=&QWP(40,"esp"); +$Gsse2=&QWP(48,"esp"); +$Hsse2=&QWP(56,"esp"); + +$A="mm0"; # B-D and +$E="mm4"; # F-H are commonly loaded to respectively mm1-mm3 and + # mm5-mm7, but it's done on on-demand basis... +$BxC="mm2"; # ... except for B^C + +sub BODY_00_15_sse2 { + my $phase=shift; + + #&movq ("mm5",$Fsse2); # load f + #&movq ("mm6",$Gsse2); # load g + + &movq ("mm1",$E); # %mm1 is sliding right + &pxor ("mm5","mm6"); # f^=g + &psrlq ("mm1",14); + &movq ($Esse2,$E); # modulo-scheduled save e + &pand ("mm5",$E); # f&=e + &psllq ($E,23); # $E is sliding left + &movq ($A,"mm3") if ($phase<2); + &movq (&QWP(8*9,"esp"),"mm7") # save X[i] + &movq ("mm3","mm1"); # %mm3 is T1 + &psrlq ("mm1",4); + &pxor ("mm5","mm6"); # Ch(e,f,g) + &pxor ("mm3",$E); + &psllq ($E,23); + &pxor ("mm3","mm1"); + &movq ($Asse2,$A); # modulo-scheduled save a + &paddq ("mm7","mm5"); # X[i]+=Ch(e,f,g) + &pxor ("mm3",$E); + &psrlq ("mm1",23); + &paddq ("mm7",$Hsse2); # X[i]+=h + &pxor ("mm3","mm1"); + &psllq ($E,4); + &paddq ("mm7",QWP(0,$K512)); # X[i]+=K512[i] + &pxor ("mm3",$E); # T1=Sigma1_512(e) + + &movq ($E,$Dsse2); # e = load d, e in next round + &paddq ("mm3","mm7"); # T1+=X[i] + &movq ("mm5",$A); # %mm5 is sliding right + &psrlq ("mm5",28); + &paddq ($E,"mm3"); # d += T1 + &movq ("mm6",$A); # %mm6 is sliding left + &movq ("mm7","mm5"); + &psllq ("mm6",25); + &movq ("mm1",$Bsse2); # load b + &psrlq ("mm5",6); + &pxor ("mm7","mm6"); + &sub ("esp",8); + &psllq ("mm6",5); + &pxor ("mm7","mm5"); + &pxor ($A,"mm1"); # a^b, b^c in next round + &psrlq ("mm5",5); + &pxor ("mm7","mm6"); + &pand ($BxC,$A); # (b^c)&(a^b) + &psllq ("mm6",6); + &pxor ("mm7","mm5"); + &pxor ($BxC,"mm1"); # [h=]Maj(a,b,c) + &pxor ("mm6","mm7"); # Sigma0_512(a) + &movq ("mm7",&QWP(8*(9+16-1),"esp")) if ($phase!=0); # pre-fetch + &movq ("mm5",$Fsse2) if ($phase==0); # load f + + if ($phase>1) { + &paddq ($BxC,"mm6"); # h+=Sigma0(a) + &add ($K512,8); + #&paddq ($BxC,"mm3"); # h+=T1 + + ($A,$BxC) = ($BxC,$A); # rotate registers + } else { + &paddq ("mm3",$BxC); # T1+=Maj(a,b,c) + &movq ($BxC,$A); + &add ($K512,8); + &paddq ("mm3","mm6"); # T1+=Sigma0(a) + &movq ("mm6",$Gsse2) if ($phase==0); # load g + #&movq ($A,"mm3"); # h=T1 + } +} + +sub BODY_00_15_x86 { + #define Sigma1(x) (ROTR((x),14) ^ ROTR((x),18) ^ ROTR((x),41)) + # LO lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23 + # HI hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23 + &mov ("ecx",$Elo); + &mov ("edx",$Ehi); + &mov ("esi","ecx"); + + &shr ("ecx",9); # lo>>9 + &mov ("edi","edx"); + &shr ("edx",9); # hi>>9 + &mov ("ebx","ecx"); + &shl ("esi",14); # lo<<14 + &mov ("eax","edx"); + &shl ("edi",14); # hi<<14 + &xor ("ebx","esi"); + + &shr ("ecx",14-9); # lo>>14 + &xor ("eax","edi"); + &shr ("edx",14-9); # hi>>14 + &xor ("eax","ecx"); + &shl ("esi",18-14); # lo<<18 + &xor ("ebx","edx"); + &shl ("edi",18-14); # hi<<18 + &xor ("ebx","esi"); + + &shr ("ecx",18-14); # lo>>18 + &xor ("eax","edi"); + &shr ("edx",18-14); # hi>>18 + &xor ("eax","ecx"); + &shl ("esi",23-18); # lo<<23 + &xor ("ebx","edx"); + &shl ("edi",23-18); # hi<<23 + &xor ("eax","esi"); + &xor ("ebx","edi"); # T1 = Sigma1(e) + + &mov ("ecx",$Flo); + &mov ("edx",$Fhi); + &mov ("esi",$Glo); + &mov ("edi",$Ghi); + &add ("eax",$Hlo); + &adc ("ebx",$Hhi); # T1 += h + &xor ("ecx","esi"); + &xor ("edx","edi"); + &and ("ecx",$Elo); + &and ("edx",$Ehi); + &add ("eax",&DWP(8*(9+15)+0,"esp")); + &adc ("ebx",&DWP(8*(9+15)+4,"esp")); # T1 += X[0] + &xor ("ecx","esi"); + &xor ("edx","edi"); # Ch(e,f,g) = (f^g)&e)^g + + &mov ("esi",&DWP(0,$K512)); + &mov ("edi",&DWP(4,$K512)); # K[i] + &add ("eax","ecx"); + &adc ("ebx","edx"); # T1 += Ch(e,f,g) + &mov ("ecx",$Dlo); + &mov ("edx",$Dhi); + &add ("eax","esi"); + &adc ("ebx","edi"); # T1 += K[i] + &mov ($Tlo,"eax"); + &mov ($Thi,"ebx"); # put T1 away + &add ("eax","ecx"); + &adc ("ebx","edx"); # d += T1 + + #define Sigma0(x) (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39)) + # LO lo>>28^hi<<4 ^ hi>>2^lo<<30 ^ hi>>7^lo<<25 + # HI hi>>28^lo<<4 ^ lo>>2^hi<<30 ^ lo>>7^hi<<25 + &mov ("ecx",$Alo); + &mov ("edx",$Ahi); + &mov ($Dlo,"eax"); + &mov ($Dhi,"ebx"); + &mov ("esi","ecx"); + + &shr ("ecx",2); # lo>>2 + &mov ("edi","edx"); + &shr ("edx",2); # hi>>2 + &mov ("ebx","ecx"); + &shl ("esi",4); # lo<<4 + &mov ("eax","edx"); + &shl ("edi",4); # hi<<4 + &xor ("ebx","esi"); + + &shr ("ecx",7-2); # lo>>7 + &xor ("eax","edi"); + &shr ("edx",7-2); # hi>>7 + &xor ("ebx","ecx"); + &shl ("esi",25-4); # lo<<25 + &xor ("eax","edx"); + &shl ("edi",25-4); # hi<<25 + &xor ("eax","esi"); + + &shr ("ecx",28-7); # lo>>28 + &xor ("ebx","edi"); + &shr ("edx",28-7); # hi>>28 + &xor ("eax","ecx"); + &shl ("esi",30-25); # lo<<30 + &xor ("ebx","edx"); + &shl ("edi",30-25); # hi<<30 + &xor ("eax","esi"); + &xor ("ebx","edi"); # Sigma0(a) + + &mov ("ecx",$Alo); + &mov ("edx",$Ahi); + &mov ("esi",$Blo); + &mov ("edi",$Bhi); + &add ("eax",$Tlo); + &adc ("ebx",$Thi); # T1 = Sigma0(a)+T1 + &or ("ecx","esi"); + &or ("edx","edi"); + &and ("ecx",$Clo); + &and ("edx",$Chi); + &and ("esi",$Alo); + &and ("edi",$Ahi); + &or ("ecx","esi"); + &or ("edx","edi"); # Maj(a,b,c) = ((a|b)&c)|(a&b) + + &add ("eax","ecx"); + &adc ("ebx","edx"); # T1 += Maj(a,b,c) + &mov ($Tlo,"eax"); + &mov ($Thi,"ebx"); + + &mov (&LB("edx"),&BP(0,$K512)); # pre-fetch LSB of *K + &sub ("esp",8); + &lea ($K512,&DWP(8,$K512)); # K++ +} + + +&function_begin("sha512_block_data_order"); + &mov ("esi",wparam(0)); # ctx + &mov ("edi",wparam(1)); # inp + &mov ("eax",wparam(2)); # num + &mov ("ebx","esp"); # saved sp + + &call (&label("pic_point")); # make it PIC! +&set_label("pic_point"); + &blindpop($K512); + &lea ($K512,&DWP(&label("K512")."-".&label("pic_point"),$K512)); + + &sub ("esp",16); + &and ("esp",-64); + + &shl ("eax",7); + &add ("eax","edi"); + &mov (&DWP(0,"esp"),"esi"); # ctx + &mov (&DWP(4,"esp"),"edi"); # inp + &mov (&DWP(8,"esp"),"eax"); # inp+num*128 + &mov (&DWP(12,"esp"),"ebx"); # saved sp + +if ($sse2) { + &picmeup("edx","OPENSSL_ia32cap_P",$K512,&label("K512")); + &mov ("ecx",&DWP(0,"edx")); + &test ("ecx",1<<26); + &jz (&label("loop_x86")); + + &mov ("edx",&DWP(4,"edx")); + + # load ctx->h[0-7] + &movq ($A,&QWP(0,"esi")); + &and ("ecx",1<<24); # XMM registers availability + &movq ("mm1",&QWP(8,"esi")); + &and ("edx",1<<9); # SSSE3 bit + &movq ($BxC,&QWP(16,"esi")); + &or ("ecx","edx"); + &movq ("mm3",&QWP(24,"esi")); + &movq ($E,&QWP(32,"esi")); + &movq ("mm5",&QWP(40,"esi")); + &movq ("mm6",&QWP(48,"esi")); + &movq ("mm7",&QWP(56,"esi")); + &cmp ("ecx",1<<24|1<<9); + &je (&label("SSSE3")); + &sub ("esp",8*10); + &jmp (&label("loop_sse2")); + +&set_label("loop_sse2",16); + #&movq ($Asse2,$A); + &movq ($Bsse2,"mm1"); + &movq ($Csse2,$BxC); + &movq ($Dsse2,"mm3"); + #&movq ($Esse2,$E); + &movq ($Fsse2,"mm5"); + &movq ($Gsse2,"mm6"); + &pxor ($BxC,"mm1"); # magic + &movq ($Hsse2,"mm7"); + &movq ("mm3",$A); # magic + + &mov ("eax",&DWP(0,"edi")); + &mov ("ebx",&DWP(4,"edi")); + &add ("edi",8); + &mov ("edx",15); # counter + &bswap ("eax"); + &bswap ("ebx"); + &jmp (&label("00_14_sse2")); + +&set_label("00_14_sse2",16); + &movd ("mm1","eax"); + &mov ("eax",&DWP(0,"edi")); + &movd ("mm7","ebx"); + &mov ("ebx",&DWP(4,"edi")); + &add ("edi",8); + &bswap ("eax"); + &bswap ("ebx"); + &punpckldq("mm7","mm1"); + + &BODY_00_15_sse2(); + + &dec ("edx"); + &jnz (&label("00_14_sse2")); + + &movd ("mm1","eax"); + &movd ("mm7","ebx"); + &punpckldq("mm7","mm1"); + + &BODY_00_15_sse2(1); + + &pxor ($A,$A); # A is in %mm3 + &mov ("edx",32); # counter + &jmp (&label("16_79_sse2")); + +&set_label("16_79_sse2",16); + for ($j=0;$j<2;$j++) { # 2x unroll + #&movq ("mm7",&QWP(8*(9+16-1),"esp")); # prefetched in BODY_00_15 + &movq ("mm5",&QWP(8*(9+16-14),"esp")); + &movq ("mm1","mm7"); + &psrlq ("mm7",1); + &movq ("mm6","mm5"); + &psrlq ("mm5",6); + &psllq ("mm1",56); + &paddq ($A,"mm3"); # from BODY_00_15 + &movq ("mm3","mm7"); + &psrlq ("mm7",7-1); + &pxor ("mm3","mm1"); + &psllq ("mm1",63-56); + &pxor ("mm3","mm7"); + &psrlq ("mm7",8-7); + &pxor ("mm3","mm1"); + &movq ("mm1","mm5"); + &psrlq ("mm5",19-6); + &pxor ("mm7","mm3"); # sigma0 + + &psllq ("mm6",3); + &pxor ("mm1","mm5"); + &paddq ("mm7",&QWP(8*(9+16),"esp")); + &pxor ("mm1","mm6"); + &psrlq ("mm5",61-19); + &paddq ("mm7",&QWP(8*(9+16-9),"esp")); + &pxor ("mm1","mm5"); + &psllq ("mm6",45-3); + &movq ("mm5",$Fsse2); # load f + &pxor ("mm1","mm6"); # sigma1 + &movq ("mm6",$Gsse2); # load g + + &paddq ("mm7","mm1"); # X[i] + #&movq (&QWP(8*9,"esp"),"mm7"); # moved to BODY_00_15 + + &BODY_00_15_sse2(2); + } + &dec ("edx"); + &jnz (&label("16_79_sse2")); + + #&movq ($A,$Asse2); + &paddq ($A,"mm3"); # from BODY_00_15 + &movq ("mm1",$Bsse2); + #&movq ($BxC,$Csse2); + &movq ("mm3",$Dsse2); + #&movq ($E,$Esse2); + &movq ("mm5",$Fsse2); + &movq ("mm6",$Gsse2); + &movq ("mm7",$Hsse2); + + &pxor ($BxC,"mm1"); # de-magic + &paddq ($A,&QWP(0,"esi")); + &paddq ("mm1",&QWP(8,"esi")); + &paddq ($BxC,&QWP(16,"esi")); + &paddq ("mm3",&QWP(24,"esi")); + &paddq ($E,&QWP(32,"esi")); + &paddq ("mm5",&QWP(40,"esi")); + &paddq ("mm6",&QWP(48,"esi")); + &paddq ("mm7",&QWP(56,"esi")); + + &mov ("eax",8*80); + &movq (&QWP(0,"esi"),$A); + &movq (&QWP(8,"esi"),"mm1"); + &movq (&QWP(16,"esi"),$BxC); + &movq (&QWP(24,"esi"),"mm3"); + &movq (&QWP(32,"esi"),$E); + &movq (&QWP(40,"esi"),"mm5"); + &movq (&QWP(48,"esi"),"mm6"); + &movq (&QWP(56,"esi"),"mm7"); + + &lea ("esp",&DWP(0,"esp","eax")); # destroy frame + &sub ($K512,"eax"); # rewind K + + &cmp ("edi",&DWP(8*10+8,"esp")); # are we done yet? + &jb (&label("loop_sse2")); + + &mov ("esp",&DWP(8*10+12,"esp")); # restore sp + &emms (); +&function_end_A(); + +&set_label("SSSE3",32); +{ my ($cnt,$frame)=("ecx","edx"); + my @X=map("xmm$_",(0..7)); + my $j; + my $i=0; + + &lea ($frame,&DWP(-64,"esp")); + &sub ("esp",256); + + # fixed stack frame layout + # + # +0 A B C D E F G H # backing store + # +64 X[0]+K[i] .. X[15]+K[i] # XMM->MM xfer area + # +192 # XMM off-load ring buffer + # +256 # saved parameters + + &movdqa (@X[1],&QWP(80*8,$K512)); # byte swap mask + &movdqu (@X[0],&QWP(0,"edi")); + &pshufb (@X[0],@X[1]); + for ($j=0;$j<8;$j++) { + &movdqa (&QWP(16*(($j-1)%4),$frame),@X[3]) if ($j>4); # off-load + &movdqa (@X[3],&QWP(16*($j%8),$K512)); + &movdqa (@X[2],@X[1]) if ($j<7); # perpetuate byte swap mask + &movdqu (@X[1],&QWP(16*($j+1),"edi")) if ($j<7); # next input + &movdqa (@X[1],&QWP(16*(($j+1)%4),$frame)) if ($j==7);# restore @X[0] + &paddq (@X[3],@X[0]); + &pshufb (@X[1],@X[2]) if ($j<7); + &movdqa (&QWP(16*($j%8)-128,$frame),@X[3]); # xfer X[i]+K[i] + + push(@X,shift(@X)); # rotate(@X) + } + #&jmp (&label("loop_ssse3")); + &nop (); + +&set_label("loop_ssse3",32); + &movdqa (@X[2],&QWP(16*(($j+1)%4),$frame)); # pre-restore @X[1] + &movdqa (&QWP(16*(($j-1)%4),$frame),@X[3]); # off-load @X[3] + &lea ($K512,&DWP(16*8,$K512)); + + #&movq ($Asse2,$A); # off-load A-H + &movq ($Bsse2,"mm1"); + &mov ("ebx","edi"); + &movq ($Csse2,$BxC); + &lea ("edi",&DWP(128,"edi")); # advance input + &movq ($Dsse2,"mm3"); + &cmp ("edi","eax"); + #&movq ($Esse2,$E); + &movq ($Fsse2,"mm5"); + &cmovb ("ebx","edi"); + &movq ($Gsse2,"mm6"); + &mov ("ecx",4); # loop counter + &pxor ($BxC,"mm1"); # magic + &movq ($Hsse2,"mm7"); + &pxor ("mm3","mm3"); # magic + + &jmp (&label("00_47_ssse3")); + +sub BODY_00_15_ssse3 { # "phase-less" copy of BODY_00_15_sse2 + ( + '&movq ("mm1",$E)', # %mm1 is sliding right + '&movq ("mm7",&QWP(((-8*$i)%128)-128,$frame))',# X[i]+K[i] + '&pxor ("mm5","mm6")', # f^=g + '&psrlq ("mm1",14)', + '&movq (&QWP(8*($i+4)%64,"esp"),$E)', # modulo-scheduled save e + '&pand ("mm5",$E)', # f&=e + '&psllq ($E,23)', # $E is sliding left + '&paddq ($A,"mm3")', # [h+=Maj(a,b,c)] + '&movq ("mm3","mm1")', # %mm3 is T1 + '&psrlq("mm1",4)', + '&pxor ("mm5","mm6")', # Ch(e,f,g) + '&pxor ("mm3",$E)', + '&psllq($E,23)', + '&pxor ("mm3","mm1")', + '&movq (&QWP(8*$i%64,"esp"),$A)', # modulo-scheduled save a + '&paddq("mm7","mm5")', # X[i]+=Ch(e,f,g) + '&pxor ("mm3",$E)', + '&psrlq("mm1",23)', + '&paddq("mm7",&QWP(8*($i+7)%64,"esp"))', # X[i]+=h + '&pxor ("mm3","mm1")', + '&psllq($E,4)', + '&pxor ("mm3",$E)', # T1=Sigma1_512(e) + + '&movq ($E,&QWP(8*($i+3)%64,"esp"))', # e = load d, e in next round + '&paddq ("mm3","mm7")', # T1+=X[i] + '&movq ("mm5",$A)', # %mm5 is sliding right + '&psrlq("mm5",28)', + '&paddq ($E,"mm3")', # d += T1 + '&movq ("mm6",$A)', # %mm6 is sliding left + '&movq ("mm7","mm5")', + '&psllq("mm6",25)', + '&movq ("mm1",&QWP(8*($i+1)%64,"esp"))', # load b + '&psrlq("mm5",6)', + '&pxor ("mm7","mm6")', + '&psllq("mm6",5)', + '&pxor ("mm7","mm5")', + '&pxor ($A,"mm1")', # a^b, b^c in next round + '&psrlq("mm5",5)', + '&pxor ("mm7","mm6")', + '&pand ($BxC,$A)', # (b^c)&(a^b) + '&psllq("mm6",6)', + '&pxor ("mm7","mm5")', + '&pxor ($BxC,"mm1")', # [h=]Maj(a,b,c) + '&pxor ("mm6","mm7")', # Sigma0_512(a) + '&movq ("mm5",&QWP(8*($i+5-1)%64,"esp"))', # pre-load f + '&paddq ($BxC,"mm6")', # h+=Sigma0(a) + '&movq ("mm6",&QWP(8*($i+6-1)%64,"esp"))', # pre-load g + + '($A,$BxC) = ($BxC,$A); $i--;' + ); +} + +&set_label("00_47_ssse3",32); + + for(;$j<16;$j++) { + my ($t0,$t2,$t1)=@X[2..4]; + my @insns = (&BODY_00_15_ssse3(),&BODY_00_15_ssse3()); + + &movdqa ($t2,@X[5]); + &movdqa (@X[1],$t0); # restore @X[1] + &palignr ($t0,@X[0],8); # X[1..2] + &movdqa (&QWP(16*($j%4),$frame),@X[4]); # off-load @X[4] + &palignr ($t2,@X[4],8); # X[9..10] + + &movdqa ($t1,$t0); + &psrlq ($t0,7); + &paddq (@X[0],$t2); # X[0..1] += X[9..10] + &movdqa ($t2,$t1); + &psrlq ($t1,1); + &psllq ($t2,64-8); + &pxor ($t0,$t1); + &psrlq ($t1,8-1); + &pxor ($t0,$t2); + &psllq ($t2,8-1); + &pxor ($t0,$t1); + &movdqa ($t1,@X[7]); + &pxor ($t0,$t2); # sigma0(X[1..2]) + &movdqa ($t2,@X[7]); + &psrlq ($t1,6); + &paddq (@X[0],$t0); # X[0..1] += sigma0(X[1..2]) + + &movdqa ($t0,@X[7]); + &psrlq ($t2,19); + &psllq ($t0,64-61); + &pxor ($t1,$t2); + &psrlq ($t2,61-19); + &pxor ($t1,$t0); + &psllq ($t0,61-19); + &pxor ($t1,$t2); + &movdqa ($t2,&QWP(16*(($j+2)%4),$frame));# pre-restore @X[1] + &pxor ($t1,$t0); # sigma0(X[1..2]) + &movdqa ($t0,&QWP(16*($j%8),$K512)); + eval(shift(@insns)); + &paddq (@X[0],$t1); # X[0..1] += sigma0(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddq ($t0,@X[0]); + foreach(@insns) { eval; } + &movdqa (&QWP(16*($j%8)-128,$frame),$t0);# xfer X[i]+K[i] + + push(@X,shift(@X)); # rotate(@X) + } + &lea ($K512,&DWP(16*8,$K512)); + &dec ("ecx"); + &jnz (&label("00_47_ssse3")); + + &movdqa (@X[1],&QWP(0,$K512)); # byte swap mask + &lea ($K512,&DWP(-80*8,$K512)); # rewind + &movdqu (@X[0],&QWP(0,"ebx")); + &pshufb (@X[0],@X[1]); + + for ($j=0;$j<8;$j++) { # load next or same block + my @insns = (&BODY_00_15_ssse3(),&BODY_00_15_ssse3()); + + &movdqa (&QWP(16*(($j-1)%4),$frame),@X[3]) if ($j>4); # off-load + &movdqa (@X[3],&QWP(16*($j%8),$K512)); + &movdqa (@X[2],@X[1]) if ($j<7); # perpetuate byte swap mask + &movdqu (@X[1],&QWP(16*($j+1),"ebx")) if ($j<7); # next input + &movdqa (@X[1],&QWP(16*(($j+1)%4),$frame)) if ($j==7);# restore @X[0] + &paddq (@X[3],@X[0]); + &pshufb (@X[1],@X[2]) if ($j<7); + foreach(@insns) { eval; } + &movdqa (&QWP(16*($j%8)-128,$frame),@X[3]);# xfer X[i]+K[i] + + push(@X,shift(@X)); # rotate(@X) + } + + #&movq ($A,$Asse2); # load A-H + &movq ("mm1",$Bsse2); + &paddq ($A,"mm3"); # from BODY_00_15 + #&movq ($BxC,$Csse2); + &movq ("mm3",$Dsse2); + #&movq ($E,$Esse2); + #&movq ("mm5",$Fsse2); + #&movq ("mm6",$Gsse2); + &movq ("mm7",$Hsse2); + + &pxor ($BxC,"mm1"); # de-magic + &paddq ($A,&QWP(0,"esi")); + &paddq ("mm1",&QWP(8,"esi")); + &paddq ($BxC,&QWP(16,"esi")); + &paddq ("mm3",&QWP(24,"esi")); + &paddq ($E,&QWP(32,"esi")); + &paddq ("mm5",&QWP(40,"esi")); + &paddq ("mm6",&QWP(48,"esi")); + &paddq ("mm7",&QWP(56,"esi")); + + &movq (&QWP(0,"esi"),$A); + &movq (&QWP(8,"esi"),"mm1"); + &movq (&QWP(16,"esi"),$BxC); + &movq (&QWP(24,"esi"),"mm3"); + &movq (&QWP(32,"esi"),$E); + &movq (&QWP(40,"esi"),"mm5"); + &movq (&QWP(48,"esi"),"mm6"); + &movq (&QWP(56,"esi"),"mm7"); + + &cmp ("edi","eax") # are we done yet? + &jb (&label("loop_ssse3")); + + &mov ("esp",&DWP(64+12,$frame)); # restore sp + &emms (); +} +&function_end_A(); +} +&set_label("loop_x86",16); + # copy input block to stack reversing byte and qword order + for ($i=0;$i<8;$i++) { + &mov ("eax",&DWP($i*16+0,"edi")); + &mov ("ebx",&DWP($i*16+4,"edi")); + &mov ("ecx",&DWP($i*16+8,"edi")); + &mov ("edx",&DWP($i*16+12,"edi")); + &bswap ("eax"); + &bswap ("ebx"); + &bswap ("ecx"); + &bswap ("edx"); + &push ("eax"); + &push ("ebx"); + &push ("ecx"); + &push ("edx"); + } + &add ("edi",128); + &sub ("esp",9*8); # place for T,A,B,C,D,E,F,G,H + &mov (&DWP(8*(9+16)+4,"esp"),"edi"); + + # copy ctx->h[0-7] to A,B,C,D,E,F,G,H on stack + &lea ("edi",&DWP(8,"esp")); + &mov ("ecx",16); + &data_word(0xA5F3F689); # rep movsd + +&set_label("00_15_x86",16); + &BODY_00_15_x86(); + + &cmp (&LB("edx"),0x94); + &jne (&label("00_15_x86")); + +&set_label("16_79_x86",16); + #define sigma0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7)) + # LO lo>>1^hi<<31 ^ lo>>8^hi<<24 ^ lo>>7^hi<<25 + # HI hi>>1^lo<<31 ^ hi>>8^lo<<24 ^ hi>>7 + &mov ("ecx",&DWP(8*(9+15+16-1)+0,"esp")); + &mov ("edx",&DWP(8*(9+15+16-1)+4,"esp")); + &mov ("esi","ecx"); + + &shr ("ecx",1); # lo>>1 + &mov ("edi","edx"); + &shr ("edx",1); # hi>>1 + &mov ("eax","ecx"); + &shl ("esi",24); # lo<<24 + &mov ("ebx","edx"); + &shl ("edi",24); # hi<<24 + &xor ("ebx","esi"); + + &shr ("ecx",7-1); # lo>>7 + &xor ("eax","edi"); + &shr ("edx",7-1); # hi>>7 + &xor ("eax","ecx"); + &shl ("esi",31-24); # lo<<31 + &xor ("ebx","edx"); + &shl ("edi",25-24); # hi<<25 + &xor ("ebx","esi"); + + &shr ("ecx",8-7); # lo>>8 + &xor ("eax","edi"); + &shr ("edx",8-7); # hi>>8 + &xor ("eax","ecx"); + &shl ("edi",31-25); # hi<<31 + &xor ("ebx","edx"); + &xor ("eax","edi"); # T1 = sigma0(X[-15]) + + &mov (&DWP(0,"esp"),"eax"); + &mov (&DWP(4,"esp"),"ebx"); # put T1 away + + #define sigma1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6)) + # LO lo>>19^hi<<13 ^ hi>>29^lo<<3 ^ lo>>6^hi<<26 + # HI hi>>19^lo<<13 ^ lo>>29^hi<<3 ^ hi>>6 + &mov ("ecx",&DWP(8*(9+15+16-14)+0,"esp")); + &mov ("edx",&DWP(8*(9+15+16-14)+4,"esp")); + &mov ("esi","ecx"); + + &shr ("ecx",6); # lo>>6 + &mov ("edi","edx"); + &shr ("edx",6); # hi>>6 + &mov ("eax","ecx"); + &shl ("esi",3); # lo<<3 + &mov ("ebx","edx"); + &shl ("edi",3); # hi<<3 + &xor ("eax","esi"); + + &shr ("ecx",19-6); # lo>>19 + &xor ("ebx","edi"); + &shr ("edx",19-6); # hi>>19 + &xor ("eax","ecx"); + &shl ("esi",13-3); # lo<<13 + &xor ("ebx","edx"); + &shl ("edi",13-3); # hi<<13 + &xor ("ebx","esi"); + + &shr ("ecx",29-19); # lo>>29 + &xor ("eax","edi"); + &shr ("edx",29-19); # hi>>29 + &xor ("ebx","ecx"); + &shl ("edi",26-13); # hi<<26 + &xor ("eax","edx"); + &xor ("eax","edi"); # sigma1(X[-2]) + + &mov ("ecx",&DWP(8*(9+15+16)+0,"esp")); + &mov ("edx",&DWP(8*(9+15+16)+4,"esp")); + &add ("eax",&DWP(0,"esp")); + &adc ("ebx",&DWP(4,"esp")); # T1 = sigma1(X[-2])+T1 + &mov ("esi",&DWP(8*(9+15+16-9)+0,"esp")); + &mov ("edi",&DWP(8*(9+15+16-9)+4,"esp")); + &add ("eax","ecx"); + &adc ("ebx","edx"); # T1 += X[-16] + &add ("eax","esi"); + &adc ("ebx","edi"); # T1 += X[-7] + &mov (&DWP(8*(9+15)+0,"esp"),"eax"); + &mov (&DWP(8*(9+15)+4,"esp"),"ebx"); # save X[0] + + &BODY_00_15_x86(); + + &cmp (&LB("edx"),0x17); + &jne (&label("16_79_x86")); + + &mov ("esi",&DWP(8*(9+16+80)+0,"esp"));# ctx + &mov ("edi",&DWP(8*(9+16+80)+4,"esp"));# inp + for($i=0;$i<4;$i++) { + &mov ("eax",&DWP($i*16+0,"esi")); + &mov ("ebx",&DWP($i*16+4,"esi")); + &mov ("ecx",&DWP($i*16+8,"esi")); + &mov ("edx",&DWP($i*16+12,"esi")); + &add ("eax",&DWP(8+($i*16)+0,"esp")); + &adc ("ebx",&DWP(8+($i*16)+4,"esp")); + &mov (&DWP($i*16+0,"esi"),"eax"); + &mov (&DWP($i*16+4,"esi"),"ebx"); + &add ("ecx",&DWP(8+($i*16)+8,"esp")); + &adc ("edx",&DWP(8+($i*16)+12,"esp")); + &mov (&DWP($i*16+8,"esi"),"ecx"); + &mov (&DWP($i*16+12,"esi"),"edx"); + } + &add ("esp",8*(9+16+80)); # destroy frame + &sub ($K512,8*80); # rewind K + + &cmp ("edi",&DWP(8,"esp")); # are we done yet? + &jb (&label("loop_x86")); + + &mov ("esp",&DWP(12,"esp")); # restore sp +&function_end_A(); + +&set_label("K512",64); # Yes! I keep it in the code segment! + &data_word(0xd728ae22,0x428a2f98); # u64 + &data_word(0x23ef65cd,0x71374491); # u64 + &data_word(0xec4d3b2f,0xb5c0fbcf); # u64 + &data_word(0x8189dbbc,0xe9b5dba5); # u64 + &data_word(0xf348b538,0x3956c25b); # u64 + &data_word(0xb605d019,0x59f111f1); # u64 + &data_word(0xaf194f9b,0x923f82a4); # u64 + &data_word(0xda6d8118,0xab1c5ed5); # u64 + &data_word(0xa3030242,0xd807aa98); # u64 + &data_word(0x45706fbe,0x12835b01); # u64 + &data_word(0x4ee4b28c,0x243185be); # u64 + &data_word(0xd5ffb4e2,0x550c7dc3); # u64 + &data_word(0xf27b896f,0x72be5d74); # u64 + &data_word(0x3b1696b1,0x80deb1fe); # u64 + &data_word(0x25c71235,0x9bdc06a7); # u64 + &data_word(0xcf692694,0xc19bf174); # u64 + &data_word(0x9ef14ad2,0xe49b69c1); # u64 + &data_word(0x384f25e3,0xefbe4786); # u64 + &data_word(0x8b8cd5b5,0x0fc19dc6); # u64 + &data_word(0x77ac9c65,0x240ca1cc); # u64 + &data_word(0x592b0275,0x2de92c6f); # u64 + &data_word(0x6ea6e483,0x4a7484aa); # u64 + &data_word(0xbd41fbd4,0x5cb0a9dc); # u64 + &data_word(0x831153b5,0x76f988da); # u64 + &data_word(0xee66dfab,0x983e5152); # u64 + &data_word(0x2db43210,0xa831c66d); # u64 + &data_word(0x98fb213f,0xb00327c8); # u64 + &data_word(0xbeef0ee4,0xbf597fc7); # u64 + &data_word(0x3da88fc2,0xc6e00bf3); # u64 + &data_word(0x930aa725,0xd5a79147); # u64 + &data_word(0xe003826f,0x06ca6351); # u64 + &data_word(0x0a0e6e70,0x14292967); # u64 + &data_word(0x46d22ffc,0x27b70a85); # u64 + &data_word(0x5c26c926,0x2e1b2138); # u64 + &data_word(0x5ac42aed,0x4d2c6dfc); # u64 + &data_word(0x9d95b3df,0x53380d13); # u64 + &data_word(0x8baf63de,0x650a7354); # u64 + &data_word(0x3c77b2a8,0x766a0abb); # u64 + &data_word(0x47edaee6,0x81c2c92e); # u64 + &data_word(0x1482353b,0x92722c85); # u64 + &data_word(0x4cf10364,0xa2bfe8a1); # u64 + &data_word(0xbc423001,0xa81a664b); # u64 + &data_word(0xd0f89791,0xc24b8b70); # u64 + &data_word(0x0654be30,0xc76c51a3); # u64 + &data_word(0xd6ef5218,0xd192e819); # u64 + &data_word(0x5565a910,0xd6990624); # u64 + &data_word(0x5771202a,0xf40e3585); # u64 + &data_word(0x32bbd1b8,0x106aa070); # u64 + &data_word(0xb8d2d0c8,0x19a4c116); # u64 + &data_word(0x5141ab53,0x1e376c08); # u64 + &data_word(0xdf8eeb99,0x2748774c); # u64 + &data_word(0xe19b48a8,0x34b0bcb5); # u64 + &data_word(0xc5c95a63,0x391c0cb3); # u64 + &data_word(0xe3418acb,0x4ed8aa4a); # u64 + &data_word(0x7763e373,0x5b9cca4f); # u64 + &data_word(0xd6b2b8a3,0x682e6ff3); # u64 + &data_word(0x5defb2fc,0x748f82ee); # u64 + &data_word(0x43172f60,0x78a5636f); # u64 + &data_word(0xa1f0ab72,0x84c87814); # u64 + &data_word(0x1a6439ec,0x8cc70208); # u64 + &data_word(0x23631e28,0x90befffa); # u64 + &data_word(0xde82bde9,0xa4506ceb); # u64 + &data_word(0xb2c67915,0xbef9a3f7); # u64 + &data_word(0xe372532b,0xc67178f2); # u64 + &data_word(0xea26619c,0xca273ece); # u64 + &data_word(0x21c0c207,0xd186b8c7); # u64 + &data_word(0xcde0eb1e,0xeada7dd6); # u64 + &data_word(0xee6ed178,0xf57d4f7f); # u64 + &data_word(0x72176fba,0x06f067aa); # u64 + &data_word(0xa2c898a6,0x0a637dc5); # u64 + &data_word(0xbef90dae,0x113f9804); # u64 + &data_word(0x131c471b,0x1b710b35); # u64 + &data_word(0x23047d84,0x28db77f5); # u64 + &data_word(0x40c72493,0x32caab7b); # u64 + &data_word(0x15c9bebc,0x3c9ebe0a); # u64 + &data_word(0x9c100d4c,0x431d67c4); # u64 + &data_word(0xcb3e42b6,0x4cc5d4be); # u64 + &data_word(0xfc657e2a,0x597f299c); # u64 + &data_word(0x3ad6faec,0x5fcb6fab); # u64 + &data_word(0x4a475817,0x6c44198c); # u64 + + &data_word(0x04050607,0x00010203); # byte swap + &data_word(0x0c0d0e0f,0x08090a0b); # mask +&function_end_B("sha512_block_data_order"); +&asciz("SHA512 block transform for x86, CRYPTOGAMS by "); + +&asm_finish(); diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-armv4.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-armv4.pl new file mode 100644 index 00000000..2964a39c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-armv4.pl @@ -0,0 +1,666 @@ +#!/usr/bin/env perl + +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# +# Permission to use under GPL terms is granted. +# ==================================================================== + +# SHA512 block procedure for ARMv4. September 2007. + +# This code is ~4.5 (four and a half) times faster than code generated +# by gcc 3.4 and it spends ~72 clock cycles per byte [on single-issue +# Xscale PXA250 core]. +# +# July 2010. +# +# Rescheduling for dual-issue pipeline resulted in 6% improvement on +# Cortex A8 core and ~40 cycles per processed byte. + +# February 2011. +# +# Profiler-assisted and platform-specific optimization resulted in 7% +# improvement on Coxtex A8 core and ~38 cycles per byte. + +# March 2011. +# +# Add NEON implementation. On Cortex A8 it was measured to process +# one byte in 23.3 cycles or ~60% faster than integer-only code. + +# August 2012. +# +# Improve NEON performance by 12% on Snapdragon S4. In absolute +# terms it's 22.6 cycles per byte, which is disappointing result. +# Technical writers asserted that 3-way S4 pipeline can sustain +# multiple NEON instructions per cycle, but dual NEON issue could +# not be observed, see http://www.openssl.org/~appro/Snapdragon-S4.html +# for further details. On side note Cortex-A15 processes one byte in +# 16 cycles. + +# Byte order [in]dependence. ========================================= +# +# Originally caller was expected to maintain specific *dword* order in +# h[0-7], namely with most significant dword at *lower* address, which +# was reflected in below two parameters as 0 and 4. Now caller is +# expected to maintain native byte order for whole 64-bit values. +$hi="HI"; +$lo="LO"; +# ==================================================================== + +$flavour = shift; +if ($flavour=~/^\w[\w\-]*\.\w+$/) { $output=$flavour; undef $flavour; } +else { while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {} } + +if ($flavour && $flavour ne "void") { + $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; + ( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or + ( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or + die "can't locate arm-xlate.pl"; + + open STDOUT,"| \"$^X\" $xlate $flavour $output"; +} else { + open STDOUT,">$output"; +} + +$ctx="r0"; # parameter block +$inp="r1"; +$len="r2"; + +$Tlo="r3"; +$Thi="r4"; +$Alo="r5"; +$Ahi="r6"; +$Elo="r7"; +$Ehi="r8"; +$t0="r9"; +$t1="r10"; +$t2="r11"; +$t3="r12"; +############ r13 is stack pointer +$Ktbl="r14"; +############ r15 is program counter + +$Aoff=8*0; +$Boff=8*1; +$Coff=8*2; +$Doff=8*3; +$Eoff=8*4; +$Foff=8*5; +$Goff=8*6; +$Hoff=8*7; +$Xoff=8*8; + +sub BODY_00_15() { +my $magic = shift; +$code.=<<___; + @ Sigma1(x) (ROTR((x),14) ^ ROTR((x),18) ^ ROTR((x),41)) + @ LO lo>>14^hi<<18 ^ lo>>18^hi<<14 ^ hi>>9^lo<<23 + @ HI hi>>14^lo<<18 ^ hi>>18^lo<<14 ^ lo>>9^hi<<23 + mov $t0,$Elo,lsr#14 + str $Tlo,[sp,#$Xoff+0] + mov $t1,$Ehi,lsr#14 + str $Thi,[sp,#$Xoff+4] + eor $t0,$t0,$Ehi,lsl#18 + ldr $t2,[sp,#$Hoff+0] @ h.lo + eor $t1,$t1,$Elo,lsl#18 + ldr $t3,[sp,#$Hoff+4] @ h.hi + eor $t0,$t0,$Elo,lsr#18 + eor $t1,$t1,$Ehi,lsr#18 + eor $t0,$t0,$Ehi,lsl#14 + eor $t1,$t1,$Elo,lsl#14 + eor $t0,$t0,$Ehi,lsr#9 + eor $t1,$t1,$Elo,lsr#9 + eor $t0,$t0,$Elo,lsl#23 + eor $t1,$t1,$Ehi,lsl#23 @ Sigma1(e) + adds $Tlo,$Tlo,$t0 + ldr $t0,[sp,#$Foff+0] @ f.lo + adc $Thi,$Thi,$t1 @ T += Sigma1(e) + ldr $t1,[sp,#$Foff+4] @ f.hi + adds $Tlo,$Tlo,$t2 + ldr $t2,[sp,#$Goff+0] @ g.lo + adc $Thi,$Thi,$t3 @ T += h + ldr $t3,[sp,#$Goff+4] @ g.hi + + eor $t0,$t0,$t2 + str $Elo,[sp,#$Eoff+0] + eor $t1,$t1,$t3 + str $Ehi,[sp,#$Eoff+4] + and $t0,$t0,$Elo + str $Alo,[sp,#$Aoff+0] + and $t1,$t1,$Ehi + str $Ahi,[sp,#$Aoff+4] + eor $t0,$t0,$t2 + ldr $t2,[$Ktbl,#$lo] @ K[i].lo + eor $t1,$t1,$t3 @ Ch(e,f,g) + ldr $t3,[$Ktbl,#$hi] @ K[i].hi + + adds $Tlo,$Tlo,$t0 + ldr $Elo,[sp,#$Doff+0] @ d.lo + adc $Thi,$Thi,$t1 @ T += Ch(e,f,g) + ldr $Ehi,[sp,#$Doff+4] @ d.hi + adds $Tlo,$Tlo,$t2 + and $t0,$t2,#0xff + adc $Thi,$Thi,$t3 @ T += K[i] + adds $Elo,$Elo,$Tlo + ldr $t2,[sp,#$Boff+0] @ b.lo + adc $Ehi,$Ehi,$Thi @ d += T + teq $t0,#$magic + + ldr $t3,[sp,#$Coff+0] @ c.lo +#if __ARM_ARCH__>=7 + it eq @ Thumb2 thing, sanity check in ARM +#endif + orreq $Ktbl,$Ktbl,#1 + @ Sigma0(x) (ROTR((x),28) ^ ROTR((x),34) ^ ROTR((x),39)) + @ LO lo>>28^hi<<4 ^ hi>>2^lo<<30 ^ hi>>7^lo<<25 + @ HI hi>>28^lo<<4 ^ lo>>2^hi<<30 ^ lo>>7^hi<<25 + mov $t0,$Alo,lsr#28 + mov $t1,$Ahi,lsr#28 + eor $t0,$t0,$Ahi,lsl#4 + eor $t1,$t1,$Alo,lsl#4 + eor $t0,$t0,$Ahi,lsr#2 + eor $t1,$t1,$Alo,lsr#2 + eor $t0,$t0,$Alo,lsl#30 + eor $t1,$t1,$Ahi,lsl#30 + eor $t0,$t0,$Ahi,lsr#7 + eor $t1,$t1,$Alo,lsr#7 + eor $t0,$t0,$Alo,lsl#25 + eor $t1,$t1,$Ahi,lsl#25 @ Sigma0(a) + adds $Tlo,$Tlo,$t0 + and $t0,$Alo,$t2 + adc $Thi,$Thi,$t1 @ T += Sigma0(a) + + ldr $t1,[sp,#$Boff+4] @ b.hi + orr $Alo,$Alo,$t2 + ldr $t2,[sp,#$Coff+4] @ c.hi + and $Alo,$Alo,$t3 + and $t3,$Ahi,$t1 + orr $Ahi,$Ahi,$t1 + orr $Alo,$Alo,$t0 @ Maj(a,b,c).lo + and $Ahi,$Ahi,$t2 + adds $Alo,$Alo,$Tlo + orr $Ahi,$Ahi,$t3 @ Maj(a,b,c).hi + sub sp,sp,#8 + adc $Ahi,$Ahi,$Thi @ h += T + tst $Ktbl,#1 + add $Ktbl,$Ktbl,#8 +___ +} +$code=<<___; +#ifndef __KERNEL__ +# include "arm_arch.h" +# define VFP_ABI_PUSH vstmdb sp!,{d8-d15} +# define VFP_ABI_POP vldmia sp!,{d8-d15} +#else +# define __ARM_ARCH__ __LINUX_ARM_ARCH__ +# define __ARM_MAX_ARCH__ 7 +# define VFP_ABI_PUSH +# define VFP_ABI_POP +#endif + +#ifdef __ARMEL__ +# define LO 0 +# define HI 4 +# define WORD64(hi0,lo0,hi1,lo1) .word lo0,hi0, lo1,hi1 +#else +# define HI 0 +# define LO 4 +# define WORD64(hi0,lo0,hi1,lo1) .word hi0,lo0, hi1,lo1 +#endif + +.text +#if __ARM_ARCH__<7 || defined(__APPLE__) +.code 32 +#else +.syntax unified +# ifdef __thumb2__ +# define adrl adr +.thumb +# else +.code 32 +# endif +#endif + +.type K512,%object +.align 5 +K512: +WORD64(0x428a2f98,0xd728ae22, 0x71374491,0x23ef65cd) +WORD64(0xb5c0fbcf,0xec4d3b2f, 0xe9b5dba5,0x8189dbbc) +WORD64(0x3956c25b,0xf348b538, 0x59f111f1,0xb605d019) +WORD64(0x923f82a4,0xaf194f9b, 0xab1c5ed5,0xda6d8118) +WORD64(0xd807aa98,0xa3030242, 0x12835b01,0x45706fbe) +WORD64(0x243185be,0x4ee4b28c, 0x550c7dc3,0xd5ffb4e2) +WORD64(0x72be5d74,0xf27b896f, 0x80deb1fe,0x3b1696b1) +WORD64(0x9bdc06a7,0x25c71235, 0xc19bf174,0xcf692694) +WORD64(0xe49b69c1,0x9ef14ad2, 0xefbe4786,0x384f25e3) +WORD64(0x0fc19dc6,0x8b8cd5b5, 0x240ca1cc,0x77ac9c65) +WORD64(0x2de92c6f,0x592b0275, 0x4a7484aa,0x6ea6e483) +WORD64(0x5cb0a9dc,0xbd41fbd4, 0x76f988da,0x831153b5) +WORD64(0x983e5152,0xee66dfab, 0xa831c66d,0x2db43210) +WORD64(0xb00327c8,0x98fb213f, 0xbf597fc7,0xbeef0ee4) +WORD64(0xc6e00bf3,0x3da88fc2, 0xd5a79147,0x930aa725) +WORD64(0x06ca6351,0xe003826f, 0x14292967,0x0a0e6e70) +WORD64(0x27b70a85,0x46d22ffc, 0x2e1b2138,0x5c26c926) +WORD64(0x4d2c6dfc,0x5ac42aed, 0x53380d13,0x9d95b3df) +WORD64(0x650a7354,0x8baf63de, 0x766a0abb,0x3c77b2a8) +WORD64(0x81c2c92e,0x47edaee6, 0x92722c85,0x1482353b) +WORD64(0xa2bfe8a1,0x4cf10364, 0xa81a664b,0xbc423001) +WORD64(0xc24b8b70,0xd0f89791, 0xc76c51a3,0x0654be30) +WORD64(0xd192e819,0xd6ef5218, 0xd6990624,0x5565a910) +WORD64(0xf40e3585,0x5771202a, 0x106aa070,0x32bbd1b8) +WORD64(0x19a4c116,0xb8d2d0c8, 0x1e376c08,0x5141ab53) +WORD64(0x2748774c,0xdf8eeb99, 0x34b0bcb5,0xe19b48a8) +WORD64(0x391c0cb3,0xc5c95a63, 0x4ed8aa4a,0xe3418acb) +WORD64(0x5b9cca4f,0x7763e373, 0x682e6ff3,0xd6b2b8a3) +WORD64(0x748f82ee,0x5defb2fc, 0x78a5636f,0x43172f60) +WORD64(0x84c87814,0xa1f0ab72, 0x8cc70208,0x1a6439ec) +WORD64(0x90befffa,0x23631e28, 0xa4506ceb,0xde82bde9) +WORD64(0xbef9a3f7,0xb2c67915, 0xc67178f2,0xe372532b) +WORD64(0xca273ece,0xea26619c, 0xd186b8c7,0x21c0c207) +WORD64(0xeada7dd6,0xcde0eb1e, 0xf57d4f7f,0xee6ed178) +WORD64(0x06f067aa,0x72176fba, 0x0a637dc5,0xa2c898a6) +WORD64(0x113f9804,0xbef90dae, 0x1b710b35,0x131c471b) +WORD64(0x28db77f5,0x23047d84, 0x32caab7b,0x40c72493) +WORD64(0x3c9ebe0a,0x15c9bebc, 0x431d67c4,0x9c100d4c) +WORD64(0x4cc5d4be,0xcb3e42b6, 0x597f299c,0xfc657e2a) +WORD64(0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817) +.size K512,.-K512 +#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) +.LOPENSSL_armcap: +.word OPENSSL_armcap_P-.Lsha512_block_data_order +.skip 32-4 +#else +.skip 32 +#endif + +.global sha512_block_data_order +.type sha512_block_data_order,%function +sha512_block_data_order: +.Lsha512_block_data_order: +#if __ARM_ARCH__<7 + sub r3,pc,#8 @ sha512_block_data_order +#else + adr r3,sha512_block_data_order +#endif +#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) + ldr r12,.LOPENSSL_armcap + ldr r12,[r3,r12] @ OPENSSL_armcap_P +#ifdef __APPLE__ + ldr r12,[r12] +#endif + tst r12,#1 + bne .LNEON +#endif + add $len,$inp,$len,lsl#7 @ len to point at the end of inp + stmdb sp!,{r4-r12,lr} + sub $Ktbl,r3,#672 @ K512 + sub sp,sp,#9*8 + + ldr $Elo,[$ctx,#$Eoff+$lo] + ldr $Ehi,[$ctx,#$Eoff+$hi] + ldr $t0, [$ctx,#$Goff+$lo] + ldr $t1, [$ctx,#$Goff+$hi] + ldr $t2, [$ctx,#$Hoff+$lo] + ldr $t3, [$ctx,#$Hoff+$hi] +.Loop: + str $t0, [sp,#$Goff+0] + str $t1, [sp,#$Goff+4] + str $t2, [sp,#$Hoff+0] + str $t3, [sp,#$Hoff+4] + ldr $Alo,[$ctx,#$Aoff+$lo] + ldr $Ahi,[$ctx,#$Aoff+$hi] + ldr $Tlo,[$ctx,#$Boff+$lo] + ldr $Thi,[$ctx,#$Boff+$hi] + ldr $t0, [$ctx,#$Coff+$lo] + ldr $t1, [$ctx,#$Coff+$hi] + ldr $t2, [$ctx,#$Doff+$lo] + ldr $t3, [$ctx,#$Doff+$hi] + str $Tlo,[sp,#$Boff+0] + str $Thi,[sp,#$Boff+4] + str $t0, [sp,#$Coff+0] + str $t1, [sp,#$Coff+4] + str $t2, [sp,#$Doff+0] + str $t3, [sp,#$Doff+4] + ldr $Tlo,[$ctx,#$Foff+$lo] + ldr $Thi,[$ctx,#$Foff+$hi] + str $Tlo,[sp,#$Foff+0] + str $Thi,[sp,#$Foff+4] + +.L00_15: +#if __ARM_ARCH__<7 + ldrb $Tlo,[$inp,#7] + ldrb $t0, [$inp,#6] + ldrb $t1, [$inp,#5] + ldrb $t2, [$inp,#4] + ldrb $Thi,[$inp,#3] + ldrb $t3, [$inp,#2] + orr $Tlo,$Tlo,$t0,lsl#8 + ldrb $t0, [$inp,#1] + orr $Tlo,$Tlo,$t1,lsl#16 + ldrb $t1, [$inp],#8 + orr $Tlo,$Tlo,$t2,lsl#24 + orr $Thi,$Thi,$t3,lsl#8 + orr $Thi,$Thi,$t0,lsl#16 + orr $Thi,$Thi,$t1,lsl#24 +#else + ldr $Tlo,[$inp,#4] + ldr $Thi,[$inp],#8 +#ifdef __ARMEL__ + rev $Tlo,$Tlo + rev $Thi,$Thi +#endif +#endif +___ + &BODY_00_15(0x94); +$code.=<<___; + tst $Ktbl,#1 + beq .L00_15 + ldr $t0,[sp,#`$Xoff+8*(16-1)`+0] + ldr $t1,[sp,#`$Xoff+8*(16-1)`+4] + bic $Ktbl,$Ktbl,#1 +.L16_79: + @ sigma0(x) (ROTR((x),1) ^ ROTR((x),8) ^ ((x)>>7)) + @ LO lo>>1^hi<<31 ^ lo>>8^hi<<24 ^ lo>>7^hi<<25 + @ HI hi>>1^lo<<31 ^ hi>>8^lo<<24 ^ hi>>7 + mov $Tlo,$t0,lsr#1 + ldr $t2,[sp,#`$Xoff+8*(16-14)`+0] + mov $Thi,$t1,lsr#1 + ldr $t3,[sp,#`$Xoff+8*(16-14)`+4] + eor $Tlo,$Tlo,$t1,lsl#31 + eor $Thi,$Thi,$t0,lsl#31 + eor $Tlo,$Tlo,$t0,lsr#8 + eor $Thi,$Thi,$t1,lsr#8 + eor $Tlo,$Tlo,$t1,lsl#24 + eor $Thi,$Thi,$t0,lsl#24 + eor $Tlo,$Tlo,$t0,lsr#7 + eor $Thi,$Thi,$t1,lsr#7 + eor $Tlo,$Tlo,$t1,lsl#25 + + @ sigma1(x) (ROTR((x),19) ^ ROTR((x),61) ^ ((x)>>6)) + @ LO lo>>19^hi<<13 ^ hi>>29^lo<<3 ^ lo>>6^hi<<26 + @ HI hi>>19^lo<<13 ^ lo>>29^hi<<3 ^ hi>>6 + mov $t0,$t2,lsr#19 + mov $t1,$t3,lsr#19 + eor $t0,$t0,$t3,lsl#13 + eor $t1,$t1,$t2,lsl#13 + eor $t0,$t0,$t3,lsr#29 + eor $t1,$t1,$t2,lsr#29 + eor $t0,$t0,$t2,lsl#3 + eor $t1,$t1,$t3,lsl#3 + eor $t0,$t0,$t2,lsr#6 + eor $t1,$t1,$t3,lsr#6 + ldr $t2,[sp,#`$Xoff+8*(16-9)`+0] + eor $t0,$t0,$t3,lsl#26 + + ldr $t3,[sp,#`$Xoff+8*(16-9)`+4] + adds $Tlo,$Tlo,$t0 + ldr $t0,[sp,#`$Xoff+8*16`+0] + adc $Thi,$Thi,$t1 + + ldr $t1,[sp,#`$Xoff+8*16`+4] + adds $Tlo,$Tlo,$t2 + adc $Thi,$Thi,$t3 + adds $Tlo,$Tlo,$t0 + adc $Thi,$Thi,$t1 +___ + &BODY_00_15(0x17); +$code.=<<___; +#if __ARM_ARCH__>=7 + ittt eq @ Thumb2 thing, sanity check in ARM +#endif + ldreq $t0,[sp,#`$Xoff+8*(16-1)`+0] + ldreq $t1,[sp,#`$Xoff+8*(16-1)`+4] + beq .L16_79 + bic $Ktbl,$Ktbl,#1 + + ldr $Tlo,[sp,#$Boff+0] + ldr $Thi,[sp,#$Boff+4] + ldr $t0, [$ctx,#$Aoff+$lo] + ldr $t1, [$ctx,#$Aoff+$hi] + ldr $t2, [$ctx,#$Boff+$lo] + ldr $t3, [$ctx,#$Boff+$hi] + adds $t0,$Alo,$t0 + str $t0, [$ctx,#$Aoff+$lo] + adc $t1,$Ahi,$t1 + str $t1, [$ctx,#$Aoff+$hi] + adds $t2,$Tlo,$t2 + str $t2, [$ctx,#$Boff+$lo] + adc $t3,$Thi,$t3 + str $t3, [$ctx,#$Boff+$hi] + + ldr $Alo,[sp,#$Coff+0] + ldr $Ahi,[sp,#$Coff+4] + ldr $Tlo,[sp,#$Doff+0] + ldr $Thi,[sp,#$Doff+4] + ldr $t0, [$ctx,#$Coff+$lo] + ldr $t1, [$ctx,#$Coff+$hi] + ldr $t2, [$ctx,#$Doff+$lo] + ldr $t3, [$ctx,#$Doff+$hi] + adds $t0,$Alo,$t0 + str $t0, [$ctx,#$Coff+$lo] + adc $t1,$Ahi,$t1 + str $t1, [$ctx,#$Coff+$hi] + adds $t2,$Tlo,$t2 + str $t2, [$ctx,#$Doff+$lo] + adc $t3,$Thi,$t3 + str $t3, [$ctx,#$Doff+$hi] + + ldr $Tlo,[sp,#$Foff+0] + ldr $Thi,[sp,#$Foff+4] + ldr $t0, [$ctx,#$Eoff+$lo] + ldr $t1, [$ctx,#$Eoff+$hi] + ldr $t2, [$ctx,#$Foff+$lo] + ldr $t3, [$ctx,#$Foff+$hi] + adds $Elo,$Elo,$t0 + str $Elo,[$ctx,#$Eoff+$lo] + adc $Ehi,$Ehi,$t1 + str $Ehi,[$ctx,#$Eoff+$hi] + adds $t2,$Tlo,$t2 + str $t2, [$ctx,#$Foff+$lo] + adc $t3,$Thi,$t3 + str $t3, [$ctx,#$Foff+$hi] + + ldr $Alo,[sp,#$Goff+0] + ldr $Ahi,[sp,#$Goff+4] + ldr $Tlo,[sp,#$Hoff+0] + ldr $Thi,[sp,#$Hoff+4] + ldr $t0, [$ctx,#$Goff+$lo] + ldr $t1, [$ctx,#$Goff+$hi] + ldr $t2, [$ctx,#$Hoff+$lo] + ldr $t3, [$ctx,#$Hoff+$hi] + adds $t0,$Alo,$t0 + str $t0, [$ctx,#$Goff+$lo] + adc $t1,$Ahi,$t1 + str $t1, [$ctx,#$Goff+$hi] + adds $t2,$Tlo,$t2 + str $t2, [$ctx,#$Hoff+$lo] + adc $t3,$Thi,$t3 + str $t3, [$ctx,#$Hoff+$hi] + + add sp,sp,#640 + sub $Ktbl,$Ktbl,#640 + + teq $inp,$len + bne .Loop + + add sp,sp,#8*9 @ destroy frame +#if __ARM_ARCH__>=5 + ldmia sp!,{r4-r12,pc} +#else + ldmia sp!,{r4-r12,lr} + tst lr,#1 + moveq pc,lr @ be binary compatible with V4, yet + bx lr @ interoperable with Thumb ISA:-) +#endif +.size sha512_block_data_order,.-sha512_block_data_order +___ + +{ +my @Sigma0=(28,34,39); +my @Sigma1=(14,18,41); +my @sigma0=(1, 8, 7); +my @sigma1=(19,61,6); + +my $Ktbl="r3"; +my $cnt="r12"; # volatile register known as ip, intra-procedure-call scratch + +my @X=map("d$_",(0..15)); +my @V=($A,$B,$C,$D,$E,$F,$G,$H)=map("d$_",(16..23)); + +sub NEON_00_15() { +my $i=shift; +my ($a,$b,$c,$d,$e,$f,$g,$h)=@_; +my ($t0,$t1,$t2,$T1,$K,$Ch,$Maj)=map("d$_",(24..31)); # temps + +$code.=<<___ if ($i<16 || $i&1); + vshr.u64 $t0,$e,#@Sigma1[0] @ $i +#if $i<16 + vld1.64 {@X[$i%16]},[$inp]! @ handles unaligned +#endif + vshr.u64 $t1,$e,#@Sigma1[1] +#if $i>0 + vadd.i64 $a,$Maj @ h+=Maj from the past +#endif + vshr.u64 $t2,$e,#@Sigma1[2] +___ +$code.=<<___; + vld1.64 {$K},[$Ktbl,:64]! @ K[i++] + vsli.64 $t0,$e,#`64-@Sigma1[0]` + vsli.64 $t1,$e,#`64-@Sigma1[1]` + vmov $Ch,$e + vsli.64 $t2,$e,#`64-@Sigma1[2]` +#if $i<16 && defined(__ARMEL__) + vrev64.8 @X[$i],@X[$i] +#endif + veor $t1,$t0 + vbsl $Ch,$f,$g @ Ch(e,f,g) + vshr.u64 $t0,$a,#@Sigma0[0] + veor $t2,$t1 @ Sigma1(e) + vadd.i64 $T1,$Ch,$h + vshr.u64 $t1,$a,#@Sigma0[1] + vsli.64 $t0,$a,#`64-@Sigma0[0]` + vadd.i64 $T1,$t2 + vshr.u64 $t2,$a,#@Sigma0[2] + vadd.i64 $K,@X[$i%16] + vsli.64 $t1,$a,#`64-@Sigma0[1]` + veor $Maj,$a,$b + vsli.64 $t2,$a,#`64-@Sigma0[2]` + veor $h,$t0,$t1 + vadd.i64 $T1,$K + vbsl $Maj,$c,$b @ Maj(a,b,c) + veor $h,$t2 @ Sigma0(a) + vadd.i64 $d,$T1 + vadd.i64 $Maj,$T1 + @ vadd.i64 $h,$Maj +___ +} + +sub NEON_16_79() { +my $i=shift; + +if ($i&1) { &NEON_00_15($i,@_); return; } + +# 2x-vectorized, therefore runs every 2nd round +my @X=map("q$_",(0..7)); # view @X as 128-bit vector +my ($t0,$t1,$s0,$s1) = map("q$_",(12..15)); # temps +my ($d0,$d1,$d2) = map("d$_",(24..26)); # temps from NEON_00_15 +my $e=@_[4]; # $e from NEON_00_15 +$i /= 2; +$code.=<<___; + vshr.u64 $t0,@X[($i+7)%8],#@sigma1[0] + vshr.u64 $t1,@X[($i+7)%8],#@sigma1[1] + vadd.i64 @_[0],d30 @ h+=Maj from the past + vshr.u64 $s1,@X[($i+7)%8],#@sigma1[2] + vsli.64 $t0,@X[($i+7)%8],#`64-@sigma1[0]` + vext.8 $s0,@X[$i%8],@X[($i+1)%8],#8 @ X[i+1] + vsli.64 $t1,@X[($i+7)%8],#`64-@sigma1[1]` + veor $s1,$t0 + vshr.u64 $t0,$s0,#@sigma0[0] + veor $s1,$t1 @ sigma1(X[i+14]) + vshr.u64 $t1,$s0,#@sigma0[1] + vadd.i64 @X[$i%8],$s1 + vshr.u64 $s1,$s0,#@sigma0[2] + vsli.64 $t0,$s0,#`64-@sigma0[0]` + vsli.64 $t1,$s0,#`64-@sigma0[1]` + vext.8 $s0,@X[($i+4)%8],@X[($i+5)%8],#8 @ X[i+9] + veor $s1,$t0 + vshr.u64 $d0,$e,#@Sigma1[0] @ from NEON_00_15 + vadd.i64 @X[$i%8],$s0 + vshr.u64 $d1,$e,#@Sigma1[1] @ from NEON_00_15 + veor $s1,$t1 @ sigma0(X[i+1]) + vshr.u64 $d2,$e,#@Sigma1[2] @ from NEON_00_15 + vadd.i64 @X[$i%8],$s1 +___ + &NEON_00_15(2*$i,@_); +} + +$code.=<<___; +#if __ARM_MAX_ARCH__>=7 +.arch armv7-a +.fpu neon + +.global sha512_block_data_order_neon +.type sha512_block_data_order_neon,%function +.align 4 +sha512_block_data_order_neon: +.LNEON: + dmb @ errata #451034 on early Cortex A8 + add $len,$inp,$len,lsl#7 @ len to point at the end of inp + adr $Ktbl,K512 + VFP_ABI_PUSH + vldmia $ctx,{$A-$H} @ load context +.Loop_neon: +___ +for($i=0;$i<16;$i++) { &NEON_00_15($i,@V); unshift(@V,pop(@V)); } +$code.=<<___; + mov $cnt,#4 +.L16_79_neon: + subs $cnt,#1 +___ +for(;$i<32;$i++) { &NEON_16_79($i,@V); unshift(@V,pop(@V)); } +$code.=<<___; + bne .L16_79_neon + + vadd.i64 $A,d30 @ h+=Maj from the past + vldmia $ctx,{d24-d31} @ load context to temp + vadd.i64 q8,q12 @ vectorized accumulate + vadd.i64 q9,q13 + vadd.i64 q10,q14 + vadd.i64 q11,q15 + vstmia $ctx,{$A-$H} @ save context + teq $inp,$len + sub $Ktbl,#640 @ rewind K512 + bne .Loop_neon + + VFP_ABI_POP + ret @ bx lr +.size sha512_block_data_order_neon,.-sha512_block_data_order_neon +#endif +___ +} +$code.=<<___; +.asciz "SHA512 block transform for ARMv4/NEON, CRYPTOGAMS by " +.align 2 +#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) +.comm OPENSSL_armcap_P,4,4 +.hidden OPENSSL_armcap_P +#endif +___ + +$code =~ s/\`([^\`]*)\`/eval $1/gem; +$code =~ s/\bbx\s+lr\b/.word\t0xe12fff1e/gm; # make it possible to compile with -march=armv4 +$code =~ s/\bret\b/bx lr/gm; + +open SELF,$0; +while() { + next if (/^#!/); + last if (!s/^#/@/ and !/^$/); + print; +} +close SELF; + +print $code; +close STDOUT; # enforce flush diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-armv8.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-armv8.pl new file mode 100644 index 00000000..43e7293f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-armv8.pl @@ -0,0 +1,436 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# SHA256/512 for ARMv8. +# +# Performance in cycles per processed byte and improvement coefficient +# over code generated with "default" compiler: +# +# SHA256-hw SHA256(*) SHA512 +# Apple A7 1.97 10.5 (+33%) 6.73 (-1%(**)) +# Cortex-A53 2.38 15.5 (+115%) 10.0 (+150%(***)) +# Cortex-A57 2.31 11.6 (+86%) 7.51 (+260%(***)) +# Denver 2.01 10.5 (+26%) 6.70 (+8%) +# X-Gene 20.0 (+100%) 12.8 (+300%(***)) +# +# (*) Software SHA256 results are of lesser relevance, presented +# mostly for informational purposes. +# (**) The result is a trade-off: it's possible to improve it by +# 10% (or by 1 cycle per round), but at the cost of 20% loss +# on Cortex-A53 (or by 4 cycles per round). +# (***) Super-impressive coefficients over gcc-generated code are +# indication of some compiler "pathology", most notably code +# generated with -mgeneral-regs-only is significanty faster +# and the gap is only 40-90%. + +$flavour=shift; +# Unlike most perlasm files, sha512-armv8.pl takes an additional argument to +# determine which hash function to emit. This differs from upstream OpenSSL so +# that the script may continue to output to stdout. +$variant=shift; +$output=shift; + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}arm-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/arm-xlate.pl" and -f $xlate) or +die "can't locate arm-xlate.pl"; + +open OUT,"| \"$^X\" $xlate $flavour $output"; +*STDOUT=*OUT; + +if ($variant eq "sha512") { + $BITS=512; + $SZ=8; + @Sigma0=(28,34,39); + @Sigma1=(14,18,41); + @sigma0=(1, 8, 7); + @sigma1=(19,61, 6); + $rounds=80; + $reg_t="x"; +} elsif ($variant eq "sha256") { + $BITS=256; + $SZ=4; + @Sigma0=( 2,13,22); + @Sigma1=( 6,11,25); + @sigma0=( 7,18, 3); + @sigma1=(17,19,10); + $rounds=64; + $reg_t="w"; +} else { + die "Unknown variant: $variant"; +} + +$func="sha${BITS}_block_data_order"; + +($ctx,$inp,$num,$Ktbl)=map("x$_",(0..2,30)); + +@X=map("$reg_t$_",(3..15,0..2)); +@V=($A,$B,$C,$D,$E,$F,$G,$H)=map("$reg_t$_",(20..27)); +($t0,$t1,$t2,$t3)=map("$reg_t$_",(16,17,19,28)); + +sub BODY_00_xx { +my ($i,$a,$b,$c,$d,$e,$f,$g,$h)=@_; +my $j=($i+1)&15; +my ($T0,$T1,$T2)=(@X[($i-8)&15],@X[($i-9)&15],@X[($i-10)&15]); + $T0=@X[$i+3] if ($i<11); + +$code.=<<___ if ($i<16); +#ifndef __ARMEB__ + rev @X[$i],@X[$i] // $i +#endif +___ +$code.=<<___ if ($i<13 && ($i&1)); + ldp @X[$i+1],@X[$i+2],[$inp],#2*$SZ +___ +$code.=<<___ if ($i==13); + ldp @X[14],@X[15],[$inp] +___ +$code.=<<___ if ($i>=14); + ldr @X[($i-11)&15],[sp,#`$SZ*(($i-11)%4)`] +___ +$code.=<<___ if ($i>0 && $i<16); + add $a,$a,$t1 // h+=Sigma0(a) +___ +$code.=<<___ if ($i>=11); + str @X[($i-8)&15],[sp,#`$SZ*(($i-8)%4)`] +___ +# While ARMv8 specifies merged rotate-n-logical operation such as +# 'eor x,y,z,ror#n', it was found to negatively affect performance +# on Apple A7. The reason seems to be that it requires even 'y' to +# be available earlier. This means that such merged instruction is +# not necessarily best choice on critical path... On the other hand +# Cortex-A5x handles merged instructions much better than disjoint +# rotate and logical... See (**) footnote above. +$code.=<<___ if ($i<15); + ror $t0,$e,#$Sigma1[0] + add $h,$h,$t2 // h+=K[i] + eor $T0,$e,$e,ror#`$Sigma1[2]-$Sigma1[1]` + and $t1,$f,$e + bic $t2,$g,$e + add $h,$h,@X[$i&15] // h+=X[i] + orr $t1,$t1,$t2 // Ch(e,f,g) + eor $t2,$a,$b // a^b, b^c in next round + eor $t0,$t0,$T0,ror#$Sigma1[1] // Sigma1(e) + ror $T0,$a,#$Sigma0[0] + add $h,$h,$t1 // h+=Ch(e,f,g) + eor $t1,$a,$a,ror#`$Sigma0[2]-$Sigma0[1]` + add $h,$h,$t0 // h+=Sigma1(e) + and $t3,$t3,$t2 // (b^c)&=(a^b) + add $d,$d,$h // d+=h + eor $t3,$t3,$b // Maj(a,b,c) + eor $t1,$T0,$t1,ror#$Sigma0[1] // Sigma0(a) + add $h,$h,$t3 // h+=Maj(a,b,c) + ldr $t3,[$Ktbl],#$SZ // *K++, $t2 in next round + //add $h,$h,$t1 // h+=Sigma0(a) +___ +$code.=<<___ if ($i>=15); + ror $t0,$e,#$Sigma1[0] + add $h,$h,$t2 // h+=K[i] + ror $T1,@X[($j+1)&15],#$sigma0[0] + and $t1,$f,$e + ror $T2,@X[($j+14)&15],#$sigma1[0] + bic $t2,$g,$e + ror $T0,$a,#$Sigma0[0] + add $h,$h,@X[$i&15] // h+=X[i] + eor $t0,$t0,$e,ror#$Sigma1[1] + eor $T1,$T1,@X[($j+1)&15],ror#$sigma0[1] + orr $t1,$t1,$t2 // Ch(e,f,g) + eor $t2,$a,$b // a^b, b^c in next round + eor $t0,$t0,$e,ror#$Sigma1[2] // Sigma1(e) + eor $T0,$T0,$a,ror#$Sigma0[1] + add $h,$h,$t1 // h+=Ch(e,f,g) + and $t3,$t3,$t2 // (b^c)&=(a^b) + eor $T2,$T2,@X[($j+14)&15],ror#$sigma1[1] + eor $T1,$T1,@X[($j+1)&15],lsr#$sigma0[2] // sigma0(X[i+1]) + add $h,$h,$t0 // h+=Sigma1(e) + eor $t3,$t3,$b // Maj(a,b,c) + eor $t1,$T0,$a,ror#$Sigma0[2] // Sigma0(a) + eor $T2,$T2,@X[($j+14)&15],lsr#$sigma1[2] // sigma1(X[i+14]) + add @X[$j],@X[$j],@X[($j+9)&15] + add $d,$d,$h // d+=h + add $h,$h,$t3 // h+=Maj(a,b,c) + ldr $t3,[$Ktbl],#$SZ // *K++, $t2 in next round + add @X[$j],@X[$j],$T1 + add $h,$h,$t1 // h+=Sigma0(a) + add @X[$j],@X[$j],$T2 +___ + ($t2,$t3)=($t3,$t2); +} + +$code.=<<___; +#include "arm_arch.h" + +.text + +.extern OPENSSL_armcap_P +.globl $func +.type $func,%function +.align 6 +$func: +___ +$code.=<<___ if ($SZ==4); + ldr x16,.LOPENSSL_armcap_P + adr x17,.LOPENSSL_armcap_P + add x16,x16,x17 + ldr w16,[x16] + tst w16,#ARMV8_SHA256 + b.ne .Lv8_entry +___ +$code.=<<___; + stp x29,x30,[sp,#-128]! + add x29,sp,#0 + + stp x19,x20,[sp,#16] + stp x21,x22,[sp,#32] + stp x23,x24,[sp,#48] + stp x25,x26,[sp,#64] + stp x27,x28,[sp,#80] + sub sp,sp,#4*$SZ + + ldp $A,$B,[$ctx] // load context + ldp $C,$D,[$ctx,#2*$SZ] + ldp $E,$F,[$ctx,#4*$SZ] + add $num,$inp,$num,lsl#`log(16*$SZ)/log(2)` // end of input + ldp $G,$H,[$ctx,#6*$SZ] + adr $Ktbl,.LK$BITS + stp $ctx,$num,[x29,#96] + +.Loop: + ldp @X[0],@X[1],[$inp],#2*$SZ + ldr $t2,[$Ktbl],#$SZ // *K++ + eor $t3,$B,$C // magic seed + str $inp,[x29,#112] +___ +for ($i=0;$i<16;$i++) { &BODY_00_xx($i,@V); unshift(@V,pop(@V)); } +$code.=".Loop_16_xx:\n"; +for (;$i<32;$i++) { &BODY_00_xx($i,@V); unshift(@V,pop(@V)); } +$code.=<<___; + cbnz $t2,.Loop_16_xx + + ldp $ctx,$num,[x29,#96] + ldr $inp,[x29,#112] + sub $Ktbl,$Ktbl,#`$SZ*($rounds+1)` // rewind + + ldp @X[0],@X[1],[$ctx] + ldp @X[2],@X[3],[$ctx,#2*$SZ] + add $inp,$inp,#14*$SZ // advance input pointer + ldp @X[4],@X[5],[$ctx,#4*$SZ] + add $A,$A,@X[0] + ldp @X[6],@X[7],[$ctx,#6*$SZ] + add $B,$B,@X[1] + add $C,$C,@X[2] + add $D,$D,@X[3] + stp $A,$B,[$ctx] + add $E,$E,@X[4] + add $F,$F,@X[5] + stp $C,$D,[$ctx,#2*$SZ] + add $G,$G,@X[6] + add $H,$H,@X[7] + cmp $inp,$num + stp $E,$F,[$ctx,#4*$SZ] + stp $G,$H,[$ctx,#6*$SZ] + b.ne .Loop + + ldp x19,x20,[x29,#16] + add sp,sp,#4*$SZ + ldp x21,x22,[x29,#32] + ldp x23,x24,[x29,#48] + ldp x25,x26,[x29,#64] + ldp x27,x28,[x29,#80] + ldp x29,x30,[sp],#128 + ret +.size $func,.-$func + +.align 6 +.type .LK$BITS,%object +.LK$BITS: +___ +$code.=<<___ if ($SZ==8); + .quad 0x428a2f98d728ae22,0x7137449123ef65cd + .quad 0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc + .quad 0x3956c25bf348b538,0x59f111f1b605d019 + .quad 0x923f82a4af194f9b,0xab1c5ed5da6d8118 + .quad 0xd807aa98a3030242,0x12835b0145706fbe + .quad 0x243185be4ee4b28c,0x550c7dc3d5ffb4e2 + .quad 0x72be5d74f27b896f,0x80deb1fe3b1696b1 + .quad 0x9bdc06a725c71235,0xc19bf174cf692694 + .quad 0xe49b69c19ef14ad2,0xefbe4786384f25e3 + .quad 0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65 + .quad 0x2de92c6f592b0275,0x4a7484aa6ea6e483 + .quad 0x5cb0a9dcbd41fbd4,0x76f988da831153b5 + .quad 0x983e5152ee66dfab,0xa831c66d2db43210 + .quad 0xb00327c898fb213f,0xbf597fc7beef0ee4 + .quad 0xc6e00bf33da88fc2,0xd5a79147930aa725 + .quad 0x06ca6351e003826f,0x142929670a0e6e70 + .quad 0x27b70a8546d22ffc,0x2e1b21385c26c926 + .quad 0x4d2c6dfc5ac42aed,0x53380d139d95b3df + .quad 0x650a73548baf63de,0x766a0abb3c77b2a8 + .quad 0x81c2c92e47edaee6,0x92722c851482353b + .quad 0xa2bfe8a14cf10364,0xa81a664bbc423001 + .quad 0xc24b8b70d0f89791,0xc76c51a30654be30 + .quad 0xd192e819d6ef5218,0xd69906245565a910 + .quad 0xf40e35855771202a,0x106aa07032bbd1b8 + .quad 0x19a4c116b8d2d0c8,0x1e376c085141ab53 + .quad 0x2748774cdf8eeb99,0x34b0bcb5e19b48a8 + .quad 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb + .quad 0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3 + .quad 0x748f82ee5defb2fc,0x78a5636f43172f60 + .quad 0x84c87814a1f0ab72,0x8cc702081a6439ec + .quad 0x90befffa23631e28,0xa4506cebde82bde9 + .quad 0xbef9a3f7b2c67915,0xc67178f2e372532b + .quad 0xca273eceea26619c,0xd186b8c721c0c207 + .quad 0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178 + .quad 0x06f067aa72176fba,0x0a637dc5a2c898a6 + .quad 0x113f9804bef90dae,0x1b710b35131c471b + .quad 0x28db77f523047d84,0x32caab7b40c72493 + .quad 0x3c9ebe0a15c9bebc,0x431d67c49c100d4c + .quad 0x4cc5d4becb3e42b6,0x597f299cfc657e2a + .quad 0x5fcb6fab3ad6faec,0x6c44198c4a475817 + .quad 0 // terminator +___ +$code.=<<___ if ($SZ==4); + .long 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5 + .long 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5 + .long 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3 + .long 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174 + .long 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc + .long 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da + .long 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7 + .long 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967 + .long 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13 + .long 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85 + .long 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3 + .long 0xd192e819,0xd6990624,0xf40e3585,0x106aa070 + .long 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5 + .long 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3 + .long 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208 + .long 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 + .long 0 //terminator +___ +$code.=<<___; +.size .LK$BITS,.-.LK$BITS +.align 3 +.LOPENSSL_armcap_P: + .quad OPENSSL_armcap_P-. +.asciz "SHA$BITS block transform for ARMv8, CRYPTOGAMS by " +.align 2 +___ + +if ($SZ==4) { +my $Ktbl="x3"; + +my ($ABCD,$EFGH,$abcd)=map("v$_.16b",(0..2)); +my @MSG=map("v$_.16b",(4..7)); +my ($W0,$W1)=("v16.4s","v17.4s"); +my ($ABCD_SAVE,$EFGH_SAVE)=("v18.16b","v19.16b"); + +$code.=<<___; +.type sha256_block_armv8,%function +.align 6 +sha256_block_armv8: +.Lv8_entry: + stp x29,x30,[sp,#-16]! + add x29,sp,#0 + + ld1.32 {$ABCD,$EFGH},[$ctx] + adr $Ktbl,.LK256 + +.Loop_hw: + ld1 {@MSG[0]-@MSG[3]},[$inp],#64 + sub $num,$num,#1 + ld1.32 {$W0},[$Ktbl],#16 + rev32 @MSG[0],@MSG[0] + rev32 @MSG[1],@MSG[1] + rev32 @MSG[2],@MSG[2] + rev32 @MSG[3],@MSG[3] + orr $ABCD_SAVE,$ABCD,$ABCD // offload + orr $EFGH_SAVE,$EFGH,$EFGH +___ +for($i=0;$i<12;$i++) { +$code.=<<___; + ld1.32 {$W1},[$Ktbl],#16 + add.i32 $W0,$W0,@MSG[0] + sha256su0 @MSG[0],@MSG[1] + orr $abcd,$ABCD,$ABCD + sha256h $ABCD,$EFGH,$W0 + sha256h2 $EFGH,$abcd,$W0 + sha256su1 @MSG[0],@MSG[2],@MSG[3] +___ + ($W0,$W1)=($W1,$W0); push(@MSG,shift(@MSG)); +} +$code.=<<___; + ld1.32 {$W1},[$Ktbl],#16 + add.i32 $W0,$W0,@MSG[0] + orr $abcd,$ABCD,$ABCD + sha256h $ABCD,$EFGH,$W0 + sha256h2 $EFGH,$abcd,$W0 + + ld1.32 {$W0},[$Ktbl],#16 + add.i32 $W1,$W1,@MSG[1] + orr $abcd,$ABCD,$ABCD + sha256h $ABCD,$EFGH,$W1 + sha256h2 $EFGH,$abcd,$W1 + + ld1.32 {$W1},[$Ktbl] + add.i32 $W0,$W0,@MSG[2] + sub $Ktbl,$Ktbl,#$rounds*$SZ-16 // rewind + orr $abcd,$ABCD,$ABCD + sha256h $ABCD,$EFGH,$W0 + sha256h2 $EFGH,$abcd,$W0 + + add.i32 $W1,$W1,@MSG[3] + orr $abcd,$ABCD,$ABCD + sha256h $ABCD,$EFGH,$W1 + sha256h2 $EFGH,$abcd,$W1 + + add.i32 $ABCD,$ABCD,$ABCD_SAVE + add.i32 $EFGH,$EFGH,$EFGH_SAVE + + cbnz $num,.Loop_hw + + st1.32 {$ABCD,$EFGH},[$ctx] + + ldr x29,[sp],#16 + ret +.size sha256_block_armv8,.-sha256_block_armv8 +___ +} + +$code.=<<___; +.comm OPENSSL_armcap_P,4,4 +___ + +{ my %opcode = ( + "sha256h" => 0x5e004000, "sha256h2" => 0x5e005000, + "sha256su0" => 0x5e282800, "sha256su1" => 0x5e006000 ); + + sub unsha256 { + my ($mnemonic,$arg)=@_; + + $arg =~ m/[qv]([0-9]+)[^,]*,\s*[qv]([0-9]+)[^,]*(?:,\s*[qv]([0-9]+))?/o + && + sprintf ".inst\t0x%08x\t//%s %s", + $opcode{$mnemonic}|$1|($2<<5)|($3<<16), + $mnemonic,$arg; + } +} + +foreach(split("\n",$code)) { + + s/\`([^\`]*)\`/eval($1)/geo; + + s/\b(sha256\w+)\s+([qv].*)/unsha256($1,$2)/geo; + + s/\.\w?32\b//o and s/\.16b/\.4s/go; + m/(ld|st)1[^\[]+\[0\]/o and s/\.4s/\.s/go; + + print $_,"\n"; +} + +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-x86_64.pl b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-x86_64.pl new file mode 100644 index 00000000..6660a88b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/asm/sha512-x86_64.pl @@ -0,0 +1,2396 @@ +#!/usr/bin/env perl +# +# ==================================================================== +# Written by Andy Polyakov for the OpenSSL +# project. Rights for redistribution and usage in source and binary +# forms are granted according to the OpenSSL license. +# ==================================================================== +# +# sha256/512_block procedure for x86_64. +# +# 40% improvement over compiler-generated code on Opteron. On EM64T +# sha256 was observed to run >80% faster and sha512 - >40%. No magical +# tricks, just straight implementation... I really wonder why gcc +# [being armed with inline assembler] fails to generate as fast code. +# The only thing which is cool about this module is that it's very +# same instruction sequence used for both SHA-256 and SHA-512. In +# former case the instructions operate on 32-bit operands, while in +# latter - on 64-bit ones. All I had to do is to get one flavor right, +# the other one passed the test right away:-) +# +# sha256_block runs in ~1005 cycles on Opteron, which gives you +# asymptotic performance of 64*1000/1005=63.7MBps times CPU clock +# frequency in GHz. sha512_block runs in ~1275 cycles, which results +# in 128*1000/1275=100MBps per GHz. Is there room for improvement? +# Well, if you compare it to IA-64 implementation, which maintains +# X[16] in register bank[!], tends to 4 instructions per CPU clock +# cycle and runs in 1003 cycles, 1275 is very good result for 3-way +# issue Opteron pipeline and X[16] maintained in memory. So that *if* +# there is a way to improve it, *then* the only way would be to try to +# offload X[16] updates to SSE unit, but that would require "deeper" +# loop unroll, which in turn would naturally cause size blow-up, not +# to mention increased complexity! And once again, only *if* it's +# actually possible to noticeably improve overall ILP, instruction +# level parallelism, on a given CPU implementation in this case. +# +# Special note on Intel EM64T. While Opteron CPU exhibits perfect +# perfromance ratio of 1.5 between 64- and 32-bit flavors [see above], +# [currently available] EM64T CPUs apparently are far from it. On the +# contrary, 64-bit version, sha512_block, is ~30% *slower* than 32-bit +# sha256_block:-( This is presumably because 64-bit shifts/rotates +# apparently are not atomic instructions, but implemented in microcode. +# +# May 2012. +# +# Optimization including one of Pavel Semjanov's ideas, alternative +# Maj, resulted in >=5% improvement on most CPUs, +20% SHA256 and +# unfortunately -2% SHA512 on P4 [which nobody should care about +# that much]. +# +# June 2012. +# +# Add SIMD code paths, see below for improvement coefficients. SSSE3 +# code path was not attempted for SHA512, because improvement is not +# estimated to be high enough, noticeably less than 9%, to justify +# the effort, not on pre-AVX processors. [Obviously with exclusion +# for VIA Nano, but it has SHA512 instruction that is faster and +# should be used instead.] For reference, corresponding estimated +# upper limit for improvement for SSSE3 SHA256 is 28%. The fact that +# higher coefficients are observed on VIA Nano and Bulldozer has more +# to do with specifics of their architecture [which is topic for +# separate discussion]. +# +# November 2012. +# +# Add AVX2 code path. Two consecutive input blocks are loaded to +# 256-bit %ymm registers, with data from first block to least +# significant 128-bit halves and data from second to most significant. +# The data is then processed with same SIMD instruction sequence as +# for AVX, but with %ymm as operands. Side effect is increased stack +# frame, 448 additional bytes in SHA256 and 1152 in SHA512, and 1.2KB +# code size increase. +# +# March 2014. +# +# Add support for Intel SHA Extensions. + +###################################################################### +# Current performance in cycles per processed byte (less is better): +# +# SHA256 SSSE3 AVX/XOP(*) SHA512 AVX/XOP(*) +# +# AMD K8 14.9 - - 9.57 - +# P4 17.3 - - 30.8 - +# Core 2 15.6 13.8(+13%) - 9.97 - +# Westmere 14.8 12.3(+19%) - 9.58 - +# Sandy Bridge 17.4 14.2(+23%) 11.6(+50%(**)) 11.2 8.10(+38%(**)) +# Ivy Bridge 12.6 10.5(+20%) 10.3(+22%) 8.17 7.22(+13%) +# Haswell 12.2 9.28(+31%) 7.80(+56%) 7.66 5.40(+42%) +# Bulldozer 21.1 13.6(+54%) 13.6(+54%(***)) 13.5 8.58(+57%) +# VIA Nano 23.0 16.5(+39%) - 14.7 - +# Atom 23.0 18.9(+22%) - 14.7 - +# Silvermont 27.4 20.6(+33%) - 17.5 - +# +# (*) whichever best applicable; +# (**) switch from ror to shrd stands for fair share of improvement; +# (***) execution time is fully determined by remaining integer-only +# part, body_00_15; reducing the amount of SIMD instructions +# below certain limit makes no difference/sense; to conserve +# space SHA256 XOP code path is therefore omitted; + +$flavour = shift; +$output = shift; +if ($flavour =~ /\./) { $output = $flavour; undef $flavour; } + +$win64=0; $win64=1 if ($flavour =~ /[nm]asm|mingw64/ || $output =~ /\.asm$/); + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}x86_64-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or +die "can't locate x86_64-xlate.pl"; + +if (`$ENV{CC} -Wa,-v -c -o /dev/null -x assembler /dev/null 2>&1` + =~ /GNU assembler version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.19) + ($1>=2.22); +} + +if (!$avx && $win64 && ($flavour =~ /nasm/ || $ENV{ASM} =~ /nasm/) && + `nasm -v 2>&1` =~ /NASM version ([2-9]\.[0-9]+)/) { + $avx = ($1>=2.09) + ($1>=2.10); +} + +if (!$avx && $win64 && ($flavour =~ /masm/ || $ENV{ASM} =~ /ml64/) && + `ml64 2>&1` =~ /Version ([0-9]+)\./) { + $avx = ($1>=10) + ($1>=11); +} + +if (!$avx && `$ENV{CC} -v 2>&1` =~ /(^clang version|based on LLVM) ([3-9]\.[0-9]+)/) { + $avx = ($2>=3.0) + ($2>3.0); +} + +$shaext=0; ### set to zero if compiling for 1.0.1 +$avx=1 if (!$shaext && $avx); + +open OUT,"| \"$^X\" $xlate $flavour"; +*STDOUT=*OUT; + +if ($output =~ /512/) { + $func="sha512_block_data_order"; + $TABLE="K512"; + $SZ=8; + @ROT=($A,$B,$C,$D,$E,$F,$G,$H)=("%rax","%rbx","%rcx","%rdx", + "%r8", "%r9", "%r10","%r11"); + ($T1,$a0,$a1,$a2,$a3)=("%r12","%r13","%r14","%r15","%rdi"); + @Sigma0=(28,34,39); + @Sigma1=(14,18,41); + @sigma0=(1, 8, 7); + @sigma1=(19,61, 6); + $rounds=80; +} else { + $func="sha256_block_data_order"; + $TABLE="K256"; + $SZ=4; + @ROT=($A,$B,$C,$D,$E,$F,$G,$H)=("%eax","%ebx","%ecx","%edx", + "%r8d","%r9d","%r10d","%r11d"); + ($T1,$a0,$a1,$a2,$a3)=("%r12d","%r13d","%r14d","%r15d","%edi"); + @Sigma0=( 2,13,22); + @Sigma1=( 6,11,25); + @sigma0=( 7,18, 3); + @sigma1=(17,19,10); + $rounds=64; +} + +$ctx="%rdi"; # 1st arg, zapped by $a3 +$inp="%rsi"; # 2nd arg +$Tbl="%rbp"; + +$_ctx="16*$SZ+0*8(%rsp)"; +$_inp="16*$SZ+1*8(%rsp)"; +$_end="16*$SZ+2*8(%rsp)"; +$_rsp="16*$SZ+3*8(%rsp)"; +$framesz="16*$SZ+4*8"; + + +sub ROUND_00_15() +{ my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_; + my $STRIDE=$SZ; + $STRIDE += 16 if ($i%(16/$SZ)==(16/$SZ-1)); + +$code.=<<___; + ror \$`$Sigma1[2]-$Sigma1[1]`,$a0 + mov $f,$a2 + + xor $e,$a0 + ror \$`$Sigma0[2]-$Sigma0[1]`,$a1 + xor $g,$a2 # f^g + + mov $T1,`$SZ*($i&0xf)`(%rsp) + xor $a,$a1 + and $e,$a2 # (f^g)&e + + ror \$`$Sigma1[1]-$Sigma1[0]`,$a0 + add $h,$T1 # T1+=h + xor $g,$a2 # Ch(e,f,g)=((f^g)&e)^g + + ror \$`$Sigma0[1]-$Sigma0[0]`,$a1 + xor $e,$a0 + add $a2,$T1 # T1+=Ch(e,f,g) + + mov $a,$a2 + add ($Tbl),$T1 # T1+=K[round] + xor $a,$a1 + + xor $b,$a2 # a^b, b^c in next round + ror \$$Sigma1[0],$a0 # Sigma1(e) + mov $b,$h + + and $a2,$a3 + ror \$$Sigma0[0],$a1 # Sigma0(a) + add $a0,$T1 # T1+=Sigma1(e) + + xor $a3,$h # h=Maj(a,b,c)=Ch(a^b,c,b) + add $T1,$d # d+=T1 + add $T1,$h # h+=T1 + + lea $STRIDE($Tbl),$Tbl # round++ +___ +$code.=<<___ if ($i<15); + add $a1,$h # h+=Sigma0(a) +___ + ($a2,$a3) = ($a3,$a2); +} + +sub ROUND_16_XX() +{ my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_; + +$code.=<<___; + mov `$SZ*(($i+1)&0xf)`(%rsp),$a0 + mov `$SZ*(($i+14)&0xf)`(%rsp),$a2 + + mov $a0,$T1 + ror \$`$sigma0[1]-$sigma0[0]`,$a0 + add $a1,$a # modulo-scheduled h+=Sigma0(a) + mov $a2,$a1 + ror \$`$sigma1[1]-$sigma1[0]`,$a2 + + xor $T1,$a0 + shr \$$sigma0[2],$T1 + ror \$$sigma0[0],$a0 + xor $a1,$a2 + shr \$$sigma1[2],$a1 + + ror \$$sigma1[0],$a2 + xor $a0,$T1 # sigma0(X[(i+1)&0xf]) + xor $a1,$a2 # sigma1(X[(i+14)&0xf]) + add `$SZ*(($i+9)&0xf)`(%rsp),$T1 + + add `$SZ*($i&0xf)`(%rsp),$T1 + mov $e,$a0 + add $a2,$T1 + mov $a,$a1 +___ + &ROUND_00_15(@_); +} + +$code=<<___; +.text + +.extern OPENSSL_ia32cap_P +.globl $func +.type $func,\@function,3 +.align 16 +$func: +___ +$code.=<<___ if ($SZ==4 || $avx); + lea OPENSSL_ia32cap_P(%rip),%r11 + mov 0(%r11),%r9d + mov 4(%r11),%r10d + mov 8(%r11),%r11d +___ +$code.=<<___ if ($SZ==4 && $shaext); + test \$`1<<29`,%r11d # check for SHA + jnz _shaext_shortcut +___ +$code.=<<___ if ($avx && $SZ==8); + test \$`1<<11`,%r10d # check for XOP + jnz .Lxop_shortcut +___ +$code.=<<___ if ($avx>1); + and \$`1<<8|1<<5|1<<3`,%r11d # check for BMI2+AVX2+BMI1 + cmp \$`1<<8|1<<5|1<<3`,%r11d + je .Lavx2_shortcut +___ +$code.=<<___ if ($avx); + and \$`1<<30`,%r9d # mask "Intel CPU" bit + and \$`1<<28|1<<9`,%r10d # mask AVX and SSSE3 bits + or %r9d,%r10d + cmp \$`1<<28|1<<9|1<<30`,%r10d + je .Lavx_shortcut +___ +$code.=<<___ if ($SZ==4); + test \$`1<<9`,%r10d + jnz .Lssse3_shortcut +___ +$code.=<<___; + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + mov %rsp,%r11 # copy %rsp + shl \$4,%rdx # num*16 + sub \$$framesz,%rsp + lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ + and \$-64,%rsp # align stack frame + mov $ctx,$_ctx # save ctx, 1st arg + mov $inp,$_inp # save inp, 2nd arh + mov %rdx,$_end # save end pointer, "3rd" arg + mov %r11,$_rsp # save copy of %rsp +.Lprologue: + + mov $SZ*0($ctx),$A + mov $SZ*1($ctx),$B + mov $SZ*2($ctx),$C + mov $SZ*3($ctx),$D + mov $SZ*4($ctx),$E + mov $SZ*5($ctx),$F + mov $SZ*6($ctx),$G + mov $SZ*7($ctx),$H + jmp .Lloop + +.align 16 +.Lloop: + mov $B,$a3 + lea $TABLE(%rip),$Tbl + xor $C,$a3 # magic +___ + for($i=0;$i<16;$i++) { + $code.=" mov $SZ*$i($inp),$T1\n"; + $code.=" mov @ROT[4],$a0\n"; + $code.=" mov @ROT[0],$a1\n"; + $code.=" bswap $T1\n"; + &ROUND_00_15($i,@ROT); + unshift(@ROT,pop(@ROT)); + } +$code.=<<___; + jmp .Lrounds_16_xx +.align 16 +.Lrounds_16_xx: +___ + for(;$i<32;$i++) { + &ROUND_16_XX($i,@ROT); + unshift(@ROT,pop(@ROT)); + } + +$code.=<<___; + cmpb \$0,`$SZ-1`($Tbl) + jnz .Lrounds_16_xx + + mov $_ctx,$ctx + add $a1,$A # modulo-scheduled h+=Sigma0(a) + lea 16*$SZ($inp),$inp + + add $SZ*0($ctx),$A + add $SZ*1($ctx),$B + add $SZ*2($ctx),$C + add $SZ*3($ctx),$D + add $SZ*4($ctx),$E + add $SZ*5($ctx),$F + add $SZ*6($ctx),$G + add $SZ*7($ctx),$H + + cmp $_end,$inp + + mov $A,$SZ*0($ctx) + mov $B,$SZ*1($ctx) + mov $C,$SZ*2($ctx) + mov $D,$SZ*3($ctx) + mov $E,$SZ*4($ctx) + mov $F,$SZ*5($ctx) + mov $G,$SZ*6($ctx) + mov $H,$SZ*7($ctx) + jb .Lloop + + mov $_rsp,%rsi + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lepilogue: + ret +.size $func,.-$func +___ + +if ($SZ==4) { +$code.=<<___; +.align 64 +.type $TABLE,\@object +$TABLE: + .long 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5 + .long 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5 + .long 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5 + .long 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5 + .long 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3 + .long 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3 + .long 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174 + .long 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174 + .long 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc + .long 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc + .long 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da + .long 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da + .long 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7 + .long 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7 + .long 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967 + .long 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967 + .long 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13 + .long 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13 + .long 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85 + .long 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85 + .long 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3 + .long 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3 + .long 0xd192e819,0xd6990624,0xf40e3585,0x106aa070 + .long 0xd192e819,0xd6990624,0xf40e3585,0x106aa070 + .long 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5 + .long 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5 + .long 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3 + .long 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3 + .long 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208 + .long 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208 + .long 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 + .long 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 + + .long 0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f + .long 0x00010203,0x04050607,0x08090a0b,0x0c0d0e0f + .long 0x03020100,0x0b0a0908,0xffffffff,0xffffffff + .long 0x03020100,0x0b0a0908,0xffffffff,0xffffffff + .long 0xffffffff,0xffffffff,0x03020100,0x0b0a0908 + .long 0xffffffff,0xffffffff,0x03020100,0x0b0a0908 + .asciz "SHA256 block transform for x86_64, CRYPTOGAMS by " +___ +} else { +$code.=<<___; +.align 64 +.type $TABLE,\@object +$TABLE: + .quad 0x428a2f98d728ae22,0x7137449123ef65cd + .quad 0x428a2f98d728ae22,0x7137449123ef65cd + .quad 0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc + .quad 0xb5c0fbcfec4d3b2f,0xe9b5dba58189dbbc + .quad 0x3956c25bf348b538,0x59f111f1b605d019 + .quad 0x3956c25bf348b538,0x59f111f1b605d019 + .quad 0x923f82a4af194f9b,0xab1c5ed5da6d8118 + .quad 0x923f82a4af194f9b,0xab1c5ed5da6d8118 + .quad 0xd807aa98a3030242,0x12835b0145706fbe + .quad 0xd807aa98a3030242,0x12835b0145706fbe + .quad 0x243185be4ee4b28c,0x550c7dc3d5ffb4e2 + .quad 0x243185be4ee4b28c,0x550c7dc3d5ffb4e2 + .quad 0x72be5d74f27b896f,0x80deb1fe3b1696b1 + .quad 0x72be5d74f27b896f,0x80deb1fe3b1696b1 + .quad 0x9bdc06a725c71235,0xc19bf174cf692694 + .quad 0x9bdc06a725c71235,0xc19bf174cf692694 + .quad 0xe49b69c19ef14ad2,0xefbe4786384f25e3 + .quad 0xe49b69c19ef14ad2,0xefbe4786384f25e3 + .quad 0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65 + .quad 0x0fc19dc68b8cd5b5,0x240ca1cc77ac9c65 + .quad 0x2de92c6f592b0275,0x4a7484aa6ea6e483 + .quad 0x2de92c6f592b0275,0x4a7484aa6ea6e483 + .quad 0x5cb0a9dcbd41fbd4,0x76f988da831153b5 + .quad 0x5cb0a9dcbd41fbd4,0x76f988da831153b5 + .quad 0x983e5152ee66dfab,0xa831c66d2db43210 + .quad 0x983e5152ee66dfab,0xa831c66d2db43210 + .quad 0xb00327c898fb213f,0xbf597fc7beef0ee4 + .quad 0xb00327c898fb213f,0xbf597fc7beef0ee4 + .quad 0xc6e00bf33da88fc2,0xd5a79147930aa725 + .quad 0xc6e00bf33da88fc2,0xd5a79147930aa725 + .quad 0x06ca6351e003826f,0x142929670a0e6e70 + .quad 0x06ca6351e003826f,0x142929670a0e6e70 + .quad 0x27b70a8546d22ffc,0x2e1b21385c26c926 + .quad 0x27b70a8546d22ffc,0x2e1b21385c26c926 + .quad 0x4d2c6dfc5ac42aed,0x53380d139d95b3df + .quad 0x4d2c6dfc5ac42aed,0x53380d139d95b3df + .quad 0x650a73548baf63de,0x766a0abb3c77b2a8 + .quad 0x650a73548baf63de,0x766a0abb3c77b2a8 + .quad 0x81c2c92e47edaee6,0x92722c851482353b + .quad 0x81c2c92e47edaee6,0x92722c851482353b + .quad 0xa2bfe8a14cf10364,0xa81a664bbc423001 + .quad 0xa2bfe8a14cf10364,0xa81a664bbc423001 + .quad 0xc24b8b70d0f89791,0xc76c51a30654be30 + .quad 0xc24b8b70d0f89791,0xc76c51a30654be30 + .quad 0xd192e819d6ef5218,0xd69906245565a910 + .quad 0xd192e819d6ef5218,0xd69906245565a910 + .quad 0xf40e35855771202a,0x106aa07032bbd1b8 + .quad 0xf40e35855771202a,0x106aa07032bbd1b8 + .quad 0x19a4c116b8d2d0c8,0x1e376c085141ab53 + .quad 0x19a4c116b8d2d0c8,0x1e376c085141ab53 + .quad 0x2748774cdf8eeb99,0x34b0bcb5e19b48a8 + .quad 0x2748774cdf8eeb99,0x34b0bcb5e19b48a8 + .quad 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb + .quad 0x391c0cb3c5c95a63,0x4ed8aa4ae3418acb + .quad 0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3 + .quad 0x5b9cca4f7763e373,0x682e6ff3d6b2b8a3 + .quad 0x748f82ee5defb2fc,0x78a5636f43172f60 + .quad 0x748f82ee5defb2fc,0x78a5636f43172f60 + .quad 0x84c87814a1f0ab72,0x8cc702081a6439ec + .quad 0x84c87814a1f0ab72,0x8cc702081a6439ec + .quad 0x90befffa23631e28,0xa4506cebde82bde9 + .quad 0x90befffa23631e28,0xa4506cebde82bde9 + .quad 0xbef9a3f7b2c67915,0xc67178f2e372532b + .quad 0xbef9a3f7b2c67915,0xc67178f2e372532b + .quad 0xca273eceea26619c,0xd186b8c721c0c207 + .quad 0xca273eceea26619c,0xd186b8c721c0c207 + .quad 0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178 + .quad 0xeada7dd6cde0eb1e,0xf57d4f7fee6ed178 + .quad 0x06f067aa72176fba,0x0a637dc5a2c898a6 + .quad 0x06f067aa72176fba,0x0a637dc5a2c898a6 + .quad 0x113f9804bef90dae,0x1b710b35131c471b + .quad 0x113f9804bef90dae,0x1b710b35131c471b + .quad 0x28db77f523047d84,0x32caab7b40c72493 + .quad 0x28db77f523047d84,0x32caab7b40c72493 + .quad 0x3c9ebe0a15c9bebc,0x431d67c49c100d4c + .quad 0x3c9ebe0a15c9bebc,0x431d67c49c100d4c + .quad 0x4cc5d4becb3e42b6,0x597f299cfc657e2a + .quad 0x4cc5d4becb3e42b6,0x597f299cfc657e2a + .quad 0x5fcb6fab3ad6faec,0x6c44198c4a475817 + .quad 0x5fcb6fab3ad6faec,0x6c44198c4a475817 + + .quad 0x0001020304050607,0x08090a0b0c0d0e0f + .quad 0x0001020304050607,0x08090a0b0c0d0e0f + .asciz "SHA512 block transform for x86_64, CRYPTOGAMS by " +___ +} + +###################################################################### +# SIMD code paths +# +if ($SZ==4 && $shaext) {{{ +###################################################################### +# Intel SHA Extensions implementation of SHA256 update function. +# +my ($ctx,$inp,$num,$Tbl)=("%rdi","%rsi","%rdx","%rcx"); + +my ($Wi,$ABEF,$CDGH,$TMP,$BSWAP,$ABEF_SAVE,$CDGH_SAVE)=map("%xmm$_",(0..2,7..10)); +my @MSG=map("%xmm$_",(3..6)); + +$code.=<<___; +.type sha256_block_data_order_shaext,\@function,3 +.align 64 +sha256_block_data_order_shaext: +_shaext_shortcut: +___ +$code.=<<___ if ($win64); + lea `-8-5*16`(%rsp),%rsp + movaps %xmm6,-8-5*16(%rax) + movaps %xmm7,-8-4*16(%rax) + movaps %xmm8,-8-3*16(%rax) + movaps %xmm9,-8-2*16(%rax) + movaps %xmm10,-8-1*16(%rax) +.Lprologue_shaext: +___ +$code.=<<___; + lea K256+0x80(%rip),$Tbl + movdqu ($ctx),$ABEF # DCBA + movdqu 16($ctx),$CDGH # HGFE + movdqa 0x200-0x80($Tbl),$TMP # byte swap mask + + pshufd \$0x1b,$ABEF,$Wi # ABCD + pshufd \$0xb1,$ABEF,$ABEF # CDAB + pshufd \$0x1b,$CDGH,$CDGH # EFGH + movdqa $TMP,$BSWAP # offload + palignr \$8,$CDGH,$ABEF # ABEF + punpcklqdq $Wi,$CDGH # CDGH + jmp .Loop_shaext + +.align 16 +.Loop_shaext: + movdqu ($inp),@MSG[0] + movdqu 0x10($inp),@MSG[1] + movdqu 0x20($inp),@MSG[2] + pshufb $TMP,@MSG[0] + movdqu 0x30($inp),@MSG[3] + + movdqa 0*32-0x80($Tbl),$Wi + paddd @MSG[0],$Wi + pshufb $TMP,@MSG[1] + movdqa $CDGH,$CDGH_SAVE # offload + sha256rnds2 $ABEF,$CDGH # 0-3 + pshufd \$0x0e,$Wi,$Wi + nop + movdqa $ABEF,$ABEF_SAVE # offload + sha256rnds2 $CDGH,$ABEF + + movdqa 1*32-0x80($Tbl),$Wi + paddd @MSG[1],$Wi + pshufb $TMP,@MSG[2] + sha256rnds2 $ABEF,$CDGH # 4-7 + pshufd \$0x0e,$Wi,$Wi + lea 0x40($inp),$inp + sha256msg1 @MSG[1],@MSG[0] + sha256rnds2 $CDGH,$ABEF + + movdqa 2*32-0x80($Tbl),$Wi + paddd @MSG[2],$Wi + pshufb $TMP,@MSG[3] + sha256rnds2 $ABEF,$CDGH # 8-11 + pshufd \$0x0e,$Wi,$Wi + movdqa @MSG[3],$TMP + palignr \$4,@MSG[2],$TMP + nop + paddd $TMP,@MSG[0] + sha256msg1 @MSG[2],@MSG[1] + sha256rnds2 $CDGH,$ABEF + + movdqa 3*32-0x80($Tbl),$Wi + paddd @MSG[3],$Wi + sha256msg2 @MSG[3],@MSG[0] + sha256rnds2 $ABEF,$CDGH # 12-15 + pshufd \$0x0e,$Wi,$Wi + movdqa @MSG[0],$TMP + palignr \$4,@MSG[3],$TMP + nop + paddd $TMP,@MSG[1] + sha256msg1 @MSG[3],@MSG[2] + sha256rnds2 $CDGH,$ABEF +___ +for($i=4;$i<16-3;$i++) { +$code.=<<___; + movdqa $i*32-0x80($Tbl),$Wi + paddd @MSG[0],$Wi + sha256msg2 @MSG[0],@MSG[1] + sha256rnds2 $ABEF,$CDGH # 16-19... + pshufd \$0x0e,$Wi,$Wi + movdqa @MSG[1],$TMP + palignr \$4,@MSG[0],$TMP + nop + paddd $TMP,@MSG[2] + sha256msg1 @MSG[0],@MSG[3] + sha256rnds2 $CDGH,$ABEF +___ + push(@MSG,shift(@MSG)); +} +$code.=<<___; + movdqa 13*32-0x80($Tbl),$Wi + paddd @MSG[0],$Wi + sha256msg2 @MSG[0],@MSG[1] + sha256rnds2 $ABEF,$CDGH # 52-55 + pshufd \$0x0e,$Wi,$Wi + movdqa @MSG[1],$TMP + palignr \$4,@MSG[0],$TMP + sha256rnds2 $CDGH,$ABEF + paddd $TMP,@MSG[2] + + movdqa 14*32-0x80($Tbl),$Wi + paddd @MSG[1],$Wi + sha256rnds2 $ABEF,$CDGH # 56-59 + pshufd \$0x0e,$Wi,$Wi + sha256msg2 @MSG[1],@MSG[2] + movdqa $BSWAP,$TMP + sha256rnds2 $CDGH,$ABEF + + movdqa 15*32-0x80($Tbl),$Wi + paddd @MSG[2],$Wi + nop + sha256rnds2 $ABEF,$CDGH # 60-63 + pshufd \$0x0e,$Wi,$Wi + dec $num + nop + sha256rnds2 $CDGH,$ABEF + + paddd $CDGH_SAVE,$CDGH + paddd $ABEF_SAVE,$ABEF + jnz .Loop_shaext + + pshufd \$0xb1,$CDGH,$CDGH # DCHG + pshufd \$0x1b,$ABEF,$TMP # FEBA + pshufd \$0xb1,$ABEF,$ABEF # BAFE + punpckhqdq $CDGH,$ABEF # DCBA + palignr \$8,$TMP,$CDGH # HGFE + + movdqu $ABEF,($ctx) + movdqu $CDGH,16($ctx) +___ +$code.=<<___ if ($win64); + movaps -8-5*16(%rax),%xmm6 + movaps -8-4*16(%rax),%xmm7 + movaps -8-3*16(%rax),%xmm8 + movaps -8-2*16(%rax),%xmm9 + movaps -8-1*16(%rax),%xmm10 + mov %rax,%rsp +.Lepilogue_shaext: +___ +$code.=<<___; + ret +.size sha256_block_data_order_shaext,.-sha256_block_data_order_shaext +___ +}}} +{{{ + +my $a4=$T1; +my ($a,$b,$c,$d,$e,$f,$g,$h); + +sub AUTOLOAD() # thunk [simplified] 32-bit style perlasm +{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; + my $arg = pop; + $arg = "\$$arg" if ($arg*1 eq $arg); + $code .= "\t$opcode\t".join(',',$arg,reverse @_)."\n"; +} + +sub body_00_15 () { + ( + '($a,$b,$c,$d,$e,$f,$g,$h)=@ROT;'. + + '&ror ($a0,$Sigma1[2]-$Sigma1[1])', + '&mov ($a,$a1)', + '&mov ($a4,$f)', + + '&ror ($a1,$Sigma0[2]-$Sigma0[1])', + '&xor ($a0,$e)', + '&xor ($a4,$g)', # f^g + + '&ror ($a0,$Sigma1[1]-$Sigma1[0])', + '&xor ($a1,$a)', + '&and ($a4,$e)', # (f^g)&e + + '&xor ($a0,$e)', + '&add ($h,$SZ*($i&15)."(%rsp)")', # h+=X[i]+K[i] + '&mov ($a2,$a)', + + '&xor ($a4,$g)', # Ch(e,f,g)=((f^g)&e)^g + '&ror ($a1,$Sigma0[1]-$Sigma0[0])', + '&xor ($a2,$b)', # a^b, b^c in next round + + '&add ($h,$a4)', # h+=Ch(e,f,g) + '&ror ($a0,$Sigma1[0])', # Sigma1(e) + '&and ($a3,$a2)', # (b^c)&(a^b) + + '&xor ($a1,$a)', + '&add ($h,$a0)', # h+=Sigma1(e) + '&xor ($a3,$b)', # Maj(a,b,c)=Ch(a^b,c,b) + + '&ror ($a1,$Sigma0[0])', # Sigma0(a) + '&add ($d,$h)', # d+=h + '&add ($h,$a3)', # h+=Maj(a,b,c) + + '&mov ($a0,$d)', + '&add ($a1,$h);'. # h+=Sigma0(a) + '($a2,$a3) = ($a3,$a2); unshift(@ROT,pop(@ROT)); $i++;' + ); +} + +###################################################################### +# SSSE3 code path +# +if ($SZ==4) { # SHA256 only +my @X = map("%xmm$_",(0..3)); +my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%xmm$_",(4..9)); + +$code.=<<___; +.type ${func}_ssse3,\@function,3 +.align 64 +${func}_ssse3: +.Lssse3_shortcut: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + mov %rsp,%r11 # copy %rsp + shl \$4,%rdx # num*16 + sub \$`$framesz+$win64*16*4`,%rsp + lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ + and \$-64,%rsp # align stack frame + mov $ctx,$_ctx # save ctx, 1st arg + mov $inp,$_inp # save inp, 2nd arh + mov %rdx,$_end # save end pointer, "3rd" arg + mov %r11,$_rsp # save copy of %rsp +___ +$code.=<<___ if ($win64); + movaps %xmm6,16*$SZ+32(%rsp) + movaps %xmm7,16*$SZ+48(%rsp) + movaps %xmm8,16*$SZ+64(%rsp) + movaps %xmm9,16*$SZ+80(%rsp) +___ +$code.=<<___; +.Lprologue_ssse3: + + mov $SZ*0($ctx),$A + mov $SZ*1($ctx),$B + mov $SZ*2($ctx),$C + mov $SZ*3($ctx),$D + mov $SZ*4($ctx),$E + mov $SZ*5($ctx),$F + mov $SZ*6($ctx),$G + mov $SZ*7($ctx),$H +___ + +$code.=<<___; + #movdqa $TABLE+`$SZ*2*$rounds`+32(%rip),$t4 + #movdqa $TABLE+`$SZ*2*$rounds`+64(%rip),$t5 + jmp .Lloop_ssse3 +.align 16 +.Lloop_ssse3: + movdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3 + movdqu 0x00($inp),@X[0] + movdqu 0x10($inp),@X[1] + movdqu 0x20($inp),@X[2] + pshufb $t3,@X[0] + movdqu 0x30($inp),@X[3] + lea $TABLE(%rip),$Tbl + pshufb $t3,@X[1] + movdqa 0x00($Tbl),$t0 + movdqa 0x20($Tbl),$t1 + pshufb $t3,@X[2] + paddd @X[0],$t0 + movdqa 0x40($Tbl),$t2 + pshufb $t3,@X[3] + movdqa 0x60($Tbl),$t3 + paddd @X[1],$t1 + paddd @X[2],$t2 + paddd @X[3],$t3 + movdqa $t0,0x00(%rsp) + mov $A,$a1 + movdqa $t1,0x10(%rsp) + mov $B,$a3 + movdqa $t2,0x20(%rsp) + xor $C,$a3 # magic + movdqa $t3,0x30(%rsp) + mov $E,$a0 + jmp .Lssse3_00_47 + +.align 16 +.Lssse3_00_47: + sub \$`-16*2*$SZ`,$Tbl # size optimization +___ +sub Xupdate_256_SSSE3 () { + ( + '&movdqa ($t0,@X[1]);', + '&movdqa ($t3,@X[3])', + '&palignr ($t0,@X[0],$SZ)', # X[1..4] + '&palignr ($t3,@X[2],$SZ);', # X[9..12] + '&movdqa ($t1,$t0)', + '&movdqa ($t2,$t0);', + '&psrld ($t0,$sigma0[2])', + '&paddd (@X[0],$t3);', # X[0..3] += X[9..12] + '&psrld ($t2,$sigma0[0])', + '&pshufd ($t3,@X[3],0b11111010)',# X[14..15] + '&pslld ($t1,8*$SZ-$sigma0[1]);'. + '&pxor ($t0,$t2)', + '&psrld ($t2,$sigma0[1]-$sigma0[0]);'. + '&pxor ($t0,$t1)', + '&pslld ($t1,$sigma0[1]-$sigma0[0]);'. + '&pxor ($t0,$t2);', + '&movdqa ($t2,$t3)', + '&pxor ($t0,$t1);', # sigma0(X[1..4]) + '&psrld ($t3,$sigma1[2])', + '&paddd (@X[0],$t0);', # X[0..3] += sigma0(X[1..4]) + '&psrlq ($t2,$sigma1[0])', + '&pxor ($t3,$t2);', + '&psrlq ($t2,$sigma1[1]-$sigma1[0])', + '&pxor ($t3,$t2)', + '&pshufb ($t3,$t4)', # sigma1(X[14..15]) + '&paddd (@X[0],$t3)', # X[0..1] += sigma1(X[14..15]) + '&pshufd ($t3,@X[0],0b01010000)',# X[16..17] + '&movdqa ($t2,$t3);', + '&psrld ($t3,$sigma1[2])', + '&psrlq ($t2,$sigma1[0])', + '&pxor ($t3,$t2);', + '&psrlq ($t2,$sigma1[1]-$sigma1[0])', + '&pxor ($t3,$t2);', + '&movdqa ($t2,16*2*$j."($Tbl)")', + '&pshufb ($t3,$t5)', + '&paddd (@X[0],$t3)' # X[2..3] += sigma1(X[16..17]) + ); +} + +sub SSSE3_256_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body,&$body,&$body); # 104 instructions + + if (0) { + foreach (Xupdate_256_SSSE3()) { # 36 instructions + eval; + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + } + } else { # squeeze extra 4% on Westmere and 19% on Atom + eval(shift(@insns)); #@ + &movdqa ($t0,@X[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa ($t3,@X[3]); + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); #@ + eval(shift(@insns)); + &palignr ($t0,@X[0],$SZ); # X[1..4] + eval(shift(@insns)); + eval(shift(@insns)); + &palignr ($t3,@X[2],$SZ); # X[9..12] + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); #@ + &movdqa ($t1,$t0); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa ($t2,$t0); + eval(shift(@insns)); #@ + eval(shift(@insns)); + &psrld ($t0,$sigma0[2]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@X[0],$t3); # X[0..3] += X[9..12] + eval(shift(@insns)); #@ + eval(shift(@insns)); + &psrld ($t2,$sigma0[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &pshufd ($t3,@X[3],0b11111010); # X[4..15] + eval(shift(@insns)); + eval(shift(@insns)); #@ + &pslld ($t1,8*$SZ-$sigma0[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &pxor ($t0,$t2); + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); #@ + &psrld ($t2,$sigma0[1]-$sigma0[0]); + eval(shift(@insns)); + &pxor ($t0,$t1); + eval(shift(@insns)); + eval(shift(@insns)); + &pslld ($t1,$sigma0[1]-$sigma0[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &pxor ($t0,$t2); + eval(shift(@insns)); + eval(shift(@insns)); #@ + &movdqa ($t2,$t3); + eval(shift(@insns)); + eval(shift(@insns)); + &pxor ($t0,$t1); # sigma0(X[1..4]) + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + &psrld ($t3,$sigma1[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@X[0],$t0); # X[0..3] += sigma0(X[1..4]) + eval(shift(@insns)); #@ + eval(shift(@insns)); + &psrlq ($t2,$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &pxor ($t3,$t2); + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); #@ + &psrlq ($t2,$sigma1[1]-$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &pxor ($t3,$t2); + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + #&pshufb ($t3,$t4); # sigma1(X[14..15]) + &pshufd ($t3,$t3,0b10000000); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &psrldq ($t3,8); + eval(shift(@insns)); + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); #@ + &paddd (@X[0],$t3); # X[0..1] += sigma1(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &pshufd ($t3,@X[0],0b01010000); # X[16..17] + eval(shift(@insns)); + eval(shift(@insns)); #@ + eval(shift(@insns)); + &movdqa ($t2,$t3); + eval(shift(@insns)); + eval(shift(@insns)); + &psrld ($t3,$sigma1[2]); + eval(shift(@insns)); + eval(shift(@insns)); #@ + &psrlq ($t2,$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &pxor ($t3,$t2); + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); #@ + eval(shift(@insns)); + &psrlq ($t2,$sigma1[1]-$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &pxor ($t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); #@ + #&pshufb ($t3,$t5); + &pshufd ($t3,$t3,0b00001000); + eval(shift(@insns)); + eval(shift(@insns)); + &movdqa ($t2,16*2*$j."($Tbl)"); + eval(shift(@insns)); #@ + eval(shift(@insns)); + &pslldq ($t3,8); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &paddd (@X[0],$t3); # X[2..3] += sigma1(X[16..17]) + eval(shift(@insns)); #@ + eval(shift(@insns)); + eval(shift(@insns)); + } + &paddd ($t2,@X[0]); + foreach (@insns) { eval; } # remaining instructions + &movdqa (16*$j."(%rsp)",$t2); +} + + for ($i=0,$j=0; $j<4; $j++) { + &SSSE3_256_00_47($j,\&body_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmpb ($SZ-1+16*2*$SZ."($Tbl)",0); + &jne (".Lssse3_00_47"); + + for ($i=0; $i<16; ) { + foreach(body_00_15()) { eval; } + } +$code.=<<___; + mov $_ctx,$ctx + mov $a1,$A + + add $SZ*0($ctx),$A + lea 16*$SZ($inp),$inp + add $SZ*1($ctx),$B + add $SZ*2($ctx),$C + add $SZ*3($ctx),$D + add $SZ*4($ctx),$E + add $SZ*5($ctx),$F + add $SZ*6($ctx),$G + add $SZ*7($ctx),$H + + cmp $_end,$inp + + mov $A,$SZ*0($ctx) + mov $B,$SZ*1($ctx) + mov $C,$SZ*2($ctx) + mov $D,$SZ*3($ctx) + mov $E,$SZ*4($ctx) + mov $F,$SZ*5($ctx) + mov $G,$SZ*6($ctx) + mov $H,$SZ*7($ctx) + jb .Lloop_ssse3 + + mov $_rsp,%rsi +___ +$code.=<<___ if ($win64); + movaps 16*$SZ+32(%rsp),%xmm6 + movaps 16*$SZ+48(%rsp),%xmm7 + movaps 16*$SZ+64(%rsp),%xmm8 + movaps 16*$SZ+80(%rsp),%xmm9 +___ +$code.=<<___; + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lepilogue_ssse3: + ret +.size ${func}_ssse3,.-${func}_ssse3 +___ +} + +if ($avx) {{ +###################################################################### +# XOP code path +# +if ($SZ==8) { # SHA512 only +$code.=<<___; +.type ${func}_xop,\@function,3 +.align 64 +${func}_xop: +.Lxop_shortcut: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + mov %rsp,%r11 # copy %rsp + shl \$4,%rdx # num*16 + sub \$`$framesz+$win64*16*($SZ==4?4:6)`,%rsp + lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ + and \$-64,%rsp # align stack frame + mov $ctx,$_ctx # save ctx, 1st arg + mov $inp,$_inp # save inp, 2nd arh + mov %rdx,$_end # save end pointer, "3rd" arg + mov %r11,$_rsp # save copy of %rsp +___ +$code.=<<___ if ($win64); + movaps %xmm6,16*$SZ+32(%rsp) + movaps %xmm7,16*$SZ+48(%rsp) + movaps %xmm8,16*$SZ+64(%rsp) + movaps %xmm9,16*$SZ+80(%rsp) +___ +$code.=<<___ if ($win64 && $SZ>4); + movaps %xmm10,16*$SZ+96(%rsp) + movaps %xmm11,16*$SZ+112(%rsp) +___ +$code.=<<___; +.Lprologue_xop: + + vzeroupper + mov $SZ*0($ctx),$A + mov $SZ*1($ctx),$B + mov $SZ*2($ctx),$C + mov $SZ*3($ctx),$D + mov $SZ*4($ctx),$E + mov $SZ*5($ctx),$F + mov $SZ*6($ctx),$G + mov $SZ*7($ctx),$H + jmp .Lloop_xop +___ + if ($SZ==4) { # SHA256 + my @X = map("%xmm$_",(0..3)); + my ($t0,$t1,$t2,$t3) = map("%xmm$_",(4..7)); + +$code.=<<___; +.align 16 +.Lloop_xop: + vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3 + vmovdqu 0x00($inp),@X[0] + vmovdqu 0x10($inp),@X[1] + vmovdqu 0x20($inp),@X[2] + vmovdqu 0x30($inp),@X[3] + vpshufb $t3,@X[0],@X[0] + lea $TABLE(%rip),$Tbl + vpshufb $t3,@X[1],@X[1] + vpshufb $t3,@X[2],@X[2] + vpaddd 0x00($Tbl),@X[0],$t0 + vpshufb $t3,@X[3],@X[3] + vpaddd 0x20($Tbl),@X[1],$t1 + vpaddd 0x40($Tbl),@X[2],$t2 + vpaddd 0x60($Tbl),@X[3],$t3 + vmovdqa $t0,0x00(%rsp) + mov $A,$a1 + vmovdqa $t1,0x10(%rsp) + mov $B,$a3 + vmovdqa $t2,0x20(%rsp) + xor $C,$a3 # magic + vmovdqa $t3,0x30(%rsp) + mov $E,$a0 + jmp .Lxop_00_47 + +.align 16 +.Lxop_00_47: + sub \$`-16*2*$SZ`,$Tbl # size optimization +___ +sub XOP_256_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body,&$body,&$body); # 104 instructions + + &vpalignr ($t0,@X[1],@X[0],$SZ); # X[1..4] + eval(shift(@insns)); + eval(shift(@insns)); + &vpalignr ($t3,@X[3],@X[2],$SZ); # X[9..12] + eval(shift(@insns)); + eval(shift(@insns)); + &vprotd ($t1,$t0,8*$SZ-$sigma0[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrld ($t0,$t0,$sigma0[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddd (@X[0],@X[0],$t3); # X[0..3] += X[9..12] + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vprotd ($t2,$t1,$sigma0[1]-$sigma0[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t0,$t0,$t1); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vprotd ($t3,@X[3],8*$SZ-$sigma1[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t0,$t0,$t2); # sigma0(X[1..4]) + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrld ($t2,@X[3],$sigma1[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddd (@X[0],@X[0],$t0); # X[0..3] += sigma0(X[1..4]) + eval(shift(@insns)); + eval(shift(@insns)); + &vprotd ($t1,$t3,$sigma1[1]-$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t3,$t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t3,$t3,$t1); # sigma1(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrldq ($t3,$t3,8); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddd (@X[0],@X[0],$t3); # X[0..1] += sigma1(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vprotd ($t3,@X[0],8*$SZ-$sigma1[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrld ($t2,@X[0],$sigma1[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vprotd ($t1,$t3,$sigma1[1]-$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t3,$t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t3,$t3,$t1); # sigma1(X[16..17]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpslldq ($t3,$t3,8); # 22 instructions + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddd (@X[0],@X[0],$t3); # X[2..3] += sigma1(X[16..17]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddd ($t2,@X[0],16*2*$j."($Tbl)"); + foreach (@insns) { eval; } # remaining instructions + &vmovdqa (16*$j."(%rsp)",$t2); +} + + for ($i=0,$j=0; $j<4; $j++) { + &XOP_256_00_47($j,\&body_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmpb ($SZ-1+16*2*$SZ."($Tbl)",0); + &jne (".Lxop_00_47"); + + for ($i=0; $i<16; ) { + foreach(body_00_15()) { eval; } + } + + } else { # SHA512 + my @X = map("%xmm$_",(0..7)); + my ($t0,$t1,$t2,$t3) = map("%xmm$_",(8..11)); + +$code.=<<___; +.align 16 +.Lloop_xop: + vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3 + vmovdqu 0x00($inp),@X[0] + lea $TABLE+0x80(%rip),$Tbl # size optimization + vmovdqu 0x10($inp),@X[1] + vmovdqu 0x20($inp),@X[2] + vpshufb $t3,@X[0],@X[0] + vmovdqu 0x30($inp),@X[3] + vpshufb $t3,@X[1],@X[1] + vmovdqu 0x40($inp),@X[4] + vpshufb $t3,@X[2],@X[2] + vmovdqu 0x50($inp),@X[5] + vpshufb $t3,@X[3],@X[3] + vmovdqu 0x60($inp),@X[6] + vpshufb $t3,@X[4],@X[4] + vmovdqu 0x70($inp),@X[7] + vpshufb $t3,@X[5],@X[5] + vpaddq -0x80($Tbl),@X[0],$t0 + vpshufb $t3,@X[6],@X[6] + vpaddq -0x60($Tbl),@X[1],$t1 + vpshufb $t3,@X[7],@X[7] + vpaddq -0x40($Tbl),@X[2],$t2 + vpaddq -0x20($Tbl),@X[3],$t3 + vmovdqa $t0,0x00(%rsp) + vpaddq 0x00($Tbl),@X[4],$t0 + vmovdqa $t1,0x10(%rsp) + vpaddq 0x20($Tbl),@X[5],$t1 + vmovdqa $t2,0x20(%rsp) + vpaddq 0x40($Tbl),@X[6],$t2 + vmovdqa $t3,0x30(%rsp) + vpaddq 0x60($Tbl),@X[7],$t3 + vmovdqa $t0,0x40(%rsp) + mov $A,$a1 + vmovdqa $t1,0x50(%rsp) + mov $B,$a3 + vmovdqa $t2,0x60(%rsp) + xor $C,$a3 # magic + vmovdqa $t3,0x70(%rsp) + mov $E,$a0 + jmp .Lxop_00_47 + +.align 16 +.Lxop_00_47: + add \$`16*2*$SZ`,$Tbl +___ +sub XOP_512_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body); # 52 instructions + + &vpalignr ($t0,@X[1],@X[0],$SZ); # X[1..2] + eval(shift(@insns)); + eval(shift(@insns)); + &vpalignr ($t3,@X[5],@X[4],$SZ); # X[9..10] + eval(shift(@insns)); + eval(shift(@insns)); + &vprotq ($t1,$t0,8*$SZ-$sigma0[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrlq ($t0,$t0,$sigma0[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddq (@X[0],@X[0],$t3); # X[0..1] += X[9..10] + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vprotq ($t2,$t1,$sigma0[1]-$sigma0[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t0,$t0,$t1); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vprotq ($t3,@X[7],8*$SZ-$sigma1[1]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t0,$t0,$t2); # sigma0(X[1..2]) + eval(shift(@insns)); + eval(shift(@insns)); + &vpsrlq ($t2,@X[7],$sigma1[2]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddq (@X[0],@X[0],$t0); # X[0..1] += sigma0(X[1..2]) + eval(shift(@insns)); + eval(shift(@insns)); + &vprotq ($t1,$t3,$sigma1[1]-$sigma1[0]); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t3,$t3,$t2); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpxor ($t3,$t3,$t1); # sigma1(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddq (@X[0],@X[0],$t3); # X[0..1] += sigma1(X[14..15]) + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + &vpaddq ($t2,@X[0],16*2*$j-0x80."($Tbl)"); + foreach (@insns) { eval; } # remaining instructions + &vmovdqa (16*$j."(%rsp)",$t2); +} + + for ($i=0,$j=0; $j<8; $j++) { + &XOP_512_00_47($j,\&body_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmpb ($SZ-1+16*2*$SZ-0x80."($Tbl)",0); + &jne (".Lxop_00_47"); + + for ($i=0; $i<16; ) { + foreach(body_00_15()) { eval; } + } +} +$code.=<<___; + mov $_ctx,$ctx + mov $a1,$A + + add $SZ*0($ctx),$A + lea 16*$SZ($inp),$inp + add $SZ*1($ctx),$B + add $SZ*2($ctx),$C + add $SZ*3($ctx),$D + add $SZ*4($ctx),$E + add $SZ*5($ctx),$F + add $SZ*6($ctx),$G + add $SZ*7($ctx),$H + + cmp $_end,$inp + + mov $A,$SZ*0($ctx) + mov $B,$SZ*1($ctx) + mov $C,$SZ*2($ctx) + mov $D,$SZ*3($ctx) + mov $E,$SZ*4($ctx) + mov $F,$SZ*5($ctx) + mov $G,$SZ*6($ctx) + mov $H,$SZ*7($ctx) + jb .Lloop_xop + + mov $_rsp,%rsi + vzeroupper +___ +$code.=<<___ if ($win64); + movaps 16*$SZ+32(%rsp),%xmm6 + movaps 16*$SZ+48(%rsp),%xmm7 + movaps 16*$SZ+64(%rsp),%xmm8 + movaps 16*$SZ+80(%rsp),%xmm9 +___ +$code.=<<___ if ($win64 && $SZ>4); + movaps 16*$SZ+96(%rsp),%xmm10 + movaps 16*$SZ+112(%rsp),%xmm11 +___ +$code.=<<___; + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lepilogue_xop: + ret +.size ${func}_xop,.-${func}_xop +___ +} +###################################################################### +# AVX+shrd code path +# +local *ror = sub { &shrd(@_[0],@_) }; + +$code.=<<___; +.type ${func}_avx,\@function,3 +.align 64 +${func}_avx: +.Lavx_shortcut: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + mov %rsp,%r11 # copy %rsp + shl \$4,%rdx # num*16 + sub \$`$framesz+$win64*16*($SZ==4?4:6)`,%rsp + lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ + and \$-64,%rsp # align stack frame + mov $ctx,$_ctx # save ctx, 1st arg + mov $inp,$_inp # save inp, 2nd arh + mov %rdx,$_end # save end pointer, "3rd" arg + mov %r11,$_rsp # save copy of %rsp +___ +$code.=<<___ if ($win64); + movaps %xmm6,16*$SZ+32(%rsp) + movaps %xmm7,16*$SZ+48(%rsp) + movaps %xmm8,16*$SZ+64(%rsp) + movaps %xmm9,16*$SZ+80(%rsp) +___ +$code.=<<___ if ($win64 && $SZ>4); + movaps %xmm10,16*$SZ+96(%rsp) + movaps %xmm11,16*$SZ+112(%rsp) +___ +$code.=<<___; +.Lprologue_avx: + + vzeroupper + mov $SZ*0($ctx),$A + mov $SZ*1($ctx),$B + mov $SZ*2($ctx),$C + mov $SZ*3($ctx),$D + mov $SZ*4($ctx),$E + mov $SZ*5($ctx),$F + mov $SZ*6($ctx),$G + mov $SZ*7($ctx),$H +___ + if ($SZ==4) { # SHA256 + my @X = map("%xmm$_",(0..3)); + my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%xmm$_",(4..9)); + +$code.=<<___; + vmovdqa $TABLE+`$SZ*2*$rounds`+32(%rip),$t4 + vmovdqa $TABLE+`$SZ*2*$rounds`+64(%rip),$t5 + jmp .Lloop_avx +.align 16 +.Lloop_avx: + vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3 + vmovdqu 0x00($inp),@X[0] + vmovdqu 0x10($inp),@X[1] + vmovdqu 0x20($inp),@X[2] + vmovdqu 0x30($inp),@X[3] + vpshufb $t3,@X[0],@X[0] + lea $TABLE(%rip),$Tbl + vpshufb $t3,@X[1],@X[1] + vpshufb $t3,@X[2],@X[2] + vpaddd 0x00($Tbl),@X[0],$t0 + vpshufb $t3,@X[3],@X[3] + vpaddd 0x20($Tbl),@X[1],$t1 + vpaddd 0x40($Tbl),@X[2],$t2 + vpaddd 0x60($Tbl),@X[3],$t3 + vmovdqa $t0,0x00(%rsp) + mov $A,$a1 + vmovdqa $t1,0x10(%rsp) + mov $B,$a3 + vmovdqa $t2,0x20(%rsp) + xor $C,$a3 # magic + vmovdqa $t3,0x30(%rsp) + mov $E,$a0 + jmp .Lavx_00_47 + +.align 16 +.Lavx_00_47: + sub \$`-16*2*$SZ`,$Tbl # size optimization +___ +sub Xupdate_256_AVX () { + ( + '&vpalignr ($t0,@X[1],@X[0],$SZ)', # X[1..4] + '&vpalignr ($t3,@X[3],@X[2],$SZ)', # X[9..12] + '&vpsrld ($t2,$t0,$sigma0[0]);', + '&vpaddd (@X[0],@X[0],$t3)', # X[0..3] += X[9..12] + '&vpsrld ($t3,$t0,$sigma0[2])', + '&vpslld ($t1,$t0,8*$SZ-$sigma0[1]);', + '&vpxor ($t0,$t3,$t2)', + '&vpshufd ($t3,@X[3],0b11111010)',# X[14..15] + '&vpsrld ($t2,$t2,$sigma0[1]-$sigma0[0]);', + '&vpxor ($t0,$t0,$t1)', + '&vpslld ($t1,$t1,$sigma0[1]-$sigma0[0]);', + '&vpxor ($t0,$t0,$t2)', + '&vpsrld ($t2,$t3,$sigma1[2]);', + '&vpxor ($t0,$t0,$t1)', # sigma0(X[1..4]) + '&vpsrlq ($t3,$t3,$sigma1[0]);', + '&vpaddd (@X[0],@X[0],$t0)', # X[0..3] += sigma0(X[1..4]) + '&vpxor ($t2,$t2,$t3);', + '&vpsrlq ($t3,$t3,$sigma1[1]-$sigma1[0])', + '&vpxor ($t2,$t2,$t3)', + '&vpshufb ($t2,$t2,$t4)', # sigma1(X[14..15]) + '&vpaddd (@X[0],@X[0],$t2)', # X[0..1] += sigma1(X[14..15]) + '&vpshufd ($t3,@X[0],0b01010000)',# X[16..17] + '&vpsrld ($t2,$t3,$sigma1[2])', + '&vpsrlq ($t3,$t3,$sigma1[0])', + '&vpxor ($t2,$t2,$t3);', + '&vpsrlq ($t3,$t3,$sigma1[1]-$sigma1[0])', + '&vpxor ($t2,$t2,$t3)', + '&vpshufb ($t2,$t2,$t5)', + '&vpaddd (@X[0],@X[0],$t2)' # X[2..3] += sigma1(X[16..17]) + ); +} + +sub AVX_256_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body,&$body,&$body); # 104 instructions + + foreach (Xupdate_256_AVX()) { # 29 instructions + eval; + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + } + &vpaddd ($t2,@X[0],16*2*$j."($Tbl)"); + foreach (@insns) { eval; } # remaining instructions + &vmovdqa (16*$j."(%rsp)",$t2); +} + + for ($i=0,$j=0; $j<4; $j++) { + &AVX_256_00_47($j,\&body_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmpb ($SZ-1+16*2*$SZ."($Tbl)",0); + &jne (".Lavx_00_47"); + + for ($i=0; $i<16; ) { + foreach(body_00_15()) { eval; } + } + + } else { # SHA512 + my @X = map("%xmm$_",(0..7)); + my ($t0,$t1,$t2,$t3) = map("%xmm$_",(8..11)); + +$code.=<<___; + jmp .Lloop_avx +.align 16 +.Lloop_avx: + vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3 + vmovdqu 0x00($inp),@X[0] + lea $TABLE+0x80(%rip),$Tbl # size optimization + vmovdqu 0x10($inp),@X[1] + vmovdqu 0x20($inp),@X[2] + vpshufb $t3,@X[0],@X[0] + vmovdqu 0x30($inp),@X[3] + vpshufb $t3,@X[1],@X[1] + vmovdqu 0x40($inp),@X[4] + vpshufb $t3,@X[2],@X[2] + vmovdqu 0x50($inp),@X[5] + vpshufb $t3,@X[3],@X[3] + vmovdqu 0x60($inp),@X[6] + vpshufb $t3,@X[4],@X[4] + vmovdqu 0x70($inp),@X[7] + vpshufb $t3,@X[5],@X[5] + vpaddq -0x80($Tbl),@X[0],$t0 + vpshufb $t3,@X[6],@X[6] + vpaddq -0x60($Tbl),@X[1],$t1 + vpshufb $t3,@X[7],@X[7] + vpaddq -0x40($Tbl),@X[2],$t2 + vpaddq -0x20($Tbl),@X[3],$t3 + vmovdqa $t0,0x00(%rsp) + vpaddq 0x00($Tbl),@X[4],$t0 + vmovdqa $t1,0x10(%rsp) + vpaddq 0x20($Tbl),@X[5],$t1 + vmovdqa $t2,0x20(%rsp) + vpaddq 0x40($Tbl),@X[6],$t2 + vmovdqa $t3,0x30(%rsp) + vpaddq 0x60($Tbl),@X[7],$t3 + vmovdqa $t0,0x40(%rsp) + mov $A,$a1 + vmovdqa $t1,0x50(%rsp) + mov $B,$a3 + vmovdqa $t2,0x60(%rsp) + xor $C,$a3 # magic + vmovdqa $t3,0x70(%rsp) + mov $E,$a0 + jmp .Lavx_00_47 + +.align 16 +.Lavx_00_47: + add \$`16*2*$SZ`,$Tbl +___ +sub Xupdate_512_AVX () { + ( + '&vpalignr ($t0,@X[1],@X[0],$SZ)', # X[1..2] + '&vpalignr ($t3,@X[5],@X[4],$SZ)', # X[9..10] + '&vpsrlq ($t2,$t0,$sigma0[0])', + '&vpaddq (@X[0],@X[0],$t3);', # X[0..1] += X[9..10] + '&vpsrlq ($t3,$t0,$sigma0[2])', + '&vpsllq ($t1,$t0,8*$SZ-$sigma0[1]);', + '&vpxor ($t0,$t3,$t2)', + '&vpsrlq ($t2,$t2,$sigma0[1]-$sigma0[0]);', + '&vpxor ($t0,$t0,$t1)', + '&vpsllq ($t1,$t1,$sigma0[1]-$sigma0[0]);', + '&vpxor ($t0,$t0,$t2)', + '&vpsrlq ($t3,@X[7],$sigma1[2]);', + '&vpxor ($t0,$t0,$t1)', # sigma0(X[1..2]) + '&vpsllq ($t2,@X[7],8*$SZ-$sigma1[1]);', + '&vpaddq (@X[0],@X[0],$t0)', # X[0..1] += sigma0(X[1..2]) + '&vpsrlq ($t1,@X[7],$sigma1[0]);', + '&vpxor ($t3,$t3,$t2)', + '&vpsllq ($t2,$t2,$sigma1[1]-$sigma1[0]);', + '&vpxor ($t3,$t3,$t1)', + '&vpsrlq ($t1,$t1,$sigma1[1]-$sigma1[0]);', + '&vpxor ($t3,$t3,$t2)', + '&vpxor ($t3,$t3,$t1)', # sigma1(X[14..15]) + '&vpaddq (@X[0],@X[0],$t3)', # X[0..1] += sigma1(X[14..15]) + ); +} + +sub AVX_512_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body); # 52 instructions + + foreach (Xupdate_512_AVX()) { # 23 instructions + eval; + eval(shift(@insns)); + eval(shift(@insns)); + } + &vpaddq ($t2,@X[0],16*2*$j-0x80."($Tbl)"); + foreach (@insns) { eval; } # remaining instructions + &vmovdqa (16*$j."(%rsp)",$t2); +} + + for ($i=0,$j=0; $j<8; $j++) { + &AVX_512_00_47($j,\&body_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &cmpb ($SZ-1+16*2*$SZ-0x80."($Tbl)",0); + &jne (".Lavx_00_47"); + + for ($i=0; $i<16; ) { + foreach(body_00_15()) { eval; } + } +} +$code.=<<___; + mov $_ctx,$ctx + mov $a1,$A + + add $SZ*0($ctx),$A + lea 16*$SZ($inp),$inp + add $SZ*1($ctx),$B + add $SZ*2($ctx),$C + add $SZ*3($ctx),$D + add $SZ*4($ctx),$E + add $SZ*5($ctx),$F + add $SZ*6($ctx),$G + add $SZ*7($ctx),$H + + cmp $_end,$inp + + mov $A,$SZ*0($ctx) + mov $B,$SZ*1($ctx) + mov $C,$SZ*2($ctx) + mov $D,$SZ*3($ctx) + mov $E,$SZ*4($ctx) + mov $F,$SZ*5($ctx) + mov $G,$SZ*6($ctx) + mov $H,$SZ*7($ctx) + jb .Lloop_avx + + mov $_rsp,%rsi + vzeroupper +___ +$code.=<<___ if ($win64); + movaps 16*$SZ+32(%rsp),%xmm6 + movaps 16*$SZ+48(%rsp),%xmm7 + movaps 16*$SZ+64(%rsp),%xmm8 + movaps 16*$SZ+80(%rsp),%xmm9 +___ +$code.=<<___ if ($win64 && $SZ>4); + movaps 16*$SZ+96(%rsp),%xmm10 + movaps 16*$SZ+112(%rsp),%xmm11 +___ +$code.=<<___; + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lepilogue_avx: + ret +.size ${func}_avx,.-${func}_avx +___ + +if ($avx>1) {{ +###################################################################### +# AVX2+BMI code path +# +my $a5=$SZ==4?"%esi":"%rsi"; # zap $inp +my $PUSH8=8*2*$SZ; +use integer; + +sub bodyx_00_15 () { + # at start $a1 should be zero, $a3 - $b^$c and $a4 copy of $f + ( + '($a,$b,$c,$d,$e,$f,$g,$h)=@ROT;'. + + '&add ($h,(32*($i/(16/$SZ))+$SZ*($i%(16/$SZ)))%$PUSH8.$base)', # h+=X[i]+K[i] + '&and ($a4,$e)', # f&e + '&rorx ($a0,$e,$Sigma1[2])', + '&rorx ($a2,$e,$Sigma1[1])', + + '&lea ($a,"($a,$a1)")', # h+=Sigma0(a) from the past + '&lea ($h,"($h,$a4)")', + '&andn ($a4,$e,$g)', # ~e&g + '&xor ($a0,$a2)', + + '&rorx ($a1,$e,$Sigma1[0])', + '&lea ($h,"($h,$a4)")', # h+=Ch(e,f,g)=(e&f)+(~e&g) + '&xor ($a0,$a1)', # Sigma1(e) + '&mov ($a2,$a)', + + '&rorx ($a4,$a,$Sigma0[2])', + '&lea ($h,"($h,$a0)")', # h+=Sigma1(e) + '&xor ($a2,$b)', # a^b, b^c in next round + '&rorx ($a1,$a,$Sigma0[1])', + + '&rorx ($a0,$a,$Sigma0[0])', + '&lea ($d,"($d,$h)")', # d+=h + '&and ($a3,$a2)', # (b^c)&(a^b) + '&xor ($a1,$a4)', + + '&xor ($a3,$b)', # Maj(a,b,c)=Ch(a^b,c,b) + '&xor ($a1,$a0)', # Sigma0(a) + '&lea ($h,"($h,$a3)");'. # h+=Maj(a,b,c) + '&mov ($a4,$e)', # copy of f in future + + '($a2,$a3) = ($a3,$a2); unshift(@ROT,pop(@ROT)); $i++;' + ); + # and at the finish one has to $a+=$a1 +} + +$code.=<<___; +.type ${func}_avx2,\@function,3 +.align 64 +${func}_avx2: +.Lavx2_shortcut: + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + mov %rsp,%r11 # copy %rsp + sub \$`2*$SZ*$rounds+4*8+$win64*16*($SZ==4?4:6)`,%rsp + shl \$4,%rdx # num*16 + and \$-256*$SZ,%rsp # align stack frame + lea ($inp,%rdx,$SZ),%rdx # inp+num*16*$SZ + add \$`2*$SZ*($rounds-8)`,%rsp + mov $ctx,$_ctx # save ctx, 1st arg + mov $inp,$_inp # save inp, 2nd arh + mov %rdx,$_end # save end pointer, "3rd" arg + mov %r11,$_rsp # save copy of %rsp +___ +$code.=<<___ if ($win64); + movaps %xmm6,16*$SZ+32(%rsp) + movaps %xmm7,16*$SZ+48(%rsp) + movaps %xmm8,16*$SZ+64(%rsp) + movaps %xmm9,16*$SZ+80(%rsp) +___ +$code.=<<___ if ($win64 && $SZ>4); + movaps %xmm10,16*$SZ+96(%rsp) + movaps %xmm11,16*$SZ+112(%rsp) +___ +$code.=<<___; +.Lprologue_avx2: + + vzeroupper + sub \$-16*$SZ,$inp # inp++, size optimization + mov $SZ*0($ctx),$A + mov $inp,%r12 # borrow $T1 + mov $SZ*1($ctx),$B + cmp %rdx,$inp # $_end + mov $SZ*2($ctx),$C + cmove %rsp,%r12 # next block or random data + mov $SZ*3($ctx),$D + mov $SZ*4($ctx),$E + mov $SZ*5($ctx),$F + mov $SZ*6($ctx),$G + mov $SZ*7($ctx),$H +___ + if ($SZ==4) { # SHA256 + my @X = map("%ymm$_",(0..3)); + my ($t0,$t1,$t2,$t3, $t4,$t5) = map("%ymm$_",(4..9)); + +$code.=<<___; + vmovdqa $TABLE+`$SZ*2*$rounds`+32(%rip),$t4 + vmovdqa $TABLE+`$SZ*2*$rounds`+64(%rip),$t5 + jmp .Loop_avx2 +.align 16 +.Loop_avx2: + vmovdqa $TABLE+`$SZ*2*$rounds`(%rip),$t3 + vmovdqu -16*$SZ+0($inp),%xmm0 + vmovdqu -16*$SZ+16($inp),%xmm1 + vmovdqu -16*$SZ+32($inp),%xmm2 + vmovdqu -16*$SZ+48($inp),%xmm3 + #mov $inp,$_inp # offload $inp + vinserti128 \$1,(%r12),@X[0],@X[0] + vinserti128 \$1,16(%r12),@X[1],@X[1] + vpshufb $t3,@X[0],@X[0] + vinserti128 \$1,32(%r12),@X[2],@X[2] + vpshufb $t3,@X[1],@X[1] + vinserti128 \$1,48(%r12),@X[3],@X[3] + + lea $TABLE(%rip),$Tbl + vpshufb $t3,@X[2],@X[2] + vpaddd 0x00($Tbl),@X[0],$t0 + vpshufb $t3,@X[3],@X[3] + vpaddd 0x20($Tbl),@X[1],$t1 + vpaddd 0x40($Tbl),@X[2],$t2 + vpaddd 0x60($Tbl),@X[3],$t3 + vmovdqa $t0,0x00(%rsp) + xor $a1,$a1 + vmovdqa $t1,0x20(%rsp) + lea -$PUSH8(%rsp),%rsp + mov $B,$a3 + vmovdqa $t2,0x00(%rsp) + xor $C,$a3 # magic + vmovdqa $t3,0x20(%rsp) + mov $F,$a4 + sub \$-16*2*$SZ,$Tbl # size optimization + jmp .Lavx2_00_47 + +.align 16 +.Lavx2_00_47: +___ + +sub AVX2_256_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body,&$body,&$body); # 96 instructions +my $base = "+2*$PUSH8(%rsp)"; + + &lea ("%rsp","-$PUSH8(%rsp)") if (($j%2)==0); + foreach (Xupdate_256_AVX()) { # 29 instructions + eval; + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + } + &vpaddd ($t2,@X[0],16*2*$j."($Tbl)"); + foreach (@insns) { eval; } # remaining instructions + &vmovdqa ((32*$j)%$PUSH8."(%rsp)",$t2); +} + + for ($i=0,$j=0; $j<4; $j++) { + &AVX2_256_00_47($j,\&bodyx_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &lea ($Tbl,16*2*$SZ."($Tbl)"); + &cmpb (($SZ-1)."($Tbl)",0); + &jne (".Lavx2_00_47"); + + for ($i=0; $i<16; ) { + my $base=$i<8?"+$PUSH8(%rsp)":"(%rsp)"; + foreach(bodyx_00_15()) { eval; } + } + } else { # SHA512 + my @X = map("%ymm$_",(0..7)); + my ($t0,$t1,$t2,$t3) = map("%ymm$_",(8..11)); + +$code.=<<___; + jmp .Loop_avx2 +.align 16 +.Loop_avx2: + vmovdqu -16*$SZ($inp),%xmm0 + vmovdqu -16*$SZ+16($inp),%xmm1 + vmovdqu -16*$SZ+32($inp),%xmm2 + lea $TABLE+0x80(%rip),$Tbl # size optimization + vmovdqu -16*$SZ+48($inp),%xmm3 + vmovdqu -16*$SZ+64($inp),%xmm4 + vmovdqu -16*$SZ+80($inp),%xmm5 + vmovdqu -16*$SZ+96($inp),%xmm6 + vmovdqu -16*$SZ+112($inp),%xmm7 + #mov $inp,$_inp # offload $inp + vmovdqa `$SZ*2*$rounds-0x80`($Tbl),$t2 + vinserti128 \$1,(%r12),@X[0],@X[0] + vinserti128 \$1,16(%r12),@X[1],@X[1] + vpshufb $t2,@X[0],@X[0] + vinserti128 \$1,32(%r12),@X[2],@X[2] + vpshufb $t2,@X[1],@X[1] + vinserti128 \$1,48(%r12),@X[3],@X[3] + vpshufb $t2,@X[2],@X[2] + vinserti128 \$1,64(%r12),@X[4],@X[4] + vpshufb $t2,@X[3],@X[3] + vinserti128 \$1,80(%r12),@X[5],@X[5] + vpshufb $t2,@X[4],@X[4] + vinserti128 \$1,96(%r12),@X[6],@X[6] + vpshufb $t2,@X[5],@X[5] + vinserti128 \$1,112(%r12),@X[7],@X[7] + + vpaddq -0x80($Tbl),@X[0],$t0 + vpshufb $t2,@X[6],@X[6] + vpaddq -0x60($Tbl),@X[1],$t1 + vpshufb $t2,@X[7],@X[7] + vpaddq -0x40($Tbl),@X[2],$t2 + vpaddq -0x20($Tbl),@X[3],$t3 + vmovdqa $t0,0x00(%rsp) + vpaddq 0x00($Tbl),@X[4],$t0 + vmovdqa $t1,0x20(%rsp) + vpaddq 0x20($Tbl),@X[5],$t1 + vmovdqa $t2,0x40(%rsp) + vpaddq 0x40($Tbl),@X[6],$t2 + vmovdqa $t3,0x60(%rsp) + lea -$PUSH8(%rsp),%rsp + vpaddq 0x60($Tbl),@X[7],$t3 + vmovdqa $t0,0x00(%rsp) + xor $a1,$a1 + vmovdqa $t1,0x20(%rsp) + mov $B,$a3 + vmovdqa $t2,0x40(%rsp) + xor $C,$a3 # magic + vmovdqa $t3,0x60(%rsp) + mov $F,$a4 + add \$16*2*$SZ,$Tbl + jmp .Lavx2_00_47 + +.align 16 +.Lavx2_00_47: +___ + +sub AVX2_512_00_47 () { +my $j = shift; +my $body = shift; +my @X = @_; +my @insns = (&$body,&$body); # 48 instructions +my $base = "+2*$PUSH8(%rsp)"; + + &lea ("%rsp","-$PUSH8(%rsp)") if (($j%4)==0); + foreach (Xupdate_512_AVX()) { # 23 instructions + eval; + if ($_ !~ /\;$/) { + eval(shift(@insns)); + eval(shift(@insns)); + eval(shift(@insns)); + } + } + &vpaddq ($t2,@X[0],16*2*$j-0x80."($Tbl)"); + foreach (@insns) { eval; } # remaining instructions + &vmovdqa ((32*$j)%$PUSH8."(%rsp)",$t2); +} + + for ($i=0,$j=0; $j<8; $j++) { + &AVX2_512_00_47($j,\&bodyx_00_15,@X); + push(@X,shift(@X)); # rotate(@X) + } + &lea ($Tbl,16*2*$SZ."($Tbl)"); + &cmpb (($SZ-1-0x80)."($Tbl)",0); + &jne (".Lavx2_00_47"); + + for ($i=0; $i<16; ) { + my $base=$i<8?"+$PUSH8(%rsp)":"(%rsp)"; + foreach(bodyx_00_15()) { eval; } + } +} +$code.=<<___; + mov `2*$SZ*$rounds`(%rsp),$ctx # $_ctx + add $a1,$A + #mov `2*$SZ*$rounds+8`(%rsp),$inp # $_inp + lea `2*$SZ*($rounds-8)`(%rsp),$Tbl + + add $SZ*0($ctx),$A + add $SZ*1($ctx),$B + add $SZ*2($ctx),$C + add $SZ*3($ctx),$D + add $SZ*4($ctx),$E + add $SZ*5($ctx),$F + add $SZ*6($ctx),$G + add $SZ*7($ctx),$H + + mov $A,$SZ*0($ctx) + mov $B,$SZ*1($ctx) + mov $C,$SZ*2($ctx) + mov $D,$SZ*3($ctx) + mov $E,$SZ*4($ctx) + mov $F,$SZ*5($ctx) + mov $G,$SZ*6($ctx) + mov $H,$SZ*7($ctx) + + cmp `$PUSH8+2*8`($Tbl),$inp # $_end + je .Ldone_avx2 + + xor $a1,$a1 + mov $B,$a3 + xor $C,$a3 # magic + mov $F,$a4 + jmp .Lower_avx2 +.align 16 +.Lower_avx2: +___ + for ($i=0; $i<8; ) { + my $base="+16($Tbl)"; + foreach(bodyx_00_15()) { eval; } + } +$code.=<<___; + lea -$PUSH8($Tbl),$Tbl + cmp %rsp,$Tbl + jae .Lower_avx2 + + mov `2*$SZ*$rounds`(%rsp),$ctx # $_ctx + add $a1,$A + #mov `2*$SZ*$rounds+8`(%rsp),$inp # $_inp + lea `2*$SZ*($rounds-8)`(%rsp),%rsp + + add $SZ*0($ctx),$A + add $SZ*1($ctx),$B + add $SZ*2($ctx),$C + add $SZ*3($ctx),$D + add $SZ*4($ctx),$E + add $SZ*5($ctx),$F + lea `2*16*$SZ`($inp),$inp # inp+=2 + add $SZ*6($ctx),$G + mov $inp,%r12 + add $SZ*7($ctx),$H + cmp $_end,$inp + + mov $A,$SZ*0($ctx) + cmove %rsp,%r12 # next block or stale data + mov $B,$SZ*1($ctx) + mov $C,$SZ*2($ctx) + mov $D,$SZ*3($ctx) + mov $E,$SZ*4($ctx) + mov $F,$SZ*5($ctx) + mov $G,$SZ*6($ctx) + mov $H,$SZ*7($ctx) + + jbe .Loop_avx2 + lea (%rsp),$Tbl + +.Ldone_avx2: + lea ($Tbl),%rsp + mov $_rsp,%rsi + vzeroupper +___ +$code.=<<___ if ($win64); + movaps 16*$SZ+32(%rsp),%xmm6 + movaps 16*$SZ+48(%rsp),%xmm7 + movaps 16*$SZ+64(%rsp),%xmm8 + movaps 16*$SZ+80(%rsp),%xmm9 +___ +$code.=<<___ if ($win64 && $SZ>4); + movaps 16*$SZ+96(%rsp),%xmm10 + movaps 16*$SZ+112(%rsp),%xmm11 +___ +$code.=<<___; + mov (%rsi),%r15 + mov 8(%rsi),%r14 + mov 16(%rsi),%r13 + mov 24(%rsi),%r12 + mov 32(%rsi),%rbp + mov 40(%rsi),%rbx + lea 48(%rsi),%rsp +.Lepilogue_avx2: + ret +.size ${func}_avx2,.-${func}_avx2 +___ +}} +}}}}} + +# EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, +# CONTEXT *context,DISPATCHER_CONTEXT *disp) +if ($win64) { +$rec="%rcx"; +$frame="%rdx"; +$context="%r8"; +$disp="%r9"; + +$code.=<<___; +.extern __imp_RtlVirtualUnwind +.type se_handler,\@abi-omnipotent +.align 16 +se_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + mov 8($disp),%rsi # disp->ImageBase + mov 56($disp),%r11 # disp->HanderlData + + mov 0(%r11),%r10d # HandlerData[0] + lea (%rsi,%r10),%r10 # prologue label + cmp %r10,%rbx # context->RipRsp + + mov 4(%r11),%r10d # HandlerData[1] + lea (%rsi,%r10),%r10 # epilogue label + cmp %r10,%rbx # context->Rip>=epilogue label + jae .Lin_prologue +___ +$code.=<<___ if ($avx>1); + lea .Lavx2_shortcut(%rip),%r10 + cmp %r10,%rbx # context->RipRbx + mov %rbp,160($context) # restore context->Rbp + mov %r12,216($context) # restore context->R12 + mov %r13,224($context) # restore context->R13 + mov %r14,232($context) # restore context->R14 + mov %r15,240($context) # restore context->R15 + + lea .Lepilogue(%rip),%r10 + cmp %r10,%rbx + jb .Lin_prologue # non-AVX code + + lea 16*$SZ+4*8(%rsi),%rsi # Xmm6- save area + lea 512($context),%rdi # &context.Xmm6 + mov \$`$SZ==4?8:12`,%ecx + .long 0xa548f3fc # cld; rep movsq + +.Lin_prologue: + mov 8(%rax),%rdi + mov 16(%rax),%rsi + mov %rax,152($context) # restore context->Rsp + mov %rsi,168($context) # restore context->Rsi + mov %rdi,176($context) # restore context->Rdi + + mov 40($disp),%rdi # disp->ContextRecord + mov $context,%rsi # context + mov \$154,%ecx # sizeof(CONTEXT) + .long 0xa548f3fc # cld; rep movsq + + mov $disp,%rsi + xor %rcx,%rcx # arg1, UNW_FLAG_NHANDLER + mov 8(%rsi),%rdx # arg2, disp->ImageBase + mov 0(%rsi),%r8 # arg3, disp->ControlPc + mov 16(%rsi),%r9 # arg4, disp->FunctionEntry + mov 40(%rsi),%r10 # disp->ContextRecord + lea 56(%rsi),%r11 # &disp->HandlerData + lea 24(%rsi),%r12 # &disp->EstablisherFrame + mov %r10,32(%rsp) # arg5 + mov %r11,40(%rsp) # arg6 + mov %r12,48(%rsp) # arg7 + mov %rcx,56(%rsp) # arg8, (NULL) + call *__imp_RtlVirtualUnwind(%rip) + + mov \$1,%eax # ExceptionContinueSearch + add \$64,%rsp + popfq + pop %r15 + pop %r14 + pop %r13 + pop %r12 + pop %rbp + pop %rbx + pop %rdi + pop %rsi + ret +.size se_handler,.-se_handler +___ +$code.=<<___ if ($SZ == 4 && $shaext); +.type shaext_handler,\@abi-omnipotent +.align 16 +shaext_handler: + push %rsi + push %rdi + push %rbx + push %rbp + push %r12 + push %r13 + push %r14 + push %r15 + pushfq + sub \$64,%rsp + + mov 120($context),%rax # pull context->Rax + mov 248($context),%rbx # pull context->Rip + + lea .Lprologue_shaext(%rip),%r10 + cmp %r10,%rbx # context->Rip<.Lprologue + jb .Lin_prologue + + lea .Lepilogue_shaext(%rip),%r10 + cmp %r10,%rbx # context->Rip>=.Lepilogue + jae .Lin_prologue + + lea -8-5*16(%rax),%rsi + lea 512($context),%rdi # &context.Xmm6 + mov \$10,%ecx + .long 0xa548f3fc # cld; rep movsq + + jmp .Lin_prologue +.size shaext_handler,.-shaext_handler +___ +$code.=<<___; +.section .pdata +.align 4 + .rva .LSEH_begin_$func + .rva .LSEH_end_$func + .rva .LSEH_info_$func +___ +$code.=<<___ if ($SZ==4 && $shext); + .rva .LSEH_begin_${func}_shaext + .rva .LSEH_end_${func}_shaext + .rva .LSEH_info_${func}_shaext +___ +$code.=<<___ if ($SZ==4); + .rva .LSEH_begin_${func}_ssse3 + .rva .LSEH_end_${func}_ssse3 + .rva .LSEH_info_${func}_ssse3 +___ +$code.=<<___ if ($avx && $SZ==8); + .rva .LSEH_begin_${func}_xop + .rva .LSEH_end_${func}_xop + .rva .LSEH_info_${func}_xop +___ +$code.=<<___ if ($avx); + .rva .LSEH_begin_${func}_avx + .rva .LSEH_end_${func}_avx + .rva .LSEH_info_${func}_avx +___ +$code.=<<___ if ($avx>1); + .rva .LSEH_begin_${func}_avx2 + .rva .LSEH_end_${func}_avx2 + .rva .LSEH_info_${func}_avx2 +___ +$code.=<<___; +.section .xdata +.align 8 +.LSEH_info_$func: + .byte 9,0,0,0 + .rva se_handler + .rva .Lprologue,.Lepilogue # HandlerData[] +___ +$code.=<<___ if ($SZ==4 && $shaext); +.LSEH_info_${func}_shaext: + .byte 9,0,0,0 + .rva shaext_handler +___ +$code.=<<___ if ($SZ==4); +.LSEH_info_${func}_ssse3: + .byte 9,0,0,0 + .rva se_handler + .rva .Lprologue_ssse3,.Lepilogue_ssse3 # HandlerData[] +___ +$code.=<<___ if ($avx && $SZ==8); +.LSEH_info_${func}_xop: + .byte 9,0,0,0 + .rva se_handler + .rva .Lprologue_xop,.Lepilogue_xop # HandlerData[] +___ +$code.=<<___ if ($avx); +.LSEH_info_${func}_avx: + .byte 9,0,0,0 + .rva se_handler + .rva .Lprologue_avx,.Lepilogue_avx # HandlerData[] +___ +$code.=<<___ if ($avx>1); +.LSEH_info_${func}_avx2: + .byte 9,0,0,0 + .rva se_handler + .rva .Lprologue_avx2,.Lepilogue_avx2 # HandlerData[] +___ +} + +sub sha256op38 { + my $instr = shift; + my %opcodelet = ( + "sha256rnds2" => 0xcb, + "sha256msg1" => 0xcc, + "sha256msg2" => 0xcd ); + + if (defined($opcodelet{$instr}) && @_[0] =~ /%xmm([0-7]),\s*%xmm([0-7])/) { + my @opcode=(0x0f,0x38); + push @opcode,$opcodelet{$instr}; + push @opcode,0xc0|($1&7)|(($2&7)<<3); # ModR/M + return ".byte\t".join(',',@opcode); + } else { + return $instr."\t".@_[0]; + } +} + +foreach (split("\n",$code)) { + s/\`([^\`]*)\`/eval $1/geo; + + s/\b(sha256[^\s]*)\s+(.*)/sha256op38($1,$2)/geo; + + print $_,"\n"; +} +close STDOUT; diff --git a/TMessagesProj/jni/boringssl/crypto/sha/sha1.c b/TMessagesProj/jni/boringssl/crypto/sha/sha1.c new file mode 100644 index 00000000..c03e6081 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/sha1.c @@ -0,0 +1,381 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) +#define SHA1_ASM +#endif + +int SHA1_Init(SHA_CTX *sha) { + memset(sha, 0, sizeof(SHA_CTX)); + sha->h0 = 0x67452301UL; + sha->h1 = 0xefcdab89UL; + sha->h2 = 0x98badcfeUL; + sha->h3 = 0x10325476UL; + sha->h4 = 0xc3d2e1f0UL; + return 1; +} + +uint8_t *SHA1(const uint8_t *data, size_t len, uint8_t *out) { + SHA_CTX ctx; + static uint8_t buf[SHA_DIGEST_LENGTH]; + + /* TODO(fork): remove this static buffer. */ + if (out == NULL) { + out = buf; + } + if (!SHA1_Init(&ctx)) { + return NULL; + } + SHA1_Update(&ctx, data, len); + SHA1_Final(out, &ctx); + OPENSSL_cleanse(&ctx, sizeof(ctx)); + return out; +} + +#define DATA_ORDER_IS_BIG_ENDIAN + +#define HASH_LONG uint32_t +#define HASH_CTX SHA_CTX +#define HASH_CBLOCK 64 +#define HASH_MAKE_STRING(c, s) \ + do { \ + uint32_t ll; \ + ll = (c)->h0; \ + (void) HOST_l2c(ll, (s)); \ + ll = (c)->h1; \ + (void) HOST_l2c(ll, (s)); \ + ll = (c)->h2; \ + (void) HOST_l2c(ll, (s)); \ + ll = (c)->h3; \ + (void) HOST_l2c(ll, (s)); \ + ll = (c)->h4; \ + (void) HOST_l2c(ll, (s)); \ + } while (0) + +#define HASH_UPDATE SHA1_Update +#define HASH_TRANSFORM SHA1_Transform +#define HASH_FINAL SHA1_Final +#define HASH_BLOCK_DATA_ORDER sha1_block_data_order +#define Xupdate(a, ix, ia, ib, ic, id) \ + ((a) = (ia ^ ib ^ ic ^ id), ix = (a) = ROTATE((a), 1)) + +#ifndef SHA1_ASM +static +#endif +void sha1_block_data_order(SHA_CTX *c, const void *p, size_t num); + +#include "../digest/md32_common.h" + +#define K_00_19 0x5a827999UL +#define K_20_39 0x6ed9eba1UL +#define K_40_59 0x8f1bbcdcUL +#define K_60_79 0xca62c1d6UL + +/* As pointed out by Wei Dai , F() below can be simplified + * to the code in F_00_19. Wei attributes these optimisations to Peter + * Gutmann's SHS code, and he attributes it to Rich Schroeppel. #define + * F(x,y,z) (((x) & (y)) | ((~(x)) & (z))) I've just become aware of another + * tweak to be made, again from Wei Dai, in F_40_59, (x&a)|(y&a) -> (x|y)&a */ +#define F_00_19(b, c, d) ((((c) ^ (d)) & (b)) ^ (d)) +#define F_20_39(b, c, d) ((b) ^ (c) ^ (d)) +#define F_40_59(b, c, d) (((b) & (c)) | (((b) | (c)) & (d))) +#define F_60_79(b, c, d) F_20_39(b, c, d) + +#define BODY_00_15(i, a, b, c, d, e, f, xi) \ + (f) = xi + (e) + K_00_19 + ROTATE((a), 5) + F_00_19((b), (c), (d)); \ + (b) = ROTATE((b), 30); + +#define BODY_16_19(i, a, b, c, d, e, f, xi, xa, xb, xc, xd) \ + Xupdate(f, xi, xa, xb, xc, xd); \ + (f) += (e) + K_00_19 + ROTATE((a), 5) + F_00_19((b), (c), (d)); \ + (b) = ROTATE((b), 30); + +#define BODY_20_31(i, a, b, c, d, e, f, xi, xa, xb, xc, xd) \ + Xupdate(f, xi, xa, xb, xc, xd); \ + (f) += (e) + K_20_39 + ROTATE((a), 5) + F_20_39((b), (c), (d)); \ + (b) = ROTATE((b), 30); + +#define BODY_32_39(i, a, b, c, d, e, f, xa, xb, xc, xd) \ + Xupdate(f, xa, xa, xb, xc, xd); \ + (f) += (e) + K_20_39 + ROTATE((a), 5) + F_20_39((b), (c), (d)); \ + (b) = ROTATE((b), 30); + +#define BODY_40_59(i, a, b, c, d, e, f, xa, xb, xc, xd) \ + Xupdate(f, xa, xa, xb, xc, xd); \ + (f) += (e) + K_40_59 + ROTATE((a), 5) + F_40_59((b), (c), (d)); \ + (b) = ROTATE((b), 30); + +#define BODY_60_79(i, a, b, c, d, e, f, xa, xb, xc, xd) \ + Xupdate(f, xa, xa, xb, xc, xd); \ + (f) = xa + (e) + K_60_79 + ROTATE((a), 5) + F_60_79((b), (c), (d)); \ + (b) = ROTATE((b), 30); + +#ifdef X +#undef X +#endif + +/* Originally X was an array. As it's automatic it's natural +* to expect RISC compiler to accomodate at least part of it in +* the register bank, isn't it? Unfortunately not all compilers +* "find" this expectation reasonable:-( On order to make such +* compilers generate better code I replace X[] with a bunch of +* X0, X1, etc. See the function body below... +* */ +#define X(i) XX##i + +#if !defined(SHA1_ASM) +static void HASH_BLOCK_DATA_ORDER(SHA_CTX *c, const void *p, size_t num) { + const uint8_t *data = p; + register uint32_t A, B, C, D, E, T, l; + uint32_t XX0, XX1, XX2, XX3, XX4, XX5, XX6, XX7, XX8, XX9, XX10, + XX11, XX12, XX13, XX14, XX15; + + A = c->h0; + B = c->h1; + C = c->h2; + D = c->h3; + E = c->h4; + + for (;;) { + const union { + long one; + char little; + } is_endian = {1}; + + if (!is_endian.little && ((size_t)p % 4) == 0) { + const uint32_t *W = (const uint32_t *)data; + + X(0) = W[0]; + X(1) = W[1]; + BODY_00_15(0, A, B, C, D, E, T, X(0)); + X(2) = W[2]; + BODY_00_15(1, T, A, B, C, D, E, X(1)); + X(3) = W[3]; + BODY_00_15(2, E, T, A, B, C, D, X(2)); + X(4) = W[4]; + BODY_00_15(3, D, E, T, A, B, C, X(3)); + X(5) = W[5]; + BODY_00_15(4, C, D, E, T, A, B, X(4)); + X(6) = W[6]; + BODY_00_15(5, B, C, D, E, T, A, X(5)); + X(7) = W[7]; + BODY_00_15(6, A, B, C, D, E, T, X(6)); + X(8) = W[8]; + BODY_00_15(7, T, A, B, C, D, E, X(7)); + X(9) = W[9]; + BODY_00_15(8, E, T, A, B, C, D, X(8)); + X(10) = W[10]; + BODY_00_15(9, D, E, T, A, B, C, X(9)); + X(11) = W[11]; + BODY_00_15(10, C, D, E, T, A, B, X(10)); + X(12) = W[12]; + BODY_00_15(11, B, C, D, E, T, A, X(11)); + X(13) = W[13]; + BODY_00_15(12, A, B, C, D, E, T, X(12)); + X(14) = W[14]; + BODY_00_15(13, T, A, B, C, D, E, X(13)); + X(15) = W[15]; + BODY_00_15(14, E, T, A, B, C, D, X(14)); + BODY_00_15(15, D, E, T, A, B, C, X(15)); + + data += HASH_CBLOCK; + } else { + (void)HOST_c2l(data, l); + X(0) = l; + (void)HOST_c2l(data, l); + X(1) = l; + BODY_00_15(0, A, B, C, D, E, T, X(0)); + (void)HOST_c2l(data, l); + X(2) = l; + BODY_00_15(1, T, A, B, C, D, E, X(1)); + (void)HOST_c2l(data, l); + X(3) = l; + BODY_00_15(2, E, T, A, B, C, D, X(2)); + (void)HOST_c2l(data, l); + X(4) = l; + BODY_00_15(3, D, E, T, A, B, C, X(3)); + (void)HOST_c2l(data, l); + X(5) = l; + BODY_00_15(4, C, D, E, T, A, B, X(4)); + (void)HOST_c2l(data, l); + X(6) = l; + BODY_00_15(5, B, C, D, E, T, A, X(5)); + (void)HOST_c2l(data, l); + X(7) = l; + BODY_00_15(6, A, B, C, D, E, T, X(6)); + (void)HOST_c2l(data, l); + X(8) = l; + BODY_00_15(7, T, A, B, C, D, E, X(7)); + (void)HOST_c2l(data, l); + X(9) = l; + BODY_00_15(8, E, T, A, B, C, D, X(8)); + (void)HOST_c2l(data, l); + X(10) = l; + BODY_00_15(9, D, E, T, A, B, C, X(9)); + (void)HOST_c2l(data, l); + X(11) = l; + BODY_00_15(10, C, D, E, T, A, B, X(10)); + (void)HOST_c2l(data, l); + X(12) = l; + BODY_00_15(11, B, C, D, E, T, A, X(11)); + (void)HOST_c2l(data, l); + X(13) = l; + BODY_00_15(12, A, B, C, D, E, T, X(12)); + (void)HOST_c2l(data, l); + X(14) = l; + BODY_00_15(13, T, A, B, C, D, E, X(13)); + (void)HOST_c2l(data, l); + X(15) = l; + BODY_00_15(14, E, T, A, B, C, D, X(14)); + BODY_00_15(15, D, E, T, A, B, C, X(15)); + } + + BODY_16_19(16, C, D, E, T, A, B, X(0), X(0), X(2), X(8), X(13)); + BODY_16_19(17, B, C, D, E, T, A, X(1), X(1), X(3), X(9), X(14)); + BODY_16_19(18, A, B, C, D, E, T, X(2), X(2), X(4), X(10), X(15)); + BODY_16_19(19, T, A, B, C, D, E, X(3), X(3), X(5), X(11), X(0)); + + BODY_20_31(20, E, T, A, B, C, D, X(4), X(4), X(6), X(12), X(1)); + BODY_20_31(21, D, E, T, A, B, C, X(5), X(5), X(7), X(13), X(2)); + BODY_20_31(22, C, D, E, T, A, B, X(6), X(6), X(8), X(14), X(3)); + BODY_20_31(23, B, C, D, E, T, A, X(7), X(7), X(9), X(15), X(4)); + BODY_20_31(24, A, B, C, D, E, T, X(8), X(8), X(10), X(0), X(5)); + BODY_20_31(25, T, A, B, C, D, E, X(9), X(9), X(11), X(1), X(6)); + BODY_20_31(26, E, T, A, B, C, D, X(10), X(10), X(12), X(2), X(7)); + BODY_20_31(27, D, E, T, A, B, C, X(11), X(11), X(13), X(3), X(8)); + BODY_20_31(28, C, D, E, T, A, B, X(12), X(12), X(14), X(4), X(9)); + BODY_20_31(29, B, C, D, E, T, A, X(13), X(13), X(15), X(5), X(10)); + BODY_20_31(30, A, B, C, D, E, T, X(14), X(14), X(0), X(6), X(11)); + BODY_20_31(31, T, A, B, C, D, E, X(15), X(15), X(1), X(7), X(12)); + + BODY_32_39(32, E, T, A, B, C, D, X(0), X(2), X(8), X(13)); + BODY_32_39(33, D, E, T, A, B, C, X(1), X(3), X(9), X(14)); + BODY_32_39(34, C, D, E, T, A, B, X(2), X(4), X(10), X(15)); + BODY_32_39(35, B, C, D, E, T, A, X(3), X(5), X(11), X(0)); + BODY_32_39(36, A, B, C, D, E, T, X(4), X(6), X(12), X(1)); + BODY_32_39(37, T, A, B, C, D, E, X(5), X(7), X(13), X(2)); + BODY_32_39(38, E, T, A, B, C, D, X(6), X(8), X(14), X(3)); + BODY_32_39(39, D, E, T, A, B, C, X(7), X(9), X(15), X(4)); + + BODY_40_59(40, C, D, E, T, A, B, X(8), X(10), X(0), X(5)); + BODY_40_59(41, B, C, D, E, T, A, X(9), X(11), X(1), X(6)); + BODY_40_59(42, A, B, C, D, E, T, X(10), X(12), X(2), X(7)); + BODY_40_59(43, T, A, B, C, D, E, X(11), X(13), X(3), X(8)); + BODY_40_59(44, E, T, A, B, C, D, X(12), X(14), X(4), X(9)); + BODY_40_59(45, D, E, T, A, B, C, X(13), X(15), X(5), X(10)); + BODY_40_59(46, C, D, E, T, A, B, X(14), X(0), X(6), X(11)); + BODY_40_59(47, B, C, D, E, T, A, X(15), X(1), X(7), X(12)); + BODY_40_59(48, A, B, C, D, E, T, X(0), X(2), X(8), X(13)); + BODY_40_59(49, T, A, B, C, D, E, X(1), X(3), X(9), X(14)); + BODY_40_59(50, E, T, A, B, C, D, X(2), X(4), X(10), X(15)); + BODY_40_59(51, D, E, T, A, B, C, X(3), X(5), X(11), X(0)); + BODY_40_59(52, C, D, E, T, A, B, X(4), X(6), X(12), X(1)); + BODY_40_59(53, B, C, D, E, T, A, X(5), X(7), X(13), X(2)); + BODY_40_59(54, A, B, C, D, E, T, X(6), X(8), X(14), X(3)); + BODY_40_59(55, T, A, B, C, D, E, X(7), X(9), X(15), X(4)); + BODY_40_59(56, E, T, A, B, C, D, X(8), X(10), X(0), X(5)); + BODY_40_59(57, D, E, T, A, B, C, X(9), X(11), X(1), X(6)); + BODY_40_59(58, C, D, E, T, A, B, X(10), X(12), X(2), X(7)); + BODY_40_59(59, B, C, D, E, T, A, X(11), X(13), X(3), X(8)); + + BODY_60_79(60, A, B, C, D, E, T, X(12), X(14), X(4), X(9)); + BODY_60_79(61, T, A, B, C, D, E, X(13), X(15), X(5), X(10)); + BODY_60_79(62, E, T, A, B, C, D, X(14), X(0), X(6), X(11)); + BODY_60_79(63, D, E, T, A, B, C, X(15), X(1), X(7), X(12)); + BODY_60_79(64, C, D, E, T, A, B, X(0), X(2), X(8), X(13)); + BODY_60_79(65, B, C, D, E, T, A, X(1), X(3), X(9), X(14)); + BODY_60_79(66, A, B, C, D, E, T, X(2), X(4), X(10), X(15)); + BODY_60_79(67, T, A, B, C, D, E, X(3), X(5), X(11), X(0)); + BODY_60_79(68, E, T, A, B, C, D, X(4), X(6), X(12), X(1)); + BODY_60_79(69, D, E, T, A, B, C, X(5), X(7), X(13), X(2)); + BODY_60_79(70, C, D, E, T, A, B, X(6), X(8), X(14), X(3)); + BODY_60_79(71, B, C, D, E, T, A, X(7), X(9), X(15), X(4)); + BODY_60_79(72, A, B, C, D, E, T, X(8), X(10), X(0), X(5)); + BODY_60_79(73, T, A, B, C, D, E, X(9), X(11), X(1), X(6)); + BODY_60_79(74, E, T, A, B, C, D, X(10), X(12), X(2), X(7)); + BODY_60_79(75, D, E, T, A, B, C, X(11), X(13), X(3), X(8)); + BODY_60_79(76, C, D, E, T, A, B, X(12), X(14), X(4), X(9)); + BODY_60_79(77, B, C, D, E, T, A, X(13), X(15), X(5), X(10)); + BODY_60_79(78, A, B, C, D, E, T, X(14), X(0), X(6), X(11)); + BODY_60_79(79, T, A, B, C, D, E, X(15), X(1), X(7), X(12)); + + c->h0 = (c->h0 + E) & 0xffffffffL; + c->h1 = (c->h1 + T) & 0xffffffffL; + c->h2 = (c->h2 + A) & 0xffffffffL; + c->h3 = (c->h3 + B) & 0xffffffffL; + c->h4 = (c->h4 + C) & 0xffffffffL; + + if (--num == 0) { + break; + } + + A = c->h0; + B = c->h1; + C = c->h2; + D = c->h3; + E = c->h4; + } +} +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/sha/sha256.c b/TMessagesProj/jni/boringssl/crypto/sha/sha256.c new file mode 100644 index 00000000..8276bbb5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/sha256.c @@ -0,0 +1,370 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) +#define SHA256_ASM +#endif + +int SHA224_Init(SHA256_CTX *sha) { + memset(sha, 0, sizeof(SHA256_CTX)); + sha->h[0] = 0xc1059ed8UL; + sha->h[1] = 0x367cd507UL; + sha->h[2] = 0x3070dd17UL; + sha->h[3] = 0xf70e5939UL; + sha->h[4] = 0xffc00b31UL; + sha->h[5] = 0x68581511UL; + sha->h[6] = 0x64f98fa7UL; + sha->h[7] = 0xbefa4fa4UL; + sha->md_len = SHA224_DIGEST_LENGTH; + return 1; +} + +int SHA256_Init(SHA256_CTX *sha) { + memset(sha, 0, sizeof(SHA256_CTX)); + sha->h[0] = 0x6a09e667UL; + sha->h[1] = 0xbb67ae85UL; + sha->h[2] = 0x3c6ef372UL; + sha->h[3] = 0xa54ff53aUL; + sha->h[4] = 0x510e527fUL; + sha->h[5] = 0x9b05688cUL; + sha->h[6] = 0x1f83d9abUL; + sha->h[7] = 0x5be0cd19UL; + sha->md_len = SHA256_DIGEST_LENGTH; + return 1; +} + +uint8_t *SHA224(const uint8_t *data, size_t len, uint8_t *out) { + SHA256_CTX ctx; + static uint8_t buf[SHA224_DIGEST_LENGTH]; + + /* TODO(fork): remove this static buffer. */ + if (out == NULL) { + out = buf; + } + SHA224_Init(&ctx); + SHA256_Update(&ctx, data, len); + SHA256_Final(out, &ctx); + OPENSSL_cleanse(&ctx, sizeof(ctx)); + return out; +} + +uint8_t *SHA256(const uint8_t *data, size_t len, uint8_t *out) { + SHA256_CTX ctx; + static uint8_t buf[SHA256_DIGEST_LENGTH]; + + /* TODO(fork): remove this static buffer. */ + if (out == NULL) { + out = buf; + } + SHA256_Init(&ctx); + SHA256_Update(&ctx, data, len); + SHA256_Final(out, &ctx); + OPENSSL_cleanse(&ctx, sizeof(ctx)); + return out; +} + +int SHA224_Update(SHA256_CTX *ctx, const void *data, size_t len) { + return SHA256_Update(ctx, data, len); +} + +int SHA224_Final(uint8_t *md, SHA256_CTX *ctx) { + return SHA256_Final(md, ctx); +} + +#define DATA_ORDER_IS_BIG_ENDIAN + +#define HASH_LONG uint32_t +#define HASH_CTX SHA256_CTX +#define HASH_CBLOCK 64 + +/* Note that FIPS180-2 discusses "Truncation of the Hash Function Output." + * default: case below covers for it. It's not clear however if it's permitted + * to truncate to amount of bytes not divisible by 4. I bet not, but if it is, + * then default: case shall be extended. For reference. Idea behind separate + * cases for pre-defined lenghts is to let the compiler decide if it's + * appropriate to unroll small loops. + * + * TODO(davidben): The small |md_len| case is one of the few places a low-level + * hash 'final' function can fail. This should never happen. */ +#define HASH_MAKE_STRING(c, s) \ + do { \ + uint32_t ll; \ + unsigned int nn; \ + switch ((c)->md_len) { \ + case SHA224_DIGEST_LENGTH: \ + for (nn = 0; nn < SHA224_DIGEST_LENGTH / 4; nn++) { \ + ll = (c)->h[nn]; \ + (void) HOST_l2c(ll, (s)); \ + } \ + break; \ + case SHA256_DIGEST_LENGTH: \ + for (nn = 0; nn < SHA256_DIGEST_LENGTH / 4; nn++) { \ + ll = (c)->h[nn]; \ + (void) HOST_l2c(ll, (s)); \ + } \ + break; \ + default: \ + if ((c)->md_len > SHA256_DIGEST_LENGTH) { \ + return 0; \ + } \ + for (nn = 0; nn < (c)->md_len / 4; nn++) { \ + ll = (c)->h[nn]; \ + (void) HOST_l2c(ll, (s)); \ + } \ + break; \ + } \ + } while (0) + + +#define HASH_UPDATE SHA256_Update +#define HASH_TRANSFORM SHA256_Transform +#define HASH_FINAL SHA256_Final +#define HASH_BLOCK_DATA_ORDER sha256_block_data_order +#ifndef SHA256_ASM +static +#endif +void sha256_block_data_order(SHA256_CTX *ctx, const void *in, size_t num); + +#include "../digest/md32_common.h" + +#ifndef SHA256_ASM +static const HASH_LONG K256[64] = { + 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL, + 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL, + 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, + 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL, + 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL, + 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL, + 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, + 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL, + 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL, + 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL, + 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, + 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL, + 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL}; + +/* FIPS specification refers to right rotations, while our ROTATE macro + * is left one. This is why you might notice that rotation coefficients + * differ from those observed in FIPS document by 32-N... */ +#define Sigma0(x) (ROTATE((x), 30) ^ ROTATE((x), 19) ^ ROTATE((x), 10)) +#define Sigma1(x) (ROTATE((x), 26) ^ ROTATE((x), 21) ^ ROTATE((x), 7)) +#define sigma0(x) (ROTATE((x), 25) ^ ROTATE((x), 14) ^ ((x) >> 3)) +#define sigma1(x) (ROTATE((x), 15) ^ ROTATE((x), 13) ^ ((x) >> 10)) + +#define Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + +#define ROUND_00_15(i, a, b, c, d, e, f, g, h) \ + do { \ + T1 += h + Sigma1(e) + Ch(e, f, g) + K256[i]; \ + h = Sigma0(a) + Maj(a, b, c); \ + d += T1; \ + h += T1; \ + } while (0) + +#define ROUND_16_63(i, a, b, c, d, e, f, g, h, X) \ + do { \ + s0 = X[(i + 1) & 0x0f]; \ + s0 = sigma0(s0); \ + s1 = X[(i + 14) & 0x0f]; \ + s1 = sigma1(s1); \ + T1 = X[(i) & 0x0f] += s0 + s1 + X[(i + 9) & 0x0f]; \ + ROUND_00_15(i, a, b, c, d, e, f, g, h); \ + } while (0) + +static void sha256_block_data_order(SHA256_CTX *ctx, const void *in, + size_t num) { + uint32_t a, b, c, d, e, f, g, h, s0, s1, T1; + HASH_LONG X[16]; + int i; + const uint8_t *data = in; + const union { + long one; + char little; + } is_endian = {1}; + + while (num--) { + a = ctx->h[0]; + b = ctx->h[1]; + c = ctx->h[2]; + d = ctx->h[3]; + e = ctx->h[4]; + f = ctx->h[5]; + g = ctx->h[6]; + h = ctx->h[7]; + + if (!is_endian.little && sizeof(HASH_LONG) == 4 && ((size_t)in % 4) == 0) { + const HASH_LONG *W = (const HASH_LONG *)data; + + T1 = X[0] = W[0]; + ROUND_00_15(0, a, b, c, d, e, f, g, h); + T1 = X[1] = W[1]; + ROUND_00_15(1, h, a, b, c, d, e, f, g); + T1 = X[2] = W[2]; + ROUND_00_15(2, g, h, a, b, c, d, e, f); + T1 = X[3] = W[3]; + ROUND_00_15(3, f, g, h, a, b, c, d, e); + T1 = X[4] = W[4]; + ROUND_00_15(4, e, f, g, h, a, b, c, d); + T1 = X[5] = W[5]; + ROUND_00_15(5, d, e, f, g, h, a, b, c); + T1 = X[6] = W[6]; + ROUND_00_15(6, c, d, e, f, g, h, a, b); + T1 = X[7] = W[7]; + ROUND_00_15(7, b, c, d, e, f, g, h, a); + T1 = X[8] = W[8]; + ROUND_00_15(8, a, b, c, d, e, f, g, h); + T1 = X[9] = W[9]; + ROUND_00_15(9, h, a, b, c, d, e, f, g); + T1 = X[10] = W[10]; + ROUND_00_15(10, g, h, a, b, c, d, e, f); + T1 = X[11] = W[11]; + ROUND_00_15(11, f, g, h, a, b, c, d, e); + T1 = X[12] = W[12]; + ROUND_00_15(12, e, f, g, h, a, b, c, d); + T1 = X[13] = W[13]; + ROUND_00_15(13, d, e, f, g, h, a, b, c); + T1 = X[14] = W[14]; + ROUND_00_15(14, c, d, e, f, g, h, a, b); + T1 = X[15] = W[15]; + ROUND_00_15(15, b, c, d, e, f, g, h, a); + + data += HASH_CBLOCK; + } else { + HASH_LONG l; + + HOST_c2l(data, l); + T1 = X[0] = l; + ROUND_00_15(0, a, b, c, d, e, f, g, h); + HOST_c2l(data, l); + T1 = X[1] = l; + ROUND_00_15(1, h, a, b, c, d, e, f, g); + HOST_c2l(data, l); + T1 = X[2] = l; + ROUND_00_15(2, g, h, a, b, c, d, e, f); + HOST_c2l(data, l); + T1 = X[3] = l; + ROUND_00_15(3, f, g, h, a, b, c, d, e); + HOST_c2l(data, l); + T1 = X[4] = l; + ROUND_00_15(4, e, f, g, h, a, b, c, d); + HOST_c2l(data, l); + T1 = X[5] = l; + ROUND_00_15(5, d, e, f, g, h, a, b, c); + HOST_c2l(data, l); + T1 = X[6] = l; + ROUND_00_15(6, c, d, e, f, g, h, a, b); + HOST_c2l(data, l); + T1 = X[7] = l; + ROUND_00_15(7, b, c, d, e, f, g, h, a); + HOST_c2l(data, l); + T1 = X[8] = l; + ROUND_00_15(8, a, b, c, d, e, f, g, h); + HOST_c2l(data, l); + T1 = X[9] = l; + ROUND_00_15(9, h, a, b, c, d, e, f, g); + HOST_c2l(data, l); + T1 = X[10] = l; + ROUND_00_15(10, g, h, a, b, c, d, e, f); + HOST_c2l(data, l); + T1 = X[11] = l; + ROUND_00_15(11, f, g, h, a, b, c, d, e); + HOST_c2l(data, l); + T1 = X[12] = l; + ROUND_00_15(12, e, f, g, h, a, b, c, d); + HOST_c2l(data, l); + T1 = X[13] = l; + ROUND_00_15(13, d, e, f, g, h, a, b, c); + HOST_c2l(data, l); + T1 = X[14] = l; + ROUND_00_15(14, c, d, e, f, g, h, a, b); + HOST_c2l(data, l); + T1 = X[15] = l; + ROUND_00_15(15, b, c, d, e, f, g, h, a); + } + + for (i = 16; i < 64; i += 8) { + ROUND_16_63(i + 0, a, b, c, d, e, f, g, h, X); + ROUND_16_63(i + 1, h, a, b, c, d, e, f, g, X); + ROUND_16_63(i + 2, g, h, a, b, c, d, e, f, X); + ROUND_16_63(i + 3, f, g, h, a, b, c, d, e, X); + ROUND_16_63(i + 4, e, f, g, h, a, b, c, d, X); + ROUND_16_63(i + 5, d, e, f, g, h, a, b, c, X); + ROUND_16_63(i + 6, c, d, e, f, g, h, a, b, X); + ROUND_16_63(i + 7, b, c, d, e, f, g, h, a, X); + } + + ctx->h[0] += a; + ctx->h[1] += b; + ctx->h[2] += c; + ctx->h[3] += d; + ctx->h[4] += e; + ctx->h[5] += f; + ctx->h[6] += g; + ctx->h[7] += h; + } +} + +#endif /* SHA256_ASM */ diff --git a/TMessagesProj/jni/boringssl/crypto/sha/sha512.c b/TMessagesProj/jni/boringssl/crypto/sha/sha512.c new file mode 100644 index 00000000..57c96ab9 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/sha/sha512.c @@ -0,0 +1,605 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + +#include "../internal.h" + + +/* IMPLEMENTATION NOTES. + * + * As you might have noticed 32-bit hash algorithms: + * + * - permit SHA_LONG to be wider than 32-bit (case on CRAY); + * - optimized versions implement two transform functions: one operating + * on [aligned] data in host byte order and one - on data in input + * stream byte order; + * - share common byte-order neutral collector and padding function + * implementations, ../md32_common.h; + * + * Neither of the above applies to this SHA-512 implementations. Reasons + * [in reverse order] are: + * + * - it's the only 64-bit hash algorithm for the moment of this writing, + * there is no need for common collector/padding implementation [yet]; + * - by supporting only one transform function [which operates on + * *aligned* data in input stream byte order, big-endian in this case] + * we minimize burden of maintenance in two ways: a) collector/padding + * function is simpler; b) only one transform function to stare at; + * - SHA_LONG64 is required to be exactly 64-bit in order to be able to + * apply a number of optimizations to mitigate potential performance + * penalties caused by previous design decision; */ + +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) +#define SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA +#define SHA512_ASM +#endif + +int SHA384_Init(SHA512_CTX *sha) { + sha->h[0] = OPENSSL_U64(0xcbbb9d5dc1059ed8); + sha->h[1] = OPENSSL_U64(0x629a292a367cd507); + sha->h[2] = OPENSSL_U64(0x9159015a3070dd17); + sha->h[3] = OPENSSL_U64(0x152fecd8f70e5939); + sha->h[4] = OPENSSL_U64(0x67332667ffc00b31); + sha->h[5] = OPENSSL_U64(0x8eb44a8768581511); + sha->h[6] = OPENSSL_U64(0xdb0c2e0d64f98fa7); + sha->h[7] = OPENSSL_U64(0x47b5481dbefa4fa4); + + sha->Nl = 0; + sha->Nh = 0; + sha->num = 0; + sha->md_len = SHA384_DIGEST_LENGTH; + return 1; +} + + +int SHA512_Init(SHA512_CTX *sha) { + sha->h[0] = OPENSSL_U64(0x6a09e667f3bcc908); + sha->h[1] = OPENSSL_U64(0xbb67ae8584caa73b); + sha->h[2] = OPENSSL_U64(0x3c6ef372fe94f82b); + sha->h[3] = OPENSSL_U64(0xa54ff53a5f1d36f1); + sha->h[4] = OPENSSL_U64(0x510e527fade682d1); + sha->h[5] = OPENSSL_U64(0x9b05688c2b3e6c1f); + sha->h[6] = OPENSSL_U64(0x1f83d9abfb41bd6b); + sha->h[7] = OPENSSL_U64(0x5be0cd19137e2179); + + sha->Nl = 0; + sha->Nh = 0; + sha->num = 0; + sha->md_len = SHA512_DIGEST_LENGTH; + return 1; +} + +uint8_t *SHA384(const uint8_t *data, size_t len, uint8_t *out) { + SHA512_CTX ctx; + static uint8_t buf[SHA384_DIGEST_LENGTH]; + + /* TODO(fork): remove this static buffer. */ + if (out == NULL) { + out = buf; + } + + SHA384_Init(&ctx); + SHA512_Update(&ctx, data, len); + SHA512_Final(out, &ctx); + OPENSSL_cleanse(&ctx, sizeof(ctx)); + return out; +} + +uint8_t *SHA512(const uint8_t *data, size_t len, uint8_t *out) { + SHA512_CTX ctx; + static uint8_t buf[SHA512_DIGEST_LENGTH]; + + /* TODO(fork): remove this static buffer. */ + if (out == NULL) { + out = buf; + } + SHA512_Init(&ctx); + SHA512_Update(&ctx, data, len); + SHA512_Final(out, &ctx); + OPENSSL_cleanse(&ctx, sizeof(ctx)); + return out; +} + +#if !defined(SHA512_ASM) +static +#endif +void sha512_block_data_order(SHA512_CTX *ctx, const void *in, size_t num); + + +int SHA384_Final(uint8_t *md, SHA512_CTX *sha) { + return SHA512_Final(md, sha); +} + +int SHA384_Update(SHA512_CTX *sha, const void *data, size_t len) { + return SHA512_Update(sha, data, len); +} + +void SHA512_Transform(SHA512_CTX *c, const uint8_t *data) { +#ifndef SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA + if ((size_t)data % sizeof(c->u.d[0]) != 0) { + memcpy(c->u.p, data, sizeof(c->u.p)); + data = c->u.p; + } +#endif + sha512_block_data_order(c, data, 1); +} + +int SHA512_Update(SHA512_CTX *c, const void *in_data, size_t len) { + uint64_t l; + uint8_t *p = c->u.p; + const uint8_t *data = (const uint8_t *)in_data; + + if (len == 0) { + return 1; + } + + l = (c->Nl + (((uint64_t)len) << 3)) & OPENSSL_U64(0xffffffffffffffff); + if (l < c->Nl) { + c->Nh++; + } + if (sizeof(len) >= 8) { + c->Nh += (((uint64_t)len) >> 61); + } + c->Nl = l; + + if (c->num != 0) { + size_t n = sizeof(c->u) - c->num; + + if (len < n) { + memcpy(p + c->num, data, len); + c->num += (unsigned int)len; + return 1; + } else { + memcpy(p + c->num, data, n), c->num = 0; + len -= n; + data += n; + sha512_block_data_order(c, p, 1); + } + } + + if (len >= sizeof(c->u)) { +#ifndef SHA512_BLOCK_CAN_MANAGE_UNALIGNED_DATA + if ((size_t)data % sizeof(c->u.d[0]) != 0) { + while (len >= sizeof(c->u)) { + memcpy(p, data, sizeof(c->u)); + sha512_block_data_order(c, p, 1); + len -= sizeof(c->u); + data += sizeof(c->u); + } + } else +#endif + { + sha512_block_data_order(c, data, len / sizeof(c->u)); + data += len; + len %= sizeof(c->u); + data -= len; + } + } + + if (len != 0) { + memcpy(p, data, len); + c->num = (int)len; + } + + return 1; +} + +int SHA512_Final(uint8_t *md, SHA512_CTX *sha) { + uint8_t *p = (uint8_t *)sha->u.p; + size_t n = sha->num; + + p[n] = 0x80; /* There always is a room for one */ + n++; + if (n > (sizeof(sha->u) - 16)) { + memset(p + n, 0, sizeof(sha->u) - n); + n = 0; + sha512_block_data_order(sha, p, 1); + } + + memset(p + n, 0, sizeof(sha->u) - 16 - n); + p[sizeof(sha->u) - 1] = (uint8_t)(sha->Nl); + p[sizeof(sha->u) - 2] = (uint8_t)(sha->Nl >> 8); + p[sizeof(sha->u) - 3] = (uint8_t)(sha->Nl >> 16); + p[sizeof(sha->u) - 4] = (uint8_t)(sha->Nl >> 24); + p[sizeof(sha->u) - 5] = (uint8_t)(sha->Nl >> 32); + p[sizeof(sha->u) - 6] = (uint8_t)(sha->Nl >> 40); + p[sizeof(sha->u) - 7] = (uint8_t)(sha->Nl >> 48); + p[sizeof(sha->u) - 8] = (uint8_t)(sha->Nl >> 56); + p[sizeof(sha->u) - 9] = (uint8_t)(sha->Nh); + p[sizeof(sha->u) - 10] = (uint8_t)(sha->Nh >> 8); + p[sizeof(sha->u) - 11] = (uint8_t)(sha->Nh >> 16); + p[sizeof(sha->u) - 12] = (uint8_t)(sha->Nh >> 24); + p[sizeof(sha->u) - 13] = (uint8_t)(sha->Nh >> 32); + p[sizeof(sha->u) - 14] = (uint8_t)(sha->Nh >> 40); + p[sizeof(sha->u) - 15] = (uint8_t)(sha->Nh >> 48); + p[sizeof(sha->u) - 16] = (uint8_t)(sha->Nh >> 56); + + sha512_block_data_order(sha, p, 1); + + if (md == NULL) { + /* TODO(davidben): This NULL check is absent in other low-level hash 'final' + * functions and is one of the few places one can fail. */ + return 0; + } + + switch (sha->md_len) { + /* Let compiler decide if it's appropriate to unroll... */ + case SHA384_DIGEST_LENGTH: + for (n = 0; n < SHA384_DIGEST_LENGTH / 8; n++) { + uint64_t t = sha->h[n]; + + *(md++) = (uint8_t)(t >> 56); + *(md++) = (uint8_t)(t >> 48); + *(md++) = (uint8_t)(t >> 40); + *(md++) = (uint8_t)(t >> 32); + *(md++) = (uint8_t)(t >> 24); + *(md++) = (uint8_t)(t >> 16); + *(md++) = (uint8_t)(t >> 8); + *(md++) = (uint8_t)(t); + } + break; + case SHA512_DIGEST_LENGTH: + for (n = 0; n < SHA512_DIGEST_LENGTH / 8; n++) { + uint64_t t = sha->h[n]; + + *(md++) = (uint8_t)(t >> 56); + *(md++) = (uint8_t)(t >> 48); + *(md++) = (uint8_t)(t >> 40); + *(md++) = (uint8_t)(t >> 32); + *(md++) = (uint8_t)(t >> 24); + *(md++) = (uint8_t)(t >> 16); + *(md++) = (uint8_t)(t >> 8); + *(md++) = (uint8_t)(t); + } + break; + /* ... as well as make sure md_len is not abused. */ + default: + /* TODO(davidben): This bad |md_len| case is one of the few places a + * low-level hash 'final' function can fail. This should never happen. */ + return 0; + } + + return 1; +} + +#ifndef SHA512_ASM +static const uint64_t K512[80] = { + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, + 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, + 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, + 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, + 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, + 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, + 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, + 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, + 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, + 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, + 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, + 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, + 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, + 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, + 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, + 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, + 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, + 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, + 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, + 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, + 0x5fcb6fab3ad6faec, 0x6c44198c4a475817}; + +#if defined(__GNUC__) && __GNUC__ >= 2 && !defined(OPENSSL_NO_ASM) +#if defined(__x86_64) || defined(__x86_64__) +#define ROTR(a, n) \ + ({ \ + uint64_t ret; \ + asm("rorq %1,%0" : "=r"(ret) : "J"(n), "0"(a) : "cc"); \ + ret; \ + }) +#define PULL64(x) \ + ({ \ + uint64_t ret = *((const uint64_t *)(&(x))); \ + asm("bswapq %0" : "=r"(ret) : "0"(ret)); \ + ret; \ + }) +#elif(defined(__i386) || defined(__i386__)) +#define PULL64(x) \ + ({ \ + const unsigned int *p = (const unsigned int *)(&(x)); \ + unsigned int hi = p[0], lo = p[1]; \ + asm("bswapl %0; bswapl %1;" : "=r"(lo), "=r"(hi) : "0"(lo), "1"(hi)); \ + ((uint64_t)hi) << 32 | lo; \ + }) +#elif(defined(_ARCH_PPC) && defined(__64BIT__)) || defined(_ARCH_PPC64) +#define ROTR(a, n) \ + ({ \ + uint64_t ret; \ + asm("rotrdi %0,%1,%2" : "=r"(ret) : "r"(a), "K"(n)); \ + ret; \ + }) +#elif defined(__aarch64__) +#define ROTR(a, n) \ + ({ \ + uint64_t ret; \ + asm("ror %0,%1,%2" : "=r"(ret) : "r"(a), "I"(n)); \ + ret; \ + }) +#if defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ + __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define PULL64(x) \ + ({ \ + uint64_t ret; \ + asm("rev %0,%1" : "=r"(ret) : "r"(*((const uint64_t *)(&(x))))); \ + ret; \ + }) +#endif +#endif +#elif defined(_MSC_VER) +#if defined(_WIN64) /* applies to both IA-64 and AMD64 */ +#pragma intrinsic(_rotr64) +#define ROTR(a, n) _rotr64((a), n) +#endif +#if defined(_M_IX86) && !defined(OPENSSL_NO_ASM) +static uint64_t __fastcall __pull64be(const void *x) { + _asm mov edx, [ecx + 0] + _asm mov eax, [ecx + 4] + _asm bswap edx + _asm bswap eax +} +#define PULL64(x) __pull64be(&(x)) +#if _MSC_VER <= 1200 +#pragma inline_depth(0) +#endif +#endif +#endif + +#ifndef PULL64 +#define B(x, j) \ + (((uint64_t)(*(((const uint8_t *)(&x)) + j))) << ((7 - j) * 8)) +#define PULL64(x) \ + (B(x, 0) | B(x, 1) | B(x, 2) | B(x, 3) | B(x, 4) | B(x, 5) | B(x, 6) | \ + B(x, 7)) +#endif + +#ifndef ROTR +#define ROTR(x, s) (((x) >> s) | (x) << (64 - s)) +#endif + +#define Sigma0(x) (ROTR((x), 28) ^ ROTR((x), 34) ^ ROTR((x), 39)) +#define Sigma1(x) (ROTR((x), 14) ^ ROTR((x), 18) ^ ROTR((x), 41)) +#define sigma0(x) (ROTR((x), 1) ^ ROTR((x), 8) ^ ((x) >> 7)) +#define sigma1(x) (ROTR((x), 19) ^ ROTR((x), 61) ^ ((x) >> 6)) + +#define Ch(x, y, z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + + +#if defined(__i386) || defined(__i386__) || defined(_M_IX86) +/* + * This code should give better results on 32-bit CPU with less than + * ~24 registers, both size and performance wise... + */ +static void sha512_block_data_order(SHA512_CTX *ctx, const void *in, + size_t num) { + const uint64_t *W = in; + uint64_t A, E, T; + uint64_t X[9 + 80], *F; + int i; + + while (num--) { + F = X + 80; + A = ctx->h[0]; + F[1] = ctx->h[1]; + F[2] = ctx->h[2]; + F[3] = ctx->h[3]; + E = ctx->h[4]; + F[5] = ctx->h[5]; + F[6] = ctx->h[6]; + F[7] = ctx->h[7]; + + for (i = 0; i < 16; i++, F--) { + T = PULL64(W[i]); + F[0] = A; + F[4] = E; + F[8] = T; + T += F[7] + Sigma1(E) + Ch(E, F[5], F[6]) + K512[i]; + E = F[3] + T; + A = T + Sigma0(A) + Maj(A, F[1], F[2]); + } + + for (; i < 80; i++, F--) { + T = sigma0(F[8 + 16 - 1]); + T += sigma1(F[8 + 16 - 14]); + T += F[8 + 16] + F[8 + 16 - 9]; + + F[0] = A; + F[4] = E; + F[8] = T; + T += F[7] + Sigma1(E) + Ch(E, F[5], F[6]) + K512[i]; + E = F[3] + T; + A = T + Sigma0(A) + Maj(A, F[1], F[2]); + } + + ctx->h[0] += A; + ctx->h[1] += F[1]; + ctx->h[2] += F[2]; + ctx->h[3] += F[3]; + ctx->h[4] += E; + ctx->h[5] += F[5]; + ctx->h[6] += F[6]; + ctx->h[7] += F[7]; + + W += 16; + } +} + +#else + +#define ROUND_00_15(i, a, b, c, d, e, f, g, h) \ + do { \ + T1 += h + Sigma1(e) + Ch(e, f, g) + K512[i]; \ + h = Sigma0(a) + Maj(a, b, c); \ + d += T1; \ + h += T1; \ + } while (0) + +#define ROUND_16_80(i, j, a, b, c, d, e, f, g, h, X) \ + do { \ + s0 = X[(j + 1) & 0x0f]; \ + s0 = sigma0(s0); \ + s1 = X[(j + 14) & 0x0f]; \ + s1 = sigma1(s1); \ + T1 = X[(j) & 0x0f] += s0 + s1 + X[(j + 9) & 0x0f]; \ + ROUND_00_15(i + j, a, b, c, d, e, f, g, h); \ + } while (0) + +static void sha512_block_data_order(SHA512_CTX *ctx, const void *in, + size_t num) { + const uint64_t *W = in; + uint64_t a, b, c, d, e, f, g, h, s0, s1, T1; + uint64_t X[16]; + int i; + + while (num--) { + + a = ctx->h[0]; + b = ctx->h[1]; + c = ctx->h[2]; + d = ctx->h[3]; + e = ctx->h[4]; + f = ctx->h[5]; + g = ctx->h[6]; + h = ctx->h[7]; + + T1 = X[0] = PULL64(W[0]); + ROUND_00_15(0, a, b, c, d, e, f, g, h); + T1 = X[1] = PULL64(W[1]); + ROUND_00_15(1, h, a, b, c, d, e, f, g); + T1 = X[2] = PULL64(W[2]); + ROUND_00_15(2, g, h, a, b, c, d, e, f); + T1 = X[3] = PULL64(W[3]); + ROUND_00_15(3, f, g, h, a, b, c, d, e); + T1 = X[4] = PULL64(W[4]); + ROUND_00_15(4, e, f, g, h, a, b, c, d); + T1 = X[5] = PULL64(W[5]); + ROUND_00_15(5, d, e, f, g, h, a, b, c); + T1 = X[6] = PULL64(W[6]); + ROUND_00_15(6, c, d, e, f, g, h, a, b); + T1 = X[7] = PULL64(W[7]); + ROUND_00_15(7, b, c, d, e, f, g, h, a); + T1 = X[8] = PULL64(W[8]); + ROUND_00_15(8, a, b, c, d, e, f, g, h); + T1 = X[9] = PULL64(W[9]); + ROUND_00_15(9, h, a, b, c, d, e, f, g); + T1 = X[10] = PULL64(W[10]); + ROUND_00_15(10, g, h, a, b, c, d, e, f); + T1 = X[11] = PULL64(W[11]); + ROUND_00_15(11, f, g, h, a, b, c, d, e); + T1 = X[12] = PULL64(W[12]); + ROUND_00_15(12, e, f, g, h, a, b, c, d); + T1 = X[13] = PULL64(W[13]); + ROUND_00_15(13, d, e, f, g, h, a, b, c); + T1 = X[14] = PULL64(W[14]); + ROUND_00_15(14, c, d, e, f, g, h, a, b); + T1 = X[15] = PULL64(W[15]); + ROUND_00_15(15, b, c, d, e, f, g, h, a); + + for (i = 16; i < 80; i += 16) { + ROUND_16_80(i, 0, a, b, c, d, e, f, g, h, X); + ROUND_16_80(i, 1, h, a, b, c, d, e, f, g, X); + ROUND_16_80(i, 2, g, h, a, b, c, d, e, f, X); + ROUND_16_80(i, 3, f, g, h, a, b, c, d, e, X); + ROUND_16_80(i, 4, e, f, g, h, a, b, c, d, X); + ROUND_16_80(i, 5, d, e, f, g, h, a, b, c, X); + ROUND_16_80(i, 6, c, d, e, f, g, h, a, b, X); + ROUND_16_80(i, 7, b, c, d, e, f, g, h, a, X); + ROUND_16_80(i, 8, a, b, c, d, e, f, g, h, X); + ROUND_16_80(i, 9, h, a, b, c, d, e, f, g, X); + ROUND_16_80(i, 10, g, h, a, b, c, d, e, f, X); + ROUND_16_80(i, 11, f, g, h, a, b, c, d, e, X); + ROUND_16_80(i, 12, e, f, g, h, a, b, c, d, X); + ROUND_16_80(i, 13, d, e, f, g, h, a, b, c, X); + ROUND_16_80(i, 14, c, d, e, f, g, h, a, b, X); + ROUND_16_80(i, 15, b, c, d, e, f, g, h, a, X); + } + + ctx->h[0] += a; + ctx->h[1] += b; + ctx->h[2] += c; + ctx->h[3] += d; + ctx->h[4] += e; + ctx->h[5] += f; + ctx->h[6] += g; + ctx->h[7] += h; + + W += 16; + } +} + +#endif + +#endif /* SHA512_ASM */ diff --git a/TMessagesProj/jni/boringssl/crypto/stack/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/stack/CMakeLists.txt new file mode 100644 index 00000000..bdb05994 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/stack/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories(. .. ../../include) + +add_library( + stack + + OBJECT + + stack.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/stack/make_macros.sh b/TMessagesProj/jni/boringssl/crypto/stack/make_macros.sh new file mode 100644 index 00000000..4837e449 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/stack/make_macros.sh @@ -0,0 +1,115 @@ +#!/bin/sh + +include_dir=../../include/openssl + +cat > "${include_dir}/stack_macros.h" << EOF +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#if !defined(IN_STACK_H) +#error "Don't include this file directly. Include stack.h." +#endif + +EOF + +output_stack () { + type=$1 + ptrtype=$2 + + cat >> "${include_dir}/stack_macros.h" << EOF +/* ${type} */ +#define sk_${type}_new(comp)\\ + ((STACK_OF(${type})*) sk_new(CHECKED_CAST(stack_cmp_func, int (*) (const ${ptrtype} *a, const ${ptrtype} *b), comp))) + +#define sk_${type}_new_null()\\ + ((STACK_OF(${type})*) sk_new_null()) + +#define sk_${type}_num(sk)\\ + sk_num(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk)) + +#define sk_${type}_zero(sk)\\ + sk_zero(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk)); + +#define sk_${type}_value(sk, i)\\ + ((${ptrtype}) sk_value(CHECKED_CAST(_STACK*, const STACK_OF(${type})*, sk), (i))) + +#define sk_${type}_set(sk, i, p)\\ + ((${ptrtype}) sk_set(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), (i), CHECKED_CAST(void*, ${ptrtype}, p))) + +#define sk_${type}_free(sk)\\ + sk_free(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk)) + +#define sk_${type}_pop_free(sk, free_func)\\ + sk_pop_free(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(void (*) (void*), void (*) (${ptrtype}), free_func)) + +#define sk_${type}_insert(sk, p, where)\\ + sk_insert(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(void*, ${ptrtype}, p), (where)) + +#define sk_${type}_delete(sk, where)\\ + ((${ptrtype}) sk_delete(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), (where))) + +#define sk_${type}_delete_ptr(sk, p)\\ + ((${ptrtype}) sk_delete_ptr(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(void*, ${ptrtype}, p))) + +#define sk_${type}_find(sk, out_index, p)\\ + sk_find(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), (out_index), CHECKED_CAST(void*, ${ptrtype}, p)) + +#define sk_${type}_shift(sk)\\ + ((${ptrtype}) sk_shift(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk))) + +#define sk_${type}_push(sk, p)\\ + sk_push(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(void*, ${ptrtype}, p)) + +#define sk_${type}_pop(sk)\\ + ((${ptrtype}) sk_pop(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk))) + +#define sk_${type}_dup(sk)\\ + ((STACK_OF(${type})*) sk_dup(CHECKED_CAST(_STACK*, const STACK_OF(${type})*, sk))) + +#define sk_${type}_sort(sk)\\ + sk_sort(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk)) + +#define sk_${type}_is_sorted(sk)\\ + sk_is_sorted(CHECKED_CAST(_STACK*, const STACK_OF(${type})*, sk)) + +#define sk_${type}_set_cmp_func(sk, comp)\\ + ((int (*) (const ${type} **a, const ${type} **b)) sk_set_cmp_func(CHECKED_CAST(_STACK*, STACK_OF(${type})*, sk), CHECKED_CAST(stack_cmp_func, int (*) (const ${type} **a, const ${type} **b), comp))) + +#define sk_${type}_deep_copy(sk, copy_func, free_func)\\ +((STACK_OF(${type})*) sk_deep_copy(CHECKED_CAST(const _STACK*, const STACK_OF(${type})*, sk), CHECKED_CAST(void* (*) (void*), ${ptrtype} (*) (${ptrtype}), copy_func), CHECKED_CAST(void (*) (void*), void (*) (${ptrtype}), free_func))) + + +EOF +} + +stack_types=$(cat "${include_dir}/stack.h" | grep '^ \* STACK_OF:' | sed -e 's/.*STACK_OF://' -e 's/ .*//') +const_stack_types=$(cat "${include_dir}/stack.h" | grep '^ \* CONST_STACK_OF:' | sed -e 's/.*CONST_STACK_OF://' -e 's/ .*//') +special_stack_types=$(cat "${include_dir}/stack.h" | grep '^ \* SPECIAL_STACK_OF:' | sed -e 's/.*SPECIAL_STACK_OF://' -e 's/ .*//') + +for type in $stack_types; do + echo Stack of ${type} + output_stack "${type}" "${type} *" +done + +for type in $const_stack_types; do + echo Stack of ${type} + output_stack "${type}" "const ${type} *" +done + +for type in $special_stack_types; do + echo Stack of ${type} + output_stack "${type}" "${type}" +done + +clang-format -i "${include_dir}/stack_macros.h" diff --git a/TMessagesProj/jni/boringssl/crypto/stack/stack.c b/TMessagesProj/jni/boringssl/crypto/stack/stack.c new file mode 100644 index 00000000..c5845159 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/stack/stack.c @@ -0,0 +1,386 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include + +/* kMinSize is the number of pointers that will be initially allocated in a new + * stack. */ +static const size_t kMinSize = 4; + +_STACK *sk_new(stack_cmp_func comp) { + _STACK *ret; + + ret = OPENSSL_malloc(sizeof(_STACK)); + if (ret == NULL) { + goto err; + } + memset(ret, 0, sizeof(_STACK)); + + ret->data = OPENSSL_malloc(sizeof(void *) * kMinSize); + if (ret->data == NULL) { + goto err; + } + + memset(ret->data, 0, sizeof(void *) * kMinSize); + + ret->comp = comp; + ret->num_alloc = kMinSize; + + return ret; + +err: + OPENSSL_free(ret); + return NULL; +} + +_STACK *sk_new_null(void) { return sk_new(NULL); } + +size_t sk_num(const _STACK *sk) { + if (sk == NULL) { + return 0; + } + return sk->num; +} + +void sk_zero(_STACK *sk) { + if (sk == NULL || sk->num == 0) { + return; + } + memset(sk->data, 0, sizeof(void*) * sk->num); + sk->num = 0; + sk->sorted = 0; +} + +void *sk_value(const _STACK *sk, size_t i) { + if (!sk || i >= sk->num) { + return NULL; + } + return sk->data[i]; +} + +void *sk_set(_STACK *sk, size_t i, void *value) { + if (!sk || i >= sk->num) { + return NULL; + } + return sk->data[i] = value; +} + +void sk_free(_STACK *sk) { + if (sk == NULL) { + return; + } + OPENSSL_free(sk->data); + OPENSSL_free(sk); +} + +void sk_pop_free(_STACK *sk, void (*func)(void *)) { + size_t i; + + if (sk == NULL) { + return; + } + + for (i = 0; i < sk->num; i++) { + if (sk->data[i] != NULL) { + func(sk->data[i]); + } + } + sk_free(sk); +} + +size_t sk_insert(_STACK *sk, void *p, size_t where) { + if (sk == NULL) { + return 0; + } + + if (sk->num_alloc <= sk->num + 1) { + /* Attempt to double the size of the array. */ + size_t new_alloc = sk->num_alloc << 1; + size_t alloc_size = new_alloc * sizeof(void *); + void **data; + + /* If the doubling overflowed, try to increment. */ + if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) { + new_alloc = sk->num_alloc + 1; + alloc_size = new_alloc * sizeof(void *); + } + + /* If the increment also overflowed, fail. */ + if (new_alloc < sk->num_alloc || alloc_size / sizeof(void *) != new_alloc) { + return 0; + } + + data = OPENSSL_realloc(sk->data, alloc_size); + if (data == NULL) { + return 0; + } + + sk->data = data; + sk->num_alloc = new_alloc; + } + + if (where >= sk->num) { + sk->data[sk->num] = p; + } else { + memmove(&sk->data[where + 1], &sk->data[where], + sizeof(void *) * (sk->num - where)); + sk->data[where] = p; + } + + sk->num++; + sk->sorted = 0; + + return sk->num; +} + +void *sk_delete(_STACK *sk, size_t where) { + void *ret; + + if (!sk || where >= sk->num) { + return NULL; + } + + ret = sk->data[where]; + + if (where != sk->num - 1) { + memmove(&sk->data[where], &sk->data[where + 1], + sizeof(void *) * (sk->num - where - 1)); + } + + sk->num--; + return ret; +} + +void *sk_delete_ptr(_STACK *sk, void *p) { + size_t i; + + if (sk == NULL) { + return NULL; + } + + for (i = 0; i < sk->num; i++) { + if (sk->data[i] == p) { + return sk_delete(sk, i); + } + } + + return NULL; +} + +int sk_find(_STACK *sk, size_t *out_index, void *p) { + const void *const *r; + size_t i; + int (*comp_func)(const void *,const void *); + + if (sk == NULL) { + return 0; + } + + if (sk->comp == NULL) { + /* Use pointer equality when no comparison function has been set. */ + for (i = 0; i < sk->num; i++) { + if (sk->data[i] == p) { + if (out_index) { + *out_index = i; + } + return 1; + } + } + return 0; + } + + if (p == NULL) { + return 0; + } + + sk_sort(sk); + + /* sk->comp is a function that takes pointers to pointers to elements, but + * qsort and bsearch take a comparison function that just takes pointers to + * elements. However, since we're passing an array of pointers to + * qsort/bsearch, we can just cast the comparison function and everything + * works. */ + comp_func=(int (*)(const void *,const void *))(sk->comp); + r = bsearch(&p, sk->data, sk->num, sizeof(void *), comp_func); + if (r == NULL) { + return 0; + } + i = ((void **)r) - sk->data; + /* This function always returns the first result. */ + while (i > 0 && sk->comp((const void**) &p, (const void**) &sk->data[i-1]) == 0) { + i--; + } + if (out_index) { + *out_index = i; + } + return 1; +} + +void *sk_shift(_STACK *sk) { + if (sk == NULL) { + return NULL; + } + if (sk->num == 0) { + return NULL; + } + return sk_delete(sk, 0); +} + +size_t sk_push(_STACK *sk, void *p) { return (sk_insert(sk, p, sk->num)); } + +void *sk_pop(_STACK *sk) { + if (sk == NULL) { + return NULL; + } + if (sk->num == 0) { + return NULL; + } + return sk_delete(sk, sk->num - 1); +} + +_STACK *sk_dup(const _STACK *sk) { + _STACK *ret; + void **s; + + if (sk == NULL) { + return NULL; + } + + ret = sk_new(sk->comp); + if (ret == NULL) { + goto err; + } + + s = (void **)OPENSSL_realloc(ret->data, sizeof(void *) * sk->num_alloc); + if (s == NULL) { + goto err; + } + ret->data = s; + + ret->num = sk->num; + memcpy(ret->data, sk->data, sizeof(void *) * sk->num); + ret->sorted = sk->sorted; + ret->num_alloc = sk->num_alloc; + ret->comp = sk->comp; + return ret; + +err: + sk_free(ret); + return NULL; +} + +void sk_sort(_STACK *sk) { + int (*comp_func)(const void *,const void *); + + if (sk == NULL || sk->sorted) { + return; + } + + /* See the comment in sk_find about this cast. */ + comp_func = (int (*)(const void *, const void *))(sk->comp); + qsort(sk->data, sk->num, sizeof(void *), comp_func); + sk->sorted = 1; +} + +int sk_is_sorted(const _STACK *sk) { + if (!sk) { + return 1; + } + return sk->sorted; +} + +stack_cmp_func sk_set_cmp_func(_STACK *sk, stack_cmp_func comp) { + stack_cmp_func old = sk->comp; + + if (sk->comp != comp) { + sk->sorted = 0; + } + sk->comp = comp; + + return old; +} + +_STACK *sk_deep_copy(const _STACK *sk, void *(*copy_func)(void *), + void (*free_func)(void *)) { + _STACK *ret = sk_dup(sk); + if (ret == NULL) { + return NULL; + } + + size_t i; + for (i = 0; i < ret->num; i++) { + if (ret->data[i] == NULL) { + continue; + } + ret->data[i] = copy_func(ret->data[i]); + if (ret->data[i] == NULL) { + size_t j; + for (j = 0; j < i; j++) { + if (ret->data[j] != NULL) { + free_func(ret->data[j]); + } + } + sk_free(ret); + return NULL; + } + } + + return ret; +} diff --git a/TMessagesProj/jni/boringssl/crypto/thread.c b/TMessagesProj/jni/boringssl/crypto/thread.c new file mode 100644 index 00000000..88371159 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/thread.c @@ -0,0 +1,101 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#if !defined(OPENSSL_WINDOWS) +#include +#else +#pragma warning(push, 3) +#include +#pragma warning(pop) +#endif + +#include + + +int CRYPTO_num_locks(void) { return 1; } + +void CRYPTO_set_locking_callback(void (*func)(int mode, int lock_num, + const char *file, int line)) {} + +void CRYPTO_set_add_lock_callback(int (*func)(int *num, int mount, int lock_num, + const char *file, int line)) {} + +const char *CRYPTO_get_lock_name(int lock_num) { + return "No old-style OpenSSL locks anymore"; +} + +int CRYPTO_THREADID_set_callback(void (*func)(CRYPTO_THREADID *)) { return 1; } + +void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, unsigned long val) {} + +void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr) {} + +void CRYPTO_THREADID_current(CRYPTO_THREADID *id) {} + +void CRYPTO_set_id_callback(unsigned long (*func)(void)) {} + +void CRYPTO_set_dynlock_create_callback(struct CRYPTO_dynlock_value *( + *dyn_create_function)(const char *file, int line)) {} + +void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)( + int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)) {} + +void CRYPTO_set_dynlock_destroy_callback(void (*dyn_destroy_function)( + struct CRYPTO_dynlock_value *l, const char *file, int line)) {} diff --git a/TMessagesProj/jni/boringssl/crypto/thread_none.c b/TMessagesProj/jni/boringssl/crypto/thread_none.c new file mode 100644 index 00000000..cf4e85a7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/thread_none.c @@ -0,0 +1,55 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include "internal.h" + +#if defined(OPENSSL_NO_THREADS) + +void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock) {} + +void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) {} + +void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) {} + +void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock) {} + +void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) {} + +void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) {} + +void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) {} + +void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) {} + +void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)) { + if (*once) { + return; + } + *once = 1; + init(); +} + +static void *g_thread_locals[NUM_OPENSSL_THREAD_LOCALS]; + +void *CRYPTO_get_thread_local(thread_local_data_t index) { + return g_thread_locals[index]; +} + +int CRYPTO_set_thread_local(thread_local_data_t index, void *value, + thread_local_destructor_t destructor) { + g_thread_locals[index] = value; + return 1; +} + +#endif /* OPENSSL_NO_THREADS */ diff --git a/TMessagesProj/jni/boringssl/crypto/thread_pthread.c b/TMessagesProj/jni/boringssl/crypto/thread_pthread.c new file mode 100644 index 00000000..59c4b8d1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/thread_pthread.c @@ -0,0 +1,162 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include "internal.h" + +#if !defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_THREADS) + +#include +#include +#include + +#include +#include + + +OPENSSL_COMPILE_ASSERT(sizeof(CRYPTO_MUTEX) >= sizeof(pthread_rwlock_t), + CRYPTO_MUTEX_too_small); + +void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock) { + if (pthread_rwlock_init((pthread_rwlock_t *) lock, NULL) != 0) { + abort(); + } +} + +void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) { + if (pthread_rwlock_rdlock((pthread_rwlock_t *) lock) != 0) { + abort(); + } +} + +void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) { + if (pthread_rwlock_wrlock((pthread_rwlock_t *) lock) != 0) { + abort(); + } +} + +void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock) { + if (pthread_rwlock_unlock((pthread_rwlock_t *) lock) != 0) { + abort(); + } +} + +void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) { + pthread_rwlock_destroy((pthread_rwlock_t *) lock); +} + +void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) { + if (pthread_rwlock_rdlock(&lock->lock) != 0) { + abort(); + } +} + +void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) { + if (pthread_rwlock_wrlock(&lock->lock) != 0) { + abort(); + } +} + +void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) { + if (pthread_rwlock_unlock(&lock->lock) != 0) { + abort(); + } +} + +void CRYPTO_once(CRYPTO_once_t *once, void (*init)(void)) { + pthread_once(once, init); +} + +static pthread_mutex_t g_destructors_lock = PTHREAD_MUTEX_INITIALIZER; +static thread_local_destructor_t g_destructors[NUM_OPENSSL_THREAD_LOCALS]; + +static void thread_local_destructor(void *arg) { + if (arg == NULL) { + return; + } + + thread_local_destructor_t destructors[NUM_OPENSSL_THREAD_LOCALS]; + if (pthread_mutex_lock(&g_destructors_lock) != 0) { + return; + } + memcpy(destructors, g_destructors, sizeof(destructors)); + pthread_mutex_unlock(&g_destructors_lock); + + unsigned i; + void **pointers = arg; + for (i = 0; i < NUM_OPENSSL_THREAD_LOCALS; i++) { + if (destructors[i] != NULL) { + destructors[i](pointers[i]); + } + } + + OPENSSL_free(pointers); +} + +static pthread_once_t g_thread_local_init_once = PTHREAD_ONCE_INIT; +static pthread_key_t g_thread_local_key; +static int g_thread_local_failed = 0; + +static void thread_local_init(void) { + g_thread_local_failed = + pthread_key_create(&g_thread_local_key, thread_local_destructor) != 0; +} + +void *CRYPTO_get_thread_local(thread_local_data_t index) { + CRYPTO_once(&g_thread_local_init_once, thread_local_init); + if (g_thread_local_failed) { + return NULL; + } + + void **pointers = pthread_getspecific(g_thread_local_key); + if (pointers == NULL) { + return NULL; + } + return pointers[index]; +} + +int CRYPTO_set_thread_local(thread_local_data_t index, void *value, + thread_local_destructor_t destructor) { + CRYPTO_once(&g_thread_local_init_once, thread_local_init); + if (g_thread_local_failed) { + destructor(value); + return 0; + } + + void **pointers = pthread_getspecific(g_thread_local_key); + if (pointers == NULL) { + pointers = OPENSSL_malloc(sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); + if (pointers == NULL) { + destructor(value); + return 0; + } + memset(pointers, 0, sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); + if (pthread_setspecific(g_thread_local_key, pointers) != 0) { + OPENSSL_free(pointers); + destructor(value); + return 0; + } + } + + if (pthread_mutex_lock(&g_destructors_lock) != 0) { + destructor(value); + return 0; + } + g_destructors[index] = destructor; + pthread_mutex_unlock(&g_destructors_lock); + + pointers[index] = value; + return 1; +} + +#endif /* !OPENSSL_WINDOWS && !OPENSSL_NO_THREADS */ diff --git a/TMessagesProj/jni/boringssl/crypto/thread_win.c b/TMessagesProj/jni/boringssl/crypto/thread_win.c new file mode 100644 index 00000000..5efd8be3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/thread_win.c @@ -0,0 +1,282 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include "internal.h" + +#if defined(OPENSSL_WINDOWS) && !defined(OPENSSL_NO_THREADS) + +#pragma warning(push, 3) +#include +#pragma warning(pop) + +#include +#include +#include + +#include +#include + + +OPENSSL_COMPILE_ASSERT(sizeof(CRYPTO_MUTEX) >= sizeof(CRITICAL_SECTION), + CRYPTO_MUTEX_too_small); + +static void run_once(CRYPTO_once_t *in_once, void (*init)(void *), void *arg) { + volatile LONG *once = in_once; + + /* Values must be aligned. */ + assert((((uintptr_t) once) & 3) == 0); + + /* This assumes that reading *once has acquire semantics. This should be true + * on x86 and x86-64, where we expect Windows to run. */ +#if !defined(OPENSSL_X86) && !defined(OPENSSL_X86_64) +#error "Windows once code may not work on other platforms." \ + "You can use InitOnceBeginInitialize on >=Vista" +#endif + if (*once == 1) { + return; + } + + for (;;) { + switch (InterlockedCompareExchange(once, 2, 0)) { + case 0: + /* The value was zero so we are the first thread to call |CRYPTO_once| + * on it. */ + init(arg); + /* Write one to indicate that initialisation is complete. */ + InterlockedExchange(once, 1); + return; + + case 1: + /* Another thread completed initialisation between our fast-path check + * and |InterlockedCompareExchange|. */ + return; + + case 2: + /* Another thread is running the initialisation. Switch to it then try + * again. */ + SwitchToThread(); + break; + + default: + abort(); + } + } +} + +static void call_once_init(void *arg) { + void (*init_func)(void); + /* MSVC does not like casting between data and function pointers. */ + memcpy(&init_func, &arg, sizeof(void *)); + init_func(); +} + +void CRYPTO_once(CRYPTO_once_t *in_once, void (*init)(void)) { + void *arg; + /* MSVC does not like casting between data and function pointers. */ + memcpy(&arg, &init, sizeof(void *)); + run_once(in_once, call_once_init, arg); +} + +void CRYPTO_MUTEX_init(CRYPTO_MUTEX *lock) { + if (!InitializeCriticalSectionAndSpinCount((CRITICAL_SECTION *) lock, 0x400)) { + abort(); + } +} + +void CRYPTO_MUTEX_lock_read(CRYPTO_MUTEX *lock) { + /* Since we have to support Windows XP, read locks are actually exclusive. */ + EnterCriticalSection((CRITICAL_SECTION *) lock); +} + +void CRYPTO_MUTEX_lock_write(CRYPTO_MUTEX *lock) { + EnterCriticalSection((CRITICAL_SECTION *) lock); +} + +void CRYPTO_MUTEX_unlock(CRYPTO_MUTEX *lock) { + LeaveCriticalSection((CRITICAL_SECTION *) lock); +} + +void CRYPTO_MUTEX_cleanup(CRYPTO_MUTEX *lock) { + DeleteCriticalSection((CRITICAL_SECTION *) lock); +} + +static void static_lock_init(void *arg) { + struct CRYPTO_STATIC_MUTEX *lock = arg; + if (!InitializeCriticalSectionAndSpinCount(&lock->lock, 0x400)) { + abort(); + } +} + +void CRYPTO_STATIC_MUTEX_lock_read(struct CRYPTO_STATIC_MUTEX *lock) { + /* Since we have to support Windows XP, read locks are actually exclusive. */ + run_once(&lock->once, static_lock_init, lock); + EnterCriticalSection(&lock->lock); +} + +void CRYPTO_STATIC_MUTEX_lock_write(struct CRYPTO_STATIC_MUTEX *lock) { + CRYPTO_STATIC_MUTEX_lock_read(lock); +} + +void CRYPTO_STATIC_MUTEX_unlock(struct CRYPTO_STATIC_MUTEX *lock) { + LeaveCriticalSection(&lock->lock); +} + +static CRITICAL_SECTION g_destructors_lock; +static thread_local_destructor_t g_destructors[NUM_OPENSSL_THREAD_LOCALS]; + +static CRYPTO_once_t g_thread_local_init_once = CRYPTO_ONCE_INIT; +static DWORD g_thread_local_key; +static int g_thread_local_failed; + +static void thread_local_init(void) { + if (!InitializeCriticalSectionAndSpinCount(&g_destructors_lock, 0x400)) { + g_thread_local_failed = 1; + return; + } + g_thread_local_key = TlsAlloc(); + g_thread_local_failed = (g_thread_local_key == TLS_OUT_OF_INDEXES); +} + +static void NTAPI thread_local_destructor(PVOID module, + DWORD reason, PVOID reserved) { + if (DLL_THREAD_DETACH != reason && DLL_PROCESS_DETACH != reason) { + return; + } + + CRYPTO_once(&g_thread_local_init_once, thread_local_init); + if (g_thread_local_failed) { + return; + } + + void **pointers = (void**) TlsGetValue(g_thread_local_key); + if (pointers == NULL) { + return; + } + + thread_local_destructor_t destructors[NUM_OPENSSL_THREAD_LOCALS]; + + EnterCriticalSection(&g_destructors_lock); + memcpy(destructors, g_destructors, sizeof(destructors)); + LeaveCriticalSection(&g_destructors_lock); + + unsigned i; + for (i = 0; i < NUM_OPENSSL_THREAD_LOCALS; i++) { + if (destructors[i] != NULL) { + destructors[i](pointers[i]); + } + } + + OPENSSL_free(pointers); +} + +/* Thread Termination Callbacks. + * + * Windows doesn't support a per-thread destructor with its TLS primitives. + * So, we build it manually by inserting a function to be called on each + * thread's exit. This magic is from http://www.codeproject.com/threads/tls.asp + * and it works for VC++ 7.0 and later. + * + * Force a reference to _tls_used to make the linker create the TLS directory + * if it's not already there. (E.g. if __declspec(thread) is not used). Force + * a reference to p_thread_callback_boringssl to prevent whole program + * optimization from discarding the variable. */ +#ifdef _WIN64 +#pragma comment(linker, "/INCLUDE:_tls_used") +#pragma comment(linker, "/INCLUDE:p_thread_callback_boringssl") +#else +#pragma comment(linker, "/INCLUDE:__tls_used") +#pragma comment(linker, "/INCLUDE:_p_thread_callback_boringssl") +#endif + +/* .CRT$XLA to .CRT$XLZ is an array of PIMAGE_TLS_CALLBACK pointers that are + * called automatically by the OS loader code (not the CRT) when the module is + * loaded and on thread creation. They are NOT called if the module has been + * loaded by a LoadLibrary() call. It must have implicitly been loaded at + * process startup. + * + * By implicitly loaded, I mean that it is directly referenced by the main EXE + * or by one of its dependent DLLs. Delay-loaded DLL doesn't count as being + * implicitly loaded. + * + * See VC\crt\src\tlssup.c for reference. */ + +/* The linker must not discard p_thread_callback_boringssl. (We force a reference + * to this variable with a linker /INCLUDE:symbol pragma to ensure that.) If + * this variable is discarded, the OnThreadExit function will never be + * called. */ +#ifdef _WIN64 + +/* .CRT section is merged with .rdata on x64 so it must be constant data. */ +#pragma const_seg(".CRT$XLC") +/* When defining a const variable, it must have external linkage to be sure the + * linker doesn't discard it. */ +extern const PIMAGE_TLS_CALLBACK p_thread_callback_boringssl; +const PIMAGE_TLS_CALLBACK p_thread_callback_boringssl = thread_local_destructor; +/* Reset the default section. */ +#pragma const_seg() + +#else + +#pragma data_seg(".CRT$XLC") +PIMAGE_TLS_CALLBACK p_thread_callback_boringssl = thread_local_destructor; +/* Reset the default section. */ +#pragma data_seg() + +#endif /* _WIN64 */ + +void *CRYPTO_get_thread_local(thread_local_data_t index) { + CRYPTO_once(&g_thread_local_init_once, thread_local_init); + if (g_thread_local_failed) { + return NULL; + } + + void **pointers = TlsGetValue(g_thread_local_key); + if (pointers == NULL) { + return NULL; + } + return pointers[index]; +} + +int CRYPTO_set_thread_local(thread_local_data_t index, void *value, + thread_local_destructor_t destructor) { + CRYPTO_once(&g_thread_local_init_once, thread_local_init); + if (g_thread_local_failed) { + destructor(value); + return 0; + } + + void **pointers = TlsGetValue(g_thread_local_key); + if (pointers == NULL) { + pointers = OPENSSL_malloc(sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); + if (pointers == NULL) { + destructor(value); + return 0; + } + memset(pointers, 0, sizeof(void *) * NUM_OPENSSL_THREAD_LOCALS); + if (TlsSetValue(g_thread_local_key, pointers) == 0) { + OPENSSL_free(pointers); + destructor(value); + return 0; + } + } + + EnterCriticalSection(&g_destructors_lock); + g_destructors[index] = destructor; + LeaveCriticalSection(&g_destructors_lock); + + pointers[index] = value; + return 1; +} + +#endif /* OPENSSL_WINDOWS && !OPENSSL_NO_THREADS */ diff --git a/TMessagesProj/jni/boringssl/crypto/time_support.c b/TMessagesProj/jni/boringssl/crypto/time_support.c new file mode 100644 index 00000000..bf9daed1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/time_support.c @@ -0,0 +1,212 @@ +/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL + * project 2001. + * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2008. + */ +/* ==================================================================== + * Copyright (c) 2001 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#if !defined(_POSIX_C_SOURCE) +#define _POSIX_C_SOURCE 201410L /* for gmtime_r */ +#endif + +#if defined(__MINGW32__) +#define MINGW_HAS_SECURE_API 1 /* supplied by libmingwex */ +#include /* for correct definition of gmtime_s */ +#undef MINGW_HAS_SECURE_API +#endif + +#include + +#include + + +#define SECS_PER_DAY (24 * 60 * 60) + +struct tm *OPENSSL_gmtime(const time_t *time, struct tm *result) { +#if defined(OPENSSL_WINDOWS) + if (gmtime_s(result, time)) { + return NULL; + } + return result; +#else + return gmtime_r(time, result); +#endif +} + +/* Convert date to and from julian day Uses Fliegel & Van Flandern algorithm */ +static long date_to_julian(int y, int m, int d) { + return (1461 * (y + 4800 + (m - 14) / 12)) / 4 + + (367 * (m - 2 - 12 * ((m - 14) / 12))) / 12 - + (3 * ((y + 4900 + (m - 14) / 12) / 100)) / 4 + d - 32075; +} + +static void julian_to_date(long jd, int *y, int *m, int *d) { + long L = jd + 68569; + long n = (4 * L) / 146097; + long i, j; + + L = L - (146097 * n + 3) / 4; + i = (4000 * (L + 1)) / 1461001; + L = L - (1461 * i) / 4 + 31; + j = (80 * L) / 2447; + *d = L - (2447 * j) / 80; + L = j / 11; + *m = j + 2 - (12 * L); + *y = 100 * (n - 49) + i + L; +} + +/* Convert tm structure and offset into julian day and seconds */ +static int julian_adj(const struct tm *tm, int off_day, long offset_sec, + long *pday, int *psec) { + int offset_hms, offset_day; + long time_jd; + int time_year, time_month, time_day; + /* split offset into days and day seconds */ + offset_day = offset_sec / SECS_PER_DAY; + /* Avoid sign issues with % operator */ + offset_hms = offset_sec - (offset_day * SECS_PER_DAY); + offset_day += off_day; + /* Add current time seconds to offset */ + offset_hms += tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec; + /* Adjust day seconds if overflow */ + if (offset_hms >= SECS_PER_DAY) { + offset_day++; + offset_hms -= SECS_PER_DAY; + } else if (offset_hms < 0) { + offset_day--; + offset_hms += SECS_PER_DAY; + } + + /* Convert date of time structure into a Julian day number. */ + + time_year = tm->tm_year + 1900; + time_month = tm->tm_mon + 1; + time_day = tm->tm_mday; + + time_jd = date_to_julian(time_year, time_month, time_day); + + /* Work out Julian day of new date */ + time_jd += offset_day; + + if (time_jd < 0) { + return 0; + } + + *pday = time_jd; + *psec = offset_hms; + return 1; +} + +int OPENSSL_gmtime_adj(struct tm *tm, int off_day, long offset_sec) { + int time_sec, time_year, time_month, time_day; + long time_jd; + + /* Convert time and offset into julian day and seconds */ + if (!julian_adj(tm, off_day, offset_sec, &time_jd, &time_sec)) { + return 0; + } + + /* Convert Julian day back to date */ + + julian_to_date(time_jd, &time_year, &time_month, &time_day); + + if (time_year < 1900 || time_year > 9999) { + return 0; + } + + /* Update tm structure */ + + tm->tm_year = time_year - 1900; + tm->tm_mon = time_month - 1; + tm->tm_mday = time_day; + + tm->tm_hour = time_sec / 3600; + tm->tm_min = (time_sec / 60) % 60; + tm->tm_sec = time_sec % 60; + + return 1; +} + +int OPENSSL_gmtime_diff(int *pday, int *psec, const struct tm *from, + const struct tm *to) { + int from_sec, to_sec, diff_sec; + long from_jd, to_jd, diff_day; + + if (!julian_adj(from, 0, 0, &from_jd, &from_sec)) { + return 0; + } + if (!julian_adj(to, 0, 0, &to_jd, &to_sec)) { + return 0; + } + + diff_day = to_jd - from_jd; + diff_sec = to_sec - from_sec; + /* Adjust differences so both positive or both negative */ + if (diff_day > 0 && diff_sec < 0) { + diff_day--; + diff_sec += SECS_PER_DAY; + } + if (diff_day < 0 && diff_sec > 0) { + diff_day++; + diff_sec -= SECS_PER_DAY; + } + + if (pday) { + *pday = (int)diff_day; + } + if (psec) { + *psec = diff_sec; + } + + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/x509/CMakeLists.txt new file mode 100644 index 00000000..456e3069 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/CMakeLists.txt @@ -0,0 +1,57 @@ +include_directories(. .. ../../include) + +add_library( + x509 + + OBJECT + + a_digest.c + a_sign.c + a_strex.c + a_verify.c + asn1_gen.c + by_dir.c + by_file.c + i2d_pr.c + pkcs7.c + t_crl.c + t_req.c + t_x509.c + t_x509a.c + x509.c + x509_att.c + x509_cmp.c + x509_d2.c + x509_def.c + x509_ext.c + x509_lu.c + x509_obj.c + x509_r2x.c + x509_req.c + x509_set.c + x509_trs.c + x509_txt.c + x509_v3.c + x509_vfy.c + x509_vpm.c + x509cset.c + x509name.c + x509rset.c + x509spki.c + x509type.c + x_algor.c + x_all.c + x_attrib.c + x_crl.c + x_exten.c + x_info.c + x_name.c + x_pkey.c + x_pubkey.c + x_req.c + x_sig.c + x_spki.c + x_val.c + x_x509.c + x_x509a.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/a_digest.c b/TMessagesProj/jni/boringssl/crypto/x509/a_digest.c new file mode 100644 index 00000000..430e2e6c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/a_digest.c @@ -0,0 +1,97 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include + + +int ASN1_digest(i2d_of_void *i2d, const EVP_MD *type, char *data, + unsigned char *md, unsigned int *len) + { + int i, ret; + unsigned char *str,*p; + + i=i2d(data,NULL); + if ((str=(unsigned char *)OPENSSL_malloc(i)) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return(0); + } + p=str; + i2d(data,&p); + + ret = EVP_Digest(str, i, md, len, type, NULL); + OPENSSL_free(str); + return ret; + } + +int ASN1_item_digest(const ASN1_ITEM *it, const EVP_MD *type, void *asn, + unsigned char *md, unsigned int *len) + { + int i, ret; + unsigned char *str = NULL; + + i=ASN1_item_i2d(asn,&str, it); + if (!str) return(0); + + ret = EVP_Digest(str, i, md, len, type, NULL); + OPENSSL_free(str); + return ret; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/a_sign.c b/TMessagesProj/jni/boringssl/crypto/x509/a_sign.c new file mode 100644 index 00000000..4e9be8a4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/a_sign.c @@ -0,0 +1,136 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include + +#include "../evp/internal.h" + + +int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2, + ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey, + const EVP_MD *type) + { + EVP_MD_CTX ctx; + EVP_MD_CTX_init(&ctx); + if (!EVP_DigestSignInit(&ctx, NULL, type, NULL, pkey)) + { + EVP_MD_CTX_cleanup(&ctx); + return 0; + } + return ASN1_item_sign_ctx(it, algor1, algor2, signature, asn, &ctx); + } + + +int ASN1_item_sign_ctx(const ASN1_ITEM *it, + X509_ALGOR *algor1, X509_ALGOR *algor2, + ASN1_BIT_STRING *signature, void *asn, EVP_MD_CTX *ctx) + { + EVP_PKEY *pkey; + unsigned char *buf_in=NULL,*buf_out=NULL; + size_t inl=0,outl=0,outll=0; + + pkey = EVP_PKEY_CTX_get0_pkey(ctx->pctx); + + /* Write out the requested copies of the AlgorithmIdentifier. */ + if (algor1 && !EVP_DigestSignAlgorithm(ctx, algor1)) + { + goto err; + } + if (algor2 && !EVP_DigestSignAlgorithm(ctx, algor2)) + { + goto err; + } + + inl=ASN1_item_i2d(asn,&buf_in, it); + outll=outl=EVP_PKEY_size(pkey); + buf_out=OPENSSL_malloc((unsigned int)outl); + if ((buf_in == NULL) || (buf_out == NULL)) + { + outl=0; + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EVP_DigestSignUpdate(ctx, buf_in, inl) + || !EVP_DigestSignFinal(ctx, buf_out, &outl)) + { + outl=0; + OPENSSL_PUT_ERROR(X509, ERR_R_EVP_LIB); + goto err; + } + if (signature->data != NULL) OPENSSL_free(signature->data); + signature->data=buf_out; + buf_out=NULL; + signature->length=outl; + /* In the interests of compatibility, I'll make sure that + * the bit string has a 'not-used bits' value of 0 + */ + signature->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); + signature->flags|=ASN1_STRING_FLAG_BITS_LEFT; +err: + EVP_MD_CTX_cleanup(ctx); + if (buf_in != NULL) + { OPENSSL_cleanse((char *)buf_in,(unsigned int)inl); OPENSSL_free(buf_in); } + if (buf_out != NULL) + { OPENSSL_cleanse((char *)buf_out,outll); OPENSSL_free(buf_out); } + return(outl); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/a_strex.c b/TMessagesProj/jni/boringssl/crypto/x509/a_strex.c new file mode 100644 index 00000000..b194d180 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/a_strex.c @@ -0,0 +1,564 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include + +#include "charmap.h" + + +/* ASN1_STRING_print_ex() and X509_NAME_print_ex(). + * Enhanced string and name printing routines handling + * multibyte characters, RFC2253 and a host of other + * options. + */ + + +#define CHARTYPE_BS_ESC (ASN1_STRFLGS_ESC_2253 | CHARTYPE_FIRST_ESC_2253 | CHARTYPE_LAST_ESC_2253) + +#define ESC_FLAGS (ASN1_STRFLGS_ESC_2253 | \ + ASN1_STRFLGS_ESC_QUOTE | \ + ASN1_STRFLGS_ESC_CTRL | \ + ASN1_STRFLGS_ESC_MSB) + + +static int send_bio_chars(void *arg, const void *buf, int len) +{ + if(!arg) return 1; + if(BIO_write(arg, buf, len) != len) return 0; + return 1; +} + +static int send_fp_chars(void *arg, const void *buf, int len) +{ + if(!arg) return 1; + if(fwrite(buf, 1, len, arg) != (unsigned int)len) return 0; + return 1; +} + +typedef int char_io(void *arg, const void *buf, int len); + +/* This function handles display of + * strings, one character at a time. + * It is passed an unsigned long for each + * character because it could come from 2 or even + * 4 byte forms. + */ + +#define HEX_SIZE(type) (sizeof(type)*2) + +static int do_esc_char(unsigned long c, unsigned char flags, char *do_quotes, char_io *io_ch, void *arg) +{ + unsigned char chflgs, chtmp; + char tmphex[HEX_SIZE(long)+3]; + + if(c > 0xffffffffL) + return -1; + if(c > 0xffff) { + BIO_snprintf(tmphex, sizeof tmphex, "\\W%08lX", c); + if(!io_ch(arg, tmphex, 10)) return -1; + return 10; + } + if(c > 0xff) { + BIO_snprintf(tmphex, sizeof tmphex, "\\U%04lX", c); + if(!io_ch(arg, tmphex, 6)) return -1; + return 6; + } + chtmp = (unsigned char)c; + if(chtmp > 0x7f) chflgs = flags & ASN1_STRFLGS_ESC_MSB; + else chflgs = char_type[chtmp] & flags; + if(chflgs & CHARTYPE_BS_ESC) { + /* If we don't escape with quotes, signal we need quotes */ + if(chflgs & ASN1_STRFLGS_ESC_QUOTE) { + if(do_quotes) *do_quotes = 1; + if(!io_ch(arg, &chtmp, 1)) return -1; + return 1; + } + if(!io_ch(arg, "\\", 1)) return -1; + if(!io_ch(arg, &chtmp, 1)) return -1; + return 2; + } + if(chflgs & (ASN1_STRFLGS_ESC_CTRL|ASN1_STRFLGS_ESC_MSB)) { + BIO_snprintf(tmphex, 11, "\\%02X", chtmp); + if(!io_ch(arg, tmphex, 3)) return -1; + return 3; + } + /* If we get this far and do any escaping at all must escape + * the escape character itself: backslash. + */ + if (chtmp == '\\' && flags & ESC_FLAGS) { + if(!io_ch(arg, "\\\\", 2)) return -1; + return 2; + } + if(!io_ch(arg, &chtmp, 1)) return -1; + return 1; +} + +#define BUF_TYPE_WIDTH_MASK 0x7 +#define BUF_TYPE_CONVUTF8 0x8 + +/* This function sends each character in a buffer to + * do_esc_char(). It interprets the content formats + * and converts to or from UTF8 as appropriate. + */ + +static int do_buf(unsigned char *buf, int buflen, + int type, unsigned char flags, char *quotes, char_io *io_ch, void *arg) +{ + int i, outlen, len; + unsigned char orflags, *p, *q; + unsigned long c; + p = buf; + q = buf + buflen; + outlen = 0; + while(p != q) { + if(p == buf && flags & ASN1_STRFLGS_ESC_2253) orflags = CHARTYPE_FIRST_ESC_2253; + else orflags = 0; + switch(type & BUF_TYPE_WIDTH_MASK) { + case 4: + c = ((unsigned long)*p++) << 24; + c |= ((unsigned long)*p++) << 16; + c |= ((unsigned long)*p++) << 8; + c |= *p++; + break; + + case 2: + c = ((unsigned long)*p++) << 8; + c |= *p++; + break; + + case 1: + c = *p++; + break; + + case 0: + i = UTF8_getc(p, buflen, &c); + if(i < 0) return -1; /* Invalid UTF8String */ + p += i; + break; + default: + return -1; /* invalid width */ + } + if (p == q && flags & ASN1_STRFLGS_ESC_2253) orflags = CHARTYPE_LAST_ESC_2253; + if(type & BUF_TYPE_CONVUTF8) { + unsigned char utfbuf[6]; + int utflen; + utflen = UTF8_putc(utfbuf, sizeof utfbuf, c); + for(i = 0; i < utflen; i++) { + /* We don't need to worry about setting orflags correctly + * because if utflen==1 its value will be correct anyway + * otherwise each character will be > 0x7f and so the + * character will never be escaped on first and last. + */ + len = do_esc_char(utfbuf[i], (unsigned char)(flags | orflags), quotes, io_ch, arg); + if(len < 0) return -1; + outlen += len; + } + } else { + len = do_esc_char(c, (unsigned char)(flags | orflags), quotes, io_ch, arg); + if(len < 0) return -1; + outlen += len; + } + } + return outlen; +} + +/* This function hex dumps a buffer of characters */ + +static int do_hex_dump(char_io *io_ch, void *arg, unsigned char *buf, int buflen) +{ + static const char hexdig[] = "0123456789ABCDEF"; + unsigned char *p, *q; + char hextmp[2]; + if(arg) { + p = buf; + q = buf + buflen; + while(p != q) { + hextmp[0] = hexdig[*p >> 4]; + hextmp[1] = hexdig[*p & 0xf]; + if(!io_ch(arg, hextmp, 2)) return -1; + p++; + } + } + return buflen << 1; +} + +/* "dump" a string. This is done when the type is unknown, + * or the flags request it. We can either dump the content + * octets or the entire DER encoding. This uses the RFC2253 + * #01234 format. + */ + +static int do_dump(unsigned long lflags, char_io *io_ch, void *arg, ASN1_STRING *str) +{ + /* Placing the ASN1_STRING in a temp ASN1_TYPE allows + * the DER encoding to readily obtained + */ + ASN1_TYPE t; + unsigned char *der_buf, *p; + int outlen, der_len; + + if(!io_ch(arg, "#", 1)) return -1; + /* If we don't dump DER encoding just dump content octets */ + if(!(lflags & ASN1_STRFLGS_DUMP_DER)) { + outlen = do_hex_dump(io_ch, arg, str->data, str->length); + if(outlen < 0) return -1; + return outlen + 1; + } + t.type = str->type; + t.value.ptr = (char *)str; + der_len = i2d_ASN1_TYPE(&t, NULL); + der_buf = OPENSSL_malloc(der_len); + if(!der_buf) return -1; + p = der_buf; + i2d_ASN1_TYPE(&t, &p); + outlen = do_hex_dump(io_ch, arg, der_buf, der_len); + OPENSSL_free(der_buf); + if(outlen < 0) return -1; + return outlen + 1; +} + +/* Lookup table to convert tags to character widths, + * 0 = UTF8 encoded, -1 is used for non string types + * otherwise it is the number of bytes per character + */ + +static const signed char tag2nbyte[] = { + -1, -1, -1, -1, -1, /* 0-4 */ + -1, -1, -1, -1, -1, /* 5-9 */ + -1, -1, 0, -1, /* 10-13 */ + -1, -1, -1, -1, /* 15-17 */ + -1, 1, 1, /* 18-20 */ + -1, 1, 1, 1, /* 21-24 */ + -1, 1, -1, /* 25-27 */ + 4, -1, 2 /* 28-30 */ +}; + +/* This is the main function, print out an + * ASN1_STRING taking note of various escape + * and display options. Returns number of + * characters written or -1 if an error + * occurred. + */ + +static int do_print_ex(char_io *io_ch, void *arg, unsigned long lflags, ASN1_STRING *str) +{ + int outlen, len; + int type; + char quotes; + unsigned char flags; + quotes = 0; + /* Keep a copy of escape flags */ + flags = (unsigned char)(lflags & ESC_FLAGS); + + type = str->type; + + outlen = 0; + + + if(lflags & ASN1_STRFLGS_SHOW_TYPE) { + const char *tagname; + tagname = ASN1_tag2str(type); + outlen += strlen(tagname); + if(!io_ch(arg, tagname, outlen) || !io_ch(arg, ":", 1)) return -1; + outlen++; + } + + /* Decide what to do with type, either dump content or display it */ + + /* Dump everything */ + if(lflags & ASN1_STRFLGS_DUMP_ALL) type = -1; + /* Ignore the string type */ + else if(lflags & ASN1_STRFLGS_IGNORE_TYPE) type = 1; + else { + /* Else determine width based on type */ + if((type > 0) && (type < 31)) type = tag2nbyte[type]; + else type = -1; + if((type == -1) && !(lflags & ASN1_STRFLGS_DUMP_UNKNOWN)) type = 1; + } + + if(type == -1) { + len = do_dump(lflags, io_ch, arg, str); + if(len < 0) return -1; + outlen += len; + return outlen; + } + + if(lflags & ASN1_STRFLGS_UTF8_CONVERT) { + /* Note: if string is UTF8 and we want + * to convert to UTF8 then we just interpret + * it as 1 byte per character to avoid converting + * twice. + */ + if(!type) type = 1; + else type |= BUF_TYPE_CONVUTF8; + } + + len = do_buf(str->data, str->length, type, flags, "es, io_ch, NULL); + if(len < 0) return -1; + outlen += len; + if(quotes) outlen += 2; + if(!arg) return outlen; + if(quotes && !io_ch(arg, "\"", 1)) return -1; + if(do_buf(str->data, str->length, type, flags, NULL, io_ch, arg) < 0) + return -1; + if(quotes && !io_ch(arg, "\"", 1)) return -1; + return outlen; +} + +/* Used for line indenting: print 'indent' spaces */ + +static int do_indent(char_io *io_ch, void *arg, int indent) +{ + int i; + for(i = 0; i < indent; i++) + if(!io_ch(arg, " ", 1)) return 0; + return 1; +} + +#define FN_WIDTH_LN 25 +#define FN_WIDTH_SN 10 + +static int do_name_ex(char_io *io_ch, void *arg, X509_NAME *n, + int indent, unsigned long flags) +{ + int i, prev = -1, orflags, cnt; + int fn_opt, fn_nid; + ASN1_OBJECT *fn; + ASN1_STRING *val; + X509_NAME_ENTRY *ent; + char objtmp[80]; + const char *objbuf; + int outlen, len; + const char *sep_dn, *sep_mv, *sep_eq; + int sep_dn_len, sep_mv_len, sep_eq_len; + if(indent < 0) indent = 0; + outlen = indent; + if(!do_indent(io_ch, arg, indent)) return -1; + switch (flags & XN_FLAG_SEP_MASK) + { + case XN_FLAG_SEP_MULTILINE: + sep_dn = "\n"; + sep_dn_len = 1; + sep_mv = " + "; + sep_mv_len = 3; + break; + + case XN_FLAG_SEP_COMMA_PLUS: + sep_dn = ","; + sep_dn_len = 1; + sep_mv = "+"; + sep_mv_len = 1; + indent = 0; + break; + + case XN_FLAG_SEP_CPLUS_SPC: + sep_dn = ", "; + sep_dn_len = 2; + sep_mv = " + "; + sep_mv_len = 3; + indent = 0; + break; + + case XN_FLAG_SEP_SPLUS_SPC: + sep_dn = "; "; + sep_dn_len = 2; + sep_mv = " + "; + sep_mv_len = 3; + indent = 0; + break; + + default: + return -1; + } + + if(flags & XN_FLAG_SPC_EQ) { + sep_eq = " = "; + sep_eq_len = 3; + } else { + sep_eq = "="; + sep_eq_len = 1; + } + + fn_opt = flags & XN_FLAG_FN_MASK; + + cnt = X509_NAME_entry_count(n); + for(i = 0; i < cnt; i++) { + if(flags & XN_FLAG_DN_REV) + ent = X509_NAME_get_entry(n, cnt - i - 1); + else ent = X509_NAME_get_entry(n, i); + if(prev != -1) { + if(prev == ent->set) { + if(!io_ch(arg, sep_mv, sep_mv_len)) return -1; + outlen += sep_mv_len; + } else { + if(!io_ch(arg, sep_dn, sep_dn_len)) return -1; + outlen += sep_dn_len; + if(!do_indent(io_ch, arg, indent)) return -1; + outlen += indent; + } + } + prev = ent->set; + fn = X509_NAME_ENTRY_get_object(ent); + val = X509_NAME_ENTRY_get_data(ent); + fn_nid = OBJ_obj2nid(fn); + if(fn_opt != XN_FLAG_FN_NONE) { + int objlen, fld_len; + if((fn_opt == XN_FLAG_FN_OID) || (fn_nid==NID_undef) ) { + OBJ_obj2txt(objtmp, sizeof objtmp, fn, 1); + fld_len = 0; /* XXX: what should this be? */ + objbuf = objtmp; + } else { + if(fn_opt == XN_FLAG_FN_SN) { + fld_len = FN_WIDTH_SN; + objbuf = OBJ_nid2sn(fn_nid); + } else if(fn_opt == XN_FLAG_FN_LN) { + fld_len = FN_WIDTH_LN; + objbuf = OBJ_nid2ln(fn_nid); + } else { + fld_len = 0; /* XXX: what should this be? */ + objbuf = ""; + } + } + objlen = strlen(objbuf); + if(!io_ch(arg, objbuf, objlen)) return -1; + if ((objlen < fld_len) && (flags & XN_FLAG_FN_ALIGN)) { + if (!do_indent(io_ch, arg, fld_len - objlen)) return -1; + outlen += fld_len - objlen; + } + if(!io_ch(arg, sep_eq, sep_eq_len)) return -1; + outlen += objlen + sep_eq_len; + } + /* If the field name is unknown then fix up the DER dump + * flag. We might want to limit this further so it will + * DER dump on anything other than a few 'standard' fields. + */ + if((fn_nid == NID_undef) && (flags & XN_FLAG_DUMP_UNKNOWN_FIELDS)) + orflags = ASN1_STRFLGS_DUMP_ALL; + else orflags = 0; + + len = do_print_ex(io_ch, arg, flags | orflags, val); + if(len < 0) return -1; + outlen += len; + } + return outlen; +} + +/* Wrappers round the main functions */ + +int X509_NAME_print_ex(BIO *out, X509_NAME *nm, int indent, unsigned long flags) +{ + if(flags == XN_FLAG_COMPAT) + return X509_NAME_print(out, nm, indent); + return do_name_ex(send_bio_chars, out, nm, indent, flags); +} + +#ifndef OPENSSL_NO_FP_API +int X509_NAME_print_ex_fp(FILE *fp, X509_NAME *nm, int indent, unsigned long flags) +{ + if(flags == XN_FLAG_COMPAT) + { + BIO *btmp; + int ret; + btmp = BIO_new_fp(fp, BIO_NOCLOSE); + if(!btmp) return -1; + ret = X509_NAME_print(btmp, nm, indent); + BIO_free(btmp); + return ret; + } + return do_name_ex(send_fp_chars, fp, nm, indent, flags); +} +#endif + +int ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags) +{ + return do_print_ex(send_bio_chars, out, flags, str); +} + +#ifndef OPENSSL_NO_FP_API +int ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags) +{ + return do_print_ex(send_fp_chars, fp, flags, str); +} +#endif + +/* Utility function: convert any string type to UTF8, returns number of bytes + * in output string or a negative error code + */ + +int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in) +{ + ASN1_STRING stmp, *str = &stmp; + int mbflag, type, ret; + if(!in) return -1; + type = in->type; + if((type < 0) || (type > 30)) return -1; + mbflag = tag2nbyte[type]; + if(mbflag == -1) return -1; + mbflag |= MBSTRING_FLAG; + stmp.data = NULL; + stmp.length = 0; + stmp.flags = 0; + ret = ASN1_mbstring_copy(&str, in->data, in->length, mbflag, B_ASN1_UTF8STRING); + if(ret < 0) return ret; + *out = stmp.data; + return stmp.length; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/a_verify.c b/TMessagesProj/jni/boringssl/crypto/x509/a_verify.c new file mode 100644 index 00000000..572a1392 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/a_verify.c @@ -0,0 +1,133 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../evp/internal.h" + + +int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *a, + ASN1_BIT_STRING *signature, void *asn, EVP_PKEY *pkey) + { + EVP_MD_CTX ctx; + uint8_t *buf_in = NULL; + int ret = 0, inl; + + if (!pkey) + { + OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (signature->type == V_ASN1_BIT_STRING && signature->flags & 0x7) + { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_BIT_STRING_BITS_LEFT); + return 0; + } + + EVP_MD_CTX_init(&ctx); + + if (!EVP_DigestVerifyInitFromAlgorithm(&ctx, a, pkey)) + { + goto err; + } + + inl = ASN1_item_i2d(asn, &buf_in, it); + + if (buf_in == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!EVP_DigestVerifyUpdate(&ctx,buf_in,inl)) + { + OPENSSL_cleanse(buf_in,(unsigned int)inl); + OPENSSL_free(buf_in); + OPENSSL_PUT_ERROR(X509, ERR_R_EVP_LIB); + goto err; + } + + OPENSSL_cleanse(buf_in,(unsigned int)inl); + OPENSSL_free(buf_in); + + if (EVP_DigestVerifyFinal(&ctx,signature->data, + (size_t)signature->length) <= 0) + { + OPENSSL_PUT_ERROR(X509, ERR_R_EVP_LIB); + goto err; + } + /* we don't need to zero the 'ctx' because we just checked + * public information */ + /* memset(&ctx,0,sizeof(ctx)); */ + ret = 1; +err: + EVP_MD_CTX_cleanup(&ctx); + return ret; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/asn1_gen.c b/TMessagesProj/jni/boringssl/crypto/x509/asn1_gen.c new file mode 100644 index 00000000..850a8167 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/asn1_gen.c @@ -0,0 +1,873 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include +#include + +#include "../internal.h" + + +/* Although this file is in crypto/x509 for layering purposes, it emits errors + * from the ASN.1 module for OpenSSL compatibility. */ + +#define ASN1_GEN_FLAG 0x10000 +#define ASN1_GEN_FLAG_IMP (ASN1_GEN_FLAG|1) +#define ASN1_GEN_FLAG_EXP (ASN1_GEN_FLAG|2) +#define ASN1_GEN_FLAG_TAG (ASN1_GEN_FLAG|3) +#define ASN1_GEN_FLAG_BITWRAP (ASN1_GEN_FLAG|4) +#define ASN1_GEN_FLAG_OCTWRAP (ASN1_GEN_FLAG|5) +#define ASN1_GEN_FLAG_SEQWRAP (ASN1_GEN_FLAG|6) +#define ASN1_GEN_FLAG_SETWRAP (ASN1_GEN_FLAG|7) +#define ASN1_GEN_FLAG_FORMAT (ASN1_GEN_FLAG|8) + +#define ASN1_GEN_STR(str,val) {str, sizeof(str) - 1, val} + +#define ASN1_FLAG_EXP_MAX 20 + +/* Input formats */ + +/* ASCII: default */ +#define ASN1_GEN_FORMAT_ASCII 1 +/* UTF8 */ +#define ASN1_GEN_FORMAT_UTF8 2 +/* Hex */ +#define ASN1_GEN_FORMAT_HEX 3 +/* List of bits */ +#define ASN1_GEN_FORMAT_BITLIST 4 + + +struct tag_name_st + { + const char *strnam; + int len; + int tag; + }; + +typedef struct + { + int exp_tag; + int exp_class; + int exp_constructed; + int exp_pad; + long exp_len; + } tag_exp_type; + +typedef struct + { + int imp_tag; + int imp_class; + int utype; + int format; + const char *str; + tag_exp_type exp_list[ASN1_FLAG_EXP_MAX]; + int exp_count; + } tag_exp_arg; + +static int bitstr_cb(const char *elem, int len, void *bitstr); +static int asn1_cb(const char *elem, int len, void *bitstr); +static int append_exp(tag_exp_arg *arg, int exp_tag, int exp_class, int exp_constructed, int exp_pad, int imp_ok); +static int parse_tagging(const char *vstart, int vlen, int *ptag, int *pclass); +static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf); +static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype); +static int asn1_str2tag(const char *tagstr, int len); + +ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf) + { + X509V3_CTX cnf; + + if (!nconf) + return ASN1_generate_v3(str, NULL); + + X509V3_set_nconf(&cnf, nconf); + return ASN1_generate_v3(str, &cnf); + } + +ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf) + OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS + { + ASN1_TYPE *ret; + tag_exp_arg asn1_tags; + tag_exp_type *etmp; + + int i, len; + + unsigned char *orig_der = NULL, *new_der = NULL; + const unsigned char *cpy_start; + unsigned char *p; + const unsigned char *cp; + int cpy_len; + long hdr_len; + int hdr_constructed = 0, hdr_tag, hdr_class; + int r; + + asn1_tags.imp_tag = -1; + asn1_tags.imp_class = -1; + asn1_tags.format = ASN1_GEN_FORMAT_ASCII; + asn1_tags.exp_count = 0; + if (CONF_parse_list(str, ',', 1, asn1_cb, &asn1_tags) != 0) + return NULL; + + if ((asn1_tags.utype == V_ASN1_SEQUENCE) || (asn1_tags.utype == V_ASN1_SET)) + { + if (!cnf) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG); + return NULL; + } + ret = asn1_multi(asn1_tags.utype, asn1_tags.str, cnf); + } + else + ret = asn1_str2type(asn1_tags.str, asn1_tags.format, asn1_tags.utype); + + if (!ret) + return NULL; + + /* If no tagging return base type */ + if ((asn1_tags.imp_tag == -1) && (asn1_tags.exp_count == 0)) + return ret; + + /* Generate the encoding */ + cpy_len = i2d_ASN1_TYPE(ret, &orig_der); + ASN1_TYPE_free(ret); + ret = NULL; + /* Set point to start copying for modified encoding */ + cpy_start = orig_der; + + /* Do we need IMPLICIT tagging? */ + if (asn1_tags.imp_tag != -1) + { + /* If IMPLICIT we will replace the underlying tag */ + /* Skip existing tag+len */ + r = ASN1_get_object(&cpy_start, &hdr_len, &hdr_tag, &hdr_class, cpy_len); + if (r & 0x80) + goto err; + /* Update copy length */ + cpy_len -= cpy_start - orig_der; + /* For IMPLICIT tagging the length should match the + * original length and constructed flag should be + * consistent. + */ + if (r & 0x1) + { + /* Indefinite length constructed */ + hdr_constructed = 2; + hdr_len = 0; + } + else + /* Just retain constructed flag */ + hdr_constructed = r & V_ASN1_CONSTRUCTED; + /* Work out new length with IMPLICIT tag: ignore constructed + * because it will mess up if indefinite length + */ + len = ASN1_object_size(0, hdr_len, asn1_tags.imp_tag); + } + else + len = cpy_len; + + /* Work out length in any EXPLICIT, starting from end */ + + for(i = 0, etmp = asn1_tags.exp_list + asn1_tags.exp_count - 1; i < asn1_tags.exp_count; i++, etmp--) + { + /* Content length: number of content octets + any padding */ + len += etmp->exp_pad; + etmp->exp_len = len; + /* Total object length: length including new header */ + len = ASN1_object_size(0, len, etmp->exp_tag); + } + + /* Allocate buffer for new encoding */ + + new_der = OPENSSL_malloc(len); + if (!new_der) + goto err; + + /* Generate tagged encoding */ + + p = new_der; + + /* Output explicit tags first */ + + for (i = 0, etmp = asn1_tags.exp_list; i < asn1_tags.exp_count; i++, etmp++) + { + ASN1_put_object(&p, etmp->exp_constructed, etmp->exp_len, + etmp->exp_tag, etmp->exp_class); + if (etmp->exp_pad) + *p++ = 0; + } + + /* If IMPLICIT, output tag */ + + if (asn1_tags.imp_tag != -1) + { + if (asn1_tags.imp_class == V_ASN1_UNIVERSAL + && (asn1_tags.imp_tag == V_ASN1_SEQUENCE + || asn1_tags.imp_tag == V_ASN1_SET) ) + hdr_constructed = V_ASN1_CONSTRUCTED; + ASN1_put_object(&p, hdr_constructed, hdr_len, + asn1_tags.imp_tag, asn1_tags.imp_class); + } + + /* Copy across original encoding */ + memcpy(p, cpy_start, cpy_len); + + cp = new_der; + + /* Obtain new ASN1_TYPE structure */ + ret = d2i_ASN1_TYPE(NULL, &cp, len); + + err: + if (orig_der) + OPENSSL_free(orig_der); + if (new_der) + OPENSSL_free(new_der); + + return ret; + + } + +static int asn1_cb(const char *elem, int len, void *bitstr) + { + tag_exp_arg *arg = bitstr; + int i; + int utype; + int vlen = 0; + const char *p, *vstart = NULL; + + int tmp_tag, tmp_class; + + if (elem == NULL) + return 0; + + for(i = 0, p = elem; i < len; p++, i++) + { + /* Look for the ':' in name value pairs */ + if (*p == ':') + { + vstart = p + 1; + vlen = len - (vstart - elem); + len = p - elem; + break; + } + } + + utype = asn1_str2tag(elem, len); + + if (utype == -1) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_TAG); + ERR_add_error_data(2, "tag=", elem); + return -1; + } + + /* If this is not a modifier mark end of string and exit */ + if (!(utype & ASN1_GEN_FLAG)) + { + arg->utype = utype; + arg->str = vstart; + /* If no value and not end of string, error */ + if (!vstart && elem[len]) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_VALUE); + return -1; + } + return 0; + } + + switch(utype) + { + + case ASN1_GEN_FLAG_IMP: + /* Check for illegal multiple IMPLICIT tagging */ + if (arg->imp_tag != -1) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_NESTED_TAGGING); + return -1; + } + if (!parse_tagging(vstart, vlen, &arg->imp_tag, &arg->imp_class)) + return -1; + break; + + case ASN1_GEN_FLAG_EXP: + + if (!parse_tagging(vstart, vlen, &tmp_tag, &tmp_class)) + return -1; + if (!append_exp(arg, tmp_tag, tmp_class, 1, 0, 0)) + return -1; + break; + + case ASN1_GEN_FLAG_SEQWRAP: + if (!append_exp(arg, V_ASN1_SEQUENCE, V_ASN1_UNIVERSAL, 1, 0, 1)) + return -1; + break; + + case ASN1_GEN_FLAG_SETWRAP: + if (!append_exp(arg, V_ASN1_SET, V_ASN1_UNIVERSAL, 1, 0, 1)) + return -1; + break; + + case ASN1_GEN_FLAG_BITWRAP: + if (!append_exp(arg, V_ASN1_BIT_STRING, V_ASN1_UNIVERSAL, 0, 1, 1)) + return -1; + break; + + case ASN1_GEN_FLAG_OCTWRAP: + if (!append_exp(arg, V_ASN1_OCTET_STRING, V_ASN1_UNIVERSAL, 0, 0, 1)) + return -1; + break; + + case ASN1_GEN_FLAG_FORMAT: + if (!vstart) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_FORMAT); + return -1; + } + if (!strncmp(vstart, "ASCII", 5)) + arg->format = ASN1_GEN_FORMAT_ASCII; + else if (!strncmp(vstart, "UTF8", 4)) + arg->format = ASN1_GEN_FORMAT_UTF8; + else if (!strncmp(vstart, "HEX", 3)) + arg->format = ASN1_GEN_FORMAT_HEX; + else if (!strncmp(vstart, "BITLIST", 7)) + arg->format = ASN1_GEN_FORMAT_BITLIST; + else + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNKNOWN_FORMAT); + return -1; + } + break; + + } + + return 1; + + } + +static int parse_tagging(const char *vstart, int vlen, int *ptag, int *pclass) + { + char erch[2]; + long tag_num; + char *eptr; + if (!vstart) + return 0; + tag_num = strtoul(vstart, &eptr, 10); + /* Check we haven't gone past max length: should be impossible */ + if (eptr && *eptr && (eptr > vstart + vlen)) + return 0; + if (tag_num < 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_NUMBER); + return 0; + } + *ptag = tag_num; + /* If we have non numeric characters, parse them */ + if (eptr) + vlen -= eptr - vstart; + else + vlen = 0; + if (vlen) + { + switch (*eptr) + { + + case 'U': + *pclass = V_ASN1_UNIVERSAL; + break; + + case 'A': + *pclass = V_ASN1_APPLICATION; + break; + + case 'P': + *pclass = V_ASN1_PRIVATE; + break; + + case 'C': + *pclass = V_ASN1_CONTEXT_SPECIFIC; + break; + + default: + erch[0] = *eptr; + erch[1] = 0; + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_MODIFIER); + ERR_add_error_data(2, "Char=", erch); + return 0; + break; + + } + } + else + *pclass = V_ASN1_CONTEXT_SPECIFIC; + + return 1; + + } + +/* Handle multiple types: SET and SEQUENCE */ + +static ASN1_TYPE *asn1_multi(int utype, const char *section, X509V3_CTX *cnf) + { + ASN1_TYPE *ret = NULL; + STACK_OF(ASN1_TYPE) *sk = NULL; + STACK_OF(CONF_VALUE) *sect = NULL; + unsigned char *der = NULL; + int derlen; + size_t i; + sk = sk_ASN1_TYPE_new_null(); + if (!sk) + goto bad; + if (section) + { + if (!cnf) + goto bad; + sect = X509V3_get_section(cnf, (char *)section); + if (!sect) + goto bad; + for (i = 0; i < sk_CONF_VALUE_num(sect); i++) + { + ASN1_TYPE *typ = ASN1_generate_v3(sk_CONF_VALUE_value(sect, i)->value, cnf); + if (!typ) + goto bad; + if (!sk_ASN1_TYPE_push(sk, typ)) + goto bad; + } + } + + /* Now we has a STACK of the components, convert to the correct form */ + + if (utype == V_ASN1_SET) + derlen = i2d_ASN1_SET_ANY(sk, &der); + else + derlen = i2d_ASN1_SEQUENCE_ANY(sk, &der); + + if (derlen < 0) + goto bad; + + if (!(ret = ASN1_TYPE_new())) + goto bad; + + if (!(ret->value.asn1_string = ASN1_STRING_type_new(utype))) + goto bad; + + ret->type = utype; + + ret->value.asn1_string->data = der; + ret->value.asn1_string->length = derlen; + + der = NULL; + + bad: + + if (der) + OPENSSL_free(der); + + if (sk) + sk_ASN1_TYPE_pop_free(sk, ASN1_TYPE_free); + if (sect) + X509V3_section_free(cnf, sect); + + return ret; + } + +static int append_exp(tag_exp_arg *arg, int exp_tag, int exp_class, int exp_constructed, int exp_pad, int imp_ok) + { + tag_exp_type *exp_tmp; + /* Can only have IMPLICIT if permitted */ + if ((arg->imp_tag != -1) && !imp_ok) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_IMPLICIT_TAG); + return 0; + } + + if (arg->exp_count == ASN1_FLAG_EXP_MAX) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_DEPTH_EXCEEDED); + return 0; + } + + exp_tmp = &arg->exp_list[arg->exp_count++]; + + /* If IMPLICIT set tag to implicit value then + * reset implicit tag since it has been used. + */ + if (arg->imp_tag != -1) + { + exp_tmp->exp_tag = arg->imp_tag; + exp_tmp->exp_class = arg->imp_class; + arg->imp_tag = -1; + arg->imp_class = -1; + } + else + { + exp_tmp->exp_tag = exp_tag; + exp_tmp->exp_class = exp_class; + } + exp_tmp->exp_constructed = exp_constructed; + exp_tmp->exp_pad = exp_pad; + + return 1; + } + + +static int asn1_str2tag(const char *tagstr, int len) + { + unsigned int i; + static const struct tag_name_st *tntmp, tnst [] = { + ASN1_GEN_STR("BOOL", V_ASN1_BOOLEAN), + ASN1_GEN_STR("BOOLEAN", V_ASN1_BOOLEAN), + ASN1_GEN_STR("NULL", V_ASN1_NULL), + ASN1_GEN_STR("INT", V_ASN1_INTEGER), + ASN1_GEN_STR("INTEGER", V_ASN1_INTEGER), + ASN1_GEN_STR("ENUM", V_ASN1_ENUMERATED), + ASN1_GEN_STR("ENUMERATED", V_ASN1_ENUMERATED), + ASN1_GEN_STR("OID", V_ASN1_OBJECT), + ASN1_GEN_STR("OBJECT", V_ASN1_OBJECT), + ASN1_GEN_STR("UTCTIME", V_ASN1_UTCTIME), + ASN1_GEN_STR("UTC", V_ASN1_UTCTIME), + ASN1_GEN_STR("GENERALIZEDTIME", V_ASN1_GENERALIZEDTIME), + ASN1_GEN_STR("GENTIME", V_ASN1_GENERALIZEDTIME), + ASN1_GEN_STR("OCT", V_ASN1_OCTET_STRING), + ASN1_GEN_STR("OCTETSTRING", V_ASN1_OCTET_STRING), + ASN1_GEN_STR("BITSTR", V_ASN1_BIT_STRING), + ASN1_GEN_STR("BITSTRING", V_ASN1_BIT_STRING), + ASN1_GEN_STR("UNIVERSALSTRING", V_ASN1_UNIVERSALSTRING), + ASN1_GEN_STR("UNIV", V_ASN1_UNIVERSALSTRING), + ASN1_GEN_STR("IA5", V_ASN1_IA5STRING), + ASN1_GEN_STR("IA5STRING", V_ASN1_IA5STRING), + ASN1_GEN_STR("UTF8", V_ASN1_UTF8STRING), + ASN1_GEN_STR("UTF8String", V_ASN1_UTF8STRING), + ASN1_GEN_STR("BMP", V_ASN1_BMPSTRING), + ASN1_GEN_STR("BMPSTRING", V_ASN1_BMPSTRING), + ASN1_GEN_STR("VISIBLESTRING", V_ASN1_VISIBLESTRING), + ASN1_GEN_STR("VISIBLE", V_ASN1_VISIBLESTRING), + ASN1_GEN_STR("PRINTABLESTRING", V_ASN1_PRINTABLESTRING), + ASN1_GEN_STR("PRINTABLE", V_ASN1_PRINTABLESTRING), + ASN1_GEN_STR("T61", V_ASN1_T61STRING), + ASN1_GEN_STR("T61STRING", V_ASN1_T61STRING), + ASN1_GEN_STR("TELETEXSTRING", V_ASN1_T61STRING), + ASN1_GEN_STR("GeneralString", V_ASN1_GENERALSTRING), + ASN1_GEN_STR("GENSTR", V_ASN1_GENERALSTRING), + ASN1_GEN_STR("NUMERIC", V_ASN1_NUMERICSTRING), + ASN1_GEN_STR("NUMERICSTRING", V_ASN1_NUMERICSTRING), + + /* Special cases */ + ASN1_GEN_STR("SEQUENCE", V_ASN1_SEQUENCE), + ASN1_GEN_STR("SEQ", V_ASN1_SEQUENCE), + ASN1_GEN_STR("SET", V_ASN1_SET), + /* type modifiers */ + /* Explicit tag */ + ASN1_GEN_STR("EXP", ASN1_GEN_FLAG_EXP), + ASN1_GEN_STR("EXPLICIT", ASN1_GEN_FLAG_EXP), + /* Implicit tag */ + ASN1_GEN_STR("IMP", ASN1_GEN_FLAG_IMP), + ASN1_GEN_STR("IMPLICIT", ASN1_GEN_FLAG_IMP), + /* OCTET STRING wrapper */ + ASN1_GEN_STR("OCTWRAP", ASN1_GEN_FLAG_OCTWRAP), + /* SEQUENCE wrapper */ + ASN1_GEN_STR("SEQWRAP", ASN1_GEN_FLAG_SEQWRAP), + /* SET wrapper */ + ASN1_GEN_STR("SETWRAP", ASN1_GEN_FLAG_SETWRAP), + /* BIT STRING wrapper */ + ASN1_GEN_STR("BITWRAP", ASN1_GEN_FLAG_BITWRAP), + ASN1_GEN_STR("FORM", ASN1_GEN_FLAG_FORMAT), + ASN1_GEN_STR("FORMAT", ASN1_GEN_FLAG_FORMAT), + }; + + if (len == -1) + len = strlen(tagstr); + + tntmp = tnst; + for (i = 0; i < sizeof(tnst) / sizeof(struct tag_name_st); i++, tntmp++) + { + if ((len == tntmp->len) && !strncmp(tntmp->strnam, tagstr, len)) + return tntmp->tag; + } + + return -1; + } + +static ASN1_TYPE *asn1_str2type(const char *str, int format, int utype) + { + ASN1_TYPE *atmp = NULL; + + CONF_VALUE vtmp; + + unsigned char *rdata; + long rdlen; + + int no_unused = 1; + + if (!(atmp = ASN1_TYPE_new())) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if (!str) + str = ""; + + switch(utype) + { + + case V_ASN1_NULL: + if (str && *str) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_NULL_VALUE); + goto bad_form; + } + break; + + case V_ASN1_BOOLEAN: + if (format != ASN1_GEN_FORMAT_ASCII) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_NOT_ASCII_FORMAT); + goto bad_form; + } + vtmp.name = NULL; + vtmp.section = NULL; + vtmp.value = (char *)str; + if (!X509V3_get_value_bool(&vtmp, &atmp->value.boolean)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_BOOLEAN); + goto bad_str; + } + break; + + case V_ASN1_INTEGER: + case V_ASN1_ENUMERATED: + if (format != ASN1_GEN_FORMAT_ASCII) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INTEGER_NOT_ASCII_FORMAT); + goto bad_form; + } + if (!(atmp->value.integer = s2i_ASN1_INTEGER(NULL, (char *)str))) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_INTEGER); + goto bad_str; + } + break; + + case V_ASN1_OBJECT: + if (format != ASN1_GEN_FORMAT_ASCII) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_OBJECT_NOT_ASCII_FORMAT); + goto bad_form; + } + if (!(atmp->value.object = OBJ_txt2obj(str, 0))) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_OBJECT); + goto bad_str; + } + break; + + case V_ASN1_UTCTIME: + case V_ASN1_GENERALIZEDTIME: + if (format != ASN1_GEN_FORMAT_ASCII) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_TIME_NOT_ASCII_FORMAT); + goto bad_form; + } + if (!(atmp->value.asn1_string = ASN1_STRING_new())) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto bad_str; + } + if (!ASN1_STRING_set(atmp->value.asn1_string, str, -1)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto bad_str; + } + atmp->value.asn1_string->type = utype; + if (!ASN1_TIME_check(atmp->value.asn1_string)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_TIME_VALUE); + goto bad_str; + } + + break; + + case V_ASN1_BMPSTRING: + case V_ASN1_PRINTABLESTRING: + case V_ASN1_IA5STRING: + case V_ASN1_T61STRING: + case V_ASN1_UTF8STRING: + case V_ASN1_VISIBLESTRING: + case V_ASN1_UNIVERSALSTRING: + case V_ASN1_GENERALSTRING: + case V_ASN1_NUMERICSTRING: + + if (format == ASN1_GEN_FORMAT_ASCII) + format = MBSTRING_ASC; + else if (format == ASN1_GEN_FORMAT_UTF8) + format = MBSTRING_UTF8; + else + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_FORMAT); + goto bad_form; + } + + + if (ASN1_mbstring_copy(&atmp->value.asn1_string, (unsigned char *)str, + -1, format, ASN1_tag2bit(utype)) <= 0) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto bad_str; + } + + + break; + + case V_ASN1_BIT_STRING: + + case V_ASN1_OCTET_STRING: + + if (!(atmp->value.asn1_string = ASN1_STRING_new())) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + goto bad_form; + } + + if (format == ASN1_GEN_FORMAT_HEX) + { + + if (!(rdata = string_to_hex((char *)str, &rdlen))) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_HEX); + goto bad_str; + } + + atmp->value.asn1_string->data = rdata; + atmp->value.asn1_string->length = rdlen; + atmp->value.asn1_string->type = utype; + + } + else if (format == ASN1_GEN_FORMAT_ASCII) + ASN1_STRING_set(atmp->value.asn1_string, str, -1); + else if ((format == ASN1_GEN_FORMAT_BITLIST) && (utype == V_ASN1_BIT_STRING)) + { + if (!CONF_parse_list(str, ',', 1, bitstr_cb, atmp->value.bit_string)) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_LIST_ERROR); + goto bad_str; + } + no_unused = 0; + + } + else + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_BITSTRING_FORMAT); + goto bad_form; + } + + if ((utype == V_ASN1_BIT_STRING) && no_unused) + { + atmp->value.asn1_string->flags + &= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); + atmp->value.asn1_string->flags + |= ASN1_STRING_FLAG_BITS_LEFT; + } + + + break; + + default: + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNSUPPORTED_TYPE); + goto bad_str; + break; + } + + + atmp->type = utype; + return atmp; + + + bad_str: + ERR_add_error_data(2, "string=", str); + bad_form: + + ASN1_TYPE_free(atmp); + return NULL; + + } + +static int bitstr_cb(const char *elem, int len, void *bitstr) + { + long bitnum; + char *eptr; + if (!elem) + return 0; + bitnum = strtoul(elem, &eptr, 10); + if (eptr && *eptr && (eptr != elem + len)) + return 0; + if (bitnum < 0) + { + OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_NUMBER); + return 0; + } + if (!ASN1_BIT_STRING_set_bit(bitstr, bitnum, 1)) + { + OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); + return 0; + } + return 1; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/by_dir.c b/TMessagesProj/jni/boringssl/crypto/x509/by_dir.c new file mode 100644 index 00000000..3393dfa4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/by_dir.c @@ -0,0 +1,491 @@ +/* crypto/x509/by_dir.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../internal.h" + + +typedef struct lookup_dir_hashes_st + { + unsigned long hash; + int suffix; + } BY_DIR_HASH; + +typedef struct lookup_dir_entry_st + { + char *dir; + int dir_type; + STACK_OF(BY_DIR_HASH) *hashes; + } BY_DIR_ENTRY; + +typedef struct lookup_dir_st + { + BUF_MEM *buffer; + STACK_OF(BY_DIR_ENTRY) *dirs; + } BY_DIR; + +DECLARE_STACK_OF(BY_DIR_HASH) +DECLARE_STACK_OF(BY_DIR_ENTRY) + +static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, + char **ret); +static int new_dir(X509_LOOKUP *lu); +static void free_dir(X509_LOOKUP *lu); +static int add_cert_dir(BY_DIR *ctx,const char *dir,int type); +static int get_cert_by_subject(X509_LOOKUP *xl,int type,X509_NAME *name, + X509_OBJECT *ret); +X509_LOOKUP_METHOD x509_dir_lookup= + { + "Load certs from files in a directory", + new_dir, /* new */ + free_dir, /* free */ + NULL, /* init */ + NULL, /* shutdown */ + dir_ctrl, /* ctrl */ + get_cert_by_subject, /* get_by_subject */ + NULL, /* get_by_issuer_serial */ + NULL, /* get_by_fingerprint */ + NULL, /* get_by_alias */ + }; + +X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void) + { + return(&x509_dir_lookup); + } + +static int dir_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, + char **retp) + { + int ret=0; + BY_DIR *ld; + char *dir = NULL; + + ld=(BY_DIR *)ctx->method_data; + + switch (cmd) + { + case X509_L_ADD_DIR: + if (argl == X509_FILETYPE_DEFAULT) + { + dir=(char *)getenv(X509_get_default_cert_dir_env()); + if (dir) + ret=add_cert_dir(ld,dir,X509_FILETYPE_PEM); + else + ret=add_cert_dir(ld,X509_get_default_cert_dir(), + X509_FILETYPE_PEM); + if (!ret) + { + OPENSSL_PUT_ERROR(X509, X509_R_LOADING_CERT_DIR); + } + } + else + ret=add_cert_dir(ld,argp,(int)argl); + break; + } + return(ret); + } + +static int new_dir(X509_LOOKUP *lu) + { + BY_DIR *a; + + if ((a=(BY_DIR *)OPENSSL_malloc(sizeof(BY_DIR))) == NULL) + return(0); + if ((a->buffer=BUF_MEM_new()) == NULL) + { + OPENSSL_free(a); + return(0); + } + a->dirs=NULL; + lu->method_data=(char *)a; + return(1); + } + +static void by_dir_hash_free(BY_DIR_HASH *hash) + { + OPENSSL_free(hash); + } + +static int by_dir_hash_cmp(const BY_DIR_HASH **a, + const BY_DIR_HASH **b) + { + if ((*a)->hash > (*b)->hash) + return 1; + if ((*a)->hash < (*b)->hash) + return -1; + return 0; + } + +static void by_dir_entry_free(BY_DIR_ENTRY *ent) + { + if (ent->dir) + OPENSSL_free(ent->dir); + if (ent->hashes) + sk_BY_DIR_HASH_pop_free(ent->hashes, by_dir_hash_free); + OPENSSL_free(ent); + } + +static void free_dir(X509_LOOKUP *lu) + { + BY_DIR *a; + + a=(BY_DIR *)lu->method_data; + if (a->dirs != NULL) + sk_BY_DIR_ENTRY_pop_free(a->dirs, by_dir_entry_free); + if (a->buffer != NULL) + BUF_MEM_free(a->buffer); + OPENSSL_free(a); + } + +static int add_cert_dir(BY_DIR *ctx, const char *dir, int type) + { + size_t j,len; + const char *s,*ss,*p; + + if (dir == NULL || !*dir) + { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_DIRECTORY); + return 0; + } + + s=dir; + p=s; + do + { + if ((*p == ':') || (*p == '\0')) + { + BY_DIR_ENTRY *ent; + ss=s; + s=p+1; + len=p-ss; + if (len == 0) continue; + for (j=0; j < sk_BY_DIR_ENTRY_num(ctx->dirs); j++) + { + ent = sk_BY_DIR_ENTRY_value(ctx->dirs, j); + if (strlen(ent->dir) == len && + strncmp(ent->dir,ss,len) == 0) + break; + } + if (j < sk_BY_DIR_ENTRY_num(ctx->dirs)) + continue; + if (ctx->dirs == NULL) + { + ctx->dirs = sk_BY_DIR_ENTRY_new_null(); + if (!ctx->dirs) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + } + ent = OPENSSL_malloc(sizeof(BY_DIR_ENTRY)); + if (!ent) + return 0; + ent->dir_type = type; + ent->hashes = sk_BY_DIR_HASH_new(by_dir_hash_cmp); + ent->dir = OPENSSL_malloc(len+1); + if (!ent->dir || !ent->hashes) + { + by_dir_entry_free(ent); + return 0; + } + strncpy(ent->dir,ss,len); + ent->dir[len] = '\0'; + if (!sk_BY_DIR_ENTRY_push(ctx->dirs, ent)) + { + by_dir_entry_free(ent); + return 0; + } + } + } while (*p++ != '\0'); + return 1; + } + +/* g_ent_hashes_lock protects the |hashes| member of all |BY_DIR_ENTRY| + * objects. */ +static struct CRYPTO_STATIC_MUTEX g_ent_hashes_lock = CRYPTO_STATIC_MUTEX_INIT; + +static int get_cert_by_subject(X509_LOOKUP *xl, int type, X509_NAME *name, + X509_OBJECT *ret) + { + BY_DIR *ctx; + union { + struct { + X509 st_x509; + X509_CINF st_x509_cinf; + } x509; + struct { + X509_CRL st_crl; + X509_CRL_INFO st_crl_info; + } crl; + } data; + int ok=0; + size_t i; + int j,k; + unsigned long h; + unsigned long hash_array[2]; + int hash_index; + BUF_MEM *b=NULL; + X509_OBJECT stmp,*tmp; + const char *postfix=""; + + if (name == NULL) return(0); + + stmp.type=type; + if (type == X509_LU_X509) + { + data.x509.st_x509.cert_info= &data.x509.st_x509_cinf; + data.x509.st_x509_cinf.subject=name; + stmp.data.x509= &data.x509.st_x509; + postfix=""; + } + else if (type == X509_LU_CRL) + { + data.crl.st_crl.crl= &data.crl.st_crl_info; + data.crl.st_crl_info.issuer=name; + stmp.data.crl= &data.crl.st_crl; + postfix="r"; + } + else + { + OPENSSL_PUT_ERROR(X509, X509_R_WRONG_LOOKUP_TYPE); + goto finish; + } + + if ((b=BUF_MEM_new()) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); + goto finish; + } + + ctx=(BY_DIR *)xl->method_data; + + hash_array[0]=X509_NAME_hash(name); + hash_array[1]=X509_NAME_hash_old(name); + for (hash_index=0; hash_index < 2; ++hash_index) + { + h=hash_array[hash_index]; + for (i=0; i < sk_BY_DIR_ENTRY_num(ctx->dirs); i++) + { + BY_DIR_ENTRY *ent; + size_t idx; + BY_DIR_HASH htmp, *hent; + ent = sk_BY_DIR_ENTRY_value(ctx->dirs, i); + j=strlen(ent->dir)+1+8+6+1+1; + if (!BUF_MEM_grow(b,j)) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto finish; + } + if (type == X509_LU_CRL && ent->hashes) + { + htmp.hash = h; + CRYPTO_STATIC_MUTEX_lock_read(&g_ent_hashes_lock); + if (sk_BY_DIR_HASH_find(ent->hashes, &idx, &htmp)) + { + hent = sk_BY_DIR_HASH_value(ent->hashes, idx); + k = hent->suffix; + } + else + { + hent = NULL; + k=0; + } + CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock); + } + else + { + k = 0; + hent = NULL; + } + for (;;) + { + char c = '/'; +#ifdef OPENSSL_SYS_VMS + c = ent->dir[strlen(ent->dir)-1]; + if (c != ':' && c != '>' && c != ']') + { + /* If no separator is present, we assume the + directory specifier is a logical name, and + add a colon. We really should use better + VMS routines for merging things like this, + but this will do for now... + -- Richard Levitte */ + c = ':'; + } + else + { + c = '\0'; + } +#endif + if (c == '\0') + { + /* This is special. When c == '\0', no + directory separator should be added. */ + BIO_snprintf(b->data,b->max, + "%s%08lx.%s%d",ent->dir,h, + postfix,k); + } + else + { + BIO_snprintf(b->data,b->max, + "%s%c%08lx.%s%d",ent->dir,c,h, + postfix,k); + } +#ifndef OPENSSL_NO_POSIX_IO +#ifdef _WIN32 +#define stat _stat +#endif + { + struct stat st; + if (stat(b->data,&st) < 0) + break; + } +#endif + /* found one. */ + if (type == X509_LU_X509) + { + if ((X509_load_cert_file(xl,b->data, + ent->dir_type)) == 0) + break; + } + else if (type == X509_LU_CRL) + { + if ((X509_load_crl_file(xl,b->data, + ent->dir_type)) == 0) + break; + } + /* else case will caught higher up */ + k++; + } + + /* we have added it to the cache so now pull + * it out again */ + CRYPTO_MUTEX_lock_write(&xl->store_ctx->objs_lock); + tmp = NULL; + if (sk_X509_OBJECT_find(xl->store_ctx->objs, &idx, &stmp)) { + tmp=sk_X509_OBJECT_value(xl->store_ctx->objs,idx); + } + CRYPTO_MUTEX_unlock(&xl->store_ctx->objs_lock); + + + /* If a CRL, update the last file suffix added for this */ + + if (type == X509_LU_CRL) + { + CRYPTO_STATIC_MUTEX_lock_write(&g_ent_hashes_lock); + /* Look for entry again in case another thread added + * an entry first. + */ + if (!hent) + { + htmp.hash = h; + if (sk_BY_DIR_HASH_find(ent->hashes, &idx, &htmp)) + hent = sk_BY_DIR_HASH_value(ent->hashes, idx); + } + if (!hent) + { + hent = OPENSSL_malloc(sizeof(BY_DIR_HASH)); + if (hent == NULL) + { + CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock); + ok = 0; + goto finish; + } + hent->hash = h; + hent->suffix = k; + if (!sk_BY_DIR_HASH_push(ent->hashes, hent)) + { + CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock); + OPENSSL_free(hent); + ok = 0; + goto finish; + } + } + else if (hent->suffix < k) + hent->suffix = k; + + CRYPTO_STATIC_MUTEX_unlock(&g_ent_hashes_lock); + } + + if (tmp != NULL) + { + ok=1; + ret->type=tmp->type; + memcpy(&ret->data,&tmp->data,sizeof(ret->data)); + /* If we were going to up the reference count, + * we would need to do it on a perl 'type' + * basis */ + /* CRYPTO_add(&tmp->data.x509->references,1, + CRYPTO_LOCK_X509);*/ + goto finish; + } + } + } +finish: + if (b != NULL) BUF_MEM_free(b); + return(ok); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/by_file.c b/TMessagesProj/jni/boringssl/crypto/x509/by_file.c new file mode 100644 index 00000000..f1d6194c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/by_file.c @@ -0,0 +1,295 @@ +/* crypto/x509/by_file.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include + + +#ifndef OPENSSL_NO_STDIO + +static int by_file_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, + long argl, char **ret); +X509_LOOKUP_METHOD x509_file_lookup= + { + "Load file into cache", + NULL, /* new */ + NULL, /* free */ + NULL, /* init */ + NULL, /* shutdown */ + by_file_ctrl, /* ctrl */ + NULL, /* get_by_subject */ + NULL, /* get_by_issuer_serial */ + NULL, /* get_by_fingerprint */ + NULL, /* get_by_alias */ + }; + +X509_LOOKUP_METHOD *X509_LOOKUP_file(void) + { + return(&x509_file_lookup); + } + +static int by_file_ctrl(X509_LOOKUP *ctx, int cmd, const char *argp, long argl, + char **ret) + { + int ok=0; + char *file; + + switch (cmd) + { + case X509_L_FILE_LOAD: + if (argl == X509_FILETYPE_DEFAULT) + { + file = (char *)getenv(X509_get_default_cert_file_env()); + if (file) + ok = (X509_load_cert_crl_file(ctx,file, + X509_FILETYPE_PEM) != 0); + + else + ok = (X509_load_cert_crl_file(ctx,X509_get_default_cert_file(), + X509_FILETYPE_PEM) != 0); + + if (!ok) + { + OPENSSL_PUT_ERROR(X509, X509_R_LOADING_DEFAULTS); + } + } + else + { + if(argl == X509_FILETYPE_PEM) + ok = (X509_load_cert_crl_file(ctx,argp, + X509_FILETYPE_PEM) != 0); + else + ok = (X509_load_cert_file(ctx,argp,(int)argl) != 0); + } + break; + } + return(ok); + } + +int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type) + { + int ret=0; + BIO *in=NULL; + int i,count=0; + X509 *x=NULL; + + if (file == NULL) return(1); + in=BIO_new(BIO_s_file()); + + if ((in == NULL) || (BIO_read_filename(in,file) <= 0)) + { + OPENSSL_PUT_ERROR(X509, ERR_R_SYS_LIB); + goto err; + } + + if (type == X509_FILETYPE_PEM) + { + for (;;) + { + x=PEM_read_bio_X509_AUX(in,NULL,NULL,NULL); + if (x == NULL) + { + if ((ERR_GET_REASON(ERR_peek_last_error()) == + PEM_R_NO_START_LINE) && (count > 0)) + { + ERR_clear_error(); + break; + } + else + { + OPENSSL_PUT_ERROR(X509, ERR_R_PEM_LIB); + goto err; + } + } + i=X509_STORE_add_cert(ctx->store_ctx,x); + if (!i) goto err; + count++; + X509_free(x); + x=NULL; + } + ret=count; + } + else if (type == X509_FILETYPE_ASN1) + { + x=d2i_X509_bio(in,NULL); + if (x == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_ASN1_LIB); + goto err; + } + i=X509_STORE_add_cert(ctx->store_ctx,x); + if (!i) goto err; + ret=i; + } + else + { + OPENSSL_PUT_ERROR(X509, X509_R_BAD_X509_FILETYPE); + goto err; + } +err: + if (x != NULL) X509_free(x); + if (in != NULL) BIO_free(in); + return(ret); + } + +int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type) + { + int ret=0; + BIO *in=NULL; + int i,count=0; + X509_CRL *x=NULL; + + if (file == NULL) return(1); + in=BIO_new(BIO_s_file()); + + if ((in == NULL) || (BIO_read_filename(in,file) <= 0)) + { + OPENSSL_PUT_ERROR(X509, ERR_R_SYS_LIB); + goto err; + } + + if (type == X509_FILETYPE_PEM) + { + for (;;) + { + x=PEM_read_bio_X509_CRL(in,NULL,NULL,NULL); + if (x == NULL) + { + if ((ERR_GET_REASON(ERR_peek_last_error()) == + PEM_R_NO_START_LINE) && (count > 0)) + { + ERR_clear_error(); + break; + } + else + { + OPENSSL_PUT_ERROR(X509, ERR_R_PEM_LIB); + goto err; + } + } + i=X509_STORE_add_crl(ctx->store_ctx,x); + if (!i) goto err; + count++; + X509_CRL_free(x); + x=NULL; + } + ret=count; + } + else if (type == X509_FILETYPE_ASN1) + { + x=d2i_X509_CRL_bio(in,NULL); + if (x == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_ASN1_LIB); + goto err; + } + i=X509_STORE_add_crl(ctx->store_ctx,x); + if (!i) goto err; + ret=i; + } + else + { + OPENSSL_PUT_ERROR(X509, X509_R_BAD_X509_FILETYPE); + goto err; + } +err: + if (x != NULL) X509_CRL_free(x); + if (in != NULL) BIO_free(in); + return(ret); + } + +int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type) +{ + STACK_OF(X509_INFO) *inf; + X509_INFO *itmp; + BIO *in; + size_t i; + int count = 0; + if(type != X509_FILETYPE_PEM) + return X509_load_cert_file(ctx, file, type); + in = BIO_new_file(file, "r"); + if(!in) { + OPENSSL_PUT_ERROR(X509, ERR_R_SYS_LIB); + return 0; + } + inf = PEM_X509_INFO_read_bio(in, NULL, NULL, NULL); + BIO_free(in); + if(!inf) { + OPENSSL_PUT_ERROR(X509, ERR_R_PEM_LIB); + return 0; + } + for(i = 0; i < sk_X509_INFO_num(inf); i++) { + itmp = sk_X509_INFO_value(inf, i); + if(itmp->x509) { + X509_STORE_add_cert(ctx->store_ctx, itmp->x509); + count++; + } + if(itmp->crl) { + X509_STORE_add_crl(ctx->store_ctx, itmp->crl); + count++; + } + } + sk_X509_INFO_pop_free(inf, X509_INFO_free); + return count; +} + +#endif /* OPENSSL_NO_STDIO */ diff --git a/TMessagesProj/jni/boringssl/crypto/x509/charmap.h b/TMessagesProj/jni/boringssl/crypto/x509/charmap.h new file mode 100644 index 00000000..b55e6387 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/charmap.h @@ -0,0 +1,15 @@ +/* Auto generated with chartype.pl script. + * Mask of various character properties + */ + +static const unsigned char char_type[] = { + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +120, 0, 1,40, 0, 0, 0,16,16,16, 0,25,25,16,16,16, +16,16,16,16,16,16,16,16,16,16,16, 9, 9,16, 9,16, + 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16, 0, 1, 0, 0, 0, + 0,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,16,16,16,16,16,16, 0, 0, 0, 0, 2 +}; + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/i2d_pr.c b/TMessagesProj/jni/boringssl/crypto/x509/i2d_pr.c new file mode 100644 index 00000000..e7f4269d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/i2d_pr.c @@ -0,0 +1,84 @@ +/* crypto/asn1/i2d_pr.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + +#include "../evp/internal.h" + + +int i2d_PrivateKey(const EVP_PKEY *a, unsigned char **pp) + { + if (a->ameth && a->ameth->old_priv_encode) + { + return a->ameth->old_priv_encode(a, pp); + } + if (a->ameth && a->ameth->priv_encode) { + PKCS8_PRIV_KEY_INFO *p8 = EVP_PKEY2PKCS8((EVP_PKEY*)a); + int ret = i2d_PKCS8_PRIV_KEY_INFO(p8,pp); + PKCS8_PRIV_KEY_INFO_free(p8); + return ret; + } + /* Although this file is in crypto/x509 for layering reasons, it emits + * an error code from ASN1 for OpenSSL compatibility. */ + OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE); + return -1; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/pkcs7.c b/TMessagesProj/jni/boringssl/crypto/x509/pkcs7.c new file mode 100644 index 00000000..2087f948 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/pkcs7.c @@ -0,0 +1,346 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "../bytestring/internal.h" + + +/* pkcs7_parse_header reads the non-certificate/non-CRL prefix of a PKCS#7 + * SignedData blob from |cbs| and sets |*out| to point to the rest of the + * input. If the input is in BER format, then |*der_bytes| will be set to a + * pointer that needs to be freed by the caller once they have finished + * processing |*out| (which will be pointing into |*der_bytes|). + * + * It returns one on success or zero on error. On error, |*der_bytes| is + * NULL. */ +static int pkcs7_parse_header(uint8_t **der_bytes, CBS *out, CBS *cbs) { + size_t der_len; + CBS in, content_info, content_type, wrapped_signed_data, signed_data; + uint64_t version; + + /* The input may be in BER format. */ + *der_bytes = NULL; + if (!CBS_asn1_ber_to_der(cbs, der_bytes, &der_len)) { + return 0; + } + if (*der_bytes != NULL) { + CBS_init(&in, *der_bytes, der_len); + } else { + CBS_init(&in, CBS_data(cbs), CBS_len(cbs)); + } + + /* See https://tools.ietf.org/html/rfc2315#section-7 */ + if (!CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1(&content_info, &content_type, CBS_ASN1_OBJECT)) { + goto err; + } + + if (OBJ_cbs2nid(&content_type) != NID_pkcs7_signed) { + OPENSSL_PUT_ERROR(X509, X509_R_NOT_PKCS7_SIGNED_DATA); + goto err; + } + + /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ + if (!CBS_get_asn1(&content_info, &wrapped_signed_data, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || + !CBS_get_asn1(&wrapped_signed_data, &signed_data, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1_uint64(&signed_data, &version) || + !CBS_get_asn1(&signed_data, NULL /* digests */, CBS_ASN1_SET) || + !CBS_get_asn1(&signed_data, NULL /* content */, CBS_ASN1_SEQUENCE)) { + goto err; + } + + if (version < 1) { + OPENSSL_PUT_ERROR(X509, X509_R_BAD_PKCS7_VERSION); + goto err; + } + + CBS_init(out, CBS_data(&signed_data), CBS_len(&signed_data)); + return 1; + +err: + if (*der_bytes) { + OPENSSL_free(*der_bytes); + *der_bytes = NULL; + } + + return 0; +} + +int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs) { + CBS signed_data, certificates; + uint8_t *der_bytes = NULL; + int ret = 0; + const size_t initial_certs_len = sk_X509_num(out_certs); + + if (!pkcs7_parse_header(&der_bytes, &signed_data, cbs)) { + return 0; + } + + /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ + if (!CBS_get_asn1(&signed_data, &certificates, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { + OPENSSL_PUT_ERROR(X509, X509_R_NO_CERTIFICATES_INCLUDED); + goto err; + } + + while (CBS_len(&certificates) > 0) { + CBS cert; + X509 *x509; + const uint8_t *inp; + + if (!CBS_get_asn1_element(&certificates, &cert, CBS_ASN1_SEQUENCE)) { + goto err; + } + + inp = CBS_data(&cert); + x509 = d2i_X509(NULL, &inp, CBS_len(&cert)); + if (!x509) { + goto err; + } + + assert(inp == CBS_data(&cert) + CBS_len(&cert)); + + if (sk_X509_push(out_certs, x509) == 0) { + X509_free(x509); + goto err; + } + } + + ret = 1; + +err: + if (der_bytes) { + OPENSSL_free(der_bytes); + } + + if (!ret) { + while (sk_X509_num(out_certs) != initial_certs_len) { + X509 *x509 = sk_X509_pop(out_certs); + X509_free(x509); + } + } + + return ret; +} + +int PKCS7_get_CRLs(STACK_OF(X509_CRL) *out_crls, CBS *cbs) { + CBS signed_data, crls; + uint8_t *der_bytes = NULL; + int ret = 0; + const size_t initial_crls_len = sk_X509_CRL_num(out_crls); + + if (!pkcs7_parse_header(&der_bytes, &signed_data, cbs)) { + return 0; + } + + /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ + + /* Even if only CRLs are included, there may be an empty certificates block. + * OpenSSL does this, for example. */ + if (CBS_peek_asn1_tag(&signed_data, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) && + !CBS_get_asn1(&signed_data, NULL /* certificates */, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { + goto err; + } + + if (!CBS_get_asn1(&signed_data, &crls, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)) { + OPENSSL_PUT_ERROR(X509, X509_R_NO_CRLS_INCLUDED); + goto err; + } + + while (CBS_len(&crls) > 0) { + CBS crl_data; + X509_CRL *crl; + const uint8_t *inp; + + if (!CBS_get_asn1_element(&crls, &crl_data, CBS_ASN1_SEQUENCE)) { + goto err; + } + + inp = CBS_data(&crl_data); + crl = d2i_X509_CRL(NULL, &inp, CBS_len(&crl_data)); + if (!crl) { + goto err; + } + + assert(inp == CBS_data(&crl_data) + CBS_len(&crl_data)); + + if (sk_X509_CRL_push(out_crls, crl) == 0) { + X509_CRL_free(crl); + goto err; + } + } + + ret = 1; + +err: + if (der_bytes) { + OPENSSL_free(der_bytes); + } + + if (!ret) { + while (sk_X509_CRL_num(out_crls) != initial_crls_len) { + X509_CRL_free(sk_X509_CRL_pop(out_crls)); + } + } + + return ret; +} + +int PKCS7_get_PEM_certificates(STACK_OF(X509) *out_certs, BIO *pem_bio) { + uint8_t *data; + long len; + int ret; + + /* Even though we pass PEM_STRING_PKCS7 as the expected PEM type here, PEM + * internally will actually allow several other values too, including + * "CERTIFICATE". */ + if (!PEM_bytes_read_bio(&data, &len, NULL /* PEM type output */, + PEM_STRING_PKCS7, pem_bio, + NULL /* password callback */, + NULL /* password callback argument */)) { + return 0; + } + + CBS cbs; + CBS_init(&cbs, data, len); + ret = PKCS7_get_certificates(out_certs, &cbs); + OPENSSL_free(data); + return ret; +} + +int PKCS7_get_PEM_CRLs(STACK_OF(X509_CRL) *out_crls, BIO *pem_bio) { + uint8_t *data; + long len; + int ret; + + /* Even though we pass PEM_STRING_PKCS7 as the expected PEM type here, PEM + * internally will actually allow several other values too, including + * "CERTIFICATE". */ + if (!PEM_bytes_read_bio(&data, &len, NULL /* PEM type output */, + PEM_STRING_PKCS7, pem_bio, + NULL /* password callback */, + NULL /* password callback argument */)) { + return 0; + } + + CBS cbs; + CBS_init(&cbs, data, len); + ret = PKCS7_get_CRLs(out_crls, &cbs); + OPENSSL_free(data); + return ret; +} + +/* pkcs7_bundle writes a PKCS#7, SignedData structure to |out| and then calls + * |cb| with a CBB to which certificate or CRL data can be written, and the + * opaque context pointer, |arg|. The callback can return zero to indicate an + * error. + * + * pkcs7_bundle returns one on success or zero on error. */ +static int pkcs7_bundle(CBB *out, int (*cb)(CBB *out, const void *arg), + const void *arg) { + CBB outer_seq, wrapped_seq, seq, version_bytes, digest_algos_set, + content_info; + + /* See https://tools.ietf.org/html/rfc2315#section-7 */ + if (!CBB_add_asn1(out, &outer_seq, CBS_ASN1_SEQUENCE) || + !OBJ_nid2cbb(&outer_seq, NID_pkcs7_signed) || + !CBB_add_asn1(&outer_seq, &wrapped_seq, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) || + /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ + !CBB_add_asn1(&wrapped_seq, &seq, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&seq, &version_bytes, CBS_ASN1_INTEGER) || + !CBB_add_u8(&version_bytes, 1) || + !CBB_add_asn1(&seq, &digest_algos_set, CBS_ASN1_SET) || + !CBB_add_asn1(&seq, &content_info, CBS_ASN1_SEQUENCE) || + !OBJ_nid2cbb(&content_info, NID_pkcs7_data) || + !cb(&seq, arg)) { + return 0; + } + + return CBB_flush(out); +} + +static int pkcs7_bundle_certificates_cb(CBB *out, const void *arg) { + const STACK_OF(X509) *certs = arg; + size_t i; + CBB certificates; + + /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ + if (!CBB_add_asn1(out, &certificates, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) { + return 0; + } + + for (i = 0; i < sk_X509_num(certs); i++) { + X509 *x509 = sk_X509_value(certs, i); + uint8_t *buf; + int len = i2d_X509(x509, NULL); + + if (len < 0 || + !CBB_add_space(&certificates, &buf, len) || + i2d_X509(x509, &buf) < 0) { + return 0; + } + } + + return CBB_flush(out); +} + +int PKCS7_bundle_certificates(CBB *out, const STACK_OF(X509) *certs) { + return pkcs7_bundle(out, pkcs7_bundle_certificates_cb, certs); +} + +static int pkcs7_bundle_crls_cb(CBB *out, const void *arg) { + const STACK_OF(X509_CRL) *crls = arg; + size_t i; + CBB crl_data; + + /* See https://tools.ietf.org/html/rfc2315#section-9.1 */ + if (!CBB_add_asn1(out, &crl_data, + CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)) { + return 0; + } + + for (i = 0; i < sk_X509_CRL_num(crls); i++) { + X509_CRL *crl = sk_X509_CRL_value(crls, i); + uint8_t *buf; + int len = i2d_X509_CRL(crl, NULL); + + if (len < 0 || + !CBB_add_space(&crl_data, &buf, len) || + i2d_X509_CRL(crl, &buf) < 0) { + return 0; + } + } + + return CBB_flush(out); +} + +int PKCS7_bundle_CRLs(CBB *out, const STACK_OF(X509_CRL) *crls) { + return pkcs7_bundle(out, pkcs7_bundle_crls_cb, crls); +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/t_crl.c b/TMessagesProj/jni/boringssl/crypto/x509/t_crl.c new file mode 100644 index 00000000..a2d8bc74 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/t_crl.c @@ -0,0 +1,129 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include + + +#ifndef OPENSSL_NO_FP_API +int X509_CRL_print_fp(FILE *fp, X509_CRL *x) + { + BIO *b; + int ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=X509_CRL_print(b, x); + BIO_free(b); + return(ret); + } +#endif + +int X509_CRL_print(BIO *out, X509_CRL *x) +{ + STACK_OF(X509_REVOKED) *rev; + X509_REVOKED *r; + long l; + size_t i; + char *p; + + BIO_printf(out, "Certificate Revocation List (CRL):\n"); + l = X509_CRL_get_version(x); + BIO_printf(out, "%8sVersion %lu (0x%lx)\n", "", l+1, l); + X509_signature_print(out, x->sig_alg, NULL); + p=X509_NAME_oneline(X509_CRL_get_issuer(x),NULL,0); + BIO_printf(out,"%8sIssuer: %s\n","",p); + OPENSSL_free(p); + BIO_printf(out,"%8sLast Update: ",""); + ASN1_TIME_print(out,X509_CRL_get_lastUpdate(x)); + BIO_printf(out,"\n%8sNext Update: ",""); + if (X509_CRL_get_nextUpdate(x)) + ASN1_TIME_print(out,X509_CRL_get_nextUpdate(x)); + else BIO_printf(out,"NONE"); + BIO_printf(out,"\n"); + + X509V3_extensions_print(out, "CRL extensions", + x->crl->extensions, 0, 8); + + rev = X509_CRL_get_REVOKED(x); + + if(sk_X509_REVOKED_num(rev) > 0) + BIO_printf(out, "Revoked Certificates:\n"); + else BIO_printf(out, "No Revoked Certificates.\n"); + + for(i = 0; i < sk_X509_REVOKED_num(rev); i++) { + r = sk_X509_REVOKED_value(rev, i); + BIO_printf(out," Serial Number: "); + i2a_ASN1_INTEGER(out,r->serialNumber); + BIO_printf(out,"\n Revocation Date: "); + ASN1_TIME_print(out,r->revocationDate); + BIO_printf(out,"\n"); + X509V3_extensions_print(out, "CRL entry extensions", + r->extensions, 0, 8); + } + X509_signature_print(out, x->sig_alg, x->signature); + + return 1; + +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/t_req.c b/TMessagesProj/jni/boringssl/crypto/x509/t_req.c new file mode 100644 index 00000000..39c836cc --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/t_req.c @@ -0,0 +1,246 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include +#include + + +int X509_REQ_print_fp(FILE *fp, X509_REQ *x) { + BIO *bio = BIO_new(BIO_s_file()); + if (bio == NULL) { + OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); + return 0; + } + + BIO_set_fp(bio, fp, BIO_NOCLOSE); + int ret = X509_REQ_print(bio, x); + BIO_free(bio); + return ret; +} + +int X509_REQ_print_ex(BIO *bio, X509_REQ *x, unsigned long nmflags, + unsigned long cflag) { + long l; + EVP_PKEY *pkey; + STACK_OF(X509_ATTRIBUTE) * sk; + char mlch = ' '; + + int nmindent = 0; + + if ((nmflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) { + mlch = '\n'; + nmindent = 12; + } + + if (nmflags == X509_FLAG_COMPAT) { + nmindent = 16; + } + + X509_REQ_INFO *ri = x->req_info; + if (!(cflag & X509_FLAG_NO_HEADER)) { + if (BIO_write(bio, "Certificate Request:\n", 21) <= 0 || + BIO_write(bio, " Data:\n", 10) <= 0) { + goto err; + } + } + if (!(cflag & X509_FLAG_NO_VERSION)) { + l = X509_REQ_get_version(x); + if (BIO_printf(bio, "%8sVersion: %ld (0x%lx)\n", "", l + 1, l) <= 0) { + goto err; + } + } + if (!(cflag & X509_FLAG_NO_SUBJECT)) { + if (BIO_printf(bio, " Subject:%c", mlch) <= 0 || + X509_NAME_print_ex(bio, ri->subject, nmindent, nmflags) < 0 || + BIO_write(bio, "\n", 1) <= 0) { + goto err; + } + } + if (!(cflag & X509_FLAG_NO_PUBKEY)) { + if (BIO_write(bio, " Subject Public Key Info:\n", 33) <= 0 || + BIO_printf(bio, "%12sPublic Key Algorithm: ", "") <= 0 || + i2a_ASN1_OBJECT(bio, ri->pubkey->algor->algorithm) <= 0 || + BIO_puts(bio, "\n") <= 0) { + goto err; + } + + pkey = X509_REQ_get_pubkey(x); + if (pkey == NULL) { + BIO_printf(bio, "%12sUnable to load Public Key\n", ""); + ERR_print_errors(bio); + } else { + EVP_PKEY_print_public(bio, pkey, 16, NULL); + EVP_PKEY_free(pkey); + } + } + + if (!(cflag & X509_FLAG_NO_ATTRIBUTES)) { + if (BIO_printf(bio, "%8sAttributes:\n", "") <= 0) { + goto err; + } + + sk = x->req_info->attributes; + if (sk_X509_ATTRIBUTE_num(sk) == 0) { + if (BIO_printf(bio, "%12sa0:00\n", "") <= 0) { + goto err; + } + } else { + size_t i; + for (i = 0; i < sk_X509_ATTRIBUTE_num(sk); i++) { + X509_ATTRIBUTE *a = sk_X509_ATTRIBUTE_value(sk, i); + ASN1_OBJECT *aobj = X509_ATTRIBUTE_get0_object(a); + + if (X509_REQ_extension_nid(OBJ_obj2nid(aobj))) { + continue; + } + + if (BIO_printf(bio, "%12s", "") <= 0) { + goto err; + } + + const int num_attrs = X509_ATTRIBUTE_count(a); + const int obj_str_len = i2a_ASN1_OBJECT(bio, aobj); + if (obj_str_len <= 0) { + if (BIO_puts(bio, "(Unable to print attribute ID.)\n") < 0) { + goto err; + } else { + continue; + } + } + + int j; + for (j = 0; j < num_attrs; j++) { + const ASN1_TYPE *at = X509_ATTRIBUTE_get0_type(a, j); + const int type = at->type; + ASN1_BIT_STRING *bs = at->value.asn1_string; + + int k; + for (k = 25 - obj_str_len; k > 0; k--) { + if (BIO_write(bio, " ", 1) != 1) { + goto err; + } + } + + if (BIO_puts(bio, ":") <= 0) { + goto err; + } + + if (type == V_ASN1_PRINTABLESTRING || + type == V_ASN1_UTF8STRING || + type == V_ASN1_IA5STRING || + type == V_ASN1_T61STRING) { + if (BIO_write(bio, (char *)bs->data, bs->length) != bs->length) { + goto err; + } + BIO_puts(bio, "\n"); + } else { + BIO_puts(bio, "unable to print attribute\n"); + } + } + } + } + } + + if (!(cflag & X509_FLAG_NO_EXTENSIONS)) { + STACK_OF(X509_EXTENSION) *exts = X509_REQ_get_extensions(x); + if (exts) { + BIO_printf(bio, "%8sRequested Extensions:\n", ""); + + size_t i; + for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { + X509_EXTENSION *ex = sk_X509_EXTENSION_value(exts, i); + if (BIO_printf(bio, "%12s", "") <= 0) { + goto err; + } + ASN1_OBJECT *obj = X509_EXTENSION_get_object(ex); + i2a_ASN1_OBJECT(bio, obj); + const int is_critical = X509_EXTENSION_get_critical(ex); + if (BIO_printf(bio, ": %s\n", is_critical ? "critical" : "") <= 0) { + goto err; + } + if (!X509V3_EXT_print(bio, ex, cflag, 16)) { + BIO_printf(bio, "%16s", ""); + ASN1_STRING_print(bio, X509_EXTENSION_get_data(ex)); + } + if (BIO_write(bio, "\n", 1) <= 0) { + goto err; + } + } + sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); + } + } + + if (!(cflag & X509_FLAG_NO_SIGDUMP) && + !X509_signature_print(bio, x->sig_alg, x->signature)) { + goto err; + } + + return 1; + +err: + OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); + return 0; +} + +int X509_REQ_print(BIO *bio, X509_REQ *req) { + return X509_REQ_print_ex(bio, req, XN_FLAG_COMPAT, X509_FLAG_COMPAT); +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/t_x509.c b/TMessagesProj/jni/boringssl/crypto/x509/t_x509.c new file mode 100644 index 00000000..7785ebff --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/t_x509.c @@ -0,0 +1,500 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../evp/internal.h" + +#ifndef OPENSSL_NO_FP_API +int X509_print_ex_fp(FILE *fp, X509 *x, unsigned long nmflag, unsigned long cflag) + { + BIO *b; + int ret; + + if ((b=BIO_new(BIO_s_file())) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); + return(0); + } + BIO_set_fp(b,fp,BIO_NOCLOSE); + ret=X509_print_ex(b, x, nmflag, cflag); + BIO_free(b); + return(ret); + } + +int X509_print_fp(FILE *fp, X509 *x) + { + return X509_print_ex_fp(fp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT); + } +#endif + +int X509_print(BIO *bp, X509 *x) +{ + return X509_print_ex(bp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT); +} + +int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags, unsigned long cflag) + { + long l; + int ret=0,i; + char *m=NULL,mlch = ' '; + int nmindent = 0; + X509_CINF *ci; + ASN1_INTEGER *bs; + EVP_PKEY *pkey=NULL; + const char *neg; + + if((nmflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) { + mlch = '\n'; + nmindent = 12; + } + + if(nmflags == X509_FLAG_COMPAT) + nmindent = 16; + + ci=x->cert_info; + if(!(cflag & X509_FLAG_NO_HEADER)) + { + if (BIO_write(bp,"Certificate:\n",13) <= 0) goto err; + if (BIO_write(bp," Data:\n",10) <= 0) goto err; + } + if(!(cflag & X509_FLAG_NO_VERSION)) + { + l=X509_get_version(x); + if (BIO_printf(bp,"%8sVersion: %lu (0x%lx)\n","",l+1,l) <= 0) goto err; + } + if(!(cflag & X509_FLAG_NO_SERIAL)) + { + + if (BIO_write(bp," Serial Number:",22) <= 0) goto err; + + bs=X509_get_serialNumber(x); + if (bs->length <= (int)sizeof(long)) + { + l=ASN1_INTEGER_get(bs); + if (bs->type == V_ASN1_NEG_INTEGER) + { + l= -l; + neg="-"; + } + else + neg=""; + if (BIO_printf(bp," %s%lu (%s0x%lx)\n",neg,l,neg,l) <= 0) + goto err; + } + else + { + neg=(bs->type == V_ASN1_NEG_INTEGER)?" (Negative)":""; + if (BIO_printf(bp,"\n%12s%s","",neg) <= 0) goto err; + + for (i=0; ilength; i++) + { + if (BIO_printf(bp,"%02x%c",bs->data[i], + ((i+1 == bs->length)?'\n':':')) <= 0) + goto err; + } + } + + } + + if(!(cflag & X509_FLAG_NO_SIGNAME)) + { + if (X509_signature_print(bp, ci->signature, NULL) <= 0) + goto err; + } + + if(!(cflag & X509_FLAG_NO_ISSUER)) + { + if (BIO_printf(bp," Issuer:%c",mlch) <= 0) goto err; + if (X509_NAME_print_ex(bp,X509_get_issuer_name(x),nmindent, nmflags) < 0) goto err; + if (BIO_write(bp,"\n",1) <= 0) goto err; + } + if(!(cflag & X509_FLAG_NO_VALIDITY)) + { + if (BIO_write(bp," Validity\n",17) <= 0) goto err; + if (BIO_write(bp," Not Before: ",24) <= 0) goto err; + if (!ASN1_TIME_print(bp,X509_get_notBefore(x))) goto err; + if (BIO_write(bp,"\n Not After : ",25) <= 0) goto err; + if (!ASN1_TIME_print(bp,X509_get_notAfter(x))) goto err; + if (BIO_write(bp,"\n",1) <= 0) goto err; + } + if(!(cflag & X509_FLAG_NO_SUBJECT)) + { + if (BIO_printf(bp," Subject:%c",mlch) <= 0) goto err; + if (X509_NAME_print_ex(bp,X509_get_subject_name(x),nmindent, nmflags) < 0) goto err; + if (BIO_write(bp,"\n",1) <= 0) goto err; + } + if(!(cflag & X509_FLAG_NO_PUBKEY)) + { + if (BIO_write(bp," Subject Public Key Info:\n",33) <= 0) + goto err; + if (BIO_printf(bp,"%12sPublic Key Algorithm: ","") <= 0) + goto err; + if (i2a_ASN1_OBJECT(bp, ci->key->algor->algorithm) <= 0) + goto err; + if (BIO_puts(bp, "\n") <= 0) + goto err; + + pkey=X509_get_pubkey(x); + if (pkey == NULL) + { + BIO_printf(bp,"%12sUnable to load Public Key\n",""); + BIO_print_errors(bp); + } + else + { + EVP_PKEY_print_public(bp, pkey, 16, NULL); + EVP_PKEY_free(pkey); + } + } + + if(!(cflag & X509_FLAG_NO_IDS)) + { + if (ci->issuerUID) + { + if (BIO_printf(bp,"%8sIssuer Unique ID: ","") <= 0) + goto err; + if (!X509_signature_dump(bp, ci->issuerUID, 12)) + goto err; + } + if (ci->subjectUID) + { + if (BIO_printf(bp,"%8sSubject Unique ID: ","") <= 0) + goto err; + if (!X509_signature_dump(bp, ci->subjectUID, 12)) + goto err; + } + } + + if (!(cflag & X509_FLAG_NO_EXTENSIONS)) + X509V3_extensions_print(bp, "X509v3 extensions", + ci->extensions, cflag, 8); + + if(!(cflag & X509_FLAG_NO_SIGDUMP)) + { + if(X509_signature_print(bp, x->sig_alg, x->signature) <= 0) goto err; + } + if(!(cflag & X509_FLAG_NO_AUX)) + { + if (!X509_CERT_AUX_print(bp, x->aux, 0)) goto err; + } + ret=1; +err: + if (m != NULL) OPENSSL_free(m); + return(ret); + } + +int X509_ocspid_print (BIO *bp, X509 *x) + { + unsigned char *der=NULL ; + unsigned char *dertmp; + int derlen; + int i; + unsigned char SHA1md[SHA_DIGEST_LENGTH]; + + /* display the hash of the subject as it would appear + in OCSP requests */ + if (BIO_printf(bp," Subject OCSP hash: ") <= 0) + goto err; + derlen = i2d_X509_NAME(x->cert_info->subject, NULL); + if ((der = dertmp = (unsigned char *)OPENSSL_malloc (derlen)) == NULL) + goto err; + i2d_X509_NAME(x->cert_info->subject, &dertmp); + + if (!EVP_Digest(der, derlen, SHA1md, NULL, EVP_sha1(), NULL)) + goto err; + for (i=0; i < SHA_DIGEST_LENGTH; i++) + { + if (BIO_printf(bp,"%02X",SHA1md[i]) <= 0) goto err; + } + OPENSSL_free (der); + der=NULL; + + /* display the hash of the public key as it would appear + in OCSP requests */ + if (BIO_printf(bp,"\n Public key OCSP hash: ") <= 0) + goto err; + + if (!EVP_Digest(x->cert_info->key->public_key->data, + x->cert_info->key->public_key->length, + SHA1md, NULL, EVP_sha1(), NULL)) + goto err; + for (i=0; i < SHA_DIGEST_LENGTH; i++) + { + if (BIO_printf(bp,"%02X",SHA1md[i]) <= 0) + goto err; + } + BIO_printf(bp,"\n"); + + return (1); +err: + if (der != NULL) OPENSSL_free(der); + return(0); + } + +int X509_signature_print(BIO *bp, X509_ALGOR *sigalg, ASN1_STRING *sig) +{ + int sig_nid; + if (BIO_puts(bp," Signature Algorithm: ") <= 0) return 0; + if (i2a_ASN1_OBJECT(bp, sigalg->algorithm) <= 0) return 0; + + sig_nid = OBJ_obj2nid(sigalg->algorithm); + if (sig_nid != NID_undef) + { + int pkey_nid, dig_nid; + const EVP_PKEY_ASN1_METHOD *ameth; + if (OBJ_find_sigid_algs(sig_nid, &dig_nid, &pkey_nid)) + { + ameth = EVP_PKEY_asn1_find(NULL, pkey_nid); + if (ameth && ameth->sig_print) + return ameth->sig_print(bp, sigalg, sig, 9, 0); + } + } + if (sig) + return X509_signature_dump(bp, sig, 9); + else if (BIO_puts(bp, "\n") <= 0) + return 0; + return 1; +} + +int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v) + { + int i,n; + char buf[80]; + const char *p; + + if (v == NULL) return(0); + n=0; + p=(const char *)v->data; + for (i=0; ilength; i++) + { + if ((p[i] > '~') || ((p[i] < ' ') && + (p[i] != '\n') && (p[i] != '\r'))) + buf[n]='.'; + else + buf[n]=p[i]; + n++; + if (n >= 80) + { + if (BIO_write(bp,buf,n) <= 0) + return(0); + n=0; + } + } + if (n > 0) + if (BIO_write(bp,buf,n) <= 0) + return(0); + return(1); + } + +int ASN1_TIME_print(BIO *bp, const ASN1_TIME *tm) +{ + if(tm->type == V_ASN1_UTCTIME) return ASN1_UTCTIME_print(bp, tm); + if(tm->type == V_ASN1_GENERALIZEDTIME) + return ASN1_GENERALIZEDTIME_print(bp, tm); + BIO_write(bp,"Bad time value",14); + return(0); +} + +static const char *const mon[12]= + { + "Jan","Feb","Mar","Apr","May","Jun", + "Jul","Aug","Sep","Oct","Nov","Dec" + }; + +int ASN1_GENERALIZEDTIME_print(BIO *bp, const ASN1_GENERALIZEDTIME *tm) + { + char *v; + int gmt=0; + int i; + int y=0,M=0,d=0,h=0,m=0,s=0; + char *f = NULL; + int f_len = 0; + + i=tm->length; + v=(char *)tm->data; + + if (i < 12) goto err; + if (v[i-1] == 'Z') gmt=1; + for (i=0; i<12; i++) + if ((v[i] > '9') || (v[i] < '0')) goto err; + y= (v[0]-'0')*1000+(v[1]-'0')*100 + (v[2]-'0')*10+(v[3]-'0'); + M= (v[4]-'0')*10+(v[5]-'0'); + if ((M > 12) || (M < 1)) goto err; + d= (v[6]-'0')*10+(v[7]-'0'); + h= (v[8]-'0')*10+(v[9]-'0'); + m= (v[10]-'0')*10+(v[11]-'0'); + if (tm->length >= 14 && + (v[12] >= '0') && (v[12] <= '9') && + (v[13] >= '0') && (v[13] <= '9')) + { + s= (v[12]-'0')*10+(v[13]-'0'); + /* Check for fractions of seconds. */ + if (tm->length >= 15 && v[14] == '.') + { + int l = tm->length; + f = &v[14]; /* The decimal point. */ + f_len = 1; + while (14 + f_len < l && f[f_len] >= '0' && f[f_len] <= '9') + ++f_len; + } + } + + if (BIO_printf(bp,"%s %2d %02d:%02d:%02d%.*s %d%s", + mon[M-1],d,h,m,s,f_len,f,y,(gmt)?" GMT":"") <= 0) + return(0); + else + return(1); +err: + BIO_write(bp,"Bad time value",14); + return(0); + } + +int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm) + { + const char *v; + int gmt=0; + int i; + int y=0,M=0,d=0,h=0,m=0,s=0; + + i=tm->length; + v=(const char *)tm->data; + + if (i < 10) goto err; + if (v[i-1] == 'Z') gmt=1; + for (i=0; i<10; i++) + if ((v[i] > '9') || (v[i] < '0')) goto err; + y= (v[0]-'0')*10+(v[1]-'0'); + if (y < 50) y+=100; + M= (v[2]-'0')*10+(v[3]-'0'); + if ((M > 12) || (M < 1)) goto err; + d= (v[4]-'0')*10+(v[5]-'0'); + h= (v[6]-'0')*10+(v[7]-'0'); + m= (v[8]-'0')*10+(v[9]-'0'); + if (tm->length >=12 && + (v[10] >= '0') && (v[10] <= '9') && + (v[11] >= '0') && (v[11] <= '9')) + s= (v[10]-'0')*10+(v[11]-'0'); + + if (BIO_printf(bp,"%s %2d %02d:%02d:%02d %d%s", + mon[M-1],d,h,m,s,y+1900,(gmt)?" GMT":"") <= 0) + return(0); + else + return(1); +err: + BIO_write(bp,"Bad time value",14); + return(0); + } + +int X509_NAME_print(BIO *bp, X509_NAME *name, int obase) + { + char *s,*c,*b; + int ret=0,l,i; + + l=80-2-obase; + + b=X509_NAME_oneline(name,NULL,0); + if (!b) + return 0; + if (!*b) + { + OPENSSL_free(b); + return 1; + } + s=b+1; /* skip the first slash */ + + c=s; + for (;;) + { + if ( ((*s == '/') && + ((s[1] >= 'A') && (s[1] <= 'Z') && ( + (s[2] == '=') || + ((s[2] >= 'A') && (s[2] <= 'Z') && + (s[3] == '=')) + ))) || + (*s == '\0')) + { + i=s-c; + if (BIO_write(bp,c,i) != i) goto err; + c=s+1; /* skip following slash */ + if (*s != '\0') + { + if (BIO_write(bp,", ",2) != 2) goto err; + } + l--; + } + if (*s == '\0') break; + s++; + l--; + } + + ret=1; + if (0) + { +err: + OPENSSL_PUT_ERROR(X509, ERR_R_BUF_LIB); + } + OPENSSL_free(b); + return(ret); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/t_x509a.c b/TMessagesProj/jni/boringssl/crypto/x509/t_x509a.c new file mode 100644 index 00000000..76672688 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/t_x509a.c @@ -0,0 +1,109 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include + + +/* X509_CERT_AUX and string set routines */ + +int X509_CERT_AUX_print(BIO *out, X509_CERT_AUX *aux, int indent) +{ + char oidstr[80], first; + size_t i; + int j; + if(!aux) return 1; + if(aux->trust) { + first = 1; + BIO_printf(out, "%*sTrusted Uses:\n%*s", + indent, "", indent + 2, ""); + for(i = 0; i < sk_ASN1_OBJECT_num(aux->trust); i++) { + if(!first) BIO_puts(out, ", "); + else first = 0; + OBJ_obj2txt(oidstr, sizeof oidstr, + sk_ASN1_OBJECT_value(aux->trust, i), 0); + BIO_puts(out, oidstr); + } + BIO_puts(out, "\n"); + } else BIO_printf(out, "%*sNo Trusted Uses.\n", indent, ""); + if(aux->reject) { + first = 1; + BIO_printf(out, "%*sRejected Uses:\n%*s", + indent, "", indent + 2, ""); + for(i = 0; i < sk_ASN1_OBJECT_num(aux->reject); i++) { + if(!first) BIO_puts(out, ", "); + else first = 0; + OBJ_obj2txt(oidstr, sizeof oidstr, + sk_ASN1_OBJECT_value(aux->reject, i), 0); + BIO_puts(out, oidstr); + } + BIO_puts(out, "\n"); + } else BIO_printf(out, "%*sNo Rejected Uses.\n", indent, ""); + if(aux->alias) BIO_printf(out, "%*sAlias: %s\n", indent, "", + aux->alias->data); + if(aux->keyid) { + BIO_printf(out, "%*sKey Id: ", indent, ""); + for(j = 0; j < aux->keyid->length; j++) + BIO_printf(out, "%s%02X", + j ? ":" : "", + aux->keyid->data[j]); + BIO_write(out,"\n",1); + } + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/vpm_int.h b/TMessagesProj/jni/boringssl/crypto/x509/vpm_int.h new file mode 100644 index 00000000..9edbd5ad --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/vpm_int.h @@ -0,0 +1,70 @@ +/* vpm_int.h */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2013. + */ +/* ==================================================================== + * Copyright (c) 2013 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +/* internal only structure to hold additional X509_VERIFY_PARAM data */ + +struct X509_VERIFY_PARAM_ID_st + { + STACK_OF(OPENSSL_STRING) *hosts; /* Set of acceptable names */ + unsigned int hostflags; /* Flags to control matching features */ + char *peername; /* Matching hostname in peer certificate */ + char *email; /* If not NULL email address to match */ + size_t emaillen; + unsigned char *ip; /* If not NULL IP address to match */ + size_t iplen; /* Length of IP address */ + }; diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509.c b/TMessagesProj/jni/boringssl/crypto/x509/x509.c new file mode 100644 index 00000000..31f9e1eb --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509.c @@ -0,0 +1,152 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj, int version, + int ptype, void *pval, uint8_t *penc, int penclen) { + uint8_t **ppenc = NULL; + if (version >= 0) { + if (!ASN1_INTEGER_set(priv->version, version)) { + return 0; + } + } + + if (penc) { + int pmtype; + ASN1_OCTET_STRING *oct; + + oct = ASN1_OCTET_STRING_new(); + if (!oct) { + return 0; + } + oct->data = penc; + ppenc = &oct->data; + oct->length = penclen; + if (priv->broken == PKCS8_NO_OCTET) { + pmtype = V_ASN1_SEQUENCE; + } else { + pmtype = V_ASN1_OCTET_STRING; + } + ASN1_TYPE_set(priv->pkey, pmtype, oct); + } + + if (!X509_ALGOR_set0(priv->pkeyalg, aobj, ptype, pval)) { + /* If call fails do not swallow 'enc' */ + if (ppenc) { + *ppenc = NULL; + } + return 0; + } + + return 1; +} + +int PKCS8_pkey_get0(ASN1_OBJECT **ppkalg, const uint8_t **pk, int *ppklen, + X509_ALGOR **pa, PKCS8_PRIV_KEY_INFO *p8) { + if (ppkalg) { + *ppkalg = p8->pkeyalg->algorithm; + } + + if (p8->pkey->type == V_ASN1_OCTET_STRING) { + p8->broken = PKCS8_OK; + if (pk) { + *pk = p8->pkey->value.octet_string->data; + *ppklen = p8->pkey->value.octet_string->length; + } + } else if (p8->pkey->type == V_ASN1_SEQUENCE) { + p8->broken = PKCS8_NO_OCTET; + if (pk) { + *pk = p8->pkey->value.sequence->data; + *ppklen = p8->pkey->value.sequence->length; + } + } else { + return 0; + } + + if (pa) { + *pa = p8->pkeyalg; + } + return 1; +} + +int X509_signature_dump(BIO *bp, const ASN1_STRING *sig, int indent) { + const uint8_t *s; + int i, n; + + n = sig->length; + s = sig->data; + for (i = 0; i < n; i++) { + if ((i % 18) == 0) { + if (BIO_write(bp, "\n", 1) <= 0 || + BIO_indent(bp, indent, indent) <= 0) { + return 0; + } + } + if (BIO_printf(bp, "%02x%s", s[i], ((i + 1) == n) ? "" : ":") <= 0) { + return 0; + } + } + if (BIO_write(bp, "\n", 1) != 1) { + return 0; + } + + return 1; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_att.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_att.c new file mode 100644 index 00000000..14914849 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_att.c @@ -0,0 +1,353 @@ +/* crypto/x509/x509_att.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include + + +int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x) +{ + return sk_X509_ATTRIBUTE_num(x); +} + +int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid, + int lastpos) +{ + const ASN1_OBJECT *obj; + + obj=OBJ_nid2obj(nid); + if (obj == NULL) return(-2); + return(X509at_get_attr_by_OBJ(x,obj,lastpos)); +} + +int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, const ASN1_OBJECT *obj, + int lastpos) +{ + int n; + X509_ATTRIBUTE *ex; + + if (sk == NULL) return(-1); + lastpos++; + if (lastpos < 0) + lastpos=0; + n=sk_X509_ATTRIBUTE_num(sk); + for ( ; lastpos < n; lastpos++) + { + ex=sk_X509_ATTRIBUTE_value(sk,lastpos); + if (OBJ_cmp(ex->object,obj) == 0) + return(lastpos); + } + return(-1); +} + +X509_ATTRIBUTE *X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc) +{ + if (x == NULL || loc < 0 || sk_X509_ATTRIBUTE_num(x) <= (size_t) loc) + return NULL; + else + return sk_X509_ATTRIBUTE_value(x,loc); +} + +X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc) +{ + X509_ATTRIBUTE *ret; + + if (x == NULL || loc < 0 || sk_X509_ATTRIBUTE_num(x) <= (size_t) loc) + return(NULL); + ret=sk_X509_ATTRIBUTE_delete(x,loc); + return(ret); +} + +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, + X509_ATTRIBUTE *attr) +{ + X509_ATTRIBUTE *new_attr=NULL; + STACK_OF(X509_ATTRIBUTE) *sk=NULL; + + if (x == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER); + goto err2; + } + + if (*x == NULL) + { + if ((sk=sk_X509_ATTRIBUTE_new_null()) == NULL) + goto err; + } + else + sk= *x; + + if ((new_attr=X509_ATTRIBUTE_dup(attr)) == NULL) + goto err2; + if (!sk_X509_ATTRIBUTE_push(sk,new_attr)) + goto err; + if (*x == NULL) + *x=sk; + return(sk); +err: + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); +err2: + if (new_attr != NULL) X509_ATTRIBUTE_free(new_attr); + if (sk != NULL) sk_X509_ATTRIBUTE_free(sk); + return(NULL); +} + +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len) +{ + X509_ATTRIBUTE *attr; + STACK_OF(X509_ATTRIBUTE) *ret; + attr = X509_ATTRIBUTE_create_by_OBJ(NULL, obj, type, bytes, len); + if(!attr) return 0; + ret = X509at_add1_attr(x, attr); + X509_ATTRIBUTE_free(attr); + return ret; +} + +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x, + int nid, int type, + const unsigned char *bytes, int len) +{ + X509_ATTRIBUTE *attr; + STACK_OF(X509_ATTRIBUTE) *ret; + attr = X509_ATTRIBUTE_create_by_NID(NULL, nid, type, bytes, len); + if(!attr) return 0; + ret = X509at_add1_attr(x, attr); + X509_ATTRIBUTE_free(attr); + return ret; +} + +STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x, + const char *attrname, int type, + const unsigned char *bytes, int len) +{ + X509_ATTRIBUTE *attr; + STACK_OF(X509_ATTRIBUTE) *ret; + attr = X509_ATTRIBUTE_create_by_txt(NULL, attrname, type, bytes, len); + if(!attr) return 0; + ret = X509at_add1_attr(x, attr); + X509_ATTRIBUTE_free(attr); + return ret; +} + +void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x, + ASN1_OBJECT *obj, int lastpos, int type) +{ + int i; + X509_ATTRIBUTE *at; + i = X509at_get_attr_by_OBJ(x, obj, lastpos); + if (i == -1) + return NULL; + if ((lastpos <= -2) && (X509at_get_attr_by_OBJ(x, obj, i) != -1)) + return NULL; + at = X509at_get_attr(x, i); + if (lastpos <= -3 && (X509_ATTRIBUTE_count(at) != 1)) + return NULL; + return X509_ATTRIBUTE_get0_data(at, 0, type, NULL); +} + +X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid, + int atrtype, const void *data, int len) +{ + const ASN1_OBJECT *obj; + + obj=OBJ_nid2obj(nid); + if (obj == NULL) + { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_NID); + return(NULL); + } + return X509_ATTRIBUTE_create_by_OBJ(attr,obj,atrtype,data,len); +} + +X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr, + const ASN1_OBJECT *obj, int atrtype, const void *data, int len) +{ + X509_ATTRIBUTE *ret; + + if ((attr == NULL) || (*attr == NULL)) + { + if ((ret=X509_ATTRIBUTE_new()) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return(NULL); + } + } + else + ret= *attr; + + if (!X509_ATTRIBUTE_set1_object(ret,obj)) + goto err; + if (!X509_ATTRIBUTE_set1_data(ret,atrtype,data,len)) + goto err; + + if ((attr != NULL) && (*attr == NULL)) *attr=ret; + return(ret); +err: + if ((attr == NULL) || (ret != *attr)) + X509_ATTRIBUTE_free(ret); + return(NULL); +} + +X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr, + const char *atrname, int type, const unsigned char *bytes, int len) + { + ASN1_OBJECT *obj; + X509_ATTRIBUTE *nattr; + + obj=OBJ_txt2obj(atrname, 0); + if (obj == NULL) + { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_FIELD_NAME); + ERR_add_error_data(2, "name=", atrname); + return(NULL); + } + nattr = X509_ATTRIBUTE_create_by_OBJ(attr,obj,type,bytes,len); + ASN1_OBJECT_free(obj); + return nattr; + } + +int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj) +{ + if ((attr == NULL) || (obj == NULL)) + return(0); + ASN1_OBJECT_free(attr->object); + attr->object=OBJ_dup(obj); + return attr->object != NULL; +} + +int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, const void *data, int len) +{ + ASN1_TYPE *ttmp; + ASN1_STRING *stmp = NULL; + int atype = 0; + if (!attr) return 0; + if(attrtype & MBSTRING_FLAG) { + stmp = ASN1_STRING_set_by_NID(NULL, data, len, attrtype, + OBJ_obj2nid(attr->object)); + if(!stmp) { + OPENSSL_PUT_ERROR(X509, ERR_R_ASN1_LIB); + return 0; + } + atype = stmp->type; + } else if (len != -1){ + if(!(stmp = ASN1_STRING_type_new(attrtype))) goto err; + if(!ASN1_STRING_set(stmp, data, len)) goto err; + atype = attrtype; + } + if(!(attr->value.set = sk_ASN1_TYPE_new_null())) goto err; + attr->single = 0; + /* This is a bit naughty because the attribute should really have + * at least one value but some types use and zero length SET and + * require this. + */ + if (attrtype == 0) + return 1; + if(!(ttmp = ASN1_TYPE_new())) goto err; + if ((len == -1) && !(attrtype & MBSTRING_FLAG)) + { + if (!ASN1_TYPE_set1(ttmp, attrtype, data)) + goto err; + } + else + ASN1_TYPE_set(ttmp, atype, stmp); + if(!sk_ASN1_TYPE_push(attr->value.set, ttmp)) goto err; + return 1; + err: + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; +} + +int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr) +{ + if(!attr->single) return sk_ASN1_TYPE_num(attr->value.set); + if(attr->value.single) return 1; + return 0; +} + +ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr) +{ + if (attr == NULL) return(NULL); + return(attr->object); +} + +void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx, + int atrtype, void *data) +{ + ASN1_TYPE *ttmp; + ttmp = X509_ATTRIBUTE_get0_type(attr, idx); + if(!ttmp) return NULL; + if(atrtype != ASN1_TYPE_get(ttmp)){ + OPENSSL_PUT_ERROR(X509, X509_R_WRONG_TYPE); + return NULL; + } + return ttmp->value.ptr; +} + +ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx) +{ + if (attr == NULL) return(NULL); + if(idx >= X509_ATTRIBUTE_count(attr)) return NULL; + if(!attr->single) return sk_ASN1_TYPE_value(attr->value.set, idx); + else return attr->value.single; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_cmp.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_cmp.c new file mode 100644 index 00000000..0e35f3ea --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_cmp.c @@ -0,0 +1,490 @@ +/* crypto/x509/x509_cmp.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b) + { + int i; + X509_CINF *ai,*bi; + + ai=a->cert_info; + bi=b->cert_info; + i=M_ASN1_INTEGER_cmp(ai->serialNumber,bi->serialNumber); + if (i) return(i); + return(X509_NAME_cmp(ai->issuer,bi->issuer)); + } + +unsigned long X509_issuer_and_serial_hash(X509 *a) + { + unsigned long ret=0; + EVP_MD_CTX ctx; + unsigned char md[16]; + char *f; + + EVP_MD_CTX_init(&ctx); + f=X509_NAME_oneline(a->cert_info->issuer,NULL,0); + if (!EVP_DigestInit_ex(&ctx, EVP_md5(), NULL)) + goto err; + if (!EVP_DigestUpdate(&ctx,(unsigned char *)f,strlen(f))) + goto err; + OPENSSL_free(f); + if(!EVP_DigestUpdate(&ctx,(unsigned char *)a->cert_info->serialNumber->data, + (unsigned long)a->cert_info->serialNumber->length)) + goto err; + if (!EVP_DigestFinal_ex(&ctx,&(md[0]),NULL)) + goto err; + ret=( ((unsigned long)md[0] )|((unsigned long)md[1]<<8L)| + ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L) + )&0xffffffffL; + err: + EVP_MD_CTX_cleanup(&ctx); + return(ret); + } + +int X509_issuer_name_cmp(const X509 *a, const X509 *b) + { + return(X509_NAME_cmp(a->cert_info->issuer,b->cert_info->issuer)); + } + +int X509_subject_name_cmp(const X509 *a, const X509 *b) + { + return(X509_NAME_cmp(a->cert_info->subject,b->cert_info->subject)); + } + +int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b) + { + return(X509_NAME_cmp(a->crl->issuer,b->crl->issuer)); + } + +int X509_CRL_match(const X509_CRL *a, const X509_CRL *b) + { + return memcmp(a->sha1_hash, b->sha1_hash, 20); + } + +X509_NAME *X509_get_issuer_name(X509 *a) + { + return(a->cert_info->issuer); + } + +unsigned long X509_issuer_name_hash(X509 *x) + { + return(X509_NAME_hash(x->cert_info->issuer)); + } + +unsigned long X509_issuer_name_hash_old(X509 *x) + { + return(X509_NAME_hash_old(x->cert_info->issuer)); + } + +X509_NAME *X509_get_subject_name(X509 *a) + { + return(a->cert_info->subject); + } + +ASN1_INTEGER *X509_get_serialNumber(X509 *a) + { + return(a->cert_info->serialNumber); + } + +unsigned long X509_subject_name_hash(X509 *x) + { + return(X509_NAME_hash(x->cert_info->subject)); + } + +unsigned long X509_subject_name_hash_old(X509 *x) + { + return(X509_NAME_hash_old(x->cert_info->subject)); + } + +/* Compare two certificates: they must be identical for + * this to work. NB: Although "cmp" operations are generally + * prototyped to take "const" arguments (eg. for use in + * STACKs), the way X509 handling is - these operations may + * involve ensuring the hashes are up-to-date and ensuring + * certain cert information is cached. So this is the point + * where the "depth-first" constification tree has to halt + * with an evil cast. + */ +int X509_cmp(const X509 *a, const X509 *b) +{ + int rv; + /* ensure hash is valid */ + X509_check_purpose((X509 *)a, -1, 0); + X509_check_purpose((X509 *)b, -1, 0); + + rv = memcmp(a->sha1_hash, b->sha1_hash, SHA_DIGEST_LENGTH); + if (rv) + return rv; + /* Check for match against stored encoding too */ + if (!a->cert_info->enc.modified && !b->cert_info->enc.modified) + { + rv = (int)(a->cert_info->enc.len - b->cert_info->enc.len); + if (rv) + return rv; + return memcmp(a->cert_info->enc.enc, b->cert_info->enc.enc, + a->cert_info->enc.len); + } + return rv; +} + + +int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b) + { + int ret; + + /* Ensure canonical encoding is present and up to date */ + + if (!a->canon_enc || a->modified) + { + ret = i2d_X509_NAME((X509_NAME *)a, NULL); + if (ret < 0) + return -2; + } + + if (!b->canon_enc || b->modified) + { + ret = i2d_X509_NAME((X509_NAME *)b, NULL); + if (ret < 0) + return -2; + } + + ret = a->canon_enclen - b->canon_enclen; + + if (ret) + return ret; + + return memcmp(a->canon_enc, b->canon_enc, a->canon_enclen); + + } + +unsigned long X509_NAME_hash(X509_NAME *x) + { + unsigned long ret=0; + unsigned char md[SHA_DIGEST_LENGTH]; + + /* Make sure X509_NAME structure contains valid cached encoding */ + i2d_X509_NAME(x,NULL); + if (!EVP_Digest(x->canon_enc, x->canon_enclen, md, NULL, EVP_sha1(), + NULL)) + return 0; + + ret=( ((unsigned long)md[0] )|((unsigned long)md[1]<<8L)| + ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L) + )&0xffffffffL; + return(ret); + } + + +/* I now DER encode the name and hash it. Since I cache the DER encoding, + * this is reasonably efficient. */ + +unsigned long X509_NAME_hash_old(X509_NAME *x) + { + EVP_MD_CTX md_ctx; + unsigned long ret=0; + unsigned char md[16]; + + /* Make sure X509_NAME structure contains valid cached encoding */ + i2d_X509_NAME(x,NULL); + EVP_MD_CTX_init(&md_ctx); + /* EVP_MD_CTX_set_flags(&md_ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); */ + if (EVP_DigestInit_ex(&md_ctx, EVP_md5(), NULL) + && EVP_DigestUpdate(&md_ctx, x->bytes->data, x->bytes->length) + && EVP_DigestFinal_ex(&md_ctx,md,NULL)) + ret=(((unsigned long)md[0] )|((unsigned long)md[1]<<8L)| + ((unsigned long)md[2]<<16L)|((unsigned long)md[3]<<24L) + )&0xffffffffL; + EVP_MD_CTX_cleanup(&md_ctx); + + return(ret); + } + +/* Search a stack of X509 for a match */ +X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk, X509_NAME *name, + ASN1_INTEGER *serial) + { + size_t i; + X509_CINF cinf; + X509 x,*x509=NULL; + + if(!sk) return NULL; + + x.cert_info= &cinf; + cinf.serialNumber=serial; + cinf.issuer=name; + + for (i=0; icert_info == NULL)) + return(NULL); + return(X509_PUBKEY_get(x->cert_info->key)); + } + +ASN1_BIT_STRING *X509_get0_pubkey_bitstr(const X509 *x) + { + if(!x) return NULL; + return x->cert_info->key->public_key; + } + + +int X509_check_private_key(X509 *x, EVP_PKEY *k) + { + EVP_PKEY *xk; + int ret; + + xk=X509_get_pubkey(x); + + if (xk) + ret = EVP_PKEY_cmp(xk, k); + else + ret = -2; + + switch (ret) + { + case 1: + break; + case 0: + OPENSSL_PUT_ERROR(X509, X509_R_KEY_VALUES_MISMATCH); + break; + case -1: + OPENSSL_PUT_ERROR(X509, X509_R_KEY_TYPE_MISMATCH); + break; + case -2: + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE); + } + if (xk) + EVP_PKEY_free(xk); + if (ret > 0) + return 1; + return 0; + } + +/* Check a suite B algorithm is permitted: pass in a public key and + * the NID of its signature (or 0 if no signature). The pflags is + * a pointer to a flags field which must contain the suite B verification + * flags. + */ + + +static int check_suite_b(EVP_PKEY *pkey, int sign_nid, unsigned long *pflags) + { + const EC_GROUP *grp = NULL; + int curve_nid; + if (pkey && pkey->type == EVP_PKEY_EC) + grp = EC_KEY_get0_group(pkey->pkey.ec); + if (!grp) + return X509_V_ERR_SUITE_B_INVALID_ALGORITHM; + curve_nid = EC_GROUP_get_curve_name(grp); + /* Check curve is consistent with LOS */ + if (curve_nid == NID_secp384r1) /* P-384 */ + { + /* Check signature algorithm is consistent with + * curve. + */ + if (sign_nid != -1 && sign_nid != NID_ecdsa_with_SHA384) + return X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM; + if (!(*pflags & X509_V_FLAG_SUITEB_192_LOS)) + return X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED; + /* If we encounter P-384 we cannot use P-256 later */ + *pflags &= ~X509_V_FLAG_SUITEB_128_LOS_ONLY; + } + else if (curve_nid == NID_X9_62_prime256v1) /* P-256 */ + { + if (sign_nid != -1 && sign_nid != NID_ecdsa_with_SHA256) + return X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM; + if (!(*pflags & X509_V_FLAG_SUITEB_128_LOS_ONLY)) + return X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED; + } + else + return X509_V_ERR_SUITE_B_INVALID_CURVE; + + return X509_V_OK; + } + +int X509_chain_check_suiteb(int *perror_depth, X509 *x, STACK_OF(X509) *chain, + unsigned long flags) + { + int rv, sign_nid; + size_t i; + EVP_PKEY *pk = NULL; + unsigned long tflags; + if (!(flags & X509_V_FLAG_SUITEB_128_LOS)) + return X509_V_OK; + tflags = flags; + /* If no EE certificate passed in must be first in chain */ + if (x == NULL) + { + x = sk_X509_value(chain, 0); + i = 1; + } + else + i = 0; + + if (X509_get_version(x) != 2) + { + rv = X509_V_ERR_SUITE_B_INVALID_VERSION; + /* Correct error depth */ + i = 0; + goto end; + } + + pk = X509_get_pubkey(x); + /* Check EE key only */ + rv = check_suite_b(pk, -1, &tflags); + if (rv != X509_V_OK) + { + /* Correct error depth */ + i = 0; + goto end; + } + for(; i < sk_X509_num(chain); i++) + { + sign_nid = X509_get_signature_nid(x); + x = sk_X509_value(chain, i); + if (X509_get_version(x) != 2) + { + rv = X509_V_ERR_SUITE_B_INVALID_VERSION; + goto end; + } + EVP_PKEY_free(pk); + pk = X509_get_pubkey(x); + rv = check_suite_b(pk, sign_nid, &tflags); + if (rv != X509_V_OK) + goto end; + } + + /* Final check: root CA signature */ + rv = check_suite_b(pk, X509_get_signature_nid(x), &tflags); + end: + if (pk) + EVP_PKEY_free(pk); + if (rv != X509_V_OK) + { + /* Invalid signature or LOS errors are for previous cert */ + if ((rv == X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM + || rv == X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED) && i) + i--; + /* If we have LOS error and flags changed then we are signing + * P-384 with P-256. Use more meaninggul error. + */ + if (rv == X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED && flags != tflags) + rv = X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256; + if (perror_depth) + *perror_depth = i; + } + return rv; + } + +int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, unsigned long flags) + { + int sign_nid; + if (!(flags & X509_V_FLAG_SUITEB_128_LOS)) + return X509_V_OK; + sign_nid = OBJ_obj2nid(crl->crl->sig_alg->algorithm); + return check_suite_b(pk, sign_nid, &flags); + } + +/* Not strictly speaking an "up_ref" as a STACK doesn't have a reference + * count but it has the same effect by duping the STACK and upping the ref + * of each X509 structure. + */ +STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain) + { + STACK_OF(X509) *ret; + size_t i; + ret = sk_X509_dup(chain); + for (i = 0; i < sk_X509_num(ret); i++) + { + X509_up_ref(sk_X509_value(ret, i)); + } + return ret; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_d2.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_d2.c new file mode 100644 index 00000000..2161d851 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_d2.c @@ -0,0 +1,105 @@ +/* crypto/x509/x509_d2.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include + + +#ifndef OPENSSL_NO_STDIO +int X509_STORE_set_default_paths(X509_STORE *ctx) + { + X509_LOOKUP *lookup; + + lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_file()); + if (lookup == NULL) return(0); + X509_LOOKUP_load_file(lookup,NULL,X509_FILETYPE_DEFAULT); + + lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_hash_dir()); + if (lookup == NULL) return(0); + X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT); + + /* clear any errors */ + ERR_clear_error(); + + return(1); + } + +int X509_STORE_load_locations(X509_STORE *ctx, const char *file, + const char *path) + { + X509_LOOKUP *lookup; + + if (file != NULL) + { + lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_file()); + if (lookup == NULL) return(0); + if (X509_LOOKUP_load_file(lookup,file,X509_FILETYPE_PEM) != 1) + return(0); + } + if (path != NULL) + { + lookup=X509_STORE_add_lookup(ctx,X509_LOOKUP_hash_dir()); + if (lookup == NULL) return(0); + if (X509_LOOKUP_add_dir(lookup,path,X509_FILETYPE_PEM) != 1) + return(0); + } + if ((path == NULL) && (file == NULL)) + return(0); + return(1); + } + +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_def.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_def.c new file mode 100644 index 00000000..dbae289f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_def.c @@ -0,0 +1,88 @@ +/* crypto/x509/x509_def.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + + +/* TODO(fork): cleanup */ + +#define OPENSSLDIR "/etc/ssl" +#define X509_CERT_AREA OPENSSLDIR +#define X509_CERT_DIR OPENSSLDIR "/certs" +#define X509_CERT_FILE OPENSSLDIR "/cert.pem" +#define X509_PRIVATE_DIR OPENSSLDIR "/private" +#define X509_CERT_DIR_EVP "SSL_CERT_DIR" +#define X509_CERT_FILE_EVP "SSL_CERT_FILE" + +const char *X509_get_default_private_dir(void) + { return(X509_PRIVATE_DIR); } + +const char *X509_get_default_cert_area(void) + { return(X509_CERT_AREA); } + +const char *X509_get_default_cert_dir(void) + { return(X509_CERT_DIR); } + +const char *X509_get_default_cert_file(void) + { return(X509_CERT_FILE); } + +const char *X509_get_default_cert_dir_env(void) + { return(X509_CERT_DIR_EVP); } + +const char *X509_get_default_cert_file_env(void) + { return(X509_CERT_FILE_EVP); } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_ext.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_ext.c new file mode 100644 index 00000000..2f1e0c5a --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_ext.c @@ -0,0 +1,206 @@ +/* crypto/x509/x509_ext.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include + + +int X509_CRL_get_ext_count(X509_CRL *x) + { + return(X509v3_get_ext_count(x->crl->extensions)); + } + +int X509_CRL_get_ext_by_NID(X509_CRL *x, int nid, int lastpos) + { + return(X509v3_get_ext_by_NID(x->crl->extensions,nid,lastpos)); + } + +int X509_CRL_get_ext_by_OBJ(X509_CRL *x, ASN1_OBJECT *obj, int lastpos) + { + return(X509v3_get_ext_by_OBJ(x->crl->extensions,obj,lastpos)); + } + +int X509_CRL_get_ext_by_critical(X509_CRL *x, int crit, int lastpos) + { + return(X509v3_get_ext_by_critical(x->crl->extensions,crit,lastpos)); + } + +X509_EXTENSION *X509_CRL_get_ext(X509_CRL *x, int loc) + { + return(X509v3_get_ext(x->crl->extensions,loc)); + } + +X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc) + { + return(X509v3_delete_ext(x->crl->extensions,loc)); + } + +void *X509_CRL_get_ext_d2i(X509_CRL *x, int nid, int *crit, int *idx) +{ + return X509V3_get_d2i(x->crl->extensions, nid, crit, idx); +} + +int X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value, int crit, + unsigned long flags) +{ + return X509V3_add1_i2d(&x->crl->extensions, nid, value, crit, flags); +} + +int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc) + { + return(X509v3_add_ext(&(x->crl->extensions),ex,loc) != NULL); + } + +int X509_get_ext_count(X509 *x) + { + return(X509v3_get_ext_count(x->cert_info->extensions)); + } + +int X509_get_ext_by_NID(X509 *x, int nid, int lastpos) + { + return(X509v3_get_ext_by_NID(x->cert_info->extensions,nid,lastpos)); + } + +int X509_get_ext_by_OBJ(X509 *x, ASN1_OBJECT *obj, int lastpos) + { + return(X509v3_get_ext_by_OBJ(x->cert_info->extensions,obj,lastpos)); + } + +int X509_get_ext_by_critical(X509 *x, int crit, int lastpos) + { + return(X509v3_get_ext_by_critical(x->cert_info->extensions,crit,lastpos)); + } + +X509_EXTENSION *X509_get_ext(X509 *x, int loc) + { + return(X509v3_get_ext(x->cert_info->extensions,loc)); + } + +X509_EXTENSION *X509_delete_ext(X509 *x, int loc) + { + return(X509v3_delete_ext(x->cert_info->extensions,loc)); + } + +int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc) + { + return(X509v3_add_ext(&(x->cert_info->extensions),ex,loc) != NULL); + } + +void *X509_get_ext_d2i(X509 *x, int nid, int *crit, int *idx) +{ + return X509V3_get_d2i(x->cert_info->extensions, nid, crit, idx); +} + +int X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit, + unsigned long flags) +{ + return X509V3_add1_i2d(&x->cert_info->extensions, nid, value, crit, + flags); +} + +int X509_REVOKED_get_ext_count(X509_REVOKED *x) + { + return(X509v3_get_ext_count(x->extensions)); + } + +int X509_REVOKED_get_ext_by_NID(X509_REVOKED *x, int nid, int lastpos) + { + return(X509v3_get_ext_by_NID(x->extensions,nid,lastpos)); + } + +int X509_REVOKED_get_ext_by_OBJ(X509_REVOKED *x, ASN1_OBJECT *obj, + int lastpos) + { + return(X509v3_get_ext_by_OBJ(x->extensions,obj,lastpos)); + } + +int X509_REVOKED_get_ext_by_critical(X509_REVOKED *x, int crit, int lastpos) + { + return(X509v3_get_ext_by_critical(x->extensions,crit,lastpos)); + } + +X509_EXTENSION *X509_REVOKED_get_ext(X509_REVOKED *x, int loc) + { + return(X509v3_get_ext(x->extensions,loc)); + } + +X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, int loc) + { + return(X509v3_delete_ext(x->extensions,loc)); + } + +int X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex, int loc) + { + return(X509v3_add_ext(&(x->extensions),ex,loc) != NULL); + } + +void *X509_REVOKED_get_ext_d2i(X509_REVOKED *x, int nid, int *crit, int *idx) +{ + return X509V3_get_d2i(x->extensions, nid, crit, idx); +} + +int X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid, void *value, int crit, + unsigned long flags) +{ + return X509V3_add1_i2d(&x->extensions, nid, value, crit, flags); +} + +IMPLEMENT_ASN1_SET_OF(X509_EXTENSION) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_lu.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_lu.c new file mode 100644 index 00000000..aa2f5e54 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_lu.c @@ -0,0 +1,732 @@ +/* crypto/x509/x509_lu.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "../internal.h" + + +X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method) + { + X509_LOOKUP *ret; + + ret=(X509_LOOKUP *)OPENSSL_malloc(sizeof(X509_LOOKUP)); + if (ret == NULL) return NULL; + + ret->init=0; + ret->skip=0; + ret->method=method; + ret->method_data=NULL; + ret->store_ctx=NULL; + if ((method->new_item != NULL) && !method->new_item(ret)) + { + OPENSSL_free(ret); + return NULL; + } + return ret; + } + +void X509_LOOKUP_free(X509_LOOKUP *ctx) + { + if (ctx == NULL) return; + if ( (ctx->method != NULL) && + (ctx->method->free != NULL)) + (*ctx->method->free)(ctx); + OPENSSL_free(ctx); + } + +int X509_LOOKUP_init(X509_LOOKUP *ctx) + { + if (ctx->method == NULL) return 0; + if (ctx->method->init != NULL) + return ctx->method->init(ctx); + else + return 1; + } + +int X509_LOOKUP_shutdown(X509_LOOKUP *ctx) + { + if (ctx->method == NULL) return 0; + if (ctx->method->shutdown != NULL) + return ctx->method->shutdown(ctx); + else + return 1; + } + +int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, long argl, + char **ret) + { + if (ctx->method == NULL) return -1; + if (ctx->method->ctrl != NULL) + return ctx->method->ctrl(ctx,cmd,argc,argl,ret); + else + return 1; + } + +int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name, + X509_OBJECT *ret) + { + if ((ctx->method == NULL) || (ctx->method->get_by_subject == NULL)) + return X509_LU_FAIL; + if (ctx->skip) return 0; + return ctx->method->get_by_subject(ctx,type,name,ret); + } + +int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, int type, X509_NAME *name, + ASN1_INTEGER *serial, X509_OBJECT *ret) + { + if ((ctx->method == NULL) || + (ctx->method->get_by_issuer_serial == NULL)) + return X509_LU_FAIL; + return ctx->method->get_by_issuer_serial(ctx,type,name,serial,ret); + } + +int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type, + unsigned char *bytes, int len, X509_OBJECT *ret) + { + if ((ctx->method == NULL) || (ctx->method->get_by_fingerprint == NULL)) + return X509_LU_FAIL; + return ctx->method->get_by_fingerprint(ctx,type,bytes,len,ret); + } + +int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, int type, char *str, int len, + X509_OBJECT *ret) + { + if ((ctx->method == NULL) || (ctx->method->get_by_alias == NULL)) + return X509_LU_FAIL; + return ctx->method->get_by_alias(ctx,type,str,len,ret); + } + + +static int x509_object_cmp(const X509_OBJECT **a, const X509_OBJECT **b) + { + int ret; + + ret=((*a)->type - (*b)->type); + if (ret) return ret; + switch ((*a)->type) + { + case X509_LU_X509: + ret=X509_subject_name_cmp((*a)->data.x509,(*b)->data.x509); + break; + case X509_LU_CRL: + ret=X509_CRL_cmp((*a)->data.crl,(*b)->data.crl); + break; + default: + /* abort(); */ + return 0; + } + return ret; + } + +X509_STORE *X509_STORE_new(void) + { + X509_STORE *ret; + + if ((ret=(X509_STORE *)OPENSSL_malloc(sizeof(X509_STORE))) == NULL) + return NULL; + memset(ret, 0, sizeof(*ret)); + ret->objs = sk_X509_OBJECT_new(x509_object_cmp); + CRYPTO_MUTEX_init(&ret->objs_lock); + ret->cache = 1; + ret->get_cert_methods = sk_X509_LOOKUP_new_null(); + + if ((ret->param = X509_VERIFY_PARAM_new()) == NULL) + goto err; + + ret->references = 1; + return ret; +err: + if (ret) + { + if (ret->param) + X509_VERIFY_PARAM_free(ret->param); + if (ret->get_cert_methods) + sk_X509_LOOKUP_free(ret->get_cert_methods); + if (ret->objs) + sk_X509_OBJECT_free(ret->objs); + OPENSSL_free(ret); + } + return NULL; + } + +static void cleanup(X509_OBJECT *a) + { + if (a->type == X509_LU_X509) + { + X509_free(a->data.x509); + } + else if (a->type == X509_LU_CRL) + { + X509_CRL_free(a->data.crl); + } + else + { + /* abort(); */ + } + + OPENSSL_free(a); + } + +void X509_STORE_free(X509_STORE *vfy) + { + size_t j; + STACK_OF(X509_LOOKUP) *sk; + X509_LOOKUP *lu; + + if (vfy == NULL) + return; + + if (!CRYPTO_refcount_dec_and_test_zero(&vfy->references)) { + return; + } + + CRYPTO_MUTEX_cleanup(&vfy->objs_lock); + + sk=vfy->get_cert_methods; + for (j=0; jobjs, cleanup); + + if (vfy->param) + X509_VERIFY_PARAM_free(vfy->param); + OPENSSL_free(vfy); + } + +X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m) + { + size_t i; + STACK_OF(X509_LOOKUP) *sk; + X509_LOOKUP *lu; + + sk=v->get_cert_methods; + for (i=0; imethod) + { + return lu; + } + } + /* a new one */ + lu=X509_LOOKUP_new(m); + if (lu == NULL) + return NULL; + else + { + lu->store_ctx=v; + if (sk_X509_LOOKUP_push(v->get_cert_methods,lu)) + return lu; + else + { + X509_LOOKUP_free(lu); + return NULL; + } + } + } + +int X509_STORE_get_by_subject(X509_STORE_CTX *vs, int type, X509_NAME *name, + X509_OBJECT *ret) + { + X509_STORE *ctx=vs->ctx; + X509_LOOKUP *lu; + X509_OBJECT stmp,*tmp; + int i,j; + + CRYPTO_MUTEX_lock_write(&ctx->objs_lock); + tmp=X509_OBJECT_retrieve_by_subject(ctx->objs,type,name); + CRYPTO_MUTEX_unlock(&ctx->objs_lock); + + if (tmp == NULL || type == X509_LU_CRL) + { + for (i=vs->current_method; i<(int)sk_X509_LOOKUP_num(ctx->get_cert_methods); i++) + { + lu=sk_X509_LOOKUP_value(ctx->get_cert_methods,i); + j=X509_LOOKUP_by_subject(lu,type,name,&stmp); + if (j < 0) + { + vs->current_method=j; + return j; + } + else if (j) + { + tmp= &stmp; + break; + } + } + vs->current_method=0; + if (tmp == NULL) + return 0; + } + +/* if (ret->data.ptr != NULL) + X509_OBJECT_free_contents(ret); */ + + ret->type=tmp->type; + ret->data.ptr=tmp->data.ptr; + + X509_OBJECT_up_ref_count(ret); + + return 1; + } + +int X509_STORE_add_cert(X509_STORE *ctx, X509 *x) + { + X509_OBJECT *obj; + int ret=1; + + if (x == NULL) return 0; + obj=(X509_OBJECT *)OPENSSL_malloc(sizeof(X509_OBJECT)); + if (obj == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + obj->type=X509_LU_X509; + obj->data.x509=x; + + CRYPTO_MUTEX_lock_write(&ctx->objs_lock); + + X509_OBJECT_up_ref_count(obj); + + if (X509_OBJECT_retrieve_match(ctx->objs, obj)) + { + X509_OBJECT_free_contents(obj); + OPENSSL_free(obj); + OPENSSL_PUT_ERROR(X509, X509_R_CERT_ALREADY_IN_HASH_TABLE); + ret=0; + } + else sk_X509_OBJECT_push(ctx->objs, obj); + + CRYPTO_MUTEX_unlock(&ctx->objs_lock); + + return ret; + } + +int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x) + { + X509_OBJECT *obj; + int ret=1; + + if (x == NULL) return 0; + obj=(X509_OBJECT *)OPENSSL_malloc(sizeof(X509_OBJECT)); + if (obj == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + obj->type=X509_LU_CRL; + obj->data.crl=x; + + CRYPTO_MUTEX_lock_write(&ctx->objs_lock); + + X509_OBJECT_up_ref_count(obj); + + if (X509_OBJECT_retrieve_match(ctx->objs, obj)) + { + X509_OBJECT_free_contents(obj); + OPENSSL_free(obj); + OPENSSL_PUT_ERROR(X509, X509_R_CERT_ALREADY_IN_HASH_TABLE); + ret=0; + } + else sk_X509_OBJECT_push(ctx->objs, obj); + + CRYPTO_MUTEX_unlock(&ctx->objs_lock); + + return ret; + } + +void X509_OBJECT_up_ref_count(X509_OBJECT *a) + { + switch (a->type) + { + case X509_LU_X509: + X509_up_ref(a->data.x509); + break; + case X509_LU_CRL: + CRYPTO_refcount_inc(&a->data.crl->references); + break; + } + } + +void X509_OBJECT_free_contents(X509_OBJECT *a) + { + switch (a->type) + { + case X509_LU_X509: + X509_free(a->data.x509); + break; + case X509_LU_CRL: + X509_CRL_free(a->data.crl); + break; + } + } + +static int x509_object_idx_cnt(STACK_OF(X509_OBJECT) *h, int type, + X509_NAME *name, int *pnmatch) + { + X509_OBJECT stmp; + X509 x509_s; + X509_CINF cinf_s; + X509_CRL crl_s; + X509_CRL_INFO crl_info_s; + size_t idx; + + stmp.type=type; + switch (type) + { + case X509_LU_X509: + stmp.data.x509= &x509_s; + x509_s.cert_info= &cinf_s; + cinf_s.subject=name; + break; + case X509_LU_CRL: + stmp.data.crl= &crl_s; + crl_s.crl= &crl_info_s; + crl_info_s.issuer=name; + break; + default: + /* abort(); */ + return -1; + } + + idx = -1; + if (sk_X509_OBJECT_find(h, &idx, &stmp) && pnmatch) + { + int tidx; + const X509_OBJECT *tobj, *pstmp; + *pnmatch = 1; + pstmp = &stmp; + for (tidx = idx + 1; tidx < (int)sk_X509_OBJECT_num(h); tidx++) + { + tobj = sk_X509_OBJECT_value(h, tidx); + if (x509_object_cmp(&tobj, &pstmp)) + break; + (*pnmatch)++; + } + } + + return idx; + } + + +int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type, + X509_NAME *name) + { + return x509_object_idx_cnt(h, type, name, NULL); + } + +X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h, int type, + X509_NAME *name) + { + int idx; + idx = X509_OBJECT_idx_by_subject(h, type, name); + if (idx==-1) return NULL; + return sk_X509_OBJECT_value(h, idx); + } + +STACK_OF(X509)* X509_STORE_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm) + { + int i, idx, cnt; + STACK_OF(X509) *sk; + X509 *x; + X509_OBJECT *obj; + sk = sk_X509_new_null(); + CRYPTO_MUTEX_lock_write(&ctx->ctx->objs_lock); + idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_X509, nm, &cnt); + if (idx < 0) + { + /* Nothing found in cache: do lookup to possibly add new + * objects to cache + */ + X509_OBJECT xobj; + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + if (!X509_STORE_get_by_subject(ctx, X509_LU_X509, nm, &xobj)) + { + sk_X509_free(sk); + return NULL; + } + X509_OBJECT_free_contents(&xobj); + CRYPTO_MUTEX_lock_write(&ctx->ctx->objs_lock); + idx = x509_object_idx_cnt(ctx->ctx->objs,X509_LU_X509,nm, &cnt); + if (idx < 0) + { + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + sk_X509_free(sk); + return NULL; + } + } + for (i = 0; i < cnt; i++, idx++) + { + obj = sk_X509_OBJECT_value(ctx->ctx->objs, idx); + x = obj->data.x509; + if (!sk_X509_push(sk, X509_up_ref(x))) + { + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + X509_free(x); + sk_X509_pop_free(sk, X509_free); + return NULL; + } + } + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + return sk; + + } + +STACK_OF(X509_CRL)* X509_STORE_get1_crls(X509_STORE_CTX *ctx, X509_NAME *nm) + { + int i, idx, cnt; + STACK_OF(X509_CRL) *sk; + X509_CRL *x; + X509_OBJECT *obj, xobj; + sk = sk_X509_CRL_new_null(); + CRYPTO_MUTEX_lock_write(&ctx->ctx->objs_lock); + /* Check cache first */ + idx = x509_object_idx_cnt(ctx->ctx->objs, X509_LU_CRL, nm, &cnt); + + /* Always do lookup to possibly add new CRLs to cache + */ + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + if (!X509_STORE_get_by_subject(ctx, X509_LU_CRL, nm, &xobj)) + { + sk_X509_CRL_free(sk); + return NULL; + } + X509_OBJECT_free_contents(&xobj); + CRYPTO_MUTEX_lock_write(&ctx->ctx->objs_lock); + idx = x509_object_idx_cnt(ctx->ctx->objs,X509_LU_CRL, nm, &cnt); + if (idx < 0) + { + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + sk_X509_CRL_free(sk); + return NULL; + } + + for (i = 0; i < cnt; i++, idx++) + { + obj = sk_X509_OBJECT_value(ctx->ctx->objs, idx); + x = obj->data.crl; + CRYPTO_refcount_inc(&x->references); + if (!sk_X509_CRL_push(sk, x)) + { + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + X509_CRL_free(x); + sk_X509_CRL_pop_free(sk, X509_CRL_free); + return NULL; + } + } + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + return sk; + } + +X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x) + { + size_t idx, i; + X509_OBJECT *obj; + + if (!sk_X509_OBJECT_find(h, &idx, x)) { + return NULL; + } + if ((x->type != X509_LU_X509) && (x->type != X509_LU_CRL)) + return sk_X509_OBJECT_value(h, idx); + for (i = idx; i < sk_X509_OBJECT_num(h); i++) + { + obj = sk_X509_OBJECT_value(h, i); + if (x509_object_cmp((const X509_OBJECT **)&obj, (const X509_OBJECT **)&x)) + return NULL; + if (x->type == X509_LU_X509) + { + if (!X509_cmp(obj->data.x509, x->data.x509)) + return obj; + } + else if (x->type == X509_LU_CRL) + { + if (!X509_CRL_match(obj->data.crl, x->data.crl)) + return obj; + } + else + return obj; + } + return NULL; + } + + +/* Try to get issuer certificate from store. Due to limitations + * of the API this can only retrieve a single certificate matching + * a given subject name. However it will fill the cache with all + * matching certificates, so we can examine the cache for all + * matches. + * + * Return values are: + * 1 lookup successful. + * 0 certificate not found. + * -1 some other error. + */ +int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) + { + X509_NAME *xn; + X509_OBJECT obj, *pobj; + int ok, idx, ret; + size_t i; + xn=X509_get_issuer_name(x); + ok=X509_STORE_get_by_subject(ctx,X509_LU_X509,xn,&obj); + if (ok != X509_LU_X509) + { + if (ok == X509_LU_RETRY) + { + X509_OBJECT_free_contents(&obj); + OPENSSL_PUT_ERROR(X509, X509_R_SHOULD_RETRY); + return -1; + } + else if (ok != X509_LU_FAIL) + { + X509_OBJECT_free_contents(&obj); + /* not good :-(, break anyway */ + return -1; + } + return 0; + } + /* If certificate matches all OK */ + if (ctx->check_issued(ctx, x, obj.data.x509)) + { + *issuer = obj.data.x509; + return 1; + } + X509_OBJECT_free_contents(&obj); + + /* Else find index of first cert accepted by 'check_issued' */ + ret = 0; + CRYPTO_MUTEX_lock_write(&ctx->ctx->objs_lock); + idx = X509_OBJECT_idx_by_subject(ctx->ctx->objs, X509_LU_X509, xn); + if (idx != -1) /* should be true as we've had at least one match */ + { + /* Look through all matching certs for suitable issuer */ + for (i = idx; i < sk_X509_OBJECT_num(ctx->ctx->objs); i++) + { + pobj = sk_X509_OBJECT_value(ctx->ctx->objs, i); + /* See if we've run past the matches */ + if (pobj->type != X509_LU_X509) + break; + if (X509_NAME_cmp(xn, X509_get_subject_name(pobj->data.x509))) + break; + if (ctx->check_issued(ctx, x, pobj->data.x509)) + { + *issuer = pobj->data.x509; + X509_OBJECT_up_ref_count(pobj); + ret = 1; + break; + } + } + } + CRYPTO_MUTEX_unlock(&ctx->ctx->objs_lock); + return ret; + } + +int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags) + { + return X509_VERIFY_PARAM_set_flags(ctx->param, flags); + } + +int X509_STORE_set_depth(X509_STORE *ctx, int depth) + { + X509_VERIFY_PARAM_set_depth(ctx->param, depth); + return 1; + } + +int X509_STORE_set_purpose(X509_STORE *ctx, int purpose) + { + return X509_VERIFY_PARAM_set_purpose(ctx->param, purpose); + } + +int X509_STORE_set_trust(X509_STORE *ctx, int trust) + { + return X509_VERIFY_PARAM_set_trust(ctx->param, trust); + } + +int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *param) + { + return X509_VERIFY_PARAM_set1(ctx->param, param); + } + +void X509_STORE_set_verify_cb(X509_STORE *ctx, + int (*verify_cb)(int, X509_STORE_CTX *)) + { + ctx->verify_cb = verify_cb; + } + +void X509_STORE_set_lookup_crls_cb(X509_STORE *ctx, + STACK_OF(X509_CRL)* (*cb)(X509_STORE_CTX *ctx, X509_NAME *nm)) + { + ctx->lookup_crls = cb; + } + +X509_STORE *X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx) + { + return ctx->ctx; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_obj.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_obj.c new file mode 100644 index 00000000..b6f08164 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_obj.c @@ -0,0 +1,191 @@ +/* crypto/x509/x509_obj.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include +#include + + +char *X509_NAME_oneline(X509_NAME *a, char *buf, int len) + { + X509_NAME_ENTRY *ne; + size_t i; + int n,lold,l,l1,l2,num,j,type; + const char *s; + char *p; + unsigned char *q; + BUF_MEM *b=NULL; + static const char hex[17]="0123456789ABCDEF"; + int gs_doit[4]; + char tmp_buf[80]; + + if (buf == NULL) + { + if ((b=BUF_MEM_new()) == NULL) goto err; + if (!BUF_MEM_grow(b,200)) goto err; + b->data[0]='\0'; + len=200; + } + if (a == NULL) + { + if(b) + { + buf=b->data; + OPENSSL_free(b); + } + strncpy(buf,"NO X509_NAME",len); + buf[len-1]='\0'; + return buf; + } + + len--; /* space for '\0' */ + l=0; + for (i=0; ientries); i++) + { + ne=sk_X509_NAME_ENTRY_value(a->entries,i); + n=OBJ_obj2nid(ne->object); + if ((n == NID_undef) || ((s=OBJ_nid2sn(n)) == NULL)) + { + i2t_ASN1_OBJECT(tmp_buf,sizeof(tmp_buf),ne->object); + s=tmp_buf; + } + l1=strlen(s); + + type=ne->value->type; + num=ne->value->length; + q=ne->value->data; + + if ((type == V_ASN1_GENERALSTRING) && ((num%4) == 0)) + { + gs_doit[0]=gs_doit[1]=gs_doit[2]=gs_doit[3]=0; + for (j=0; j '~')) l2+=3; + } + + lold=l; + l+=1+l1+1+l2; + if (b != NULL) + { + if (!BUF_MEM_grow(b,l+1)) goto err; + p= &(b->data[lold]); + } + else if (l > len) + { + break; + } + else + p= &(buf[lold]); + *(p++)='/'; + memcpy(p,s,(unsigned int)l1); p+=l1; + *(p++)='='; + + q=ne->value->data; + + for (j=0; j '~')) + { + *(p++)='\\'; + *(p++)='x'; + *(p++)=hex[(n>>4)&0x0f]; + *(p++)=hex[n&0x0f]; + } + else + *(p++)=n; + } + *p='\0'; + } + if (b != NULL) + { + p=b->data; + OPENSSL_free(b); + } + else + p=buf; + if (i == 0) + *p = '\0'; + return(p); +err: + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + if (b != NULL) BUF_MEM_free(b); + return(NULL); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_r2x.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_r2x.c new file mode 100644 index 00000000..85979ac0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_r2x.c @@ -0,0 +1,113 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +X509 *X509_REQ_to_X509(X509_REQ *r, int days, EVP_PKEY *pkey) + { + X509 *ret=NULL; + X509_CINF *xi=NULL; + X509_NAME *xn; + + if ((ret=X509_new()) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* duplicate the request */ + xi=ret->cert_info; + + if (sk_X509_ATTRIBUTE_num(r->req_info->attributes) != 0) + { + if ((xi->version=M_ASN1_INTEGER_new()) == NULL) goto err; + if (!ASN1_INTEGER_set(xi->version,2)) goto err; +/* xi->extensions=ri->attributes; <- bad, should not ever be done + ri->attributes=NULL; */ + } + + xn=X509_REQ_get_subject_name(r); + if (X509_set_subject_name(ret,X509_NAME_dup(xn)) == 0) + goto err; + if (X509_set_issuer_name(ret,X509_NAME_dup(xn)) == 0) + goto err; + + if (X509_gmtime_adj(xi->validity->notBefore,0) == NULL) + goto err; + if (X509_gmtime_adj(xi->validity->notAfter,(long)60*60*24*days) == NULL) + goto err; + + X509_set_pubkey(ret,X509_REQ_get_pubkey(r)); + + if (!X509_sign(ret,pkey,EVP_md5())) + goto err; + if (0) + { +err: + X509_free(ret); + ret=NULL; + } + return(ret); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_req.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_req.c new file mode 100644 index 00000000..01c5113e --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_req.c @@ -0,0 +1,315 @@ +/* crypto/x509/x509_req.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +X509_REQ *X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md) + { + X509_REQ *ret; + X509_REQ_INFO *ri; + int i; + EVP_PKEY *pktmp; + + ret=X509_REQ_new(); + if (ret == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto err; + } + + ri=ret->req_info; + + ri->version->length=1; + ri->version->data=(unsigned char *)OPENSSL_malloc(1); + if (ri->version->data == NULL) goto err; + ri->version->data[0]=0; /* version == 0 */ + + if (!X509_REQ_set_subject_name(ret,X509_get_subject_name(x))) + goto err; + + pktmp = X509_get_pubkey(x); + if (pktmp == NULL) + goto err; + i=X509_REQ_set_pubkey(ret,pktmp); + EVP_PKEY_free(pktmp); + if (!i) goto err; + + if (pkey != NULL) + { + if (!X509_REQ_sign(ret,pkey,md)) + goto err; + } + return(ret); +err: + X509_REQ_free(ret); + return(NULL); + } + +EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *req) + { + if ((req == NULL) || (req->req_info == NULL)) + return(NULL); + return(X509_PUBKEY_get(req->req_info->pubkey)); + } + +int X509_REQ_check_private_key(X509_REQ *x, EVP_PKEY *k) + { + EVP_PKEY *xk=NULL; + int ok=0; + + xk=X509_REQ_get_pubkey(x); + switch (EVP_PKEY_cmp(xk, k)) + { + case 1: + ok=1; + break; + case 0: + OPENSSL_PUT_ERROR(X509, X509_R_KEY_VALUES_MISMATCH); + break; + case -1: + OPENSSL_PUT_ERROR(X509, X509_R_KEY_TYPE_MISMATCH); + break; + case -2: + if (k->type == EVP_PKEY_EC) + { + OPENSSL_PUT_ERROR(X509, ERR_R_EC_LIB); + break; + } + if (k->type == EVP_PKEY_DH) + { + /* No idea */ + OPENSSL_PUT_ERROR(X509, X509_R_CANT_CHECK_DH_KEY); + break; + } + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE); + } + + EVP_PKEY_free(xk); + return(ok); + } + +/* It seems several organisations had the same idea of including a list of + * extensions in a certificate request. There are at least two OIDs that are + * used and there may be more: so the list is configurable. + */ + +static const int ext_nid_list[] = { NID_ext_req, NID_ms_ext_req, NID_undef}; + +static const int *ext_nids = ext_nid_list; + +int X509_REQ_extension_nid(int req_nid) +{ + int i, nid; + for(i = 0; ; i++) { + nid = ext_nids[i]; + if(nid == NID_undef) return 0; + else if (req_nid == nid) return 1; + } +} + +const int *X509_REQ_get_extension_nids(void) +{ + return ext_nids; +} + +void X509_REQ_set_extension_nids(const int *nids) +{ + ext_nids = nids; +} + +STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req) + { + X509_ATTRIBUTE *attr; + ASN1_TYPE *ext = NULL; + int idx; + const int *pnid; + const unsigned char *p; + + if ((req == NULL) || (req->req_info == NULL) || !ext_nids) + return(NULL); + for (pnid = ext_nids; *pnid != NID_undef; pnid++) + { + idx = X509_REQ_get_attr_by_NID(req, *pnid, -1); + if (idx == -1) + continue; + attr = X509_REQ_get_attr(req, idx); + if(attr->single) ext = attr->value.single; + else if(sk_ASN1_TYPE_num(attr->value.set)) + ext = sk_ASN1_TYPE_value(attr->value.set, 0); + break; + } + if(!ext || (ext->type != V_ASN1_SEQUENCE)) + return NULL; + p = ext->value.sequence->data; + return (STACK_OF(X509_EXTENSION) *) + ASN1_item_d2i(NULL, &p, ext->value.sequence->length, + ASN1_ITEM_rptr(X509_EXTENSIONS)); +} + +/* Add a STACK_OF extensions to a certificate request: allow alternative OIDs + * in case we want to create a non standard one. + */ + +int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts, + int nid) +{ + ASN1_TYPE *at = NULL; + X509_ATTRIBUTE *attr = NULL; + if(!(at = ASN1_TYPE_new()) || + !(at->value.sequence = ASN1_STRING_new())) goto err; + + at->type = V_ASN1_SEQUENCE; + /* Generate encoding of extensions */ + at->value.sequence->length = + ASN1_item_i2d((ASN1_VALUE *)exts, + &at->value.sequence->data, + ASN1_ITEM_rptr(X509_EXTENSIONS)); + if(!(attr = X509_ATTRIBUTE_new())) goto err; + if(!(attr->value.set = sk_ASN1_TYPE_new_null())) goto err; + if(!sk_ASN1_TYPE_push(attr->value.set, at)) goto err; + at = NULL; + attr->single = 0; + attr->object = (ASN1_OBJECT*) OBJ_nid2obj(nid); + if (!req->req_info->attributes) + { + if (!(req->req_info->attributes = sk_X509_ATTRIBUTE_new_null())) + goto err; + } + if(!sk_X509_ATTRIBUTE_push(req->req_info->attributes, attr)) goto err; + return 1; + err: + X509_ATTRIBUTE_free(attr); + ASN1_TYPE_free(at); + return 0; +} +/* This is the normal usage: use the "official" OID */ +int X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts) +{ + return X509_REQ_add_extensions_nid(req, exts, NID_ext_req); +} + +/* Request attribute functions */ + +int X509_REQ_get_attr_count(const X509_REQ *req) +{ + return X509at_get_attr_count(req->req_info->attributes); +} + +int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid, + int lastpos) +{ + return X509at_get_attr_by_NID(req->req_info->attributes, nid, lastpos); +} + +int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, ASN1_OBJECT *obj, + int lastpos) +{ + return X509at_get_attr_by_OBJ(req->req_info->attributes, obj, lastpos); +} + +X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc) +{ + return X509at_get_attr(req->req_info->attributes, loc); +} + +X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc) +{ + return X509at_delete_attr(req->req_info->attributes, loc); +} + +int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr) +{ + if(X509at_add1_attr(&req->req_info->attributes, attr)) return 1; + return 0; +} + +int X509_REQ_add1_attr_by_OBJ(X509_REQ *req, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len) +{ + if(X509at_add1_attr_by_OBJ(&req->req_info->attributes, obj, + type, bytes, len)) return 1; + return 0; +} + +int X509_REQ_add1_attr_by_NID(X509_REQ *req, + int nid, int type, + const unsigned char *bytes, int len) +{ + if(X509at_add1_attr_by_NID(&req->req_info->attributes, nid, + type, bytes, len)) return 1; + return 0; +} + +int X509_REQ_add1_attr_by_txt(X509_REQ *req, + const char *attrname, int type, + const unsigned char *bytes, int len) +{ + if(X509at_add1_attr_by_txt(&req->req_info->attributes, attrname, + type, bytes, len)) return 1; + return 0; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_set.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_set.c new file mode 100644 index 00000000..06658b07 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_set.c @@ -0,0 +1,154 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include + + +int X509_set_version(X509 *x, long version) + { + if (x == NULL) return(0); + if (version == 0) + { + M_ASN1_INTEGER_free(x->cert_info->version); + x->cert_info->version = NULL; + return(1); + } + if (x->cert_info->version == NULL) + { + if ((x->cert_info->version=M_ASN1_INTEGER_new()) == NULL) + return(0); + } + return(ASN1_INTEGER_set(x->cert_info->version,version)); + } + +int X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial) + { + ASN1_INTEGER *in; + + if (x == NULL) return(0); + in=x->cert_info->serialNumber; + if (in != serial) + { + in=M_ASN1_INTEGER_dup(serial); + if (in != NULL) + { + M_ASN1_INTEGER_free(x->cert_info->serialNumber); + x->cert_info->serialNumber=in; + } + } + return(in != NULL); + } + +int X509_set_issuer_name(X509 *x, X509_NAME *name) + { + if ((x == NULL) || (x->cert_info == NULL)) return(0); + return(X509_NAME_set(&x->cert_info->issuer,name)); + } + +int X509_set_subject_name(X509 *x, X509_NAME *name) + { + if ((x == NULL) || (x->cert_info == NULL)) return(0); + return(X509_NAME_set(&x->cert_info->subject,name)); + } + +int X509_set_notBefore(X509 *x, const ASN1_TIME *tm) + { + ASN1_TIME *in; + + if ((x == NULL) || (x->cert_info->validity == NULL)) return(0); + in=x->cert_info->validity->notBefore; + if (in != tm) + { + in=M_ASN1_TIME_dup(tm); + if (in != NULL) + { + M_ASN1_TIME_free(x->cert_info->validity->notBefore); + x->cert_info->validity->notBefore=in; + } + } + return(in != NULL); + } + +int X509_set_notAfter(X509 *x, const ASN1_TIME *tm) + { + ASN1_TIME *in; + + if ((x == NULL) || (x->cert_info->validity == NULL)) return(0); + in=x->cert_info->validity->notAfter; + if (in != tm) + { + in=M_ASN1_TIME_dup(tm); + if (in != NULL) + { + M_ASN1_TIME_free(x->cert_info->validity->notAfter); + x->cert_info->validity->notAfter=in; + } + } + return(in != NULL); + } + +int X509_set_pubkey(X509 *x, EVP_PKEY *pkey) + { + if ((x == NULL) || (x->cert_info == NULL)) return(0); + return(X509_PUBKEY_set(&(x->cert_info->key),pkey)); + } + + + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_trs.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_trs.c new file mode 100644 index 00000000..820e6052 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_trs.c @@ -0,0 +1,304 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include +#include +#include +#include + + +static int tr_cmp(const X509_TRUST **a, + const X509_TRUST **b); +static void trtable_free(X509_TRUST *p); + +static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags); +static int trust_1oid(X509_TRUST *trust, X509 *x, int flags); +static int trust_compat(X509_TRUST *trust, X509 *x, int flags); + +static int obj_trust(int id, X509 *x, int flags); +static int (*default_trust)(int id, X509 *x, int flags) = obj_trust; + +/* WARNING: the following table should be kept in order of trust + * and without any gaps so we can just subtract the minimum trust + * value to get an index into the table + */ + +static X509_TRUST trstandard[] = { +{X509_TRUST_COMPAT, 0, trust_compat, (char *) "compatible", 0, NULL}, +{X509_TRUST_SSL_CLIENT, 0, trust_1oidany, (char *) "SSL Client", NID_client_auth, NULL}, +{X509_TRUST_SSL_SERVER, 0, trust_1oidany, (char *) "SSL Server", NID_server_auth, NULL}, +{X509_TRUST_EMAIL, 0, trust_1oidany, (char *) "S/MIME email", NID_email_protect, NULL}, +{X509_TRUST_OBJECT_SIGN, 0, trust_1oidany, (char *) "Object Signer", NID_code_sign, NULL}, +{X509_TRUST_OCSP_SIGN, 0, trust_1oid, (char *) "OCSP responder", NID_OCSP_sign, NULL}, +{X509_TRUST_OCSP_REQUEST, 0, trust_1oid, (char *) "OCSP request", NID_ad_OCSP, NULL}, +{X509_TRUST_TSA, 0, trust_1oidany, (char *) "TSA server", NID_time_stamp, NULL} +}; + +#define X509_TRUST_COUNT (sizeof(trstandard)/sizeof(X509_TRUST)) + +static STACK_OF(X509_TRUST) *trtable = NULL; + +static int tr_cmp(const X509_TRUST **a, + const X509_TRUST **b) +{ + return (*a)->trust - (*b)->trust; +} + +int (*X509_TRUST_set_default(int (*trust)(int , X509 *, int)))(int, X509 *, int) +{ + int (*oldtrust)(int , X509 *, int); + oldtrust = default_trust; + default_trust = trust; + return oldtrust; +} + + +int X509_check_trust(X509 *x, int id, int flags) +{ + X509_TRUST *pt; + int idx; + if(id == -1) return 1; + /* We get this as a default value */ + if (id == 0) + { + int rv; + rv = obj_trust(NID_anyExtendedKeyUsage, x, 0); + if (rv != X509_TRUST_UNTRUSTED) + return rv; + return trust_compat(NULL, x, 0); + } + idx = X509_TRUST_get_by_id(id); + if(idx == -1) return default_trust(id, x, flags); + pt = X509_TRUST_get0(idx); + return pt->check_trust(pt, x, flags); +} + +int X509_TRUST_get_count(void) +{ + if(!trtable) return X509_TRUST_COUNT; + return sk_X509_TRUST_num(trtable) + X509_TRUST_COUNT; +} + +X509_TRUST * X509_TRUST_get0(int idx) +{ + if(idx < 0) return NULL; + if(idx < (int)X509_TRUST_COUNT) return trstandard + idx; + return sk_X509_TRUST_value(trtable, idx - X509_TRUST_COUNT); +} + +int X509_TRUST_get_by_id(int id) +{ + X509_TRUST tmp; + size_t idx; + + if((id >= X509_TRUST_MIN) && (id <= X509_TRUST_MAX)) + return id - X509_TRUST_MIN; + tmp.trust = id; + if(!trtable) return -1; + if (!sk_X509_TRUST_find(trtable, &idx, &tmp)) { + return -1; + } + return idx + X509_TRUST_COUNT; +} + +int X509_TRUST_set(int *t, int trust) +{ + if(X509_TRUST_get_by_id(trust) == -1) { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_TRUST); + return 0; + } + *t = trust; + return 1; +} + +int X509_TRUST_add(int id, int flags, int (*ck)(X509_TRUST *, X509 *, int), + char *name, int arg1, void *arg2) +{ + int idx; + X509_TRUST *trtmp; + char *name_dup; + + /* This is set according to what we change: application can't set it */ + flags &= ~X509_TRUST_DYNAMIC; + /* This will always be set for application modified trust entries */ + flags |= X509_TRUST_DYNAMIC_NAME; + /* Get existing entry if any */ + idx = X509_TRUST_get_by_id(id); + /* Need a new entry */ + if(idx == -1) { + if(!(trtmp = OPENSSL_malloc(sizeof(X509_TRUST)))) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + trtmp->flags = X509_TRUST_DYNAMIC; + } else trtmp = X509_TRUST_get0(idx); + + /* Duplicate the supplied name. */ + name_dup = BUF_strdup(name); + if (name_dup == NULL) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + if (idx == -1) + OPENSSL_free(trtmp); + return 0; + } + + /* OPENSSL_free existing name if dynamic */ + if (trtmp->flags & X509_TRUST_DYNAMIC_NAME) OPENSSL_free(trtmp->name); + trtmp->name = name_dup; + /* Keep the dynamic flag of existing entry */ + trtmp->flags &= X509_TRUST_DYNAMIC; + /* Set all other flags */ + trtmp->flags |= flags; + + trtmp->trust = id; + trtmp->check_trust = ck; + trtmp->arg1 = arg1; + trtmp->arg2 = arg2; + + /* If its a new entry manage the dynamic table */ + if(idx == -1) { + if(!trtable && !(trtable = sk_X509_TRUST_new(tr_cmp))) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + trtable_free(trtmp); + return 0; + } + if (!sk_X509_TRUST_push(trtable, trtmp)) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + trtable_free(trtmp); + return 0; + } + } + return 1; +} + +static void trtable_free(X509_TRUST *p) + { + if(!p) return; + if (p->flags & X509_TRUST_DYNAMIC) + { + if (p->flags & X509_TRUST_DYNAMIC_NAME) + OPENSSL_free(p->name); + OPENSSL_free(p); + } + } + +void X509_TRUST_cleanup(void) +{ + unsigned int i; + for(i = 0; i < X509_TRUST_COUNT; i++) trtable_free(trstandard + i); + sk_X509_TRUST_pop_free(trtable, trtable_free); + trtable = NULL; +} + +int X509_TRUST_get_flags(X509_TRUST *xp) +{ + return xp->flags; +} + +char *X509_TRUST_get0_name(X509_TRUST *xp) +{ + return xp->name; +} + +int X509_TRUST_get_trust(X509_TRUST *xp) +{ + return xp->trust; +} + +static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags) +{ + if(x->aux && (x->aux->trust || x->aux->reject)) + return obj_trust(trust->arg1, x, flags); + /* we don't have any trust settings: for compatibility + * we return trusted if it is self signed + */ + return trust_compat(trust, x, flags); +} + +static int trust_1oid(X509_TRUST *trust, X509 *x, int flags) +{ + if(x->aux) return obj_trust(trust->arg1, x, flags); + return X509_TRUST_UNTRUSTED; +} + +static int trust_compat(X509_TRUST *trust, X509 *x, int flags) +{ + X509_check_purpose(x, -1, 0); + if(x->ex_flags & EXFLAG_SS) return X509_TRUST_TRUSTED; + else return X509_TRUST_UNTRUSTED; +} + +static int obj_trust(int id, X509 *x, int flags) +{ + ASN1_OBJECT *obj; + size_t i; + X509_CERT_AUX *ax; + ax = x->aux; + if(!ax) return X509_TRUST_UNTRUSTED; + if(ax->reject) { + for(i = 0; i < sk_ASN1_OBJECT_num(ax->reject); i++) { + obj = sk_ASN1_OBJECT_value(ax->reject, i); + if(OBJ_obj2nid(obj) == id) return X509_TRUST_REJECTED; + } + } + if(ax->trust) { + for(i = 0; i < sk_ASN1_OBJECT_num(ax->trust); i++) { + obj = sk_ASN1_OBJECT_value(ax->trust, i); + if(OBJ_obj2nid(obj) == id) return X509_TRUST_TRUSTED; + } + } + return X509_TRUST_UNTRUSTED; +} + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_txt.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_txt.c new file mode 100644 index 00000000..c2867102 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_txt.c @@ -0,0 +1,209 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +const char *X509_verify_cert_error_string(long n) + { + static char buf[100]; + + switch ((int)n) + { + case X509_V_OK: + return("ok"); + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + return("unable to get issuer certificate"); + case X509_V_ERR_UNABLE_TO_GET_CRL: + return("unable to get certificate CRL"); + case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: + return("unable to decrypt certificate's signature"); + case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: + return("unable to decrypt CRL's signature"); + case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: + return("unable to decode issuer public key"); + case X509_V_ERR_CERT_SIGNATURE_FAILURE: + return("certificate signature failure"); + case X509_V_ERR_CRL_SIGNATURE_FAILURE: + return("CRL signature failure"); + case X509_V_ERR_CERT_NOT_YET_VALID: + return("certificate is not yet valid"); + case X509_V_ERR_CRL_NOT_YET_VALID: + return("CRL is not yet valid"); + case X509_V_ERR_CERT_HAS_EXPIRED: + return("certificate has expired"); + case X509_V_ERR_CRL_HAS_EXPIRED: + return("CRL has expired"); + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + return("format error in certificate's notBefore field"); + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + return("format error in certificate's notAfter field"); + case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: + return("format error in CRL's lastUpdate field"); + case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: + return("format error in CRL's nextUpdate field"); + case X509_V_ERR_OUT_OF_MEM: + return("out of memory"); + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + return("self signed certificate"); + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + return("self signed certificate in certificate chain"); + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + return("unable to get local issuer certificate"); + case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + return("unable to verify the first certificate"); + case X509_V_ERR_CERT_CHAIN_TOO_LONG: + return("certificate chain too long"); + case X509_V_ERR_CERT_REVOKED: + return("certificate revoked"); + case X509_V_ERR_INVALID_CA: + return ("invalid CA certificate"); + case X509_V_ERR_INVALID_NON_CA: + return ("invalid non-CA certificate (has CA markings)"); + case X509_V_ERR_PATH_LENGTH_EXCEEDED: + return ("path length constraint exceeded"); + case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: + return("proxy path length constraint exceeded"); + case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: + return("proxy certificates not allowed, please set the appropriate flag"); + case X509_V_ERR_INVALID_PURPOSE: + return ("unsupported certificate purpose"); + case X509_V_ERR_CERT_UNTRUSTED: + return ("certificate not trusted"); + case X509_V_ERR_CERT_REJECTED: + return ("certificate rejected"); + case X509_V_ERR_APPLICATION_VERIFICATION: + return("application verification failure"); + case X509_V_ERR_SUBJECT_ISSUER_MISMATCH: + return("subject issuer mismatch"); + case X509_V_ERR_AKID_SKID_MISMATCH: + return("authority and subject key identifier mismatch"); + case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: + return("authority and issuer serial number mismatch"); + case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: + return("key usage does not include certificate signing"); + case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: + return("unable to get CRL issuer certificate"); + case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: + return("unhandled critical extension"); + case X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: + return("key usage does not include CRL signing"); + case X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: + return("key usage does not include digital signature"); + case X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: + return("unhandled critical CRL extension"); + case X509_V_ERR_INVALID_EXTENSION: + return("invalid or inconsistent certificate extension"); + case X509_V_ERR_INVALID_POLICY_EXTENSION: + return("invalid or inconsistent certificate policy extension"); + case X509_V_ERR_NO_EXPLICIT_POLICY: + return("no explicit policy"); + case X509_V_ERR_DIFFERENT_CRL_SCOPE: + return("Different CRL scope"); + case X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: + return("Unsupported extension feature"); + case X509_V_ERR_UNNESTED_RESOURCE: + return("RFC 3779 resource not subset of parent's resources"); + + case X509_V_ERR_PERMITTED_VIOLATION: + return("permitted subtree violation"); + case X509_V_ERR_EXCLUDED_VIOLATION: + return("excluded subtree violation"); + case X509_V_ERR_SUBTREE_MINMAX: + return("name constraints minimum and maximum not supported"); + case X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: + return("unsupported name constraint type"); + case X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: + return("unsupported or invalid name constraint syntax"); + case X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: + return("unsupported or invalid name syntax"); + case X509_V_ERR_CRL_PATH_VALIDATION_ERROR: + return("CRL path validation error"); + + case X509_V_ERR_SUITE_B_INVALID_VERSION: + return("Suite B: certificate version invalid"); + case X509_V_ERR_SUITE_B_INVALID_ALGORITHM: + return("Suite B: invalid public key algorithm"); + case X509_V_ERR_SUITE_B_INVALID_CURVE: + return("Suite B: invalid ECC curve"); + case X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM: + return("Suite B: invalid signature algorithm"); + case X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED: + return("Suite B: curve not allowed for this LOS"); + case X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256: + return("Suite B: cannot sign P-384 with P-256"); + + case X509_V_ERR_HOSTNAME_MISMATCH: + return("Hostname mismatch"); + case X509_V_ERR_EMAIL_MISMATCH: + return("Email address mismatch"); + case X509_V_ERR_IP_ADDRESS_MISMATCH: + return("IP address mismatch"); + + default: + BIO_snprintf(buf,sizeof buf,"error number %ld",n); + return(buf); + } + } + + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_v3.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_v3.c new file mode 100644 index 00000000..b0429851 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_v3.c @@ -0,0 +1,271 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include + + +int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x) + { + if (x == NULL) return(0); + return(sk_X509_EXTENSION_num(x)); + } + +int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x, int nid, + int lastpos) + { + const ASN1_OBJECT *obj; + + obj=OBJ_nid2obj(nid); + if (obj == NULL) return(-2); + return(X509v3_get_ext_by_OBJ(x,obj,lastpos)); + } + +int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *sk, const ASN1_OBJECT *obj, + int lastpos) + { + int n; + X509_EXTENSION *ex; + + if (sk == NULL) return(-1); + lastpos++; + if (lastpos < 0) + lastpos=0; + n=sk_X509_EXTENSION_num(sk); + for ( ; lastpos < n; lastpos++) + { + ex=sk_X509_EXTENSION_value(sk,lastpos); + if (OBJ_cmp(ex->object,obj) == 0) + return(lastpos); + } + return(-1); + } + +int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *sk, int crit, + int lastpos) + { + int n; + X509_EXTENSION *ex; + + if (sk == NULL) return(-1); + lastpos++; + if (lastpos < 0) + lastpos=0; + n=sk_X509_EXTENSION_num(sk); + for ( ; lastpos < n; lastpos++) + { + ex=sk_X509_EXTENSION_value(sk,lastpos); + if ( ((ex->critical > 0) && crit) || + ((ex->critical <= 0) && !crit)) + return(lastpos); + } + return(-1); + } + +X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc) + { + if (x == NULL || loc < 0 || sk_X509_EXTENSION_num(x) <= (size_t) loc) + return NULL; + else + return sk_X509_EXTENSION_value(x,loc); + } + +X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc) + { + X509_EXTENSION *ret; + + if (x == NULL || loc < 0 || sk_X509_EXTENSION_num(x) <= (size_t) loc) + return(NULL); + ret=sk_X509_EXTENSION_delete(x,loc); + return(ret); + } + +STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x, + X509_EXTENSION *ex, int loc) + { + X509_EXTENSION *new_ex=NULL; + int n; + STACK_OF(X509_EXTENSION) *sk=NULL; + + if (x == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER); + goto err2; + } + + if (*x == NULL) + { + if ((sk=sk_X509_EXTENSION_new_null()) == NULL) + goto err; + } + else + sk= *x; + + n=sk_X509_EXTENSION_num(sk); + if (loc > n) loc=n; + else if (loc < 0) loc=n; + + if ((new_ex=X509_EXTENSION_dup(ex)) == NULL) + goto err2; + if (!sk_X509_EXTENSION_insert(sk,new_ex,loc)) + goto err; + if (*x == NULL) + *x=sk; + return(sk); +err: + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); +err2: + if (new_ex != NULL) X509_EXTENSION_free(new_ex); + if (sk != NULL) sk_X509_EXTENSION_free(sk); + return(NULL); + } + +X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex, int nid, + int crit, ASN1_OCTET_STRING *data) + { + const ASN1_OBJECT *obj; + X509_EXTENSION *ret; + + obj=OBJ_nid2obj(nid); + if (obj == NULL) + { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_NID); + return(NULL); + } + ret=X509_EXTENSION_create_by_OBJ(ex,obj,crit,data); + return(ret); + } + +X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **ex, + const ASN1_OBJECT *obj, int crit, ASN1_OCTET_STRING *data) + { + X509_EXTENSION *ret; + + if ((ex == NULL) || (*ex == NULL)) + { + if ((ret=X509_EXTENSION_new()) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return(NULL); + } + } + else + ret= *ex; + + if (!X509_EXTENSION_set_object(ret,obj)) + goto err; + if (!X509_EXTENSION_set_critical(ret,crit)) + goto err; + if (!X509_EXTENSION_set_data(ret,data)) + goto err; + + if ((ex != NULL) && (*ex == NULL)) *ex=ret; + return(ret); +err: + if ((ex == NULL) || (ret != *ex)) + X509_EXTENSION_free(ret); + return(NULL); + } + +int X509_EXTENSION_set_object(X509_EXTENSION *ex, const ASN1_OBJECT *obj) + { + if ((ex == NULL) || (obj == NULL)) + return(0); + ASN1_OBJECT_free(ex->object); + ex->object=OBJ_dup(obj); + return ex->object != NULL; + } + +int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit) + { + if (ex == NULL) return(0); + ex->critical=(crit)?0xFF:-1; + return(1); + } + +int X509_EXTENSION_set_data(X509_EXTENSION *ex, ASN1_OCTET_STRING *data) + { + int i; + + if (ex == NULL) return(0); + i=M_ASN1_OCTET_STRING_set(ex->value,data->data,data->length); + if (!i) return(0); + return(1); + } + +ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *ex) + { + if (ex == NULL) return(NULL); + return(ex->object); + } + +ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ex) + { + if (ex == NULL) return(NULL); + return(ex->value); + } + +int X509_EXTENSION_get_critical(X509_EXTENSION *ex) + { + if (ex == NULL) return(0); + if(ex->critical > 0) return 1; + return 0; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_vfy.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_vfy.c new file mode 100644 index 00000000..288ddd8c --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_vfy.c @@ -0,0 +1,2465 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vpm_int.h" +#include "../internal.h" + + +static CRYPTO_EX_DATA_CLASS g_ex_data_class = + CRYPTO_EX_DATA_CLASS_INIT_WITH_APP_DATA; + +/* CRL score values */ + +/* No unhandled critical extensions */ + +#define CRL_SCORE_NOCRITICAL 0x100 + +/* certificate is within CRL scope */ + +#define CRL_SCORE_SCOPE 0x080 + +/* CRL times valid */ + +#define CRL_SCORE_TIME 0x040 + +/* Issuer name matches certificate */ + +#define CRL_SCORE_ISSUER_NAME 0x020 + +/* If this score or above CRL is probably valid */ + +#define CRL_SCORE_VALID (CRL_SCORE_NOCRITICAL|CRL_SCORE_TIME|CRL_SCORE_SCOPE) + +/* CRL issuer is certificate issuer */ + +#define CRL_SCORE_ISSUER_CERT 0x018 + +/* CRL issuer is on certificate path */ + +#define CRL_SCORE_SAME_PATH 0x008 + +/* CRL issuer matches CRL AKID */ + +#define CRL_SCORE_AKID 0x004 + +/* Have a delta CRL with valid times */ + +#define CRL_SCORE_TIME_DELTA 0x002 + +static int null_callback(int ok,X509_STORE_CTX *e); +static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); +static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x); +static int check_chain_extensions(X509_STORE_CTX *ctx); +static int check_name_constraints(X509_STORE_CTX *ctx); +static int check_id(X509_STORE_CTX *ctx); +static int check_trust(X509_STORE_CTX *ctx); +static int check_revocation(X509_STORE_CTX *ctx); +static int check_cert(X509_STORE_CTX *ctx); +static int check_policy(X509_STORE_CTX *ctx); + +static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, + unsigned int *preasons, + X509_CRL *crl, X509 *x); +static int get_crl_delta(X509_STORE_CTX *ctx, + X509_CRL **pcrl, X509_CRL **pdcrl, X509 *x); +static void get_delta_sk(X509_STORE_CTX *ctx, X509_CRL **dcrl, int *pcrl_score, + X509_CRL *base, STACK_OF(X509_CRL) *crls); +static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, + X509 **pissuer, int *pcrl_score); +static int crl_crldp_check(X509 *x, X509_CRL *crl, int crl_score, + unsigned int *preasons); +static int check_crl_path(X509_STORE_CTX *ctx, X509 *x); +static int check_crl_chain(X509_STORE_CTX *ctx, + STACK_OF(X509) *cert_path, + STACK_OF(X509) *crl_path); + +static int internal_verify(X509_STORE_CTX *ctx); +const char X509_version[]="X.509"; + + +static int null_callback(int ok, X509_STORE_CTX *e) + { + return ok; + } + +#if 0 +static int x509_subject_cmp(X509 **a, X509 **b) + { + return X509_subject_name_cmp(*a,*b); + } +#endif +/* Return 1 is a certificate is self signed */ +static int cert_self_signed(X509 *x) + { + X509_check_purpose(x, -1, 0); + if (x->ex_flags & EXFLAG_SS) + return 1; + else + return 0; + } + +/* Given a certificate try and find an exact match in the store */ + +static X509 *lookup_cert_match(X509_STORE_CTX *ctx, X509 *x) + { + STACK_OF(X509) *certs; + X509 *xtmp = NULL; + size_t i; + /* Lookup all certs with matching subject name */ + certs = ctx->lookup_certs(ctx, X509_get_subject_name(x)); + if (certs == NULL) + return NULL; + /* Look for exact match */ + for (i = 0; i < sk_X509_num(certs); i++) + { + xtmp = sk_X509_value(certs, i); + if (!X509_cmp(xtmp, x)) + break; + } + if (i < sk_X509_num(certs)) + X509_up_ref(xtmp); + else + xtmp = NULL; + sk_X509_pop_free(certs, X509_free); + return xtmp; + } + +int X509_verify_cert(X509_STORE_CTX *ctx) + { + X509 *x,*xtmp,*chain_ss=NULL; + int bad_chain = 0; + X509_VERIFY_PARAM *param = ctx->param; + int depth,i,ok=0; + int num; + int (*cb)(int xok,X509_STORE_CTX *xctx); + STACK_OF(X509) *sktmp=NULL; + if (ctx->cert == NULL) + { + OPENSSL_PUT_ERROR(X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY); + return -1; + } + + cb=ctx->verify_cb; + + /* first we make sure the chain we are going to build is + * present and that the first entry is in place */ + if (ctx->chain == NULL) + { + if ( ((ctx->chain=sk_X509_new_null()) == NULL) || + (!sk_X509_push(ctx->chain,ctx->cert))) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto end; + } + X509_up_ref(ctx->cert); + ctx->last_untrusted=1; + } + + /* We use a temporary STACK so we can chop and hack at it */ + if (ctx->untrusted != NULL + && (sktmp=sk_X509_dup(ctx->untrusted)) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto end; + } + + num=sk_X509_num(ctx->chain); + x=sk_X509_value(ctx->chain,num-1); + depth=param->depth; + + + for (;;) + { + /* If we have enough, we break */ + if (depth < num) break; /* FIXME: If this happens, we should take + * note of it and, if appropriate, use the + * X509_V_ERR_CERT_CHAIN_TOO_LONG error + * code later. + */ + + /* If we are self signed, we break */ + if (cert_self_signed(x)) + break; + /* If asked see if we can find issuer in trusted store first */ + if (ctx->param->flags & X509_V_FLAG_TRUSTED_FIRST) + { + ok = ctx->get_issuer(&xtmp, ctx, x); + if (ok < 0) + return ok; + /* If successful for now free up cert so it + * will be picked up again later. + */ + if (ok > 0) + { + X509_free(xtmp); + break; + } + } + + /* If we were passed a cert chain, use it first */ + if (ctx->untrusted != NULL) + { + xtmp=find_issuer(ctx, sktmp,x); + if (xtmp != NULL) + { + if (!sk_X509_push(ctx->chain,xtmp)) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto end; + } + CRYPTO_refcount_inc(&xtmp->references); + (void)sk_X509_delete_ptr(sktmp,xtmp); + ctx->last_untrusted++; + x=xtmp; + num++; + /* reparse the full chain for + * the next one */ + continue; + } + } + break; + } + + /* at this point, chain should contain a list of untrusted + * certificates. We now need to add at least one trusted one, + * if possible, otherwise we complain. */ + + /* Examine last certificate in chain and see if it + * is self signed. + */ + + i=sk_X509_num(ctx->chain); + x=sk_X509_value(ctx->chain,i-1); + if (cert_self_signed(x)) + { + /* we have a self signed certificate */ + if (sk_X509_num(ctx->chain) == 1) + { + /* We have a single self signed certificate: see if + * we can find it in the store. We must have an exact + * match to avoid possible impersonation. + */ + ok = ctx->get_issuer(&xtmp, ctx, x); + if ((ok <= 0) || X509_cmp(x, xtmp)) + { + ctx->error=X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT; + ctx->current_cert=x; + ctx->error_depth=i-1; + if (ok == 1) X509_free(xtmp); + bad_chain = 1; + ok=cb(0,ctx); + if (!ok) goto end; + } + else + { + /* We have a match: replace certificate with store version + * so we get any trust settings. + */ + X509_free(x); + x = xtmp; + (void)sk_X509_set(ctx->chain, i - 1, x); + ctx->last_untrusted=0; + } + } + else + { + /* extract and save self signed certificate for later use */ + chain_ss=sk_X509_pop(ctx->chain); + ctx->last_untrusted--; + num--; + x=sk_X509_value(ctx->chain,num-1); + } + } + + /* We now lookup certs from the certificate store */ + for (;;) + { + /* If we have enough, we break */ + if (depth < num) break; + + /* If we are self signed, we break */ + if (cert_self_signed(x)) + break; + + ok = ctx->get_issuer(&xtmp, ctx, x); + + if (ok < 0) return ok; + if (ok == 0) break; + + x = xtmp; + if (!sk_X509_push(ctx->chain,x)) + { + X509_free(xtmp); + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + num++; + } + + /* we now have our chain, lets check it... */ + + i = check_trust(ctx); + + /* If explicitly rejected error */ + if (i == X509_TRUST_REJECTED) + goto end; + /* If not explicitly trusted then indicate error unless it's + * a single self signed certificate in which case we've indicated + * an error already and set bad_chain == 1 + */ + if (i != X509_TRUST_TRUSTED && !bad_chain) + { + if ((chain_ss == NULL) || !ctx->check_issued(ctx, x, chain_ss)) + { + if (ctx->last_untrusted >= num) + ctx->error=X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY; + else + ctx->error=X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT; + ctx->current_cert=x; + } + else + { + + sk_X509_push(ctx->chain,chain_ss); + num++; + ctx->last_untrusted=num; + ctx->current_cert=chain_ss; + ctx->error=X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN; + chain_ss=NULL; + } + + ctx->error_depth=num-1; + bad_chain = 1; + ok=cb(0,ctx); + if (!ok) goto end; + } + + /* We have the chain complete: now we need to check its purpose */ + ok = check_chain_extensions(ctx); + + if (!ok) goto end; + + /* Check name constraints */ + + ok = check_name_constraints(ctx); + + if (!ok) goto end; + + ok = check_id(ctx); + + if (!ok) goto end; + + /* Check revocation status: we do this after copying parameters + * because they may be needed for CRL signature verification. + */ + + ok = ctx->check_revocation(ctx); + if(!ok) goto end; + + i = X509_chain_check_suiteb(&ctx->error_depth, NULL, ctx->chain, + ctx->param->flags); + if (i != X509_V_OK) + { + ctx->error = i; + ctx->current_cert = sk_X509_value(ctx->chain, ctx->error_depth); + ok = cb(0, ctx); + if (!ok) + goto end; + } + + /* At this point, we have a chain and need to verify it */ + if (ctx->verify != NULL) + ok=ctx->verify(ctx); + else + ok=internal_verify(ctx); + if(!ok) goto end; + + /* If we get this far evaluate policies */ + if (!bad_chain && (ctx->param->flags & X509_V_FLAG_POLICY_CHECK)) + ok = ctx->check_policy(ctx); + +end: + if (sktmp != NULL) sk_X509_free(sktmp); + if (chain_ss != NULL) X509_free(chain_ss); + return ok; + } + + +/* Given a STACK_OF(X509) find the issuer of cert (if any) + */ + +static X509 *find_issuer(X509_STORE_CTX *ctx, STACK_OF(X509) *sk, X509 *x) +{ + size_t i; + X509 *issuer; + for (i = 0; i < sk_X509_num(sk); i++) + { + issuer = sk_X509_value(sk, i); + if (ctx->check_issued(ctx, x, issuer)) + return issuer; + } + return NULL; +} + +/* Given a possible certificate and issuer check them */ + +static int check_issued(X509_STORE_CTX *ctx, X509 *x, X509 *issuer) +{ + int ret; + ret = X509_check_issued(issuer, x); + if (ret == X509_V_OK) + return 1; + /* If we haven't asked for issuer errors don't set ctx */ + if (!(ctx->param->flags & X509_V_FLAG_CB_ISSUER_CHECK)) + return 0; + + ctx->error = ret; + ctx->current_cert = x; + ctx->current_issuer = issuer; + return ctx->verify_cb(0, ctx); +} + +/* Alternative lookup method: look from a STACK stored in other_ctx */ + +static int get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x) +{ + *issuer = find_issuer(ctx, ctx->other_ctx, x); + if (*issuer) + { + X509_up_ref(*issuer); + return 1; + } + else + return 0; +} + + +/* Check a certificate chains extensions for consistency + * with the supplied purpose + */ + +static int check_chain_extensions(X509_STORE_CTX *ctx) +{ + int i, ok=0, must_be_ca, plen = 0; + X509 *x; + int (*cb)(int xok,X509_STORE_CTX *xctx); + int proxy_path_length = 0; + int purpose; + int allow_proxy_certs; + cb=ctx->verify_cb; + + /* must_be_ca can have 1 of 3 values: + -1: we accept both CA and non-CA certificates, to allow direct + use of self-signed certificates (which are marked as CA). + 0: we only accept non-CA certificates. This is currently not + used, but the possibility is present for future extensions. + 1: we only accept CA certificates. This is currently used for + all certificates in the chain except the leaf certificate. + */ + must_be_ca = -1; + + /* CRL path validation */ + if (ctx->parent) + { + allow_proxy_certs = 0; + purpose = X509_PURPOSE_CRL_SIGN; + } + else + { + allow_proxy_certs = + !!(ctx->param->flags & X509_V_FLAG_ALLOW_PROXY_CERTS); + /* A hack to keep people who don't want to modify their + software happy */ + if (getenv("OPENSSL_ALLOW_PROXY_CERTS")) + allow_proxy_certs = 1; + purpose = ctx->param->purpose; + } + + /* Check all untrusted certificates */ + for (i = 0; i < ctx->last_untrusted; i++) + { + int ret; + x = sk_X509_value(ctx->chain, i); + if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) + && (x->ex_flags & EXFLAG_CRITICAL)) + { + ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION; + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + if (!allow_proxy_certs && (x->ex_flags & EXFLAG_PROXY)) + { + ctx->error = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED; + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + ret = X509_check_ca(x); + switch(must_be_ca) + { + case -1: + if ((ctx->param->flags & X509_V_FLAG_X509_STRICT) + && (ret != 1) && (ret != 0)) + { + ret = 0; + ctx->error = X509_V_ERR_INVALID_CA; + } + else + ret = 1; + break; + case 0: + if (ret != 0) + { + ret = 0; + ctx->error = X509_V_ERR_INVALID_NON_CA; + } + else + ret = 1; + break; + default: + if ((ret == 0) + || ((ctx->param->flags & X509_V_FLAG_X509_STRICT) + && (ret != 1))) + { + ret = 0; + ctx->error = X509_V_ERR_INVALID_CA; + } + else + ret = 1; + break; + } + if (ret == 0) + { + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + if (ctx->param->purpose > 0) + { + ret = X509_check_purpose(x, purpose, must_be_ca > 0); + if ((ret == 0) + || ((ctx->param->flags & X509_V_FLAG_X509_STRICT) + && (ret != 1))) + { + ctx->error = X509_V_ERR_INVALID_PURPOSE; + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + } + /* Check pathlen if not self issued */ + if ((i > 1) && !(x->ex_flags & EXFLAG_SI) + && (x->ex_pathlen != -1) + && (plen > (x->ex_pathlen + proxy_path_length + 1))) + { + ctx->error = X509_V_ERR_PATH_LENGTH_EXCEEDED; + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + /* Increment path length if not self issued */ + if (!(x->ex_flags & EXFLAG_SI)) + plen++; + /* If this certificate is a proxy certificate, the next + certificate must be another proxy certificate or a EE + certificate. If not, the next certificate must be a + CA certificate. */ + if (x->ex_flags & EXFLAG_PROXY) + { + if (x->ex_pcpathlen != -1 && i > x->ex_pcpathlen) + { + ctx->error = + X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED; + ctx->error_depth = i; + ctx->current_cert = x; + ok=cb(0,ctx); + if (!ok) goto end; + } + proxy_path_length++; + must_be_ca = 0; + } + else + must_be_ca = 1; + } + ok = 1; + end: + return ok; +} + +static int check_name_constraints(X509_STORE_CTX *ctx) + { + X509 *x; + int i, j, rv; + /* Check name constraints for all certificates */ + for (i = sk_X509_num(ctx->chain) - 1; i >= 0; i--) + { + x = sk_X509_value(ctx->chain, i); + /* Ignore self issued certs unless last in chain */ + if (i && (x->ex_flags & EXFLAG_SI)) + continue; + /* Check against constraints for all certificates higher in + * chain including trust anchor. Trust anchor not strictly + * speaking needed but if it includes constraints it is to be + * assumed it expects them to be obeyed. + */ + for (j = sk_X509_num(ctx->chain) - 1; j > i; j--) + { + NAME_CONSTRAINTS *nc = sk_X509_value(ctx->chain, j)->nc; + if (nc) + { + rv = NAME_CONSTRAINTS_check(x, nc); + if (rv != X509_V_OK) + { + ctx->error = rv; + ctx->error_depth = i; + ctx->current_cert = x; + if (!ctx->verify_cb(0,ctx)) + return 0; + } + } + } + } + return 1; + } + +static int check_id_error(X509_STORE_CTX *ctx, int errcode) + { + ctx->error = errcode; + ctx->current_cert = ctx->cert; + ctx->error_depth = 0; + return ctx->verify_cb(0, ctx); + } + +static int check_hosts(X509 *x, X509_VERIFY_PARAM_ID *id) + { + size_t i; + size_t n = sk_OPENSSL_STRING_num(id->hosts); + char *name; + + for (i = 0; i < n; ++i) + { + name = sk_OPENSSL_STRING_value(id->hosts, i); + if (X509_check_host(x, name, strlen(name), id->hostflags, + &id->peername) > 0) + return 1; + } + return n == 0; + } + +static int check_id(X509_STORE_CTX *ctx) + { + X509_VERIFY_PARAM *vpm = ctx->param; + X509_VERIFY_PARAM_ID *id = vpm->id; + X509 *x = ctx->cert; + if (id->hosts && check_hosts(x, id) <= 0) + { + if (!check_id_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH)) + return 0; + } + if (id->email && X509_check_email(x, id->email, id->emaillen, 0) <= 0) + { + if (!check_id_error(ctx, X509_V_ERR_EMAIL_MISMATCH)) + return 0; + } + if (id->ip && X509_check_ip(x, id->ip, id->iplen, 0) <= 0) + { + if (!check_id_error(ctx, X509_V_ERR_IP_ADDRESS_MISMATCH)) + return 0; + } + return 1; + } + +static int check_trust(X509_STORE_CTX *ctx) +{ + size_t i; + int ok; + X509 *x = NULL; + int (*cb)(int xok,X509_STORE_CTX *xctx); + cb=ctx->verify_cb; + /* Check all trusted certificates in chain */ + for (i = ctx->last_untrusted; i < sk_X509_num(ctx->chain); i++) + { + x = sk_X509_value(ctx->chain, i); + ok = X509_check_trust(x, ctx->param->trust, 0); + /* If explicitly trusted return trusted */ + if (ok == X509_TRUST_TRUSTED) + return X509_TRUST_TRUSTED; + /* If explicitly rejected notify callback and reject if + * not overridden. + */ + if (ok == X509_TRUST_REJECTED) + { + ctx->error_depth = i; + ctx->current_cert = x; + ctx->error = X509_V_ERR_CERT_REJECTED; + ok = cb(0, ctx); + if (!ok) + return X509_TRUST_REJECTED; + } + } + /* If we accept partial chains and have at least one trusted + * certificate return success. + */ + if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) + { + X509 *mx; + if (ctx->last_untrusted < (int) sk_X509_num(ctx->chain)) + return X509_TRUST_TRUSTED; + x = sk_X509_value(ctx->chain, 0); + mx = lookup_cert_match(ctx, x); + if (mx) + { + (void)sk_X509_set(ctx->chain, 0, mx); + X509_free(x); + ctx->last_untrusted = 0; + return X509_TRUST_TRUSTED; + } + } + + /* If no trusted certs in chain at all return untrusted and + * allow standard (no issuer cert) etc errors to be indicated. + */ + return X509_TRUST_UNTRUSTED; +} + +static int check_revocation(X509_STORE_CTX *ctx) + { + int i, last, ok; + if (!(ctx->param->flags & X509_V_FLAG_CRL_CHECK)) + return 1; + if (ctx->param->flags & X509_V_FLAG_CRL_CHECK_ALL) + last = sk_X509_num(ctx->chain) - 1; + else + { + /* If checking CRL paths this isn't the EE certificate */ + if (ctx->parent) + return 1; + last = 0; + } + for(i = 0; i <= last; i++) + { + ctx->error_depth = i; + ok = check_cert(ctx); + if (!ok) return ok; + } + return 1; + } + +static int check_cert(X509_STORE_CTX *ctx) + OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS + { + X509_CRL *crl = NULL, *dcrl = NULL; + X509 *x; + int ok, cnum; + unsigned int last_reasons; + cnum = ctx->error_depth; + x = sk_X509_value(ctx->chain, cnum); + ctx->current_cert = x; + ctx->current_issuer = NULL; + ctx->current_crl_score = 0; + ctx->current_reasons = 0; + while (ctx->current_reasons != CRLDP_ALL_REASONS) + { + last_reasons = ctx->current_reasons; + /* Try to retrieve relevant CRL */ + if (ctx->get_crl) + ok = ctx->get_crl(ctx, &crl, x); + else + ok = get_crl_delta(ctx, &crl, &dcrl, x); + /* If error looking up CRL, nothing we can do except + * notify callback + */ + if(!ok) + { + ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL; + ok = ctx->verify_cb(0, ctx); + goto err; + } + ctx->current_crl = crl; + ok = ctx->check_crl(ctx, crl); + if (!ok) + goto err; + + if (dcrl) + { + ok = ctx->check_crl(ctx, dcrl); + if (!ok) + goto err; + ok = ctx->cert_crl(ctx, dcrl, x); + if (!ok) + goto err; + } + else + ok = 1; + + /* Don't look in full CRL if delta reason is removefromCRL */ + if (ok != 2) + { + ok = ctx->cert_crl(ctx, crl, x); + if (!ok) + goto err; + } + + X509_CRL_free(crl); + X509_CRL_free(dcrl); + crl = NULL; + dcrl = NULL; + /* If reasons not updated we wont get anywhere by + * another iteration, so exit loop. + */ + if (last_reasons == ctx->current_reasons) + { + ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL; + ok = ctx->verify_cb(0, ctx); + goto err; + } + } + err: + X509_CRL_free(crl); + X509_CRL_free(dcrl); + + ctx->current_crl = NULL; + return ok; + + } + +/* Check CRL times against values in X509_STORE_CTX */ + +static int check_crl_time(X509_STORE_CTX *ctx, X509_CRL *crl, int notify) + { + time_t *ptime; + int i; + if (notify) + ctx->current_crl = crl; + if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) + ptime = &ctx->param->check_time; + else + ptime = NULL; + + i=X509_cmp_time(X509_CRL_get_lastUpdate(crl), ptime); + if (i == 0) + { + if (!notify) + return 0; + ctx->error=X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + + if (i > 0) + { + if (!notify) + return 0; + ctx->error=X509_V_ERR_CRL_NOT_YET_VALID; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + + if(X509_CRL_get_nextUpdate(crl)) + { + i=X509_cmp_time(X509_CRL_get_nextUpdate(crl), ptime); + + if (i == 0) + { + if (!notify) + return 0; + ctx->error=X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + /* Ignore expiry of base CRL is delta is valid */ + if ((i < 0) && !(ctx->current_crl_score & CRL_SCORE_TIME_DELTA)) + { + if (!notify) + return 0; + ctx->error=X509_V_ERR_CRL_HAS_EXPIRED; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + } + + if (notify) + ctx->current_crl = NULL; + + return 1; + } + +static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509_CRL **pdcrl, + X509 **pissuer, int *pscore, unsigned int *preasons, + STACK_OF(X509_CRL) *crls) + { + int crl_score, best_score = *pscore; + size_t i; + unsigned int reasons, best_reasons = 0; + X509 *x = ctx->current_cert; + X509_CRL *crl, *best_crl = NULL; + X509 *crl_issuer = NULL, *best_crl_issuer = NULL; + + for (i = 0; i < sk_X509_CRL_num(crls); i++) + { + crl = sk_X509_CRL_value(crls, i); + reasons = *preasons; + crl_score = get_crl_score(ctx, &crl_issuer, &reasons, crl, x); + + if (crl_score > best_score) + { + best_crl = crl; + best_crl_issuer = crl_issuer; + best_score = crl_score; + best_reasons = reasons; + } + } + + if (best_crl) + { + if (*pcrl) + X509_CRL_free(*pcrl); + *pcrl = best_crl; + *pissuer = best_crl_issuer; + *pscore = best_score; + *preasons = best_reasons; + CRYPTO_refcount_inc(&best_crl->references); + if (*pdcrl) + { + X509_CRL_free(*pdcrl); + *pdcrl = NULL; + } + get_delta_sk(ctx, pdcrl, pscore, best_crl, crls); + } + + if (best_score >= CRL_SCORE_VALID) + return 1; + + return 0; + } + +/* Compare two CRL extensions for delta checking purposes. They should be + * both present or both absent. If both present all fields must be identical. + */ + +static int crl_extension_match(X509_CRL *a, X509_CRL *b, int nid) + { + ASN1_OCTET_STRING *exta, *extb; + int i; + i = X509_CRL_get_ext_by_NID(a, nid, -1); + if (i >= 0) + { + /* Can't have multiple occurrences */ + if (X509_CRL_get_ext_by_NID(a, nid, i) != -1) + return 0; + exta = X509_EXTENSION_get_data(X509_CRL_get_ext(a, i)); + } + else + exta = NULL; + + i = X509_CRL_get_ext_by_NID(b, nid, -1); + + if (i >= 0) + { + + if (X509_CRL_get_ext_by_NID(b, nid, i) != -1) + return 0; + extb = X509_EXTENSION_get_data(X509_CRL_get_ext(b, i)); + } + else + extb = NULL; + + if (!exta && !extb) + return 1; + + if (!exta || !extb) + return 0; + + + if (ASN1_OCTET_STRING_cmp(exta, extb)) + return 0; + + return 1; + } + +/* See if a base and delta are compatible */ + +static int check_delta_base(X509_CRL *delta, X509_CRL *base) + { + /* Delta CRL must be a delta */ + if (!delta->base_crl_number) + return 0; + /* Base must have a CRL number */ + if (!base->crl_number) + return 0; + /* Issuer names must match */ + if (X509_NAME_cmp(X509_CRL_get_issuer(base), + X509_CRL_get_issuer(delta))) + return 0; + /* AKID and IDP must match */ + if (!crl_extension_match(delta, base, NID_authority_key_identifier)) + return 0; + if (!crl_extension_match(delta, base, NID_issuing_distribution_point)) + return 0; + /* Delta CRL base number must not exceed Full CRL number. */ + if (ASN1_INTEGER_cmp(delta->base_crl_number, base->crl_number) > 0) + return 0; + /* Delta CRL number must exceed full CRL number */ + if (ASN1_INTEGER_cmp(delta->crl_number, base->crl_number) > 0) + return 1; + return 0; + } + +/* For a given base CRL find a delta... maybe extend to delta scoring + * or retrieve a chain of deltas... + */ + +static void get_delta_sk(X509_STORE_CTX *ctx, X509_CRL **dcrl, int *pscore, + X509_CRL *base, STACK_OF(X509_CRL) *crls) + { + X509_CRL *delta; + size_t i; + if (!(ctx->param->flags & X509_V_FLAG_USE_DELTAS)) + return; + if (!((ctx->current_cert->ex_flags | base->flags) & EXFLAG_FRESHEST)) + return; + for (i = 0; i < sk_X509_CRL_num(crls); i++) + { + delta = sk_X509_CRL_value(crls, i); + if (check_delta_base(delta, base)) + { + if (check_crl_time(ctx, delta, 0)) + *pscore |= CRL_SCORE_TIME_DELTA; + CRYPTO_refcount_inc(&delta->references); + *dcrl = delta; + return; + } + } + *dcrl = NULL; + } + +/* For a given CRL return how suitable it is for the supplied certificate 'x'. + * The return value is a mask of several criteria. + * If the issuer is not the certificate issuer this is returned in *pissuer. + * The reasons mask is also used to determine if the CRL is suitable: if + * no new reasons the CRL is rejected, otherwise reasons is updated. + */ + +static int get_crl_score(X509_STORE_CTX *ctx, X509 **pissuer, + unsigned int *preasons, + X509_CRL *crl, X509 *x) + { + + int crl_score = 0; + unsigned int tmp_reasons = *preasons, crl_reasons; + + /* First see if we can reject CRL straight away */ + + /* Invalid IDP cannot be processed */ + if (crl->idp_flags & IDP_INVALID) + return 0; + /* Reason codes or indirect CRLs need extended CRL support */ + if (!(ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT)) + { + if (crl->idp_flags & (IDP_INDIRECT | IDP_REASONS)) + return 0; + } + else if (crl->idp_flags & IDP_REASONS) + { + /* If no new reasons reject */ + if (!(crl->idp_reasons & ~tmp_reasons)) + return 0; + } + /* Don't process deltas at this stage */ + else if (crl->base_crl_number) + return 0; + /* If issuer name doesn't match certificate need indirect CRL */ + if (X509_NAME_cmp(X509_get_issuer_name(x), X509_CRL_get_issuer(crl))) + { + if (!(crl->idp_flags & IDP_INDIRECT)) + return 0; + } + else + crl_score |= CRL_SCORE_ISSUER_NAME; + + if (!(crl->flags & EXFLAG_CRITICAL)) + crl_score |= CRL_SCORE_NOCRITICAL; + + /* Check expiry */ + if (check_crl_time(ctx, crl, 0)) + crl_score |= CRL_SCORE_TIME; + + /* Check authority key ID and locate certificate issuer */ + crl_akid_check(ctx, crl, pissuer, &crl_score); + + /* If we can't locate certificate issuer at this point forget it */ + + if (!(crl_score & CRL_SCORE_AKID)) + return 0; + + /* Check cert for matching CRL distribution points */ + + if (crl_crldp_check(x, crl, crl_score, &crl_reasons)) + { + /* If no new reasons reject */ + if (!(crl_reasons & ~tmp_reasons)) + return 0; + tmp_reasons |= crl_reasons; + crl_score |= CRL_SCORE_SCOPE; + } + + *preasons = tmp_reasons; + + return crl_score; + + } + +static void crl_akid_check(X509_STORE_CTX *ctx, X509_CRL *crl, + X509 **pissuer, int *pcrl_score) + { + X509 *crl_issuer = NULL; + X509_NAME *cnm = X509_CRL_get_issuer(crl); + int cidx = ctx->error_depth; + size_t i; + + if (cidx != sk_X509_num(ctx->chain) - 1) + cidx++; + + crl_issuer = sk_X509_value(ctx->chain, cidx); + + if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) + { + if (*pcrl_score & CRL_SCORE_ISSUER_NAME) + { + *pcrl_score |= CRL_SCORE_AKID|CRL_SCORE_ISSUER_CERT; + *pissuer = crl_issuer; + return; + } + } + + for (cidx++; cidx < (int) sk_X509_num(ctx->chain); cidx++) + { + crl_issuer = sk_X509_value(ctx->chain, cidx); + if (X509_NAME_cmp(X509_get_subject_name(crl_issuer), cnm)) + continue; + if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) + { + *pcrl_score |= CRL_SCORE_AKID|CRL_SCORE_SAME_PATH; + *pissuer = crl_issuer; + return; + } + } + + /* Anything else needs extended CRL support */ + + if (!(ctx->param->flags & X509_V_FLAG_EXTENDED_CRL_SUPPORT)) + return; + + /* Otherwise the CRL issuer is not on the path. Look for it in the + * set of untrusted certificates. + */ + for (i = 0; i < sk_X509_num(ctx->untrusted); i++) + { + crl_issuer = sk_X509_value(ctx->untrusted, i); + if (X509_NAME_cmp(X509_get_subject_name(crl_issuer), cnm)) + continue; + if (X509_check_akid(crl_issuer, crl->akid) == X509_V_OK) + { + *pissuer = crl_issuer; + *pcrl_score |= CRL_SCORE_AKID; + return; + } + } + } + +/* Check the path of a CRL issuer certificate. This creates a new + * X509_STORE_CTX and populates it with most of the parameters from the + * parent. This could be optimised somewhat since a lot of path checking + * will be duplicated by the parent, but this will rarely be used in + * practice. + */ + +static int check_crl_path(X509_STORE_CTX *ctx, X509 *x) + { + X509_STORE_CTX crl_ctx; + int ret; + /* Don't allow recursive CRL path validation */ + if (ctx->parent) + return 0; + if (!X509_STORE_CTX_init(&crl_ctx, ctx->ctx, x, ctx->untrusted)) + return -1; + + crl_ctx.crls = ctx->crls; + /* Copy verify params across */ + X509_STORE_CTX_set0_param(&crl_ctx, ctx->param); + + crl_ctx.parent = ctx; + crl_ctx.verify_cb = ctx->verify_cb; + + /* Verify CRL issuer */ + ret = X509_verify_cert(&crl_ctx); + + if (ret <= 0) + goto err; + + /* Check chain is acceptable */ + + ret = check_crl_chain(ctx, ctx->chain, crl_ctx.chain); + err: + X509_STORE_CTX_cleanup(&crl_ctx); + return ret; + } + +/* RFC3280 says nothing about the relationship between CRL path + * and certificate path, which could lead to situations where a + * certificate could be revoked or validated by a CA not authorised + * to do so. RFC5280 is more strict and states that the two paths must + * end in the same trust anchor, though some discussions remain... + * until this is resolved we use the RFC5280 version + */ + +static int check_crl_chain(X509_STORE_CTX *ctx, + STACK_OF(X509) *cert_path, + STACK_OF(X509) *crl_path) + { + X509 *cert_ta, *crl_ta; + cert_ta = sk_X509_value(cert_path, sk_X509_num(cert_path) - 1); + crl_ta = sk_X509_value(crl_path, sk_X509_num(crl_path) - 1); + if (!X509_cmp(cert_ta, crl_ta)) + return 1; + return 0; + } + +/* Check for match between two dist point names: three separate cases. + * 1. Both are relative names and compare X509_NAME types. + * 2. One full, one relative. Compare X509_NAME to GENERAL_NAMES. + * 3. Both are full names and compare two GENERAL_NAMES. + * 4. One is NULL: automatic match. + */ + + +static int idp_check_dp(DIST_POINT_NAME *a, DIST_POINT_NAME *b) + { + X509_NAME *nm = NULL; + GENERAL_NAMES *gens = NULL; + GENERAL_NAME *gena, *genb; + size_t i, j; + if (!a || !b) + return 1; + if (a->type == 1) + { + if (!a->dpname) + return 0; + /* Case 1: two X509_NAME */ + if (b->type == 1) + { + if (!b->dpname) + return 0; + if (!X509_NAME_cmp(a->dpname, b->dpname)) + return 1; + else + return 0; + } + /* Case 2: set name and GENERAL_NAMES appropriately */ + nm = a->dpname; + gens = b->name.fullname; + } + else if (b->type == 1) + { + if (!b->dpname) + return 0; + /* Case 2: set name and GENERAL_NAMES appropriately */ + gens = a->name.fullname; + nm = b->dpname; + } + + /* Handle case 2 with one GENERAL_NAMES and one X509_NAME */ + if (nm) + { + for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) + { + gena = sk_GENERAL_NAME_value(gens, i); + if (gena->type != GEN_DIRNAME) + continue; + if (!X509_NAME_cmp(nm, gena->d.directoryName)) + return 1; + } + return 0; + } + + /* Else case 3: two GENERAL_NAMES */ + + for (i = 0; i < sk_GENERAL_NAME_num(a->name.fullname); i++) + { + gena = sk_GENERAL_NAME_value(a->name.fullname, i); + for (j = 0; j < sk_GENERAL_NAME_num(b->name.fullname); j++) + { + genb = sk_GENERAL_NAME_value(b->name.fullname, j); + if (!GENERAL_NAME_cmp(gena, genb)) + return 1; + } + } + + return 0; + + } + +static int crldp_check_crlissuer(DIST_POINT *dp, X509_CRL *crl, int crl_score) + { + size_t i; + X509_NAME *nm = X509_CRL_get_issuer(crl); + /* If no CRLissuer return is successful iff don't need a match */ + if (!dp->CRLissuer) + return !!(crl_score & CRL_SCORE_ISSUER_NAME); + for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) + { + GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i); + if (gen->type != GEN_DIRNAME) + continue; + if (!X509_NAME_cmp(gen->d.directoryName, nm)) + return 1; + } + return 0; + } + +/* Check CRLDP and IDP */ + +static int crl_crldp_check(X509 *x, X509_CRL *crl, int crl_score, + unsigned int *preasons) + { + size_t i; + if (crl->idp_flags & IDP_ONLYATTR) + return 0; + if (x->ex_flags & EXFLAG_CA) + { + if (crl->idp_flags & IDP_ONLYUSER) + return 0; + } + else + { + if (crl->idp_flags & IDP_ONLYCA) + return 0; + } + *preasons = crl->idp_reasons; + for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++) + { + DIST_POINT *dp = sk_DIST_POINT_value(x->crldp, i); + if (crldp_check_crlissuer(dp, crl, crl_score)) + { + if (!crl->idp || + idp_check_dp(dp->distpoint, crl->idp->distpoint)) + { + *preasons &= dp->dp_reasons; + return 1; + } + } + } + if ((!crl->idp || !crl->idp->distpoint) && (crl_score & CRL_SCORE_ISSUER_NAME)) + return 1; + return 0; + } + +/* Retrieve CRL corresponding to current certificate. + * If deltas enabled try to find a delta CRL too + */ + +static int get_crl_delta(X509_STORE_CTX *ctx, + X509_CRL **pcrl, X509_CRL **pdcrl, X509 *x) + { + int ok; + X509 *issuer = NULL; + int crl_score = 0; + unsigned int reasons; + X509_CRL *crl = NULL, *dcrl = NULL; + STACK_OF(X509_CRL) *skcrl; + X509_NAME *nm = X509_get_issuer_name(x); + reasons = ctx->current_reasons; + ok = get_crl_sk(ctx, &crl, &dcrl, + &issuer, &crl_score, &reasons, ctx->crls); + + if (ok) + goto done; + + /* Lookup CRLs from store */ + + skcrl = ctx->lookup_crls(ctx, nm); + + /* If no CRLs found and a near match from get_crl_sk use that */ + if (!skcrl && crl) + goto done; + + get_crl_sk(ctx, &crl, &dcrl, &issuer, &crl_score, &reasons, skcrl); + + sk_X509_CRL_pop_free(skcrl, X509_CRL_free); + + done: + + /* If we got any kind of CRL use it and return success */ + if (crl) + { + ctx->current_issuer = issuer; + ctx->current_crl_score = crl_score; + ctx->current_reasons = reasons; + *pcrl = crl; + *pdcrl = dcrl; + return 1; + } + + return 0; + } + +/* Check CRL validity */ +static int check_crl(X509_STORE_CTX *ctx, X509_CRL *crl) + { + X509 *issuer = NULL; + EVP_PKEY *ikey = NULL; + int ok = 0, chnum, cnum; + cnum = ctx->error_depth; + chnum = sk_X509_num(ctx->chain) - 1; + /* if we have an alternative CRL issuer cert use that */ + if (ctx->current_issuer) + issuer = ctx->current_issuer; + + /* Else find CRL issuer: if not last certificate then issuer + * is next certificate in chain. + */ + else if (cnum < chnum) + issuer = sk_X509_value(ctx->chain, cnum + 1); + else + { + issuer = sk_X509_value(ctx->chain, chnum); + /* If not self signed, can't check signature */ + if(!ctx->check_issued(ctx, issuer, issuer)) + { + ctx->error = X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER; + ok = ctx->verify_cb(0, ctx); + if(!ok) goto err; + } + } + + if(issuer) + { + /* Skip most tests for deltas because they have already + * been done + */ + if (!crl->base_crl_number) + { + /* Check for cRLSign bit if keyUsage present */ + if ((issuer->ex_flags & EXFLAG_KUSAGE) && + !(issuer->ex_kusage & KU_CRL_SIGN)) + { + ctx->error = X509_V_ERR_KEYUSAGE_NO_CRL_SIGN; + ok = ctx->verify_cb(0, ctx); + if(!ok) goto err; + } + + if (!(ctx->current_crl_score & CRL_SCORE_SCOPE)) + { + ctx->error = X509_V_ERR_DIFFERENT_CRL_SCOPE; + ok = ctx->verify_cb(0, ctx); + if(!ok) goto err; + } + + if (!(ctx->current_crl_score & CRL_SCORE_SAME_PATH)) + { + if (check_crl_path(ctx, ctx->current_issuer) <= 0) + { + ctx->error = X509_V_ERR_CRL_PATH_VALIDATION_ERROR; + ok = ctx->verify_cb(0, ctx); + if(!ok) goto err; + } + } + + if (crl->idp_flags & IDP_INVALID) + { + ctx->error = X509_V_ERR_INVALID_EXTENSION; + ok = ctx->verify_cb(0, ctx); + if(!ok) goto err; + } + + + } + + if (!(ctx->current_crl_score & CRL_SCORE_TIME)) + { + ok = check_crl_time(ctx, crl, 1); + if (!ok) + goto err; + } + + /* Attempt to get issuer certificate public key */ + ikey = X509_get_pubkey(issuer); + + if(!ikey) + { + ctx->error=X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY; + ok = ctx->verify_cb(0, ctx); + if (!ok) goto err; + } + else + { + int rv; + rv = X509_CRL_check_suiteb(crl, ikey, ctx->param->flags); + if (rv != X509_V_OK) + { + ctx->error=rv; + ok = ctx->verify_cb(0, ctx); + if (!ok) + goto err; + } + /* Verify CRL signature */ + if(X509_CRL_verify(crl, ikey) <= 0) + { + ctx->error=X509_V_ERR_CRL_SIGNATURE_FAILURE; + ok = ctx->verify_cb(0, ctx); + if (!ok) goto err; + } + } + } + + ok = 1; + + err: + EVP_PKEY_free(ikey); + return ok; + } + +/* Check certificate against CRL */ +static int cert_crl(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x) + { + int ok; + X509_REVOKED *rev; + /* The rules changed for this... previously if a CRL contained + * unhandled critical extensions it could still be used to indicate + * a certificate was revoked. This has since been changed since + * critical extension can change the meaning of CRL entries. + */ + if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) + && (crl->flags & EXFLAG_CRITICAL)) + { + ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION; + ok = ctx->verify_cb(0, ctx); + if(!ok) + return 0; + } + /* Look for serial number of certificate in CRL + * If found make sure reason is not removeFromCRL. + */ + if (X509_CRL_get0_by_cert(crl, &rev, x)) + { + if (rev->reason == CRL_REASON_REMOVE_FROM_CRL) + return 2; + ctx->error = X509_V_ERR_CERT_REVOKED; + ok = ctx->verify_cb(0, ctx); + if (!ok) + return 0; + } + + return 1; + } + +static int check_policy(X509_STORE_CTX *ctx) + { + int ret; + if (ctx->parent) + return 1; + ret = X509_policy_check(&ctx->tree, &ctx->explicit_policy, ctx->chain, + ctx->param->policies, ctx->param->flags); + if (ret == 0) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + /* Invalid or inconsistent extensions */ + if (ret == -1) + { + /* Locate certificates with bad extensions and notify + * callback. + */ + X509 *x; + size_t i; + for (i = 1; i < sk_X509_num(ctx->chain); i++) + { + x = sk_X509_value(ctx->chain, i); + if (!(x->ex_flags & EXFLAG_INVALID_POLICY)) + continue; + ctx->current_cert = x; + ctx->error = X509_V_ERR_INVALID_POLICY_EXTENSION; + if(!ctx->verify_cb(0, ctx)) + return 0; + } + return 1; + } + if (ret == -2) + { + ctx->current_cert = NULL; + ctx->error = X509_V_ERR_NO_EXPLICIT_POLICY; + return ctx->verify_cb(0, ctx); + } + + if (ctx->param->flags & X509_V_FLAG_NOTIFY_POLICY) + { + ctx->current_cert = NULL; + ctx->error = X509_V_OK; + if (!ctx->verify_cb(2, ctx)) + return 0; + } + + return 1; + } + +static int check_cert_time(X509_STORE_CTX *ctx, X509 *x) + { + time_t *ptime; + int i; + + if (ctx->param->flags & X509_V_FLAG_USE_CHECK_TIME) + ptime = &ctx->param->check_time; + else + ptime = NULL; + + i=X509_cmp_time(X509_get_notBefore(x), ptime); + if (i == 0) + { + ctx->error=X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD; + ctx->current_cert=x; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + + if (i > 0) + { + ctx->error=X509_V_ERR_CERT_NOT_YET_VALID; + ctx->current_cert=x; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + + i=X509_cmp_time(X509_get_notAfter(x), ptime); + if (i == 0) + { + ctx->error=X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD; + ctx->current_cert=x; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + + if (i < 0) + { + ctx->error=X509_V_ERR_CERT_HAS_EXPIRED; + ctx->current_cert=x; + if (!ctx->verify_cb(0, ctx)) + return 0; + } + + return 1; + } + +static int internal_verify(X509_STORE_CTX *ctx) + { + int ok=0,n; + X509 *xs,*xi; + EVP_PKEY *pkey=NULL; + int (*cb)(int xok,X509_STORE_CTX *xctx); + + cb=ctx->verify_cb; + + n=sk_X509_num(ctx->chain); + ctx->error_depth=n-1; + n--; + xi=sk_X509_value(ctx->chain,n); + + if (ctx->check_issued(ctx, xi, xi)) + xs=xi; + else + { + if (ctx->param->flags & X509_V_FLAG_PARTIAL_CHAIN) + { + xs = xi; + goto check_cert; + } + if (n <= 0) + { + ctx->error=X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE; + ctx->current_cert=xi; + ok=cb(0,ctx); + goto end; + } + else + { + n--; + ctx->error_depth=n; + xs=sk_X509_value(ctx->chain,n); + } + } + +/* ctx->error=0; not needed */ + while (n >= 0) + { + ctx->error_depth=n; + + /* Skip signature check for self signed certificates unless + * explicitly asked for. It doesn't add any security and + * just wastes time. + */ + if (!xs->valid && (xs != xi || (ctx->param->flags & X509_V_FLAG_CHECK_SS_SIGNATURE))) + { + if ((pkey=X509_get_pubkey(xi)) == NULL) + { + ctx->error=X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY; + ctx->current_cert=xi; + ok=(*cb)(0,ctx); + if (!ok) goto end; + } + else if (X509_verify(xs,pkey) <= 0) + { + ctx->error=X509_V_ERR_CERT_SIGNATURE_FAILURE; + ctx->current_cert=xs; + ok=(*cb)(0,ctx); + if (!ok) + { + EVP_PKEY_free(pkey); + goto end; + } + } + EVP_PKEY_free(pkey); + pkey=NULL; + } + + xs->valid = 1; + + check_cert: + ok = check_cert_time(ctx, xs); + if (!ok) + goto end; + + /* The last error (if any) is still in the error value */ + ctx->current_issuer=xi; + ctx->current_cert=xs; + ok=(*cb)(1,ctx); + if (!ok) goto end; + + n--; + if (n >= 0) + { + xi=xs; + xs=sk_X509_value(ctx->chain,n); + } + } + ok=1; +end: + return ok; + } + +int X509_cmp_current_time(const ASN1_TIME *ctm) +{ + return X509_cmp_time(ctm, NULL); +} + +int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time) + { + char *str; + ASN1_TIME atm; + long offset; + char buff1[24],buff2[24],*p; + int i, j, remaining; + + p=buff1; + remaining = ctm->length; + str=(char *)ctm->data; + /* Note that the following (historical) code allows much more slack in + * the time format than RFC5280. In RFC5280, the representation is + * fixed: + * UTCTime: YYMMDDHHMMSSZ + * GeneralizedTime: YYYYMMDDHHMMSSZ */ + if (ctm->type == V_ASN1_UTCTIME) + { + /* YYMMDDHHMM[SS]Z or YYMMDDHHMM[SS](+-)hhmm */ + int min_length = sizeof("YYMMDDHHMMZ") - 1; + int max_length = sizeof("YYMMDDHHMMSS+hhmm") - 1; + if (remaining < min_length || remaining > max_length) + return 0; + memcpy(p,str,10); + p+=10; + str+=10; + remaining -= 10; + } + else + { + /* YYYYMMDDHHMM[SS[.fff]]Z or YYYYMMDDHHMM[SS[.f[f[f]]]](+-)hhmm */ + int min_length = sizeof("YYYYMMDDHHMMZ") - 1; + int max_length = sizeof("YYYYMMDDHHMMSS.fff+hhmm") - 1; + if (remaining < min_length || remaining > max_length) + return 0; + memcpy(p,str,12); + p+=12; + str+=12; + remaining -= 12; + } + + if ((*str == 'Z') || (*str == '-') || (*str == '+')) + { *(p++)='0'; *(p++)='0'; } + else + { + /* SS (seconds) */ + if (remaining < 2) + return 0; + *(p++)= *(str++); + *(p++)= *(str++); + remaining -= 2; + /* Skip any (up to three) fractional seconds... + * TODO(emilia): in RFC5280, fractional seconds are forbidden. + * Can we just kill them altogether? */ + if (remaining && *str == '.') + { + str++; + remaining--; + for (i = 0; i < 3 && remaining; i++, str++, remaining--) + { + if (*str < '0' || *str > '9') + break; + } + } + + } + *(p++)='Z'; + *(p++)='\0'; + + /* We now need either a terminating 'Z' or an offset. */ + if (!remaining) + return 0; + if (*str == 'Z') + { + if (remaining != 1) + return 0; + offset=0; + } + else + { + /* (+-)HHMM */ + if ((*str != '+') && (*str != '-')) + return 0; + /* Historical behaviour: the (+-)hhmm offset is forbidden in RFC5280. */ + if (remaining != 5) + return 0; + if (str[1] < '0' || str[1] > '9' || str[2] < '0' || str[2] > '9' || + str[3] < '0' || str[3] > '9' || str[4] < '0' || str[4] > '9') + return 0; + offset=((str[1]-'0')*10+(str[2]-'0'))*60; + offset+=(str[3]-'0')*10+(str[4]-'0'); + if (*str == '-') + offset= -offset; + } + atm.type=ctm->type; + atm.flags = 0; + atm.length=sizeof(buff2); + atm.data=(unsigned char *)buff2; + + if (X509_time_adj(&atm, offset*60, cmp_time) == NULL) + return 0; + + if (ctm->type == V_ASN1_UTCTIME) + { + i=(buff1[0]-'0')*10+(buff1[1]-'0'); + if (i < 50) i+=100; /* cf. RFC 2459 */ + j=(buff2[0]-'0')*10+(buff2[1]-'0'); + if (j < 50) j+=100; + + if (i < j) return -1; + if (i > j) return 1; + } + i=strcmp(buff1,buff2); + if (i == 0) /* wait a second then return younger :-) */ + return -1; + else + return i; + } + +ASN1_TIME *X509_gmtime_adj(ASN1_TIME *s, long adj) +{ + return X509_time_adj(s, adj, NULL); +} + +ASN1_TIME *X509_time_adj(ASN1_TIME *s, long offset_sec, time_t *in_tm) + { + return X509_time_adj_ex(s, 0, offset_sec, in_tm); + } + +ASN1_TIME *X509_time_adj_ex(ASN1_TIME *s, + int offset_day, long offset_sec, time_t *in_tm) + { + time_t t = 0; + + if (in_tm) t = *in_tm; + else time(&t); + + if (s && !(s->flags & ASN1_STRING_FLAG_MSTRING)) + { + if (s->type == V_ASN1_UTCTIME) + return ASN1_UTCTIME_adj(s,t, offset_day, offset_sec); + if (s->type == V_ASN1_GENERALIZEDTIME) + return ASN1_GENERALIZEDTIME_adj(s, t, offset_day, + offset_sec); + } + return ASN1_TIME_adj(s, t, offset_day, offset_sec); + } + +/* Make a delta CRL as the diff between two full CRLs */ + +X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer, + EVP_PKEY *skey, const EVP_MD *md, unsigned int flags) + { + X509_CRL *crl = NULL; + int i; + size_t j; + STACK_OF(X509_REVOKED) *revs = NULL; + /* CRLs can't be delta already */ + if (base->base_crl_number || newer->base_crl_number) + { + OPENSSL_PUT_ERROR(X509, X509_R_CRL_ALREADY_DELTA); + return NULL; + } + /* Base and new CRL must have a CRL number */ + if (!base->crl_number || !newer->crl_number) + { + OPENSSL_PUT_ERROR(X509, X509_R_NO_CRL_NUMBER); + return NULL; + } + /* Issuer names must match */ + if (X509_NAME_cmp(X509_CRL_get_issuer(base), + X509_CRL_get_issuer(newer))) + { + OPENSSL_PUT_ERROR(X509, X509_R_ISSUER_MISMATCH); + return NULL; + } + /* AKID and IDP must match */ + if (!crl_extension_match(base, newer, NID_authority_key_identifier)) + { + OPENSSL_PUT_ERROR(X509, X509_R_AKID_MISMATCH); + return NULL; + } + if (!crl_extension_match(base, newer, NID_issuing_distribution_point)) + { + OPENSSL_PUT_ERROR(X509, X509_R_IDP_MISMATCH); + return NULL; + } + /* Newer CRL number must exceed full CRL number */ + if (ASN1_INTEGER_cmp(newer->crl_number, base->crl_number) <= 0) + { + OPENSSL_PUT_ERROR(X509, X509_R_NEWER_CRL_NOT_NEWER); + return NULL; + } + /* CRLs must verify */ + if (skey && (X509_CRL_verify(base, skey) <= 0 || + X509_CRL_verify(newer, skey) <= 0)) + { + OPENSSL_PUT_ERROR(X509, X509_R_CRL_VERIFY_FAILURE); + return NULL; + } + /* Create new CRL */ + crl = X509_CRL_new(); + if (!crl || !X509_CRL_set_version(crl, 1)) + goto memerr; + /* Set issuer name */ + if (!X509_CRL_set_issuer_name(crl, X509_CRL_get_issuer(newer))) + goto memerr; + + if (!X509_CRL_set_lastUpdate(crl, X509_CRL_get_lastUpdate(newer))) + goto memerr; + if (!X509_CRL_set_nextUpdate(crl, X509_CRL_get_nextUpdate(newer))) + goto memerr; + + /* Set base CRL number: must be critical */ + + if (!X509_CRL_add1_ext_i2d(crl, NID_delta_crl, base->crl_number, 1, 0)) + goto memerr; + + /* Copy extensions across from newest CRL to delta: this will set + * CRL number to correct value too. + */ + + for (i = 0; i < X509_CRL_get_ext_count(newer); i++) + { + X509_EXTENSION *ext; + ext = X509_CRL_get_ext(newer, i); + if (!X509_CRL_add_ext(crl, ext, -1)) + goto memerr; + } + + /* Go through revoked entries, copying as needed */ + + revs = X509_CRL_get_REVOKED(newer); + + for (j = 0; j < sk_X509_REVOKED_num(revs); j++) + { + X509_REVOKED *rvn, *rvtmp; + rvn = sk_X509_REVOKED_value(revs, j); + /* Add only if not also in base. + * TODO: need something cleverer here for some more complex + * CRLs covering multiple CAs. + */ + if (!X509_CRL_get0_by_serial(base, &rvtmp, rvn->serialNumber)) + { + rvtmp = X509_REVOKED_dup(rvn); + if (!rvtmp) + goto memerr; + if (!X509_CRL_add0_revoked(crl, rvtmp)) + { + X509_REVOKED_free(rvtmp); + goto memerr; + } + } + } + /* TODO: optionally prune deleted entries */ + + if (skey && md && !X509_CRL_sign(crl, skey, md)) + goto memerr; + + return crl; + + memerr: + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + if (crl) + X509_CRL_free(crl); + return NULL; + } + +int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) + { + /* This function is (usually) called only once, by + * SSL_get_ex_data_X509_STORE_CTX_idx (ssl/ssl_cert.c). */ + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, + new_func, dup_func, free_func)) + { + return -1; + } + return index; + } + +int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx, int idx, void *data) + { + return CRYPTO_set_ex_data(&ctx->ex_data,idx,data); + } + +void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx, int idx) + { + return CRYPTO_get_ex_data(&ctx->ex_data,idx); + } + +int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx) + { + return ctx->error; + } + +void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx, int err) + { + ctx->error=err; + } + +int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx) + { + return ctx->error_depth; + } + +X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx) + { + return ctx->current_cert; + } + +STACK_OF(X509) *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx) + { + return ctx->chain; + } + +STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx) + { + if (!ctx->chain) + return NULL; + return X509_chain_up_ref(ctx->chain); + } + +X509 *X509_STORE_CTX_get0_current_issuer(X509_STORE_CTX *ctx) + { + return ctx->current_issuer; + } + +X509_CRL *X509_STORE_CTX_get0_current_crl(X509_STORE_CTX *ctx) + { + return ctx->current_crl; + } + +X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(X509_STORE_CTX *ctx) + { + return ctx->parent; + } + +void X509_STORE_CTX_set_cert(X509_STORE_CTX *ctx, X509 *x) + { + ctx->cert=x; + } + +void X509_STORE_CTX_set_chain(X509_STORE_CTX *ctx, STACK_OF(X509) *sk) + { + ctx->untrusted=sk; + } + +void X509_STORE_CTX_set0_crls(X509_STORE_CTX *ctx, STACK_OF(X509_CRL) *sk) + { + ctx->crls=sk; + } + +int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose) + { + return X509_STORE_CTX_purpose_inherit(ctx, 0, purpose, 0); + } + +int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust) + { + return X509_STORE_CTX_purpose_inherit(ctx, 0, 0, trust); + } + +/* This function is used to set the X509_STORE_CTX purpose and trust + * values. This is intended to be used when another structure has its + * own trust and purpose values which (if set) will be inherited by + * the ctx. If they aren't set then we will usually have a default + * purpose in mind which should then be used to set the trust value. + * An example of this is SSL use: an SSL structure will have its own + * purpose and trust settings which the application can set: if they + * aren't set then we use the default of SSL client/server. + */ + +int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, + int purpose, int trust) +{ + int idx; + /* If purpose not set use default */ + if (!purpose) purpose = def_purpose; + /* If we have a purpose then check it is valid */ + if (purpose) + { + X509_PURPOSE *ptmp; + idx = X509_PURPOSE_get_by_id(purpose); + if (idx == -1) + { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_PURPOSE_ID); + return 0; + } + ptmp = X509_PURPOSE_get0(idx); + if (ptmp->trust == X509_TRUST_DEFAULT) + { + idx = X509_PURPOSE_get_by_id(def_purpose); + if (idx == -1) + { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_PURPOSE_ID); + return 0; + } + ptmp = X509_PURPOSE_get0(idx); + } + /* If trust not set then get from purpose default */ + if (!trust) trust = ptmp->trust; + } + if (trust) + { + idx = X509_TRUST_get_by_id(trust); + if (idx == -1) + { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_TRUST_ID); + return 0; + } + } + + if (purpose && !ctx->param->purpose) ctx->param->purpose = purpose; + if (trust && !ctx->param->trust) ctx->param->trust = trust; + return 1; +} + +X509_STORE_CTX *X509_STORE_CTX_new(void) +{ + X509_STORE_CTX *ctx; + ctx = (X509_STORE_CTX *)OPENSSL_malloc(sizeof(X509_STORE_CTX)); + if (!ctx) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return NULL; + } + memset(ctx, 0, sizeof(X509_STORE_CTX)); + return ctx; +} + +void X509_STORE_CTX_free(X509_STORE_CTX *ctx) +{ + X509_STORE_CTX_cleanup(ctx); + OPENSSL_free(ctx); +} + +int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, X509 *x509, + STACK_OF(X509) *chain) + { + int ret = 1; + int ex_data_allocated = 0; + + memset(ctx, 0, sizeof(X509_STORE_CTX)); + ctx->ctx=store; + ctx->cert=x509; + ctx->untrusted=chain; + + if(!CRYPTO_new_ex_data(&g_ex_data_class, ctx, + &ctx->ex_data)) + { + goto err; + } + ex_data_allocated = 1; + + ctx->param = X509_VERIFY_PARAM_new(); + if (!ctx->param) + goto err; + + /* Inherit callbacks and flags from X509_STORE if not set + * use defaults. */ + + if (store) + ret = X509_VERIFY_PARAM_inherit(ctx->param, store->param); + else + ctx->param->inh_flags |= X509_VP_FLAG_DEFAULT|X509_VP_FLAG_ONCE; + + if (store) + { + ctx->verify_cb = store->verify_cb; + ctx->cleanup = store->cleanup; + } + else + ctx->cleanup = 0; + + if (ret) + ret = X509_VERIFY_PARAM_inherit(ctx->param, + X509_VERIFY_PARAM_lookup("default")); + + if (ret == 0) + goto err; + + if (store && store->check_issued) + ctx->check_issued = store->check_issued; + else + ctx->check_issued = check_issued; + + if (store && store->get_issuer) + ctx->get_issuer = store->get_issuer; + else + ctx->get_issuer = X509_STORE_CTX_get1_issuer; + + if (store && store->verify_cb) + ctx->verify_cb = store->verify_cb; + else + ctx->verify_cb = null_callback; + + if (store && store->verify) + ctx->verify = store->verify; + else + ctx->verify = internal_verify; + + if (store && store->check_revocation) + ctx->check_revocation = store->check_revocation; + else + ctx->check_revocation = check_revocation; + + if (store && store->get_crl) + ctx->get_crl = store->get_crl; + else + ctx->get_crl = NULL; + + if (store && store->check_crl) + ctx->check_crl = store->check_crl; + else + ctx->check_crl = check_crl; + + if (store && store->cert_crl) + ctx->cert_crl = store->cert_crl; + else + ctx->cert_crl = cert_crl; + + if (store && store->lookup_certs) + ctx->lookup_certs = store->lookup_certs; + else + ctx->lookup_certs = X509_STORE_get1_certs; + + if (store && store->lookup_crls) + ctx->lookup_crls = store->lookup_crls; + else + ctx->lookup_crls = X509_STORE_get1_crls; + + ctx->check_policy = check_policy; + + return 1; + +err: + if (ex_data_allocated) + { + CRYPTO_free_ex_data(&g_ex_data_class, ctx, &ctx->ex_data); + } + if (ctx->param != NULL) + { + X509_VERIFY_PARAM_free(ctx->param); + } + + memset(ctx, 0, sizeof(X509_STORE_CTX)); + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + +/* Set alternative lookup method: just a STACK of trusted certificates. + * This avoids X509_STORE nastiness where it isn't needed. + */ + +void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk) +{ + ctx->other_ctx = sk; + ctx->get_issuer = get_issuer_sk; +} + +void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx) + { + if (ctx->cleanup) ctx->cleanup(ctx); + if (ctx->param != NULL) + { + if (ctx->parent == NULL) + X509_VERIFY_PARAM_free(ctx->param); + ctx->param=NULL; + } + if (ctx->tree != NULL) + { + X509_policy_tree_free(ctx->tree); + ctx->tree=NULL; + } + if (ctx->chain != NULL) + { + sk_X509_pop_free(ctx->chain,X509_free); + ctx->chain=NULL; + } + CRYPTO_free_ex_data(&g_ex_data_class, ctx, &(ctx->ex_data)); + memset(&ctx->ex_data,0,sizeof(CRYPTO_EX_DATA)); + } + +void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth) + { + X509_VERIFY_PARAM_set_depth(ctx->param, depth); + } + +void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags) + { + X509_VERIFY_PARAM_set_flags(ctx->param, flags); + } + +void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags, time_t t) + { + X509_VERIFY_PARAM_set_time(ctx->param, t); + } + +void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx, + int (*verify_cb)(int, X509_STORE_CTX *)) + { + ctx->verify_cb=verify_cb; + } + +X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx) + { + return ctx->tree; + } + +int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx) + { + return ctx->explicit_policy; + } + +int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name) + { + const X509_VERIFY_PARAM *param; + param = X509_VERIFY_PARAM_lookup(name); + if (!param) + return 0; + return X509_VERIFY_PARAM_inherit(ctx->param, param); + } + +X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx) + { + return ctx->param; + } + +void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param) + { + if (ctx->param) + X509_VERIFY_PARAM_free(ctx->param); + ctx->param = param; + } + +IMPLEMENT_ASN1_SET_OF(X509) +IMPLEMENT_ASN1_SET_OF(X509_ATTRIBUTE) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509_vpm.c b/TMessagesProj/jni/boringssl/crypto/x509/x509_vpm.c new file mode 100644 index 00000000..8c8f98ea --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509_vpm.c @@ -0,0 +1,672 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "vpm_int.h" + + +/* X509_VERIFY_PARAM functions */ + +#define SET_HOST 0 +#define ADD_HOST 1 + +static char *str_copy(char *s) { return OPENSSL_strdup(s); } +static void str_free(char *s) { OPENSSL_free(s); } + +#define string_stack_free(sk) sk_OPENSSL_STRING_pop_free(sk, str_free) + +static int int_x509_param_set_hosts(X509_VERIFY_PARAM_ID *id, int mode, + const char *name, size_t namelen) + { + char *copy; + + /* + * Refuse names with embedded NUL bytes. + * XXX: Do we need to push an error onto the error stack? + */ + if (name && memchr(name, '\0', namelen)) + return 0; + + if (mode == SET_HOST && id->hosts) + { + string_stack_free(id->hosts); + id->hosts = NULL; + } + if (name == NULL || namelen == 0) + return 1; + + copy = BUF_strndup(name, namelen); + if (copy == NULL) + return 0; + + if (id->hosts == NULL && + (id->hosts = sk_OPENSSL_STRING_new_null()) == NULL) + { + OPENSSL_free(copy); + return 0; + } + + if (!sk_OPENSSL_STRING_push(id->hosts, copy)) + { + OPENSSL_free(copy); + if (sk_OPENSSL_STRING_num(id->hosts) == 0) + { + sk_OPENSSL_STRING_free(id->hosts); + id->hosts = NULL; + } + return 0; + } + + return 1; + } + +static void x509_verify_param_zero(X509_VERIFY_PARAM *param) + { + X509_VERIFY_PARAM_ID *paramid; + if (!param) + return; + param->name = NULL; + param->purpose = 0; + param->trust = 0; + /*param->inh_flags = X509_VP_FLAG_DEFAULT;*/ + param->inh_flags = 0; + param->flags = 0; + param->depth = -1; + if (param->policies) + { + sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free); + param->policies = NULL; + } + paramid = param->id; + if (paramid->hosts) + { + string_stack_free(paramid->hosts); + paramid->hosts = NULL; + } + if (paramid->peername) + { + OPENSSL_free(paramid->peername); + paramid->peername = NULL; + } + if (paramid->email) + { + OPENSSL_free(paramid->email); + paramid->email = NULL; + paramid->emaillen = 0; + } + if (paramid->ip) + { + OPENSSL_free(paramid->ip); + paramid->ip = NULL; + paramid->iplen = 0; + } + + } + +X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void) + { + X509_VERIFY_PARAM *param; + X509_VERIFY_PARAM_ID *paramid; + param = OPENSSL_malloc(sizeof(X509_VERIFY_PARAM)); + if (!param) + return NULL; + paramid = OPENSSL_malloc(sizeof(X509_VERIFY_PARAM_ID)); + if (!paramid) + { + OPENSSL_free(param); + return NULL; + } + memset(param, 0, sizeof(X509_VERIFY_PARAM)); + memset(paramid, 0, sizeof(X509_VERIFY_PARAM_ID)); + param->id = paramid; + x509_verify_param_zero(param); + return param; + } + +void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param) + { + if (param == NULL) + return; + x509_verify_param_zero(param); + OPENSSL_free(param->id); + OPENSSL_free(param); + } + +/* This function determines how parameters are "inherited" from one structure + * to another. There are several different ways this can happen. + * + * 1. If a child structure needs to have its values initialized from a parent + * they are simply copied across. For example SSL_CTX copied to SSL. + * 2. If the structure should take on values only if they are currently unset. + * For example the values in an SSL structure will take appropriate value + * for SSL servers or clients but only if the application has not set new + * ones. + * + * The "inh_flags" field determines how this function behaves. + * + * Normally any values which are set in the default are not copied from the + * destination and verify flags are ORed together. + * + * If X509_VP_FLAG_DEFAULT is set then anything set in the source is copied + * to the destination. Effectively the values in "to" become default values + * which will be used only if nothing new is set in "from". + * + * If X509_VP_FLAG_OVERWRITE is set then all value are copied across whether + * they are set or not. Flags is still Ored though. + * + * If X509_VP_FLAG_RESET_FLAGS is set then the flags value is copied instead + * of ORed. + * + * If X509_VP_FLAG_LOCKED is set then no values are copied. + * + * If X509_VP_FLAG_ONCE is set then the current inh_flags setting is zeroed + * after the next call. + */ + +/* Macro to test if a field should be copied from src to dest */ + +#define test_x509_verify_param_copy(field, def) \ + (to_overwrite || \ + ((src->field != def) && (to_default || (dest->field == def)))) + +/* As above but for ID fields */ + +#define test_x509_verify_param_copy_id(idf, def) \ + test_x509_verify_param_copy(id->idf, def) + +/* Macro to test and copy a field if necessary */ + +#define x509_verify_param_copy(field, def) \ + if (test_x509_verify_param_copy(field, def)) \ + dest->field = src->field + + +int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest, + const X509_VERIFY_PARAM *src) + { + unsigned long inh_flags; + int to_default, to_overwrite; + X509_VERIFY_PARAM_ID *id; + if (!src) + return 1; + id = src->id; + inh_flags = dest->inh_flags | src->inh_flags; + + if (inh_flags & X509_VP_FLAG_ONCE) + dest->inh_flags = 0; + + if (inh_flags & X509_VP_FLAG_LOCKED) + return 1; + + if (inh_flags & X509_VP_FLAG_DEFAULT) + to_default = 1; + else + to_default = 0; + + if (inh_flags & X509_VP_FLAG_OVERWRITE) + to_overwrite = 1; + else + to_overwrite = 0; + + x509_verify_param_copy(purpose, 0); + x509_verify_param_copy(trust, 0); + x509_verify_param_copy(depth, -1); + + /* If overwrite or check time not set, copy across */ + + if (to_overwrite || !(dest->flags & X509_V_FLAG_USE_CHECK_TIME)) + { + dest->check_time = src->check_time; + dest->flags &= ~X509_V_FLAG_USE_CHECK_TIME; + /* Don't need to copy flag: that is done below */ + } + + if (inh_flags & X509_VP_FLAG_RESET_FLAGS) + dest->flags = 0; + + dest->flags |= src->flags; + + if (test_x509_verify_param_copy(policies, NULL)) + { + if (!X509_VERIFY_PARAM_set1_policies(dest, src->policies)) + return 0; + } + + /* Copy the host flags if and only if we're copying the host list */ + if (test_x509_verify_param_copy_id(hosts, NULL)) + { + if (dest->id->hosts) + { + string_stack_free(dest->id->hosts); + dest->id->hosts = NULL; + } + if (id->hosts) + { + dest->id->hosts = + sk_OPENSSL_STRING_deep_copy(id->hosts, + str_copy, str_free); + if (dest->id->hosts == NULL) + return 0; + dest->id->hostflags = id->hostflags; + } + } + + if (test_x509_verify_param_copy_id(email, NULL)) + { + if (!X509_VERIFY_PARAM_set1_email(dest, id->email, id->emaillen)) + return 0; + } + + if (test_x509_verify_param_copy_id(ip, NULL)) + { + if (!X509_VERIFY_PARAM_set1_ip(dest, id->ip, id->iplen)) + return 0; + } + + return 1; + } + +int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from) + { + unsigned long save_flags = to->inh_flags; + int ret; + to->inh_flags |= X509_VP_FLAG_DEFAULT; + ret = X509_VERIFY_PARAM_inherit(to, from); + to->inh_flags = save_flags; + return ret; + } + +static int int_x509_param_set1(char **pdest, size_t *pdestlen, + const char *src, size_t srclen) + { + void *tmp; + if (src) + { + if (srclen == 0) + { + tmp = BUF_strdup(src); + srclen = strlen(src); + } + else + tmp = BUF_memdup(src, srclen); + if (!tmp) + return 0; + } + else + { + tmp = NULL; + srclen = 0; + } + if (*pdest) + OPENSSL_free(*pdest); + *pdest = tmp; + if (pdestlen) + *pdestlen = srclen; + return 1; + } + +int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name) + { + if (param->name) + OPENSSL_free(param->name); + param->name = BUF_strdup(name); + if (param->name) + return 1; + return 0; + } + +int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags) + { + param->flags |= flags; + if (flags & X509_V_FLAG_POLICY_MASK) + param->flags |= X509_V_FLAG_POLICY_CHECK; + return 1; + } + +int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, unsigned long flags) + { + param->flags &= ~flags; + return 1; + } + +unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param) + { + return param->flags; + } + +int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose) + { + return X509_PURPOSE_set(¶m->purpose, purpose); + } + +int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust) + { + return X509_TRUST_set(¶m->trust, trust); + } + +void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth) + { + param->depth = depth; + } + +void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t) + { + param->check_time = t; + param->flags |= X509_V_FLAG_USE_CHECK_TIME; + } + +int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, ASN1_OBJECT *policy) + { + if (!param->policies) + { + param->policies = sk_ASN1_OBJECT_new_null(); + if (!param->policies) + return 0; + } + if (!sk_ASN1_OBJECT_push(param->policies, policy)) + return 0; + return 1; + } + +int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, + STACK_OF(ASN1_OBJECT) *policies) + { + size_t i; + ASN1_OBJECT *oid, *doid; + if (!param) + return 0; + if (param->policies) + sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free); + + if (!policies) + { + param->policies = NULL; + return 1; + } + + param->policies = sk_ASN1_OBJECT_new_null(); + if (!param->policies) + return 0; + + for (i = 0; i < sk_ASN1_OBJECT_num(policies); i++) + { + oid = sk_ASN1_OBJECT_value(policies, i); + doid = OBJ_dup(oid); + if (!doid) + return 0; + if (!sk_ASN1_OBJECT_push(param->policies, doid)) + { + ASN1_OBJECT_free(doid); + return 0; + } + } + param->flags |= X509_V_FLAG_POLICY_CHECK; + return 1; + } + +int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param, + const char *name, size_t namelen) + { + return int_x509_param_set_hosts(param->id, SET_HOST, name, namelen); + } + +int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param, + const char *name, size_t namelen) + { + return int_x509_param_set_hosts(param->id, ADD_HOST, name, namelen); + } + +void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param, + unsigned int flags) + { + param->id->hostflags = flags; + } + +char *X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *param) + { + return param->id->peername; + } + +int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, + const char *email, size_t emaillen) + { + return int_x509_param_set1(¶m->id->email, ¶m->id->emaillen, + email, emaillen); + } + +int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, + const unsigned char *ip, size_t iplen) + { + if (iplen != 0 && iplen != 4 && iplen != 16) + return 0; + return int_x509_param_set1((char **)¶m->id->ip, ¶m->id->iplen, + (char *)ip, iplen); + } + +int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc) + { + unsigned char ipout[16]; + size_t iplen; + + iplen = (size_t) a2i_ipadd(ipout, ipasc); + if (iplen == 0) + return 0; + return X509_VERIFY_PARAM_set1_ip(param, ipout, iplen); + } + +int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param) + { + return param->depth; + } + +const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param) + { + return param->name; + } + +static const X509_VERIFY_PARAM_ID _empty_id = {NULL, 0U, NULL, NULL, 0, NULL, 0}; + +#define vpm_empty_id (X509_VERIFY_PARAM_ID *)&_empty_id + +/* Default verify parameters: these are used for various + * applications and can be overridden by the user specified table. + * NB: the 'name' field *must* be in alphabetical order because it + * will be searched using OBJ_search. + */ + +static const X509_VERIFY_PARAM default_table[] = { + { + (char *) "default", /* X509 default parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + 0, /* purpose */ + 0, /* trust */ + 100, /* depth */ + NULL, /* policies */ + vpm_empty_id + }, + { + (char *) "pkcs7", /* S/MIME sign parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + X509_PURPOSE_SMIME_SIGN, /* purpose */ + X509_TRUST_EMAIL, /* trust */ + -1, /* depth */ + NULL, /* policies */ + vpm_empty_id + }, + { + (char *) "smime_sign", /* S/MIME sign parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + X509_PURPOSE_SMIME_SIGN, /* purpose */ + X509_TRUST_EMAIL, /* trust */ + -1, /* depth */ + NULL, /* policies */ + vpm_empty_id + }, + { + (char *) "ssl_client", /* SSL/TLS client parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + X509_PURPOSE_SSL_CLIENT, /* purpose */ + X509_TRUST_SSL_CLIENT, /* trust */ + -1, /* depth */ + NULL, /* policies */ + vpm_empty_id + }, + { + (char *) "ssl_server", /* SSL/TLS server parameters */ + 0, /* Check time */ + 0, /* internal flags */ + 0, /* flags */ + X509_PURPOSE_SSL_SERVER, /* purpose */ + X509_TRUST_SSL_SERVER, /* trust */ + -1, /* depth */ + NULL, /* policies */ + vpm_empty_id + }}; + +static STACK_OF(X509_VERIFY_PARAM) *param_table = NULL; + +static int param_cmp(const X509_VERIFY_PARAM **a, + const X509_VERIFY_PARAM **b) + { + return strcmp((*a)->name, (*b)->name); + } + +int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param) + { + X509_VERIFY_PARAM *ptmp; + if (!param_table) + { + param_table = sk_X509_VERIFY_PARAM_new(param_cmp); + if (!param_table) + return 0; + } + else + { + size_t idx; + + if (sk_X509_VERIFY_PARAM_find(param_table, &idx, param)) + { + ptmp = sk_X509_VERIFY_PARAM_value(param_table, idx); + X509_VERIFY_PARAM_free(ptmp); + (void)sk_X509_VERIFY_PARAM_delete(param_table, idx); + } + } + if (!sk_X509_VERIFY_PARAM_push(param_table, param)) + return 0; + return 1; + } + +int X509_VERIFY_PARAM_get_count(void) + { + int num = sizeof(default_table)/sizeof(X509_VERIFY_PARAM); + if (param_table) + num += sk_X509_VERIFY_PARAM_num(param_table); + return num; + } + +const X509_VERIFY_PARAM *X509_VERIFY_PARAM_get0(int id) + { + int num = sizeof(default_table)/sizeof(X509_VERIFY_PARAM); + if (id < num) + return default_table + id; + return sk_X509_VERIFY_PARAM_value(param_table, id - num); + } + +const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name) + { + X509_VERIFY_PARAM pm; + unsigned i, limit; + + pm.name = (char *)name; + if (param_table) + { + size_t idx; + if (sk_X509_VERIFY_PARAM_find(param_table, &idx, &pm)) + return sk_X509_VERIFY_PARAM_value(param_table, idx); + } + + limit = sizeof(default_table)/sizeof(X509_VERIFY_PARAM); + for (i = 0; i < limit; i++) { + if (strcmp(default_table[i].name, name) == 0) { + return &default_table[i]; + } + } + return NULL; + } + +void X509_VERIFY_PARAM_table_cleanup(void) + { + if (param_table) + sk_X509_VERIFY_PARAM_pop_free(param_table, + X509_VERIFY_PARAM_free); + param_table = NULL; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509cset.c b/TMessagesProj/jni/boringssl/crypto/x509/x509cset.c new file mode 100644 index 00000000..b526c69d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509cset.c @@ -0,0 +1,165 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2001. */ +/* ==================================================================== + * Copyright (c) 2001 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include +#include +#include + + +int X509_CRL_set_version(X509_CRL *x, long version) + { + if (x == NULL) return(0); + if (x->crl->version == NULL) + { + if ((x->crl->version=M_ASN1_INTEGER_new()) == NULL) + return(0); + } + return(ASN1_INTEGER_set(x->crl->version,version)); + } + +int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name) + { + if ((x == NULL) || (x->crl == NULL)) return(0); + return(X509_NAME_set(&x->crl->issuer,name)); + } + + +int X509_CRL_set_lastUpdate(X509_CRL *x, const ASN1_TIME *tm) + { + ASN1_TIME *in; + + if (x == NULL) return(0); + in=x->crl->lastUpdate; + if (in != tm) + { + in=M_ASN1_TIME_dup(tm); + if (in != NULL) + { + M_ASN1_TIME_free(x->crl->lastUpdate); + x->crl->lastUpdate=in; + } + } + return(in != NULL); + } + +int X509_CRL_set_nextUpdate(X509_CRL *x, const ASN1_TIME *tm) + { + ASN1_TIME *in; + + if (x == NULL) return(0); + in=x->crl->nextUpdate; + if (in != tm) + { + in=M_ASN1_TIME_dup(tm); + if (in != NULL) + { + M_ASN1_TIME_free(x->crl->nextUpdate); + x->crl->nextUpdate=in; + } + } + return(in != NULL); + } + +int X509_CRL_sort(X509_CRL *c) + { + size_t i; + X509_REVOKED *r; + /* sort the data so it will be written in serial + * number order */ + sk_X509_REVOKED_sort(c->crl->revoked); + for (i=0; icrl->revoked); i++) + { + r=sk_X509_REVOKED_value(c->crl->revoked,i); + r->sequence=i; + } + c->crl->enc.modified = 1; + return 1; + } + +int X509_REVOKED_set_revocationDate(X509_REVOKED *x, ASN1_TIME *tm) + { + ASN1_TIME *in; + + if (x == NULL) return(0); + in=x->revocationDate; + if (in != tm) + { + in=M_ASN1_TIME_dup(tm); + if (in != NULL) + { + M_ASN1_TIME_free(x->revocationDate); + x->revocationDate=in; + } + } + return(in != NULL); + } + +int X509_REVOKED_set_serialNumber(X509_REVOKED *x, ASN1_INTEGER *serial) + { + ASN1_INTEGER *in; + + if (x == NULL) return(0); + in=x->serialNumber; + if (in != serial) + { + in=M_ASN1_INTEGER_dup(serial); + if (in != NULL) + { + M_ASN1_INTEGER_free(x->serialNumber); + x->serialNumber=in; + } + } + return(in != NULL); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509name.c b/TMessagesProj/jni/boringssl/crypto/x509/x509name.c new file mode 100644 index 00000000..7bb3aa15 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509name.c @@ -0,0 +1,381 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include +#include + + +int X509_NAME_get_text_by_NID(X509_NAME *name, int nid, char *buf, int len) + { + const ASN1_OBJECT *obj; + + obj=OBJ_nid2obj(nid); + if (obj == NULL) return(-1); + return(X509_NAME_get_text_by_OBJ(name,obj,buf,len)); + } + +int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, char *buf, + int len) + { + int i; + ASN1_STRING *data; + + i=X509_NAME_get_index_by_OBJ(name,obj,-1); + if (i < 0) return(-1); + data=X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i)); + i=(data->length > (len-1))?(len-1):data->length; + if (buf == NULL) return(data->length); + memcpy(buf,data->data,i); + buf[i]='\0'; + return(i); + } + +int X509_NAME_entry_count(X509_NAME *name) + { + if (name == NULL) return(0); + return(sk_X509_NAME_ENTRY_num(name->entries)); + } + +int X509_NAME_get_index_by_NID(X509_NAME *name, int nid, int lastpos) + { + const ASN1_OBJECT *obj; + + obj=OBJ_nid2obj(nid); + if (obj == NULL) return(-2); + return(X509_NAME_get_index_by_OBJ(name,obj,lastpos)); + } + +/* NOTE: you should be passsing -1, not 0 as lastpos */ +int X509_NAME_get_index_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, + int lastpos) + { + int n; + X509_NAME_ENTRY *ne; + STACK_OF(X509_NAME_ENTRY) *sk; + + if (name == NULL) return(-1); + if (lastpos < 0) + lastpos= -1; + sk=name->entries; + n=sk_X509_NAME_ENTRY_num(sk); + for (lastpos++; lastpos < n; lastpos++) + { + ne=sk_X509_NAME_ENTRY_value(sk,lastpos); + if (OBJ_cmp(ne->object,obj) == 0) + return(lastpos); + } + return(-1); + } + +X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *name, int loc) + { + if(name == NULL || loc < 0 || sk_X509_NAME_ENTRY_num(name->entries) <= (size_t) loc) + return(NULL); + else + return(sk_X509_NAME_ENTRY_value(name->entries,loc)); + } + +X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc) + { + X509_NAME_ENTRY *ret; + int i,n,set_prev,set_next; + STACK_OF(X509_NAME_ENTRY) *sk; + + if (name == NULL || loc < 0 || sk_X509_NAME_ENTRY_num(name->entries) <= (size_t) loc) + return(NULL); + sk=name->entries; + ret=sk_X509_NAME_ENTRY_delete(sk,loc); + n=sk_X509_NAME_ENTRY_num(sk); + name->modified=1; + if (loc == n) return(ret); + + /* else we need to fixup the set field */ + if (loc != 0) + set_prev=(sk_X509_NAME_ENTRY_value(sk,loc-1))->set; + else + set_prev=ret->set-1; + set_next=sk_X509_NAME_ENTRY_value(sk,loc)->set; + + /* set_prev is the previous set + * set is the current set + * set_next is the following + * prev 1 1 1 1 1 1 1 1 + * set 1 1 2 2 + * next 1 1 2 2 2 2 3 2 + * so basically only if prev and next differ by 2, then + * re-number down by 1 */ + if (set_prev+1 < set_next) + for (i=loc; iset--; + return(ret); + } + +int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type, + unsigned char *bytes, int len, int loc, int set) +{ + X509_NAME_ENTRY *ne; + int ret; + ne = X509_NAME_ENTRY_create_by_OBJ(NULL, obj, type, bytes, len); + if(!ne) return 0; + ret = X509_NAME_add_entry(name, ne, loc, set); + X509_NAME_ENTRY_free(ne); + return ret; +} + +int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type, + unsigned char *bytes, int len, int loc, int set) +{ + X509_NAME_ENTRY *ne; + int ret; + ne = X509_NAME_ENTRY_create_by_NID(NULL, nid, type, bytes, len); + if(!ne) return 0; + ret = X509_NAME_add_entry(name, ne, loc, set); + X509_NAME_ENTRY_free(ne); + return ret; +} + +int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type, + const unsigned char *bytes, int len, int loc, int set) +{ + X509_NAME_ENTRY *ne; + int ret; + ne = X509_NAME_ENTRY_create_by_txt(NULL, field, type, bytes, len); + if(!ne) return 0; + ret = X509_NAME_add_entry(name, ne, loc, set); + X509_NAME_ENTRY_free(ne); + return ret; +} + +/* if set is -1, append to previous set, 0 'a new one', and 1, + * prepend to the guy we are about to stomp on. */ +int X509_NAME_add_entry(X509_NAME *name, X509_NAME_ENTRY *ne, int loc, + int set) + { + X509_NAME_ENTRY *new_name=NULL; + int n,i,inc; + STACK_OF(X509_NAME_ENTRY) *sk; + + if (name == NULL) return(0); + sk=name->entries; + n=sk_X509_NAME_ENTRY_num(sk); + if (loc > n) loc=n; + else if (loc < 0) loc=n; + + name->modified=1; + + if (set == -1) + { + if (loc == 0) + { + set=0; + inc=1; + } + else + { + set=sk_X509_NAME_ENTRY_value(sk,loc-1)->set; + inc=0; + } + } + else /* if (set >= 0) */ + { + if (loc >= n) + { + if (loc != 0) + set=sk_X509_NAME_ENTRY_value(sk,loc-1)->set+1; + else + set=0; + } + else + set=sk_X509_NAME_ENTRY_value(sk,loc)->set; + inc=(set == 0)?1:0; + } + + if ((new_name=X509_NAME_ENTRY_dup(ne)) == NULL) + goto err; + new_name->set=set; + if (!sk_X509_NAME_ENTRY_insert(sk,new_name,loc)) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto err; + } + if (inc) + { + n=sk_X509_NAME_ENTRY_num(sk); + for (i=loc+1; iset+=1; + } + return(1); +err: + if (new_name != NULL) + X509_NAME_ENTRY_free(new_name); + return(0); + } + +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne, + const char *field, int type, const unsigned char *bytes, int len) + { + ASN1_OBJECT *obj; + X509_NAME_ENTRY *nentry; + + obj=OBJ_txt2obj(field, 0); + if (obj == NULL) + { + OPENSSL_PUT_ERROR(X509, X509_R_INVALID_FIELD_NAME); + ERR_add_error_data(2, "name=", field); + return(NULL); + } + nentry = X509_NAME_ENTRY_create_by_OBJ(ne,obj,type,bytes,len); + ASN1_OBJECT_free(obj); + return nentry; + } + +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid, + int type, unsigned char *bytes, int len) + { + const ASN1_OBJECT *obj; + X509_NAME_ENTRY *nentry; + + obj=OBJ_nid2obj(nid); + if (obj == NULL) + { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_NID); + return(NULL); + } + nentry = X509_NAME_ENTRY_create_by_OBJ(ne,obj,type,bytes,len); + /* TODO(fork): remove this? */ + /* ASN1_OBJECT_free(obj); */ + return nentry; + } + +X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne, + const ASN1_OBJECT *obj, int type, const unsigned char *bytes, int len) + { + X509_NAME_ENTRY *ret; + + if ((ne == NULL) || (*ne == NULL)) + { + if ((ret=X509_NAME_ENTRY_new()) == NULL) + return(NULL); + } + else + ret= *ne; + + if (!X509_NAME_ENTRY_set_object(ret,obj)) + goto err; + if (!X509_NAME_ENTRY_set_data(ret,type,bytes,len)) + goto err; + + if ((ne != NULL) && (*ne == NULL)) *ne=ret; + return(ret); +err: + if ((ne == NULL) || (ret != *ne)) + X509_NAME_ENTRY_free(ret); + return(NULL); + } + +int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne, const ASN1_OBJECT *obj) + { + if ((ne == NULL) || (obj == NULL)) + { + OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER); + return(0); + } + ASN1_OBJECT_free(ne->object); + ne->object=OBJ_dup(obj); + return((ne->object == NULL)?0:1); + } + +int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type, + const unsigned char *bytes, int len) + { + int i; + + if ((ne == NULL) || ((bytes == NULL) && (len != 0))) return(0); + if((type > 0) && (type & MBSTRING_FLAG)) + return ASN1_STRING_set_by_NID(&ne->value, bytes, + len, type, + OBJ_obj2nid(ne->object)) ? 1 : 0; + if (len < 0) len=strlen((const char *)bytes); + i=ASN1_STRING_set(ne->value,bytes,len); + if (!i) return(0); + if (type != V_ASN1_UNDEF) + { + if (type == V_ASN1_APP_CHOOSE) + ne->value->type=ASN1_PRINTABLE_type(bytes,len); + else + ne->value->type=type; + } + return(1); + } + +ASN1_OBJECT *X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *ne) + { + if (ne == NULL) return(NULL); + return(ne->object); + } + +ASN1_STRING *X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *ne) + { + if (ne == NULL) return(NULL); + return(ne->value); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509rset.c b/TMessagesProj/jni/boringssl/crypto/x509/x509rset.c new file mode 100644 index 00000000..dbab555d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509rset.c @@ -0,0 +1,80 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include + + +int X509_REQ_set_version(X509_REQ *x, long version) + { + if (x == NULL) return(0); + return(ASN1_INTEGER_set(x->req_info->version,version)); + } + +int X509_REQ_set_subject_name(X509_REQ *x, X509_NAME *name) + { + if ((x == NULL) || (x->req_info == NULL)) return(0); + return(X509_NAME_set(&x->req_info->subject,name)); + } + +int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey) + { + if ((x == NULL) || (x->req_info == NULL)) return(0); + return(X509_PUBKEY_set(&x->req_info->pubkey,pkey)); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509spki.c b/TMessagesProj/jni/boringssl/crypto/x509/x509spki.c new file mode 100644 index 00000000..ccf93e06 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509spki.c @@ -0,0 +1,135 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include + + +int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey) +{ + if ((x == NULL) || (x->spkac == NULL)) return(0); + return(X509_PUBKEY_set(&(x->spkac->pubkey),pkey)); +} + +EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *x) +{ + if ((x == NULL) || (x->spkac == NULL)) + return(NULL); + return(X509_PUBKEY_get(x->spkac->pubkey)); +} + +/* Load a Netscape SPKI from a base64 encoded string */ + +NETSCAPE_SPKI * NETSCAPE_SPKI_b64_decode(const char *str, int len) +{ + unsigned char *spki_der; + const unsigned char *p; + size_t spki_len; + NETSCAPE_SPKI *spki; + if (len <= 0) + len = strlen(str); + if (!EVP_DecodedLength(&spki_len, len)) { + OPENSSL_PUT_ERROR(X509, X509_R_BASE64_DECODE_ERROR); + return NULL; + } + if (!(spki_der = OPENSSL_malloc(spki_len))) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return NULL; + } + if (!EVP_DecodeBase64(spki_der, &spki_len, spki_len, (const uint8_t *)str, len)) { + OPENSSL_PUT_ERROR(X509, X509_R_BASE64_DECODE_ERROR); + OPENSSL_free(spki_der); + return NULL; + } + p = spki_der; + spki = d2i_NETSCAPE_SPKI(NULL, &p, spki_len); + OPENSSL_free(spki_der); + return spki; +} + +/* Generate a base64 encoded string from an SPKI */ + +char * NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *spki) +{ + unsigned char *der_spki, *p; + char *b64_str; + size_t b64_len; + int der_len; + der_len = i2d_NETSCAPE_SPKI(spki, NULL); + if (!EVP_EncodedLength(&b64_len, der_len)) + { + OPENSSL_PUT_ERROR(X509, ERR_R_OVERFLOW); + return NULL; + } + der_spki = OPENSSL_malloc(der_len); + if (der_spki == NULL) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return NULL; + } + b64_str = OPENSSL_malloc(b64_len); + if (b64_str == NULL) { + OPENSSL_free(der_spki); + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return NULL; + } + p = der_spki; + i2d_NETSCAPE_SPKI(spki, &p); + EVP_EncodeBlock((unsigned char *)b64_str, der_spki, der_len); + OPENSSL_free(der_spki); + return b64_str; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x509type.c b/TMessagesProj/jni/boringssl/crypto/x509/x509type.c new file mode 100644 index 00000000..e7c79354 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x509type.c @@ -0,0 +1,128 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include + + +int X509_certificate_type(X509 *x, EVP_PKEY *pkey) + { + EVP_PKEY *pk; + int ret=0,i; + + if (x == NULL) return(0); + + if (pkey == NULL) + pk=X509_get_pubkey(x); + else + pk=pkey; + + if (pk == NULL) return(0); + + switch (pk->type) + { + case EVP_PKEY_RSA: + ret=EVP_PK_RSA|EVP_PKT_SIGN; +/* if (!sign only extension) */ + ret|=EVP_PKT_ENC; + break; + case EVP_PKEY_DSA: + ret=EVP_PK_DSA|EVP_PKT_SIGN; + break; + case EVP_PKEY_EC: + ret=EVP_PK_EC|EVP_PKT_SIGN|EVP_PKT_EXCH; + break; + case EVP_PKEY_DH: + ret=EVP_PK_DH|EVP_PKT_EXCH; + break; + case NID_id_GostR3410_94: + case NID_id_GostR3410_2001: + ret=EVP_PKT_EXCH|EVP_PKT_SIGN; + break; + default: + break; + } + + i=OBJ_obj2nid(x->sig_alg->algorithm); + if (i && OBJ_find_sigid_algs(i, NULL, &i)) + { + + switch (i) + { + case NID_rsaEncryption: + case NID_rsa: + ret|=EVP_PKS_RSA; + break; + case NID_dsa: + case NID_dsa_2: + ret|=EVP_PKS_DSA; + break; + case NID_X9_62_id_ecPublicKey: + ret|=EVP_PKS_EC; + break; + default: + break; + } + } + + if (EVP_PKEY_size(pk) <= 1024/8)/* /8 because it's 1024 bits we look + for, not bytes */ + ret|=EVP_PKT_EXP; + if(pkey==NULL) EVP_PKEY_free(pk); + return(ret); + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_algor.c b/TMessagesProj/jni/boringssl/crypto/x509/x_algor.c new file mode 100644 index 00000000..ae694e3d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_algor.c @@ -0,0 +1,154 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. */ +/* ==================================================================== + * Copyright (c) 2000 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include + + +ASN1_SEQUENCE(X509_ALGOR) = { + ASN1_SIMPLE(X509_ALGOR, algorithm, ASN1_OBJECT), + ASN1_OPT(X509_ALGOR, parameter, ASN1_ANY) +} ASN1_SEQUENCE_END(X509_ALGOR) + +ASN1_ITEM_TEMPLATE(X509_ALGORS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, algorithms, X509_ALGOR) +ASN1_ITEM_TEMPLATE_END(X509_ALGORS) + +IMPLEMENT_ASN1_FUNCTIONS(X509_ALGOR) +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(X509_ALGORS, X509_ALGORS, X509_ALGORS) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_ALGOR) + +IMPLEMENT_ASN1_SET_OF(X509_ALGOR) + +int X509_ALGOR_set0(X509_ALGOR *alg, const ASN1_OBJECT *aobj, int ptype, void *pval) + { + if (!alg) + return 0; + if (ptype != V_ASN1_UNDEF) + { + if (alg->parameter == NULL) + alg->parameter = ASN1_TYPE_new(); + if (alg->parameter == NULL) + return 0; + } + if (alg) + { + if (alg->algorithm) + ASN1_OBJECT_free(alg->algorithm); + alg->algorithm = (ASN1_OBJECT*) aobj; + } + if (ptype == 0) + return 1; + if (ptype == V_ASN1_UNDEF) + { + if (alg->parameter) + { + ASN1_TYPE_free(alg->parameter); + alg->parameter = NULL; + } + } + else + ASN1_TYPE_set(alg->parameter, ptype, pval); + return 1; + } + +void X509_ALGOR_get0(ASN1_OBJECT **paobj, int *pptype, void **ppval, + X509_ALGOR *algor) + { + if (paobj) + *paobj = algor->algorithm; + if (pptype) + { + if (algor->parameter == NULL) + { + *pptype = V_ASN1_UNDEF; + return; + } + else + *pptype = algor->parameter->type; + if (ppval) + *ppval = algor->parameter->value.ptr; + } + } + +/* Set up an X509_ALGOR DigestAlgorithmIdentifier from an EVP_MD */ + +void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md) + { + int param_type; + + if (EVP_MD_flags(md) & EVP_MD_FLAG_DIGALGID_ABSENT) + param_type = V_ASN1_UNDEF; + else + param_type = V_ASN1_NULL; + + X509_ALGOR_set0(alg, OBJ_nid2obj(EVP_MD_type(md)), param_type, NULL); + + } + +/* X509_ALGOR_cmp returns 0 if |a| and |b| are equal and non-zero otherwise. */ +int X509_ALGOR_cmp(const X509_ALGOR *a, const X509_ALGOR *b) + { + int rv; + rv = OBJ_cmp(a->algorithm, b->algorithm); + if (rv) + return rv; + if (!a->parameter && !b->parameter) + return 0; + return ASN1_TYPE_cmp(a->parameter, b->parameter); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_all.c b/TMessagesProj/jni/boringssl/crypto/x509/x_all.c new file mode 100644 index 00000000..d7f2d295 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_all.c @@ -0,0 +1,547 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +int X509_verify(X509 *a, EVP_PKEY *r) + { + if (X509_ALGOR_cmp(a->sig_alg, a->cert_info->signature)) + return 0; + return(ASN1_item_verify(ASN1_ITEM_rptr(X509_CINF),a->sig_alg, + a->signature,a->cert_info,r)); + } + +int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r) + { + return( ASN1_item_verify(ASN1_ITEM_rptr(X509_REQ_INFO), + a->sig_alg,a->signature,a->req_info,r)); + } + +int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md) + { + x->cert_info->enc.modified = 1; + return(ASN1_item_sign(ASN1_ITEM_rptr(X509_CINF), x->cert_info->signature, + x->sig_alg, x->signature, x->cert_info,pkey,md)); + } + +int X509_sign_ctx(X509 *x, EVP_MD_CTX *ctx) + { + x->cert_info->enc.modified = 1; + return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_CINF), + x->cert_info->signature, + x->sig_alg, x->signature, x->cert_info, ctx); + } + +/* TODO(fork) +int X509_http_nbio(OCSP_REQ_CTX *rctx, X509 **pcert) + { + return OCSP_REQ_CTX_nbio_d2i(rctx, + (ASN1_VALUE **)pcert, ASN1_ITEM_rptr(X509)); + } +*/ + +int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md) + { + return(ASN1_item_sign(ASN1_ITEM_rptr(X509_REQ_INFO),x->sig_alg, NULL, + x->signature, x->req_info,pkey,md)); + } + +int X509_REQ_sign_ctx(X509_REQ *x, EVP_MD_CTX *ctx) + { + return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_REQ_INFO), + x->sig_alg, NULL, x->signature, x->req_info, ctx); + } + +int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md) + { + x->crl->enc.modified = 1; + return(ASN1_item_sign(ASN1_ITEM_rptr(X509_CRL_INFO),x->crl->sig_alg, + x->sig_alg, x->signature, x->crl,pkey,md)); + } + +int X509_CRL_sign_ctx(X509_CRL *x, EVP_MD_CTX *ctx) + { + x->crl->enc.modified = 1; + return ASN1_item_sign_ctx(ASN1_ITEM_rptr(X509_CRL_INFO), + x->crl->sig_alg, x->sig_alg, x->signature, x->crl, ctx); + } + +/* TODO(fork) +int X509_CRL_http_nbio(OCSP_REQ_CTX *rctx, X509_CRL **pcrl) + { + return OCSP_REQ_CTX_nbio_d2i(rctx, + (ASN1_VALUE **)pcrl, ASN1_ITEM_rptr(X509_CRL)); + } +*/ + +int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *x, EVP_PKEY *pkey, const EVP_MD *md) + { + return(ASN1_item_sign(ASN1_ITEM_rptr(NETSCAPE_SPKAC), x->sig_algor,NULL, + x->signature, x->spkac,pkey,md)); + } + +int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *x, EVP_PKEY *pkey) + { + return (ASN1_item_verify(ASN1_ITEM_rptr(NETSCAPE_SPKAC), x->sig_algor, + x->signature, x->spkac, pkey)); + } + +#ifndef OPENSSL_NO_FP_API +X509 *d2i_X509_fp(FILE *fp, X509 **x509) + { + return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509), fp, x509); + } + +int i2d_X509_fp(FILE *fp, X509 *x509) + { + return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509), fp, x509); + } +#endif + +X509 *d2i_X509_bio(BIO *bp, X509 **x509) + { + return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509), bp, x509); + } + +int i2d_X509_bio(BIO *bp, X509 *x509) + { + return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509), bp, x509); + } + +#ifndef OPENSSL_NO_FP_API +X509_CRL *d2i_X509_CRL_fp(FILE *fp, X509_CRL **crl) + { + return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_CRL), fp, crl); + } + +int i2d_X509_CRL_fp(FILE *fp, X509_CRL *crl) + { + return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_CRL), fp, crl); + } +#endif + +X509_CRL *d2i_X509_CRL_bio(BIO *bp, X509_CRL **crl) + { + return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509_CRL), bp, crl); + } + +int i2d_X509_CRL_bio(BIO *bp, X509_CRL *crl) + { + return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_CRL), bp, crl); + } + +/* TODO(fork) */ +#if 0 +#ifndef OPENSSL_NO_FP_API +PKCS7 *d2i_PKCS7_fp(FILE *fp, PKCS7 **p7) + { + return ASN1_item_d2i_fp(ASN1_ITEM_rptr(PKCS7), fp, p7); + } + +int i2d_PKCS7_fp(FILE *fp, PKCS7 *p7) + { + return ASN1_item_i2d_fp(ASN1_ITEM_rptr(PKCS7), fp, p7); + } +#endif + +PKCS7 *d2i_PKCS7_bio(BIO *bp, PKCS7 **p7) + { + return ASN1_item_d2i_bio(ASN1_ITEM_rptr(PKCS7), bp, p7); + } + +int i2d_PKCS7_bio(BIO *bp, PKCS7 *p7) + { + return ASN1_item_i2d_bio(ASN1_ITEM_rptr(PKCS7), bp, p7); + } +#endif + +#ifndef OPENSSL_NO_FP_API +X509_REQ *d2i_X509_REQ_fp(FILE *fp, X509_REQ **req) + { + return ASN1_item_d2i_fp(ASN1_ITEM_rptr(X509_REQ), fp, req); + } + +int i2d_X509_REQ_fp(FILE *fp, X509_REQ *req) + { + return ASN1_item_i2d_fp(ASN1_ITEM_rptr(X509_REQ), fp, req); + } +#endif + +X509_REQ *d2i_X509_REQ_bio(BIO *bp, X509_REQ **req) + { + return ASN1_item_d2i_bio(ASN1_ITEM_rptr(X509_REQ), bp, req); + } + +int i2d_X509_REQ_bio(BIO *bp, X509_REQ *req) + { + return ASN1_item_i2d_bio(ASN1_ITEM_rptr(X509_REQ), bp, req); + } + + +#ifndef OPENSSL_NO_FP_API +RSA *d2i_RSAPrivateKey_fp(FILE *fp, RSA **rsa) + { + return ASN1_d2i_fp_of(RSA, RSA_new, d2i_RSAPrivateKey, fp, rsa); + } + +int i2d_RSAPrivateKey_fp(FILE *fp, RSA *rsa) + { + return ASN1_i2d_fp_of_const(RSA, i2d_RSAPrivateKey, fp, rsa); + } + +RSA *d2i_RSAPublicKey_fp(FILE *fp, RSA **rsa) + { + return ASN1_d2i_fp_of(RSA, RSA_new, d2i_RSAPublicKey, fp, rsa); + } + +RSA *d2i_RSA_PUBKEY_fp(FILE *fp, RSA **rsa) + { + return ASN1_d2i_fp((void *(*)(void)) + RSA_new,(D2I_OF(void))d2i_RSA_PUBKEY, fp, + (void **)rsa); + } + +int i2d_RSAPublicKey_fp(FILE *fp, RSA *rsa) + { + return ASN1_i2d_fp_of_const(RSA, i2d_RSAPublicKey, fp, rsa); + } + +int i2d_RSA_PUBKEY_fp(FILE *fp, RSA *rsa) + { + return ASN1_i2d_fp((I2D_OF_const(void))i2d_RSA_PUBKEY,fp,rsa); + } +#endif + +RSA *d2i_RSAPrivateKey_bio(BIO *bp, RSA **rsa) + { + return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSAPrivateKey, bp, rsa); + } + +int i2d_RSAPrivateKey_bio(BIO *bp, RSA *rsa) + { + return ASN1_i2d_bio_of_const(RSA, i2d_RSAPrivateKey, bp, rsa); + } + +RSA *d2i_RSAPublicKey_bio(BIO *bp, RSA **rsa) + { + return ASN1_d2i_bio_of(RSA, RSA_new, d2i_RSAPublicKey, bp, rsa); + } + + +RSA *d2i_RSA_PUBKEY_bio(BIO *bp, RSA **rsa) + { + return ASN1_d2i_bio_of(RSA,RSA_new,d2i_RSA_PUBKEY,bp,rsa); + } + +int i2d_RSAPublicKey_bio(BIO *bp, RSA *rsa) + { + return ASN1_i2d_bio_of_const(RSA, i2d_RSAPublicKey, bp, rsa); + } + +int i2d_RSA_PUBKEY_bio(BIO *bp, RSA *rsa) + { + return ASN1_i2d_bio_of_const(RSA,i2d_RSA_PUBKEY,bp,rsa); + } + +#ifndef OPENSSL_NO_DSA +#ifndef OPENSSL_NO_FP_API +DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa) + { + return ASN1_d2i_fp_of(DSA,DSA_new,d2i_DSAPrivateKey,fp,dsa); + } + +int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa) + { + return ASN1_i2d_fp_of_const(DSA,i2d_DSAPrivateKey,fp,dsa); + } + +DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa) + { + return ASN1_d2i_fp_of(DSA,DSA_new,d2i_DSA_PUBKEY,fp,dsa); + } + +int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa) + { + return ASN1_i2d_fp_of_const(DSA,i2d_DSA_PUBKEY,fp,dsa); + } +#endif + +DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa) + { + return ASN1_d2i_bio_of(DSA,DSA_new,d2i_DSAPrivateKey,bp,dsa +); + } + +int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa) + { + return ASN1_i2d_bio_of_const(DSA,i2d_DSAPrivateKey,bp,dsa); + } + +DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa) + { + return ASN1_d2i_bio_of(DSA,DSA_new,d2i_DSA_PUBKEY,bp,dsa); + } + +int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa) + { + return ASN1_i2d_bio_of_const(DSA,i2d_DSA_PUBKEY,bp,dsa); + } + +#endif + +#ifndef OPENSSL_NO_FP_API +EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey) + { + return ASN1_d2i_fp_of(EC_KEY,EC_KEY_new,d2i_EC_PUBKEY,fp,eckey); + } + +int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey) + { + return ASN1_i2d_fp_of_const(EC_KEY,i2d_EC_PUBKEY,fp,eckey); + } + +EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey) + { + return ASN1_d2i_fp_of(EC_KEY,EC_KEY_new,d2i_ECPrivateKey,fp,eckey); + } + +int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey) + { + return ASN1_i2d_fp_of_const(EC_KEY,i2d_ECPrivateKey,fp,eckey); + } +#endif +EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey) + { + return ASN1_d2i_bio_of(EC_KEY,EC_KEY_new,d2i_EC_PUBKEY,bp,eckey); + } + +int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *ecdsa) + { + return ASN1_i2d_bio_of_const(EC_KEY,i2d_EC_PUBKEY,bp,ecdsa); + } + +EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey) + { + return ASN1_d2i_bio_of(EC_KEY,EC_KEY_new,d2i_ECPrivateKey,bp,eckey); + } + +int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey) + { + return ASN1_i2d_bio_of_const(EC_KEY,i2d_ECPrivateKey,bp,eckey); + } + + +int X509_pubkey_digest(const X509 *data, const EVP_MD *type, unsigned char *md, + unsigned int *len) + { + ASN1_BIT_STRING *key; + key = X509_get0_pubkey_bitstr(data); + if(!key) return 0; + return EVP_Digest(key->data, key->length, md, len, type, NULL); + } + +int X509_digest(const X509 *data, const EVP_MD *type, unsigned char *md, + unsigned int *len) + { + return(ASN1_item_digest(ASN1_ITEM_rptr(X509),type,(char *)data,md,len)); + } + +int X509_CRL_digest(const X509_CRL *data, const EVP_MD *type, unsigned char *md, + unsigned int *len) + { + return(ASN1_item_digest(ASN1_ITEM_rptr(X509_CRL),type,(char *)data,md,len)); + } + +int X509_REQ_digest(const X509_REQ *data, const EVP_MD *type, unsigned char *md, + unsigned int *len) + { + return(ASN1_item_digest(ASN1_ITEM_rptr(X509_REQ),type,(char *)data,md,len)); + } + +int X509_NAME_digest(const X509_NAME *data, const EVP_MD *type, unsigned char *md, + unsigned int *len) + { + return(ASN1_item_digest(ASN1_ITEM_rptr(X509_NAME),type,(char *)data,md,len)); + } + +#if 0 /* TODO(fork): remove */ +int PKCS7_ISSUER_AND_SERIAL_digest(PKCS7_ISSUER_AND_SERIAL *data, const EVP_MD *type, + unsigned char *md, unsigned int *len) + { + return(ASN1_item_digest(ASN1_ITEM_rptr(PKCS7_ISSUER_AND_SERIAL),type, + (char *)data,md,len)); + } +#endif + +#ifndef OPENSSL_NO_FP_API +X509_SIG *d2i_PKCS8_fp(FILE *fp, X509_SIG **p8) + { + return ASN1_d2i_fp_of(X509_SIG,X509_SIG_new,d2i_X509_SIG,fp,p8); + } + +int i2d_PKCS8_fp(FILE *fp, X509_SIG *p8) + { + return ASN1_i2d_fp_of(X509_SIG,i2d_X509_SIG,fp,p8); + } +#endif + +X509_SIG *d2i_PKCS8_bio(BIO *bp, X509_SIG **p8) + { + return ASN1_d2i_bio_of(X509_SIG,X509_SIG_new,d2i_X509_SIG,bp,p8); + } + +int i2d_PKCS8_bio(BIO *bp, X509_SIG *p8) + { + return ASN1_i2d_bio_of(X509_SIG,i2d_X509_SIG,bp,p8); + } + +#ifndef OPENSSL_NO_FP_API +PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, + PKCS8_PRIV_KEY_INFO **p8inf) + { + return ASN1_d2i_fp_of(PKCS8_PRIV_KEY_INFO,PKCS8_PRIV_KEY_INFO_new, + d2i_PKCS8_PRIV_KEY_INFO,fp,p8inf); + } + +int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, PKCS8_PRIV_KEY_INFO *p8inf) + { + return ASN1_i2d_fp_of(PKCS8_PRIV_KEY_INFO,i2d_PKCS8_PRIV_KEY_INFO,fp, + p8inf); + } + +int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key) + { + PKCS8_PRIV_KEY_INFO *p8inf; + int ret; + p8inf = EVP_PKEY2PKCS8(key); + if(!p8inf) return 0; + ret = i2d_PKCS8_PRIV_KEY_INFO_fp(fp, p8inf); + PKCS8_PRIV_KEY_INFO_free(p8inf); + return ret; + } + +int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey) + { + return ASN1_i2d_fp_of_const(EVP_PKEY,i2d_PrivateKey,fp,pkey); + } + +EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a) +{ + return ASN1_d2i_fp_of(EVP_PKEY,EVP_PKEY_new,d2i_AutoPrivateKey,fp,a); +} + +int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey) + { + return ASN1_i2d_fp_of_const(EVP_PKEY,i2d_PUBKEY,fp,pkey); + } + +EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a) +{ + return ASN1_d2i_fp_of(EVP_PKEY,EVP_PKEY_new,d2i_PUBKEY,fp,a); +} + +PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, + PKCS8_PRIV_KEY_INFO **p8inf) + { + return ASN1_d2i_bio_of(PKCS8_PRIV_KEY_INFO,PKCS8_PRIV_KEY_INFO_new, + d2i_PKCS8_PRIV_KEY_INFO,bp,p8inf); + } + +int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, PKCS8_PRIV_KEY_INFO *p8inf) + { + return ASN1_i2d_bio_of(PKCS8_PRIV_KEY_INFO,i2d_PKCS8_PRIV_KEY_INFO,bp, + p8inf); + } + +int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key) + { + PKCS8_PRIV_KEY_INFO *p8inf; + int ret; + p8inf = EVP_PKEY2PKCS8(key); + if(!p8inf) return 0; + ret = i2d_PKCS8_PRIV_KEY_INFO_bio(bp, p8inf); + PKCS8_PRIV_KEY_INFO_free(p8inf); + return ret; + } +#endif + +int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey) + { + return ASN1_i2d_bio_of_const(EVP_PKEY,i2d_PrivateKey,bp,pkey); + } + +EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a) + { + return ASN1_d2i_bio_of(EVP_PKEY,EVP_PKEY_new,d2i_AutoPrivateKey,bp,a); + } + +int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey) + { + return ASN1_i2d_bio_of_const(EVP_PKEY,i2d_PUBKEY,bp,pkey); + } + +EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a) + { + return ASN1_d2i_bio_of(EVP_PKEY,EVP_PKEY_new,d2i_PUBKEY,bp,a); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_attrib.c b/TMessagesProj/jni/boringssl/crypto/x509/x_attrib.c new file mode 100644 index 00000000..c460a702 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_attrib.c @@ -0,0 +1,117 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include + + +/* X509_ATTRIBUTE: this has the following form: + * + * typedef struct x509_attributes_st + * { + * ASN1_OBJECT *object; + * int single; + * union { + * char *ptr; + * STACK_OF(ASN1_TYPE) *set; + * ASN1_TYPE *single; + * } value; + * } X509_ATTRIBUTE; + * + * this needs some extra thought because the CHOICE type is + * merged with the main structure and because the value can + * be anything at all we *must* try the SET OF first because + * the ASN1_ANY type will swallow anything including the whole + * SET OF structure. + */ + +ASN1_CHOICE(X509_ATTRIBUTE_SET) = { + ASN1_SET_OF(X509_ATTRIBUTE, value.set, ASN1_ANY), + ASN1_SIMPLE(X509_ATTRIBUTE, value.single, ASN1_ANY) +} ASN1_CHOICE_END_selector(X509_ATTRIBUTE, X509_ATTRIBUTE_SET, single) + +ASN1_SEQUENCE(X509_ATTRIBUTE) = { + ASN1_SIMPLE(X509_ATTRIBUTE, object, ASN1_OBJECT), + /* CHOICE type merged with parent */ + ASN1_EX_COMBINE(0, 0, X509_ATTRIBUTE_SET) +} ASN1_SEQUENCE_END(X509_ATTRIBUTE) + +IMPLEMENT_ASN1_FUNCTIONS(X509_ATTRIBUTE) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_ATTRIBUTE) + +X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value) + { + X509_ATTRIBUTE *ret=NULL; + ASN1_TYPE *val=NULL; + + if ((ret=X509_ATTRIBUTE_new()) == NULL) + return(NULL); + /* TODO(fork): const correctness. */ + ret->object=(ASN1_OBJECT*) OBJ_nid2obj(nid); + ret->single=0; + if ((ret->value.set=sk_ASN1_TYPE_new_null()) == NULL) goto err; + if ((val=ASN1_TYPE_new()) == NULL) goto err; + if (!sk_ASN1_TYPE_push(ret->value.set,val)) goto err; + + ASN1_TYPE_set(val,atrtype,value); + return(ret); +err: + if (ret != NULL) X509_ATTRIBUTE_free(ret); + if (val != NULL) ASN1_TYPE_free(val); + return(NULL); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_crl.c b/TMessagesProj/jni/boringssl/crypto/x509/x_crl.c new file mode 100644 index 00000000..d5168727 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_crl.c @@ -0,0 +1,560 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../internal.h" + + +/* Method to handle CRL access. + * In general a CRL could be very large (several Mb) and can consume large + * amounts of resources if stored in memory by multiple processes. + * This method allows general CRL operations to be redirected to more + * efficient callbacks: for example a CRL entry database. + */ + +#define X509_CRL_METHOD_DYNAMIC 1 + +struct x509_crl_method_st + { + int flags; + int (*crl_init)(X509_CRL *crl); + int (*crl_free)(X509_CRL *crl); + int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret, + ASN1_INTEGER *ser, X509_NAME *issuer); + int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk); + }; + +static int X509_REVOKED_cmp(const X509_REVOKED **a, + const X509_REVOKED **b); +static void setup_idp(X509_CRL *crl, ISSUING_DIST_POINT *idp); + +ASN1_SEQUENCE(X509_REVOKED) = { + ASN1_SIMPLE(X509_REVOKED,serialNumber, ASN1_INTEGER), + ASN1_SIMPLE(X509_REVOKED,revocationDate, ASN1_TIME), + ASN1_SEQUENCE_OF_OPT(X509_REVOKED,extensions, X509_EXTENSION) +} ASN1_SEQUENCE_END(X509_REVOKED) + +static int def_crl_verify(X509_CRL *crl, EVP_PKEY *r); +static int def_crl_lookup(X509_CRL *crl, + X509_REVOKED **ret, ASN1_INTEGER *serial, X509_NAME *issuer); + +static const X509_CRL_METHOD int_crl_meth = + { + 0, + 0,0, + def_crl_lookup, + def_crl_verify + }; + +static const X509_CRL_METHOD *default_crl_method = &int_crl_meth; + +/* The X509_CRL_INFO structure needs a bit of customisation. + * Since we cache the original encoding the signature wont be affected by + * reordering of the revoked field. + */ +static int crl_inf_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) +{ + X509_CRL_INFO *a = (X509_CRL_INFO *)*pval; + + if(!a || !a->revoked) return 1; + switch(operation) { + /* Just set cmp function here. We don't sort because that + * would affect the output of X509_CRL_print(). + */ + case ASN1_OP_D2I_POST: + (void)sk_X509_REVOKED_set_cmp_func(a->revoked,X509_REVOKED_cmp); + break; + } + return 1; +} + + +ASN1_SEQUENCE_enc(X509_CRL_INFO, enc, crl_inf_cb) = { + ASN1_OPT(X509_CRL_INFO, version, ASN1_INTEGER), + ASN1_SIMPLE(X509_CRL_INFO, sig_alg, X509_ALGOR), + ASN1_SIMPLE(X509_CRL_INFO, issuer, X509_NAME), + ASN1_SIMPLE(X509_CRL_INFO, lastUpdate, ASN1_TIME), + ASN1_OPT(X509_CRL_INFO, nextUpdate, ASN1_TIME), + ASN1_SEQUENCE_OF_OPT(X509_CRL_INFO, revoked, X509_REVOKED), + ASN1_EXP_SEQUENCE_OF_OPT(X509_CRL_INFO, extensions, X509_EXTENSION, 0) +} ASN1_SEQUENCE_END_enc(X509_CRL_INFO, X509_CRL_INFO) + +/* Set CRL entry issuer according to CRL certificate issuer extension. + * Check for unhandled critical CRL entry extensions. + */ + +static int crl_set_issuers(X509_CRL *crl) + { + + size_t i, k; + int j; + GENERAL_NAMES *gens, *gtmp; + STACK_OF(X509_REVOKED) *revoked; + + revoked = X509_CRL_get_REVOKED(crl); + + gens = NULL; + for (i = 0; i < sk_X509_REVOKED_num(revoked); i++) + { + X509_REVOKED *rev = sk_X509_REVOKED_value(revoked, i); + STACK_OF(X509_EXTENSION) *exts; + ASN1_ENUMERATED *reason; + X509_EXTENSION *ext; + gtmp = X509_REVOKED_get_ext_d2i(rev, + NID_certificate_issuer, + &j, NULL); + if (!gtmp && (j != -1)) + { + crl->flags |= EXFLAG_INVALID; + return 1; + } + + if (gtmp) + { + gens = gtmp; + if (!crl->issuers) + { + crl->issuers = sk_GENERAL_NAMES_new_null(); + if (!crl->issuers) + return 0; + } + if (!sk_GENERAL_NAMES_push(crl->issuers, gtmp)) + return 0; + } + rev->issuer = gens; + + reason = X509_REVOKED_get_ext_d2i(rev, NID_crl_reason, + &j, NULL); + if (!reason && (j != -1)) + { + crl->flags |= EXFLAG_INVALID; + return 1; + } + + if (reason) + { + rev->reason = ASN1_ENUMERATED_get(reason); + ASN1_ENUMERATED_free(reason); + } + else + rev->reason = CRL_REASON_NONE; + + /* Check for critical CRL entry extensions */ + + exts = rev->extensions; + + for (k = 0; k < sk_X509_EXTENSION_num(exts); k++) + { + ext = sk_X509_EXTENSION_value(exts, k); + if (ext->critical > 0) + { + if (OBJ_obj2nid(ext->object) == + NID_certificate_issuer) + continue; + crl->flags |= EXFLAG_CRITICAL; + break; + } + } + + + } + + return 1; + + } + +/* The X509_CRL structure needs a bit of customisation. Cache some extensions + * and hash of the whole CRL. + */ +static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) + { + X509_CRL *crl = (X509_CRL *)*pval; + STACK_OF(X509_EXTENSION) *exts; + X509_EXTENSION *ext; + size_t idx; + + switch(operation) + { + case ASN1_OP_NEW_POST: + crl->idp = NULL; + crl->akid = NULL; + crl->flags = 0; + crl->idp_flags = 0; + crl->idp_reasons = CRLDP_ALL_REASONS; + crl->meth = default_crl_method; + crl->meth_data = NULL; + crl->issuers = NULL; + crl->crl_number = NULL; + crl->base_crl_number = NULL; + break; + + case ASN1_OP_D2I_POST: + X509_CRL_digest(crl, EVP_sha1(), crl->sha1_hash, NULL); + crl->idp = X509_CRL_get_ext_d2i(crl, + NID_issuing_distribution_point, NULL, NULL); + if (crl->idp) + setup_idp(crl, crl->idp); + + crl->akid = X509_CRL_get_ext_d2i(crl, + NID_authority_key_identifier, NULL, NULL); + + crl->crl_number = X509_CRL_get_ext_d2i(crl, + NID_crl_number, NULL, NULL); + + crl->base_crl_number = X509_CRL_get_ext_d2i(crl, + NID_delta_crl, NULL, NULL); + /* Delta CRLs must have CRL number */ + if (crl->base_crl_number && !crl->crl_number) + crl->flags |= EXFLAG_INVALID; + + /* See if we have any unhandled critical CRL extensions and + * indicate this in a flag. We only currently handle IDP so + * anything else critical sets the flag. + * + * This code accesses the X509_CRL structure directly: + * applications shouldn't do this. + */ + + exts = crl->crl->extensions; + + for (idx = 0; idx < sk_X509_EXTENSION_num(exts); idx++) + { + int nid; + ext = sk_X509_EXTENSION_value(exts, idx); + nid = OBJ_obj2nid(ext->object); + if (nid == NID_freshest_crl) + crl->flags |= EXFLAG_FRESHEST; + if (ext->critical > 0) + { + /* We handle IDP and deltas */ + if ((nid == NID_issuing_distribution_point) + || (nid == NID_authority_key_identifier) + || (nid == NID_delta_crl)) + break;; + crl->flags |= EXFLAG_CRITICAL; + break; + } + } + + + if (!crl_set_issuers(crl)) + return 0; + + if (crl->meth->crl_init) + { + if (crl->meth->crl_init(crl) == 0) + return 0; + } + break; + + case ASN1_OP_FREE_POST: + if (crl->meth->crl_free) + { + if (!crl->meth->crl_free(crl)) + return 0; + } + if (crl->akid) + AUTHORITY_KEYID_free(crl->akid); + if (crl->idp) + ISSUING_DIST_POINT_free(crl->idp); + ASN1_INTEGER_free(crl->crl_number); + ASN1_INTEGER_free(crl->base_crl_number); + sk_GENERAL_NAMES_pop_free(crl->issuers, GENERAL_NAMES_free); + break; + } + return 1; + } + +/* Convert IDP into a more convenient form */ + +static void setup_idp(X509_CRL *crl, ISSUING_DIST_POINT *idp) + { + int idp_only = 0; + /* Set various flags according to IDP */ + crl->idp_flags |= IDP_PRESENT; + if (idp->onlyuser > 0) + { + idp_only++; + crl->idp_flags |= IDP_ONLYUSER; + } + if (idp->onlyCA > 0) + { + idp_only++; + crl->idp_flags |= IDP_ONLYCA; + } + if (idp->onlyattr > 0) + { + idp_only++; + crl->idp_flags |= IDP_ONLYATTR; + } + + if (idp_only > 1) + crl->idp_flags |= IDP_INVALID; + + if (idp->indirectCRL > 0) + crl->idp_flags |= IDP_INDIRECT; + + if (idp->onlysomereasons) + { + crl->idp_flags |= IDP_REASONS; + if (idp->onlysomereasons->length > 0) + crl->idp_reasons = idp->onlysomereasons->data[0]; + if (idp->onlysomereasons->length > 1) + crl->idp_reasons |= + (idp->onlysomereasons->data[1] << 8); + crl->idp_reasons &= CRLDP_ALL_REASONS; + } + + DIST_POINT_set_dpname(idp->distpoint, X509_CRL_get_issuer(crl)); + } + +ASN1_SEQUENCE_ref(X509_CRL, crl_cb) = { + ASN1_SIMPLE(X509_CRL, crl, X509_CRL_INFO), + ASN1_SIMPLE(X509_CRL, sig_alg, X509_ALGOR), + ASN1_SIMPLE(X509_CRL, signature, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END_ref(X509_CRL, X509_CRL) + +IMPLEMENT_ASN1_FUNCTIONS(X509_REVOKED) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_REVOKED) +IMPLEMENT_ASN1_FUNCTIONS(X509_CRL_INFO) +IMPLEMENT_ASN1_FUNCTIONS(X509_CRL) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_CRL) + +static int X509_REVOKED_cmp(const X509_REVOKED **a, + const X509_REVOKED **b) + { + return(ASN1_STRING_cmp( + (ASN1_STRING *)(*a)->serialNumber, + (ASN1_STRING *)(*b)->serialNumber)); + } + +int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev) +{ + X509_CRL_INFO *inf; + inf = crl->crl; + if(!inf->revoked) + inf->revoked = sk_X509_REVOKED_new(X509_REVOKED_cmp); + if(!inf->revoked || !sk_X509_REVOKED_push(inf->revoked, rev)) { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + inf->enc.modified = 1; + return 1; +} + +int X509_CRL_verify(X509_CRL *crl, EVP_PKEY *r) + { + if (crl->meth->crl_verify) + return crl->meth->crl_verify(crl, r); + return 0; + } + +int X509_CRL_get0_by_serial(X509_CRL *crl, + X509_REVOKED **ret, ASN1_INTEGER *serial) + { + if (crl->meth->crl_lookup) + return crl->meth->crl_lookup(crl, ret, serial, NULL); + return 0; + } + +int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x) + { + if (crl->meth->crl_lookup) + return crl->meth->crl_lookup(crl, ret, + X509_get_serialNumber(x), + X509_get_issuer_name(x)); + return 0; + } + +static int def_crl_verify(X509_CRL *crl, EVP_PKEY *r) + { + return(ASN1_item_verify(ASN1_ITEM_rptr(X509_CRL_INFO), + crl->sig_alg, crl->signature,crl->crl,r)); + } + +static int crl_revoked_issuer_match(X509_CRL *crl, X509_NAME *nm, + X509_REVOKED *rev) + { + size_t i; + + if (!rev->issuer) + { + if (!nm) + return 1; + if (!X509_NAME_cmp(nm, X509_CRL_get_issuer(crl))) + return 1; + return 0; + } + + if (!nm) + nm = X509_CRL_get_issuer(crl); + + for (i = 0; i < sk_GENERAL_NAME_num(rev->issuer); i++) + { + GENERAL_NAME *gen = sk_GENERAL_NAME_value(rev->issuer, i); + if (gen->type != GEN_DIRNAME) + continue; + if (!X509_NAME_cmp(nm, gen->d.directoryName)) + return 1; + } + return 0; + + } + +static struct CRYPTO_STATIC_MUTEX g_crl_sort_lock = CRYPTO_STATIC_MUTEX_INIT; + +static int def_crl_lookup(X509_CRL *crl, + X509_REVOKED **ret, ASN1_INTEGER *serial, X509_NAME *issuer) + { + X509_REVOKED rtmp, *rev; + size_t idx; + rtmp.serialNumber = serial; + /* Sort revoked into serial number order if not already sorted. + * Do this under a lock to avoid race condition. + */ + + CRYPTO_STATIC_MUTEX_lock_read(&g_crl_sort_lock); + const int is_sorted = sk_X509_REVOKED_is_sorted(crl->crl->revoked); + CRYPTO_STATIC_MUTEX_unlock(&g_crl_sort_lock); + + if (!is_sorted) + { + CRYPTO_STATIC_MUTEX_lock_write(&g_crl_sort_lock); + if (!sk_X509_REVOKED_is_sorted(crl->crl->revoked)) + { + sk_X509_REVOKED_sort(crl->crl->revoked); + } + CRYPTO_STATIC_MUTEX_unlock(&g_crl_sort_lock); + } + + if (!sk_X509_REVOKED_find(crl->crl->revoked, &idx, &rtmp)) + return 0; + /* Need to look for matching name */ + for(;idx < sk_X509_REVOKED_num(crl->crl->revoked); idx++) + { + rev = sk_X509_REVOKED_value(crl->crl->revoked, idx); + if (ASN1_INTEGER_cmp(rev->serialNumber, serial)) + return 0; + if (crl_revoked_issuer_match(crl, issuer, rev)) + { + if (ret) + *ret = rev; + if (rev->reason == CRL_REASON_REMOVE_FROM_CRL) + return 2; + return 1; + } + } + return 0; + } + +void X509_CRL_set_default_method(const X509_CRL_METHOD *meth) + { + if (meth == NULL) + default_crl_method = &int_crl_meth; + else + default_crl_method = meth; + } + +X509_CRL_METHOD *X509_CRL_METHOD_new( + int (*crl_init)(X509_CRL *crl), + int (*crl_free)(X509_CRL *crl), + int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret, + ASN1_INTEGER *ser, X509_NAME *issuer), + int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk)) + { + X509_CRL_METHOD *m; + m = OPENSSL_malloc(sizeof(X509_CRL_METHOD)); + if (!m) + return NULL; + m->crl_init = crl_init; + m->crl_free = crl_free; + m->crl_lookup = crl_lookup; + m->crl_verify = crl_verify; + m->flags = X509_CRL_METHOD_DYNAMIC; + return m; + } + +void X509_CRL_METHOD_free(X509_CRL_METHOD *m) + { + if (!(m->flags & X509_CRL_METHOD_DYNAMIC)) + return; + OPENSSL_free(m); + } + +void X509_CRL_set_meth_data(X509_CRL *crl, void *dat) + { + crl->meth_data = dat; + } + +void *X509_CRL_get_meth_data(X509_CRL *crl) + { + return crl->meth_data; + } + +IMPLEMENT_ASN1_SET_OF(X509_REVOKED) +IMPLEMENT_ASN1_SET_OF(X509_CRL) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_exten.c b/TMessagesProj/jni/boringssl/crypto/x509/x_exten.c new file mode 100644 index 00000000..cf64c844 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_exten.c @@ -0,0 +1,75 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include + + +ASN1_SEQUENCE(X509_EXTENSION) = { + ASN1_SIMPLE(X509_EXTENSION, object, ASN1_OBJECT), + ASN1_OPT(X509_EXTENSION, critical, ASN1_BOOLEAN), + ASN1_SIMPLE(X509_EXTENSION, value, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(X509_EXTENSION) + +ASN1_ITEM_TEMPLATE(X509_EXTENSIONS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Extension, X509_EXTENSION) +ASN1_ITEM_TEMPLATE_END(X509_EXTENSIONS) + +IMPLEMENT_ASN1_FUNCTIONS(X509_EXTENSION) +IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_EXTENSION) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_info.c b/TMessagesProj/jni/boringssl/crypto/x509/x_info.c new file mode 100644 index 00000000..be579d79 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_info.c @@ -0,0 +1,95 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include + + +X509_INFO *X509_INFO_new(void) + { + X509_INFO *ret=NULL; + + ret=(X509_INFO *)OPENSSL_malloc(sizeof(X509_INFO)); + if (ret == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return(NULL); + } + + ret->enc_cipher.cipher=NULL; + ret->enc_len=0; + ret->enc_data=NULL; + + ret->x509=NULL; + ret->crl=NULL; + ret->x_pkey=NULL; + return(ret); + } + +void X509_INFO_free(X509_INFO *x) + { + if (x == NULL) return; + + if (x->x509 != NULL) X509_free(x->x509); + if (x->crl != NULL) X509_CRL_free(x->crl); + if (x->x_pkey != NULL) X509_PKEY_free(x->x_pkey); + if (x->enc_data != NULL) OPENSSL_free(x->enc_data); + OPENSSL_free(x); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_name.c b/TMessagesProj/jni/boringssl/crypto/x509/x_name.c new file mode 100644 index 00000000..762756bf --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_name.c @@ -0,0 +1,538 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../asn1/asn1_locl.h" + + +typedef STACK_OF(X509_NAME_ENTRY) STACK_OF_X509_NAME_ENTRY; +DECLARE_STACK_OF(STACK_OF_X509_NAME_ENTRY) + +static int x509_name_ex_d2i(ASN1_VALUE **val, + const unsigned char **in, long len, + const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx); + +static int x509_name_ex_i2d(ASN1_VALUE **val, unsigned char **out, + const ASN1_ITEM *it, int tag, int aclass); +static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it); +static void x509_name_ex_free(ASN1_VALUE **val, const ASN1_ITEM *it); + +static int x509_name_encode(X509_NAME *a); +static int x509_name_canon(X509_NAME *a); +static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in); +static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) *intname, + unsigned char **in); + + +static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval, + int indent, + const char *fname, + const ASN1_PCTX *pctx); + +ASN1_SEQUENCE(X509_NAME_ENTRY) = { + ASN1_SIMPLE(X509_NAME_ENTRY, object, ASN1_OBJECT), + ASN1_SIMPLE(X509_NAME_ENTRY, value, ASN1_PRINTABLE) +} ASN1_SEQUENCE_END(X509_NAME_ENTRY) + +IMPLEMENT_ASN1_FUNCTIONS(X509_NAME_ENTRY) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_NAME_ENTRY) + +/* For the "Name" type we need a SEQUENCE OF { SET OF X509_NAME_ENTRY } + * so declare two template wrappers for this + */ + +ASN1_ITEM_TEMPLATE(X509_NAME_ENTRIES) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SET_OF, 0, RDNS, X509_NAME_ENTRY) +ASN1_ITEM_TEMPLATE_END(X509_NAME_ENTRIES) + +ASN1_ITEM_TEMPLATE(X509_NAME_INTERNAL) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, Name, X509_NAME_ENTRIES) +ASN1_ITEM_TEMPLATE_END(X509_NAME_INTERNAL) + +/* Normally that's where it would end: we'd have two nested STACK structures + * representing the ASN1. Unfortunately X509_NAME uses a completely different + * form and caches encodings so we have to process the internal form and convert + * to the external form. + */ + +const ASN1_EXTERN_FUNCS x509_name_ff = { + NULL, + x509_name_ex_new, + x509_name_ex_free, + 0, /* Default clear behaviour is OK */ + x509_name_ex_d2i, + x509_name_ex_i2d, + x509_name_ex_print +}; + +IMPLEMENT_EXTERN_ASN1(X509_NAME, V_ASN1_SEQUENCE, x509_name_ff) + +IMPLEMENT_ASN1_FUNCTIONS(X509_NAME) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_NAME) + +static int x509_name_ex_new(ASN1_VALUE **val, const ASN1_ITEM *it) +{ + X509_NAME *ret = NULL; + ret = OPENSSL_malloc(sizeof(X509_NAME)); + if(!ret) goto memerr; + if ((ret->entries=sk_X509_NAME_ENTRY_new_null()) == NULL) + goto memerr; + if((ret->bytes = BUF_MEM_new()) == NULL) goto memerr; + ret->canon_enc = NULL; + ret->canon_enclen = 0; + ret->modified=1; + *val = (ASN1_VALUE *)ret; + return 1; + + memerr: + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + if (ret) + { + if (ret->entries) + sk_X509_NAME_ENTRY_free(ret->entries); + OPENSSL_free(ret); + } + return 0; +} + +static void x509_name_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it) +{ + X509_NAME *a; + if(!pval || !*pval) + return; + a = (X509_NAME *)*pval; + + BUF_MEM_free(a->bytes); + sk_X509_NAME_ENTRY_pop_free(a->entries,X509_NAME_ENTRY_free); + if (a->canon_enc) + OPENSSL_free(a->canon_enc); + OPENSSL_free(a); + *pval = NULL; +} + +static void local_sk_X509_NAME_ENTRY_free(STACK_OF(X509_NAME_ENTRY) *ne) +{ + sk_X509_NAME_ENTRY_free(ne); +} + +static void local_sk_X509_NAME_ENTRY_pop_free(STACK_OF(X509_NAME_ENTRY) *ne) +{ + sk_X509_NAME_ENTRY_pop_free(ne, X509_NAME_ENTRY_free); +} + +static int x509_name_ex_d2i(ASN1_VALUE **val, + const unsigned char **in, long len, const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx) +{ + const unsigned char *p = *in, *q; + union { STACK_OF(STACK_OF_X509_NAME_ENTRY) *s; + ASN1_VALUE *a; } intname = {NULL}; + union { X509_NAME *x; ASN1_VALUE *a; } nm = {NULL}; + size_t i, j; + int ret; + STACK_OF(X509_NAME_ENTRY) *entries; + X509_NAME_ENTRY *entry; + q = p; + + /* Get internal representation of Name */ + ret = ASN1_item_ex_d2i(&intname.a, + &p, len, ASN1_ITEM_rptr(X509_NAME_INTERNAL), + tag, aclass, opt, ctx); + + if(ret <= 0) return ret; + + if(*val) x509_name_ex_free(val, NULL); + /* We've decoded it: now cache encoding */ + if (!x509_name_ex_new(&nm.a, NULL) || + !BUF_MEM_grow(nm.x->bytes, p - q)) + { + sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, + local_sk_X509_NAME_ENTRY_pop_free); + goto err; + } + memcpy(nm.x->bytes->data, q, p - q); + + /* Convert internal representation to X509_NAME structure */ + for(i = 0; i < sk_STACK_OF_X509_NAME_ENTRY_num(intname.s); i++) { + entries = sk_STACK_OF_X509_NAME_ENTRY_value(intname.s, i); + for(j = 0; j < sk_X509_NAME_ENTRY_num(entries); j++) { + entry = sk_X509_NAME_ENTRY_value(entries, j); + entry->set = i; + if(!sk_X509_NAME_ENTRY_push(nm.x->entries, entry)) + goto err; + } + sk_X509_NAME_ENTRY_free(entries); + } + sk_STACK_OF_X509_NAME_ENTRY_free(intname.s); + ret = x509_name_canon(nm.x); + if (!ret) + goto err; + nm.x->modified = 0; + *val = nm.a; + *in = p; + return ret; +err: + if (nm.x != NULL) + X509_NAME_free(nm.x); + OPENSSL_PUT_ERROR(X509, ERR_R_ASN1_LIB); + return 0; +} + +static int x509_name_ex_i2d(ASN1_VALUE **val, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass) +{ + int ret; + X509_NAME *a = (X509_NAME *)*val; + if(a->modified) { + ret = x509_name_encode(a); + if(ret < 0) + return ret; + ret = x509_name_canon(a); + if(ret < 0) + return ret; + } + ret = a->bytes->length; + if(out != NULL) { + memcpy(*out,a->bytes->data,ret); + *out+=ret; + } + return ret; +} + +static int x509_name_encode(X509_NAME *a) +{ + union { STACK_OF(STACK_OF_X509_NAME_ENTRY) *s; + ASN1_VALUE *a; } intname = {NULL}; + int len; + unsigned char *p; + STACK_OF(X509_NAME_ENTRY) *entries = NULL; + X509_NAME_ENTRY *entry; + int set = -1; + size_t i; + intname.s = sk_STACK_OF_X509_NAME_ENTRY_new_null(); + if(!intname.s) goto memerr; + for(i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) { + entry = sk_X509_NAME_ENTRY_value(a->entries, i); + if(entry->set != set) { + entries = sk_X509_NAME_ENTRY_new_null(); + if(!entries) goto memerr; + if(!sk_STACK_OF_X509_NAME_ENTRY_push(intname.s, + entries)) + goto memerr; + set = entry->set; + } + if(!sk_X509_NAME_ENTRY_push(entries, entry)) goto memerr; + } + len = ASN1_item_ex_i2d(&intname.a, NULL, + ASN1_ITEM_rptr(X509_NAME_INTERNAL), -1, -1); + if (!BUF_MEM_grow(a->bytes,len)) goto memerr; + p=(unsigned char *)a->bytes->data; + ASN1_item_ex_i2d(&intname.a, + &p, ASN1_ITEM_rptr(X509_NAME_INTERNAL), -1, -1); + sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, + local_sk_X509_NAME_ENTRY_free); + a->modified = 0; + return len; +memerr: + sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname.s, + local_sk_X509_NAME_ENTRY_free); + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return -1; +} + +static int x509_name_ex_print(BIO *out, ASN1_VALUE **pval, + int indent, + const char *fname, + const ASN1_PCTX *pctx) + { + if (X509_NAME_print_ex(out, (X509_NAME *)*pval, + indent, pctx->nm_flags) <= 0) + return 0; + return 2; + } + +/* This function generates the canonical encoding of the Name structure. + * In it all strings are converted to UTF8, leading, trailing and + * multiple spaces collapsed, converted to lower case and the leading + * SEQUENCE header removed. + * + * In future we could also normalize the UTF8 too. + * + * By doing this comparison of Name structures can be rapidly + * perfomed by just using memcmp() of the canonical encoding. + * By omitting the leading SEQUENCE name constraints of type + * dirName can also be checked with a simple memcmp(). + */ + +static int x509_name_canon(X509_NAME *a) + { + unsigned char *p; + STACK_OF(STACK_OF_X509_NAME_ENTRY) *intname = NULL; + STACK_OF(X509_NAME_ENTRY) *entries = NULL; + X509_NAME_ENTRY *entry, *tmpentry = NULL; + int set = -1, ret = 0; + size_t i; + + if (a->canon_enc) + { + OPENSSL_free(a->canon_enc); + a->canon_enc = NULL; + } + /* Special case: empty X509_NAME => null encoding */ + if (sk_X509_NAME_ENTRY_num(a->entries) == 0) + { + a->canon_enclen = 0; + return 1; + } + intname = sk_STACK_OF_X509_NAME_ENTRY_new_null(); + if(!intname) + goto err; + for(i = 0; i < sk_X509_NAME_ENTRY_num(a->entries); i++) + { + entry = sk_X509_NAME_ENTRY_value(a->entries, i); + if(entry->set != set) + { + entries = sk_X509_NAME_ENTRY_new_null(); + if(!entries) + goto err; + if(!sk_STACK_OF_X509_NAME_ENTRY_push(intname, entries)) + { + sk_X509_NAME_ENTRY_free(entries); + goto err; + } + set = entry->set; + } + tmpentry = X509_NAME_ENTRY_new(); + if (tmpentry == NULL) + goto err; + tmpentry->object = OBJ_dup(entry->object); + if (!asn1_string_canon(tmpentry->value, entry->value)) + goto err; + if(!sk_X509_NAME_ENTRY_push(entries, tmpentry)) + goto err; + tmpentry = NULL; + } + + /* Finally generate encoding */ + + a->canon_enclen = i2d_name_canon(intname, NULL); + + p = OPENSSL_malloc(a->canon_enclen); + + if (!p) + goto err; + + a->canon_enc = p; + + i2d_name_canon(intname, &p); + + ret = 1; + + err: + + if (tmpentry) + X509_NAME_ENTRY_free(tmpentry); + if (intname) + sk_STACK_OF_X509_NAME_ENTRY_pop_free(intname, + local_sk_X509_NAME_ENTRY_pop_free); + return ret; + } + +/* Bitmap of all the types of string that will be canonicalized. */ + +#define ASN1_MASK_CANON \ + (B_ASN1_UTF8STRING | B_ASN1_BMPSTRING | B_ASN1_UNIVERSALSTRING \ + | B_ASN1_PRINTABLESTRING | B_ASN1_T61STRING | B_ASN1_IA5STRING \ + | B_ASN1_VISIBLESTRING) + + +static int asn1_string_canon(ASN1_STRING *out, ASN1_STRING *in) + { + unsigned char *to, *from; + int len, i; + + /* If type not in bitmask just copy string across */ + if (!(ASN1_tag2bit(in->type) & ASN1_MASK_CANON)) + { + if (!ASN1_STRING_copy(out, in)) + return 0; + return 1; + } + + out->type = V_ASN1_UTF8STRING; + out->length = ASN1_STRING_to_UTF8(&out->data, in); + if (out->length == -1) + return 0; + + to = out->data; + from = to; + + len = out->length; + + /* Convert string in place to canonical form. + * Ultimately we may need to handle a wider range of characters + * but for now ignore anything with MSB set and rely on the + * isspace() and tolower() functions. + */ + + /* Ignore leading spaces */ + while((len > 0) && !(*from & 0x80) && isspace(*from)) + { + from++; + len--; + } + + to = from + len - 1; + + /* Ignore trailing spaces */ + while ((len > 0) && !(*to & 0x80) && isspace(*to)) + { + to--; + len--; + } + + to = out->data; + + i = 0; + while(i < len) + { + /* If MSB set just copy across */ + if (*from & 0x80) + { + *to++ = *from++; + i++; + } + /* Collapse multiple spaces */ + else if (isspace(*from)) + { + /* Copy one space across */ + *to++ = ' '; + /* Ignore subsequent spaces. Note: don't need to + * check len here because we know the last + * character is a non-space so we can't overflow. + */ + do + { + from++; + i++; + } + while(!(*from & 0x80) && isspace(*from)); + } + else + { + *to++ = tolower(*from); + from++; + i++; + } + } + + out->length = to - out->data; + + return 1; + + } + +static int i2d_name_canon(STACK_OF(STACK_OF_X509_NAME_ENTRY) *_intname, + unsigned char **in) + { + int len, ltmp; + size_t i; + ASN1_VALUE *v; + STACK_OF(ASN1_VALUE) *intname = (STACK_OF(ASN1_VALUE) *)_intname; + + len = 0; + for (i = 0; i < sk_ASN1_VALUE_num(intname); i++) + { + v = sk_ASN1_VALUE_value(intname, i); + ltmp = ASN1_item_ex_i2d(&v, in, + ASN1_ITEM_rptr(X509_NAME_ENTRIES), -1, -1); + if (ltmp < 0) + return ltmp; + len += ltmp; + } + return len; + } + +int X509_NAME_set(X509_NAME **xn, X509_NAME *name) + { + X509_NAME *in; + + if (!xn || !name) return(0); + + if (*xn != name) + { + in=X509_NAME_dup(name); + if (in != NULL) + { + X509_NAME_free(*xn); + *xn=in; + } + } + return(*xn != NULL); + } + +IMPLEMENT_ASN1_SET_OF(X509_NAME_ENTRY) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_pkey.c b/TMessagesProj/jni/boringssl/crypto/x509/x_pkey.c new file mode 100644 index 00000000..f5e98b82 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_pkey.c @@ -0,0 +1,100 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include + +#include +#include +#include +#include + + +X509_PKEY *X509_PKEY_new(void) + { + X509_PKEY *ret = OPENSSL_malloc(sizeof(X509_PKEY)); + if (ret == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto err; + } + memset(ret, 0, sizeof(X509_PKEY)); + + ret->enc_algor = X509_ALGOR_new(); + if (ret->enc_algor == NULL) + goto err; + ret->enc_pkey = M_ASN1_OCTET_STRING_new(); + if (ret->enc_pkey == NULL) + goto err; + return ret; + +err: + if (ret != NULL) + X509_PKEY_free(ret); + return NULL; + } + +void X509_PKEY_free(X509_PKEY *x) + { + if (x == NULL) return; + + if (x->enc_algor != NULL) X509_ALGOR_free(x->enc_algor); + if (x->enc_pkey != NULL) M_ASN1_OCTET_STRING_free(x->enc_pkey); + if (x->dec_pkey != NULL)EVP_PKEY_free(x->dec_pkey); + if ((x->key_data != NULL) && (x->key_free)) OPENSSL_free(x->key_data); + OPENSSL_free(x); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_pubkey.c b/TMessagesProj/jni/boringssl/crypto/x509/x_pubkey.c new file mode 100644 index 00000000..a16edcab --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_pubkey.c @@ -0,0 +1,384 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../evp/internal.h" +#include "../internal.h" + + +/* Minor tweak to operation: free up EVP_PKEY */ +static int pubkey_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) + { + if (operation == ASN1_OP_FREE_POST) + { + X509_PUBKEY *pubkey = (X509_PUBKEY *)*pval; + EVP_PKEY_free(pubkey->pkey); + } + return 1; + } + +ASN1_SEQUENCE_cb(X509_PUBKEY, pubkey_cb) = { + ASN1_SIMPLE(X509_PUBKEY, algor, X509_ALGOR), + ASN1_SIMPLE(X509_PUBKEY, public_key, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END_cb(X509_PUBKEY, X509_PUBKEY) + +IMPLEMENT_ASN1_FUNCTIONS(X509_PUBKEY) + +int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey) + { + X509_PUBKEY *pk=NULL; + + if (x == NULL) return(0); + + if ((pk=X509_PUBKEY_new()) == NULL) goto error; + + if (pkey->ameth) + { + if (pkey->ameth->pub_encode) + { + if (!pkey->ameth->pub_encode(pk, pkey)) + { + OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_ENCODE_ERROR); + goto error; + } + } + else + { + OPENSSL_PUT_ERROR(X509, X509_R_METHOD_NOT_SUPPORTED); + goto error; + } + } + else + { + OPENSSL_PUT_ERROR(X509, X509_R_UNSUPPORTED_ALGORITHM); + goto error; + } + + if (*x != NULL) + X509_PUBKEY_free(*x); + + *x=pk; + + return 1; +error: + if (pk != NULL) X509_PUBKEY_free(pk); + return 0; + } + +/* g_pubkey_lock is used to protect the initialisation of the |pkey| member of + * |X509_PUBKEY| objects. Really |X509_PUBKEY| should have a |CRYPTO_once_t| + * inside it for this, but |CRYPTO_once_t| is private and |X509_PUBKEY| is + * not. */ +static struct CRYPTO_STATIC_MUTEX g_pubkey_lock = CRYPTO_STATIC_MUTEX_INIT; + +EVP_PKEY *X509_PUBKEY_get(X509_PUBKEY *key) + { + EVP_PKEY *ret=NULL; + + if (key == NULL) goto error; + + CRYPTO_STATIC_MUTEX_lock_read(&g_pubkey_lock); + if (key->pkey != NULL) + { + CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock); + return EVP_PKEY_up_ref(key->pkey); + } + CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock); + + if (key->public_key == NULL) goto error; + + if ((ret = EVP_PKEY_new()) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + goto error; + } + + if (!EVP_PKEY_set_type(ret, OBJ_obj2nid(key->algor->algorithm))) + { + OPENSSL_PUT_ERROR(X509, X509_R_UNSUPPORTED_ALGORITHM); + goto error; + } + + if (ret->ameth->pub_decode) + { + if (!ret->ameth->pub_decode(ret, key)) + { + OPENSSL_PUT_ERROR(X509, X509_R_PUBLIC_KEY_DECODE_ERROR); + goto error; + } + } + else + { + OPENSSL_PUT_ERROR(X509, X509_R_METHOD_NOT_SUPPORTED); + goto error; + } + + /* Check to see if another thread set key->pkey first */ + CRYPTO_STATIC_MUTEX_lock_write(&g_pubkey_lock); + if (key->pkey) + { + CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock); + EVP_PKEY_free(ret); + ret = key->pkey; + } + else + { + key->pkey = ret; + CRYPTO_STATIC_MUTEX_unlock(&g_pubkey_lock); + } + + return EVP_PKEY_up_ref(ret); + + error: + if (ret != NULL) + EVP_PKEY_free(ret); + return(NULL); + } + +/* Now two pseudo ASN1 routines that take an EVP_PKEY structure + * and encode or decode as X509_PUBKEY + */ + +EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, + long length) + { + X509_PUBKEY *xpk; + EVP_PKEY *pktmp; + xpk = d2i_X509_PUBKEY(NULL, pp, length); + if(!xpk) return NULL; + pktmp = X509_PUBKEY_get(xpk); + X509_PUBKEY_free(xpk); + if(!pktmp) return NULL; + if(a) + { + EVP_PKEY_free(*a); + *a = pktmp; + } + return pktmp; + } + +int i2d_PUBKEY(const EVP_PKEY *a, unsigned char **pp) + { + X509_PUBKEY *xpk=NULL; + int ret; + if(!a) return 0; + if(!X509_PUBKEY_set(&xpk, (EVP_PKEY*) a)) return 0; + ret = i2d_X509_PUBKEY(xpk, pp); + X509_PUBKEY_free(xpk); + return ret; + } + +/* The following are equivalents but which return RSA and DSA + * keys + */ +RSA *d2i_RSA_PUBKEY(RSA **a, const unsigned char **pp, + long length) + { + EVP_PKEY *pkey; + RSA *key; + const unsigned char *q; + q = *pp; + pkey = d2i_PUBKEY(NULL, &q, length); + if (!pkey) return NULL; + key = EVP_PKEY_get1_RSA(pkey); + EVP_PKEY_free(pkey); + if (!key) return NULL; + *pp = q; + if (a) + { + RSA_free(*a); + *a = key; + } + return key; + } + +int i2d_RSA_PUBKEY(const RSA *a, unsigned char **pp) + { + EVP_PKEY *pktmp; + int ret; + if (!a) return 0; + pktmp = EVP_PKEY_new(); + if (!pktmp) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + EVP_PKEY_set1_RSA(pktmp, (RSA*) a); + ret = i2d_PUBKEY(pktmp, pp); + EVP_PKEY_free(pktmp); + return ret; + } + +#ifndef OPENSSL_NO_DSA +DSA *d2i_DSA_PUBKEY(DSA **a, const unsigned char **pp, + long length) + { + EVP_PKEY *pkey; + DSA *key; + const unsigned char *q; + q = *pp; + pkey = d2i_PUBKEY(NULL, &q, length); + if (!pkey) return NULL; + key = EVP_PKEY_get1_DSA(pkey); + EVP_PKEY_free(pkey); + if (!key) return NULL; + *pp = q; + if (a) + { + DSA_free(*a); + *a = key; + } + return key; + } + +int i2d_DSA_PUBKEY(const DSA *a, unsigned char **pp) + { + EVP_PKEY *pktmp; + int ret; + if(!a) return 0; + pktmp = EVP_PKEY_new(); + if(!pktmp) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return 0; + } + EVP_PKEY_set1_DSA(pktmp, (DSA*) a); + ret = i2d_PUBKEY(pktmp, pp); + EVP_PKEY_free(pktmp); + return ret; + } +#endif + +EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, long length) + { + EVP_PKEY *pkey; + EC_KEY *key; + const unsigned char *q; + q = *pp; + pkey = d2i_PUBKEY(NULL, &q, length); + if (!pkey) return(NULL); + key = EVP_PKEY_get1_EC_KEY(pkey); + EVP_PKEY_free(pkey); + if (!key) return(NULL); + *pp = q; + if (a) + { + EC_KEY_free(*a); + *a = key; + } + return(key); + } + +int i2d_EC_PUBKEY(const EC_KEY *a, unsigned char **pp) + { + EVP_PKEY *pktmp; + int ret; + if (!a) return(0); + if ((pktmp = EVP_PKEY_new()) == NULL) + { + OPENSSL_PUT_ERROR(X509, ERR_R_MALLOC_FAILURE); + return(0); + } + EVP_PKEY_set1_EC_KEY(pktmp, (EC_KEY*) a); + ret = i2d_PUBKEY(pktmp, pp); + EVP_PKEY_free(pktmp); + return(ret); + } + +int X509_PUBKEY_set0_param(X509_PUBKEY *pub, const ASN1_OBJECT *aobj, + int ptype, void *pval, + unsigned char *penc, int penclen) + { + if (!X509_ALGOR_set0(pub->algor, aobj, ptype, pval)) + return 0; + if (penc) + { + if (pub->public_key->data) + OPENSSL_free(pub->public_key->data); + pub->public_key->data = penc; + pub->public_key->length = penclen; + /* Set number of unused bits to zero */ + pub->public_key->flags&= ~(ASN1_STRING_FLAG_BITS_LEFT|0x07); + pub->public_key->flags|=ASN1_STRING_FLAG_BITS_LEFT; + } + return 1; + } + +int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg, + const unsigned char **pk, int *ppklen, + X509_ALGOR **pa, + X509_PUBKEY *pub) + { + if (ppkalg) + *ppkalg = pub->algor->algorithm; + if (pk) + { + *pk = pub->public_key->data; + *ppklen = pub->public_key->length; + } + if (pa) + *pa = pub->algor; + return 1; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_req.c b/TMessagesProj/jni/boringssl/crypto/x509/x_req.c new file mode 100644 index 00000000..3d301297 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_req.c @@ -0,0 +1,112 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include + +/* X509_REQ_INFO is handled in an unusual way to get round + * invalid encodings. Some broken certificate requests don't + * encode the attributes field if it is empty. This is in + * violation of PKCS#10 but we need to tolerate it. We do + * this by making the attributes field OPTIONAL then using + * the callback to initialise it to an empty STACK. + * + * This means that the field will be correctly encoded unless + * we NULL out the field. + * + * As a result we no longer need the req_kludge field because + * the information is now contained in the attributes field: + * 1. If it is NULL then it's the invalid omission. + * 2. If it is empty it is the correct encoding. + * 3. If it is not empty then some attributes are present. + * + */ + +static int rinf_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) +{ + X509_REQ_INFO *rinf = (X509_REQ_INFO *)*pval; + + if(operation == ASN1_OP_NEW_POST) { + rinf->attributes = sk_X509_ATTRIBUTE_new_null(); + if(!rinf->attributes) return 0; + } + return 1; +} + +ASN1_SEQUENCE_enc(X509_REQ_INFO, enc, rinf_cb) = { + ASN1_SIMPLE(X509_REQ_INFO, version, ASN1_INTEGER), + ASN1_SIMPLE(X509_REQ_INFO, subject, X509_NAME), + ASN1_SIMPLE(X509_REQ_INFO, pubkey, X509_PUBKEY), + /* This isn't really OPTIONAL but it gets round invalid + * encodings + */ + ASN1_IMP_SET_OF_OPT(X509_REQ_INFO, attributes, X509_ATTRIBUTE, 0) +} ASN1_SEQUENCE_END_enc(X509_REQ_INFO, X509_REQ_INFO) + +IMPLEMENT_ASN1_FUNCTIONS(X509_REQ_INFO) + +ASN1_SEQUENCE_ref(X509_REQ, 0) = { + ASN1_SIMPLE(X509_REQ, req_info, X509_REQ_INFO), + ASN1_SIMPLE(X509_REQ, sig_alg, X509_ALGOR), + ASN1_SIMPLE(X509_REQ, signature, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END_ref(X509_REQ, X509_REQ) + +IMPLEMENT_ASN1_FUNCTIONS(X509_REQ) +IMPLEMENT_ASN1_DUP_FUNCTION(X509_REQ) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_sig.c b/TMessagesProj/jni/boringssl/crypto/x509/x_sig.c new file mode 100644 index 00000000..fabdb676 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_sig.c @@ -0,0 +1,69 @@ +/* crypto/asn1/x_sig.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +ASN1_SEQUENCE(X509_SIG) = { + ASN1_SIMPLE(X509_SIG, algor, X509_ALGOR), + ASN1_SIMPLE(X509_SIG, digest, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(X509_SIG) + +IMPLEMENT_ASN1_FUNCTIONS(X509_SIG) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_spki.c b/TMessagesProj/jni/boringssl/crypto/x509/x_spki.c new file mode 100644 index 00000000..35bf2465 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_spki.c @@ -0,0 +1,78 @@ +/* crypto/asn1/x_spki.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + + /* This module was send to me my Pat Richards who + * wrote it. It is under my Copyright with his permission. */ + +#include +#include + + +ASN1_SEQUENCE(NETSCAPE_SPKAC) = { + ASN1_SIMPLE(NETSCAPE_SPKAC, pubkey, X509_PUBKEY), + ASN1_SIMPLE(NETSCAPE_SPKAC, challenge, ASN1_IA5STRING) +} ASN1_SEQUENCE_END(NETSCAPE_SPKAC) + +IMPLEMENT_ASN1_FUNCTIONS(NETSCAPE_SPKAC) + +ASN1_SEQUENCE(NETSCAPE_SPKI) = { + ASN1_SIMPLE(NETSCAPE_SPKI, spkac, NETSCAPE_SPKAC), + ASN1_SIMPLE(NETSCAPE_SPKI, sig_algor, X509_ALGOR), + ASN1_SIMPLE(NETSCAPE_SPKI, signature, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END(NETSCAPE_SPKI) + +IMPLEMENT_ASN1_FUNCTIONS(NETSCAPE_SPKI) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_val.c b/TMessagesProj/jni/boringssl/crypto/x509/x_val.c new file mode 100644 index 00000000..26200ee4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_val.c @@ -0,0 +1,69 @@ +/* crypto/asn1/x_val.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include + + +ASN1_SEQUENCE(X509_VAL) = { + ASN1_SIMPLE(X509_VAL, notBefore, ASN1_TIME), + ASN1_SIMPLE(X509_VAL, notAfter, ASN1_TIME) +} ASN1_SEQUENCE_END(X509_VAL) + +IMPLEMENT_ASN1_FUNCTIONS(X509_VAL) diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_x509.c b/TMessagesProj/jni/boringssl/crypto/x509/x_x509.c new file mode 100644 index 00000000..c975dd35 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_x509.c @@ -0,0 +1,228 @@ +/* crypto/asn1/x_x509.c */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "../internal.h" + + +static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT; + +ASN1_SEQUENCE_enc(X509_CINF, enc, 0) = { + ASN1_EXP_OPT(X509_CINF, version, ASN1_INTEGER, 0), + ASN1_SIMPLE(X509_CINF, serialNumber, ASN1_INTEGER), + ASN1_SIMPLE(X509_CINF, signature, X509_ALGOR), + ASN1_SIMPLE(X509_CINF, issuer, X509_NAME), + ASN1_SIMPLE(X509_CINF, validity, X509_VAL), + ASN1_SIMPLE(X509_CINF, subject, X509_NAME), + ASN1_SIMPLE(X509_CINF, key, X509_PUBKEY), + ASN1_IMP_OPT(X509_CINF, issuerUID, ASN1_BIT_STRING, 1), + ASN1_IMP_OPT(X509_CINF, subjectUID, ASN1_BIT_STRING, 2), + ASN1_EXP_SEQUENCE_OF_OPT(X509_CINF, extensions, X509_EXTENSION, 3) +} ASN1_SEQUENCE_END_enc(X509_CINF, X509_CINF) + +IMPLEMENT_ASN1_FUNCTIONS(X509_CINF) +/* X509 top level structure needs a bit of customisation */ + +extern void policy_cache_free(X509_POLICY_CACHE *cache); + +static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) +{ + X509 *ret = (X509 *)*pval; + + switch(operation) { + + case ASN1_OP_NEW_POST: + ret->valid=0; + ret->name = NULL; + ret->ex_flags = 0; + ret->ex_pathlen = -1; + ret->skid = NULL; + ret->akid = NULL; + ret->aux = NULL; + ret->crldp = NULL; + CRYPTO_new_ex_data(&g_ex_data_class, ret, &ret->ex_data); + break; + + case ASN1_OP_D2I_POST: + if (ret->name != NULL) OPENSSL_free(ret->name); + ret->name=X509_NAME_oneline(ret->cert_info->subject,NULL,0); + break; + + case ASN1_OP_FREE_POST: + CRYPTO_free_ex_data(&g_ex_data_class, ret, &ret->ex_data); + X509_CERT_AUX_free(ret->aux); + ASN1_OCTET_STRING_free(ret->skid); + AUTHORITY_KEYID_free(ret->akid); + CRL_DIST_POINTS_free(ret->crldp); + policy_cache_free(ret->policy_cache); + GENERAL_NAMES_free(ret->altname); + NAME_CONSTRAINTS_free(ret->nc); + + if (ret->name != NULL) OPENSSL_free(ret->name); + break; + + } + + return 1; + +} + +ASN1_SEQUENCE_ref(X509, x509_cb) = { + ASN1_SIMPLE(X509, cert_info, X509_CINF), + ASN1_SIMPLE(X509, sig_alg, X509_ALGOR), + ASN1_SIMPLE(X509, signature, ASN1_BIT_STRING) +} ASN1_SEQUENCE_END_ref(X509, X509) + +IMPLEMENT_ASN1_FUNCTIONS(X509) +IMPLEMENT_ASN1_DUP_FUNCTION(X509) + +X509 *X509_up_ref(X509 *x) + { + CRYPTO_refcount_inc(&x->references); + return x; + } + +int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) + { + int index; + if (!CRYPTO_get_ex_new_index(&g_ex_data_class, &index, argl, argp, + new_func, dup_func, free_func)) + { + return -1; + } + return index; + } + +int X509_set_ex_data(X509 *r, int idx, void *arg) + { + return(CRYPTO_set_ex_data(&r->ex_data,idx,arg)); + } + +void *X509_get_ex_data(X509 *r, int idx) + { + return(CRYPTO_get_ex_data(&r->ex_data,idx)); + } + +/* X509_AUX ASN1 routines. X509_AUX is the name given to + * a certificate with extra info tagged on the end. Since these + * functions set how a certificate is trusted they should only + * be used when the certificate comes from a reliable source + * such as local storage. + * + */ + +X509 *d2i_X509_AUX(X509 **a, const unsigned char **pp, long length) +{ + const unsigned char *q; + X509 *ret; + int freeret = 0; + + /* Save start position */ + q = *pp; + + if (!a || *a == NULL) + freeret = 1; + ret = d2i_X509(a, pp, length); + /* If certificate unreadable then forget it */ + if(!ret) return NULL; + /* update length */ + length -= *pp - q; + if(!length) return ret; + if(!d2i_X509_CERT_AUX(&ret->aux, pp, length)) goto err; + return ret; + err: + if (freeret) + { + X509_free(ret); + if (a) + *a = NULL; + } + return NULL; +} + +int i2d_X509_AUX(X509 *a, unsigned char **pp) +{ + int length; + length = i2d_X509(a, pp); + if(a) length += i2d_X509_CERT_AUX(a->aux, pp); + return length; +} + +void X509_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, + const X509 *x) + { + if (psig) + *psig = x->signature; + if (palg) + *palg = x->sig_alg; + } + +int X509_get_signature_nid(const X509 *x) + { + return OBJ_obj2nid(x->sig_alg->algorithm); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509/x_x509a.c b/TMessagesProj/jni/boringssl/crypto/x509/x_x509a.c new file mode 100644 index 00000000..e13204b8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509/x_x509a.c @@ -0,0 +1,177 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include + + +/* X509_CERT_AUX routines. These are used to encode additional + * user modifiable data about a certificate. This data is + * appended to the X509 encoding when the *_X509_AUX routines + * are used. This means that the "traditional" X509 routines + * will simply ignore the extra data. */ + +static X509_CERT_AUX *aux_get(X509 *x); + +ASN1_SEQUENCE(X509_CERT_AUX) = { + ASN1_SEQUENCE_OF_OPT(X509_CERT_AUX, trust, ASN1_OBJECT), + ASN1_IMP_SEQUENCE_OF_OPT(X509_CERT_AUX, reject, ASN1_OBJECT, 0), + ASN1_OPT(X509_CERT_AUX, alias, ASN1_UTF8STRING), + ASN1_OPT(X509_CERT_AUX, keyid, ASN1_OCTET_STRING), + ASN1_IMP_SEQUENCE_OF_OPT(X509_CERT_AUX, other, X509_ALGOR, 1) +} ASN1_SEQUENCE_END(X509_CERT_AUX) + +IMPLEMENT_ASN1_FUNCTIONS(X509_CERT_AUX) + +static X509_CERT_AUX *aux_get(X509 *x) +{ + if(!x) return NULL; + if(!x->aux && !(x->aux = X509_CERT_AUX_new())) return NULL; + return x->aux; +} + +int X509_alias_set1(X509 *x, unsigned char *name, int len) +{ + X509_CERT_AUX *aux; + if (!name) + { + if (!x || !x->aux || !x->aux->alias) + return 1; + ASN1_UTF8STRING_free(x->aux->alias); + x->aux->alias = NULL; + return 1; + } + if(!(aux = aux_get(x))) return 0; + if(!aux->alias && !(aux->alias = ASN1_UTF8STRING_new())) return 0; + return ASN1_STRING_set(aux->alias, name, len); +} + +int X509_keyid_set1(X509 *x, unsigned char *id, int len) +{ + X509_CERT_AUX *aux; + if (!id) + { + if (!x || !x->aux || !x->aux->keyid) + return 1; + ASN1_OCTET_STRING_free(x->aux->keyid); + x->aux->keyid = NULL; + return 1; + } + if(!(aux = aux_get(x))) return 0; + if(!aux->keyid && !(aux->keyid = ASN1_OCTET_STRING_new())) return 0; + return ASN1_STRING_set(aux->keyid, id, len); +} + +unsigned char *X509_alias_get0(X509 *x, int *len) +{ + if(!x->aux || !x->aux->alias) return NULL; + if(len) *len = x->aux->alias->length; + return x->aux->alias->data; +} + +unsigned char *X509_keyid_get0(X509 *x, int *len) +{ + if(!x->aux || !x->aux->keyid) return NULL; + if(len) *len = x->aux->keyid->length; + return x->aux->keyid->data; +} + +int X509_add1_trust_object(X509 *x, ASN1_OBJECT *obj) +{ + X509_CERT_AUX *aux; + ASN1_OBJECT *objtmp; + if(!(objtmp = OBJ_dup(obj))) return 0; + if(!(aux = aux_get(x))) return 0; + if(!aux->trust + && !(aux->trust = sk_ASN1_OBJECT_new_null())) return 0; + return sk_ASN1_OBJECT_push(aux->trust, objtmp); +} + +int X509_add1_reject_object(X509 *x, ASN1_OBJECT *obj) +{ + X509_CERT_AUX *aux; + ASN1_OBJECT *objtmp; + if(!(objtmp = OBJ_dup(obj))) return 0; + if(!(aux = aux_get(x))) return 0; + if(!aux->reject + && !(aux->reject = sk_ASN1_OBJECT_new_null())) return 0; + return sk_ASN1_OBJECT_push(aux->reject, objtmp); +} + +void X509_trust_clear(X509 *x) +{ + if(x->aux && x->aux->trust) { + sk_ASN1_OBJECT_pop_free(x->aux->trust, ASN1_OBJECT_free); + x->aux->trust = NULL; + } +} + +void X509_reject_clear(X509 *x) +{ + if(x->aux && x->aux->reject) { + sk_ASN1_OBJECT_pop_free(x->aux->reject, ASN1_OBJECT_free); + x->aux->reject = NULL; + } +} + +ASN1_SEQUENCE(X509_CERT_PAIR) = { + ASN1_EXP_OPT(X509_CERT_PAIR, forward, X509, 0), + ASN1_EXP_OPT(X509_CERT_PAIR, reverse, X509, 1) +} ASN1_SEQUENCE_END(X509_CERT_PAIR) + +IMPLEMENT_ASN1_FUNCTIONS(X509_CERT_PAIR) diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/CMakeLists.txt b/TMessagesProj/jni/boringssl/crypto/x509v3/CMakeLists.txt new file mode 100644 index 00000000..b8418a95 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/CMakeLists.txt @@ -0,0 +1,44 @@ +include_directories(. .. ../../include) + +add_library( + x509v3 + + OBJECT + + # v3_addr.c - disabled by upstream by default. + # v3_asid.c - disabled by upstream by default. + # v3_ocsp.c - missing OCSP for now. + + pcy_cache.c + pcy_data.c + pcy_lib.c + pcy_map.c + pcy_node.c + pcy_tree.c + v3_akey.c + v3_akeya.c + v3_alt.c + v3_bcons.c + v3_bitst.c + v3_conf.c + v3_cpols.c + v3_crld.c + v3_enum.c + v3_extku.c + v3_genn.c + v3_ia5.c + v3_info.c + v3_int.c + v3_lib.c + v3_ncons.c + v3_pci.c + v3_pcia.c + v3_pcons.c + v3_pku.c + v3_pmaps.c + v3_prn.c + v3_purp.c + v3_skey.c + v3_sxnet.c + v3_utl.c +) diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/ext_dat.h b/TMessagesProj/jni/boringssl/crypto/x509v3/ext_dat.h new file mode 100644 index 00000000..8b2c123b --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/ext_dat.h @@ -0,0 +1,129 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +/* This file contains a table of "standard" extensions */ + +extern X509V3_EXT_METHOD v3_bcons, v3_nscert, v3_key_usage, v3_ext_ku; +extern X509V3_EXT_METHOD v3_pkey_usage_period, v3_sxnet, v3_info, v3_sinfo; +extern X509V3_EXT_METHOD v3_ns_ia5_list[], v3_alt[], v3_skey_id, v3_akey_id; +extern X509V3_EXT_METHOD v3_crl_num, v3_crl_reason, v3_crl_invdate; +extern X509V3_EXT_METHOD v3_delta_crl, v3_cpols, v3_crld, v3_freshest_crl; +extern X509V3_EXT_METHOD v3_ocsp_nonce, v3_ocsp_accresp, v3_ocsp_acutoff; +extern X509V3_EXT_METHOD v3_ocsp_crlid, v3_ocsp_nocheck, v3_ocsp_serviceloc; +extern X509V3_EXT_METHOD v3_crl_hold, v3_pci; +extern X509V3_EXT_METHOD v3_policy_mappings, v3_policy_constraints; +extern X509V3_EXT_METHOD v3_name_constraints, v3_inhibit_anyp, v3_idp; +extern X509V3_EXT_METHOD v3_addr, v3_asid; + +/* This table will be searched using OBJ_bsearch so it *must* kept in + * order of the ext_nid values. + */ + +/* TODO(fork): OCSP support */ +#define OPENSSL_NO_OCSP + +static const X509V3_EXT_METHOD *const standard_exts[] = { +&v3_nscert, +&v3_ns_ia5_list[0], +&v3_ns_ia5_list[1], +&v3_ns_ia5_list[2], +&v3_ns_ia5_list[3], +&v3_ns_ia5_list[4], +&v3_ns_ia5_list[5], +&v3_ns_ia5_list[6], +&v3_skey_id, +&v3_key_usage, +&v3_pkey_usage_period, +&v3_alt[0], +&v3_alt[1], +&v3_bcons, +&v3_crl_num, +&v3_cpols, +&v3_akey_id, +&v3_crld, +&v3_ext_ku, +&v3_delta_crl, +&v3_crl_reason, +#ifndef OPENSSL_NO_OCSP +&v3_crl_invdate, +#endif +&v3_sxnet, +&v3_info, +#ifndef OPENSSL_NO_OCSP +&v3_ocsp_nonce, +&v3_ocsp_crlid, +&v3_ocsp_accresp, +&v3_ocsp_nocheck, +&v3_ocsp_acutoff, +&v3_ocsp_serviceloc, +#endif +&v3_sinfo, +&v3_policy_constraints, +#ifndef OPENSSL_NO_OCSP +&v3_crl_hold, +#endif +&v3_pci, +&v3_name_constraints, +&v3_policy_mappings, +&v3_inhibit_anyp, +&v3_idp, +&v3_alt[2], +&v3_freshest_crl, +}; + +/* Number of standard extensions */ + +#define STANDARD_EXTENSION_COUNT (sizeof(standard_exts)/sizeof(X509V3_EXT_METHOD *)) + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_cache.c b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_cache.c new file mode 100644 index 00000000..08f20aa2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_cache.c @@ -0,0 +1,299 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include +#include +#include +#include + +#include "pcy_int.h" +#include "../internal.h" + + +static int policy_data_cmp(const X509_POLICY_DATA **a, + const X509_POLICY_DATA **b); +static int policy_cache_set_int(long *out, ASN1_INTEGER *value); + +/* Set cache entry according to CertificatePolicies extension. + * Note: this destroys the passed CERTIFICATEPOLICIES structure. + */ + +static int policy_cache_create(X509 *x, + CERTIFICATEPOLICIES *policies, int crit) + { + size_t i; + int ret = 0; + X509_POLICY_CACHE *cache = x->policy_cache; + X509_POLICY_DATA *data = NULL; + POLICYINFO *policy; + if (sk_POLICYINFO_num(policies) == 0) + goto bad_policy; + cache->data = sk_X509_POLICY_DATA_new(policy_data_cmp); + if (!cache->data) + goto bad_policy; + for (i = 0; i < sk_POLICYINFO_num(policies); i++) + { + policy = sk_POLICYINFO_value(policies, i); + data = policy_data_new(policy, NULL, crit); + if (!data) + goto bad_policy; + /* Duplicate policy OIDs are illegal: reject if matches + * found. + */ + if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) + { + if (cache->anyPolicy) + { + ret = -1; + goto bad_policy; + } + cache->anyPolicy = data; + } + else if (sk_X509_POLICY_DATA_find(cache->data, NULL, data)) + { + ret = -1; + goto bad_policy; + } + else if (!sk_X509_POLICY_DATA_push(cache->data, data)) + goto bad_policy; + data = NULL; + } + ret = 1; + bad_policy: + if (ret == -1) + x->ex_flags |= EXFLAG_INVALID_POLICY; + if (data) + policy_data_free(data); + sk_POLICYINFO_pop_free(policies, POLICYINFO_free); + if (ret <= 0) + { + sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free); + cache->data = NULL; + } + return ret; + } + + +static int policy_cache_new(X509 *x) + { + X509_POLICY_CACHE *cache; + ASN1_INTEGER *ext_any = NULL; + POLICY_CONSTRAINTS *ext_pcons = NULL; + CERTIFICATEPOLICIES *ext_cpols = NULL; + POLICY_MAPPINGS *ext_pmaps = NULL; + int i; + cache = OPENSSL_malloc(sizeof(X509_POLICY_CACHE)); + if (!cache) + return 0; + cache->anyPolicy = NULL; + cache->data = NULL; + cache->any_skip = -1; + cache->explicit_skip = -1; + cache->map_skip = -1; + + x->policy_cache = cache; + + /* Handle requireExplicitPolicy *first*. Need to process this + * even if we don't have any policies. + */ + ext_pcons = X509_get_ext_d2i(x, NID_policy_constraints, &i, NULL); + + if (!ext_pcons) + { + if (i != -1) + goto bad_cache; + } + else + { + if (!ext_pcons->requireExplicitPolicy + && !ext_pcons->inhibitPolicyMapping) + goto bad_cache; + if (!policy_cache_set_int(&cache->explicit_skip, + ext_pcons->requireExplicitPolicy)) + goto bad_cache; + if (!policy_cache_set_int(&cache->map_skip, + ext_pcons->inhibitPolicyMapping)) + goto bad_cache; + } + + /* Process CertificatePolicies */ + + ext_cpols = X509_get_ext_d2i(x, NID_certificate_policies, &i, NULL); + /* If no CertificatePolicies extension or problem decoding then + * there is no point continuing because the valid policies will be + * NULL. + */ + if (!ext_cpols) + { + /* If not absent some problem with extension */ + if (i != -1) + goto bad_cache; + return 1; + } + + i = policy_cache_create(x, ext_cpols, i); + + /* NB: ext_cpols freed by policy_cache_set_policies */ + + if (i <= 0) + return i; + + ext_pmaps = X509_get_ext_d2i(x, NID_policy_mappings, &i, NULL); + + if (!ext_pmaps) + { + /* If not absent some problem with extension */ + if (i != -1) + goto bad_cache; + } + else + { + i = policy_cache_set_mapping(x, ext_pmaps); + if (i <= 0) + goto bad_cache; + } + + ext_any = X509_get_ext_d2i(x, NID_inhibit_any_policy, &i, NULL); + + if (!ext_any) + { + if (i != -1) + goto bad_cache; + } + else if (!policy_cache_set_int(&cache->any_skip, ext_any)) + goto bad_cache; + + if (0) + { + bad_cache: + x->ex_flags |= EXFLAG_INVALID_POLICY; + } + + if(ext_pcons) + POLICY_CONSTRAINTS_free(ext_pcons); + + if (ext_any) + ASN1_INTEGER_free(ext_any); + + return 1; + + +} + +void policy_cache_free(X509_POLICY_CACHE *cache) + { + if (!cache) + return; + if (cache->anyPolicy) + policy_data_free(cache->anyPolicy); + if (cache->data) + sk_X509_POLICY_DATA_pop_free(cache->data, policy_data_free); + OPENSSL_free(cache); + } + +/* g_x509_policy_cache_lock is used to protect against concurrent calls to + * |policy_cache_new|. Ideally this would be done with a |CRYPTO_once_t| + * in the |X509| structure, but |CRYPTO_once_t| isn't public. */ +static struct CRYPTO_STATIC_MUTEX g_x509_policy_cache_lock = + CRYPTO_STATIC_MUTEX_INIT; + +const X509_POLICY_CACHE *policy_cache_set(X509 *x) + { + X509_POLICY_CACHE *cache; + + CRYPTO_STATIC_MUTEX_lock_read(&g_x509_policy_cache_lock); + cache = x->policy_cache; + CRYPTO_STATIC_MUTEX_unlock(&g_x509_policy_cache_lock); + + if (cache != NULL) + return cache; + + CRYPTO_STATIC_MUTEX_lock_write(&g_x509_policy_cache_lock); + if (x->policy_cache == NULL) + policy_cache_new(x); + cache = x->policy_cache; + CRYPTO_STATIC_MUTEX_unlock(&g_x509_policy_cache_lock); + + return cache; + } + +X509_POLICY_DATA *policy_cache_find_data(const X509_POLICY_CACHE *cache, + const ASN1_OBJECT *id) + { + size_t idx; + X509_POLICY_DATA tmp; + + tmp.valid_policy = (ASN1_OBJECT *)id; + if (!sk_X509_POLICY_DATA_find(cache->data, &idx, &tmp)) + return NULL; + return sk_X509_POLICY_DATA_value(cache->data, idx); + } + +static int policy_data_cmp(const X509_POLICY_DATA **a, + const X509_POLICY_DATA **b) + { + return OBJ_cmp((*a)->valid_policy, (*b)->valid_policy); + } + +static int policy_cache_set_int(long *out, ASN1_INTEGER *value) + { + if (value == NULL) + return 1; + if (value->type == V_ASN1_NEG_INTEGER) + return 0; + *out = ASN1_INTEGER_get(value); + return 1; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_data.c b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_data.c new file mode 100644 index 00000000..cd45dcaa --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_data.c @@ -0,0 +1,137 @@ +/* pcy_data.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include +#include +#include + +#include "pcy_int.h" + + +/* Policy Node routines */ + +void policy_data_free(X509_POLICY_DATA *data) + { + ASN1_OBJECT_free(data->valid_policy); + /* Don't free qualifiers if shared */ + if (!(data->flags & POLICY_DATA_FLAG_SHARED_QUALIFIERS)) + sk_POLICYQUALINFO_pop_free(data->qualifier_set, + POLICYQUALINFO_free); + sk_ASN1_OBJECT_pop_free(data->expected_policy_set, ASN1_OBJECT_free); + OPENSSL_free(data); + } + +/* Create a data based on an existing policy. If 'id' is NULL use the + * oid in the policy, otherwise use 'id'. This behaviour covers the two + * types of data in RFC3280: data with from a CertificatePolcies extension + * and additional data with just the qualifiers of anyPolicy and ID from + * another source. + */ + +X509_POLICY_DATA *policy_data_new(POLICYINFO *policy, + const ASN1_OBJECT *cid, int crit) + { + X509_POLICY_DATA *ret; + ASN1_OBJECT *id; + if (!policy && !cid) + return NULL; + if (cid) + { + id = OBJ_dup(cid); + if (!id) + return NULL; + } + else + id = NULL; + ret = OPENSSL_malloc(sizeof(X509_POLICY_DATA)); + if (!ret) + return NULL; + ret->expected_policy_set = sk_ASN1_OBJECT_new_null(); + if (!ret->expected_policy_set) + { + OPENSSL_free(ret); + if (id) + ASN1_OBJECT_free(id); + return NULL; + } + + if (crit) + ret->flags = POLICY_DATA_FLAG_CRITICAL; + else + ret->flags = 0; + + if (id) + ret->valid_policy = id; + else + { + ret->valid_policy = policy->policyid; + policy->policyid = NULL; + } + + if (policy) + { + ret->qualifier_set = policy->qualifiers; + policy->qualifiers = NULL; + } + else + ret->qualifier_set = NULL; + + return ret; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_int.h b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_int.h new file mode 100644 index 00000000..ccff9284 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_int.h @@ -0,0 +1,212 @@ +/* pcy_int.h */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + +typedef struct X509_POLICY_DATA_st X509_POLICY_DATA; + +DECLARE_STACK_OF(X509_POLICY_DATA) + +/* Internal structures */ + +/* This structure and the field names correspond to the Policy 'node' of + * RFC3280. NB this structure contains no pointers to parent or child + * data: X509_POLICY_NODE contains that. This means that the main policy data + * can be kept static and cached with the certificate. + */ + +struct X509_POLICY_DATA_st + { + unsigned int flags; + /* Policy OID and qualifiers for this data */ + ASN1_OBJECT *valid_policy; + STACK_OF(POLICYQUALINFO) *qualifier_set; + STACK_OF(ASN1_OBJECT) *expected_policy_set; + }; + +/* X509_POLICY_DATA flags values */ + +/* This flag indicates the structure has been mapped using a policy mapping + * extension. If policy mapping is not active its references get deleted. + */ + +#define POLICY_DATA_FLAG_MAPPED 0x1 + +/* This flag indicates the data doesn't correspond to a policy in Certificate + * Policies: it has been mapped to any policy. + */ + +#define POLICY_DATA_FLAG_MAPPED_ANY 0x2 + +/* AND with flags to see if any mapping has occurred */ + +#define POLICY_DATA_FLAG_MAP_MASK 0x3 + +/* qualifiers are shared and shouldn't be freed */ + +#define POLICY_DATA_FLAG_SHARED_QUALIFIERS 0x4 + +/* Parent node is an extra node and should be freed */ + +#define POLICY_DATA_FLAG_EXTRA_NODE 0x8 + +/* Corresponding CertificatePolicies is critical */ + +#define POLICY_DATA_FLAG_CRITICAL 0x10 + +/* This structure is cached with a certificate */ + +struct X509_POLICY_CACHE_st { + /* anyPolicy data or NULL if no anyPolicy */ + X509_POLICY_DATA *anyPolicy; + /* other policy data */ + STACK_OF(X509_POLICY_DATA) *data; + /* If InhibitAnyPolicy present this is its value or -1 if absent. */ + long any_skip; + /* If policyConstraints and requireExplicitPolicy present this is its + * value or -1 if absent. + */ + long explicit_skip; + /* If policyConstraints and policyMapping present this is its + * value or -1 if absent. + */ + long map_skip; + }; + +/*#define POLICY_CACHE_FLAG_CRITICAL POLICY_DATA_FLAG_CRITICAL*/ + +/* This structure represents the relationship between nodes */ + +struct X509_POLICY_NODE_st + { + /* node data this refers to */ + const X509_POLICY_DATA *data; + /* Parent node */ + X509_POLICY_NODE *parent; + /* Number of child nodes */ + int nchild; + }; + +struct X509_POLICY_LEVEL_st + { + /* Cert for this level */ + X509 *cert; + /* nodes at this level */ + STACK_OF(X509_POLICY_NODE) *nodes; + /* anyPolicy node */ + X509_POLICY_NODE *anyPolicy; + /* Extra data */ + /*STACK_OF(X509_POLICY_DATA) *extra_data;*/ + unsigned int flags; + }; + +struct X509_POLICY_TREE_st + { + /* This is the tree 'level' data */ + X509_POLICY_LEVEL *levels; + int nlevel; + /* Extra policy data when additional nodes (not from the certificate) + * are required. + */ + STACK_OF(X509_POLICY_DATA) *extra_data; + /* This is the authority constained policy set */ + STACK_OF(X509_POLICY_NODE) *auth_policies; + STACK_OF(X509_POLICY_NODE) *user_policies; + unsigned int flags; + }; + +/* Set if anyPolicy present in user policies */ +#define POLICY_FLAG_ANY_POLICY 0x2 + +/* Useful macros */ + +#define node_data_critical(data) (data->flags & POLICY_DATA_FLAG_CRITICAL) +#define node_critical(node) node_data_critical(node->data) + +/* Internal functions */ + +X509_POLICY_DATA *policy_data_new(POLICYINFO *policy, const ASN1_OBJECT *id, + int crit); +void policy_data_free(X509_POLICY_DATA *data); + +X509_POLICY_DATA *policy_cache_find_data(const X509_POLICY_CACHE *cache, + const ASN1_OBJECT *id); +int policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps); + + +STACK_OF(X509_POLICY_NODE) *policy_node_cmp_new(void); + +void policy_cache_init(void); + +void policy_cache_free(X509_POLICY_CACHE *cache); + +X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level, + const X509_POLICY_NODE *parent, + const ASN1_OBJECT *id); + +X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_NODE) *sk, + const ASN1_OBJECT *id); + +X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, + const X509_POLICY_DATA *data, + X509_POLICY_NODE *parent, + X509_POLICY_TREE *tree); +void policy_node_free(X509_POLICY_NODE *node); +int policy_node_match(const X509_POLICY_LEVEL *lvl, + const X509_POLICY_NODE *node, const ASN1_OBJECT *oid); + +const X509_POLICY_CACHE *policy_cache_set(X509 *x); diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_lib.c b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_lib.c new file mode 100644 index 00000000..16be2f00 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_lib.c @@ -0,0 +1,165 @@ +/* pcy_lib.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include +#include + +#include "pcy_int.h" + + +/* accessor functions */ + +/* X509_POLICY_TREE stuff */ + +int X509_policy_tree_level_count(const X509_POLICY_TREE *tree) + { + if (!tree) + return 0; + return tree->nlevel; + } + +X509_POLICY_LEVEL * + X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, int i) + { + if (!tree || (i < 0) || (i >= tree->nlevel)) + return NULL; + return tree->levels + i; + } + +STACK_OF(X509_POLICY_NODE) * + X509_policy_tree_get0_policies(const X509_POLICY_TREE *tree) + { + if (!tree) + return NULL; + return tree->auth_policies; + } + +STACK_OF(X509_POLICY_NODE) * + X509_policy_tree_get0_user_policies(const X509_POLICY_TREE *tree) + { + if (!tree) + return NULL; + if (tree->flags & POLICY_FLAG_ANY_POLICY) + return tree->auth_policies; + else + return tree->user_policies; + } + +/* X509_POLICY_LEVEL stuff */ + +int X509_policy_level_node_count(X509_POLICY_LEVEL *level) + { + int n; + if (!level) + return 0; + if (level->anyPolicy) + n = 1; + else + n = 0; + if (level->nodes) + n += sk_X509_POLICY_NODE_num(level->nodes); + return n; + } + +X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i) + { + if (!level) + return NULL; + if (level->anyPolicy) + { + if (i == 0) + return level->anyPolicy; + i--; + } + return sk_X509_POLICY_NODE_value(level->nodes, i); + } + +/* X509_POLICY_NODE stuff */ + +const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node) + { + if (!node) + return NULL; + return node->data->valid_policy; + } + +#if 0 +int X509_policy_node_get_critical(const X509_POLICY_NODE *node) + { + if (node_critical(node)) + return 1; + return 0; + } +#endif + +STACK_OF(POLICYQUALINFO) * + X509_policy_node_get0_qualifiers(const X509_POLICY_NODE *node) + { + if (!node) + return NULL; + return node->data->qualifier_set; + } + +const X509_POLICY_NODE * + X509_policy_node_get0_parent(const X509_POLICY_NODE *node) + { + if (!node) + return NULL; + return node->parent; + } + + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_map.c b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_map.c new file mode 100644 index 00000000..2b8307b1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_map.c @@ -0,0 +1,133 @@ +/* pcy_map.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include +#include + +#include "pcy_int.h" + + +/* Set policy mapping entries in cache. + * Note: this modifies the passed POLICY_MAPPINGS structure + */ + +int policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps) + { + POLICY_MAPPING *map; + X509_POLICY_DATA *data; + X509_POLICY_CACHE *cache = x->policy_cache; + size_t i; + int ret = 0; + if (sk_POLICY_MAPPING_num(maps) == 0) + { + ret = -1; + goto bad_mapping; + } + for (i = 0; i < sk_POLICY_MAPPING_num(maps); i++) + { + map = sk_POLICY_MAPPING_value(maps, i); + /* Reject if map to or from anyPolicy */ + if ((OBJ_obj2nid(map->subjectDomainPolicy) == NID_any_policy) + || (OBJ_obj2nid(map->issuerDomainPolicy) == NID_any_policy)) + { + ret = -1; + goto bad_mapping; + } + + /* Attempt to find matching policy data */ + data = policy_cache_find_data(cache, map->issuerDomainPolicy); + /* If we don't have anyPolicy can't map */ + if (!data && !cache->anyPolicy) + continue; + + /* Create a NODE from anyPolicy */ + if (!data) + { + data = policy_data_new(NULL, map->issuerDomainPolicy, + cache->anyPolicy->flags + & POLICY_DATA_FLAG_CRITICAL); + if (!data) + goto bad_mapping; + data->qualifier_set = cache->anyPolicy->qualifier_set; + /*map->issuerDomainPolicy = NULL;*/ + data->flags |= POLICY_DATA_FLAG_MAPPED_ANY; + data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; + if (!sk_X509_POLICY_DATA_push(cache->data, data)) + { + policy_data_free(data); + goto bad_mapping; + } + } + else + data->flags |= POLICY_DATA_FLAG_MAPPED; + if (!sk_ASN1_OBJECT_push(data->expected_policy_set, + map->subjectDomainPolicy)) + goto bad_mapping; + map->subjectDomainPolicy = NULL; + + } + + ret = 1; + bad_mapping: + if (ret == -1) + x->ex_flags |= EXFLAG_INVALID_POLICY; + sk_POLICY_MAPPING_pop_free(maps, POLICY_MAPPING_free); + return ret; + + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_node.c b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_node.c new file mode 100644 index 00000000..55cc2039 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_node.c @@ -0,0 +1,197 @@ +/* pcy_node.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include +#include +#include +#include + +#include "pcy_int.h" + + +static int node_cmp(const X509_POLICY_NODE **a, + const X509_POLICY_NODE **b) + { + return OBJ_cmp((*a)->data->valid_policy, (*b)->data->valid_policy); + } + +STACK_OF(X509_POLICY_NODE) *policy_node_cmp_new(void) + { + return sk_X509_POLICY_NODE_new(node_cmp); + } + +X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_NODE) *nodes, + const ASN1_OBJECT *id) + { + X509_POLICY_DATA n; + X509_POLICY_NODE l; + size_t idx; + + n.valid_policy = (ASN1_OBJECT *)id; + l.data = &n; + + if (!sk_X509_POLICY_NODE_find(nodes, &idx, &l)) + return NULL; + + return sk_X509_POLICY_NODE_value(nodes, idx); + + } + +X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level, + const X509_POLICY_NODE *parent, + const ASN1_OBJECT *id) + { + X509_POLICY_NODE *node; + size_t i; + for (i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++) + { + node = sk_X509_POLICY_NODE_value(level->nodes, i); + if (node->parent == parent) + { + if (!OBJ_cmp(node->data->valid_policy, id)) + return node; + } + } + return NULL; + } + +X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level, + const X509_POLICY_DATA *data, + X509_POLICY_NODE *parent, + X509_POLICY_TREE *tree) + { + X509_POLICY_NODE *node; + node = OPENSSL_malloc(sizeof(X509_POLICY_NODE)); + if (!node) + return NULL; + node->data = data; + node->parent = parent; + node->nchild = 0; + if (level) + { + if (OBJ_obj2nid(data->valid_policy) == NID_any_policy) + { + if (level->anyPolicy) + goto node_error; + level->anyPolicy = node; + } + else + { + + if (!level->nodes) + level->nodes = policy_node_cmp_new(); + if (!level->nodes) + goto node_error; + if (!sk_X509_POLICY_NODE_push(level->nodes, node)) + goto node_error; + } + } + + if (tree) + { + if (!tree->extra_data) + tree->extra_data = sk_X509_POLICY_DATA_new_null(); + if (!tree->extra_data) + goto node_error; + if (!sk_X509_POLICY_DATA_push(tree->extra_data, data)) + goto node_error; + } + + if (parent) + parent->nchild++; + + return node; + + node_error: + policy_node_free(node); + return 0; + + } + +void policy_node_free(X509_POLICY_NODE *node) + { + OPENSSL_free(node); + } + +/* See if a policy node matches a policy OID. If mapping enabled look through + * expected policy set otherwise just valid policy. + */ + +int policy_node_match(const X509_POLICY_LEVEL *lvl, + const X509_POLICY_NODE *node, const ASN1_OBJECT *oid) + { + size_t i; + ASN1_OBJECT *policy_oid; + const X509_POLICY_DATA *x = node->data; + + if ( (lvl->flags & X509_V_FLAG_INHIBIT_MAP) + || !(x->flags & POLICY_DATA_FLAG_MAP_MASK)) + { + if (!OBJ_cmp(x->valid_policy, oid)) + return 1; + return 0; + } + + for (i = 0; i < sk_ASN1_OBJECT_num(x->expected_policy_set); i++) + { + policy_oid = sk_ASN1_OBJECT_value(x->expected_policy_set, i); + if (!OBJ_cmp(policy_oid, oid)) + return 1; + } + return 0; + + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_tree.c b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_tree.c new file mode 100644 index 00000000..682474d8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/pcy_tree.c @@ -0,0 +1,876 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2004. + */ +/* ==================================================================== + * Copyright (c) 2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "pcy_int.h" + + +/* Enable this to print out the complete policy tree at various point during + * evaluation. + */ + +/*#define OPENSSL_POLICY_DEBUG*/ + +#ifdef OPENSSL_POLICY_DEBUG + +static void expected_print(BIO *err, X509_POLICY_LEVEL *lev, + X509_POLICY_NODE *node, int indent) + { + if ( (lev->flags & X509_V_FLAG_INHIBIT_MAP) + || !(node->data->flags & POLICY_DATA_FLAG_MAP_MASK)) + BIO_puts(err, " Not Mapped\n"); + else + { + int i; + STACK_OF(ASN1_OBJECT) *pset = node->data->expected_policy_set; + ASN1_OBJECT *oid; + BIO_puts(err, " Expected: "); + for (i = 0; i < sk_ASN1_OBJECT_num(pset); i++) + { + oid = sk_ASN1_OBJECT_value(pset, i); + if (i) + BIO_puts(err, ", "); + i2a_ASN1_OBJECT(err, oid); + } + BIO_puts(err, "\n"); + } + } + +static void tree_print(char *str, X509_POLICY_TREE *tree, + X509_POLICY_LEVEL *curr) + { + X509_POLICY_LEVEL *plev; + X509_POLICY_NODE *node; + int i; + BIO *err; + err = BIO_new_fp(stderr, BIO_NOCLOSE); + if (!curr) + curr = tree->levels + tree->nlevel; + else + curr++; + BIO_printf(err, "Level print after %s\n", str); + BIO_printf(err, "Printing Up to Level %ld\n", curr - tree->levels); + for (plev = tree->levels; plev != curr; plev++) + { + BIO_printf(err, "Level %ld, flags = %x\n", + plev - tree->levels, plev->flags); + for (i = 0; i < sk_X509_POLICY_NODE_num(plev->nodes); i++) + { + node = sk_X509_POLICY_NODE_value(plev->nodes, i); + X509_POLICY_NODE_print(err, node, 2); + expected_print(err, plev, node, 2); + BIO_printf(err, " Flags: %x\n", node->data->flags); + } + if (plev->anyPolicy) + X509_POLICY_NODE_print(err, plev->anyPolicy, 2); + } + + BIO_free(err); + + } +#else + +#define tree_print(a,b,c) /* */ + +#endif + +/* Initialize policy tree. Return values: + * 0 Some internal error occured. + * -1 Inconsistent or invalid extensions in certificates. + * 1 Tree initialized OK. + * 2 Policy tree is empty. + * 5 Tree OK and requireExplicitPolicy true. + * 6 Tree empty and requireExplicitPolicy true. + */ + +static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs, + unsigned int flags) + { + X509_POLICY_TREE *tree; + X509_POLICY_LEVEL *level; + const X509_POLICY_CACHE *cache; + X509_POLICY_DATA *data = NULL; + X509 *x; + int ret = 1; + int i, n; + int explicit_policy; + int any_skip; + int map_skip; + *ptree = NULL; + n = sk_X509_num(certs); + +#if 0 + /* Disable policy mapping for now... */ + flags |= X509_V_FLAG_INHIBIT_MAP; +#endif + + if (flags & X509_V_FLAG_EXPLICIT_POLICY) + explicit_policy = 0; + else + explicit_policy = n + 1; + + if (flags & X509_V_FLAG_INHIBIT_ANY) + any_skip = 0; + else + any_skip = n + 1; + + if (flags & X509_V_FLAG_INHIBIT_MAP) + map_skip = 0; + else + map_skip = n + 1; + + /* Can't do anything with just a trust anchor */ + if (n == 1) + return 1; + /* First setup policy cache in all certificates apart from the + * trust anchor. Note any bad cache results on the way. Also can + * calculate explicit_policy value at this point. + */ + for (i = n - 2; i >= 0; i--) + { + x = sk_X509_value(certs, i); + X509_check_purpose(x, -1, -1); + cache = policy_cache_set(x); + /* If cache NULL something bad happened: return immediately */ + if (cache == NULL) + return 0; + /* If inconsistent extensions keep a note of it but continue */ + if (x->ex_flags & EXFLAG_INVALID_POLICY) + ret = -1; + /* Otherwise if we have no data (hence no CertificatePolicies) + * and haven't already set an inconsistent code note it. + */ + else if ((ret == 1) && !cache->data) + ret = 2; + if (explicit_policy > 0) + { + if (!(x->ex_flags & EXFLAG_SI)) + explicit_policy--; + if ((cache->explicit_skip != -1) + && (cache->explicit_skip < explicit_policy)) + explicit_policy = cache->explicit_skip; + } + } + + if (ret != 1) + { + if (ret == 2 && !explicit_policy) + return 6; + return ret; + } + + + /* If we get this far initialize the tree */ + + tree = OPENSSL_malloc(sizeof(X509_POLICY_TREE)); + + if (!tree) + return 0; + + tree->flags = 0; + tree->levels = OPENSSL_malloc(sizeof(X509_POLICY_LEVEL) * n); + tree->nlevel = 0; + tree->extra_data = NULL; + tree->auth_policies = NULL; + tree->user_policies = NULL; + + if (!tree->levels) + { + OPENSSL_free(tree); + return 0; + } + + memset(tree->levels, 0, n * sizeof(X509_POLICY_LEVEL)); + + tree->nlevel = n; + + level = tree->levels; + + /* Root data: initialize to anyPolicy */ + + data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0); + + if (!data || !level_add_node(level, data, NULL, tree)) + goto bad_tree; + + for (i = n - 2; i >= 0; i--) + { + level++; + x = sk_X509_value(certs, i); + cache = policy_cache_set(x); + level->cert = X509_up_ref(x); + + if (!cache->anyPolicy) + level->flags |= X509_V_FLAG_INHIBIT_ANY; + + /* Determine inhibit any and inhibit map flags */ + if (any_skip == 0) + { + /* Any matching allowed if certificate is self + * issued and not the last in the chain. + */ + if (!(x->ex_flags & EXFLAG_SI) || (i == 0)) + level->flags |= X509_V_FLAG_INHIBIT_ANY; + } + else + { + if (!(x->ex_flags & EXFLAG_SI)) + any_skip--; + if ((cache->any_skip >= 0) + && (cache->any_skip < any_skip)) + any_skip = cache->any_skip; + } + + if (map_skip == 0) + level->flags |= X509_V_FLAG_INHIBIT_MAP; + else + { + if (!(x->ex_flags & EXFLAG_SI)) + map_skip--; + if ((cache->map_skip >= 0) + && (cache->map_skip < map_skip)) + map_skip = cache->map_skip; + } + + } + + *ptree = tree; + + if (explicit_policy) + return 1; + else + return 5; + + bad_tree: + + X509_policy_tree_free(tree); + + return 0; + + } + +static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr, + const X509_POLICY_DATA *data) + { + X509_POLICY_LEVEL *last = curr - 1; + X509_POLICY_NODE *node; + int matched = 0; + size_t i; + /* Iterate through all in nodes linking matches */ + for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) + { + node = sk_X509_POLICY_NODE_value(last->nodes, i); + if (policy_node_match(last, node, data->valid_policy)) + { + if (!level_add_node(curr, data, node, NULL)) + return 0; + matched = 1; + } + } + if (!matched && last->anyPolicy) + { + if (!level_add_node(curr, data, last->anyPolicy, NULL)) + return 0; + } + return 1; + } + +/* This corresponds to RFC3280 6.1.3(d)(1): + * link any data from CertificatePolicies onto matching parent + * or anyPolicy if no match. + */ + +static int tree_link_nodes(X509_POLICY_LEVEL *curr, + const X509_POLICY_CACHE *cache) + { + size_t i; + X509_POLICY_DATA *data; + + for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++) + { + data = sk_X509_POLICY_DATA_value(cache->data, i); + /* If a node is mapped any it doesn't have a corresponding + * CertificatePolicies entry. + * However such an identical node would be created + * if anyPolicy matching is enabled because there would be + * no match with the parent valid_policy_set. So we create + * link because then it will have the mapping flags + * right and we can prune it later. + */ +#if 0 + if ((data->flags & POLICY_DATA_FLAG_MAPPED_ANY) + && !(curr->flags & X509_V_FLAG_INHIBIT_ANY)) + continue; +#endif + /* Look for matching nodes in previous level */ + if (!tree_link_matching_nodes(curr, data)) + return 0; + } + return 1; + } + +/* This corresponds to RFC3280 6.1.3(d)(2): + * Create new data for any unmatched policies in the parent and link + * to anyPolicy. + */ + +static int tree_add_unmatched(X509_POLICY_LEVEL *curr, + const X509_POLICY_CACHE *cache, + const ASN1_OBJECT *id, + X509_POLICY_NODE *node, + X509_POLICY_TREE *tree) + { + X509_POLICY_DATA *data; + if (id == NULL) + id = node->data->valid_policy; + /* Create a new node with qualifiers from anyPolicy and + * id from unmatched node. + */ + data = policy_data_new(NULL, id, node_critical(node)); + + if (data == NULL) + return 0; + /* Curr may not have anyPolicy */ + data->qualifier_set = cache->anyPolicy->qualifier_set; + data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; + if (!level_add_node(curr, data, node, tree)) + { + policy_data_free(data); + return 0; + } + + return 1; + } + +static int tree_link_unmatched(X509_POLICY_LEVEL *curr, + const X509_POLICY_CACHE *cache, + X509_POLICY_NODE *node, + X509_POLICY_TREE *tree) + { + const X509_POLICY_LEVEL *last = curr - 1; + size_t i; + + if ( (last->flags & X509_V_FLAG_INHIBIT_MAP) + || !(node->data->flags & POLICY_DATA_FLAG_MAPPED)) + { + /* If no policy mapping: matched if one child present */ + if (node->nchild) + return 1; + if (!tree_add_unmatched(curr, cache, NULL, node, tree)) + return 0; + /* Add it */ + } + else + { + /* If mapping: matched if one child per expected policy set */ + STACK_OF(ASN1_OBJECT) *expset = node->data->expected_policy_set; + if (node->nchild == sk_ASN1_OBJECT_num(expset)) + return 1; + /* Locate unmatched nodes */ + for (i = 0; i < sk_ASN1_OBJECT_num(expset); i++) + { + ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(expset, i); + if (level_find_node(curr, node, oid)) + continue; + if (!tree_add_unmatched(curr, cache, oid, node, tree)) + return 0; + } + + } + + return 1; + + } + +static int tree_link_any(X509_POLICY_LEVEL *curr, + const X509_POLICY_CACHE *cache, + X509_POLICY_TREE *tree) + { + size_t i; + /*X509_POLICY_DATA *data;*/ + X509_POLICY_NODE *node; + X509_POLICY_LEVEL *last = curr - 1; + + for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++) + { + node = sk_X509_POLICY_NODE_value(last->nodes, i); + + if (!tree_link_unmatched(curr, cache, node, tree)) + return 0; + +#if 0 + + /* Skip any node with any children: we only want unmathced + * nodes. + * + * Note: need something better for policy mapping + * because each node may have multiple children + */ + if (node->nchild) + continue; + + /* Create a new node with qualifiers from anyPolicy and + * id from unmatched node. + */ + data = policy_data_new(NULL, node->data->valid_policy, + node_critical(node)); + + if (data == NULL) + return 0; + /* Curr may not have anyPolicy */ + data->qualifier_set = cache->anyPolicy->qualifier_set; + data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS; + if (!level_add_node(curr, data, node, tree)) + { + policy_data_free(data); + return 0; + } + +#endif + + } + /* Finally add link to anyPolicy */ + if (last->anyPolicy) + { + if (!level_add_node(curr, cache->anyPolicy, + last->anyPolicy, NULL)) + return 0; + } + return 1; + } + +/* Prune the tree: delete any child mapped child data on the current level + * then proceed up the tree deleting any data with no children. If we ever + * have no data on a level we can halt because the tree will be empty. + */ + +static int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr) + { + STACK_OF(X509_POLICY_NODE) *nodes; + X509_POLICY_NODE *node; + int i; + nodes = curr->nodes; + if (curr->flags & X509_V_FLAG_INHIBIT_MAP) + { + for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) + { + node = sk_X509_POLICY_NODE_value(nodes, i); + /* Delete any mapped data: see RFC3280 XXXX */ + if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK) + { + node->parent->nchild--; + OPENSSL_free(node); + (void)sk_X509_POLICY_NODE_delete(nodes,i); + } + } + } + + for(;;) { + --curr; + nodes = curr->nodes; + for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--) + { + node = sk_X509_POLICY_NODE_value(nodes, i); + if (node->nchild == 0) + { + node->parent->nchild--; + OPENSSL_free(node); + (void)sk_X509_POLICY_NODE_delete(nodes, i); + } + } + if (curr->anyPolicy && !curr->anyPolicy->nchild) + { + if (curr->anyPolicy->parent) + curr->anyPolicy->parent->nchild--; + OPENSSL_free(curr->anyPolicy); + curr->anyPolicy = NULL; + } + if (curr == tree->levels) + { + /* If we zapped anyPolicy at top then tree is empty */ + if (!curr->anyPolicy) + return 2; + return 1; + } + } + + } + +static int tree_add_auth_node(STACK_OF(X509_POLICY_NODE) **pnodes, + X509_POLICY_NODE *pcy) + { + if (!*pnodes) + { + *pnodes = policy_node_cmp_new(); + if (!*pnodes) + return 0; + } + else if (sk_X509_POLICY_NODE_find(*pnodes, NULL, pcy)) + return 1; + + if (!sk_X509_POLICY_NODE_push(*pnodes, pcy)) + return 0; + + return 1; + + } + +/* Calculate the authority set based on policy tree. + * The 'pnodes' parameter is used as a store for the set of policy nodes + * used to calculate the user set. If the authority set is not anyPolicy + * then pnodes will just point to the authority set. If however the authority + * set is anyPolicy then the set of valid policies (other than anyPolicy) + * is store in pnodes. The return value of '2' is used in this case to indicate + * that pnodes should be freed. + */ + +static int tree_calculate_authority_set(X509_POLICY_TREE *tree, + STACK_OF(X509_POLICY_NODE) **pnodes) + { + X509_POLICY_LEVEL *curr; + X509_POLICY_NODE *node, *anyptr; + STACK_OF(X509_POLICY_NODE) **addnodes; + int i; + size_t j; + curr = tree->levels + tree->nlevel - 1; + + /* If last level contains anyPolicy set is anyPolicy */ + if (curr->anyPolicy) + { + if (!tree_add_auth_node(&tree->auth_policies, curr->anyPolicy)) + return 0; + addnodes = pnodes; + } + else + /* Add policies to authority set */ + addnodes = &tree->auth_policies; + + curr = tree->levels; + for (i = 1; i < tree->nlevel; i++) + { + /* If no anyPolicy node on this this level it can't + * appear on lower levels so end search. + */ + if (!(anyptr = curr->anyPolicy)) + break; + curr++; + for (j = 0; j < sk_X509_POLICY_NODE_num(curr->nodes); j++) + { + node = sk_X509_POLICY_NODE_value(curr->nodes, j); + if ((node->parent == anyptr) + && !tree_add_auth_node(addnodes, node)) + return 0; + } + } + + if (addnodes == pnodes) + return 2; + + *pnodes = tree->auth_policies; + + return 1; + } + +static int tree_calculate_user_set(X509_POLICY_TREE *tree, + STACK_OF(ASN1_OBJECT) *policy_oids, + STACK_OF(X509_POLICY_NODE) *auth_nodes) + { + size_t i; + X509_POLICY_NODE *node; + ASN1_OBJECT *oid; + + X509_POLICY_NODE *anyPolicy; + X509_POLICY_DATA *extra; + + /* Check if anyPolicy present in authority constrained policy set: + * this will happen if it is a leaf node. + */ + + if (sk_ASN1_OBJECT_num(policy_oids) <= 0) + return 1; + + anyPolicy = tree->levels[tree->nlevel - 1].anyPolicy; + + for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) + { + oid = sk_ASN1_OBJECT_value(policy_oids, i); + if (OBJ_obj2nid(oid) == NID_any_policy) + { + tree->flags |= POLICY_FLAG_ANY_POLICY; + return 1; + } + } + + for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++) + { + oid = sk_ASN1_OBJECT_value(policy_oids, i); + node = tree_find_sk(auth_nodes, oid); + if (!node) + { + if (!anyPolicy) + continue; + /* Create a new node with policy ID from user set + * and qualifiers from anyPolicy. + */ + extra = policy_data_new(NULL, oid, + node_critical(anyPolicy)); + if (!extra) + return 0; + extra->qualifier_set = anyPolicy->data->qualifier_set; + extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS + | POLICY_DATA_FLAG_EXTRA_NODE; + node = level_add_node(NULL, extra, anyPolicy->parent, + tree); + } + if (!tree->user_policies) + { + tree->user_policies = sk_X509_POLICY_NODE_new_null(); + if (!tree->user_policies) + return 1; + } + if (!sk_X509_POLICY_NODE_push(tree->user_policies, node)) + return 0; + } + return 1; + + } + +static int tree_evaluate(X509_POLICY_TREE *tree) + { + int ret, i; + X509_POLICY_LEVEL *curr = tree->levels + 1; + const X509_POLICY_CACHE *cache; + + for(i = 1; i < tree->nlevel; i++, curr++) + { + cache = policy_cache_set(curr->cert); + if (!tree_link_nodes(curr, cache)) + return 0; + + if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY) + && !tree_link_any(curr, cache, tree)) + return 0; + tree_print("before tree_prune()", tree, curr); + ret = tree_prune(tree, curr); + if (ret != 1) + return ret; + } + + return 1; + + } + +static void exnode_free(X509_POLICY_NODE *node) + { + if (node->data && (node->data->flags & POLICY_DATA_FLAG_EXTRA_NODE)) + OPENSSL_free(node); + } + + +void X509_policy_tree_free(X509_POLICY_TREE *tree) + { + X509_POLICY_LEVEL *curr; + int i; + + if (!tree) + return; + + sk_X509_POLICY_NODE_free(tree->auth_policies); + sk_X509_POLICY_NODE_pop_free(tree->user_policies, exnode_free); + + for(i = 0, curr = tree->levels; i < tree->nlevel; i++, curr++) + { + if (curr->cert) + X509_free(curr->cert); + if (curr->nodes) + sk_X509_POLICY_NODE_pop_free(curr->nodes, + policy_node_free); + if (curr->anyPolicy) + policy_node_free(curr->anyPolicy); + } + + if (tree->extra_data) + sk_X509_POLICY_DATA_pop_free(tree->extra_data, + policy_data_free); + + OPENSSL_free(tree->levels); + OPENSSL_free(tree); + + } + +/* Application policy checking function. + * Return codes: + * 0 Internal Error. + * 1 Successful. + * -1 One or more certificates contain invalid or inconsistent extensions + * -2 User constrained policy set empty and requireExplicit true. + */ + +int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy, + STACK_OF(X509) *certs, + STACK_OF(ASN1_OBJECT) *policy_oids, + unsigned int flags) + { + int ret; + X509_POLICY_TREE *tree = NULL; + STACK_OF(X509_POLICY_NODE) *nodes, *auth_nodes = NULL; + *ptree = NULL; + + *pexplicit_policy = 0; + ret = tree_init(&tree, certs, flags); + + switch (ret) + { + + /* Tree empty requireExplicit False: OK */ + case 2: + return 1; + + /* Some internal error */ + case -1: + return -1; + + /* Some internal error */ + case 0: + return 0; + + /* Tree empty requireExplicit True: Error */ + + case 6: + *pexplicit_policy = 1; + return -2; + + /* Tree OK requireExplicit True: OK and continue */ + case 5: + *pexplicit_policy = 1; + break; + + /* Tree OK: continue */ + + case 1: + if (!tree) + /* + * tree_init() returns success and a null tree + * if it's just looking at a trust anchor. + * I'm not sure that returning success here is + * correct, but I'm sure that reporting this + * as an internal error which our caller + * interprets as a malloc failure is wrong. + */ + return 1; + break; + } + + if (!tree) goto error; + ret = tree_evaluate(tree); + + tree_print("tree_evaluate()", tree, NULL); + + if (ret <= 0) + goto error; + + /* Return value 2 means tree empty */ + if (ret == 2) + { + X509_policy_tree_free(tree); + if (*pexplicit_policy) + return -2; + else + return 1; + } + + /* Tree is not empty: continue */ + + ret = tree_calculate_authority_set(tree, &auth_nodes); + + if (!ret) + goto error; + + if (!tree_calculate_user_set(tree, policy_oids, auth_nodes)) + goto error; + + if (ret == 2) + sk_X509_POLICY_NODE_free(auth_nodes); + + if (tree) + *ptree = tree; + + if (*pexplicit_policy) + { + nodes = X509_policy_tree_get0_user_policies(tree); + if (sk_X509_POLICY_NODE_num(nodes) <= 0) + return -2; + } + + return 1; + + error: + + X509_policy_tree_free(tree); + + return 0; + + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_akey.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_akey.c new file mode 100644 index 00000000..9578a570 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_akey.c @@ -0,0 +1,212 @@ +/* v3_akey.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, + AUTHORITY_KEYID *akeyid, STACK_OF(CONF_VALUE) *extlist); +static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values); + +const X509V3_EXT_METHOD v3_akey_id = + { + NID_authority_key_identifier, + X509V3_EXT_MULTILINE, ASN1_ITEM_ref(AUTHORITY_KEYID), + 0,0,0,0, + 0,0, + (X509V3_EXT_I2V)i2v_AUTHORITY_KEYID, + (X509V3_EXT_V2I)v2i_AUTHORITY_KEYID, + 0,0, + NULL + }; + +static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, + AUTHORITY_KEYID *akeyid, STACK_OF(CONF_VALUE) *extlist) +{ + char *tmp; + if(akeyid->keyid) { + tmp = hex_to_string(akeyid->keyid->data, akeyid->keyid->length); + X509V3_add_value("keyid", tmp, &extlist); + OPENSSL_free(tmp); + } + if(akeyid->issuer) + extlist = i2v_GENERAL_NAMES(NULL, akeyid->issuer, extlist); + if(akeyid->serial) { + tmp = hex_to_string(akeyid->serial->data, + akeyid->serial->length); + X509V3_add_value("serial", tmp, &extlist); + OPENSSL_free(tmp); + } + return extlist; +} + +/* Currently two options: + * keyid: use the issuers subject keyid, the value 'always' means its is + * an error if the issuer certificate doesn't have a key id. + * issuer: use the issuers cert issuer and serial number. The default is + * to only use this if keyid is not present. With the option 'always' + * this is always included. + */ + +static AUTHORITY_KEYID *v2i_AUTHORITY_KEYID(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values) + { + char keyid=0, issuer=0; + size_t i; + int j; + CONF_VALUE *cnf; + ASN1_OCTET_STRING *ikeyid = NULL; + X509_NAME *isname = NULL; + GENERAL_NAMES * gens = NULL; + GENERAL_NAME *gen = NULL; + ASN1_INTEGER *serial = NULL; + X509_EXTENSION *ext; + X509 *cert; + AUTHORITY_KEYID *akeyid; + + for(i = 0; i < sk_CONF_VALUE_num(values); i++) + { + cnf = sk_CONF_VALUE_value(values, i); + if(!strcmp(cnf->name, "keyid")) + { + keyid = 1; + if(cnf->value && !strcmp(cnf->value, "always")) + keyid = 2; + } + else if(!strcmp(cnf->name, "issuer")) + { + issuer = 1; + if(cnf->value && !strcmp(cnf->value, "always")) + issuer = 2; + } + else + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_OPTION); + ERR_add_error_data(2, "name=", cnf->name); + return NULL; + } + } + + if(!ctx || !ctx->issuer_cert) + { + if(ctx && (ctx->flags==CTX_TEST)) + return AUTHORITY_KEYID_new(); + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_ISSUER_CERTIFICATE); + return NULL; + } + + cert = ctx->issuer_cert; + + if(keyid) + { + j = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1); + if((j >= 0) && (ext = X509_get_ext(cert, j))) + ikeyid = X509V3_EXT_d2i(ext); + if(keyid==2 && !ikeyid) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID); + return NULL; + } + } + + if((issuer && !ikeyid) || (issuer == 2)) + { + isname = X509_NAME_dup(X509_get_issuer_name(cert)); + serial = M_ASN1_INTEGER_dup(X509_get_serialNumber(cert)); + if(!isname || !serial) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS); + goto err; + } + } + + if(!(akeyid = AUTHORITY_KEYID_new())) goto err; + + if(isname) + { + if(!(gens = sk_GENERAL_NAME_new_null()) + || !(gen = GENERAL_NAME_new()) + || !sk_GENERAL_NAME_push(gens, gen)) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + gen->type = GEN_DIRNAME; + gen->d.dirn = isname; + } + + akeyid->issuer = gens; + akeyid->serial = serial; + akeyid->keyid = ikeyid; + + return akeyid; + + err: + X509_NAME_free(isname); + M_ASN1_INTEGER_free(serial); + M_ASN1_OCTET_STRING_free(ikeyid); + return NULL; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_akeya.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_akeya.c new file mode 100644 index 00000000..8b72cca2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_akeya.c @@ -0,0 +1,71 @@ +/* v3_akey_asn1.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include + + +ASN1_SEQUENCE(AUTHORITY_KEYID) = { + ASN1_IMP_OPT(AUTHORITY_KEYID, keyid, ASN1_OCTET_STRING, 0), + ASN1_IMP_SEQUENCE_OF_OPT(AUTHORITY_KEYID, issuer, GENERAL_NAME, 1), + ASN1_IMP_OPT(AUTHORITY_KEYID, serial, ASN1_INTEGER, 2) +} ASN1_SEQUENCE_END(AUTHORITY_KEYID) + +IMPLEMENT_ASN1_FUNCTIONS(AUTHORITY_KEYID) diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_alt.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_alt.c new file mode 100644 index 00000000..e639f458 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_alt.c @@ -0,0 +1,620 @@ +/* v3_alt.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 1999-2003 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include + +#include +#include +#include +#include +#include + + +static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); +static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); +static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p); +static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens); +static int do_othername(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx); +static int do_dirname(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx); + +const X509V3_EXT_METHOD v3_alt[] = { +{ NID_subject_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES), +0,0,0,0, +0,0, +(X509V3_EXT_I2V)i2v_GENERAL_NAMES, +(X509V3_EXT_V2I)v2i_subject_alt, +NULL, NULL, NULL}, + +{ NID_issuer_alt_name, 0, ASN1_ITEM_ref(GENERAL_NAMES), +0,0,0,0, +0,0, +(X509V3_EXT_I2V)i2v_GENERAL_NAMES, +(X509V3_EXT_V2I)v2i_issuer_alt, +NULL, NULL, NULL}, + +{ NID_certificate_issuer, 0, ASN1_ITEM_ref(GENERAL_NAMES), +0,0,0,0, +0,0, +(X509V3_EXT_I2V)i2v_GENERAL_NAMES, +NULL, NULL, NULL, NULL}, +}; + +STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method, + GENERAL_NAMES *gens, STACK_OF(CONF_VALUE) *ret) +{ + size_t i; + GENERAL_NAME *gen; + for(i = 0; i < sk_GENERAL_NAME_num(gens); i++) { + gen = sk_GENERAL_NAME_value(gens, i); + ret = i2v_GENERAL_NAME(method, gen, ret); + } + if(!ret) return sk_CONF_VALUE_new_null(); + return ret; +} + +STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, + GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret) +{ + unsigned char *p; + char oline[256], htmp[5]; + int i; + switch (gen->type) + { + case GEN_OTHERNAME: + X509V3_add_value("othername","", &ret); + break; + + case GEN_X400: + X509V3_add_value("X400Name","", &ret); + break; + + case GEN_EDIPARTY: + X509V3_add_value("EdiPartyName","", &ret); + break; + + case GEN_EMAIL: + X509V3_add_value_uchar("email",gen->d.ia5->data, &ret); + break; + + case GEN_DNS: + X509V3_add_value_uchar("DNS",gen->d.ia5->data, &ret); + break; + + case GEN_URI: + X509V3_add_value_uchar("URI",gen->d.ia5->data, &ret); + break; + + case GEN_DIRNAME: + X509_NAME_oneline(gen->d.dirn, oline, 256); + X509V3_add_value("DirName",oline, &ret); + break; + + case GEN_IPADD: + p = gen->d.ip->data; + if(gen->d.ip->length == 4) + BIO_snprintf(oline, sizeof oline, + "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); + else if(gen->d.ip->length == 16) + { + oline[0] = 0; + for (i = 0; i < 8; i++) + { + BIO_snprintf(htmp, sizeof htmp, + "%X", p[0] << 8 | p[1]); + p += 2; + strcat(oline, htmp); + if (i != 7) + strcat(oline, ":"); + } + } + else + { + X509V3_add_value("IP Address","", &ret); + break; + } + X509V3_add_value("IP Address",oline, &ret); + break; + + case GEN_RID: + i2t_ASN1_OBJECT(oline, 256, gen->d.rid); + X509V3_add_value("Registered ID",oline, &ret); + break; + } + return ret; +} + +int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen) +{ + unsigned char *p; + int i; + switch (gen->type) + { + case GEN_OTHERNAME: + BIO_printf(out, "othername:"); + break; + + case GEN_X400: + BIO_printf(out, "X400Name:"); + break; + + case GEN_EDIPARTY: + /* Maybe fix this: it is supported now */ + BIO_printf(out, "EdiPartyName:"); + break; + + case GEN_EMAIL: + BIO_printf(out, "email:%s",gen->d.ia5->data); + break; + + case GEN_DNS: + BIO_printf(out, "DNS:%s",gen->d.ia5->data); + break; + + case GEN_URI: + BIO_printf(out, "URI:%s",gen->d.ia5->data); + break; + + case GEN_DIRNAME: + BIO_printf(out, "DirName: "); + X509_NAME_print_ex(out, gen->d.dirn, 0, XN_FLAG_ONELINE); + break; + + case GEN_IPADD: + p = gen->d.ip->data; + if(gen->d.ip->length == 4) + BIO_printf(out, "IP Address:%d.%d.%d.%d", + p[0], p[1], p[2], p[3]); + else if(gen->d.ip->length == 16) + { + BIO_printf(out, "IP Address"); + for (i = 0; i < 8; i++) + { + BIO_printf(out, ":%X", p[0] << 8 | p[1]); + p += 2; + } + BIO_puts(out, "\n"); + } + else + { + BIO_printf(out,"IP Address:"); + break; + } + break; + + case GEN_RID: + BIO_printf(out, "Registered ID"); + i2a_ASN1_OBJECT(out, gen->d.rid); + break; + } + return 1; +} + +static GENERAL_NAMES *v2i_issuer_alt(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) +{ + GENERAL_NAMES *gens = NULL; + CONF_VALUE *cnf; + size_t i; + if(!(gens = sk_GENERAL_NAME_new_null())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + cnf = sk_CONF_VALUE_value(nval, i); + if(!name_cmp(cnf->name, "issuer") && cnf->value && + !strcmp(cnf->value, "copy")) { + if(!copy_issuer(ctx, gens)) goto err; + } else { + GENERAL_NAME *gen; + if(!(gen = v2i_GENERAL_NAME(method, ctx, cnf))) + goto err; + sk_GENERAL_NAME_push(gens, gen); + } + } + return gens; + err: + sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); + return NULL; +} + +/* Append subject altname of issuer to issuer alt name of subject */ + +static int copy_issuer(X509V3_CTX *ctx, GENERAL_NAMES *gens) +{ + GENERAL_NAMES *ialt; + GENERAL_NAME *gen; + X509_EXTENSION *ext; + int i; + size_t j; + if(ctx && (ctx->flags == CTX_TEST)) return 1; + if(!ctx || !ctx->issuer_cert) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_ISSUER_DETAILS); + goto err; + } + i = X509_get_ext_by_NID(ctx->issuer_cert, NID_subject_alt_name, -1); + if(i < 0) return 1; + if(!(ext = X509_get_ext(ctx->issuer_cert, i)) || + !(ialt = X509V3_EXT_d2i(ext)) ) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ISSUER_DECODE_ERROR); + goto err; + } + + for(j = 0; j < sk_GENERAL_NAME_num(ialt); j++) { + gen = sk_GENERAL_NAME_value(ialt, j); + if(!sk_GENERAL_NAME_push(gens, gen)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + } + sk_GENERAL_NAME_free(ialt); + + return 1; + + err: + return 0; + +} + +static GENERAL_NAMES *v2i_subject_alt(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) +{ + GENERAL_NAMES *gens = NULL; + CONF_VALUE *cnf; + size_t i; + if(!(gens = sk_GENERAL_NAME_new_null())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + cnf = sk_CONF_VALUE_value(nval, i); + if(!name_cmp(cnf->name, "email") && cnf->value && + !strcmp(cnf->value, "copy")) { + if(!copy_email(ctx, gens, 0)) goto err; + } else if(!name_cmp(cnf->name, "email") && cnf->value && + !strcmp(cnf->value, "move")) { + if(!copy_email(ctx, gens, 1)) goto err; + } else { + GENERAL_NAME *gen; + if(!(gen = v2i_GENERAL_NAME(method, ctx, cnf))) + goto err; + sk_GENERAL_NAME_push(gens, gen); + } + } + return gens; + err: + sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); + return NULL; +} + +/* Copy any email addresses in a certificate or request to + * GENERAL_NAMES + */ + +static int copy_email(X509V3_CTX *ctx, GENERAL_NAMES *gens, int move_p) +{ + X509_NAME *nm; + ASN1_IA5STRING *email = NULL; + X509_NAME_ENTRY *ne; + GENERAL_NAME *gen = NULL; + int i; + if(ctx != NULL && ctx->flags == CTX_TEST) + return 1; + if(!ctx || (!ctx->subject_cert && !ctx->subject_req)) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_SUBJECT_DETAILS); + goto err; + } + /* Find the subject name */ + if(ctx->subject_cert) nm = X509_get_subject_name(ctx->subject_cert); + else nm = X509_REQ_get_subject_name(ctx->subject_req); + + /* Now add any email address(es) to STACK */ + i = -1; + while((i = X509_NAME_get_index_by_NID(nm, + NID_pkcs9_emailAddress, i)) >= 0) { + ne = X509_NAME_get_entry(nm, i); + email = M_ASN1_IA5STRING_dup(X509_NAME_ENTRY_get_data(ne)); + if (move_p) + { + X509_NAME_delete_entry(nm, i); + X509_NAME_ENTRY_free(ne); + i--; + } + if(!email || !(gen = GENERAL_NAME_new())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + gen->d.ia5 = email; + email = NULL; + gen->type = GEN_EMAIL; + if(!sk_GENERAL_NAME_push(gens, gen)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + gen = NULL; + } + + + return 1; + + err: + GENERAL_NAME_free(gen); + M_ASN1_IA5STRING_free(email); + return 0; + +} + +GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) +{ + GENERAL_NAME *gen; + GENERAL_NAMES *gens = NULL; + CONF_VALUE *cnf; + size_t i; + if(!(gens = sk_GENERAL_NAME_new_null())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + cnf = sk_CONF_VALUE_value(nval, i); + if(!(gen = v2i_GENERAL_NAME(method, ctx, cnf))) goto err; + sk_GENERAL_NAME_push(gens, gen); + } + return gens; + err: + sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); + return NULL; +} + +GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + CONF_VALUE *cnf) + { + return v2i_GENERAL_NAME_ex(NULL, method, ctx, cnf, 0); + } + +GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out, + const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + int gen_type, char *value, int is_nc) + { + char is_string = 0; + GENERAL_NAME *gen = NULL; + + if(!value) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_MISSING_VALUE); + return NULL; + } + + if (out) + gen = out; + else + { + gen = GENERAL_NAME_new(); + if(gen == NULL) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + } + + switch (gen_type) + { + case GEN_URI: + case GEN_EMAIL: + case GEN_DNS: + is_string = 1; + break; + + case GEN_RID: + { + ASN1_OBJECT *obj; + if(!(obj = OBJ_txt2obj(value,0))) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_BAD_OBJECT); + ERR_add_error_data(2, "value=", value); + goto err; + } + gen->d.rid = obj; + } + break; + + case GEN_IPADD: + if (is_nc) + gen->d.ip = a2i_IPADDRESS_NC(value); + else + gen->d.ip = a2i_IPADDRESS(value); + if(gen->d.ip == NULL) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_BAD_IP_ADDRESS); + ERR_add_error_data(2, "value=", value); + goto err; + } + break; + + case GEN_DIRNAME: + if (!do_dirname(gen, value, ctx)) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_DIRNAME_ERROR); + goto err; + } + break; + + case GEN_OTHERNAME: + if (!do_othername(gen, value, ctx)) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_OTHERNAME_ERROR); + goto err; + } + break; + default: + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNSUPPORTED_TYPE); + goto err; + } + + if(is_string) + { + if(!(gen->d.ia5 = M_ASN1_IA5STRING_new()) || + !ASN1_STRING_set(gen->d.ia5, (unsigned char*)value, + strlen(value))) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + gen->type = gen_type; + + return gen; + + err: + if (!out) + GENERAL_NAME_free(gen); + return NULL; + } + +GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, + const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc) + { + int type; + + char *name, *value; + + name = cnf->name; + value = cnf->value; + + if(!value) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_MISSING_VALUE); + return NULL; + } + + if(!name_cmp(name, "email")) + type = GEN_EMAIL; + else if(!name_cmp(name, "URI")) + type = GEN_URI; + else if(!name_cmp(name, "DNS")) + type = GEN_DNS; + else if(!name_cmp(name, "RID")) + type = GEN_RID; + else if(!name_cmp(name, "IP")) + type = GEN_IPADD; + else if(!name_cmp(name, "dirName")) + type = GEN_DIRNAME; + else if(!name_cmp(name, "otherName")) + type = GEN_OTHERNAME; + else + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNSUPPORTED_OPTION); + ERR_add_error_data(2, "name=", name); + return NULL; + } + + return a2i_GENERAL_NAME(out, method, ctx, type, value, is_nc); + + } + +static int do_othername(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx) + { + char *objtmp = NULL, *p; + int objlen; + if (!(p = strchr(value, ';'))) + return 0; + if (!(gen->d.otherName = OTHERNAME_new())) + return 0; + /* Free this up because we will overwrite it. + * no need to free type_id because it is static + */ + ASN1_TYPE_free(gen->d.otherName->value); + if (!(gen->d.otherName->value = ASN1_generate_v3(p + 1, ctx))) + return 0; + objlen = p - value; + objtmp = OPENSSL_malloc(objlen + 1); + if (objtmp == NULL) + return 0; + strncpy(objtmp, value, objlen); + objtmp[objlen] = 0; + gen->d.otherName->type_id = OBJ_txt2obj(objtmp, 0); + OPENSSL_free(objtmp); + if (!gen->d.otherName->type_id) + return 0; + return 1; + } + +static int do_dirname(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx) + { + int ret; + STACK_OF(CONF_VALUE) *sk; + X509_NAME *nm; + if (!(nm = X509_NAME_new())) + return 0; + sk = X509V3_get_section(ctx, value); + if (!sk) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_SECTION_NOT_FOUND); + ERR_add_error_data(2, "section=", value); + X509_NAME_free(nm); + return 0; + } + /* FIXME: should allow other character types... */ + ret = X509V3_NAME_from_section(nm, sk, MBSTRING_ASC); + if (!ret) + X509_NAME_free(nm); + gen->d.dirn = nm; + X509V3_section_free(ctx, sk); + + return ret; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_bcons.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_bcons.c new file mode 100644 index 00000000..73ef21ee --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_bcons.c @@ -0,0 +1,126 @@ +/* v3_bcons.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include +#include + +#include +#include +#include +#include +#include +#include + + +static STACK_OF(CONF_VALUE) *i2v_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method, BASIC_CONSTRAINTS *bcons, STACK_OF(CONF_VALUE) *extlist); +static BASIC_CONSTRAINTS *v2i_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values); + +const X509V3_EXT_METHOD v3_bcons = { +NID_basic_constraints, 0, +ASN1_ITEM_ref(BASIC_CONSTRAINTS), +0,0,0,0, +0,0, +(X509V3_EXT_I2V)i2v_BASIC_CONSTRAINTS, +(X509V3_EXT_V2I)v2i_BASIC_CONSTRAINTS, +NULL,NULL, +NULL +}; + +ASN1_SEQUENCE(BASIC_CONSTRAINTS) = { + ASN1_OPT(BASIC_CONSTRAINTS, ca, ASN1_FBOOLEAN), + ASN1_OPT(BASIC_CONSTRAINTS, pathlen, ASN1_INTEGER) +} ASN1_SEQUENCE_END(BASIC_CONSTRAINTS) + +IMPLEMENT_ASN1_FUNCTIONS(BASIC_CONSTRAINTS) + + +static STACK_OF(CONF_VALUE) *i2v_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method, + BASIC_CONSTRAINTS *bcons, STACK_OF(CONF_VALUE) *extlist) +{ + X509V3_add_value_bool("CA", bcons->ca, &extlist); + X509V3_add_value_int("pathlen", bcons->pathlen, &extlist); + return extlist; +} + +static BASIC_CONSTRAINTS *v2i_BASIC_CONSTRAINTS(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values) +{ + BASIC_CONSTRAINTS *bcons=NULL; + CONF_VALUE *val; + size_t i; + if(!(bcons = BASIC_CONSTRAINTS_new())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + for(i = 0; i < sk_CONF_VALUE_num(values); i++) { + val = sk_CONF_VALUE_value(values, i); + if(!strcmp(val->name, "CA")) { + if(!X509V3_get_value_bool(val, &bcons->ca)) goto err; + } else if(!strcmp(val->name, "pathlen")) { + if(!X509V3_get_value_int(val, &bcons->pathlen)) goto err; + } else { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NAME); + X509V3_conf_err(val); + goto err; + } + } + return bcons; + err: + BASIC_CONSTRAINTS_free(bcons); + return NULL; +} + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_bitst.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_bitst.c new file mode 100644 index 00000000..e1e20871 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_bitst.c @@ -0,0 +1,141 @@ +/* v3_bitst.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include + +#include +#include +#include +#include + + +static const BIT_STRING_BITNAME ns_cert_type_table[] = { +{0, "SSL Client", "client"}, +{1, "SSL Server", "server"}, +{2, "S/MIME", "email"}, +{3, "Object Signing", "objsign"}, +{4, "Unused", "reserved"}, +{5, "SSL CA", "sslCA"}, +{6, "S/MIME CA", "emailCA"}, +{7, "Object Signing CA", "objCA"}, +{-1, NULL, NULL} +}; + +static const BIT_STRING_BITNAME key_usage_type_table[] = { +{0, "Digital Signature", "digitalSignature"}, +{1, "Non Repudiation", "nonRepudiation"}, +{2, "Key Encipherment", "keyEncipherment"}, +{3, "Data Encipherment", "dataEncipherment"}, +{4, "Key Agreement", "keyAgreement"}, +{5, "Certificate Sign", "keyCertSign"}, +{6, "CRL Sign", "cRLSign"}, +{7, "Encipher Only", "encipherOnly"}, +{8, "Decipher Only", "decipherOnly"}, +{-1, NULL, NULL} +}; + + + +const X509V3_EXT_METHOD v3_nscert = EXT_BITSTRING(NID_netscape_cert_type, ns_cert_type_table); +const X509V3_EXT_METHOD v3_key_usage = EXT_BITSTRING(NID_key_usage, key_usage_type_table); + +STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, + ASN1_BIT_STRING *bits, STACK_OF(CONF_VALUE) *ret) +{ + const BIT_STRING_BITNAME *bnam; + for(bnam =method->usr_data; bnam->lname; bnam++) { + if(ASN1_BIT_STRING_get_bit(bits, bnam->bitnum)) + X509V3_add_value(bnam->lname, NULL, &ret); + } + return ret; +} + +ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) +{ + CONF_VALUE *val; + ASN1_BIT_STRING *bs; + size_t i; + const BIT_STRING_BITNAME *bnam; + if(!(bs = M_ASN1_BIT_STRING_new())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + val = sk_CONF_VALUE_value(nval, i); + for(bnam = method->usr_data; bnam->lname; bnam++) { + if(!strcmp(bnam->sname, val->name) || + !strcmp(bnam->lname, val->name) ) { + if(!ASN1_BIT_STRING_set_bit(bs, bnam->bitnum, 1)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + M_ASN1_BIT_STRING_free(bs); + return NULL; + } + break; + } + } + if(!bnam->lname) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT); + X509V3_conf_err(val); + M_ASN1_BIT_STRING_free(bs); + return NULL; + } + } + return bs; +} + + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_conf.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_conf.c new file mode 100644 index 00000000..fe715665 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_conf.c @@ -0,0 +1,459 @@ +/* v3_conf.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2002 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +/* extension creation utilities */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "../internal.h" + + +static int v3_check_critical(char **value); +static int v3_check_generic(char **value); +static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid, int crit, char *value); +static X509_EXTENSION *v3_generic_extension(const char *ext, char *value, int crit, int type, X509V3_CTX *ctx); +static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method, int ext_nid, + int crit, void *ext_struc); +static unsigned char *generic_asn1(char *value, X509V3_CTX *ctx, long *ext_len); +/* CONF *conf: Config file */ +/* char *name: Name */ +/* char *value: Value */ +X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, char *name, + char *value) + { + int crit; + int ext_type; + X509_EXTENSION *ret; + crit = v3_check_critical(&value); + if ((ext_type = v3_check_generic(&value))) + return v3_generic_extension(name, value, crit, ext_type, ctx); + ret = do_ext_nconf(conf, ctx, OBJ_sn2nid(name), crit, value); + if (!ret) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ERROR_IN_EXTENSION); + ERR_add_error_data(4,"name=", name, ", value=", value); + } + return ret; + } + +/* CONF *conf: Config file */ +/* char *value: Value */ +X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid, + char *value) + { + int crit; + int ext_type; + crit = v3_check_critical(&value); + if ((ext_type = v3_check_generic(&value))) + return v3_generic_extension(OBJ_nid2sn(ext_nid), + value, crit, ext_type, ctx); + return do_ext_nconf(conf, ctx, ext_nid, crit, value); + } + +/* CONF *conf: Config file */ +/* char *value: Value */ +static X509_EXTENSION *do_ext_nconf(CONF *conf, X509V3_CTX *ctx, int ext_nid, + int crit, char *value) + { + const X509V3_EXT_METHOD *method; + X509_EXTENSION *ext; + STACK_OF(CONF_VALUE) *nval; + void *ext_struc; + if (ext_nid == NID_undef) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_EXTENSION_NAME); + return NULL; + } + if (!(method = X509V3_EXT_get_nid(ext_nid))) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_EXTENSION); + return NULL; + } + /* Now get internal extension representation based on type */ + if (method->v2i) + { + if(*value == '@') nval = NCONF_get_section(conf, value + 1); + else nval = X509V3_parse_list(value); + if(sk_CONF_VALUE_num(nval) <= 0) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_EXTENSION_STRING); + ERR_add_error_data(4, "name=", OBJ_nid2sn(ext_nid), ",section=", value); + return NULL; + } + ext_struc = method->v2i(method, ctx, nval); + if(*value != '@') sk_CONF_VALUE_pop_free(nval, + X509V3_conf_free); + if(!ext_struc) return NULL; + } + else if(method->s2i) + { + if(!(ext_struc = method->s2i(method, ctx, value))) return NULL; + } + else if(method->r2i) + { + if(!ctx->db || !ctx->db_meth) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_CONFIG_DATABASE); + return NULL; + } + if(!(ext_struc = method->r2i(method, ctx, value))) return NULL; + } + else + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED); + ERR_add_error_data(2, "name=", OBJ_nid2sn(ext_nid)); + return NULL; + } + + ext = do_ext_i2d(method, ext_nid, crit, ext_struc); + if(method->it) ASN1_item_free(ext_struc, ASN1_ITEM_ptr(method->it)); + else method->ext_free(ext_struc); + return ext; + + } + +static X509_EXTENSION *do_ext_i2d(const X509V3_EXT_METHOD *method, int ext_nid, + int crit, void *ext_struc) + { + unsigned char *ext_der; + int ext_len; + ASN1_OCTET_STRING *ext_oct; + X509_EXTENSION *ext; + /* Convert internal representation to DER */ + if (method->it) + { + ext_der = NULL; + ext_len = ASN1_item_i2d(ext_struc, &ext_der, ASN1_ITEM_ptr(method->it)); + if (ext_len < 0) goto merr; + } + else + { + unsigned char *p; + ext_len = method->i2d(ext_struc, NULL); + if(!(ext_der = OPENSSL_malloc(ext_len))) goto merr; + p = ext_der; + method->i2d(ext_struc, &p); + } + if (!(ext_oct = M_ASN1_OCTET_STRING_new())) goto merr; + ext_oct->data = ext_der; + ext_oct->length = ext_len; + + ext = X509_EXTENSION_create_by_NID(NULL, ext_nid, crit, ext_oct); + if (!ext) goto merr; + M_ASN1_OCTET_STRING_free(ext_oct); + + return ext; + + merr: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + + } + +/* Given an internal structure, nid and critical flag create an extension */ + +X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc) + { + const X509V3_EXT_METHOD *method; + if (!(method = X509V3_EXT_get_nid(ext_nid))) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_UNKNOWN_EXTENSION); + return NULL; + } + return do_ext_i2d(method, ext_nid, crit, ext_struc); +} + +/* Check the extension string for critical flag */ +static int v3_check_critical(char **value) +{ + char *p = *value; + if ((strlen(p) < 9) || strncmp(p, "critical,", 9)) return 0; + p+=9; + while(isspace((unsigned char)*p)) p++; + *value = p; + return 1; +} + +/* Check extension string for generic extension and return the type */ +static int v3_check_generic(char **value) +{ + int gen_type = 0; + char *p = *value; + if ((strlen(p) >= 4) && !strncmp(p, "DER:", 4)) + { + p+=4; + gen_type = 1; + } + else if ((strlen(p) >= 5) && !strncmp(p, "ASN1:", 5)) + { + p+=5; + gen_type = 2; + } + else + return 0; + + while (isspace((unsigned char)*p)) p++; + *value = p; + return gen_type; +} + +/* Create a generic extension: for now just handle DER type */ +static X509_EXTENSION *v3_generic_extension(const char *ext, char *value, + int crit, int gen_type, + X509V3_CTX *ctx) + OPENSSL_SUPPRESS_POTENTIALLY_UNINITIALIZED_WARNINGS + { + unsigned char *ext_der=NULL; + long ext_len; + ASN1_OBJECT *obj=NULL; + ASN1_OCTET_STRING *oct=NULL; + X509_EXTENSION *extension=NULL; + if (!(obj = OBJ_txt2obj(ext, 0))) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_NAME_ERROR); + ERR_add_error_data(2, "name=", ext); + goto err; + } + + if (gen_type == 1) + ext_der = string_to_hex(value, &ext_len); + else if (gen_type == 2) + ext_der = generic_asn1(value, ctx, &ext_len); + + if (ext_der == NULL) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_VALUE_ERROR); + ERR_add_error_data(2, "value=", value); + goto err; + } + + if (!(oct = M_ASN1_OCTET_STRING_new())) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + + oct->data = ext_der; + oct->length = ext_len; + ext_der = NULL; + + extension = X509_EXTENSION_create_by_OBJ(NULL, obj, crit, oct); + + err: + ASN1_OBJECT_free(obj); + M_ASN1_OCTET_STRING_free(oct); + if(ext_der) OPENSSL_free(ext_der); + return extension; + + } + +static unsigned char *generic_asn1(char *value, X509V3_CTX *ctx, long *ext_len) + { + ASN1_TYPE *typ; + unsigned char *ext_der = NULL; + typ = ASN1_generate_v3(value, ctx); + if (typ == NULL) + return NULL; + *ext_len = i2d_ASN1_TYPE(typ, &ext_der); + ASN1_TYPE_free(typ); + return ext_der; + } + +/* This is the main function: add a bunch of extensions based on a config file + * section to an extension STACK. + */ + + +int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, char *section, + STACK_OF(X509_EXTENSION) **sk) + { + X509_EXTENSION *ext; + STACK_OF(CONF_VALUE) *nval; + CONF_VALUE *val; + size_t i; + if (!(nval = NCONF_get_section(conf, section))) return 0; + for (i = 0; i < sk_CONF_VALUE_num(nval); i++) + { + val = sk_CONF_VALUE_value(nval, i); + if (!(ext = X509V3_EXT_nconf(conf, ctx, val->name, val->value))) + return 0; + if (sk) X509v3_add_ext(sk, ext, -1); + X509_EXTENSION_free(ext); + } + return 1; + } + +/* Convenience functions to add extensions to a certificate, CRL and request */ + +int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, + X509 *cert) + { + STACK_OF(X509_EXTENSION) **sk = NULL; + if (cert) + sk = &cert->cert_info->extensions; + return X509V3_EXT_add_nconf_sk(conf, ctx, section, sk); + } + +/* Same as above but for a CRL */ + +int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, + X509_CRL *crl) + { + STACK_OF(X509_EXTENSION) **sk = NULL; + if (crl) + sk = &crl->crl->extensions; + return X509V3_EXT_add_nconf_sk(conf, ctx, section, sk); + } + +/* Add extensions to certificate request */ + +int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, + X509_REQ *req) + { + STACK_OF(X509_EXTENSION) *extlist = NULL, **sk = NULL; + int i; + if (req) + sk = &extlist; + i = X509V3_EXT_add_nconf_sk(conf, ctx, section, sk); + if (!i || !sk) + return i; + i = X509_REQ_add_extensions(req, extlist); + sk_X509_EXTENSION_pop_free(extlist, X509_EXTENSION_free); + return i; + } + +/* Config database functions */ + +char * X509V3_get_string(X509V3_CTX *ctx, char *name, char *section) + { + if(!ctx->db || !ctx->db_meth || !ctx->db_meth->get_string) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_OPERATION_NOT_DEFINED); + return NULL; + } + if (ctx->db_meth->get_string) + return ctx->db_meth->get_string(ctx->db, name, section); + return NULL; + } + +STACK_OF(CONF_VALUE) * X509V3_get_section(X509V3_CTX *ctx, char *section) + { + if(!ctx->db || !ctx->db_meth || !ctx->db_meth->get_section) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_OPERATION_NOT_DEFINED); + return NULL; + } + if (ctx->db_meth->get_section) + return ctx->db_meth->get_section(ctx->db, section); + return NULL; + } + +void X509V3_string_free(X509V3_CTX *ctx, char *str) + { + if (!str) return; + if (ctx->db_meth->free_string) + ctx->db_meth->free_string(ctx->db, str); + } + +void X509V3_section_free(X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section) + { + if (!section) return; + if (ctx->db_meth->free_section) + ctx->db_meth->free_section(ctx->db, section); + } + +static char *nconf_get_string(void *db, char *section, char *value) + { + /* TODO(fork): this should return a const value. */ + return (char *) NCONF_get_string(db, section, value); + } + +static STACK_OF(CONF_VALUE) *nconf_get_section(void *db, char *section) + { + return NCONF_get_section(db, section); + } + +static const X509V3_CONF_METHOD nconf_method = { +nconf_get_string, +nconf_get_section, +NULL, +NULL +}; + +void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf) + { + ctx->db_meth = &nconf_method; + ctx->db = conf; + } + +void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subj, X509_REQ *req, + X509_CRL *crl, int flags) + { + ctx->issuer_cert = issuer; + ctx->subject_cert = subj; + ctx->crl = crl; + ctx->subject_req = req; + ctx->flags = flags; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_cpols.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_cpols.c new file mode 100644 index 00000000..0b586762 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_cpols.c @@ -0,0 +1,475 @@ +/* v3_cpols.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcy_int.h" + +/* Certificate policies extension support: this one is a bit complex... */ + +static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol, BIO *out, int indent); +static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *value); +static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals, int indent); +static void print_notice(BIO *out, USERNOTICE *notice, int indent); +static POLICYINFO *policy_section(X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *polstrs, int ia5org); +static POLICYQUALINFO *notice_section(X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *unot, int ia5org); +static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos); + +const X509V3_EXT_METHOD v3_cpols = { +NID_certificate_policies, 0,ASN1_ITEM_ref(CERTIFICATEPOLICIES), +0,0,0,0, +0,0, +0,0, +(X509V3_EXT_I2R)i2r_certpol, +(X509V3_EXT_R2I)r2i_certpol, +NULL +}; + +ASN1_ITEM_TEMPLATE(CERTIFICATEPOLICIES) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CERTIFICATEPOLICIES, POLICYINFO) +ASN1_ITEM_TEMPLATE_END(CERTIFICATEPOLICIES) + +IMPLEMENT_ASN1_FUNCTIONS(CERTIFICATEPOLICIES) + +ASN1_SEQUENCE(POLICYINFO) = { + ASN1_SIMPLE(POLICYINFO, policyid, ASN1_OBJECT), + ASN1_SEQUENCE_OF_OPT(POLICYINFO, qualifiers, POLICYQUALINFO) +} ASN1_SEQUENCE_END(POLICYINFO) + +IMPLEMENT_ASN1_FUNCTIONS(POLICYINFO) + +ASN1_ADB_TEMPLATE(policydefault) = ASN1_SIMPLE(POLICYQUALINFO, d.other, ASN1_ANY); + +ASN1_ADB(POLICYQUALINFO) = { + ADB_ENTRY(NID_id_qt_cps, ASN1_SIMPLE(POLICYQUALINFO, d.cpsuri, ASN1_IA5STRING)), + ADB_ENTRY(NID_id_qt_unotice, ASN1_SIMPLE(POLICYQUALINFO, d.usernotice, USERNOTICE)) +} ASN1_ADB_END(POLICYQUALINFO, 0, pqualid, 0, &policydefault_tt, NULL); + +ASN1_SEQUENCE(POLICYQUALINFO) = { + ASN1_SIMPLE(POLICYQUALINFO, pqualid, ASN1_OBJECT), + ASN1_ADB_OBJECT(POLICYQUALINFO) +} ASN1_SEQUENCE_END(POLICYQUALINFO) + +IMPLEMENT_ASN1_FUNCTIONS(POLICYQUALINFO) + +ASN1_SEQUENCE(USERNOTICE) = { + ASN1_OPT(USERNOTICE, noticeref, NOTICEREF), + ASN1_OPT(USERNOTICE, exptext, DISPLAYTEXT) +} ASN1_SEQUENCE_END(USERNOTICE) + +IMPLEMENT_ASN1_FUNCTIONS(USERNOTICE) + +ASN1_SEQUENCE(NOTICEREF) = { + ASN1_SIMPLE(NOTICEREF, organization, DISPLAYTEXT), + ASN1_SEQUENCE_OF(NOTICEREF, noticenos, ASN1_INTEGER) +} ASN1_SEQUENCE_END(NOTICEREF) + +IMPLEMENT_ASN1_FUNCTIONS(NOTICEREF) + +static STACK_OF(POLICYINFO) *r2i_certpol(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, char *value) +{ + STACK_OF(POLICYINFO) *pols = NULL; + char *pstr; + POLICYINFO *pol; + ASN1_OBJECT *pobj; + STACK_OF(CONF_VALUE) *vals; + CONF_VALUE *cnf; + size_t i; + int ia5org; + pols = sk_POLICYINFO_new_null(); + if (pols == NULL) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + vals = X509V3_parse_list(value); + if (vals == NULL) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_X509V3_LIB); + goto err; + } + ia5org = 0; + for(i = 0; i < sk_CONF_VALUE_num(vals); i++) { + cnf = sk_CONF_VALUE_value(vals, i); + if(cnf->value || !cnf->name ) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_POLICY_IDENTIFIER); + X509V3_conf_err(cnf); + goto err; + } + pstr = cnf->name; + if(!strcmp(pstr,"ia5org")) { + ia5org = 1; + continue; + } else if(*pstr == '@') { + STACK_OF(CONF_VALUE) *polsect; + polsect = X509V3_get_section(ctx, pstr + 1); + if(!polsect) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SECTION); + + X509V3_conf_err(cnf); + goto err; + } + pol = policy_section(ctx, polsect, ia5org); + X509V3_section_free(ctx, polsect); + if(!pol) goto err; + } else { + if(!(pobj = OBJ_txt2obj(cnf->name, 0))) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER); + X509V3_conf_err(cnf); + goto err; + } + pol = POLICYINFO_new(); + pol->policyid = pobj; + } + if (!sk_POLICYINFO_push(pols, pol)){ + POLICYINFO_free(pol); + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + } + sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); + return pols; + err: + sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); + sk_POLICYINFO_pop_free(pols, POLICYINFO_free); + return NULL; +} + +static POLICYINFO *policy_section(X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *polstrs, int ia5org) +{ + size_t i; + CONF_VALUE *cnf; + POLICYINFO *pol; + POLICYQUALINFO *qual; + if(!(pol = POLICYINFO_new())) goto merr; + for(i = 0; i < sk_CONF_VALUE_num(polstrs); i++) { + cnf = sk_CONF_VALUE_value(polstrs, i); + if(!strcmp(cnf->name, "policyIdentifier")) { + ASN1_OBJECT *pobj; + if(!(pobj = OBJ_txt2obj(cnf->value, 0))) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER); + X509V3_conf_err(cnf); + goto err; + } + pol->policyid = pobj; + + } else if(!name_cmp(cnf->name, "CPS")) { + if(!pol->qualifiers) pol->qualifiers = + sk_POLICYQUALINFO_new_null(); + if(!(qual = POLICYQUALINFO_new())) goto merr; + if(!sk_POLICYQUALINFO_push(pol->qualifiers, qual)) + goto merr; + /* TODO(fork): const correctness */ + qual->pqualid = (ASN1_OBJECT*) OBJ_nid2obj(NID_id_qt_cps); + if (qual->pqualid == NULL) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_INTERNAL_ERROR); + goto err; + } + qual->d.cpsuri = M_ASN1_IA5STRING_new(); + if (qual->d.cpsuri == NULL) { + goto err; + } + if(!ASN1_STRING_set(qual->d.cpsuri, cnf->value, + strlen(cnf->value))) goto merr; + } else if(!name_cmp(cnf->name, "userNotice")) { + STACK_OF(CONF_VALUE) *unot; + if(*cnf->value != '@') { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXPECTED_A_SECTION_NAME); + X509V3_conf_err(cnf); + goto err; + } + unot = X509V3_get_section(ctx, cnf->value + 1); + if(!unot) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SECTION); + + X509V3_conf_err(cnf); + goto err; + } + qual = notice_section(ctx, unot, ia5org); + X509V3_section_free(ctx, unot); + if(!qual) goto err; + if(!pol->qualifiers) pol->qualifiers = + sk_POLICYQUALINFO_new_null(); + if(!sk_POLICYQUALINFO_push(pol->qualifiers, qual)) + goto merr; + } else { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OPTION); + + X509V3_conf_err(cnf); + goto err; + } + } + if(!pol->policyid) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_POLICY_IDENTIFIER); + goto err; + } + + return pol; + + merr: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + + err: + POLICYINFO_free(pol); + return NULL; + + +} + +static POLICYQUALINFO *notice_section(X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *unot, int ia5org) +{ + size_t i; + int ret; + CONF_VALUE *cnf; + USERNOTICE *not; + POLICYQUALINFO *qual; + if(!(qual = POLICYQUALINFO_new())) goto merr; + /* TODO(fork): const correctness */ + qual->pqualid = (ASN1_OBJECT *) OBJ_nid2obj(NID_id_qt_unotice); + if (qual->pqualid == NULL) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_INTERNAL_ERROR); + goto err; + } + if(!(not = USERNOTICE_new())) goto merr; + qual->d.usernotice = not; + for(i = 0; i < sk_CONF_VALUE_num(unot); i++) { + cnf = sk_CONF_VALUE_value(unot, i); + if(!strcmp(cnf->name, "explicitText")) { + not->exptext = M_ASN1_VISIBLESTRING_new(); + if (not->exptext == NULL) + goto merr; + if(!ASN1_STRING_set(not->exptext, cnf->value, + strlen(cnf->value))) goto merr; + } else if(!strcmp(cnf->name, "organization")) { + NOTICEREF *nref; + if(!not->noticeref) { + if(!(nref = NOTICEREF_new())) goto merr; + not->noticeref = nref; + } else nref = not->noticeref; + if(ia5org) nref->organization->type = V_ASN1_IA5STRING; + else nref->organization->type = V_ASN1_VISIBLESTRING; + if(!ASN1_STRING_set(nref->organization, cnf->value, + strlen(cnf->value))) goto merr; + } else if(!strcmp(cnf->name, "noticeNumbers")) { + NOTICEREF *nref; + STACK_OF(CONF_VALUE) *nos; + if(!not->noticeref) { + if(!(nref = NOTICEREF_new())) goto merr; + not->noticeref = nref; + } else nref = not->noticeref; + nos = X509V3_parse_list(cnf->value); + if(!nos || !sk_CONF_VALUE_num(nos)) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NUMBERS); + X509V3_conf_err(cnf); + goto err; + } + ret = nref_nos(nref->noticenos, nos); + sk_CONF_VALUE_pop_free(nos, X509V3_conf_free); + if (!ret) + goto err; + } else { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OPTION); + X509V3_conf_err(cnf); + goto err; + } + } + + if(not->noticeref && + (!not->noticeref->noticenos || !not->noticeref->organization)) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS); + goto err; + } + + return qual; + + merr: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + + err: + POLICYQUALINFO_free(qual); + return NULL; +} + +static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos) +{ + CONF_VALUE *cnf; + ASN1_INTEGER *aint; + + size_t i; + + for(i = 0; i < sk_CONF_VALUE_num(nos); i++) { + cnf = sk_CONF_VALUE_value(nos, i); + if(!(aint = s2i_ASN1_INTEGER(NULL, cnf->name))) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NUMBER); + goto err; + } + if(!sk_ASN1_INTEGER_push(nnums, aint)) goto merr; + } + return 1; + + merr: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + + err: + sk_ASN1_INTEGER_pop_free(nnums, ASN1_STRING_free); + return 0; +} + + +static int i2r_certpol(X509V3_EXT_METHOD *method, STACK_OF(POLICYINFO) *pol, + BIO *out, int indent) +{ + size_t i; + POLICYINFO *pinfo; + /* First print out the policy OIDs */ + for(i = 0; i < sk_POLICYINFO_num(pol); i++) { + pinfo = sk_POLICYINFO_value(pol, i); + BIO_printf(out, "%*sPolicy: ", indent, ""); + i2a_ASN1_OBJECT(out, pinfo->policyid); + BIO_puts(out, "\n"); + if(pinfo->qualifiers) + print_qualifiers(out, pinfo->qualifiers, indent + 2); + } + return 1; +} + +static void print_qualifiers(BIO *out, STACK_OF(POLICYQUALINFO) *quals, + int indent) +{ + POLICYQUALINFO *qualinfo; + size_t i; + for(i = 0; i < sk_POLICYQUALINFO_num(quals); i++) { + qualinfo = sk_POLICYQUALINFO_value(quals, i); + switch(OBJ_obj2nid(qualinfo->pqualid)) + { + case NID_id_qt_cps: + BIO_printf(out, "%*sCPS: %s\n", indent, "", + qualinfo->d.cpsuri->data); + break; + + case NID_id_qt_unotice: + BIO_printf(out, "%*sUser Notice:\n", indent, ""); + print_notice(out, qualinfo->d.usernotice, indent + 2); + break; + + default: + BIO_printf(out, "%*sUnknown Qualifier: ", + indent + 2, ""); + + i2a_ASN1_OBJECT(out, qualinfo->pqualid); + BIO_puts(out, "\n"); + break; + } + } +} + +static void print_notice(BIO *out, USERNOTICE *notice, int indent) +{ + size_t i; + if(notice->noticeref) { + NOTICEREF *ref; + ref = notice->noticeref; + BIO_printf(out, "%*sOrganization: %s\n", indent, "", + ref->organization->data); + BIO_printf(out, "%*sNumber%s: ", indent, "", + sk_ASN1_INTEGER_num(ref->noticenos) > 1 ? "s" : ""); + for(i = 0; i < sk_ASN1_INTEGER_num(ref->noticenos); i++) { + ASN1_INTEGER *num; + char *tmp; + num = sk_ASN1_INTEGER_value(ref->noticenos, i); + if(i) BIO_puts(out, ", "); + tmp = i2s_ASN1_INTEGER(NULL, num); + BIO_puts(out, tmp); + OPENSSL_free(tmp); + } + BIO_puts(out, "\n"); + } + if(notice->exptext) + BIO_printf(out, "%*sExplicit Text: %s\n", indent, "", + notice->exptext->data); +} + +void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent) + { + const X509_POLICY_DATA *dat = node->data; + + BIO_printf(out, "%*sPolicy: ", indent, ""); + + i2a_ASN1_OBJECT(out, dat->valid_policy); + BIO_puts(out, "\n"); + BIO_printf(out, "%*s%s\n", indent + 2, "", + node_data_critical(dat) ? "Critical" : "Non Critical"); + if (dat->qualifier_set) + print_qualifiers(out, dat->qualifier_set, indent + 2); + else + BIO_printf(out, "%*sNo Qualifiers\n", indent + 2, ""); + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_crld.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_crld.c new file mode 100644 index 00000000..3984c316 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_crld.c @@ -0,0 +1,616 @@ +/* v3_crld.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2008 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +static void *v2i_crld(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); +static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out, + int indent); + +const X509V3_EXT_METHOD v3_crld = + { + NID_crl_distribution_points, 0, ASN1_ITEM_ref(CRL_DIST_POINTS), + 0,0,0,0, + 0,0, + 0, + v2i_crld, + i2r_crldp,0, + NULL + }; + +const X509V3_EXT_METHOD v3_freshest_crl = + { + NID_freshest_crl, 0, ASN1_ITEM_ref(CRL_DIST_POINTS), + 0,0,0,0, + 0,0, + 0, + v2i_crld, + i2r_crldp,0, + NULL + }; + +static STACK_OF(GENERAL_NAME) *gnames_from_sectname(X509V3_CTX *ctx, char *sect) + { + STACK_OF(CONF_VALUE) *gnsect; + STACK_OF(GENERAL_NAME) *gens; + if (*sect == '@') + gnsect = X509V3_get_section(ctx, sect + 1); + else + gnsect = X509V3_parse_list(sect); + if (!gnsect) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_SECTION_NOT_FOUND); + return NULL; + } + gens = v2i_GENERAL_NAMES(NULL, ctx, gnsect); + if (*sect == '@') + X509V3_section_free(ctx, gnsect); + else + sk_CONF_VALUE_pop_free(gnsect, X509V3_conf_free); + return gens; + } + +static int set_dist_point_name(DIST_POINT_NAME **pdp, X509V3_CTX *ctx, + CONF_VALUE *cnf) + { + STACK_OF(GENERAL_NAME) *fnm = NULL; + STACK_OF(X509_NAME_ENTRY) *rnm = NULL; + if (!strncmp(cnf->name, "fullname", 9)) + { + fnm = gnames_from_sectname(ctx, cnf->value); + if (!fnm) + goto err; + } + else if (!strcmp(cnf->name, "relativename")) + { + int ret; + STACK_OF(CONF_VALUE) *dnsect; + X509_NAME *nm; + nm = X509_NAME_new(); + if (!nm) + return -1; + dnsect = X509V3_get_section(ctx, cnf->value); + if (!dnsect) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_SECTION_NOT_FOUND); + return -1; + } + ret = X509V3_NAME_from_section(nm, dnsect, MBSTRING_ASC); + X509V3_section_free(ctx, dnsect); + rnm = nm->entries; + nm->entries = NULL; + X509_NAME_free(nm); + if (!ret || sk_X509_NAME_ENTRY_num(rnm) <= 0) + goto err; + /* Since its a name fragment can't have more than one + * RDNSequence + */ + if (sk_X509_NAME_ENTRY_value(rnm, + sk_X509_NAME_ENTRY_num(rnm) - 1)->set) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_MULTIPLE_RDNS); + goto err; + } + } + else + return 0; + + if (*pdp) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_DISTPOINT_ALREADY_SET); + goto err; + } + + *pdp = DIST_POINT_NAME_new(); + if (!*pdp) + goto err; + if (fnm) + { + (*pdp)->type = 0; + (*pdp)->name.fullname = fnm; + } + else + { + (*pdp)->type = 1; + (*pdp)->name.relativename = rnm; + } + + return 1; + + err: + if (fnm) + sk_GENERAL_NAME_pop_free(fnm, GENERAL_NAME_free); + if (rnm) + sk_X509_NAME_ENTRY_pop_free(rnm, X509_NAME_ENTRY_free); + return -1; + } + +static const BIT_STRING_BITNAME reason_flags[] = { +{0, "Unused", "unused"}, +{1, "Key Compromise", "keyCompromise"}, +{2, "CA Compromise", "CACompromise"}, +{3, "Affiliation Changed", "affiliationChanged"}, +{4, "Superseded", "superseded"}, +{5, "Cessation Of Operation", "cessationOfOperation"}, +{6, "Certificate Hold", "certificateHold"}, +{7, "Privilege Withdrawn", "privilegeWithdrawn"}, +{8, "AA Compromise", "AACompromise"}, +{-1, NULL, NULL} +}; + +static int set_reasons(ASN1_BIT_STRING **preas, char *value) + { + STACK_OF(CONF_VALUE) *rsk = NULL; + const BIT_STRING_BITNAME *pbn; + const char *bnam; + size_t i; + int ret = 0; + rsk = X509V3_parse_list(value); + if (!rsk) + return 0; + if (*preas) + return 0; + for (i = 0; i < sk_CONF_VALUE_num(rsk); i++) + { + bnam = sk_CONF_VALUE_value(rsk, i)->name; + if (!*preas) + { + *preas = ASN1_BIT_STRING_new(); + if (!*preas) + goto err; + } + for (pbn = reason_flags; pbn->lname; pbn++) + { + if (!strcmp(pbn->sname, bnam)) + { + if (!ASN1_BIT_STRING_set_bit(*preas, + pbn->bitnum, 1)) + goto err; + break; + } + } + if (!pbn->lname) + goto err; + } + ret = 1; + + err: + sk_CONF_VALUE_pop_free(rsk, X509V3_conf_free); + return ret; + } + +static int print_reasons(BIO *out, const char *rname, + ASN1_BIT_STRING *rflags, int indent) + { + int first = 1; + const BIT_STRING_BITNAME *pbn; + BIO_printf(out, "%*s%s:\n%*s", indent, "", rname, indent + 2, ""); + for (pbn = reason_flags; pbn->lname; pbn++) + { + if (ASN1_BIT_STRING_get_bit(rflags, pbn->bitnum)) + { + if (first) + first = 0; + else + BIO_puts(out, ", "); + BIO_puts(out, pbn->lname); + } + } + if (first) + BIO_puts(out, "\n"); + else + BIO_puts(out, "\n"); + return 1; + } + +static DIST_POINT *crldp_from_section(X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *nval) + { + size_t i; + CONF_VALUE *cnf; + DIST_POINT *point = NULL; + point = DIST_POINT_new(); + if (!point) + goto err; + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) + { + int ret; + cnf = sk_CONF_VALUE_value(nval, i); + ret = set_dist_point_name(&point->distpoint, ctx, cnf); + if (ret > 0) + continue; + if (ret < 0) + goto err; + if (!strcmp(cnf->name, "reasons")) + { + if (!set_reasons(&point->reasons, cnf->value)) + goto err; + } + else if (!strcmp(cnf->name, "CRLissuer")) + { + point->CRLissuer = + gnames_from_sectname(ctx, cnf->value); + if (!point->CRLissuer) + goto err; + } + } + + return point; + + + err: + if (point) + DIST_POINT_free(point); + return NULL; + } + +static void *v2i_crld(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) + { + STACK_OF(DIST_POINT) *crld = NULL; + GENERAL_NAMES *gens = NULL; + GENERAL_NAME *gen = NULL; + CONF_VALUE *cnf; + size_t i; + if(!(crld = sk_DIST_POINT_new_null())) goto merr; + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + DIST_POINT *point; + cnf = sk_CONF_VALUE_value(nval, i); + if (!cnf->value) + { + STACK_OF(CONF_VALUE) *dpsect; + dpsect = X509V3_get_section(ctx, cnf->name); + if (!dpsect) + goto err; + point = crldp_from_section(ctx, dpsect); + X509V3_section_free(ctx, dpsect); + if (!point) + goto err; + if(!sk_DIST_POINT_push(crld, point)) + { + DIST_POINT_free(point); + goto merr; + } + } + else + { + if(!(gen = v2i_GENERAL_NAME(method, ctx, cnf))) + goto err; + if(!(gens = GENERAL_NAMES_new())) + goto merr; + if(!sk_GENERAL_NAME_push(gens, gen)) + goto merr; + gen = NULL; + if(!(point = DIST_POINT_new())) + goto merr; + if(!sk_DIST_POINT_push(crld, point)) + { + DIST_POINT_free(point); + goto merr; + } + if(!(point->distpoint = DIST_POINT_NAME_new())) + goto merr; + point->distpoint->name.fullname = gens; + point->distpoint->type = 0; + gens = NULL; + } + } + return crld; + + merr: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + err: + GENERAL_NAME_free(gen); + GENERAL_NAMES_free(gens); + sk_DIST_POINT_pop_free(crld, DIST_POINT_free); + return NULL; +} + +IMPLEMENT_ASN1_SET_OF(DIST_POINT) + +static int dpn_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, + void *exarg) + { + DIST_POINT_NAME *dpn = (DIST_POINT_NAME *)*pval; + + switch(operation) + { + case ASN1_OP_NEW_POST: + dpn->dpname = NULL; + break; + + case ASN1_OP_FREE_POST: + if (dpn->dpname) + X509_NAME_free(dpn->dpname); + break; + } + return 1; + } + + +ASN1_CHOICE_cb(DIST_POINT_NAME, dpn_cb) = { + ASN1_IMP_SEQUENCE_OF(DIST_POINT_NAME, name.fullname, GENERAL_NAME, 0), + ASN1_IMP_SET_OF(DIST_POINT_NAME, name.relativename, X509_NAME_ENTRY, 1) +} ASN1_CHOICE_END_cb(DIST_POINT_NAME, DIST_POINT_NAME, type) + + +IMPLEMENT_ASN1_FUNCTIONS(DIST_POINT_NAME) + +ASN1_SEQUENCE(DIST_POINT) = { + ASN1_EXP_OPT(DIST_POINT, distpoint, DIST_POINT_NAME, 0), + ASN1_IMP_OPT(DIST_POINT, reasons, ASN1_BIT_STRING, 1), + ASN1_IMP_SEQUENCE_OF_OPT(DIST_POINT, CRLissuer, GENERAL_NAME, 2) +} ASN1_SEQUENCE_END(DIST_POINT) + +IMPLEMENT_ASN1_FUNCTIONS(DIST_POINT) + +ASN1_ITEM_TEMPLATE(CRL_DIST_POINTS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, CRLDistributionPoints, DIST_POINT) +ASN1_ITEM_TEMPLATE_END(CRL_DIST_POINTS) + +IMPLEMENT_ASN1_FUNCTIONS(CRL_DIST_POINTS) + +ASN1_SEQUENCE(ISSUING_DIST_POINT) = { + ASN1_EXP_OPT(ISSUING_DIST_POINT, distpoint, DIST_POINT_NAME, 0), + ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyuser, ASN1_FBOOLEAN, 1), + ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyCA, ASN1_FBOOLEAN, 2), + ASN1_IMP_OPT(ISSUING_DIST_POINT, onlysomereasons, ASN1_BIT_STRING, 3), + ASN1_IMP_OPT(ISSUING_DIST_POINT, indirectCRL, ASN1_FBOOLEAN, 4), + ASN1_IMP_OPT(ISSUING_DIST_POINT, onlyattr, ASN1_FBOOLEAN, 5) +} ASN1_SEQUENCE_END(ISSUING_DIST_POINT) + +IMPLEMENT_ASN1_FUNCTIONS(ISSUING_DIST_POINT) + +static int i2r_idp(const X509V3_EXT_METHOD *method, void *pidp, BIO *out, + int indent); +static void *v2i_idp(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *nval); + +const X509V3_EXT_METHOD v3_idp = + { + NID_issuing_distribution_point, X509V3_EXT_MULTILINE, + ASN1_ITEM_ref(ISSUING_DIST_POINT), + 0,0,0,0, + 0,0, + 0, + v2i_idp, + i2r_idp,0, + NULL + }; + +static void *v2i_idp(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *nval) + { + ISSUING_DIST_POINT *idp = NULL; + CONF_VALUE *cnf; + char *name, *val; + size_t i; + int ret; + idp = ISSUING_DIST_POINT_new(); + if (!idp) + goto merr; + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) + { + cnf = sk_CONF_VALUE_value(nval, i); + name = cnf->name; + val = cnf->value; + ret = set_dist_point_name(&idp->distpoint, ctx, cnf); + if (ret > 0) + continue; + if (ret < 0) + goto err; + if (!strcmp(name, "onlyuser")) + { + if (!X509V3_get_value_bool(cnf, &idp->onlyuser)) + goto err; + } + else if (!strcmp(name, "onlyCA")) + { + if (!X509V3_get_value_bool(cnf, &idp->onlyCA)) + goto err; + } + else if (!strcmp(name, "onlyAA")) + { + if (!X509V3_get_value_bool(cnf, &idp->onlyattr)) + goto err; + } + else if (!strcmp(name, "indirectCRL")) + { + if (!X509V3_get_value_bool(cnf, &idp->indirectCRL)) + goto err; + } + else if (!strcmp(name, "onlysomereasons")) + { + if (!set_reasons(&idp->onlysomereasons, val)) + goto err; + } + else + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NAME); + X509V3_conf_err(cnf); + goto err; + } + } + return idp; + + merr: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + err: + ISSUING_DIST_POINT_free(idp); + return NULL; + } + +static int print_gens(BIO *out, STACK_OF(GENERAL_NAME) *gens, int indent) + { + size_t i; + for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) + { + BIO_printf(out, "%*s", indent + 2, ""); + GENERAL_NAME_print(out, sk_GENERAL_NAME_value(gens, i)); + BIO_puts(out, "\n"); + } + return 1; + } + +static int print_distpoint(BIO *out, DIST_POINT_NAME *dpn, int indent) + { + if (dpn->type == 0) + { + BIO_printf(out, "%*sFull Name:\n", indent, ""); + print_gens(out, dpn->name.fullname, indent); + } + else + { + X509_NAME ntmp; + ntmp.entries = dpn->name.relativename; + BIO_printf(out, "%*sRelative Name:\n%*s", + indent, "", indent + 2, ""); + X509_NAME_print_ex(out, &ntmp, 0, XN_FLAG_ONELINE); + BIO_puts(out, "\n"); + } + return 1; + } + +static int i2r_idp(const X509V3_EXT_METHOD *method, void *pidp, BIO *out, + int indent) + { + ISSUING_DIST_POINT *idp = pidp; + if (idp->distpoint) + print_distpoint(out, idp->distpoint, indent); + if (idp->onlyuser > 0) + BIO_printf(out, "%*sOnly User Certificates\n", indent, ""); + if (idp->onlyCA > 0) + BIO_printf(out, "%*sOnly CA Certificates\n", indent, ""); + if (idp->indirectCRL > 0) + BIO_printf(out, "%*sIndirect CRL\n", indent, ""); + if (idp->onlysomereasons) + print_reasons(out, "Only Some Reasons", + idp->onlysomereasons, indent); + if (idp->onlyattr > 0) + BIO_printf(out, "%*sOnly Attribute Certificates\n", indent, ""); + if (!idp->distpoint && (idp->onlyuser <= 0) && (idp->onlyCA <= 0) + && (idp->indirectCRL <= 0) && !idp->onlysomereasons + && (idp->onlyattr <= 0)) + BIO_printf(out, "%*s\n", indent, ""); + + return 1; + } + +static int i2r_crldp(const X509V3_EXT_METHOD *method, void *pcrldp, BIO *out, + int indent) + { + STACK_OF(DIST_POINT) *crld = pcrldp; + DIST_POINT *point; + size_t i; + for(i = 0; i < sk_DIST_POINT_num(crld); i++) + { + BIO_puts(out, "\n"); + point = sk_DIST_POINT_value(crld, i); + if(point->distpoint) + print_distpoint(out, point->distpoint, indent); + if(point->reasons) + print_reasons(out, "Reasons", point->reasons, + indent); + if(point->CRLissuer) + { + BIO_printf(out, "%*sCRL Issuer:\n", indent, ""); + print_gens(out, point->CRLissuer, indent); + } + } + return 1; + } + +int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, X509_NAME *iname) + { + size_t i; + STACK_OF(X509_NAME_ENTRY) *frag; + X509_NAME_ENTRY *ne; + if (!dpn || (dpn->type != 1)) + return 1; + frag = dpn->name.relativename; + dpn->dpname = X509_NAME_dup(iname); + if (!dpn->dpname) + return 0; + for (i = 0; i < sk_X509_NAME_ENTRY_num(frag); i++) + { + ne = sk_X509_NAME_ENTRY_value(frag, i); + if (!X509_NAME_add_entry(dpn->dpname, ne, -1, i ? 0 : 1)) + { + X509_NAME_free(dpn->dpname); + dpn->dpname = NULL; + return 0; + } + } + /* generate cached encoding of name */ + if (i2d_X509_NAME(dpn->dpname, NULL) < 0) + { + X509_NAME_free(dpn->dpname); + dpn->dpname = NULL; + return 0; + } + return 1; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_enum.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_enum.c new file mode 100644 index 00000000..0fe6bb63 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_enum.c @@ -0,0 +1,98 @@ +/* v3_enum.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include + + +static const ENUMERATED_NAMES crl_reasons[] = { +{CRL_REASON_UNSPECIFIED, "Unspecified", "unspecified"}, +{CRL_REASON_KEY_COMPROMISE, "Key Compromise", "keyCompromise"}, +{CRL_REASON_CA_COMPROMISE, "CA Compromise", "CACompromise"}, +{CRL_REASON_AFFILIATION_CHANGED, "Affiliation Changed", "affiliationChanged"}, +{CRL_REASON_SUPERSEDED, "Superseded", "superseded"}, +{CRL_REASON_CESSATION_OF_OPERATION, + "Cessation Of Operation", "cessationOfOperation"}, +{CRL_REASON_CERTIFICATE_HOLD, "Certificate Hold", "certificateHold"}, +{CRL_REASON_REMOVE_FROM_CRL, "Remove From CRL", "removeFromCRL"}, +{CRL_REASON_PRIVILEGE_WITHDRAWN, "Privilege Withdrawn", "privilegeWithdrawn"}, +{CRL_REASON_AA_COMPROMISE, "AA Compromise", "AACompromise"}, +{-1, NULL, NULL} +}; + +const X509V3_EXT_METHOD v3_crl_reason = { +NID_crl_reason, 0, ASN1_ITEM_ref(ASN1_ENUMERATED), +0,0,0,0, +(X509V3_EXT_I2S)i2s_ASN1_ENUMERATED_TABLE, +0, +0,0,0,0, +(void *)crl_reasons}; + + +char *i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *method, + ASN1_ENUMERATED *e) +{ + const ENUMERATED_NAMES *enam; + long strval; + strval = ASN1_ENUMERATED_get(e); + for(enam = method->usr_data; enam->lname; enam++) { + if(strval == enam->bitnum) return BUF_strdup(enam->lname); + } + return i2s_ASN1_ENUMERATED(method, e); +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_extku.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_extku.c new file mode 100644 index 00000000..d64eb9cc --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_extku.c @@ -0,0 +1,145 @@ +/* v3_extku.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include + +#include +#include +#include +#include +#include + + +static void *v2i_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *nval); +static STACK_OF(CONF_VALUE) *i2v_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method, + void *eku, STACK_OF(CONF_VALUE) *extlist); + +const X509V3_EXT_METHOD v3_ext_ku = { + NID_ext_key_usage, 0, + ASN1_ITEM_ref(EXTENDED_KEY_USAGE), + 0,0,0,0, + 0,0, + i2v_EXTENDED_KEY_USAGE, + v2i_EXTENDED_KEY_USAGE, + 0,0, + NULL +}; + +/* NB OCSP acceptable responses also is a SEQUENCE OF OBJECT */ +const X509V3_EXT_METHOD v3_ocsp_accresp = { + NID_id_pkix_OCSP_acceptableResponses, 0, + ASN1_ITEM_ref(EXTENDED_KEY_USAGE), + 0,0,0,0, + 0,0, + i2v_EXTENDED_KEY_USAGE, + v2i_EXTENDED_KEY_USAGE, + 0,0, + NULL +}; + +ASN1_ITEM_TEMPLATE(EXTENDED_KEY_USAGE) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, EXTENDED_KEY_USAGE, ASN1_OBJECT) +ASN1_ITEM_TEMPLATE_END(EXTENDED_KEY_USAGE) + +IMPLEMENT_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE) + +static STACK_OF(CONF_VALUE) * + i2v_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method, void *a, + STACK_OF(CONF_VALUE) *ext_list) +{ + EXTENDED_KEY_USAGE *eku = a; + size_t i; + ASN1_OBJECT *obj; + char obj_tmp[80]; + for(i = 0; i < sk_ASN1_OBJECT_num(eku); i++) { + obj = sk_ASN1_OBJECT_value(eku, i); + i2t_ASN1_OBJECT(obj_tmp, 80, obj); + X509V3_add_value(NULL, obj_tmp, &ext_list); + } + return ext_list; +} + +static void *v2i_EXTENDED_KEY_USAGE(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) +{ + EXTENDED_KEY_USAGE *extku; + char *extval; + ASN1_OBJECT *objtmp; + CONF_VALUE *val; + size_t i; + + if(!(extku = sk_ASN1_OBJECT_new_null())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + val = sk_CONF_VALUE_value(nval, i); + if(val->value) extval = val->value; + else extval = val->name; + if(!(objtmp = OBJ_txt2obj(extval, 0))) { + sk_ASN1_OBJECT_pop_free(extku, ASN1_OBJECT_free); + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER); + X509V3_conf_err(val); + return NULL; + } + sk_ASN1_OBJECT_push(extku, objtmp); + } + return extku; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_genn.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_genn.c new file mode 100644 index 00000000..8b0a68d4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_genn.c @@ -0,0 +1,252 @@ +/* v3_genn.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2008 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include + +#include +#include +#include +#include + + +ASN1_SEQUENCE(OTHERNAME) = { + ASN1_SIMPLE(OTHERNAME, type_id, ASN1_OBJECT), + /* Maybe have a true ANY DEFINED BY later */ + ASN1_EXP(OTHERNAME, value, ASN1_ANY, 0) +} ASN1_SEQUENCE_END(OTHERNAME) + +IMPLEMENT_ASN1_FUNCTIONS(OTHERNAME) + +ASN1_SEQUENCE(EDIPARTYNAME) = { + ASN1_IMP_OPT(EDIPARTYNAME, nameAssigner, DIRECTORYSTRING, 0), + ASN1_IMP_OPT(EDIPARTYNAME, partyName, DIRECTORYSTRING, 1) +} ASN1_SEQUENCE_END(EDIPARTYNAME) + +IMPLEMENT_ASN1_FUNCTIONS(EDIPARTYNAME) + +ASN1_CHOICE(GENERAL_NAME) = { + ASN1_IMP(GENERAL_NAME, d.otherName, OTHERNAME, GEN_OTHERNAME), + ASN1_IMP(GENERAL_NAME, d.rfc822Name, ASN1_IA5STRING, GEN_EMAIL), + ASN1_IMP(GENERAL_NAME, d.dNSName, ASN1_IA5STRING, GEN_DNS), + /* Don't decode this */ + ASN1_IMP(GENERAL_NAME, d.x400Address, ASN1_SEQUENCE, GEN_X400), + /* X509_NAME is a CHOICE type so use EXPLICIT */ + ASN1_EXP(GENERAL_NAME, d.directoryName, X509_NAME, GEN_DIRNAME), + ASN1_IMP(GENERAL_NAME, d.ediPartyName, EDIPARTYNAME, GEN_EDIPARTY), + ASN1_IMP(GENERAL_NAME, d.uniformResourceIdentifier, ASN1_IA5STRING, GEN_URI), + ASN1_IMP(GENERAL_NAME, d.iPAddress, ASN1_OCTET_STRING, GEN_IPADD), + ASN1_IMP(GENERAL_NAME, d.registeredID, ASN1_OBJECT, GEN_RID) +} ASN1_CHOICE_END(GENERAL_NAME) + +IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAME) + +ASN1_ITEM_TEMPLATE(GENERAL_NAMES) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, GeneralNames, GENERAL_NAME) +ASN1_ITEM_TEMPLATE_END(GENERAL_NAMES) + +IMPLEMENT_ASN1_FUNCTIONS(GENERAL_NAMES) + +GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a) + { + return (GENERAL_NAME *) ASN1_dup((i2d_of_void *) i2d_GENERAL_NAME, + (d2i_of_void *) d2i_GENERAL_NAME, + (char *) a); + } + +/* Returns 0 if they are equal, != 0 otherwise. */ +int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) + { + int result = -1; + + if (!a || !b || a->type != b->type) return -1; + switch(a->type) + { + case GEN_X400: + case GEN_EDIPARTY: + result = ASN1_TYPE_cmp(a->d.other, b->d.other); + break; + + case GEN_OTHERNAME: + result = OTHERNAME_cmp(a->d.otherName, b->d.otherName); + break; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + result = ASN1_STRING_cmp(a->d.ia5, b->d.ia5); + break; + + case GEN_DIRNAME: + result = X509_NAME_cmp(a->d.dirn, b->d.dirn); + break; + + case GEN_IPADD: + result = ASN1_OCTET_STRING_cmp(a->d.ip, b->d.ip); + break; + + case GEN_RID: + result = OBJ_cmp(a->d.rid, b->d.rid); + break; + } + return result; + } + +/* Returns 0 if they are equal, != 0 otherwise. */ +int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b) + { + int result = -1; + + if (!a || !b) return -1; + /* Check their type first. */ + if ((result = OBJ_cmp(a->type_id, b->type_id)) != 0) + return result; + /* Check the value. */ + result = ASN1_TYPE_cmp(a->value, b->value); + return result; + } + +void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value) + { + switch(type) + { + case GEN_X400: + case GEN_EDIPARTY: + a->d.other = value; + break; + + case GEN_OTHERNAME: + a->d.otherName = value; + break; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + a->d.ia5 = value; + break; + + case GEN_DIRNAME: + a->d.dirn = value; + break; + + case GEN_IPADD: + a->d.ip = value; + break; + + case GEN_RID: + a->d.rid = value; + break; + } + a->type = type; + } + +void *GENERAL_NAME_get0_value(GENERAL_NAME *a, int *ptype) + { + if (ptype) + *ptype = a->type; + switch(a->type) + { + case GEN_X400: + case GEN_EDIPARTY: + return a->d.other; + + case GEN_OTHERNAME: + return a->d.otherName; + + case GEN_EMAIL: + case GEN_DNS: + case GEN_URI: + return a->d.ia5; + + case GEN_DIRNAME: + return a->d.dirn; + + case GEN_IPADD: + return a->d.ip; + + case GEN_RID: + return a->d.rid; + + default: + return NULL; + } + } + +int GENERAL_NAME_set0_othername(GENERAL_NAME *gen, + ASN1_OBJECT *oid, ASN1_TYPE *value) + { + OTHERNAME *oth; + oth = OTHERNAME_new(); + if (!oth) + return 0; + oth->type_id = oid; + oth->value = value; + GENERAL_NAME_set0_value(gen, GEN_OTHERNAME, oth); + return 1; + } + +int GENERAL_NAME_get0_otherName(GENERAL_NAME *gen, + ASN1_OBJECT **poid, ASN1_TYPE **pvalue) + { + if (gen->type != GEN_OTHERNAME) + return 0; + if (poid) + *poid = gen->d.otherName->type_id; + if (pvalue) + *pvalue = gen->d.otherName->value; + return 1; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_ia5.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_ia5.c new file mode 100644 index 00000000..5a272335 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_ia5.c @@ -0,0 +1,117 @@ +/* v3_ia5.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + + +static char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, ASN1_IA5STRING *ia5); +static ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str); +const X509V3_EXT_METHOD v3_ns_ia5_list[] = { +EXT_IA5STRING(NID_netscape_base_url), +EXT_IA5STRING(NID_netscape_revocation_url), +EXT_IA5STRING(NID_netscape_ca_revocation_url), +EXT_IA5STRING(NID_netscape_renewal_url), +EXT_IA5STRING(NID_netscape_ca_policy_url), +EXT_IA5STRING(NID_netscape_ssl_server_name), +EXT_IA5STRING(NID_netscape_comment), +EXT_END +}; + + +static char *i2s_ASN1_IA5STRING(X509V3_EXT_METHOD *method, + ASN1_IA5STRING *ia5) +{ + char *tmp; + if(!ia5 || !ia5->length) return NULL; + if(!(tmp = OPENSSL_malloc(ia5->length + 1))) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + memcpy(tmp, ia5->data, ia5->length); + tmp[ia5->length] = 0; + return tmp; +} + +static ASN1_IA5STRING *s2i_ASN1_IA5STRING(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, char *str) +{ + ASN1_IA5STRING *ia5; + if(!str) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_ARGUMENT); + return NULL; + } + if(!(ia5 = M_ASN1_IA5STRING_new())) goto err; + if(!ASN1_STRING_set((ASN1_STRING *)ia5, (unsigned char*)str, + strlen(str))) { + M_ASN1_IA5STRING_free(ia5); + goto err; + } + return ia5; + err: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; +} + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_info.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_info.c new file mode 100644 index 00000000..475c56f7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_info.c @@ -0,0 +1,200 @@ +/* v3_info.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD *method, + AUTHORITY_INFO_ACCESS *ainfo, + STACK_OF(CONF_VALUE) *ret); +static AUTHORITY_INFO_ACCESS *v2i_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); + +const X509V3_EXT_METHOD v3_info = +{ NID_info_access, X509V3_EXT_MULTILINE, ASN1_ITEM_ref(AUTHORITY_INFO_ACCESS), +0,0,0,0, +0,0, +(X509V3_EXT_I2V)i2v_AUTHORITY_INFO_ACCESS, +(X509V3_EXT_V2I)v2i_AUTHORITY_INFO_ACCESS, +0,0, +NULL}; + +const X509V3_EXT_METHOD v3_sinfo = +{ NID_sinfo_access, X509V3_EXT_MULTILINE, ASN1_ITEM_ref(AUTHORITY_INFO_ACCESS), +0,0,0,0, +0,0, +(X509V3_EXT_I2V)i2v_AUTHORITY_INFO_ACCESS, +(X509V3_EXT_V2I)v2i_AUTHORITY_INFO_ACCESS, +0,0, +NULL}; + +ASN1_SEQUENCE(ACCESS_DESCRIPTION) = { + ASN1_SIMPLE(ACCESS_DESCRIPTION, method, ASN1_OBJECT), + ASN1_SIMPLE(ACCESS_DESCRIPTION, location, GENERAL_NAME) +} ASN1_SEQUENCE_END(ACCESS_DESCRIPTION) + +IMPLEMENT_ASN1_FUNCTIONS(ACCESS_DESCRIPTION) + +ASN1_ITEM_TEMPLATE(AUTHORITY_INFO_ACCESS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, GeneralNames, ACCESS_DESCRIPTION) +ASN1_ITEM_TEMPLATE_END(AUTHORITY_INFO_ACCESS) + +IMPLEMENT_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS) + +static STACK_OF(CONF_VALUE) *i2v_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD *method, + AUTHORITY_INFO_ACCESS *ainfo, + STACK_OF(CONF_VALUE) *ret) +{ + ACCESS_DESCRIPTION *desc; + size_t i; + int nlen; + char objtmp[80], *ntmp; + CONF_VALUE *vtmp; + for(i = 0; i < sk_ACCESS_DESCRIPTION_num(ainfo); i++) { + desc = sk_ACCESS_DESCRIPTION_value(ainfo, i); + ret = i2v_GENERAL_NAME(method, desc->location, ret); + if(!ret) break; + vtmp = sk_CONF_VALUE_value(ret, i); + i2t_ASN1_OBJECT(objtmp, sizeof objtmp, desc->method); + nlen = strlen(objtmp) + strlen(vtmp->name) + 5; + ntmp = OPENSSL_malloc(nlen); + if(!ntmp) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + BUF_strlcpy(ntmp, objtmp, nlen); + BUF_strlcat(ntmp, " - ", nlen); + BUF_strlcat(ntmp, vtmp->name, nlen); + OPENSSL_free(vtmp->name); + vtmp->name = ntmp; + + } + if(!ret) return sk_CONF_VALUE_new_null(); + return ret; +} + +static AUTHORITY_INFO_ACCESS *v2i_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) +{ + AUTHORITY_INFO_ACCESS *ainfo = NULL; + CONF_VALUE *cnf, ctmp; + ACCESS_DESCRIPTION *acc; + size_t i; + int objlen; + char *objtmp, *ptmp; + if(!(ainfo = sk_ACCESS_DESCRIPTION_new_null())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + cnf = sk_CONF_VALUE_value(nval, i); + if(!(acc = ACCESS_DESCRIPTION_new()) + || !sk_ACCESS_DESCRIPTION_push(ainfo, acc)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + ptmp = strchr(cnf->name, ';'); + if(!ptmp) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SYNTAX); + goto err; + } + objlen = ptmp - cnf->name; + ctmp.name = ptmp + 1; + ctmp.value = cnf->value; + if(!v2i_GENERAL_NAME_ex(acc->location, method, ctx, &ctmp, 0)) + goto err; + if(!(objtmp = OPENSSL_malloc(objlen + 1))) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + strncpy(objtmp, cnf->name, objlen); + objtmp[objlen] = 0; + acc->method = OBJ_txt2obj(objtmp, 0); + if(!acc->method) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_BAD_OBJECT); + ERR_add_error_data(2, "value=", objtmp); + OPENSSL_free(objtmp); + goto err; + } + OPENSSL_free(objtmp); + + } + return ainfo; + err: + sk_ACCESS_DESCRIPTION_pop_free(ainfo, ACCESS_DESCRIPTION_free); + return NULL; +} + +int i2a_ACCESS_DESCRIPTION(BIO *bp, ACCESS_DESCRIPTION* a) + { + i2a_ASN1_OBJECT(bp, a->method); +#ifdef UNDEF + i2a_GENERAL_NAME(bp, a->location); +#endif + return 2; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_int.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_int.c new file mode 100644 index 00000000..8ca23bd7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_int.c @@ -0,0 +1,87 @@ +/* v3_int.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999-2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include + + +const X509V3_EXT_METHOD v3_crl_num = { + NID_crl_number, 0, ASN1_ITEM_ref(ASN1_INTEGER), + 0,0,0,0, + (X509V3_EXT_I2S)i2s_ASN1_INTEGER, + 0, + 0,0,0,0, NULL}; + +const X509V3_EXT_METHOD v3_delta_crl = { + NID_delta_crl, 0, ASN1_ITEM_ref(ASN1_INTEGER), + 0,0,0,0, + (X509V3_EXT_I2S)i2s_ASN1_INTEGER, + 0, + 0,0,0,0, NULL}; + +static void * s2i_asn1_int(X509V3_EXT_METHOD *meth, X509V3_CTX *ctx, char *value) + { + return s2i_ASN1_INTEGER(meth, value); + } + +const X509V3_EXT_METHOD v3_inhibit_anyp = { + NID_inhibit_any_policy, 0, ASN1_ITEM_ref(ASN1_INTEGER), + 0,0,0,0, + (X509V3_EXT_I2S)i2s_ASN1_INTEGER, + (X509V3_EXT_S2I)s2i_asn1_int, + 0,0,0,0, NULL}; diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_lib.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_lib.c new file mode 100644 index 00000000..f8e5531d --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_lib.c @@ -0,0 +1,335 @@ +/* v3_lib.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* X509 v3 extension utilities */ + +#include + +#include +#include +#include +#include +#include + +#include "ext_dat.h" +static STACK_OF(X509V3_EXT_METHOD) *ext_list = NULL; + +static void ext_list_free(X509V3_EXT_METHOD *ext); + +static int ext_stack_cmp(const X509V3_EXT_METHOD **a, const X509V3_EXT_METHOD **b) +{ + return ((*a)->ext_nid - (*b)->ext_nid); +} + +int X509V3_EXT_add(X509V3_EXT_METHOD *ext) +{ + if(!ext_list && !(ext_list = sk_X509V3_EXT_METHOD_new(ext_stack_cmp))) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + ext_list_free(ext); + return 0; + } + if(!sk_X509V3_EXT_METHOD_push(ext_list, ext)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + ext_list_free(ext); + return 0; + } + return 1; +} + +static int ext_cmp(const void *void_a, + const void *void_b) +{ + const X509V3_EXT_METHOD **a = (const X509V3_EXT_METHOD**) void_a; + const X509V3_EXT_METHOD **b = (const X509V3_EXT_METHOD**) void_b; + return ext_stack_cmp(a, b); +} + +const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid) +{ + X509V3_EXT_METHOD tmp; + const X509V3_EXT_METHOD *t = &tmp, * const *ret; + size_t idx; + + if(nid < 0) return NULL; + tmp.ext_nid = nid; + ret = bsearch(&t, standard_exts, STANDARD_EXTENSION_COUNT, sizeof(X509V3_EXT_METHOD*), ext_cmp); + if(ret) return *ret; + if(!ext_list) return NULL; + + if (!sk_X509V3_EXT_METHOD_find(ext_list, &idx, &tmp)) + return NULL; + return sk_X509V3_EXT_METHOD_value(ext_list, idx); +} + +const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext) +{ + int nid; + if((nid = OBJ_obj2nid(ext->object)) == NID_undef) return NULL; + return X509V3_EXT_get_nid(nid); +} + +int X509V3_EXT_free(int nid, void *ext_data) +{ + const X509V3_EXT_METHOD *ext_method = X509V3_EXT_get_nid(nid); + if (ext_method == NULL) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_CANNOT_FIND_FREE_FUNCTION); + return 0; + } + + if (ext_method->it != NULL) + ASN1_item_free(ext_data, ASN1_ITEM_ptr(ext_method->it)); + else if (ext_method->ext_free != NULL) + ext_method->ext_free(ext_data); + else + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_CANNOT_FIND_FREE_FUNCTION); + return 0; + } + + return 1; +} + +int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist) +{ + for(;extlist->ext_nid!=-1;extlist++) + if(!X509V3_EXT_add(extlist)) return 0; + return 1; +} + +int X509V3_EXT_add_alias(int nid_to, int nid_from) +{ + const X509V3_EXT_METHOD *ext; + X509V3_EXT_METHOD *tmpext; + + if(!(ext = X509V3_EXT_get_nid(nid_from))) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_EXTENSION_NOT_FOUND); + return 0; + } + if(!(tmpext = (X509V3_EXT_METHOD *)OPENSSL_malloc(sizeof(X509V3_EXT_METHOD)))) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return 0; + } + *tmpext = *ext; + tmpext->ext_nid = nid_to; + tmpext->ext_flags |= X509V3_EXT_DYNAMIC; + return X509V3_EXT_add(tmpext); +} + +void X509V3_EXT_cleanup(void) +{ + sk_X509V3_EXT_METHOD_pop_free(ext_list, ext_list_free); + ext_list = NULL; +} + +static void ext_list_free(X509V3_EXT_METHOD *ext) +{ + if(ext->ext_flags & X509V3_EXT_DYNAMIC) OPENSSL_free(ext); +} + +/* Legacy function: we don't need to add standard extensions + * any more because they are now kept in ext_dat.h. + */ + +int X509V3_add_standard_extensions(void) +{ + return 1; +} + +/* Return an extension internal structure */ + +void *X509V3_EXT_d2i(X509_EXTENSION *ext) +{ + const X509V3_EXT_METHOD *method; + const unsigned char *p; + + if(!(method = X509V3_EXT_get(ext))) return NULL; + p = ext->value->data; + if(method->it) return ASN1_item_d2i(NULL, &p, ext->value->length, ASN1_ITEM_ptr(method->it)); + return method->d2i(NULL, &p, ext->value->length); +} + +/* Get critical flag and decoded version of extension from a NID. + * The "idx" variable returns the last found extension and can + * be used to retrieve multiple extensions of the same NID. + * However multiple extensions with the same NID is usually + * due to a badly encoded certificate so if idx is NULL we + * choke if multiple extensions exist. + * The "crit" variable is set to the critical value. + * The return value is the decoded extension or NULL on + * error. The actual error can have several different causes, + * the value of *crit reflects the cause: + * >= 0, extension found but not decoded (reflects critical value). + * -1 extension not found. + * -2 extension occurs more than once. + */ + +void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx) +{ + int lastpos; + size_t i; + X509_EXTENSION *ex, *found_ex = NULL; + if(!x) { + if(idx) *idx = -1; + if(crit) *crit = -1; + return NULL; + } + if(idx) lastpos = *idx + 1; + else lastpos = 0; + if(lastpos < 0) lastpos = 0; + for(i = lastpos; i < sk_X509_EXTENSION_num(x); i++) + { + ex = sk_X509_EXTENSION_value(x, i); + if(OBJ_obj2nid(ex->object) == nid) { + if(idx) { + *idx = i; + found_ex = ex; + break; + } else if(found_ex) { + /* Found more than one */ + if(crit) *crit = -2; + return NULL; + } + found_ex = ex; + } + } + if(found_ex) { + /* Found it */ + if(crit) *crit = X509_EXTENSION_get_critical(found_ex); + return X509V3_EXT_d2i(found_ex); + } + + /* Extension not found */ + if(idx) *idx = -1; + if(crit) *crit = -1; + return NULL; +} + +/* This function is a general extension append, replace and delete utility. + * The precise operation is governed by the 'flags' value. The 'crit' and + * 'value' arguments (if relevant) are the extensions internal structure. + */ + +int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, + int crit, unsigned long flags) +{ + int extidx = -1; + int errcode; + X509_EXTENSION *ext, *extmp; + unsigned long ext_op = flags & X509V3_ADD_OP_MASK; + + /* If appending we don't care if it exists, otherwise + * look for existing extension. + */ + if(ext_op != X509V3_ADD_APPEND) + extidx = X509v3_get_ext_by_NID(*x, nid, -1); + + /* See if extension exists */ + if(extidx >= 0) { + /* If keep existing, nothing to do */ + if(ext_op == X509V3_ADD_KEEP_EXISTING) + return 1; + /* If default then its an error */ + if(ext_op == X509V3_ADD_DEFAULT) { + errcode = X509V3_R_EXTENSION_EXISTS; + goto err; + } + /* If delete, just delete it */ + if(ext_op == X509V3_ADD_DELETE) { + if(!sk_X509_EXTENSION_delete(*x, extidx)) return -1; + return 1; + } + } else { + /* If replace existing or delete, error since + * extension must exist + */ + if((ext_op == X509V3_ADD_REPLACE_EXISTING) || + (ext_op == X509V3_ADD_DELETE)) { + errcode = X509V3_R_EXTENSION_NOT_FOUND; + goto err; + } + } + + /* If we get this far then we have to create an extension: + * could have some flags for alternative encoding schemes... + */ + + ext = X509V3_EXT_i2d(nid, crit, value); + + if(!ext) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ERROR_CREATING_EXTENSION); + return 0; + } + + /* If extension exists replace it.. */ + if(extidx >= 0) { + extmp = sk_X509_EXTENSION_value(*x, extidx); + X509_EXTENSION_free(extmp); + if(!sk_X509_EXTENSION_set(*x, extidx, ext)) return -1; + return 1; + } + + if(!*x && !(*x = sk_X509_EXTENSION_new_null())) return -1; + if(!sk_X509_EXTENSION_push(*x, ext)) return -1; + + return 1; + + err: + if(!(flags & X509V3_ADD_SILENT)) + OPENSSL_PUT_ERROR(X509V3, errcode); + return 0; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_ncons.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_ncons.c new file mode 100644 index 00000000..19f5e949 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_ncons.c @@ -0,0 +1,510 @@ +/* v3_ncons.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2003 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include +#include + +#include +#include +#include +#include +#include +#include + + +static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); +static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, + void *a, BIO *bp, int ind); +static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method, + STACK_OF(GENERAL_SUBTREE) *trees, + BIO *bp, int ind, const char *name); +static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip); + +static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc); +static int nc_match_single(GENERAL_NAME *sub, GENERAL_NAME *gen); +static int nc_dn(X509_NAME *sub, X509_NAME *nm); +static int nc_dns(ASN1_IA5STRING *sub, ASN1_IA5STRING *dns); +static int nc_email(ASN1_IA5STRING *sub, ASN1_IA5STRING *eml); +static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base); + +const X509V3_EXT_METHOD v3_name_constraints = { + NID_name_constraints, 0, + ASN1_ITEM_ref(NAME_CONSTRAINTS), + 0,0,0,0, + 0,0, + 0, v2i_NAME_CONSTRAINTS, + i2r_NAME_CONSTRAINTS,0, + NULL +}; + +ASN1_SEQUENCE(GENERAL_SUBTREE) = { + ASN1_SIMPLE(GENERAL_SUBTREE, base, GENERAL_NAME), + ASN1_IMP_OPT(GENERAL_SUBTREE, minimum, ASN1_INTEGER, 0), + ASN1_IMP_OPT(GENERAL_SUBTREE, maximum, ASN1_INTEGER, 1) +} ASN1_SEQUENCE_END(GENERAL_SUBTREE) + +ASN1_SEQUENCE(NAME_CONSTRAINTS) = { + ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, permittedSubtrees, + GENERAL_SUBTREE, 0), + ASN1_IMP_SEQUENCE_OF_OPT(NAME_CONSTRAINTS, excludedSubtrees, + GENERAL_SUBTREE, 1), +} ASN1_SEQUENCE_END(NAME_CONSTRAINTS) + + +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE) +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS) + +static void *v2i_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) + { + size_t i; + CONF_VALUE tval, *val; + STACK_OF(GENERAL_SUBTREE) **ptree = NULL; + NAME_CONSTRAINTS *ncons = NULL; + GENERAL_SUBTREE *sub = NULL; + ncons = NAME_CONSTRAINTS_new(); + if (!ncons) + goto memerr; + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) + { + val = sk_CONF_VALUE_value(nval, i); + if (!strncmp(val->name, "permitted", 9) && val->name[9]) + { + ptree = &ncons->permittedSubtrees; + tval.name = val->name + 10; + } + else if (!strncmp(val->name, "excluded", 8) && val->name[8]) + { + ptree = &ncons->excludedSubtrees; + tval.name = val->name + 9; + } + else + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SYNTAX); + goto err; + } + tval.value = val->value; + sub = GENERAL_SUBTREE_new(); + if (!v2i_GENERAL_NAME_ex(sub->base, method, ctx, &tval, 1)) + goto err; + if (!*ptree) + *ptree = sk_GENERAL_SUBTREE_new_null(); + if (!*ptree || !sk_GENERAL_SUBTREE_push(*ptree, sub)) + goto memerr; + sub = NULL; + } + + return ncons; + + memerr: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + err: + if (ncons) + NAME_CONSTRAINTS_free(ncons); + if (sub) + GENERAL_SUBTREE_free(sub); + + return NULL; + } + + + + +static int i2r_NAME_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a, + BIO *bp, int ind) + { + NAME_CONSTRAINTS *ncons = a; + do_i2r_name_constraints(method, ncons->permittedSubtrees, + bp, ind, "Permitted"); + do_i2r_name_constraints(method, ncons->excludedSubtrees, + bp, ind, "Excluded"); + return 1; + } + +static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method, + STACK_OF(GENERAL_SUBTREE) *trees, + BIO *bp, int ind, const char *name) + { + GENERAL_SUBTREE *tree; + size_t i; + if (sk_GENERAL_SUBTREE_num(trees) > 0) + BIO_printf(bp, "%*s%s:\n", ind, "", name); + for(i = 0; i < sk_GENERAL_SUBTREE_num(trees); i++) + { + tree = sk_GENERAL_SUBTREE_value(trees, i); + BIO_printf(bp, "%*s", ind + 2, ""); + if (tree->base->type == GEN_IPADD) + print_nc_ipadd(bp, tree->base->d.ip); + else + GENERAL_NAME_print(bp, tree->base); + BIO_puts(bp, "\n"); + } + return 1; + } + +static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip) + { + int i, len; + unsigned char *p; + p = ip->data; + len = ip->length; + BIO_puts(bp, "IP:"); + if(len == 8) + { + BIO_printf(bp, "%d.%d.%d.%d/%d.%d.%d.%d", + p[0], p[1], p[2], p[3], + p[4], p[5], p[6], p[7]); + } + else if(len == 32) + { + for (i = 0; i < 16; i++) + { + BIO_printf(bp, "%X", p[0] << 8 | p[1]); + p += 2; + if (i == 7) + BIO_puts(bp, "/"); + else if (i != 15) + BIO_puts(bp, ":"); + } + } + else + BIO_printf(bp, "IP Address:"); + return 1; + } + +/* Check a certificate conforms to a specified set of constraints. + * Return values: + * X509_V_OK: All constraints obeyed. + * X509_V_ERR_PERMITTED_VIOLATION: Permitted subtree violation. + * X509_V_ERR_EXCLUDED_VIOLATION: Excluded subtree violation. + * X509_V_ERR_SUBTREE_MINMAX: Min or max values present and matching type. + * X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: Unsupported constraint type. + * X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: bad unsupported constraint syntax. + * X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: bad or unsupported syntax of name + + */ + +int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc) + { + int r, i; + size_t j; + X509_NAME *nm; + + nm = X509_get_subject_name(x); + + if (X509_NAME_entry_count(nm) > 0) + { + GENERAL_NAME gntmp; + gntmp.type = GEN_DIRNAME; + gntmp.d.directoryName = nm; + + r = nc_match(&gntmp, nc); + + if (r != X509_V_OK) + return r; + + gntmp.type = GEN_EMAIL; + + + /* Process any email address attributes in subject name */ + + for (i = -1;;) + { + X509_NAME_ENTRY *ne; + i = X509_NAME_get_index_by_NID(nm, + NID_pkcs9_emailAddress, + i); + if (i == -1) + break; + ne = X509_NAME_get_entry(nm, i); + gntmp.d.rfc822Name = X509_NAME_ENTRY_get_data(ne); + if (gntmp.d.rfc822Name->type != V_ASN1_IA5STRING) + return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; + + r = nc_match(&gntmp, nc); + + if (r != X509_V_OK) + return r; + } + + } + + for (j = 0; j < sk_GENERAL_NAME_num(x->altname); j++) + { + GENERAL_NAME *gen = sk_GENERAL_NAME_value(x->altname, j); + r = nc_match(gen, nc); + if (r != X509_V_OK) + return r; + } + + return X509_V_OK; + + } + +static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc) + { + GENERAL_SUBTREE *sub; + int r, match = 0; + size_t i; + + /* Permitted subtrees: if any subtrees exist of matching the type + * at least one subtree must match. + */ + + for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++) + { + sub = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i); + if (gen->type != sub->base->type) + continue; + if (sub->minimum || sub->maximum) + return X509_V_ERR_SUBTREE_MINMAX; + /* If we already have a match don't bother trying any more */ + if (match == 2) + continue; + if (match == 0) + match = 1; + r = nc_match_single(gen, sub->base); + if (r == X509_V_OK) + match = 2; + else if (r != X509_V_ERR_PERMITTED_VIOLATION) + return r; + } + + if (match == 1) + return X509_V_ERR_PERMITTED_VIOLATION; + + /* Excluded subtrees: must not match any of these */ + + for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->excludedSubtrees); i++) + { + sub = sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, i); + if (gen->type != sub->base->type) + continue; + if (sub->minimum || sub->maximum) + return X509_V_ERR_SUBTREE_MINMAX; + + r = nc_match_single(gen, sub->base); + if (r == X509_V_OK) + return X509_V_ERR_EXCLUDED_VIOLATION; + else if (r != X509_V_ERR_PERMITTED_VIOLATION) + return r; + + } + + return X509_V_OK; + + } + +static int nc_match_single(GENERAL_NAME *gen, GENERAL_NAME *base) + { + switch(base->type) + { + case GEN_DIRNAME: + return nc_dn(gen->d.directoryName, base->d.directoryName); + + case GEN_DNS: + return nc_dns(gen->d.dNSName, base->d.dNSName); + + case GEN_EMAIL: + return nc_email(gen->d.rfc822Name, base->d.rfc822Name); + + case GEN_URI: + return nc_uri(gen->d.uniformResourceIdentifier, + base->d.uniformResourceIdentifier); + + default: + return X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE; + } + + } + +/* directoryName name constraint matching. + * The canonical encoding of X509_NAME makes this comparison easy. It is + * matched if the subtree is a subset of the name. + */ + +static int nc_dn(X509_NAME *nm, X509_NAME *base) + { + /* Ensure canonical encodings are up to date. */ + if (nm->modified && i2d_X509_NAME(nm, NULL) < 0) + return X509_V_ERR_OUT_OF_MEM; + if (base->modified && i2d_X509_NAME(base, NULL) < 0) + return X509_V_ERR_OUT_OF_MEM; + if (base->canon_enclen > nm->canon_enclen) + return X509_V_ERR_PERMITTED_VIOLATION; + if (memcmp(base->canon_enc, nm->canon_enc, base->canon_enclen)) + return X509_V_ERR_PERMITTED_VIOLATION; + return X509_V_OK; + } + +static int nc_dns(ASN1_IA5STRING *dns, ASN1_IA5STRING *base) + { + char *baseptr = (char *)base->data; + char *dnsptr = (char *)dns->data; + /* Empty matches everything */ + if (!*baseptr) + return X509_V_OK; + /* Otherwise can add zero or more components on the left so + * compare RHS and if dns is longer and expect '.' as preceding + * character. + */ + if (dns->length > base->length) + { + dnsptr += dns->length - base->length; + if (*baseptr != '.' && dnsptr[-1] != '.') + return X509_V_ERR_PERMITTED_VIOLATION; + } + + if (OPENSSL_strcasecmp(baseptr, dnsptr)) + return X509_V_ERR_PERMITTED_VIOLATION; + + return X509_V_OK; + + } + +static int nc_email(ASN1_IA5STRING *eml, ASN1_IA5STRING *base) + { + const char *baseptr = (char *)base->data; + const char *emlptr = (char *)eml->data; + + const char *baseat = strchr(baseptr, '@'); + const char *emlat = strchr(emlptr, '@'); + if (!emlat) + return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; + /* Special case: inital '.' is RHS match */ + if (!baseat && (*baseptr == '.')) + { + if (eml->length > base->length) + { + emlptr += eml->length - base->length; + if (!OPENSSL_strcasecmp(baseptr, emlptr)) + return X509_V_OK; + } + return X509_V_ERR_PERMITTED_VIOLATION; + } + + /* If we have anything before '@' match local part */ + + if (baseat) + { + if (baseat != baseptr) + { + if ((baseat - baseptr) != (emlat - emlptr)) + return X509_V_ERR_PERMITTED_VIOLATION; + /* Case sensitive match of local part */ + if (strncmp(baseptr, emlptr, emlat - emlptr)) + return X509_V_ERR_PERMITTED_VIOLATION; + } + /* Position base after '@' */ + baseptr = baseat + 1; + } + emlptr = emlat + 1; + /* Just have hostname left to match: case insensitive */ + if (OPENSSL_strcasecmp(baseptr, emlptr)) + return X509_V_ERR_PERMITTED_VIOLATION; + + return X509_V_OK; + + } + +static int nc_uri(ASN1_IA5STRING *uri, ASN1_IA5STRING *base) + { + const char *baseptr = (char *)base->data; + const char *hostptr = (char *)uri->data; + const char *p = strchr(hostptr, ':'); + int hostlen; + /* Check for foo:// and skip past it */ + if (!p || (p[1] != '/') || (p[2] != '/')) + return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; + hostptr = p + 3; + + /* Determine length of hostname part of URI */ + + /* Look for a port indicator as end of hostname first */ + + p = strchr(hostptr, ':'); + /* Otherwise look for trailing slash */ + if (!p) + p = strchr(hostptr, '/'); + + if (!p) + hostlen = strlen(hostptr); + else + hostlen = p - hostptr; + + if (hostlen == 0) + return X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; + + /* Special case: inital '.' is RHS match */ + if (*baseptr == '.') + { + if (hostlen > base->length) + { + p = hostptr + hostlen - base->length; + if (!OPENSSL_strncasecmp(p, baseptr, base->length)) + return X509_V_OK; + } + return X509_V_ERR_PERMITTED_VIOLATION; + } + + if ((base->length != (int)hostlen) || OPENSSL_strncasecmp(hostptr, baseptr, hostlen)) + return X509_V_ERR_PERMITTED_VIOLATION; + + return X509_V_OK; + + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pci.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pci.c new file mode 100644 index 00000000..f19a37a8 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pci.c @@ -0,0 +1,335 @@ +/* v3_pci.c -*- mode:C; c-file-style: "eay" -*- */ +/* Contributed to the OpenSSL Project 2004 + * by Richard Levitte (richard@levitte.org) + */ +/* Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * 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. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS 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 INSTITUTE OR 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. + */ + +#include +#include + +#include +#include +#include +#include +#include + + +static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *ext, + BIO *out, int indent); +static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, char *str); + +const X509V3_EXT_METHOD v3_pci = + { NID_proxyCertInfo, 0, ASN1_ITEM_ref(PROXY_CERT_INFO_EXTENSION), + 0,0,0,0, + 0,0, + NULL, NULL, + (X509V3_EXT_I2R)i2r_pci, + (X509V3_EXT_R2I)r2i_pci, + NULL, + }; + +static int i2r_pci(X509V3_EXT_METHOD *method, PROXY_CERT_INFO_EXTENSION *pci, + BIO *out, int indent) + { + BIO_printf(out, "%*sPath Length Constraint: ", indent, ""); + if (pci->pcPathLengthConstraint) + i2a_ASN1_INTEGER(out, pci->pcPathLengthConstraint); + else + BIO_printf(out, "infinite"); + BIO_puts(out, "\n"); + BIO_printf(out, "%*sPolicy Language: ", indent, ""); + i2a_ASN1_OBJECT(out, pci->proxyPolicy->policyLanguage); + BIO_puts(out, "\n"); + if (pci->proxyPolicy->policy && pci->proxyPolicy->policy->data) + BIO_printf(out, "%*sPolicy Text: %s\n", indent, "", + pci->proxyPolicy->policy->data); + return 1; + } + +static int process_pci_value(CONF_VALUE *val, + ASN1_OBJECT **language, ASN1_INTEGER **pathlen, + ASN1_OCTET_STRING **policy) + { + int free_policy = 0; + + if (strcmp(val->name, "language") == 0) + { + if (*language) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED); + X509V3_conf_err(val); + return 0; + } + if (!(*language = OBJ_txt2obj(val->value, 0))) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER); + X509V3_conf_err(val); + return 0; + } + } + else if (strcmp(val->name, "pathlen") == 0) + { + if (*pathlen) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED); + X509V3_conf_err(val); + return 0; + } + if (!X509V3_get_value_int(val, pathlen)) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_POLICY_PATH_LENGTH); + X509V3_conf_err(val); + return 0; + } + } + else if (strcmp(val->name, "policy") == 0) + { + unsigned char *tmp_data = NULL; + long val_len; + if (!*policy) + { + *policy = ASN1_OCTET_STRING_new(); + if (!*policy) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + X509V3_conf_err(val); + return 0; + } + free_policy = 1; + } + if (strncmp(val->value, "hex:", 4) == 0) + { + unsigned char *tmp_data2 = + string_to_hex(val->value + 4, &val_len); + + if (!tmp_data2) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ILLEGAL_HEX_DIGIT); + X509V3_conf_err(val); + goto err; + } + + tmp_data = OPENSSL_realloc((*policy)->data, + (*policy)->length + val_len + 1); + if (tmp_data) + { + (*policy)->data = tmp_data; + memcpy(&(*policy)->data[(*policy)->length], + tmp_data2, val_len); + (*policy)->length += val_len; + (*policy)->data[(*policy)->length] = '\0'; + } + else + { + OPENSSL_free(tmp_data2); + /* realloc failure implies the original data space is b0rked too! */ + (*policy)->data = NULL; + (*policy)->length = 0; + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + X509V3_conf_err(val); + goto err; + } + OPENSSL_free(tmp_data2); + } + else if (strncmp(val->value, "file:", 5) == 0) + { + unsigned char buf[2048]; + int n; + BIO *b = BIO_new_file(val->value + 5, "r"); + if (!b) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_BIO_LIB); + X509V3_conf_err(val); + goto err; + } + while((n = BIO_read(b, buf, sizeof(buf))) > 0 + || (n == 0 && BIO_should_retry(b))) + { + if (!n) continue; + + tmp_data = OPENSSL_realloc((*policy)->data, + (*policy)->length + n + 1); + + if (!tmp_data) + break; + + (*policy)->data = tmp_data; + memcpy(&(*policy)->data[(*policy)->length], + buf, n); + (*policy)->length += n; + (*policy)->data[(*policy)->length] = '\0'; + } + BIO_free_all(b); + + if (n < 0) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_BIO_LIB); + X509V3_conf_err(val); + goto err; + } + } + else if (strncmp(val->value, "text:", 5) == 0) + { + val_len = strlen(val->value + 5); + tmp_data = OPENSSL_realloc((*policy)->data, + (*policy)->length + val_len + 1); + if (tmp_data) + { + (*policy)->data = tmp_data; + memcpy(&(*policy)->data[(*policy)->length], + val->value + 5, val_len); + (*policy)->length += val_len; + (*policy)->data[(*policy)->length] = '\0'; + } + else + { + /* realloc failure implies the original data space is b0rked too! */ + (*policy)->data = NULL; + (*policy)->length = 0; + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + X509V3_conf_err(val); + goto err; + } + } + else + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INCORRECT_POLICY_SYNTAX_TAG); + X509V3_conf_err(val); + goto err; + } + if (!tmp_data) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + X509V3_conf_err(val); + goto err; + } + } + return 1; +err: + if (free_policy) + { + ASN1_OCTET_STRING_free(*policy); + *policy = NULL; + } + return 0; + } + +static PROXY_CERT_INFO_EXTENSION *r2i_pci(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, char *value) + { + PROXY_CERT_INFO_EXTENSION *pci = NULL; + STACK_OF(CONF_VALUE) *vals; + ASN1_OBJECT *language = NULL; + ASN1_INTEGER *pathlen = NULL; + ASN1_OCTET_STRING *policy = NULL; + size_t i, j; + int nid; + + vals = X509V3_parse_list(value); + for (i = 0; i < sk_CONF_VALUE_num(vals); i++) + { + CONF_VALUE *cnf = sk_CONF_VALUE_value(vals, i); + if (!cnf->name || (*cnf->name != '@' && !cnf->value)) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_PROXY_POLICY_SETTING); + X509V3_conf_err(cnf); + goto err; + } + if (*cnf->name == '@') + { + STACK_OF(CONF_VALUE) *sect; + int success_p = 1; + + sect = X509V3_get_section(ctx, cnf->name + 1); + if (!sect) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_SECTION); + X509V3_conf_err(cnf); + goto err; + } + for (j = 0; success_p && j < sk_CONF_VALUE_num(sect); j++) + { + success_p = + process_pci_value(sk_CONF_VALUE_value(sect, j), + &language, &pathlen, &policy); + } + X509V3_section_free(ctx, sect); + if (!success_p) + goto err; + } + else + { + if (!process_pci_value(cnf, + &language, &pathlen, &policy)) + { + X509V3_conf_err(cnf); + goto err; + } + } + } + + /* Language is mandatory */ + if (!language) + { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED); + goto err; + } + nid = OBJ_obj2nid(language); + if ((nid == NID_Independent || nid == NID_id_ppl_inheritAll) && policy) + { + OPENSSL_PUT_ERROR(X509V3, + X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY); + goto err; + } + + pci = PROXY_CERT_INFO_EXTENSION_new(); + if (!pci) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + + pci->proxyPolicy->policyLanguage = language; language = NULL; + pci->proxyPolicy->policy = policy; policy = NULL; + pci->pcPathLengthConstraint = pathlen; pathlen = NULL; + goto end; +err: + if (language) { ASN1_OBJECT_free(language); language = NULL; } + if (pathlen) { ASN1_INTEGER_free(pathlen); pathlen = NULL; } + if (policy) { ASN1_OCTET_STRING_free(policy); policy = NULL; } + if (pci) { PROXY_CERT_INFO_EXTENSION_free(pci); pci = NULL; } +end: + sk_CONF_VALUE_pop_free(vals, X509V3_conf_free); + return pci; + } diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pcia.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pcia.c new file mode 100644 index 00000000..e3e3192f --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pcia.c @@ -0,0 +1,56 @@ +/* v3_pcia.c -*- mode:C; c-file-style: "eay" -*- */ +/* Contributed to the OpenSSL Project 2004 + * by Richard Levitte (richard@levitte.org) + */ +/* Copyright (c) 2004 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * 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. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS 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 INSTITUTE OR 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. + */ + +#include +#include +#include + + +ASN1_SEQUENCE(PROXY_POLICY) = + { + ASN1_SIMPLE(PROXY_POLICY,policyLanguage,ASN1_OBJECT), + ASN1_OPT(PROXY_POLICY,policy,ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(PROXY_POLICY) + +IMPLEMENT_ASN1_FUNCTIONS(PROXY_POLICY) + +ASN1_SEQUENCE(PROXY_CERT_INFO_EXTENSION) = + { + ASN1_OPT(PROXY_CERT_INFO_EXTENSION,pcPathLengthConstraint,ASN1_INTEGER), + ASN1_SIMPLE(PROXY_CERT_INFO_EXTENSION,proxyPolicy,PROXY_POLICY) +} ASN1_SEQUENCE_END(PROXY_CERT_INFO_EXTENSION) + +IMPLEMENT_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION) diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pcons.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pcons.c new file mode 100644 index 00000000..b7522904 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pcons.c @@ -0,0 +1,142 @@ +/* v3_pcons.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2003 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include +#include + +#include +#include +#include +#include +#include +#include + + +static STACK_OF(CONF_VALUE) * +i2v_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *bcons, + STACK_OF(CONF_VALUE) *extlist); +static void *v2i_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *values); + +const X509V3_EXT_METHOD v3_policy_constraints = { +NID_policy_constraints, 0, +ASN1_ITEM_ref(POLICY_CONSTRAINTS), +0,0,0,0, +0,0, +i2v_POLICY_CONSTRAINTS, +v2i_POLICY_CONSTRAINTS, +NULL,NULL, +NULL +}; + +ASN1_SEQUENCE(POLICY_CONSTRAINTS) = { + ASN1_IMP_OPT(POLICY_CONSTRAINTS, requireExplicitPolicy, ASN1_INTEGER,0), + ASN1_IMP_OPT(POLICY_CONSTRAINTS, inhibitPolicyMapping, ASN1_INTEGER,1) +} ASN1_SEQUENCE_END(POLICY_CONSTRAINTS) + +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(POLICY_CONSTRAINTS) + + +static STACK_OF(CONF_VALUE) * +i2v_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method, void *a, + STACK_OF(CONF_VALUE) *extlist) +{ + POLICY_CONSTRAINTS *pcons = a; + X509V3_add_value_int("Require Explicit Policy", + pcons->requireExplicitPolicy, &extlist); + X509V3_add_value_int("Inhibit Policy Mapping", + pcons->inhibitPolicyMapping, &extlist); + return extlist; +} + +static void *v2i_POLICY_CONSTRAINTS(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *values) +{ + POLICY_CONSTRAINTS *pcons=NULL; + CONF_VALUE *val; + size_t i; + if(!(pcons = POLICY_CONSTRAINTS_new())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + for(i = 0; i < sk_CONF_VALUE_num(values); i++) { + val = sk_CONF_VALUE_value(values, i); + if(!strcmp(val->name, "requireExplicitPolicy")) { + if(!X509V3_get_value_int(val, + &pcons->requireExplicitPolicy)) goto err; + } else if(!strcmp(val->name, "inhibitPolicyMapping")) { + if(!X509V3_get_value_int(val, + &pcons->inhibitPolicyMapping)) goto err; + } else { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NAME); + X509V3_conf_err(val); + goto err; + } + } + if (!pcons->inhibitPolicyMapping && !pcons->requireExplicitPolicy) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ILLEGAL_EMPTY_EXTENSION); + goto err; + } + + return pcons; + err: + POLICY_CONSTRAINTS_free(pcons); + return NULL; +} + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pku.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pku.c new file mode 100644 index 00000000..445eda67 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pku.c @@ -0,0 +1,109 @@ +/* v3_pku.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include +#include +#include +#include +#include + + +static int i2r_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method, PKEY_USAGE_PERIOD *usage, BIO *out, int indent); +/* +static PKEY_USAGE_PERIOD *v2i_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *values); +*/ +const X509V3_EXT_METHOD v3_pkey_usage_period = { +NID_private_key_usage_period, 0, ASN1_ITEM_ref(PKEY_USAGE_PERIOD), +0,0,0,0, +0,0,0,0, +(X509V3_EXT_I2R)i2r_PKEY_USAGE_PERIOD, NULL, +NULL +}; + +ASN1_SEQUENCE(PKEY_USAGE_PERIOD) = { + ASN1_IMP_OPT(PKEY_USAGE_PERIOD, notBefore, ASN1_GENERALIZEDTIME, 0), + ASN1_IMP_OPT(PKEY_USAGE_PERIOD, notAfter, ASN1_GENERALIZEDTIME, 1) +} ASN1_SEQUENCE_END(PKEY_USAGE_PERIOD) + +IMPLEMENT_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD) + +static int i2r_PKEY_USAGE_PERIOD(X509V3_EXT_METHOD *method, + PKEY_USAGE_PERIOD *usage, BIO *out, int indent) +{ + BIO_printf(out, "%*s", indent, ""); + if(usage->notBefore) { + BIO_write(out, "Not Before: ", 12); + ASN1_GENERALIZEDTIME_print(out, usage->notBefore); + if(usage->notAfter) BIO_write(out, ", ", 2); + } + if(usage->notAfter) { + BIO_write(out, "Not After: ", 11); + ASN1_GENERALIZEDTIME_print(out, usage->notAfter); + } + return 1; +} + +/* +static PKEY_USAGE_PERIOD *v2i_PKEY_USAGE_PERIOD(method, ctx, values) +X509V3_EXT_METHOD *method; +X509V3_CTX *ctx; +STACK_OF(CONF_VALUE) *values; +{ +return NULL; +} +*/ diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pmaps.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pmaps.c new file mode 100644 index 00000000..5b909773 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_pmaps.c @@ -0,0 +1,156 @@ +/* v3_pmaps.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 2003 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include + +#include +#include +#include +#include +#include + + +static void *v2i_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); +static STACK_OF(CONF_VALUE) * +i2v_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method, void *pmps, + STACK_OF(CONF_VALUE) *extlist); + +const X509V3_EXT_METHOD v3_policy_mappings = { + NID_policy_mappings, 0, + ASN1_ITEM_ref(POLICY_MAPPINGS), + 0,0,0,0, + 0,0, + i2v_POLICY_MAPPINGS, + v2i_POLICY_MAPPINGS, + 0,0, + NULL +}; + +ASN1_SEQUENCE(POLICY_MAPPING) = { + ASN1_SIMPLE(POLICY_MAPPING, issuerDomainPolicy, ASN1_OBJECT), + ASN1_SIMPLE(POLICY_MAPPING, subjectDomainPolicy, ASN1_OBJECT) +} ASN1_SEQUENCE_END(POLICY_MAPPING) + +ASN1_ITEM_TEMPLATE(POLICY_MAPPINGS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, POLICY_MAPPINGS, + POLICY_MAPPING) +ASN1_ITEM_TEMPLATE_END(POLICY_MAPPINGS) + +IMPLEMENT_ASN1_ALLOC_FUNCTIONS(POLICY_MAPPING) + + +static STACK_OF(CONF_VALUE) * +i2v_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method, void *a, + STACK_OF(CONF_VALUE) *ext_list) +{ + POLICY_MAPPINGS *pmaps = a; + POLICY_MAPPING *pmap; + size_t i; + char obj_tmp1[80]; + char obj_tmp2[80]; + for(i = 0; i < sk_POLICY_MAPPING_num(pmaps); i++) { + pmap = sk_POLICY_MAPPING_value(pmaps, i); + i2t_ASN1_OBJECT(obj_tmp1, 80, pmap->issuerDomainPolicy); + i2t_ASN1_OBJECT(obj_tmp2, 80, pmap->subjectDomainPolicy); + X509V3_add_value(obj_tmp1, obj_tmp2, &ext_list); + } + return ext_list; +} + +static void *v2i_POLICY_MAPPINGS(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval) +{ + POLICY_MAPPINGS *pmaps; + POLICY_MAPPING *pmap; + ASN1_OBJECT *obj1, *obj2; + CONF_VALUE *val; + size_t i; + + if(!(pmaps = sk_POLICY_MAPPING_new_null())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + val = sk_CONF_VALUE_value(nval, i); + if(!val->value || !val->name) { + sk_POLICY_MAPPING_pop_free(pmaps, POLICY_MAPPING_free); + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER); + X509V3_conf_err(val); + return NULL; + } + obj1 = OBJ_txt2obj(val->name, 0); + obj2 = OBJ_txt2obj(val->value, 0); + if(!obj1 || !obj2) { + sk_POLICY_MAPPING_pop_free(pmaps, POLICY_MAPPING_free); + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_OBJECT_IDENTIFIER); + X509V3_conf_err(val); + return NULL; + } + pmap = POLICY_MAPPING_new(); + if (!pmap) { + sk_POLICY_MAPPING_pop_free(pmaps, POLICY_MAPPING_free); + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + pmap->issuerDomainPolicy = obj1; + pmap->subjectDomainPolicy = obj2; + sk_POLICY_MAPPING_push(pmaps, pmap); + } + return pmaps; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_prn.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_prn.c new file mode 100644 index 00000000..87aef4d4 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_prn.c @@ -0,0 +1,207 @@ +/* v3_prn.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +/* X509 v3 extension utilities */ + +#include + +#include +#include +#include +#include + + +/* Extension printing routines */ + +static int unknown_ext_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent, int supported); + +/* Print out a name+value stack */ + +void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent, int ml) +{ + size_t i; + CONF_VALUE *nval; + if(!val) return; + if(!ml || !sk_CONF_VALUE_num(val)) { + BIO_printf(out, "%*s", indent, ""); + if(!sk_CONF_VALUE_num(val)) BIO_puts(out, "\n"); + } + for(i = 0; i < sk_CONF_VALUE_num(val); i++) { + if(ml) BIO_printf(out, "%*s", indent, ""); + else if(i > 0) BIO_printf(out, ", "); + nval = sk_CONF_VALUE_value(val, i); + if(!nval->name) BIO_puts(out, nval->value); + else if(!nval->value) BIO_puts(out, nval->name); + else BIO_printf(out, "%s:%s", nval->name, nval->value); + if(ml) BIO_puts(out, "\n"); + } +} + +/* Main routine: print out a general extension */ + +int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent) +{ + void *ext_str = NULL; + char *value = NULL; + const unsigned char *p; + const X509V3_EXT_METHOD *method; + STACK_OF(CONF_VALUE) *nval = NULL; + int ok = 1; + + if(!(method = X509V3_EXT_get(ext))) + return unknown_ext_print(out, ext, flag, indent, 0); + p = ext->value->data; + if(method->it) ext_str = ASN1_item_d2i(NULL, &p, ext->value->length, ASN1_ITEM_ptr(method->it)); + else ext_str = method->d2i(NULL, &p, ext->value->length); + + if(!ext_str) return unknown_ext_print(out, ext, flag, indent, 1); + + if(method->i2s) { + if(!(value = method->i2s(method, ext_str))) { + ok = 0; + goto err; + } + BIO_printf(out, "%*s%s", indent, "", value); + } else if(method->i2v) { + if(!(nval = method->i2v(method, ext_str, NULL))) { + ok = 0; + goto err; + } + X509V3_EXT_val_prn(out, nval, indent, + method->ext_flags & X509V3_EXT_MULTILINE); + } else if(method->i2r) { + if(!method->i2r(method, ext_str, out, indent)) ok = 0; + } else ok = 0; + + err: + sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); + if(value) OPENSSL_free(value); + if(method->it) ASN1_item_free(ext_str, ASN1_ITEM_ptr(method->it)); + else method->ext_free(ext_str); + return ok; +} + +int X509V3_extensions_print(BIO *bp, const char *title, STACK_OF(X509_EXTENSION) *exts, unsigned long flag, int indent) +{ + size_t i; + int j; + + if(sk_X509_EXTENSION_num(exts) <= 0) return 1; + + if(title) + { + BIO_printf(bp,"%*s%s:\n",indent, "", title); + indent += 4; + } + + for (i=0; ivalue); + } + if (BIO_write(bp,"\n",1) <= 0) return 0; + } + return 1; +} + +static int unknown_ext_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent, int supported) +{ + switch(flag & X509V3_EXT_UNKNOWN_MASK) { + + case X509V3_EXT_DEFAULT: + return 0; + + case X509V3_EXT_ERROR_UNKNOWN: + if(supported) + BIO_printf(out, "%*s", indent, ""); + else + BIO_printf(out, "%*s", indent, ""); + return 1; + + case X509V3_EXT_PARSE_UNKNOWN: + return ASN1_parse_dump(out, + ext->value->data, ext->value->length, indent, -1); + case X509V3_EXT_DUMP_UNKNOWN: + return BIO_hexdump(out, ext->value->data, ext->value->length, indent); + + default: + return 1; + } +} + + +#ifndef OPENSSL_NO_FP_API +int X509V3_EXT_print_fp(FILE *fp, X509_EXTENSION *ext, int flag, int indent) +{ + BIO *bio_tmp; + int ret; + if(!(bio_tmp = BIO_new_fp(fp, BIO_NOCLOSE))) return 0; + ret = X509V3_EXT_print(bio_tmp, ext, flag, indent); + BIO_free(bio_tmp); + return ret; +} +#endif diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_purp.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_purp.c new file mode 100644 index 00000000..f53c0f11 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_purp.c @@ -0,0 +1,804 @@ +/* v3_purp.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2001. + */ +/* ==================================================================== + * Copyright (c) 1999-2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../internal.h" + + +static void x509v3_cache_extensions(X509 *x); + +static int check_ssl_ca(const X509 *x); +static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, int ca); +static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca); +static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca); +static int purpose_smime(const X509 *x, int ca); +static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int ca); +static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca); +static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca); +static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, int ca); +static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca); +static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca); + +static int xp_cmp(const X509_PURPOSE **a, const X509_PURPOSE **b); +static void xptable_free(X509_PURPOSE *p); + +static X509_PURPOSE xstandard[] = { + {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0, check_purpose_ssl_client, (char *) "SSL client", (char *) "sslclient", NULL}, + {X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ssl_server, (char *) "SSL server", (char *) "sslserver", NULL}, + {X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ns_ssl_server, (char *) "Netscape SSL server", (char *) "nssslserver", NULL}, + {X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign, (char *) "S/MIME signing", (char *) "smimesign", NULL}, + {X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0, check_purpose_smime_encrypt, (char *) "S/MIME encryption", (char *) "smimeencrypt", NULL}, + {X509_PURPOSE_CRL_SIGN, X509_TRUST_COMPAT, 0, check_purpose_crl_sign, (char *) "CRL signing", (char *) "crlsign", NULL}, + {X509_PURPOSE_ANY, X509_TRUST_DEFAULT, 0, no_check, (char *) "Any Purpose", (char *) "any", NULL}, + {X509_PURPOSE_OCSP_HELPER, X509_TRUST_COMPAT, 0, ocsp_helper, (char *) "OCSP helper", (char *) "ocsphelper", NULL}, + {X509_PURPOSE_TIMESTAMP_SIGN, X509_TRUST_TSA, 0, check_purpose_timestamp_sign, (char *) "Time Stamp signing", (char *) "timestampsign", NULL}, +}; + +#define X509_PURPOSE_COUNT (sizeof(xstandard)/sizeof(X509_PURPOSE)) + +static STACK_OF(X509_PURPOSE) *xptable = NULL; + +static int xp_cmp(const X509_PURPOSE **a, const X509_PURPOSE **b) +{ + return (*a)->purpose - (*b)->purpose; +} + +/* As much as I'd like to make X509_check_purpose use a "const" X509* + * I really can't because it does recalculate hashes and do other non-const + * things. */ +int X509_check_purpose(X509 *x, int id, int ca) +{ + int idx; + const X509_PURPOSE *pt; + if(!(x->ex_flags & EXFLAG_SET)) { + x509v3_cache_extensions(x); + } + if(id == -1) return 1; + idx = X509_PURPOSE_get_by_id(id); + if(idx == -1) return -1; + pt = X509_PURPOSE_get0(idx); + return pt->check_purpose(pt, x, ca); +} + +int X509_PURPOSE_set(int *p, int purpose) +{ + if(X509_PURPOSE_get_by_id(purpose) == -1) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_PURPOSE); + return 0; + } + *p = purpose; + return 1; +} + +int X509_PURPOSE_get_count(void) +{ + if(!xptable) return X509_PURPOSE_COUNT; + return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT; +} + +X509_PURPOSE * X509_PURPOSE_get0(int idx) +{ + if(idx < 0) return NULL; + if(idx < (int)X509_PURPOSE_COUNT) return xstandard + idx; + return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT); +} + +int X509_PURPOSE_get_by_sname(char *sname) +{ + int i; + X509_PURPOSE *xptmp; + for(i = 0; i < X509_PURPOSE_get_count(); i++) { + xptmp = X509_PURPOSE_get0(i); + if(!strcmp(xptmp->sname, sname)) return i; + } + return -1; +} + +int X509_PURPOSE_get_by_id(int purpose) +{ + X509_PURPOSE tmp; + size_t idx; + + if((purpose >= X509_PURPOSE_MIN) && (purpose <= X509_PURPOSE_MAX)) + return purpose - X509_PURPOSE_MIN; + tmp.purpose = purpose; + if(!xptable) return -1; + + if (!sk_X509_PURPOSE_find(xptable, &idx, &tmp)) + return -1; + return idx + X509_PURPOSE_COUNT; +} + +int X509_PURPOSE_add(int id, int trust, int flags, + int (*ck)(const X509_PURPOSE *, const X509 *, int), + char *name, char *sname, void *arg) +{ + int idx; + X509_PURPOSE *ptmp; + char *name_dup, *sname_dup; + + /* This is set according to what we change: application can't set it */ + flags &= ~X509_PURPOSE_DYNAMIC; + /* This will always be set for application modified trust entries */ + flags |= X509_PURPOSE_DYNAMIC_NAME; + /* Get existing entry if any */ + idx = X509_PURPOSE_get_by_id(id); + /* Need a new entry */ + if(idx == -1) { + if(!(ptmp = OPENSSL_malloc(sizeof(X509_PURPOSE)))) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return 0; + } + ptmp->flags = X509_PURPOSE_DYNAMIC; + } else ptmp = X509_PURPOSE_get0(idx); + + /* Duplicate the supplied names. */ + name_dup = BUF_strdup(name); + sname_dup = BUF_strdup(sname); + if (name_dup == NULL || sname_dup == NULL) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + if (name_dup != NULL) + OPENSSL_free(name_dup); + if (sname_dup != NULL) + OPENSSL_free(sname_dup); + if (idx == -1) + OPENSSL_free(ptmp); + return 0; + } + + /* OPENSSL_free existing name if dynamic */ + if(ptmp->flags & X509_PURPOSE_DYNAMIC_NAME) { + OPENSSL_free(ptmp->name); + OPENSSL_free(ptmp->sname); + } + /* dup supplied name */ + ptmp->name = name_dup; + ptmp->sname = sname_dup; + /* Keep the dynamic flag of existing entry */ + ptmp->flags &= X509_PURPOSE_DYNAMIC; + /* Set all other flags */ + ptmp->flags |= flags; + + ptmp->purpose = id; + ptmp->trust = trust; + ptmp->check_purpose = ck; + ptmp->usr_data = arg; + + /* If its a new entry manage the dynamic table */ + if(idx == -1) { + if(!xptable && !(xptable = sk_X509_PURPOSE_new(xp_cmp))) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + xptable_free(ptmp); + return 0; + } + if (!sk_X509_PURPOSE_push(xptable, ptmp)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + xptable_free(ptmp); + return 0; + } + } + return 1; +} + +static void xptable_free(X509_PURPOSE *p) + { + if(!p) return; + if (p->flags & X509_PURPOSE_DYNAMIC) + { + if (p->flags & X509_PURPOSE_DYNAMIC_NAME) { + OPENSSL_free(p->name); + OPENSSL_free(p->sname); + } + OPENSSL_free(p); + } + } + +void X509_PURPOSE_cleanup(void) +{ + unsigned int i; + sk_X509_PURPOSE_pop_free(xptable, xptable_free); + for(i = 0; i < X509_PURPOSE_COUNT; i++) xptable_free(xstandard + i); + xptable = NULL; +} + +int X509_PURPOSE_get_id(X509_PURPOSE *xp) +{ + return xp->purpose; +} + +char *X509_PURPOSE_get0_name(X509_PURPOSE *xp) +{ + return xp->name; +} + +char *X509_PURPOSE_get0_sname(X509_PURPOSE *xp) +{ + return xp->sname; +} + +int X509_PURPOSE_get_trust(X509_PURPOSE *xp) +{ + return xp->trust; +} + +static int nid_cmp(const void *void_a, const void *void_b) + { + const int *a = void_a, *b = void_b; + + return *a - *b; + } + +int X509_supported_extension(X509_EXTENSION *ex) + { + /* This table is a list of the NIDs of supported extensions: + * that is those which are used by the verify process. If + * an extension is critical and doesn't appear in this list + * then the verify process will normally reject the certificate. + * The list must be kept in numerical order because it will be + * searched using bsearch. + */ + + static const int supported_nids[] = { + NID_netscape_cert_type, /* 71 */ + NID_key_usage, /* 83 */ + NID_subject_alt_name, /* 85 */ + NID_basic_constraints, /* 87 */ + NID_certificate_policies, /* 89 */ + NID_ext_key_usage, /* 126 */ + NID_policy_constraints, /* 401 */ + NID_proxyCertInfo, /* 663 */ + NID_name_constraints, /* 666 */ + NID_policy_mappings, /* 747 */ + NID_inhibit_any_policy /* 748 */ + }; + + int ex_nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex)); + + if (ex_nid == NID_undef) + return 0; + + if (bsearch(&ex_nid, supported_nids, sizeof(supported_nids)/sizeof(int), sizeof(int), nid_cmp) != NULL) + return 1; + return 0; + } + +static void setup_dp(X509 *x, DIST_POINT *dp) + { + X509_NAME *iname = NULL; + size_t i; + if (dp->reasons) + { + if (dp->reasons->length > 0) + dp->dp_reasons = dp->reasons->data[0]; + if (dp->reasons->length > 1) + dp->dp_reasons |= (dp->reasons->data[1] << 8); + dp->dp_reasons &= CRLDP_ALL_REASONS; + } + else + dp->dp_reasons = CRLDP_ALL_REASONS; + if (!dp->distpoint || (dp->distpoint->type != 1)) + return; + for (i = 0; i < sk_GENERAL_NAME_num(dp->CRLissuer); i++) + { + GENERAL_NAME *gen = sk_GENERAL_NAME_value(dp->CRLissuer, i); + if (gen->type == GEN_DIRNAME) + { + iname = gen->d.directoryName; + break; + } + } + if (!iname) + iname = X509_get_issuer_name(x); + + DIST_POINT_set_dpname(dp->distpoint, iname); + + } + +static void setup_crldp(X509 *x) + { + size_t i; + x->crldp = X509_get_ext_d2i(x, NID_crl_distribution_points, NULL, NULL); + for (i = 0; i < sk_DIST_POINT_num(x->crldp); i++) + setup_dp(x, sk_DIST_POINT_value(x->crldp, i)); + } + +/* g_x509_cache_extensions_lock is used to protect against concurrent calls to + * |x509v3_cache_extensions|. Ideally this would be done with a |CRYPTO_once_t| + * in the |X509| structure, but |CRYPTO_once_t| isn't public. + * + * Note: it's not entirely clear whether this lock is needed. Not all paths to + * this function took a lock in OpenSSL. */ +static struct CRYPTO_STATIC_MUTEX g_x509_cache_extensions_lock = + CRYPTO_STATIC_MUTEX_INIT; + +static void x509v3_cache_extensions(X509 *x) +{ + BASIC_CONSTRAINTS *bs; + PROXY_CERT_INFO_EXTENSION *pci; + ASN1_BIT_STRING *usage; + ASN1_BIT_STRING *ns; + EXTENDED_KEY_USAGE *extusage; + X509_EXTENSION *ex; + size_t i; + int j; + + CRYPTO_STATIC_MUTEX_lock_write(&g_x509_cache_extensions_lock); + + if(x->ex_flags & EXFLAG_SET) + { + CRYPTO_STATIC_MUTEX_unlock(&g_x509_cache_extensions_lock); + return; + } + + X509_digest(x, EVP_sha1(), x->sha1_hash, NULL); + /* V1 should mean no extensions ... */ + if(!X509_get_version(x)) x->ex_flags |= EXFLAG_V1; + /* Handle basic constraints */ + if((bs=X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL))) { + if(bs->ca) x->ex_flags |= EXFLAG_CA; + if(bs->pathlen) { + if((bs->pathlen->type == V_ASN1_NEG_INTEGER) + || !bs->ca) { + x->ex_flags |= EXFLAG_INVALID; + x->ex_pathlen = 0; + } else x->ex_pathlen = ASN1_INTEGER_get(bs->pathlen); + } else x->ex_pathlen = -1; + BASIC_CONSTRAINTS_free(bs); + x->ex_flags |= EXFLAG_BCONS; + } + /* Handle proxy certificates */ + if((pci=X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) { + if (x->ex_flags & EXFLAG_CA + || X509_get_ext_by_NID(x, NID_subject_alt_name, -1) >= 0 + || X509_get_ext_by_NID(x, NID_issuer_alt_name, -1) >= 0) { + x->ex_flags |= EXFLAG_INVALID; + } + if (pci->pcPathLengthConstraint) { + x->ex_pcpathlen = + ASN1_INTEGER_get(pci->pcPathLengthConstraint); + } else x->ex_pcpathlen = -1; + PROXY_CERT_INFO_EXTENSION_free(pci); + x->ex_flags |= EXFLAG_PROXY; + } + /* Handle key usage */ + if((usage=X509_get_ext_d2i(x, NID_key_usage, NULL, NULL))) { + if(usage->length > 0) { + x->ex_kusage = usage->data[0]; + if(usage->length > 1) + x->ex_kusage |= usage->data[1] << 8; + } else x->ex_kusage = 0; + x->ex_flags |= EXFLAG_KUSAGE; + ASN1_BIT_STRING_free(usage); + } + x->ex_xkusage = 0; + if((extusage=X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL))) { + x->ex_flags |= EXFLAG_XKUSAGE; + for(i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) { + switch(OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage,i))) { + case NID_server_auth: + x->ex_xkusage |= XKU_SSL_SERVER; + break; + + case NID_client_auth: + x->ex_xkusage |= XKU_SSL_CLIENT; + break; + + case NID_email_protect: + x->ex_xkusage |= XKU_SMIME; + break; + + case NID_code_sign: + x->ex_xkusage |= XKU_CODE_SIGN; + break; + + case NID_ms_sgc: + case NID_ns_sgc: + x->ex_xkusage |= XKU_SGC; + break; + + case NID_OCSP_sign: + x->ex_xkusage |= XKU_OCSP_SIGN; + break; + + case NID_time_stamp: + x->ex_xkusage |= XKU_TIMESTAMP; + break; + + case NID_dvcs: + x->ex_xkusage |= XKU_DVCS; + break; + + case NID_anyExtendedKeyUsage: + x->ex_xkusage |= XKU_ANYEKU; + break; + } + } + sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free); + } + + if((ns=X509_get_ext_d2i(x, NID_netscape_cert_type, NULL, NULL))) { + if(ns->length > 0) x->ex_nscert = ns->data[0]; + else x->ex_nscert = 0; + x->ex_flags |= EXFLAG_NSCERT; + ASN1_BIT_STRING_free(ns); + } + x->skid =X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL); + x->akid =X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL); + /* Does subject name match issuer ? */ + if(!X509_NAME_cmp(X509_get_subject_name(x), X509_get_issuer_name(x))) + { + x->ex_flags |= EXFLAG_SI; + /* If SKID matches AKID also indicate self signed */ + if (X509_check_akid(x, x->akid) == X509_V_OK) + x->ex_flags |= EXFLAG_SS; + } + x->altname = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); + x->nc = X509_get_ext_d2i(x, NID_name_constraints, &j, NULL); + if (!x->nc && (j != -1)) + x->ex_flags |= EXFLAG_INVALID; + setup_crldp(x); + + for (j = 0; j < X509_get_ext_count(x); j++) + { + ex = X509_get_ext(x, j); + if (OBJ_obj2nid(X509_EXTENSION_get_object(ex)) + == NID_freshest_crl) + x->ex_flags |= EXFLAG_FRESHEST; + if (!X509_EXTENSION_get_critical(ex)) + continue; + if (!X509_supported_extension(ex)) + { + x->ex_flags |= EXFLAG_CRITICAL; + break; + } + } + x->ex_flags |= EXFLAG_SET; + + CRYPTO_STATIC_MUTEX_unlock(&g_x509_cache_extensions_lock); +} + +/* CA checks common to all purposes + * return codes: + * 0 not a CA + * 1 is a CA + * 2 basicConstraints absent so "maybe" a CA + * 3 basicConstraints absent but self signed V1. + * 4 basicConstraints absent but keyUsage present and keyCertSign asserted. + */ + +#define V1_ROOT (EXFLAG_V1|EXFLAG_SS) +#define ku_reject(x, usage) \ + (((x)->ex_flags & EXFLAG_KUSAGE) && !((x)->ex_kusage & (usage))) +#define xku_reject(x, usage) \ + (((x)->ex_flags & EXFLAG_XKUSAGE) && !((x)->ex_xkusage & (usage))) +#define ns_reject(x, usage) \ + (((x)->ex_flags & EXFLAG_NSCERT) && !((x)->ex_nscert & (usage))) + +static int check_ca(const X509 *x) +{ + /* keyUsage if present should allow cert signing */ + if(ku_reject(x, KU_KEY_CERT_SIGN)) return 0; + if(x->ex_flags & EXFLAG_BCONS) { + if(x->ex_flags & EXFLAG_CA) return 1; + /* If basicConstraints says not a CA then say so */ + else return 0; + } else { + /* we support V1 roots for... uh, I don't really know why. */ + if((x->ex_flags & V1_ROOT) == V1_ROOT) return 3; + /* If key usage present it must have certSign so tolerate it */ + else if (x->ex_flags & EXFLAG_KUSAGE) return 4; + /* Older certificates could have Netscape-specific CA types */ + else if (x->ex_flags & EXFLAG_NSCERT + && x->ex_nscert & NS_ANY_CA) return 5; + /* can this still be regarded a CA certificate? I doubt it */ + return 0; + } +} + +int X509_check_ca(X509 *x) +{ + if(!(x->ex_flags & EXFLAG_SET)) { + x509v3_cache_extensions(x); + } + + return check_ca(x); +} + +/* Check SSL CA: common checks for SSL client and server */ +static int check_ssl_ca(const X509 *x) +{ + int ca_ret; + ca_ret = check_ca(x); + if(!ca_ret) return 0; + /* check nsCertType if present */ + if(ca_ret != 5 || x->ex_nscert & NS_SSL_CA) return ca_ret; + else return 0; +} + + +static int check_purpose_ssl_client(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + if(xku_reject(x,XKU_SSL_CLIENT)) return 0; + if(ca) return check_ssl_ca(x); + /* We need to do digital signatures or key agreement */ + if(ku_reject(x,KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT)) return 0; + /* nsCertType if present should allow SSL client use */ + if(ns_reject(x, NS_SSL_CLIENT)) return 0; + return 1; +} +/* Key usage needed for TLS/SSL server: digital signature, encipherment or + * key agreement. The ssl code can check this more thoroughly for individual + * key types. + */ +#define KU_TLS \ + KU_DIGITAL_SIGNATURE|KU_KEY_ENCIPHERMENT|KU_KEY_AGREEMENT + +static int check_purpose_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + if(xku_reject(x,XKU_SSL_SERVER|XKU_SGC)) return 0; + if(ca) return check_ssl_ca(x); + + if(ns_reject(x, NS_SSL_SERVER)) return 0; + if(ku_reject(x, KU_TLS)) return 0; + + return 1; + +} + +static int check_purpose_ns_ssl_server(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + int ret; + ret = check_purpose_ssl_server(xp, x, ca); + if(!ret || ca) return ret; + /* We need to encipher or Netscape complains */ + if(ku_reject(x, KU_KEY_ENCIPHERMENT)) return 0; + return ret; +} + +/* common S/MIME checks */ +static int purpose_smime(const X509 *x, int ca) +{ + if(xku_reject(x,XKU_SMIME)) return 0; + if(ca) { + int ca_ret; + ca_ret = check_ca(x); + if(!ca_ret) return 0; + /* check nsCertType if present */ + if(ca_ret != 5 || x->ex_nscert & NS_SMIME_CA) return ca_ret; + else return 0; + } + if(x->ex_flags & EXFLAG_NSCERT) { + if(x->ex_nscert & NS_SMIME) return 1; + /* Workaround for some buggy certificates */ + if(x->ex_nscert & NS_SSL_CLIENT) return 2; + return 0; + } + return 1; +} + +static int check_purpose_smime_sign(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + int ret; + ret = purpose_smime(x, ca); + if(!ret || ca) return ret; + if(ku_reject(x, KU_DIGITAL_SIGNATURE|KU_NON_REPUDIATION)) return 0; + return ret; +} + +static int check_purpose_smime_encrypt(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + int ret; + ret = purpose_smime(x, ca); + if(!ret || ca) return ret; + if(ku_reject(x, KU_KEY_ENCIPHERMENT)) return 0; + return ret; +} + +static int check_purpose_crl_sign(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + if(ca) { + int ca_ret; + if((ca_ret = check_ca(x)) != 2) return ca_ret; + else return 0; + } + if(ku_reject(x, KU_CRL_SIGN)) return 0; + return 1; +} + +/* OCSP helper: this is *not* a full OCSP check. It just checks that + * each CA is valid. Additional checks must be made on the chain. + */ + +static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + /* Must be a valid CA. Should we really support the "I don't know" + value (2)? */ + if(ca) return check_ca(x); + /* leaf certificate is checked in OCSP_verify() */ + return 1; +} + +static int check_purpose_timestamp_sign(const X509_PURPOSE *xp, const X509 *x, + int ca) +{ + int i_ext; + + /* If ca is true we must return if this is a valid CA certificate. */ + if (ca) return check_ca(x); + + /* + * Check the optional key usage field: + * if Key Usage is present, it must be one of digitalSignature + * and/or nonRepudiation (other values are not consistent and shall + * be rejected). + */ + if ((x->ex_flags & EXFLAG_KUSAGE) + && ((x->ex_kusage & ~(KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)) || + !(x->ex_kusage & (KU_NON_REPUDIATION | KU_DIGITAL_SIGNATURE)))) + return 0; + + /* Only time stamp key usage is permitted and it's required. */ + if (!(x->ex_flags & EXFLAG_XKUSAGE) || x->ex_xkusage != XKU_TIMESTAMP) + return 0; + + /* Extended Key Usage MUST be critical */ + i_ext = X509_get_ext_by_NID((X509 *) x, NID_ext_key_usage, -1); + if (i_ext >= 0) + { + X509_EXTENSION *ext = X509_get_ext((X509 *) x, i_ext); + if (!X509_EXTENSION_get_critical(ext)) + return 0; + } + + return 1; +} + +static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca) +{ + return 1; +} + +/* Various checks to see if one certificate issued the second. + * This can be used to prune a set of possible issuer certificates + * which have been looked up using some simple method such as by + * subject name. + * These are: + * 1. Check issuer_name(subject) == subject_name(issuer) + * 2. If akid(subject) exists check it matches issuer + * 3. If key_usage(issuer) exists check it supports certificate signing + * returns 0 for OK, positive for reason for mismatch, reasons match + * codes for X509_verify_cert() + */ + +int X509_check_issued(X509 *issuer, X509 *subject) +{ + if(X509_NAME_cmp(X509_get_subject_name(issuer), + X509_get_issuer_name(subject))) + return X509_V_ERR_SUBJECT_ISSUER_MISMATCH; + x509v3_cache_extensions(issuer); + x509v3_cache_extensions(subject); + + if(subject->akid) + { + int ret = X509_check_akid(issuer, subject->akid); + if (ret != X509_V_OK) + return ret; + } + + if(subject->ex_flags & EXFLAG_PROXY) + { + if(ku_reject(issuer, KU_DIGITAL_SIGNATURE)) + return X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE; + } + else if(ku_reject(issuer, KU_KEY_CERT_SIGN)) + return X509_V_ERR_KEYUSAGE_NO_CERTSIGN; + return X509_V_OK; +} + +int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid) + { + + if(!akid) + return X509_V_OK; + + /* Check key ids (if present) */ + if(akid->keyid && issuer->skid && + ASN1_OCTET_STRING_cmp(akid->keyid, issuer->skid) ) + return X509_V_ERR_AKID_SKID_MISMATCH; + /* Check serial number */ + if(akid->serial && + ASN1_INTEGER_cmp(X509_get_serialNumber(issuer), akid->serial)) + return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH; + /* Check issuer name */ + if(akid->issuer) + { + /* Ugh, for some peculiar reason AKID includes + * SEQUENCE OF GeneralName. So look for a DirName. + * There may be more than one but we only take any + * notice of the first. + */ + GENERAL_NAMES *gens; + GENERAL_NAME *gen; + X509_NAME *nm = NULL; + size_t i; + gens = akid->issuer; + for(i = 0; i < sk_GENERAL_NAME_num(gens); i++) + { + gen = sk_GENERAL_NAME_value(gens, i); + if(gen->type == GEN_DIRNAME) + { + nm = gen->d.dirn; + break; + } + } + if(nm && X509_NAME_cmp(nm, X509_get_issuer_name(issuer))) + return X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH; + } + return X509_V_OK; + } + diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_skey.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_skey.c new file mode 100644 index 00000000..e396f054 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_skey.c @@ -0,0 +1,148 @@ +/* v3_skey.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#include +#include + +#include +#include +#include +#include + + +static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str); +const X509V3_EXT_METHOD v3_skey_id = { +NID_subject_key_identifier, 0, ASN1_ITEM_ref(ASN1_OCTET_STRING), +0,0,0,0, +(X509V3_EXT_I2S)i2s_ASN1_OCTET_STRING, +(X509V3_EXT_S2I)s2i_skey_id, +0,0,0,0, +NULL}; + +char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, + ASN1_OCTET_STRING *oct) +{ + return hex_to_string(oct->data, oct->length); +} + +ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, char *str) +{ + ASN1_OCTET_STRING *oct; + long length; + + if(!(oct = M_ASN1_OCTET_STRING_new())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if(!(oct->data = string_to_hex(str, &length))) { + M_ASN1_OCTET_STRING_free(oct); + return NULL; + } + + oct->length = length; + + return oct; + +} + +static ASN1_OCTET_STRING *s2i_skey_id(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, char *str) +{ + ASN1_OCTET_STRING *oct; + ASN1_BIT_STRING *pk; + unsigned char pkey_dig[EVP_MAX_MD_SIZE]; + unsigned int diglen; + + if(strcmp(str, "hash")) return s2i_ASN1_OCTET_STRING(method, ctx, str); + + if(!(oct = M_ASN1_OCTET_STRING_new())) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + + if(ctx && (ctx->flags == CTX_TEST)) return oct; + + if(!ctx || (!ctx->subject_req && !ctx->subject_cert)) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_PUBLIC_KEY); + goto err; + } + + if(ctx->subject_req) + pk = ctx->subject_req->req_info->pubkey->public_key; + else pk = ctx->subject_cert->cert_info->key->public_key; + + if(!pk) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_NO_PUBLIC_KEY); + goto err; + } + + if (!EVP_Digest(pk->data, pk->length, pkey_dig, &diglen, EVP_sha1(), NULL)) + goto err; + + if(!M_ASN1_OCTET_STRING_set(oct, pkey_dig, diglen)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + + return oct; + + err: + M_ASN1_OCTET_STRING_free(oct); + return NULL; +} diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_sxnet.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_sxnet.c new file mode 100644 index 00000000..4dd5bfc1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_sxnet.c @@ -0,0 +1,266 @@ +/* v3_sxnet.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +/* Support for Thawte strong extranet extension */ + +#define SXNET_TEST + +static int sxnet_i2r(X509V3_EXT_METHOD *method, SXNET *sx, BIO *out, int indent); +#ifdef SXNET_TEST +static SXNET * sxnet_v2i(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *nval); +#endif +const X509V3_EXT_METHOD v3_sxnet = { +NID_sxnet, X509V3_EXT_MULTILINE, ASN1_ITEM_ref(SXNET), +0,0,0,0, +0,0, +0, +#ifdef SXNET_TEST +(X509V3_EXT_V2I)sxnet_v2i, +#else +0, +#endif +(X509V3_EXT_I2R)sxnet_i2r, +0, +NULL +}; + +ASN1_SEQUENCE(SXNETID) = { + ASN1_SIMPLE(SXNETID, zone, ASN1_INTEGER), + ASN1_SIMPLE(SXNETID, user, ASN1_OCTET_STRING) +} ASN1_SEQUENCE_END(SXNETID) + +IMPLEMENT_ASN1_FUNCTIONS(SXNETID) + +ASN1_SEQUENCE(SXNET) = { + ASN1_SIMPLE(SXNET, version, ASN1_INTEGER), + ASN1_SEQUENCE_OF(SXNET, ids, SXNETID) +} ASN1_SEQUENCE_END(SXNET) + +IMPLEMENT_ASN1_FUNCTIONS(SXNET) + +static int sxnet_i2r(X509V3_EXT_METHOD *method, SXNET *sx, BIO *out, + int indent) +{ + long v; + char *tmp; + SXNETID *id; + size_t i; + v = ASN1_INTEGER_get(sx->version); + BIO_printf(out, "%*sVersion: %ld (0x%lX)", indent, "", v + 1, v); + for(i = 0; i < sk_SXNETID_num(sx->ids); i++) { + id = sk_SXNETID_value(sx->ids, i); + tmp = i2s_ASN1_INTEGER(NULL, id->zone); + BIO_printf(out, "\n%*sZone: %s, User: ", indent, "", tmp); + OPENSSL_free(tmp); + M_ASN1_OCTET_STRING_print(out, id->user); + } + return 1; +} + +#ifdef SXNET_TEST + +/* NBB: this is used for testing only. It should *not* be used for anything + * else because it will just take static IDs from the configuration file and + * they should really be separate values for each user. + */ + + +static SXNET * sxnet_v2i(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + STACK_OF(CONF_VALUE) *nval) +{ + CONF_VALUE *cnf; + SXNET *sx = NULL; + size_t i; + for(i = 0; i < sk_CONF_VALUE_num(nval); i++) { + cnf = sk_CONF_VALUE_value(nval, i); + if(!SXNET_add_id_asc(&sx, cnf->name, cnf->value, -1)) + return NULL; + } + return sx; +} + + +#endif + +/* Strong Extranet utility functions */ + +/* Add an id given the zone as an ASCII number */ + +int SXNET_add_id_asc(SXNET **psx, char *zone, char *user, + int userlen) +{ + ASN1_INTEGER *izone = NULL; + if(!(izone = s2i_ASN1_INTEGER(NULL, zone))) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ERROR_CONVERTING_ZONE); + return 0; + } + return SXNET_add_id_INTEGER(psx, izone, user, userlen); +} + +/* Add an id given the zone as an unsigned long */ + +int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, char *user, + int userlen) +{ + ASN1_INTEGER *izone = NULL; + if(!(izone = M_ASN1_INTEGER_new()) || !ASN1_INTEGER_set(izone, lzone)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + M_ASN1_INTEGER_free(izone); + return 0; + } + return SXNET_add_id_INTEGER(psx, izone, user, userlen); + +} + +/* Add an id given the zone as an ASN1_INTEGER. + * Note this version uses the passed integer and doesn't make a copy so don't + * free it up afterwards. + */ + +int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *zone, char *user, + int userlen) +{ + SXNET *sx = NULL; + SXNETID *id = NULL; + if(!psx || !zone || !user) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_ARGUMENT); + return 0; + } + if(userlen == -1) userlen = strlen(user); + if(userlen > 64) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_USER_TOO_LONG); + return 0; + } + if(!*psx) { + if(!(sx = SXNET_new())) goto err; + if(!ASN1_INTEGER_set(sx->version, 0)) goto err; + *psx = sx; + } else sx = *psx; + if(SXNET_get_id_INTEGER(sx, zone)) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_DUPLICATE_ZONE_ID); + return 0; + } + + if(!(id = SXNETID_new())) goto err; + if(userlen == -1) userlen = strlen(user); + + if(!M_ASN1_OCTET_STRING_set(id->user, user, userlen)) goto err; + if(!sk_SXNETID_push(sx->ids, id)) goto err; + id->zone = zone; + return 1; + + err: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + SXNETID_free(id); + SXNET_free(sx); + *psx = NULL; + return 0; +} + +ASN1_OCTET_STRING *SXNET_get_id_asc(SXNET *sx, char *zone) +{ + ASN1_INTEGER *izone = NULL; + ASN1_OCTET_STRING *oct; + if(!(izone = s2i_ASN1_INTEGER(NULL, zone))) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ERROR_CONVERTING_ZONE); + return NULL; + } + oct = SXNET_get_id_INTEGER(sx, izone); + M_ASN1_INTEGER_free(izone); + return oct; +} + +ASN1_OCTET_STRING *SXNET_get_id_ulong(SXNET *sx, unsigned long lzone) +{ + ASN1_INTEGER *izone = NULL; + ASN1_OCTET_STRING *oct; + if(!(izone = M_ASN1_INTEGER_new()) || !ASN1_INTEGER_set(izone, lzone)) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + M_ASN1_INTEGER_free(izone); + return NULL; + } + oct = SXNET_get_id_INTEGER(sx, izone); + M_ASN1_INTEGER_free(izone); + return oct; +} + +ASN1_OCTET_STRING *SXNET_get_id_INTEGER(SXNET *sx, ASN1_INTEGER *zone) +{ + SXNETID *id; + size_t i; + for(i = 0; i < sk_SXNETID_num(sx->ids); i++) { + id = sk_SXNETID_value(sx->ids, i); + if(!M_ASN1_INTEGER_cmp(id->zone, zone)) return id->user; + } + return NULL; +} + +IMPLEMENT_ASN1_SET_OF(SXNETID) diff --git a/TMessagesProj/jni/boringssl/crypto/x509v3/v3_utl.c b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_utl.c new file mode 100644 index 00000000..790c5ab5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/crypto/x509v3/v3_utl.c @@ -0,0 +1,1316 @@ +/* v3_utl.c */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project. + */ +/* ==================================================================== + * Copyright (c) 1999-2003 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* X509 v3 extension utilities */ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +static char *strip_spaces(char *name); +static int sk_strcmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b); +static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name, GENERAL_NAMES *gens); +static void str_free(OPENSSL_STRING str); +static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, ASN1_IA5STRING *email); + +static int ipv4_from_asc(unsigned char *v4, const char *in); +static int ipv6_from_asc(unsigned char *v6, const char *in); +static int ipv6_cb(const char *elem, int len, void *usr); +static int ipv6_hex(unsigned char *out, const char *in, int inlen); + +/* Add a CONF_VALUE name value pair to stack */ + +int X509V3_add_value(const char *name, const char *value, + STACK_OF(CONF_VALUE) **extlist) +{ + CONF_VALUE *vtmp = NULL; + char *tname = NULL, *tvalue = NULL; + if(name && !(tname = BUF_strdup(name))) goto err; + if(value && !(tvalue = BUF_strdup(value))) goto err; + if(!(vtmp = (CONF_VALUE *)OPENSSL_malloc(sizeof(CONF_VALUE)))) goto err; + if(!*extlist && !(*extlist = sk_CONF_VALUE_new_null())) goto err; + vtmp->section = NULL; + vtmp->name = tname; + vtmp->value = tvalue; + if(!sk_CONF_VALUE_push(*extlist, vtmp)) goto err; + return 1; + err: + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + if(vtmp) OPENSSL_free(vtmp); + if(tname) OPENSSL_free(tname); + if(tvalue) OPENSSL_free(tvalue); + return 0; +} + +int X509V3_add_value_uchar(const char *name, const unsigned char *value, + STACK_OF(CONF_VALUE) **extlist) + { + return X509V3_add_value(name,(const char *)value,extlist); + } + +/* Free function for STACK_OF(CONF_VALUE) */ + +void X509V3_conf_free(CONF_VALUE *conf) +{ + if(!conf) return; + if(conf->name) OPENSSL_free(conf->name); + if(conf->value) OPENSSL_free(conf->value); + if(conf->section) OPENSSL_free(conf->section); + OPENSSL_free(conf); +} + +int X509V3_add_value_bool(const char *name, int asn1_bool, + STACK_OF(CONF_VALUE) **extlist) +{ + if(asn1_bool) return X509V3_add_value(name, "TRUE", extlist); + return X509V3_add_value(name, "FALSE", extlist); +} + +int X509V3_add_value_bool_nf(char *name, int asn1_bool, + STACK_OF(CONF_VALUE) **extlist) +{ + if(asn1_bool) return X509V3_add_value(name, "TRUE", extlist); + return 1; +} + + +char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, ASN1_ENUMERATED *a) +{ + BIGNUM *bntmp = NULL; + char *strtmp = NULL; + if(!a) return NULL; + if(!(bntmp = ASN1_ENUMERATED_to_BN(a, NULL)) || + !(strtmp = BN_bn2dec(bntmp)) ) + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + BN_free(bntmp); + return strtmp; +} + +char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *method, ASN1_INTEGER *a) +{ + BIGNUM *bntmp = NULL; + char *strtmp = NULL; + if(!a) return NULL; + if(!(bntmp = ASN1_INTEGER_to_BN(a, NULL)) || + !(strtmp = BN_bn2dec(bntmp)) ) + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + BN_free(bntmp); + return strtmp; +} + +ASN1_INTEGER *s2i_ASN1_INTEGER(X509V3_EXT_METHOD *method, char *value) +{ + BIGNUM *bn = NULL; + ASN1_INTEGER *aint; + int isneg, ishex; + int ret; + if (!value) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_VALUE); + return 0; + } + bn = BN_new(); + if (value[0] == '-') { + value++; + isneg = 1; + } else isneg = 0; + + if (value[0] == '0' && ((value[1] == 'x') || (value[1] == 'X'))) { + value += 2; + ishex = 1; + } else ishex = 0; + + if (ishex) ret = BN_hex2bn(&bn, value); + else ret = BN_dec2bn(&bn, value); + + if (!ret || value[ret]) { + BN_free(bn); + OPENSSL_PUT_ERROR(X509V3, X509V3_R_BN_DEC2BN_ERROR); + return 0; + } + + if (isneg && BN_is_zero(bn)) isneg = 0; + + aint = BN_to_ASN1_INTEGER(bn, NULL); + BN_free(bn); + if (!aint) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_BN_TO_ASN1_INTEGER_ERROR); + return 0; + } + if (isneg) aint->type |= V_ASN1_NEG; + return aint; +} + +int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint, + STACK_OF(CONF_VALUE) **extlist) +{ + char *strtmp; + int ret; + if(!aint) return 1; + if(!(strtmp = i2s_ASN1_INTEGER(NULL, aint))) return 0; + ret = X509V3_add_value(name, strtmp, extlist); + OPENSSL_free(strtmp); + return ret; +} + +int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool) +{ + char *btmp; + if(!(btmp = value->value)) goto err; + if(!strcmp(btmp, "TRUE") || !strcmp(btmp, "true") + || !strcmp(btmp, "Y") || !strcmp(btmp, "y") + || !strcmp(btmp, "YES") || !strcmp(btmp, "yes")) { + *asn1_bool = 0xff; + return 1; + } else if(!strcmp(btmp, "FALSE") || !strcmp(btmp, "false") + || !strcmp(btmp, "N") || !strcmp(btmp, "n") + || !strcmp(btmp, "NO") || !strcmp(btmp, "no")) { + *asn1_bool = 0; + return 1; + } + err: + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_BOOLEAN_STRING); + X509V3_conf_err(value); + return 0; +} + +int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint) +{ + ASN1_INTEGER *itmp; + if(!(itmp = s2i_ASN1_INTEGER(NULL, value->value))) { + X509V3_conf_err(value); + return 0; + } + *aint = itmp; + return 1; +} + +#define HDR_NAME 1 +#define HDR_VALUE 2 + +/*#define DEBUG*/ + +STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line) +{ + char *p, *q, c; + char *ntmp, *vtmp; + STACK_OF(CONF_VALUE) *values = NULL; + char *linebuf; + int state; + /* We are going to modify the line so copy it first */ + linebuf = BUF_strdup(line); + if (linebuf == NULL) + { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + goto err; + } + state = HDR_NAME; + ntmp = NULL; + /* Go through all characters */ + for(p = linebuf, q = linebuf; (c = *p) && (c!='\r') && (c!='\n'); p++) { + + switch(state) { + case HDR_NAME: + if(c == ':') { + state = HDR_VALUE; + *p = 0; + ntmp = strip_spaces(q); + if(!ntmp) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_NAME); + goto err; + } + q = p + 1; + } else if(c == ',') { + *p = 0; + ntmp = strip_spaces(q); + q = p + 1; +#if 0 + printf("%s\n", ntmp); +#endif + if(!ntmp) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_NAME); + goto err; + } + X509V3_add_value(ntmp, NULL, &values); + } + break ; + + case HDR_VALUE: + if(c == ',') { + state = HDR_NAME; + *p = 0; + vtmp = strip_spaces(q); +#if 0 + printf("%s\n", ntmp); +#endif + if(!vtmp) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_VALUE); + goto err; + } + X509V3_add_value(ntmp, vtmp, &values); + ntmp = NULL; + q = p + 1; + } + + } + } + + if(state == HDR_VALUE) { + vtmp = strip_spaces(q); +#if 0 + printf("%s=%s\n", ntmp, vtmp); +#endif + if(!vtmp) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_VALUE); + goto err; + } + X509V3_add_value(ntmp, vtmp, &values); + } else { + ntmp = strip_spaces(q); +#if 0 + printf("%s\n", ntmp); +#endif + if(!ntmp) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_NAME); + goto err; + } + X509V3_add_value(ntmp, NULL, &values); + } +OPENSSL_free(linebuf); +return values; + +err: +OPENSSL_free(linebuf); +sk_CONF_VALUE_pop_free(values, X509V3_conf_free); +return NULL; + +} + +/* Delete leading and trailing spaces from a string */ +static char *strip_spaces(char *name) +{ + char *p, *q; + /* Skip over leading spaces */ + p = name; + while(*p && isspace((unsigned char)*p)) p++; + if(!*p) return NULL; + q = p + strlen(p) - 1; + while((q != p) && isspace((unsigned char)*q)) q--; + if(p != q) q[1] = 0; + if(!*p) return NULL; + return p; +} + +/* hex string utilities */ + +/* Given a buffer of length 'len' return a OPENSSL_malloc'ed string with its + * hex representation + * @@@ (Contents of buffer are always kept in ASCII, also on EBCDIC machines) + */ + +char *hex_to_string(const unsigned char *buffer, long len) +{ + char *tmp, *q; + const unsigned char *p; + int i; + static const char hexdig[] = "0123456789ABCDEF"; + if(!buffer || !len) return NULL; + if(!(tmp = OPENSSL_malloc(len * 3 + 1))) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + } + q = tmp; + for(i = 0, p = buffer; i < len; i++,p++) { + *q++ = hexdig[(*p >> 4) & 0xf]; + *q++ = hexdig[*p & 0xf]; + *q++ = ':'; + } + q[-1] = 0; + + return tmp; +} + +/* Give a string of hex digits convert to + * a buffer + */ + +unsigned char *string_to_hex(const char *str, long *len) +{ + unsigned char *hexbuf, *q; + unsigned char ch, cl, *p; + if(!str) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_INVALID_NULL_ARGUMENT); + return NULL; + } + if(!(hexbuf = OPENSSL_malloc(strlen(str) >> 1))) goto err; + for(p = (unsigned char *)str, q = hexbuf; *p;) { + ch = *p++; + if(ch == ':') continue; + cl = *p++; + if(!cl) { + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ODD_NUMBER_OF_DIGITS); + OPENSSL_free(hexbuf); + return NULL; + } + if(isupper(ch)) ch = tolower(ch); + if(isupper(cl)) cl = tolower(cl); + + if((ch >= '0') && (ch <= '9')) ch -= '0'; + else if ((ch >= 'a') && (ch <= 'f')) ch -= 'a' - 10; + else goto badhex; + + if((cl >= '0') && (cl <= '9')) cl -= '0'; + else if ((cl >= 'a') && (cl <= 'f')) cl -= 'a' - 10; + else goto badhex; + + *q++ = (ch << 4) | cl; + } + + if(len) *len = q - hexbuf; + + return hexbuf; + + err: + if(hexbuf) OPENSSL_free(hexbuf); + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + return NULL; + + badhex: + OPENSSL_free(hexbuf); + OPENSSL_PUT_ERROR(X509V3, X509V3_R_ILLEGAL_HEX_DIGIT); + return NULL; + +} + +/* V2I name comparison function: returns zero if 'name' matches + * cmp or cmp.* + */ + +int name_cmp(const char *name, const char *cmp) +{ + int len, ret; + char c; + len = strlen(cmp); + if((ret = strncmp(name, cmp, len))) return ret; + c = name[len]; + if(!c || (c=='.')) return 0; + return 1; +} + +static int sk_strcmp(const OPENSSL_STRING *a, const OPENSSL_STRING *b) +{ + return strcmp(*a, *b); +} + +STACK_OF(OPENSSL_STRING) *X509_get1_email(X509 *x) +{ + GENERAL_NAMES *gens; + STACK_OF(OPENSSL_STRING) *ret; + + gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); + ret = get_email(X509_get_subject_name(x), gens); + sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); + return ret; +} + +STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x) +{ + AUTHORITY_INFO_ACCESS *info; + STACK_OF(OPENSSL_STRING) *ret = NULL; + size_t i; + + info = X509_get_ext_d2i(x, NID_info_access, NULL, NULL); + if (!info) + return NULL; + for (i = 0; i < sk_ACCESS_DESCRIPTION_num(info); i++) + { + ACCESS_DESCRIPTION *ad = sk_ACCESS_DESCRIPTION_value(info, i); + if (OBJ_obj2nid(ad->method) == NID_ad_OCSP) + { + if (ad->location->type == GEN_URI) + { + if (!append_ia5(&ret, ad->location->d.uniformResourceIdentifier)) + break; + } + } + } + AUTHORITY_INFO_ACCESS_free(info); + return ret; +} + +STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x) +{ + GENERAL_NAMES *gens; + STACK_OF(X509_EXTENSION) *exts; + STACK_OF(OPENSSL_STRING) *ret; + + exts = X509_REQ_get_extensions(x); + gens = X509V3_get_d2i(exts, NID_subject_alt_name, NULL, NULL); + ret = get_email(X509_REQ_get_subject_name(x), gens); + sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free); + sk_X509_EXTENSION_pop_free(exts, X509_EXTENSION_free); + return ret; +} + + +static STACK_OF(OPENSSL_STRING) *get_email(X509_NAME *name, GENERAL_NAMES *gens) +{ + STACK_OF(OPENSSL_STRING) *ret = NULL; + X509_NAME_ENTRY *ne; + ASN1_IA5STRING *email; + GENERAL_NAME *gen; + int i; + size_t j; + /* Now add any email address(es) to STACK */ + i = -1; + /* First supplied X509_NAME */ + while((i = X509_NAME_get_index_by_NID(name, + NID_pkcs9_emailAddress, i)) >= 0) { + ne = X509_NAME_get_entry(name, i); + email = X509_NAME_ENTRY_get_data(ne); + if(!append_ia5(&ret, email)) return NULL; + } + for(j = 0; j < sk_GENERAL_NAME_num(gens); j++) + { + gen = sk_GENERAL_NAME_value(gens, j); + if(gen->type != GEN_EMAIL) continue; + if(!append_ia5(&ret, gen->d.ia5)) return NULL; + } + return ret; +} + +static void str_free(OPENSSL_STRING str) +{ + OPENSSL_free(str); +} + +static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, ASN1_IA5STRING *email) +{ + char *emtmp; + /* First some sanity checks */ + if(email->type != V_ASN1_IA5STRING) return 1; + if(!email->data || !email->length) return 1; + if(!*sk) *sk = sk_OPENSSL_STRING_new(sk_strcmp); + if(!*sk) return 0; + /* Don't add duplicates */ + if(sk_OPENSSL_STRING_find(*sk, NULL, (char *)email->data)) return 1; + emtmp = BUF_strdup((char *)email->data); + if(!emtmp || !sk_OPENSSL_STRING_push(*sk, emtmp)) { + X509_email_free(*sk); + *sk = NULL; + return 0; + } + return 1; +} + +void X509_email_free(STACK_OF(OPENSSL_STRING) *sk) +{ + sk_OPENSSL_STRING_pop_free(sk, str_free); +} + +typedef int (*equal_fn)(const unsigned char *pattern, size_t pattern_len, + const unsigned char *subject, size_t subject_len, + unsigned int flags); + +/* Skip pattern prefix to match "wildcard" subject */ +static void skip_prefix(const unsigned char **p, size_t *plen, + const unsigned char *subject, size_t subject_len, + unsigned int flags) + { + const unsigned char *pattern = *p; + size_t pattern_len = *plen; + + /* + * If subject starts with a leading '.' followed by more octets, and + * pattern is longer, compare just an equal-length suffix with the + * full subject (starting at the '.'), provided the prefix contains + * no NULs. + */ + if ((flags & _X509_CHECK_FLAG_DOT_SUBDOMAINS) == 0) + return; + + while (pattern_len > subject_len && *pattern) + { + if ((flags & X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS) && + *pattern == '.') + break; + ++pattern; + --pattern_len; + } + + /* Skip if entire prefix acceptable */ + if (pattern_len == subject_len) + { + *p = pattern; + *plen = pattern_len; + } + } + +/* Compare while ASCII ignoring case. */ +static int equal_nocase(const unsigned char *pattern, size_t pattern_len, + const unsigned char *subject, size_t subject_len, + unsigned int flags) + { + skip_prefix(&pattern, &pattern_len, subject, subject_len, flags); + if (pattern_len != subject_len) + return 0; + while (pattern_len) + { + unsigned char l = *pattern; + unsigned char r = *subject; + /* The pattern must not contain NUL characters. */ + if (l == 0) + return 0; + if (l != r) + { + if ('A' <= l && l <= 'Z') + l = (l - 'A') + 'a'; + if ('A' <= r && r <= 'Z') + r = (r - 'A') + 'a'; + if (l != r) + return 0; + } + ++pattern; + ++subject; + --pattern_len; + } + return 1; + } + +/* Compare using memcmp. */ +static int equal_case(const unsigned char *pattern, size_t pattern_len, + const unsigned char *subject, size_t subject_len, + unsigned int flags) +{ + skip_prefix(&pattern, &pattern_len, subject, subject_len, flags); + if (pattern_len != subject_len) + return 0; + return !memcmp(pattern, subject, pattern_len); +} + +/* RFC 5280, section 7.5, requires that only the domain is compared in + a case-insensitive manner. */ +static int equal_email(const unsigned char *a, size_t a_len, + const unsigned char *b, size_t b_len, + unsigned int unused_flags) + { + size_t i = a_len; + if (a_len != b_len) + return 0; + /* We search backwards for the '@' character, so that we do + not have to deal with quoted local-parts. The domain part + is compared in a case-insensitive manner. */ + while (i > 0) + { + --i; + if (a[i] == '@' || b[i] == '@') + { + if (!equal_nocase(a + i, a_len - i, + b + i, a_len - i, 0)) + return 0; + break; + } + } + if (i == 0) + i = a_len; + return equal_case(a, i, b, i, 0); + } + +/* Compare the prefix and suffix with the subject, and check that the + characters in-between are valid. */ +static int wildcard_match(const unsigned char *prefix, size_t prefix_len, + const unsigned char *suffix, size_t suffix_len, + const unsigned char *subject, size_t subject_len, + unsigned int flags) + { + const unsigned char *wildcard_start; + const unsigned char *wildcard_end; + const unsigned char *p; + int allow_multi = 0; + int allow_idna = 0; + + if (subject_len < prefix_len + suffix_len) + return 0; + if (!equal_nocase(prefix, prefix_len, subject, prefix_len, flags)) + return 0; + wildcard_start = subject + prefix_len; + wildcard_end = subject + (subject_len - suffix_len); + if (!equal_nocase(wildcard_end, suffix_len, suffix, suffix_len, flags)) + return 0; + /* + * If the wildcard makes up the entire first label, it must match at + * least one character. + */ + if (prefix_len == 0 && *suffix == '.') + { + if (wildcard_start == wildcard_end) + return 0; + allow_idna = 1; + if (flags & X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS) + allow_multi = 1; + } + /* IDNA labels cannot match partial wildcards */ + if (!allow_idna && + subject_len >= 4 && OPENSSL_strncasecmp((char *)subject, "xn--", 4) == 0) + return 0; + /* The wildcard may match a literal '*' */ + if (wildcard_end == wildcard_start + 1 && *wildcard_start == '*') + return 1; + /* + * Check that the part matched by the wildcard contains only + * permitted characters and only matches a single label unless + * allow_multi is set. + */ + for (p = wildcard_start; p != wildcard_end; ++p) + if (!(('0' <= *p && *p <= '9') || + ('A' <= *p && *p <= 'Z') || + ('a' <= *p && *p <= 'z') || + *p == '-' || (allow_multi && *p == '.'))) + return 0; + return 1; + } + +#define LABEL_START (1 << 0) +#define LABEL_END (1 << 1) +#define LABEL_HYPHEN (1 << 2) +#define LABEL_IDNA (1 << 3) + +static const unsigned char *valid_star(const unsigned char *p, size_t len, + unsigned int flags) + { + const unsigned char *star = 0; + size_t i; + int state = LABEL_START; + int dots = 0; + for (i = 0; i < len; ++i) + { + /* + * Locate first and only legal wildcard, either at the start + * or end of a non-IDNA first and not final label. + */ + if (p[i] == '*') + { + int atstart = (state & LABEL_START); + int atend = (i == len - 1 || p[i+1] == '.'); + /* + * At most one wildcard per pattern. + * No wildcards in IDNA labels. + * No wildcards after the first label. + */ + if (star != NULL || (state & LABEL_IDNA) != 0 || dots) + return NULL; + /* Only full-label '*.example.com' wildcards? */ + if ((flags & X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS) + && (!atstart || !atend)) + return NULL; + /* No 'foo*bar' wildcards */ + if (!atstart && !atend) + return NULL; + star = &p[i]; + state &= ~LABEL_START; + } + else if ((state & LABEL_START) != 0) + { + /* + * At the start of a label, skip any "xn--" and + * remain in the LABEL_START state, but set the + * IDNA label state + */ + if ((state & LABEL_IDNA) == 0 && len - i >= 4 + && OPENSSL_strncasecmp((char *)&p[i], "xn--", 4) == 0) + { + i += 3; + state |= LABEL_IDNA; + continue; + } + /* Labels must start with a letter or digit */ + state &= ~LABEL_START; + if (('a' <= p[i] && p[i] <= 'z') + || ('A' <= p[i] && p[i] <= 'Z') + || ('0' <= p[i] && p[i] <= '9')) + continue; + return NULL; + } + else if (('a' <= p[i] && p[i] <= 'z') + || ('A' <= p[i] && p[i] <= 'Z') + || ('0' <= p[i] && p[i] <= '9')) + { + state &= LABEL_IDNA; + continue; + } + else if (p[i] == '.') + { + if (state & (LABEL_HYPHEN | LABEL_START)) + return NULL; + state = LABEL_START; + ++dots; + } + else if (p[i] == '-') + { + if (state & LABEL_HYPHEN) + return NULL; + state |= LABEL_HYPHEN; + } + else + return NULL; + } + + /* + * The final label must not end in a hyphen or ".", and + * there must be at least two dots after the star. + */ + if ((state & (LABEL_START | LABEL_HYPHEN)) != 0 + || dots < 2) + return NULL; + return star; + } + +/* Compare using wildcards. */ +static int equal_wildcard(const unsigned char *pattern, size_t pattern_len, + const unsigned char *subject, size_t subject_len, + unsigned int flags) + { + const unsigned char *star = NULL; + + /* + * Subject names starting with '.' can only match a wildcard pattern + * via a subject sub-domain pattern suffix match. + */ + if (!(subject_len > 1 && subject[0] == '.')) + star = valid_star(pattern, pattern_len, flags); + if (star == NULL) + return equal_nocase(pattern, pattern_len, + subject, subject_len, flags); + return wildcard_match(pattern, star - pattern, + star + 1, (pattern + pattern_len) - star - 1, + subject, subject_len, flags); + } + +/* Compare an ASN1_STRING to a supplied string. If they match + * return 1. If cmp_type > 0 only compare if string matches the + * type, otherwise convert it to UTF8. + */ + +static int do_check_string(ASN1_STRING *a, int cmp_type, equal_fn equal, + unsigned int flags, const char *b, size_t blen, + char **peername) + { + int rv = 0; + + if (!a->data || !a->length) + return 0; + if (cmp_type > 0) + { + if (cmp_type != a->type) + return 0; + if (cmp_type == V_ASN1_IA5STRING) + rv = equal(a->data, a->length, + (unsigned char *)b, blen, flags); + else if (a->length == (int)blen && !memcmp(a->data, b, blen)) + rv = 1; + if (rv > 0 && peername) + *peername = BUF_strndup((char *)a->data, a->length); + } + else + { + int astrlen; + unsigned char *astr; + astrlen = ASN1_STRING_to_UTF8(&astr, a); + if (astrlen < 0) + return -1; + rv = equal(astr, astrlen, (unsigned char *)b, blen, flags); + if (rv > 0 && peername) + *peername = BUF_strndup((char *)astr, astrlen); + OPENSSL_free(astr); + } + return rv; + } + +static int do_x509_check(X509 *x, const char *chk, size_t chklen, + unsigned int flags, int check_type, + char **peername) + { + GENERAL_NAMES *gens = NULL; + X509_NAME *name = NULL; + size_t i; + int j; + int cnid; + int alt_type; + int san_present = 0; + int rv = 0; + equal_fn equal; + + /* See below, this flag is internal-only */ + flags &= ~_X509_CHECK_FLAG_DOT_SUBDOMAINS; + if (check_type == GEN_EMAIL) + { + cnid = NID_pkcs9_emailAddress; + alt_type = V_ASN1_IA5STRING; + equal = equal_email; + } + else if (check_type == GEN_DNS) + { + cnid = NID_commonName; + /* Implicit client-side DNS sub-domain pattern */ + if (chklen > 1 && chk[0] == '.') + flags |= _X509_CHECK_FLAG_DOT_SUBDOMAINS; + alt_type = V_ASN1_IA5STRING; + if (flags & X509_CHECK_FLAG_NO_WILDCARDS) + equal = equal_nocase; + else + equal = equal_wildcard; + } + else + { + cnid = 0; + alt_type = V_ASN1_OCTET_STRING; + equal = equal_case; + } + + gens = X509_get_ext_d2i(x, NID_subject_alt_name, NULL, NULL); + if (gens) + { + for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) + { + GENERAL_NAME *gen; + ASN1_STRING *cstr; + gen = sk_GENERAL_NAME_value(gens, i); + if (gen->type != check_type) + continue; + san_present = 1; + if (check_type == GEN_EMAIL) + cstr = gen->d.rfc822Name; + else if (check_type == GEN_DNS) + cstr = gen->d.dNSName; + else + cstr = gen->d.iPAddress; + /* Positive on success, negative on error! */ + if ((rv = do_check_string(cstr, alt_type, equal, flags, + chk, chklen, peername)) != 0) + break; + } + GENERAL_NAMES_free(gens); + if (rv != 0) + return rv; + if (!cnid + || (san_present + && !(flags & X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT))) + return 0; + } + j = -1; + name = X509_get_subject_name(x); + while((j = X509_NAME_get_index_by_NID(name, cnid, j)) >= 0) + { + X509_NAME_ENTRY *ne; + ASN1_STRING *str; + ne = X509_NAME_get_entry(name, j); + str = X509_NAME_ENTRY_get_data(ne); + /* Positive on success, negative on error! */ + if ((rv = do_check_string(str, -1, equal, flags, + chk, chklen, peername)) != 0) + return rv; + } + return 0; + } + +int X509_check_host(X509 *x, const char *chk, size_t chklen, + unsigned int flags, char **peername) + { + if (chk == NULL) + return -2; + if (memchr(chk, '\0', chklen)) + return -2; + return do_x509_check(x, chk, chklen, flags, GEN_DNS, peername); + } + +int X509_check_email(X509 *x, const char *chk, size_t chklen, + unsigned int flags) + { + if (chk == NULL) + return -2; + if (memchr(chk, '\0', chklen)) + return -2; + return do_x509_check(x, chk, chklen, flags, GEN_EMAIL, NULL); + } + +int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags) + { + if (chk == NULL) + return -2; + return do_x509_check(x, (char *)chk, chklen, flags, GEN_IPADD, NULL); + } + +int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags) + { + unsigned char ipout[16]; + size_t iplen; + + if (ipasc == NULL) + return -2; + iplen = (size_t) a2i_ipadd(ipout, ipasc); + if (iplen == 0) + return -2; + return do_x509_check(x, (char *)ipout, iplen, flags, GEN_IPADD, NULL); + } + +/* Convert IP addresses both IPv4 and IPv6 into an + * OCTET STRING compatible with RFC3280. + */ + +ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc) + { + unsigned char ipout[16]; + ASN1_OCTET_STRING *ret; + int iplen; + + /* If string contains a ':' assume IPv6 */ + + iplen = a2i_ipadd(ipout, ipasc); + + if (!iplen) + return NULL; + + ret = ASN1_OCTET_STRING_new(); + if (!ret) + return NULL; + if (!ASN1_OCTET_STRING_set(ret, ipout, iplen)) + { + ASN1_OCTET_STRING_free(ret); + return NULL; + } + return ret; + } + +ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc) + { + ASN1_OCTET_STRING *ret = NULL; + unsigned char ipout[32]; + char *iptmp = NULL, *p; + int iplen1, iplen2; + p = strchr(ipasc,'/'); + if (!p) + return NULL; + iptmp = BUF_strdup(ipasc); + if (!iptmp) + return NULL; + p = iptmp + (p - ipasc); + *p++ = 0; + + iplen1 = a2i_ipadd(ipout, iptmp); + + if (!iplen1) + goto err; + + iplen2 = a2i_ipadd(ipout + iplen1, p); + + OPENSSL_free(iptmp); + iptmp = NULL; + + if (!iplen2 || (iplen1 != iplen2)) + goto err; + + ret = ASN1_OCTET_STRING_new(); + if (!ret) + goto err; + if (!ASN1_OCTET_STRING_set(ret, ipout, iplen1 + iplen2)) + goto err; + + return ret; + + err: + if (iptmp) + OPENSSL_free(iptmp); + if (ret) + ASN1_OCTET_STRING_free(ret); + return NULL; + } + + +int a2i_ipadd(unsigned char *ipout, const char *ipasc) + { + /* If string contains a ':' assume IPv6 */ + + if (strchr(ipasc, ':')) + { + if (!ipv6_from_asc(ipout, ipasc)) + return 0; + return 16; + } + else + { + if (!ipv4_from_asc(ipout, ipasc)) + return 0; + return 4; + } + } + +static int ipv4_from_asc(unsigned char *v4, const char *in) + { + int a0, a1, a2, a3; + if (sscanf(in, "%d.%d.%d.%d", &a0, &a1, &a2, &a3) != 4) + return 0; + if ((a0 < 0) || (a0 > 255) || (a1 < 0) || (a1 > 255) + || (a2 < 0) || (a2 > 255) || (a3 < 0) || (a3 > 255)) + return 0; + v4[0] = a0; + v4[1] = a1; + v4[2] = a2; + v4[3] = a3; + return 1; + } + +typedef struct { + /* Temporary store for IPV6 output */ + unsigned char tmp[16]; + /* Total number of bytes in tmp */ + int total; + /* The position of a zero (corresponding to '::') */ + int zero_pos; + /* Number of zeroes */ + int zero_cnt; + } IPV6_STAT; + + +static int ipv6_from_asc(unsigned char *v6, const char *in) + { + IPV6_STAT v6stat; + v6stat.total = 0; + v6stat.zero_pos = -1; + v6stat.zero_cnt = 0; + /* Treat the IPv6 representation as a list of values + * separated by ':'. The presence of a '::' will parse + * as one, two or three zero length elements. + */ + if (!CONF_parse_list(in, ':', 0, ipv6_cb, &v6stat)) + return 0; + + /* Now for some sanity checks */ + + if (v6stat.zero_pos == -1) + { + /* If no '::' must have exactly 16 bytes */ + if (v6stat.total != 16) + return 0; + } + else + { + /* If '::' must have less than 16 bytes */ + if (v6stat.total == 16) + return 0; + /* More than three zeroes is an error */ + if (v6stat.zero_cnt > 3) + return 0; + /* Can only have three zeroes if nothing else present */ + else if (v6stat.zero_cnt == 3) + { + if (v6stat.total > 0) + return 0; + } + /* Can only have two zeroes if at start or end */ + else if (v6stat.zero_cnt == 2) + { + if ((v6stat.zero_pos != 0) + && (v6stat.zero_pos != v6stat.total)) + return 0; + } + else + /* Can only have one zero if *not* start or end */ + { + if ((v6stat.zero_pos == 0) + || (v6stat.zero_pos == v6stat.total)) + return 0; + } + } + + /* Format result */ + + if (v6stat.zero_pos >= 0) + { + /* Copy initial part */ + memcpy(v6, v6stat.tmp, v6stat.zero_pos); + /* Zero middle */ + memset(v6 + v6stat.zero_pos, 0, 16 - v6stat.total); + /* Copy final part */ + if (v6stat.total != v6stat.zero_pos) + memcpy(v6 + v6stat.zero_pos + 16 - v6stat.total, + v6stat.tmp + v6stat.zero_pos, + v6stat.total - v6stat.zero_pos); + } + else + memcpy(v6, v6stat.tmp, 16); + + return 1; + } + +static int ipv6_cb(const char *elem, int len, void *usr) + { + IPV6_STAT *s = usr; + /* Error if 16 bytes written */ + if (s->total == 16) + return 0; + if (len == 0) + { + /* Zero length element, corresponds to '::' */ + if (s->zero_pos == -1) + s->zero_pos = s->total; + /* If we've already got a :: its an error */ + else if (s->zero_pos != s->total) + return 0; + s->zero_cnt++; + } + else + { + /* If more than 4 characters could be final a.b.c.d form */ + if (len > 4) + { + /* Need at least 4 bytes left */ + if (s->total > 12) + return 0; + /* Must be end of string */ + if (elem[len]) + return 0; + if (!ipv4_from_asc(s->tmp + s->total, elem)) + return 0; + s->total += 4; + } + else + { + if (!ipv6_hex(s->tmp + s->total, elem, len)) + return 0; + s->total += 2; + } + } + return 1; + } + +/* Convert a string of up to 4 hex digits into the corresponding + * IPv6 form. + */ + +static int ipv6_hex(unsigned char *out, const char *in, int inlen) + { + unsigned char c; + unsigned int num = 0; + if (inlen > 4) + return 0; + while(inlen--) + { + c = *in++; + num <<= 4; + if ((c >= '0') && (c <= '9')) + num |= c - '0'; + else if ((c >= 'A') && (c <= 'F')) + num |= c - 'A' + 10; + else if ((c >= 'a') && (c <= 'f')) + num |= c - 'a' + 10; + else + return 0; + } + out[0] = num >> 8; + out[1] = num & 0xff; + return 1; + } + + +int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE)*dn_sk, + unsigned long chtype) + { + CONF_VALUE *v; + int mval; + size_t i; + char *p, *type; + if (!nm) + return 0; + + for (i = 0; i < sk_CONF_VALUE_num(dn_sk); i++) + { + v=sk_CONF_VALUE_value(dn_sk,i); + type=v->name; + /* Skip past any leading X. X: X, etc to allow for + * multiple instances + */ + for(p = type; *p ; p++) + if ((*p == ':') || (*p == ',') || (*p == '.')) + { + p++; + if(*p) type = p; + break; + } + if (*type == '+') + { + mval = -1; + type++; + } + else + mval = 0; + if (!X509_NAME_add_entry_by_txt(nm,type, chtype, + (unsigned char *) v->value,-1,-1,mval)) + return 0; + + } + return 1; + } diff --git a/TMessagesProj/jni/boringssl/include/openssl/aead.h b/TMessagesProj/jni/boringssl/include/openssl/aead.h new file mode 100644 index 00000000..d36cf95b --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/aead.h @@ -0,0 +1,315 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_AEAD_H +#define OPENSSL_HEADER_AEAD_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Authenticated Encryption with Additional Data. + * + * AEAD couples confidentiality and integrity in a single primtive. AEAD + * algorithms take a key and then can seal and open individual messages. Each + * message has a unique, per-message nonce and, optionally, additional data + * which is authenticated but not included in the ciphertext. + * + * The |EVP_AEAD_CTX_init| function initialises an |EVP_AEAD_CTX| structure and + * performs any precomputation needed to use |aead| with |key|. The length of + * the key, |key_len|, is given in bytes. + * + * The |tag_len| argument contains the length of the tags, in bytes, and allows + * for the processing of truncated authenticators. A zero value indicates that + * the default tag length should be used and this is defined as + * |EVP_AEAD_DEFAULT_TAG_LENGTH| in order to make the code clear. Using + * truncated tags increases an attacker's chance of creating a valid forgery. + * Be aware that the attacker's chance may increase more than exponentially as + * would naively be expected. + * + * When no longer needed, the initialised |EVP_AEAD_CTX| structure must be + * passed to |EVP_AEAD_CTX_cleanup|, which will deallocate any memory used. + * + * With an |EVP_AEAD_CTX| in hand, one can seal and open messages. These + * operations are intended to meet the standard notions of privacy and + * authenticity for authenticated encryption. For formal definitions see + * Bellare and Namprempre, "Authenticated encryption: relations among notions + * and analysis of the generic composition paradigm," Lecture Notes in Computer + * Science B<1976> (2000), 531–545, + * http://www-cse.ucsd.edu/~mihir/papers/oem.html. + * + * When sealing messages, a nonce must be given. The length of the nonce is + * fixed by the AEAD in use and is returned by |EVP_AEAD_nonce_length|. *The + * nonce must be unique for all messages with the same key*. This is critically + * important - nonce reuse may completely undermine the security of the AEAD. + * Nonces may be predictable and public, so long as they are unique. Uniqueness + * may be achieved with a simple counter or, if large enough, may be generated + * randomly. The nonce must be passed into the "open" operation by the receiver + * so must either be implicit (e.g. a counter), or must be transmitted along + * with the sealed message. + * + * The "seal" and "open" operations are atomic - an entire message must be + * encrypted or decrypted in a single call. Large messages may have to be split + * up in order to accomodate this. When doing so, be mindful of the need not to + * repeat nonces and the possibility that an attacker could duplicate, reorder + * or drop message chunks. For example, using a single key for a given (large) + * message and sealing chunks with nonces counting from zero would be secure as + * long as the number of chunks was securely transmitted. (Otherwise an + * attacker could truncate the message by dropping chunks from the end.) + * + * The number of chunks could be transmitted by prefixing it to the plaintext, + * for example. This also assumes that no other message would ever use the same + * key otherwise the rule that nonces must be unique for a given key would be + * violated. + * + * The "seal" and "open" operations also permit additional data to be + * authenticated via the |ad| parameter. This data is not included in the + * ciphertext and must be identical for both the "seal" and "open" call. This + * permits implicit context to be authenticated but may be empty if not needed. + * + * The "seal" and "open" operations may work in-place if the |out| and |in| + * arguments are equal. They may also be used to shift the data left inside the + * same buffer if |out| is less than |in|. However, |out| may not point inside + * the input data otherwise the input may be overwritten before it has been + * read. This situation will cause an error. + * + * The "seal" and "open" operations return one on success and zero on error. */ + + +/* AEAD algorithms. */ + +/* EVP_aead_aes_128_gcm is AES-128 in Galois Counter Mode. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_gcm(void); + +/* EVP_aead_aes_256_gcm is AES-256 in Galois Counter Mode. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_gcm(void); + +/* EVP_aead_chacha20_poly1305 is an AEAD built from ChaCha20 and Poly1305. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_chacha20_poly1305(void); + +/* EVP_aead_aes_128_key_wrap is AES-128 Key Wrap mode. This should never be + * used except to interoperate with existing systems that use this mode. + * + * If the nonce is empty then the default nonce will be used, otherwise it must + * be eight bytes long. The input must be a multiple of eight bytes long. No + * additional data can be given to this mode. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_key_wrap(void); + +/* EVP_aead_aes_256_key_wrap is AES-256 in Key Wrap mode. This should never be + * used except to interoperate with existing systems that use this mode. + * + * See |EVP_aead_aes_128_key_wrap| for details. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_key_wrap(void); + +/* EVP_aead_aes_128_ctr_hmac_sha256 is AES-128 in CTR mode with HMAC-SHA256 for + * authentication. The nonce is 12 bytes; the bottom 32-bits are used as the + * block counter, thus the maximum plaintext size is 64GB. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_ctr_hmac_sha256(void); + +/* EVP_aead_aes_128_ctr_hmac_sha256 is AES-256 in CTR mode with HMAC-SHA256 for + * authentication. See |EVP_aead_aes_128_ctr_hmac_sha256| for details. */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_ctr_hmac_sha256(void); + +/* EVP_has_aes_hardware returns one if we enable hardware support for fast and + * constant-time AES-GCM. */ +OPENSSL_EXPORT int EVP_has_aes_hardware(void); + + +/* TLS-specific AEAD algorithms. + * + * These AEAD primitives do not meet the definition of generic AEADs. They are + * all specific to TLS and should not be used outside of that context. They must + * be initialized with |EVP_AEAD_CTX_init_with_direction|, are stateful, and may + * not be used concurrently. Any nonces are used as IVs, so they must be + * unpredictable. They only accept an |ad| parameter of length 11 (the standard + * TLS one with length omitted). */ + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_md5_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_sha1_tls(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_tls_implicit_iv(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha256_tls(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_tls_implicit_iv(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha256_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha384_tls(void); + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv(void); + + +/* SSLv3-specific AEAD algorithms. + * + * These AEAD primitives do not meet the definition of generic AEADs. They are + * all specific to SSLv3 and should not be used outside of that context. They + * must be initialized with |EVP_AEAD_CTX_init_with_direction|, are stateful, + * and may not be used concurrently. They only accept an |ad| parameter of + * length 9 (the standard TLS one with length and version omitted). */ + +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_md5_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_rc4_sha1_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_cbc_sha1_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_cbc_sha1_ssl3(void); +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_des_ede3_cbc_sha1_ssl3(void); + + +/* Utility functions. */ + +/* EVP_AEAD_key_length returns the length, in bytes, of the keys used by + * |aead|. */ +OPENSSL_EXPORT size_t EVP_AEAD_key_length(const EVP_AEAD *aead); + +/* EVP_AEAD_nonce_length returns the length, in bytes, of the per-message nonce + * for |aead|. */ +OPENSSL_EXPORT size_t EVP_AEAD_nonce_length(const EVP_AEAD *aead); + +/* EVP_AEAD_max_overhead returns the maximum number of additional bytes added + * by the act of sealing data with |aead|. */ +OPENSSL_EXPORT size_t EVP_AEAD_max_overhead(const EVP_AEAD *aead); + +/* EVP_AEAD_max_tag_len returns the maximum tag length when using |aead|. This + * is the largest value that can be passed as |tag_len| to + * |EVP_AEAD_CTX_init|. */ +OPENSSL_EXPORT size_t EVP_AEAD_max_tag_len(const EVP_AEAD *aead); + + +/* AEAD operations. */ + +/* An EVP_AEAD_CTX represents an AEAD algorithm configured with a specific key + * and message-independent IV. */ +typedef struct evp_aead_ctx_st { + const EVP_AEAD *aead; + /* aead_state is an opaque pointer to whatever state the AEAD needs to + * maintain. */ + void *aead_state; +} EVP_AEAD_CTX; + +/* EVP_AEAD_MAX_KEY_LENGTH contains the maximum key length used by + * any AEAD defined in this header. */ +#define EVP_AEAD_MAX_KEY_LENGTH 80 + +/* EVP_AEAD_MAX_NONCE_LENGTH contains the maximum nonce length used by + * any AEAD defined in this header. */ +#define EVP_AEAD_MAX_NONCE_LENGTH 16 + +/* EVP_AEAD_MAX_OVERHEAD contains the maximum overhead used by any AEAD + * defined in this header. */ +#define EVP_AEAD_MAX_OVERHEAD 64 + +/* EVP_AEAD_DEFAULT_TAG_LENGTH is a magic value that can be passed to + * EVP_AEAD_CTX_init to indicate that the default tag length for an AEAD should + * be used. */ +#define EVP_AEAD_DEFAULT_TAG_LENGTH 0 + +/* evp_aead_direction_t denotes the direction of an AEAD operation. */ +enum evp_aead_direction_t { + evp_aead_open, + evp_aead_seal, +}; + +/* EVP_AEAD_CTX_init initializes |ctx| for the given AEAD algorithm. The |impl| + * argument is ignored and should be NULL. Authentication tags may be truncated + * by passing a size as |tag_len|. A |tag_len| of zero indicates the default + * tag length and this is defined as EVP_AEAD_DEFAULT_TAG_LENGTH for + * readability. + * + * Returns 1 on success. Otherwise returns 0 and pushes to the error stack. In + * the error case, you do not need to call |EVP_AEAD_CTX_cleanup|, but it's + * harmless to do so. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_init(EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, + const uint8_t *key, size_t key_len, + size_t tag_len, ENGINE *impl); + +/* EVP_AEAD_CTX_init_with_direction calls |EVP_AEAD_CTX_init| for normal + * AEADs. For TLS-specific and SSL3-specific AEADs, it initializes |ctx| for a + * given direction. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_init_with_direction( + EVP_AEAD_CTX *ctx, const EVP_AEAD *aead, const uint8_t *key, size_t key_len, + size_t tag_len, enum evp_aead_direction_t dir); + +/* EVP_AEAD_CTX_cleanup frees any data allocated by |ctx|. It is a no-op to + * call |EVP_AEAD_CTX_cleanup| on a |EVP_AEAD_CTX| that has been |memset| to + * all zeros. */ +OPENSSL_EXPORT void EVP_AEAD_CTX_cleanup(EVP_AEAD_CTX *ctx); + +/* EVP_AEAD_CTX_seal encrypts and authenticates |in_len| bytes from |in| and + * authenticates |ad_len| bytes from |ad| and writes the result to |out|. It + * returns one on success and zero otherwise. + * + * This function may be called (with the same |EVP_AEAD_CTX|) concurrently with + * itself or |EVP_AEAD_CTX_open|. + * + * At most |max_out_len| bytes are written to |out| and, in order to ensure + * success, |max_out_len| should be |in_len| plus the result of + * |EVP_AEAD_max_overhead|. On successful return, |*out_len| is set to the + * actual number of bytes written. + * + * The length of |nonce|, |nonce_len|, must be equal to the result of + * |EVP_AEAD_nonce_length| for this AEAD. + * + * |EVP_AEAD_CTX_seal| never results in a partial output. If |max_out_len| is + * insufficient, zero will be returned. (In this case, |*out_len| is set to + * zero.) + * + * If |in| and |out| alias then |out| must be <= |in|. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len); + +/* EVP_AEAD_CTX_open authenticates |in_len| bytes from |in| and |ad_len| bytes + * from |ad| and decrypts at most |in_len| bytes into |out|. It returns one on + * success and zero otherwise. + * + * This function may be called (with the same |EVP_AEAD_CTX|) concurrently with + * itself or |EVP_AEAD_CTX_seal|. + * + * At most |in_len| bytes are written to |out|. In order to ensure success, + * |max_out_len| should be at least |in_len|. On successful return, |*out_len| + * is set to the the actual number of bytes written. + * + * The length of |nonce|, |nonce_len|, must be equal to the result of + * |EVP_AEAD_nonce_length| for this AEAD. + * + * |EVP_AEAD_CTX_open| never results in a partial output. If |max_out_len| is + * insufficient, zero will be returned. (In this case, |*out_len| is set to + * zero.) + * + * If |in| and |out| alias then |out| must be <= |in|. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_open(const EVP_AEAD_CTX *ctx, uint8_t *out, + size_t *out_len, size_t max_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len); + + +/* Obscure functions. */ + +/* EVP_AEAD_CTX_get_rc4_state sets |*out_key| to point to an RC4 key structure. + * It returns one on success or zero if |ctx| doesn't have an RC4 key. */ +OPENSSL_EXPORT int EVP_AEAD_CTX_get_rc4_state(const EVP_AEAD_CTX *ctx, + const RC4_KEY **out_key); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_AEAD_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/aes.h b/TMessagesProj/jni/boringssl/include/openssl/aes.h new file mode 100644 index 00000000..cdec9406 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/aes.h @@ -0,0 +1,167 @@ +/* ==================================================================== + * Copyright (c) 2002-2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== */ + +#ifndef OPENSSL_HEADER_AES_H +#define OPENSSL_HEADER_AES_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Raw AES functions. */ + + +#define AES_ENCRYPT 1 +#define AES_DECRYPT 0 + +/* AES_MAXNR is the maximum number of AES rounds. */ +#define AES_MAXNR 14 + +#define AES_BLOCK_SIZE 16 + +/* aes_key_st should be an opaque type, but EVP requires that the size be + * known. */ +struct aes_key_st { + uint32_t rd_key[4 * (AES_MAXNR + 1)]; + unsigned rounds; +}; +typedef struct aes_key_st AES_KEY; + +/* AES_set_encrypt_key configures |aeskey| to encrypt with the |bits|-bit key, + * |key|. + * + * WARNING: unlike other OpenSSL functions, this returns zero on success and a + * negative number on error. */ +OPENSSL_EXPORT int AES_set_encrypt_key(const uint8_t *key, unsigned bits, + AES_KEY *aeskey); + +/* AES_set_decrypt_key configures |aeskey| to decrypt with the |bits|-bit key, + * |key|. + * + * WARNING: unlike other OpenSSL functions, this returns zero on success and a + * negative number on error. */ +OPENSSL_EXPORT int AES_set_decrypt_key(const uint8_t *key, unsigned bits, + AES_KEY *aeskey); + +/* AES_encrypt encrypts a single block from |in| to |out| with |key|. The |in| + * and |out| pointers may overlap. */ +OPENSSL_EXPORT void AES_encrypt(const uint8_t *in, uint8_t *out, + const AES_KEY *key); + +/* AES_decrypt decrypts a single block from |in| to |out| with |key|. The |in| + * and |out| pointers may overlap. */ +OPENSSL_EXPORT void AES_decrypt(const uint8_t *in, uint8_t *out, + const AES_KEY *key); + + +/* Block cipher modes. */ + +/* AES_ctr128_encrypt encrypts (or decrypts, it's the same in CTR mode) |len| + * bytes from |in| to |out|. The |num| parameter must be set to zero on the + * first call and |ivec| will be incremented. */ +OPENSSL_EXPORT void AES_ctr128_encrypt(const uint8_t *in, uint8_t *out, + size_t len, const AES_KEY *key, + uint8_t ivec[AES_BLOCK_SIZE], + uint8_t ecount_buf[AES_BLOCK_SIZE], + unsigned int *num); + +/* AES_ecb_encrypt encrypts (or decrypts, if |enc| == |AES_DECRYPT|) a single, + * 16 byte block from |in| to |out|. */ +OPENSSL_EXPORT void AES_ecb_encrypt(const uint8_t *in, uint8_t *out, + const AES_KEY *key, const int enc); + +/* AES_cbc_encrypt encrypts (or decrypts, if |enc| == |AES_DECRYPT|) |len| + * bytes from |in| to |out|. The length must be a multiple of the block size. */ +OPENSSL_EXPORT void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, uint8_t *ivec, + const int enc); + +/* AES_ofb128_encrypt encrypts (or decrypts, it's the same in OFB mode) |len| + * bytes from |in| to |out|. The |num| parameter must be set to zero on the + * first call. */ +OPENSSL_EXPORT void AES_ofb128_encrypt(const uint8_t *in, uint8_t *out, + size_t len, const AES_KEY *key, + uint8_t *ivec, int *num); + +/* AES_cfb128_encrypt encrypts (or decrypts, if |enc| == |AES_DECRYPT|) |len| + * bytes from |in| to |out|. The |num| parameter must be set to zero on the + * first call. */ +OPENSSL_EXPORT void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, + size_t len, const AES_KEY *key, + uint8_t *ivec, int *num, int enc); + +/* NB: the IV is _two_ blocks long */ +OPENSSL_EXPORT void AES_ige_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char *ivec, const int enc); +/* NB: the IV is _four_ blocks long */ +OPENSSL_EXPORT void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + const AES_KEY *key2, const unsigned char *ivec, + const int enc); + +/* Android compatibility section. + * + * These functions are declared, temporarily, for Android because + * wpa_supplicant will take a little time to sync with upstream. Outside of + * Android they'll have no definition. */ + +OPENSSL_EXPORT int AES_wrap_key(AES_KEY *key, const uint8_t *iv, uint8_t *out, + const uint8_t *in, unsigned in_len); +OPENSSL_EXPORT int AES_unwrap_key(AES_KEY *key, const uint8_t *iv, uint8_t *out, + const uint8_t *in, unsigned in_len); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_AES_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/asn1.h b/TMessagesProj/jni/boringssl/include/openssl/asn1.h new file mode 100644 index 00000000..401532ab --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/asn1.h @@ -0,0 +1,1169 @@ +/* crypto/asn1/asn1.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_ASN1_H +#define HEADER_ASN1_H + +#include + +#include + +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define V_ASN1_UNIVERSAL 0x00 +#define V_ASN1_APPLICATION 0x40 +#define V_ASN1_CONTEXT_SPECIFIC 0x80 +#define V_ASN1_PRIVATE 0xc0 + +#define V_ASN1_CONSTRUCTED 0x20 +#define V_ASN1_PRIMITIVE_TAG 0x1f +#define V_ASN1_PRIMATIVE_TAG 0x1f + +#define V_ASN1_APP_CHOOSE -2 /* let the recipient choose */ +#define V_ASN1_OTHER -3 /* used in ASN1_TYPE */ +#define V_ASN1_ANY -4 /* used in ASN1 template code */ + +#define V_ASN1_NEG 0x100 /* negative flag */ + +#define V_ASN1_UNDEF -1 +#define V_ASN1_EOC 0 +#define V_ASN1_BOOLEAN 1 /**/ +#define V_ASN1_INTEGER 2 +#define V_ASN1_NEG_INTEGER (2 | V_ASN1_NEG) +#define V_ASN1_BIT_STRING 3 +#define V_ASN1_OCTET_STRING 4 +#define V_ASN1_NULL 5 +#define V_ASN1_OBJECT 6 +#define V_ASN1_OBJECT_DESCRIPTOR 7 +#define V_ASN1_EXTERNAL 8 +#define V_ASN1_REAL 9 +#define V_ASN1_ENUMERATED 10 +#define V_ASN1_NEG_ENUMERATED (10 | V_ASN1_NEG) +#define V_ASN1_UTF8STRING 12 +#define V_ASN1_SEQUENCE 16 +#define V_ASN1_SET 17 +#define V_ASN1_NUMERICSTRING 18 /**/ +#define V_ASN1_PRINTABLESTRING 19 +#define V_ASN1_T61STRING 20 +#define V_ASN1_TELETEXSTRING 20 /* alias */ +#define V_ASN1_VIDEOTEXSTRING 21 /**/ +#define V_ASN1_IA5STRING 22 +#define V_ASN1_UTCTIME 23 +#define V_ASN1_GENERALIZEDTIME 24 /**/ +#define V_ASN1_GRAPHICSTRING 25 /**/ +#define V_ASN1_ISO64STRING 26 /**/ +#define V_ASN1_VISIBLESTRING 26 /* alias */ +#define V_ASN1_GENERALSTRING 27 /**/ +#define V_ASN1_UNIVERSALSTRING 28 /**/ +#define V_ASN1_BMPSTRING 30 + +/* For use with d2i_ASN1_type_bytes() */ +#define B_ASN1_NUMERICSTRING 0x0001 +#define B_ASN1_PRINTABLESTRING 0x0002 +#define B_ASN1_T61STRING 0x0004 +#define B_ASN1_TELETEXSTRING 0x0004 +#define B_ASN1_VIDEOTEXSTRING 0x0008 +#define B_ASN1_IA5STRING 0x0010 +#define B_ASN1_GRAPHICSTRING 0x0020 +#define B_ASN1_ISO64STRING 0x0040 +#define B_ASN1_VISIBLESTRING 0x0040 +#define B_ASN1_GENERALSTRING 0x0080 +#define B_ASN1_UNIVERSALSTRING 0x0100 +#define B_ASN1_OCTET_STRING 0x0200 +#define B_ASN1_BIT_STRING 0x0400 +#define B_ASN1_BMPSTRING 0x0800 +#define B_ASN1_UNKNOWN 0x1000 +#define B_ASN1_UTF8STRING 0x2000 +#define B_ASN1_UTCTIME 0x4000 +#define B_ASN1_GENERALIZEDTIME 0x8000 +#define B_ASN1_SEQUENCE 0x10000 + +/* For use with ASN1_mbstring_copy() */ +#define MBSTRING_FLAG 0x1000 +#define MBSTRING_UTF8 (MBSTRING_FLAG) +#define MBSTRING_ASC (MBSTRING_FLAG|1) +#define MBSTRING_BMP (MBSTRING_FLAG|2) +#define MBSTRING_UNIV (MBSTRING_FLAG|4) + +#define SMIME_OLDMIME 0x400 +#define SMIME_CRLFEOL 0x800 +#define SMIME_STREAM 0x1000 + +#define DECLARE_ASN1_SET_OF(type) /* filled in by mkstack.pl */ +#define IMPLEMENT_ASN1_SET_OF(type) /* nothing, no longer needed */ + +/* We MUST make sure that, except for constness, asn1_ctx_st and + asn1_const_ctx are exactly the same. Fortunately, as soon as + the old ASN1 parsing macros are gone, we can throw this away + as well... */ +typedef struct asn1_ctx_st + { + unsigned char *p;/* work char pointer */ + int eos; /* end of sequence read for indefinite encoding */ + int error; /* error code to use when returning an error */ + int inf; /* constructed if 0x20, indefinite is 0x21 */ + int tag; /* tag from last 'get object' */ + int xclass; /* class from last 'get object' */ + long slen; /* length of last 'get object' */ + unsigned char *max; /* largest value of p allowed */ + unsigned char *q;/* temporary variable */ + unsigned char **pp;/* variable */ + int line; /* used in error processing */ + } ASN1_CTX; + +typedef struct asn1_const_ctx_st + { + const unsigned char *p;/* work char pointer */ + int eos; /* end of sequence read for indefinite encoding */ + int error; /* error code to use when returning an error */ + int inf; /* constructed if 0x20, indefinite is 0x21 */ + int tag; /* tag from last 'get object' */ + int xclass; /* class from last 'get object' */ + long slen; /* length of last 'get object' */ + const unsigned char *max; /* largest value of p allowed */ + const unsigned char *q;/* temporary variable */ + const unsigned char **pp;/* variable */ + int line; /* used in error processing */ + } ASN1_const_CTX; + +/* These are used internally in the ASN1_OBJECT to keep track of + * whether the names and data need to be free()ed */ +#define ASN1_OBJECT_FLAG_DYNAMIC 0x01 /* internal use */ +#define ASN1_OBJECT_FLAG_CRITICAL 0x02 /* critical x509v3 object id */ +#define ASN1_OBJECT_FLAG_DYNAMIC_STRINGS 0x04 /* internal use */ +#define ASN1_OBJECT_FLAG_DYNAMIC_DATA 0x08 /* internal use */ +struct asn1_object_st + { + const char *sn,*ln; + int nid; + int length; + const unsigned char *data; /* data remains const after init */ + int flags; /* Should we free this one */ + }; + +#define ASN1_STRING_FLAG_BITS_LEFT 0x08 /* Set if 0x07 has bits left value */ +/* This indicates that the ASN1_STRING is not a real value but just a place + * holder for the location where indefinite length constructed data should + * be inserted in the memory buffer + */ +#define ASN1_STRING_FLAG_NDEF 0x010 + +/* This flag is used by the CMS code to indicate that a string is not + * complete and is a place holder for content when it had all been + * accessed. The flag will be reset when content has been written to it. + */ + +#define ASN1_STRING_FLAG_CONT 0x020 +/* This flag is used by ASN1 code to indicate an ASN1_STRING is an MSTRING + * type. + */ +#define ASN1_STRING_FLAG_MSTRING 0x040 +/* This is the base type that holds just about everything :-) */ +struct asn1_string_st + { + int length; + int type; + unsigned char *data; + /* The value of the following field depends on the type being + * held. It is mostly being used for BIT_STRING so if the + * input data has a non-zero 'unused bits' value, it will be + * handled correctly */ + long flags; + }; + +/* ASN1_ENCODING structure: this is used to save the received + * encoding of an ASN1 type. This is useful to get round + * problems with invalid encodings which can break signatures. + */ + +typedef struct ASN1_ENCODING_st + { + unsigned char *enc; /* DER encoding */ + long len; /* Length of encoding */ + int modified; /* set to 1 if 'enc' is invalid */ + } ASN1_ENCODING; + +/* Used with ASN1 LONG type: if a long is set to this it is omitted */ +#define ASN1_LONG_UNDEF 0x7fffffffL + +#define STABLE_FLAGS_MALLOC 0x01 +#define STABLE_NO_MASK 0x02 +#define DIRSTRING_TYPE \ + (B_ASN1_PRINTABLESTRING|B_ASN1_T61STRING|B_ASN1_BMPSTRING|B_ASN1_UTF8STRING) +#define PKCS9STRING_TYPE (DIRSTRING_TYPE|B_ASN1_IA5STRING) + +typedef struct asn1_string_table_st { + int nid; + long minsize; + long maxsize; + unsigned long mask; + unsigned long flags; +} ASN1_STRING_TABLE; + +/* size limits: this stuff is taken straight from RFC2459 */ + +#define ub_name 32768 +#define ub_common_name 64 +#define ub_locality_name 128 +#define ub_state_name 128 +#define ub_organization_name 64 +#define ub_organization_unit_name 64 +#define ub_title 64 +#define ub_email_address 128 + +/* Declarations for template structures: for full definitions + * see asn1t.h + */ +typedef struct ASN1_TEMPLATE_st ASN1_TEMPLATE; +typedef struct ASN1_TLC_st ASN1_TLC; +/* This is just an opaque pointer */ +typedef struct ASN1_VALUE_st ASN1_VALUE; + +/* Declare ASN1 functions: the implement macro in in asn1t.h */ + +#define DECLARE_ASN1_FUNCTIONS(type) DECLARE_ASN1_FUNCTIONS_name(type, type) + +#define DECLARE_ASN1_ALLOC_FUNCTIONS(type) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, type) + +#define DECLARE_ASN1_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS(type, name, name) + +#define DECLARE_ASN1_FUNCTIONS_fname(type, itname, name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) + +#define DECLARE_ASN1_ENCODE_FUNCTIONS(type, itname, name) \ + OPENSSL_EXPORT type *d2i_##name(type **a, const unsigned char **in, long len); \ + OPENSSL_EXPORT int i2d_##name(type *a, unsigned char **out); \ + DECLARE_ASN1_ITEM(itname) + +#define DECLARE_ASN1_ENCODE_FUNCTIONS_const(type, name) \ + OPENSSL_EXPORT type *d2i_##name(type **a, const unsigned char **in, long len); \ + OPENSSL_EXPORT int i2d_##name(const type *a, unsigned char **out); \ + DECLARE_ASN1_ITEM(name) + +#define DECLARE_ASN1_NDEF_FUNCTION(name) \ + OPENSSL_EXPORT int i2d_##name##_NDEF(name *a, unsigned char **out); + +#define DECLARE_ASN1_FUNCTIONS_const(name) \ + DECLARE_ASN1_ALLOC_FUNCTIONS(name) \ + DECLARE_ASN1_ENCODE_FUNCTIONS_const(name, name) + +#define DECLARE_ASN1_ALLOC_FUNCTIONS_name(type, name) \ + OPENSSL_EXPORT type *name##_new(void); \ + OPENSSL_EXPORT void name##_free(type *a); + +#define DECLARE_ASN1_PRINT_FUNCTION(stname) \ + DECLARE_ASN1_PRINT_FUNCTION_fname(stname, stname) + +#define DECLARE_ASN1_PRINT_FUNCTION_fname(stname, fname) \ + OPENSSL_EXPORT int fname##_print_ctx(BIO *out, stname *x, int indent, \ + const ASN1_PCTX *pctx); + +#define D2I_OF(type) type *(*)(type **,const unsigned char **,long) +#define I2D_OF(type) int (*)(type *,unsigned char **) +#define I2D_OF_const(type) int (*)(const type *,unsigned char **) + +#define CHECKED_D2I_OF(type, d2i) \ + ((d2i_of_void*) (1 ? d2i : ((D2I_OF(type))0))) +#define CHECKED_I2D_OF(type, i2d) \ + ((i2d_of_void*) (1 ? i2d : ((I2D_OF(type))0))) +#define CHECKED_NEW_OF(type, xnew) \ + ((void *(*)(void)) (1 ? xnew : ((type *(*)(void))0))) +#define CHECKED_PPTR_OF(type, p) \ + ((void**) (1 ? p : (type**)0)) + +#define TYPEDEF_D2I_OF(type) typedef type *d2i_of_##type(type **,const unsigned char **,long) +#define TYPEDEF_I2D_OF(type) typedef int i2d_of_##type(const type *,unsigned char **) +#define TYPEDEF_D2I2D_OF(type) TYPEDEF_D2I_OF(type); TYPEDEF_I2D_OF(type) + +TYPEDEF_D2I2D_OF(void); + +/* The following macros and typedefs allow an ASN1_ITEM + * to be embedded in a structure and referenced. Since + * the ASN1_ITEM pointers need to be globally accessible + * (possibly from shared libraries) they may exist in + * different forms. On platforms that support it the + * ASN1_ITEM structure itself will be globally exported. + * Other platforms will export a function that returns + * an ASN1_ITEM pointer. + * + * To handle both cases transparently the macros below + * should be used instead of hard coding an ASN1_ITEM + * pointer in a structure. + * + * The structure will look like this: + * + * typedef struct SOMETHING_st { + * ... + * ASN1_ITEM_EXP *iptr; + * ... + * } SOMETHING; + * + * It would be initialised as e.g.: + * + * SOMETHING somevar = {...,ASN1_ITEM_ref(X509),...}; + * + * and the actual pointer extracted with: + * + * const ASN1_ITEM *it = ASN1_ITEM_ptr(somevar.iptr); + * + * Finally an ASN1_ITEM pointer can be extracted from an + * appropriate reference with: ASN1_ITEM_rptr(X509). This + * would be used when a function takes an ASN1_ITEM * argument. + * + */ + +/* ASN1_ITEM pointer exported type */ +typedef const ASN1_ITEM ASN1_ITEM_EXP; + +/* Macro to obtain ASN1_ITEM pointer from exported type */ +#define ASN1_ITEM_ptr(iptr) (iptr) + +/* Macro to include ASN1_ITEM pointer from base type */ +#define ASN1_ITEM_ref(iptr) (&(iptr##_it)) + +#define ASN1_ITEM_rptr(ref) (&(ref##_it)) + +#define DECLARE_ASN1_ITEM(name) \ + extern OPENSSL_EXPORT const ASN1_ITEM name##_it; + +/* Parameters used by ASN1_STRING_print_ex() */ + +/* These determine which characters to escape: + * RFC2253 special characters, control characters and + * MSB set characters + */ + +#define ASN1_STRFLGS_ESC_2253 1 +#define ASN1_STRFLGS_ESC_CTRL 2 +#define ASN1_STRFLGS_ESC_MSB 4 + + +/* This flag determines how we do escaping: normally + * RC2253 backslash only, set this to use backslash and + * quote. + */ + +#define ASN1_STRFLGS_ESC_QUOTE 8 + + +/* These three flags are internal use only. */ + +/* Character is a valid PrintableString character */ +#define CHARTYPE_PRINTABLESTRING 0x10 +/* Character needs escaping if it is the first character */ +#define CHARTYPE_FIRST_ESC_2253 0x20 +/* Character needs escaping if it is the last character */ +#define CHARTYPE_LAST_ESC_2253 0x40 + +/* NB the internal flags are safely reused below by flags + * handled at the top level. + */ + +/* If this is set we convert all character strings + * to UTF8 first + */ + +#define ASN1_STRFLGS_UTF8_CONVERT 0x10 + +/* If this is set we don't attempt to interpret content: + * just assume all strings are 1 byte per character. This + * will produce some pretty odd looking output! + */ + +#define ASN1_STRFLGS_IGNORE_TYPE 0x20 + +/* If this is set we include the string type in the output */ +#define ASN1_STRFLGS_SHOW_TYPE 0x40 + +/* This determines which strings to display and which to + * 'dump' (hex dump of content octets or DER encoding). We can + * only dump non character strings or everything. If we + * don't dump 'unknown' they are interpreted as character + * strings with 1 octet per character and are subject to + * the usual escaping options. + */ + +#define ASN1_STRFLGS_DUMP_ALL 0x80 +#define ASN1_STRFLGS_DUMP_UNKNOWN 0x100 + +/* These determine what 'dumping' does, we can dump the + * content octets or the DER encoding: both use the + * RFC2253 #XXXXX notation. + */ + +#define ASN1_STRFLGS_DUMP_DER 0x200 + +/* All the string flags consistent with RFC2253, + * escaping control characters isn't essential in + * RFC2253 but it is advisable anyway. + */ + +#define ASN1_STRFLGS_RFC2253 (ASN1_STRFLGS_ESC_2253 | \ + ASN1_STRFLGS_ESC_CTRL | \ + ASN1_STRFLGS_ESC_MSB | \ + ASN1_STRFLGS_UTF8_CONVERT | \ + ASN1_STRFLGS_DUMP_UNKNOWN | \ + ASN1_STRFLGS_DUMP_DER) + +DECLARE_ASN1_SET_OF(ASN1_INTEGER) + +typedef struct asn1_type_st + { + int type; + union { + char *ptr; + ASN1_BOOLEAN boolean; + ASN1_STRING * asn1_string; + ASN1_OBJECT * object; + ASN1_INTEGER * integer; + ASN1_ENUMERATED * enumerated; + ASN1_BIT_STRING * bit_string; + ASN1_OCTET_STRING * octet_string; + ASN1_PRINTABLESTRING * printablestring; + ASN1_T61STRING * t61string; + ASN1_IA5STRING * ia5string; + ASN1_GENERALSTRING * generalstring; + ASN1_BMPSTRING * bmpstring; + ASN1_UNIVERSALSTRING * universalstring; + ASN1_UTCTIME * utctime; + ASN1_GENERALIZEDTIME * generalizedtime; + ASN1_VISIBLESTRING * visiblestring; + ASN1_UTF8STRING * utf8string; + /* set and sequence are left complete and still + * contain the set or sequence bytes */ + ASN1_STRING * set; + ASN1_STRING * sequence; + ASN1_VALUE * asn1_value; + } value; + } ASN1_TYPE; + +DECLARE_ASN1_SET_OF(ASN1_TYPE) + +typedef STACK_OF(ASN1_TYPE) ASN1_SEQUENCE_ANY; + +DECLARE_ASN1_ENCODE_FUNCTIONS_const(ASN1_SEQUENCE_ANY, ASN1_SEQUENCE_ANY) +DECLARE_ASN1_ENCODE_FUNCTIONS_const(ASN1_SEQUENCE_ANY, ASN1_SET_ANY) + +struct X509_algor_st + { + ASN1_OBJECT *algorithm; + ASN1_TYPE *parameter; + } /* X509_ALGOR */; + +DECLARE_ASN1_FUNCTIONS(X509_ALGOR) + +typedef struct NETSCAPE_X509_st + { + ASN1_OCTET_STRING *header; + X509 *cert; + } NETSCAPE_X509; + +/* This is used to contain a list of bit names */ +typedef struct BIT_STRING_BITNAME_st { + int bitnum; + const char *lname; + const char *sname; +} BIT_STRING_BITNAME; + + +#define M_ASN1_STRING_length(x) ((x)->length) +#define M_ASN1_STRING_length_set(x, n) ((x)->length = (n)) +#define M_ASN1_STRING_type(x) ((x)->type) +#define M_ASN1_STRING_data(x) ((x)->data) + +/* Macros for string operations */ +#define M_ASN1_BIT_STRING_new() (ASN1_BIT_STRING *)\ + ASN1_STRING_type_new(V_ASN1_BIT_STRING) +#define M_ASN1_BIT_STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_BIT_STRING_dup(a) (ASN1_BIT_STRING *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_ASN1_BIT_STRING_cmp(a,b) ASN1_STRING_cmp(\ + (const ASN1_STRING *)a,(const ASN1_STRING *)b) +#define M_ASN1_BIT_STRING_set(a,b,c) ASN1_STRING_set((ASN1_STRING *)a,b,c) + +#define M_ASN1_INTEGER_new() (ASN1_INTEGER *)\ + ASN1_STRING_type_new(V_ASN1_INTEGER) +#define M_ASN1_INTEGER_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_INTEGER_dup(a) (ASN1_INTEGER *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_ASN1_INTEGER_cmp(a,b) ASN1_STRING_cmp(\ + (const ASN1_STRING *)a,(const ASN1_STRING *)b) + +#define M_ASN1_ENUMERATED_new() (ASN1_ENUMERATED *)\ + ASN1_STRING_type_new(V_ASN1_ENUMERATED) +#define M_ASN1_ENUMERATED_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_ENUMERATED_dup(a) (ASN1_ENUMERATED *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_ASN1_ENUMERATED_cmp(a,b) ASN1_STRING_cmp(\ + (const ASN1_STRING *)a,(const ASN1_STRING *)b) + +#define M_ASN1_OCTET_STRING_new() (ASN1_OCTET_STRING *)\ + ASN1_STRING_type_new(V_ASN1_OCTET_STRING) +#define M_ASN1_OCTET_STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_OCTET_STRING_dup(a) (ASN1_OCTET_STRING *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_ASN1_OCTET_STRING_cmp(a,b) ASN1_STRING_cmp(\ + (const ASN1_STRING *)a,(const ASN1_STRING *)b) +#define M_ASN1_OCTET_STRING_set(a,b,c) ASN1_STRING_set((ASN1_STRING *)a,b,c) +#define M_ASN1_OCTET_STRING_print(a,b) ASN1_STRING_print(a,(ASN1_STRING *)b) +#define M_i2d_ASN1_OCTET_STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_OCTET_STRING,\ + V_ASN1_UNIVERSAL) + +#define B_ASN1_TIME \ + B_ASN1_UTCTIME | \ + B_ASN1_GENERALIZEDTIME + +#define B_ASN1_PRINTABLE \ + B_ASN1_NUMERICSTRING| \ + B_ASN1_PRINTABLESTRING| \ + B_ASN1_T61STRING| \ + B_ASN1_IA5STRING| \ + B_ASN1_BIT_STRING| \ + B_ASN1_UNIVERSALSTRING|\ + B_ASN1_BMPSTRING|\ + B_ASN1_UTF8STRING|\ + B_ASN1_SEQUENCE|\ + B_ASN1_UNKNOWN + +#define B_ASN1_DIRECTORYSTRING \ + B_ASN1_PRINTABLESTRING| \ + B_ASN1_TELETEXSTRING|\ + B_ASN1_BMPSTRING|\ + B_ASN1_UNIVERSALSTRING|\ + B_ASN1_UTF8STRING + +#define B_ASN1_DISPLAYTEXT \ + B_ASN1_IA5STRING| \ + B_ASN1_VISIBLESTRING| \ + B_ASN1_BMPSTRING|\ + B_ASN1_UTF8STRING + +#define M_ASN1_PRINTABLE_new() ASN1_STRING_type_new(V_ASN1_T61STRING) +#define M_ASN1_PRINTABLE_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_PRINTABLE(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ + pp,a->type,V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_PRINTABLE(a,pp,l) \ + d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ + B_ASN1_PRINTABLE) + +#define M_DIRECTORYSTRING_new() ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING) +#define M_DIRECTORYSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_DIRECTORYSTRING(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ + pp,a->type,V_ASN1_UNIVERSAL) +#define M_d2i_DIRECTORYSTRING(a,pp,l) \ + d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ + B_ASN1_DIRECTORYSTRING) + +#define M_DISPLAYTEXT_new() ASN1_STRING_type_new(V_ASN1_VISIBLESTRING) +#define M_DISPLAYTEXT_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_DISPLAYTEXT(a,pp) i2d_ASN1_bytes((ASN1_STRING *)a,\ + pp,a->type,V_ASN1_UNIVERSAL) +#define M_d2i_DISPLAYTEXT(a,pp,l) \ + d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l, \ + B_ASN1_DISPLAYTEXT) + +#define M_ASN1_PRINTABLESTRING_new() (ASN1_PRINTABLESTRING *)\ + ASN1_STRING_type_new(V_ASN1_PRINTABLESTRING) +#define M_ASN1_PRINTABLESTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_PRINTABLESTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_PRINTABLESTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_PRINTABLESTRING(a,pp,l) \ + (ASN1_PRINTABLESTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_PRINTABLESTRING) + +#define M_ASN1_T61STRING_new() (ASN1_T61STRING *)\ + ASN1_STRING_type_new(V_ASN1_T61STRING) +#define M_ASN1_T61STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_T61STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_T61STRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_T61STRING(a,pp,l) \ + (ASN1_T61STRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_T61STRING) + +#define M_ASN1_IA5STRING_new() (ASN1_IA5STRING *)\ + ASN1_STRING_type_new(V_ASN1_IA5STRING) +#define M_ASN1_IA5STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_IA5STRING_dup(a) \ + (ASN1_IA5STRING *)ASN1_STRING_dup((const ASN1_STRING *)a) +#define M_i2d_ASN1_IA5STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_IA5STRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_IA5STRING(a,pp,l) \ + (ASN1_IA5STRING *)d2i_ASN1_type_bytes((ASN1_STRING **)a,pp,l,\ + B_ASN1_IA5STRING) + +#define M_ASN1_UTCTIME_new() (ASN1_UTCTIME *)\ + ASN1_STRING_type_new(V_ASN1_UTCTIME) +#define M_ASN1_UTCTIME_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_UTCTIME_dup(a) (ASN1_UTCTIME *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) + +#define M_ASN1_GENERALIZEDTIME_new() (ASN1_GENERALIZEDTIME *)\ + ASN1_STRING_type_new(V_ASN1_GENERALIZEDTIME) +#define M_ASN1_GENERALIZEDTIME_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_GENERALIZEDTIME_dup(a) (ASN1_GENERALIZEDTIME *)ASN1_STRING_dup(\ + (const ASN1_STRING *)a) + +#define M_ASN1_TIME_new() (ASN1_TIME *)\ + ASN1_STRING_type_new(V_ASN1_UTCTIME) +#define M_ASN1_TIME_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_ASN1_TIME_dup(a) (ASN1_TIME *)\ + ASN1_STRING_dup((const ASN1_STRING *)a) + +#define M_ASN1_GENERALSTRING_new() (ASN1_GENERALSTRING *)\ + ASN1_STRING_type_new(V_ASN1_GENERALSTRING) +#define M_ASN1_GENERALSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_GENERALSTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_GENERALSTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_GENERALSTRING(a,pp,l) \ + (ASN1_GENERALSTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_GENERALSTRING) + +#define M_ASN1_UNIVERSALSTRING_new() (ASN1_UNIVERSALSTRING *)\ + ASN1_STRING_type_new(V_ASN1_UNIVERSALSTRING) +#define M_ASN1_UNIVERSALSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_UNIVERSALSTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UNIVERSALSTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_UNIVERSALSTRING(a,pp,l) \ + (ASN1_UNIVERSALSTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_UNIVERSALSTRING) + +#define M_ASN1_BMPSTRING_new() (ASN1_BMPSTRING *)\ + ASN1_STRING_type_new(V_ASN1_BMPSTRING) +#define M_ASN1_BMPSTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_BMPSTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_BMPSTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_BMPSTRING(a,pp,l) \ + (ASN1_BMPSTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_BMPSTRING) + +#define M_ASN1_VISIBLESTRING_new() (ASN1_VISIBLESTRING *)\ + ASN1_STRING_type_new(V_ASN1_VISIBLESTRING) +#define M_ASN1_VISIBLESTRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_VISIBLESTRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_VISIBLESTRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_VISIBLESTRING(a,pp,l) \ + (ASN1_VISIBLESTRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_VISIBLESTRING) + +#define M_ASN1_UTF8STRING_new() (ASN1_UTF8STRING *)\ + ASN1_STRING_type_new(V_ASN1_UTF8STRING) +#define M_ASN1_UTF8STRING_free(a) ASN1_STRING_free((ASN1_STRING *)a) +#define M_i2d_ASN1_UTF8STRING(a,pp) \ + i2d_ASN1_bytes((ASN1_STRING *)a,pp,V_ASN1_UTF8STRING,\ + V_ASN1_UNIVERSAL) +#define M_d2i_ASN1_UTF8STRING(a,pp,l) \ + (ASN1_UTF8STRING *)d2i_ASN1_type_bytes\ + ((ASN1_STRING **)a,pp,l,B_ASN1_UTF8STRING) + + /* for the is_set parameter to i2d_ASN1_SET */ +#define IS_SEQUENCE 0 +#define IS_SET 1 + +DECLARE_ASN1_FUNCTIONS_fname(ASN1_TYPE, ASN1_ANY, ASN1_TYPE) + +OPENSSL_EXPORT int ASN1_TYPE_get(ASN1_TYPE *a); +OPENSSL_EXPORT void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value); +OPENSSL_EXPORT int ASN1_TYPE_set1(ASN1_TYPE *a, int type, const void *value); +OPENSSL_EXPORT int ASN1_TYPE_cmp(const ASN1_TYPE *a, const ASN1_TYPE *b); + +OPENSSL_EXPORT ASN1_OBJECT * ASN1_OBJECT_new(void ); +OPENSSL_EXPORT void ASN1_OBJECT_free(ASN1_OBJECT *a); +OPENSSL_EXPORT int i2d_ASN1_OBJECT(ASN1_OBJECT *a,unsigned char **pp); +OPENSSL_EXPORT ASN1_OBJECT * c2i_ASN1_OBJECT(ASN1_OBJECT **a,const unsigned char **pp, + long length); +OPENSSL_EXPORT ASN1_OBJECT * d2i_ASN1_OBJECT(ASN1_OBJECT **a,const unsigned char **pp, + long length); + +DECLARE_ASN1_ITEM(ASN1_OBJECT) + +DECLARE_ASN1_SET_OF(ASN1_OBJECT) + +OPENSSL_EXPORT ASN1_STRING * ASN1_STRING_new(void); +OPENSSL_EXPORT void ASN1_STRING_free(ASN1_STRING *a); +OPENSSL_EXPORT int ASN1_STRING_copy(ASN1_STRING *dst, const ASN1_STRING *str); +OPENSSL_EXPORT ASN1_STRING * ASN1_STRING_dup(const ASN1_STRING *a); +OPENSSL_EXPORT ASN1_STRING * ASN1_STRING_type_new(int type ); +OPENSSL_EXPORT int ASN1_STRING_cmp(const ASN1_STRING *a, const ASN1_STRING *b); + /* Since this is used to store all sorts of things, via macros, for now, make + its data void * */ +OPENSSL_EXPORT int ASN1_STRING_set(ASN1_STRING *str, const void *data, int len); +OPENSSL_EXPORT void ASN1_STRING_set0(ASN1_STRING *str, void *data, int len); +OPENSSL_EXPORT int ASN1_STRING_length(const ASN1_STRING *x); +OPENSSL_EXPORT void ASN1_STRING_length_set(ASN1_STRING *x, int n); +OPENSSL_EXPORT int ASN1_STRING_type(ASN1_STRING *x); +OPENSSL_EXPORT unsigned char * ASN1_STRING_data(ASN1_STRING *x); + +DECLARE_ASN1_FUNCTIONS(ASN1_BIT_STRING) +OPENSSL_EXPORT int i2c_ASN1_BIT_STRING(ASN1_BIT_STRING *a,unsigned char **pp); +OPENSSL_EXPORT ASN1_BIT_STRING *c2i_ASN1_BIT_STRING(ASN1_BIT_STRING **a,const unsigned char **pp, long length); +OPENSSL_EXPORT int ASN1_BIT_STRING_set(ASN1_BIT_STRING *a, unsigned char *d, int length ); +OPENSSL_EXPORT int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *a, int n, int value); +OPENSSL_EXPORT int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *a, int n); +OPENSSL_EXPORT int ASN1_BIT_STRING_check(ASN1_BIT_STRING *a, unsigned char *flags, int flags_len); + +OPENSSL_EXPORT int ASN1_BIT_STRING_name_print(BIO *out, ASN1_BIT_STRING *bs, BIT_STRING_BITNAME *tbl, int indent); +OPENSSL_EXPORT int ASN1_BIT_STRING_num_asc(char *name, BIT_STRING_BITNAME *tbl); +OPENSSL_EXPORT int ASN1_BIT_STRING_set_asc(ASN1_BIT_STRING *bs, char *name, int value, BIT_STRING_BITNAME *tbl); + +OPENSSL_EXPORT int i2d_ASN1_BOOLEAN(int a,unsigned char **pp); +OPENSSL_EXPORT int d2i_ASN1_BOOLEAN(int *a,const unsigned char **pp,long length); + +DECLARE_ASN1_FUNCTIONS(ASN1_INTEGER) +OPENSSL_EXPORT int i2c_ASN1_INTEGER(ASN1_INTEGER *a,unsigned char **pp); +OPENSSL_EXPORT ASN1_INTEGER *c2i_ASN1_INTEGER(ASN1_INTEGER **a,const unsigned char **pp, long length); +OPENSSL_EXPORT ASN1_INTEGER *d2i_ASN1_UINTEGER(ASN1_INTEGER **a,const unsigned char **pp, long length); +OPENSSL_EXPORT ASN1_INTEGER * ASN1_INTEGER_dup(const ASN1_INTEGER *x); +OPENSSL_EXPORT int ASN1_INTEGER_cmp(const ASN1_INTEGER *x, const ASN1_INTEGER *y); + +DECLARE_ASN1_FUNCTIONS(ASN1_ENUMERATED) + +OPENSSL_EXPORT int ASN1_UTCTIME_check(const ASN1_UTCTIME *a); +OPENSSL_EXPORT ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *s,time_t t); +OPENSSL_EXPORT ASN1_UTCTIME *ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, int offset_day, long offset_sec); +OPENSSL_EXPORT int ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str); +OPENSSL_EXPORT int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t); +#if 0 +time_t ASN1_UTCTIME_get(const ASN1_UTCTIME *s); +#endif + +OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *a); +OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s,time_t t); +OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, time_t t, int offset_day, long offset_sec); +OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str); +OPENSSL_EXPORT int ASN1_TIME_diff(int *pday, int *psec, const ASN1_TIME *from, const ASN1_TIME *to); + +DECLARE_ASN1_FUNCTIONS(ASN1_OCTET_STRING) +OPENSSL_EXPORT ASN1_OCTET_STRING * ASN1_OCTET_STRING_dup(const ASN1_OCTET_STRING *a); +OPENSSL_EXPORT int ASN1_OCTET_STRING_cmp(const ASN1_OCTET_STRING *a, const ASN1_OCTET_STRING *b); +OPENSSL_EXPORT int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *str, const unsigned char *data, int len); + +DECLARE_ASN1_FUNCTIONS(ASN1_VISIBLESTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UNIVERSALSTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UTF8STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_NULL) +DECLARE_ASN1_FUNCTIONS(ASN1_BMPSTRING) + +OPENSSL_EXPORT int UTF8_getc(const unsigned char *str, int len, unsigned long *val); +OPENSSL_EXPORT int UTF8_putc(unsigned char *str, int len, unsigned long value); + +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, ASN1_PRINTABLE) + +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DIRECTORYSTRING) +DECLARE_ASN1_FUNCTIONS_name(ASN1_STRING, DISPLAYTEXT) +DECLARE_ASN1_FUNCTIONS(ASN1_PRINTABLESTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_T61STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_IA5STRING) +DECLARE_ASN1_FUNCTIONS(ASN1_GENERALSTRING) +DECLARE_ASN1_FUNCTIONS(ASN1_UTCTIME) +DECLARE_ASN1_FUNCTIONS(ASN1_GENERALIZEDTIME) +DECLARE_ASN1_FUNCTIONS(ASN1_TIME) + +DECLARE_ASN1_ITEM(ASN1_OCTET_STRING_NDEF) + +OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_set(ASN1_TIME *s,time_t t); +OPENSSL_EXPORT ASN1_TIME *ASN1_TIME_adj(ASN1_TIME *s,time_t t, int offset_day, long offset_sec); +OPENSSL_EXPORT int ASN1_TIME_check(ASN1_TIME *t); +OPENSSL_EXPORT ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out); +OPENSSL_EXPORT int ASN1_TIME_set_string(ASN1_TIME *s, const char *str); + +OPENSSL_EXPORT int i2d_ASN1_SET(STACK_OF(OPENSSL_BLOCK) *a, unsigned char **pp, i2d_of_void *i2d, int ex_tag, int ex_class, int is_set); +OPENSSL_EXPORT STACK_OF(OPENSSL_BLOCK) *d2i_ASN1_SET(STACK_OF(OPENSSL_BLOCK) **a, + const unsigned char **pp, + long length, d2i_of_void *d2i, + void (*free_func)(OPENSSL_BLOCK), int ex_tag, + int ex_class); + +OPENSSL_EXPORT int i2a_ASN1_INTEGER(BIO *bp, ASN1_INTEGER *a); +OPENSSL_EXPORT int a2i_ASN1_INTEGER(BIO *bp,ASN1_INTEGER *bs,char *buf,int size); +OPENSSL_EXPORT int i2a_ASN1_ENUMERATED(BIO *bp, ASN1_ENUMERATED *a); +OPENSSL_EXPORT int a2i_ASN1_ENUMERATED(BIO *bp,ASN1_ENUMERATED *bs,char *buf,int size); +OPENSSL_EXPORT int i2a_ASN1_OBJECT(BIO *bp,ASN1_OBJECT *a); +OPENSSL_EXPORT int a2i_ASN1_STRING(BIO *bp,ASN1_STRING *bs,char *buf,int size); +OPENSSL_EXPORT int i2a_ASN1_STRING(BIO *bp, ASN1_STRING *a, int type); +OPENSSL_EXPORT int i2t_ASN1_OBJECT(char *buf,int buf_len,ASN1_OBJECT *a); + +OPENSSL_EXPORT int a2d_ASN1_OBJECT(unsigned char *out,int olen, const char *buf, int num); +OPENSSL_EXPORT ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data,int len, const char *sn, const char *ln); + +OPENSSL_EXPORT int ASN1_INTEGER_set(ASN1_INTEGER *a, long v); +OPENSSL_EXPORT long ASN1_INTEGER_get(const ASN1_INTEGER *a); +OPENSSL_EXPORT ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai); +OPENSSL_EXPORT BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai,BIGNUM *bn); + +OPENSSL_EXPORT int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v); +OPENSSL_EXPORT long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a); +OPENSSL_EXPORT ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai); +OPENSSL_EXPORT BIGNUM *ASN1_ENUMERATED_to_BN(ASN1_ENUMERATED *ai,BIGNUM *bn); + +/* General */ +/* given a string, return the correct type, max is the maximum length */ +OPENSSL_EXPORT int ASN1_PRINTABLE_type(const unsigned char *s, int max); + +OPENSSL_EXPORT int i2d_ASN1_bytes(ASN1_STRING *a, unsigned char **pp, int tag, int xclass); +OPENSSL_EXPORT ASN1_STRING *d2i_ASN1_bytes(ASN1_STRING **a, const unsigned char **pp, long length, int Ptag, int Pclass); +OPENSSL_EXPORT unsigned long ASN1_tag2bit(int tag); +/* type is one or more of the B_ASN1_ values. */ +OPENSSL_EXPORT ASN1_STRING *d2i_ASN1_type_bytes(ASN1_STRING **a,const unsigned char **pp, long length,int type); + +/* PARSING */ +OPENSSL_EXPORT int asn1_Finish(ASN1_CTX *c); +OPENSSL_EXPORT int asn1_const_Finish(ASN1_const_CTX *c); + +/* SPECIALS */ +OPENSSL_EXPORT int ASN1_get_object(const unsigned char **pp, long *plength, int *ptag, int *pclass, long omax); +OPENSSL_EXPORT int ASN1_check_infinite_end(unsigned char **p,long len); +OPENSSL_EXPORT int ASN1_const_check_infinite_end(const unsigned char **p,long len); +OPENSSL_EXPORT void ASN1_put_object(unsigned char **pp, int constructed, int length, int tag, int xclass); +OPENSSL_EXPORT int ASN1_put_eoc(unsigned char **pp); +OPENSSL_EXPORT int ASN1_object_size(int constructed, int length, int tag); + +/* Used to implement other functions */ +OPENSSL_EXPORT void *ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, void *x); + +#define ASN1_dup_of(type,i2d,d2i,x) \ + ((type*)ASN1_dup(CHECKED_I2D_OF(type, i2d), \ + CHECKED_D2I_OF(type, d2i), \ + CHECKED_PTR_OF(type, x))) + +#define ASN1_dup_of_const(type,i2d,d2i,x) \ + ((type*)ASN1_dup(CHECKED_I2D_OF(const type, i2d), \ + CHECKED_D2I_OF(type, d2i), \ + CHECKED_PTR_OF(const type, x))) + +OPENSSL_EXPORT void *ASN1_item_dup(const ASN1_ITEM *it, void *x); + +/* ASN1 alloc/free macros for when a type is only used internally */ + +#define M_ASN1_new_of(type) (type *)ASN1_item_new(ASN1_ITEM_rptr(type)) +#define M_ASN1_free_of(x, type) \ + ASN1_item_free(CHECKED_PTR_OF(type, x), ASN1_ITEM_rptr(type)) + +#ifndef OPENSSL_NO_FP_API +OPENSSL_EXPORT void *ASN1_d2i_fp(void *(*xnew)(void), d2i_of_void *d2i, FILE *in, void **x); + +#define ASN1_d2i_fp_of(type,xnew,d2i,in,x) \ + ((type*)ASN1_d2i_fp(CHECKED_NEW_OF(type, xnew), \ + CHECKED_D2I_OF(type, d2i), \ + in, \ + CHECKED_PPTR_OF(type, x))) + +OPENSSL_EXPORT void *ASN1_item_d2i_fp(const ASN1_ITEM *it, FILE *in, void *x); +OPENSSL_EXPORT int ASN1_i2d_fp(i2d_of_void *i2d,FILE *out,void *x); + +#define ASN1_i2d_fp_of(type,i2d,out,x) \ + (ASN1_i2d_fp(CHECKED_I2D_OF(type, i2d), \ + out, \ + CHECKED_PTR_OF(type, x))) + +#define ASN1_i2d_fp_of_const(type,i2d,out,x) \ + (ASN1_i2d_fp(CHECKED_I2D_OF(const type, i2d), \ + out, \ + CHECKED_PTR_OF(const type, x))) + +OPENSSL_EXPORT int ASN1_item_i2d_fp(const ASN1_ITEM *it, FILE *out, void *x); +OPENSSL_EXPORT int ASN1_STRING_print_ex_fp(FILE *fp, ASN1_STRING *str, unsigned long flags); +#endif + +OPENSSL_EXPORT int ASN1_STRING_to_UTF8(unsigned char **out, ASN1_STRING *in); + +OPENSSL_EXPORT void *ASN1_d2i_bio(void *(*xnew)(void), d2i_of_void *d2i, BIO *in, void **x); + +#define ASN1_d2i_bio_of(type,xnew,d2i,in,x) \ + ((type*)ASN1_d2i_bio( CHECKED_NEW_OF(type, xnew), \ + CHECKED_D2I_OF(type, d2i), \ + in, \ + CHECKED_PPTR_OF(type, x))) + +OPENSSL_EXPORT void *ASN1_item_d2i_bio(const ASN1_ITEM *it, BIO *in, void *x); +OPENSSL_EXPORT int ASN1_i2d_bio(i2d_of_void *i2d,BIO *out, unsigned char *x); + +#define ASN1_i2d_bio_of(type,i2d,out,x) \ + (ASN1_i2d_bio(CHECKED_I2D_OF(type, i2d), \ + out, \ + CHECKED_PTR_OF(type, x))) + +#define ASN1_i2d_bio_of_const(type,i2d,out,x) \ + (ASN1_i2d_bio(CHECKED_I2D_OF(const type, i2d), \ + out, \ + CHECKED_PTR_OF(const type, x))) + +OPENSSL_EXPORT int ASN1_item_i2d_bio(const ASN1_ITEM *it, BIO *out, void *x); +OPENSSL_EXPORT int ASN1_UTCTIME_print(BIO *fp, const ASN1_UTCTIME *a); +OPENSSL_EXPORT int ASN1_GENERALIZEDTIME_print(BIO *fp, const ASN1_GENERALIZEDTIME *a); +OPENSSL_EXPORT int ASN1_TIME_print(BIO *fp, const ASN1_TIME *a); +OPENSSL_EXPORT int ASN1_STRING_print(BIO *bp, const ASN1_STRING *v); +OPENSSL_EXPORT int ASN1_STRING_print_ex(BIO *out, ASN1_STRING *str, unsigned long flags); +OPENSSL_EXPORT int ASN1_bn_print(BIO *bp, const char *number, const BIGNUM *num, unsigned char *buf, int off); +OPENSSL_EXPORT int ASN1_parse(BIO *bp,const unsigned char *pp,long len,int indent); +OPENSSL_EXPORT int ASN1_parse_dump(BIO *bp,const unsigned char *pp,long len,int indent,int dump); +OPENSSL_EXPORT const char *ASN1_tag2str(int tag); + +/* Used to load and write netscape format cert */ + +DECLARE_ASN1_FUNCTIONS(NETSCAPE_X509) + +int ASN1_UNIVERSALSTRING_to_string(ASN1_UNIVERSALSTRING *s); + +OPENSSL_EXPORT STACK_OF(OPENSSL_BLOCK) *ASN1_seq_unpack(const unsigned char *buf, int len, d2i_of_void *d2i, void (*free_func)(OPENSSL_BLOCK)); +OPENSSL_EXPORT unsigned char *ASN1_seq_pack(STACK_OF(OPENSSL_BLOCK) *safes, i2d_of_void *i2d, unsigned char **buf, int *len ); +OPENSSL_EXPORT void *ASN1_unpack_string(ASN1_STRING *oct, d2i_of_void *d2i); +OPENSSL_EXPORT void *ASN1_item_unpack(ASN1_STRING *oct, const ASN1_ITEM *it); +OPENSSL_EXPORT ASN1_STRING *ASN1_pack_string(void *obj, i2d_of_void *i2d, ASN1_OCTET_STRING **oct); + +#define ASN1_pack_string_of(type,obj,i2d,oct) \ + (ASN1_pack_string(CHECKED_PTR_OF(type, obj), \ + CHECKED_I2D_OF(type, i2d), \ + oct)) + +OPENSSL_EXPORT ASN1_STRING *ASN1_item_pack(void *obj, const ASN1_ITEM *it, ASN1_OCTET_STRING **oct); + +OPENSSL_EXPORT void ASN1_STRING_set_default_mask(unsigned long mask); +OPENSSL_EXPORT int ASN1_STRING_set_default_mask_asc(const char *p); +OPENSSL_EXPORT unsigned long ASN1_STRING_get_default_mask(void); +OPENSSL_EXPORT int ASN1_mbstring_copy(ASN1_STRING **out, const unsigned char *in, int len, int inform, unsigned long mask); +OPENSSL_EXPORT int ASN1_mbstring_ncopy(ASN1_STRING **out, const unsigned char *in, int len, int inform, unsigned long mask, long minsize, long maxsize); + +OPENSSL_EXPORT ASN1_STRING *ASN1_STRING_set_by_NID(ASN1_STRING **out, const unsigned char *in, int inlen, int inform, int nid); +OPENSSL_EXPORT ASN1_STRING_TABLE *ASN1_STRING_TABLE_get(int nid); +OPENSSL_EXPORT int ASN1_STRING_TABLE_add(int, long, long, unsigned long, unsigned long); +OPENSSL_EXPORT void ASN1_STRING_TABLE_cleanup(void); + +/* ASN1 template functions */ + +/* Old API compatible functions */ +OPENSSL_EXPORT ASN1_VALUE *ASN1_item_new(const ASN1_ITEM *it); +OPENSSL_EXPORT void ASN1_item_free(ASN1_VALUE *val, const ASN1_ITEM *it); +OPENSSL_EXPORT ASN1_VALUE * ASN1_item_d2i(ASN1_VALUE **val, const unsigned char **in, long len, const ASN1_ITEM *it); +OPENSSL_EXPORT int ASN1_item_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it); +OPENSSL_EXPORT int ASN1_item_ndef_i2d(ASN1_VALUE *val, unsigned char **out, const ASN1_ITEM *it); + +OPENSSL_EXPORT void ASN1_add_oid_module(void); + +OPENSSL_EXPORT ASN1_TYPE *ASN1_generate_nconf(char *str, CONF *nconf); +OPENSSL_EXPORT ASN1_TYPE *ASN1_generate_v3(char *str, X509V3_CTX *cnf); + +/* ASN1 Print flags */ + +/* Indicate missing OPTIONAL fields */ +#define ASN1_PCTX_FLAGS_SHOW_ABSENT 0x001 +/* Mark start and end of SEQUENCE */ +#define ASN1_PCTX_FLAGS_SHOW_SEQUENCE 0x002 +/* Mark start and end of SEQUENCE/SET OF */ +#define ASN1_PCTX_FLAGS_SHOW_SSOF 0x004 +/* Show the ASN1 type of primitives */ +#define ASN1_PCTX_FLAGS_SHOW_TYPE 0x008 +/* Don't show ASN1 type of ANY */ +#define ASN1_PCTX_FLAGS_NO_ANY_TYPE 0x010 +/* Don't show ASN1 type of MSTRINGs */ +#define ASN1_PCTX_FLAGS_NO_MSTRING_TYPE 0x020 +/* Don't show field names in SEQUENCE */ +#define ASN1_PCTX_FLAGS_NO_FIELD_NAME 0x040 +/* Show structure names of each SEQUENCE field */ +#define ASN1_PCTX_FLAGS_SHOW_FIELD_STRUCT_NAME 0x080 +/* Don't show structure name even at top level */ +#define ASN1_PCTX_FLAGS_NO_STRUCT_NAME 0x100 + +OPENSSL_EXPORT int ASN1_item_print(BIO *out, ASN1_VALUE *ifld, int indent, const ASN1_ITEM *it, const ASN1_PCTX *pctx); +OPENSSL_EXPORT ASN1_PCTX *ASN1_PCTX_new(void); +OPENSSL_EXPORT void ASN1_PCTX_free(ASN1_PCTX *p); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_flags(ASN1_PCTX *p, unsigned long flags); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_nm_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_nm_flags(ASN1_PCTX *p, unsigned long flags); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_cert_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_cert_flags(ASN1_PCTX *p, unsigned long flags); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_oid_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_oid_flags(ASN1_PCTX *p, unsigned long flags); +OPENSSL_EXPORT unsigned long ASN1_PCTX_get_str_flags(ASN1_PCTX *p); +OPENSSL_EXPORT void ASN1_PCTX_set_str_flags(ASN1_PCTX *p, unsigned long flags); + +OPENSSL_EXPORT const BIO_METHOD *BIO_f_asn1(void); + +OPENSSL_EXPORT BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it); + +OPENSSL_EXPORT int i2d_ASN1_bio_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags, const ASN1_ITEM *it); +OPENSSL_EXPORT int PEM_write_bio_ASN1_stream(BIO *out, ASN1_VALUE *val, BIO *in, int flags, const char *hdr, const ASN1_ITEM *it); +OPENSSL_EXPORT ASN1_VALUE *SMIME_read_ASN1(BIO *bio, BIO **bcont, const ASN1_ITEM *it); +OPENSSL_EXPORT int SMIME_crlf_copy(BIO *in, BIO *out, int flags); +OPENSSL_EXPORT int SMIME_text(BIO *in, BIO *out); + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_ASN1_strings(void); + +typedef int asn1_ps_func(BIO *b, unsigned char **pbuf, int *plen, void *parg); +OPENSSL_EXPORT int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free); +OPENSSL_EXPORT int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free); +OPENSSL_EXPORT int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, asn1_ps_func *suffix_free); +OPENSSL_EXPORT int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_func **psuffix_free); + +#ifdef __cplusplus +} +#endif + +#define ASN1_R_ASN1_LENGTH_MISMATCH 100 +#define ASN1_R_AUX_ERROR 101 +#define ASN1_R_BAD_GET_ASN1_OBJECT_CALL 102 +#define ASN1_R_BAD_OBJECT_HEADER 103 +#define ASN1_R_BMPSTRING_IS_WRONG_LENGTH 104 +#define ASN1_R_BN_LIB 105 +#define ASN1_R_BOOLEAN_IS_WRONG_LENGTH 106 +#define ASN1_R_BUFFER_TOO_SMALL 107 +#define ASN1_R_DECODE_ERROR 108 +#define ASN1_R_DEPTH_EXCEEDED 109 +#define ASN1_R_ENCODE_ERROR 110 +#define ASN1_R_ERROR_GETTING_TIME 111 +#define ASN1_R_EXPECTING_AN_ASN1_SEQUENCE 112 +#define ASN1_R_EXPECTING_AN_INTEGER 113 +#define ASN1_R_EXPECTING_AN_OBJECT 114 +#define ASN1_R_EXPECTING_A_BOOLEAN 115 +#define ASN1_R_EXPECTING_A_TIME 116 +#define ASN1_R_EXPLICIT_LENGTH_MISMATCH 117 +#define ASN1_R_EXPLICIT_TAG_NOT_CONSTRUCTED 118 +#define ASN1_R_FIELD_MISSING 119 +#define ASN1_R_FIRST_NUM_TOO_LARGE 120 +#define ASN1_R_HEADER_TOO_LONG 121 +#define ASN1_R_ILLEGAL_BITSTRING_FORMAT 122 +#define ASN1_R_ILLEGAL_BOOLEAN 123 +#define ASN1_R_ILLEGAL_CHARACTERS 124 +#define ASN1_R_ILLEGAL_FORMAT 125 +#define ASN1_R_ILLEGAL_HEX 126 +#define ASN1_R_ILLEGAL_IMPLICIT_TAG 127 +#define ASN1_R_ILLEGAL_INTEGER 128 +#define ASN1_R_ILLEGAL_NESTED_TAGGING 129 +#define ASN1_R_ILLEGAL_NULL 130 +#define ASN1_R_ILLEGAL_NULL_VALUE 131 +#define ASN1_R_ILLEGAL_OBJECT 132 +#define ASN1_R_ILLEGAL_OPTIONAL_ANY 133 +#define ASN1_R_ILLEGAL_OPTIONS_ON_ITEM_TEMPLATE 134 +#define ASN1_R_ILLEGAL_TAGGED_ANY 135 +#define ASN1_R_ILLEGAL_TIME_VALUE 136 +#define ASN1_R_INTEGER_NOT_ASCII_FORMAT 137 +#define ASN1_R_INTEGER_TOO_LARGE_FOR_LONG 138 +#define ASN1_R_INVALID_BIT_STRING_BITS_LEFT 139 +#define ASN1_R_INVALID_BMPSTRING_LENGTH 140 +#define ASN1_R_INVALID_DIGIT 141 +#define ASN1_R_INVALID_MODIFIER 142 +#define ASN1_R_INVALID_NUMBER 143 +#define ASN1_R_INVALID_OBJECT_ENCODING 144 +#define ASN1_R_INVALID_SEPARATOR 145 +#define ASN1_R_INVALID_TIME_FORMAT 146 +#define ASN1_R_INVALID_UNIVERSALSTRING_LENGTH 147 +#define ASN1_R_INVALID_UTF8STRING 148 +#define ASN1_R_LIST_ERROR 149 +#define ASN1_R_MALLOC_FAILURE 150 +#define ASN1_R_MISSING_ASN1_EOS 151 +#define ASN1_R_MISSING_EOC 152 +#define ASN1_R_MISSING_SECOND_NUMBER 153 +#define ASN1_R_MISSING_VALUE 154 +#define ASN1_R_MSTRING_NOT_UNIVERSAL 155 +#define ASN1_R_MSTRING_WRONG_TAG 156 +#define ASN1_R_NESTED_ASN1_ERROR 157 +#define ASN1_R_NESTED_ASN1_STRING 158 +#define ASN1_R_NON_HEX_CHARACTERS 159 +#define ASN1_R_NOT_ASCII_FORMAT 160 +#define ASN1_R_NOT_ENOUGH_DATA 161 +#define ASN1_R_NO_MATCHING_CHOICE_TYPE 162 +#define ASN1_R_NULL_IS_WRONG_LENGTH 163 +#define ASN1_R_OBJECT_NOT_ASCII_FORMAT 164 +#define ASN1_R_ODD_NUMBER_OF_CHARS 165 +#define ASN1_R_SECOND_NUMBER_TOO_LARGE 166 +#define ASN1_R_SEQUENCE_LENGTH_MISMATCH 167 +#define ASN1_R_SEQUENCE_NOT_CONSTRUCTED 168 +#define ASN1_R_SEQUENCE_OR_SET_NEEDS_CONFIG 169 +#define ASN1_R_SHORT_LINE 170 +#define ASN1_R_STREAMING_NOT_SUPPORTED 171 +#define ASN1_R_STRING_TOO_LONG 172 +#define ASN1_R_STRING_TOO_SHORT 173 +#define ASN1_R_TAG_VALUE_TOO_HIGH 174 +#define ASN1_R_TIME_NOT_ASCII_FORMAT 175 +#define ASN1_R_TOO_LONG 176 +#define ASN1_R_TYPE_NOT_CONSTRUCTED 177 +#define ASN1_R_TYPE_NOT_PRIMITIVE 178 +#define ASN1_R_UNEXPECTED_EOC 179 +#define ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH 180 +#define ASN1_R_UNKNOWN_FORMAT 181 +#define ASN1_R_UNKNOWN_TAG 182 +#define ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE 183 +#define ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE 184 +#define ASN1_R_UNSUPPORTED_TYPE 185 +#define ASN1_R_WRONG_TAG 186 +#define ASN1_R_WRONG_TYPE 187 + +#endif diff --git a/TMessagesProj/jni/boringssl/include/openssl/asn1_mac.h b/TMessagesProj/jni/boringssl/include/openssl/asn1_mac.h new file mode 100644 index 00000000..49b2a286 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/asn1_mac.h @@ -0,0 +1,76 @@ +/* crypto/asn1/asn1_mac.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_ASN1_MAC_H +#define HEADER_ASN1_MAC_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +OPENSSL_EXPORT int asn1_GetSequence(ASN1_const_CTX *c, long *length); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/TMessagesProj/jni/boringssl/include/openssl/asn1t.h b/TMessagesProj/jni/boringssl/include/openssl/asn1t.h new file mode 100644 index 00000000..0f2560b7 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/asn1t.h @@ -0,0 +1,907 @@ +/* asn1t.h */ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2000. + */ +/* ==================================================================== + * Copyright (c) 2000-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +#ifndef HEADER_ASN1T_H +#define HEADER_ASN1T_H + +#include +#include + +#ifdef OPENSSL_BUILD_SHLIBCRYPTO +# undef OPENSSL_EXTERN +# define OPENSSL_EXTERN OPENSSL_EXPORT +#endif + +/* ASN1 template defines, structures and functions */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Macro to obtain ASN1_ADB pointer from a type (only used internally) */ +#define ASN1_ADB_ptr(iptr) ((const ASN1_ADB *)(iptr)) + + +/* Macros for start and end of ASN1_ITEM definition */ + +#define ASN1_ITEM_start(itname) \ + const ASN1_ITEM itname##_it = { + +#define ASN1_ITEM_end(itname) \ + }; + +/* Macros to aid ASN1 template writing */ + +#define ASN1_ITEM_TEMPLATE(tname) \ + static const ASN1_TEMPLATE tname##_item_tt + +#define ASN1_ITEM_TEMPLATE_END(tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_PRIMITIVE,\ + -1,\ + &tname##_item_tt,\ + 0,\ + NULL,\ + 0,\ + #tname \ + ASN1_ITEM_end(tname) + + +/* This is a ASN1 type which just embeds a template */ + +/* This pair helps declare a SEQUENCE. We can do: + * + * ASN1_SEQUENCE(stname) = { + * ... SEQUENCE components ... + * } ASN1_SEQUENCE_END(stname) + * + * This will produce an ASN1_ITEM called stname_it + * for a structure called stname. + * + * If you want the same structure but a different + * name then use: + * + * ASN1_SEQUENCE(itname) = { + * ... SEQUENCE components ... + * } ASN1_SEQUENCE_END_name(stname, itname) + * + * This will create an item called itname_it using + * a structure called stname. + */ + +#define ASN1_SEQUENCE(tname) \ + static const ASN1_TEMPLATE tname##_seq_tt[] + +#define ASN1_SEQUENCE_END(stname) ASN1_SEQUENCE_END_name(stname, stname) + +#define ASN1_SEQUENCE_END_name(stname, tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +#define ASN1_NDEF_SEQUENCE(tname) \ + ASN1_SEQUENCE(tname) + +#define ASN1_NDEF_SEQUENCE_cb(tname, cb) \ + ASN1_SEQUENCE_cb(tname, cb) + +#define ASN1_SEQUENCE_cb(tname, cb) \ + static const ASN1_AUX tname##_aux = {NULL, 0, 0, cb, 0}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_BROKEN_SEQUENCE(tname) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_BROKEN, 0, 0, 0}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_SEQUENCE_ref(tname, cb) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_REFCOUNT, offsetof(tname, references), cb, 0}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_SEQUENCE_enc(tname, enc, cb) \ + static const ASN1_AUX tname##_aux = {NULL, ASN1_AFLG_ENCODING, 0, cb, offsetof(tname, enc)}; \ + ASN1_SEQUENCE(tname) + +#define ASN1_NDEF_SEQUENCE_END(tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_NDEF_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(tname),\ + #tname \ + ASN1_ITEM_end(tname) + +#define ASN1_BROKEN_SEQUENCE_END(stname) ASN1_SEQUENCE_END_ref(stname, stname) + +#define ASN1_SEQUENCE_END_enc(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname) + +#define ASN1_SEQUENCE_END_cb(stname, tname) ASN1_SEQUENCE_END_ref(stname, tname) + +#define ASN1_SEQUENCE_END_ref(stname, tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +#define ASN1_NDEF_SEQUENCE_END_cb(stname, tname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_NDEF_SEQUENCE,\ + V_ASN1_SEQUENCE,\ + tname##_seq_tt,\ + sizeof(tname##_seq_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + + +/* This pair helps declare a CHOICE type. We can do: + * + * ASN1_CHOICE(chname) = { + * ... CHOICE options ... + * ASN1_CHOICE_END(chname) + * + * This will produce an ASN1_ITEM called chname_it + * for a structure called chname. The structure + * definition must look like this: + * typedef struct { + * int type; + * union { + * ASN1_SOMETHING *opt1; + * ASN1_SOMEOTHER *opt2; + * } value; + * } chname; + * + * the name of the selector must be 'type'. + * to use an alternative selector name use the + * ASN1_CHOICE_END_selector() version. + */ + +#define ASN1_CHOICE(tname) \ + static const ASN1_TEMPLATE tname##_ch_tt[] + +#define ASN1_CHOICE_cb(tname, cb) \ + static const ASN1_AUX tname##_aux = {NULL, 0, 0, cb, 0}; \ + ASN1_CHOICE(tname) + +#define ASN1_CHOICE_END(stname) ASN1_CHOICE_END_name(stname, stname) + +#define ASN1_CHOICE_END_name(stname, tname) ASN1_CHOICE_END_selector(stname, tname, type) + +#define ASN1_CHOICE_END_selector(stname, tname, selname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_CHOICE,\ + offsetof(stname,selname) ,\ + tname##_ch_tt,\ + sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\ + NULL,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +#define ASN1_CHOICE_END_cb(stname, tname, selname) \ + ;\ + ASN1_ITEM_start(tname) \ + ASN1_ITYPE_CHOICE,\ + offsetof(stname,selname) ,\ + tname##_ch_tt,\ + sizeof(tname##_ch_tt) / sizeof(ASN1_TEMPLATE),\ + &tname##_aux,\ + sizeof(stname),\ + #stname \ + ASN1_ITEM_end(tname) + +/* This helps with the template wrapper form of ASN1_ITEM */ + +#define ASN1_EX_TEMPLATE_TYPE(flags, tag, name, type) { \ + (flags), (tag), 0,\ + #name, ASN1_ITEM_ref(type) } + +/* These help with SEQUENCE or CHOICE components */ + +/* used to declare other types */ + +#define ASN1_EX_TYPE(flags, tag, stname, field, type) { \ + (flags), (tag), offsetof(stname, field),\ + #field, ASN1_ITEM_ref(type) } + +/* used when the structure is combined with the parent */ + +#define ASN1_EX_COMBINE(flags, tag, type) { \ + (flags)|ASN1_TFLG_COMBINE, (tag), 0, NULL, ASN1_ITEM_ref(type) } + +/* implicit and explicit helper macros */ + +#define ASN1_IMP_EX(stname, field, type, tag, ex) \ + ASN1_EX_TYPE(ASN1_TFLG_IMPLICIT | ex, tag, stname, field, type) + +#define ASN1_EXP_EX(stname, field, type, tag, ex) \ + ASN1_EX_TYPE(ASN1_TFLG_EXPLICIT | ex, tag, stname, field, type) + +/* Any defined by macros: the field used is in the table itself */ + +#define ASN1_ADB_OBJECT(tblname) { ASN1_TFLG_ADB_OID, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) } +#define ASN1_ADB_INTEGER(tblname) { ASN1_TFLG_ADB_INT, -1, 0, #tblname, (const ASN1_ITEM *)&(tblname##_adb) } +/* Plain simple type */ +#define ASN1_SIMPLE(stname, field, type) ASN1_EX_TYPE(0,0, stname, field, type) + +/* OPTIONAL simple type */ +#define ASN1_OPT(stname, field, type) ASN1_EX_TYPE(ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* IMPLICIT tagged simple type */ +#define ASN1_IMP(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, 0) + +/* IMPLICIT tagged OPTIONAL simple type */ +#define ASN1_IMP_OPT(stname, field, type, tag) ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL) + +/* Same as above but EXPLICIT */ + +#define ASN1_EXP(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, 0) +#define ASN1_EXP_OPT(stname, field, type, tag) ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL) + +/* SEQUENCE OF type */ +#define ASN1_SEQUENCE_OF(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, stname, field, type) + +/* OPTIONAL SEQUENCE OF */ +#define ASN1_SEQUENCE_OF_OPT(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* Same as above but for SET OF */ + +#define ASN1_SET_OF(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SET_OF, 0, stname, field, type) + +#define ASN1_SET_OF_OPT(stname, field, type) \ + ASN1_EX_TYPE(ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL, 0, stname, field, type) + +/* Finally compound types of SEQUENCE, SET, IMPLICIT, EXPLICIT and OPTIONAL */ + +#define ASN1_IMP_SET_OF(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF) + +#define ASN1_EXP_SET_OF(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF) + +#define ASN1_IMP_SET_OF_OPT(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL) + +#define ASN1_EXP_SET_OF_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SET_OF|ASN1_TFLG_OPTIONAL) + +#define ASN1_IMP_SEQUENCE_OF(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF) + +#define ASN1_IMP_SEQUENCE_OF_OPT(stname, field, type, tag) \ + ASN1_IMP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL) + +#define ASN1_EXP_SEQUENCE_OF(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF) + +#define ASN1_EXP_SEQUENCE_OF_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_SEQUENCE_OF|ASN1_TFLG_OPTIONAL) + +/* EXPLICIT using indefinite length constructed form */ +#define ASN1_NDEF_EXP(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_NDEF) + +/* EXPLICIT OPTIONAL using indefinite length constructed form */ +#define ASN1_NDEF_EXP_OPT(stname, field, type, tag) \ + ASN1_EXP_EX(stname, field, type, tag, ASN1_TFLG_OPTIONAL|ASN1_TFLG_NDEF) + +/* Macros for the ASN1_ADB structure */ + +#define ASN1_ADB(name) \ + static const ASN1_ADB_TABLE name##_adbtbl[] + +#define ASN1_ADB_END(name, flags, field, app_table, def, none) \ + ;\ + static const ASN1_ADB name##_adb = {\ + flags,\ + offsetof(name, field),\ + app_table,\ + name##_adbtbl,\ + sizeof(name##_adbtbl) / sizeof(ASN1_ADB_TABLE),\ + def,\ + none\ + } + +#define ADB_ENTRY(val, template) {val, template} + +#define ASN1_ADB_TEMPLATE(name) \ + static const ASN1_TEMPLATE name##_tt + +/* This is the ASN1 template structure that defines + * a wrapper round the actual type. It determines the + * actual position of the field in the value structure, + * various flags such as OPTIONAL and the field name. + */ + +struct ASN1_TEMPLATE_st { +unsigned long flags; /* Various flags */ +long tag; /* tag, not used if no tagging */ +unsigned long offset; /* Offset of this field in structure */ +#ifndef NO_ASN1_FIELD_NAMES +const char *field_name; /* Field name */ +#endif +ASN1_ITEM_EXP *item; /* Relevant ASN1_ITEM or ASN1_ADB */ +}; + +/* Macro to extract ASN1_ITEM and ASN1_ADB pointer from ASN1_TEMPLATE */ + +#define ASN1_TEMPLATE_item(t) (t->item_ptr) +#define ASN1_TEMPLATE_adb(t) (t->item_ptr) + +typedef struct ASN1_ADB_TABLE_st ASN1_ADB_TABLE; +typedef struct ASN1_ADB_st ASN1_ADB; + +struct ASN1_ADB_st { + unsigned long flags; /* Various flags */ + unsigned long offset; /* Offset of selector field */ + STACK_OF(ASN1_ADB_TABLE) **app_items; /* Application defined items */ + const ASN1_ADB_TABLE *tbl; /* Table of possible types */ + long tblcount; /* Number of entries in tbl */ + const ASN1_TEMPLATE *default_tt; /* Type to use if no match */ + const ASN1_TEMPLATE *null_tt; /* Type to use if selector is NULL */ +}; + +struct ASN1_ADB_TABLE_st { + long value; /* NID for an object or value for an int */ + const ASN1_TEMPLATE tt; /* item for this value */ +}; + +/* template flags */ + +/* Field is optional */ +#define ASN1_TFLG_OPTIONAL (0x1) + +/* Field is a SET OF */ +#define ASN1_TFLG_SET_OF (0x1 << 1) + +/* Field is a SEQUENCE OF */ +#define ASN1_TFLG_SEQUENCE_OF (0x2 << 1) + +/* Special case: this refers to a SET OF that + * will be sorted into DER order when encoded *and* + * the corresponding STACK will be modified to match + * the new order. + */ +#define ASN1_TFLG_SET_ORDER (0x3 << 1) + +/* Mask for SET OF or SEQUENCE OF */ +#define ASN1_TFLG_SK_MASK (0x3 << 1) + +/* These flags mean the tag should be taken from the + * tag field. If EXPLICIT then the underlying type + * is used for the inner tag. + */ + +/* IMPLICIT tagging */ +#define ASN1_TFLG_IMPTAG (0x1 << 3) + + +/* EXPLICIT tagging, inner tag from underlying type */ +#define ASN1_TFLG_EXPTAG (0x2 << 3) + +#define ASN1_TFLG_TAG_MASK (0x3 << 3) + +/* context specific IMPLICIT */ +#define ASN1_TFLG_IMPLICIT ASN1_TFLG_IMPTAG|ASN1_TFLG_CONTEXT + +/* context specific EXPLICIT */ +#define ASN1_TFLG_EXPLICIT ASN1_TFLG_EXPTAG|ASN1_TFLG_CONTEXT + +/* If tagging is in force these determine the + * type of tag to use. Otherwise the tag is + * determined by the underlying type. These + * values reflect the actual octet format. + */ + +/* Universal tag */ +#define ASN1_TFLG_UNIVERSAL (0x0<<6) +/* Application tag */ +#define ASN1_TFLG_APPLICATION (0x1<<6) +/* Context specific tag */ +#define ASN1_TFLG_CONTEXT (0x2<<6) +/* Private tag */ +#define ASN1_TFLG_PRIVATE (0x3<<6) + +#define ASN1_TFLG_TAG_CLASS (0x3<<6) + +/* These are for ANY DEFINED BY type. In this case + * the 'item' field points to an ASN1_ADB structure + * which contains a table of values to decode the + * relevant type + */ + +#define ASN1_TFLG_ADB_MASK (0x3<<8) + +#define ASN1_TFLG_ADB_OID (0x1<<8) + +#define ASN1_TFLG_ADB_INT (0x1<<9) + +/* This flag means a parent structure is passed + * instead of the field: this is useful is a + * SEQUENCE is being combined with a CHOICE for + * example. Since this means the structure and + * item name will differ we need to use the + * ASN1_CHOICE_END_name() macro for example. + */ + +#define ASN1_TFLG_COMBINE (0x1<<10) + +/* This flag when present in a SEQUENCE OF, SET OF + * or EXPLICIT causes indefinite length constructed + * encoding to be used if required. + */ + +#define ASN1_TFLG_NDEF (0x1<<11) + +/* This is the actual ASN1 item itself */ + +struct ASN1_ITEM_st { +char itype; /* The item type, primitive, SEQUENCE, CHOICE or extern */ +long utype; /* underlying type */ +const ASN1_TEMPLATE *templates; /* If SEQUENCE or CHOICE this contains the contents */ +long tcount; /* Number of templates if SEQUENCE or CHOICE */ +const void *funcs; /* functions that handle this type */ +long size; /* Structure size (usually)*/ +#ifndef NO_ASN1_FIELD_NAMES +const char *sname; /* Structure name */ +#endif +}; + +/* These are values for the itype field and + * determine how the type is interpreted. + * + * For PRIMITIVE types the underlying type + * determines the behaviour if items is NULL. + * + * Otherwise templates must contain a single + * template and the type is treated in the + * same way as the type specified in the template. + * + * For SEQUENCE types the templates field points + * to the members, the size field is the + * structure size. + * + * For CHOICE types the templates field points + * to each possible member (typically a union) + * and the 'size' field is the offset of the + * selector. + * + * The 'funcs' field is used for application + * specific functions. + * + * For COMPAT types the funcs field gives a + * set of functions that handle this type, this + * supports the old d2i, i2d convention. + * + * The EXTERN type uses a new style d2i/i2d. + * The new style should be used where possible + * because it avoids things like the d2i IMPLICIT + * hack. + * + * MSTRING is a multiple string type, it is used + * for a CHOICE of character strings where the + * actual strings all occupy an ASN1_STRING + * structure. In this case the 'utype' field + * has a special meaning, it is used as a mask + * of acceptable types using the B_ASN1 constants. + * + * NDEF_SEQUENCE is the same as SEQUENCE except + * that it will use indefinite length constructed + * encoding if requested. + * + */ + +#define ASN1_ITYPE_PRIMITIVE 0x0 + +#define ASN1_ITYPE_SEQUENCE 0x1 + +#define ASN1_ITYPE_CHOICE 0x2 + +#define ASN1_ITYPE_COMPAT 0x3 + +#define ASN1_ITYPE_EXTERN 0x4 + +#define ASN1_ITYPE_MSTRING 0x5 + +#define ASN1_ITYPE_NDEF_SEQUENCE 0x6 + +/* Cache for ASN1 tag and length, so we + * don't keep re-reading it for things + * like CHOICE + */ + +struct ASN1_TLC_st{ + char valid; /* Values below are valid */ + int ret; /* return value */ + long plen; /* length */ + int ptag; /* class value */ + int pclass; /* class value */ + int hdrlen; /* header length */ +}; + +/* Typedefs for ASN1 function pointers */ + +typedef ASN1_VALUE * ASN1_new_func(void); +typedef void ASN1_free_func(ASN1_VALUE *a); +typedef ASN1_VALUE * ASN1_d2i_func(ASN1_VALUE **a, const unsigned char ** in, long length); +typedef int ASN1_i2d_func(ASN1_VALUE * a, unsigned char **in); + +typedef int ASN1_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx); + +typedef int ASN1_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass); +typedef int ASN1_ex_new_func(ASN1_VALUE **pval, const ASN1_ITEM *it); +typedef void ASN1_ex_free_func(ASN1_VALUE **pval, const ASN1_ITEM *it); + +typedef int ASN1_ex_print_func(BIO *out, ASN1_VALUE **pval, + int indent, const char *fname, + const ASN1_PCTX *pctx); + +typedef int ASN1_primitive_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it); +typedef int ASN1_primitive_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it); +typedef int ASN1_primitive_print(BIO *out, ASN1_VALUE **pval, const ASN1_ITEM *it, int indent, const ASN1_PCTX *pctx); + +typedef struct ASN1_COMPAT_FUNCS_st { + ASN1_new_func *asn1_new; + ASN1_free_func *asn1_free; + ASN1_d2i_func *asn1_d2i; + ASN1_i2d_func *asn1_i2d; +} ASN1_COMPAT_FUNCS; + +typedef struct ASN1_EXTERN_FUNCS_st { + void *app_data; + ASN1_ex_new_func *asn1_ex_new; + ASN1_ex_free_func *asn1_ex_free; + ASN1_ex_free_func *asn1_ex_clear; + ASN1_ex_d2i *asn1_ex_d2i; + ASN1_ex_i2d *asn1_ex_i2d; + ASN1_ex_print_func *asn1_ex_print; +} ASN1_EXTERN_FUNCS; + +typedef struct ASN1_PRIMITIVE_FUNCS_st { + void *app_data; + unsigned long flags; + ASN1_ex_new_func *prim_new; + ASN1_ex_free_func *prim_free; + ASN1_ex_free_func *prim_clear; + ASN1_primitive_c2i *prim_c2i; + ASN1_primitive_i2c *prim_i2c; + ASN1_primitive_print *prim_print; +} ASN1_PRIMITIVE_FUNCS; + +/* This is the ASN1_AUX structure: it handles various + * miscellaneous requirements. For example the use of + * reference counts and an informational callback. + * + * The "informational callback" is called at various + * points during the ASN1 encoding and decoding. It can + * be used to provide minor customisation of the structures + * used. This is most useful where the supplied routines + * *almost* do the right thing but need some extra help + * at a few points. If the callback returns zero then + * it is assumed a fatal error has occurred and the + * main operation should be abandoned. + * + * If major changes in the default behaviour are required + * then an external type is more appropriate. + */ + +typedef int ASN1_aux_cb(int operation, ASN1_VALUE **in, const ASN1_ITEM *it, + void *exarg); + +typedef struct ASN1_AUX_st { + void *app_data; + int flags; + int ref_offset; /* Offset of reference value */ + ASN1_aux_cb *asn1_cb; + int enc_offset; /* Offset of ASN1_ENCODING structure */ +} ASN1_AUX; + +/* For print related callbacks exarg points to this structure */ +typedef struct ASN1_PRINT_ARG_st { + BIO *out; + int indent; + const ASN1_PCTX *pctx; +} ASN1_PRINT_ARG; + +/* For streaming related callbacks exarg points to this structure */ +typedef struct ASN1_STREAM_ARG_st { + /* BIO to stream through */ + BIO *out; + /* BIO with filters appended */ + BIO *ndef_bio; + /* Streaming I/O boundary */ + unsigned char **boundary; +} ASN1_STREAM_ARG; + +/* Flags in ASN1_AUX */ + +/* Use a reference count */ +#define ASN1_AFLG_REFCOUNT 1 +/* Save the encoding of structure (useful for signatures) */ +#define ASN1_AFLG_ENCODING 2 +/* The Sequence length is invalid */ +#define ASN1_AFLG_BROKEN 4 + +/* operation values for asn1_cb */ + +#define ASN1_OP_NEW_PRE 0 +#define ASN1_OP_NEW_POST 1 +#define ASN1_OP_FREE_PRE 2 +#define ASN1_OP_FREE_POST 3 +#define ASN1_OP_D2I_PRE 4 +#define ASN1_OP_D2I_POST 5 +#define ASN1_OP_I2D_PRE 6 +#define ASN1_OP_I2D_POST 7 +#define ASN1_OP_PRINT_PRE 8 +#define ASN1_OP_PRINT_POST 9 +#define ASN1_OP_STREAM_PRE 10 +#define ASN1_OP_STREAM_POST 11 +#define ASN1_OP_DETACHED_PRE 12 +#define ASN1_OP_DETACHED_POST 13 + +/* Macro to implement a primitive type */ +#define IMPLEMENT_ASN1_TYPE(stname) IMPLEMENT_ASN1_TYPE_ex(stname, stname, 0) +#define IMPLEMENT_ASN1_TYPE_ex(itname, vname, ex) \ + ASN1_ITEM_start(itname) \ + ASN1_ITYPE_PRIMITIVE, V_##vname, NULL, 0, NULL, ex, #itname \ + ASN1_ITEM_end(itname) + +/* Macro to implement a multi string type */ +#define IMPLEMENT_ASN1_MSTRING(itname, mask) \ + ASN1_ITEM_start(itname) \ + ASN1_ITYPE_MSTRING, mask, NULL, 0, NULL, sizeof(ASN1_STRING), #itname \ + ASN1_ITEM_end(itname) + +/* Macro to implement an ASN1_ITEM in terms of old style funcs */ + +#define IMPLEMENT_COMPAT_ASN1(sname) IMPLEMENT_COMPAT_ASN1_type(sname, V_ASN1_SEQUENCE) + +#define IMPLEMENT_COMPAT_ASN1_type(sname, tag) \ + static const ASN1_COMPAT_FUNCS sname##_ff = { \ + (ASN1_new_func *)sname##_new, \ + (ASN1_free_func *)sname##_free, \ + (ASN1_d2i_func *)d2i_##sname, \ + (ASN1_i2d_func *)i2d_##sname, \ + }; \ + ASN1_ITEM_start(sname) \ + ASN1_ITYPE_COMPAT, \ + tag, \ + NULL, \ + 0, \ + &sname##_ff, \ + 0, \ + #sname \ + ASN1_ITEM_end(sname) + +#define IMPLEMENT_EXTERN_ASN1(sname, tag, fptrs) \ + ASN1_ITEM_start(sname) \ + ASN1_ITYPE_EXTERN, \ + tag, \ + NULL, \ + 0, \ + &fptrs, \ + 0, \ + #sname \ + ASN1_ITEM_end(sname) + +/* Macro to implement standard functions in terms of ASN1_ITEM structures */ + +#define IMPLEMENT_ASN1_FUNCTIONS(stname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, stname, stname) + +#define IMPLEMENT_ASN1_FUNCTIONS_name(stname, itname) IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, itname) + +#define IMPLEMENT_ASN1_FUNCTIONS_ENCODE_name(stname, itname) \ + IMPLEMENT_ASN1_FUNCTIONS_ENCODE_fname(stname, itname, itname) + +#define IMPLEMENT_STATIC_ASN1_ALLOC_FUNCTIONS(stname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(static, stname, stname, stname) + +#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS(stname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, stname, stname) + +#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_pfname(pre, stname, itname, fname) \ + pre stname *fname##_new(void) \ + { \ + return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \ + } \ + pre void fname##_free(stname *a) \ + { \ + ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \ + } + +#define IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) \ + stname *fname##_new(void) \ + { \ + return (stname *)ASN1_item_new(ASN1_ITEM_rptr(itname)); \ + } \ + void fname##_free(stname *a) \ + { \ + ASN1_item_free((ASN1_VALUE *)a, ASN1_ITEM_rptr(itname)); \ + } + +#define IMPLEMENT_ASN1_FUNCTIONS_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) + +#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_fname(stname, itname, fname) \ + stname *d2i_##fname(stname **a, const unsigned char **in, long len) \ + { \ + return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\ + } \ + int i2d_##fname(stname *a, unsigned char **out) \ + { \ + return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\ + } + +#define IMPLEMENT_ASN1_NDEF_FUNCTION(stname) \ + int i2d_##stname##_NDEF(stname *a, unsigned char **out) \ + { \ + return ASN1_item_ndef_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(stname));\ + } + +/* This includes evil casts to remove const: they will go away when full + * ASN1 constification is done. + */ +#define IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \ + stname *d2i_##fname(stname **a, const unsigned char **in, long len) \ + { \ + return (stname *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, ASN1_ITEM_rptr(itname));\ + } \ + int i2d_##fname(const stname *a, unsigned char **out) \ + { \ + return ASN1_item_i2d((ASN1_VALUE *)a, out, ASN1_ITEM_rptr(itname));\ + } + +#define IMPLEMENT_ASN1_DUP_FUNCTION(stname) \ + stname * stname##_dup(stname *x) \ + { \ + return ASN1_item_dup(ASN1_ITEM_rptr(stname), x); \ + } + +#define IMPLEMENT_ASN1_PRINT_FUNCTION(stname) \ + IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, stname, stname) + +#define IMPLEMENT_ASN1_PRINT_FUNCTION_fname(stname, itname, fname) \ + int fname##_print_ctx(BIO *out, stname *x, int indent, \ + const ASN1_PCTX *pctx) \ + { \ + return ASN1_item_print(out, (ASN1_VALUE *)x, indent, \ + ASN1_ITEM_rptr(itname), pctx); \ + } + +#define IMPLEMENT_ASN1_FUNCTIONS_const(name) \ + IMPLEMENT_ASN1_FUNCTIONS_const_fname(name, name, name) + +#define IMPLEMENT_ASN1_FUNCTIONS_const_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(stname, itname, fname) \ + IMPLEMENT_ASN1_ALLOC_FUNCTIONS_fname(stname, itname, fname) + +/* external definitions for primitive types */ + +DECLARE_ASN1_ITEM(ASN1_BOOLEAN) +DECLARE_ASN1_ITEM(ASN1_TBOOLEAN) +DECLARE_ASN1_ITEM(ASN1_FBOOLEAN) +DECLARE_ASN1_ITEM(ASN1_SEQUENCE) +DECLARE_ASN1_ITEM(CBIGNUM) +DECLARE_ASN1_ITEM(BIGNUM) +DECLARE_ASN1_ITEM(LONG) +DECLARE_ASN1_ITEM(ZLONG) + +DECLARE_STACK_OF(ASN1_VALUE) + +/* Functions used internally by the ASN1 code */ + +int ASN1_item_ex_new(ASN1_VALUE **pval, const ASN1_ITEM *it); +void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it); +int ASN1_template_new(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); +int ASN1_primitive_new(ASN1_VALUE **pval, const ASN1_ITEM *it); + +void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); +int ASN1_template_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_TEMPLATE *tt); +int ASN1_item_ex_d2i(ASN1_VALUE **pval, const unsigned char **in, long len, const ASN1_ITEM *it, + int tag, int aclass, char opt, ASN1_TLC *ctx); + +int ASN1_item_ex_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_ITEM *it, int tag, int aclass); +int ASN1_template_i2d(ASN1_VALUE **pval, unsigned char **out, const ASN1_TEMPLATE *tt); +void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it); + +int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cont, int *putype, const ASN1_ITEM *it); +int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len, int utype, char *free_cont, const ASN1_ITEM *it); + +int asn1_get_choice_selector(ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_set_choice_selector(ASN1_VALUE **pval, int value, const ASN1_ITEM *it); + +ASN1_VALUE ** asn1_get_field_ptr(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt); + +const ASN1_TEMPLATE *asn1_do_adb(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt, int nullerr); + +void asn1_refcount_set_one(ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_refcount_dec_and_test_zero(ASN1_VALUE **pval, const ASN1_ITEM *it); + +void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it); +void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_enc_restore(int *len, unsigned char **out, ASN1_VALUE **pval, const ASN1_ITEM *it); +int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen, const ASN1_ITEM *it); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/TMessagesProj/jni/boringssl/include/openssl/base.h b/TMessagesProj/jni/boringssl/include/openssl/base.h new file mode 100644 index 00000000..8468b778 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/base.h @@ -0,0 +1,257 @@ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_BASE_H +#define OPENSSL_HEADER_BASE_H + + +/* This file should be the first included by all BoringSSL headers. */ + +#include +#include +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#if defined(__x86_64) || defined(_M_AMD64) || defined(_M_X64) +#define OPENSSL_64_BIT +#define OPENSSL_X86_64 +#elif defined(__x86) || defined(__i386) || defined(__i386__) || defined(_M_IX86) +#define OPENSSL_32_BIT +#define OPENSSL_X86 +#elif defined(__aarch64__) +#define OPENSSL_64_BIT +#define OPENSSL_AARCH64 +#elif defined(__arm) || defined(__arm__) || defined(_M_ARM) +#define OPENSSL_32_BIT +#define OPENSSL_ARM +#elif defined(__PPC64__) || defined(__powerpc64__) +#define OPENSSL_64_BIT +#elif defined(__mips__) && !defined(__LP64__) +#define OPENSSL_32_BIT +#define OPENSSL_MIPS +#elif defined(__mips__) && defined(__LP64__) +#define OPENSSL_64_BIT +#define OPENSSL_MIPS64 +#elif defined(__pnacl__) +#define OPENSSL_32_BIT +#define OPENSSL_PNACL +#else +#error "Unknown target CPU" +#endif + +#if defined(__APPLE__) +#define OPENSSL_APPLE +#endif + +#if defined(_WIN32) +#define OPENSSL_WINDOWS +#endif + +#if defined(TRUSTY) +#define OPENSSL_TRUSTY +#define OPENSSL_NO_THREADS +#endif + +#define OPENSSL_IS_BORINGSSL +#define OPENSSL_VERSION_NUMBER 0x10002000 +#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER + +#if defined(BORINGSSL_SHARED_LIBRARY) + +#if defined(OPENSSL_WINDOWS) + +#if defined(BORINGSSL_IMPLEMENTATION) +#define OPENSSL_EXPORT __declspec(dllexport) +#else +#define OPENSSL_EXPORT __declspec(dllimport) +#endif + +#else /* defined(OPENSSL_WINDOWS) */ + +#if defined(BORINGSSL_IMPLEMENTATION) +#define OPENSSL_EXPORT __attribute__((visibility("default"))) +#else +#define OPENSSL_EXPORT +#endif + +#endif /* defined(OPENSSL_WINDOWS) */ + +#else /* defined(BORINGSSL_SHARED_LIBRARY) */ + +#define OPENSSL_EXPORT + +#endif /* defined(BORINGSSL_SHARED_LIBRARY) */ + +/* CRYPTO_THREADID is a dummy value. */ +typedef int CRYPTO_THREADID; + +typedef int ASN1_BOOLEAN; +typedef int ASN1_NULL; +typedef struct ASN1_ITEM_st ASN1_ITEM; +typedef struct asn1_object_st ASN1_OBJECT; +typedef struct asn1_pctx_st ASN1_PCTX; +typedef struct asn1_string_st ASN1_BIT_STRING; +typedef struct asn1_string_st ASN1_BMPSTRING; +typedef struct asn1_string_st ASN1_ENUMERATED; +typedef struct asn1_string_st ASN1_GENERALIZEDTIME; +typedef struct asn1_string_st ASN1_GENERALSTRING; +typedef struct asn1_string_st ASN1_IA5STRING; +typedef struct asn1_string_st ASN1_INTEGER; +typedef struct asn1_string_st ASN1_OCTET_STRING; +typedef struct asn1_string_st ASN1_PRINTABLESTRING; +typedef struct asn1_string_st ASN1_STRING; +typedef struct asn1_string_st ASN1_T61STRING; +typedef struct asn1_string_st ASN1_TIME; +typedef struct asn1_string_st ASN1_UNIVERSALSTRING; +typedef struct asn1_string_st ASN1_UTCTIME; +typedef struct asn1_string_st ASN1_UTF8STRING; +typedef struct asn1_string_st ASN1_VISIBLESTRING; + +typedef struct AUTHORITY_KEYID_st AUTHORITY_KEYID; +typedef struct DIST_POINT_st DIST_POINT; +typedef struct ISSUING_DIST_POINT_st ISSUING_DIST_POINT; +typedef struct NAME_CONSTRAINTS_st NAME_CONSTRAINTS; +typedef struct Netscape_certificate_sequence NETSCAPE_CERT_SEQUENCE; +typedef struct Netscape_spkac_st NETSCAPE_SPKAC; +typedef struct Netscape_spki_st NETSCAPE_SPKI; +typedef struct PBE2PARAM_st PBE2PARAM; +typedef struct PBEPARAM_st PBEPARAM; +typedef struct PBKDF2PARAM_st PBKDF2PARAM; +typedef struct X509_POLICY_CACHE_st X509_POLICY_CACHE; +typedef struct X509_POLICY_LEVEL_st X509_POLICY_LEVEL; +typedef struct X509_POLICY_NODE_st X509_POLICY_NODE; +typedef struct X509_POLICY_TREE_st X509_POLICY_TREE; +typedef struct X509_algor_st X509_ALGOR; +typedef struct X509_crl_info_st X509_CRL_INFO; +typedef struct X509_crl_st X509_CRL; +typedef struct X509_extension_st X509_EXTENSION; +typedef struct X509_info_st X509_INFO; +typedef struct X509_name_entry_st X509_NAME_ENTRY; +typedef struct X509_name_st X509_NAME; +typedef struct X509_objects_st X509_OBJECTS; +typedef struct X509_pubkey_st X509_PUBKEY; +typedef struct X509_req_info_st X509_REQ_INFO; +typedef struct X509_req_st X509_REQ; +typedef struct X509_sig_st X509_SIG; +typedef struct X509_val_st X509_VAL; +typedef struct bignum_ctx BN_CTX; +typedef struct bignum_st BIGNUM; +typedef struct bio_method_st BIO_METHOD; +typedef struct bio_st BIO; +typedef struct bn_gencb_st BN_GENCB; +typedef struct bn_mont_ctx_st BN_MONT_CTX; +typedef struct buf_mem_st BUF_MEM; +typedef struct cbb_st CBB; +typedef struct cbs_st CBS; +typedef struct cmac_ctx_st CMAC_CTX; +typedef struct conf_st CONF; +typedef struct conf_value_st CONF_VALUE; +typedef struct dh_method DH_METHOD; +typedef struct dh_st DH; +typedef struct dsa_method DSA_METHOD; +typedef struct dsa_st DSA; +typedef struct ec_key_st EC_KEY; +typedef struct ecdsa_method_st ECDSA_METHOD; +typedef struct ecdsa_sig_st ECDSA_SIG; +typedef struct engine_st ENGINE; +typedef struct env_md_ctx_st EVP_MD_CTX; +typedef struct env_md_st EVP_MD; +typedef struct evp_aead_st EVP_AEAD; +typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX; +typedef struct evp_cipher_st EVP_CIPHER; +typedef struct evp_pkey_asn1_method_st EVP_PKEY_ASN1_METHOD; +typedef struct evp_pkey_ctx_st EVP_PKEY_CTX; +typedef struct evp_pkey_method_st EVP_PKEY_METHOD; +typedef struct evp_pkey_st EVP_PKEY; +typedef struct hmac_ctx_st HMAC_CTX; +typedef struct md4_state_st MD4_CTX; +typedef struct md5_state_st MD5_CTX; +typedef struct pkcs12_st PKCS12; +typedef struct pkcs8_priv_key_info_st PKCS8_PRIV_KEY_INFO; +typedef struct private_key_st X509_PKEY; +typedef struct rand_meth_st RAND_METHOD; +typedef struct rc4_key_st RC4_KEY; +typedef struct rsa_meth_st RSA_METHOD; +typedef struct rsa_st RSA; +typedef struct sha256_state_st SHA256_CTX; +typedef struct sha512_state_st SHA512_CTX; +typedef struct sha_state_st SHA_CTX; +typedef struct ssl_ctx_st SSL_CTX; +typedef struct ssl_custom_extension SSL_CUSTOM_EXTENSION; +typedef struct ssl_st SSL; +typedef struct st_ERR_FNS ERR_FNS; +typedef struct v3_ext_ctx X509V3_CTX; +typedef struct x509_attributes_st X509_ATTRIBUTE; +typedef struct x509_cert_aux_st X509_CERT_AUX; +typedef struct x509_cert_pair_st X509_CERT_PAIR; +typedef struct x509_cinf_st X509_CINF; +typedef struct x509_crl_method_st X509_CRL_METHOD; +typedef struct x509_revoked_st X509_REVOKED; +typedef struct x509_st X509; +typedef struct x509_store_ctx_st X509_STORE_CTX; +typedef struct x509_store_st X509_STORE; +typedef struct x509_trust_st X509_TRUST; + +typedef void *OPENSSL_BLOCK; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BASE_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/base64.h b/TMessagesProj/jni/boringssl/include/openssl/base64.h new file mode 100644 index 00000000..7aee9907 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/base64.h @@ -0,0 +1,179 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BASE64_H +#define OPENSSL_HEADER_BASE64_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* base64 functions. + * + * For historical reasons, these functions have the EVP_ prefix but just do + * base64 encoding and decoding. */ + + +typedef struct evp_encode_ctx_st EVP_ENCODE_CTX; + + +/* Encoding */ + +/* EVP_EncodeInit initialises |*ctx|, which is typically stack + * allocated, for an encoding operation. + * + * NOTE: The encoding operation breaks its output with newlines every + * 64 characters of output (48 characters of input). Use + * EVP_EncodeBlock to encode raw base64. */ +OPENSSL_EXPORT void EVP_EncodeInit(EVP_ENCODE_CTX *ctx); + +/* EVP_EncodeUpdate encodes |in_len| bytes from |in| and writes an encoded + * version of them to |out| and sets |*out_len| to the number of bytes written. + * Some state may be contained in |ctx| so |EVP_EncodeFinal| must be used to + * flush it before using the encoded data. */ +OPENSSL_EXPORT void EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + size_t in_len); + +/* EVP_EncodeFinal flushes any remaining output bytes from |ctx| to |out| and + * sets |*out_len| to the number of bytes written. */ +OPENSSL_EXPORT void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, + int *out_len); + +/* EVP_EncodeBlock encodes |src_len| bytes from |src| and writes the + * result to |dst| with a trailing NUL. It returns the number of bytes + * written, not including this trailing NUL. */ +OPENSSL_EXPORT size_t EVP_EncodeBlock(uint8_t *dst, const uint8_t *src, + size_t src_len); + +/* EVP_EncodedLength sets |*out_len| to the number of bytes that will be needed + * to call |EVP_EncodeBlock| on an input of length |len|. This includes the + * final NUL that |EVP_EncodeBlock| writes. It returns one on success or zero + * on error. */ +OPENSSL_EXPORT int EVP_EncodedLength(size_t *out_len, size_t len); + + +/* Decoding */ + +/* EVP_DecodedLength sets |*out_len| to the maximum number of bytes + * that will be needed to call |EVP_DecodeBase64| on an input of + * length |len|. */ +OPENSSL_EXPORT int EVP_DecodedLength(size_t *out_len, size_t len); + +/* EVP_DecodeBase64 decodes |in_len| bytes from base64 and writes + * |*out_len| bytes to |out|. |max_out| is the size of the output + * buffer. If it is not enough for the maximum output size, the + * operation fails. */ +OPENSSL_EXPORT int EVP_DecodeBase64(uint8_t *out, size_t *out_len, + size_t max_out, const uint8_t *in, + size_t in_len); + +/* EVP_DecodeInit initialises |*ctx|, which is typically stack allocated, for + * a decoding operation. + * + * TODO(davidben): This isn't a straight-up base64 decode either. Document + * and/or fix exactly what's going on here; maximum line length and such. */ +OPENSSL_EXPORT void EVP_DecodeInit(EVP_ENCODE_CTX *ctx); + +/* EVP_DecodeUpdate decodes |in_len| bytes from |in| and writes the decoded + * data to |out| and sets |*out_len| to the number of bytes written. Some state + * may be contained in |ctx| so |EVP_DecodeFinal| must be used to flush it + * before using the encoded data. + * + * It returns -1 on error, one if a full line of input was processed and zero + * if the line was short (i.e. it was the last line). */ +OPENSSL_EXPORT int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + size_t in_len); + +/* EVP_DecodeFinal flushes any remaining output bytes from |ctx| to |out| and + * sets |*out_len| to the number of bytes written. It returns one on success + * and minus one on error. */ +OPENSSL_EXPORT int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, uint8_t *out, + int *out_len); + +/* Deprecated: EVP_DecodeBlock encodes |src_len| bytes from |src| and + * writes the result to |dst|. It returns the number of bytes written + * or -1 on error. + * + * WARNING: EVP_DecodeBlock's return value does not take padding into + * account. It also strips leading whitespace and trailing + * whitespace. */ +OPENSSL_EXPORT int EVP_DecodeBlock(uint8_t *dst, const uint8_t *src, + size_t src_len); + + +struct evp_encode_ctx_st { + unsigned num; /* number saved in a partial encode/decode */ + unsigned length; /* The length is either the output line length + * (in input bytes) or the shortest input line + * length that is ok. Once decoding begins, + * the length is adjusted up each time a longer + * line is decoded */ + uint8_t enc_data[80]; /* data to encode */ + unsigned line_num; /* number read on current line */ + int expect_nl; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BASE64_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/bio.h b/TMessagesProj/jni/boringssl/include/openssl/bio.h new file mode 100644 index 00000000..a3c1f62e --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/bio.h @@ -0,0 +1,904 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BIO_H +#define OPENSSL_HEADER_BIO_H + +#include + +#include /* For FILE */ + +#include /* for ERR_print_errors_fp */ +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* BIO abstracts over a file-descriptor like interface. */ + + +/* Allocation and freeing. */ + +/* BIO_new creates a new BIO with the given type and a reference count of one. + * It returns the fresh |BIO|, or NULL on error. */ +OPENSSL_EXPORT BIO *BIO_new(const BIO_METHOD *type); + +/* BIO_free decrements the reference count of |bio|. If the reference count + * drops to zero, it (optionally) calls the BIO's callback with |BIO_CB_FREE|, + * frees the ex_data and then, if the BIO has a destroy callback for the + * method, calls it. Finally it frees |bio| itself. It then repeats that for + * the next BIO in the chain, if any. + * + * It returns one on success or zero otherwise. */ +OPENSSL_EXPORT int BIO_free(BIO *bio); + +/* BIO_vfree performs the same actions as |BIO_free|, but has a void return + * value. This is provided for API-compat. + * + * TODO(fork): remove. */ +OPENSSL_EXPORT void BIO_vfree(BIO *bio); + +/* BIO_up_ref increments the reference count of |bio| and returns it. */ +OPENSSL_EXPORT BIO *BIO_up_ref(BIO *bio); + + +/* Basic I/O. */ + +/* BIO_read attempts to read |len| bytes into |data|. It returns the number of + * bytes read, zero on EOF, or a negative number on error. */ +OPENSSL_EXPORT int BIO_read(BIO *bio, void *data, int len); + +/* BIO_gets "reads a line" from |bio| and puts at most |size| bytes into |buf|. + * It returns the number of bytes read or a negative number on error. The + * phrase "reads a line" is in quotes in the previous sentence because the + * exact operation depends on the BIO's method. For example, a digest BIO will + * return the digest in response to a |BIO_gets| call. + * + * TODO(fork): audit the set of BIOs that we end up needing. If all actually + * return a line for this call, remove the warning above. */ +OPENSSL_EXPORT int BIO_gets(BIO *bio, char *buf, int size); + +/* BIO_write writes |len| bytes from |data| to BIO. It returns the number of + * bytes written or a negative number on error. */ +OPENSSL_EXPORT int BIO_write(BIO *bio, const void *data, int len); + +/* BIO_puts writes a NUL terminated string from |buf| to |bio|. It returns the + * number of bytes written or a negative number on error. */ +OPENSSL_EXPORT int BIO_puts(BIO *bio, const char *buf); + +/* BIO_flush flushes any buffered output. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int BIO_flush(BIO *bio); + + +/* Low-level control functions. + * + * These are generic functions for sending control requests to a BIO. In + * general one should use the wrapper functions like |BIO_get_close|. */ + +/* BIO_ctrl sends the control request |cmd| to |bio|. The |cmd| argument should + * be one of the |BIO_C_*| values. */ +OPENSSL_EXPORT long BIO_ctrl(BIO *bio, int cmd, long larg, void *parg); + +/* BIO_ptr_ctrl acts like |BIO_ctrl| but passes the address of a |void*| + * pointer as |parg| and returns the value that is written to it, or NULL if + * the control request returns <= 0. */ +OPENSSL_EXPORT char *BIO_ptr_ctrl(BIO *bp, int cmd, long larg); + +/* BIO_int_ctrl acts like |BIO_ctrl| but passes the address of a copy of |iarg| + * as |parg|. */ +OPENSSL_EXPORT long BIO_int_ctrl(BIO *bp, int cmd, long larg, int iarg); + +/* BIO_reset resets |bio| to its initial state, the precise meaning of which + * depends on the concrete type of |bio|. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int BIO_reset(BIO *bio); + +/* BIO_set_flags ORs |flags| with |bio->flags|. */ +OPENSSL_EXPORT void BIO_set_flags(BIO *bio, int flags); + +/* BIO_test_flags returns |bio->flags| AND |flags|. */ +OPENSSL_EXPORT int BIO_test_flags(const BIO *bio, int flags); + +/* BIO_should_read returns non-zero if |bio| encountered a temporary error + * while reading (i.e. EAGAIN), indicating that the caller should retry the + * read. */ +OPENSSL_EXPORT int BIO_should_read(const BIO *bio); + +/* BIO_should_write returns non-zero if |bio| encountered a temporary error + * while writing (i.e. EAGAIN), indicating that the caller should retry the + * write. */ +OPENSSL_EXPORT int BIO_should_write(const BIO *bio); + +/* BIO_should_retry returns non-zero if the reason that caused a failed I/O + * operation is temporary and thus the operation should be retried. Otherwise, + * it was a permanent error and it returns zero. */ +OPENSSL_EXPORT int BIO_should_retry(const BIO *bio); + +/* BIO_should_io_special returns non-zero if |bio| encountered a temporary + * error while performing a special I/O operation, indicating that the caller + * should retry. The operation that caused the error is returned by + * |BIO_get_retry_reason|. */ +OPENSSL_EXPORT int BIO_should_io_special(const BIO *bio); + +/* BIO_RR_SSL_X509_LOOKUP indicates that an SSL BIO blocked because the SSL + * library returned with SSL_ERROR_WANT_X509_LOOKUP. + * + * TODO(fork): remove. */ +#define BIO_RR_SSL_X509_LOOKUP 0x01 + +/* BIO_RR_CONNECT indicates that a connect would have blocked */ +#define BIO_RR_CONNECT 0x02 + +/* BIO_RR_ACCEPT indicates that an accept would have blocked */ +#define BIO_RR_ACCEPT 0x03 + +/* BIO_RR_SSL_CHANNEL_ID_LOOKUP indicates that the ChannelID code cannot find + * a private key for a TLS connection. */ +#define BIO_RR_SSL_CHANNEL_ID_LOOKUP 0x04 + +/* BIO_get_retry_reason returns the special I/O operation that needs to be + * retried. The return value is one of the |BIO_RR_*| values. */ +OPENSSL_EXPORT int BIO_get_retry_reason(const BIO *bio); + +/* BIO_clear_flags ANDs |bio->flags| with the bitwise-complement of |flags|. */ +OPENSSL_EXPORT void BIO_clear_flags(BIO *bio, int flags); + +/* BIO_set_retry_read sets the |BIO_FLAGS_READ| and |BIO_FLAGS_SHOULD_RETRY| + * flags on |bio|. */ +OPENSSL_EXPORT void BIO_set_retry_read(BIO *bio); + +/* BIO_set_retry_write sets the |BIO_FLAGS_WRITE| and |BIO_FLAGS_SHOULD_RETRY| + * flags on |bio|. */ +OPENSSL_EXPORT void BIO_set_retry_write(BIO *bio); + +/* BIO_get_retry_flags gets the |BIO_FLAGS_READ|, |BIO_FLAGS_WRITE|, + * |BIO_FLAGS_IO_SPECIAL| and |BIO_FLAGS_SHOULD_RETRY| flags from |bio|. */ +OPENSSL_EXPORT int BIO_get_retry_flags(BIO *bio); + +/* BIO_clear_retry_flags clears the |BIO_FLAGS_READ|, |BIO_FLAGS_WRITE|, + * |BIO_FLAGS_IO_SPECIAL| and |BIO_FLAGS_SHOULD_RETRY| flags from |bio|. */ +OPENSSL_EXPORT void BIO_clear_retry_flags(BIO *bio); + +/* BIO_method_type returns the type of |bio|, which is one of the |BIO_TYPE_*| + * values. */ +OPENSSL_EXPORT int BIO_method_type(const BIO *bio); + +/* bio_info_cb is the type of a callback function that can be called for most + * BIO operations. The |event| argument is one of |BIO_CB_*| and can be ORed + * with |BIO_CB_RETURN| if the callback is being made after the operation in + * question. In that case, |return_value| will contain the return value from + * the operation. */ +typedef long (*bio_info_cb)(BIO *bio, int event, const char *parg, int cmd, + long larg, long return_value); + +/* BIO_callback_ctrl allows the callback function to be manipulated. The |cmd| + * arg will generally be |BIO_CTRL_SET_CALLBACK| but arbitary command values + * can be interpreted by the |BIO|. */ +OPENSSL_EXPORT long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp); + +/* BIO_pending returns the number of bytes pending to be read. */ +OPENSSL_EXPORT size_t BIO_pending(const BIO *bio); + +/* BIO_ctrl_pending calls |BIO_pending| and exists only for compatibility with + * OpenSSL. */ +OPENSSL_EXPORT size_t BIO_ctrl_pending(const BIO *bio); + +/* BIO_wpending returns the number of bytes pending to be written. */ +OPENSSL_EXPORT size_t BIO_wpending(const BIO *bio); + +/* BIO_set_close sets the close flag for |bio|. The meaning of which depends on + * the type of |bio| but, for example, a memory BIO interprets the close flag + * as meaning that it owns its buffer. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int BIO_set_close(BIO *bio, int close_flag); + +/* BIO_set_callback sets a callback function that will be called before and + * after most operations. See the comment above |bio_info_cb|. */ +OPENSSL_EXPORT void BIO_set_callback(BIO *bio, bio_info_cb callback_func); + +/* BIO_set_callback_arg sets the opaque pointer value that can be read within a + * callback with |BIO_get_callback_arg|. */ +OPENSSL_EXPORT void BIO_set_callback_arg(BIO *bio, char *arg); + +/* BIO_get_callback_arg returns the last value of the opaque callback pointer + * set by |BIO_set_callback_arg|. */ +OPENSSL_EXPORT char *BIO_get_callback_arg(const BIO *bio); + +/* BIO_number_read returns the number of bytes that have been read from + * |bio|. */ +OPENSSL_EXPORT size_t BIO_number_read(const BIO *bio); + +/* BIO_number_written returns the number of bytes that have been written to + * |bio|. */ +OPENSSL_EXPORT size_t BIO_number_written(const BIO *bio); + + +/* Managing chains of BIOs. + * + * BIOs can be put into chains where the output of one is used as the input of + * the next etc. The most common case is a buffering BIO, which accepts and + * buffers writes until flushed into the next BIO in the chain. */ + +/* BIO_push adds |appended_bio| to the end of the chain with |bio| at the head. + * It returns |bio|. Note that |appended_bio| may be the head of a chain itself + * and thus this function can be used to join two chains. + * + * BIO_push takes ownership of the caller's reference to |appended_bio|. */ +OPENSSL_EXPORT BIO *BIO_push(BIO *bio, BIO *appended_bio); + +/* BIO_pop removes |bio| from the head of a chain and returns the next BIO in + * the chain, or NULL if there is no next BIO. + * + * The caller takes ownership of the chain's reference to |bio|. */ +OPENSSL_EXPORT BIO *BIO_pop(BIO *bio); + +/* BIO_next returns the next BIO in the chain after |bio|, or NULL if there is + * no such BIO. */ +OPENSSL_EXPORT BIO *BIO_next(BIO *bio); + +/* BIO_free_all calls |BIO_free|. + * + * TODO(fork): update callers and remove. */ +OPENSSL_EXPORT void BIO_free_all(BIO *bio); + +/* BIO_find_type walks a chain of BIOs and returns the first that matches + * |type|, which is one of the |BIO_TYPE_*| values. */ +OPENSSL_EXPORT BIO *BIO_find_type(BIO *bio, int type); + +/* BIO_copy_next_retry sets the retry flags and |retry_reason| of |bio| from + * the next BIO in the chain. */ +OPENSSL_EXPORT void BIO_copy_next_retry(BIO *bio); + + +/* Printf functions. + * + * These functions are versions of printf functions that output to a BIO rather + * than a FILE. */ +#ifdef __GNUC__ +#define __bio_h__attr__ __attribute__ +#else +#define __bio_h__attr__(x) +#endif +OPENSSL_EXPORT int BIO_printf(BIO *bio, const char *format, ...) + __bio_h__attr__((__format__(__printf__, 2, 3))); +#undef __bio_h__attr__ + + +/* Utility functions. */ + +/* BIO_indent prints min(|indent|, |max_indent|) spaces. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int BIO_indent(BIO *bio, unsigned indent, unsigned max_indent); + +/* BIO_hexdump writes a hex dump of |data| to |bio|. Each line will be indented + * by |indent| spaces. */ +OPENSSL_EXPORT int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len, + unsigned indent); + +/* BIO_print_errors prints the current contents of the error stack to |bio| + * using human readable strings where possible. */ +OPENSSL_EXPORT void BIO_print_errors(BIO *bio); + +/* BIO_read_asn1 reads a single ASN.1 object from |bio|. If successful it sets + * |*out| to be an allocated buffer (that should be freed with |OPENSSL_free|), + * |*out_size| to the length, in bytes, of that buffer and returns one. + * Otherwise it returns zero. + * + * If the length of the object is greater than |max_len| or 2^32 then the + * function will fail. Long-form tags are not supported. If the length of the + * object is indefinite the full contents of |bio| are read, unless it would be + * greater than |max_len|, in which case the function fails. + * + * If the function fails then some unknown amount of data may have been read + * from |bio|. */ +OPENSSL_EXPORT int BIO_read_asn1(BIO *bio, uint8_t **out, size_t *out_len, + size_t max_len); + + +/* Memory BIOs. + * + * Memory BIOs can be used as a read-only source (with |BIO_new_mem_buf|) or a + * writable sink (with |BIO_new|, |BIO_s_mem| and |BIO_get_mem_buf|). Data + * written to a writable, memory BIO can be recalled by reading from it. + * + * Calling |BIO_reset| on a read-only BIO resets it to the original contents. + * On a writable BIO, it clears any data. + * + * If the close flag is set to |BIO_NOCLOSE| (not the default) then the + * underlying |BUF_MEM| will not be freed when the |BIO| is freed. + * + * Memory BIOs support |BIO_gets| and |BIO_puts|. + * + * |BIO_eof| is true if no data is in the BIO. + * + * |BIO_ctrl_pending| returns the number of bytes currently stored. */ + +/* BIO_s_mem returns a |BIO_METHOD| that uses a in-memory buffer. */ +OPENSSL_EXPORT const BIO_METHOD *BIO_s_mem(void); + +/* BIO_new_mem_buf creates BIO that reads and writes from |len| bytes at |buf|. + * It does not take ownership of |buf|. It returns the BIO or NULL on error. + * + * If |len| is negative, then |buf| is treated as a NUL-terminated string, but + * don't depend on this in new code. */ +OPENSSL_EXPORT BIO *BIO_new_mem_buf(void *buf, int len); + +/* BIO_mem_contents sets |*out_contents| to point to the current contents of + * |bio| and |*out_len| to contain the length of that data. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int BIO_mem_contents(const BIO *bio, + const uint8_t **out_contents, + size_t *out_len); + +/* BIO_get_mem_data sets |*contents| to point to the current contents of |bio| + * and returns the length of the data. + * + * WARNING: don't use this, use |BIO_mem_contents|. A return value of zero from + * this function can mean either that it failed or that the memory buffer is + * empty. */ +OPENSSL_EXPORT long BIO_get_mem_data(BIO *bio, char **contents); + +/* BIO_get_mem_ptr sets |*out| to a BUF_MEM containing the current contents of + * |bio|. It returns one on success or zero on error. */ +OPENSSL_EXPORT int BIO_get_mem_ptr(BIO *bio, BUF_MEM **out); + +/* BIO_set_mem_buf sets |b| as the contents of |bio|. If |take_ownership| is + * non-zero, then |b| will be freed when |bio| is closed. Returns one on + * success or zero otherwise. */ +OPENSSL_EXPORT int BIO_set_mem_buf(BIO *bio, BUF_MEM *b, int take_ownership); + +/* BIO_set_mem_eof_return sets the value that will be returned from reading + * |bio| when empty. If |eof_value| is zero then an empty memory BIO will + * return EOF (that is it will return zero and |BIO_should_retry| will be + * false). If |eof_value| is non zero then it will return |eof_value| when it + * is empty and it will set the read retry flag (that is |BIO_read_retry| is + * true). To avoid ambiguity with a normal positive return value, |eof_value| + * should be set to a negative value, typically -1. + * + * For a read-only BIO, the default is zero (EOF). For a writable BIO, the + * default is -1 so that additional data can be written once exhausted. */ +OPENSSL_EXPORT int BIO_set_mem_eof_return(BIO *bio, int eof_value); + + +/* File descriptor BIOs. + * + * File descriptor BIOs are wrappers around the system's |read| and |write| + * functions. If the close flag is set then then |close| is called on the + * underlying file descriptor when the BIO is freed. + * + * |BIO_reset| attempts to seek the file pointer to the start of file using + * |lseek|. + * + * |BIO_seek| sets the file pointer to position |off| from start of file using + * |lseek|. + * + * |BIO_tell| returns the current file position. */ + +/* BIO_s_fd returns a |BIO_METHOD| for file descriptor fds. */ +OPENSSL_EXPORT const BIO_METHOD *BIO_s_fd(void); + +/* BIO_new_fd creates a new file descriptor BIO wrapping |fd|. If |close_flag| + * is non-zero, then |fd| will be closed when the BIO is. */ +OPENSSL_EXPORT BIO *BIO_new_fd(int fd, int close_flag); + +/* BIO_set_fd sets the file descriptor of |bio| to |fd|. If |close_flag| is + * non-zero then |fd| will be closed when |bio| is. It returns one on success + * or zero on error. */ +OPENSSL_EXPORT int BIO_set_fd(BIO *bio, int fd, int close_flag); + +/* BIO_get_fd sets |*out_fd| to the file descriptor currently in use by |bio|. + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int BIO_get_fd(BIO *bio, int *out_fd); + + +/* File BIOs. + * + * File BIOs are wrappers around a C |FILE| object. + * + * |BIO_flush| on a file BIO calls |fflush| on the wrapped stream. + * + * |BIO_reset| attempts to seek the file pointer to the start of file using + * |fseek|. + * + * |BIO_seek| sets the file pointer to the given position from the start of + * file using |fseek|. + * + * |BIO_eof| calls |feof|. + * + * Setting the close flag causes |fclose| to be called on the stream when the + * BIO is freed. */ + +/* BIO_s_file returns a BIO_METHOD that wraps a |FILE|. */ +OPENSSL_EXPORT const BIO_METHOD *BIO_s_file(void); + +/* BIO_new_file creates a file BIO by opening |filename| with the given mode. + * See the |fopen| manual page for details of the mode argument. */ +OPENSSL_EXPORT BIO *BIO_new_file(const char *filename, const char *mode); + +/* BIO_new_fp creates a new file BIO that wraps the given |FILE|. If + * |close_flag| is |BIO_CLOSE|, then |fclose| will be called on |stream| when + * the BIO is closed. */ +OPENSSL_EXPORT BIO *BIO_new_fp(FILE *stream, int close_flag); + +/* BIO_get_fp sets |*out_file| to the current |FILE| for |bio|. It returns one + * on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_get_fp(BIO *bio, FILE **out_file); + +/* BIO_set_fp sets the |FILE| for |bio|. If |close_flag| is |BIO_CLOSE| then + * |fclose| will be called on |file| when |bio| is closed. It returns one on + * sucess and zero otherwise. */ +OPENSSL_EXPORT int BIO_set_fp(BIO *bio, FILE *file, int close_flag); + +/* BIO_read_filename opens |filename| for reading and sets the result as the + * |FILE| for |bio|. It returns one on success and zero otherwise. The |FILE| + * will be closed when |bio| is freed. */ +OPENSSL_EXPORT int BIO_read_filename(BIO *bio, const char *filename); + +/* BIO_write_filename opens |filename| for writing and sets the result as the + * |FILE| for |bio|. It returns one on success and zero otherwise. The |FILE| + * will be closed when |bio| is freed. */ +OPENSSL_EXPORT int BIO_write_filename(BIO *bio, const char *filename); + +/* BIO_append_filename opens |filename| for appending and sets the result as + * the |FILE| for |bio|. It returns one on success and zero otherwise. The + * |FILE| will be closed when |bio| is freed. */ +OPENSSL_EXPORT int BIO_append_filename(BIO *bio, const char *filename); + +/* BIO_rw_filename opens |filename| for reading and writing and sets the result + * as the |FILE| for |bio|. It returns one on success and zero otherwise. The + * |FILE| will be closed when |bio| is freed. */ +OPENSSL_EXPORT int BIO_rw_filename(BIO *bio, const char *filename); + + +/* Buffer BIOs. + * + * Buffer BIOs are a filter-type BIO, i.e. they are designed to be used in a + * chain of BIOs. They provide buffering to reduce the number of operations on + * the underlying BIOs. */ + +OPENSSL_EXPORT const BIO_METHOD *BIO_f_buffer(void); + +/* BIO_set_read_buffer_size sets the size, in bytes, of the read buffer and + * clears it. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int BIO_set_read_buffer_size(BIO *bio, int buffer_size); + +/* BIO_set_write_buffer_size sets the size, in bytes, of the write buffer and + * clears it. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int BIO_set_write_buffer_size(BIO *bio, int buffer_size); + + +/* Socket BIOs. */ + +OPENSSL_EXPORT const BIO_METHOD *BIO_s_socket(void); + +/* BIO_new_socket allocates and initialises a fresh BIO which will read and + * write to the socket |fd|. If |close_flag| is |BIO_CLOSE| then closing the + * BIO will close |fd|. It returns the fresh |BIO| or NULL on error. */ +OPENSSL_EXPORT BIO *BIO_new_socket(int fd, int close_flag); + + +/* Connect BIOs. + * + * A connection BIO creates a network connection and transfers data over the + * resulting socket. */ + +OPENSSL_EXPORT const BIO_METHOD *BIO_s_connect(void); + +/* BIO_new_connect returns a BIO that connects to the given hostname and port. + * The |host_and_optional_port| argument should be of the form + * "www.example.com" or "www.example.com:443". If the port is omitted, it must + * be provided with |BIO_set_conn_port|. + * + * It returns the new BIO on success, or NULL on error. */ +OPENSSL_EXPORT BIO *BIO_new_connect(const char *host_and_optional_port); + +/* BIO_set_conn_hostname sets |host_and_optional_port| as the hostname and + * optional port that |bio| will connect to. If the port is omitted, it must be + * provided with |BIO_set_conn_port|. + * + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_set_conn_hostname(BIO *bio, + const char *host_and_optional_port); + +/* BIO_set_conn_port sets |port_str| as the port or service name that |bio| + * will connect to. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_set_conn_port(BIO *bio, const char *port_str); + +/* BIO_set_nbio sets whether |bio| will use non-blocking I/O operations. It + * returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_set_nbio(BIO *bio, int on); + + +/* Datagram BIOs. + * + * TODO(fork): not implemented. */ + +#define BIO_CTRL_DGRAM_QUERY_MTU 40 /* as kernel for current MTU */ + +#define BIO_CTRL_DGRAM_SET_MTU 42 /* set cached value for MTU. want to use + this if asking the kernel fails */ + +#define BIO_CTRL_DGRAM_MTU_EXCEEDED 43 /* check whether the MTU was exceed in + the previous write operation. */ + +#define BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT \ + 45 /* Next DTLS handshake timeout to adjust socket timeouts */ + +#define BIO_CTRL_DGRAM_GET_PEER 46 + +#define BIO_CTRL_DGRAM_GET_FALLBACK_MTU 47 + + +/* BIO Pairs. + * + * BIO pairs provide a "loopback" like system: a pair of BIOs where data + * written to one can be read from the other and vice versa. */ + +/* BIO_new_bio_pair sets |*out1| and |*out2| to two freshly created BIOs where + * data written to one can be read from the other and vice versa. The + * |writebuf1| argument gives the size of the buffer used in |*out1| and + * |writebuf2| for |*out2|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int BIO_new_bio_pair(BIO **out1, size_t writebuf1, BIO **out2, + size_t writebuf2); + +/* BIO_new_bio_pair_external_buf is the same as |BIO_new_bio_pair| with the + * difference that the caller keeps ownership of the write buffers + * |ext_writebuf1_len| and |ext_writebuf2_len|. This is useful when using zero + * copy API for read and write operations, in cases where the buffers need to + * outlive the BIO pairs. It returns one on success and zero on error. */ +OPENSSL_EXPORT int BIO_new_bio_pair_external_buf(BIO** bio1_p, + size_t writebuf1_len, + uint8_t* ext_writebuf1, + BIO** bio2_p, + size_t writebuf2_len, + uint8_t* ext_writebuf2); + +/* BIO_ctrl_get_read_request returns the number of bytes that the other side of + * |bio| tried (unsuccessfully) to read. */ +OPENSSL_EXPORT size_t BIO_ctrl_get_read_request(BIO *bio); + +/* BIO_ctrl_get_write_guarantee returns the number of bytes that |bio| (which + * must have been returned by |BIO_new_bio_pair|) will accept on the next + * |BIO_write| call. */ +OPENSSL_EXPORT size_t BIO_ctrl_get_write_guarantee(BIO *bio); + +/* BIO_shutdown_wr marks |bio| as closed, from the point of view of the other + * side of the pair. Future |BIO_write| calls on |bio| will fail. It returns + * one on success and zero otherwise. */ +OPENSSL_EXPORT int BIO_shutdown_wr(BIO *bio); + + +/* Zero copy versions of BIO_read and BIO_write for BIO pairs. */ + +/* BIO_zero_copy_get_read_buf initiates a zero copy read operation. + * |out_read_buf| is set to the internal read buffer, and |out_buf_offset| is + * set to the current read position of |out_read_buf|. The number of bytes + * available for read from |out_read_buf| + |out_buf_offset| is returned in + * |out_available_bytes|. Note that this function might report fewer bytes + * available than |BIO_pending|, if the internal ring buffer is wrapped. It + * returns one on success. In case of error it returns zero and pushes to the + * error stack. + * + * The zero copy read operation is completed by calling + * |BIO_zero_copy_get_read_buf_done|. Neither |BIO_zero_copy_get_read_buf| nor + * any other I/O read operation may be called while a zero copy read operation + * is active. */ +OPENSSL_EXPORT int BIO_zero_copy_get_read_buf(BIO* bio, + uint8_t** out_read_buf, + size_t* out_buf_offset, + size_t* out_available_bytes); + +/* BIO_zero_copy_get_read_buf_done must be called after reading from a BIO using + * |BIO_zero_copy_get_read_buf| to finish the read operation. The |bytes_read| + * argument is the number of bytes read. + * + * It returns one on success. In case of error it returns zero and pushes to the + * error stack. */ +OPENSSL_EXPORT int BIO_zero_copy_get_read_buf_done(BIO* bio, size_t bytes_read); + +/* BIO_zero_copy_get_write_buf initiates a zero copy write operation. + * |out_write_buf| is set to to the internal write buffer, and |out_buf_offset| + * is set to the current write position of |out_write_buf|. + * The number of bytes available for write from |out_write_buf| + + * |out_buf_offset| is returned in |out_available_bytes|. Note that this + * function might report fewer bytes available than + * |BIO_ctrl_get_write_guarantee|, if the internal buffer is wrapped. It returns + * one on success. In case of error it returns zero and pushes to the error + * stack. + * + * The zero copy write operation is completed by calling + * |BIO_zero_copy_get_write_buf_done|. Neither |BIO_zero_copy_get_write_buf| + * nor any other I/O write operation may be called while a zero copy write + * operation is active. */ +OPENSSL_EXPORT int BIO_zero_copy_get_write_buf(BIO* bio, + uint8_t** out_write_buf, + size_t* out_buf_offset, + size_t* out_available_bytes); + +/* BIO_zero_copy_get_write_buf_done must be called after writing to a BIO using + * |BIO_zero_copy_get_write_buf| to finish the write operation. The + * |bytes_written| argument gives the number of bytes written. + * + * It returns one on success. In case of error it returns zero and pushes to the + * error stack. */ +OPENSSL_EXPORT int BIO_zero_copy_get_write_buf_done(BIO* bio, + size_t bytes_written); + + +/* Deprecated functions. */ + +/* ERR_print_errors is an alias for |BIO_print_errors|. */ +OPENSSL_EXPORT void ERR_print_errors(BIO *bio); + + +/* BIO_NOCLOSE and |BIO_CLOSE| can be used as symbolic arguments when a "close + * flag" is passed to a BIO function. */ +#define BIO_NOCLOSE 0 +#define BIO_CLOSE 1 + +/* These are passed to the BIO callback */ +#define BIO_CB_FREE 0x01 +#define BIO_CB_READ 0x02 +#define BIO_CB_WRITE 0x03 +#define BIO_CB_PUTS 0x04 +#define BIO_CB_GETS 0x05 +#define BIO_CB_CTRL 0x06 + +/* The callback is called before and after the underling operation, + * The BIO_CB_RETURN flag indicates if it is after the call */ +#define BIO_CB_RETURN 0x80 + +/* These are values of the |cmd| argument to |BIO_ctrl|. */ +#define BIO_CTRL_RESET 1 /* opt - rewind/zero etc */ +#define BIO_CTRL_EOF 2 /* opt - are we at the eof */ +#define BIO_CTRL_INFO 3 /* opt - extra tit-bits */ +#define BIO_CTRL_SET 4 /* man - set the 'IO' type */ +#define BIO_CTRL_GET 5 /* man - get the 'IO' type */ +#define BIO_CTRL_GET_CLOSE 8 /* man - set the 'close' on free */ +#define BIO_CTRL_SET_CLOSE 9 /* man - set the 'close' on free */ +#define BIO_CTRL_PENDING 10 /* opt - is their more data buffered */ +#define BIO_CTRL_FLUSH 11 /* opt - 'flush' buffered output */ +#define BIO_CTRL_WPENDING 13 /* opt - number of bytes still to write */ +/* callback is int cb(BIO *bio,state,ret); */ +#define BIO_CTRL_SET_CALLBACK 14 /* opt - set callback function */ +#define BIO_CTRL_GET_CALLBACK 15 /* opt - set callback function */ +#define BIO_CTRL_SET_FILENAME 30 /* BIO_s_file special */ + + +/* Android compatibility section. + * + * A previous version of BoringSSL used in Android renamed ERR_print_errors_fp + * to BIO_print_errors_fp. It has subsequently been renamed back to + * ERR_print_errors_fp. */ +#define BIO_print_errors_fp ERR_print_errors_fp + + +/* Deprecated functions. */ + +/* Returns a filter |BIO| that base64-encodes data written into it, and decodes + * data read from it. |BIO_gets| is not supported. Call |BIO_flush| when done + * writing, to signal that no more data are to be encoded. The flag + * |BIO_FLAGS_BASE64_NO_NL| may be set to encode all the data on one line. */ +OPENSSL_EXPORT const BIO_METHOD *BIO_f_base64(void); + + +/* Private functions */ + +#define BIO_FLAGS_READ 0x01 +#define BIO_FLAGS_WRITE 0x02 +#define BIO_FLAGS_IO_SPECIAL 0x04 +#define BIO_FLAGS_RWS (BIO_FLAGS_READ | BIO_FLAGS_WRITE | BIO_FLAGS_IO_SPECIAL) +#define BIO_FLAGS_SHOULD_RETRY 0x08 +#define BIO_FLAGS_BASE64_NO_NL 0x100 +/* This is used with memory BIOs: it means we shouldn't free up or change the + * data in any way. */ +#define BIO_FLAGS_MEM_RDONLY 0x200 + +/* These are the 'types' of BIOs */ +#define BIO_TYPE_NONE 0 +#define BIO_TYPE_MEM (1 | 0x0400) +#define BIO_TYPE_FILE (2 | 0x0400) +#define BIO_TYPE_FD (4 | 0x0400 | 0x0100) +#define BIO_TYPE_SOCKET (5 | 0x0400 | 0x0100) +#define BIO_TYPE_NULL (6 | 0x0400) +#define BIO_TYPE_SSL (7 | 0x0200) +#define BIO_TYPE_MD (8 | 0x0200) /* passive filter */ +#define BIO_TYPE_BUFFER (9 | 0x0200) /* filter */ +#define BIO_TYPE_CIPHER (10 | 0x0200) /* filter */ +#define BIO_TYPE_BASE64 (11 | 0x0200) /* filter */ +#define BIO_TYPE_CONNECT (12 | 0x0400 | 0x0100) /* socket - connect */ +#define BIO_TYPE_ACCEPT (13 | 0x0400 | 0x0100) /* socket for accept */ +#define BIO_TYPE_PROXY_CLIENT (14 | 0x0200) /* client proxy BIO */ +#define BIO_TYPE_PROXY_SERVER (15 | 0x0200) /* server proxy BIO */ +#define BIO_TYPE_NBIO_TEST (16 | 0x0200) /* server proxy BIO */ +#define BIO_TYPE_NULL_FILTER (17 | 0x0200) +#define BIO_TYPE_BER (18 | 0x0200) /* BER -> bin filter */ +#define BIO_TYPE_BIO (19 | 0x0400) /* (half a) BIO pair */ +#define BIO_TYPE_LINEBUFFER (20 | 0x0200) /* filter */ +#define BIO_TYPE_DGRAM (21 | 0x0400 | 0x0100) +#define BIO_TYPE_ASN1 (22 | 0x0200) /* filter */ +#define BIO_TYPE_COMP (23 | 0x0200) /* filter */ + +#define BIO_TYPE_DESCRIPTOR 0x0100 /* socket, fd, connect or accept */ +#define BIO_TYPE_FILTER 0x0200 +#define BIO_TYPE_SOURCE_SINK 0x0400 + +struct bio_method_st { + int type; + const char *name; + int (*bwrite)(BIO *, const char *, int); + int (*bread)(BIO *, char *, int); + /* TODO(fork): remove bputs. */ + int (*bputs)(BIO *, const char *); + int (*bgets)(BIO *, char *, int); + long (*ctrl)(BIO *, int, long, void *); + int (*create)(BIO *); + int (*destroy)(BIO *); + long (*callback_ctrl)(BIO *, int, bio_info_cb); +}; + +struct bio_st { + const BIO_METHOD *method; + /* bio, mode, argp, argi, argl, ret */ + long (*callback)(struct bio_st *, int, const char *, int, long, long); + char *cb_arg; /* first argument for the callback */ + + /* init is non-zero if this |BIO| has been initialised. */ + int init; + /* shutdown is often used by specific |BIO_METHOD|s to determine whether + * they own some underlying resource. This flag can often by controlled by + * |BIO_set_close|. For example, whether an fd BIO closes the underlying fd + * when it, itself, is closed. */ + int shutdown; + int flags; + int retry_reason; + /* num is a BIO-specific value. For example, in fd BIOs it's used to store a + * file descriptor. */ + int num; + CRYPTO_refcount_t references; + void *ptr; + /* next_bio points to the next |BIO| in a chain. This |BIO| owns a reference + * to |next_bio|. */ + struct bio_st *next_bio; /* used by filter BIOs */ + size_t num_read, num_write; +}; + +#define BIO_C_SET_CONNECT 100 +#define BIO_C_DO_STATE_MACHINE 101 +#define BIO_C_SET_NBIO 102 +#define BIO_C_SET_PROXY_PARAM 103 +#define BIO_C_SET_FD 104 +#define BIO_C_GET_FD 105 +#define BIO_C_SET_FILE_PTR 106 +#define BIO_C_GET_FILE_PTR 107 +#define BIO_C_SET_FILENAME 108 +#define BIO_C_SET_SSL 109 +#define BIO_C_GET_SSL 110 +#define BIO_C_SET_MD 111 +#define BIO_C_GET_MD 112 +#define BIO_C_GET_CIPHER_STATUS 113 +#define BIO_C_SET_BUF_MEM 114 +#define BIO_C_GET_BUF_MEM_PTR 115 +#define BIO_C_GET_BUFF_NUM_LINES 116 +#define BIO_C_SET_BUFF_SIZE 117 +#define BIO_C_SET_ACCEPT 118 +#define BIO_C_SSL_MODE 119 +#define BIO_C_GET_MD_CTX 120 +#define BIO_C_GET_PROXY_PARAM 121 +#define BIO_C_SET_BUFF_READ_DATA 122 /* data to read first */ +#define BIO_C_GET_CONNECT 123 +#define BIO_C_GET_ACCEPT 124 +#define BIO_C_SET_SSL_RENEGOTIATE_BYTES 125 +#define BIO_C_GET_SSL_NUM_RENEGOTIATES 126 +#define BIO_C_SET_SSL_RENEGOTIATE_TIMEOUT 127 +#define BIO_C_FILE_SEEK 128 +#define BIO_C_GET_CIPHER_CTX 129 +#define BIO_C_SET_BUF_MEM_EOF_RETURN 130/*return end of input value*/ +#define BIO_C_SET_BIND_MODE 131 +#define BIO_C_GET_BIND_MODE 132 +#define BIO_C_FILE_TELL 133 +#define BIO_C_GET_SOCKS 134 +#define BIO_C_SET_SOCKS 135 + +#define BIO_C_SET_WRITE_BUF_SIZE 136/* for BIO_s_bio */ +#define BIO_C_GET_WRITE_BUF_SIZE 137 +#define BIO_C_GET_WRITE_GUARANTEE 140 +#define BIO_C_GET_READ_REQUEST 141 +#define BIO_C_SHUTDOWN_WR 142 +#define BIO_C_NREAD0 143 +#define BIO_C_NREAD 144 +#define BIO_C_NWRITE0 145 +#define BIO_C_NWRITE 146 +#define BIO_C_RESET_READ_REQUEST 147 +#define BIO_C_SET_MD_CTX 148 + +#define BIO_C_SET_PREFIX 149 +#define BIO_C_GET_PREFIX 150 +#define BIO_C_SET_SUFFIX 151 +#define BIO_C_GET_SUFFIX 152 + +#define BIO_C_SET_EX_ARG 153 +#define BIO_C_GET_EX_ARG 154 + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define BIO_R_BAD_FOPEN_MODE 100 +#define BIO_R_BROKEN_PIPE 101 +#define BIO_R_CONNECT_ERROR 102 +#define BIO_R_ERROR_SETTING_NBIO 103 +#define BIO_R_INVALID_ARGUMENT 104 +#define BIO_R_IN_USE 105 +#define BIO_R_KEEPALIVE 106 +#define BIO_R_NBIO_CONNECT_ERROR 107 +#define BIO_R_NO_HOSTNAME_SPECIFIED 108 +#define BIO_R_NO_PORT_SPECIFIED 109 +#define BIO_R_NO_SUCH_FILE 110 +#define BIO_R_NULL_PARAMETER 111 +#define BIO_R_SYS_LIB 112 +#define BIO_R_UNABLE_TO_CREATE_SOCKET 113 +#define BIO_R_UNINITIALIZED 114 +#define BIO_R_UNSUPPORTED_METHOD 115 +#define BIO_R_WRITE_TO_READ_ONLY_BIO 116 + +#endif /* OPENSSL_HEADER_BIO_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/blowfish.h b/TMessagesProj/jni/boringssl/include/openssl/blowfish.h new file mode 100644 index 00000000..fa60d533 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/blowfish.h @@ -0,0 +1,93 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BLOWFISH_H +#define OPENSSL_HEADER_BLOWFISH_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define BF_ENCRYPT 1 +#define BF_DECRYPT 0 + +#define BF_ROUNDS 16 +#define BF_BLOCK 8 + +typedef struct bf_key_st { + uint32_t P[BF_ROUNDS + 2]; + uint32_t S[4 * 256]; +} BF_KEY; + +OPENSSL_EXPORT void BF_set_key(BF_KEY *key, size_t len, const uint8_t *data); +OPENSSL_EXPORT void BF_encrypt(uint32_t *data, const BF_KEY *key); +OPENSSL_EXPORT void BF_decrypt(uint32_t *data, const BF_KEY *key); + +OPENSSL_EXPORT void BF_ecb_encrypt(const uint8_t *in, uint8_t *out, + const BF_KEY *key, int enc); +OPENSSL_EXPORT void BF_cbc_encrypt(const uint8_t *in, uint8_t *out, long length, + const BF_KEY *schedule, uint8_t *ivec, + int enc); + + +#ifdef __cplusplus +} +#endif + +#endif /* OPENSSL_HEADER_BLOWFISH_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/bn.h b/TMessagesProj/jni/boringssl/include/openssl/bn.h new file mode 100644 index 00000000..f84aba5d --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/bn.h @@ -0,0 +1,862 @@ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the Eric Young open source + * license provided above. + * + * The binary polynomial arithmetic software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#ifndef OPENSSL_HEADER_BN_H +#define OPENSSL_HEADER_BN_H + +#include +#include + +#include /* for PRIu64 and friends */ +#include /* for FILE* */ + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* BN provides support for working with arbitary sized integers. For example, + * although the largest integer supported by the compiler might be 64 bits, BN + * will allow you to work with numbers until you run out of memory. */ + + +/* BN_ULONG is the native word size when working with big integers. + * + * Note: on some platforms, inttypes.h does not define print format macros in + * C++ unless |__STDC_FORMAT_MACROS| defined. As this is a public header, bn.h + * does not define |__STDC_FORMAT_MACROS| itself. C++ source files which use the + * FMT macros must define it externally. */ +#if defined(OPENSSL_64_BIT) +#define BN_ULONG uint64_t +#define BN_BITS2 64 +#define BN_DEC_FMT1 "%" PRIu64 +#define BN_DEC_FMT2 "%019" PRIu64 +#define BN_HEX_FMT1 "%" PRIx64 +#elif defined(OPENSSL_32_BIT) +#define BN_ULONG uint32_t +#define BN_BITS2 32 +#define BN_DEC_FMT1 "%" PRIu32 +#define BN_DEC_FMT2 "%09" PRIu32 +#define BN_HEX_FMT1 "%" PRIx32 +#else +#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT" +#endif + + +/* Allocation and freeing. */ + +/* BN_new creates a new, allocated BIGNUM and initialises it. */ +OPENSSL_EXPORT BIGNUM *BN_new(void); + +/* BN_init initialises a stack allocated |BIGNUM|. */ +OPENSSL_EXPORT void BN_init(BIGNUM *bn); + +/* BN_free frees the data referenced by |bn| and, if |bn| was originally + * allocated on the heap, frees |bn| also. */ +OPENSSL_EXPORT void BN_free(BIGNUM *bn); + +/* BN_clear_free erases and frees the data referenced by |bn| and, if |bn| was + * originally allocated on the heap, frees |bn| also. */ +OPENSSL_EXPORT void BN_clear_free(BIGNUM *bn); + +/* BN_dup allocates a new BIGNUM and sets it equal to |src|. It returns the + * allocated BIGNUM on success or NULL otherwise. */ +OPENSSL_EXPORT BIGNUM *BN_dup(const BIGNUM *src); + +/* BN_copy sets |dest| equal to |src| and returns |dest| or NULL on allocation + * failure. */ +OPENSSL_EXPORT BIGNUM *BN_copy(BIGNUM *dest, const BIGNUM *src); + +/* BN_clear sets |bn| to zero and erases the old data. */ +OPENSSL_EXPORT void BN_clear(BIGNUM *bn); + +/* BN_value_one returns a static BIGNUM with value 1. */ +OPENSSL_EXPORT const BIGNUM *BN_value_one(void); + +/* BN_with_flags initialises a stack allocated |BIGNUM| with pointers to the + * contents of |in| but with |flags| ORed into the flags field. + * + * Note: the two BIGNUMs share state and so |out| should /not/ be passed to + * |BN_free|. */ +OPENSSL_EXPORT void BN_with_flags(BIGNUM *out, const BIGNUM *in, int flags); + + +/* Basic functions. */ + +/* BN_num_bits returns the minimum number of bits needed to represent the + * absolute value of |bn|. */ +OPENSSL_EXPORT unsigned BN_num_bits(const BIGNUM *bn); + +/* BN_num_bytes returns the minimum number of bytes needed to represent the + * absolute value of |bn|. */ +OPENSSL_EXPORT unsigned BN_num_bytes(const BIGNUM *bn); + +/* BN_zero sets |bn| to zero. */ +OPENSSL_EXPORT void BN_zero(BIGNUM *bn); + +/* BN_one sets |bn| to one. It returns one on success or zero on allocation + * failure. */ +OPENSSL_EXPORT int BN_one(BIGNUM *bn); + +/* BN_set_word sets |bn| to |value|. It returns one on success or zero on + * allocation failure. */ +OPENSSL_EXPORT int BN_set_word(BIGNUM *bn, BN_ULONG value); + +/* BN_set_negative sets the sign of |bn|. */ +OPENSSL_EXPORT void BN_set_negative(BIGNUM *bn, int sign); + +/* BN_is_negative returns one if |bn| is negative and zero otherwise. */ +OPENSSL_EXPORT int BN_is_negative(const BIGNUM *bn); + +/* BN_get_flags returns |bn->flags| & |flags|. */ +OPENSSL_EXPORT int BN_get_flags(const BIGNUM *bn, int flags); + +/* BN_set_flags sets |flags| on |bn|. */ +OPENSSL_EXPORT void BN_set_flags(BIGNUM *bn, int flags); + + +/* Conversion functions. */ + +/* BN_bin2bn sets |*ret| to the value of |len| bytes from |in|, interpreted as + * a big-endian number, and returns |ret|. If |ret| is NULL then a fresh + * |BIGNUM| is allocated and returned. It returns NULL on allocation + * failure. */ +OPENSSL_EXPORT BIGNUM *BN_bin2bn(const uint8_t *in, size_t len, BIGNUM *ret); + +/* BN_bn2bin serialises the absolute value of |in| to |out| as a big-endian + * integer, which must have |BN_num_bytes| of space available. It returns the + * number of bytes written. */ +OPENSSL_EXPORT size_t BN_bn2bin(const BIGNUM *in, uint8_t *out); + +/* BN_bn2bin_padded serialises the absolute value of |in| to |out| as a + * big-endian integer. The integer is padded with leading zeros up to size + * |len|. If |len| is smaller than |BN_num_bytes|, the function fails and + * returns 0. Otherwise, it returns 1. */ +OPENSSL_EXPORT int BN_bn2bin_padded(uint8_t *out, size_t len, const BIGNUM *in); + +/* BN_bn2hex returns an allocated string that contains a NUL-terminated, hex + * representation of |bn|. If |bn| is negative, the first char in the resulting + * string will be '-'. Returns NULL on allocation failure. */ +OPENSSL_EXPORT char *BN_bn2hex(const BIGNUM *bn); + +/* BN_hex2bn parses the leading hex number from |in|, which may be proceeded by + * a '-' to indicate a negative number and may contain trailing, non-hex data. + * If |outp| is not NULL, it constructs a BIGNUM equal to the hex number and + * stores it in |*outp|. If |*outp| is NULL then it allocates a new BIGNUM and + * updates |*outp|. It returns the number of bytes of |in| processed or zero on + * error. */ +OPENSSL_EXPORT int BN_hex2bn(BIGNUM **outp, const char *in); + +/* BN_bn2dec returns an allocated string that contains a NUL-terminated, + * decimal representation of |bn|. If |bn| is negative, the first char in the + * resulting string will be '-'. Returns NULL on allocation failure. */ +OPENSSL_EXPORT char *BN_bn2dec(const BIGNUM *a); + +/* BN_dec2bn parses the leading decimal number from |in|, which may be + * proceeded by a '-' to indicate a negative number and may contain trailing, + * non-decimal data. If |outp| is not NULL, it constructs a BIGNUM equal to the + * decimal number and stores it in |*outp|. If |*outp| is NULL then it + * allocates a new BIGNUM and updates |*outp|. It returns the number of bytes + * of |in| processed or zero on error. */ +OPENSSL_EXPORT int BN_dec2bn(BIGNUM **outp, const char *in); + +/* BN_asc2bn acts like |BN_dec2bn| or |BN_hex2bn| depending on whether |in| + * begins with "0X" or "0x" (indicating hex) or not (indicating decimal). A + * leading '-' is still permitted and comes before the optional 0X/0x. It + * returns one on success or zero on error. */ +OPENSSL_EXPORT int BN_asc2bn(BIGNUM **outp, const char *in); + +/* BN_print writes a hex encoding of |a| to |bio|. It returns one on success + * and zero on error. */ +OPENSSL_EXPORT int BN_print(BIO *bio, const BIGNUM *a); + +/* BN_print_fp acts like |BIO_print|, but wraps |fp| in a |BIO| first. */ +OPENSSL_EXPORT int BN_print_fp(FILE *fp, const BIGNUM *a); + +/* BN_get_word returns the absolute value of |bn| as a single word. If |bn| is + * too large to be represented as a single word, the maximum possible value + * will be returned. */ +OPENSSL_EXPORT BN_ULONG BN_get_word(const BIGNUM *bn); + + +/* ASN.1 functions. */ + +/* BN_cbs2unsigned parses a non-negative DER INTEGER from |cbs| writes the + * result to |ret|. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int BN_cbs2unsigned(CBS *cbs, BIGNUM *ret); + +/* BN_bn2cbb marshals |bn| as a non-negative DER INTEGER and appends the result + * to |cbb|. It returns one on success and zero on failure. */ +OPENSSL_EXPORT int BN_bn2cbb(CBB *cbb, const BIGNUM *bn); + + +/* Internal functions. + * + * These functions are useful for code that is doing low-level manipulations of + * BIGNUM values. However, be sure that no other function in this file does + * what you want before turning to these. */ + +/* bn_correct_top decrements |bn->top| until |bn->d[top-1]| is non-zero or + * until |top| is zero. */ +OPENSSL_EXPORT void bn_correct_top(BIGNUM *bn); + +/* bn_wexpand ensures that |bn| has at least |words| works of space without + * altering its value. It returns one on success or zero on allocation + * failure. */ +OPENSSL_EXPORT BIGNUM *bn_wexpand(BIGNUM *bn, unsigned words); + + +/* BIGNUM pools. + * + * Certain BIGNUM operations need to use many temporary variables and + * allocating and freeing them can be quite slow. Thus such opertions typically + * take a |BN_CTX| parameter, which contains a pool of |BIGNUMs|. The |ctx| + * argument to a public function may be NULL, in which case a local |BN_CTX| + * will be created just for the lifetime of that call. + * + * A function must call |BN_CTX_start| first. Then, |BN_CTX_get| may be called + * repeatedly to obtain temporary |BIGNUM|s. All |BN_CTX_get| calls must be made + * before calling any other functions that use the |ctx| as an argument. + * + * Finally, |BN_CTX_end| must be called before returning from the function. + * When |BN_CTX_end| is called, the |BIGNUM| pointers obtained from + * |BN_CTX_get| become invalid. */ + +/* BN_CTX_new returns a new, empty BN_CTX or NULL on allocation failure. */ +OPENSSL_EXPORT BN_CTX *BN_CTX_new(void); + +/* BN_CTX_free frees all BIGNUMs contained in |ctx| and then frees |ctx| + * itself. */ +OPENSSL_EXPORT void BN_CTX_free(BN_CTX *ctx); + +/* BN_CTX_start "pushes" a new entry onto the |ctx| stack and allows future + * calls to |BN_CTX_get|. */ +OPENSSL_EXPORT void BN_CTX_start(BN_CTX *ctx); + +/* BN_CTX_get returns a new |BIGNUM|, or NULL on allocation failure. Once + * |BN_CTX_get| has returned NULL, all future calls will also return NULL until + * |BN_CTX_end| is called. */ +OPENSSL_EXPORT BIGNUM *BN_CTX_get(BN_CTX *ctx); + +/* BN_CTX_end invalidates all |BIGNUM|s returned from |BN_CTX_get| since the + * matching |BN_CTX_start| call. */ +OPENSSL_EXPORT void BN_CTX_end(BN_CTX *ctx); + + +/* Simple arithmetic */ + +/* BN_add sets |r| = |a| + |b|, where |r| may be the same pointer as either |a| + * or |b|. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); + +/* BN_uadd sets |r| = |a| + |b|, where |a| and |b| are non-negative and |r| may + * be the same pointer as either |a| or |b|. It returns one on success and zero + * on allocation failure. */ +OPENSSL_EXPORT int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); + +/* BN_add_word adds |w| to |a|. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BN_add_word(BIGNUM *a, BN_ULONG w); + +/* BN_sub sets |r| = |a| - |b|, where |r| must be a distinct pointer from |a| + * and |b|. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); + +/* BN_usub sets |r| = |a| - |b|, where |a| and |b| are non-negative integers, + * |b| < |a| and |r| must be a distinct pointer from |a| and |b|. It returns + * one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); + +/* BN_sub_word subtracts |w| from |a|. It returns one on success and zero on + * allocation failure. */ +OPENSSL_EXPORT int BN_sub_word(BIGNUM *a, BN_ULONG w); + +/* BN_mul sets |r| = |a| * |b|, where |r| may be the same pointer as |a| or + * |b|. Returns one on success and zero otherwise. */ +OPENSSL_EXPORT int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + BN_CTX *ctx); + +/* BN_mul_word sets |bn| = |bn| * |w|. It returns one on success or zero on + * allocation failure. */ +OPENSSL_EXPORT int BN_mul_word(BIGNUM *bn, BN_ULONG w); + +/* BN_sqr sets |r| = |a|^2 (i.e. squares), where |r| may be the same pointer as + * |a|. Returns one on success and zero otherwise. This is more efficient than + * BN_mul(r, a, a, ctx). */ +OPENSSL_EXPORT int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx); + +/* BN_div divides |numerator| by |divisor| and places the result in |quotient| + * and the remainder in |rem|. Either of |quotient| or |rem| may be NULL, in + * which case the respective value is not returned. The result is rounded + * towards zero; thus if |numerator| is negative, the remainder will be zero or + * negative. It returns one on success or zero on error. */ +OPENSSL_EXPORT int BN_div(BIGNUM *quotient, BIGNUM *rem, + const BIGNUM *numerator, const BIGNUM *divisor, + BN_CTX *ctx); + +/* BN_div_word sets |numerator| = |numerator|/|divisor| and returns the + * remainder or (BN_ULONG)-1 on error. */ +OPENSSL_EXPORT BN_ULONG BN_div_word(BIGNUM *numerator, BN_ULONG divisor); + +/* BN_sqrt sets |*out_sqrt| (which may be the same |BIGNUM| as |in|) to the + * square root of |in|, using |ctx|. It returns one on success or zero on + * error. Negative numbers and non-square numbers will result in an error with + * appropriate errors on the error queue. */ +OPENSSL_EXPORT int BN_sqrt(BIGNUM *out_sqrt, const BIGNUM *in, BN_CTX *ctx); + + +/* Comparison functions */ + +/* BN_cmp returns a value less than, equal to or greater than zero if |a| is + * less than, equal to or greater than |b|, respectively. */ +OPENSSL_EXPORT int BN_cmp(const BIGNUM *a, const BIGNUM *b); + +/* BN_ucmp returns a value less than, equal to or greater than zero if the + * absolute value of |a| is less than, equal to or greater than the absolute + * value of |b|, respectively. */ +OPENSSL_EXPORT int BN_ucmp(const BIGNUM *a, const BIGNUM *b); + +/* BN_abs_is_word returns one if the absolute value of |bn| equals |w| and zero + * otherwise. */ +OPENSSL_EXPORT int BN_abs_is_word(const BIGNUM *bn, BN_ULONG w); + +/* BN_is_zero returns one if |bn| is zero and zero otherwise. */ +OPENSSL_EXPORT int BN_is_zero(const BIGNUM *bn); + +/* BN_is_one returns one if |bn| equals one and zero otherwise. */ +OPENSSL_EXPORT int BN_is_one(const BIGNUM *bn); + +/* BN_is_word returns one if |bn| is exactly |w| and zero otherwise. */ +OPENSSL_EXPORT int BN_is_word(const BIGNUM *bn, BN_ULONG w); + +/* BN_is_odd returns one if |bn| is odd and zero otherwise. */ +OPENSSL_EXPORT int BN_is_odd(const BIGNUM *bn); + + +/* Bitwise operations. */ + +/* BN_lshift sets |r| equal to |a| << n. The |a| and |r| arguments may be the + * same |BIGNUM|. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_lshift(BIGNUM *r, const BIGNUM *a, int n); + +/* BN_lshift1 sets |r| equal to |a| << 1, where |r| and |a| may be the same + * pointer. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_lshift1(BIGNUM *r, const BIGNUM *a); + +/* BN_rshift sets |r| equal to |a| >> n, where |r| and |a| may be the same + * pointer. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_rshift(BIGNUM *r, const BIGNUM *a, int n); + +/* BN_rshift1 sets |r| equal to |a| >> 1, where |r| and |a| may be the same + * pointer. It returns one on success and zero on allocation failure. */ +OPENSSL_EXPORT int BN_rshift1(BIGNUM *r, const BIGNUM *a); + +/* BN_set_bit sets the |n|th, least-significant bit in |a|. For example, if |a| + * is 2 then setting bit zero will make it 3. It returns one on success or zero + * on allocation failure. */ +OPENSSL_EXPORT int BN_set_bit(BIGNUM *a, int n); + +/* BN_clear_bit clears the |n|th, least-significant bit in |a|. For example, if + * |a| is 3, clearing bit zero will make it two. It returns one on success or + * zero on allocation failure. */ +OPENSSL_EXPORT int BN_clear_bit(BIGNUM *a, int n); + +/* BN_is_bit_set returns the value of the |n|th, least-significant bit in |a|, + * or zero if the bit doesn't exist. */ +OPENSSL_EXPORT int BN_is_bit_set(const BIGNUM *a, int n); + +/* BN_mask_bits truncates |a| so that it is only |n| bits long. It returns one + * on success or zero if |n| is greater than the length of |a| already. */ +OPENSSL_EXPORT int BN_mask_bits(BIGNUM *a, int n); + + +/* Modulo arithmetic. */ + +/* BN_mod_word returns |a| mod |w|. */ +OPENSSL_EXPORT BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w); + +/* BN_mod is a helper macro that calls |BN_div| and discards the quotient. */ +#define BN_mod(rem, numerator, divisor, ctx) \ + BN_div(NULL, (rem), (numerator), (divisor), (ctx)) + +/* BN_nnmod is a non-negative modulo function. It acts like |BN_mod|, but 0 <= + * |rem| < |divisor| is always true. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int BN_nnmod(BIGNUM *rem, const BIGNUM *numerator, + const BIGNUM *divisor, BN_CTX *ctx); + +/* BN_mod_add sets |r| = |a| + |b| mod |m|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m, BN_CTX *ctx); + +/* BN_mod_add_quick acts like |BN_mod_add| but requires that |a| and |b| be + * non-negative and less than |m|. */ +OPENSSL_EXPORT int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m); + +/* BN_mod_sub sets |r| = |a| - |b| mod |m|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m, BN_CTX *ctx); + +/* BN_mod_sub_quick acts like |BN_mod_sub| but requires that |a| and |b| be + * non-negative and less than |m|. */ +OPENSSL_EXPORT int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m); + +/* BN_mod_mul sets |r| = |a|*|b| mod |m|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + const BIGNUM *m, BN_CTX *ctx); + +/* BN_mod_mul sets |r| = |a|^2 mod |m|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, + BN_CTX *ctx); + +/* BN_mod_lshift sets |r| = (|a| << n) mod |m|, where |r| and |a| may be the + * same pointer. It returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, + const BIGNUM *m, BN_CTX *ctx); + +/* BN_mod_lshift_quick acts like |BN_mod_lshift| but requires that |a| be + * non-negative and less than |m|. */ +OPENSSL_EXPORT int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, + const BIGNUM *m); + +/* BN_mod_lshift1 sets |r| = (|a| << 1) mod |m|, where |r| and |a| may be the + * same pointer. It returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, + BN_CTX *ctx); + +/* BN_mod_lshift1_quick acts like |BN_mod_lshift1| but requires that |a| be + * non-negative and less than |m|. */ +OPENSSL_EXPORT int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, + const BIGNUM *m); + +/* BN_mod_sqrt returns a |BIGNUM|, r, such that r^2 == a (mod p). */ +OPENSSL_EXPORT BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx); + + +/* Random and prime number generation. */ + +/* BN_rand sets |rnd| to a random number of length |bits|. If |top| is zero, the + * most-significant bit, if any, will be set. If |top| is one, the two most + * significant bits, if any, will be set. + * + * If |top| is -1 then no extra action will be taken and |BN_num_bits(rnd)| may + * not equal |bits| if the most significant bits randomly ended up as zeros. + * + * If |bottom| is non-zero, the least-significant bit, if any, will be set. The + * function returns one on success or zero otherwise. */ +OPENSSL_EXPORT int BN_rand(BIGNUM *rnd, int bits, int top, int bottom); + +/* BN_pseudo_rand is an alias for |BN_rand|. */ +OPENSSL_EXPORT int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom); + +/* BN_rand_range sets |rnd| to a random value [0..range). It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int BN_rand_range(BIGNUM *rnd, const BIGNUM *range); + +/* BN_pseudo_rand_range is an alias for BN_rand_range. */ +OPENSSL_EXPORT int BN_pseudo_rand_range(BIGNUM *rnd, const BIGNUM *range); + +/* BN_generate_dsa_nonce generates a random number 0 <= out < range. Unlike + * BN_rand_range, it also includes the contents of |priv| and |message| in the + * generation so that an RNG failure isn't fatal as long as |priv| remains + * secret. This is intended for use in DSA and ECDSA where an RNG weakness + * leads directly to private key exposure unless this function is used. + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_generate_dsa_nonce(BIGNUM *out, const BIGNUM *range, + const BIGNUM *priv, + const uint8_t *message, + size_t message_len, BN_CTX *ctx); + +/* BN_GENCB holds a callback function that is used by generation functions that + * can take a very long time to complete. Use |BN_GENCB_set| to initialise a + * |BN_GENCB| structure. + * + * The callback receives the address of that |BN_GENCB| structure as its last + * argument and the user is free to put an arbitary pointer in |arg|. The other + * arguments are set as follows: + * event=BN_GENCB_GENERATED, n=i: after generating the i'th possible prime + * number. + * event=BN_GENCB_PRIME_TEST, n=-1: when finished trial division primality + * checks. + * event=BN_GENCB_PRIME_TEST, n=i: when the i'th primality test has finished. + * + * The callback can return zero to abort the generation progress or one to + * allow it to continue. + * + * When other code needs to call a BN generation function it will often take a + * BN_GENCB argument and may call the function with other argument values. */ +#define BN_GENCB_GENERATED 0 +#define BN_GENCB_PRIME_TEST 1 + +struct bn_gencb_st { + void *arg; /* callback-specific data */ + int (*callback)(int event, int n, struct bn_gencb_st *); +}; + +/* BN_GENCB_set configures |callback| to call |f| and sets |callout->arg| to + * |arg|. */ +OPENSSL_EXPORT void BN_GENCB_set(BN_GENCB *callback, + int (*f)(int event, int n, + struct bn_gencb_st *), + void *arg); + +/* BN_GENCB_call calls |callback|, if not NULL, and returns the return value of + * the callback, or 1 if |callback| is NULL. */ +OPENSSL_EXPORT int BN_GENCB_call(BN_GENCB *callback, int event, int n); + +/* BN_generate_prime_ex sets |ret| to a prime number of |bits| length. If safe + * is non-zero then the prime will be such that (ret-1)/2 is also a prime. + * (This is needed for Diffie-Hellman groups to ensure that the only subgroups + * are of size 2 and (p-1)/2.). + * + * If |add| is not NULL, the prime will fulfill the condition |ret| % |add| == + * |rem| in order to suit a given generator. (If |rem| is NULL then |ret| % + * |add| == 1.) + * + * If |cb| is not NULL, it will be called during processing to give an + * indication of progress. See the comments for |BN_GENCB|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int BN_generate_prime_ex(BIGNUM *ret, int bits, int safe, + const BIGNUM *add, const BIGNUM *rem, + BN_GENCB *cb); + +/* BN_prime_checks is magic value that can be used as the |checks| argument to + * the primality testing functions in order to automatically select a number of + * Miller-Rabin checks that gives a false positive rate of ~2^{-80}. */ +#define BN_prime_checks 0 + +/* BN_primality_test sets |*is_probably_prime| to one if |candidate| is + * probably a prime number by the Miller-Rabin test or zero if it's certainly + * not. + * + * If |do_trial_division| is non-zero then |candidate| will be tested against a + * list of small primes before Miller-Rabin tests. The probability of this + * function returning a false positive is 2^{2*checks}. If |checks| is + * |BN_prime_checks| then a value that results in approximately 2^{-80} false + * positive probability is used. If |cb| is not NULL then it is called during + * the checking process. See the comment above |BN_GENCB|. + * + * The function returns one on success and zero on error. + * + * (If you are unsure whether you want |do_trial_division|, don't set it.) */ +OPENSSL_EXPORT int BN_primality_test(int *is_probably_prime, + const BIGNUM *candidate, int checks, + BN_CTX *ctx, int do_trial_division, + BN_GENCB *cb); + +/* BN_is_prime_fasttest_ex returns one if |candidate| is probably a prime + * number by the Miller-Rabin test, zero if it's certainly not and -1 on error. + * + * If |do_trial_division| is non-zero then |candidate| will be tested against a + * list of small primes before Miller-Rabin tests. The probability of this + * function returning one when |candidate| is composite is 2^{2*checks}. If + * |checks| is |BN_prime_checks| then a value that results in approximately + * 2^{-80} false positive probability is used. If |cb| is not NULL then it is + * called during the checking process. See the comment above |BN_GENCB|. + * + * WARNING: deprecated. Use |BN_primality_test|. */ +OPENSSL_EXPORT int BN_is_prime_fasttest_ex(const BIGNUM *candidate, int checks, + BN_CTX *ctx, int do_trial_division, + BN_GENCB *cb); + +/* BN_is_prime_ex acts the same as |BN_is_prime_fasttest_ex| with + * |do_trial_division| set to zero. + * + * WARNING: deprecated: Use |BN_primality_test|. */ +OPENSSL_EXPORT int BN_is_prime_ex(const BIGNUM *candidate, int checks, + BN_CTX *ctx, BN_GENCB *cb); + + +/* Number theory functions */ + +/* BN_gcd sets |r| = gcd(|a|, |b|). It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int BN_gcd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, + BN_CTX *ctx); + +/* BN_mod_inverse sets |out| equal to |a|^-1, mod |n|. If either of |a| or |n| + * have |BN_FLG_CONSTTIME| set then the operation is performed in constant + * time. If |out| is NULL, a fresh BIGNUM is allocated. It returns the result + * or NULL on error. */ +OPENSSL_EXPORT BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, + const BIGNUM *n, BN_CTX *ctx); + +/* BN_kronecker returns the Kronecker symbol of |a| and |b| (which is -1, 0 or + * 1), or -2 on error. */ +OPENSSL_EXPORT int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx); + + +/* Montgomery arithmetic. */ + +/* BN_MONT_CTX contains the precomputed values needed to work in a specific + * Montgomery domain. */ + +/* BN_MONT_CTX_new returns a fresh BN_MONT_CTX or NULL on allocation failure. */ +OPENSSL_EXPORT BN_MONT_CTX *BN_MONT_CTX_new(void); + +/* BN_MONT_CTX_init initialises a stack allocated |BN_MONT_CTX|. */ +OPENSSL_EXPORT void BN_MONT_CTX_init(BN_MONT_CTX *mont); + +/* BN_MONT_CTX_free frees the contexts of |mont| and, if it was originally + * allocated with |BN_MONT_CTX_new|, |mont| itself. */ +OPENSSL_EXPORT void BN_MONT_CTX_free(BN_MONT_CTX *mont); + +/* BN_MONT_CTX_copy sets |to| equal to |from|. It returns |to| on success or + * NULL on error. */ +OPENSSL_EXPORT BN_MONT_CTX *BN_MONT_CTX_copy(BN_MONT_CTX *to, + BN_MONT_CTX *from); + +/* BN_MONT_CTX_set sets up a Montgomery context given the modulus, |mod|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, + BN_CTX *ctx); + +/* BN_MONT_CTX_set_locked takes |lock| and checks whether |*pmont| is NULL. If + * so, it creates a new |BN_MONT_CTX| and sets the modulus for it to |mod|. It + * then stores it as |*pmont| and returns it, or NULL on error. + * + * If |*pmont| is already non-NULL then the existing value is returned. */ +BN_MONT_CTX *BN_MONT_CTX_set_locked(BN_MONT_CTX **pmont, CRYPTO_MUTEX *lock, + const BIGNUM *mod, BN_CTX *bn_ctx); + +/* BN_to_montgomery sets |ret| equal to |a| in the Montgomery domain. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int BN_to_montgomery(BIGNUM *ret, const BIGNUM *a, + const BN_MONT_CTX *mont, BN_CTX *ctx); + +/* BN_from_montgomery sets |ret| equal to |a| * R^-1, i.e. translates values + * out of the Montgomery domain. It returns one on success or zero on error. */ +OPENSSL_EXPORT int BN_from_montgomery(BIGNUM *ret, const BIGNUM *a, + const BN_MONT_CTX *mont, BN_CTX *ctx); + +/* BN_mod_mul_montgomery set |r| equal to |a| * |b|, in the Montgomery domain. + * Both |a| and |b| must already be in the Montgomery domain (by + * |BN_to_montgomery|). It returns one on success or zero on error. */ +OPENSSL_EXPORT int BN_mod_mul_montgomery(BIGNUM *r, const BIGNUM *a, + const BIGNUM *b, + const BN_MONT_CTX *mont, BN_CTX *ctx); + + +/* Exponentiation. */ + +/* BN_exp sets |r| equal to |a|^{|p|}. It does so with a square-and-multiply + * algorithm that leaks side-channel information. It returns one on success or + * zero otherwise. */ +OPENSSL_EXPORT int BN_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + BN_CTX *ctx); + +/* BN_mod_exp sets |r| equal to |a|^{|p|} mod |m|. It does so with the best + * algorithm for the values provided and can run in constant time if + * |BN_FLG_CONSTTIME| is set for |p|. It returns one on success or zero + * otherwise. */ +OPENSSL_EXPORT int BN_mod_exp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx); + +OPENSSL_EXPORT int BN_mod_exp_mont(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); + +OPENSSL_EXPORT int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, + const BIGNUM *p, const BIGNUM *m, + BN_CTX *ctx, BN_MONT_CTX *in_mont); + +OPENSSL_EXPORT int BN_mod_exp_mont_word(BIGNUM *r, BN_ULONG a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); +OPENSSL_EXPORT int BN_mod_exp2_mont(BIGNUM *r, const BIGNUM *a1, + const BIGNUM *p1, const BIGNUM *a2, + const BIGNUM *p2, const BIGNUM *m, + BN_CTX *ctx, BN_MONT_CTX *m_ctx); + + +/* Private functions */ + +struct bignum_st { + BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks in little-endian + order. */ + int top; /* Index of last used element in |d|, plus one. */ + int dmax; /* Size of |d|, in words. */ + int neg; /* one if the number is negative */ + int flags; /* bitmask of BN_FLG_* values */ +}; + +struct bn_mont_ctx_st { + BIGNUM RR; /* used to convert to montgomery form */ + BIGNUM N; /* The modulus */ + BIGNUM Ni; /* R*(1/R mod N) - N*Ni = 1 + * (Ni is only stored for bignum algorithm) */ + BN_ULONG n0[2]; /* least significant word(s) of Ni; + (type changed with 0.9.9, was "BN_ULONG n0;" before) */ + int flags; + int ri; /* number of bits in R */ +}; + +OPENSSL_EXPORT unsigned BN_num_bits_word(BN_ULONG l); + +#define BN_FLG_MALLOCED 0x01 +#define BN_FLG_STATIC_DATA 0x02 +/* avoid leaking exponent information through timing, BN_mod_exp_mont() will + * call BN_mod_exp_mont_consttime, BN_div() will call BN_div_no_branch, + * BN_mod_inverse() will call BN_mod_inverse_no_branch. */ +#define BN_FLG_CONSTTIME 0x04 + + +/* Android compatibility section. + * + * These functions are declared, temporarily, for Android because + * wpa_supplicant will take a little time to sync with upstream. Outside of + * Android they'll have no definition. */ + +OPENSSL_EXPORT BIGNUM *get_rfc3526_prime_1536(BIGNUM *bn); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define BN_R_ARG2_LT_ARG3 100 +#define BN_R_BAD_RECIPROCAL 101 +#define BN_R_BIGNUM_TOO_LONG 102 +#define BN_R_BITS_TOO_SMALL 103 +#define BN_R_CALLED_WITH_EVEN_MODULUS 104 +#define BN_R_DIV_BY_ZERO 105 +#define BN_R_EXPAND_ON_STATIC_BIGNUM_DATA 106 +#define BN_R_INPUT_NOT_REDUCED 107 +#define BN_R_INVALID_RANGE 108 +#define BN_R_NEGATIVE_NUMBER 109 +#define BN_R_NOT_A_SQUARE 110 +#define BN_R_NOT_INITIALIZED 111 +#define BN_R_NO_INVERSE 112 +#define BN_R_PRIVATE_KEY_TOO_LARGE 113 +#define BN_R_P_IS_NOT_PRIME 114 +#define BN_R_TOO_MANY_ITERATIONS 115 +#define BN_R_TOO_MANY_TEMPORARY_VARIABLES 116 +#define BN_R_BAD_ENCODING 117 +#define BN_R_ENCODE_ERROR 118 + +#endif /* OPENSSL_HEADER_BN_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/buf.h b/TMessagesProj/jni/boringssl/include/openssl/buf.h new file mode 100644 index 00000000..76e3795e --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/buf.h @@ -0,0 +1,118 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_BUFFER_H +#define OPENSSL_HEADER_BUFFER_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Memory and string functions, see also mem.h. */ + + +/* BUF_MEM is a generic buffer object used by OpenSSL. */ +struct buf_mem_st { + size_t length; /* current number of bytes */ + char *data; + size_t max; /* size of buffer */ +}; + +/* BUF_MEM_new creates a new BUF_MEM which has no allocated data buffer. */ +OPENSSL_EXPORT BUF_MEM *BUF_MEM_new(void); + +/* BUF_MEM_free frees |buf->data| if needed and then frees |buf| itself. */ +OPENSSL_EXPORT void BUF_MEM_free(BUF_MEM *buf); + +/* BUF_MEM_grow ensures that |buf| has length |len| and allocates memory if + * needed. If the length of |buf| increased, the new bytes are filled with + * zeros. It returns the length of |buf|, or zero if there's an error. */ +OPENSSL_EXPORT size_t BUF_MEM_grow(BUF_MEM *buf, size_t len); + +/* BUF_MEM_grow_clean acts the same as |BUF_MEM_grow|, but clears the previous + * contents of memory if reallocing. */ +OPENSSL_EXPORT size_t BUF_MEM_grow_clean(BUF_MEM *str, size_t len); + +/* BUF_strdup returns an allocated, duplicate of |str|. */ +OPENSSL_EXPORT char *BUF_strdup(const char *str); + +/* BUF_strnlen returns the number of characters in |str|, excluding the NUL + * byte, but at most |max_len|. This function never reads more than |max_len| + * bytes from |str|. */ +OPENSSL_EXPORT size_t BUF_strnlen(const char *str, size_t max_len); + +/* BUF_strndup returns an allocated, duplicate of |str|, which is, at most, + * |size| bytes. The result is always NUL terminated. */ +OPENSSL_EXPORT char *BUF_strndup(const char *str, size_t size); + +/* BUF_memdup returns an allocated, duplicate of |size| bytes from |data|. */ +OPENSSL_EXPORT void *BUF_memdup(const void *data, size_t size); + +/* BUF_strlcpy acts like strlcpy(3). */ +OPENSSL_EXPORT size_t BUF_strlcpy(char *dst, const char *src, size_t dst_size); + +/* BUF_strlcat acts like strlcat(3). */ +OPENSSL_EXPORT size_t BUF_strlcat(char *dst, const char *src, size_t size); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BUFFER_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/buffer.h b/TMessagesProj/jni/boringssl/include/openssl/buffer.h new file mode 100644 index 00000000..c6b721c2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/buffer.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "buf.h" diff --git a/TMessagesProj/jni/boringssl/include/openssl/bytestring.h b/TMessagesProj/jni/boringssl/include/openssl/bytestring.h new file mode 100644 index 00000000..4fceeaab --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/bytestring.h @@ -0,0 +1,349 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_BYTESTRING_H +#define OPENSSL_HEADER_BYTESTRING_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Bytestrings are used for parsing and building TLS and ASN.1 messages. + * + * A "CBS" (CRYPTO ByteString) represents a string of bytes in memory and + * provides utility functions for safely parsing length-prefixed structures + * like TLS and ASN.1 from it. + * + * A "CBB" (CRYPTO ByteBuilder) is a memory buffer that grows as needed and + * provides utility functions for building length-prefixed messages. */ + + +/* CRYPTO ByteString */ + +struct cbs_st { + const uint8_t *data; + size_t len; +}; + +/* CBS_init sets |cbs| to point to |data|. It does not take ownership of + * |data|. */ +OPENSSL_EXPORT void CBS_init(CBS *cbs, const uint8_t *data, size_t len); + +/* CBS_skip advances |cbs| by |len| bytes. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int CBS_skip(CBS *cbs, size_t len); + +/* CBS_data returns a pointer to the contents of |cbs|. */ +OPENSSL_EXPORT const uint8_t *CBS_data(const CBS *cbs); + +/* CBS_len returns the number of bytes remaining in |cbs|. */ +OPENSSL_EXPORT size_t CBS_len(const CBS *cbs); + +/* CBS_stow copies the current contents of |cbs| into |*out_ptr| and + * |*out_len|. If |*out_ptr| is not NULL, the contents are freed with + * OPENSSL_free. It returns one on success and zero on allocation failure. On + * success, |*out_ptr| should be freed with OPENSSL_free. If |cbs| is empty, + * |*out_ptr| will be NULL. */ +OPENSSL_EXPORT int CBS_stow(const CBS *cbs, uint8_t **out_ptr, size_t *out_len); + +/* CBS_strdup copies the current contents of |cbs| into |*out_ptr| as a + * NUL-terminated C string. If |*out_ptr| is not NULL, the contents are freed + * with OPENSSL_free. It returns one on success and zero on allocation + * failure. On success, |*out_ptr| should be freed with OPENSSL_free. + * + * NOTE: If |cbs| contains NUL bytes, the string will be truncated. Call + * |CBS_contains_zero_byte(cbs)| to check for NUL bytes. */ +OPENSSL_EXPORT int CBS_strdup(const CBS *cbs, char **out_ptr); + +/* CBS_contains_zero_byte returns one if the current contents of |cbs| contains + * a NUL byte and zero otherwise. */ +OPENSSL_EXPORT int CBS_contains_zero_byte(const CBS *cbs); + +/* CBS_mem_equal compares the current contents of |cbs| with the |len| bytes + * starting at |data|. If they're equal, it returns one, otherwise zero. If the + * lengths match, it uses a constant-time comparison. */ +OPENSSL_EXPORT int CBS_mem_equal(const CBS *cbs, const uint8_t *data, + size_t len); + +/* CBS_get_u8 sets |*out| to the next uint8_t from |cbs| and advances |cbs|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u8(CBS *cbs, uint8_t *out); + +/* CBS_get_u16 sets |*out| to the next, big-endian uint16_t from |cbs| and + * advances |cbs|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u16(CBS *cbs, uint16_t *out); + +/* CBS_get_u24 sets |*out| to the next, big-endian 24-bit value from |cbs| and + * advances |cbs|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u24(CBS *cbs, uint32_t *out); + +/* CBS_get_u32 sets |*out| to the next, big-endian uint32_t value from |cbs| + * and advances |cbs|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u32(CBS *cbs, uint32_t *out); + +/* CBS_get_bytes sets |*out| to the next |len| bytes from |cbs| and advances + * |cbs|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_bytes(CBS *cbs, CBS *out, size_t len); + +/* CBS_get_u8_length_prefixed sets |*out| to the contents of an 8-bit, + * length-prefixed value from |cbs| and advances |cbs| over it. It returns one + * on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u8_length_prefixed(CBS *cbs, CBS *out); + +/* CBS_get_u16_length_prefixed sets |*out| to the contents of a 16-bit, + * big-endian, length-prefixed value from |cbs| and advances |cbs| over it. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u16_length_prefixed(CBS *cbs, CBS *out); + +/* CBS_get_u24_length_prefixed sets |*out| to the contents of a 24-bit, + * big-endian, length-prefixed value from |cbs| and advances |cbs| over it. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out); + + +/* Parsing ASN.1 */ + +#define CBS_ASN1_BOOLEAN 0x1 +#define CBS_ASN1_INTEGER 0x2 +#define CBS_ASN1_BITSTRING 0x3 +#define CBS_ASN1_OCTETSTRING 0x4 +#define CBS_ASN1_NULL 0x5 +#define CBS_ASN1_OBJECT 0x6 +#define CBS_ASN1_ENUMERATED 0xa +#define CBS_ASN1_SEQUENCE (0x10 | CBS_ASN1_CONSTRUCTED) +#define CBS_ASN1_SET (0x11 | CBS_ASN1_CONSTRUCTED) +#define CBS_ASN1_GENERALIZEDTIME 0x18 + +#define CBS_ASN1_CONSTRUCTED 0x20 +#define CBS_ASN1_CONTEXT_SPECIFIC 0x80 + +/* CBS_get_asn1 sets |*out| to the contents of DER-encoded, ASN.1 element (not + * including tag and length bytes) and advances |cbs| over it. The ASN.1 + * element must match |tag_value|. It returns one on success and zero + * on error. + * + * Tag numbers greater than 30 are not supported (i.e. short form only). */ +OPENSSL_EXPORT int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value); + +/* CBS_get_asn1_element acts like |CBS_get_asn1| but |out| will include the + * ASN.1 header bytes too. */ +OPENSSL_EXPORT int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value); + +/* CBS_peek_asn1_tag looks ahead at the next ASN.1 tag and returns one + * if the next ASN.1 element on |cbs| would have tag |tag_value|. If + * |cbs| is empty or the tag does not match, it returns zero. Note: if + * it returns one, CBS_get_asn1 may still fail if the rest of the + * element is malformed. */ +OPENSSL_EXPORT int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value); + +/* CBS_get_any_asn1_element sets |*out| to contain the next ASN.1 element from + * |*cbs| (including header bytes) and advances |*cbs|. It sets |*out_tag| to + * the tag number and |*out_header_len| to the length of the ASN.1 header. Each + * of |out|, |out_tag|, and |out_header_len| may be NULL to ignore the value. + * + * Tag numbers greater than 30 are not supported (i.e. short form only). */ +OPENSSL_EXPORT int CBS_get_any_asn1_element(CBS *cbs, CBS *out, + unsigned *out_tag, + size_t *out_header_len); + +/* CBS_get_any_ber_asn1_element acts the same as |CBS_get_any_asn1_element| but + * also allows indefinite-length elements to be returned. In that case, + * |*out_header_len| and |CBS_len(out)| will both be two as only the header is + * returned, otherwise it behaves the same as the previous function. */ +OPENSSL_EXPORT int CBS_get_any_ber_asn1_element(CBS *cbs, CBS *out, + unsigned *out_tag, + size_t *out_header_len); + +/* CBS_get_asn1_uint64 gets an ASN.1 INTEGER from |cbs| using |CBS_get_asn1| + * and sets |*out| to its value. It returns one on success and zero on error, + * where error includes the integer being negative, or too large to represent + * in 64 bits. */ +OPENSSL_EXPORT int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out); + +/* CBS_get_optional_asn1 gets an optional explicitly-tagged element + * from |cbs| tagged with |tag| and sets |*out| to its contents. If + * present, it sets |*out_present| to one, otherwise zero. It returns + * one on success, whether or not the element was present, and zero on + * decode failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, + unsigned tag); + +/* CBS_get_optional_asn1_octet_string gets an optional + * explicitly-tagged OCTET STRING from |cbs|. If present, it sets + * |*out| to the string and |*out_present| to one. Otherwise, it sets + * |*out| to empty and |*out_present| to zero. |out_present| may be + * NULL. It returns one on success, whether or not the element was + * present, and zero on decode failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, + int *out_present, + unsigned tag); + +/* CBS_get_optional_asn1_uint64 gets an optional explicitly-tagged + * INTEGER from |cbs|. If present, it sets |*out| to the + * value. Otherwise, it sets |*out| to |default_value|. It returns one + * on success, whether or not the element was present, and zero on + * decode failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, + unsigned tag, + uint64_t default_value); + +/* CBS_get_optional_asn1_bool gets an optional, explicitly-tagged BOOLEAN from + * |cbs|. If present, it sets |*out| to either zero or one, based on the + * boolean. Otherwise, it sets |*out| to |default_value|. It returns one on + * success, whether or not the element was present, and zero on decode + * failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, + int default_value); + + +/* CRYPTO ByteBuilder. + * + * |CBB| objects allow one to build length-prefixed serialisations. A |CBB| + * object is associated with a buffer and new buffers are created with + * |CBB_init|. Several |CBB| objects can point at the same buffer when a + * length-prefix is pending, however only a single |CBB| can be 'current' at + * any one time. For example, if one calls |CBB_add_u8_length_prefixed| then + * the new |CBB| points at the same buffer as the original. But if the original + * |CBB| is used then the length prefix is written out and the new |CBB| must + * not be used again. + * + * If one needs to force a length prefix to be written out because a |CBB| is + * going out of scope, use |CBB_flush|. */ + +struct cbb_buffer_st { + uint8_t *buf; + size_t len; /* The number of valid bytes. */ + size_t cap; /* The size of buf. */ + char can_resize; /* One iff |buf| is owned by this object. If not then |buf| + cannot be resized. */ +}; + +struct cbb_st { + struct cbb_buffer_st *base; + /* offset is the offset from the start of |base->buf| to the position of any + * pending length-prefix. */ + size_t offset; + /* child points to a child CBB if a length-prefix is pending. */ + struct cbb_st *child; + /* pending_len_len contains the number of bytes in a pending length-prefix, + * or zero if no length-prefix is pending. */ + uint8_t pending_len_len; + char pending_is_asn1; + /* is_top_level is true iff this is a top-level |CBB| (as opposed to a child + * |CBB|). Top-level objects are valid arguments for |CBB_finish|. */ + char is_top_level; +}; + +/* CBB_zero sets an uninitialised |cbb| to the zero state. It must be + * initialised with |CBB_init| or |CBB_init_fixed| before use, but it is safe to + * call |CBB_cleanup| without a successful |CBB_init|. This may be used for more + * uniform cleanup of a |CBB|. */ +OPENSSL_EXPORT void CBB_zero(CBB *cbb); + +/* CBB_init initialises |cbb| with |initial_capacity|. Since a |CBB| grows as + * needed, the |initial_capacity| is just a hint. It returns one on success or + * zero on error. */ +OPENSSL_EXPORT int CBB_init(CBB *cbb, size_t initial_capacity); + +/* CBB_init_fixed initialises |cbb| to write to |len| bytes at |buf|. Since + * |buf| cannot grow, trying to write more than |len| bytes will cause CBB + * functions to fail. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CBB_init_fixed(CBB *cbb, uint8_t *buf, size_t len); + +/* CBB_cleanup frees all resources owned by |cbb| and other |CBB| objects + * writing to the same buffer. This should be used in an error case where a + * serialisation is abandoned. */ +OPENSSL_EXPORT void CBB_cleanup(CBB *cbb); + +/* CBB_finish completes any pending length prefix and sets |*out_data| to a + * malloced buffer and |*out_len| to the length of that buffer. The caller + * takes ownership of the buffer and, unless the buffer was fixed with + * |CBB_init_fixed|, must call |OPENSSL_free| when done. + * + * It can only be called on a "top level" |CBB|, i.e. one initialised with + * |CBB_init| or |CBB_init_fixed|. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len); + +/* CBB_flush causes any pending length prefixes to be written out and any child + * |CBB| objects of |cbb| to be invalidated. It returns one on success or zero + * on error. */ +OPENSSL_EXPORT int CBB_flush(CBB *cbb); + +/* CBB_len returns the number of bytes written to |cbb|'s top-level |CBB|. It + * may be compared before and after an operation to determine how many bytes + * were written. + * + * It is a fatal error to call this on a CBB with any active children. This does + * not flush |cbb|. */ +OPENSSL_EXPORT size_t CBB_len(const CBB *cbb); + +/* CBB_add_u8_length_prefixed sets |*out_contents| to a new child of |cbb|. The + * data written to |*out_contents| will be prefixed in |cbb| with an 8-bit + * length. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CBB_add_u8_length_prefixed(CBB *cbb, CBB *out_contents); + +/* CBB_add_u16_length_prefixed sets |*out_contents| to a new child of |cbb|. + * The data written to |*out_contents| will be prefixed in |cbb| with a 16-bit, + * big-endian length. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CBB_add_u16_length_prefixed(CBB *cbb, CBB *out_contents); + +/* CBB_add_u24_length_prefixed sets |*out_contents| to a new child of |cbb|. + * The data written to |*out_contents| will be prefixed in |cbb| with a 24-bit, + * big-endian length. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents); + +/* CBB_add_asn1 sets |*out_contents| to a |CBB| into which the contents of an + * ASN.1 object can be written. The |tag| argument will be used as the tag for + * the object. Passing in |tag| number 31 will return in an error since only + * single octet identifiers are supported. It returns one on success or zero + * on error. */ +OPENSSL_EXPORT int CBB_add_asn1(CBB *cbb, CBB *out_contents, uint8_t tag); + +/* CBB_add_bytes appends |len| bytes from |data| to |cbb|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int CBB_add_bytes(CBB *cbb, const uint8_t *data, size_t len); + +/* CBB_add_space appends |len| bytes to |cbb| and sets |*out_data| to point to + * the beginning of that space. The caller must then write |len| bytes of + * actual contents to |*out_data|. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int CBB_add_space(CBB *cbb, uint8_t **out_data, size_t len); + +/* CBB_add_u8 appends an 8-bit number from |value| to |cbb|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int CBB_add_u8(CBB *cbb, uint8_t value); + +/* CBB_add_u16 appends a 16-bit, big-endian number from |value| to |cbb|. It + * returns one on success and zero otherwise. */ +OPENSSL_EXPORT int CBB_add_u16(CBB *cbb, uint16_t value); + +/* CBB_add_u24 appends a 24-bit, big-endian number from |value| to |cbb|. It + * returns one on success and zero otherwise. */ +OPENSSL_EXPORT int CBB_add_u24(CBB *cbb, uint32_t value); + +/* CBB_add_asn1_uint64 writes an ASN.1 INTEGER into |cbb| using |CBB_add_asn1| + * and writes |value| in its contents. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int CBB_add_asn1_uint64(CBB *cbb, uint64_t value); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_BYTESTRING_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/cast.h b/TMessagesProj/jni/boringssl/include/openssl/cast.h new file mode 100644 index 00000000..80217239 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/cast.h @@ -0,0 +1,96 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_CAST_H +#define OPENSSL_HEADER_CAST_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define CAST_ENCRYPT 1 +#define CAST_DECRYPT 0 + +#define CAST_BLOCK 8 +#define CAST_KEY_LENGTH 16 + +typedef struct cast_key_st { + uint32_t data[32]; + int short_key; /* Use reduced rounds for short key */ +} CAST_KEY; + +OPENSSL_EXPORT void CAST_set_key(CAST_KEY *key, size_t len, + const uint8_t *data); +OPENSSL_EXPORT void CAST_ecb_encrypt(const uint8_t *in, uint8_t *out, + const CAST_KEY *key, int enc); +OPENSSL_EXPORT void CAST_encrypt(uint32_t *data, const CAST_KEY *key); +OPENSSL_EXPORT void CAST_decrypt(uint32_t *data, const CAST_KEY *key); +OPENSSL_EXPORT void CAST_cbc_encrypt(const uint8_t *in, uint8_t *out, + long length, const CAST_KEY *ks, + uint8_t *iv, int enc); + +OPENSSL_EXPORT void CAST_cfb64_encrypt(const uint8_t *in, uint8_t *out, + long length, const CAST_KEY *schedule, + uint8_t *ivec, int *num, int enc); + +#ifdef __cplusplus +} +#endif + +#endif /* OPENSSL_HEADER_CAST_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/chacha.h b/TMessagesProj/jni/boringssl/include/openssl/chacha.h new file mode 100644 index 00000000..b7f58828 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/chacha.h @@ -0,0 +1,37 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_CHACHA_H +#define OPENSSL_HEADER_CHACHA_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* CRYPTO_chacha_20 encrypts |in_len| bytes from |in| with the given key and + * nonce and writes the result to |out|, which may be equal to |in|. The + * initial block counter is specified by |counter|. */ +OPENSSL_EXPORT void CRYPTO_chacha_20(uint8_t *out, const uint8_t *in, + size_t in_len, const uint8_t key[32], + const uint8_t nonce[8], size_t counter); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CHACHA_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/cipher.h b/TMessagesProj/jni/boringssl/include/openssl/cipher.h new file mode 100644 index 00000000..eb000825 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/cipher.h @@ -0,0 +1,565 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_CIPHER_H +#define OPENSSL_HEADER_CIPHER_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Ciphers. */ + + +/* Cipher primitives. + * + * The following functions return |EVP_CIPHER| objects that implement the named + * cipher algorithm. */ + +OPENSSL_EXPORT const EVP_CIPHER *EVP_rc4(void); + +OPENSSL_EXPORT const EVP_CIPHER *EVP_des_cbc(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_des_ede3_cbc(void); + +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_ecb(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_cbc(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_ctr(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_ofb(void); + +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_ecb(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_cbc(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_ctr(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_ofb(void); + +/* Deprecated AES-GCM implementations that set |EVP_CIPH_FLAG_CUSTOM_CIPHER|. + * Use |EVP_aead_aes_128_gcm| and |EVP_aead_aes_256_gcm| instead. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_128_gcm(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_256_gcm(void); + +/* Deprecated 192-bit version of AES. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_192_ecb(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_192_cbc(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_192_ctr(void); +OPENSSL_EXPORT const EVP_CIPHER *EVP_aes_192_gcm(void); + +/* EVP_enc_null returns a 'cipher' that passes plaintext through as + * ciphertext. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_enc_null(void); + +/* EVP_rc2_cbc returns a cipher that implements 128-bit RC2 in CBC mode. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_rc2_cbc(void); + +/* EVP_rc2_40_cbc returns a cipher that implements 40-bit RC2 in CBC mode. This + * is obviously very, very weak and is included only in order to read PKCS#12 + * files, which often encrypt the certificate chain using this cipher. It is + * deliberately not exported. */ +const EVP_CIPHER *EVP_rc2_40_cbc(void); + +/* EVP_get_cipherbynid returns the cipher corresponding to the given NID, or + * NULL if no such cipher is known. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_get_cipherbynid(int nid); + + +/* Cipher context allocation. + * + * An |EVP_CIPHER_CTX| represents the state of an encryption or decryption in + * progress. */ + +/* EVP_CIPHER_CTX_init initialises an, already allocated, |EVP_CIPHER_CTX|. */ +OPENSSL_EXPORT void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_new allocates a fresh |EVP_CIPHER_CTX|, calls + * |EVP_CIPHER_CTX_init| and returns it, or NULL on allocation failure. */ +OPENSSL_EXPORT EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void); + +/* EVP_CIPHER_CTX_cleanup frees any memory referenced by |ctx|. It returns + * one. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_free calls |EVP_CIPHER_CTX_cleanup| on |ctx| and then frees + * |ctx| itself. */ +OPENSSL_EXPORT void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_copy sets |out| to be a duplicate of the current state of + * |in|. The |out| argument must have been previously initialised. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, + const EVP_CIPHER_CTX *in); + + +/* Cipher context configuration. */ + +/* EVP_CipherInit_ex configures |ctx| for a fresh encryption (or decryption, if + * |enc| is zero) operation using |cipher|. If |ctx| has been previously + * configured with a cipher then |cipher|, |key| and |iv| may be |NULL| and + * |enc| may be -1 to reuse the previous values. The operation will use |key| + * as the key and |iv| as the IV (if any). These should have the correct + * lengths given by |EVP_CIPHER_key_length| and |EVP_CIPHER_iv_length|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, ENGINE *engine, + const uint8_t *key, const uint8_t *iv, + int enc); + +/* EVP_EncryptInit_ex calls |EVP_CipherInit_ex| with |enc| equal to one. */ +OPENSSL_EXPORT int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, ENGINE *impl, + const uint8_t *key, const uint8_t *iv); + +/* EVP_DecryptInit_ex calls |EVP_CipherInit_ex| with |enc| equal to zero. */ +OPENSSL_EXPORT int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, ENGINE *impl, + const uint8_t *key, const uint8_t *iv); + + +/* Cipher operations. */ + +/* EVP_EncryptUpdate encrypts |in_len| bytes from |in| to |out|. The number + * of output bytes may be up to |in_len| plus the block length minus one and + * |out| must have sufficient space. The number of bytes actually output is + * written to |*out_len|. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + int in_len); + +/* EVP_EncryptFinal_ex writes at most a block of ciphertext to |out| and sets + * |*out_len| to the number of bytes written. If padding is enabled (the + * default) then standard padding is applied to create the final block. If + * padding is disabled (with |EVP_CIPHER_CTX_set_padding|) then any partial + * block remaining will cause an error. The function returns one on success and + * zero otherwise. */ +OPENSSL_EXPORT int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len); + +/* EVP_DecryptUpdate decrypts |in_len| bytes from |in| to |out|. The number of + * output bytes may be up to |in_len| plus the block length minus one and |out| + * must have sufficient space. The number of bytes actually output is written + * to |*out_len|. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + int in_len); + +/* EVP_DecryptFinal_ex writes at most a block of ciphertext to |out| and sets + * |*out_len| to the number of bytes written. If padding is enabled (the + * default) then padding is removed from the final block. + * + * WARNING: it is unsafe to call this function with unauthenticted + * ciphertext if padding is enabled. */ +OPENSSL_EXPORT int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, + int *out_len); + +/* EVP_Cipher performs a one-shot encryption/decryption operation. No partial + * blocks are maintained between calls. However, any internal cipher state is + * still updated. For CBC-mode ciphers, the IV is updated to the final + * ciphertext block. For stream ciphers, the stream is advanced past the bytes + * used. It returns one on success and zero otherwise, unless |EVP_CIPHER_flags| + * has |EVP_CIPH_FLAG_CUSTOM_CIPHER| set. Then it returns the number of bytes + * written or -1 on error. + * + * WARNING: this differs from the usual return value convention when using + * |EVP_CIPH_FLAG_CUSTOM_CIPHER|. + * + * TODO(davidben): The normal ciphers currently never fail, even if, e.g., + * |in_len| is not a multiple of the block size for CBC-mode decryption. The + * input just gets rounded up while the output gets truncated. This should + * either be officially documented or fail. */ +OPENSSL_EXPORT int EVP_Cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, + const uint8_t *in, size_t in_len); + +/* EVP_CipherUpdate calls either |EVP_EncryptUpdate| or |EVP_DecryptUpdate| + * depending on how |ctx| has been setup. */ +OPENSSL_EXPORT int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len, const uint8_t *in, + int in_len); + +/* EVP_CipherFinal_ex calls either |EVP_EncryptFinal_ex| or + * |EVP_DecryptFinal_ex| depending on how |ctx| has been setup. */ +OPENSSL_EXPORT int EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, + int *out_len); + + +/* Cipher context accessors. */ + +/* EVP_CIPHER_CTX_cipher returns the |EVP_CIPHER| underlying |ctx|, or NULL if + * none has been set. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_CIPHER_CTX_cipher( + const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_nid returns a NID identifying the |EVP_CIPHER| underlying + * |ctx| (e.g. |NID_aes_128_gcm|). It will crash if no cipher has been + * configured. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_nid(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_block_size returns the block size, in bytes, of the cipher + * underlying |ctx|, or one if the cipher is a stream cipher. It will crash if + * no cipher has been configured. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_key_length returns the key size, in bytes, of the cipher + * underlying |ctx| or zero if no cipher has been configured. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_CTX_key_length(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_iv_length returns the IV size, in bytes, of the cipher + * underlying |ctx|. It will crash if no cipher has been configured. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_CTX_iv_length(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_get_app_data returns the opaque, application data pointer for + * |ctx|, or NULL if none has been set. */ +OPENSSL_EXPORT void *EVP_CIPHER_CTX_get_app_data(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_set_app_data sets the opaque, application data pointer for + * |ctx| to |data|. */ +OPENSSL_EXPORT void EVP_CIPHER_CTX_set_app_data(EVP_CIPHER_CTX *ctx, + void *data); + +/* EVP_CIPHER_CTX_flags returns a value which is the OR of zero or more + * |EVP_CIPH_*| flags. It will crash if no cipher has been configured. */ +OPENSSL_EXPORT uint32_t EVP_CIPHER_CTX_flags(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_mode returns one of the |EVP_CIPH_*| cipher mode values + * enumerated below. It will crash if no cipher has been configured. */ +OPENSSL_EXPORT uint32_t EVP_CIPHER_CTX_mode(const EVP_CIPHER_CTX *ctx); + +/* EVP_CIPHER_CTX_ctrl is an |ioctl| like function. The |command| argument + * should be one of the |EVP_CTRL_*| values. The |arg| and |ptr| arguments are + * specific to the command in question. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int command, + int arg, void *ptr); + +/* EVP_CIPHER_CTX_set_padding sets whether padding is enabled for |ctx| and + * returns one. Pass a non-zero |pad| to enable padding (the default) or zero + * to disable. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad); + +/* EVP_CIPHER_CTX_set_key_length sets the key length for |ctx|. This is only + * valid for ciphers that can take a variable length key. It returns one on + * success and zero on error. */ +OPENSSL_EXPORT int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *ctx, unsigned key_len); + + +/* Cipher accessors. */ + +/* EVP_CIPHER_nid returns a NID identifing |cipher|. (For example, + * |NID_aes_128_gcm|.) */ +OPENSSL_EXPORT int EVP_CIPHER_nid(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_block_size returns the block size, in bytes, for |cipher|, or one + * if |cipher| is a stream cipher. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_block_size(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_key_length returns the key size, in bytes, for |cipher|. If + * |cipher| can take a variable key length then this function returns the + * default key length and |EVP_CIPHER_flags| will return a value with + * |EVP_CIPH_VARIABLE_LENGTH| set. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_key_length(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_iv_length returns the IV size, in bytes, of |cipher|, or zero if + * |cipher| doesn't take an IV. */ +OPENSSL_EXPORT unsigned EVP_CIPHER_iv_length(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_flags returns a value which is the OR of zero or more + * |EVP_CIPH_*| flags. */ +OPENSSL_EXPORT uint32_t EVP_CIPHER_flags(const EVP_CIPHER *cipher); + +/* EVP_CIPHER_mode returns one of the cipher mode values enumerated below. */ +OPENSSL_EXPORT uint32_t EVP_CIPHER_mode(const EVP_CIPHER *cipher); + + +/* Key derivation. */ + +/* EVP_BytesToKey generates a key and IV for the cipher |type| by iterating + * |md| |count| times using |data| and |salt|. On entry, the |key| and |iv| + * buffers must have enough space to hold a key and IV for |type|. It returns + * the length of the key on success or zero on error. */ +OPENSSL_EXPORT int EVP_BytesToKey(const EVP_CIPHER *type, const EVP_MD *md, + const uint8_t *salt, const uint8_t *data, + size_t data_len, unsigned count, uint8_t *key, + uint8_t *iv); + + +/* Cipher modes (for |EVP_CIPHER_mode|). */ + +#define EVP_CIPH_STREAM_CIPHER 0x0 +#define EVP_CIPH_ECB_MODE 0x1 +#define EVP_CIPH_CBC_MODE 0x2 +#define EVP_CIPH_CFB_MODE 0x3 +#define EVP_CIPH_OFB_MODE 0x4 +#define EVP_CIPH_CTR_MODE 0x5 +#define EVP_CIPH_GCM_MODE 0x6 + + +/* Cipher flags (for |EVP_CIPHER_flags|). */ + +/* EVP_CIPH_VARIABLE_LENGTH indicates that the cipher takes a variable length + * key. */ +#define EVP_CIPH_VARIABLE_LENGTH 0x40 + +/* EVP_CIPH_ALWAYS_CALL_INIT indicates that the |init| function for the cipher + * should always be called when initialising a new operation, even if the key + * is NULL to indicate that the same key is being used. */ +#define EVP_CIPH_ALWAYS_CALL_INIT 0x80 + +/* EVP_CIPH_CUSTOM_IV indicates that the cipher manages the IV itself rather + * than keeping it in the |iv| member of |EVP_CIPHER_CTX|. */ +#define EVP_CIPH_CUSTOM_IV 0x100 + +/* EVP_CIPH_CTRL_INIT indicates that EVP_CTRL_INIT should be used when + * initialising an |EVP_CIPHER_CTX|. */ +#define EVP_CIPH_CTRL_INIT 0x200 + +/* EVP_CIPH_FLAG_CUSTOM_CIPHER indicates that the cipher manages blocking + * itself. This causes EVP_(En|De)crypt_ex to be simple wrapper functions. */ +#define EVP_CIPH_FLAG_CUSTOM_CIPHER 0x400 + +/* EVP_CIPH_FLAG_AEAD_CIPHER specifies that the cipher is an AEAD. This is an + * older version of the proper AEAD interface. See aead.h for the current + * one. */ +#define EVP_CIPH_FLAG_AEAD_CIPHER 0x800 + +/* EVP_CIPH_CUSTOM_COPY indicates that the |ctrl| callback should be called + * with |EVP_CTRL_COPY| at the end of normal |EVP_CIPHER_CTX_copy| + * processing. */ +#define EVP_CIPH_CUSTOM_COPY 0x1000 + + +/* Deprecated functions */ + +/* EVP_CipherInit acts like EVP_CipherInit_ex except that |EVP_CIPHER_CTX_init| + * is called on |cipher| first, if |cipher| is not NULL. */ +OPENSSL_EXPORT int EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const uint8_t *key, const uint8_t *iv, + int enc); + +/* EVP_EncryptInit calls |EVP_CipherInit| with |enc| equal to one. */ +OPENSSL_EXPORT int EVP_EncryptInit(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, const uint8_t *key, + const uint8_t *iv); + +/* EVP_DecryptInit calls |EVP_CipherInit| with |enc| equal to zero. */ +OPENSSL_EXPORT int EVP_DecryptInit(EVP_CIPHER_CTX *ctx, + const EVP_CIPHER *cipher, const uint8_t *key, + const uint8_t *iv); + +/* EVP_add_cipher_alias does nothing and returns one. */ +OPENSSL_EXPORT int EVP_add_cipher_alias(const char *a, const char *b); + +/* EVP_get_cipherbyname returns an |EVP_CIPHER| given a human readable name in + * |name|, or NULL if the name is unknown. */ +OPENSSL_EXPORT const EVP_CIPHER *EVP_get_cipherbyname(const char *name); + + +/* Private functions. */ + +/* EVP_CIPH_NO_PADDING disables padding in block ciphers. */ +#define EVP_CIPH_NO_PADDING 0x800 + +/* EVP_CIPHER_CTX_ctrl commands. */ +#define EVP_CTRL_INIT 0x0 +#define EVP_CTRL_SET_KEY_LENGTH 0x1 +#define EVP_CTRL_GET_RC2_KEY_BITS 0x2 +#define EVP_CTRL_SET_RC2_KEY_BITS 0x3 +#define EVP_CTRL_GET_RC5_ROUNDS 0x4 +#define EVP_CTRL_SET_RC5_ROUNDS 0x5 +#define EVP_CTRL_RAND_KEY 0x6 +#define EVP_CTRL_PBE_PRF_NID 0x7 +#define EVP_CTRL_COPY 0x8 +#define EVP_CTRL_GCM_SET_IVLEN 0x9 +#define EVP_CTRL_GCM_GET_TAG 0x10 +#define EVP_CTRL_GCM_SET_TAG 0x11 +#define EVP_CTRL_GCM_SET_IV_FIXED 0x12 +#define EVP_CTRL_GCM_IV_GEN 0x13 +#define EVP_CTRL_AEAD_SET_MAC_KEY 0x17 +/* Set the GCM invocation field, decrypt only */ +#define EVP_CTRL_GCM_SET_IV_INV 0x18 + +/* GCM TLS constants */ +/* Length of fixed part of IV derived from PRF */ +#define EVP_GCM_TLS_FIXED_IV_LEN 4 +/* Length of explicit part of IV part of TLS records */ +#define EVP_GCM_TLS_EXPLICIT_IV_LEN 8 +/* Length of tag for TLS */ +#define EVP_GCM_TLS_TAG_LEN 16 + +#define EVP_MAX_KEY_LENGTH 64 +#define EVP_MAX_IV_LENGTH 16 +#define EVP_MAX_BLOCK_LENGTH 32 + +struct evp_cipher_ctx_st { + /* cipher contains the underlying cipher for this context. */ + const EVP_CIPHER *cipher; + + /* app_data is a pointer to opaque, user data. */ + void *app_data; /* application stuff */ + + /* cipher_data points to the |cipher| specific state. */ + void *cipher_data; + + /* key_len contains the length of the key, which may differ from + * |cipher->key_len| if the cipher can take a variable key length. */ + unsigned key_len; + + /* encrypt is one if encrypting and zero if decrypting. */ + int encrypt; + + /* flags contains the OR of zero or more |EVP_CIPH_*| flags, above. */ + uint32_t flags; + + /* oiv contains the original IV value. */ + uint8_t oiv[EVP_MAX_IV_LENGTH]; + + /* iv contains the current IV value, which may have been updated. */ + uint8_t iv[EVP_MAX_IV_LENGTH]; + + /* buf contains a partial block which is used by, for example, CTR mode to + * store unused keystream bytes. */ + uint8_t buf[EVP_MAX_BLOCK_LENGTH]; + + /* buf_len contains the number of bytes of a partial block contained in + * |buf|. */ + int buf_len; + + /* num contains the number of bytes of |iv| which are valid for modes that + * manage partial blocks themselves. */ + int num; + + /* final_used is non-zero if the |final| buffer contains plaintext. */ + int final_used; + + /* block_mask contains |cipher->block_size| minus one. (The block size + * assumed to be a power of two.) */ + int block_mask; + + uint8_t final[EVP_MAX_BLOCK_LENGTH]; /* possible final block */ +} /* EVP_CIPHER_CTX */; + +typedef struct evp_cipher_info_st { + const EVP_CIPHER *cipher; + unsigned char iv[EVP_MAX_IV_LENGTH]; +} EVP_CIPHER_INFO; + +struct evp_cipher_st { + /* type contains a NID identifing the cipher. (e.g. NID_aes_128_gcm.) */ + int nid; + + /* block_size contains the block size, in bytes, of the cipher, or 1 for a + * stream cipher. */ + unsigned block_size; + + /* key_len contains the key size, in bytes, for the cipher. If the cipher + * takes a variable key size then this contains the default size. */ + unsigned key_len; + + /* iv_len contains the IV size, in bytes, or zero if inapplicable. */ + unsigned iv_len; + + /* ctx_size contains the size, in bytes, of the per-key context for this + * cipher. */ + unsigned ctx_size; + + /* flags contains the OR of a number of flags. See |EVP_CIPH_*|. */ + uint32_t flags; + + /* app_data is a pointer to opaque, user data. */ + void *app_data; + + int (*init)(EVP_CIPHER_CTX *ctx, const uint8_t *key, const uint8_t *iv, + int enc); + + int (*cipher)(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, + size_t inl); + + /* cleanup, if non-NULL, releases memory associated with the context. It is + * called if |EVP_CTRL_INIT| succeeds. Note that |init| may not have been + * called at this point. */ + void (*cleanup)(EVP_CIPHER_CTX *); + + int (*ctrl)(EVP_CIPHER_CTX *, int type, int arg, void *ptr); +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define CIPHER_R_AES_KEY_SETUP_FAILED 100 +#define CIPHER_R_BAD_DECRYPT 101 +#define CIPHER_R_BAD_KEY_LENGTH 102 +#define CIPHER_R_BUFFER_TOO_SMALL 103 +#define CIPHER_R_CTRL_NOT_IMPLEMENTED 104 +#define CIPHER_R_CTRL_OPERATION_NOT_IMPLEMENTED 105 +#define CIPHER_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH 106 +#define CIPHER_R_INITIALIZATION_ERROR 107 +#define CIPHER_R_INPUT_NOT_INITIALIZED 108 +#define CIPHER_R_INVALID_AD_SIZE 109 +#define CIPHER_R_INVALID_KEY_LENGTH 110 +#define CIPHER_R_INVALID_NONCE_SIZE 111 +#define CIPHER_R_INVALID_OPERATION 112 +#define CIPHER_R_IV_TOO_LARGE 113 +#define CIPHER_R_NO_CIPHER_SET 114 +#define CIPHER_R_OUTPUT_ALIASES_INPUT 115 +#define CIPHER_R_TAG_TOO_LARGE 116 +#define CIPHER_R_TOO_LARGE 117 +#define CIPHER_R_UNSUPPORTED_AD_SIZE 118 +#define CIPHER_R_UNSUPPORTED_INPUT_SIZE 119 +#define CIPHER_R_UNSUPPORTED_KEY_SIZE 120 +#define CIPHER_R_UNSUPPORTED_NONCE_SIZE 121 +#define CIPHER_R_UNSUPPORTED_TAG_SIZE 122 +#define CIPHER_R_WRONG_FINAL_BLOCK_LENGTH 123 +#define CIPHER_R_NO_DIRECTION_SET 124 + +#endif /* OPENSSL_HEADER_CIPHER_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/cmac.h b/TMessagesProj/jni/boringssl/include/openssl/cmac.h new file mode 100644 index 00000000..183f41bc --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/cmac.h @@ -0,0 +1,76 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_CMAC_H +#define OPENSSL_HEADER_CMAC_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* CMAC. + * + * CMAC is a MAC based on AES-CBC and defined in + * https://tools.ietf.org/html/rfc4493#section-2.3. */ + + +/* One-shot functions. */ + +/* AES_CMAC calculates the 16-byte, CMAC authenticator of |in_len| bytes of + * |in| and writes it to |out|. The |key_len| may be 16 or 32 bytes to select + * between AES-128 and AES-256. It returns one on success or zero on error. */ +OPENSSL_EXPORT int AES_CMAC(uint8_t out[16], const uint8_t *key, size_t key_len, + const uint8_t *in, size_t in_len); + + +/* Incremental interface. */ + +/* CMAC_CTX_new allocates a fresh |CMAC_CTX| and returns it, or NULL on + * error. */ +OPENSSL_EXPORT CMAC_CTX *CMAC_CTX_new(void); + +/* CMAC_CTX_free frees a |CMAC_CTX|. */ +OPENSSL_EXPORT void CMAC_CTX_free(CMAC_CTX *ctx); + +/* CMAC_Init configures |ctx| to use the given |key| and |cipher|. The CMAC RFC + * only specifies the use of AES-128 thus |key_len| should be 16 and |cipher| + * should be |EVP_aes_128_cbc()|. However, this implementation also supports + * AES-256 by setting |key_len| to 32 and |cipher| to |EVP_aes_256_cbc()|. The + * |engine| argument is ignored. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t key_len, + const EVP_CIPHER *cipher, ENGINE *engine); + + +/* CMAC_Reset resets |ctx| so that a fresh message can be authenticated. */ +OPENSSL_EXPORT int CMAC_Reset(CMAC_CTX *ctx); + +/* CMAC_Update processes |in_len| bytes of message from |in|. It returns one on + * success or zero on error. */ +OPENSSL_EXPORT int CMAC_Update(CMAC_CTX *ctx, const uint8_t *in, size_t in_len); + +/* CMAC_Final sets |*out_len| to 16 and, if |out| is not NULL, writes 16 bytes + * of authenticator to it. It returns one on success or zero on error. */ +OPENSSL_EXPORT int CMAC_Final(CMAC_CTX *ctx, uint8_t *out, size_t *out_len); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CBC_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/conf.h b/TMessagesProj/jni/boringssl/include/openssl/conf.h new file mode 100644 index 00000000..a2741a8a --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/conf.h @@ -0,0 +1,145 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_CONF_H +#define OPENSSL_HEADER_CONF_H + +#include + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Config files look like: + * + * # Comment + * + * # This key is in the default section. + * key=value + * + * [section_name] + * key2=value2 + * + * Config files are representated by a |CONF|. */ + +struct conf_value_st { + char *section; + char *name; + char *value; +}; + +struct conf_st { + LHASH_OF(CONF_VALUE) *data; +}; + + +/* NCONF_new returns a fresh, empty |CONF|, or NULL on error. The |method| + * argument must be NULL. */ +CONF *NCONF_new(void *method); + +/* NCONF_free frees all the data owned by |conf| and then |conf| itself. */ +void NCONF_free(CONF *conf); + +/* NCONF_load parses the file named |filename| and adds the values found to + * |conf|. It returns one on success and zero on error. In the event of an + * error, if |out_error_line| is not NULL, |*out_error_line| is set to the + * number of the line that contained the error. */ +int NCONF_load(CONF *conf, const char *filename, long *out_error_line); + +/* NCONF_load_bio acts like |NCONF_load| but reads from |bio| rather than from + * a named file. */ +int NCONF_load_bio(CONF *conf, BIO *bio, long *out_error_line); + +/* NCONF_get_section returns a stack of values for a given section in |conf|. + * If |section| is NULL, the default section is returned. It returns NULL on + * error. */ +STACK_OF(CONF_VALUE) *NCONF_get_section(const CONF *conf, const char *section); + +/* NCONF_get_string returns the value of the key |name|, in section |section|. + * The |section| argument may be NULL to indicate the default section. It + * returns the value or NULL on error. */ +const char *NCONF_get_string(const CONF *conf, const char *section, + const char *name); + + +/* Utility functions */ + +/* CONF_parse_list takes a list separated by 'sep' and calls |list_cb| giving + * the start and length of each member, optionally stripping leading and + * trailing whitespace. This can be used to parse comma separated lists for + * example. If |list_cb| returns <= 0, then the iteration is halted and that + * value is returned immediately. Otherwise it returns one. Note that |list_cb| + * may be called on an empty member. */ +int CONF_parse_list(const char *list, char sep, int remove_whitespace, + int (*list_cb)(const char *elem, int len, void *usr), + void *arg); + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define CONF_R_LIST_CANNOT_BE_NULL 100 +#define CONF_R_MISSING_CLOSE_SQUARE_BRACKET 101 +#define CONF_R_MISSING_EQUAL_SIGN 102 +#define CONF_R_NO_CLOSE_BRACE 103 +#define CONF_R_UNABLE_TO_CREATE_NEW_SECTION 104 +#define CONF_R_VARIABLE_HAS_NO_VALUE 105 + +#endif /* OPENSSL_HEADER_THREAD_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/cpu.h b/TMessagesProj/jni/boringssl/include/openssl/cpu.h new file mode 100644 index 00000000..981d246b --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/cpu.h @@ -0,0 +1,126 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_CPU_H +#define OPENSSL_HEADER_CPU_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Runtime CPU feature support */ + + +#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) +/* OPENSSL_ia32cap_P contains the Intel CPUID bits when running on an x86 or + * x86-64 system. + * + * Index 0: + * EDX for CPUID where EAX = 1 + * Bit 20 is always zero + * Bit 28 is adjusted to reflect whether the data cache is shared between + * multiple logical cores + * Bit 30 is used to indicate an Intel CPU + * Index 1: + * ECX for CPUID where EAX = 1 + * Bit 11 is used to indicate AMD XOP support, not SDBG + * Index 2: + * EBX for CPUID where EAX = 7 + * Index 3 is set to zero. + * + * Note: the CPUID bits are pre-adjusted for the OSXSAVE bit and the YMM and XMM + * bits in XCR0, so it is not necessary to check those. */ +extern uint32_t OPENSSL_ia32cap_P[4]; +#endif + +#if defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) +/* CRYPTO_is_NEON_capable returns true if the current CPU has a NEON unit. Note + * that |OPENSSL_armcap_P| also exists and contains the same information in a + * form that's easier for assembly to use. */ +OPENSSL_EXPORT char CRYPTO_is_NEON_capable(void); + +/* CRYPTO_set_NEON_capable sets the return value of |CRYPTO_is_NEON_capable|. + * By default, unless the code was compiled with |-mfpu=neon|, NEON is assumed + * not to be present. It is not autodetected. Calling this with a zero + * argument also causes |CRYPTO_is_NEON_functional| to return false. */ +OPENSSL_EXPORT void CRYPTO_set_NEON_capable(char neon_capable); + +/* CRYPTO_is_NEON_functional returns true if the current CPU has a /working/ + * NEON unit. Some phones have a NEON unit, but the Poly1305 NEON code causes + * it to fail. See https://code.google.com/p/chromium/issues/detail?id=341598 */ +OPENSSL_EXPORT char CRYPTO_is_NEON_functional(void); + +/* CRYPTO_set_NEON_functional sets the "NEON functional" flag. For + * |CRYPTO_is_NEON_functional| to return true, both this flag and the NEON flag + * must be true. By default NEON is assumed to be functional if the code was + * compiled with |-mfpu=neon| or if |CRYPTO_set_NEON_capable| has been called + * with a non-zero argument. */ +OPENSSL_EXPORT void CRYPTO_set_NEON_functional(char neon_functional); +#endif /* OPENSSL_ARM */ + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CPU_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/crypto.h b/TMessagesProj/jni/boringssl/include/openssl/crypto.h new file mode 100644 index 00000000..5207a126 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/crypto.h @@ -0,0 +1,62 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_CRYPTO_H +#define OPENSSL_HEADER_CRYPTO_H + +#include + +/* Upstream OpenSSL defines |OPENSSL_malloc|, etc., in crypto.h rather than + * mem.h. */ +#include + +/* Upstream OpenSSL defines |CRYPTO_LOCK|, etc., in crypto.h rather than + * thread.h. */ +#include + + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* crypto.h contains functions for initializing the crypto library. */ + + +/* CRYPTO_library_init initializes the crypto library. It must be called if the + * library is built with BORINGSSL_NO_STATIC_INITIALIZER. Otherwise, it does + * nothing and a static initializer is used instead. */ +OPENSSL_EXPORT void CRYPTO_library_init(void); + + +/* Deprecated functions. */ + +#define OPENSSL_VERSION_TEXT "BoringSSL" + +#define SSLEAY_VERSION 0 + +/* SSLeay_version is a compatibility function that returns the string + * "BoringSSL". */ +OPENSSL_EXPORT const char *SSLeay_version(int unused); + +/* SSLeay is a compatibility function that returns OPENSSL_VERSION_NUMBER from + * base.h. */ +OPENSSL_EXPORT unsigned long SSLeay(void); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_CRYPTO_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/des.h b/TMessagesProj/jni/boringssl/include/openssl/des.h new file mode 100644 index 00000000..f9db62d6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/des.h @@ -0,0 +1,164 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DES_H +#define OPENSSL_HEADER_DES_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* DES. */ + + +typedef struct DES_cblock_st { + uint8_t bytes[8]; +} DES_cblock; + +typedef struct DES_ks { + uint32_t subkeys[16][2]; +} DES_key_schedule; + + +#define DES_KEY_SZ (sizeof(DES_cblock)) +#define DES_SCHEDULE_SZ (sizeof(DES_key_schedule)) + +#define DES_ENCRYPT 1 +#define DES_DECRYPT 0 + +#define DES_CBC_MODE 0 +#define DES_PCBC_MODE 1 + +/* DES_set_key performs a key schedule and initialises |schedule| with |key|. */ +OPENSSL_EXPORT void DES_set_key(const DES_cblock *key, + DES_key_schedule *schedule); + +/* DES_set_odd_parity sets the parity bits (the least-significant bits in each + * byte) of |key| given the other bits in each byte. */ +OPENSSL_EXPORT void DES_set_odd_parity(DES_cblock *key); + +/* DES_ecb_encrypt encrypts (or decrypts, if |is_encrypt| is |DES_DECRYPT|) a + * single DES block (8 bytes) from in to out, using the key configured in + * |schedule|. */ +OPENSSL_EXPORT void DES_ecb_encrypt(const DES_cblock *in, DES_cblock *out, + const DES_key_schedule *schedule, + int is_encrypt); + +/* DES_ncbc_encrypt encrypts (or decrypts, if |enc| is |DES_DECRYPT|) |len| + * bytes from |in| to |out| with DES in CBC mode. */ +OPENSSL_EXPORT void DES_ncbc_encrypt(const uint8_t *in, uint8_t *out, + size_t len, + const DES_key_schedule *schedule, + DES_cblock *ivec, int enc); + +/* DES_ecb3_encrypt encrypts (or decrypts, if |enc| is |DES_DECRYPT|) a single + * block (8 bytes) of data from |input| to |output| using 3DES. */ +OPENSSL_EXPORT void DES_ecb3_encrypt(const DES_cblock *input, + DES_cblock *output, + const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + const DES_key_schedule *ks3, + int enc); + +/* DES_ede3_cbc_encrypt encrypts (or decrypts, if |enc| is |DES_DECRYPT|) |len| + * bytes from |in| to |out| with 3DES in CBC mode. 3DES uses three keys, thus + * the function takes three different |DES_key_schedule|s. */ +OPENSSL_EXPORT void DES_ede3_cbc_encrypt(const uint8_t *in, uint8_t *out, + size_t len, + const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + const DES_key_schedule *ks3, + DES_cblock *ivec, int enc); + +/* DES_ede2_cbc_encrypt encrypts (or decrypts, if |enc| is |DES_DECRYPT|) |len| + * bytes from |in| to |out| with 3DES in CBC mode. With this keying option, the + * first and third 3DES keys are identical. Thus, this function takes only two + * different |DES_key_schedule|s. */ +OPENSSL_EXPORT void DES_ede2_cbc_encrypt(const uint8_t *in, uint8_t *out, + size_t len, + const DES_key_schedule *ks1, + const DES_key_schedule *ks2, + DES_cblock *ivec, int enc); + + +/* Deprecated functions. */ + +/* DES_set_key_unchecked calls |DES_set_key|. */ +OPENSSL_EXPORT void DES_set_key_unchecked(const DES_cblock *key, + DES_key_schedule *schedule); + +OPENSSL_EXPORT void DES_ede3_cfb64_encrypt(const uint8_t *in, uint8_t *out, + long length, DES_key_schedule *ks1, + DES_key_schedule *ks2, + DES_key_schedule *ks3, + DES_cblock *ivec, int *num, int enc); + +OPENSSL_EXPORT void DES_ede3_cfb_encrypt(const uint8_t *in, uint8_t *out, + int numbits, long length, + DES_key_schedule *ks1, + DES_key_schedule *ks2, + DES_key_schedule *ks3, + DES_cblock *ivec, int enc); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_DES_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/dh.h b/TMessagesProj/jni/boringssl/include/openssl/dh.h new file mode 100644 index 00000000..0174f07c --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/dh.h @@ -0,0 +1,270 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DH_H +#define OPENSSL_HEADER_DH_H + +#include + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* DH contains functions for performing Diffie-Hellman key agreement in + * multiplicative groups. */ + + +/* Allocation and destruction. */ + +/* DH_new returns a new, empty DH object or NULL on error. */ +OPENSSL_EXPORT DH *DH_new(void); + +/* DH_new_method acts the same as |DH_new| but takes an explicit |ENGINE|. */ +OPENSSL_EXPORT DH *DH_new_method(const ENGINE *engine); + +/* DH_free decrements the reference count of |dh| and frees it if the reference + * count drops to zero. */ +OPENSSL_EXPORT void DH_free(DH *dh); + +/* DH_up_ref increments the reference count of |dh|. */ +OPENSSL_EXPORT int DH_up_ref(DH *dh); + + +/* Standard parameters. + * + * These functions return new DH objects with standard parameters configured + * that use the given ENGINE, which may be NULL. They return NULL on allocation + * failure. */ + +/* These parameters are taken from RFC 5114. */ + +OPENSSL_EXPORT DH *DH_get_1024_160(const ENGINE *engine); +OPENSSL_EXPORT DH *DH_get_2048_224(const ENGINE *engine); +OPENSSL_EXPORT DH *DH_get_2048_256(const ENGINE *engine); + + +/* Parameter generation. */ + +#define DH_GENERATOR_2 2 +#define DH_GENERATOR_5 5 + +/* DH_generate_parameters_ex generates a suitable Diffie-Hellman group with a + * prime that is |prime_bits| long and stores it in |dh|. The generator of the + * group will be |generator|, which should be |DH_GENERATOR_2| unless there's a + * good reason to use a different value. The |cb| argument contains a callback + * function that will be called during the generation. See the documentation in + * |bn.h| about this. In addition to the callback invocations from |BN|, |cb| + * will also be called with |event| equal to three when the generation is + * complete. */ +OPENSSL_EXPORT int DH_generate_parameters_ex(DH *dh, int prime_bits, + int generator, BN_GENCB *cb); + + +/* Diffie-Hellman operations. */ + +/* DH_generate_key generates a new, random, private key and stores it in + * |dh|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int DH_generate_key(DH *dh); + +/* DH_compute_key calculates the shared key between |dh| and |peers_key| and + * writes it as a big-endian integer into |out|, which must have |DH_size| + * bytes of space. It returns the number of bytes written, or a negative number + * on error. */ +OPENSSL_EXPORT int DH_compute_key(uint8_t *out, const BIGNUM *peers_key, + DH *dh); + + +/* Utility functions. */ + +/* DH_size returns the number of bytes in the DH group's prime. */ +OPENSSL_EXPORT int DH_size(const DH *dh); + +/* DH_num_bits returns the minimum number of bits needed to represent the + * absolute value of the DH group's prime. */ +OPENSSL_EXPORT unsigned DH_num_bits(const DH *dh); + +#define DH_CHECK_P_NOT_PRIME 0x01 +#define DH_CHECK_P_NOT_SAFE_PRIME 0x02 +#define DH_CHECK_UNABLE_TO_CHECK_GENERATOR 0x04 +#define DH_CHECK_NOT_SUITABLE_GENERATOR 0x08 +#define DH_CHECK_Q_NOT_PRIME 0x10 +#define DH_CHECK_INVALID_Q_VALUE 0x20 +#define DH_CHECK_INVALID_J_VALUE 0x40 + +/* These are compatibility defines. */ +#define DH_NOT_SUITABLE_GENERATOR DH_CHECK_NOT_SUITABLE_GENERATOR +#define DH_UNABLE_TO_CHECK_GENERATOR DH_CHECK_UNABLE_TO_CHECK_GENERATOR + +/* DH_check checks the suitability of |dh| as a Diffie-Hellman group. and sets + * |DH_CHECK_*| flags in |*out_flags| if it finds any errors. It returns one if + * |*out_flags| was successfully set and zero on error. + * + * Note: these checks may be quite computationally expensive. */ +OPENSSL_EXPORT int DH_check(const DH *dh, int *out_flags); + +#define DH_CHECK_PUBKEY_TOO_SMALL 1 +#define DH_CHECK_PUBKEY_TOO_LARGE 2 + +/* DH_check_pub_key checks the suitability of |pub_key| as a public key for the + * DH group in |dh| and sets |DH_CHECK_PUBKEY_*| flags in |*out_flags| if it + * finds any errors. It returns one if |*out_flags| was successfully set and + * zero on error. */ +OPENSSL_EXPORT int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, + int *out_flags); + +/* DHparams_dup allocates a fresh |DH| and copies the parameters from |dh| into + * it. It returns the new |DH| or NULL on error. */ +OPENSSL_EXPORT DH *DHparams_dup(const DH *dh); + + +/* ASN.1 functions. */ + +/* d2i_DHparams parses an ASN.1, DER encoded Diffie-Hellman parameters + * structure from |len| bytes at |*inp|. If |ret| is not NULL then, on exit, a + * pointer to the result is in |*ret|. If |*ret| is already non-NULL on entry + * then the result is written directly into |*ret|, otherwise a fresh |DH| is + * allocated. On successful exit, |*inp| is advanced past the DER structure. It + * returns the result or NULL on error. */ +OPENSSL_EXPORT DH *d2i_DHparams(DH **ret, const unsigned char **inp, long len); + +/* i2d_DHparams marshals |in| to an ASN.1, DER structure. If |outp| is not NULL + * then the result is written to |*outp| and |*outp| is advanced just past the + * output. It returns the number of bytes in the result, whether written or + * not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_DHparams(const DH *in, unsigned char **outp); + + +/* ex_data functions. + * + * See |ex_data.h| for details. */ + +OPENSSL_EXPORT int DH_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int DH_set_ex_data(DH *d, int idx, void *arg); +OPENSSL_EXPORT void *DH_get_ex_data(DH *d, int idx); + + +/* dh_method contains function pointers to override the implementation of DH. + * See |engine.h| for details. */ +struct dh_method { + struct openssl_method_common_st common; + + /* app_data is an opaque pointer for the method to use. */ + void *app_data; + + /* init is called just before the return of |DH_new_method|. It returns one + * on success or zero on error. */ + int (*init)(DH *dh); + + /* finish is called before |dh| is destructed. */ + void (*finish)(DH *dh); + + /* generate_parameters is called by |DH_generate_parameters_ex|. */ + int (*generate_parameters)(DH *dh, int prime_bits, int generator, + BN_GENCB *cb); + + /* generate_parameters is called by |DH_generate_key|. */ + int (*generate_key)(DH *dh); + + /* compute_key is called by |DH_compute_key|. */ + int (*compute_key)(DH *dh, uint8_t *out, const BIGNUM *pub_key); +}; + +struct dh_st { + DH_METHOD *meth; + + BIGNUM *p; + BIGNUM *g; + BIGNUM *pub_key; /* g^x */ + BIGNUM *priv_key; /* x */ + + /* priv_length contains the length, in bits, of the private value. If zero, + * the private value will be the same length as |p|. */ + unsigned priv_length; + + CRYPTO_MUTEX method_mont_p_lock; + BN_MONT_CTX *method_mont_p; + + /* Place holders if we want to do X9.42 DH */ + BIGNUM *q; + BIGNUM *j; + unsigned char *seed; + int seedlen; + BIGNUM *counter; + + int flags; + CRYPTO_refcount_t references; + CRYPTO_EX_DATA ex_data; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define DH_R_BAD_GENERATOR 100 +#define DH_R_INVALID_PUBKEY 101 +#define DH_R_MODULUS_TOO_LARGE 102 +#define DH_R_NO_PRIVATE_VALUE 103 + +#endif /* OPENSSL_HEADER_DH_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/digest.h b/TMessagesProj/jni/boringssl/include/openssl/digest.h new file mode 100644 index 00000000..66be4d04 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/digest.h @@ -0,0 +1,257 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_DIGEST_H +#define OPENSSL_HEADER_DIGEST_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Digest functions. + * + * An EVP_MD abstracts the details of a specific hash function allowing code to + * deal with the concept of a "hash function" without needing to know exactly + * which hash function it is. */ + + +/* Hash algorithms. + * + * The following functions return |EVP_MD| objects that implement the named hash + * function. */ + +OPENSSL_EXPORT const EVP_MD *EVP_md4(void); +OPENSSL_EXPORT const EVP_MD *EVP_md5(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha1(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha224(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha256(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha384(void); +OPENSSL_EXPORT const EVP_MD *EVP_sha512(void); + +/* EVP_md5_sha1 is a TLS-specific |EVP_MD| which computes the concatenation of + * MD5 and SHA-1, as used in TLS 1.1 and below. */ +OPENSSL_EXPORT const EVP_MD *EVP_md5_sha1(void); + +/* EVP_get_digestbynid returns an |EVP_MD| for the given NID, or NULL if no + * such digest is known. */ +OPENSSL_EXPORT const EVP_MD *EVP_get_digestbynid(int nid); + +/* EVP_get_digestbyobj returns an |EVP_MD| for the given |ASN1_OBJECT|, or NULL + * if no such digest is known. */ +OPENSSL_EXPORT const EVP_MD *EVP_get_digestbyobj(const ASN1_OBJECT *obj); + + +/* Digest contexts. + * + * An EVP_MD_CTX represents the state of a specific digest operation in + * progress. */ + +/* EVP_MD_CTX_init initialises an, already allocated, |EVP_MD_CTX|. */ +OPENSSL_EXPORT void EVP_MD_CTX_init(EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_create allocates and initialises a fresh |EVP_MD_CTX| and returns + * it, or NULL on allocation failure. */ +OPENSSL_EXPORT EVP_MD_CTX *EVP_MD_CTX_create(void); + +/* EVP_MD_CTX_cleanup frees any resources owned by |ctx| and resets it to a + * freshly initialised state. It does not free |ctx| itself. It returns one. */ +OPENSSL_EXPORT int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_destroy calls |EVP_MD_CTX_cleanup| and then frees |ctx| itself. */ +OPENSSL_EXPORT void EVP_MD_CTX_destroy(EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_copy_ex sets |out|, which must already be initialised, to be a + * copy of |in|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in); + + +/* Digest operations. */ + +/* EVP_DigestInit_ex configures |ctx|, which must already have been + * initialised, for a fresh hashing operation using |type|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, + ENGINE *engine); + +/* EVP_DigestInit acts like |EVP_DigestInit_ex| except that |ctx| is + * initialised before use. */ +OPENSSL_EXPORT int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type); + +/* EVP_DigestUpdate hashes |len| bytes from |data| into the hashing operation + * in |ctx|. It returns one. */ +OPENSSL_EXPORT int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_MAX_MD_SIZE is the largest digest size supported. Functions that output + * a digest generally require the buffer have at least this much space. */ +#define EVP_MAX_MD_SIZE 64 /* SHA-512 is the longest so far. */ + +/* EVP_DigestFinal_ex finishes the digest in |ctx| and writes the output to + * |md_out|. At most |EVP_MAX_MD_SIZE| bytes are written. If |out_size| is not + * NULL then |*out_size| is set to the number of bytes written. It returns one. + * After this call, the hash cannot be updated or finished again until + * |EVP_DigestInit_ex| is called to start another hashing operation. */ +OPENSSL_EXPORT int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, uint8_t *md_out, + unsigned int *out_size); + +/* EVP_DigestFinal acts like |EVP_DigestFinal_ex| except that + * |EVP_MD_CTX_cleanup| is called on |ctx| before returning. */ +OPENSSL_EXPORT int EVP_DigestFinal(EVP_MD_CTX *ctx, uint8_t *md_out, + unsigned int *out_size); + +/* EVP_Digest performs a complete hashing operation in one call. It hashes + * |len| bytes from |data| and writes the digest to |md_out|. At most + * |EVP_MAX_MD_SIZE| bytes are written. If |out_size| is not NULL then + * |*out_size| is set to the number of bytes written. It returns one on success + * and zero otherwise. */ +OPENSSL_EXPORT int EVP_Digest(const void *data, size_t len, uint8_t *md_out, + unsigned int *md_out_size, const EVP_MD *type, + ENGINE *impl); + + +/* Digest function accessors. + * + * These functions allow code to learn details about an abstract hash + * function. */ + +/* EVP_MD_type returns a NID identifing |md|. (For example, |NID_sha256|.) */ +OPENSSL_EXPORT int EVP_MD_type(const EVP_MD *md); + +/* EVP_MD_flags returns the flags for |md|, which is a set of |EVP_MD_FLAG_*| + * values, ORed together. */ +OPENSSL_EXPORT uint32_t EVP_MD_flags(const EVP_MD *md); + +/* EVP_MD_size returns the digest size of |md|, in bytes. */ +OPENSSL_EXPORT size_t EVP_MD_size(const EVP_MD *md); + +/* EVP_MD_block_size returns the native block-size of |md|. */ +OPENSSL_EXPORT size_t EVP_MD_block_size(const EVP_MD *md); + +/* EVP_MD_FLAG_PKEY_DIGEST indicates the the digest function is used with a + * specific public key in order to verify signatures. (For example, + * EVP_dss1.) */ +#define EVP_MD_FLAG_PKEY_DIGEST 1 + +/* EVP_MD_FLAG_DIGALGID_ABSENT indicates that the parameter type in an X.509 + * DigestAlgorithmIdentifier representing this digest function should be + * undefined rather than NULL. */ +#define EVP_MD_FLAG_DIGALGID_ABSENT 2 + + +/* Deprecated functions. */ + +/* EVP_MD_CTX_copy sets |out|, which must /not/ be initialised, to be a copy of + * |in|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in); + +/* EVP_add_digest does nothing and returns one. It exists only for + * compatibility with OpenSSL. */ +OPENSSL_EXPORT int EVP_add_digest(const EVP_MD *digest); + +/* EVP_get_cipherbyname returns an |EVP_MD| given a human readable name in + * |name|, or NULL if the name is unknown. */ +OPENSSL_EXPORT const EVP_MD *EVP_get_digestbyname(const char *); + + +/* Digest operation accessors. */ + +/* EVP_MD_CTX_md returns the underlying digest function, or NULL if one has not + * been set. */ +OPENSSL_EXPORT const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_size returns the digest size of |ctx|. It will crash if a digest + * hasn't been set on |ctx|. */ +OPENSSL_EXPORT unsigned EVP_MD_CTX_size(const EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_block_size returns the block size of the digest function used by + * |ctx|. It will crash if a digest hasn't been set on |ctx|. */ +OPENSSL_EXPORT unsigned EVP_MD_CTX_block_size(const EVP_MD_CTX *ctx); + +/* EVP_MD_CTX_type returns a NID describing the digest function used by |ctx|. + * (For example, |NID_sha256|.) It will crash if a digest hasn't been set on + * |ctx|. */ +OPENSSL_EXPORT int EVP_MD_CTX_type(const EVP_MD_CTX *ctx); + + +struct evp_md_pctx_ops; + +struct env_md_ctx_st { + /* digest is the underlying digest function, or NULL if not set. */ + const EVP_MD *digest; + /* md_data points to a block of memory that contains the hash-specific + * context. */ + void *md_data; + + /* pctx is an opaque (at this layer) pointer to additional context that + * EVP_PKEY functions may store in this object. */ + EVP_PKEY_CTX *pctx; + + /* pctx_ops, if not NULL, points to a vtable that contains functions to + * manipulate |pctx|. */ + const struct evp_md_pctx_ops *pctx_ops; +} /* EVP_MD_CTX */; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define DIGEST_R_INPUT_NOT_INITIALIZED 100 + +#endif /* OPENSSL_HEADER_DIGEST_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/dsa.h b/TMessagesProj/jni/boringssl/include/openssl/dsa.h new file mode 100644 index 00000000..b1e73091 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/dsa.h @@ -0,0 +1,374 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + * + * The DSS routines are based on patches supplied by + * Steven Schoch . */ + +#ifndef OPENSSL_HEADER_DSA_H +#define OPENSSL_HEADER_DSA_H + +#include + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* DSA contains functions for signing and verifing with the Digital Signature + * Algorithm. */ + + +/* Allocation and destruction. */ + +/* DSA_new returns a new, empty DSA object or NULL on error. */ +OPENSSL_EXPORT DSA *DSA_new(void); + +/* DSA_new_method acts the same as |DH_new| but takes an explicit |ENGINE|. */ +OPENSSL_EXPORT DSA *DSA_new_method(const ENGINE *engine); + +/* DSA_free decrements the reference count of |dsa| and frees it if the + * reference count drops to zero. */ +OPENSSL_EXPORT void DSA_free(DSA *dsa); + +/* DSA_up_ref increments the reference count of |dsa|. */ +OPENSSL_EXPORT int DSA_up_ref(DSA *dsa); + + +/* Parameter generation. */ + +/* DSA_generate_parameters_ex generates a set of DSA parameters by following + * the procedure given in FIPS 186-4, appendix A. + * (http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf) + * + * The larger prime will have a length of |bits| (e.g. 2048). The |seed| value + * allows others to generate and verify the same parameters and should be + * random input which is kept for reference. If |out_counter| or |out_h| are + * not NULL then the counter and h value used in the generation are written to + * them. + * + * The |cb| argument is passed to |BN_generate_prime_ex| and is thus called + * during the generation process in order to indicate progress. See the + * comments for that function for details. In addition to the calls made by + * |BN_generate_prime_ex|, |DSA_generate_parameters_ex| will call it with + * |event| equal to 2 and 3 at different stages of the process. + * + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int DSA_generate_parameters_ex(DSA *dsa, unsigned bits, + const uint8_t *seed, + size_t seed_len, int *out_counter, + unsigned long *out_h, + BN_GENCB *cb); + +/* DSAparams_dup returns a freshly allocated |DSA| that contains a copy of the + * parameters from |dsa|. It returns NULL on error. */ +OPENSSL_EXPORT DSA *DSAparams_dup(const DSA *dsa); + + +/* Key generation. */ + +/* DSA_generate_key generates a public/private key pair in |dsa|, which must + * already have parameters setup. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int DSA_generate_key(DSA *dsa); + + +/* Signatures. */ + +/* DSA_SIG contains a DSA signature as a pair of integers. */ +typedef struct DSA_SIG_st { + BIGNUM *r, *s; +} DSA_SIG; + +/* DSA_SIG_new returns a freshly allocated, DIG_SIG structure or NULL on error. + * Both |r| and |s| in the signature will be NULL. */ +OPENSSL_EXPORT DSA_SIG *DSA_SIG_new(void); + +/* DSA_SIG_free frees the contents of |sig| and then frees |sig| itself. */ +OPENSSL_EXPORT void DSA_SIG_free(DSA_SIG *sig); + +/* DSA_do_sign returns a signature of the hash in |digest| by the key in |dsa| + * and returns an allocated, DSA_SIG structure, or NULL on error. */ +OPENSSL_EXPORT DSA_SIG *DSA_do_sign(const uint8_t *digest, size_t digest_len, + DSA *dsa); + +/* DSA_do_verify verifies that |sig| is a valid signature, by the public key in + * |dsa|, of the hash in |digest|. It returns one if so, zero if invalid and -1 + * on error. + * + * WARNING: do not use. This function returns -1 for error, 0 for invalid and 1 + * for valid. However, this is dangerously different to the usual OpenSSL + * convention and could be a disaster if a user did |if (DSA_do_verify(...))|. + * Because of this, |DSA_check_signature| is a safer version of this. + * + * TODO(fork): deprecate. */ +OPENSSL_EXPORT int DSA_do_verify(const uint8_t *digest, size_t digest_len, + DSA_SIG *sig, const DSA *dsa); + +/* DSA_do_check_signature sets |*out_valid| to zero. Then it verifies that |sig| + * is a valid signature, by the public key in |dsa| of the hash in |digest| + * and, if so, it sets |*out_valid| to one. + * + * It returns one if it was able to verify the signature as valid or invalid, + * and zero on error. */ +OPENSSL_EXPORT int DSA_do_check_signature(int *out_valid, const uint8_t *digest, + size_t digest_len, DSA_SIG *sig, + const DSA *dsa); + + +/* ASN.1 signatures. + * + * These functions also perform DSA signature operations, but deal with ASN.1 + * encoded signatures as opposed to raw |BIGNUM|s. If you don't know what + * encoding a DSA signature is in, it's probably ASN.1. */ + +/* DSA_sign signs |digest| with the key in |dsa| and writes the resulting + * signature, in ASN.1 form, to |out_sig| and the length of the signature to + * |*out_siglen|. There must be, at least, |DSA_size(dsa)| bytes of space in + * |out_sig|. It returns one on success and zero otherwise. + * + * (The |type| argument is ignored.) */ +OPENSSL_EXPORT int DSA_sign(int type, const uint8_t *digest, size_t digest_len, + uint8_t *out_sig, unsigned int *out_siglen, + DSA *dsa); + +/* DSA_verify verifies that |sig| is a valid, ASN.1 signature, by the public + * key in |dsa|, of the hash in |digest|. It returns one if so, zero if invalid + * and -1 on error. + * + * (The |type| argument is ignored.) + * + * WARNING: do not use. This function returns -1 for error, 0 for invalid and 1 + * for valid. However, this is dangerously different to the usual OpenSSL + * convention and could be a disaster if a user did |if (DSA_do_verify(...))|. + * Because of this, |DSA_check_signature| is a safer version of this. + * + * TODO(fork): deprecate. */ +OPENSSL_EXPORT int DSA_verify(int type, const uint8_t *digest, + size_t digest_len, const uint8_t *sig, + size_t sig_len, const DSA *dsa); + +/* DSA_check_signature sets |*out_valid| to zero. Then it verifies that |sig| + * is a valid, ASN.1 signature, by the public key in |dsa|, of the hash in + * |digest|. If so, it sets |*out_valid| to one. + * + * It returns one if it was able to verify the signature as valid or invalid, + * and zero on error. */ +OPENSSL_EXPORT int DSA_check_signature(int *out_valid, const uint8_t *digest, + size_t digest_len, const uint8_t *sig, + size_t sig_len, const DSA *dsa); + +/* DSA_size returns the size, in bytes, of an ASN.1 encoded, DSA signature + * generated by |dsa|. Parameters must already have been setup in |dsa|. */ +OPENSSL_EXPORT int DSA_size(const DSA *dsa); + + +/* ASN.1 encoding. */ + +/* d2i_DSA_SIG parses an ASN.1, DER-encoded, DSA signature from |len| bytes at + * |*inp|. If |out_sig| is not NULL then, on exit, a pointer to the result is + * in |*out_sig|. If |*out_sig| is already non-NULL on entry then the result is + * written directly into |*out_sig|, otherwise a fresh |DSA_SIG| is allocated. + * On successful exit, |*inp| is advanced past the DER structure. It returns + * the result or NULL on error. */ +OPENSSL_EXPORT DSA_SIG *d2i_DSA_SIG(DSA_SIG **out_sig, const uint8_t **inp, + long len); + +/* i2d_DSA_SIG marshals |in| to an ASN.1, DER structure. If |outp| is not NULL + * then the result is written to |*outp| and |*outp| is advanced just past the + * output. It returns the number of bytes in the result, whether written or not, + * or a negative value on error. */ +OPENSSL_EXPORT int i2d_DSA_SIG(const DSA_SIG *in, uint8_t **outp); + +/* d2i_DSAPublicKey parses an ASN.1, DER-encoded, DSA public key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. If |*out| is already non-NULL on entry then the result is + * written directly into |*out|, otherwise a fresh |DSA| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT DSA *d2i_DSAPublicKey(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAPublicKey marshals a public key from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_DSAPublicKey(const DSA *in, unsigned char **outp); + +/* d2i_DSAPrivateKey parses an ASN.1, DER-encoded, DSA private key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. If |*out| is already non-NULL on entry then the result is + * written directly into |*out|, otherwise a fresh |DSA| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT DSA *d2i_DSAPrivateKey(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAPrivateKey marshals a private key from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_DSAPrivateKey(const DSA *in, unsigned char **outp); + +/* d2i_DSAparams parses ASN.1, DER-encoded, DSA parameters from |len| bytes at + * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in + * |*out|. If |*out| is already non-NULL on entry then the result is written + * directly into |*out|, otherwise a fresh |DSA| is allocated. On successful + * exit, |*inp| is advanced past the DER structure. It returns the result or + * NULL on error. */ +OPENSSL_EXPORT DSA *d2i_DSAparams(DSA **out, const uint8_t **inp, long len); + +/* i2d_DSAparams marshals DSA parameters from |in| to an ASN.1, DER structure. + * If |outp| is not NULL then the result is written to |*outp| and |*outp| is + * advanced just past the output. It returns the number of bytes in the result, + * whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_DSAparams(const DSA *in, unsigned char **outp); + + +/* Precomputation. */ + +/* DSA_sign_setup precomputes the message independent part of the DSA signature + * and writes them to |*out_kinv| and |*out_r|. Returns one on success, zero on + * error. + * + * TODO(fork): decide what to do with this. Since making DSA* opaque there's no + * way for the user to install them. Also, it forces the DSA* not to be const + * when passing to the signing function. */ +OPENSSL_EXPORT int DSA_sign_setup(const DSA *dsa, BN_CTX *ctx, + BIGNUM **out_kinv, BIGNUM **out_r); + + +/* Conversion. */ + +/* DSA_dup_DH returns a |DH| constructed from the parameters of |dsa|. This is + * sometimes needed when Diffie-Hellman parameters are stored in the form of + * DSA parameters. It returns an allocated |DH| on success or NULL on error. */ +OPENSSL_EXPORT DH *DSA_dup_DH(const DSA *dsa); + + +/* ex_data functions. + * + * See |ex_data.h| for details. */ + +OPENSSL_EXPORT int DSA_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int DSA_set_ex_data(DSA *d, int idx, void *arg); +OPENSSL_EXPORT void *DSA_get_ex_data(const DSA *d, int idx); + + +struct dsa_method { + struct openssl_method_common_st common; + + void *app_data; + + int (*init)(DSA *dsa); + int (*finish)(DSA *dsa); + + DSA_SIG *(*sign)(const uint8_t *digest, size_t digest_len, DSA *dsa); + + int (*sign_setup)(const DSA *dsa, BN_CTX *ctx_in, BIGNUM **kinvp, BIGNUM **rp, + const uint8_t *digest, size_t digest_len); + + int (*verify)(int *out_valid, const uint8_t *digest, size_t digest_len, + DSA_SIG *sig, const DSA *dsa); + + /* generate_parameters, if non-NULL, is used to generate DSA parameters. */ + int (*generate_parameters)(DSA *dsa, unsigned bits, const uint8_t *seed, + size_t seed_len, int *counter_ret, + unsigned long *h_ret, BN_GENCB *cb); + + /* keygen, if non-NULL, is used to generate DSA keys. */ + int (*keygen)(DSA *dsa); +}; + +struct dsa_st { + long version; + int write_params; + BIGNUM *p; + BIGNUM *q; /* == 20 */ + BIGNUM *g; + + BIGNUM *pub_key; /* y public key */ + BIGNUM *priv_key; /* x private key */ + + BIGNUM *kinv; /* Signing pre-calc */ + BIGNUM *r; /* Signing pre-calc */ + + int flags; + /* Normally used to cache montgomery values */ + CRYPTO_MUTEX method_mont_p_lock; + BN_MONT_CTX *method_mont_p; + CRYPTO_refcount_t references; + CRYPTO_EX_DATA ex_data; + DSA_METHOD *meth; + /* functional reference if 'meth' is ENGINE-provided */ + ENGINE *engine; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define DSA_R_BAD_Q_VALUE 100 +#define DSA_R_MISSING_PARAMETERS 101 +#define DSA_R_MODULUS_TOO_LARGE 102 +#define DSA_R_NEED_NEW_SETUP_VALUES 103 + +#endif /* OPENSSL_HEADER_DSA_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/dtls1.h b/TMessagesProj/jni/boringssl/include/openssl/dtls1.h new file mode 100644 index 00000000..38ca801c --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/dtls1.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/ec.h b/TMessagesProj/jni/boringssl/include/openssl/ec.h new file mode 100644 index 00000000..f664211c --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ec.h @@ -0,0 +1,366 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#ifndef OPENSSL_HEADER_EC_H +#define OPENSSL_HEADER_EC_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Low-level operations on elliptic curves. */ + + +typedef struct ec_group_st EC_GROUP; +typedef struct ec_point_st EC_POINT; + +/** Enum for the point conversion form as defined in X9.62 (ECDSA) + * for the encoding of a elliptic curve point (x,y) */ +typedef enum { + /** the point is encoded as z||x, where the octet z specifies + * which solution of the quadratic equation y is */ + POINT_CONVERSION_COMPRESSED = 2, + /** the point is encoded as z||x||y, where z is the octet 0x02 */ + POINT_CONVERSION_UNCOMPRESSED = 4 +} point_conversion_form_t; + + +/* Elliptic curve groups. */ + +/* EC_GROUP_new_by_curve_name returns a fresh EC_GROUP object for the elliptic + * curve specified by |nid|, or NULL on error. + * + * The supported NIDs are: + * NID_secp224r1, + * NID_X9_62_prime256v1, + * NID_secp384r1, + * NID_secp521r1 */ +OPENSSL_EXPORT EC_GROUP *EC_GROUP_new_by_curve_name(int nid); + +/* EC_GROUP_free frees |group| and the data that it points to. */ +OPENSSL_EXPORT void EC_GROUP_free(EC_GROUP *group); + +/* EC_GROUP_dup returns a fresh |EC_GROUP| which is equal to |a| or NULL on + * error. */ +OPENSSL_EXPORT EC_GROUP *EC_GROUP_dup(const EC_GROUP *a); + +/* EC_GROUP_cmp returns zero if |a| and |b| are the same group and non-zero + * otherwise. */ +OPENSSL_EXPORT int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, + BN_CTX *ignored); + +/* EC_GROUP_get0_generator returns a pointer to the internal |EC_POINT| object + * in |group| that specifies the generator for the group. */ +OPENSSL_EXPORT const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group); + +/* EC_GROUP_get_order sets |*order| to the order of |group|, if it's not + * NULL. It returns one on success and zero otherwise. |ctx| is ignored. */ +OPENSSL_EXPORT int EC_GROUP_get_order(const EC_GROUP *group, BIGNUM *order, + BN_CTX *ctx); + +/* EC_GROUP_get_cofactor sets |*cofactor| to the cofactor of |group| using + * |ctx|, if it's not NULL. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_GROUP_get_cofactor(const EC_GROUP *group, + BIGNUM *cofactor, BN_CTX *ctx); + +/* EC_GROUP_get_curve_GFp gets various parameters about a group. It sets + * |*out_p| to the order of the coordinate field and |*out_a| and |*out_b| to + * the parameters of the curve when expressed as y² = x³ + ax + b. Any of the + * output parameters can be NULL. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int EC_GROUP_get_curve_GFp(const EC_GROUP *group, BIGNUM *out_p, + BIGNUM *out_a, BIGNUM *out_b, + BN_CTX *ctx); + +/* EC_GROUP_get_curve_name returns a NID that identifies |group|. */ +OPENSSL_EXPORT int EC_GROUP_get_curve_name(const EC_GROUP *group); + +/* EC_GROUP_get_degree returns the number of bits needed to represent an + * element of the field underlying |group|. */ +OPENSSL_EXPORT int EC_GROUP_get_degree(const EC_GROUP *group); + +/* EC_GROUP_precompute_mult precomputes multiplies of the generator in order to + * speed up operations that involve calculating generator multiples. It returns + * one on sucess and zero otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_GROUP_precompute_mult(EC_GROUP *group, BN_CTX *ctx); + +/* EC_GROUP_have_precompute_mult returns one if |group| contains precomputed + * generator multiples. */ +OPENSSL_EXPORT int EC_GROUP_have_precompute_mult(const EC_GROUP *group); + + +/* Points on elliptic curves. */ + +/* EC_POINT_new returns a fresh |EC_POINT| object in the given group, or NULL + * on error. */ +OPENSSL_EXPORT EC_POINT *EC_POINT_new(const EC_GROUP *group); + +/* EC_POINT_free frees |point| and the data that it points to. */ +OPENSSL_EXPORT void EC_POINT_free(EC_POINT *point); + +/* EC_POINT_clear_free clears the data that |point| points to, frees it and + * then frees |point| itself. */ +OPENSSL_EXPORT void EC_POINT_clear_free(EC_POINT *point); + +/* EC_POINT_copy sets |*dest| equal to |*src|. It returns one on success and + * zero otherwise. */ +OPENSSL_EXPORT int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src); + +/* EC_POINT_dup returns a fresh |EC_POINT| that contains the same values as + * |src|, or NULL on error. */ +OPENSSL_EXPORT EC_POINT *EC_POINT_dup(const EC_POINT *src, + const EC_GROUP *group); + +/* EC_POINT_set_to_infinity sets |point| to be the "point at infinity" for the + * given group. */ +OPENSSL_EXPORT int EC_POINT_set_to_infinity(const EC_GROUP *group, + EC_POINT *point); + +/* EC_POINT_is_at_infinity returns one iff |point| is the point at infinity and + * zero otherwise. */ +OPENSSL_EXPORT int EC_POINT_is_at_infinity(const EC_GROUP *group, + const EC_POINT *point); + +/* EC_POINT_is_on_curve returns one if |point| is an element of |group| and + * zero otheriwse. If |ctx| is non-NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_is_on_curve(const EC_GROUP *group, + const EC_POINT *point, BN_CTX *ctx); + +/* EC_POINT_cmp returns zero if |a| is equal to |b|, greater than zero is + * non-equal and -1 on error. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, + const EC_POINT *b, BN_CTX *ctx); + +/* EC_POINT_make_affine converts |point| to affine form, internally. It returns + * one on success and zero otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, + BN_CTX *ctx); + +/* EC_POINTs_make_affine converts |num| points from |points| to affine form, + * internally. It returns one on success and zero otherwise. If |ctx| is not + * NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, + EC_POINT *points[], BN_CTX *ctx); + + +/* Point conversion. */ + +/* EC_POINT_get_affine_coordinates_GFp sets |x| and |y| to the affine value of + * |point| using |ctx|, if it's not NULL. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, + const EC_POINT *point, + BIGNUM *x, BIGNUM *y, + BN_CTX *ctx); + +/* EC_POINT_set_affine_coordinates_GFp sets the value of |p| to be (|x|, |y|). The + * |ctx| argument may be used if not NULL. */ +OPENSSL_EXPORT int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, + EC_POINT *point, + const BIGNUM *x, + const BIGNUM *y, + BN_CTX *ctx); + +/* EC_POINT_point2oct serialises |point| into the X9.62 form given by |form| + * into, at most, |len| bytes at |buf|. It returns the number of bytes written + * or zero on error if |buf| is non-NULL, else the number of bytes needed. The + * |ctx| argument may be used if not NULL. */ +OPENSSL_EXPORT size_t EC_POINT_point2oct(const EC_GROUP *group, + const EC_POINT *point, + point_conversion_form_t form, + uint8_t *buf, size_t len, BN_CTX *ctx); + +/* EC_POINT_oct2point sets |point| from |len| bytes of X9.62 format + * serialisation in |buf|. It returns one on success and zero otherwise. The + * |ctx| argument may be used if not NULL. */ +OPENSSL_EXPORT int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point, + const uint8_t *buf, size_t len, + BN_CTX *ctx); + +/* EC_POINT_set_compressed_coordinates_GFp sets |point| to equal the point with + * the given |x| coordinate and the y coordinate specified by |y_bit| (see + * X9.62). It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_POINT_set_compressed_coordinates_GFp( + const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, int y_bit, + BN_CTX *ctx); + + +/* Group operations. */ + +/* EC_POINT_add sets |r| equal to |a| plus |b|. It returns one on success and + * zero otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, + const EC_POINT *a, const EC_POINT *b, + BN_CTX *ctx); + +/* EC_POINT_dbl sets |r| equal to |a| plus |a|. It returns one on success and + * zero otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, + const EC_POINT *a, BN_CTX *ctx); + +/* EC_POINT_invert sets |a| equal to minus |a|. It returns one on success and zero + * otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, + BN_CTX *ctx); + +/* EC_POINT_mul sets r = generator*n + q*m. It returns one on success and zero + * otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, + const BIGNUM *n, const EC_POINT *q, + const BIGNUM *m, BN_CTX *ctx); + +/* EC_POINTs_mul sets r = generator*n + sum(p[i]*m[i]). It returns one on + * success and zero otherwise. If |ctx| is not NULL, it may be used. */ +OPENSSL_EXPORT int EC_POINTs_mul(const EC_GROUP *group, EC_POINT *r, + const BIGNUM *n, size_t num, + const EC_POINT *p[], const BIGNUM *m[], + BN_CTX *ctx); + + +/* Deprecated functions. */ + +/* EC_GROUP_new_curve_GFp creates a new, arbitrary elliptic curve group based + * on the equation y² = x³ + a·x + b. It returns the new group or NULL on + * error. + * + * |EC_GROUP|s returned by this function will always compare as unequal via + * |EC_GROUP_cmp| (even to themselves). |EC_GROUP_get_curve_name| will always + * return |NID_undef|. */ +OPENSSL_EXPORT EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, + const BIGNUM *a, + const BIGNUM *b, BN_CTX *ctx); + +/* EC_GROUP_set_generator sets the generator for |group| to |generator|, which + * must have the given order and cofactor. This should only be used with + * |EC_GROUP| objects returned by |EC_GROUP_new_curve_GFp|. */ +OPENSSL_EXPORT int EC_GROUP_set_generator(EC_GROUP *group, + const EC_POINT *generator, + const BIGNUM *order, + const BIGNUM *cofactor); + +/* EC_GROUP_set_asn1_flag does nothing. */ +OPENSSL_EXPORT void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag); + +#define OPENSSL_EC_NAMED_CURVE 0 + +typedef struct ec_method_st EC_METHOD; + +/* EC_GROUP_method_of returns NULL. */ +OPENSSL_EXPORT const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *group); + +/* EC_METHOD_get_field_type returns NID_X9_62_prime_field. */ +OPENSSL_EXPORT int EC_METHOD_get_field_type(const EC_METHOD *meth); + +/* EC_GROUP_set_point_conversion_form aborts the process if |form| is not + * |POINT_CONVERSION_UNCOMPRESSED| and otherwise does nothing. */ +OPENSSL_EXPORT void EC_GROUP_set_point_conversion_form( + EC_GROUP *group, point_conversion_form_t form); + + +/* Old code expects to get EC_KEY from ec.h. */ +#if !defined(OPENSSL_HEADER_EC_KEY_H) +#include +#endif + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define EC_R_BUFFER_TOO_SMALL 100 +#define EC_R_COORDINATES_OUT_OF_RANGE 101 +#define EC_R_D2I_ECPKPARAMETERS_FAILURE 102 +#define EC_R_EC_GROUP_NEW_BY_NAME_FAILURE 103 +#define EC_R_GROUP2PKPARAMETERS_FAILURE 104 +#define EC_R_I2D_ECPKPARAMETERS_FAILURE 105 +#define EC_R_INCOMPATIBLE_OBJECTS 106 +#define EC_R_INVALID_COMPRESSED_POINT 107 +#define EC_R_INVALID_COMPRESSION_BIT 108 +#define EC_R_INVALID_ENCODING 109 +#define EC_R_INVALID_FIELD 110 +#define EC_R_INVALID_FORM 111 +#define EC_R_INVALID_GROUP_ORDER 112 +#define EC_R_INVALID_PRIVATE_KEY 113 +#define EC_R_MISSING_PARAMETERS 114 +#define EC_R_MISSING_PRIVATE_KEY 115 +#define EC_R_NON_NAMED_CURVE 116 +#define EC_R_NOT_INITIALIZED 117 +#define EC_R_PKPARAMETERS2GROUP_FAILURE 118 +#define EC_R_POINT_AT_INFINITY 119 +#define EC_R_POINT_IS_NOT_ON_CURVE 120 +#define EC_R_SLOT_FULL 121 +#define EC_R_UNDEFINED_GENERATOR 122 +#define EC_R_UNKNOWN_GROUP 123 +#define EC_R_UNKNOWN_ORDER 124 +#define EC_R_WRONG_ORDER 125 +#define EC_R_BIGNUM_OUT_OF_RANGE 126 +#define EC_R_WRONG_CURVE_PARAMETERS 127 + +#endif /* OPENSSL_HEADER_EC_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/ec_key.h b/TMessagesProj/jni/boringssl/include/openssl/ec_key.h new file mode 100644 index 00000000..1cd4e6e6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ec_key.h @@ -0,0 +1,286 @@ +/* Originally written by Bodo Moeller for the OpenSSL project. + * ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * The elliptic curve binary polynomial software is originally written by + * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems + * Laboratories. */ + +#ifndef OPENSSL_HEADER_EC_KEY_H +#define OPENSSL_HEADER_EC_KEY_H + +#include + +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* ec_key.h contains functions that handle elliptic-curve points that are + * public/private keys. */ + + +/* EC key objects. */ + +/* EC_KEY_new returns a fresh |EC_KEY| object or NULL on error. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_new(void); + +/* EC_KEY_new_method acts the same as |EC_KEY_new|, but takes an explicit + * |ENGINE|. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_new_method(const ENGINE *engine); + +/* EC_KEY_new_by_curve_name returns a fresh EC_KEY for group specified by |nid| + * or NULL on error. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_new_by_curve_name(int nid); + +/* EC_KEY_free frees all the data owned by |key| and |key| itself. */ +OPENSSL_EXPORT void EC_KEY_free(EC_KEY *key); + +/* EC_KEY_copy sets |dst| equal to |src| and returns |dst| or NULL on error. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_copy(EC_KEY *dst, const EC_KEY *src); + +/* EC_KEY_dup returns a fresh copy of |src| or NULL on error. */ +OPENSSL_EXPORT EC_KEY *EC_KEY_dup(const EC_KEY *src); + +/* EC_KEY_up_ref increases the reference count of |key|. It returns one on + * success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_up_ref(EC_KEY *key); + +/* EC_KEY_is_opaque returns one if |key| is opaque and doesn't expose its key + * material. Otherwise it return zero. */ +OPENSSL_EXPORT int EC_KEY_is_opaque(const EC_KEY *key); + +/* EC_KEY_get0_group returns a pointer to the |EC_GROUP| object inside |key|. */ +OPENSSL_EXPORT const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key); + +/* EC_KEY_set_group sets the |EC_GROUP| object that |key| will use to |group|. + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group); + +/* EC_KEY_get0_private_key returns a pointer to the private key inside |key|. */ +OPENSSL_EXPORT const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key); + +/* EC_KEY_set_private_key sets the private key of |key| to |priv|. It returns + * one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *prv); + +/* EC_KEY_get0_public_key returns a pointer to the public key point inside + * |key|. */ +OPENSSL_EXPORT const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key); + +/* EC_KEY_set_public_key sets the public key of |key| to |pub|, by copying it. + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub); + +#define EC_PKEY_NO_PARAMETERS 0x001 +#define EC_PKEY_NO_PUBKEY 0x002 + +/* EC_KEY_get_enc_flags returns the encoding flags for |key|, which is a + * bitwise-OR of |EC_PKEY_*| values. */ +OPENSSL_EXPORT unsigned EC_KEY_get_enc_flags(const EC_KEY *key); + +/* EC_KEY_set_enc_flags sets the encoding flags for |key|, which is a + * bitwise-OR of |EC_PKEY_*| values. */ +OPENSSL_EXPORT void EC_KEY_set_enc_flags(EC_KEY *key, unsigned flags); + +/* EC_KEY_get_conv_form returns the conversation form that will be used by + * |key|. */ +OPENSSL_EXPORT point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key); + +/* EC_KEY_set_conv_form sets the conversion form to be used by |key|. */ +OPENSSL_EXPORT void EC_KEY_set_conv_form(EC_KEY *key, + point_conversion_form_t cform); + +/* EC_KEY_precompute_mult precomputes multiplies of the generator of the + * underlying group in order to speed up operations that calculate generator + * multiples. If |ctx| is not NULL, it may be used. It returns one on success + * and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_precompute_mult(EC_KEY *key, BN_CTX *ctx); + +/* EC_KEY_check_key performs several checks on |key| (possibly including an + * expensive check that the public key is in the primary subgroup). It returns + * one if all checks pass and zero otherwise. If it returns zero then detail + * about the problem can be found on the error stack. */ +OPENSSL_EXPORT int EC_KEY_check_key(const EC_KEY *key); + +/* EC_KEY_set_public_key_affine_coordinates sets the public key in |key| to + * (|x|, |y|). It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, + BIGNUM *x, + BIGNUM *y); + + +/* Key generation. */ + +/* EC_KEY_generate_key generates a random, private key, calculates the + * corresponding public key and stores both in |key|. It returns one on success + * or zero otherwise. */ +OPENSSL_EXPORT int EC_KEY_generate_key(EC_KEY *key); + + +/* Serialisation. */ + +/* d2i_ECPrivateKey parses an ASN.1, DER-encoded, private key from |len| bytes + * at |*inp|. If |out_key| is not NULL then, on exit, a pointer to the result + * is in |*out_key|. If |*out_key| is already non-NULL on entry then the result + * is written directly into |*out_key|, otherwise a fresh |EC_KEY| is + * allocated. On successful exit, |*inp| is advanced past the DER structure. It + * returns the result or NULL on error. */ +OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey(EC_KEY **out_key, const uint8_t **inp, + long len); + +/* i2d_ECPrivateKey marshals an EC private key from |key| to an ASN.1, DER + * structure. If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_ECPrivateKey(const EC_KEY *key, uint8_t **outp); + +/* d2i_ECParameters parses an ASN.1, DER-encoded, set of EC parameters from + * |len| bytes at |*inp|. If |out_key| is not NULL then, on exit, a pointer to + * the result is in |*out_key|. If |*out_key| is already non-NULL on entry then + * the result is written directly into |*out_key|, otherwise a fresh |EC_KEY| + * is allocated. On successful exit, |*inp| is advanced past the DER structure. + * It returns the result or NULL on error. */ +OPENSSL_EXPORT EC_KEY *d2i_ECParameters(EC_KEY **out_key, const uint8_t **inp, + long len); + +/* i2d_ECParameters marshals EC parameters from |key| to an ASN.1, DER + * structure. If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_ECParameters(const EC_KEY *key, uint8_t **outp); + +/* o2i_ECPublicKey parses an EC point from |len| bytes at |*inp| into + * |*out_key|. Note that this differs from the d2i format in that |*out_key| + * must be non-NULL with a group set. On successful exit, |*inp| is advanced by + * |len| bytes. It returns |*out_key| or NULL on error. */ +OPENSSL_EXPORT EC_KEY *o2i_ECPublicKey(EC_KEY **out_key, const uint8_t **inp, + long len); + +/* i2o_ECPublicKey marshals an EC point from |key|. If |outp| is not NULL then + * the result is written to |*outp| and |*outp| is advanced just past the + * output. It returns the number of bytes in the result, whether written or + * not, or a negative value on error. */ +OPENSSL_EXPORT int i2o_ECPublicKey(const EC_KEY *key, unsigned char **outp); + + +/* ex_data functions. + * + * These functions are wrappers. See |ex_data.h| for details. */ + +OPENSSL_EXPORT int EC_KEY_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int EC_KEY_set_ex_data(EC_KEY *r, int idx, void *arg); +OPENSSL_EXPORT void *EC_KEY_get_ex_data(const EC_KEY *r, int idx); + + +/* ECDSA method. */ + +/* ECDSA_FLAG_OPAQUE specifies that this ECDSA_METHOD does not expose its key + * material. This may be set if, for instance, it is wrapping some other crypto + * API, like a platform key store. */ +#define ECDSA_FLAG_OPAQUE 1 + +/* ecdsa_method_st is a structure of function pointers for implementing ECDSA. + * See engine.h. */ +struct ecdsa_method_st { + struct openssl_method_common_st common; + + void *app_data; + + int (*init)(EC_KEY *key); + int (*finish)(EC_KEY *key); + + /* group_order_size returns the number of bytes needed to represent the order + * of the group. This is used to calculate the maximum size of an ECDSA + * signature in |ECDSA_size|. */ + size_t (*group_order_size)(const EC_KEY *key); + + /* sign matches the arguments and behaviour of |ECDSA_sign|. */ + int (*sign)(const uint8_t *digest, size_t digest_len, uint8_t *sig, + unsigned int *sig_len, EC_KEY *eckey); + + /* verify matches the arguments and behaviour of |ECDSA_verify|. */ + int (*verify)(const uint8_t *digest, size_t digest_len, const uint8_t *sig, + size_t sig_len, EC_KEY *eckey); + + int flags; +}; + + +/* Deprecated functions. */ + +/* EC_KEY_set_asn1_flag does nothing. */ +OPENSSL_EXPORT void EC_KEY_set_asn1_flag(EC_KEY *key, int flag); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_EC_KEY_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/ecdh.h b/TMessagesProj/jni/boringssl/include/openssl/ecdh.h new file mode 100644 index 00000000..878cbeb5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ecdh.h @@ -0,0 +1,102 @@ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * The Elliptic Curve Public-Key Crypto Library (ECC Code) included + * herein is developed by SUN MICROSYSTEMS, INC., and is contributed + * to the OpenSSL project. + * + * The ECC Code is licensed pursuant to the OpenSSL open source + * license provided below. + * + * The ECDH software is originally written by Douglas Stebila of + * Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright (c) 2000-2002 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_ECDH_H +#define OPENSSL_HEADER_ECDH_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Elliptic curve Diffie-Hellman. */ + + +/* ECDH_compute_key calculates the shared key between |pub_key| and |priv_key|. + * If |KDF| is not NULL, then it is called with the bytes of the shared key and + * the parameter |out|. When |KDF| returns, the value of |*outlen| becomes the + * return value. Otherwise, as many bytes of the shared key as will fit are + * copied directly to, at most, |outlen| bytes at |out|. It returns the number + * of bytes written to |out|, or -1 on error. */ +OPENSSL_EXPORT int ECDH_compute_key(void *out, size_t outlen, + const EC_POINT *pub_key, EC_KEY *priv_key, + void *(*KDF)(const void *in, size_t inlen, + void *out, size_t *outlen)); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define ECDH_R_KDF_FAILED 100 +#define ECDH_R_NO_PRIVATE_VALUE 101 +#define ECDH_R_POINT_ARITHMETIC_FAILURE 102 + +#endif /* OPENSSL_HEADER_ECDH_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/ecdsa.h b/TMessagesProj/jni/boringssl/include/openssl/ecdsa.h new file mode 100644 index 00000000..84702c33 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ecdsa.h @@ -0,0 +1,206 @@ +/* ==================================================================== + * Copyright (c) 1998-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_ECDSA_H +#define OPENSSL_HEADER_ECDSA_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* ECDSA contains functions for signing and verifying with the Digital Signature + * Algorithm over elliptic curves. */ + + +/* Signing and verifing. */ + +/* ECDSA_sign signs |digest_len| bytes from |digest| with |key| and writes the + * resulting signature to |sig|, which must have |ECDSA_size(key)| bytes of + * space. On successful exit, |*sig_len| is set to the actual number of bytes + * written. The |type| argument should be zero. It returns one on success and + * zero otherwise. */ +OPENSSL_EXPORT int ECDSA_sign(int type, const uint8_t *digest, + size_t digest_len, uint8_t *sig, + unsigned int *sig_len, EC_KEY *key); + +/* ECDSA_verify verifies that |sig_len| bytes from |sig| constitute a valid + * signature by |key| of |digest|. (The |type| argument should be zero.) It + * returns one on success or zero if the signature is invalid or an error + * occured. */ +OPENSSL_EXPORT int ECDSA_verify(int type, const uint8_t *digest, + size_t digest_len, const uint8_t *sig, + size_t sig_len, EC_KEY *key); + +/* ECDSA_size returns the maximum size of an ECDSA signature using |key|. It + * returns zero on error. */ +OPENSSL_EXPORT size_t ECDSA_size(const EC_KEY *key); + + +/* Low-level signing and verification. + * + * Low-level functions handle signatures as |ECDSA_SIG| structures which allow + * the two values in an ECDSA signature to be handled separately. */ + +struct ecdsa_sig_st { + BIGNUM *r; + BIGNUM *s; +}; + +/* ECDSA_SIG_new returns a fresh |ECDSA_SIG| structure or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_SIG_new(void); + +/* ECDSA_SIG_free frees |sig| its member |BIGNUM|s. */ +OPENSSL_EXPORT void ECDSA_SIG_free(ECDSA_SIG *sig); + +/* ECDSA_sign signs |digest_len| bytes from |digest| with |key| and returns the + * resulting signature structure, or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, + size_t digest_len, EC_KEY *key); + +/* ECDSA_verify verifies that |sig| constitutes a valid signature by |key| of + * |digest|. It returns one on success or zero if the signature is invalid or + * on error. */ +OPENSSL_EXPORT int ECDSA_do_verify(const uint8_t *digest, size_t digest_len, + const ECDSA_SIG *sig, EC_KEY *key); + + +/* Signing with precomputation. + * + * Parts of the ECDSA signature can be independent of the message to be signed + * thus it's possible to precompute them and reduce the signing latency. + * + * TODO(fork): remove support for this as it cannot support safe-randomness. */ + +/* ECDSA_sign_setup precomputes parts of an ECDSA signing operation. It sets + * |*kinv| and |*rp| to the precomputed values and uses the |ctx| argument, if + * not NULL. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int ECDSA_sign_setup(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinv, + BIGNUM **rp); + +/* ECDSA_do_sign_ex is the same as |ECDSA_do_sign| but takes precomputed values + * as generated by |ECDSA_sign_setup|. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_do_sign_ex(const uint8_t *digest, + size_t digest_len, + const BIGNUM *kinv, const BIGNUM *rp, + EC_KEY *eckey); + +/* ECDSA_sign_ex is the same as |ECDSA_sign| but takes precomputed values as + * generated by |ECDSA_sign_setup|. */ +OPENSSL_EXPORT int ECDSA_sign_ex(int type, const uint8_t *digest, + size_t digest_len, uint8_t *sig, + unsigned int *sig_len, const BIGNUM *kinv, + const BIGNUM *rp, EC_KEY *eckey); + + +/* ASN.1 functions. */ + +/* ECDSA_SIG_parse parses a DER-encoded ECDSA-Sig-Value structure from |cbs| and + * advances |cbs|. It returns a newly-allocated |ECDSA_SIG| or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_SIG_parse(CBS *cbs); + +/* ECDSA_SIG_from_bytes parses |in| as a DER-encoded ECDSA-Sig-Value structure. + * It returns a newly-allocated |ECDSA_SIG| structure or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *ECDSA_SIG_from_bytes(const uint8_t *in, + size_t in_len); + +/* ECDSA_SIG_marshal marshals |sig| as a DER-encoded ECDSA-Sig-Value and appends + * the result to |cbb|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int ECDSA_SIG_marshal(CBB *cbb, const ECDSA_SIG *sig); + +/* ECDSA_SIG_to_asn1 marshals |sig| as a DER-encoded ECDSA-Sig-Value and, on + * success, sets |*out_bytes| to a newly allocated buffer containing the result + * and returns one. Otherwise, it returns zero. The result should be freed with + * |OPENSSL_free|. */ +OPENSSL_EXPORT int ECDSA_SIG_to_bytes(uint8_t **out_bytes, size_t *out_len, + const ECDSA_SIG *sig); + +/* ECDSA_SIG_max_len returns the maximum length of a DER-encoded ECDSA-Sig-Value + * structure for a group whose order is represented in |order_len| bytes, or + * zero on overflow. */ +OPENSSL_EXPORT size_t ECDSA_SIG_max_len(size_t order_len); + + +/* Deprecated functions. */ + +/* d2i_ECDSA_SIG parses an ASN.1, DER-encoded, signature from |len| bytes at + * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in + * |*out|. If |*out| is already non-NULL on entry then the result is written + * directly into |*out|, otherwise a fresh |ECDSA_SIG| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **out, const uint8_t **inp, + long len); + +/* i2d_ECDSA_SIG marshals a signature from |sig| to an ASN.1, DER + * structure. If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_ECDSA_SIG(const ECDSA_SIG *sig, uint8_t **outp); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define ECDSA_R_BAD_SIGNATURE 100 +#define ECDSA_R_MISSING_PARAMETERS 101 +#define ECDSA_R_NEED_NEW_SETUP_VALUES 102 +#define ECDSA_R_NOT_IMPLEMENTED 103 +#define ECDSA_R_RANDOM_NUMBER_GENERATION_FAILED 104 +#define ECDSA_R_ENCODE_ERROR 105 + +#endif /* OPENSSL_HEADER_ECDSA_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/engine.h b/TMessagesProj/jni/boringssl/include/openssl/engine.h new file mode 100644 index 00000000..d3d278a6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/engine.h @@ -0,0 +1,107 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_ENGINE_H +#define OPENSSL_HEADER_ENGINE_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Engines are collections of methods. Methods are tables of function pointers, + * defined for certain algorithms, that allow operations on those algorithms to + * be overridden via a callback. This can be used, for example, to implement an + * RSA* that forwards operations to a hardware module. + * + * Methods are reference counted but |ENGINE|s are not. When creating a method, + * you should zero the whole structure and fill in the function pointers that + * you wish before setting it on an |ENGINE|. Any functions pointers that + * are NULL indicate that the default behaviour should be used. */ + + +/* Allocation and destruction. */ + +/* ENGINE_new returns an empty ENGINE that uses the default method for all + * algorithms. */ +OPENSSL_EXPORT ENGINE *ENGINE_new(void); + +/* ENGINE_free decrements the reference counts for all methods linked from + * |engine| and frees |engine| itself. */ +OPENSSL_EXPORT void ENGINE_free(ENGINE *engine); + + +/* Method accessors. + * + * Method accessors take a method pointer and the size of the structure. The + * size allows for ABI compatibility in the case that the method structure is + * extended with extra elements at the end. Methods are always copied by the + * set functions. + * + * Set functions return one on success and zero on allocation failure. */ + +OPENSSL_EXPORT int ENGINE_set_DH_method(ENGINE *engine, const DH_METHOD *method, + size_t method_size); +OPENSSL_EXPORT DH_METHOD *ENGINE_get_DH_method(const ENGINE *engine); + +OPENSSL_EXPORT int ENGINE_set_DSA_method(ENGINE *engine, + const DSA_METHOD *method, + size_t method_size); +OPENSSL_EXPORT DSA_METHOD *ENGINE_get_DSA_method(const ENGINE *engine); + +OPENSSL_EXPORT int ENGINE_set_RSA_method(ENGINE *engine, + const RSA_METHOD *method, + size_t method_size); +OPENSSL_EXPORT RSA_METHOD *ENGINE_get_RSA_method(const ENGINE *engine); + +OPENSSL_EXPORT int ENGINE_set_ECDSA_method(ENGINE *engine, + const ECDSA_METHOD *method, + size_t method_size); +OPENSSL_EXPORT ECDSA_METHOD *ENGINE_get_ECDSA_method(const ENGINE *engine); + + +/* Generic method functions. + * + * These functions take a void* type but actually operate on all method + * structures. */ + +/* METHOD_ref increments the reference count of |method|. This is a no-op for + * now because all methods are currently static. */ +void METHOD_ref(void *method); + +/* METHOD_unref decrements the reference count of |method| and frees it if the + * reference count drops to zero. This is a no-op for now because all methods + * are currently static. */ +void METHOD_unref(void *method); + + +/* Private functions. */ + +/* openssl_method_common_st contains the common part of all method structures. + * This must be the first member of all method structures. */ +struct openssl_method_common_st { + int references; /* dummy – not used. */ + char is_static; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define ENGINE_R_OPERATION_NOT_SUPPORTED 100 + +#endif /* OPENSSL_HEADER_ENGINE_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/err.h b/TMessagesProj/jni/boringssl/include/openssl/err.h new file mode 100644 index 00000000..0a90b0e3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/err.h @@ -0,0 +1,503 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_ERR_H +#define OPENSSL_HEADER_ERR_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Error queue handling functions. + * + * Errors in OpenSSL are generally signalled by the return value of a function. + * When a function fails it may add an entry to a per-thread error queue, + * which is managed by the functions in this header. + * + * Each error contains: + * 1) The library (i.e. ec, pem, rsa) which created it. + * 2) The function, file, and line number of the call that added the error. + * 3) A pointer to some error specific data, which may be NULL. + * + * The library identifier and reason code are packed in a uint32_t and there + * exist various functions for unpacking it. + * + * The typical behaviour is that an error will occur deep in a call queue and + * that code will push an error onto the error queue. As the error queue + * unwinds, other functions will push their own errors. Thus, the "least + * recent" error is the most specific and the other errors will provide a + * backtrace of sorts. */ + + +/* Startup and shutdown. */ + +/* ERR_load_BIO_strings does nothing. + * + * TODO(fork): remove. libjingle calls this. */ +OPENSSL_EXPORT void ERR_load_BIO_strings(void); + +/* ERR_load_ERR_strings does nothing. */ +OPENSSL_EXPORT void ERR_load_ERR_strings(void); + +/* ERR_load_crypto_strings does nothing. */ +OPENSSL_EXPORT void ERR_load_crypto_strings(void); + +/* ERR_free_strings does nothing. */ +OPENSSL_EXPORT void ERR_free_strings(void); + + +/* Reading and formatting errors. */ + +/* ERR_get_error gets the packed error code for the least recent error and + * removes that error from the queue. If there are no errors in the queue then + * it returns zero. */ +OPENSSL_EXPORT uint32_t ERR_get_error(void); + +/* ERR_get_error_line acts like |ERR_get_error|, except that the file and line + * number of the call that added the error are also returned. */ +OPENSSL_EXPORT uint32_t ERR_get_error_line(const char **file, int *line); + +/* ERR_get_error_line_data acts like |ERR_get_error_line|, but also returns the + * error-specific data pointer and flags. The flags are a bitwise-OR of + * |ERR_FLAG_*| values. The error-specific data is owned by the error queue + * and the pointer becomes invalid after the next call that affects the same + * thread's error queue. If |*flags| contains |ERR_FLAG_STRING| then |*data| is + * human-readable. */ +OPENSSL_EXPORT uint32_t ERR_get_error_line_data(const char **file, int *line, + const char **data, int *flags); + +/* The "peek" functions act like the |ERR_get_error| functions, above, but they + * do not remove the error from the queue. */ +OPENSSL_EXPORT uint32_t ERR_peek_error(void); +OPENSSL_EXPORT uint32_t ERR_peek_error_line(const char **file, int *line); +OPENSSL_EXPORT uint32_t ERR_peek_error_line_data(const char **file, int *line, + const char **data, int *flags); + +/* ERR_peek_function returns the name of the function which added the least + * recent error or NULL if the queue is empty. */ +OPENSSL_EXPORT const char *ERR_peek_function(void); + +/* The "peek last" functions act like the "peek" functions, above, except that + * they return the most recent error. */ +OPENSSL_EXPORT uint32_t ERR_peek_last_error(void); +OPENSSL_EXPORT uint32_t ERR_peek_last_error_line(const char **file, int *line); +OPENSSL_EXPORT uint32_t ERR_peek_last_error_line_data(const char **file, + int *line, + const char **data, + int *flags); + +/* ERR_error_string generates a human-readable string representing + * |packed_error|, places it at |buf| (which must be at least + * ERR_ERROR_STRING_BUF_LEN bytes long) and returns |buf|. If |buf| is NULL, + * the error string is placed in a static buffer which is returned. (The static + * buffer may be overridden by concurrent calls in other threads so this form + * is deprecated.) + * + * The string will have the following format: + * + * error:[error code]:[library name]:OPENSSL_internal:[reason string] + * + * error code is an 8 digit hexadecimal number; library name and reason string + * are ASCII text. + * + * TODO(fork): remove in favour of |ERR_error_string_n|. */ +OPENSSL_EXPORT char *ERR_error_string(uint32_t packed_error, char *buf); +#define ERR_ERROR_STRING_BUF_LEN 256 + +/* ERR_error_string_n is a variant of |ERR_error_string| that writes at most + * len characters (including the terminating NUL) and truncates the string if + * necessary. If |len| is greater than zero then |buf| is always NUL + * terminated. */ +OPENSSL_EXPORT void ERR_error_string_n(uint32_t packed_error, char *buf, + size_t len); + +/* ERR_lib_error_string returns a string representation of the library that + * generated |packed_error|. */ +OPENSSL_EXPORT const char *ERR_lib_error_string(uint32_t packed_error); + +/* ERR_reason_error_string returns a string representation of the reason for + * |packed_error|. */ +OPENSSL_EXPORT const char *ERR_reason_error_string(uint32_t packed_error); + +/* ERR_print_errors_callback_t is the type of a function used by + * |ERR_print_errors_cb|. It takes a pointer to a human readable string (and + * its length) that describes an entry in the error queue. The |ctx| argument + * is an opaque pointer given to |ERR_print_errors_cb|. + * + * It should return one on success or zero on error, which will stop the + * iteration over the error queue. */ +typedef int (*ERR_print_errors_callback_t)(const char *str, size_t len, + void *ctx); + +/* ERR_print_errors_cb calls |callback| with a string representation of each + * error in the current thread's error queue, from the least recent to the most + * recent error. + * + * The string will have the following format (which differs from + * |ERR_error_string|): + * + * [thread id]:error:[error code]:[library name]:[function name]: + * [reason string]:[file]:[line number]:[optional string data] + * + * (All in one line.) + * + * The callback can return one to continue the iteration or zero to stop it. + * The |ctx| argument is an opaque value that is passed through to the + * callback. */ +OPENSSL_EXPORT void ERR_print_errors_cb(ERR_print_errors_callback_t callback, + void *ctx); + + +/* ERR_print_errors_fp prints the current contents of the error stack to |file| + * using human readable strings where possible. */ +OPENSSL_EXPORT void ERR_print_errors_fp(FILE *file); + +/* Clearing errors. */ + +/* ERR_clear_error clears the error queue for the current thread. */ +OPENSSL_EXPORT void ERR_clear_error(void); + +/* ERR_remove_thread_state clears the error queue for the current thread if + * |tid| is NULL. Otherwise it calls |assert(0)|, because it's no longer + * possible to delete the error queue for other threads. + * + * Error queues are thread-local data and are deleted automatically. You do not + * need to call this function. Use |ERR_clear_error|. */ +OPENSSL_EXPORT void ERR_remove_thread_state(const CRYPTO_THREADID *tid); + + +/* Custom errors. */ + +/* ERR_get_next_error_library returns a value suitable for passing as the + * |library| argument to |ERR_put_error|. This is intended for code that wishes + * to push its own, non-standard errors to the error queue. */ +OPENSSL_EXPORT int ERR_get_next_error_library(void); + + +/* Deprecated functions. */ + +/* ERR_remove_state calls |ERR_clear_error|. */ +OPENSSL_EXPORT void ERR_remove_state(unsigned long pid); + +/* ERR_func_error_string returns the string "OPENSSL_internal". */ +OPENSSL_EXPORT const char *ERR_func_error_string(uint32_t packed_error); + + +/* Private functions. */ + +/* ERR_clear_system_error clears the system's error value (i.e. errno). */ +OPENSSL_EXPORT void ERR_clear_system_error(void); + +#if defined(OPENSSL_WINDOWS) +/* TODO(davidben): Use |__func__| directly once the minimum MSVC version + * supports it. */ +#define OPENSSL_CURRENT_FUNCTION __FUNCTION__ +#else +#define OPENSSL_CURRENT_FUNCTION __func__ +#endif + +/* OPENSSL_PUT_ERROR is used by OpenSSL code to add an error to the error + * queue. */ +#define OPENSSL_PUT_ERROR(library, reason) \ + ERR_put_error(ERR_LIB_##library, reason, OPENSSL_CURRENT_FUNCTION, __FILE__, \ + __LINE__) + +/* OPENSSL_PUT_SYSTEM_ERROR is used by OpenSSL code to add an error from the + * operating system to the error queue. */ +/* TODO(fork): include errno. */ +#define OPENSSL_PUT_SYSTEM_ERROR(func) \ + ERR_put_error(ERR_LIB_SYS, 0, #func, __FILE__, __LINE__); + +/* ERR_put_error adds an error to the error queue, dropping the least recent + * error if neccessary for space reasons. */ +OPENSSL_EXPORT void ERR_put_error(int library, int reason, const char *function, + const char *file, unsigned line); + +/* ERR_add_error_data takes a variable number (|count|) of const char* + * pointers, concatenates them and sets the result as the data on the most + * recent error. */ +OPENSSL_EXPORT void ERR_add_error_data(unsigned count, ...); + +/* ERR_add_error_dataf takes a printf-style format and arguments, and sets the + * result as the data on the most recent error. */ +OPENSSL_EXPORT void ERR_add_error_dataf(const char *format, ...); + +/* ERR_set_mark "marks" the most recent error for use with |ERR_pop_to_mark|. + * It returns one if an error was marked and zero if there are no errors. */ +OPENSSL_EXPORT int ERR_set_mark(void); + +/* ERR_pop_to_mark removes errors from the most recent to the least recent + * until (and not including) a "marked" error. It returns zero if no marked + * error was found (and thus all errors were removed) and one otherwise. Errors + * are marked using |ERR_set_mark|. */ +OPENSSL_EXPORT int ERR_pop_to_mark(void); + +struct err_error_st { + /* function contains the name of the function where the error occured. */ + const char *function; + /* file contains the filename where the error occured. */ + const char *file; + /* data contains optional data. It must be freed with |OPENSSL_free| if + * |flags&ERR_FLAG_MALLOCED|. */ + char *data; + /* packed contains the error library, function and reason, as packed by + * ERR_PACK. */ + uint32_t packed; + /* line contains the line number where the error occured. */ + uint16_t line; + /* flags contains a bitwise-OR of ERR_FLAG_* values. */ + uint8_t flags; +}; + +/* ERR_FLAG_STRING means that the |data| member is a NUL-terminated string that + * can be printed. */ +#define ERR_FLAG_STRING 1 +/* ERR_TXT_STRING is provided for compatibility with code that assumes that + * it's using OpenSSL. */ +#define ERR_TXT_STRING ERR_FLAG_STRING + +/* ERR_FLAG_PUBLIC_MASK is applied to the flags field before it is returned + * from functions like |ERR_get_error_line_data|. */ +#define ERR_FLAG_PUBLIC_MASK 0xf + +/* The following flag values are internal and are masked when flags are + * returned from functions like |ERR_get_error_line_data|. */ + +/* ERR_FLAG_MALLOCED means the the |data| member must be freed when no longer + * needed. */ +#define ERR_FLAG_MALLOCED 16 +/* ERR_FLAG_MARK is used to indicate a reversion point in the queue. See + * |ERR_pop_to_mark|. */ +#define ERR_FLAG_MARK 32 + +/* ERR_NUM_ERRORS is the limit of the number of errors in the queue. */ +#define ERR_NUM_ERRORS 16 + +/* ERR_STATE contains the per-thread, error queue. */ +typedef struct err_state_st { + /* errors contains the ERR_NUM_ERRORS most recent errors, organised as a ring + * buffer. */ + struct err_error_st errors[ERR_NUM_ERRORS]; + /* top contains the index one past the most recent error. If |top| equals + * |bottom| then the queue is empty. */ + unsigned top; + /* bottom contains the index of the last error in the queue. */ + unsigned bottom; + + /* to_free, if not NULL, contains a pointer owned by this structure that was + * previously a |data| pointer of one of the elements of |errors|. */ + void *to_free; +} ERR_STATE; + +enum { + ERR_LIB_NONE = 1, + ERR_LIB_SYS, + ERR_LIB_BN, + ERR_LIB_RSA, + ERR_LIB_DH, + ERR_LIB_EVP, + ERR_LIB_BUF, + ERR_LIB_OBJ, + ERR_LIB_PEM, + ERR_LIB_DSA, + ERR_LIB_X509, + ERR_LIB_ASN1, + ERR_LIB_CONF, + ERR_LIB_CRYPTO, + ERR_LIB_EC, + ERR_LIB_SSL, + ERR_LIB_BIO, + ERR_LIB_PKCS7, + ERR_LIB_PKCS8, + ERR_LIB_X509V3, + ERR_LIB_RAND, + ERR_LIB_ENGINE, + ERR_LIB_OCSP, + ERR_LIB_UI, + ERR_LIB_COMP, + ERR_LIB_ECDSA, + ERR_LIB_ECDH, + ERR_LIB_HMAC, + ERR_LIB_DIGEST, + ERR_LIB_CIPHER, + ERR_LIB_HKDF, + ERR_LIB_USER, + ERR_NUM_LIBS +}; + +#define ERR_R_SYS_LIB ERR_LIB_SYS +#define ERR_R_BN_LIB ERR_LIB_BN +#define ERR_R_RSA_LIB ERR_LIB_RSA +#define ERR_R_DH_LIB ERR_LIB_DH +#define ERR_R_EVP_LIB ERR_LIB_EVP +#define ERR_R_BUF_LIB ERR_LIB_BUF +#define ERR_R_OBJ_LIB ERR_LIB_OBJ +#define ERR_R_PEM_LIB ERR_LIB_PEM +#define ERR_R_DSA_LIB ERR_LIB_DSA +#define ERR_R_X509_LIB ERR_LIB_X509 +#define ERR_R_ASN1_LIB ERR_LIB_ASN1 +#define ERR_R_CONF_LIB ERR_LIB_CONF +#define ERR_R_CRYPTO_LIB ERR_LIB_CRYPTO +#define ERR_R_EC_LIB ERR_LIB_EC +#define ERR_R_SSL_LIB ERR_LIB_SSL +#define ERR_R_BIO_LIB ERR_LIB_BIO +#define ERR_R_PKCS7_LIB ERR_LIB_PKCS7 +#define ERR_R_PKCS8_LIB ERR_LIB_PKCS8 +#define ERR_R_X509V3_LIB ERR_LIB_X509V3 +#define ERR_R_RAND_LIB ERR_LIB_RAND +#define ERR_R_DSO_LIB ERR_LIB_DSO +#define ERR_R_ENGINE_LIB ERR_LIB_ENGINE +#define ERR_R_OCSP_LIB ERR_LIB_OCSP +#define ERR_R_UI_LIB ERR_LIB_UI +#define ERR_R_COMP_LIB ERR_LIB_COMP +#define ERR_R_ECDSA_LIB ERR_LIB_ECDSA +#define ERR_R_ECDH_LIB ERR_LIB_ECDH +#define ERR_R_STORE_LIB ERR_LIB_STORE +#define ERR_R_FIPS_LIB ERR_LIB_FIPS +#define ERR_R_CMS_LIB ERR_LIB_CMS +#define ERR_R_TS_LIB ERR_LIB_TS +#define ERR_R_HMAC_LIB ERR_LIB_HMAC +#define ERR_R_JPAKE_LIB ERR_LIB_JPAKE +#define ERR_R_USER_LIB ERR_LIB_USER +#define ERR_R_DIGEST_LIB ERR_LIB_DIGEST +#define ERR_R_CIPHER_LIB ERR_LIB_CIPHER +#define ERR_R_HKDF_LIB ERR_LIB_HKDF + +/* Global reasons. */ +#define ERR_R_FATAL 64 +#define ERR_R_MALLOC_FAILURE (1 | ERR_R_FATAL) +#define ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED (2 | ERR_R_FATAL) +#define ERR_R_PASSED_NULL_PARAMETER (3 | ERR_R_FATAL) +#define ERR_R_INTERNAL_ERROR (4 | ERR_R_FATAL) +#define ERR_R_OVERFLOW (5 | ERR_R_FATAL) + +#define ERR_PACK(lib, reason) \ + (((((uint32_t)lib) & 0xff) << 24) | ((((uint32_t)reason) & 0xfff))) + +#define ERR_GET_LIB(packed_error) ((int)(((packed_error) >> 24) & 0xff)) +#define ERR_GET_FUNC(packed_error) 0 +#define ERR_GET_REASON(packed_error) ((int)((packed_error) & 0xfff)) + +/* OPENSSL_DECLARE_ERROR_REASON is used by util/make_errors.h (which generates + * the error defines) to recognise that an additional reason value is needed. + * This is needed when the reason value is used outside of an + * |OPENSSL_PUT_ERROR| macro. The resulting define will be + * ${lib}_R_${reason}. */ +#define OPENSSL_DECLARE_ERROR_REASON(lib, reason) + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_ERR_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/evp.h b/TMessagesProj/jni/boringssl/include/openssl/evp.h new file mode 100644 index 00000000..99b147e1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/evp.h @@ -0,0 +1,743 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_EVP_H +#define OPENSSL_HEADER_EVP_H + +#include + +#include + +/* OpenSSL included digest and cipher functions in this header so we include + * them for users that still expect that. + * + * TODO(fork): clean up callers so that they include what they use. */ +#include +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* EVP abstracts over public/private key algorithms. */ + + +/* Public key objects. */ + +/* EVP_PKEY_new creates a new, empty public-key object and returns it or NULL + * on allocation failure. */ +OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_new(void); + +/* EVP_PKEY_free frees all data referenced by |pkey| and then frees |pkey| + * itself. */ +OPENSSL_EXPORT void EVP_PKEY_free(EVP_PKEY *pkey); + +/* EVP_PKEY_up_ref increments the reference count of |pkey| and returns it. */ +OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_up_ref(EVP_PKEY *pkey); + +/* EVP_PKEY_is_opaque returns one if |pkey| is opaque. Opaque keys are backed by + * custom implementations which do not expose key material and parameters. It is + * an error to attempt to duplicate, export, or compare an opaque key. */ +OPENSSL_EXPORT int EVP_PKEY_is_opaque(const EVP_PKEY *pkey); + +/* EVP_PKEY_supports_digest returns one if |pkey| supports digests of + * type |md|. This is intended for use with EVP_PKEYs backing custom + * implementations which can't sign all digests. */ +OPENSSL_EXPORT int EVP_PKEY_supports_digest(const EVP_PKEY *pkey, + const EVP_MD *md); + +/* EVP_PKEY_cmp compares |a| and |b| and returns one if they are equal, zero if + * not and a negative number on error. + * + * WARNING: this differs from the traditional return value of a "cmp" + * function. */ +OPENSSL_EXPORT int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b); + +/* EVP_PKEY_copy_parameters sets the parameters of |to| to equal the parameters + * of |from|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from); + +/* EVP_PKEY_missing_parameters returns one if |pkey| is missing needed + * parameters or zero if not, or if the algorithm doesn't take parameters. */ +OPENSSL_EXPORT int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey); + +/* EVP_PKEY_size returns the maximum size, in bytes, of a signature signed by + * |pkey|. For an RSA key, this returns the number of bytes needed to represent + * the modulus. For an EC key, this returns the maximum size of a DER-encoded + * ECDSA signature. */ +OPENSSL_EXPORT int EVP_PKEY_size(const EVP_PKEY *pkey); + +/* EVP_PKEY_bits returns the "size", in bits, of |pkey|. For an RSA key, this + * returns the bit length of the modulus. For an EC key, this returns the bit + * length of the group order. */ +OPENSSL_EXPORT int EVP_PKEY_bits(EVP_PKEY *pkey); + +/* EVP_PKEY_id returns the type of |pkey|, which is one of the |EVP_PKEY_*| + * values. */ +OPENSSL_EXPORT int EVP_PKEY_id(const EVP_PKEY *pkey); + +/* EVP_PKEY_type returns a canonicalised form of |NID|. For example, + * |EVP_PKEY_RSA2| will be turned into |EVP_PKEY_RSA|. */ +OPENSSL_EXPORT int EVP_PKEY_type(int nid); + + +/* Getting and setting concrete public key types. + * + * The following functions get and set the underlying public key in an + * |EVP_PKEY| object. The |set1| functions take an additional reference to the + * underlying key and return one on success or zero on error. The |assign| + * functions adopt the caller's reference. The getters return a fresh reference + * to the underlying object. */ + +OPENSSL_EXPORT int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, RSA *key); +OPENSSL_EXPORT int EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *key); +OPENSSL_EXPORT RSA *EVP_PKEY_get1_RSA(EVP_PKEY *pkey); + +OPENSSL_EXPORT int EVP_PKEY_set1_DSA(EVP_PKEY *pkey, struct dsa_st *key); +OPENSSL_EXPORT int EVP_PKEY_assign_DSA(EVP_PKEY *pkey, DSA *key); +OPENSSL_EXPORT struct dsa_st *EVP_PKEY_get1_DSA(EVP_PKEY *pkey); + +OPENSSL_EXPORT int EVP_PKEY_set1_EC_KEY(EVP_PKEY *pkey, struct ec_key_st *key); +OPENSSL_EXPORT int EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, EC_KEY *key); +OPENSSL_EXPORT struct ec_key_st *EVP_PKEY_get1_EC_KEY(EVP_PKEY *pkey); + +OPENSSL_EXPORT int EVP_PKEY_set1_DH(EVP_PKEY *pkey, struct dh_st *key); +OPENSSL_EXPORT int EVP_PKEY_assign_DH(EVP_PKEY *pkey, DH *key); +OPENSSL_EXPORT struct dh_st *EVP_PKEY_get1_DH(EVP_PKEY *pkey); + +#define EVP_PKEY_NONE NID_undef +#define EVP_PKEY_RSA NID_rsaEncryption +#define EVP_PKEY_RSA2 NID_rsa +#define EVP_PKEY_DSA NID_dsa +#define EVP_PKEY_DH NID_dhKeyAgreement +#define EVP_PKEY_DHX NID_dhpublicnumber +#define EVP_PKEY_EC NID_X9_62_id_ecPublicKey + +/* EVP_PKEY_assign sets the underlying key of |pkey| to |key|, which must be of + * the given type. The |type| argument should be one of the |EVP_PKEY_*| + * values. */ +OPENSSL_EXPORT int EVP_PKEY_assign(EVP_PKEY *pkey, int type, void *key); + +/* EVP_PKEY_set_type sets the type of |pkey| to |type|, which should be one of + * the |EVP_PKEY_*| values. It returns one if sucessful or zero otherwise. If + * |pkey| is NULL, it simply reports whether the type is known. */ +OPENSSL_EXPORT int EVP_PKEY_set_type(EVP_PKEY *pkey, int type); + +/* EVP_PKEY_cmp_parameters compares the parameters of |a| and |b|. It returns + * one if they match, zero if not, or a negative number of on error. + * + * WARNING: the return value differs from the usual return value convention. */ +OPENSSL_EXPORT int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, + const EVP_PKEY *b); + + +/* ASN.1 functions */ + +/* d2i_PrivateKey parses an ASN.1, DER-encoded, private key from |len| bytes at + * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in + * |*out|. If |*out| is already non-NULL on entry then the result is written + * directly into |*out|, otherwise a fresh |EVP_PKEY| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, + const uint8_t **inp, long len); + +/* d2i_AutoPrivateKey acts the same as |d2i_PrivateKey|, but detects the type + * of the private key. */ +OPENSSL_EXPORT EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, + long len); + +/* i2d_PrivateKey marshals a private key from |key| to an ASN.1, DER + * structure. If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_PrivateKey(const EVP_PKEY *key, uint8_t **outp); + +/* i2d_PublicKey marshals a public key from |key| to a type-specific format. + * If |outp| is not NULL then the result is written to |*outp| and + * |*outp| is advanced just past the output. It returns the number of bytes in + * the result, whether written or not, or a negative value on error. + * + * RSA keys are serialized as a DER-encoded RSAPublicKey (RFC 3447) structure. + * EC keys are serialized as an EC point per SEC 1. */ +OPENSSL_EXPORT int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp); + + +/* Signing */ + +/* EVP_DigestSignInit sets up |ctx| for a signing operation with |type| and + * |pkey|. The |ctx| argument must have been initialised with + * |EVP_MD_CTX_init|. If |pctx| is not NULL, the |EVP_PKEY_CTX| of the signing + * operation will be written to |*pctx|; this can be used to set alternative + * signing options. + * + * It returns one on success, or zero on error. */ +OPENSSL_EXPORT int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, + EVP_PKEY *pkey); + +/* EVP_DigestSignUpdate appends |len| bytes from |data| to the data which will + * be signed in |EVP_DigestSignFinal|. It returns one. */ +OPENSSL_EXPORT int EVP_DigestSignUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_DigestSignFinal signs the data that has been included by one or more + * calls to |EVP_DigestSignUpdate|. If |out_sig| is NULL then |*out_sig_len| is + * set to the maximum number of output bytes. Otherwise, on entry, + * |*out_sig_len| must contain the length of the |out_sig| buffer. If the call + * is successful, the signature is written to |out_sig| and |*out_sig_len| is + * set to its length. + * + * It returns one on success, or zero on error. */ +OPENSSL_EXPORT int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig, + size_t *out_sig_len); + +/* EVP_DigestSignAlgorithm encodes the signing parameters of |ctx| as an + * AlgorithmIdentifer and saves the result in |algor|. + * + * It returns one on success, or zero on error. + * + * TODO(davidben): This API should eventually lose the dependency on + * crypto/asn1/. */ +OPENSSL_EXPORT int EVP_DigestSignAlgorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor); + + +/* Verifying */ + +/* EVP_DigestVerifyInit sets up |ctx| for a signature verification operation + * with |type| and |pkey|. The |ctx| argument must have been initialised with + * |EVP_MD_CTX_init|. If |pctx| is not NULL, the |EVP_PKEY_CTX| of the signing + * operation will be written to |*pctx|; this can be used to set alternative + * signing options. + * + * It returns one on success, or zero on error. */ +OPENSSL_EXPORT int EVP_DigestVerifyInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, + const EVP_MD *type, ENGINE *e, + EVP_PKEY *pkey); + +/* EVP_DigestVerifyInitFromAlgorithm sets up |ctx| for a signature verification + * operation with public key |pkey| and parameters from |algor|. The |ctx| + * argument must have been initialised with |EVP_MD_CTX_init|. + * + * It returns one on success, or zero on error. + * + * TODO(davidben): This API should eventually lose the dependency on + * crypto/asn1/. */ +OPENSSL_EXPORT int EVP_DigestVerifyInitFromAlgorithm(EVP_MD_CTX *ctx, + X509_ALGOR *algor, + EVP_PKEY *pkey); + +/* EVP_DigestVerifyUpdate appends |len| bytes from |data| to the data which + * will be verified by |EVP_DigestVerifyFinal|. It returns one. */ +OPENSSL_EXPORT int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_DigestVerifyFinal verifies that |sig_len| bytes of |sig| are a valid + * signature for the data that has been included by one or more calls to + * |EVP_DigestVerifyUpdate|. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, + size_t sig_len); + + +/* Signing (old functions) */ + +/* EVP_SignInit_ex configures |ctx|, which must already have been initialised, + * for a fresh signing operation using the hash function |type|. It returns one + * on success and zero otherwise. + * + * (In order to initialise |ctx|, either obtain it initialised with + * |EVP_MD_CTX_create|, or use |EVP_MD_CTX_init|.) */ +OPENSSL_EXPORT int EVP_SignInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, + ENGINE *impl); + +/* EVP_SignInit is a deprecated version of |EVP_SignInit_ex|. + * + * TODO(fork): remove. */ +OPENSSL_EXPORT int EVP_SignInit(EVP_MD_CTX *ctx, const EVP_MD *type); + +/* EVP_SignUpdate appends |len| bytes from |data| to the data which will be + * signed in |EVP_SignFinal|. */ +OPENSSL_EXPORT int EVP_SignUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_SignFinal signs the data that has been included by one or more calls to + * |EVP_SignUpdate|, using the key |pkey|, and writes it to |sig|. On entry, + * |sig| must point to at least |EVP_PKEY_size(pkey)| bytes of space. The + * actual size of the signature is written to |*out_sig_len|. + * + * It returns one on success and zero otherwise. + * + * It does not modify |ctx|, thus it's possible to continue to use |ctx| in + * order to sign a longer message. */ +OPENSSL_EXPORT int EVP_SignFinal(const EVP_MD_CTX *ctx, uint8_t *sig, + unsigned int *out_sig_len, EVP_PKEY *pkey); + + +/* Verifying (old functions) */ + +/* EVP_VerifyInit_ex configures |ctx|, which must already have been + * initialised, for a fresh signature verification operation using the hash + * function |type|. It returns one on success and zero otherwise. + * + * (In order to initialise |ctx|, either obtain it initialised with + * |EVP_MD_CTX_create|, or use |EVP_MD_CTX_init|.) */ +OPENSSL_EXPORT int EVP_VerifyInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, + ENGINE *impl); + +/* EVP_VerifyInit is a deprecated version of |EVP_VerifyInit_ex|. + * + * TODO(fork): remove. */ +OPENSSL_EXPORT int EVP_VerifyInit(EVP_MD_CTX *ctx, const EVP_MD *type); + +/* EVP_VerifyUpdate appends |len| bytes from |data| to the data which will be + * signed in |EVP_VerifyFinal|. */ +OPENSSL_EXPORT int EVP_VerifyUpdate(EVP_MD_CTX *ctx, const void *data, + size_t len); + +/* EVP_VerifyFinal verifies that |sig_len| bytes of |sig| are a valid + * signature, by |pkey|, for the data that has been included by one or more + * calls to |EVP_VerifyUpdate|. + * + * It returns one on success and zero otherwise. + * + * It does not modify |ctx|, thus it's possible to continue to use |ctx| in + * order to sign a longer message. */ +OPENSSL_EXPORT int EVP_VerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, + size_t sig_len, EVP_PKEY *pkey); + + +/* Printing */ + +/* EVP_PKEY_print_public prints a textual representation of the public key in + * |pkey| to |out|. Returns one on success or zero otherwise. */ +OPENSSL_EXPORT int EVP_PKEY_print_public(BIO *out, const EVP_PKEY *pkey, + int indent, ASN1_PCTX *pctx); + +/* EVP_PKEY_print_private prints a textual representation of the private key in + * |pkey| to |out|. Returns one on success or zero otherwise. */ +OPENSSL_EXPORT int EVP_PKEY_print_private(BIO *out, const EVP_PKEY *pkey, + int indent, ASN1_PCTX *pctx); + +/* EVP_PKEY_print_params prints a textual representation of the parameters in + * |pkey| to |out|. Returns one on success or zero otherwise. */ +OPENSSL_EXPORT int EVP_PKEY_print_params(BIO *out, const EVP_PKEY *pkey, + int indent, ASN1_PCTX *pctx); + + +/* Password stretching. + * + * Password stretching functions take a low-entropy password and apply a slow + * function that results in a key suitable for use in symmetric + * cryptography. */ + +/* PKCS5_PBKDF2_HMAC computes |iterations| iterations of PBKDF2 of |password| + * and |salt|, using |digest|, and outputs |key_len| bytes to |out_key|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS5_PBKDF2_HMAC(const char *password, size_t password_len, + const uint8_t *salt, size_t salt_len, + unsigned iterations, const EVP_MD *digest, + size_t key_len, uint8_t *out_key); + +/* PKCS5_PBKDF2_HMAC_SHA1 is the same as PKCS5_PBKDF2_HMAC, but with |digest| + * fixed to |EVP_sha1|. */ +OPENSSL_EXPORT int PKCS5_PBKDF2_HMAC_SHA1(const char *password, + size_t password_len, const uint8_t *salt, + size_t salt_len, unsigned iterations, + size_t key_len, uint8_t *out_key); + + +/* Public key contexts. + * + * |EVP_PKEY_CTX| objects hold the context of an operation (e.g. signing or + * encrypting) that uses a public key. */ + +/* EVP_PKEY_CTX_new allocates a fresh |EVP_PKEY_CTX| for use with |pkey|. It + * returns the context or NULL on error. */ +OPENSSL_EXPORT EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e); + +/* EVP_PKEY_CTX_new_id allocates a fresh |EVP_PKEY_CTX| for a key of type |id| + * (e.g. |EVP_PKEY_HMAC|). This can be used for key generation where + * |EVP_PKEY_CTX_new| can't be used because there isn't an |EVP_PKEY| to pass + * it. It returns the context or NULL on error. */ +OPENSSL_EXPORT EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int id, ENGINE *e); + +/* EVP_PKEY_CTX_free frees |ctx| and the data it owns. */ +OPENSSL_EXPORT void EVP_PKEY_CTX_free(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_CTX_dup allocates a fresh |EVP_PKEY_CTX| and sets it equal to the + * state of |ctx|. It returns the fresh |EVP_PKEY_CTX| or NULL on error. */ +OPENSSL_EXPORT EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_CTX_get0_pkey returns the |EVP_PKEY| associated with |ctx|. */ +OPENSSL_EXPORT EVP_PKEY *EVP_PKEY_CTX_get0_pkey(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_CTX_set_app_data sets an opaque pointer on |ctx|. */ +OPENSSL_EXPORT void EVP_PKEY_CTX_set_app_data(EVP_PKEY_CTX *ctx, void *data); + +/* EVP_PKEY_CTX_get_app_data returns the opaque pointer from |ctx| that was + * previously set with |EVP_PKEY_CTX_set_app_data|, or NULL if none has been + * set. */ +OPENSSL_EXPORT void *EVP_PKEY_CTX_get_app_data(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_sign_init initialises an |EVP_PKEY_CTX| for a signing operation. It + * should be called before |EVP_PKEY_sign|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_sign signs |data_len| bytes from |data| using |ctx|. If |sig| is + * NULL, the maximum size of the signature is written to + * |out_sig_len|. Otherwise, |*sig_len| must contain the number of bytes of + * space available at |sig|. If sufficient, the signature will be written to + * |sig| and |*sig_len| updated with the true length. + * + * WARNING: Setting |sig| to NULL only gives the maximum size of the + * signature. The actual signature may be smaller. + * + * It returns one on success or zero on error. (Note: this differs from + * OpenSSL, which can also return negative values to indicate an error. ) */ +OPENSSL_EXPORT int EVP_PKEY_sign(EVP_PKEY_CTX *ctx, uint8_t *sig, + size_t *sig_len, const uint8_t *data, + size_t data_len); + +/* EVP_PKEY_verify_init initialises an |EVP_PKEY_CTX| for a signature + * verification operation. It should be called before |EVP_PKEY_verify|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_verify_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_verify verifies that |sig_len| bytes from |sig| are a valid signature + * for |data|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_verify(EVP_PKEY_CTX *ctx, const uint8_t *sig, + size_t sig_len, const uint8_t *data, + size_t data_len); + +/* EVP_PKEY_encrypt_init initialises an |EVP_PKEY_CTX| for an encryption + * operation. It should be called before |EVP_PKEY_encrypt|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_encrypt encrypts |in_len| bytes from |in|. If |out| is NULL, the + * maximum size of the ciphertext is written to |out_len|. Otherwise, |*out_len| + * must contain the number of bytes of space available at |out|. If sufficient, + * the ciphertext will be written to |out| and |*out_len| updated with the true + * length. + * + * WARNING: Setting |out| to NULL only gives the maximum size of the + * ciphertext. The actual ciphertext may be smaller. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, uint8_t *out, + size_t *out_len, const uint8_t *in, + size_t in_len); + +/* EVP_PKEY_decrypt_init initialises an |EVP_PKEY_CTX| for a decryption + * operation. It should be called before |EVP_PKEY_decrypt|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_decrypt decrypts |in_len| bytes from |in|. If |out| is NULL, the + * maximum size of the plaintext is written to |out_len|. Otherwise, |*out_len| + * must contain the number of bytes of space available at |out|. If sufficient, + * the ciphertext will be written to |out| and |*out_len| updated with the true + * length. + * + * WARNING: Setting |out| to NULL only gives the maximum size of the + * plaintext. The actual plaintext may be smaller. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, uint8_t *out, + size_t *out_len, const uint8_t *in, + size_t in_len); + +/* EVP_PKEY_derive_init initialises an |EVP_PKEY_CTX| for a key derivation + * operation. It should be called before |EVP_PKEY_derive_set_peer| and + * |EVP_PKEY_derive|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_derive_set_peer sets the peer's key to be used for key derivation + * by |ctx| to |peer|. It should be called after |EVP_PKEY_derive_init|. (For + * example, this is used to set the peer's key in (EC)DH.) It returns one on + * success and zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *ctx, EVP_PKEY *peer); + +/* EVP_PKEY_derive derives a shared key between the two keys configured in + * |ctx|. If |key| is non-NULL then, on entry, |out_key_len| must contain the + * amount of space at |key|. If sufficient then the shared key will be written + * to |key| and |*out_key_len| will be set to the length. If |key| is NULL then + * |out_key_len| will be set to the maximum length. + * + * WARNING: Setting |out| to NULL only gives the maximum size of the key. The + * actual key may be smaller. + * + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_derive(EVP_PKEY_CTX *ctx, uint8_t *key, + size_t *out_key_len); + +/* EVP_PKEY_keygen_init initialises an |EVP_PKEY_CTX| for a key generation + * operation. It should be called before |EVP_PKEY_keygen|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_keygen_init(EVP_PKEY_CTX *ctx); + +/* EVP_PKEY_keygen performs a key generation operation using the values from + * |ctx| and sets |*ppkey| to a fresh |EVP_PKEY| containing the resulting key. + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY **ppkey); + + +/* Generic control functions. */ + +/* EVP_PKEY_CTX_set_signature_md sets |md| as the digest to be used in a + * signature operation. It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, + const EVP_MD *md); + +/* EVP_PKEY_CTX_get_signature_md sets |*out_md| to the digest to be used in a + * signature operation. It returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_signature_md(EVP_PKEY_CTX *ctx, + const EVP_MD **out_md); + + +/* RSA specific control functions. */ + +/* EVP_PKEY_CTX_set_rsa_padding sets the padding type to use. It should be one + * of the |RSA_*_PADDING| values. Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *ctx, int padding); + +/* EVP_PKEY_CTX_get_rsa_padding sets |*out_padding| to the current padding + * value, which is one of the |RSA_*_PADDING| values. Returns one on success or + * zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_rsa_padding(EVP_PKEY_CTX *ctx, + int *out_padding); + +/* EVP_PKEY_CTX_set_rsa_pss_saltlen sets the length of the salt in a PSS-padded + * signature. A value of -1 cause the salt to be the same length as the digest + * in the signature. A value of -2 causes the salt to be the maximum length + * that will fit. Otherwise the value gives the size of the salt in bytes. + * + * Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, + int salt_len); + +/* EVP_PKEY_CTX_get_rsa_pss_saltlen sets |*out_salt_len| to the salt length of + * a PSS-padded signature. See the documentation for + * |EVP_PKEY_CTX_set_rsa_pss_saltlen| for details of the special values that it + * can take. + * + * Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_rsa_pss_saltlen(EVP_PKEY_CTX *ctx, + int *out_salt_len); + +/* EVP_PKEY_CTX_set_rsa_keygen_bits sets the size of the desired RSA modulus, + * in bits, for key generation. Returns one on success or zero on + * error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_keygen_bits(EVP_PKEY_CTX *ctx, + int bits); + +/* EVP_PKEY_CTX_set_rsa_keygen_pubexp sets |e| as the public exponent for key + * generation. Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_keygen_pubexp(EVP_PKEY_CTX *ctx, + BIGNUM *e); + +/* EVP_PKEY_CTX_set_rsa_oaep_md sets |md| as the digest used in OAEP padding. + * Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *ctx, + const EVP_MD *md); + +/* EVP_PKEY_CTX_get_rsa_oaep_md sets |*out_md| to the digest function used in + * OAEP padding. Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_rsa_oaep_md(EVP_PKEY_CTX *ctx, + const EVP_MD **out_md); + +/* EVP_PKEY_CTX_set_rsa_mgf1_md sets |md| as the digest used in MGF1. Returns + * one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *ctx, + const EVP_MD *md); + +/* EVP_PKEY_CTX_get_rsa_mgf1_md sets |*out_md| to the digest function used in + * MGF1. Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, + const EVP_MD **out_md); + +/* EVP_PKEY_CTX_set0_rsa_oaep_label sets |label_len| bytes from |label| as the + * label used in OAEP. DANGER: On success, this call takes ownership of |label| + * and will call |OPENSSL_free| on it when |ctx| is destroyed. + * + * Returns one on success or zero on error. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, + const uint8_t *label, + size_t label_len); + +/* EVP_PKEY_CTX_get0_rsa_oaep_label sets |*out_label| to point to the internal + * buffer containing the OAEP label (which may be NULL) and returns the length + * of the label or a negative value on error. + * + * WARNING: the return value differs from the usual return value convention. */ +OPENSSL_EXPORT int EVP_PKEY_CTX_get0_rsa_oaep_label(EVP_PKEY_CTX *ctx, + const uint8_t **out_label); + + +/* Deprecated functions. */ + +/* OpenSSL_add_all_algorithms does nothing. */ +OPENSSL_EXPORT void OpenSSL_add_all_algorithms(void); + +/* OpenSSL_add_all_ciphers does nothing. */ +OPENSSL_EXPORT void OpenSSL_add_all_ciphers(void); + +/* OpenSSL_add_all_digests does nothing. */ +OPENSSL_EXPORT void OpenSSL_add_all_digests(void); + +/* EVP_cleanup does nothing. */ +OPENSSL_EXPORT void EVP_cleanup(void); + + +/* Private functions */ + +/* EVP_PKEY_asn1_find returns the ASN.1 method table for the given |nid|, which + * should be one of the |EVP_PKEY_*| values. It returns NULL if |nid| is + * unknown. */ +OPENSSL_EXPORT const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find(ENGINE **pengine, + int nid); + +/* TODO(fork): move to PEM? */ +OPENSSL_EXPORT const EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_find_str( + ENGINE **pengine, const char *name, size_t len); + +struct evp_pkey_st { + CRYPTO_refcount_t references; + + /* type contains one of the EVP_PKEY_* values or NID_undef and determines + * which element (if any) of the |pkey| union is valid. */ + int type; + + union { + char *ptr; + RSA *rsa; + DSA *dsa; + DH *dh; + EC_KEY *ec; + } pkey; + + /* ameth contains a pointer to a method table that contains many ASN.1 + * methods for the key type. */ + const EVP_PKEY_ASN1_METHOD *ameth; +} /* EVP_PKEY */; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define EVP_R_BUFFER_TOO_SMALL 100 +#define EVP_R_COMMAND_NOT_SUPPORTED 101 +#define EVP_R_DIFFERENT_KEY_TYPES 104 +#define EVP_R_DIFFERENT_PARAMETERS 105 +#define EVP_R_EXPECTING_AN_EC_KEY_KEY 107 +#define EVP_R_EXPECTING_A_DH_KEY 109 +#define EVP_R_EXPECTING_A_DSA_KEY 110 +#define EVP_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE 111 +#define EVP_R_INVALID_CURVE 112 +#define EVP_R_INVALID_DIGEST_LENGTH 113 +#define EVP_R_INVALID_DIGEST_TYPE 114 +#define EVP_R_INVALID_KEYBITS 115 +#define EVP_R_INVALID_MGF1_MD 116 +#define EVP_R_INVALID_PADDING_MODE 118 +#define EVP_R_INVALID_PSS_PARAMETERS 119 +#define EVP_R_INVALID_SALT_LENGTH 121 +#define EVP_R_INVALID_TRAILER 122 +#define EVP_R_KEYS_NOT_SET 123 +#define EVP_R_MISSING_PARAMETERS 124 +#define EVP_R_NO_DEFAULT_DIGEST 125 +#define EVP_R_NO_KEY_SET 126 +#define EVP_R_NO_MDC2_SUPPORT 127 +#define EVP_R_NO_NID_FOR_CURVE 128 +#define EVP_R_NO_OPERATION_SET 129 +#define EVP_R_NO_PARAMETERS_SET 130 +#define EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE 131 +#define EVP_R_OPERATON_NOT_INITIALIZED 132 +#define EVP_R_UNKNOWN_DIGEST 133 +#define EVP_R_UNKNOWN_MASK_DIGEST 134 +#define EVP_R_UNSUPPORTED_ALGORITHM 138 +#define EVP_R_UNSUPPORTED_MASK_ALGORITHM 139 +#define EVP_R_UNSUPPORTED_MASK_PARAMETER 140 +#define EVP_R_EXPECTING_AN_RSA_KEY 141 +#define EVP_R_INVALID_OPERATION 142 +#define EVP_R_DECODE_ERROR 143 +#define EVP_R_INVALID_PSS_SALTLEN 144 +#define EVP_R_UNKNOWN_PUBLIC_KEY_TYPE 145 +#define EVP_R_CONTEXT_NOT_INITIALISED 146 +#define EVP_R_DIGEST_AND_KEY_TYPE_NOT_SUPPORTED 147 +#define EVP_R_WRONG_PUBLIC_KEY_TYPE 148 +#define EVP_R_UNKNOWN_SIGNATURE_ALGORITHM 149 +#define EVP_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM 150 +#define EVP_R_BN_DECODE_ERROR 151 +#define EVP_R_PARAMETER_ENCODING_ERROR 152 +#define EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE 153 +#define EVP_R_UNSUPPORTED_SIGNATURE_TYPE 154 + +#endif /* OPENSSL_HEADER_EVP_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/ex_data.h b/TMessagesProj/jni/boringssl/include/openssl/ex_data.h new file mode 100644 index 00000000..c0d37731 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ex_data.h @@ -0,0 +1,214 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_EX_DATA_H +#define OPENSSL_HEADER_EX_DATA_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* ex_data is a mechanism for associating arbitrary extra data with objects. + * For each type of object that supports ex_data, different users can be + * assigned indexes in which to store their data. Each index has callback + * functions that are called when a new object of that type is created, freed + * and duplicated. */ + + +typedef struct crypto_ex_data_st CRYPTO_EX_DATA; + + +/* Type-specific functions. + * + * Each type that supports ex_data provides three functions: */ + +#if 0 /* Sample */ + +/* TYPE_get_ex_new_index allocates a new index for |TYPE|. See the + * descriptions of the callback typedefs for details of when they are + * called. Any of the callback arguments may be NULL. The |argl| and |argp| + * arguments are opaque values that are passed to the callbacks. It returns the + * new index or a negative number on error. + * + * TODO(fork): this should follow the standard calling convention. */ +OPENSSL_EXPORT int TYPE_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); + +/* TYPE_set_ex_data sets an extra data pointer on |t|. The |index| argument + * should have been returned from a previous call to |TYPE_get_ex_new_index|. */ +OPENSSL_EXPORT int TYPE_set_ex_data(TYPE *t, int index, void *arg); + +/* TYPE_get_ex_data returns an extra data pointer for |t|, or NULL if no such + * pointer exists. The |index| argument should have been returned from a + * previous call to |TYPE_get_ex_new_index|. */ +OPENSSL_EXPORT void *TYPE_get_ex_data(const TYPE *t, int index); + +#endif /* Sample */ + + +/* Callback types. */ + +/* CRYPTO_EX_new is the type of a callback function that is called whenever a + * new object of a given class is created. For example, if this callback has + * been passed to |SSL_get_ex_new_index| then it'll be called each time an SSL* + * is created. + * + * The callback is passed the new object (i.e. the SSL*) in |parent|. The + * arguments |argl| and |argp| contain opaque values that were given to + * |CRYPTO_get_ex_new_index|. The callback should return one on success, but + * the value is ignored. + * + * TODO(fork): the |ptr| argument is always NULL, no? */ +typedef int CRYPTO_EX_new(void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int index, long argl, void *argp); + +/* CRYPTO_EX_free is a callback function that is called when an object of the + * class is being destroyed. See |CRYPTO_EX_new| for a discussion of the + * arguments. + * + * If |CRYPTO_get_ex_new_index| was called after the creation of objects of the + * class that this applies to then, when those those objects are destroyed, + * this callback will be called with a NULL value for |ptr|. */ +typedef void CRYPTO_EX_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int index, long argl, void *argp); + +/* CRYPTO_EX_dup is a callback function that is called when an object of the + * class is being copied and thus the ex_data linked to it also needs to be + * copied. On entry, |*from_d| points to the data for this index from the + * original object. When the callback returns, |*from_d| will be set as the + * data for this index in |to|. + * + * If |CRYPTO_get_ex_new_index| was called after the creation of objects of the + * class that this applies to then, when those those objects are copies, this + * callback will be called with a NULL value for |*from_d|. */ +typedef int CRYPTO_EX_dup(CRYPTO_EX_DATA *to, const CRYPTO_EX_DATA *from, + void **from_d, int index, long argl, void *argp); + + +/* Deprecated functions. */ + +/* CRYPTO_cleanup_all_ex_data does nothing. */ +OPENSSL_EXPORT void CRYPTO_cleanup_all_ex_data(void); + +struct crypto_ex_data_st { + STACK_OF(void) *sk; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_EX_DATA_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/hkdf.h b/TMessagesProj/jni/boringssl/include/openssl/hkdf.h new file mode 100644 index 00000000..b7a0dc25 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/hkdf.h @@ -0,0 +1,44 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_HKDF_H +#define OPENSSL_HEADER_HKDF_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Computes HKDF (as specified by RFC 5869) of initial keying material |secret| + * with |salt| and |info| using |digest|, and outputs |out_len| bytes to + * |out_key|. It returns one on success and zero on error. + * + * HKDF is an Extract-and-Expand algorithm. It does not do any key stretching, + * and as such, is not suited to be used alone to generate a key from a + * password. */ +OPENSSL_EXPORT int HKDF(uint8_t *out_key, size_t out_len, const EVP_MD *digest, + const uint8_t *secret, size_t secret_len, + const uint8_t *salt, size_t salt_len, + const uint8_t *info, size_t info_len); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define HKDF_R_OUTPUT_TOO_LARGE 100 + +#endif /* OPENSSL_HEADER_HKDF_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/hmac.h b/TMessagesProj/jni/boringssl/include/openssl/hmac.h new file mode 100644 index 00000000..e521212d --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/hmac.h @@ -0,0 +1,160 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_HMAC_H +#define OPENSSL_HEADER_HMAC_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* HMAC contains functions for constructing PRFs from Merkle–Damgård hash + * functions using HMAC. */ + + +/* One-shot operation. */ + +/* HMAC calculates the HMAC of |data_len| bytes of |data|, using the given key + * and hash function, and writes the result to |out|. On entry, |out| must + * contain |EVP_MAX_MD_SIZE| bytes of space. The actual length of the result is + * written to |*out_len|. It returns |out| or NULL on error. */ +OPENSSL_EXPORT uint8_t *HMAC(const EVP_MD *evp_md, const void *key, + size_t key_len, const uint8_t *data, + size_t data_len, uint8_t *out, + unsigned int *out_len); + + +/* Incremental operation. */ + +/* HMAC_CTX_init initialises |ctx| for use in an HMAC operation. It's assumed + * that HMAC_CTX objects will be allocated on the stack thus no allocation + * function is provided. If needed, allocate |sizeof(HMAC_CTX)| and call + * |HMAC_CTX_init| on it. */ +OPENSSL_EXPORT void HMAC_CTX_init(HMAC_CTX *ctx); + +/* HMAC_CTX_cleanup frees data owned by |ctx|. */ +OPENSSL_EXPORT void HMAC_CTX_cleanup(HMAC_CTX *ctx); + +/* HMAC_Init_ex sets up an initialised |HMAC_CTX| to use |md| as the hash + * function and |key| as the key. For a non-initial call, |md| may be NULL, in + * which case the previous hash function will be used. If the hash function has + * not changed and |key| is NULL, |ctx| reuses the previous key. It returns one + * on success or zero otherwise. + * + * WARNING: NULL and empty keys are ambiguous on non-initial calls. Passing NULL + * |key| but repeating the previous |md| reuses the previous key rather than the + * empty key. */ +OPENSSL_EXPORT int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len, + const EVP_MD *md, ENGINE *impl); + +/* HMAC_Update hashes |data_len| bytes from |data| into the current HMAC + * operation in |ctx|. It returns one. */ +OPENSSL_EXPORT int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, + size_t data_len); + +/* HMAC_Final completes the HMAC operation in |ctx| and writes the result to + * |out| and the sets |*out_len| to the length of the result. On entry, |out| + * must contain at least |EVP_MAX_MD_SIZE| bytes of space. It returns one on + * success or zero on error. */ +OPENSSL_EXPORT int HMAC_Final(HMAC_CTX *ctx, uint8_t *out, + unsigned int *out_len); + + +/* Utility functions. */ + +/* HMAC_size returns the size, in bytes, of the HMAC that will be produced by + * |ctx|. On entry, |ctx| must have been setup with |HMAC_Init_ex|. */ +OPENSSL_EXPORT size_t HMAC_size(const HMAC_CTX *ctx); + +/* HMAC_CTX_copy_ex sets |dest| equal to |src|. On entry, |dest| must have been + * initialised by calling |HMAC_CTX_init|. It returns one on success and zero + * on error. */ +OPENSSL_EXPORT int HMAC_CTX_copy_ex(HMAC_CTX *dest, const HMAC_CTX *src); + + +/* Deprecated functions. */ + +OPENSSL_EXPORT int HMAC_Init(HMAC_CTX *ctx, const void *key, int key_len, + const EVP_MD *md); + +/* HMAC_CTX_copy calls |HMAC_CTX_init| on |dest| and then sets it equal to + * |src|. On entry, |dest| must /not/ be initialised for an operation with + * |HMAC_Init_ex|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int HMAC_CTX_copy(HMAC_CTX *dest, const HMAC_CTX *src); + + +/* Private functions */ + +#define HMAC_MAX_MD_CBLOCK 128 /* largest known is SHA512 */ + +struct hmac_ctx_st { + const EVP_MD *md; + EVP_MD_CTX md_ctx; + EVP_MD_CTX i_ctx; + EVP_MD_CTX o_ctx; +} /* HMAC_CTX */; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_HMAC_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/lhash.h b/TMessagesProj/jni/boringssl/include/openssl/lhash.h new file mode 100644 index 00000000..691b247c --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/lhash.h @@ -0,0 +1,192 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_LHASH_H +#define OPENSSL_HEADER_LHASH_H + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* lhash is a traditional, chaining hash table that automatically expands and + * contracts as needed. One should not use the lh_* functions directly, rather + * use the type-safe macro wrappers: + * + * A hash table of a specific type of object has type |LHASH_OF(type)|. This + * can be defined (once) with |DEFINE_LHASH_OF(type)| and declared where needed + * with |DECLARE_LHASH_OF(type)|. For example: + * + * struct foo { + * int bar; + * }; + * + * DEFINE_LHASH_OF(struct foo); + * + * Although note that the hash table will contain /pointers/ to |foo|. + * + * A macro will be defined for each of the lh_* functions below. For + * LHASH_OF(foo), the macros would be lh_foo_new, lh_foo_num_items etc. */ + + +#define LHASH_OF(type) struct lhash_st_##type + +#define DEFINE_LHASH_OF(type) LHASH_OF(type) { int dummy; } + +#define DECLARE_LHASH_OF(type) LHASH_OF(type); + +/* The make_macros.sh script in this directory parses the following lines and + * generates the lhash_macros.h file that contains macros for the following + * types of stacks: + * + * LHASH_OF:ASN1_OBJECT + * LHASH_OF:CONF_VALUE + * LHASH_OF:SSL_SESSION */ + +#define IN_LHASH_H +#include +#undef IN_LHASH_H + + +/* lhash_item_st is an element of a hash chain. It points to the opaque data + * for this element and to the next item in the chain. The linked-list is NULL + * terminated. */ +typedef struct lhash_item_st { + void *data; + struct lhash_item_st *next; + /* hash contains the cached, hash value of |data|. */ + uint32_t hash; +} LHASH_ITEM; + +/* lhash_cmp_func is a comparison function that returns a value equal, or not + * equal, to zero depending on whether |*a| is equal, or not equal to |*b|, + * respectively. Note the difference between this and |stack_cmp_func| in that + * this takes pointers to the objects directly. */ +typedef int (*lhash_cmp_func)(const void *a, const void *b); + +/* lhash_hash_func is a function that maps an object to a uniformly distributed + * uint32_t. */ +typedef uint32_t (*lhash_hash_func)(const void *a); + +typedef struct lhash_st { + /* num_items contains the total number of items in the hash table. */ + size_t num_items; + /* buckets is an array of |num_buckets| pointers. Each points to the head of + * a chain of LHASH_ITEM objects that have the same hash value, mod + * |num_buckets|. */ + LHASH_ITEM **buckets; + /* num_buckets contains the length of |buckets|. This value is always >= + * kMinNumBuckets. */ + size_t num_buckets; + /* callback_depth contains the current depth of |lh_doall| or |lh_doall_arg| + * calls. If non-zero then this suppresses resizing of the |buckets| array, + * which would otherwise disrupt the iteration. */ + unsigned callback_depth; + + lhash_cmp_func comp; + lhash_hash_func hash; +} _LHASH; + +/* lh_new returns a new, empty hash table or NULL on error. If |comp| is NULL, + * |strcmp| will be used. If |hash| is NULL, a generic hash function will be + * used. */ +OPENSSL_EXPORT _LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp); + +/* lh_free frees the hash table itself but none of the elements. See + * |lh_doall|. */ +OPENSSL_EXPORT void lh_free(_LHASH *lh); + +/* lh_num_items returns the number of items in |lh|. */ +OPENSSL_EXPORT size_t lh_num_items(const _LHASH *lh); + +/* lh_retrieve finds an element equal to |data| in the hash table and returns + * it. If no such element exists, it returns NULL. */ +OPENSSL_EXPORT void *lh_retrieve(const _LHASH *lh, const void *data); + +/* lh_insert inserts |data| into the hash table. If an existing element is + * equal to |data| (with respect to the comparison function) then |*old_data| + * will be set to that value and it will be replaced. Otherwise, or in the + * event of an error, |*old_data| will be set to NULL. It returns one on + * success or zero in the case of an allocation error. */ +OPENSSL_EXPORT int lh_insert(_LHASH *lh, void **old_data, void *data); + +/* lh_delete removes an element equal to |data| from the hash table and returns + * it. If no such element is found, it returns NULL. */ +OPENSSL_EXPORT void *lh_delete(_LHASH *lh, const void *data); + +/* lh_doall calls |func| on each element of the hash table. + * TODO(fork): rename this */ +OPENSSL_EXPORT void lh_doall(_LHASH *lh, void (*func)(void *)); + +/* lh_doall_arg calls |func| on each element of the hash table and also passes + * |arg| as the second argument. + * TODO(fork): rename this */ +OPENSSL_EXPORT void lh_doall_arg(_LHASH *lh, void (*func)(void *, void *), + void *arg); + +/* lh_strhash is the default hash function which processes NUL-terminated + * strings. */ +OPENSSL_EXPORT uint32_t lh_strhash(const char *c); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_STACK_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/lhash_macros.h b/TMessagesProj/jni/boringssl/include/openssl/lhash_macros.h new file mode 100644 index 00000000..1d981073 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/lhash_macros.h @@ -0,0 +1,132 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#if !defined(IN_LHASH_H) +#error "Don't include this file directly. Include lhash.h" +#endif + +/* ASN1_OBJECT */ +#define lh_ASN1_OBJECT_new(hash, comp) \ + ((LHASH_OF(ASN1_OBJECT) *)lh_new( \ + CHECKED_CAST(lhash_hash_func, uint32_t (*)(const ASN1_OBJECT *), hash), \ + CHECKED_CAST(lhash_cmp_func, \ + int (*)(const ASN1_OBJECT *a, const ASN1_OBJECT *b), \ + comp))) + +#define lh_ASN1_OBJECT_free(lh) \ + lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh)); + +#define lh_ASN1_OBJECT_num_items(lh) \ + lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh)) + +#define lh_ASN1_OBJECT_retrieve(lh, data) \ + ((ASN1_OBJECT *)lh_retrieve( \ + CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void *, ASN1_OBJECT *, data))) + +#define lh_ASN1_OBJECT_insert(lh, old_data, data) \ + lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void **, ASN1_OBJECT **, old_data), \ + CHECKED_CAST(void *, ASN1_OBJECT *, data)) + +#define lh_ASN1_OBJECT_delete(lh, data) \ + ((ASN1_OBJECT *)lh_delete( \ + CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void *, ASN1_OBJECT *, data))) + +#define lh_ASN1_OBJECT_doall(lh, func) \ + lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_OBJECT *), func)); + +#define lh_ASN1_OBJECT_doall_arg(lh, func, arg) \ + lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(ASN1_OBJECT) *, lh), \ + CHECKED_CAST(void (*)(void *, void *), \ + void (*)(ASN1_OBJECT *, void *), func), \ + arg); + +/* CONF_VALUE */ +#define lh_CONF_VALUE_new(hash, comp) \ + ((LHASH_OF(CONF_VALUE) *)lh_new( \ + CHECKED_CAST(lhash_hash_func, uint32_t (*)(const CONF_VALUE *), hash), \ + CHECKED_CAST(lhash_cmp_func, \ + int (*)(const CONF_VALUE *a, const CONF_VALUE *b), comp))) + +#define lh_CONF_VALUE_free(lh) \ + lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh)); + +#define lh_CONF_VALUE_num_items(lh) \ + lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh)) + +#define lh_CONF_VALUE_retrieve(lh, data) \ + ((CONF_VALUE *)lh_retrieve( \ + CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void *, CONF_VALUE *, data))) + +#define lh_CONF_VALUE_insert(lh, old_data, data) \ + lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void **, CONF_VALUE **, old_data), \ + CHECKED_CAST(void *, CONF_VALUE *, data)) + +#define lh_CONF_VALUE_delete(lh, data) \ + ((CONF_VALUE *)lh_delete(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void *, CONF_VALUE *, data))) + +#define lh_CONF_VALUE_doall(lh, func) \ + lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), func)); + +#define lh_CONF_VALUE_doall_arg(lh, func, arg) \ + lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(CONF_VALUE) *, lh), \ + CHECKED_CAST(void (*)(void *, void *), \ + void (*)(CONF_VALUE *, void *), func), \ + arg); + +/* SSL_SESSION */ +#define lh_SSL_SESSION_new(hash, comp) \ + ((LHASH_OF(SSL_SESSION) *)lh_new( \ + CHECKED_CAST(lhash_hash_func, uint32_t (*)(const SSL_SESSION *), hash), \ + CHECKED_CAST(lhash_cmp_func, \ + int (*)(const SSL_SESSION *a, const SSL_SESSION *b), \ + comp))) + +#define lh_SSL_SESSION_free(lh) \ + lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh)); + +#define lh_SSL_SESSION_num_items(lh) \ + lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh)) + +#define lh_SSL_SESSION_retrieve(lh, data) \ + ((SSL_SESSION *)lh_retrieve( \ + CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void *, SSL_SESSION *, data))) + +#define lh_SSL_SESSION_insert(lh, old_data, data) \ + lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void **, SSL_SESSION **, old_data), \ + CHECKED_CAST(void *, SSL_SESSION *, data)) + +#define lh_SSL_SESSION_delete(lh, data) \ + ((SSL_SESSION *)lh_delete( \ + CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void *, SSL_SESSION *, data))) + +#define lh_SSL_SESSION_doall(lh, func) \ + lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_SESSION *), func)); + +#define lh_SSL_SESSION_doall_arg(lh, func, arg) \ + lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(SSL_SESSION) *, lh), \ + CHECKED_CAST(void (*)(void *, void *), \ + void (*)(SSL_SESSION *, void *), func), \ + arg); diff --git a/TMessagesProj/jni/boringssl/include/openssl/md5.h b/TMessagesProj/jni/boringssl/include/openssl/md5.h new file mode 100644 index 00000000..9b139222 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/md5.h @@ -0,0 +1,107 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_MD5_H +#define OPENSSL_HEADER_MD5_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* MD5. */ + + +/* MD5_CBLOCK is the block size of MD5. */ +#define MD5_CBLOCK 64 + +/* MD5_DIGEST_LENGTH is the length of an MD5 digest. */ +#define MD5_DIGEST_LENGTH 16 + +/* MD5_Init initialises |md5| and returns one. */ +OPENSSL_EXPORT int MD5_Init(MD5_CTX *md5); + +/* MD5_Update adds |len| bytes from |data| to |md5| and returns one. */ +OPENSSL_EXPORT int MD5_Update(MD5_CTX *md5, const void *data, size_t len); + +/* MD5_Final adds the final padding to |md5| and writes the resulting digest to + * |md|, which must have at least |MD5_DIGEST_LENGTH| bytes of space. It + * returns one. */ +OPENSSL_EXPORT int MD5_Final(uint8_t *md, MD5_CTX *md5); + +/* MD5 writes the digest of |len| bytes from |data| to |out| and returns |out|. + * There must be at least |MD5_DIGEST_LENGTH| bytes of space in |out|. */ +OPENSSL_EXPORT uint8_t *MD5(const uint8_t *data, size_t len, uint8_t *out); + +/* MD5_Transform is a low-level function that performs a single, MD5 block + * transformation using the state from |md5| and 64 bytes from |block|. */ +OPENSSL_EXPORT void MD5_Transform(MD5_CTX *md5, const uint8_t *block); + +struct md5_state_st { + uint32_t A, B, C, D; + uint32_t Nl, Nh; + uint32_t data[16]; + unsigned int num; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_MD5_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/mem.h b/TMessagesProj/jni/boringssl/include/openssl/mem.h new file mode 100644 index 00000000..c8e2b3ef --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/mem.h @@ -0,0 +1,140 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_MEM_H +#define OPENSSL_HEADER_MEM_H + +#include + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Memory and string functions, see also buf.h. + * + * OpenSSL has, historically, had a complex set of malloc debugging options. + * However, that was written in a time before Valgrind and ASAN. Since we now + * have those tools, the OpenSSL allocation functions are simply macros around + * the standard memory functions. */ + + +#define OPENSSL_malloc malloc +#define OPENSSL_realloc realloc +#define OPENSSL_free free + +/* OPENSSL_realloc_clean acts like |realloc|, but clears the previous memory + * buffer. Because this is implemented as a wrapper around |malloc|, it needs + * to be given the size of the buffer pointed to by |ptr|. */ +void *OPENSSL_realloc_clean(void *ptr, size_t old_size, size_t new_size); + +/* OPENSSL_cleanse zeros out |len| bytes of memory at |ptr|. This is similar to + * |memset_s| from C11. */ +OPENSSL_EXPORT void OPENSSL_cleanse(void *ptr, size_t len); + +/* CRYPTO_memcmp returns zero iff the |len| bytes at |a| and |b| are equal. It + * takes an amount of time dependent on |len|, but independent of the contents + * of |a| and |b|. Unlike memcmp, it cannot be used to put elements into a + * defined order as the return value when a != b is undefined, other than to be + * non-zero. */ +OPENSSL_EXPORT int CRYPTO_memcmp(const void *a, const void *b, size_t len); + +/* OPENSSL_hash32 implements the 32 bit, FNV-1a hash. */ +OPENSSL_EXPORT uint32_t OPENSSL_hash32(const void *ptr, size_t len); + +/* OPENSSL_strdup has the same behaviour as strdup(3). */ +OPENSSL_EXPORT char *OPENSSL_strdup(const char *s); + +/* OPENSSL_strnlen has the same behaviour as strnlen(3). */ +OPENSSL_EXPORT size_t OPENSSL_strnlen(const char *s, size_t len); + +/* OPENSSL_strcasecmp has the same behaviour as strcasecmp(3). */ +OPENSSL_EXPORT int OPENSSL_strcasecmp(const char *a, const char *b); + +/* OPENSSL_strncasecmp has the same behaviour as strncasecmp(3). */ +OPENSSL_EXPORT int OPENSSL_strncasecmp(const char *a, const char *b, size_t n); + +/* DECIMAL_SIZE returns an upper bound for the length of the decimal + * representation of the given type. */ +#define DECIMAL_SIZE(type) ((sizeof(type)*8+2)/3+1) + +/* Printf functions. + * + * These functions are either OpenSSL wrappers for standard functions (i.e. + * |BIO_snprintf| and |BIO_vsnprintf|) which don't exist in C89, or are + * versions of printf functions that output to a BIO rather than a FILE. */ +#ifdef __GNUC__ +#define __bio_h__attr__ __attribute__ +#else +#define __bio_h__attr__(x) +#endif +OPENSSL_EXPORT int BIO_snprintf(char *buf, size_t n, const char *format, ...) + __bio_h__attr__((__format__(__printf__, 3, 4))); + +OPENSSL_EXPORT int BIO_vsnprintf(char *buf, size_t n, const char *format, + va_list args) + __bio_h__attr__((__format__(__printf__, 3, 0))); +#undef __bio_h__attr__ + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_MEM_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/modes.h b/TMessagesProj/jni/boringssl/include/openssl/modes.h new file mode 100644 index 00000000..220adec5 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/modes.h @@ -0,0 +1,223 @@ +/* ==================================================================== + * Copyright (c) 2008 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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. + * ==================================================================== */ + +#ifndef OPENSSL_HEADER_MODES_H +#define OPENSSL_HEADER_MODES_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* modes.h contains functions that implement various block-cipher modes. */ + + +/* block128_f is the type of a 128-bit, block cipher. */ +typedef void (*block128_f)(const uint8_t in[16], uint8_t out[16], + const void *key); + + +/* CTR. */ + +/* ctr128_f is the type of a function that performs CTR-mode encryption. */ +typedef void (*ctr128_f)(const uint8_t *in, uint8_t *out, size_t blocks, + const void *key, const uint8_t ivec[16]); + +/* CRYPTO_ctr128_encrypt encrypts (or decrypts, it's the same in CTR mode) + * |len| bytes from |in| to |out| using |block| in counter mode. There's no + * requirement that |len| be a multiple of any value and any partial blocks are + * stored in |ecount_buf| and |*num|, which must be zeroed before the initial + * call. The counter is a 128-bit, big-endian value in |ivec| and is + * incremented by this function. */ +OPENSSL_EXPORT void CRYPTO_ctr128_encrypt(const uint8_t *in, uint8_t *out, + size_t len, const void *key, + uint8_t ivec[16], + uint8_t ecount_buf[16], + unsigned int *num, block128_f block); + +/* CRYPTO_ctr128_encrypt_ctr32 acts like |CRYPTO_ctr128_encrypt| but takes + * |ctr|, a function that performs CTR mode but only deals with the lower 32 + * bits of the counter. This is useful when |ctr| can be an optimised + * function. */ +OPENSSL_EXPORT void CRYPTO_ctr128_encrypt_ctr32( + const uint8_t *in, uint8_t *out, size_t len, const void *key, + uint8_t ivec[16], uint8_t ecount_buf[16], unsigned int *num, ctr128_f ctr); + + +/* GCM. */ + +typedef struct gcm128_context GCM128_CONTEXT; + +/* CRYPTO_gcm128_new allocates a fresh |GCM128_CONTEXT| and calls + * |CRYPTO_gcm128_init|. It returns the new context, or NULL on error. */ +OPENSSL_EXPORT GCM128_CONTEXT *CRYPTO_gcm128_new(void *key, block128_f block); + +/* CRYPTO_gcm128_init initialises |ctx| to use |block| (typically AES) with the + * given key. */ +OPENSSL_EXPORT void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, void *key, + block128_f block); + +/* CRYPTO_gcm128_setiv sets the IV (nonce) for |ctx|. */ +OPENSSL_EXPORT void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const uint8_t *iv, + size_t len); + +/* CRYPTO_gcm128_aad sets the authenticated data for an instance of GCM. This + * must be called before and data is encrypted. It returns one on success and + * zero otherwise. */ +OPENSSL_EXPORT int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, + size_t len); + +/* CRYPTO_gcm128_encrypt encrypts |len| bytes from |in| to |out|. It returns + * one on success and zero otherwise. */ +OPENSSL_EXPORT int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const uint8_t *in, + uint8_t *out, size_t len); + +/* CRYPTO_gcm128_decrypt decrypts |len| bytes from |in| to |out|. It returns + * one on success and zero otherwise. */ +OPENSSL_EXPORT int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const uint8_t *in, + uint8_t *out, size_t len); + +/* CRYPTO_gcm128_encrypt_ctr32 encrypts |len| bytes from |in| to |out| using a + * CTR function that only handles the bottom 32 bits of the nonce, like + * |CRYPTO_ctr128_encrypt_ctr32|. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, + const uint8_t *in, uint8_t *out, + size_t len, ctr128_f stream); + +/* CRYPTO_gcm128_decrypt_ctr32 decrypts |len| bytes from |in| to |out| using a + * CTR function that only handles the bottom 32 bits of the nonce, like + * |CRYPTO_ctr128_encrypt_ctr32|. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, + const uint8_t *in, uint8_t *out, + size_t len, ctr128_f stream); + +/* CRYPTO_gcm128_finish calculates the authenticator and compares it against + * |len| bytes of |tag|. It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const uint8_t *tag, + size_t len); + +/* CRYPTO_gcm128_tag calculates the authenticator and copies it into |tag|. The + * minimum of |len| and 16 bytes are copied into |tag|. */ +OPENSSL_EXPORT void CRYPTO_gcm128_tag(GCM128_CONTEXT *ctx, uint8_t *tag, + size_t len); + +/* CRYPTO_gcm128_release clears and frees |ctx|. */ +OPENSSL_EXPORT void CRYPTO_gcm128_release(GCM128_CONTEXT *ctx); + + +/* CBC. */ + +/* cbc128_f is the type of a function that performs CBC-mode encryption. */ +typedef void (*cbc128_f)(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], int enc); + +/* CRYPTO_cbc128_encrypt encrypts |len| bytes from |in| to |out| using the + * given IV and block cipher in CBC mode. The input need not be a multiple of + * 128 bits long, but the output will round up to the nearest 128 bit multiple, + * zero padding the input if needed. The IV will be updated on return. */ +void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], block128_f block); + +/* CRYPTO_cbc128_decrypt decrypts |len| bytes from |in| to |out| using the + * given IV and block cipher in CBC mode. If |len| is not a multiple of 128 + * bits then only that many bytes will be written, but a multiple of 128 bits + * is always read from |in|. The IV will be updated on return. */ +void CRYPTO_cbc128_decrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], block128_f block); + + +/* OFB. */ + +/* CRYPTO_ofb128_encrypt encrypts (or decrypts, it's the same with OFB mode) + * |len| bytes from |in| to |out| using |block| in OFB mode. There's no + * requirement that |len| be a multiple of any value and any partial blocks are + * stored in |ivec| and |*num|, the latter must be zero before the initial + * call. */ +void CRYPTO_ofb128_encrypt(const uint8_t *in, uint8_t *out, + size_t len, const void *key, uint8_t ivec[16], + int *num, block128_f block); + + +/* CFB. */ + +/* CRYPTO_cfb128_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes + * from |in| to |out| using |block| in CFB mode. There's no requirement that + * |len| be a multiple of any value and any partial blocks are stored in |ivec| + * and |*num|, the latter must be zero before the initial call. */ +void CRYPTO_cfb128_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], int *num, int enc, + block128_f block); + +/* CRYPTO_cfb128_8_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes + * from |in| to |out| using |block| in CFB-8 mode. Prior to the first call + * |num| should be set to zero. */ +void CRYPTO_cfb128_8_encrypt(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], int *num, + int enc, block128_f block); + +/* CRYPTO_cfb128_1_encrypt encrypts (or decrypts, if |enc| is zero) |len| bytes + * from |in| to |out| using |block| in CFB-1 mode. Prior to the first call + * |num| should be set to zero. */ +void CRYPTO_cfb128_1_encrypt(const uint8_t *in, uint8_t *out, size_t bits, + const void *key, uint8_t ivec[16], int *num, + int enc, block128_f block); + +size_t CRYPTO_cts128_encrypt_block(const uint8_t *in, uint8_t *out, size_t len, + const void *key, uint8_t ivec[16], + block128_f block); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_MODES_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/obj.h b/TMessagesProj/jni/boringssl/include/openssl/obj.h new file mode 100644 index 00000000..0c7ae60b --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/obj.h @@ -0,0 +1,198 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_OBJECTS_H +#define OPENSSL_HEADER_OBJECTS_H + +#include + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* The objects library deals with the registration and indexing of ASN.1 object + * identifiers. These values are often written as a dotted sequence of numbers, + * e.g. 1.2.840.113549.1.9.16.3.9. + * + * Internally, OpenSSL likes to deal with these values by numbering them with + * numbers called "nids". OpenSSL has a large, built-in database of common + * object identifiers and also has both short and long names for them. + * + * This library provides functions for translating between object identifiers, + * nids, short names and long names. + * + * The nid values should not be used outside of a single process: they are not + * stable identifiers. */ + + +/* Basic operations. */ + +/* OBJ_dup returns a duplicate copy of |obj| or NULL on allocation failure. */ +OPENSSL_EXPORT ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *obj); + +/* OBJ_cmp returns a value less than, equal to or greater than zero if |a| is + * less than, equal to or greater than |b|, respectively. */ +OPENSSL_EXPORT int OBJ_cmp(const ASN1_OBJECT *a, const ASN1_OBJECT *b); + + +/* Looking up nids. */ + +/* OBJ_obj2nid returns the nid corresponding to |obj|, or |NID_undef| if no + * such object is known. */ +OPENSSL_EXPORT int OBJ_obj2nid(const ASN1_OBJECT *obj); + +/* OBJ_cbs2nid returns the nid corresponding to the DER data in |cbs|, or + * |NID_undef| if no such object is known. */ +OPENSSL_EXPORT int OBJ_cbs2nid(const CBS *cbs); + +/* OBJ_sn2nid returns the nid corresponding to |short_name|, or |NID_undef| if + * no such short name is known. */ +OPENSSL_EXPORT int OBJ_sn2nid(const char *short_name); + +/* OBJ_ln2nid returns the nid corresponding to |long_name|, or |NID_undef| if + * no such long name is known. */ +OPENSSL_EXPORT int OBJ_ln2nid(const char *long_name); + +/* OBJ_txt2nid returns the nid corresponding to |s|, which may be a short name, + * long name, or an ASCII string containing a dotted sequence of numbers. It + * returns the nid or NID_undef if unknown. */ +OPENSSL_EXPORT int OBJ_txt2nid(const char *s); + + +/* Getting information about nids. */ + +/* OBJ_nid2obj returns the ASN1_OBJECT corresponding to |nid|, or NULL if |nid| + * is unknown. */ +OPENSSL_EXPORT const ASN1_OBJECT *OBJ_nid2obj(int nid); + +/* OBJ_nid2sn returns the short name for |nid|, or NULL if |nid| is unknown. */ +OPENSSL_EXPORT const char *OBJ_nid2sn(int nid); + +/* OBJ_nid2sn returns the long name for |nid|, or NULL if |nid| is unknown. */ +OPENSSL_EXPORT const char *OBJ_nid2ln(int nid); + +/* OBJ_nid2cbb writes |nid| as an ASN.1 OBJECT IDENTIFIER to |out|. It returns + * one on success or zero otherwise. */ +OPENSSL_EXPORT int OBJ_nid2cbb(CBB *out, int nid); + + +/* Dealing with textual representations of object identifiers. */ + +/* OBJ_txt2obj returns an ASN1_OBJECT for the textual respresentation in |s|. + * If |dont_search_names| is zero, then |s| will be matched against the long + * and short names of a known objects to find a match. Otherwise |s| must + * contain an ASCII string with a dotted sequence of numbers. The resulting + * object need not be previously known. It returns a freshly allocated + * |ASN1_OBJECT| or NULL on error. */ +OPENSSL_EXPORT ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names); + +/* OBJ_obj2txt converts |obj| to a textual representation. If + * |dont_return_name| is zero then |obj| will be matched against known objects + * and the long (preferably) or short name will be used if found. Otherwise + * |obj| will be converted into a dotted sequence of integers. If |out| is not + * NULL, then at most |out_len| bytes of the textual form will be written + * there. If |out_len| is at least one, then string written to |out| will + * always be NUL terminated. It returns the number of characters that could + * have been written, not including the final NUL, or -1 on error. */ +OPENSSL_EXPORT int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj, + int dont_return_name); + + +/* Adding objects at runtime. */ + +/* OBJ_create adds a known object and returns the nid of the new object, or + * NID_undef on error. */ +OPENSSL_EXPORT int OBJ_create(const char *oid, const char *short_name, + const char *long_name); + + +/* Handling signature algorithm identifiers. + * + * Some NIDs (e.g. sha256WithRSAEncryption) specify both a digest algorithm and + * a public key algorithm. The following functions map between pairs of digest + * and public-key algorithms and the NIDs that specify their combination. + * + * Sometimes the combination NID leaves the digest unspecified (e.g. + * rsassaPss). In these cases, the digest NID is |NID_undef|. */ + +/* OBJ_find_sigid_algs finds the digest and public-key NIDs that correspond to + * the signing algorithm |sign_nid|. If successful, it sets |*out_digest_nid| + * and |*out_pkey_nid| and returns one. Otherwise it returns zero. Any of + * |out_digest_nid| or |out_pkey_nid| can be NULL if the caller doesn't need + * that output value. */ +OPENSSL_EXPORT int OBJ_find_sigid_algs(int sign_nid, int *out_digest_nid, + int *out_pkey_nid); + +/* OBJ_find_sigid_by_algs finds the signature NID that corresponds to the + * combination of |digest_nid| and |pkey_nid|. If success, it sets + * |*out_sign_nid| and returns one. Otherwise it returns zero. The + * |out_sign_nid| argument can be NULL if the caller only wishes to learn + * whether the combination is valid. */ +OPENSSL_EXPORT int OBJ_find_sigid_by_algs(int *out_sign_nid, int digest_nid, + int pkey_nid); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define OBJ_R_UNKNOWN_NID 100 + +#endif /* OPENSSL_HEADER_OBJECTS_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/obj_mac.h b/TMessagesProj/jni/boringssl/include/openssl/obj_mac.h new file mode 100644 index 00000000..55e1cba2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/obj_mac.h @@ -0,0 +1,4140 @@ +/* THIS FILE IS GENERATED FROM objects.txt by objects.pl via the + * following command: + * perl objects.pl objects.txt obj_mac.num ../../include/openssl/obj_mac.h */ + +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#define SN_undef "UNDEF" +#define LN_undef "undefined" +#define NID_undef 0 +#define OBJ_undef 0L + +#define SN_itu_t "ITU-T" +#define LN_itu_t "itu-t" +#define NID_itu_t 645 +#define OBJ_itu_t 0L + +#define NID_ccitt 404 +#define OBJ_ccitt OBJ_itu_t + +#define SN_iso "ISO" +#define LN_iso "iso" +#define NID_iso 181 +#define OBJ_iso 1L + +#define SN_joint_iso_itu_t "JOINT-ISO-ITU-T" +#define LN_joint_iso_itu_t "joint-iso-itu-t" +#define NID_joint_iso_itu_t 646 +#define OBJ_joint_iso_itu_t 2L + +#define NID_joint_iso_ccitt 393 +#define OBJ_joint_iso_ccitt OBJ_joint_iso_itu_t + +#define SN_member_body "member-body" +#define LN_member_body "ISO Member Body" +#define NID_member_body 182 +#define OBJ_member_body OBJ_iso,2L + +#define SN_identified_organization "identified-organization" +#define NID_identified_organization 676 +#define OBJ_identified_organization OBJ_iso,3L + +#define SN_hmac_md5 "HMAC-MD5" +#define LN_hmac_md5 "hmac-md5" +#define NID_hmac_md5 780 +#define OBJ_hmac_md5 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,1L + +#define SN_hmac_sha1 "HMAC-SHA1" +#define LN_hmac_sha1 "hmac-sha1" +#define NID_hmac_sha1 781 +#define OBJ_hmac_sha1 OBJ_identified_organization,6L,1L,5L,5L,8L,1L,2L + +#define SN_certicom_arc "certicom-arc" +#define NID_certicom_arc 677 +#define OBJ_certicom_arc OBJ_identified_organization,132L + +#define SN_international_organizations "international-organizations" +#define LN_international_organizations "International Organizations" +#define NID_international_organizations 647 +#define OBJ_international_organizations OBJ_joint_iso_itu_t,23L + +#define SN_wap "wap" +#define NID_wap 678 +#define OBJ_wap OBJ_international_organizations,43L + +#define SN_wap_wsg "wap-wsg" +#define NID_wap_wsg 679 +#define OBJ_wap_wsg OBJ_wap,1L + +#define SN_selected_attribute_types "selected-attribute-types" +#define LN_selected_attribute_types "Selected Attribute Types" +#define NID_selected_attribute_types 394 +#define OBJ_selected_attribute_types OBJ_joint_iso_itu_t,5L,1L,5L + +#define SN_clearance "clearance" +#define NID_clearance 395 +#define OBJ_clearance OBJ_selected_attribute_types,55L + +#define SN_ISO_US "ISO-US" +#define LN_ISO_US "ISO US Member Body" +#define NID_ISO_US 183 +#define OBJ_ISO_US OBJ_member_body,840L + +#define SN_X9_57 "X9-57" +#define LN_X9_57 "X9.57" +#define NID_X9_57 184 +#define OBJ_X9_57 OBJ_ISO_US,10040L + +#define SN_X9cm "X9cm" +#define LN_X9cm "X9.57 CM ?" +#define NID_X9cm 185 +#define OBJ_X9cm OBJ_X9_57,4L + +#define SN_dsa "DSA" +#define LN_dsa "dsaEncryption" +#define NID_dsa 116 +#define OBJ_dsa OBJ_X9cm,1L + +#define SN_dsaWithSHA1 "DSA-SHA1" +#define LN_dsaWithSHA1 "dsaWithSHA1" +#define NID_dsaWithSHA1 113 +#define OBJ_dsaWithSHA1 OBJ_X9cm,3L + +#define SN_ansi_X9_62 "ansi-X9-62" +#define LN_ansi_X9_62 "ANSI X9.62" +#define NID_ansi_X9_62 405 +#define OBJ_ansi_X9_62 OBJ_ISO_US,10045L + +#define OBJ_X9_62_id_fieldType OBJ_ansi_X9_62,1L + +#define SN_X9_62_prime_field "prime-field" +#define NID_X9_62_prime_field 406 +#define OBJ_X9_62_prime_field OBJ_X9_62_id_fieldType,1L + +#define SN_X9_62_characteristic_two_field "characteristic-two-field" +#define NID_X9_62_characteristic_two_field 407 +#define OBJ_X9_62_characteristic_two_field OBJ_X9_62_id_fieldType,2L + +#define SN_X9_62_id_characteristic_two_basis "id-characteristic-two-basis" +#define NID_X9_62_id_characteristic_two_basis 680 +#define OBJ_X9_62_id_characteristic_two_basis OBJ_X9_62_characteristic_two_field,3L + +#define SN_X9_62_onBasis "onBasis" +#define NID_X9_62_onBasis 681 +#define OBJ_X9_62_onBasis OBJ_X9_62_id_characteristic_two_basis,1L + +#define SN_X9_62_tpBasis "tpBasis" +#define NID_X9_62_tpBasis 682 +#define OBJ_X9_62_tpBasis OBJ_X9_62_id_characteristic_two_basis,2L + +#define SN_X9_62_ppBasis "ppBasis" +#define NID_X9_62_ppBasis 683 +#define OBJ_X9_62_ppBasis OBJ_X9_62_id_characteristic_two_basis,3L + +#define OBJ_X9_62_id_publicKeyType OBJ_ansi_X9_62,2L + +#define SN_X9_62_id_ecPublicKey "id-ecPublicKey" +#define NID_X9_62_id_ecPublicKey 408 +#define OBJ_X9_62_id_ecPublicKey OBJ_X9_62_id_publicKeyType,1L + +#define OBJ_X9_62_ellipticCurve OBJ_ansi_X9_62,3L + +#define OBJ_X9_62_c_TwoCurve OBJ_X9_62_ellipticCurve,0L + +#define SN_X9_62_c2pnb163v1 "c2pnb163v1" +#define NID_X9_62_c2pnb163v1 684 +#define OBJ_X9_62_c2pnb163v1 OBJ_X9_62_c_TwoCurve,1L + +#define SN_X9_62_c2pnb163v2 "c2pnb163v2" +#define NID_X9_62_c2pnb163v2 685 +#define OBJ_X9_62_c2pnb163v2 OBJ_X9_62_c_TwoCurve,2L + +#define SN_X9_62_c2pnb163v3 "c2pnb163v3" +#define NID_X9_62_c2pnb163v3 686 +#define OBJ_X9_62_c2pnb163v3 OBJ_X9_62_c_TwoCurve,3L + +#define SN_X9_62_c2pnb176v1 "c2pnb176v1" +#define NID_X9_62_c2pnb176v1 687 +#define OBJ_X9_62_c2pnb176v1 OBJ_X9_62_c_TwoCurve,4L + +#define SN_X9_62_c2tnb191v1 "c2tnb191v1" +#define NID_X9_62_c2tnb191v1 688 +#define OBJ_X9_62_c2tnb191v1 OBJ_X9_62_c_TwoCurve,5L + +#define SN_X9_62_c2tnb191v2 "c2tnb191v2" +#define NID_X9_62_c2tnb191v2 689 +#define OBJ_X9_62_c2tnb191v2 OBJ_X9_62_c_TwoCurve,6L + +#define SN_X9_62_c2tnb191v3 "c2tnb191v3" +#define NID_X9_62_c2tnb191v3 690 +#define OBJ_X9_62_c2tnb191v3 OBJ_X9_62_c_TwoCurve,7L + +#define SN_X9_62_c2onb191v4 "c2onb191v4" +#define NID_X9_62_c2onb191v4 691 +#define OBJ_X9_62_c2onb191v4 OBJ_X9_62_c_TwoCurve,8L + +#define SN_X9_62_c2onb191v5 "c2onb191v5" +#define NID_X9_62_c2onb191v5 692 +#define OBJ_X9_62_c2onb191v5 OBJ_X9_62_c_TwoCurve,9L + +#define SN_X9_62_c2pnb208w1 "c2pnb208w1" +#define NID_X9_62_c2pnb208w1 693 +#define OBJ_X9_62_c2pnb208w1 OBJ_X9_62_c_TwoCurve,10L + +#define SN_X9_62_c2tnb239v1 "c2tnb239v1" +#define NID_X9_62_c2tnb239v1 694 +#define OBJ_X9_62_c2tnb239v1 OBJ_X9_62_c_TwoCurve,11L + +#define SN_X9_62_c2tnb239v2 "c2tnb239v2" +#define NID_X9_62_c2tnb239v2 695 +#define OBJ_X9_62_c2tnb239v2 OBJ_X9_62_c_TwoCurve,12L + +#define SN_X9_62_c2tnb239v3 "c2tnb239v3" +#define NID_X9_62_c2tnb239v3 696 +#define OBJ_X9_62_c2tnb239v3 OBJ_X9_62_c_TwoCurve,13L + +#define SN_X9_62_c2onb239v4 "c2onb239v4" +#define NID_X9_62_c2onb239v4 697 +#define OBJ_X9_62_c2onb239v4 OBJ_X9_62_c_TwoCurve,14L + +#define SN_X9_62_c2onb239v5 "c2onb239v5" +#define NID_X9_62_c2onb239v5 698 +#define OBJ_X9_62_c2onb239v5 OBJ_X9_62_c_TwoCurve,15L + +#define SN_X9_62_c2pnb272w1 "c2pnb272w1" +#define NID_X9_62_c2pnb272w1 699 +#define OBJ_X9_62_c2pnb272w1 OBJ_X9_62_c_TwoCurve,16L + +#define SN_X9_62_c2pnb304w1 "c2pnb304w1" +#define NID_X9_62_c2pnb304w1 700 +#define OBJ_X9_62_c2pnb304w1 OBJ_X9_62_c_TwoCurve,17L + +#define SN_X9_62_c2tnb359v1 "c2tnb359v1" +#define NID_X9_62_c2tnb359v1 701 +#define OBJ_X9_62_c2tnb359v1 OBJ_X9_62_c_TwoCurve,18L + +#define SN_X9_62_c2pnb368w1 "c2pnb368w1" +#define NID_X9_62_c2pnb368w1 702 +#define OBJ_X9_62_c2pnb368w1 OBJ_X9_62_c_TwoCurve,19L + +#define SN_X9_62_c2tnb431r1 "c2tnb431r1" +#define NID_X9_62_c2tnb431r1 703 +#define OBJ_X9_62_c2tnb431r1 OBJ_X9_62_c_TwoCurve,20L + +#define OBJ_X9_62_primeCurve OBJ_X9_62_ellipticCurve,1L + +#define SN_X9_62_prime192v1 "prime192v1" +#define NID_X9_62_prime192v1 409 +#define OBJ_X9_62_prime192v1 OBJ_X9_62_primeCurve,1L + +#define SN_X9_62_prime192v2 "prime192v2" +#define NID_X9_62_prime192v2 410 +#define OBJ_X9_62_prime192v2 OBJ_X9_62_primeCurve,2L + +#define SN_X9_62_prime192v3 "prime192v3" +#define NID_X9_62_prime192v3 411 +#define OBJ_X9_62_prime192v3 OBJ_X9_62_primeCurve,3L + +#define SN_X9_62_prime239v1 "prime239v1" +#define NID_X9_62_prime239v1 412 +#define OBJ_X9_62_prime239v1 OBJ_X9_62_primeCurve,4L + +#define SN_X9_62_prime239v2 "prime239v2" +#define NID_X9_62_prime239v2 413 +#define OBJ_X9_62_prime239v2 OBJ_X9_62_primeCurve,5L + +#define SN_X9_62_prime239v3 "prime239v3" +#define NID_X9_62_prime239v3 414 +#define OBJ_X9_62_prime239v3 OBJ_X9_62_primeCurve,6L + +#define SN_X9_62_prime256v1 "prime256v1" +#define NID_X9_62_prime256v1 415 +#define OBJ_X9_62_prime256v1 OBJ_X9_62_primeCurve,7L + +#define OBJ_X9_62_id_ecSigType OBJ_ansi_X9_62,4L + +#define SN_ecdsa_with_SHA1 "ecdsa-with-SHA1" +#define NID_ecdsa_with_SHA1 416 +#define OBJ_ecdsa_with_SHA1 OBJ_X9_62_id_ecSigType,1L + +#define SN_ecdsa_with_Recommended "ecdsa-with-Recommended" +#define NID_ecdsa_with_Recommended 791 +#define OBJ_ecdsa_with_Recommended OBJ_X9_62_id_ecSigType,2L + +#define SN_ecdsa_with_Specified "ecdsa-with-Specified" +#define NID_ecdsa_with_Specified 792 +#define OBJ_ecdsa_with_Specified OBJ_X9_62_id_ecSigType,3L + +#define SN_ecdsa_with_SHA224 "ecdsa-with-SHA224" +#define NID_ecdsa_with_SHA224 793 +#define OBJ_ecdsa_with_SHA224 OBJ_ecdsa_with_Specified,1L + +#define SN_ecdsa_with_SHA256 "ecdsa-with-SHA256" +#define NID_ecdsa_with_SHA256 794 +#define OBJ_ecdsa_with_SHA256 OBJ_ecdsa_with_Specified,2L + +#define SN_ecdsa_with_SHA384 "ecdsa-with-SHA384" +#define NID_ecdsa_with_SHA384 795 +#define OBJ_ecdsa_with_SHA384 OBJ_ecdsa_with_Specified,3L + +#define SN_ecdsa_with_SHA512 "ecdsa-with-SHA512" +#define NID_ecdsa_with_SHA512 796 +#define OBJ_ecdsa_with_SHA512 OBJ_ecdsa_with_Specified,4L + +#define OBJ_secg_ellipticCurve OBJ_certicom_arc,0L + +#define SN_secp112r1 "secp112r1" +#define NID_secp112r1 704 +#define OBJ_secp112r1 OBJ_secg_ellipticCurve,6L + +#define SN_secp112r2 "secp112r2" +#define NID_secp112r2 705 +#define OBJ_secp112r2 OBJ_secg_ellipticCurve,7L + +#define SN_secp128r1 "secp128r1" +#define NID_secp128r1 706 +#define OBJ_secp128r1 OBJ_secg_ellipticCurve,28L + +#define SN_secp128r2 "secp128r2" +#define NID_secp128r2 707 +#define OBJ_secp128r2 OBJ_secg_ellipticCurve,29L + +#define SN_secp160k1 "secp160k1" +#define NID_secp160k1 708 +#define OBJ_secp160k1 OBJ_secg_ellipticCurve,9L + +#define SN_secp160r1 "secp160r1" +#define NID_secp160r1 709 +#define OBJ_secp160r1 OBJ_secg_ellipticCurve,8L + +#define SN_secp160r2 "secp160r2" +#define NID_secp160r2 710 +#define OBJ_secp160r2 OBJ_secg_ellipticCurve,30L + +#define SN_secp192k1 "secp192k1" +#define NID_secp192k1 711 +#define OBJ_secp192k1 OBJ_secg_ellipticCurve,31L + +#define SN_secp224k1 "secp224k1" +#define NID_secp224k1 712 +#define OBJ_secp224k1 OBJ_secg_ellipticCurve,32L + +#define SN_secp224r1 "secp224r1" +#define NID_secp224r1 713 +#define OBJ_secp224r1 OBJ_secg_ellipticCurve,33L + +#define SN_secp256k1 "secp256k1" +#define NID_secp256k1 714 +#define OBJ_secp256k1 OBJ_secg_ellipticCurve,10L + +#define SN_secp384r1 "secp384r1" +#define NID_secp384r1 715 +#define OBJ_secp384r1 OBJ_secg_ellipticCurve,34L + +#define SN_secp521r1 "secp521r1" +#define NID_secp521r1 716 +#define OBJ_secp521r1 OBJ_secg_ellipticCurve,35L + +#define SN_sect113r1 "sect113r1" +#define NID_sect113r1 717 +#define OBJ_sect113r1 OBJ_secg_ellipticCurve,4L + +#define SN_sect113r2 "sect113r2" +#define NID_sect113r2 718 +#define OBJ_sect113r2 OBJ_secg_ellipticCurve,5L + +#define SN_sect131r1 "sect131r1" +#define NID_sect131r1 719 +#define OBJ_sect131r1 OBJ_secg_ellipticCurve,22L + +#define SN_sect131r2 "sect131r2" +#define NID_sect131r2 720 +#define OBJ_sect131r2 OBJ_secg_ellipticCurve,23L + +#define SN_sect163k1 "sect163k1" +#define NID_sect163k1 721 +#define OBJ_sect163k1 OBJ_secg_ellipticCurve,1L + +#define SN_sect163r1 "sect163r1" +#define NID_sect163r1 722 +#define OBJ_sect163r1 OBJ_secg_ellipticCurve,2L + +#define SN_sect163r2 "sect163r2" +#define NID_sect163r2 723 +#define OBJ_sect163r2 OBJ_secg_ellipticCurve,15L + +#define SN_sect193r1 "sect193r1" +#define NID_sect193r1 724 +#define OBJ_sect193r1 OBJ_secg_ellipticCurve,24L + +#define SN_sect193r2 "sect193r2" +#define NID_sect193r2 725 +#define OBJ_sect193r2 OBJ_secg_ellipticCurve,25L + +#define SN_sect233k1 "sect233k1" +#define NID_sect233k1 726 +#define OBJ_sect233k1 OBJ_secg_ellipticCurve,26L + +#define SN_sect233r1 "sect233r1" +#define NID_sect233r1 727 +#define OBJ_sect233r1 OBJ_secg_ellipticCurve,27L + +#define SN_sect239k1 "sect239k1" +#define NID_sect239k1 728 +#define OBJ_sect239k1 OBJ_secg_ellipticCurve,3L + +#define SN_sect283k1 "sect283k1" +#define NID_sect283k1 729 +#define OBJ_sect283k1 OBJ_secg_ellipticCurve,16L + +#define SN_sect283r1 "sect283r1" +#define NID_sect283r1 730 +#define OBJ_sect283r1 OBJ_secg_ellipticCurve,17L + +#define SN_sect409k1 "sect409k1" +#define NID_sect409k1 731 +#define OBJ_sect409k1 OBJ_secg_ellipticCurve,36L + +#define SN_sect409r1 "sect409r1" +#define NID_sect409r1 732 +#define OBJ_sect409r1 OBJ_secg_ellipticCurve,37L + +#define SN_sect571k1 "sect571k1" +#define NID_sect571k1 733 +#define OBJ_sect571k1 OBJ_secg_ellipticCurve,38L + +#define SN_sect571r1 "sect571r1" +#define NID_sect571r1 734 +#define OBJ_sect571r1 OBJ_secg_ellipticCurve,39L + +#define OBJ_wap_wsg_idm_ecid OBJ_wap_wsg,4L + +#define SN_wap_wsg_idm_ecid_wtls1 "wap-wsg-idm-ecid-wtls1" +#define NID_wap_wsg_idm_ecid_wtls1 735 +#define OBJ_wap_wsg_idm_ecid_wtls1 OBJ_wap_wsg_idm_ecid,1L + +#define SN_wap_wsg_idm_ecid_wtls3 "wap-wsg-idm-ecid-wtls3" +#define NID_wap_wsg_idm_ecid_wtls3 736 +#define OBJ_wap_wsg_idm_ecid_wtls3 OBJ_wap_wsg_idm_ecid,3L + +#define SN_wap_wsg_idm_ecid_wtls4 "wap-wsg-idm-ecid-wtls4" +#define NID_wap_wsg_idm_ecid_wtls4 737 +#define OBJ_wap_wsg_idm_ecid_wtls4 OBJ_wap_wsg_idm_ecid,4L + +#define SN_wap_wsg_idm_ecid_wtls5 "wap-wsg-idm-ecid-wtls5" +#define NID_wap_wsg_idm_ecid_wtls5 738 +#define OBJ_wap_wsg_idm_ecid_wtls5 OBJ_wap_wsg_idm_ecid,5L + +#define SN_wap_wsg_idm_ecid_wtls6 "wap-wsg-idm-ecid-wtls6" +#define NID_wap_wsg_idm_ecid_wtls6 739 +#define OBJ_wap_wsg_idm_ecid_wtls6 OBJ_wap_wsg_idm_ecid,6L + +#define SN_wap_wsg_idm_ecid_wtls7 "wap-wsg-idm-ecid-wtls7" +#define NID_wap_wsg_idm_ecid_wtls7 740 +#define OBJ_wap_wsg_idm_ecid_wtls7 OBJ_wap_wsg_idm_ecid,7L + +#define SN_wap_wsg_idm_ecid_wtls8 "wap-wsg-idm-ecid-wtls8" +#define NID_wap_wsg_idm_ecid_wtls8 741 +#define OBJ_wap_wsg_idm_ecid_wtls8 OBJ_wap_wsg_idm_ecid,8L + +#define SN_wap_wsg_idm_ecid_wtls9 "wap-wsg-idm-ecid-wtls9" +#define NID_wap_wsg_idm_ecid_wtls9 742 +#define OBJ_wap_wsg_idm_ecid_wtls9 OBJ_wap_wsg_idm_ecid,9L + +#define SN_wap_wsg_idm_ecid_wtls10 "wap-wsg-idm-ecid-wtls10" +#define NID_wap_wsg_idm_ecid_wtls10 743 +#define OBJ_wap_wsg_idm_ecid_wtls10 OBJ_wap_wsg_idm_ecid,10L + +#define SN_wap_wsg_idm_ecid_wtls11 "wap-wsg-idm-ecid-wtls11" +#define NID_wap_wsg_idm_ecid_wtls11 744 +#define OBJ_wap_wsg_idm_ecid_wtls11 OBJ_wap_wsg_idm_ecid,11L + +#define SN_wap_wsg_idm_ecid_wtls12 "wap-wsg-idm-ecid-wtls12" +#define NID_wap_wsg_idm_ecid_wtls12 745 +#define OBJ_wap_wsg_idm_ecid_wtls12 OBJ_wap_wsg_idm_ecid,12L + +#define SN_cast5_cbc "CAST5-CBC" +#define LN_cast5_cbc "cast5-cbc" +#define NID_cast5_cbc 108 +#define OBJ_cast5_cbc OBJ_ISO_US,113533L,7L,66L,10L + +#define SN_cast5_ecb "CAST5-ECB" +#define LN_cast5_ecb "cast5-ecb" +#define NID_cast5_ecb 109 + +#define SN_cast5_cfb64 "CAST5-CFB" +#define LN_cast5_cfb64 "cast5-cfb" +#define NID_cast5_cfb64 110 + +#define SN_cast5_ofb64 "CAST5-OFB" +#define LN_cast5_ofb64 "cast5-ofb" +#define NID_cast5_ofb64 111 + +#define LN_pbeWithMD5AndCast5_CBC "pbeWithMD5AndCast5CBC" +#define NID_pbeWithMD5AndCast5_CBC 112 +#define OBJ_pbeWithMD5AndCast5_CBC OBJ_ISO_US,113533L,7L,66L,12L + +#define SN_id_PasswordBasedMAC "id-PasswordBasedMAC" +#define LN_id_PasswordBasedMAC "password based MAC" +#define NID_id_PasswordBasedMAC 782 +#define OBJ_id_PasswordBasedMAC OBJ_ISO_US,113533L,7L,66L,13L + +#define SN_id_DHBasedMac "id-DHBasedMac" +#define LN_id_DHBasedMac "Diffie-Hellman based MAC" +#define NID_id_DHBasedMac 783 +#define OBJ_id_DHBasedMac OBJ_ISO_US,113533L,7L,66L,30L + +#define SN_rsadsi "rsadsi" +#define LN_rsadsi "RSA Data Security, Inc." +#define NID_rsadsi 1 +#define OBJ_rsadsi OBJ_ISO_US,113549L + +#define SN_pkcs "pkcs" +#define LN_pkcs "RSA Data Security, Inc. PKCS" +#define NID_pkcs 2 +#define OBJ_pkcs OBJ_rsadsi,1L + +#define SN_pkcs1 "pkcs1" +#define NID_pkcs1 186 +#define OBJ_pkcs1 OBJ_pkcs,1L + +#define LN_rsaEncryption "rsaEncryption" +#define NID_rsaEncryption 6 +#define OBJ_rsaEncryption OBJ_pkcs1,1L + +#define SN_md2WithRSAEncryption "RSA-MD2" +#define LN_md2WithRSAEncryption "md2WithRSAEncryption" +#define NID_md2WithRSAEncryption 7 +#define OBJ_md2WithRSAEncryption OBJ_pkcs1,2L + +#define SN_md4WithRSAEncryption "RSA-MD4" +#define LN_md4WithRSAEncryption "md4WithRSAEncryption" +#define NID_md4WithRSAEncryption 396 +#define OBJ_md4WithRSAEncryption OBJ_pkcs1,3L + +#define SN_md5WithRSAEncryption "RSA-MD5" +#define LN_md5WithRSAEncryption "md5WithRSAEncryption" +#define NID_md5WithRSAEncryption 8 +#define OBJ_md5WithRSAEncryption OBJ_pkcs1,4L + +#define SN_sha1WithRSAEncryption "RSA-SHA1" +#define LN_sha1WithRSAEncryption "sha1WithRSAEncryption" +#define NID_sha1WithRSAEncryption 65 +#define OBJ_sha1WithRSAEncryption OBJ_pkcs1,5L + +#define SN_rsaesOaep "RSAES-OAEP" +#define LN_rsaesOaep "rsaesOaep" +#define NID_rsaesOaep 919 +#define OBJ_rsaesOaep OBJ_pkcs1,7L + +#define SN_mgf1 "MGF1" +#define LN_mgf1 "mgf1" +#define NID_mgf1 911 +#define OBJ_mgf1 OBJ_pkcs1,8L + +#define SN_pSpecified "PSPECIFIED" +#define LN_pSpecified "pSpecified" +#define NID_pSpecified 935 +#define OBJ_pSpecified OBJ_pkcs1,9L + +#define SN_rsassaPss "RSASSA-PSS" +#define LN_rsassaPss "rsassaPss" +#define NID_rsassaPss 912 +#define OBJ_rsassaPss OBJ_pkcs1,10L + +#define SN_sha256WithRSAEncryption "RSA-SHA256" +#define LN_sha256WithRSAEncryption "sha256WithRSAEncryption" +#define NID_sha256WithRSAEncryption 668 +#define OBJ_sha256WithRSAEncryption OBJ_pkcs1,11L + +#define SN_sha384WithRSAEncryption "RSA-SHA384" +#define LN_sha384WithRSAEncryption "sha384WithRSAEncryption" +#define NID_sha384WithRSAEncryption 669 +#define OBJ_sha384WithRSAEncryption OBJ_pkcs1,12L + +#define SN_sha512WithRSAEncryption "RSA-SHA512" +#define LN_sha512WithRSAEncryption "sha512WithRSAEncryption" +#define NID_sha512WithRSAEncryption 670 +#define OBJ_sha512WithRSAEncryption OBJ_pkcs1,13L + +#define SN_sha224WithRSAEncryption "RSA-SHA224" +#define LN_sha224WithRSAEncryption "sha224WithRSAEncryption" +#define NID_sha224WithRSAEncryption 671 +#define OBJ_sha224WithRSAEncryption OBJ_pkcs1,14L + +#define SN_pkcs3 "pkcs3" +#define NID_pkcs3 27 +#define OBJ_pkcs3 OBJ_pkcs,3L + +#define LN_dhKeyAgreement "dhKeyAgreement" +#define NID_dhKeyAgreement 28 +#define OBJ_dhKeyAgreement OBJ_pkcs3,1L + +#define SN_pkcs5 "pkcs5" +#define NID_pkcs5 187 +#define OBJ_pkcs5 OBJ_pkcs,5L + +#define SN_pbeWithMD2AndDES_CBC "PBE-MD2-DES" +#define LN_pbeWithMD2AndDES_CBC "pbeWithMD2AndDES-CBC" +#define NID_pbeWithMD2AndDES_CBC 9 +#define OBJ_pbeWithMD2AndDES_CBC OBJ_pkcs5,1L + +#define SN_pbeWithMD5AndDES_CBC "PBE-MD5-DES" +#define LN_pbeWithMD5AndDES_CBC "pbeWithMD5AndDES-CBC" +#define NID_pbeWithMD5AndDES_CBC 10 +#define OBJ_pbeWithMD5AndDES_CBC OBJ_pkcs5,3L + +#define SN_pbeWithMD2AndRC2_CBC "PBE-MD2-RC2-64" +#define LN_pbeWithMD2AndRC2_CBC "pbeWithMD2AndRC2-CBC" +#define NID_pbeWithMD2AndRC2_CBC 168 +#define OBJ_pbeWithMD2AndRC2_CBC OBJ_pkcs5,4L + +#define SN_pbeWithMD5AndRC2_CBC "PBE-MD5-RC2-64" +#define LN_pbeWithMD5AndRC2_CBC "pbeWithMD5AndRC2-CBC" +#define NID_pbeWithMD5AndRC2_CBC 169 +#define OBJ_pbeWithMD5AndRC2_CBC OBJ_pkcs5,6L + +#define SN_pbeWithSHA1AndDES_CBC "PBE-SHA1-DES" +#define LN_pbeWithSHA1AndDES_CBC "pbeWithSHA1AndDES-CBC" +#define NID_pbeWithSHA1AndDES_CBC 170 +#define OBJ_pbeWithSHA1AndDES_CBC OBJ_pkcs5,10L + +#define SN_pbeWithSHA1AndRC2_CBC "PBE-SHA1-RC2-64" +#define LN_pbeWithSHA1AndRC2_CBC "pbeWithSHA1AndRC2-CBC" +#define NID_pbeWithSHA1AndRC2_CBC 68 +#define OBJ_pbeWithSHA1AndRC2_CBC OBJ_pkcs5,11L + +#define LN_id_pbkdf2 "PBKDF2" +#define NID_id_pbkdf2 69 +#define OBJ_id_pbkdf2 OBJ_pkcs5,12L + +#define LN_pbes2 "PBES2" +#define NID_pbes2 161 +#define OBJ_pbes2 OBJ_pkcs5,13L + +#define LN_pbmac1 "PBMAC1" +#define NID_pbmac1 162 +#define OBJ_pbmac1 OBJ_pkcs5,14L + +#define SN_pkcs7 "pkcs7" +#define NID_pkcs7 20 +#define OBJ_pkcs7 OBJ_pkcs,7L + +#define LN_pkcs7_data "pkcs7-data" +#define NID_pkcs7_data 21 +#define OBJ_pkcs7_data OBJ_pkcs7,1L + +#define LN_pkcs7_signed "pkcs7-signedData" +#define NID_pkcs7_signed 22 +#define OBJ_pkcs7_signed OBJ_pkcs7,2L + +#define LN_pkcs7_enveloped "pkcs7-envelopedData" +#define NID_pkcs7_enveloped 23 +#define OBJ_pkcs7_enveloped OBJ_pkcs7,3L + +#define LN_pkcs7_signedAndEnveloped "pkcs7-signedAndEnvelopedData" +#define NID_pkcs7_signedAndEnveloped 24 +#define OBJ_pkcs7_signedAndEnveloped OBJ_pkcs7,4L + +#define LN_pkcs7_digest "pkcs7-digestData" +#define NID_pkcs7_digest 25 +#define OBJ_pkcs7_digest OBJ_pkcs7,5L + +#define LN_pkcs7_encrypted "pkcs7-encryptedData" +#define NID_pkcs7_encrypted 26 +#define OBJ_pkcs7_encrypted OBJ_pkcs7,6L + +#define SN_pkcs9 "pkcs9" +#define NID_pkcs9 47 +#define OBJ_pkcs9 OBJ_pkcs,9L + +#define LN_pkcs9_emailAddress "emailAddress" +#define NID_pkcs9_emailAddress 48 +#define OBJ_pkcs9_emailAddress OBJ_pkcs9,1L + +#define LN_pkcs9_unstructuredName "unstructuredName" +#define NID_pkcs9_unstructuredName 49 +#define OBJ_pkcs9_unstructuredName OBJ_pkcs9,2L + +#define LN_pkcs9_contentType "contentType" +#define NID_pkcs9_contentType 50 +#define OBJ_pkcs9_contentType OBJ_pkcs9,3L + +#define LN_pkcs9_messageDigest "messageDigest" +#define NID_pkcs9_messageDigest 51 +#define OBJ_pkcs9_messageDigest OBJ_pkcs9,4L + +#define LN_pkcs9_signingTime "signingTime" +#define NID_pkcs9_signingTime 52 +#define OBJ_pkcs9_signingTime OBJ_pkcs9,5L + +#define LN_pkcs9_countersignature "countersignature" +#define NID_pkcs9_countersignature 53 +#define OBJ_pkcs9_countersignature OBJ_pkcs9,6L + +#define LN_pkcs9_challengePassword "challengePassword" +#define NID_pkcs9_challengePassword 54 +#define OBJ_pkcs9_challengePassword OBJ_pkcs9,7L + +#define LN_pkcs9_unstructuredAddress "unstructuredAddress" +#define NID_pkcs9_unstructuredAddress 55 +#define OBJ_pkcs9_unstructuredAddress OBJ_pkcs9,8L + +#define LN_pkcs9_extCertAttributes "extendedCertificateAttributes" +#define NID_pkcs9_extCertAttributes 56 +#define OBJ_pkcs9_extCertAttributes OBJ_pkcs9,9L + +#define SN_ext_req "extReq" +#define LN_ext_req "Extension Request" +#define NID_ext_req 172 +#define OBJ_ext_req OBJ_pkcs9,14L + +#define SN_SMIMECapabilities "SMIME-CAPS" +#define LN_SMIMECapabilities "S/MIME Capabilities" +#define NID_SMIMECapabilities 167 +#define OBJ_SMIMECapabilities OBJ_pkcs9,15L + +#define SN_SMIME "SMIME" +#define LN_SMIME "S/MIME" +#define NID_SMIME 188 +#define OBJ_SMIME OBJ_pkcs9,16L + +#define SN_id_smime_mod "id-smime-mod" +#define NID_id_smime_mod 189 +#define OBJ_id_smime_mod OBJ_SMIME,0L + +#define SN_id_smime_ct "id-smime-ct" +#define NID_id_smime_ct 190 +#define OBJ_id_smime_ct OBJ_SMIME,1L + +#define SN_id_smime_aa "id-smime-aa" +#define NID_id_smime_aa 191 +#define OBJ_id_smime_aa OBJ_SMIME,2L + +#define SN_id_smime_alg "id-smime-alg" +#define NID_id_smime_alg 192 +#define OBJ_id_smime_alg OBJ_SMIME,3L + +#define SN_id_smime_cd "id-smime-cd" +#define NID_id_smime_cd 193 +#define OBJ_id_smime_cd OBJ_SMIME,4L + +#define SN_id_smime_spq "id-smime-spq" +#define NID_id_smime_spq 194 +#define OBJ_id_smime_spq OBJ_SMIME,5L + +#define SN_id_smime_cti "id-smime-cti" +#define NID_id_smime_cti 195 +#define OBJ_id_smime_cti OBJ_SMIME,6L + +#define SN_id_smime_mod_cms "id-smime-mod-cms" +#define NID_id_smime_mod_cms 196 +#define OBJ_id_smime_mod_cms OBJ_id_smime_mod,1L + +#define SN_id_smime_mod_ess "id-smime-mod-ess" +#define NID_id_smime_mod_ess 197 +#define OBJ_id_smime_mod_ess OBJ_id_smime_mod,2L + +#define SN_id_smime_mod_oid "id-smime-mod-oid" +#define NID_id_smime_mod_oid 198 +#define OBJ_id_smime_mod_oid OBJ_id_smime_mod,3L + +#define SN_id_smime_mod_msg_v3 "id-smime-mod-msg-v3" +#define NID_id_smime_mod_msg_v3 199 +#define OBJ_id_smime_mod_msg_v3 OBJ_id_smime_mod,4L + +#define SN_id_smime_mod_ets_eSignature_88 "id-smime-mod-ets-eSignature-88" +#define NID_id_smime_mod_ets_eSignature_88 200 +#define OBJ_id_smime_mod_ets_eSignature_88 OBJ_id_smime_mod,5L + +#define SN_id_smime_mod_ets_eSignature_97 "id-smime-mod-ets-eSignature-97" +#define NID_id_smime_mod_ets_eSignature_97 201 +#define OBJ_id_smime_mod_ets_eSignature_97 OBJ_id_smime_mod,6L + +#define SN_id_smime_mod_ets_eSigPolicy_88 "id-smime-mod-ets-eSigPolicy-88" +#define NID_id_smime_mod_ets_eSigPolicy_88 202 +#define OBJ_id_smime_mod_ets_eSigPolicy_88 OBJ_id_smime_mod,7L + +#define SN_id_smime_mod_ets_eSigPolicy_97 "id-smime-mod-ets-eSigPolicy-97" +#define NID_id_smime_mod_ets_eSigPolicy_97 203 +#define OBJ_id_smime_mod_ets_eSigPolicy_97 OBJ_id_smime_mod,8L + +#define SN_id_smime_ct_receipt "id-smime-ct-receipt" +#define NID_id_smime_ct_receipt 204 +#define OBJ_id_smime_ct_receipt OBJ_id_smime_ct,1L + +#define SN_id_smime_ct_authData "id-smime-ct-authData" +#define NID_id_smime_ct_authData 205 +#define OBJ_id_smime_ct_authData OBJ_id_smime_ct,2L + +#define SN_id_smime_ct_publishCert "id-smime-ct-publishCert" +#define NID_id_smime_ct_publishCert 206 +#define OBJ_id_smime_ct_publishCert OBJ_id_smime_ct,3L + +#define SN_id_smime_ct_TSTInfo "id-smime-ct-TSTInfo" +#define NID_id_smime_ct_TSTInfo 207 +#define OBJ_id_smime_ct_TSTInfo OBJ_id_smime_ct,4L + +#define SN_id_smime_ct_TDTInfo "id-smime-ct-TDTInfo" +#define NID_id_smime_ct_TDTInfo 208 +#define OBJ_id_smime_ct_TDTInfo OBJ_id_smime_ct,5L + +#define SN_id_smime_ct_contentInfo "id-smime-ct-contentInfo" +#define NID_id_smime_ct_contentInfo 209 +#define OBJ_id_smime_ct_contentInfo OBJ_id_smime_ct,6L + +#define SN_id_smime_ct_DVCSRequestData "id-smime-ct-DVCSRequestData" +#define NID_id_smime_ct_DVCSRequestData 210 +#define OBJ_id_smime_ct_DVCSRequestData OBJ_id_smime_ct,7L + +#define SN_id_smime_ct_DVCSResponseData "id-smime-ct-DVCSResponseData" +#define NID_id_smime_ct_DVCSResponseData 211 +#define OBJ_id_smime_ct_DVCSResponseData OBJ_id_smime_ct,8L + +#define SN_id_smime_ct_compressedData "id-smime-ct-compressedData" +#define NID_id_smime_ct_compressedData 786 +#define OBJ_id_smime_ct_compressedData OBJ_id_smime_ct,9L + +#define SN_id_ct_asciiTextWithCRLF "id-ct-asciiTextWithCRLF" +#define NID_id_ct_asciiTextWithCRLF 787 +#define OBJ_id_ct_asciiTextWithCRLF OBJ_id_smime_ct,27L + +#define SN_id_smime_aa_receiptRequest "id-smime-aa-receiptRequest" +#define NID_id_smime_aa_receiptRequest 212 +#define OBJ_id_smime_aa_receiptRequest OBJ_id_smime_aa,1L + +#define SN_id_smime_aa_securityLabel "id-smime-aa-securityLabel" +#define NID_id_smime_aa_securityLabel 213 +#define OBJ_id_smime_aa_securityLabel OBJ_id_smime_aa,2L + +#define SN_id_smime_aa_mlExpandHistory "id-smime-aa-mlExpandHistory" +#define NID_id_smime_aa_mlExpandHistory 214 +#define OBJ_id_smime_aa_mlExpandHistory OBJ_id_smime_aa,3L + +#define SN_id_smime_aa_contentHint "id-smime-aa-contentHint" +#define NID_id_smime_aa_contentHint 215 +#define OBJ_id_smime_aa_contentHint OBJ_id_smime_aa,4L + +#define SN_id_smime_aa_msgSigDigest "id-smime-aa-msgSigDigest" +#define NID_id_smime_aa_msgSigDigest 216 +#define OBJ_id_smime_aa_msgSigDigest OBJ_id_smime_aa,5L + +#define SN_id_smime_aa_encapContentType "id-smime-aa-encapContentType" +#define NID_id_smime_aa_encapContentType 217 +#define OBJ_id_smime_aa_encapContentType OBJ_id_smime_aa,6L + +#define SN_id_smime_aa_contentIdentifier "id-smime-aa-contentIdentifier" +#define NID_id_smime_aa_contentIdentifier 218 +#define OBJ_id_smime_aa_contentIdentifier OBJ_id_smime_aa,7L + +#define SN_id_smime_aa_macValue "id-smime-aa-macValue" +#define NID_id_smime_aa_macValue 219 +#define OBJ_id_smime_aa_macValue OBJ_id_smime_aa,8L + +#define SN_id_smime_aa_equivalentLabels "id-smime-aa-equivalentLabels" +#define NID_id_smime_aa_equivalentLabels 220 +#define OBJ_id_smime_aa_equivalentLabels OBJ_id_smime_aa,9L + +#define SN_id_smime_aa_contentReference "id-smime-aa-contentReference" +#define NID_id_smime_aa_contentReference 221 +#define OBJ_id_smime_aa_contentReference OBJ_id_smime_aa,10L + +#define SN_id_smime_aa_encrypKeyPref "id-smime-aa-encrypKeyPref" +#define NID_id_smime_aa_encrypKeyPref 222 +#define OBJ_id_smime_aa_encrypKeyPref OBJ_id_smime_aa,11L + +#define SN_id_smime_aa_signingCertificate "id-smime-aa-signingCertificate" +#define NID_id_smime_aa_signingCertificate 223 +#define OBJ_id_smime_aa_signingCertificate OBJ_id_smime_aa,12L + +#define SN_id_smime_aa_smimeEncryptCerts "id-smime-aa-smimeEncryptCerts" +#define NID_id_smime_aa_smimeEncryptCerts 224 +#define OBJ_id_smime_aa_smimeEncryptCerts OBJ_id_smime_aa,13L + +#define SN_id_smime_aa_timeStampToken "id-smime-aa-timeStampToken" +#define NID_id_smime_aa_timeStampToken 225 +#define OBJ_id_smime_aa_timeStampToken OBJ_id_smime_aa,14L + +#define SN_id_smime_aa_ets_sigPolicyId "id-smime-aa-ets-sigPolicyId" +#define NID_id_smime_aa_ets_sigPolicyId 226 +#define OBJ_id_smime_aa_ets_sigPolicyId OBJ_id_smime_aa,15L + +#define SN_id_smime_aa_ets_commitmentType "id-smime-aa-ets-commitmentType" +#define NID_id_smime_aa_ets_commitmentType 227 +#define OBJ_id_smime_aa_ets_commitmentType OBJ_id_smime_aa,16L + +#define SN_id_smime_aa_ets_signerLocation "id-smime-aa-ets-signerLocation" +#define NID_id_smime_aa_ets_signerLocation 228 +#define OBJ_id_smime_aa_ets_signerLocation OBJ_id_smime_aa,17L + +#define SN_id_smime_aa_ets_signerAttr "id-smime-aa-ets-signerAttr" +#define NID_id_smime_aa_ets_signerAttr 229 +#define OBJ_id_smime_aa_ets_signerAttr OBJ_id_smime_aa,18L + +#define SN_id_smime_aa_ets_otherSigCert "id-smime-aa-ets-otherSigCert" +#define NID_id_smime_aa_ets_otherSigCert 230 +#define OBJ_id_smime_aa_ets_otherSigCert OBJ_id_smime_aa,19L + +#define SN_id_smime_aa_ets_contentTimestamp "id-smime-aa-ets-contentTimestamp" +#define NID_id_smime_aa_ets_contentTimestamp 231 +#define OBJ_id_smime_aa_ets_contentTimestamp OBJ_id_smime_aa,20L + +#define SN_id_smime_aa_ets_CertificateRefs "id-smime-aa-ets-CertificateRefs" +#define NID_id_smime_aa_ets_CertificateRefs 232 +#define OBJ_id_smime_aa_ets_CertificateRefs OBJ_id_smime_aa,21L + +#define SN_id_smime_aa_ets_RevocationRefs "id-smime-aa-ets-RevocationRefs" +#define NID_id_smime_aa_ets_RevocationRefs 233 +#define OBJ_id_smime_aa_ets_RevocationRefs OBJ_id_smime_aa,22L + +#define SN_id_smime_aa_ets_certValues "id-smime-aa-ets-certValues" +#define NID_id_smime_aa_ets_certValues 234 +#define OBJ_id_smime_aa_ets_certValues OBJ_id_smime_aa,23L + +#define SN_id_smime_aa_ets_revocationValues "id-smime-aa-ets-revocationValues" +#define NID_id_smime_aa_ets_revocationValues 235 +#define OBJ_id_smime_aa_ets_revocationValues OBJ_id_smime_aa,24L + +#define SN_id_smime_aa_ets_escTimeStamp "id-smime-aa-ets-escTimeStamp" +#define NID_id_smime_aa_ets_escTimeStamp 236 +#define OBJ_id_smime_aa_ets_escTimeStamp OBJ_id_smime_aa,25L + +#define SN_id_smime_aa_ets_certCRLTimestamp "id-smime-aa-ets-certCRLTimestamp" +#define NID_id_smime_aa_ets_certCRLTimestamp 237 +#define OBJ_id_smime_aa_ets_certCRLTimestamp OBJ_id_smime_aa,26L + +#define SN_id_smime_aa_ets_archiveTimeStamp "id-smime-aa-ets-archiveTimeStamp" +#define NID_id_smime_aa_ets_archiveTimeStamp 238 +#define OBJ_id_smime_aa_ets_archiveTimeStamp OBJ_id_smime_aa,27L + +#define SN_id_smime_aa_signatureType "id-smime-aa-signatureType" +#define NID_id_smime_aa_signatureType 239 +#define OBJ_id_smime_aa_signatureType OBJ_id_smime_aa,28L + +#define SN_id_smime_aa_dvcs_dvc "id-smime-aa-dvcs-dvc" +#define NID_id_smime_aa_dvcs_dvc 240 +#define OBJ_id_smime_aa_dvcs_dvc OBJ_id_smime_aa,29L + +#define SN_id_smime_alg_ESDHwith3DES "id-smime-alg-ESDHwith3DES" +#define NID_id_smime_alg_ESDHwith3DES 241 +#define OBJ_id_smime_alg_ESDHwith3DES OBJ_id_smime_alg,1L + +#define SN_id_smime_alg_ESDHwithRC2 "id-smime-alg-ESDHwithRC2" +#define NID_id_smime_alg_ESDHwithRC2 242 +#define OBJ_id_smime_alg_ESDHwithRC2 OBJ_id_smime_alg,2L + +#define SN_id_smime_alg_3DESwrap "id-smime-alg-3DESwrap" +#define NID_id_smime_alg_3DESwrap 243 +#define OBJ_id_smime_alg_3DESwrap OBJ_id_smime_alg,3L + +#define SN_id_smime_alg_RC2wrap "id-smime-alg-RC2wrap" +#define NID_id_smime_alg_RC2wrap 244 +#define OBJ_id_smime_alg_RC2wrap OBJ_id_smime_alg,4L + +#define SN_id_smime_alg_ESDH "id-smime-alg-ESDH" +#define NID_id_smime_alg_ESDH 245 +#define OBJ_id_smime_alg_ESDH OBJ_id_smime_alg,5L + +#define SN_id_smime_alg_CMS3DESwrap "id-smime-alg-CMS3DESwrap" +#define NID_id_smime_alg_CMS3DESwrap 246 +#define OBJ_id_smime_alg_CMS3DESwrap OBJ_id_smime_alg,6L + +#define SN_id_smime_alg_CMSRC2wrap "id-smime-alg-CMSRC2wrap" +#define NID_id_smime_alg_CMSRC2wrap 247 +#define OBJ_id_smime_alg_CMSRC2wrap OBJ_id_smime_alg,7L + +#define SN_id_alg_PWRI_KEK "id-alg-PWRI-KEK" +#define NID_id_alg_PWRI_KEK 893 +#define OBJ_id_alg_PWRI_KEK OBJ_id_smime_alg,9L + +#define SN_id_smime_cd_ldap "id-smime-cd-ldap" +#define NID_id_smime_cd_ldap 248 +#define OBJ_id_smime_cd_ldap OBJ_id_smime_cd,1L + +#define SN_id_smime_spq_ets_sqt_uri "id-smime-spq-ets-sqt-uri" +#define NID_id_smime_spq_ets_sqt_uri 249 +#define OBJ_id_smime_spq_ets_sqt_uri OBJ_id_smime_spq,1L + +#define SN_id_smime_spq_ets_sqt_unotice "id-smime-spq-ets-sqt-unotice" +#define NID_id_smime_spq_ets_sqt_unotice 250 +#define OBJ_id_smime_spq_ets_sqt_unotice OBJ_id_smime_spq,2L + +#define SN_id_smime_cti_ets_proofOfOrigin "id-smime-cti-ets-proofOfOrigin" +#define NID_id_smime_cti_ets_proofOfOrigin 251 +#define OBJ_id_smime_cti_ets_proofOfOrigin OBJ_id_smime_cti,1L + +#define SN_id_smime_cti_ets_proofOfReceipt "id-smime-cti-ets-proofOfReceipt" +#define NID_id_smime_cti_ets_proofOfReceipt 252 +#define OBJ_id_smime_cti_ets_proofOfReceipt OBJ_id_smime_cti,2L + +#define SN_id_smime_cti_ets_proofOfDelivery "id-smime-cti-ets-proofOfDelivery" +#define NID_id_smime_cti_ets_proofOfDelivery 253 +#define OBJ_id_smime_cti_ets_proofOfDelivery OBJ_id_smime_cti,3L + +#define SN_id_smime_cti_ets_proofOfSender "id-smime-cti-ets-proofOfSender" +#define NID_id_smime_cti_ets_proofOfSender 254 +#define OBJ_id_smime_cti_ets_proofOfSender OBJ_id_smime_cti,4L + +#define SN_id_smime_cti_ets_proofOfApproval "id-smime-cti-ets-proofOfApproval" +#define NID_id_smime_cti_ets_proofOfApproval 255 +#define OBJ_id_smime_cti_ets_proofOfApproval OBJ_id_smime_cti,5L + +#define SN_id_smime_cti_ets_proofOfCreation "id-smime-cti-ets-proofOfCreation" +#define NID_id_smime_cti_ets_proofOfCreation 256 +#define OBJ_id_smime_cti_ets_proofOfCreation OBJ_id_smime_cti,6L + +#define LN_friendlyName "friendlyName" +#define NID_friendlyName 156 +#define OBJ_friendlyName OBJ_pkcs9,20L + +#define LN_localKeyID "localKeyID" +#define NID_localKeyID 157 +#define OBJ_localKeyID OBJ_pkcs9,21L + +#define SN_ms_csp_name "CSPName" +#define LN_ms_csp_name "Microsoft CSP Name" +#define NID_ms_csp_name 417 +#define OBJ_ms_csp_name 1L,3L,6L,1L,4L,1L,311L,17L,1L + +#define SN_LocalKeySet "LocalKeySet" +#define LN_LocalKeySet "Microsoft Local Key set" +#define NID_LocalKeySet 856 +#define OBJ_LocalKeySet 1L,3L,6L,1L,4L,1L,311L,17L,2L + +#define OBJ_certTypes OBJ_pkcs9,22L + +#define LN_x509Certificate "x509Certificate" +#define NID_x509Certificate 158 +#define OBJ_x509Certificate OBJ_certTypes,1L + +#define LN_sdsiCertificate "sdsiCertificate" +#define NID_sdsiCertificate 159 +#define OBJ_sdsiCertificate OBJ_certTypes,2L + +#define OBJ_crlTypes OBJ_pkcs9,23L + +#define LN_x509Crl "x509Crl" +#define NID_x509Crl 160 +#define OBJ_x509Crl OBJ_crlTypes,1L + +#define OBJ_pkcs12 OBJ_pkcs,12L + +#define OBJ_pkcs12_pbeids OBJ_pkcs12,1L + +#define SN_pbe_WithSHA1And128BitRC4 "PBE-SHA1-RC4-128" +#define LN_pbe_WithSHA1And128BitRC4 "pbeWithSHA1And128BitRC4" +#define NID_pbe_WithSHA1And128BitRC4 144 +#define OBJ_pbe_WithSHA1And128BitRC4 OBJ_pkcs12_pbeids,1L + +#define SN_pbe_WithSHA1And40BitRC4 "PBE-SHA1-RC4-40" +#define LN_pbe_WithSHA1And40BitRC4 "pbeWithSHA1And40BitRC4" +#define NID_pbe_WithSHA1And40BitRC4 145 +#define OBJ_pbe_WithSHA1And40BitRC4 OBJ_pkcs12_pbeids,2L + +#define SN_pbe_WithSHA1And3_Key_TripleDES_CBC "PBE-SHA1-3DES" +#define LN_pbe_WithSHA1And3_Key_TripleDES_CBC "pbeWithSHA1And3-KeyTripleDES-CBC" +#define NID_pbe_WithSHA1And3_Key_TripleDES_CBC 146 +#define OBJ_pbe_WithSHA1And3_Key_TripleDES_CBC OBJ_pkcs12_pbeids,3L + +#define SN_pbe_WithSHA1And2_Key_TripleDES_CBC "PBE-SHA1-2DES" +#define LN_pbe_WithSHA1And2_Key_TripleDES_CBC "pbeWithSHA1And2-KeyTripleDES-CBC" +#define NID_pbe_WithSHA1And2_Key_TripleDES_CBC 147 +#define OBJ_pbe_WithSHA1And2_Key_TripleDES_CBC OBJ_pkcs12_pbeids,4L + +#define SN_pbe_WithSHA1And128BitRC2_CBC "PBE-SHA1-RC2-128" +#define LN_pbe_WithSHA1And128BitRC2_CBC "pbeWithSHA1And128BitRC2-CBC" +#define NID_pbe_WithSHA1And128BitRC2_CBC 148 +#define OBJ_pbe_WithSHA1And128BitRC2_CBC OBJ_pkcs12_pbeids,5L + +#define SN_pbe_WithSHA1And40BitRC2_CBC "PBE-SHA1-RC2-40" +#define LN_pbe_WithSHA1And40BitRC2_CBC "pbeWithSHA1And40BitRC2-CBC" +#define NID_pbe_WithSHA1And40BitRC2_CBC 149 +#define OBJ_pbe_WithSHA1And40BitRC2_CBC OBJ_pkcs12_pbeids,6L + +#define OBJ_pkcs12_Version1 OBJ_pkcs12,10L + +#define OBJ_pkcs12_BagIds OBJ_pkcs12_Version1,1L + +#define LN_keyBag "keyBag" +#define NID_keyBag 150 +#define OBJ_keyBag OBJ_pkcs12_BagIds,1L + +#define LN_pkcs8ShroudedKeyBag "pkcs8ShroudedKeyBag" +#define NID_pkcs8ShroudedKeyBag 151 +#define OBJ_pkcs8ShroudedKeyBag OBJ_pkcs12_BagIds,2L + +#define LN_certBag "certBag" +#define NID_certBag 152 +#define OBJ_certBag OBJ_pkcs12_BagIds,3L + +#define LN_crlBag "crlBag" +#define NID_crlBag 153 +#define OBJ_crlBag OBJ_pkcs12_BagIds,4L + +#define LN_secretBag "secretBag" +#define NID_secretBag 154 +#define OBJ_secretBag OBJ_pkcs12_BagIds,5L + +#define LN_safeContentsBag "safeContentsBag" +#define NID_safeContentsBag 155 +#define OBJ_safeContentsBag OBJ_pkcs12_BagIds,6L + +#define SN_md2 "MD2" +#define LN_md2 "md2" +#define NID_md2 3 +#define OBJ_md2 OBJ_rsadsi,2L,2L + +#define SN_md4 "MD4" +#define LN_md4 "md4" +#define NID_md4 257 +#define OBJ_md4 OBJ_rsadsi,2L,4L + +#define SN_md5 "MD5" +#define LN_md5 "md5" +#define NID_md5 4 +#define OBJ_md5 OBJ_rsadsi,2L,5L + +#define SN_md5_sha1 "MD5-SHA1" +#define LN_md5_sha1 "md5-sha1" +#define NID_md5_sha1 114 + +#define LN_hmacWithMD5 "hmacWithMD5" +#define NID_hmacWithMD5 797 +#define OBJ_hmacWithMD5 OBJ_rsadsi,2L,6L + +#define LN_hmacWithSHA1 "hmacWithSHA1" +#define NID_hmacWithSHA1 163 +#define OBJ_hmacWithSHA1 OBJ_rsadsi,2L,7L + +#define LN_hmacWithSHA224 "hmacWithSHA224" +#define NID_hmacWithSHA224 798 +#define OBJ_hmacWithSHA224 OBJ_rsadsi,2L,8L + +#define LN_hmacWithSHA256 "hmacWithSHA256" +#define NID_hmacWithSHA256 799 +#define OBJ_hmacWithSHA256 OBJ_rsadsi,2L,9L + +#define LN_hmacWithSHA384 "hmacWithSHA384" +#define NID_hmacWithSHA384 800 +#define OBJ_hmacWithSHA384 OBJ_rsadsi,2L,10L + +#define LN_hmacWithSHA512 "hmacWithSHA512" +#define NID_hmacWithSHA512 801 +#define OBJ_hmacWithSHA512 OBJ_rsadsi,2L,11L + +#define SN_rc2_cbc "RC2-CBC" +#define LN_rc2_cbc "rc2-cbc" +#define NID_rc2_cbc 37 +#define OBJ_rc2_cbc OBJ_rsadsi,3L,2L + +#define SN_rc2_ecb "RC2-ECB" +#define LN_rc2_ecb "rc2-ecb" +#define NID_rc2_ecb 38 + +#define SN_rc2_cfb64 "RC2-CFB" +#define LN_rc2_cfb64 "rc2-cfb" +#define NID_rc2_cfb64 39 + +#define SN_rc2_ofb64 "RC2-OFB" +#define LN_rc2_ofb64 "rc2-ofb" +#define NID_rc2_ofb64 40 + +#define SN_rc2_40_cbc "RC2-40-CBC" +#define LN_rc2_40_cbc "rc2-40-cbc" +#define NID_rc2_40_cbc 98 + +#define SN_rc2_64_cbc "RC2-64-CBC" +#define LN_rc2_64_cbc "rc2-64-cbc" +#define NID_rc2_64_cbc 166 + +#define SN_rc4 "RC4" +#define LN_rc4 "rc4" +#define NID_rc4 5 +#define OBJ_rc4 OBJ_rsadsi,3L,4L + +#define SN_rc4_40 "RC4-40" +#define LN_rc4_40 "rc4-40" +#define NID_rc4_40 97 + +#define SN_des_ede3_cbc "DES-EDE3-CBC" +#define LN_des_ede3_cbc "des-ede3-cbc" +#define NID_des_ede3_cbc 44 +#define OBJ_des_ede3_cbc OBJ_rsadsi,3L,7L + +#define SN_rc5_cbc "RC5-CBC" +#define LN_rc5_cbc "rc5-cbc" +#define NID_rc5_cbc 120 +#define OBJ_rc5_cbc OBJ_rsadsi,3L,8L + +#define SN_rc5_ecb "RC5-ECB" +#define LN_rc5_ecb "rc5-ecb" +#define NID_rc5_ecb 121 + +#define SN_rc5_cfb64 "RC5-CFB" +#define LN_rc5_cfb64 "rc5-cfb" +#define NID_rc5_cfb64 122 + +#define SN_rc5_ofb64 "RC5-OFB" +#define LN_rc5_ofb64 "rc5-ofb" +#define NID_rc5_ofb64 123 + +#define SN_ms_ext_req "msExtReq" +#define LN_ms_ext_req "Microsoft Extension Request" +#define NID_ms_ext_req 171 +#define OBJ_ms_ext_req 1L,3L,6L,1L,4L,1L,311L,2L,1L,14L + +#define SN_ms_code_ind "msCodeInd" +#define LN_ms_code_ind "Microsoft Individual Code Signing" +#define NID_ms_code_ind 134 +#define OBJ_ms_code_ind 1L,3L,6L,1L,4L,1L,311L,2L,1L,21L + +#define SN_ms_code_com "msCodeCom" +#define LN_ms_code_com "Microsoft Commercial Code Signing" +#define NID_ms_code_com 135 +#define OBJ_ms_code_com 1L,3L,6L,1L,4L,1L,311L,2L,1L,22L + +#define SN_ms_ctl_sign "msCTLSign" +#define LN_ms_ctl_sign "Microsoft Trust List Signing" +#define NID_ms_ctl_sign 136 +#define OBJ_ms_ctl_sign 1L,3L,6L,1L,4L,1L,311L,10L,3L,1L + +#define SN_ms_sgc "msSGC" +#define LN_ms_sgc "Microsoft Server Gated Crypto" +#define NID_ms_sgc 137 +#define OBJ_ms_sgc 1L,3L,6L,1L,4L,1L,311L,10L,3L,3L + +#define SN_ms_efs "msEFS" +#define LN_ms_efs "Microsoft Encrypted File System" +#define NID_ms_efs 138 +#define OBJ_ms_efs 1L,3L,6L,1L,4L,1L,311L,10L,3L,4L + +#define SN_ms_smartcard_login "msSmartcardLogin" +#define LN_ms_smartcard_login "Microsoft Smartcardlogin" +#define NID_ms_smartcard_login 648 +#define OBJ_ms_smartcard_login 1L,3L,6L,1L,4L,1L,311L,20L,2L,2L + +#define SN_ms_upn "msUPN" +#define LN_ms_upn "Microsoft Universal Principal Name" +#define NID_ms_upn 649 +#define OBJ_ms_upn 1L,3L,6L,1L,4L,1L,311L,20L,2L,3L + +#define SN_idea_cbc "IDEA-CBC" +#define LN_idea_cbc "idea-cbc" +#define NID_idea_cbc 34 +#define OBJ_idea_cbc 1L,3L,6L,1L,4L,1L,188L,7L,1L,1L,2L + +#define SN_idea_ecb "IDEA-ECB" +#define LN_idea_ecb "idea-ecb" +#define NID_idea_ecb 36 + +#define SN_idea_cfb64 "IDEA-CFB" +#define LN_idea_cfb64 "idea-cfb" +#define NID_idea_cfb64 35 + +#define SN_idea_ofb64 "IDEA-OFB" +#define LN_idea_ofb64 "idea-ofb" +#define NID_idea_ofb64 46 + +#define SN_bf_cbc "BF-CBC" +#define LN_bf_cbc "bf-cbc" +#define NID_bf_cbc 91 +#define OBJ_bf_cbc 1L,3L,6L,1L,4L,1L,3029L,1L,2L + +#define SN_bf_ecb "BF-ECB" +#define LN_bf_ecb "bf-ecb" +#define NID_bf_ecb 92 + +#define SN_bf_cfb64 "BF-CFB" +#define LN_bf_cfb64 "bf-cfb" +#define NID_bf_cfb64 93 + +#define SN_bf_ofb64 "BF-OFB" +#define LN_bf_ofb64 "bf-ofb" +#define NID_bf_ofb64 94 + +#define SN_id_pkix "PKIX" +#define NID_id_pkix 127 +#define OBJ_id_pkix 1L,3L,6L,1L,5L,5L,7L + +#define SN_id_pkix_mod "id-pkix-mod" +#define NID_id_pkix_mod 258 +#define OBJ_id_pkix_mod OBJ_id_pkix,0L + +#define SN_id_pe "id-pe" +#define NID_id_pe 175 +#define OBJ_id_pe OBJ_id_pkix,1L + +#define SN_id_qt "id-qt" +#define NID_id_qt 259 +#define OBJ_id_qt OBJ_id_pkix,2L + +#define SN_id_kp "id-kp" +#define NID_id_kp 128 +#define OBJ_id_kp OBJ_id_pkix,3L + +#define SN_id_it "id-it" +#define NID_id_it 260 +#define OBJ_id_it OBJ_id_pkix,4L + +#define SN_id_pkip "id-pkip" +#define NID_id_pkip 261 +#define OBJ_id_pkip OBJ_id_pkix,5L + +#define SN_id_alg "id-alg" +#define NID_id_alg 262 +#define OBJ_id_alg OBJ_id_pkix,6L + +#define SN_id_cmc "id-cmc" +#define NID_id_cmc 263 +#define OBJ_id_cmc OBJ_id_pkix,7L + +#define SN_id_on "id-on" +#define NID_id_on 264 +#define OBJ_id_on OBJ_id_pkix,8L + +#define SN_id_pda "id-pda" +#define NID_id_pda 265 +#define OBJ_id_pda OBJ_id_pkix,9L + +#define SN_id_aca "id-aca" +#define NID_id_aca 266 +#define OBJ_id_aca OBJ_id_pkix,10L + +#define SN_id_qcs "id-qcs" +#define NID_id_qcs 267 +#define OBJ_id_qcs OBJ_id_pkix,11L + +#define SN_id_cct "id-cct" +#define NID_id_cct 268 +#define OBJ_id_cct OBJ_id_pkix,12L + +#define SN_id_ppl "id-ppl" +#define NID_id_ppl 662 +#define OBJ_id_ppl OBJ_id_pkix,21L + +#define SN_id_ad "id-ad" +#define NID_id_ad 176 +#define OBJ_id_ad OBJ_id_pkix,48L + +#define SN_id_pkix1_explicit_88 "id-pkix1-explicit-88" +#define NID_id_pkix1_explicit_88 269 +#define OBJ_id_pkix1_explicit_88 OBJ_id_pkix_mod,1L + +#define SN_id_pkix1_implicit_88 "id-pkix1-implicit-88" +#define NID_id_pkix1_implicit_88 270 +#define OBJ_id_pkix1_implicit_88 OBJ_id_pkix_mod,2L + +#define SN_id_pkix1_explicit_93 "id-pkix1-explicit-93" +#define NID_id_pkix1_explicit_93 271 +#define OBJ_id_pkix1_explicit_93 OBJ_id_pkix_mod,3L + +#define SN_id_pkix1_implicit_93 "id-pkix1-implicit-93" +#define NID_id_pkix1_implicit_93 272 +#define OBJ_id_pkix1_implicit_93 OBJ_id_pkix_mod,4L + +#define SN_id_mod_crmf "id-mod-crmf" +#define NID_id_mod_crmf 273 +#define OBJ_id_mod_crmf OBJ_id_pkix_mod,5L + +#define SN_id_mod_cmc "id-mod-cmc" +#define NID_id_mod_cmc 274 +#define OBJ_id_mod_cmc OBJ_id_pkix_mod,6L + +#define SN_id_mod_kea_profile_88 "id-mod-kea-profile-88" +#define NID_id_mod_kea_profile_88 275 +#define OBJ_id_mod_kea_profile_88 OBJ_id_pkix_mod,7L + +#define SN_id_mod_kea_profile_93 "id-mod-kea-profile-93" +#define NID_id_mod_kea_profile_93 276 +#define OBJ_id_mod_kea_profile_93 OBJ_id_pkix_mod,8L + +#define SN_id_mod_cmp "id-mod-cmp" +#define NID_id_mod_cmp 277 +#define OBJ_id_mod_cmp OBJ_id_pkix_mod,9L + +#define SN_id_mod_qualified_cert_88 "id-mod-qualified-cert-88" +#define NID_id_mod_qualified_cert_88 278 +#define OBJ_id_mod_qualified_cert_88 OBJ_id_pkix_mod,10L + +#define SN_id_mod_qualified_cert_93 "id-mod-qualified-cert-93" +#define NID_id_mod_qualified_cert_93 279 +#define OBJ_id_mod_qualified_cert_93 OBJ_id_pkix_mod,11L + +#define SN_id_mod_attribute_cert "id-mod-attribute-cert" +#define NID_id_mod_attribute_cert 280 +#define OBJ_id_mod_attribute_cert OBJ_id_pkix_mod,12L + +#define SN_id_mod_timestamp_protocol "id-mod-timestamp-protocol" +#define NID_id_mod_timestamp_protocol 281 +#define OBJ_id_mod_timestamp_protocol OBJ_id_pkix_mod,13L + +#define SN_id_mod_ocsp "id-mod-ocsp" +#define NID_id_mod_ocsp 282 +#define OBJ_id_mod_ocsp OBJ_id_pkix_mod,14L + +#define SN_id_mod_dvcs "id-mod-dvcs" +#define NID_id_mod_dvcs 283 +#define OBJ_id_mod_dvcs OBJ_id_pkix_mod,15L + +#define SN_id_mod_cmp2000 "id-mod-cmp2000" +#define NID_id_mod_cmp2000 284 +#define OBJ_id_mod_cmp2000 OBJ_id_pkix_mod,16L + +#define SN_info_access "authorityInfoAccess" +#define LN_info_access "Authority Information Access" +#define NID_info_access 177 +#define OBJ_info_access OBJ_id_pe,1L + +#define SN_biometricInfo "biometricInfo" +#define LN_biometricInfo "Biometric Info" +#define NID_biometricInfo 285 +#define OBJ_biometricInfo OBJ_id_pe,2L + +#define SN_qcStatements "qcStatements" +#define NID_qcStatements 286 +#define OBJ_qcStatements OBJ_id_pe,3L + +#define SN_ac_auditEntity "ac-auditEntity" +#define NID_ac_auditEntity 287 +#define OBJ_ac_auditEntity OBJ_id_pe,4L + +#define SN_ac_targeting "ac-targeting" +#define NID_ac_targeting 288 +#define OBJ_ac_targeting OBJ_id_pe,5L + +#define SN_aaControls "aaControls" +#define NID_aaControls 289 +#define OBJ_aaControls OBJ_id_pe,6L + +#define SN_sbgp_ipAddrBlock "sbgp-ipAddrBlock" +#define NID_sbgp_ipAddrBlock 290 +#define OBJ_sbgp_ipAddrBlock OBJ_id_pe,7L + +#define SN_sbgp_autonomousSysNum "sbgp-autonomousSysNum" +#define NID_sbgp_autonomousSysNum 291 +#define OBJ_sbgp_autonomousSysNum OBJ_id_pe,8L + +#define SN_sbgp_routerIdentifier "sbgp-routerIdentifier" +#define NID_sbgp_routerIdentifier 292 +#define OBJ_sbgp_routerIdentifier OBJ_id_pe,9L + +#define SN_ac_proxying "ac-proxying" +#define NID_ac_proxying 397 +#define OBJ_ac_proxying OBJ_id_pe,10L + +#define SN_sinfo_access "subjectInfoAccess" +#define LN_sinfo_access "Subject Information Access" +#define NID_sinfo_access 398 +#define OBJ_sinfo_access OBJ_id_pe,11L + +#define SN_proxyCertInfo "proxyCertInfo" +#define LN_proxyCertInfo "Proxy Certificate Information" +#define NID_proxyCertInfo 663 +#define OBJ_proxyCertInfo OBJ_id_pe,14L + +#define SN_id_qt_cps "id-qt-cps" +#define LN_id_qt_cps "Policy Qualifier CPS" +#define NID_id_qt_cps 164 +#define OBJ_id_qt_cps OBJ_id_qt,1L + +#define SN_id_qt_unotice "id-qt-unotice" +#define LN_id_qt_unotice "Policy Qualifier User Notice" +#define NID_id_qt_unotice 165 +#define OBJ_id_qt_unotice OBJ_id_qt,2L + +#define SN_textNotice "textNotice" +#define NID_textNotice 293 +#define OBJ_textNotice OBJ_id_qt,3L + +#define SN_server_auth "serverAuth" +#define LN_server_auth "TLS Web Server Authentication" +#define NID_server_auth 129 +#define OBJ_server_auth OBJ_id_kp,1L + +#define SN_client_auth "clientAuth" +#define LN_client_auth "TLS Web Client Authentication" +#define NID_client_auth 130 +#define OBJ_client_auth OBJ_id_kp,2L + +#define SN_code_sign "codeSigning" +#define LN_code_sign "Code Signing" +#define NID_code_sign 131 +#define OBJ_code_sign OBJ_id_kp,3L + +#define SN_email_protect "emailProtection" +#define LN_email_protect "E-mail Protection" +#define NID_email_protect 132 +#define OBJ_email_protect OBJ_id_kp,4L + +#define SN_ipsecEndSystem "ipsecEndSystem" +#define LN_ipsecEndSystem "IPSec End System" +#define NID_ipsecEndSystem 294 +#define OBJ_ipsecEndSystem OBJ_id_kp,5L + +#define SN_ipsecTunnel "ipsecTunnel" +#define LN_ipsecTunnel "IPSec Tunnel" +#define NID_ipsecTunnel 295 +#define OBJ_ipsecTunnel OBJ_id_kp,6L + +#define SN_ipsecUser "ipsecUser" +#define LN_ipsecUser "IPSec User" +#define NID_ipsecUser 296 +#define OBJ_ipsecUser OBJ_id_kp,7L + +#define SN_time_stamp "timeStamping" +#define LN_time_stamp "Time Stamping" +#define NID_time_stamp 133 +#define OBJ_time_stamp OBJ_id_kp,8L + +#define SN_OCSP_sign "OCSPSigning" +#define LN_OCSP_sign "OCSP Signing" +#define NID_OCSP_sign 180 +#define OBJ_OCSP_sign OBJ_id_kp,9L + +#define SN_dvcs "DVCS" +#define LN_dvcs "dvcs" +#define NID_dvcs 297 +#define OBJ_dvcs OBJ_id_kp,10L + +#define SN_id_it_caProtEncCert "id-it-caProtEncCert" +#define NID_id_it_caProtEncCert 298 +#define OBJ_id_it_caProtEncCert OBJ_id_it,1L + +#define SN_id_it_signKeyPairTypes "id-it-signKeyPairTypes" +#define NID_id_it_signKeyPairTypes 299 +#define OBJ_id_it_signKeyPairTypes OBJ_id_it,2L + +#define SN_id_it_encKeyPairTypes "id-it-encKeyPairTypes" +#define NID_id_it_encKeyPairTypes 300 +#define OBJ_id_it_encKeyPairTypes OBJ_id_it,3L + +#define SN_id_it_preferredSymmAlg "id-it-preferredSymmAlg" +#define NID_id_it_preferredSymmAlg 301 +#define OBJ_id_it_preferredSymmAlg OBJ_id_it,4L + +#define SN_id_it_caKeyUpdateInfo "id-it-caKeyUpdateInfo" +#define NID_id_it_caKeyUpdateInfo 302 +#define OBJ_id_it_caKeyUpdateInfo OBJ_id_it,5L + +#define SN_id_it_currentCRL "id-it-currentCRL" +#define NID_id_it_currentCRL 303 +#define OBJ_id_it_currentCRL OBJ_id_it,6L + +#define SN_id_it_unsupportedOIDs "id-it-unsupportedOIDs" +#define NID_id_it_unsupportedOIDs 304 +#define OBJ_id_it_unsupportedOIDs OBJ_id_it,7L + +#define SN_id_it_subscriptionRequest "id-it-subscriptionRequest" +#define NID_id_it_subscriptionRequest 305 +#define OBJ_id_it_subscriptionRequest OBJ_id_it,8L + +#define SN_id_it_subscriptionResponse "id-it-subscriptionResponse" +#define NID_id_it_subscriptionResponse 306 +#define OBJ_id_it_subscriptionResponse OBJ_id_it,9L + +#define SN_id_it_keyPairParamReq "id-it-keyPairParamReq" +#define NID_id_it_keyPairParamReq 307 +#define OBJ_id_it_keyPairParamReq OBJ_id_it,10L + +#define SN_id_it_keyPairParamRep "id-it-keyPairParamRep" +#define NID_id_it_keyPairParamRep 308 +#define OBJ_id_it_keyPairParamRep OBJ_id_it,11L + +#define SN_id_it_revPassphrase "id-it-revPassphrase" +#define NID_id_it_revPassphrase 309 +#define OBJ_id_it_revPassphrase OBJ_id_it,12L + +#define SN_id_it_implicitConfirm "id-it-implicitConfirm" +#define NID_id_it_implicitConfirm 310 +#define OBJ_id_it_implicitConfirm OBJ_id_it,13L + +#define SN_id_it_confirmWaitTime "id-it-confirmWaitTime" +#define NID_id_it_confirmWaitTime 311 +#define OBJ_id_it_confirmWaitTime OBJ_id_it,14L + +#define SN_id_it_origPKIMessage "id-it-origPKIMessage" +#define NID_id_it_origPKIMessage 312 +#define OBJ_id_it_origPKIMessage OBJ_id_it,15L + +#define SN_id_it_suppLangTags "id-it-suppLangTags" +#define NID_id_it_suppLangTags 784 +#define OBJ_id_it_suppLangTags OBJ_id_it,16L + +#define SN_id_regCtrl "id-regCtrl" +#define NID_id_regCtrl 313 +#define OBJ_id_regCtrl OBJ_id_pkip,1L + +#define SN_id_regInfo "id-regInfo" +#define NID_id_regInfo 314 +#define OBJ_id_regInfo OBJ_id_pkip,2L + +#define SN_id_regCtrl_regToken "id-regCtrl-regToken" +#define NID_id_regCtrl_regToken 315 +#define OBJ_id_regCtrl_regToken OBJ_id_regCtrl,1L + +#define SN_id_regCtrl_authenticator "id-regCtrl-authenticator" +#define NID_id_regCtrl_authenticator 316 +#define OBJ_id_regCtrl_authenticator OBJ_id_regCtrl,2L + +#define SN_id_regCtrl_pkiPublicationInfo "id-regCtrl-pkiPublicationInfo" +#define NID_id_regCtrl_pkiPublicationInfo 317 +#define OBJ_id_regCtrl_pkiPublicationInfo OBJ_id_regCtrl,3L + +#define SN_id_regCtrl_pkiArchiveOptions "id-regCtrl-pkiArchiveOptions" +#define NID_id_regCtrl_pkiArchiveOptions 318 +#define OBJ_id_regCtrl_pkiArchiveOptions OBJ_id_regCtrl,4L + +#define SN_id_regCtrl_oldCertID "id-regCtrl-oldCertID" +#define NID_id_regCtrl_oldCertID 319 +#define OBJ_id_regCtrl_oldCertID OBJ_id_regCtrl,5L + +#define SN_id_regCtrl_protocolEncrKey "id-regCtrl-protocolEncrKey" +#define NID_id_regCtrl_protocolEncrKey 320 +#define OBJ_id_regCtrl_protocolEncrKey OBJ_id_regCtrl,6L + +#define SN_id_regInfo_utf8Pairs "id-regInfo-utf8Pairs" +#define NID_id_regInfo_utf8Pairs 321 +#define OBJ_id_regInfo_utf8Pairs OBJ_id_regInfo,1L + +#define SN_id_regInfo_certReq "id-regInfo-certReq" +#define NID_id_regInfo_certReq 322 +#define OBJ_id_regInfo_certReq OBJ_id_regInfo,2L + +#define SN_id_alg_des40 "id-alg-des40" +#define NID_id_alg_des40 323 +#define OBJ_id_alg_des40 OBJ_id_alg,1L + +#define SN_id_alg_noSignature "id-alg-noSignature" +#define NID_id_alg_noSignature 324 +#define OBJ_id_alg_noSignature OBJ_id_alg,2L + +#define SN_id_alg_dh_sig_hmac_sha1 "id-alg-dh-sig-hmac-sha1" +#define NID_id_alg_dh_sig_hmac_sha1 325 +#define OBJ_id_alg_dh_sig_hmac_sha1 OBJ_id_alg,3L + +#define SN_id_alg_dh_pop "id-alg-dh-pop" +#define NID_id_alg_dh_pop 326 +#define OBJ_id_alg_dh_pop OBJ_id_alg,4L + +#define SN_id_cmc_statusInfo "id-cmc-statusInfo" +#define NID_id_cmc_statusInfo 327 +#define OBJ_id_cmc_statusInfo OBJ_id_cmc,1L + +#define SN_id_cmc_identification "id-cmc-identification" +#define NID_id_cmc_identification 328 +#define OBJ_id_cmc_identification OBJ_id_cmc,2L + +#define SN_id_cmc_identityProof "id-cmc-identityProof" +#define NID_id_cmc_identityProof 329 +#define OBJ_id_cmc_identityProof OBJ_id_cmc,3L + +#define SN_id_cmc_dataReturn "id-cmc-dataReturn" +#define NID_id_cmc_dataReturn 330 +#define OBJ_id_cmc_dataReturn OBJ_id_cmc,4L + +#define SN_id_cmc_transactionId "id-cmc-transactionId" +#define NID_id_cmc_transactionId 331 +#define OBJ_id_cmc_transactionId OBJ_id_cmc,5L + +#define SN_id_cmc_senderNonce "id-cmc-senderNonce" +#define NID_id_cmc_senderNonce 332 +#define OBJ_id_cmc_senderNonce OBJ_id_cmc,6L + +#define SN_id_cmc_recipientNonce "id-cmc-recipientNonce" +#define NID_id_cmc_recipientNonce 333 +#define OBJ_id_cmc_recipientNonce OBJ_id_cmc,7L + +#define SN_id_cmc_addExtensions "id-cmc-addExtensions" +#define NID_id_cmc_addExtensions 334 +#define OBJ_id_cmc_addExtensions OBJ_id_cmc,8L + +#define SN_id_cmc_encryptedPOP "id-cmc-encryptedPOP" +#define NID_id_cmc_encryptedPOP 335 +#define OBJ_id_cmc_encryptedPOP OBJ_id_cmc,9L + +#define SN_id_cmc_decryptedPOP "id-cmc-decryptedPOP" +#define NID_id_cmc_decryptedPOP 336 +#define OBJ_id_cmc_decryptedPOP OBJ_id_cmc,10L + +#define SN_id_cmc_lraPOPWitness "id-cmc-lraPOPWitness" +#define NID_id_cmc_lraPOPWitness 337 +#define OBJ_id_cmc_lraPOPWitness OBJ_id_cmc,11L + +#define SN_id_cmc_getCert "id-cmc-getCert" +#define NID_id_cmc_getCert 338 +#define OBJ_id_cmc_getCert OBJ_id_cmc,15L + +#define SN_id_cmc_getCRL "id-cmc-getCRL" +#define NID_id_cmc_getCRL 339 +#define OBJ_id_cmc_getCRL OBJ_id_cmc,16L + +#define SN_id_cmc_revokeRequest "id-cmc-revokeRequest" +#define NID_id_cmc_revokeRequest 340 +#define OBJ_id_cmc_revokeRequest OBJ_id_cmc,17L + +#define SN_id_cmc_regInfo "id-cmc-regInfo" +#define NID_id_cmc_regInfo 341 +#define OBJ_id_cmc_regInfo OBJ_id_cmc,18L + +#define SN_id_cmc_responseInfo "id-cmc-responseInfo" +#define NID_id_cmc_responseInfo 342 +#define OBJ_id_cmc_responseInfo OBJ_id_cmc,19L + +#define SN_id_cmc_queryPending "id-cmc-queryPending" +#define NID_id_cmc_queryPending 343 +#define OBJ_id_cmc_queryPending OBJ_id_cmc,21L + +#define SN_id_cmc_popLinkRandom "id-cmc-popLinkRandom" +#define NID_id_cmc_popLinkRandom 344 +#define OBJ_id_cmc_popLinkRandom OBJ_id_cmc,22L + +#define SN_id_cmc_popLinkWitness "id-cmc-popLinkWitness" +#define NID_id_cmc_popLinkWitness 345 +#define OBJ_id_cmc_popLinkWitness OBJ_id_cmc,23L + +#define SN_id_cmc_confirmCertAcceptance "id-cmc-confirmCertAcceptance" +#define NID_id_cmc_confirmCertAcceptance 346 +#define OBJ_id_cmc_confirmCertAcceptance OBJ_id_cmc,24L + +#define SN_id_on_personalData "id-on-personalData" +#define NID_id_on_personalData 347 +#define OBJ_id_on_personalData OBJ_id_on,1L + +#define SN_id_on_permanentIdentifier "id-on-permanentIdentifier" +#define LN_id_on_permanentIdentifier "Permanent Identifier" +#define NID_id_on_permanentIdentifier 858 +#define OBJ_id_on_permanentIdentifier OBJ_id_on,3L + +#define SN_id_pda_dateOfBirth "id-pda-dateOfBirth" +#define NID_id_pda_dateOfBirth 348 +#define OBJ_id_pda_dateOfBirth OBJ_id_pda,1L + +#define SN_id_pda_placeOfBirth "id-pda-placeOfBirth" +#define NID_id_pda_placeOfBirth 349 +#define OBJ_id_pda_placeOfBirth OBJ_id_pda,2L + +#define SN_id_pda_gender "id-pda-gender" +#define NID_id_pda_gender 351 +#define OBJ_id_pda_gender OBJ_id_pda,3L + +#define SN_id_pda_countryOfCitizenship "id-pda-countryOfCitizenship" +#define NID_id_pda_countryOfCitizenship 352 +#define OBJ_id_pda_countryOfCitizenship OBJ_id_pda,4L + +#define SN_id_pda_countryOfResidence "id-pda-countryOfResidence" +#define NID_id_pda_countryOfResidence 353 +#define OBJ_id_pda_countryOfResidence OBJ_id_pda,5L + +#define SN_id_aca_authenticationInfo "id-aca-authenticationInfo" +#define NID_id_aca_authenticationInfo 354 +#define OBJ_id_aca_authenticationInfo OBJ_id_aca,1L + +#define SN_id_aca_accessIdentity "id-aca-accessIdentity" +#define NID_id_aca_accessIdentity 355 +#define OBJ_id_aca_accessIdentity OBJ_id_aca,2L + +#define SN_id_aca_chargingIdentity "id-aca-chargingIdentity" +#define NID_id_aca_chargingIdentity 356 +#define OBJ_id_aca_chargingIdentity OBJ_id_aca,3L + +#define SN_id_aca_group "id-aca-group" +#define NID_id_aca_group 357 +#define OBJ_id_aca_group OBJ_id_aca,4L + +#define SN_id_aca_role "id-aca-role" +#define NID_id_aca_role 358 +#define OBJ_id_aca_role OBJ_id_aca,5L + +#define SN_id_aca_encAttrs "id-aca-encAttrs" +#define NID_id_aca_encAttrs 399 +#define OBJ_id_aca_encAttrs OBJ_id_aca,6L + +#define SN_id_qcs_pkixQCSyntax_v1 "id-qcs-pkixQCSyntax-v1" +#define NID_id_qcs_pkixQCSyntax_v1 359 +#define OBJ_id_qcs_pkixQCSyntax_v1 OBJ_id_qcs,1L + +#define SN_id_cct_crs "id-cct-crs" +#define NID_id_cct_crs 360 +#define OBJ_id_cct_crs OBJ_id_cct,1L + +#define SN_id_cct_PKIData "id-cct-PKIData" +#define NID_id_cct_PKIData 361 +#define OBJ_id_cct_PKIData OBJ_id_cct,2L + +#define SN_id_cct_PKIResponse "id-cct-PKIResponse" +#define NID_id_cct_PKIResponse 362 +#define OBJ_id_cct_PKIResponse OBJ_id_cct,3L + +#define SN_id_ppl_anyLanguage "id-ppl-anyLanguage" +#define LN_id_ppl_anyLanguage "Any language" +#define NID_id_ppl_anyLanguage 664 +#define OBJ_id_ppl_anyLanguage OBJ_id_ppl,0L + +#define SN_id_ppl_inheritAll "id-ppl-inheritAll" +#define LN_id_ppl_inheritAll "Inherit all" +#define NID_id_ppl_inheritAll 665 +#define OBJ_id_ppl_inheritAll OBJ_id_ppl,1L + +#define SN_Independent "id-ppl-independent" +#define LN_Independent "Independent" +#define NID_Independent 667 +#define OBJ_Independent OBJ_id_ppl,2L + +#define SN_ad_OCSP "OCSP" +#define LN_ad_OCSP "OCSP" +#define NID_ad_OCSP 178 +#define OBJ_ad_OCSP OBJ_id_ad,1L + +#define SN_ad_ca_issuers "caIssuers" +#define LN_ad_ca_issuers "CA Issuers" +#define NID_ad_ca_issuers 179 +#define OBJ_ad_ca_issuers OBJ_id_ad,2L + +#define SN_ad_timeStamping "ad_timestamping" +#define LN_ad_timeStamping "AD Time Stamping" +#define NID_ad_timeStamping 363 +#define OBJ_ad_timeStamping OBJ_id_ad,3L + +#define SN_ad_dvcs "AD_DVCS" +#define LN_ad_dvcs "ad dvcs" +#define NID_ad_dvcs 364 +#define OBJ_ad_dvcs OBJ_id_ad,4L + +#define SN_caRepository "caRepository" +#define LN_caRepository "CA Repository" +#define NID_caRepository 785 +#define OBJ_caRepository OBJ_id_ad,5L + +#define OBJ_id_pkix_OCSP OBJ_ad_OCSP + +#define SN_id_pkix_OCSP_basic "basicOCSPResponse" +#define LN_id_pkix_OCSP_basic "Basic OCSP Response" +#define NID_id_pkix_OCSP_basic 365 +#define OBJ_id_pkix_OCSP_basic OBJ_id_pkix_OCSP,1L + +#define SN_id_pkix_OCSP_Nonce "Nonce" +#define LN_id_pkix_OCSP_Nonce "OCSP Nonce" +#define NID_id_pkix_OCSP_Nonce 366 +#define OBJ_id_pkix_OCSP_Nonce OBJ_id_pkix_OCSP,2L + +#define SN_id_pkix_OCSP_CrlID "CrlID" +#define LN_id_pkix_OCSP_CrlID "OCSP CRL ID" +#define NID_id_pkix_OCSP_CrlID 367 +#define OBJ_id_pkix_OCSP_CrlID OBJ_id_pkix_OCSP,3L + +#define SN_id_pkix_OCSP_acceptableResponses "acceptableResponses" +#define LN_id_pkix_OCSP_acceptableResponses "Acceptable OCSP Responses" +#define NID_id_pkix_OCSP_acceptableResponses 368 +#define OBJ_id_pkix_OCSP_acceptableResponses OBJ_id_pkix_OCSP,4L + +#define SN_id_pkix_OCSP_noCheck "noCheck" +#define LN_id_pkix_OCSP_noCheck "OCSP No Check" +#define NID_id_pkix_OCSP_noCheck 369 +#define OBJ_id_pkix_OCSP_noCheck OBJ_id_pkix_OCSP,5L + +#define SN_id_pkix_OCSP_archiveCutoff "archiveCutoff" +#define LN_id_pkix_OCSP_archiveCutoff "OCSP Archive Cutoff" +#define NID_id_pkix_OCSP_archiveCutoff 370 +#define OBJ_id_pkix_OCSP_archiveCutoff OBJ_id_pkix_OCSP,6L + +#define SN_id_pkix_OCSP_serviceLocator "serviceLocator" +#define LN_id_pkix_OCSP_serviceLocator "OCSP Service Locator" +#define NID_id_pkix_OCSP_serviceLocator 371 +#define OBJ_id_pkix_OCSP_serviceLocator OBJ_id_pkix_OCSP,7L + +#define SN_id_pkix_OCSP_extendedStatus "extendedStatus" +#define LN_id_pkix_OCSP_extendedStatus "Extended OCSP Status" +#define NID_id_pkix_OCSP_extendedStatus 372 +#define OBJ_id_pkix_OCSP_extendedStatus OBJ_id_pkix_OCSP,8L + +#define SN_id_pkix_OCSP_valid "valid" +#define NID_id_pkix_OCSP_valid 373 +#define OBJ_id_pkix_OCSP_valid OBJ_id_pkix_OCSP,9L + +#define SN_id_pkix_OCSP_path "path" +#define NID_id_pkix_OCSP_path 374 +#define OBJ_id_pkix_OCSP_path OBJ_id_pkix_OCSP,10L + +#define SN_id_pkix_OCSP_trustRoot "trustRoot" +#define LN_id_pkix_OCSP_trustRoot "Trust Root" +#define NID_id_pkix_OCSP_trustRoot 375 +#define OBJ_id_pkix_OCSP_trustRoot OBJ_id_pkix_OCSP,11L + +#define SN_algorithm "algorithm" +#define LN_algorithm "algorithm" +#define NID_algorithm 376 +#define OBJ_algorithm 1L,3L,14L,3L,2L + +#define SN_md5WithRSA "RSA-NP-MD5" +#define LN_md5WithRSA "md5WithRSA" +#define NID_md5WithRSA 104 +#define OBJ_md5WithRSA OBJ_algorithm,3L + +#define SN_des_ecb "DES-ECB" +#define LN_des_ecb "des-ecb" +#define NID_des_ecb 29 +#define OBJ_des_ecb OBJ_algorithm,6L + +#define SN_des_cbc "DES-CBC" +#define LN_des_cbc "des-cbc" +#define NID_des_cbc 31 +#define OBJ_des_cbc OBJ_algorithm,7L + +#define SN_des_ofb64 "DES-OFB" +#define LN_des_ofb64 "des-ofb" +#define NID_des_ofb64 45 +#define OBJ_des_ofb64 OBJ_algorithm,8L + +#define SN_des_cfb64 "DES-CFB" +#define LN_des_cfb64 "des-cfb" +#define NID_des_cfb64 30 +#define OBJ_des_cfb64 OBJ_algorithm,9L + +#define SN_rsaSignature "rsaSignature" +#define NID_rsaSignature 377 +#define OBJ_rsaSignature OBJ_algorithm,11L + +#define SN_dsa_2 "DSA-old" +#define LN_dsa_2 "dsaEncryption-old" +#define NID_dsa_2 67 +#define OBJ_dsa_2 OBJ_algorithm,12L + +#define SN_dsaWithSHA "DSA-SHA" +#define LN_dsaWithSHA "dsaWithSHA" +#define NID_dsaWithSHA 66 +#define OBJ_dsaWithSHA OBJ_algorithm,13L + +#define SN_shaWithRSAEncryption "RSA-SHA" +#define LN_shaWithRSAEncryption "shaWithRSAEncryption" +#define NID_shaWithRSAEncryption 42 +#define OBJ_shaWithRSAEncryption OBJ_algorithm,15L + +#define SN_des_ede_ecb "DES-EDE" +#define LN_des_ede_ecb "des-ede" +#define NID_des_ede_ecb 32 +#define OBJ_des_ede_ecb OBJ_algorithm,17L + +#define SN_des_ede3_ecb "DES-EDE3" +#define LN_des_ede3_ecb "des-ede3" +#define NID_des_ede3_ecb 33 + +#define SN_des_ede_cbc "DES-EDE-CBC" +#define LN_des_ede_cbc "des-ede-cbc" +#define NID_des_ede_cbc 43 + +#define SN_des_ede_cfb64 "DES-EDE-CFB" +#define LN_des_ede_cfb64 "des-ede-cfb" +#define NID_des_ede_cfb64 60 + +#define SN_des_ede3_cfb64 "DES-EDE3-CFB" +#define LN_des_ede3_cfb64 "des-ede3-cfb" +#define NID_des_ede3_cfb64 61 + +#define SN_des_ede_ofb64 "DES-EDE-OFB" +#define LN_des_ede_ofb64 "des-ede-ofb" +#define NID_des_ede_ofb64 62 + +#define SN_des_ede3_ofb64 "DES-EDE3-OFB" +#define LN_des_ede3_ofb64 "des-ede3-ofb" +#define NID_des_ede3_ofb64 63 + +#define SN_desx_cbc "DESX-CBC" +#define LN_desx_cbc "desx-cbc" +#define NID_desx_cbc 80 + +#define SN_sha "SHA" +#define LN_sha "sha" +#define NID_sha 41 +#define OBJ_sha OBJ_algorithm,18L + +#define SN_sha1 "SHA1" +#define LN_sha1 "sha1" +#define NID_sha1 64 +#define OBJ_sha1 OBJ_algorithm,26L + +#define SN_dsaWithSHA1_2 "DSA-SHA1-old" +#define LN_dsaWithSHA1_2 "dsaWithSHA1-old" +#define NID_dsaWithSHA1_2 70 +#define OBJ_dsaWithSHA1_2 OBJ_algorithm,27L + +#define SN_sha1WithRSA "RSA-SHA1-2" +#define LN_sha1WithRSA "sha1WithRSA" +#define NID_sha1WithRSA 115 +#define OBJ_sha1WithRSA OBJ_algorithm,29L + +#define SN_ripemd160 "RIPEMD160" +#define LN_ripemd160 "ripemd160" +#define NID_ripemd160 117 +#define OBJ_ripemd160 1L,3L,36L,3L,2L,1L + +#define SN_ripemd160WithRSA "RSA-RIPEMD160" +#define LN_ripemd160WithRSA "ripemd160WithRSA" +#define NID_ripemd160WithRSA 119 +#define OBJ_ripemd160WithRSA 1L,3L,36L,3L,3L,1L,2L + +#define SN_sxnet "SXNetID" +#define LN_sxnet "Strong Extranet ID" +#define NID_sxnet 143 +#define OBJ_sxnet 1L,3L,101L,1L,4L,1L + +#define SN_X500 "X500" +#define LN_X500 "directory services (X.500)" +#define NID_X500 11 +#define OBJ_X500 2L,5L + +#define SN_X509 "X509" +#define NID_X509 12 +#define OBJ_X509 OBJ_X500,4L + +#define SN_commonName "CN" +#define LN_commonName "commonName" +#define NID_commonName 13 +#define OBJ_commonName OBJ_X509,3L + +#define SN_surname "SN" +#define LN_surname "surname" +#define NID_surname 100 +#define OBJ_surname OBJ_X509,4L + +#define LN_serialNumber "serialNumber" +#define NID_serialNumber 105 +#define OBJ_serialNumber OBJ_X509,5L + +#define SN_countryName "C" +#define LN_countryName "countryName" +#define NID_countryName 14 +#define OBJ_countryName OBJ_X509,6L + +#define SN_localityName "L" +#define LN_localityName "localityName" +#define NID_localityName 15 +#define OBJ_localityName OBJ_X509,7L + +#define SN_stateOrProvinceName "ST" +#define LN_stateOrProvinceName "stateOrProvinceName" +#define NID_stateOrProvinceName 16 +#define OBJ_stateOrProvinceName OBJ_X509,8L + +#define SN_streetAddress "street" +#define LN_streetAddress "streetAddress" +#define NID_streetAddress 660 +#define OBJ_streetAddress OBJ_X509,9L + +#define SN_organizationName "O" +#define LN_organizationName "organizationName" +#define NID_organizationName 17 +#define OBJ_organizationName OBJ_X509,10L + +#define SN_organizationalUnitName "OU" +#define LN_organizationalUnitName "organizationalUnitName" +#define NID_organizationalUnitName 18 +#define OBJ_organizationalUnitName OBJ_X509,11L + +#define SN_title "title" +#define LN_title "title" +#define NID_title 106 +#define OBJ_title OBJ_X509,12L + +#define LN_description "description" +#define NID_description 107 +#define OBJ_description OBJ_X509,13L + +#define LN_searchGuide "searchGuide" +#define NID_searchGuide 859 +#define OBJ_searchGuide OBJ_X509,14L + +#define LN_businessCategory "businessCategory" +#define NID_businessCategory 860 +#define OBJ_businessCategory OBJ_X509,15L + +#define LN_postalAddress "postalAddress" +#define NID_postalAddress 861 +#define OBJ_postalAddress OBJ_X509,16L + +#define LN_postalCode "postalCode" +#define NID_postalCode 661 +#define OBJ_postalCode OBJ_X509,17L + +#define LN_postOfficeBox "postOfficeBox" +#define NID_postOfficeBox 862 +#define OBJ_postOfficeBox OBJ_X509,18L + +#define LN_physicalDeliveryOfficeName "physicalDeliveryOfficeName" +#define NID_physicalDeliveryOfficeName 863 +#define OBJ_physicalDeliveryOfficeName OBJ_X509,19L + +#define LN_telephoneNumber "telephoneNumber" +#define NID_telephoneNumber 864 +#define OBJ_telephoneNumber OBJ_X509,20L + +#define LN_telexNumber "telexNumber" +#define NID_telexNumber 865 +#define OBJ_telexNumber OBJ_X509,21L + +#define LN_teletexTerminalIdentifier "teletexTerminalIdentifier" +#define NID_teletexTerminalIdentifier 866 +#define OBJ_teletexTerminalIdentifier OBJ_X509,22L + +#define LN_facsimileTelephoneNumber "facsimileTelephoneNumber" +#define NID_facsimileTelephoneNumber 867 +#define OBJ_facsimileTelephoneNumber OBJ_X509,23L + +#define LN_x121Address "x121Address" +#define NID_x121Address 868 +#define OBJ_x121Address OBJ_X509,24L + +#define LN_internationaliSDNNumber "internationaliSDNNumber" +#define NID_internationaliSDNNumber 869 +#define OBJ_internationaliSDNNumber OBJ_X509,25L + +#define LN_registeredAddress "registeredAddress" +#define NID_registeredAddress 870 +#define OBJ_registeredAddress OBJ_X509,26L + +#define LN_destinationIndicator "destinationIndicator" +#define NID_destinationIndicator 871 +#define OBJ_destinationIndicator OBJ_X509,27L + +#define LN_preferredDeliveryMethod "preferredDeliveryMethod" +#define NID_preferredDeliveryMethod 872 +#define OBJ_preferredDeliveryMethod OBJ_X509,28L + +#define LN_presentationAddress "presentationAddress" +#define NID_presentationAddress 873 +#define OBJ_presentationAddress OBJ_X509,29L + +#define LN_supportedApplicationContext "supportedApplicationContext" +#define NID_supportedApplicationContext 874 +#define OBJ_supportedApplicationContext OBJ_X509,30L + +#define SN_member "member" +#define NID_member 875 +#define OBJ_member OBJ_X509,31L + +#define SN_owner "owner" +#define NID_owner 876 +#define OBJ_owner OBJ_X509,32L + +#define LN_roleOccupant "roleOccupant" +#define NID_roleOccupant 877 +#define OBJ_roleOccupant OBJ_X509,33L + +#define SN_seeAlso "seeAlso" +#define NID_seeAlso 878 +#define OBJ_seeAlso OBJ_X509,34L + +#define LN_userPassword "userPassword" +#define NID_userPassword 879 +#define OBJ_userPassword OBJ_X509,35L + +#define LN_userCertificate "userCertificate" +#define NID_userCertificate 880 +#define OBJ_userCertificate OBJ_X509,36L + +#define LN_cACertificate "cACertificate" +#define NID_cACertificate 881 +#define OBJ_cACertificate OBJ_X509,37L + +#define LN_authorityRevocationList "authorityRevocationList" +#define NID_authorityRevocationList 882 +#define OBJ_authorityRevocationList OBJ_X509,38L + +#define LN_certificateRevocationList "certificateRevocationList" +#define NID_certificateRevocationList 883 +#define OBJ_certificateRevocationList OBJ_X509,39L + +#define LN_crossCertificatePair "crossCertificatePair" +#define NID_crossCertificatePair 884 +#define OBJ_crossCertificatePair OBJ_X509,40L + +#define SN_name "name" +#define LN_name "name" +#define NID_name 173 +#define OBJ_name OBJ_X509,41L + +#define SN_givenName "GN" +#define LN_givenName "givenName" +#define NID_givenName 99 +#define OBJ_givenName OBJ_X509,42L + +#define SN_initials "initials" +#define LN_initials "initials" +#define NID_initials 101 +#define OBJ_initials OBJ_X509,43L + +#define LN_generationQualifier "generationQualifier" +#define NID_generationQualifier 509 +#define OBJ_generationQualifier OBJ_X509,44L + +#define LN_x500UniqueIdentifier "x500UniqueIdentifier" +#define NID_x500UniqueIdentifier 503 +#define OBJ_x500UniqueIdentifier OBJ_X509,45L + +#define SN_dnQualifier "dnQualifier" +#define LN_dnQualifier "dnQualifier" +#define NID_dnQualifier 174 +#define OBJ_dnQualifier OBJ_X509,46L + +#define LN_enhancedSearchGuide "enhancedSearchGuide" +#define NID_enhancedSearchGuide 885 +#define OBJ_enhancedSearchGuide OBJ_X509,47L + +#define LN_protocolInformation "protocolInformation" +#define NID_protocolInformation 886 +#define OBJ_protocolInformation OBJ_X509,48L + +#define LN_distinguishedName "distinguishedName" +#define NID_distinguishedName 887 +#define OBJ_distinguishedName OBJ_X509,49L + +#define LN_uniqueMember "uniqueMember" +#define NID_uniqueMember 888 +#define OBJ_uniqueMember OBJ_X509,50L + +#define LN_houseIdentifier "houseIdentifier" +#define NID_houseIdentifier 889 +#define OBJ_houseIdentifier OBJ_X509,51L + +#define LN_supportedAlgorithms "supportedAlgorithms" +#define NID_supportedAlgorithms 890 +#define OBJ_supportedAlgorithms OBJ_X509,52L + +#define LN_deltaRevocationList "deltaRevocationList" +#define NID_deltaRevocationList 891 +#define OBJ_deltaRevocationList OBJ_X509,53L + +#define SN_dmdName "dmdName" +#define NID_dmdName 892 +#define OBJ_dmdName OBJ_X509,54L + +#define LN_pseudonym "pseudonym" +#define NID_pseudonym 510 +#define OBJ_pseudonym OBJ_X509,65L + +#define SN_role "role" +#define LN_role "role" +#define NID_role 400 +#define OBJ_role OBJ_X509,72L + +#define SN_X500algorithms "X500algorithms" +#define LN_X500algorithms "directory services - algorithms" +#define NID_X500algorithms 378 +#define OBJ_X500algorithms OBJ_X500,8L + +#define SN_rsa "RSA" +#define LN_rsa "rsa" +#define NID_rsa 19 +#define OBJ_rsa OBJ_X500algorithms,1L,1L + +#define SN_mdc2WithRSA "RSA-MDC2" +#define LN_mdc2WithRSA "mdc2WithRSA" +#define NID_mdc2WithRSA 96 +#define OBJ_mdc2WithRSA OBJ_X500algorithms,3L,100L + +#define SN_mdc2 "MDC2" +#define LN_mdc2 "mdc2" +#define NID_mdc2 95 +#define OBJ_mdc2 OBJ_X500algorithms,3L,101L + +#define SN_id_ce "id-ce" +#define NID_id_ce 81 +#define OBJ_id_ce OBJ_X500,29L + +#define SN_subject_directory_attributes "subjectDirectoryAttributes" +#define LN_subject_directory_attributes "X509v3 Subject Directory Attributes" +#define NID_subject_directory_attributes 769 +#define OBJ_subject_directory_attributes OBJ_id_ce,9L + +#define SN_subject_key_identifier "subjectKeyIdentifier" +#define LN_subject_key_identifier "X509v3 Subject Key Identifier" +#define NID_subject_key_identifier 82 +#define OBJ_subject_key_identifier OBJ_id_ce,14L + +#define SN_key_usage "keyUsage" +#define LN_key_usage "X509v3 Key Usage" +#define NID_key_usage 83 +#define OBJ_key_usage OBJ_id_ce,15L + +#define SN_private_key_usage_period "privateKeyUsagePeriod" +#define LN_private_key_usage_period "X509v3 Private Key Usage Period" +#define NID_private_key_usage_period 84 +#define OBJ_private_key_usage_period OBJ_id_ce,16L + +#define SN_subject_alt_name "subjectAltName" +#define LN_subject_alt_name "X509v3 Subject Alternative Name" +#define NID_subject_alt_name 85 +#define OBJ_subject_alt_name OBJ_id_ce,17L + +#define SN_issuer_alt_name "issuerAltName" +#define LN_issuer_alt_name "X509v3 Issuer Alternative Name" +#define NID_issuer_alt_name 86 +#define OBJ_issuer_alt_name OBJ_id_ce,18L + +#define SN_basic_constraints "basicConstraints" +#define LN_basic_constraints "X509v3 Basic Constraints" +#define NID_basic_constraints 87 +#define OBJ_basic_constraints OBJ_id_ce,19L + +#define SN_crl_number "crlNumber" +#define LN_crl_number "X509v3 CRL Number" +#define NID_crl_number 88 +#define OBJ_crl_number OBJ_id_ce,20L + +#define SN_crl_reason "CRLReason" +#define LN_crl_reason "X509v3 CRL Reason Code" +#define NID_crl_reason 141 +#define OBJ_crl_reason OBJ_id_ce,21L + +#define SN_invalidity_date "invalidityDate" +#define LN_invalidity_date "Invalidity Date" +#define NID_invalidity_date 142 +#define OBJ_invalidity_date OBJ_id_ce,24L + +#define SN_delta_crl "deltaCRL" +#define LN_delta_crl "X509v3 Delta CRL Indicator" +#define NID_delta_crl 140 +#define OBJ_delta_crl OBJ_id_ce,27L + +#define SN_issuing_distribution_point "issuingDistributionPoint" +#define LN_issuing_distribution_point "X509v3 Issuing Distribution Point" +#define NID_issuing_distribution_point 770 +#define OBJ_issuing_distribution_point OBJ_id_ce,28L + +#define SN_certificate_issuer "certificateIssuer" +#define LN_certificate_issuer "X509v3 Certificate Issuer" +#define NID_certificate_issuer 771 +#define OBJ_certificate_issuer OBJ_id_ce,29L + +#define SN_name_constraints "nameConstraints" +#define LN_name_constraints "X509v3 Name Constraints" +#define NID_name_constraints 666 +#define OBJ_name_constraints OBJ_id_ce,30L + +#define SN_crl_distribution_points "crlDistributionPoints" +#define LN_crl_distribution_points "X509v3 CRL Distribution Points" +#define NID_crl_distribution_points 103 +#define OBJ_crl_distribution_points OBJ_id_ce,31L + +#define SN_certificate_policies "certificatePolicies" +#define LN_certificate_policies "X509v3 Certificate Policies" +#define NID_certificate_policies 89 +#define OBJ_certificate_policies OBJ_id_ce,32L + +#define SN_any_policy "anyPolicy" +#define LN_any_policy "X509v3 Any Policy" +#define NID_any_policy 746 +#define OBJ_any_policy OBJ_certificate_policies,0L + +#define SN_policy_mappings "policyMappings" +#define LN_policy_mappings "X509v3 Policy Mappings" +#define NID_policy_mappings 747 +#define OBJ_policy_mappings OBJ_id_ce,33L + +#define SN_authority_key_identifier "authorityKeyIdentifier" +#define LN_authority_key_identifier "X509v3 Authority Key Identifier" +#define NID_authority_key_identifier 90 +#define OBJ_authority_key_identifier OBJ_id_ce,35L + +#define SN_policy_constraints "policyConstraints" +#define LN_policy_constraints "X509v3 Policy Constraints" +#define NID_policy_constraints 401 +#define OBJ_policy_constraints OBJ_id_ce,36L + +#define SN_ext_key_usage "extendedKeyUsage" +#define LN_ext_key_usage "X509v3 Extended Key Usage" +#define NID_ext_key_usage 126 +#define OBJ_ext_key_usage OBJ_id_ce,37L + +#define SN_freshest_crl "freshestCRL" +#define LN_freshest_crl "X509v3 Freshest CRL" +#define NID_freshest_crl 857 +#define OBJ_freshest_crl OBJ_id_ce,46L + +#define SN_inhibit_any_policy "inhibitAnyPolicy" +#define LN_inhibit_any_policy "X509v3 Inhibit Any Policy" +#define NID_inhibit_any_policy 748 +#define OBJ_inhibit_any_policy OBJ_id_ce,54L + +#define SN_target_information "targetInformation" +#define LN_target_information "X509v3 AC Targeting" +#define NID_target_information 402 +#define OBJ_target_information OBJ_id_ce,55L + +#define SN_no_rev_avail "noRevAvail" +#define LN_no_rev_avail "X509v3 No Revocation Available" +#define NID_no_rev_avail 403 +#define OBJ_no_rev_avail OBJ_id_ce,56L + +#define SN_anyExtendedKeyUsage "anyExtendedKeyUsage" +#define LN_anyExtendedKeyUsage "Any Extended Key Usage" +#define NID_anyExtendedKeyUsage 910 +#define OBJ_anyExtendedKeyUsage OBJ_ext_key_usage,0L + +#define SN_netscape "Netscape" +#define LN_netscape "Netscape Communications Corp." +#define NID_netscape 57 +#define OBJ_netscape 2L,16L,840L,1L,113730L + +#define SN_netscape_cert_extension "nsCertExt" +#define LN_netscape_cert_extension "Netscape Certificate Extension" +#define NID_netscape_cert_extension 58 +#define OBJ_netscape_cert_extension OBJ_netscape,1L + +#define SN_netscape_data_type "nsDataType" +#define LN_netscape_data_type "Netscape Data Type" +#define NID_netscape_data_type 59 +#define OBJ_netscape_data_type OBJ_netscape,2L + +#define SN_netscape_cert_type "nsCertType" +#define LN_netscape_cert_type "Netscape Cert Type" +#define NID_netscape_cert_type 71 +#define OBJ_netscape_cert_type OBJ_netscape_cert_extension,1L + +#define SN_netscape_base_url "nsBaseUrl" +#define LN_netscape_base_url "Netscape Base Url" +#define NID_netscape_base_url 72 +#define OBJ_netscape_base_url OBJ_netscape_cert_extension,2L + +#define SN_netscape_revocation_url "nsRevocationUrl" +#define LN_netscape_revocation_url "Netscape Revocation Url" +#define NID_netscape_revocation_url 73 +#define OBJ_netscape_revocation_url OBJ_netscape_cert_extension,3L + +#define SN_netscape_ca_revocation_url "nsCaRevocationUrl" +#define LN_netscape_ca_revocation_url "Netscape CA Revocation Url" +#define NID_netscape_ca_revocation_url 74 +#define OBJ_netscape_ca_revocation_url OBJ_netscape_cert_extension,4L + +#define SN_netscape_renewal_url "nsRenewalUrl" +#define LN_netscape_renewal_url "Netscape Renewal Url" +#define NID_netscape_renewal_url 75 +#define OBJ_netscape_renewal_url OBJ_netscape_cert_extension,7L + +#define SN_netscape_ca_policy_url "nsCaPolicyUrl" +#define LN_netscape_ca_policy_url "Netscape CA Policy Url" +#define NID_netscape_ca_policy_url 76 +#define OBJ_netscape_ca_policy_url OBJ_netscape_cert_extension,8L + +#define SN_netscape_ssl_server_name "nsSslServerName" +#define LN_netscape_ssl_server_name "Netscape SSL Server Name" +#define NID_netscape_ssl_server_name 77 +#define OBJ_netscape_ssl_server_name OBJ_netscape_cert_extension,12L + +#define SN_netscape_comment "nsComment" +#define LN_netscape_comment "Netscape Comment" +#define NID_netscape_comment 78 +#define OBJ_netscape_comment OBJ_netscape_cert_extension,13L + +#define SN_netscape_cert_sequence "nsCertSequence" +#define LN_netscape_cert_sequence "Netscape Certificate Sequence" +#define NID_netscape_cert_sequence 79 +#define OBJ_netscape_cert_sequence OBJ_netscape_data_type,5L + +#define SN_ns_sgc "nsSGC" +#define LN_ns_sgc "Netscape Server Gated Crypto" +#define NID_ns_sgc 139 +#define OBJ_ns_sgc OBJ_netscape,4L,1L + +#define SN_org "ORG" +#define LN_org "org" +#define NID_org 379 +#define OBJ_org OBJ_iso,3L + +#define SN_dod "DOD" +#define LN_dod "dod" +#define NID_dod 380 +#define OBJ_dod OBJ_org,6L + +#define SN_iana "IANA" +#define LN_iana "iana" +#define NID_iana 381 +#define OBJ_iana OBJ_dod,1L + +#define OBJ_internet OBJ_iana + +#define SN_Directory "directory" +#define LN_Directory "Directory" +#define NID_Directory 382 +#define OBJ_Directory OBJ_internet,1L + +#define SN_Management "mgmt" +#define LN_Management "Management" +#define NID_Management 383 +#define OBJ_Management OBJ_internet,2L + +#define SN_Experimental "experimental" +#define LN_Experimental "Experimental" +#define NID_Experimental 384 +#define OBJ_Experimental OBJ_internet,3L + +#define SN_Private "private" +#define LN_Private "Private" +#define NID_Private 385 +#define OBJ_Private OBJ_internet,4L + +#define SN_Security "security" +#define LN_Security "Security" +#define NID_Security 386 +#define OBJ_Security OBJ_internet,5L + +#define SN_SNMPv2 "snmpv2" +#define LN_SNMPv2 "SNMPv2" +#define NID_SNMPv2 387 +#define OBJ_SNMPv2 OBJ_internet,6L + +#define LN_Mail "Mail" +#define NID_Mail 388 +#define OBJ_Mail OBJ_internet,7L + +#define SN_Enterprises "enterprises" +#define LN_Enterprises "Enterprises" +#define NID_Enterprises 389 +#define OBJ_Enterprises OBJ_Private,1L + +#define SN_dcObject "dcobject" +#define LN_dcObject "dcObject" +#define NID_dcObject 390 +#define OBJ_dcObject OBJ_Enterprises,1466L,344L + +#define SN_mime_mhs "mime-mhs" +#define LN_mime_mhs "MIME MHS" +#define NID_mime_mhs 504 +#define OBJ_mime_mhs OBJ_Mail,1L + +#define SN_mime_mhs_headings "mime-mhs-headings" +#define LN_mime_mhs_headings "mime-mhs-headings" +#define NID_mime_mhs_headings 505 +#define OBJ_mime_mhs_headings OBJ_mime_mhs,1L + +#define SN_mime_mhs_bodies "mime-mhs-bodies" +#define LN_mime_mhs_bodies "mime-mhs-bodies" +#define NID_mime_mhs_bodies 506 +#define OBJ_mime_mhs_bodies OBJ_mime_mhs,2L + +#define SN_id_hex_partial_message "id-hex-partial-message" +#define LN_id_hex_partial_message "id-hex-partial-message" +#define NID_id_hex_partial_message 507 +#define OBJ_id_hex_partial_message OBJ_mime_mhs_headings,1L + +#define SN_id_hex_multipart_message "id-hex-multipart-message" +#define LN_id_hex_multipart_message "id-hex-multipart-message" +#define NID_id_hex_multipart_message 508 +#define OBJ_id_hex_multipart_message OBJ_mime_mhs_headings,2L + +#define SN_zlib_compression "ZLIB" +#define LN_zlib_compression "zlib compression" +#define NID_zlib_compression 125 +#define OBJ_zlib_compression OBJ_id_smime_alg,8L + +#define OBJ_csor 2L,16L,840L,1L,101L,3L + +#define OBJ_nistAlgorithms OBJ_csor,4L + +#define OBJ_aes OBJ_nistAlgorithms,1L + +#define SN_aes_128_ecb "AES-128-ECB" +#define LN_aes_128_ecb "aes-128-ecb" +#define NID_aes_128_ecb 418 +#define OBJ_aes_128_ecb OBJ_aes,1L + +#define SN_aes_128_cbc "AES-128-CBC" +#define LN_aes_128_cbc "aes-128-cbc" +#define NID_aes_128_cbc 419 +#define OBJ_aes_128_cbc OBJ_aes,2L + +#define SN_aes_128_ofb128 "AES-128-OFB" +#define LN_aes_128_ofb128 "aes-128-ofb" +#define NID_aes_128_ofb128 420 +#define OBJ_aes_128_ofb128 OBJ_aes,3L + +#define SN_aes_128_cfb128 "AES-128-CFB" +#define LN_aes_128_cfb128 "aes-128-cfb" +#define NID_aes_128_cfb128 421 +#define OBJ_aes_128_cfb128 OBJ_aes,4L + +#define SN_id_aes128_wrap "id-aes128-wrap" +#define NID_id_aes128_wrap 788 +#define OBJ_id_aes128_wrap OBJ_aes,5L + +#define SN_aes_128_gcm "id-aes128-GCM" +#define LN_aes_128_gcm "aes-128-gcm" +#define NID_aes_128_gcm 895 +#define OBJ_aes_128_gcm OBJ_aes,6L + +#define SN_aes_128_ccm "id-aes128-CCM" +#define LN_aes_128_ccm "aes-128-ccm" +#define NID_aes_128_ccm 896 +#define OBJ_aes_128_ccm OBJ_aes,7L + +#define SN_id_aes128_wrap_pad "id-aes128-wrap-pad" +#define NID_id_aes128_wrap_pad 897 +#define OBJ_id_aes128_wrap_pad OBJ_aes,8L + +#define SN_aes_192_ecb "AES-192-ECB" +#define LN_aes_192_ecb "aes-192-ecb" +#define NID_aes_192_ecb 422 +#define OBJ_aes_192_ecb OBJ_aes,21L + +#define SN_aes_192_cbc "AES-192-CBC" +#define LN_aes_192_cbc "aes-192-cbc" +#define NID_aes_192_cbc 423 +#define OBJ_aes_192_cbc OBJ_aes,22L + +#define SN_aes_192_ofb128 "AES-192-OFB" +#define LN_aes_192_ofb128 "aes-192-ofb" +#define NID_aes_192_ofb128 424 +#define OBJ_aes_192_ofb128 OBJ_aes,23L + +#define SN_aes_192_cfb128 "AES-192-CFB" +#define LN_aes_192_cfb128 "aes-192-cfb" +#define NID_aes_192_cfb128 425 +#define OBJ_aes_192_cfb128 OBJ_aes,24L + +#define SN_id_aes192_wrap "id-aes192-wrap" +#define NID_id_aes192_wrap 789 +#define OBJ_id_aes192_wrap OBJ_aes,25L + +#define SN_aes_192_gcm "id-aes192-GCM" +#define LN_aes_192_gcm "aes-192-gcm" +#define NID_aes_192_gcm 898 +#define OBJ_aes_192_gcm OBJ_aes,26L + +#define SN_aes_192_ccm "id-aes192-CCM" +#define LN_aes_192_ccm "aes-192-ccm" +#define NID_aes_192_ccm 899 +#define OBJ_aes_192_ccm OBJ_aes,27L + +#define SN_id_aes192_wrap_pad "id-aes192-wrap-pad" +#define NID_id_aes192_wrap_pad 900 +#define OBJ_id_aes192_wrap_pad OBJ_aes,28L + +#define SN_aes_256_ecb "AES-256-ECB" +#define LN_aes_256_ecb "aes-256-ecb" +#define NID_aes_256_ecb 426 +#define OBJ_aes_256_ecb OBJ_aes,41L + +#define SN_aes_256_cbc "AES-256-CBC" +#define LN_aes_256_cbc "aes-256-cbc" +#define NID_aes_256_cbc 427 +#define OBJ_aes_256_cbc OBJ_aes,42L + +#define SN_aes_256_ofb128 "AES-256-OFB" +#define LN_aes_256_ofb128 "aes-256-ofb" +#define NID_aes_256_ofb128 428 +#define OBJ_aes_256_ofb128 OBJ_aes,43L + +#define SN_aes_256_cfb128 "AES-256-CFB" +#define LN_aes_256_cfb128 "aes-256-cfb" +#define NID_aes_256_cfb128 429 +#define OBJ_aes_256_cfb128 OBJ_aes,44L + +#define SN_id_aes256_wrap "id-aes256-wrap" +#define NID_id_aes256_wrap 790 +#define OBJ_id_aes256_wrap OBJ_aes,45L + +#define SN_aes_256_gcm "id-aes256-GCM" +#define LN_aes_256_gcm "aes-256-gcm" +#define NID_aes_256_gcm 901 +#define OBJ_aes_256_gcm OBJ_aes,46L + +#define SN_aes_256_ccm "id-aes256-CCM" +#define LN_aes_256_ccm "aes-256-ccm" +#define NID_aes_256_ccm 902 +#define OBJ_aes_256_ccm OBJ_aes,47L + +#define SN_id_aes256_wrap_pad "id-aes256-wrap-pad" +#define NID_id_aes256_wrap_pad 903 +#define OBJ_id_aes256_wrap_pad OBJ_aes,48L + +#define SN_aes_128_cfb1 "AES-128-CFB1" +#define LN_aes_128_cfb1 "aes-128-cfb1" +#define NID_aes_128_cfb1 650 + +#define SN_aes_192_cfb1 "AES-192-CFB1" +#define LN_aes_192_cfb1 "aes-192-cfb1" +#define NID_aes_192_cfb1 651 + +#define SN_aes_256_cfb1 "AES-256-CFB1" +#define LN_aes_256_cfb1 "aes-256-cfb1" +#define NID_aes_256_cfb1 652 + +#define SN_aes_128_cfb8 "AES-128-CFB8" +#define LN_aes_128_cfb8 "aes-128-cfb8" +#define NID_aes_128_cfb8 653 + +#define SN_aes_192_cfb8 "AES-192-CFB8" +#define LN_aes_192_cfb8 "aes-192-cfb8" +#define NID_aes_192_cfb8 654 + +#define SN_aes_256_cfb8 "AES-256-CFB8" +#define LN_aes_256_cfb8 "aes-256-cfb8" +#define NID_aes_256_cfb8 655 + +#define SN_aes_128_ctr "AES-128-CTR" +#define LN_aes_128_ctr "aes-128-ctr" +#define NID_aes_128_ctr 904 + +#define SN_aes_192_ctr "AES-192-CTR" +#define LN_aes_192_ctr "aes-192-ctr" +#define NID_aes_192_ctr 905 + +#define SN_aes_256_ctr "AES-256-CTR" +#define LN_aes_256_ctr "aes-256-ctr" +#define NID_aes_256_ctr 906 + +#define SN_aes_128_xts "AES-128-XTS" +#define LN_aes_128_xts "aes-128-xts" +#define NID_aes_128_xts 913 + +#define SN_aes_256_xts "AES-256-XTS" +#define LN_aes_256_xts "aes-256-xts" +#define NID_aes_256_xts 914 + +#define SN_des_cfb1 "DES-CFB1" +#define LN_des_cfb1 "des-cfb1" +#define NID_des_cfb1 656 + +#define SN_des_cfb8 "DES-CFB8" +#define LN_des_cfb8 "des-cfb8" +#define NID_des_cfb8 657 + +#define SN_des_ede3_cfb1 "DES-EDE3-CFB1" +#define LN_des_ede3_cfb1 "des-ede3-cfb1" +#define NID_des_ede3_cfb1 658 + +#define SN_des_ede3_cfb8 "DES-EDE3-CFB8" +#define LN_des_ede3_cfb8 "des-ede3-cfb8" +#define NID_des_ede3_cfb8 659 + +#define OBJ_nist_hashalgs OBJ_nistAlgorithms,2L + +#define SN_sha256 "SHA256" +#define LN_sha256 "sha256" +#define NID_sha256 672 +#define OBJ_sha256 OBJ_nist_hashalgs,1L + +#define SN_sha384 "SHA384" +#define LN_sha384 "sha384" +#define NID_sha384 673 +#define OBJ_sha384 OBJ_nist_hashalgs,2L + +#define SN_sha512 "SHA512" +#define LN_sha512 "sha512" +#define NID_sha512 674 +#define OBJ_sha512 OBJ_nist_hashalgs,3L + +#define SN_sha224 "SHA224" +#define LN_sha224 "sha224" +#define NID_sha224 675 +#define OBJ_sha224 OBJ_nist_hashalgs,4L + +#define OBJ_dsa_with_sha2 OBJ_nistAlgorithms,3L + +#define SN_dsa_with_SHA224 "dsa_with_SHA224" +#define NID_dsa_with_SHA224 802 +#define OBJ_dsa_with_SHA224 OBJ_dsa_with_sha2,1L + +#define SN_dsa_with_SHA256 "dsa_with_SHA256" +#define NID_dsa_with_SHA256 803 +#define OBJ_dsa_with_SHA256 OBJ_dsa_with_sha2,2L + +#define SN_hold_instruction_code "holdInstructionCode" +#define LN_hold_instruction_code "Hold Instruction Code" +#define NID_hold_instruction_code 430 +#define OBJ_hold_instruction_code OBJ_id_ce,23L + +#define OBJ_holdInstruction OBJ_X9_57,2L + +#define SN_hold_instruction_none "holdInstructionNone" +#define LN_hold_instruction_none "Hold Instruction None" +#define NID_hold_instruction_none 431 +#define OBJ_hold_instruction_none OBJ_holdInstruction,1L + +#define SN_hold_instruction_call_issuer "holdInstructionCallIssuer" +#define LN_hold_instruction_call_issuer "Hold Instruction Call Issuer" +#define NID_hold_instruction_call_issuer 432 +#define OBJ_hold_instruction_call_issuer OBJ_holdInstruction,2L + +#define SN_hold_instruction_reject "holdInstructionReject" +#define LN_hold_instruction_reject "Hold Instruction Reject" +#define NID_hold_instruction_reject 433 +#define OBJ_hold_instruction_reject OBJ_holdInstruction,3L + +#define SN_data "data" +#define NID_data 434 +#define OBJ_data OBJ_itu_t,9L + +#define SN_pss "pss" +#define NID_pss 435 +#define OBJ_pss OBJ_data,2342L + +#define SN_ucl "ucl" +#define NID_ucl 436 +#define OBJ_ucl OBJ_pss,19200300L + +#define SN_pilot "pilot" +#define NID_pilot 437 +#define OBJ_pilot OBJ_ucl,100L + +#define LN_pilotAttributeType "pilotAttributeType" +#define NID_pilotAttributeType 438 +#define OBJ_pilotAttributeType OBJ_pilot,1L + +#define LN_pilotAttributeSyntax "pilotAttributeSyntax" +#define NID_pilotAttributeSyntax 439 +#define OBJ_pilotAttributeSyntax OBJ_pilot,3L + +#define LN_pilotObjectClass "pilotObjectClass" +#define NID_pilotObjectClass 440 +#define OBJ_pilotObjectClass OBJ_pilot,4L + +#define LN_pilotGroups "pilotGroups" +#define NID_pilotGroups 441 +#define OBJ_pilotGroups OBJ_pilot,10L + +#define LN_iA5StringSyntax "iA5StringSyntax" +#define NID_iA5StringSyntax 442 +#define OBJ_iA5StringSyntax OBJ_pilotAttributeSyntax,4L + +#define LN_caseIgnoreIA5StringSyntax "caseIgnoreIA5StringSyntax" +#define NID_caseIgnoreIA5StringSyntax 443 +#define OBJ_caseIgnoreIA5StringSyntax OBJ_pilotAttributeSyntax,5L + +#define LN_pilotObject "pilotObject" +#define NID_pilotObject 444 +#define OBJ_pilotObject OBJ_pilotObjectClass,3L + +#define LN_pilotPerson "pilotPerson" +#define NID_pilotPerson 445 +#define OBJ_pilotPerson OBJ_pilotObjectClass,4L + +#define SN_account "account" +#define NID_account 446 +#define OBJ_account OBJ_pilotObjectClass,5L + +#define SN_document "document" +#define NID_document 447 +#define OBJ_document OBJ_pilotObjectClass,6L + +#define SN_room "room" +#define NID_room 448 +#define OBJ_room OBJ_pilotObjectClass,7L + +#define LN_documentSeries "documentSeries" +#define NID_documentSeries 449 +#define OBJ_documentSeries OBJ_pilotObjectClass,9L + +#define SN_Domain "domain" +#define LN_Domain "Domain" +#define NID_Domain 392 +#define OBJ_Domain OBJ_pilotObjectClass,13L + +#define LN_rFC822localPart "rFC822localPart" +#define NID_rFC822localPart 450 +#define OBJ_rFC822localPart OBJ_pilotObjectClass,14L + +#define LN_dNSDomain "dNSDomain" +#define NID_dNSDomain 451 +#define OBJ_dNSDomain OBJ_pilotObjectClass,15L + +#define LN_domainRelatedObject "domainRelatedObject" +#define NID_domainRelatedObject 452 +#define OBJ_domainRelatedObject OBJ_pilotObjectClass,17L + +#define LN_friendlyCountry "friendlyCountry" +#define NID_friendlyCountry 453 +#define OBJ_friendlyCountry OBJ_pilotObjectClass,18L + +#define LN_simpleSecurityObject "simpleSecurityObject" +#define NID_simpleSecurityObject 454 +#define OBJ_simpleSecurityObject OBJ_pilotObjectClass,19L + +#define LN_pilotOrganization "pilotOrganization" +#define NID_pilotOrganization 455 +#define OBJ_pilotOrganization OBJ_pilotObjectClass,20L + +#define LN_pilotDSA "pilotDSA" +#define NID_pilotDSA 456 +#define OBJ_pilotDSA OBJ_pilotObjectClass,21L + +#define LN_qualityLabelledData "qualityLabelledData" +#define NID_qualityLabelledData 457 +#define OBJ_qualityLabelledData OBJ_pilotObjectClass,22L + +#define SN_userId "UID" +#define LN_userId "userId" +#define NID_userId 458 +#define OBJ_userId OBJ_pilotAttributeType,1L + +#define LN_textEncodedORAddress "textEncodedORAddress" +#define NID_textEncodedORAddress 459 +#define OBJ_textEncodedORAddress OBJ_pilotAttributeType,2L + +#define SN_rfc822Mailbox "mail" +#define LN_rfc822Mailbox "rfc822Mailbox" +#define NID_rfc822Mailbox 460 +#define OBJ_rfc822Mailbox OBJ_pilotAttributeType,3L + +#define SN_info "info" +#define NID_info 461 +#define OBJ_info OBJ_pilotAttributeType,4L + +#define LN_favouriteDrink "favouriteDrink" +#define NID_favouriteDrink 462 +#define OBJ_favouriteDrink OBJ_pilotAttributeType,5L + +#define LN_roomNumber "roomNumber" +#define NID_roomNumber 463 +#define OBJ_roomNumber OBJ_pilotAttributeType,6L + +#define SN_photo "photo" +#define NID_photo 464 +#define OBJ_photo OBJ_pilotAttributeType,7L + +#define LN_userClass "userClass" +#define NID_userClass 465 +#define OBJ_userClass OBJ_pilotAttributeType,8L + +#define SN_host "host" +#define NID_host 466 +#define OBJ_host OBJ_pilotAttributeType,9L + +#define SN_manager "manager" +#define NID_manager 467 +#define OBJ_manager OBJ_pilotAttributeType,10L + +#define LN_documentIdentifier "documentIdentifier" +#define NID_documentIdentifier 468 +#define OBJ_documentIdentifier OBJ_pilotAttributeType,11L + +#define LN_documentTitle "documentTitle" +#define NID_documentTitle 469 +#define OBJ_documentTitle OBJ_pilotAttributeType,12L + +#define LN_documentVersion "documentVersion" +#define NID_documentVersion 470 +#define OBJ_documentVersion OBJ_pilotAttributeType,13L + +#define LN_documentAuthor "documentAuthor" +#define NID_documentAuthor 471 +#define OBJ_documentAuthor OBJ_pilotAttributeType,14L + +#define LN_documentLocation "documentLocation" +#define NID_documentLocation 472 +#define OBJ_documentLocation OBJ_pilotAttributeType,15L + +#define LN_homeTelephoneNumber "homeTelephoneNumber" +#define NID_homeTelephoneNumber 473 +#define OBJ_homeTelephoneNumber OBJ_pilotAttributeType,20L + +#define SN_secretary "secretary" +#define NID_secretary 474 +#define OBJ_secretary OBJ_pilotAttributeType,21L + +#define LN_otherMailbox "otherMailbox" +#define NID_otherMailbox 475 +#define OBJ_otherMailbox OBJ_pilotAttributeType,22L + +#define LN_lastModifiedTime "lastModifiedTime" +#define NID_lastModifiedTime 476 +#define OBJ_lastModifiedTime OBJ_pilotAttributeType,23L + +#define LN_lastModifiedBy "lastModifiedBy" +#define NID_lastModifiedBy 477 +#define OBJ_lastModifiedBy OBJ_pilotAttributeType,24L + +#define SN_domainComponent "DC" +#define LN_domainComponent "domainComponent" +#define NID_domainComponent 391 +#define OBJ_domainComponent OBJ_pilotAttributeType,25L + +#define LN_aRecord "aRecord" +#define NID_aRecord 478 +#define OBJ_aRecord OBJ_pilotAttributeType,26L + +#define LN_pilotAttributeType27 "pilotAttributeType27" +#define NID_pilotAttributeType27 479 +#define OBJ_pilotAttributeType27 OBJ_pilotAttributeType,27L + +#define LN_mXRecord "mXRecord" +#define NID_mXRecord 480 +#define OBJ_mXRecord OBJ_pilotAttributeType,28L + +#define LN_nSRecord "nSRecord" +#define NID_nSRecord 481 +#define OBJ_nSRecord OBJ_pilotAttributeType,29L + +#define LN_sOARecord "sOARecord" +#define NID_sOARecord 482 +#define OBJ_sOARecord OBJ_pilotAttributeType,30L + +#define LN_cNAMERecord "cNAMERecord" +#define NID_cNAMERecord 483 +#define OBJ_cNAMERecord OBJ_pilotAttributeType,31L + +#define LN_associatedDomain "associatedDomain" +#define NID_associatedDomain 484 +#define OBJ_associatedDomain OBJ_pilotAttributeType,37L + +#define LN_associatedName "associatedName" +#define NID_associatedName 485 +#define OBJ_associatedName OBJ_pilotAttributeType,38L + +#define LN_homePostalAddress "homePostalAddress" +#define NID_homePostalAddress 486 +#define OBJ_homePostalAddress OBJ_pilotAttributeType,39L + +#define LN_personalTitle "personalTitle" +#define NID_personalTitle 487 +#define OBJ_personalTitle OBJ_pilotAttributeType,40L + +#define LN_mobileTelephoneNumber "mobileTelephoneNumber" +#define NID_mobileTelephoneNumber 488 +#define OBJ_mobileTelephoneNumber OBJ_pilotAttributeType,41L + +#define LN_pagerTelephoneNumber "pagerTelephoneNumber" +#define NID_pagerTelephoneNumber 489 +#define OBJ_pagerTelephoneNumber OBJ_pilotAttributeType,42L + +#define LN_friendlyCountryName "friendlyCountryName" +#define NID_friendlyCountryName 490 +#define OBJ_friendlyCountryName OBJ_pilotAttributeType,43L + +#define LN_organizationalStatus "organizationalStatus" +#define NID_organizationalStatus 491 +#define OBJ_organizationalStatus OBJ_pilotAttributeType,45L + +#define LN_janetMailbox "janetMailbox" +#define NID_janetMailbox 492 +#define OBJ_janetMailbox OBJ_pilotAttributeType,46L + +#define LN_mailPreferenceOption "mailPreferenceOption" +#define NID_mailPreferenceOption 493 +#define OBJ_mailPreferenceOption OBJ_pilotAttributeType,47L + +#define LN_buildingName "buildingName" +#define NID_buildingName 494 +#define OBJ_buildingName OBJ_pilotAttributeType,48L + +#define LN_dSAQuality "dSAQuality" +#define NID_dSAQuality 495 +#define OBJ_dSAQuality OBJ_pilotAttributeType,49L + +#define LN_singleLevelQuality "singleLevelQuality" +#define NID_singleLevelQuality 496 +#define OBJ_singleLevelQuality OBJ_pilotAttributeType,50L + +#define LN_subtreeMinimumQuality "subtreeMinimumQuality" +#define NID_subtreeMinimumQuality 497 +#define OBJ_subtreeMinimumQuality OBJ_pilotAttributeType,51L + +#define LN_subtreeMaximumQuality "subtreeMaximumQuality" +#define NID_subtreeMaximumQuality 498 +#define OBJ_subtreeMaximumQuality OBJ_pilotAttributeType,52L + +#define LN_personalSignature "personalSignature" +#define NID_personalSignature 499 +#define OBJ_personalSignature OBJ_pilotAttributeType,53L + +#define LN_dITRedirect "dITRedirect" +#define NID_dITRedirect 500 +#define OBJ_dITRedirect OBJ_pilotAttributeType,54L + +#define SN_audio "audio" +#define NID_audio 501 +#define OBJ_audio OBJ_pilotAttributeType,55L + +#define LN_documentPublisher "documentPublisher" +#define NID_documentPublisher 502 +#define OBJ_documentPublisher OBJ_pilotAttributeType,56L + +#define SN_id_set "id-set" +#define LN_id_set "Secure Electronic Transactions" +#define NID_id_set 512 +#define OBJ_id_set OBJ_international_organizations,42L + +#define SN_set_ctype "set-ctype" +#define LN_set_ctype "content types" +#define NID_set_ctype 513 +#define OBJ_set_ctype OBJ_id_set,0L + +#define SN_set_msgExt "set-msgExt" +#define LN_set_msgExt "message extensions" +#define NID_set_msgExt 514 +#define OBJ_set_msgExt OBJ_id_set,1L + +#define SN_set_attr "set-attr" +#define NID_set_attr 515 +#define OBJ_set_attr OBJ_id_set,3L + +#define SN_set_policy "set-policy" +#define NID_set_policy 516 +#define OBJ_set_policy OBJ_id_set,5L + +#define SN_set_certExt "set-certExt" +#define LN_set_certExt "certificate extensions" +#define NID_set_certExt 517 +#define OBJ_set_certExt OBJ_id_set,7L + +#define SN_set_brand "set-brand" +#define NID_set_brand 518 +#define OBJ_set_brand OBJ_id_set,8L + +#define SN_setct_PANData "setct-PANData" +#define NID_setct_PANData 519 +#define OBJ_setct_PANData OBJ_set_ctype,0L + +#define SN_setct_PANToken "setct-PANToken" +#define NID_setct_PANToken 520 +#define OBJ_setct_PANToken OBJ_set_ctype,1L + +#define SN_setct_PANOnly "setct-PANOnly" +#define NID_setct_PANOnly 521 +#define OBJ_setct_PANOnly OBJ_set_ctype,2L + +#define SN_setct_OIData "setct-OIData" +#define NID_setct_OIData 522 +#define OBJ_setct_OIData OBJ_set_ctype,3L + +#define SN_setct_PI "setct-PI" +#define NID_setct_PI 523 +#define OBJ_setct_PI OBJ_set_ctype,4L + +#define SN_setct_PIData "setct-PIData" +#define NID_setct_PIData 524 +#define OBJ_setct_PIData OBJ_set_ctype,5L + +#define SN_setct_PIDataUnsigned "setct-PIDataUnsigned" +#define NID_setct_PIDataUnsigned 525 +#define OBJ_setct_PIDataUnsigned OBJ_set_ctype,6L + +#define SN_setct_HODInput "setct-HODInput" +#define NID_setct_HODInput 526 +#define OBJ_setct_HODInput OBJ_set_ctype,7L + +#define SN_setct_AuthResBaggage "setct-AuthResBaggage" +#define NID_setct_AuthResBaggage 527 +#define OBJ_setct_AuthResBaggage OBJ_set_ctype,8L + +#define SN_setct_AuthRevReqBaggage "setct-AuthRevReqBaggage" +#define NID_setct_AuthRevReqBaggage 528 +#define OBJ_setct_AuthRevReqBaggage OBJ_set_ctype,9L + +#define SN_setct_AuthRevResBaggage "setct-AuthRevResBaggage" +#define NID_setct_AuthRevResBaggage 529 +#define OBJ_setct_AuthRevResBaggage OBJ_set_ctype,10L + +#define SN_setct_CapTokenSeq "setct-CapTokenSeq" +#define NID_setct_CapTokenSeq 530 +#define OBJ_setct_CapTokenSeq OBJ_set_ctype,11L + +#define SN_setct_PInitResData "setct-PInitResData" +#define NID_setct_PInitResData 531 +#define OBJ_setct_PInitResData OBJ_set_ctype,12L + +#define SN_setct_PI_TBS "setct-PI-TBS" +#define NID_setct_PI_TBS 532 +#define OBJ_setct_PI_TBS OBJ_set_ctype,13L + +#define SN_setct_PResData "setct-PResData" +#define NID_setct_PResData 533 +#define OBJ_setct_PResData OBJ_set_ctype,14L + +#define SN_setct_AuthReqTBS "setct-AuthReqTBS" +#define NID_setct_AuthReqTBS 534 +#define OBJ_setct_AuthReqTBS OBJ_set_ctype,16L + +#define SN_setct_AuthResTBS "setct-AuthResTBS" +#define NID_setct_AuthResTBS 535 +#define OBJ_setct_AuthResTBS OBJ_set_ctype,17L + +#define SN_setct_AuthResTBSX "setct-AuthResTBSX" +#define NID_setct_AuthResTBSX 536 +#define OBJ_setct_AuthResTBSX OBJ_set_ctype,18L + +#define SN_setct_AuthTokenTBS "setct-AuthTokenTBS" +#define NID_setct_AuthTokenTBS 537 +#define OBJ_setct_AuthTokenTBS OBJ_set_ctype,19L + +#define SN_setct_CapTokenData "setct-CapTokenData" +#define NID_setct_CapTokenData 538 +#define OBJ_setct_CapTokenData OBJ_set_ctype,20L + +#define SN_setct_CapTokenTBS "setct-CapTokenTBS" +#define NID_setct_CapTokenTBS 539 +#define OBJ_setct_CapTokenTBS OBJ_set_ctype,21L + +#define SN_setct_AcqCardCodeMsg "setct-AcqCardCodeMsg" +#define NID_setct_AcqCardCodeMsg 540 +#define OBJ_setct_AcqCardCodeMsg OBJ_set_ctype,22L + +#define SN_setct_AuthRevReqTBS "setct-AuthRevReqTBS" +#define NID_setct_AuthRevReqTBS 541 +#define OBJ_setct_AuthRevReqTBS OBJ_set_ctype,23L + +#define SN_setct_AuthRevResData "setct-AuthRevResData" +#define NID_setct_AuthRevResData 542 +#define OBJ_setct_AuthRevResData OBJ_set_ctype,24L + +#define SN_setct_AuthRevResTBS "setct-AuthRevResTBS" +#define NID_setct_AuthRevResTBS 543 +#define OBJ_setct_AuthRevResTBS OBJ_set_ctype,25L + +#define SN_setct_CapReqTBS "setct-CapReqTBS" +#define NID_setct_CapReqTBS 544 +#define OBJ_setct_CapReqTBS OBJ_set_ctype,26L + +#define SN_setct_CapReqTBSX "setct-CapReqTBSX" +#define NID_setct_CapReqTBSX 545 +#define OBJ_setct_CapReqTBSX OBJ_set_ctype,27L + +#define SN_setct_CapResData "setct-CapResData" +#define NID_setct_CapResData 546 +#define OBJ_setct_CapResData OBJ_set_ctype,28L + +#define SN_setct_CapRevReqTBS "setct-CapRevReqTBS" +#define NID_setct_CapRevReqTBS 547 +#define OBJ_setct_CapRevReqTBS OBJ_set_ctype,29L + +#define SN_setct_CapRevReqTBSX "setct-CapRevReqTBSX" +#define NID_setct_CapRevReqTBSX 548 +#define OBJ_setct_CapRevReqTBSX OBJ_set_ctype,30L + +#define SN_setct_CapRevResData "setct-CapRevResData" +#define NID_setct_CapRevResData 549 +#define OBJ_setct_CapRevResData OBJ_set_ctype,31L + +#define SN_setct_CredReqTBS "setct-CredReqTBS" +#define NID_setct_CredReqTBS 550 +#define OBJ_setct_CredReqTBS OBJ_set_ctype,32L + +#define SN_setct_CredReqTBSX "setct-CredReqTBSX" +#define NID_setct_CredReqTBSX 551 +#define OBJ_setct_CredReqTBSX OBJ_set_ctype,33L + +#define SN_setct_CredResData "setct-CredResData" +#define NID_setct_CredResData 552 +#define OBJ_setct_CredResData OBJ_set_ctype,34L + +#define SN_setct_CredRevReqTBS "setct-CredRevReqTBS" +#define NID_setct_CredRevReqTBS 553 +#define OBJ_setct_CredRevReqTBS OBJ_set_ctype,35L + +#define SN_setct_CredRevReqTBSX "setct-CredRevReqTBSX" +#define NID_setct_CredRevReqTBSX 554 +#define OBJ_setct_CredRevReqTBSX OBJ_set_ctype,36L + +#define SN_setct_CredRevResData "setct-CredRevResData" +#define NID_setct_CredRevResData 555 +#define OBJ_setct_CredRevResData OBJ_set_ctype,37L + +#define SN_setct_PCertReqData "setct-PCertReqData" +#define NID_setct_PCertReqData 556 +#define OBJ_setct_PCertReqData OBJ_set_ctype,38L + +#define SN_setct_PCertResTBS "setct-PCertResTBS" +#define NID_setct_PCertResTBS 557 +#define OBJ_setct_PCertResTBS OBJ_set_ctype,39L + +#define SN_setct_BatchAdminReqData "setct-BatchAdminReqData" +#define NID_setct_BatchAdminReqData 558 +#define OBJ_setct_BatchAdminReqData OBJ_set_ctype,40L + +#define SN_setct_BatchAdminResData "setct-BatchAdminResData" +#define NID_setct_BatchAdminResData 559 +#define OBJ_setct_BatchAdminResData OBJ_set_ctype,41L + +#define SN_setct_CardCInitResTBS "setct-CardCInitResTBS" +#define NID_setct_CardCInitResTBS 560 +#define OBJ_setct_CardCInitResTBS OBJ_set_ctype,42L + +#define SN_setct_MeAqCInitResTBS "setct-MeAqCInitResTBS" +#define NID_setct_MeAqCInitResTBS 561 +#define OBJ_setct_MeAqCInitResTBS OBJ_set_ctype,43L + +#define SN_setct_RegFormResTBS "setct-RegFormResTBS" +#define NID_setct_RegFormResTBS 562 +#define OBJ_setct_RegFormResTBS OBJ_set_ctype,44L + +#define SN_setct_CertReqData "setct-CertReqData" +#define NID_setct_CertReqData 563 +#define OBJ_setct_CertReqData OBJ_set_ctype,45L + +#define SN_setct_CertReqTBS "setct-CertReqTBS" +#define NID_setct_CertReqTBS 564 +#define OBJ_setct_CertReqTBS OBJ_set_ctype,46L + +#define SN_setct_CertResData "setct-CertResData" +#define NID_setct_CertResData 565 +#define OBJ_setct_CertResData OBJ_set_ctype,47L + +#define SN_setct_CertInqReqTBS "setct-CertInqReqTBS" +#define NID_setct_CertInqReqTBS 566 +#define OBJ_setct_CertInqReqTBS OBJ_set_ctype,48L + +#define SN_setct_ErrorTBS "setct-ErrorTBS" +#define NID_setct_ErrorTBS 567 +#define OBJ_setct_ErrorTBS OBJ_set_ctype,49L + +#define SN_setct_PIDualSignedTBE "setct-PIDualSignedTBE" +#define NID_setct_PIDualSignedTBE 568 +#define OBJ_setct_PIDualSignedTBE OBJ_set_ctype,50L + +#define SN_setct_PIUnsignedTBE "setct-PIUnsignedTBE" +#define NID_setct_PIUnsignedTBE 569 +#define OBJ_setct_PIUnsignedTBE OBJ_set_ctype,51L + +#define SN_setct_AuthReqTBE "setct-AuthReqTBE" +#define NID_setct_AuthReqTBE 570 +#define OBJ_setct_AuthReqTBE OBJ_set_ctype,52L + +#define SN_setct_AuthResTBE "setct-AuthResTBE" +#define NID_setct_AuthResTBE 571 +#define OBJ_setct_AuthResTBE OBJ_set_ctype,53L + +#define SN_setct_AuthResTBEX "setct-AuthResTBEX" +#define NID_setct_AuthResTBEX 572 +#define OBJ_setct_AuthResTBEX OBJ_set_ctype,54L + +#define SN_setct_AuthTokenTBE "setct-AuthTokenTBE" +#define NID_setct_AuthTokenTBE 573 +#define OBJ_setct_AuthTokenTBE OBJ_set_ctype,55L + +#define SN_setct_CapTokenTBE "setct-CapTokenTBE" +#define NID_setct_CapTokenTBE 574 +#define OBJ_setct_CapTokenTBE OBJ_set_ctype,56L + +#define SN_setct_CapTokenTBEX "setct-CapTokenTBEX" +#define NID_setct_CapTokenTBEX 575 +#define OBJ_setct_CapTokenTBEX OBJ_set_ctype,57L + +#define SN_setct_AcqCardCodeMsgTBE "setct-AcqCardCodeMsgTBE" +#define NID_setct_AcqCardCodeMsgTBE 576 +#define OBJ_setct_AcqCardCodeMsgTBE OBJ_set_ctype,58L + +#define SN_setct_AuthRevReqTBE "setct-AuthRevReqTBE" +#define NID_setct_AuthRevReqTBE 577 +#define OBJ_setct_AuthRevReqTBE OBJ_set_ctype,59L + +#define SN_setct_AuthRevResTBE "setct-AuthRevResTBE" +#define NID_setct_AuthRevResTBE 578 +#define OBJ_setct_AuthRevResTBE OBJ_set_ctype,60L + +#define SN_setct_AuthRevResTBEB "setct-AuthRevResTBEB" +#define NID_setct_AuthRevResTBEB 579 +#define OBJ_setct_AuthRevResTBEB OBJ_set_ctype,61L + +#define SN_setct_CapReqTBE "setct-CapReqTBE" +#define NID_setct_CapReqTBE 580 +#define OBJ_setct_CapReqTBE OBJ_set_ctype,62L + +#define SN_setct_CapReqTBEX "setct-CapReqTBEX" +#define NID_setct_CapReqTBEX 581 +#define OBJ_setct_CapReqTBEX OBJ_set_ctype,63L + +#define SN_setct_CapResTBE "setct-CapResTBE" +#define NID_setct_CapResTBE 582 +#define OBJ_setct_CapResTBE OBJ_set_ctype,64L + +#define SN_setct_CapRevReqTBE "setct-CapRevReqTBE" +#define NID_setct_CapRevReqTBE 583 +#define OBJ_setct_CapRevReqTBE OBJ_set_ctype,65L + +#define SN_setct_CapRevReqTBEX "setct-CapRevReqTBEX" +#define NID_setct_CapRevReqTBEX 584 +#define OBJ_setct_CapRevReqTBEX OBJ_set_ctype,66L + +#define SN_setct_CapRevResTBE "setct-CapRevResTBE" +#define NID_setct_CapRevResTBE 585 +#define OBJ_setct_CapRevResTBE OBJ_set_ctype,67L + +#define SN_setct_CredReqTBE "setct-CredReqTBE" +#define NID_setct_CredReqTBE 586 +#define OBJ_setct_CredReqTBE OBJ_set_ctype,68L + +#define SN_setct_CredReqTBEX "setct-CredReqTBEX" +#define NID_setct_CredReqTBEX 587 +#define OBJ_setct_CredReqTBEX OBJ_set_ctype,69L + +#define SN_setct_CredResTBE "setct-CredResTBE" +#define NID_setct_CredResTBE 588 +#define OBJ_setct_CredResTBE OBJ_set_ctype,70L + +#define SN_setct_CredRevReqTBE "setct-CredRevReqTBE" +#define NID_setct_CredRevReqTBE 589 +#define OBJ_setct_CredRevReqTBE OBJ_set_ctype,71L + +#define SN_setct_CredRevReqTBEX "setct-CredRevReqTBEX" +#define NID_setct_CredRevReqTBEX 590 +#define OBJ_setct_CredRevReqTBEX OBJ_set_ctype,72L + +#define SN_setct_CredRevResTBE "setct-CredRevResTBE" +#define NID_setct_CredRevResTBE 591 +#define OBJ_setct_CredRevResTBE OBJ_set_ctype,73L + +#define SN_setct_BatchAdminReqTBE "setct-BatchAdminReqTBE" +#define NID_setct_BatchAdminReqTBE 592 +#define OBJ_setct_BatchAdminReqTBE OBJ_set_ctype,74L + +#define SN_setct_BatchAdminResTBE "setct-BatchAdminResTBE" +#define NID_setct_BatchAdminResTBE 593 +#define OBJ_setct_BatchAdminResTBE OBJ_set_ctype,75L + +#define SN_setct_RegFormReqTBE "setct-RegFormReqTBE" +#define NID_setct_RegFormReqTBE 594 +#define OBJ_setct_RegFormReqTBE OBJ_set_ctype,76L + +#define SN_setct_CertReqTBE "setct-CertReqTBE" +#define NID_setct_CertReqTBE 595 +#define OBJ_setct_CertReqTBE OBJ_set_ctype,77L + +#define SN_setct_CertReqTBEX "setct-CertReqTBEX" +#define NID_setct_CertReqTBEX 596 +#define OBJ_setct_CertReqTBEX OBJ_set_ctype,78L + +#define SN_setct_CertResTBE "setct-CertResTBE" +#define NID_setct_CertResTBE 597 +#define OBJ_setct_CertResTBE OBJ_set_ctype,79L + +#define SN_setct_CRLNotificationTBS "setct-CRLNotificationTBS" +#define NID_setct_CRLNotificationTBS 598 +#define OBJ_setct_CRLNotificationTBS OBJ_set_ctype,80L + +#define SN_setct_CRLNotificationResTBS "setct-CRLNotificationResTBS" +#define NID_setct_CRLNotificationResTBS 599 +#define OBJ_setct_CRLNotificationResTBS OBJ_set_ctype,81L + +#define SN_setct_BCIDistributionTBS "setct-BCIDistributionTBS" +#define NID_setct_BCIDistributionTBS 600 +#define OBJ_setct_BCIDistributionTBS OBJ_set_ctype,82L + +#define SN_setext_genCrypt "setext-genCrypt" +#define LN_setext_genCrypt "generic cryptogram" +#define NID_setext_genCrypt 601 +#define OBJ_setext_genCrypt OBJ_set_msgExt,1L + +#define SN_setext_miAuth "setext-miAuth" +#define LN_setext_miAuth "merchant initiated auth" +#define NID_setext_miAuth 602 +#define OBJ_setext_miAuth OBJ_set_msgExt,3L + +#define SN_setext_pinSecure "setext-pinSecure" +#define NID_setext_pinSecure 603 +#define OBJ_setext_pinSecure OBJ_set_msgExt,4L + +#define SN_setext_pinAny "setext-pinAny" +#define NID_setext_pinAny 604 +#define OBJ_setext_pinAny OBJ_set_msgExt,5L + +#define SN_setext_track2 "setext-track2" +#define NID_setext_track2 605 +#define OBJ_setext_track2 OBJ_set_msgExt,7L + +#define SN_setext_cv "setext-cv" +#define LN_setext_cv "additional verification" +#define NID_setext_cv 606 +#define OBJ_setext_cv OBJ_set_msgExt,8L + +#define SN_set_policy_root "set-policy-root" +#define NID_set_policy_root 607 +#define OBJ_set_policy_root OBJ_set_policy,0L + +#define SN_setCext_hashedRoot "setCext-hashedRoot" +#define NID_setCext_hashedRoot 608 +#define OBJ_setCext_hashedRoot OBJ_set_certExt,0L + +#define SN_setCext_certType "setCext-certType" +#define NID_setCext_certType 609 +#define OBJ_setCext_certType OBJ_set_certExt,1L + +#define SN_setCext_merchData "setCext-merchData" +#define NID_setCext_merchData 610 +#define OBJ_setCext_merchData OBJ_set_certExt,2L + +#define SN_setCext_cCertRequired "setCext-cCertRequired" +#define NID_setCext_cCertRequired 611 +#define OBJ_setCext_cCertRequired OBJ_set_certExt,3L + +#define SN_setCext_tunneling "setCext-tunneling" +#define NID_setCext_tunneling 612 +#define OBJ_setCext_tunneling OBJ_set_certExt,4L + +#define SN_setCext_setExt "setCext-setExt" +#define NID_setCext_setExt 613 +#define OBJ_setCext_setExt OBJ_set_certExt,5L + +#define SN_setCext_setQualf "setCext-setQualf" +#define NID_setCext_setQualf 614 +#define OBJ_setCext_setQualf OBJ_set_certExt,6L + +#define SN_setCext_PGWYcapabilities "setCext-PGWYcapabilities" +#define NID_setCext_PGWYcapabilities 615 +#define OBJ_setCext_PGWYcapabilities OBJ_set_certExt,7L + +#define SN_setCext_TokenIdentifier "setCext-TokenIdentifier" +#define NID_setCext_TokenIdentifier 616 +#define OBJ_setCext_TokenIdentifier OBJ_set_certExt,8L + +#define SN_setCext_Track2Data "setCext-Track2Data" +#define NID_setCext_Track2Data 617 +#define OBJ_setCext_Track2Data OBJ_set_certExt,9L + +#define SN_setCext_TokenType "setCext-TokenType" +#define NID_setCext_TokenType 618 +#define OBJ_setCext_TokenType OBJ_set_certExt,10L + +#define SN_setCext_IssuerCapabilities "setCext-IssuerCapabilities" +#define NID_setCext_IssuerCapabilities 619 +#define OBJ_setCext_IssuerCapabilities OBJ_set_certExt,11L + +#define SN_setAttr_Cert "setAttr-Cert" +#define NID_setAttr_Cert 620 +#define OBJ_setAttr_Cert OBJ_set_attr,0L + +#define SN_setAttr_PGWYcap "setAttr-PGWYcap" +#define LN_setAttr_PGWYcap "payment gateway capabilities" +#define NID_setAttr_PGWYcap 621 +#define OBJ_setAttr_PGWYcap OBJ_set_attr,1L + +#define SN_setAttr_TokenType "setAttr-TokenType" +#define NID_setAttr_TokenType 622 +#define OBJ_setAttr_TokenType OBJ_set_attr,2L + +#define SN_setAttr_IssCap "setAttr-IssCap" +#define LN_setAttr_IssCap "issuer capabilities" +#define NID_setAttr_IssCap 623 +#define OBJ_setAttr_IssCap OBJ_set_attr,3L + +#define SN_set_rootKeyThumb "set-rootKeyThumb" +#define NID_set_rootKeyThumb 624 +#define OBJ_set_rootKeyThumb OBJ_setAttr_Cert,0L + +#define SN_set_addPolicy "set-addPolicy" +#define NID_set_addPolicy 625 +#define OBJ_set_addPolicy OBJ_setAttr_Cert,1L + +#define SN_setAttr_Token_EMV "setAttr-Token-EMV" +#define NID_setAttr_Token_EMV 626 +#define OBJ_setAttr_Token_EMV OBJ_setAttr_TokenType,1L + +#define SN_setAttr_Token_B0Prime "setAttr-Token-B0Prime" +#define NID_setAttr_Token_B0Prime 627 +#define OBJ_setAttr_Token_B0Prime OBJ_setAttr_TokenType,2L + +#define SN_setAttr_IssCap_CVM "setAttr-IssCap-CVM" +#define NID_setAttr_IssCap_CVM 628 +#define OBJ_setAttr_IssCap_CVM OBJ_setAttr_IssCap,3L + +#define SN_setAttr_IssCap_T2 "setAttr-IssCap-T2" +#define NID_setAttr_IssCap_T2 629 +#define OBJ_setAttr_IssCap_T2 OBJ_setAttr_IssCap,4L + +#define SN_setAttr_IssCap_Sig "setAttr-IssCap-Sig" +#define NID_setAttr_IssCap_Sig 630 +#define OBJ_setAttr_IssCap_Sig OBJ_setAttr_IssCap,5L + +#define SN_setAttr_GenCryptgrm "setAttr-GenCryptgrm" +#define LN_setAttr_GenCryptgrm "generate cryptogram" +#define NID_setAttr_GenCryptgrm 631 +#define OBJ_setAttr_GenCryptgrm OBJ_setAttr_IssCap_CVM,1L + +#define SN_setAttr_T2Enc "setAttr-T2Enc" +#define LN_setAttr_T2Enc "encrypted track 2" +#define NID_setAttr_T2Enc 632 +#define OBJ_setAttr_T2Enc OBJ_setAttr_IssCap_T2,1L + +#define SN_setAttr_T2cleartxt "setAttr-T2cleartxt" +#define LN_setAttr_T2cleartxt "cleartext track 2" +#define NID_setAttr_T2cleartxt 633 +#define OBJ_setAttr_T2cleartxt OBJ_setAttr_IssCap_T2,2L + +#define SN_setAttr_TokICCsig "setAttr-TokICCsig" +#define LN_setAttr_TokICCsig "ICC or token signature" +#define NID_setAttr_TokICCsig 634 +#define OBJ_setAttr_TokICCsig OBJ_setAttr_IssCap_Sig,1L + +#define SN_setAttr_SecDevSig "setAttr-SecDevSig" +#define LN_setAttr_SecDevSig "secure device signature" +#define NID_setAttr_SecDevSig 635 +#define OBJ_setAttr_SecDevSig OBJ_setAttr_IssCap_Sig,2L + +#define SN_set_brand_IATA_ATA "set-brand-IATA-ATA" +#define NID_set_brand_IATA_ATA 636 +#define OBJ_set_brand_IATA_ATA OBJ_set_brand,1L + +#define SN_set_brand_Diners "set-brand-Diners" +#define NID_set_brand_Diners 637 +#define OBJ_set_brand_Diners OBJ_set_brand,30L + +#define SN_set_brand_AmericanExpress "set-brand-AmericanExpress" +#define NID_set_brand_AmericanExpress 638 +#define OBJ_set_brand_AmericanExpress OBJ_set_brand,34L + +#define SN_set_brand_JCB "set-brand-JCB" +#define NID_set_brand_JCB 639 +#define OBJ_set_brand_JCB OBJ_set_brand,35L + +#define SN_set_brand_Visa "set-brand-Visa" +#define NID_set_brand_Visa 640 +#define OBJ_set_brand_Visa OBJ_set_brand,4L + +#define SN_set_brand_MasterCard "set-brand-MasterCard" +#define NID_set_brand_MasterCard 641 +#define OBJ_set_brand_MasterCard OBJ_set_brand,5L + +#define SN_set_brand_Novus "set-brand-Novus" +#define NID_set_brand_Novus 642 +#define OBJ_set_brand_Novus OBJ_set_brand,6011L + +#define SN_des_cdmf "DES-CDMF" +#define LN_des_cdmf "des-cdmf" +#define NID_des_cdmf 643 +#define OBJ_des_cdmf OBJ_rsadsi,3L,10L + +#define SN_rsaOAEPEncryptionSET "rsaOAEPEncryptionSET" +#define NID_rsaOAEPEncryptionSET 644 +#define OBJ_rsaOAEPEncryptionSET OBJ_rsadsi,1L,1L,6L + +#define SN_ipsec3 "Oakley-EC2N-3" +#define LN_ipsec3 "ipsec3" +#define NID_ipsec3 749 + +#define SN_ipsec4 "Oakley-EC2N-4" +#define LN_ipsec4 "ipsec4" +#define NID_ipsec4 750 + +#define SN_whirlpool "whirlpool" +#define NID_whirlpool 804 +#define OBJ_whirlpool OBJ_iso,0L,10118L,3L,0L,55L + +#define SN_cryptopro "cryptopro" +#define NID_cryptopro 805 +#define OBJ_cryptopro OBJ_member_body,643L,2L,2L + +#define SN_cryptocom "cryptocom" +#define NID_cryptocom 806 +#define OBJ_cryptocom OBJ_member_body,643L,2L,9L + +#define SN_id_GostR3411_94_with_GostR3410_2001 "id-GostR3411-94-with-GostR3410-2001" +#define LN_id_GostR3411_94_with_GostR3410_2001 "GOST R 34.11-94 with GOST R 34.10-2001" +#define NID_id_GostR3411_94_with_GostR3410_2001 807 +#define OBJ_id_GostR3411_94_with_GostR3410_2001 OBJ_cryptopro,3L + +#define SN_id_GostR3411_94_with_GostR3410_94 "id-GostR3411-94-with-GostR3410-94" +#define LN_id_GostR3411_94_with_GostR3410_94 "GOST R 34.11-94 with GOST R 34.10-94" +#define NID_id_GostR3411_94_with_GostR3410_94 808 +#define OBJ_id_GostR3411_94_with_GostR3410_94 OBJ_cryptopro,4L + +#define SN_id_GostR3411_94 "md_gost94" +#define LN_id_GostR3411_94 "GOST R 34.11-94" +#define NID_id_GostR3411_94 809 +#define OBJ_id_GostR3411_94 OBJ_cryptopro,9L + +#define SN_id_HMACGostR3411_94 "id-HMACGostR3411-94" +#define LN_id_HMACGostR3411_94 "HMAC GOST 34.11-94" +#define NID_id_HMACGostR3411_94 810 +#define OBJ_id_HMACGostR3411_94 OBJ_cryptopro,10L + +#define SN_id_GostR3410_2001 "gost2001" +#define LN_id_GostR3410_2001 "GOST R 34.10-2001" +#define NID_id_GostR3410_2001 811 +#define OBJ_id_GostR3410_2001 OBJ_cryptopro,19L + +#define SN_id_GostR3410_94 "gost94" +#define LN_id_GostR3410_94 "GOST R 34.10-94" +#define NID_id_GostR3410_94 812 +#define OBJ_id_GostR3410_94 OBJ_cryptopro,20L + +#define SN_id_Gost28147_89 "gost89" +#define LN_id_Gost28147_89 "GOST 28147-89" +#define NID_id_Gost28147_89 813 +#define OBJ_id_Gost28147_89 OBJ_cryptopro,21L + +#define SN_gost89_cnt "gost89-cnt" +#define NID_gost89_cnt 814 + +#define SN_id_Gost28147_89_MAC "gost-mac" +#define LN_id_Gost28147_89_MAC "GOST 28147-89 MAC" +#define NID_id_Gost28147_89_MAC 815 +#define OBJ_id_Gost28147_89_MAC OBJ_cryptopro,22L + +#define SN_id_GostR3411_94_prf "prf-gostr3411-94" +#define LN_id_GostR3411_94_prf "GOST R 34.11-94 PRF" +#define NID_id_GostR3411_94_prf 816 +#define OBJ_id_GostR3411_94_prf OBJ_cryptopro,23L + +#define SN_id_GostR3410_2001DH "id-GostR3410-2001DH" +#define LN_id_GostR3410_2001DH "GOST R 34.10-2001 DH" +#define NID_id_GostR3410_2001DH 817 +#define OBJ_id_GostR3410_2001DH OBJ_cryptopro,98L + +#define SN_id_GostR3410_94DH "id-GostR3410-94DH" +#define LN_id_GostR3410_94DH "GOST R 34.10-94 DH" +#define NID_id_GostR3410_94DH 818 +#define OBJ_id_GostR3410_94DH OBJ_cryptopro,99L + +#define SN_id_Gost28147_89_CryptoPro_KeyMeshing "id-Gost28147-89-CryptoPro-KeyMeshing" +#define NID_id_Gost28147_89_CryptoPro_KeyMeshing 819 +#define OBJ_id_Gost28147_89_CryptoPro_KeyMeshing OBJ_cryptopro,14L,1L + +#define SN_id_Gost28147_89_None_KeyMeshing "id-Gost28147-89-None-KeyMeshing" +#define NID_id_Gost28147_89_None_KeyMeshing 820 +#define OBJ_id_Gost28147_89_None_KeyMeshing OBJ_cryptopro,14L,0L + +#define SN_id_GostR3411_94_TestParamSet "id-GostR3411-94-TestParamSet" +#define NID_id_GostR3411_94_TestParamSet 821 +#define OBJ_id_GostR3411_94_TestParamSet OBJ_cryptopro,30L,0L + +#define SN_id_GostR3411_94_CryptoProParamSet "id-GostR3411-94-CryptoProParamSet" +#define NID_id_GostR3411_94_CryptoProParamSet 822 +#define OBJ_id_GostR3411_94_CryptoProParamSet OBJ_cryptopro,30L,1L + +#define SN_id_Gost28147_89_TestParamSet "id-Gost28147-89-TestParamSet" +#define NID_id_Gost28147_89_TestParamSet 823 +#define OBJ_id_Gost28147_89_TestParamSet OBJ_cryptopro,31L,0L + +#define SN_id_Gost28147_89_CryptoPro_A_ParamSet "id-Gost28147-89-CryptoPro-A-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_A_ParamSet 824 +#define OBJ_id_Gost28147_89_CryptoPro_A_ParamSet OBJ_cryptopro,31L,1L + +#define SN_id_Gost28147_89_CryptoPro_B_ParamSet "id-Gost28147-89-CryptoPro-B-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_B_ParamSet 825 +#define OBJ_id_Gost28147_89_CryptoPro_B_ParamSet OBJ_cryptopro,31L,2L + +#define SN_id_Gost28147_89_CryptoPro_C_ParamSet "id-Gost28147-89-CryptoPro-C-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_C_ParamSet 826 +#define OBJ_id_Gost28147_89_CryptoPro_C_ParamSet OBJ_cryptopro,31L,3L + +#define SN_id_Gost28147_89_CryptoPro_D_ParamSet "id-Gost28147-89-CryptoPro-D-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_D_ParamSet 827 +#define OBJ_id_Gost28147_89_CryptoPro_D_ParamSet OBJ_cryptopro,31L,4L + +#define SN_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet "id-Gost28147-89-CryptoPro-Oscar-1-1-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet 828 +#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet OBJ_cryptopro,31L,5L + +#define SN_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet "id-Gost28147-89-CryptoPro-Oscar-1-0-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet 829 +#define OBJ_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet OBJ_cryptopro,31L,6L + +#define SN_id_Gost28147_89_CryptoPro_RIC_1_ParamSet "id-Gost28147-89-CryptoPro-RIC-1-ParamSet" +#define NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet 830 +#define OBJ_id_Gost28147_89_CryptoPro_RIC_1_ParamSet OBJ_cryptopro,31L,7L + +#define SN_id_GostR3410_94_TestParamSet "id-GostR3410-94-TestParamSet" +#define NID_id_GostR3410_94_TestParamSet 831 +#define OBJ_id_GostR3410_94_TestParamSet OBJ_cryptopro,32L,0L + +#define SN_id_GostR3410_94_CryptoPro_A_ParamSet "id-GostR3410-94-CryptoPro-A-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_A_ParamSet 832 +#define OBJ_id_GostR3410_94_CryptoPro_A_ParamSet OBJ_cryptopro,32L,2L + +#define SN_id_GostR3410_94_CryptoPro_B_ParamSet "id-GostR3410-94-CryptoPro-B-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_B_ParamSet 833 +#define OBJ_id_GostR3410_94_CryptoPro_B_ParamSet OBJ_cryptopro,32L,3L + +#define SN_id_GostR3410_94_CryptoPro_C_ParamSet "id-GostR3410-94-CryptoPro-C-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_C_ParamSet 834 +#define OBJ_id_GostR3410_94_CryptoPro_C_ParamSet OBJ_cryptopro,32L,4L + +#define SN_id_GostR3410_94_CryptoPro_D_ParamSet "id-GostR3410-94-CryptoPro-D-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_D_ParamSet 835 +#define OBJ_id_GostR3410_94_CryptoPro_D_ParamSet OBJ_cryptopro,32L,5L + +#define SN_id_GostR3410_94_CryptoPro_XchA_ParamSet "id-GostR3410-94-CryptoPro-XchA-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchA_ParamSet 836 +#define OBJ_id_GostR3410_94_CryptoPro_XchA_ParamSet OBJ_cryptopro,33L,1L + +#define SN_id_GostR3410_94_CryptoPro_XchB_ParamSet "id-GostR3410-94-CryptoPro-XchB-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchB_ParamSet 837 +#define OBJ_id_GostR3410_94_CryptoPro_XchB_ParamSet OBJ_cryptopro,33L,2L + +#define SN_id_GostR3410_94_CryptoPro_XchC_ParamSet "id-GostR3410-94-CryptoPro-XchC-ParamSet" +#define NID_id_GostR3410_94_CryptoPro_XchC_ParamSet 838 +#define OBJ_id_GostR3410_94_CryptoPro_XchC_ParamSet OBJ_cryptopro,33L,3L + +#define SN_id_GostR3410_2001_TestParamSet "id-GostR3410-2001-TestParamSet" +#define NID_id_GostR3410_2001_TestParamSet 839 +#define OBJ_id_GostR3410_2001_TestParamSet OBJ_cryptopro,35L,0L + +#define SN_id_GostR3410_2001_CryptoPro_A_ParamSet "id-GostR3410-2001-CryptoPro-A-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_A_ParamSet 840 +#define OBJ_id_GostR3410_2001_CryptoPro_A_ParamSet OBJ_cryptopro,35L,1L + +#define SN_id_GostR3410_2001_CryptoPro_B_ParamSet "id-GostR3410-2001-CryptoPro-B-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_B_ParamSet 841 +#define OBJ_id_GostR3410_2001_CryptoPro_B_ParamSet OBJ_cryptopro,35L,2L + +#define SN_id_GostR3410_2001_CryptoPro_C_ParamSet "id-GostR3410-2001-CryptoPro-C-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_C_ParamSet 842 +#define OBJ_id_GostR3410_2001_CryptoPro_C_ParamSet OBJ_cryptopro,35L,3L + +#define SN_id_GostR3410_2001_CryptoPro_XchA_ParamSet "id-GostR3410-2001-CryptoPro-XchA-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet 843 +#define OBJ_id_GostR3410_2001_CryptoPro_XchA_ParamSet OBJ_cryptopro,36L,0L + +#define SN_id_GostR3410_2001_CryptoPro_XchB_ParamSet "id-GostR3410-2001-CryptoPro-XchB-ParamSet" +#define NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet 844 +#define OBJ_id_GostR3410_2001_CryptoPro_XchB_ParamSet OBJ_cryptopro,36L,1L + +#define SN_id_GostR3410_94_a "id-GostR3410-94-a" +#define NID_id_GostR3410_94_a 845 +#define OBJ_id_GostR3410_94_a OBJ_id_GostR3410_94,1L + +#define SN_id_GostR3410_94_aBis "id-GostR3410-94-aBis" +#define NID_id_GostR3410_94_aBis 846 +#define OBJ_id_GostR3410_94_aBis OBJ_id_GostR3410_94,2L + +#define SN_id_GostR3410_94_b "id-GostR3410-94-b" +#define NID_id_GostR3410_94_b 847 +#define OBJ_id_GostR3410_94_b OBJ_id_GostR3410_94,3L + +#define SN_id_GostR3410_94_bBis "id-GostR3410-94-bBis" +#define NID_id_GostR3410_94_bBis 848 +#define OBJ_id_GostR3410_94_bBis OBJ_id_GostR3410_94,4L + +#define SN_id_Gost28147_89_cc "id-Gost28147-89-cc" +#define LN_id_Gost28147_89_cc "GOST 28147-89 Cryptocom ParamSet" +#define NID_id_Gost28147_89_cc 849 +#define OBJ_id_Gost28147_89_cc OBJ_cryptocom,1L,6L,1L + +#define SN_id_GostR3410_94_cc "gost94cc" +#define LN_id_GostR3410_94_cc "GOST 34.10-94 Cryptocom" +#define NID_id_GostR3410_94_cc 850 +#define OBJ_id_GostR3410_94_cc OBJ_cryptocom,1L,5L,3L + +#define SN_id_GostR3410_2001_cc "gost2001cc" +#define LN_id_GostR3410_2001_cc "GOST 34.10-2001 Cryptocom" +#define NID_id_GostR3410_2001_cc 851 +#define OBJ_id_GostR3410_2001_cc OBJ_cryptocom,1L,5L,4L + +#define SN_id_GostR3411_94_with_GostR3410_94_cc "id-GostR3411-94-with-GostR3410-94-cc" +#define LN_id_GostR3411_94_with_GostR3410_94_cc "GOST R 34.11-94 with GOST R 34.10-94 Cryptocom" +#define NID_id_GostR3411_94_with_GostR3410_94_cc 852 +#define OBJ_id_GostR3411_94_with_GostR3410_94_cc OBJ_cryptocom,1L,3L,3L + +#define SN_id_GostR3411_94_with_GostR3410_2001_cc "id-GostR3411-94-with-GostR3410-2001-cc" +#define LN_id_GostR3411_94_with_GostR3410_2001_cc "GOST R 34.11-94 with GOST R 34.10-2001 Cryptocom" +#define NID_id_GostR3411_94_with_GostR3410_2001_cc 853 +#define OBJ_id_GostR3411_94_with_GostR3410_2001_cc OBJ_cryptocom,1L,3L,4L + +#define SN_id_GostR3410_2001_ParamSet_cc "id-GostR3410-2001-ParamSet-cc" +#define LN_id_GostR3410_2001_ParamSet_cc "GOST R 3410-2001 Parameter Set Cryptocom" +#define NID_id_GostR3410_2001_ParamSet_cc 854 +#define OBJ_id_GostR3410_2001_ParamSet_cc OBJ_cryptocom,1L,8L,1L + +#define SN_camellia_128_cbc "CAMELLIA-128-CBC" +#define LN_camellia_128_cbc "camellia-128-cbc" +#define NID_camellia_128_cbc 751 +#define OBJ_camellia_128_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,2L + +#define SN_camellia_192_cbc "CAMELLIA-192-CBC" +#define LN_camellia_192_cbc "camellia-192-cbc" +#define NID_camellia_192_cbc 752 +#define OBJ_camellia_192_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,3L + +#define SN_camellia_256_cbc "CAMELLIA-256-CBC" +#define LN_camellia_256_cbc "camellia-256-cbc" +#define NID_camellia_256_cbc 753 +#define OBJ_camellia_256_cbc 1L,2L,392L,200011L,61L,1L,1L,1L,4L + +#define SN_id_camellia128_wrap "id-camellia128-wrap" +#define NID_id_camellia128_wrap 907 +#define OBJ_id_camellia128_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,2L + +#define SN_id_camellia192_wrap "id-camellia192-wrap" +#define NID_id_camellia192_wrap 908 +#define OBJ_id_camellia192_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,3L + +#define SN_id_camellia256_wrap "id-camellia256-wrap" +#define NID_id_camellia256_wrap 909 +#define OBJ_id_camellia256_wrap 1L,2L,392L,200011L,61L,1L,1L,3L,4L + +#define OBJ_ntt_ds 0L,3L,4401L,5L + +#define OBJ_camellia OBJ_ntt_ds,3L,1L,9L + +#define SN_camellia_128_ecb "CAMELLIA-128-ECB" +#define LN_camellia_128_ecb "camellia-128-ecb" +#define NID_camellia_128_ecb 754 +#define OBJ_camellia_128_ecb OBJ_camellia,1L + +#define SN_camellia_128_ofb128 "CAMELLIA-128-OFB" +#define LN_camellia_128_ofb128 "camellia-128-ofb" +#define NID_camellia_128_ofb128 766 +#define OBJ_camellia_128_ofb128 OBJ_camellia,3L + +#define SN_camellia_128_cfb128 "CAMELLIA-128-CFB" +#define LN_camellia_128_cfb128 "camellia-128-cfb" +#define NID_camellia_128_cfb128 757 +#define OBJ_camellia_128_cfb128 OBJ_camellia,4L + +#define SN_camellia_192_ecb "CAMELLIA-192-ECB" +#define LN_camellia_192_ecb "camellia-192-ecb" +#define NID_camellia_192_ecb 755 +#define OBJ_camellia_192_ecb OBJ_camellia,21L + +#define SN_camellia_192_ofb128 "CAMELLIA-192-OFB" +#define LN_camellia_192_ofb128 "camellia-192-ofb" +#define NID_camellia_192_ofb128 767 +#define OBJ_camellia_192_ofb128 OBJ_camellia,23L + +#define SN_camellia_192_cfb128 "CAMELLIA-192-CFB" +#define LN_camellia_192_cfb128 "camellia-192-cfb" +#define NID_camellia_192_cfb128 758 +#define OBJ_camellia_192_cfb128 OBJ_camellia,24L + +#define SN_camellia_256_ecb "CAMELLIA-256-ECB" +#define LN_camellia_256_ecb "camellia-256-ecb" +#define NID_camellia_256_ecb 756 +#define OBJ_camellia_256_ecb OBJ_camellia,41L + +#define SN_camellia_256_ofb128 "CAMELLIA-256-OFB" +#define LN_camellia_256_ofb128 "camellia-256-ofb" +#define NID_camellia_256_ofb128 768 +#define OBJ_camellia_256_ofb128 OBJ_camellia,43L + +#define SN_camellia_256_cfb128 "CAMELLIA-256-CFB" +#define LN_camellia_256_cfb128 "camellia-256-cfb" +#define NID_camellia_256_cfb128 759 +#define OBJ_camellia_256_cfb128 OBJ_camellia,44L + +#define SN_camellia_128_cfb1 "CAMELLIA-128-CFB1" +#define LN_camellia_128_cfb1 "camellia-128-cfb1" +#define NID_camellia_128_cfb1 760 + +#define SN_camellia_192_cfb1 "CAMELLIA-192-CFB1" +#define LN_camellia_192_cfb1 "camellia-192-cfb1" +#define NID_camellia_192_cfb1 761 + +#define SN_camellia_256_cfb1 "CAMELLIA-256-CFB1" +#define LN_camellia_256_cfb1 "camellia-256-cfb1" +#define NID_camellia_256_cfb1 762 + +#define SN_camellia_128_cfb8 "CAMELLIA-128-CFB8" +#define LN_camellia_128_cfb8 "camellia-128-cfb8" +#define NID_camellia_128_cfb8 763 + +#define SN_camellia_192_cfb8 "CAMELLIA-192-CFB8" +#define LN_camellia_192_cfb8 "camellia-192-cfb8" +#define NID_camellia_192_cfb8 764 + +#define SN_camellia_256_cfb8 "CAMELLIA-256-CFB8" +#define LN_camellia_256_cfb8 "camellia-256-cfb8" +#define NID_camellia_256_cfb8 765 + +#define SN_kisa "KISA" +#define LN_kisa "kisa" +#define NID_kisa 773 +#define OBJ_kisa OBJ_member_body,410L,200004L + +#define SN_seed_ecb "SEED-ECB" +#define LN_seed_ecb "seed-ecb" +#define NID_seed_ecb 776 +#define OBJ_seed_ecb OBJ_kisa,1L,3L + +#define SN_seed_cbc "SEED-CBC" +#define LN_seed_cbc "seed-cbc" +#define NID_seed_cbc 777 +#define OBJ_seed_cbc OBJ_kisa,1L,4L + +#define SN_seed_cfb128 "SEED-CFB" +#define LN_seed_cfb128 "seed-cfb" +#define NID_seed_cfb128 779 +#define OBJ_seed_cfb128 OBJ_kisa,1L,5L + +#define SN_seed_ofb128 "SEED-OFB" +#define LN_seed_ofb128 "seed-ofb" +#define NID_seed_ofb128 778 +#define OBJ_seed_ofb128 OBJ_kisa,1L,6L + +#define SN_hmac "HMAC" +#define LN_hmac "hmac" +#define NID_hmac 855 + +#define SN_cmac "CMAC" +#define LN_cmac "cmac" +#define NID_cmac 894 + +#define SN_rc4_hmac_md5 "RC4-HMAC-MD5" +#define LN_rc4_hmac_md5 "rc4-hmac-md5" +#define NID_rc4_hmac_md5 915 + +#define SN_aes_128_cbc_hmac_sha1 "AES-128-CBC-HMAC-SHA1" +#define LN_aes_128_cbc_hmac_sha1 "aes-128-cbc-hmac-sha1" +#define NID_aes_128_cbc_hmac_sha1 916 + +#define SN_aes_192_cbc_hmac_sha1 "AES-192-CBC-HMAC-SHA1" +#define LN_aes_192_cbc_hmac_sha1 "aes-192-cbc-hmac-sha1" +#define NID_aes_192_cbc_hmac_sha1 917 + +#define SN_aes_256_cbc_hmac_sha1 "AES-256-CBC-HMAC-SHA1" +#define LN_aes_256_cbc_hmac_sha1 "aes-256-cbc-hmac-sha1" +#define NID_aes_256_cbc_hmac_sha1 918 + +#define SN_dhpublicnumber "dhpublicnumber" +#define LN_dhpublicnumber "X9.42 DH" +#define NID_dhpublicnumber 920 +#define OBJ_dhpublicnumber OBJ_ISO_US,10046L,2L,1L + +#define SN_brainpoolP160r1 "brainpoolP160r1" +#define NID_brainpoolP160r1 921 +#define OBJ_brainpoolP160r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,1L + +#define SN_brainpoolP160t1 "brainpoolP160t1" +#define NID_brainpoolP160t1 922 +#define OBJ_brainpoolP160t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,2L + +#define SN_brainpoolP192r1 "brainpoolP192r1" +#define NID_brainpoolP192r1 923 +#define OBJ_brainpoolP192r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,3L + +#define SN_brainpoolP192t1 "brainpoolP192t1" +#define NID_brainpoolP192t1 924 +#define OBJ_brainpoolP192t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,4L + +#define SN_brainpoolP224r1 "brainpoolP224r1" +#define NID_brainpoolP224r1 925 +#define OBJ_brainpoolP224r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,5L + +#define SN_brainpoolP224t1 "brainpoolP224t1" +#define NID_brainpoolP224t1 926 +#define OBJ_brainpoolP224t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,6L + +#define SN_brainpoolP256r1 "brainpoolP256r1" +#define NID_brainpoolP256r1 927 +#define OBJ_brainpoolP256r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,7L + +#define SN_brainpoolP256t1 "brainpoolP256t1" +#define NID_brainpoolP256t1 928 +#define OBJ_brainpoolP256t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,8L + +#define SN_brainpoolP320r1 "brainpoolP320r1" +#define NID_brainpoolP320r1 929 +#define OBJ_brainpoolP320r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,9L + +#define SN_brainpoolP320t1 "brainpoolP320t1" +#define NID_brainpoolP320t1 930 +#define OBJ_brainpoolP320t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,10L + +#define SN_brainpoolP384r1 "brainpoolP384r1" +#define NID_brainpoolP384r1 931 +#define OBJ_brainpoolP384r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,11L + +#define SN_brainpoolP384t1 "brainpoolP384t1" +#define NID_brainpoolP384t1 932 +#define OBJ_brainpoolP384t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,12L + +#define SN_brainpoolP512r1 "brainpoolP512r1" +#define NID_brainpoolP512r1 933 +#define OBJ_brainpoolP512r1 1L,3L,36L,3L,3L,2L,8L,1L,1L,13L + +#define SN_brainpoolP512t1 "brainpoolP512t1" +#define NID_brainpoolP512t1 934 +#define OBJ_brainpoolP512t1 1L,3L,36L,3L,3L,2L,8L,1L,1L,14L + +#define OBJ_x9_63_scheme 1L,3L,133L,16L,840L,63L,0L + +#define OBJ_secg_scheme OBJ_certicom_arc,1L + +#define SN_dhSinglePass_stdDH_sha1kdf_scheme "dhSinglePass-stdDH-sha1kdf-scheme" +#define NID_dhSinglePass_stdDH_sha1kdf_scheme 936 +#define OBJ_dhSinglePass_stdDH_sha1kdf_scheme OBJ_x9_63_scheme,2L + +#define SN_dhSinglePass_stdDH_sha224kdf_scheme "dhSinglePass-stdDH-sha224kdf-scheme" +#define NID_dhSinglePass_stdDH_sha224kdf_scheme 937 +#define OBJ_dhSinglePass_stdDH_sha224kdf_scheme OBJ_secg_scheme,11L,0L + +#define SN_dhSinglePass_stdDH_sha256kdf_scheme "dhSinglePass-stdDH-sha256kdf-scheme" +#define NID_dhSinglePass_stdDH_sha256kdf_scheme 938 +#define OBJ_dhSinglePass_stdDH_sha256kdf_scheme OBJ_secg_scheme,11L,1L + +#define SN_dhSinglePass_stdDH_sha384kdf_scheme "dhSinglePass-stdDH-sha384kdf-scheme" +#define NID_dhSinglePass_stdDH_sha384kdf_scheme 939 +#define OBJ_dhSinglePass_stdDH_sha384kdf_scheme OBJ_secg_scheme,11L,2L + +#define SN_dhSinglePass_stdDH_sha512kdf_scheme "dhSinglePass-stdDH-sha512kdf-scheme" +#define NID_dhSinglePass_stdDH_sha512kdf_scheme 940 +#define OBJ_dhSinglePass_stdDH_sha512kdf_scheme OBJ_secg_scheme,11L,3L + +#define SN_dhSinglePass_cofactorDH_sha1kdf_scheme "dhSinglePass-cofactorDH-sha1kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha1kdf_scheme 941 +#define OBJ_dhSinglePass_cofactorDH_sha1kdf_scheme OBJ_x9_63_scheme,3L + +#define SN_dhSinglePass_cofactorDH_sha224kdf_scheme "dhSinglePass-cofactorDH-sha224kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha224kdf_scheme 942 +#define OBJ_dhSinglePass_cofactorDH_sha224kdf_scheme OBJ_secg_scheme,14L,0L + +#define SN_dhSinglePass_cofactorDH_sha256kdf_scheme "dhSinglePass-cofactorDH-sha256kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha256kdf_scheme 943 +#define OBJ_dhSinglePass_cofactorDH_sha256kdf_scheme OBJ_secg_scheme,14L,1L + +#define SN_dhSinglePass_cofactorDH_sha384kdf_scheme "dhSinglePass-cofactorDH-sha384kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha384kdf_scheme 944 +#define OBJ_dhSinglePass_cofactorDH_sha384kdf_scheme OBJ_secg_scheme,14L,2L + +#define SN_dhSinglePass_cofactorDH_sha512kdf_scheme "dhSinglePass-cofactorDH-sha512kdf-scheme" +#define NID_dhSinglePass_cofactorDH_sha512kdf_scheme 945 +#define OBJ_dhSinglePass_cofactorDH_sha512kdf_scheme OBJ_secg_scheme,14L,3L + +#define SN_dh_std_kdf "dh-std-kdf" +#define NID_dh_std_kdf 946 + +#define SN_dh_cofactor_kdf "dh-cofactor-kdf" +#define NID_dh_cofactor_kdf 947 + diff --git a/TMessagesProj/jni/boringssl/include/openssl/objects.h b/TMessagesProj/jni/boringssl/include/openssl/objects.h new file mode 100644 index 00000000..dd6556f2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/objects.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "obj.h" diff --git a/TMessagesProj/jni/boringssl/include/openssl/opensslfeatures.h b/TMessagesProj/jni/boringssl/include/openssl/opensslfeatures.h new file mode 100644 index 00000000..73814e54 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/opensslfeatures.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#ifndef OPENSSL_HEADER_OPENSSLFEATURES_H +#define OPENSSL_HEADER_OPENSSLFEATURES_H + +#define TRUSTY +#define OPENSSL_NO_BF +#define OPENSSL_NO_BUF_FREELISTS +#define OPENSSL_NO_CAMELLIA +#define OPENSSL_NO_CAPIENG +#define OPENSSL_NO_CAST +#define OPENSSL_NO_CMS +#define OPENSSL_NO_COMP +#define OPENSSL_NO_DANE +#define OPENSSL_NO_DEPRECATED +#define OPENSSL_NO_DYNAMIC_ENGINE +#define OPENSSL_NO_EC_NISTP_64_GCC_128 +#define OPENSSL_NO_EC2M +#define OPENSSL_NO_ENGINE +#define OPENSSL_NO_GMP +#define OPENSSL_NO_GOST +#define OPENSSL_NO_HEARTBEATS +#define OPENSSL_NO_HW +#define OPENSSL_NO_IDEA +#define OPENSSL_NO_JPAKE +#define OPENSSL_NO_KRB5 +#define OPENSSL_NO_MD2 +#define OPENSSL_NO_MDC2 +#define OPENSSL_NO_OCB +#define OPENSSL_NO_OCSP +#define OPENSSL_NO_RC2 +#define OPENSSL_NO_RC5 +#define OPENSSL_NO_RFC3779 +#define OPENSSL_NO_RIPEMD +#define OPENSSL_NO_RMD160 +#define OPENSSL_NO_SCTP +#define OPENSSL_NO_SEED +#define OPENSSL_NO_SRP +#define OPENSSL_NO_SSL2 +#define OPENSSL_NO_STATIC_ENGINE +#define OPENSSL_NO_STORE +#define OPENSSL_NO_WHIRLPOOL + + +#endif /* OPENSSL_HEADER_OPENSSLFEATURES_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/opensslv.h b/TMessagesProj/jni/boringssl/include/openssl/opensslv.h new file mode 100644 index 00000000..a3555d4f --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/opensslv.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "crypto.h" diff --git a/TMessagesProj/jni/boringssl/include/openssl/ossl_typ.h b/TMessagesProj/jni/boringssl/include/openssl/ossl_typ.h new file mode 100644 index 00000000..c2b3fe7c --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ossl_typ.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "base.h" diff --git a/TMessagesProj/jni/boringssl/include/openssl/pem.h b/TMessagesProj/jni/boringssl/include/openssl/pem.h new file mode 100644 index 00000000..db763d5a --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/pem.h @@ -0,0 +1,521 @@ +/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_PEM_H +#define OPENSSL_HEADER_PEM_H + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define PEM_BUFSIZE 1024 + +#define PEM_OBJ_UNDEF 0 +#define PEM_OBJ_X509 1 +#define PEM_OBJ_X509_REQ 2 +#define PEM_OBJ_CRL 3 +#define PEM_OBJ_SSL_SESSION 4 +#define PEM_OBJ_PRIV_KEY 10 +#define PEM_OBJ_PRIV_RSA 11 +#define PEM_OBJ_PRIV_DSA 12 +#define PEM_OBJ_PRIV_DH 13 +#define PEM_OBJ_PUB_RSA 14 +#define PEM_OBJ_PUB_DSA 15 +#define PEM_OBJ_PUB_DH 16 +#define PEM_OBJ_DHPARAMS 17 +#define PEM_OBJ_DSAPARAMS 18 +#define PEM_OBJ_PRIV_RSA_PUBLIC 19 +#define PEM_OBJ_PRIV_ECDSA 20 +#define PEM_OBJ_PUB_ECDSA 21 +#define PEM_OBJ_ECPARAMETERS 22 + +#define PEM_ERROR 30 +#define PEM_DEK_DES_CBC 40 +#define PEM_DEK_IDEA_CBC 45 +#define PEM_DEK_DES_EDE 50 +#define PEM_DEK_DES_ECB 60 +#define PEM_DEK_RSA 70 +#define PEM_DEK_RSA_MD2 80 +#define PEM_DEK_RSA_MD5 90 + +#define PEM_MD_MD2 NID_md2 +#define PEM_MD_MD5 NID_md5 +#define PEM_MD_SHA NID_sha +#define PEM_MD_MD2_RSA NID_md2WithRSAEncryption +#define PEM_MD_MD5_RSA NID_md5WithRSAEncryption +#define PEM_MD_SHA_RSA NID_sha1WithRSAEncryption + +#define PEM_STRING_X509_OLD "X509 CERTIFICATE" +#define PEM_STRING_X509 "CERTIFICATE" +#define PEM_STRING_X509_PAIR "CERTIFICATE PAIR" +#define PEM_STRING_X509_TRUSTED "TRUSTED CERTIFICATE" +#define PEM_STRING_X509_REQ_OLD "NEW CERTIFICATE REQUEST" +#define PEM_STRING_X509_REQ "CERTIFICATE REQUEST" +#define PEM_STRING_X509_CRL "X509 CRL" +#define PEM_STRING_EVP_PKEY "ANY PRIVATE KEY" +#define PEM_STRING_PUBLIC "PUBLIC KEY" +#define PEM_STRING_RSA "RSA PRIVATE KEY" +#define PEM_STRING_RSA_PUBLIC "RSA PUBLIC KEY" +#define PEM_STRING_DSA "DSA PRIVATE KEY" +#define PEM_STRING_DSA_PUBLIC "DSA PUBLIC KEY" +#define PEM_STRING_PKCS7 "PKCS7" +#define PEM_STRING_PKCS7_SIGNED "PKCS #7 SIGNED DATA" +#define PEM_STRING_PKCS8 "ENCRYPTED PRIVATE KEY" +#define PEM_STRING_PKCS8INF "PRIVATE KEY" +#define PEM_STRING_DHPARAMS "DH PARAMETERS" +#define PEM_STRING_DHXPARAMS "X9.42 DH PARAMETERS" +#define PEM_STRING_SSL_SESSION "SSL SESSION PARAMETERS" +#define PEM_STRING_DSAPARAMS "DSA PARAMETERS" +#define PEM_STRING_ECDSA_PUBLIC "ECDSA PUBLIC KEY" +#define PEM_STRING_ECPARAMETERS "EC PARAMETERS" +#define PEM_STRING_ECPRIVATEKEY "EC PRIVATE KEY" +#define PEM_STRING_PARAMETERS "PARAMETERS" +#define PEM_STRING_CMS "CMS" + + /* Note that this structure is initialised by PEM_SealInit and cleaned up + by PEM_SealFinal (at least for now) */ +typedef struct PEM_Encode_Seal_st + { + EVP_ENCODE_CTX encode; + EVP_MD_CTX md; + EVP_CIPHER_CTX cipher; + } PEM_ENCODE_SEAL_CTX; + +/* enc_type is one off */ +#define PEM_TYPE_ENCRYPTED 10 +#define PEM_TYPE_MIC_ONLY 20 +#define PEM_TYPE_MIC_CLEAR 30 +#define PEM_TYPE_CLEAR 40 + +typedef struct pem_recip_st + { + char *name; + X509_NAME *dn; + + int cipher; + int key_enc; + /* char iv[8]; unused and wrong size */ + } PEM_USER; + +typedef struct pem_ctx_st + { + int type; /* what type of object */ + + struct { + int version; + int mode; + } proc_type; + + char *domain; + + struct { + int cipher; + /* unused, and wrong size + unsigned char iv[8]; */ + } DEK_info; + + PEM_USER *originator; + + int num_recipient; + PEM_USER **recipient; + + EVP_MD *md; /* signature type */ + + int md_enc; /* is the md encrypted or not? */ + int md_len; /* length of md_data */ + char *md_data; /* message digest, could be pkey encrypted */ + + EVP_CIPHER *dec; /* date encryption cipher */ + int key_len; /* key length */ + unsigned char *key; /* key */ + /* unused, and wrong size + unsigned char iv[8]; */ + + + int data_enc; /* is the data encrypted */ + int data_len; + unsigned char *data; + } PEM_CTX; + +/* These macros make the PEM_read/PEM_write functions easier to maintain and + * write. Now they are all implemented with either: + * IMPLEMENT_PEM_rw(...) or IMPLEMENT_PEM_rw_cb(...) + */ + +#ifdef OPENSSL_NO_FP_API + +#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) /**/ +#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) /**/ +#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) /**/ +#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) /**/ +#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) /**/ + +#else + +#define IMPLEMENT_PEM_read_fp(name, type, str, asn1) \ +OPENSSL_EXPORT type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u)\ +{ \ +return PEM_ASN1_read((d2i_of_void *)d2i_##asn1, str,fp,(void **)x,cb,u); \ +} + +#define IMPLEMENT_PEM_write_fp(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x) \ +{ \ +return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,NULL,NULL,0,NULL,NULL); \ +} + +#define IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_##name(FILE *fp, const type *x) \ +{ \ +return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,(void *)x,NULL,NULL,0,NULL,NULL); \ +} + +#define IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, \ + void *u) \ + { \ + return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u); \ + } + +#define IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, \ + void *u) \ + { \ + return PEM_ASN1_write((i2d_of_void *)i2d_##asn1,str,fp,x,enc,kstr,klen,cb,u); \ + } + +#endif + +#define IMPLEMENT_PEM_read_bio(name, type, str, asn1) \ +OPENSSL_EXPORT type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u)\ +{ \ +return PEM_ASN1_read_bio((d2i_of_void *)d2i_##asn1, str,bp,(void **)x,cb,u); \ +} + +#define IMPLEMENT_PEM_write_bio(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x) \ +{ \ +return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,x,NULL,NULL,0,NULL,NULL); \ +} + +#define IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, const type *x) \ +{ \ +return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,(void *)x,NULL,NULL,0,NULL,NULL); \ +} + +#define IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \ + { \ + return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,x,enc,kstr,klen,cb,u); \ + } + +#define IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \ +OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u) \ + { \ + return PEM_ASN1_write_bio((i2d_of_void *)i2d_##asn1,str,bp,(void *)x,enc,kstr,klen,cb,u); \ + } + +#define IMPLEMENT_PEM_write(name, type, str, asn1) \ + IMPLEMENT_PEM_write_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_write_fp(name, type, str, asn1) + +#define IMPLEMENT_PEM_write_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_bio_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_fp_const(name, type, str, asn1) + +#define IMPLEMENT_PEM_write_cb(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_fp(name, type, str, asn1) + +#define IMPLEMENT_PEM_write_cb_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_bio_const(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb_fp_const(name, type, str, asn1) + +#define IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_read_bio(name, type, str, asn1) \ + IMPLEMENT_PEM_read_fp(name, type, str, asn1) + +#define IMPLEMENT_PEM_rw(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write(name, type, str, asn1) + +#define IMPLEMENT_PEM_rw_const(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write_const(name, type, str, asn1) + +#define IMPLEMENT_PEM_rw_cb(name, type, str, asn1) \ + IMPLEMENT_PEM_read(name, type, str, asn1) \ + IMPLEMENT_PEM_write_cb(name, type, str, asn1) + +/* These are the same except they are for the declarations */ + +#if defined(OPENSSL_NO_FP_API) + +#define DECLARE_PEM_read_fp(name, type) /**/ +#define DECLARE_PEM_write_fp(name, type) /**/ +#define DECLARE_PEM_write_cb_fp(name, type) /**/ + +#else + +#define DECLARE_PEM_read_fp(name, type) \ + OPENSSL_EXPORT type *PEM_read_##name(FILE *fp, type **x, pem_password_cb *cb, void *u); + +#define DECLARE_PEM_write_fp(name, type) \ + OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x); + +#define DECLARE_PEM_write_fp_const(name, type) \ + OPENSSL_EXPORT int PEM_write_##name(FILE *fp, const type *x); + +#define DECLARE_PEM_write_cb_fp(name, type) \ + OPENSSL_EXPORT int PEM_write_##name(FILE *fp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u); + +#endif + +#define DECLARE_PEM_read_bio(name, type) \ + OPENSSL_EXPORT type *PEM_read_bio_##name(BIO *bp, type **x, pem_password_cb *cb, void *u); + +#define DECLARE_PEM_write_bio(name, type) \ + OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x); + +#define DECLARE_PEM_write_bio_const(name, type) \ + OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, const type *x); + +#define DECLARE_PEM_write_cb_bio(name, type) \ + OPENSSL_EXPORT int PEM_write_bio_##name(BIO *bp, type *x, const EVP_CIPHER *enc, \ + unsigned char *kstr, int klen, pem_password_cb *cb, void *u); + + +#define DECLARE_PEM_write(name, type) \ + DECLARE_PEM_write_bio(name, type) \ + DECLARE_PEM_write_fp(name, type) + +#define DECLARE_PEM_write_const(name, type) \ + DECLARE_PEM_write_bio_const(name, type) \ + DECLARE_PEM_write_fp_const(name, type) + +#define DECLARE_PEM_write_cb(name, type) \ + DECLARE_PEM_write_cb_bio(name, type) \ + DECLARE_PEM_write_cb_fp(name, type) + +#define DECLARE_PEM_read(name, type) \ + DECLARE_PEM_read_bio(name, type) \ + DECLARE_PEM_read_fp(name, type) + +#define DECLARE_PEM_rw(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write(name, type) + +#define DECLARE_PEM_rw_const(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write_const(name, type) + +#define DECLARE_PEM_rw_cb(name, type) \ + DECLARE_PEM_read(name, type) \ + DECLARE_PEM_write_cb(name, type) + +/* "userdata": new with OpenSSL 0.9.4 */ +typedef int pem_password_cb(char *buf, int size, int rwflag, void *userdata); + +OPENSSL_EXPORT int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher); +OPENSSL_EXPORT int PEM_do_header (EVP_CIPHER_INFO *cipher, unsigned char *data,long *len, pem_password_cb *callback,void *u); + +OPENSSL_EXPORT int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,long *len); +OPENSSL_EXPORT int PEM_write_bio(BIO *bp,const char *name, const char *hdr, const unsigned char *data, long len); +OPENSSL_EXPORT int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, const char *name, BIO *bp, pem_password_cb *cb, void *u); +OPENSSL_EXPORT void * PEM_ASN1_read_bio(d2i_of_void *d2i, const char *name, BIO *bp, void **x, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_ASN1_write_bio(i2d_of_void *i2d,const char *name,BIO *bp, void *x, const EVP_CIPHER *enc,unsigned char *kstr,int klen, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT STACK_OF(X509_INFO) * PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_X509_INFO_write_bio(BIO *bp,X509_INFO *xi, EVP_CIPHER *enc, unsigned char *kstr, int klen, pem_password_cb *cd, void *u); + +OPENSSL_EXPORT int PEM_read(FILE *fp, char **name, char **header, unsigned char **data,long *len); +OPENSSL_EXPORT int PEM_write(FILE *fp, const char *name, const char *hdr, const unsigned char *data, long len); +OPENSSL_EXPORT void * PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_ASN1_write(i2d_of_void *i2d,const char *name,FILE *fp, void *x,const EVP_CIPHER *enc,unsigned char *kstr, int klen,pem_password_cb *callback, void *u); +OPENSSL_EXPORT STACK_OF(X509_INFO) * PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT int PEM_SealInit(PEM_ENCODE_SEAL_CTX *ctx, EVP_CIPHER *type, EVP_MD *md_type, unsigned char **ek, int *ekl, unsigned char *iv, EVP_PKEY **pubk, int npubk); +OPENSSL_EXPORT void PEM_SealUpdate(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *out, int *outl, unsigned char *in, int inl); +OPENSSL_EXPORT int PEM_SealFinal(PEM_ENCODE_SEAL_CTX *ctx, unsigned char *sig,int *sigl, unsigned char *out, int *outl, EVP_PKEY *priv); + +OPENSSL_EXPORT void PEM_SignInit(EVP_MD_CTX *ctx, EVP_MD *type); +OPENSSL_EXPORT void PEM_SignUpdate(EVP_MD_CTX *ctx,unsigned char *d,unsigned int cnt); +OPENSSL_EXPORT int PEM_SignFinal(EVP_MD_CTX *ctx, unsigned char *sigret, unsigned int *siglen, EVP_PKEY *pkey); + +/* PEM_def_callback treats |userdata| as a string and copies it into |buf|, + * assuming its |size| is sufficient. Returns the length of the string, or 0 + * if there is not enough room. If either |buf| or |userdata| is NULL, 0 is + * returned. Note that this is different from OpenSSL, which prompts for a + * password. */ +OPENSSL_EXPORT int PEM_def_callback(char *buf, int size, int rwflag, void *userdata); +OPENSSL_EXPORT void PEM_proc_type(char *buf, int type); +OPENSSL_EXPORT void PEM_dek_info(char *buf, const char *type, int len, char *str); + + +DECLARE_PEM_rw(X509, X509) + +DECLARE_PEM_rw(X509_AUX, X509) + +DECLARE_PEM_rw(X509_CERT_PAIR, X509_CERT_PAIR) + +DECLARE_PEM_rw(X509_REQ, X509_REQ) +DECLARE_PEM_write(X509_REQ_NEW, X509_REQ) + +DECLARE_PEM_rw(X509_CRL, X509_CRL) + +/* DECLARE_PEM_rw(PKCS7, PKCS7) */ + +DECLARE_PEM_rw(NETSCAPE_CERT_SEQUENCE, NETSCAPE_CERT_SEQUENCE) + +DECLARE_PEM_rw(PKCS8, X509_SIG) + +DECLARE_PEM_rw(PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO) + +DECLARE_PEM_rw_cb(RSAPrivateKey, RSA) + +DECLARE_PEM_rw_const(RSAPublicKey, RSA) +DECLARE_PEM_rw(RSA_PUBKEY, RSA) + +#ifndef OPENSSL_NO_DSA + +DECLARE_PEM_rw_cb(DSAPrivateKey, DSA) + +DECLARE_PEM_rw(DSA_PUBKEY, DSA) + +DECLARE_PEM_rw_const(DSAparams, DSA) + +#endif + +DECLARE_PEM_rw_const(ECPKParameters, EC_GROUP) +DECLARE_PEM_rw_cb(ECPrivateKey, EC_KEY) +DECLARE_PEM_rw(EC_PUBKEY, EC_KEY) + + +DECLARE_PEM_rw_const(DHparams, DH) +DECLARE_PEM_write_const(DHxparams, DH) + + +DECLARE_PEM_rw_cb(PrivateKey, EVP_PKEY) + +DECLARE_PEM_rw(PUBKEY, EVP_PKEY) + +OPENSSL_EXPORT int PEM_write_bio_PKCS8PrivateKey_nid(BIO *bp, EVP_PKEY *x, int nid, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *, char *, int, pem_password_cb *, void *); +OPENSSL_EXPORT int i2d_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY *x, const EVP_CIPHER *enc, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int i2d_PKCS8PrivateKey_nid_bio(BIO *bp, EVP_PKEY *x, int nid, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT int i2d_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY *x, const EVP_CIPHER *enc, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int i2d_PKCS8PrivateKey_nid_fp(FILE *fp, EVP_PKEY *x, int nid, char *kstr, int klen, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int PEM_write_PKCS8PrivateKey_nid(FILE *fp, EVP_PKEY *x, int nid, char *kstr, int klen, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT EVP_PKEY *d2i_PKCS8PrivateKey_fp(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u); + +OPENSSL_EXPORT int PEM_write_PKCS8PrivateKey(FILE *fp,EVP_PKEY *x,const EVP_CIPHER *enc, char *kstr,int klen, pem_password_cb *cd, void *u); + +OPENSSL_EXPORT EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x); +OPENSSL_EXPORT int PEM_write_bio_Parameters(BIO *bp, EVP_PKEY *x); + + +OPENSSL_EXPORT EVP_PKEY *b2i_PrivateKey(const unsigned char **in, long length); +OPENSSL_EXPORT EVP_PKEY *b2i_PublicKey(const unsigned char **in, long length); +OPENSSL_EXPORT EVP_PKEY *b2i_PrivateKey_bio(BIO *in); +OPENSSL_EXPORT EVP_PKEY *b2i_PublicKey_bio(BIO *in); +OPENSSL_EXPORT int i2b_PrivateKey_bio(BIO *out, EVP_PKEY *pk); +OPENSSL_EXPORT int i2b_PublicKey_bio(BIO *out, EVP_PKEY *pk); +OPENSSL_EXPORT EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u); +OPENSSL_EXPORT int i2b_PVK_bio(BIO *out, EVP_PKEY *pk, int enclevel, pem_password_cb *cb, void *u); + + +void ERR_load_PEM_strings(void); + + +#ifdef __cplusplus +} +#endif + +#define PEM_R_BAD_BASE64_DECODE 100 +#define PEM_R_BAD_DECRYPT 101 +#define PEM_R_BAD_END_LINE 102 +#define PEM_R_BAD_IV_CHARS 103 +#define PEM_R_BAD_PASSWORD_READ 104 +#define PEM_R_CIPHER_IS_NULL 105 +#define PEM_R_ERROR_CONVERTING_PRIVATE_KEY 106 +#define PEM_R_NOT_DEK_INFO 107 +#define PEM_R_NOT_ENCRYPTED 108 +#define PEM_R_NOT_PROC_TYPE 109 +#define PEM_R_NO_START_LINE 110 +#define PEM_R_READ_KEY 111 +#define PEM_R_SHORT_HEADER 112 +#define PEM_R_UNSUPPORTED_CIPHER 113 +#define PEM_R_UNSUPPORTED_ENCRYPTION 114 + +#endif /* OPENSSL_HEADER_PEM_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/pkcs12.h b/TMessagesProj/jni/boringssl/include/openssl/pkcs12.h new file mode 100644 index 00000000..b5e95163 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/pkcs12.h @@ -0,0 +1,18 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ + +#include "pkcs8.h" diff --git a/TMessagesProj/jni/boringssl/include/openssl/pkcs7.h b/TMessagesProj/jni/boringssl/include/openssl/pkcs7.h new file mode 100644 index 00000000..6e5e4330 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/pkcs7.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/pkcs8.h b/TMessagesProj/jni/boringssl/include/openssl/pkcs8.h new file mode 100644 index 00000000..677b46f2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/pkcs8.h @@ -0,0 +1,199 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. + */ +/* ==================================================================== + * Copyright (c) 1999 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + + +#ifndef OPENSSL_HEADER_PKCS8_H +#define OPENSSL_HEADER_PKCS8_H + +#include +#include + + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* PKCS8_encrypt_pbe serializes and encrypts a PKCS8_PRIV_KEY_INFO with PBES1 as + * defined in PKCS #5. Only pbeWithSHAAnd128BitRC4, + * pbeWithSHAAnd3-KeyTripleDES-CBC and pbeWithSHA1And40BitRC2, defined in PKCS + * #12, are supported. The |pass_raw_len| bytes pointed to by |pass_raw| are + * used as the password. Note that any conversions from the password as + * supplied in a text string (such as those specified in B.1 of PKCS #12) must + * be performed by the caller. + * + * If |salt| is NULL, a random salt of |salt_len| bytes is generated. If + * |salt_len| is zero, a default salt length is used instead. + * + * The resulting structure is stored in an X509_SIG which must be freed by the + * caller. + * + * TODO(davidben): Really? An X509_SIG? OpenSSL probably did that because it has + * the same structure as EncryptedPrivateKeyInfo. */ +OPENSSL_EXPORT X509_SIG *PKCS8_encrypt_pbe(int pbe_nid, + const uint8_t *pass_raw, + size_t pass_raw_len, + uint8_t *salt, size_t salt_len, + int iterations, + PKCS8_PRIV_KEY_INFO *p8inf); + +/* PKCS8_decrypt_pbe decrypts and decodes a PKCS8_PRIV_KEY_INFO with PBES1 as + * defined in PKCS #5. Only pbeWithSHAAnd128BitRC4, + * pbeWithSHAAnd3-KeyTripleDES-CBC and pbeWithSHA1And40BitRC2, defined in PKCS + * #12, are supported. The |pass_raw_len| bytes pointed to by |pass_raw| are + * used as the password. Note that any conversions from the password as + * supplied in a text string (such as those specified in B.1 of PKCS #12) must + * be performed by the caller. + * + * The resulting structure must be freed by the caller. */ +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_decrypt_pbe(X509_SIG *pkcs8, + const uint8_t *pass_raw, + size_t pass_raw_len); + + +/* Deprecated functions. */ + +/* PKCS8_encrypt calls PKCS8_encrypt_pbe after treating |pass| as an ASCII + * string, appending U+0000, and converting to UCS-2. (So the empty password + * encodes as two NUL bytes.) The |cipher| argument is ignored. */ +OPENSSL_EXPORT X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, + const char *pass, int pass_len, + uint8_t *salt, size_t salt_len, + int iterations, + PKCS8_PRIV_KEY_INFO *p8inf); + +/* PKCS8_decrypt calls PKCS8_decrypt_pbe after treating |pass| as an ASCII + * string, appending U+0000, and converting to UCS-2. (So the empty password + * encodes as two NUL bytes.) */ +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, + const char *pass, + int pass_len); + +/* PKCS12_get_key_and_certs parses a PKCS#12 structure from |in|, authenticates + * and decrypts it using |password|, sets |*out_key| to the included private + * key and appends the included certificates to |out_certs|. It returns one on + * success and zero on error. The caller takes ownership of the outputs. */ +OPENSSL_EXPORT int PKCS12_get_key_and_certs(EVP_PKEY **out_key, + STACK_OF(X509) *out_certs, + CBS *in, const char *password); + + +/* Deprecated functions. */ + +/* PKCS12_PBE_add does nothing. It exists for compatibility with OpenSSL. */ +OPENSSL_EXPORT void PKCS12_PBE_add(void); + +/* d2i_PKCS12 is a dummy function that copies |*ber_bytes| into a + * |PKCS12| structure. The |out_p12| argument must be NULL. On exit, + * |*ber_bytes| will be advanced by |ber_len|. It returns a fresh |PKCS12| + * structure or NULL on error. + * + * Note: unlike other d2i functions, |d2i_PKCS12| will always consume |ber_len| + * bytes.*/ +OPENSSL_EXPORT PKCS12 *d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes, + size_t ber_len); + +/* d2i_PKCS12_bio acts like |d2i_PKCS12| but reads from a |BIO|. */ +OPENSSL_EXPORT PKCS12* d2i_PKCS12_bio(BIO *bio, PKCS12 **out_p12); + +/* d2i_PKCS12_fp acts like |d2i_PKCS12| but reads from a |FILE|. */ +OPENSSL_EXPORT PKCS12* d2i_PKCS12_fp(FILE *fp, PKCS12 **out_p12); + +/* PKCS12_parse calls |PKCS12_get_key_and_certs| on the ASN.1 data stored in + * |p12|. The |out_pkey| and |out_cert| arguments must not be NULL and, on + * successful exit, the private key and first certificate will be stored in + * them. The |out_ca_certs| argument may be NULL but, if not, then any extra + * certificates will be appended to |*out_ca_certs|. If |*out_ca_certs| is NULL + * then it will be set to a freshly allocated stack containing the extra certs. + * + * It returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS12_parse(const PKCS12 *p12, const char *password, + EVP_PKEY **out_pkey, X509 **out_cert, + STACK_OF(X509) **out_ca_certs); + +/* PKCS12_free frees |p12| and its contents. */ +OPENSSL_EXPORT void PKCS12_free(PKCS12 *p12); + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define PKCS8_R_BAD_PKCS12_DATA 100 +#define PKCS8_R_BAD_PKCS12_VERSION 101 +#define PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER 102 +#define PKCS8_R_CRYPT_ERROR 103 +#define PKCS8_R_DECODE_ERROR 104 +#define PKCS8_R_ENCODE_ERROR 105 +#define PKCS8_R_ENCRYPT_ERROR 106 +#define PKCS8_R_ERROR_SETTING_CIPHER_PARAMS 107 +#define PKCS8_R_INCORRECT_PASSWORD 108 +#define PKCS8_R_KEYGEN_FAILURE 109 +#define PKCS8_R_KEY_GEN_ERROR 110 +#define PKCS8_R_METHOD_NOT_SUPPORTED 111 +#define PKCS8_R_MISSING_MAC 112 +#define PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12 113 +#define PKCS8_R_PKCS12_PUBLIC_KEY_INTEGRITY_NOT_SUPPORTED 114 +#define PKCS8_R_PKCS12_TOO_DEEPLY_NESTED 115 +#define PKCS8_R_PRIVATE_KEY_DECODE_ERROR 116 +#define PKCS8_R_PRIVATE_KEY_ENCODE_ERROR 117 +#define PKCS8_R_TOO_LONG 118 +#define PKCS8_R_UNKNOWN_ALGORITHM 119 +#define PKCS8_R_UNKNOWN_CIPHER 120 +#define PKCS8_R_UNKNOWN_CIPHER_ALGORITHM 121 +#define PKCS8_R_UNKNOWN_DIGEST 122 +#define PKCS8_R_UNKNOWN_HASH 123 +#define PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM 124 + +#endif /* OPENSSL_HEADER_PKCS8_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/poly1305.h b/TMessagesProj/jni/boringssl/include/openssl/poly1305.h new file mode 100644 index 00000000..0da9f6e1 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/poly1305.h @@ -0,0 +1,50 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_POLY1305_H +#define OPENSSL_HEADER_POLY1305_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef uint8_t poly1305_state[512]; + +/* poly1305_init sets up |state| so that it can be used to calculate an + * authentication tag with the one-time key |key|. Note that |key| is a + * one-time key and therefore there is no `reset' method because that would + * enable several messages to be authenticated with the same key. */ +OPENSSL_EXPORT void CRYPTO_poly1305_init(poly1305_state* state, + const uint8_t key[32]); + +/* poly1305_update processes |in_len| bytes from |in|. It can be called zero or + * more times after poly1305_init. */ +OPENSSL_EXPORT void CRYPTO_poly1305_update(poly1305_state* state, + const uint8_t* in, + size_t in_len); + +/* poly1305_finish completes the poly1305 calculation and writes a 16 byte + * authentication tag to |mac|. The |mac| address must be 16-byte aligned. */ +OPENSSL_EXPORT void CRYPTO_poly1305_finish(poly1305_state* state, + uint8_t mac[16]); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_POLY1305_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/pqueue.h b/TMessagesProj/jni/boringssl/include/openssl/pqueue.h new file mode 100644 index 00000000..ceb1fa2a --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/pqueue.h @@ -0,0 +1,146 @@ +/* + * DTLS implementation written by Nagendra Modadugu + * (nagendra@cs.stanford.edu) for the OpenSSL project 2005. + */ +/* ==================================================================== + * Copyright (c) 1999-2005 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_PQUEUE_H +#define OPENSSL_HEADER_PQUEUE_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Priority queue. + * + * The priority queue maintains a linked-list of nodes, each with a unique, + * 64-bit priority, in ascending priority order. */ + +typedef struct _pqueue *pqueue; + +typedef struct _pitem { + uint8_t priority[8]; /* 64-bit value in big-endian encoding */ + void *data; + struct _pitem *next; +} pitem; + +typedef struct _pitem *piterator; + + +/* Creating and freeing queues. */ + +/* pqueue_new allocates a fresh, empty priority queue object and returns it, or + * NULL on error. */ +OPENSSL_EXPORT pqueue pqueue_new(void); + +/* pqueue_free frees |pq| but not any of the items it points to. Thus |pq| must + * be empty or a memory leak will occur. */ +OPENSSL_EXPORT void pqueue_free(pqueue pq); + + +/* Creating and freeing items. */ + +/* pitem_new allocates a fresh priority queue item that points at |data| and + * has a priority given by |prio64be|, which is a 64-bit, unsigned number + * expressed in big-endian form. It returns the fresh item, or NULL on + * error. */ +OPENSSL_EXPORT pitem *pitem_new(uint8_t prio64be[8], void *data); + +/* pitem_free frees |item|, but not any data that it points to. */ +OPENSSL_EXPORT void pitem_free(pitem *item); + + +/* Queue accessor functions */ + +/* pqueue_peek returns the item with the smallest priority from |pq|, or NULL + * if empty. */ +OPENSSL_EXPORT pitem *pqueue_peek(pqueue pq); + +/* pqueue_find returns the item whose priority matches |prio64be| or NULL if no + * such item exists. */ +OPENSSL_EXPORT pitem *pqueue_find(pqueue pq, uint8_t *prio64be); + + +/* Queue mutation functions */ + +/* pqueue_insert inserts |item| into |pq| and returns item. */ +OPENSSL_EXPORT pitem *pqueue_insert(pqueue pq, pitem *item); + +/* pqueue_pop takes the item with the least priority from |pq| and returns it, + * or NULL if |pq| is empty. */ +OPENSSL_EXPORT pitem *pqueue_pop(pqueue pq); + +/* pqueue_size returns the number of items in |pq|. */ +OPENSSL_EXPORT size_t pqueue_size(pqueue pq); + + +/* Iterating */ + +/* pqueue_iterator returns an iterator that can be used to iterate over the + * contents of the queue. */ +OPENSSL_EXPORT piterator pqueue_iterator(pqueue pq); + +/* pqueue_next returns the current value of |iter| and advances it to the next + * position. If the iterator has advanced over all the elements, it returns + * NULL. */ +OPENSSL_EXPORT pitem *pqueue_next(piterator *iter); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_PQUEUE_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/rand.h b/TMessagesProj/jni/boringssl/include/openssl/rand.h new file mode 100644 index 00000000..335c76ed --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/rand.h @@ -0,0 +1,97 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#ifndef OPENSSL_HEADER_RAND_H +#define OPENSSL_HEADER_RAND_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Random number generation. */ + + +/* RAND_bytes writes |len| bytes of random data to |buf| and returns one. */ +OPENSSL_EXPORT int RAND_bytes(uint8_t *buf, size_t len); + +/* RAND_cleanup frees any resources used by the RNG. This is not safe if other + * threads might still be calling |RAND_bytes|. */ +OPENSSL_EXPORT void RAND_cleanup(void); + + +/* Obscure functions. */ + +#if !defined(OPENSSL_WINDOWS) +/* RAND_set_urandom_fd causes the module to use a copy of |fd| for system + * randomness rather opening /dev/urandom internally. The caller retains + * ownership of |fd| and is at liberty to close it at any time. This is useful + * if, due to a sandbox, /dev/urandom isn't available. If used, it must be + * called before |RAND_bytes| is called in the current address space. + * + * |RAND_set_urandom_fd| does not buffer any entropy, so it is safe to call + * |fork| between |RAND_set_urandom_fd| and the first call to |RAND_bytes|. */ +OPENSSL_EXPORT void RAND_set_urandom_fd(int fd); +#endif + + +/* Deprecated functions */ + +/* RAND_pseudo_bytes is a wrapper around |RAND_bytes|. */ +OPENSSL_EXPORT int RAND_pseudo_bytes(uint8_t *buf, size_t len); + +/* RAND_seed does nothing. */ +OPENSSL_EXPORT void RAND_seed(const void *buf, int num); + +/* RAND_load_file returns a nonnegative number. */ +OPENSSL_EXPORT int RAND_load_file(const char *path, long num); + +/* RAND_add does nothing. */ +OPENSSL_EXPORT void RAND_add(const void *buf, int num, double entropy); + +/* RAND_egd returns 255. */ +OPENSSL_EXPORT int RAND_egd(const char *); + +/* RAND_poll returns one. */ +OPENSSL_EXPORT int RAND_poll(void); + +/* RAND_status returns one. */ +OPENSSL_EXPORT int RAND_status(void); + +/* rand_meth_st is typedefed to |RAND_METHOD| in base.h. It isn't used; it + * exists only to be the return type of |RAND_SSLeay|. It's + * external so that variables of this type can be initialized. */ +struct rand_meth_st { + void (*seed) (const void *buf, int num); + int (*bytes) (uint8_t *buf, size_t num); + void (*cleanup) (void); + void (*add) (const void *buf, int num, double entropy); + int (*pseudorand) (uint8_t *buf, size_t num); + int (*status) (void); +}; + +/* RAND_SSLeay returns a pointer to a dummy |RAND_METHOD|. */ +OPENSSL_EXPORT RAND_METHOD *RAND_SSLeay(void); + +/* RAND_set_rand_method does nothing. */ +OPENSSL_EXPORT void RAND_set_rand_method(const RAND_METHOD *); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_RAND_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/rc4.h b/TMessagesProj/jni/boringssl/include/openssl/rc4.h new file mode 100644 index 00000000..0619cac3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/rc4.h @@ -0,0 +1,90 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_RC4_H +#define OPENSSL_HEADER_RC4_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* RC4. */ + + +struct rc4_key_st { + uint32_t x, y; + uint32_t data[256]; +} /* RC4_KEY */; + +/* RC4_set_key performs an RC4 key schedule and initialises |rc4key| with |len| + * bytes of key material from |key|. */ +OPENSSL_EXPORT void RC4_set_key(RC4_KEY *rc4key, unsigned len, + const uint8_t *key); + +/* RC4 encrypts (or decrypts, it's the same with RC4) |len| bytes from |in| to + * |out|. */ +OPENSSL_EXPORT void RC4(RC4_KEY *key, size_t len, const uint8_t *in, + uint8_t *out); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_RC4_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/rsa.h b/TMessagesProj/jni/boringssl/include/openssl/rsa.h new file mode 100644 index 00000000..0d87f278 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/rsa.h @@ -0,0 +1,633 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_RSA_H +#define OPENSSL_HEADER_RSA_H + +#include + +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* rsa.h contains functions for handling encryption and signature using RSA. */ + + +/* Allocation and destruction. */ + +/* RSA_new returns a new, empty RSA object or NULL on error. */ +OPENSSL_EXPORT RSA *RSA_new(void); + +/* RSA_new_method acts the same as |RSA_new| but takes an explicit |ENGINE|. */ +OPENSSL_EXPORT RSA *RSA_new_method(const ENGINE *engine); + +/* RSA_free decrements the reference count of |rsa| and frees it if the + * reference count drops to zero. */ +OPENSSL_EXPORT void RSA_free(RSA *rsa); + +/* RSA_up_ref increments the reference count of |rsa|. */ +OPENSSL_EXPORT int RSA_up_ref(RSA *rsa); + + +/* Key generation. */ + +/* RSA_generate_key_ex generates a new RSA key where the modulus has size + * |bits| and the public exponent is |e|. If unsure, |RSA_F4| is a good value + * for |e|. If |cb| is not NULL then it is called during the key generation + * process. In addition to the calls documented for |BN_generate_prime_ex|, it + * is called with event=2 when the n'th prime is rejected as unsuitable and + * with event=3 when a suitable value for |p| is found. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e, + BN_GENCB *cb); + +/* RSA_generate_multi_prime_key acts like |RSA_generate_key_ex| but can + * generate an RSA private key with more than two primes. */ +OPENSSL_EXPORT int RSA_generate_multi_prime_key(RSA *rsa, int bits, + int num_primes, BIGNUM *e, + BN_GENCB *cb); + + +/* Encryption / Decryption */ + +/* Padding types for encryption. */ +#define RSA_PKCS1_PADDING 1 +#define RSA_NO_PADDING 3 +#define RSA_PKCS1_OAEP_PADDING 4 +/* RSA_PKCS1_PSS_PADDING can only be used via the EVP interface. */ +#define RSA_PKCS1_PSS_PADDING 6 + +/* RSA_encrypt encrypts |in_len| bytes from |in| to the public key from |rsa| + * and writes, at most, |max_out| bytes of encrypted data to |out|. The + * |max_out| argument must be, at least, |RSA_size| in order to ensure success. + * + * It returns 1 on success or zero on error. + * + * The |padding| argument must be one of the |RSA_*_PADDING| values. If in + * doubt, |RSA_PKCS1_PADDING| is the most common but |RSA_PKCS1_OAEP_PADDING| + * is the most secure. */ +OPENSSL_EXPORT int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, + size_t max_out, const uint8_t *in, size_t in_len, + int padding); + +/* RSA_decrypt decrypts |in_len| bytes from |in| with the private key from + * |rsa| and writes, at most, |max_out| bytes of plaintext to |out|. The + * |max_out| argument must be, at least, |RSA_size| in order to ensure success. + * + * It returns 1 on success or zero on error. + * + * The |padding| argument must be one of the |RSA_*_PADDING| values. If in + * doubt, |RSA_PKCS1_PADDING| is the most common but |RSA_PKCS1_OAEP_PADDING| + * is the most secure. */ +OPENSSL_EXPORT int RSA_decrypt(RSA *rsa, size_t *out_len, uint8_t *out, + size_t max_out, const uint8_t *in, size_t in_len, + int padding); + +/* RSA_public_encrypt encrypts |flen| bytes from |from| to the public key in + * |rsa| and writes the encrypted data to |to|. The |to| buffer must have at + * least |RSA_size| bytes of space. It returns the number of bytes written, or + * -1 on error. The |padding| argument must be one of the |RSA_*_PADDING| + * values. If in doubt, |RSA_PKCS1_PADDING| is the most common but + * |RSA_PKCS1_OAEP_PADDING| is the most secure. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use |RSA_encrypt| instead. */ +OPENSSL_EXPORT int RSA_public_encrypt(int flen, const uint8_t *from, + uint8_t *to, RSA *rsa, int padding); + +/* RSA_private_decrypt decrypts |flen| bytes from |from| with the public key in + * |rsa| and writes the plaintext to |to|. The |to| buffer must have at + * least |RSA_size| bytes of space. It returns the number of bytes written, or + * -1 on error. The |padding| argument must be one of the |RSA_*_PADDING| + * values. If in doubt, |RSA_PKCS1_PADDING| is the most common but + * |RSA_PKCS1_OAEP_PADDING| is the most secure. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use |RSA_decrypt| instead. */ +OPENSSL_EXPORT int RSA_private_decrypt(int flen, const uint8_t *from, + uint8_t *to, RSA *rsa, int padding); + +/* RSA_message_index_PKCS1_type_2 performs the first step of a PKCS #1 padding + * check for decryption. If the |from_len| bytes pointed to at |from| are a + * valid PKCS #1 message, it returns one and sets |*out_index| to the start of + * the unpadded message. The unpadded message is a suffix of the input and has + * length |from_len - *out_index|. Otherwise, it returns zero and sets + * |*out_index| to zero. This function runs in time independent of the input + * data and is intended to be used directly to avoid Bleichenbacher's attack. + * + * WARNING: This function behaves differently from the usual OpenSSL convention + * in that it does NOT put an error on the queue in the error case. */ +OPENSSL_EXPORT int RSA_message_index_PKCS1_type_2(const uint8_t *from, + size_t from_len, + size_t *out_index); + + +/* Signing / Verification */ + +/* RSA_sign signs |in_len| bytes of digest from |in| with |rsa| and writes, at + * most, |RSA_size(rsa)| bytes to |out|. On successful return, the actual + * number of bytes written is written to |*out_len|. + * + * The |hash_nid| argument identifies the hash function used to calculate |in| + * and is embedded in the resulting signature. For example, it might be + * |NID_sha256|. + * + * It returns 1 on success and zero on error. */ +OPENSSL_EXPORT int RSA_sign(int hash_nid, const uint8_t *in, + unsigned int in_len, uint8_t *out, + unsigned int *out_len, RSA *rsa); + +/* RSA_sign_raw signs |in_len| bytes from |in| with the public key from |rsa| + * and writes, at most, |max_out| bytes of signature data to |out|. The + * |max_out| argument must be, at least, |RSA_size| in order to ensure success. + * + * It returns 1 on success or zero on error. + * + * The |padding| argument must be one of the |RSA_*_PADDING| values. If in + * doubt, |RSA_PKCS1_PADDING| is the most common. */ +OPENSSL_EXPORT int RSA_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, + size_t max_out, const uint8_t *in, + size_t in_len, int padding); + +/* RSA_verify verifies that |sig_len| bytes from |sig| are a valid, PKCS#1 + * signature of |msg_len| bytes at |msg| by |rsa|. + * + * The |hash_nid| argument identifies the hash function used to calculate |in| + * and is embedded in the resulting signature in order to prevent hash + * confusion attacks. For example, it might be |NID_sha256|. + * + * It returns one if the signature is valid and zero otherwise. + * + * WARNING: this differs from the original, OpenSSL function which additionally + * returned -1 on error. */ +OPENSSL_EXPORT int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len, + const uint8_t *sig, size_t sig_len, RSA *rsa); + +/* RSA_verify_raw verifies |in_len| bytes of signature from |in| using the + * public key from |rsa| and writes, at most, |max_out| bytes of plaintext to + * |out|. The |max_out| argument must be, at least, |RSA_size| in order to + * ensure success. + * + * It returns 1 on success or zero on error. + * + * The |padding| argument must be one of the |RSA_*_PADDING| values. If in + * doubt, |RSA_PKCS1_PADDING| is the most common. */ +OPENSSL_EXPORT int RSA_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, + size_t max_out, const uint8_t *in, + size_t in_len, int padding); + +/* RSA_private_encrypt encrypts |flen| bytes from |from| with the private key in + * |rsa| and writes the encrypted data to |to|. The |to| buffer must have at + * least |RSA_size| bytes of space. It returns the number of bytes written, or + * -1 on error. The |padding| argument must be one of the |RSA_*_PADDING| + * values. If in doubt, |RSA_PKCS1_PADDING| is the most common. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use |RSA_sign_raw| instead. */ +OPENSSL_EXPORT int RSA_private_encrypt(int flen, const uint8_t *from, + uint8_t *to, RSA *rsa, int padding); + +/* RSA_public_decrypt verifies |flen| bytes of signature from |from| using the + * public key in |rsa| and writes the plaintext to |to|. The |to| buffer must + * have at least |RSA_size| bytes of space. It returns the number of bytes + * written, or -1 on error. The |padding| argument must be one of the + * |RSA_*_PADDING| values. If in doubt, |RSA_PKCS1_PADDING| is the most common. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use |RSA_verify_raw| instead. */ +OPENSSL_EXPORT int RSA_public_decrypt(int flen, const uint8_t *from, + uint8_t *to, RSA *rsa, int padding); + + +/* Utility functions. */ + +/* RSA_size returns the number of bytes in the modulus, which is also the size + * of a signature or encrypted value using |rsa|. */ +OPENSSL_EXPORT unsigned RSA_size(const RSA *rsa); + +/* RSA_is_opaque returns one if |rsa| is opaque and doesn't expose its key + * material. Otherwise it returns zero. */ +OPENSSL_EXPORT int RSA_is_opaque(const RSA *rsa); + +/* RSA_supports_digest returns one if |rsa| supports signing digests + * of type |md|. Otherwise it returns zero. */ +OPENSSL_EXPORT int RSA_supports_digest(const RSA *rsa, const EVP_MD *md); + +/* RSAPublicKey_dup allocates a fresh |RSA| and copies the public key from + * |rsa| into it. It returns the fresh |RSA| object, or NULL on error. */ +OPENSSL_EXPORT RSA *RSAPublicKey_dup(const RSA *rsa); + +/* RSAPrivateKey_dup allocates a fresh |RSA| and copies the private key from + * |rsa| into it. It returns the fresh |RSA| object, or NULL on error. */ +OPENSSL_EXPORT RSA *RSAPrivateKey_dup(const RSA *rsa); + +/* RSA_check_key performs basic validatity tests on |rsa|. It returns one if + * they pass and zero otherwise. Opaque keys and public keys always pass. If it + * returns zero then a more detailed error is available on the error queue. */ +OPENSSL_EXPORT int RSA_check_key(const RSA *rsa); + +/* RSA_recover_crt_params uses |rsa->n|, |rsa->d| and |rsa->e| in order to + * calculate the two primes used and thus the precomputed, CRT values. These + * values are set in the |p|, |q|, |dmp1|, |dmq1| and |iqmp| members of |rsa|, + * which must be |NULL| on entry. It returns one on success and zero + * otherwise. */ +OPENSSL_EXPORT int RSA_recover_crt_params(RSA *rsa); + +/* RSA_verify_PKCS1_PSS_mgf1 verifies that |EM| is a correct PSS padding of + * |mHash|, where |mHash| is a digest produced by |Hash|. |EM| must point to + * exactly |RSA_size(rsa)| bytes of data. The |mgf1Hash| argument specifies the + * hash function for generating the mask. If NULL, |Hash| is used. The |sLen| + * argument specifies the expected salt length in bytes. If |sLen| is -1 then + * the salt length is the same as the hash length. If -2, then the salt length + * is maximal and is taken from the size of |EM|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash, + const EVP_MD *Hash, + const EVP_MD *mgf1Hash, + const uint8_t *EM, int sLen); + +/* RSA_padding_add_PKCS1_PSS_mgf1 writes a PSS padding of |mHash| to |EM|, + * where |mHash| is a digest produced by |Hash|. |RSA_size(rsa)| bytes of + * output will be written to |EM|. The |mgf1Hash| argument specifies the hash + * function for generating the mask. If NULL, |Hash| is used. The |sLen| + * argument specifies the expected salt length in bytes. If |sLen| is -1 then + * the salt length is the same as the hash length. If -2, then the salt length + * is maximal given the space in |EM|. + * + * It returns one on success or zero on error. */ +OPENSSL_EXPORT int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, uint8_t *EM, + const uint8_t *mHash, + const EVP_MD *Hash, + const EVP_MD *mgf1Hash, + int sLen); + +/* RSA_add_pkcs1_prefix builds a version of |msg| prefixed with the DigestInfo + * header for the given hash function and sets |out_msg| to point to it. On + * successful return, |*out_msg| may be allocated memory and, if so, + * |*is_alloced| will be 1. */ +OPENSSL_EXPORT int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len, + int *is_alloced, int hash_nid, + const uint8_t *msg, size_t msg_len); + + +/* ASN.1 functions. */ + +/* RSA_parse_public_key parses a DER-encoded RSAPublicKey structure (RFC 3447) + * from |cbs| and advances |cbs|. It returns a newly-allocated |RSA| or NULL on + * error. */ +OPENSSL_EXPORT RSA *RSA_parse_public_key(CBS *cbs); + +/* RSA_public_key_from_bytes parses |in| as a DER-encoded RSAPublicKey structure + * (RFC 3447). It returns a newly-allocated |RSA| or NULL on error. */ +OPENSSL_EXPORT RSA *RSA_public_key_from_bytes(const uint8_t *in, size_t in_len); + +/* RSA_marshal_public_key marshals |rsa| as a DER-encoded RSAPublicKey structure + * (RFC 3447) and appends the result to |cbb|. It returns one on success and + * zero on failure. */ +OPENSSL_EXPORT int RSA_marshal_public_key(CBB *cbb, const RSA *rsa); + +/* RSA_public_key_to_bytes marshals |rsa| as a DER-encoded RSAPublicKey + * structure (RFC 3447) and, on success, sets |*out_bytes| to a newly allocated + * buffer containing the result and returns one. Otherwise, it returns zero. The + * result should be freed with |OPENSSL_free|. */ +OPENSSL_EXPORT int RSA_public_key_to_bytes(uint8_t **out_bytes, size_t *out_len, + const RSA *rsa); + +/* RSA_parse_private_key parses a DER-encoded RSAPrivateKey structure (RFC 3447) + * from |cbs| and advances |cbs|. It returns a newly-allocated |RSA| or NULL on + * error. */ +OPENSSL_EXPORT RSA *RSA_parse_private_key(CBS *cbs); + +/* RSA_private_key_from_bytes parses |in| as a DER-encoded RSAPrivateKey + * structure (RFC 3447). It returns a newly-allocated |RSA| or NULL on error. */ +OPENSSL_EXPORT RSA *RSA_private_key_from_bytes(const uint8_t *in, + size_t in_len); + +/* RSA_marshal_private_key marshals |rsa| as a DER-encoded RSAPrivateKey + * structure (RFC 3447) and appends the result to |cbb|. It returns one on + * success and zero on failure. */ +OPENSSL_EXPORT int RSA_marshal_private_key(CBB *cbb, const RSA *rsa); + +/* RSA_private_key_to_bytes marshals |rsa| as a DER-encoded RSAPrivateKey + * structure (RFC 3447) and, on success, sets |*out_bytes| to a newly allocated + * buffer containing the result and returns one. Otherwise, it returns zero. The + * result should be freed with |OPENSSL_free|. */ +OPENSSL_EXPORT int RSA_private_key_to_bytes(uint8_t **out_bytes, + size_t *out_len, const RSA *rsa); + + +/* Deprecated functions. */ + +/* d2i_RSAPublicKey parses an ASN.1, DER-encoded, RSA public key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. If |*out| is already non-NULL on entry then the result is + * written directly into |*out|, otherwise a fresh |RSA| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT RSA *d2i_RSAPublicKey(RSA **out, const uint8_t **inp, long len); + +/* i2d_RSAPublicKey marshals |in| to an ASN.1, DER structure. If |outp| is not + * NULL then the result is written to |*outp| and |*outp| is advanced just past + * the output. It returns the number of bytes in the result, whether written or + * not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_RSAPublicKey(const RSA *in, uint8_t **outp); + +/* d2i_RSAPrivateKey parses an ASN.1, DER-encoded, RSA private key from |len| + * bytes at |*inp|. If |out| is not NULL then, on exit, a pointer to the result + * is in |*out|. If |*out| is already non-NULL on entry then the result is + * written directly into |*out|, otherwise a fresh |RSA| is allocated. On + * successful exit, |*inp| is advanced past the DER structure. It returns the + * result or NULL on error. */ +OPENSSL_EXPORT RSA *d2i_RSAPrivateKey(RSA **out, const uint8_t **inp, long len); + +/* i2d_RSAPrivateKey marshals |in| to an ASN.1, DER structure. If |outp| is not + * NULL then the result is written to |*outp| and |*outp| is advanced just past + * the output. It returns the number of bytes in the result, whether written or + * not, or a negative value on error. */ +OPENSSL_EXPORT int i2d_RSAPrivateKey(const RSA *in, uint8_t **outp); + + +/* ex_data functions. + * + * See |ex_data.h| for details. */ + +OPENSSL_EXPORT int RSA_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int RSA_set_ex_data(RSA *r, int idx, void *arg); +OPENSSL_EXPORT void *RSA_get_ex_data(const RSA *r, int idx); + +/* RSA_FLAG_OPAQUE specifies that this RSA_METHOD does not expose its key + * material. This may be set if, for instance, it is wrapping some other crypto + * API, like a platform key store. */ +#define RSA_FLAG_OPAQUE 1 + +/* RSA_FLAG_CACHE_PUBLIC causes a precomputed Montgomery context to be created, + * on demand, for the public key operations. */ +#define RSA_FLAG_CACHE_PUBLIC 2 + +/* RSA_FLAG_CACHE_PRIVATE causes a precomputed Montgomery context to be + * created, on demand, for the private key operations. */ +#define RSA_FLAG_CACHE_PRIVATE 4 + +/* RSA_FLAG_NO_BLINDING disables blinding of private operations. */ +#define RSA_FLAG_NO_BLINDING 8 + +/* RSA_FLAG_EXT_PKEY means that private key operations will be handled by + * |mod_exp| and that they do not depend on the private key components being + * present: for example a key stored in external hardware. */ +#define RSA_FLAG_EXT_PKEY 0x20 + +/* RSA_FLAG_SIGN_VER causes the |sign| and |verify| functions of |rsa_meth_st| + * to be called when set. */ +#define RSA_FLAG_SIGN_VER 0x40 + + +/* RSA public exponent values. */ + +#define RSA_3 0x3 +#define RSA_F4 0x10001 + + +/* Deprecated functions. */ + +/* RSA_blinding_on returns one. */ +OPENSSL_EXPORT int RSA_blinding_on(RSA *rsa, BN_CTX *ctx); + +/* RSA_generate_key behaves like |RSA_generate_key_ex|, which is what you + * should use instead. It returns NULL on error, or a newly-allocated |RSA| on + * success. This function is provided for compatibility only. The |callback| + * and |cb_arg| parameters must be NULL. */ +OPENSSL_EXPORT RSA *RSA_generate_key(int bits, unsigned long e, void *callback, + void *cb_arg); + +typedef struct rsa_pss_params_st { + X509_ALGOR *hashAlgorithm; + X509_ALGOR *maskGenAlgorithm; + ASN1_INTEGER *saltLength; + ASN1_INTEGER *trailerField; +} RSA_PSS_PARAMS; + +DECLARE_ASN1_FUNCTIONS(RSA_PSS_PARAMS) + + +struct rsa_meth_st { + struct openssl_method_common_st common; + + void *app_data; + + int (*init)(RSA *rsa); + int (*finish)(RSA *rsa); + + /* size returns the size of the RSA modulus in bytes. */ + size_t (*size)(const RSA *rsa); + + int (*sign)(int type, const uint8_t *m, unsigned int m_length, + uint8_t *sigret, unsigned int *siglen, const RSA *rsa); + + int (*verify)(int dtype, const uint8_t *m, unsigned int m_length, + const uint8_t *sigbuf, unsigned int siglen, const RSA *rsa); + + + /* These functions mirror the |RSA_*| functions of the same name. */ + int (*encrypt)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding); + int (*sign_raw)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding); + + int (*decrypt)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding); + int (*verify_raw)(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, int padding); + + /* private_transform takes a big-endian integer from |in|, calculates the + * d'th power of it, modulo the RSA modulus and writes the result as a + * big-endian integer to |out|. Both |in| and |out| are |len| bytes long and + * |len| is always equal to |RSA_size(rsa)|. If the result of the transform + * can be represented in fewer than |len| bytes, then |out| must be zero + * padded on the left. + * + * It returns one on success and zero otherwise. + * + * RSA decrypt and sign operations will call this, thus an ENGINE might wish + * to override it in order to avoid having to implement the padding + * functionality demanded by those, higher level, operations. */ + int (*private_transform)(RSA *rsa, uint8_t *out, const uint8_t *in, + size_t len); + + int (*mod_exp)(BIGNUM *r0, const BIGNUM *I, RSA *rsa, + BN_CTX *ctx); /* Can be null */ + int (*bn_mod_exp)(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, + BN_MONT_CTX *m_ctx); + + int flags; + + int (*keygen)(RSA *rsa, int bits, BIGNUM *e, BN_GENCB *cb); + + int (*multi_prime_keygen)(RSA *rsa, int bits, int num_primes, BIGNUM *e, + BN_GENCB *cb); + + /* supports_digest returns one if |rsa| supports digests of type + * |md|. If null, it is assumed that all digests are supported. */ + int (*supports_digest)(const RSA *rsa, const EVP_MD *md); +}; + + +/* Private functions. */ + +typedef struct bn_blinding_st BN_BLINDING; + +struct rsa_st { + RSA_METHOD *meth; + + BIGNUM *n; + BIGNUM *e; + BIGNUM *d; + BIGNUM *p; + BIGNUM *q; + BIGNUM *dmp1; + BIGNUM *dmq1; + BIGNUM *iqmp; + + STACK_OF(RSA_additional_prime) *additional_primes; + + /* be careful using this if the RSA structure is shared */ + CRYPTO_EX_DATA ex_data; + CRYPTO_refcount_t references; + int flags; + + CRYPTO_MUTEX lock; + + /* Used to cache montgomery values. The creation of these values is protected + * by |lock|. */ + BN_MONT_CTX *_method_mod_n; + BN_MONT_CTX *_method_mod_p; + BN_MONT_CTX *_method_mod_q; + + /* num_blindings contains the size of the |blindings| and |blindings_inuse| + * arrays. This member and the |blindings_inuse| array are protected by + * |lock|. */ + unsigned num_blindings; + /* blindings is an array of BN_BLINDING structures that can be reserved by a + * thread by locking |lock| and changing the corresponding element in + * |blindings_inuse| from 0 to 1. */ + BN_BLINDING **blindings; + unsigned char *blindings_inuse; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#define RSA_R_BAD_E_VALUE 100 +#define RSA_R_BAD_FIXED_HEADER_DECRYPT 101 +#define RSA_R_BAD_PAD_BYTE_COUNT 102 +#define RSA_R_BAD_RSA_PARAMETERS 103 +#define RSA_R_BAD_SIGNATURE 104 +#define RSA_R_BLOCK_TYPE_IS_NOT_01 105 +#define RSA_R_BN_NOT_INITIALIZED 106 +#define RSA_R_CRT_PARAMS_ALREADY_GIVEN 107 +#define RSA_R_CRT_VALUES_INCORRECT 108 +#define RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN 109 +#define RSA_R_DATA_TOO_LARGE 110 +#define RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE 111 +#define RSA_R_DATA_TOO_LARGE_FOR_MODULUS 112 +#define RSA_R_DATA_TOO_SMALL 113 +#define RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE 114 +#define RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY 115 +#define RSA_R_D_E_NOT_CONGRUENT_TO_1 116 +#define RSA_R_EMPTY_PUBLIC_KEY 117 +#define RSA_R_FIRST_OCTET_INVALID 118 +#define RSA_R_INCONSISTENT_SET_OF_CRT_VALUES 119 +#define RSA_R_INTERNAL_ERROR 120 +#define RSA_R_INVALID_MESSAGE_LENGTH 121 +#define RSA_R_KEY_SIZE_TOO_SMALL 122 +#define RSA_R_LAST_OCTET_INVALID 123 +#define RSA_R_MODULUS_TOO_LARGE 124 +#define RSA_R_NO_PUBLIC_EXPONENT 125 +#define RSA_R_NULL_BEFORE_BLOCK_MISSING 126 +#define RSA_R_N_NOT_EQUAL_P_Q 127 +#define RSA_R_OAEP_DECODING_ERROR 128 +#define RSA_R_ONLY_ONE_OF_P_Q_GIVEN 129 +#define RSA_R_OUTPUT_BUFFER_TOO_SMALL 130 +#define RSA_R_PADDING_CHECK_FAILED 131 +#define RSA_R_PKCS_DECODING_ERROR 132 +#define RSA_R_SLEN_CHECK_FAILED 133 +#define RSA_R_SLEN_RECOVERY_FAILED 134 +#define RSA_R_TOO_LONG 135 +#define RSA_R_TOO_MANY_ITERATIONS 136 +#define RSA_R_UNKNOWN_ALGORITHM_TYPE 137 +#define RSA_R_UNKNOWN_PADDING_TYPE 138 +#define RSA_R_VALUE_MISSING 139 +#define RSA_R_WRONG_SIGNATURE_LENGTH 140 +#define RSA_R_MUST_HAVE_AT_LEAST_TWO_PRIMES 141 +#define RSA_R_CANNOT_RECOVER_MULTI_PRIME_KEY 142 +#define RSA_R_BAD_ENCODING 143 +#define RSA_R_ENCODE_ERROR 144 +#define RSA_R_BAD_VERSION 145 + +#endif /* OPENSSL_HEADER_RSA_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/safestack.h b/TMessagesProj/jni/boringssl/include/openssl/safestack.h new file mode 100644 index 00000000..6e5e4330 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/safestack.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +/* This header is provided in order to make compiling against code that expects + OpenSSL easier. */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/sha.h b/TMessagesProj/jni/boringssl/include/openssl/sha.h new file mode 100644 index 00000000..ac2ab758 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/sha.h @@ -0,0 +1,241 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_SHA_H +#define OPENSSL_HEADER_SHA_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* The SHA family of hash functions (SHA-1 and SHA-2). */ + + +/* SHA_CBLOCK is the block size of SHA-1. */ +#define SHA_CBLOCK 64 + +/* SHA_DIGEST_LENGTH is the length of a SHA-1 digest. */ +#define SHA_DIGEST_LENGTH 20 + +/* TODO(fork): remove */ +#define SHA_LBLOCK 16 +#define SHA_LONG uint32_t + +/* SHA1_Init initialises |sha| and returns one. */ +OPENSSL_EXPORT int SHA1_Init(SHA_CTX *sha); + +/* SHA1_Update adds |len| bytes from |data| to |sha| and returns one. */ +OPENSSL_EXPORT int SHA1_Update(SHA_CTX *sha, const void *data, size_t len); + +/* SHA1_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA_DIGEST_LENGTH| bytes of space. It + * returns one. */ +OPENSSL_EXPORT int SHA1_Final(uint8_t *md, SHA_CTX *sha); + +/* SHA1 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA1(const uint8_t *data, size_t len, uint8_t *out); + +/* SHA1_Transform is a low-level function that performs a single, SHA-1 block + * transformation using the state from |sha| and 64 bytes from |block|. */ +OPENSSL_EXPORT void SHA1_Transform(SHA_CTX *sha, const uint8_t *block); + +struct sha_state_st { + uint32_t h0, h1, h2, h3, h4; + uint32_t Nl, Nh; + uint32_t data[16]; + unsigned int num; +}; + + +/* SHA-224. */ + +/* SHA224_CBLOCK is the block size of SHA-224. */ +#define SHA224_CBLOCK 64 + +/* SHA224_DIGEST_LENGTH is the length of a SHA-224 digest. */ +#define SHA224_DIGEST_LENGTH 28 + +/* SHA224_Init initialises |sha| and returns 1. */ +OPENSSL_EXPORT int SHA224_Init(SHA256_CTX *sha); + +/* SHA224_Update adds |len| bytes from |data| to |sha| and returns 1. */ +OPENSSL_EXPORT int SHA224_Update(SHA256_CTX *sha, const void *data, size_t len); + +/* SHA224_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA224_DIGEST_LENGTH| bytes of space. It + * returns one on success and zero on programmer error. */ +OPENSSL_EXPORT int SHA224_Final(uint8_t *md, SHA256_CTX *sha); + +/* SHA224 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA224_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA224(const uint8_t *data, size_t len, uint8_t *out); + + +/* SHA-256. */ + +/* SHA256_CBLOCK is the block size of SHA-256. */ +#define SHA256_CBLOCK 64 + +/* SHA256_DIGEST_LENGTH is the length of a SHA-256 digest. */ +#define SHA256_DIGEST_LENGTH 32 + +/* SHA256_Init initialises |sha| and returns 1. */ +OPENSSL_EXPORT int SHA256_Init(SHA256_CTX *sha); + +/* SHA256_Update adds |len| bytes from |data| to |sha| and returns 1. */ +OPENSSL_EXPORT int SHA256_Update(SHA256_CTX *sha, const void *data, size_t len); + +/* SHA256_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA256_DIGEST_LENGTH| bytes of space. It + * returns one on success and zero on programmer error. */ +OPENSSL_EXPORT int SHA256_Final(uint8_t *md, SHA256_CTX *sha); + +/* SHA256 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA256_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA256(const uint8_t *data, size_t len, uint8_t *out); + +/* SHA256_Transform is a low-level function that performs a single, SHA-1 block + * transformation using the state from |sha| and 64 bytes from |block|. */ +OPENSSL_EXPORT void SHA256_Transform(SHA256_CTX *sha, const uint8_t *data); + +struct sha256_state_st { + uint32_t h[8]; + uint32_t Nl, Nh; + uint32_t data[16]; + unsigned int num, md_len; +}; + + +/* SHA-384. */ + +/* SHA384_CBLOCK is the block size of SHA-384. */ +#define SHA384_CBLOCK 128 + +/* SHA384_DIGEST_LENGTH is the length of a SHA-384 digest. */ +#define SHA384_DIGEST_LENGTH 48 + +/* SHA384_Init initialises |sha| and returns 1. */ +OPENSSL_EXPORT int SHA384_Init(SHA512_CTX *sha); + +/* SHA384_Update adds |len| bytes from |data| to |sha| and returns 1. */ +OPENSSL_EXPORT int SHA384_Update(SHA512_CTX *sha, const void *data, size_t len); + +/* SHA384_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA384_DIGEST_LENGTH| bytes of space. It + * returns one on success and zero on programmer error. */ +OPENSSL_EXPORT int SHA384_Final(uint8_t *md, SHA512_CTX *sha); + +/* SHA384 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA384_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA384(const uint8_t *data, size_t len, uint8_t *out); + +/* SHA384_Transform is a low-level function that performs a single, SHA-1 block + * transformation using the state from |sha| and 64 bytes from |block|. */ +OPENSSL_EXPORT void SHA384_Transform(SHA512_CTX *sha, const uint8_t *data); + + +/* SHA-512. */ + +/* SHA512_CBLOCK is the block size of SHA-512. */ +#define SHA512_CBLOCK 128 + +/* SHA512_DIGEST_LENGTH is the length of a SHA-512 digest. */ +#define SHA512_DIGEST_LENGTH 64 + +/* SHA512_Init initialises |sha| and returns 1. */ +OPENSSL_EXPORT int SHA512_Init(SHA512_CTX *sha); + +/* SHA512_Update adds |len| bytes from |data| to |sha| and returns 1. */ +OPENSSL_EXPORT int SHA512_Update(SHA512_CTX *sha, const void *data, size_t len); + +/* SHA512_Final adds the final padding to |sha| and writes the resulting digest + * to |md|, which must have at least |SHA512_DIGEST_LENGTH| bytes of space. It + * returns one on success and zero on programmer error. */ +OPENSSL_EXPORT int SHA512_Final(uint8_t *md, SHA512_CTX *sha); + +/* SHA512 writes the digest of |len| bytes from |data| to |out| and returns + * |out|. There must be at least |SHA512_DIGEST_LENGTH| bytes of space in + * |out|. */ +OPENSSL_EXPORT uint8_t *SHA512(const uint8_t *data, size_t len, uint8_t *out); + +/* SHA512_Transform is a low-level function that performs a single, SHA-1 block + * transformation using the state from |sha| and 64 bytes from |block|. */ +OPENSSL_EXPORT void SHA512_Transform(SHA512_CTX *sha, const uint8_t *data); + +struct sha512_state_st { + uint64_t h[8]; + uint64_t Nl, Nh; + union { + uint64_t d[16]; + uint8_t p[128]; + } u; + unsigned int num, md_len; +}; + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_SHA_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/srtp.h b/TMessagesProj/jni/boringssl/include/openssl/srtp.h new file mode 100644 index 00000000..3f5a53e2 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/srtp.h @@ -0,0 +1,178 @@ +/* ssl/tls1.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* + DTLS code by Eric Rescorla + + Copyright (C) 2006, Network Resonance, Inc. + Copyright (C) 2011, RTFM, Inc. +*/ + +#ifndef OPENSSL_HEADER_SRTP_H +#define OPENSSL_HEADER_SRTP_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Constants for SRTP profiles */ +#define SRTP_AES128_CM_SHA1_80 0x0001 +#define SRTP_AES128_CM_SHA1_32 0x0002 +#define SRTP_AES128_F8_SHA1_80 0x0003 +#define SRTP_AES128_F8_SHA1_32 0x0004 +#define SRTP_NULL_SHA1_80 0x0005 +#define SRTP_NULL_SHA1_32 0x0006 + +/* SSL_CTX_set_srtp_profiles enables SRTP for all SSL objects created from + * |ctx|. |profile| contains a colon-separated list of profile names. It returns + * one on success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx, + const char *profiles); + +/* SSL_set_srtp_profiles enables SRTP for |ssl|. |profile| contains a + * colon-separated list of profile names. It returns one on success and zero on + * failure. */ +OPENSSL_EXPORT int SSL_set_srtp_profiles(SSL *ctx, const char *profiles); + +/* SSL_get_srtp_profiles returns the SRTP profiles supported by |ssl|. */ +OPENSSL_EXPORT STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles( + SSL *ssl); + +/* SSL_get_selected_srtp_profile returns the selected SRTP profile, or NULL if + * SRTP was not negotiated. */ +OPENSSL_EXPORT const SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile( + SSL *s); + + +/* Deprecated functions */ + +/* SSL_CTX_set_tlsext_use_srtp calls SSL_CTX_set_srtp_profiles. It returns zero + * on success and one on failure. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use SSL_CTX_set_srtp_profiles instead. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, + const char *profiles); + +/* SSL_set_tlsext_use_srtp calls SSL_set_srtp_profiles. It returns zero on + * success and one on failure. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use SSL_set_srtp_profiles instead. */ +OPENSSL_EXPORT int SSL_set_tlsext_use_srtp(SSL *ctx, const char *profiles); + + +#ifdef __cplusplus +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_SRTP_H */ + diff --git a/TMessagesProj/jni/boringssl/include/openssl/ssl.h b/TMessagesProj/jni/boringssl/include/openssl/ssl.h new file mode 100644 index 00000000..ffbd8cae --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ssl.h @@ -0,0 +1,3067 @@ +/* ssl/ssl.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2007 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#ifndef OPENSSL_HEADER_SSL_H +#define OPENSSL_HEADER_SSL_H + +#include + +#include +#include +#include +#include +#include +#include +#include + +#if !defined(OPENSSL_WINDOWS) +#include +#endif + +/* wpa_supplicant expects to get the version functions from ssl.h */ +#include + +/* Forward-declare struct timeval. On Windows, it is defined in winsock2.h and + * Windows headers define too many macros to be included in public headers. + * However, only a forward declaration is needed. */ +struct timeval; + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* SSL implementation. */ + + +/* Initialization. */ + +/* SSL_library_init initializes the crypto and SSL libraries and returns one. */ +OPENSSL_EXPORT int SSL_library_init(void); + + +/* Cipher suites. */ + +/* An SSL_CIPHER represents a cipher suite. */ +typedef struct ssl_cipher_st { + /* name is the OpenSSL name for the cipher. */ + const char *name; + /* id is the cipher suite value bitwise OR-d with 0x03000000. */ + uint32_t id; + + /* The following are internal fields. See ssl/internal.h for their values. */ + + uint32_t algorithm_mkey; + uint32_t algorithm_auth; + uint32_t algorithm_enc; + uint32_t algorithm_mac; + uint32_t algorithm_ssl; + uint32_t algo_strength; + uint32_t algorithm_prf; + + /* strength_bits is the strength of the cipher in bits. */ + int strength_bits; + /* alg_bits is the number of bits of key material used by the algorithm. */ + int alg_bits; +} SSL_CIPHER; + +DECLARE_STACK_OF(SSL_CIPHER) + +/* SSL_get_cipher_by_value returns the structure representing a TLS cipher + * suite based on its assigned number, or NULL if unknown. See + * https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4. */ +OPENSSL_EXPORT const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value); + +/* SSL_CIPHER_get_id returns |cipher|'s id. It may be cast to a |uint16_t| to + * get the cipher suite value. */ +OPENSSL_EXPORT uint32_t SSL_CIPHER_get_id(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_AES returns one if |cipher| uses AES (either GCM or CBC + * mode). */ +OPENSSL_EXPORT int SSL_CIPHER_is_AES(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_has_MD5_HMAC returns one if |cipher| uses HMAC-MD5. */ +OPENSSL_EXPORT int SSL_CIPHER_has_MD5_HMAC(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_AESGCM returns one if |cipher| uses AES-GCM. */ +OPENSSL_EXPORT int SSL_CIPHER_is_AESGCM(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_is_CHACHA20POLY1305 returns one if |cipher| uses + * CHACHA20_POLY1305. */ +OPENSSL_EXPORT int SSL_CIPHER_is_CHACHA20POLY1305(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_get_name returns the OpenSSL name of |cipher|. */ +OPENSSL_EXPORT const char *SSL_CIPHER_get_name(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_get_kx_name returns a string that describes the key-exchange + * method used by |cipher|. For example, "ECDHE_ECDSA". */ +OPENSSL_EXPORT const char *SSL_CIPHER_get_kx_name(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_get_rfc_name returns a newly-allocated string with the standard + * name for |cipher| or NULL on error. For example, + * "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256". The caller is responsible for + * calling |OPENSSL_free| on the result. */ +OPENSSL_EXPORT char *SSL_CIPHER_get_rfc_name(const SSL_CIPHER *cipher); + +/* SSL_CIPHER_get_bits returns the strength, in bits, of |cipher|. If + * |out_alg_bits| is not NULL, it writes the number of bits consumed by the + * symmetric algorithm to |*out_alg_bits|. */ +OPENSSL_EXPORT int SSL_CIPHER_get_bits(const SSL_CIPHER *cipher, + int *out_alg_bits); + + +/* SSL contexts. */ + +/* An SSL_METHOD selects whether to use TLS or DTLS. */ +typedef struct ssl_method_st SSL_METHOD; + +/* TLS_method is the |SSL_METHOD| used for TLS (and SSLv3) connections. */ +OPENSSL_EXPORT const SSL_METHOD *TLS_method(void); + +/* DTLS_method is the |SSL_METHOD| used for DTLS connections. */ +OPENSSL_EXPORT const SSL_METHOD *DTLS_method(void); + +/* SSL_CTX_new returns a newly-allocated |SSL_CTX| with default settings or NULL + * on error. An |SSL_CTX| manages shared state and configuration between + * multiple TLS or DTLS connections. */ +OPENSSL_EXPORT SSL_CTX *SSL_CTX_new(const SSL_METHOD *method); + +/* SSL_CTX_free releases memory associated with |ctx|. */ +OPENSSL_EXPORT void SSL_CTX_free(SSL_CTX *ctx); + + +/* SSL connections. */ + +/* SSL_new returns a newly-allocated |SSL| using |ctx| or NULL on error. An + * |SSL| object represents a single TLS or DTLS connection. It inherits settings + * from |ctx| at the time of creation. Settings may also be individually + * configured on the connection. + * + * On creation, an |SSL| is not configured to be either a client or server. Call + * |SSL_set_connect_state| or |SSL_set_accept_state| to set this. */ +OPENSSL_EXPORT SSL *SSL_new(SSL_CTX *ctx); + +/* SSL_free releases memory associated with |ssl|. */ +OPENSSL_EXPORT void SSL_free(SSL *ssl); + +/* SSL_set_connect_state configures |ssl| to be a client. */ +OPENSSL_EXPORT void SSL_set_connect_state(SSL *ssl); + +/* SSL_set_accept_state configures |ssl| to be a server. */ +OPENSSL_EXPORT void SSL_set_accept_state(SSL *ssl); + + +/* Protocol versions. */ + +#define SSL3_VERSION_MAJOR 0x03 + +#define SSL3_VERSION 0x0300 +#define TLS1_VERSION 0x0301 +#define TLS1_1_VERSION 0x0302 +#define TLS1_2_VERSION 0x0303 + +#define DTLS1_VERSION 0xfeff +#define DTLS1_2_VERSION 0xfefd + +/* SSL_CTX_set_min_version sets the minimum protocol version for |ctx| to + * |version|. */ +OPENSSL_EXPORT void SSL_CTX_set_min_version(SSL_CTX *ctx, uint16_t version); + +/* SSL_CTX_set_max_version sets the maximum protocol version for |ctx| to + * |version|. */ +OPENSSL_EXPORT void SSL_CTX_set_max_version(SSL_CTX *ctx, uint16_t version); + +/* SSL_set_min_version sets the minimum protocol version for |ssl| to + * |version|. */ +OPENSSL_EXPORT void SSL_set_min_version(SSL *ssl, uint16_t version); + +/* SSL_set_max_version sets the maximum protocol version for |ssl| to + * |version|. */ +OPENSSL_EXPORT void SSL_set_max_version(SSL *ssl, uint16_t version); + + +/* Options. + * + * Options configure protocol behavior. */ + +/* SSL_OP_LEGACY_SERVER_CONNECT allows initial connections to servers that don't + * support the renegotiation_info extension (RFC 5746). It is on by default. */ +#define SSL_OP_LEGACY_SERVER_CONNECT 0x00000004L + +/* SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER allows for record sizes |SSL3_RT_MAX_EXTRA| + * bytes above the maximum record size. */ +#define SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0x00000020L + +/* SSL_OP_TLS_D5_BUG accepts an RSAClientKeyExchange in TLS encoded as in SSL3 + * (i.e. without a length prefix). */ +#define SSL_OP_TLS_D5_BUG 0x00000100L + +/* SSL_OP_ALL enables the above bug workarounds that are enabled by many + * consumers. + * TODO(davidben): Determine which of the remaining may be removed now. */ +#define SSL_OP_ALL 0x00000BFFL + +/* SSL_OP_NO_QUERY_MTU, in DTLS, disables querying the MTU from the underlying + * |BIO|. Instead, the MTU is configured with |SSL_set_mtu|. */ +#define SSL_OP_NO_QUERY_MTU 0x00001000L + +/* SSL_OP_NO_TICKET disables session ticket support (RFC 4507). */ +#define SSL_OP_NO_TICKET 0x00004000L + +/* SSL_OP_CIPHER_SERVER_PREFERENCE configures servers to select ciphers and + * ECDHE curves according to the server's preferences instead of the + * client's. */ +#define SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000L + +/* The following flags toggle individual protocol versions. This is deprecated. + * Use |SSL_CTX_set_min_version| and |SSL_CTX_set_max_version| instead. */ +#define SSL_OP_NO_SSLv3 0x02000000L +#define SSL_OP_NO_TLSv1 0x04000000L +#define SSL_OP_NO_TLSv1_2 0x08000000L +#define SSL_OP_NO_TLSv1_1 0x10000000L +#define SSL_OP_NO_DTLSv1 SSL_OP_NO_TLSv1 +#define SSL_OP_NO_DTLSv1_2 SSL_OP_NO_TLSv1_2 + +/* The following flags do nothing and are included only to make it easier to + * compile code with BoringSSL. */ +#define SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0 +#define SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0 +#define SSL_OP_EPHEMERAL_RSA 0 +#define SSL_OP_MICROSOFT_SESS_ID_BUG 0 +#define SSL_OP_MSIE_SSLV2_RSA_PADDING 0 +#define SSL_OP_NETSCAPE_CA_DN_BUG 0 +#define SSL_OP_NETSCAPE_CHALLENGE_BUG 0 +#define SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG 0 +#define SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0 +#define SSL_OP_NO_COMPRESSION 0 +#define SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0 +#define SSL_OP_NO_SSLv2 0 +#define SSL_OP_PKCS1_CHECK_1 0 +#define SSL_OP_PKCS1_CHECK_2 0 +#define SSL_OP_SINGLE_DH_USE 0 +#define SSL_OP_SINGLE_ECDH_USE 0 +#define SSL_OP_SSLEAY_080_CLIENT_DH_BUG 0 +#define SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0 +#define SSL_OP_TLS_BLOCK_PADDING_BUG 0 +#define SSL_OP_TLS_ROLLBACK_BUG 0 + +/* SSL_CTX_set_options enables all options set in |options| (which should be one + * or more of the |SSL_OP_*| values, ORed together) in |ctx|. It returns a + * bitmask representing the resulting enabled options. */ +OPENSSL_EXPORT uint32_t SSL_CTX_set_options(SSL_CTX *ctx, uint32_t options); + +/* SSL_CTX_clear_options disables all options set in |options| (which should be + * one or more of the |SSL_OP_*| values, ORed together) in |ctx|. It returns a + * bitmask representing the resulting enabled options. */ +OPENSSL_EXPORT uint32_t SSL_CTX_clear_options(SSL_CTX *ctx, uint32_t options); + +/* SSL_CTX_get_options returns a bitmask of |SSL_OP_*| values that represent all + * the options enabled for |ctx|. */ +OPENSSL_EXPORT uint32_t SSL_CTX_get_options(const SSL_CTX *ctx); + +/* SSL_set_options enables all options set in |options| (which should be one or + * more of the |SSL_OP_*| values, ORed together) in |ssl|. It returns a bitmask + * representing the resulting enabled options. */ +OPENSSL_EXPORT uint32_t SSL_set_options(SSL *ssl, uint32_t options); + +/* SSL_clear_options disables all options set in |options| (which should be one + * or more of the |SSL_OP_*| values, ORed together) in |ssl|. It returns a + * bitmask representing the resulting enabled options. */ +OPENSSL_EXPORT uint32_t SSL_clear_options(SSL *ssl, uint32_t options); + +/* SSL_get_options returns a bitmask of |SSL_OP_*| values that represent all the + * options enabled for |ssl|. */ +OPENSSL_EXPORT uint32_t SSL_get_options(const SSL *ssl); + + +/* Modes. + * + * Modes configure API behavior. */ + +/* SSL_MODE_ENABLE_PARTIAL_WRITE allows |SSL_write| to complete with a partial + * result when the only part of the input was written in a single record. */ +#define SSL_MODE_ENABLE_PARTIAL_WRITE 0x00000001L + +/* SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER allows retrying an incomplete |SSL_write| + * with a different buffer. However, |SSL_write| still assumes the buffer + * contents are unchanged. This is not the default to avoid the misconception + * that non-blocking |SSL_write| behaves like non-blocking |write|. */ +#define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L + +/* SSL_MODE_NO_AUTO_CHAIN disables automatically building a certificate chain + * before sending certificates to the peer. + * TODO(davidben): Remove this behavior. https://crbug.com/486295. */ +#define SSL_MODE_NO_AUTO_CHAIN 0x00000008L + +/* SSL_MODE_ENABLE_FALSE_START allows clients to send application data before + * receipt of CCS and Finished. This mode enables full-handshakes to 'complete' + * in one RTT. See draft-bmoeller-tls-falsestart-01. */ +#define SSL_MODE_ENABLE_FALSE_START 0x00000080L + +/* Deprecated: SSL_MODE_HANDSHAKE_CUTTHROUGH is the same as + * SSL_MODE_ENABLE_FALSE_START. */ +#define SSL_MODE_HANDSHAKE_CUTTHROUGH SSL_MODE_ENABLE_FALSE_START + +/* SSL_MODE_CBC_RECORD_SPLITTING causes multi-byte CBC records in SSL 3.0 and + * TLS 1.0 to be split in two: the first record will contain a single byte and + * the second will contain the remainder. This effectively randomises the IV and + * prevents BEAST attacks. */ +#define SSL_MODE_CBC_RECORD_SPLITTING 0x00000100L + +/* SSL_MODE_NO_SESSION_CREATION will cause any attempts to create a session to + * fail with SSL_R_SESSION_MAY_NOT_BE_CREATED. This can be used to enforce that + * session resumption is used for a given SSL*. */ +#define SSL_MODE_NO_SESSION_CREATION 0x00000200L + +/* SSL_MODE_SEND_FALLBACK_SCSV sends TLS_FALLBACK_SCSV in the ClientHello. + * To be set only by applications that reconnect with a downgraded protocol + * version; see RFC 7507 for details. + * + * DO NOT ENABLE THIS if your application attempts a normal handshake. Only use + * this in explicit fallback retries, following the guidance in RFC 7507. */ +#define SSL_MODE_SEND_FALLBACK_SCSV 0x00000400L + +/* The following flags do nothing and are included only to make it easier to + * compile code with BoringSSL. */ +#define SSL_MODE_AUTO_RETRY 0 +#define SSL_MODE_RELEASE_BUFFERS 0 +#define SSL_MODE_SEND_CLIENTHELLO_TIME 0 +#define SSL_MODE_SEND_SERVERHELLO_TIME 0 + +/* SSL_CTX_set_mode enables all modes set in |mode| (which should be one or more + * of the |SSL_MODE_*| values, ORed together) in |ctx|. It returns a bitmask + * representing the resulting enabled modes. */ +OPENSSL_EXPORT uint32_t SSL_CTX_set_mode(SSL_CTX *ctx, uint32_t mode); + +/* SSL_CTX_clear_mode disables all modes set in |mode| (which should be one or + * more of the |SSL_MODE_*| values, ORed together) in |ctx|. It returns a + * bitmask representing the resulting enabled modes. */ +OPENSSL_EXPORT uint32_t SSL_CTX_clear_mode(SSL_CTX *ctx, uint32_t mode); + +/* SSL_CTX_get_mode returns a bitmask of |SSL_MODE_*| values that represent all + * the modes enabled for |ssl|. */ +OPENSSL_EXPORT uint32_t SSL_CTX_get_mode(const SSL_CTX *ctx); + +/* SSL_set_mode enables all modes set in |mode| (which should be one or more of + * the |SSL_MODE_*| values, ORed together) in |ssl|. It returns a bitmask + * representing the resulting enabled modes. */ +OPENSSL_EXPORT uint32_t SSL_set_mode(SSL *ssl, uint32_t mode); + +/* SSL_clear_mode disables all modes set in |mode| (which should be one or more + * of the |SSL_MODE_*| values, ORed together) in |ssl|. It returns a bitmask + * representing the resulting enabled modes. */ +OPENSSL_EXPORT uint32_t SSL_clear_mode(SSL *ssl, uint32_t mode); + +/* SSL_get_mode returns a bitmask of |SSL_MODE_*| values that represent all the + * modes enabled for |ssl|. */ +OPENSSL_EXPORT uint32_t SSL_get_mode(const SSL *ssl); + + +/* Configuring certificates and private keys. + * + * These functions configure the connection's leaf certificate, private key, and + * certificate chain. The certificate chain is ordered leaf to root (as sent on + * the wire) but does not include the leaf. Both client and server certificates + * use these functions. + * + * Certificates and keys may be configured before the handshake or dynamically + * in the early callback and certificate callback. */ + +/* SSL_CTX_use_certificate sets |ctx|'s leaf certificate to |x509|. It returns + * one on success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x509); + +/* SSL_use_certificate sets |ssl|'s leaf certificate to |x509|. It returns one + * on success and zero on failure. */ +OPENSSL_EXPORT int SSL_use_certificate(SSL *ssl, X509 *x509); + +/* SSL_CTX_use_PrivateKey sets |ctx|'s private key to |pkey|. It returns one on + * success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); + +/* SSL_use_PrivateKey sets |ssl|'s private key to |pkey|. It returns one on + * success and zero on failure. */ +OPENSSL_EXPORT int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey); + +/* SSL_CTX_set0_chain sets |ctx|'s certificate chain, excluding the leaf, to + * |chain|. On success, it returns one and takes ownership of |chain|. + * Otherwise, it returns zero. */ +OPENSSL_EXPORT int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *chain); + +/* SSL_CTX_set1_chain sets |ctx|'s certificate chain, excluding the leaf, to + * |chain|. It returns one on success and zero on failure. The caller retains + * ownership of |chain| and may release it freely. */ +OPENSSL_EXPORT int SSL_CTX_set1_chain(SSL_CTX *ctx, STACK_OF(X509) *chain); + +/* SSL_set0_chain sets |ssl|'s certificate chain, excluding the leaf, to + * |chain|. On success, it returns one and takes ownership of |chain|. + * Otherwise, it returns zero. */ +OPENSSL_EXPORT int SSL_set0_chain(SSL *ssl, STACK_OF(X509) *chain); + +/* SSL_set1_chain sets |ssl|'s certificate chain, excluding the leaf, to + * |chain|. It returns one on success and zero on failure. The caller retains + * ownership of |chain| and may release it freely. */ +OPENSSL_EXPORT int SSL_set1_chain(SSL *ssl, STACK_OF(X509) *chain); + +/* SSL_CTX_add0_chain_cert appends |x509| to |ctx|'s certificate chain. On + * success, it returns one and takes ownership of |x509|. Otherwise, it returns + * zero. */ +OPENSSL_EXPORT int SSL_CTX_add0_chain_cert(SSL_CTX *ctx, X509 *x509); + +/* SSL_CTX_add1_chain_cert appends |x509| to |ctx|'s certificate chain. It + * returns one on success and zero on failure. The caller retains ownership of + * |x509| and may release it freely. */ +OPENSSL_EXPORT int SSL_CTX_add1_chain_cert(SSL_CTX *ctx, X509 *x509); + +/* SSL_add0_chain_cert appends |x509| to |ctx|'s certificate chain. On success, + * it returns one and takes ownership of |x509|. Otherwise, it returns zero. */ +OPENSSL_EXPORT int SSL_add0_chain_cert(SSL *ssl, X509 *x509); + +/* SSL_CTX_add_extra_chain_cert calls |SSL_CTX_add0_chain_cert|. */ +OPENSSL_EXPORT int SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x509); + +/* SSL_add1_chain_cert appends |x509| to |ctx|'s certificate chain. It returns + * one on success and zero on failure. The caller retains ownership of |x509| + * and may release it freely. */ +OPENSSL_EXPORT int SSL_add1_chain_cert(SSL *ssl, X509 *x509); + +/* SSL_CTX_clear_chain_certs clears |ctx|'s certificate chain and returns + * one. */ +OPENSSL_EXPORT int SSL_CTX_clear_chain_certs(SSL_CTX *ctx); + +/* SSL_CTX_clear_extra_chain_certs calls |SSL_CTX_clear_chain_certs|. */ +OPENSSL_EXPORT int SSL_CTX_clear_extra_chain_certs(SSL_CTX *ctx); + +/* SSL_clear_chain_certs clears |ssl|'s certificate chain and returns one. */ +OPENSSL_EXPORT int SSL_clear_chain_certs(SSL *ssl); + +/* SSL_CTX_set_cert_cb sets a callback that is called to select a certificate. + * The callback returns one on success, zero on internal error, and a negative + * number on failure or to pause the handshake. If the handshake is paused, + * |SSL_get_error| will return |SSL_ERROR_WANT_X509_LOOKUP|. */ +OPENSSL_EXPORT void SSL_CTX_set_cert_cb(SSL_CTX *ctx, + int (*cb)(SSL *ssl, void *arg), + void *arg); + +/* SSL_set_cert_cb sets a callback that is called to select a certificate. The + * callback returns one on success, zero on internal error, and a negative + * number on failure or to pause the handshake. If the handshake is paused, + * |SSL_get_error| will return |SSL_ERROR_WANT_X509_LOOKUP|. */ +OPENSSL_EXPORT void SSL_set_cert_cb(SSL *ssl, int (*cb)(SSL *ssl, void *arg), + void *arg); + +/* SSL_certs_clear resets the private key, leaf certificate, and certificate + * chain of |ssl|. */ +OPENSSL_EXPORT void SSL_certs_clear(SSL *ssl); + +/* SSL_CTX_check_private_key returns one if the certificate and private key + * configured in |ctx| are consistent and zero otherwise. */ +OPENSSL_EXPORT int SSL_CTX_check_private_key(const SSL_CTX *ctx); + +/* SSL_check_private_key returns one if the certificate and private key + * configured in |ssl| are consistent and zero otherwise. */ +OPENSSL_EXPORT int SSL_check_private_key(const SSL *ssl); + +/* SSL_CTX_get0_certificate returns |ctx|'s leaf certificate. */ +OPENSSL_EXPORT X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx); + +/* SSL_get_certificate returns |ssl|'s leaf certificate. */ +OPENSSL_EXPORT X509 *SSL_get_certificate(const SSL *ssl); + +/* SSL_CTX_get0_privatekey returns |ctx|'s private key. */ +OPENSSL_EXPORT EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx); + +/* SSL_get_privatekey returns |ssl|'s private key. */ +OPENSSL_EXPORT EVP_PKEY *SSL_get_privatekey(const SSL *ssl); + +/* SSL_CTX_get0_chain_certs sets |*out_chain| to |ctx|'s certificate chain and + * returns one. */ +OPENSSL_EXPORT int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, + STACK_OF(X509) **out_chain); + +/* SSL_CTX_get_extra_chain_certs calls |SSL_CTX_get0_chain_certs|. */ +OPENSSL_EXPORT int SSL_CTX_get_extra_chain_certs(const SSL_CTX *ctx, + STACK_OF(X509) **out_chain); + +/* SSL_get0_chain_certs sets |*out_chain| to |ssl|'s certificate chain and + * returns one. */ +OPENSSL_EXPORT int SSL_get0_chain_certs(const SSL *ssl, + STACK_OF(X509) **out_chain); + + +/* Certificate and private key convenience functions. */ + +/* SSL_CTX_use_RSAPrivateKey sets |ctx|'s private key to |rsa|. It returns one + * on success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa); + +/* SSL_use_RSAPrivateKey sets |ctx|'s private key to |rsa|. It returns one on + * success and zero on failure. */ +OPENSSL_EXPORT int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa); + +/* The following functions configure certificates or private keys but take as + * input DER-encoded structures. They return one on success and zero on + * failure. */ + +OPENSSL_EXPORT int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, + const uint8_t *d); +OPENSSL_EXPORT int SSL_use_certificate_ASN1(SSL *ssl, const uint8_t *der, + int len); + +OPENSSL_EXPORT int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, + const uint8_t *d, long len); +OPENSSL_EXPORT int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, + const uint8_t *d, long len); + +OPENSSL_EXPORT int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, + const uint8_t *der, + size_t der_len); +OPENSSL_EXPORT int SSL_use_RSAPrivateKey_ASN1(SSL *ssl, const uint8_t *der, + size_t der_len); + +/* The following functions configure certificates or private keys but take as + * input files to read from. They return one on success and zero on failure. The + * |type| parameter is one of the |SSL_FILETYPE_*| values and determines whether + * the file's contents are read as PEM or DER. */ + +#define SSL_FILETYPE_ASN1 X509_FILETYPE_ASN1 +#define SSL_FILETYPE_PEM X509_FILETYPE_PEM + +OPENSSL_EXPORT int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, + const char *file, + int type); +OPENSSL_EXPORT int SSL_use_RSAPrivateKey_file(SSL *ssl, const char *file, + int type); + +OPENSSL_EXPORT int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, + int type); +OPENSSL_EXPORT int SSL_use_certificate_file(SSL *ssl, const char *file, + int type); + +OPENSSL_EXPORT int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, + int type); +OPENSSL_EXPORT int SSL_use_PrivateKey_file(SSL *ssl, const char *file, + int type); + +/* SSL_CTX_use_certificate_file configures certificates for |ctx|. It reads the + * contents of |file| as a PEM-encoded leaf certificate followed optionally by + * the certificate chain to send to the peer. It returns one on success and zero + * on failure. */ +OPENSSL_EXPORT int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, + const char *file); + + +/* Custom private keys. */ + +enum ssl_private_key_result_t { + ssl_private_key_success, + ssl_private_key_retry, + ssl_private_key_failure, +}; + +/* SSL_PRIVATE_KEY_METHOD describes private key hooks. This is used to off-load + * signing operations to a custom, potentially asynchronous, backend. */ +typedef struct ssl_private_key_method_st { + /* type returns either |EVP_PKEY_RSA| or |EVP_PKEY_EC| to denote the type of + * key used by |ssl|. */ + int (*type)(SSL *ssl); + + /* supports_digest returns one if the key used by |ssl| supports signing + * digests of type |md| and zero otherwise. */ + int (*supports_digest)(SSL *ssl, const EVP_MD *md); + + /* max_signature_len returns the maximum length of a signature signed by the + * key used by |ssl|. This must be a constant value for a given |ssl|. */ + size_t (*max_signature_len)(SSL *ssl); + + /* sign signs |in_len| bytes of digest from |in|. |md| is the hash function + * used to calculate |in|. On success, it returns |ssl_private_key_success| + * and writes at most |max_out| bytes of signature data to |out|. On failure, + * it returns |ssl_private_key_failure|. If the operation has not completed, + * it returns |ssl_private_key_retry|. |sign| should arrange for the + * high-level operation on |ssl| to be retried when the operation is + * completed. This will result in a call to |sign_complete|. + * + * If the key is an RSA key, implementations must use PKCS#1 padding. |in| is + * the digest itself, so the DigestInfo prefix, if any, must be prepended by + * |sign|. If |md| is |EVP_md5_sha1|, there is no prefix. + * + * It is an error to call |sign| while another private key operation is in + * progress on |ssl|. */ + enum ssl_private_key_result_t (*sign)(SSL *ssl, uint8_t *out, size_t *out_len, + size_t max_out, const EVP_MD *md, + const uint8_t *in, size_t in_len); + + /* sign_complete completes a pending |sign| operation. If the operation has + * completed, it returns |ssl_private_key_success| and writes the result to + * |out| as in |sign|. Otherwise, it returns |ssl_private_key_failure| on + * failure and |ssl_private_key_retry| if the operation is still in progress. + * + * |sign_complete| may be called arbitrarily many times before completion, but + * it is an error to call |sign_complete| if there is no pending |sign| + * operation in progress on |ssl|. */ + enum ssl_private_key_result_t (*sign_complete)(SSL *ssl, uint8_t *out, + size_t *out_len, size_t max_out); +} SSL_PRIVATE_KEY_METHOD; + +/* SSL_use_private_key_method configures a custom private key on |ssl|. + * |key_method| must remain valid for the lifetime of |ssl|. */ +OPENSSL_EXPORT void SSL_set_private_key_method( + SSL *ssl, const SSL_PRIVATE_KEY_METHOD *key_method); + + +/* Connection information. */ + +/* SSL_get_tls_unique writes at most |max_out| bytes of the tls-unique value + * for |ssl| to |out| and sets |*out_len| to the number of bytes written. It + * returns one on success or zero on error. In general |max_out| should be at + * least 12. + * + * This function will always fail if the initial handshake has not completed. + * The tls-unique value will change after a renegotiation but, since + * renegotiations can be initiated by the server at any point, the higher-level + * protocol must either leave them disabled or define states in which the + * tls-unique value can be read. + * + * The tls-unique value is defined by + * https://tools.ietf.org/html/rfc5929#section-3.1. Due to a weakness in the + * TLS protocol, tls-unique is broken for resumed connections unless the + * Extended Master Secret extension is negotiated. Thus this function will + * return zero if |ssl| performed session resumption unless EMS was used when + * negotiating the original session. */ +OPENSSL_EXPORT int SSL_get_tls_unique(const SSL *ssl, uint8_t *out, + size_t *out_len, size_t max_out); + + +/* Custom extensions. + * + * The custom extension functions allow TLS extensions to be added to + * ClientHello and ServerHello messages. */ + +/* SSL_custom_ext_add_cb is a callback function that is called when the + * ClientHello (for clients) or ServerHello (for servers) is constructed. In + * the case of a server, this callback will only be called for a given + * extension if the ClientHello contained that extension – it's not possible to + * inject extensions into a ServerHello that the client didn't request. + * + * When called, |extension_value| will contain the extension number that is + * being considered for addition (so that a single callback can handle multiple + * extensions). If the callback wishes to include the extension, it must set + * |*out| to point to |*out_len| bytes of extension contents and return one. In + * this case, the corresponding |SSL_custom_ext_free_cb| callback will later be + * called with the value of |*out| once that data has been copied. + * + * If the callback does not wish to add an extension it must return zero. + * + * Alternatively, the callback can abort the connection by setting + * |*out_alert_value| to a TLS alert number and returning -1. */ +typedef int (*SSL_custom_ext_add_cb)(SSL *ssl, unsigned extension_value, + const uint8_t **out, size_t *out_len, + int *out_alert_value, void *add_arg); + +/* SSL_custom_ext_free_cb is a callback function that is called by OpenSSL iff + * an |SSL_custom_ext_add_cb| callback previously returned one. In that case, + * this callback is called and passed the |out| pointer that was returned by + * the add callback. This is to free any dynamically allocated data created by + * the add callback. */ +typedef void (*SSL_custom_ext_free_cb)(SSL *ssl, unsigned extension_value, + const uint8_t *out, void *add_arg); + +/* SSL_custom_ext_parse_cb is a callback function that is called by OpenSSL to + * parse an extension from the peer: that is from the ServerHello for a client + * and from the ClientHello for a server. + * + * When called, |extension_value| will contain the extension number and the + * contents of the extension are |contents_len| bytes at |contents|. + * + * The callback must return one to continue the handshake. Otherwise, if it + * returns zero, a fatal alert with value |*out_alert_value| is sent and the + * handshake is aborted. */ +typedef int (*SSL_custom_ext_parse_cb)(SSL *ssl, unsigned extension_value, + const uint8_t *contents, + size_t contents_len, + int *out_alert_value, void *parse_arg); + +/* SSL_extension_supported returns one iff OpenSSL internally handles + * extensions of type |extension_value|. This can be used to avoid registering + * custom extension handlers for extensions that a future version of OpenSSL + * may handle internally. */ +OPENSSL_EXPORT int SSL_extension_supported(unsigned extension_value); + +/* SSL_CTX_add_client_custom_ext registers callback functions for handling + * custom TLS extensions for client connections. + * + * If |add_cb| is NULL then an empty extension will be added in each + * ClientHello. Otherwise, see the comment for |SSL_custom_ext_add_cb| about + * this callback. + * + * The |free_cb| may be NULL if |add_cb| doesn't dynamically allocate data that + * needs to be freed. + * + * It returns one on success or zero on error. It's always an error to register + * callbacks for the same extension twice, or to register callbacks for an + * extension that OpenSSL handles internally. See |SSL_extension_supported| to + * discover, at runtime, which extensions OpenSSL handles internally. */ +OPENSSL_EXPORT int SSL_CTX_add_client_custom_ext( + SSL_CTX *ctx, unsigned extension_value, SSL_custom_ext_add_cb add_cb, + SSL_custom_ext_free_cb free_cb, void *add_arg, + SSL_custom_ext_parse_cb parse_cb, void *parse_arg); + +/* SSL_CTX_add_server_custom_ext is the same as + * |SSL_CTX_add_client_custom_ext|, but for server connections. + * + * Unlike on the client side, if |add_cb| is NULL no extension will be added. + * The |add_cb|, if any, will only be called if the ClientHello contained a + * matching extension. */ +OPENSSL_EXPORT int SSL_CTX_add_server_custom_ext( + SSL_CTX *ctx, unsigned extension_value, SSL_custom_ext_add_cb add_cb, + SSL_custom_ext_free_cb free_cb, void *add_arg, + SSL_custom_ext_parse_cb parse_cb, void *parse_arg); + + +/* Session tickets. */ + +/* SSL_CTX_get_tlsext_ticket_keys writes |ctx|'s session ticket key material to + * |len| bytes of |out|. It returns one on success and zero if |len| is not + * 48. If |out| is NULL, it returns 48 instead. */ +OPENSSL_EXPORT int SSL_CTX_get_tlsext_ticket_keys(SSL_CTX *ctx, void *out, + size_t len); + +/* SSL_CTX_set_tlsext_ticket_keys sets |ctx|'s session ticket key material to + * |len| bytes of |in|. It returns one on success and zero if |len| is not + * 48. If |in| is NULL, it returns 48 instead. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_ticket_keys(SSL_CTX *ctx, const void *in, + size_t len); + +/* SSL_TICKET_KEY_NAME_LEN is the length of the key name prefix of a session + * ticket. */ +#define SSL_TICKET_KEY_NAME_LEN 16 + +/* SSL_CTX_set_tlsext_ticket_key_cb sets the ticket callback to |callback| and + * returns one. |callback| will be called when encrypting a new ticket and when + * decrypting a ticket from the client. + * + * In both modes, |ctx| and |hmac_ctx| will already have been initialized with + * |EVP_CIPHER_CTX_init| and |HMAC_CTX_init|, respectively. |callback| + * configures |hmac_ctx| with an HMAC digest and key, and configures |ctx| + * for encryption or decryption, based on the mode. + * + * When encrypting a new ticket, |encrypt| will be one. It writes a public + * 16-byte key name to |key_name| and a fresh IV to |iv|. The output IV length + * must match |EVP_CIPHER_CTX_iv_length| of the cipher selected. In this mode, + * |callback| returns 1 on success and -1 on error. + * + * When decrypting a ticket, |encrypt| will be zero. |key_name| will point to a + * 16-byte key name and |iv| points to an IV. The length of the IV consumed must + * match |EVP_CIPHER_CTX_iv_length| of the cipher selected. In this mode, + * |callback| returns -1 to abort the handshake, 0 if decrypting the ticket + * failed, and 1 or 2 on success. If it returns 2, the ticket will be renewed. + * This may be used to re-key the ticket. + * + * WARNING: |callback| wildly breaks the usual return value convention and is + * called in two different modes. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_ticket_key_cb( + SSL_CTX *ctx, int (*callback)(SSL *ssl, uint8_t *key_name, uint8_t *iv, + EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx, + int encrypt)); + + +/* Underdocumented functions. + * + * Functions below here haven't been touched up and may be underdocumented. */ + +/* SSLeay version number for ASN.1 encoding of the session information */ +/* Version 0 - initial version + * Version 1 - added the optional peer certificate. */ +#define SSL_SESSION_ASN1_VERSION 0x0001 + +#define SSL_MAX_SSL_SESSION_ID_LENGTH 32 +#define SSL_MAX_SID_CTX_LENGTH 32 +#define SSL_MAX_MASTER_KEY_LENGTH 48 + +/* These are used to specify which ciphers to use and not to use */ + +#define SSL_TXT_MEDIUM "MEDIUM" +#define SSL_TXT_HIGH "HIGH" +#define SSL_TXT_FIPS "FIPS" + +#define SSL_TXT_kRSA "kRSA" +#define SSL_TXT_kDHE "kDHE" +#define SSL_TXT_kEDH "kEDH" /* same as "kDHE" */ +#define SSL_TXT_kECDHE "kECDHE" +#define SSL_TXT_kEECDH "kEECDH" /* same as "kECDHE" */ +#define SSL_TXT_kPSK "kPSK" + +#define SSL_TXT_aRSA "aRSA" +#define SSL_TXT_aECDSA "aECDSA" +#define SSL_TXT_aPSK "aPSK" + +#define SSL_TXT_DH "DH" +#define SSL_TXT_DHE "DHE" /* same as "kDHE" */ +#define SSL_TXT_EDH "EDH" /* same as "DHE" */ +#define SSL_TXT_RSA "RSA" +#define SSL_TXT_ECDH "ECDH" +#define SSL_TXT_ECDHE "ECDHE" /* same as "kECDHE" */ +#define SSL_TXT_EECDH "EECDH" /* same as "ECDHE" */ +#define SSL_TXT_ECDSA "ECDSA" +#define SSL_TXT_PSK "PSK" + +#define SSL_TXT_3DES "3DES" +#define SSL_TXT_RC4 "RC4" +#define SSL_TXT_AES128 "AES128" +#define SSL_TXT_AES256 "AES256" +#define SSL_TXT_AES "AES" +#define SSL_TXT_AES_GCM "AESGCM" +#define SSL_TXT_CHACHA20 "CHACHA20" + +#define SSL_TXT_MD5 "MD5" +#define SSL_TXT_SHA1 "SHA1" +#define SSL_TXT_SHA "SHA" /* same as "SHA1" */ +#define SSL_TXT_SHA256 "SHA256" +#define SSL_TXT_SHA384 "SHA384" + +#define SSL_TXT_SSLV3 "SSLv3" +#define SSL_TXT_TLSV1 "TLSv1" +#define SSL_TXT_TLSV1_1 "TLSv1.1" +#define SSL_TXT_TLSV1_2 "TLSv1.2" + +#define SSL_TXT_ALL "ALL" + +/* COMPLEMENTOF* definitions. These identifiers are used to (de-select) ciphers + * normally not being used. + * + * Example: "RC4" will activate all ciphers using RC4 including ciphers without + * authentication, which would normally disabled by DEFAULT (due the "!ADH" + * being part of default). Therefore "RC4:!COMPLEMENTOFDEFAULT" will make sure + * that it is also disabled in the specific selection. COMPLEMENTOF* + * identifiers are portable between version, as adjustments to the default + * cipher setup will also be included here. + * + * COMPLEMENTOFDEFAULT does not experience the same special treatment that + * DEFAULT gets, as only selection is being done and no sorting as needed for + * DEFAULT. */ +#define SSL_TXT_CMPDEF "COMPLEMENTOFDEFAULT" + +/* The following cipher list is used by default. It also is substituted when an + * application-defined cipher list string starts with 'DEFAULT'. */ +#define SSL_DEFAULT_CIPHER_LIST "ALL" + +/* As of OpenSSL 1.0.0, ssl_create_cipher_list() in ssl/ssl_ciph.c always + * starts with a reasonable order, and all we have to do for DEFAULT is + * throwing out anonymous and unencrypted ciphersuites! (The latter are not + * actually enabled by ALL, but "ALL:RSA" would enable some of them.) */ + +/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */ +#define SSL_SENT_SHUTDOWN 1 +#define SSL_RECEIVED_SHUTDOWN 2 + +typedef struct ssl_protocol_method_st SSL_PROTOCOL_METHOD; +typedef struct ssl_session_st SSL_SESSION; +typedef struct ssl_conf_ctx_st SSL_CONF_CTX; +typedef struct ssl3_enc_method SSL3_ENC_METHOD; + +/* SRTP protection profiles for use with the use_srtp extension (RFC 5764). */ +typedef struct srtp_protection_profile_st { + const char *name; + unsigned long id; +} SRTP_PROTECTION_PROFILE; + +DECLARE_STACK_OF(SRTP_PROTECTION_PROFILE) + +/* An SSL_SESSION represents an SSL session that may be resumed in an + * abbreviated handshake. */ +struct ssl_session_st { + int ssl_version; /* what ssl version session info is being kept in here? */ + + int master_key_length; + uint8_t master_key[SSL_MAX_MASTER_KEY_LENGTH]; + /* session_id - valid? */ + unsigned int session_id_length; + uint8_t session_id[SSL_MAX_SSL_SESSION_ID_LENGTH]; + /* this is used to determine whether the session is being reused in + * the appropriate context. It is up to the application to set this, + * via SSL_new */ + unsigned int sid_ctx_length; + uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + + char *psk_identity; + /* Used to indicate that session resumption is not allowed. Applications can + * also set this bit for a new session via not_resumable_session_cb to + * disable session caching and tickets. */ + int not_resumable; + + /* The cert is the certificate used to establish this connection + * + * TODO(davidben): Remove this field. It is not serialized as part of the + * session, but some APIs access it. Certificate-related fields, where not + * redundant with |peer|, should be added to the session. Others should + * probably not be retained across resumptions. */ + struct sess_cert_st /* SESS_CERT */ *sess_cert; + + /* This is the cert for the other end. On clients, it will be the same as + * sess_cert->peer_key->x509 (the latter is not enough as sess_cert is not + * retained in the external representation of sessions, see ssl_asn1.c). */ + X509 *peer; + /* when app_verify_callback accepts a session where the peer's certificate is + * not ok, we must remember the error for session reuse: */ + long verify_result; /* only for servers */ + + CRYPTO_refcount_t references; + long timeout; + long time; + + const SSL_CIPHER *cipher; + + CRYPTO_EX_DATA ex_data; /* application specific data */ + + /* These are used to make removal of session-ids more efficient and to + * implement a maximum cache size. */ + SSL_SESSION *prev, *next; + char *tlsext_hostname; + /* RFC4507 info */ + uint8_t *tlsext_tick; /* Session ticket */ + size_t tlsext_ticklen; /* Session ticket length */ + uint32_t tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */ + + size_t tlsext_signed_cert_timestamp_list_length; + uint8_t *tlsext_signed_cert_timestamp_list; /* Server's list. */ + + /* The OCSP response that came with the session. */ + size_t ocsp_response_length; + uint8_t *ocsp_response; + + char peer_sha256_valid; /* Non-zero if peer_sha256 is valid */ + uint8_t + peer_sha256[SHA256_DIGEST_LENGTH]; /* SHA256 of peer certificate */ + + /* original_handshake_hash contains the handshake hash (either SHA-1+MD5 or + * SHA-2, depending on TLS version) for the original, full handshake that + * created a session. This is used by Channel IDs during resumption. */ + uint8_t original_handshake_hash[EVP_MAX_MD_SIZE]; + unsigned int original_handshake_hash_len; + + /* extended_master_secret is true if the master secret in this session was + * generated using EMS and thus isn't vulnerable to the Triple Handshake + * attack. */ + char extended_master_secret; +}; + + +/* SSL_set_mtu sets the |ssl|'s MTU in DTLS to |mtu|. It returns one on success + * and zero on failure. */ +OPENSSL_EXPORT int SSL_set_mtu(SSL *ssl, unsigned mtu); + +/* SSL_get_secure_renegotiation_support returns one if the peer supports secure + * renegotiation (RFC 5746) and zero otherwise. */ +OPENSSL_EXPORT int SSL_get_secure_renegotiation_support(const SSL *ssl); + +/* SSL_CTX_set_msg_callback installs |cb| as the message callback for |ctx|. + * This callback will be called when sending or receiving low-level record + * headers, complete handshake messages, ChangeCipherSpec, and alerts. + * |write_p| is one for outgoing messages and zero for incoming messages. + * + * For each record header, |cb| is called with |version| = 0 and |content_type| + * = |SSL3_RT_HEADER|. The |len| bytes from |buf| contain the header. Note that + * this does not include the record body. If the record is sealed, the length + * in the header is the length of the ciphertext. + * + * For each handshake message, ChangeCipherSpec, and alert, |version| is the + * protocol version and |content_type| is the corresponding record type. The + * |len| bytes from |buf| contain the handshake message, one-byte + * ChangeCipherSpec body, and two-byte alert, respectively. */ +OPENSSL_EXPORT void SSL_CTX_set_msg_callback( + SSL_CTX *ctx, void (*cb)(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg)); + +/* SSL_CTX_set_msg_callback_arg sets the |arg| parameter of the message + * callback. */ +OPENSSL_EXPORT void SSL_CTX_set_msg_callback_arg(SSL_CTX *ctx, void *arg); + +/* SSL_set_msg_callback installs |cb| as the message callback of |ssl|. See + * |SSL_CTX_set_msg_callback| for when this callback is called. */ +OPENSSL_EXPORT void SSL_set_msg_callback( + SSL *ssl, void (*cb)(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg)); + +/* SSL_set_msg_callback_arg sets the |arg| parameter of the message callback. */ +OPENSSL_EXPORT void SSL_set_msg_callback_arg(SSL *ssl, void *arg); + +/* SSL_CTX_set_keylog_bio sets configures all SSL objects attached to |ctx| to + * log session material to |keylog_bio|. This is intended for debugging use + * with tools like Wireshark. |ctx| takes ownership of |keylog_bio|. + * + * The format is described in + * https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format. */ +OPENSSL_EXPORT void SSL_CTX_set_keylog_bio(SSL_CTX *ctx, BIO *keylog_bio); + + +struct ssl_aead_ctx_st; +typedef struct ssl_aead_ctx_st SSL_AEAD_CTX; + +#define SSL_MAX_CERT_LIST_DEFAULT 1024 * 100 /* 100k max cert list */ + +#define SSL_SESSION_CACHE_MAX_SIZE_DEFAULT (1024 * 20) + +#define SSL_DEFAULT_SESSION_TIMEOUT (2 * 60 * 60) + +/* This callback type is used inside SSL_CTX, SSL, and in the functions that + * set them. It is used to override the generation of SSL/TLS session IDs in a + * server. Return value should be zero on an error, non-zero to proceed. Also, + * callbacks should themselves check if the id they generate is unique + * otherwise the SSL handshake will fail with an error - callbacks can do this + * using the 'ssl' value they're passed by; + * SSL_has_matching_session_id(ssl, id, *id_len) + * The length value passed in is set at the maximum size the session ID can be. + * In SSLv2 this is 16 bytes, whereas SSLv3/TLSv1 it is 32 bytes. The callback + * can alter this length to be less if desired, but under SSLv2 session IDs are + * supposed to be fixed at 16 bytes so the id will be padded after the callback + * returns in this case. It is also an error for the callback to set the size + * to zero. */ +typedef int (*GEN_SESSION_CB)(const SSL *ssl, uint8_t *id, + unsigned int *id_len); + +/* ssl_early_callback_ctx is passed to certain callbacks that are called very + * early on during the server handshake. At this point, much of the SSL* hasn't + * been filled out and only the ClientHello can be depended on. */ +struct ssl_early_callback_ctx { + SSL *ssl; + const uint8_t *client_hello; + size_t client_hello_len; + const uint8_t *session_id; + size_t session_id_len; + const uint8_t *cipher_suites; + size_t cipher_suites_len; + const uint8_t *compression_methods; + size_t compression_methods_len; + const uint8_t *extensions; + size_t extensions_len; +}; + +/* SSL_early_callback_ctx_extension_get searches the extensions in |ctx| for an + * extension of the given type. If not found, it returns zero. Otherwise it + * sets |out_data| to point to the extension contents (not including the type + * and length bytes), sets |out_len| to the length of the extension contents + * and returns one. */ +OPENSSL_EXPORT char SSL_early_callback_ctx_extension_get( + const struct ssl_early_callback_ctx *ctx, uint16_t extension_type, + const uint8_t **out_data, size_t *out_len); + +typedef struct ssl_comp_st SSL_COMP; + +struct ssl_comp_st { + int id; + const char *name; + char *method; +}; + +DECLARE_STACK_OF(SSL_COMP) +DECLARE_LHASH_OF(SSL_SESSION) + +/* ssl_cipher_preference_list_st contains a list of SSL_CIPHERs with + * equal-preference groups. For TLS clients, the groups are moot because the + * server picks the cipher and groups cannot be expressed on the wire. However, + * for servers, the equal-preference groups allow the client's preferences to + * be partially respected. (This only has an effect with + * SSL_OP_CIPHER_SERVER_PREFERENCE). + * + * The equal-preference groups are expressed by grouping SSL_CIPHERs together. + * All elements of a group have the same priority: no ordering is expressed + * within a group. + * + * The values in |ciphers| are in one-to-one correspondence with + * |in_group_flags|. (That is, sk_SSL_CIPHER_num(ciphers) is the number of + * bytes in |in_group_flags|.) The bytes in |in_group_flags| are either 1, to + * indicate that the corresponding SSL_CIPHER is not the last element of a + * group, or 0 to indicate that it is. + * + * For example, if |in_group_flags| contains all zeros then that indicates a + * traditional, fully-ordered preference. Every SSL_CIPHER is the last element + * of the group (i.e. they are all in a one-element group). + * + * For a more complex example, consider: + * ciphers: A B C D E F + * in_group_flags: 1 1 0 0 1 0 + * + * That would express the following, order: + * + * A E + * B -> D -> F + * C + */ +struct ssl_cipher_preference_list_st { + STACK_OF(SSL_CIPHER) *ciphers; + uint8_t *in_group_flags; +}; + +struct ssl_ctx_st { + const SSL_PROTOCOL_METHOD *method; + + /* lock is used to protect various operations on this object. */ + CRYPTO_MUTEX lock; + + /* max_version is the maximum acceptable protocol version. If zero, the + * maximum supported version, currently (D)TLS 1.2, is used. */ + uint16_t max_version; + + /* min_version is the minimum acceptable protocl version. If zero, the + * minimum supported version, currently SSL 3.0 and DTLS 1.0, is used */ + uint16_t min_version; + + struct ssl_cipher_preference_list_st *cipher_list; + /* same as above but sorted for lookup */ + STACK_OF(SSL_CIPHER) *cipher_list_by_id; + /* cipher_list_tls11 is the list of ciphers when TLS 1.1 or greater is in + * use. This only applies to server connections as, for clients, the version + * number is known at connect time and so the cipher list can be set then. */ + struct ssl_cipher_preference_list_st *cipher_list_tls11; + + X509_STORE *cert_store; + LHASH_OF(SSL_SESSION) *sessions; + /* Most session-ids that will be cached, default is + * SSL_SESSION_CACHE_MAX_SIZE_DEFAULT. 0 is unlimited. */ + unsigned long session_cache_size; + SSL_SESSION *session_cache_head; + SSL_SESSION *session_cache_tail; + + /* handshakes_since_cache_flush is the number of successful handshakes since + * the last cache flush. */ + int handshakes_since_cache_flush; + + /* This can have one of 2 values, ored together, + * SSL_SESS_CACHE_CLIENT, + * SSL_SESS_CACHE_SERVER, + * Default is SSL_SESSION_CACHE_SERVER, which means only + * SSL_accept which cache SSL_SESSIONS. */ + int session_cache_mode; + + /* If timeout is not 0, it is the default timeout value set when SSL_new() is + * called. This has been put in to make life easier to set things up */ + long session_timeout; + + /* If this callback is not null, it will be called each time a session id is + * added to the cache. If this function returns 1, it means that the + * callback will do a SSL_SESSION_free() when it has finished using it. + * Otherwise, on 0, it means the callback has finished with it. If + * remove_session_cb is not null, it will be called when a session-id is + * removed from the cache. After the call, OpenSSL will SSL_SESSION_free() + * it. */ + int (*new_session_cb)(SSL *ssl, SSL_SESSION *sess); + void (*remove_session_cb)(SSL_CTX *ctx, SSL_SESSION *sess); + SSL_SESSION *(*get_session_cb)(SSL *ssl, uint8_t *data, int len, + int *copy); + + CRYPTO_refcount_t references; + + /* if defined, these override the X509_verify_cert() calls */ + int (*app_verify_callback)(X509_STORE_CTX *, void *); + void *app_verify_arg; + /* before OpenSSL 0.9.7, 'app_verify_arg' was ignored ('app_verify_callback' + * was called with just one argument) */ + + /* Default password callback. */ + pem_password_cb *default_passwd_callback; + + /* Default password callback user data. */ + void *default_passwd_callback_userdata; + + /* get client cert callback */ + int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey); + + /* get channel id callback */ + void (*channel_id_cb)(SSL *ssl, EVP_PKEY **pkey); + + CRYPTO_EX_DATA ex_data; + + /* custom_*_extensions stores any callback sets for custom extensions. Note + * that these pointers will be NULL if the stack would otherwise be empty. */ + STACK_OF(SSL_CUSTOM_EXTENSION) *client_custom_extensions; + STACK_OF(SSL_CUSTOM_EXTENSION) *server_custom_extensions; + + /* Default values used when no per-SSL value is defined follow */ + + void (*info_callback)(const SSL *ssl, int type, + int val); /* used if SSL's info_callback is NULL */ + + /* what we put in client cert requests */ + STACK_OF(X509_NAME) *client_CA; + + + /* Default values to use in SSL structures follow (these are copied by + * SSL_new) */ + + uint32_t options; + uint32_t mode; + uint32_t max_cert_list; + + struct cert_st /* CERT */ *cert; + + /* callback that allows applications to peek at protocol messages */ + void (*msg_callback)(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg); + void *msg_callback_arg; + + int verify_mode; + unsigned int sid_ctx_length; + uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + int (*default_verify_callback)( + int ok, X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */ + + /* Default generate session ID callback. */ + GEN_SESSION_CB generate_session_id; + + X509_VERIFY_PARAM *param; + + /* select_certificate_cb is called before most ClientHello processing and + * before the decision whether to resume a session is made. It may return one + * to continue the handshake or zero to cause the handshake loop to return + * with an error and cause SSL_get_error to return + * SSL_ERROR_PENDING_CERTIFICATE. Note: when the handshake loop is resumed, it + * will not call the callback a second time. */ + int (*select_certificate_cb)(const struct ssl_early_callback_ctx *); + + /* dos_protection_cb is called once the resumption decision for a ClientHello + * has been made. It returns one to continue the handshake or zero to + * abort. */ + int (*dos_protection_cb) (const struct ssl_early_callback_ctx *); + + /* quiet_shutdown is true if the connection should not send a close_notify on + * shutdown. */ + int quiet_shutdown; + + /* Maximum amount of data to send in one fragment. actual record size can be + * more than this due to padding and MAC overheads. */ + uint16_t max_send_fragment; + + /* TLS extensions servername callback */ + int (*tlsext_servername_callback)(SSL *, int *, void *); + void *tlsext_servername_arg; + /* RFC 4507 session ticket keys */ + uint8_t tlsext_tick_key_name[SSL_TICKET_KEY_NAME_LEN]; + uint8_t tlsext_tick_hmac_key[16]; + uint8_t tlsext_tick_aes_key[16]; + /* Callback to support customisation of ticket key setting */ + int (*tlsext_ticket_key_cb)(SSL *ssl, uint8_t *name, uint8_t *iv, + EVP_CIPHER_CTX *ectx, HMAC_CTX *hctx, int enc); + + /* Server-only: psk_identity_hint is the default identity hint to send in + * PSK-based key exchanges. */ + char *psk_identity_hint; + + unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, + char *identity, + unsigned int max_identity_len, + uint8_t *psk, unsigned int max_psk_len); + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + uint8_t *psk, unsigned int max_psk_len); + + + /* retain_only_sha256_of_client_certs is true if we should compute the SHA256 + * hash of the peer's certifiate and then discard it to save memory and + * session space. Only effective on the server side. */ + char retain_only_sha256_of_client_certs; + + /* Next protocol negotiation information */ + /* (for experimental NPN extension). */ + + /* For a server, this contains a callback function by which the set of + * advertised protocols can be provided. */ + int (*next_protos_advertised_cb)(SSL *s, const uint8_t **buf, + unsigned int *len, void *arg); + void *next_protos_advertised_cb_arg; + /* For a client, this contains a callback function that selects the + * next protocol from the list provided by the server. */ + int (*next_proto_select_cb)(SSL *s, uint8_t **out, uint8_t *outlen, + const uint8_t *in, unsigned int inlen, void *arg); + void *next_proto_select_cb_arg; + + /* ALPN information + * (we are in the process of transitioning from NPN to ALPN.) */ + + /* For a server, this contains a callback function that allows the + * server to select the protocol for the connection. + * out: on successful return, this must point to the raw protocol + * name (without the length prefix). + * outlen: on successful return, this contains the length of |*out|. + * in: points to the client's list of supported protocols in + * wire-format. + * inlen: the length of |in|. */ + int (*alpn_select_cb)(SSL *s, const uint8_t **out, uint8_t *outlen, + const uint8_t *in, unsigned int inlen, void *arg); + void *alpn_select_cb_arg; + + /* For a client, this contains the list of supported protocols in wire + * format. */ + uint8_t *alpn_client_proto_list; + unsigned alpn_client_proto_list_len; + + /* SRTP profiles we are willing to do from RFC 5764 */ + STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; + + /* EC extension values inherited by SSL structure */ + size_t tlsext_ellipticcurvelist_length; + uint16_t *tlsext_ellipticcurvelist; + + /* If true, a client will advertise the Channel ID extension and a server + * will echo it. */ + char tlsext_channel_id_enabled; + /* The client's Channel ID private key. */ + EVP_PKEY *tlsext_channel_id_private; + + /* If true, a client will request certificate timestamps. */ + char signed_cert_timestamps_enabled; + + /* If true, a client will request a stapled OCSP response. */ + char ocsp_stapling_enabled; + + /* If not NULL, session key material will be logged to this BIO for debugging + * purposes. The format matches NSS's and is readable by Wireshark. */ + BIO *keylog_bio; + + /* current_time_cb, if not NULL, is the function to use to get the current + * time. It sets |*out_clock| to the current time. */ + void (*current_time_cb)(const SSL *ssl, struct timeval *out_clock); +}; + +OPENSSL_EXPORT LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx); + +/* SSL_CTX_sess_number returns the number of sessions in |ctx|'s internal + * session cache. */ +OPENSSL_EXPORT size_t SSL_CTX_sess_number(const SSL_CTX *ctx); + +OPENSSL_EXPORT void SSL_CTX_sess_set_new_cb( + SSL_CTX *ctx, int (*new_session_cb)(SSL *ssl, SSL_SESSION *sess)); +OPENSSL_EXPORT int (*SSL_CTX_sess_get_new_cb(SSL_CTX *ctx))(SSL *ssl, + SSL_SESSION *sess); +OPENSSL_EXPORT void SSL_CTX_sess_set_remove_cb( + SSL_CTX *ctx, + void (*remove_session_cb)(SSL_CTX *ctx, SSL_SESSION *sess)); +OPENSSL_EXPORT void (*SSL_CTX_sess_get_remove_cb(SSL_CTX *ctx))( + SSL_CTX *ctx, SSL_SESSION *sess); +OPENSSL_EXPORT void SSL_CTX_sess_set_get_cb( + SSL_CTX *ctx, + SSL_SESSION *(*get_session_cb)(SSL *ssl, uint8_t *data, int len, + int *copy)); +OPENSSL_EXPORT SSL_SESSION *(*SSL_CTX_sess_get_get_cb(SSL_CTX *ctx))( + SSL *ssl, uint8_t *data, int len, int *copy); +/* SSL_magic_pending_session_ptr returns a magic SSL_SESSION* which indicates + * that the session isn't currently unavailable. SSL_get_error will then return + * SSL_ERROR_PENDING_SESSION and the handshake can be retried later when the + * lookup has completed. */ +OPENSSL_EXPORT SSL_SESSION *SSL_magic_pending_session_ptr(void); +OPENSSL_EXPORT void SSL_CTX_set_info_callback(SSL_CTX *ctx, + void (*cb)(const SSL *ssl, + int type, int val)); +OPENSSL_EXPORT void (*SSL_CTX_get_info_callback(SSL_CTX *ctx))(const SSL *ssl, + int type, + int val); +OPENSSL_EXPORT void SSL_CTX_set_client_cert_cb( + SSL_CTX *ctx, + int (*client_cert_cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey)); +OPENSSL_EXPORT int (*SSL_CTX_get_client_cert_cb(SSL_CTX *ctx))(SSL *ssl, + X509 **x509, + EVP_PKEY **pkey); +OPENSSL_EXPORT void SSL_CTX_set_channel_id_cb( + SSL_CTX *ctx, void (*channel_id_cb)(SSL *ssl, EVP_PKEY **pkey)); +OPENSSL_EXPORT void (*SSL_CTX_get_channel_id_cb(SSL_CTX *ctx))(SSL *ssl, + EVP_PKEY **pkey); + +/* SSL_enable_signed_cert_timestamps causes |ssl| (which must be the client end + * of a connection) to request SCTs from the server. See + * https://tools.ietf.org/html/rfc6962. It returns one. */ +OPENSSL_EXPORT int SSL_enable_signed_cert_timestamps(SSL *ssl); + +/* SSL_CTX_enable_signed_cert_timestamps enables SCT requests on all client SSL + * objects created from |ctx|. */ +OPENSSL_EXPORT void SSL_CTX_enable_signed_cert_timestamps(SSL_CTX *ctx); + +/* SSL_enable_ocsp_stapling causes |ssl| (which must be the client end of a + * connection) to request a stapled OCSP response from the server. It returns + * one. */ +OPENSSL_EXPORT int SSL_enable_ocsp_stapling(SSL *ssl); + +/* SSL_CTX_enable_ocsp_stapling enables OCSP stapling on all client SSL objects + * created from |ctx|. */ +OPENSSL_EXPORT void SSL_CTX_enable_ocsp_stapling(SSL_CTX *ctx); + +/* SSL_get0_signed_cert_timestamp_list sets |*out| and |*out_len| to point to + * |*out_len| bytes of SCT information from the server. This is only valid if + * |ssl| is a client. The SCT information is a SignedCertificateTimestampList + * (including the two leading length bytes). + * See https://tools.ietf.org/html/rfc6962#section-3.3 + * If no SCT was received then |*out_len| will be zero on return. + * + * WARNING: the returned data is not guaranteed to be well formed. */ +OPENSSL_EXPORT void SSL_get0_signed_cert_timestamp_list(const SSL *ssl, + const uint8_t **out, + size_t *out_len); + +/* SSL_get0_ocsp_response sets |*out| and |*out_len| to point to |*out_len| + * bytes of an OCSP response from the server. This is the DER encoding of an + * OCSPResponse type as defined in RFC 2560. + * + * WARNING: the returned data is not guaranteed to be well formed. */ +OPENSSL_EXPORT void SSL_get0_ocsp_response(const SSL *ssl, const uint8_t **out, + size_t *out_len); + +OPENSSL_EXPORT void SSL_CTX_set_next_protos_advertised_cb( + SSL_CTX *s, + int (*cb)(SSL *ssl, const uint8_t **out, unsigned int *outlen, void *arg), + void *arg); +OPENSSL_EXPORT void SSL_CTX_set_next_proto_select_cb( + SSL_CTX *s, int (*cb)(SSL *ssl, uint8_t **out, uint8_t *outlen, + const uint8_t *in, unsigned int inlen, void *arg), + void *arg); +OPENSSL_EXPORT void SSL_get0_next_proto_negotiated(const SSL *s, + const uint8_t **data, + unsigned *len); + +OPENSSL_EXPORT int SSL_select_next_proto(uint8_t **out, uint8_t *outlen, + const uint8_t *in, unsigned int inlen, + const uint8_t *client, + unsigned int client_len); + +#define OPENSSL_NPN_UNSUPPORTED 0 +#define OPENSSL_NPN_NEGOTIATED 1 +#define OPENSSL_NPN_NO_OVERLAP 2 + +/* SSL_CTX_set_alpn_protos sets the ALPN protocol list on |ctx| to |protos|. + * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit + * length-prefixed strings). It returns zero on success and one on failure. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. */ +OPENSSL_EXPORT int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const uint8_t *protos, + unsigned protos_len); + +/* SSL_set_alpn_protos sets the ALPN protocol list on |ssl| to |protos|. + * |protos| must be in wire-format (i.e. a series of non-empty, 8-bit + * length-prefixed strings). It returns zero on success and one on failure. + * + * WARNING: this function is dangerous because it breaks the usual return value + * convention. */ +OPENSSL_EXPORT int SSL_set_alpn_protos(SSL *ssl, const uint8_t *protos, + unsigned protos_len); + +OPENSSL_EXPORT void SSL_CTX_set_alpn_select_cb( + SSL_CTX *ctx, int (*cb)(SSL *ssl, const uint8_t **out, uint8_t *outlen, + const uint8_t *in, unsigned int inlen, void *arg), + void *arg); +OPENSSL_EXPORT void SSL_get0_alpn_selected(const SSL *ssl, const uint8_t **data, + unsigned *len); + +/* SSL_set_reject_peer_renegotiations controls whether renegotiation attempts by + * the peer are rejected. It may be set at any point in a connection's lifetime + * to control future renegotiations programmatically. By default, renegotiations + * are rejected. (Renegotiations requested by a client are always rejected.) */ +OPENSSL_EXPORT void SSL_set_reject_peer_renegotiations(SSL *ssl, int reject); + +/* the maximum length of the buffer given to callbacks containing the resulting + * identity/psk */ +#define PSK_MAX_IDENTITY_LEN 128 +#define PSK_MAX_PSK_LEN 256 +OPENSSL_EXPORT void SSL_CTX_set_psk_client_callback( + SSL_CTX *ctx, + unsigned int (*psk_client_callback)( + SSL *ssl, const char *hint, char *identity, + unsigned int max_identity_len, uint8_t *psk, unsigned int max_psk_len)); +OPENSSL_EXPORT void SSL_set_psk_client_callback( + SSL *ssl, unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, + char *identity, + unsigned int max_identity_len, + uint8_t *psk, + unsigned int max_psk_len)); +OPENSSL_EXPORT void SSL_CTX_set_psk_server_callback( + SSL_CTX *ctx, + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + uint8_t *psk, + unsigned int max_psk_len)); +OPENSSL_EXPORT void SSL_set_psk_server_callback( + SSL *ssl, + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + uint8_t *psk, + unsigned int max_psk_len)); +OPENSSL_EXPORT int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, + const char *identity_hint); +OPENSSL_EXPORT int SSL_use_psk_identity_hint(SSL *s, const char *identity_hint); +OPENSSL_EXPORT const char *SSL_get_psk_identity_hint(const SSL *s); +OPENSSL_EXPORT const char *SSL_get_psk_identity(const SSL *s); + +#define SSL_NOTHING 1 +#define SSL_WRITING 2 +#define SSL_READING 3 +#define SSL_X509_LOOKUP 4 +#define SSL_CHANNEL_ID_LOOKUP 5 +#define SSL_PENDING_SESSION 7 +#define SSL_CERTIFICATE_SELECTION_PENDING 8 +#define SSL_PRIVATE_KEY_OPERATION 9 + +/* These will only be used when doing non-blocking IO */ +#define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING) +#define SSL_want_read(s) (SSL_want(s) == SSL_READING) +#define SSL_want_write(s) (SSL_want(s) == SSL_WRITING) +#define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_X509_LOOKUP) +#define SSL_want_channel_id_lookup(s) (SSL_want(s) == SSL_CHANNEL_ID_LOOKUP) +#define SSL_want_session(s) (SSL_want(s) == SSL_PENDING_SESSION) +#define SSL_want_certificate(s) \ + (SSL_want(s) == SSL_CERTIFICATE_SELECTION_PENDING) +#define SSL_want_private_key_operation(s) \ + (SSL_want(s) == SSL_PRIVATE_KEY_OPERATION) + +struct ssl_st { + /* version is the protocol version. */ + int version; + + /* method is the method table corresponding to the current protocol (DTLS or + * TLS). */ + const SSL_PROTOCOL_METHOD *method; + + /* enc_method is the method table corresponding to the current protocol + * version. */ + const SSL3_ENC_METHOD *enc_method; + + /* max_version is the maximum acceptable protocol version. If zero, the + * maximum supported version, currently (D)TLS 1.2, is used. */ + uint16_t max_version; + + /* min_version is the minimum acceptable protocl version. If zero, the + * minimum supported version, currently SSL 3.0 and DTLS 1.0, is used */ + uint16_t min_version; + + /* There are 2 BIO's even though they are normally both the same. This is so + * data can be read and written to different handlers */ + + BIO *rbio; /* used by SSL_read */ + BIO *wbio; /* used by SSL_write */ + BIO *bbio; /* used during session-id reuse to concatenate + * messages */ + + /* This holds a variable that indicates what we were doing when a 0 or -1 is + * returned. This is needed for non-blocking IO so we know what request + * needs re-doing when in SSL_accept or SSL_connect */ + int rwstate; + + /* true when we are actually in SSL_accept() or SSL_connect() */ + int in_handshake; + int (*handshake_func)(SSL *); + + /* Imagine that here's a boolean member "init" that is switched as soon as + * SSL_set_{accept/connect}_state is called for the first time, so that + * "state" and "handshake_func" are properly initialized. But as + * handshake_func is == 0 until then, we use this test instead of an "init" + * member. */ + + /* server is true iff the this SSL* is the server half. Note: before the SSL* + * is initialized by either SSL_set_accept_state or SSL_set_connect_state, + * the side is not determined. In this state, server is always false. */ + int server; + + /* quiet_shutdown is true if the connection should not send a close_notify on + * shutdown. */ + int quiet_shutdown; + + int shutdown; /* we have shut things down, 0x01 sent, 0x02 + * for received */ + int state; /* where we are */ + int rstate; /* where we are when reading */ + + BUF_MEM *init_buf; /* buffer used during init */ + uint8_t *init_msg; /* pointer to handshake message body, set by + ssl3_get_message() */ + int init_num; /* amount read/written */ + int init_off; /* amount read/written */ + + /* used internally to point at a raw packet */ + uint8_t *packet; + unsigned int packet_length; + + struct ssl3_state_st *s3; /* SSLv3 variables */ + struct dtls1_state_st *d1; /* DTLSv1 variables */ + + /* callback that allows applications to peek at protocol messages */ + void (*msg_callback)(int write_p, int version, int content_type, + const void *buf, size_t len, SSL *ssl, void *arg); + void *msg_callback_arg; + + int hit; /* reusing a previous session */ + + X509_VERIFY_PARAM *param; + + /* crypto */ + struct ssl_cipher_preference_list_st *cipher_list; + STACK_OF(SSL_CIPHER) *cipher_list_by_id; + + SSL_AEAD_CTX *aead_read_ctx; + SSL_AEAD_CTX *aead_write_ctx; + + /* session info */ + + /* client cert? */ + /* This is used to hold the server certificate used */ + struct cert_st /* CERT */ *cert; + + /* the session_id_context is used to ensure sessions are only reused + * in the appropriate context */ + unsigned int sid_ctx_length; + uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; + + /* This can also be in the session once a session is established */ + SSL_SESSION *session; + + /* Default generate session ID callback. */ + GEN_SESSION_CB generate_session_id; + + /* Used in SSL2 and SSL3 */ + int verify_mode; /* 0 don't care about verify failure. + * 1 fail if verify fails */ + int (*verify_callback)(int ok, + X509_STORE_CTX *ctx); /* fail if callback returns 0 */ + + void (*info_callback)(const SSL *ssl, int type, + int val); /* optional informational callback */ + + /* Server-only: psk_identity_hint is the identity hint to send in + * PSK-based key exchanges. */ + char *psk_identity_hint; + + unsigned int (*psk_client_callback)(SSL *ssl, const char *hint, + char *identity, + unsigned int max_identity_len, + uint8_t *psk, unsigned int max_psk_len); + unsigned int (*psk_server_callback)(SSL *ssl, const char *identity, + uint8_t *psk, unsigned int max_psk_len); + + SSL_CTX *ctx; + + /* extra application data */ + long verify_result; + CRYPTO_EX_DATA ex_data; + + /* for server side, keep the list of CA_dn we can use */ + STACK_OF(X509_NAME) *client_CA; + + uint32_t options; /* protocol behaviour */ + uint32_t mode; /* API behaviour */ + uint32_t max_cert_list; + int client_version; /* what was passed, used for + * SSLv3/TLS rollback check */ + uint16_t max_send_fragment; + char *tlsext_hostname; + /* RFC4507 session ticket expected to be received or sent */ + int tlsext_ticket_expected; + size_t tlsext_ellipticcurvelist_length; + uint16_t *tlsext_ellipticcurvelist; /* our list */ + + SSL_CTX *initial_ctx; /* initial ctx, used to store sessions */ + + /* Next protocol negotiation. For the client, this is the protocol that we + * sent in NextProtocol and is set when handling ServerHello extensions. + * + * For a server, this is the client's selected_protocol from NextProtocol and + * is set when handling the NextProtocol message, before the Finished + * message. */ + uint8_t *next_proto_negotiated; + size_t next_proto_negotiated_len; + + /* srtp_profiles is the list of configured SRTP protection profiles for + * DTLS-SRTP. */ + STACK_OF(SRTP_PROTECTION_PROFILE) *srtp_profiles; + + /* srtp_profile is the selected SRTP protection profile for + * DTLS-SRTP. */ + const SRTP_PROTECTION_PROFILE *srtp_profile; + + /* Copied from the SSL_CTX. For a server, means that we'll accept Channel IDs + * from clients. For a client, means that we'll advertise support. */ + char tlsext_channel_id_enabled; + /* The client's Channel ID private key. */ + EVP_PKEY *tlsext_channel_id_private; + + /* Enable signed certificate time stamps. Currently client only. */ + char signed_cert_timestamps_enabled; + + /* Enable OCSP stapling. Currently client only. + * TODO(davidben): Add a server-side implementation when it becomes + * necesary. */ + char ocsp_stapling_enabled; + + /* For a client, this contains the list of supported protocols in wire + * format. */ + uint8_t *alpn_client_proto_list; + unsigned alpn_client_proto_list_len; + + /* accept_peer_renegotiations, if one, accepts renegotiation attempts from the + * peer. Otherwise, they will be rejected with a fatal error. */ + char accept_peer_renegotiations; + + /* These fields are always NULL and exist only to keep wpa_supplicant happy + * about the change to EVP_AEAD. They are only needed for EAP-FAST, which we + * don't support. */ + EVP_CIPHER_CTX *enc_read_ctx; + EVP_MD_CTX *read_hash; +}; + +/* compatibility */ +#define SSL_set_app_data(s, arg) (SSL_set_ex_data(s, 0, (char *)arg)) +#define SSL_get_app_data(s) (SSL_get_ex_data(s, 0)) +#define SSL_SESSION_set_app_data(s, a) \ + (SSL_SESSION_set_ex_data(s, 0, (char *)a)) +#define SSL_SESSION_get_app_data(s) (SSL_SESSION_get_ex_data(s, 0)) +#define SSL_CTX_get_app_data(ctx) (SSL_CTX_get_ex_data(ctx, 0)) +#define SSL_CTX_set_app_data(ctx, arg) \ + (SSL_CTX_set_ex_data(ctx, 0, (char *)arg)) + +/* The following are the possible values for ssl->state are are used to + * indicate where we are up to in the SSL connection establishment. The macros + * that follow are about the only things you should need to use and even then, + * only when using non-blocking IO. It can also be useful to work out where you + * were when the connection failed */ + +#define SSL_ST_CONNECT 0x1000 +#define SSL_ST_ACCEPT 0x2000 +#define SSL_ST_MASK 0x0FFF +#define SSL_ST_INIT (SSL_ST_CONNECT | SSL_ST_ACCEPT) +#define SSL_ST_OK 0x03 +#define SSL_ST_RENEGOTIATE (0x04 | SSL_ST_INIT) + +#define SSL_CB_LOOP 0x01 +#define SSL_CB_EXIT 0x02 +#define SSL_CB_READ 0x04 +#define SSL_CB_WRITE 0x08 +#define SSL_CB_ALERT 0x4000 /* used in callback */ +#define SSL_CB_READ_ALERT (SSL_CB_ALERT | SSL_CB_READ) +#define SSL_CB_WRITE_ALERT (SSL_CB_ALERT | SSL_CB_WRITE) +#define SSL_CB_ACCEPT_LOOP (SSL_ST_ACCEPT | SSL_CB_LOOP) +#define SSL_CB_ACCEPT_EXIT (SSL_ST_ACCEPT | SSL_CB_EXIT) +#define SSL_CB_CONNECT_LOOP (SSL_ST_CONNECT | SSL_CB_LOOP) +#define SSL_CB_CONNECT_EXIT (SSL_ST_CONNECT | SSL_CB_EXIT) +#define SSL_CB_HANDSHAKE_START 0x10 +#define SSL_CB_HANDSHAKE_DONE 0x20 + +/* Is the SSL_connection established? */ +#define SSL_get_state(a) SSL_state(a) +#define SSL_is_init_finished(a) (SSL_state(a) == SSL_ST_OK) +#define SSL_in_init(a) (SSL_state(a) & SSL_ST_INIT) +#define SSL_in_connect_init(a) (SSL_state(a) & SSL_ST_CONNECT) +#define SSL_in_accept_init(a) (SSL_state(a) & SSL_ST_ACCEPT) + +/* SSL_in_false_start returns one if |s| has a pending unfinished handshake that + * is in False Start. |SSL_write| may be called at this point without waiting + * for the peer, but |SSL_read| will require the handshake to be completed. */ +OPENSSL_EXPORT int SSL_in_false_start(const SSL *s); + +/* The following 2 states are kept in ssl->rstate when reads fail, + * you should not need these */ +#define SSL_ST_READ_HEADER 0xF0 +#define SSL_ST_READ_BODY 0xF1 +#define SSL_ST_READ_DONE 0xF2 + +/* Obtain latest Finished message + * -- that we sent (SSL_get_finished) + * -- that we expected from peer (SSL_get_peer_finished). + * Returns length (0 == no Finished so far), copies up to 'count' bytes. */ +OPENSSL_EXPORT size_t SSL_get_finished(const SSL *s, void *buf, size_t count); +OPENSSL_EXPORT size_t SSL_get_peer_finished(const SSL *s, void *buf, size_t count); + +/* use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 3 options + * are 'ored' with SSL_VERIFY_PEER if they are desired */ +#define SSL_VERIFY_NONE 0x00 +#define SSL_VERIFY_PEER 0x01 +#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 +/* SSL_VERIFY_CLIENT_ONCE does nothing. */ +#define SSL_VERIFY_CLIENT_ONCE 0x04 +#define SSL_VERIFY_PEER_IF_NO_OBC 0x08 + +#define OpenSSL_add_ssl_algorithms() SSL_library_init() +#define SSLeay_add_ssl_algorithms() SSL_library_init() + +/* For backward compatibility */ +#define SSL_get_cipher(s) SSL_CIPHER_get_name(SSL_get_current_cipher(s)) +#define SSL_get_cipher_bits(s, np) \ + SSL_CIPHER_get_bits(SSL_get_current_cipher(s), np) +#define SSL_get_cipher_version(s) \ + SSL_CIPHER_get_version(SSL_get_current_cipher(s)) +#define SSL_get_cipher_name(s) SSL_CIPHER_get_name(SSL_get_current_cipher(s)) +#define SSL_get_time(a) SSL_SESSION_get_time(a) +#define SSL_set_time(a, b) SSL_SESSION_set_time((a), (b)) +#define SSL_get_timeout(a) SSL_SESSION_get_timeout(a) +#define SSL_set_timeout(a, b) SSL_SESSION_set_timeout((a), (b)) + +#define d2i_SSL_SESSION_bio(bp, s_id) \ + ASN1_d2i_bio_of(SSL_SESSION, SSL_SESSION_new, d2i_SSL_SESSION, bp, s_id) +#define i2d_SSL_SESSION_bio(bp, s_id) \ + ASN1_i2d_bio_of(SSL_SESSION, i2d_SSL_SESSION, bp, s_id) + +DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) + +/* make_errors.go reserves error codes above 1000 for manually-assigned errors. + * This value must be kept in sync with reservedReasonCode in make_errors.h */ +#define SSL_AD_REASON_OFFSET \ + 1000 /* offset to get SSL_R_... value from SSL_AD_... */ + +/* These alert types are for SSLv3 and TLSv1 */ +#define SSL_AD_CLOSE_NOTIFY SSL3_AD_CLOSE_NOTIFY +#define SSL_AD_UNEXPECTED_MESSAGE SSL3_AD_UNEXPECTED_MESSAGE /* fatal */ +#define SSL_AD_BAD_RECORD_MAC SSL3_AD_BAD_RECORD_MAC /* fatal */ +#define SSL_AD_DECRYPTION_FAILED TLS1_AD_DECRYPTION_FAILED +#define SSL_AD_RECORD_OVERFLOW TLS1_AD_RECORD_OVERFLOW +#define SSL_AD_DECOMPRESSION_FAILURE SSL3_AD_DECOMPRESSION_FAILURE /* fatal */ +#define SSL_AD_HANDSHAKE_FAILURE SSL3_AD_HANDSHAKE_FAILURE /* fatal */ +#define SSL_AD_NO_CERTIFICATE SSL3_AD_NO_CERTIFICATE /* Not for TLS */ +#define SSL_AD_BAD_CERTIFICATE SSL3_AD_BAD_CERTIFICATE +#define SSL_AD_UNSUPPORTED_CERTIFICATE SSL3_AD_UNSUPPORTED_CERTIFICATE +#define SSL_AD_CERTIFICATE_REVOKED SSL3_AD_CERTIFICATE_REVOKED +#define SSL_AD_CERTIFICATE_EXPIRED SSL3_AD_CERTIFICATE_EXPIRED +#define SSL_AD_CERTIFICATE_UNKNOWN SSL3_AD_CERTIFICATE_UNKNOWN +#define SSL_AD_ILLEGAL_PARAMETER SSL3_AD_ILLEGAL_PARAMETER /* fatal */ +#define SSL_AD_UNKNOWN_CA TLS1_AD_UNKNOWN_CA /* fatal */ +#define SSL_AD_ACCESS_DENIED TLS1_AD_ACCESS_DENIED /* fatal */ +#define SSL_AD_DECODE_ERROR TLS1_AD_DECODE_ERROR /* fatal */ +#define SSL_AD_DECRYPT_ERROR TLS1_AD_DECRYPT_ERROR +#define SSL_AD_EXPORT_RESTRICTION TLS1_AD_EXPORT_RESTRICTION /* fatal */ +#define SSL_AD_PROTOCOL_VERSION TLS1_AD_PROTOCOL_VERSION /* fatal */ +#define SSL_AD_INSUFFICIENT_SECURITY TLS1_AD_INSUFFICIENT_SECURITY /* fatal */ +#define SSL_AD_INTERNAL_ERROR TLS1_AD_INTERNAL_ERROR /* fatal */ +#define SSL_AD_USER_CANCELLED TLS1_AD_USER_CANCELLED +#define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION +#define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION +#define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE +#define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME +#define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE \ + TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE +#define SSL_AD_BAD_CERTIFICATE_HASH_VALUE TLS1_AD_BAD_CERTIFICATE_HASH_VALUE +#define SSL_AD_UNKNOWN_PSK_IDENTITY TLS1_AD_UNKNOWN_PSK_IDENTITY /* fatal */ +#define SSL_AD_INAPPROPRIATE_FALLBACK SSL3_AD_INAPPROPRIATE_FALLBACK /* fatal */ + +#define SSL_ERROR_NONE 0 +#define SSL_ERROR_SSL 1 +#define SSL_ERROR_WANT_READ 2 +#define SSL_ERROR_WANT_WRITE 3 +#define SSL_ERROR_WANT_X509_LOOKUP 4 +#define SSL_ERROR_SYSCALL 5 /* look at error stack/return value/errno */ +#define SSL_ERROR_ZERO_RETURN 6 +#define SSL_ERROR_WANT_CONNECT 7 +#define SSL_ERROR_WANT_ACCEPT 8 +#define SSL_ERROR_WANT_CHANNEL_ID_LOOKUP 9 +#define SSL_ERROR_PENDING_SESSION 11 +#define SSL_ERROR_PENDING_CERTIFICATE 12 +#define SSL_ERROR_WANT_PRIVATE_KEY_OPERATION 13 + +#define SSL_CTRL_GET_CURVES 90 +#define SSL_CTRL_SET_CURVES 91 +#define SSL_CTRL_SET_CURVES_LIST 92 +#define SSL_CTRL_SET_SIGALGS 97 +#define SSL_CTRL_SET_SIGALGS_LIST 98 +#define SSL_CTRL_SET_CLIENT_SIGALGS 101 +#define SSL_CTRL_SET_CLIENT_SIGALGS_LIST 102 +#define SSL_CTRL_GET_CLIENT_CERT_TYPES 103 +#define SSL_CTRL_SET_CLIENT_CERT_TYPES 104 +#define SSL_CTRL_SET_VERIFY_CERT_STORE 106 +#define SSL_CTRL_SET_CHAIN_CERT_STORE 107 + +/* DTLSv1_get_timeout queries the next DTLS handshake timeout. If there is a + * timeout in progress, it sets |*out| to the time remaining and returns one. + * Otherwise, it returns zero. + * + * When the timeout expires, call |DTLSv1_handle_timeout| to handle the + * retransmit behavior. + * + * NOTE: This function must be queried again whenever the handshake state + * machine changes, including when |DTLSv1_handle_timeout| is called. */ +OPENSSL_EXPORT int DTLSv1_get_timeout(const SSL *ssl, struct timeval *out); + +/* DTLSv1_handle_timeout is called when a DTLS handshake timeout expires. If no + * timeout had expired, it returns 0. Otherwise, it retransmits the previous + * flight of handshake messages and returns 1. If too many timeouts had expired + * without progress or an error occurs, it returns -1. + * + * NOTE: The caller's external timer should be compatible with the one |ssl| + * queries within some fudge factor. Otherwise, the call will be a no-op, but + * |DTLSv1_get_timeout| will return an updated timeout. + * + * WARNING: This function breaks the usual return value convention. */ +OPENSSL_EXPORT int DTLSv1_handle_timeout(SSL *ssl); + +/* SSL_session_reused returns one if |ssl| performed an abbreviated handshake + * and zero otherwise. + * + * TODO(davidben): Hammer down the semantics of this API while a handshake, + * initial or renego, is in progress. */ +OPENSSL_EXPORT int SSL_session_reused(const SSL *ssl); + +/* SSL_total_renegotiations returns the total number of renegotiation handshakes + * peformed by |ssl|. This includes the pending renegotiation, if any. */ +OPENSSL_EXPORT int SSL_total_renegotiations(const SSL *ssl); + +/* SSL_CTX_set_tmp_dh configures |ctx| to use the group from |dh| as the group + * for DHE. Only the group is used, so |dh| needn't have a keypair. It returns + * one on success and zero on error. */ +OPENSSL_EXPORT int SSL_CTX_set_tmp_dh(SSL_CTX *ctx, const DH *dh); + +/* SSL_set_tmp_dh configures |ssl| to use the group from |dh| as the group for + * DHE. Only the group is used, so |dh| needn't have a keypair. It returns one + * on success and zero on error. */ +OPENSSL_EXPORT int SSL_set_tmp_dh(SSL *ssl, const DH *dh); + +/* SSL_CTX_set_tmp_ecdh configures |ctx| to use the curve from |ecdh| as the + * curve for ephemeral ECDH keys. For historical reasons, this API expects an + * |EC_KEY|, but only the curve is used. It returns one on success and zero on + * error. If unset, an appropriate curve will be chosen automatically. (This is + * recommended.) */ +OPENSSL_EXPORT int SSL_CTX_set_tmp_ecdh(SSL_CTX *ctx, const EC_KEY *ec_key); + +/* SSL_set_tmp_ecdh configures |ssl| to use the curve from |ecdh| as the curve + * for ephemeral ECDH keys. For historical reasons, this API expects an + * |EC_KEY|, but only the curve is used. It returns one on success and zero on + * error. If unset, an appropriate curve will be chosen automatically. (This is + * recommended.) */ +OPENSSL_EXPORT int SSL_set_tmp_ecdh(SSL *ssl, const EC_KEY *ec_key); + +/* SSL_CTX_enable_tls_channel_id either configures a TLS server to accept TLS + * client IDs from clients, or configures a client to send TLS client IDs to + * a server. It returns one. */ +OPENSSL_EXPORT int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx); + +/* SSL_enable_tls_channel_id either configures a TLS server to accept TLS + * client IDs from clients, or configure a client to send TLS client IDs to + * server. It returns one. */ +OPENSSL_EXPORT int SSL_enable_tls_channel_id(SSL *ssl); + +/* SSL_CTX_set1_tls_channel_id configures a TLS client to send a TLS Channel ID + * to compatible servers. |private_key| must be a P-256 EC key. It returns one + * on success and zero on error. */ +OPENSSL_EXPORT int SSL_CTX_set1_tls_channel_id(SSL_CTX *ctx, + EVP_PKEY *private_key); + +/* SSL_set1_tls_channel_id configures a TLS client to send a TLS Channel ID to + * compatible servers. |private_key| must be a P-256 EC key. It returns one on + * success and zero on error. */ +OPENSSL_EXPORT int SSL_set1_tls_channel_id(SSL *ssl, EVP_PKEY *private_key); + +/* SSL_get_tls_channel_id gets the client's TLS Channel ID from a server SSL* + * and copies up to the first |max_out| bytes into |out|. The Channel ID + * consists of the client's P-256 public key as an (x,y) pair where each is a + * 32-byte, big-endian field element. It returns 0 if the client didn't offer a + * Channel ID and the length of the complete Channel ID otherwise. */ +OPENSSL_EXPORT size_t SSL_get_tls_channel_id(SSL *ssl, uint8_t *out, + size_t max_out); + +#define SSL_CTX_set0_verify_cert_store(ctx, st) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, (char *)st) +#define SSL_CTX_set1_verify_cert_store(ctx, st) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 1, (char *)st) +#define SSL_CTX_set0_chain_cert_store(ctx, st) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_CHAIN_CERT_STORE, 0, (char *)st) +#define SSL_CTX_set1_chain_cert_store(ctx, st) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_CHAIN_CERT_STORE, 1, (char *)st) + +#define SSL_set0_verify_cert_store(s, st) \ + SSL_ctrl(s, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, (char *)st) +#define SSL_set1_verify_cert_store(s, st) \ + SSL_ctrl(s, SSL_CTRL_SET_VERIFY_CERT_STORE, 1, (char *)st) +#define SSL_set0_chain_cert_store(s, st) \ + SSL_ctrl(s, SSL_CTRL_SET_CHAIN_CERT_STORE, 0, (char *)st) +#define SSL_set1_chain_cert_store(s, st) \ + SSL_ctrl(s, SSL_CTRL_SET_CHAIN_CERT_STORE, 1, (char *)st) + +#define SSL_get1_curves(ctx, s) SSL_ctrl(ctx, SSL_CTRL_GET_CURVES, 0, (char *)s) +#define SSL_CTX_set1_curves(ctx, clist, clistlen) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_CURVES, clistlen, (char *)clist) +#define SSL_CTX_set1_curves_list(ctx, s) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_CURVES_LIST, 0, (char *)s) +#define SSL_set1_curves(ctx, clist, clistlen) \ + SSL_ctrl(ctx, SSL_CTRL_SET_CURVES, clistlen, (char *)clist) +#define SSL_set1_curves_list(ctx, s) \ + SSL_ctrl(ctx, SSL_CTRL_SET_CURVES_LIST, 0, (char *)s) + +#define SSL_CTX_set1_sigalgs(ctx, slist, slistlen) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_SIGALGS, slistlen, (int *)slist) +#define SSL_CTX_set1_sigalgs_list(ctx, s) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_SIGALGS_LIST, 0, (char *)s) +#define SSL_set1_sigalgs(ctx, slist, slistlen) \ + SSL_ctrl(ctx, SSL_CTRL_SET_SIGALGS, clistlen, (int *)slist) +#define SSL_set1_sigalgs_list(ctx, s) \ + SSL_ctrl(ctx, SSL_CTRL_SET_SIGALGS_LIST, 0, (char *)s) + +#define SSL_CTX_set1_client_sigalgs(ctx, slist, slistlen) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_CLIENT_SIGALGS, slistlen, (int *)slist) +#define SSL_CTX_set1_client_sigalgs_list(ctx, s) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_CLIENT_SIGALGS_LIST, 0, (char *)s) +#define SSL_set1_client_sigalgs(ctx, slist, slistlen) \ + SSL_ctrl(ctx, SSL_CTRL_SET_CLIENT_SIGALGS, clistlen, (int *)slist) +#define SSL_set1_client_sigalgs_list(ctx, s) \ + SSL_ctrl(ctx, SSL_CTRL_SET_CLIENT_SIGALGS_LIST, 0, (char *)s) + +#define SSL_get0_certificate_types(s, clist) \ + SSL_ctrl(s, SSL_CTRL_GET_CLIENT_CERT_TYPES, 0, (char *)clist) + +#define SSL_CTX_set1_client_certificate_types(ctx, clist, clistlen) \ + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_CLIENT_CERT_TYPES, clistlen, (char *)clist) +#define SSL_set1_client_certificate_types(s, clist, clistlen) \ + SSL_ctrl(s, SSL_CTRL_SET_CLIENT_CERT_TYPES, clistlen, (char *)clist) + +OPENSSL_EXPORT int SSL_CTX_set_cipher_list(SSL_CTX *, const char *str); +OPENSSL_EXPORT int SSL_CTX_set_cipher_list_tls11(SSL_CTX *, const char *str); +OPENSSL_EXPORT long SSL_CTX_set_timeout(SSL_CTX *ctx, long t); +OPENSSL_EXPORT long SSL_CTX_get_timeout(const SSL_CTX *ctx); +OPENSSL_EXPORT X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *); +OPENSSL_EXPORT void SSL_CTX_set_cert_store(SSL_CTX *, X509_STORE *); +OPENSSL_EXPORT int SSL_want(const SSL *s); + +OPENSSL_EXPORT void SSL_CTX_flush_sessions(SSL_CTX *ctx, long tm); + +/* SSL_get_current_cipher returns the cipher used in the current outgoing + * connection state, or NULL if the null cipher is active. */ +OPENSSL_EXPORT const SSL_CIPHER *SSL_get_current_cipher(const SSL *s); + +OPENSSL_EXPORT int SSL_get_fd(const SSL *s); +OPENSSL_EXPORT int SSL_get_rfd(const SSL *s); +OPENSSL_EXPORT int SSL_get_wfd(const SSL *s); +OPENSSL_EXPORT const char *SSL_get_cipher_list(const SSL *s, int n); +OPENSSL_EXPORT int SSL_pending(const SSL *s); +OPENSSL_EXPORT int SSL_set_fd(SSL *s, int fd); +OPENSSL_EXPORT int SSL_set_rfd(SSL *s, int fd); +OPENSSL_EXPORT int SSL_set_wfd(SSL *s, int fd); +OPENSSL_EXPORT void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio); +OPENSSL_EXPORT BIO *SSL_get_rbio(const SSL *s); +OPENSSL_EXPORT BIO *SSL_get_wbio(const SSL *s); +OPENSSL_EXPORT int SSL_set_cipher_list(SSL *s, const char *str); +OPENSSL_EXPORT int SSL_get_verify_mode(const SSL *s); +OPENSSL_EXPORT int SSL_get_verify_depth(const SSL *s); +OPENSSL_EXPORT int (*SSL_get_verify_callback(const SSL *s))(int, + X509_STORE_CTX *); +OPENSSL_EXPORT void SSL_set_verify(SSL *s, int mode, + int (*callback)(int ok, + X509_STORE_CTX *ctx)); +OPENSSL_EXPORT void SSL_set_verify_depth(SSL *s, int depth); +OPENSSL_EXPORT STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file); +OPENSSL_EXPORT int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) * + stackCAs, + const char *file); +OPENSSL_EXPORT int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) * + stackCAs, + const char *dir); + +/* SSL_load_error_strings does nothing. */ +OPENSSL_EXPORT void SSL_load_error_strings(void); + +OPENSSL_EXPORT const char *SSL_state_string(const SSL *s); +OPENSSL_EXPORT const char *SSL_rstate_string(const SSL *s); +OPENSSL_EXPORT const char *SSL_state_string_long(const SSL *s); +OPENSSL_EXPORT const char *SSL_rstate_string_long(const SSL *s); +OPENSSL_EXPORT long SSL_SESSION_get_time(const SSL_SESSION *s); +OPENSSL_EXPORT long SSL_SESSION_set_time(SSL_SESSION *s, long t); +OPENSSL_EXPORT long SSL_SESSION_get_timeout(const SSL_SESSION *s); +OPENSSL_EXPORT long SSL_SESSION_set_timeout(SSL_SESSION *s, long t); +OPENSSL_EXPORT X509 *SSL_SESSION_get0_peer(SSL_SESSION *s); +OPENSSL_EXPORT int SSL_SESSION_set1_id_context(SSL_SESSION *s, + const uint8_t *sid_ctx, + unsigned int sid_ctx_len); + +OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_new(void); +OPENSSL_EXPORT const uint8_t *SSL_SESSION_get_id(const SSL_SESSION *s, + unsigned int *len); +OPENSSL_EXPORT int SSL_SESSION_print_fp(FILE *fp, const SSL_SESSION *ses); +OPENSSL_EXPORT int SSL_SESSION_print(BIO *fp, const SSL_SESSION *ses); + +/* SSL_SESSION_up_ref, if |session| is not NULL, increments the reference count + * of |session|. It then returns |session|. */ +OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_up_ref(SSL_SESSION *session); + +/* SSL_SESSION_free decrements the reference count of |session|. If it reaches + * zero, all data referenced by |session| and |session| itself are released. */ +OPENSSL_EXPORT void SSL_SESSION_free(SSL_SESSION *session); + +OPENSSL_EXPORT int SSL_set_session(SSL *to, SSL_SESSION *session); +OPENSSL_EXPORT int SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c); +OPENSSL_EXPORT int SSL_CTX_remove_session(SSL_CTX *, SSL_SESSION *c); +OPENSSL_EXPORT int SSL_CTX_set_generate_session_id(SSL_CTX *, GEN_SESSION_CB); +OPENSSL_EXPORT int SSL_set_generate_session_id(SSL *, GEN_SESSION_CB); +OPENSSL_EXPORT int SSL_has_matching_session_id(const SSL *ssl, + const uint8_t *id, + unsigned int id_len); + +/* SSL_SESSION_to_bytes serializes |in| into a newly allocated buffer and sets + * |*out_data| to that buffer and |*out_len| to its length. The caller takes + * ownership of the buffer and must call |OPENSSL_free| when done. It returns + * one on success and zero on error. */ +OPENSSL_EXPORT int SSL_SESSION_to_bytes(SSL_SESSION *in, uint8_t **out_data, + size_t *out_len); + +/* SSL_SESSION_to_bytes_for_ticket serializes |in|, but excludes the session + * identification information, namely the session ID and ticket. */ +OPENSSL_EXPORT int SSL_SESSION_to_bytes_for_ticket(SSL_SESSION *in, + uint8_t **out_data, + size_t *out_len); + +/* SSL_SESSION_from_bytes parses |in_len| bytes from |in| as an SSL_SESSION. It + * returns a newly-allocated |SSL_SESSION| on success or NULL on error. */ +OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, + size_t in_len); + +/* Deprecated: i2d_SSL_SESSION serializes |in| to the bytes pointed to by + * |*pp|. On success, it returns the number of bytes written and advances |*pp| + * by that many bytes. On failure, it returns -1. If |pp| is NULL, no bytes are + * written and only the length is returned. + * + * Use |SSL_SESSION_to_bytes| instead. */ +OPENSSL_EXPORT int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp); + +/* Deprecated: d2i_SSL_SESSION parses a serialized session from the |length| + * bytes pointed to by |*pp|. It returns the new |SSL_SESSION| and advances + * |*pp| by the number of bytes consumed on success and NULL on failure. The + * caller takes ownership of the new session and must call |SSL_SESSION_free| + * when done. + * + * If |a| is non-NULL, |*a| is released and set the new |SSL_SESSION|. + * + * Use |SSL_SESSION_from_bytes| instead. */ +OPENSSL_EXPORT SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, + long length); + +OPENSSL_EXPORT X509 *SSL_get_peer_certificate(const SSL *s); + +OPENSSL_EXPORT STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s); + +OPENSSL_EXPORT int SSL_CTX_get_verify_mode(const SSL_CTX *ctx); +OPENSSL_EXPORT int SSL_CTX_get_verify_depth(const SSL_CTX *ctx); +OPENSSL_EXPORT int (*SSL_CTX_get_verify_callback(const SSL_CTX *ctx))( + int, X509_STORE_CTX *); +OPENSSL_EXPORT void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, + int (*callback)(int, X509_STORE_CTX *)); +OPENSSL_EXPORT void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth); +OPENSSL_EXPORT void SSL_CTX_set_cert_verify_callback( + SSL_CTX *ctx, int (*cb)(X509_STORE_CTX *, void *), void *arg); + +OPENSSL_EXPORT void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, + pem_password_cb *cb); +OPENSSL_EXPORT void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, + void *u); + +OPENSSL_EXPORT int SSL_CTX_set_session_id_context(SSL_CTX *ctx, + const uint8_t *sid_ctx, + unsigned int sid_ctx_len); + +OPENSSL_EXPORT int SSL_set_session_id_context(SSL *ssl, const uint8_t *sid_ctx, + unsigned int sid_ctx_len); + +OPENSSL_EXPORT int SSL_CTX_set_purpose(SSL_CTX *s, int purpose); +OPENSSL_EXPORT int SSL_set_purpose(SSL *s, int purpose); +OPENSSL_EXPORT int SSL_CTX_set_trust(SSL_CTX *s, int trust); +OPENSSL_EXPORT int SSL_set_trust(SSL *s, int trust); + +OPENSSL_EXPORT int SSL_CTX_set1_param(SSL_CTX *ctx, X509_VERIFY_PARAM *vpm); +OPENSSL_EXPORT int SSL_set1_param(SSL *ssl, X509_VERIFY_PARAM *vpm); + +OPENSSL_EXPORT X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *ctx); +OPENSSL_EXPORT X509_VERIFY_PARAM *SSL_get0_param(SSL *ssl); + +OPENSSL_EXPORT int SSL_accept(SSL *ssl); +OPENSSL_EXPORT int SSL_connect(SSL *ssl); +OPENSSL_EXPORT int SSL_read(SSL *ssl, void *buf, int num); +OPENSSL_EXPORT int SSL_peek(SSL *ssl, void *buf, int num); +OPENSSL_EXPORT int SSL_write(SSL *ssl, const void *buf, int num); +OPENSSL_EXPORT long SSL_ctrl(SSL *ssl, int cmd, long larg, void *parg); +OPENSSL_EXPORT long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg); + +OPENSSL_EXPORT int SSL_get_error(const SSL *s, int ret_code); +/* SSL_get_version returns a string describing the TLS version used by |s|. For + * example, "TLSv1.2" or "SSLv3". */ +OPENSSL_EXPORT const char *SSL_get_version(const SSL *s); +/* SSL_SESSION_get_version returns a string describing the TLS version used by + * |sess|. For example, "TLSv1.2" or "SSLv3". */ +OPENSSL_EXPORT const char *SSL_SESSION_get_version(const SSL_SESSION *sess); + +OPENSSL_EXPORT STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *s); + +OPENSSL_EXPORT int SSL_do_handshake(SSL *s); + +/* SSL_renegotiate_pending returns one if |ssl| is in the middle of a + * renegotiation. */ +OPENSSL_EXPORT int SSL_renegotiate_pending(SSL *ssl); + +OPENSSL_EXPORT int SSL_shutdown(SSL *s); + +OPENSSL_EXPORT const char *SSL_alert_type_string_long(int value); +OPENSSL_EXPORT const char *SSL_alert_type_string(int value); +OPENSSL_EXPORT const char *SSL_alert_desc_string_long(int value); +OPENSSL_EXPORT const char *SSL_alert_desc_string(int value); + +OPENSSL_EXPORT void SSL_set_client_CA_list(SSL *s, + STACK_OF(X509_NAME) *name_list); +OPENSSL_EXPORT void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, + STACK_OF(X509_NAME) *name_list); +OPENSSL_EXPORT STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s); +OPENSSL_EXPORT STACK_OF(X509_NAME) * + SSL_CTX_get_client_CA_list(const SSL_CTX *s); +OPENSSL_EXPORT int SSL_add_client_CA(SSL *ssl, X509 *x); +OPENSSL_EXPORT int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); + +OPENSSL_EXPORT long SSL_get_default_timeout(const SSL *s); + +OPENSSL_EXPORT STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *sk); + +OPENSSL_EXPORT void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode); +OPENSSL_EXPORT int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx); +OPENSSL_EXPORT void SSL_set_quiet_shutdown(SSL *ssl, int mode); +OPENSSL_EXPORT int SSL_get_quiet_shutdown(const SSL *ssl); +OPENSSL_EXPORT void SSL_set_shutdown(SSL *ssl, int mode); +OPENSSL_EXPORT int SSL_get_shutdown(const SSL *ssl); +OPENSSL_EXPORT int SSL_version(const SSL *ssl); +OPENSSL_EXPORT int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); +OPENSSL_EXPORT int SSL_CTX_load_verify_locations(SSL_CTX *ctx, + const char *CAfile, + const char *CApath); +#define SSL_get0_session SSL_get_session /* just peek at pointer */ +OPENSSL_EXPORT SSL_SESSION *SSL_get_session(const SSL *ssl); +OPENSSL_EXPORT SSL_SESSION *SSL_get1_session( + SSL *ssl); /* obtain a reference count */ +OPENSSL_EXPORT SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); +OPENSSL_EXPORT SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx); +OPENSSL_EXPORT void SSL_set_info_callback(SSL *ssl, + void (*cb)(const SSL *ssl, int type, + int val)); +OPENSSL_EXPORT void (*SSL_get_info_callback(const SSL *ssl))(const SSL *ssl, + int type, int val); +OPENSSL_EXPORT int SSL_state(const SSL *ssl); + +OPENSSL_EXPORT void SSL_set_verify_result(SSL *ssl, long v); +OPENSSL_EXPORT long SSL_get_verify_result(const SSL *ssl); + +OPENSSL_EXPORT int SSL_set_ex_data(SSL *ssl, int idx, void *data); +OPENSSL_EXPORT void *SSL_get_ex_data(const SSL *ssl, int idx); +OPENSSL_EXPORT int SSL_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); + +OPENSSL_EXPORT int SSL_SESSION_set_ex_data(SSL_SESSION *ss, int idx, + void *data); +OPENSSL_EXPORT void *SSL_SESSION_get_ex_data(const SSL_SESSION *ss, int idx); +OPENSSL_EXPORT int SSL_SESSION_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); + +OPENSSL_EXPORT int SSL_CTX_set_ex_data(SSL_CTX *ssl, int idx, void *data); +OPENSSL_EXPORT void *SSL_CTX_get_ex_data(const SSL_CTX *ssl, int idx); +OPENSSL_EXPORT int SSL_CTX_get_ex_new_index(long argl, void *argp, + CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, + CRYPTO_EX_free *free_func); + +OPENSSL_EXPORT int SSL_get_ex_data_X509_STORE_CTX_idx(void); + +/* SSL_CTX_sess_set_cache_size sets the maximum size of |ctx|'s session cache to + * |size|. It returns the previous value. */ +OPENSSL_EXPORT unsigned long SSL_CTX_sess_set_cache_size(SSL_CTX *ctx, + unsigned long size); + +/* SSL_CTX_sess_get_cache_size returns the maximum size of |ctx|'s session + * cache. */ +OPENSSL_EXPORT unsigned long SSL_CTX_sess_get_cache_size(const SSL_CTX *ctx); + +/* SSL_SESS_CACHE_* are the possible session cache mode bits. + * TODO(davidben): Document. */ +#define SSL_SESS_CACHE_OFF 0x0000 +#define SSL_SESS_CACHE_CLIENT 0x0001 +#define SSL_SESS_CACHE_SERVER 0x0002 +#define SSL_SESS_CACHE_BOTH (SSL_SESS_CACHE_CLIENT | SSL_SESS_CACHE_SERVER) +#define SSL_SESS_CACHE_NO_AUTO_CLEAR 0x0080 +#define SSL_SESS_CACHE_NO_INTERNAL_LOOKUP 0x0100 +#define SSL_SESS_CACHE_NO_INTERNAL_STORE 0x0200 +#define SSL_SESS_CACHE_NO_INTERNAL \ + (SSL_SESS_CACHE_NO_INTERNAL_LOOKUP | SSL_SESS_CACHE_NO_INTERNAL_STORE) + +/* SSL_CTX_set_session_cache_mode sets the session cache mode bits for |ctx| to + * |mode|. It returns the previous value. */ +OPENSSL_EXPORT int SSL_CTX_set_session_cache_mode(SSL_CTX *ctx, int mode); + +/* SSL_CTX_get_session_cache_mode returns the session cache mode bits for + * |ctx| */ +OPENSSL_EXPORT int SSL_CTX_get_session_cache_mode(const SSL_CTX *ctx); + +/* SSL_CTX_get_max_cert_list returns the maximum length, in bytes, of a peer + * certificate chain accepted by |ctx|. */ +OPENSSL_EXPORT size_t SSL_CTX_get_max_cert_list(const SSL_CTX *ctx); + +/* SSL_CTX_set_max_cert_list sets the maximum length, in bytes, of a peer + * certificate chain to |max_cert_list|. This affects how much memory may be + * consumed during the handshake. */ +OPENSSL_EXPORT void SSL_CTX_set_max_cert_list(SSL_CTX *ctx, + size_t max_cert_list); + +/* SSL_get_max_cert_list returns the maximum length, in bytes, of a peer + * certificate chain accepted by |ssl|. */ +OPENSSL_EXPORT size_t SSL_get_max_cert_list(const SSL *ssl); + +/* SSL_set_max_cert_list sets the maximum length, in bytes, of a peer + * certificate chain to |max_cert_list|. This affects how much memory may be + * consumed during the handshake. */ +OPENSSL_EXPORT void SSL_set_max_cert_list(SSL *ssl, size_t max_cert_list); + +/* SSL_CTX_set_max_send_fragment sets the maximum length, in bytes, of records + * sent by |ctx|. Beyond this length, handshake messages and application data + * will be split into multiple records. */ +OPENSSL_EXPORT void SSL_CTX_set_max_send_fragment(SSL_CTX *ctx, + size_t max_send_fragment); + +/* SSL_set_max_send_fragment sets the maximum length, in bytes, of records + * sent by |ssl|. Beyond this length, handshake messages and application data + * will be split into multiple records. */ +OPENSSL_EXPORT void SSL_set_max_send_fragment(SSL *ssl, + size_t max_send_fragment); + +/* SSL_CTX_set_tmp_dh_callback configures |ctx| to use |callback| to determine + * the group for DHE ciphers. |callback| should ignore |is_export| and + * |keylength| and return a |DH| of the selected group or NULL on error. Only + * the parameters are used, so the |DH| needn't have a generated keypair. + * + * WARNING: The caller does not take ownership of the resulting |DH|, so + * |callback| must save and release the object elsewhere. */ +OPENSSL_EXPORT void SSL_CTX_set_tmp_dh_callback( + SSL_CTX *ctx, DH *(*callback)(SSL *ssl, int is_export, int keylength)); + +/* SSL_set_tmp_dh_callback configures |ssl| to use |callback| to determine the + * group for DHE ciphers. |callback| should ignore |is_export| and |keylength| + * and return a |DH| of the selected group or NULL on error. Only the + * parameters are used, so the |DH| needn't have a generated keypair. + * + * WARNING: The caller does not take ownership of the resulting |DH|, so + * |callback| must save and release the object elsewhere. */ +OPENSSL_EXPORT void SSL_set_tmp_dh_callback(SSL *ssl, + DH *(*dh)(SSL *ssl, int is_export, + int keylength)); + +/* SSL_CTX_set_tmp_ecdh_callback configures |ctx| to use |callback| to determine + * the curve for ephemeral ECDH keys. |callback| should ignore |is_export| and + * |keylength| and return an |EC_KEY| of the selected curve or NULL on + * error. Only the curve is used, so the |EC_KEY| needn't have a generated + * keypair. + * + * If the callback is unset, an appropriate curve will be chosen automatically. + * (This is recommended.) + * + * WARNING: The caller does not take ownership of the resulting |EC_KEY|, so + * |callback| must save and release the object elsewhere. */ +OPENSSL_EXPORT void SSL_CTX_set_tmp_ecdh_callback( + SSL_CTX *ctx, EC_KEY *(*callback)(SSL *ssl, int is_export, int keylength)); + +/* SSL_set_tmp_ecdh_callback configures |ssl| to use |callback| to determine the + * curve for ephemeral ECDH keys. |callback| should ignore |is_export| and + * |keylength| and return an |EC_KEY| of the selected curve or NULL on + * error. Only the curve is used, so the |EC_KEY| needn't have a generated + * keypair. + * + * If the callback is unset, an appropriate curve will be chosen automatically. + * (This is recommended.) + * + * WARNING: The caller does not take ownership of the resulting |EC_KEY|, so + * |callback| must save and release the object elsewhere. */ +OPENSSL_EXPORT void SSL_set_tmp_ecdh_callback( + SSL *ssl, EC_KEY *(*callback)(SSL *ssl, int is_export, int keylength)); + +typedef void COMP_METHOD; + +/* SSL_get_current_compression returns NULL. */ +OPENSSL_EXPORT const COMP_METHOD *SSL_get_current_compression(SSL *s); + +/* SSL_get_current_expansion returns NULL. */ +OPENSSL_EXPORT const COMP_METHOD *SSL_get_current_expansion(SSL *s); + +OPENSSL_EXPORT int SSL_cache_hit(SSL *s); +OPENSSL_EXPORT int SSL_is_server(SSL *s); + +/* SSL_CTX_set_dos_protection_cb sets a callback that is called once the + * resumption decision for a ClientHello has been made. It can return 1 to + * allow the handshake to continue or zero to cause the handshake to abort. */ +OPENSSL_EXPORT void SSL_CTX_set_dos_protection_cb( + SSL_CTX *ctx, int (*cb)(const struct ssl_early_callback_ctx *)); + +/* SSL_get_structure_sizes returns the sizes of the SSL, SSL_CTX and + * SSL_SESSION structures so that a test can ensure that outside code agrees on + * these values. */ +OPENSSL_EXPORT void SSL_get_structure_sizes(size_t *ssl_size, + size_t *ssl_ctx_size, + size_t *ssl_session_size); + +OPENSSL_EXPORT void ERR_load_SSL_strings(void); + +/* SSL_get_rc4_state sets |*read_key| and |*write_key| to the RC4 states for + * the read and write directions. It returns one on success or zero if |ssl| + * isn't using an RC4-based cipher suite. */ +OPENSSL_EXPORT int SSL_get_rc4_state(const SSL *ssl, const RC4_KEY **read_key, + const RC4_KEY **write_key); + + +/* Deprecated functions. */ + +/* SSL_CIPHER_description writes a description of |cipher| into |buf| and + * returns |buf|. If |buf| is NULL, it returns a newly allocated string, to be + * freed with |OPENSSL_free|, or NULL on error. + * + * The description includes a trailing newline and has the form: + * AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1 + * + * Consider |SSL_CIPHER_get_name| or |SSL_CIPHER_get_rfc_name| instead. */ +OPENSSL_EXPORT const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, + char *buf, int len); + +/* SSL_CIPHER_get_version returns the string "TLSv1/SSLv3". */ +OPENSSL_EXPORT const char *SSL_CIPHER_get_version(const SSL_CIPHER *cipher); + +/* SSL_COMP_get_compression_methods returns NULL. */ +OPENSSL_EXPORT COMP_METHOD *SSL_COMP_get_compression_methods(void); + +/* SSL_COMP_add_compression_method returns one. */ +OPENSSL_EXPORT int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm); + +/* SSL_COMP_get_name returns NULL. */ +OPENSSL_EXPORT const char *SSL_COMP_get_name(const COMP_METHOD *comp); + +/* SSLv23_method calls |TLS_method|. */ +OPENSSL_EXPORT const SSL_METHOD *SSLv23_method(void); + +/* Version-specific methods behave exactly like |TLS_method| and |DTLS_method| + * except they also call |SSL_CTX_set_min_version| and |SSL_CTX_set_max_version| + * to lock connections to that protocol version. */ +OPENSSL_EXPORT const SSL_METHOD *SSLv3_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_1_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_2_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_2_method(void); + +/* Client- and server-specific methods call their corresponding generic + * methods. */ +OPENSSL_EXPORT const SSL_METHOD *SSLv23_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *SSLv23_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *SSLv3_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *SSLv3_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_1_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_1_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_2_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *TLSv1_2_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLS_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLS_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_client_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_2_server_method(void); +OPENSSL_EXPORT const SSL_METHOD *DTLSv1_2_client_method(void); + +/* SSL_clear resets |ssl| to allow another connection and returns one on success + * or zero on failure. It returns most configuration state but releases memory + * associated with the current connection. + * + * Free |ssl| and create a new one instead. */ +OPENSSL_EXPORT int SSL_clear(SSL *ssl); + +/* SSL_CTX_set_tmp_rsa_callback does nothing. */ +OPENSSL_EXPORT void SSL_CTX_set_tmp_rsa_callback( + SSL_CTX *ctx, RSA *(*cb)(SSL *ssl, int is_export, int keylength)); + +/* SSL_set_tmp_rsa_callback does nothing. */ +OPENSSL_EXPORT void SSL_set_tmp_rsa_callback(SSL *ssl, + RSA *(*cb)(SSL *ssl, int is_export, + int keylength)); + +/* SSL_CTX_sess_connect returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_connect(const SSL_CTX *ctx); + +/* SSL_CTX_sess_connect_good returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_connect_good(const SSL_CTX *ctx); + +/* SSL_CTX_sess_connect_renegotiate returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_connect_renegotiate(const SSL_CTX *ctx); + +/* SSL_CTX_sess_accept returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_accept(const SSL_CTX *ctx); + +/* SSL_CTX_sess_accept_renegotiate returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_accept_renegotiate(const SSL_CTX *ctx); + +/* SSL_CTX_sess_accept_good returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_accept_good(const SSL_CTX *ctx); + +/* SSL_CTX_sess_hits returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_hits(const SSL_CTX *ctx); + +/* SSL_CTX_sess_cb_hits returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_cb_hits(const SSL_CTX *ctx); + +/* SSL_CTX_sess_misses returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_misses(const SSL_CTX *ctx); + +/* SSL_CTX_sess_timeouts returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_timeouts(const SSL_CTX *ctx); + +/* SSL_CTX_sess_cache_full returns zero. */ +OPENSSL_EXPORT int SSL_CTX_sess_cache_full(const SSL_CTX *ctx); + +/* SSL_cutthrough_complete calls |SSL_in_false_start|. */ +OPENSSL_EXPORT int SSL_cutthrough_complete(const SSL *s); + +/* SSL_num_renegotiations calls |SSL_total_renegotiations|. */ +OPENSSL_EXPORT int SSL_num_renegotiations(const SSL *ssl); + +/* SSL_CTX_need_tmp_RSA returns zero. */ +OPENSSL_EXPORT int SSL_CTX_need_tmp_RSA(const SSL_CTX *ctx); + +/* SSL_need_tmp_RSA returns zero. */ +OPENSSL_EXPORT int SSL_need_tmp_RSA(const SSL *ssl); + +/* SSL_CTX_set_tmp_rsa returns one. */ +OPENSSL_EXPORT int SSL_CTX_set_tmp_rsa(SSL_CTX *ctx, const RSA *rsa); + +/* SSL_set_tmp_rsa returns one. */ +OPENSSL_EXPORT int SSL_set_tmp_rsa(SSL *ssl, const RSA *rsa); + +/* SSL_CTX_get_read_ahead returns zero. */ +OPENSSL_EXPORT int SSL_CTX_get_read_ahead(const SSL_CTX *ctx); + +/* SSL_CTX_set_read_ahead does nothing. */ +OPENSSL_EXPORT void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes); + +/* SSL_get_read_ahead returns zero. */ +OPENSSL_EXPORT int SSL_get_read_ahead(const SSL *s); + +/* SSL_set_read_ahead does nothing. */ +OPENSSL_EXPORT void SSL_set_read_ahead(SSL *s, int yes); + +/* SSL_renegotiate put an error on the error queue and returns zero. */ +OPENSSL_EXPORT int SSL_renegotiate(SSL *ssl); + +/* SSL_set_state does nothing. */ +OPENSSL_EXPORT void SSL_set_state(SSL *ssl, int state); + + +/* Android compatibility section. + * + * These functions are declared, temporarily, for Android because + * wpa_supplicant will take a little time to sync with upstream. Outside of + * Android they'll have no definition. */ + +#define SSL_F_SSL_SET_SESSION_TICKET_EXT doesnt_exist + +OPENSSL_EXPORT int SSL_set_session_ticket_ext(SSL *s, void *ext_data, + int ext_len); +OPENSSL_EXPORT int SSL_set_session_secret_cb(SSL *s, void *cb, void *arg); +OPENSSL_EXPORT int SSL_set_session_ticket_ext_cb(SSL *s, void *cb, void *arg); +OPENSSL_EXPORT int SSL_set_ssl_method(SSL *s, const SSL_METHOD *method); + +#define OPENSSL_VERSION_TEXT "BoringSSL" + +#define SSLEAY_VERSION 0 + +/* SSLeay_version is a compatibility function that returns the string + * "BoringSSL". */ +OPENSSL_EXPORT const char *SSLeay_version(int unused); + + +/* Preprocessor compatibility section. + * + * Historically, a number of APIs were implemented in OpenSSL as macros and + * constants to 'ctrl' functions. To avoid breaking #ifdefs in consumers, this + * section defines a number of legacy macros. + * + * Although using either the CTRL values or their wrapper macros in #ifdefs is + * still supported, the CTRL values may not be passed to |SSL_ctrl| and + * |SSL_CTX_ctrl|. Call the functions (previously wrapper macros) instead. */ + +#define DTLS_CTRL_GET_TIMEOUT doesnt_exist +#define DTLS_CTRL_HANDLE_TIMEOUT doesnt_exist +#define SSL_CTRL_CHAIN doesnt_exist +#define SSL_CTRL_CHAIN_CERT doesnt_exist +#define SSL_CTRL_CHANNEL_ID doesnt_exist +#define SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS doesnt_exist +#define SSL_CTRL_CLEAR_MODE doesnt_exist +#define SSL_CTRL_CLEAR_OPTIONS doesnt_exist +#define SSL_CTRL_EXTRA_CHAIN_CERT doesnt_exist +#define SSL_CTRL_GET_CHAIN_CERTS doesnt_exist +#define SSL_CTRL_GET_CHANNEL_ID doesnt_exist +#define SSL_CTRL_GET_EXTRA_CHAIN_CERTS doesnt_exist +#define SSL_CTRL_GET_MAX_CERT_LIST doesnt_exist +#define SSL_CTRL_GET_NUM_RENEGOTIATIONS doesnt_exist +#define SSL_CTRL_GET_READ_AHEAD doesnt_exist +#define SSL_CTRL_GET_RI_SUPPORT doesnt_exist +#define SSL_CTRL_GET_SESSION_REUSED doesnt_exist +#define SSL_CTRL_GET_SESS_CACHE_MODE doesnt_exist +#define SSL_CTRL_GET_SESS_CACHE_SIZE doesnt_exist +#define SSL_CTRL_GET_TLSEXT_TICKET_KEYS doesnt_exist +#define SSL_CTRL_GET_TOTAL_RENEGOTIATIONS doesnt_exist +#define SSL_CTRL_MODE doesnt_exist +#define SSL_CTRL_NEED_TMP_RSA doesnt_exist +#define SSL_CTRL_OPTIONS doesnt_exist +#define SSL_CTRL_SESS_NUMBER doesnt_exist +#define SSL_CTRL_SET_CHANNEL_ID doesnt_exist +#define SSL_CTRL_SET_MAX_CERT_LIST doesnt_exist +#define SSL_CTRL_SET_MAX_SEND_FRAGMENT doesnt_exist +#define SSL_CTRL_SET_MSG_CALLBACK doesnt_exist +#define SSL_CTRL_SET_MSG_CALLBACK_ARG doesnt_exist +#define SSL_CTRL_SET_MTU doesnt_exist +#define SSL_CTRL_SET_READ_AHEAD doesnt_exist +#define SSL_CTRL_SET_SESS_CACHE_MODE doesnt_exist +#define SSL_CTRL_SET_SESS_CACHE_SIZE doesnt_exist +#define SSL_CTRL_SET_TLSEXT_HOSTNAME doesnt_exist +#define SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG doesnt_exist +#define SSL_CTRL_SET_TLSEXT_SERVERNAME_CB doesnt_exist +#define SSL_CTRL_SET_TLSEXT_TICKET_KEYS doesnt_exist +#define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB doesnt_exist +#define SSL_CTRL_SET_TMP_DH doesnt_exist +#define SSL_CTRL_SET_TMP_DH_CB doesnt_exist +#define SSL_CTRL_SET_TMP_ECDH doesnt_exist +#define SSL_CTRL_SET_TMP_ECDH_CB doesnt_exist +#define SSL_CTRL_SET_TMP_RSA doesnt_exist +#define SSL_CTRL_SET_TMP_RSA_CB doesnt_exist + +#define DTLSv1_get_timeout DTLSv1_get_timeout +#define DTLSv1_handle_timeout DTLSv1_handle_timeout +#define SSL_CTX_add0_chain_cert SSL_CTX_add0_chain_cert +#define SSL_CTX_add1_chain_cert SSL_CTX_add1_chain_cert +#define SSL_CTX_add_extra_chain_cert SSL_CTX_add_extra_chain_cert +#define SSL_CTX_clear_extra_chain_certs SSL_CTX_clear_extra_chain_certs +#define SSL_CTX_clear_chain_certs SSL_CTX_clear_chain_certs +#define SSL_CTX_clear_mode SSL_CTX_clear_mode +#define SSL_CTX_clear_options SSL_CTX_clear_options +#define SSL_CTX_enable_tls_channel_id SSL_CTX_enable_tls_channel_id +#define SSL_CTX_get0_chain_certs SSL_CTX_get0_chain_certs +#define SSL_CTX_get_extra_chain_certs SSL_CTX_get_extra_chain_certs +#define SSL_CTX_get_max_cert_list SSL_CTX_get_max_cert_list +#define SSL_CTX_get_mode SSL_CTX_get_mode +#define SSL_CTX_get_options SSL_CTX_get_options +#define SSL_CTX_get_read_ahead SSL_CTX_get_read_ahead +#define SSL_CTX_get_session_cache_mode SSL_CTX_get_session_cache_mode +#define SSL_CTX_get_tlsext_ticket_keys SSL_CTX_get_tlsext_ticket_keys +#define SSL_CTX_need_tmp_RSA SSL_CTX_need_tmp_RSA +#define SSL_CTX_sess_get_cache_size SSL_CTX_sess_get_cache_size +#define SSL_CTX_sess_number SSL_CTX_sess_number +#define SSL_CTX_sess_set_cache_size SSL_CTX_sess_set_cache_size +#define SSL_CTX_set0_chain SSL_CTX_set0_chain +#define SSL_CTX_set1_chain SSL_CTX_set1_chain +#define SSL_CTX_set1_tls_channel_id SSL_CTX_set1_tls_channel_id +#define SSL_CTX_set_max_cert_list SSL_CTX_set_max_cert_list +#define SSL_CTX_set_max_send_fragment SSL_CTX_set_max_send_fragment +#define SSL_CTX_set_mode SSL_CTX_set_mode +#define SSL_CTX_set_msg_callback_arg SSL_CTX_set_msg_callback_arg +#define SSL_CTX_set_options SSL_CTX_set_options +#define SSL_CTX_set_read_ahead SSL_CTX_set_read_ahead +#define SSL_CTX_set_session_cache_mode SSL_CTX_set_session_cache_mode +#define SSL_CTX_set_tlsext_servername_arg SSL_CTX_set_tlsext_servername_arg +#define SSL_CTX_set_tlsext_servername_callback \ + SSL_CTX_set_tlsext_servername_callback +#define SSL_CTX_set_tlsext_ticket_key_cb SSL_CTX_set_tlsext_ticket_key_cb +#define SSL_CTX_set_tlsext_ticket_keys SSL_CTX_set_tlsext_ticket_keys +#define SSL_CTX_set_tmp_dh SSL_CTX_set_tmp_dh +#define SSL_CTX_set_tmp_ecdh SSL_CTX_set_tmp_ecdh +#define SSL_CTX_set_tmp_rsa SSL_CTX_set_tmp_rsa +#define SSL_add0_chain_cert SSL_add0_chain_cert +#define SSL_add1_chain_cert SSL_add1_chain_cert +#define SSL_clear_chain_certs SSL_clear_chain_certs +#define SSL_clear_mode SSL_clear_mode +#define SSL_clear_options SSL_clear_options +#define SSL_enable_tls_channel_id SSL_enable_tls_channel_id +#define SSL_get0_chain_certs SSL_get0_chain_certs +#define SSL_get_max_cert_list SSL_get_max_cert_list +#define SSL_get_mode SSL_get_mode +#define SSL_get_options SSL_get_options +#define SSL_get_secure_renegotiation_support \ + SSL_get_secure_renegotiation_support +#define SSL_get_tls_channel_id SSL_get_tls_channel_id +#define SSL_need_tmp_RSA SSL_need_tmp_RSA +#define SSL_num_renegotiations SSL_num_renegotiations +#define SSL_session_reused SSL_session_reused +#define SSL_set0_chain SSL_set0_chain +#define SSL_set1_chain SSL_set1_chain +#define SSL_set1_tls_channel_id SSL_set1_tls_channel_id +#define SSL_set_max_cert_list SSL_set_max_cert_list +#define SSL_set_max_send_fragment SSL_set_max_send_fragment +#define SSL_set_mode SSL_set_mode +#define SSL_set_msg_callback_arg SSL_set_msg_callback_arg +#define SSL_set_mtu SSL_set_mtu +#define SSL_set_options SSL_set_options +#define SSL_set_tlsext_host_name SSL_set_tlsext_host_name +#define SSL_set_tmp_dh SSL_set_tmp_dh +#define SSL_set_tmp_ecdh SSL_set_tmp_ecdh +#define SSL_set_tmp_rsa SSL_set_tmp_rsa +#define SSL_total_renegotiations SSL_total_renegotiations + + +#if defined(__cplusplus) +} /* extern C */ +#endif + + +/* Library consumers assume these headers are included by ssl.h, but they depend + * on ssl.h, so include them after all declarations. + * + * TODO(davidben): The separation between ssl.h and these version-specific + * headers introduces circular dependencies and is inconsistent. The function + * declarations should move to ssl.h. Many of the constants can probably be + * pruned or unexported. */ +#include +#include /* This is mostly sslv3 with a few tweaks */ +#include /* Support for the use_srtp extension */ + + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script make_errors.go. Any + * changes made after this point may be overwritten when the script is next run. + */ +#define SSL_R_APP_DATA_IN_HANDSHAKE 100 +#define SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT 101 +#define SSL_R_BAD_ALERT 102 +#define SSL_R_BAD_CHANGE_CIPHER_SPEC 103 +#define SSL_R_BAD_DATA_RETURNED_BY_CALLBACK 104 +#define SSL_R_BAD_DH_P_LENGTH 105 +#define SSL_R_BAD_DIGEST_LENGTH 106 +#define SSL_R_BAD_ECC_CERT 107 +#define SSL_R_BAD_ECPOINT 108 +#define SSL_R_BAD_HANDSHAKE_LENGTH 109 +#define SSL_R_BAD_HANDSHAKE_RECORD 110 +#define SSL_R_BAD_HELLO_REQUEST 111 +#define SSL_R_BAD_LENGTH 112 +#define SSL_R_BAD_PACKET_LENGTH 113 +#define SSL_R_BAD_RSA_ENCRYPT 114 +#define SSL_R_BAD_SIGNATURE 115 +#define SSL_R_BAD_SRTP_MKI_VALUE 116 +#define SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST 117 +#define SSL_R_BAD_SSL_FILETYPE 118 +#define SSL_R_BAD_WRITE_RETRY 119 +#define SSL_R_BIO_NOT_SET 120 +#define SSL_R_BN_LIB 121 +#define SSL_R_CANNOT_SERIALIZE_PUBLIC_KEY 122 +#define SSL_R_CA_DN_LENGTH_MISMATCH 123 +#define SSL_R_CA_DN_TOO_LONG 124 +#define SSL_R_CCS_RECEIVED_EARLY 125 +#define SSL_R_CERTIFICATE_VERIFY_FAILED 126 +#define SSL_R_CERT_CB_ERROR 127 +#define SSL_R_CERT_LENGTH_MISMATCH 128 +#define SSL_R_CHANNEL_ID_NOT_P256 129 +#define SSL_R_CHANNEL_ID_SIGNATURE_INVALID 130 +#define SSL_R_CIPHER_CODE_WRONG_LENGTH 131 +#define SSL_R_CIPHER_OR_HASH_UNAVAILABLE 132 +#define SSL_R_CLIENTHELLO_PARSE_FAILED 133 +#define SSL_R_CLIENTHELLO_TLSEXT 134 +#define SSL_R_CONNECTION_REJECTED 135 +#define SSL_R_CONNECTION_TYPE_NOT_SET 136 +#define SSL_R_COOKIE_MISMATCH 137 +#define SSL_R_D2I_ECDSA_SIG 138 +#define SSL_R_DATA_BETWEEN_CCS_AND_FINISHED 139 +#define SSL_R_DATA_LENGTH_TOO_LONG 140 +#define SSL_R_DECODE_ERROR 141 +#define SSL_R_DECRYPTION_FAILED 142 +#define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 143 +#define SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG 144 +#define SSL_R_DIGEST_CHECK_FAILED 145 +#define SSL_R_DTLS_MESSAGE_TOO_BIG 146 +#define SSL_R_ECC_CERT_NOT_FOR_SIGNING 147 +#define SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST 148 +#define SSL_R_ENCRYPTED_LENGTH_TOO_LONG 149 +#define SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST 150 +#define SSL_R_EVP_DIGESTSIGNFINAL_FAILED 151 +#define SSL_R_EVP_DIGESTSIGNINIT_FAILED 152 +#define SSL_R_EXCESSIVE_MESSAGE_SIZE 153 +#define SSL_R_EXTRA_DATA_IN_MESSAGE 154 +#define SSL_R_GOT_A_FIN_BEFORE_A_CCS 155 +#define SSL_R_GOT_CHANNEL_ID_BEFORE_A_CCS 156 +#define SSL_R_GOT_NEXT_PROTO_BEFORE_A_CCS 157 +#define SSL_R_GOT_NEXT_PROTO_WITHOUT_EXTENSION 158 +#define SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO 159 +#define SSL_R_HANDSHAKE_RECORD_BEFORE_CCS 160 +#define SSL_R_HTTPS_PROXY_REQUEST 161 +#define SSL_R_HTTP_REQUEST 162 +#define SSL_R_INAPPROPRIATE_FALLBACK 163 +#define SSL_R_INVALID_COMMAND 164 +#define SSL_R_INVALID_MESSAGE 165 +#define SSL_R_INVALID_SSL_SESSION 166 +#define SSL_R_INVALID_TICKET_KEYS_LENGTH 167 +#define SSL_R_LENGTH_MISMATCH 168 +#define SSL_R_LIBRARY_HAS_NO_CIPHERS 169 +#define SSL_R_MISSING_DH_KEY 170 +#define SSL_R_MISSING_ECDSA_SIGNING_CERT 171 +#define SSL_R_MISSING_RSA_CERTIFICATE 172 +#define SSL_R_MISSING_RSA_ENCRYPTING_CERT 173 +#define SSL_R_MISSING_RSA_SIGNING_CERT 174 +#define SSL_R_MISSING_TMP_DH_KEY 175 +#define SSL_R_MISSING_TMP_ECDH_KEY 176 +#define SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS 177 +#define SSL_R_MTU_TOO_SMALL 178 +#define SSL_R_NESTED_GROUP 179 +#define SSL_R_NO_CERTIFICATES_RETURNED 180 +#define SSL_R_NO_CERTIFICATE_ASSIGNED 181 +#define SSL_R_NO_CERTIFICATE_SET 182 +#define SSL_R_NO_CIPHERS_AVAILABLE 183 +#define SSL_R_NO_CIPHERS_PASSED 184 +#define SSL_R_NO_CIPHERS_SPECIFIED 185 +#define SSL_R_NO_CIPHER_MATCH 186 +#define SSL_R_NO_COMPRESSION_SPECIFIED 187 +#define SSL_R_NO_METHOD_SPECIFIED 188 +#define SSL_R_NO_P256_SUPPORT 189 +#define SSL_R_NO_PRIVATE_KEY_ASSIGNED 190 +#define SSL_R_NO_RENEGOTIATION 191 +#define SSL_R_NO_REQUIRED_DIGEST 192 +#define SSL_R_NO_SHARED_CIPHER 193 +#define SSL_R_NO_SHARED_SIGATURE_ALGORITHMS 194 +#define SSL_R_NO_SRTP_PROFILES 195 +#define SSL_R_NULL_SSL_CTX 196 +#define SSL_R_NULL_SSL_METHOD_PASSED 197 +#define SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED 198 +#define SSL_R_PACKET_LENGTH_TOO_LONG 199 +#define SSL_R_PARSE_TLSEXT 200 +#define SSL_R_PATH_TOO_LONG 201 +#define SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE 202 +#define SSL_R_PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE 203 +#define SSL_R_PROTOCOL_IS_SHUTDOWN 204 +#define SSL_R_PSK_IDENTITY_NOT_FOUND 205 +#define SSL_R_PSK_NO_CLIENT_CB 206 +#define SSL_R_PSK_NO_SERVER_CB 207 +#define SSL_R_READ_BIO_NOT_SET 208 +#define SSL_R_READ_TIMEOUT_EXPIRED 209 +#define SSL_R_RECORD_LENGTH_MISMATCH 210 +#define SSL_R_RECORD_TOO_LARGE 211 +#define SSL_R_RENEGOTIATE_EXT_TOO_LONG 212 +#define SSL_R_RENEGOTIATION_ENCODING_ERR 213 +#define SSL_R_RENEGOTIATION_MISMATCH 214 +#define SSL_R_REQUIRED_CIPHER_MISSING 215 +#define SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING 216 +#define SSL_R_SERVERHELLO_TLSEXT 217 +#define SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED 218 +#define SSL_R_SESSION_MAY_NOT_BE_CREATED 219 +#define SSL_R_SIGNATURE_ALGORITHMS_ERROR 220 +#define SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES 221 +#define SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG 222 +#define SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE 223 +#define SSL_R_SSL3_EXT_INVALID_SERVERNAME 224 +#define SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE 225 +#define SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION 226 +#define SSL_R_SSL_HANDSHAKE_FAILURE 227 +#define SSL_R_SSL_SESSION_ID_CALLBACK_FAILED 228 +#define SSL_R_SSL_SESSION_ID_CONFLICT 229 +#define SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG 230 +#define SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH 231 +#define SSL_R_TLS_CLIENT_CERT_REQ_WITH_ANON_CIPHER 232 +#define SSL_R_TLS_ILLEGAL_EXPORTER_LABEL 233 +#define SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST 234 +#define SSL_R_TLS_PEER_DID_NOT_RESPOND_WITH_CERTIFICATE_LIST 235 +#define SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG 236 +#define SSL_R_TOO_MANY_EMPTY_FRAGMENTS 237 +#define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 238 +#define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS 239 +#define SSL_R_UNEXPECTED_GROUP_CLOSE 240 +#define SSL_R_UNEXPECTED_MESSAGE 241 +#define SSL_R_UNEXPECTED_OPERATOR_IN_GROUP 242 +#define SSL_R_UNEXPECTED_RECORD 243 +#define SSL_R_UNINITIALIZED 244 +#define SSL_R_UNKNOWN_ALERT_TYPE 245 +#define SSL_R_UNKNOWN_CERTIFICATE_TYPE 246 +#define SSL_R_UNKNOWN_CIPHER_RETURNED 247 +#define SSL_R_UNKNOWN_CIPHER_TYPE 248 +#define SSL_R_UNKNOWN_DIGEST 249 +#define SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE 250 +#define SSL_R_UNKNOWN_PROTOCOL 251 +#define SSL_R_UNKNOWN_SSL_VERSION 252 +#define SSL_R_UNKNOWN_STATE 253 +#define SSL_R_UNPROCESSED_HANDSHAKE_DATA 254 +#define SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED 255 +#define SSL_R_UNSUPPORTED_CIPHER 256 +#define SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM 257 +#define SSL_R_UNSUPPORTED_ELLIPTIC_CURVE 258 +#define SSL_R_UNSUPPORTED_PROTOCOL 259 +#define SSL_R_UNSUPPORTED_SSL_VERSION 260 +#define SSL_R_USE_SRTP_NOT_NEGOTIATED 261 +#define SSL_R_WRONG_CERTIFICATE_TYPE 262 +#define SSL_R_WRONG_CIPHER_RETURNED 263 +#define SSL_R_WRONG_CURVE 264 +#define SSL_R_WRONG_MESSAGE_TYPE 265 +#define SSL_R_WRONG_SIGNATURE_TYPE 266 +#define SSL_R_WRONG_SSL_VERSION 267 +#define SSL_R_WRONG_VERSION_NUMBER 268 +#define SSL_R_X509_LIB 269 +#define SSL_R_X509_VERIFICATION_SETUP_PROBLEMS 270 +#define SSL_R_FRAGMENT_MISMATCH 271 +#define SSL_R_BUFFER_TOO_SMALL 272 +#define SSL_R_OLD_SESSION_VERSION_NOT_RETURNED 273 +#define SSL_R_OUTPUT_ALIASES_INPUT 274 +#define SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION 275 +#define SSL_R_EMS_STATE_INCONSISTENT 276 +#define SSL_R_RESUMED_NON_EMS_SESSION_WITH_EMS_EXTENSION 277 +#define SSL_R_TOO_MANY_WARNING_ALERTS 278 +#define SSL_R_UNEXPECTED_EXTENSION 279 +#define SSL_R_SIGNATURE_ALGORITHMS_EXTENSION_SENT_BY_SERVER 280 +#define SSL_R_ERROR_ADDING_EXTENSION 281 +#define SSL_R_ERROR_PARSING_EXTENSION 282 +#define SSL_R_MISSING_EXTENSION 283 +#define SSL_R_CUSTOM_EXTENSION_CONTENTS_TOO_LARGE 284 +#define SSL_R_CUSTOM_EXTENSION_ERROR 285 +#define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000 +#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 +#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020 +#define SSL_R_TLSV1_ALERT_DECRYPTION_FAILED 1021 +#define SSL_R_TLSV1_ALERT_RECORD_OVERFLOW 1022 +#define SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE 1030 +#define SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE 1040 +#define SSL_R_SSLV3_ALERT_NO_CERTIFICATE 1041 +#define SSL_R_SSLV3_ALERT_BAD_CERTIFICATE 1042 +#define SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE 1043 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED 1044 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED 1045 +#define SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN 1046 +#define SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER 1047 +#define SSL_R_TLSV1_ALERT_UNKNOWN_CA 1048 +#define SSL_R_TLSV1_ALERT_ACCESS_DENIED 1049 +#define SSL_R_TLSV1_ALERT_DECODE_ERROR 1050 +#define SSL_R_TLSV1_ALERT_DECRYPT_ERROR 1051 +#define SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION 1060 +#define SSL_R_TLSV1_ALERT_PROTOCOL_VERSION 1070 +#define SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY 1071 +#define SSL_R_TLSV1_ALERT_INTERNAL_ERROR 1080 +#define SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK 1086 +#define SSL_R_TLSV1_ALERT_USER_CANCELLED 1090 +#define SSL_R_TLSV1_ALERT_NO_RENEGOTIATION 1100 +#define SSL_R_TLSV1_UNSUPPORTED_EXTENSION 1110 +#define SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE 1111 +#define SSL_R_TLSV1_UNRECOGNIZED_NAME 1112 +#define SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE 1113 +#define SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE 1114 + +#endif /* OPENSSL_HEADER_SSL_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/ssl3.h b/TMessagesProj/jni/boringssl/include/openssl/ssl3.h new file mode 100644 index 00000000..e07488d0 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/ssl3.h @@ -0,0 +1,696 @@ +/* ssl/ssl3.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2002 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECC cipher suite support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef HEADER_SSL3_H +#define HEADER_SSL3_H + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* These are kept to support clients that negotiates higher protocol versions + * using SSLv2 client hello records. */ +#define SSL2_MT_CLIENT_HELLO 1 +#define SSL2_VERSION 0x0002 + +/* Signalling cipher suite value from RFC 5746. */ +#define SSL3_CK_SCSV 0x030000FF +/* Fallback signalling cipher suite value from RFC 7507. */ +#define SSL3_CK_FALLBACK_SCSV 0x03005600 + +#define SSL3_CK_RSA_NULL_MD5 0x03000001 +#define SSL3_CK_RSA_NULL_SHA 0x03000002 +#define SSL3_CK_RSA_RC4_40_MD5 0x03000003 +#define SSL3_CK_RSA_RC4_128_MD5 0x03000004 +#define SSL3_CK_RSA_RC4_128_SHA 0x03000005 +#define SSL3_CK_RSA_RC2_40_MD5 0x03000006 +#define SSL3_CK_RSA_IDEA_128_SHA 0x03000007 +#define SSL3_CK_RSA_DES_40_CBC_SHA 0x03000008 +#define SSL3_CK_RSA_DES_64_CBC_SHA 0x03000009 +#define SSL3_CK_RSA_DES_192_CBC3_SHA 0x0300000A + +#define SSL3_CK_DH_DSS_DES_40_CBC_SHA 0x0300000B +#define SSL3_CK_DH_DSS_DES_64_CBC_SHA 0x0300000C +#define SSL3_CK_DH_DSS_DES_192_CBC3_SHA 0x0300000D +#define SSL3_CK_DH_RSA_DES_40_CBC_SHA 0x0300000E +#define SSL3_CK_DH_RSA_DES_64_CBC_SHA 0x0300000F +#define SSL3_CK_DH_RSA_DES_192_CBC3_SHA 0x03000010 + +#define SSL3_CK_EDH_DSS_DES_40_CBC_SHA 0x03000011 +#define SSL3_CK_EDH_DSS_DES_64_CBC_SHA 0x03000012 +#define SSL3_CK_EDH_DSS_DES_192_CBC3_SHA 0x03000013 +#define SSL3_CK_EDH_RSA_DES_40_CBC_SHA 0x03000014 +#define SSL3_CK_EDH_RSA_DES_64_CBC_SHA 0x03000015 +#define SSL3_CK_EDH_RSA_DES_192_CBC3_SHA 0x03000016 + +#define SSL3_CK_ADH_RC4_40_MD5 0x03000017 +#define SSL3_CK_ADH_RC4_128_MD5 0x03000018 +#define SSL3_CK_ADH_DES_40_CBC_SHA 0x03000019 +#define SSL3_CK_ADH_DES_64_CBC_SHA 0x0300001A +#define SSL3_CK_ADH_DES_192_CBC_SHA 0x0300001B + +#define SSL3_TXT_RSA_NULL_MD5 "NULL-MD5" +#define SSL3_TXT_RSA_NULL_SHA "NULL-SHA" +#define SSL3_TXT_RSA_RC4_40_MD5 "EXP-RC4-MD5" +#define SSL3_TXT_RSA_RC4_128_MD5 "RC4-MD5" +#define SSL3_TXT_RSA_RC4_128_SHA "RC4-SHA" +#define SSL3_TXT_RSA_RC2_40_MD5 "EXP-RC2-CBC-MD5" +#define SSL3_TXT_RSA_IDEA_128_SHA "IDEA-CBC-SHA" +#define SSL3_TXT_RSA_DES_40_CBC_SHA "EXP-DES-CBC-SHA" +#define SSL3_TXT_RSA_DES_64_CBC_SHA "DES-CBC-SHA" +#define SSL3_TXT_RSA_DES_192_CBC3_SHA "DES-CBC3-SHA" + +#define SSL3_TXT_DH_DSS_DES_40_CBC_SHA "EXP-DH-DSS-DES-CBC-SHA" +#define SSL3_TXT_DH_DSS_DES_64_CBC_SHA "DH-DSS-DES-CBC-SHA" +#define SSL3_TXT_DH_DSS_DES_192_CBC3_SHA "DH-DSS-DES-CBC3-SHA" +#define SSL3_TXT_DH_RSA_DES_40_CBC_SHA "EXP-DH-RSA-DES-CBC-SHA" +#define SSL3_TXT_DH_RSA_DES_64_CBC_SHA "DH-RSA-DES-CBC-SHA" +#define SSL3_TXT_DH_RSA_DES_192_CBC3_SHA "DH-RSA-DES-CBC3-SHA" + +#define SSL3_TXT_EDH_DSS_DES_40_CBC_SHA "EXP-EDH-DSS-DES-CBC-SHA" +#define SSL3_TXT_EDH_DSS_DES_64_CBC_SHA "EDH-DSS-DES-CBC-SHA" +#define SSL3_TXT_EDH_DSS_DES_192_CBC3_SHA "EDH-DSS-DES-CBC3-SHA" +#define SSL3_TXT_EDH_RSA_DES_40_CBC_SHA "EXP-EDH-RSA-DES-CBC-SHA" +#define SSL3_TXT_EDH_RSA_DES_64_CBC_SHA "EDH-RSA-DES-CBC-SHA" +#define SSL3_TXT_EDH_RSA_DES_192_CBC3_SHA "EDH-RSA-DES-CBC3-SHA" + +#define SSL3_TXT_ADH_RC4_40_MD5 "EXP-ADH-RC4-MD5" +#define SSL3_TXT_ADH_RC4_128_MD5 "ADH-RC4-MD5" +#define SSL3_TXT_ADH_DES_40_CBC_SHA "EXP-ADH-DES-CBC-SHA" +#define SSL3_TXT_ADH_DES_64_CBC_SHA "ADH-DES-CBC-SHA" +#define SSL3_TXT_ADH_DES_192_CBC_SHA "ADH-DES-CBC3-SHA" + +#define SSL3_SSL_SESSION_ID_LENGTH 32 +#define SSL3_MAX_SSL_SESSION_ID_LENGTH 32 + +#define SSL3_MASTER_SECRET_SIZE 48 +#define SSL3_RANDOM_SIZE 32 +#define SSL3_SESSION_ID_SIZE 32 +#define SSL3_RT_HEADER_LENGTH 5 + +#define SSL3_HM_HEADER_LENGTH 4 + +#ifndef SSL3_ALIGN_PAYLOAD +/* Some will argue that this increases memory footprint, but it's not actually + * true. Point is that malloc has to return at least 64-bit aligned pointers, + * meaning that allocating 5 bytes wastes 3 bytes in either case. Suggested + * pre-gaping simply moves these wasted bytes from the end of allocated region + * to its front, but makes data payload aligned, which improves performance. */ +#define SSL3_ALIGN_PAYLOAD 8 +#else +#if (SSL3_ALIGN_PAYLOAD & (SSL3_ALIGN_PAYLOAD - 1)) != 0 +#error "insane SSL3_ALIGN_PAYLOAD" +#undef SSL3_ALIGN_PAYLOAD +#endif +#endif + +/* This is the maximum MAC (digest) size used by the SSL library. Currently + * maximum of 20 is used by SHA1, but we reserve for future extension for + * 512-bit hashes. */ + +#define SSL3_RT_MAX_MD_SIZE 64 + +/* Maximum block size used in all ciphersuites. Currently 16 for AES. */ + +#define SSL_RT_MAX_CIPHER_BLOCK_SIZE 16 + +#define SSL3_RT_MAX_EXTRA (16384) + +/* Maximum plaintext length: defined by SSL/TLS standards */ +#define SSL3_RT_MAX_PLAIN_LENGTH 16384 +/* Maximum compression overhead: defined by SSL/TLS standards */ +#define SSL3_RT_MAX_COMPRESSED_OVERHEAD 1024 + +/* The standards give a maximum encryption overhead of 1024 bytes. In practice + * the value is lower than this. The overhead is the maximum number of padding + * bytes (256) plus the mac size. + * + * TODO(davidben): This derivation doesn't take AEADs into account, or TLS 1.1 + * explicit nonces. It happens to work because |SSL3_RT_MAX_MD_SIZE| is larger + * than necessary and no true AEAD has variable overhead in TLS 1.2. */ +#define SSL3_RT_MAX_ENCRYPTED_OVERHEAD (256 + SSL3_RT_MAX_MD_SIZE) + +/* SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD is the maximum overhead in encrypting a + * record. This does not include the record header. Some ciphers use explicit + * nonces, so it includes both the AEAD overhead as well as the nonce. */ +#define SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD \ + (EVP_AEAD_MAX_OVERHEAD + EVP_AEAD_MAX_NONCE_LENGTH) + +OPENSSL_COMPILE_ASSERT( + SSL3_RT_MAX_ENCRYPTED_OVERHEAD >= SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD, + max_overheads_are_consistent); + +/* SSL3_RT_MAX_COMPRESSED_LENGTH is an alias for + * |SSL3_RT_MAX_PLAIN_LENGTH|. Compression is gone, so don't include the + * compression overhead. */ +#define SSL3_RT_MAX_COMPRESSED_LENGTH SSL3_RT_MAX_PLAIN_LENGTH + +#define SSL3_RT_MAX_ENCRYPTED_LENGTH \ + (SSL3_RT_MAX_ENCRYPTED_OVERHEAD + SSL3_RT_MAX_COMPRESSED_LENGTH) +#define SSL3_RT_MAX_PACKET_SIZE \ + (SSL3_RT_MAX_ENCRYPTED_LENGTH + SSL3_RT_HEADER_LENGTH) + +#define SSL3_MD_CLIENT_FINISHED_CONST "\x43\x4C\x4E\x54" +#define SSL3_MD_SERVER_FINISHED_CONST "\x53\x52\x56\x52" + +#define SSL3_VERSION 0x0300 +#define SSL3_VERSION_MAJOR 0x03 +#define SSL3_VERSION_MINOR 0x00 + +#define SSL3_RT_CHANGE_CIPHER_SPEC 20 +#define SSL3_RT_ALERT 21 +#define SSL3_RT_HANDSHAKE 22 +#define SSL3_RT_APPLICATION_DATA 23 + +/* Pseudo content type for SSL/TLS header info */ +#define SSL3_RT_HEADER 0x100 + +#define SSL3_AL_WARNING 1 +#define SSL3_AL_FATAL 2 + +#define SSL3_AD_CLOSE_NOTIFY 0 +#define SSL3_AD_UNEXPECTED_MESSAGE 10 /* fatal */ +#define SSL3_AD_BAD_RECORD_MAC 20 /* fatal */ +#define SSL3_AD_DECOMPRESSION_FAILURE 30 /* fatal */ +#define SSL3_AD_HANDSHAKE_FAILURE 40 /* fatal */ +#define SSL3_AD_NO_CERTIFICATE 41 +#define SSL3_AD_BAD_CERTIFICATE 42 +#define SSL3_AD_UNSUPPORTED_CERTIFICATE 43 +#define SSL3_AD_CERTIFICATE_REVOKED 44 +#define SSL3_AD_CERTIFICATE_EXPIRED 45 +#define SSL3_AD_CERTIFICATE_UNKNOWN 46 +#define SSL3_AD_ILLEGAL_PARAMETER 47 /* fatal */ +#define SSL3_AD_INAPPROPRIATE_FALLBACK 86 /* fatal */ + +typedef struct ssl3_record_st { + /* type is the record type. */ + uint8_t type; + /* length is the number of unconsumed bytes of |data|. */ + uint16_t length; + /* off is the number of consumed bytes of |data|. */ + uint16_t off; + /* data is a non-owning pointer to the record contents. The total length of + * the buffer is |off| + |length|. */ + uint8_t *data; + /* epoch, in DTLS, is the epoch number of the record. */ + uint16_t epoch; +} SSL3_RECORD; + +typedef struct ssl3_buffer_st { + uint8_t *buf; /* at least SSL3_RT_MAX_PACKET_SIZE bytes, see + ssl3_setup_buffers() */ + size_t len; /* buffer size */ + int offset; /* where to 'copy from' */ + int left; /* how many bytes left */ +} SSL3_BUFFER; + +#define SSL3_CT_RSA_SIGN 1 +#define SSL3_CT_DSS_SIGN 2 +#define SSL3_CT_RSA_FIXED_DH 3 +#define SSL3_CT_DSS_FIXED_DH 4 +#define SSL3_CT_RSA_EPHEMERAL_DH 5 +#define SSL3_CT_DSS_EPHEMERAL_DH 6 +#define SSL3_CT_FORTEZZA_DMS 20 + + +/* TODO(davidben): This flag can probably be merged into s3->change_cipher_spec + * to something tri-state. (Normal / Expect CCS / Between CCS and Finished). */ +#define SSL3_FLAGS_EXPECT_CCS 0x0080 + +typedef struct ssl3_state_st { + long flags; + + uint8_t read_sequence[8]; + int read_mac_secret_size; + uint8_t read_mac_secret[EVP_MAX_MD_SIZE]; + uint8_t write_sequence[8]; + int write_mac_secret_size; + uint8_t write_mac_secret[EVP_MAX_MD_SIZE]; + + uint8_t server_random[SSL3_RANDOM_SIZE]; + uint8_t client_random[SSL3_RANDOM_SIZE]; + + /* flags for countermeasure against known-IV weakness */ + int need_record_splitting; + + /* The value of 'extra' when the buffers were initialized */ + int init_extra; + + /* have_version is true if the connection's final version is known. Otherwise + * the version has not been negotiated yet. */ + char have_version; + + /* initial_handshake_complete is true if the initial handshake has + * completed. */ + char initial_handshake_complete; + + /* sniff_buffer is used by the server in the initial handshake to read a + * V2ClientHello before the record layer is initialized. */ + BUF_MEM *sniff_buffer; + size_t sniff_buffer_len; + + SSL3_BUFFER rbuf; /* read IO goes into here */ + SSL3_BUFFER wbuf; /* write IO goes into here */ + + SSL3_RECORD rrec; /* each decoded record goes in here */ + + /* storage for Handshake protocol data received but not yet processed by + * ssl3_read_bytes: */ + uint8_t handshake_fragment[4]; + unsigned int handshake_fragment_len; + + /* partial write - check the numbers match */ + unsigned int wnum; /* number of bytes sent so far */ + int wpend_tot; /* number bytes written */ + int wpend_type; + int wpend_ret; /* number of bytes submitted */ + const uint8_t *wpend_buf; + + /* handshake_buffer, if non-NULL, contains the handshake transcript. */ + BUF_MEM *handshake_buffer; + /* handshake_hash, if initialized with an |EVP_MD|, maintains the handshake + * hash. For TLS 1.1 and below, it is the SHA-1 half. */ + EVP_MD_CTX handshake_hash; + /* handshake_md5, if initialized with an |EVP_MD|, maintains the MD5 half of + * the handshake hash for TLS 1.1 and below. */ + EVP_MD_CTX handshake_md5; + + /* this is set whenerver we see a change_cipher_spec message come in when we + * are not looking for one */ + int change_cipher_spec; + + int warn_alert; + int fatal_alert; + /* we allow one fatal and one warning alert to be outstanding, send close + * alert via the warning alert */ + int alert_dispatch; + uint8_t send_alert[2]; + + int total_renegotiations; + + /* empty_record_count is the number of consecutive empty records received. */ + uint8_t empty_record_count; + + /* warning_alert_count is the number of consecutive warning alerts + * received. */ + uint8_t warning_alert_count; + + /* State pertaining to the pending handshake. + * + * TODO(davidben): State is current spread all over the place. Move + * pending handshake state here so it can be managed separately from + * established connection state in case of renegotiations. */ + struct { + /* actually only need to be 16+20 for SSLv3 and 12 for TLS */ + uint8_t finish_md[EVP_MAX_MD_SIZE * 2]; + int finish_md_len; + uint8_t peer_finish_md[EVP_MAX_MD_SIZE * 2]; + int peer_finish_md_len; + + unsigned long message_size; + int message_type; + + /* used to hold the new cipher we are going to use */ + const SSL_CIPHER *new_cipher; + DH *dh; + + EC_KEY *ecdh; /* holds short lived ECDH key */ + + /* used when SSL_ST_FLUSH_DATA is entered */ + int next_state; + + int reuse_message; + + union { + /* sent is a bitset where the bits correspond to elements of kExtensions + * in t1_lib.c. Each bit is set if that extension was sent in a + * ClientHello. It's not used by servers. */ + uint32_t sent; + /* received is a bitset, like |sent|, but is used by servers to record + * which extensions were received from a client. */ + uint32_t received; + } extensions; + + union { + /* sent is a bitset where the bits correspond to elements of + * |client_custom_extensions| in the |SSL_CTX|. Each bit is set if that + * extension was sent in a ClientHello. It's not used by servers. */ + uint16_t sent; + /* received is a bitset, like |sent|, but is used by servers to record + * which custom extensions were received from a client. The bits here + * correspond to |server_custom_extensions|. */ + uint16_t received; + } custom_extensions; + + /* SNI extension */ + + /* should_ack_sni is used by a server and indicates that the SNI extension + * should be echoed in the ServerHello. */ + unsigned should_ack_sni:1; + + + /* Client-only: cert_req determines if a client certificate is to be sent. + * This is 0 if no client Certificate message is to be sent, 1 if there is + * a client certificate, and 2 to send an empty client Certificate + * message. */ + int cert_req; + + /* Client-only: ca_names contains the list of CAs received in a + * CertificateRequest message. */ + STACK_OF(X509_NAME) *ca_names; + + /* Client-only: certificate_types contains the set of certificate types + * received in a CertificateRequest message. */ + uint8_t *certificate_types; + size_t num_certificate_types; + + int key_block_length; + uint8_t *key_block; + + const EVP_AEAD *new_aead; + uint8_t new_mac_secret_len; + uint8_t new_fixed_iv_len; + uint8_t new_variable_iv_len; + + /* Server-only: cert_request is true if a client certificate was + * requested. */ + int cert_request; + + /* certificate_status_expected is true if OCSP stapling was negotiated and + * the server is expected to send a CertificateStatus message. */ + char certificate_status_expected; + + /* Server-only: peer_ellipticcurvelist contains the EC curve IDs advertised + * by the peer. This is only set on the server's end. The server does not + * advertise this extension to the client. */ + uint16_t *peer_ellipticcurvelist; + size_t peer_ellipticcurvelist_length; + + /* extended_master_secret indicates whether the extended master secret + * computation is used in this handshake. Note that this is different from + * whether it was used for the current session. If this is a resumption + * handshake then EMS might be negotiated in the client and server hello + * messages, but it doesn't matter if the session that's being resumed + * didn't use it to create the master secret initially. */ + char extended_master_secret; + + /* Client-only: peer_psk_identity_hint is the psk_identity_hint sent by the + * server when using a PSK key exchange. */ + char *peer_psk_identity_hint; + + /* new_mac_secret_size is unused and exists only until wpa_supplicant can + * be updated. It is only needed for EAP-FAST, which we don't support. */ + uint8_t new_mac_secret_size; + + /* Client-only: in_false_start is one if there is a pending handshake in + * False Start. The client may write data at this point. */ + char in_false_start; + } tmp; + + /* Connection binding to prevent renegotiation attacks */ + uint8_t previous_client_finished[EVP_MAX_MD_SIZE]; + uint8_t previous_client_finished_len; + uint8_t previous_server_finished[EVP_MAX_MD_SIZE]; + uint8_t previous_server_finished_len; + int send_connection_binding; /* TODOEKR */ + + /* Set if we saw the Next Protocol Negotiation extension from our peer. */ + int next_proto_neg_seen; + + /* ALPN information + * (we are in the process of transitioning from NPN to ALPN.) */ + + /* In a server these point to the selected ALPN protocol after the + * ClientHello has been processed. In a client these contain the protocol + * that the server selected once the ServerHello has been processed. */ + uint8_t *alpn_selected; + size_t alpn_selected_len; + + /* In a client, this means that the server supported Channel ID and that a + * Channel ID was sent. In a server it means that we echoed support for + * Channel IDs and that tlsext_channel_id will be valid after the + * handshake. */ + char tlsext_channel_id_valid; + /* For a server: + * If |tlsext_channel_id_valid| is true, then this contains the + * verified Channel ID from the client: a P256 point, (x,y), where + * each are big-endian values. */ + uint8_t tlsext_channel_id[64]; +} SSL3_STATE; + +/* SSLv3 */ +/* client */ +/* extra state */ +#define SSL3_ST_CW_FLUSH (0x100 | SSL_ST_CONNECT) +#define SSL3_ST_FALSE_START (0x101 | SSL_ST_CONNECT) +/* write to server */ +#define SSL3_ST_CW_CLNT_HELLO_A (0x110 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CLNT_HELLO_B (0x111 | SSL_ST_CONNECT) +/* read from server */ +#define SSL3_ST_CR_SRVR_HELLO_A (0x120 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_HELLO_B (0x121 | SSL_ST_CONNECT) +#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A (0x126 | SSL_ST_CONNECT) +#define DTLS1_ST_CR_HELLO_VERIFY_REQUEST_B (0x127 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_A (0x130 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_B (0x131 | SSL_ST_CONNECT) +#define SSL3_ST_CR_KEY_EXCH_A (0x140 | SSL_ST_CONNECT) +#define SSL3_ST_CR_KEY_EXCH_B (0x141 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_REQ_A (0x150 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_REQ_B (0x151 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_DONE_A (0x160 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SRVR_DONE_B (0x161 | SSL_ST_CONNECT) +/* write to server */ +#define SSL3_ST_CW_CERT_A (0x170 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_B (0x171 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_C (0x172 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_D (0x173 | SSL_ST_CONNECT) +#define SSL3_ST_CW_KEY_EXCH_A (0x180 | SSL_ST_CONNECT) +#define SSL3_ST_CW_KEY_EXCH_B (0x181 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_VRFY_A (0x190 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_VRFY_B (0x191 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CERT_VRFY_C (0x192 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANGE_A (0x1A0 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANGE_B (0x1A1 | SSL_ST_CONNECT) +#define SSL3_ST_CW_NEXT_PROTO_A (0x200 | SSL_ST_CONNECT) +#define SSL3_ST_CW_NEXT_PROTO_B (0x201 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANNEL_ID_A (0x220 | SSL_ST_CONNECT) +#define SSL3_ST_CW_CHANNEL_ID_B (0x221 | SSL_ST_CONNECT) +#define SSL3_ST_CW_FINISHED_A (0x1B0 | SSL_ST_CONNECT) +#define SSL3_ST_CW_FINISHED_B (0x1B1 | SSL_ST_CONNECT) +/* read from server */ +#define SSL3_ST_CR_CHANGE (0x1C0 | SSL_ST_CONNECT) +#define SSL3_ST_CR_FINISHED_A (0x1D0 | SSL_ST_CONNECT) +#define SSL3_ST_CR_FINISHED_B (0x1D1 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SESSION_TICKET_A (0x1E0 | SSL_ST_CONNECT) +#define SSL3_ST_CR_SESSION_TICKET_B (0x1E1 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_STATUS_A (0x1F0 | SSL_ST_CONNECT) +#define SSL3_ST_CR_CERT_STATUS_B (0x1F1 | SSL_ST_CONNECT) + +/* server */ +/* extra state */ +#define SSL3_ST_SW_FLUSH (0x100 | SSL_ST_ACCEPT) +/* read from client */ +#define SSL3_ST_SR_INITIAL_BYTES (0x240 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_V2_CLIENT_HELLO (0x241 | SSL_ST_ACCEPT) +/* Do not change the number values, they do matter */ +#define SSL3_ST_SR_CLNT_HELLO_A (0x110 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_B (0x111 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_C (0x112 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CLNT_HELLO_D (0x115 | SSL_ST_ACCEPT) +/* write to client */ +#define SSL3_ST_SW_HELLO_REQ_A (0x120 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_HELLO_REQ_B (0x121 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_HELLO_REQ_C (0x122 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_HELLO_A (0x130 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_HELLO_B (0x131 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_A (0x140 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_B (0x141 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_A (0x150 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_B (0x151 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_C (0x152 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_KEY_EXCH_D (0x153 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_REQ_A (0x160 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_REQ_B (0x161 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_DONE_A (0x170 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SRVR_DONE_B (0x171 | SSL_ST_ACCEPT) +/* read from client */ +#define SSL3_ST_SR_CERT_A (0x180 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_B (0x181 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_KEY_EXCH_A (0x190 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_KEY_EXCH_B (0x191 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_VRFY_A (0x1A0 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CERT_VRFY_B (0x1A1 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CHANGE (0x1B0 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_NEXT_PROTO_A (0x210 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_NEXT_PROTO_B (0x211 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CHANNEL_ID_A (0x230 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_CHANNEL_ID_B (0x231 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_FINISHED_A (0x1C0 | SSL_ST_ACCEPT) +#define SSL3_ST_SR_FINISHED_B (0x1C1 | SSL_ST_ACCEPT) + +/* write to client */ +#define SSL3_ST_SW_CHANGE_A (0x1D0 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CHANGE_B (0x1D1 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_FINISHED_A (0x1E0 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_FINISHED_B (0x1E1 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SESSION_TICKET_A (0x1F0 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SESSION_TICKET_B (0x1F1 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_STATUS_A (0x200 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_CERT_STATUS_B (0x201 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SUPPLEMENTAL_DATA_A (0x220 | SSL_ST_ACCEPT) +#define SSL3_ST_SW_SUPPLEMENTAL_DATA_B (0x221 | SSL_ST_ACCEPT) + +#define SSL3_MT_HELLO_REQUEST 0 +#define SSL3_MT_CLIENT_HELLO 1 +#define SSL3_MT_SERVER_HELLO 2 +#define SSL3_MT_NEWSESSION_TICKET 4 +#define SSL3_MT_CERTIFICATE 11 +#define SSL3_MT_SERVER_KEY_EXCHANGE 12 +#define SSL3_MT_CERTIFICATE_REQUEST 13 +#define SSL3_MT_SERVER_DONE 14 +#define SSL3_MT_CERTIFICATE_VERIFY 15 +#define SSL3_MT_CLIENT_KEY_EXCHANGE 16 +#define SSL3_MT_FINISHED 20 +#define SSL3_MT_CERTIFICATE_STATUS 22 +#define SSL3_MT_SUPPLEMENTAL_DATA 23 +#define SSL3_MT_NEXT_PROTO 67 +#define SSL3_MT_ENCRYPTED_EXTENSIONS 203 +#define DTLS1_MT_HELLO_VERIFY_REQUEST 3 + + +#define SSL3_MT_CCS 1 + +/* These are used when changing over to a new cipher */ +#define SSL3_CC_READ 0x01 +#define SSL3_CC_WRITE 0x02 +#define SSL3_CC_CLIENT 0x10 +#define SSL3_CC_SERVER 0x20 +#define SSL3_CHANGE_CIPHER_CLIENT_WRITE (SSL3_CC_CLIENT | SSL3_CC_WRITE) +#define SSL3_CHANGE_CIPHER_SERVER_READ (SSL3_CC_SERVER | SSL3_CC_READ) +#define SSL3_CHANGE_CIPHER_CLIENT_READ (SSL3_CC_CLIENT | SSL3_CC_READ) +#define SSL3_CHANGE_CIPHER_SERVER_WRITE (SSL3_CC_SERVER | SSL3_CC_WRITE) + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/TMessagesProj/jni/boringssl/include/openssl/stack.h b/TMessagesProj/jni/boringssl/include/openssl/stack.h new file mode 100644 index 00000000..b600b43d --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/stack.h @@ -0,0 +1,298 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_STACK_H +#define OPENSSL_HEADER_STACK_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* A stack, in OpenSSL, is an array of pointers. They are the most commonly + * used collection object. + * + * This file defines macros for type safe use of the stack functions. A stack + * of a specific type of object has type |STACK_OF(type)|. This can be defined + * (once) with |DEFINE_STACK_OF(type)| and declared where needed with + * |DECLARE_STACK_OF(type)|. For example: + * + * struct foo { + * int bar; + * }; + * + * DEFINE_STACK_OF(struct foo); + * + * Although note that the stack will contain /pointers/ to |foo|. + * + * A macro will be defined for each of the sk_* functions below. For + * STACK_OF(foo), the macros would be sk_foo_new, sk_foo_pop etc. */ + + +/* stack_cmp_func is a comparison function that returns a value < 0, 0 or > 0 + * if |*a| is less than, equal to or greater than |*b|, respectively. Note the + * extra indirection - the function is given a pointer to a pointer to the + * element. This differs from the usual qsort/bsearch comparison function. */ +typedef int (*stack_cmp_func)(const void **a, const void **b); + +/* stack_st contains an array of pointers. It is not designed to be used + * directly, rather the wrapper macros should be used. */ +typedef struct stack_st { + /* num contains the number of valid pointers in |data|. */ + size_t num; + void **data; + /* sorted is non-zero if the values pointed to by |data| are in ascending + * order, based on |comp|. */ + size_t sorted; + /* num_alloc contains the number of pointers allocated in the buffer pointed + * to by |data|, which may be larger than |num|. */ + size_t num_alloc; + /* comp is an optional comparison function. */ + stack_cmp_func comp; +} _STACK; + + +#define STACK_OF(type) struct stack_st_##type + +#define DECLARE_STACK_OF(type) STACK_OF(type); + +/* The make_macros.sh script in this directory parses the following lines and + * generates the stack_macros.h file that contains macros for the following + * types of stacks: + * + * STACK_OF:ACCESS_DESCRIPTION + * STACK_OF:ASN1_ADB_TABLE + * STACK_OF:ASN1_GENERALSTRING + * STACK_OF:ASN1_INTEGER + * STACK_OF:ASN1_OBJECT + * STACK_OF:ASN1_STRING_TABLE + * STACK_OF:ASN1_TYPE + * STACK_OF:ASN1_VALUE + * STACK_OF:BIO + * STACK_OF:BY_DIR_ENTRY + * STACK_OF:BY_DIR_HASH + * STACK_OF:CONF_VALUE + * STACK_OF:CRYPTO_EX_DATA_FUNCS + * STACK_OF:DIST_POINT + * STACK_OF:GENERAL_NAME + * STACK_OF:GENERAL_NAMES + * STACK_OF:GENERAL_SUBTREE + * STACK_OF:MIME_HEADER + * STACK_OF:PKCS7_RECIP_INFO + * STACK_OF:PKCS7_SIGNER_INFO + * STACK_OF:POLICYINFO + * STACK_OF:POLICYQUALINFO + * STACK_OF:POLICY_MAPPING + * STACK_OF:RSA_additional_prime + * STACK_OF:SSL_COMP + * STACK_OF:SSL_CUSTOM_EXTENSION + * STACK_OF:STACK_OF_X509_NAME_ENTRY + * STACK_OF:SXNETID + * STACK_OF:X509 + * STACK_OF:X509V3_EXT_METHOD + * STACK_OF:X509_ALGOR + * STACK_OF:X509_ATTRIBUTE + * STACK_OF:X509_CRL + * STACK_OF:X509_EXTENSION + * STACK_OF:X509_INFO + * STACK_OF:X509_LOOKUP + * STACK_OF:X509_NAME + * STACK_OF:X509_NAME_ENTRY + * STACK_OF:X509_OBJECT + * STACK_OF:X509_POLICY_DATA + * STACK_OF:X509_POLICY_NODE + * STACK_OF:X509_PURPOSE + * STACK_OF:X509_REVOKED + * STACK_OF:X509_TRUST + * STACK_OF:X509_VERIFY_PARAM + * STACK_OF:void + * + * Some stacks contain only const structures, so the stack should return const + * pointers to retain type-checking. + * + * CONST_STACK_OF:SRTP_PROTECTION_PROFILE + * CONST_STACK_OF:SSL_CIPHER */ + + +/* Some stacks are special because, although we would like STACK_OF(char *), + * that would actually be a stack of pointers to char*, but we just want to + * point to the string directly. In this case we call them "special" and use + * |DEFINE_SPECIAL_STACK_OF(type)| */ +#define DEFINE_SPECIAL_STACK_OF(type, inner) \ + STACK_OF(type) { _STACK special_stack; }; \ + OPENSSL_COMPILE_ASSERT(sizeof(type) == sizeof(void *), \ + special_stack_of_non_pointer_##type); + +typedef char *OPENSSL_STRING; + +DEFINE_SPECIAL_STACK_OF(OPENSSL_STRING, char) +DEFINE_SPECIAL_STACK_OF(OPENSSL_BLOCK, uint8_t) + +/* The make_macros.sh script in this directory parses the following lines and + * generates the stack_macros.h file that contains macros for the following + * types of stacks: + * + * SPECIAL_STACK_OF:OPENSSL_STRING + * SPECIAL_STACK_OF:OPENSSL_BLOCK */ + +#define IN_STACK_H +#include +#undef IN_STACK_H + + +/* These are the raw stack functions, you shouldn't be using them. Rather you + * should be using the type stack macros implemented above. */ + +/* sk_new creates a new, empty stack with the given comparison function, which + * may be zero. It returns the new stack or NULL on allocation failure. */ +OPENSSL_EXPORT _STACK *sk_new(stack_cmp_func comp); + +/* sk_new_null creates a new, empty stack. It returns the new stack or NULL on + * allocation failure. */ +OPENSSL_EXPORT _STACK *sk_new_null(void); + +/* sk_num returns the number of elements in |s|. */ +OPENSSL_EXPORT size_t sk_num(const _STACK *sk); + +/* sk_zero resets |sk| to the empty state but does nothing to free the + * individual elements themselves. */ +OPENSSL_EXPORT void sk_zero(_STACK *sk); + +/* sk_value returns the |i|th pointer in |sk|, or NULL if |i| is out of + * range. */ +OPENSSL_EXPORT void *sk_value(const _STACK *sk, size_t i); + +/* sk_set sets the |i|th pointer in |sk| to |p| and returns |p|. If |i| is out + * of range, it returns NULL. */ +OPENSSL_EXPORT void *sk_set(_STACK *sk, size_t i, void *p); + +/* sk_free frees the given stack and array of pointers, but does nothing to + * free the individual elements. Also see |sk_pop_free|. */ +OPENSSL_EXPORT void sk_free(_STACK *sk); + +/* sk_pop_free calls |free_func| on each element in the stack and then frees + * the stack itself. */ +OPENSSL_EXPORT void sk_pop_free(_STACK *sk, void (*free_func)(void *)); + +/* sk_insert inserts |p| into the stack at index |where|, moving existing + * elements if needed. It returns the length of the new stack, or zero on + * error. */ +OPENSSL_EXPORT size_t sk_insert(_STACK *sk, void *p, size_t where); + +/* sk_delete removes the pointer at index |where|, moving other elements down + * if needed. It returns the removed pointer, or NULL if |where| is out of + * range. */ +OPENSSL_EXPORT void *sk_delete(_STACK *sk, size_t where); + +/* sk_delete_ptr removes, at most, one instance of |p| from the stack based on + * pointer equality. If an instance of |p| is found then |p| is returned, + * otherwise it returns NULL. */ +OPENSSL_EXPORT void *sk_delete_ptr(_STACK *sk, void *p); + +/* sk_find returns the first value in the stack equal to |p|. If a comparison + * function has been set on the stack, then equality is defined by it and the + * stack will be sorted if need be so that a binary search can be used. + * Otherwise pointer equality is used. If a matching element is found, its + * index is written to |*out_index| (if |out_index| is not NULL) and one is + * returned. Otherwise zero is returned. */ +OPENSSL_EXPORT int sk_find(_STACK *sk, size_t *out_index, void *p); + +/* sk_shift removes and returns the first element in the stack, or returns NULL + * if the stack is empty. */ +OPENSSL_EXPORT void *sk_shift(_STACK *sk); + +/* sk_push appends |p| to the stack and returns the length of the new stack, or + * 0 on allocation failure. */ +OPENSSL_EXPORT size_t sk_push(_STACK *sk, void *p); + +/* sk_pop returns and removes the last element on the stack, or NULL if the + * stack is empty. */ +OPENSSL_EXPORT void *sk_pop(_STACK *sk); + +/* sk_dup performs a shallow copy of a stack and returns the new stack, or NULL + * on error. */ +OPENSSL_EXPORT _STACK *sk_dup(const _STACK *sk); + +/* sk_sort sorts the elements of |sk| into ascending order based on the + * comparison function. The stack maintains a |sorted| flag and sorting an + * already sorted stack is a no-op. */ +OPENSSL_EXPORT void sk_sort(_STACK *sk); + +/* sk_is_sorted returns one if |sk| is known to be sorted and zero + * otherwise. */ +OPENSSL_EXPORT int sk_is_sorted(const _STACK *sk); + +/* sk_set_cmp_func sets the comparison function to be used by |sk| and returns + * the previous one. */ +OPENSSL_EXPORT stack_cmp_func sk_set_cmp_func(_STACK *sk, stack_cmp_func comp); + +/* sk_deep_copy performs a copy of |sk| and of each of the non-NULL elements in + * |sk| by using |copy_func|. If an error occurs, |free_func| is used to free + * any copies already made and NULL is returned. */ +OPENSSL_EXPORT _STACK *sk_deep_copy(const _STACK *sk, + void *(*copy_func)(void *), + void (*free_func)(void *)); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_STACK_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/stack_macros.h b/TMessagesProj/jni/boringssl/include/openssl/stack_macros.h new file mode 100644 index 00000000..08097af3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/stack_macros.h @@ -0,0 +1,4190 @@ +/* Copyright (c) 2014, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#if !defined(IN_STACK_H) +#error "Don't include this file directly. Include stack.h." +#endif + +/* ACCESS_DESCRIPTION */ +#define sk_ACCESS_DESCRIPTION_new(comp) \ + ((STACK_OF(ACCESS_DESCRIPTION) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const ACCESS_DESCRIPTION **a, const ACCESS_DESCRIPTION **b), \ + comp))) + +#define sk_ACCESS_DESCRIPTION_new_null() \ + ((STACK_OF(ACCESS_DESCRIPTION) *)sk_new_null()) + +#define sk_ACCESS_DESCRIPTION_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)) + +#define sk_ACCESS_DESCRIPTION_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)); + +#define sk_ACCESS_DESCRIPTION_value(sk, i) \ + ((ACCESS_DESCRIPTION *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk), (i))) + +#define sk_ACCESS_DESCRIPTION_set(sk, i, p) \ + ((ACCESS_DESCRIPTION *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), (i), \ + CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p))) + +#define sk_ACCESS_DESCRIPTION_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)) + +#define sk_ACCESS_DESCRIPTION_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ACCESS_DESCRIPTION *), \ + free_func)) + +#define sk_ACCESS_DESCRIPTION_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p), (where)) + +#define sk_ACCESS_DESCRIPTION_delete(sk, where) \ + ((ACCESS_DESCRIPTION *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), (where))) + +#define sk_ACCESS_DESCRIPTION_delete_ptr(sk, p) \ + ((ACCESS_DESCRIPTION *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p))) + +#define sk_ACCESS_DESCRIPTION_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + (out_index), CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p)) + +#define sk_ACCESS_DESCRIPTION_shift(sk) \ + ((ACCESS_DESCRIPTION *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk))) + +#define sk_ACCESS_DESCRIPTION_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void *, ACCESS_DESCRIPTION *, p)) + +#define sk_ACCESS_DESCRIPTION_pop(sk) \ + ((ACCESS_DESCRIPTION *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk))) + +#define sk_ACCESS_DESCRIPTION_dup(sk) \ + ((STACK_OF(ACCESS_DESCRIPTION) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk))) + +#define sk_ACCESS_DESCRIPTION_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk)) + +#define sk_ACCESS_DESCRIPTION_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk)) + +#define sk_ACCESS_DESCRIPTION_set_cmp_func(sk, comp) \ + ((int (*)(const ACCESS_DESCRIPTION **a, const ACCESS_DESCRIPTION **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const ACCESS_DESCRIPTION **a, \ + const ACCESS_DESCRIPTION **b), \ + comp))) + +#define sk_ACCESS_DESCRIPTION_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ACCESS_DESCRIPTION) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ACCESS_DESCRIPTION) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + ACCESS_DESCRIPTION *(*)(ACCESS_DESCRIPTION *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ACCESS_DESCRIPTION *), \ + free_func))) + +/* ASN1_ADB_TABLE */ +#define sk_ASN1_ADB_TABLE_new(comp) \ + ((STACK_OF(ASN1_ADB_TABLE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const ASN1_ADB_TABLE **a, const ASN1_ADB_TABLE **b), comp))) + +#define sk_ASN1_ADB_TABLE_new_null() ((STACK_OF(ASN1_ADB_TABLE) *)sk_new_null()) + +#define sk_ASN1_ADB_TABLE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)) + +#define sk_ASN1_ADB_TABLE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)); + +#define sk_ASN1_ADB_TABLE_value(sk, i) \ + ((ASN1_ADB_TABLE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk), (i))) + +#define sk_ASN1_ADB_TABLE_set(sk, i, p) \ + ((ASN1_ADB_TABLE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p))) + +#define sk_ASN1_ADB_TABLE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)) + +#define sk_ASN1_ADB_TABLE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_ADB_TABLE *), free_func)) + +#define sk_ASN1_ADB_TABLE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p), (where)) + +#define sk_ASN1_ADB_TABLE_delete(sk, where) \ + ((ASN1_ADB_TABLE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), (where))) + +#define sk_ASN1_ADB_TABLE_delete_ptr(sk, p) \ + ((ASN1_ADB_TABLE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p))) + +#define sk_ASN1_ADB_TABLE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p)) + +#define sk_ASN1_ADB_TABLE_shift(sk) \ + ((ASN1_ADB_TABLE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk))) + +#define sk_ASN1_ADB_TABLE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_ADB_TABLE *, p)) + +#define sk_ASN1_ADB_TABLE_pop(sk) \ + ((ASN1_ADB_TABLE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk))) + +#define sk_ASN1_ADB_TABLE_dup(sk) \ + ((STACK_OF(ASN1_ADB_TABLE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk))) + +#define sk_ASN1_ADB_TABLE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk)) + +#define sk_ASN1_ADB_TABLE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk)) + +#define sk_ASN1_ADB_TABLE_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_ADB_TABLE **a, const ASN1_ADB_TABLE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const ASN1_ADB_TABLE **a, \ + const ASN1_ADB_TABLE **b), \ + comp))) + +#define sk_ASN1_ADB_TABLE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_ADB_TABLE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_ADB_TABLE) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_ADB_TABLE *(*)(ASN1_ADB_TABLE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_ADB_TABLE *), free_func))) + +/* ASN1_GENERALSTRING */ +#define sk_ASN1_GENERALSTRING_new(comp) \ + ((STACK_OF(ASN1_GENERALSTRING) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const ASN1_GENERALSTRING **a, const ASN1_GENERALSTRING **b), \ + comp))) + +#define sk_ASN1_GENERALSTRING_new_null() \ + ((STACK_OF(ASN1_GENERALSTRING) *)sk_new_null()) + +#define sk_ASN1_GENERALSTRING_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)) + +#define sk_ASN1_GENERALSTRING_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)); + +#define sk_ASN1_GENERALSTRING_value(sk, i) \ + ((ASN1_GENERALSTRING *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk), (i))) + +#define sk_ASN1_GENERALSTRING_set(sk, i, p) \ + ((ASN1_GENERALSTRING *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_GENERALSTRING *, p))) + +#define sk_ASN1_GENERALSTRING_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)) + +#define sk_ASN1_GENERALSTRING_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_GENERALSTRING *), \ + free_func)) + +#define sk_ASN1_GENERALSTRING_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void *, ASN1_GENERALSTRING *, p), (where)) + +#define sk_ASN1_GENERALSTRING_delete(sk, where) \ + ((ASN1_GENERALSTRING *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), (where))) + +#define sk_ASN1_GENERALSTRING_delete_ptr(sk, p) \ + ((ASN1_GENERALSTRING *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void *, ASN1_GENERALSTRING *, p))) + +#define sk_ASN1_GENERALSTRING_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + (out_index), CHECKED_CAST(void *, ASN1_GENERALSTRING *, p)) + +#define sk_ASN1_GENERALSTRING_shift(sk) \ + ((ASN1_GENERALSTRING *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk))) + +#define sk_ASN1_GENERALSTRING_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void *, ASN1_GENERALSTRING *, p)) + +#define sk_ASN1_GENERALSTRING_pop(sk) \ + ((ASN1_GENERALSTRING *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk))) + +#define sk_ASN1_GENERALSTRING_dup(sk) \ + ((STACK_OF(ASN1_GENERALSTRING) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk))) + +#define sk_ASN1_GENERALSTRING_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk)) + +#define sk_ASN1_GENERALSTRING_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk)) + +#define sk_ASN1_GENERALSTRING_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_GENERALSTRING **a, const ASN1_GENERALSTRING **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const ASN1_GENERALSTRING **a, \ + const ASN1_GENERALSTRING **b), \ + comp))) + +#define sk_ASN1_GENERALSTRING_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_GENERALSTRING) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_GENERALSTRING) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + ASN1_GENERALSTRING *(*)(ASN1_GENERALSTRING *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_GENERALSTRING *), \ + free_func))) + +/* ASN1_INTEGER */ +#define sk_ASN1_INTEGER_new(comp) \ + ((STACK_OF(ASN1_INTEGER) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const ASN1_INTEGER **a, const ASN1_INTEGER **b), \ + comp))) + +#define sk_ASN1_INTEGER_new_null() ((STACK_OF(ASN1_INTEGER) *)sk_new_null()) + +#define sk_ASN1_INTEGER_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)) + +#define sk_ASN1_INTEGER_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)); + +#define sk_ASN1_INTEGER_value(sk, i) \ + ((ASN1_INTEGER *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk), (i))) + +#define sk_ASN1_INTEGER_set(sk, i, p) \ + ((ASN1_INTEGER *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p))) + +#define sk_ASN1_INTEGER_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)) + +#define sk_ASN1_INTEGER_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_INTEGER *), free_func)) + +#define sk_ASN1_INTEGER_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p), (where)) + +#define sk_ASN1_INTEGER_delete(sk, where) \ + ((ASN1_INTEGER *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), (where))) + +#define sk_ASN1_INTEGER_delete_ptr(sk, p) \ + ((ASN1_INTEGER *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p))) + +#define sk_ASN1_INTEGER_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p)) + +#define sk_ASN1_INTEGER_shift(sk) \ + ((ASN1_INTEGER *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk))) + +#define sk_ASN1_INTEGER_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void *, ASN1_INTEGER *, p)) + +#define sk_ASN1_INTEGER_pop(sk) \ + ((ASN1_INTEGER *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk))) + +#define sk_ASN1_INTEGER_dup(sk) \ + ((STACK_OF(ASN1_INTEGER) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk))) + +#define sk_ASN1_INTEGER_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk)) + +#define sk_ASN1_INTEGER_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_INTEGER) *, sk)) + +#define sk_ASN1_INTEGER_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_INTEGER **a, const ASN1_INTEGER **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_INTEGER **a, const ASN1_INTEGER **b), \ + comp))) + +#define sk_ASN1_INTEGER_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_INTEGER) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_INTEGER) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_INTEGER *(*)(ASN1_INTEGER *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_INTEGER *), free_func))) + +/* ASN1_OBJECT */ +#define sk_ASN1_OBJECT_new(comp) \ + ((STACK_OF(ASN1_OBJECT) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const ASN1_OBJECT **a, const ASN1_OBJECT **b), \ + comp))) + +#define sk_ASN1_OBJECT_new_null() ((STACK_OF(ASN1_OBJECT) *)sk_new_null()) + +#define sk_ASN1_OBJECT_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)) + +#define sk_ASN1_OBJECT_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)); + +#define sk_ASN1_OBJECT_value(sk, i) \ + ((ASN1_OBJECT *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk), (i))) + +#define sk_ASN1_OBJECT_set(sk, i, p) \ + ((ASN1_OBJECT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + (i), CHECKED_CAST(void *, ASN1_OBJECT *, p))) + +#define sk_ASN1_OBJECT_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)) + +#define sk_ASN1_OBJECT_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_OBJECT *), free_func)) + +#define sk_ASN1_OBJECT_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void *, ASN1_OBJECT *, p), (where)) + +#define sk_ASN1_OBJECT_delete(sk, where) \ + ((ASN1_OBJECT *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), (where))) + +#define sk_ASN1_OBJECT_delete_ptr(sk, p) \ + ((ASN1_OBJECT *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void *, ASN1_OBJECT *, p))) + +#define sk_ASN1_OBJECT_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_OBJECT *, p)) + +#define sk_ASN1_OBJECT_shift(sk) \ + ((ASN1_OBJECT *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk))) + +#define sk_ASN1_OBJECT_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void *, ASN1_OBJECT *, p)) + +#define sk_ASN1_OBJECT_pop(sk) \ + ((ASN1_OBJECT *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk))) + +#define sk_ASN1_OBJECT_dup(sk) \ + ((STACK_OF(ASN1_OBJECT) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk))) + +#define sk_ASN1_OBJECT_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk)) + +#define sk_ASN1_OBJECT_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_OBJECT) *, sk)) + +#define sk_ASN1_OBJECT_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_OBJECT **a, const ASN1_OBJECT **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_OBJECT **a, const ASN1_OBJECT **b), \ + comp))) + +#define sk_ASN1_OBJECT_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_OBJECT) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_OBJECT) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_OBJECT *(*)(ASN1_OBJECT *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_OBJECT *), free_func))) + +/* ASN1_STRING_TABLE */ +#define sk_ASN1_STRING_TABLE_new(comp) \ + ((STACK_OF(ASN1_STRING_TABLE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const ASN1_STRING_TABLE **a, const ASN1_STRING_TABLE **b), \ + comp))) + +#define sk_ASN1_STRING_TABLE_new_null() \ + ((STACK_OF(ASN1_STRING_TABLE) *)sk_new_null()) + +#define sk_ASN1_STRING_TABLE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)) + +#define sk_ASN1_STRING_TABLE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)); + +#define sk_ASN1_STRING_TABLE_value(sk, i) \ + ((ASN1_STRING_TABLE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk), (i))) + +#define sk_ASN1_STRING_TABLE_set(sk, i, p) \ + ((ASN1_STRING_TABLE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_STRING_TABLE *, p))) + +#define sk_ASN1_STRING_TABLE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)) + +#define sk_ASN1_STRING_TABLE_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_STRING_TABLE *), \ + free_func)) + +#define sk_ASN1_STRING_TABLE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_STRING_TABLE *, p), (where)) + +#define sk_ASN1_STRING_TABLE_delete(sk, where) \ + ((ASN1_STRING_TABLE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), (where))) + +#define sk_ASN1_STRING_TABLE_delete_ptr(sk, p) \ + ((ASN1_STRING_TABLE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_STRING_TABLE *, p))) + +#define sk_ASN1_STRING_TABLE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + (out_index), CHECKED_CAST(void *, ASN1_STRING_TABLE *, p)) + +#define sk_ASN1_STRING_TABLE_shift(sk) \ + ((ASN1_STRING_TABLE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk))) + +#define sk_ASN1_STRING_TABLE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void *, ASN1_STRING_TABLE *, p)) + +#define sk_ASN1_STRING_TABLE_pop(sk) \ + ((ASN1_STRING_TABLE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk))) + +#define sk_ASN1_STRING_TABLE_dup(sk) \ + ((STACK_OF(ASN1_STRING_TABLE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk))) + +#define sk_ASN1_STRING_TABLE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk)) + +#define sk_ASN1_STRING_TABLE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk)) + +#define sk_ASN1_STRING_TABLE_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_STRING_TABLE **a, const ASN1_STRING_TABLE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const ASN1_STRING_TABLE **a, \ + const ASN1_STRING_TABLE **b), \ + comp))) + +#define sk_ASN1_STRING_TABLE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_STRING_TABLE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_STRING_TABLE) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + ASN1_STRING_TABLE *(*)(ASN1_STRING_TABLE *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_STRING_TABLE *), \ + free_func))) + +/* ASN1_TYPE */ +#define sk_ASN1_TYPE_new(comp) \ + ((STACK_OF(ASN1_TYPE) *)sk_new( \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_TYPE **a, const ASN1_TYPE **b), comp))) + +#define sk_ASN1_TYPE_new_null() ((STACK_OF(ASN1_TYPE) *)sk_new_null()) + +#define sk_ASN1_TYPE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)) + +#define sk_ASN1_TYPE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)); + +#define sk_ASN1_TYPE_value(sk, i) \ + ((ASN1_TYPE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk), (i))) + +#define sk_ASN1_TYPE_set(sk, i, p) \ + ((ASN1_TYPE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), (i), \ + CHECKED_CAST(void *, ASN1_TYPE *, p))) + +#define sk_ASN1_TYPE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)) + +#define sk_ASN1_TYPE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_TYPE *), free_func)) + +#define sk_ASN1_TYPE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void *, ASN1_TYPE *, p), (where)) + +#define sk_ASN1_TYPE_delete(sk, where) \ + ((ASN1_TYPE *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + (where))) + +#define sk_ASN1_TYPE_delete_ptr(sk, p) \ + ((ASN1_TYPE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void *, ASN1_TYPE *, p))) + +#define sk_ASN1_TYPE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_TYPE *, p)) + +#define sk_ASN1_TYPE_shift(sk) \ + ((ASN1_TYPE *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk))) + +#define sk_ASN1_TYPE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void *, ASN1_TYPE *, p)) + +#define sk_ASN1_TYPE_pop(sk) \ + ((ASN1_TYPE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk))) + +#define sk_ASN1_TYPE_dup(sk) \ + ((STACK_OF(ASN1_TYPE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk))) + +#define sk_ASN1_TYPE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk)) + +#define sk_ASN1_TYPE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_TYPE) *, sk)) + +#define sk_ASN1_TYPE_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_TYPE **a, const ASN1_TYPE **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_TYPE **a, const ASN1_TYPE **b), comp))) + +#define sk_ASN1_TYPE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_TYPE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_TYPE) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_TYPE *(*)(ASN1_TYPE *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_TYPE *), free_func))) + +/* ASN1_VALUE */ +#define sk_ASN1_VALUE_new(comp) \ + ((STACK_OF(ASN1_VALUE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const ASN1_VALUE **a, const ASN1_VALUE **b), \ + comp))) + +#define sk_ASN1_VALUE_new_null() ((STACK_OF(ASN1_VALUE) *)sk_new_null()) + +#define sk_ASN1_VALUE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)) + +#define sk_ASN1_VALUE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)); + +#define sk_ASN1_VALUE_value(sk, i) \ + ((ASN1_VALUE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk), (i))) + +#define sk_ASN1_VALUE_set(sk, i, p) \ + ((ASN1_VALUE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + (i), CHECKED_CAST(void *, ASN1_VALUE *, p))) + +#define sk_ASN1_VALUE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)) + +#define sk_ASN1_VALUE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_VALUE *), free_func)) + +#define sk_ASN1_VALUE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void *, ASN1_VALUE *, p), (where)) + +#define sk_ASN1_VALUE_delete(sk, where) \ + ((ASN1_VALUE *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + (where))) + +#define sk_ASN1_VALUE_delete_ptr(sk, p) \ + ((ASN1_VALUE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void *, ASN1_VALUE *, p))) + +#define sk_ASN1_VALUE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), (out_index), \ + CHECKED_CAST(void *, ASN1_VALUE *, p)) + +#define sk_ASN1_VALUE_shift(sk) \ + ((ASN1_VALUE *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk))) + +#define sk_ASN1_VALUE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void *, ASN1_VALUE *, p)) + +#define sk_ASN1_VALUE_pop(sk) \ + ((ASN1_VALUE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk))) + +#define sk_ASN1_VALUE_dup(sk) \ + ((STACK_OF(ASN1_VALUE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk))) + +#define sk_ASN1_VALUE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk)) + +#define sk_ASN1_VALUE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(ASN1_VALUE) *, sk)) + +#define sk_ASN1_VALUE_set_cmp_func(sk, comp) \ + ((int (*)(const ASN1_VALUE **a, const ASN1_VALUE **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const ASN1_VALUE **a, const ASN1_VALUE **b), \ + comp))) + +#define sk_ASN1_VALUE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(ASN1_VALUE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(ASN1_VALUE) *, sk), \ + CHECKED_CAST(void *(*)(void *), ASN1_VALUE *(*)(ASN1_VALUE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(ASN1_VALUE *), free_func))) + +/* BIO */ +#define sk_BIO_new(comp) \ + ((STACK_OF(BIO) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const BIO **a, const BIO **b), comp))) + +#define sk_BIO_new_null() ((STACK_OF(BIO) *)sk_new_null()) + +#define sk_BIO_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)) + +#define sk_BIO_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)); + +#define sk_BIO_value(sk, i) \ + ((BIO *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk), (i))) + +#define sk_BIO_set(sk, i, p) \ + ((BIO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), (i), \ + CHECKED_CAST(void *, BIO *, p))) + +#define sk_BIO_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)) + +#define sk_BIO_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(BIO *), free_func)) + +#define sk_BIO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void *, BIO *, p), (where)) + +#define sk_BIO_delete(sk, where) \ + ((BIO *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), (where))) + +#define sk_BIO_delete_ptr(sk, p) \ + ((BIO *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void *, BIO *, p))) + +#define sk_BIO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), (out_index), \ + CHECKED_CAST(void *, BIO *, p)) + +#define sk_BIO_shift(sk) \ + ((BIO *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk))) + +#define sk_BIO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void *, BIO *, p)) + +#define sk_BIO_pop(sk) \ + ((BIO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk))) + +#define sk_BIO_dup(sk) \ + ((STACK_OF(BIO) *)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk))) + +#define sk_BIO_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk)) + +#define sk_BIO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BIO) *, sk)) + +#define sk_BIO_set_cmp_func(sk, comp) \ + ((int (*)(const BIO **a, const BIO **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(BIO) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const BIO **a, const BIO **b), \ + comp))) + +#define sk_BIO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(BIO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(BIO) *, sk), \ + CHECKED_CAST(void *(*)(void *), BIO *(*)(BIO *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(BIO *), free_func))) + +/* BY_DIR_ENTRY */ +#define sk_BY_DIR_ENTRY_new(comp) \ + ((STACK_OF(BY_DIR_ENTRY) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const BY_DIR_ENTRY **a, const BY_DIR_ENTRY **b), \ + comp))) + +#define sk_BY_DIR_ENTRY_new_null() ((STACK_OF(BY_DIR_ENTRY) *)sk_new_null()) + +#define sk_BY_DIR_ENTRY_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)) + +#define sk_BY_DIR_ENTRY_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)); + +#define sk_BY_DIR_ENTRY_value(sk, i) \ + ((BY_DIR_ENTRY *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk), (i))) + +#define sk_BY_DIR_ENTRY_set(sk, i, p) \ + ((BY_DIR_ENTRY *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), (i), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p))) + +#define sk_BY_DIR_ENTRY_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)) + +#define sk_BY_DIR_ENTRY_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_ENTRY *), free_func)) + +#define sk_BY_DIR_ENTRY_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p), (where)) + +#define sk_BY_DIR_ENTRY_delete(sk, where) \ + ((BY_DIR_ENTRY *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), (where))) + +#define sk_BY_DIR_ENTRY_delete_ptr(sk, p) \ + ((BY_DIR_ENTRY *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p))) + +#define sk_BY_DIR_ENTRY_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), (out_index), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p)) + +#define sk_BY_DIR_ENTRY_shift(sk) \ + ((BY_DIR_ENTRY *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk))) + +#define sk_BY_DIR_ENTRY_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void *, BY_DIR_ENTRY *, p)) + +#define sk_BY_DIR_ENTRY_pop(sk) \ + ((BY_DIR_ENTRY *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk))) + +#define sk_BY_DIR_ENTRY_dup(sk) \ + ((STACK_OF(BY_DIR_ENTRY) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk))) + +#define sk_BY_DIR_ENTRY_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk)) + +#define sk_BY_DIR_ENTRY_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk)) + +#define sk_BY_DIR_ENTRY_set_cmp_func(sk, comp) \ + ((int (*)(const BY_DIR_ENTRY **a, const BY_DIR_ENTRY **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const BY_DIR_ENTRY **a, const BY_DIR_ENTRY **b), \ + comp))) + +#define sk_BY_DIR_ENTRY_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(BY_DIR_ENTRY) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(BY_DIR_ENTRY) *, sk), \ + CHECKED_CAST(void *(*)(void *), BY_DIR_ENTRY *(*)(BY_DIR_ENTRY *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_ENTRY *), free_func))) + +/* BY_DIR_HASH */ +#define sk_BY_DIR_HASH_new(comp) \ + ((STACK_OF(BY_DIR_HASH) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const BY_DIR_HASH **a, const BY_DIR_HASH **b), \ + comp))) + +#define sk_BY_DIR_HASH_new_null() ((STACK_OF(BY_DIR_HASH) *)sk_new_null()) + +#define sk_BY_DIR_HASH_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)) + +#define sk_BY_DIR_HASH_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)); + +#define sk_BY_DIR_HASH_value(sk, i) \ + ((BY_DIR_HASH *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk), (i))) + +#define sk_BY_DIR_HASH_set(sk, i, p) \ + ((BY_DIR_HASH *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + (i), CHECKED_CAST(void *, BY_DIR_HASH *, p))) + +#define sk_BY_DIR_HASH_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)) + +#define sk_BY_DIR_HASH_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_HASH *), free_func)) + +#define sk_BY_DIR_HASH_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void *, BY_DIR_HASH *, p), (where)) + +#define sk_BY_DIR_HASH_delete(sk, where) \ + ((BY_DIR_HASH *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), (where))) + +#define sk_BY_DIR_HASH_delete_ptr(sk, p) \ + ((BY_DIR_HASH *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void *, BY_DIR_HASH *, p))) + +#define sk_BY_DIR_HASH_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), (out_index), \ + CHECKED_CAST(void *, BY_DIR_HASH *, p)) + +#define sk_BY_DIR_HASH_shift(sk) \ + ((BY_DIR_HASH *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk))) + +#define sk_BY_DIR_HASH_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void *, BY_DIR_HASH *, p)) + +#define sk_BY_DIR_HASH_pop(sk) \ + ((BY_DIR_HASH *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk))) + +#define sk_BY_DIR_HASH_dup(sk) \ + ((STACK_OF(BY_DIR_HASH) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk))) + +#define sk_BY_DIR_HASH_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk)) + +#define sk_BY_DIR_HASH_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(BY_DIR_HASH) *, sk)) + +#define sk_BY_DIR_HASH_set_cmp_func(sk, comp) \ + ((int (*)(const BY_DIR_HASH **a, const BY_DIR_HASH **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const BY_DIR_HASH **a, const BY_DIR_HASH **b), \ + comp))) + +#define sk_BY_DIR_HASH_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(BY_DIR_HASH) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(BY_DIR_HASH) *, sk), \ + CHECKED_CAST(void *(*)(void *), BY_DIR_HASH *(*)(BY_DIR_HASH *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(BY_DIR_HASH *), free_func))) + +/* CONF_VALUE */ +#define sk_CONF_VALUE_new(comp) \ + ((STACK_OF(CONF_VALUE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const CONF_VALUE **a, const CONF_VALUE **b), \ + comp))) + +#define sk_CONF_VALUE_new_null() ((STACK_OF(CONF_VALUE) *)sk_new_null()) + +#define sk_CONF_VALUE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)) + +#define sk_CONF_VALUE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)); + +#define sk_CONF_VALUE_value(sk, i) \ + ((CONF_VALUE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk), (i))) + +#define sk_CONF_VALUE_set(sk, i, p) \ + ((CONF_VALUE *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + (i), CHECKED_CAST(void *, CONF_VALUE *, p))) + +#define sk_CONF_VALUE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)) + +#define sk_CONF_VALUE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), free_func)) + +#define sk_CONF_VALUE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void *, CONF_VALUE *, p), (where)) + +#define sk_CONF_VALUE_delete(sk, where) \ + ((CONF_VALUE *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + (where))) + +#define sk_CONF_VALUE_delete_ptr(sk, p) \ + ((CONF_VALUE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void *, CONF_VALUE *, p))) + +#define sk_CONF_VALUE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), (out_index), \ + CHECKED_CAST(void *, CONF_VALUE *, p)) + +#define sk_CONF_VALUE_shift(sk) \ + ((CONF_VALUE *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk))) + +#define sk_CONF_VALUE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void *, CONF_VALUE *, p)) + +#define sk_CONF_VALUE_pop(sk) \ + ((CONF_VALUE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk))) + +#define sk_CONF_VALUE_dup(sk) \ + ((STACK_OF(CONF_VALUE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk))) + +#define sk_CONF_VALUE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk)) + +#define sk_CONF_VALUE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(CONF_VALUE) *, sk)) + +#define sk_CONF_VALUE_set_cmp_func(sk, comp) \ + ((int (*)(const CONF_VALUE **a, const CONF_VALUE **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const CONF_VALUE **a, const CONF_VALUE **b), \ + comp))) + +#define sk_CONF_VALUE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(CONF_VALUE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(CONF_VALUE) *, sk), \ + CHECKED_CAST(void *(*)(void *), CONF_VALUE *(*)(CONF_VALUE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), free_func))) + +/* CRYPTO_EX_DATA_FUNCS */ +#define sk_CRYPTO_EX_DATA_FUNCS_new(comp) \ + ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const CRYPTO_EX_DATA_FUNCS **a, const CRYPTO_EX_DATA_FUNCS **b), \ + comp))) + +#define sk_CRYPTO_EX_DATA_FUNCS_new_null() \ + ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_new_null()) + +#define sk_CRYPTO_EX_DATA_FUNCS_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) + +#define sk_CRYPTO_EX_DATA_FUNCS_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)); + +#define sk_CRYPTO_EX_DATA_FUNCS_value(sk, i) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + (i))) + +#define sk_CRYPTO_EX_DATA_FUNCS_set(sk, i, p) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), (i), \ + CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p))) + +#define sk_CRYPTO_EX_DATA_FUNCS_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) + +#define sk_CRYPTO_EX_DATA_FUNCS_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_EX_DATA_FUNCS *), \ + free_func)) + +#define sk_CRYPTO_EX_DATA_FUNCS_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p), (where)) + +#define sk_CRYPTO_EX_DATA_FUNCS_delete(sk, where) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), (where))) + +#define sk_CRYPTO_EX_DATA_FUNCS_delete_ptr(sk, p) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p))) + +#define sk_CRYPTO_EX_DATA_FUNCS_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + (out_index), CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p)) + +#define sk_CRYPTO_EX_DATA_FUNCS_shift(sk) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))) + +#define sk_CRYPTO_EX_DATA_FUNCS_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(void *, CRYPTO_EX_DATA_FUNCS *, p)) + +#define sk_CRYPTO_EX_DATA_FUNCS_pop(sk) \ + ((CRYPTO_EX_DATA_FUNCS *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))) + +#define sk_CRYPTO_EX_DATA_FUNCS_dup(sk) \ + ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk))) + +#define sk_CRYPTO_EX_DATA_FUNCS_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) + +#define sk_CRYPTO_EX_DATA_FUNCS_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk)) + +#define sk_CRYPTO_EX_DATA_FUNCS_set_cmp_func(sk, comp) \ + ((int (*)(const CRYPTO_EX_DATA_FUNCS **a, const CRYPTO_EX_DATA_FUNCS **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_EX_DATA_FUNCS) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const CRYPTO_EX_DATA_FUNCS **a, \ + const CRYPTO_EX_DATA_FUNCS **b), \ + comp))) + +#define sk_CRYPTO_EX_DATA_FUNCS_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_EX_DATA_FUNCS) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), \ + CRYPTO_EX_DATA_FUNCS *(*)(CRYPTO_EX_DATA_FUNCS *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_EX_DATA_FUNCS *), \ + free_func))) + +/* DIST_POINT */ +#define sk_DIST_POINT_new(comp) \ + ((STACK_OF(DIST_POINT) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const DIST_POINT **a, const DIST_POINT **b), \ + comp))) + +#define sk_DIST_POINT_new_null() ((STACK_OF(DIST_POINT) *)sk_new_null()) + +#define sk_DIST_POINT_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)) + +#define sk_DIST_POINT_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)); + +#define sk_DIST_POINT_value(sk, i) \ + ((DIST_POINT *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk), (i))) + +#define sk_DIST_POINT_set(sk, i, p) \ + ((DIST_POINT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + (i), CHECKED_CAST(void *, DIST_POINT *, p))) + +#define sk_DIST_POINT_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)) + +#define sk_DIST_POINT_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(DIST_POINT *), free_func)) + +#define sk_DIST_POINT_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void *, DIST_POINT *, p), (where)) + +#define sk_DIST_POINT_delete(sk, where) \ + ((DIST_POINT *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + (where))) + +#define sk_DIST_POINT_delete_ptr(sk, p) \ + ((DIST_POINT *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void *, DIST_POINT *, p))) + +#define sk_DIST_POINT_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), (out_index), \ + CHECKED_CAST(void *, DIST_POINT *, p)) + +#define sk_DIST_POINT_shift(sk) \ + ((DIST_POINT *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk))) + +#define sk_DIST_POINT_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void *, DIST_POINT *, p)) + +#define sk_DIST_POINT_pop(sk) \ + ((DIST_POINT *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk))) + +#define sk_DIST_POINT_dup(sk) \ + ((STACK_OF(DIST_POINT) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk))) + +#define sk_DIST_POINT_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk)) + +#define sk_DIST_POINT_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(DIST_POINT) *, sk)) + +#define sk_DIST_POINT_set_cmp_func(sk, comp) \ + ((int (*)(const DIST_POINT **a, const DIST_POINT **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const DIST_POINT **a, const DIST_POINT **b), \ + comp))) + +#define sk_DIST_POINT_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(DIST_POINT) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(DIST_POINT) *, sk), \ + CHECKED_CAST(void *(*)(void *), DIST_POINT *(*)(DIST_POINT *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(DIST_POINT *), free_func))) + +/* GENERAL_NAME */ +#define sk_GENERAL_NAME_new(comp) \ + ((STACK_OF(GENERAL_NAME) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const GENERAL_NAME **a, const GENERAL_NAME **b), \ + comp))) + +#define sk_GENERAL_NAME_new_null() ((STACK_OF(GENERAL_NAME) *)sk_new_null()) + +#define sk_GENERAL_NAME_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)) + +#define sk_GENERAL_NAME_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)); + +#define sk_GENERAL_NAME_value(sk, i) \ + ((GENERAL_NAME *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk), (i))) + +#define sk_GENERAL_NAME_set(sk, i, p) \ + ((GENERAL_NAME *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), (i), \ + CHECKED_CAST(void *, GENERAL_NAME *, p))) + +#define sk_GENERAL_NAME_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)) + +#define sk_GENERAL_NAME_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAME *), free_func)) + +#define sk_GENERAL_NAME_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAME *, p), (where)) + +#define sk_GENERAL_NAME_delete(sk, where) \ + ((GENERAL_NAME *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), (where))) + +#define sk_GENERAL_NAME_delete_ptr(sk, p) \ + ((GENERAL_NAME *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAME *, p))) + +#define sk_GENERAL_NAME_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), (out_index), \ + CHECKED_CAST(void *, GENERAL_NAME *, p)) + +#define sk_GENERAL_NAME_shift(sk) \ + ((GENERAL_NAME *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk))) + +#define sk_GENERAL_NAME_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAME *, p)) + +#define sk_GENERAL_NAME_pop(sk) \ + ((GENERAL_NAME *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk))) + +#define sk_GENERAL_NAME_dup(sk) \ + ((STACK_OF(GENERAL_NAME) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk))) + +#define sk_GENERAL_NAME_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk)) + +#define sk_GENERAL_NAME_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAME) *, sk)) + +#define sk_GENERAL_NAME_set_cmp_func(sk, comp) \ + ((int (*)(const GENERAL_NAME **a, const GENERAL_NAME **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const GENERAL_NAME **a, const GENERAL_NAME **b), \ + comp))) + +#define sk_GENERAL_NAME_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(GENERAL_NAME) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_NAME) *, sk), \ + CHECKED_CAST(void *(*)(void *), GENERAL_NAME *(*)(GENERAL_NAME *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAME *), free_func))) + +/* GENERAL_NAMES */ +#define sk_GENERAL_NAMES_new(comp) \ + ((STACK_OF(GENERAL_NAMES) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const GENERAL_NAMES **a, const GENERAL_NAMES **b), comp))) + +#define sk_GENERAL_NAMES_new_null() ((STACK_OF(GENERAL_NAMES) *)sk_new_null()) + +#define sk_GENERAL_NAMES_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)) + +#define sk_GENERAL_NAMES_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)); + +#define sk_GENERAL_NAMES_value(sk, i) \ + ((GENERAL_NAMES *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk), (i))) + +#define sk_GENERAL_NAMES_set(sk, i, p) \ + ((GENERAL_NAMES *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), (i), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p))) + +#define sk_GENERAL_NAMES_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)) + +#define sk_GENERAL_NAMES_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAMES *), free_func)) + +#define sk_GENERAL_NAMES_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p), (where)) + +#define sk_GENERAL_NAMES_delete(sk, where) \ + ((GENERAL_NAMES *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), (where))) + +#define sk_GENERAL_NAMES_delete_ptr(sk, p) \ + ((GENERAL_NAMES *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p))) + +#define sk_GENERAL_NAMES_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), (out_index), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p)) + +#define sk_GENERAL_NAMES_shift(sk) \ + ((GENERAL_NAMES *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk))) + +#define sk_GENERAL_NAMES_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void *, GENERAL_NAMES *, p)) + +#define sk_GENERAL_NAMES_pop(sk) \ + ((GENERAL_NAMES *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk))) + +#define sk_GENERAL_NAMES_dup(sk) \ + ((STACK_OF(GENERAL_NAMES) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk))) + +#define sk_GENERAL_NAMES_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk)) + +#define sk_GENERAL_NAMES_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_NAMES) *, sk)) + +#define sk_GENERAL_NAMES_set_cmp_func(sk, comp) \ + ((int (*)(const GENERAL_NAMES **a, const GENERAL_NAMES **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const GENERAL_NAMES **a, const GENERAL_NAMES **b), \ + comp))) + +#define sk_GENERAL_NAMES_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(GENERAL_NAMES) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_NAMES) *, sk), \ + CHECKED_CAST(void *(*)(void *), GENERAL_NAMES *(*)(GENERAL_NAMES *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_NAMES *), free_func))) + +/* GENERAL_SUBTREE */ +#define sk_GENERAL_SUBTREE_new(comp) \ + ((STACK_OF(GENERAL_SUBTREE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const GENERAL_SUBTREE **a, const GENERAL_SUBTREE **b), comp))) + +#define sk_GENERAL_SUBTREE_new_null() \ + ((STACK_OF(GENERAL_SUBTREE) *)sk_new_null()) + +#define sk_GENERAL_SUBTREE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)) + +#define sk_GENERAL_SUBTREE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)); + +#define sk_GENERAL_SUBTREE_value(sk, i) \ + ((GENERAL_SUBTREE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk), (i))) + +#define sk_GENERAL_SUBTREE_set(sk, i, p) \ + ((GENERAL_SUBTREE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), (i), \ + CHECKED_CAST(void *, GENERAL_SUBTREE *, p))) + +#define sk_GENERAL_SUBTREE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)) + +#define sk_GENERAL_SUBTREE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_SUBTREE *), free_func)) + +#define sk_GENERAL_SUBTREE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void *, GENERAL_SUBTREE *, p), (where)) + +#define sk_GENERAL_SUBTREE_delete(sk, where) \ + ((GENERAL_SUBTREE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), (where))) + +#define sk_GENERAL_SUBTREE_delete_ptr(sk, p) \ + ((GENERAL_SUBTREE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void *, GENERAL_SUBTREE *, p))) + +#define sk_GENERAL_SUBTREE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + (out_index), CHECKED_CAST(void *, GENERAL_SUBTREE *, p)) + +#define sk_GENERAL_SUBTREE_shift(sk) \ + ((GENERAL_SUBTREE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk))) + +#define sk_GENERAL_SUBTREE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void *, GENERAL_SUBTREE *, p)) + +#define sk_GENERAL_SUBTREE_pop(sk) \ + ((GENERAL_SUBTREE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk))) + +#define sk_GENERAL_SUBTREE_dup(sk) \ + ((STACK_OF(GENERAL_SUBTREE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk))) + +#define sk_GENERAL_SUBTREE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk)) + +#define sk_GENERAL_SUBTREE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk)) + +#define sk_GENERAL_SUBTREE_set_cmp_func(sk, comp) \ + ((int (*)(const GENERAL_SUBTREE **a, const GENERAL_SUBTREE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const GENERAL_SUBTREE **a, \ + const GENERAL_SUBTREE **b), \ + comp))) + +#define sk_GENERAL_SUBTREE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(GENERAL_SUBTREE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(GENERAL_SUBTREE) *, sk), \ + CHECKED_CAST(void *(*)(void *), GENERAL_SUBTREE *(*)(GENERAL_SUBTREE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(GENERAL_SUBTREE *), free_func))) + +/* MIME_HEADER */ +#define sk_MIME_HEADER_new(comp) \ + ((STACK_OF(MIME_HEADER) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const MIME_HEADER **a, const MIME_HEADER **b), \ + comp))) + +#define sk_MIME_HEADER_new_null() ((STACK_OF(MIME_HEADER) *)sk_new_null()) + +#define sk_MIME_HEADER_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk)) + +#define sk_MIME_HEADER_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk)); + +#define sk_MIME_HEADER_value(sk, i) \ + ((MIME_HEADER *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(MIME_HEADER) *, sk), (i))) + +#define sk_MIME_HEADER_set(sk, i, p) \ + ((MIME_HEADER *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \ + (i), CHECKED_CAST(void *, MIME_HEADER *, p))) + +#define sk_MIME_HEADER_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk)) + +#define sk_MIME_HEADER_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(MIME_HEADER *), free_func)) + +#define sk_MIME_HEADER_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \ + CHECKED_CAST(void *, MIME_HEADER *, p), (where)) + +#define sk_MIME_HEADER_delete(sk, where) \ + ((MIME_HEADER *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), (where))) + +#define sk_MIME_HEADER_delete_ptr(sk, p) \ + ((MIME_HEADER *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \ + CHECKED_CAST(void *, MIME_HEADER *, p))) + +#define sk_MIME_HEADER_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), (out_index), \ + CHECKED_CAST(void *, MIME_HEADER *, p)) + +#define sk_MIME_HEADER_shift(sk) \ + ((MIME_HEADER *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk))) + +#define sk_MIME_HEADER_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \ + CHECKED_CAST(void *, MIME_HEADER *, p)) + +#define sk_MIME_HEADER_pop(sk) \ + ((MIME_HEADER *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk))) + +#define sk_MIME_HEADER_dup(sk) \ + ((STACK_OF(MIME_HEADER) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(MIME_HEADER) *, sk))) + +#define sk_MIME_HEADER_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk)) + +#define sk_MIME_HEADER_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(MIME_HEADER) *, sk)) + +#define sk_MIME_HEADER_set_cmp_func(sk, comp) \ + ((int (*)(const MIME_HEADER **a, const MIME_HEADER **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(MIME_HEADER) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const MIME_HEADER **a, const MIME_HEADER **b), \ + comp))) + +#define sk_MIME_HEADER_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(MIME_HEADER) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(MIME_HEADER) *, sk), \ + CHECKED_CAST(void *(*)(void *), MIME_HEADER *(*)(MIME_HEADER *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(MIME_HEADER *), free_func))) + +/* PKCS7_RECIP_INFO */ +#define sk_PKCS7_RECIP_INFO_new(comp) \ + ((STACK_OF(PKCS7_RECIP_INFO) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const PKCS7_RECIP_INFO **a, const PKCS7_RECIP_INFO **b), comp))) + +#define sk_PKCS7_RECIP_INFO_new_null() \ + ((STACK_OF(PKCS7_RECIP_INFO) *)sk_new_null()) + +#define sk_PKCS7_RECIP_INFO_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk)) + +#define sk_PKCS7_RECIP_INFO_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk)); + +#define sk_PKCS7_RECIP_INFO_value(sk, i) \ + ((PKCS7_RECIP_INFO *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk), (i))) + +#define sk_PKCS7_RECIP_INFO_set(sk, i, p) \ + ((PKCS7_RECIP_INFO *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), (i), \ + CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p))) + +#define sk_PKCS7_RECIP_INFO_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk)) + +#define sk_PKCS7_RECIP_INFO_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(PKCS7_RECIP_INFO *), free_func)) + +#define sk_PKCS7_RECIP_INFO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \ + CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p), (where)) + +#define sk_PKCS7_RECIP_INFO_delete(sk, where) \ + ((PKCS7_RECIP_INFO *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), (where))) + +#define sk_PKCS7_RECIP_INFO_delete_ptr(sk, p) \ + ((PKCS7_RECIP_INFO *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \ + CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p))) + +#define sk_PKCS7_RECIP_INFO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \ + (out_index), CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p)) + +#define sk_PKCS7_RECIP_INFO_shift(sk) \ + ((PKCS7_RECIP_INFO *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk))) + +#define sk_PKCS7_RECIP_INFO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \ + CHECKED_CAST(void *, PKCS7_RECIP_INFO *, p)) + +#define sk_PKCS7_RECIP_INFO_pop(sk) \ + ((PKCS7_RECIP_INFO *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk))) + +#define sk_PKCS7_RECIP_INFO_dup(sk) \ + ((STACK_OF(PKCS7_RECIP_INFO) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk))) + +#define sk_PKCS7_RECIP_INFO_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk)) + +#define sk_PKCS7_RECIP_INFO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk)) + +#define sk_PKCS7_RECIP_INFO_set_cmp_func(sk, comp) \ + ((int (*)(const PKCS7_RECIP_INFO **a, const PKCS7_RECIP_INFO **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_RECIP_INFO) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const PKCS7_RECIP_INFO **a, \ + const PKCS7_RECIP_INFO **b), \ + comp))) + +#define sk_PKCS7_RECIP_INFO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(PKCS7_RECIP_INFO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(PKCS7_RECIP_INFO) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + PKCS7_RECIP_INFO *(*)(PKCS7_RECIP_INFO *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(PKCS7_RECIP_INFO *), \ + free_func))) + +/* PKCS7_SIGNER_INFO */ +#define sk_PKCS7_SIGNER_INFO_new(comp) \ + ((STACK_OF(PKCS7_SIGNER_INFO) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const PKCS7_SIGNER_INFO **a, const PKCS7_SIGNER_INFO **b), \ + comp))) + +#define sk_PKCS7_SIGNER_INFO_new_null() \ + ((STACK_OF(PKCS7_SIGNER_INFO) *)sk_new_null()) + +#define sk_PKCS7_SIGNER_INFO_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk)) + +#define sk_PKCS7_SIGNER_INFO_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk)); + +#define sk_PKCS7_SIGNER_INFO_value(sk, i) \ + ((PKCS7_SIGNER_INFO *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_SIGNER_INFO) *, sk), (i))) + +#define sk_PKCS7_SIGNER_INFO_set(sk, i, p) \ + ((PKCS7_SIGNER_INFO *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), (i), \ + CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p))) + +#define sk_PKCS7_SIGNER_INFO_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk)) + +#define sk_PKCS7_SIGNER_INFO_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(PKCS7_SIGNER_INFO *), \ + free_func)) + +#define sk_PKCS7_SIGNER_INFO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \ + CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p), (where)) + +#define sk_PKCS7_SIGNER_INFO_delete(sk, where) \ + ((PKCS7_SIGNER_INFO *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), (where))) + +#define sk_PKCS7_SIGNER_INFO_delete_ptr(sk, p) \ + ((PKCS7_SIGNER_INFO *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \ + CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p))) + +#define sk_PKCS7_SIGNER_INFO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \ + (out_index), CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p)) + +#define sk_PKCS7_SIGNER_INFO_shift(sk) \ + ((PKCS7_SIGNER_INFO *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk))) + +#define sk_PKCS7_SIGNER_INFO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \ + CHECKED_CAST(void *, PKCS7_SIGNER_INFO *, p)) + +#define sk_PKCS7_SIGNER_INFO_pop(sk) \ + ((PKCS7_SIGNER_INFO *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk))) + +#define sk_PKCS7_SIGNER_INFO_dup(sk) \ + ((STACK_OF(PKCS7_SIGNER_INFO) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_SIGNER_INFO) *, sk))) + +#define sk_PKCS7_SIGNER_INFO_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk)) + +#define sk_PKCS7_SIGNER_INFO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(PKCS7_SIGNER_INFO) *, sk)) + +#define sk_PKCS7_SIGNER_INFO_set_cmp_func(sk, comp) \ + ((int (*)(const PKCS7_SIGNER_INFO **a, const PKCS7_SIGNER_INFO **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(PKCS7_SIGNER_INFO) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const PKCS7_SIGNER_INFO **a, \ + const PKCS7_SIGNER_INFO **b), \ + comp))) + +#define sk_PKCS7_SIGNER_INFO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(PKCS7_SIGNER_INFO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(PKCS7_SIGNER_INFO) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + PKCS7_SIGNER_INFO *(*)(PKCS7_SIGNER_INFO *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(PKCS7_SIGNER_INFO *), \ + free_func))) + +/* POLICYINFO */ +#define sk_POLICYINFO_new(comp) \ + ((STACK_OF(POLICYINFO) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const POLICYINFO **a, const POLICYINFO **b), \ + comp))) + +#define sk_POLICYINFO_new_null() ((STACK_OF(POLICYINFO) *)sk_new_null()) + +#define sk_POLICYINFO_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)) + +#define sk_POLICYINFO_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)); + +#define sk_POLICYINFO_value(sk, i) \ + ((POLICYINFO *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk), (i))) + +#define sk_POLICYINFO_set(sk, i, p) \ + ((POLICYINFO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + (i), CHECKED_CAST(void *, POLICYINFO *, p))) + +#define sk_POLICYINFO_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)) + +#define sk_POLICYINFO_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICYINFO *), free_func)) + +#define sk_POLICYINFO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void *, POLICYINFO *, p), (where)) + +#define sk_POLICYINFO_delete(sk, where) \ + ((POLICYINFO *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + (where))) + +#define sk_POLICYINFO_delete_ptr(sk, p) \ + ((POLICYINFO *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void *, POLICYINFO *, p))) + +#define sk_POLICYINFO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), (out_index), \ + CHECKED_CAST(void *, POLICYINFO *, p)) + +#define sk_POLICYINFO_shift(sk) \ + ((POLICYINFO *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk))) + +#define sk_POLICYINFO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void *, POLICYINFO *, p)) + +#define sk_POLICYINFO_pop(sk) \ + ((POLICYINFO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk))) + +#define sk_POLICYINFO_dup(sk) \ + ((STACK_OF(POLICYINFO) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk))) + +#define sk_POLICYINFO_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk)) + +#define sk_POLICYINFO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICYINFO) *, sk)) + +#define sk_POLICYINFO_set_cmp_func(sk, comp) \ + ((int (*)(const POLICYINFO **a, const POLICYINFO **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const POLICYINFO **a, const POLICYINFO **b), \ + comp))) + +#define sk_POLICYINFO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(POLICYINFO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(POLICYINFO) *, sk), \ + CHECKED_CAST(void *(*)(void *), POLICYINFO *(*)(POLICYINFO *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICYINFO *), free_func))) + +/* POLICYQUALINFO */ +#define sk_POLICYQUALINFO_new(comp) \ + ((STACK_OF(POLICYQUALINFO) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const POLICYQUALINFO **a, const POLICYQUALINFO **b), comp))) + +#define sk_POLICYQUALINFO_new_null() ((STACK_OF(POLICYQUALINFO) *)sk_new_null()) + +#define sk_POLICYQUALINFO_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)) + +#define sk_POLICYQUALINFO_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)); + +#define sk_POLICYQUALINFO_value(sk, i) \ + ((POLICYQUALINFO *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk), (i))) + +#define sk_POLICYQUALINFO_set(sk, i, p) \ + ((POLICYQUALINFO *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (i), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p))) + +#define sk_POLICYQUALINFO_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)) + +#define sk_POLICYQUALINFO_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICYQUALINFO *), free_func)) + +#define sk_POLICYQUALINFO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p), (where)) + +#define sk_POLICYQUALINFO_delete(sk, where) \ + ((POLICYQUALINFO *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (where))) + +#define sk_POLICYQUALINFO_delete_ptr(sk, p) \ + ((POLICYQUALINFO *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p))) + +#define sk_POLICYQUALINFO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), (out_index), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p)) + +#define sk_POLICYQUALINFO_shift(sk) \ + ((POLICYQUALINFO *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))) + +#define sk_POLICYQUALINFO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void *, POLICYQUALINFO *, p)) + +#define sk_POLICYQUALINFO_pop(sk) \ + ((POLICYQUALINFO *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk))) + +#define sk_POLICYQUALINFO_dup(sk) \ + ((STACK_OF(POLICYQUALINFO) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk))) + +#define sk_POLICYQUALINFO_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk)) + +#define sk_POLICYQUALINFO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICYQUALINFO) *, sk)) + +#define sk_POLICYQUALINFO_set_cmp_func(sk, comp) \ + ((int (*)(const POLICYQUALINFO **a, const POLICYQUALINFO **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const POLICYQUALINFO **a, \ + const POLICYQUALINFO **b), \ + comp))) + +#define sk_POLICYQUALINFO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(POLICYQUALINFO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(POLICYQUALINFO) *, sk), \ + CHECKED_CAST(void *(*)(void *), POLICYQUALINFO *(*)(POLICYQUALINFO *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICYQUALINFO *), free_func))) + +/* POLICY_MAPPING */ +#define sk_POLICY_MAPPING_new(comp) \ + ((STACK_OF(POLICY_MAPPING) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const POLICY_MAPPING **a, const POLICY_MAPPING **b), comp))) + +#define sk_POLICY_MAPPING_new_null() ((STACK_OF(POLICY_MAPPING) *)sk_new_null()) + +#define sk_POLICY_MAPPING_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)) + +#define sk_POLICY_MAPPING_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)); + +#define sk_POLICY_MAPPING_value(sk, i) \ + ((POLICY_MAPPING *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk), (i))) + +#define sk_POLICY_MAPPING_set(sk, i, p) \ + ((POLICY_MAPPING *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), (i), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p))) + +#define sk_POLICY_MAPPING_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)) + +#define sk_POLICY_MAPPING_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICY_MAPPING *), free_func)) + +#define sk_POLICY_MAPPING_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p), (where)) + +#define sk_POLICY_MAPPING_delete(sk, where) \ + ((POLICY_MAPPING *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), (where))) + +#define sk_POLICY_MAPPING_delete_ptr(sk, p) \ + ((POLICY_MAPPING *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p))) + +#define sk_POLICY_MAPPING_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), (out_index), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p)) + +#define sk_POLICY_MAPPING_shift(sk) \ + ((POLICY_MAPPING *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk))) + +#define sk_POLICY_MAPPING_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void *, POLICY_MAPPING *, p)) + +#define sk_POLICY_MAPPING_pop(sk) \ + ((POLICY_MAPPING *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk))) + +#define sk_POLICY_MAPPING_dup(sk) \ + ((STACK_OF(POLICY_MAPPING) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk))) + +#define sk_POLICY_MAPPING_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk)) + +#define sk_POLICY_MAPPING_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(POLICY_MAPPING) *, sk)) + +#define sk_POLICY_MAPPING_set_cmp_func(sk, comp) \ + ((int (*)(const POLICY_MAPPING **a, const POLICY_MAPPING **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const POLICY_MAPPING **a, \ + const POLICY_MAPPING **b), \ + comp))) + +#define sk_POLICY_MAPPING_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(POLICY_MAPPING) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(POLICY_MAPPING) *, sk), \ + CHECKED_CAST(void *(*)(void *), POLICY_MAPPING *(*)(POLICY_MAPPING *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(POLICY_MAPPING *), free_func))) + +/* RSA_additional_prime */ +#define sk_RSA_additional_prime_new(comp) \ + ((STACK_OF(RSA_additional_prime) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const RSA_additional_prime **a, const RSA_additional_prime **b), \ + comp))) + +#define sk_RSA_additional_prime_new_null() \ + ((STACK_OF(RSA_additional_prime) *)sk_new_null()) + +#define sk_RSA_additional_prime_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)) + +#define sk_RSA_additional_prime_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)); + +#define sk_RSA_additional_prime_value(sk, i) \ + ((RSA_additional_prime *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk), \ + (i))) + +#define sk_RSA_additional_prime_set(sk, i, p) \ + ((RSA_additional_prime *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), (i), \ + CHECKED_CAST(void *, RSA_additional_prime *, p))) + +#define sk_RSA_additional_prime_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)) + +#define sk_RSA_additional_prime_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(RSA_additional_prime *), \ + free_func)) + +#define sk_RSA_additional_prime_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(void *, RSA_additional_prime *, p), (where)) + +#define sk_RSA_additional_prime_delete(sk, where) \ + ((RSA_additional_prime *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), (where))) + +#define sk_RSA_additional_prime_delete_ptr(sk, p) \ + ((RSA_additional_prime *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(void *, RSA_additional_prime *, p))) + +#define sk_RSA_additional_prime_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + (out_index), CHECKED_CAST(void *, RSA_additional_prime *, p)) + +#define sk_RSA_additional_prime_shift(sk) \ + ((RSA_additional_prime *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk))) + +#define sk_RSA_additional_prime_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(void *, RSA_additional_prime *, p)) + +#define sk_RSA_additional_prime_pop(sk) \ + ((RSA_additional_prime *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk))) + +#define sk_RSA_additional_prime_dup(sk) \ + ((STACK_OF(RSA_additional_prime) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk))) + +#define sk_RSA_additional_prime_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk)) + +#define sk_RSA_additional_prime_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(RSA_additional_prime) *, sk)) + +#define sk_RSA_additional_prime_set_cmp_func(sk, comp) \ + ((int (*)(const RSA_additional_prime **a, const RSA_additional_prime **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(RSA_additional_prime) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const RSA_additional_prime **a, \ + const RSA_additional_prime **b), \ + comp))) + +#define sk_RSA_additional_prime_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(RSA_additional_prime) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(RSA_additional_prime) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), \ + RSA_additional_prime *(*)(RSA_additional_prime *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(RSA_additional_prime *), \ + free_func))) + +/* SSL_COMP */ +#define sk_SSL_COMP_new(comp) \ + ((STACK_OF(SSL_COMP) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const SSL_COMP **a, const SSL_COMP **b), comp))) + +#define sk_SSL_COMP_new_null() ((STACK_OF(SSL_COMP) *)sk_new_null()) + +#define sk_SSL_COMP_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)) + +#define sk_SSL_COMP_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)); + +#define sk_SSL_COMP_value(sk, i) \ + ((SSL_COMP *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk), (i))) + +#define sk_SSL_COMP_set(sk, i, p) \ + ((SSL_COMP *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), (i), \ + CHECKED_CAST(void *, SSL_COMP *, p))) + +#define sk_SSL_COMP_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)) + +#define sk_SSL_COMP_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_COMP *), free_func)) + +#define sk_SSL_COMP_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void *, SSL_COMP *, p), (where)) + +#define sk_SSL_COMP_delete(sk, where) \ + ((SSL_COMP *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + (where))) + +#define sk_SSL_COMP_delete_ptr(sk, p) \ + ((SSL_COMP *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void *, SSL_COMP *, p))) + +#define sk_SSL_COMP_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), (out_index), \ + CHECKED_CAST(void *, SSL_COMP *, p)) + +#define sk_SSL_COMP_shift(sk) \ + ((SSL_COMP *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk))) + +#define sk_SSL_COMP_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void *, SSL_COMP *, p)) + +#define sk_SSL_COMP_pop(sk) \ + ((SSL_COMP *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk))) + +#define sk_SSL_COMP_dup(sk) \ + ((STACK_OF(SSL_COMP) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk))) + +#define sk_SSL_COMP_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk)) + +#define sk_SSL_COMP_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SSL_COMP) *, sk)) + +#define sk_SSL_COMP_set_cmp_func(sk, comp) \ + ((int (*)(const SSL_COMP **a, const SSL_COMP **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SSL_COMP **a, const SSL_COMP **b), comp))) + +#define sk_SSL_COMP_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SSL_COMP) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SSL_COMP) *, sk), \ + CHECKED_CAST(void *(*)(void *), SSL_COMP *(*)(SSL_COMP *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_COMP *), free_func))) + +/* SSL_CUSTOM_EXTENSION */ +#define sk_SSL_CUSTOM_EXTENSION_new(comp) \ + ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const SSL_CUSTOM_EXTENSION **a, const SSL_CUSTOM_EXTENSION **b), \ + comp))) + +#define sk_SSL_CUSTOM_EXTENSION_new_null() \ + ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_new_null()) + +#define sk_SSL_CUSTOM_EXTENSION_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) + +#define sk_SSL_CUSTOM_EXTENSION_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)); + +#define sk_SSL_CUSTOM_EXTENSION_value(sk, i) \ + ((SSL_CUSTOM_EXTENSION *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + (i))) + +#define sk_SSL_CUSTOM_EXTENSION_set(sk, i, p) \ + ((SSL_CUSTOM_EXTENSION *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), (i), \ + CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p))) + +#define sk_SSL_CUSTOM_EXTENSION_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) + +#define sk_SSL_CUSTOM_EXTENSION_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_CUSTOM_EXTENSION *), \ + free_func)) + +#define sk_SSL_CUSTOM_EXTENSION_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p), (where)) + +#define sk_SSL_CUSTOM_EXTENSION_delete(sk, where) \ + ((SSL_CUSTOM_EXTENSION *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), (where))) + +#define sk_SSL_CUSTOM_EXTENSION_delete_ptr(sk, p) \ + ((SSL_CUSTOM_EXTENSION *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p))) + +#define sk_SSL_CUSTOM_EXTENSION_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + (out_index), CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p)) + +#define sk_SSL_CUSTOM_EXTENSION_shift(sk) \ + ((SSL_CUSTOM_EXTENSION *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))) + +#define sk_SSL_CUSTOM_EXTENSION_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(void *, SSL_CUSTOM_EXTENSION *, p)) + +#define sk_SSL_CUSTOM_EXTENSION_pop(sk) \ + ((SSL_CUSTOM_EXTENSION *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))) + +#define sk_SSL_CUSTOM_EXTENSION_dup(sk) \ + ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk))) + +#define sk_SSL_CUSTOM_EXTENSION_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) + +#define sk_SSL_CUSTOM_EXTENSION_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, sk)) + +#define sk_SSL_CUSTOM_EXTENSION_set_cmp_func(sk, comp) \ + ((int (*)(const SSL_CUSTOM_EXTENSION **a, const SSL_CUSTOM_EXTENSION **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CUSTOM_EXTENSION) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SSL_CUSTOM_EXTENSION **a, \ + const SSL_CUSTOM_EXTENSION **b), \ + comp))) + +#define sk_SSL_CUSTOM_EXTENSION_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SSL_CUSTOM_EXTENSION) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SSL_CUSTOM_EXTENSION) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), \ + SSL_CUSTOM_EXTENSION *(*)(SSL_CUSTOM_EXTENSION *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(SSL_CUSTOM_EXTENSION *), \ + free_func))) + +/* STACK_OF_X509_NAME_ENTRY */ +#define sk_STACK_OF_X509_NAME_ENTRY_new(comp) \ + ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const STACK_OF_X509_NAME_ENTRY **a, \ + const STACK_OF_X509_NAME_ENTRY **b), \ + comp))) + +#define sk_STACK_OF_X509_NAME_ENTRY_new_null() \ + ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_new_null()) + +#define sk_STACK_OF_X509_NAME_ENTRY_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) + +#define sk_STACK_OF_X509_NAME_ENTRY_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)); + +#define sk_STACK_OF_X509_NAME_ENTRY_value(sk, i) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + (i))) + +#define sk_STACK_OF_X509_NAME_ENTRY_set(sk, i, p) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), (i), \ + CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p))) + +#define sk_STACK_OF_X509_NAME_ENTRY_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) + +#define sk_STACK_OF_X509_NAME_ENTRY_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(STACK_OF_X509_NAME_ENTRY *), \ + free_func)) + +#define sk_STACK_OF_X509_NAME_ENTRY_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p), (where)) + +#define sk_STACK_OF_X509_NAME_ENTRY_delete(sk, where) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + (where))) + +#define sk_STACK_OF_X509_NAME_ENTRY_delete_ptr(sk, p) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p))) + +#define sk_STACK_OF_X509_NAME_ENTRY_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + (out_index), CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p)) + +#define sk_STACK_OF_X509_NAME_ENTRY_shift(sk) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))) + +#define sk_STACK_OF_X509_NAME_ENTRY_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, STACK_OF_X509_NAME_ENTRY *, p)) + +#define sk_STACK_OF_X509_NAME_ENTRY_pop(sk) \ + ((STACK_OF_X509_NAME_ENTRY *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))) + +#define sk_STACK_OF_X509_NAME_ENTRY_dup(sk) \ + ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk))) + +#define sk_STACK_OF_X509_NAME_ENTRY_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) + +#define sk_STACK_OF_X509_NAME_ENTRY_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk)) + +#define sk_STACK_OF_X509_NAME_ENTRY_set_cmp_func(sk, comp) \ + ((int (*)(const STACK_OF_X509_NAME_ENTRY **a, \ + const STACK_OF_X509_NAME_ENTRY **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(STACK_OF_X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const STACK_OF_X509_NAME_ENTRY **a, \ + const STACK_OF_X509_NAME_ENTRY **b), \ + comp))) + +#define sk_STACK_OF_X509_NAME_ENTRY_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(STACK_OF_X509_NAME_ENTRY) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(STACK_OF_X509_NAME_ENTRY) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), \ + STACK_OF_X509_NAME_ENTRY *(*)(STACK_OF_X509_NAME_ENTRY *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(STACK_OF_X509_NAME_ENTRY *), \ + free_func))) + +/* SXNETID */ +#define sk_SXNETID_new(comp) \ + ((STACK_OF(SXNETID) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const SXNETID **a, const SXNETID **b), comp))) + +#define sk_SXNETID_new_null() ((STACK_OF(SXNETID) *)sk_new_null()) + +#define sk_SXNETID_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)) + +#define sk_SXNETID_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)); + +#define sk_SXNETID_value(sk, i) \ + ((SXNETID *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk), \ + (i))) + +#define sk_SXNETID_set(sk, i, p) \ + ((SXNETID *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), (i), \ + CHECKED_CAST(void *, SXNETID *, p))) + +#define sk_SXNETID_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)) + +#define sk_SXNETID_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(SXNETID *), free_func)) + +#define sk_SXNETID_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void *, SXNETID *, p), (where)) + +#define sk_SXNETID_delete(sk, where) \ + ((SXNETID *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + (where))) + +#define sk_SXNETID_delete_ptr(sk, p) \ + ((SXNETID *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void *, SXNETID *, p))) + +#define sk_SXNETID_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), (out_index), \ + CHECKED_CAST(void *, SXNETID *, p)) + +#define sk_SXNETID_shift(sk) \ + ((SXNETID *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk))) + +#define sk_SXNETID_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void *, SXNETID *, p)) + +#define sk_SXNETID_pop(sk) \ + ((SXNETID *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk))) + +#define sk_SXNETID_dup(sk) \ + ((STACK_OF(SXNETID) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk))) + +#define sk_SXNETID_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk)) + +#define sk_SXNETID_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SXNETID) *, sk)) + +#define sk_SXNETID_set_cmp_func(sk, comp) \ + ((int (*)(const SXNETID **a, const SXNETID **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SXNETID **a, const SXNETID **b), comp))) + +#define sk_SXNETID_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SXNETID) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SXNETID) *, sk), \ + CHECKED_CAST(void *(*)(void *), SXNETID *(*)(SXNETID *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(SXNETID *), free_func))) + +/* X509 */ +#define sk_X509_new(comp) \ + ((STACK_OF(X509) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509 **a, const X509 **b), comp))) + +#define sk_X509_new_null() ((STACK_OF(X509) *)sk_new_null()) + +#define sk_X509_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)) + +#define sk_X509_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)); + +#define sk_X509_value(sk, i) \ + ((X509 *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk), (i))) + +#define sk_X509_set(sk, i, p) \ + ((X509 *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), (i), \ + CHECKED_CAST(void *, X509 *, p))) + +#define sk_X509_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)) + +#define sk_X509_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509 *), free_func)) + +#define sk_X509_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(void *, X509 *, p), (where)) + +#define sk_X509_delete(sk, where) \ + ((X509 *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), (where))) + +#define sk_X509_delete_ptr(sk, p) \ + ((X509 *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(void *, X509 *, p))) + +#define sk_X509_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), (out_index), \ + CHECKED_CAST(void *, X509 *, p)) + +#define sk_X509_shift(sk) \ + ((X509 *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk))) + +#define sk_X509_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(void *, X509 *, p)) + +#define sk_X509_pop(sk) \ + ((X509 *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk))) + +#define sk_X509_dup(sk) \ + ((STACK_OF(X509) *)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk))) + +#define sk_X509_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk)) + +#define sk_X509_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509) *, sk)) + +#define sk_X509_set_cmp_func(sk, comp) \ + ((int (*)(const X509 **a, const X509 **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509 **a, const X509 **b), \ + comp))) + +#define sk_X509_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509 *(*)(X509 *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509 *), free_func))) + +/* X509V3_EXT_METHOD */ +#define sk_X509V3_EXT_METHOD_new(comp) \ + ((STACK_OF(X509V3_EXT_METHOD) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509V3_EXT_METHOD **a, const X509V3_EXT_METHOD **b), \ + comp))) + +#define sk_X509V3_EXT_METHOD_new_null() \ + ((STACK_OF(X509V3_EXT_METHOD) *)sk_new_null()) + +#define sk_X509V3_EXT_METHOD_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)) + +#define sk_X509V3_EXT_METHOD_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)); + +#define sk_X509V3_EXT_METHOD_value(sk, i) \ + ((X509V3_EXT_METHOD *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk), (i))) + +#define sk_X509V3_EXT_METHOD_set(sk, i, p) \ + ((X509V3_EXT_METHOD *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), (i), \ + CHECKED_CAST(void *, X509V3_EXT_METHOD *, p))) + +#define sk_X509V3_EXT_METHOD_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)) + +#define sk_X509V3_EXT_METHOD_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509V3_EXT_METHOD *), \ + free_func)) + +#define sk_X509V3_EXT_METHOD_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void *, X509V3_EXT_METHOD *, p), (where)) + +#define sk_X509V3_EXT_METHOD_delete(sk, where) \ + ((X509V3_EXT_METHOD *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), (where))) + +#define sk_X509V3_EXT_METHOD_delete_ptr(sk, p) \ + ((X509V3_EXT_METHOD *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void *, X509V3_EXT_METHOD *, p))) + +#define sk_X509V3_EXT_METHOD_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + (out_index), CHECKED_CAST(void *, X509V3_EXT_METHOD *, p)) + +#define sk_X509V3_EXT_METHOD_shift(sk) \ + ((X509V3_EXT_METHOD *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk))) + +#define sk_X509V3_EXT_METHOD_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void *, X509V3_EXT_METHOD *, p)) + +#define sk_X509V3_EXT_METHOD_pop(sk) \ + ((X509V3_EXT_METHOD *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk))) + +#define sk_X509V3_EXT_METHOD_dup(sk) \ + ((STACK_OF(X509V3_EXT_METHOD) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk))) + +#define sk_X509V3_EXT_METHOD_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk)) + +#define sk_X509V3_EXT_METHOD_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk)) + +#define sk_X509V3_EXT_METHOD_set_cmp_func(sk, comp) \ + ((int (*)(const X509V3_EXT_METHOD **a, const X509V3_EXT_METHOD **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509V3_EXT_METHOD **a, \ + const X509V3_EXT_METHOD **b), \ + comp))) + +#define sk_X509V3_EXT_METHOD_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509V3_EXT_METHOD) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509V3_EXT_METHOD) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + X509V3_EXT_METHOD *(*)(X509V3_EXT_METHOD *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509V3_EXT_METHOD *), \ + free_func))) + +/* X509_ALGOR */ +#define sk_X509_ALGOR_new(comp) \ + ((STACK_OF(X509_ALGOR) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_ALGOR **a, const X509_ALGOR **b), \ + comp))) + +#define sk_X509_ALGOR_new_null() ((STACK_OF(X509_ALGOR) *)sk_new_null()) + +#define sk_X509_ALGOR_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)) + +#define sk_X509_ALGOR_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)); + +#define sk_X509_ALGOR_value(sk, i) \ + ((X509_ALGOR *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk), (i))) + +#define sk_X509_ALGOR_set(sk, i, p) \ + ((X509_ALGOR *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + (i), CHECKED_CAST(void *, X509_ALGOR *, p))) + +#define sk_X509_ALGOR_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)) + +#define sk_X509_ALGOR_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_ALGOR *), free_func)) + +#define sk_X509_ALGOR_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void *, X509_ALGOR *, p), (where)) + +#define sk_X509_ALGOR_delete(sk, where) \ + ((X509_ALGOR *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + (where))) + +#define sk_X509_ALGOR_delete_ptr(sk, p) \ + ((X509_ALGOR *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void *, X509_ALGOR *, p))) + +#define sk_X509_ALGOR_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_ALGOR *, p)) + +#define sk_X509_ALGOR_shift(sk) \ + ((X509_ALGOR *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))) + +#define sk_X509_ALGOR_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void *, X509_ALGOR *, p)) + +#define sk_X509_ALGOR_pop(sk) \ + ((X509_ALGOR *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk))) + +#define sk_X509_ALGOR_dup(sk) \ + ((STACK_OF(X509_ALGOR) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk))) + +#define sk_X509_ALGOR_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk)) + +#define sk_X509_ALGOR_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_ALGOR) *, sk)) + +#define sk_X509_ALGOR_set_cmp_func(sk, comp) \ + ((int (*)(const X509_ALGOR **a, const X509_ALGOR **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_ALGOR **a, const X509_ALGOR **b), \ + comp))) + +#define sk_X509_ALGOR_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_ALGOR) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_ALGOR) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_ALGOR *(*)(X509_ALGOR *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_ALGOR *), free_func))) + +/* X509_ATTRIBUTE */ +#define sk_X509_ATTRIBUTE_new(comp) \ + ((STACK_OF(X509_ATTRIBUTE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_ATTRIBUTE **a, const X509_ATTRIBUTE **b), comp))) + +#define sk_X509_ATTRIBUTE_new_null() ((STACK_OF(X509_ATTRIBUTE) *)sk_new_null()) + +#define sk_X509_ATTRIBUTE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)) + +#define sk_X509_ATTRIBUTE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)); + +#define sk_X509_ATTRIBUTE_value(sk, i) \ + ((X509_ATTRIBUTE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk), (i))) + +#define sk_X509_ATTRIBUTE_set(sk, i, p) \ + ((X509_ATTRIBUTE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (i), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p))) + +#define sk_X509_ATTRIBUTE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)) + +#define sk_X509_ATTRIBUTE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_ATTRIBUTE *), free_func)) + +#define sk_X509_ATTRIBUTE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p), (where)) + +#define sk_X509_ATTRIBUTE_delete(sk, where) \ + ((X509_ATTRIBUTE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (where))) + +#define sk_X509_ATTRIBUTE_delete_ptr(sk, p) \ + ((X509_ATTRIBUTE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p))) + +#define sk_X509_ATTRIBUTE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p)) + +#define sk_X509_ATTRIBUTE_shift(sk) \ + ((X509_ATTRIBUTE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))) + +#define sk_X509_ATTRIBUTE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void *, X509_ATTRIBUTE *, p)) + +#define sk_X509_ATTRIBUTE_pop(sk) \ + ((X509_ATTRIBUTE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk))) + +#define sk_X509_ATTRIBUTE_dup(sk) \ + ((STACK_OF(X509_ATTRIBUTE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk))) + +#define sk_X509_ATTRIBUTE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk)) + +#define sk_X509_ATTRIBUTE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk)) + +#define sk_X509_ATTRIBUTE_set_cmp_func(sk, comp) \ + ((int (*)(const X509_ATTRIBUTE **a, const X509_ATTRIBUTE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_ATTRIBUTE **a, \ + const X509_ATTRIBUTE **b), \ + comp))) + +#define sk_X509_ATTRIBUTE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_ATTRIBUTE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_ATTRIBUTE) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_ATTRIBUTE *(*)(X509_ATTRIBUTE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_ATTRIBUTE *), free_func))) + +/* X509_CRL */ +#define sk_X509_CRL_new(comp) \ + ((STACK_OF(X509_CRL) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_CRL **a, const X509_CRL **b), comp))) + +#define sk_X509_CRL_new_null() ((STACK_OF(X509_CRL) *)sk_new_null()) + +#define sk_X509_CRL_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)) + +#define sk_X509_CRL_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)); + +#define sk_X509_CRL_value(sk, i) \ + ((X509_CRL *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk), (i))) + +#define sk_X509_CRL_set(sk, i, p) \ + ((X509_CRL *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), (i), \ + CHECKED_CAST(void *, X509_CRL *, p))) + +#define sk_X509_CRL_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)) + +#define sk_X509_CRL_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_CRL *), free_func)) + +#define sk_X509_CRL_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void *, X509_CRL *, p), (where)) + +#define sk_X509_CRL_delete(sk, where) \ + ((X509_CRL *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + (where))) + +#define sk_X509_CRL_delete_ptr(sk, p) \ + ((X509_CRL *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void *, X509_CRL *, p))) + +#define sk_X509_CRL_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_CRL *, p)) + +#define sk_X509_CRL_shift(sk) \ + ((X509_CRL *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))) + +#define sk_X509_CRL_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void *, X509_CRL *, p)) + +#define sk_X509_CRL_pop(sk) \ + ((X509_CRL *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk))) + +#define sk_X509_CRL_dup(sk) \ + ((STACK_OF(X509_CRL) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk))) + +#define sk_X509_CRL_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk)) + +#define sk_X509_CRL_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_CRL) *, sk)) + +#define sk_X509_CRL_set_cmp_func(sk, comp) \ + ((int (*)(const X509_CRL **a, const X509_CRL **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_CRL **a, const X509_CRL **b), comp))) + +#define sk_X509_CRL_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_CRL) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_CRL) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_CRL *(*)(X509_CRL *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_CRL *), free_func))) + +/* X509_EXTENSION */ +#define sk_X509_EXTENSION_new(comp) \ + ((STACK_OF(X509_EXTENSION) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_EXTENSION **a, const X509_EXTENSION **b), comp))) + +#define sk_X509_EXTENSION_new_null() ((STACK_OF(X509_EXTENSION) *)sk_new_null()) + +#define sk_X509_EXTENSION_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)) + +#define sk_X509_EXTENSION_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)); + +#define sk_X509_EXTENSION_value(sk, i) \ + ((X509_EXTENSION *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk), (i))) + +#define sk_X509_EXTENSION_set(sk, i, p) \ + ((X509_EXTENSION *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (i), \ + CHECKED_CAST(void *, X509_EXTENSION *, p))) + +#define sk_X509_EXTENSION_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)) + +#define sk_X509_EXTENSION_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_EXTENSION *), free_func)) + +#define sk_X509_EXTENSION_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void *, X509_EXTENSION *, p), (where)) + +#define sk_X509_EXTENSION_delete(sk, where) \ + ((X509_EXTENSION *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (where))) + +#define sk_X509_EXTENSION_delete_ptr(sk, p) \ + ((X509_EXTENSION *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void *, X509_EXTENSION *, p))) + +#define sk_X509_EXTENSION_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_EXTENSION *, p)) + +#define sk_X509_EXTENSION_shift(sk) \ + ((X509_EXTENSION *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))) + +#define sk_X509_EXTENSION_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void *, X509_EXTENSION *, p)) + +#define sk_X509_EXTENSION_pop(sk) \ + ((X509_EXTENSION *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk))) + +#define sk_X509_EXTENSION_dup(sk) \ + ((STACK_OF(X509_EXTENSION) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk))) + +#define sk_X509_EXTENSION_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk)) + +#define sk_X509_EXTENSION_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_EXTENSION) *, sk)) + +#define sk_X509_EXTENSION_set_cmp_func(sk, comp) \ + ((int (*)(const X509_EXTENSION **a, const X509_EXTENSION **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_EXTENSION **a, \ + const X509_EXTENSION **b), \ + comp))) + +#define sk_X509_EXTENSION_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_EXTENSION) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_EXTENSION) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_EXTENSION *(*)(X509_EXTENSION *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_EXTENSION *), free_func))) + +/* X509_INFO */ +#define sk_X509_INFO_new(comp) \ + ((STACK_OF(X509_INFO) *)sk_new( \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_INFO **a, const X509_INFO **b), comp))) + +#define sk_X509_INFO_new_null() ((STACK_OF(X509_INFO) *)sk_new_null()) + +#define sk_X509_INFO_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)) + +#define sk_X509_INFO_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)); + +#define sk_X509_INFO_value(sk, i) \ + ((X509_INFO *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk), (i))) + +#define sk_X509_INFO_set(sk, i, p) \ + ((X509_INFO *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), (i), \ + CHECKED_CAST(void *, X509_INFO *, p))) + +#define sk_X509_INFO_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)) + +#define sk_X509_INFO_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_INFO *), free_func)) + +#define sk_X509_INFO_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void *, X509_INFO *, p), (where)) + +#define sk_X509_INFO_delete(sk, where) \ + ((X509_INFO *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + (where))) + +#define sk_X509_INFO_delete_ptr(sk, p) \ + ((X509_INFO *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void *, X509_INFO *, p))) + +#define sk_X509_INFO_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_INFO *, p)) + +#define sk_X509_INFO_shift(sk) \ + ((X509_INFO *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))) + +#define sk_X509_INFO_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void *, X509_INFO *, p)) + +#define sk_X509_INFO_pop(sk) \ + ((X509_INFO *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk))) + +#define sk_X509_INFO_dup(sk) \ + ((STACK_OF(X509_INFO) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk))) + +#define sk_X509_INFO_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk)) + +#define sk_X509_INFO_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_INFO) *, sk)) + +#define sk_X509_INFO_set_cmp_func(sk, comp) \ + ((int (*)(const X509_INFO **a, const X509_INFO **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_INFO **a, const X509_INFO **b), comp))) + +#define sk_X509_INFO_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_INFO) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_INFO) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_INFO *(*)(X509_INFO *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_INFO *), free_func))) + +/* X509_LOOKUP */ +#define sk_X509_LOOKUP_new(comp) \ + ((STACK_OF(X509_LOOKUP) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b), \ + comp))) + +#define sk_X509_LOOKUP_new_null() ((STACK_OF(X509_LOOKUP) *)sk_new_null()) + +#define sk_X509_LOOKUP_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)) + +#define sk_X509_LOOKUP_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)); + +#define sk_X509_LOOKUP_value(sk, i) \ + ((X509_LOOKUP *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk), (i))) + +#define sk_X509_LOOKUP_set(sk, i, p) \ + ((X509_LOOKUP *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + (i), CHECKED_CAST(void *, X509_LOOKUP *, p))) + +#define sk_X509_LOOKUP_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)) + +#define sk_X509_LOOKUP_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_LOOKUP *), free_func)) + +#define sk_X509_LOOKUP_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void *, X509_LOOKUP *, p), (where)) + +#define sk_X509_LOOKUP_delete(sk, where) \ + ((X509_LOOKUP *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), (where))) + +#define sk_X509_LOOKUP_delete_ptr(sk, p) \ + ((X509_LOOKUP *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void *, X509_LOOKUP *, p))) + +#define sk_X509_LOOKUP_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_LOOKUP *, p)) + +#define sk_X509_LOOKUP_shift(sk) \ + ((X509_LOOKUP *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))) + +#define sk_X509_LOOKUP_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void *, X509_LOOKUP *, p)) + +#define sk_X509_LOOKUP_pop(sk) \ + ((X509_LOOKUP *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk))) + +#define sk_X509_LOOKUP_dup(sk) \ + ((STACK_OF(X509_LOOKUP) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk))) + +#define sk_X509_LOOKUP_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk)) + +#define sk_X509_LOOKUP_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_LOOKUP) *, sk)) + +#define sk_X509_LOOKUP_set_cmp_func(sk, comp) \ + ((int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_LOOKUP **a, const X509_LOOKUP **b), \ + comp))) + +#define sk_X509_LOOKUP_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_LOOKUP) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_LOOKUP) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_LOOKUP *(*)(X509_LOOKUP *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_LOOKUP *), free_func))) + +/* X509_NAME */ +#define sk_X509_NAME_new(comp) \ + ((STACK_OF(X509_NAME) *)sk_new( \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_NAME **a, const X509_NAME **b), comp))) + +#define sk_X509_NAME_new_null() ((STACK_OF(X509_NAME) *)sk_new_null()) + +#define sk_X509_NAME_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)) + +#define sk_X509_NAME_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)); + +#define sk_X509_NAME_value(sk, i) \ + ((X509_NAME *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk), (i))) + +#define sk_X509_NAME_set(sk, i, p) \ + ((X509_NAME *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), (i), \ + CHECKED_CAST(void *, X509_NAME *, p))) + +#define sk_X509_NAME_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)) + +#define sk_X509_NAME_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_NAME *), free_func)) + +#define sk_X509_NAME_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void *, X509_NAME *, p), (where)) + +#define sk_X509_NAME_delete(sk, where) \ + ((X509_NAME *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + (where))) + +#define sk_X509_NAME_delete_ptr(sk, p) \ + ((X509_NAME *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void *, X509_NAME *, p))) + +#define sk_X509_NAME_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_NAME *, p)) + +#define sk_X509_NAME_shift(sk) \ + ((X509_NAME *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))) + +#define sk_X509_NAME_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void *, X509_NAME *, p)) + +#define sk_X509_NAME_pop(sk) \ + ((X509_NAME *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk))) + +#define sk_X509_NAME_dup(sk) \ + ((STACK_OF(X509_NAME) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk))) + +#define sk_X509_NAME_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk)) + +#define sk_X509_NAME_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME) *, sk)) + +#define sk_X509_NAME_set_cmp_func(sk, comp) \ + ((int (*)(const X509_NAME **a, const X509_NAME **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_NAME **a, const X509_NAME **b), comp))) + +#define sk_X509_NAME_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_NAME) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_NAME *(*)(X509_NAME *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_NAME *), free_func))) + +/* X509_NAME_ENTRY */ +#define sk_X509_NAME_ENTRY_new(comp) \ + ((STACK_OF(X509_NAME_ENTRY) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b), comp))) + +#define sk_X509_NAME_ENTRY_new_null() \ + ((STACK_OF(X509_NAME_ENTRY) *)sk_new_null()) + +#define sk_X509_NAME_ENTRY_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)) + +#define sk_X509_NAME_ENTRY_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)); + +#define sk_X509_NAME_ENTRY_value(sk, i) \ + ((X509_NAME_ENTRY *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk), (i))) + +#define sk_X509_NAME_ENTRY_set(sk, i, p) \ + ((X509_NAME_ENTRY *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), (i), \ + CHECKED_CAST(void *, X509_NAME_ENTRY *, p))) + +#define sk_X509_NAME_ENTRY_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)) + +#define sk_X509_NAME_ENTRY_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_NAME_ENTRY *), free_func)) + +#define sk_X509_NAME_ENTRY_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, X509_NAME_ENTRY *, p), (where)) + +#define sk_X509_NAME_ENTRY_delete(sk, where) \ + ((X509_NAME_ENTRY *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), (where))) + +#define sk_X509_NAME_ENTRY_delete_ptr(sk, p) \ + ((X509_NAME_ENTRY *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, X509_NAME_ENTRY *, p))) + +#define sk_X509_NAME_ENTRY_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + (out_index), CHECKED_CAST(void *, X509_NAME_ENTRY *, p)) + +#define sk_X509_NAME_ENTRY_shift(sk) \ + ((X509_NAME_ENTRY *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))) + +#define sk_X509_NAME_ENTRY_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *, X509_NAME_ENTRY *, p)) + +#define sk_X509_NAME_ENTRY_pop(sk) \ + ((X509_NAME_ENTRY *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk))) + +#define sk_X509_NAME_ENTRY_dup(sk) \ + ((STACK_OF(X509_NAME_ENTRY) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk))) + +#define sk_X509_NAME_ENTRY_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk)) + +#define sk_X509_NAME_ENTRY_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk)) + +#define sk_X509_NAME_ENTRY_set_cmp_func(sk, comp) \ + ((int (*)(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_NAME_ENTRY **a, \ + const X509_NAME_ENTRY **b), \ + comp))) + +#define sk_X509_NAME_ENTRY_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_NAME_ENTRY) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_NAME_ENTRY) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_NAME_ENTRY *(*)(X509_NAME_ENTRY *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_NAME_ENTRY *), free_func))) + +/* X509_OBJECT */ +#define sk_X509_OBJECT_new(comp) \ + ((STACK_OF(X509_OBJECT) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_OBJECT **a, const X509_OBJECT **b), \ + comp))) + +#define sk_X509_OBJECT_new_null() ((STACK_OF(X509_OBJECT) *)sk_new_null()) + +#define sk_X509_OBJECT_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)) + +#define sk_X509_OBJECT_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)); + +#define sk_X509_OBJECT_value(sk, i) \ + ((X509_OBJECT *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk), (i))) + +#define sk_X509_OBJECT_set(sk, i, p) \ + ((X509_OBJECT *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + (i), CHECKED_CAST(void *, X509_OBJECT *, p))) + +#define sk_X509_OBJECT_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)) + +#define sk_X509_OBJECT_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_OBJECT *), free_func)) + +#define sk_X509_OBJECT_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void *, X509_OBJECT *, p), (where)) + +#define sk_X509_OBJECT_delete(sk, where) \ + ((X509_OBJECT *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), (where))) + +#define sk_X509_OBJECT_delete_ptr(sk, p) \ + ((X509_OBJECT *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void *, X509_OBJECT *, p))) + +#define sk_X509_OBJECT_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_OBJECT *, p)) + +#define sk_X509_OBJECT_shift(sk) \ + ((X509_OBJECT *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))) + +#define sk_X509_OBJECT_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void *, X509_OBJECT *, p)) + +#define sk_X509_OBJECT_pop(sk) \ + ((X509_OBJECT *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk))) + +#define sk_X509_OBJECT_dup(sk) \ + ((STACK_OF(X509_OBJECT) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk))) + +#define sk_X509_OBJECT_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk)) + +#define sk_X509_OBJECT_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_OBJECT) *, sk)) + +#define sk_X509_OBJECT_set_cmp_func(sk, comp) \ + ((int (*)(const X509_OBJECT **a, const X509_OBJECT **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_OBJECT **a, const X509_OBJECT **b), \ + comp))) + +#define sk_X509_OBJECT_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_OBJECT) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_OBJECT) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_OBJECT *(*)(X509_OBJECT *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_OBJECT *), free_func))) + +/* X509_POLICY_DATA */ +#define sk_X509_POLICY_DATA_new(comp) \ + ((STACK_OF(X509_POLICY_DATA) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_POLICY_DATA **a, const X509_POLICY_DATA **b), comp))) + +#define sk_X509_POLICY_DATA_new_null() \ + ((STACK_OF(X509_POLICY_DATA) *)sk_new_null()) + +#define sk_X509_POLICY_DATA_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)) + +#define sk_X509_POLICY_DATA_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)); + +#define sk_X509_POLICY_DATA_value(sk, i) \ + ((X509_POLICY_DATA *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk), (i))) + +#define sk_X509_POLICY_DATA_set(sk, i, p) \ + ((X509_POLICY_DATA *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), (i), \ + CHECKED_CAST(void *, X509_POLICY_DATA *, p))) + +#define sk_X509_POLICY_DATA_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)) + +#define sk_X509_POLICY_DATA_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_DATA *), free_func)) + +#define sk_X509_POLICY_DATA_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_DATA *, p), (where)) + +#define sk_X509_POLICY_DATA_delete(sk, where) \ + ((X509_POLICY_DATA *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), (where))) + +#define sk_X509_POLICY_DATA_delete_ptr(sk, p) \ + ((X509_POLICY_DATA *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_DATA *, p))) + +#define sk_X509_POLICY_DATA_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + (out_index), CHECKED_CAST(void *, X509_POLICY_DATA *, p)) + +#define sk_X509_POLICY_DATA_shift(sk) \ + ((X509_POLICY_DATA *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))) + +#define sk_X509_POLICY_DATA_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_DATA *, p)) + +#define sk_X509_POLICY_DATA_pop(sk) \ + ((X509_POLICY_DATA *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk))) + +#define sk_X509_POLICY_DATA_dup(sk) \ + ((STACK_OF(X509_POLICY_DATA) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk))) + +#define sk_X509_POLICY_DATA_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk)) + +#define sk_X509_POLICY_DATA_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_DATA) *, sk)) + +#define sk_X509_POLICY_DATA_set_cmp_func(sk, comp) \ + ((int (*)(const X509_POLICY_DATA **a, const X509_POLICY_DATA **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_POLICY_DATA **a, \ + const X509_POLICY_DATA **b), \ + comp))) + +#define sk_X509_POLICY_DATA_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_POLICY_DATA) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_DATA) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + X509_POLICY_DATA *(*)(X509_POLICY_DATA *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_DATA *), \ + free_func))) + +/* X509_POLICY_NODE */ +#define sk_X509_POLICY_NODE_new(comp) \ + ((STACK_OF(X509_POLICY_NODE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_POLICY_NODE **a, const X509_POLICY_NODE **b), comp))) + +#define sk_X509_POLICY_NODE_new_null() \ + ((STACK_OF(X509_POLICY_NODE) *)sk_new_null()) + +#define sk_X509_POLICY_NODE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)) + +#define sk_X509_POLICY_NODE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)); + +#define sk_X509_POLICY_NODE_value(sk, i) \ + ((X509_POLICY_NODE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk), (i))) + +#define sk_X509_POLICY_NODE_set(sk, i, p) \ + ((X509_POLICY_NODE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), (i), \ + CHECKED_CAST(void *, X509_POLICY_NODE *, p))) + +#define sk_X509_POLICY_NODE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)) + +#define sk_X509_POLICY_NODE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_NODE *), free_func)) + +#define sk_X509_POLICY_NODE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_NODE *, p), (where)) + +#define sk_X509_POLICY_NODE_delete(sk, where) \ + ((X509_POLICY_NODE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), (where))) + +#define sk_X509_POLICY_NODE_delete_ptr(sk, p) \ + ((X509_POLICY_NODE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_NODE *, p))) + +#define sk_X509_POLICY_NODE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + (out_index), CHECKED_CAST(void *, X509_POLICY_NODE *, p)) + +#define sk_X509_POLICY_NODE_shift(sk) \ + ((X509_POLICY_NODE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))) + +#define sk_X509_POLICY_NODE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void *, X509_POLICY_NODE *, p)) + +#define sk_X509_POLICY_NODE_pop(sk) \ + ((X509_POLICY_NODE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk))) + +#define sk_X509_POLICY_NODE_dup(sk) \ + ((STACK_OF(X509_POLICY_NODE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk))) + +#define sk_X509_POLICY_NODE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk)) + +#define sk_X509_POLICY_NODE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_POLICY_NODE) *, sk)) + +#define sk_X509_POLICY_NODE_set_cmp_func(sk, comp) \ + ((int (*)(const X509_POLICY_NODE **a, const X509_POLICY_NODE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_POLICY_NODE **a, \ + const X509_POLICY_NODE **b), \ + comp))) + +#define sk_X509_POLICY_NODE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_POLICY_NODE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_POLICY_NODE) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + X509_POLICY_NODE *(*)(X509_POLICY_NODE *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_POLICY_NODE *), \ + free_func))) + +/* X509_PURPOSE */ +#define sk_X509_PURPOSE_new(comp) \ + ((STACK_OF(X509_PURPOSE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b), \ + comp))) + +#define sk_X509_PURPOSE_new_null() ((STACK_OF(X509_PURPOSE) *)sk_new_null()) + +#define sk_X509_PURPOSE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)) + +#define sk_X509_PURPOSE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)); + +#define sk_X509_PURPOSE_value(sk, i) \ + ((X509_PURPOSE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk), (i))) + +#define sk_X509_PURPOSE_set(sk, i, p) \ + ((X509_PURPOSE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (i), \ + CHECKED_CAST(void *, X509_PURPOSE *, p))) + +#define sk_X509_PURPOSE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)) + +#define sk_X509_PURPOSE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_PURPOSE *), free_func)) + +#define sk_X509_PURPOSE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void *, X509_PURPOSE *, p), (where)) + +#define sk_X509_PURPOSE_delete(sk, where) \ + ((X509_PURPOSE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (where))) + +#define sk_X509_PURPOSE_delete_ptr(sk, p) \ + ((X509_PURPOSE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void *, X509_PURPOSE *, p))) + +#define sk_X509_PURPOSE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_PURPOSE *, p)) + +#define sk_X509_PURPOSE_shift(sk) \ + ((X509_PURPOSE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))) + +#define sk_X509_PURPOSE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void *, X509_PURPOSE *, p)) + +#define sk_X509_PURPOSE_pop(sk) \ + ((X509_PURPOSE *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk))) + +#define sk_X509_PURPOSE_dup(sk) \ + ((STACK_OF(X509_PURPOSE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk))) + +#define sk_X509_PURPOSE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk)) + +#define sk_X509_PURPOSE_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_PURPOSE) *, sk)) + +#define sk_X509_PURPOSE_set_cmp_func(sk, comp) \ + ((int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_PURPOSE **a, const X509_PURPOSE **b), \ + comp))) + +#define sk_X509_PURPOSE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_PURPOSE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_PURPOSE) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_PURPOSE *(*)(X509_PURPOSE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_PURPOSE *), free_func))) + +/* X509_REVOKED */ +#define sk_X509_REVOKED_new(comp) \ + ((STACK_OF(X509_REVOKED) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_REVOKED **a, const X509_REVOKED **b), \ + comp))) + +#define sk_X509_REVOKED_new_null() ((STACK_OF(X509_REVOKED) *)sk_new_null()) + +#define sk_X509_REVOKED_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)) + +#define sk_X509_REVOKED_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)); + +#define sk_X509_REVOKED_value(sk, i) \ + ((X509_REVOKED *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk), (i))) + +#define sk_X509_REVOKED_set(sk, i, p) \ + ((X509_REVOKED *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (i), \ + CHECKED_CAST(void *, X509_REVOKED *, p))) + +#define sk_X509_REVOKED_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)) + +#define sk_X509_REVOKED_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_REVOKED *), free_func)) + +#define sk_X509_REVOKED_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void *, X509_REVOKED *, p), (where)) + +#define sk_X509_REVOKED_delete(sk, where) \ + ((X509_REVOKED *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (where))) + +#define sk_X509_REVOKED_delete_ptr(sk, p) \ + ((X509_REVOKED *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void *, X509_REVOKED *, p))) + +#define sk_X509_REVOKED_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_REVOKED *, p)) + +#define sk_X509_REVOKED_shift(sk) \ + ((X509_REVOKED *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))) + +#define sk_X509_REVOKED_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void *, X509_REVOKED *, p)) + +#define sk_X509_REVOKED_pop(sk) \ + ((X509_REVOKED *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk))) + +#define sk_X509_REVOKED_dup(sk) \ + ((STACK_OF(X509_REVOKED) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk))) + +#define sk_X509_REVOKED_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk)) + +#define sk_X509_REVOKED_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_REVOKED) *, sk)) + +#define sk_X509_REVOKED_set_cmp_func(sk, comp) \ + ((int (*)(const X509_REVOKED **a, const X509_REVOKED **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_REVOKED **a, const X509_REVOKED **b), \ + comp))) + +#define sk_X509_REVOKED_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_REVOKED) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_REVOKED) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_REVOKED *(*)(X509_REVOKED *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_REVOKED *), free_func))) + +/* X509_TRUST */ +#define sk_X509_TRUST_new(comp) \ + ((STACK_OF(X509_TRUST) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const X509_TRUST **a, const X509_TRUST **b), \ + comp))) + +#define sk_X509_TRUST_new_null() ((STACK_OF(X509_TRUST) *)sk_new_null()) + +#define sk_X509_TRUST_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)) + +#define sk_X509_TRUST_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)); + +#define sk_X509_TRUST_value(sk, i) \ + ((X509_TRUST *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk), (i))) + +#define sk_X509_TRUST_set(sk, i, p) \ + ((X509_TRUST *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + (i), CHECKED_CAST(void *, X509_TRUST *, p))) + +#define sk_X509_TRUST_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)) + +#define sk_X509_TRUST_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_TRUST *), free_func)) + +#define sk_X509_TRUST_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void *, X509_TRUST *, p), (where)) + +#define sk_X509_TRUST_delete(sk, where) \ + ((X509_TRUST *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + (where))) + +#define sk_X509_TRUST_delete_ptr(sk, p) \ + ((X509_TRUST *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void *, X509_TRUST *, p))) + +#define sk_X509_TRUST_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), (out_index), \ + CHECKED_CAST(void *, X509_TRUST *, p)) + +#define sk_X509_TRUST_shift(sk) \ + ((X509_TRUST *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))) + +#define sk_X509_TRUST_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void *, X509_TRUST *, p)) + +#define sk_X509_TRUST_pop(sk) \ + ((X509_TRUST *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk))) + +#define sk_X509_TRUST_dup(sk) \ + ((STACK_OF(X509_TRUST) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk))) + +#define sk_X509_TRUST_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk)) + +#define sk_X509_TRUST_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_TRUST) *, sk)) + +#define sk_X509_TRUST_set_cmp_func(sk, comp) \ + ((int (*)(const X509_TRUST **a, const X509_TRUST **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const X509_TRUST **a, const X509_TRUST **b), \ + comp))) + +#define sk_X509_TRUST_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_TRUST) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_TRUST) *, sk), \ + CHECKED_CAST(void *(*)(void *), X509_TRUST *(*)(X509_TRUST *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_TRUST *), free_func))) + +/* X509_VERIFY_PARAM */ +#define sk_X509_VERIFY_PARAM_new(comp) \ + ((STACK_OF(X509_VERIFY_PARAM) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const X509_VERIFY_PARAM **a, const X509_VERIFY_PARAM **b), \ + comp))) + +#define sk_X509_VERIFY_PARAM_new_null() \ + ((STACK_OF(X509_VERIFY_PARAM) *)sk_new_null()) + +#define sk_X509_VERIFY_PARAM_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)) + +#define sk_X509_VERIFY_PARAM_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)); + +#define sk_X509_VERIFY_PARAM_value(sk, i) \ + ((X509_VERIFY_PARAM *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk), (i))) + +#define sk_X509_VERIFY_PARAM_set(sk, i, p) \ + ((X509_VERIFY_PARAM *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), (i), \ + CHECKED_CAST(void *, X509_VERIFY_PARAM *, p))) + +#define sk_X509_VERIFY_PARAM_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)) + +#define sk_X509_VERIFY_PARAM_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_VERIFY_PARAM *), \ + free_func)) + +#define sk_X509_VERIFY_PARAM_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void *, X509_VERIFY_PARAM *, p), (where)) + +#define sk_X509_VERIFY_PARAM_delete(sk, where) \ + ((X509_VERIFY_PARAM *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), (where))) + +#define sk_X509_VERIFY_PARAM_delete_ptr(sk, p) \ + ((X509_VERIFY_PARAM *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void *, X509_VERIFY_PARAM *, p))) + +#define sk_X509_VERIFY_PARAM_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + (out_index), CHECKED_CAST(void *, X509_VERIFY_PARAM *, p)) + +#define sk_X509_VERIFY_PARAM_shift(sk) \ + ((X509_VERIFY_PARAM *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk))) + +#define sk_X509_VERIFY_PARAM_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void *, X509_VERIFY_PARAM *, p)) + +#define sk_X509_VERIFY_PARAM_pop(sk) \ + ((X509_VERIFY_PARAM *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk))) + +#define sk_X509_VERIFY_PARAM_dup(sk) \ + ((STACK_OF(X509_VERIFY_PARAM) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk))) + +#define sk_X509_VERIFY_PARAM_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk)) + +#define sk_X509_VERIFY_PARAM_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk)) + +#define sk_X509_VERIFY_PARAM_set_cmp_func(sk, comp) \ + ((int (*)(const X509_VERIFY_PARAM **a, const X509_VERIFY_PARAM **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const X509_VERIFY_PARAM **a, \ + const X509_VERIFY_PARAM **b), \ + comp))) + +#define sk_X509_VERIFY_PARAM_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(X509_VERIFY_PARAM) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(X509_VERIFY_PARAM) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + X509_VERIFY_PARAM *(*)(X509_VERIFY_PARAM *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(X509_VERIFY_PARAM *), \ + free_func))) + +/* void */ +#define sk_void_new(comp) \ + ((STACK_OF(void)*)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const void **a, const void **b), comp))) + +#define sk_void_new_null() ((STACK_OF(void)*)sk_new_null()) + +#define sk_void_num(sk) sk_num(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)) + +#define sk_void_zero(sk) sk_zero(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)); + +#define sk_void_value(sk, i) \ + ((void *)sk_value(CHECKED_CAST(_STACK *, const STACK_OF(void) *, sk), (i))) + +#define sk_void_set(sk, i, p) \ + ((void *)sk_set(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (i), \ + CHECKED_CAST(void *, void *, p))) + +#define sk_void_free(sk) sk_free(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)) + +#define sk_void_pop_free(sk, free_func) \ + sk_pop_free(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(void *), free_func)) + +#define sk_void_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), \ + CHECKED_CAST(void *, void *, p), (where)) + +#define sk_void_delete(sk, where) \ + ((void *)sk_delete(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), (where))) + +#define sk_void_delete_ptr(sk, p) \ + ((void *)sk_delete_ptr(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \ + CHECKED_CAST(void *, void *, p))) + +#define sk_void_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), (out_index), \ + CHECKED_CAST(void *, void *, p)) + +#define sk_void_shift(sk) \ + ((void *)sk_shift(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))) + +#define sk_void_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk), \ + CHECKED_CAST(void *, void *, p)) + +#define sk_void_pop(sk) \ + ((void *)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(void)*, sk))) + +#define sk_void_dup(sk) \ + ((STACK_OF(void)*)sk_dup(CHECKED_CAST(_STACK *, const STACK_OF(void) *, sk))) + +#define sk_void_sort(sk) sk_sort(CHECKED_CAST(_STACK *, STACK_OF(void) *, sk)) + +#define sk_void_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(void) *, sk)) + +#define sk_void_set_cmp_func(sk, comp) \ + ((int (*)(const void **a, const void **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(void)*, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const void **a, const void **b), \ + comp))) + +#define sk_void_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(void)*)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(void) *, sk), \ + CHECKED_CAST(void *(*)(void *), void *(*)(void *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(void *), free_func))) + +/* SRTP_PROTECTION_PROFILE */ +#define sk_SRTP_PROTECTION_PROFILE_new(comp) \ + ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const const SRTP_PROTECTION_PROFILE **a, \ + const const SRTP_PROTECTION_PROFILE **b), \ + comp))) + +#define sk_SRTP_PROTECTION_PROFILE_new_null() \ + ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_new_null()) + +#define sk_SRTP_PROTECTION_PROFILE_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) + +#define sk_SRTP_PROTECTION_PROFILE_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)); + +#define sk_SRTP_PROTECTION_PROFILE_value(sk, i) \ + ((const SRTP_PROTECTION_PROFILE *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + (i))) + +#define sk_SRTP_PROTECTION_PROFILE_set(sk, i, p) \ + ((const SRTP_PROTECTION_PROFILE *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), (i), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p))) + +#define sk_SRTP_PROTECTION_PROFILE_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) + +#define sk_SRTP_PROTECTION_PROFILE_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(void (*)(void *), \ + void (*)(const SRTP_PROTECTION_PROFILE *), free_func)) + +#define sk_SRTP_PROTECTION_PROFILE_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p), (where)) + +#define sk_SRTP_PROTECTION_PROFILE_delete(sk, where) \ + ((const SRTP_PROTECTION_PROFILE *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + (where))) + +#define sk_SRTP_PROTECTION_PROFILE_delete_ptr(sk, p) \ + ((const SRTP_PROTECTION_PROFILE *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p))) + +#define sk_SRTP_PROTECTION_PROFILE_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + (out_index), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p)) + +#define sk_SRTP_PROTECTION_PROFILE_shift(sk) \ + ((const SRTP_PROTECTION_PROFILE *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))) + +#define sk_SRTP_PROTECTION_PROFILE_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(void *, const SRTP_PROTECTION_PROFILE *, p)) + +#define sk_SRTP_PROTECTION_PROFILE_pop(sk) \ + ((const SRTP_PROTECTION_PROFILE *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))) + +#define sk_SRTP_PROTECTION_PROFILE_dup(sk) \ + ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk))) + +#define sk_SRTP_PROTECTION_PROFILE_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) + +#define sk_SRTP_PROTECTION_PROFILE_is_sorted(sk) \ + sk_is_sorted( \ + CHECKED_CAST(_STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, sk)) + +#define sk_SRTP_PROTECTION_PROFILE_set_cmp_func(sk, comp) \ + ((int (*)(const SRTP_PROTECTION_PROFILE **a, \ + const SRTP_PROTECTION_PROFILE **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SRTP_PROTECTION_PROFILE) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SRTP_PROTECTION_PROFILE **a, \ + const SRTP_PROTECTION_PROFILE **b), \ + comp))) + +#define sk_SRTP_PROTECTION_PROFILE_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SRTP_PROTECTION_PROFILE) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SRTP_PROTECTION_PROFILE) *, \ + sk), \ + CHECKED_CAST(void *(*)(void *), const SRTP_PROTECTION_PROFILE *(*)( \ + const SRTP_PROTECTION_PROFILE *), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), \ + void (*)(const SRTP_PROTECTION_PROFILE *), free_func))) + +/* SSL_CIPHER */ +#define sk_SSL_CIPHER_new(comp) \ + ((STACK_OF(SSL_CIPHER) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const const SSL_CIPHER **a, const const SSL_CIPHER **b), comp))) + +#define sk_SSL_CIPHER_new_null() ((STACK_OF(SSL_CIPHER) *)sk_new_null()) + +#define sk_SSL_CIPHER_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)) + +#define sk_SSL_CIPHER_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)); + +#define sk_SSL_CIPHER_value(sk, i) \ + ((const SSL_CIPHER *)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk), (i))) + +#define sk_SSL_CIPHER_set(sk, i, p) \ + ((const SSL_CIPHER *)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), (i), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p))) + +#define sk_SSL_CIPHER_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)) + +#define sk_SSL_CIPHER_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(const SSL_CIPHER *), free_func)) + +#define sk_SSL_CIPHER_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p), (where)) + +#define sk_SSL_CIPHER_delete(sk, where) \ + ((const SSL_CIPHER *)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), (where))) + +#define sk_SSL_CIPHER_delete_ptr(sk, p) \ + ((const SSL_CIPHER *)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p))) + +#define sk_SSL_CIPHER_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), (out_index), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p)) + +#define sk_SSL_CIPHER_shift(sk) \ + ((const SSL_CIPHER *)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk))) + +#define sk_SSL_CIPHER_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void *, const SSL_CIPHER *, p)) + +#define sk_SSL_CIPHER_pop(sk) \ + ((const SSL_CIPHER *)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk))) + +#define sk_SSL_CIPHER_dup(sk) \ + ((STACK_OF(SSL_CIPHER) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk))) + +#define sk_SSL_CIPHER_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk)) + +#define sk_SSL_CIPHER_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(SSL_CIPHER) *, sk)) + +#define sk_SSL_CIPHER_set_cmp_func(sk, comp) \ + ((int (*)(const SSL_CIPHER **a, const SSL_CIPHER **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const SSL_CIPHER **a, const SSL_CIPHER **b), \ + comp))) + +#define sk_SSL_CIPHER_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(SSL_CIPHER) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(SSL_CIPHER) *, sk), \ + CHECKED_CAST(void *(*)(void *), \ + const SSL_CIPHER *(*)(const SSL_CIPHER *), copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(const SSL_CIPHER *), \ + free_func))) + +/* OPENSSL_STRING */ +#define sk_OPENSSL_STRING_new(comp) \ + ((STACK_OF(OPENSSL_STRING) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, \ + int (*)(const OPENSSL_STRING *a, const OPENSSL_STRING *b), comp))) + +#define sk_OPENSSL_STRING_new_null() ((STACK_OF(OPENSSL_STRING) *)sk_new_null()) + +#define sk_OPENSSL_STRING_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)) + +#define sk_OPENSSL_STRING_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)); + +#define sk_OPENSSL_STRING_value(sk, i) \ + ((OPENSSL_STRING)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk), (i))) + +#define sk_OPENSSL_STRING_set(sk, i, p) \ + ((OPENSSL_STRING)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), (i), \ + CHECKED_CAST(void *, OPENSSL_STRING, p))) + +#define sk_OPENSSL_STRING_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)) + +#define sk_OPENSSL_STRING_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_STRING), free_func)) + +#define sk_OPENSSL_STRING_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void *, OPENSSL_STRING, p), (where)) + +#define sk_OPENSSL_STRING_delete(sk, where) \ + ((OPENSSL_STRING)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), (where))) + +#define sk_OPENSSL_STRING_delete_ptr(sk, p) \ + ((OPENSSL_STRING)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void *, OPENSSL_STRING, p))) + +#define sk_OPENSSL_STRING_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), (out_index), \ + CHECKED_CAST(void *, OPENSSL_STRING, p)) + +#define sk_OPENSSL_STRING_shift(sk) \ + ((OPENSSL_STRING)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk))) + +#define sk_OPENSSL_STRING_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void *, OPENSSL_STRING, p)) + +#define sk_OPENSSL_STRING_pop(sk) \ + ((OPENSSL_STRING)sk_pop( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk))) + +#define sk_OPENSSL_STRING_dup(sk) \ + ((STACK_OF(OPENSSL_STRING) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk))) + +#define sk_OPENSSL_STRING_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk)) + +#define sk_OPENSSL_STRING_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_STRING) *, sk)) + +#define sk_OPENSSL_STRING_set_cmp_func(sk, comp) \ + ((int (*)(const OPENSSL_STRING **a, const OPENSSL_STRING **b)) \ + sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(stack_cmp_func, int (*)(const OPENSSL_STRING **a, \ + const OPENSSL_STRING **b), \ + comp))) + +#define sk_OPENSSL_STRING_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(OPENSSL_STRING) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(OPENSSL_STRING) *, sk), \ + CHECKED_CAST(void *(*)(void *), OPENSSL_STRING (*)(OPENSSL_STRING), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_STRING), free_func))) + +/* OPENSSL_BLOCK */ +#define sk_OPENSSL_BLOCK_new(comp) \ + ((STACK_OF(OPENSSL_BLOCK) *)sk_new(CHECKED_CAST( \ + stack_cmp_func, int (*)(const OPENSSL_BLOCK *a, const OPENSSL_BLOCK *b), \ + comp))) + +#define sk_OPENSSL_BLOCK_new_null() ((STACK_OF(OPENSSL_BLOCK) *)sk_new_null()) + +#define sk_OPENSSL_BLOCK_num(sk) \ + sk_num(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)) + +#define sk_OPENSSL_BLOCK_zero(sk) \ + sk_zero(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)); + +#define sk_OPENSSL_BLOCK_value(sk, i) \ + ((OPENSSL_BLOCK)sk_value( \ + CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk), (i))) + +#define sk_OPENSSL_BLOCK_set(sk, i, p) \ + ((OPENSSL_BLOCK)sk_set( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (i), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p))) + +#define sk_OPENSSL_BLOCK_free(sk) \ + sk_free(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)) + +#define sk_OPENSSL_BLOCK_pop_free(sk, free_func) \ + sk_pop_free( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_BLOCK), free_func)) + +#define sk_OPENSSL_BLOCK_insert(sk, p, where) \ + sk_insert(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p), (where)) + +#define sk_OPENSSL_BLOCK_delete(sk, where) \ + ((OPENSSL_BLOCK)sk_delete( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (where))) + +#define sk_OPENSSL_BLOCK_delete_ptr(sk, p) \ + ((OPENSSL_BLOCK)sk_delete_ptr( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p))) + +#define sk_OPENSSL_BLOCK_find(sk, out_index, p) \ + sk_find(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), (out_index), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p)) + +#define sk_OPENSSL_BLOCK_shift(sk) \ + ((OPENSSL_BLOCK)sk_shift( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk))) + +#define sk_OPENSSL_BLOCK_push(sk, p) \ + sk_push(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void *, OPENSSL_BLOCK, p)) + +#define sk_OPENSSL_BLOCK_pop(sk) \ + ((OPENSSL_BLOCK)sk_pop(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk))) + +#define sk_OPENSSL_BLOCK_dup(sk) \ + ((STACK_OF(OPENSSL_BLOCK) *)sk_dup( \ + CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk))) + +#define sk_OPENSSL_BLOCK_sort(sk) \ + sk_sort(CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk)) + +#define sk_OPENSSL_BLOCK_is_sorted(sk) \ + sk_is_sorted(CHECKED_CAST(_STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk)) + +#define sk_OPENSSL_BLOCK_set_cmp_func(sk, comp) \ + ((int (*)(const OPENSSL_BLOCK **a, const OPENSSL_BLOCK **b))sk_set_cmp_func( \ + CHECKED_CAST(_STACK *, STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(stack_cmp_func, \ + int (*)(const OPENSSL_BLOCK **a, const OPENSSL_BLOCK **b), \ + comp))) + +#define sk_OPENSSL_BLOCK_deep_copy(sk, copy_func, free_func) \ + ((STACK_OF(OPENSSL_BLOCK) *)sk_deep_copy( \ + CHECKED_CAST(const _STACK *, const STACK_OF(OPENSSL_BLOCK) *, sk), \ + CHECKED_CAST(void *(*)(void *), OPENSSL_BLOCK (*)(OPENSSL_BLOCK), \ + copy_func), \ + CHECKED_CAST(void (*)(void *), void (*)(OPENSSL_BLOCK), free_func))) diff --git a/TMessagesProj/jni/boringssl/include/openssl/thread.h b/TMessagesProj/jni/boringssl/include/openssl/thread.h new file mode 100644 index 00000000..568a8583 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/thread.h @@ -0,0 +1,173 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_THREAD_H +#define OPENSSL_HEADER_THREAD_H + +#include + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +#if defined(OPENSSL_NO_THREADS) +typedef struct crypto_mutex_st {} CRYPTO_MUTEX; +#elif defined(OPENSSL_WINDOWS) +/* CRYPTO_MUTEX can appear in public header files so we really don't want to + * pull in windows.h. It's statically asserted that this structure is large + * enough to contain a Windows CRITICAL_SECTION by thread_win.c. */ +typedef union crypto_mutex_st { + double alignment; + uint8_t padding[4*sizeof(void*) + 2*sizeof(int)]; +} CRYPTO_MUTEX; +#elif defined(__MACH__) && defined(__APPLE__) +typedef pthread_rwlock_t CRYPTO_MUTEX; +#else +/* It is reasonable to include pthread.h on non-Windows systems, however the + * |pthread_rwlock_t| that we need is hidden under feature flags, and we can't + * ensure that we'll be able to get it. It's statically asserted that this + * structure is large enough to contain a |pthread_rwlock_t| by + * thread_pthread.c. */ +typedef union crypto_mutex_st { + double alignment; + uint8_t padding[3*sizeof(int) + 5*sizeof(unsigned) + 16 + 8]; +} CRYPTO_MUTEX; +#endif + +/* CRYPTO_refcount_t is the type of a reference count. + * + * Since some platforms use C11 atomics to access this, it should have the + * _Atomic qualifier. However, this header is included by C++ programs as well + * as C code that might not set -std=c11. So, in practice, it's not possible to + * do that. Instead we statically assert that the size and native alignment of + * a plain uint32_t and an _Atomic uint32_t are equal in refcount_c11.c. */ +typedef uint32_t CRYPTO_refcount_t; + + +/* Deprecated functions */ + +/* These defines do nothing but are provided to make old code easier to + * compile. */ +#define CRYPTO_LOCK 1 +#define CRYPTO_UNLOCK 2 +#define CRYPTO_READ 4 +#define CRYPTO_WRITE 8 + +/* CRYPTO_num_locks returns one. (This is non-zero that callers who allocate + * sizeof(lock) times this value don't get zero and then fail because malloc(0) + * returned NULL.) */ +OPENSSL_EXPORT int CRYPTO_num_locks(void); + +/* CRYPTO_set_locking_callback does nothing. */ +OPENSSL_EXPORT void CRYPTO_set_locking_callback( + void (*func)(int mode, int lock_num, const char *file, int line)); + +/* CRYPTO_set_add_lock_callback does nothing. */ +OPENSSL_EXPORT void CRYPTO_set_add_lock_callback(int (*func)( + int *num, int amount, int lock_num, const char *file, int line)); + +/* CRYPTO_get_lock_name returns a fixed, dummy string. */ +OPENSSL_EXPORT const char *CRYPTO_get_lock_name(int lock_num); + +/* CRYPTO_THREADID_set_callback returns one. */ +OPENSSL_EXPORT int CRYPTO_THREADID_set_callback( + void (*threadid_func)(CRYPTO_THREADID *threadid)); + +/* CRYPTO_THREADID_set_numeric does nothing. */ +OPENSSL_EXPORT void CRYPTO_THREADID_set_numeric(CRYPTO_THREADID *id, + unsigned long val); + +/* CRYPTO_THREADID_set_pointer does nothing. */ +OPENSSL_EXPORT void CRYPTO_THREADID_set_pointer(CRYPTO_THREADID *id, void *ptr); + +/* CRYPTO_THREADID_current does nothing. */ +OPENSSL_EXPORT void CRYPTO_THREADID_current(CRYPTO_THREADID *id); + + +/* Private functions. + * + * Some old code calls these functions and so no-op implementations are + * provided. + * + * TODO(fork): cleanup callers and remove. */ + +OPENSSL_EXPORT void CRYPTO_set_id_callback(unsigned long (*func)(void)); + +typedef struct { + int references; + struct CRYPTO_dynlock_value *data; +} CRYPTO_dynlock; + +OPENSSL_EXPORT void CRYPTO_set_dynlock_create_callback( + struct CRYPTO_dynlock_value *(*dyn_create_function)(const char *file, + int line)); + +OPENSSL_EXPORT void CRYPTO_set_dynlock_lock_callback(void (*dyn_lock_function)( + int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)); + +OPENSSL_EXPORT void CRYPTO_set_dynlock_destroy_callback( + void (*dyn_destroy_function)(struct CRYPTO_dynlock_value *l, + const char *file, int line)); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_THREAD_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/time_support.h b/TMessagesProj/jni/boringssl/include/openssl/time_support.h new file mode 100644 index 00000000..912e6724 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/time_support.h @@ -0,0 +1,90 @@ +/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL + * project 2001. + * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 2008. + */ +/* ==================================================================== + * Copyright (c) 2001 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef OPENSSL_HEADER_TIME_H +#define OPENSSL_HEADER_TIME_H + +#include + + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Wrapper functions for time functions. */ + + +/* OPENSSL_gmtime wraps |gmtime_r|. See the manual page for that function. */ +struct tm *OPENSSL_gmtime(const time_t *timer, struct tm *result); + +/* OPENSSL_gmtime_adj updates |tm| by adding |offset_day| days and |offset_sec| + * seconds. */ +int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec); + +/* OPENSSL_gmtime_diff calculates the difference between |from| and |to| and + * outputs the difference as a number of days and seconds in |*out_days| and + * |*out_secs|. */ +int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from, + const struct tm *to); + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_TIME_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/tls1.h b/TMessagesProj/jni/boringssl/include/openssl/tls1.h new file mode 100644 index 00000000..b68db3d6 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/tls1.h @@ -0,0 +1,672 @@ +/* ssl/tls1.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2006 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * + * Portions of the attached software ("Contribution") are developed by + * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project. + * + * The Contribution is licensed pursuant to the OpenSSL open source + * license provided above. + * + * ECC cipher suite support in OpenSSL originally written by + * Vipul Gupta and Sumit Gupta of Sun Microsystems Laboratories. + * + */ +/* ==================================================================== + * Copyright 2005 Nokia. All rights reserved. + * + * The portions of the attached software ("Contribution") is developed by + * Nokia Corporation and is licensed pursuant to the OpenSSL open source + * license. + * + * The Contribution, originally written by Mika Kousa and Pasi Eronen of + * Nokia Corporation, consists of the "PSK" (Pre-Shared Key) ciphersuites + * support (see RFC 4279) to OpenSSL. + * + * No patent licenses or other rights except those expressly stated in + * the OpenSSL open source license shall be deemed granted or received + * expressly, by implication, estoppel, or otherwise. + * + * No assurances are provided by Nokia that the Contribution does not + * infringe the patent or other intellectual property rights of any third + * party or that the license provides you with all the necessary rights + * to make use of the Contribution. + * + * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. IN + * ADDITION TO THE DISCLAIMERS INCLUDED IN THE LICENSE, NOKIA + * SPECIFICALLY DISCLAIMS ANY LIABILITY FOR CLAIMS BROUGHT BY YOU OR ANY + * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR + * OTHERWISE. + */ + +#ifndef HEADER_TLS1_H +#define HEADER_TLS1_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES 0 + +#define TLS1_AD_DECRYPTION_FAILED 21 +#define TLS1_AD_RECORD_OVERFLOW 22 +#define TLS1_AD_UNKNOWN_CA 48 /* fatal */ +#define TLS1_AD_ACCESS_DENIED 49 /* fatal */ +#define TLS1_AD_DECODE_ERROR 50 /* fatal */ +#define TLS1_AD_DECRYPT_ERROR 51 +#define TLS1_AD_EXPORT_RESTRICTION 60 /* fatal */ +#define TLS1_AD_PROTOCOL_VERSION 70 /* fatal */ +#define TLS1_AD_INSUFFICIENT_SECURITY 71 /* fatal */ +#define TLS1_AD_INTERNAL_ERROR 80 /* fatal */ +#define TLS1_AD_USER_CANCELLED 90 +#define TLS1_AD_NO_RENEGOTIATION 100 +/* codes 110-114 are from RFC3546 */ +#define TLS1_AD_UNSUPPORTED_EXTENSION 110 +#define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111 +#define TLS1_AD_UNRECOGNIZED_NAME 112 +#define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113 +#define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114 +#define TLS1_AD_UNKNOWN_PSK_IDENTITY 115 /* fatal */ + +/* ExtensionType values from RFC3546 / RFC4366 / RFC6066 */ +#define TLSEXT_TYPE_server_name 0 +#define TLSEXT_TYPE_max_fragment_length 1 +#define TLSEXT_TYPE_client_certificate_url 2 +#define TLSEXT_TYPE_trusted_ca_keys 3 +#define TLSEXT_TYPE_truncated_hmac 4 +#define TLSEXT_TYPE_status_request 5 +/* ExtensionType values from RFC4681 */ +#define TLSEXT_TYPE_user_mapping 6 + +/* ExtensionType values from RFC5878 */ +#define TLSEXT_TYPE_client_authz 7 +#define TLSEXT_TYPE_server_authz 8 + +/* ExtensionType values from RFC6091 */ +#define TLSEXT_TYPE_cert_type 9 + +/* ExtensionType values from RFC4492 */ +#define TLSEXT_TYPE_elliptic_curves 10 +#define TLSEXT_TYPE_ec_point_formats 11 + +/* ExtensionType value from RFC5054 */ +#define TLSEXT_TYPE_srp 12 + +/* ExtensionType values from RFC5246 */ +#define TLSEXT_TYPE_signature_algorithms 13 + +/* ExtensionType value from RFC5764 */ +#define TLSEXT_TYPE_srtp 14 + +/* ExtensionType value from RFC5620 */ +#define TLSEXT_TYPE_heartbeat 15 + +/* ExtensionType value from RFC7301 */ +#define TLSEXT_TYPE_application_layer_protocol_negotiation 16 + +/* ExtensionType value for TLS padding extension. + * http://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml + * http://tools.ietf.org/html/draft-agl-tls-padding-03 + */ +#define TLSEXT_TYPE_padding 21 + +/* https://tools.ietf.org/html/draft-ietf-tls-session-hash-01 */ +#define TLSEXT_TYPE_extended_master_secret 23 + +/* ExtensionType value from RFC4507 */ +#define TLSEXT_TYPE_session_ticket 35 + +/* ExtensionType value from RFC5746 */ +#define TLSEXT_TYPE_renegotiate 0xff01 + +/* ExtensionType value from RFC6962 */ +#define TLSEXT_TYPE_certificate_timestamp 18 + +/* This is not an IANA defined extension number */ +#define TLSEXT_TYPE_next_proto_neg 13172 + +/* This is not an IANA defined extension number */ +#define TLSEXT_TYPE_channel_id 30032 + +/* NameType value from RFC 3546 */ +#define TLSEXT_NAMETYPE_host_name 0 +/* status request value from RFC 3546 */ +#define TLSEXT_STATUSTYPE_ocsp 1 + +/* ECPointFormat values from RFC 4492 */ +#define TLSEXT_ECPOINTFORMAT_uncompressed 0 +#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_prime 1 +#define TLSEXT_ECPOINTFORMAT_ansiX962_compressed_char2 2 + +/* Signature and hash algorithms from RFC 5246 */ + +#define TLSEXT_signature_anonymous 0 +#define TLSEXT_signature_rsa 1 +#define TLSEXT_signature_dsa 2 +#define TLSEXT_signature_ecdsa 3 + +#define TLSEXT_hash_none 0 +#define TLSEXT_hash_md5 1 +#define TLSEXT_hash_sha1 2 +#define TLSEXT_hash_sha224 3 +#define TLSEXT_hash_sha256 4 +#define TLSEXT_hash_sha384 5 +#define TLSEXT_hash_sha512 6 + +/* Flag set for unrecognised algorithms */ +#define TLSEXT_nid_unknown 0x1000000 + +/* ECC curves */ + +#define TLSEXT_curve_P_256 23 +#define TLSEXT_curve_P_384 24 + + +#define TLSEXT_MAXLEN_host_name 255 + +OPENSSL_EXPORT const char *SSL_get_servername(const SSL *s, const int type); +OPENSSL_EXPORT int SSL_get_servername_type(const SSL *s); + +/* SSL_export_keying_material exports a value derived from the master secret, as + * specified in RFC 5705. It writes |out_len| bytes to |out| given a label and + * optional context. (Since a zero length context is allowed, the |use_context| + * flag controls whether a context is included.) + * + * It returns one on success and zero otherwise. */ +OPENSSL_EXPORT int SSL_export_keying_material( + SSL *s, uint8_t *out, size_t out_len, const char *label, size_t label_len, + const uint8_t *context, size_t context_len, int use_context); + +/* SSL_set_tlsext_host_name, for a client, configures |ssl| to advertise |name| + * in the server_name extension. It returns one on success and zero on error. */ +OPENSSL_EXPORT int SSL_set_tlsext_host_name(SSL *ssl, const char *name); + +/* SSL_CTX_set_tlsext_servername_callback configures |callback| to be called on + * the server after ClientHello extensions have been parsed and returns one. + * |callback| may use |SSL_get_servername| to examine the server_name extension + * and return a |SSL_TLSEXT_ERR_*| value. If it returns |SSL_TLSEXT_ERR_NOACK|, + * the server_name extension is not acknowledged in the ServerHello. If the + * return value signals an alert, |callback| should set |*out_alert| to the + * alert to send. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_servername_callback( + SSL_CTX *ctx, int (*callback)(SSL *ssl, int *out_alert, void *arg)); + +#define SSL_TLSEXT_ERR_OK 0 +#define SSL_TLSEXT_ERR_ALERT_WARNING 1 +#define SSL_TLSEXT_ERR_ALERT_FATAL 2 +#define SSL_TLSEXT_ERR_NOACK 3 + +/* SSL_CTX_set_tlsext_servername_arg sets the argument to the servername + * callback and returns one. See |SSL_CTX_set_tlsext_servername_callback|. */ +OPENSSL_EXPORT int SSL_CTX_set_tlsext_servername_arg(SSL_CTX *ctx, void *arg); + +/* PSK ciphersuites from 4279 */ +#define TLS1_CK_PSK_WITH_RC4_128_SHA 0x0300008A +#define TLS1_CK_PSK_WITH_3DES_EDE_CBC_SHA 0x0300008B +#define TLS1_CK_PSK_WITH_AES_128_CBC_SHA 0x0300008C +#define TLS1_CK_PSK_WITH_AES_256_CBC_SHA 0x0300008D + +/* PSK ciphersuites from RFC 5489 */ +#define TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA 0x0300C035 +#define TLS1_CK_ECDHE_PSK_WITH_AES_256_CBC_SHA 0x0300C036 + +/* Additional TLS ciphersuites from expired Internet Draft + * draft-ietf-tls-56-bit-ciphersuites-01.txt + * (available if TLS1_ALLOW_EXPERIMENTAL_CIPHERSUITES is defined, see + * s3_lib.c). We actually treat them like SSL 3.0 ciphers, which we probably + * shouldn't. Note that the first two are actually not in the IDs. */ +#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_MD5 0x03000060 /* not in ID */ +#define TLS1_CK_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 0x03000061 /* not in ID */ +#define TLS1_CK_RSA_EXPORT1024_WITH_DES_CBC_SHA 0x03000062 +#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA 0x03000063 +#define TLS1_CK_RSA_EXPORT1024_WITH_RC4_56_SHA 0x03000064 +#define TLS1_CK_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA 0x03000065 +#define TLS1_CK_DHE_DSS_WITH_RC4_128_SHA 0x03000066 + +/* AES ciphersuites from RFC3268 */ + +#define TLS1_CK_RSA_WITH_AES_128_SHA 0x0300002F +#define TLS1_CK_DH_DSS_WITH_AES_128_SHA 0x03000030 +#define TLS1_CK_DH_RSA_WITH_AES_128_SHA 0x03000031 +#define TLS1_CK_DHE_DSS_WITH_AES_128_SHA 0x03000032 +#define TLS1_CK_DHE_RSA_WITH_AES_128_SHA 0x03000033 +#define TLS1_CK_ADH_WITH_AES_128_SHA 0x03000034 + +#define TLS1_CK_RSA_WITH_AES_256_SHA 0x03000035 +#define TLS1_CK_DH_DSS_WITH_AES_256_SHA 0x03000036 +#define TLS1_CK_DH_RSA_WITH_AES_256_SHA 0x03000037 +#define TLS1_CK_DHE_DSS_WITH_AES_256_SHA 0x03000038 +#define TLS1_CK_DHE_RSA_WITH_AES_256_SHA 0x03000039 +#define TLS1_CK_ADH_WITH_AES_256_SHA 0x0300003A + +/* TLS v1.2 ciphersuites */ +#define TLS1_CK_RSA_WITH_NULL_SHA256 0x0300003B +#define TLS1_CK_RSA_WITH_AES_128_SHA256 0x0300003C +#define TLS1_CK_RSA_WITH_AES_256_SHA256 0x0300003D +#define TLS1_CK_DH_DSS_WITH_AES_128_SHA256 0x0300003E +#define TLS1_CK_DH_RSA_WITH_AES_128_SHA256 0x0300003F +#define TLS1_CK_DHE_DSS_WITH_AES_128_SHA256 0x03000040 + +/* Camellia ciphersuites from RFC4132 */ +#define TLS1_CK_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000041 +#define TLS1_CK_DH_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000042 +#define TLS1_CK_DH_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000043 +#define TLS1_CK_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA 0x03000044 +#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA 0x03000045 +#define TLS1_CK_ADH_WITH_CAMELLIA_128_CBC_SHA 0x03000046 + +/* TLS v1.2 ciphersuites */ +#define TLS1_CK_DHE_RSA_WITH_AES_128_SHA256 0x03000067 +#define TLS1_CK_DH_DSS_WITH_AES_256_SHA256 0x03000068 +#define TLS1_CK_DH_RSA_WITH_AES_256_SHA256 0x03000069 +#define TLS1_CK_DHE_DSS_WITH_AES_256_SHA256 0x0300006A +#define TLS1_CK_DHE_RSA_WITH_AES_256_SHA256 0x0300006B +#define TLS1_CK_ADH_WITH_AES_128_SHA256 0x0300006C +#define TLS1_CK_ADH_WITH_AES_256_SHA256 0x0300006D + +/* Camellia ciphersuites from RFC4132 */ +#define TLS1_CK_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000084 +#define TLS1_CK_DH_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000085 +#define TLS1_CK_DH_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000086 +#define TLS1_CK_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA 0x03000087 +#define TLS1_CK_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x03000088 +#define TLS1_CK_ADH_WITH_CAMELLIA_256_CBC_SHA 0x03000089 + +/* SEED ciphersuites from RFC4162 */ +#define TLS1_CK_RSA_WITH_SEED_SHA 0x03000096 +#define TLS1_CK_DH_DSS_WITH_SEED_SHA 0x03000097 +#define TLS1_CK_DH_RSA_WITH_SEED_SHA 0x03000098 +#define TLS1_CK_DHE_DSS_WITH_SEED_SHA 0x03000099 +#define TLS1_CK_DHE_RSA_WITH_SEED_SHA 0x0300009A +#define TLS1_CK_ADH_WITH_SEED_SHA 0x0300009B + +/* TLS v1.2 GCM ciphersuites from RFC5288 */ +#define TLS1_CK_RSA_WITH_AES_128_GCM_SHA256 0x0300009C +#define TLS1_CK_RSA_WITH_AES_256_GCM_SHA384 0x0300009D +#define TLS1_CK_DHE_RSA_WITH_AES_128_GCM_SHA256 0x0300009E +#define TLS1_CK_DHE_RSA_WITH_AES_256_GCM_SHA384 0x0300009F +#define TLS1_CK_DH_RSA_WITH_AES_128_GCM_SHA256 0x030000A0 +#define TLS1_CK_DH_RSA_WITH_AES_256_GCM_SHA384 0x030000A1 +#define TLS1_CK_DHE_DSS_WITH_AES_128_GCM_SHA256 0x030000A2 +#define TLS1_CK_DHE_DSS_WITH_AES_256_GCM_SHA384 0x030000A3 +#define TLS1_CK_DH_DSS_WITH_AES_128_GCM_SHA256 0x030000A4 +#define TLS1_CK_DH_DSS_WITH_AES_256_GCM_SHA384 0x030000A5 +#define TLS1_CK_ADH_WITH_AES_128_GCM_SHA256 0x030000A6 +#define TLS1_CK_ADH_WITH_AES_256_GCM_SHA384 0x030000A7 + +/* ECC ciphersuites from RFC4492 */ +#define TLS1_CK_ECDH_ECDSA_WITH_NULL_SHA 0x0300C001 +#define TLS1_CK_ECDH_ECDSA_WITH_RC4_128_SHA 0x0300C002 +#define TLS1_CK_ECDH_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C003 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0x0300C004 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0x0300C005 + +#define TLS1_CK_ECDHE_ECDSA_WITH_NULL_SHA 0x0300C006 +#define TLS1_CK_ECDHE_ECDSA_WITH_RC4_128_SHA 0x0300C007 +#define TLS1_CK_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA 0x0300C008 +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0x0300C009 +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0x0300C00A + +#define TLS1_CK_ECDH_RSA_WITH_NULL_SHA 0x0300C00B +#define TLS1_CK_ECDH_RSA_WITH_RC4_128_SHA 0x0300C00C +#define TLS1_CK_ECDH_RSA_WITH_DES_192_CBC3_SHA 0x0300C00D +#define TLS1_CK_ECDH_RSA_WITH_AES_128_CBC_SHA 0x0300C00E +#define TLS1_CK_ECDH_RSA_WITH_AES_256_CBC_SHA 0x0300C00F + +#define TLS1_CK_ECDHE_RSA_WITH_NULL_SHA 0x0300C010 +#define TLS1_CK_ECDHE_RSA_WITH_RC4_128_SHA 0x0300C011 +#define TLS1_CK_ECDHE_RSA_WITH_DES_192_CBC3_SHA 0x0300C012 +#define TLS1_CK_ECDHE_RSA_WITH_AES_128_CBC_SHA 0x0300C013 +#define TLS1_CK_ECDHE_RSA_WITH_AES_256_CBC_SHA 0x0300C014 + +#define TLS1_CK_ECDH_anon_WITH_NULL_SHA 0x0300C015 +#define TLS1_CK_ECDH_anon_WITH_RC4_128_SHA 0x0300C016 +#define TLS1_CK_ECDH_anon_WITH_DES_192_CBC3_SHA 0x0300C017 +#define TLS1_CK_ECDH_anon_WITH_AES_128_CBC_SHA 0x0300C018 +#define TLS1_CK_ECDH_anon_WITH_AES_256_CBC_SHA 0x0300C019 + +/* SRP ciphersuites from RFC 5054 */ +#define TLS1_CK_SRP_SHA_WITH_3DES_EDE_CBC_SHA 0x0300C01A +#define TLS1_CK_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA 0x0300C01B +#define TLS1_CK_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA 0x0300C01C +#define TLS1_CK_SRP_SHA_WITH_AES_128_CBC_SHA 0x0300C01D +#define TLS1_CK_SRP_SHA_RSA_WITH_AES_128_CBC_SHA 0x0300C01E +#define TLS1_CK_SRP_SHA_DSS_WITH_AES_128_CBC_SHA 0x0300C01F +#define TLS1_CK_SRP_SHA_WITH_AES_256_CBC_SHA 0x0300C020 +#define TLS1_CK_SRP_SHA_RSA_WITH_AES_256_CBC_SHA 0x0300C021 +#define TLS1_CK_SRP_SHA_DSS_WITH_AES_256_CBC_SHA 0x0300C022 + +/* ECDH HMAC based ciphersuites from RFC5289 */ + +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_SHA256 0x0300C023 +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_SHA384 0x0300C024 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_SHA256 0x0300C025 +#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_SHA384 0x0300C026 +#define TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256 0x0300C027 +#define TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384 0x0300C028 +#define TLS1_CK_ECDH_RSA_WITH_AES_128_SHA256 0x0300C029 +#define TLS1_CK_ECDH_RSA_WITH_AES_256_SHA384 0x0300C02A + +/* ECDH GCM based ciphersuites from RFC5289 */ +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0x0300C02B +#define TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0x0300C02C +#define TLS1_CK_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0x0300C02D +#define TLS1_CK_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0x0300C02E +#define TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0x0300C02F +#define TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0x0300C030 +#define TLS1_CK_ECDH_RSA_WITH_AES_128_GCM_SHA256 0x0300C031 +#define TLS1_CK_ECDH_RSA_WITH_AES_256_GCM_SHA384 0x0300C032 + +#define TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305 0x0300CC13 +#define TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305 0x0300CC14 +#define TLS1_CK_DHE_RSA_CHACHA20_POLY1305 0x0300CC15 + +/* XXX + * Inconsistency alert: + * The OpenSSL names of ciphers with ephemeral DH here include the string + * "DHE", while elsewhere it has always been "EDH". + * (The alias for the list of all such ciphers also is "EDH".) + * The specifications speak of "EDH"; maybe we should allow both forms + * for everything. */ +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_MD5 "EXP1024-RC4-MD5" +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 "EXP1024-RC2-CBC-MD5" +#define TLS1_TXT_RSA_EXPORT1024_WITH_DES_CBC_SHA "EXP1024-DES-CBC-SHA" +#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA \ + "EXP1024-DHE-DSS-DES-CBC-SHA" +#define TLS1_TXT_RSA_EXPORT1024_WITH_RC4_56_SHA "EXP1024-RC4-SHA" +#define TLS1_TXT_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA "EXP1024-DHE-DSS-RC4-SHA" +#define TLS1_TXT_DHE_DSS_WITH_RC4_128_SHA "DHE-DSS-RC4-SHA" + +/* AES ciphersuites from RFC3268 */ +#define TLS1_TXT_RSA_WITH_AES_128_SHA "AES128-SHA" +#define TLS1_TXT_DH_DSS_WITH_AES_128_SHA "DH-DSS-AES128-SHA" +#define TLS1_TXT_DH_RSA_WITH_AES_128_SHA "DH-RSA-AES128-SHA" +#define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA "DHE-DSS-AES128-SHA" +#define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA "DHE-RSA-AES128-SHA" +#define TLS1_TXT_ADH_WITH_AES_128_SHA "ADH-AES128-SHA" + +#define TLS1_TXT_RSA_WITH_AES_256_SHA "AES256-SHA" +#define TLS1_TXT_DH_DSS_WITH_AES_256_SHA "DH-DSS-AES256-SHA" +#define TLS1_TXT_DH_RSA_WITH_AES_256_SHA "DH-RSA-AES256-SHA" +#define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA "DHE-DSS-AES256-SHA" +#define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA "DHE-RSA-AES256-SHA" +#define TLS1_TXT_ADH_WITH_AES_256_SHA "ADH-AES256-SHA" + +/* ECC ciphersuites from RFC4492 */ +#define TLS1_TXT_ECDH_ECDSA_WITH_NULL_SHA "ECDH-ECDSA-NULL-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_RC4_128_SHA "ECDH-ECDSA-RC4-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_DES_192_CBC3_SHA "ECDH-ECDSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_CBC_SHA "ECDH-ECDSA-AES128-SHA" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_CBC_SHA "ECDH-ECDSA-AES256-SHA" + +#define TLS1_TXT_ECDHE_ECDSA_WITH_NULL_SHA "ECDHE-ECDSA-NULL-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_RC4_128_SHA "ECDHE-ECDSA-RC4-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_DES_192_CBC3_SHA "ECDHE-ECDSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_CBC_SHA "ECDHE-ECDSA-AES128-SHA" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_CBC_SHA "ECDHE-ECDSA-AES256-SHA" + +#define TLS1_TXT_ECDH_RSA_WITH_NULL_SHA "ECDH-RSA-NULL-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_RC4_128_SHA "ECDH-RSA-RC4-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_DES_192_CBC3_SHA "ECDH-RSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_AES_128_CBC_SHA "ECDH-RSA-AES128-SHA" +#define TLS1_TXT_ECDH_RSA_WITH_AES_256_CBC_SHA "ECDH-RSA-AES256-SHA" + +#define TLS1_TXT_ECDHE_RSA_WITH_NULL_SHA "ECDHE-RSA-NULL-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_RC4_128_SHA "ECDHE-RSA-RC4-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_DES_192_CBC3_SHA "ECDHE-RSA-DES-CBC3-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_CBC_SHA "ECDHE-RSA-AES128-SHA" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_CBC_SHA "ECDHE-RSA-AES256-SHA" + +#define TLS1_TXT_ECDH_anon_WITH_NULL_SHA "AECDH-NULL-SHA" +#define TLS1_TXT_ECDH_anon_WITH_RC4_128_SHA "AECDH-RC4-SHA" +#define TLS1_TXT_ECDH_anon_WITH_DES_192_CBC3_SHA "AECDH-DES-CBC3-SHA" +#define TLS1_TXT_ECDH_anon_WITH_AES_128_CBC_SHA "AECDH-AES128-SHA" +#define TLS1_TXT_ECDH_anon_WITH_AES_256_CBC_SHA "AECDH-AES256-SHA" + +/* PSK ciphersuites from RFC 4279 */ +#define TLS1_TXT_PSK_WITH_RC4_128_SHA "PSK-RC4-SHA" +#define TLS1_TXT_PSK_WITH_3DES_EDE_CBC_SHA "PSK-3DES-EDE-CBC-SHA" +#define TLS1_TXT_PSK_WITH_AES_128_CBC_SHA "PSK-AES128-CBC-SHA" +#define TLS1_TXT_PSK_WITH_AES_256_CBC_SHA "PSK-AES256-CBC-SHA" + +/* PSK ciphersuites from RFC 5489 */ +#define TLS1_TXT_ECDHE_PSK_WITH_AES_128_CBC_SHA "ECDHE-PSK-AES128-CBC-SHA" +#define TLS1_TXT_ECDHE_PSK_WITH_AES_256_CBC_SHA "ECDHE-PSK-AES256-CBC-SHA" + +/* SRP ciphersuite from RFC 5054 */ +#define TLS1_TXT_SRP_SHA_WITH_3DES_EDE_CBC_SHA "SRP-3DES-EDE-CBC-SHA" +#define TLS1_TXT_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA "SRP-RSA-3DES-EDE-CBC-SHA" +#define TLS1_TXT_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA "SRP-DSS-3DES-EDE-CBC-SHA" +#define TLS1_TXT_SRP_SHA_WITH_AES_128_CBC_SHA "SRP-AES-128-CBC-SHA" +#define TLS1_TXT_SRP_SHA_RSA_WITH_AES_128_CBC_SHA "SRP-RSA-AES-128-CBC-SHA" +#define TLS1_TXT_SRP_SHA_DSS_WITH_AES_128_CBC_SHA "SRP-DSS-AES-128-CBC-SHA" +#define TLS1_TXT_SRP_SHA_WITH_AES_256_CBC_SHA "SRP-AES-256-CBC-SHA" +#define TLS1_TXT_SRP_SHA_RSA_WITH_AES_256_CBC_SHA "SRP-RSA-AES-256-CBC-SHA" +#define TLS1_TXT_SRP_SHA_DSS_WITH_AES_256_CBC_SHA "SRP-DSS-AES-256-CBC-SHA" + +/* Camellia ciphersuites from RFC4132 */ +#define TLS1_TXT_RSA_WITH_CAMELLIA_128_CBC_SHA "CAMELLIA128-SHA" +#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_128_CBC_SHA "DH-DSS-CAMELLIA128-SHA" +#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_128_CBC_SHA "DH-RSA-CAMELLIA128-SHA" +#define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA "DHE-DSS-CAMELLIA128-SHA" +#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA "DHE-RSA-CAMELLIA128-SHA" +#define TLS1_TXT_ADH_WITH_CAMELLIA_128_CBC_SHA "ADH-CAMELLIA128-SHA" + +#define TLS1_TXT_RSA_WITH_CAMELLIA_256_CBC_SHA "CAMELLIA256-SHA" +#define TLS1_TXT_DH_DSS_WITH_CAMELLIA_256_CBC_SHA "DH-DSS-CAMELLIA256-SHA" +#define TLS1_TXT_DH_RSA_WITH_CAMELLIA_256_CBC_SHA "DH-RSA-CAMELLIA256-SHA" +#define TLS1_TXT_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA "DHE-DSS-CAMELLIA256-SHA" +#define TLS1_TXT_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA "DHE-RSA-CAMELLIA256-SHA" +#define TLS1_TXT_ADH_WITH_CAMELLIA_256_CBC_SHA "ADH-CAMELLIA256-SHA" + +/* SEED ciphersuites from RFC4162 */ +#define TLS1_TXT_RSA_WITH_SEED_SHA "SEED-SHA" +#define TLS1_TXT_DH_DSS_WITH_SEED_SHA "DH-DSS-SEED-SHA" +#define TLS1_TXT_DH_RSA_WITH_SEED_SHA "DH-RSA-SEED-SHA" +#define TLS1_TXT_DHE_DSS_WITH_SEED_SHA "DHE-DSS-SEED-SHA" +#define TLS1_TXT_DHE_RSA_WITH_SEED_SHA "DHE-RSA-SEED-SHA" +#define TLS1_TXT_ADH_WITH_SEED_SHA "ADH-SEED-SHA" + +/* TLS v1.2 ciphersuites */ +#define TLS1_TXT_RSA_WITH_NULL_SHA256 "NULL-SHA256" +#define TLS1_TXT_RSA_WITH_AES_128_SHA256 "AES128-SHA256" +#define TLS1_TXT_RSA_WITH_AES_256_SHA256 "AES256-SHA256" +#define TLS1_TXT_DH_DSS_WITH_AES_128_SHA256 "DH-DSS-AES128-SHA256" +#define TLS1_TXT_DH_RSA_WITH_AES_128_SHA256 "DH-RSA-AES128-SHA256" +#define TLS1_TXT_DHE_DSS_WITH_AES_128_SHA256 "DHE-DSS-AES128-SHA256" +#define TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256 "DHE-RSA-AES128-SHA256" +#define TLS1_TXT_DH_DSS_WITH_AES_256_SHA256 "DH-DSS-AES256-SHA256" +#define TLS1_TXT_DH_RSA_WITH_AES_256_SHA256 "DH-RSA-AES256-SHA256" +#define TLS1_TXT_DHE_DSS_WITH_AES_256_SHA256 "DHE-DSS-AES256-SHA256" +#define TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256 "DHE-RSA-AES256-SHA256" +#define TLS1_TXT_ADH_WITH_AES_128_SHA256 "ADH-AES128-SHA256" +#define TLS1_TXT_ADH_WITH_AES_256_SHA256 "ADH-AES256-SHA256" + +/* TLS v1.2 GCM ciphersuites from RFC5288 */ +#define TLS1_TXT_RSA_WITH_AES_128_GCM_SHA256 "AES128-GCM-SHA256" +#define TLS1_TXT_RSA_WITH_AES_256_GCM_SHA384 "AES256-GCM-SHA384" +#define TLS1_TXT_DHE_RSA_WITH_AES_128_GCM_SHA256 "DHE-RSA-AES128-GCM-SHA256" +#define TLS1_TXT_DHE_RSA_WITH_AES_256_GCM_SHA384 "DHE-RSA-AES256-GCM-SHA384" +#define TLS1_TXT_DH_RSA_WITH_AES_128_GCM_SHA256 "DH-RSA-AES128-GCM-SHA256" +#define TLS1_TXT_DH_RSA_WITH_AES_256_GCM_SHA384 "DH-RSA-AES256-GCM-SHA384" +#define TLS1_TXT_DHE_DSS_WITH_AES_128_GCM_SHA256 "DHE-DSS-AES128-GCM-SHA256" +#define TLS1_TXT_DHE_DSS_WITH_AES_256_GCM_SHA384 "DHE-DSS-AES256-GCM-SHA384" +#define TLS1_TXT_DH_DSS_WITH_AES_128_GCM_SHA256 "DH-DSS-AES128-GCM-SHA256" +#define TLS1_TXT_DH_DSS_WITH_AES_256_GCM_SHA384 "DH-DSS-AES256-GCM-SHA384" +#define TLS1_TXT_ADH_WITH_AES_128_GCM_SHA256 "ADH-AES128-GCM-SHA256" +#define TLS1_TXT_ADH_WITH_AES_256_GCM_SHA384 "ADH-AES256-GCM-SHA384" + +/* ECDH HMAC based ciphersuites from RFC5289 */ + +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_SHA256 "ECDHE-ECDSA-AES128-SHA256" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_SHA384 "ECDHE-ECDSA-AES256-SHA384" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_SHA256 "ECDH-ECDSA-AES128-SHA256" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_SHA384 "ECDH-ECDSA-AES256-SHA384" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_SHA256 "ECDHE-RSA-AES128-SHA256" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_SHA384 "ECDHE-RSA-AES256-SHA384" +#define TLS1_TXT_ECDH_RSA_WITH_AES_128_SHA256 "ECDH-RSA-AES128-SHA256" +#define TLS1_TXT_ECDH_RSA_WITH_AES_256_SHA384 "ECDH-RSA-AES256-SHA384" + +/* ECDH GCM based ciphersuites from RFC5289 */ +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 \ + "ECDHE-ECDSA-AES128-GCM-SHA256" +#define TLS1_TXT_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 \ + "ECDHE-ECDSA-AES256-GCM-SHA384" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 \ + "ECDH-ECDSA-AES128-GCM-SHA256" +#define TLS1_TXT_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 \ + "ECDH-ECDSA-AES256-GCM-SHA384" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256 "ECDHE-RSA-AES128-GCM-SHA256" +#define TLS1_TXT_ECDHE_RSA_WITH_AES_256_GCM_SHA384 "ECDHE-RSA-AES256-GCM-SHA384" +#define TLS1_TXT_ECDH_RSA_WITH_AES_128_GCM_SHA256 "ECDH-RSA-AES128-GCM-SHA256" +#define TLS1_TXT_ECDH_RSA_WITH_AES_256_GCM_SHA384 "ECDH-RSA-AES256-GCM-SHA384" + +#define TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 "ECDHE-RSA-CHACHA20-POLY1305" +#define TLS1_TXT_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 \ + "ECDHE-ECDSA-CHACHA20-POLY1305" +#define TLS1_TXT_DHE_RSA_WITH_CHACHA20_POLY1305 "DHE-RSA-CHACHA20-POLY1305" + +#define TLS_CT_RSA_SIGN 1 +#define TLS_CT_DSS_SIGN 2 +#define TLS_CT_RSA_FIXED_DH 3 +#define TLS_CT_DSS_FIXED_DH 4 +#define TLS_CT_ECDSA_SIGN 64 +#define TLS_CT_RSA_FIXED_ECDH 65 +#define TLS_CT_ECDSA_FIXED_ECDH 66 + +#define TLS_MD_MAX_CONST_SIZE 20 +#define TLS_MD_CLIENT_FINISH_CONST "client finished" +#define TLS_MD_CLIENT_FINISH_CONST_SIZE 15 +#define TLS_MD_SERVER_FINISH_CONST "server finished" +#define TLS_MD_SERVER_FINISH_CONST_SIZE 15 +#define TLS_MD_KEY_EXPANSION_CONST "key expansion" +#define TLS_MD_KEY_EXPANSION_CONST_SIZE 13 +#define TLS_MD_CLIENT_WRITE_KEY_CONST "client write key" +#define TLS_MD_CLIENT_WRITE_KEY_CONST_SIZE 16 +#define TLS_MD_SERVER_WRITE_KEY_CONST "server write key" +#define TLS_MD_SERVER_WRITE_KEY_CONST_SIZE 16 +#define TLS_MD_IV_BLOCK_CONST "IV block" +#define TLS_MD_IV_BLOCK_CONST_SIZE 8 +#define TLS_MD_MASTER_SECRET_CONST "master secret" +#define TLS_MD_MASTER_SECRET_CONST_SIZE 13 +#define TLS_MD_EXTENDED_MASTER_SECRET_CONST "extended master secret" +#define TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE 22 + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/TMessagesProj/jni/boringssl/include/openssl/type_check.h b/TMessagesProj/jni/boringssl/include/openssl/type_check.h new file mode 100644 index 00000000..674913a3 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/type_check.h @@ -0,0 +1,91 @@ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] */ + +#ifndef OPENSSL_HEADER_TYPE_CHECK_H +#define OPENSSL_HEADER_TYPE_CHECK_H + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* This header file contains some common macros for enforcing type checking. + * Several, common OpenSSL structures (i.e. stack and lhash) operate on void + * pointers, but we wish to have type checking when they are used with a + * specific type. */ + +/* CHECKED_CAST casts |p| from type |from| to type |to|. */ +#define CHECKED_CAST(to, from, p) ((to) (1 ? (p) : (from)0)) + +/* CHECKED_PTR_OF casts a given pointer to void* and statically checks that it + * was a pointer to |type|. */ +#define CHECKED_PTR_OF(type, p) CHECKED_CAST(void*, type*, (p)) + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#define OPENSSL_COMPILE_ASSERT(cond, msg) _Static_assert(cond, #msg) +#else +#define OPENSSL_COMPILE_ASSERT(cond, msg) \ + typedef char OPENSSL_COMPILE_ASSERT_##msg[((cond) ? 1 : -1)] +#endif + + +#if defined(__cplusplus) +} /* extern C */ +#endif + +#endif /* OPENSSL_HEADER_TYPE_CHECK_H */ diff --git a/TMessagesProj/jni/boringssl/include/openssl/x509.h b/TMessagesProj/jni/boringssl/include/openssl/x509.h new file mode 100644 index 00000000..88719109 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/x509.h @@ -0,0 +1,1258 @@ +/* crypto/x509/x509.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED. + * ECDH support in OpenSSL originally developed by + * SUN MICROSYSTEMS, INC., and contributed to the OpenSSL project. + */ + +#ifndef HEADER_X509_H +#define HEADER_X509_H + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define X509_FILETYPE_PEM 1 +#define X509_FILETYPE_ASN1 2 +#define X509_FILETYPE_DEFAULT 3 + +#define X509v3_KU_DIGITAL_SIGNATURE 0x0080 +#define X509v3_KU_NON_REPUDIATION 0x0040 +#define X509v3_KU_KEY_ENCIPHERMENT 0x0020 +#define X509v3_KU_DATA_ENCIPHERMENT 0x0010 +#define X509v3_KU_KEY_AGREEMENT 0x0008 +#define X509v3_KU_KEY_CERT_SIGN 0x0004 +#define X509v3_KU_CRL_SIGN 0x0002 +#define X509v3_KU_ENCIPHER_ONLY 0x0001 +#define X509v3_KU_DECIPHER_ONLY 0x8000 +#define X509v3_KU_UNDEF 0xffff + +struct X509_objects_st + { + int nid; + int (*a2i)(void); + int (*i2a)(void); + } /* X509_OBJECTS */; + +DECLARE_ASN1_SET_OF(X509_ALGOR) + +typedef STACK_OF(X509_ALGOR) X509_ALGORS; + +struct X509_val_st + { + ASN1_TIME *notBefore; + ASN1_TIME *notAfter; + } /* X509_VAL */; + +struct X509_pubkey_st + { + X509_ALGOR *algor; + ASN1_BIT_STRING *public_key; + EVP_PKEY *pkey; + }; + +struct X509_sig_st + { + X509_ALGOR *algor; + ASN1_OCTET_STRING *digest; + } /* X509_SIG */; + +struct X509_name_entry_st + { + ASN1_OBJECT *object; + ASN1_STRING *value; + int set; + int size; /* temp variable */ + } /* X509_NAME_ENTRY */; + +DECLARE_STACK_OF(X509_NAME_ENTRY) +DECLARE_ASN1_SET_OF(X509_NAME_ENTRY) + +/* we always keep X509_NAMEs in 2 forms. */ +struct X509_name_st + { + STACK_OF(X509_NAME_ENTRY) *entries; + int modified; /* true if 'bytes' needs to be built */ +#ifndef OPENSSL_NO_BUFFER + BUF_MEM *bytes; +#else + char *bytes; +#endif +/* unsigned long hash; Keep the hash around for lookups */ + unsigned char *canon_enc; + int canon_enclen; + } /* X509_NAME */; + +DECLARE_STACK_OF(X509_NAME) + +#define X509_EX_V_NETSCAPE_HACK 0x8000 +#define X509_EX_V_INIT 0x0001 +struct X509_extension_st + { + ASN1_OBJECT *object; + ASN1_BOOLEAN critical; + ASN1_OCTET_STRING *value; + } /* X509_EXTENSION */; + +typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS; + +DECLARE_STACK_OF(X509_EXTENSION) +DECLARE_ASN1_SET_OF(X509_EXTENSION) + +/* a sequence of these are used */ +struct x509_attributes_st + { + ASN1_OBJECT *object; + int single; /* 0 for a set, 1 for a single item (which is wrong) */ + union { + char *ptr; +/* 0 */ STACK_OF(ASN1_TYPE) *set; +/* 1 */ ASN1_TYPE *single; + } value; + } /* X509_ATTRIBUTE */; + +DECLARE_STACK_OF(X509_ATTRIBUTE) +DECLARE_ASN1_SET_OF(X509_ATTRIBUTE) + + +struct X509_req_info_st + { + ASN1_ENCODING enc; + ASN1_INTEGER *version; + X509_NAME *subject; + X509_PUBKEY *pubkey; + /* d=2 hl=2 l= 0 cons: cont: 00 */ + STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */ + } /* X509_REQ_INFO */; + +struct X509_req_st + { + X509_REQ_INFO *req_info; + X509_ALGOR *sig_alg; + ASN1_BIT_STRING *signature; + CRYPTO_refcount_t references; + } /* X509_REQ */; + +struct x509_cinf_st + { + ASN1_INTEGER *version; /* [ 0 ] default of v1 */ + ASN1_INTEGER *serialNumber; + X509_ALGOR *signature; + X509_NAME *issuer; + X509_VAL *validity; + X509_NAME *subject; + X509_PUBKEY *key; + ASN1_BIT_STRING *issuerUID; /* [ 1 ] optional in v2 */ + ASN1_BIT_STRING *subjectUID; /* [ 2 ] optional in v2 */ + STACK_OF(X509_EXTENSION) *extensions; /* [ 3 ] optional in v3 */ + ASN1_ENCODING enc; + } /* X509_CINF */; + +/* This stuff is certificate "auxiliary info" + * it contains details which are useful in certificate + * stores and databases. When used this is tagged onto + * the end of the certificate itself + */ + +struct x509_cert_aux_st + { + STACK_OF(ASN1_OBJECT) *trust; /* trusted uses */ + STACK_OF(ASN1_OBJECT) *reject; /* rejected uses */ + ASN1_UTF8STRING *alias; /* "friendly name" */ + ASN1_OCTET_STRING *keyid; /* key id of private key */ + STACK_OF(X509_ALGOR) *other; /* other unspecified info */ + } /* X509_CERT_AUX */; + +struct x509_st + { + X509_CINF *cert_info; + X509_ALGOR *sig_alg; + ASN1_BIT_STRING *signature; + int valid; + CRYPTO_refcount_t references; + char *name; + CRYPTO_EX_DATA ex_data; + /* These contain copies of various extension values */ + long ex_pathlen; + long ex_pcpathlen; + unsigned long ex_flags; + unsigned long ex_kusage; + unsigned long ex_xkusage; + unsigned long ex_nscert; + ASN1_OCTET_STRING *skid; + AUTHORITY_KEYID *akid; + X509_POLICY_CACHE *policy_cache; + STACK_OF(DIST_POINT) *crldp; + STACK_OF(GENERAL_NAME) *altname; + NAME_CONSTRAINTS *nc; + unsigned char sha1_hash[SHA_DIGEST_LENGTH]; + X509_CERT_AUX *aux; + } /* X509 */; + +DECLARE_STACK_OF(X509) +DECLARE_ASN1_SET_OF(X509) + +/* This is used for a table of trust checking functions */ + +struct x509_trust_st { + int trust; + int flags; + int (*check_trust)(struct x509_trust_st *, X509 *, int); + char *name; + int arg1; + void *arg2; +} /* X509_TRUST */; + +DECLARE_STACK_OF(X509_TRUST) + +struct x509_cert_pair_st { + X509 *forward; + X509 *reverse; +} /* X509_CERT_PAIR */; + +/* standard trust ids */ + +#define X509_TRUST_DEFAULT -1 /* Only valid in purpose settings */ + +#define X509_TRUST_COMPAT 1 +#define X509_TRUST_SSL_CLIENT 2 +#define X509_TRUST_SSL_SERVER 3 +#define X509_TRUST_EMAIL 4 +#define X509_TRUST_OBJECT_SIGN 5 +#define X509_TRUST_OCSP_SIGN 6 +#define X509_TRUST_OCSP_REQUEST 7 +#define X509_TRUST_TSA 8 + +/* Keep these up to date! */ +#define X509_TRUST_MIN 1 +#define X509_TRUST_MAX 8 + + +/* trust_flags values */ +#define X509_TRUST_DYNAMIC 1 +#define X509_TRUST_DYNAMIC_NAME 2 + +/* check_trust return codes */ + +#define X509_TRUST_TRUSTED 1 +#define X509_TRUST_REJECTED 2 +#define X509_TRUST_UNTRUSTED 3 + +/* Flags for X509_print_ex() */ + +#define X509_FLAG_COMPAT 0 +#define X509_FLAG_NO_HEADER 1L +#define X509_FLAG_NO_VERSION (1L << 1) +#define X509_FLAG_NO_SERIAL (1L << 2) +#define X509_FLAG_NO_SIGNAME (1L << 3) +#define X509_FLAG_NO_ISSUER (1L << 4) +#define X509_FLAG_NO_VALIDITY (1L << 5) +#define X509_FLAG_NO_SUBJECT (1L << 6) +#define X509_FLAG_NO_PUBKEY (1L << 7) +#define X509_FLAG_NO_EXTENSIONS (1L << 8) +#define X509_FLAG_NO_SIGDUMP (1L << 9) +#define X509_FLAG_NO_AUX (1L << 10) +#define X509_FLAG_NO_ATTRIBUTES (1L << 11) +#define X509_FLAG_NO_IDS (1L << 12) + +/* Flags specific to X509_NAME_print_ex() */ + +/* The field separator information */ + +#define XN_FLAG_SEP_MASK (0xf << 16) + +#define XN_FLAG_COMPAT 0 /* Traditional SSLeay: use old X509_NAME_print */ +#define XN_FLAG_SEP_COMMA_PLUS (1 << 16) /* RFC2253 ,+ */ +#define XN_FLAG_SEP_CPLUS_SPC (2 << 16) /* ,+ spaced: more readable */ +#define XN_FLAG_SEP_SPLUS_SPC (3 << 16) /* ;+ spaced */ +#define XN_FLAG_SEP_MULTILINE (4 << 16) /* One line per field */ + +#define XN_FLAG_DN_REV (1 << 20) /* Reverse DN order */ + +/* How the field name is shown */ + +#define XN_FLAG_FN_MASK (0x3 << 21) + +#define XN_FLAG_FN_SN 0 /* Object short name */ +#define XN_FLAG_FN_LN (1 << 21) /* Object long name */ +#define XN_FLAG_FN_OID (2 << 21) /* Always use OIDs */ +#define XN_FLAG_FN_NONE (3 << 21) /* No field names */ + +#define XN_FLAG_SPC_EQ (1 << 23) /* Put spaces round '=' */ + +/* This determines if we dump fields we don't recognise: + * RFC2253 requires this. + */ + +#define XN_FLAG_DUMP_UNKNOWN_FIELDS (1 << 24) + +#define XN_FLAG_FN_ALIGN (1 << 25) /* Align field names to 20 characters */ + +/* Complete set of RFC2253 flags */ + +#define XN_FLAG_RFC2253 (ASN1_STRFLGS_RFC2253 | \ + XN_FLAG_SEP_COMMA_PLUS | \ + XN_FLAG_DN_REV | \ + XN_FLAG_FN_SN | \ + XN_FLAG_DUMP_UNKNOWN_FIELDS) + +/* readable oneline form */ + +#define XN_FLAG_ONELINE (ASN1_STRFLGS_RFC2253 | \ + ASN1_STRFLGS_ESC_QUOTE | \ + XN_FLAG_SEP_CPLUS_SPC | \ + XN_FLAG_SPC_EQ | \ + XN_FLAG_FN_SN) + +/* readable multiline form */ + +#define XN_FLAG_MULTILINE (ASN1_STRFLGS_ESC_CTRL | \ + ASN1_STRFLGS_ESC_MSB | \ + XN_FLAG_SEP_MULTILINE | \ + XN_FLAG_SPC_EQ | \ + XN_FLAG_FN_LN | \ + XN_FLAG_FN_ALIGN) + +struct x509_revoked_st + { + ASN1_INTEGER *serialNumber; + ASN1_TIME *revocationDate; + STACK_OF(X509_EXTENSION) /* optional */ *extensions; + /* Set up if indirect CRL */ + STACK_OF(GENERAL_NAME) *issuer; + /* Revocation reason */ + int reason; + int sequence; /* load sequence */ + }; + +DECLARE_STACK_OF(X509_REVOKED) +DECLARE_ASN1_SET_OF(X509_REVOKED) + +struct X509_crl_info_st + { + ASN1_INTEGER *version; + X509_ALGOR *sig_alg; + X509_NAME *issuer; + ASN1_TIME *lastUpdate; + ASN1_TIME *nextUpdate; + STACK_OF(X509_REVOKED) *revoked; + STACK_OF(X509_EXTENSION) /* [0] */ *extensions; + ASN1_ENCODING enc; + } /* X509_CRL_INFO */; + +struct X509_crl_st + { + /* actual signature */ + X509_CRL_INFO *crl; + X509_ALGOR *sig_alg; + ASN1_BIT_STRING *signature; + CRYPTO_refcount_t references; + int flags; + /* Copies of various extensions */ + AUTHORITY_KEYID *akid; + ISSUING_DIST_POINT *idp; + /* Convenient breakdown of IDP */ + int idp_flags; + int idp_reasons; + /* CRL and base CRL numbers for delta processing */ + ASN1_INTEGER *crl_number; + ASN1_INTEGER *base_crl_number; + unsigned char sha1_hash[SHA_DIGEST_LENGTH]; + STACK_OF(GENERAL_NAMES) *issuers; + const X509_CRL_METHOD *meth; + void *meth_data; + } /* X509_CRL */; + +DECLARE_STACK_OF(X509_CRL) +DECLARE_ASN1_SET_OF(X509_CRL) + +struct private_key_st + { + int version; + /* The PKCS#8 data types */ + X509_ALGOR *enc_algor; + ASN1_OCTET_STRING *enc_pkey; /* encrypted pub key */ + + /* When decrypted, the following will not be NULL */ + EVP_PKEY *dec_pkey; + + /* used to encrypt and decrypt */ + int key_length; + char *key_data; + int key_free; /* true if we should auto free key_data */ + + /* expanded version of 'enc_algor' */ + EVP_CIPHER_INFO cipher; + } /* X509_PKEY */; + +#ifndef OPENSSL_NO_EVP +struct X509_info_st + { + X509 *x509; + X509_CRL *crl; + X509_PKEY *x_pkey; + + EVP_CIPHER_INFO enc_cipher; + int enc_len; + char *enc_data; + + } /* X509_INFO */; + +DECLARE_STACK_OF(X509_INFO) +#endif + +/* The next 2 structures and their 8 routines were sent to me by + * Pat Richard and are used to manipulate + * Netscapes spki structures - useful if you are writing a CA web page + */ +struct Netscape_spkac_st + { + X509_PUBKEY *pubkey; + ASN1_IA5STRING *challenge; /* challenge sent in atlas >= PR2 */ + } /* NETSCAPE_SPKAC */; + +struct Netscape_spki_st + { + NETSCAPE_SPKAC *spkac; /* signed public key and challenge */ + X509_ALGOR *sig_algor; + ASN1_BIT_STRING *signature; + } /* NETSCAPE_SPKI */; + +/* Netscape certificate sequence structure */ +struct Netscape_certificate_sequence + { + ASN1_OBJECT *type; + STACK_OF(X509) *certs; + } /* NETSCAPE_CERT_SEQUENCE */; + +/* Unused (and iv length is wrong) +typedef struct CBCParameter_st + { + unsigned char iv[8]; + } CBC_PARAM; +*/ + +/* Password based encryption structure */ + +struct PBEPARAM_st { +ASN1_OCTET_STRING *salt; +ASN1_INTEGER *iter; +} /* PBEPARAM */; + +/* Password based encryption V2 structures */ + +struct PBE2PARAM_st { +X509_ALGOR *keyfunc; +X509_ALGOR *encryption; +} /* PBE2PARAM */; + +struct PBKDF2PARAM_st { +ASN1_TYPE *salt; /* Usually OCTET STRING but could be anything */ +ASN1_INTEGER *iter; +ASN1_INTEGER *keylength; +X509_ALGOR *prf; +} /* PBKDF2PARAM */; + + +/* PKCS#8 private key info structure */ + +struct pkcs8_priv_key_info_st + { + int broken; /* Flag for various broken formats */ +#define PKCS8_OK 0 +#define PKCS8_NO_OCTET 1 +#define PKCS8_EMBEDDED_PARAM 2 +#define PKCS8_NS_DB 3 +#define PKCS8_NEG_PRIVKEY 4 + ASN1_INTEGER *version; + X509_ALGOR *pkeyalg; + ASN1_TYPE *pkey; /* Should be OCTET STRING but some are broken */ + STACK_OF(X509_ATTRIBUTE) *attributes; + }; + +#ifdef __cplusplus +} +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define X509_EXT_PACK_UNKNOWN 1 +#define X509_EXT_PACK_STRING 2 + +#define X509_get_version(x) ASN1_INTEGER_get((x)->cert_info->version) +/* #define X509_get_serialNumber(x) ((x)->cert_info->serialNumber) */ +#define X509_get_notBefore(x) ((x)->cert_info->validity->notBefore) +#define X509_get_notAfter(x) ((x)->cert_info->validity->notAfter) +#define X509_get_cert_info(x) ((x)->cert_info) +#define X509_extract_key(x) X509_get_pubkey(x) /*****/ +#define X509_REQ_get_version(x) ASN1_INTEGER_get((x)->req_info->version) +#define X509_REQ_get_subject_name(x) ((x)->req_info->subject) +#define X509_REQ_extract_key(a) X509_REQ_get_pubkey(a) +#define X509_name_cmp(a,b) X509_NAME_cmp((a),(b)) +#define X509_get_signature_type(x) EVP_PKEY_type(OBJ_obj2nid((x)->sig_alg->algorithm)) + +#define X509_CRL_get_version(x) ASN1_INTEGER_get((x)->crl->version) +#define X509_CRL_get_lastUpdate(x) ((x)->crl->lastUpdate) +#define X509_CRL_get_nextUpdate(x) ((x)->crl->nextUpdate) +#define X509_CRL_get_issuer(x) ((x)->crl->issuer) +#define X509_CRL_get_REVOKED(x) ((x)->crl->revoked) + +#define X509_CINF_set_modified(c) ((c)->enc.modified = 1) +#define X509_CINF_get_issuer(c) (&(c)->issuer) +#define X509_CINF_get_extensions(c) ((c)->extensions) +#define X509_CINF_get_signature(c) ((c)->signature) + +OPENSSL_EXPORT void X509_CRL_set_default_method(const X509_CRL_METHOD *meth); +OPENSSL_EXPORT X509_CRL_METHOD *X509_CRL_METHOD_new( + int (*crl_init)(X509_CRL *crl), + int (*crl_free)(X509_CRL *crl), + int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret, + ASN1_INTEGER *ser, X509_NAME *issuer), + int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk)); +OPENSSL_EXPORT void X509_CRL_METHOD_free(X509_CRL_METHOD *m); + +OPENSSL_EXPORT void X509_CRL_set_meth_data(X509_CRL *crl, void *dat); +OPENSSL_EXPORT void *X509_CRL_get_meth_data(X509_CRL *crl); + +/* This one is only used so that a binary form can output, as in + * i2d_X509_NAME(X509_get_X509_PUBKEY(x),&buf) */ +#define X509_get_X509_PUBKEY(x) ((x)->cert_info->key) + + +OPENSSL_EXPORT const char *X509_verify_cert_error_string(long n); + +#ifndef OPENSSL_NO_EVP +OPENSSL_EXPORT int X509_verify(X509 *a, EVP_PKEY *r); + +OPENSSL_EXPORT int X509_REQ_verify(X509_REQ *a, EVP_PKEY *r); +OPENSSL_EXPORT int X509_CRL_verify(X509_CRL *a, EVP_PKEY *r); +OPENSSL_EXPORT int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *a, EVP_PKEY *r); + +OPENSSL_EXPORT NETSCAPE_SPKI * NETSCAPE_SPKI_b64_decode(const char *str, int len); +OPENSSL_EXPORT char * NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *x); +OPENSSL_EXPORT EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *x); +OPENSSL_EXPORT int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *x, EVP_PKEY *pkey); + +OPENSSL_EXPORT int NETSCAPE_SPKI_print(BIO *out, NETSCAPE_SPKI *spki); + +OPENSSL_EXPORT int X509_signature_dump(BIO *bp,const ASN1_STRING *sig, int indent); +OPENSSL_EXPORT int X509_signature_print(BIO *bp,X509_ALGOR *alg, ASN1_STRING *sig); + +OPENSSL_EXPORT int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md); +OPENSSL_EXPORT int X509_sign_ctx(X509 *x, EVP_MD_CTX *ctx); +/* int X509_http_nbio(OCSP_REQ_CTX *rctx, X509 **pcert); */ +OPENSSL_EXPORT int X509_REQ_sign(X509_REQ *x, EVP_PKEY *pkey, const EVP_MD *md); +OPENSSL_EXPORT int X509_REQ_sign_ctx(X509_REQ *x, EVP_MD_CTX *ctx); +OPENSSL_EXPORT int X509_CRL_sign(X509_CRL *x, EVP_PKEY *pkey, const EVP_MD *md); +OPENSSL_EXPORT int X509_CRL_sign_ctx(X509_CRL *x, EVP_MD_CTX *ctx); +/* int X509_CRL_http_nbio(OCSP_REQ_CTX *rctx, X509_CRL **pcrl); */ +OPENSSL_EXPORT int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *x, EVP_PKEY *pkey, const EVP_MD *md); + +OPENSSL_EXPORT int X509_pubkey_digest(const X509 *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +OPENSSL_EXPORT int X509_digest(const X509 *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +OPENSSL_EXPORT int X509_CRL_digest(const X509_CRL *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +OPENSSL_EXPORT int X509_REQ_digest(const X509_REQ *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +OPENSSL_EXPORT int X509_NAME_digest(const X509_NAME *data,const EVP_MD *type, + unsigned char *md, unsigned int *len); +#endif + +#ifndef OPENSSL_NO_FP_API +OPENSSL_EXPORT X509 *d2i_X509_fp(FILE *fp, X509 **x509); +OPENSSL_EXPORT int i2d_X509_fp(FILE *fp,X509 *x509); +OPENSSL_EXPORT X509_CRL *d2i_X509_CRL_fp(FILE *fp,X509_CRL **crl); +OPENSSL_EXPORT int i2d_X509_CRL_fp(FILE *fp,X509_CRL *crl); +OPENSSL_EXPORT X509_REQ *d2i_X509_REQ_fp(FILE *fp,X509_REQ **req); +OPENSSL_EXPORT int i2d_X509_REQ_fp(FILE *fp,X509_REQ *req); +OPENSSL_EXPORT RSA *d2i_RSAPrivateKey_fp(FILE *fp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSAPrivateKey_fp(FILE *fp,RSA *rsa); +OPENSSL_EXPORT RSA *d2i_RSAPublicKey_fp(FILE *fp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSAPublicKey_fp(FILE *fp,RSA *rsa); +OPENSSL_EXPORT RSA *d2i_RSA_PUBKEY_fp(FILE *fp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSA_PUBKEY_fp(FILE *fp,RSA *rsa); +#ifndef OPENSSL_NO_DSA +OPENSSL_EXPORT DSA *d2i_DSA_PUBKEY_fp(FILE *fp, DSA **dsa); +OPENSSL_EXPORT int i2d_DSA_PUBKEY_fp(FILE *fp, DSA *dsa); +OPENSSL_EXPORT DSA *d2i_DSAPrivateKey_fp(FILE *fp, DSA **dsa); +OPENSSL_EXPORT int i2d_DSAPrivateKey_fp(FILE *fp, DSA *dsa); +#endif +OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY_fp(FILE *fp, EC_KEY **eckey); +OPENSSL_EXPORT int i2d_EC_PUBKEY_fp(FILE *fp, EC_KEY *eckey); +OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey_fp(FILE *fp, EC_KEY **eckey); +OPENSSL_EXPORT int i2d_ECPrivateKey_fp(FILE *fp, EC_KEY *eckey); +OPENSSL_EXPORT X509_SIG *d2i_PKCS8_fp(FILE *fp,X509_SIG **p8); +OPENSSL_EXPORT int i2d_PKCS8_fp(FILE *fp,X509_SIG *p8); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_fp(FILE *fp, + PKCS8_PRIV_KEY_INFO **p8inf); +OPENSSL_EXPORT int i2d_PKCS8_PRIV_KEY_INFO_fp(FILE *fp,PKCS8_PRIV_KEY_INFO *p8inf); +OPENSSL_EXPORT int i2d_PKCS8PrivateKeyInfo_fp(FILE *fp, EVP_PKEY *key); +OPENSSL_EXPORT int i2d_PrivateKey_fp(FILE *fp, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey_fp(FILE *fp, EVP_PKEY **a); +OPENSSL_EXPORT int i2d_PUBKEY_fp(FILE *fp, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY *d2i_PUBKEY_fp(FILE *fp, EVP_PKEY **a); +#endif + +OPENSSL_EXPORT X509 *d2i_X509_bio(BIO *bp,X509 **x509); +OPENSSL_EXPORT int i2d_X509_bio(BIO *bp,X509 *x509); +OPENSSL_EXPORT X509_CRL *d2i_X509_CRL_bio(BIO *bp,X509_CRL **crl); +OPENSSL_EXPORT int i2d_X509_CRL_bio(BIO *bp,X509_CRL *crl); +OPENSSL_EXPORT X509_REQ *d2i_X509_REQ_bio(BIO *bp,X509_REQ **req); +OPENSSL_EXPORT int i2d_X509_REQ_bio(BIO *bp,X509_REQ *req); +OPENSSL_EXPORT RSA *d2i_RSAPrivateKey_bio(BIO *bp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSAPrivateKey_bio(BIO *bp,RSA *rsa); +OPENSSL_EXPORT RSA *d2i_RSAPublicKey_bio(BIO *bp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSAPublicKey_bio(BIO *bp,RSA *rsa); +OPENSSL_EXPORT RSA *d2i_RSA_PUBKEY_bio(BIO *bp,RSA **rsa); +OPENSSL_EXPORT int i2d_RSA_PUBKEY_bio(BIO *bp,RSA *rsa); +#ifndef OPENSSL_NO_DSA +OPENSSL_EXPORT DSA *d2i_DSA_PUBKEY_bio(BIO *bp, DSA **dsa); +OPENSSL_EXPORT int i2d_DSA_PUBKEY_bio(BIO *bp, DSA *dsa); +OPENSSL_EXPORT DSA *d2i_DSAPrivateKey_bio(BIO *bp, DSA **dsa); +OPENSSL_EXPORT int i2d_DSAPrivateKey_bio(BIO *bp, DSA *dsa); +#endif +OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY_bio(BIO *bp, EC_KEY **eckey); +OPENSSL_EXPORT int i2d_EC_PUBKEY_bio(BIO *bp, EC_KEY *eckey); +OPENSSL_EXPORT EC_KEY *d2i_ECPrivateKey_bio(BIO *bp, EC_KEY **eckey); +OPENSSL_EXPORT int i2d_ECPrivateKey_bio(BIO *bp, EC_KEY *eckey); +OPENSSL_EXPORT X509_SIG *d2i_PKCS8_bio(BIO *bp,X509_SIG **p8); +OPENSSL_EXPORT int i2d_PKCS8_bio(BIO *bp,X509_SIG *p8); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *bp, + PKCS8_PRIV_KEY_INFO **p8inf); +OPENSSL_EXPORT int i2d_PKCS8_PRIV_KEY_INFO_bio(BIO *bp,PKCS8_PRIV_KEY_INFO *p8inf); +OPENSSL_EXPORT int i2d_PKCS8PrivateKeyInfo_bio(BIO *bp, EVP_PKEY *key); +OPENSSL_EXPORT int i2d_PrivateKey_bio(BIO *bp, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a); +OPENSSL_EXPORT int i2d_PUBKEY_bio(BIO *bp, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a); + +OPENSSL_EXPORT X509 *X509_dup(X509 *x509); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_dup(X509_ATTRIBUTE *xa); +OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *ex); +OPENSSL_EXPORT X509_CRL *X509_CRL_dup(X509_CRL *crl); +OPENSSL_EXPORT X509_REVOKED *X509_REVOKED_dup(X509_REVOKED *rev); +OPENSSL_EXPORT X509_REQ *X509_REQ_dup(X509_REQ *req); +OPENSSL_EXPORT X509_ALGOR *X509_ALGOR_dup(X509_ALGOR *xn); +OPENSSL_EXPORT int X509_ALGOR_set0(X509_ALGOR *alg, const ASN1_OBJECT *aobj, int ptype, void *pval); +OPENSSL_EXPORT void X509_ALGOR_get0(ASN1_OBJECT **paobj, int *pptype, void **ppval, + X509_ALGOR *algor); +OPENSSL_EXPORT void X509_ALGOR_set_md(X509_ALGOR *alg, const EVP_MD *md); +OPENSSL_EXPORT int X509_ALGOR_cmp(const X509_ALGOR *a, const X509_ALGOR *b); + +OPENSSL_EXPORT X509_NAME *X509_NAME_dup(X509_NAME *xn); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_dup(X509_NAME_ENTRY *ne); + +OPENSSL_EXPORT int X509_cmp_time(const ASN1_TIME *s, time_t *t); +OPENSSL_EXPORT int X509_cmp_current_time(const ASN1_TIME *s); +OPENSSL_EXPORT ASN1_TIME * X509_time_adj(ASN1_TIME *s, long adj, time_t *t); +OPENSSL_EXPORT ASN1_TIME * X509_time_adj_ex(ASN1_TIME *s, int offset_day, long offset_sec, time_t *t); +OPENSSL_EXPORT ASN1_TIME * X509_gmtime_adj(ASN1_TIME *s, long adj); + +OPENSSL_EXPORT const char * X509_get_default_cert_area(void ); +OPENSSL_EXPORT const char * X509_get_default_cert_dir(void ); +OPENSSL_EXPORT const char * X509_get_default_cert_file(void ); +OPENSSL_EXPORT const char * X509_get_default_cert_dir_env(void ); +OPENSSL_EXPORT const char * X509_get_default_cert_file_env(void ); +OPENSSL_EXPORT const char * X509_get_default_private_dir(void ); + +OPENSSL_EXPORT X509_REQ * X509_to_X509_REQ(X509 *x, EVP_PKEY *pkey, const EVP_MD *md); +OPENSSL_EXPORT X509 * X509_REQ_to_X509(X509_REQ *r, int days,EVP_PKEY *pkey); + +DECLARE_ASN1_ENCODE_FUNCTIONS(X509_ALGORS, X509_ALGORS, X509_ALGORS) +DECLARE_ASN1_FUNCTIONS(X509_VAL) + +DECLARE_ASN1_FUNCTIONS(X509_PUBKEY) + +OPENSSL_EXPORT int X509_PUBKEY_set(X509_PUBKEY **x, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY * X509_PUBKEY_get(X509_PUBKEY *key); +OPENSSL_EXPORT int i2d_PUBKEY(const EVP_PKEY *a,unsigned char **pp); +OPENSSL_EXPORT EVP_PKEY * d2i_PUBKEY(EVP_PKEY **a,const unsigned char **pp, + long length); +OPENSSL_EXPORT int i2d_RSA_PUBKEY(const RSA *a,unsigned char **pp); +OPENSSL_EXPORT RSA * d2i_RSA_PUBKEY(RSA **a,const unsigned char **pp, + long length); +#ifndef OPENSSL_NO_DSA +OPENSSL_EXPORT int i2d_DSA_PUBKEY(const DSA *a,unsigned char **pp); +OPENSSL_EXPORT DSA * d2i_DSA_PUBKEY(DSA **a,const unsigned char **pp, + long length); +#endif +OPENSSL_EXPORT int i2d_EC_PUBKEY(const EC_KEY *a, unsigned char **pp); +OPENSSL_EXPORT EC_KEY *d2i_EC_PUBKEY(EC_KEY **a, const unsigned char **pp, + long length); + +DECLARE_ASN1_FUNCTIONS(X509_SIG) +DECLARE_ASN1_FUNCTIONS(X509_REQ_INFO) +DECLARE_ASN1_FUNCTIONS(X509_REQ) + +DECLARE_ASN1_FUNCTIONS(X509_ATTRIBUTE) +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create(int nid, int atrtype, void *value); + +DECLARE_ASN1_FUNCTIONS(X509_EXTENSION) +DECLARE_ASN1_ENCODE_FUNCTIONS(X509_EXTENSIONS, X509_EXTENSIONS, X509_EXTENSIONS) + +DECLARE_ASN1_FUNCTIONS(X509_NAME_ENTRY) + +DECLARE_ASN1_FUNCTIONS(X509_NAME) + +OPENSSL_EXPORT int X509_NAME_set(X509_NAME **xn, X509_NAME *name); + +DECLARE_ASN1_FUNCTIONS(X509_CINF) + +DECLARE_ASN1_FUNCTIONS(X509) +DECLARE_ASN1_FUNCTIONS(X509_CERT_AUX) + +DECLARE_ASN1_FUNCTIONS(X509_CERT_PAIR) + +/* X509_up_ref adds one to the reference count of |x| and returns + * |x|. */ +OPENSSL_EXPORT X509 *X509_up_ref(X509 *x); + +OPENSSL_EXPORT int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int X509_set_ex_data(X509 *r, int idx, void *arg); +OPENSSL_EXPORT void *X509_get_ex_data(X509 *r, int idx); +OPENSSL_EXPORT int i2d_X509_AUX(X509 *a,unsigned char **pp); +OPENSSL_EXPORT X509 * d2i_X509_AUX(X509 **a,const unsigned char **pp,long length); + +OPENSSL_EXPORT void X509_get0_signature(ASN1_BIT_STRING **psig, X509_ALGOR **palg, + const X509 *x); +OPENSSL_EXPORT int X509_get_signature_nid(const X509 *x); + +OPENSSL_EXPORT int X509_alias_set1(X509 *x, unsigned char *name, int len); +OPENSSL_EXPORT int X509_keyid_set1(X509 *x, unsigned char *id, int len); +OPENSSL_EXPORT unsigned char * X509_alias_get0(X509 *x, int *len); +OPENSSL_EXPORT unsigned char * X509_keyid_get0(X509 *x, int *len); +OPENSSL_EXPORT int (*X509_TRUST_set_default(int (*trust)(int , X509 *, int)))(int, X509 *, int); +OPENSSL_EXPORT int X509_TRUST_set(int *t, int trust); +OPENSSL_EXPORT int X509_add1_trust_object(X509 *x, ASN1_OBJECT *obj); +OPENSSL_EXPORT int X509_add1_reject_object(X509 *x, ASN1_OBJECT *obj); +OPENSSL_EXPORT void X509_trust_clear(X509 *x); +OPENSSL_EXPORT void X509_reject_clear(X509 *x); + +DECLARE_ASN1_FUNCTIONS(X509_REVOKED) +DECLARE_ASN1_FUNCTIONS(X509_CRL_INFO) +DECLARE_ASN1_FUNCTIONS(X509_CRL) + +OPENSSL_EXPORT int X509_CRL_add0_revoked(X509_CRL *crl, X509_REVOKED *rev); +OPENSSL_EXPORT int X509_CRL_get0_by_serial(X509_CRL *crl, + X509_REVOKED **ret, ASN1_INTEGER *serial); +OPENSSL_EXPORT int X509_CRL_get0_by_cert(X509_CRL *crl, X509_REVOKED **ret, X509 *x); + +OPENSSL_EXPORT X509_PKEY * X509_PKEY_new(void ); +OPENSSL_EXPORT void X509_PKEY_free(X509_PKEY *a); + +DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKI) +DECLARE_ASN1_FUNCTIONS(NETSCAPE_SPKAC) +DECLARE_ASN1_FUNCTIONS(NETSCAPE_CERT_SEQUENCE) + +#ifndef OPENSSL_NO_EVP +OPENSSL_EXPORT X509_INFO * X509_INFO_new(void); +OPENSSL_EXPORT void X509_INFO_free(X509_INFO *a); +OPENSSL_EXPORT char * X509_NAME_oneline(X509_NAME *a,char *buf,int size); + +OPENSSL_EXPORT int ASN1_digest(i2d_of_void *i2d,const EVP_MD *type,char *data, + unsigned char *md,unsigned int *len); + +OPENSSL_EXPORT int ASN1_item_digest(const ASN1_ITEM *it,const EVP_MD *type,void *data, + unsigned char *md,unsigned int *len); + +OPENSSL_EXPORT int ASN1_item_verify(const ASN1_ITEM *it, X509_ALGOR *algor1, + ASN1_BIT_STRING *signature,void *data,EVP_PKEY *pkey); + +OPENSSL_EXPORT int ASN1_item_sign(const ASN1_ITEM *it, X509_ALGOR *algor1, X509_ALGOR *algor2, + ASN1_BIT_STRING *signature, + void *data, EVP_PKEY *pkey, const EVP_MD *type); +OPENSSL_EXPORT int ASN1_item_sign_ctx(const ASN1_ITEM *it, + X509_ALGOR *algor1, X509_ALGOR *algor2, + ASN1_BIT_STRING *signature, void *asn, EVP_MD_CTX *ctx); +#endif + +OPENSSL_EXPORT int X509_set_version(X509 *x,long version); +OPENSSL_EXPORT int X509_set_serialNumber(X509 *x, ASN1_INTEGER *serial); +OPENSSL_EXPORT ASN1_INTEGER * X509_get_serialNumber(X509 *x); +OPENSSL_EXPORT int X509_set_issuer_name(X509 *x, X509_NAME *name); +OPENSSL_EXPORT X509_NAME * X509_get_issuer_name(X509 *a); +OPENSSL_EXPORT int X509_set_subject_name(X509 *x, X509_NAME *name); +OPENSSL_EXPORT X509_NAME * X509_get_subject_name(X509 *a); +OPENSSL_EXPORT int X509_set_notBefore(X509 *x, const ASN1_TIME *tm); +OPENSSL_EXPORT int X509_set_notAfter(X509 *x, const ASN1_TIME *tm); +OPENSSL_EXPORT int X509_set_pubkey(X509 *x, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY * X509_get_pubkey(X509 *x); +OPENSSL_EXPORT ASN1_BIT_STRING * X509_get0_pubkey_bitstr(const X509 *x); +OPENSSL_EXPORT int X509_certificate_type(X509 *x,EVP_PKEY *pubkey /* optional */); + +OPENSSL_EXPORT int X509_REQ_set_version(X509_REQ *x,long version); +OPENSSL_EXPORT int X509_REQ_set_subject_name(X509_REQ *req,X509_NAME *name); +OPENSSL_EXPORT int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey); +OPENSSL_EXPORT EVP_PKEY * X509_REQ_get_pubkey(X509_REQ *req); +OPENSSL_EXPORT int X509_REQ_extension_nid(int nid); +OPENSSL_EXPORT const int * X509_REQ_get_extension_nids(void); +OPENSSL_EXPORT void X509_REQ_set_extension_nids(const int *nids); +OPENSSL_EXPORT STACK_OF(X509_EXTENSION) *X509_REQ_get_extensions(X509_REQ *req); +OPENSSL_EXPORT int X509_REQ_add_extensions_nid(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts, + int nid); +OPENSSL_EXPORT int X509_REQ_add_extensions(X509_REQ *req, STACK_OF(X509_EXTENSION) *exts); +OPENSSL_EXPORT int X509_REQ_get_attr_count(const X509_REQ *req); +OPENSSL_EXPORT int X509_REQ_get_attr_by_NID(const X509_REQ *req, int nid, + int lastpos); +OPENSSL_EXPORT int X509_REQ_get_attr_by_OBJ(const X509_REQ *req, ASN1_OBJECT *obj, + int lastpos); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *req, int loc); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_REQ_delete_attr(X509_REQ *req, int loc); +OPENSSL_EXPORT int X509_REQ_add1_attr(X509_REQ *req, X509_ATTRIBUTE *attr); +OPENSSL_EXPORT int X509_REQ_add1_attr_by_OBJ(X509_REQ *req, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT int X509_REQ_add1_attr_by_NID(X509_REQ *req, + int nid, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT int X509_REQ_add1_attr_by_txt(X509_REQ *req, + const char *attrname, int type, + const unsigned char *bytes, int len); + +OPENSSL_EXPORT int X509_CRL_set_version(X509_CRL *x, long version); +OPENSSL_EXPORT int X509_CRL_set_issuer_name(X509_CRL *x, X509_NAME *name); +OPENSSL_EXPORT int X509_CRL_set_lastUpdate(X509_CRL *x, const ASN1_TIME *tm); +OPENSSL_EXPORT int X509_CRL_set_nextUpdate(X509_CRL *x, const ASN1_TIME *tm); +OPENSSL_EXPORT int X509_CRL_sort(X509_CRL *crl); + +OPENSSL_EXPORT int X509_REVOKED_set_serialNumber(X509_REVOKED *x, ASN1_INTEGER *serial); +OPENSSL_EXPORT int X509_REVOKED_set_revocationDate(X509_REVOKED *r, ASN1_TIME *tm); + +OPENSSL_EXPORT X509_CRL *X509_CRL_diff(X509_CRL *base, X509_CRL *newer, + EVP_PKEY *skey, const EVP_MD *md, unsigned int flags); + +OPENSSL_EXPORT int X509_REQ_check_private_key(X509_REQ *x509,EVP_PKEY *pkey); + +OPENSSL_EXPORT int X509_check_private_key(X509 *x509,EVP_PKEY *pkey); +OPENSSL_EXPORT int X509_chain_check_suiteb(int *perror_depth, + X509 *x, STACK_OF(X509) *chain, + unsigned long flags); +OPENSSL_EXPORT int X509_CRL_check_suiteb(X509_CRL *crl, EVP_PKEY *pk, + unsigned long flags); +OPENSSL_EXPORT STACK_OF(X509) *X509_chain_up_ref(STACK_OF(X509) *chain); + +OPENSSL_EXPORT int X509_issuer_and_serial_cmp(const X509 *a, const X509 *b); +OPENSSL_EXPORT unsigned long X509_issuer_and_serial_hash(X509 *a); + +OPENSSL_EXPORT int X509_issuer_name_cmp(const X509 *a, const X509 *b); +OPENSSL_EXPORT unsigned long X509_issuer_name_hash(X509 *a); + +OPENSSL_EXPORT int X509_subject_name_cmp(const X509 *a, const X509 *b); +OPENSSL_EXPORT unsigned long X509_subject_name_hash(X509 *x); + +OPENSSL_EXPORT unsigned long X509_issuer_name_hash_old(X509 *a); +OPENSSL_EXPORT unsigned long X509_subject_name_hash_old(X509 *x); + +OPENSSL_EXPORT int X509_cmp(const X509 *a, const X509 *b); +OPENSSL_EXPORT int X509_NAME_cmp(const X509_NAME *a, const X509_NAME *b); +OPENSSL_EXPORT unsigned long X509_NAME_hash(X509_NAME *x); +OPENSSL_EXPORT unsigned long X509_NAME_hash_old(X509_NAME *x); + +OPENSSL_EXPORT int X509_CRL_cmp(const X509_CRL *a, const X509_CRL *b); +OPENSSL_EXPORT int X509_CRL_match(const X509_CRL *a, const X509_CRL *b); +#ifndef OPENSSL_NO_FP_API +OPENSSL_EXPORT int X509_print_ex_fp(FILE *bp,X509 *x, unsigned long nmflag, unsigned long cflag); +OPENSSL_EXPORT int X509_print_fp(FILE *bp,X509 *x); +OPENSSL_EXPORT int X509_CRL_print_fp(FILE *bp,X509_CRL *x); +OPENSSL_EXPORT int X509_REQ_print_fp(FILE *bp,X509_REQ *req); +OPENSSL_EXPORT int X509_NAME_print_ex_fp(FILE *fp, X509_NAME *nm, int indent, unsigned long flags); +#endif + +OPENSSL_EXPORT int X509_NAME_print(BIO *bp, X509_NAME *name, int obase); +OPENSSL_EXPORT int X509_NAME_print_ex(BIO *out, X509_NAME *nm, int indent, unsigned long flags); +OPENSSL_EXPORT int X509_print_ex(BIO *bp,X509 *x, unsigned long nmflag, unsigned long cflag); +OPENSSL_EXPORT int X509_print(BIO *bp,X509 *x); +OPENSSL_EXPORT int X509_ocspid_print(BIO *bp,X509 *x); +OPENSSL_EXPORT int X509_CERT_AUX_print(BIO *bp,X509_CERT_AUX *x, int indent); +OPENSSL_EXPORT int X509_CRL_print(BIO *bp,X509_CRL *x); +OPENSSL_EXPORT int X509_REQ_print_ex(BIO *bp, X509_REQ *x, unsigned long nmflag, unsigned long cflag); +OPENSSL_EXPORT int X509_REQ_print(BIO *bp,X509_REQ *req); + +OPENSSL_EXPORT int X509_NAME_entry_count(X509_NAME *name); +OPENSSL_EXPORT int X509_NAME_get_text_by_NID(X509_NAME *name, int nid, + char *buf,int len); +OPENSSL_EXPORT int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, + char *buf,int len); + +/* NOTE: you should be passsing -1, not 0 as lastpos. The functions that use + * lastpos, search after that position on. */ +OPENSSL_EXPORT int X509_NAME_get_index_by_NID(X509_NAME *name,int nid,int lastpos); +OPENSSL_EXPORT int X509_NAME_get_index_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, + int lastpos); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *name, int loc); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *name, int loc); +OPENSSL_EXPORT int X509_NAME_add_entry(X509_NAME *name,X509_NAME_ENTRY *ne, + int loc, int set); +OPENSSL_EXPORT int X509_NAME_add_entry_by_OBJ(X509_NAME *name, ASN1_OBJECT *obj, int type, + unsigned char *bytes, int len, int loc, int set); +OPENSSL_EXPORT int X509_NAME_add_entry_by_NID(X509_NAME *name, int nid, int type, + unsigned char *bytes, int len, int loc, int set); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_txt(X509_NAME_ENTRY **ne, + const char *field, int type, const unsigned char *bytes, int len); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_NID(X509_NAME_ENTRY **ne, int nid, + int type,unsigned char *bytes, int len); +OPENSSL_EXPORT int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type, + const unsigned char *bytes, int len, int loc, int set); +OPENSSL_EXPORT X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **ne, + const ASN1_OBJECT *obj, int type,const unsigned char *bytes, + int len); +OPENSSL_EXPORT int X509_NAME_ENTRY_set_object(X509_NAME_ENTRY *ne, + const ASN1_OBJECT *obj); +OPENSSL_EXPORT int X509_NAME_ENTRY_set_data(X509_NAME_ENTRY *ne, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT ASN1_OBJECT * X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *ne); +OPENSSL_EXPORT ASN1_STRING * X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *ne); + +OPENSSL_EXPORT int X509v3_get_ext_count(const STACK_OF(X509_EXTENSION) *x); +OPENSSL_EXPORT int X509v3_get_ext_by_NID(const STACK_OF(X509_EXTENSION) *x, + int nid, int lastpos); +OPENSSL_EXPORT int X509v3_get_ext_by_OBJ(const STACK_OF(X509_EXTENSION) *x, + const ASN1_OBJECT *obj,int lastpos); +OPENSSL_EXPORT int X509v3_get_ext_by_critical(const STACK_OF(X509_EXTENSION) *x, + int crit, int lastpos); +OPENSSL_EXPORT X509_EXTENSION *X509v3_get_ext(const STACK_OF(X509_EXTENSION) *x, int loc); +OPENSSL_EXPORT X509_EXTENSION *X509v3_delete_ext(STACK_OF(X509_EXTENSION) *x, int loc); +OPENSSL_EXPORT STACK_OF(X509_EXTENSION) *X509v3_add_ext(STACK_OF(X509_EXTENSION) **x, + X509_EXTENSION *ex, int loc); + +OPENSSL_EXPORT int X509_get_ext_count(X509 *x); +OPENSSL_EXPORT int X509_get_ext_by_NID(X509 *x, int nid, int lastpos); +OPENSSL_EXPORT int X509_get_ext_by_OBJ(X509 *x,ASN1_OBJECT *obj,int lastpos); +OPENSSL_EXPORT int X509_get_ext_by_critical(X509 *x, int crit, int lastpos); +OPENSSL_EXPORT X509_EXTENSION *X509_get_ext(X509 *x, int loc); +OPENSSL_EXPORT X509_EXTENSION *X509_delete_ext(X509 *x, int loc); +OPENSSL_EXPORT int X509_add_ext(X509 *x, X509_EXTENSION *ex, int loc); +OPENSSL_EXPORT void * X509_get_ext_d2i(X509 *x, int nid, int *crit, int *idx); +OPENSSL_EXPORT int X509_add1_ext_i2d(X509 *x, int nid, void *value, int crit, + unsigned long flags); + +OPENSSL_EXPORT int X509_CRL_get_ext_count(X509_CRL *x); +OPENSSL_EXPORT int X509_CRL_get_ext_by_NID(X509_CRL *x, int nid, int lastpos); +OPENSSL_EXPORT int X509_CRL_get_ext_by_OBJ(X509_CRL *x,ASN1_OBJECT *obj,int lastpos); +OPENSSL_EXPORT int X509_CRL_get_ext_by_critical(X509_CRL *x, int crit, int lastpos); +OPENSSL_EXPORT X509_EXTENSION *X509_CRL_get_ext(X509_CRL *x, int loc); +OPENSSL_EXPORT X509_EXTENSION *X509_CRL_delete_ext(X509_CRL *x, int loc); +OPENSSL_EXPORT int X509_CRL_add_ext(X509_CRL *x, X509_EXTENSION *ex, int loc); +OPENSSL_EXPORT void * X509_CRL_get_ext_d2i(X509_CRL *x, int nid, int *crit, int *idx); +OPENSSL_EXPORT int X509_CRL_add1_ext_i2d(X509_CRL *x, int nid, void *value, int crit, + unsigned long flags); + +OPENSSL_EXPORT int X509_REVOKED_get_ext_count(X509_REVOKED *x); +OPENSSL_EXPORT int X509_REVOKED_get_ext_by_NID(X509_REVOKED *x, int nid, int lastpos); +OPENSSL_EXPORT int X509_REVOKED_get_ext_by_OBJ(X509_REVOKED *x,ASN1_OBJECT *obj,int lastpos); +OPENSSL_EXPORT int X509_REVOKED_get_ext_by_critical(X509_REVOKED *x, int crit, int lastpos); +OPENSSL_EXPORT X509_EXTENSION *X509_REVOKED_get_ext(X509_REVOKED *x, int loc); +OPENSSL_EXPORT X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *x, int loc); +OPENSSL_EXPORT int X509_REVOKED_add_ext(X509_REVOKED *x, X509_EXTENSION *ex, int loc); +OPENSSL_EXPORT void * X509_REVOKED_get_ext_d2i(X509_REVOKED *x, int nid, int *crit, int *idx); +OPENSSL_EXPORT int X509_REVOKED_add1_ext_i2d(X509_REVOKED *x, int nid, void *value, int crit, + unsigned long flags); + +OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_create_by_NID(X509_EXTENSION **ex, + int nid, int crit, ASN1_OCTET_STRING *data); +OPENSSL_EXPORT X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **ex, + const ASN1_OBJECT *obj,int crit,ASN1_OCTET_STRING *data); +OPENSSL_EXPORT int X509_EXTENSION_set_object(X509_EXTENSION *ex,const ASN1_OBJECT *obj); +OPENSSL_EXPORT int X509_EXTENSION_set_critical(X509_EXTENSION *ex, int crit); +OPENSSL_EXPORT int X509_EXTENSION_set_data(X509_EXTENSION *ex, + ASN1_OCTET_STRING *data); +OPENSSL_EXPORT ASN1_OBJECT * X509_EXTENSION_get_object(X509_EXTENSION *ex); +OPENSSL_EXPORT ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *ne); +OPENSSL_EXPORT int X509_EXTENSION_get_critical(X509_EXTENSION *ex); + +OPENSSL_EXPORT int X509at_get_attr_count(const STACK_OF(X509_ATTRIBUTE) *x); +OPENSSL_EXPORT int X509at_get_attr_by_NID(const STACK_OF(X509_ATTRIBUTE) *x, int nid, + int lastpos); +OPENSSL_EXPORT int X509at_get_attr_by_OBJ(const STACK_OF(X509_ATTRIBUTE) *sk, const ASN1_OBJECT *obj, + int lastpos); +OPENSSL_EXPORT X509_ATTRIBUTE *X509at_get_attr(const STACK_OF(X509_ATTRIBUTE) *x, int loc); +OPENSSL_EXPORT X509_ATTRIBUTE *X509at_delete_attr(STACK_OF(X509_ATTRIBUTE) *x, int loc); +OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr(STACK_OF(X509_ATTRIBUTE) **x, + X509_ATTRIBUTE *attr); +OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_OBJ(STACK_OF(X509_ATTRIBUTE) **x, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_NID(STACK_OF(X509_ATTRIBUTE) **x, + int nid, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT STACK_OF(X509_ATTRIBUTE) *X509at_add1_attr_by_txt(STACK_OF(X509_ATTRIBUTE) **x, + const char *attrname, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT void *X509at_get0_data_by_OBJ(STACK_OF(X509_ATTRIBUTE) *x, + ASN1_OBJECT *obj, int lastpos, int type); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_NID(X509_ATTRIBUTE **attr, int nid, + int atrtype, const void *data, int len); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_OBJ(X509_ATTRIBUTE **attr, + const ASN1_OBJECT *obj, int atrtype, const void *data, int len); +OPENSSL_EXPORT X509_ATTRIBUTE *X509_ATTRIBUTE_create_by_txt(X509_ATTRIBUTE **attr, + const char *atrname, int type, const unsigned char *bytes, int len); +OPENSSL_EXPORT int X509_ATTRIBUTE_set1_object(X509_ATTRIBUTE *attr, const ASN1_OBJECT *obj); +OPENSSL_EXPORT int X509_ATTRIBUTE_set1_data(X509_ATTRIBUTE *attr, int attrtype, const void *data, int len); +OPENSSL_EXPORT void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *attr, int idx, + int atrtype, void *data); +OPENSSL_EXPORT int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr); +OPENSSL_EXPORT ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr); +OPENSSL_EXPORT ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx); + +OPENSSL_EXPORT int EVP_PKEY_get_attr_count(const EVP_PKEY *key); +OPENSSL_EXPORT int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid, + int lastpos); +OPENSSL_EXPORT int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, ASN1_OBJECT *obj, + int lastpos); +OPENSSL_EXPORT X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc); +OPENSSL_EXPORT X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc); +OPENSSL_EXPORT int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr); +OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key, + const ASN1_OBJECT *obj, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key, + int nid, int type, + const unsigned char *bytes, int len); +OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key, + const char *attrname, int type, + const unsigned char *bytes, int len); + +OPENSSL_EXPORT int X509_verify_cert(X509_STORE_CTX *ctx); + +/* lookup a cert from a X509 STACK */ +OPENSSL_EXPORT X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk,X509_NAME *name, + ASN1_INTEGER *serial); +OPENSSL_EXPORT X509 *X509_find_by_subject(STACK_OF(X509) *sk,X509_NAME *name); + +DECLARE_ASN1_FUNCTIONS(PBEPARAM) +DECLARE_ASN1_FUNCTIONS(PBE2PARAM) +DECLARE_ASN1_FUNCTIONS(PBKDF2PARAM) + +OPENSSL_EXPORT int PKCS5_pbe_set0_algor(X509_ALGOR *algor, int alg, int iter, + const unsigned char *salt, int saltlen); + +OPENSSL_EXPORT X509_ALGOR *PKCS5_pbe_set(int alg, int iter, + const unsigned char *salt, int saltlen); +OPENSSL_EXPORT X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter, + unsigned char *salt, int saltlen); +OPENSSL_EXPORT X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter, + unsigned char *salt, int saltlen, + unsigned char *aiv, int prf_nid); + +OPENSSL_EXPORT X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen, + int prf_nid, int keylen); + +/* PKCS#8 utilities */ + +DECLARE_ASN1_FUNCTIONS(PKCS8_PRIV_KEY_INFO) + +OPENSSL_EXPORT EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8_broken(EVP_PKEY *pkey, int broken); +OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_set_broken(PKCS8_PRIV_KEY_INFO *p8, int broken); + +OPENSSL_EXPORT int PKCS8_pkey_set0(PKCS8_PRIV_KEY_INFO *priv, ASN1_OBJECT *aobj, + int version, int ptype, void *pval, + unsigned char *penc, int penclen); +OPENSSL_EXPORT int PKCS8_pkey_get0(ASN1_OBJECT **ppkalg, + const unsigned char **pk, int *ppklen, + X509_ALGOR **pa, + PKCS8_PRIV_KEY_INFO *p8); + +OPENSSL_EXPORT int X509_PUBKEY_set0_param(X509_PUBKEY *pub, const ASN1_OBJECT *aobj, + int ptype, void *pval, + unsigned char *penc, int penclen); +OPENSSL_EXPORT int X509_PUBKEY_get0_param(ASN1_OBJECT **ppkalg, + const unsigned char **pk, int *ppklen, + X509_ALGOR **pa, + X509_PUBKEY *pub); + +OPENSSL_EXPORT int X509_check_trust(X509 *x, int id, int flags); +OPENSSL_EXPORT int X509_TRUST_get_count(void); +OPENSSL_EXPORT X509_TRUST * X509_TRUST_get0(int idx); +OPENSSL_EXPORT int X509_TRUST_get_by_id(int id); +OPENSSL_EXPORT int X509_TRUST_add(int id, int flags, int (*ck)(X509_TRUST *, X509 *, int), + char *name, int arg1, void *arg2); +OPENSSL_EXPORT void X509_TRUST_cleanup(void); +OPENSSL_EXPORT int X509_TRUST_get_flags(X509_TRUST *xp); +OPENSSL_EXPORT char *X509_TRUST_get0_name(X509_TRUST *xp); +OPENSSL_EXPORT int X509_TRUST_get_trust(X509_TRUST *xp); + +/* PKCS7_get_certificates parses a PKCS#7, SignedData structure from |cbs| and + * appends the included certificates to |out_certs|. It returns one on success + * and zero on error. */ +OPENSSL_EXPORT int PKCS7_get_certificates(STACK_OF(X509) *out_certs, CBS *cbs); + +/* PKCS7_bundle_certificates appends a PKCS#7, SignedData structure containing + * |certs| to |out|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS7_bundle_certificates( + CBB *out, const STACK_OF(X509) *certs); + +/* PKCS7_get_CRLs parses a PKCS#7, SignedData structure from |cbs| and appends + * the included CRLs to |out_crls|. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int PKCS7_get_CRLs(STACK_OF(X509_CRL) *out_crls, CBS *cbs); + +/* PKCS7_bundle_CRLs appends a PKCS#7, SignedData structure containing + * |crls| to |out|. It returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS7_bundle_CRLs(CBB *out, const STACK_OF(X509_CRL) *crls); + +/* PKCS7_get_PEM_certificates reads a PEM-encoded, PKCS#7, SignedData structure + * from |pem_bio| and appends the included certificates to |out_certs|. It + * returns one on success and zero on error. */ +OPENSSL_EXPORT int PKCS7_get_PEM_certificates(STACK_OF(X509) *out_certs, + BIO *pem_bio); + +/* PKCS7_get_PEM_CRLs reads a PEM-encoded, PKCS#7, SignedData structure from + * |pem_bio| and appends the included CRLs to |out_crls|. It returns one on + * success and zero on error. */ +OPENSSL_EXPORT int PKCS7_get_PEM_CRLs(STACK_OF(X509_CRL) *out_crls, + BIO *pem_bio); + +/* EVP_PK values indicate the algorithm of the public key in a certificate. */ + +#define EVP_PK_RSA 0x0001 +#define EVP_PK_DSA 0x0002 +#define EVP_PK_DH 0x0004 +#define EVP_PK_EC 0x0008 + +/* EVP_PKS values indicate the algorithm used to sign a certificate. */ + +#define EVP_PKS_RSA 0x0100 +#define EVP_PKS_DSA 0x0200 +#define EVP_PKS_EC 0x0400 + +/* EVP_PKT values are flags that define what public-key operations can be + * performed with the public key from a certificate. */ + +/* EVP_PKT_SIGN indicates that the public key can be used for signing. */ +#define EVP_PKT_SIGN 0x0010 +/* EVP_PKT_ENC indicates that a session key can be encrypted to the public + * key. */ +#define EVP_PKT_ENC 0x0020 +/* EVP_PKT_EXCH indicates that key-agreement can be performed. */ +#define EVP_PKT_EXCH 0x0040 +/* EVP_PKT_EXP indicates that key is weak (i.e. "export"). */ +#define EVP_PKT_EXP 0x1000 + + +#ifdef __cplusplus +} +#endif + +#define X509_R_AKID_MISMATCH 100 +#define X509_R_BAD_PKCS7_VERSION 101 +#define X509_R_BAD_X509_FILETYPE 102 +#define X509_R_BASE64_DECODE_ERROR 103 +#define X509_R_CANT_CHECK_DH_KEY 104 +#define X509_R_CERT_ALREADY_IN_HASH_TABLE 105 +#define X509_R_CRL_ALREADY_DELTA 106 +#define X509_R_CRL_VERIFY_FAILURE 107 +#define X509_R_IDP_MISMATCH 108 +#define X509_R_INVALID_BIT_STRING_BITS_LEFT 109 +#define X509_R_INVALID_DIRECTORY 110 +#define X509_R_INVALID_FIELD_NAME 111 +#define X509_R_INVALID_TRUST 112 +#define X509_R_ISSUER_MISMATCH 113 +#define X509_R_KEY_TYPE_MISMATCH 114 +#define X509_R_KEY_VALUES_MISMATCH 115 +#define X509_R_LOADING_CERT_DIR 116 +#define X509_R_LOADING_DEFAULTS 117 +#define X509_R_METHOD_NOT_SUPPORTED 118 +#define X509_R_NEWER_CRL_NOT_NEWER 119 +#define X509_R_NOT_PKCS7_SIGNED_DATA 120 +#define X509_R_NO_CERTIFICATES_INCLUDED 121 +#define X509_R_NO_CERT_SET_FOR_US_TO_VERIFY 122 +#define X509_R_NO_CRL_NUMBER 123 +#define X509_R_PUBLIC_KEY_DECODE_ERROR 124 +#define X509_R_PUBLIC_KEY_ENCODE_ERROR 125 +#define X509_R_SHOULD_RETRY 126 +#define X509_R_UNABLE_TO_FIND_PARAMETERS_IN_CHAIN 127 +#define X509_R_UNABLE_TO_GET_CERTS_PUBLIC_KEY 128 +#define X509_R_UNKNOWN_KEY_TYPE 129 +#define X509_R_UNKNOWN_NID 130 +#define X509_R_UNKNOWN_PURPOSE_ID 131 +#define X509_R_UNKNOWN_TRUST_ID 132 +#define X509_R_UNSUPPORTED_ALGORITHM 133 +#define X509_R_WRONG_LOOKUP_TYPE 134 +#define X509_R_WRONG_TYPE 135 +#define X509_R_NO_CRLS_INCLUDED 136 + +#endif diff --git a/TMessagesProj/jni/boringssl/include/openssl/x509_vfy.h b/TMessagesProj/jni/boringssl/include/openssl/x509_vfy.h new file mode 100644 index 00000000..146e047a --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/x509_vfy.h @@ -0,0 +1,612 @@ +/* crypto/x509/x509_vfy.h */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * 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 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS 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 AUTHOR OR 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. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#ifndef HEADER_X509_H +#include +/* openssl/x509.h ends up #include-ing this file at about the only + * appropriate moment. */ +#endif + +#ifndef HEADER_X509_VFY_H +#define HEADER_X509_VFY_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if 0 +/* Outer object */ +typedef struct x509_hash_dir_st + { + int num_dirs; + char **dirs; + int *dirs_type; + int num_dirs_alloced; + } X509_HASH_DIR_CTX; +#endif + +typedef struct x509_file_st + { + int num_paths; /* number of paths to files or directories */ + int num_alloced; + char **paths; /* the list of paths or directories */ + int *path_type; + } X509_CERT_FILE_CTX; + +/*******************************/ +/* +SSL_CTX -> X509_STORE + -> X509_LOOKUP + ->X509_LOOKUP_METHOD + -> X509_LOOKUP + ->X509_LOOKUP_METHOD + +SSL -> X509_STORE_CTX + ->X509_STORE + +The X509_STORE holds the tables etc for verification stuff. +A X509_STORE_CTX is used while validating a single certificate. +The X509_STORE has X509_LOOKUPs for looking up certs. +The X509_STORE then calls a function to actually verify the +certificate chain. +*/ + +#define X509_LU_RETRY -1 +#define X509_LU_FAIL 0 +#define X509_LU_X509 1 +#define X509_LU_CRL 2 +#define X509_LU_PKEY 3 + +typedef struct x509_object_st + { + /* one of the above types */ + int type; + union { + char *ptr; + X509 *x509; + X509_CRL *crl; + EVP_PKEY *pkey; + } data; + } X509_OBJECT; + +typedef struct x509_lookup_st X509_LOOKUP; + +DECLARE_STACK_OF(X509_LOOKUP) +DECLARE_STACK_OF(X509_OBJECT) + +/* This is a static that defines the function interface */ +typedef struct x509_lookup_method_st + { + const char *name; + int (*new_item)(X509_LOOKUP *ctx); + void (*free)(X509_LOOKUP *ctx); + int (*init)(X509_LOOKUP *ctx); + int (*shutdown)(X509_LOOKUP *ctx); + int (*ctrl)(X509_LOOKUP *ctx,int cmd,const char *argc,long argl, + char **ret); + int (*get_by_subject)(X509_LOOKUP *ctx,int type,X509_NAME *name, + X509_OBJECT *ret); + int (*get_by_issuer_serial)(X509_LOOKUP *ctx,int type,X509_NAME *name, + ASN1_INTEGER *serial,X509_OBJECT *ret); + int (*get_by_fingerprint)(X509_LOOKUP *ctx,int type, + unsigned char *bytes,int len, + X509_OBJECT *ret); + int (*get_by_alias)(X509_LOOKUP *ctx,int type,char *str,int len, + X509_OBJECT *ret); + } X509_LOOKUP_METHOD; + +typedef struct X509_VERIFY_PARAM_ID_st X509_VERIFY_PARAM_ID; + +/* This structure hold all parameters associated with a verify operation + * by including an X509_VERIFY_PARAM structure in related structures the + * parameters used can be customized + */ + +typedef struct X509_VERIFY_PARAM_st + { + char *name; + time_t check_time; /* Time to use */ + unsigned long inh_flags; /* Inheritance flags */ + unsigned long flags; /* Various verify flags */ + int purpose; /* purpose to check untrusted certificates */ + int trust; /* trust setting to check */ + int depth; /* Verify depth */ + STACK_OF(ASN1_OBJECT) *policies; /* Permissible policies */ + X509_VERIFY_PARAM_ID *id; /* opaque ID data */ + } X509_VERIFY_PARAM; + +DECLARE_STACK_OF(X509_VERIFY_PARAM) + +/* This is used to hold everything. It is used for all certificate + * validation. Once we have a certificate chain, the 'verify' + * function is then called to actually check the cert chain. */ +struct x509_store_st + { + /* The following is a cache of trusted certs */ + int cache; /* if true, stash any hits */ + STACK_OF(X509_OBJECT) *objs; /* Cache of all objects */ + CRYPTO_MUTEX objs_lock; + + /* These are external lookup methods */ + STACK_OF(X509_LOOKUP) *get_cert_methods; + + X509_VERIFY_PARAM *param; + + /* Callbacks for various operations */ + int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */ + int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */ + int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */ + int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */ + int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */ + int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */ + int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */ + int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */ + STACK_OF(X509) * (*lookup_certs)(X509_STORE_CTX *ctx, X509_NAME *nm); + STACK_OF(X509_CRL) * (*lookup_crls)(X509_STORE_CTX *ctx, X509_NAME *nm); + int (*cleanup)(X509_STORE_CTX *ctx); + + CRYPTO_refcount_t references; + } /* X509_STORE */; + +OPENSSL_EXPORT int X509_STORE_set_depth(X509_STORE *store, int depth); + +#define X509_STORE_set_verify_cb_func(ctx,func) ((ctx)->verify_cb=(func)) +#define X509_STORE_set_verify_func(ctx,func) ((ctx)->verify=(func)) + +/* This is the functions plus an instance of the local variables. */ +struct x509_lookup_st + { + int init; /* have we been started */ + int skip; /* don't use us. */ + X509_LOOKUP_METHOD *method; /* the functions */ + char *method_data; /* method data */ + + X509_STORE *store_ctx; /* who owns us */ + } /* X509_LOOKUP */; + +/* This is a used when verifying cert chains. Since the + * gathering of the cert chain can take some time (and have to be + * 'retried', this needs to be kept and passed around. */ +struct x509_store_ctx_st /* X509_STORE_CTX */ + { + X509_STORE *ctx; + int current_method; /* used when looking up certs */ + + /* The following are set by the caller */ + X509 *cert; /* The cert to check */ + STACK_OF(X509) *untrusted; /* chain of X509s - untrusted - passed in */ + STACK_OF(X509_CRL) *crls; /* set of CRLs passed in */ + + X509_VERIFY_PARAM *param; + void *other_ctx; /* Other info for use with get_issuer() */ + + /* Callbacks for various operations */ + int (*verify)(X509_STORE_CTX *ctx); /* called to verify a certificate */ + int (*verify_cb)(int ok,X509_STORE_CTX *ctx); /* error callback */ + int (*get_issuer)(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); /* get issuers cert from ctx */ + int (*check_issued)(X509_STORE_CTX *ctx, X509 *x, X509 *issuer); /* check issued */ + int (*check_revocation)(X509_STORE_CTX *ctx); /* Check revocation status of chain */ + int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */ + int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */ + int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */ + int (*check_policy)(X509_STORE_CTX *ctx); + STACK_OF(X509) * (*lookup_certs)(X509_STORE_CTX *ctx, X509_NAME *nm); + STACK_OF(X509_CRL) * (*lookup_crls)(X509_STORE_CTX *ctx, X509_NAME *nm); + int (*cleanup)(X509_STORE_CTX *ctx); + + /* The following is built up */ + int valid; /* if 0, rebuild chain */ + int last_untrusted; /* index of last untrusted cert */ + STACK_OF(X509) *chain; /* chain of X509s - built up and trusted */ + X509_POLICY_TREE *tree; /* Valid policy tree */ + + int explicit_policy; /* Require explicit policy value */ + + /* When something goes wrong, this is why */ + int error_depth; + int error; + X509 *current_cert; + X509 *current_issuer; /* cert currently being tested as valid issuer */ + X509_CRL *current_crl; /* current CRL */ + + int current_crl_score; /* score of current CRL */ + unsigned int current_reasons; /* Reason mask */ + + X509_STORE_CTX *parent; /* For CRL path validation: parent context */ + + CRYPTO_EX_DATA ex_data; + } /* X509_STORE_CTX */; + +OPENSSL_EXPORT void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth); + +#define X509_STORE_CTX_set_app_data(ctx,data) \ + X509_STORE_CTX_set_ex_data(ctx,0,data) +#define X509_STORE_CTX_get_app_data(ctx) \ + X509_STORE_CTX_get_ex_data(ctx,0) + +#define X509_L_FILE_LOAD 1 +#define X509_L_ADD_DIR 2 + +#define X509_LOOKUP_load_file(x,name,type) \ + X509_LOOKUP_ctrl((x),X509_L_FILE_LOAD,(name),(long)(type),NULL) + +#define X509_LOOKUP_add_dir(x,name,type) \ + X509_LOOKUP_ctrl((x),X509_L_ADD_DIR,(name),(long)(type),NULL) + +#define X509_V_OK 0 +/* illegal error (for uninitialized values, to avoid X509_V_OK): 1 */ + +#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2 +#define X509_V_ERR_UNABLE_TO_GET_CRL 3 +#define X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE 4 +#define X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE 5 +#define X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 6 +#define X509_V_ERR_CERT_SIGNATURE_FAILURE 7 +#define X509_V_ERR_CRL_SIGNATURE_FAILURE 8 +#define X509_V_ERR_CERT_NOT_YET_VALID 9 +#define X509_V_ERR_CERT_HAS_EXPIRED 10 +#define X509_V_ERR_CRL_NOT_YET_VALID 11 +#define X509_V_ERR_CRL_HAS_EXPIRED 12 +#define X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD 13 +#define X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD 14 +#define X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD 15 +#define X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD 16 +#define X509_V_ERR_OUT_OF_MEM 17 +#define X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT 18 +#define X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN 19 +#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY 20 +#define X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE 21 +#define X509_V_ERR_CERT_CHAIN_TOO_LONG 22 +#define X509_V_ERR_CERT_REVOKED 23 +#define X509_V_ERR_INVALID_CA 24 +#define X509_V_ERR_PATH_LENGTH_EXCEEDED 25 +#define X509_V_ERR_INVALID_PURPOSE 26 +#define X509_V_ERR_CERT_UNTRUSTED 27 +#define X509_V_ERR_CERT_REJECTED 28 +/* These are 'informational' when looking for issuer cert */ +#define X509_V_ERR_SUBJECT_ISSUER_MISMATCH 29 +#define X509_V_ERR_AKID_SKID_MISMATCH 30 +#define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31 +#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32 + +#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33 +#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34 +#define X509_V_ERR_KEYUSAGE_NO_CRL_SIGN 35 +#define X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION 36 +#define X509_V_ERR_INVALID_NON_CA 37 +#define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38 +#define X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE 39 +#define X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED 40 + +#define X509_V_ERR_INVALID_EXTENSION 41 +#define X509_V_ERR_INVALID_POLICY_EXTENSION 42 +#define X509_V_ERR_NO_EXPLICIT_POLICY 43 +#define X509_V_ERR_DIFFERENT_CRL_SCOPE 44 +#define X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE 45 + +#define X509_V_ERR_UNNESTED_RESOURCE 46 + +#define X509_V_ERR_PERMITTED_VIOLATION 47 +#define X509_V_ERR_EXCLUDED_VIOLATION 48 +#define X509_V_ERR_SUBTREE_MINMAX 49 +#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE 51 +#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX 52 +#define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53 +#define X509_V_ERR_CRL_PATH_VALIDATION_ERROR 54 + +/* Suite B mode algorithm violation */ +#define X509_V_ERR_SUITE_B_INVALID_VERSION 56 +#define X509_V_ERR_SUITE_B_INVALID_ALGORITHM 57 +#define X509_V_ERR_SUITE_B_INVALID_CURVE 58 +#define X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM 59 +#define X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED 60 +#define X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 61 + +/* Host, email and IP check errors */ +#define X509_V_ERR_HOSTNAME_MISMATCH 62 +#define X509_V_ERR_EMAIL_MISMATCH 63 +#define X509_V_ERR_IP_ADDRESS_MISMATCH 64 + +/* The application is not happy */ +#define X509_V_ERR_APPLICATION_VERIFICATION 50 + +/* Certificate verify flags */ + +/* Send issuer+subject checks to verify_cb */ +#define X509_V_FLAG_CB_ISSUER_CHECK 0x1 +/* Use check time instead of current time */ +#define X509_V_FLAG_USE_CHECK_TIME 0x2 +/* Lookup CRLs */ +#define X509_V_FLAG_CRL_CHECK 0x4 +/* Lookup CRLs for whole chain */ +#define X509_V_FLAG_CRL_CHECK_ALL 0x8 +/* Ignore unhandled critical extensions */ +#define X509_V_FLAG_IGNORE_CRITICAL 0x10 +/* Disable workarounds for broken certificates */ +#define X509_V_FLAG_X509_STRICT 0x20 +/* Enable proxy certificate validation */ +#define X509_V_FLAG_ALLOW_PROXY_CERTS 0x40 +/* Enable policy checking */ +#define X509_V_FLAG_POLICY_CHECK 0x80 +/* Policy variable require-explicit-policy */ +#define X509_V_FLAG_EXPLICIT_POLICY 0x100 +/* Policy variable inhibit-any-policy */ +#define X509_V_FLAG_INHIBIT_ANY 0x200 +/* Policy variable inhibit-policy-mapping */ +#define X509_V_FLAG_INHIBIT_MAP 0x400 +/* Notify callback that policy is OK */ +#define X509_V_FLAG_NOTIFY_POLICY 0x800 +/* Extended CRL features such as indirect CRLs, alternate CRL signing keys */ +#define X509_V_FLAG_EXTENDED_CRL_SUPPORT 0x1000 +/* Delta CRL support */ +#define X509_V_FLAG_USE_DELTAS 0x2000 +/* Check selfsigned CA signature */ +#define X509_V_FLAG_CHECK_SS_SIGNATURE 0x4000 +/* Use trusted store first */ +#define X509_V_FLAG_TRUSTED_FIRST 0x8000 +/* Suite B 128 bit only mode: not normally used */ +#define X509_V_FLAG_SUITEB_128_LOS_ONLY 0x10000 +/* Suite B 192 bit only mode */ +#define X509_V_FLAG_SUITEB_192_LOS 0x20000 +/* Suite B 128 bit mode allowing 192 bit algorithms */ +#define X509_V_FLAG_SUITEB_128_LOS 0x30000 + +/* Allow partial chains if at least one certificate is in trusted store */ +#define X509_V_FLAG_PARTIAL_CHAIN 0x80000 + +#define X509_VP_FLAG_DEFAULT 0x1 +#define X509_VP_FLAG_OVERWRITE 0x2 +#define X509_VP_FLAG_RESET_FLAGS 0x4 +#define X509_VP_FLAG_LOCKED 0x8 +#define X509_VP_FLAG_ONCE 0x10 + +/* Internal use: mask of policy related options */ +#define X509_V_FLAG_POLICY_MASK (X509_V_FLAG_POLICY_CHECK \ + | X509_V_FLAG_EXPLICIT_POLICY \ + | X509_V_FLAG_INHIBIT_ANY \ + | X509_V_FLAG_INHIBIT_MAP) + +OPENSSL_EXPORT int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type, + X509_NAME *name); +OPENSSL_EXPORT X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h,int type,X509_NAME *name); +OPENSSL_EXPORT X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x); +OPENSSL_EXPORT void X509_OBJECT_up_ref_count(X509_OBJECT *a); +OPENSSL_EXPORT void X509_OBJECT_free_contents(X509_OBJECT *a); +OPENSSL_EXPORT X509_STORE *X509_STORE_new(void ); +OPENSSL_EXPORT void X509_STORE_free(X509_STORE *v); + +OPENSSL_EXPORT STACK_OF(X509)* X509_STORE_get1_certs(X509_STORE_CTX *st, X509_NAME *nm); +OPENSSL_EXPORT STACK_OF(X509_CRL)* X509_STORE_get1_crls(X509_STORE_CTX *st, X509_NAME *nm); +OPENSSL_EXPORT int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags); +OPENSSL_EXPORT int X509_STORE_set_purpose(X509_STORE *ctx, int purpose); +OPENSSL_EXPORT int X509_STORE_set_trust(X509_STORE *ctx, int trust); +OPENSSL_EXPORT int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *pm); + +OPENSSL_EXPORT void X509_STORE_set_verify_cb(X509_STORE *ctx, + int (*verify_cb)(int, X509_STORE_CTX *)); + +OPENSSL_EXPORT void X509_STORE_set_lookup_crls_cb(X509_STORE *ctx, + STACK_OF(X509_CRL)* (*cb)(X509_STORE_CTX *ctx, X509_NAME *nm)); + +OPENSSL_EXPORT X509_STORE_CTX *X509_STORE_CTX_new(void); + +OPENSSL_EXPORT int X509_STORE_CTX_get1_issuer(X509 **issuer, X509_STORE_CTX *ctx, X509 *x); + +OPENSSL_EXPORT void X509_STORE_CTX_free(X509_STORE_CTX *ctx); +OPENSSL_EXPORT int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, + X509 *x509, STACK_OF(X509) *chain); +OPENSSL_EXPORT void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk); +OPENSSL_EXPORT void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx); + +OPENSSL_EXPORT X509_STORE *X509_STORE_CTX_get0_store(X509_STORE_CTX *ctx); + +OPENSSL_EXPORT X509_LOOKUP *X509_STORE_add_lookup(X509_STORE *v, X509_LOOKUP_METHOD *m); + +OPENSSL_EXPORT X509_LOOKUP_METHOD *X509_LOOKUP_hash_dir(void); +OPENSSL_EXPORT X509_LOOKUP_METHOD *X509_LOOKUP_file(void); + +OPENSSL_EXPORT int X509_STORE_add_cert(X509_STORE *ctx, X509 *x); +OPENSSL_EXPORT int X509_STORE_add_crl(X509_STORE *ctx, X509_CRL *x); + +OPENSSL_EXPORT int X509_STORE_get_by_subject(X509_STORE_CTX *vs,int type,X509_NAME *name, + X509_OBJECT *ret); + +OPENSSL_EXPORT int X509_LOOKUP_ctrl(X509_LOOKUP *ctx, int cmd, const char *argc, + long argl, char **ret); + +#ifndef OPENSSL_NO_STDIO +OPENSSL_EXPORT int X509_load_cert_file(X509_LOOKUP *ctx, const char *file, int type); +OPENSSL_EXPORT int X509_load_crl_file(X509_LOOKUP *ctx, const char *file, int type); +OPENSSL_EXPORT int X509_load_cert_crl_file(X509_LOOKUP *ctx, const char *file, int type); +#endif + + +OPENSSL_EXPORT X509_LOOKUP *X509_LOOKUP_new(X509_LOOKUP_METHOD *method); +OPENSSL_EXPORT void X509_LOOKUP_free(X509_LOOKUP *ctx); +OPENSSL_EXPORT int X509_LOOKUP_init(X509_LOOKUP *ctx); +OPENSSL_EXPORT int X509_LOOKUP_by_subject(X509_LOOKUP *ctx, int type, X509_NAME *name, + X509_OBJECT *ret); +OPENSSL_EXPORT int X509_LOOKUP_by_issuer_serial(X509_LOOKUP *ctx, int type, X509_NAME *name, + ASN1_INTEGER *serial, X509_OBJECT *ret); +OPENSSL_EXPORT int X509_LOOKUP_by_fingerprint(X509_LOOKUP *ctx, int type, + unsigned char *bytes, int len, X509_OBJECT *ret); +OPENSSL_EXPORT int X509_LOOKUP_by_alias(X509_LOOKUP *ctx, int type, char *str, + int len, X509_OBJECT *ret); +OPENSSL_EXPORT int X509_LOOKUP_shutdown(X509_LOOKUP *ctx); + +#ifndef OPENSSL_NO_STDIO +OPENSSL_EXPORT int X509_STORE_load_locations (X509_STORE *ctx, + const char *file, const char *dir); +OPENSSL_EXPORT int X509_STORE_set_default_paths(X509_STORE *ctx); +#endif + +OPENSSL_EXPORT int X509_STORE_CTX_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, + CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func); +OPENSSL_EXPORT int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *ctx,int idx,void *data); +OPENSSL_EXPORT void * X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx,int idx); +OPENSSL_EXPORT int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx); +OPENSSL_EXPORT void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx,int s); +OPENSSL_EXPORT int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx); +OPENSSL_EXPORT X509 * X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx); +OPENSSL_EXPORT X509 *X509_STORE_CTX_get0_current_issuer(X509_STORE_CTX *ctx); +OPENSSL_EXPORT X509_CRL *X509_STORE_CTX_get0_current_crl(X509_STORE_CTX *ctx); +OPENSSL_EXPORT X509_STORE_CTX *X509_STORE_CTX_get0_parent_ctx(X509_STORE_CTX *ctx); +OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_CTX_get_chain(X509_STORE_CTX *ctx); +OPENSSL_EXPORT STACK_OF(X509) *X509_STORE_CTX_get1_chain(X509_STORE_CTX *ctx); +OPENSSL_EXPORT void X509_STORE_CTX_set_cert(X509_STORE_CTX *c,X509 *x); +OPENSSL_EXPORT void X509_STORE_CTX_set_chain(X509_STORE_CTX *c,STACK_OF(X509) *sk); +OPENSSL_EXPORT void X509_STORE_CTX_set0_crls(X509_STORE_CTX *c,STACK_OF(X509_CRL) *sk); +OPENSSL_EXPORT int X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose); +OPENSSL_EXPORT int X509_STORE_CTX_set_trust(X509_STORE_CTX *ctx, int trust); +OPENSSL_EXPORT int X509_STORE_CTX_purpose_inherit(X509_STORE_CTX *ctx, int def_purpose, + int purpose, int trust); +OPENSSL_EXPORT void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags); +OPENSSL_EXPORT void X509_STORE_CTX_set_time(X509_STORE_CTX *ctx, unsigned long flags, + time_t t); +OPENSSL_EXPORT void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *ctx, + int (*verify_cb)(int, X509_STORE_CTX *)); + +OPENSSL_EXPORT X509_POLICY_TREE *X509_STORE_CTX_get0_policy_tree(X509_STORE_CTX *ctx); +OPENSSL_EXPORT int X509_STORE_CTX_get_explicit_policy(X509_STORE_CTX *ctx); + +OPENSSL_EXPORT X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *ctx); +OPENSSL_EXPORT void X509_STORE_CTX_set0_param(X509_STORE_CTX *ctx, X509_VERIFY_PARAM *param); +OPENSSL_EXPORT int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, const char *name); + +/* X509_VERIFY_PARAM functions */ + +OPENSSL_EXPORT X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void); +OPENSSL_EXPORT void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param); +OPENSSL_EXPORT int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to, + const X509_VERIFY_PARAM *from); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, unsigned long flags); +OPENSSL_EXPORT int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, + unsigned long flags); +OPENSSL_EXPORT unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *param); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust); +OPENSSL_EXPORT void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth); +OPENSSL_EXPORT void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *param, time_t t); +OPENSSL_EXPORT int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *param, + ASN1_OBJECT *policy); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param, + STACK_OF(ASN1_OBJECT) *policies); + +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param, + const char *name, size_t namelen); +OPENSSL_EXPORT int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param, + const char *name, + size_t namelen); +OPENSSL_EXPORT void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param, + unsigned int flags); +OPENSSL_EXPORT char *X509_VERIFY_PARAM_get0_peername(X509_VERIFY_PARAM *); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param, + const char *email, size_t emaillen); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param, + const unsigned char *ip, size_t iplen); +OPENSSL_EXPORT int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc); + +OPENSSL_EXPORT int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param); +OPENSSL_EXPORT const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param); + +OPENSSL_EXPORT int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param); +OPENSSL_EXPORT int X509_VERIFY_PARAM_get_count(void); +OPENSSL_EXPORT const X509_VERIFY_PARAM *X509_VERIFY_PARAM_get0(int id); +OPENSSL_EXPORT const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name); +OPENSSL_EXPORT void X509_VERIFY_PARAM_table_cleanup(void); + +OPENSSL_EXPORT int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy, + STACK_OF(X509) *certs, + STACK_OF(ASN1_OBJECT) *policy_oids, + unsigned int flags); + +OPENSSL_EXPORT void X509_policy_tree_free(X509_POLICY_TREE *tree); + +OPENSSL_EXPORT int X509_policy_tree_level_count(const X509_POLICY_TREE *tree); +OPENSSL_EXPORT X509_POLICY_LEVEL * + X509_policy_tree_get0_level(const X509_POLICY_TREE *tree, int i); + +OPENSSL_EXPORT STACK_OF(X509_POLICY_NODE) * + X509_policy_tree_get0_policies(const X509_POLICY_TREE *tree); + +OPENSSL_EXPORT STACK_OF(X509_POLICY_NODE) * + X509_policy_tree_get0_user_policies(const X509_POLICY_TREE *tree); + +OPENSSL_EXPORT int X509_policy_level_node_count(X509_POLICY_LEVEL *level); + +OPENSSL_EXPORT X509_POLICY_NODE *X509_policy_level_get0_node(X509_POLICY_LEVEL *level, int i); + +OPENSSL_EXPORT const ASN1_OBJECT *X509_policy_node_get0_policy(const X509_POLICY_NODE *node); + +OPENSSL_EXPORT STACK_OF(POLICYQUALINFO) * + X509_policy_node_get0_qualifiers(const X509_POLICY_NODE *node); +OPENSSL_EXPORT const X509_POLICY_NODE * + X509_policy_node_get0_parent(const X509_POLICY_NODE *node); + +#ifdef __cplusplus +} +#endif +#endif + diff --git a/TMessagesProj/jni/boringssl/include/openssl/x509v3.h b/TMessagesProj/jni/boringssl/include/openssl/x509v3.h new file mode 100644 index 00000000..b7b8ba71 --- /dev/null +++ b/TMessagesProj/jni/boringssl/include/openssl/x509v3.h @@ -0,0 +1,798 @@ +/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL + * project 1999. */ +/* ==================================================================== + * Copyright (c) 1999-2004 The OpenSSL Project. 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. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * licensing@OpenSSL.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``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 OpenSSL PROJECT 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 product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#ifndef HEADER_X509V3_H +#define HEADER_X509V3_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Forward reference */ +struct v3_ext_method; +struct v3_ext_ctx; + +/* Useful typedefs */ + +typedef void * (*X509V3_EXT_NEW)(void); +typedef void (*X509V3_EXT_FREE)(void *); +typedef void * (*X509V3_EXT_D2I)(void *, const unsigned char ** , long); +typedef int (*X509V3_EXT_I2D)(void *, unsigned char **); +typedef STACK_OF(CONF_VALUE) * + (*X509V3_EXT_I2V)(const struct v3_ext_method *method, void *ext, + STACK_OF(CONF_VALUE) *extlist); +typedef void * (*X509V3_EXT_V2I)(const struct v3_ext_method *method, + struct v3_ext_ctx *ctx, + STACK_OF(CONF_VALUE) *values); +typedef char * (*X509V3_EXT_I2S)(const struct v3_ext_method *method, void *ext); +typedef void * (*X509V3_EXT_S2I)(const struct v3_ext_method *method, + struct v3_ext_ctx *ctx, const char *str); +typedef int (*X509V3_EXT_I2R)(const struct v3_ext_method *method, void *ext, + BIO *out, int indent); +typedef void * (*X509V3_EXT_R2I)(const struct v3_ext_method *method, + struct v3_ext_ctx *ctx, const char *str); + +/* V3 extension structure */ + +struct v3_ext_method { +int ext_nid; +int ext_flags; +/* If this is set the following four fields are ignored */ +ASN1_ITEM_EXP *it; +/* Old style ASN1 calls */ +X509V3_EXT_NEW ext_new; +X509V3_EXT_FREE ext_free; +X509V3_EXT_D2I d2i; +X509V3_EXT_I2D i2d; + +/* The following pair is used for string extensions */ +X509V3_EXT_I2S i2s; +X509V3_EXT_S2I s2i; + +/* The following pair is used for multi-valued extensions */ +X509V3_EXT_I2V i2v; +X509V3_EXT_V2I v2i; + +/* The following are used for raw extensions */ +X509V3_EXT_I2R i2r; +X509V3_EXT_R2I r2i; + +void *usr_data; /* Any extension specific data */ +}; + +typedef struct X509V3_CONF_METHOD_st { +char * (*get_string)(void *db, char *section, char *value); +STACK_OF(CONF_VALUE) * (*get_section)(void *db, char *section); +void (*free_string)(void *db, char * string); +void (*free_section)(void *db, STACK_OF(CONF_VALUE) *section); +} X509V3_CONF_METHOD; + +/* Context specific info */ +struct v3_ext_ctx { +#define CTX_TEST 0x1 +int flags; +X509 *issuer_cert; +X509 *subject_cert; +X509_REQ *subject_req; +X509_CRL *crl; +const X509V3_CONF_METHOD *db_meth; +void *db; +/* Maybe more here */ +}; + +typedef struct v3_ext_method X509V3_EXT_METHOD; + +DECLARE_STACK_OF(X509V3_EXT_METHOD) + +/* ext_flags values */ +#define X509V3_EXT_DYNAMIC 0x1 +#define X509V3_EXT_CTX_DEP 0x2 +#define X509V3_EXT_MULTILINE 0x4 + +typedef BIT_STRING_BITNAME ENUMERATED_NAMES; + +typedef struct BASIC_CONSTRAINTS_st { +int ca; +ASN1_INTEGER *pathlen; +} BASIC_CONSTRAINTS; + + +typedef struct PKEY_USAGE_PERIOD_st { +ASN1_GENERALIZEDTIME *notBefore; +ASN1_GENERALIZEDTIME *notAfter; +} PKEY_USAGE_PERIOD; + +typedef struct otherName_st { +ASN1_OBJECT *type_id; +ASN1_TYPE *value; +} OTHERNAME; + +typedef struct EDIPartyName_st { + ASN1_STRING *nameAssigner; + ASN1_STRING *partyName; +} EDIPARTYNAME; + +typedef struct GENERAL_NAME_st { + +#define GEN_OTHERNAME 0 +#define GEN_EMAIL 1 +#define GEN_DNS 2 +#define GEN_X400 3 +#define GEN_DIRNAME 4 +#define GEN_EDIPARTY 5 +#define GEN_URI 6 +#define GEN_IPADD 7 +#define GEN_RID 8 + +int type; +union { + char *ptr; + OTHERNAME *otherName; /* otherName */ + ASN1_IA5STRING *rfc822Name; + ASN1_IA5STRING *dNSName; + ASN1_TYPE *x400Address; + X509_NAME *directoryName; + EDIPARTYNAME *ediPartyName; + ASN1_IA5STRING *uniformResourceIdentifier; + ASN1_OCTET_STRING *iPAddress; + ASN1_OBJECT *registeredID; + + /* Old names */ + ASN1_OCTET_STRING *ip; /* iPAddress */ + X509_NAME *dirn; /* dirn */ + ASN1_IA5STRING *ia5;/* rfc822Name, dNSName, uniformResourceIdentifier */ + ASN1_OBJECT *rid; /* registeredID */ + ASN1_TYPE *other; /* x400Address */ +} d; +} GENERAL_NAME; + +typedef STACK_OF(GENERAL_NAME) GENERAL_NAMES; + +typedef struct ACCESS_DESCRIPTION_st { + ASN1_OBJECT *method; + GENERAL_NAME *location; +} ACCESS_DESCRIPTION; + +typedef STACK_OF(ACCESS_DESCRIPTION) AUTHORITY_INFO_ACCESS; + +typedef STACK_OF(ASN1_OBJECT) EXTENDED_KEY_USAGE; + +DECLARE_STACK_OF(GENERAL_NAME) +DECLARE_ASN1_SET_OF(GENERAL_NAME) + +DECLARE_STACK_OF(ACCESS_DESCRIPTION) +DECLARE_ASN1_SET_OF(ACCESS_DESCRIPTION) + +typedef struct DIST_POINT_NAME_st { +int type; +union { + GENERAL_NAMES *fullname; + STACK_OF(X509_NAME_ENTRY) *relativename; +} name; +/* If relativename then this contains the full distribution point name */ +X509_NAME *dpname; +} DIST_POINT_NAME; +/* All existing reasons */ +#define CRLDP_ALL_REASONS 0x807f + +#define CRL_REASON_NONE -1 +#define CRL_REASON_UNSPECIFIED 0 +#define CRL_REASON_KEY_COMPROMISE 1 +#define CRL_REASON_CA_COMPROMISE 2 +#define CRL_REASON_AFFILIATION_CHANGED 3 +#define CRL_REASON_SUPERSEDED 4 +#define CRL_REASON_CESSATION_OF_OPERATION 5 +#define CRL_REASON_CERTIFICATE_HOLD 6 +#define CRL_REASON_REMOVE_FROM_CRL 8 +#define CRL_REASON_PRIVILEGE_WITHDRAWN 9 +#define CRL_REASON_AA_COMPROMISE 10 + +struct DIST_POINT_st { +DIST_POINT_NAME *distpoint; +ASN1_BIT_STRING *reasons; +GENERAL_NAMES *CRLissuer; +int dp_reasons; +}; + +typedef STACK_OF(DIST_POINT) CRL_DIST_POINTS; + +DECLARE_STACK_OF(DIST_POINT) +DECLARE_ASN1_SET_OF(DIST_POINT) + +struct AUTHORITY_KEYID_st { +ASN1_OCTET_STRING *keyid; +GENERAL_NAMES *issuer; +ASN1_INTEGER *serial; +}; + +/* Strong extranet structures */ + +typedef struct SXNET_ID_st { + ASN1_INTEGER *zone; + ASN1_OCTET_STRING *user; +} SXNETID; + +DECLARE_STACK_OF(SXNETID) +DECLARE_ASN1_SET_OF(SXNETID) + +typedef struct SXNET_st { + ASN1_INTEGER *version; + STACK_OF(SXNETID) *ids; +} SXNET; + +typedef struct NOTICEREF_st { + ASN1_STRING *organization; + STACK_OF(ASN1_INTEGER) *noticenos; +} NOTICEREF; + +typedef struct USERNOTICE_st { + NOTICEREF *noticeref; + ASN1_STRING *exptext; +} USERNOTICE; + +typedef struct POLICYQUALINFO_st { + ASN1_OBJECT *pqualid; + union { + ASN1_IA5STRING *cpsuri; + USERNOTICE *usernotice; + ASN1_TYPE *other; + } d; +} POLICYQUALINFO; + +DECLARE_STACK_OF(POLICYQUALINFO) +DECLARE_ASN1_SET_OF(POLICYQUALINFO) + +typedef struct POLICYINFO_st { + ASN1_OBJECT *policyid; + STACK_OF(POLICYQUALINFO) *qualifiers; +} POLICYINFO; + +typedef STACK_OF(POLICYINFO) CERTIFICATEPOLICIES; + +DECLARE_STACK_OF(POLICYINFO) +DECLARE_ASN1_SET_OF(POLICYINFO) + +typedef struct POLICY_MAPPING_st { + ASN1_OBJECT *issuerDomainPolicy; + ASN1_OBJECT *subjectDomainPolicy; +} POLICY_MAPPING; + +DECLARE_STACK_OF(POLICY_MAPPING) + +typedef STACK_OF(POLICY_MAPPING) POLICY_MAPPINGS; + +typedef struct GENERAL_SUBTREE_st { + GENERAL_NAME *base; + ASN1_INTEGER *minimum; + ASN1_INTEGER *maximum; +} GENERAL_SUBTREE; + +DECLARE_STACK_OF(GENERAL_SUBTREE) + +struct NAME_CONSTRAINTS_st { + STACK_OF(GENERAL_SUBTREE) *permittedSubtrees; + STACK_OF(GENERAL_SUBTREE) *excludedSubtrees; +}; + +typedef struct POLICY_CONSTRAINTS_st { + ASN1_INTEGER *requireExplicitPolicy; + ASN1_INTEGER *inhibitPolicyMapping; +} POLICY_CONSTRAINTS; + +/* Proxy certificate structures, see RFC 3820 */ +typedef struct PROXY_POLICY_st + { + ASN1_OBJECT *policyLanguage; + ASN1_OCTET_STRING *policy; + } PROXY_POLICY; + +typedef struct PROXY_CERT_INFO_EXTENSION_st + { + ASN1_INTEGER *pcPathLengthConstraint; + PROXY_POLICY *proxyPolicy; + } PROXY_CERT_INFO_EXTENSION; + +DECLARE_ASN1_FUNCTIONS(PROXY_POLICY) +DECLARE_ASN1_FUNCTIONS(PROXY_CERT_INFO_EXTENSION) + +struct ISSUING_DIST_POINT_st + { + DIST_POINT_NAME *distpoint; + int onlyuser; + int onlyCA; + ASN1_BIT_STRING *onlysomereasons; + int indirectCRL; + int onlyattr; + }; + +/* Values in idp_flags field */ +/* IDP present */ +#define IDP_PRESENT 0x1 +/* IDP values inconsistent */ +#define IDP_INVALID 0x2 +/* onlyuser true */ +#define IDP_ONLYUSER 0x4 +/* onlyCA true */ +#define IDP_ONLYCA 0x8 +/* onlyattr true */ +#define IDP_ONLYATTR 0x10 +/* indirectCRL true */ +#define IDP_INDIRECT 0x20 +/* onlysomereasons present */ +#define IDP_REASONS 0x40 + +#define X509V3_conf_err(val) ERR_add_error_data(6, "section:", val->section, \ +",name:", val->name, ",value:", val->value); + +#define X509V3_set_ctx_test(ctx) \ + X509V3_set_ctx(ctx, NULL, NULL, NULL, NULL, CTX_TEST) +#define X509V3_set_ctx_nodb(ctx) (ctx)->db = NULL; + +#define EXT_BITSTRING(nid, table) { nid, 0, ASN1_ITEM_ref(ASN1_BIT_STRING), \ + 0,0,0,0, \ + 0,0, \ + (X509V3_EXT_I2V)i2v_ASN1_BIT_STRING, \ + (X509V3_EXT_V2I)v2i_ASN1_BIT_STRING, \ + NULL, NULL, \ + (void *)table} + +#define EXT_IA5STRING(nid) { nid, 0, ASN1_ITEM_ref(ASN1_IA5STRING), \ + 0,0,0,0, \ + (X509V3_EXT_I2S)i2s_ASN1_IA5STRING, \ + (X509V3_EXT_S2I)s2i_ASN1_IA5STRING, \ + 0,0,0,0, \ + NULL} + +#define EXT_END { -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + + +/* X509_PURPOSE stuff */ + +#define EXFLAG_BCONS 0x1 +#define EXFLAG_KUSAGE 0x2 +#define EXFLAG_XKUSAGE 0x4 +#define EXFLAG_NSCERT 0x8 + +#define EXFLAG_CA 0x10 +/* Really self issued not necessarily self signed */ +#define EXFLAG_SI 0x20 +#define EXFLAG_V1 0x40 +#define EXFLAG_INVALID 0x80 +#define EXFLAG_SET 0x100 +#define EXFLAG_CRITICAL 0x200 +#define EXFLAG_PROXY 0x400 + +#define EXFLAG_INVALID_POLICY 0x800 +#define EXFLAG_FRESHEST 0x1000 +/* Self signed */ +#define EXFLAG_SS 0x2000 + +#define KU_DIGITAL_SIGNATURE 0x0080 +#define KU_NON_REPUDIATION 0x0040 +#define KU_KEY_ENCIPHERMENT 0x0020 +#define KU_DATA_ENCIPHERMENT 0x0010 +#define KU_KEY_AGREEMENT 0x0008 +#define KU_KEY_CERT_SIGN 0x0004 +#define KU_CRL_SIGN 0x0002 +#define KU_ENCIPHER_ONLY 0x0001 +#define KU_DECIPHER_ONLY 0x8000 + +#define NS_SSL_CLIENT 0x80 +#define NS_SSL_SERVER 0x40 +#define NS_SMIME 0x20 +#define NS_OBJSIGN 0x10 +#define NS_SSL_CA 0x04 +#define NS_SMIME_CA 0x02 +#define NS_OBJSIGN_CA 0x01 +#define NS_ANY_CA (NS_SSL_CA|NS_SMIME_CA|NS_OBJSIGN_CA) + +#define XKU_SSL_SERVER 0x1 +#define XKU_SSL_CLIENT 0x2 +#define XKU_SMIME 0x4 +#define XKU_CODE_SIGN 0x8 +#define XKU_SGC 0x10 +#define XKU_OCSP_SIGN 0x20 +#define XKU_TIMESTAMP 0x40 +#define XKU_DVCS 0x80 +#define XKU_ANYEKU 0x100 + +#define X509_PURPOSE_DYNAMIC 0x1 +#define X509_PURPOSE_DYNAMIC_NAME 0x2 + +typedef struct x509_purpose_st { + int purpose; + int trust; /* Default trust ID */ + int flags; + int (*check_purpose)(const struct x509_purpose_st *, + const X509 *, int); + char *name; + char *sname; + void *usr_data; +} X509_PURPOSE; + +#define X509_PURPOSE_SSL_CLIENT 1 +#define X509_PURPOSE_SSL_SERVER 2 +#define X509_PURPOSE_NS_SSL_SERVER 3 +#define X509_PURPOSE_SMIME_SIGN 4 +#define X509_PURPOSE_SMIME_ENCRYPT 5 +#define X509_PURPOSE_CRL_SIGN 6 +#define X509_PURPOSE_ANY 7 +#define X509_PURPOSE_OCSP_HELPER 8 +#define X509_PURPOSE_TIMESTAMP_SIGN 9 + +#define X509_PURPOSE_MIN 1 +#define X509_PURPOSE_MAX 9 + +/* Flags for X509V3_EXT_print() */ + +#define X509V3_EXT_UNKNOWN_MASK (0xfL << 16) +/* Return error for unknown extensions */ +#define X509V3_EXT_DEFAULT 0 +/* Print error for unknown extensions */ +#define X509V3_EXT_ERROR_UNKNOWN (1L << 16) +/* ASN1 parse unknown extensions */ +#define X509V3_EXT_PARSE_UNKNOWN (2L << 16) +/* BIO_dump unknown extensions */ +#define X509V3_EXT_DUMP_UNKNOWN (3L << 16) + +/* Flags for X509V3_add1_i2d */ + +#define X509V3_ADD_OP_MASK 0xfL +#define X509V3_ADD_DEFAULT 0L +#define X509V3_ADD_APPEND 1L +#define X509V3_ADD_REPLACE 2L +#define X509V3_ADD_REPLACE_EXISTING 3L +#define X509V3_ADD_KEEP_EXISTING 4L +#define X509V3_ADD_DELETE 5L +#define X509V3_ADD_SILENT 0x10 + +DECLARE_STACK_OF(X509_PURPOSE) + +DECLARE_ASN1_FUNCTIONS(BASIC_CONSTRAINTS) + +DECLARE_ASN1_FUNCTIONS(SXNET) +DECLARE_ASN1_FUNCTIONS(SXNETID) + +int SXNET_add_id_asc(SXNET **psx, char *zone, char *user, int userlen); +int SXNET_add_id_ulong(SXNET **psx, unsigned long lzone, char *user, int userlen); +int SXNET_add_id_INTEGER(SXNET **psx, ASN1_INTEGER *izone, char *user, int userlen); + +ASN1_OCTET_STRING *SXNET_get_id_asc(SXNET *sx, char *zone); +ASN1_OCTET_STRING *SXNET_get_id_ulong(SXNET *sx, unsigned long lzone); +ASN1_OCTET_STRING *SXNET_get_id_INTEGER(SXNET *sx, ASN1_INTEGER *zone); + +DECLARE_ASN1_FUNCTIONS(AUTHORITY_KEYID) + +DECLARE_ASN1_FUNCTIONS(PKEY_USAGE_PERIOD) + +DECLARE_ASN1_FUNCTIONS(GENERAL_NAME) +OPENSSL_EXPORT GENERAL_NAME *GENERAL_NAME_dup(GENERAL_NAME *a); +OPENSSL_EXPORT int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b); + + + +OPENSSL_EXPORT ASN1_BIT_STRING *v2i_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); +OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_ASN1_BIT_STRING(X509V3_EXT_METHOD *method, + ASN1_BIT_STRING *bits, + STACK_OF(CONF_VALUE) *extlist); + +OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, GENERAL_NAME *gen, STACK_OF(CONF_VALUE) *ret); +OPENSSL_EXPORT int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen); + +DECLARE_ASN1_FUNCTIONS(GENERAL_NAMES) + +OPENSSL_EXPORT STACK_OF(CONF_VALUE) *i2v_GENERAL_NAMES(X509V3_EXT_METHOD *method, + GENERAL_NAMES *gen, STACK_OF(CONF_VALUE) *extlist); +OPENSSL_EXPORT GENERAL_NAMES *v2i_GENERAL_NAMES(const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *nval); + +DECLARE_ASN1_FUNCTIONS(OTHERNAME) +DECLARE_ASN1_FUNCTIONS(EDIPARTYNAME) +OPENSSL_EXPORT int OTHERNAME_cmp(OTHERNAME *a, OTHERNAME *b); +OPENSSL_EXPORT void GENERAL_NAME_set0_value(GENERAL_NAME *a, int type, void *value); +OPENSSL_EXPORT void *GENERAL_NAME_get0_value(GENERAL_NAME *a, int *ptype); +OPENSSL_EXPORT int GENERAL_NAME_set0_othername(GENERAL_NAME *gen, + ASN1_OBJECT *oid, ASN1_TYPE *value); +OPENSSL_EXPORT int GENERAL_NAME_get0_otherName(GENERAL_NAME *gen, + ASN1_OBJECT **poid, ASN1_TYPE **pvalue); + +OPENSSL_EXPORT char *i2s_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, ASN1_OCTET_STRING *ia5); +OPENSSL_EXPORT ASN1_OCTET_STRING *s2i_ASN1_OCTET_STRING(X509V3_EXT_METHOD *method, X509V3_CTX *ctx, char *str); + +DECLARE_ASN1_FUNCTIONS(EXTENDED_KEY_USAGE) +OPENSSL_EXPORT int i2a_ACCESS_DESCRIPTION(BIO *bp, ACCESS_DESCRIPTION* a); + +DECLARE_ASN1_FUNCTIONS(CERTIFICATEPOLICIES) +DECLARE_ASN1_FUNCTIONS(POLICYINFO) +DECLARE_ASN1_FUNCTIONS(POLICYQUALINFO) +DECLARE_ASN1_FUNCTIONS(USERNOTICE) +DECLARE_ASN1_FUNCTIONS(NOTICEREF) + +DECLARE_ASN1_FUNCTIONS(CRL_DIST_POINTS) +DECLARE_ASN1_FUNCTIONS(DIST_POINT) +DECLARE_ASN1_FUNCTIONS(DIST_POINT_NAME) +DECLARE_ASN1_FUNCTIONS(ISSUING_DIST_POINT) + +OPENSSL_EXPORT int DIST_POINT_set_dpname(DIST_POINT_NAME *dpn, X509_NAME *iname); + +OPENSSL_EXPORT int NAME_CONSTRAINTS_check(X509 *x, NAME_CONSTRAINTS *nc); + +DECLARE_ASN1_FUNCTIONS(ACCESS_DESCRIPTION) +DECLARE_ASN1_FUNCTIONS(AUTHORITY_INFO_ACCESS) + +DECLARE_ASN1_ITEM(POLICY_MAPPING) +DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_MAPPING) +DECLARE_ASN1_ITEM(POLICY_MAPPINGS) + +DECLARE_ASN1_ITEM(GENERAL_SUBTREE) +DECLARE_ASN1_ALLOC_FUNCTIONS(GENERAL_SUBTREE) + +DECLARE_ASN1_ITEM(NAME_CONSTRAINTS) +DECLARE_ASN1_ALLOC_FUNCTIONS(NAME_CONSTRAINTS) + +DECLARE_ASN1_ALLOC_FUNCTIONS(POLICY_CONSTRAINTS) +DECLARE_ASN1_ITEM(POLICY_CONSTRAINTS) + +OPENSSL_EXPORT GENERAL_NAME *a2i_GENERAL_NAME(GENERAL_NAME *out, + const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + int gen_type, char *value, int is_nc); + +OPENSSL_EXPORT GENERAL_NAME *v2i_GENERAL_NAME(const X509V3_EXT_METHOD *method, X509V3_CTX *ctx, + CONF_VALUE *cnf); +OPENSSL_EXPORT GENERAL_NAME *v2i_GENERAL_NAME_ex(GENERAL_NAME *out, + const X509V3_EXT_METHOD *method, + X509V3_CTX *ctx, CONF_VALUE *cnf, int is_nc); +OPENSSL_EXPORT void X509V3_conf_free(CONF_VALUE *val); + +OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_nconf_nid(CONF *conf, X509V3_CTX *ctx, int ext_nid, char *value); +OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_nconf(CONF *conf, X509V3_CTX *ctx, char *name, char *value); +OPENSSL_EXPORT int X509V3_EXT_add_nconf_sk(CONF *conf, X509V3_CTX *ctx, char *section, STACK_OF(X509_EXTENSION) **sk); +OPENSSL_EXPORT int X509V3_EXT_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509 *cert); +OPENSSL_EXPORT int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_REQ *req); +OPENSSL_EXPORT int X509V3_EXT_CRL_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section, X509_CRL *crl); + +OPENSSL_EXPORT int X509V3_EXT_CRL_add_conf(LHASH_OF(CONF_VALUE) *conf, X509V3_CTX *ctx, + char *section, X509_CRL *crl); + +OPENSSL_EXPORT int X509V3_add_value_bool_nf(char *name, int asn1_bool, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT int X509V3_get_value_bool(CONF_VALUE *value, int *asn1_bool); +OPENSSL_EXPORT int X509V3_get_value_int(CONF_VALUE *value, ASN1_INTEGER **aint); +OPENSSL_EXPORT void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf); + +OPENSSL_EXPORT char * X509V3_get_string(X509V3_CTX *ctx, char *name, char *section); +OPENSSL_EXPORT STACK_OF(CONF_VALUE) * X509V3_get_section(X509V3_CTX *ctx, char *section); +OPENSSL_EXPORT void X509V3_string_free(X509V3_CTX *ctx, char *str); +OPENSSL_EXPORT void X509V3_section_free( X509V3_CTX *ctx, STACK_OF(CONF_VALUE) *section); +OPENSSL_EXPORT void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject, + X509_REQ *req, X509_CRL *crl, int flags); + +OPENSSL_EXPORT int X509V3_add_value(const char *name, const char *value, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT int X509V3_add_value_uchar(const char *name, const unsigned char *value, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT int X509V3_add_value_bool(const char *name, int asn1_bool, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT int X509V3_add_value_int(const char *name, ASN1_INTEGER *aint, + STACK_OF(CONF_VALUE) **extlist); +OPENSSL_EXPORT char * i2s_ASN1_INTEGER(X509V3_EXT_METHOD *meth, ASN1_INTEGER *aint); +OPENSSL_EXPORT ASN1_INTEGER * s2i_ASN1_INTEGER(X509V3_EXT_METHOD *meth, char *value); +OPENSSL_EXPORT char * i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint); +OPENSSL_EXPORT char * i2s_ASN1_ENUMERATED_TABLE(X509V3_EXT_METHOD *meth, ASN1_ENUMERATED *aint); +OPENSSL_EXPORT int X509V3_EXT_add(X509V3_EXT_METHOD *ext); +OPENSSL_EXPORT int X509V3_EXT_add_list(X509V3_EXT_METHOD *extlist); +OPENSSL_EXPORT int X509V3_EXT_add_alias(int nid_to, int nid_from); +OPENSSL_EXPORT void X509V3_EXT_cleanup(void); + +OPENSSL_EXPORT const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *ext); +OPENSSL_EXPORT const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid); +OPENSSL_EXPORT int X509V3_add_standard_extensions(void); +OPENSSL_EXPORT STACK_OF(CONF_VALUE) *X509V3_parse_list(const char *line); +OPENSSL_EXPORT void *X509V3_EXT_d2i(X509_EXTENSION *ext); +OPENSSL_EXPORT void *X509V3_get_d2i(STACK_OF(X509_EXTENSION) *x, int nid, int *crit, int *idx); + + +OPENSSL_EXPORT X509_EXTENSION *X509V3_EXT_i2d(int ext_nid, int crit, void *ext_struc); +OPENSSL_EXPORT int X509V3_add1_i2d(STACK_OF(X509_EXTENSION) **x, int nid, void *value, int crit, unsigned long flags); + +char *hex_to_string(const unsigned char *buffer, long len); +unsigned char *string_to_hex(const char *str, long *len); +int name_cmp(const char *name, const char *cmp); + +OPENSSL_EXPORT void X509V3_EXT_val_prn(BIO *out, STACK_OF(CONF_VALUE) *val, int indent, + int ml); +OPENSSL_EXPORT int X509V3_EXT_print(BIO *out, X509_EXTENSION *ext, unsigned long flag, int indent); +OPENSSL_EXPORT int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, int indent); + +OPENSSL_EXPORT int X509V3_extensions_print(BIO *out, const char *title, STACK_OF(X509_EXTENSION) *exts, unsigned long flag, int indent); + +OPENSSL_EXPORT int X509_check_ca(X509 *x); +OPENSSL_EXPORT int X509_check_purpose(X509 *x, int id, int ca); +OPENSSL_EXPORT int X509_supported_extension(X509_EXTENSION *ex); +OPENSSL_EXPORT int X509_PURPOSE_set(int *p, int purpose); +OPENSSL_EXPORT int X509_check_issued(X509 *issuer, X509 *subject); +OPENSSL_EXPORT int X509_check_akid(X509 *issuer, AUTHORITY_KEYID *akid); +OPENSSL_EXPORT int X509_PURPOSE_get_count(void); +OPENSSL_EXPORT X509_PURPOSE * X509_PURPOSE_get0(int idx); +OPENSSL_EXPORT int X509_PURPOSE_get_by_sname(char *sname); +OPENSSL_EXPORT int X509_PURPOSE_get_by_id(int id); +OPENSSL_EXPORT int X509_PURPOSE_add(int id, int trust, int flags, + int (*ck)(const X509_PURPOSE *, const X509 *, int), + char *name, char *sname, void *arg); +OPENSSL_EXPORT char *X509_PURPOSE_get0_name(X509_PURPOSE *xp); +OPENSSL_EXPORT char *X509_PURPOSE_get0_sname(X509_PURPOSE *xp); +OPENSSL_EXPORT int X509_PURPOSE_get_trust(X509_PURPOSE *xp); +OPENSSL_EXPORT void X509_PURPOSE_cleanup(void); +OPENSSL_EXPORT int X509_PURPOSE_get_id(X509_PURPOSE *); + +OPENSSL_EXPORT STACK_OF(OPENSSL_STRING) *X509_get1_email(X509 *x); +OPENSSL_EXPORT STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x); +OPENSSL_EXPORT void X509_email_free(STACK_OF(OPENSSL_STRING) *sk); +OPENSSL_EXPORT STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x); +/* Flags for X509_check_* functions */ + +/* Always check subject name for host match even if subject alt names present */ +#define X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT 0x1 +/* Disable wildcard matching for dnsName fields and common name. */ +#define X509_CHECK_FLAG_NO_WILDCARDS 0x2 +/* Wildcards must not match a partial label. */ +#define X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS 0x4 +/* Allow (non-partial) wildcards to match multiple labels. */ +#define X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS 0x8 +/* Constraint verifier subdomain patterns to match a single labels. */ +#define X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS 0x10 +/* + * Match reference identifiers starting with "." to any sub-domain. + * This is a non-public flag, turned on implicitly when the subject + * reference identity is a DNS name. + */ +#define _X509_CHECK_FLAG_DOT_SUBDOMAINS 0x8000 + +OPENSSL_EXPORT int X509_check_host(X509 *x, const char *chk, size_t chklen, + unsigned int flags, char **peername); +OPENSSL_EXPORT int X509_check_email(X509 *x, const char *chk, size_t chklen, + unsigned int flags); +OPENSSL_EXPORT int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen, + unsigned int flags); +OPENSSL_EXPORT int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags); + +OPENSSL_EXPORT ASN1_OCTET_STRING *a2i_IPADDRESS(const char *ipasc); +OPENSSL_EXPORT ASN1_OCTET_STRING *a2i_IPADDRESS_NC(const char *ipasc); +OPENSSL_EXPORT int a2i_ipadd(unsigned char *ipout, const char *ipasc); +OPENSSL_EXPORT int X509V3_NAME_from_section(X509_NAME *nm, STACK_OF(CONF_VALUE)*dn_sk, + unsigned long chtype); + +OPENSSL_EXPORT void X509_POLICY_NODE_print(BIO *out, X509_POLICY_NODE *node, int indent); +DECLARE_STACK_OF(X509_POLICY_NODE) + +/* BEGIN ERROR CODES */ +/* The following lines are auto generated by the script mkerr.pl. Any changes + * made after this point may be overwritten when the script is next run. + */ +void ERR_load_X509V3_strings(void); + + +#ifdef __cplusplus +} +#endif +#define X509V3_R_BAD_IP_ADDRESS 100 +#define X509V3_R_BAD_OBJECT 101 +#define X509V3_R_BN_DEC2BN_ERROR 102 +#define X509V3_R_BN_TO_ASN1_INTEGER_ERROR 103 +#define X509V3_R_CANNOT_FIND_FREE_FUNCTION 104 +#define X509V3_R_DIRNAME_ERROR 105 +#define X509V3_R_DISTPOINT_ALREADY_SET 106 +#define X509V3_R_DUPLICATE_ZONE_ID 107 +#define X509V3_R_ERROR_CONVERTING_ZONE 108 +#define X509V3_R_ERROR_CREATING_EXTENSION 109 +#define X509V3_R_ERROR_IN_EXTENSION 110 +#define X509V3_R_EXPECTED_A_SECTION_NAME 111 +#define X509V3_R_EXTENSION_EXISTS 112 +#define X509V3_R_EXTENSION_NAME_ERROR 113 +#define X509V3_R_EXTENSION_NOT_FOUND 114 +#define X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED 115 +#define X509V3_R_EXTENSION_VALUE_ERROR 116 +#define X509V3_R_ILLEGAL_EMPTY_EXTENSION 117 +#define X509V3_R_ILLEGAL_HEX_DIGIT 118 +#define X509V3_R_INCORRECT_POLICY_SYNTAX_TAG 119 +#define X509V3_R_INVALID_BOOLEAN_STRING 120 +#define X509V3_R_INVALID_EXTENSION_STRING 121 +#define X509V3_R_INVALID_MULTIPLE_RDNS 122 +#define X509V3_R_INVALID_NAME 123 +#define X509V3_R_INVALID_NULL_ARGUMENT 124 +#define X509V3_R_INVALID_NULL_NAME 125 +#define X509V3_R_INVALID_NULL_VALUE 126 +#define X509V3_R_INVALID_NUMBER 127 +#define X509V3_R_INVALID_NUMBERS 128 +#define X509V3_R_INVALID_OBJECT_IDENTIFIER 129 +#define X509V3_R_INVALID_OPTION 130 +#define X509V3_R_INVALID_POLICY_IDENTIFIER 131 +#define X509V3_R_INVALID_PROXY_POLICY_SETTING 132 +#define X509V3_R_INVALID_PURPOSE 133 +#define X509V3_R_INVALID_SECTION 134 +#define X509V3_R_INVALID_SYNTAX 135 +#define X509V3_R_ISSUER_DECODE_ERROR 136 +#define X509V3_R_MISSING_VALUE 137 +#define X509V3_R_NEED_ORGANIZATION_AND_NUMBERS 138 +#define X509V3_R_NO_CONFIG_DATABASE 139 +#define X509V3_R_NO_ISSUER_CERTIFICATE 140 +#define X509V3_R_NO_ISSUER_DETAILS 141 +#define X509V3_R_NO_POLICY_IDENTIFIER 142 +#define X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED 143 +#define X509V3_R_NO_PUBLIC_KEY 144 +#define X509V3_R_NO_SUBJECT_DETAILS 145 +#define X509V3_R_ODD_NUMBER_OF_DIGITS 146 +#define X509V3_R_OPERATION_NOT_DEFINED 147 +#define X509V3_R_OTHERNAME_ERROR 148 +#define X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED 149 +#define X509V3_R_POLICY_PATH_LENGTH 150 +#define X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED 151 +#define X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY 152 +#define X509V3_R_SECTION_NOT_FOUND 153 +#define X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS 154 +#define X509V3_R_UNABLE_TO_GET_ISSUER_KEYID 155 +#define X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT 156 +#define X509V3_R_UNKNOWN_EXTENSION 157 +#define X509V3_R_UNKNOWN_EXTENSION_NAME 158 +#define X509V3_R_UNKNOWN_OPTION 159 +#define X509V3_R_UNSUPPORTED_OPTION 160 +#define X509V3_R_UNSUPPORTED_TYPE 161 +#define X509V3_R_USER_TOO_LONG 162 + +#endif diff --git a/TMessagesProj/jni/boringssl/lib/libcrypto_armeabi-v7a.a b/TMessagesProj/jni/boringssl/lib/libcrypto_armeabi-v7a.a new file mode 100644 index 00000000..6f7fc05c Binary files /dev/null and b/TMessagesProj/jni/boringssl/lib/libcrypto_armeabi-v7a.a differ diff --git a/TMessagesProj/jni/boringssl/lib/libcrypto_armeabi.a b/TMessagesProj/jni/boringssl/lib/libcrypto_armeabi.a new file mode 100644 index 00000000..c9fe7418 Binary files /dev/null and b/TMessagesProj/jni/boringssl/lib/libcrypto_armeabi.a differ diff --git a/TMessagesProj/jni/boringssl/lib/libcrypto_x86.a b/TMessagesProj/jni/boringssl/lib/libcrypto_x86.a new file mode 100644 index 00000000..009a63c6 Binary files /dev/null and b/TMessagesProj/jni/boringssl/lib/libcrypto_x86.a differ diff --git a/TMessagesProj/jni/boringssl/util/android-cmake/AndroidNdkGdb.cmake b/TMessagesProj/jni/boringssl/util/android-cmake/AndroidNdkGdb.cmake new file mode 100644 index 00000000..0677dcda --- /dev/null +++ b/TMessagesProj/jni/boringssl/util/android-cmake/AndroidNdkGdb.cmake @@ -0,0 +1,96 @@ +# Copyright (c) 2014, Pavel Rojtberg +# 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. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS 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 COPYRIGHT HOLDER OR 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. + +# ------------------------------------------------------------------------------ +# Usage: +# 1. place AndroidNdkGdb.cmake somewhere inside ${CMAKE_MODULE_PATH} +# 2. inside your project add +# +# include(AndroidNdkGdb) +# android_ndk_gdb_enable() +# # for each target +# add_library(MyLibrary ...) +# android_ndk_gdb_debuggable(MyLibrary) + + +# add gdbserver and general gdb configuration to project +# also create a mininal NDK skeleton so ndk-gdb finds the paths +# +# the optional parameter defines the path to the android project. +# uses PROJECT_SOURCE_DIR by default. +macro(android_ndk_gdb_enable) + if(ANDROID) + # create custom target that depends on the real target so it gets executed afterwards + add_custom_target(NDK_GDB ALL) + + if(${ARGC}) + set(ANDROID_PROJECT_DIR ${ARGV0}) + else() + set(ANDROID_PROJECT_DIR ${PROJECT_SOURCE_DIR}) + endif() + + set(NDK_GDB_SOLIB_PATH ${ANDROID_PROJECT_DIR}/obj/local/${ANDROID_NDK_ABI_NAME}/) + file(MAKE_DIRECTORY ${NDK_GDB_SOLIB_PATH}) + + # 1. generate essential Android Makefiles + file(MAKE_DIRECTORY ${ANDROID_PROJECT_DIR}/jni) + if(NOT EXISTS ${ANDROID_PROJECT_DIR}/jni/Android.mk) + file(WRITE ${ANDROID_PROJECT_DIR}/jni/Android.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n") + endif() + if(NOT EXISTS ${ANDROID_PROJECT_DIR}/jni/Application.mk) + file(WRITE ${ANDROID_PROJECT_DIR}/jni/Application.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n") + endif() + + # 2. generate gdb.setup + get_directory_property(PROJECT_INCLUDES DIRECTORY ${PROJECT_SOURCE_DIR} INCLUDE_DIRECTORIES) + string(REGEX REPLACE ";" " " PROJECT_INCLUDES "${PROJECT_INCLUDES}") + file(WRITE ${LIBRARY_OUTPUT_PATH}/gdb.setup "set solib-search-path ${NDK_GDB_SOLIB_PATH}\n") + file(APPEND ${LIBRARY_OUTPUT_PATH}/gdb.setup "directory ${PROJECT_INCLUDES}\n") + + # 3. copy gdbserver executable + file(COPY ${ANDROID_NDK}/prebuilt/android-${ANDROID_ARCH_NAME}/gdbserver/gdbserver DESTINATION ${LIBRARY_OUTPUT_PATH}) + endif() +endmacro() + +# register a target for remote debugging +# copies the debug version to NDK_GDB_SOLIB_PATH then strips symbols of original +macro(android_ndk_gdb_debuggable TARGET_NAME) + if(ANDROID) + get_property(TARGET_LOCATION TARGET ${TARGET_NAME} PROPERTY LOCATION) + + # create custom target that depends on the real target so it gets executed afterwards + add_dependencies(NDK_GDB ${TARGET_NAME}) + + # 4. copy lib to obj + add_custom_command(TARGET NDK_GDB POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${TARGET_LOCATION} ${NDK_GDB_SOLIB_PATH}) + + # 5. strip symbols + add_custom_command(TARGET NDK_GDB POST_BUILD COMMAND ${CMAKE_STRIP} ${TARGET_LOCATION}) + endif() +endmacro() diff --git a/TMessagesProj/jni/boringssl/util/android-cmake/AndroidNdkModules.cmake b/TMessagesProj/jni/boringssl/util/android-cmake/AndroidNdkModules.cmake new file mode 100644 index 00000000..64f37fde --- /dev/null +++ b/TMessagesProj/jni/boringssl/util/android-cmake/AndroidNdkModules.cmake @@ -0,0 +1,58 @@ +# Copyright (c) 2014, Pavel Rojtberg +# 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. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS 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 COPYRIGHT HOLDER OR 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. + +macro(android_ndk_import_module_cpufeatures) + if(ANDROID) + include_directories(${ANDROID_NDK}/sources/android/cpufeatures) + add_library(cpufeatures ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c) + target_link_libraries(cpufeatures dl) + endif() +endmacro() + +macro(android_ndk_import_module_native_app_glue) + if(ANDROID) + include_directories(${ANDROID_NDK}/sources/android/native_app_glue) + add_library(native_app_glue ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c) + target_link_libraries(native_app_glue log) + endif() +endmacro() + +macro(android_ndk_import_module_ndk_helper) + if(ANDROID) + android_ndk_import_module_cpufeatures() + android_ndk_import_module_native_app_glue() + + include_directories(${ANDROID_NDK}/sources/android/ndk_helper) + file(GLOB _NDK_HELPER_SRCS ${ANDROID_NDK}/sources/android/ndk_helper/*.cpp ${ANDROID_NDK}/sources/android/ndk_helper/gl3stub.c) + add_library(ndk_helper ${_NDK_HELPER_SRCS}) + target_link_libraries(ndk_helper log android EGL GLESv2 cpufeatures native_app_glue) + + unset(_NDK_HELPER_SRCS) + endif() +endmacro() \ No newline at end of file diff --git a/TMessagesProj/jni/boringssl/util/android-cmake/README.md b/TMessagesProj/jni/boringssl/util/android-cmake/README.md new file mode 100644 index 00000000..ee630212 --- /dev/null +++ b/TMessagesProj/jni/boringssl/util/android-cmake/README.md @@ -0,0 +1,240 @@ +# android-cmake + +CMake is great, and so is Android. This is a collection of CMake scripts that may be useful to the Android NDK community. It is based on experience from porting OpenCV library to Android: http://opencv.org/platforms/android.html + +Main goal is to share these scripts so that devs that use CMake as their build system may easily compile native code for Android. + +## TL;DR + + cmake -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake \ + -DANDROID_NDK= \ + -DCMAKE_BUILD_TYPE=Release \ + -DANDROID_ABI="armeabi-v7a with NEON" \ + + cmake --build . + +One-liner: + + cmake -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake -DANDROID_NDK= -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="armeabi-v7a with NEON" && cmake --build . + +_android-cmake_ will search for your NDK install in the following order: + +1. Value of `ANDROID_NDK` CMake variable; +1. Value of `ANDROID_NDK` environment variable; +1. Search under paths from `ANDROID_NDK_SEARCH_PATHS` CMake variable; +1. Search platform specific locations (home folder, Windows "Program Files", etc). + +So if you have installed the NDK as `~/android-ndk-r10d` then _android-cmake_ will locate it automatically. + +## Getting started + +To build a cmake-based C/C++ project for Android you need: + +* Android NDK (>= r5) http://developer.android.com/tools/sdk/ndk/index.html +* CMake (>= v2.6.3, >= v2.8.9 recommended) http://www.cmake.org/download + +The _android-cmake_ is also capable to build with NDK from AOSP or Linaro Android source tree, but you may be required to manually specify path to `libm` binary to link with. + +## Difference from traditional CMake + +Folowing the _ndk-build_ the _android-cmake_ supports **only two build targets**: + +* `-DCMAKE_BUILD_TYPE=Release` +* `-DCMAKE_BUILD_TYPE=Debug` + +So don't even try other targets that can be found in CMake documentation and don't forget to explicitly specify `Release` or `Debug` because CMake builds without a build configuration by default. + +## Difference from _ndk-build_ + +* Latest GCC available in NDK is used as the default compiler; +* `Release` builds with `-O3` instead of `-Os`; +* `Release` builds without debug info (without `-g`) (because _ndk-build_ always creates a stripped version but cmake delays this for `install/strip` target); +* `-fsigned-char` is added to compiler flags to make `char` signed by default as it is on x86/x86_64; +* GCC's stack protector is not used neither in `Debug` nor `Release` configurations; +* No builds for multiple platforms (e.g. building for both arm and x86 require to run cmake twice with different parameters); +* No file level Neon via `.neon` suffix; + +The following features of _ndk-build_ are not supported by the _android-cmake_ yet: + +* `armeabi-v7a-hard` ABI +* `libc++_static`/`libc++_shared` STL runtime + +## Basic options + +Similarly to the NDK build system _android-cmake_ allows to select between several compiler toolchains and target platforms. Most of the options can be set either as cmake arguments: `-D=` or as environment variables: + +* **ANDROID_NDK** - path to the Android NDK. If not set then _android-cmake_ will search for the most recent version of supported NDK in commonly used locations; +* **ANDROID_ABI** - specifies the target Application Binary Interface (ABI). This option nearly matches to the APP_ABI variable used by ndk-build tool from Android NDK. If not specified then set to `armeabi-v7a`. Possible target names are: + * `armeabi` - ARMv5TE based CPU with software floating point operations; + * **`armeabi-v7a`** - ARMv7 based devices with hardware FPU instructions (VFPv3_D16); + * `armeabi-v7a with NEON` - same as armeabi-v7a, but sets NEON as floating-point unit; + * `armeabi-v7a with VFPV3` - same as armeabi-v7a, but sets VFPv3_D32 as floating-point unit; + * `armeabi-v6 with VFP` - tuned for ARMv6 processors having VFP; + * `x86` - IA-32 instruction set + * `mips` - MIPS32 instruction set + * `arm64-v8a` - ARMv8 AArch64 instruction set - only for NDK r10 and newer + * `x86_64` - Intel64 instruction set (r1) - only for NDK r10 and newer + * `mips64` - MIPS64 instruction set (r6) - only for NDK r10 and newer +* **ANDROID_NATIVE_API_LEVEL** - level of android API to build for. Can be set either to full name (example: `android-8`) or a numeric value (example: `17`). The default API level depends on the target ABI: + * `android-8` for ARM; + * `android-9` for x86 and MIPS; + * `android-21` for 64-bit ABIs. + + Building for `android-L` is possible only when it is explicitly selected. +* **ANDROID_TOOLCHAIN_NAME** - the name of compiler toolchain to be used. This option allows to select between different GCC and Clang versions. The list of possible values depends on the NDK version and will be printed by toolchain file if an invalid value is set. By default _android-cmake_ selects the most recent version of GCC which can build for specified `ANDROID_ABI`. + + Example values are: + * `aarch64-linux-android-4.9` + * `aarch64-linux-android-clang3.5` + * `arm-linux-androideabi-4.8` + * `arm-linux-androideabi-4.9` + * `arm-linux-androideabi-clang3.5` + * `mips64el-linux-android-4.9` + * `mipsel-linux-android-4.8` + * `x86-4.9` + * `x86_64-4.9` + * etc. +* **ANDROID_STL** - the name of C++ runtime to use. The default is `gnustl_static`. + * `none` - do not configure the runtime. + * `system` - use the default minimal system C++ runtime library. + * Implies `-fno-rtti -fno-exceptions`. + * `system_re` - use the default minimal system C++ runtime library. + * Implies `-frtti -fexceptions`. + * `gabi++_static` - use the GAbi++ runtime as a static library. + * Implies `-frtti -fno-exceptions`. + * Available for NDK r7 and newer. + * `gabi++_shared` - use the GAbi++ runtime as a shared library. + * Implies `-frtti -fno-exceptions`. + * Available for NDK r7 and newer. + * `stlport_static` - use the STLport runtime as a static library. + * Implies `-fno-rtti -fno-exceptions` for NDK before r7. + * Implies `-frtti -fno-exceptions` for NDK r7 and newer. + * `stlport_shared` - use the STLport runtime as a shared library. + * Implies `-fno-rtti -fno-exceptions` for NDK before r7. + * Implies `-frtti -fno-exceptions` for NDK r7 and newer. + * **`gnustl_static`** - use the GNU STL as a static library. + * Implies `-frtti -fexceptions`. + * `gnustl_shared` - use the GNU STL as a shared library. + * Implies `-frtti -fno-exceptions`. + * Available for NDK r7b and newer. + * Silently degrades to `gnustl_static` if not available. +* **NDK_CCACHE** - path to `ccache` executable. If not set then initialized from `NDK_CCACHE` environment variable. + +## Advanced _android-cmake_ options + +Normally _android-cmake_ users are not supposed to touch these variables but they might be useful to workaround some build issues: + +* **ANDROID_FORCE_ARM_BUILD** = `OFF` - generate 32-bit ARM instructions instead of Thumb. Applicable only for arm ABIs and is forced to be `ON` for `armeabi-v6 with VFP`; +* **ANDROID_NO_UNDEFINED** = `ON` - show all undefined symbols as linker errors; +* **ANDROID_SO_UNDEFINED** = `OFF` - allow undefined symbols in shared libraries; + * actually it is turned `ON` by default for NDK older than `r7` +* **ANDROID_STL_FORCE_FEATURES** = `ON` - automatically configure rtti and exceptions support based on C++ runtime; +* **ANDROID_NDK_LAYOUT** = `RELEASE` - inner layout of Android NDK, should be detected automatically. Possible values are: + * `RELEASE` - public releases from Google; + * `LINARO` - NDK from Linaro project; + * `ANDROID` - NDK from AOSP. +* **ANDROID_FUNCTION_LEVEL_LINKING** = `ON` - enables saparate putting each function and data items into separate sections and enable garbage collection of unused input sections at link time (`-fdata-sections -ffunction-sections -Wl,--gc-sections`); +* **ANDROID_GOLD_LINKER** = `ON` - use gold linker with GCC 4.6 for NDK r8b and newer (only for ARM and x86); +* **ANDROID_NOEXECSTACK** = `ON` - enables or disables stack execution protection code (`-Wl,-z,noexecstack`); +* **ANDROID_RELRO** = `ON` - Enables RELRO - a memory corruption mitigation technique (`-Wl,-z,relro -Wl,-z,now`); +* **ANDROID_LIBM_PATH** - path to `libm.so` (set to something like `$(TOP)/out/target/product//obj/lib/libm.so`) to workaround unresolved `sincos`. + +## Fine-tuning `CMakeLists.txt` for _android-cmake_ + +### Recognizing Android build + +_android-cmake_ defines `ANDROID` CMake variable which can be used to add Android-specific stuff: + + if (ANDROID) + message(STATUS "Hello from Android build!") + endif() + +The recommended way to identify ARM/MIPS/x86 architecture is examining `CMAKE_SYSTEM_PROCESSOR` which is set to the appropriate value: + +* `armv5te` - for `armeabi` ABI +* `armv6` - for `armeabi-v6 with VFP` ABI +* `armv7-a` - for `armeabi-v7a`, `armeabi-v7a with VFPV3` and `armeabi-v7a with NEON` ABIs +* `aarch64` - for `arm64-v8a` ABI +* `i686` - for `x86` ABI +* `x86_64` - for `x86_64` ABI +* `mips` - for `mips` ABI +* `mips64` - for `mips64` ABI + +Other variables that are set by _android-cmake_ and can be used for the fine-grained build configuration are: + +* `NEON` - set if target ABI supports Neon; +* `ANDROID_NATIVE_API_LEVEL` - native Android API level we are building for (note: Java part of Andoid application can be built for another API level) +* `ANDROID_NDK_RELEASE` - version of the Android NDK +* `ANDROID_NDK_HOST_SYSTEM_NAME` - "windows", "linux-x86" or "darwin-x86" depending on the host platform +* `ANDROID_RTTI` - set if rtti is enabled by the runtime +* `ANDROID_EXCEPTIONS` - set if exceptions are enabled by the runtime + +### Finding packages + +When crosscompiling CMake `find_*` commands are normally expected to find libraries and packages belonging to the same build target. So _android-cmake_ configures CMake to search in Android-specific paths only and ignore your host system locations. So + + find_package(ZLIB) + +will surely find libz.so within the Android NDK. + +However sometimes you need to locate a host package even when cross-compiling. For example you can be searching for your documentation generator. The _android-cmake_ recommends you to use `find_host_package` and `find_host_program` macro defined in the `android.toolchain.cmake`: + + find_host_package(Doxygen) + find_host_program(PDFLATEX pdflatex) + +However this will break regular builds so instead of wrapping package search into platform-specific logic you can copy the following snippet into your project (put it after your top-level `project()` command): + + # Search packages for host system instead of packages for target system + # in case of cross compilation these macro should be defined by toolchain file + if(NOT COMMAND find_host_package) + macro(find_host_package) + find_package(${ARGN}) + endmacro() + endif() + if(NOT COMMAND find_host_program) + macro(find_host_program) + find_program(${ARGN}) + endmacro() + endif() + +### Compiler flags recycling + +Make sure to do the following in your scripts: + + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}") + +The flags will be prepopulated with critical flags, so don't loose them. Also be aware that _android-cmake_ also sets configuration-specific compiler and linker flags. + +## Troubleshooting + +### Building on Windows + +First of all `cygwin` builds are **NOT supported** and will not be supported by _android-cmake_. To build natively on Windows you need a port of make but I recommend http://martine.github.io/ninja/ instead. + +To build with Ninja you need: + +* Ensure you are using CMake newer than 2.8.9; +* Download the latest Ninja from https://github.com/martine/ninja/releases; +* Put the `ninja.exe` into your PATH (or add path to `ninja.exe` to your PATH environment variable); +* Pass `-GNinja` to `cmake` alongside with other arguments (or choose Ninja generator in `cmake-gui`). +* Enjoy the fast native multithreaded build :) + +But if you still want to stick to old make then: + +* Get a Windows port of GNU Make: + * Android NDK r7 (and newer) already has `make.exe` on board; + * `mingw-make` should work as fine; + * Download some other port. For example, this one: http://gnuwin32.sourceforge.net/packages/make.htm. +* Add path to your `make.exe` to system PATH or always use full path; +* Pass `-G"MinGW Makefiles"` and `-DCMAKE_MAKE_PROGRAM="make.exe"` + * It must be `MinGW Makefiles` and not `Unix Makefiles` even if your `make.exe` is not a MinGW's make. +* Run `make.exe` or `cmake --build .` for single-threaded build. + +### Projects with assembler files + +The _android-cmake_ should correctly handle projects with assembler sources (`*.s` or `*.S`). But if you still facing problems with assembler then try to upgrade your CMake to version newer than 2.8.5 + +## Copying + +_android-cmake_ is distributed under the terms of [BSD 3-Clause License](http://opensource.org/licenses/BSD-3-Clause) \ No newline at end of file diff --git a/TMessagesProj/jni/boringssl/util/android-cmake/android.toolchain.cmake b/TMessagesProj/jni/boringssl/util/android-cmake/android.toolchain.cmake new file mode 100644 index 00000000..ffa26126 --- /dev/null +++ b/TMessagesProj/jni/boringssl/util/android-cmake/android.toolchain.cmake @@ -0,0 +1,1693 @@ +# Copyright (c) 2010-2011, Ethan Rublee +# Copyright (c) 2011-2014, Andrey Kamaev +# 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. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from this +# software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS 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 COPYRIGHT HOLDER OR 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. + +# ------------------------------------------------------------------------------ +# Android CMake toolchain file, for use with the Android NDK r5-r10d +# Requires cmake 2.6.3 or newer (2.8.9 or newer is recommended). +# See home page: https://github.com/taka-no-me/android-cmake +# +# Usage Linux: +# $ export ANDROID_NDK=/absolute/path/to/the/android-ndk +# $ mkdir build && cd build +# $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake .. +# $ make -j8 +# +# Usage Windows: +# You need native port of make to build your project. +# Android NDK r7 (and newer) already has make.exe on board. +# For older NDK you have to install it separately. +# For example, this one: http://gnuwin32.sourceforge.net/packages/make.htm +# +# $ SET ANDROID_NDK=C:\absolute\path\to\the\android-ndk +# $ mkdir build && cd build +# $ cmake.exe -G"MinGW Makefiles" +# -DCMAKE_TOOLCHAIN_FILE=path\to\the\android.toolchain.cmake +# -DCMAKE_MAKE_PROGRAM="%ANDROID_NDK%\prebuilt\windows\bin\make.exe" .. +# $ cmake.exe --build . +# +# +# Options (can be set as cmake parameters: -D=): +# ANDROID_NDK=/opt/android-ndk - path to the NDK root. +# Can be set as environment variable. Can be set only at first cmake run. +# +# ANDROID_ABI=armeabi-v7a - specifies the target Application Binary +# Interface (ABI). This option nearly matches to the APP_ABI variable +# used by ndk-build tool from Android NDK. +# +# Possible targets are: +# "armeabi" - ARMv5TE based CPU with software floating point operations +# "armeabi-v7a" - ARMv7 based devices with hardware FPU instructions +# this ABI target is used by default +# "armeabi-v7a with NEON" - same as armeabi-v7a, but +# sets NEON as floating-point unit +# "armeabi-v7a with VFPV3" - same as armeabi-v7a, but +# sets VFPV3 as floating-point unit (has 32 registers instead of 16) +# "armeabi-v6 with VFP" - tuned for ARMv6 processors having VFP +# "x86" - IA-32 instruction set +# "mips" - MIPS32 instruction set +# +# 64-bit ABIs for NDK r10 and newer: +# "arm64-v8a" - ARMv8 AArch64 instruction set +# "x86_64" - Intel64 instruction set (r1) +# "mips64" - MIPS64 instruction set (r6) +# +# ANDROID_NATIVE_API_LEVEL=android-8 - level of Android API compile for. +# Option is read-only when standalone toolchain is used. +# Note: building for "android-L" requires explicit configuration. +# +# ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 - the name of compiler +# toolchain to be used. The list of possible values depends on the NDK +# version. For NDK r10c the possible values are: +# +# * aarch64-linux-android-4.9 +# * aarch64-linux-android-clang3.4 +# * aarch64-linux-android-clang3.5 +# * arm-linux-androideabi-4.6 +# * arm-linux-androideabi-4.8 +# * arm-linux-androideabi-4.9 (default) +# * arm-linux-androideabi-clang3.4 +# * arm-linux-androideabi-clang3.5 +# * mips64el-linux-android-4.9 +# * mips64el-linux-android-clang3.4 +# * mips64el-linux-android-clang3.5 +# * mipsel-linux-android-4.6 +# * mipsel-linux-android-4.8 +# * mipsel-linux-android-4.9 +# * mipsel-linux-android-clang3.4 +# * mipsel-linux-android-clang3.5 +# * x86-4.6 +# * x86-4.8 +# * x86-4.9 +# * x86-clang3.4 +# * x86-clang3.5 +# * x86_64-4.9 +# * x86_64-clang3.4 +# * x86_64-clang3.5 +# +# ANDROID_FORCE_ARM_BUILD=OFF - set ON to generate 32-bit ARM instructions +# instead of Thumb. Is not available for "armeabi-v6 with VFP" +# (is forced to be ON) ABI. +# +# ANDROID_NO_UNDEFINED=ON - set ON to show all undefined symbols as linker +# errors even if they are not used. +# +# ANDROID_SO_UNDEFINED=OFF - set ON to allow undefined symbols in shared +# libraries. Automatically turned for NDK r5x and r6x due to GLESv2 +# problems. +# +# ANDROID_STL=gnustl_static - specify the runtime to use. +# +# Possible values are: +# none -> Do not configure the runtime. +# system -> Use the default minimal system C++ runtime library. +# Implies -fno-rtti -fno-exceptions. +# Is not available for standalone toolchain. +# system_re -> Use the default minimal system C++ runtime library. +# Implies -frtti -fexceptions. +# Is not available for standalone toolchain. +# gabi++_static -> Use the GAbi++ runtime as a static library. +# Implies -frtti -fno-exceptions. +# Available for NDK r7 and newer. +# Is not available for standalone toolchain. +# gabi++_shared -> Use the GAbi++ runtime as a shared library. +# Implies -frtti -fno-exceptions. +# Available for NDK r7 and newer. +# Is not available for standalone toolchain. +# stlport_static -> Use the STLport runtime as a static library. +# Implies -fno-rtti -fno-exceptions for NDK before r7. +# Implies -frtti -fno-exceptions for NDK r7 and newer. +# Is not available for standalone toolchain. +# stlport_shared -> Use the STLport runtime as a shared library. +# Implies -fno-rtti -fno-exceptions for NDK before r7. +# Implies -frtti -fno-exceptions for NDK r7 and newer. +# Is not available for standalone toolchain. +# gnustl_static -> Use the GNU STL as a static library. +# Implies -frtti -fexceptions. +# gnustl_shared -> Use the GNU STL as a shared library. +# Implies -frtti -fno-exceptions. +# Available for NDK r7b and newer. +# Silently degrades to gnustl_static if not available. +# +# ANDROID_STL_FORCE_FEATURES=ON - turn rtti and exceptions support based on +# chosen runtime. If disabled, then the user is responsible for settings +# these options. +# +# What?: +# android-cmake toolchain searches for NDK/toolchain in the following order: +# ANDROID_NDK - cmake parameter +# ANDROID_NDK - environment variable +# ANDROID_STANDALONE_TOOLCHAIN - cmake parameter +# ANDROID_STANDALONE_TOOLCHAIN - environment variable +# ANDROID_NDK - default locations +# ANDROID_STANDALONE_TOOLCHAIN - default locations +# +# Make sure to do the following in your scripts: +# SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}" ) +# SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}" ) +# The flags will be prepopulated with critical flags, so don't loose them. +# Also be aware that toolchain also sets configuration-specific compiler +# flags and linker flags. +# +# ANDROID and BUILD_ANDROID will be set to true, you may test any of these +# variables to make necessary Android-specific configuration changes. +# +# Also ARMEABI or ARMEABI_V7A or X86 or MIPS or ARM64_V8A or X86_64 or MIPS64 +# will be set true, mutually exclusive. NEON option will be set true +# if VFP is set to NEON. +# +# ------------------------------------------------------------------------------ + +cmake_minimum_required( VERSION 2.6.3 ) + +if( DEFINED CMAKE_CROSSCOMPILING ) + # subsequent toolchain loading is not really needed + return() +endif() + +if( CMAKE_TOOLCHAIN_FILE ) + # touch toolchain variable to suppress "unused variable" warning +endif() + +# inherit settings in recursive loads +get_property( _CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE ) +if( _CMAKE_IN_TRY_COMPILE ) + include( "${CMAKE_CURRENT_SOURCE_DIR}/../android.toolchain.config.cmake" OPTIONAL ) +endif() + +# this one is important +if( CMAKE_VERSION VERSION_GREATER "3.0.99" ) + set( CMAKE_SYSTEM_NAME Android ) +else() + set( CMAKE_SYSTEM_NAME Linux ) +endif() + +# this one not so much +set( CMAKE_SYSTEM_VERSION 1 ) + +# rpath makes low sense for Android +set( CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "" ) +set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." ) + +# NDK search paths +set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10d -r10c -r10b -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) +if( NOT DEFINED ANDROID_NDK_SEARCH_PATHS ) + if( CMAKE_HOST_WIN32 ) + file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS ) + set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}" "$ENV{SystemDrive}/NVPACK" ) + else() + file( TO_CMAKE_PATH "$ENV{HOME}" ANDROID_NDK_SEARCH_PATHS ) + set( ANDROID_NDK_SEARCH_PATHS /opt "${ANDROID_NDK_SEARCH_PATHS}/NVPACK" ) + endif() +endif() +if( NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH ) + set( ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH /opt/android-toolchain ) +endif() + +# known ABIs +set( ANDROID_SUPPORTED_ABIS_arm "armeabi-v7a;armeabi;armeabi-v7a with NEON;armeabi-v7a with VFPV3;armeabi-v6 with VFP" ) +set( ANDROID_SUPPORTED_ABIS_arm64 "arm64-v8a" ) +set( ANDROID_SUPPORTED_ABIS_x86 "x86" ) +set( ANDROID_SUPPORTED_ABIS_x86_64 "x86_64" ) +set( ANDROID_SUPPORTED_ABIS_mips "mips" ) +set( ANDROID_SUPPORTED_ABIS_mips64 "mips64" ) + +# API level defaults +set( ANDROID_DEFAULT_NDK_API_LEVEL 8 ) +set( ANDROID_DEFAULT_NDK_API_LEVEL_arm64 21 ) +set( ANDROID_DEFAULT_NDK_API_LEVEL_x86 9 ) +set( ANDROID_DEFAULT_NDK_API_LEVEL_x86_64 21 ) +set( ANDROID_DEFAULT_NDK_API_LEVEL_mips 9 ) +set( ANDROID_DEFAULT_NDK_API_LEVEL_mips64 21 ) + + +macro( __LIST_FILTER listvar regex ) + if( ${listvar} ) + foreach( __val ${${listvar}} ) + if( __val MATCHES "${regex}" ) + list( REMOVE_ITEM ${listvar} "${__val}" ) + endif() + endforeach() + endif() +endmacro() + +macro( __INIT_VARIABLE var_name ) + set( __test_path 0 ) + foreach( __var ${ARGN} ) + if( __var STREQUAL "PATH" ) + set( __test_path 1 ) + break() + endif() + endforeach() + + if( __test_path AND NOT EXISTS "${${var_name}}" ) + unset( ${var_name} CACHE ) + endif() + + if( " ${${var_name}}" STREQUAL " " ) + set( __values 0 ) + foreach( __var ${ARGN} ) + if( __var STREQUAL "VALUES" ) + set( __values 1 ) + elseif( NOT __var STREQUAL "PATH" ) + if( __var MATCHES "^ENV_.*$" ) + string( REPLACE "ENV_" "" __var "${__var}" ) + set( __value "$ENV{${__var}}" ) + elseif( DEFINED ${__var} ) + set( __value "${${__var}}" ) + elseif( __values ) + set( __value "${__var}" ) + else() + set( __value "" ) + endif() + + if( NOT " ${__value}" STREQUAL " " AND (NOT __test_path OR EXISTS "${__value}") ) + set( ${var_name} "${__value}" ) + break() + endif() + endif() + endforeach() + unset( __value ) + unset( __values ) + endif() + + if( __test_path ) + file( TO_CMAKE_PATH "${${var_name}}" ${var_name} ) + endif() + unset( __test_path ) +endmacro() + +macro( __DETECT_NATIVE_API_LEVEL _var _path ) + set( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*.*$" ) + file( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" ) + if( NOT __apiFileContent ) + message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." ) + endif() + string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" ) + unset( __apiFileContent ) + unset( __ndkApiLevelRegex ) +endmacro() + +macro( __DETECT_TOOLCHAIN_MACHINE_NAME _var _root ) + if( EXISTS "${_root}" ) + file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" ) + __LIST_FILTER( __gccExePath "^[.].*" ) + list( LENGTH __gccExePath __gccExePathsCount ) + if( NOT __gccExePathsCount EQUAL 1 AND NOT _CMAKE_IN_TRY_COMPILE ) + message( WARNING "Could not determine machine name for compiler from ${_root}" ) + set( ${_var} "" ) + else() + get_filename_component( __gccExeName "${__gccExePath}" NAME_WE ) + string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" ) + endif() + unset( __gccExePath ) + unset( __gccExePathsCount ) + unset( __gccExeName ) + else() + set( ${_var} "" ) + endif() +endmacro() + + +# fight against cygwin +set( ANDROID_FORBID_SYGWIN TRUE CACHE BOOL "Prevent cmake from working under cygwin and using cygwin tools") +mark_as_advanced( ANDROID_FORBID_SYGWIN ) +if( ANDROID_FORBID_SYGWIN ) + if( CYGWIN ) + message( FATAL_ERROR "Android NDK and android-cmake toolchain are not welcome Cygwin. It is unlikely that this cmake toolchain will work under cygwin. But if you want to try then you can set cmake variable ANDROID_FORBID_SYGWIN to FALSE and rerun cmake." ) + endif() + + if( CMAKE_HOST_WIN32 ) + # remove cygwin from PATH + set( __new_path "$ENV{PATH}") + __LIST_FILTER( __new_path "cygwin" ) + set(ENV{PATH} "${__new_path}") + unset(__new_path) + endif() +endif() + + +# detect current host platform +if( NOT DEFINED ANDROID_NDK_HOST_X64 AND (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64" OR CMAKE_HOST_APPLE) ) + set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" ) + mark_as_advanced( ANDROID_NDK_HOST_X64 ) +endif() + +set( TOOL_OS_SUFFIX "" ) +if( CMAKE_HOST_APPLE ) + set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86_64" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME2 "darwin-x86" ) +elseif( CMAKE_HOST_WIN32 ) + set( ANDROID_NDK_HOST_SYSTEM_NAME "windows-x86_64" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME2 "windows" ) + set( TOOL_OS_SUFFIX ".exe" ) +elseif( CMAKE_HOST_UNIX ) + set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86_64" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME2 "linux-x86" ) +else() + message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" ) +endif() + +if( NOT ANDROID_NDK_HOST_X64 ) + set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) +endif() + +# see if we have path to Android NDK +if( NOT ANDROID_NDK AND NOT ANDROID_STANDALONE_TOOLCHAIN ) + __INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK ) +endif() +if( NOT ANDROID_NDK ) + # see if we have path to Android standalone toolchain + __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN ) + + if( NOT ANDROID_STANDALONE_TOOLCHAIN ) + #try to find Android NDK in one of the the default locations + set( __ndkSearchPaths ) + foreach( __ndkSearchPath ${ANDROID_NDK_SEARCH_PATHS} ) + foreach( suffix ${ANDROID_SUPPORTED_NDK_VERSIONS} ) + list( APPEND __ndkSearchPaths "${__ndkSearchPath}/android-ndk${suffix}" ) + endforeach() + endforeach() + __INIT_VARIABLE( ANDROID_NDK PATH VALUES ${__ndkSearchPaths} ) + unset( __ndkSearchPaths ) + + if( ANDROID_NDK ) + message( STATUS "Using default path for Android NDK: ${ANDROID_NDK}" ) + message( STATUS " If you prefer to use a different location, please define a cmake or environment variable: ANDROID_NDK" ) + else() + #try to find Android standalone toolchain in one of the the default locations + __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH ) + + if( ANDROID_STANDALONE_TOOLCHAIN ) + message( STATUS "Using default path for standalone toolchain ${ANDROID_STANDALONE_TOOLCHAIN}" ) + message( STATUS " If you prefer to use a different location, please define the variable: ANDROID_STANDALONE_TOOLCHAIN" ) + endif( ANDROID_STANDALONE_TOOLCHAIN ) + endif( ANDROID_NDK ) + endif( NOT ANDROID_STANDALONE_TOOLCHAIN ) +endif( NOT ANDROID_NDK ) + +# remember found paths +if( ANDROID_NDK ) + get_filename_component( ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE ) + set( ANDROID_NDK "${ANDROID_NDK}" CACHE INTERNAL "Path of the Android NDK" FORCE ) + set( BUILD_WITH_ANDROID_NDK True ) + if( EXISTS "${ANDROID_NDK}/RELEASE.TXT" ) + file( STRINGS "${ANDROID_NDK}/RELEASE.TXT" ANDROID_NDK_RELEASE_FULL LIMIT_COUNT 1 REGEX "r[0-9]+[a-z]?" ) + string( REGEX MATCH "r([0-9]+)([a-z]?)" ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_FULL}" ) + else() + set( ANDROID_NDK_RELEASE "r1x" ) + set( ANDROID_NDK_RELEASE_FULL "unreleased" ) + endif() + string( REGEX REPLACE "r([0-9]+)([a-z]?)" "\\1*1000" ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE}" ) + string( FIND " abcdefghijklmnopqastuvwxyz" "${CMAKE_MATCH_2}" __ndkReleaseLetterNum ) + math( EXPR ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE_NUM}+${__ndkReleaseLetterNum}" ) +elseif( ANDROID_STANDALONE_TOOLCHAIN ) + get_filename_component( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" ABSOLUTE ) + # try to detect change + if( CMAKE_AR ) + string( LENGTH "${ANDROID_STANDALONE_TOOLCHAIN}" __length ) + string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidStandaloneToolchainPreviousPath ) + if( NOT __androidStandaloneToolchainPreviousPath STREQUAL ANDROID_STANDALONE_TOOLCHAIN ) + message( FATAL_ERROR "It is not possible to change path to the Android standalone toolchain on subsequent run." ) + endif() + unset( __androidStandaloneToolchainPreviousPath ) + unset( __length ) + endif() + set( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" CACHE INTERNAL "Path of the Android standalone toolchain" FORCE ) + set( BUILD_WITH_STANDALONE_TOOLCHAIN True ) +else() + list(GET ANDROID_NDK_SEARCH_PATHS 0 ANDROID_NDK_SEARCH_PATH) + message( FATAL_ERROR "Could not find neither Android NDK nor Android standalone toolchain. + You should either set an environment variable: + export ANDROID_NDK=~/my-android-ndk + or + export ANDROID_STANDALONE_TOOLCHAIN=~/my-android-toolchain + or put the toolchain or NDK in the default path: + sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH}/android-ndk + sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" ) +endif() + +# android NDK layout +if( BUILD_WITH_ANDROID_NDK ) + if( NOT DEFINED ANDROID_NDK_LAYOUT ) + # try to automatically detect the layout + if( EXISTS "${ANDROID_NDK}/RELEASE.TXT") + set( ANDROID_NDK_LAYOUT "RELEASE" ) + elseif( EXISTS "${ANDROID_NDK}/../../linux-x86/toolchain/" ) + set( ANDROID_NDK_LAYOUT "LINARO" ) + elseif( EXISTS "${ANDROID_NDK}/../../gcc/" ) + set( ANDROID_NDK_LAYOUT "ANDROID" ) + endif() + endif() + set( ANDROID_NDK_LAYOUT "${ANDROID_NDK_LAYOUT}" CACHE STRING "The inner layout of NDK" ) + mark_as_advanced( ANDROID_NDK_LAYOUT ) + if( ANDROID_NDK_LAYOUT STREQUAL "LINARO" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment + set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../${ANDROID_NDK_HOST_SYSTEM_NAME}/toolchain" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) + elseif( ANDROID_NDK_LAYOUT STREQUAL "ANDROID" ) + set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment + set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../gcc/${ANDROID_NDK_HOST_SYSTEM_NAME}/arm" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) + else() # ANDROID_NDK_LAYOUT STREQUAL "RELEASE" + set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/toolchains" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME2}" ) + endif() + get_filename_component( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK_TOOLCHAINS_PATH}" ABSOLUTE ) + + # try to detect change of NDK + if( CMAKE_AR ) + string( LENGTH "${ANDROID_NDK_TOOLCHAINS_PATH}" __length ) + string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath ) + if( NOT __androidNdkPreviousPath STREQUAL ANDROID_NDK_TOOLCHAINS_PATH ) + message( FATAL_ERROR "It is not possible to change the path to the NDK on subsequent CMake run. You must remove all generated files from your build folder first. + " ) + endif() + unset( __androidNdkPreviousPath ) + unset( __length ) + endif() +endif() + + +# get all the details about standalone toolchain +if( BUILD_WITH_STANDALONE_TOOLCHAIN ) + __DETECT_NATIVE_API_LEVEL( ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h" ) + set( ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) + set( __availableToolchains "standalone" ) + __DETECT_TOOLCHAIN_MACHINE_NAME( __availableToolchainMachines "${ANDROID_STANDALONE_TOOLCHAIN}" ) + if( NOT __availableToolchainMachines ) + message( FATAL_ERROR "Could not determine machine name of your toolchain. Probably your Android standalone toolchain is broken." ) + endif() + if( __availableToolchainMachines MATCHES x86_64 ) + set( __availableToolchainArchs "x86_64" ) + elseif( __availableToolchainMachines MATCHES i686 ) + set( __availableToolchainArchs "x86" ) + elseif( __availableToolchainMachines MATCHES aarch64 ) + set( __availableToolchainArchs "arm64" ) + elseif( __availableToolchainMachines MATCHES arm ) + set( __availableToolchainArchs "arm" ) + elseif( __availableToolchainMachines MATCHES mips64el ) + set( __availableToolchainArchs "mips64" ) + elseif( __availableToolchainMachines MATCHES mipsel ) + set( __availableToolchainArchs "mips" ) + endif() + execute_process( COMMAND "${ANDROID_STANDALONE_TOOLCHAIN}/bin/${__availableToolchainMachines}-gcc${TOOL_OS_SUFFIX}" -dumpversion + OUTPUT_VARIABLE __availableToolchainCompilerVersions OUTPUT_STRIP_TRAILING_WHITESPACE ) + string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9]+)?" __availableToolchainCompilerVersions "${__availableToolchainCompilerVersions}" ) + if( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/bin/clang${TOOL_OS_SUFFIX}" ) + list( APPEND __availableToolchains "standalone-clang" ) + list( APPEND __availableToolchainMachines ${__availableToolchainMachines} ) + list( APPEND __availableToolchainArchs ${__availableToolchainArchs} ) + list( APPEND __availableToolchainCompilerVersions ${__availableToolchainCompilerVersions} ) + endif() +endif() + +macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst __toolchain_subpath ) + foreach( __toolchain ${${__availableToolchainsLst}} ) + if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" ) + SET( __toolchainVersionRegex "^TOOLCHAIN_VERSION[\t ]+:=[\t ]+(.*)$" ) + FILE( STRINGS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}/setup.mk" __toolchainVersionStr REGEX "${__toolchainVersionRegex}" ) + if( __toolchainVersionStr ) + string( REGEX REPLACE "${__toolchainVersionRegex}" "\\1" __toolchainVersionStr "${__toolchainVersionStr}" ) + string( REGEX REPLACE "-clang3[.][0-9]$" "-${__toolchainVersionStr}" __gcc_toolchain "${__toolchain}" ) + else() + string( REGEX REPLACE "-clang3[.][0-9]$" "-4.6" __gcc_toolchain "${__toolchain}" ) + endif() + unset( __toolchainVersionStr ) + unset( __toolchainVersionRegex ) + else() + set( __gcc_toolchain "${__toolchain}" ) + endif() + __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK_TOOLCHAINS_PATH}/${__gcc_toolchain}${__toolchain_subpath}" ) + if( __machine ) + string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9x]+)?$" __version "${__gcc_toolchain}" ) + if( __machine MATCHES x86_64 ) + set( __arch "x86_64" ) + elseif( __machine MATCHES i686 ) + set( __arch "x86" ) + elseif( __machine MATCHES aarch64 ) + set( __arch "arm64" ) + elseif( __machine MATCHES arm ) + set( __arch "arm" ) + elseif( __machine MATCHES mips64el ) + set( __arch "mips64" ) + elseif( __machine MATCHES mipsel ) + set( __arch "mips" ) + else() + set( __arch "" ) + endif() + #message("machine: !${__machine}!\narch: !${__arch}!\nversion: !${__version}!\ntoolchain: !${__toolchain}!\n") + if (__arch) + list( APPEND __availableToolchainMachines "${__machine}" ) + list( APPEND __availableToolchainArchs "${__arch}" ) + list( APPEND __availableToolchainCompilerVersions "${__version}" ) + list( APPEND ${__availableToolchainsVar} "${__toolchain}" ) + endif() + endif() + unset( __gcc_toolchain ) + endforeach() +endmacro() + +# get all the details about NDK +if( BUILD_WITH_ANDROID_NDK ) + file( GLOB ANDROID_SUPPORTED_NATIVE_API_LEVELS RELATIVE "${ANDROID_NDK}/platforms" "${ANDROID_NDK}/platforms/android-*" ) + string( REPLACE "android-" "" ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_SUPPORTED_NATIVE_API_LEVELS}" ) + set( __availableToolchains "" ) + set( __availableToolchainMachines "" ) + set( __availableToolchainArchs "" ) + set( __availableToolchainCompilerVersions "" ) + if( ANDROID_TOOLCHAIN_NAME AND EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_TOOLCHAIN_NAME}/" ) + # do not go through all toolchains if we know the name + set( __availableToolchainsLst "${ANDROID_TOOLCHAIN_NAME}" ) + __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) + if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) + __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) + if( __availableToolchains ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) + endif() + endif() + endif() + if( NOT __availableToolchains ) + file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" ) + if( __availableToolchainsLst ) + list(SORT __availableToolchainsLst) # we need clang to go after gcc + endif() + __LIST_FILTER( __availableToolchainsLst "^[.]" ) + __LIST_FILTER( __availableToolchainsLst "llvm" ) + __LIST_FILTER( __availableToolchainsLst "renderscript" ) + __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) + if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) + __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) + if( __availableToolchains ) + set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) + endif() + endif() + endif() + if( NOT __availableToolchains ) + message( FATAL_ERROR "Could not find any working toolchain in the NDK. Probably your Android NDK is broken." ) + endif() +endif() + +# build list of available ABIs +set( ANDROID_SUPPORTED_ABIS "" ) +set( __uniqToolchainArchNames ${__availableToolchainArchs} ) +list( REMOVE_DUPLICATES __uniqToolchainArchNames ) +list( SORT __uniqToolchainArchNames ) +foreach( __arch ${__uniqToolchainArchNames} ) + list( APPEND ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${__arch}} ) +endforeach() +unset( __uniqToolchainArchNames ) +if( NOT ANDROID_SUPPORTED_ABIS ) + message( FATAL_ERROR "No one of known Android ABIs is supported by this cmake toolchain." ) +endif() + +# choose target ABI +__INIT_VARIABLE( ANDROID_ABI VALUES ${ANDROID_SUPPORTED_ABIS} ) +# verify that target ABI is supported +list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx ) +if( __androidAbiIdx EQUAL -1 ) + string( REPLACE ";" "\", \"" PRINTABLE_ANDROID_SUPPORTED_ABIS "${ANDROID_SUPPORTED_ABIS}" ) + message( FATAL_ERROR "Specified ANDROID_ABI = \"${ANDROID_ABI}\" is not supported by this cmake toolchain or your NDK/toolchain. + Supported values are: \"${PRINTABLE_ANDROID_SUPPORTED_ABIS}\" + " ) +endif() +unset( __androidAbiIdx ) + +# set target ABI options +if( ANDROID_ABI STREQUAL "x86" ) + set( X86 true ) + set( ANDROID_NDK_ABI_NAME "x86" ) + set( ANDROID_ARCH_NAME "x86" ) + set( ANDROID_LLVM_TRIPLE "i686-none-linux-android" ) + set( CMAKE_SYSTEM_PROCESSOR "i686" ) +elseif( ANDROID_ABI STREQUAL "x86_64" ) + set( X86 true ) + set( X86_64 true ) + set( ANDROID_NDK_ABI_NAME "x86_64" ) + set( ANDROID_ARCH_NAME "x86_64" ) + set( CMAKE_SYSTEM_PROCESSOR "x86_64" ) + set( ANDROID_LLVM_TRIPLE "x86_64-none-linux-android" ) +elseif( ANDROID_ABI STREQUAL "mips64" ) + set( MIPS64 true ) + set( ANDROID_NDK_ABI_NAME "mips64" ) + set( ANDROID_ARCH_NAME "mips64" ) + set( ANDROID_LLVM_TRIPLE "mips64el-none-linux-android" ) + set( CMAKE_SYSTEM_PROCESSOR "mips64" ) +elseif( ANDROID_ABI STREQUAL "mips" ) + set( MIPS true ) + set( ANDROID_NDK_ABI_NAME "mips" ) + set( ANDROID_ARCH_NAME "mips" ) + set( ANDROID_LLVM_TRIPLE "mipsel-none-linux-android" ) + set( CMAKE_SYSTEM_PROCESSOR "mips" ) +elseif( ANDROID_ABI STREQUAL "arm64-v8a" ) + set( ARM64_V8A true ) + set( ANDROID_NDK_ABI_NAME "arm64-v8a" ) + set( ANDROID_ARCH_NAME "arm64" ) + set( ANDROID_LLVM_TRIPLE "aarch64-none-linux-android" ) + set( CMAKE_SYSTEM_PROCESSOR "aarch64" ) + set( VFPV3 true ) + set( NEON true ) +elseif( ANDROID_ABI STREQUAL "armeabi" ) + set( ARMEABI true ) + set( ANDROID_NDK_ABI_NAME "armeabi" ) + set( ANDROID_ARCH_NAME "arm" ) + set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" ) + set( CMAKE_SYSTEM_PROCESSOR "armv5te" ) +elseif( ANDROID_ABI STREQUAL "armeabi-v6 with VFP" ) + set( ARMEABI_V6 true ) + set( ANDROID_NDK_ABI_NAME "armeabi" ) + set( ANDROID_ARCH_NAME "arm" ) + set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" ) + set( CMAKE_SYSTEM_PROCESSOR "armv6" ) + # need always fallback to older platform + set( ARMEABI true ) +elseif( ANDROID_ABI STREQUAL "armeabi-v7a") + set( ARMEABI_V7A true ) + set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) + set( ANDROID_ARCH_NAME "arm" ) + set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) + set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) +elseif( ANDROID_ABI STREQUAL "armeabi-v7a with VFPV3" ) + set( ARMEABI_V7A true ) + set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) + set( ANDROID_ARCH_NAME "arm" ) + set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) + set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) + set( VFPV3 true ) +elseif( ANDROID_ABI STREQUAL "armeabi-v7a with NEON" ) + set( ARMEABI_V7A true ) + set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) + set( ANDROID_ARCH_NAME "arm" ) + set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) + set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) + set( VFPV3 true ) + set( NEON true ) +else() + message( SEND_ERROR "Unknown ANDROID_ABI=\"${ANDROID_ABI}\" is specified." ) +endif() + +if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" ) + # really dirty hack + # it is not possible to change CMAKE_SYSTEM_PROCESSOR after the first run... + file( APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" "SET(CMAKE_SYSTEM_PROCESSOR \"${CMAKE_SYSTEM_PROCESSOR}\")\n" ) +endif() + +if( ANDROID_ARCH_NAME STREQUAL "arm" AND NOT ARMEABI_V6 ) + __INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD VALUES OFF ) + set( ANDROID_FORCE_ARM_BUILD ${ANDROID_FORCE_ARM_BUILD} CACHE BOOL "Use 32-bit ARM instructions instead of Thumb-1" FORCE ) + mark_as_advanced( ANDROID_FORCE_ARM_BUILD ) +else() + unset( ANDROID_FORCE_ARM_BUILD CACHE ) +endif() + +# choose toolchain +if( ANDROID_TOOLCHAIN_NAME ) + list( FIND __availableToolchains "${ANDROID_TOOLCHAIN_NAME}" __toolchainIdx ) + if( __toolchainIdx EQUAL -1 ) + list( SORT __availableToolchains ) + string( REPLACE ";" "\n * " toolchains_list "${__availableToolchains}" ) + set( toolchains_list " * ${toolchains_list}") + message( FATAL_ERROR "Specified toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is missing in your NDK or broken. Please verify that your NDK is working or select another compiler toolchain. +To configure the toolchain set CMake variable ANDROID_TOOLCHAIN_NAME to one of the following values:\n${toolchains_list}\n" ) + endif() + list( GET __availableToolchainArchs ${__toolchainIdx} __toolchainArch ) + if( NOT __toolchainArch STREQUAL ANDROID_ARCH_NAME ) + message( SEND_ERROR "Selected toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is not able to compile binaries for the \"${ANDROID_ARCH_NAME}\" platform." ) + endif() +else() + set( __toolchainIdx -1 ) + set( __applicableToolchains "" ) + set( __toolchainMaxVersion "0.0.0" ) + list( LENGTH __availableToolchains __availableToolchainsCount ) + math( EXPR __availableToolchainsCount "${__availableToolchainsCount}-1" ) + foreach( __idx RANGE ${__availableToolchainsCount} ) + list( GET __availableToolchainArchs ${__idx} __toolchainArch ) + if( __toolchainArch STREQUAL ANDROID_ARCH_NAME ) + list( GET __availableToolchainCompilerVersions ${__idx} __toolchainVersion ) + string( REPLACE "x" "99" __toolchainVersion "${__toolchainVersion}") + if( __toolchainVersion VERSION_GREATER __toolchainMaxVersion ) + set( __toolchainMaxVersion "${__toolchainVersion}" ) + set( __toolchainIdx ${__idx} ) + endif() + endif() + endforeach() + unset( __availableToolchainsCount ) + unset( __toolchainMaxVersion ) + unset( __toolchainVersion ) +endif() +unset( __toolchainArch ) +if( __toolchainIdx EQUAL -1 ) + message( FATAL_ERROR "No one of available compiler toolchains is able to compile for ${ANDROID_ARCH_NAME} platform." ) +endif() +list( GET __availableToolchains ${__toolchainIdx} ANDROID_TOOLCHAIN_NAME ) +list( GET __availableToolchainMachines ${__toolchainIdx} ANDROID_TOOLCHAIN_MACHINE_NAME ) +list( GET __availableToolchainCompilerVersions ${__toolchainIdx} ANDROID_COMPILER_VERSION ) + +unset( __toolchainIdx ) +unset( __availableToolchains ) +unset( __availableToolchainMachines ) +unset( __availableToolchainArchs ) +unset( __availableToolchainCompilerVersions ) + +# choose native API level +__INIT_VARIABLE( ANDROID_NATIVE_API_LEVEL ENV_ANDROID_NATIVE_API_LEVEL ANDROID_API_LEVEL ENV_ANDROID_API_LEVEL ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME} ANDROID_DEFAULT_NDK_API_LEVEL ) +string( REPLACE "android-" "" ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" ) +string( STRIP "${ANDROID_NATIVE_API_LEVEL}" ANDROID_NATIVE_API_LEVEL ) +# adjust API level +set( __real_api_level ${ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME}} ) +foreach( __level ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) + if( (__level LESS ANDROID_NATIVE_API_LEVEL OR __level STREQUAL ANDROID_NATIVE_API_LEVEL) AND NOT __level LESS __real_api_level ) + set( __real_api_level ${__level} ) + endif() +endforeach() +if( __real_api_level AND NOT ANDROID_NATIVE_API_LEVEL STREQUAL __real_api_level ) + message( STATUS "Adjusting Android API level 'android-${ANDROID_NATIVE_API_LEVEL}' to 'android-${__real_api_level}'") + set( ANDROID_NATIVE_API_LEVEL ${__real_api_level} ) +endif() +unset(__real_api_level) +# validate +list( FIND ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_NATIVE_API_LEVEL}" __levelIdx ) +if( __levelIdx EQUAL -1 ) + message( SEND_ERROR "Specified Android native API level 'android-${ANDROID_NATIVE_API_LEVEL}' is not supported by your NDK/toolchain." ) +else() + if( BUILD_WITH_ANDROID_NDK ) + __DETECT_NATIVE_API_LEVEL( __realApiLevel "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}/usr/include/android/api-level.h" ) + if( NOT __realApiLevel EQUAL ANDROID_NATIVE_API_LEVEL AND NOT __realApiLevel GREATER 9000 ) + message( SEND_ERROR "Specified Android API level (${ANDROID_NATIVE_API_LEVEL}) does not match to the level found (${__realApiLevel}). Probably your copy of NDK is broken." ) + endif() + unset( __realApiLevel ) + endif() + set( ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android API level for native code" FORCE ) + set( CMAKE_ANDROID_API ${ANDROID_NATIVE_API_LEVEL} ) + if( CMAKE_VERSION VERSION_GREATER "2.8" ) + list( SORT ANDROID_SUPPORTED_NATIVE_API_LEVELS ) + set_property( CACHE ANDROID_NATIVE_API_LEVEL PROPERTY STRINGS ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) + endif() +endif() +unset( __levelIdx ) + + +# remember target ABI +set( ANDROID_ABI "${ANDROID_ABI}" CACHE STRING "The target ABI for Android. If arm, then armeabi-v7a is recommended for hardware floating point." FORCE ) +if( CMAKE_VERSION VERSION_GREATER "2.8" ) + list( SORT ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME} ) + set_property( CACHE ANDROID_ABI PROPERTY STRINGS ${ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME}} ) +endif() + + +# runtime choice (STL, rtti, exceptions) +if( NOT ANDROID_STL ) + set( ANDROID_STL gnustl_static ) +endif() +set( ANDROID_STL "${ANDROID_STL}" CACHE STRING "C++ runtime" ) +set( ANDROID_STL_FORCE_FEATURES ON CACHE BOOL "automatically configure rtti and exceptions support based on C++ runtime" ) +mark_as_advanced( ANDROID_STL ANDROID_STL_FORCE_FEATURES ) + +if( BUILD_WITH_ANDROID_NDK ) + if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared)$") + message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\". +The possible values are: + none -> Do not configure the runtime. + system -> Use the default minimal system C++ runtime library. + system_re -> Same as system but with rtti and exceptions. + gabi++_static -> Use the GAbi++ runtime as a static library. + gabi++_shared -> Use the GAbi++ runtime as a shared library. + stlport_static -> Use the STLport runtime as a static library. + stlport_shared -> Use the STLport runtime as a shared library. + gnustl_static -> (default) Use the GNU STL as a static library. + gnustl_shared -> Use the GNU STL as a shared library. +" ) + endif() +elseif( BUILD_WITH_STANDALONE_TOOLCHAIN ) + if( NOT "${ANDROID_STL}" MATCHES "^(none|gnustl_static|gnustl_shared)$") + message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\". +The possible values are: + none -> Do not configure the runtime. + gnustl_static -> (default) Use the GNU STL as a static library. + gnustl_shared -> Use the GNU STL as a shared library. +" ) + endif() +endif() + +unset( ANDROID_RTTI ) +unset( ANDROID_EXCEPTIONS ) +unset( ANDROID_STL_INCLUDE_DIRS ) +unset( __libstl ) +unset( __libsupcxx ) + +if( NOT _CMAKE_IN_TRY_COMPILE AND ANDROID_NDK_RELEASE STREQUAL "r7b" AND ARMEABI_V7A AND NOT VFPV3 AND ANDROID_STL MATCHES "gnustl" ) + message( WARNING "The GNU STL armeabi-v7a binaries from NDK r7b can crash non-NEON devices. The files provided with NDK r7b were not configured properly, resulting in crashes on Tegra2-based devices and others when trying to use certain floating-point functions (e.g., cosf, sinf, expf). +You are strongly recommended to switch to another NDK release. +" ) +endif() + +if( NOT _CMAKE_IN_TRY_COMPILE AND X86 AND ANDROID_STL MATCHES "gnustl" AND ANDROID_NDK_RELEASE STREQUAL "r6" ) + message( WARNING "The x86 system header file from NDK r6 has incorrect definition for ptrdiff_t. You are recommended to upgrade to a newer NDK release or manually patch the header: +See https://android.googlesource.com/platform/development.git f907f4f9d4e56ccc8093df6fee54454b8bcab6c2 + diff --git a/ndk/platforms/android-9/arch-x86/include/machine/_types.h b/ndk/platforms/android-9/arch-x86/include/machine/_types.h + index 5e28c64..65892a1 100644 + --- a/ndk/platforms/android-9/arch-x86/include/machine/_types.h + +++ b/ndk/platforms/android-9/arch-x86/include/machine/_types.h + @@ -51,7 +51,11 @@ typedef long int ssize_t; + #endif + #ifndef _PTRDIFF_T + #define _PTRDIFF_T + -typedef long ptrdiff_t; + +# ifdef __ANDROID__ + + typedef int ptrdiff_t; + +# else + + typedef long ptrdiff_t; + +# endif + #endif +" ) +endif() + + +# setup paths and STL for standalone toolchain +if( BUILD_WITH_STANDALONE_TOOLCHAIN ) + set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) + set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) + set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" ) + + if( NOT ANDROID_STL STREQUAL "none" ) + set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/include/c++/${ANDROID_COMPILER_VERSION}" ) + if( NOT EXISTS "${ANDROID_STL_INCLUDE_DIRS}" ) + # old location ( pre r8c ) + set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) + endif() + if( ARMEABI_V7A AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/bits" ) + list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}" ) + elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb/bits" ) + list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb" ) + else() + list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" ) + endif() + # always search static GNU STL to get the location of libsupc++.a + if( ARMEABI_V7A AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libstdc++.a" ) + set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb" ) + elseif( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libstdc++.a" ) + set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}" ) + elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libstdc++.a" ) + set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb" ) + elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libstdc++.a" ) + set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib" ) + endif() + if( __libstl ) + set( __libsupcxx "${__libstl}/libsupc++.a" ) + set( __libstl "${__libstl}/libstdc++.a" ) + endif() + if( NOT EXISTS "${__libsupcxx}" ) + message( FATAL_ERROR "The required libstdsupc++.a is missing in your standalone toolchain. + Usually it happens because of bug in make-standalone-toolchain.sh script from NDK r7, r7b and r7c. + You need to either upgrade to newer NDK or manually copy + $ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a + to + ${__libsupcxx} + " ) + endif() + if( ANDROID_STL STREQUAL "gnustl_shared" ) + if( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" ) + set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" ) + elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" ) + set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" ) + elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" ) + set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" ) + endif() + endif() + endif() +endif() + +# clang +if( "${ANDROID_TOOLCHAIN_NAME}" STREQUAL "standalone-clang" ) + set( ANDROID_COMPILER_IS_CLANG 1 ) + execute_process( COMMAND "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/clang${TOOL_OS_SUFFIX}" --version OUTPUT_VARIABLE ANDROID_CLANG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) + string( REGEX MATCH "[0-9]+[.][0-9]+" ANDROID_CLANG_VERSION "${ANDROID_CLANG_VERSION}") +elseif( "${ANDROID_TOOLCHAIN_NAME}" MATCHES "-clang3[.][0-9]?$" ) + string( REGEX MATCH "3[.][0-9]$" ANDROID_CLANG_VERSION "${ANDROID_TOOLCHAIN_NAME}") + string( REGEX REPLACE "-clang${ANDROID_CLANG_VERSION}$" "-${ANDROID_COMPILER_VERSION}" ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) + if( NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}/bin/clang${TOOL_OS_SUFFIX}" ) + message( FATAL_ERROR "Could not find the Clang compiler driver" ) + endif() + set( ANDROID_COMPILER_IS_CLANG 1 ) + set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) +else() + set( ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) + unset( ANDROID_COMPILER_IS_CLANG CACHE ) +endif() + +string( REPLACE "." "" _clang_name "clang${ANDROID_CLANG_VERSION}" ) +if( NOT EXISTS "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" ) + set( _clang_name "clang" ) +endif() + + +# setup paths and STL for NDK +if( BUILD_WITH_ANDROID_NDK ) + set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) + set( ANDROID_SYSROOT "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}" ) + + if( ANDROID_STL STREQUAL "none" ) + # do nothing + elseif( ANDROID_STL STREQUAL "system" ) + set( ANDROID_RTTI OFF ) + set( ANDROID_EXCEPTIONS OFF ) + set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" ) + elseif( ANDROID_STL STREQUAL "system_re" ) + set( ANDROID_RTTI ON ) + set( ANDROID_EXCEPTIONS ON ) + set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" ) + elseif( ANDROID_STL MATCHES "gabi" ) + if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 + message( FATAL_ERROR "gabi++ is not available in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.") + endif() + set( ANDROID_RTTI ON ) + set( ANDROID_EXCEPTIONS OFF ) + set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/gabi++/include" ) + set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gabi++/libs/${ANDROID_NDK_ABI_NAME}/libgabi++_static.a" ) + elseif( ANDROID_STL MATCHES "stlport" ) + if( NOT ANDROID_NDK_RELEASE_NUM LESS 8004 ) # before r8d + set( ANDROID_EXCEPTIONS ON ) + else() + set( ANDROID_EXCEPTIONS OFF ) + endif() + if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 + set( ANDROID_RTTI OFF ) + else() + set( ANDROID_RTTI ON ) + endif() + set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/stlport/stlport" ) + set( __libstl "${ANDROID_NDK}/sources/cxx-stl/stlport/libs/${ANDROID_NDK_ABI_NAME}/libstlport_static.a" ) + elseif( ANDROID_STL MATCHES "gnustl" ) + set( ANDROID_EXCEPTIONS ON ) + set( ANDROID_RTTI ON ) + if( EXISTS "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" ) + if( ARMEABI_V7A AND ANDROID_COMPILER_VERSION VERSION_EQUAL "4.7" AND ANDROID_NDK_RELEASE STREQUAL "r8d" ) + # gnustl binary for 4.7 compiler is buggy :( + # TODO: look for right fix + set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.6" ) + else() + set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" ) + endif() + else() + set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++" ) + endif() + set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" "${__libstl}/include/backward" ) + if( EXISTS "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" ) + set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" ) + else() + set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libstdc++.a" ) + endif() + else() + message( FATAL_ERROR "Unknown runtime: ${ANDROID_STL}" ) + endif() + # find libsupc++.a - rtti & exceptions + if( ANDROID_STL STREQUAL "system_re" OR ANDROID_STL MATCHES "gnustl" ) + set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r8b or newer + if( NOT EXISTS "${__libsupcxx}" ) + set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r7-r8 + endif() + if( NOT EXISTS "${__libsupcxx}" ) # before r7 + if( ARMEABI_V7A ) + if( ANDROID_FORCE_ARM_BUILD ) + set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libsupc++.a" ) + else() + set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libsupc++.a" ) + endif() + elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD ) + set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libsupc++.a" ) + else() + set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libsupc++.a" ) + endif() + endif() + if( NOT EXISTS "${__libsupcxx}") + message( ERROR "Could not find libsupc++.a for a chosen platform. Either your NDK is not supported or is broken.") + endif() + endif() +endif() + + +# case of shared STL linkage +if( ANDROID_STL MATCHES "shared" AND DEFINED __libstl ) + string( REPLACE "_static.a" "_shared.so" __libstl "${__libstl}" ) + # TODO: check if .so file exists before the renaming +endif() + + +# ccache support +__INIT_VARIABLE( _ndk_ccache NDK_CCACHE ENV_NDK_CCACHE ) +if( _ndk_ccache ) + if( DEFINED NDK_CCACHE AND NOT EXISTS NDK_CCACHE ) + unset( NDK_CCACHE CACHE ) + endif() + find_program( NDK_CCACHE "${_ndk_ccache}" DOC "The path to ccache binary") +else() + unset( NDK_CCACHE CACHE ) +endif() +unset( _ndk_ccache ) + + +# setup the cross-compiler +if( NOT CMAKE_C_COMPILER ) + if( NDK_CCACHE AND NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) + set( CMAKE_C_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C compiler" ) + set( CMAKE_CXX_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C++ compiler" ) + if( ANDROID_COMPILER_IS_CLANG ) + set( CMAKE_C_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") + set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") + else() + set( CMAKE_C_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") + set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") + endif() + else() + if( ANDROID_COMPILER_IS_CLANG ) + set( CMAKE_C_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") + set( CMAKE_CXX_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") + else() + set( CMAKE_C_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler" ) + set( CMAKE_CXX_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler" ) + endif() + endif() + set( CMAKE_ASM_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "assembler" ) + set( CMAKE_STRIP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip" ) + if( EXISTS "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" ) + # Use gcc-ar if we have it for better LTO support. + set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" ) + else() + set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" ) + endif() + set( CMAKE_LINKER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker" ) + set( CMAKE_NM "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-nm${TOOL_OS_SUFFIX}" CACHE PATH "nm" ) + set( CMAKE_OBJCOPY "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" ) + set( CMAKE_OBJDUMP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objdump${TOOL_OS_SUFFIX}" CACHE PATH "objdump" ) + set( CMAKE_RANLIB "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ranlib${TOOL_OS_SUFFIX}" CACHE PATH "ranlib" ) +endif() + +set( _CMAKE_TOOLCHAIN_PREFIX "${ANDROID_TOOLCHAIN_MACHINE_NAME}-" ) +if( CMAKE_VERSION VERSION_LESS 2.8.5 ) + set( CMAKE_ASM_COMPILER_ARG1 "-c" ) +endif() +if( APPLE ) + find_program( CMAKE_INSTALL_NAME_TOOL NAMES install_name_tool ) + if( NOT CMAKE_INSTALL_NAME_TOOL ) + message( FATAL_ERROR "Could not find install_name_tool, please check your installation." ) + endif() + mark_as_advanced( CMAKE_INSTALL_NAME_TOOL ) +endif() + +# Force set compilers because standard identification works badly for us +include( CMakeForceCompiler ) +CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU ) +if( ANDROID_COMPILER_IS_CLANG ) + set( CMAKE_C_COMPILER_ID Clang ) +endif() +set( CMAKE_C_PLATFORM_ID Linux ) +if( X86_64 OR MIPS64 OR ARM64_V8A ) + set( CMAKE_C_SIZEOF_DATA_PTR 8 ) +else() + set( CMAKE_C_SIZEOF_DATA_PTR 4 ) +endif() +set( CMAKE_C_HAS_ISYSROOT 1 ) +set( CMAKE_C_COMPILER_ABI ELF ) +CMAKE_FORCE_CXX_COMPILER( "${CMAKE_CXX_COMPILER}" GNU ) +if( ANDROID_COMPILER_IS_CLANG ) + set( CMAKE_CXX_COMPILER_ID Clang) +endif() +set( CMAKE_CXX_PLATFORM_ID Linux ) +set( CMAKE_CXX_SIZEOF_DATA_PTR ${CMAKE_C_SIZEOF_DATA_PTR} ) +set( CMAKE_CXX_HAS_ISYSROOT 1 ) +set( CMAKE_CXX_COMPILER_ABI ELF ) +set( CMAKE_CXX_SOURCE_FILE_EXTENSIONS cc cp cxx cpp CPP c++ C ) +# force ASM compiler (required for CMake < 2.8.5) +set( CMAKE_ASM_COMPILER_ID_RUN TRUE ) +set( CMAKE_ASM_COMPILER_ID GNU ) +set( CMAKE_ASM_COMPILER_WORKS TRUE ) +set( CMAKE_ASM_COMPILER_FORCED TRUE ) +set( CMAKE_COMPILER_IS_GNUASM 1) +set( CMAKE_ASM_SOURCE_FILE_EXTENSIONS s S asm ) + +foreach( lang C CXX ASM ) + if( ANDROID_COMPILER_IS_CLANG ) + set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_CLANG_VERSION} ) + else() + set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_COMPILER_VERSION} ) + endif() +endforeach() + +# flags and definitions +remove_definitions( -DANDROID ) +add_definitions( -DANDROID ) + +if( ANDROID_SYSROOT MATCHES "[ ;\"]" ) + if( CMAKE_HOST_WIN32 ) + # try to convert path to 8.3 form + file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "@echo %~s1" ) + execute_process( COMMAND "$ENV{ComSpec}" /c "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "${ANDROID_SYSROOT}" + OUTPUT_VARIABLE __path OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE __result ERROR_QUIET ) + if( __result EQUAL 0 ) + file( TO_CMAKE_PATH "${__path}" ANDROID_SYSROOT ) + set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) + else() + set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" ) + endif() + else() + set( ANDROID_CXX_FLAGS "'--sysroot=${ANDROID_SYSROOT}'" ) + endif() + if( NOT _CMAKE_IN_TRY_COMPILE ) + # quotes can break try_compile and compiler identification + message(WARNING "Path to your Android NDK (or toolchain) has non-alphanumeric symbols.\nThe build might be broken.\n") + endif() +else() + set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) +endif() + +# NDK flags +if (ARM64_V8A ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) + set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) + set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) + if( NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) + endif() +elseif( ARMEABI OR ARMEABI_V7A) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) + if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 ) + set( ANDROID_CXX_FLAGS_RELEASE "-mthumb -fomit-frame-pointer -fno-strict-aliasing" ) + set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) + if( NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -finline-limit=64" ) + endif() + else() + # always compile ARMEABI_V6 in arm mode; otherwise there is no difference from ARMEABI + set( ANDROID_CXX_FLAGS_RELEASE "-marm -fomit-frame-pointer -fstrict-aliasing" ) + set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) + if( NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) + endif() + endif() +elseif( X86 OR X86_64 ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) + if( NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) + endif() + set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) + set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) +elseif( MIPS OR MIPS64 ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-strict-aliasing -finline-functions -funwind-tables -fmessage-length=0" ) + set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" ) + set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer" ) + if( NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers" ) + set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) + endif() +elseif() + set( ANDROID_CXX_FLAGS_RELEASE "" ) + set( ANDROID_CXX_FLAGS_DEBUG "" ) +endif() + +set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" ) # good/necessary when porting desktop libraries + +if( NOT X86 AND NOT ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "-Wno-psabi ${ANDROID_CXX_FLAGS}" ) +endif() + +if( NOT ANDROID_COMPILER_VERSION VERSION_LESS "4.6" ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -no-canonical-prefixes" ) # see https://android-review.googlesource.com/#/c/47564/ +endif() + +# ABI-specific flags +if( ARMEABI_V7A ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv7-a -mfloat-abi=softfp" ) + if( NEON ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=neon" ) + elseif( VFPV3 ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3" ) + else() + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3-d16" ) + endif() +elseif( ARMEABI_V6 ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv6 -mfloat-abi=softfp -mfpu=vfp" ) # vfp == vfpv2 +elseif( ARMEABI ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv5te -mtune=xscale -msoft-float" ) +endif() + +if( ANDROID_STL MATCHES "gnustl" AND (EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}") ) + set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) + set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) + set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) +else() + set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) + set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) + set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) +endif() + +# STL +if( EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}" ) + if( EXISTS "${__libstl}" ) + set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libstl}\"" ) + set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libstl}\"" ) + set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libstl}\"" ) + endif() + if( EXISTS "${__libsupcxx}" ) + set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" ) + set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" ) + set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) + # C objects: + set( CMAKE_C_CREATE_SHARED_LIBRARY " -o " ) + set( CMAKE_C_CREATE_SHARED_MODULE " -o " ) + set( CMAKE_C_LINK_EXECUTABLE " -o " ) + set( CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" ) + set( CMAKE_C_CREATE_SHARED_MODULE "${CMAKE_C_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" ) + set( CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) + endif() + if( ANDROID_STL MATCHES "gnustl" ) + if( NOT EXISTS "${ANDROID_LIBM_PATH}" ) + set( ANDROID_LIBM_PATH -lm ) + endif() + set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} ${ANDROID_LIBM_PATH}" ) + set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} ${ANDROID_LIBM_PATH}" ) + set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} ${ANDROID_LIBM_PATH}" ) + endif() +endif() + +# variables controlling optional build flags +if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 + # libGLESv2.so in NDK's prior to r7 refers to missing external symbols. + # So this flag option is required for all projects using OpenGL from native. + __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES ON ) +else() + __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES OFF ) +endif() +__INIT_VARIABLE( ANDROID_NO_UNDEFINED VALUES ON ) +__INIT_VARIABLE( ANDROID_FUNCTION_LEVEL_LINKING VALUES ON ) +__INIT_VARIABLE( ANDROID_GOLD_LINKER VALUES ON ) +__INIT_VARIABLE( ANDROID_NOEXECSTACK VALUES ON ) +__INIT_VARIABLE( ANDROID_RELRO VALUES ON ) + +set( ANDROID_NO_UNDEFINED ${ANDROID_NO_UNDEFINED} CACHE BOOL "Show all undefined symbols as linker errors" ) +set( ANDROID_SO_UNDEFINED ${ANDROID_SO_UNDEFINED} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) +set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Put each function in separate section and enable garbage collection of unused input sections at link time" ) +set( ANDROID_GOLD_LINKER ${ANDROID_GOLD_LINKER} CACHE BOOL "Enables gold linker" ) +set( ANDROID_NOEXECSTACK ${ANDROID_NOEXECSTACK} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) +set( ANDROID_RELRO ${ANDROID_RELRO} CACHE BOOL "Enables RELRO - a memory corruption mitigation technique" ) +mark_as_advanced( ANDROID_NO_UNDEFINED ANDROID_SO_UNDEFINED ANDROID_FUNCTION_LEVEL_LINKING ANDROID_GOLD_LINKER ANDROID_NOEXECSTACK ANDROID_RELRO ) + +# linker flags +set( ANDROID_LINKER_FLAGS "" ) + +if( ARMEABI_V7A ) + # this is *required* to use the following linker flags that routes around + # a CPU bug in some Cortex-A8 implementations: + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--fix-cortex-a8" ) +endif() + +if( ANDROID_NO_UNDEFINED ) + if( MIPS ) + # there is some sysroot-related problem in mips linker... + if( NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined -Wl,-rpath-link,${ANDROID_SYSROOT}/usr/lib" ) + endif() + else() + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined" ) + endif() +endif() + +if( ANDROID_SO_UNDEFINED ) + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-allow-shlib-undefined" ) +endif() + +if( ANDROID_FUNCTION_LEVEL_LINKING ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fdata-sections -ffunction-sections" ) + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--gc-sections" ) +endif() + +if( ANDROID_COMPILER_VERSION VERSION_EQUAL "4.6" ) + if( ANDROID_GOLD_LINKER AND (CMAKE_HOST_UNIX OR ANDROID_NDK_RELEASE_NUM GREATER 8002) AND (ARMEABI OR ARMEABI_V7A OR X86) ) + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=gold" ) + elseif( ANDROID_NDK_RELEASE_NUM GREATER 8002 ) # after r8b + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=bfd" ) + elseif( ANDROID_NDK_RELEASE STREQUAL "r8b" AND ARMEABI AND NOT _CMAKE_IN_TRY_COMPILE ) + message( WARNING "The default bfd linker from arm GCC 4.6 toolchain can fail with 'unresolvable R_ARM_THM_CALL relocation' error message. See https://code.google.com/p/android/issues/detail?id=35342 + On Linux and OS X host platform you can workaround this problem using gold linker (default). + Rerun cmake with -DANDROID_GOLD_LINKER=ON option in case of problems. +" ) + endif() +endif() # version 4.6 + +if( ANDROID_NOEXECSTACK ) + if( ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Xclang -mnoexecstack" ) + else() + set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Wa,--noexecstack" ) + endif() + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,noexecstack" ) +endif() + +if( ANDROID_RELRO ) + set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now" ) +endif() + +if( ANDROID_COMPILER_IS_CLANG ) + set( ANDROID_CXX_FLAGS "-target ${ANDROID_LLVM_TRIPLE} -Qunused-arguments ${ANDROID_CXX_FLAGS}" ) + if( BUILD_WITH_ANDROID_NDK ) + set( ANDROID_CXX_FLAGS "-gcc-toolchain ${ANDROID_TOOLCHAIN_ROOT} ${ANDROID_CXX_FLAGS}" ) + endif() +endif() + +# cache flags +set( CMAKE_CXX_FLAGS "" CACHE STRING "c++ flags" ) +set( CMAKE_C_FLAGS "" CACHE STRING "c flags" ) +set( CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c++ Release flags" ) +set( CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c Release flags" ) +set( CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c++ Debug flags" ) +set( CMAKE_C_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c Debug flags" ) +set( CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "shared linker flags" ) +set( CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "module linker flags" ) +set( CMAKE_EXE_LINKER_FLAGS "-Wl,-z,nocopyreloc" CACHE STRING "executable linker flags" ) + +# put flags to cache (for debug purpose only) +set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS}" CACHE INTERNAL "Android specific c/c++ flags" ) +set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE}" CACHE INTERNAL "Android specific c/c++ Release flags" ) +set( ANDROID_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG}" CACHE INTERNAL "Android specific c/c++ Debug flags" ) +set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}" CACHE INTERNAL "Android specific c/c++ linker flags" ) + +# finish flags +set( CMAKE_CXX_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" ) +set( CMAKE_C_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_C_FLAGS}" ) +set( CMAKE_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_CXX_FLAGS_RELEASE}" ) +set( CMAKE_C_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_C_FLAGS_RELEASE}" ) +set( CMAKE_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_CXX_FLAGS_DEBUG}" ) +set( CMAKE_C_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_C_FLAGS_DEBUG}" ) +set( CMAKE_SHARED_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}" ) +set( CMAKE_MODULE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}" ) +set( CMAKE_EXE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" ) + +if( MIPS AND BUILD_WITH_ANDROID_NDK AND ANDROID_NDK_RELEASE STREQUAL "r8" ) + set( CMAKE_SHARED_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_SHARED_LINKER_FLAGS}" ) + set( CMAKE_MODULE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_MODULE_LINKER_FLAGS}" ) + set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" ) +endif() + +# pie/pic +if( NOT (ANDROID_NATIVE_API_LEVEL LESS 16) AND (NOT DEFINED ANDROID_APP_PIE OR ANDROID_APP_PIE) AND (CMAKE_VERSION VERSION_GREATER 2.8.8) ) + set( CMAKE_POSITION_INDEPENDENT_CODE TRUE ) + set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIE -pie") +else() + set( CMAKE_POSITION_INDEPENDENT_CODE FALSE ) + set( CMAKE_CXX_FLAGS "-fpic ${CMAKE_CXX_FLAGS}" ) + set( CMAKE_C_FLAGS "-fpic ${CMAKE_C_FLAGS}" ) +endif() + +# configure rtti +if( DEFINED ANDROID_RTTI AND ANDROID_STL_FORCE_FEATURES ) + if( ANDROID_RTTI ) + set( CMAKE_CXX_FLAGS "-frtti ${CMAKE_CXX_FLAGS}" ) + else() + set( CMAKE_CXX_FLAGS "-fno-rtti ${CMAKE_CXX_FLAGS}" ) + endif() +endif() + +# configure exceptios +if( DEFINED ANDROID_EXCEPTIONS AND ANDROID_STL_FORCE_FEATURES ) + if( ANDROID_EXCEPTIONS ) + set( CMAKE_CXX_FLAGS "-fexceptions ${CMAKE_CXX_FLAGS}" ) + set( CMAKE_C_FLAGS "-fexceptions ${CMAKE_C_FLAGS}" ) + else() + set( CMAKE_CXX_FLAGS "-fno-exceptions ${CMAKE_CXX_FLAGS}" ) + set( CMAKE_C_FLAGS "-fno-exceptions ${CMAKE_C_FLAGS}" ) + endif() +endif() + +# global includes and link directories +include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} ) +get_filename_component(__android_install_path "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ABSOLUTE) # avoid CMP0015 policy warning +link_directories( "${__android_install_path}" ) + +# detect if need link crtbegin_so.o explicitly +if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK ) + set( __cmd "${CMAKE_CXX_CREATE_SHARED_LIBRARY}" ) + string( REPLACE "" "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" __cmd "${__cmd}" ) + string( REPLACE "" "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}" __cmd "${__cmd}" ) + string( REPLACE "" "${CMAKE_CXX_FLAGS}" __cmd "${__cmd}" ) + string( REPLACE "" "" __cmd "${__cmd}" ) + string( REPLACE "" "${CMAKE_SHARED_LINKER_FLAGS}" __cmd "${__cmd}" ) + string( REPLACE "" "-shared" __cmd "${__cmd}" ) + string( REPLACE "" "" __cmd "${__cmd}" ) + string( REPLACE "" "" __cmd "${__cmd}" ) + string( REPLACE "" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain_crtlink_test.so" __cmd "${__cmd}" ) + string( REPLACE "" "\"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" __cmd "${__cmd}" ) + string( REPLACE "" "" __cmd "${__cmd}" ) + separate_arguments( __cmd ) + foreach( __var ANDROID_NDK ANDROID_NDK_TOOLCHAINS_PATH ANDROID_STANDALONE_TOOLCHAIN ) + if( ${__var} ) + set( __tmp "${${__var}}" ) + separate_arguments( __tmp ) + string( REPLACE "${__tmp}" "${${__var}}" __cmd "${__cmd}") + endif() + endforeach() + string( REPLACE "'" "" __cmd "${__cmd}" ) + string( REPLACE "\"" "" __cmd "${__cmd}" ) + execute_process( COMMAND ${__cmd} RESULT_VARIABLE __cmd_result OUTPUT_QUIET ERROR_QUIET ) + if( __cmd_result EQUAL 0 ) + set( ANDROID_EXPLICIT_CRT_LINK ON ) + else() + set( ANDROID_EXPLICIT_CRT_LINK OFF ) + endif() +endif() + +if( ANDROID_EXPLICIT_CRT_LINK ) + set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) + set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) +endif() + +# setup output directories +set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" ) + +if( DEFINED LIBRARY_OUTPUT_PATH_ROOT + OR EXISTS "${CMAKE_SOURCE_DIR}/AndroidManifest.xml" + OR (EXISTS "${CMAKE_SOURCE_DIR}/../AndroidManifest.xml" AND EXISTS "${CMAKE_SOURCE_DIR}/../jni/") ) + set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "Root for binaries output, set this to change where Android libs are installed to" ) + if( NOT _CMAKE_IN_TRY_COMPILE ) + if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" ) + set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" ) + else() + set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" ) + endif() + set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for Android libs" ) + endif() +endif() + +# copy shaed stl library to build directory +if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" AND DEFINED LIBRARY_OUTPUT_PATH ) + get_filename_component( __libstlname "${__libstl}" NAME ) + execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess ) + if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}") + message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" ) + endif() + unset( __fileCopyProcess ) + unset( __libstlname ) +endif() + + +# set these global flags for cmake client scripts to change behavior +set( ANDROID True ) +set( BUILD_ANDROID True ) + +# where is the target environment +set( CMAKE_FIND_ROOT_PATH "${ANDROID_TOOLCHAIN_ROOT}/bin" "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" "${ANDROID_SYSROOT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share" ) + +# only search for libraries and includes in the ndk toolchain +set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) +set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) +set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) + + +# macro to find packages on the host OS +macro( find_host_package ) + set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) + set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) + set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) + if( CMAKE_HOST_WIN32 ) + SET( WIN32 1 ) + SET( UNIX ) + elseif( CMAKE_HOST_APPLE ) + SET( APPLE 1 ) + SET( UNIX ) + endif() + find_package( ${ARGN} ) + SET( WIN32 ) + SET( APPLE ) + SET( UNIX 1 ) + set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) + set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) + set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) +endmacro() + + +# macro to find programs on the host OS +macro( find_host_program ) + set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) + set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) + set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) + if( CMAKE_HOST_WIN32 ) + SET( WIN32 1 ) + SET( UNIX ) + elseif( CMAKE_HOST_APPLE ) + SET( APPLE 1 ) + SET( UNIX ) + endif() + find_program( ${ARGN} ) + SET( WIN32 ) + SET( APPLE ) + SET( UNIX 1 ) + set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) + set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) + set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) +endmacro() + + +# export toolchain settings for the try_compile() command +if( NOT _CMAKE_IN_TRY_COMPILE ) + set( __toolchain_config "") + foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN + ANDROID_NDK_HOST_X64 + ANDROID_NDK + ANDROID_NDK_LAYOUT + ANDROID_STANDALONE_TOOLCHAIN + ANDROID_TOOLCHAIN_NAME + ANDROID_ABI + ANDROID_NATIVE_API_LEVEL + ANDROID_STL + ANDROID_STL_FORCE_FEATURES + ANDROID_FORCE_ARM_BUILD + ANDROID_NO_UNDEFINED + ANDROID_SO_UNDEFINED + ANDROID_FUNCTION_LEVEL_LINKING + ANDROID_GOLD_LINKER + ANDROID_NOEXECSTACK + ANDROID_RELRO + ANDROID_LIBM_PATH + ANDROID_EXPLICIT_CRT_LINK + ANDROID_APP_PIE + ) + if( DEFINED ${__var} ) + if( ${__var} MATCHES " ") + set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" CACHE INTERNAL \"\" )\n" ) + else() + set( __toolchain_config "${__toolchain_config}set( ${__var} ${${__var}} CACHE INTERNAL \"\" )\n" ) + endif() + endif() + endforeach() + file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android.toolchain.config.cmake" "${__toolchain_config}" ) + unset( __toolchain_config ) +endif() + + +# force cmake to produce / instead of \ in build commands for Ninja generator +if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 ) + # it is a bad hack after all + # CMake generates Ninja makefiles with UNIX paths only if it thinks that we are going to build with MinGW + set( CMAKE_COMPILER_IS_MINGW TRUE ) # tell CMake that we are MinGW + set( CMAKE_CROSSCOMPILING TRUE ) # stop recursion + enable_language( C ) + enable_language( CXX ) + # unset( CMAKE_COMPILER_IS_MINGW ) # can't unset because CMake does not convert back-slashes in response files without it + unset( MINGW ) +endif() + + +# Variables controlling behavior or set by cmake toolchain: +# ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "x86", "mips", "arm64-v8a", "x86_64", "mips64" +# ANDROID_NATIVE_API_LEVEL : 3,4,5,8,9,14,15,16,17,18,19,21 (depends on NDK version) +# ANDROID_STL : gnustl_static/gnustl_shared/stlport_static/stlport_shared/gabi++_static/gabi++_shared/system_re/system/none +# ANDROID_FORBID_SYGWIN : ON/OFF +# ANDROID_NO_UNDEFINED : ON/OFF +# ANDROID_SO_UNDEFINED : OFF/ON (default depends on NDK version) +# ANDROID_FUNCTION_LEVEL_LINKING : ON/OFF +# ANDROID_GOLD_LINKER : ON/OFF +# ANDROID_NOEXECSTACK : ON/OFF +# ANDROID_RELRO : ON/OFF +# ANDROID_FORCE_ARM_BUILD : ON/OFF +# ANDROID_STL_FORCE_FEATURES : ON/OFF +# ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product//obj/lib/libm.so) to workaround unresolved `sincos` +# Can be set only at the first run: +# ANDROID_NDK : path to your NDK install +# NDK_CCACHE : path to your ccache executable +# ANDROID_TOOLCHAIN_NAME : the NDK name of compiler toolchain +# ANDROID_NDK_HOST_X64 : try to use x86_64 toolchain (default for x64 host systems) +# ANDROID_NDK_LAYOUT : the inner NDK structure (RELEASE, LINARO, ANDROID) +# LIBRARY_OUTPUT_PATH_ROOT : +# ANDROID_STANDALONE_TOOLCHAIN +# +# Primary read-only variables: +# ANDROID : always TRUE +# ARMEABI : TRUE for arm v6 and older devices +# ARMEABI_V6 : TRUE for arm v6 +# ARMEABI_V7A : TRUE for arm v7a +# ARM64_V8A : TRUE for arm64-v8a +# NEON : TRUE if NEON unit is enabled +# VFPV3 : TRUE if VFP version 3 is enabled +# X86 : TRUE if configured for x86 +# X86_64 : TRUE if configured for x86_64 +# MIPS : TRUE if configured for mips +# MIPS64 : TRUE if configured for mips64 +# BUILD_WITH_ANDROID_NDK : TRUE if NDK is used +# BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used +# ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform +# ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86", "mips", "arm64-v8a", "x86_64", "mips64" depending on ANDROID_ABI +# ANDROID_NDK_RELEASE : from r5 to r10d; set only for NDK +# ANDROID_NDK_RELEASE_NUM : numeric ANDROID_NDK_RELEASE version (1000*major+minor) +# ANDROID_ARCH_NAME : "arm", "x86", "mips", "arm64", "x86_64", "mips64" depending on ANDROID_ABI +# ANDROID_SYSROOT : path to the compiler sysroot +# TOOL_OS_SUFFIX : "" or ".exe" depending on host platform +# ANDROID_COMPILER_IS_CLANG : TRUE if clang compiler is used +# +# Secondary (less stable) read-only variables: +# ANDROID_COMPILER_VERSION : GCC version used (not Clang version) +# ANDROID_CLANG_VERSION : version of clang compiler if clang is used +# ANDROID_CXX_FLAGS : C/C++ compiler flags required by Android platform +# ANDROID_SUPPORTED_ABIS : list of currently allowed values for ANDROID_ABI +# ANDROID_TOOLCHAIN_MACHINE_NAME : "arm-linux-androideabi", "arm-eabi" or "i686-android-linux" +# ANDROID_TOOLCHAIN_ROOT : path to the top level of toolchain (standalone or placed inside NDK) +# ANDROID_CLANG_TOOLCHAIN_ROOT : path to clang tools +# ANDROID_SUPPORTED_NATIVE_API_LEVELS : list of native API levels found inside NDK +# ANDROID_STL_INCLUDE_DIRS : stl include paths +# ANDROID_RTTI : if rtti is enabled by the runtime +# ANDROID_EXCEPTIONS : if exceptions are enabled by the runtime +# ANDROID_GCC_TOOLCHAIN_NAME : read-only, differs from ANDROID_TOOLCHAIN_NAME only if clang is used +# +# Defaults: +# ANDROID_DEFAULT_NDK_API_LEVEL +# ANDROID_DEFAULT_NDK_API_LEVEL_${ARCH} +# ANDROID_NDK_SEARCH_PATHS +# ANDROID_SUPPORTED_ABIS_${ARCH} +# ANDROID_SUPPORTED_NDK_VERSIONS diff --git a/TMessagesProj/jni/boringssl/util/android-cmake/ndk_links.md b/TMessagesProj/jni/boringssl/util/android-cmake/ndk_links.md new file mode 100644 index 00000000..6d93d61d --- /dev/null +++ b/TMessagesProj/jni/boringssl/util/android-cmake/ndk_links.md @@ -0,0 +1,211 @@ + +============== r1 ============== (dead links) + +* http://dl.google.com/android/ndk/android-ndk-1.5_r1-windows.zip +* http://dl.google.com/android/ndk/android-ndk-1.5_r1-darwin-x86.zip +* http://dl.google.com/android/ndk/android-ndk-1.5_r1-linux-x86.zip + +============== r2 ============== + +* http://dl.google.com/android/ndk/android-ndk-1.6_r1-windows.zip +* http://dl.google.com/android/ndk/android-ndk-1.6_r1-darwin-x86.zip +* http://dl.google.com/android/ndk/android-ndk-1.6_r1-linux-x86.zip + +============== r3 ============== + +* http://dl.google.com/android/ndk/android-ndk-r3-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r3-darwin-x86.zip +* http://dl.google.com/android/ndk/android-ndk-r3-linux-x86.zip + +============== r4 ============== + +* http://dl.google.com/android/ndk/android-ndk-r4-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r4-darwin-x86.zip +* http://dl.google.com/android/ndk/android-ndk-r4-linux-x86.zip + +============== r4b ============== + +* http://dl.google.com/android/ndk/android-ndk-r4b-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r4b-darwin-x86.zip +* http://dl.google.com/android/ndk/android-ndk-r4b-linux-x86.zip + +============== r5 ============== + +* http://dl.google.com/android/ndk/android-ndk-r5-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r5-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r5-linux-x86.tar.bz2 + +============== r5b ============== + +* http://dl.google.com/android/ndk/android-ndk-r5b-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r5b-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r5b-linux-x86.tar.bz2 + +============== r5c ============== + +* http://dl.google.com/android/ndk/android-ndk-r5c-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r5c-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r5c-linux-x86.tar.bz2 + +============== r6 ============== + +* http://dl.google.com/android/ndk/android-ndk-r6-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r6-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r6-linux-x86.tar.bz2 + +============== r6b ============== + +* http://dl.google.com/android/ndk/android-ndk-r6b-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r6b-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r6b-linux-x86.tar.bz2 + +============== r7 ============== + +* http://dl.google.com/android/ndk/android-ndk-r7-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r7-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r7-linux-x86.tar.bz2 + +============== r7b ============== + +* http://dl.google.com/android/ndk/android-ndk-r7b-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r7b-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r7b-linux-x86.tar.bz2 + +============== r7c ============== + +* http://dl.google.com/android/ndk/android-ndk-r7c-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r7c-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r7c-linux-x86.tar.bz2 + +============== r8 ============== + +* http://dl.google.com/android/ndk/android-ndk-r8-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r8-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r8-linux-x86.tar.bz2 + +============== r8b ============== + +* http://dl.google.com/android/ndk/android-ndk-r8b-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r8b-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r8b-linux-x86.tar.bz2 + +============== r8c ============== + +* http://dl.google.com/android/ndk/android-ndk-r8c-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r8c-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r8c-linux-x86.tar.bz2 + +============== r8d ============== + +* http://dl.google.com/android/ndk/android-ndk-r8d-windows.zip +* http://dl.google.com/android/ndk/android-ndk-r8d-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r8d-linux-x86.tar.bz2 + +============== r8e ============== + +* http://dl.google.com/android/ndk/android-ndk-r8e-windows-x86.zip +* http://dl.google.com/android/ndk/android-ndk-r8e-windows-x86_64.zip +* http://dl.google.com/android/ndk/android-ndk-r8e-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r8e-darwin-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r8e-linux-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r8e-linux-x86_64.tar.bz2 + +============== r9 ============== + +* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86.zip +* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86-legacy-toolchains.zip +* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86_64.zip +* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86_64-legacy-toolchains.zip +* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86-legacy-toolchains.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86_64-legacy-toolchains.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86-legacy-toolchains.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86_64-legacy-toolchains.tar.bz2 + +============== r9b ============== + +* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86.zip +* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86-legacy-toolchains.zip +* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86_64.zip +* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86_64-legacy-toolchains.zip +* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86-legacy-toolchains.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86_64-legacy-toolchains.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86-legacy-toolchains.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86_64-legacy-toolchains.tar.bz2 + +============== r9c ============== + +* http://dl.google.com/android/ndk/android-ndk-r9c-windows-x86.zip +* http://dl.google.com/android/ndk/android-ndk-r9c-windows-x86_64.zip +* http://dl.google.com/android/ndk/android-ndk-r9c-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9c-darwin-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9c-linux-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9c-linux-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9c-cxx-stl-libs-with-debugging-info.zip + +============== r9d ============== + +* http://dl.google.com/android/ndk/android-ndk-r9d-windows-x86.zip +* http://dl.google.com/android/ndk/android-ndk-r9d-windows-x86_64.zip +* http://dl.google.com/android/ndk/android-ndk-r9d-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9d-darwin-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r9d-cxx-stl-libs-with-debug-info.zip + +============== r10 ============== + +* http://dl.google.com/android/ndk/android-ndk32-r10-windows-x86.zip +* http://dl.google.com/android/ndk/android-ndk32-r10-windows-x86_64.zip +* http://dl.google.com/android/ndk/android-ndk32-r10-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk32-r10-darwin-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk32-r10-linux-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk32-r10-linux-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk64-r10-windows-x86.zip +* http://dl.google.com/android/ndk/android-ndk64-r10-windows-x86_64.zip +* http://dl.google.com/android/ndk/android-ndk64-r10-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk64-r10-darwin-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk64-r10-linux-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk64-r10-linux-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r10-cxx-stl-libs-with-debug-info.zip + +============== r10b ============== + +* http://dl.google.com/android/ndk/android-ndk32-r10b-windows-x86.zip +* http://dl.google.com/android/ndk/android-ndk32-r10b-windows-x86_64.zip +* http://dl.google.com/android/ndk/android-ndk32-r10b-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk32-r10b-darwin-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk32-r10b-linux-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk32-r10b-linux-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk64-r10b-windows-x86.zip +* http://dl.google.com/android/ndk/android-ndk64-r10b-windows-x86_64.zip +* http://dl.google.com/android/ndk/android-ndk64-r10b-darwin-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk64-r10b-darwin-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk64-r10b-linux-x86.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk64-r10b-linux-x86_64.tar.bz2 +* http://dl.google.com/android/ndk/android-ndk-r10b-cxx-stl-libs-with-debug-info.zip + +============== r10c ============== + +* http://dl.google.com/android/ndk/android-ndk-r10c-windows-x86.exe +* http://dl.google.com/android/ndk/android-ndk-r10c-windows-x86_64.exe +* http://dl.google.com/android/ndk/android-ndk-r10c-darwin-x86.bin +* http://dl.google.com/android/ndk/android-ndk-r10c-darwin-x86_64.bin +* http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86.bin +* http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86_64.bin + +============== r10d ============== + +* http://dl.google.com/android/ndk/android-ndk-r10d-windows-x86.exe +* http://dl.google.com/android/ndk/android-ndk-r10d-windows-x86_64.exe +* http://dl.google.com/android/ndk/android-ndk-r10d-darwin-x86.bin +* http://dl.google.com/android/ndk/android-ndk-r10d-darwin-x86_64.bin +* http://dl.google.com/android/ndk/android-ndk-r10d-linux-x86.bin +* http://dl.google.com/android/ndk/android-ndk-r10d-linux-x86_64.bin diff --git a/TMessagesProj/jni/breakpad/LICENSE b/TMessagesProj/jni/breakpad/LICENSE new file mode 100644 index 00000000..95207bdf --- /dev/null +++ b/TMessagesProj/jni/breakpad/LICENSE @@ -0,0 +1,50 @@ +Copyright (c) 2006, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS 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 COPYRIGHT +OWNER OR 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. + +-------------------------------------------------------------------- + +Copyright 2001-2004 Unicode, Inc. + +Disclaimer + +This source code is provided as is by Unicode, Inc. No claims are +made as to fitness for any particular purpose. No warranties of any +kind are expressed or implied. The recipient agrees to determine +applicability of information provided. If this file has been +purchased on magnetic or optical media from Unicode, Inc., the +sole remedy for any claim will be exchange of defective media +within 90 days of receipt. + +Limitations on Rights to Redistribute This Code + +Unicode, Inc. hereby grants the right to freely use the information +supplied in this file in the creation of products supporting the +Unicode Standard, and to make copies of this file in any form +for internal or external distribution as long as this notice +remains attached. diff --git a/TMessagesProj/jni/breakpad/client/linux/crash_generation/client_info.h b/TMessagesProj/jni/breakpad/client/linux/crash_generation/client_info.h new file mode 100644 index 00000000..d0a184a6 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/crash_generation/client_info.h @@ -0,0 +1,53 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_ +#define CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_ + +namespace google_breakpad { + +class CrashGenerationServer; + +class ClientInfo { + public: + ClientInfo(pid_t pid, CrashGenerationServer* crash_server) + : crash_server_(crash_server), + pid_(pid) {} + + CrashGenerationServer* crash_server() const { return crash_server_; } + pid_t pid() const { return pid_; } + + private: + CrashGenerationServer* crash_server_; + pid_t pid_; +}; + +} + +#endif // CLIENT_LINUX_CRASH_GENERATION_CLIENT_INFO_H_ diff --git a/TMessagesProj/jni/breakpad/client/linux/crash_generation/crash_generation_client.cc b/TMessagesProj/jni/breakpad/client/linux/crash_generation/crash_generation_client.cc new file mode 100644 index 00000000..d8bfbbad --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/crash_generation/crash_generation_client.cc @@ -0,0 +1,105 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#include "client/linux/crash_generation/crash_generation_client.h" + +#include +#include +#include + +#include + +#include "common/linux/eintr_wrapper.h" +#include "common/linux/ignore_ret.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +namespace { + +class CrashGenerationClientImpl : public CrashGenerationClient { + public: + explicit CrashGenerationClientImpl(int server_fd) : server_fd_(server_fd) {} + virtual ~CrashGenerationClientImpl() {} + + virtual bool RequestDump(const void* blob, size_t blob_size) { + int fds[2]; + if (sys_pipe(fds) < 0) + return false; + static const unsigned kControlMsgSize = CMSG_SPACE(sizeof(int)); + + struct kernel_iovec iov; + iov.iov_base = const_cast(blob); + iov.iov_len = blob_size; + + struct kernel_msghdr msg = { 0 }; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + char cmsg[kControlMsgSize] = ""; + msg.msg_control = cmsg; + msg.msg_controllen = sizeof(cmsg); + + struct cmsghdr* hdr = CMSG_FIRSTHDR(&msg); + hdr->cmsg_level = SOL_SOCKET; + hdr->cmsg_type = SCM_RIGHTS; + hdr->cmsg_len = CMSG_LEN(sizeof(int)); + int* p = reinterpret_cast(CMSG_DATA(hdr)); + *p = fds[1]; + + ssize_t ret = HANDLE_EINTR(sys_sendmsg(server_fd_, &msg, 0)); + sys_close(fds[1]); + if (ret < 0) { + sys_close(fds[0]); + return false; + } + + // Wait for an ACK from the server. + char b; + IGNORE_RET(HANDLE_EINTR(sys_read(fds[0], &b, 1))); + sys_close(fds[0]); + + return true; + } + + private: + int server_fd_; + + DISALLOW_COPY_AND_ASSIGN(CrashGenerationClientImpl); +}; + +} // namespace + +// static +CrashGenerationClient* CrashGenerationClient::TryCreate(int server_fd) { + if (server_fd < 0) + return NULL; + return new CrashGenerationClientImpl(server_fd); +} + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/client/linux/crash_generation/crash_generation_client.h b/TMessagesProj/jni/breakpad/client/linux/crash_generation/crash_generation_client.h new file mode 100644 index 00000000..4e68424a --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/crash_generation/crash_generation_client.h @@ -0,0 +1,65 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ +#define CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ + +#include "common/basictypes.h" + +#include + +namespace google_breakpad { + +// CrashGenerationClient is an interface for implementing out-of-process crash +// dumping. The default implementation, accessed via the TryCreate() factory, +// works in conjunction with the CrashGenerationServer to generate a minidump +// via a remote process. +class CrashGenerationClient { + public: + CrashGenerationClient() {} + virtual ~CrashGenerationClient() {} + + // Request the crash server to generate a dump. |blob| is an opaque + // CrashContext pointer from exception_handler.h. + // Returns true if the dump was successful; false otherwise. + virtual bool RequestDump(const void* blob, size_t blob_size) = 0; + + // Returns a new CrashGenerationClient if |server_fd| is valid and + // connects to a CrashGenerationServer. Otherwise, return NULL. + // The returned CrashGenerationClient* is owned by the caller of + // this function. + static CrashGenerationClient* TryCreate(int server_fd); + + private: + DISALLOW_COPY_AND_ASSIGN(CrashGenerationClient); +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_CRASH_GENERATION_CRASH_GENERATION_CLIENT_H_ diff --git a/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/mapping_info.h b/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/mapping_info.h new file mode 100644 index 00000000..5f247cfd --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/mapping_info.h @@ -0,0 +1,61 @@ +// Copyright (c) 2014, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_ +#define CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_ + +#include +#include +#include + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +// One of these is produced for each mapping in the process (i.e. line in +// /proc/$x/maps). +struct MappingInfo { + uintptr_t start_addr; + size_t size; + size_t offset; // offset into the backed file. + bool exec; // true if the mapping has the execute bit set. + char name[NAME_MAX]; +}; + +struct MappingEntry { + MappingInfo first; + uint8_t second[sizeof(MDGUID)]; +}; + +// A list of +typedef std::list MappingList; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_MAPPING_INFO_H_ diff --git a/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/raw_context_cpu.h b/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/raw_context_cpu.h new file mode 100644 index 00000000..e2ef45df --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/raw_context_cpu.h @@ -0,0 +1,53 @@ +// Copyright (c) 2014, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H +#define CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +#if defined(__i386__) +typedef MDRawContextX86 RawContextCPU; +#elif defined(__x86_64) +typedef MDRawContextAMD64 RawContextCPU; +#elif defined(__ARM_EABI__) +typedef MDRawContextARM RawContextCPU; +#elif defined(__aarch64__) +typedef MDRawContextARM64 RawContextCPU; +#elif defined(__mips__) +typedef MDRawContextMIPS RawContextCPU; +#else +#error "This code has not been ported to your platform yet." +#endif + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_RAW_CONTEXT_CPU_H diff --git a/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/thread_info.cc b/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/thread_info.cc new file mode 100644 index 00000000..9956d445 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/thread_info.cc @@ -0,0 +1,299 @@ +// Copyright (c) 2014, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#include "client/linux/dump_writer_common/thread_info.h" + +#include +#include + +#include "common/linux/linux_libc_support.h" +#include "google_breakpad/common/minidump_format.h" + +namespace { + +#if defined(__i386__) +// Write a uint16_t to memory +// out: memory location to write to +// v: value to write. +void U16(void* out, uint16_t v) { + my_memcpy(out, &v, sizeof(v)); +} + +// Write a uint32_t to memory +// out: memory location to write to +// v: value to write. +void U32(void* out, uint32_t v) { + my_memcpy(out, &v, sizeof(v)); +} +#endif + +} + +namespace google_breakpad { + +#if defined(__i386__) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return regs.eip; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { + out->context_flags = MD_CONTEXT_X86_ALL; + + out->dr0 = dregs[0]; + out->dr1 = dregs[1]; + out->dr2 = dregs[2]; + out->dr3 = dregs[3]; + // 4 and 5 deliberatly omitted because they aren't included in the minidump + // format. + out->dr6 = dregs[6]; + out->dr7 = dregs[7]; + + out->gs = regs.xgs; + out->fs = regs.xfs; + out->es = regs.xes; + out->ds = regs.xds; + + out->edi = regs.edi; + out->esi = regs.esi; + out->ebx = regs.ebx; + out->edx = regs.edx; + out->ecx = regs.ecx; + out->eax = regs.eax; + + out->ebp = regs.ebp; + out->eip = regs.eip; + out->cs = regs.xcs; + out->eflags = regs.eflags; + out->esp = regs.esp; + out->ss = regs.xss; + + out->float_save.control_word = fpregs.cwd; + out->float_save.status_word = fpregs.swd; + out->float_save.tag_word = fpregs.twd; + out->float_save.error_offset = fpregs.fip; + out->float_save.error_selector = fpregs.fcs; + out->float_save.data_offset = fpregs.foo; + out->float_save.data_selector = fpregs.fos; + + // 8 registers * 10 bytes per register. + my_memcpy(out->float_save.register_area, fpregs.st_space, 10 * 8); + + // This matches the Intel fpsave format. + U16(out->extended_registers + 0, fpregs.cwd); + U16(out->extended_registers + 2, fpregs.swd); + U16(out->extended_registers + 4, fpregs.twd); + U16(out->extended_registers + 6, fpxregs.fop); + U32(out->extended_registers + 8, fpxregs.fip); + U16(out->extended_registers + 12, fpxregs.fcs); + U32(out->extended_registers + 16, fpregs.foo); + U16(out->extended_registers + 20, fpregs.fos); + U32(out->extended_registers + 24, fpxregs.mxcsr); + + my_memcpy(out->extended_registers + 32, &fpxregs.st_space, 128); + my_memcpy(out->extended_registers + 160, &fpxregs.xmm_space, 128); +} + +#elif defined(__x86_64) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return regs.rip; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { + out->context_flags = MD_CONTEXT_AMD64_FULL | + MD_CONTEXT_AMD64_SEGMENTS; + + out->cs = regs.cs; + + out->ds = regs.ds; + out->es = regs.es; + out->fs = regs.fs; + out->gs = regs.gs; + + out->ss = regs.ss; + out->eflags = regs.eflags; + + out->dr0 = dregs[0]; + out->dr1 = dregs[1]; + out->dr2 = dregs[2]; + out->dr3 = dregs[3]; + // 4 and 5 deliberatly omitted because they aren't included in the minidump + // format. + out->dr6 = dregs[6]; + out->dr7 = dregs[7]; + + out->rax = regs.rax; + out->rcx = regs.rcx; + out->rdx = regs.rdx; + out->rbx = regs.rbx; + + out->rsp = regs.rsp; + + out->rbp = regs.rbp; + out->rsi = regs.rsi; + out->rdi = regs.rdi; + out->r8 = regs.r8; + out->r9 = regs.r9; + out->r10 = regs.r10; + out->r11 = regs.r11; + out->r12 = regs.r12; + out->r13 = regs.r13; + out->r14 = regs.r14; + out->r15 = regs.r15; + + out->rip = regs.rip; + + out->flt_save.control_word = fpregs.cwd; + out->flt_save.status_word = fpregs.swd; + out->flt_save.tag_word = fpregs.ftw; + out->flt_save.error_opcode = fpregs.fop; + out->flt_save.error_offset = fpregs.rip; + out->flt_save.error_selector = 0; // We don't have this. + out->flt_save.data_offset = fpregs.rdp; + out->flt_save.data_selector = 0; // We don't have this. + out->flt_save.mx_csr = fpregs.mxcsr; + out->flt_save.mx_csr_mask = fpregs.mxcr_mask; + + my_memcpy(&out->flt_save.float_registers, &fpregs.st_space, 8 * 16); + my_memcpy(&out->flt_save.xmm_registers, &fpregs.xmm_space, 16 * 16); +} + +#elif defined(__ARM_EABI__) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return regs.uregs[15]; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { + out->context_flags = MD_CONTEXT_ARM_FULL; + + for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i) + out->iregs[i] = regs.uregs[i]; + // No CPSR register in ThreadInfo(it's not accessible via ptrace) + out->cpsr = 0; +#if !defined(__ANDROID__) + out->float_save.fpscr = fpregs.fpsr | + (static_cast(fpregs.fpcr) << 32); + // TODO: sort this out, actually collect floating point registers + my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); + my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); +#endif +} + +#elif defined(__aarch64__) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return regs.pc; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { + out->context_flags = MD_CONTEXT_ARM64_FULL; + + out->cpsr = static_cast(regs.pstate); + for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i) + out->iregs[i] = regs.regs[i]; + out->iregs[MD_CONTEXT_ARM64_REG_SP] = regs.sp; + out->iregs[MD_CONTEXT_ARM64_REG_PC] = regs.pc; + + out->float_save.fpsr = fpregs.fpsr; + out->float_save.fpcr = fpregs.fpcr; + my_memcpy(&out->float_save.regs, &fpregs.vregs, + MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16); +} + +#elif defined(__mips__) + +uintptr_t ThreadInfo::GetInstructionPointer() const { + return mcontext.pc; +} + +void ThreadInfo::FillCPUContext(RawContextCPU* out) const { + out->context_flags = MD_CONTEXT_MIPS_FULL; + + for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) + out->iregs[i] = mcontext.gregs[i]; + + out->mdhi = mcontext.mdhi; + out->mdlo = mcontext.mdlo; + out->dsp_control = mcontext.dsp; + + out->hi[0] = mcontext.hi1; + out->lo[0] = mcontext.lo1; + out->hi[1] = mcontext.hi2; + out->lo[1] = mcontext.lo2; + out->hi[2] = mcontext.hi3; + out->lo[2] = mcontext.lo3; + + out->epc = mcontext.pc; + out->badvaddr = 0; // Not stored in mcontext + out->status = 0; // Not stored in mcontext + out->cause = 0; // Not stored in mcontext + + for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) + out->float_save.regs[i] = mcontext.fpregs.fp_r.fp_fregs[i]._fp_fregs; + + out->float_save.fpcsr = mcontext.fpc_csr; +#if _MIPS_SIM == _ABIO32 + out->float_save.fir = mcontext.fpc_eir; +#endif +} +#endif // __mips__ + +void ThreadInfo::GetGeneralPurposeRegisters(void** gp_regs, size_t* size) { + assert(gp_regs || size); +#if defined(__mips__) + if (gp_regs) + *gp_regs = mcontext.gregs; + if (size) + *size = sizeof(mcontext.gregs); +#else + if (gp_regs) + *gp_regs = ®s; + if (size) + *size = sizeof(regs); +#endif +} + +void ThreadInfo::GetFloatingPointRegisters(void** fp_regs, size_t* size) { + assert(fp_regs || size); +#if defined(__mips__) + if (fp_regs) + *fp_regs = &mcontext.fpregs; + if (size) + *size = sizeof(mcontext.fpregs); +#else + if (fp_regs) + *fp_regs = &fpregs; + if (size) + *size = sizeof(fpregs); +#endif +} + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/thread_info.h b/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/thread_info.h new file mode 100644 index 00000000..99093d2e --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/thread_info.h @@ -0,0 +1,91 @@ +// Copyright (c) 2014, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_ +#define CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_ + +#include +#include + +#include "client/linux/dump_writer_common/raw_context_cpu.h" +#include "common/memory.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +#if defined(__i386) || defined(__x86_64) +typedef __typeof__(((struct user*) 0)->u_debugreg[0]) debugreg_t; +#endif + +// We produce one of these structures for each thread in the crashed process. +struct ThreadInfo { + pid_t tgid; // thread group id + pid_t ppid; // parent process + + uintptr_t stack_pointer; // thread stack pointer + + +#if defined(__i386) || defined(__x86_64) + user_regs_struct regs; + user_fpregs_struct fpregs; + static const unsigned kNumDebugRegisters = 8; + debugreg_t dregs[8]; +#if defined(__i386) + user_fpxregs_struct fpxregs; +#endif // defined(__i386) + +#elif defined(__ARM_EABI__) + // Mimicking how strace does this(see syscall.c, search for GETREGS) + struct user_regs regs; + struct user_fpregs fpregs; +#elif defined(__aarch64__) + // Use the structures defined in + struct user_regs_struct regs; + struct user_fpsimd_struct fpregs; +#elif defined(__mips__) + // Use the structure defined in . + mcontext_t mcontext; +#endif + + // Returns the instruction pointer (platform-dependent impl.). + uintptr_t GetInstructionPointer() const; + + // Fills a RawContextCPU using the context in the ThreadInfo object. + void FillCPUContext(RawContextCPU* out) const; + + // Returns the pointer and size of general purpose register area. + void GetGeneralPurposeRegisters(void** gp_regs, size_t* size); + + // Returns the pointer and size of float point register area. + void GetFloatingPointRegisters(void** fp_regs, size_t* size); +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_THREAD_INFO_H_ diff --git a/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/ucontext_reader.cc b/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/ucontext_reader.cc new file mode 100644 index 00000000..d37fdeb0 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/ucontext_reader.cc @@ -0,0 +1,253 @@ +// Copyright (c) 2014, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#include "client/linux/dump_writer_common/ucontext_reader.h" + +#include "common/linux/linux_libc_support.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +// Minidump defines register structures which are different from the raw +// structures which we get from the kernel. These are platform specific +// functions to juggle the ucontext and user structures into minidump format. + +#if defined(__i386__) + +uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { + return uc->uc_mcontext.gregs[REG_ESP]; +} + +uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { + return uc->uc_mcontext.gregs[REG_EIP]; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc, + const struct _libc_fpstate* fp) { + const greg_t* regs = uc->uc_mcontext.gregs; + + out->context_flags = MD_CONTEXT_X86_FULL | + MD_CONTEXT_X86_FLOATING_POINT; + + out->gs = regs[REG_GS]; + out->fs = regs[REG_FS]; + out->es = regs[REG_ES]; + out->ds = regs[REG_DS]; + + out->edi = regs[REG_EDI]; + out->esi = regs[REG_ESI]; + out->ebx = regs[REG_EBX]; + out->edx = regs[REG_EDX]; + out->ecx = regs[REG_ECX]; + out->eax = regs[REG_EAX]; + + out->ebp = regs[REG_EBP]; + out->eip = regs[REG_EIP]; + out->cs = regs[REG_CS]; + out->eflags = regs[REG_EFL]; + out->esp = regs[REG_UESP]; + out->ss = regs[REG_SS]; + + out->float_save.control_word = fp->cw; + out->float_save.status_word = fp->sw; + out->float_save.tag_word = fp->tag; + out->float_save.error_offset = fp->ipoff; + out->float_save.error_selector = fp->cssel; + out->float_save.data_offset = fp->dataoff; + out->float_save.data_selector = fp->datasel; + + // 8 registers * 10 bytes per register. + my_memcpy(out->float_save.register_area, fp->_st, 10 * 8); +} + +#elif defined(__x86_64) + +uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { + return uc->uc_mcontext.gregs[REG_RSP]; +} + +uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { + return uc->uc_mcontext.gregs[REG_RIP]; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc, + const struct _libc_fpstate* fpregs) { + const greg_t* regs = uc->uc_mcontext.gregs; + + out->context_flags = MD_CONTEXT_AMD64_FULL; + + out->cs = regs[REG_CSGSFS] & 0xffff; + + out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff; + out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff; + + out->eflags = regs[REG_EFL]; + + out->rax = regs[REG_RAX]; + out->rcx = regs[REG_RCX]; + out->rdx = regs[REG_RDX]; + out->rbx = regs[REG_RBX]; + + out->rsp = regs[REG_RSP]; + out->rbp = regs[REG_RBP]; + out->rsi = regs[REG_RSI]; + out->rdi = regs[REG_RDI]; + out->r8 = regs[REG_R8]; + out->r9 = regs[REG_R9]; + out->r10 = regs[REG_R10]; + out->r11 = regs[REG_R11]; + out->r12 = regs[REG_R12]; + out->r13 = regs[REG_R13]; + out->r14 = regs[REG_R14]; + out->r15 = regs[REG_R15]; + + out->rip = regs[REG_RIP]; + + out->flt_save.control_word = fpregs->cwd; + out->flt_save.status_word = fpregs->swd; + out->flt_save.tag_word = fpregs->ftw; + out->flt_save.error_opcode = fpregs->fop; + out->flt_save.error_offset = fpregs->rip; + out->flt_save.data_offset = fpregs->rdp; + out->flt_save.error_selector = 0; // We don't have this. + out->flt_save.data_selector = 0; // We don't have this. + out->flt_save.mx_csr = fpregs->mxcsr; + out->flt_save.mx_csr_mask = fpregs->mxcr_mask; + my_memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16); + my_memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16); +} + +#elif defined(__ARM_EABI__) + +uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { + return uc->uc_mcontext.arm_sp; +} + +uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { + return uc->uc_mcontext.arm_pc; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) { + out->context_flags = MD_CONTEXT_ARM_FULL; + + out->iregs[0] = uc->uc_mcontext.arm_r0; + out->iregs[1] = uc->uc_mcontext.arm_r1; + out->iregs[2] = uc->uc_mcontext.arm_r2; + out->iregs[3] = uc->uc_mcontext.arm_r3; + out->iregs[4] = uc->uc_mcontext.arm_r4; + out->iregs[5] = uc->uc_mcontext.arm_r5; + out->iregs[6] = uc->uc_mcontext.arm_r6; + out->iregs[7] = uc->uc_mcontext.arm_r7; + out->iregs[8] = uc->uc_mcontext.arm_r8; + out->iregs[9] = uc->uc_mcontext.arm_r9; + out->iregs[10] = uc->uc_mcontext.arm_r10; + + out->iregs[11] = uc->uc_mcontext.arm_fp; + out->iregs[12] = uc->uc_mcontext.arm_ip; + out->iregs[13] = uc->uc_mcontext.arm_sp; + out->iregs[14] = uc->uc_mcontext.arm_lr; + out->iregs[15] = uc->uc_mcontext.arm_pc; + + out->cpsr = uc->uc_mcontext.arm_cpsr; + + // TODO: fix this after fixing ExceptionHandler + out->float_save.fpscr = 0; + my_memset(&out->float_save.regs, 0, sizeof(out->float_save.regs)); + my_memset(&out->float_save.extra, 0, sizeof(out->float_save.extra)); +} + +#elif defined(__aarch64__) + +uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { + return uc->uc_mcontext.sp; +} + +uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { + return uc->uc_mcontext.pc; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc, + const struct fpsimd_context* fpregs) { + out->context_flags = MD_CONTEXT_ARM64_FULL; + + out->cpsr = static_cast(uc->uc_mcontext.pstate); + for (int i = 0; i < MD_CONTEXT_ARM64_REG_SP; ++i) + out->iregs[i] = uc->uc_mcontext.regs[i]; + out->iregs[MD_CONTEXT_ARM64_REG_SP] = uc->uc_mcontext.sp; + out->iregs[MD_CONTEXT_ARM64_REG_PC] = uc->uc_mcontext.pc; + + out->float_save.fpsr = fpregs->fpsr; + out->float_save.fpcr = fpregs->fpcr; + my_memcpy(&out->float_save.regs, &fpregs->vregs, + MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT * 16); +} + +#elif defined(__mips__) + +uintptr_t UContextReader::GetStackPointer(const struct ucontext* uc) { + return uc->uc_mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]; +} + +uintptr_t UContextReader::GetInstructionPointer(const struct ucontext* uc) { + return uc->uc_mcontext.pc; +} + +void UContextReader::FillCPUContext(RawContextCPU *out, const ucontext *uc) { + out->context_flags = MD_CONTEXT_MIPS_FULL; + + for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i) + out->iregs[i] = uc->uc_mcontext.gregs[i]; + + out->mdhi = uc->uc_mcontext.mdhi; + out->mdlo = uc->uc_mcontext.mdlo; + + out->hi[0] = uc->uc_mcontext.hi1; + out->hi[1] = uc->uc_mcontext.hi2; + out->hi[2] = uc->uc_mcontext.hi3; + out->lo[0] = uc->uc_mcontext.lo1; + out->lo[1] = uc->uc_mcontext.lo2; + out->lo[2] = uc->uc_mcontext.lo3; + out->dsp_control = uc->uc_mcontext.dsp; + + out->epc = uc->uc_mcontext.pc; + out->badvaddr = 0; // Not reported in signal context. + out->status = 0; // Not reported in signal context. + out->cause = 0; // Not reported in signal context. + + for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i) + out->float_save.regs[i] = uc->uc_mcontext.fpregs.fp_r.fp_dregs[i]; + + out->float_save.fpcsr = uc->uc_mcontext.fpc_csr; +#if _MIPS_SIM == _ABIO32 + out->float_save.fir = uc->uc_mcontext.fpc_eir; // Unused. +#endif +} +#endif + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/ucontext_reader.h b/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/ucontext_reader.h new file mode 100644 index 00000000..b6e77b4b --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/dump_writer_common/ucontext_reader.h @@ -0,0 +1,64 @@ +// Copyright (c) 2014, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H +#define CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H + +#include +#include + +#include "client/linux/dump_writer_common/raw_context_cpu.h" +#include "common/memory.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +// Wraps platform-dependent implementations of accessors to ucontext structs. +struct UContextReader { + static uintptr_t GetStackPointer(const struct ucontext* uc); + + static uintptr_t GetInstructionPointer(const struct ucontext* uc); + + // Juggle a arch-specific ucontext into a minidump format + // out: the minidump structure + // info: the collection of register structures. +#if defined(__i386__) || defined(__x86_64) + static void FillCPUContext(RawContextCPU *out, const ucontext *uc, + const struct _libc_fpstate* fp); +#elif defined(__aarch64__) + static void FillCPUContext(RawContextCPU *out, const ucontext *uc, + const struct fpsimd_context* fpregs); +#else + static void FillCPUContext(RawContextCPU *out, const ucontext *uc); +#endif +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_DUMP_WRITER_COMMON_UCONTEXT_READER_H diff --git a/TMessagesProj/jni/breakpad/client/linux/handler/exception_handler.cc b/TMessagesProj/jni/breakpad/client/linux/handler/exception_handler.cc new file mode 100644 index 00000000..9b20fe25 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/handler/exception_handler.cc @@ -0,0 +1,754 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// The ExceptionHandler object installs signal handlers for a number of +// signals. We rely on the signal handler running on the thread which crashed +// in order to identify it. This is true of the synchronous signals (SEGV etc), +// but not true of ABRT. Thus, if you send ABRT to yourself in a program which +// uses ExceptionHandler, you need to use tgkill to direct it to the current +// thread. +// +// The signal flow looks like this: +// +// SignalHandler (uses a global stack of ExceptionHandler objects to find +// | one to handle the signal. If the first rejects it, try +// | the second etc...) +// V +// HandleSignal ----------------------------| (clones a new process which +// | | shares an address space with +// (wait for cloned | the crashed process. This +// process) | allows us to ptrace the crashed +// | | process) +// V V +// (set signal handler to ThreadEntry (static function to bounce +// SIG_DFL and rethrow, | back into the object) +// killing the crashed | +// process) V +// DoDump (writes minidump) +// | +// V +// sys_exit +// + +// This code is a little fragmented. Different functions of the ExceptionHandler +// class run in a number of different contexts. Some of them run in a normal +// context and are easy to code, others run in a compromised context and the +// restrictions at the top of minidump_writer.cc apply: no libc and use the +// alternative malloc. Each function should have comment above it detailing the +// context which it runs in. + +#include "client/linux/handler/exception_handler.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "common/basictypes.h" +#include "common/linux/linux_libc_support.h" +#include "common/memory.h" +#include "client/linux/log/log.h" +#include "client/linux/microdump_writer/microdump_writer.h" +#include "client/linux/minidump_writer/linux_dumper.h" +#include "client/linux/minidump_writer/minidump_writer.h" +#include "common/linux/eintr_wrapper.h" +#include "third_party/lss/linux_syscall_support.h" + +#if defined(__ANDROID__) +#include "linux/sched.h" +#endif + +#ifndef PR_SET_PTRACER +#define PR_SET_PTRACER 0x59616d61 +#endif + +// A wrapper for the tgkill syscall: send a signal to a specific thread. +static int tgkill(pid_t tgid, pid_t tid, int sig) { + return syscall(__NR_tgkill, tgid, tid, sig); + return 0; +} + +namespace google_breakpad { + +namespace { +// The list of signals which we consider to be crashes. The default action for +// all these signals must be Core (see man 7 signal) because we rethrow the +// signal after handling it and expect that it'll be fatal. +const int kExceptionSignals[] = { + SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS +}; +const int kNumHandledSignals = + sizeof(kExceptionSignals) / sizeof(kExceptionSignals[0]); +struct sigaction old_handlers[kNumHandledSignals]; +bool handlers_installed = false; + +// InstallAlternateStackLocked will store the newly installed stack in new_stack +// and (if it exists) the previously installed stack in old_stack. +stack_t old_stack; +stack_t new_stack; +bool stack_installed = false; + +// Create an alternative stack to run the signal handlers on. This is done since +// the signal might have been caused by a stack overflow. +// Runs before crashing: normal context. +void InstallAlternateStackLocked() { + if (stack_installed) + return; + + memset(&old_stack, 0, sizeof(old_stack)); + memset(&new_stack, 0, sizeof(new_stack)); + + // SIGSTKSZ may be too small to prevent the signal handlers from overrunning + // the alternative stack. Ensure that the size of the alternative stack is + // large enough. + static const unsigned kSigStackSize = std::max(16384, SIGSTKSZ); + + // Only set an alternative stack if there isn't already one, or if the current + // one is too small. + if (sys_sigaltstack(NULL, &old_stack) == -1 || !old_stack.ss_sp || + old_stack.ss_size < kSigStackSize) { + new_stack.ss_sp = calloc(1, kSigStackSize); + new_stack.ss_size = kSigStackSize; + + if (sys_sigaltstack(&new_stack, NULL) == -1) { + free(new_stack.ss_sp); + return; + } + stack_installed = true; + } +} + +// Runs before crashing: normal context. +void RestoreAlternateStackLocked() { + if (!stack_installed) + return; + + stack_t current_stack; + if (sys_sigaltstack(NULL, ¤t_stack) == -1) + return; + + // Only restore the old_stack if the current alternative stack is the one + // installed by the call to InstallAlternateStackLocked. + if (current_stack.ss_sp == new_stack.ss_sp) { + if (old_stack.ss_sp) { + if (sys_sigaltstack(&old_stack, NULL) == -1) + return; + } else { + stack_t disable_stack; + disable_stack.ss_flags = SS_DISABLE; + if (sys_sigaltstack(&disable_stack, NULL) == -1) + return; + } + } + + free(new_stack.ss_sp); + stack_installed = false; +} + +void InstallDefaultHandler(int sig) { +#if defined(__ANDROID__) + // Android L+ expose signal and sigaction symbols that override the system + // ones. There is a bug in these functions where a request to set the handler + // to SIG_DFL is ignored. In that case, an infinite loop is entered as the + // signal is repeatedly sent to breakpad's signal handler. + // To work around this, directly call the system's sigaction. + struct kernel_sigaction sa; + memset(&sa, 0, sizeof(sa)); + sys_sigemptyset(&sa.sa_mask); + sa.sa_handler_ = SIG_DFL; + sa.sa_flags = SA_RESTART; + sys_rt_sigaction(sig, &sa, NULL, sizeof(kernel_sigset_t)); +#else + signal(sig, SIG_DFL); +#endif +} + +// The global exception handler stack. This is needed because there may exist +// multiple ExceptionHandler instances in a process. Each will have itself +// registered in this stack. +std::vector* g_handler_stack_ = NULL; +pthread_mutex_t g_handler_stack_mutex_ = PTHREAD_MUTEX_INITIALIZER; + +} // namespace + +// Runs before crashing: normal context. +ExceptionHandler::ExceptionHandler(const MinidumpDescriptor& descriptor, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + bool install_handler, + const int server_fd) + : filter_(filter), + callback_(callback), + callback_context_(callback_context), + minidump_descriptor_(descriptor), + crash_handler_(NULL) { + if (server_fd >= 0) + crash_generation_client_.reset(CrashGenerationClient::TryCreate(server_fd)); + + if (!IsOutOfProcess() && !minidump_descriptor_.IsFD() && + !minidump_descriptor_.IsMicrodumpOnConsole()) + minidump_descriptor_.UpdatePath(); + +#if defined(__ANDROID__) + if (minidump_descriptor_.IsMicrodumpOnConsole()) + logger::initializeCrashLogWriter(); +#endif + + pthread_mutex_lock(&g_handler_stack_mutex_); + if (!g_handler_stack_) + g_handler_stack_ = new std::vector; + if (install_handler) { + InstallAlternateStackLocked(); + InstallHandlersLocked(); + } + g_handler_stack_->push_back(this); + pthread_mutex_unlock(&g_handler_stack_mutex_); +} + +// Runs before crashing: normal context. +ExceptionHandler::~ExceptionHandler() { + pthread_mutex_lock(&g_handler_stack_mutex_); + std::vector::iterator handler = + std::find(g_handler_stack_->begin(), g_handler_stack_->end(), this); + g_handler_stack_->erase(handler); + if (g_handler_stack_->empty()) { + delete g_handler_stack_; + g_handler_stack_ = NULL; + RestoreAlternateStackLocked(); + RestoreHandlersLocked(); + } + pthread_mutex_unlock(&g_handler_stack_mutex_); +} + +// Runs before crashing: normal context. +// static +bool ExceptionHandler::InstallHandlersLocked() { + if (handlers_installed) + return false; + + // Fail if unable to store all the old handlers. + for (int i = 0; i < kNumHandledSignals; ++i) { + if (sigaction(kExceptionSignals[i], NULL, &old_handlers[i]) == -1) + return false; + } + + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + + // Mask all exception signals when we're handling one of them. + for (int i = 0; i < kNumHandledSignals; ++i) + sigaddset(&sa.sa_mask, kExceptionSignals[i]); + + sa.sa_sigaction = SignalHandler; + sa.sa_flags = SA_ONSTACK | SA_SIGINFO; + + for (int i = 0; i < kNumHandledSignals; ++i) { + if (sigaction(kExceptionSignals[i], &sa, NULL) == -1) { + // At this point it is impractical to back out changes, and so failure to + // install a signal is intentionally ignored. + } + } + handlers_installed = true; + return true; +} + +// This function runs in a compromised context: see the top of the file. +// Runs on the crashing thread. +// static +void ExceptionHandler::RestoreHandlersLocked() { + if (!handlers_installed) + return; + + for (int i = 0; i < kNumHandledSignals; ++i) { + if (sigaction(kExceptionSignals[i], &old_handlers[i], NULL) == -1) { + InstallDefaultHandler(kExceptionSignals[i]); + } + } + handlers_installed = false; +} + +// void ExceptionHandler::set_crash_handler(HandlerCallback callback) { +// crash_handler_ = callback; +// } + +// This function runs in a compromised context: see the top of the file. +// Runs on the crashing thread. +// static +void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { + // All the exception signals are blocked at this point. + pthread_mutex_lock(&g_handler_stack_mutex_); + + // Sometimes, Breakpad runs inside a process where some other buggy code + // saves and restores signal handlers temporarily with 'signal' + // instead of 'sigaction'. This loses the SA_SIGINFO flag associated + // with this function. As a consequence, the values of 'info' and 'uc' + // become totally bogus, generally inducing a crash. + // + // The following code tries to detect this case. When it does, it + // resets the signal handlers with sigaction + SA_SIGINFO and returns. + // This forces the signal to be thrown again, but this time the kernel + // will call the function with the right arguments. + struct sigaction cur_handler; + if (sigaction(sig, NULL, &cur_handler) == 0 && + (cur_handler.sa_flags & SA_SIGINFO) == 0) { + // Reset signal handler with the right flags. + sigemptyset(&cur_handler.sa_mask); + sigaddset(&cur_handler.sa_mask, sig); + + cur_handler.sa_sigaction = SignalHandler; + cur_handler.sa_flags = SA_ONSTACK | SA_SIGINFO; + + if (sigaction(sig, &cur_handler, NULL) == -1) { + // When resetting the handler fails, try to reset the + // default one to avoid an infinite loop here. + InstallDefaultHandler(sig); + } + pthread_mutex_unlock(&g_handler_stack_mutex_); + return; + } + + bool handled = false; + for (int i = g_handler_stack_->size() - 1; !handled && i >= 0; --i) { + handled = (*g_handler_stack_)[i]->HandleSignal(sig, info, uc); + } + + // Upon returning from this signal handler, sig will become unmasked and then + // it will be retriggered. If one of the ExceptionHandlers handled it + // successfully, restore the default handler. Otherwise, restore the + // previously installed handler. Then, when the signal is retriggered, it will + // be delivered to the appropriate handler. + if (handled) { + InstallDefaultHandler(sig); + } else { + RestoreHandlersLocked(); + } + + pthread_mutex_unlock(&g_handler_stack_mutex_); + + // info->si_code <= 0 iff SI_FROMUSER (SI_FROMKERNEL otherwise). + if (info->si_code <= 0 || sig == SIGABRT) { + // This signal was triggered by somebody sending us the signal with kill(). + // In order to retrigger it, we have to queue a new signal by calling + // kill() ourselves. The special case (si_pid == 0 && sig == SIGABRT) is + // due to the kernel sending a SIGABRT from a user request via SysRQ. + if (tgkill(getpid(), syscall(__NR_gettid), sig) < 0) { + // If we failed to kill ourselves (e.g. because a sandbox disallows us + // to do so), we instead resort to terminating our process. This will + // result in an incorrect exit code. + _exit(1); + } + } else { + // This was a synchronous signal triggered by a hard fault (e.g. SIGSEGV). + // No need to reissue the signal. It will automatically trigger again, + // when we return from the signal handler. + } +} + +struct ThreadArgument { + pid_t pid; // the crashing process + const MinidumpDescriptor* minidump_descriptor; + ExceptionHandler* handler; + const void* context; // a CrashContext structure + size_t context_size; +}; + +// This is the entry function for the cloned process. We are in a compromised +// context here: see the top of the file. +// static +int ExceptionHandler::ThreadEntry(void *arg) { + const ThreadArgument *thread_arg = reinterpret_cast(arg); + + // Block here until the crashing process unblocks us when + // we're allowed to use ptrace + thread_arg->handler->WaitForContinueSignal(); + + return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context, + thread_arg->context_size) == false; +} + +// This function runs in a compromised context: see the top of the file. +// Runs on the crashing thread. +bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) { + if (filter_ && !filter_(callback_context_)) + return false; + + // Allow ourselves to be dumped if the signal is trusted. + bool signal_trusted = info->si_code > 0; + bool signal_pid_trusted = info->si_code == SI_USER || + info->si_code == SI_TKILL; + if (signal_trusted || (signal_pid_trusted && info->si_pid == getpid())) { + sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); + } + CrashContext context; + // Fill in all the holes in the struct to make Valgrind happy. + memset(&context, 0, sizeof(context)); + memcpy(&context.siginfo, info, sizeof(siginfo_t)); + memcpy(&context.context, uc, sizeof(struct ucontext)); +#if defined(__aarch64__) + struct ucontext *uc_ptr = (struct ucontext*)uc; + struct fpsimd_context *fp_ptr = + (struct fpsimd_context*)&uc_ptr->uc_mcontext.__reserved; + if (fp_ptr->head.magic == FPSIMD_MAGIC) { + memcpy(&context.float_state, fp_ptr, sizeof(context.float_state)); + } +#elif !defined(__ARM_EABI__) && !defined(__mips__) + // FP state is not part of user ABI on ARM Linux. + // In case of MIPS Linux FP state is already part of struct ucontext + // and 'float_state' is not a member of CrashContext. + struct ucontext *uc_ptr = (struct ucontext*)uc; + if (uc_ptr->uc_mcontext.fpregs) { + memcpy(&context.float_state, + uc_ptr->uc_mcontext.fpregs, + sizeof(context.float_state)); + } +#endif + context.tid = syscall(__NR_gettid); + if (crash_handler_ != NULL) { + if (crash_handler_(&context, sizeof(context), callback_context_)) { + return true; + } + } + return GenerateDump(&context); +} + +// This is a public interface to HandleSignal that allows the client to +// generate a crash dump. This function may run in a compromised context. +bool ExceptionHandler::SimulateSignalDelivery(int sig) { + siginfo_t siginfo = {}; + // Mimic a trusted signal to allow tracing the process (see + // ExceptionHandler::HandleSignal(). + siginfo.si_code = SI_USER; + siginfo.si_pid = getpid(); + struct ucontext context; + getcontext(&context); + return HandleSignal(sig, &siginfo, &context); +} + +// This function may run in a compromised context: see the top of the file. +bool ExceptionHandler::GenerateDump(CrashContext *context) { + if (IsOutOfProcess()) + return crash_generation_client_->RequestDump(context, sizeof(*context)); + + // Allocating too much stack isn't a problem, and better to err on the side + // of caution than smash it into random locations. + static const unsigned kChildStackSize = 16000; + PageAllocator allocator; + uint8_t* stack = reinterpret_cast(allocator.Alloc(kChildStackSize)); + if (!stack) + return false; + // clone() needs the top-most address. (scrub just to be safe) + stack += kChildStackSize; + my_memset(stack - 16, 0, 16); + + ThreadArgument thread_arg; + thread_arg.handler = this; + thread_arg.minidump_descriptor = &minidump_descriptor_; + thread_arg.pid = getpid(); + thread_arg.context = context; + thread_arg.context_size = sizeof(*context); + + // We need to explicitly enable ptrace of parent processes on some + // kernels, but we need to know the PID of the cloned process before we + // can do this. Create a pipe here which we can use to block the + // cloned process after creating it, until we have explicitly enabled ptrace + if (sys_pipe(fdes) == -1) { + // Creating the pipe failed. We'll log an error but carry on anyway, + // as we'll probably still get a useful crash report. All that will happen + // is the write() and read() calls will fail with EBADF + static const char no_pipe_msg[] = "ExceptionHandler::GenerateDump " + "sys_pipe failed:"; + logger::write(no_pipe_msg, sizeof(no_pipe_msg) - 1); + logger::write(strerror(errno), strlen(strerror(errno))); + logger::write("\n", 1); + + // Ensure fdes[0] and fdes[1] are invalid file descriptors. + fdes[0] = fdes[1] = -1; + } + + const pid_t child = sys_clone( + ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED, + &thread_arg, NULL, NULL, NULL); + if (child == -1) { + sys_close(fdes[0]); + sys_close(fdes[1]); + return false; + } + + // Allow the child to ptrace us + sys_prctl(PR_SET_PTRACER, child, 0, 0, 0); + SendContinueSignalToChild(); + int status; + const int r = HANDLE_EINTR(sys_waitpid(child, &status, __WALL)); + + sys_close(fdes[0]); + sys_close(fdes[1]); + + if (r == -1) { + static const char msg[] = "ExceptionHandler::GenerateDump waitpid failed:"; + logger::write(msg, sizeof(msg) - 1); + logger::write(strerror(errno), strlen(strerror(errno))); + logger::write("\n", 1); + } + + bool success = r != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0; + if (callback_) + success = callback_(minidump_descriptor_, callback_context_, success); + return success; +} + +// This function runs in a compromised context: see the top of the file. +void ExceptionHandler::SendContinueSignalToChild() { + static const char okToContinueMessage = 'a'; + int r; + r = HANDLE_EINTR(sys_write(fdes[1], &okToContinueMessage, sizeof(char))); + if (r == -1) { + static const char msg[] = "ExceptionHandler::SendContinueSignalToChild " + "sys_write failed:"; + logger::write(msg, sizeof(msg) - 1); + logger::write(strerror(errno), strlen(strerror(errno))); + logger::write("\n", 1); + } +} + +// This function runs in a compromised context: see the top of the file. +// Runs on the cloned process. +void ExceptionHandler::WaitForContinueSignal() { + int r; + char receivedMessage; + r = HANDLE_EINTR(sys_read(fdes[0], &receivedMessage, sizeof(char))); + if (r == -1) { + static const char msg[] = "ExceptionHandler::WaitForContinueSignal " + "sys_read failed:"; + logger::write(msg, sizeof(msg) - 1); + logger::write(strerror(errno), strlen(strerror(errno))); + logger::write("\n", 1); + } +} + +// This function runs in a compromised context: see the top of the file. +// Runs on the cloned process. +bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context, + size_t context_size) { + if (minidump_descriptor_.IsMicrodumpOnConsole()) { + return google_breakpad::WriteMicrodump( + crashing_process, + context, + context_size, + mapping_list_, + minidump_descriptor_.microdump_build_fingerprint(), + minidump_descriptor_.microdump_product_info()); + } + if (minidump_descriptor_.IsFD()) { + return google_breakpad::WriteMinidump(minidump_descriptor_.fd(), + minidump_descriptor_.size_limit(), + crashing_process, + context, + context_size, + mapping_list_, + app_memory_list_); + } + return google_breakpad::WriteMinidump(minidump_descriptor_.path(), + minidump_descriptor_.size_limit(), + crashing_process, + context, + context_size, + mapping_list_, + app_memory_list_); +} + +// static +bool ExceptionHandler::WriteMinidump(const string& dump_path, + MinidumpCallback callback, + void* callback_context) { + MinidumpDescriptor descriptor(dump_path); + ExceptionHandler eh(descriptor, NULL, callback, callback_context, false, -1); + return eh.WriteMinidump(); +} + +// In order to making using EBP to calculate the desired value for ESP +// a valid operation, ensure that this function is compiled with a +// frame pointer using the following attribute. This attribute +// is supported on GCC but not on clang. +#if defined(__i386__) && defined(__GNUC__) && !defined(__clang__) +__attribute__((optimize("no-omit-frame-pointer"))) +#endif +bool ExceptionHandler::WriteMinidump() { + if (!IsOutOfProcess() && !minidump_descriptor_.IsFD() && + !minidump_descriptor_.IsMicrodumpOnConsole()) { + // Update the path of the minidump so that this can be called multiple times + // and new files are created for each minidump. This is done before the + // generation happens, as clients may want to access the MinidumpDescriptor + // after this call to find the exact path to the minidump file. + minidump_descriptor_.UpdatePath(); + } else if (minidump_descriptor_.IsFD()) { + // Reposition the FD to its beginning and resize it to get rid of the + // previous minidump info. + lseek(minidump_descriptor_.fd(), 0, SEEK_SET); + ignore_result(ftruncate(minidump_descriptor_.fd(), 0)); + } + + // Allow this process to be dumped. + sys_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); + + CrashContext context; + int getcontext_result = getcontext(&context.context); + if (getcontext_result) + return false; + +#if defined(__i386__) + // In CPUFillFromUContext in minidumpwriter.cc the stack pointer is retrieved + // from REG_UESP instead of from REG_ESP. REG_UESP is the user stack pointer + // and it only makes sense when running in kernel mode with a different stack + // pointer. When WriteMiniDump is called during normal processing REG_UESP is + // zero which leads to bad minidump files. + if (!context.context.uc_mcontext.gregs[REG_UESP]) { + // If REG_UESP is set to REG_ESP then that includes the stack space for the + // CrashContext object in this function, which is about 128 KB. Since the + // Linux dumper only records 32 KB of stack this would mean that nothing + // useful would be recorded. A better option is to set REG_UESP to REG_EBP, + // perhaps with a small negative offset in case there is any code that + // objects to them being equal. + context.context.uc_mcontext.gregs[REG_UESP] = + context.context.uc_mcontext.gregs[REG_EBP] - 16; + // The stack saving is based off of REG_ESP so it must be set to match the + // new REG_UESP. + context.context.uc_mcontext.gregs[REG_ESP] = + context.context.uc_mcontext.gregs[REG_UESP]; + } +#endif + +#if !defined(__ARM_EABI__) && !defined(__aarch64__) && !defined(__mips__) + // FPU state is not part of ARM EABI ucontext_t. + memcpy(&context.float_state, context.context.uc_mcontext.fpregs, + sizeof(context.float_state)); +#endif + context.tid = sys_gettid(); + + // Add an exception stream to the minidump for better reporting. + memset(&context.siginfo, 0, sizeof(context.siginfo)); + context.siginfo.si_signo = MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED; +#if defined(__i386__) + context.siginfo.si_addr = + reinterpret_cast(context.context.uc_mcontext.gregs[REG_EIP]); +#elif defined(__x86_64__) + context.siginfo.si_addr = + reinterpret_cast(context.context.uc_mcontext.gregs[REG_RIP]); +#elif defined(__arm__) + context.siginfo.si_addr = + reinterpret_cast(context.context.uc_mcontext.arm_pc); +#elif defined(__aarch64__) + context.siginfo.si_addr = + reinterpret_cast(context.context.uc_mcontext.pc); +#elif defined(__mips__) + context.siginfo.si_addr = + reinterpret_cast(context.context.uc_mcontext.pc); +#else +#error "This code has not been ported to your platform yet." +#endif + + return GenerateDump(&context); +} + +void ExceptionHandler::AddMappingInfo(const string& name, + const uint8_t identifier[sizeof(MDGUID)], + uintptr_t start_address, + size_t mapping_size, + size_t file_offset) { + MappingInfo info; + info.start_addr = start_address; + info.size = mapping_size; + info.offset = file_offset; + strncpy(info.name, name.c_str(), sizeof(info.name) - 1); + info.name[sizeof(info.name) - 1] = '\0'; + + MappingEntry mapping; + mapping.first = info; + memcpy(mapping.second, identifier, sizeof(MDGUID)); + mapping_list_.push_back(mapping); +} + +void ExceptionHandler::RegisterAppMemory(void* ptr, size_t length) { + AppMemoryList::iterator iter = + std::find(app_memory_list_.begin(), app_memory_list_.end(), ptr); + if (iter != app_memory_list_.end()) { + // Don't allow registering the same pointer twice. + return; + } + + AppMemory app_memory; + app_memory.ptr = ptr; + app_memory.length = length; + app_memory_list_.push_back(app_memory); +} + +void ExceptionHandler::UnregisterAppMemory(void* ptr) { + AppMemoryList::iterator iter = + std::find(app_memory_list_.begin(), app_memory_list_.end(), ptr); + if (iter != app_memory_list_.end()) { + app_memory_list_.erase(iter); + } +} + +// static +bool ExceptionHandler::WriteMinidumpForChild(pid_t child, + pid_t child_blamed_thread, + const string& dump_path, + MinidumpCallback callback, + void* callback_context) { + // This function is not run in a compromised context. + MinidumpDescriptor descriptor(dump_path); + descriptor.UpdatePath(); + if (!google_breakpad::WriteMinidump(descriptor.path(), + child, + child_blamed_thread)) + return false; + + return callback ? callback(descriptor, callback_context, true) : true; +} + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/client/linux/handler/exception_handler.h b/TMessagesProj/jni/breakpad/client/linux/handler/exception_handler.h new file mode 100644 index 00000000..591c3108 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/handler/exception_handler.h @@ -0,0 +1,278 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_ +#define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_ + +#include +#include +#include +#include + +#include + +#include "client/linux/crash_generation/crash_generation_client.h" +#include "client/linux/handler/minidump_descriptor.h" +#include "client/linux/minidump_writer/minidump_writer.h" +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +// ExceptionHandler +// +// ExceptionHandler can write a minidump file when an exception occurs, +// or when WriteMinidump() is called explicitly by your program. +// +// To have the exception handler write minidumps when an uncaught exception +// (crash) occurs, you should create an instance early in the execution +// of your program, and keep it around for the entire time you want to +// have crash handling active (typically, until shutdown). +// (NOTE): There should be only be one this kind of exception handler +// object per process. +// +// If you want to write minidumps without installing the exception handler, +// you can create an ExceptionHandler with install_handler set to false, +// then call WriteMinidump. You can also use this technique if you want to +// use different minidump callbacks for different call sites. +// +// In either case, a callback function is called when a minidump is written, +// which receives the full path or file descriptor of the minidump. The +// caller can collect and write additional application state to that minidump, +// and launch an external crash-reporting application. +// +// Caller should try to make the callbacks as crash-friendly as possible, +// it should avoid use heap memory allocation as much as possible. + +class ExceptionHandler { + public: + // A callback function to run before Breakpad performs any substantial + // processing of an exception. A FilterCallback is called before writing + // a minidump. |context| is the parameter supplied by the user as + // callback_context when the handler was created. + // + // If a FilterCallback returns true, Breakpad will continue processing, + // attempting to write a minidump. If a FilterCallback returns false, + // Breakpad will immediately report the exception as unhandled without + // writing a minidump, allowing another handler the opportunity to handle it. + typedef bool (*FilterCallback)(void *context); + + // A callback function to run after the minidump has been written. + // |descriptor| contains the file descriptor or file path containing the + // minidump. |context| is the parameter supplied by the user as + // callback_context when the handler was created. |succeeded| indicates + // whether a minidump file was successfully written. + // + // If an exception occurred and the callback returns true, Breakpad will + // treat the exception as fully-handled, suppressing any other handlers from + // being notified of the exception. If the callback returns false, Breakpad + // will treat the exception as unhandled, and allow another handler to handle + // it. If there are no other handlers, Breakpad will report the exception to + // the system as unhandled, allowing a debugger or native crash dialog the + // opportunity to handle the exception. Most callback implementations + // should normally return the value of |succeeded|, or when they wish to + // not report an exception of handled, false. Callbacks will rarely want to + // return true directly (unless |succeeded| is true). + typedef bool (*MinidumpCallback)(const MinidumpDescriptor& descriptor, + void* context, + bool succeeded); + + // In certain cases, a user may wish to handle the generation of the minidump + // themselves. In this case, they can install a handler callback which is + // called when a crash has occurred. If this function returns true, no other + // processing of occurs and the process will shortly be crashed. If this + // returns false, the normal processing continues. + typedef bool (*HandlerCallback)(const void* crash_context, + size_t crash_context_size, + void* context); + + // Creates a new ExceptionHandler instance to handle writing minidumps. + // Before writing a minidump, the optional |filter| callback will be called. + // Its return value determines whether or not Breakpad should write a + // minidump. The minidump content will be written to the file path or file + // descriptor from |descriptor|, and the optional |callback| is called after + // writing the dump file, as described above. + // If install_handler is true, then a minidump will be written whenever + // an unhandled exception occurs. If it is false, minidumps will only + // be written when WriteMinidump is called. + // If |server_fd| is valid, the minidump is generated out-of-process. If it + // is -1, in-process generation will always be used. + ExceptionHandler(const MinidumpDescriptor& descriptor, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + bool install_handler, + const int server_fd); + ~ExceptionHandler(); + + const MinidumpDescriptor& minidump_descriptor() const { + return minidump_descriptor_; + } + + void set_minidump_descriptor(const MinidumpDescriptor& descriptor) { + minidump_descriptor_ = descriptor; + } + + void set_crash_handler(HandlerCallback callback) { + crash_handler_ = callback; + } + + void set_crash_generation_client(CrashGenerationClient* client) { + crash_generation_client_.reset(client); + } + + // Writes a minidump immediately. This can be used to capture the execution + // state independently of a crash. + // Returns true on success. + // If the ExceptionHandler has been created with a path, a new file is + // generated for each minidump. The file path can be retrieved in the + // MinidumpDescriptor passed to the MinidumpCallback or by accessing the + // MinidumpDescriptor directly from the ExceptionHandler (with + // minidump_descriptor()). + // If the ExceptionHandler has been created with a file descriptor, the file + // descriptor is repositioned to its beginning and the previous generated + // minidump is overwritten. + // Note that this method is not supposed to be called from a compromised + // context as it uses the heap. + bool WriteMinidump(); + + // Convenience form of WriteMinidump which does not require an + // ExceptionHandler instance. + static bool WriteMinidump(const string& dump_path, + MinidumpCallback callback, + void* callback_context); + + // Write a minidump of |child| immediately. This can be used to + // capture the execution state of |child| independently of a crash. + // Pass a meaningful |child_blamed_thread| to make that thread in + // the child process the one from which a crash signature is + // extracted. + // + // WARNING: the return of this function *must* happen before + // the code that will eventually reap |child| executes. + // Otherwise there's a pernicious race condition in which |child| + // exits, is reaped, another process created with its pid, then that + // new process dumped. + static bool WriteMinidumpForChild(pid_t child, + pid_t child_blamed_thread, + const string& dump_path, + MinidumpCallback callback, + void* callback_context); + + // This structure is passed to minidump_writer.h:WriteMinidump via an opaque + // blob. It shouldn't be needed in any user code. + struct CrashContext { + siginfo_t siginfo; + pid_t tid; // the crashing thread. + struct ucontext context; +#if !defined(__ARM_EABI__) && !defined(__mips__) + // #ifdef this out because FP state is not part of user ABI for Linux ARM. + // In case of MIPS Linux FP state is already part of struct + // ucontext so 'float_state' is not required. + fpstate_t float_state; +#endif + }; + + // Returns whether out-of-process dump generation is used or not. + bool IsOutOfProcess() const { + return crash_generation_client_.get() != NULL; + } + + // Add information about a memory mapping. This can be used if + // a custom library loader is used that maps things in a way + // that the linux dumper can't handle by reading the maps file. + void AddMappingInfo(const string& name, + const uint8_t identifier[sizeof(MDGUID)], + uintptr_t start_address, + size_t mapping_size, + size_t file_offset); + + // Register a block of memory of length bytes starting at address ptr + // to be copied to the minidump when a crash happens. + void RegisterAppMemory(void* ptr, size_t length); + + // Unregister a block of memory that was registered with RegisterAppMemory. + void UnregisterAppMemory(void* ptr); + + // Force signal handling for the specified signal. + bool SimulateSignalDelivery(int sig); + + // Report a crash signal from an SA_SIGINFO signal handler. + bool HandleSignal(int sig, siginfo_t* info, void* uc); + + private: + // Save the old signal handlers and install new ones. + static bool InstallHandlersLocked(); + // Restore the old signal handlers. + static void RestoreHandlersLocked(); + + void PreresolveSymbols(); + bool GenerateDump(CrashContext *context); + void SendContinueSignalToChild(); + void WaitForContinueSignal(); + + static void SignalHandler(int sig, siginfo_t* info, void* uc); + static int ThreadEntry(void* arg); + bool DoDump(pid_t crashing_process, const void* context, + size_t context_size); + + const FilterCallback filter_; + const MinidumpCallback callback_; + void* const callback_context_; + + scoped_ptr crash_generation_client_; + + MinidumpDescriptor minidump_descriptor_; + + // Must be volatile. The compiler is unaware of the code which runs in + // the signal handler which reads this variable. Without volatile the + // compiler is free to optimise away writes to this variable which it + // believes are never read. + volatile HandlerCallback crash_handler_; + + // We need to explicitly enable ptrace of parent processes on some + // kernels, but we need to know the PID of the cloned process before we + // can do this. We create a pipe which we can use to block the + // cloned process after creating it, until we have explicitly enabled + // ptrace. This is used to store the file descriptors for the pipe + int fdes[2]; + + // Callers can add extra info about mappings for cases where the + // dumper code cannot extract enough information from /proc//maps. + MappingList mapping_list_; + + // Callers can request additional memory regions to be included in + // the dump. + AppMemoryList app_memory_list_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_ diff --git a/TMessagesProj/jni/breakpad/client/linux/handler/minidump_descriptor.cc b/TMessagesProj/jni/breakpad/client/linux/handler/minidump_descriptor.cc new file mode 100644 index 00000000..c601d35f --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/handler/minidump_descriptor.cc @@ -0,0 +1,100 @@ +// Copyright (c) 2012 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#include + +#include "client/linux/handler/minidump_descriptor.h" + +#include "common/linux/guid_creator.h" + +namespace google_breakpad { + +//static +const MinidumpDescriptor::MicrodumpOnConsole + MinidumpDescriptor::kMicrodumpOnConsole = {}; + +MinidumpDescriptor::MinidumpDescriptor(const MinidumpDescriptor& descriptor) + : mode_(descriptor.mode_), + fd_(descriptor.fd_), + directory_(descriptor.directory_), + c_path_(NULL), + size_limit_(descriptor.size_limit_), + microdump_build_fingerprint_(descriptor.microdump_build_fingerprint_), + microdump_product_info_(descriptor.microdump_product_info_) { + // The copy constructor is not allowed to be called on a MinidumpDescriptor + // with a valid path_, as getting its c_path_ would require the heap which + // can cause problems in compromised environments. + assert(descriptor.path_.empty()); +} + +MinidumpDescriptor& MinidumpDescriptor::operator=( + const MinidumpDescriptor& descriptor) { + assert(descriptor.path_.empty()); + + mode_ = descriptor.mode_; + fd_ = descriptor.fd_; + directory_ = descriptor.directory_; + path_.clear(); + if (c_path_) { + // This descriptor already had a path set, so generate a new one. + c_path_ = NULL; + UpdatePath(); + } + size_limit_ = descriptor.size_limit_; + microdump_build_fingerprint_ = descriptor.microdump_build_fingerprint_; + microdump_product_info_ = descriptor.microdump_product_info_; + return *this; +} + +void MinidumpDescriptor::UpdatePath() { + assert(mode_ == kWriteMinidumpToFile && !directory_.empty()); + + GUID guid; + char guid_str[kGUIDStringLength + 1]; + if (!CreateGUID(&guid) || !GUIDToString(&guid, guid_str, sizeof(guid_str))) { + assert(false); + } + + path_.clear(); + path_ = directory_ + "/" + guid_str + ".dmp"; + c_path_ = path_.c_str(); +} + +void MinidumpDescriptor::SetMicrodumpBuildFingerprint( + const char* build_fingerprint) { + assert(mode_ == kWriteMicrodumpToConsole); + microdump_build_fingerprint_ = build_fingerprint; +} + +void MinidumpDescriptor::SetMicrodumpProductInfo(const char* product_info) { + assert(mode_ == kWriteMicrodumpToConsole); + microdump_product_info_ = product_info; +} + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/client/linux/handler/minidump_descriptor.h b/TMessagesProj/jni/breakpad/client/linux/handler/minidump_descriptor.h new file mode 100644 index 00000000..3584c692 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/handler/minidump_descriptor.h @@ -0,0 +1,161 @@ +// Copyright (c) 2012 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_HANDLER_MINIDUMP_DESCRIPTOR_H_ +#define CLIENT_LINUX_HANDLER_MINIDUMP_DESCRIPTOR_H_ + +#include +#include + +#include + +#include "common/using_std_string.h" + +// This class describes how a crash dump should be generated, either: +// - Writing a full minidump to a file in a given directory (the actual path, +// inside the directory, is determined by this class). +// - Writing a full minidump to a given fd. +// - Writing a reduced microdump to the console (logcat on Android). +namespace google_breakpad { + +class MinidumpDescriptor { + public: + struct MicrodumpOnConsole {}; + static const MicrodumpOnConsole kMicrodumpOnConsole; + + MinidumpDescriptor() : mode_(kUninitialized), + fd_(-1), + size_limit_(-1), + microdump_build_fingerprint_(NULL), + microdump_product_info_(NULL) {} + + explicit MinidumpDescriptor(const string& directory) + : mode_(kWriteMinidumpToFile), + fd_(-1), + directory_(directory), + c_path_(NULL), + size_limit_(-1), + microdump_build_fingerprint_(NULL), + microdump_product_info_(NULL) { + assert(!directory.empty()); + } + + explicit MinidumpDescriptor(int fd) + : mode_(kWriteMinidumpToFd), + fd_(fd), + c_path_(NULL), + size_limit_(-1), + microdump_build_fingerprint_(NULL), + microdump_product_info_(NULL) { + assert(fd != -1); + } + + explicit MinidumpDescriptor(const MicrodumpOnConsole&) + : mode_(kWriteMicrodumpToConsole), + fd_(-1), + size_limit_(-1), + microdump_build_fingerprint_(NULL), + microdump_product_info_(NULL) {} + + explicit MinidumpDescriptor(const MinidumpDescriptor& descriptor); + MinidumpDescriptor& operator=(const MinidumpDescriptor& descriptor); + + static MinidumpDescriptor getMicrodumpDescriptor(); + + bool IsFD() const { return mode_ == kWriteMinidumpToFd; } + + int fd() const { return fd_; } + + string directory() const { return directory_; } + + const char* path() const { return c_path_; } + + bool IsMicrodumpOnConsole() const { + return mode_ == kWriteMicrodumpToConsole; + } + + // Updates the path so it is unique. + // Should be called from a normal context: this methods uses the heap. + void UpdatePath(); + + off_t size_limit() const { return size_limit_; } + void set_size_limit(off_t limit) { size_limit_ = limit; } + + // TODO(primiano): make this and product info (below) just part of the + // microdump ctor once it is rolled stably into Chrome. ETA: June 2015. + void SetMicrodumpBuildFingerprint(const char* build_fingerprint); + const char* microdump_build_fingerprint() const { + return microdump_build_fingerprint_; + } + + void SetMicrodumpProductInfo(const char* product_info); + const char* microdump_product_info() const { + return microdump_product_info_; + } + + private: + enum DumpMode { + kUninitialized = 0, + kWriteMinidumpToFile, + kWriteMinidumpToFd, + kWriteMicrodumpToConsole + }; + + // Specifies the dump mode (see DumpMode). + DumpMode mode_; + + // The file descriptor where the minidump is generated. + int fd_; + + // The directory where the minidump should be generated. + string directory_; + + // The full path to the generated minidump. + string path_; + + // The C string of |path_|. Precomputed so it can be access from a compromised + // context. + const char* c_path_; + + off_t size_limit_; + + // The product name/version and build fingerprint that should be appended to + // the dump (microdump only). Microdumps don't have the ability of appending + // extra metadata after the dump is generated (as opposite to minidumps + // MIME fields), therefore the product details must be provided upfront. + // The string pointers are supposed to be valid through all the lifetime of + // the process (read: the caller has to guarantee that they are stored in + // global static storage). + const char* microdump_build_fingerprint_; + const char* microdump_product_info_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_HANDLER_MINIDUMP_DESCRIPTOR_H_ diff --git a/TMessagesProj/jni/breakpad/client/linux/log/log.cc b/TMessagesProj/jni/breakpad/client/linux/log/log.cc new file mode 100644 index 00000000..fc23aa6d --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/log/log.cc @@ -0,0 +1,84 @@ +// Copyright (c) 2012 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#include "client/linux/log/log.h" + +#if defined(__ANDROID__) +#include +#include +#else +#include "third_party/lss/linux_syscall_support.h" +#endif + +namespace logger { + +#if defined(__ANDROID__) +namespace { + +// __android_log_buf_write() is not exported in the NDK and is being used by +// dynamic runtime linking. Its declaration is taken from Android's +// system/core/include/log/log.h. +using AndroidLogBufferWriteFunc = int (*)(int bufID, int prio, const char *tag, + const char *text); +const int kAndroidCrashLogId = 4; // From LOG_ID_CRASH in log.h. +const char kAndroidLogTag[] = "google-breakpad"; + +bool g_crash_log_initialized = false; +AndroidLogBufferWriteFunc g_android_log_buf_write = nullptr; + +} // namespace + +void initializeCrashLogWriter() { + if (g_crash_log_initialized) + return; + g_android_log_buf_write = reinterpret_cast( + dlsym(RTLD_DEFAULT, "__android_log_buf_write")); + g_crash_log_initialized = true; +} + +int writeToCrashLog(const char* buf) { + // Try writing to the crash log ring buffer. If not available, fall back to + // the standard log buffer. + if (g_android_log_buf_write) { + return g_android_log_buf_write(kAndroidCrashLogId, ANDROID_LOG_FATAL, + kAndroidLogTag, buf); + } + return __android_log_write(ANDROID_LOG_FATAL, kAndroidLogTag, buf); +} +#endif + +int write(const char* buf, size_t nbytes) { +#if defined(__ANDROID__) + return __android_log_write(ANDROID_LOG_WARN, kAndroidLogTag, buf); +#else + return sys_write(2, buf, nbytes); +#endif +} + +} // namespace logger diff --git a/TMessagesProj/jni/breakpad/client/linux/log/log.h b/TMessagesProj/jni/breakpad/client/linux/log/log.h new file mode 100644 index 00000000..f94bbd5f --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/log/log.h @@ -0,0 +1,55 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_LOG_LOG_H_ +#define CLIENT_LINUX_LOG_LOG_H_ + +#include + +namespace logger { + +int write(const char* buf, size_t nbytes); + +// In the case of Android the log can be written to the default system log +// (default behavior of write() above, or to the crash log (see +// writeToCrashLog() below). +#if defined(__ANDROID__) + +// The logger must be initialized in a non-compromised context. +void initializeCrashLogWriter(); + +// Once initialized, writeToCrashLog is safe to use in a compromised context, +// even if the initialization failed, in which case this will silently fall +// back on write(). +int writeToCrashLog(const char* buf); +#endif + +} // namespace logger + +#endif // CLIENT_LINUX_LOG_LOG_H_ diff --git a/TMessagesProj/jni/breakpad/client/linux/microdump_writer/microdump_writer.cc b/TMessagesProj/jni/breakpad/client/linux/microdump_writer/microdump_writer.cc new file mode 100644 index 00000000..d2eaa6ee --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/microdump_writer/microdump_writer.cc @@ -0,0 +1,425 @@ +// Copyright (c) 2014, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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 translation unit generates microdumps into the console (logcat on +// Android). See crbug.com/410294 for more info and design docs. + +#include "client/linux/microdump_writer/microdump_writer.h" + +#include + +#include "client/linux/dump_writer_common/thread_info.h" +#include "client/linux/dump_writer_common/ucontext_reader.h" +#include "client/linux/handler/exception_handler.h" +#include "client/linux/log/log.h" +#include "client/linux/minidump_writer/linux_ptrace_dumper.h" +#include "common/linux/linux_libc_support.h" + +namespace { + +using google_breakpad::ExceptionHandler; +using google_breakpad::LinuxDumper; +using google_breakpad::LinuxPtraceDumper; +using google_breakpad::MappingInfo; +using google_breakpad::MappingList; +using google_breakpad::RawContextCPU; +using google_breakpad::ThreadInfo; +using google_breakpad::UContextReader; + +const size_t kLineBufferSize = 2048; + +class MicrodumpWriter { + public: + MicrodumpWriter(const ExceptionHandler::CrashContext* context, + const MappingList& mappings, + const char* build_fingerprint, + const char* product_info, + LinuxDumper* dumper) + : ucontext_(context ? &context->context : NULL), +#if !defined(__ARM_EABI__) && !defined(__mips__) + float_state_(context ? &context->float_state : NULL), +#endif + dumper_(dumper), + mapping_list_(mappings), + build_fingerprint_(build_fingerprint), + product_info_(product_info), + log_line_(NULL) { + log_line_ = reinterpret_cast(Alloc(kLineBufferSize)); + if (log_line_) + log_line_[0] = '\0'; // Clear out the log line buffer. + } + + ~MicrodumpWriter() { dumper_->ThreadsResume(); } + + bool Init() { + // In the exceptional case where the system was out of memory and there + // wasn't even room to allocate the line buffer, bail out. There is nothing + // useful we can possibly achieve without the ability to Log. At least let's + // try to not crash. + if (!dumper_->Init() || !log_line_) + return false; + return dumper_->ThreadsSuspend() && dumper_->LateInit(); + } + + bool Dump() { + bool success; + LogLine("-----BEGIN BREAKPAD MICRODUMP-----"); + DumpProductInformation(); + DumpOSInformation(); + success = DumpCrashingThread(); + if (success) + success = DumpMappings(); + LogLine("-----END BREAKPAD MICRODUMP-----"); + dumper_->ThreadsResume(); + return success; + } + + private: + // Writes one line to the system log. + void LogLine(const char* msg) { +#if defined(__ANDROID__) + logger::writeToCrashLog(msg); +#else + logger::write(msg, my_strlen(msg)); + logger::write("\n", 1); +#endif + } + + // Stages the given string in the current line buffer. + void LogAppend(const char* str) { + my_strlcat(log_line_, str, kLineBufferSize); + } + + // As above (required to take precedence over template specialization below). + void LogAppend(char* str) { + LogAppend(const_cast(str)); + } + + // Stages the hex repr. of the given int type in the current line buffer. + template + void LogAppend(T value) { + // Make enough room to hex encode the largest int type + NUL. + static const char HEX[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F'}; + char hexstr[sizeof(T) * 2 + 1]; + for (int i = sizeof(T) * 2 - 1; i >= 0; --i, value >>= 4) + hexstr[i] = HEX[static_cast(value) & 0x0F]; + hexstr[sizeof(T) * 2] = '\0'; + LogAppend(hexstr); + } + + // Stages the buffer content hex-encoded in the current line buffer. + void LogAppend(const void* buf, size_t length) { + const uint8_t* ptr = reinterpret_cast(buf); + for (size_t i = 0; i < length; ++i, ++ptr) + LogAppend(*ptr); + } + + // Writes out the current line buffer on the system log. + void LogCommitLine() { + LogLine(log_line_); + my_strlcpy(log_line_, "", kLineBufferSize); + } + + void DumpProductInformation() { + LogAppend("V "); + if (product_info_) { + LogAppend(product_info_); + } else { + LogAppend("UNKNOWN:0.0.0.0"); + } + LogCommitLine(); + } + + void DumpOSInformation() { + const uint8_t n_cpus = static_cast(sysconf(_SC_NPROCESSORS_CONF)); + +#if defined(__ANDROID__) + const char kOSId[] = "A"; +#else + const char kOSId[] = "L"; +#endif + +// Dump the runtime architecture. On multiarch devices it might not match the +// hw architecture (the one returned by uname()), for instance in the case of +// a 32-bit app running on a aarch64 device. +#if defined(__aarch64__) + const char kArch[] = "arm64"; +#elif defined(__ARMEL__) + const char kArch[] = "arm"; +#elif defined(__x86_64__) + const char kArch[] = "x86_64"; +#elif defined(__i386__) + const char kArch[] = "x86"; +#elif defined(__mips__) + const char kArch[] = "mips"; +#else +#error "This code has not been ported to your platform yet" +#endif + + LogAppend("O "); + LogAppend(kOSId); + LogAppend(" "); + LogAppend(kArch); + LogAppend(" "); + LogAppend(n_cpus); + LogAppend(" "); + + // Dump the HW architecture (e.g., armv7l, aarch64). + struct utsname uts; + const bool has_uts_info = (uname(&uts) == 0); + const char* hwArch = has_uts_info ? uts.machine : "unknown_hw_arch"; + LogAppend(hwArch); + LogAppend(" "); + + // If the client has attached a build fingerprint to the MinidumpDescriptor + // use that one. Otherwise try to get some basic info from uname(). + if (build_fingerprint_) { + LogAppend(build_fingerprint_); + } else if (has_uts_info) { + LogAppend(uts.release); + LogAppend(" "); + LogAppend(uts.version); + } else { + LogAppend("no build fingerprint available"); + } + LogCommitLine(); + } + + bool DumpThreadStack(uint32_t thread_id, + uintptr_t stack_pointer, + int max_stack_len, + uint8_t** stack_copy) { + *stack_copy = NULL; + const void* stack; + size_t stack_len; + + if (!dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) { + // The stack pointer might not be available. In this case we don't hard + // fail, just produce a (almost useless) microdump w/o a stack section. + return true; + } + + LogAppend("S 0 "); + LogAppend(stack_pointer); + LogAppend(" "); + LogAppend(reinterpret_cast(stack)); + LogAppend(" "); + LogAppend(stack_len); + LogCommitLine(); + + if (max_stack_len >= 0 && + stack_len > static_cast(max_stack_len)) { + stack_len = max_stack_len; + } + + *stack_copy = reinterpret_cast(Alloc(stack_len)); + dumper_->CopyFromProcess(*stack_copy, thread_id, stack, stack_len); + + // Dump the content of the stack, splicing it into chunks which size is + // compatible with the max logcat line size (see LOGGER_ENTRY_MAX_PAYLOAD). + const size_t STACK_DUMP_CHUNK_SIZE = 384; + for (size_t stack_off = 0; stack_off < stack_len; + stack_off += STACK_DUMP_CHUNK_SIZE) { + LogAppend("S "); + LogAppend(reinterpret_cast(stack) + stack_off); + LogAppend(" "); + LogAppend(*stack_copy + stack_off, + std::min(STACK_DUMP_CHUNK_SIZE, stack_len - stack_off)); + LogCommitLine(); + } + return true; + } + + // Write information about the crashing thread. + bool DumpCrashingThread() { + const unsigned num_threads = dumper_->threads().size(); + + for (unsigned i = 0; i < num_threads; ++i) { + MDRawThread thread; + my_memset(&thread, 0, sizeof(thread)); + thread.thread_id = dumper_->threads()[i]; + + // Dump only the crashing thread. + if (static_cast(thread.thread_id) != dumper_->crash_thread()) + continue; + + assert(ucontext_); + assert(!dumper_->IsPostMortem()); + + uint8_t* stack_copy; + const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_); + if (!DumpThreadStack(thread.thread_id, stack_ptr, -1, &stack_copy)) + return false; + + RawContextCPU cpu; + my_memset(&cpu, 0, sizeof(RawContextCPU)); +#if !defined(__ARM_EABI__) && !defined(__mips__) + UContextReader::FillCPUContext(&cpu, ucontext_, float_state_); +#else + UContextReader::FillCPUContext(&cpu, ucontext_); +#endif + DumpCPUState(&cpu); + } + return true; + } + + void DumpCPUState(RawContextCPU* cpu) { + LogAppend("C "); + LogAppend(cpu, sizeof(*cpu)); + LogCommitLine(); + } + + // If there is caller-provided information about this mapping + // in the mapping_list_ list, return true. Otherwise, return false. + bool HaveMappingInfo(const MappingInfo& mapping) { + for (MappingList::const_iterator iter = mapping_list_.begin(); + iter != mapping_list_.end(); + ++iter) { + // Ignore any mappings that are wholly contained within + // mappings in the mapping_info_ list. + if (mapping.start_addr >= iter->first.start_addr && + (mapping.start_addr + mapping.size) <= + (iter->first.start_addr + iter->first.size)) { + return true; + } + } + return false; + } + + // Dump information about the provided |mapping|. If |identifier| is non-NULL, + // use it instead of calculating a file ID from the mapping. + void DumpModule(const MappingInfo& mapping, + bool member, + unsigned int mapping_id, + const uint8_t* identifier) { + MDGUID module_identifier; + if (identifier) { + // GUID was provided by caller. + my_memcpy(&module_identifier, identifier, sizeof(MDGUID)); + } else { + dumper_->ElfFileIdentifierForMapping( + mapping, + member, + mapping_id, + reinterpret_cast(&module_identifier)); + } + + char file_name[NAME_MAX]; + char file_path[NAME_MAX]; + LinuxDumper::GetMappingEffectiveNameAndPath( + mapping, file_path, sizeof(file_path), file_name, sizeof(file_name)); + + LogAppend("M "); + LogAppend(static_cast(mapping.start_addr)); + LogAppend(" "); + LogAppend(mapping.offset); + LogAppend(" "); + LogAppend(mapping.size); + LogAppend(" "); + LogAppend(module_identifier.data1); + LogAppend(module_identifier.data2); + LogAppend(module_identifier.data3); + LogAppend(module_identifier.data4[0]); + LogAppend(module_identifier.data4[1]); + LogAppend(module_identifier.data4[2]); + LogAppend(module_identifier.data4[3]); + LogAppend(module_identifier.data4[4]); + LogAppend(module_identifier.data4[5]); + LogAppend(module_identifier.data4[6]); + LogAppend(module_identifier.data4[7]); + LogAppend("0 "); // Age is always 0 on Linux. + LogAppend(file_name); + LogCommitLine(); + } + + // Write information about the mappings in effect. + bool DumpMappings() { + // First write all the mappings from the dumper + for (unsigned i = 0; i < dumper_->mappings().size(); ++i) { + const MappingInfo& mapping = *dumper_->mappings()[i]; + if (mapping.name[0] == 0 || // only want modules with filenames. + !mapping.exec || // only want executable mappings. + mapping.size < 4096 || // too small to get a signature for. + HaveMappingInfo(mapping)) { + continue; + } + + DumpModule(mapping, true, i, NULL); + } + // Next write all the mappings provided by the caller + for (MappingList::const_iterator iter = mapping_list_.begin(); + iter != mapping_list_.end(); + ++iter) { + DumpModule(iter->first, false, 0, iter->second); + } + return true; + } + + void* Alloc(unsigned bytes) { return dumper_->allocator()->Alloc(bytes); } + + const struct ucontext* const ucontext_; +#if !defined(__ARM_EABI__) && !defined(__mips__) + const google_breakpad::fpstate_t* const float_state_; +#endif + LinuxDumper* dumper_; + const MappingList& mapping_list_; + const char* const build_fingerprint_; + const char* const product_info_; + char* log_line_; +}; +} // namespace + +namespace google_breakpad { + +bool WriteMicrodump(pid_t crashing_process, + const void* blob, + size_t blob_size, + const MappingList& mappings, + const char* build_fingerprint, + const char* product_info) { + LinuxPtraceDumper dumper(crashing_process); + const ExceptionHandler::CrashContext* context = NULL; + if (blob) { + if (blob_size != sizeof(ExceptionHandler::CrashContext)) + return false; + context = reinterpret_cast(blob); + dumper.set_crash_address( + reinterpret_cast(context->siginfo.si_addr)); + dumper.set_crash_signal(context->siginfo.si_signo); + dumper.set_crash_thread(context->tid); + } + MicrodumpWriter writer(context, mappings, build_fingerprint, product_info, + &dumper); + if (!writer.Init()) + return false; + return writer.Dump(); +} + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/client/linux/microdump_writer/microdump_writer.h b/TMessagesProj/jni/breakpad/client/linux/microdump_writer/microdump_writer.h new file mode 100644 index 00000000..e2185583 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/microdump_writer/microdump_writer.h @@ -0,0 +1,64 @@ +// Copyright (c) 2014, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_MICRODUMP_WRITER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_MICRODUMP_WRITER_H_ + +#include +#include + +#include "client/linux/dump_writer_common/mapping_info.h" + +namespace google_breakpad { + +// Writes a microdump (a reduced dump containing only the state of the crashing +// thread) on the console (logcat on Android). These functions do not malloc nor +// use libc functions which may. Thus, it can be used in contexts where the +// state of the heap may be corrupt. +// Args: +// crashing_process: the pid of the crashing process. This must be trusted. +// blob: a blob of data from the crashing process. See exception_handler.h +// blob_size: the length of |blob| in bytes. +// mappings: a list of additional mappings provided by the application. +// build_fingerprint: a (optional) C string which determines the OS +// build fingerprint (e.g., aosp/occam/mako:5.1.1/LMY47W/1234:eng/dev-keys). +// product_info: a (optional) C string which determines the product name and +// version (e.g., WebView:42.0.2311.136). +// +// Returns true iff successful. +bool WriteMicrodump(pid_t crashing_process, + const void* blob, + size_t blob_size, + const MappingList& mappings, + const char* build_fingerprint, + const char* product_info); + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_MICRODUMP_WRITER_H_ diff --git a/TMessagesProj/jni/breakpad/client/linux/minidump_writer/cpu_set.h b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/cpu_set.h new file mode 100644 index 00000000..1cca9aa5 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/cpu_set.h @@ -0,0 +1,144 @@ +// Copyright (c) 2013, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_CPU_SET_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_CPU_SET_H_ + +#include +#include +#include + +#include "common/linux/linux_libc_support.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +// Helper class used to model a set of CPUs, as read from sysfs +// files like /sys/devices/system/cpu/present +// See See http://www.kernel.org/doc/Documentation/cputopology.txt +class CpuSet { +public: + // The maximum number of supported CPUs. + static const size_t kMaxCpus = 1024; + + CpuSet() { + my_memset(mask_, 0, sizeof(mask_)); + } + + // Parse a sysfs file to extract the corresponding CPU set. + bool ParseSysFile(int fd) { + char buffer[512]; + int ret = sys_read(fd, buffer, sizeof(buffer)-1); + if (ret < 0) + return false; + + buffer[ret] = '\0'; + + // Expected format: comma-separated list of items, where each + // item can be a decimal integer, or two decimal integers separated + // by a dash. + // E.g.: + // 0 + // 0,1,2,3 + // 0-3 + // 1,10-23 + const char* p = buffer; + const char* p_end = p + ret; + while (p < p_end) { + // Skip leading space, if any + while (p < p_end && my_isspace(*p)) + p++; + + // Find start and size of current item. + const char* item = p; + size_t item_len = static_cast(p_end - p); + const char* item_next = + static_cast(my_memchr(p, ',', item_len)); + if (item_next != NULL) { + p = item_next + 1; + item_len = static_cast(item_next - item); + } else { + p = p_end; + item_next = p_end; + } + + // Ignore trailing spaces. + while (item_next > item && my_isspace(item_next[-1])) + item_next--; + + // skip empty items. + if (item_next == item) + continue; + + // read first decimal value. + uintptr_t start = 0; + const char* next = my_read_decimal_ptr(&start, item); + uintptr_t end = start; + if (*next == '-') + my_read_decimal_ptr(&end, next+1); + + while (start <= end) + SetBit(start++); + } + return true; + } + + // Intersect this CPU set with another one. + void IntersectWith(const CpuSet& other) { + for (size_t nn = 0; nn < kMaskWordCount; ++nn) + mask_[nn] &= other.mask_[nn]; + } + + // Return the number of CPUs in this set. + int GetCount() { + int result = 0; + for (size_t nn = 0; nn < kMaskWordCount; ++nn) { + result += __builtin_popcount(mask_[nn]); + } + return result; + } + +private: + void SetBit(uintptr_t index) { + size_t nn = static_cast(index); + if (nn < kMaxCpus) + mask_[nn / kMaskWordBits] |= (1U << (nn % kMaskWordBits)); + } + + typedef uint32_t MaskWordType; + static const size_t kMaskWordBits = 8*sizeof(MaskWordType); + static const size_t kMaskWordCount = + (kMaxCpus + kMaskWordBits - 1) / kMaskWordBits; + + MaskWordType mask_[kMaskWordCount]; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_CPU_SET_H_ diff --git a/TMessagesProj/jni/breakpad/client/linux/minidump_writer/directory_reader.h b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/directory_reader.h new file mode 100644 index 00000000..a4bde180 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/directory_reader.h @@ -0,0 +1,106 @@ +// Copyright (c) 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_ + +#include +#include +#include +#include +#include +#include + +#include "common/linux/linux_libc_support.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +// A class for enumerating a directory without using diropen/readdir or other +// functions which may allocate memory. +class DirectoryReader { + public: + DirectoryReader(int fd) + : fd_(fd), + buf_used_(0) { + } + + // Return the next entry from the directory + // name: (output) the NUL terminated entry name + // + // Returns true iff successful (false on EOF). + // + // After calling this, one must call |PopEntry| otherwise you'll get the same + // entry over and over. + bool GetNextEntry(const char** name) { + struct kernel_dirent* const dent = + reinterpret_cast(buf_); + + if (buf_used_ == 0) { + // need to read more entries. + const int n = sys_getdents(fd_, dent, sizeof(buf_)); + if (n < 0) { + return false; + } else if (n == 0) { + hit_eof_ = true; + } else { + buf_used_ += n; + } + } + + if (buf_used_ == 0 && hit_eof_) + return false; + + assert(buf_used_ > 0); + + *name = dent->d_name; + return true; + } + + void PopEntry() { + if (!buf_used_) + return; + + const struct kernel_dirent* const dent = + reinterpret_cast(buf_); + + buf_used_ -= dent->d_reclen; + my_memmove(buf_, buf_ + dent->d_reclen, buf_used_); + } + + private: + const int fd_; + bool hit_eof_; + unsigned buf_used_; + uint8_t buf_[sizeof(struct kernel_dirent) + NAME_MAX + 1]; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_ diff --git a/TMessagesProj/jni/breakpad/client/linux/minidump_writer/line_reader.h b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/line_reader.h new file mode 100644 index 00000000..779cfeb6 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/line_reader.h @@ -0,0 +1,131 @@ +// Copyright (c) 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_ + +#include +#include +#include + +#include "common/linux/linux_libc_support.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +// A class for reading a file, line by line, without using fopen/fgets or other +// functions which may allocate memory. +class LineReader { + public: + LineReader(int fd) + : fd_(fd), + hit_eof_(false), + buf_used_(0) { + } + + // The maximum length of a line. + static const size_t kMaxLineLen = 512; + + // Return the next line from the file. + // line: (output) a pointer to the start of the line. The line is NUL + // terminated. + // len: (output) the length of the line (not inc the NUL byte) + // + // Returns true iff successful (false on EOF). + // + // One must call |PopLine| after this function, otherwise you'll continue to + // get the same line over and over. + bool GetNextLine(const char **line, unsigned *len) { + for (;;) { + if (buf_used_ == 0 && hit_eof_) + return false; + + for (unsigned i = 0; i < buf_used_; ++i) { + if (buf_[i] == '\n' || buf_[i] == 0) { + buf_[i] = 0; + *len = i; + *line = buf_; + return true; + } + } + + if (buf_used_ == sizeof(buf_)) { + // we scanned the whole buffer and didn't find an end-of-line marker. + // This line is too long to process. + return false; + } + + // We didn't find any end-of-line terminators in the buffer. However, if + // this is the last line in the file it might not have one: + if (hit_eof_) { + assert(buf_used_); + // There's room for the NUL because of the buf_used_ == sizeof(buf_) + // check above. + buf_[buf_used_] = 0; + *len = buf_used_; + buf_used_ += 1; // since we appended the NUL. + *line = buf_; + return true; + } + + // Otherwise, we should pull in more data from the file + const ssize_t n = sys_read(fd_, buf_ + buf_used_, + sizeof(buf_) - buf_used_); + if (n < 0) { + return false; + } else if (n == 0) { + hit_eof_ = true; + } else { + buf_used_ += n; + } + + // At this point, we have either set the hit_eof_ flag, or we have more + // data to process... + } + } + + void PopLine(unsigned len) { + // len doesn't include the NUL byte at the end. + + assert(buf_used_ >= len + 1); + buf_used_ -= len + 1; + my_memmove(buf_, buf_ + len + 1, buf_used_); + } + + private: + const int fd_; + + bool hit_eof_; + unsigned buf_used_; + char buf_[kMaxLineLen]; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_ diff --git a/TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_dumper.cc b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_dumper.cc new file mode 100644 index 00000000..4df68a84 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_dumper.cc @@ -0,0 +1,612 @@ +// Copyright (c) 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// linux_dumper.cc: Implement google_breakpad::LinuxDumper. +// See linux_dumper.h for details. + +// This code deals with the mechanics of getting information about a crashed +// process. Since this code may run in a compromised address space, the same +// rules apply as detailed at the top of minidump_writer.h: no libc calls and +// use the alternative allocator. + +#include "client/linux/minidump_writer/linux_dumper.h" + +#include +#include +#include +#include +#include +#include + +# if __WORDSIZE == 64 +# define UINTPTR_MAX (18446744073709551615UL) +# else +# define UINTPTR_MAX (4294967295U) +# endif + + +#include "client/linux/minidump_writer/line_reader.h" +#include "common/linux/elfutils.h" +#include "common/linux/file_id.h" +#include "common/linux/linux_libc_support.h" +#include "common/linux/memory_mapped_file.h" +#include "common/linux/safe_readlink.h" +#include "third_party/lss/linux_syscall_support.h" + +#if defined(__ANDROID__) + +// Android packed relocations definitions are not yet available from the +// NDK header files, so we have to provide them manually here. +#ifndef DT_LOOS +#define DT_LOOS 0x6000000d +#endif +#ifndef DT_ANDROID_REL +static const int DT_ANDROID_REL = DT_LOOS + 2; +#endif +#ifndef DT_ANDROID_RELA +static const int DT_ANDROID_RELA = DT_LOOS + 4; +#endif + +#endif // __ANDROID __ + +static const char kMappedFileUnsafePrefix[] = "/dev/"; +static const char kDeletedSuffix[] = " (deleted)"; +static const char kReservedFlags[] = " ---p"; + +inline static bool IsMappedFileOpenUnsafe( + const google_breakpad::MappingInfo& mapping) { + // It is unsafe to attempt to open a mapped file that lives under /dev, + // because the semantics of the open may be driver-specific so we'd risk + // hanging the crash dumper. And a file in /dev/ almost certainly has no + // ELF file identifier anyways. + return my_strncmp(mapping.name, + kMappedFileUnsafePrefix, + sizeof(kMappedFileUnsafePrefix) - 1) == 0; +} + +namespace google_breakpad { + +// All interesting auvx entry types are below AT_SYSINFO_EHDR +#define AT_MAX AT_SYSINFO_EHDR + +LinuxDumper::LinuxDumper(pid_t pid) + : pid_(pid), + crash_address_(0), + crash_signal_(0), + crash_thread_(pid), + threads_(&allocator_, 8), + mappings_(&allocator_), + auxv_(&allocator_, AT_MAX + 1) { + // The passed-in size to the constructor (above) is only a hint. + // Must call .resize() to do actual initialization of the elements. + auxv_.resize(AT_MAX + 1); +} + +LinuxDumper::~LinuxDumper() { +} + +bool LinuxDumper::Init() { + return ReadAuxv() && EnumerateThreads() && EnumerateMappings(); +} + +bool LinuxDumper::LateInit() { +#if defined(__ANDROID__) + LatePostprocessMappings(); +#endif + return true; +} + +bool +LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping, + bool member, + unsigned int mapping_id, + uint8_t identifier[sizeof(MDGUID)]) { + assert(!member || mapping_id < mappings_.size()); + my_memset(identifier, 0, sizeof(MDGUID)); + if (IsMappedFileOpenUnsafe(mapping)) + return false; + + // Special-case linux-gate because it's not a real file. + if (my_strcmp(mapping.name, kLinuxGateLibraryName) == 0) { + void* linux_gate = NULL; + if (pid_ == sys_getpid()) { + linux_gate = reinterpret_cast(mapping.start_addr); + } else { + linux_gate = allocator_.Alloc(mapping.size); + CopyFromProcess(linux_gate, pid_, + reinterpret_cast(mapping.start_addr), + mapping.size); + } + return FileID::ElfFileIdentifierFromMappedFile(linux_gate, identifier); + } + + char filename[NAME_MAX]; + size_t filename_len = my_strlen(mapping.name); + if (filename_len >= NAME_MAX) { + assert(false); + return false; + } + my_memcpy(filename, mapping.name, filename_len); + filename[filename_len] = '\0'; + bool filename_modified = HandleDeletedFileInMapping(filename); + + MemoryMappedFile mapped_file(filename, mapping.offset); + if (!mapped_file.data() || mapped_file.size() < SELFMAG) + return false; + + bool success = + FileID::ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier); + if (success && member && filename_modified) { + mappings_[mapping_id]->name[filename_len - + sizeof(kDeletedSuffix) + 1] = '\0'; + } + + return success; +} + +namespace { +bool ElfFileSoNameFromMappedFile( + const void* elf_base, char* soname, size_t soname_size) { + if (!IsValidElf(elf_base)) { + // Not ELF + return false; + } + + const void* segment_start; + size_t segment_size; + int elf_class; + if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC, + &segment_start, &segment_size, &elf_class)) { + // No dynamic section + return false; + } + + const void* dynstr_start; + size_t dynstr_size; + if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB, + &dynstr_start, &dynstr_size, &elf_class)) { + // No dynstr section + return false; + } + + const ElfW(Dyn)* dynamic = static_cast(segment_start); + size_t dcount = segment_size / sizeof(ElfW(Dyn)); + for (const ElfW(Dyn)* dyn = dynamic; dyn < dynamic + dcount; ++dyn) { + if (dyn->d_tag == DT_SONAME) { + const char* dynstr = static_cast(dynstr_start); + if (dyn->d_un.d_val >= dynstr_size) { + // Beyond the end of the dynstr section + return false; + } + const char* str = dynstr + dyn->d_un.d_val; + const size_t maxsize = dynstr_size - dyn->d_un.d_val; + my_strlcpy(soname, str, maxsize < soname_size ? maxsize : soname_size); + return true; + } + } + + // Did not find SONAME + return false; +} + +// Find the shared object name (SONAME) by examining the ELF information +// for |mapping|. If the SONAME is found copy it into the passed buffer +// |soname| and return true. The size of the buffer is |soname_size|. +// The SONAME will be truncated if it is too long to fit in the buffer. +bool ElfFileSoName( + const MappingInfo& mapping, char* soname, size_t soname_size) { + if (IsMappedFileOpenUnsafe(mapping)) { + // Not safe + return false; + } + + char filename[NAME_MAX]; + size_t filename_len = my_strlen(mapping.name); + if (filename_len >= NAME_MAX) { + assert(false); + // name too long + return false; + } + + my_memcpy(filename, mapping.name, filename_len); + filename[filename_len] = '\0'; + + MemoryMappedFile mapped_file(filename, mapping.offset); + if (!mapped_file.data() || mapped_file.size() < SELFMAG) { + // mmap failed + return false; + } + + return ElfFileSoNameFromMappedFile(mapped_file.data(), soname, soname_size); +} + +} // namespace + + +// static +void LinuxDumper::GetMappingEffectiveNameAndPath(const MappingInfo& mapping, + char* file_path, + size_t file_path_size, + char* file_name, + size_t file_name_size) { + my_strlcpy(file_path, mapping.name, file_path_size); + + // If an executable is mapped from a non-zero offset, this is likely because + // the executable was loaded directly from inside an archive file (e.g., an + // apk on Android). We try to find the name of the shared object (SONAME) by + // looking in the file for ELF sections. + bool mapped_from_archive = false; + if (mapping.exec && mapping.offset != 0) + mapped_from_archive = ElfFileSoName(mapping, file_name, file_name_size); + + if (mapped_from_archive) { + // Some tools (e.g., stackwalk) extract the basename from the pathname. In + // this case, we append the file_name to the mapped archive path as follows: + // file_name := libname.so + // file_path := /path/to/ARCHIVE.APK/libname.so + if (my_strlen(file_path) + 1 + my_strlen(file_name) < file_path_size) { + my_strlcat(file_path, "/", file_path_size); + my_strlcat(file_path, file_name, file_path_size); + } + } else { + // Common case: + // file_path := /path/to/libname.so + // file_name := libname.so + const char* basename = my_strrchr(file_path, '/'); + basename = basename == NULL ? file_path : (basename + 1); + my_strlcpy(file_name, basename, file_name_size); + } +} + +bool LinuxDumper::ReadAuxv() { + char auxv_path[NAME_MAX]; + if (!BuildProcPath(auxv_path, pid_, "auxv")) { + return false; + } + + int fd = sys_open(auxv_path, O_RDONLY, 0); + if (fd < 0) { + return false; + } + + elf_aux_entry one_aux_entry; + bool res = false; + while (sys_read(fd, + &one_aux_entry, + sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) && + one_aux_entry.a_type != AT_NULL) { + if (one_aux_entry.a_type <= AT_MAX) { + auxv_[one_aux_entry.a_type] = one_aux_entry.a_un.a_val; + res = true; + } + } + sys_close(fd); + return res; +} + +bool LinuxDumper::EnumerateMappings() { + char maps_path[NAME_MAX]; + if (!BuildProcPath(maps_path, pid_, "maps")) + return false; + + // linux_gate_loc is the beginning of the kernel's mapping of + // linux-gate.so in the process. It doesn't actually show up in the + // maps list as a filename, but it can be found using the AT_SYSINFO_EHDR + // aux vector entry, which gives the information necessary to special + // case its entry when creating the list of mappings. + // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more + // information. + const void* linux_gate_loc = + reinterpret_cast(auxv_[AT_SYSINFO_EHDR]); + // Although the initial executable is usually the first mapping, it's not + // guaranteed (see http://crosbug.com/25355); therefore, try to use the + // actual entry point to find the mapping. + const void* entry_point_loc = reinterpret_cast(auxv_[AT_ENTRY]); + + const int fd = sys_open(maps_path, O_RDONLY, 0); + if (fd < 0) + return false; + LineReader* const line_reader = new(allocator_) LineReader(fd); + + const char* line; + unsigned line_len; + while (line_reader->GetNextLine(&line, &line_len)) { + uintptr_t start_addr, end_addr, offset; + + const char* i1 = my_read_hex_ptr(&start_addr, line); + if (*i1 == '-') { + const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1); + if (*i2 == ' ') { + bool exec = (*(i2 + 3) == 'x'); + const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */); + if (*i3 == ' ') { + const char* name = NULL; + // Only copy name if the name is a valid path name, or if + // it's the VDSO image. + if (((name = my_strchr(line, '/')) == NULL) && + linux_gate_loc && + reinterpret_cast(start_addr) == linux_gate_loc) { + name = kLinuxGateLibraryName; + offset = 0; + } + // Merge adjacent mappings with the same name into one module, + // assuming they're a single library mapped by the dynamic linker + if (name && !mappings_.empty()) { + MappingInfo* module = mappings_.back(); + if ((start_addr == module->start_addr + module->size) && + (my_strlen(name) == my_strlen(module->name)) && + (my_strncmp(name, module->name, my_strlen(name)) == 0)) { + module->size = end_addr - module->start_addr; + line_reader->PopLine(line_len); + continue; + } + } + // Also merge mappings that result from address ranges that the + // linker reserved but which a loaded library did not use. These + // appear as an anonymous private mapping with no access flags set + // and which directly follow an executable mapping. + if (!name && !mappings_.empty()) { + MappingInfo* module = mappings_.back(); + if ((start_addr == module->start_addr + module->size) && + module->exec && + module->name[0] == '/' && + offset == 0 && my_strncmp(i2, + kReservedFlags, + sizeof(kReservedFlags) - 1) == 0) { + module->size = end_addr - module->start_addr; + line_reader->PopLine(line_len); + continue; + } + } + MappingInfo* const module = new(allocator_) MappingInfo; + my_memset(module, 0, sizeof(MappingInfo)); + module->start_addr = start_addr; + module->size = end_addr - start_addr; + module->offset = offset; + module->exec = exec; + if (name != NULL) { + const unsigned l = my_strlen(name); + if (l < sizeof(module->name)) + my_memcpy(module->name, name, l); + } + // If this is the entry-point mapping, and it's not already the + // first one, then we need to make it be first. This is because + // the minidump format assumes the first module is the one that + // corresponds to the main executable (as codified in + // processor/minidump.cc:MinidumpModuleList::GetMainModule()). + if (entry_point_loc && + (entry_point_loc >= + reinterpret_cast(module->start_addr)) && + (entry_point_loc < + reinterpret_cast(module->start_addr+module->size)) && + !mappings_.empty()) { + // push the module onto the front of the list. + mappings_.resize(mappings_.size() + 1); + for (size_t idx = mappings_.size() - 1; idx > 0; idx--) + mappings_[idx] = mappings_[idx - 1]; + mappings_[0] = module; + } else { + mappings_.push_back(module); + } + } + } + } + line_reader->PopLine(line_len); + } + + sys_close(fd); + + return !mappings_.empty(); +} + +#if defined(__ANDROID__) + +bool LinuxDumper::GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr) { + CopyFromProcess(ehdr, pid_, + reinterpret_cast(start_addr), + sizeof(*ehdr)); + return my_memcmp(&ehdr->e_ident, ELFMAG, SELFMAG) == 0; +} + +void LinuxDumper::ParseLoadedElfProgramHeaders(ElfW(Ehdr)* ehdr, + uintptr_t start_addr, + uintptr_t* min_vaddr_ptr, + uintptr_t* dyn_vaddr_ptr, + size_t* dyn_count_ptr) { + uintptr_t phdr_addr = start_addr + ehdr->e_phoff; + + const uintptr_t max_addr = UINTPTR_MAX; + uintptr_t min_vaddr = max_addr; + uintptr_t dyn_vaddr = 0; + size_t dyn_count = 0; + + for (size_t i = 0; i < ehdr->e_phnum; ++i) { + ElfW(Phdr) phdr; + CopyFromProcess(&phdr, pid_, + reinterpret_cast(phdr_addr), + sizeof(phdr)); + if (phdr.p_type == PT_LOAD && phdr.p_vaddr < min_vaddr) { + min_vaddr = phdr.p_vaddr; + } + if (phdr.p_type == PT_DYNAMIC) { + dyn_vaddr = phdr.p_vaddr; + dyn_count = phdr.p_memsz / sizeof(ElfW(Dyn)); + } + phdr_addr += sizeof(phdr); + } + + *min_vaddr_ptr = min_vaddr; + *dyn_vaddr_ptr = dyn_vaddr; + *dyn_count_ptr = dyn_count; +} + +bool LinuxDumper::HasAndroidPackedRelocations(uintptr_t load_bias, + uintptr_t dyn_vaddr, + size_t dyn_count) { + uintptr_t dyn_addr = load_bias + dyn_vaddr; + for (size_t i = 0; i < dyn_count; ++i) { + ElfW(Dyn) dyn; + CopyFromProcess(&dyn, pid_, + reinterpret_cast(dyn_addr), + sizeof(dyn)); + if (dyn.d_tag == DT_ANDROID_REL || dyn.d_tag == DT_ANDROID_RELA) { + return true; + } + dyn_addr += sizeof(dyn); + } + return false; +} + +uintptr_t LinuxDumper::GetEffectiveLoadBias(ElfW(Ehdr)* ehdr, + uintptr_t start_addr) { + uintptr_t min_vaddr = 0; + uintptr_t dyn_vaddr = 0; + size_t dyn_count = 0; + ParseLoadedElfProgramHeaders(ehdr, start_addr, + &min_vaddr, &dyn_vaddr, &dyn_count); + // If |min_vaddr| is non-zero and we find Android packed relocation tags, + // return the effective load bias. + if (min_vaddr != 0) { + const uintptr_t load_bias = start_addr - min_vaddr; + if (HasAndroidPackedRelocations(load_bias, dyn_vaddr, dyn_count)) { + return load_bias; + } + } + // Either |min_vaddr| is zero, or it is non-zero but we did not find the + // expected Android packed relocations tags. + return start_addr; +} + +void LinuxDumper::LatePostprocessMappings() { + for (size_t i = 0; i < mappings_.size(); ++i) { + // Only consider exec mappings that indicate a file path was mapped, and + // where the ELF header indicates a mapped shared library. + MappingInfo* mapping = mappings_[i]; + if (!(mapping->exec && mapping->name[0] == '/')) { + continue; + } + ElfW(Ehdr) ehdr; + if (!GetLoadedElfHeader(mapping->start_addr, &ehdr)) { + continue; + } + if (ehdr.e_type == ET_DYN) { + // Compute the effective load bias for this mapped library, and update + // the mapping to hold that rather than |start_addr|, at the same time + // adjusting |size| to account for the change in |start_addr|. Where + // the library does not contain Android packed relocations, + // GetEffectiveLoadBias() returns |start_addr| and the mapping entry + // is not changed. + const uintptr_t load_bias = GetEffectiveLoadBias(&ehdr, + mapping->start_addr); + mapping->size += mapping->start_addr - load_bias; + mapping->start_addr = load_bias; + } + } +} + +#endif // __ANDROID__ + +// Get information about the stack, given the stack pointer. We don't try to +// walk the stack since we might not have all the information needed to do +// unwind. So we just grab, up to, 32k of stack. +bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len, + uintptr_t int_stack_pointer) { + // Move the stack pointer to the bottom of the page that it's in. + const uintptr_t page_size = getpagesize(); + + uint8_t* const stack_pointer = + reinterpret_cast(int_stack_pointer & ~(page_size - 1)); + + // The number of bytes of stack which we try to capture. + static const ptrdiff_t kStackToCapture = 32 * 1024; + + const MappingInfo* mapping = FindMapping(stack_pointer); + if (!mapping) + return false; + const ptrdiff_t offset = stack_pointer - + reinterpret_cast(mapping->start_addr); + const ptrdiff_t distance_to_end = + static_cast(mapping->size) - offset; + *stack_len = distance_to_end > kStackToCapture ? + kStackToCapture : distance_to_end; + *stack = stack_pointer; + return true; +} + +// Find the mapping which the given memory address falls in. +const MappingInfo* LinuxDumper::FindMapping(const void* address) const { + const uintptr_t addr = (uintptr_t) address; + + for (size_t i = 0; i < mappings_.size(); ++i) { + const uintptr_t start = static_cast(mappings_[i]->start_addr); + if (addr >= start && addr - start < mappings_[i]->size) + return mappings_[i]; + } + + return NULL; +} + +bool LinuxDumper::HandleDeletedFileInMapping(char* path) const { + static const size_t kDeletedSuffixLen = sizeof(kDeletedSuffix) - 1; + + // Check for ' (deleted)' in |path|. + // |path| has to be at least as long as "/x (deleted)". + const size_t path_len = my_strlen(path); + if (path_len < kDeletedSuffixLen + 2) + return false; + if (my_strncmp(path + path_len - kDeletedSuffixLen, kDeletedSuffix, + kDeletedSuffixLen) != 0) { + return false; + } + + // Check |path| against the /proc/pid/exe 'symlink'. + char exe_link[NAME_MAX]; + char new_path[NAME_MAX]; + if (!BuildProcPath(exe_link, pid_, "exe")) + return false; + if (!SafeReadLink(exe_link, new_path)) + return false; + if (my_strcmp(path, new_path) != 0) + return false; + + // Check to see if someone actually named their executable 'foo (deleted)'. + struct kernel_stat exe_stat; + struct kernel_stat new_path_stat; + if (sys_stat(exe_link, &exe_stat) == 0 && + sys_stat(new_path, &new_path_stat) == 0 && + exe_stat.st_dev == new_path_stat.st_dev && + exe_stat.st_ino == new_path_stat.st_ino) { + return false; + } + + my_memcpy(path, exe_link, NAME_MAX); + return true; +} + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_dumper.h b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_dumper.h new file mode 100644 index 00000000..6a3a100f --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_dumper.h @@ -0,0 +1,254 @@ +// Copyright (c) 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// linux_dumper.h: Define the google_breakpad::LinuxDumper class, which +// is a base class for extracting information of a crashed process. It +// was originally a complete implementation using the ptrace API, but +// has been refactored to allow derived implementations supporting both +// ptrace and core dump. A portion of the original implementation is now +// in google_breakpad::LinuxPtraceDumper (see linux_ptrace_dumper.h for +// details). + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_ + +#include +#if defined(__ANDROID__) +#include +#endif +#include +#include +#include +#include + +#include "client/linux/dump_writer_common/mapping_info.h" +#include "client/linux/dump_writer_common/thread_info.h" +#include "common/memory.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +// Typedef for our parsing of the auxv variables in /proc/pid/auxv. +#if defined(__i386) || defined(__ARM_EABI__) || \ + (defined(__mips__) && _MIPS_SIM == _ABIO32) +typedef Elf32_auxv_t elf_aux_entry; +#elif defined(__x86_64) || defined(__aarch64__) || \ + (defined(__mips__) && _MIPS_SIM != _ABIO32) +typedef Elf64_auxv_t elf_aux_entry; +#endif + +typedef __typeof__(((elf_aux_entry*) 0)->a_un.a_val) elf_aux_val_t; + +// When we find the VDSO mapping in the process's address space, this +// is the name we use for it when writing it to the minidump. +// This should always be less than NAME_MAX! +const char kLinuxGateLibraryName[] = "linux-gate.so"; + +class LinuxDumper { + public: + explicit LinuxDumper(pid_t pid); + + virtual ~LinuxDumper(); + + // Parse the data for |threads| and |mappings|. + virtual bool Init(); + + // Take any actions that could not be taken in Init(). LateInit() is + // called after all other caller's initialization is complete, and in + // particular after it has called ThreadsSuspend(), so that ptrace is + // available. + virtual bool LateInit(); + + // Return true if the dumper performs a post-mortem dump. + virtual bool IsPostMortem() const = 0; + + // Suspend/resume all threads in the given process. + virtual bool ThreadsSuspend() = 0; + virtual bool ThreadsResume() = 0; + + // Read information about the |index|-th thread of |threads_|. + // Returns true on success. One must have called |ThreadsSuspend| first. + virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info) = 0; + + // These are only valid after a call to |Init|. + const wasteful_vector &threads() { return threads_; } + const wasteful_vector &mappings() { return mappings_; } + const MappingInfo* FindMapping(const void* address) const; + const wasteful_vector& auxv() { return auxv_; } + + // Find a block of memory to take as the stack given the top of stack pointer. + // stack: (output) the lowest address in the memory area + // stack_len: (output) the length of the memory area + // stack_top: the current top of the stack + bool GetStackInfo(const void** stack, size_t* stack_len, uintptr_t stack_top); + + PageAllocator* allocator() { return &allocator_; } + + // Copy content of |length| bytes from a given process |child|, + // starting from |src|, into |dest|. Returns true on success. + virtual bool CopyFromProcess(void* dest, pid_t child, const void* src, + size_t length) = 0; + + // Builds a proc path for a certain pid for a node (/proc//). + // |path| is a character array of at least NAME_MAX bytes to return the + // result.|node| is the final node without any slashes. Returns true on + // success. + virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const = 0; + + // Generate a File ID from the .text section of a mapped entry. + // If not a member, mapping_id is ignored. This method can also manipulate the + // |mapping|.name to truncate "(deleted)" from the file name if necessary. + bool ElfFileIdentifierForMapping(const MappingInfo& mapping, + bool member, + unsigned int mapping_id, + uint8_t identifier[sizeof(MDGUID)]); + + uintptr_t crash_address() const { return crash_address_; } + void set_crash_address(uintptr_t crash_address) { + crash_address_ = crash_address; + } + + int crash_signal() const { return crash_signal_; } + void set_crash_signal(int crash_signal) { crash_signal_ = crash_signal; } + + pid_t crash_thread() const { return crash_thread_; } + void set_crash_thread(pid_t crash_thread) { crash_thread_ = crash_thread; } + + // Extracts the effective path and file name of from |mapping|. In most cases + // the effective name/path are just the mapping's path and basename. In some + // other cases, however, a library can be mapped from an archive (e.g., when + // loading .so libs from an apk on Android) and this method is able to + // reconstruct the original file name. + static void GetMappingEffectiveNameAndPath(const MappingInfo& mapping, + char* file_path, + size_t file_path_size, + char* file_name, + size_t file_name_size); + + protected: + bool ReadAuxv(); + + virtual bool EnumerateMappings(); + + virtual bool EnumerateThreads() = 0; + + // For the case where a running program has been deleted, it'll show up in + // /proc/pid/maps as "/path/to/program (deleted)". If this is the case, then + // see if '/path/to/program (deleted)' matches /proc/pid/exe and return + // /proc/pid/exe in |path| so ELF identifier generation works correctly. This + // also checks to see if '/path/to/program (deleted)' exists, so it does not + // get fooled by a poorly named binary. + // For programs that don't end with ' (deleted)', this is a no-op. + // This assumes |path| is a buffer with length NAME_MAX. + // Returns true if |path| is modified. + bool HandleDeletedFileInMapping(char* path) const; + + // ID of the crashed process. + const pid_t pid_; + + // Virtual address at which the process crashed. + uintptr_t crash_address_; + + // Signal that terminated the crashed process. + int crash_signal_; + + // ID of the crashed thread. + pid_t crash_thread_; + + mutable PageAllocator allocator_; + + // IDs of all the threads. + wasteful_vector threads_; + + // Info from /proc//maps. + wasteful_vector mappings_; + + // Info from /proc//auxv + wasteful_vector auxv_; + +#if defined(__ANDROID__) + private: + // Android M and later support packed ELF relocations in shared libraries. + // Packing relocations changes the vaddr of the LOAD segments, such that + // the effective load bias is no longer the same as the start address of + // the memory mapping containing the executable parts of the library. The + // packing is applied to the stripped library run on the target, but not to + // any other library, and in particular not to the library used to generate + // breakpad symbols. As a result, we need to adjust the |start_addr| for + // any mapping that results from a shared library that contains Android + // packed relocations, so that it properly represents the effective library + // load bias. The following functions support this adjustment. + + // Check that a given mapping at |start_addr| is for an ELF shared library. + // If it is, place the ELF header in |ehdr| and return true. + // The first LOAD segment in an ELF shared library has offset zero, so the + // ELF file header is at the start of this map entry, and in already mapped + // memory. + bool GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr); + + // For the ELF file mapped at |start_addr|, iterate ELF program headers to + // find the min vaddr of all program header LOAD segments, the vaddr for + // the DYNAMIC segment, and a count of DYNAMIC entries. Return values in + // |min_vaddr_ptr|, |dyn_vaddr_ptr|, and |dyn_count_ptr|. + // The program header table is also in already mapped memory. + void ParseLoadedElfProgramHeaders(ElfW(Ehdr)* ehdr, + uintptr_t start_addr, + uintptr_t* min_vaddr_ptr, + uintptr_t* dyn_vaddr_ptr, + size_t* dyn_count_ptr); + + // Search the DYNAMIC tags for the ELF file with the given |load_bias|, and + // return true if the tags indicate that the file contains Android packed + // relocations. Dynamic tags are found at |dyn_vaddr| past the |load_bias|. + bool HasAndroidPackedRelocations(uintptr_t load_bias, + uintptr_t dyn_vaddr, + size_t dyn_count); + + // If the ELF file mapped at |start_addr| contained Android packed + // relocations, return the load bias that the system linker (or Chromium + // crazy linker) will have used. If the file did not contain Android + // packed relocations, returns |start_addr|, indicating that no adjustment + // is necessary. + // The effective load bias is |start_addr| adjusted downwards by the + // min vaddr in the library LOAD segments. + uintptr_t GetEffectiveLoadBias(ElfW(Ehdr)* ehdr, uintptr_t start_addr); + + // Called from LateInit(). Iterates |mappings_| and rewrites the |start_addr| + // field of any that represent ELF shared libraries with Android packed + // relocations, so that |start_addr| is the load bias that the system linker + // (or Chromium crazy linker) used. This value matches the addresses produced + // when the non-relocation-packed library is used for breakpad symbol + // generation. + void LatePostprocessMappings(); +#endif // __ANDROID__ +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_HANDLER_LINUX_DUMPER_H_ diff --git a/TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_ptrace_dumper.cc b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_ptrace_dumper.cc new file mode 100644 index 00000000..c35e0e95 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_ptrace_dumper.cc @@ -0,0 +1,355 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// linux_ptrace_dumper.cc: Implement google_breakpad::LinuxPtraceDumper. +// See linux_ptrace_dumper.h for detals. +// This class was originally splitted from google_breakpad::LinuxDumper. + +// This code deals with the mechanics of getting information about a crashed +// process. Since this code may run in a compromised address space, the same +// rules apply as detailed at the top of minidump_writer.h: no libc calls and +// use the alternative allocator. + +#include "client/linux/minidump_writer/linux_ptrace_dumper.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(__i386) +#include +#endif + +#include "client/linux/minidump_writer/directory_reader.h" +#include "client/linux/minidump_writer/line_reader.h" +#include "common/linux/linux_libc_support.h" +#include "third_party/lss/linux_syscall_support.h" + +// Suspends a thread by attaching to it. +static bool SuspendThread(pid_t pid) { + // This may fail if the thread has just died or debugged. + errno = 0; + if (sys_ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 && + errno != 0) { + return false; + } + while (sys_waitpid(pid, NULL, __WALL) < 0) { + if (errno != EINTR) { + sys_ptrace(PTRACE_DETACH, pid, NULL, NULL); + return false; + } + } +#if defined(__i386) || defined(__x86_64) + // On x86, the stack pointer is NULL or -1, when executing trusted code in + // the seccomp sandbox. Not only does this cause difficulties down the line + // when trying to dump the thread's stack, it also results in the minidumps + // containing information about the trusted threads. This information is + // generally completely meaningless and just pollutes the minidumps. + // We thus test the stack pointer and exclude any threads that are part of + // the seccomp sandbox's trusted code. + user_regs_struct regs; + if (sys_ptrace(PTRACE_GETREGS, pid, NULL, ®s) == -1 || +#if defined(__i386) + !regs.esp +#elif defined(__x86_64) + !regs.rsp +#endif + ) { + sys_ptrace(PTRACE_DETACH, pid, NULL, NULL); + return false; + } +#endif + return true; +} + +// Resumes a thread by detaching from it. +static bool ResumeThread(pid_t pid) { + return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0; +} + +namespace google_breakpad { + +LinuxPtraceDumper::LinuxPtraceDumper(pid_t pid) + : LinuxDumper(pid), + threads_suspended_(false) { +} + +bool LinuxPtraceDumper::BuildProcPath(char* path, pid_t pid, + const char* node) const { + if (!path || !node || pid <= 0) + return false; + + size_t node_len = my_strlen(node); + if (node_len == 0) + return false; + + const unsigned pid_len = my_uint_len(pid); + const size_t total_length = 6 + pid_len + 1 + node_len; + if (total_length >= NAME_MAX) + return false; + + my_memcpy(path, "/proc/", 6); + my_uitos(path + 6, pid, pid_len); + path[6 + pid_len] = '/'; + my_memcpy(path + 6 + pid_len + 1, node, node_len); + path[total_length] = '\0'; + return true; +} + +bool LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child, + const void* src, size_t length) { + unsigned long tmp = 55; + size_t done = 0; + static const size_t word_size = sizeof(tmp); + uint8_t* const local = (uint8_t*) dest; + uint8_t* const remote = (uint8_t*) src; + + while (done < length) { + const size_t l = (length - done > word_size) ? word_size : (length - done); + if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1) { + tmp = 0; + } + my_memcpy(local + done, &tmp, l); + done += l; + } + return true; +} + +// Read thread info from /proc/$pid/status. +// Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailable, +// these members are set to -1. Returns true iff all three members are +// available. +bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { + if (index >= threads_.size()) + return false; + + pid_t tid = threads_[index]; + + assert(info != NULL); + char status_path[NAME_MAX]; + if (!BuildProcPath(status_path, tid, "status")) + return false; + + const int fd = sys_open(status_path, O_RDONLY, 0); + if (fd < 0) + return false; + + LineReader* const line_reader = new(allocator_) LineReader(fd); + const char* line; + unsigned line_len; + + info->ppid = info->tgid = -1; + + while (line_reader->GetNextLine(&line, &line_len)) { + if (my_strncmp("Tgid:\t", line, 6) == 0) { + my_strtoui(&info->tgid, line + 6); + } else if (my_strncmp("PPid:\t", line, 6) == 0) { + my_strtoui(&info->ppid, line + 6); + } + + line_reader->PopLine(line_len); + } + sys_close(fd); + + if (info->ppid == -1 || info->tgid == -1) + return false; + +#ifdef PTRACE_GETREGSET + struct iovec io; + info->GetGeneralPurposeRegisters(&io.iov_base, &io.iov_len); + if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) { + return false; + } + + info->GetFloatingPointRegisters(&io.iov_base, &io.iov_len); + if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) { + return false; + } +#else // PTRACE_GETREGSET + void* gp_addr; + info->GetGeneralPurposeRegisters(&gp_addr, NULL); + if (sys_ptrace(PTRACE_GETREGS, tid, NULL, gp_addr) == -1) { + return false; + } + +#if !(defined(__ANDROID__) && defined(__ARM_EABI__)) + // When running an arm build on an arm64 device, attempting to get the + // floating point registers fails. On Android, the floating point registers + // aren't written to the cpu context anyway, so just don't get them here. + // See http://crbug.com/508324 + void* fp_addr; + info->GetFloatingPointRegisters(&fp_addr, NULL); + if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, fp_addr) == -1) { + return false; + } +#endif +#endif // PTRACE_GETREGSET + +#if defined(__i386) +#if !defined(bit_FXSAVE) // e.g. Clang +#define bit_FXSAVE bit_FXSR +#endif + // Detect if the CPU supports the FXSAVE/FXRSTOR instructions + int eax, ebx, ecx, edx; + __cpuid(1, eax, ebx, ecx, edx); + if (edx & bit_FXSAVE) { + if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1) { + return false; + } + } else { + memset(&info->fpxregs, 0, sizeof(info->fpxregs)); + } +#endif // defined(__i386) + +#if defined(__i386) || defined(__x86_64) + for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) { + if (sys_ptrace( + PTRACE_PEEKUSER, tid, + reinterpret_cast (offsetof(struct user, + u_debugreg[0]) + i * + sizeof(debugreg_t)), + &info->dregs[i]) == -1) { + return false; + } + } +#endif + +#if defined(__mips__) + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(DSP_BASE), &info->mcontext.hi1); + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(DSP_BASE + 1), &info->mcontext.lo1); + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(DSP_BASE + 2), &info->mcontext.hi2); + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(DSP_BASE + 3), &info->mcontext.lo2); + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(DSP_BASE + 4), &info->mcontext.hi3); + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(DSP_BASE + 5), &info->mcontext.lo3); + sys_ptrace(PTRACE_PEEKUSER, tid, + reinterpret_cast(DSP_CONTROL), &info->mcontext.dsp); +#endif + + const uint8_t* stack_pointer; +#if defined(__i386) + my_memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp)); +#elif defined(__x86_64) + my_memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp)); +#elif defined(__ARM_EABI__) + my_memcpy(&stack_pointer, &info->regs.ARM_sp, sizeof(info->regs.ARM_sp)); +#elif defined(__aarch64__) + my_memcpy(&stack_pointer, &info->regs.sp, sizeof(info->regs.sp)); +#elif defined(__mips__) + stack_pointer = + reinterpret_cast(info->mcontext.gregs[MD_CONTEXT_MIPS_REG_SP]); +#else +#error "This code hasn't been ported to your platform yet." +#endif + info->stack_pointer = reinterpret_cast(stack_pointer); + + return true; +} + +bool LinuxPtraceDumper::IsPostMortem() const { + return false; +} + +bool LinuxPtraceDumper::ThreadsSuspend() { + if (threads_suspended_) + return true; + for (size_t i = 0; i < threads_.size(); ++i) { + if (!SuspendThread(threads_[i])) { + // If the thread either disappeared before we could attach to it, or if + // it was part of the seccomp sandbox's trusted code, it is OK to + // silently drop it from the minidump. + if (i < threads_.size() - 1) { + my_memmove(&threads_[i], &threads_[i + 1], + (threads_.size() - i - 1) * sizeof(threads_[i])); + } + threads_.resize(threads_.size() - 1); + --i; + } + } + threads_suspended_ = true; + return threads_.size() > 0; +} + +bool LinuxPtraceDumper::ThreadsResume() { + if (!threads_suspended_) + return false; + bool good = true; + for (size_t i = 0; i < threads_.size(); ++i) + good &= ResumeThread(threads_[i]); + threads_suspended_ = false; + return good; +} + +// Parse /proc/$pid/task to list all the threads of the process identified by +// pid. +bool LinuxPtraceDumper::EnumerateThreads() { + char task_path[NAME_MAX]; + if (!BuildProcPath(task_path, pid_, "task")) + return false; + + const int fd = sys_open(task_path, O_RDONLY | O_DIRECTORY, 0); + if (fd < 0) + return false; + DirectoryReader* dir_reader = new(allocator_) DirectoryReader(fd); + + // The directory may contain duplicate entries which we filter by assuming + // that they are consecutive. + int last_tid = -1; + const char* dent_name; + while (dir_reader->GetNextEntry(&dent_name)) { + if (my_strcmp(dent_name, ".") && + my_strcmp(dent_name, "..")) { + int tid = 0; + if (my_strtoui(&tid, dent_name) && + last_tid != tid) { + last_tid = tid; + threads_.push_back(tid); + } + } + dir_reader->PopEntry(); + } + + sys_close(fd); + return true; +} + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_ptrace_dumper.h b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_ptrace_dumper.h new file mode 100644 index 00000000..2ce834b0 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/linux_ptrace_dumper.h @@ -0,0 +1,92 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// linux_ptrace_dumper.h: Define the google_breakpad::LinuxPtraceDumper +// class, which is derived from google_breakpad::LinuxDumper to extract +// information from a crashed process via ptrace. +// This class was originally splitted from google_breakpad::LinuxDumper. + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_PTRACE_DUMPER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_PTRACE_DUMPER_H_ + +#include "client/linux/minidump_writer/linux_dumper.h" + +namespace google_breakpad { + +class LinuxPtraceDumper : public LinuxDumper { + public: + // Constructs a dumper for extracting information of a given process + // with a process ID of |pid|. + explicit LinuxPtraceDumper(pid_t pid); + + // Implements LinuxDumper::BuildProcPath(). + // Builds a proc path for a certain pid for a node (/proc//). + // |path| is a character array of at least NAME_MAX bytes to return the + // result. |node| is the final node without any slashes. Returns true on + // success. + virtual bool BuildProcPath(char* path, pid_t pid, const char* node) const; + + // Implements LinuxDumper::CopyFromProcess(). + // Copies content of |length| bytes from a given process |child|, + // starting from |src|, into |dest|. This method uses ptrace to extract + // the content from the target process. Always returns true. + virtual bool CopyFromProcess(void* dest, pid_t child, const void* src, + size_t length); + + // Implements LinuxDumper::GetThreadInfoByIndex(). + // Reads information about the |index|-th thread of |threads_|. + // Returns true on success. One must have called |ThreadsSuspend| first. + virtual bool GetThreadInfoByIndex(size_t index, ThreadInfo* info); + + // Implements LinuxDumper::IsPostMortem(). + // Always returns false to indicate this dumper performs a dump of + // a crashed process via ptrace. + virtual bool IsPostMortem() const; + + // Implements LinuxDumper::ThreadsSuspend(). + // Suspends all threads in the given process. Returns true on success. + virtual bool ThreadsSuspend(); + + // Implements LinuxDumper::ThreadsResume(). + // Resumes all threads in the given process. Returns true on success. + virtual bool ThreadsResume(); + + protected: + // Implements LinuxDumper::EnumerateThreads(). + // Enumerates all threads of the given process into |threads_|. + virtual bool EnumerateThreads(); + + private: + // Set to true if all threads of the crashed process are suspended. + bool threads_suspended_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_HANDLER_LINUX_PTRACE_DUMPER_H_ diff --git a/TMessagesProj/jni/breakpad/client/linux/minidump_writer/minidump_writer.cc b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/minidump_writer.cc new file mode 100644 index 00000000..4b1e6f87 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/minidump_writer.cc @@ -0,0 +1,1367 @@ +// Copyright (c) 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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 code writes out minidump files: +// http://msdn.microsoft.com/en-us/library/ms680378(VS.85,loband).aspx +// +// Minidumps are a Microsoft format which Breakpad uses for recording crash +// dumps. This code has to run in a compromised environment (the address space +// may have received SIGSEGV), thus the following rules apply: +// * You may not enter the dynamic linker. This means that we cannot call +// any symbols in a shared library (inc libc). Because of this we replace +// libc functions in linux_libc_support.h. +// * You may not call syscalls via the libc wrappers. This rule is a subset +// of the first rule but it bears repeating. We have direct wrappers +// around the system calls in linux_syscall_support.h. +// * You may not malloc. There's an alternative allocator in memory.h and +// a canonical instance in the LinuxDumper object. We use the placement +// new form to allocate objects and we don't delete them. + +#include "client/linux/handler/minidump_descriptor.h" +#include "client/linux/minidump_writer/minidump_writer.h" +#include "client/minidump_file_writer-inl.h" + +#include +#include +#include +#include +#include +#if defined(__ANDROID__) +#include +#endif +#include +#include +#include +#include +#include +#include + +#include + +#include "client/linux/dump_writer_common/thread_info.h" +#include "client/linux/dump_writer_common/ucontext_reader.h" +#include "client/linux/handler/exception_handler.h" +#include "client/linux/minidump_writer/cpu_set.h" +#include "client/linux/minidump_writer/line_reader.h" +#include "client/linux/minidump_writer/linux_dumper.h" +#include "client/linux/minidump_writer/linux_ptrace_dumper.h" +#include "client/linux/minidump_writer/proc_cpuinfo_reader.h" +#include "client/minidump_file_writer.h" +#include "common/linux/linux_libc_support.h" +#include "common/minidump_type_helper.h" +#include "google_breakpad/common/minidump_format.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace { + +using google_breakpad::AppMemoryList; +using google_breakpad::ExceptionHandler; +using google_breakpad::CpuSet; +using google_breakpad::LineReader; +using google_breakpad::LinuxDumper; +using google_breakpad::LinuxPtraceDumper; +using google_breakpad::MDTypeHelper; +using google_breakpad::MappingEntry; +using google_breakpad::MappingInfo; +using google_breakpad::MappingList; +using google_breakpad::MinidumpFileWriter; +using google_breakpad::PageAllocator; +using google_breakpad::ProcCpuInfoReader; +using google_breakpad::RawContextCPU; +using google_breakpad::ThreadInfo; +using google_breakpad::TypedMDRVA; +using google_breakpad::UContextReader; +using google_breakpad::UntypedMDRVA; +using google_breakpad::wasteful_vector; + +typedef MDTypeHelper::MDRawDebug MDRawDebug; +typedef MDTypeHelper::MDRawLinkMap MDRawLinkMap; + +class MinidumpWriter { + public: + // The following kLimit* constants are for when minidump_size_limit_ is set + // and the minidump size might exceed it. + // + // Estimate for how big each thread's stack will be (in bytes). + static const unsigned kLimitAverageThreadStackLength = 8 * 1024; + // Number of threads whose stack size we don't want to limit. These base + // threads will simply be the first N threads returned by the dumper (although + // the crashing thread will never be limited). Threads beyond this count are + // the extra threads. + static const unsigned kLimitBaseThreadCount = 20; + // Maximum stack size to dump for any extra thread (in bytes). + static const unsigned kLimitMaxExtraThreadStackLen = 2 * 1024; + // Make sure this number of additional bytes can fit in the minidump + // (exclude the stack data). + static const unsigned kLimitMinidumpFudgeFactor = 64 * 1024; + + MinidumpWriter(const char* minidump_path, + int minidump_fd, + const ExceptionHandler::CrashContext* context, + const MappingList& mappings, + const AppMemoryList& appmem, + LinuxDumper* dumper) + : fd_(minidump_fd), + path_(minidump_path), + ucontext_(context ? &context->context : NULL), +#if !defined(__ARM_EABI__) && !defined(__mips__) + float_state_(context ? &context->float_state : NULL), +#endif + dumper_(dumper), + minidump_size_limit_(-1), + memory_blocks_(dumper_->allocator()), + mapping_list_(mappings), + app_memory_list_(appmem) { + // Assert there should be either a valid fd or a valid path, not both. + assert(fd_ != -1 || minidump_path); + assert(fd_ == -1 || !minidump_path); + } + + bool Init() { + if (!dumper_->Init()) + return false; + + if (fd_ != -1) + minidump_writer_.SetFile(fd_); + else if (!minidump_writer_.Open(path_)) + return false; + + return dumper_->ThreadsSuspend() && dumper_->LateInit(); + } + + ~MinidumpWriter() { + // Don't close the file descriptor when it's been provided explicitly. + // Callers might still need to use it. + if (fd_ == -1) + minidump_writer_.Close(); + dumper_->ThreadsResume(); + } + + bool Dump() { + // A minidump file contains a number of tagged streams. This is the number + // of stream which we write. + unsigned kNumWriters = 13; + + TypedMDRVA header(&minidump_writer_); + TypedMDRVA dir(&minidump_writer_); + if (!header.Allocate()) + return false; + if (!dir.AllocateArray(kNumWriters)) + return false; + my_memset(header.get(), 0, sizeof(MDRawHeader)); + + header.get()->signature = MD_HEADER_SIGNATURE; + header.get()->version = MD_HEADER_VERSION; + header.get()->time_date_stamp = time(NULL); + header.get()->stream_count = kNumWriters; + header.get()->stream_directory_rva = dir.position(); + + unsigned dir_index = 0; + MDRawDirectory dirent; + + if (!WriteThreadListStream(&dirent)) + return false; + dir.CopyIndex(dir_index++, &dirent); + + if (!WriteMappings(&dirent)) + return false; + dir.CopyIndex(dir_index++, &dirent); + + if (!WriteAppMemory()) + return false; + + if (!WriteMemoryListStream(&dirent)) + return false; + dir.CopyIndex(dir_index++, &dirent); + + if (!WriteExceptionStream(&dirent)) + return false; + dir.CopyIndex(dir_index++, &dirent); + + if (!WriteSystemInfoStream(&dirent)) + return false; + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_CPU_INFO; + if (!WriteFile(&dirent.location, "/proc/cpuinfo")) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_PROC_STATUS; + if (!WriteProcFile(&dirent.location, GetCrashThread(), "status")) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_LSB_RELEASE; + if (!WriteFile(&dirent.location, "/etc/lsb-release")) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_CMD_LINE; + if (!WriteProcFile(&dirent.location, GetCrashThread(), "cmdline")) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_ENVIRON; + if (!WriteProcFile(&dirent.location, GetCrashThread(), "environ")) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_AUXV; + if (!WriteProcFile(&dirent.location, GetCrashThread(), "auxv")) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_MAPS; + if (!WriteProcFile(&dirent.location, GetCrashThread(), "maps")) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + dirent.stream_type = MD_LINUX_DSO_DEBUG; + if (!WriteDSODebugStream(&dirent)) + NullifyDirectoryEntry(&dirent); + dir.CopyIndex(dir_index++, &dirent); + + // If you add more directory entries, don't forget to update kNumWriters, + // above. + + dumper_->ThreadsResume(); + return true; + } + + bool FillThreadStack(MDRawThread* thread, uintptr_t stack_pointer, + int max_stack_len, uint8_t** stack_copy) { + *stack_copy = NULL; + const void* stack; + size_t stack_len; + if (dumper_->GetStackInfo(&stack, &stack_len, stack_pointer)) { + UntypedMDRVA memory(&minidump_writer_); + if (max_stack_len >= 0 && + stack_len > static_cast(max_stack_len)) { + stack_len = max_stack_len; + } + if (!memory.Allocate(stack_len)) + return false; + *stack_copy = reinterpret_cast(Alloc(stack_len)); + dumper_->CopyFromProcess(*stack_copy, thread->thread_id, stack, + stack_len); + memory.Copy(*stack_copy, stack_len); + thread->stack.start_of_memory_range = + reinterpret_cast(stack); + thread->stack.memory = memory.location(); + memory_blocks_.push_back(thread->stack); + } else { + thread->stack.start_of_memory_range = stack_pointer; + thread->stack.memory.data_size = 0; + thread->stack.memory.rva = minidump_writer_.position(); + } + return true; + } + + // Write information about the threads. + bool WriteThreadListStream(MDRawDirectory* dirent) { + const unsigned num_threads = dumper_->threads().size(); + + TypedMDRVA list(&minidump_writer_); + if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread))) + return false; + + dirent->stream_type = MD_THREAD_LIST_STREAM; + dirent->location = list.location(); + + *list.get() = num_threads; + + // If there's a minidump size limit, check if it might be exceeded. Since + // most of the space is filled with stack data, just check against that. + // If this expects to exceed the limit, set extra_thread_stack_len such + // that any thread beyond the first kLimitBaseThreadCount threads will + // have only kLimitMaxExtraThreadStackLen bytes dumped. + int extra_thread_stack_len = -1; // default to no maximum + if (minidump_size_limit_ >= 0) { + const unsigned estimated_total_stack_size = num_threads * + kLimitAverageThreadStackLength; + const off_t estimated_minidump_size = minidump_writer_.position() + + estimated_total_stack_size + kLimitMinidumpFudgeFactor; + if (estimated_minidump_size > minidump_size_limit_) + extra_thread_stack_len = kLimitMaxExtraThreadStackLen; + } + + for (unsigned i = 0; i < num_threads; ++i) { + MDRawThread thread; + my_memset(&thread, 0, sizeof(thread)); + thread.thread_id = dumper_->threads()[i]; + + // We have a different source of information for the crashing thread. If + // we used the actual state of the thread we would find it running in the + // signal handler with the alternative stack, which would be deeply + // unhelpful. + if (static_cast(thread.thread_id) == GetCrashThread() && + ucontext_ && + !dumper_->IsPostMortem()) { + uint8_t* stack_copy; + const uintptr_t stack_ptr = UContextReader::GetStackPointer(ucontext_); + if (!FillThreadStack(&thread, stack_ptr, -1, &stack_copy)) + return false; + + // Copy 256 bytes around crashing instruction pointer to minidump. + const size_t kIPMemorySize = 256; + uint64_t ip = UContextReader::GetInstructionPointer(ucontext_); + // Bound it to the upper and lower bounds of the memory map + // it's contained within. If it's not in mapped memory, + // don't bother trying to write it. + bool ip_is_mapped = false; + MDMemoryDescriptor ip_memory_d; + for (unsigned j = 0; j < dumper_->mappings().size(); ++j) { + const MappingInfo& mapping = *dumper_->mappings()[j]; + if (ip >= mapping.start_addr && + ip < mapping.start_addr + mapping.size) { + ip_is_mapped = true; + // Try to get 128 bytes before and after the IP, but + // settle for whatever's available. + ip_memory_d.start_of_memory_range = + std::max(mapping.start_addr, + uintptr_t(ip - (kIPMemorySize / 2))); + uintptr_t end_of_range = + std::min(uintptr_t(ip + (kIPMemorySize / 2)), + uintptr_t(mapping.start_addr + mapping.size)); + ip_memory_d.memory.data_size = + end_of_range - ip_memory_d.start_of_memory_range; + break; + } + } + + if (ip_is_mapped) { + UntypedMDRVA ip_memory(&minidump_writer_); + if (!ip_memory.Allocate(ip_memory_d.memory.data_size)) + return false; + uint8_t* memory_copy = + reinterpret_cast(Alloc(ip_memory_d.memory.data_size)); + dumper_->CopyFromProcess( + memory_copy, + thread.thread_id, + reinterpret_cast(ip_memory_d.start_of_memory_range), + ip_memory_d.memory.data_size); + ip_memory.Copy(memory_copy, ip_memory_d.memory.data_size); + ip_memory_d.memory = ip_memory.location(); + memory_blocks_.push_back(ip_memory_d); + } + + TypedMDRVA cpu(&minidump_writer_); + if (!cpu.Allocate()) + return false; + my_memset(cpu.get(), 0, sizeof(RawContextCPU)); +#if !defined(__ARM_EABI__) && !defined(__mips__) + UContextReader::FillCPUContext(cpu.get(), ucontext_, float_state_); +#else + UContextReader::FillCPUContext(cpu.get(), ucontext_); +#endif + thread.thread_context = cpu.location(); + crashing_thread_context_ = cpu.location(); + } else { + ThreadInfo info; + if (!dumper_->GetThreadInfoByIndex(i, &info)) + return false; + + uint8_t* stack_copy; + int max_stack_len = -1; // default to no maximum for this thread + if (minidump_size_limit_ >= 0 && i >= kLimitBaseThreadCount) + max_stack_len = extra_thread_stack_len; + if (!FillThreadStack(&thread, info.stack_pointer, max_stack_len, + &stack_copy)) + return false; + + TypedMDRVA cpu(&minidump_writer_); + if (!cpu.Allocate()) + return false; + my_memset(cpu.get(), 0, sizeof(RawContextCPU)); + info.FillCPUContext(cpu.get()); + thread.thread_context = cpu.location(); + if (dumper_->threads()[i] == GetCrashThread()) { + crashing_thread_context_ = cpu.location(); + if (!dumper_->IsPostMortem()) { + // This is the crashing thread of a live process, but + // no context was provided, so set the crash address + // while the instruction pointer is already here. + dumper_->set_crash_address(info.GetInstructionPointer()); + } + } + } + + list.CopyIndexAfterObject(i, &thread, sizeof(thread)); + } + + return true; + } + + // Write application-provided memory regions. + bool WriteAppMemory() { + for (AppMemoryList::const_iterator iter = app_memory_list_.begin(); + iter != app_memory_list_.end(); + ++iter) { + uint8_t* data_copy = + reinterpret_cast(dumper_->allocator()->Alloc(iter->length)); + dumper_->CopyFromProcess(data_copy, GetCrashThread(), iter->ptr, + iter->length); + + UntypedMDRVA memory(&minidump_writer_); + if (!memory.Allocate(iter->length)) { + return false; + } + memory.Copy(data_copy, iter->length); + MDMemoryDescriptor desc; + desc.start_of_memory_range = reinterpret_cast(iter->ptr); + desc.memory = memory.location(); + memory_blocks_.push_back(desc); + } + + return true; + } + + static bool ShouldIncludeMapping(const MappingInfo& mapping) { + if (mapping.name[0] == 0 || // only want modules with filenames. + // Only want to include one mapping per shared lib. + // Avoid filtering executable mappings. + (mapping.offset != 0 && !mapping.exec) || + mapping.size < 4096) { // too small to get a signature for. + return false; + } + + return true; + } + + // If there is caller-provided information about this mapping + // in the mapping_list_ list, return true. Otherwise, return false. + bool HaveMappingInfo(const MappingInfo& mapping) { + for (MappingList::const_iterator iter = mapping_list_.begin(); + iter != mapping_list_.end(); + ++iter) { + // Ignore any mappings that are wholly contained within + // mappings in the mapping_info_ list. + if (mapping.start_addr >= iter->first.start_addr && + (mapping.start_addr + mapping.size) <= + (iter->first.start_addr + iter->first.size)) { + return true; + } + } + return false; + } + + // Write information about the mappings in effect. Because we are using the + // minidump format, the information about the mappings is pretty limited. + // Because of this, we also include the full, unparsed, /proc/$x/maps file in + // another stream in the file. + bool WriteMappings(MDRawDirectory* dirent) { + const unsigned num_mappings = dumper_->mappings().size(); + unsigned num_output_mappings = mapping_list_.size(); + + for (unsigned i = 0; i < dumper_->mappings().size(); ++i) { + const MappingInfo& mapping = *dumper_->mappings()[i]; + if (ShouldIncludeMapping(mapping) && !HaveMappingInfo(mapping)) + num_output_mappings++; + } + + TypedMDRVA list(&minidump_writer_); + if (num_output_mappings) { + if (!list.AllocateObjectAndArray(num_output_mappings, MD_MODULE_SIZE)) + return false; + } else { + // Still create the module list stream, although it will have zero + // modules. + if (!list.Allocate()) + return false; + } + + dirent->stream_type = MD_MODULE_LIST_STREAM; + dirent->location = list.location(); + *list.get() = num_output_mappings; + + // First write all the mappings from the dumper + unsigned int j = 0; + for (unsigned i = 0; i < num_mappings; ++i) { + const MappingInfo& mapping = *dumper_->mappings()[i]; + if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping)) + continue; + + MDRawModule mod; + if (!FillRawModule(mapping, true, i, mod, NULL)) + return false; + list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); + } + // Next write all the mappings provided by the caller + for (MappingList::const_iterator iter = mapping_list_.begin(); + iter != mapping_list_.end(); + ++iter) { + MDRawModule mod; + if (!FillRawModule(iter->first, false, 0, mod, iter->second)) + return false; + list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); + } + + return true; + } + + // Fill the MDRawModule |mod| with information about the provided + // |mapping|. If |identifier| is non-NULL, use it instead of calculating + // a file ID from the mapping. + bool FillRawModule(const MappingInfo& mapping, + bool member, + unsigned int mapping_id, + MDRawModule& mod, + const uint8_t* identifier) { + my_memset(&mod, 0, MD_MODULE_SIZE); + + mod.base_of_image = mapping.start_addr; + mod.size_of_image = mapping.size; + + uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX]; + uint8_t* cv_ptr = cv_buf; + + const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE; + my_memcpy(cv_ptr, &cv_signature, sizeof(cv_signature)); + cv_ptr += sizeof(cv_signature); + uint8_t* signature = cv_ptr; + cv_ptr += sizeof(MDGUID); + if (identifier) { + // GUID was provided by caller. + my_memcpy(signature, identifier, sizeof(MDGUID)); + } else { + // Note: ElfFileIdentifierForMapping() can manipulate the |mapping.name|. + dumper_->ElfFileIdentifierForMapping(mapping, member, + mapping_id, signature); + } + my_memset(cv_ptr, 0, sizeof(uint32_t)); // Set age to 0 on Linux. + cv_ptr += sizeof(uint32_t); + + char file_name[NAME_MAX]; + char file_path[NAME_MAX]; + LinuxDumper::GetMappingEffectiveNameAndPath( + mapping, file_path, sizeof(file_path), file_name, sizeof(file_name)); + + const size_t file_name_len = my_strlen(file_name); + UntypedMDRVA cv(&minidump_writer_); + if (!cv.Allocate(MDCVInfoPDB70_minsize + file_name_len + 1)) + return false; + + // Write pdb_file_name + my_memcpy(cv_ptr, file_name, file_name_len + 1); + cv.Copy(cv_buf, MDCVInfoPDB70_minsize + file_name_len + 1); + + mod.cv_record = cv.location(); + + MDLocationDescriptor ld; + if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld)) + return false; + mod.module_name_rva = ld.rva; + return true; + } + + bool WriteMemoryListStream(MDRawDirectory* dirent) { + TypedMDRVA list(&minidump_writer_); + if (memory_blocks_.size()) { + if (!list.AllocateObjectAndArray(memory_blocks_.size(), + sizeof(MDMemoryDescriptor))) + return false; + } else { + // Still create the memory list stream, although it will have zero + // memory blocks. + if (!list.Allocate()) + return false; + } + + dirent->stream_type = MD_MEMORY_LIST_STREAM; + dirent->location = list.location(); + + *list.get() = memory_blocks_.size(); + + for (size_t i = 0; i < memory_blocks_.size(); ++i) { + list.CopyIndexAfterObject(i, &memory_blocks_[i], + sizeof(MDMemoryDescriptor)); + } + return true; + } + + bool WriteExceptionStream(MDRawDirectory* dirent) { + TypedMDRVA exc(&minidump_writer_); + if (!exc.Allocate()) + return false; + my_memset(exc.get(), 0, sizeof(MDRawExceptionStream)); + + dirent->stream_type = MD_EXCEPTION_STREAM; + dirent->location = exc.location(); + + exc.get()->thread_id = GetCrashThread(); + exc.get()->exception_record.exception_code = dumper_->crash_signal(); + exc.get()->exception_record.exception_address = dumper_->crash_address(); + exc.get()->thread_context = crashing_thread_context_; + + return true; + } + + bool WriteSystemInfoStream(MDRawDirectory* dirent) { + TypedMDRVA si(&minidump_writer_); + if (!si.Allocate()) + return false; + my_memset(si.get(), 0, sizeof(MDRawSystemInfo)); + + dirent->stream_type = MD_SYSTEM_INFO_STREAM; + dirent->location = si.location(); + + WriteCPUInformation(si.get()); + WriteOSInformation(si.get()); + + return true; + } + + bool WriteDSODebugStream(MDRawDirectory* dirent) { + ElfW(Phdr)* phdr = reinterpret_cast(dumper_->auxv()[AT_PHDR]); + char* base; + int phnum = dumper_->auxv()[AT_PHNUM]; + if (!phnum || !phdr) + return false; + + // Assume the program base is at the beginning of the same page as the PHDR + base = reinterpret_cast(reinterpret_cast(phdr) & ~0xfff); + + // Search for the program PT_DYNAMIC segment + ElfW(Addr) dyn_addr = 0; + for (; phnum >= 0; phnum--, phdr++) { + ElfW(Phdr) ph; + if (!dumper_->CopyFromProcess(&ph, GetCrashThread(), phdr, sizeof(ph))) + return false; + + // Adjust base address with the virtual address of the PT_LOAD segment + // corresponding to offset 0 + if (ph.p_type == PT_LOAD && ph.p_offset == 0) { + base -= ph.p_vaddr; + } + if (ph.p_type == PT_DYNAMIC) { + dyn_addr = ph.p_vaddr; + } + } + if (!dyn_addr) + return false; + + ElfW(Dyn) *dynamic = reinterpret_cast(dyn_addr + base); + + // The dynamic linker makes information available that helps gdb find all + // DSOs loaded into the program. If this information is indeed available, + // dump it to a MD_LINUX_DSO_DEBUG stream. + struct r_debug* r_debug = NULL; + uint32_t dynamic_length = 0; + + for (int i = 0; ; ++i) { + ElfW(Dyn) dyn; + dynamic_length += sizeof(dyn); + if (!dumper_->CopyFromProcess(&dyn, GetCrashThread(), dynamic + i, + sizeof(dyn))) { + return false; + } + +#ifdef __mips__ + if (dyn.d_tag == DT_MIPS_RLD_MAP) { + r_debug = reinterpret_cast(dyn.d_un.d_ptr); + continue; + } +#else + if (dyn.d_tag == DT_DEBUG) { + r_debug = reinterpret_cast(dyn.d_un.d_ptr); + continue; + } +#endif + else if (dyn.d_tag == DT_NULL) { + break; + } + } + + // The "r_map" field of that r_debug struct contains a linked list of all + // loaded DSOs. + // Our list of DSOs potentially is different from the ones in the crashing + // process. So, we have to be careful to never dereference pointers + // directly. Instead, we use CopyFromProcess() everywhere. + // See for a more detailed discussion of the how the dynamic + // loader communicates with debuggers. + + // Count the number of loaded DSOs + int dso_count = 0; + struct r_debug debug_entry; + if (!dumper_->CopyFromProcess(&debug_entry, GetCrashThread(), r_debug, + sizeof(debug_entry))) { + return false; + } + for (struct link_map* ptr = debug_entry.r_map; ptr; ) { + struct link_map map; + if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map))) + return false; + + ptr = map.l_next; + dso_count++; + } + + MDRVA linkmap_rva = minidump_writer_.kInvalidMDRVA; + if (dso_count > 0) { + // If we have at least one DSO, create an array of MDRawLinkMap + // entries in the minidump file. + TypedMDRVA linkmap(&minidump_writer_); + if (!linkmap.AllocateArray(dso_count)) + return false; + linkmap_rva = linkmap.location().rva; + int idx = 0; + + // Iterate over DSOs and write their information to mini dump + for (struct link_map* ptr = debug_entry.r_map; ptr; ) { + struct link_map map; + if (!dumper_->CopyFromProcess(&map, GetCrashThread(), ptr, sizeof(map))) + return false; + + ptr = map.l_next; + char filename[257] = { 0 }; + if (map.l_name) { + dumper_->CopyFromProcess(filename, GetCrashThread(), map.l_name, + sizeof(filename) - 1); + } + MDLocationDescriptor location; + if (!minidump_writer_.WriteString(filename, 0, &location)) + return false; + MDRawLinkMap entry; + entry.name = location.rva; + entry.addr = map.l_addr; + entry.ld = reinterpret_cast(map.l_ld); + linkmap.CopyIndex(idx++, &entry); + } + } + + // Write MD_LINUX_DSO_DEBUG record + TypedMDRVA debug(&minidump_writer_); + if (!debug.AllocateObjectAndArray(1, dynamic_length)) + return false; + my_memset(debug.get(), 0, sizeof(MDRawDebug)); + dirent->stream_type = MD_LINUX_DSO_DEBUG; + dirent->location = debug.location(); + + debug.get()->version = debug_entry.r_version; + debug.get()->map = linkmap_rva; + debug.get()->dso_count = dso_count; + debug.get()->brk = debug_entry.r_brk; + debug.get()->ldbase = debug_entry.r_ldbase; + debug.get()->dynamic = reinterpret_cast(dynamic); + + wasteful_vector dso_debug_data(dumper_->allocator(), dynamic_length); + // The passed-in size to the constructor (above) is only a hint. + // Must call .resize() to do actual initialization of the elements. + dso_debug_data.resize(dynamic_length); + dumper_->CopyFromProcess(&dso_debug_data[0], GetCrashThread(), dynamic, + dynamic_length); + debug.CopyIndexAfterObject(0, &dso_debug_data[0], dynamic_length); + + return true; + } + + void set_minidump_size_limit(off_t limit) { minidump_size_limit_ = limit; } + + private: + void* Alloc(unsigned bytes) { + return dumper_->allocator()->Alloc(bytes); + } + + pid_t GetCrashThread() const { + return dumper_->crash_thread(); + } + + void NullifyDirectoryEntry(MDRawDirectory* dirent) { + dirent->stream_type = 0; + dirent->location.data_size = 0; + dirent->location.rva = 0; + } + +#if defined(__i386__) || defined(__x86_64__) || defined(__mips__) + bool WriteCPUInformation(MDRawSystemInfo* sys_info) { + char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0}; + static const char vendor_id_name[] = "vendor_id"; + + struct CpuInfoEntry { + const char* info_name; + int value; + bool found; + } cpu_info_table[] = { + { "processor", -1, false }, +#if defined(__i386__) || defined(__x86_64__) + { "model", 0, false }, + { "stepping", 0, false }, + { "cpu family", 0, false }, +#endif + }; + + // processor_architecture should always be set, do this first + sys_info->processor_architecture = +#if defined(__mips__) + MD_CPU_ARCHITECTURE_MIPS; +#elif defined(__i386__) + MD_CPU_ARCHITECTURE_X86; +#else + MD_CPU_ARCHITECTURE_AMD64; +#endif + + const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0); + if (fd < 0) + return false; + + { + PageAllocator allocator; + ProcCpuInfoReader* const reader = new(allocator) ProcCpuInfoReader(fd); + const char* field; + while (reader->GetNextField(&field)) { + for (size_t i = 0; + i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]); + i++) { + CpuInfoEntry* entry = &cpu_info_table[i]; + if (i > 0 && entry->found) { + // except for the 'processor' field, ignore repeated values. + continue; + } + if (!my_strcmp(field, entry->info_name)) { + size_t value_len; + const char* value = reader->GetValueAndLen(&value_len); + if (value_len == 0) + continue; + + uintptr_t val; + if (my_read_decimal_ptr(&val, value) == value) + continue; + + entry->value = static_cast(val); + entry->found = true; + } + } + + // special case for vendor_id + if (!my_strcmp(field, vendor_id_name)) { + size_t value_len; + const char* value = reader->GetValueAndLen(&value_len); + if (value_len > 0) + my_strlcpy(vendor_id, value, sizeof(vendor_id)); + } + } + sys_close(fd); + } + + // make sure we got everything we wanted + for (size_t i = 0; + i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]); + i++) { + if (!cpu_info_table[i].found) { + return false; + } + } + // cpu_info_table[0] holds the last cpu id listed in /proc/cpuinfo, + // assuming this is the highest id, change it to the number of CPUs + // by adding one. + cpu_info_table[0].value++; + + sys_info->number_of_processors = cpu_info_table[0].value; +#if defined(__i386__) || defined(__x86_64__) + sys_info->processor_level = cpu_info_table[3].value; + sys_info->processor_revision = cpu_info_table[1].value << 8 | + cpu_info_table[2].value; +#endif + + if (vendor_id[0] != '\0') { + my_memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id, + sizeof(sys_info->cpu.x86_cpu_info.vendor_id)); + } + return true; + } +#elif defined(__arm__) || defined(__aarch64__) + bool WriteCPUInformation(MDRawSystemInfo* sys_info) { + // The CPUID value is broken up in several entries in /proc/cpuinfo. + // This table is used to rebuild it from the entries. + const struct CpuIdEntry { + const char* field; + char format; + char bit_lshift; + char bit_length; + } cpu_id_entries[] = { + { "CPU implementer", 'x', 24, 8 }, + { "CPU variant", 'x', 20, 4 }, + { "CPU part", 'x', 4, 12 }, + { "CPU revision", 'd', 0, 4 }, + }; + + // The ELF hwcaps are listed in the "Features" entry as textual tags. + // This table is used to rebuild them. + const struct CpuFeaturesEntry { + const char* tag; + uint32_t hwcaps; + } cpu_features_entries[] = { +#if defined(__arm__) + { "swp", MD_CPU_ARM_ELF_HWCAP_SWP }, + { "half", MD_CPU_ARM_ELF_HWCAP_HALF }, + { "thumb", MD_CPU_ARM_ELF_HWCAP_THUMB }, + { "26bit", MD_CPU_ARM_ELF_HWCAP_26BIT }, + { "fastmult", MD_CPU_ARM_ELF_HWCAP_FAST_MULT }, + { "fpa", MD_CPU_ARM_ELF_HWCAP_FPA }, + { "vfp", MD_CPU_ARM_ELF_HWCAP_VFP }, + { "edsp", MD_CPU_ARM_ELF_HWCAP_EDSP }, + { "java", MD_CPU_ARM_ELF_HWCAP_JAVA }, + { "iwmmxt", MD_CPU_ARM_ELF_HWCAP_IWMMXT }, + { "crunch", MD_CPU_ARM_ELF_HWCAP_CRUNCH }, + { "thumbee", MD_CPU_ARM_ELF_HWCAP_THUMBEE }, + { "neon", MD_CPU_ARM_ELF_HWCAP_NEON }, + { "vfpv3", MD_CPU_ARM_ELF_HWCAP_VFPv3 }, + { "vfpv3d16", MD_CPU_ARM_ELF_HWCAP_VFPv3D16 }, + { "tls", MD_CPU_ARM_ELF_HWCAP_TLS }, + { "vfpv4", MD_CPU_ARM_ELF_HWCAP_VFPv4 }, + { "idiva", MD_CPU_ARM_ELF_HWCAP_IDIVA }, + { "idivt", MD_CPU_ARM_ELF_HWCAP_IDIVT }, + { "idiv", MD_CPU_ARM_ELF_HWCAP_IDIVA | MD_CPU_ARM_ELF_HWCAP_IDIVT }, +#elif defined(__aarch64__) + // No hwcaps on aarch64. +#endif + }; + + // processor_architecture should always be set, do this first + sys_info->processor_architecture = +#if defined(__aarch64__) + MD_CPU_ARCHITECTURE_ARM64; +#else + MD_CPU_ARCHITECTURE_ARM; +#endif + + // /proc/cpuinfo is not readable under various sandboxed environments + // (e.g. Android services with the android:isolatedProcess attribute) + // prepare for this by setting default values now, which will be + // returned when this happens. + // + // Note: Bogus values are used to distinguish between failures (to + // read /sys and /proc files) and really badly configured kernels. + sys_info->number_of_processors = 0; + sys_info->processor_level = 1U; // There is no ARMv1 + sys_info->processor_revision = 42; + sys_info->cpu.arm_cpu_info.cpuid = 0; + sys_info->cpu.arm_cpu_info.elf_hwcaps = 0; + + // Counting the number of CPUs involves parsing two sysfs files, + // because the content of /proc/cpuinfo will only mirror the number + // of 'online' cores, and thus will vary with time. + // See http://www.kernel.org/doc/Documentation/cputopology.txt + { + CpuSet cpus_present; + CpuSet cpus_possible; + + int fd = sys_open("/sys/devices/system/cpu/present", O_RDONLY, 0); + if (fd >= 0) { + cpus_present.ParseSysFile(fd); + sys_close(fd); + + fd = sys_open("/sys/devices/system/cpu/possible", O_RDONLY, 0); + if (fd >= 0) { + cpus_possible.ParseSysFile(fd); + sys_close(fd); + + cpus_present.IntersectWith(cpus_possible); + int cpu_count = cpus_present.GetCount(); + if (cpu_count > 255) + cpu_count = 255; + sys_info->number_of_processors = static_cast(cpu_count); + } + } + } + + // Parse /proc/cpuinfo to reconstruct the CPUID value, as well + // as the ELF hwcaps field. For the latter, it would be easier to + // read /proc/self/auxv but unfortunately, this file is not always + // readable from regular Android applications on later versions + // (>= 4.1) of the Android platform. + const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0); + if (fd < 0) { + // Do not return false here to allow the minidump generation + // to happen properly. + return true; + } + + { + PageAllocator allocator; + ProcCpuInfoReader* const reader = + new(allocator) ProcCpuInfoReader(fd); + const char* field; + while (reader->GetNextField(&field)) { + for (size_t i = 0; + i < sizeof(cpu_id_entries)/sizeof(cpu_id_entries[0]); + ++i) { + const CpuIdEntry* entry = &cpu_id_entries[i]; + if (my_strcmp(entry->field, field) != 0) + continue; + uintptr_t result = 0; + const char* value = reader->GetValue(); + const char* p = value; + if (value[0] == '0' && value[1] == 'x') { + p = my_read_hex_ptr(&result, value+2); + } else if (entry->format == 'x') { + p = my_read_hex_ptr(&result, value); + } else { + p = my_read_decimal_ptr(&result, value); + } + if (p == value) + continue; + + result &= (1U << entry->bit_length)-1; + result <<= entry->bit_lshift; + sys_info->cpu.arm_cpu_info.cpuid |= + static_cast(result); + } +#if defined(__arm__) + // Get the architecture version from the "Processor" field. + // Note that it is also available in the "CPU architecture" field, + // however, some existing kernels are misconfigured and will report + // invalid values here (e.g. 6, while the CPU is ARMv7-A based). + // The "Processor" field doesn't have this issue. + if (!my_strcmp(field, "Processor")) { + size_t value_len; + const char* value = reader->GetValueAndLen(&value_len); + // Expected format: (v) + // Where is some text like "ARMv7 Processor rev 2" + // and is a decimal corresponding to the ARM + // architecture number. is either 'l' or 'b' + // and corresponds to the endianess, it is ignored here. + while (value_len > 0 && my_isspace(value[value_len-1])) + value_len--; + + size_t nn = value_len; + while (nn > 0 && value[nn-1] != '(') + nn--; + if (nn > 0 && value[nn] == 'v') { + uintptr_t arch_level = 5; + my_read_decimal_ptr(&arch_level, value + nn + 1); + sys_info->processor_level = static_cast(arch_level); + } + } +#elif defined(__aarch64__) + // The aarch64 architecture does not provide the architecture level + // in the Processor field, so we instead check the "CPU architecture" + // field. + if (!my_strcmp(field, "CPU architecture")) { + uintptr_t arch_level = 0; + const char* value = reader->GetValue(); + const char* p = value; + p = my_read_decimal_ptr(&arch_level, value); + if (p == value) + continue; + sys_info->processor_level = static_cast(arch_level); + } +#endif + // Rebuild the ELF hwcaps from the 'Features' field. + if (!my_strcmp(field, "Features")) { + size_t value_len; + const char* value = reader->GetValueAndLen(&value_len); + + // Parse each space-separated tag. + while (value_len > 0) { + const char* tag = value; + size_t tag_len = value_len; + const char* p = my_strchr(tag, ' '); + if (p != NULL) { + tag_len = static_cast(p - tag); + value += tag_len + 1; + value_len -= tag_len + 1; + } else { + tag_len = strlen(tag); + value_len = 0; + } + for (size_t i = 0; + i < sizeof(cpu_features_entries)/ + sizeof(cpu_features_entries[0]); + ++i) { + const CpuFeaturesEntry* entry = &cpu_features_entries[i]; + if (tag_len == strlen(entry->tag) && + !memcmp(tag, entry->tag, tag_len)) { + sys_info->cpu.arm_cpu_info.elf_hwcaps |= entry->hwcaps; + break; + } + } + } + } + } + sys_close(fd); + } + + return true; + } +#else +# error "Unsupported CPU" +#endif + + bool WriteFile(MDLocationDescriptor* result, const char* filename) { + const int fd = sys_open(filename, O_RDONLY, 0); + if (fd < 0) + return false; + + // We can't stat the files because several of the files that we want to + // read are kernel seqfiles, which always have a length of zero. So we have + // to read as much as we can into a buffer. + static const unsigned kBufSize = 1024 - 2*sizeof(void*); + struct Buffers { + Buffers* next; + size_t len; + uint8_t data[kBufSize]; + } *buffers = reinterpret_cast(Alloc(sizeof(Buffers))); + buffers->next = NULL; + buffers->len = 0; + + size_t total = 0; + for (Buffers* bufptr = buffers;;) { + ssize_t r; + do { + r = sys_read(fd, &bufptr->data[bufptr->len], kBufSize - bufptr->len); + } while (r == -1 && errno == EINTR); + + if (r < 1) + break; + + total += r; + bufptr->len += r; + if (bufptr->len == kBufSize) { + bufptr->next = reinterpret_cast(Alloc(sizeof(Buffers))); + bufptr = bufptr->next; + bufptr->next = NULL; + bufptr->len = 0; + } + } + sys_close(fd); + + if (!total) + return false; + + UntypedMDRVA memory(&minidump_writer_); + if (!memory.Allocate(total)) + return false; + for (MDRVA pos = memory.position(); buffers; buffers = buffers->next) { + // Check for special case of a zero-length buffer. This should only + // occur if a file's size happens to be a multiple of the buffer's + // size, in which case the final sys_read() will have resulted in + // zero bytes being read after the final buffer was just allocated. + if (buffers->len == 0) { + // This can only occur with final buffer. + assert(buffers->next == NULL); + continue; + } + memory.Copy(pos, &buffers->data, buffers->len); + pos += buffers->len; + } + *result = memory.location(); + return true; + } + + bool WriteOSInformation(MDRawSystemInfo* sys_info) { +#if defined(__ANDROID__) + sys_info->platform_id = MD_OS_ANDROID; +#else + sys_info->platform_id = MD_OS_LINUX; +#endif + + struct utsname uts; + if (uname(&uts)) + return false; + + static const size_t buf_len = 512; + char buf[buf_len] = {0}; + size_t space_left = buf_len - 1; + const char* info_table[] = { + uts.sysname, + uts.release, + uts.version, + uts.machine, + NULL + }; + bool first_item = true; + for (const char** cur_info = info_table; *cur_info; cur_info++) { + static const char separator[] = " "; + size_t separator_len = sizeof(separator) - 1; + size_t info_len = my_strlen(*cur_info); + if (info_len == 0) + continue; + + if (space_left < info_len + (first_item ? 0 : separator_len)) + break; + + if (!first_item) { + my_strlcat(buf, separator, sizeof(buf)); + space_left -= separator_len; + } + + first_item = false; + my_strlcat(buf, *cur_info, sizeof(buf)); + space_left -= info_len; + } + + MDLocationDescriptor location; + if (!minidump_writer_.WriteString(buf, 0, &location)) + return false; + sys_info->csd_version_rva = location.rva; + + return true; + } + + bool WriteProcFile(MDLocationDescriptor* result, pid_t pid, + const char* filename) { + char buf[NAME_MAX]; + if (!dumper_->BuildProcPath(buf, pid, filename)) + return false; + return WriteFile(result, buf); + } + + // Only one of the 2 member variables below should be set to a valid value. + const int fd_; // File descriptor where the minidum should be written. + const char* path_; // Path to the file where the minidum should be written. + + const struct ucontext* const ucontext_; // also from the signal handler +#if !defined(__ARM_EABI__) && !defined(__mips__) + const google_breakpad::fpstate_t* const float_state_; // ditto +#endif + LinuxDumper* dumper_; + MinidumpFileWriter minidump_writer_; + off_t minidump_size_limit_; + MDLocationDescriptor crashing_thread_context_; + // Blocks of memory written to the dump. These are all currently + // written while writing the thread list stream, but saved here + // so a memory list stream can be written afterwards. + wasteful_vector memory_blocks_; + // Additional information about some mappings provided by the caller. + const MappingList& mapping_list_; + // Additional memory regions to be included in the dump, + // provided by the caller. + const AppMemoryList& app_memory_list_; +}; + + +bool WriteMinidumpImpl(const char* minidump_path, + int minidump_fd, + off_t minidump_size_limit, + pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appmem) { + LinuxPtraceDumper dumper(crashing_process); + const ExceptionHandler::CrashContext* context = NULL; + if (blob) { + if (blob_size != sizeof(ExceptionHandler::CrashContext)) + return false; + context = reinterpret_cast(blob); + dumper.set_crash_address( + reinterpret_cast(context->siginfo.si_addr)); + dumper.set_crash_signal(context->siginfo.si_signo); + dumper.set_crash_thread(context->tid); + } + MinidumpWriter writer(minidump_path, minidump_fd, context, mappings, + appmem, &dumper); + // Set desired limit for file size of minidump (-1 means no limit). + writer.set_minidump_size_limit(minidump_size_limit); + if (!writer.Init()) + return false; + return writer.Dump(); +} + +} // namespace + +namespace google_breakpad { + +bool WriteMinidump(const char* minidump_path, pid_t crashing_process, + const void* blob, size_t blob_size) { + return WriteMinidumpImpl(minidump_path, -1, -1, + crashing_process, blob, blob_size, + MappingList(), AppMemoryList()); +} + +bool WriteMinidump(int minidump_fd, pid_t crashing_process, + const void* blob, size_t blob_size) { + return WriteMinidumpImpl(NULL, minidump_fd, -1, + crashing_process, blob, blob_size, + MappingList(), AppMemoryList()); +} + +bool WriteMinidump(const char* minidump_path, pid_t process, + pid_t process_blamed_thread) { + LinuxPtraceDumper dumper(process); + // MinidumpWriter will set crash address + dumper.set_crash_signal(MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED); + dumper.set_crash_thread(process_blamed_thread); + MinidumpWriter writer(minidump_path, -1, NULL, MappingList(), + AppMemoryList(), &dumper); + if (!writer.Init()) + return false; + return writer.Dump(); +} + +bool WriteMinidump(const char* minidump_path, pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appmem) { + return WriteMinidumpImpl(minidump_path, -1, -1, crashing_process, + blob, blob_size, + mappings, appmem); +} + +bool WriteMinidump(int minidump_fd, pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appmem) { + return WriteMinidumpImpl(NULL, minidump_fd, -1, crashing_process, + blob, blob_size, + mappings, appmem); +} + +bool WriteMinidump(const char* minidump_path, off_t minidump_size_limit, + pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appmem) { + return WriteMinidumpImpl(minidump_path, -1, minidump_size_limit, + crashing_process, blob, blob_size, + mappings, appmem); +} + +bool WriteMinidump(int minidump_fd, off_t minidump_size_limit, + pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appmem) { + return WriteMinidumpImpl(NULL, minidump_fd, minidump_size_limit, + crashing_process, blob, blob_size, + mappings, appmem); +} + +bool WriteMinidump(const char* filename, + const MappingList& mappings, + const AppMemoryList& appmem, + LinuxDumper* dumper) { + MinidumpWriter writer(filename, -1, NULL, mappings, appmem, dumper); + if (!writer.Init()) + return false; + return writer.Dump(); +} + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/client/linux/minidump_writer/minidump_writer.h b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/minidump_writer.h new file mode 100644 index 00000000..d13fb120 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/minidump_writer.h @@ -0,0 +1,124 @@ +// Copyright (c) 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_ + +#include +#include +#include +#include + +#include +#include + +#include "client/linux/minidump_writer/linux_dumper.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +class ExceptionHandler; + +#if defined(__aarch64__) +typedef struct fpsimd_context fpstate_t; +#elif !defined(__ARM_EABI__) && !defined(__mips__) +typedef struct _libc_fpstate fpstate_t; +#endif + +// These entries store a list of memory regions that the client wants included +// in the minidump. +struct AppMemory { + void* ptr; + size_t length; + + bool operator==(const struct AppMemory& other) const { + return ptr == other.ptr; + } + + bool operator==(const void* other) const { + return ptr == other; + } +}; +typedef std::list AppMemoryList; + +// Writes a minidump to the filesystem. These functions do not malloc nor use +// libc functions which may. Thus, it can be used in contexts where the state +// of the heap may be corrupt. +// minidump_path: the path to the file to write to. This is opened O_EXCL and +// fails open fails. +// crashing_process: the pid of the crashing process. This must be trusted. +// blob: a blob of data from the crashing process. See exception_handler.h +// blob_size: the length of |blob|, in bytes +// +// Returns true iff successful. +bool WriteMinidump(const char* minidump_path, pid_t crashing_process, + const void* blob, size_t blob_size); +// Same as above but takes an open file descriptor instead of a path. +bool WriteMinidump(int minidump_fd, pid_t crashing_process, + const void* blob, size_t blob_size); + +// Alternate form of WriteMinidump() that works with processes that +// are not expected to have crashed. If |process_blamed_thread| is +// meaningful, it will be the one from which a crash signature is +// extracted. It is not expected that this function will be called +// from a compromised context, but it is safe to do so. +bool WriteMinidump(const char* minidump_path, pid_t process, + pid_t process_blamed_thread); + +// These overloads also allow passing a list of known mappings and +// a list of additional memory regions to be included in the minidump. +bool WriteMinidump(const char* minidump_path, pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appdata); +bool WriteMinidump(int minidump_fd, pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appdata); + +// These overloads also allow passing a file size limit for the minidump. +bool WriteMinidump(const char* minidump_path, off_t minidump_size_limit, + pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appdata); +bool WriteMinidump(int minidump_fd, off_t minidump_size_limit, + pid_t crashing_process, + const void* blob, size_t blob_size, + const MappingList& mappings, + const AppMemoryList& appdata); + +bool WriteMinidump(const char* filename, + const MappingList& mappings, + const AppMemoryList& appdata, + LinuxDumper* dumper); + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_ diff --git a/TMessagesProj/jni/breakpad/client/linux/minidump_writer/proc_cpuinfo_reader.h b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/proc_cpuinfo_reader.h new file mode 100644 index 00000000..d9461bf3 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/linux/minidump_writer/proc_cpuinfo_reader.h @@ -0,0 +1,130 @@ +// Copyright (c) 2013, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef CLIENT_LINUX_MINIDUMP_WRITER_PROC_CPUINFO_READER_H_ +#define CLIENT_LINUX_MINIDUMP_WRITER_PROC_CPUINFO_READER_H_ + +#include +#include +#include + +#include "client/linux/minidump_writer/line_reader.h" +#include "common/linux/linux_libc_support.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +// A class for reading /proc/cpuinfo without using fopen/fgets or other +// functions which may allocate memory. +class ProcCpuInfoReader { +public: + ProcCpuInfoReader(int fd) + : line_reader_(fd), pop_count_(-1) { + } + + // Return the next field name, or NULL in case of EOF. + // field: (output) Pointer to zero-terminated field name. + // Returns true on success, or false on EOF or error (line too long). + bool GetNextField(const char** field) { + for (;;) { + const char* line; + unsigned line_len; + + // Try to read next line. + if (pop_count_ >= 0) { + line_reader_.PopLine(pop_count_); + pop_count_ = -1; + } + + if (!line_reader_.GetNextLine(&line, &line_len)) + return false; + + pop_count_ = static_cast(line_len); + + const char* line_end = line + line_len; + + // Expected format: + ':' + // Note that: + // - empty lines happen. + // - can contain spaces. + // - some fields have an empty + char* sep = static_cast(my_memchr(line, ':', line_len)); + if (sep == NULL) + continue; + + // Record the value. Skip leading space after the column to get + // its start. + const char* val = sep+1; + while (val < line_end && my_isspace(*val)) + val++; + + value_ = val; + value_len_ = static_cast(line_end - val); + + // Remove trailing spaces before the column to properly 0-terminate + // the field name. + while (sep > line && my_isspace(sep[-1])) + sep--; + + if (sep == line) + continue; + + // zero-terminate field name. + *sep = '\0'; + + *field = line; + return true; + } + } + + // Return the field value. This must be called after a succesful + // call to GetNextField(). + const char* GetValue() { + assert(value_); + return value_; + } + + // Same as GetValue(), but also returns the length in characters of + // the value. + const char* GetValueAndLen(size_t* length) { + assert(value_); + *length = value_len_; + return value_; + } + +private: + LineReader line_reader_; + int pop_count_; + const char* value_; + size_t value_len_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_LINUX_MINIDUMP_WRITER_PROC_CPUINFO_READER_H_ diff --git a/TMessagesProj/jni/breakpad/client/minidump_file_writer-inl.h b/TMessagesProj/jni/breakpad/client/minidump_file_writer-inl.h new file mode 100644 index 00000000..0e12e00b --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/minidump_file_writer-inl.h @@ -0,0 +1,97 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// minidump_file_writer-inl.h: Minidump file writer implementation. +// +// See minidump_file_writer.h for documentation. + +#ifndef CLIENT_MINIDUMP_FILE_WRITER_INL_H__ +#define CLIENT_MINIDUMP_FILE_WRITER_INL_H__ + +#include + +#include "client/minidump_file_writer.h" +#include "google_breakpad/common/minidump_size.h" + +namespace google_breakpad { + +template +inline bool TypedMDRVA::Allocate() { + allocation_state_ = SINGLE_OBJECT; + return UntypedMDRVA::Allocate(minidump_size::size()); +} + +template +inline bool TypedMDRVA::Allocate(size_t additional) { + allocation_state_ = SINGLE_OBJECT; + return UntypedMDRVA::Allocate(minidump_size::size() + additional); +} + +template +inline bool TypedMDRVA::AllocateArray(size_t count) { + assert(count); + allocation_state_ = ARRAY; + return UntypedMDRVA::Allocate(minidump_size::size() * count); +} + +template +inline bool TypedMDRVA::AllocateObjectAndArray(size_t count, + size_t length) { + assert(count && length); + allocation_state_ = SINGLE_OBJECT_WITH_ARRAY; + return UntypedMDRVA::Allocate(minidump_size::size() + count * length); +} + +template +inline bool TypedMDRVA::CopyIndex(unsigned int index, MDType *item) { + assert(allocation_state_ == ARRAY); + return writer_->Copy( + static_cast(position_ + index * minidump_size::size()), + item, minidump_size::size()); +} + +template +inline bool TypedMDRVA::CopyIndexAfterObject(unsigned int index, + const void *src, + size_t length) { + assert(allocation_state_ == SINGLE_OBJECT_WITH_ARRAY); + return writer_->Copy( + static_cast(position_ + minidump_size::size() + + index * length), + src, length); +} + +template +inline bool TypedMDRVA::Flush() { + return writer_->Copy(position_, &data_, minidump_size::size()); +} + +} // namespace google_breakpad + +#endif // CLIENT_MINIDUMP_FILE_WRITER_INL_H__ diff --git a/TMessagesProj/jni/breakpad/client/minidump_file_writer.cc b/TMessagesProj/jni/breakpad/client/minidump_file_writer.cc new file mode 100644 index 00000000..9e905335 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/minidump_file_writer.cc @@ -0,0 +1,284 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// minidump_file_writer.cc: Minidump file writer implementation. +// +// See minidump_file_writer.h for documentation. + +#include +#include +#include +#include +#include + +#include "client/minidump_file_writer-inl.h" +#include "common/linux/linux_libc_support.h" +#include "common/string_conversion.h" +#if defined(__linux__) && __linux__ +#include "third_party/lss/linux_syscall_support.h" +#endif + +namespace google_breakpad { + +const MDRVA MinidumpFileWriter::kInvalidMDRVA = static_cast(-1); + +MinidumpFileWriter::MinidumpFileWriter() + : file_(-1), + close_file_when_destroyed_(true), + position_(0), + size_(0) { +} + +MinidumpFileWriter::~MinidumpFileWriter() { + if (close_file_when_destroyed_) + Close(); +} + +bool MinidumpFileWriter::Open(const char *path) { + assert(file_ == -1); +#if defined(__linux__) && __linux__ + file_ = sys_open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); +#else + file_ = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600); +#endif + + return file_ != -1; +} + +void MinidumpFileWriter::SetFile(const int file) { + assert(file_ == -1); + file_ = file; + close_file_when_destroyed_ = false; +} + +bool MinidumpFileWriter::Close() { + bool result = true; + + if (file_ != -1) { + if (-1 == ftruncate(file_, position_)) { + return false; + } +#if defined(__linux__) && __linux__ + result = (sys_close(file_) == 0); +#else + result = (close(file_) == 0); +#endif + file_ = -1; + } + + return result; +} + +bool MinidumpFileWriter::CopyStringToMDString(const wchar_t *str, + unsigned int length, + TypedMDRVA *mdstring) { + bool result = true; + if (sizeof(wchar_t) == sizeof(uint16_t)) { + // Shortcut if wchar_t is the same size as MDString's buffer + result = mdstring->Copy(str, mdstring->get()->length); + } else { + uint16_t out[2]; + int out_idx = 0; + + // Copy the string character by character + while (length && result) { + UTF32ToUTF16Char(*str, out); + if (!out[0]) + return false; + + // Process one character at a time + --length; + ++str; + + // Append the one or two UTF-16 characters. The first one will be non- + // zero, but the second one may be zero, depending on the conversion from + // UTF-32. + int out_count = out[1] ? 2 : 1; + size_t out_size = sizeof(uint16_t) * out_count; + result = mdstring->CopyIndexAfterObject(out_idx, out, out_size); + out_idx += out_count; + } + } + return result; +} + +bool MinidumpFileWriter::CopyStringToMDString(const char *str, + unsigned int length, + TypedMDRVA *mdstring) { + bool result = true; + uint16_t out[2]; + int out_idx = 0; + + // Copy the string character by character + while (length && result) { + int conversion_count = UTF8ToUTF16Char(str, length, out); + if (!conversion_count) + return false; + + // Move the pointer along based on the nubmer of converted characters + length -= conversion_count; + str += conversion_count; + + // Append the one or two UTF-16 characters + int out_count = out[1] ? 2 : 1; + size_t out_size = sizeof(uint16_t) * out_count; + result = mdstring->CopyIndexAfterObject(out_idx, out, out_size); + out_idx += out_count; + } + return result; +} + +template +bool MinidumpFileWriter::WriteStringCore(const CharType *str, + unsigned int length, + MDLocationDescriptor *location) { + assert(str); + assert(location); + // Calculate the mdstring length by either limiting to |length| as passed in + // or by finding the location of the NULL character. + unsigned int mdstring_length = 0; + if (!length) + length = INT_MAX; + for (; mdstring_length < length && str[mdstring_length]; ++mdstring_length) + ; + + // Allocate the string buffer + TypedMDRVA mdstring(this); + if (!mdstring.AllocateObjectAndArray(mdstring_length + 1, sizeof(uint16_t))) + return false; + + // Set length excluding the NULL and copy the string + mdstring.get()->length = + static_cast(mdstring_length * sizeof(uint16_t)); + bool result = CopyStringToMDString(str, mdstring_length, &mdstring); + + // NULL terminate + if (result) { + uint16_t ch = 0; + result = mdstring.CopyIndexAfterObject(mdstring_length, &ch, sizeof(ch)); + + if (result) + *location = mdstring.location(); + } + + return result; +} + +bool MinidumpFileWriter::WriteString(const wchar_t *str, unsigned int length, + MDLocationDescriptor *location) { + return WriteStringCore(str, length, location); +} + +bool MinidumpFileWriter::WriteString(const char *str, unsigned int length, + MDLocationDescriptor *location) { + return WriteStringCore(str, length, location); +} + +bool MinidumpFileWriter::WriteMemory(const void *src, size_t size, + MDMemoryDescriptor *output) { + assert(src); + assert(output); + UntypedMDRVA mem(this); + + if (!mem.Allocate(size)) + return false; + if (!mem.Copy(src, mem.size())) + return false; + + output->start_of_memory_range = reinterpret_cast(src); + output->memory = mem.location(); + + return true; +} + +MDRVA MinidumpFileWriter::Allocate(size_t size) { + assert(size); + assert(file_ != -1); + size_t aligned_size = (size + 7) & ~7; // 64-bit alignment + + if (position_ + aligned_size > size_) { + size_t growth = aligned_size; + size_t minimal_growth = getpagesize(); + + // Ensure that the file grows by at least the size of a memory page + if (growth < minimal_growth) + growth = minimal_growth; + + size_t new_size = size_ + growth; + if (ftruncate(file_, new_size) != 0) + return kInvalidMDRVA; + + size_ = new_size; + } + + MDRVA current_position = position_; + position_ += static_cast(aligned_size); + + return current_position; +} + +bool MinidumpFileWriter::Copy(MDRVA position, const void *src, ssize_t size) { + assert(src); + assert(size); + assert(file_ != -1); + + // Ensure that the data will fit in the allocated space + if (static_cast(size + position) > size_) + return false; + + // Seek and write the data +#if defined(__linux__) && __linux__ + if (sys_lseek(file_, position, SEEK_SET) == static_cast(position)) { + if (sys_write(file_, src, size) == size) { +#else + if (lseek(file_, position, SEEK_SET) == static_cast(position)) { + if (write(file_, src, size) == size) { +#endif + return true; + } + } + + return false; +} + +bool UntypedMDRVA::Allocate(size_t size) { + assert(size_ == 0); + size_ = size; + position_ = writer_->Allocate(size_); + return position_ != MinidumpFileWriter::kInvalidMDRVA; +} + +bool UntypedMDRVA::Copy(MDRVA pos, const void *src, size_t size) { + assert(src); + assert(size); + assert(pos + size <= position_ + size_); + return writer_->Copy(pos, src, size); +} + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/client/minidump_file_writer.h b/TMessagesProj/jni/breakpad/client/minidump_file_writer.h new file mode 100644 index 00000000..ce32b6d0 --- /dev/null +++ b/TMessagesProj/jni/breakpad/client/minidump_file_writer.h @@ -0,0 +1,272 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// minidump_file_writer.h: Implements file-based minidump generation. It's +// intended to be used with the Google Breakpad open source crash handling +// project. + +#ifndef CLIENT_MINIDUMP_FILE_WRITER_H__ +#define CLIENT_MINIDUMP_FILE_WRITER_H__ + +#include + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +class UntypedMDRVA; +template class TypedMDRVA; + +// The user of this class can Open() a file and add minidump streams, data, and +// strings using the definitions in minidump_format.h. Since this class is +// expected to be used in a situation where the current process may be +// damaged, it will not allocate heap memory. +// Sample usage: +// MinidumpFileWriter writer; +// writer.Open("/tmp/minidump.dmp"); +// TypedMDRVA header(&writer_); +// header.Allocate(); +// header->get()->signature = MD_HEADER_SIGNATURE; +// : +// writer.Close(); +// +// An alternative is to use SetFile and provide a file descriptor: +// MinidumpFileWriter writer; +// writer.SetFile(minidump_fd); +// TypedMDRVA header(&writer_); +// header.Allocate(); +// header->get()->signature = MD_HEADER_SIGNATURE; +// : +// writer.Close(); + +class MinidumpFileWriter { +public: + // Invalid MDRVA (Minidump Relative Virtual Address) + // returned on failed allocation + static const MDRVA kInvalidMDRVA; + + MinidumpFileWriter(); + ~MinidumpFileWriter(); + + // Open |path| as the destination of the minidump data. If |path| already + // exists, then Open() will fail. + // Return true on success, or false on failure. + bool Open(const char *path); + + // Sets the file descriptor |file| as the destination of the minidump data. + // Can be used as an alternative to Open() when a file descriptor is + // available. + // Note that |fd| is not closed when the instance of MinidumpFileWriter is + // destroyed. + void SetFile(const int file); + + // Close the current file (that was either created when Open was called, or + // specified with SetFile). + // Return true on success, or false on failure. + bool Close(); + + // Copy the contents of |str| to a MDString and write it to the file. + // |str| is expected to be either UTF-16 or UTF-32 depending on the size + // of wchar_t. + // Maximum |length| of characters to copy from |str|, or specify 0 to use the + // entire NULL terminated string. Copying will stop at the first NULL. + // |location| the allocated location + // Return true on success, or false on failure + bool WriteString(const wchar_t *str, unsigned int length, + MDLocationDescriptor *location); + + // Same as above, except with |str| as a UTF-8 string + bool WriteString(const char *str, unsigned int length, + MDLocationDescriptor *location); + + // Write |size| bytes starting at |src| into the current position. + // Return true on success and set |output| to position, or false on failure + bool WriteMemory(const void *src, size_t size, MDMemoryDescriptor *output); + + // Copies |size| bytes from |src| to |position| + // Return true on success, or false on failure + bool Copy(MDRVA position, const void *src, ssize_t size); + + // Return the current position for writing to the minidump + inline MDRVA position() const { return position_; } + + private: + friend class UntypedMDRVA; + + // Allocates an area of |size| bytes. + // Returns the position of the allocation, or kInvalidMDRVA if it was + // unable to allocate the bytes. + MDRVA Allocate(size_t size); + + // The file descriptor for the output file. + int file_; + + // Whether |file_| should be closed when the instance is destroyed. + bool close_file_when_destroyed_; + + // Current position in buffer + MDRVA position_; + + // Current allocated size + size_t size_; + + // Copy |length| characters from |str| to |mdstring|. These are distinct + // because the underlying MDString is a UTF-16 based string. The wchar_t + // variant may need to create a MDString that has more characters than the + // source |str|, whereas the UTF-8 variant may coalesce characters to form + // a single UTF-16 character. + bool CopyStringToMDString(const wchar_t *str, unsigned int length, + TypedMDRVA *mdstring); + bool CopyStringToMDString(const char *str, unsigned int length, + TypedMDRVA *mdstring); + + // The common templated code for writing a string + template + bool WriteStringCore(const CharType *str, unsigned int length, + MDLocationDescriptor *location); +}; + +// Represents an untyped allocated chunk +class UntypedMDRVA { + public: + explicit UntypedMDRVA(MinidumpFileWriter *writer) + : writer_(writer), + position_(writer->position()), + size_(0) {} + + // Allocates |size| bytes. Must not call more than once. + // Return true on success, or false on failure + bool Allocate(size_t size); + + // Returns the current position or kInvalidMDRVA if allocation failed + inline MDRVA position() const { return position_; } + + // Number of bytes allocated + inline size_t size() const { return size_; } + + // Return size and position + inline MDLocationDescriptor location() const { + MDLocationDescriptor location = { static_cast(size_), + position_ }; + return location; + } + + // Copy |size| bytes starting at |src| into the minidump at |position| + // Return true on success, or false on failure + bool Copy(MDRVA position, const void *src, size_t size); + + // Copy |size| bytes from |src| to the current position + inline bool Copy(const void *src, size_t size) { + return Copy(position_, src, size); + } + + protected: + // Writer we associate with + MinidumpFileWriter *writer_; + + // Position of the start of the data + MDRVA position_; + + // Allocated size + size_t size_; +}; + +// Represents a Minidump object chunk. Additional memory can be allocated at +// the end of the object as a: +// - single allocation +// - Array of MDType objects +// - A MDType object followed by an array +template +class TypedMDRVA : public UntypedMDRVA { + public: + // Constructs an unallocated MDRVA + explicit TypedMDRVA(MinidumpFileWriter *writer) + : UntypedMDRVA(writer), + data_(), + allocation_state_(UNALLOCATED) {} + + inline ~TypedMDRVA() { + // Ensure that the data_ object is written out + if (allocation_state_ != ARRAY) + Flush(); + } + + // Address of object data_ of MDType. This is not declared const as the + // typical usage will be to access the underlying |data_| object as to + // alter its contents. + MDType *get() { return &data_; } + + // Allocates minidump_size::size() bytes. + // Must not call more than once. + // Return true on success, or false on failure + bool Allocate(); + + // Allocates minidump_size::size() + |additional| bytes. + // Must not call more than once. + // Return true on success, or false on failure + bool Allocate(size_t additional); + + // Allocate an array of |count| elements of MDType. + // Must not call more than once. + // Return true on success, or false on failure + bool AllocateArray(size_t count); + + // Allocate an array of |count| elements of |size| after object of MDType + // Must not call more than once. + // Return true on success, or false on failure + bool AllocateObjectAndArray(size_t count, size_t size); + + // Copy |item| to |index| + // Must have been allocated using AllocateArray(). + // Return true on success, or false on failure + bool CopyIndex(unsigned int index, MDType *item); + + // Copy |size| bytes starting at |str| to |index| + // Must have been allocated using AllocateObjectAndArray(). + // Return true on success, or false on failure + bool CopyIndexAfterObject(unsigned int index, const void *src, size_t size); + + // Write data_ + bool Flush(); + + private: + enum AllocationState { + UNALLOCATED = 0, + SINGLE_OBJECT, + ARRAY, + SINGLE_OBJECT_WITH_ARRAY + }; + + MDType data_; + AllocationState allocation_state_; +}; + +} // namespace google_breakpad + +#endif // CLIENT_MINIDUMP_FILE_WRITER_H__ diff --git a/TMessagesProj/jni/breakpad/common/android/breakpad_getcontext.S b/TMessagesProj/jni/breakpad/common/android/breakpad_getcontext.S new file mode 100644 index 00000000..fd6326ad --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/android/breakpad_getcontext.S @@ -0,0 +1,489 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// A minimalistic implementation of getcontext() to be used by +// Google Breakpad on Android. + +#include "common/android/ucontext_constants.h" + +/* int getcontext (ucontext_t *ucp) */ + +#if defined(__arm__) + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .type breakpad_getcontext, #function + .align 0 + .fnstart +breakpad_getcontext: + + /* First, save r4-r11 */ + add r1, r0, #(MCONTEXT_GREGS_OFFSET + 4*4) + stm r1, {r4-r11} + + /* r12 is a scratch register, don't save it */ + + /* Save sp and lr explicitly. */ + /* - sp can't be stored with stmia in Thumb-2 */ + /* - STM instructions that store sp and pc are deprecated in ARM */ + str sp, [r0, #(MCONTEXT_GREGS_OFFSET + 13*4)] + str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)] + + /* Save the caller's address in 'pc' */ + str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 15*4)] + + /* Save ucontext_t* pointer across next call */ + mov r4, r0 + + /* Call sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask)) */ + mov r0, #0 /* SIG_BLOCK */ + mov r1, #0 /* NULL */ + add r2, r4, #UCONTEXT_SIGMASK_OFFSET + bl sigprocmask(PLT) + + /* Intentionally do not save the FPU state here. This is because on + * Linux/ARM, one should instead use ptrace(PTRACE_GETFPREGS) or + * ptrace(PTRACE_GETVFPREGS) to get it. + * + * Note that a real implementation of getcontext() would need to save + * this here to allow setcontext()/swapcontext() to work correctly. + */ + + /* Restore the values of r4 and lr */ + mov r0, r4 + ldr lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)] + ldr r4, [r0, #(MCONTEXT_GREGS_OFFSET + 4*4)] + + /* Return 0 */ + mov r0, #0 + bx lr + + .fnend + .size breakpad_getcontext, . - breakpad_getcontext + +#elif defined(__aarch64__) + +#define _NSIG 64 +#define __NR_rt_sigprocmask 135 + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .type breakpad_getcontext, #function + .align 4 + .cfi_startproc +breakpad_getcontext: + + /* The saved context will return to the getcontext() call point + with a return value of 0 */ + str xzr, [x0, MCONTEXT_GREGS_OFFSET + 0 * REGISTER_SIZE] + + stp x18, x19, [x0, MCONTEXT_GREGS_OFFSET + 18 * REGISTER_SIZE] + stp x20, x21, [x0, MCONTEXT_GREGS_OFFSET + 20 * REGISTER_SIZE] + stp x22, x23, [x0, MCONTEXT_GREGS_OFFSET + 22 * REGISTER_SIZE] + stp x24, x25, [x0, MCONTEXT_GREGS_OFFSET + 24 * REGISTER_SIZE] + stp x26, x27, [x0, MCONTEXT_GREGS_OFFSET + 26 * REGISTER_SIZE] + stp x28, x29, [x0, MCONTEXT_GREGS_OFFSET + 28 * REGISTER_SIZE] + str x30, [x0, MCONTEXT_GREGS_OFFSET + 30 * REGISTER_SIZE] + + /* Place LR into the saved PC, this will ensure that when + switching to this saved context with setcontext() control + will pass back to the caller of getcontext(), we have + already arranged to return the appropriate return value in x0 + above. */ + str x30, [x0, MCONTEXT_PC_OFFSET] + + /* Save the current SP */ + mov x2, sp + str x2, [x0, MCONTEXT_SP_OFFSET] + + /* Initialize the pstate. */ + str xzr, [x0, MCONTEXT_PSTATE_OFFSET] + + /* Figure out where to place the first context extension + block. */ + add x2, x0, #MCONTEXT_EXTENSION_OFFSET + + /* Write the context extension fpsimd header. */ + mov w3, #(FPSIMD_MAGIC & 0xffff) + movk w3, #(FPSIMD_MAGIC >> 16), lsl #16 + str w3, [x2, #FPSIMD_CONTEXT_MAGIC_OFFSET] + mov w3, #FPSIMD_CONTEXT_SIZE + str w3, [x2, #FPSIMD_CONTEXT_SIZE_OFFSET] + + /* Fill in the FP SIMD context. */ + add x3, x2, #(FPSIMD_CONTEXT_VREGS_OFFSET + 8 * SIMD_REGISTER_SIZE) + stp d8, d9, [x3], #(2 * SIMD_REGISTER_SIZE) + stp d10, d11, [x3], #(2 * SIMD_REGISTER_SIZE) + stp d12, d13, [x3], #(2 * SIMD_REGISTER_SIZE) + stp d14, d15, [x3], #(2 * SIMD_REGISTER_SIZE) + + add x3, x2, FPSIMD_CONTEXT_FPSR_OFFSET + + mrs x4, fpsr + str w4, [x3] + + mrs x4, fpcr + str w4, [x3, FPSIMD_CONTEXT_FPCR_OFFSET - FPSIMD_CONTEXT_FPSR_OFFSET] + + /* Write the termination context extension header. */ + add x2, x2, #FPSIMD_CONTEXT_SIZE + + str xzr, [x2, #FPSIMD_CONTEXT_MAGIC_OFFSET] + str xzr, [x2, #FPSIMD_CONTEXT_SIZE_OFFSET] + + /* Grab the signal mask */ + /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + add x2, x0, #UCONTEXT_SIGMASK_OFFSET + mov x0, #0 /* SIG_BLOCK */ + mov x1, #0 /* NULL */ + mov x3, #(_NSIG / 8) + mov x8, #__NR_rt_sigprocmask + svc 0 + + /* Return x0 for success */ + mov x0, 0 + ret + + .cfi_endproc + .size breakpad_getcontext, . - breakpad_getcontext + +#elif defined(__i386__) + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .align 4 + .type breakpad_getcontext, @function + +breakpad_getcontext: + + movl 4(%esp), %eax /* eax = uc */ + + /* Save register values */ + movl %ecx, MCONTEXT_ECX_OFFSET(%eax) + movl %edx, MCONTEXT_EDX_OFFSET(%eax) + movl %ebx, MCONTEXT_EBX_OFFSET(%eax) + movl %edi, MCONTEXT_EDI_OFFSET(%eax) + movl %esi, MCONTEXT_ESI_OFFSET(%eax) + movl %ebp, MCONTEXT_EBP_OFFSET(%eax) + + movl (%esp), %edx /* return address */ + lea 4(%esp), %ecx /* exclude return address from stack */ + mov %edx, MCONTEXT_EIP_OFFSET(%eax) + mov %ecx, MCONTEXT_ESP_OFFSET(%eax) + + xorl %ecx, %ecx + movw %fs, %cx + mov %ecx, MCONTEXT_FS_OFFSET(%eax) + + movl $0, MCONTEXT_EAX_OFFSET(%eax) + + /* Save floating point state to fpregstate, then update + * the fpregs pointer to point to it */ + leal UCONTEXT_FPREGS_MEM_OFFSET(%eax), %ecx + fnstenv (%ecx) + fldenv (%ecx) + mov %ecx, UCONTEXT_FPREGS_OFFSET(%eax) + + /* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */ + leal UCONTEXT_SIGMASK_OFFSET(%eax), %edx + xorl %ecx, %ecx + push %edx /* &uc->uc_sigmask */ + push %ecx /* NULL */ + push %ecx /* SIGBLOCK == 0 on i386 */ + call sigprocmask@PLT + addl $12, %esp + + movl $0, %eax + ret + + .size breakpad_getcontext, . - breakpad_getcontext + +#elif defined(__mips__) + +// This implementation is inspired by implementation of getcontext in glibc. +#if _MIPS_SIM == _ABIO32 +#include +#include +#include +#else +#include +#include +#endif + +// from asm/asm.h +#if _MIPS_SIM == _ABIO32 +#define ALSZ 7 +#define ALMASK ~7 +#define SZREG 4 +#else // _MIPS_SIM != _ABIO32 +#define ALSZ 15 +#define ALMASK ~15 +#define SZREG 8 +#endif + +#include // for __NR_rt_sigprocmask + +#define _NSIG8 128 / 8 +#define SIG_BLOCK 1 + + + .text +LOCALS_NUM = 1 // save gp on stack +FRAME_SIZE = ((LOCALS_NUM * SZREG) + ALSZ) & ALMASK + +GP_FRAME_OFFSET = FRAME_SIZE - (1 * SZREG) +MCONTEXT_REG_SIZE = 8 + +#if _MIPS_SIM == _ABIO32 + +NESTED (breakpad_getcontext, FRAME_SIZE, ra) + .mask 0x00000000, 0 + .fmask 0x00000000, 0 + + .set noreorder + .cpload t9 + .set reorder + + move a2, sp +#define _SP a2 + + addiu sp, -FRAME_SIZE + .cprestore GP_FRAME_OFFSET + + sw s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw fp, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw ra, MCONTEXT_PC_OFFSET(a0) + +#ifdef __mips_hard_float + s.d fs0, (20 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs1, (22 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs2, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs3, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs4, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs5, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + + cfc1 v1, fcr31 + sw v1, MCONTEXT_FPC_CSR(a0) +#endif // __mips_hard_float + + /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + li a3, _NSIG8 + addu a2, a0, UCONTEXT_SIGMASK_OFFSET + move a1, zero + li a0, SIG_BLOCK + li v0, __NR_rt_sigprocmask + syscall + + addiu sp, FRAME_SIZE + jr ra + +END (breakpad_getcontext) +#else + +#ifndef NESTED +/* + * NESTED - declare nested routine entry point + */ +#define NESTED(symbol, framesize, rpc) \ + .globl symbol; \ + .align 2; \ + .type symbol,@function; \ + .ent symbol,0; \ +symbol: .frame sp, framesize, rpc; +#endif + +/* + * END - mark end of function + */ +#ifndef END +# define END(function) \ + .end function; \ + .size function,.-function +#endif + +/* int getcontext (ucontext_t *ucp) */ + +NESTED (breakpad_getcontext, FRAME_SIZE, ra) + .mask 0x10000000, 0 + .fmask 0x00000000, 0 + + move a2, sp +#define _SP a2 + move a3, gp +#define _GP a3 + + daddiu sp, -FRAME_SIZE + .cpsetup $25, GP_FRAME_OFFSET, breakpad_getcontext + + /* Store a magic flag. */ + li v1, 1 + sd v1, (0 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) /* zero */ + + sd s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd _GP, (28 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s8, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd ra, MCONTEXT_PC_OFFSET(a0) + +#ifdef __mips_hard_float + s.d $f24, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f25, (25 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f26, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f27, (27 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f28, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f29, (29 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f30, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f31, (31 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + + cfc1 v1, $31 + sw v1, MCONTEXT_FPC_CSR(a0) +#endif /* __mips_hard_float */ + +/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + li a3, _NSIG8 + daddu a2, a0, UCONTEXT_SIGMASK_OFFSET + move a1, zero + li a0, SIG_BLOCK + + li v0, __NR_rt_sigprocmask + syscall + + .cpreturn + daddiu sp, FRAME_SIZE + move v0, zero + jr ra + +END (breakpad_getcontext) +#endif // _MIPS_SIM == _ABIO32 + +#elif defined(__x86_64__) +/* The x64 implementation of breakpad_getcontext was derived in part + from the implementation of libunwind which requires the following + notice. */ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 Google, Inc + Contributed by Paul Pluzhnikov + Copyright (C) 2010 Konstantin Belousov + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .align 4 + .type breakpad_getcontext, @function + +breakpad_getcontext: + .cfi_startproc + + /* Callee saved: RBX, RBP, R12-R15 */ + movq %r12, MCONTEXT_GREGS_R12(%rdi) + movq %r13, MCONTEXT_GREGS_R13(%rdi) + movq %r14, MCONTEXT_GREGS_R14(%rdi) + movq %r15, MCONTEXT_GREGS_R15(%rdi) + movq %rbp, MCONTEXT_GREGS_RBP(%rdi) + movq %rbx, MCONTEXT_GREGS_RBX(%rdi) + + /* Save argument registers (not strictly needed, but setcontext + restores them, so don't restore garbage). */ + movq %r8, MCONTEXT_GREGS_R8(%rdi) + movq %r9, MCONTEXT_GREGS_R9(%rdi) + movq %rdi, MCONTEXT_GREGS_RDI(%rdi) + movq %rsi, MCONTEXT_GREGS_RSI(%rdi) + movq %rdx, MCONTEXT_GREGS_RDX(%rdi) + movq %rax, MCONTEXT_GREGS_RAX(%rdi) + movq %rcx, MCONTEXT_GREGS_RCX(%rdi) + + /* Save fp state (not needed, except for setcontext not + restoring garbage). */ + leaq MCONTEXT_FPREGS_MEM(%rdi),%r8 + movq %r8, MCONTEXT_FPREGS_PTR(%rdi) + fnstenv (%r8) + stmxcsr FPREGS_OFFSET_MXCSR(%r8) + + leaq 8(%rsp), %rax /* exclude this call. */ + movq %rax, MCONTEXT_GREGS_RSP(%rdi) + + movq 0(%rsp), %rax + movq %rax, MCONTEXT_GREGS_RIP(%rdi) + + /* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */ + leaq UCONTEXT_SIGMASK_OFFSET(%rdi), %rdx // arg3 + xorq %rsi, %rsi // arg2 NULL + xorq %rdi, %rdi // arg1 SIGBLOCK == 0 + call sigprocmask@PLT + + /* Always return 0 for success, even if sigprocmask failed. */ + xorl %eax, %eax + ret + .cfi_endproc + .size breakpad_getcontext, . - breakpad_getcontext + +#else +#error "This file has not been ported for your CPU!" +#endif diff --git a/TMessagesProj/jni/breakpad/common/android/include/elf.h b/TMessagesProj/jni/breakpad/common/android/include/elf.h new file mode 100644 index 00000000..b2a28df4 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/android/include/elf.h @@ -0,0 +1,168 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ELF_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ELF_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// The Android provides BSD-based definitions for the ElfXX_Nhdr +// types +// always source-compatible with the GLibc/kernel ones. To overcome this +// issue without modifying a lot of code in Breakpad, use an ugly macro +// renaming trick with #include_next + +// Avoid conflict with BSD-based definition of ElfXX_Nhdr. +// Unfortunately, their field member names do not use a 'n_' prefix. +#define Elf32_Nhdr __bsd_Elf32_Nhdr +#define Elf64_Nhdr __bsd_Elf64_Nhdr + +// In case they are defined by the NDK version +#define Elf32_auxv_t __bionic_Elf32_auxv_t +#define Elf64_auxv_t __bionic_Elf64_auxv_t + +#define Elf32_Dyn __bionic_Elf32_Dyn +#define Elf64_Dyn __bionic_Elf64_Dyn + +#include_next + +#undef Elf32_Nhdr +#undef Elf64_Nhdr + +typedef struct { + Elf32_Word n_namesz; + Elf32_Word n_descsz; + Elf32_Word n_type; +} Elf32_Nhdr; + +typedef struct { + Elf64_Word n_namesz; + Elf64_Word n_descsz; + Elf64_Word n_type; +} Elf64_Nhdr; + +#undef Elf32_auxv_t +#undef Elf64_auxv_t + +typedef struct { + uint32_t a_type; + union { + uint32_t a_val; + } a_un; +} Elf32_auxv_t; + +typedef struct { + uint64_t a_type; + union { + uint64_t a_val; + } a_un; +} Elf64_auxv_t; + +#undef Elf32_Dyn +#undef Elf64_Dyn + +typedef struct { + Elf32_Sword d_tag; + union { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +} Elf32_Dyn; + +typedef struct { + Elf64_Sxword d_tag; + union { + Elf64_Xword d_val; + Elf64_Addr d_ptr; + } d_un; +} Elf64_Dyn; + + +// __WORDSIZE is GLibc-specific and used by Google Breakpad on Linux. +#ifndef __WORDSIZE +#if defined(__i386__) || defined(__ARM_EABI__) || defined(__mips__) +#define __WORDSIZE 32 +#elif defined(__x86_64__) || defined(__aarch64__) +#define __WORDSIZE 64 +#else +#error "Unsupported Android CPU ABI" +#endif +#endif + +// The Android headers don't always define this constant. +#ifndef EM_X86_64 +#define EM_X86_64 62 +#endif + +#ifndef EM_PPC64 +#define EM_PPC64 21 +#endif + +#ifndef EM_S390 +#define EM_S390 22 +#endif + +#if !defined(AT_SYSINFO_EHDR) +#define AT_SYSINFO_EHDR 33 +#endif + +#if !defined(NT_PRSTATUS) +#define NT_PRSTATUS 1 +#endif + +#if !defined(NT_PRPSINFO) +#define NT_PRPSINFO 3 +#endif + +#if !defined(NT_AUXV) +#define NT_AUXV 6 +#endif + +#if !defined(NT_PRXFPREG) +#define NT_PRXFPREG 0x46e62b7f +#endif + +#if !defined(NT_FPREGSET) +#define NT_FPREGSET 2 +#endif + +#if !defined(SHT_MIPS_DWARF) +#define SHT_MIPS_DWARF 0x7000001e +#endif + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ELF_H diff --git a/TMessagesProj/jni/breakpad/common/android/include/link.h b/TMessagesProj/jni/breakpad/common/android/include/link.h new file mode 100644 index 00000000..e7ff8e2d --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/android/include/link.h @@ -0,0 +1,71 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef GOOGLE_BREAKPAD_ANDROID_INCLUDE_LINK_H +#define GOOGLE_BREAKPAD_ANDROID_INCLUDE_LINK_H + +/* Android doesn't provide all the data-structures required in its . + Provide custom version here. */ +#include_next + +// TODO(rmcilroy): Remove this file once the ndk is updated for other +// architectures - crbug.com/358831 +#if !defined(__aarch64__) && !defined(__x86_64__) && \ + !(defined(__mips__) && _MIPS_SIM == _ABI64) + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +struct r_debug { + int r_version; + struct link_map* r_map; + ElfW(Addr) r_brk; + enum { + RT_CONSISTENT, + RT_ADD, + RT_DELETE } r_state; + ElfW(Addr) r_ldbase; +}; + +struct link_map { + ElfW(Addr) l_addr; + char* l_name; + ElfW(Dyn)* l_ld; + struct link_map* l_next; + struct link_map* l_prev; +}; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // !defined(__aarch64__) && !defined(__x86_64__) + +#endif /* GOOGLE_BREAKPAD_ANDROID_INCLUDE_LINK_H */ diff --git a/TMessagesProj/jni/breakpad/common/android/include/sgidefs.h b/TMessagesProj/jni/breakpad/common/android/include/sgidefs.h new file mode 100644 index 00000000..33796dcf --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/android/include/sgidefs.h @@ -0,0 +1,41 @@ +// Copyright (c) 2013, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef GOOGLE_BREAKPAD_ANDROID_INCLUDE_SGIDEFS_H +#define GOOGLE_BREAKPAD_ANDROID_INCLUDE_SGIDEFS_H + +#ifdef __mips__ + +// Android doesn't contain sgidefs.h, but does have which +// contains what we need. +#include + +#endif // __mips__ + +#endif // GOOGLE_BREAKPAD_ANDROID_INCLUDE_SGIDEFS_H diff --git a/TMessagesProj/jni/breakpad/common/android/include/stab.h b/TMessagesProj/jni/breakpad/common/android/include/stab.h new file mode 100644 index 00000000..cd929021 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/android/include/stab.h @@ -0,0 +1,100 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_STAB_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_STAB_H + +#include + +#ifdef __BIONIC_HAVE_STAB_H +#include +#else + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#define _STAB_CODE_LIST \ + _STAB_CODE_DEF(UNDF,0x00) \ + _STAB_CODE_DEF(GSYM,0x20) \ + _STAB_CODE_DEF(FNAME,0x22) \ + _STAB_CODE_DEF(FUN,0x24) \ + _STAB_CODE_DEF(STSYM,0x26) \ + _STAB_CODE_DEF(LCSYM,0x28) \ + _STAB_CODE_DEF(MAIN,0x2a) \ + _STAB_CODE_DEF(PC,0x30) \ + _STAB_CODE_DEF(NSYMS,0x32) \ + _STAB_CODE_DEF(NOMAP,0x34) \ + _STAB_CODE_DEF(OBJ,0x38) \ + _STAB_CODE_DEF(OPT,0x3c) \ + _STAB_CODE_DEF(RSYM,0x40) \ + _STAB_CODE_DEF(M2C,0x42) \ + _STAB_CODE_DEF(SLINE,0x44) \ + _STAB_CODE_DEF(DSLINE,0x46) \ + _STAB_CODE_DEF(BSLINE,0x48) \ + _STAB_CODE_DEF(BROWS,0x48) \ + _STAB_CODE_DEF(DEFD,0x4a) \ + _STAB_CODE_DEF(EHDECL,0x50) \ + _STAB_CODE_DEF(MOD2,0x50) \ + _STAB_CODE_DEF(CATCH,0x54) \ + _STAB_CODE_DEF(SSYM,0x60) \ + _STAB_CODE_DEF(SO,0x64) \ + _STAB_CODE_DEF(LSYM,0x80) \ + _STAB_CODE_DEF(BINCL,0x82) \ + _STAB_CODE_DEF(SOL,0x84) \ + _STAB_CODE_DEF(PSYM,0xa0) \ + _STAB_CODE_DEF(EINCL,0xa2) \ + _STAB_CODE_DEF(ENTRY,0xa4) \ + _STAB_CODE_DEF(LBRAC,0xc0) \ + _STAB_CODE_DEF(EXCL,0xc2) \ + _STAB_CODE_DEF(SCOPE,0xc4) \ + _STAB_CODE_DEF(RBRAC,0xe0) \ + _STAB_CODE_DEF(BCOMM,0xe2) \ + _STAB_CODE_DEF(ECOMM,0xe4) \ + _STAB_CODE_DEF(ECOML,0xe8) \ + _STAB_CODE_DEF(NBTEXT,0xf0) \ + _STAB_CODE_DEF(NBDATA,0xf2) \ + _STAB_CODE_DEF(NBBSS,0xf4) \ + _STAB_CODE_DEF(NBSTS,0xf6) \ + _STAB_CODE_DEF(NBLCS,0xf8) \ + _STAB_CODE_DEF(LENG,0xfe) + +enum __stab_debug_code { +#define _STAB_CODE_DEF(x,y) N_##x = y, +_STAB_CODE_LIST +#undef _STAB_CODE_DEF +}; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // __BIONIC_HAVE_STAB_H + +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_STAB_H diff --git a/TMessagesProj/jni/breakpad/common/android/include/sys/procfs.h b/TMessagesProj/jni/breakpad/common/android/include/sys/procfs.h new file mode 100644 index 00000000..27223ea3 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/android/include/sys/procfs.h @@ -0,0 +1,124 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_SYS_PROCFS_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_SYS_PROCFS_H + +#ifdef __BIONIC_HAVE_SYS_PROCFS_H + +#include_next + +#else + +#include +#include +#if defined (__mips__) +#include +#endif +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#if defined(__x86_64__) || defined(__aarch64__) +typedef unsigned long long elf_greg_t; +#else +typedef unsigned long elf_greg_t; +#endif + +#ifdef __arm__ +#define ELF_NGREG (sizeof(struct user_regs) / sizeof(elf_greg_t)) +#elif defined(__aarch64__) +#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t)) +#elif defined(__mips__) +#define ELF_NGREG 45 +#else +#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t)) +#endif + +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +struct elf_siginfo { + int si_signo; + int si_code; + int si_errno; +}; + +struct elf_prstatus { + struct elf_siginfo pr_info; + short pr_cursig; + unsigned long pr_sigpend; + unsigned long pr_sighold; + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pd_sid; + struct timeval pr_utime; + struct timeval pr_stime; + struct timeval pr_cutime; + struct timeval pr_cstime; + elf_gregset_t pr_reg; + int pr_fpvalid; +}; + +#define ELF_PRARGSZ 80 + +struct elf_prpsinfo { + char pr_state; + char pr_sname; + char pr_zomb; + char pr_nice; + unsigned long pr_flags; +#ifdef __x86_64__ + unsigned int pr_uid; + unsigned int pr_gid; +#elif defined(__mips__) + unsigned long pr_uid; + unsigned long pr_gid; +#else + unsigned short pr_uid; + unsigned short pr_gid; +#endif + int pr_pid; + int pr_ppid; + int pr_pgrp; + int pr_sid; + char pr_fname[16]; + char pr_psargs[ELF_PRARGSZ]; +}; + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // __BIONIC_HAVE_SYS_PROCFS_H + +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_SYS_PROCFS_H diff --git a/TMessagesProj/jni/breakpad/common/android/include/sys/signal.h b/TMessagesProj/jni/breakpad/common/android/include/sys/signal.h new file mode 100644 index 00000000..20c81e93 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/android/include/sys/signal.h @@ -0,0 +1,35 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_SIGNAL_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_SIGNAL_H + +#include + +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_SIGNAL_H diff --git a/TMessagesProj/jni/breakpad/common/android/include/sys/user.h b/TMessagesProj/jni/breakpad/common/android/include/sys/user.h new file mode 100644 index 00000000..5f036047 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/android/include/sys/user.h @@ -0,0 +1,75 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H + +// The purpose of this file is to glue the mismatching headers (Android NDK vs +// glibc) and therefore avoid doing otherwise awkward #ifdefs in the code. +// The following quirks are currently handled by this file: +// - i386: Use the Android NDK but alias user_fxsr_struct > user_fpxregs_struct. +// - aarch64: Add missing user_regs_struct and user_fpsimd_struct structs. +// - Other platforms: Just use the Android NDK unchanged. + +// TODO(primiano): remove these changes after Chromium has stably rolled to +// an NDK with the appropriate fixes. + +#include_next + +#ifdef __i386__ +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus +typedef struct user_fxsr_struct user_fpxregs_struct; +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus +#endif // __i386__ + +#ifdef __aarch64__ +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus +struct user_regs_struct { + __u64 regs[31]; + __u64 sp; + __u64 pc; + __u64 pstate; +}; +struct user_fpsimd_struct { + __uint128_t vregs[32]; + __u32 fpsr; + __u32 fpcr; +}; +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus +#endif // __aarch64__ + +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H diff --git a/TMessagesProj/jni/breakpad/common/android/include/ucontext.h b/TMessagesProj/jni/breakpad/common/android/include/ucontext.h new file mode 100644 index 00000000..29db8ade --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/android/include/ucontext.h @@ -0,0 +1,56 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_UCONTEXT_H +#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_UCONTEXT_H + +#include + +#ifdef __BIONIC_UCONTEXT_H +#include +#else + +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Provided by src/android/common/breakpad_getcontext.S +int breakpad_getcontext(ucontext_t* ucp); + +#define getcontext(x) breakpad_getcontext(x) + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // __BIONIC_UCONTEXT_H + +#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_UCONTEXT_H diff --git a/TMessagesProj/jni/breakpad/common/android/ucontext_constants.h b/TMessagesProj/jni/breakpad/common/android/ucontext_constants.h new file mode 100644 index 00000000..1932d573 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/android/ucontext_constants.h @@ -0,0 +1,144 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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 header can be included either from a C, C++ or Assembly file. +// Its purpose is to contain constants that must match the offsets of +// various fields in ucontext_t. +// +// They should match the definitions from +// src/common/android/include/sys/ucontext.h +// +// Used by src/common/android/breakpad_getcontext.S +// Tested by src/common/android/testing/breakpad_getcontext_unittest.cc + +#ifndef GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H +#define GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H + +#if defined(__arm__) + +#define MCONTEXT_GREGS_OFFSET 32 +#define UCONTEXT_SIGMASK_OFFSET 104 + +#elif defined(__aarch64__) + +#define UCONTEXT_SIGMASK_OFFSET 40 + +#define MCONTEXT_GREGS_OFFSET 184 +#define MCONTEXT_SP_OFFSET 432 +#define MCONTEXT_PC_OFFSET 440 +#define MCONTEXT_PSTATE_OFFSET 448 +#define MCONTEXT_EXTENSION_OFFSET 464 + +#define FPSIMD_MAGIC 0x46508001 + +#define FPSIMD_CONTEXT_MAGIC_OFFSET 0 +#define FPSIMD_CONTEXT_SIZE_OFFSET 4 +#define FPSIMD_CONTEXT_FPSR_OFFSET 8 +#define FPSIMD_CONTEXT_FPCR_OFFSET 12 +#define FPSIMD_CONTEXT_VREGS_OFFSET 16 +#define FPSIMD_CONTEXT_SIZE 528 + +#define REGISTER_SIZE 8 +#define SIMD_REGISTER_SIZE 16 + +#elif defined(__i386__) + +#define MCONTEXT_GREGS_OFFSET 20 +#define MCONTEXT_GS_OFFSET (MCONTEXT_GREGS_OFFSET + 0*4) +#define MCONTEXT_FS_OFFSET (MCONTEXT_GREGS_OFFSET + 1*4) +#define MCONTEXT_ES_OFFSET (MCONTEXT_GREGS_OFFSET + 2*4) +#define MCONTEXT_DS_OFFSET (MCONTEXT_GREGS_OFFSET + 3*4) +#define MCONTEXT_EDI_OFFSET (MCONTEXT_GREGS_OFFSET + 4*4) +#define MCONTEXT_ESI_OFFSET (MCONTEXT_GREGS_OFFSET + 5*4) +#define MCONTEXT_EBP_OFFSET (MCONTEXT_GREGS_OFFSET + 6*4) +#define MCONTEXT_ESP_OFFSET (MCONTEXT_GREGS_OFFSET + 7*4) +#define MCONTEXT_EBX_OFFSET (MCONTEXT_GREGS_OFFSET + 8*4) +#define MCONTEXT_EDX_OFFSET (MCONTEXT_GREGS_OFFSET + 9*4) +#define MCONTEXT_ECX_OFFSET (MCONTEXT_GREGS_OFFSET + 10*4) +#define MCONTEXT_EAX_OFFSET (MCONTEXT_GREGS_OFFSET + 11*4) +#define MCONTEXT_TRAPNO_OFFSET (MCONTEXT_GREGS_OFFSET + 12*4) +#define MCONTEXT_ERR_OFFSET (MCONTEXT_GREGS_OFFSET + 13*4) +#define MCONTEXT_EIP_OFFSET (MCONTEXT_GREGS_OFFSET + 14*4) +#define MCONTEXT_CS_OFFSET (MCONTEXT_GREGS_OFFSET + 15*4) +#define MCONTEXT_EFL_OFFSET (MCONTEXT_GREGS_OFFSET + 16*4) +#define MCONTEXT_UESP_OFFSET (MCONTEXT_GREGS_OFFSET + 17*4) +#define MCONTEXT_SS_OFFSET (MCONTEXT_GREGS_OFFSET + 18*4) + +#define UCONTEXT_SIGMASK_OFFSET 108 + +#define UCONTEXT_FPREGS_OFFSET 96 +#define UCONTEXT_FPREGS_MEM_OFFSET 116 + +#elif defined(__mips__) + +#if _MIPS_SIM == _ABIO32 +#define MCONTEXT_PC_OFFSET 32 +#define MCONTEXT_GREGS_OFFSET 40 +#define MCONTEXT_FPREGS_OFFSET 296 +#define MCONTEXT_FPC_CSR 556 +#define UCONTEXT_SIGMASK_OFFSET 616 +#else +#define MCONTEXT_GREGS_OFFSET 40 +#define MCONTEXT_FPREGS_OFFSET 296 +#define MCONTEXT_PC_OFFSET 616 +#define MCONTEXT_FPC_CSR 624 +#define UCONTEXT_SIGMASK_OFFSET 640 +#endif + +#elif defined(__x86_64__) + +#define MCONTEXT_GREGS_OFFSET 40 +#define UCONTEXT_SIGMASK_OFFSET 296 + +#define MCONTEXT_GREGS_R8 40 +#define MCONTEXT_GREGS_R9 48 +#define MCONTEXT_GREGS_R10 56 +#define MCONTEXT_GREGS_R11 64 +#define MCONTEXT_GREGS_R12 72 +#define MCONTEXT_GREGS_R13 80 +#define MCONTEXT_GREGS_R14 88 +#define MCONTEXT_GREGS_R15 96 +#define MCONTEXT_GREGS_RDI 104 +#define MCONTEXT_GREGS_RSI 112 +#define MCONTEXT_GREGS_RBP 120 +#define MCONTEXT_GREGS_RBX 128 +#define MCONTEXT_GREGS_RDX 136 +#define MCONTEXT_GREGS_RAX 144 +#define MCONTEXT_GREGS_RCX 152 +#define MCONTEXT_GREGS_RSP 160 +#define MCONTEXT_GREGS_RIP 168 +#define MCONTEXT_FPREGS_PTR 224 +#define MCONTEXT_FPREGS_MEM 304 +#define FPREGS_OFFSET_MXCSR 24 + +#else +#error "This header has not been ported for your CPU" +#endif + +#endif // GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H diff --git a/TMessagesProj/jni/breakpad/common/basictypes.h b/TMessagesProj/jni/breakpad/common/basictypes.h new file mode 100644 index 00000000..9426c1f6 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/basictypes.h @@ -0,0 +1,58 @@ +// Copyright (c) 2011 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef COMMON_BASICTYPES_H_ +#define COMMON_BASICTYPES_H_ + +// A macro to disallow the copy constructor and operator= functions +// This should be used in the private: declarations for a class +#ifndef DISALLOW_COPY_AND_ASSIGN +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) +#endif // DISALLOW_COPY_AND_ASSIGN + +namespace google_breakpad { + +// Used to explicitly mark the return value of a function as unused. If you are +// really sure you don't want to do anything with the return value of a function +// that has been marked with __attribute__((warn_unused_result)), wrap it with +// this. Example: +// +// scoped_ptr my_var = ...; +// if (TakeOwnership(my_var.get()) == SUCCESS) +// ignore_result(my_var.release()); +// +template +inline void ignore_result(const T&) { +} + +} // namespace google_breakpad + +#endif // COMMON_BASICTYPES_H_ diff --git a/TMessagesProj/jni/breakpad/common/byte_cursor.h b/TMessagesProj/jni/breakpad/common/byte_cursor.h new file mode 100644 index 00000000..accd54e0 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/byte_cursor.h @@ -0,0 +1,265 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// Original author: Jim Blandy + +// byte_cursor.h: Classes for parsing values from a buffer of bytes. +// The ByteCursor class provides a convenient interface for reading +// fixed-size integers of arbitrary endianness, being thorough about +// checking for buffer overruns. + +#ifndef COMMON_BYTE_CURSOR_H_ +#define COMMON_BYTE_CURSOR_H_ + +#include +#include +#include +#include +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { + +// A buffer holding a series of bytes. +struct ByteBuffer { + ByteBuffer() : start(0), end(0) { } + ByteBuffer(const uint8_t *set_start, size_t set_size) + : start(set_start), end(set_start + set_size) { } + ~ByteBuffer() { }; + + // Equality operators. Useful in unit tests, and when we're using + // ByteBuffers to refer to regions of a larger buffer. + bool operator==(const ByteBuffer &that) const { + return start == that.start && end == that.end; + } + bool operator!=(const ByteBuffer &that) const { + return start != that.start || end != that.end; + } + + // Not C++ style guide compliant, but this definitely belongs here. + size_t Size() const { + assert(start <= end); + return end - start; + } + + const uint8_t *start, *end; +}; + +// A cursor pointing into a ByteBuffer that can parse numbers of various +// widths and representations, strings, and data blocks, advancing through +// the buffer as it goes. All ByteCursor operations check that accesses +// haven't gone beyond the end of the enclosing ByteBuffer. +class ByteCursor { + public: + // Create a cursor reading bytes from the start of BUFFER. By default, the + // cursor reads multi-byte values in little-endian form. + ByteCursor(const ByteBuffer *buffer, bool big_endian = false) + : buffer_(buffer), here_(buffer->start), + big_endian_(big_endian), complete_(true) { } + + // Accessor and setter for this cursor's endianness flag. + bool big_endian() const { return big_endian_; } + void set_big_endian(bool big_endian) { big_endian_ = big_endian; } + + // Accessor and setter for this cursor's current position. The setter + // returns a reference to this cursor. + const uint8_t *here() const { return here_; } + ByteCursor &set_here(const uint8_t *here) { + assert(buffer_->start <= here && here <= buffer_->end); + here_ = here; + return *this; + } + + // Return the number of bytes available to read at the cursor. + size_t Available() const { return size_t(buffer_->end - here_); } + + // Return true if this cursor is at the end of its buffer. + bool AtEnd() const { return Available() == 0; } + + // When used as a boolean value this cursor converts to true if all + // prior reads have been completed, or false if we ran off the end + // of the buffer. + operator bool() const { return complete_; } + + // Read a SIZE-byte integer at this cursor, signed if IS_SIGNED is true, + // unsigned otherwise, using the cursor's established endianness, and set + // *RESULT to the number. If we read off the end of our buffer, clear + // this cursor's complete_ flag, and store a dummy value in *RESULT. + // Return a reference to this cursor. + template + ByteCursor &Read(size_t size, bool is_signed, T *result) { + if (CheckAvailable(size)) { + T v = 0; + if (big_endian_) { + for (size_t i = 0; i < size; i++) + v = (v << 8) + here_[i]; + } else { + // This loop condition looks weird, but size_t is unsigned, so + // decrementing i after it is zero yields the largest size_t value. + for (size_t i = size - 1; i < size; i--) + v = (v << 8) + here_[i]; + } + if (is_signed && size < sizeof(T)) { + size_t sign_bit = (T)1 << (size * 8 - 1); + v = (v ^ sign_bit) - sign_bit; + } + here_ += size; + *result = v; + } else { + *result = (T) 0xdeadbeef; + } + return *this; + } + + // Read an integer, using the cursor's established endianness and + // *RESULT's size and signedness, and set *RESULT to the number. If we + // read off the end of our buffer, clear this cursor's complete_ flag. + // Return a reference to this cursor. + template + ByteCursor &operator>>(T &result) { + bool T_is_signed = (T)-1 < 0; + return Read(sizeof(T), T_is_signed, &result); + } + + // Copy the SIZE bytes at the cursor to BUFFER, and advance this + // cursor to the end of them. If we read off the end of our buffer, + // clear this cursor's complete_ flag, and set *POINTER to NULL. + // Return a reference to this cursor. + ByteCursor &Read(uint8_t *buffer, size_t size) { + if (CheckAvailable(size)) { + memcpy(buffer, here_, size); + here_ += size; + } + return *this; + } + + // Set STR to a copy of the '\0'-terminated string at the cursor. If the + // byte buffer does not contain a terminating zero, clear this cursor's + // complete_ flag, and set STR to the empty string. Return a reference to + // this cursor. + ByteCursor &CString(string *str) { + const uint8_t *end + = static_cast(memchr(here_, '\0', Available())); + if (end) { + str->assign(reinterpret_cast(here_), end - here_); + here_ = end + 1; + } else { + str->clear(); + here_ = buffer_->end; + complete_ = false; + } + return *this; + } + + // Like CString(STR), but extract the string from a fixed-width buffer + // LIMIT bytes long, which may or may not contain a terminating '\0' + // byte. Specifically: + // + // - If there are not LIMIT bytes available at the cursor, clear the + // cursor's complete_ flag and set STR to the empty string. + // + // - Otherwise, if the LIMIT bytes at the cursor contain any '\0' + // characters, set *STR to a copy of the bytes before the first '\0', + // and advance the cursor by LIMIT bytes. + // + // - Otherwise, set *STR to a copy of those LIMIT bytes, and advance the + // cursor by LIMIT bytes. + ByteCursor &CString(string *str, size_t limit) { + if (CheckAvailable(limit)) { + const uint8_t *end + = static_cast(memchr(here_, '\0', limit)); + if (end) + str->assign(reinterpret_cast(here_), end - here_); + else + str->assign(reinterpret_cast(here_), limit); + here_ += limit; + } else { + str->clear(); + } + return *this; + } + + // Set *POINTER to point to the SIZE bytes at the cursor, and advance + // this cursor to the end of them. If SIZE is omitted, don't move the + // cursor. If we read off the end of our buffer, clear this cursor's + // complete_ flag, and set *POINTER to NULL. Return a reference to this + // cursor. + ByteCursor &PointTo(const uint8_t **pointer, size_t size = 0) { + if (CheckAvailable(size)) { + *pointer = here_; + here_ += size; + } else { + *pointer = NULL; + } + return *this; + } + + // Skip SIZE bytes at the cursor. If doing so would advance us off + // the end of our buffer, clear this cursor's complete_ flag, and + // set *POINTER to NULL. Return a reference to this cursor. + ByteCursor &Skip(size_t size) { + if (CheckAvailable(size)) + here_ += size; + return *this; + } + + private: + // If there are at least SIZE bytes available to read from the buffer, + // return true. Otherwise, set here_ to the end of the buffer, set + // complete_ to false, and return false. + bool CheckAvailable(size_t size) { + if (Available() >= size) { + return true; + } else { + here_ = buffer_->end; + complete_ = false; + return false; + } + } + + // The buffer we're reading bytes from. + const ByteBuffer *buffer_; + + // The next byte within buffer_ that we'll read. + const uint8_t *here_; + + // True if we should read numbers in big-endian form; false if we + // should read in little-endian form. + bool big_endian_; + + // True if we've been able to read all we've been asked to. + bool complete_; +}; + +} // namespace google_breakpad + +#endif // COMMON_BYTE_CURSOR_H_ diff --git a/TMessagesProj/jni/breakpad/common/convert_UTF.c b/TMessagesProj/jni/breakpad/common/convert_UTF.c new file mode 100644 index 00000000..12a3c891 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/convert_UTF.c @@ -0,0 +1,554 @@ +/* + * Copyright © 1991-2015 Unicode, Inc. All rights reserved. + * Distributed under the Terms of Use in + * http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of the Unicode data files and any associated documentation + * (the "Data Files") or Unicode software and any associated documentation + * (the "Software") to deal in the Data Files or Software + * without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, and/or sell copies of + * the Data Files or Software, and to permit persons to whom the Data Files + * or Software are furnished to do so, provided that + * (a) this copyright and permission notice appear with all copies + * of the Data Files or Software, + * (b) this copyright and permission notice appear in associated + * documentation, and + * (c) there is clear notice in each modified Data File or in the Software + * as well as in the documentation associated with the Data File(s) or + * Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF + * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT OF THIRD PARTY RIGHTS. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS + * NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL + * DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder + * shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in these Data Files or Software without prior + * written authorization of the copyright holder. + */ + +/* --------------------------------------------------------------------- + +Conversions between UTF32, UTF-16, and UTF-8. Source code file. +Author: Mark E. Davis, 1994. +Rev History: Rick McGowan, fixes & updates May 2001. +Sept 2001: fixed const & error conditions per +mods suggested by S. Parent & A. Lillich. +June 2002: Tim Dodd added detection and handling of incomplete +source sequences, enhanced error detection, added casts +to eliminate compiler warnings. +July 2003: slight mods to back out aggressive FFFE detection. +Jan 2004: updated switches in from-UTF8 conversions. +Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. + +See the header file "ConvertUTF.h" for complete documentation. + +------------------------------------------------------------------------ */ + + +#include "convert_UTF.h" +#ifdef CVTUTF_DEBUG +#include +#endif + +static const int halfShift = 10; /* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF32 halfMask = 0x3FFUL; + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF + +#ifndef false +#define false 0 +#endif +#ifndef true +#define true 1 +#endif + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + if (target >= targetEnd) { + result = targetExhausted; break; + } + ch = *source++; + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_LEGAL_UTF32) { + if (flags == strictConversion) { + result = sourceIllegal; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + --source; /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } +*sourceStart = source; +*targetStart = target; +return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF32* target = *targetStart; + UTF32 ch, ch2; + while (source < sourceEnd) { + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + if (target >= targetEnd) { + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; break; + } + *target++ = ch; + } + *sourceStart = source; + *targetStart = target; +#ifdef CVTUTF_DEBUG + if (result == sourceIllegal) { + fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); + fflush(stderr); + } +#endif + return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. + */ +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. + */ +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... etc.). Remember that sequencs + * for *legal* UTF-8 will be 4 or fewer bytes total. + */ +static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* --------------------------------------------------------------------- */ + +/* The interface converts a whole buffer to avoid function-call overhead. +* Constants have been gathered. Loops & conditionals have been removed as +* much as possible for efficiency, in favor of drop-through switches. +* (See "Note A" at the bottom of the file for equivalent code.) +* If your compiler supports it, the "isLegalUTF8" call can be turned +* into an inline function. +*/ + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + UTF32 ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } +*sourceStart = source; +*targetStart = target; +return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * If not calling this from ConvertUTF8to*, then the length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns false. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ + +static Boolean isLegalUTF8(const UTF8 *source, int length) { + UTF8 a; + const UTF8 *srcptr = source+length; + switch (length) { + default: return false; + /* Everything else falls through when "true"... */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 2: if ((a = (*--srcptr)) > 0xBF) return false; + + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xED: if (a > 0x9F) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; + } + + case 1: if (*source >= 0x80 && *source < 0xC2) return false; + } + if (*source > 0xF4) return false; + return true; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 sequence is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { + int length = trailingBytesForUTF8[*source]+1; + if (source+length > sourceEnd) { + return false; + } + return isLegalUTF8(source, length); +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } +*sourceStart = source; +*targetStart = target; +return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + ch = *source++; + if (flags == strictConversion ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + } + + target += bytesToWrite; + if (target > targetEnd) { + --source; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } +*sourceStart = source; +*targetStart = target; +return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF32* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (! isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; + case 4: ch += *source++; ch <<= 6; + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up the source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_LEGAL_UTF32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = ch; + } + } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- + +Note A. +The fall-through switches in UTF-8 reading code save a +temp variable, some decrements & conditionals. The switches +are equivalent to the following loop: +{ + int tmpBytesToRead = extraBytesToRead+1; + do { + ch += *source++; + --tmpBytesToRead; + if (tmpBytesToRead) ch <<= 6; + } while (tmpBytesToRead > 0); +} +In UTF-8 writing code, the switches on "bytesToWrite" are +similarly unrolled loops. + +--------------------------------------------------------------------- */ diff --git a/TMessagesProj/jni/breakpad/common/convert_UTF.h b/TMessagesProj/jni/breakpad/common/convert_UTF.h new file mode 100644 index 00000000..644d0995 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/convert_UTF.h @@ -0,0 +1,164 @@ +/* + * Copyright © 1991-2015 Unicode, Inc. All rights reserved. + * Distributed under the Terms of Use in + * http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of the Unicode data files and any associated documentation + * (the "Data Files") or Unicode software and any associated documentation + * (the "Software") to deal in the Data Files or Software + * without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, and/or sell copies of + * the Data Files or Software, and to permit persons to whom the Data Files + * or Software are furnished to do so, provided that + * (a) this copyright and permission notice appear with all copies + * of the Data Files or Software, + * (b) this copyright and permission notice appear in associated + * documentation, and + * (c) there is clear notice in each modified Data File or in the Software + * as well as in the documentation associated with the Data File(s) or + * Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF + * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT OF THIRD PARTY RIGHTS. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS + * NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL + * DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder + * shall not be used in advertising or otherwise to promote the sale, + * use or other dealings in these Data Files or Software without prior + * written authorization of the copyright holder. + */ + +#ifndef COMMON_CONVERT_UTF_H_ +#define COMMON_CONVERT_UTF_H_ + +/* --------------------------------------------------------------------- + +Conversions between UTF32, UTF-16, and UTF-8. Header file. + +Several funtions are included here, forming a complete set of +conversions between the three formats. UTF-7 is not included +here, but is handled in a separate source file. + +Each of these routines takes pointers to input buffers and output +buffers. The input buffers are const. + +Each routine converts the text between *sourceStart and sourceEnd, +putting the result into the buffer between *targetStart and +targetEnd. Note: the end pointers are *after* the last item: e.g. +*(sourceEnd - 1) is the last item. + +The return result indicates whether the conversion was successful, +and if not, whether the problem was in the source or target buffers. +(Only the first encountered problem is indicated.) + +After the conversion, *sourceStart and *targetStart are both +updated to point to the end of last text successfully converted in +the respective buffers. + +Input parameters: +sourceStart - pointer to a pointer to the source buffer. +The contents of this are modified on return so that +it points at the next thing to be converted. +targetStart - similarly, pointer to pointer to the target buffer. +sourceEnd, targetEnd - respectively pointers to the ends of the +two buffers, for overflow checking only. + +These conversion functions take a ConversionFlags argument. When this +flag is set to strict, both irregular sequences and isolated surrogates +will cause an error. When the flag is set to lenient, both irregular +sequences and isolated surrogates are converted. + +Whether the flag is strict or lenient, all illegal sequences will cause +an error return. This includes sequences such as: , , +or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code +must check for illegal sequences. + +When the flag is set to lenient, characters over 0x10FFFF are converted +to the replacement character; otherwise (when the flag is set to strict) +they constitute an error. + +Output parameters: +The value "sourceIllegal" is returned from some routines if the input +sequence is malformed. When "sourceIllegal" is returned, the source +value will point to the illegal value that caused the problem. E.g., +in UTF-8 when a sequence is malformed, it points to the start of the +malformed sequence. + +Author: Mark E. Davis, 1994. +Rev History: Rick McGowan, fixes & updates May 2001. +Fixes & updates, Sept 2001. + +------------------------------------------------------------------------ */ + +/* --------------------------------------------------------------------- +The following 4 definitions are compiler-specific. +The C standard does not guarantee that wchar_t has at least +16 bits, so wchar_t is no less portable than unsigned short! +All should be unsigned values to avoid sign extension during +bit mask & shift operations. +------------------------------------------------------------------------ */ + +typedef unsigned long UTF32; /* at least 32 bits */ +typedef unsigned short UTF16; /* at least 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ +typedef unsigned char Boolean; /* 0 or 1 */ + +/* Some fundamental constants */ +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD +#define UNI_MAX_BMP (UTF32)0x0000FFFF +#define UNI_MAX_UTF16 (UTF32)0x0010FFFF +#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF +#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF + +typedef enum { + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ +} ConversionResult; + +typedef enum { + strictConversion = 0, + lenientConversion +} ConversionFlags; + +/* This is for C++ and does no harm in C */ +#ifdef __cplusplus +extern "C" { +#endif + +ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); + +#ifdef __cplusplus +} +#endif + +/* --------------------------------------------------------------------- */ + +#endif // COMMON_CONVERT_UTF_H_ diff --git a/TMessagesProj/jni/breakpad/common/linux/eintr_wrapper.h b/TMessagesProj/jni/breakpad/common/linux/eintr_wrapper.h new file mode 100644 index 00000000..3f1d1848 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/eintr_wrapper.h @@ -0,0 +1,58 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef COMMON_LINUX_EINTR_WRAPPER_H_ +#define COMMON_LINUX_EINTR_WRAPPER_H_ + +#include + +// This provides a wrapper around system calls which may be interrupted by a +// signal and return EINTR. See man 7 signal. +// + +#define HANDLE_EINTR(x) ({ \ + __typeof__(x) eintr_wrapper_result; \ + do { \ + eintr_wrapper_result = (x); \ + } while (eintr_wrapper_result == -1 && errno == EINTR); \ + eintr_wrapper_result; \ +}) + +#define IGNORE_EINTR(x) ({ \ + __typeof__(x) eintr_wrapper_result; \ + do { \ + eintr_wrapper_result = (x); \ + if (eintr_wrapper_result == -1 && errno == EINTR) { \ + eintr_wrapper_result = 0; \ + } \ + } while (0); \ + eintr_wrapper_result; \ +}) + +#endif // COMMON_LINUX_EINTR_WRAPPER_H_ diff --git a/TMessagesProj/jni/breakpad/common/linux/elf_gnu_compat.h b/TMessagesProj/jni/breakpad/common/linux/elf_gnu_compat.h new file mode 100644 index 00000000..f870cbc7 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/elf_gnu_compat.h @@ -0,0 +1,46 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2013, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// Original author: Lei Zhang + +// elf_gnu_compat.h: #defines unique to glibc's elf.h. + +#ifndef COMMON_LINUX_ELF_GNU_COMPAT_H_ +#define COMMON_LINUX_ELF_GNU_COMPAT_H_ + +#include + +// A note type on GNU systems corresponding to the .note.gnu.build-id section. +#ifndef NT_GNU_BUILD_ID +#define NT_GNU_BUILD_ID 3 +#endif + +#endif // COMMON_LINUX_ELF_GNU_COMPAT_H_ diff --git a/TMessagesProj/jni/breakpad/common/linux/elfutils-inl.h b/TMessagesProj/jni/breakpad/common/linux/elfutils-inl.h new file mode 100644 index 00000000..e56b37a9 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/elfutils-inl.h @@ -0,0 +1,74 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef COMMON_LINUX_ELFUTILS_INL_H__ +#define COMMON_LINUX_ELFUTILS_INL_H__ + +#include "common/linux/linux_libc_support.h" +#include "elfutils.h" + +namespace google_breakpad { + +template +const T* GetOffset(const typename ElfClass::Ehdr* elf_header, + typename ElfClass::Off offset) { + return reinterpret_cast(reinterpret_cast(elf_header) + + offset); +} + +template +const typename ElfClass::Shdr* FindElfSectionByName( + const char* name, + typename ElfClass::Word section_type, + const typename ElfClass::Shdr* sections, + const char* section_names, + const char* names_end, + int nsection) { + assert(name != NULL); + assert(sections != NULL); + assert(nsection > 0); + + int name_len = my_strlen(name); + if (name_len == 0) + return NULL; + + for (int i = 0; i < nsection; ++i) { + const char* section_name = section_names + sections[i].sh_name; + if (sections[i].sh_type == section_type && + names_end - section_name >= name_len + 1 && + my_strcmp(name, section_name) == 0) { + return sections + i; + } + } + return NULL; +} + +} // namespace google_breakpad + +#endif // COMMON_LINUX_ELFUTILS_INL_H__ diff --git a/TMessagesProj/jni/breakpad/common/linux/elfutils.cc b/TMessagesProj/jni/breakpad/common/linux/elfutils.cc new file mode 100644 index 00000000..a79391c1 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/elfutils.cc @@ -0,0 +1,194 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#include "common/linux/elfutils.h" + +#include +#include + +#include "common/linux/linux_libc_support.h" +#include "common/linux/elfutils-inl.h" + +namespace google_breakpad { + +namespace { + +template +void FindElfClassSection(const char *elf_base, + const char *section_name, + typename ElfClass::Word section_type, + const void **section_start, + size_t *section_size) { + typedef typename ElfClass::Ehdr Ehdr; + typedef typename ElfClass::Shdr Shdr; + + assert(elf_base); + assert(section_start); + assert(section_size); + + assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0); + + const Ehdr* elf_header = reinterpret_cast(elf_base); + assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass); + + const Shdr* sections = + GetOffset(elf_header, elf_header->e_shoff); + const Shdr* section_names = sections + elf_header->e_shstrndx; + const char* names = + GetOffset(elf_header, section_names->sh_offset); + const char *names_end = names + section_names->sh_size; + + const Shdr* section = + FindElfSectionByName(section_name, section_type, + sections, names, names_end, + elf_header->e_shnum); + + if (section != NULL && section->sh_size > 0) { + *section_start = elf_base + section->sh_offset; + *section_size = section->sh_size; + } +} + +template +void FindElfClassSegment(const char *elf_base, + typename ElfClass::Word segment_type, + const void **segment_start, + size_t *segment_size) { + typedef typename ElfClass::Ehdr Ehdr; + typedef typename ElfClass::Phdr Phdr; + + assert(elf_base); + assert(segment_start); + assert(segment_size); + + assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0); + + const Ehdr* elf_header = reinterpret_cast(elf_base); + assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass); + + const Phdr* phdrs = + GetOffset(elf_header, elf_header->e_phoff); + + for (int i = 0; i < elf_header->e_phnum; ++i) { + if (phdrs[i].p_type == segment_type) { + *segment_start = elf_base + phdrs[i].p_offset; + *segment_size = phdrs[i].p_filesz; + return; + } + } +} + +} // namespace + +bool IsValidElf(const void* elf_base) { + return my_strncmp(reinterpret_cast(elf_base), + ELFMAG, SELFMAG) == 0; +} + +int ElfClass(const void* elf_base) { + const ElfW(Ehdr)* elf_header = + reinterpret_cast(elf_base); + + return elf_header->e_ident[EI_CLASS]; +} + +bool FindElfSection(const void *elf_mapped_base, + const char *section_name, + uint32_t section_type, + const void **section_start, + size_t *section_size, + int *elfclass) { + assert(elf_mapped_base); + assert(section_start); + assert(section_size); + + *section_start = NULL; + *section_size = 0; + + if (!IsValidElf(elf_mapped_base)) + return false; + + int cls = ElfClass(elf_mapped_base); + if (elfclass) { + *elfclass = cls; + } + + const char* elf_base = + static_cast(elf_mapped_base); + + if (cls == ELFCLASS32) { + FindElfClassSection(elf_base, section_name, section_type, + section_start, section_size); + return *section_start != NULL; + } else if (cls == ELFCLASS64) { + FindElfClassSection(elf_base, section_name, section_type, + section_start, section_size); + return *section_start != NULL; + } + + return false; +} + +bool FindElfSegment(const void *elf_mapped_base, + uint32_t segment_type, + const void **segment_start, + size_t *segment_size, + int *elfclass) { + assert(elf_mapped_base); + assert(segment_start); + assert(segment_size); + + *segment_start = NULL; + *segment_size = 0; + + if (!IsValidElf(elf_mapped_base)) + return false; + + int cls = ElfClass(elf_mapped_base); + if (elfclass) { + *elfclass = cls; + } + + const char* elf_base = + static_cast(elf_mapped_base); + + if (cls == ELFCLASS32) { + FindElfClassSegment(elf_base, segment_type, + segment_start, segment_size); + return *segment_start != NULL; + } else if (cls == ELFCLASS64) { + FindElfClassSegment(elf_base, segment_type, + segment_start, segment_size); + return *segment_start != NULL; + } + + return false; +} + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/common/linux/elfutils.h b/TMessagesProj/jni/breakpad/common/linux/elfutils.h new file mode 100644 index 00000000..dccdc235 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/elfutils.h @@ -0,0 +1,118 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. +// +// elfutils.h: Utilities for dealing with ELF files. +// + +#ifndef COMMON_LINUX_ELFUTILS_H_ +#define COMMON_LINUX_ELFUTILS_H_ + +#include +#include +#include + +namespace google_breakpad { + +// Traits classes so consumers can write templatized code to deal +// with specific ELF bits. +struct ElfClass32 { + typedef Elf32_Addr Addr; + typedef Elf32_Ehdr Ehdr; + typedef Elf32_Nhdr Nhdr; + typedef Elf32_Phdr Phdr; + typedef Elf32_Shdr Shdr; + typedef Elf32_Half Half; + typedef Elf32_Off Off; + typedef Elf32_Word Word; + static const int kClass = ELFCLASS32; + static const size_t kAddrSize = sizeof(Elf32_Addr); +}; + +struct ElfClass64 { + typedef Elf64_Addr Addr; + typedef Elf64_Ehdr Ehdr; + typedef Elf64_Nhdr Nhdr; + typedef Elf64_Phdr Phdr; + typedef Elf64_Shdr Shdr; + typedef Elf64_Half Half; + typedef Elf64_Off Off; + typedef Elf64_Word Word; + static const int kClass = ELFCLASS64; + static const size_t kAddrSize = sizeof(Elf64_Addr); +}; + +bool IsValidElf(const void* elf_header); +int ElfClass(const void* elf_base); + +// Attempt to find a section named |section_name| of type |section_type| +// in the ELF binary data at |elf_mapped_base|. On success, returns true +// and sets |*section_start| to point to the start of the section data, +// and |*section_size| to the size of the section's data. If |elfclass| +// is not NULL, set |*elfclass| to the ELF file class. +bool FindElfSection(const void *elf_mapped_base, + const char *section_name, + uint32_t section_type, + const void **section_start, + size_t *section_size, + int *elfclass); + +// Internal helper method, exposed for convenience for callers +// that already have more info. +template +const typename ElfClass::Shdr* +FindElfSectionByName(const char* name, + typename ElfClass::Word section_type, + const typename ElfClass::Shdr* sections, + const char* section_names, + const char* names_end, + int nsection); + +// Attempt to find the first segment of type |segment_type| in the ELF +// binary data at |elf_mapped_base|. On success, returns true and sets +// |*segment_start| to point to the start of the segment data, and +// and |*segment_size| to the size of the segment's data. If |elfclass| +// is not NULL, set |*elfclass| to the ELF file class. +bool FindElfSegment(const void *elf_mapped_base, + uint32_t segment_type, + const void **segment_start, + size_t *segment_size, + int *elfclass); + +// Convert an offset from an Elf header into a pointer to the mapped +// address in the current process. Takes an extra template parameter +// to specify the return type to avoid having to dynamic_cast the +// result. +template +const T* +GetOffset(const typename ElfClass::Ehdr* elf_header, + typename ElfClass::Off offset); + +} // namespace google_breakpad + +#endif // COMMON_LINUX_ELFUTILS_H_ diff --git a/TMessagesProj/jni/breakpad/common/linux/file_id.cc b/TMessagesProj/jni/breakpad/common/linux/file_id.cc new file mode 100644 index 00000000..00b37313 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/file_id.cc @@ -0,0 +1,191 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. +// +// file_id.cc: Return a unique identifier for a file +// +// See file_id.h for documentation +// + +#include "common/linux/file_id.h" + +#include +#include +#include + +#include + +#include "common/linux/elf_gnu_compat.h" +#include "common/linux/elfutils.h" +#include "common/linux/linux_libc_support.h" +#include "common/linux/memory_mapped_file.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +FileID::FileID(const char* path) : path_(path) {} + +// ELF note name and desc are 32-bits word padded. +#define NOTE_PADDING(a) ((a + 3) & ~3) + +// These functions are also used inside the crashed process, so be safe +// and use the syscall/libc wrappers instead of direct syscalls or libc. + +template +static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length, + uint8_t identifier[kMDGUIDSize]) { + typedef typename ElfClass::Nhdr Nhdr; + + const void* section_end = reinterpret_cast(section) + length; + const Nhdr* note_header = reinterpret_cast(section); + while (reinterpret_cast(note_header) < section_end) { + if (note_header->n_type == NT_GNU_BUILD_ID) + break; + note_header = reinterpret_cast( + reinterpret_cast(note_header) + sizeof(Nhdr) + + NOTE_PADDING(note_header->n_namesz) + + NOTE_PADDING(note_header->n_descsz)); + } + if (reinterpret_cast(note_header) >= section_end || + note_header->n_descsz == 0) { + return false; + } + + const char* build_id = reinterpret_cast(note_header) + + sizeof(Nhdr) + NOTE_PADDING(note_header->n_namesz); + // Copy as many bits of the build ID as will fit + // into the GUID space. + my_memset(identifier, 0, kMDGUIDSize); + memcpy(identifier, build_id, + std::min(kMDGUIDSize, (size_t)note_header->n_descsz)); + + return true; +} + +// Attempt to locate a .note.gnu.build-id section in an ELF binary +// and copy as many bytes of it as will fit into |identifier|. +static bool FindElfBuildIDNote(const void *elf_mapped_base, + uint8_t identifier[kMDGUIDSize]) { + void* note_section; + size_t note_size; + int elfclass; + if ((!FindElfSegment(elf_mapped_base, PT_NOTE, + (const void**)¬e_section, ¬e_size, &elfclass) || + note_size == 0) && + (!FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE, + (const void**)¬e_section, ¬e_size, &elfclass) || + note_size == 0)) { + return false; + } + + if (elfclass == ELFCLASS32) { + return ElfClassBuildIDNoteIdentifier(note_section, note_size, + identifier); + } else if (elfclass == ELFCLASS64) { + return ElfClassBuildIDNoteIdentifier(note_section, note_size, + identifier); + } + + return false; +} + +// Attempt to locate the .text section of an ELF binary and generate +// a simple hash by XORing the first page worth of bytes into |identifier|. +static bool HashElfTextSection(const void *elf_mapped_base, + uint8_t identifier[kMDGUIDSize]) { + void* text_section; + size_t text_size; + if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS, + (const void**)&text_section, &text_size, NULL) || + text_size == 0) { + return false; + } + + my_memset(identifier, 0, kMDGUIDSize); + const uint8_t* ptr = reinterpret_cast(text_section); + const uint8_t* ptr_end = ptr + std::min(text_size, static_cast(4096)); + while (ptr < ptr_end) { + for (unsigned i = 0; i < kMDGUIDSize; i++) + identifier[i] ^= ptr[i]; + ptr += kMDGUIDSize; + } + return true; +} + +// static +bool FileID::ElfFileIdentifierFromMappedFile(const void* base, + uint8_t identifier[kMDGUIDSize]) { + // Look for a build id note first. + if (FindElfBuildIDNote(base, identifier)) + return true; + + // Fall back on hashing the first page of the text section. + return HashElfTextSection(base, identifier); +} + +bool FileID::ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]) { + MemoryMappedFile mapped_file(path_.c_str(), 0); + if (!mapped_file.data()) // Should probably check if size >= ElfW(Ehdr)? + return false; + + return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier); +} + +// static +void FileID::ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize], + char* buffer, int buffer_length) { + uint8_t identifier_swapped[kMDGUIDSize]; + + // Endian-ness swap to match dump processor expectation. + memcpy(identifier_swapped, identifier, kMDGUIDSize); + uint32_t* data1 = reinterpret_cast(identifier_swapped); + *data1 = htonl(*data1); + uint16_t* data2 = reinterpret_cast(identifier_swapped + 4); + *data2 = htons(*data2); + uint16_t* data3 = reinterpret_cast(identifier_swapped + 6); + *data3 = htons(*data3); + + int buffer_idx = 0; + for (unsigned int idx = 0; + (buffer_idx < buffer_length) && (idx < kMDGUIDSize); + ++idx) { + int hi = (identifier_swapped[idx] >> 4) & 0x0F; + int lo = (identifier_swapped[idx]) & 0x0F; + + if (idx == 4 || idx == 6 || idx == 8 || idx == 10) + buffer[buffer_idx++] = '-'; + + buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi; + buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo; + } + + // NULL terminate + buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0; +} + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/common/linux/file_id.h b/TMessagesProj/jni/breakpad/common/linux/file_id.h new file mode 100644 index 00000000..2642722a --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/file_id.h @@ -0,0 +1,78 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. +// +// file_id.h: Return a unique identifier for a file +// + +#ifndef COMMON_LINUX_FILE_ID_H__ +#define COMMON_LINUX_FILE_ID_H__ + +#include +#include + +#include "common/linux/guid_creator.h" + +namespace google_breakpad { + +static const size_t kMDGUIDSize = sizeof(MDGUID); + +class FileID { + public: + explicit FileID(const char* path); + ~FileID() {} + + // Load the identifier for the elf file path specified in the constructor into + // |identifier|. Return false if the identifier could not be created for the + // file. + // The current implementation will look for a .note.gnu.build-id + // section and use that as the file id, otherwise it falls back to + // XORing the first 4096 bytes of the .text section to generate an identifier. + bool ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]); + + // Load the identifier for the elf file mapped into memory at |base| into + // |identifier|. Return false if the identifier could not be created for the + // file. + static bool ElfFileIdentifierFromMappedFile(const void* base, + uint8_t identifier[kMDGUIDSize]); + + // Convert the |identifier| data to a NULL terminated string. The string will + // be formatted as a UUID (e.g., 22F065BB-FC9C-49F7-80FE-26A7CEBD7BCE). + // The |buffer| should be at least 37 bytes long to receive all of the data + // and termination. Shorter buffers will contain truncated data. + static void ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize], + char* buffer, int buffer_length); + + private: + // Storage for the path specified + std::string path_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_FILE_ID_H__ diff --git a/TMessagesProj/jni/breakpad/common/linux/guid_creator.cc b/TMessagesProj/jni/breakpad/common/linux/guid_creator.cc new file mode 100644 index 00000000..bfb308ee --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/guid_creator.cc @@ -0,0 +1,104 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#include "common/linux/guid_creator.h" + +#include +#include +#include +#include +#include +#include + +// +// GUIDGenerator +// +// This class is used to generate random GUID. +// Currently use random number to generate a GUID since Linux has +// no native GUID generator. This should be OK since we don't expect +// crash to happen very offen. +// +class GUIDGenerator { + public: + static uint32_t BytesToUInt32(const uint8_t bytes[]) { + return ((uint32_t) bytes[0] + | ((uint32_t) bytes[1] << 8) + | ((uint32_t) bytes[2] << 16) + | ((uint32_t) bytes[3] << 24)); + } + + static void UInt32ToBytes(uint8_t bytes[], uint32_t n) { + bytes[0] = n & 0xff; + bytes[1] = (n >> 8) & 0xff; + bytes[2] = (n >> 16) & 0xff; + bytes[3] = (n >> 24) & 0xff; + } + + static bool CreateGUID(GUID *guid) { + InitOnce(); + guid->data1 = random(); + guid->data2 = (uint16_t)(random()); + guid->data3 = (uint16_t)(random()); + UInt32ToBytes(&guid->data4[0], random()); + UInt32ToBytes(&guid->data4[4], random()); + return true; + } + + private: + static void InitOnce() { + pthread_once(&once_control, &InitOnceImpl); + } + + static void InitOnceImpl() { + srandom(time(NULL)); + } + + static pthread_once_t once_control; +}; + +pthread_once_t GUIDGenerator::once_control = PTHREAD_ONCE_INIT; + +bool CreateGUID(GUID *guid) { + return GUIDGenerator::CreateGUID(guid); +} + +// Parse guid to string. +bool GUIDToString(const GUID *guid, char *buf, int buf_len) { + // Should allow more space the the max length of GUID. + assert(buf_len > kGUIDStringLength); + int num = snprintf(buf, buf_len, kGUIDFormatString, + guid->data1, guid->data2, guid->data3, + GUIDGenerator::BytesToUInt32(&(guid->data4[0])), + GUIDGenerator::BytesToUInt32(&(guid->data4[4]))); + if (num != kGUIDStringLength) + return false; + + buf[num] = '\0'; + return true; +} diff --git a/TMessagesProj/jni/breakpad/common/linux/guid_creator.h b/TMessagesProj/jni/breakpad/common/linux/guid_creator.h new file mode 100644 index 00000000..c86d856c --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/guid_creator.h @@ -0,0 +1,48 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef COMMON_LINUX_GUID_CREATOR_H__ +#define COMMON_LINUX_GUID_CREATOR_H__ + +#include "google_breakpad/common/minidump_format.h" + +typedef MDGUID GUID; + +// Format string for parsing GUID. +#define kGUIDFormatString "%08x-%04x-%04x-%08x-%08x" +// Length of GUID string. Don't count the ending '\0'. +#define kGUIDStringLength 36 + +// Create a guid. +bool CreateGUID(GUID *guid); + +// Get the string from guid. +bool GUIDToString(const GUID *guid, char *buf, int buf_len); + +#endif diff --git a/TMessagesProj/jni/breakpad/common/linux/ignore_ret.h b/TMessagesProj/jni/breakpad/common/linux/ignore_ret.h new file mode 100644 index 00000000..f60384bb --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/ignore_ret.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef COMMON_LINUX_IGNORE_RET_H_ +#define COMMON_LINUX_IGNORE_RET_H_ + +// Some compilers are prone to warn about unused return values. In cases where +// either a) the call cannot fail, or b) there is nothing that can be done when +// the call fails, IGNORE_RET() can be used to mark the return code as ignored. +// This avoids spurious compiler warnings. + +#define IGNORE_RET(x) do { if (x); } while (0) + +#endif // COMMON_LINUX_IGNORE_RET_H_ diff --git a/TMessagesProj/jni/breakpad/common/linux/linux_libc_support.cc b/TMessagesProj/jni/breakpad/common/linux/linux_libc_support.cc new file mode 100644 index 00000000..08b0325e --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/linux_libc_support.cc @@ -0,0 +1,237 @@ +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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 source file provides replacements for libc functions that we need. If +// we call the libc functions directly we risk crashing in the dynamic linker +// as it tries to resolve uncached PLT entries. + +#include "common/linux/linux_libc_support.h" + +#include + +extern "C" { + +size_t my_strlen(const char* s) { + size_t len = 0; + while (*s++) len++; + return len; +} + +int my_strcmp(const char* a, const char* b) { + for (;;) { + if (*a < *b) + return -1; + else if (*a > *b) + return 1; + else if (*a == 0) + return 0; + a++; + b++; + } +} + +int my_strncmp(const char* a, const char* b, size_t len) { + for (size_t i = 0; i < len; ++i) { + if (*a < *b) + return -1; + else if (*a > *b) + return 1; + else if (*a == 0) + return 0; + a++; + b++; + } + + return 0; +} + +// Parse a non-negative integer. +// result: (output) the resulting non-negative integer +// s: a NUL terminated string +// Return true iff successful. +bool my_strtoui(int* result, const char* s) { + if (*s == 0) + return false; + int r = 0; + for (;; s++) { + if (*s == 0) + break; + const int old_r = r; + r *= 10; + if (*s < '0' || *s > '9') + return false; + r += *s - '0'; + if (r < old_r) + return false; + } + + *result = r; + return true; +} + +// Return the length of the given unsigned integer when expressed in base 10. +unsigned my_uint_len(uintmax_t i) { + if (!i) + return 1; + + int len = 0; + while (i) { + len++; + i /= 10; + } + + return len; +} + +// Convert an unsigned integer to a string +// output: (output) the resulting string is written here. This buffer must be +// large enough to hold the resulting string. Call |my_uint_len| to get the +// required length. +// i: the unsigned integer to serialise. +// i_len: the length of the integer in base 10 (see |my_uint_len|). +void my_uitos(char* output, uintmax_t i, unsigned i_len) { + for (unsigned index = i_len; index; --index, i /= 10) + output[index - 1] = '0' + (i % 10); +} + +const char* my_strchr(const char* haystack, char needle) { + while (*haystack && *haystack != needle) + haystack++; + if (*haystack == needle) + return haystack; + return (const char*) 0; +} + +const char* my_strrchr(const char* haystack, char needle) { + const char* ret = NULL; + while (*haystack) { + if (*haystack == needle) + ret = haystack; + haystack++; + } + return ret; +} + +void* my_memchr(const void* src, int needle, size_t src_len) { + const unsigned char* p = (const unsigned char*)src; + const unsigned char* p_end = p + src_len; + for (; p < p_end; ++p) { + if (*p == needle) + return (void*)p; + } + return NULL; +} + +// Read a hex value +// result: (output) the resulting value +// s: a string +// Returns a pointer to the first invalid charactor. +const char* my_read_hex_ptr(uintptr_t* result, const char* s) { + uintptr_t r = 0; + + for (;; ++s) { + if (*s >= '0' && *s <= '9') { + r <<= 4; + r += *s - '0'; + } else if (*s >= 'a' && *s <= 'f') { + r <<= 4; + r += (*s - 'a') + 10; + } else if (*s >= 'A' && *s <= 'F') { + r <<= 4; + r += (*s - 'A') + 10; + } else { + break; + } + } + + *result = r; + return s; +} + +const char* my_read_decimal_ptr(uintptr_t* result, const char* s) { + uintptr_t r = 0; + + for (;; ++s) { + if (*s >= '0' && *s <= '9') { + r *= 10; + r += *s - '0'; + } else { + break; + } + } + *result = r; + return s; +} + +void my_memset(void* ip, char c, size_t len) { + char* p = (char *) ip; + while (len--) + *p++ = c; +} + +size_t my_strlcpy(char* s1, const char* s2, size_t len) { + size_t pos1 = 0; + size_t pos2 = 0; + + while (s2[pos2] != '\0') { + if (pos1 + 1 < len) { + s1[pos1] = s2[pos2]; + pos1++; + } + pos2++; + } + if (len > 0) + s1[pos1] = '\0'; + + return pos2; +} + +size_t my_strlcat(char* s1, const char* s2, size_t len) { + size_t pos1 = 0; + + while (pos1 < len && s1[pos1] != '\0') + pos1++; + + if (pos1 == len) + return pos1; + + return pos1 + my_strlcpy(s1 + pos1, s2, len - pos1); +} + +int my_isspace(int ch) { + // Matches the C locale. + const char spaces[] = " \t\f\n\r\t\v"; + for (size_t i = 0; i < sizeof(spaces); i++) { + if (ch == spaces[i]) + return 1; + } + return 0; +} + +} // extern "C" diff --git a/TMessagesProj/jni/breakpad/common/linux/linux_libc_support.h b/TMessagesProj/jni/breakpad/common/linux/linux_libc_support.h new file mode 100644 index 00000000..ec5a8d6b --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/linux_libc_support.h @@ -0,0 +1,96 @@ +// Copyright (c) 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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 header provides replacements for libc functions that we need. We if +// call the libc functions directly we risk crashing in the dynamic linker as +// it tries to resolve uncached PLT entries. + +#ifndef CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_ +#define CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_ + +#include +#include +#include + +extern "C" { + +extern size_t my_strlen(const char* s); + +extern int my_strcmp(const char* a, const char* b); + +extern int my_strncmp(const char* a, const char* b, size_t len); + +// Parse a non-negative integer. +// result: (output) the resulting non-negative integer +// s: a NUL terminated string +// Return true iff successful. +extern bool my_strtoui(int* result, const char* s); + +// Return the length of the given unsigned integer when expressed in base 10. +extern unsigned my_uint_len(uintmax_t i); + +// Convert an unsigned integer to a string +// output: (output) the resulting string is written here. This buffer must be +// large enough to hold the resulting string. Call |my_uint_len| to get the +// required length. +// i: the unsigned integer to serialise. +// i_len: the length of the integer in base 10 (see |my_uint_len|). +extern void my_uitos(char* output, uintmax_t i, unsigned i_len); + +extern const char* my_strchr(const char* haystack, char needle); + +extern const char* my_strrchr(const char* haystack, char needle); + +// Read a hex value +// result: (output) the resulting value +// s: a string +// Returns a pointer to the first invalid charactor. +extern const char* my_read_hex_ptr(uintptr_t* result, const char* s); + +extern const char* my_read_decimal_ptr(uintptr_t* result, const char* s); + +extern void my_memset(void* ip, char c, size_t len); + +extern void* my_memchr(const void* src, int c, size_t len); + +// The following are considered safe to use in a compromised environment. +// Besides, this gives the compiler an opportunity to optimize their calls. +#define my_memcpy memcpy +#define my_memmove memmove +#define my_memcmp memcmp + +extern size_t my_strlcpy(char* s1, const char* s2, size_t len); + +extern size_t my_strlcat(char* s1, const char* s2, size_t len); + +extern int my_isspace(int ch); + +} // extern "C" + +#endif // CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_ diff --git a/TMessagesProj/jni/breakpad/common/linux/memory_mapped_file.cc b/TMessagesProj/jni/breakpad/common/linux/memory_mapped_file.cc new file mode 100644 index 00000000..592b66c8 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/memory_mapped_file.cc @@ -0,0 +1,118 @@ +// Copyright (c) 2011, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// memory_mapped_file.cc: Implement google_breakpad::MemoryMappedFile. +// See memory_mapped_file.h for details. + +#include "common/linux/memory_mapped_file.h" + +#include +#include +#if defined(__ANDROID__) +#include +#endif +#include + +#include "common/memory_range.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +MemoryMappedFile::MemoryMappedFile() {} + +MemoryMappedFile::MemoryMappedFile(const char* path, size_t offset) { + Map(path, offset); +} + +MemoryMappedFile::~MemoryMappedFile() { + Unmap(); +} + +#include + +bool MemoryMappedFile::Map(const char* path, size_t offset) { + Unmap(); + + int fd = sys_open(path, O_RDONLY, 0); + if (fd == -1) { + return false; + } + +#if defined(__x86_64__) || defined(__aarch64__) || \ + (defined(__mips__) && _MIPS_SIM == _ABI64) + + struct kernel_stat st; + if (sys_fstat(fd, &st) == -1 || st.st_size < 0) { +#else + struct kernel_stat64 st; + if (sys_fstat64(fd, &st) == -1 || st.st_size < 0) { +#endif + sys_close(fd); + return false; + } + + // Strangely file size can be negative, but we check above that it is not. + size_t file_len = static_cast(st.st_size); + // If the file does not extend beyond the offset, simply use an empty + // MemoryRange and return true. Don't bother to call mmap() + // even though mmap() can handle an empty file on some platforms. + if (offset >= file_len) { + sys_close(fd); + return true; + } + +#if defined(__x86_64__) || defined(__aarch64__) || \ + (defined(__mips__) && _MIPS_SIM == _ABI64) + void* data = sys_mmap(NULL, file_len, PROT_READ, MAP_PRIVATE, fd, offset); +#else + if ((offset & 4095) != 0) { + // Not page aligned. + sys_close(fd); + return false; + } + void* data = sys_mmap2( + NULL, file_len, PROT_READ, MAP_PRIVATE, fd, offset >> 12); +#endif + sys_close(fd); + if (data == MAP_FAILED) { + return false; + } + + content_.Set(data, file_len - offset); + return true; +} + +void MemoryMappedFile::Unmap() { + if (content_.data()) { + sys_munmap(const_cast(content_.data()), content_.length()); + content_.Set(NULL, 0); + } +} + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/common/linux/memory_mapped_file.h b/TMessagesProj/jni/breakpad/common/linux/memory_mapped_file.h new file mode 100644 index 00000000..fa660cc9 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/memory_mapped_file.h @@ -0,0 +1,87 @@ +// Copyright (c) 2011, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// memory_mapped_file.h: Define the google_breakpad::MemoryMappedFile +// class, which maps a file into memory for read-only access. + +#ifndef COMMON_LINUX_MEMORY_MAPPED_FILE_H_ +#define COMMON_LINUX_MEMORY_MAPPED_FILE_H_ + +#include +#include "common/basictypes.h" +#include "common/memory_range.h" + +namespace google_breakpad { + +// A utility class for mapping a file into memory for read-only access of +// the file content. Its implementation avoids calling into libc functions +// by directly making system calls for open, close, mmap, and munmap. +class MemoryMappedFile { + public: + MemoryMappedFile(); + + // Constructor that calls Map() to map a file at |path| into memory. + // If Map() fails, the object behaves as if it is default constructed. + MemoryMappedFile(const char* path, size_t offset); + + ~MemoryMappedFile(); + + // Maps a file at |path| into memory, which can then be accessed via + // content() as a MemoryRange object or via data(), and returns true on + // success. Mapping an empty file will succeed but with data() and size() + // returning NULL and 0, respectively. An existing mapping is unmapped + // before a new mapping is created. + bool Map(const char* path, size_t offset); + + // Unmaps the memory for the mapped file. It's a no-op if no file is + // mapped. + void Unmap(); + + // Returns a MemoryRange object that covers the memory for the mapped + // file. The MemoryRange object is empty if no file is mapped. + const MemoryRange& content() const { return content_; } + + // Returns a pointer to the beginning of the memory for the mapped file. + // or NULL if no file is mapped or the mapped file is empty. + const void* data() const { return content_.data(); } + + // Returns the size in bytes of the mapped file, or zero if no file + // is mapped. + size_t size() const { return content_.length(); } + + private: + // Mapped file content as a MemoryRange object. + MemoryRange content_; + + DISALLOW_COPY_AND_ASSIGN(MemoryMappedFile); +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_MEMORY_MAPPED_FILE_H_ diff --git a/TMessagesProj/jni/breakpad/common/linux/safe_readlink.cc b/TMessagesProj/jni/breakpad/common/linux/safe_readlink.cc new file mode 100644 index 00000000..870c28af --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/safe_readlink.cc @@ -0,0 +1,53 @@ +// Copyright (c) 2011, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// safe_readlink.cc: Implement google_breakpad::SafeReadLink. +// See safe_readlink.h for details. + +#include + +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +bool SafeReadLink(const char* path, char* buffer, size_t buffer_size) { + // sys_readlink() does not add a NULL byte to |buffer|. In order to return + // a NULL-terminated string in |buffer|, |buffer_size| should be at least + // one byte longer than the expected path length. Also, sys_readlink() + // returns the actual path length on success, which does not count the + // NULL byte, so |result_size| should be less than |buffer_size|. + ssize_t result_size = sys_readlink(path, buffer, buffer_size); + if (result_size >= 0 && static_cast(result_size) < buffer_size) { + buffer[result_size] = '\0'; + return true; + } + return false; +} + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/common/linux/safe_readlink.h b/TMessagesProj/jni/breakpad/common/linux/safe_readlink.h new file mode 100644 index 00000000..4ae131b5 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/linux/safe_readlink.h @@ -0,0 +1,65 @@ +// Copyright (c) 2011, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// safe_readlink.h: Define the google_breakpad::SafeReadLink function, +// which wraps sys_readlink and gurantees the result is NULL-terminated. + +#ifndef COMMON_LINUX_SAFE_READLINK_H_ +#define COMMON_LINUX_SAFE_READLINK_H_ + +#include + +namespace google_breakpad { + +// This function wraps sys_readlink() and performs the same functionalty, +// but guarantees |buffer| is NULL-terminated if sys_readlink() returns +// no error. It takes the same arguments as sys_readlink(), but unlike +// sys_readlink(), it returns true on success. +// +// |buffer_size| specifies the size of |buffer| in bytes. As this function +// always NULL-terminates |buffer| on success, |buffer_size| should be +// at least one byte longer than the expected path length (e.g. PATH_MAX, +// which is typically defined as the maximum length of a path name +// including the NULL byte). +// +// The implementation of this function calls sys_readlink() instead of +// readlink(), it can thus be used in the context where calling to libc +// functions is discouraged. +bool SafeReadLink(const char* path, char* buffer, size_t buffer_size); + +// Same as the three-argument version of SafeReadLink() but deduces the +// size of |buffer| if it is a char array of known size. +template +bool SafeReadLink(const char* path, char (&buffer)[N]) { + return SafeReadLink(path, buffer, sizeof(buffer)); +} + +} // namespace google_breakpad + +#endif // COMMON_LINUX_SAFE_READLINK_H_ diff --git a/TMessagesProj/jni/breakpad/common/md5.cc b/TMessagesProj/jni/breakpad/common/md5.cc new file mode 100644 index 00000000..a0d9a1bd --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/md5.cc @@ -0,0 +1,251 @@ +/* + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +#include + +#include "common/md5.h" + +namespace google_breakpad { + +#ifndef WORDS_BIGENDIAN +#define byteReverse(buf, len) /* Nothing */ +#else +/* + * Note: this code is harmless on little-endian machines. + */ +static void byteReverse(unsigned char *buf, unsigned longs) +{ + u32 t; + do { + t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(u32 *) buf = t; + buf += 4; + } while (--longs); +} +#endif + +static void MD5Transform(u32 buf[4], u32 const in[16]); + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len) +{ + u32 t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((u32) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void MD5Final(unsigned char digest[16], struct MD5Context *ctx) +{ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + MD5Transform(ctx->buf, (u32 *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((u32 *) ctx->in)[14] = ctx->bits[0]; + ((u32 *) ctx->in)[15] = ctx->bits[1]; + + MD5Transform(ctx->buf, (u32 *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +static void MD5Transform(u32 buf[4], u32 const in[16]) +{ + u32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +} // namespace google_breakpad + diff --git a/TMessagesProj/jni/breakpad/common/md5.h b/TMessagesProj/jni/breakpad/common/md5.h new file mode 100644 index 00000000..2ab0ab95 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/md5.h @@ -0,0 +1,27 @@ +// Copyright 2007 Google Inc. All Rights Reserved. +// Author: liuli@google.com (Liu Li) +#ifndef COMMON_MD5_H__ +#define COMMON_MD5_H__ + +#include + +namespace google_breakpad { + +typedef uint32_t u32; +typedef uint8_t u8; + +struct MD5Context { + u32 buf[4]; + u32 bits[2]; + u8 in[64]; +}; + +void MD5Init(struct MD5Context *ctx); + +void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len); + +void MD5Final(unsigned char digest[16], struct MD5Context *ctx); + +} // namespace google_breakpad + +#endif // COMMON_MD5_H__ diff --git a/TMessagesProj/jni/breakpad/common/memory.h b/TMessagesProj/jni/breakpad/common/memory.h new file mode 100644 index 00000000..d6aa137d --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/memory.h @@ -0,0 +1,212 @@ +// Copyright (c) 2009, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef GOOGLE_BREAKPAD_COMMON_MEMORY_H_ +#define GOOGLE_BREAKPAD_COMMON_MEMORY_H_ + +#include +#include +#include +#include + +#include +#include + +#if defined(MEMORY_SANITIZER) +#include +#endif + +#ifdef __APPLE__ +#define sys_mmap mmap +#define sys_mmap2 mmap +#define sys_munmap munmap +#define MAP_ANONYMOUS MAP_ANON +#else +#include "third_party/lss/linux_syscall_support.h" +#endif + +namespace google_breakpad { + +// This is very simple allocator which fetches pages from the kernel directly. +// Thus, it can be used even when the heap may be corrupted. +// +// There is no free operation. The pages are only freed when the object is +// destroyed. +class PageAllocator { + public: + PageAllocator() + : page_size_(getpagesize()), + last_(NULL), + current_page_(NULL), + page_offset_(0) { + } + + ~PageAllocator() { + FreeAll(); + } + + void *Alloc(size_t bytes) { + if (!bytes) + return NULL; + + if (current_page_ && page_size_ - page_offset_ >= bytes) { + uint8_t *const ret = current_page_ + page_offset_; + page_offset_ += bytes; + if (page_offset_ == page_size_) { + page_offset_ = 0; + current_page_ = NULL; + } + + return ret; + } + + const size_t pages = + (bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_; + uint8_t *const ret = GetNPages(pages); + if (!ret) + return NULL; + + page_offset_ = + (page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeader)))) % + page_size_; + current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : NULL; + + return ret + sizeof(PageHeader); + } + + // Checks whether the page allocator owns the passed-in pointer. + // This method exists for testing pursposes only. + bool OwnsPointer(const void* p) { + for (PageHeader* header = last_; header; header = header->next) { + const char* current = reinterpret_cast(header); + if ((p >= current) && (p < current + header->num_pages * page_size_)) + return true; + } + + return false; + } + + private: + uint8_t *GetNPages(size_t num_pages) { +#if defined(__x86_64__) || defined(__aarch64__) || defined(__aarch64__) || \ + ((defined(__mips__) && _MIPS_SIM == _ABI64)) + void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +#else + void *a = sys_mmap2(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +#endif + if (a == MAP_FAILED) + return NULL; + +#if defined(MEMORY_SANITIZER) + // We need to indicate to MSan that memory allocated through sys_mmap is + // initialized, since linux_syscall_support.h doesn't have MSan hooks. + __msan_unpoison(a, page_size_ * num_pages); +#endif + + struct PageHeader *header = reinterpret_cast(a); + header->next = last_; + header->num_pages = num_pages; + last_ = header; + + return reinterpret_cast(a); + } + + void FreeAll() { + PageHeader *next; + + for (PageHeader *cur = last_; cur; cur = next) { + next = cur->next; + sys_munmap(cur, cur->num_pages * page_size_); + } + } + + struct PageHeader { + PageHeader *next; // pointer to the start of the next set of pages. + size_t num_pages; // the number of pages in this set. + }; + + const size_t page_size_; + PageHeader *last_; + uint8_t *current_page_; + size_t page_offset_; +}; + +// Wrapper to use with STL containers +template +struct PageStdAllocator : public std::allocator { + typedef typename std::allocator::pointer pointer; + typedef typename std::allocator::size_type size_type; + + explicit PageStdAllocator(PageAllocator& allocator): allocator_(allocator) {} + template PageStdAllocator(const PageStdAllocator& other) + : allocator_(other.allocator_) {} + + inline pointer allocate(size_type n, const void* = 0) { + return static_cast(allocator_.Alloc(sizeof(T) * n)); + } + + inline void deallocate(pointer, size_type) { + // The PageAllocator doesn't free. + } + + template struct rebind { + typedef PageStdAllocator other; + }; + + private: + // Silly workaround for the gcc from Android's ndk (gcc 4.6), which will + // otherwise complain that `other.allocator_` is private in the constructor + // code. + template friend struct PageStdAllocator; + + PageAllocator& allocator_; +}; + +// A wasteful vector is a std::vector, except that it allocates memory from a +// PageAllocator. It's wasteful because, when resizing, it always allocates a +// whole new array since the PageAllocator doesn't support realloc. +template +class wasteful_vector : public std::vector > { + public: + wasteful_vector(PageAllocator* allocator, unsigned size_hint = 16) + : std::vector >(PageStdAllocator(*allocator)) { + std::vector >::reserve(size_hint); + } +}; + +} // namespace google_breakpad + +inline void* operator new(size_t nbytes, + google_breakpad::PageAllocator& allocator) { + return allocator.Alloc(nbytes); +} + +#endif // GOOGLE_BREAKPAD_COMMON_MEMORY_H_ diff --git a/TMessagesProj/jni/breakpad/common/memory_range.h b/TMessagesProj/jni/breakpad/common/memory_range.h new file mode 100644 index 00000000..41dd2da6 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/memory_range.h @@ -0,0 +1,145 @@ +// Copyright (c) 2011, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// memory_range.h: Define the google_breakpad::MemoryRange class, which +// is a lightweight wrapper with a pointer and a length to encapsulate +// a contiguous range of memory. + +#ifndef COMMON_MEMORY_RANGE_H_ +#define COMMON_MEMORY_RANGE_H_ + +#include + +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +// A lightweight wrapper with a pointer and a length to encapsulate a +// contiguous range of memory. It provides helper methods for checked +// access of a subrange of the memory. Its implemementation does not +// allocate memory or call into libc functions, and is thus safer to use +// in a crashed environment. +class MemoryRange { + public: + MemoryRange() : data_(NULL), length_(0) {} + + MemoryRange(const void* data, size_t length) { + Set(data, length); + } + + // Returns true if this memory range contains no data. + bool IsEmpty() const { + // Set() guarantees that |length_| is zero if |data_| is NULL. + return length_ == 0; + } + + // Resets to an empty range. + void Reset() { + data_ = NULL; + length_ = 0; + } + + // Sets this memory range to point to |data| and its length to |length|. + void Set(const void* data, size_t length) { + data_ = reinterpret_cast(data); + // Always set |length_| to zero if |data_| is NULL. + length_ = data ? length : 0; + } + + // Returns true if this range covers a subrange of |sub_length| bytes + // at |sub_offset| bytes of this memory range, or false otherwise. + bool Covers(size_t sub_offset, size_t sub_length) const { + // The following checks verify that: + // 1. sub_offset is within [ 0 .. length_ - 1 ] + // 2. sub_offset + sub_length is within + // [ sub_offset .. length_ ] + return sub_offset < length_ && + sub_offset + sub_length >= sub_offset && + sub_offset + sub_length <= length_; + } + + // Returns a raw data pointer to a subrange of |sub_length| bytes at + // |sub_offset| bytes of this memory range, or NULL if the subrange + // is out of bounds. + const void* GetData(size_t sub_offset, size_t sub_length) const { + return Covers(sub_offset, sub_length) ? (data_ + sub_offset) : NULL; + } + + // Same as the two-argument version of GetData() but uses sizeof(DataType) + // as the subrange length and returns an |DataType| pointer for convenience. + template + const DataType* GetData(size_t sub_offset) const { + return reinterpret_cast( + GetData(sub_offset, sizeof(DataType))); + } + + // Returns a raw pointer to the |element_index|-th element of an array + // of elements of length |element_size| starting at |sub_offset| bytes + // of this memory range, or NULL if the element is out of bounds. + const void* GetArrayElement(size_t element_offset, + size_t element_size, + unsigned element_index) const { + size_t sub_offset = element_offset + element_index * element_size; + return GetData(sub_offset, element_size); + } + + // Same as the three-argument version of GetArrayElement() but deduces + // the element size using sizeof(ElementType) and returns an |ElementType| + // pointer for convenience. + template + const ElementType* GetArrayElement(size_t element_offset, + unsigned element_index) const { + return reinterpret_cast( + GetArrayElement(element_offset, sizeof(ElementType), element_index)); + } + + // Returns a subrange of |sub_length| bytes at |sub_offset| bytes of + // this memory range, or an empty range if the subrange is out of bounds. + MemoryRange Subrange(size_t sub_offset, size_t sub_length) const { + return Covers(sub_offset, sub_length) ? + MemoryRange(data_ + sub_offset, sub_length) : MemoryRange(); + } + + // Returns a pointer to the beginning of this memory range. + const uint8_t* data() const { return data_; } + + // Returns the length, in bytes, of this memory range. + size_t length() const { return length_; } + + private: + // Pointer to the beginning of this memory range. + const uint8_t* data_; + + // Length, in bytes, of this memory range. + size_t length_; +}; + +} // namespace google_breakpad + +#endif // COMMON_MEMORY_RANGE_H_ diff --git a/TMessagesProj/jni/breakpad/common/minidump_type_helper.h b/TMessagesProj/jni/breakpad/common/minidump_type_helper.h new file mode 100644 index 00000000..5a7d5a6a --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/minidump_type_helper.h @@ -0,0 +1,56 @@ +// Copyright (c) 2014, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_TYPE_HELPER_H_ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_TYPE_HELPER_H_ + +#include + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +template +struct MDTypeHelper; + +template <> +struct MDTypeHelper { + typedef MDRawDebug32 MDRawDebug; + typedef MDRawLinkMap32 MDRawLinkMap; +}; + +template <> +struct MDTypeHelper { + typedef MDRawDebug64 MDRawDebug; + typedef MDRawLinkMap64 MDRawLinkMap; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_TYPE_HELPER_H_ diff --git a/TMessagesProj/jni/breakpad/common/scoped_ptr.h b/TMessagesProj/jni/breakpad/common/scoped_ptr.h new file mode 100644 index 00000000..d137c186 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/scoped_ptr.h @@ -0,0 +1,404 @@ +// Copyright 2013 Google Inc. All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// Scopers help you manage ownership of a pointer, helping you easily manage the +// a pointer within a scope, and automatically destroying the pointer at the +// end of a scope. There are two main classes you will use, which correspond +// to the operators new/delete and new[]/delete[]. +// +// Example usage (scoped_ptr): +// { +// scoped_ptr foo(new Foo("wee")); +// } // foo goes out of scope, releasing the pointer with it. +// +// { +// scoped_ptr foo; // No pointer managed. +// foo.reset(new Foo("wee")); // Now a pointer is managed. +// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed. +// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed. +// foo->Method(); // Foo::Method() called. +// foo.get()->Method(); // Foo::Method() called. +// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer +// // manages a pointer. +// foo.reset(new Foo("wee4")); // foo manages a pointer again. +// foo.reset(); // Foo("wee4") destroyed, foo no longer +// // manages a pointer. +// } // foo wasn't managing a pointer, so nothing was destroyed. +// +// Example usage (scoped_array): +// { +// scoped_array foo(new Foo[100]); +// foo.get()->Method(); // Foo::Method on the 0th element. +// foo[10].Method(); // Foo::Method on the 10th element. +// } + +#ifndef COMMON_SCOPED_PTR_H_ +#define COMMON_SCOPED_PTR_H_ + +// This is an implementation designed to match the anticipated future TR2 +// implementation of the scoped_ptr class, and its closely-related brethren, +// scoped_array, scoped_ptr_malloc. + +#include +#include +#include + +namespace google_breakpad { + +// A scoped_ptr is like a T*, except that the destructor of scoped_ptr +// automatically deletes the pointer it holds (if any). +// That is, scoped_ptr owns the T object that it points to. +// Like a T*, a scoped_ptr may hold either NULL or a pointer to a T object. +// Also like T*, scoped_ptr is thread-compatible, and once you +// dereference it, you get the threadsafety guarantees of T. +// +// The size of a scoped_ptr is small: +// sizeof(scoped_ptr) == sizeof(C*) +template +class scoped_ptr { + public: + + // The element type + typedef C element_type; + + // Constructor. Defaults to initializing with NULL. + // There is no way to create an uninitialized scoped_ptr. + // The input parameter must be allocated with new. + explicit scoped_ptr(C* p = NULL) : ptr_(p) { } + + // Destructor. If there is a C object, delete it. + // We don't need to test ptr_ == NULL because C++ does that for us. + ~scoped_ptr() { + enum { type_must_be_complete = sizeof(C) }; + delete ptr_; + } + + // Reset. Deletes the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (p != ptr_) { + enum { type_must_be_complete = sizeof(C) }; + delete ptr_; + ptr_ = p; + } + } + + // Accessors to get the owned object. + // operator* and operator-> will assert() if there is no current object. + C& operator*() const { + assert(ptr_ != NULL); + return *ptr_; + } + C* operator->() const { + assert(ptr_ != NULL); + return ptr_; + } + C* get() const { return ptr_; } + + // Comparison operators. + // These return whether two scoped_ptr refer to the same object, not just to + // two different but equal objects. + bool operator==(C* p) const { return ptr_ == p; } + bool operator!=(C* p) const { return ptr_ != p; } + + // Swap two scoped pointers. + void swap(scoped_ptr& p2) { + C* tmp = ptr_; + ptr_ = p2.ptr_; + p2.ptr_ = tmp; + } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* retVal = ptr_; + ptr_ = NULL; + return retVal; + } + + private: + C* ptr_; + + // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't + // make sense, and if C2 == C, it still doesn't make sense because you should + // never have the same object owned by two different scoped_ptrs. + template bool operator==(scoped_ptr const& p2) const; + template bool operator!=(scoped_ptr const& p2) const; + + // Disallow evil constructors + scoped_ptr(const scoped_ptr&); + void operator=(const scoped_ptr&); +}; + +// Free functions +template +void swap(scoped_ptr& p1, scoped_ptr& p2) { + p1.swap(p2); +} + +template +bool operator==(C* p1, const scoped_ptr& p2) { + return p1 == p2.get(); +} + +template +bool operator!=(C* p1, const scoped_ptr& p2) { + return p1 != p2.get(); +} + +// scoped_array is like scoped_ptr, except that the caller must allocate +// with new [] and the destructor deletes objects with delete []. +// +// As with scoped_ptr, a scoped_array either points to an object +// or is NULL. A scoped_array owns the object that it points to. +// scoped_array is thread-compatible, and once you index into it, +// the returned objects have only the threadsafety guarantees of T. +// +// Size: sizeof(scoped_array) == sizeof(C*) +template +class scoped_array { + public: + + // The element type + typedef C element_type; + + // Constructor. Defaults to intializing with NULL. + // There is no way to create an uninitialized scoped_array. + // The input parameter must be allocated with new []. + explicit scoped_array(C* p = NULL) : array_(p) { } + + // Destructor. If there is a C object, delete it. + // We don't need to test ptr_ == NULL because C++ does that for us. + ~scoped_array() { + enum { type_must_be_complete = sizeof(C) }; + delete[] array_; + } + + // Reset. Deletes the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (p != array_) { + enum { type_must_be_complete = sizeof(C) }; + delete[] array_; + array_ = p; + } + } + + // Get one element of the current object. + // Will assert() if there is no current object, or index i is negative. + C& operator[](ptrdiff_t i) const { + assert(i >= 0); + assert(array_ != NULL); + return array_[i]; + } + + // Get a pointer to the zeroth element of the current object. + // If there is no current object, return NULL. + C* get() const { + return array_; + } + + // Comparison operators. + // These return whether two scoped_array refer to the same object, not just to + // two different but equal objects. + bool operator==(C* p) const { return array_ == p; } + bool operator!=(C* p) const { return array_ != p; } + + // Swap two scoped arrays. + void swap(scoped_array& p2) { + C* tmp = array_; + array_ = p2.array_; + p2.array_ = tmp; + } + + // Release an array. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* retVal = array_; + array_ = NULL; + return retVal; + } + + private: + C* array_; + + // Forbid comparison of different scoped_array types. + template bool operator==(scoped_array const& p2) const; + template bool operator!=(scoped_array const& p2) const; + + // Disallow evil constructors + scoped_array(const scoped_array&); + void operator=(const scoped_array&); +}; + +// Free functions +template +void swap(scoped_array& p1, scoped_array& p2) { + p1.swap(p2); +} + +template +bool operator==(C* p1, const scoped_array& p2) { + return p1 == p2.get(); +} + +template +bool operator!=(C* p1, const scoped_array& p2) { + return p1 != p2.get(); +} + +// This class wraps the c library function free() in a class that can be +// passed as a template argument to scoped_ptr_malloc below. +class ScopedPtrMallocFree { + public: + inline void operator()(void* x) const { + free(x); + } +}; + +// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a +// second template argument, the functor used to free the object. + +template +class scoped_ptr_malloc { + public: + + // The element type + typedef C element_type; + + // Constructor. Defaults to initializing with NULL. + // There is no way to create an uninitialized scoped_ptr. + // The input parameter must be allocated with an allocator that matches the + // Free functor. For the default Free functor, this is malloc, calloc, or + // realloc. + explicit scoped_ptr_malloc(C* p = NULL): ptr_(p) {} + + // Destructor. If there is a C object, call the Free functor. + ~scoped_ptr_malloc() { + reset(); + } + + // Reset. Calls the Free functor on the current owned object, if any. + // Then takes ownership of a new object, if given. + // this->reset(this->get()) works. + void reset(C* p = NULL) { + if (ptr_ != p) { + FreeProc free_proc; + free_proc(ptr_); + ptr_ = p; + } + } + + // Get the current object. + // operator* and operator-> will cause an assert() failure if there is + // no current object. + C& operator*() const { + assert(ptr_ != NULL); + return *ptr_; + } + + C* operator->() const { + assert(ptr_ != NULL); + return ptr_; + } + + C* get() const { + return ptr_; + } + + // Comparison operators. + // These return whether a scoped_ptr_malloc and a plain pointer refer + // to the same object, not just to two different but equal objects. + // For compatibility with the boost-derived implementation, these + // take non-const arguments. + bool operator==(C* p) const { + return ptr_ == p; + } + + bool operator!=(C* p) const { + return ptr_ != p; + } + + // Swap two scoped pointers. + void swap(scoped_ptr_malloc & b) { + C* tmp = b.ptr_; + b.ptr_ = ptr_; + ptr_ = tmp; + } + + // Release a pointer. + // The return value is the current pointer held by this object. + // If this object holds a NULL pointer, the return value is NULL. + // After this operation, this object will hold a NULL pointer, + // and will not own the object any more. + C* release() { + C* tmp = ptr_; + ptr_ = NULL; + return tmp; + } + + private: + C* ptr_; + + // no reason to use these: each scoped_ptr_malloc should have its own object + template + bool operator==(scoped_ptr_malloc const& p) const; + template + bool operator!=(scoped_ptr_malloc const& p) const; + + // Disallow evil constructors + scoped_ptr_malloc(const scoped_ptr_malloc&); + void operator=(const scoped_ptr_malloc&); +}; + +template inline +void swap(scoped_ptr_malloc& a, scoped_ptr_malloc& b) { + a.swap(b); +} + +template inline +bool operator==(C* p, const scoped_ptr_malloc& b) { + return p == b.get(); +} + +template inline +bool operator!=(C* p, const scoped_ptr_malloc& b) { + return p != b.get(); +} + +} // namespace google_breakpad + +#endif // COMMON_SCOPED_PTR_H_ diff --git a/TMessagesProj/jni/breakpad/common/string_conversion.cc b/TMessagesProj/jni/breakpad/common/string_conversion.cc new file mode 100644 index 00000000..9c0d623f --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/string_conversion.cc @@ -0,0 +1,155 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#include + +#include "common/convert_UTF.h" +#include "common/scoped_ptr.h" +#include "common/string_conversion.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +using std::vector; + +void UTF8ToUTF16(const char *in, vector *out) { + size_t source_length = strlen(in); + const UTF8 *source_ptr = reinterpret_cast(in); + const UTF8 *source_end_ptr = source_ptr + source_length; + // Erase the contents and zero fill to the expected size + out->clear(); + out->insert(out->begin(), source_length, 0); + uint16_t *target_ptr = &(*out)[0]; + uint16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(uint16_t); + ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + // Resize to be the size of the # of converted characters + NULL + out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0); +} + +int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]) { + const UTF8 *source_ptr = reinterpret_cast(in); + const UTF8 *source_end_ptr = source_ptr + sizeof(char); + uint16_t *target_ptr = out; + uint16_t *target_end_ptr = target_ptr + 2 * sizeof(uint16_t); + out[0] = out[1] = 0; + + // Process one character at a time + while (1) { + ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + if (result == conversionOK) + return static_cast(source_ptr - reinterpret_cast(in)); + + // Add another character to the input stream and try again + source_ptr = reinterpret_cast(in); + ++source_end_ptr; + + if (source_end_ptr > reinterpret_cast(in) + in_length) + break; + } + + return 0; +} + +void UTF32ToUTF16(const wchar_t *in, vector *out) { + size_t source_length = wcslen(in); + const UTF32 *source_ptr = reinterpret_cast(in); + const UTF32 *source_end_ptr = source_ptr + source_length; + // Erase the contents and zero fill to the expected size + out->clear(); + out->insert(out->begin(), source_length, 0); + uint16_t *target_ptr = &(*out)[0]; + uint16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(uint16_t); + ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + // Resize to be the size of the # of converted characters + NULL + out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0); +} + +void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]) { + const UTF32 *source_ptr = reinterpret_cast(&in); + const UTF32 *source_end_ptr = source_ptr + 1; + uint16_t *target_ptr = out; + uint16_t *target_end_ptr = target_ptr + 2 * sizeof(uint16_t); + out[0] = out[1] = 0; + ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + if (result != conversionOK) { + out[0] = out[1] = 0; + } +} + +static inline uint16_t Swap(uint16_t value) { + return (value >> 8) | static_cast(value << 8); +} + +string UTF16ToUTF8(const vector &in, bool swap) { + const UTF16 *source_ptr = &in[0]; + scoped_array source_buffer; + + // If we're to swap, we need to make a local copy and swap each byte pair + if (swap) { + int idx = 0; + source_buffer.reset(new uint16_t[in.size()]); + UTF16 *source_buffer_ptr = source_buffer.get(); + for (vector::const_iterator it = in.begin(); + it != in.end(); ++it, ++idx) + source_buffer_ptr[idx] = Swap(*it); + + source_ptr = source_buffer.get(); + } + + // The maximum expansion would be 4x the size of the input string. + const UTF16 *source_end_ptr = source_ptr + in.size(); + size_t target_capacity = in.size() * 4; + scoped_array target_buffer(new UTF8[target_capacity]); + UTF8 *target_ptr = target_buffer.get(); + UTF8 *target_end_ptr = target_ptr + target_capacity; + ConversionResult result = ConvertUTF16toUTF8(&source_ptr, source_end_ptr, + &target_ptr, target_end_ptr, + strictConversion); + + if (result == conversionOK) { + const char *targetPtr = reinterpret_cast(target_buffer.get()); + return targetPtr; + } + + return ""; +} + +} // namespace google_breakpad diff --git a/TMessagesProj/jni/breakpad/common/string_conversion.h b/TMessagesProj/jni/breakpad/common/string_conversion.h new file mode 100644 index 00000000..b9ba96a2 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/string_conversion.h @@ -0,0 +1,68 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// string_conversion.h: Conversion between different UTF-8/16/32 encodings. + +#ifndef COMMON_STRING_CONVERSION_H__ +#define COMMON_STRING_CONVERSION_H__ + +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +using std::vector; + +// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the +// conversion failed, |out| will be zero length. +void UTF8ToUTF16(const char *in, vector *out); + +// Convert at least one character (up to a maximum of |in_length|) from |in| +// to UTF-16 into |out|. Return the number of characters consumed from |in|. +// Any unused characters in |out| will be initialized to 0. No memory will +// be allocated by this routine. +int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]); + +// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the +// conversion failed, |out| will be zero length. +void UTF32ToUTF16(const wchar_t *in, vector *out); + +// Convert |in| to UTF-16 into |out|. Any unused characters in |out| will be +// initialized to 0. No memory will be allocated by this routine. +void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]); + +// Convert |in| to UTF-8. If |swap| is true, swap bytes before converting. +string UTF16ToUTF8(const vector &in, bool swap); + +} // namespace google_breakpad + +#endif // COMMON_STRING_CONVERSION_H__ diff --git a/TMessagesProj/jni/breakpad/common/symbol_data.h b/TMessagesProj/jni/breakpad/common/symbol_data.h new file mode 100644 index 00000000..2cf15a85 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/symbol_data.h @@ -0,0 +1,42 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2013 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef COMMON_SYMBOL_DATA_H_ +#define COMMON_SYMBOL_DATA_H_ + +// Control what data is used from the symbol file. +enum SymbolData { + ALL_SYMBOL_DATA, + NO_CFI, + ONLY_CFI +}; + +#endif // COMMON_SYMBOL_DATA_H_ diff --git a/TMessagesProj/jni/breakpad/common/unordered.h b/TMessagesProj/jni/breakpad/common/unordered.h new file mode 100644 index 00000000..ec665cc0 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/unordered.h @@ -0,0 +1,62 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// Include this file to use unordered_map and unordered_set. If tr1 +// or C++11 is not available, you can switch to using hash_set and +// hash_map by defining BP_USE_HASH_SET. + +#ifndef COMMON_UNORDERED_H_ +#define COMMON_UNORDERED_H_ + +#if defined(BP_USE_HASH_SET) +#include +#include + +// For hash. +#include "util/hash/hash.h" + +template > +struct unordered_map : public hash_map {}; +template > +struct unordered_set : public hash_set {}; + +#elif defined(_LIBCPP_VERSION) // c++11 +#include +#include +using std::unordered_map; +using std::unordered_set; + +#else // Fallback to tr1::unordered +#include +#include +using std::tr1::unordered_map; +using std::tr1::unordered_set; +#endif + +#endif // COMMON_UNORDERED_H_ diff --git a/TMessagesProj/jni/breakpad/common/using_std_string.h b/TMessagesProj/jni/breakpad/common/using_std_string.h new file mode 100644 index 00000000..13c1da59 --- /dev/null +++ b/TMessagesProj/jni/breakpad/common/using_std_string.h @@ -0,0 +1,65 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2012, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// Original author: Ivan Penkov + +// using_std_string.h: Allows building this code in environments where +// global string (::string) exists. +// +// The problem: +// ------------- +// Let's say you want to build this code in an environment where a global +// string type is defined (i.e. ::string). Now, let's suppose that ::string +// is different that std::string and you'd like to have the option to easily +// choose between the two string types. Ideally you'd like to control which +// string type is chosen by simply #defining an identifier. +// +// The solution: +// ------------- +// #define HAS_GLOBAL_STRING somewhere in a global header file and then +// globally replace std::string with string. Then include this header +// file everywhere where string is used. If you want to revert back to +// using std::string, simply remove the #define (HAS_GLOBAL_STRING). + +#ifndef THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_ +#define THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_ + +#ifdef HAS_GLOBAL_STRING + typedef ::string google_breakpad_string; +#else + using std::string; + typedef std::string google_breakpad_string; +#endif + +// Inicates that type google_breakpad_string is defined +#define HAS_GOOGLE_BREAKPAD_STRING + +#endif // THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/breakpad_types.h b/TMessagesProj/jni/breakpad/google_breakpad/common/breakpad_types.h new file mode 100644 index 00000000..e92436ff --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/breakpad_types.h @@ -0,0 +1,86 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* breakpad_types.h: Precise-width types + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file ensures that types uintN_t are defined for N = 8, 16, 32, and + * 64. Types of precise widths are crucial to the task of writing data + * structures on one platform and reading them on another. + * + * Author: Mark Mentovai */ + +#ifndef GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__ +#define GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__ + +#ifndef _WIN32 + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif /* __STDC_FORMAT_MACROS */ +#include + +#else /* !_WIN32 */ + +#if _MSC_VER >= 1600 +#include +#elif defined(BREAKPAD_CUSTOM_STDINT_H) +/* Visual C++ Pre-2010 did not ship a stdint.h, so allow + * consumers of this library to provide their own because + * there are often subtle type incompatibilities. + */ +#include BREAKPAD_CUSTOM_STDINT_H +#else +#include + +typedef unsigned __int8 uint8_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#endif + +#endif /* !_WIN32 */ + +typedef struct { + uint64_t high; + uint64_t low; +} uint128_struct; + +typedef uint64_t breakpad_time_t; + +/* Try to get PRIx64 from inttypes.h, but if it's not defined, fall back to + * llx, which is the format string for "long long" - this is a 64-bit + * integral type on many systems. */ +#ifndef PRIx64 +#define PRIx64 "llx" +#endif /* !PRIx64 */ + +#endif /* GOOGLE_BREAKPAD_COMMON_BREAKPAD_TYPES_H__ */ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_amd64.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_amd64.h new file mode 100644 index 00000000..4256706d --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_amd64.h @@ -0,0 +1,235 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on amd64. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by ensuring + * ensuring that all members are aligned on their natural boundaries. In + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * These definitions may be extended to support handling minidump files + * for other CPUs and other operating systems. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably in terms of interoperability with minidumps + * produced by DbgHelp on Windows, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. DbgHelp + * on Windows is assumed to be the reference implementation; this file + * seeks to provide a cross-platform compatible implementation. To avoid + * collisions with the types and values defined and used by DbgHelp in the + * event that this implementation is used on Windows, each type and value + * defined here is given a new name, beginning with "MD". Names of the + * equivalent types and values in the Windows Platform SDK are given in + * comments. + * + * Author: Mark Mentovai + * Change to split into its own file: Neal Sidhwaney */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__ + + +/* + * AMD64 support, see WINNT.H + */ + +typedef struct { + uint16_t control_word; + uint16_t status_word; + uint8_t tag_word; + uint8_t reserved1; + uint16_t error_opcode; + uint32_t error_offset; + uint16_t error_selector; + uint16_t reserved2; + uint32_t data_offset; + uint16_t data_selector; + uint16_t reserved3; + uint32_t mx_csr; + uint32_t mx_csr_mask; + uint128_struct float_registers[8]; + uint128_struct xmm_registers[16]; + uint8_t reserved4[96]; +} MDXmmSaveArea32AMD64; /* XMM_SAVE_AREA32 */ + +#define MD_CONTEXT_AMD64_VR_COUNT 26 + +typedef struct { + /* + * Register parameter home addresses. + */ + uint64_t p1_home; + uint64_t p2_home; + uint64_t p3_home; + uint64_t p4_home; + uint64_t p5_home; + uint64_t p6_home; + + /* The next field determines the layout of the structure, and which parts + * of it are populated */ + uint32_t context_flags; + uint32_t mx_csr; + + /* The next register is included with MD_CONTEXT_AMD64_CONTROL */ + uint16_t cs; + + /* The next 4 registers are included with MD_CONTEXT_AMD64_SEGMENTS */ + uint16_t ds; + uint16_t es; + uint16_t fs; + uint16_t gs; + + /* The next 2 registers are included with MD_CONTEXT_AMD64_CONTROL */ + uint16_t ss; + uint32_t eflags; + + /* The next 6 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */ + uint64_t dr0; + uint64_t dr1; + uint64_t dr2; + uint64_t dr3; + uint64_t dr6; + uint64_t dr7; + + /* The next 4 registers are included with MD_CONTEXT_AMD64_INTEGER */ + uint64_t rax; + uint64_t rcx; + uint64_t rdx; + uint64_t rbx; + + /* The next register is included with MD_CONTEXT_AMD64_CONTROL */ + uint64_t rsp; + + /* The next 11 registers are included with MD_CONTEXT_AMD64_INTEGER */ + uint64_t rbp; + uint64_t rsi; + uint64_t rdi; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + + /* The next register is included with MD_CONTEXT_AMD64_CONTROL */ + uint64_t rip; + + /* The next set of registers are included with + * MD_CONTEXT_AMD64_FLOATING_POINT + */ + union { + MDXmmSaveArea32AMD64 flt_save; + struct { + uint128_struct header[2]; + uint128_struct legacy[8]; + uint128_struct xmm0; + uint128_struct xmm1; + uint128_struct xmm2; + uint128_struct xmm3; + uint128_struct xmm4; + uint128_struct xmm5; + uint128_struct xmm6; + uint128_struct xmm7; + uint128_struct xmm8; + uint128_struct xmm9; + uint128_struct xmm10; + uint128_struct xmm11; + uint128_struct xmm12; + uint128_struct xmm13; + uint128_struct xmm14; + uint128_struct xmm15; + } sse_registers; + }; + + uint128_struct vector_register[MD_CONTEXT_AMD64_VR_COUNT]; + uint64_t vector_control; + + /* The next 5 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */ + uint64_t debug_control; + uint64_t last_branch_to_rip; + uint64_t last_branch_from_rip; + uint64_t last_exception_to_rip; + uint64_t last_exception_from_rip; + +} MDRawContextAMD64; /* CONTEXT */ + +/* For (MDRawContextAMD64).context_flags. These values indicate the type of + * context stored in the structure. The high 24 bits identify the CPU, the + * low 8 bits identify the type of context saved. */ +#define MD_CONTEXT_AMD64 0x00100000 /* CONTEXT_AMD64 */ +#define MD_CONTEXT_AMD64_CONTROL (MD_CONTEXT_AMD64 | 0x00000001) + /* CONTEXT_CONTROL */ +#define MD_CONTEXT_AMD64_INTEGER (MD_CONTEXT_AMD64 | 0x00000002) + /* CONTEXT_INTEGER */ +#define MD_CONTEXT_AMD64_SEGMENTS (MD_CONTEXT_AMD64 | 0x00000004) + /* CONTEXT_SEGMENTS */ +#define MD_CONTEXT_AMD64_FLOATING_POINT (MD_CONTEXT_AMD64 | 0x00000008) + /* CONTEXT_FLOATING_POINT */ +#define MD_CONTEXT_AMD64_DEBUG_REGISTERS (MD_CONTEXT_AMD64 | 0x00000010) + /* CONTEXT_DEBUG_REGISTERS */ +#define MD_CONTEXT_AMD64_XSTATE (MD_CONTEXT_AMD64 | 0x00000040) + /* CONTEXT_XSTATE */ + +/* WinNT.h refers to CONTEXT_MMX_REGISTERS but doesn't appear to define it + * I think it really means CONTEXT_FLOATING_POINT. + */ + +#define MD_CONTEXT_AMD64_FULL (MD_CONTEXT_AMD64_CONTROL | \ + MD_CONTEXT_AMD64_INTEGER | \ + MD_CONTEXT_AMD64_FLOATING_POINT) + /* CONTEXT_FULL */ + +#define MD_CONTEXT_AMD64_ALL (MD_CONTEXT_AMD64_FULL | \ + MD_CONTEXT_AMD64_SEGMENTS | \ + MD_CONTEXT_X86_DEBUG_REGISTERS) + /* CONTEXT_ALL */ + + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__ */ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_arm.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_arm.h new file mode 100644 index 00000000..6a711383 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_arm.h @@ -0,0 +1,151 @@ +/* Copyright (c) 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on ARM. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by + * ensuring that all members are aligned on their natural boundaries. + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. + * + * Author: Julian Seward + */ + +/* + * ARM support + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__ + +#define MD_FLOATINGSAVEAREA_ARM_FPR_COUNT 32 +#define MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT 8 + +/* + * Note that these structures *do not* map directly to the CONTEXT + * structure defined in WinNT.h in the Windows Mobile SDK. That structure + * does not accomodate VFPv3, and I'm unsure if it was ever used in the + * wild anyway, as Windows CE only seems to produce "cedumps" which + * are not exactly minidumps. + */ +typedef struct { + uint64_t fpscr; /* FPU status register */ + + /* 32 64-bit floating point registers, d0 .. d31. */ + uint64_t regs[MD_FLOATINGSAVEAREA_ARM_FPR_COUNT]; + + /* Miscellaneous control words */ + uint32_t extra[MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT]; +} MDFloatingSaveAreaARM; + +#define MD_CONTEXT_ARM_GPR_COUNT 16 + +typedef struct { + /* The next field determines the layout of the structure, and which parts + * of it are populated + */ + uint32_t context_flags; + + /* 16 32-bit integer registers, r0 .. r15 + * Note the following fixed uses: + * r13 is the stack pointer + * r14 is the link register + * r15 is the program counter + */ + uint32_t iregs[MD_CONTEXT_ARM_GPR_COUNT]; + + /* CPSR (flags, basically): 32 bits: + bit 31 - N (negative) + bit 30 - Z (zero) + bit 29 - C (carry) + bit 28 - V (overflow) + bit 27 - Q (saturation flag, sticky) + All other fields -- ignore */ + uint32_t cpsr; + + /* The next field is included with MD_CONTEXT_ARM_FLOATING_POINT */ + MDFloatingSaveAreaARM float_save; + +} MDRawContextARM; + +/* Indices into iregs for registers with a dedicated or conventional + * purpose. + */ +enum MDARMRegisterNumbers { + MD_CONTEXT_ARM_REG_IOS_FP = 7, + MD_CONTEXT_ARM_REG_FP = 11, + MD_CONTEXT_ARM_REG_SP = 13, + MD_CONTEXT_ARM_REG_LR = 14, + MD_CONTEXT_ARM_REG_PC = 15 +}; + +/* For (MDRawContextARM).context_flags. These values indicate the type of + * context stored in the structure. */ +/* CONTEXT_ARM from the Windows CE 5.0 SDK. This value isn't correct + * because this bit can be used for flags. Presumably this value was + * never actually used in minidumps, but only in "CEDumps" which + * are a whole parallel minidump file format for Windows CE. + * Therefore, Breakpad defines its own value for ARM CPUs. + */ +#define MD_CONTEXT_ARM_OLD 0x00000040 +/* This value was chosen to avoid likely conflicts with MD_CONTEXT_* + * for other CPUs. */ +#define MD_CONTEXT_ARM 0x40000000 +#define MD_CONTEXT_ARM_INTEGER (MD_CONTEXT_ARM | 0x00000002) +#define MD_CONTEXT_ARM_FLOATING_POINT (MD_CONTEXT_ARM | 0x00000004) + +#define MD_CONTEXT_ARM_FULL (MD_CONTEXT_ARM_INTEGER | \ + MD_CONTEXT_ARM_FLOATING_POINT) + +#define MD_CONTEXT_ARM_ALL (MD_CONTEXT_ARM_INTEGER | \ + MD_CONTEXT_ARM_FLOATING_POINT) + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM_H__ */ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_arm64.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_arm64.h new file mode 100644 index 00000000..5ace0d9d --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_arm64.h @@ -0,0 +1,140 @@ +/* Copyright 2013 Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on ARM. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by + * ensuring that all members are aligned on their natural boundaries. + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. + * + * Author: Colin Blundell + */ + +/* + * ARM64 support + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__ + +#define MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT 32 + +typedef struct { + uint32_t fpsr; /* FPU status register */ + uint32_t fpcr; /* FPU control register */ + + /* 32 128-bit floating point registers, d0 .. d31. */ + uint128_struct regs[MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT]; +} MDFloatingSaveAreaARM64; + +#define MD_CONTEXT_ARM64_GPR_COUNT 33 + +/* Use the same 32-bit alignment when accessing this structure from 64-bit code + * as is used natively in 32-bit code. */ +#pragma pack(push, 4) + +typedef struct { + /* The next field determines the layout of the structure, and which parts + * of it are populated + */ + uint64_t context_flags; + + /* 33 64-bit integer registers, x0 .. x31 + the PC + * Note the following fixed uses: + * x29 is the frame pointer + * x30 is the link register + * x31 is the stack pointer + * The PC is effectively x32. + */ + uint64_t iregs[MD_CONTEXT_ARM64_GPR_COUNT]; + + /* CPSR (flags, basically): 32 bits: + bit 31 - N (negative) + bit 30 - Z (zero) + bit 29 - C (carry) + bit 28 - V (overflow) + bit 27 - Q (saturation flag, sticky) + All other fields -- ignore */ + uint32_t cpsr; + + /* The next field is included with MD_CONTEXT64_ARM_FLOATING_POINT */ + MDFloatingSaveAreaARM64 float_save; + +} MDRawContextARM64; + +#pragma pack(pop) + +/* Indices into iregs for registers with a dedicated or conventional + * purpose. + */ +enum MDARM64RegisterNumbers { + MD_CONTEXT_ARM64_REG_FP = 29, + MD_CONTEXT_ARM64_REG_LR = 30, + MD_CONTEXT_ARM64_REG_SP = 31, + MD_CONTEXT_ARM64_REG_PC = 32 +}; + +/* For (MDRawContextARM64).context_flags. These values indicate the type of + * context stored in the structure. MD_CONTEXT_ARM64 is Breakpad-defined. + * This value was chosen to avoid likely conflicts with MD_CONTEXT_* + * for other CPUs. */ +#define MD_CONTEXT_ARM64 0x80000000 +#define MD_CONTEXT_ARM64_INTEGER (MD_CONTEXT_ARM64 | 0x00000002) +#define MD_CONTEXT_ARM64_FLOATING_POINT (MD_CONTEXT_ARM64 | 0x00000004) + +#define MD_CONTEXT_ARM64_FULL (MD_CONTEXT_ARM64_INTEGER | \ + MD_CONTEXT_ARM64_FLOATING_POINT) + +#define MD_CONTEXT_ARM64_ALL (MD_CONTEXT_ARM64_INTEGER | \ + MD_CONTEXT_ARM64_FLOATING_POINT) + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_ARM64_H__ */ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_mips.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_mips.h new file mode 100644 index 00000000..6cbe3023 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_mips.h @@ -0,0 +1,160 @@ +/* Copyright (c) 2013, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on MIPS. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by + * ensuring that all members are aligned on their natural boundaries. + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. + * + * Author: Chris Dearman + */ + +/* + * MIPS support + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__ + +#define MD_CONTEXT_MIPS_GPR_COUNT 32 +#define MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT 32 +#define MD_CONTEXT_MIPS_DSP_COUNT 3 + +/* + * Note that these structures *do not* map directly to the CONTEXT + * structure defined in WinNT.h in the Windows Mobile SDK. That structure + * does not accomodate VFPv3, and I'm unsure if it was ever used in the + * wild anyway, as Windows CE only seems to produce "cedumps" which + * are not exactly minidumps. + */ +typedef struct { + /* 32 64-bit floating point registers, f0..f31 */ + uint64_t regs[MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT]; + + uint32_t fpcsr; /* FPU status register. */ + uint32_t fir; /* FPU implementation register. */ +} MDFloatingSaveAreaMIPS; + +typedef struct { + /* The next field determines the layout of the structure, and which parts + * of it are populated. + */ + uint32_t context_flags; + uint32_t _pad0; + + /* 32 64-bit integer registers, r0..r31. + * Note the following fixed uses: + * r29 is the stack pointer. + * r31 is the return address. + */ + uint64_t iregs[MD_CONTEXT_MIPS_GPR_COUNT]; + + /* multiply/divide result. */ + uint64_t mdhi, mdlo; + + /* DSP accumulators. */ + uint32_t hi[MD_CONTEXT_MIPS_DSP_COUNT]; + uint32_t lo[MD_CONTEXT_MIPS_DSP_COUNT]; + uint32_t dsp_control; + uint32_t _pad1; + + uint64_t epc; + uint64_t badvaddr; + uint32_t status; + uint32_t cause; + + /* The next field is included with MD_CONTEXT_MIPS_FLOATING_POINT. */ + MDFloatingSaveAreaMIPS float_save; + +} MDRawContextMIPS; + +/* Indices into iregs for registers with a dedicated or conventional + * purpose. + */ +enum MDMIPSRegisterNumbers { + MD_CONTEXT_MIPS_REG_S0 = 16, + MD_CONTEXT_MIPS_REG_S1 = 17, + MD_CONTEXT_MIPS_REG_S2 = 18, + MD_CONTEXT_MIPS_REG_S3 = 19, + MD_CONTEXT_MIPS_REG_S4 = 20, + MD_CONTEXT_MIPS_REG_S5 = 21, + MD_CONTEXT_MIPS_REG_S6 = 22, + MD_CONTEXT_MIPS_REG_S7 = 23, + MD_CONTEXT_MIPS_REG_GP = 28, + MD_CONTEXT_MIPS_REG_SP = 29, + MD_CONTEXT_MIPS_REG_FP = 30, + MD_CONTEXT_MIPS_REG_RA = 31, +}; + +/* For (MDRawContextMIPS).context_flags. These values indicate the type of + * context stored in the structure. */ +/* CONTEXT_MIPS from the Windows CE 5.0 SDK. This value isn't correct + * because this bit can be used for flags. Presumably this value was + * never actually used in minidumps, but only in "CEDumps" which + * are a whole parallel minidump file format for Windows CE. + * Therefore, Breakpad defines its own value for MIPS CPUs. + */ +#define MD_CONTEXT_MIPS 0x00040000 +#define MD_CONTEXT_MIPS_INTEGER (MD_CONTEXT_MIPS | 0x00000002) +#define MD_CONTEXT_MIPS_FLOATING_POINT (MD_CONTEXT_MIPS | 0x00000004) +#define MD_CONTEXT_MIPS_DSP (MD_CONTEXT_MIPS | 0x00000008) + +#define MD_CONTEXT_MIPS_FULL (MD_CONTEXT_MIPS_INTEGER | \ + MD_CONTEXT_MIPS_FLOATING_POINT | \ + MD_CONTEXT_MIPS_DSP) + +#define MD_CONTEXT_MIPS_ALL (MD_CONTEXT_MIPS_INTEGER | \ + MD_CONTEXT_MIPS_FLOATING_POINT \ + MD_CONTEXT_MIPS_DSP) + +#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_MIPS_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_ppc.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_ppc.h new file mode 100644 index 00000000..b24cc424 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_ppc.h @@ -0,0 +1,168 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on ppc. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by ensuring + * ensuring that all members are aligned on their natural boundaries. In + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * These definitions may be extended to support handling minidump files + * for other CPUs and other operating systems. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably in terms of interoperability with minidumps + * produced by DbgHelp on Windows, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. DbgHelp + * on Windows is assumed to be the reference implementation; this file + * seeks to provide a cross-platform compatible implementation. To avoid + * collisions with the types and values defined and used by DbgHelp in the + * event that this implementation is used on Windows, each type and value + * defined here is given a new name, beginning with "MD". Names of the + * equivalent types and values in the Windows Platform SDK are given in + * comments. + * + * Author: Mark Mentovai + * Change to split into its own file: Neal Sidhwaney */ + +/* + * Breakpad minidump extension for PowerPC support. Based on Darwin/Mac OS X' + * mach/ppc/_types.h + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__ + +#define MD_FLOATINGSAVEAREA_PPC_FPR_COUNT 32 + +typedef struct { + /* fpregs is a double[32] in mach/ppc/_types.h, but a uint64_t is used + * here for precise sizing. */ + uint64_t fpregs[MD_FLOATINGSAVEAREA_PPC_FPR_COUNT]; + uint32_t fpscr_pad; + uint32_t fpscr; /* Status/control */ +} MDFloatingSaveAreaPPC; /* Based on ppc_float_state */ + + +#define MD_VECTORSAVEAREA_PPC_VR_COUNT 32 + +typedef struct { + /* Vector registers (including vscr) are 128 bits, but mach/ppc/_types.h + * exposes them as four 32-bit quantities. */ + uint128_struct save_vr[MD_VECTORSAVEAREA_PPC_VR_COUNT]; + uint128_struct save_vscr; /* Status/control */ + uint32_t save_pad5[4]; + uint32_t save_vrvalid; /* Indicates which vector registers are saved */ + uint32_t save_pad6[7]; +} MDVectorSaveAreaPPC; /* ppc_vector_state */ + + +#define MD_CONTEXT_PPC_GPR_COUNT 32 + +/* Use the same 32-bit alignment when accessing this structure from 64-bit code + * as is used natively in 32-bit code. #pragma pack is a MSVC extension + * supported by gcc. */ +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma pack(4) +#else +#pragma pack(push, 4) +#endif + +typedef struct { + /* context_flags is not present in ppc_thread_state, but it aids + * identification of MDRawContextPPC among other raw context types, + * and it guarantees alignment when we get to float_save. */ + uint32_t context_flags; + + uint32_t srr0; /* Machine status save/restore: stores pc + * (instruction) */ + uint32_t srr1; /* Machine status save/restore: stores msr + * (ps, program/machine state) */ + /* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is + * used for brevity. */ + uint32_t gpr[MD_CONTEXT_PPC_GPR_COUNT]; + uint32_t cr; /* Condition */ + uint32_t xer; /* Integer (fiXed-point) exception */ + uint32_t lr; /* Link */ + uint32_t ctr; /* Count */ + uint32_t mq; /* Multiply/Quotient (PPC 601, POWER only) */ + uint32_t vrsave; /* Vector save */ + + /* float_save and vector_save aren't present in ppc_thread_state, but + * are represented in separate structures that still define a thread's + * context. */ + MDFloatingSaveAreaPPC float_save; + MDVectorSaveAreaPPC vector_save; +} MDRawContextPPC; /* Based on ppc_thread_state */ + +/* Indices into gpr for registers with a dedicated or conventional purpose. */ +enum MDPPCRegisterNumbers { + MD_CONTEXT_PPC_REG_SP = 1 +}; + +#if defined(__SUNPRO_C) || defined(__SUNPRO_CC) +#pragma pack(0) +#else +#pragma pack(pop) +#endif + +/* For (MDRawContextPPC).context_flags. These values indicate the type of + * context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its + * value was chosen to avoid likely conflicts with MD_CONTEXT_* for other + * CPUs. */ +#define MD_CONTEXT_PPC 0x20000000 +#define MD_CONTEXT_PPC_BASE (MD_CONTEXT_PPC | 0x00000001) +#define MD_CONTEXT_PPC_FLOATING_POINT (MD_CONTEXT_PPC | 0x00000008) +#define MD_CONTEXT_PPC_VECTOR (MD_CONTEXT_PPC | 0x00000020) + +#define MD_CONTEXT_PPC_FULL MD_CONTEXT_PPC_BASE +#define MD_CONTEXT_PPC_ALL (MD_CONTEXT_PPC_FULL | \ + MD_CONTEXT_PPC_FLOATING_POINT | \ + MD_CONTEXT_PPC_VECTOR) + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC_H__ */ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_ppc64.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_ppc64.h new file mode 100644 index 00000000..61f41938 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_ppc64.h @@ -0,0 +1,134 @@ +/* Copyright (c) 2008, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on ppc64. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by ensuring + * ensuring that all members are aligned on their natural boundaries. In + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * These definitions may be extended to support handling minidump files + * for other CPUs and other operating systems. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably in terms of interoperability with minidumps + * produced by DbgHelp on Windows, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. DbgHelp + * on Windows is assumed to be the reference implementation; this file + * seeks to provide a cross-platform compatible implementation. To avoid + * collisions with the types and values defined and used by DbgHelp in the + * event that this implementation is used on Windows, each type and value + * defined here is given a new name, beginning with "MD". Names of the + * equivalent types and values in the Windows Platform SDK are given in + * comments. + * + * Author: Neal Sidhwaney */ + + +/* + * Breakpad minidump extension for PPC64 support. Based on Darwin/Mac OS X' + * mach/ppc/_types.h + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ + +#include "minidump_cpu_ppc.h" + +// these types are the same in ppc64 & ppc +typedef MDFloatingSaveAreaPPC MDFloatingSaveAreaPPC64; +typedef MDVectorSaveAreaPPC MDVectorSaveAreaPPC64; + +#define MD_CONTEXT_PPC64_GPR_COUNT MD_CONTEXT_PPC_GPR_COUNT + +typedef struct { + /* context_flags is not present in ppc_thread_state, but it aids + * identification of MDRawContextPPC among other raw context types, + * and it guarantees alignment when we get to float_save. */ + uint64_t context_flags; + + uint64_t srr0; /* Machine status save/restore: stores pc + * (instruction) */ + uint64_t srr1; /* Machine status save/restore: stores msr + * (ps, program/machine state) */ + /* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is + * used for brevity. */ + uint64_t gpr[MD_CONTEXT_PPC64_GPR_COUNT]; + uint64_t cr; /* Condition */ + uint64_t xer; /* Integer (fiXed-point) exception */ + uint64_t lr; /* Link */ + uint64_t ctr; /* Count */ + uint64_t vrsave; /* Vector save */ + + /* float_save and vector_save aren't present in ppc_thread_state, but + * are represented in separate structures that still define a thread's + * context. */ + MDFloatingSaveAreaPPC float_save; + MDVectorSaveAreaPPC vector_save; +} MDRawContextPPC64; /* Based on ppc_thread_state */ + +/* Indices into gpr for registers with a dedicated or conventional purpose. */ +enum MDPPC64RegisterNumbers { + MD_CONTEXT_PPC64_REG_SP = 1 +}; + +/* For (MDRawContextPPC).context_flags. These values indicate the type of + * context stored in the structure. MD_CONTEXT_PPC is Breakpad-defined. Its + * value was chosen to avoid likely conflicts with MD_CONTEXT_* for other + * CPUs. */ +#define MD_CONTEXT_PPC64 0x01000000 +#define MD_CONTEXT_PPC64_BASE (MD_CONTEXT_PPC64 | 0x00000001) +#define MD_CONTEXT_PPC64_FLOATING_POINT (MD_CONTEXT_PPC64 | 0x00000008) +#define MD_CONTEXT_PPC64_VECTOR (MD_CONTEXT_PPC64 | 0x00000020) + +#define MD_CONTEXT_PPC64_FULL MD_CONTEXT_PPC64_BASE +#define MD_CONTEXT_PPC64_ALL (MD_CONTEXT_PPC64_FULL | \ + MD_CONTEXT_PPC64_FLOATING_POINT | \ + MD_CONTEXT_PPC64_VECTOR) + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_PPC64_H__ */ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_sparc.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_sparc.h new file mode 100644 index 00000000..95c08b17 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_sparc.h @@ -0,0 +1,163 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on sparc. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by ensuring + * ensuring that all members are aligned on their natural boundaries. In + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * These definitions may be extended to support handling minidump files + * for other CPUs and other operating systems. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably in terms of interoperability with minidumps + * produced by DbgHelp on Windows, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. DbgHelp + * on Windows is assumed to be the reference implementation; this file + * seeks to provide a cross-platform compatible implementation. To avoid + * collisions with the types and values defined and used by DbgHelp in the + * event that this implementation is used on Windows, each type and value + * defined here is given a new name, beginning with "MD". Names of the + * equivalent types and values in the Windows Platform SDK are given in + * comments. + * + * Author: Mark Mentovai + * Change to split into its own file: Neal Sidhwaney */ + +/* + * SPARC support, see (solaris)sys/procfs_isa.h also + */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__ + +#define MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT 32 + +typedef struct { + + /* FPU floating point regs */ + uint64_t regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT]; + + uint64_t filler; + uint64_t fsr; /* FPU status register */ +} MDFloatingSaveAreaSPARC; /* FLOATING_SAVE_AREA */ + +#define MD_CONTEXT_SPARC_GPR_COUNT 32 + +typedef struct { + /* The next field determines the layout of the structure, and which parts + * of it are populated + */ + uint32_t context_flags; + uint32_t flag_pad; + /* + * General register access (SPARC). + * Don't confuse definitions here with definitions in . + * Registers are 32 bits for ILP32, 64 bits for LP64. + * SPARC V7/V8 is for 32bit, SPARC V9 is for 64bit + */ + + /* 32 Integer working registers */ + + /* g_r[0-7] global registers(g0-g7) + * g_r[8-15] out registers(o0-o7) + * g_r[16-23] local registers(l0-l7) + * g_r[24-31] in registers(i0-i7) + */ + uint64_t g_r[MD_CONTEXT_SPARC_GPR_COUNT]; + + /* several control registers */ + + /* Processor State register(PSR) for SPARC V7/V8 + * Condition Code register (CCR) for SPARC V9 + */ + uint64_t ccr; + + uint64_t pc; /* Program Counter register (PC) */ + uint64_t npc; /* Next Program Counter register (nPC) */ + uint64_t y; /* Y register (Y) */ + + /* Address Space Identifier register (ASI) for SPARC V9 + * WIM for SPARC V7/V8 + */ + uint64_t asi; + + /* Floating-Point Registers State register (FPRS) for SPARC V9 + * TBR for for SPARC V7/V8 + */ + uint64_t fprs; + + /* The next field is included with MD_CONTEXT_SPARC_FLOATING_POINT */ + MDFloatingSaveAreaSPARC float_save; + +} MDRawContextSPARC; /* CONTEXT_SPARC */ + +/* Indices into g_r for registers with a dedicated or conventional purpose. */ +enum MDSPARCRegisterNumbers { + MD_CONTEXT_SPARC_REG_SP = 14 +}; + +/* For (MDRawContextSPARC).context_flags. These values indicate the type of + * context stored in the structure. MD_CONTEXT_SPARC is Breakpad-defined. Its + * value was chosen to avoid likely conflicts with MD_CONTEXT_* for other + * CPUs. */ +#define MD_CONTEXT_SPARC 0x10000000 +#define MD_CONTEXT_SPARC_CONTROL (MD_CONTEXT_SPARC | 0x00000001) +#define MD_CONTEXT_SPARC_INTEGER (MD_CONTEXT_SPARC | 0x00000002) +#define MD_CONTEXT_SAPARC_FLOATING_POINT (MD_CONTEXT_SPARC | 0x00000004) +#define MD_CONTEXT_SAPARC_EXTRA (MD_CONTEXT_SPARC | 0x00000008) + +#define MD_CONTEXT_SPARC_FULL (MD_CONTEXT_SPARC_CONTROL | \ + MD_CONTEXT_SPARC_INTEGER) + +#define MD_CONTEXT_SPARC_ALL (MD_CONTEXT_SPARC_FULL | \ + MD_CONTEXT_SAPARC_FLOATING_POINT | \ + MD_CONTEXT_SAPARC_EXTRA) + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_SPARC_H__ */ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_x86.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_x86.h new file mode 100644 index 00000000..e09cb7cb --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_cpu_x86.h @@ -0,0 +1,174 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * This file contains the necessary definitions to read minidump files + * produced on x86. These files may be read on any platform provided + * that the alignments of these structures on the processing system are + * identical to the alignments of these structures on the producing system. + * For this reason, precise-sized types are used. The structures defined + * by this file have been laid out to minimize alignment problems by ensuring + * ensuring that all members are aligned on their natural boundaries. In + * In some cases, tail-padding may be significant when different ABIs specify + * different tail-padding behaviors. To avoid problems when reading or + * writing affected structures, MD_*_SIZE macros are provided where needed, + * containing the useful size of the structures without padding. + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * These definitions may be extended to support handling minidump files + * for other CPUs and other operating systems. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably in terms of interoperability with minidumps + * produced by DbgHelp on Windows, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. DbgHelp + * on Windows is assumed to be the reference implementation; this file + * seeks to provide a cross-platform compatible implementation. To avoid + * collisions with the types and values defined and used by DbgHelp in the + * event that this implementation is used on Windows, each type and value + * defined here is given a new name, beginning with "MD". Names of the + * equivalent types and values in the Windows Platform SDK are given in + * comments. + * + * Author: Mark Mentovai */ + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__ + +#define MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE 80 + /* SIZE_OF_80387_REGISTERS */ + +typedef struct { + uint32_t control_word; + uint32_t status_word; + uint32_t tag_word; + uint32_t error_offset; + uint32_t error_selector; + uint32_t data_offset; + uint32_t data_selector; + + /* register_area contains eight 80-bit (x87 "long double") quantities for + * floating-point registers %st0 (%mm0) through %st7 (%mm7). */ + uint8_t register_area[MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE]; + uint32_t cr0_npx_state; +} MDFloatingSaveAreaX86; /* FLOATING_SAVE_AREA */ + + +#define MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE 512 + /* MAXIMUM_SUPPORTED_EXTENSION */ + +typedef struct { + /* The next field determines the layout of the structure, and which parts + * of it are populated */ + uint32_t context_flags; + + /* The next 6 registers are included with MD_CONTEXT_X86_DEBUG_REGISTERS */ + uint32_t dr0; + uint32_t dr1; + uint32_t dr2; + uint32_t dr3; + uint32_t dr6; + uint32_t dr7; + + /* The next field is included with MD_CONTEXT_X86_FLOATING_POINT */ + MDFloatingSaveAreaX86 float_save; + + /* The next 4 registers are included with MD_CONTEXT_X86_SEGMENTS */ + uint32_t gs; + uint32_t fs; + uint32_t es; + uint32_t ds; + /* The next 6 registers are included with MD_CONTEXT_X86_INTEGER */ + uint32_t edi; + uint32_t esi; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + + /* The next 6 registers are included with MD_CONTEXT_X86_CONTROL */ + uint32_t ebp; + uint32_t eip; + uint32_t cs; /* WinNT.h says "must be sanitized" */ + uint32_t eflags; /* WinNT.h says "must be sanitized" */ + uint32_t esp; + uint32_t ss; + + /* The next field is included with MD_CONTEXT_X86_EXTENDED_REGISTERS. + * It contains vector (MMX/SSE) registers. It it laid out in the + * format used by the fxsave and fsrstor instructions, so it includes + * a copy of the x87 floating-point registers as well. See FXSAVE in + * "Intel Architecture Software Developer's Manual, Volume 2." */ + uint8_t extended_registers[ + MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE]; +} MDRawContextX86; /* CONTEXT */ + +/* For (MDRawContextX86).context_flags. These values indicate the type of + * context stored in the structure. The high 24 bits identify the CPU, the + * low 8 bits identify the type of context saved. */ +#define MD_CONTEXT_X86 0x00010000 + /* CONTEXT_i386, CONTEXT_i486: identifies CPU */ +#define MD_CONTEXT_X86_CONTROL (MD_CONTEXT_X86 | 0x00000001) + /* CONTEXT_CONTROL */ +#define MD_CONTEXT_X86_INTEGER (MD_CONTEXT_X86 | 0x00000002) + /* CONTEXT_INTEGER */ +#define MD_CONTEXT_X86_SEGMENTS (MD_CONTEXT_X86 | 0x00000004) + /* CONTEXT_SEGMENTS */ +#define MD_CONTEXT_X86_FLOATING_POINT (MD_CONTEXT_X86 | 0x00000008) + /* CONTEXT_FLOATING_POINT */ +#define MD_CONTEXT_X86_DEBUG_REGISTERS (MD_CONTEXT_X86 | 0x00000010) + /* CONTEXT_DEBUG_REGISTERS */ +#define MD_CONTEXT_X86_EXTENDED_REGISTERS (MD_CONTEXT_X86 | 0x00000020) + /* CONTEXT_EXTENDED_REGISTERS */ +#define MD_CONTEXT_X86_XSTATE (MD_CONTEXT_X86 | 0x00000040) + /* CONTEXT_XSTATE */ + +#define MD_CONTEXT_X86_FULL (MD_CONTEXT_X86_CONTROL | \ + MD_CONTEXT_X86_INTEGER | \ + MD_CONTEXT_X86_SEGMENTS) + /* CONTEXT_FULL */ + +#define MD_CONTEXT_X86_ALL (MD_CONTEXT_X86_FULL | \ + MD_CONTEXT_X86_FLOATING_POINT | \ + MD_CONTEXT_X86_DEBUG_REGISTERS | \ + MD_CONTEXT_X86_EXTENDED_REGISTERS) + /* CONTEXT_ALL */ + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_X86_H__ */ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_linux.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_linux.h new file mode 100644 index 00000000..9e7e4f1e --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_linux.h @@ -0,0 +1,87 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* minidump_exception_linux.h: A definition of exception codes for + * Linux + * + * (This is C99 source, please don't corrupt it with C++.) + * + * Author: Mark Mentovai + * Split into its own file: Neal Sidhwaney */ + + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ + +#include + +#include "google_breakpad/common/breakpad_types.h" + + +/* For (MDException).exception_code. These values come from bits/signum.h. + */ +typedef enum { + MD_EXCEPTION_CODE_LIN_SIGHUP = 1, /* Hangup (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGINT = 2, /* Interrupt (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGQUIT = 3, /* Quit (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGILL = 4, /* Illegal instruction (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGTRAP = 5, /* Trace trap (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGABRT = 6, /* Abort (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGBUS = 7, /* BUS error (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGFPE = 8, /* Floating-point exception (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGKILL = 9, /* Kill, unblockable (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGUSR1 = 10, /* User-defined signal 1 (POSIX). */ + MD_EXCEPTION_CODE_LIN_SIGSEGV = 11, /* Segmentation violation (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGUSR2 = 12, /* User-defined signal 2 (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGPIPE = 13, /* Broken pipe (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGALRM = 14, /* Alarm clock (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGTERM = 15, /* Termination (ANSI) */ + MD_EXCEPTION_CODE_LIN_SIGSTKFLT = 16, /* Stack faultd */ + MD_EXCEPTION_CODE_LIN_SIGCHLD = 17, /* Child status has changed (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGCONT = 18, /* Continue (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGSTOP = 19, /* Stop, unblockable (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGTSTP = 20, /* Keyboard stop (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGTTIN = 21, /* Background read from tty (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGTTOU = 22, /* Background write to tty (POSIX) */ + MD_EXCEPTION_CODE_LIN_SIGURG = 23, + /* Urgent condition on socket (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGXCPU = 24, /* CPU limit exceeded (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGXFSZ = 25, + /* File size limit exceeded (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGVTALRM = 26, /* Virtual alarm clock (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGPROF = 27, /* Profiling alarm clock (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGWINCH = 28, /* Window size change (4.3 BSD, Sun) */ + MD_EXCEPTION_CODE_LIN_SIGIO = 29, /* I/O now possible (4.2 BSD) */ + MD_EXCEPTION_CODE_LIN_SIGPWR = 30, /* Power failure restart (System V) */ + MD_EXCEPTION_CODE_LIN_SIGSYS = 31, /* Bad system call */ + MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED = 0xFFFFFFFF /* No exception, + dump requested. */ +} MDExceptionCodeLinux; + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ */ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_mac.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_mac.h new file mode 100644 index 00000000..91c1c097 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_mac.h @@ -0,0 +1,205 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* minidump_exception_mac.h: A definition of exception codes for Mac + * OS X + * + * (This is C99 source, please don't corrupt it with C++.) + * + * Author: Mark Mentovai + * Split into its own file: Neal Sidhwaney */ + + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_H__ + +#include + +#include "google_breakpad/common/breakpad_types.h" + +/* For (MDException).exception_code. Breakpad minidump extension for Mac OS X + * support. Based on Darwin/Mac OS X' mach/exception_types.h. This is + * what Mac OS X calls an "exception", not a "code". */ +typedef enum { + /* Exception code. The high 16 bits of exception_code contains one of + * these values. */ + MD_EXCEPTION_MAC_BAD_ACCESS = 1, /* code can be a kern_return_t */ + /* EXC_BAD_ACCESS */ + MD_EXCEPTION_MAC_BAD_INSTRUCTION = 2, /* code is CPU-specific */ + /* EXC_BAD_INSTRUCTION */ + MD_EXCEPTION_MAC_ARITHMETIC = 3, /* code is CPU-specific */ + /* EXC_ARITHMETIC */ + MD_EXCEPTION_MAC_EMULATION = 4, /* code is CPU-specific */ + /* EXC_EMULATION */ + MD_EXCEPTION_MAC_SOFTWARE = 5, + /* EXC_SOFTWARE */ + MD_EXCEPTION_MAC_BREAKPOINT = 6, /* code is CPU-specific */ + /* EXC_BREAKPOINT */ + MD_EXCEPTION_MAC_SYSCALL = 7, + /* EXC_SYSCALL */ + MD_EXCEPTION_MAC_MACH_SYSCALL = 8, + /* EXC_MACH_SYSCALL */ + MD_EXCEPTION_MAC_RPC_ALERT = 9 + /* EXC_RPC_ALERT */ +} MDExceptionMac; + +/* For (MDException).exception_flags. Breakpad minidump extension for Mac OS X + * support. Based on Darwin/Mac OS X' mach/ppc/exception.h and + * mach/i386/exception.h. This is what Mac OS X calls a "code". */ +typedef enum { + /* With MD_EXCEPTION_BAD_ACCESS. These are relevant kern_return_t values + * from mach/kern_return.h. */ + MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS = 1, + /* KERN_INVALID_ADDRESS */ + MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE = 2, + /* KERN_PROTECTION_FAILURE */ + MD_EXCEPTION_CODE_MAC_NO_ACCESS = 8, + /* KERN_NO_ACCESS */ + MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE = 9, + /* KERN_MEMORY_FAILURE */ + MD_EXCEPTION_CODE_MAC_MEMORY_ERROR = 10, + /* KERN_MEMORY_ERROR */ + + /* With MD_EXCEPTION_SOFTWARE */ + MD_EXCEPTION_CODE_MAC_BAD_SYSCALL = 0x00010000, /* Mach SIGSYS */ + MD_EXCEPTION_CODE_MAC_BAD_PIPE = 0x00010001, /* Mach SIGPIPE */ + MD_EXCEPTION_CODE_MAC_ABORT = 0x00010002, /* Mach SIGABRT */ + /* Custom values */ + MD_EXCEPTION_CODE_MAC_NS_EXCEPTION = 0xDEADC0DE, /* uncaught NSException */ + + /* With MD_EXCEPTION_MAC_BAD_ACCESS on arm */ + MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN = 0x0101, /* EXC_ARM_DA_ALIGN */ + MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG = 0x0102, /* EXC_ARM_DA_DEBUG */ + + /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on arm */ + MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED = 1, /* EXC_ARM_UNDEFINED */ + + /* With MD_EXCEPTION_MAC_BREAKPOINT on arm */ + MD_EXCEPTION_CODE_MAC_ARM_BREAKPOINT = 1, /* EXC_ARM_BREAKPOINT */ + + /* With MD_EXCEPTION_MAC_BAD_ACCESS on ppc */ + MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ = 0x0101, + /* EXC_PPC_VM_PROT_READ */ + MD_EXCEPTION_CODE_MAC_PPC_BADSPACE = 0x0102, + /* EXC_PPC_BADSPACE */ + MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED = 0x0103, + /* EXC_PPC_UNALIGNED */ + + /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on ppc */ + MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL = 1, + /* EXC_PPC_INVALID_SYSCALL */ + MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION = 2, + /* EXC_PPC_UNIPL_INST */ + MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION = 3, + /* EXC_PPC_PRIVINST */ + MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER = 4, + /* EXC_PPC_PRIVREG */ + MD_EXCEPTION_CODE_MAC_PPC_TRACE = 5, + /* EXC_PPC_TRACE */ + MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR = 6, + /* EXC_PPC_PERFMON */ + + /* With MD_EXCEPTION_MAC_ARITHMETIC on ppc */ + MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW = 1, + /* EXC_PPC_OVERFLOW */ + MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE = 2, + /* EXC_PPC_ZERO_DIVIDE */ + MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT = 3, + /* EXC_FLT_INEXACT */ + MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE = 4, + /* EXC_PPC_FLT_ZERO_DIVIDE */ + MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW = 5, + /* EXC_PPC_FLT_UNDERFLOW */ + MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW = 6, + /* EXC_PPC_FLT_OVERFLOW */ + MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER = 7, + /* EXC_PPC_FLT_NOT_A_NUMBER */ + + /* With MD_EXCEPTION_MAC_EMULATION on ppc */ + MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION = 8, + /* EXC_PPC_NOEMULATION */ + MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST = 9, + /* EXC_PPC_ALTIVECASSIST */ + + /* With MD_EXCEPTION_MAC_SOFTWARE on ppc */ + MD_EXCEPTION_CODE_MAC_PPC_TRAP = 0x00000001, /* EXC_PPC_TRAP */ + MD_EXCEPTION_CODE_MAC_PPC_MIGRATE = 0x00010100, /* EXC_PPC_MIGRATE */ + + /* With MD_EXCEPTION_MAC_BREAKPOINT on ppc */ + MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT = 1, /* EXC_PPC_BREAKPOINT */ + + /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86, see also x86 interrupt + * values below. */ + MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION = 1, /* EXC_I386_INVOP */ + + /* With MD_EXCEPTION_MAC_ARITHMETIC on x86 */ + MD_EXCEPTION_CODE_MAC_X86_DIV = 1, /* EXC_I386_DIV */ + MD_EXCEPTION_CODE_MAC_X86_INTO = 2, /* EXC_I386_INTO */ + MD_EXCEPTION_CODE_MAC_X86_NOEXT = 3, /* EXC_I386_NOEXT */ + MD_EXCEPTION_CODE_MAC_X86_EXTOVR = 4, /* EXC_I386_EXTOVR */ + MD_EXCEPTION_CODE_MAC_X86_EXTERR = 5, /* EXC_I386_EXTERR */ + MD_EXCEPTION_CODE_MAC_X86_EMERR = 6, /* EXC_I386_EMERR */ + MD_EXCEPTION_CODE_MAC_X86_BOUND = 7, /* EXC_I386_BOUND */ + MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR = 8, /* EXC_I386_SSEEXTERR */ + + /* With MD_EXCEPTION_MAC_BREAKPOINT on x86 */ + MD_EXCEPTION_CODE_MAC_X86_SGL = 1, /* EXC_I386_SGL */ + MD_EXCEPTION_CODE_MAC_X86_BPT = 2, /* EXC_I386_BPT */ + + /* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on x86. These are the raw + * x86 interrupt codes. Most of these are mapped to other Mach + * exceptions and codes, are handled, or should not occur in user space. + * A few of these will do occur with MD_EXCEPTION_MAC_BAD_INSTRUCTION. */ + /* EXC_I386_DIVERR = 0: mapped to EXC_ARITHMETIC/EXC_I386_DIV */ + /* EXC_I386_SGLSTP = 1: mapped to EXC_BREAKPOINT/EXC_I386_SGL */ + /* EXC_I386_NMIFLT = 2: should not occur in user space */ + /* EXC_I386_BPTFLT = 3: mapped to EXC_BREAKPOINT/EXC_I386_BPT */ + /* EXC_I386_INTOFLT = 4: mapped to EXC_ARITHMETIC/EXC_I386_INTO */ + /* EXC_I386_BOUNDFLT = 5: mapped to EXC_ARITHMETIC/EXC_I386_BOUND */ + /* EXC_I386_INVOPFLT = 6: mapped to EXC_BAD_INSTRUCTION/EXC_I386_INVOP */ + /* EXC_I386_NOEXTFLT = 7: should be handled by the kernel */ + /* EXC_I386_DBLFLT = 8: should be handled (if possible) by the kernel */ + /* EXC_I386_EXTOVRFLT = 9: mapped to EXC_BAD_ACCESS/(PROT_READ|PROT_EXEC) */ + MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT = 10, + /* EXC_INVTSSFLT */ + MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT = 11, + /* EXC_SEGNPFLT */ + MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT = 12, + /* EXC_STKFLT */ + MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT = 13, + /* EXC_GPFLT */ + /* EXC_I386_PGFLT = 14: should not occur in user space */ + /* EXC_I386_EXTERRFLT = 16: mapped to EXC_ARITHMETIC/EXC_I386_EXTERR */ + MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT = 17 + /* EXC_ALIGNFLT (for vector operations) */ + /* EXC_I386_ENOEXTFLT = 32: should be handled by the kernel */ + /* EXC_I386_ENDPERR = 33: should not occur */ +} MDExceptionCodeMac; + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_MAC_OSX_H__ */ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_ps3.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_ps3.h new file mode 100644 index 00000000..adff5a6b --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_ps3.h @@ -0,0 +1,67 @@ +/* Copyright (c) 2013, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* minidump_exception_ps3.h: A definition of exception codes for + * PS3 */ + + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__ + +#include + +#include "google_breakpad/common/breakpad_types.h" + +typedef enum { + MD_EXCEPTION_CODE_PS3_UNKNOWN = 0, + MD_EXCEPTION_CODE_PS3_TRAP_EXCEP = 1, + MD_EXCEPTION_CODE_PS3_PRIV_INSTR = 2, + MD_EXCEPTION_CODE_PS3_ILLEGAL_INSTR = 3, + MD_EXCEPTION_CODE_PS3_INSTR_STORAGE = 4, + MD_EXCEPTION_CODE_PS3_INSTR_SEGMENT = 5, + MD_EXCEPTION_CODE_PS3_DATA_STORAGE = 6, + MD_EXCEPTION_CODE_PS3_DATA_SEGMENT = 7, + MD_EXCEPTION_CODE_PS3_FLOAT_POINT = 8, + MD_EXCEPTION_CODE_PS3_DABR_MATCH = 9, + MD_EXCEPTION_CODE_PS3_ALIGN_EXCEP = 10, + MD_EXCEPTION_CODE_PS3_MEMORY_ACCESS = 11, + MD_EXCEPTION_CODE_PS3_COPRO_ALIGN = 12, + MD_EXCEPTION_CODE_PS3_COPRO_INVALID_COM = 13, + MD_EXCEPTION_CODE_PS3_COPRO_ERR = 14, + MD_EXCEPTION_CODE_PS3_COPRO_FIR = 15, + MD_EXCEPTION_CODE_PS3_COPRO_DATA_SEGMENT = 16, + MD_EXCEPTION_CODE_PS3_COPRO_DATA_STORAGE = 17, + MD_EXCEPTION_CODE_PS3_COPRO_STOP_INSTR = 18, + MD_EXCEPTION_CODE_PS3_COPRO_HALT_INSTR = 19, + MD_EXCEPTION_CODE_PS3_COPRO_HALTINST_UNKNOWN = 20, + MD_EXCEPTION_CODE_PS3_COPRO_MEMORY_ACCESS = 21, + MD_EXCEPTION_CODE_PS3_GRAPHIC = 22 +} MDExceptionCodePS3; + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_PS3_H__ */ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_solaris.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_solaris.h new file mode 100644 index 00000000..f18ddf42 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_solaris.h @@ -0,0 +1,94 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* minidump_exception_solaris.h: A definition of exception codes for + * Solaris + * + * (This is C99 source, please don't corrupt it with C++.) + * + * Author: Mark Mentovai + * Split into its own file: Neal Sidhwaney */ + + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__ + +#include + +#include "google_breakpad/common/breakpad_types.h" + +/* For (MDException).exception_code. These values come from sys/iso/signal_iso.h + */ +typedef enum { + MD_EXCEPTION_CODE_SOL_SIGHUP = 1, /* Hangup */ + MD_EXCEPTION_CODE_SOL_SIGINT = 2, /* interrupt (rubout) */ + MD_EXCEPTION_CODE_SOL_SIGQUIT = 3, /* quit (ASCII FS) */ + MD_EXCEPTION_CODE_SOL_SIGILL = 4, /* illegal instruction (not reset when caught) */ + MD_EXCEPTION_CODE_SOL_SIGTRAP = 5, /* trace trap (not reset when caught) */ + MD_EXCEPTION_CODE_SOL_SIGIOT = 6, /* IOT instruction */ + MD_EXCEPTION_CODE_SOL_SIGABRT = 6, /* used by abort, replace SIGIOT in the future */ + MD_EXCEPTION_CODE_SOL_SIGEMT = 7, /* EMT instruction */ + MD_EXCEPTION_CODE_SOL_SIGFPE = 8, /* floating point exception */ + MD_EXCEPTION_CODE_SOL_SIGKILL = 9, /* kill (cannot be caught or ignored) */ + MD_EXCEPTION_CODE_SOL_SIGBUS = 10, /* bus error */ + MD_EXCEPTION_CODE_SOL_SIGSEGV = 11, /* segmentation violation */ + MD_EXCEPTION_CODE_SOL_SIGSYS = 12, /* bad argument to system call */ + MD_EXCEPTION_CODE_SOL_SIGPIPE = 13, /* write on a pipe with no one to read it */ + MD_EXCEPTION_CODE_SOL_SIGALRM = 14, /* alarm clock */ + MD_EXCEPTION_CODE_SOL_SIGTERM = 15, /* software termination signal from kill */ + MD_EXCEPTION_CODE_SOL_SIGUSR1 = 16, /* user defined signal 1 */ + MD_EXCEPTION_CODE_SOL_SIGUSR2 = 17, /* user defined signal 2 */ + MD_EXCEPTION_CODE_SOL_SIGCLD = 18, /* child status change */ + MD_EXCEPTION_CODE_SOL_SIGCHLD = 18, /* child status change alias (POSIX) */ + MD_EXCEPTION_CODE_SOL_SIGPWR = 19, /* power-fail restart */ + MD_EXCEPTION_CODE_SOL_SIGWINCH = 20, /* window size change */ + MD_EXCEPTION_CODE_SOL_SIGURG = 21, /* urgent socket condition */ + MD_EXCEPTION_CODE_SOL_SIGPOLL = 22, /* pollable event occurred */ + MD_EXCEPTION_CODE_SOL_SIGIO = 22, /* socket I/O possible (SIGPOLL alias) */ + MD_EXCEPTION_CODE_SOL_SIGSTOP = 23, /* stop (cannot be caught or ignored) */ + MD_EXCEPTION_CODE_SOL_SIGTSTP = 24, /* user stop requested from tty */ + MD_EXCEPTION_CODE_SOL_SIGCONT = 25, /* stopped process has been continued */ + MD_EXCEPTION_CODE_SOL_SIGTTIN = 26, /* background tty read attempted */ + MD_EXCEPTION_CODE_SOL_SIGTTOU = 27, /* background tty write attempted */ + MD_EXCEPTION_CODE_SOL_SIGVTALRM = 28, /* virtual timer expired */ + MD_EXCEPTION_CODE_SOL_SIGPROF = 29, /* profiling timer expired */ + MD_EXCEPTION_CODE_SOL_SIGXCPU = 30, /* exceeded cpu limit */ + MD_EXCEPTION_CODE_SOL_SIGXFSZ = 31, /* exceeded file size limit */ + MD_EXCEPTION_CODE_SOL_SIGWAITING = 32, /* reserved signal no longer used by threading code */ + MD_EXCEPTION_CODE_SOL_SIGLWP = 33, /* reserved signal no longer used by threading code */ + MD_EXCEPTION_CODE_SOL_SIGFREEZE = 34, /* special signal used by CPR */ + MD_EXCEPTION_CODE_SOL_SIGTHAW = 35, /* special signal used by CPR */ + MD_EXCEPTION_CODE_SOL_SIGCANCEL = 36, /* reserved signal for thread cancellation */ + MD_EXCEPTION_CODE_SOL_SIGLOST = 37, /* resource lost (eg, record-lock lost) */ + MD_EXCEPTION_CODE_SOL_SIGXRES = 38, /* resource control exceeded */ + MD_EXCEPTION_CODE_SOL_SIGJVM1 = 39, /* reserved signal for Java Virtual Machine */ + MD_EXCEPTION_CODE_SOL_SIGJVM2 = 40 /* reserved signal for Java Virtual Machine */ +} MDExceptionCodeSolaris; + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_SOLARIS_H__ */ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_win32.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_win32.h new file mode 100644 index 00000000..e4cd59ed --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_exception_win32.h @@ -0,0 +1,2261 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* minidump_exception_win32.h: Definitions of exception codes for + * Win32 platform + * + * (This is C99 source, please don't corrupt it with C++.) + * + * Author: Mark Mentovai + * Split into its own file: Neal Sidhwaney */ + + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ + +#include + +#include "google_breakpad/common/breakpad_types.h" + + +/* For (MDException).exception_code. These values come from WinBase.h + * and WinNT.h (names beginning with EXCEPTION_ are in WinBase.h, + * they are STATUS_ in WinNT.h). */ +typedef enum { + MD_EXCEPTION_CODE_WIN_CONTROL_C = 0x40010005, + /* DBG_CONTROL_C */ + MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION = 0x80000001, + /* EXCEPTION_GUARD_PAGE */ + MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT = 0x80000002, + /* EXCEPTION_DATATYPE_MISALIGNMENT */ + MD_EXCEPTION_CODE_WIN_BREAKPOINT = 0x80000003, + /* EXCEPTION_BREAKPOINT */ + MD_EXCEPTION_CODE_WIN_SINGLE_STEP = 0x80000004, + /* EXCEPTION_SINGLE_STEP */ + MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION = 0xc0000005, + /* EXCEPTION_ACCESS_VIOLATION */ + MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR = 0xc0000006, + /* EXCEPTION_IN_PAGE_ERROR */ + MD_EXCEPTION_CODE_WIN_INVALID_HANDLE = 0xc0000008, + /* EXCEPTION_INVALID_HANDLE */ + MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION = 0xc000001d, + /* EXCEPTION_ILLEGAL_INSTRUCTION */ + MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION = 0xc0000025, + /* EXCEPTION_NONCONTINUABLE_EXCEPTION */ + MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION = 0xc0000026, + /* EXCEPTION_INVALID_DISPOSITION */ + MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED = 0xc000008c, + /* EXCEPTION_BOUNDS_EXCEEDED */ + MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND = 0xc000008d, + /* EXCEPTION_FLT_DENORMAL_OPERAND */ + MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO = 0xc000008e, + /* EXCEPTION_FLT_DIVIDE_BY_ZERO */ + MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT = 0xc000008f, + /* EXCEPTION_FLT_INEXACT_RESULT */ + MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION = 0xc0000090, + /* EXCEPTION_FLT_INVALID_OPERATION */ + MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW = 0xc0000091, + /* EXCEPTION_FLT_OVERFLOW */ + MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK = 0xc0000092, + /* EXCEPTION_FLT_STACK_CHECK */ + MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW = 0xc0000093, + /* EXCEPTION_FLT_UNDERFLOW */ + MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO = 0xc0000094, + /* EXCEPTION_INT_DIVIDE_BY_ZERO */ + MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW = 0xc0000095, + /* EXCEPTION_INT_OVERFLOW */ + MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION = 0xc0000096, + /* EXCEPTION_PRIV_INSTRUCTION */ + MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW = 0xc00000fd, + /* EXCEPTION_STACK_OVERFLOW */ + MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK = 0xc0000194, + /* EXCEPTION_POSSIBLE_DEADLOCK */ + MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN = 0xc0000409, + /* STATUS_STACK_BUFFER_OVERRUN */ + MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION = 0xc0000374, + /* STATUS_HEAP_CORRUPTION */ + MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION = 0xe06d7363 + /* Per http://support.microsoft.com/kb/185294, + generated by Visual C++ compiler */ +} MDExceptionCodeWin; + + +/* For (MDException).exception_information[2], when (MDException).exception_code + * is MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR. This describes the underlying reason + * for the error. These values come from ntstatus.h. + * + * The content of this enum was created from ntstatus.h in the 8.1 SDK with + * + * egrep '#define [A-Z_0-9]+\s+\(\(NTSTATUS\)0xC[0-9A-F]+L\)' ntstatus.h + * | tr -d '\r' + * | sed -r 's@#define ([A-Z_0-9]+)\s+\(\(NTSTATUS\)(0xC[0-9A-F]+)L\).*@\2 \1@' + * | sort + * | sed -r 's@(0xC[0-9A-F]+) ([A-Z_0-9]+)@ MD_NTSTATUS_WIN_\2 = \1,@' + * + * With easy copy to clipboard with + * | xclip -selection c # on linux + * | clip # on windows + * | pbcopy # on mac + * + * and then the last comma manually removed. */ +typedef enum { + MD_NTSTATUS_WIN_STATUS_UNSUCCESSFUL = 0xC0000001, + MD_NTSTATUS_WIN_STATUS_NOT_IMPLEMENTED = 0xC0000002, + MD_NTSTATUS_WIN_STATUS_INVALID_INFO_CLASS = 0xC0000003, + MD_NTSTATUS_WIN_STATUS_INFO_LENGTH_MISMATCH = 0xC0000004, + MD_NTSTATUS_WIN_STATUS_ACCESS_VIOLATION = 0xC0000005, + MD_NTSTATUS_WIN_STATUS_IN_PAGE_ERROR = 0xC0000006, + MD_NTSTATUS_WIN_STATUS_PAGEFILE_QUOTA = 0xC0000007, + MD_NTSTATUS_WIN_STATUS_INVALID_HANDLE = 0xC0000008, + MD_NTSTATUS_WIN_STATUS_BAD_INITIAL_STACK = 0xC0000009, + MD_NTSTATUS_WIN_STATUS_BAD_INITIAL_PC = 0xC000000A, + MD_NTSTATUS_WIN_STATUS_INVALID_CID = 0xC000000B, + MD_NTSTATUS_WIN_STATUS_TIMER_NOT_CANCELED = 0xC000000C, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER = 0xC000000D, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_DEVICE = 0xC000000E, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_FILE = 0xC000000F, + MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_REQUEST = 0xC0000010, + MD_NTSTATUS_WIN_STATUS_END_OF_FILE = 0xC0000011, + MD_NTSTATUS_WIN_STATUS_WRONG_VOLUME = 0xC0000012, + MD_NTSTATUS_WIN_STATUS_NO_MEDIA_IN_DEVICE = 0xC0000013, + MD_NTSTATUS_WIN_STATUS_UNRECOGNIZED_MEDIA = 0xC0000014, + MD_NTSTATUS_WIN_STATUS_NONEXISTENT_SECTOR = 0xC0000015, + MD_NTSTATUS_WIN_STATUS_MORE_PROCESSING_REQUIRED = 0xC0000016, + MD_NTSTATUS_WIN_STATUS_NO_MEMORY = 0xC0000017, + MD_NTSTATUS_WIN_STATUS_CONFLICTING_ADDRESSES = 0xC0000018, + MD_NTSTATUS_WIN_STATUS_NOT_MAPPED_VIEW = 0xC0000019, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_FREE_VM = 0xC000001A, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_DELETE_SECTION = 0xC000001B, + MD_NTSTATUS_WIN_STATUS_INVALID_SYSTEM_SERVICE = 0xC000001C, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_INSTRUCTION = 0xC000001D, + MD_NTSTATUS_WIN_STATUS_INVALID_LOCK_SEQUENCE = 0xC000001E, + MD_NTSTATUS_WIN_STATUS_INVALID_VIEW_SIZE = 0xC000001F, + MD_NTSTATUS_WIN_STATUS_INVALID_FILE_FOR_SECTION = 0xC0000020, + MD_NTSTATUS_WIN_STATUS_ALREADY_COMMITTED = 0xC0000021, + MD_NTSTATUS_WIN_STATUS_ACCESS_DENIED = 0xC0000022, + MD_NTSTATUS_WIN_STATUS_BUFFER_TOO_SMALL = 0xC0000023, + MD_NTSTATUS_WIN_STATUS_OBJECT_TYPE_MISMATCH = 0xC0000024, + MD_NTSTATUS_WIN_STATUS_NONCONTINUABLE_EXCEPTION = 0xC0000025, + MD_NTSTATUS_WIN_STATUS_INVALID_DISPOSITION = 0xC0000026, + MD_NTSTATUS_WIN_STATUS_UNWIND = 0xC0000027, + MD_NTSTATUS_WIN_STATUS_BAD_STACK = 0xC0000028, + MD_NTSTATUS_WIN_STATUS_INVALID_UNWIND_TARGET = 0xC0000029, + MD_NTSTATUS_WIN_STATUS_NOT_LOCKED = 0xC000002A, + MD_NTSTATUS_WIN_STATUS_PARITY_ERROR = 0xC000002B, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_DECOMMIT_VM = 0xC000002C, + MD_NTSTATUS_WIN_STATUS_NOT_COMMITTED = 0xC000002D, + MD_NTSTATUS_WIN_STATUS_INVALID_PORT_ATTRIBUTES = 0xC000002E, + MD_NTSTATUS_WIN_STATUS_PORT_MESSAGE_TOO_LONG = 0xC000002F, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_MIX = 0xC0000030, + MD_NTSTATUS_WIN_STATUS_INVALID_QUOTA_LOWER = 0xC0000031, + MD_NTSTATUS_WIN_STATUS_DISK_CORRUPT_ERROR = 0xC0000032, + MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_INVALID = 0xC0000033, + MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034, + MD_NTSTATUS_WIN_STATUS_OBJECT_NAME_COLLISION = 0xC0000035, + MD_NTSTATUS_WIN_STATUS_PORT_DISCONNECTED = 0xC0000037, + MD_NTSTATUS_WIN_STATUS_DEVICE_ALREADY_ATTACHED = 0xC0000038, + MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_INVALID = 0xC0000039, + MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A, + MD_NTSTATUS_WIN_STATUS_OBJECT_PATH_SYNTAX_BAD = 0xC000003B, + MD_NTSTATUS_WIN_STATUS_DATA_OVERRUN = 0xC000003C, + MD_NTSTATUS_WIN_STATUS_DATA_LATE_ERROR = 0xC000003D, + MD_NTSTATUS_WIN_STATUS_DATA_ERROR = 0xC000003E, + MD_NTSTATUS_WIN_STATUS_CRC_ERROR = 0xC000003F, + MD_NTSTATUS_WIN_STATUS_SECTION_TOO_BIG = 0xC0000040, + MD_NTSTATUS_WIN_STATUS_PORT_CONNECTION_REFUSED = 0xC0000041, + MD_NTSTATUS_WIN_STATUS_INVALID_PORT_HANDLE = 0xC0000042, + MD_NTSTATUS_WIN_STATUS_SHARING_VIOLATION = 0xC0000043, + MD_NTSTATUS_WIN_STATUS_QUOTA_EXCEEDED = 0xC0000044, + MD_NTSTATUS_WIN_STATUS_INVALID_PAGE_PROTECTION = 0xC0000045, + MD_NTSTATUS_WIN_STATUS_MUTANT_NOT_OWNED = 0xC0000046, + MD_NTSTATUS_WIN_STATUS_SEMAPHORE_LIMIT_EXCEEDED = 0xC0000047, + MD_NTSTATUS_WIN_STATUS_PORT_ALREADY_SET = 0xC0000048, + MD_NTSTATUS_WIN_STATUS_SECTION_NOT_IMAGE = 0xC0000049, + MD_NTSTATUS_WIN_STATUS_SUSPEND_COUNT_EXCEEDED = 0xC000004A, + MD_NTSTATUS_WIN_STATUS_THREAD_IS_TERMINATING = 0xC000004B, + MD_NTSTATUS_WIN_STATUS_BAD_WORKING_SET_LIMIT = 0xC000004C, + MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_FILE_MAP = 0xC000004D, + MD_NTSTATUS_WIN_STATUS_SECTION_PROTECTION = 0xC000004E, + MD_NTSTATUS_WIN_STATUS_EAS_NOT_SUPPORTED = 0xC000004F, + MD_NTSTATUS_WIN_STATUS_EA_TOO_LARGE = 0xC0000050, + MD_NTSTATUS_WIN_STATUS_NONEXISTENT_EA_ENTRY = 0xC0000051, + MD_NTSTATUS_WIN_STATUS_NO_EAS_ON_FILE = 0xC0000052, + MD_NTSTATUS_WIN_STATUS_EA_CORRUPT_ERROR = 0xC0000053, + MD_NTSTATUS_WIN_STATUS_FILE_LOCK_CONFLICT = 0xC0000054, + MD_NTSTATUS_WIN_STATUS_LOCK_NOT_GRANTED = 0xC0000055, + MD_NTSTATUS_WIN_STATUS_DELETE_PENDING = 0xC0000056, + MD_NTSTATUS_WIN_STATUS_CTL_FILE_NOT_SUPPORTED = 0xC0000057, + MD_NTSTATUS_WIN_STATUS_UNKNOWN_REVISION = 0xC0000058, + MD_NTSTATUS_WIN_STATUS_REVISION_MISMATCH = 0xC0000059, + MD_NTSTATUS_WIN_STATUS_INVALID_OWNER = 0xC000005A, + MD_NTSTATUS_WIN_STATUS_INVALID_PRIMARY_GROUP = 0xC000005B, + MD_NTSTATUS_WIN_STATUS_NO_IMPERSONATION_TOKEN = 0xC000005C, + MD_NTSTATUS_WIN_STATUS_CANT_DISABLE_MANDATORY = 0xC000005D, + MD_NTSTATUS_WIN_STATUS_NO_LOGON_SERVERS = 0xC000005E, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_LOGON_SESSION = 0xC000005F, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_PRIVILEGE = 0xC0000060, + MD_NTSTATUS_WIN_STATUS_PRIVILEGE_NOT_HELD = 0xC0000061, + MD_NTSTATUS_WIN_STATUS_INVALID_ACCOUNT_NAME = 0xC0000062, + MD_NTSTATUS_WIN_STATUS_USER_EXISTS = 0xC0000063, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_USER = 0xC0000064, + MD_NTSTATUS_WIN_STATUS_GROUP_EXISTS = 0xC0000065, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_GROUP = 0xC0000066, + MD_NTSTATUS_WIN_STATUS_MEMBER_IN_GROUP = 0xC0000067, + MD_NTSTATUS_WIN_STATUS_MEMBER_NOT_IN_GROUP = 0xC0000068, + MD_NTSTATUS_WIN_STATUS_LAST_ADMIN = 0xC0000069, + MD_NTSTATUS_WIN_STATUS_WRONG_PASSWORD = 0xC000006A, + MD_NTSTATUS_WIN_STATUS_ILL_FORMED_PASSWORD = 0xC000006B, + MD_NTSTATUS_WIN_STATUS_PASSWORD_RESTRICTION = 0xC000006C, + MD_NTSTATUS_WIN_STATUS_LOGON_FAILURE = 0xC000006D, + MD_NTSTATUS_WIN_STATUS_ACCOUNT_RESTRICTION = 0xC000006E, + MD_NTSTATUS_WIN_STATUS_INVALID_LOGON_HOURS = 0xC000006F, + MD_NTSTATUS_WIN_STATUS_INVALID_WORKSTATION = 0xC0000070, + MD_NTSTATUS_WIN_STATUS_PASSWORD_EXPIRED = 0xC0000071, + MD_NTSTATUS_WIN_STATUS_ACCOUNT_DISABLED = 0xC0000072, + MD_NTSTATUS_WIN_STATUS_NONE_MAPPED = 0xC0000073, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_LUIDS_REQUESTED = 0xC0000074, + MD_NTSTATUS_WIN_STATUS_LUIDS_EXHAUSTED = 0xC0000075, + MD_NTSTATUS_WIN_STATUS_INVALID_SUB_AUTHORITY = 0xC0000076, + MD_NTSTATUS_WIN_STATUS_INVALID_ACL = 0xC0000077, + MD_NTSTATUS_WIN_STATUS_INVALID_SID = 0xC0000078, + MD_NTSTATUS_WIN_STATUS_INVALID_SECURITY_DESCR = 0xC0000079, + MD_NTSTATUS_WIN_STATUS_PROCEDURE_NOT_FOUND = 0xC000007A, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_FORMAT = 0xC000007B, + MD_NTSTATUS_WIN_STATUS_NO_TOKEN = 0xC000007C, + MD_NTSTATUS_WIN_STATUS_BAD_INHERITANCE_ACL = 0xC000007D, + MD_NTSTATUS_WIN_STATUS_RANGE_NOT_LOCKED = 0xC000007E, + MD_NTSTATUS_WIN_STATUS_DISK_FULL = 0xC000007F, + MD_NTSTATUS_WIN_STATUS_SERVER_DISABLED = 0xC0000080, + MD_NTSTATUS_WIN_STATUS_SERVER_NOT_DISABLED = 0xC0000081, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_GUIDS_REQUESTED = 0xC0000082, + MD_NTSTATUS_WIN_STATUS_GUIDS_EXHAUSTED = 0xC0000083, + MD_NTSTATUS_WIN_STATUS_INVALID_ID_AUTHORITY = 0xC0000084, + MD_NTSTATUS_WIN_STATUS_AGENTS_EXHAUSTED = 0xC0000085, + MD_NTSTATUS_WIN_STATUS_INVALID_VOLUME_LABEL = 0xC0000086, + MD_NTSTATUS_WIN_STATUS_SECTION_NOT_EXTENDED = 0xC0000087, + MD_NTSTATUS_WIN_STATUS_NOT_MAPPED_DATA = 0xC0000088, + MD_NTSTATUS_WIN_STATUS_RESOURCE_DATA_NOT_FOUND = 0xC0000089, + MD_NTSTATUS_WIN_STATUS_RESOURCE_TYPE_NOT_FOUND = 0xC000008A, + MD_NTSTATUS_WIN_STATUS_RESOURCE_NAME_NOT_FOUND = 0xC000008B, + MD_NTSTATUS_WIN_STATUS_ARRAY_BOUNDS_EXCEEDED = 0xC000008C, + MD_NTSTATUS_WIN_STATUS_FLOAT_DENORMAL_OPERAND = 0xC000008D, + MD_NTSTATUS_WIN_STATUS_FLOAT_DIVIDE_BY_ZERO = 0xC000008E, + MD_NTSTATUS_WIN_STATUS_FLOAT_INEXACT_RESULT = 0xC000008F, + MD_NTSTATUS_WIN_STATUS_FLOAT_INVALID_OPERATION = 0xC0000090, + MD_NTSTATUS_WIN_STATUS_FLOAT_OVERFLOW = 0xC0000091, + MD_NTSTATUS_WIN_STATUS_FLOAT_STACK_CHECK = 0xC0000092, + MD_NTSTATUS_WIN_STATUS_FLOAT_UNDERFLOW = 0xC0000093, + MD_NTSTATUS_WIN_STATUS_INTEGER_DIVIDE_BY_ZERO = 0xC0000094, + MD_NTSTATUS_WIN_STATUS_INTEGER_OVERFLOW = 0xC0000095, + MD_NTSTATUS_WIN_STATUS_PRIVILEGED_INSTRUCTION = 0xC0000096, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_PAGING_FILES = 0xC0000097, + MD_NTSTATUS_WIN_STATUS_FILE_INVALID = 0xC0000098, + MD_NTSTATUS_WIN_STATUS_ALLOTTED_SPACE_EXCEEDED = 0xC0000099, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_RESOURCES = 0xC000009A, + MD_NTSTATUS_WIN_STATUS_DFS_EXIT_PATH_FOUND = 0xC000009B, + MD_NTSTATUS_WIN_STATUS_DEVICE_DATA_ERROR = 0xC000009C, + MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_CONNECTED = 0xC000009D, + MD_NTSTATUS_WIN_STATUS_DEVICE_POWER_FAILURE = 0xC000009E, + MD_NTSTATUS_WIN_STATUS_FREE_VM_NOT_AT_BASE = 0xC000009F, + MD_NTSTATUS_WIN_STATUS_MEMORY_NOT_ALLOCATED = 0xC00000A0, + MD_NTSTATUS_WIN_STATUS_WORKING_SET_QUOTA = 0xC00000A1, + MD_NTSTATUS_WIN_STATUS_MEDIA_WRITE_PROTECTED = 0xC00000A2, + MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_READY = 0xC00000A3, + MD_NTSTATUS_WIN_STATUS_INVALID_GROUP_ATTRIBUTES = 0xC00000A4, + MD_NTSTATUS_WIN_STATUS_BAD_IMPERSONATION_LEVEL = 0xC00000A5, + MD_NTSTATUS_WIN_STATUS_CANT_OPEN_ANONYMOUS = 0xC00000A6, + MD_NTSTATUS_WIN_STATUS_BAD_VALIDATION_CLASS = 0xC00000A7, + MD_NTSTATUS_WIN_STATUS_BAD_TOKEN_TYPE = 0xC00000A8, + MD_NTSTATUS_WIN_STATUS_BAD_MASTER_BOOT_RECORD = 0xC00000A9, + MD_NTSTATUS_WIN_STATUS_INSTRUCTION_MISALIGNMENT = 0xC00000AA, + MD_NTSTATUS_WIN_STATUS_INSTANCE_NOT_AVAILABLE = 0xC00000AB, + MD_NTSTATUS_WIN_STATUS_PIPE_NOT_AVAILABLE = 0xC00000AC, + MD_NTSTATUS_WIN_STATUS_INVALID_PIPE_STATE = 0xC00000AD, + MD_NTSTATUS_WIN_STATUS_PIPE_BUSY = 0xC00000AE, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_FUNCTION = 0xC00000AF, + MD_NTSTATUS_WIN_STATUS_PIPE_DISCONNECTED = 0xC00000B0, + MD_NTSTATUS_WIN_STATUS_PIPE_CLOSING = 0xC00000B1, + MD_NTSTATUS_WIN_STATUS_PIPE_CONNECTED = 0xC00000B2, + MD_NTSTATUS_WIN_STATUS_PIPE_LISTENING = 0xC00000B3, + MD_NTSTATUS_WIN_STATUS_INVALID_READ_MODE = 0xC00000B4, + MD_NTSTATUS_WIN_STATUS_IO_TIMEOUT = 0xC00000B5, + MD_NTSTATUS_WIN_STATUS_FILE_FORCED_CLOSED = 0xC00000B6, + MD_NTSTATUS_WIN_STATUS_PROFILING_NOT_STARTED = 0xC00000B7, + MD_NTSTATUS_WIN_STATUS_PROFILING_NOT_STOPPED = 0xC00000B8, + MD_NTSTATUS_WIN_STATUS_COULD_NOT_INTERPRET = 0xC00000B9, + MD_NTSTATUS_WIN_STATUS_FILE_IS_A_DIRECTORY = 0xC00000BA, + MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED = 0xC00000BB, + MD_NTSTATUS_WIN_STATUS_REMOTE_NOT_LISTENING = 0xC00000BC, + MD_NTSTATUS_WIN_STATUS_DUPLICATE_NAME = 0xC00000BD, + MD_NTSTATUS_WIN_STATUS_BAD_NETWORK_PATH = 0xC00000BE, + MD_NTSTATUS_WIN_STATUS_NETWORK_BUSY = 0xC00000BF, + MD_NTSTATUS_WIN_STATUS_DEVICE_DOES_NOT_EXIST = 0xC00000C0, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_COMMANDS = 0xC00000C1, + MD_NTSTATUS_WIN_STATUS_ADAPTER_HARDWARE_ERROR = 0xC00000C2, + MD_NTSTATUS_WIN_STATUS_INVALID_NETWORK_RESPONSE = 0xC00000C3, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_NETWORK_ERROR = 0xC00000C4, + MD_NTSTATUS_WIN_STATUS_BAD_REMOTE_ADAPTER = 0xC00000C5, + MD_NTSTATUS_WIN_STATUS_PRINT_QUEUE_FULL = 0xC00000C6, + MD_NTSTATUS_WIN_STATUS_NO_SPOOL_SPACE = 0xC00000C7, + MD_NTSTATUS_WIN_STATUS_PRINT_CANCELLED = 0xC00000C8, + MD_NTSTATUS_WIN_STATUS_NETWORK_NAME_DELETED = 0xC00000C9, + MD_NTSTATUS_WIN_STATUS_NETWORK_ACCESS_DENIED = 0xC00000CA, + MD_NTSTATUS_WIN_STATUS_BAD_DEVICE_TYPE = 0xC00000CB, + MD_NTSTATUS_WIN_STATUS_BAD_NETWORK_NAME = 0xC00000CC, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_NAMES = 0xC00000CD, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_SESSIONS = 0xC00000CE, + MD_NTSTATUS_WIN_STATUS_SHARING_PAUSED = 0xC00000CF, + MD_NTSTATUS_WIN_STATUS_REQUEST_NOT_ACCEPTED = 0xC00000D0, + MD_NTSTATUS_WIN_STATUS_REDIRECTOR_PAUSED = 0xC00000D1, + MD_NTSTATUS_WIN_STATUS_NET_WRITE_FAULT = 0xC00000D2, + MD_NTSTATUS_WIN_STATUS_PROFILING_AT_LIMIT = 0xC00000D3, + MD_NTSTATUS_WIN_STATUS_NOT_SAME_DEVICE = 0xC00000D4, + MD_NTSTATUS_WIN_STATUS_FILE_RENAMED = 0xC00000D5, + MD_NTSTATUS_WIN_STATUS_VIRTUAL_CIRCUIT_CLOSED = 0xC00000D6, + MD_NTSTATUS_WIN_STATUS_NO_SECURITY_ON_OBJECT = 0xC00000D7, + MD_NTSTATUS_WIN_STATUS_CANT_WAIT = 0xC00000D8, + MD_NTSTATUS_WIN_STATUS_PIPE_EMPTY = 0xC00000D9, + MD_NTSTATUS_WIN_STATUS_CANT_ACCESS_DOMAIN_INFO = 0xC00000DA, + MD_NTSTATUS_WIN_STATUS_CANT_TERMINATE_SELF = 0xC00000DB, + MD_NTSTATUS_WIN_STATUS_INVALID_SERVER_STATE = 0xC00000DC, + MD_NTSTATUS_WIN_STATUS_INVALID_DOMAIN_STATE = 0xC00000DD, + MD_NTSTATUS_WIN_STATUS_INVALID_DOMAIN_ROLE = 0xC00000DE, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_DOMAIN = 0xC00000DF, + MD_NTSTATUS_WIN_STATUS_DOMAIN_EXISTS = 0xC00000E0, + MD_NTSTATUS_WIN_STATUS_DOMAIN_LIMIT_EXCEEDED = 0xC00000E1, + MD_NTSTATUS_WIN_STATUS_OPLOCK_NOT_GRANTED = 0xC00000E2, + MD_NTSTATUS_WIN_STATUS_INVALID_OPLOCK_PROTOCOL = 0xC00000E3, + MD_NTSTATUS_WIN_STATUS_INTERNAL_DB_CORRUPTION = 0xC00000E4, + MD_NTSTATUS_WIN_STATUS_INTERNAL_ERROR = 0xC00000E5, + MD_NTSTATUS_WIN_STATUS_GENERIC_NOT_MAPPED = 0xC00000E6, + MD_NTSTATUS_WIN_STATUS_BAD_DESCRIPTOR_FORMAT = 0xC00000E7, + MD_NTSTATUS_WIN_STATUS_INVALID_USER_BUFFER = 0xC00000E8, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_IO_ERROR = 0xC00000E9, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_CREATE_ERR = 0xC00000EA, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_MAP_ERROR = 0xC00000EB, + MD_NTSTATUS_WIN_STATUS_UNEXPECTED_MM_EXTEND_ERR = 0xC00000EC, + MD_NTSTATUS_WIN_STATUS_NOT_LOGON_PROCESS = 0xC00000ED, + MD_NTSTATUS_WIN_STATUS_LOGON_SESSION_EXISTS = 0xC00000EE, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_1 = 0xC00000EF, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_2 = 0xC00000F0, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_3 = 0xC00000F1, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_4 = 0xC00000F2, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_5 = 0xC00000F3, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_6 = 0xC00000F4, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_7 = 0xC00000F5, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_8 = 0xC00000F6, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_9 = 0xC00000F7, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_10 = 0xC00000F8, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_11 = 0xC00000F9, + MD_NTSTATUS_WIN_STATUS_INVALID_PARAMETER_12 = 0xC00000FA, + MD_NTSTATUS_WIN_STATUS_REDIRECTOR_NOT_STARTED = 0xC00000FB, + MD_NTSTATUS_WIN_STATUS_REDIRECTOR_STARTED = 0xC00000FC, + MD_NTSTATUS_WIN_STATUS_STACK_OVERFLOW = 0xC00000FD, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_PACKAGE = 0xC00000FE, + MD_NTSTATUS_WIN_STATUS_BAD_FUNCTION_TABLE = 0xC00000FF, + MD_NTSTATUS_WIN_STATUS_VARIABLE_NOT_FOUND = 0xC0000100, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_EMPTY = 0xC0000101, + MD_NTSTATUS_WIN_STATUS_FILE_CORRUPT_ERROR = 0xC0000102, + MD_NTSTATUS_WIN_STATUS_NOT_A_DIRECTORY = 0xC0000103, + MD_NTSTATUS_WIN_STATUS_BAD_LOGON_SESSION_STATE = 0xC0000104, + MD_NTSTATUS_WIN_STATUS_LOGON_SESSION_COLLISION = 0xC0000105, + MD_NTSTATUS_WIN_STATUS_NAME_TOO_LONG = 0xC0000106, + MD_NTSTATUS_WIN_STATUS_FILES_OPEN = 0xC0000107, + MD_NTSTATUS_WIN_STATUS_CONNECTION_IN_USE = 0xC0000108, + MD_NTSTATUS_WIN_STATUS_MESSAGE_NOT_FOUND = 0xC0000109, + MD_NTSTATUS_WIN_STATUS_PROCESS_IS_TERMINATING = 0xC000010A, + MD_NTSTATUS_WIN_STATUS_INVALID_LOGON_TYPE = 0xC000010B, + MD_NTSTATUS_WIN_STATUS_NO_GUID_TRANSLATION = 0xC000010C, + MD_NTSTATUS_WIN_STATUS_CANNOT_IMPERSONATE = 0xC000010D, + MD_NTSTATUS_WIN_STATUS_IMAGE_ALREADY_LOADED = 0xC000010E, + MD_NTSTATUS_WIN_STATUS_ABIOS_NOT_PRESENT = 0xC000010F, + MD_NTSTATUS_WIN_STATUS_ABIOS_LID_NOT_EXIST = 0xC0000110, + MD_NTSTATUS_WIN_STATUS_ABIOS_LID_ALREADY_OWNED = 0xC0000111, + MD_NTSTATUS_WIN_STATUS_ABIOS_NOT_LID_OWNER = 0xC0000112, + MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_COMMAND = 0xC0000113, + MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_LID = 0xC0000114, + MD_NTSTATUS_WIN_STATUS_ABIOS_SELECTOR_NOT_AVAILABLE = 0xC0000115, + MD_NTSTATUS_WIN_STATUS_ABIOS_INVALID_SELECTOR = 0xC0000116, + MD_NTSTATUS_WIN_STATUS_NO_LDT = 0xC0000117, + MD_NTSTATUS_WIN_STATUS_INVALID_LDT_SIZE = 0xC0000118, + MD_NTSTATUS_WIN_STATUS_INVALID_LDT_OFFSET = 0xC0000119, + MD_NTSTATUS_WIN_STATUS_INVALID_LDT_DESCRIPTOR = 0xC000011A, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_NE_FORMAT = 0xC000011B, + MD_NTSTATUS_WIN_STATUS_RXACT_INVALID_STATE = 0xC000011C, + MD_NTSTATUS_WIN_STATUS_RXACT_COMMIT_FAILURE = 0xC000011D, + MD_NTSTATUS_WIN_STATUS_MAPPED_FILE_SIZE_ZERO = 0xC000011E, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_OPENED_FILES = 0xC000011F, + MD_NTSTATUS_WIN_STATUS_CANCELLED = 0xC0000120, + MD_NTSTATUS_WIN_STATUS_CANNOT_DELETE = 0xC0000121, + MD_NTSTATUS_WIN_STATUS_INVALID_COMPUTER_NAME = 0xC0000122, + MD_NTSTATUS_WIN_STATUS_FILE_DELETED = 0xC0000123, + MD_NTSTATUS_WIN_STATUS_SPECIAL_ACCOUNT = 0xC0000124, + MD_NTSTATUS_WIN_STATUS_SPECIAL_GROUP = 0xC0000125, + MD_NTSTATUS_WIN_STATUS_SPECIAL_USER = 0xC0000126, + MD_NTSTATUS_WIN_STATUS_MEMBERS_PRIMARY_GROUP = 0xC0000127, + MD_NTSTATUS_WIN_STATUS_FILE_CLOSED = 0xC0000128, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_THREADS = 0xC0000129, + MD_NTSTATUS_WIN_STATUS_THREAD_NOT_IN_PROCESS = 0xC000012A, + MD_NTSTATUS_WIN_STATUS_TOKEN_ALREADY_IN_USE = 0xC000012B, + MD_NTSTATUS_WIN_STATUS_PAGEFILE_QUOTA_EXCEEDED = 0xC000012C, + MD_NTSTATUS_WIN_STATUS_COMMITMENT_LIMIT = 0xC000012D, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_LE_FORMAT = 0xC000012E, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_NOT_MZ = 0xC000012F, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_PROTECT = 0xC0000130, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_16 = 0xC0000131, + MD_NTSTATUS_WIN_STATUS_LOGON_SERVER_CONFLICT = 0xC0000132, + MD_NTSTATUS_WIN_STATUS_TIME_DIFFERENCE_AT_DC = 0xC0000133, + MD_NTSTATUS_WIN_STATUS_SYNCHRONIZATION_REQUIRED = 0xC0000134, + MD_NTSTATUS_WIN_STATUS_DLL_NOT_FOUND = 0xC0000135, + MD_NTSTATUS_WIN_STATUS_OPEN_FAILED = 0xC0000136, + MD_NTSTATUS_WIN_STATUS_IO_PRIVILEGE_FAILED = 0xC0000137, + MD_NTSTATUS_WIN_STATUS_ORDINAL_NOT_FOUND = 0xC0000138, + MD_NTSTATUS_WIN_STATUS_ENTRYPOINT_NOT_FOUND = 0xC0000139, + MD_NTSTATUS_WIN_STATUS_CONTROL_C_EXIT = 0xC000013A, + MD_NTSTATUS_WIN_STATUS_LOCAL_DISCONNECT = 0xC000013B, + MD_NTSTATUS_WIN_STATUS_REMOTE_DISCONNECT = 0xC000013C, + MD_NTSTATUS_WIN_STATUS_REMOTE_RESOURCES = 0xC000013D, + MD_NTSTATUS_WIN_STATUS_LINK_FAILED = 0xC000013E, + MD_NTSTATUS_WIN_STATUS_LINK_TIMEOUT = 0xC000013F, + MD_NTSTATUS_WIN_STATUS_INVALID_CONNECTION = 0xC0000140, + MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS = 0xC0000141, + MD_NTSTATUS_WIN_STATUS_DLL_INIT_FAILED = 0xC0000142, + MD_NTSTATUS_WIN_STATUS_MISSING_SYSTEMFILE = 0xC0000143, + MD_NTSTATUS_WIN_STATUS_UNHANDLED_EXCEPTION = 0xC0000144, + MD_NTSTATUS_WIN_STATUS_APP_INIT_FAILURE = 0xC0000145, + MD_NTSTATUS_WIN_STATUS_PAGEFILE_CREATE_FAILED = 0xC0000146, + MD_NTSTATUS_WIN_STATUS_NO_PAGEFILE = 0xC0000147, + MD_NTSTATUS_WIN_STATUS_INVALID_LEVEL = 0xC0000148, + MD_NTSTATUS_WIN_STATUS_WRONG_PASSWORD_CORE = 0xC0000149, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_FLOAT_CONTEXT = 0xC000014A, + MD_NTSTATUS_WIN_STATUS_PIPE_BROKEN = 0xC000014B, + MD_NTSTATUS_WIN_STATUS_REGISTRY_CORRUPT = 0xC000014C, + MD_NTSTATUS_WIN_STATUS_REGISTRY_IO_FAILED = 0xC000014D, + MD_NTSTATUS_WIN_STATUS_NO_EVENT_PAIR = 0xC000014E, + MD_NTSTATUS_WIN_STATUS_UNRECOGNIZED_VOLUME = 0xC000014F, + MD_NTSTATUS_WIN_STATUS_SERIAL_NO_DEVICE_INITED = 0xC0000150, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_ALIAS = 0xC0000151, + MD_NTSTATUS_WIN_STATUS_MEMBER_NOT_IN_ALIAS = 0xC0000152, + MD_NTSTATUS_WIN_STATUS_MEMBER_IN_ALIAS = 0xC0000153, + MD_NTSTATUS_WIN_STATUS_ALIAS_EXISTS = 0xC0000154, + MD_NTSTATUS_WIN_STATUS_LOGON_NOT_GRANTED = 0xC0000155, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_SECRETS = 0xC0000156, + MD_NTSTATUS_WIN_STATUS_SECRET_TOO_LONG = 0xC0000157, + MD_NTSTATUS_WIN_STATUS_INTERNAL_DB_ERROR = 0xC0000158, + MD_NTSTATUS_WIN_STATUS_FULLSCREEN_MODE = 0xC0000159, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_CONTEXT_IDS = 0xC000015A, + MD_NTSTATUS_WIN_STATUS_LOGON_TYPE_NOT_GRANTED = 0xC000015B, + MD_NTSTATUS_WIN_STATUS_NOT_REGISTRY_FILE = 0xC000015C, + MD_NTSTATUS_WIN_STATUS_NT_CROSS_ENCRYPTION_REQUIRED = 0xC000015D, + MD_NTSTATUS_WIN_STATUS_DOMAIN_CTRLR_CONFIG_ERROR = 0xC000015E, + MD_NTSTATUS_WIN_STATUS_FT_MISSING_MEMBER = 0xC000015F, + MD_NTSTATUS_WIN_STATUS_ILL_FORMED_SERVICE_ENTRY = 0xC0000160, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_CHARACTER = 0xC0000161, + MD_NTSTATUS_WIN_STATUS_UNMAPPABLE_CHARACTER = 0xC0000162, + MD_NTSTATUS_WIN_STATUS_UNDEFINED_CHARACTER = 0xC0000163, + MD_NTSTATUS_WIN_STATUS_FLOPPY_VOLUME = 0xC0000164, + MD_NTSTATUS_WIN_STATUS_FLOPPY_ID_MARK_NOT_FOUND = 0xC0000165, + MD_NTSTATUS_WIN_STATUS_FLOPPY_WRONG_CYLINDER = 0xC0000166, + MD_NTSTATUS_WIN_STATUS_FLOPPY_UNKNOWN_ERROR = 0xC0000167, + MD_NTSTATUS_WIN_STATUS_FLOPPY_BAD_REGISTERS = 0xC0000168, + MD_NTSTATUS_WIN_STATUS_DISK_RECALIBRATE_FAILED = 0xC0000169, + MD_NTSTATUS_WIN_STATUS_DISK_OPERATION_FAILED = 0xC000016A, + MD_NTSTATUS_WIN_STATUS_DISK_RESET_FAILED = 0xC000016B, + MD_NTSTATUS_WIN_STATUS_SHARED_IRQ_BUSY = 0xC000016C, + MD_NTSTATUS_WIN_STATUS_FT_ORPHANING = 0xC000016D, + MD_NTSTATUS_WIN_STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT = 0xC000016E, + MD_NTSTATUS_WIN_STATUS_PARTITION_FAILURE = 0xC0000172, + MD_NTSTATUS_WIN_STATUS_INVALID_BLOCK_LENGTH = 0xC0000173, + MD_NTSTATUS_WIN_STATUS_DEVICE_NOT_PARTITIONED = 0xC0000174, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_LOCK_MEDIA = 0xC0000175, + MD_NTSTATUS_WIN_STATUS_UNABLE_TO_UNLOAD_MEDIA = 0xC0000176, + MD_NTSTATUS_WIN_STATUS_EOM_OVERFLOW = 0xC0000177, + MD_NTSTATUS_WIN_STATUS_NO_MEDIA = 0xC0000178, + MD_NTSTATUS_WIN_STATUS_NO_SUCH_MEMBER = 0xC000017A, + MD_NTSTATUS_WIN_STATUS_INVALID_MEMBER = 0xC000017B, + MD_NTSTATUS_WIN_STATUS_KEY_DELETED = 0xC000017C, + MD_NTSTATUS_WIN_STATUS_NO_LOG_SPACE = 0xC000017D, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_SIDS = 0xC000017E, + MD_NTSTATUS_WIN_STATUS_LM_CROSS_ENCRYPTION_REQUIRED = 0xC000017F, + MD_NTSTATUS_WIN_STATUS_KEY_HAS_CHILDREN = 0xC0000180, + MD_NTSTATUS_WIN_STATUS_CHILD_MUST_BE_VOLATILE = 0xC0000181, + MD_NTSTATUS_WIN_STATUS_DEVICE_CONFIGURATION_ERROR = 0xC0000182, + MD_NTSTATUS_WIN_STATUS_DRIVER_INTERNAL_ERROR = 0xC0000183, + MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_STATE = 0xC0000184, + MD_NTSTATUS_WIN_STATUS_IO_DEVICE_ERROR = 0xC0000185, + MD_NTSTATUS_WIN_STATUS_DEVICE_PROTOCOL_ERROR = 0xC0000186, + MD_NTSTATUS_WIN_STATUS_BACKUP_CONTROLLER = 0xC0000187, + MD_NTSTATUS_WIN_STATUS_LOG_FILE_FULL = 0xC0000188, + MD_NTSTATUS_WIN_STATUS_TOO_LATE = 0xC0000189, + MD_NTSTATUS_WIN_STATUS_NO_TRUST_LSA_SECRET = 0xC000018A, + MD_NTSTATUS_WIN_STATUS_NO_TRUST_SAM_ACCOUNT = 0xC000018B, + MD_NTSTATUS_WIN_STATUS_TRUSTED_DOMAIN_FAILURE = 0xC000018C, + MD_NTSTATUS_WIN_STATUS_TRUSTED_RELATIONSHIP_FAILURE = 0xC000018D, + MD_NTSTATUS_WIN_STATUS_EVENTLOG_FILE_CORRUPT = 0xC000018E, + MD_NTSTATUS_WIN_STATUS_EVENTLOG_CANT_START = 0xC000018F, + MD_NTSTATUS_WIN_STATUS_TRUST_FAILURE = 0xC0000190, + MD_NTSTATUS_WIN_STATUS_MUTANT_LIMIT_EXCEEDED = 0xC0000191, + MD_NTSTATUS_WIN_STATUS_NETLOGON_NOT_STARTED = 0xC0000192, + MD_NTSTATUS_WIN_STATUS_ACCOUNT_EXPIRED = 0xC0000193, + MD_NTSTATUS_WIN_STATUS_POSSIBLE_DEADLOCK = 0xC0000194, + MD_NTSTATUS_WIN_STATUS_NETWORK_CREDENTIAL_CONFLICT = 0xC0000195, + MD_NTSTATUS_WIN_STATUS_REMOTE_SESSION_LIMIT = 0xC0000196, + MD_NTSTATUS_WIN_STATUS_EVENTLOG_FILE_CHANGED = 0xC0000197, + MD_NTSTATUS_WIN_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT = 0xC0000198, + MD_NTSTATUS_WIN_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT = 0xC0000199, + MD_NTSTATUS_WIN_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT = 0xC000019A, + MD_NTSTATUS_WIN_STATUS_DOMAIN_TRUST_INCONSISTENT = 0xC000019B, + MD_NTSTATUS_WIN_STATUS_FS_DRIVER_REQUIRED = 0xC000019C, + MD_NTSTATUS_WIN_STATUS_IMAGE_ALREADY_LOADED_AS_DLL = 0xC000019D, + MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING = 0xC000019E, + MD_NTSTATUS_WIN_STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME = 0xC000019F, + MD_NTSTATUS_WIN_STATUS_SECURITY_STREAM_IS_INCONSISTENT = 0xC00001A0, + MD_NTSTATUS_WIN_STATUS_INVALID_LOCK_RANGE = 0xC00001A1, + MD_NTSTATUS_WIN_STATUS_INVALID_ACE_CONDITION = 0xC00001A2, + MD_NTSTATUS_WIN_STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT = 0xC00001A3, + MD_NTSTATUS_WIN_STATUS_NOTIFICATION_GUID_ALREADY_DEFINED = 0xC00001A4, + MD_NTSTATUS_WIN_STATUS_INVALID_EXCEPTION_HANDLER = 0xC00001A5, + MD_NTSTATUS_WIN_STATUS_DUPLICATE_PRIVILEGES = 0xC00001A6, + MD_NTSTATUS_WIN_STATUS_NOT_ALLOWED_ON_SYSTEM_FILE = 0xC00001A7, + MD_NTSTATUS_WIN_STATUS_REPAIR_NEEDED = 0xC00001A8, + MD_NTSTATUS_WIN_STATUS_QUOTA_NOT_ENABLED = 0xC00001A9, + MD_NTSTATUS_WIN_STATUS_NO_APPLICATION_PACKAGE = 0xC00001AA, + MD_NTSTATUS_WIN_STATUS_NETWORK_OPEN_RESTRICTION = 0xC0000201, + MD_NTSTATUS_WIN_STATUS_NO_USER_SESSION_KEY = 0xC0000202, + MD_NTSTATUS_WIN_STATUS_USER_SESSION_DELETED = 0xC0000203, + MD_NTSTATUS_WIN_STATUS_RESOURCE_LANG_NOT_FOUND = 0xC0000204, + MD_NTSTATUS_WIN_STATUS_INSUFF_SERVER_RESOURCES = 0xC0000205, + MD_NTSTATUS_WIN_STATUS_INVALID_BUFFER_SIZE = 0xC0000206, + MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS_COMPONENT = 0xC0000207, + MD_NTSTATUS_WIN_STATUS_INVALID_ADDRESS_WILDCARD = 0xC0000208, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_ADDRESSES = 0xC0000209, + MD_NTSTATUS_WIN_STATUS_ADDRESS_ALREADY_EXISTS = 0xC000020A, + MD_NTSTATUS_WIN_STATUS_ADDRESS_CLOSED = 0xC000020B, + MD_NTSTATUS_WIN_STATUS_CONNECTION_DISCONNECTED = 0xC000020C, + MD_NTSTATUS_WIN_STATUS_CONNECTION_RESET = 0xC000020D, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_NODES = 0xC000020E, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_ABORTED = 0xC000020F, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_TIMED_OUT = 0xC0000210, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_RELEASE = 0xC0000211, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_MATCH = 0xC0000212, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_RESPONDED = 0xC0000213, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_ID = 0xC0000214, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_TYPE = 0xC0000215, + MD_NTSTATUS_WIN_STATUS_NOT_SERVER_SESSION = 0xC0000216, + MD_NTSTATUS_WIN_STATUS_NOT_CLIENT_SESSION = 0xC0000217, + MD_NTSTATUS_WIN_STATUS_CANNOT_LOAD_REGISTRY_FILE = 0xC0000218, + MD_NTSTATUS_WIN_STATUS_DEBUG_ATTACH_FAILED = 0xC0000219, + MD_NTSTATUS_WIN_STATUS_SYSTEM_PROCESS_TERMINATED = 0xC000021A, + MD_NTSTATUS_WIN_STATUS_DATA_NOT_ACCEPTED = 0xC000021B, + MD_NTSTATUS_WIN_STATUS_NO_BROWSER_SERVERS_FOUND = 0xC000021C, + MD_NTSTATUS_WIN_STATUS_VDM_HARD_ERROR = 0xC000021D, + MD_NTSTATUS_WIN_STATUS_DRIVER_CANCEL_TIMEOUT = 0xC000021E, + MD_NTSTATUS_WIN_STATUS_REPLY_MESSAGE_MISMATCH = 0xC000021F, + MD_NTSTATUS_WIN_STATUS_MAPPED_ALIGNMENT = 0xC0000220, + MD_NTSTATUS_WIN_STATUS_IMAGE_CHECKSUM_MISMATCH = 0xC0000221, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA = 0xC0000222, + MD_NTSTATUS_WIN_STATUS_CLIENT_SERVER_PARAMETERS_INVALID = 0xC0000223, + MD_NTSTATUS_WIN_STATUS_PASSWORD_MUST_CHANGE = 0xC0000224, + MD_NTSTATUS_WIN_STATUS_NOT_FOUND = 0xC0000225, + MD_NTSTATUS_WIN_STATUS_NOT_TINY_STREAM = 0xC0000226, + MD_NTSTATUS_WIN_STATUS_RECOVERY_FAILURE = 0xC0000227, + MD_NTSTATUS_WIN_STATUS_STACK_OVERFLOW_READ = 0xC0000228, + MD_NTSTATUS_WIN_STATUS_FAIL_CHECK = 0xC0000229, + MD_NTSTATUS_WIN_STATUS_DUPLICATE_OBJECTID = 0xC000022A, + MD_NTSTATUS_WIN_STATUS_OBJECTID_EXISTS = 0xC000022B, + MD_NTSTATUS_WIN_STATUS_CONVERT_TO_LARGE = 0xC000022C, + MD_NTSTATUS_WIN_STATUS_RETRY = 0xC000022D, + MD_NTSTATUS_WIN_STATUS_FOUND_OUT_OF_SCOPE = 0xC000022E, + MD_NTSTATUS_WIN_STATUS_ALLOCATE_BUCKET = 0xC000022F, + MD_NTSTATUS_WIN_STATUS_PROPSET_NOT_FOUND = 0xC0000230, + MD_NTSTATUS_WIN_STATUS_MARSHALL_OVERFLOW = 0xC0000231, + MD_NTSTATUS_WIN_STATUS_INVALID_VARIANT = 0xC0000232, + MD_NTSTATUS_WIN_STATUS_DOMAIN_CONTROLLER_NOT_FOUND = 0xC0000233, + MD_NTSTATUS_WIN_STATUS_ACCOUNT_LOCKED_OUT = 0xC0000234, + MD_NTSTATUS_WIN_STATUS_HANDLE_NOT_CLOSABLE = 0xC0000235, + MD_NTSTATUS_WIN_STATUS_CONNECTION_REFUSED = 0xC0000236, + MD_NTSTATUS_WIN_STATUS_GRACEFUL_DISCONNECT = 0xC0000237, + MD_NTSTATUS_WIN_STATUS_ADDRESS_ALREADY_ASSOCIATED = 0xC0000238, + MD_NTSTATUS_WIN_STATUS_ADDRESS_NOT_ASSOCIATED = 0xC0000239, + MD_NTSTATUS_WIN_STATUS_CONNECTION_INVALID = 0xC000023A, + MD_NTSTATUS_WIN_STATUS_CONNECTION_ACTIVE = 0xC000023B, + MD_NTSTATUS_WIN_STATUS_NETWORK_UNREACHABLE = 0xC000023C, + MD_NTSTATUS_WIN_STATUS_HOST_UNREACHABLE = 0xC000023D, + MD_NTSTATUS_WIN_STATUS_PROTOCOL_UNREACHABLE = 0xC000023E, + MD_NTSTATUS_WIN_STATUS_PORT_UNREACHABLE = 0xC000023F, + MD_NTSTATUS_WIN_STATUS_REQUEST_ABORTED = 0xC0000240, + MD_NTSTATUS_WIN_STATUS_CONNECTION_ABORTED = 0xC0000241, + MD_NTSTATUS_WIN_STATUS_BAD_COMPRESSION_BUFFER = 0xC0000242, + MD_NTSTATUS_WIN_STATUS_USER_MAPPED_FILE = 0xC0000243, + MD_NTSTATUS_WIN_STATUS_AUDIT_FAILED = 0xC0000244, + MD_NTSTATUS_WIN_STATUS_TIMER_RESOLUTION_NOT_SET = 0xC0000245, + MD_NTSTATUS_WIN_STATUS_CONNECTION_COUNT_LIMIT = 0xC0000246, + MD_NTSTATUS_WIN_STATUS_LOGIN_TIME_RESTRICTION = 0xC0000247, + MD_NTSTATUS_WIN_STATUS_LOGIN_WKSTA_RESTRICTION = 0xC0000248, + MD_NTSTATUS_WIN_STATUS_IMAGE_MP_UP_MISMATCH = 0xC0000249, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_LOGON_INFO = 0xC0000250, + MD_NTSTATUS_WIN_STATUS_BAD_DLL_ENTRYPOINT = 0xC0000251, + MD_NTSTATUS_WIN_STATUS_BAD_SERVICE_ENTRYPOINT = 0xC0000252, + MD_NTSTATUS_WIN_STATUS_LPC_REPLY_LOST = 0xC0000253, + MD_NTSTATUS_WIN_STATUS_IP_ADDRESS_CONFLICT1 = 0xC0000254, + MD_NTSTATUS_WIN_STATUS_IP_ADDRESS_CONFLICT2 = 0xC0000255, + MD_NTSTATUS_WIN_STATUS_REGISTRY_QUOTA_LIMIT = 0xC0000256, + MD_NTSTATUS_WIN_STATUS_PATH_NOT_COVERED = 0xC0000257, + MD_NTSTATUS_WIN_STATUS_NO_CALLBACK_ACTIVE = 0xC0000258, + MD_NTSTATUS_WIN_STATUS_LICENSE_QUOTA_EXCEEDED = 0xC0000259, + MD_NTSTATUS_WIN_STATUS_PWD_TOO_SHORT = 0xC000025A, + MD_NTSTATUS_WIN_STATUS_PWD_TOO_RECENT = 0xC000025B, + MD_NTSTATUS_WIN_STATUS_PWD_HISTORY_CONFLICT = 0xC000025C, + MD_NTSTATUS_WIN_STATUS_PLUGPLAY_NO_DEVICE = 0xC000025E, + MD_NTSTATUS_WIN_STATUS_UNSUPPORTED_COMPRESSION = 0xC000025F, + MD_NTSTATUS_WIN_STATUS_INVALID_HW_PROFILE = 0xC0000260, + MD_NTSTATUS_WIN_STATUS_INVALID_PLUGPLAY_DEVICE_PATH = 0xC0000261, + MD_NTSTATUS_WIN_STATUS_DRIVER_ORDINAL_NOT_FOUND = 0xC0000262, + MD_NTSTATUS_WIN_STATUS_DRIVER_ENTRYPOINT_NOT_FOUND = 0xC0000263, + MD_NTSTATUS_WIN_STATUS_RESOURCE_NOT_OWNED = 0xC0000264, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_LINKS = 0xC0000265, + MD_NTSTATUS_WIN_STATUS_QUOTA_LIST_INCONSISTENT = 0xC0000266, + MD_NTSTATUS_WIN_STATUS_FILE_IS_OFFLINE = 0xC0000267, + MD_NTSTATUS_WIN_STATUS_EVALUATION_EXPIRATION = 0xC0000268, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_DLL_RELOCATION = 0xC0000269, + MD_NTSTATUS_WIN_STATUS_LICENSE_VIOLATION = 0xC000026A, + MD_NTSTATUS_WIN_STATUS_DLL_INIT_FAILED_LOGOFF = 0xC000026B, + MD_NTSTATUS_WIN_STATUS_DRIVER_UNABLE_TO_LOAD = 0xC000026C, + MD_NTSTATUS_WIN_STATUS_DFS_UNAVAILABLE = 0xC000026D, + MD_NTSTATUS_WIN_STATUS_VOLUME_DISMOUNTED = 0xC000026E, + MD_NTSTATUS_WIN_STATUS_WX86_INTERNAL_ERROR = 0xC000026F, + MD_NTSTATUS_WIN_STATUS_WX86_FLOAT_STACK_CHECK = 0xC0000270, + MD_NTSTATUS_WIN_STATUS_VALIDATE_CONTINUE = 0xC0000271, + MD_NTSTATUS_WIN_STATUS_NO_MATCH = 0xC0000272, + MD_NTSTATUS_WIN_STATUS_NO_MORE_MATCHES = 0xC0000273, + MD_NTSTATUS_WIN_STATUS_NOT_A_REPARSE_POINT = 0xC0000275, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_INVALID = 0xC0000276, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_MISMATCH = 0xC0000277, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_DATA_INVALID = 0xC0000278, + MD_NTSTATUS_WIN_STATUS_IO_REPARSE_TAG_NOT_HANDLED = 0xC0000279, + MD_NTSTATUS_WIN_STATUS_PWD_TOO_LONG = 0xC000027A, + MD_NTSTATUS_WIN_STATUS_STOWED_EXCEPTION = 0xC000027B, + MD_NTSTATUS_WIN_STATUS_REPARSE_POINT_NOT_RESOLVED = 0xC0000280, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_IS_A_REPARSE_POINT = 0xC0000281, + MD_NTSTATUS_WIN_STATUS_RANGE_LIST_CONFLICT = 0xC0000282, + MD_NTSTATUS_WIN_STATUS_SOURCE_ELEMENT_EMPTY = 0xC0000283, + MD_NTSTATUS_WIN_STATUS_DESTINATION_ELEMENT_FULL = 0xC0000284, + MD_NTSTATUS_WIN_STATUS_ILLEGAL_ELEMENT_ADDRESS = 0xC0000285, + MD_NTSTATUS_WIN_STATUS_MAGAZINE_NOT_PRESENT = 0xC0000286, + MD_NTSTATUS_WIN_STATUS_REINITIALIZATION_NEEDED = 0xC0000287, + MD_NTSTATUS_WIN_STATUS_ENCRYPTION_FAILED = 0xC000028A, + MD_NTSTATUS_WIN_STATUS_DECRYPTION_FAILED = 0xC000028B, + MD_NTSTATUS_WIN_STATUS_RANGE_NOT_FOUND = 0xC000028C, + MD_NTSTATUS_WIN_STATUS_NO_RECOVERY_POLICY = 0xC000028D, + MD_NTSTATUS_WIN_STATUS_NO_EFS = 0xC000028E, + MD_NTSTATUS_WIN_STATUS_WRONG_EFS = 0xC000028F, + MD_NTSTATUS_WIN_STATUS_NO_USER_KEYS = 0xC0000290, + MD_NTSTATUS_WIN_STATUS_FILE_NOT_ENCRYPTED = 0xC0000291, + MD_NTSTATUS_WIN_STATUS_NOT_EXPORT_FORMAT = 0xC0000292, + MD_NTSTATUS_WIN_STATUS_FILE_ENCRYPTED = 0xC0000293, + MD_NTSTATUS_WIN_STATUS_WMI_GUID_NOT_FOUND = 0xC0000295, + MD_NTSTATUS_WIN_STATUS_WMI_INSTANCE_NOT_FOUND = 0xC0000296, + MD_NTSTATUS_WIN_STATUS_WMI_ITEMID_NOT_FOUND = 0xC0000297, + MD_NTSTATUS_WIN_STATUS_WMI_TRY_AGAIN = 0xC0000298, + MD_NTSTATUS_WIN_STATUS_SHARED_POLICY = 0xC0000299, + MD_NTSTATUS_WIN_STATUS_POLICY_OBJECT_NOT_FOUND = 0xC000029A, + MD_NTSTATUS_WIN_STATUS_POLICY_ONLY_IN_DS = 0xC000029B, + MD_NTSTATUS_WIN_STATUS_VOLUME_NOT_UPGRADED = 0xC000029C, + MD_NTSTATUS_WIN_STATUS_REMOTE_STORAGE_NOT_ACTIVE = 0xC000029D, + MD_NTSTATUS_WIN_STATUS_REMOTE_STORAGE_MEDIA_ERROR = 0xC000029E, + MD_NTSTATUS_WIN_STATUS_NO_TRACKING_SERVICE = 0xC000029F, + MD_NTSTATUS_WIN_STATUS_SERVER_SID_MISMATCH = 0xC00002A0, + MD_NTSTATUS_WIN_STATUS_DS_NO_ATTRIBUTE_OR_VALUE = 0xC00002A1, + MD_NTSTATUS_WIN_STATUS_DS_INVALID_ATTRIBUTE_SYNTAX = 0xC00002A2, + MD_NTSTATUS_WIN_STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED = 0xC00002A3, + MD_NTSTATUS_WIN_STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS = 0xC00002A4, + MD_NTSTATUS_WIN_STATUS_DS_BUSY = 0xC00002A5, + MD_NTSTATUS_WIN_STATUS_DS_UNAVAILABLE = 0xC00002A6, + MD_NTSTATUS_WIN_STATUS_DS_NO_RIDS_ALLOCATED = 0xC00002A7, + MD_NTSTATUS_WIN_STATUS_DS_NO_MORE_RIDS = 0xC00002A8, + MD_NTSTATUS_WIN_STATUS_DS_INCORRECT_ROLE_OWNER = 0xC00002A9, + MD_NTSTATUS_WIN_STATUS_DS_RIDMGR_INIT_ERROR = 0xC00002AA, + MD_NTSTATUS_WIN_STATUS_DS_OBJ_CLASS_VIOLATION = 0xC00002AB, + MD_NTSTATUS_WIN_STATUS_DS_CANT_ON_NON_LEAF = 0xC00002AC, + MD_NTSTATUS_WIN_STATUS_DS_CANT_ON_RDN = 0xC00002AD, + MD_NTSTATUS_WIN_STATUS_DS_CANT_MOD_OBJ_CLASS = 0xC00002AE, + MD_NTSTATUS_WIN_STATUS_DS_CROSS_DOM_MOVE_FAILED = 0xC00002AF, + MD_NTSTATUS_WIN_STATUS_DS_GC_NOT_AVAILABLE = 0xC00002B0, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_SERVICE_REQUIRED = 0xC00002B1, + MD_NTSTATUS_WIN_STATUS_REPARSE_ATTRIBUTE_CONFLICT = 0xC00002B2, + MD_NTSTATUS_WIN_STATUS_CANT_ENABLE_DENY_ONLY = 0xC00002B3, + MD_NTSTATUS_WIN_STATUS_FLOAT_MULTIPLE_FAULTS = 0xC00002B4, + MD_NTSTATUS_WIN_STATUS_FLOAT_MULTIPLE_TRAPS = 0xC00002B5, + MD_NTSTATUS_WIN_STATUS_DEVICE_REMOVED = 0xC00002B6, + MD_NTSTATUS_WIN_STATUS_JOURNAL_DELETE_IN_PROGRESS = 0xC00002B7, + MD_NTSTATUS_WIN_STATUS_JOURNAL_NOT_ACTIVE = 0xC00002B8, + MD_NTSTATUS_WIN_STATUS_NOINTERFACE = 0xC00002B9, + MD_NTSTATUS_WIN_STATUS_DS_RIDMGR_DISABLED = 0xC00002BA, + MD_NTSTATUS_WIN_STATUS_DS_ADMIN_LIMIT_EXCEEDED = 0xC00002C1, + MD_NTSTATUS_WIN_STATUS_DRIVER_FAILED_SLEEP = 0xC00002C2, + MD_NTSTATUS_WIN_STATUS_MUTUAL_AUTHENTICATION_FAILED = 0xC00002C3, + MD_NTSTATUS_WIN_STATUS_CORRUPT_SYSTEM_FILE = 0xC00002C4, + MD_NTSTATUS_WIN_STATUS_DATATYPE_MISALIGNMENT_ERROR = 0xC00002C5, + MD_NTSTATUS_WIN_STATUS_WMI_READ_ONLY = 0xC00002C6, + MD_NTSTATUS_WIN_STATUS_WMI_SET_FAILURE = 0xC00002C7, + MD_NTSTATUS_WIN_STATUS_COMMITMENT_MINIMUM = 0xC00002C8, + MD_NTSTATUS_WIN_STATUS_REG_NAT_CONSUMPTION = 0xC00002C9, + MD_NTSTATUS_WIN_STATUS_TRANSPORT_FULL = 0xC00002CA, + MD_NTSTATUS_WIN_STATUS_DS_SAM_INIT_FAILURE = 0xC00002CB, + MD_NTSTATUS_WIN_STATUS_ONLY_IF_CONNECTED = 0xC00002CC, + MD_NTSTATUS_WIN_STATUS_DS_SENSITIVE_GROUP_VIOLATION = 0xC00002CD, + MD_NTSTATUS_WIN_STATUS_PNP_RESTART_ENUMERATION = 0xC00002CE, + MD_NTSTATUS_WIN_STATUS_JOURNAL_ENTRY_DELETED = 0xC00002CF, + MD_NTSTATUS_WIN_STATUS_DS_CANT_MOD_PRIMARYGROUPID = 0xC00002D0, + MD_NTSTATUS_WIN_STATUS_SYSTEM_IMAGE_BAD_SIGNATURE = 0xC00002D1, + MD_NTSTATUS_WIN_STATUS_PNP_REBOOT_REQUIRED = 0xC00002D2, + MD_NTSTATUS_WIN_STATUS_POWER_STATE_INVALID = 0xC00002D3, + MD_NTSTATUS_WIN_STATUS_DS_INVALID_GROUP_TYPE = 0xC00002D4, + MD_NTSTATUS_WIN_STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN = 0xC00002D5, + MD_NTSTATUS_WIN_STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN = 0xC00002D6, + MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER = 0xC00002D7, + MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER = 0xC00002D8, + MD_NTSTATUS_WIN_STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER = 0xC00002D9, + MD_NTSTATUS_WIN_STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER = 0xC00002DA, + MD_NTSTATUS_WIN_STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER = 0xC00002DB, + MD_NTSTATUS_WIN_STATUS_DS_HAVE_PRIMARY_MEMBERS = 0xC00002DC, + MD_NTSTATUS_WIN_STATUS_WMI_NOT_SUPPORTED = 0xC00002DD, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_POWER = 0xC00002DE, + MD_NTSTATUS_WIN_STATUS_SAM_NEED_BOOTKEY_PASSWORD = 0xC00002DF, + MD_NTSTATUS_WIN_STATUS_SAM_NEED_BOOTKEY_FLOPPY = 0xC00002E0, + MD_NTSTATUS_WIN_STATUS_DS_CANT_START = 0xC00002E1, + MD_NTSTATUS_WIN_STATUS_DS_INIT_FAILURE = 0xC00002E2, + MD_NTSTATUS_WIN_STATUS_SAM_INIT_FAILURE = 0xC00002E3, + MD_NTSTATUS_WIN_STATUS_DS_GC_REQUIRED = 0xC00002E4, + MD_NTSTATUS_WIN_STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY = 0xC00002E5, + MD_NTSTATUS_WIN_STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS = 0xC00002E6, + MD_NTSTATUS_WIN_STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED = 0xC00002E7, + MD_NTSTATUS_WIN_STATUS_MULTIPLE_FAULT_VIOLATION = 0xC00002E8, + MD_NTSTATUS_WIN_STATUS_CURRENT_DOMAIN_NOT_ALLOWED = 0xC00002E9, + MD_NTSTATUS_WIN_STATUS_CANNOT_MAKE = 0xC00002EA, + MD_NTSTATUS_WIN_STATUS_SYSTEM_SHUTDOWN = 0xC00002EB, + MD_NTSTATUS_WIN_STATUS_DS_INIT_FAILURE_CONSOLE = 0xC00002EC, + MD_NTSTATUS_WIN_STATUS_DS_SAM_INIT_FAILURE_CONSOLE = 0xC00002ED, + MD_NTSTATUS_WIN_STATUS_UNFINISHED_CONTEXT_DELETED = 0xC00002EE, + MD_NTSTATUS_WIN_STATUS_NO_TGT_REPLY = 0xC00002EF, + MD_NTSTATUS_WIN_STATUS_OBJECTID_NOT_FOUND = 0xC00002F0, + MD_NTSTATUS_WIN_STATUS_NO_IP_ADDRESSES = 0xC00002F1, + MD_NTSTATUS_WIN_STATUS_WRONG_CREDENTIAL_HANDLE = 0xC00002F2, + MD_NTSTATUS_WIN_STATUS_CRYPTO_SYSTEM_INVALID = 0xC00002F3, + MD_NTSTATUS_WIN_STATUS_MAX_REFERRALS_EXCEEDED = 0xC00002F4, + MD_NTSTATUS_WIN_STATUS_MUST_BE_KDC = 0xC00002F5, + MD_NTSTATUS_WIN_STATUS_STRONG_CRYPTO_NOT_SUPPORTED = 0xC00002F6, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_PRINCIPALS = 0xC00002F7, + MD_NTSTATUS_WIN_STATUS_NO_PA_DATA = 0xC00002F8, + MD_NTSTATUS_WIN_STATUS_PKINIT_NAME_MISMATCH = 0xC00002F9, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_LOGON_REQUIRED = 0xC00002FA, + MD_NTSTATUS_WIN_STATUS_KDC_INVALID_REQUEST = 0xC00002FB, + MD_NTSTATUS_WIN_STATUS_KDC_UNABLE_TO_REFER = 0xC00002FC, + MD_NTSTATUS_WIN_STATUS_KDC_UNKNOWN_ETYPE = 0xC00002FD, + MD_NTSTATUS_WIN_STATUS_SHUTDOWN_IN_PROGRESS = 0xC00002FE, + MD_NTSTATUS_WIN_STATUS_SERVER_SHUTDOWN_IN_PROGRESS = 0xC00002FF, + MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_ON_SBS = 0xC0000300, + MD_NTSTATUS_WIN_STATUS_WMI_GUID_DISCONNECTED = 0xC0000301, + MD_NTSTATUS_WIN_STATUS_WMI_ALREADY_DISABLED = 0xC0000302, + MD_NTSTATUS_WIN_STATUS_WMI_ALREADY_ENABLED = 0xC0000303, + MD_NTSTATUS_WIN_STATUS_MFT_TOO_FRAGMENTED = 0xC0000304, + MD_NTSTATUS_WIN_STATUS_COPY_PROTECTION_FAILURE = 0xC0000305, + MD_NTSTATUS_WIN_STATUS_CSS_AUTHENTICATION_FAILURE = 0xC0000306, + MD_NTSTATUS_WIN_STATUS_CSS_KEY_NOT_PRESENT = 0xC0000307, + MD_NTSTATUS_WIN_STATUS_CSS_KEY_NOT_ESTABLISHED = 0xC0000308, + MD_NTSTATUS_WIN_STATUS_CSS_SCRAMBLED_SECTOR = 0xC0000309, + MD_NTSTATUS_WIN_STATUS_CSS_REGION_MISMATCH = 0xC000030A, + MD_NTSTATUS_WIN_STATUS_CSS_RESETS_EXHAUSTED = 0xC000030B, + MD_NTSTATUS_WIN_STATUS_PASSWORD_CHANGE_REQUIRED = 0xC000030C, + MD_NTSTATUS_WIN_STATUS_PKINIT_FAILURE = 0xC0000320, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_SUBSYSTEM_FAILURE = 0xC0000321, + MD_NTSTATUS_WIN_STATUS_NO_KERB_KEY = 0xC0000322, + MD_NTSTATUS_WIN_STATUS_HOST_DOWN = 0xC0000350, + MD_NTSTATUS_WIN_STATUS_UNSUPPORTED_PREAUTH = 0xC0000351, + MD_NTSTATUS_WIN_STATUS_EFS_ALG_BLOB_TOO_BIG = 0xC0000352, + MD_NTSTATUS_WIN_STATUS_PORT_NOT_SET = 0xC0000353, + MD_NTSTATUS_WIN_STATUS_DEBUGGER_INACTIVE = 0xC0000354, + MD_NTSTATUS_WIN_STATUS_DS_VERSION_CHECK_FAILURE = 0xC0000355, + MD_NTSTATUS_WIN_STATUS_AUDITING_DISABLED = 0xC0000356, + MD_NTSTATUS_WIN_STATUS_PRENT4_MACHINE_ACCOUNT = 0xC0000357, + MD_NTSTATUS_WIN_STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER = 0xC0000358, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_32 = 0xC0000359, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_WIN_64 = 0xC000035A, + MD_NTSTATUS_WIN_STATUS_BAD_BINDINGS = 0xC000035B, + MD_NTSTATUS_WIN_STATUS_NETWORK_SESSION_EXPIRED = 0xC000035C, + MD_NTSTATUS_WIN_STATUS_APPHELP_BLOCK = 0xC000035D, + MD_NTSTATUS_WIN_STATUS_ALL_SIDS_FILTERED = 0xC000035E, + MD_NTSTATUS_WIN_STATUS_NOT_SAFE_MODE_DRIVER = 0xC000035F, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT = 0xC0000361, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_PATH = 0xC0000362, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER = 0xC0000363, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER = 0xC0000364, + MD_NTSTATUS_WIN_STATUS_FAILED_DRIVER_ENTRY = 0xC0000365, + MD_NTSTATUS_WIN_STATUS_DEVICE_ENUMERATION_ERROR = 0xC0000366, + MD_NTSTATUS_WIN_STATUS_MOUNT_POINT_NOT_RESOLVED = 0xC0000368, + MD_NTSTATUS_WIN_STATUS_INVALID_DEVICE_OBJECT_PARAMETER = 0xC0000369, + MD_NTSTATUS_WIN_STATUS_MCA_OCCURED = 0xC000036A, + MD_NTSTATUS_WIN_STATUS_DRIVER_BLOCKED_CRITICAL = 0xC000036B, + MD_NTSTATUS_WIN_STATUS_DRIVER_BLOCKED = 0xC000036C, + MD_NTSTATUS_WIN_STATUS_DRIVER_DATABASE_ERROR = 0xC000036D, + MD_NTSTATUS_WIN_STATUS_SYSTEM_HIVE_TOO_LARGE = 0xC000036E, + MD_NTSTATUS_WIN_STATUS_INVALID_IMPORT_OF_NON_DLL = 0xC000036F, + MD_NTSTATUS_WIN_STATUS_NO_SECRETS = 0xC0000371, + MD_NTSTATUS_WIN_STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY = 0xC0000372, + MD_NTSTATUS_WIN_STATUS_FAILED_STACK_SWITCH = 0xC0000373, + MD_NTSTATUS_WIN_STATUS_HEAP_CORRUPTION = 0xC0000374, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_WRONG_PIN = 0xC0000380, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_CARD_BLOCKED = 0xC0000381, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED = 0xC0000382, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_CARD = 0xC0000383, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_KEY_CONTAINER = 0xC0000384, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_CERTIFICATE = 0xC0000385, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_NO_KEYSET = 0xC0000386, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_IO_ERROR = 0xC0000387, + MD_NTSTATUS_WIN_STATUS_DOWNGRADE_DETECTED = 0xC0000388, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_CERT_REVOKED = 0xC0000389, + MD_NTSTATUS_WIN_STATUS_ISSUING_CA_UNTRUSTED = 0xC000038A, + MD_NTSTATUS_WIN_STATUS_REVOCATION_OFFLINE_C = 0xC000038B, + MD_NTSTATUS_WIN_STATUS_PKINIT_CLIENT_FAILURE = 0xC000038C, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_CERT_EXPIRED = 0xC000038D, + MD_NTSTATUS_WIN_STATUS_DRIVER_FAILED_PRIOR_UNLOAD = 0xC000038E, + MD_NTSTATUS_WIN_STATUS_SMARTCARD_SILENT_CONTEXT = 0xC000038F, + MD_NTSTATUS_WIN_STATUS_PER_USER_TRUST_QUOTA_EXCEEDED = 0xC0000401, + MD_NTSTATUS_WIN_STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED = 0xC0000402, + MD_NTSTATUS_WIN_STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED = 0xC0000403, + MD_NTSTATUS_WIN_STATUS_DS_NAME_NOT_UNIQUE = 0xC0000404, + MD_NTSTATUS_WIN_STATUS_DS_DUPLICATE_ID_FOUND = 0xC0000405, + MD_NTSTATUS_WIN_STATUS_DS_GROUP_CONVERSION_ERROR = 0xC0000406, + MD_NTSTATUS_WIN_STATUS_VOLSNAP_PREPARE_HIBERNATE = 0xC0000407, + MD_NTSTATUS_WIN_STATUS_USER2USER_REQUIRED = 0xC0000408, + MD_NTSTATUS_WIN_STATUS_STACK_BUFFER_OVERRUN = 0xC0000409, + MD_NTSTATUS_WIN_STATUS_NO_S4U_PROT_SUPPORT = 0xC000040A, + MD_NTSTATUS_WIN_STATUS_CROSSREALM_DELEGATION_FAILURE = 0xC000040B, + MD_NTSTATUS_WIN_STATUS_REVOCATION_OFFLINE_KDC = 0xC000040C, + MD_NTSTATUS_WIN_STATUS_ISSUING_CA_UNTRUSTED_KDC = 0xC000040D, + MD_NTSTATUS_WIN_STATUS_KDC_CERT_EXPIRED = 0xC000040E, + MD_NTSTATUS_WIN_STATUS_KDC_CERT_REVOKED = 0xC000040F, + MD_NTSTATUS_WIN_STATUS_PARAMETER_QUOTA_EXCEEDED = 0xC0000410, + MD_NTSTATUS_WIN_STATUS_HIBERNATION_FAILURE = 0xC0000411, + MD_NTSTATUS_WIN_STATUS_DELAY_LOAD_FAILED = 0xC0000412, + MD_NTSTATUS_WIN_STATUS_AUTHENTICATION_FIREWALL_FAILED = 0xC0000413, + MD_NTSTATUS_WIN_STATUS_VDM_DISALLOWED = 0xC0000414, + MD_NTSTATUS_WIN_STATUS_HUNG_DISPLAY_DRIVER_THREAD = 0xC0000415, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE = 0xC0000416, + MD_NTSTATUS_WIN_STATUS_INVALID_CRUNTIME_PARAMETER = 0xC0000417, + MD_NTSTATUS_WIN_STATUS_NTLM_BLOCKED = 0xC0000418, + MD_NTSTATUS_WIN_STATUS_DS_SRC_SID_EXISTS_IN_FOREST = 0xC0000419, + MD_NTSTATUS_WIN_STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST = 0xC000041A, + MD_NTSTATUS_WIN_STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST = 0xC000041B, + MD_NTSTATUS_WIN_STATUS_INVALID_USER_PRINCIPAL_NAME = 0xC000041C, + MD_NTSTATUS_WIN_STATUS_FATAL_USER_CALLBACK_EXCEPTION = 0xC000041D, + MD_NTSTATUS_WIN_STATUS_ASSERTION_FAILURE = 0xC0000420, + MD_NTSTATUS_WIN_STATUS_VERIFIER_STOP = 0xC0000421, + MD_NTSTATUS_WIN_STATUS_CALLBACK_POP_STACK = 0xC0000423, + MD_NTSTATUS_WIN_STATUS_INCOMPATIBLE_DRIVER_BLOCKED = 0xC0000424, + MD_NTSTATUS_WIN_STATUS_HIVE_UNLOADED = 0xC0000425, + MD_NTSTATUS_WIN_STATUS_COMPRESSION_DISABLED = 0xC0000426, + MD_NTSTATUS_WIN_STATUS_FILE_SYSTEM_LIMITATION = 0xC0000427, + MD_NTSTATUS_WIN_STATUS_INVALID_IMAGE_HASH = 0xC0000428, + MD_NTSTATUS_WIN_STATUS_NOT_CAPABLE = 0xC0000429, + MD_NTSTATUS_WIN_STATUS_REQUEST_OUT_OF_SEQUENCE = 0xC000042A, + MD_NTSTATUS_WIN_STATUS_IMPLEMENTATION_LIMIT = 0xC000042B, + MD_NTSTATUS_WIN_STATUS_ELEVATION_REQUIRED = 0xC000042C, + MD_NTSTATUS_WIN_STATUS_NO_SECURITY_CONTEXT = 0xC000042D, + MD_NTSTATUS_WIN_STATUS_PKU2U_CERT_FAILURE = 0xC000042F, + MD_NTSTATUS_WIN_STATUS_BEYOND_VDL = 0xC0000432, + MD_NTSTATUS_WIN_STATUS_ENCOUNTERED_WRITE_IN_PROGRESS = 0xC0000433, + MD_NTSTATUS_WIN_STATUS_PTE_CHANGED = 0xC0000434, + MD_NTSTATUS_WIN_STATUS_PURGE_FAILED = 0xC0000435, + MD_NTSTATUS_WIN_STATUS_CRED_REQUIRES_CONFIRMATION = 0xC0000440, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE = 0xC0000441, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER = 0xC0000442, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE = 0xC0000443, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE = 0xC0000444, + MD_NTSTATUS_WIN_STATUS_CS_ENCRYPTION_FILE_NOT_CSE = 0xC0000445, + MD_NTSTATUS_WIN_STATUS_INVALID_LABEL = 0xC0000446, + MD_NTSTATUS_WIN_STATUS_DRIVER_PROCESS_TERMINATED = 0xC0000450, + MD_NTSTATUS_WIN_STATUS_AMBIGUOUS_SYSTEM_DEVICE = 0xC0000451, + MD_NTSTATUS_WIN_STATUS_SYSTEM_DEVICE_NOT_FOUND = 0xC0000452, + MD_NTSTATUS_WIN_STATUS_RESTART_BOOT_APPLICATION = 0xC0000453, + MD_NTSTATUS_WIN_STATUS_INSUFFICIENT_NVRAM_RESOURCES = 0xC0000454, + MD_NTSTATUS_WIN_STATUS_INVALID_SESSION = 0xC0000455, + MD_NTSTATUS_WIN_STATUS_THREAD_ALREADY_IN_SESSION = 0xC0000456, + MD_NTSTATUS_WIN_STATUS_THREAD_NOT_IN_SESSION = 0xC0000457, + MD_NTSTATUS_WIN_STATUS_INVALID_WEIGHT = 0xC0000458, + MD_NTSTATUS_WIN_STATUS_REQUEST_PAUSED = 0xC0000459, + MD_NTSTATUS_WIN_STATUS_NO_RANGES_PROCESSED = 0xC0000460, + MD_NTSTATUS_WIN_STATUS_DISK_RESOURCES_EXHAUSTED = 0xC0000461, + MD_NTSTATUS_WIN_STATUS_NEEDS_REMEDIATION = 0xC0000462, + MD_NTSTATUS_WIN_STATUS_DEVICE_FEATURE_NOT_SUPPORTED = 0xC0000463, + MD_NTSTATUS_WIN_STATUS_DEVICE_UNREACHABLE = 0xC0000464, + MD_NTSTATUS_WIN_STATUS_INVALID_TOKEN = 0xC0000465, + MD_NTSTATUS_WIN_STATUS_SERVER_UNAVAILABLE = 0xC0000466, + MD_NTSTATUS_WIN_STATUS_FILE_NOT_AVAILABLE = 0xC0000467, + MD_NTSTATUS_WIN_STATUS_DEVICE_INSUFFICIENT_RESOURCES = 0xC0000468, + MD_NTSTATUS_WIN_STATUS_PACKAGE_UPDATING = 0xC0000469, + MD_NTSTATUS_WIN_STATUS_NOT_READ_FROM_COPY = 0xC000046A, + MD_NTSTATUS_WIN_STATUS_FT_WRITE_FAILURE = 0xC000046B, + MD_NTSTATUS_WIN_STATUS_FT_DI_SCAN_REQUIRED = 0xC000046C, + MD_NTSTATUS_WIN_STATUS_OBJECT_NOT_EXTERNALLY_BACKED = 0xC000046D, + MD_NTSTATUS_WIN_STATUS_EXTERNAL_BACKING_PROVIDER_UNKNOWN = 0xC000046E, + MD_NTSTATUS_WIN_STATUS_DATA_CHECKSUM_ERROR = 0xC0000470, + MD_NTSTATUS_WIN_STATUS_INTERMIXED_KERNEL_EA_OPERATION = 0xC0000471, + MD_NTSTATUS_WIN_STATUS_TRIM_READ_ZERO_NOT_SUPPORTED = 0xC0000472, + MD_NTSTATUS_WIN_STATUS_TOO_MANY_SEGMENT_DESCRIPTORS = 0xC0000473, + MD_NTSTATUS_WIN_STATUS_INVALID_OFFSET_ALIGNMENT = 0xC0000474, + MD_NTSTATUS_WIN_STATUS_INVALID_FIELD_IN_PARAMETER_LIST = 0xC0000475, + MD_NTSTATUS_WIN_STATUS_OPERATION_IN_PROGRESS = 0xC0000476, + MD_NTSTATUS_WIN_STATUS_INVALID_INITIATOR_TARGET_PATH = 0xC0000477, + MD_NTSTATUS_WIN_STATUS_SCRUB_DATA_DISABLED = 0xC0000478, + MD_NTSTATUS_WIN_STATUS_NOT_REDUNDANT_STORAGE = 0xC0000479, + MD_NTSTATUS_WIN_STATUS_RESIDENT_FILE_NOT_SUPPORTED = 0xC000047A, + MD_NTSTATUS_WIN_STATUS_COMPRESSED_FILE_NOT_SUPPORTED = 0xC000047B, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_SUPPORTED = 0xC000047C, + MD_NTSTATUS_WIN_STATUS_IO_OPERATION_TIMEOUT = 0xC000047D, + MD_NTSTATUS_WIN_STATUS_SYSTEM_NEEDS_REMEDIATION = 0xC000047E, + MD_NTSTATUS_WIN_STATUS_APPX_INTEGRITY_FAILURE_CLR_NGEN = 0xC000047F, + MD_NTSTATUS_WIN_STATUS_SHARE_UNAVAILABLE = 0xC0000480, + MD_NTSTATUS_WIN_STATUS_APISET_NOT_HOSTED = 0xC0000481, + MD_NTSTATUS_WIN_STATUS_APISET_NOT_PRESENT = 0xC0000482, + MD_NTSTATUS_WIN_STATUS_DEVICE_HARDWARE_ERROR = 0xC0000483, + MD_NTSTATUS_WIN_STATUS_INVALID_TASK_NAME = 0xC0000500, + MD_NTSTATUS_WIN_STATUS_INVALID_TASK_INDEX = 0xC0000501, + MD_NTSTATUS_WIN_STATUS_THREAD_ALREADY_IN_TASK = 0xC0000502, + MD_NTSTATUS_WIN_STATUS_CALLBACK_BYPASS = 0xC0000503, + MD_NTSTATUS_WIN_STATUS_UNDEFINED_SCOPE = 0xC0000504, + MD_NTSTATUS_WIN_STATUS_INVALID_CAP = 0xC0000505, + MD_NTSTATUS_WIN_STATUS_NOT_GUI_PROCESS = 0xC0000506, + MD_NTSTATUS_WIN_STATUS_FAIL_FAST_EXCEPTION = 0xC0000602, + MD_NTSTATUS_WIN_STATUS_IMAGE_CERT_REVOKED = 0xC0000603, + MD_NTSTATUS_WIN_STATUS_DYNAMIC_CODE_BLOCKED = 0xC0000604, + MD_NTSTATUS_WIN_STATUS_PORT_CLOSED = 0xC0000700, + MD_NTSTATUS_WIN_STATUS_MESSAGE_LOST = 0xC0000701, + MD_NTSTATUS_WIN_STATUS_INVALID_MESSAGE = 0xC0000702, + MD_NTSTATUS_WIN_STATUS_REQUEST_CANCELED = 0xC0000703, + MD_NTSTATUS_WIN_STATUS_RECURSIVE_DISPATCH = 0xC0000704, + MD_NTSTATUS_WIN_STATUS_LPC_RECEIVE_BUFFER_EXPECTED = 0xC0000705, + MD_NTSTATUS_WIN_STATUS_LPC_INVALID_CONNECTION_USAGE = 0xC0000706, + MD_NTSTATUS_WIN_STATUS_LPC_REQUESTS_NOT_ALLOWED = 0xC0000707, + MD_NTSTATUS_WIN_STATUS_RESOURCE_IN_USE = 0xC0000708, + MD_NTSTATUS_WIN_STATUS_HARDWARE_MEMORY_ERROR = 0xC0000709, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_HANDLE_EXCEPTION = 0xC000070A, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED = 0xC000070B, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED = 0xC000070C, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED = 0xC000070D, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED = 0xC000070E, + MD_NTSTATUS_WIN_STATUS_THREADPOOL_RELEASED_DURING_OPERATION = 0xC000070F, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING = 0xC0000710, + MD_NTSTATUS_WIN_STATUS_APC_RETURNED_WHILE_IMPERSONATING = 0xC0000711, + MD_NTSTATUS_WIN_STATUS_PROCESS_IS_PROTECTED = 0xC0000712, + MD_NTSTATUS_WIN_STATUS_MCA_EXCEPTION = 0xC0000713, + MD_NTSTATUS_WIN_STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE = 0xC0000714, + MD_NTSTATUS_WIN_STATUS_SYMLINK_CLASS_DISABLED = 0xC0000715, + MD_NTSTATUS_WIN_STATUS_INVALID_IDN_NORMALIZATION = 0xC0000716, + MD_NTSTATUS_WIN_STATUS_NO_UNICODE_TRANSLATION = 0xC0000717, + MD_NTSTATUS_WIN_STATUS_ALREADY_REGISTERED = 0xC0000718, + MD_NTSTATUS_WIN_STATUS_CONTEXT_MISMATCH = 0xC0000719, + MD_NTSTATUS_WIN_STATUS_PORT_ALREADY_HAS_COMPLETION_LIST = 0xC000071A, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_PRIORITY = 0xC000071B, + MD_NTSTATUS_WIN_STATUS_INVALID_THREAD = 0xC000071C, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_TRANSACTION = 0xC000071D, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_LDR_LOCK = 0xC000071E, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_LANG = 0xC000071F, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_PRI_BACK = 0xC0000720, + MD_NTSTATUS_WIN_STATUS_CALLBACK_RETURNED_THREAD_AFFINITY = 0xC0000721, + MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_DISABLED = 0xC0000800, + MD_NTSTATUS_WIN_STATUS_DS_DOMAIN_RENAME_IN_PROGRESS = 0xC0000801, + MD_NTSTATUS_WIN_STATUS_DISK_QUOTA_EXCEEDED = 0xC0000802, + MD_NTSTATUS_WIN_STATUS_CONTENT_BLOCKED = 0xC0000804, + MD_NTSTATUS_WIN_STATUS_BAD_CLUSTERS = 0xC0000805, + MD_NTSTATUS_WIN_STATUS_VOLUME_DIRTY = 0xC0000806, + MD_NTSTATUS_WIN_STATUS_DISK_REPAIR_UNSUCCESSFUL = 0xC0000808, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_OVERFULL = 0xC0000809, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_CORRUPTED = 0xC000080A, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_UNAVAILABLE = 0xC000080B, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_DELETED_FULL = 0xC000080C, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_CLEARED = 0xC000080D, + MD_NTSTATUS_WIN_STATUS_ORPHAN_NAME_EXHAUSTED = 0xC000080E, + MD_NTSTATUS_WIN_STATUS_PROACTIVE_SCAN_IN_PROGRESS = 0xC000080F, + MD_NTSTATUS_WIN_STATUS_ENCRYPTED_IO_NOT_POSSIBLE = 0xC0000810, + MD_NTSTATUS_WIN_STATUS_CORRUPT_LOG_UPLEVEL_RECORDS = 0xC0000811, + MD_NTSTATUS_WIN_STATUS_FILE_CHECKED_OUT = 0xC0000901, + MD_NTSTATUS_WIN_STATUS_CHECKOUT_REQUIRED = 0xC0000902, + MD_NTSTATUS_WIN_STATUS_BAD_FILE_TYPE = 0xC0000903, + MD_NTSTATUS_WIN_STATUS_FILE_TOO_LARGE = 0xC0000904, + MD_NTSTATUS_WIN_STATUS_FORMS_AUTH_REQUIRED = 0xC0000905, + MD_NTSTATUS_WIN_STATUS_VIRUS_INFECTED = 0xC0000906, + MD_NTSTATUS_WIN_STATUS_VIRUS_DELETED = 0xC0000907, + MD_NTSTATUS_WIN_STATUS_BAD_MCFG_TABLE = 0xC0000908, + MD_NTSTATUS_WIN_STATUS_CANNOT_BREAK_OPLOCK = 0xC0000909, + MD_NTSTATUS_WIN_STATUS_BAD_KEY = 0xC000090A, + MD_NTSTATUS_WIN_STATUS_BAD_DATA = 0xC000090B, + MD_NTSTATUS_WIN_STATUS_NO_KEY = 0xC000090C, + MD_NTSTATUS_WIN_STATUS_FILE_HANDLE_REVOKED = 0xC0000910, + MD_NTSTATUS_WIN_STATUS_WOW_ASSERTION = 0xC0009898, + MD_NTSTATUS_WIN_STATUS_INVALID_SIGNATURE = 0xC000A000, + MD_NTSTATUS_WIN_STATUS_HMAC_NOT_SUPPORTED = 0xC000A001, + MD_NTSTATUS_WIN_STATUS_AUTH_TAG_MISMATCH = 0xC000A002, + MD_NTSTATUS_WIN_STATUS_INVALID_STATE_TRANSITION = 0xC000A003, + MD_NTSTATUS_WIN_STATUS_INVALID_KERNEL_INFO_VERSION = 0xC000A004, + MD_NTSTATUS_WIN_STATUS_INVALID_PEP_INFO_VERSION = 0xC000A005, + MD_NTSTATUS_WIN_STATUS_IPSEC_QUEUE_OVERFLOW = 0xC000A010, + MD_NTSTATUS_WIN_STATUS_ND_QUEUE_OVERFLOW = 0xC000A011, + MD_NTSTATUS_WIN_STATUS_HOPLIMIT_EXCEEDED = 0xC000A012, + MD_NTSTATUS_WIN_STATUS_PROTOCOL_NOT_SUPPORTED = 0xC000A013, + MD_NTSTATUS_WIN_STATUS_FASTPATH_REJECTED = 0xC000A014, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED = 0xC000A080, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR = 0xC000A081, + MD_NTSTATUS_WIN_STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR = 0xC000A082, + MD_NTSTATUS_WIN_STATUS_XML_PARSE_ERROR = 0xC000A083, + MD_NTSTATUS_WIN_STATUS_XMLDSIG_ERROR = 0xC000A084, + MD_NTSTATUS_WIN_STATUS_WRONG_COMPARTMENT = 0xC000A085, + MD_NTSTATUS_WIN_STATUS_AUTHIP_FAILURE = 0xC000A086, + MD_NTSTATUS_WIN_STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS = 0xC000A087, + MD_NTSTATUS_WIN_STATUS_DS_OID_NOT_FOUND = 0xC000A088, + MD_NTSTATUS_WIN_STATUS_INCORRECT_ACCOUNT_TYPE = 0xC000A089, + MD_NTSTATUS_WIN_STATUS_HASH_NOT_SUPPORTED = 0xC000A100, + MD_NTSTATUS_WIN_STATUS_HASH_NOT_PRESENT = 0xC000A101, + MD_NTSTATUS_WIN_STATUS_SECONDARY_IC_PROVIDER_NOT_REGISTERED = 0xC000A121, + MD_NTSTATUS_WIN_STATUS_GPIO_CLIENT_INFORMATION_INVALID = 0xC000A122, + MD_NTSTATUS_WIN_STATUS_GPIO_VERSION_NOT_SUPPORTED = 0xC000A123, + MD_NTSTATUS_WIN_STATUS_GPIO_INVALID_REGISTRATION_PACKET = 0xC000A124, + MD_NTSTATUS_WIN_STATUS_GPIO_OPERATION_DENIED = 0xC000A125, + MD_NTSTATUS_WIN_STATUS_GPIO_INCOMPATIBLE_CONNECT_MODE = 0xC000A126, + MD_NTSTATUS_WIN_STATUS_CANNOT_SWITCH_RUNLEVEL = 0xC000A141, + MD_NTSTATUS_WIN_STATUS_INVALID_RUNLEVEL_SETTING = 0xC000A142, + MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_TIMEOUT = 0xC000A143, + MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_AGENT_TIMEOUT = 0xC000A145, + MD_NTSTATUS_WIN_STATUS_RUNLEVEL_SWITCH_IN_PROGRESS = 0xC000A146, + MD_NTSTATUS_WIN_STATUS_NOT_APPCONTAINER = 0xC000A200, + MD_NTSTATUS_WIN_STATUS_NOT_SUPPORTED_IN_APPCONTAINER = 0xC000A201, + MD_NTSTATUS_WIN_STATUS_INVALID_PACKAGE_SID_LENGTH = 0xC000A202, + MD_NTSTATUS_WIN_STATUS_APP_DATA_NOT_FOUND = 0xC000A281, + MD_NTSTATUS_WIN_STATUS_APP_DATA_EXPIRED = 0xC000A282, + MD_NTSTATUS_WIN_STATUS_APP_DATA_CORRUPT = 0xC000A283, + MD_NTSTATUS_WIN_STATUS_APP_DATA_LIMIT_EXCEEDED = 0xC000A284, + MD_NTSTATUS_WIN_STATUS_APP_DATA_REBOOT_REQUIRED = 0xC000A285, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FLT_NOT_SUPPORTED = 0xC000A2A1, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FLT_NOT_SUPPORTED = 0xC000A2A2, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_READ_FILE_NOT_SUPPORTED = 0xC000A2A3, + MD_NTSTATUS_WIN_STATUS_OFFLOAD_WRITE_FILE_NOT_SUPPORTED = 0xC000A2A4, + MD_NTSTATUS_WIN_DBG_NO_STATE_CHANGE = 0xC0010001, + MD_NTSTATUS_WIN_DBG_APP_NOT_IDLE = 0xC0010002, + MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_BINDING = 0xC0020001, + MD_NTSTATUS_WIN_RPC_NT_WRONG_KIND_OF_BINDING = 0xC0020002, + MD_NTSTATUS_WIN_RPC_NT_INVALID_BINDING = 0xC0020003, + MD_NTSTATUS_WIN_RPC_NT_PROTSEQ_NOT_SUPPORTED = 0xC0020004, + MD_NTSTATUS_WIN_RPC_NT_INVALID_RPC_PROTSEQ = 0xC0020005, + MD_NTSTATUS_WIN_RPC_NT_INVALID_STRING_UUID = 0xC0020006, + MD_NTSTATUS_WIN_RPC_NT_INVALID_ENDPOINT_FORMAT = 0xC0020007, + MD_NTSTATUS_WIN_RPC_NT_INVALID_NET_ADDR = 0xC0020008, + MD_NTSTATUS_WIN_RPC_NT_NO_ENDPOINT_FOUND = 0xC0020009, + MD_NTSTATUS_WIN_RPC_NT_INVALID_TIMEOUT = 0xC002000A, + MD_NTSTATUS_WIN_RPC_NT_OBJECT_NOT_FOUND = 0xC002000B, + MD_NTSTATUS_WIN_RPC_NT_ALREADY_REGISTERED = 0xC002000C, + MD_NTSTATUS_WIN_RPC_NT_TYPE_ALREADY_REGISTERED = 0xC002000D, + MD_NTSTATUS_WIN_RPC_NT_ALREADY_LISTENING = 0xC002000E, + MD_NTSTATUS_WIN_RPC_NT_NO_PROTSEQS_REGISTERED = 0xC002000F, + MD_NTSTATUS_WIN_RPC_NT_NOT_LISTENING = 0xC0020010, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_MGR_TYPE = 0xC0020011, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_IF = 0xC0020012, + MD_NTSTATUS_WIN_RPC_NT_NO_BINDINGS = 0xC0020013, + MD_NTSTATUS_WIN_RPC_NT_NO_PROTSEQS = 0xC0020014, + MD_NTSTATUS_WIN_RPC_NT_CANT_CREATE_ENDPOINT = 0xC0020015, + MD_NTSTATUS_WIN_RPC_NT_OUT_OF_RESOURCES = 0xC0020016, + MD_NTSTATUS_WIN_RPC_NT_SERVER_UNAVAILABLE = 0xC0020017, + MD_NTSTATUS_WIN_RPC_NT_SERVER_TOO_BUSY = 0xC0020018, + MD_NTSTATUS_WIN_RPC_NT_INVALID_NETWORK_OPTIONS = 0xC0020019, + MD_NTSTATUS_WIN_RPC_NT_NO_CALL_ACTIVE = 0xC002001A, + MD_NTSTATUS_WIN_RPC_NT_CALL_FAILED = 0xC002001B, + MD_NTSTATUS_WIN_RPC_NT_CALL_FAILED_DNE = 0xC002001C, + MD_NTSTATUS_WIN_RPC_NT_PROTOCOL_ERROR = 0xC002001D, + MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_TRANS_SYN = 0xC002001F, + MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_TYPE = 0xC0020021, + MD_NTSTATUS_WIN_RPC_NT_INVALID_TAG = 0xC0020022, + MD_NTSTATUS_WIN_RPC_NT_INVALID_BOUND = 0xC0020023, + MD_NTSTATUS_WIN_RPC_NT_NO_ENTRY_NAME = 0xC0020024, + MD_NTSTATUS_WIN_RPC_NT_INVALID_NAME_SYNTAX = 0xC0020025, + MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_NAME_SYNTAX = 0xC0020026, + MD_NTSTATUS_WIN_RPC_NT_UUID_NO_ADDRESS = 0xC0020028, + MD_NTSTATUS_WIN_RPC_NT_DUPLICATE_ENDPOINT = 0xC0020029, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_TYPE = 0xC002002A, + MD_NTSTATUS_WIN_RPC_NT_MAX_CALLS_TOO_SMALL = 0xC002002B, + MD_NTSTATUS_WIN_RPC_NT_STRING_TOO_LONG = 0xC002002C, + MD_NTSTATUS_WIN_RPC_NT_PROTSEQ_NOT_FOUND = 0xC002002D, + MD_NTSTATUS_WIN_RPC_NT_PROCNUM_OUT_OF_RANGE = 0xC002002E, + MD_NTSTATUS_WIN_RPC_NT_BINDING_HAS_NO_AUTH = 0xC002002F, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_SERVICE = 0xC0020030, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHN_LEVEL = 0xC0020031, + MD_NTSTATUS_WIN_RPC_NT_INVALID_AUTH_IDENTITY = 0xC0020032, + MD_NTSTATUS_WIN_RPC_NT_UNKNOWN_AUTHZ_SERVICE = 0xC0020033, + MD_NTSTATUS_WIN_EPT_NT_INVALID_ENTRY = 0xC0020034, + MD_NTSTATUS_WIN_EPT_NT_CANT_PERFORM_OP = 0xC0020035, + MD_NTSTATUS_WIN_EPT_NT_NOT_REGISTERED = 0xC0020036, + MD_NTSTATUS_WIN_RPC_NT_NOTHING_TO_EXPORT = 0xC0020037, + MD_NTSTATUS_WIN_RPC_NT_INCOMPLETE_NAME = 0xC0020038, + MD_NTSTATUS_WIN_RPC_NT_INVALID_VERS_OPTION = 0xC0020039, + MD_NTSTATUS_WIN_RPC_NT_NO_MORE_MEMBERS = 0xC002003A, + MD_NTSTATUS_WIN_RPC_NT_NOT_ALL_OBJS_UNEXPORTED = 0xC002003B, + MD_NTSTATUS_WIN_RPC_NT_INTERFACE_NOT_FOUND = 0xC002003C, + MD_NTSTATUS_WIN_RPC_NT_ENTRY_ALREADY_EXISTS = 0xC002003D, + MD_NTSTATUS_WIN_RPC_NT_ENTRY_NOT_FOUND = 0xC002003E, + MD_NTSTATUS_WIN_RPC_NT_NAME_SERVICE_UNAVAILABLE = 0xC002003F, + MD_NTSTATUS_WIN_RPC_NT_INVALID_NAF_ID = 0xC0020040, + MD_NTSTATUS_WIN_RPC_NT_CANNOT_SUPPORT = 0xC0020041, + MD_NTSTATUS_WIN_RPC_NT_NO_CONTEXT_AVAILABLE = 0xC0020042, + MD_NTSTATUS_WIN_RPC_NT_INTERNAL_ERROR = 0xC0020043, + MD_NTSTATUS_WIN_RPC_NT_ZERO_DIVIDE = 0xC0020044, + MD_NTSTATUS_WIN_RPC_NT_ADDRESS_ERROR = 0xC0020045, + MD_NTSTATUS_WIN_RPC_NT_FP_DIV_ZERO = 0xC0020046, + MD_NTSTATUS_WIN_RPC_NT_FP_UNDERFLOW = 0xC0020047, + MD_NTSTATUS_WIN_RPC_NT_FP_OVERFLOW = 0xC0020048, + MD_NTSTATUS_WIN_RPC_NT_CALL_IN_PROGRESS = 0xC0020049, + MD_NTSTATUS_WIN_RPC_NT_NO_MORE_BINDINGS = 0xC002004A, + MD_NTSTATUS_WIN_RPC_NT_GROUP_MEMBER_NOT_FOUND = 0xC002004B, + MD_NTSTATUS_WIN_EPT_NT_CANT_CREATE = 0xC002004C, + MD_NTSTATUS_WIN_RPC_NT_INVALID_OBJECT = 0xC002004D, + MD_NTSTATUS_WIN_RPC_NT_NO_INTERFACES = 0xC002004F, + MD_NTSTATUS_WIN_RPC_NT_CALL_CANCELLED = 0xC0020050, + MD_NTSTATUS_WIN_RPC_NT_BINDING_INCOMPLETE = 0xC0020051, + MD_NTSTATUS_WIN_RPC_NT_COMM_FAILURE = 0xC0020052, + MD_NTSTATUS_WIN_RPC_NT_UNSUPPORTED_AUTHN_LEVEL = 0xC0020053, + MD_NTSTATUS_WIN_RPC_NT_NO_PRINC_NAME = 0xC0020054, + MD_NTSTATUS_WIN_RPC_NT_NOT_RPC_ERROR = 0xC0020055, + MD_NTSTATUS_WIN_RPC_NT_SEC_PKG_ERROR = 0xC0020057, + MD_NTSTATUS_WIN_RPC_NT_NOT_CANCELLED = 0xC0020058, + MD_NTSTATUS_WIN_RPC_NT_INVALID_ASYNC_HANDLE = 0xC0020062, + MD_NTSTATUS_WIN_RPC_NT_INVALID_ASYNC_CALL = 0xC0020063, + MD_NTSTATUS_WIN_RPC_NT_PROXY_ACCESS_DENIED = 0xC0020064, + MD_NTSTATUS_WIN_RPC_NT_COOKIE_AUTH_FAILED = 0xC0020065, + MD_NTSTATUS_WIN_RPC_NT_NO_MORE_ENTRIES = 0xC0030001, + MD_NTSTATUS_WIN_RPC_NT_SS_CHAR_TRANS_OPEN_FAIL = 0xC0030002, + MD_NTSTATUS_WIN_RPC_NT_SS_CHAR_TRANS_SHORT_FILE = 0xC0030003, + MD_NTSTATUS_WIN_RPC_NT_SS_IN_NULL_CONTEXT = 0xC0030004, + MD_NTSTATUS_WIN_RPC_NT_SS_CONTEXT_MISMATCH = 0xC0030005, + MD_NTSTATUS_WIN_RPC_NT_SS_CONTEXT_DAMAGED = 0xC0030006, + MD_NTSTATUS_WIN_RPC_NT_SS_HANDLES_MISMATCH = 0xC0030007, + MD_NTSTATUS_WIN_RPC_NT_SS_CANNOT_GET_CALL_HANDLE = 0xC0030008, + MD_NTSTATUS_WIN_RPC_NT_NULL_REF_POINTER = 0xC0030009, + MD_NTSTATUS_WIN_RPC_NT_ENUM_VALUE_OUT_OF_RANGE = 0xC003000A, + MD_NTSTATUS_WIN_RPC_NT_BYTE_COUNT_TOO_SMALL = 0xC003000B, + MD_NTSTATUS_WIN_RPC_NT_BAD_STUB_DATA = 0xC003000C, + MD_NTSTATUS_WIN_RPC_NT_INVALID_ES_ACTION = 0xC0030059, + MD_NTSTATUS_WIN_RPC_NT_WRONG_ES_VERSION = 0xC003005A, + MD_NTSTATUS_WIN_RPC_NT_WRONG_STUB_VERSION = 0xC003005B, + MD_NTSTATUS_WIN_RPC_NT_INVALID_PIPE_OBJECT = 0xC003005C, + MD_NTSTATUS_WIN_RPC_NT_INVALID_PIPE_OPERATION = 0xC003005D, + MD_NTSTATUS_WIN_RPC_NT_WRONG_PIPE_VERSION = 0xC003005E, + MD_NTSTATUS_WIN_RPC_NT_PIPE_CLOSED = 0xC003005F, + MD_NTSTATUS_WIN_RPC_NT_PIPE_DISCIPLINE_ERROR = 0xC0030060, + MD_NTSTATUS_WIN_RPC_NT_PIPE_EMPTY = 0xC0030061, + MD_NTSTATUS_WIN_STATUS_PNP_BAD_MPS_TABLE = 0xC0040035, + MD_NTSTATUS_WIN_STATUS_PNP_TRANSLATION_FAILED = 0xC0040036, + MD_NTSTATUS_WIN_STATUS_PNP_IRQ_TRANSLATION_FAILED = 0xC0040037, + MD_NTSTATUS_WIN_STATUS_PNP_INVALID_ID = 0xC0040038, + MD_NTSTATUS_WIN_STATUS_IO_REISSUE_AS_CACHED = 0xC0040039, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NAME_INVALID = 0xC00A0001, + MD_NTSTATUS_WIN_STATUS_CTX_INVALID_PD = 0xC00A0002, + MD_NTSTATUS_WIN_STATUS_CTX_PD_NOT_FOUND = 0xC00A0003, + MD_NTSTATUS_WIN_STATUS_CTX_CLOSE_PENDING = 0xC00A0006, + MD_NTSTATUS_WIN_STATUS_CTX_NO_OUTBUF = 0xC00A0007, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_INF_NOT_FOUND = 0xC00A0008, + MD_NTSTATUS_WIN_STATUS_CTX_INVALID_MODEMNAME = 0xC00A0009, + MD_NTSTATUS_WIN_STATUS_CTX_RESPONSE_ERROR = 0xC00A000A, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_TIMEOUT = 0xC00A000B, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_NO_CARRIER = 0xC00A000C, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE = 0xC00A000D, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_BUSY = 0xC00A000E, + MD_NTSTATUS_WIN_STATUS_CTX_MODEM_RESPONSE_VOICE = 0xC00A000F, + MD_NTSTATUS_WIN_STATUS_CTX_TD_ERROR = 0xC00A0010, + MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_CLIENT_INVALID = 0xC00A0012, + MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_NOT_AVAILABLE = 0xC00A0013, + MD_NTSTATUS_WIN_STATUS_CTX_LICENSE_EXPIRED = 0xC00A0014, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NOT_FOUND = 0xC00A0015, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_NAME_COLLISION = 0xC00A0016, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_BUSY = 0xC00A0017, + MD_NTSTATUS_WIN_STATUS_CTX_BAD_VIDEO_MODE = 0xC00A0018, + MD_NTSTATUS_WIN_STATUS_CTX_GRAPHICS_INVALID = 0xC00A0022, + MD_NTSTATUS_WIN_STATUS_CTX_NOT_CONSOLE = 0xC00A0024, + MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_QUERY_TIMEOUT = 0xC00A0026, + MD_NTSTATUS_WIN_STATUS_CTX_CONSOLE_DISCONNECT = 0xC00A0027, + MD_NTSTATUS_WIN_STATUS_CTX_CONSOLE_CONNECT = 0xC00A0028, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_DENIED = 0xC00A002A, + MD_NTSTATUS_WIN_STATUS_CTX_WINSTATION_ACCESS_DENIED = 0xC00A002B, + MD_NTSTATUS_WIN_STATUS_CTX_INVALID_WD = 0xC00A002E, + MD_NTSTATUS_WIN_STATUS_CTX_WD_NOT_FOUND = 0xC00A002F, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_INVALID = 0xC00A0030, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_DISABLED = 0xC00A0031, + MD_NTSTATUS_WIN_STATUS_RDP_PROTOCOL_ERROR = 0xC00A0032, + MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_LICENSE_NOT_SET = 0xC00A0033, + MD_NTSTATUS_WIN_STATUS_CTX_CLIENT_LICENSE_IN_USE = 0xC00A0034, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_ENDED_BY_MODE_CHANGE = 0xC00A0035, + MD_NTSTATUS_WIN_STATUS_CTX_SHADOW_NOT_RUNNING = 0xC00A0036, + MD_NTSTATUS_WIN_STATUS_CTX_LOGON_DISABLED = 0xC00A0037, + MD_NTSTATUS_WIN_STATUS_CTX_SECURITY_LAYER_ERROR = 0xC00A0038, + MD_NTSTATUS_WIN_STATUS_TS_INCOMPATIBLE_SESSIONS = 0xC00A0039, + MD_NTSTATUS_WIN_STATUS_TS_VIDEO_SUBSYSTEM_ERROR = 0xC00A003A, + MD_NTSTATUS_WIN_STATUS_MUI_FILE_NOT_FOUND = 0xC00B0001, + MD_NTSTATUS_WIN_STATUS_MUI_INVALID_FILE = 0xC00B0002, + MD_NTSTATUS_WIN_STATUS_MUI_INVALID_RC_CONFIG = 0xC00B0003, + MD_NTSTATUS_WIN_STATUS_MUI_INVALID_LOCALE_NAME = 0xC00B0004, + MD_NTSTATUS_WIN_STATUS_MUI_INVALID_ULTIMATEFALLBACK_NAME = 0xC00B0005, + MD_NTSTATUS_WIN_STATUS_MUI_FILE_NOT_LOADED = 0xC00B0006, + MD_NTSTATUS_WIN_STATUS_RESOURCE_ENUM_USER_STOP = 0xC00B0007, + MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NODE = 0xC0130001, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_EXISTS = 0xC0130002, + MD_NTSTATUS_WIN_STATUS_CLUSTER_JOIN_IN_PROGRESS = 0xC0130003, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_FOUND = 0xC0130004, + MD_NTSTATUS_WIN_STATUS_CLUSTER_LOCAL_NODE_NOT_FOUND = 0xC0130005, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_EXISTS = 0xC0130006, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_NOT_FOUND = 0xC0130007, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETINTERFACE_EXISTS = 0xC0130008, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETINTERFACE_NOT_FOUND = 0xC0130009, + MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_REQUEST = 0xC013000A, + MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NETWORK_PROVIDER = 0xC013000B, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_DOWN = 0xC013000C, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_UNREACHABLE = 0xC013000D, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_MEMBER = 0xC013000E, + MD_NTSTATUS_WIN_STATUS_CLUSTER_JOIN_NOT_IN_PROGRESS = 0xC013000F, + MD_NTSTATUS_WIN_STATUS_CLUSTER_INVALID_NETWORK = 0xC0130010, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NO_NET_ADAPTERS = 0xC0130011, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_UP = 0xC0130012, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_PAUSED = 0xC0130013, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NODE_NOT_PAUSED = 0xC0130014, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NO_SECURITY_CONTEXT = 0xC0130015, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NETWORK_NOT_INTERNAL = 0xC0130016, + MD_NTSTATUS_WIN_STATUS_CLUSTER_POISONED = 0xC0130017, + MD_NTSTATUS_WIN_STATUS_CLUSTER_NON_CSV_PATH = 0xC0130018, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_NOT_LOCAL = 0xC0130019, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_READ_OPLOCK_BREAK_IN_PROGRESS = 0xC0130020, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_AUTO_PAUSE_ERROR = 0xC0130021, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_REDIRECTED = 0xC0130022, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_NOT_REDIRECTED = 0xC0130023, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING = 0xC0130024, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_SNAPSHOT_CREATION_IN_PROGRESS = 0xC0130025, + MD_NTSTATUS_WIN_STATUS_CLUSTER_CSV_VOLUME_DRAINING_SUCCEEDED_DOWNLEVEL = 0xC0130026, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_OPCODE = 0xC0140001, + MD_NTSTATUS_WIN_STATUS_ACPI_STACK_OVERFLOW = 0xC0140002, + MD_NTSTATUS_WIN_STATUS_ACPI_ASSERT_FAILED = 0xC0140003, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_INDEX = 0xC0140004, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ARGUMENT = 0xC0140005, + MD_NTSTATUS_WIN_STATUS_ACPI_FATAL = 0xC0140006, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_SUPERNAME = 0xC0140007, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ARGTYPE = 0xC0140008, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_OBJTYPE = 0xC0140009, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_TARGETTYPE = 0xC014000A, + MD_NTSTATUS_WIN_STATUS_ACPI_INCORRECT_ARGUMENT_COUNT = 0xC014000B, + MD_NTSTATUS_WIN_STATUS_ACPI_ADDRESS_NOT_MAPPED = 0xC014000C, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_EVENTTYPE = 0xC014000D, + MD_NTSTATUS_WIN_STATUS_ACPI_HANDLER_COLLISION = 0xC014000E, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_DATA = 0xC014000F, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_REGION = 0xC0140010, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_ACCESS_SIZE = 0xC0140011, + MD_NTSTATUS_WIN_STATUS_ACPI_ACQUIRE_GLOBAL_LOCK = 0xC0140012, + MD_NTSTATUS_WIN_STATUS_ACPI_ALREADY_INITIALIZED = 0xC0140013, + MD_NTSTATUS_WIN_STATUS_ACPI_NOT_INITIALIZED = 0xC0140014, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_MUTEX_LEVEL = 0xC0140015, + MD_NTSTATUS_WIN_STATUS_ACPI_MUTEX_NOT_OWNED = 0xC0140016, + MD_NTSTATUS_WIN_STATUS_ACPI_MUTEX_NOT_OWNER = 0xC0140017, + MD_NTSTATUS_WIN_STATUS_ACPI_RS_ACCESS = 0xC0140018, + MD_NTSTATUS_WIN_STATUS_ACPI_INVALID_TABLE = 0xC0140019, + MD_NTSTATUS_WIN_STATUS_ACPI_REG_HANDLER_FAILED = 0xC0140020, + MD_NTSTATUS_WIN_STATUS_ACPI_POWER_REQUEST_FAILED = 0xC0140021, + MD_NTSTATUS_WIN_STATUS_SXS_SECTION_NOT_FOUND = 0xC0150001, + MD_NTSTATUS_WIN_STATUS_SXS_CANT_GEN_ACTCTX = 0xC0150002, + MD_NTSTATUS_WIN_STATUS_SXS_INVALID_ACTCTXDATA_FORMAT = 0xC0150003, + MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_NOT_FOUND = 0xC0150004, + MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_FORMAT_ERROR = 0xC0150005, + MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_PARSE_ERROR = 0xC0150006, + MD_NTSTATUS_WIN_STATUS_SXS_ACTIVATION_CONTEXT_DISABLED = 0xC0150007, + MD_NTSTATUS_WIN_STATUS_SXS_KEY_NOT_FOUND = 0xC0150008, + MD_NTSTATUS_WIN_STATUS_SXS_VERSION_CONFLICT = 0xC0150009, + MD_NTSTATUS_WIN_STATUS_SXS_WRONG_SECTION_TYPE = 0xC015000A, + MD_NTSTATUS_WIN_STATUS_SXS_THREAD_QUERIES_DISABLED = 0xC015000B, + MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_MISSING = 0xC015000C, + MD_NTSTATUS_WIN_STATUS_SXS_PROCESS_DEFAULT_ALREADY_SET = 0xC015000E, + MD_NTSTATUS_WIN_STATUS_SXS_EARLY_DEACTIVATION = 0xC015000F, + MD_NTSTATUS_WIN_STATUS_SXS_INVALID_DEACTIVATION = 0xC0150010, + MD_NTSTATUS_WIN_STATUS_SXS_MULTIPLE_DEACTIVATION = 0xC0150011, + MD_NTSTATUS_WIN_STATUS_SXS_SYSTEM_DEFAULT_ACTIVATION_CONTEXT_EMPTY = 0xC0150012, + MD_NTSTATUS_WIN_STATUS_SXS_PROCESS_TERMINATION_REQUESTED = 0xC0150013, + MD_NTSTATUS_WIN_STATUS_SXS_CORRUPT_ACTIVATION_STACK = 0xC0150014, + MD_NTSTATUS_WIN_STATUS_SXS_CORRUPTION = 0xC0150015, + MD_NTSTATUS_WIN_STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_VALUE = 0xC0150016, + MD_NTSTATUS_WIN_STATUS_SXS_INVALID_IDENTITY_ATTRIBUTE_NAME = 0xC0150017, + MD_NTSTATUS_WIN_STATUS_SXS_IDENTITY_DUPLICATE_ATTRIBUTE = 0xC0150018, + MD_NTSTATUS_WIN_STATUS_SXS_IDENTITY_PARSE_ERROR = 0xC0150019, + MD_NTSTATUS_WIN_STATUS_SXS_COMPONENT_STORE_CORRUPT = 0xC015001A, + MD_NTSTATUS_WIN_STATUS_SXS_FILE_HASH_MISMATCH = 0xC015001B, + MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_IDENTITY_SAME_BUT_CONTENTS_DIFFERENT = 0xC015001C, + MD_NTSTATUS_WIN_STATUS_SXS_IDENTITIES_DIFFERENT = 0xC015001D, + MD_NTSTATUS_WIN_STATUS_SXS_ASSEMBLY_IS_NOT_A_DEPLOYMENT = 0xC015001E, + MD_NTSTATUS_WIN_STATUS_SXS_FILE_NOT_PART_OF_ASSEMBLY = 0xC015001F, + MD_NTSTATUS_WIN_STATUS_ADVANCED_INSTALLER_FAILED = 0xC0150020, + MD_NTSTATUS_WIN_STATUS_XML_ENCODING_MISMATCH = 0xC0150021, + MD_NTSTATUS_WIN_STATUS_SXS_MANIFEST_TOO_BIG = 0xC0150022, + MD_NTSTATUS_WIN_STATUS_SXS_SETTING_NOT_REGISTERED = 0xC0150023, + MD_NTSTATUS_WIN_STATUS_SXS_TRANSACTION_CLOSURE_INCOMPLETE = 0xC0150024, + MD_NTSTATUS_WIN_STATUS_SMI_PRIMITIVE_INSTALLER_FAILED = 0xC0150025, + MD_NTSTATUS_WIN_STATUS_GENERIC_COMMAND_FAILED = 0xC0150026, + MD_NTSTATUS_WIN_STATUS_SXS_FILE_HASH_MISSING = 0xC0150027, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONAL_CONFLICT = 0xC0190001, + MD_NTSTATUS_WIN_STATUS_INVALID_TRANSACTION = 0xC0190002, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ACTIVE = 0xC0190003, + MD_NTSTATUS_WIN_STATUS_TM_INITIALIZATION_FAILED = 0xC0190004, + MD_NTSTATUS_WIN_STATUS_RM_NOT_ACTIVE = 0xC0190005, + MD_NTSTATUS_WIN_STATUS_RM_METADATA_CORRUPT = 0xC0190006, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_JOINED = 0xC0190007, + MD_NTSTATUS_WIN_STATUS_DIRECTORY_NOT_RM = 0xC0190008, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONS_UNSUPPORTED_REMOTE = 0xC019000A, + MD_NTSTATUS_WIN_STATUS_LOG_RESIZE_INVALID_SIZE = 0xC019000B, + MD_NTSTATUS_WIN_STATUS_REMOTE_FILE_VERSION_MISMATCH = 0xC019000C, + MD_NTSTATUS_WIN_STATUS_CRM_PROTOCOL_ALREADY_EXISTS = 0xC019000F, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_PROPAGATION_FAILED = 0xC0190010, + MD_NTSTATUS_WIN_STATUS_CRM_PROTOCOL_NOT_FOUND = 0xC0190011, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_SUPERIOR_EXISTS = 0xC0190012, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_REQUEST_NOT_VALID = 0xC0190013, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_REQUESTED = 0xC0190014, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_ALREADY_ABORTED = 0xC0190015, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_ALREADY_COMMITTED = 0xC0190016, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_INVALID_MARSHALL_BUFFER = 0xC0190017, + MD_NTSTATUS_WIN_STATUS_CURRENT_TRANSACTION_NOT_VALID = 0xC0190018, + MD_NTSTATUS_WIN_STATUS_LOG_GROWTH_FAILED = 0xC0190019, + MD_NTSTATUS_WIN_STATUS_OBJECT_NO_LONGER_EXISTS = 0xC0190021, + MD_NTSTATUS_WIN_STATUS_STREAM_MINIVERSION_NOT_FOUND = 0xC0190022, + MD_NTSTATUS_WIN_STATUS_STREAM_MINIVERSION_NOT_VALID = 0xC0190023, + MD_NTSTATUS_WIN_STATUS_MINIVERSION_INACCESSIBLE_FROM_SPECIFIED_TRANSACTION = 0xC0190024, + MD_NTSTATUS_WIN_STATUS_CANT_OPEN_MINIVERSION_WITH_MODIFY_INTENT = 0xC0190025, + MD_NTSTATUS_WIN_STATUS_CANT_CREATE_MORE_STREAM_MINIVERSIONS = 0xC0190026, + MD_NTSTATUS_WIN_STATUS_HANDLE_NO_LONGER_VALID = 0xC0190028, + MD_NTSTATUS_WIN_STATUS_LOG_CORRUPTION_DETECTED = 0xC0190030, + MD_NTSTATUS_WIN_STATUS_RM_DISCONNECTED = 0xC0190032, + MD_NTSTATUS_WIN_STATUS_ENLISTMENT_NOT_SUPERIOR = 0xC0190033, + MD_NTSTATUS_WIN_STATUS_FILE_IDENTITY_NOT_PERSISTENT = 0xC0190036, + MD_NTSTATUS_WIN_STATUS_CANT_BREAK_TRANSACTIONAL_DEPENDENCY = 0xC0190037, + MD_NTSTATUS_WIN_STATUS_CANT_CROSS_RM_BOUNDARY = 0xC0190038, + MD_NTSTATUS_WIN_STATUS_TXF_DIR_NOT_EMPTY = 0xC0190039, + MD_NTSTATUS_WIN_STATUS_INDOUBT_TRANSACTIONS_EXIST = 0xC019003A, + MD_NTSTATUS_WIN_STATUS_TM_VOLATILE = 0xC019003B, + MD_NTSTATUS_WIN_STATUS_ROLLBACK_TIMER_EXPIRED = 0xC019003C, + MD_NTSTATUS_WIN_STATUS_TXF_ATTRIBUTE_CORRUPT = 0xC019003D, + MD_NTSTATUS_WIN_STATUS_EFS_NOT_ALLOWED_IN_TRANSACTION = 0xC019003E, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONAL_OPEN_NOT_ALLOWED = 0xC019003F, + MD_NTSTATUS_WIN_STATUS_TRANSACTED_MAPPING_UNSUPPORTED_REMOTE = 0xC0190040, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_REQUIRED_PROMOTION = 0xC0190043, + MD_NTSTATUS_WIN_STATUS_CANNOT_EXECUTE_FILE_IN_TRANSACTION = 0xC0190044, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONS_NOT_FROZEN = 0xC0190045, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_FREEZE_IN_PROGRESS = 0xC0190046, + MD_NTSTATUS_WIN_STATUS_NOT_SNAPSHOT_VOLUME = 0xC0190047, + MD_NTSTATUS_WIN_STATUS_NO_SAVEPOINT_WITH_OPEN_FILES = 0xC0190048, + MD_NTSTATUS_WIN_STATUS_SPARSE_NOT_ALLOWED_IN_TRANSACTION = 0xC0190049, + MD_NTSTATUS_WIN_STATUS_TM_IDENTITY_MISMATCH = 0xC019004A, + MD_NTSTATUS_WIN_STATUS_FLOATED_SECTION = 0xC019004B, + MD_NTSTATUS_WIN_STATUS_CANNOT_ACCEPT_TRANSACTED_WORK = 0xC019004C, + MD_NTSTATUS_WIN_STATUS_CANNOT_ABORT_TRANSACTIONS = 0xC019004D, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_FOUND = 0xC019004E, + MD_NTSTATUS_WIN_STATUS_RESOURCEMANAGER_NOT_FOUND = 0xC019004F, + MD_NTSTATUS_WIN_STATUS_ENLISTMENT_NOT_FOUND = 0xC0190050, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_NOT_FOUND = 0xC0190051, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_NOT_ONLINE = 0xC0190052, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_RECOVERY_NAME_COLLISION = 0xC0190053, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ROOT = 0xC0190054, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_OBJECT_EXPIRED = 0xC0190055, + MD_NTSTATUS_WIN_STATUS_COMPRESSION_NOT_ALLOWED_IN_TRANSACTION = 0xC0190056, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_RESPONSE_NOT_ENLISTED = 0xC0190057, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_RECORD_TOO_LONG = 0xC0190058, + MD_NTSTATUS_WIN_STATUS_NO_LINK_TRACKING_IN_TRANSACTION = 0xC0190059, + MD_NTSTATUS_WIN_STATUS_OPERATION_NOT_SUPPORTED_IN_TRANSACTION = 0xC019005A, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_INTEGRITY_VIOLATED = 0xC019005B, + MD_NTSTATUS_WIN_STATUS_TRANSACTIONMANAGER_IDENTITY_MISMATCH = 0xC019005C, + MD_NTSTATUS_WIN_STATUS_RM_CANNOT_BE_FROZEN_FOR_SNAPSHOT = 0xC019005D, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_MUST_WRITETHROUGH = 0xC019005E, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NO_SUPERIOR = 0xC019005F, + MD_NTSTATUS_WIN_STATUS_EXPIRED_HANDLE = 0xC0190060, + MD_NTSTATUS_WIN_STATUS_TRANSACTION_NOT_ENLISTED = 0xC0190061, + MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_INVALID = 0xC01A0001, + MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_PARITY_INVALID = 0xC01A0002, + MD_NTSTATUS_WIN_STATUS_LOG_SECTOR_REMAPPED = 0xC01A0003, + MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_INCOMPLETE = 0xC01A0004, + MD_NTSTATUS_WIN_STATUS_LOG_INVALID_RANGE = 0xC01A0005, + MD_NTSTATUS_WIN_STATUS_LOG_BLOCKS_EXHAUSTED = 0xC01A0006, + MD_NTSTATUS_WIN_STATUS_LOG_READ_CONTEXT_INVALID = 0xC01A0007, + MD_NTSTATUS_WIN_STATUS_LOG_RESTART_INVALID = 0xC01A0008, + MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_VERSION = 0xC01A0009, + MD_NTSTATUS_WIN_STATUS_LOG_BLOCK_INVALID = 0xC01A000A, + MD_NTSTATUS_WIN_STATUS_LOG_READ_MODE_INVALID = 0xC01A000B, + MD_NTSTATUS_WIN_STATUS_LOG_METADATA_CORRUPT = 0xC01A000D, + MD_NTSTATUS_WIN_STATUS_LOG_METADATA_INVALID = 0xC01A000E, + MD_NTSTATUS_WIN_STATUS_LOG_METADATA_INCONSISTENT = 0xC01A000F, + MD_NTSTATUS_WIN_STATUS_LOG_RESERVATION_INVALID = 0xC01A0010, + MD_NTSTATUS_WIN_STATUS_LOG_CANT_DELETE = 0xC01A0011, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_LIMIT_EXCEEDED = 0xC01A0012, + MD_NTSTATUS_WIN_STATUS_LOG_START_OF_LOG = 0xC01A0013, + MD_NTSTATUS_WIN_STATUS_LOG_POLICY_ALREADY_INSTALLED = 0xC01A0014, + MD_NTSTATUS_WIN_STATUS_LOG_POLICY_NOT_INSTALLED = 0xC01A0015, + MD_NTSTATUS_WIN_STATUS_LOG_POLICY_INVALID = 0xC01A0016, + MD_NTSTATUS_WIN_STATUS_LOG_POLICY_CONFLICT = 0xC01A0017, + MD_NTSTATUS_WIN_STATUS_LOG_PINNED_ARCHIVE_TAIL = 0xC01A0018, + MD_NTSTATUS_WIN_STATUS_LOG_RECORD_NONEXISTENT = 0xC01A0019, + MD_NTSTATUS_WIN_STATUS_LOG_RECORDS_RESERVED_INVALID = 0xC01A001A, + MD_NTSTATUS_WIN_STATUS_LOG_SPACE_RESERVED_INVALID = 0xC01A001B, + MD_NTSTATUS_WIN_STATUS_LOG_TAIL_INVALID = 0xC01A001C, + MD_NTSTATUS_WIN_STATUS_LOG_FULL = 0xC01A001D, + MD_NTSTATUS_WIN_STATUS_LOG_MULTIPLEXED = 0xC01A001E, + MD_NTSTATUS_WIN_STATUS_LOG_DEDICATED = 0xC01A001F, + MD_NTSTATUS_WIN_STATUS_LOG_ARCHIVE_NOT_IN_PROGRESS = 0xC01A0020, + MD_NTSTATUS_WIN_STATUS_LOG_ARCHIVE_IN_PROGRESS = 0xC01A0021, + MD_NTSTATUS_WIN_STATUS_LOG_EPHEMERAL = 0xC01A0022, + MD_NTSTATUS_WIN_STATUS_LOG_NOT_ENOUGH_CONTAINERS = 0xC01A0023, + MD_NTSTATUS_WIN_STATUS_LOG_CLIENT_ALREADY_REGISTERED = 0xC01A0024, + MD_NTSTATUS_WIN_STATUS_LOG_CLIENT_NOT_REGISTERED = 0xC01A0025, + MD_NTSTATUS_WIN_STATUS_LOG_FULL_HANDLER_IN_PROGRESS = 0xC01A0026, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_READ_FAILED = 0xC01A0027, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_WRITE_FAILED = 0xC01A0028, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_OPEN_FAILED = 0xC01A0029, + MD_NTSTATUS_WIN_STATUS_LOG_CONTAINER_STATE_INVALID = 0xC01A002A, + MD_NTSTATUS_WIN_STATUS_LOG_STATE_INVALID = 0xC01A002B, + MD_NTSTATUS_WIN_STATUS_LOG_PINNED = 0xC01A002C, + MD_NTSTATUS_WIN_STATUS_LOG_METADATA_FLUSH_FAILED = 0xC01A002D, + MD_NTSTATUS_WIN_STATUS_LOG_INCONSISTENT_SECURITY = 0xC01A002E, + MD_NTSTATUS_WIN_STATUS_LOG_APPENDED_FLUSH_FAILED = 0xC01A002F, + MD_NTSTATUS_WIN_STATUS_LOG_PINNED_RESERVATION = 0xC01A0030, + MD_NTSTATUS_WIN_STATUS_VIDEO_HUNG_DISPLAY_DRIVER_THREAD = 0xC01B00EA, + MD_NTSTATUS_WIN_STATUS_FLT_NO_HANDLER_DEFINED = 0xC01C0001, + MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALREADY_DEFINED = 0xC01C0002, + MD_NTSTATUS_WIN_STATUS_FLT_INVALID_ASYNCHRONOUS_REQUEST = 0xC01C0003, + MD_NTSTATUS_WIN_STATUS_FLT_DISALLOW_FAST_IO = 0xC01C0004, + MD_NTSTATUS_WIN_STATUS_FLT_INVALID_NAME_REQUEST = 0xC01C0005, + MD_NTSTATUS_WIN_STATUS_FLT_NOT_SAFE_TO_POST_OPERATION = 0xC01C0006, + MD_NTSTATUS_WIN_STATUS_FLT_NOT_INITIALIZED = 0xC01C0007, + MD_NTSTATUS_WIN_STATUS_FLT_FILTER_NOT_READY = 0xC01C0008, + MD_NTSTATUS_WIN_STATUS_FLT_POST_OPERATION_CLEANUP = 0xC01C0009, + MD_NTSTATUS_WIN_STATUS_FLT_INTERNAL_ERROR = 0xC01C000A, + MD_NTSTATUS_WIN_STATUS_FLT_DELETING_OBJECT = 0xC01C000B, + MD_NTSTATUS_WIN_STATUS_FLT_MUST_BE_NONPAGED_POOL = 0xC01C000C, + MD_NTSTATUS_WIN_STATUS_FLT_DUPLICATE_ENTRY = 0xC01C000D, + MD_NTSTATUS_WIN_STATUS_FLT_CBDQ_DISABLED = 0xC01C000E, + MD_NTSTATUS_WIN_STATUS_FLT_DO_NOT_ATTACH = 0xC01C000F, + MD_NTSTATUS_WIN_STATUS_FLT_DO_NOT_DETACH = 0xC01C0010, + MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_ALTITUDE_COLLISION = 0xC01C0011, + MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_NAME_COLLISION = 0xC01C0012, + MD_NTSTATUS_WIN_STATUS_FLT_FILTER_NOT_FOUND = 0xC01C0013, + MD_NTSTATUS_WIN_STATUS_FLT_VOLUME_NOT_FOUND = 0xC01C0014, + MD_NTSTATUS_WIN_STATUS_FLT_INSTANCE_NOT_FOUND = 0xC01C0015, + MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALLOCATION_NOT_FOUND = 0xC01C0016, + MD_NTSTATUS_WIN_STATUS_FLT_INVALID_CONTEXT_REGISTRATION = 0xC01C0017, + MD_NTSTATUS_WIN_STATUS_FLT_NAME_CACHE_MISS = 0xC01C0018, + MD_NTSTATUS_WIN_STATUS_FLT_NO_DEVICE_OBJECT = 0xC01C0019, + MD_NTSTATUS_WIN_STATUS_FLT_VOLUME_ALREADY_MOUNTED = 0xC01C001A, + MD_NTSTATUS_WIN_STATUS_FLT_ALREADY_ENLISTED = 0xC01C001B, + MD_NTSTATUS_WIN_STATUS_FLT_CONTEXT_ALREADY_LINKED = 0xC01C001C, + MD_NTSTATUS_WIN_STATUS_FLT_NO_WAITER_FOR_REPLY = 0xC01C0020, + MD_NTSTATUS_WIN_STATUS_FLT_REGISTRATION_BUSY = 0xC01C0023, + MD_NTSTATUS_WIN_STATUS_MONITOR_NO_DESCRIPTOR = 0xC01D0001, + MD_NTSTATUS_WIN_STATUS_MONITOR_UNKNOWN_DESCRIPTOR_FORMAT = 0xC01D0002, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_DESCRIPTOR_CHECKSUM = 0xC01D0003, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_STANDARD_TIMING_BLOCK = 0xC01D0004, + MD_NTSTATUS_WIN_STATUS_MONITOR_WMI_DATABLOCK_REGISTRATION_FAILED = 0xC01D0005, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_SERIAL_NUMBER_MONDSC_BLOCK = 0xC01D0006, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_USER_FRIENDLY_MONDSC_BLOCK = 0xC01D0007, + MD_NTSTATUS_WIN_STATUS_MONITOR_NO_MORE_DESCRIPTOR_DATA = 0xC01D0008, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_DETAILED_TIMING_BLOCK = 0xC01D0009, + MD_NTSTATUS_WIN_STATUS_MONITOR_INVALID_MANUFACTURE_DATE = 0xC01D000A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_EXCLUSIVE_MODE_OWNER = 0xC01E0000, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INSUFFICIENT_DMA_BUFFER = 0xC01E0001, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_DISPLAY_ADAPTER = 0xC01E0002, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_WAS_RESET = 0xC01E0003, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_DRIVER_MODEL = 0xC01E0004, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_MODE_CHANGED = 0xC01E0005, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_OCCLUDED = 0xC01E0006, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_DENIED = 0xC01E0007, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANNOTCOLORCONVERT = 0xC01E0008, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DRIVER_MISMATCH = 0xC01E0009, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_REDIRECTION_DISABLED = 0xC01E000B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PRESENT_UNOCCLUDED = 0xC01E000C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWDC_NOT_AVAILABLE = 0xC01E000D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_WINDOWLESS_PRESENT_DISABLED = 0xC01E000E, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_VIDEO_MEMORY = 0xC01E0100, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_LOCK_MEMORY = 0xC01E0101, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_BUSY = 0xC01E0102, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TOO_MANY_REFERENCES = 0xC01E0103, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TRY_AGAIN_LATER = 0xC01E0104, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TRY_AGAIN_NOW = 0xC01E0105, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_INVALID = 0xC01E0106, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNAVAILABLE = 0xC01E0107, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNSWIZZLING_APERTURE_UNSUPPORTED = 0xC01E0108, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_EVICT_PINNED_ALLOCATION = 0xC01E0109, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_USAGE = 0xC01E0110, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_RENDER_LOCKED_ALLOCATION = 0xC01E0111, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_CLOSED = 0xC01E0112, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_INSTANCE = 0xC01E0113, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ALLOCATION_HANDLE = 0xC01E0114, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_WRONG_ALLOCATION_DEVICE = 0xC01E0115, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ALLOCATION_CONTENT_LOST = 0xC01E0116, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_GPU_EXCEPTION_ON_DEVICE = 0xC01E0200, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY = 0xC01E0300, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_TOPOLOGY_NOT_SUPPORTED = 0xC01E0301, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_TOPOLOGY_CURRENTLY_NOT_SUPPORTED = 0xC01E0302, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN = 0xC01E0303, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE = 0xC01E0304, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET = 0xC01E0305, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_MODALITY_NOT_SUPPORTED = 0xC01E0306, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_SOURCEMODESET = 0xC01E0308, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TARGETMODESET = 0xC01E0309, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_FREQUENCY = 0xC01E030A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_ACTIVE_REGION = 0xC01E030B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_TOTAL_REGION = 0xC01E030C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_SOURCE_MODE = 0xC01E0310, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEO_PRESENT_TARGET_MODE = 0xC01E0311, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PINNED_MODE_MUST_REMAIN_IN_SET = 0xC01E0312, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_ALREADY_IN_TOPOLOGY = 0xC01E0313, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_ALREADY_IN_MODESET = 0xC01E0314, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEOPRESENTSOURCESET = 0xC01E0315, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDEOPRESENTTARGETSET = 0xC01E0316, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_ALREADY_IN_SET = 0xC01E0317, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_ALREADY_IN_SET = 0xC01E0318, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_PRESENT_PATH = 0xC01E0319, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_RECOMMENDED_VIDPN_TOPOLOGY = 0xC01E031A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGESET = 0xC01E031B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE = 0xC01E031C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_FREQUENCYRANGE_NOT_IN_SET = 0xC01E031D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_FREQUENCYRANGE_ALREADY_IN_SET = 0xC01E031F, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_STALE_MODESET = 0xC01E0320, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_SOURCEMODESET = 0xC01E0321, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_SOURCE_MODE = 0xC01E0322, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_RECOMMENDED_FUNCTIONAL_VIDPN = 0xC01E0323, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_ID_MUST_BE_UNIQUE = 0xC01E0324, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_EMPTY_ADAPTER_MONITOR_MODE_SUPPORT_INTERSECTION = 0xC01E0325, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDEO_PRESENT_TARGETS_LESS_THAN_SOURCES = 0xC01E0326, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_NOT_IN_TOPOLOGY = 0xC01E0327, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_SOURCE = 0xC01E0328, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_MUST_HAVE_AT_LEAST_ONE_TARGET = 0xC01E0329, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITORDESCRIPTORSET = 0xC01E032A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITORDESCRIPTOR = 0xC01E032B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_NOT_IN_SET = 0xC01E032C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_ALREADY_IN_SET = 0xC01E032D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITORDESCRIPTOR_ID_MUST_BE_UNIQUE = 0xC01E032E, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TARGET_SUBSET_TYPE = 0xC01E032F, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_RESOURCES_NOT_RELATED = 0xC01E0330, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_ID_MUST_BE_UNIQUE = 0xC01E0331, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_ID_MUST_BE_UNIQUE = 0xC01E0332, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_AVAILABLE_VIDPN_TARGET = 0xC01E0333, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_COULD_NOT_BE_ASSOCIATED_WITH_ADAPTER = 0xC01E0334, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_VIDPNMGR = 0xC01E0335, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_ACTIVE_VIDPN = 0xC01E0336, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_STALE_VIDPN_TOPOLOGY = 0xC01E0337, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_NOT_CONNECTED = 0xC01E0338, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SOURCE_NOT_IN_TOPOLOGY = 0xC01E0339, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PRIMARYSURFACE_SIZE = 0xC01E033A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VISIBLEREGION_SIZE = 0xC01E033B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_STRIDE = 0xC01E033C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PIXELFORMAT = 0xC01E033D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_COLORBASIS = 0xC01E033E, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PIXELVALUEACCESSMODE = 0xC01E033F, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TARGET_NOT_IN_TOPOLOGY = 0xC01E0340, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_DISPLAY_MODE_MANAGEMENT_SUPPORT = 0xC01E0341, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_VIDPN_SOURCE_IN_USE = 0xC01E0342, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANT_ACCESS_ACTIVE_VIDPN = 0xC01E0343, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_IMPORTANCE_ORDINAL = 0xC01E0344, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_CONTENT_GEOMETRY_TRANSFORMATION = 0xC01E0345, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PATH_CONTENT_GEOMETRY_TRANSFORMATION_NOT_SUPPORTED = 0xC01E0346, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_GAMMA_RAMP = 0xC01E0347, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_GAMMA_RAMP_NOT_SUPPORTED = 0xC01E0348, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MULTISAMPLING_NOT_SUPPORTED = 0xC01E0349, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MODE_NOT_IN_MODESET = 0xC01E034A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_VIDPN_TOPOLOGY_RECOMMENDATION_REASON = 0xC01E034D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PATH_CONTENT_TYPE = 0xC01E034E, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_COPYPROTECTION_TYPE = 0xC01E034F, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UNASSIGNED_MODESET_ALREADY_EXISTS = 0xC01E0350, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_SCANLINE_ORDERING = 0xC01E0352, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_TOPOLOGY_CHANGES_NOT_ALLOWED = 0xC01E0353, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_AVAILABLE_IMPORTANCE_ORDINALS = 0xC01E0354, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INCOMPATIBLE_PRIVATE_FORMAT = 0xC01E0355, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MODE_PRUNING_ALGORITHM = 0xC01E0356, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_CAPABILITY_ORIGIN = 0xC01E0357, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_MONITOR_FREQUENCYRANGE_CONSTRAINT = 0xC01E0358, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MAX_NUM_PATHS_REACHED = 0xC01E0359, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CANCEL_VIDPN_TOPOLOGY_AUGMENTATION = 0xC01E035A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_CLIENT_TYPE = 0xC01E035B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CLIENTVIDPN_NOT_SET = 0xC01E035C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SPECIFIED_CHILD_ALREADY_CONNECTED = 0xC01E0400, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHILD_DESCRIPTOR_NOT_SUPPORTED = 0xC01E0401, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_A_LINKED_ADAPTER = 0xC01E0430, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_LEADLINK_NOT_ENUMERATED = 0xC01E0431, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_ENUMERATED = 0xC01E0432, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_CHAIN_NOT_READY = 0xC01E0433, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_STARTED = 0xC01E0434, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_CHAINLINKS_NOT_POWERED_ON = 0xC01E0435, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INCONSISTENT_DEVICE_LINK_STATE = 0xC01E0436, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NOT_POST_DEVICE_DRIVER = 0xC01E0438, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ADAPTER_ACCESS_NOT_EXCLUDED = 0xC01E043B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_NOT_SUPPORTED = 0xC01E0500, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_COPP_NOT_SUPPORTED = 0xC01E0501, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_UAB_NOT_SUPPORTED = 0xC01E0502, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_ENCRYPTED_PARAMETERS = 0xC01E0503, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_NO_PROTECTED_OUTPUTS_EXIST = 0xC01E0505, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INTERNAL_ERROR = 0xC01E050B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_HANDLE = 0xC01E050C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PVP_INVALID_CERTIFICATE_LENGTH = 0xC01E050E, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_SPANNING_MODE_ENABLED = 0xC01E050F, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_THEATER_MODE_ENABLED = 0xC01E0510, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PVP_HFS_FAILED = 0xC01E0511, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_SRM = 0xC01E0512, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_HDCP = 0xC01E0513, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_ACP = 0xC01E0514, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_OUTPUT_DOES_NOT_SUPPORT_CGMSA = 0xC01E0515, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_HDCP_SRM_NEVER_SET = 0xC01E0516, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_RESOLUTION_TOO_HIGH = 0xC01E0517, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_ALL_HDCP_HARDWARE_ALREADY_IN_USE = 0xC01E0518, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_NO_LONGER_EXISTS = 0xC01E051A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_COPP_SEMANTICS = 0xC01E051C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_INFORMATION_REQUEST = 0xC01E051D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_DRIVER_INTERNAL_ERROR = 0xC01E051E, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_PROTECTED_OUTPUT_DOES_NOT_HAVE_OPM_SEMANTICS = 0xC01E051F, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_SIGNALING_NOT_SUPPORTED = 0xC01E0520, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_OPM_INVALID_CONFIGURATION_REQUEST = 0xC01E0521, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_NOT_SUPPORTED = 0xC01E0580, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_DEVICE_DOES_NOT_EXIST = 0xC01E0581, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_ERROR_TRANSMITTING_DATA = 0xC01E0582, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_I2C_ERROR_RECEIVING_DATA = 0xC01E0583, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_VCP_NOT_SUPPORTED = 0xC01E0584, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_DATA = 0xC01E0585, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_MONITOR_RETURNED_INVALID_TIMING_STATUS_BYTE = 0xC01E0586, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_CAPABILITIES_STRING = 0xC01E0587, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MCA_INTERNAL_ERROR = 0xC01E0588, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_COMMAND = 0xC01E0589, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_LENGTH = 0xC01E058A, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DDCCI_INVALID_MESSAGE_CHECKSUM = 0xC01E058B, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_PHYSICAL_MONITOR_HANDLE = 0xC01E058C, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MONITOR_NO_LONGER_EXISTS = 0xC01E058D, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_ONLY_CONSOLE_SESSION_SUPPORTED = 0xC01E05E0, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_DISPLAY_DEVICE_CORRESPONDS_TO_NAME = 0xC01E05E1, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_DISPLAY_DEVICE_NOT_ATTACHED_TO_DESKTOP = 0xC01E05E2, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_MIRRORING_DEVICES_NOT_SUPPORTED = 0xC01E05E3, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INVALID_POINTER = 0xC01E05E4, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_NO_MONITORS_CORRESPOND_TO_DISPLAY_DEVICE = 0xC01E05E5, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_PARAMETER_ARRAY_TOO_SMALL = 0xC01E05E6, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_INTERNAL_ERROR = 0xC01E05E7, + MD_NTSTATUS_WIN_STATUS_GRAPHICS_SESSION_TYPE_CHANGE_IN_PROGRESS = 0xC01E05E8, + MD_NTSTATUS_WIN_STATUS_FVE_LOCKED_VOLUME = 0xC0210000, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_ENCRYPTED = 0xC0210001, + MD_NTSTATUS_WIN_STATUS_FVE_BAD_INFORMATION = 0xC0210002, + MD_NTSTATUS_WIN_STATUS_FVE_TOO_SMALL = 0xC0210003, + MD_NTSTATUS_WIN_STATUS_FVE_FAILED_WRONG_FS = 0xC0210004, + MD_NTSTATUS_WIN_STATUS_FVE_BAD_PARTITION_SIZE = 0xC0210005, + MD_NTSTATUS_WIN_STATUS_FVE_FS_NOT_EXTENDED = 0xC0210006, + MD_NTSTATUS_WIN_STATUS_FVE_FS_MOUNTED = 0xC0210007, + MD_NTSTATUS_WIN_STATUS_FVE_NO_LICENSE = 0xC0210008, + MD_NTSTATUS_WIN_STATUS_FVE_ACTION_NOT_ALLOWED = 0xC0210009, + MD_NTSTATUS_WIN_STATUS_FVE_BAD_DATA = 0xC021000A, + MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_NOT_BOUND = 0xC021000B, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_DATA_VOLUME = 0xC021000C, + MD_NTSTATUS_WIN_STATUS_FVE_CONV_READ_ERROR = 0xC021000D, + MD_NTSTATUS_WIN_STATUS_FVE_CONV_WRITE_ERROR = 0xC021000E, + MD_NTSTATUS_WIN_STATUS_FVE_OVERLAPPED_UPDATE = 0xC021000F, + MD_NTSTATUS_WIN_STATUS_FVE_FAILED_SECTOR_SIZE = 0xC0210010, + MD_NTSTATUS_WIN_STATUS_FVE_FAILED_AUTHENTICATION = 0xC0210011, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_OS_VOLUME = 0xC0210012, + MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_NOT_FOUND = 0xC0210013, + MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_INVALID = 0xC0210014, + MD_NTSTATUS_WIN_STATUS_FVE_KEYFILE_NO_VMK = 0xC0210015, + MD_NTSTATUS_WIN_STATUS_FVE_TPM_DISABLED = 0xC0210016, + MD_NTSTATUS_WIN_STATUS_FVE_TPM_SRK_AUTH_NOT_ZERO = 0xC0210017, + MD_NTSTATUS_WIN_STATUS_FVE_TPM_INVALID_PCR = 0xC0210018, + MD_NTSTATUS_WIN_STATUS_FVE_TPM_NO_VMK = 0xC0210019, + MD_NTSTATUS_WIN_STATUS_FVE_PIN_INVALID = 0xC021001A, + MD_NTSTATUS_WIN_STATUS_FVE_AUTH_INVALID_APPLICATION = 0xC021001B, + MD_NTSTATUS_WIN_STATUS_FVE_AUTH_INVALID_CONFIG = 0xC021001C, + MD_NTSTATUS_WIN_STATUS_FVE_DEBUGGER_ENABLED = 0xC021001D, + MD_NTSTATUS_WIN_STATUS_FVE_DRY_RUN_FAILED = 0xC021001E, + MD_NTSTATUS_WIN_STATUS_FVE_BAD_METADATA_POINTER = 0xC021001F, + MD_NTSTATUS_WIN_STATUS_FVE_OLD_METADATA_COPY = 0xC0210020, + MD_NTSTATUS_WIN_STATUS_FVE_REBOOT_REQUIRED = 0xC0210021, + MD_NTSTATUS_WIN_STATUS_FVE_RAW_ACCESS = 0xC0210022, + MD_NTSTATUS_WIN_STATUS_FVE_RAW_BLOCKED = 0xC0210023, + MD_NTSTATUS_WIN_STATUS_FVE_NO_AUTOUNLOCK_MASTER_KEY = 0xC0210024, + MD_NTSTATUS_WIN_STATUS_FVE_MOR_FAILED = 0xC0210025, + MD_NTSTATUS_WIN_STATUS_FVE_NO_FEATURE_LICENSE = 0xC0210026, + MD_NTSTATUS_WIN_STATUS_FVE_POLICY_USER_DISABLE_RDV_NOT_ALLOWED = 0xC0210027, + MD_NTSTATUS_WIN_STATUS_FVE_CONV_RECOVERY_FAILED = 0xC0210028, + MD_NTSTATUS_WIN_STATUS_FVE_VIRTUALIZED_SPACE_TOO_BIG = 0xC0210029, + MD_NTSTATUS_WIN_STATUS_FVE_INVALID_DATUM_TYPE = 0xC021002A, + MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_TOO_SMALL = 0xC0210030, + MD_NTSTATUS_WIN_STATUS_FVE_ENH_PIN_INVALID = 0xC0210031, + MD_NTSTATUS_WIN_STATUS_FVE_FULL_ENCRYPTION_NOT_ALLOWED_ON_TP_STORAGE = 0xC0210032, + MD_NTSTATUS_WIN_STATUS_FVE_WIPE_NOT_ALLOWED_ON_TP_STORAGE = 0xC0210033, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_ON_CSV_STACK = 0xC0210034, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_ON_CLUSTER = 0xC0210035, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_ALLOWED_TO_UPGRADE_WHILE_CONVERTING = 0xC0210036, + MD_NTSTATUS_WIN_STATUS_FVE_WIPE_CANCEL_NOT_APPLICABLE = 0xC0210037, + MD_NTSTATUS_WIN_STATUS_FVE_EDRIVE_DRY_RUN_FAILED = 0xC0210038, + MD_NTSTATUS_WIN_STATUS_FVE_SECUREBOOT_DISABLED = 0xC0210039, + MD_NTSTATUS_WIN_STATUS_FVE_SECUREBOOT_CONFIG_CHANGE = 0xC021003A, + MD_NTSTATUS_WIN_STATUS_FVE_DEVICE_LOCKEDOUT = 0xC021003B, + MD_NTSTATUS_WIN_STATUS_FVE_VOLUME_EXTEND_PREVENTS_EOW_DECRYPT = 0xC021003C, + MD_NTSTATUS_WIN_STATUS_FVE_NOT_DE_VOLUME = 0xC021003D, + MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_DISABLED = 0xC021003E, + MD_NTSTATUS_WIN_STATUS_FVE_PROTECTION_CANNOT_BE_DISABLED = 0xC021003F, + MD_NTSTATUS_WIN_STATUS_FWP_CALLOUT_NOT_FOUND = 0xC0220001, + MD_NTSTATUS_WIN_STATUS_FWP_CONDITION_NOT_FOUND = 0xC0220002, + MD_NTSTATUS_WIN_STATUS_FWP_FILTER_NOT_FOUND = 0xC0220003, + MD_NTSTATUS_WIN_STATUS_FWP_LAYER_NOT_FOUND = 0xC0220004, + MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_NOT_FOUND = 0xC0220005, + MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_CONTEXT_NOT_FOUND = 0xC0220006, + MD_NTSTATUS_WIN_STATUS_FWP_SUBLAYER_NOT_FOUND = 0xC0220007, + MD_NTSTATUS_WIN_STATUS_FWP_NOT_FOUND = 0xC0220008, + MD_NTSTATUS_WIN_STATUS_FWP_ALREADY_EXISTS = 0xC0220009, + MD_NTSTATUS_WIN_STATUS_FWP_IN_USE = 0xC022000A, + MD_NTSTATUS_WIN_STATUS_FWP_DYNAMIC_SESSION_IN_PROGRESS = 0xC022000B, + MD_NTSTATUS_WIN_STATUS_FWP_WRONG_SESSION = 0xC022000C, + MD_NTSTATUS_WIN_STATUS_FWP_NO_TXN_IN_PROGRESS = 0xC022000D, + MD_NTSTATUS_WIN_STATUS_FWP_TXN_IN_PROGRESS = 0xC022000E, + MD_NTSTATUS_WIN_STATUS_FWP_TXN_ABORTED = 0xC022000F, + MD_NTSTATUS_WIN_STATUS_FWP_SESSION_ABORTED = 0xC0220010, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_TXN = 0xC0220011, + MD_NTSTATUS_WIN_STATUS_FWP_TIMEOUT = 0xC0220012, + MD_NTSTATUS_WIN_STATUS_FWP_NET_EVENTS_DISABLED = 0xC0220013, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_LAYER = 0xC0220014, + MD_NTSTATUS_WIN_STATUS_FWP_KM_CLIENTS_ONLY = 0xC0220015, + MD_NTSTATUS_WIN_STATUS_FWP_LIFETIME_MISMATCH = 0xC0220016, + MD_NTSTATUS_WIN_STATUS_FWP_BUILTIN_OBJECT = 0xC0220017, + MD_NTSTATUS_WIN_STATUS_FWP_TOO_MANY_CALLOUTS = 0xC0220018, + MD_NTSTATUS_WIN_STATUS_FWP_NOTIFICATION_DROPPED = 0xC0220019, + MD_NTSTATUS_WIN_STATUS_FWP_TRAFFIC_MISMATCH = 0xC022001A, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_SA_STATE = 0xC022001B, + MD_NTSTATUS_WIN_STATUS_FWP_NULL_POINTER = 0xC022001C, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_ENUMERATOR = 0xC022001D, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_FLAGS = 0xC022001E, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_NET_MASK = 0xC022001F, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_RANGE = 0xC0220020, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_INTERVAL = 0xC0220021, + MD_NTSTATUS_WIN_STATUS_FWP_ZERO_LENGTH_ARRAY = 0xC0220022, + MD_NTSTATUS_WIN_STATUS_FWP_NULL_DISPLAY_NAME = 0xC0220023, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_ACTION_TYPE = 0xC0220024, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_WEIGHT = 0xC0220025, + MD_NTSTATUS_WIN_STATUS_FWP_MATCH_TYPE_MISMATCH = 0xC0220026, + MD_NTSTATUS_WIN_STATUS_FWP_TYPE_MISMATCH = 0xC0220027, + MD_NTSTATUS_WIN_STATUS_FWP_OUT_OF_BOUNDS = 0xC0220028, + MD_NTSTATUS_WIN_STATUS_FWP_RESERVED = 0xC0220029, + MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_CONDITION = 0xC022002A, + MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_KEYMOD = 0xC022002B, + MD_NTSTATUS_WIN_STATUS_FWP_ACTION_INCOMPATIBLE_WITH_LAYER = 0xC022002C, + MD_NTSTATUS_WIN_STATUS_FWP_ACTION_INCOMPATIBLE_WITH_SUBLAYER = 0xC022002D, + MD_NTSTATUS_WIN_STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_LAYER = 0xC022002E, + MD_NTSTATUS_WIN_STATUS_FWP_CONTEXT_INCOMPATIBLE_WITH_CALLOUT = 0xC022002F, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_AUTH_METHOD = 0xC0220030, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_DH_GROUP = 0xC0220031, + MD_NTSTATUS_WIN_STATUS_FWP_EM_NOT_SUPPORTED = 0xC0220032, + MD_NTSTATUS_WIN_STATUS_FWP_NEVER_MATCH = 0xC0220033, + MD_NTSTATUS_WIN_STATUS_FWP_PROVIDER_CONTEXT_MISMATCH = 0xC0220034, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_PARAMETER = 0xC0220035, + MD_NTSTATUS_WIN_STATUS_FWP_TOO_MANY_SUBLAYERS = 0xC0220036, + MD_NTSTATUS_WIN_STATUS_FWP_CALLOUT_NOTIFICATION_FAILED = 0xC0220037, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_AUTH_TRANSFORM = 0xC0220038, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_CIPHER_TRANSFORM = 0xC0220039, + MD_NTSTATUS_WIN_STATUS_FWP_INCOMPATIBLE_CIPHER_TRANSFORM = 0xC022003A, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_TRANSFORM_COMBINATION = 0xC022003B, + MD_NTSTATUS_WIN_STATUS_FWP_DUPLICATE_AUTH_METHOD = 0xC022003C, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_TUNNEL_ENDPOINT = 0xC022003D, + MD_NTSTATUS_WIN_STATUS_FWP_L2_DRIVER_NOT_READY = 0xC022003E, + MD_NTSTATUS_WIN_STATUS_FWP_KEY_DICTATOR_ALREADY_REGISTERED = 0xC022003F, + MD_NTSTATUS_WIN_STATUS_FWP_KEY_DICTATION_INVALID_KEYING_MATERIAL = 0xC0220040, + MD_NTSTATUS_WIN_STATUS_FWP_CONNECTIONS_DISABLED = 0xC0220041, + MD_NTSTATUS_WIN_STATUS_FWP_INVALID_DNS_NAME = 0xC0220042, + MD_NTSTATUS_WIN_STATUS_FWP_STILL_ON = 0xC0220043, + MD_NTSTATUS_WIN_STATUS_FWP_IKEEXT_NOT_RUNNING = 0xC0220044, + MD_NTSTATUS_WIN_STATUS_FWP_TCPIP_NOT_READY = 0xC0220100, + MD_NTSTATUS_WIN_STATUS_FWP_INJECT_HANDLE_CLOSING = 0xC0220101, + MD_NTSTATUS_WIN_STATUS_FWP_INJECT_HANDLE_STALE = 0xC0220102, + MD_NTSTATUS_WIN_STATUS_FWP_CANNOT_PEND = 0xC0220103, + MD_NTSTATUS_WIN_STATUS_FWP_DROP_NOICMP = 0xC0220104, + MD_NTSTATUS_WIN_STATUS_NDIS_CLOSING = 0xC0230002, + MD_NTSTATUS_WIN_STATUS_NDIS_BAD_VERSION = 0xC0230004, + MD_NTSTATUS_WIN_STATUS_NDIS_BAD_CHARACTERISTICS = 0xC0230005, + MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_NOT_FOUND = 0xC0230006, + MD_NTSTATUS_WIN_STATUS_NDIS_OPEN_FAILED = 0xC0230007, + MD_NTSTATUS_WIN_STATUS_NDIS_DEVICE_FAILED = 0xC0230008, + MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_FULL = 0xC0230009, + MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_EXISTS = 0xC023000A, + MD_NTSTATUS_WIN_STATUS_NDIS_MULTICAST_NOT_FOUND = 0xC023000B, + MD_NTSTATUS_WIN_STATUS_NDIS_REQUEST_ABORTED = 0xC023000C, + MD_NTSTATUS_WIN_STATUS_NDIS_RESET_IN_PROGRESS = 0xC023000D, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PACKET = 0xC023000F, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_DEVICE_REQUEST = 0xC0230010, + MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_NOT_READY = 0xC0230011, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_LENGTH = 0xC0230014, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_DATA = 0xC0230015, + MD_NTSTATUS_WIN_STATUS_NDIS_BUFFER_TOO_SHORT = 0xC0230016, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_OID = 0xC0230017, + MD_NTSTATUS_WIN_STATUS_NDIS_ADAPTER_REMOVED = 0xC0230018, + MD_NTSTATUS_WIN_STATUS_NDIS_UNSUPPORTED_MEDIA = 0xC0230019, + MD_NTSTATUS_WIN_STATUS_NDIS_GROUP_ADDRESS_IN_USE = 0xC023001A, + MD_NTSTATUS_WIN_STATUS_NDIS_FILE_NOT_FOUND = 0xC023001B, + MD_NTSTATUS_WIN_STATUS_NDIS_ERROR_READING_FILE = 0xC023001C, + MD_NTSTATUS_WIN_STATUS_NDIS_ALREADY_MAPPED = 0xC023001D, + MD_NTSTATUS_WIN_STATUS_NDIS_RESOURCE_CONFLICT = 0xC023001E, + MD_NTSTATUS_WIN_STATUS_NDIS_MEDIA_DISCONNECTED = 0xC023001F, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_ADDRESS = 0xC0230022, + MD_NTSTATUS_WIN_STATUS_NDIS_PAUSED = 0xC023002A, + MD_NTSTATUS_WIN_STATUS_NDIS_INTERFACE_NOT_FOUND = 0xC023002B, + MD_NTSTATUS_WIN_STATUS_NDIS_UNSUPPORTED_REVISION = 0xC023002C, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PORT = 0xC023002D, + MD_NTSTATUS_WIN_STATUS_NDIS_INVALID_PORT_STATE = 0xC023002E, + MD_NTSTATUS_WIN_STATUS_NDIS_LOW_POWER_STATE = 0xC023002F, + MD_NTSTATUS_WIN_STATUS_NDIS_REINIT_REQUIRED = 0xC0230030, + MD_NTSTATUS_WIN_STATUS_NDIS_NOT_SUPPORTED = 0xC02300BB, + MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_POLICY = 0xC023100F, + MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_CONNECTION_REJECTED = 0xC0231012, + MD_NTSTATUS_WIN_STATUS_NDIS_OFFLOAD_PATH_REJECTED = 0xC0231013, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_AUTO_CONFIG_ENABLED = 0xC0232000, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_MEDIA_IN_USE = 0xC0232001, + MD_NTSTATUS_WIN_STATUS_NDIS_DOT11_POWER_STATE_INVALID = 0xC0232002, + MD_NTSTATUS_WIN_STATUS_NDIS_PM_WOL_PATTERN_LIST_FULL = 0xC0232003, + MD_NTSTATUS_WIN_STATUS_NDIS_PM_PROTOCOL_OFFLOAD_LIST_FULL = 0xC0232004, + MD_NTSTATUS_WIN_STATUS_TPM_ERROR_MASK = 0xC0290000, + MD_NTSTATUS_WIN_STATUS_TPM_AUTHFAIL = 0xC0290001, + MD_NTSTATUS_WIN_STATUS_TPM_BADINDEX = 0xC0290002, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_PARAMETER = 0xC0290003, + MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAILURE = 0xC0290004, + MD_NTSTATUS_WIN_STATUS_TPM_CLEAR_DISABLED = 0xC0290005, + MD_NTSTATUS_WIN_STATUS_TPM_DEACTIVATED = 0xC0290006, + MD_NTSTATUS_WIN_STATUS_TPM_DISABLED = 0xC0290007, + MD_NTSTATUS_WIN_STATUS_TPM_DISABLED_CMD = 0xC0290008, + MD_NTSTATUS_WIN_STATUS_TPM_FAIL = 0xC0290009, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_ORDINAL = 0xC029000A, + MD_NTSTATUS_WIN_STATUS_TPM_INSTALL_DISABLED = 0xC029000B, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_KEYHANDLE = 0xC029000C, + MD_NTSTATUS_WIN_STATUS_TPM_KEYNOTFOUND = 0xC029000D, + MD_NTSTATUS_WIN_STATUS_TPM_INAPPROPRIATE_ENC = 0xC029000E, + MD_NTSTATUS_WIN_STATUS_TPM_MIGRATEFAIL = 0xC029000F, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_PCR_INFO = 0xC0290010, + MD_NTSTATUS_WIN_STATUS_TPM_NOSPACE = 0xC0290011, + MD_NTSTATUS_WIN_STATUS_TPM_NOSRK = 0xC0290012, + MD_NTSTATUS_WIN_STATUS_TPM_NOTSEALED_BLOB = 0xC0290013, + MD_NTSTATUS_WIN_STATUS_TPM_OWNER_SET = 0xC0290014, + MD_NTSTATUS_WIN_STATUS_TPM_RESOURCES = 0xC0290015, + MD_NTSTATUS_WIN_STATUS_TPM_SHORTRANDOM = 0xC0290016, + MD_NTSTATUS_WIN_STATUS_TPM_SIZE = 0xC0290017, + MD_NTSTATUS_WIN_STATUS_TPM_WRONGPCRVAL = 0xC0290018, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_PARAM_SIZE = 0xC0290019, + MD_NTSTATUS_WIN_STATUS_TPM_SHA_THREAD = 0xC029001A, + MD_NTSTATUS_WIN_STATUS_TPM_SHA_ERROR = 0xC029001B, + MD_NTSTATUS_WIN_STATUS_TPM_FAILEDSELFTEST = 0xC029001C, + MD_NTSTATUS_WIN_STATUS_TPM_AUTH2FAIL = 0xC029001D, + MD_NTSTATUS_WIN_STATUS_TPM_BADTAG = 0xC029001E, + MD_NTSTATUS_WIN_STATUS_TPM_IOERROR = 0xC029001F, + MD_NTSTATUS_WIN_STATUS_TPM_ENCRYPT_ERROR = 0xC0290020, + MD_NTSTATUS_WIN_STATUS_TPM_DECRYPT_ERROR = 0xC0290021, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_AUTHHANDLE = 0xC0290022, + MD_NTSTATUS_WIN_STATUS_TPM_NO_ENDORSEMENT = 0xC0290023, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_KEYUSAGE = 0xC0290024, + MD_NTSTATUS_WIN_STATUS_TPM_WRONG_ENTITYTYPE = 0xC0290025, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_POSTINIT = 0xC0290026, + MD_NTSTATUS_WIN_STATUS_TPM_INAPPROPRIATE_SIG = 0xC0290027, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_KEY_PROPERTY = 0xC0290028, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_MIGRATION = 0xC0290029, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_SCHEME = 0xC029002A, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_DATASIZE = 0xC029002B, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_MODE = 0xC029002C, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_PRESENCE = 0xC029002D, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_VERSION = 0xC029002E, + MD_NTSTATUS_WIN_STATUS_TPM_NO_WRAP_TRANSPORT = 0xC029002F, + MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAIL_UNSUCCESSFUL = 0xC0290030, + MD_NTSTATUS_WIN_STATUS_TPM_AUDITFAIL_SUCCESSFUL = 0xC0290031, + MD_NTSTATUS_WIN_STATUS_TPM_NOTRESETABLE = 0xC0290032, + MD_NTSTATUS_WIN_STATUS_TPM_NOTLOCAL = 0xC0290033, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_TYPE = 0xC0290034, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_RESOURCE = 0xC0290035, + MD_NTSTATUS_WIN_STATUS_TPM_NOTFIPS = 0xC0290036, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_FAMILY = 0xC0290037, + MD_NTSTATUS_WIN_STATUS_TPM_NO_NV_PERMISSION = 0xC0290038, + MD_NTSTATUS_WIN_STATUS_TPM_REQUIRES_SIGN = 0xC0290039, + MD_NTSTATUS_WIN_STATUS_TPM_KEY_NOTSUPPORTED = 0xC029003A, + MD_NTSTATUS_WIN_STATUS_TPM_AUTH_CONFLICT = 0xC029003B, + MD_NTSTATUS_WIN_STATUS_TPM_AREA_LOCKED = 0xC029003C, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_LOCALITY = 0xC029003D, + MD_NTSTATUS_WIN_STATUS_TPM_READ_ONLY = 0xC029003E, + MD_NTSTATUS_WIN_STATUS_TPM_PER_NOWRITE = 0xC029003F, + MD_NTSTATUS_WIN_STATUS_TPM_FAMILYCOUNT = 0xC0290040, + MD_NTSTATUS_WIN_STATUS_TPM_WRITE_LOCKED = 0xC0290041, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_ATTRIBUTES = 0xC0290042, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_STRUCTURE = 0xC0290043, + MD_NTSTATUS_WIN_STATUS_TPM_KEY_OWNER_CONTROL = 0xC0290044, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_COUNTER = 0xC0290045, + MD_NTSTATUS_WIN_STATUS_TPM_NOT_FULLWRITE = 0xC0290046, + MD_NTSTATUS_WIN_STATUS_TPM_CONTEXT_GAP = 0xC0290047, + MD_NTSTATUS_WIN_STATUS_TPM_MAXNVWRITES = 0xC0290048, + MD_NTSTATUS_WIN_STATUS_TPM_NOOPERATOR = 0xC0290049, + MD_NTSTATUS_WIN_STATUS_TPM_RESOURCEMISSING = 0xC029004A, + MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_LOCK = 0xC029004B, + MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_FAMILY = 0xC029004C, + MD_NTSTATUS_WIN_STATUS_TPM_DELEGATE_ADMIN = 0xC029004D, + MD_NTSTATUS_WIN_STATUS_TPM_TRANSPORT_NOTEXCLUSIVE = 0xC029004E, + MD_NTSTATUS_WIN_STATUS_TPM_OWNER_CONTROL = 0xC029004F, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_RESOURCES = 0xC0290050, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_INPUT_DATA0 = 0xC0290051, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_INPUT_DATA1 = 0xC0290052, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_ISSUER_SETTINGS = 0xC0290053, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_TPM_SETTINGS = 0xC0290054, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_STAGE = 0xC0290055, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_ISSUER_VALIDITY = 0xC0290056, + MD_NTSTATUS_WIN_STATUS_TPM_DAA_WRONG_W = 0xC0290057, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_HANDLE = 0xC0290058, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_DELEGATE = 0xC0290059, + MD_NTSTATUS_WIN_STATUS_TPM_BADCONTEXT = 0xC029005A, + MD_NTSTATUS_WIN_STATUS_TPM_TOOMANYCONTEXTS = 0xC029005B, + MD_NTSTATUS_WIN_STATUS_TPM_MA_TICKET_SIGNATURE = 0xC029005C, + MD_NTSTATUS_WIN_STATUS_TPM_MA_DESTINATION = 0xC029005D, + MD_NTSTATUS_WIN_STATUS_TPM_MA_SOURCE = 0xC029005E, + MD_NTSTATUS_WIN_STATUS_TPM_MA_AUTHORITY = 0xC029005F, + MD_NTSTATUS_WIN_STATUS_TPM_PERMANENTEK = 0xC0290061, + MD_NTSTATUS_WIN_STATUS_TPM_BAD_SIGNATURE = 0xC0290062, + MD_NTSTATUS_WIN_STATUS_TPM_NOCONTEXTSPACE = 0xC0290063, + MD_NTSTATUS_WIN_STATUS_TPM_COMMAND_BLOCKED = 0xC0290400, + MD_NTSTATUS_WIN_STATUS_TPM_INVALID_HANDLE = 0xC0290401, + MD_NTSTATUS_WIN_STATUS_TPM_DUPLICATE_VHANDLE = 0xC0290402, + MD_NTSTATUS_WIN_STATUS_TPM_EMBEDDED_COMMAND_BLOCKED = 0xC0290403, + MD_NTSTATUS_WIN_STATUS_TPM_EMBEDDED_COMMAND_UNSUPPORTED = 0xC0290404, + MD_NTSTATUS_WIN_STATUS_TPM_RETRY = 0xC0290800, + MD_NTSTATUS_WIN_STATUS_TPM_NEEDS_SELFTEST = 0xC0290801, + MD_NTSTATUS_WIN_STATUS_TPM_DOING_SELFTEST = 0xC0290802, + MD_NTSTATUS_WIN_STATUS_TPM_DEFEND_LOCK_RUNNING = 0xC0290803, + MD_NTSTATUS_WIN_STATUS_TPM_COMMAND_CANCELED = 0xC0291001, + MD_NTSTATUS_WIN_STATUS_TPM_TOO_MANY_CONTEXTS = 0xC0291002, + MD_NTSTATUS_WIN_STATUS_TPM_NOT_FOUND = 0xC0291003, + MD_NTSTATUS_WIN_STATUS_TPM_ACCESS_DENIED = 0xC0291004, + MD_NTSTATUS_WIN_STATUS_TPM_INSUFFICIENT_BUFFER = 0xC0291005, + MD_NTSTATUS_WIN_STATUS_TPM_PPI_FUNCTION_UNSUPPORTED = 0xC0291006, + MD_NTSTATUS_WIN_STATUS_PCP_ERROR_MASK = 0xC0292000, + MD_NTSTATUS_WIN_STATUS_PCP_DEVICE_NOT_READY = 0xC0292001, + MD_NTSTATUS_WIN_STATUS_PCP_INVALID_HANDLE = 0xC0292002, + MD_NTSTATUS_WIN_STATUS_PCP_INVALID_PARAMETER = 0xC0292003, + MD_NTSTATUS_WIN_STATUS_PCP_FLAG_NOT_SUPPORTED = 0xC0292004, + MD_NTSTATUS_WIN_STATUS_PCP_NOT_SUPPORTED = 0xC0292005, + MD_NTSTATUS_WIN_STATUS_PCP_BUFFER_TOO_SMALL = 0xC0292006, + MD_NTSTATUS_WIN_STATUS_PCP_INTERNAL_ERROR = 0xC0292007, + MD_NTSTATUS_WIN_STATUS_PCP_AUTHENTICATION_FAILED = 0xC0292008, + MD_NTSTATUS_WIN_STATUS_PCP_AUTHENTICATION_IGNORED = 0xC0292009, + MD_NTSTATUS_WIN_STATUS_PCP_POLICY_NOT_FOUND = 0xC029200A, + MD_NTSTATUS_WIN_STATUS_PCP_PROFILE_NOT_FOUND = 0xC029200B, + MD_NTSTATUS_WIN_STATUS_PCP_VALIDATION_FAILED = 0xC029200C, + MD_NTSTATUS_WIN_STATUS_PCP_DEVICE_NOT_FOUND = 0xC029200D, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_CODE = 0xC0350002, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_HYPERCALL_INPUT = 0xC0350003, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_ALIGNMENT = 0xC0350004, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARAMETER = 0xC0350005, + MD_NTSTATUS_WIN_STATUS_HV_ACCESS_DENIED = 0xC0350006, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARTITION_STATE = 0xC0350007, + MD_NTSTATUS_WIN_STATUS_HV_OPERATION_DENIED = 0xC0350008, + MD_NTSTATUS_WIN_STATUS_HV_UNKNOWN_PROPERTY = 0xC0350009, + MD_NTSTATUS_WIN_STATUS_HV_PROPERTY_VALUE_OUT_OF_RANGE = 0xC035000A, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_MEMORY = 0xC035000B, + MD_NTSTATUS_WIN_STATUS_HV_PARTITION_TOO_DEEP = 0xC035000C, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PARTITION_ID = 0xC035000D, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_VP_INDEX = 0xC035000E, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PORT_ID = 0xC0350011, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_CONNECTION_ID = 0xC0350012, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFERS = 0xC0350013, + MD_NTSTATUS_WIN_STATUS_HV_NOT_ACKNOWLEDGED = 0xC0350014, + MD_NTSTATUS_WIN_STATUS_HV_ACKNOWLEDGED = 0xC0350016, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_SAVE_RESTORE_STATE = 0xC0350017, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_SYNIC_STATE = 0xC0350018, + MD_NTSTATUS_WIN_STATUS_HV_OBJECT_IN_USE = 0xC0350019, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_PROXIMITY_DOMAIN_INFO = 0xC035001A, + MD_NTSTATUS_WIN_STATUS_HV_NO_DATA = 0xC035001B, + MD_NTSTATUS_WIN_STATUS_HV_INACTIVE = 0xC035001C, + MD_NTSTATUS_WIN_STATUS_HV_NO_RESOURCES = 0xC035001D, + MD_NTSTATUS_WIN_STATUS_HV_FEATURE_UNAVAILABLE = 0xC035001E, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_BUFFER = 0xC0350033, + MD_NTSTATUS_WIN_STATUS_HV_INSUFFICIENT_DEVICE_DOMAINS = 0xC0350038, + MD_NTSTATUS_WIN_STATUS_HV_INVALID_LP_INDEX = 0xC0350041, + MD_NTSTATUS_WIN_STATUS_HV_NOT_PRESENT = 0xC0351000, + MD_NTSTATUS_WIN_STATUS_IPSEC_BAD_SPI = 0xC0360001, + MD_NTSTATUS_WIN_STATUS_IPSEC_SA_LIFETIME_EXPIRED = 0xC0360002, + MD_NTSTATUS_WIN_STATUS_IPSEC_WRONG_SA = 0xC0360003, + MD_NTSTATUS_WIN_STATUS_IPSEC_REPLAY_CHECK_FAILED = 0xC0360004, + MD_NTSTATUS_WIN_STATUS_IPSEC_INVALID_PACKET = 0xC0360005, + MD_NTSTATUS_WIN_STATUS_IPSEC_INTEGRITY_CHECK_FAILED = 0xC0360006, + MD_NTSTATUS_WIN_STATUS_IPSEC_CLEAR_TEXT_DROP = 0xC0360007, + MD_NTSTATUS_WIN_STATUS_IPSEC_AUTH_FIREWALL_DROP = 0xC0360008, + MD_NTSTATUS_WIN_STATUS_IPSEC_THROTTLE_DROP = 0xC0360009, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_BLOCK = 0xC0368000, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_RECEIVED_MULTICAST = 0xC0368001, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_INVALID_PACKET = 0xC0368002, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_STATE_LOOKUP_FAILED = 0xC0368003, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_MAX_ENTRIES = 0xC0368004, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_KEYMOD_NOT_ALLOWED = 0xC0368005, + MD_NTSTATUS_WIN_STATUS_IPSEC_DOSP_MAX_PER_IP_RATELIMIT_QUEUES = 0xC0368006, + MD_NTSTATUS_WIN_STATUS_VID_DUPLICATE_HANDLER = 0xC0370001, + MD_NTSTATUS_WIN_STATUS_VID_TOO_MANY_HANDLERS = 0xC0370002, + MD_NTSTATUS_WIN_STATUS_VID_QUEUE_FULL = 0xC0370003, + MD_NTSTATUS_WIN_STATUS_VID_HANDLER_NOT_PRESENT = 0xC0370004, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_OBJECT_NAME = 0xC0370005, + MD_NTSTATUS_WIN_STATUS_VID_PARTITION_NAME_TOO_LONG = 0xC0370006, + MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_NAME_TOO_LONG = 0xC0370007, + MD_NTSTATUS_WIN_STATUS_VID_PARTITION_ALREADY_EXISTS = 0xC0370008, + MD_NTSTATUS_WIN_STATUS_VID_PARTITION_DOES_NOT_EXIST = 0xC0370009, + MD_NTSTATUS_WIN_STATUS_VID_PARTITION_NAME_NOT_FOUND = 0xC037000A, + MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_ALREADY_EXISTS = 0xC037000B, + MD_NTSTATUS_WIN_STATUS_VID_EXCEEDED_MBP_ENTRY_MAP_LIMIT = 0xC037000C, + MD_NTSTATUS_WIN_STATUS_VID_MB_STILL_REFERENCED = 0xC037000D, + MD_NTSTATUS_WIN_STATUS_VID_CHILD_GPA_PAGE_SET_CORRUPTED = 0xC037000E, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_NUMA_SETTINGS = 0xC037000F, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_NUMA_NODE_INDEX = 0xC0370010, + MD_NTSTATUS_WIN_STATUS_VID_NOTIFICATION_QUEUE_ALREADY_ASSOCIATED = 0xC0370011, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_MEMORY_BLOCK_HANDLE = 0xC0370012, + MD_NTSTATUS_WIN_STATUS_VID_PAGE_RANGE_OVERFLOW = 0xC0370013, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_MESSAGE_QUEUE_HANDLE = 0xC0370014, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_GPA_RANGE_HANDLE = 0xC0370015, + MD_NTSTATUS_WIN_STATUS_VID_NO_MEMORY_BLOCK_NOTIFICATION_QUEUE = 0xC0370016, + MD_NTSTATUS_WIN_STATUS_VID_MEMORY_BLOCK_LOCK_COUNT_EXCEEDED = 0xC0370017, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_PPM_HANDLE = 0xC0370018, + MD_NTSTATUS_WIN_STATUS_VID_MBPS_ARE_LOCKED = 0xC0370019, + MD_NTSTATUS_WIN_STATUS_VID_MESSAGE_QUEUE_CLOSED = 0xC037001A, + MD_NTSTATUS_WIN_STATUS_VID_VIRTUAL_PROCESSOR_LIMIT_EXCEEDED = 0xC037001B, + MD_NTSTATUS_WIN_STATUS_VID_STOP_PENDING = 0xC037001C, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_PROCESSOR_STATE = 0xC037001D, + MD_NTSTATUS_WIN_STATUS_VID_EXCEEDED_KM_CONTEXT_COUNT_LIMIT = 0xC037001E, + MD_NTSTATUS_WIN_STATUS_VID_KM_INTERFACE_ALREADY_INITIALIZED = 0xC037001F, + MD_NTSTATUS_WIN_STATUS_VID_MB_PROPERTY_ALREADY_SET_RESET = 0xC0370020, + MD_NTSTATUS_WIN_STATUS_VID_MMIO_RANGE_DESTROYED = 0xC0370021, + MD_NTSTATUS_WIN_STATUS_VID_INVALID_CHILD_GPA_PAGE_SET = 0xC0370022, + MD_NTSTATUS_WIN_STATUS_VID_RESERVE_PAGE_SET_IS_BEING_USED = 0xC0370023, + MD_NTSTATUS_WIN_STATUS_VID_RESERVE_PAGE_SET_TOO_SMALL = 0xC0370024, + MD_NTSTATUS_WIN_STATUS_VID_MBP_ALREADY_LOCKED_USING_RESERVED_PAGE = 0xC0370025, + MD_NTSTATUS_WIN_STATUS_VID_MBP_COUNT_EXCEEDED_LIMIT = 0xC0370026, + MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_CORRUPT = 0xC0370027, + MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_UNRECOGNIZED_ITEM = 0xC0370028, + MD_NTSTATUS_WIN_STATUS_VID_SAVED_STATE_INCOMPATIBLE = 0xC0370029, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DATABASE_FULL = 0xC0380001, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_CORRUPTED = 0xC0380002, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONFIGURATION_NOT_IN_SYNC = 0xC0380003, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_UPDATE_FAILED = 0xC0380004, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_CONTAINS_NON_SIMPLE_VOLUME = 0xC0380005, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_DUPLICATE = 0xC0380006, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_DYNAMIC = 0xC0380007, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_ID_INVALID = 0xC0380008, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_INVALID = 0xC0380009, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAST_VOTER = 0xC038000A, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_INVALID = 0xC038000B, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_NON_BASIC_BETWEEN_BASIC_PARTITIONS = 0xC038000C, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_NOT_CYLINDER_ALIGNED = 0xC038000D, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_PARTITIONS_TOO_SMALL = 0xC038000E, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_PRIMARY_BETWEEN_LOGICAL_PARTITIONS = 0xC038000F, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_LAYOUT_TOO_MANY_PARTITIONS = 0xC0380010, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_MISSING = 0xC0380011, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_NOT_EMPTY = 0xC0380012, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_NOT_ENOUGH_SPACE = 0xC0380013, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_REVECTORING_FAILED = 0xC0380014, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_SECTOR_SIZE_INVALID = 0xC0380015, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_SET_NOT_CONTAINED = 0xC0380016, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_MEMBERS = 0xC0380017, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DISK_USED_BY_MULTIPLE_PLEXES = 0xC0380018, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DYNAMIC_DISK_NOT_SUPPORTED = 0xC0380019, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_ALREADY_USED = 0xC038001A, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_CONTIGUOUS = 0xC038001B, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_IN_PUBLIC_REGION = 0xC038001C, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_NOT_SECTOR_ALIGNED = 0xC038001D, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_OVERLAPS_EBR_PARTITION = 0xC038001E, + MD_NTSTATUS_WIN_STATUS_VOLMGR_EXTENT_VOLUME_LENGTHS_DO_NOT_MATCH = 0xC038001F, + MD_NTSTATUS_WIN_STATUS_VOLMGR_FAULT_TOLERANT_NOT_SUPPORTED = 0xC0380020, + MD_NTSTATUS_WIN_STATUS_VOLMGR_INTERLEAVE_LENGTH_INVALID = 0xC0380021, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MAXIMUM_REGISTERED_USERS = 0xC0380022, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_IN_SYNC = 0xC0380023, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_INDEX_DUPLICATE = 0xC0380024, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_INDEX_INVALID = 0xC0380025, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_MISSING = 0xC0380026, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_NOT_DETACHED = 0xC0380027, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MEMBER_REGENERATING = 0xC0380028, + MD_NTSTATUS_WIN_STATUS_VOLMGR_ALL_DISKS_FAILED = 0xC0380029, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_REGISTERED_USERS = 0xC038002A, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_SUCH_USER = 0xC038002B, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NOTIFICATION_RESET = 0xC038002C, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_MEMBERS_INVALID = 0xC038002D, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_PLEXES_INVALID = 0xC038002E, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_DUPLICATE = 0xC038002F, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_ID_INVALID = 0xC0380030, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_INVALID = 0xC0380031, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_NAME_INVALID = 0xC0380032, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_OFFLINE = 0xC0380033, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_HAS_QUORUM = 0xC0380034, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_WITHOUT_QUORUM = 0xC0380035, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PARTITION_STYLE_INVALID = 0xC0380036, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PARTITION_UPDATE_FAILED = 0xC0380037, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_IN_SYNC = 0xC0380038, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_INDEX_DUPLICATE = 0xC0380039, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_INDEX_INVALID = 0xC038003A, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_LAST_ACTIVE = 0xC038003B, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_MISSING = 0xC038003C, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_REGENERATING = 0xC038003D, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_TYPE_INVALID = 0xC038003E, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_RAID5 = 0xC038003F, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_SIMPLE = 0xC0380040, + MD_NTSTATUS_WIN_STATUS_VOLMGR_STRUCTURE_SIZE_INVALID = 0xC0380041, + MD_NTSTATUS_WIN_STATUS_VOLMGR_TOO_MANY_NOTIFICATION_REQUESTS = 0xC0380042, + MD_NTSTATUS_WIN_STATUS_VOLMGR_TRANSACTION_IN_PROGRESS = 0xC0380043, + MD_NTSTATUS_WIN_STATUS_VOLMGR_UNEXPECTED_DISK_LAYOUT_CHANGE = 0xC0380044, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_CONTAINS_MISSING_DISK = 0xC0380045, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_ID_INVALID = 0xC0380046, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_LENGTH_INVALID = 0xC0380047, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_LENGTH_NOT_SECTOR_SIZE_MULTIPLE = 0xC0380048, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_NOT_MIRRORED = 0xC0380049, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_NOT_RETAINED = 0xC038004A, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_OFFLINE = 0xC038004B, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_RETAINED = 0xC038004C, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_EXTENTS_INVALID = 0xC038004D, + MD_NTSTATUS_WIN_STATUS_VOLMGR_DIFFERENT_SECTOR_SIZE = 0xC038004E, + MD_NTSTATUS_WIN_STATUS_VOLMGR_BAD_BOOT_DISK = 0xC038004F, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_OFFLINE = 0xC0380050, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_CONFIG_ONLINE = 0xC0380051, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NOT_PRIMARY_PACK = 0xC0380052, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PACK_LOG_UPDATE_FAILED = 0xC0380053, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_IN_PLEX_INVALID = 0xC0380054, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_IN_MEMBER_INVALID = 0xC0380055, + MD_NTSTATUS_WIN_STATUS_VOLMGR_VOLUME_MIRRORED = 0xC0380056, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PLEX_NOT_SIMPLE_SPANNED = 0xC0380057, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NO_VALID_LOG_COPIES = 0xC0380058, + MD_NTSTATUS_WIN_STATUS_VOLMGR_PRIMARY_PACK_PRESENT = 0xC0380059, + MD_NTSTATUS_WIN_STATUS_VOLMGR_NUMBER_OF_DISKS_INVALID = 0xC038005A, + MD_NTSTATUS_WIN_STATUS_VOLMGR_MIRROR_NOT_SUPPORTED = 0xC038005B, + MD_NTSTATUS_WIN_STATUS_VOLMGR_RAID5_NOT_SUPPORTED = 0xC038005C, + MD_NTSTATUS_WIN_STATUS_BCD_TOO_MANY_ELEMENTS = 0xC0390002, + MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_MISSING = 0xC03A0001, + MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_CHECKSUM_MISMATCH = 0xC03A0002, + MD_NTSTATUS_WIN_STATUS_VHD_DRIVE_FOOTER_CORRUPT = 0xC03A0003, + MD_NTSTATUS_WIN_STATUS_VHD_FORMAT_UNKNOWN = 0xC03A0004, + MD_NTSTATUS_WIN_STATUS_VHD_FORMAT_UNSUPPORTED_VERSION = 0xC03A0005, + MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_CHECKSUM_MISMATCH = 0xC03A0006, + MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_UNSUPPORTED_VERSION = 0xC03A0007, + MD_NTSTATUS_WIN_STATUS_VHD_SPARSE_HEADER_CORRUPT = 0xC03A0008, + MD_NTSTATUS_WIN_STATUS_VHD_BLOCK_ALLOCATION_FAILURE = 0xC03A0009, + MD_NTSTATUS_WIN_STATUS_VHD_BLOCK_ALLOCATION_TABLE_CORRUPT = 0xC03A000A, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_BLOCK_SIZE = 0xC03A000B, + MD_NTSTATUS_WIN_STATUS_VHD_BITMAP_MISMATCH = 0xC03A000C, + MD_NTSTATUS_WIN_STATUS_VHD_PARENT_VHD_NOT_FOUND = 0xC03A000D, + MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_ID_MISMATCH = 0xC03A000E, + MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_TIMESTAMP_MISMATCH = 0xC03A000F, + MD_NTSTATUS_WIN_STATUS_VHD_METADATA_READ_FAILURE = 0xC03A0010, + MD_NTSTATUS_WIN_STATUS_VHD_METADATA_WRITE_FAILURE = 0xC03A0011, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_SIZE = 0xC03A0012, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_FILE_SIZE = 0xC03A0013, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_PROVIDER_NOT_FOUND = 0xC03A0014, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_NOT_VIRTUAL_DISK = 0xC03A0015, + MD_NTSTATUS_WIN_STATUS_VHD_PARENT_VHD_ACCESS_DENIED = 0xC03A0016, + MD_NTSTATUS_WIN_STATUS_VHD_CHILD_PARENT_SIZE_MISMATCH = 0xC03A0017, + MD_NTSTATUS_WIN_STATUS_VHD_DIFFERENCING_CHAIN_CYCLE_DETECTED = 0xC03A0018, + MD_NTSTATUS_WIN_STATUS_VHD_DIFFERENCING_CHAIN_ERROR_IN_PARENT = 0xC03A0019, + MD_NTSTATUS_WIN_STATUS_VIRTUAL_DISK_LIMITATION = 0xC03A001A, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_TYPE = 0xC03A001B, + MD_NTSTATUS_WIN_STATUS_VHD_INVALID_STATE = 0xC03A001C, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_UNSUPPORTED_DISK_SECTOR_SIZE = 0xC03A001D, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_DISK_ALREADY_OWNED = 0xC03A001E, + MD_NTSTATUS_WIN_STATUS_VIRTDISK_DISK_ONLINE_AND_WRITABLE = 0xC03A001F, + MD_NTSTATUS_WIN_STATUS_CTLOG_TRACKING_NOT_INITIALIZED = 0xC03A0020, + MD_NTSTATUS_WIN_STATUS_CTLOG_LOGFILE_SIZE_EXCEEDED_MAXSIZE = 0xC03A0021, + MD_NTSTATUS_WIN_STATUS_CTLOG_VHD_CHANGED_OFFLINE = 0xC03A0022, + MD_NTSTATUS_WIN_STATUS_CTLOG_INVALID_TRACKING_STATE = 0xC03A0023, + MD_NTSTATUS_WIN_STATUS_CTLOG_INCONSISTENT_TRACKING_FILE = 0xC03A0024, + MD_NTSTATUS_WIN_STATUS_VHD_METADATA_FULL = 0xC03A0028, + MD_NTSTATUS_WIN_STATUS_RKF_KEY_NOT_FOUND = 0xC0400001, + MD_NTSTATUS_WIN_STATUS_RKF_DUPLICATE_KEY = 0xC0400002, + MD_NTSTATUS_WIN_STATUS_RKF_BLOB_FULL = 0xC0400003, + MD_NTSTATUS_WIN_STATUS_RKF_STORE_FULL = 0xC0400004, + MD_NTSTATUS_WIN_STATUS_RKF_FILE_BLOCKED = 0xC0400005, + MD_NTSTATUS_WIN_STATUS_RKF_ACTIVE_KEY = 0xC0400006, + MD_NTSTATUS_WIN_STATUS_RDBSS_RESTART_OPERATION = 0xC0410001, + MD_NTSTATUS_WIN_STATUS_RDBSS_CONTINUE_OPERATION = 0xC0410002, + MD_NTSTATUS_WIN_STATUS_RDBSS_POST_OPERATION = 0xC0410003, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_HANDLE = 0xC0420001, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_READ_NOT_PERMITTED = 0xC0420002, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_WRITE_NOT_PERMITTED = 0xC0420003, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_PDU = 0xC0420004, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_AUTHENTICATION = 0xC0420005, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_REQUEST_NOT_SUPPORTED = 0xC0420006, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_OFFSET = 0xC0420007, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_AUTHORIZATION = 0xC0420008, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_PREPARE_QUEUE_FULL = 0xC0420009, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_ATTRIBUTE_NOT_FOUND = 0xC042000A, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_ATTRIBUTE_NOT_LONG = 0xC042000B, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION_KEY_SIZE = 0xC042000C, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INVALID_ATTRIBUTE_VALUE_LENGTH = 0xC042000D, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNLIKELY = 0xC042000E, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_ENCRYPTION = 0xC042000F, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNSUPPORTED_GROUP_TYPE = 0xC0420010, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_INSUFFICIENT_RESOURCES = 0xC0420011, + MD_NTSTATUS_WIN_STATUS_BTH_ATT_UNKNOWN_ERROR = 0xC0421000, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_ROLLBACK_DETECTED = 0xC0430001, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_VIOLATION = 0xC0430002, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_INVALID_POLICY = 0xC0430003, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_PUBLISHER_NOT_FOUND = 0xC0430004, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_POLICY_NOT_SIGNED = 0xC0430005, + MD_NTSTATUS_WIN_STATUS_SECUREBOOT_FILE_REPLACED = 0xC0430007, + MD_NTSTATUS_WIN_STATUS_AUDIO_ENGINE_NODE_NOT_FOUND = 0xC0440001, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_EMPTY_CONNECTION_LIST = 0xC0440002, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_CONNECTION_LIST_NOT_SUPPORTED = 0xC0440003, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_NO_LOGICAL_DEVICES_CREATED = 0xC0440004, + MD_NTSTATUS_WIN_STATUS_HDAUDIO_NULL_LINKED_LIST_ENTRY = 0xC0440005, + MD_NTSTATUS_WIN_STATUS_VOLSNAP_BOOTFILE_NOT_VALID = 0xC0500003, + MD_NTSTATUS_WIN_STATUS_IO_PREEMPTED = 0xC0510001, + MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_STORED = 0xC05C0000, + MD_NTSTATUS_WIN_STATUS_SVHDX_ERROR_NOT_AVAILABLE = 0xC05CFF00, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_AVAILABLE = 0xC05CFF01, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_CAPACITY_DATA_CHANGED = 0xC05CFF02, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_PREEMPTED = 0xC05CFF03, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_RESERVATIONS_RELEASED = 0xC05CFF04, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_REGISTRATIONS_PREEMPTED = 0xC05CFF05, + MD_NTSTATUS_WIN_STATUS_SVHDX_UNIT_ATTENTION_OPERATING_DEFINITION_CHANGED = 0xC05CFF06, + MD_NTSTATUS_WIN_STATUS_SVHDX_RESERVATION_CONFLICT = 0xC05CFF07, + MD_NTSTATUS_WIN_STATUS_SVHDX_WRONG_FILE_TYPE = 0xC05CFF08, + MD_NTSTATUS_WIN_STATUS_SVHDX_VERSION_MISMATCH = 0xC05CFF09, + MD_NTSTATUS_WIN_STATUS_VHD_SHARED = 0xC05CFF0A, + MD_NTSTATUS_WIN_STATUS_SPACES_RESILIENCY_TYPE_INVALID = 0xC0E70003, + MD_NTSTATUS_WIN_STATUS_SPACES_DRIVE_SECTOR_SIZE_INVALID = 0xC0E70004, + MD_NTSTATUS_WIN_STATUS_SPACES_INTERLEAVE_LENGTH_INVALID = 0xC0E70009, + MD_NTSTATUS_WIN_STATUS_SPACES_NUMBER_OF_COLUMNS_INVALID = 0xC0E7000A, + MD_NTSTATUS_WIN_STATUS_SPACES_NOT_ENOUGH_DRIVES = 0xC0E7000B +} MDNTStatusCodeWin; + +// These constants are defined in the MSDN documentation of +// the EXCEPTION_RECORD structure. +typedef enum { + MD_ACCESS_VIOLATION_WIN_READ = 0, + MD_ACCESS_VIOLATION_WIN_WRITE = 1, + MD_ACCESS_VIOLATION_WIN_EXEC = 8 +} MDAccessViolationTypeWin; + +// These constants are defined in the MSDN documentation of +// the EXCEPTION_RECORD structure. +typedef enum { + MD_IN_PAGE_ERROR_WIN_READ = 0, + MD_IN_PAGE_ERROR_WIN_WRITE = 1, + MD_IN_PAGE_ERROR_WIN_EXEC = 8 +} MDInPageErrorTypeWin; + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_WIN32_H__ */ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_format.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_format.h new file mode 100644 index 00000000..17a5abba --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_format.h @@ -0,0 +1,972 @@ +/* Copyright (c) 2006, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. */ + +/* minidump_format.h: A cross-platform reimplementation of minidump-related + * portions of DbgHelp.h from the Windows Platform SDK. + * + * (This is C99 source, please don't corrupt it with C++.) + * + * Structures that are defined by Microsoft to contain a zero-length array + * are instead defined here to contain an array with one element, as + * zero-length arrays are forbidden by standard C and C++. In these cases, + * *_minsize constants are provided to be used in place of sizeof. For a + * cleaner interface to these sizes when using C++, see minidump_size.h. + * + * These structures are also sufficient to populate minidump files. + * + * These definitions may be extended to support handling minidump files + * for other CPUs and other operating systems. + * + * Because precise data type sizes are crucial for this implementation to + * function properly and portably in terms of interoperability with minidumps + * produced by DbgHelp on Windows, a set of primitive types with known sizes + * are used as the basis of each structure defined by this file. DbgHelp + * on Windows is assumed to be the reference implementation; this file + * seeks to provide a cross-platform compatible implementation. To avoid + * collisions with the types and values defined and used by DbgHelp in the + * event that this implementation is used on Windows, each type and value + * defined here is given a new name, beginning with "MD". Names of the + * equivalent types and values in the Windows Platform SDK are given in + * comments. + * + * Author: Mark Mentovai */ + + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__ + +#include + +#include "google_breakpad/common/breakpad_types.h" + + +#if defined(_MSC_VER) +/* Disable "zero-sized array in struct/union" warnings when compiling in + * MSVC. DbgHelp.h does this too. */ +#pragma warning(push) +#pragma warning(disable:4200) +#endif /* _MSC_VER */ + + +/* + * guiddef.h + */ + +typedef struct { + uint32_t data1; + uint16_t data2; + uint16_t data3; + uint8_t data4[8]; +} MDGUID; /* GUID */ + + +/* + * WinNT.h + */ + +/* Non-x86 CPU identifiers found in the high 24 bits of + * (MDRawContext*).context_flags. These aren't used by Breakpad, but are + * defined here for reference, to avoid assigning values that conflict + * (although some values already conflict). */ +#define MD_CONTEXT_IA64 0x00080000 /* CONTEXT_IA64 */ +/* Additional values from winnt.h in the Windows CE 5.0 SDK: */ +#define MD_CONTEXT_SHX 0x000000c0 /* CONTEXT_SH4 (Super-H, includes SH3) */ +#define MD_CONTEXT_ALPHA 0x00020000 /* CONTEXT_ALPHA */ + +/* As of Windows 7 SP1, the number of flag bits has increased to + * include 0x40 (CONTEXT_XSTATE): + * http://msdn.microsoft.com/en-us/library/hh134238%28v=vs.85%29.aspx */ +#define MD_CONTEXT_CPU_MASK 0xffffff00 + + +/* This is a base type for MDRawContextX86 and MDRawContextPPC. This + * structure should never be allocated directly. The actual structure type + * can be determined by examining the context_flags field. */ +typedef struct { + uint32_t context_flags; +} MDRawContextBase; + +#include "minidump_cpu_amd64.h" +#include "minidump_cpu_arm.h" +#include "minidump_cpu_arm64.h" +#include "minidump_cpu_mips.h" +#include "minidump_cpu_ppc.h" +#include "minidump_cpu_ppc64.h" +#include "minidump_cpu_sparc.h" +#include "minidump_cpu_x86.h" + +/* + * WinVer.h + */ + + +typedef struct { + uint32_t signature; + uint32_t struct_version; + uint32_t file_version_hi; + uint32_t file_version_lo; + uint32_t product_version_hi; + uint32_t product_version_lo; + uint32_t file_flags_mask; /* Identifies valid bits in fileFlags */ + uint32_t file_flags; + uint32_t file_os; + uint32_t file_type; + uint32_t file_subtype; + uint32_t file_date_hi; + uint32_t file_date_lo; +} MDVSFixedFileInfo; /* VS_FIXEDFILEINFO */ + +/* For (MDVSFixedFileInfo).signature */ +#define MD_VSFIXEDFILEINFO_SIGNATURE 0xfeef04bd + /* VS_FFI_SIGNATURE */ + +/* For (MDVSFixedFileInfo).version */ +#define MD_VSFIXEDFILEINFO_VERSION 0x00010000 + /* VS_FFI_STRUCVERSION */ + +/* For (MDVSFixedFileInfo).file_flags_mask and + * (MDVSFixedFileInfo).file_flags */ +#define MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG 0x00000001 + /* VS_FF_DEBUG */ +#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PRERELEASE 0x00000002 + /* VS_FF_PRERELEASE */ +#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PATCHED 0x00000004 + /* VS_FF_PATCHED */ +#define MD_VSFIXEDFILEINFO_FILE_FLAGS_PRIVATEBUILD 0x00000008 + /* VS_FF_PRIVATEBUILD */ +#define MD_VSFIXEDFILEINFO_FILE_FLAGS_INFOINFERRED 0x00000010 + /* VS_FF_INFOINFERRED */ +#define MD_VSFIXEDFILEINFO_FILE_FLAGS_SPECIALBUILD 0x00000020 + /* VS_FF_SPECIALBUILD */ + +/* For (MDVSFixedFileInfo).file_os: high 16 bits */ +#define MD_VSFIXEDFILEINFO_FILE_OS_UNKNOWN 0 /* VOS_UNKNOWN */ +#define MD_VSFIXEDFILEINFO_FILE_OS_DOS (1 << 16) /* VOS_DOS */ +#define MD_VSFIXEDFILEINFO_FILE_OS_OS216 (2 << 16) /* VOS_OS216 */ +#define MD_VSFIXEDFILEINFO_FILE_OS_OS232 (3 << 16) /* VOS_OS232 */ +#define MD_VSFIXEDFILEINFO_FILE_OS_NT (4 << 16) /* VOS_NT */ +#define MD_VSFIXEDFILEINFO_FILE_OS_WINCE (5 << 16) /* VOS_WINCE */ +/* Low 16 bits */ +#define MD_VSFIXEDFILEINFO_FILE_OS__BASE 0 /* VOS__BASE */ +#define MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS16 1 /* VOS__WINDOWS16 */ +#define MD_VSFIXEDFILEINFO_FILE_OS__PM16 2 /* VOS__PM16 */ +#define MD_VSFIXEDFILEINFO_FILE_OS__PM32 3 /* VOS__PM32 */ +#define MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS32 4 /* VOS__WINDOWS32 */ + +/* For (MDVSFixedFileInfo).file_type */ +#define MD_VSFIXEDFILEINFO_FILE_TYPE_UNKNOWN 0 /* VFT_UNKNOWN */ +#define MD_VSFIXEDFILEINFO_FILE_TYPE_APP 1 /* VFT_APP */ +#define MD_VSFIXEDFILEINFO_FILE_TYPE_DLL 2 /* VFT_DLL */ +#define MD_VSFIXEDFILEINFO_FILE_TYPE_DRV 3 /* VFT_DLL */ +#define MD_VSFIXEDFILEINFO_FILE_TYPE_FONT 4 /* VFT_FONT */ +#define MD_VSFIXEDFILEINFO_FILE_TYPE_VXD 5 /* VFT_VXD */ +#define MD_VSFIXEDFILEINFO_FILE_TYPE_STATIC_LIB 7 /* VFT_STATIC_LIB */ + +/* For (MDVSFixedFileInfo).file_subtype */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN 0 + /* VFT2_UNKNOWN */ +/* with file_type = MD_VSFIXEDFILEINFO_FILETYPE_DRV */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_PRINTER 1 + /* VFT2_DRV_PRINTER */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_KEYBOARD 2 + /* VFT2_DRV_KEYBOARD */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_LANGUAGE 3 + /* VFT2_DRV_LANGUAGE */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_DISPLAY 4 + /* VFT2_DRV_DISPLAY */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_MOUSE 5 + /* VFT2_DRV_MOUSE */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_NETWORK 6 + /* VFT2_DRV_NETWORK */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_SYSTEM 7 + /* VFT2_DRV_SYSTEM */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_INSTALLABLE 8 + /* VFT2_DRV_INSTALLABLE */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_SOUND 9 + /* VFT2_DRV_SOUND */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_COMM 10 + /* VFT2_DRV_COMM */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_INPUTMETHOD 11 + /* VFT2_DRV_INPUTMETHOD */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_DRV_VERSIONED_PRINTER 12 + /* VFT2_DRV_VERSIONED_PRINTER */ +/* with file_type = MD_VSFIXEDFILEINFO_FILETYPE_FONT */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_RASTER 1 + /* VFT2_FONT_RASTER */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_VECTOR 2 + /* VFT2_FONT_VECTOR */ +#define MD_VSFIXEDFILEINFO_FILE_SUBTYPE_FONT_TRUETYPE 3 + /* VFT2_FONT_TRUETYPE */ + + +/* + * DbgHelp.h + */ + + +/* An MDRVA is an offset into the minidump file. The beginning of the + * MDRawHeader is at offset 0. */ +typedef uint32_t MDRVA; /* RVA */ + +typedef struct { + uint32_t data_size; + MDRVA rva; +} MDLocationDescriptor; /* MINIDUMP_LOCATION_DESCRIPTOR */ + + +typedef struct { + /* The base address of the memory range on the host that produced the + * minidump. */ + uint64_t start_of_memory_range; + + MDLocationDescriptor memory; +} MDMemoryDescriptor; /* MINIDUMP_MEMORY_DESCRIPTOR */ + + +typedef struct { + uint32_t signature; + uint32_t version; + uint32_t stream_count; + MDRVA stream_directory_rva; /* A |stream_count|-sized array of + * MDRawDirectory structures. */ + uint32_t checksum; /* Can be 0. In fact, that's all that's + * been found in minidump files. */ + uint32_t time_date_stamp; /* time_t */ + uint64_t flags; +} MDRawHeader; /* MINIDUMP_HEADER */ + +/* For (MDRawHeader).signature and (MDRawHeader).version. Note that only the + * low 16 bits of (MDRawHeader).version are MD_HEADER_VERSION. Per the + * documentation, the high 16 bits are implementation-specific. */ +#define MD_HEADER_SIGNATURE 0x504d444d /* 'PMDM' */ + /* MINIDUMP_SIGNATURE */ +#define MD_HEADER_VERSION 0x0000a793 /* 42899 */ + /* MINIDUMP_VERSION */ + +/* For (MDRawHeader).flags: */ +typedef enum { + /* MD_NORMAL is the standard type of minidump. It includes full + * streams for the thread list, module list, exception, system info, + * and miscellaneous info. A memory list stream is also present, + * pointing to the same stack memory contained in the thread list, + * as well as a 256-byte region around the instruction address that + * was executing when the exception occurred. Stack memory is from + * 4 bytes below a thread's stack pointer up to the top of the + * memory region encompassing the stack. */ + MD_NORMAL = 0x00000000, + MD_WITH_DATA_SEGS = 0x00000001, + MD_WITH_FULL_MEMORY = 0x00000002, + MD_WITH_HANDLE_DATA = 0x00000004, + MD_FILTER_MEMORY = 0x00000008, + MD_SCAN_MEMORY = 0x00000010, + MD_WITH_UNLOADED_MODULES = 0x00000020, + MD_WITH_INDIRECTLY_REFERENCED_MEMORY = 0x00000040, + MD_FILTER_MODULE_PATHS = 0x00000080, + MD_WITH_PROCESS_THREAD_DATA = 0x00000100, + MD_WITH_PRIVATE_READ_WRITE_MEMORY = 0x00000200, + MD_WITHOUT_OPTIONAL_DATA = 0x00000400, + MD_WITH_FULL_MEMORY_INFO = 0x00000800, + MD_WITH_THREAD_INFO = 0x00001000, + MD_WITH_CODE_SEGS = 0x00002000, + MD_WITHOUT_AUXILLIARY_SEGS = 0x00004000, + MD_WITH_FULL_AUXILLIARY_STATE = 0x00008000, + MD_WITH_PRIVATE_WRITE_COPY_MEMORY = 0x00010000, + MD_IGNORE_INACCESSIBLE_MEMORY = 0x00020000, + MD_WITH_TOKEN_INFORMATION = 0x00040000 +} MDType; /* MINIDUMP_TYPE */ + + +typedef struct { + uint32_t stream_type; + MDLocationDescriptor location; +} MDRawDirectory; /* MINIDUMP_DIRECTORY */ + +/* For (MDRawDirectory).stream_type */ +typedef enum { + MD_UNUSED_STREAM = 0, + MD_RESERVED_STREAM_0 = 1, + MD_RESERVED_STREAM_1 = 2, + MD_THREAD_LIST_STREAM = 3, /* MDRawThreadList */ + MD_MODULE_LIST_STREAM = 4, /* MDRawModuleList */ + MD_MEMORY_LIST_STREAM = 5, /* MDRawMemoryList */ + MD_EXCEPTION_STREAM = 6, /* MDRawExceptionStream */ + MD_SYSTEM_INFO_STREAM = 7, /* MDRawSystemInfo */ + MD_THREAD_EX_LIST_STREAM = 8, + MD_MEMORY_64_LIST_STREAM = 9, + MD_COMMENT_STREAM_A = 10, + MD_COMMENT_STREAM_W = 11, + MD_HANDLE_DATA_STREAM = 12, + MD_FUNCTION_TABLE_STREAM = 13, + MD_UNLOADED_MODULE_LIST_STREAM = 14, + MD_MISC_INFO_STREAM = 15, /* MDRawMiscInfo */ + MD_MEMORY_INFO_LIST_STREAM = 16, /* MDRawMemoryInfoList */ + MD_THREAD_INFO_LIST_STREAM = 17, + MD_HANDLE_OPERATION_LIST_STREAM = 18, + MD_LAST_RESERVED_STREAM = 0x0000ffff, + + /* Breakpad extension types. 0x4767 = "Gg" */ + MD_BREAKPAD_INFO_STREAM = 0x47670001, /* MDRawBreakpadInfo */ + MD_ASSERTION_INFO_STREAM = 0x47670002, /* MDRawAssertionInfo */ + /* These are additional minidump stream values which are specific to + * the linux breakpad implementation. */ + MD_LINUX_CPU_INFO = 0x47670003, /* /proc/cpuinfo */ + MD_LINUX_PROC_STATUS = 0x47670004, /* /proc/$x/status */ + MD_LINUX_LSB_RELEASE = 0x47670005, /* /etc/lsb-release */ + MD_LINUX_CMD_LINE = 0x47670006, /* /proc/$x/cmdline */ + MD_LINUX_ENVIRON = 0x47670007, /* /proc/$x/environ */ + MD_LINUX_AUXV = 0x47670008, /* /proc/$x/auxv */ + MD_LINUX_MAPS = 0x47670009, /* /proc/$x/maps */ + MD_LINUX_DSO_DEBUG = 0x4767000A /* MDRawDebug{32,64} */ +} MDStreamType; /* MINIDUMP_STREAM_TYPE */ + + +typedef struct { + uint32_t length; /* Length of buffer in bytes (not characters), + * excluding 0-terminator */ + uint16_t buffer[1]; /* UTF-16-encoded, 0-terminated */ +} MDString; /* MINIDUMP_STRING */ + +static const size_t MDString_minsize = offsetof(MDString, buffer[0]); + + +typedef struct { + uint32_t thread_id; + uint32_t suspend_count; + uint32_t priority_class; + uint32_t priority; + uint64_t teb; /* Thread environment block */ + MDMemoryDescriptor stack; + MDLocationDescriptor thread_context; /* MDRawContext[CPU] */ +} MDRawThread; /* MINIDUMP_THREAD */ + + +typedef struct { + uint32_t number_of_threads; + MDRawThread threads[1]; +} MDRawThreadList; /* MINIDUMP_THREAD_LIST */ + +static const size_t MDRawThreadList_minsize = offsetof(MDRawThreadList, + threads[0]); + + +typedef struct { + uint64_t base_of_image; + uint32_t size_of_image; + uint32_t checksum; /* 0 if unknown */ + uint32_t time_date_stamp; /* time_t */ + MDRVA module_name_rva; /* MDString, pathname or filename */ + MDVSFixedFileInfo version_info; + + /* The next field stores a CodeView record and is populated when a module's + * debug information resides in a PDB file. It identifies the PDB file. */ + MDLocationDescriptor cv_record; + + /* The next field is populated when a module's debug information resides + * in a DBG file. It identifies the DBG file. This field is effectively + * obsolete with modules built by recent toolchains. */ + MDLocationDescriptor misc_record; + + /* Alignment problem: reserved0 and reserved1 are defined by the platform + * SDK as 64-bit quantities. However, that results in a structure whose + * alignment is unpredictable on different CPUs and ABIs. If the ABI + * specifies full alignment of 64-bit quantities in structures (as ppc + * does), there will be padding between miscRecord and reserved0. If + * 64-bit quantities can be aligned on 32-bit boundaries (as on x86), + * this padding will not exist. (Note that the structure up to this point + * contains 1 64-bit member followed by 21 32-bit members.) + * As a workaround, reserved0 and reserved1 are instead defined here as + * four 32-bit quantities. This should be harmless, as there are + * currently no known uses for these fields. */ + uint32_t reserved0[2]; + uint32_t reserved1[2]; +} MDRawModule; /* MINIDUMP_MODULE */ + +/* The inclusion of a 64-bit type in MINIDUMP_MODULE forces the struct to + * be tail-padded out to a multiple of 64 bits under some ABIs (such as PPC). + * This doesn't occur on systems that don't tail-pad in this manner. Define + * this macro to be the usable size of the MDRawModule struct, and use it in + * place of sizeof(MDRawModule). */ +#define MD_MODULE_SIZE 108 + + +/* (MDRawModule).cv_record can reference MDCVInfoPDB20 or MDCVInfoPDB70. + * Ref.: http://www.debuginfo.com/articles/debuginfomatch.html + * MDCVInfoPDB70 is the expected structure type with recent toolchains. */ + +typedef struct { + uint32_t signature; + uint32_t offset; /* Offset to debug data (expect 0 in minidump) */ +} MDCVHeader; + +typedef struct { + MDCVHeader cv_header; + uint32_t signature; /* time_t debug information created */ + uint32_t age; /* revision of PDB file */ + uint8_t pdb_file_name[1]; /* Pathname or filename of PDB file */ +} MDCVInfoPDB20; + +static const size_t MDCVInfoPDB20_minsize = offsetof(MDCVInfoPDB20, + pdb_file_name[0]); + +#define MD_CVINFOPDB20_SIGNATURE 0x3031424e /* cvHeader.signature = '01BN' */ + +typedef struct { + uint32_t cv_signature; + MDGUID signature; /* GUID, identifies PDB file */ + uint32_t age; /* Identifies incremental changes to PDB file */ + uint8_t pdb_file_name[1]; /* Pathname or filename of PDB file, + * 0-terminated 8-bit character data (UTF-8?) */ +} MDCVInfoPDB70; + +static const size_t MDCVInfoPDB70_minsize = offsetof(MDCVInfoPDB70, + pdb_file_name[0]); + +#define MD_CVINFOPDB70_SIGNATURE 0x53445352 /* cvSignature = 'SDSR' */ + +typedef struct { + uint32_t data1[2]; + uint32_t data2; + uint32_t data3; + uint32_t data4; + uint32_t data5[3]; + uint8_t extra[2]; +} MDCVInfoELF; + +/* In addition to the two CodeView record formats above, used for linking + * to external pdb files, it is possible for debugging data to be carried + * directly in the CodeView record itself. These signature values will + * be found in the first 4 bytes of the CodeView record. Additional values + * not commonly experienced in the wild are given by "Microsoft Symbol and + * Type Information", http://www.x86.org/ftp/manuals/tools/sym.pdf, section + * 7.2. An in-depth description of the CodeView 4.1 format is given by + * "Undocumented Windows 2000 Secrets", Windows 2000 Debugging Support/ + * Microsoft Symbol File Internals/CodeView Subsections, + * http://www.rawol.com/features/undocumented/sbs-w2k-1-windows-2000-debugging-support.pdf + */ +#define MD_CVINFOCV41_SIGNATURE 0x3930424e /* '90BN', CodeView 4.10. */ +#define MD_CVINFOCV50_SIGNATURE 0x3131424e /* '11BN', CodeView 5.0, + * MS C7-format (/Z7). */ + +#define MD_CVINFOUNKNOWN_SIGNATURE 0xffffffff /* An unlikely value. */ + +/* (MDRawModule).miscRecord can reference MDImageDebugMisc. The Windows + * structure is actually defined in WinNT.h. This structure is effectively + * obsolete with modules built by recent toolchains. */ + +typedef struct { + uint32_t data_type; /* IMAGE_DEBUG_TYPE_*, not defined here because + * this debug record type is mostly obsolete. */ + uint32_t length; /* Length of entire MDImageDebugMisc structure */ + uint8_t unicode; /* True if data is multibyte */ + uint8_t reserved[3]; + uint8_t data[1]; +} MDImageDebugMisc; /* IMAGE_DEBUG_MISC */ + +static const size_t MDImageDebugMisc_minsize = offsetof(MDImageDebugMisc, + data[0]); + + +typedef struct { + uint32_t number_of_modules; + MDRawModule modules[1]; +} MDRawModuleList; /* MINIDUMP_MODULE_LIST */ + +static const size_t MDRawModuleList_minsize = offsetof(MDRawModuleList, + modules[0]); + + +typedef struct { + uint32_t number_of_memory_ranges; + MDMemoryDescriptor memory_ranges[1]; +} MDRawMemoryList; /* MINIDUMP_MEMORY_LIST */ + +static const size_t MDRawMemoryList_minsize = offsetof(MDRawMemoryList, + memory_ranges[0]); + + +#define MD_EXCEPTION_MAXIMUM_PARAMETERS 15 + +typedef struct { + uint32_t exception_code; /* Windows: MDExceptionCodeWin, + * Mac OS X: MDExceptionMac, + * Linux: MDExceptionCodeLinux. */ + uint32_t exception_flags; /* Windows: 1 if noncontinuable, + Mac OS X: MDExceptionCodeMac. */ + uint64_t exception_record; /* Address (in the minidump-producing host's + * memory) of another MDException, for + * nested exceptions. */ + uint64_t exception_address; /* The address that caused the exception. + * Mac OS X: exception subcode (which is + * typically the address). */ + uint32_t number_parameters; /* Number of valid elements in + * exception_information. */ + uint32_t __align; + uint64_t exception_information[MD_EXCEPTION_MAXIMUM_PARAMETERS]; +} MDException; /* MINIDUMP_EXCEPTION */ + +#include "minidump_exception_linux.h" +#include "minidump_exception_mac.h" +#include "minidump_exception_ps3.h" +#include "minidump_exception_solaris.h" +#include "minidump_exception_win32.h" + +typedef struct { + uint32_t thread_id; /* Thread in which the exception + * occurred. Corresponds to + * (MDRawThread).thread_id. */ + uint32_t __align; + MDException exception_record; + MDLocationDescriptor thread_context; /* MDRawContext[CPU] */ +} MDRawExceptionStream; /* MINIDUMP_EXCEPTION_STREAM */ + + +typedef union { + struct { + uint32_t vendor_id[3]; /* cpuid 0: ebx, edx, ecx */ + uint32_t version_information; /* cpuid 1: eax */ + uint32_t feature_information; /* cpuid 1: edx */ + uint32_t amd_extended_cpu_features; /* cpuid 0x80000001, ebx */ + } x86_cpu_info; + struct { + uint32_t cpuid; + uint32_t elf_hwcaps; /* linux specific, 0 otherwise */ + } arm_cpu_info; + struct { + uint64_t processor_features[2]; + } other_cpu_info; +} MDCPUInformation; /* CPU_INFORMATION */ + +/* For (MDCPUInformation).arm_cpu_info.elf_hwcaps. + * This matches the Linux kernel definitions from */ +typedef enum { + MD_CPU_ARM_ELF_HWCAP_SWP = (1 << 0), + MD_CPU_ARM_ELF_HWCAP_HALF = (1 << 1), + MD_CPU_ARM_ELF_HWCAP_THUMB = (1 << 2), + MD_CPU_ARM_ELF_HWCAP_26BIT = (1 << 3), + MD_CPU_ARM_ELF_HWCAP_FAST_MULT = (1 << 4), + MD_CPU_ARM_ELF_HWCAP_FPA = (1 << 5), + MD_CPU_ARM_ELF_HWCAP_VFP = (1 << 6), + MD_CPU_ARM_ELF_HWCAP_EDSP = (1 << 7), + MD_CPU_ARM_ELF_HWCAP_JAVA = (1 << 8), + MD_CPU_ARM_ELF_HWCAP_IWMMXT = (1 << 9), + MD_CPU_ARM_ELF_HWCAP_CRUNCH = (1 << 10), + MD_CPU_ARM_ELF_HWCAP_THUMBEE = (1 << 11), + MD_CPU_ARM_ELF_HWCAP_NEON = (1 << 12), + MD_CPU_ARM_ELF_HWCAP_VFPv3 = (1 << 13), + MD_CPU_ARM_ELF_HWCAP_VFPv3D16 = (1 << 14), + MD_CPU_ARM_ELF_HWCAP_TLS = (1 << 15), + MD_CPU_ARM_ELF_HWCAP_VFPv4 = (1 << 16), + MD_CPU_ARM_ELF_HWCAP_IDIVA = (1 << 17), + MD_CPU_ARM_ELF_HWCAP_IDIVT = (1 << 18), +} MDCPUInformationARMElfHwCaps; + +typedef struct { + /* The next 3 fields and numberOfProcessors are from the SYSTEM_INFO + * structure as returned by GetSystemInfo */ + uint16_t processor_architecture; + uint16_t processor_level; /* x86: 5 = 586, 6 = 686, ... */ + /* ARM: 6 = ARMv6, 7 = ARMv7 ... */ + uint16_t processor_revision; /* x86: 0xMMSS, where MM=model, + * SS=stepping */ + /* ARM: 0 */ + + uint8_t number_of_processors; + uint8_t product_type; /* Windows: VER_NT_* from WinNT.h */ + + /* The next 5 fields are from the OSVERSIONINFO structure as returned + * by GetVersionEx */ + uint32_t major_version; + uint32_t minor_version; + uint32_t build_number; + uint32_t platform_id; + MDRVA csd_version_rva; /* MDString further identifying the + * host OS. + * Windows: name of the installed OS + * service pack. + * Mac OS X: the Apple OS build number + * (sw_vers -buildVersion). + * Linux: uname -srvmo */ + + uint16_t suite_mask; /* Windows: VER_SUITE_* from WinNT.h */ + uint16_t reserved2; + + MDCPUInformation cpu; +} MDRawSystemInfo; /* MINIDUMP_SYSTEM_INFO */ + +/* For (MDRawSystemInfo).processor_architecture: */ +typedef enum { + MD_CPU_ARCHITECTURE_X86 = 0, /* PROCESSOR_ARCHITECTURE_INTEL */ + MD_CPU_ARCHITECTURE_MIPS = 1, /* PROCESSOR_ARCHITECTURE_MIPS */ + MD_CPU_ARCHITECTURE_ALPHA = 2, /* PROCESSOR_ARCHITECTURE_ALPHA */ + MD_CPU_ARCHITECTURE_PPC = 3, /* PROCESSOR_ARCHITECTURE_PPC */ + MD_CPU_ARCHITECTURE_SHX = 4, /* PROCESSOR_ARCHITECTURE_SHX + * (Super-H) */ + MD_CPU_ARCHITECTURE_ARM = 5, /* PROCESSOR_ARCHITECTURE_ARM */ + MD_CPU_ARCHITECTURE_IA64 = 6, /* PROCESSOR_ARCHITECTURE_IA64 */ + MD_CPU_ARCHITECTURE_ALPHA64 = 7, /* PROCESSOR_ARCHITECTURE_ALPHA64 */ + MD_CPU_ARCHITECTURE_MSIL = 8, /* PROCESSOR_ARCHITECTURE_MSIL + * (Microsoft Intermediate Language) */ + MD_CPU_ARCHITECTURE_AMD64 = 9, /* PROCESSOR_ARCHITECTURE_AMD64 */ + MD_CPU_ARCHITECTURE_X86_WIN64 = 10, + /* PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 (WoW64) */ + MD_CPU_ARCHITECTURE_SPARC = 0x8001, /* Breakpad-defined value for SPARC */ + MD_CPU_ARCHITECTURE_PPC64 = 0x8002, /* Breakpad-defined value for PPC64 */ + MD_CPU_ARCHITECTURE_ARM64 = 0x8003, /* Breakpad-defined value for ARM64 */ + MD_CPU_ARCHITECTURE_UNKNOWN = 0xffff /* PROCESSOR_ARCHITECTURE_UNKNOWN */ +} MDCPUArchitecture; + +/* For (MDRawSystemInfo).platform_id: */ +typedef enum { + MD_OS_WIN32S = 0, /* VER_PLATFORM_WIN32s (Windows 3.1) */ + MD_OS_WIN32_WINDOWS = 1, /* VER_PLATFORM_WIN32_WINDOWS (Windows 95-98-Me) */ + MD_OS_WIN32_NT = 2, /* VER_PLATFORM_WIN32_NT (Windows NT, 2000+) */ + MD_OS_WIN32_CE = 3, /* VER_PLATFORM_WIN32_CE, VER_PLATFORM_WIN32_HH + * (Windows CE, Windows Mobile, "Handheld") */ + + /* The following values are Breakpad-defined. */ + MD_OS_UNIX = 0x8000, /* Generic Unix-ish */ + MD_OS_MAC_OS_X = 0x8101, /* Mac OS X/Darwin */ + MD_OS_IOS = 0x8102, /* iOS */ + MD_OS_LINUX = 0x8201, /* Linux */ + MD_OS_SOLARIS = 0x8202, /* Solaris */ + MD_OS_ANDROID = 0x8203, /* Android */ + MD_OS_PS3 = 0x8204, /* PS3 */ + MD_OS_NACL = 0x8205 /* Native Client (NaCl) */ +} MDOSPlatform; + +typedef struct { + uint16_t year; + uint16_t month; + uint16_t day_of_week; + uint16_t day; + uint16_t hour; + uint16_t minute; + uint16_t second; + uint16_t milliseconds; +} MDSystemTime; /* SYSTEMTIME */ + +typedef struct { + /* Required field. The bias is the difference, in minutes, between + * Coordinated Universal Time (UTC) and local time. + * Formula: UTC = local time + bias */ + int32_t bias; + /* A description for standard time. For example, "EST" could indicate Eastern + * Standard Time. In practice this contains the full time zone names. This + * string can be empty. */ + uint16_t standard_name[32]; /* UTF-16-encoded, 0-terminated */ + /* A MDSystemTime structure that contains a date and local time when the + * transition from daylight saving time to standard time occurs on this + * operating system. If the time zone does not support daylight saving time, + * the month member in the MDSystemTime structure is zero. */ + MDSystemTime standard_date; + /* The bias value to be used during local time translations that occur during + * standard time. */ + int32_t standard_bias; + /* A description for daylight saving time. For example, "PDT" could indicate + * Pacific Daylight Time. In practice this contains the full time zone names. + * This string can be empty. */ + uint16_t daylight_name[32]; /* UTF-16-encoded, 0-terminated */ + /* A MDSystemTime structure that contains a date and local time when the + * transition from standard time to daylight saving time occurs on this + * operating system. If the time zone does not support daylight saving time, + * the month member in the MDSystemTime structure is zero.*/ + MDSystemTime daylight_date; + /* The bias value to be used during local time translations that occur during + * daylight saving time. */ + int32_t daylight_bias; +} MDTimeZoneInformation; /* TIME_ZONE_INFORMATION */ + +/* MAX_PATH from windef.h */ +#define MD_MAX_PATH 260 + +/* The miscellaneous information stream contains a variety + * of small pieces of information. A member is valid if + * it's within the available size and its corresponding + * bit is set. */ +typedef struct { + uint32_t size_of_info; /* Length of entire MDRawMiscInfo structure. */ + uint32_t flags1; + + /* The next field is only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROCESS_ID. */ + uint32_t process_id; + + /* The next 3 fields are only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROCESS_TIMES. */ + uint32_t process_create_time; /* time_t process started */ + uint32_t process_user_time; /* seconds of user CPU time */ + uint32_t process_kernel_time; /* seconds of kernel CPU time */ + + /* The following fields are not present in MINIDUMP_MISC_INFO but are + * in MINIDUMP_MISC_INFO_2. When this struct is populated, these values + * may not be set. Use flags1 and size_of_info to determine whether these + * values are present. These are only valid when flags1 contains + * MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO. */ + uint32_t processor_max_mhz; + uint32_t processor_current_mhz; + uint32_t processor_mhz_limit; + uint32_t processor_max_idle_state; + uint32_t processor_current_idle_state; + + /* The following fields are not present in MINIDUMP_MISC_INFO_2 but are + * in MINIDUMP_MISC_INFO_3. When this struct is populated, these values + * may not be set. Use flags1 and size_of_info to determine whether these + * values are present. */ + + /* The following field is only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROCESS_INTEGRITY. */ + uint32_t process_integrity_level; + + /* The following field is only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROCESS_EXECUTE_FLAGS. */ + uint32_t process_execute_flags; + + /* The following field is only valid if flags1 contains + * MD_MISCINFO_FLAGS1_PROTECTED_PROCESS. */ + uint32_t protected_process; + + /* The following 2 fields are only valid if flags1 contains + * MD_MISCINFO_FLAGS1_TIMEZONE. */ + uint32_t time_zone_id; + MDTimeZoneInformation time_zone; + + /* The following fields are not present in MINIDUMP_MISC_INFO_3 but are + * in MINIDUMP_MISC_INFO_4. When this struct is populated, these values + * may not be set. Use flags1 and size_of_info to determine whether these + * values are present. */ + + /* The following 2 fields are only valid if flags1 contains + * MD_MISCINFO_FLAGS1_BUILDSTRING. */ + uint16_t build_string[MD_MAX_PATH]; /* UTF-16-encoded, 0-terminated */ + uint16_t dbg_bld_str[40]; /* UTF-16-encoded, 0-terminated */ +} MDRawMiscInfo; /* MINIDUMP_MISC_INFO, MINIDUMP_MISC_INFO_2, + * MINIDUMP_MISC_INFO_3, MINIDUMP_MISC_INFO_4, + * MINIDUMP_MISC_INFO_N */ + +static const size_t MD_MISCINFO_SIZE = + offsetof(MDRawMiscInfo, processor_max_mhz); +static const size_t MD_MISCINFO2_SIZE = + offsetof(MDRawMiscInfo, process_integrity_level); +static const size_t MD_MISCINFO3_SIZE = + offsetof(MDRawMiscInfo, build_string[0]); +static const size_t MD_MISCINFO4_SIZE = sizeof(MDRawMiscInfo); + +/* For (MDRawMiscInfo).flags1. These values indicate which fields in the + * MDRawMiscInfoStructure are valid. */ +typedef enum { + MD_MISCINFO_FLAGS1_PROCESS_ID = 0x00000001, + /* MINIDUMP_MISC1_PROCESS_ID */ + MD_MISCINFO_FLAGS1_PROCESS_TIMES = 0x00000002, + /* MINIDUMP_MISC1_PROCESS_TIMES */ + MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO = 0x00000004, + /* MINIDUMP_MISC1_PROCESSOR_POWER_INFO */ + MD_MISCINFO_FLAGS1_PROCESS_INTEGRITY = 0x00000010, + /* MINIDUMP_MISC3_PROCESS_INTEGRITY */ + MD_MISCINFO_FLAGS1_PROCESS_EXECUTE_FLAGS = 0x00000020, + /* MINIDUMP_MISC3_PROCESS_EXECUTE_FLAGS */ + MD_MISCINFO_FLAGS1_TIMEZONE = 0x00000040, + /* MINIDUMP_MISC3_TIMEZONE */ + MD_MISCINFO_FLAGS1_PROTECTED_PROCESS = 0x00000080, + /* MINIDUMP_MISC3_PROTECTED_PROCESS */ + MD_MISCINFO_FLAGS1_BUILDSTRING = 0x00000100, + /* MINIDUMP_MISC4_BUILDSTRING */ +} MDMiscInfoFlags1; + +/* + * Around DbgHelp version 6.0, the style of new LIST structures changed + * from including an array of length 1 at the end of the struct to + * represent the variable-length data to including explicit + * "size of header", "size of entry" and "number of entries" fields + * in the header, presumably to allow backwards-compatibly-extending + * the structures in the future. The actual list entries follow the + * header data directly in this case. + */ + +typedef struct { + uint32_t size_of_header; /* sizeof(MDRawMemoryInfoList) */ + uint32_t size_of_entry; /* sizeof(MDRawMemoryInfo) */ + uint64_t number_of_entries; +} MDRawMemoryInfoList; /* MINIDUMP_MEMORY_INFO_LIST */ + +typedef struct { + uint64_t base_address; /* Base address of a region of pages */ + uint64_t allocation_base; /* Base address of a range of pages + * within this region. */ + uint32_t allocation_protection; /* Memory protection when this region + * was originally allocated: + * MDMemoryProtection */ + uint32_t __alignment1; + uint64_t region_size; + uint32_t state; /* MDMemoryState */ + uint32_t protection; /* MDMemoryProtection */ + uint32_t type; /* MDMemoryType */ + uint32_t __alignment2; +} MDRawMemoryInfo; /* MINIDUMP_MEMORY_INFO */ + +/* For (MDRawMemoryInfo).state */ +typedef enum { + MD_MEMORY_STATE_COMMIT = 0x1000, /* physical storage has been allocated */ + MD_MEMORY_STATE_RESERVE = 0x2000, /* reserved, but no physical storage */ + MD_MEMORY_STATE_FREE = 0x10000 /* available to be allocated */ +} MDMemoryState; + +/* For (MDRawMemoryInfo).allocation_protection and .protection */ +typedef enum { + MD_MEMORY_PROTECT_NOACCESS = 0x01, /* PAGE_NOACCESS */ + MD_MEMORY_PROTECT_READONLY = 0x02, /* PAGE_READONLY */ + MD_MEMORY_PROTECT_READWRITE = 0x04, /* PAGE_READWRITE */ + MD_MEMORY_PROTECT_WRITECOPY = 0x08, /* PAGE_WRITECOPY */ + MD_MEMORY_PROTECT_EXECUTE = 0x10, /* PAGE_EXECUTE */ + MD_MEMORY_PROTECT_EXECUTE_READ = 0x20, /* PAGE_EXECUTE_READ */ + MD_MEMORY_PROTECT_EXECUTE_READWRITE = 0x40, /* PAGE_EXECUTE_READWRITE */ + MD_MEMORY_PROTECT_EXECUTE_WRITECOPY = 0x80, /* PAGE_EXECUTE_WRITECOPY */ + /* These options can be combined with the previous flags. */ + MD_MEMORY_PROTECT_GUARD = 0x100, /* PAGE_GUARD */ + MD_MEMORY_PROTECT_NOCACHE = 0x200, /* PAGE_NOCACHE */ + MD_MEMORY_PROTECT_WRITECOMBINE = 0x400, /* PAGE_WRITECOMBINE */ +} MDMemoryProtection; + +/* Used to mask the mutually exclusive options from the combinable flags. */ +const uint32_t MD_MEMORY_PROTECTION_ACCESS_MASK = 0xFF; + +/* For (MDRawMemoryInfo).type */ +typedef enum { + MD_MEMORY_TYPE_PRIVATE = 0x20000, /* not shared by other processes */ + MD_MEMORY_TYPE_MAPPED = 0x40000, /* mapped into the view of a section */ + MD_MEMORY_TYPE_IMAGE = 0x1000000 /* mapped into the view of an image */ +} MDMemoryType; + +/* + * Breakpad extension types + */ + + +typedef struct { + /* validity is a bitmask with values from MDBreakpadInfoValidity, indicating + * which of the other fields in the structure are valid. */ + uint32_t validity; + + /* Thread ID of the handler thread. dump_thread_id should correspond to + * the thread_id of an MDRawThread in the minidump's MDRawThreadList if + * a dedicated thread in that list was used to produce the minidump. If + * the MDRawThreadList does not contain a dedicated thread used to produce + * the minidump, this field should be set to 0 and the validity field + * must not contain MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID. */ + uint32_t dump_thread_id; + + /* Thread ID of the thread that requested the minidump be produced. As + * with dump_thread_id, requesting_thread_id should correspond to the + * thread_id of an MDRawThread in the minidump's MDRawThreadList. For + * minidumps produced as a result of an exception, requesting_thread_id + * will be the same as the MDRawExceptionStream's thread_id field. For + * minidumps produced "manually" at the program's request, + * requesting_thread_id will indicate which thread caused the dump to be + * written. If the minidump was produced at the request of something + * other than a thread in the MDRawThreadList, this field should be set + * to 0 and the validity field must not contain + * MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID. */ + uint32_t requesting_thread_id; +} MDRawBreakpadInfo; + +/* For (MDRawBreakpadInfo).validity: */ +typedef enum { + /* When set, the dump_thread_id field is valid. */ + MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID = 1 << 0, + + /* When set, the requesting_thread_id field is valid. */ + MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID = 1 << 1 +} MDBreakpadInfoValidity; + +typedef struct { + /* expression, function, and file are 0-terminated UTF-16 strings. They + * may be truncated if necessary, but should always be 0-terminated when + * written to a file. + * Fixed-length strings are used because MiniDumpWriteDump doesn't offer + * a way for user streams to point to arbitrary RVAs for strings. */ + uint16_t expression[128]; /* Assertion that failed... */ + uint16_t function[128]; /* ...within this function... */ + uint16_t file[128]; /* ...in this file... */ + uint32_t line; /* ...at this line. */ + uint32_t type; +} MDRawAssertionInfo; + +/* For (MDRawAssertionInfo).type: */ +typedef enum { + MD_ASSERTION_INFO_TYPE_UNKNOWN = 0, + + /* Used for assertions that would be raised by the MSVC CRT but are + * directed to an invalid parameter handler instead. */ + MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER, + + /* Used for assertions that would be raised by the MSVC CRT but are + * directed to a pure virtual call handler instead. */ + MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL +} MDAssertionInfoData; + +/* These structs are used to store the DSO debug data in Linux minidumps, + * which is necessary for converting minidumps to usable coredumps. + * Because of a historical accident, several fields are variably encoded + * according to client word size, so tools potentially need to support both. */ + +typedef struct { + uint32_t addr; + MDRVA name; + uint32_t ld; +} MDRawLinkMap32; + +typedef struct { + uint32_t version; + MDRVA map; /* array of MDRawLinkMap32 */ + uint32_t dso_count; + uint32_t brk; + uint32_t ldbase; + uint32_t dynamic; +} MDRawDebug32; + +typedef struct { + uint64_t addr; + MDRVA name; + uint64_t ld; +} MDRawLinkMap64; + +typedef struct { + uint32_t version; + MDRVA map; /* array of MDRawLinkMap64 */ + uint32_t dso_count; + uint64_t brk; + uint64_t ldbase; + uint64_t dynamic; +} MDRawDebug64; + +#if defined(_MSC_VER) +#pragma warning(pop) +#endif /* _MSC_VER */ + + +#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_FORMAT_H__ */ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_size.h b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_size.h new file mode 100644 index 00000000..918544b6 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/common/minidump_size.h @@ -0,0 +1,107 @@ +// Copyright (c) 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. */ + +// minidump_size.h: Provides a C++ template for programmatic access to +// the sizes of various types defined in minidump_format.h. +// +// Author: Mark Mentovai + +#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__ +#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__ + +#include + +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +template +class minidump_size { + public: + static size_t size() { return sizeof(T); } +}; + +// Explicit specializations for variable-length types. The size returned +// for these should be the size for an object without its variable-length +// section. + +template<> +class minidump_size { + public: + static size_t size() { return MDString_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDRawThreadList_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDCVInfoPDB20_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDCVInfoPDB70_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDImageDebugMisc_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDRawModuleList_minsize; } +}; + +template<> +class minidump_size { + public: + static size_t size() { return MDRawMemoryList_minsize; } +}; + +// Explicit specialization for MDRawModule, for which sizeof may include +// tail-padding on some architectures but not others. + +template<> +class minidump_size { + public: + static size_t size() { return MD_MODULE_SIZE; } +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_SIZE_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/basic_source_line_resolver.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/basic_source_line_resolver.h new file mode 100644 index 00000000..6bb6d863 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/basic_source_line_resolver.h @@ -0,0 +1,144 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// basic_source_line_resolver.h: BasicSourceLineResolver is derived from +// SourceLineResolverBase, and is a concrete implementation of +// SourceLineResolverInterface, using address map files produced by a +// compatible writer, e.g. PDBSourceLineWriter. +// +// see "processor/source_line_resolver_base.h" +// and "source_line_resolver_interface.h" for more documentation. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_H__ + +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/processor/source_line_resolver_base.h" + +namespace google_breakpad { + +using std::map; + +class BasicSourceLineResolver : public SourceLineResolverBase { + public: + BasicSourceLineResolver(); + virtual ~BasicSourceLineResolver() { } + + using SourceLineResolverBase::LoadModule; + using SourceLineResolverBase::LoadModuleUsingMapBuffer; + using SourceLineResolverBase::LoadModuleUsingMemoryBuffer; + using SourceLineResolverBase::ShouldDeleteMemoryBufferAfterLoadModule; + using SourceLineResolverBase::UnloadModule; + using SourceLineResolverBase::HasModule; + using SourceLineResolverBase::IsModuleCorrupt; + using SourceLineResolverBase::FillSourceLineInfo; + using SourceLineResolverBase::FindWindowsFrameInfo; + using SourceLineResolverBase::FindCFIFrameInfo; + + private: + // friend declarations: + friend class BasicModuleFactory; + friend class ModuleComparer; + friend class ModuleSerializer; + template friend class SimpleSerializer; + + // Function derives from SourceLineResolverBase::Function. + struct Function; + // Module implements SourceLineResolverBase::Module interface. + class Module; + + // Disallow unwanted copy ctor and assignment operator + BasicSourceLineResolver(const BasicSourceLineResolver&); + void operator=(const BasicSourceLineResolver&); +}; + +// Helper class, containing useful methods for parsing of Breakpad symbol files. +class SymbolParseHelper { + public: + // Parses a |file_line| declaration. Returns true on success. + // Format: FILE . + // Notice, that this method modifies the input |file_line| which is why it + // can't be const. On success, , and are stored in |*index|, + // and |*filename|. No allocation is done, |*filename| simply points inside + // |file_line|. + static bool ParseFile(char *file_line, // in + long *index, // out + char **filename); // out + + // Parses a |function_line| declaration. Returns true on success. + // Format: FUNC
. + // Notice, that this method modifies the input |function_line| which is why it + // can't be const. On success,
, , , and + // are stored in |*address|, |*size|, |*stack_param_size|, and |*name|. + // No allocation is done, |*name| simply points inside |function_line|. + static bool ParseFunction(char *function_line, // in + uint64_t *address, // out + uint64_t *size, // out + long *stack_param_size, // out + char **name); // out + + // Parses a |line| declaration. Returns true on success. + // Format:
+ // Notice, that this method modifies the input |function_line| which is why + // it can't be const. On success,
, , , and + // are stored in |*address|, |*size|, |*line_number|, and + // |*source_file|. + static bool ParseLine(char *line_line, // in + uint64_t *address, // out + uint64_t *size, // out + long *line_number, // out + long *source_file); // out + + // Parses a |public_line| declaration. Returns true on success. + // Format: PUBLIC
+ // Notice, that this method modifies the input |function_line| which is why + // it can't be const. On success,
, , + // are stored in |*address|, |*stack_param_size|, and |*name|. + // No allocation is done, |*name| simply points inside |public_line|. + static bool ParsePublicSymbol(char *public_line, // in + uint64_t *address, // out + long *stack_param_size, // out + char **name); // out + + private: + // Used for success checks after strtoull and strtol. + static bool IsValidAfterNumber(char *after_number); + + // Only allow static methods. + SymbolParseHelper(); + SymbolParseHelper(const SymbolParseHelper&); + void operator=(const SymbolParseHelper&); +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/call_stack.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/call_stack.h new file mode 100644 index 00000000..21f595e7 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/call_stack.h @@ -0,0 +1,77 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// call_stack.h: A call stack comprised of stack frames. +// +// This class manages a vector of stack frames. It is used instead of +// exposing the vector directly to allow the CallStack to own StackFrame +// pointers without having to publicly export the linked_ptr class. A +// CallStack must be composed of pointers instead of objects to allow for +// CPU-specific StackFrame subclasses. +// +// By convention, the stack frame at index 0 is the innermost callee frame, +// and the frame at the highest index in a call stack is the outermost +// caller. CallStack only allows stacks to be built by pushing frames, +// beginning with the innermost callee frame. +// +// Author: Mark Mentovai + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_CALL_STACK_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_CALL_STACK_H__ + +#include + +namespace google_breakpad { + +using std::vector; + +struct StackFrame; +template class linked_ptr; + +class CallStack { + public: + CallStack() { Clear(); } + ~CallStack(); + + // Resets the CallStack to its initial empty state + void Clear(); + + const vector* frames() const { return &frames_; } + + private: + // Stackwalker is responsible for building the frames_ vector. + friend class Stackwalker; + + // Storage for pushed frames. + vector frames_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCSSOR_CALL_STACK_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/code_module.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/code_module.h new file mode 100644 index 00000000..4e892824 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/code_module.h @@ -0,0 +1,94 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// code_module.h: Carries information about code modules that are loaded +// into a process. +// +// Author: Mark Mentovai + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULE_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULE_H__ + +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +class CodeModule { + public: + virtual ~CodeModule() {} + + // The base address of this code module as it was loaded by the process. + // (uint64_t)-1 on error. + virtual uint64_t base_address() const = 0; + + // The size of the code module. 0 on error. + virtual uint64_t size() const = 0; + + // The path or file name that the code module was loaded from. Empty on + // error. + virtual string code_file() const = 0; + + // An identifying string used to discriminate between multiple versions and + // builds of the same code module. This may contain a uuid, timestamp, + // version number, or any combination of this or other information, in an + // implementation-defined format. Empty on error. + virtual string code_identifier() const = 0; + + // The filename containing debugging information associated with the code + // module. If debugging information is stored in a file separate from the + // code module itself (as is the case when .pdb or .dSYM files are used), + // this will be different from code_file. If debugging information is + // stored in the code module itself (possibly prior to stripping), this + // will be the same as code_file. Empty on error. + virtual string debug_file() const = 0; + + // An identifying string similar to code_identifier, but identifies a + // specific version and build of the associated debug file. This may be + // the same as code_identifier when the debug_file and code_file are + // identical or when the same identifier is used to identify distinct + // debug and code files. + virtual string debug_identifier() const = 0; + + // A human-readable representation of the code module's version. Empty on + // error. + virtual string version() const = 0; + + // Creates a new copy of this CodeModule object, which the caller takes + // ownership of. The new CodeModule may be of a different concrete class + // than the CodeModule being copied, but will behave identically to the + // copied CodeModule as far as the CodeModule interface is concerned. + virtual const CodeModule* Copy() const = 0; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULE_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/code_modules.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/code_modules.h new file mode 100644 index 00000000..a38579af --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/code_modules.h @@ -0,0 +1,98 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// code_modules.h: Contains all of the CodeModule objects that were loaded +// into a single process. +// +// Author: Mark Mentovai + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULES_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULES_H__ + +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +class CodeModule; + +class CodeModules { + public: + virtual ~CodeModules() {} + + // The number of contained CodeModule objects. + virtual unsigned int module_count() const = 0; + + // Random access to modules. Returns the module whose code is present + // at the address indicated by |address|. If no module is present at this + // address, returns NULL. Ownership of the returned CodeModule is retained + // by the CodeModules object; pointers returned by this method are valid for + // comparison with pointers returned by the other Get methods. + virtual const CodeModule* GetModuleForAddress(uint64_t address) const = 0; + + // Returns the module corresponding to the main executable. If there is + // no main executable, returns NULL. Ownership of the returned CodeModule + // is retained by the CodeModules object; pointers returned by this method + // are valid for comparison with pointers returned by the other Get + // methods. + virtual const CodeModule* GetMainModule() const = 0; + + // Sequential access to modules. A sequence number of 0 corresponds to the + // module residing lowest in memory. If the sequence number is out of + // range, returns NULL. Ownership of the returned CodeModule is retained + // by the CodeModules object; pointers returned by this method are valid for + // comparison with pointers returned by the other Get methods. + virtual const CodeModule* GetModuleAtSequence( + unsigned int sequence) const = 0; + + // Sequential access to modules. This is similar to GetModuleAtSequence, + // except no ordering requirement is enforced. A CodeModules implementation + // may return CodeModule objects from GetModuleAtIndex in any order it + // wishes, provided that the order remain the same throughout the life of + // the CodeModules object. Typically, GetModuleAtIndex would be used by + // a caller to enumerate all CodeModule objects quickly when the enumeration + // does not require any ordering. If the index argument is out of range, + // returns NULL. Ownership of the returned CodeModule is retained by + // the CodeModules object; pointers returned by this method are valid for + // comparison with pointers returned by the other Get methods. + virtual const CodeModule* GetModuleAtIndex(unsigned int index) const = 0; + + // Creates a new copy of this CodeModules object, which the caller takes + // ownership of. The new object will also contain copies of the existing + // object's child CodeModule objects. The new CodeModules object may be of + // a different concrete class than the object being copied, but will behave + // identically to the copied object as far as the CodeModules and CodeModule + // interfaces are concerned, except that the order that GetModuleAtIndex + // returns objects in may differ between a copy and the original CodeModules + // object. + virtual const CodeModules* Copy() const = 0; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_CODE_MODULES_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/dump_context.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/dump_context.h new file mode 100644 index 00000000..df80bf7e --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/dump_context.h @@ -0,0 +1,116 @@ +// Copyright (c) 2014 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// dump_context.h: A (mini/micro) dump CPU-specific context. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_DUMP_CONTEXT_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_DUMP_CONTEXT_H__ + +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/dump_object.h" + +namespace google_breakpad { + +// DumpContext carries a CPU-specific MDRawContext structure, which contains CPU +// context such as register states. +class DumpContext : public DumpObject { + public: + virtual ~DumpContext(); + + // Returns an MD_CONTEXT_* value such as MD_CONTEXT_X86 or MD_CONTEXT_PPC + // identifying the CPU type that the context was collected from. The + // returned value will identify the CPU only, and will have any other + // MD_CONTEXT_* bits masked out. Returns 0 on failure. + uint32_t GetContextCPU() const; + + // Return the raw value of |context_flags_| + uint32_t GetContextFlags() const; + + // Returns raw CPU-specific context data for the named CPU type. If the + // context data does not match the CPU type or does not exist, returns NULL. + const MDRawContextAMD64* GetContextAMD64() const; + const MDRawContextARM* GetContextARM() const; + const MDRawContextARM64* GetContextARM64() const; + const MDRawContextMIPS* GetContextMIPS() const; + const MDRawContextPPC* GetContextPPC() const; + const MDRawContextPPC64* GetContextPPC64() const; + const MDRawContextSPARC* GetContextSPARC() const; + const MDRawContextX86* GetContextX86() const; + + // A convenience method to get the instruction pointer out of the + // MDRawContext, since it varies per-CPU architecture. + bool GetInstructionPointer(uint64_t* ip) const; + + // Similar to the GetInstructionPointer method, this method gets the stack + // pointer for all CPU architectures. + bool GetStackPointer(uint64_t* sp) const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + protected: + DumpContext(); + + // Sets row CPU-specific context data for the names CPU type. + void SetContextFlags(uint32_t context_flags); + void SetContextX86(MDRawContextX86* x86); + void SetContextPPC(MDRawContextPPC* ppc); + void SetContextPPC64(MDRawContextPPC64* ppc64); + void SetContextAMD64(MDRawContextAMD64* amd64); + void SetContextSPARC(MDRawContextSPARC* ctx_sparc); + void SetContextARM(MDRawContextARM* arm); + void SetContextARM64(MDRawContextARM64* arm64); + void SetContextMIPS(MDRawContextMIPS* ctx_mips); + + // Free the CPU-specific context structure. + void FreeContext(); + + private: + // The CPU-specific context structure. + union { + MDRawContextBase* base; + MDRawContextX86* x86; + MDRawContextPPC* ppc; + MDRawContextPPC64* ppc64; + MDRawContextAMD64* amd64; + // on Solaris SPARC, sparc is defined as a numeric constant, + // so variables can NOT be named as sparc + MDRawContextSPARC* ctx_sparc; + MDRawContextARM* arm; + MDRawContextARM64* arm64; + MDRawContextMIPS* ctx_mips; + } context_; + + // Store this separately because of the weirdo AMD64 context + uint32_t context_flags_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_DUMP_CONTEXT_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/dump_object.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/dump_object.h new file mode 100644 index 00000000..112f687f --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/dump_object.h @@ -0,0 +1,53 @@ +// Copyright (c) 2014 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// dump_object.h: A base class for all mini/micro dump object. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_DUMP_OBJECT_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_DUMP_OBJECT_H__ + +namespace google_breakpad { + +// DumpObject is the base of various mini/micro dump's objects. +class DumpObject { + public: + DumpObject(); + + bool valid() const { return valid_; } + + protected: + // DumpObjects are not valid when created. When a subclass populates its own + // fields, it can set valid_ to true. Accessors and mutators may wish to + // consider or alter the valid_ state as they interact with objects. + bool valid_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_DUMP_OBJECT_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/exploitability.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/exploitability.h new file mode 100644 index 00000000..014413c9 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/exploitability.h @@ -0,0 +1,82 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// exploitability_engine.h: Generic exploitability engine. +// +// The Exploitability class is an abstract base class providing common +// generic methods that apply to exploitability engines for specific platforms. +// Specific implementations will extend this class by providing run +// methods to fill in the exploitability_ enumeration of the ProcessState +// for a crash. +// +// Author: Cris Neckar + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_EXPLOITABILITY_H_ +#define GOOGLE_BREAKPAD_PROCESSOR_EXPLOITABILITY_H_ + +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/minidump.h" +#include "google_breakpad/processor/process_state.h" + +namespace google_breakpad { + +class Exploitability { + public: + virtual ~Exploitability() {} + + static Exploitability *ExploitabilityForPlatform(Minidump *dump, + ProcessState *process_state); + + // The boolean parameter signals whether the exploitability engine is + // enabled to call out to objdump for disassembly. This is disabled by + // default. It is used to check the identity of the instruction that + // caused the program to crash. This should not be enabled if there are + // portability concerns. + static Exploitability *ExploitabilityForPlatform(Minidump *dump, + ProcessState *process_state, + bool enable_objdump); + + ExploitabilityRating CheckExploitability(); + bool AddressIsAscii(uint64_t); + + protected: + Exploitability(Minidump *dump, + ProcessState *process_state); + + Minidump *dump_; + ProcessState *process_state_; + SystemInfo *system_info_; + + private: + virtual ExploitabilityRating CheckPlatformExploitability() = 0; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_EXPLOITABILITY_H_ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/fast_source_line_resolver.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/fast_source_line_resolver.h new file mode 100644 index 00000000..fdf91077 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/fast_source_line_resolver.h @@ -0,0 +1,100 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. +// +// fast_source_line_resolver.h: FastSourceLineResolver is derived from +// SourceLineResolverBase, and is a concrete implementation of +// SourceLineResolverInterface. +// +// FastSourceLineResolver is a sibling class of BasicSourceLineResolver. The +// difference is FastSourceLineResolver loads a serialized memory chunk of data +// which can be used directly a Module without parsing or copying of underlying +// data. Therefore loading a symbol in FastSourceLineResolver is much faster +// and more memory-efficient than BasicSourceLineResolver. +// +// See "source_line_resolver_base.h" and +// "google_breakpad/source_line_resolver_interface.h" for more reference. +// +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_FAST_SOURCE_LINE_RESOLVER_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_FAST_SOURCE_LINE_RESOLVER_H__ + +#include +#include + +#include "google_breakpad/processor/source_line_resolver_base.h" + +namespace google_breakpad { + +using std::map; + +class FastSourceLineResolver : public SourceLineResolverBase { + public: + FastSourceLineResolver(); + virtual ~FastSourceLineResolver() { } + + using SourceLineResolverBase::FillSourceLineInfo; + using SourceLineResolverBase::FindCFIFrameInfo; + using SourceLineResolverBase::FindWindowsFrameInfo; + using SourceLineResolverBase::HasModule; + using SourceLineResolverBase::IsModuleCorrupt; + using SourceLineResolverBase::LoadModule; + using SourceLineResolverBase::LoadModuleUsingMapBuffer; + using SourceLineResolverBase::LoadModuleUsingMemoryBuffer; + using SourceLineResolverBase::UnloadModule; + + private: + // Friend declarations. + friend class ModuleComparer; + friend class ModuleSerializer; + friend class FastModuleFactory; + + // Nested types that will derive from corresponding nested types defined in + // SourceLineResolverBase. + struct Line; + struct Function; + struct PublicSymbol; + class Module; + + // Deserialize raw memory data to construct a WindowsFrameInfo object. + static WindowsFrameInfo CopyWFI(const char *raw_memory); + + // FastSourceLineResolver requires the memory buffer stays alive during the + // lifetime of a corresponding module, therefore it needs to redefine this + // virtual method. + virtual bool ShouldDeleteMemoryBufferAfterLoadModule(); + + // Disallow unwanted copy ctor and assignment operator + FastSourceLineResolver(const FastSourceLineResolver&); + void operator=(const FastSourceLineResolver&); +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_FAST_SOURCE_LINE_RESOLVER_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/memory_region.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/memory_region.h new file mode 100644 index 00000000..30f88df4 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/memory_region.h @@ -0,0 +1,79 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// memory_region.h: Access to memory regions. +// +// A MemoryRegion provides virtual access to a range of memory. It is an +// abstraction allowing the actual source of memory to be independent of +// methods which need to access a virtual memory space. +// +// Author: Mark Mentovai + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_MEMORY_REGION_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_MEMORY_REGION_H__ + + +#include "google_breakpad/common/breakpad_types.h" + + +namespace google_breakpad { + + +class MemoryRegion { + public: + virtual ~MemoryRegion() {} + + // The base address of this memory region. + virtual uint64_t GetBase() const = 0; + + // The size of this memory region. + virtual uint32_t GetSize() const = 0; + + // Access to data of various sizes within the memory region. address + // is a pointer to read, and it must lie within the memory region as + // defined by its base address and size. The location pointed to by + // value is set to the value at address. Byte-swapping is performed + // if necessary so that the value is appropriate for the running + // program. Returns true on success. Fails and returns false if address + // is out of the region's bounds (after considering the width of value), + // or for other types of errors. + virtual bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const = 0; + virtual bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const = 0; + virtual bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const = 0; + virtual bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const = 0; + + // Print a human-readable representation of the object to stdout. + virtual void Print() const = 0; +}; + + +} // namespace google_breakpad + + +#endif // GOOGLE_BREAKPAD_PROCESSOR_MEMORY_REGION_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/microdump.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/microdump.h new file mode 100644 index 00000000..abdaecb1 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/microdump.h @@ -0,0 +1,126 @@ +// Copyright (c) 2014 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// microdump.h: A microdump reader. Microdump is a minified variant of a +// minidump (see minidump.h for documentation) which contains the minimum +// amount of information required to get a stack trace for the crashing thread. +// The information contained in a microdump is: +// - the crashing thread stack +// - system information (os type / version) +// - cpu context (state of the registers) +// - list of mmaps + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_H__ + +#include +#include + +#include "common/scoped_ptr.h" +#include "common/using_std_string.h" +#include "google_breakpad/processor/dump_context.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/system_info.h" +#include "processor/basic_code_modules.h" + +namespace google_breakpad { + +// MicrodumpModuleList contains all of the loaded code modules for a process +// in the form of MicrodumpModules. It maintains a vector of these modules +// and provides access to a code module corresponding to a specific address. +class MicrodumpModules : public BasicCodeModules { + public: + // Takes over ownership of |module|. + void Add(const CodeModule* module); +}; + +// MicrodumpContext carries a CPU-specific context. +// See dump_context.h for documentation. +class MicrodumpContext : public DumpContext { + public: + virtual void SetContextARM(MDRawContextARM* arm); + virtual void SetContextARM64(MDRawContextARM64* arm64); +}; + +// This class provides access to microdump memory regions. +// See memory_region.h for documentation. +class MicrodumpMemoryRegion : public MemoryRegion { + public: + MicrodumpMemoryRegion(); + virtual ~MicrodumpMemoryRegion() {} + + // Set this region's address and contents. If we have placed an + // instance of this class in a test fixture class, individual tests + // can use this to provide the region's contents. + void Init(uint64_t base_address, const std::vector& contents); + + virtual uint64_t GetBase() const; + virtual uint32_t GetSize() const; + + virtual bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const; + virtual bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const; + virtual bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const; + virtual bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const; + + // Print a human-readable representation of the object to stdout. + virtual void Print() const; + + private: + // Fetch a little-endian value from ADDRESS in contents_ whose size + // is BYTES, and store it in *VALUE. Returns true on success. + template + bool GetMemoryLittleEndian(uint64_t address, ValueType* value) const; + + uint64_t base_address_; + std::vector contents_; +}; + +// Microdump is the user's interface to a microdump file. It provides access to +// the microdump's context, memory regions and modules. +class Microdump { + public: + explicit Microdump(const string& contents); + virtual ~Microdump() {} + + DumpContext* GetContext() { return context_.get(); } + MicrodumpMemoryRegion* GetMemory() { return stack_region_.get(); } + MicrodumpModules* GetModules() { return modules_.get(); } + SystemInfo* GetSystemInfo() { return system_info_.get(); } + + private: + scoped_ptr context_; + scoped_ptr stack_region_; + scoped_ptr modules_; + scoped_ptr system_info_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_H__ + diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/microdump_processor.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/microdump_processor.h new file mode 100644 index 00000000..1322a01c --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/microdump_processor.h @@ -0,0 +1,63 @@ +// Copyright (c) 2014, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// The processor for microdump (a reduced dump containing only the state of the +// crashing thread). See crbug.com/410294 for more info and design docs. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_PROCESSOR_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_PROCESSOR_H__ + +#include + +#include "common/using_std_string.h" +#include "google_breakpad/processor/process_result.h" + +namespace google_breakpad { + +class ProcessState; +class StackFrameSymbolizer; + +class MicrodumpProcessor { + public: + // Initializes the MicrodumpProcessor with a stack frame symbolizer. + // Does not take ownership of frame_symbolizer, which must NOT be NULL. + explicit MicrodumpProcessor(StackFrameSymbolizer* frame_symbolizer); + + virtual ~MicrodumpProcessor(); + + // Processes the microdump contents and fills process_state with the result. + google_breakpad::ProcessResult Process(const string& microdump_contents, + ProcessState* process_state); + private: + StackFrameSymbolizer* frame_symbolizer_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_MICRODUMP_PROCESSOR_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/minidump.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/minidump.h new file mode 100644 index 00000000..2b5025e4 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/minidump.h @@ -0,0 +1,1130 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// minidump.h: A minidump reader. +// +// The basic structure of this module tracks the structure of the minidump +// file itself. At the top level, a minidump file is represented by a +// Minidump object. Like most other classes in this module, Minidump +// provides a Read method that initializes the object with information from +// the file. Most of the classes in this file are wrappers around the +// "raw" structures found in the minidump file itself, and defined in +// minidump_format.h. For example, each thread is represented by a +// MinidumpThread object, whose parameters are specified in an MDRawThread +// structure. A properly byte-swapped MDRawThread can be obtained from a +// MinidumpThread easily by calling its thread() method. +// +// Most of the module lazily reads only the portion of the minidump file +// necessary to fulfill the user's request. Calling Minidump::Read +// only reads the minidump's directory. The thread list is not read until +// it is needed, and even once it's read, the memory regions for each +// thread's stack aren't read until they're needed. This strategy avoids +// unnecessary file input, and allocating memory for data in which the user +// has no interest. Note that although memory allocations for a typical +// minidump file are not particularly large, it is possible for legitimate +// minidumps to be sizable. A full-memory minidump, for example, contains +// a snapshot of the entire mapped memory space. Even a normal minidump, +// with stack memory only, can be large if, for example, the dump was +// generated in response to a crash that occurred due to an infinite- +// recursion bug that caused the stack's limits to be exceeded. Finally, +// some users of this library will unfortunately find themselves in the +// position of having to process potentially-hostile minidumps that might +// attempt to cause problems by forcing the minidump processor to over- +// allocate memory. +// +// Memory management in this module is based on a strict +// you-don't-own-anything policy. The only object owned by the user is +// the top-level Minidump object, the creation and destruction of which +// must be the user's own responsibility. All other objects obtained +// through interaction with this module are ultimately owned by the +// Minidump object, and will be freed upon the Minidump object's destruction. +// Because memory regions can potentially involve large allocations, a +// FreeMemory method is provided by MinidumpMemoryRegion, allowing the user +// to release data when it is no longer needed. Use of this method is +// optional but recommended. If freed data is later required, it will +// be read back in from the minidump file again. +// +// There is one exception to this memory management policy: +// Minidump::ReadString will return a string object to the user, and the user +// is responsible for its deletion. +// +// Author: Mark Mentovai + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_H__ + +#include + +#ifndef _WIN32 +#include +#endif + +#include +#include +#include +#include + +#include "common/basictypes.h" +#include "common/using_std_string.h" +#include "google_breakpad/processor/code_module.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/dump_context.h" +#include "google_breakpad/processor/dump_object.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/proc_maps_linux.h" + + +namespace google_breakpad { + + +using std::map; +using std::vector; + + +class Minidump; +template class RangeMap; + + +// MinidumpObject is the base of all Minidump* objects except for Minidump +// itself. +class MinidumpObject : public DumpObject { + public: + virtual ~MinidumpObject() {} + + protected: + explicit MinidumpObject(Minidump* minidump); + + // Refers to the Minidump object that is the ultimate parent of this + // Some MinidumpObjects are owned by other MinidumpObjects, but at the + // root of the ownership tree is always a Minidump. The Minidump object + // is kept here for access to its seeking and reading facilities, and + // for access to data about the minidump file itself, such as whether + // it should be byte-swapped. + Minidump* minidump_; +}; + + +// This class exists primarily to provide a virtual destructor in a base +// class common to all objects that might be stored in +// Minidump::mStreamObjects. Some object types will never be stored in +// Minidump::mStreamObjects, but are represented as streams and adhere to the +// same interface, and may be derived from this class. +class MinidumpStream : public MinidumpObject { + public: + virtual ~MinidumpStream() {} + + protected: + explicit MinidumpStream(Minidump* minidump); + + private: + // Populate (and validate) the MinidumpStream. minidump_ is expected + // to be positioned at the beginning of the stream, so that the next + // read from the minidump will be at the beginning of the stream. + // expected_size should be set to the stream's length as contained in + // the MDRawDirectory record or other identifying record. A class + // that implements MinidumpStream can compare expected_size to a + // known size as an integrity check. + virtual bool Read(uint32_t expected_size) = 0; +}; + + +// MinidumpContext carries a CPU-specific MDRawContext structure, which +// contains CPU context such as register states. Each thread has its +// own context, and the exception record, if present, also has its own +// context. Note that if the exception record is present, the context it +// refers to is probably what the user wants to use for the exception +// thread, instead of that thread's own context. The exception thread's +// context (as opposed to the exception record's context) will contain +// context for the exception handler (which performs minidump generation), +// and not the context that caused the exception (which is probably what the +// user wants). +class MinidumpContext : public DumpContext { + public: + virtual ~MinidumpContext(); + + protected: + explicit MinidumpContext(Minidump* minidump); + + private: + friend class MinidumpThread; + friend class MinidumpException; + + bool Read(uint32_t expected_size); + + // If the minidump contains a SYSTEM_INFO_STREAM, makes sure that the + // system info stream gives an appropriate CPU type matching the context + // CPU type in context_cpu_type. Returns false if the CPU type does not + // match. Returns true if the CPU type matches or if the minidump does + // not contain a system info stream. + bool CheckAgainstSystemInfo(uint32_t context_cpu_type); + + // Refers to the Minidump object that is the ultimate parent of this + // Some MinidumpObjects are owned by other MinidumpObjects, but at the + // root of the ownership tree is always a Minidump. The Minidump object + // is kept here for access to its seeking and reading facilities, and + // for access to data about the minidump file itself, such as whether + // it should be byte-swapped. + Minidump* minidump_; +}; + + +// MinidumpMemoryRegion does not wrap any MDRaw structure, and only contains +// a reference to an MDMemoryDescriptor. This object is intended to wrap +// portions of a minidump file that contain memory dumps. In normal +// minidumps, each MinidumpThread owns a MinidumpMemoryRegion corresponding +// to the thread's stack memory. MinidumpMemoryList also gives access to +// memory regions in its list as MinidumpMemoryRegions. This class +// adheres to MemoryRegion so that it may be used as a data provider to +// the Stackwalker family of classes. +class MinidumpMemoryRegion : public MinidumpObject, + public MemoryRegion { + public: + virtual ~MinidumpMemoryRegion(); + + static void set_max_bytes(uint32_t max_bytes) { max_bytes_ = max_bytes; } + static uint32_t max_bytes() { return max_bytes_; } + + // Returns a pointer to the base of the memory region. Returns the + // cached value if available, otherwise, reads the minidump file and + // caches the memory region. + const uint8_t* GetMemory() const; + + // The address of the base of the memory region. + uint64_t GetBase() const; + + // The size, in bytes, of the memory region. + uint32_t GetSize() const; + + // Frees the cached memory region, if cached. + void FreeMemory(); + + // Obtains the value of memory at the pointer specified by address. + bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const; + bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const; + bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const; + bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const; + + // Print a human-readable representation of the object to stdout. + void Print() const; + + protected: + explicit MinidumpMemoryRegion(Minidump* minidump); + + private: + friend class MinidumpThread; + friend class MinidumpMemoryList; + + // Identify the base address and size of the memory region, and the + // location it may be found in the minidump file. + void SetDescriptor(MDMemoryDescriptor* descriptor); + + // Implementation for GetMemoryAtAddress + template bool GetMemoryAtAddressInternal(uint64_t address, + T* value) const; + + // The largest memory region that will be read from a minidump. The + // default is 1MB. + static uint32_t max_bytes_; + + // Base address and size of the memory region, and its position in the + // minidump file. + MDMemoryDescriptor* descriptor_; + + // Cached memory. + mutable vector* memory_; +}; + + +// MinidumpThread contains information about a thread of execution, +// including a snapshot of the thread's stack and CPU context. For +// the thread that caused an exception, the context carried by +// MinidumpException is probably desired instead of the CPU context +// provided here. +// Note that a MinidumpThread may be valid() even if it does not +// contain a memory region or context. +class MinidumpThread : public MinidumpObject { + public: + virtual ~MinidumpThread(); + + const MDRawThread* thread() const { return valid_ ? &thread_ : NULL; } + // GetMemory may return NULL even if the MinidumpThread is valid, + // if the thread memory cannot be read. + virtual MinidumpMemoryRegion* GetMemory(); + // GetContext may return NULL even if the MinidumpThread is valid. + virtual MinidumpContext* GetContext(); + + // The thread ID is used to determine if a thread is the exception thread, + // so a special getter is provided to retrieve this data from the + // MDRawThread structure. Returns false if the thread ID cannot be + // determined. + virtual bool GetThreadID(uint32_t *thread_id) const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + // Returns the start address of the thread stack memory region. Returns 0 if + // MinidumpThread is invalid. Note that this method can be called even when + // the thread memory cannot be read and GetMemory returns NULL. + virtual uint64_t GetStartOfStackMemoryRange() const; + + protected: + explicit MinidumpThread(Minidump* minidump); + + private: + // These objects are managed by MinidumpThreadList. + friend class MinidumpThreadList; + + // This works like MinidumpStream::Read, but is driven by + // MinidumpThreadList. No size checking is done, because + // MinidumpThreadList handles that directly. + bool Read(); + + MDRawThread thread_; + MinidumpMemoryRegion* memory_; + MinidumpContext* context_; +}; + + +// MinidumpThreadList contains all of the threads (as MinidumpThreads) in +// a process. +class MinidumpThreadList : public MinidumpStream { + public: + virtual ~MinidumpThreadList(); + + static void set_max_threads(uint32_t max_threads) { + max_threads_ = max_threads; + } + static uint32_t max_threads() { return max_threads_; } + + virtual unsigned int thread_count() const { + return valid_ ? thread_count_ : 0; + } + + // Sequential access to threads. + virtual MinidumpThread* GetThreadAtIndex(unsigned int index) const; + + // Random access to threads. + MinidumpThread* GetThreadByID(uint32_t thread_id); + + // Print a human-readable representation of the object to stdout. + void Print(); + + protected: + explicit MinidumpThreadList(Minidump* aMinidump); + + private: + friend class Minidump; + + typedef map IDToThreadMap; + typedef vector MinidumpThreads; + + static const uint32_t kStreamType = MD_THREAD_LIST_STREAM; + + bool Read(uint32_t aExpectedSize); + + // The largest number of threads that will be read from a minidump. The + // default is 256. + static uint32_t max_threads_; + + // Access to threads using the thread ID as the key. + IDToThreadMap id_to_thread_map_; + + // The list of threads. + MinidumpThreads* threads_; + uint32_t thread_count_; +}; + + +// MinidumpModule wraps MDRawModule, which contains information about loaded +// code modules. Access is provided to various data referenced indirectly +// by MDRawModule, such as the module's name and a specification for where +// to locate debugging information for the module. +class MinidumpModule : public MinidumpObject, + public CodeModule { + public: + virtual ~MinidumpModule(); + + static void set_max_cv_bytes(uint32_t max_cv_bytes) { + max_cv_bytes_ = max_cv_bytes; + } + static uint32_t max_cv_bytes() { return max_cv_bytes_; } + + static void set_max_misc_bytes(uint32_t max_misc_bytes) { + max_misc_bytes_ = max_misc_bytes; + } + static uint32_t max_misc_bytes() { return max_misc_bytes_; } + + const MDRawModule* module() const { return valid_ ? &module_ : NULL; } + + // CodeModule implementation + virtual uint64_t base_address() const { + return valid_ ? module_.base_of_image : static_cast(-1); + } + virtual uint64_t size() const { return valid_ ? module_.size_of_image : 0; } + virtual string code_file() const; + virtual string code_identifier() const; + virtual string debug_file() const; + virtual string debug_identifier() const; + virtual string version() const; + virtual const CodeModule* Copy() const; + + // The CodeView record, which contains information to locate the module's + // debugging information (pdb). This is returned as uint8_t* because + // the data can be of types MDCVInfoPDB20* or MDCVInfoPDB70*, or it may be + // of a type unknown to Breakpad, in which case the raw data will still be + // returned but no byte-swapping will have been performed. Check the + // record's signature in the first four bytes to differentiate between + // the various types. Current toolchains generate modules which carry + // MDCVInfoPDB70 by default. Returns a pointer to the CodeView record on + // success, and NULL on failure. On success, the optional |size| argument + // is set to the size of the CodeView record. + const uint8_t* GetCVRecord(uint32_t* size); + + // The miscellaneous debug record, which is obsolete. Current toolchains + // do not generate this type of debugging information (dbg), and this + // field is not expected to be present. Returns a pointer to the debugging + // record on success, and NULL on failure. On success, the optional |size| + // argument is set to the size of the debugging record. + const MDImageDebugMisc* GetMiscRecord(uint32_t* size); + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + // These objects are managed by MinidumpModuleList. + friend class MinidumpModuleList; + + explicit MinidumpModule(Minidump* minidump); + + // This works like MinidumpStream::Read, but is driven by + // MinidumpModuleList. No size checking is done, because + // MinidumpModuleList handles that directly. + bool Read(); + + // Reads indirectly-referenced data, including the module name, CodeView + // record, and miscellaneous debugging record. This is necessary to allow + // MinidumpModuleList to fully construct MinidumpModule objects without + // requiring seeks to read a contiguous set of MinidumpModule objects. + // All auxiliary data should be available when Read is called, in order to + // allow the CodeModule getters to be const methods. + bool ReadAuxiliaryData(); + + // The largest number of bytes that will be read from a minidump for a + // CodeView record or miscellaneous debugging record, respectively. The + // default for each is 1024. + static uint32_t max_cv_bytes_; + static uint32_t max_misc_bytes_; + + // True after a successful Read. This is different from valid_, which is + // not set true until ReadAuxiliaryData also completes successfully. + // module_valid_ is only used by ReadAuxiliaryData and the functions it + // calls to determine whether the object is ready for auxiliary data to + // be read. + bool module_valid_; + + // True if debug info was read from the module. Certain modules + // may contain debug records in formats we don't support, + // so we can just set this to false to ignore them. + bool has_debug_info_; + + MDRawModule module_; + + // Cached module name. + const string* name_; + + // Cached CodeView record - this is MDCVInfoPDB20 or (likely) + // MDCVInfoPDB70, or possibly something else entirely. Stored as a uint8_t + // because the structure contains a variable-sized string and its exact + // size cannot be known until it is processed. + vector* cv_record_; + + // If cv_record_ is present, cv_record_signature_ contains a copy of the + // CodeView record's first four bytes, for ease of determinining the + // type of structure that cv_record_ contains. + uint32_t cv_record_signature_; + + // Cached MDImageDebugMisc (usually not present), stored as uint8_t + // because the structure contains a variable-sized string and its exact + // size cannot be known until it is processed. + vector* misc_record_; +}; + + +// MinidumpModuleList contains all of the loaded code modules for a process +// in the form of MinidumpModules. It maintains a map of these modules +// so that it may easily provide a code module corresponding to a specific +// address. +class MinidumpModuleList : public MinidumpStream, + public CodeModules { + public: + virtual ~MinidumpModuleList(); + + static void set_max_modules(uint32_t max_modules) { + max_modules_ = max_modules; + } + static uint32_t max_modules() { return max_modules_; } + + // CodeModules implementation. + virtual unsigned int module_count() const { + return valid_ ? module_count_ : 0; + } + virtual const MinidumpModule* GetModuleForAddress(uint64_t address) const; + virtual const MinidumpModule* GetMainModule() const; + virtual const MinidumpModule* GetModuleAtSequence( + unsigned int sequence) const; + virtual const MinidumpModule* GetModuleAtIndex(unsigned int index) const; + virtual const CodeModules* Copy() const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + protected: + explicit MinidumpModuleList(Minidump* minidump); + + private: + friend class Minidump; + + typedef vector MinidumpModules; + + static const uint32_t kStreamType = MD_MODULE_LIST_STREAM; + + bool Read(uint32_t expected_size); + + // The largest number of modules that will be read from a minidump. The + // default is 1024. + static uint32_t max_modules_; + + // Access to modules using addresses as the key. + RangeMap *range_map_; + + MinidumpModules *modules_; + uint32_t module_count_; +}; + + +// MinidumpMemoryList corresponds to a minidump's MEMORY_LIST_STREAM stream, +// which references the snapshots of all of the memory regions contained +// within the minidump. For a normal minidump, this includes stack memory +// (also referenced by each MinidumpThread, in fact, the MDMemoryDescriptors +// here and in MDRawThread both point to exactly the same data in a +// minidump file, conserving space), as well as a 256-byte snapshot of memory +// surrounding the instruction pointer in the case of an exception. Other +// types of minidumps may contain significantly more memory regions. Full- +// memory minidumps contain all of a process' mapped memory. +class MinidumpMemoryList : public MinidumpStream { + public: + virtual ~MinidumpMemoryList(); + + static void set_max_regions(uint32_t max_regions) { + max_regions_ = max_regions; + } + static uint32_t max_regions() { return max_regions_; } + + unsigned int region_count() const { return valid_ ? region_count_ : 0; } + + // Sequential access to memory regions. + MinidumpMemoryRegion* GetMemoryRegionAtIndex(unsigned int index); + + // Random access to memory regions. Returns the region encompassing + // the address identified by address. + virtual MinidumpMemoryRegion* GetMemoryRegionForAddress(uint64_t address); + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + friend class Minidump; + friend class MockMinidumpMemoryList; + + typedef vector MemoryDescriptors; + typedef vector MemoryRegions; + + static const uint32_t kStreamType = MD_MEMORY_LIST_STREAM; + + explicit MinidumpMemoryList(Minidump* minidump); + + bool Read(uint32_t expected_size); + + // The largest number of memory regions that will be read from a minidump. + // The default is 256. + static uint32_t max_regions_; + + // Access to memory regions using addresses as the key. + RangeMap *range_map_; + + // The list of descriptors. This is maintained separately from the list + // of regions, because MemoryRegion doesn't own its MemoryDescriptor, it + // maintains a pointer to it. descriptors_ provides the storage for this + // purpose. + MemoryDescriptors *descriptors_; + + // The list of regions. + MemoryRegions *regions_; + uint32_t region_count_; +}; + + +// MinidumpException wraps MDRawExceptionStream, which contains information +// about the exception that caused the minidump to be generated, if the +// minidump was generated in an exception handler called as a result of an +// exception. It also provides access to a MinidumpContext object, which +// contains the CPU context for the exception thread at the time the exception +// occurred. +class MinidumpException : public MinidumpStream { + public: + virtual ~MinidumpException(); + + const MDRawExceptionStream* exception() const { + return valid_ ? &exception_ : NULL; + } + + // The thread ID is used to determine if a thread is the exception thread, + // so a special getter is provided to retrieve this data from the + // MDRawExceptionStream structure. Returns false if the thread ID cannot + // be determined. + bool GetThreadID(uint32_t *thread_id) const; + + MinidumpContext* GetContext(); + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + friend class Minidump; + + static const uint32_t kStreamType = MD_EXCEPTION_STREAM; + + explicit MinidumpException(Minidump* minidump); + + bool Read(uint32_t expected_size); + + MDRawExceptionStream exception_; + MinidumpContext* context_; +}; + +// MinidumpAssertion wraps MDRawAssertionInfo, which contains information +// about an assertion that caused the minidump to be generated. +class MinidumpAssertion : public MinidumpStream { + public: + virtual ~MinidumpAssertion(); + + const MDRawAssertionInfo* assertion() const { + return valid_ ? &assertion_ : NULL; + } + + string expression() const { + return valid_ ? expression_ : ""; + } + + string function() const { + return valid_ ? function_ : ""; + } + + string file() const { + return valid_ ? file_ : ""; + } + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + friend class Minidump; + + static const uint32_t kStreamType = MD_ASSERTION_INFO_STREAM; + + explicit MinidumpAssertion(Minidump* minidump); + + bool Read(uint32_t expected_size); + + MDRawAssertionInfo assertion_; + string expression_; + string function_; + string file_; +}; + + +// MinidumpSystemInfo wraps MDRawSystemInfo and provides information about +// the system on which the minidump was generated. See also MinidumpMiscInfo. +class MinidumpSystemInfo : public MinidumpStream { + public: + virtual ~MinidumpSystemInfo(); + + const MDRawSystemInfo* system_info() const { + return valid_ ? &system_info_ : NULL; + } + + // GetOS and GetCPU return textual representations of the operating system + // and CPU that produced the minidump. Unlike most other Minidump* methods, + // they return string objects, not weak pointers. Defined values for + // GetOS() are "mac", "windows", and "linux". Defined values for GetCPU + // are "x86" and "ppc". These methods return an empty string when their + // values are unknown. + string GetOS(); + string GetCPU(); + + // I don't know what CSD stands for, but this field is documented as + // returning a textual representation of the OS service pack. On other + // platforms, this provides additional information about an OS version + // level beyond major.minor.micro. Returns NULL if unknown. + const string* GetCSDVersion(); + + // If a CPU vendor string can be determined, returns a pointer to it, + // otherwise, returns NULL. CPU vendor strings can be determined from + // x86 CPUs with CPUID 0. + const string* GetCPUVendor(); + + // Print a human-readable representation of the object to stdout. + void Print(); + + protected: + explicit MinidumpSystemInfo(Minidump* minidump); + MDRawSystemInfo system_info_; + + // Textual representation of the OS service pack, for minidumps produced + // by MiniDumpWriteDump on Windows. + const string* csd_version_; + + private: + friend class Minidump; + + static const uint32_t kStreamType = MD_SYSTEM_INFO_STREAM; + + bool Read(uint32_t expected_size); + + // A string identifying the CPU vendor, if known. + const string* cpu_vendor_; +}; + + +// MinidumpMiscInfo wraps MDRawMiscInfo and provides information about +// the process that generated the minidump, and optionally additional system +// information. See also MinidumpSystemInfo. +class MinidumpMiscInfo : public MinidumpStream { + public: + const MDRawMiscInfo* misc_info() const { + return valid_ ? &misc_info_ : NULL; + } + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + friend class Minidump; + friend class TestMinidumpMiscInfo; + + static const uint32_t kStreamType = MD_MISC_INFO_STREAM; + + explicit MinidumpMiscInfo(Minidump* minidump_); + + bool Read(uint32_t expected_size_); + + MDRawMiscInfo misc_info_; + + // Populated by Read. Contains the converted strings from the corresponding + // UTF-16 fields in misc_info_ + string standard_name_; + string daylight_name_; + string build_string_; + string dbg_bld_str_; +}; + + +// MinidumpBreakpadInfo wraps MDRawBreakpadInfo, which is an optional stream in +// a minidump that provides additional information about the process state +// at the time the minidump was generated. +class MinidumpBreakpadInfo : public MinidumpStream { + public: + const MDRawBreakpadInfo* breakpad_info() const { + return valid_ ? &breakpad_info_ : NULL; + } + + // These thread IDs are used to determine if threads deserve special + // treatment, so special getters are provided to retrieve this data from + // the MDRawBreakpadInfo structure. The getters return false if the thread + // IDs cannot be determined. + bool GetDumpThreadID(uint32_t *thread_id) const; + bool GetRequestingThreadID(uint32_t *thread_id) const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + friend class Minidump; + + static const uint32_t kStreamType = MD_BREAKPAD_INFO_STREAM; + + explicit MinidumpBreakpadInfo(Minidump* minidump_); + + bool Read(uint32_t expected_size_); + + MDRawBreakpadInfo breakpad_info_; +}; + +// MinidumpMemoryInfo wraps MDRawMemoryInfo, which provides information +// about mapped memory regions in a process, including their ranges +// and protection. +class MinidumpMemoryInfo : public MinidumpObject { + public: + const MDRawMemoryInfo* info() const { return valid_ ? &memory_info_ : NULL; } + + // The address of the base of the memory region. + uint64_t GetBase() const { return valid_ ? memory_info_.base_address : 0; } + + // The size, in bytes, of the memory region. + uint64_t GetSize() const { return valid_ ? memory_info_.region_size : 0; } + + // Return true if the memory protection allows execution. + bool IsExecutable() const; + + // Return true if the memory protection allows writing. + bool IsWritable() const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + // These objects are managed by MinidumpMemoryInfoList. + friend class MinidumpMemoryInfoList; + + explicit MinidumpMemoryInfo(Minidump* minidump_); + + // This works like MinidumpStream::Read, but is driven by + // MinidumpMemoryInfoList. No size checking is done, because + // MinidumpMemoryInfoList handles that directly. + bool Read(); + + MDRawMemoryInfo memory_info_; +}; + +// MinidumpMemoryInfoList contains a list of information about +// mapped memory regions for a process in the form of MDRawMemoryInfo. +// It maintains a map of these structures so that it may easily provide +// info corresponding to a specific address. +class MinidumpMemoryInfoList : public MinidumpStream { + public: + virtual ~MinidumpMemoryInfoList(); + + unsigned int info_count() const { return valid_ ? info_count_ : 0; } + + const MinidumpMemoryInfo* GetMemoryInfoForAddress(uint64_t address) const; + const MinidumpMemoryInfo* GetMemoryInfoAtIndex(unsigned int index) const; + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + friend class Minidump; + + typedef vector MinidumpMemoryInfos; + + static const uint32_t kStreamType = MD_MEMORY_INFO_LIST_STREAM; + + explicit MinidumpMemoryInfoList(Minidump* minidump_); + + bool Read(uint32_t expected_size); + + // Access to memory info using addresses as the key. + RangeMap *range_map_; + + MinidumpMemoryInfos* infos_; + uint32_t info_count_; +}; + +// MinidumpLinuxMaps wraps information about a single mapped memory region +// from /proc/self/maps. +class MinidumpLinuxMaps : public MinidumpObject { + public: + // The memory address of the base of the mapped region. + uint64_t GetBase() const { return valid_ ? region_.start : 0; } + // The size of the mapped region. + uint64_t GetSize() const { return valid_ ? region_.end - region_.start : 0; } + + // The permissions of the mapped region. + bool IsReadable() const { + return valid_ ? region_.permissions & MappedMemoryRegion::READ : false; + } + bool IsWriteable() const { + return valid_ ? region_.permissions & MappedMemoryRegion::WRITE : false; + } + bool IsExecutable() const { + return valid_ ? region_.permissions & MappedMemoryRegion::EXECUTE : false; + } + bool IsPrivate() const { + return valid_ ? region_.permissions & MappedMemoryRegion::PRIVATE : false; + } + + // The offset of the mapped region. + uint64_t GetOffset() const { return valid_ ? region_.offset : 0; } + + // The major device number. + uint8_t GetMajorDevice() const { return valid_ ? region_.major_device : 0; } + // The minor device number. + uint8_t GetMinorDevice() const { return valid_ ? region_.minor_device : 0; } + + // The inode of the mapped region. + uint64_t GetInode() const { return valid_ ? region_.inode : 0; } + + // The pathname of the mapped region. + const string GetPathname() const { return valid_ ? region_.path : ""; } + + // Print the contents of this mapping. + void Print() const; + + private: + // These objects are managed by MinidumpLinuxMapsList. + friend class MinidumpLinuxMapsList; + + // This caller owns the pointer. + explicit MinidumpLinuxMaps(Minidump *minidump); + + // The memory region struct that this class wraps. + MappedMemoryRegion region_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpLinuxMaps); +}; + +// MinidumpLinuxMapsList corresponds to the Linux-exclusive MD_LINUX_MAPS +// stream, which contains the contents of /prod/self/maps, which contains +// the mapped memory regions and their access permissions. +class MinidumpLinuxMapsList : public MinidumpStream { + public: + virtual ~MinidumpLinuxMapsList(); + + // Get number of mappings. + unsigned int get_maps_count() const { return valid_ ? maps_count_ : 0; } + + // Get mapping at the given memory address. The caller owns the pointer. + const MinidumpLinuxMaps *GetLinuxMapsForAddress(uint64_t address) const; + // Get mapping at the given index. The caller owns the pointer. + const MinidumpLinuxMaps *GetLinuxMapsAtIndex(unsigned int index) const; + + // Print the contents of /proc/self/maps to stdout. + void Print() const; + + private: + friend class Minidump; + + typedef vector MinidumpLinuxMappings; + + static const uint32_t kStreamType = MD_LINUX_MAPS; + + // The caller owns the pointer. + explicit MinidumpLinuxMapsList(Minidump *minidump); + + // Read and load the contents of the process mapping data. + // The stream should have data in the form of /proc/self/maps. + // This method returns whether the stream was read successfully. + bool Read(uint32_t expected_size); + + // The list of individual mappings. + MinidumpLinuxMappings *maps_; + // The number of mappings. + uint32_t maps_count_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpLinuxMapsList); +}; + +// Minidump is the user's interface to a minidump file. It wraps MDRawHeader +// and provides access to the minidump's top-level stream directory. +class Minidump { + public: + // path is the pathname of a file containing the minidump. + explicit Minidump(const string& path); + // input is an istream wrapping minidump data. Minidump holds a + // weak pointer to input, and the caller must ensure that the stream + // is valid as long as the Minidump object is. + explicit Minidump(std::istream& input); + + virtual ~Minidump(); + + // path may be empty if the minidump was not opened from a file + virtual string path() const { + return path_; + } + static void set_max_streams(uint32_t max_streams) { + max_streams_ = max_streams; + } + static uint32_t max_streams() { return max_streams_; } + + static void set_max_string_length(uint32_t max_string_length) { + max_string_length_ = max_string_length; + } + static uint32_t max_string_length() { return max_string_length_; } + + virtual const MDRawHeader* header() const { return valid_ ? &header_ : NULL; } + + // Reads the CPU information from the system info stream and generates the + // appropriate CPU flags. The returned context_cpu_flags are the same as + // if the CPU type bits were set in the context_flags of a context record. + // On success, context_cpu_flags will have the flags that identify the CPU. + // If a system info stream is missing, context_cpu_flags will be 0. + // Returns true if the current position in the stream was not changed. + // Returns false when the current location in the stream was changed and the + // attempt to restore the original position failed. + bool GetContextCPUFlagsFromSystemInfo(uint32_t* context_cpu_flags); + + // Reads the minidump file's header and top-level stream directory. + // The minidump is expected to be positioned at the beginning of the + // header. Read() sets up the stream list and map, and validates the + // Minidump object. + virtual bool Read(); + + // The next set of methods are stubs that call GetStream. They exist to + // force code generation of the templatized API within the module, and + // to avoid exposing an ugly API (GetStream needs to accept a garbage + // parameter). + virtual MinidumpThreadList* GetThreadList(); + virtual MinidumpModuleList* GetModuleList(); + virtual MinidumpMemoryList* GetMemoryList(); + virtual MinidumpException* GetException(); + virtual MinidumpAssertion* GetAssertion(); + virtual MinidumpSystemInfo* GetSystemInfo(); + virtual MinidumpMiscInfo* GetMiscInfo(); + virtual MinidumpBreakpadInfo* GetBreakpadInfo(); + virtual MinidumpMemoryInfoList* GetMemoryInfoList(); + + // The next method also calls GetStream, but is exclusive for Linux dumps. + virtual MinidumpLinuxMapsList *GetLinuxMapsList(); + + // The next set of methods are provided for users who wish to access + // data in minidump files directly, while leveraging the rest of + // this class and related classes to handle the basic minidump + // structure and known stream types. + + unsigned int GetDirectoryEntryCount() const { + return valid_ ? header_.stream_count : 0; + } + const MDRawDirectory* GetDirectoryEntryAtIndex(unsigned int index) const; + + // The next 2 methods are lower-level I/O routines. They use fd_. + + // Reads count bytes from the minidump at the current position into + // the storage area pointed to by bytes. bytes must be of sufficient + // size. After the read, the file position is advanced by count. + bool ReadBytes(void* bytes, size_t count); + + // Sets the position of the minidump file to offset. + bool SeekSet(off_t offset); + + // Returns the current position of the minidump file. + off_t Tell(); + + // The next 2 methods are medium-level I/O routines. + + // ReadString returns a string which is owned by the caller! offset + // specifies the offset that a length-encoded string is stored at in the + // minidump file. + string* ReadString(off_t offset); + + // SeekToStreamType positions the file at the beginning of a stream + // identified by stream_type, and informs the caller of the stream's + // length by setting *stream_length. Because stream_map maps each stream + // type to only one stream in the file, this might mislead the user into + // thinking that the stream that this seeks to is the only stream with + // type stream_type. That can't happen for streams that these classes + // deal with directly, because they're only supposed to be present in the + // file singly, and that's verified when stream_map_ is built. Users who + // are looking for other stream types should be aware of this + // possibility, and consider using GetDirectoryEntryAtIndex (possibly + // with GetDirectoryEntryCount) if expecting multiple streams of the same + // type in a single minidump file. + bool SeekToStreamType(uint32_t stream_type, uint32_t* stream_length); + + bool swap() const { return valid_ ? swap_ : false; } + + // Print a human-readable representation of the object to stdout. + void Print(); + + private: + // MinidumpStreamInfo is used in the MinidumpStreamMap. It lets + // the Minidump object locate interesting streams quickly, and + // provides a convenient place to stash MinidumpStream objects. + struct MinidumpStreamInfo { + MinidumpStreamInfo() : stream_index(0), stream(NULL) {} + ~MinidumpStreamInfo() { delete stream; } + + // Index into the MinidumpDirectoryEntries vector + unsigned int stream_index; + + // Pointer to the stream if cached, or NULL if not yet populated + MinidumpStream* stream; + }; + + typedef vector MinidumpDirectoryEntries; + typedef map MinidumpStreamMap; + + template T* GetStream(T** stream); + + // Opens the minidump file, or if already open, seeks to the beginning. + bool Open(); + + // The largest number of top-level streams that will be read from a minidump. + // Note that streams are only read (and only consume memory) as needed, + // when directed by the caller. The default is 128. + static uint32_t max_streams_; + + // The maximum length of a UTF-16 string that will be read from a minidump + // in 16-bit words. The default is 1024. UTF-16 strings are converted + // to UTF-8 when stored in memory, and each UTF-16 word will be represented + // by as many as 3 bytes in UTF-8. + static unsigned int max_string_length_; + + MDRawHeader header_; + + // The list of streams. + MinidumpDirectoryEntries* directory_; + + // Access to streams using the stream type as the key. + MinidumpStreamMap* stream_map_; + + // The pathname of the minidump file to process, set in the constructor. + // This may be empty if the minidump was opened directly from a stream. + const string path_; + + // The stream for all file I/O. Used by ReadBytes and SeekSet. + // Set based on the path in Open, or directly in the constructor. + std::istream* stream_; + + // swap_ is true if the minidump file should be byte-swapped. If the + // minidump was produced by a CPU that is other-endian than the CPU + // processing the minidump, this will be true. If the two CPUs are + // same-endian, this will be false. + bool swap_; + + // Validity of the Minidump structure, false immediately after + // construction or after a failed Read(); true following a successful + // Read(). + bool valid_; +}; + + +} // namespace google_breakpad + + +#endif // GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/minidump_processor.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/minidump_processor.h new file mode 100644 index 00000000..387115ef --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/minidump_processor.h @@ -0,0 +1,147 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_PROCESSOR_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_PROCESSOR_H__ + +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/process_result.h" + +namespace google_breakpad { + +class Minidump; +class ProcessState; +class StackFrameSymbolizer; +class SourceLineResolverInterface; +class SymbolSupplier; +struct SystemInfo; + +class MinidumpProcessor { + public: + // Initializes this MinidumpProcessor. supplier should be an + // implementation of the SymbolSupplier abstract base class. + MinidumpProcessor(SymbolSupplier* supplier, + SourceLineResolverInterface* resolver); + + // Initializes the MinidumpProcessor with the option of + // enabling the exploitability framework to analyze dumps + // for probable security relevance. + MinidumpProcessor(SymbolSupplier* supplier, + SourceLineResolverInterface* resolver, + bool enable_exploitability); + + // Initializes the MinidumpProcessor with source line resolver helper, and + // the option of enabling the exploitability framework to analyze dumps + // for probable security relevance. + // Does not take ownership of resolver_helper, which must NOT be NULL. + MinidumpProcessor(StackFrameSymbolizer* stack_frame_symbolizer, + bool enable_exploitability); + + ~MinidumpProcessor(); + + // Processes the minidump file and fills process_state with the result. + ProcessResult Process(const string &minidump_file, + ProcessState* process_state); + + // Processes the minidump structure and fills process_state with the + // result. + ProcessResult Process(Minidump* minidump, + ProcessState* process_state); + // Populates the cpu_* fields of the |info| parameter with textual + // representations of the CPU type that the minidump in |dump| was + // produced on. Returns false if this information is not available in + // the minidump. + static bool GetCPUInfo(Minidump* dump, SystemInfo* info); + + // Populates the os_* fields of the |info| parameter with textual + // representations of the operating system that the minidump in |dump| + // was produced on. Returns false if this information is not available in + // the minidump. + static bool GetOSInfo(Minidump* dump, SystemInfo* info); + + // Populates the |process_create_time| parameter with the create time of the + // crashed process. Returns false if this information is not available in + // the minidump |dump|. + static bool GetProcessCreateTime(Minidump* dump, + uint32_t* process_create_time); + + // Returns a textual representation of the reason that a crash occurred, + // if the minidump in dump was produced as a result of a crash. Returns + // an empty string if this information cannot be determined. If address + // is non-NULL, it will be set to contain the address that caused the + // exception, if this information is available. This will be a code + // address when the crash was caused by problems such as illegal + // instructions or divisions by zero, or a data address when the crash + // was caused by a memory access violation. + static string GetCrashReason(Minidump* dump, uint64_t* address); + + // This function returns true if the passed-in error code is + // something unrecoverable(i.e. retry should not happen). For + // instance, if the minidump is corrupt, then it makes no sense to + // retry as we won't be able to glean additional information. + // However, as an example of the other case, the symbol supplier can + // return an error code indicating it was 'interrupted', which can + // happen of the symbols are fetched from a remote store, and a + // retry might be successful later on. + // You should not call this method with PROCESS_OK! Test for + // that separately before calling this. + static bool IsErrorUnrecoverable(ProcessResult p) { + assert(p != PROCESS_OK); + return (p != PROCESS_SYMBOL_SUPPLIER_INTERRUPTED); + } + + // Returns a textual representation of an assertion included + // in the minidump. Returns an empty string if this information + // does not exist or cannot be determined. + static string GetAssertion(Minidump* dump); + + void set_enable_objdump(bool enabled) { enable_objdump_ = enabled; } + + private: + StackFrameSymbolizer* frame_symbolizer_; + // Indicate whether resolver_helper_ is owned by this instance. + bool own_frame_symbolizer_; + + // This flag enables the exploitability scanner which attempts to + // guess how likely it is that the crash represents an exploitable + // memory corruption issue. + bool enable_exploitability_; + + // This flag permits the exploitability scanner to shell out to objdump + // for purposes of disassembly. + bool enable_objdump_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_PROCESSOR_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/proc_maps_linux.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/proc_maps_linux.h new file mode 100644 index 00000000..b8e6eb92 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/proc_maps_linux.h @@ -0,0 +1,60 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_DEBUG_PROC_MAPS_LINUX_H_ +#define BASE_DEBUG_PROC_MAPS_LINUX_H_ + +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +// Describes a region of mapped memory and the path of the file mapped. +struct MappedMemoryRegion { + enum Permission { + READ = 1 << 0, + WRITE = 1 << 1, + EXECUTE = 1 << 2, + PRIVATE = 1 << 3, // If set, region is private, otherwise it is shared. + }; + + // The address range [start,end) of mapped memory. + uint64_t start; + uint64_t end; + + // Byte offset into |path| of the range mapped into memory. + uint64_t offset; + + // Bitmask of read/write/execute/private/shared permissions. + uint8_t permissions; + + // Major and minor devices. + uint8_t major_device; + uint8_t minor_device; + + // Value of the inode. + uint64_t inode; + + // Name of the file mapped into memory. + // + // NOTE: path names aren't guaranteed to point at valid files. For example, + // "[heap]" and "[stack]" are used to represent the location of the process' + // heap and stack, respectively. + string path; + + // The line from /proc//maps that this struct represents. + string line; +}; + +// Parses /proc//maps input data and stores in |regions|. Returns true +// and updates |regions| if and only if all of |input| was successfully parsed. +bool ParseProcMaps(const std::string& input, + std::vector* regions); + +} // namespace google_breakpad + +#endif // BASE_DEBUG_PROC_MAPS_LINUX_H_ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/process_result.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/process_result.h new file mode 100644 index 00000000..15c7213e --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/process_result.h @@ -0,0 +1,66 @@ +// Copyright (c) 2014, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_PROCESS_RESULT_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_PROCESS_RESULT_H__ + +namespace google_breakpad { + +// Return type for MinidumpProcessor or MicrodumpProcessor's Process() +enum ProcessResult { + PROCESS_OK, // The dump was processed + // successfully. + + PROCESS_ERROR_MINIDUMP_NOT_FOUND, // The minidump file was not + // found. + + PROCESS_ERROR_NO_MINIDUMP_HEADER, // The minidump file had no + // header. + + PROCESS_ERROR_NO_THREAD_LIST, // The minidump file has no + // thread list. + + PROCESS_ERROR_GETTING_THREAD, // There was an error getting one + // thread's data from th dump. + + PROCESS_ERROR_GETTING_THREAD_ID, // There was an error getting a + // thread id from the thread's + // data. + + PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS, // There was more than one + // requesting thread. + + PROCESS_SYMBOL_SUPPLIER_INTERRUPTED // The dump processing was + // interrupted by the + // SymbolSupplier(not fatal). +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_PROCESS_RESULT_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/process_state.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/process_state.h new file mode 100644 index 00000000..728656f2 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/process_state.h @@ -0,0 +1,189 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// process_state.h: A snapshot of a process, in a fully-digested state. +// +// Author: Mark Mentovai + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_PROCESS_STATE_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_PROCESS_STATE_H__ + +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/system_info.h" +#include "google_breakpad/processor/minidump.h" + +namespace google_breakpad { + +using std::vector; + +class CallStack; +class CodeModules; + +enum ExploitabilityRating { + EXPLOITABILITY_HIGH, // The crash likely represents + // a exploitable memory corruption + // vulnerability. + + EXPLOITABILITY_MEDIUM, // The crash appears to corrupt + // memory in a way which may be + // exploitable in some situations. + + EXPLOITABLITY_MEDIUM = EXPLOITABILITY_MEDIUM, // an old misspelling + + EXPLOITABILITY_LOW, // The crash either does not corrupt + // memory directly or control over + // the affected data is limited. The + // issue may still be exploitable + // on certain platforms or situations. + + EXPLOITABILITY_INTERESTING, // The crash does not appear to be + // directly exploitable. However it + // represents a condition which should + // be further analyzed. + + EXPLOITABILITY_NONE, // The crash does not appear to represent + // an exploitable condition. + + EXPLOITABILITY_NOT_ANALYZED, // The crash was not analyzed for + // exploitability because the engine + // was disabled. + + EXPLOITABILITY_ERR_NOENGINE, // The supplied minidump's platform does + // not have a exploitability engine + // associated with it. + + EXPLOITABILITY_ERR_PROCESSING // An error occured within the + // exploitability engine and no rating + // was calculated. +}; + +class ProcessState { + public: + ProcessState() : modules_(NULL) { Clear(); } + ~ProcessState(); + + // Resets the ProcessState to its default values + void Clear(); + + // Accessors. See the data declarations below. + uint32_t time_date_stamp() const { return time_date_stamp_; } + uint32_t process_create_time() const { return process_create_time_; } + bool crashed() const { return crashed_; } + string crash_reason() const { return crash_reason_; } + uint64_t crash_address() const { return crash_address_; } + string assertion() const { return assertion_; } + int requesting_thread() const { return requesting_thread_; } + const vector* threads() const { return &threads_; } + const vector* thread_memory_regions() const { + return &thread_memory_regions_; + } + const SystemInfo* system_info() const { return &system_info_; } + const CodeModules* modules() const { return modules_; } + const vector* modules_without_symbols() const { + return &modules_without_symbols_; + } + const vector* modules_with_corrupt_symbols() const { + return &modules_with_corrupt_symbols_; + } + ExploitabilityRating exploitability() const { return exploitability_; } + + private: + // MinidumpProcessor and MicrodumpProcessor are responsible for building + // ProcessState objects. + friend class MinidumpProcessor; + friend class MicrodumpProcessor; + + // The time-date stamp of the minidump (time_t format) + uint32_t time_date_stamp_; + + // The time-date stamp when the process was created (time_t format) + uint32_t process_create_time_; + + // True if the process crashed, false if the dump was produced outside + // of an exception handler. + bool crashed_; + + // If the process crashed, the type of crash. OS- and possibly CPU- + // specific. For example, "EXCEPTION_ACCESS_VIOLATION" (Windows), + // "EXC_BAD_ACCESS / KERN_INVALID_ADDRESS" (Mac OS X), "SIGSEGV" + // (other Unix). + string crash_reason_; + + // If the process crashed, and if crash_reason implicates memory, + // the memory address that caused the crash. For data access errors, + // this will be the data address that caused the fault. For code errors, + // this will be the address of the instruction that caused the fault. + uint64_t crash_address_; + + // If there was an assertion that was hit, a textual representation + // of that assertion, possibly including the file and line at which + // it occurred. + string assertion_; + + // The index of the thread that requested a dump be written in the + // threads vector. If a dump was produced as a result of a crash, this + // will point to the thread that crashed. If the dump was produced as + // by user code without crashing, and the dump contains extended Breakpad + // information, this will point to the thread that requested the dump. + // If the dump was not produced as a result of an exception and no + // extended Breakpad information is present, this field will be set to -1, + // indicating that the dump thread is not available. + int requesting_thread_; + + // Stacks for each thread (except possibly the exception handler + // thread) at the time of the crash. + vector threads_; + vector thread_memory_regions_; + + // OS and CPU information. + SystemInfo system_info_; + + // The modules that were loaded into the process represented by the + // ProcessState. + const CodeModules *modules_; + + // The modules that didn't have symbols when the report was processed. + vector modules_without_symbols_; + + // The modules that had corrupt symbols when the report was processed. + vector modules_with_corrupt_symbols_; + + // The exploitability rating as determined by the exploitability + // engine. When the exploitability engine is not enabled this + // defaults to EXPLOITABILITY_NOT_ANALYZED. + ExploitabilityRating exploitability_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_PROCESS_STATE_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/source_line_resolver_base.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/source_line_resolver_base.h new file mode 100644 index 00000000..c720b0c3 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/source_line_resolver_base.h @@ -0,0 +1,128 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. +// +// source_line_resolver_base.h: SourceLineResolverBase, an (incomplete) +// implementation of SourceLineResolverInterface. It serves as a common base +// class for concrete implementations: FastSourceLineResolver and +// BasicSourceLineResolver. It is designed for refactoring that removes +// code redundancy in the two concrete source line resolver classes. +// +// See "google_breakpad/processor/source_line_resolver_interface.h" for more +// documentation. + +// Author: Siyang Xie (lambxsy@google.com) + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_BASE_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_BASE_H__ + +#include +#include +#include + +#include "google_breakpad/processor/source_line_resolver_interface.h" + +namespace google_breakpad { + +using std::map; +using std::set; + +// Forward declaration. +// ModuleFactory is a simple factory interface for creating a Module instance +// at run-time. +class ModuleFactory; + +class SourceLineResolverBase : public SourceLineResolverInterface { + public: + // Read the symbol_data from a file with given file_name. + // The part of code was originally in BasicSourceLineResolver::Module's + // LoadMap() method. + // Place dynamically allocated heap buffer in symbol_data. Caller has the + // ownership of the buffer, and should call delete [] to free the buffer. + static bool ReadSymbolFile(const string &file_name, + char **symbol_data, + size_t *symbol_data_size); + + protected: + // Users are not allowed create SourceLineResolverBase instance directly. + SourceLineResolverBase(ModuleFactory *module_factory); + virtual ~SourceLineResolverBase(); + + // Virtual methods inherited from SourceLineResolverInterface. + virtual bool LoadModule(const CodeModule *module, const string &map_file); + virtual bool LoadModuleUsingMapBuffer(const CodeModule *module, + const string &map_buffer); + virtual bool LoadModuleUsingMemoryBuffer(const CodeModule *module, + char *memory_buffer, + size_t memory_buffer_size); + virtual bool ShouldDeleteMemoryBufferAfterLoadModule(); + virtual void UnloadModule(const CodeModule *module); + virtual bool HasModule(const CodeModule *module); + virtual bool IsModuleCorrupt(const CodeModule *module); + virtual void FillSourceLineInfo(StackFrame *frame); + virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame); + virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame); + + // Nested structs and classes. + struct Line; + struct Function; + struct PublicSymbol; + struct CompareString { + bool operator()(const string &s1, const string &s2) const; + }; + // Module is an interface for an in-memory symbol file. + class Module; + class AutoFileCloser; + + // All of the modules that are loaded. + typedef map ModuleMap; + ModuleMap *modules_; + + // The loaded modules that were detecting to be corrupt during load. + typedef set ModuleSet; + ModuleSet *corrupt_modules_; + + // All of heap-allocated buffers that are owned locally by resolver. + typedef std::map MemoryMap; + MemoryMap *memory_buffers_; + + // Creates a concrete module at run-time. + ModuleFactory *module_factory_; + + private: + // ModuleFactory needs to have access to protected type Module. + friend class ModuleFactory; + + // Disallow unwanted copy ctor and assignment operator + SourceLineResolverBase(const SourceLineResolverBase&); + void operator=(const SourceLineResolverBase&); +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_BASE_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/source_line_resolver_interface.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/source_line_resolver_interface.h new file mode 100644 index 00000000..a694bf2e --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/source_line_resolver_interface.h @@ -0,0 +1,117 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// Abstract interface to return function/file/line info for a memory address. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__ + +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/code_module.h" + +namespace google_breakpad { + +struct StackFrame; +struct WindowsFrameInfo; +class CFIFrameInfo; + +class SourceLineResolverInterface { + public: + typedef uint64_t MemAddr; + + virtual ~SourceLineResolverInterface() {} + + // Adds a module to this resolver, returning true on success. + // + // module should have at least the code_file, debug_file, + // and debug_identifier members populated. + // + // map_file should contain line/address mappings for this module. + virtual bool LoadModule(const CodeModule *module, + const string &map_file) = 0; + // Same as above, but takes the contents of a pre-read map buffer + virtual bool LoadModuleUsingMapBuffer(const CodeModule *module, + const string &map_buffer) = 0; + + // Add an interface to load symbol using C-String data instead of string. + // This is useful in the optimization design for avoiding unnecessary copying + // of symbol data, in order to improve memory efficiency. + // LoadModuleUsingMemoryBuffer() does NOT take ownership of memory_buffer. + // LoadModuleUsingMemoryBuffer() null terminates the passed in buffer, if + // the last character is not a null terminator. + virtual bool LoadModuleUsingMemoryBuffer(const CodeModule *module, + char *memory_buffer, + size_t memory_buffer_size) = 0; + + // Return true if the memory buffer should be deleted immediately after + // LoadModuleUsingMemoryBuffer(). Return false if the memory buffer has to be + // alive during the lifetime of the corresponding Module. + virtual bool ShouldDeleteMemoryBufferAfterLoadModule() = 0; + + // Request that the specified module be unloaded from this resolver. + // A resolver may choose to ignore such a request. + virtual void UnloadModule(const CodeModule *module) = 0; + + // Returns true if the module has been loaded. + virtual bool HasModule(const CodeModule *module) = 0; + + // Returns true if the module has been loaded and it is corrupt. + virtual bool IsModuleCorrupt(const CodeModule *module) = 0; + + // Fills in the function_base, function_name, source_file_name, + // and source_line fields of the StackFrame. The instruction and + // module_name fields must already be filled in. + virtual void FillSourceLineInfo(StackFrame *frame) = 0; + + // If Windows stack walking information is available covering + // FRAME's instruction address, return a WindowsFrameInfo structure + // describing it. If the information is not available, returns NULL. + // A NULL return value does not indicate an error. The caller takes + // ownership of any returned WindowsFrameInfo object. + virtual WindowsFrameInfo *FindWindowsFrameInfo(const StackFrame *frame) = 0; + + // If CFI stack walking information is available covering ADDRESS, + // return a CFIFrameInfo structure describing it. If the information + // is not available, return NULL. The caller takes ownership of any + // returned CFIFrameInfo object. + virtual CFIFrameInfo *FindCFIFrameInfo(const StackFrame *frame) = 0; + + protected: + // SourceLineResolverInterface cannot be instantiated except by subclasses + SourceLineResolverInterface() {} +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_SOURCE_LINE_RESOLVER_INTERFACE_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/stack_frame.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/stack_frame.h new file mode 100644 index 00000000..b55eb9c7 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/stack_frame.h @@ -0,0 +1,144 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_H__ + +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" + +namespace google_breakpad { + +class CodeModule; + +struct StackFrame { + // Indicates how well the instruction pointer derived during + // stack walking is trusted. Since the stack walker can resort to + // stack scanning, it can wind up with dubious frames. + // In rough order of "trust metric". + enum FrameTrust { + FRAME_TRUST_NONE, // Unknown + FRAME_TRUST_SCAN, // Scanned the stack, found this + FRAME_TRUST_CFI_SCAN, // Found while scanning stack using call frame info + FRAME_TRUST_FP, // Derived from frame pointer + FRAME_TRUST_CFI, // Derived from call frame info + FRAME_TRUST_PREWALKED, // Explicitly provided by some external stack walker. + FRAME_TRUST_CONTEXT // Given as instruction pointer in a context + }; + + StackFrame() + : instruction(), + module(NULL), + function_name(), + function_base(), + source_file_name(), + source_line(), + source_line_base(), + trust(FRAME_TRUST_NONE) {} + virtual ~StackFrame() {} + + // Return a string describing how this stack frame was found + // by the stackwalker. + string trust_description() const { + switch (trust) { + case StackFrame::FRAME_TRUST_CONTEXT: + return "given as instruction pointer in context"; + case StackFrame::FRAME_TRUST_PREWALKED: + return "recovered by external stack walker"; + case StackFrame::FRAME_TRUST_CFI: + return "call frame info"; + case StackFrame::FRAME_TRUST_CFI_SCAN: + return "call frame info with scanning"; + case StackFrame::FRAME_TRUST_FP: + return "previous frame's frame pointer"; + case StackFrame::FRAME_TRUST_SCAN: + return "stack scanning"; + default: + return "unknown"; + } + }; + + // Return the actual return address, as saved on the stack or in a + // register. See the comments for 'instruction', below, for details. + virtual uint64_t ReturnAddress() const { return instruction; } + + // The program counter location as an absolute virtual address. + // + // - For the innermost called frame in a stack, this will be an exact + // program counter or instruction pointer value. + // + // - For all other frames, this address is within the instruction that + // caused execution to branch to this frame's callee (although it may + // not point to the exact beginning of that instruction). This ensures + // that, when we look up the source code location for this frame, we + // get the source location of the call, not of the point at which + // control will resume when the call returns, which may be on the next + // line. (If the compiler knows the callee never returns, it may even + // place the call instruction at the very end of the caller's machine + // code, such that the "return address" (which will never be used) + // immediately after the call instruction is in an entirely different + // function, perhaps even from a different source file.) + // + // On some architectures, the return address as saved on the stack or in + // a register is fine for looking up the point of the call. On others, it + // requires adjustment. ReturnAddress returns the address as saved by the + // machine. + uint64_t instruction; + + // The module in which the instruction resides. + const CodeModule *module; + + // The function name, may be omitted if debug symbols are not available. + string function_name; + + // The start address of the function, may be omitted if debug symbols + // are not available. + uint64_t function_base; + + // The source file name, may be omitted if debug symbols are not available. + string source_file_name; + + // The (1-based) source line number, may be omitted if debug symbols are + // not available. + int source_line; + + // The start address of the source line, may be omitted if debug symbols + // are not available. + uint64_t source_line_base; + + // Amount of trust the stack walker has in the instruction pointer + // of this frame. + FrameTrust trust; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/stack_frame_cpu.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/stack_frame_cpu.h new file mode 100644 index 00000000..dc5d8ae6 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/stack_frame_cpu.h @@ -0,0 +1,405 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// stack_frame_cpu.h: CPU-specific StackFrame extensions. +// +// These types extend the StackFrame structure to carry CPU-specific register +// state. They are defined in this header instead of stack_frame.h to +// avoid the need to include minidump_format.h when only the generic +// StackFrame type is needed. +// +// Author: Mark Mentovai + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_CPU_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_CPU_H__ + +#include "google_breakpad/common/minidump_format.h" +#include "google_breakpad/processor/stack_frame.h" + +namespace google_breakpad { + +struct WindowsFrameInfo; +class CFIFrameInfo; + +struct StackFrameX86 : public StackFrame { + // ContextValidity has one entry for each relevant hardware pointer + // register (%eip and %esp) and one entry for each general-purpose + // register. It's worthwhile having validity flags for caller-saves + // registers: they are valid in the youngest frame, and such a frame + // might save a callee-saves register in a caller-saves register, but + // SimpleCFIWalker won't touch registers unless they're marked as valid. + enum ContextValidity { + CONTEXT_VALID_NONE = 0, + CONTEXT_VALID_EIP = 1 << 0, + CONTEXT_VALID_ESP = 1 << 1, + CONTEXT_VALID_EBP = 1 << 2, + CONTEXT_VALID_EAX = 1 << 3, + CONTEXT_VALID_EBX = 1 << 4, + CONTEXT_VALID_ECX = 1 << 5, + CONTEXT_VALID_EDX = 1 << 6, + CONTEXT_VALID_ESI = 1 << 7, + CONTEXT_VALID_EDI = 1 << 8, + CONTEXT_VALID_ALL = -1 + }; + + StackFrameX86() + : context(), + context_validity(CONTEXT_VALID_NONE), + windows_frame_info(NULL), + cfi_frame_info(NULL) {} + ~StackFrameX86(); + + // Overriden to return the return address as saved on the stack. + virtual uint64_t ReturnAddress() const; + + // Register state. This is only fully valid for the topmost frame in a + // stack. In other frames, the values of nonvolatile registers may be + // present, given sufficient debugging information. Refer to + // context_validity. + MDRawContextX86 context; + + // context_validity is actually ContextValidity, but int is used because + // the OR operator doesn't work well with enumerated types. This indicates + // which fields in context are valid. + int context_validity; + + // Any stack walking information we found describing this.instruction. + // These may be NULL if there is no such information for that address. + WindowsFrameInfo *windows_frame_info; + CFIFrameInfo *cfi_frame_info; +}; + +struct StackFramePPC : public StackFrame { + // ContextValidity should eventually contain entries for the validity of + // other nonvolatile (callee-save) registers as in + // StackFrameX86::ContextValidity, but the ppc stackwalker doesn't currently + // locate registers other than the ones listed here. + enum ContextValidity { + CONTEXT_VALID_NONE = 0, + CONTEXT_VALID_SRR0 = 1 << 0, + CONTEXT_VALID_GPR1 = 1 << 1, + CONTEXT_VALID_ALL = -1 + }; + + StackFramePPC() : context(), context_validity(CONTEXT_VALID_NONE) {} + + // Register state. This is only fully valid for the topmost frame in a + // stack. In other frames, the values of nonvolatile registers may be + // present, given sufficient debugging information. Refer to + // context_validity. + MDRawContextPPC context; + + // context_validity is actually ContextValidity, but int is used because + // the OR operator doesn't work well with enumerated types. This indicates + // which fields in context are valid. + int context_validity; +}; + +struct StackFramePPC64 : public StackFrame { + // ContextValidity should eventually contain entries for the validity of + // other nonvolatile (callee-save) registers as in + // StackFrameX86::ContextValidity, but the ppc stackwalker doesn't currently + // locate registers other than the ones listed here. + enum ContextValidity { + CONTEXT_VALID_NONE = 0, + CONTEXT_VALID_SRR0 = 1 << 0, + CONTEXT_VALID_GPR1 = 1 << 1, + CONTEXT_VALID_ALL = -1 + }; + + StackFramePPC64() : context(), context_validity(CONTEXT_VALID_NONE) {} + + // Register state. This is only fully valid for the topmost frame in a + // stack. In other frames, the values of nonvolatile registers may be + // present, given sufficient debugging information. Refer to + // context_validity. + MDRawContextPPC64 context; + + // context_validity is actually ContextValidity, but int is used because + // the OR operator doesn't work well with enumerated types. This indicates + // which fields in context are valid. + int context_validity; +}; + +struct StackFrameAMD64 : public StackFrame { + // ContextValidity has one entry for each register that we might be able + // to recover. + enum ContextValidity { + CONTEXT_VALID_NONE = 0, + CONTEXT_VALID_RAX = 1 << 0, + CONTEXT_VALID_RDX = 1 << 1, + CONTEXT_VALID_RCX = 1 << 2, + CONTEXT_VALID_RBX = 1 << 3, + CONTEXT_VALID_RSI = 1 << 4, + CONTEXT_VALID_RDI = 1 << 5, + CONTEXT_VALID_RBP = 1 << 6, + CONTEXT_VALID_RSP = 1 << 7, + CONTEXT_VALID_R8 = 1 << 8, + CONTEXT_VALID_R9 = 1 << 9, + CONTEXT_VALID_R10 = 1 << 10, + CONTEXT_VALID_R11 = 1 << 11, + CONTEXT_VALID_R12 = 1 << 12, + CONTEXT_VALID_R13 = 1 << 13, + CONTEXT_VALID_R14 = 1 << 14, + CONTEXT_VALID_R15 = 1 << 15, + CONTEXT_VALID_RIP = 1 << 16, + CONTEXT_VALID_ALL = -1 + }; + + StackFrameAMD64() : context(), context_validity(CONTEXT_VALID_NONE) {} + + // Overriden to return the return address as saved on the stack. + virtual uint64_t ReturnAddress() const; + + // Register state. This is only fully valid for the topmost frame in a + // stack. In other frames, which registers are present depends on what + // debugging information we had available. Refer to context_validity. + MDRawContextAMD64 context; + + // For each register in context whose value has been recovered, we set + // the corresponding CONTEXT_VALID_ bit in context_validity. + // + // context_validity's type should actually be ContextValidity, but + // we use int instead because the bitwise inclusive or operator + // yields an int when applied to enum values, and C++ doesn't + // silently convert from ints to enums. + int context_validity; +}; + +struct StackFrameSPARC : public StackFrame { + // to be confirmed + enum ContextValidity { + CONTEXT_VALID_NONE = 0, + CONTEXT_VALID_PC = 1 << 0, + CONTEXT_VALID_SP = 1 << 1, + CONTEXT_VALID_FP = 1 << 2, + CONTEXT_VALID_ALL = -1 + }; + + StackFrameSPARC() : context(), context_validity(CONTEXT_VALID_NONE) {} + + // Register state. This is only fully valid for the topmost frame in a + // stack. In other frames, the values of nonvolatile registers may be + // present, given sufficient debugging information. Refer to + // context_validity. + MDRawContextSPARC context; + + // context_validity is actually ContextValidity, but int is used because + // the OR operator doesn't work well with enumerated types. This indicates + // which fields in context are valid. + int context_validity; +}; + +struct StackFrameARM : public StackFrame { + // A flag for each register we might know. + enum ContextValidity { + CONTEXT_VALID_NONE = 0, + CONTEXT_VALID_R0 = 1 << 0, + CONTEXT_VALID_R1 = 1 << 1, + CONTEXT_VALID_R2 = 1 << 2, + CONTEXT_VALID_R3 = 1 << 3, + CONTEXT_VALID_R4 = 1 << 4, + CONTEXT_VALID_R5 = 1 << 5, + CONTEXT_VALID_R6 = 1 << 6, + CONTEXT_VALID_R7 = 1 << 7, + CONTEXT_VALID_R8 = 1 << 8, + CONTEXT_VALID_R9 = 1 << 9, + CONTEXT_VALID_R10 = 1 << 10, + CONTEXT_VALID_R11 = 1 << 11, + CONTEXT_VALID_R12 = 1 << 12, + CONTEXT_VALID_R13 = 1 << 13, + CONTEXT_VALID_R14 = 1 << 14, + CONTEXT_VALID_R15 = 1 << 15, + CONTEXT_VALID_ALL = ~CONTEXT_VALID_NONE, + + // Aliases for registers with dedicated or conventional roles. + CONTEXT_VALID_FP = CONTEXT_VALID_R11, + CONTEXT_VALID_SP = CONTEXT_VALID_R13, + CONTEXT_VALID_LR = CONTEXT_VALID_R14, + CONTEXT_VALID_PC = CONTEXT_VALID_R15 + }; + + StackFrameARM() : context(), context_validity(CONTEXT_VALID_NONE) {} + + // Return the ContextValidity flag for register rN. + static ContextValidity RegisterValidFlag(int n) { + return ContextValidity(1 << n); + } + + // Register state. This is only fully valid for the topmost frame in a + // stack. In other frames, the values of nonvolatile registers may be + // present, given sufficient debugging information. Refer to + // context_validity. + MDRawContextARM context; + + // For each register in context whose value has been recovered, we set + // the corresponding CONTEXT_VALID_ bit in context_validity. + // + // context_validity's type should actually be ContextValidity, but + // we use int instead because the bitwise inclusive or operator + // yields an int when applied to enum values, and C++ doesn't + // silently convert from ints to enums. + int context_validity; +}; + +struct StackFrameARM64 : public StackFrame { + // A flag for each register we might know. Note that we can't use an enum + // here as there are 33 values to represent. + static const uint64_t CONTEXT_VALID_NONE = 0; + static const uint64_t CONTEXT_VALID_X0 = 1ULL << 0; + static const uint64_t CONTEXT_VALID_X1 = 1ULL << 1; + static const uint64_t CONTEXT_VALID_X2 = 1ULL << 2; + static const uint64_t CONTEXT_VALID_X3 = 1ULL << 3; + static const uint64_t CONTEXT_VALID_X4 = 1ULL << 4; + static const uint64_t CONTEXT_VALID_X5 = 1ULL << 5; + static const uint64_t CONTEXT_VALID_X6 = 1ULL << 6; + static const uint64_t CONTEXT_VALID_X7 = 1ULL << 7; + static const uint64_t CONTEXT_VALID_X8 = 1ULL << 8; + static const uint64_t CONTEXT_VALID_X9 = 1ULL << 9; + static const uint64_t CONTEXT_VALID_X10 = 1ULL << 10; + static const uint64_t CONTEXT_VALID_X11 = 1ULL << 11; + static const uint64_t CONTEXT_VALID_X12 = 1ULL << 12; + static const uint64_t CONTEXT_VALID_X13 = 1ULL << 13; + static const uint64_t CONTEXT_VALID_X14 = 1ULL << 14; + static const uint64_t CONTEXT_VALID_X15 = 1ULL << 15; + static const uint64_t CONTEXT_VALID_X16 = 1ULL << 16; + static const uint64_t CONTEXT_VALID_X17 = 1ULL << 17; + static const uint64_t CONTEXT_VALID_X18 = 1ULL << 18; + static const uint64_t CONTEXT_VALID_X19 = 1ULL << 19; + static const uint64_t CONTEXT_VALID_X20 = 1ULL << 20; + static const uint64_t CONTEXT_VALID_X21 = 1ULL << 21; + static const uint64_t CONTEXT_VALID_X22 = 1ULL << 22; + static const uint64_t CONTEXT_VALID_X23 = 1ULL << 23; + static const uint64_t CONTEXT_VALID_X24 = 1ULL << 24; + static const uint64_t CONTEXT_VALID_X25 = 1ULL << 25; + static const uint64_t CONTEXT_VALID_X26 = 1ULL << 26; + static const uint64_t CONTEXT_VALID_X27 = 1ULL << 27; + static const uint64_t CONTEXT_VALID_X28 = 1ULL << 28; + static const uint64_t CONTEXT_VALID_X29 = 1ULL << 29; + static const uint64_t CONTEXT_VALID_X30 = 1ULL << 30; + static const uint64_t CONTEXT_VALID_X31 = 1ULL << 31; + static const uint64_t CONTEXT_VALID_X32 = 1ULL << 32; + static const uint64_t CONTEXT_VALID_ALL = ~CONTEXT_VALID_NONE; + + // Aliases for registers with dedicated or conventional roles. + static const uint64_t CONTEXT_VALID_FP = CONTEXT_VALID_X29; + static const uint64_t CONTEXT_VALID_LR = CONTEXT_VALID_X30; + static const uint64_t CONTEXT_VALID_SP = CONTEXT_VALID_X31; + static const uint64_t CONTEXT_VALID_PC = CONTEXT_VALID_X32; + + StackFrameARM64() : context(), + context_validity(CONTEXT_VALID_NONE) {} + + // Return the validity flag for register xN. + static uint64_t RegisterValidFlag(int n) { + return 1ULL << n; + } + + // Register state. This is only fully valid for the topmost frame in a + // stack. In other frames, the values of nonvolatile registers may be + // present, given sufficient debugging information. Refer to + // context_validity. + MDRawContextARM64 context; + + // For each register in context whose value has been recovered, we set + // the corresponding CONTEXT_VALID_ bit in context_validity. + uint64_t context_validity; +}; + +struct StackFrameMIPS : public StackFrame { + // MIPS callee save registers for o32 ABI (32bit registers) are: + // 1. $s0-$s7, + // 2. $sp, $fp + // 3. $f20-$f31 + // + // The register structure is available at + // http://en.wikipedia.org/wiki/MIPS_architecture#Compiler_register_usage + +#define INDEX_MIPS_REG_S0 MD_CONTEXT_MIPS_REG_S0 // 16 +#define INDEX_MIPS_REG_S7 MD_CONTEXT_MIPS_REG_S7 // 23 +#define INDEX_MIPS_REG_GP MD_CONTEXT_MIPS_REG_GP // 28 +#define INDEX_MIPS_REG_RA MD_CONTEXT_MIPS_REG_RA // 31 +#define INDEX_MIPS_REG_PC 34 +#define SHIFT_MIPS_REG_S0 0 +#define SHIFT_MIPS_REG_GP 8 +#define SHIFT_MIPS_REG_PC 12 + + enum ContextValidity { + CONTEXT_VALID_NONE = 0, + CONTEXT_VALID_S0 = 1 << 0, // $16 + CONTEXT_VALID_S1 = 1 << 1, // $17 + CONTEXT_VALID_S2 = 1 << 2, // $18 + CONTEXT_VALID_S3 = 1 << 3, // $19 + CONTEXT_VALID_S4 = 1 << 4, // $20 + CONTEXT_VALID_S5 = 1 << 5, // $21 + CONTEXT_VALID_S6 = 1 << 6, // $22 + CONTEXT_VALID_S7 = 1 << 7, // $23 + // GP is not calee-save for o32 abi. + CONTEXT_VALID_GP = 1 << 8, // $28 + CONTEXT_VALID_SP = 1 << 9, // $29 + CONTEXT_VALID_FP = 1 << 10, // $30 + CONTEXT_VALID_RA = 1 << 11, // $31 + CONTEXT_VALID_PC = 1 << 12, // $34 + CONTEXT_VALID_ALL = ~CONTEXT_VALID_NONE + }; + + // Return the ContextValidity flag for register rN. + static ContextValidity RegisterValidFlag(int n) { + if (n >= INDEX_MIPS_REG_S0 && n <= INDEX_MIPS_REG_S7) + return ContextValidity(1 << (n - INDEX_MIPS_REG_S0 + SHIFT_MIPS_REG_S0)); + else if (n >= INDEX_MIPS_REG_GP && n <= INDEX_MIPS_REG_RA) + return ContextValidity(1 << (n - INDEX_MIPS_REG_GP + SHIFT_MIPS_REG_GP)); + else if (n == INDEX_MIPS_REG_PC) + return ContextValidity(1 << SHIFT_MIPS_REG_PC); + + return CONTEXT_VALID_NONE; + } + + StackFrameMIPS() : context(), context_validity(CONTEXT_VALID_NONE) {} + + // Register state. This is only fully valid for the topmost frame in a + // stack. In other frames, which registers are present depends on what + // debugging information were available. Refer to 'context_validity' below. + MDRawContextMIPS context; + + // For each register in context whose value has been recovered, + // the corresponding CONTEXT_VALID_ bit in 'context_validity' is set. + // + // context_validity's type should actually be ContextValidity, but + // type int is used instead because the bitwise inclusive or operator + // yields an int when applied to enum values, and C++ doesn't + // silently convert from ints to enums. + int context_validity; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_CPU_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/stack_frame_symbolizer.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/stack_frame_symbolizer.h new file mode 100644 index 00000000..074907cb --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/stack_frame_symbolizer.h @@ -0,0 +1,108 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2012 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// Helper class that encapsulates the logic of how symbol supplier interacts +// with source line resolver to fill stack frame information. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_SYMBOLIZER_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_SYMBOLIZER_H__ + +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/code_module.h" + +namespace google_breakpad { +class CFIFrameInfo; +class CodeModules; +class SymbolSupplier; +class SourceLineResolverInterface; +struct StackFrame; +struct SystemInfo; +struct WindowsFrameInfo; + +class StackFrameSymbolizer { + public: + enum SymbolizerResult { + // Symbol data was found and successfully loaded in resolver. + // This does NOT guarantee source line info is found within symbol file. + kNoError, + // This indicates non-critical error, such as, no code module found for + // frame's instruction, no symbol file, or resolver failed to load symbol. + kError, + // This indicates error for which stack walk should be interrupted + // and retried in future. + kInterrupt, + // Symbol data was found and loaded in resolver however some corruptions + // were detected. + kWarningCorruptSymbols, + }; + + StackFrameSymbolizer(SymbolSupplier* supplier, + SourceLineResolverInterface* resolver); + + virtual ~StackFrameSymbolizer() { } + + // Encapsulate the step of resolving source line info for a stack frame. + // "frame" must not be NULL. + virtual SymbolizerResult FillSourceLineInfo(const CodeModules* modules, + const SystemInfo* system_info, + StackFrame* stack_frame); + + virtual WindowsFrameInfo* FindWindowsFrameInfo(const StackFrame* frame); + + virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame); + + // Reset internal (locally owned) data as if the helper is re-instantiated. + // A typical case is to call Reset() after processing an individual report + // before start to process next one, in order to reset internal information + // about missing symbols found so far. + virtual void Reset() { no_symbol_modules_.clear(); } + + // Returns true if there is valid implementation for stack symbolization. + virtual bool HasImplementation() { return resolver_ && supplier_; } + + SourceLineResolverInterface* resolver() { return resolver_; } + SymbolSupplier* supplier() { return supplier_; } + + protected: + SymbolSupplier* supplier_; + SourceLineResolverInterface* resolver_; + // A list of modules known to have symbols missing. This helps avoid + // repeated lookups for the missing symbols within one minidump. + std::set no_symbol_modules_; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_STACK_FRAME_SYMBOLIZER_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/stackwalker.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/stackwalker.h new file mode 100644 index 00000000..a1bd3e7f --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/stackwalker.h @@ -0,0 +1,235 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// stackwalker.h: Generic stackwalker. +// +// The Stackwalker class is an abstract base class providing common generic +// methods that apply to stacks from all systems. Specific implementations +// will extend this class by providing GetContextFrame and GetCallerFrame +// methods to fill in system-specific data in a StackFrame structure. +// Stackwalker assembles these StackFrame strucutres into a CallStack. +// +// Author: Mark Mentovai + + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_STACKWALKER_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_STACKWALKER_H__ + +#include +#include +#include + +#include "common/using_std_string.h" +#include "google_breakpad/common/breakpad_types.h" +#include "google_breakpad/processor/code_modules.h" +#include "google_breakpad/processor/memory_region.h" +#include "google_breakpad/processor/stack_frame_symbolizer.h" + +namespace google_breakpad { + +class CallStack; +class DumpContext; +class StackFrameSymbolizer; + +using std::set; +using std::vector; + +class Stackwalker { + public: + virtual ~Stackwalker() {} + + // Populates the given CallStack by calling GetContextFrame and + // GetCallerFrame. The frames are further processed to fill all available + // data. Returns true if the stackwalk completed, or false if it was + // interrupted by SymbolSupplier::GetSymbolFile(). + // Upon return, |modules_without_symbols| will be populated with pointers to + // the code modules (CodeModule*) that DON'T have symbols. + // |modules_with_corrupt_symbols| will be populated with pointers to the + // modules which have corrupt symbols. |modules_without_symbols| and + // |modules_with_corrupt_symbols| DO NOT take ownership of the code modules. + // The lifetime of these code modules is the same as the lifetime of the + // CodeModules passed to the StackWalker constructor (which currently + // happens to be the lifetime of the Breakpad's ProcessingState object). + // There is a check for duplicate modules so no duplicates are expected. + bool Walk(CallStack* stack, + vector* modules_without_symbols, + vector* modules_with_corrupt_symbols); + + // Returns a new concrete subclass suitable for the CPU that a stack was + // generated on, according to the CPU type indicated by the context + // argument. If no suitable concrete subclass exists, returns NULL. + static Stackwalker* StackwalkerForCPU( + const SystemInfo* system_info, + DumpContext* context, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* resolver_helper); + + static void set_max_frames(uint32_t max_frames) { + max_frames_ = max_frames; + max_frames_set_ = true; + } + static uint32_t max_frames() { return max_frames_; } + + static void set_max_frames_scanned(uint32_t max_frames_scanned) { + max_frames_scanned_ = max_frames_scanned; + } + + protected: + // system_info identifies the operating system, NULL or empty if unknown. + // memory identifies a MemoryRegion that provides the stack memory + // for the stack to walk. modules, if non-NULL, is a CodeModules + // object that is used to look up which code module each stack frame is + // associated with. frame_symbolizer is a StackFrameSymbolizer object that + // encapsulates the logic of how source line resolver interacts with symbol + // supplier to symbolize stack frame and look up caller frame information + // (see stack_frame_symbolizer.h). + // frame_symbolizer MUST NOT be NULL (asserted). + Stackwalker(const SystemInfo* system_info, + MemoryRegion* memory, + const CodeModules* modules, + StackFrameSymbolizer* frame_symbolizer); + + // This can be used to filter out potential return addresses when + // the stack walker resorts to stack scanning. + // Returns true if any of: + // * This address is within a loaded module, but we don't have symbols + // for that module. + // * This address is within a loaded module for which we have symbols, + // and falls inside a function in that module. + // Returns false otherwise. + bool InstructionAddressSeemsValid(uint64_t address); + + // The default number of words to search through on the stack + // for a return address. + static const int kRASearchWords; + + template + bool ScanForReturnAddress(InstructionType location_start, + InstructionType* location_found, + InstructionType* ip_found, + bool is_context_frame) { + // When searching for the caller of the context frame, + // allow the scanner to look farther down the stack. + const int search_words = is_context_frame ? + kRASearchWords * 4 : + kRASearchWords; + + return ScanForReturnAddress(location_start, location_found, ip_found, + search_words); + } + + // Scan the stack starting at location_start, looking for an address + // that looks like a valid instruction pointer. Addresses must + // 1) be contained in the current stack memory + // 2) pass the checks in InstructionAddressSeemsValid + // + // Returns true if a valid-looking instruction pointer was found. + // When returning true, sets location_found to the address at which + // the value was found, and ip_found to the value contained at that + // location in memory. + template + bool ScanForReturnAddress(InstructionType location_start, + InstructionType* location_found, + InstructionType* ip_found, + int searchwords) { + for (InstructionType location = location_start; + location <= location_start + searchwords * sizeof(InstructionType); + location += sizeof(InstructionType)) { + InstructionType ip; + if (!memory_->GetMemoryAtAddress(location, &ip)) + break; + + if (modules_ && modules_->GetModuleForAddress(ip) && + InstructionAddressSeemsValid(ip)) { + *ip_found = ip; + *location_found = location; + return true; + } + } + // nothing found + return false; + } + + // Information about the system that produced the minidump. Subclasses + // and the SymbolSupplier may find this information useful. + const SystemInfo* system_info_; + + // The stack memory to walk. Subclasses will require this region to + // get information from the stack. + MemoryRegion* memory_; + + // A list of modules, for populating each StackFrame's module information. + // This field is optional and may be NULL. + const CodeModules* modules_; + + protected: + // The StackFrameSymbolizer implementation. + StackFrameSymbolizer* frame_symbolizer_; + + private: + // Obtains the context frame, the innermost called procedure in a stack + // trace. Returns NULL on failure. GetContextFrame allocates a new + // StackFrame (or StackFrame subclass), ownership of which is taken by + // the caller. + virtual StackFrame* GetContextFrame() = 0; + + // Obtains a caller frame. Each call to GetCallerFrame should return the + // frame that called the last frame returned by GetContextFrame or + // GetCallerFrame. To aid this purpose, stack contains the CallStack + // made of frames that have already been walked. GetCallerFrame should + // return NULL on failure or when there are no more caller frames (when + // the end of the stack has been reached). GetCallerFrame allocates a new + // StackFrame (or StackFrame subclass), ownership of which is taken by + // the caller. |stack_scan_allowed| controls whether stack scanning is + // an allowable frame-recovery method, since it is desirable to be able to + // disable stack scanning in performance-critical use cases. + virtual StackFrame* GetCallerFrame(const CallStack* stack, + bool stack_scan_allowed) = 0; + + // The maximum number of frames Stackwalker will walk through. + // This defaults to 1024 to prevent infinite loops. + static uint32_t max_frames_; + + // Keep track of whether max_frames_ has been set by the user, since + // it affects whether or not an error message is printed in the case + // where an unwind got stopped by the limit. + static bool max_frames_set_; + + // The maximum number of stack-scanned and otherwise untrustworthy + // frames allowed. Stack-scanning can be expensive, so the option to + // disable or limit it is helpful in cases where unwind performance is + // important. This defaults to 1024, the same as max_frames_. + static uint32_t max_frames_scanned_; +}; + +} // namespace google_breakpad + + +#endif // GOOGLE_BREAKPAD_PROCESSOR_STACKWALKER_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/symbol_supplier.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/symbol_supplier.h new file mode 100644 index 00000000..a042081f --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/symbol_supplier.h @@ -0,0 +1,99 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// The caller may implement the SymbolSupplier abstract base class +// to provide symbols for a given module. + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_SYMBOL_SUPPLIER_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_SYMBOL_SUPPLIER_H__ + +#include +#include "common/using_std_string.h" + +namespace google_breakpad { + +class CodeModule; +struct SystemInfo; + +class SymbolSupplier { + public: + // Result type for GetSymbolFile + enum SymbolResult { + // no symbols were found, but continue processing + NOT_FOUND, + + // symbols were found, and the path has been placed in symbol_file + FOUND, + + // stops processing the minidump immediately + INTERRUPT + }; + + virtual ~SymbolSupplier() {} + + // Retrieves the symbol file for the given CodeModule, placing the + // path in symbol_file if successful. system_info contains strings + // identifying the operating system and CPU; SymbolSupplier may use + // to help locate the symbol file. system_info may be NULL or its + // fields may be empty if these values are unknown. symbol_file + // must be a pointer to a valid string + virtual SymbolResult GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file) = 0; + // Same as above, except also places symbol data into symbol_data. + // If symbol_data is NULL, the data is not returned. + // TODO(nealsid) Once we have symbol data caching behavior implemented + // investigate making all symbol suppliers implement all methods, + // and make this pure virtual + virtual SymbolResult GetSymbolFile(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + string *symbol_data) = 0; + + // Same as above, except allocates data buffer on heap and then places the + // symbol data into the buffer as C-string. + // SymbolSupplier is responsible for deleting the data buffer. After the call + // to GetCStringSymbolData(), the caller should call FreeSymbolData(const + // Module *module) once the data buffer is no longer needed. + // If symbol_data is not NULL, symbol supplier won't return FOUND unless it + // returns a valid buffer in symbol_data, e.g., returns INTERRUPT on memory + // allocation failure. + virtual SymbolResult GetCStringSymbolData(const CodeModule *module, + const SystemInfo *system_info, + string *symbol_file, + char **symbol_data, + size_t *symbol_data_size) = 0; + + // Frees the data buffer allocated for the module in GetCStringSymbolData. + virtual void FreeSymbolData(const CodeModule *module) = 0; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_SYMBOL_SUPPLIER_H__ diff --git a/TMessagesProj/jni/breakpad/google_breakpad/processor/system_info.h b/TMessagesProj/jni/breakpad/google_breakpad/processor/system_info.h new file mode 100644 index 00000000..9583d9e8 --- /dev/null +++ b/TMessagesProj/jni/breakpad/google_breakpad/processor/system_info.h @@ -0,0 +1,98 @@ +// Copyright (c) 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS 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 COPYRIGHT +// OWNER OR 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. + +// system_info.h: Information about the system that was running a program +// when a crash report was produced. +// +// Author: Mark Mentovai + +#ifndef GOOGLE_BREAKPAD_PROCESSOR_SYSTEM_INFO_H__ +#define GOOGLE_BREAKPAD_PROCESSOR_SYSTEM_INFO_H__ + +#include + +#include "common/using_std_string.h" + +namespace google_breakpad { + +struct SystemInfo { + public: + SystemInfo() : os(), os_short(), os_version(), cpu(), cpu_info(), + cpu_count(0) {} + + // Resets the SystemInfo object to its default values. + void Clear() { + os.clear(); + os_short.clear(); + os_version.clear(); + cpu.clear(); + cpu_info.clear(); + cpu_count = 0; + } + + // A string identifying the operating system, such as "Windows NT", + // "Mac OS X", or "Linux". If the information is present in the dump but + // its value is unknown, this field will contain a numeric value. If + // the information is not present in the dump, this field will be empty. + string os; + + // A short form of the os string, using lowercase letters and no spaces, + // suitable for use in a filesystem. Possible values include "windows", + // "mac", "linux" and "nacl". Empty if the information is not present + // in the dump or if the OS given by the dump is unknown. The values + // stored in this field should match those used by + // MinidumpSystemInfo::GetOS. + string os_short; + + // A string identifying the version of the operating system, such as + // "5.1.2600 Service Pack 2" or "10.4.8 8L2127". If the dump does not + // contain this information, this field will be empty. + string os_version; + + // A string identifying the basic CPU family, such as "x86" or "ppc". + // If this information is present in the dump but its value is unknown, + // this field will contain a numeric value. If the information is not + // present in the dump, this field will be empty. The values stored in + // this field should match those used by MinidumpSystemInfo::GetCPU. + string cpu; + + // A string further identifying the specific CPU, such as + // "GenuineIntel level 6 model 13 stepping 8". If the information is not + // present in the dump, or additional identifying information is not + // defined for the CPU family, this field will be empty. + string cpu_info; + + // The number of processors in the system. Will be greater than one for + // multi-core systems. + int cpu_count; +}; + +} // namespace google_breakpad + +#endif // GOOGLE_BREAKPAD_PROCESSOR_SYSTEM_INFO_H__ diff --git a/TMessagesProj/jni/breakpad/third_party/lss/linux_syscall_support.h b/TMessagesProj/jni/breakpad/third_party/lss/linux_syscall_support.h new file mode 100644 index 00000000..1fe0ae89 --- /dev/null +++ b/TMessagesProj/jni/breakpad/third_party/lss/linux_syscall_support.h @@ -0,0 +1,4029 @@ +/* Copyright (c) 2005-2011, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS 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 COPYRIGHT + * OWNER OR 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. + * + * --- + * Author: Markus Gutschke + */ + +/* This file includes Linux-specific support functions common to the + * coredumper and the thread lister; primarily, this is a collection + * of direct system calls, and a couple of symbols missing from + * standard header files. + * There are a few options that the including file can set to control + * the behavior of this file: + * + * SYS_CPLUSPLUS: + * The entire header file will normally be wrapped in 'extern "C" { }", + * making it suitable for compilation as both C and C++ source. If you + * do not want to do this, you can set the SYS_CPLUSPLUS macro to inhibit + * the wrapping. N.B. doing so will suppress inclusion of all prerequisite + * system header files, too. It is the caller's responsibility to provide + * the necessary definitions. + * + * SYS_ERRNO: + * All system calls will update "errno" unless overriden by setting the + * SYS_ERRNO macro prior to including this file. SYS_ERRNO should be + * an l-value. + * + * SYS_INLINE: + * New symbols will be defined "static inline", unless overridden by + * the SYS_INLINE macro. + * + * SYS_LINUX_SYSCALL_SUPPORT_H + * This macro is used to avoid multiple inclusions of this header file. + * If you need to include this file more than once, make sure to + * unset SYS_LINUX_SYSCALL_SUPPORT_H before each inclusion. + * + * SYS_PREFIX: + * New system calls will have a prefix of "sys_" unless overridden by + * the SYS_PREFIX macro. Valid values for this macro are [0..9] which + * results in prefixes "sys[0..9]_". It is also possible to set this + * macro to -1, which avoids all prefixes. + * + * SYS_SYSCALL_ENTRYPOINT: + * Some applications (such as sandboxes that filter system calls), need + * to be able to run custom-code each time a system call is made. If this + * macro is defined, it expands to the name of a "common" symbol. If + * this symbol is assigned a non-NULL pointer value, it is used as the + * address of the system call entrypoint. + * A pointer to this symbol can be obtained by calling + * get_syscall_entrypoint() + * + * This file defines a few internal symbols that all start with "LSS_". + * Do not access these symbols from outside this file. They are not part + * of the supported API. + */ +#ifndef SYS_LINUX_SYSCALL_SUPPORT_H +#define SYS_LINUX_SYSCALL_SUPPORT_H + +/* We currently only support x86-32, x86-64, ARM, MIPS, and PPC on Linux. + * Porting to other related platforms should not be difficult. + */ +#if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || \ + defined(__mips__) || defined(__PPC__) || defined(__ARM_EABI__) || \ + defined(__aarch64__)) \ + && (defined(__linux) || defined(__ANDROID__)) + +#ifndef SYS_CPLUSPLUS +#ifdef __cplusplus +/* Some system header files in older versions of gcc neglect to properly + * handle being included from C++. As it appears to be harmless to have + * multiple nested 'extern "C"' blocks, just add another one here. + */ +extern "C" { +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __mips__ +/* Include definitions of the ABI currently in use. */ +#include +#endif +#endif + +/* The Android NDK's #defines these macros as aliases + * to their non-64 counterparts. To avoid naming conflict, remove them. */ +#ifdef __ANDROID__ + /* These are restored by the corresponding #pragma pop_macro near + * the end of this file. */ +# pragma push_macro("stat64") +# pragma push_macro("fstat64") +# pragma push_macro("lstat64") +# undef stat64 +# undef fstat64 +# undef lstat64 +#endif + +/* As glibc often provides subtly incompatible data structures (and implicit + * wrapper functions that convert them), we provide our own kernel data + * structures for use by the system calls. + * These structures have been developed by using Linux 2.6.23 headers for + * reference. Note though, we do not care about exact API compatibility + * with the kernel, and in fact the kernel often does not have a single + * API that works across architectures. Instead, we try to mimic the glibc + * API where reasonable, and only guarantee ABI compatibility with the + * kernel headers. + * Most notably, here are a few changes that were made to the structures + * defined by kernel headers: + * + * - we only define structures, but not symbolic names for kernel data + * types. For the latter, we directly use the native C datatype + * (i.e. "unsigned" instead of "mode_t"). + * - in a few cases, it is possible to define identical structures for + * both 32bit (e.g. i386) and 64bit (e.g. x86-64) platforms by + * standardizing on the 64bit version of the data types. In particular, + * this means that we use "unsigned" where the 32bit headers say + * "unsigned long". + * - overall, we try to minimize the number of cases where we need to + * conditionally define different structures. + * - the "struct kernel_sigaction" class of structures have been + * modified to more closely mimic glibc's API by introducing an + * anonymous union for the function pointer. + * - a small number of field names had to have an underscore appended to + * them, because glibc defines a global macro by the same name. + */ + +/* include/linux/dirent.h */ +struct kernel_dirent64 { + unsigned long long d_ino; + long long d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[256]; +}; + +/* include/linux/dirent.h */ +#if defined(__aarch64__) +// aarch64 only defines dirent64, just uses that for dirent too. +#define kernel_dirent kernel_dirent64 +#else +struct kernel_dirent { + long d_ino; + long d_off; + unsigned short d_reclen; + char d_name[256]; +}; +#endif + +/* include/linux/uio.h */ +struct kernel_iovec { + void *iov_base; + unsigned long iov_len; +}; + +/* include/linux/socket.h */ +struct kernel_msghdr { + void *msg_name; + int msg_namelen; + struct kernel_iovec*msg_iov; + unsigned long msg_iovlen; + void *msg_control; + unsigned long msg_controllen; + unsigned msg_flags; +}; + +/* include/asm-generic/poll.h */ +struct kernel_pollfd { + int fd; + short events; + short revents; +}; + +/* include/linux/resource.h */ +struct kernel_rlimit { + unsigned long rlim_cur; + unsigned long rlim_max; +}; + +/* include/linux/time.h */ +struct kernel_timespec { + long tv_sec; + long tv_nsec; +}; + +/* include/linux/time.h */ +struct kernel_timeval { + long tv_sec; + long tv_usec; +}; + +/* include/linux/resource.h */ +struct kernel_rusage { + struct kernel_timeval ru_utime; + struct kernel_timeval ru_stime; + long ru_maxrss; + long ru_ixrss; + long ru_idrss; + long ru_isrss; + long ru_minflt; + long ru_majflt; + long ru_nswap; + long ru_inblock; + long ru_oublock; + long ru_msgsnd; + long ru_msgrcv; + long ru_nsignals; + long ru_nvcsw; + long ru_nivcsw; +}; + +#if defined(__i386__) || defined(__ARM_EABI__) || defined(__ARM_ARCH_3__) \ + || defined(__PPC__) + +/* include/asm-{arm,i386,mips,ppc}/signal.h */ +struct kernel_old_sigaction { + union { + void (*sa_handler_)(int); + void (*sa_sigaction_)(int, siginfo_t *, void *); + }; + unsigned long sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +} __attribute__((packed,aligned(4))); +#elif (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) + #define kernel_old_sigaction kernel_sigaction +#elif defined(__aarch64__) + // No kernel_old_sigaction defined for arm64. +#endif + +/* Some kernel functions (e.g. sigaction() in 2.6.23) require that the + * exactly match the size of the signal set, even though the API was + * intended to be extensible. We define our own KERNEL_NSIG to deal with + * this. + * Please note that glibc provides signals [1.._NSIG-1], whereas the + * kernel (and this header) provides the range [1..KERNEL_NSIG]. The + * actual number of signals is obviously the same, but the constants + * differ by one. + */ +#ifdef __mips__ +#define KERNEL_NSIG 128 +#else +#define KERNEL_NSIG 64 +#endif + +/* include/asm-{arm,aarch64,i386,mips,x86_64}/signal.h */ +struct kernel_sigset_t { + unsigned long sig[(KERNEL_NSIG + 8*sizeof(unsigned long) - 1)/ + (8*sizeof(unsigned long))]; +}; + +/* include/asm-{arm,i386,mips,x86_64,ppc}/signal.h */ +struct kernel_sigaction { +#ifdef __mips__ + unsigned long sa_flags; + union { + void (*sa_handler_)(int); + void (*sa_sigaction_)(int, siginfo_t *, void *); + }; + struct kernel_sigset_t sa_mask; +#else + union { + void (*sa_handler_)(int); + void (*sa_sigaction_)(int, siginfo_t *, void *); + }; + unsigned long sa_flags; + void (*sa_restorer)(void); + struct kernel_sigset_t sa_mask; +#endif +}; + +/* include/linux/socket.h */ +struct kernel_sockaddr { + unsigned short sa_family; + char sa_data[14]; +}; + +/* include/asm-{arm,aarch64,i386,mips,ppc}/stat.h */ +#ifdef __mips__ +#if _MIPS_SIM == _MIPS_SIM_ABI64 +struct kernel_stat { +#else +struct kernel_stat64 { +#endif + unsigned st_dev; + unsigned __pad0[3]; + unsigned long long st_ino; + unsigned st_mode; + unsigned st_nlink; + unsigned st_uid; + unsigned st_gid; + unsigned st_rdev; + unsigned __pad1[3]; + long long st_size; + unsigned st_atime_; + unsigned st_atime_nsec_; + unsigned st_mtime_; + unsigned st_mtime_nsec_; + unsigned st_ctime_; + unsigned st_ctime_nsec_; + unsigned st_blksize; + unsigned __pad2; + unsigned long long st_blocks; +}; +#elif defined __PPC__ +struct kernel_stat64 { + unsigned long long st_dev; + unsigned long long st_ino; + unsigned st_mode; + unsigned st_nlink; + unsigned st_uid; + unsigned st_gid; + unsigned long long st_rdev; + unsigned short int __pad2; + long long st_size; + long st_blksize; + long long st_blocks; + long st_atime_; + unsigned long st_atime_nsec_; + long st_mtime_; + unsigned long st_mtime_nsec_; + long st_ctime_; + unsigned long st_ctime_nsec_; + unsigned long __unused4; + unsigned long __unused5; +}; +#else +struct kernel_stat64 { + unsigned long long st_dev; + unsigned char __pad0[4]; + unsigned __st_ino; + unsigned st_mode; + unsigned st_nlink; + unsigned st_uid; + unsigned st_gid; + unsigned long long st_rdev; + unsigned char __pad3[4]; + long long st_size; + unsigned st_blksize; + unsigned long long st_blocks; + unsigned st_atime_; + unsigned st_atime_nsec_; + unsigned st_mtime_; + unsigned st_mtime_nsec_; + unsigned st_ctime_; + unsigned st_ctime_nsec_; + unsigned long long st_ino; +}; +#endif + +/* include/asm-{arm,aarch64,i386,mips,x86_64,ppc}/stat.h */ +#if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) +struct kernel_stat { + /* The kernel headers suggest that st_dev and st_rdev should be 32bit + * quantities encoding 12bit major and 20bit minor numbers in an interleaved + * format. In reality, we do not see useful data in the top bits. So, + * we'll leave the padding in here, until we find a better solution. + */ + unsigned short st_dev; + short pad1; + unsigned st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + short pad2; + unsigned st_size; + unsigned st_blksize; + unsigned st_blocks; + unsigned st_atime_; + unsigned st_atime_nsec_; + unsigned st_mtime_; + unsigned st_mtime_nsec_; + unsigned st_ctime_; + unsigned st_ctime_nsec_; + unsigned __unused4; + unsigned __unused5; +}; +#elif defined(__x86_64__) +struct kernel_stat { + uint64_t st_dev; + uint64_t st_ino; + uint64_t st_nlink; + unsigned st_mode; + unsigned st_uid; + unsigned st_gid; + unsigned __pad0; + uint64_t st_rdev; + int64_t st_size; + int64_t st_blksize; + int64_t st_blocks; + uint64_t st_atime_; + uint64_t st_atime_nsec_; + uint64_t st_mtime_; + uint64_t st_mtime_nsec_; + uint64_t st_ctime_; + uint64_t st_ctime_nsec_; + int64_t __unused4[3]; +}; +#elif defined(__PPC__) +struct kernel_stat { + unsigned st_dev; + unsigned long st_ino; // ino_t + unsigned long st_mode; // mode_t + unsigned short st_nlink; // nlink_t + unsigned st_uid; // uid_t + unsigned st_gid; // gid_t + unsigned st_rdev; + long st_size; // off_t + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime_; + unsigned long st_atime_nsec_; + unsigned long st_mtime_; + unsigned long st_mtime_nsec_; + unsigned long st_ctime_; + unsigned long st_ctime_nsec_; + unsigned long __unused4; + unsigned long __unused5; +}; +#elif (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64) +struct kernel_stat { + unsigned st_dev; + int st_pad1[3]; + unsigned st_ino; + unsigned st_mode; + unsigned st_nlink; + unsigned st_uid; + unsigned st_gid; + unsigned st_rdev; + int st_pad2[2]; + long st_size; + int st_pad3; + long st_atime_; + long st_atime_nsec_; + long st_mtime_; + long st_mtime_nsec_; + long st_ctime_; + long st_ctime_nsec_; + int st_blksize; + int st_blocks; + int st_pad4[14]; +}; +#elif defined(__aarch64__) +struct kernel_stat { + unsigned long st_dev; + unsigned long st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned long st_rdev; + unsigned long __pad1; + long st_size; + int st_blksize; + int __pad2; + long st_blocks; + long st_atime_; + unsigned long st_atime_nsec_; + long st_mtime_; + unsigned long st_mtime_nsec_; + long st_ctime_; + unsigned long st_ctime_nsec_; + unsigned int __unused4; + unsigned int __unused5; +}; +#endif + +/* include/asm-{arm,aarch64,i386,mips,x86_64,ppc}/statfs.h */ +#ifdef __mips__ +#if _MIPS_SIM != _MIPS_SIM_ABI64 +struct kernel_statfs64 { + unsigned long f_type; + unsigned long f_bsize; + unsigned long f_frsize; + unsigned long __pad; + unsigned long long f_blocks; + unsigned long long f_bfree; + unsigned long long f_files; + unsigned long long f_ffree; + unsigned long long f_bavail; + struct { int val[2]; } f_fsid; + unsigned long f_namelen; + unsigned long f_spare[6]; +}; +#endif +#elif !defined(__x86_64__) +struct kernel_statfs64 { + unsigned long f_type; + unsigned long f_bsize; + unsigned long long f_blocks; + unsigned long long f_bfree; + unsigned long long f_bavail; + unsigned long long f_files; + unsigned long long f_ffree; + struct { int val[2]; } f_fsid; + unsigned long f_namelen; + unsigned long f_frsize; + unsigned long f_spare[5]; +}; +#endif + +/* include/asm-{arm,i386,mips,x86_64,ppc,generic}/statfs.h */ +#ifdef __mips__ +struct kernel_statfs { + long f_type; + long f_bsize; + long f_frsize; + long f_blocks; + long f_bfree; + long f_files; + long f_ffree; + long f_bavail; + struct { int val[2]; } f_fsid; + long f_namelen; + long f_spare[6]; +}; +#elif defined(__x86_64__) +struct kernel_statfs { + /* x86_64 actually defines all these fields as signed, whereas all other */ + /* platforms define them as unsigned. Leaving them at unsigned should not */ + /* cause any problems. Make sure these are 64-bit even on x32. */ + uint64_t f_type; + uint64_t f_bsize; + uint64_t f_blocks; + uint64_t f_bfree; + uint64_t f_bavail; + uint64_t f_files; + uint64_t f_ffree; + struct { int val[2]; } f_fsid; + uint64_t f_namelen; + uint64_t f_frsize; + uint64_t f_spare[5]; +}; +#else +struct kernel_statfs { + unsigned long f_type; + unsigned long f_bsize; + unsigned long f_blocks; + unsigned long f_bfree; + unsigned long f_bavail; + unsigned long f_files; + unsigned long f_ffree; + struct { int val[2]; } f_fsid; + unsigned long f_namelen; + unsigned long f_frsize; + unsigned long f_spare[5]; +}; +#endif + + +/* Definitions missing from the standard header files */ +#ifndef O_DIRECTORY +#if defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) || defined(__aarch64__) +#define O_DIRECTORY 0040000 +#else +#define O_DIRECTORY 0200000 +#endif +#endif +#ifndef NT_PRXFPREG +#define NT_PRXFPREG 0x46e62b7f +#endif +#ifndef PTRACE_GETFPXREGS +#define PTRACE_GETFPXREGS ((enum __ptrace_request)18) +#endif +#ifndef PR_GET_DUMPABLE +#define PR_GET_DUMPABLE 3 +#endif +#ifndef PR_SET_DUMPABLE +#define PR_SET_DUMPABLE 4 +#endif +#ifndef PR_GET_SECCOMP +#define PR_GET_SECCOMP 21 +#endif +#ifndef PR_SET_SECCOMP +#define PR_SET_SECCOMP 22 +#endif +#ifndef AT_FDCWD +#define AT_FDCWD (-100) +#endif +#ifndef AT_SYMLINK_NOFOLLOW +#define AT_SYMLINK_NOFOLLOW 0x100 +#endif +#ifndef AT_REMOVEDIR +#define AT_REMOVEDIR 0x200 +#endif +#ifndef MREMAP_FIXED +#define MREMAP_FIXED 2 +#endif +#ifndef SA_RESTORER +#define SA_RESTORER 0x04000000 +#endif +#ifndef CPUCLOCK_PROF +#define CPUCLOCK_PROF 0 +#endif +#ifndef CPUCLOCK_VIRT +#define CPUCLOCK_VIRT 1 +#endif +#ifndef CPUCLOCK_SCHED +#define CPUCLOCK_SCHED 2 +#endif +#ifndef CPUCLOCK_PERTHREAD_MASK +#define CPUCLOCK_PERTHREAD_MASK 4 +#endif +#ifndef MAKE_PROCESS_CPUCLOCK +#define MAKE_PROCESS_CPUCLOCK(pid, clock) \ + ((~(int)(pid) << 3) | (int)(clock)) +#endif +#ifndef MAKE_THREAD_CPUCLOCK +#define MAKE_THREAD_CPUCLOCK(tid, clock) \ + ((~(int)(tid) << 3) | (int)((clock) | CPUCLOCK_PERTHREAD_MASK)) +#endif + +#ifndef FUTEX_WAIT +#define FUTEX_WAIT 0 +#endif +#ifndef FUTEX_WAKE +#define FUTEX_WAKE 1 +#endif +#ifndef FUTEX_FD +#define FUTEX_FD 2 +#endif +#ifndef FUTEX_REQUEUE +#define FUTEX_REQUEUE 3 +#endif +#ifndef FUTEX_CMP_REQUEUE +#define FUTEX_CMP_REQUEUE 4 +#endif +#ifndef FUTEX_WAKE_OP +#define FUTEX_WAKE_OP 5 +#endif +#ifndef FUTEX_LOCK_PI +#define FUTEX_LOCK_PI 6 +#endif +#ifndef FUTEX_UNLOCK_PI +#define FUTEX_UNLOCK_PI 7 +#endif +#ifndef FUTEX_TRYLOCK_PI +#define FUTEX_TRYLOCK_PI 8 +#endif +#ifndef FUTEX_PRIVATE_FLAG +#define FUTEX_PRIVATE_FLAG 128 +#endif +#ifndef FUTEX_CMD_MASK +#define FUTEX_CMD_MASK ~FUTEX_PRIVATE_FLAG +#endif +#ifndef FUTEX_WAIT_PRIVATE +#define FUTEX_WAIT_PRIVATE (FUTEX_WAIT | FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_WAKE_PRIVATE +#define FUTEX_WAKE_PRIVATE (FUTEX_WAKE | FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_REQUEUE_PRIVATE +#define FUTEX_REQUEUE_PRIVATE (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_CMP_REQUEUE_PRIVATE +#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_WAKE_OP_PRIVATE +#define FUTEX_WAKE_OP_PRIVATE (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_LOCK_PI_PRIVATE +#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_UNLOCK_PI_PRIVATE +#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG) +#endif +#ifndef FUTEX_TRYLOCK_PI_PRIVATE +#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG) +#endif + + +#if defined(__x86_64__) +#ifndef ARCH_SET_GS +#define ARCH_SET_GS 0x1001 +#endif +#ifndef ARCH_GET_GS +#define ARCH_GET_GS 0x1004 +#endif +#endif + +#if defined(__i386__) +#ifndef __NR_quotactl +#define __NR_quotactl 131 +#endif +#ifndef __NR_setresuid +#define __NR_setresuid 164 +#define __NR_getresuid 165 +#define __NR_setresgid 170 +#define __NR_getresgid 171 +#endif +#ifndef __NR_rt_sigaction +#define __NR_rt_sigreturn 173 +#define __NR_rt_sigaction 174 +#define __NR_rt_sigprocmask 175 +#define __NR_rt_sigpending 176 +#define __NR_rt_sigsuspend 179 +#endif +#ifndef __NR_pread64 +#define __NR_pread64 180 +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 181 +#endif +#ifndef __NR_ugetrlimit +#define __NR_ugetrlimit 191 +#endif +#ifndef __NR_stat64 +#define __NR_stat64 195 +#endif +#ifndef __NR_fstat64 +#define __NR_fstat64 197 +#endif +#ifndef __NR_setresuid32 +#define __NR_setresuid32 208 +#define __NR_getresuid32 209 +#define __NR_setresgid32 210 +#define __NR_getresgid32 211 +#endif +#ifndef __NR_setfsuid32 +#define __NR_setfsuid32 215 +#define __NR_setfsgid32 216 +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 220 +#endif +#ifndef __NR_gettid +#define __NR_gettid 224 +#endif +#ifndef __NR_readahead +#define __NR_readahead 225 +#endif +#ifndef __NR_setxattr +#define __NR_setxattr 226 +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr 227 +#endif +#ifndef __NR_getxattr +#define __NR_getxattr 229 +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr 230 +#endif +#ifndef __NR_listxattr +#define __NR_listxattr 232 +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr 233 +#endif +#ifndef __NR_tkill +#define __NR_tkill 238 +#endif +#ifndef __NR_futex +#define __NR_futex 240 +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity 241 +#define __NR_sched_getaffinity 242 +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address 258 +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime 265 +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres 266 +#endif +#ifndef __NR_statfs64 +#define __NR_statfs64 268 +#endif +#ifndef __NR_fstatfs64 +#define __NR_fstatfs64 269 +#endif +#ifndef __NR_fadvise64_64 +#define __NR_fadvise64_64 272 +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set 289 +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get 290 +#endif +#ifndef __NR_openat +#define __NR_openat 295 +#endif +#ifndef __NR_fstatat64 +#define __NR_fstatat64 300 +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat 301 +#endif +#ifndef __NR_move_pages +#define __NR_move_pages 317 +#endif +#ifndef __NR_getcpu +#define __NR_getcpu 318 +#endif +#ifndef __NR_fallocate +#define __NR_fallocate 324 +#endif +/* End of i386 definitions */ +#elif defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) +#ifndef __NR_setresuid +#define __NR_setresuid (__NR_SYSCALL_BASE + 164) +#define __NR_getresuid (__NR_SYSCALL_BASE + 165) +#define __NR_setresgid (__NR_SYSCALL_BASE + 170) +#define __NR_getresgid (__NR_SYSCALL_BASE + 171) +#endif +#ifndef __NR_rt_sigaction +#define __NR_rt_sigreturn (__NR_SYSCALL_BASE + 173) +#define __NR_rt_sigaction (__NR_SYSCALL_BASE + 174) +#define __NR_rt_sigprocmask (__NR_SYSCALL_BASE + 175) +#define __NR_rt_sigpending (__NR_SYSCALL_BASE + 176) +#define __NR_rt_sigsuspend (__NR_SYSCALL_BASE + 179) +#endif +#ifndef __NR_pread64 +#define __NR_pread64 (__NR_SYSCALL_BASE + 180) +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 (__NR_SYSCALL_BASE + 181) +#endif +#ifndef __NR_ugetrlimit +#define __NR_ugetrlimit (__NR_SYSCALL_BASE + 191) +#endif +#ifndef __NR_stat64 +#define __NR_stat64 (__NR_SYSCALL_BASE + 195) +#endif +#ifndef __NR_fstat64 +#define __NR_fstat64 (__NR_SYSCALL_BASE + 197) +#endif +#ifndef __NR_setresuid32 +#define __NR_setresuid32 (__NR_SYSCALL_BASE + 208) +#define __NR_getresuid32 (__NR_SYSCALL_BASE + 209) +#define __NR_setresgid32 (__NR_SYSCALL_BASE + 210) +#define __NR_getresgid32 (__NR_SYSCALL_BASE + 211) +#endif +#ifndef __NR_setfsuid32 +#define __NR_setfsuid32 (__NR_SYSCALL_BASE + 215) +#define __NR_setfsgid32 (__NR_SYSCALL_BASE + 216) +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 (__NR_SYSCALL_BASE + 217) +#endif +#ifndef __NR_gettid +#define __NR_gettid (__NR_SYSCALL_BASE + 224) +#endif +#ifndef __NR_readahead +#define __NR_readahead (__NR_SYSCALL_BASE + 225) +#endif +#ifndef __NR_setxattr +#define __NR_setxattr (__NR_SYSCALL_BASE + 226) +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr (__NR_SYSCALL_BASE + 227) +#endif +#ifndef __NR_getxattr +#define __NR_getxattr (__NR_SYSCALL_BASE + 229) +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr (__NR_SYSCALL_BASE + 230) +#endif +#ifndef __NR_listxattr +#define __NR_listxattr (__NR_SYSCALL_BASE + 232) +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr (__NR_SYSCALL_BASE + 233) +#endif +#ifndef __NR_tkill +#define __NR_tkill (__NR_SYSCALL_BASE + 238) +#endif +#ifndef __NR_futex +#define __NR_futex (__NR_SYSCALL_BASE + 240) +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity (__NR_SYSCALL_BASE + 241) +#define __NR_sched_getaffinity (__NR_SYSCALL_BASE + 242) +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address (__NR_SYSCALL_BASE + 256) +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime (__NR_SYSCALL_BASE + 263) +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres (__NR_SYSCALL_BASE + 264) +#endif +#ifndef __NR_statfs64 +#define __NR_statfs64 (__NR_SYSCALL_BASE + 266) +#endif +#ifndef __NR_fstatfs64 +#define __NR_fstatfs64 (__NR_SYSCALL_BASE + 267) +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set (__NR_SYSCALL_BASE + 314) +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get (__NR_SYSCALL_BASE + 315) +#endif +#ifndef __NR_move_pages +#define __NR_move_pages (__NR_SYSCALL_BASE + 344) +#endif +#ifndef __NR_getcpu +#define __NR_getcpu (__NR_SYSCALL_BASE + 345) +#endif +/* End of ARM 3/EABI definitions */ +#elif defined(__aarch64__) +#ifndef __NR_setxattr +#define __NR_setxattr 5 +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr 6 +#endif +#ifndef __NR_getxattr +#define __NR_getxattr 8 +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr 9 +#endif +#ifndef __NR_listxattr +#define __NR_listxattr 11 +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr 12 +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set 30 +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get 31 +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat 35 +#endif +#ifndef __NR_fallocate +#define __NR_fallocate 47 +#endif +#ifndef __NR_openat +#define __NR_openat 56 +#endif +#ifndef __NR_quotactl +#define __NR_quotactl 60 +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 61 +#endif +#ifndef __NR_getdents +#define __NR_getdents __NR_getdents64 +#endif +#ifndef __NR_pread64 +#define __NR_pread64 67 +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 68 +#endif +#ifndef __NR_ppoll +#define __NR_ppoll 73 +#endif +#ifndef __NR_readlinkat +#define __NR_readlinkat 78 +#endif +#ifndef __NR_newfstatat +#define __NR_newfstatat 79 +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address 96 +#endif +#ifndef __NR_futex +#define __NR_futex 98 +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime 113 +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres 114 +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity 122 +#define __NR_sched_getaffinity 123 +#endif +#ifndef __NR_tkill +#define __NR_tkill 130 +#endif +#ifndef __NR_setresuid +#define __NR_setresuid 147 +#define __NR_getresuid 148 +#define __NR_setresgid 149 +#define __NR_getresgid 150 +#endif +#ifndef __NR_gettid +#define __NR_gettid 178 +#endif +#ifndef __NR_readahead +#define __NR_readahead 213 +#endif +#ifndef __NR_fadvise64 +#define __NR_fadvise64 223 +#endif +#ifndef __NR_move_pages +#define __NR_move_pages 239 +#endif +/* End of aarch64 definitions */ +#elif defined(__x86_64__) +#ifndef __NR_pread64 +#define __NR_pread64 17 +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 18 +#endif +#ifndef __NR_setresuid +#define __NR_setresuid 117 +#define __NR_getresuid 118 +#define __NR_setresgid 119 +#define __NR_getresgid 120 +#endif +#ifndef __NR_quotactl +#define __NR_quotactl 179 +#endif +#ifndef __NR_gettid +#define __NR_gettid 186 +#endif +#ifndef __NR_readahead +#define __NR_readahead 187 +#endif +#ifndef __NR_setxattr +#define __NR_setxattr 188 +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr 189 +#endif +#ifndef __NR_getxattr +#define __NR_getxattr 191 +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr 192 +#endif +#ifndef __NR_listxattr +#define __NR_listxattr 194 +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr 195 +#endif +#ifndef __NR_tkill +#define __NR_tkill 200 +#endif +#ifndef __NR_futex +#define __NR_futex 202 +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity 203 +#define __NR_sched_getaffinity 204 +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 217 +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address 218 +#endif +#ifndef __NR_fadvise64 +#define __NR_fadvise64 221 +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime 228 +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres 229 +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set 251 +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get 252 +#endif +#ifndef __NR_openat +#define __NR_openat 257 +#endif +#ifndef __NR_newfstatat +#define __NR_newfstatat 262 +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat 263 +#endif +#ifndef __NR_move_pages +#define __NR_move_pages 279 +#endif +#ifndef __NR_fallocate +#define __NR_fallocate 285 +#endif +/* End of x86-64 definitions */ +#elif defined(__mips__) +#if _MIPS_SIM == _MIPS_SIM_ABI32 +#ifndef __NR_setresuid +#define __NR_setresuid (__NR_Linux + 185) +#define __NR_getresuid (__NR_Linux + 186) +#define __NR_setresgid (__NR_Linux + 190) +#define __NR_getresgid (__NR_Linux + 191) +#endif +#ifndef __NR_rt_sigaction +#define __NR_rt_sigreturn (__NR_Linux + 193) +#define __NR_rt_sigaction (__NR_Linux + 194) +#define __NR_rt_sigprocmask (__NR_Linux + 195) +#define __NR_rt_sigpending (__NR_Linux + 196) +#define __NR_rt_sigsuspend (__NR_Linux + 199) +#endif +#ifndef __NR_pread64 +#define __NR_pread64 (__NR_Linux + 200) +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 (__NR_Linux + 201) +#endif +#ifndef __NR_stat64 +#define __NR_stat64 (__NR_Linux + 213) +#endif +#ifndef __NR_fstat64 +#define __NR_fstat64 (__NR_Linux + 215) +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 (__NR_Linux + 219) +#endif +#ifndef __NR_gettid +#define __NR_gettid (__NR_Linux + 222) +#endif +#ifndef __NR_readahead +#define __NR_readahead (__NR_Linux + 223) +#endif +#ifndef __NR_setxattr +#define __NR_setxattr (__NR_Linux + 224) +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr (__NR_Linux + 225) +#endif +#ifndef __NR_getxattr +#define __NR_getxattr (__NR_Linux + 227) +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr (__NR_Linux + 228) +#endif +#ifndef __NR_listxattr +#define __NR_listxattr (__NR_Linux + 230) +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr (__NR_Linux + 231) +#endif +#ifndef __NR_tkill +#define __NR_tkill (__NR_Linux + 236) +#endif +#ifndef __NR_futex +#define __NR_futex (__NR_Linux + 238) +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity (__NR_Linux + 239) +#define __NR_sched_getaffinity (__NR_Linux + 240) +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address (__NR_Linux + 252) +#endif +#ifndef __NR_statfs64 +#define __NR_statfs64 (__NR_Linux + 255) +#endif +#ifndef __NR_fstatfs64 +#define __NR_fstatfs64 (__NR_Linux + 256) +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime (__NR_Linux + 263) +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres (__NR_Linux + 264) +#endif +#ifndef __NR_openat +#define __NR_openat (__NR_Linux + 288) +#endif +#ifndef __NR_fstatat +#define __NR_fstatat (__NR_Linux + 293) +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat (__NR_Linux + 294) +#endif +#ifndef __NR_move_pages +#define __NR_move_pages (__NR_Linux + 308) +#endif +#ifndef __NR_getcpu +#define __NR_getcpu (__NR_Linux + 312) +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set (__NR_Linux + 314) +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get (__NR_Linux + 315) +#endif +/* End of MIPS (old 32bit API) definitions */ +#elif _MIPS_SIM == _MIPS_SIM_ABI64 +#ifndef __NR_pread64 +#define __NR_pread64 (__NR_Linux + 16) +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 (__NR_Linux + 17) +#endif +#ifndef __NR_setresuid +#define __NR_setresuid (__NR_Linux + 115) +#define __NR_getresuid (__NR_Linux + 116) +#define __NR_setresgid (__NR_Linux + 117) +#define __NR_getresgid (__NR_Linux + 118) +#endif +#ifndef __NR_gettid +#define __NR_gettid (__NR_Linux + 178) +#endif +#ifndef __NR_readahead +#define __NR_readahead (__NR_Linux + 179) +#endif +#ifndef __NR_setxattr +#define __NR_setxattr (__NR_Linux + 180) +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr (__NR_Linux + 181) +#endif +#ifndef __NR_getxattr +#define __NR_getxattr (__NR_Linux + 183) +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr (__NR_Linux + 184) +#endif +#ifndef __NR_listxattr +#define __NR_listxattr (__NR_Linux + 186) +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr (__NR_Linux + 187) +#endif +#ifndef __NR_tkill +#define __NR_tkill (__NR_Linux + 192) +#endif +#ifndef __NR_futex +#define __NR_futex (__NR_Linux + 194) +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity (__NR_Linux + 195) +#define __NR_sched_getaffinity (__NR_Linux + 196) +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address (__NR_Linux + 212) +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime (__NR_Linux + 222) +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres (__NR_Linux + 223) +#endif +#ifndef __NR_openat +#define __NR_openat (__NR_Linux + 247) +#endif +#ifndef __NR_fstatat +#define __NR_fstatat (__NR_Linux + 252) +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat (__NR_Linux + 253) +#endif +#ifndef __NR_move_pages +#define __NR_move_pages (__NR_Linux + 267) +#endif +#ifndef __NR_getcpu +#define __NR_getcpu (__NR_Linux + 271) +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set (__NR_Linux + 273) +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get (__NR_Linux + 274) +#endif +/* End of MIPS (64bit API) definitions */ +#else +#ifndef __NR_setresuid +#define __NR_setresuid (__NR_Linux + 115) +#define __NR_getresuid (__NR_Linux + 116) +#define __NR_setresgid (__NR_Linux + 117) +#define __NR_getresgid (__NR_Linux + 118) +#endif +#ifndef __NR_gettid +#define __NR_gettid (__NR_Linux + 178) +#endif +#ifndef __NR_readahead +#define __NR_readahead (__NR_Linux + 179) +#endif +#ifndef __NR_setxattr +#define __NR_setxattr (__NR_Linux + 180) +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr (__NR_Linux + 181) +#endif +#ifndef __NR_getxattr +#define __NR_getxattr (__NR_Linux + 183) +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr (__NR_Linux + 184) +#endif +#ifndef __NR_listxattr +#define __NR_listxattr (__NR_Linux + 186) +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr (__NR_Linux + 187) +#endif +#ifndef __NR_tkill +#define __NR_tkill (__NR_Linux + 192) +#endif +#ifndef __NR_futex +#define __NR_futex (__NR_Linux + 194) +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity (__NR_Linux + 195) +#define __NR_sched_getaffinity (__NR_Linux + 196) +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address (__NR_Linux + 213) +#endif +#ifndef __NR_statfs64 +#define __NR_statfs64 (__NR_Linux + 217) +#endif +#ifndef __NR_fstatfs64 +#define __NR_fstatfs64 (__NR_Linux + 218) +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime (__NR_Linux + 226) +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres (__NR_Linux + 227) +#endif +#ifndef __NR_openat +#define __NR_openat (__NR_Linux + 251) +#endif +#ifndef __NR_fstatat +#define __NR_fstatat (__NR_Linux + 256) +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat (__NR_Linux + 257) +#endif +#ifndef __NR_move_pages +#define __NR_move_pages (__NR_Linux + 271) +#endif +#ifndef __NR_getcpu +#define __NR_getcpu (__NR_Linux + 275) +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set (__NR_Linux + 277) +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get (__NR_Linux + 278) +#endif +/* End of MIPS (new 32bit API) definitions */ +#endif +/* End of MIPS definitions */ +#elif defined(__PPC__) +#ifndef __NR_setfsuid +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#endif +#ifndef __NR_setresuid +#define __NR_setresuid 164 +#define __NR_getresuid 165 +#define __NR_setresgid 169 +#define __NR_getresgid 170 +#endif +#ifndef __NR_rt_sigaction +#define __NR_rt_sigreturn 172 +#define __NR_rt_sigaction 173 +#define __NR_rt_sigprocmask 174 +#define __NR_rt_sigpending 175 +#define __NR_rt_sigsuspend 178 +#endif +#ifndef __NR_pread64 +#define __NR_pread64 179 +#endif +#ifndef __NR_pwrite64 +#define __NR_pwrite64 180 +#endif +#ifndef __NR_ugetrlimit +#define __NR_ugetrlimit 190 +#endif +#ifndef __NR_readahead +#define __NR_readahead 191 +#endif +#ifndef __NR_stat64 +#define __NR_stat64 195 +#endif +#ifndef __NR_fstat64 +#define __NR_fstat64 197 +#endif +#ifndef __NR_getdents64 +#define __NR_getdents64 202 +#endif +#ifndef __NR_gettid +#define __NR_gettid 207 +#endif +#ifndef __NR_tkill +#define __NR_tkill 208 +#endif +#ifndef __NR_setxattr +#define __NR_setxattr 209 +#endif +#ifndef __NR_lsetxattr +#define __NR_lsetxattr 210 +#endif +#ifndef __NR_getxattr +#define __NR_getxattr 212 +#endif +#ifndef __NR_lgetxattr +#define __NR_lgetxattr 213 +#endif +#ifndef __NR_listxattr +#define __NR_listxattr 215 +#endif +#ifndef __NR_llistxattr +#define __NR_llistxattr 216 +#endif +#ifndef __NR_futex +#define __NR_futex 221 +#endif +#ifndef __NR_sched_setaffinity +#define __NR_sched_setaffinity 222 +#define __NR_sched_getaffinity 223 +#endif +#ifndef __NR_set_tid_address +#define __NR_set_tid_address 232 +#endif +#ifndef __NR_clock_gettime +#define __NR_clock_gettime 246 +#endif +#ifndef __NR_clock_getres +#define __NR_clock_getres 247 +#endif +#ifndef __NR_statfs64 +#define __NR_statfs64 252 +#endif +#ifndef __NR_fstatfs64 +#define __NR_fstatfs64 253 +#endif +#ifndef __NR_fadvise64_64 +#define __NR_fadvise64_64 254 +#endif +#ifndef __NR_ioprio_set +#define __NR_ioprio_set 273 +#endif +#ifndef __NR_ioprio_get +#define __NR_ioprio_get 274 +#endif +#ifndef __NR_openat +#define __NR_openat 286 +#endif +#ifndef __NR_fstatat64 +#define __NR_fstatat64 291 +#endif +#ifndef __NR_unlinkat +#define __NR_unlinkat 292 +#endif +#ifndef __NR_move_pages +#define __NR_move_pages 301 +#endif +#ifndef __NR_getcpu +#define __NR_getcpu 302 +#endif +/* End of powerpc defininitions */ +#endif + + +/* After forking, we must make sure to only call system calls. */ +#if defined(__BOUNDED_POINTERS__) + #error "Need to port invocations of syscalls for bounded ptrs" +#else + /* The core dumper and the thread lister get executed after threads + * have been suspended. As a consequence, we cannot call any functions + * that acquire locks. Unfortunately, libc wraps most system calls + * (e.g. in order to implement pthread_atfork, and to make calls + * cancellable), which means we cannot call these functions. Instead, + * we have to call syscall() directly. + */ + #undef LSS_ERRNO + #ifdef SYS_ERRNO + /* Allow the including file to override the location of errno. This can + * be useful when using clone() with the CLONE_VM option. + */ + #define LSS_ERRNO SYS_ERRNO + #else + #define LSS_ERRNO errno + #endif + + #undef LSS_INLINE + #ifdef SYS_INLINE + #define LSS_INLINE SYS_INLINE + #else + #define LSS_INLINE static inline + #endif + + /* Allow the including file to override the prefix used for all new + * system calls. By default, it will be set to "sys_". + */ + #undef LSS_NAME + #ifndef SYS_PREFIX + #define LSS_NAME(name) sys_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX < 0 + #define LSS_NAME(name) name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 0 + #define LSS_NAME(name) sys0_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 1 + #define LSS_NAME(name) sys1_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 2 + #define LSS_NAME(name) sys2_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 3 + #define LSS_NAME(name) sys3_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 4 + #define LSS_NAME(name) sys4_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 5 + #define LSS_NAME(name) sys5_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 6 + #define LSS_NAME(name) sys6_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 7 + #define LSS_NAME(name) sys7_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 8 + #define LSS_NAME(name) sys8_##name + #elif defined(SYS_PREFIX) && SYS_PREFIX == 9 + #define LSS_NAME(name) sys9_##name + #endif + + #undef LSS_RETURN + #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) \ + || defined(__ARM_EABI__) || defined(__aarch64__)) + /* Failing system calls return a negative result in the range of + * -1..-4095. These are "errno" values with the sign inverted. + */ + #define LSS_RETURN(type, res) \ + do { \ + if ((unsigned long)(res) >= (unsigned long)(-4095)) { \ + LSS_ERRNO = -(res); \ + res = -1; \ + } \ + return (type) (res); \ + } while (0) + #elif defined(__mips__) + /* On MIPS, failing system calls return -1, and set errno in a + * separate CPU register. + */ + #define LSS_RETURN(type, res, err) \ + do { \ + if (err) { \ + unsigned long __errnovalue = (res); \ + LSS_ERRNO = __errnovalue; \ + res = -1; \ + } \ + return (type) (res); \ + } while (0) + #elif defined(__PPC__) + /* On PPC, failing system calls return -1, and set errno in a + * separate CPU register. See linux/unistd.h. + */ + #define LSS_RETURN(type, res, err) \ + do { \ + if (err & 0x10000000 ) { \ + LSS_ERRNO = (res); \ + res = -1; \ + } \ + return (type) (res); \ + } while (0) + #endif + #if defined(__i386__) + /* In PIC mode (e.g. when building shared libraries), gcc for i386 + * reserves ebx. Unfortunately, most distribution ship with implementations + * of _syscallX() which clobber ebx. + * Also, most definitions of _syscallX() neglect to mark "memory" as being + * clobbered. This causes problems with compilers, that do a better job + * at optimizing across __asm__ calls. + * So, we just have to redefine all of the _syscallX() macros. + */ + #undef LSS_ENTRYPOINT + #ifdef SYS_SYSCALL_ENTRYPOINT + static inline void (**LSS_NAME(get_syscall_entrypoint)(void))(void) { + void (**entrypoint)(void); + asm volatile(".bss\n" + ".align 8\n" + ".globl " SYS_SYSCALL_ENTRYPOINT "\n" + ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" + ".previous\n" + /* This logically does 'lea "SYS_SYSCALL_ENTRYPOINT", %0' */ + "call 0f\n" + "0:pop %0\n" + "add $_GLOBAL_OFFSET_TABLE_+[.-0b], %0\n" + "mov " SYS_SYSCALL_ENTRYPOINT "@GOT(%0), %0\n" + : "=r"(entrypoint)); + return entrypoint; + } + + #define LSS_ENTRYPOINT ".bss\n" \ + ".align 8\n" \ + ".globl " SYS_SYSCALL_ENTRYPOINT "\n" \ + ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" \ + ".previous\n" \ + /* Check the SYS_SYSCALL_ENTRYPOINT vector */ \ + "push %%eax\n" \ + "call 10000f\n" \ + "10000:pop %%eax\n" \ + "add $_GLOBAL_OFFSET_TABLE_+[.-10000b], %%eax\n" \ + "mov " SYS_SYSCALL_ENTRYPOINT \ + "@GOT(%%eax), %%eax\n" \ + "mov 0(%%eax), %%eax\n" \ + "test %%eax, %%eax\n" \ + "jz 10002f\n" \ + "push %%eax\n" \ + "call 10001f\n" \ + "10001:pop %%eax\n" \ + "add $(10003f-10001b), %%eax\n" \ + "xchg 4(%%esp), %%eax\n" \ + "ret\n" \ + "10002:pop %%eax\n" \ + "int $0x80\n" \ + "10003:\n" + #else + #define LSS_ENTRYPOINT "int $0x80\n" + #endif + #undef LSS_BODY + #define LSS_BODY(type,args...) \ + long __res; \ + __asm__ __volatile__("push %%ebx\n" \ + "movl %2,%%ebx\n" \ + LSS_ENTRYPOINT \ + "pop %%ebx" \ + args \ + : "esp", "memory"); \ + LSS_RETURN(type,__res) + #undef _syscall0 + #define _syscall0(type,name) \ + type LSS_NAME(name)(void) { \ + long __res; \ + __asm__ volatile(LSS_ENTRYPOINT \ + : "=a" (__res) \ + : "0" (__NR_##name) \ + : "esp", "memory"); \ + LSS_RETURN(type,__res); \ + } + #undef _syscall1 + #define _syscall1(type,name,type1,arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_BODY(type, \ + : "=a" (__res) \ + : "0" (__NR_##name), "ri" ((long)(arg1))); \ + } + #undef _syscall2 + #define _syscall2(type,name,type1,arg1,type2,arg2) \ + type LSS_NAME(name)(type1 arg1,type2 arg2) { \ + LSS_BODY(type, \ + : "=a" (__res) \ + : "0" (__NR_##name),"ri" ((long)(arg1)), "c" ((long)(arg2))); \ + } + #undef _syscall3 + #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ + type LSS_NAME(name)(type1 arg1,type2 arg2,type3 arg3) { \ + LSS_BODY(type, \ + : "=a" (__res) \ + : "0" (__NR_##name), "ri" ((long)(arg1)), "c" ((long)(arg2)), \ + "d" ((long)(arg3))); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_BODY(type, \ + : "=a" (__res) \ + : "0" (__NR_##name), "ri" ((long)(arg1)), "c" ((long)(arg2)), \ + "d" ((long)(arg3)),"S" ((long)(arg4))); \ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + long __res; \ + __asm__ __volatile__("push %%ebx\n" \ + "movl %2,%%ebx\n" \ + "movl %1,%%eax\n" \ + LSS_ENTRYPOINT \ + "pop %%ebx" \ + : "=a" (__res) \ + : "i" (__NR_##name), "ri" ((long)(arg1)), \ + "c" ((long)(arg2)), "d" ((long)(arg3)), \ + "S" ((long)(arg4)), "D" ((long)(arg5)) \ + : "esp", "memory"); \ + LSS_RETURN(type,__res); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + long __res; \ + struct { long __a1; long __a6; } __s = { (long)arg1, (long) arg6 }; \ + __asm__ __volatile__("push %%ebp\n" \ + "push %%ebx\n" \ + "movl 4(%2),%%ebp\n" \ + "movl 0(%2), %%ebx\n" \ + "movl %1,%%eax\n" \ + LSS_ENTRYPOINT \ + "pop %%ebx\n" \ + "pop %%ebp" \ + : "=a" (__res) \ + : "i" (__NR_##name), "0" ((long)(&__s)), \ + "c" ((long)(arg2)), "d" ((long)(arg3)), \ + "S" ((long)(arg4)), "D" ((long)(arg5)) \ + : "esp", "memory"); \ + LSS_RETURN(type,__res); \ + } + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + long __res; + __asm__ __volatile__(/* if (fn == NULL) + * return -EINVAL; + */ + "movl %3,%%ecx\n" + "jecxz 1f\n" + + /* if (child_stack == NULL) + * return -EINVAL; + */ + "movl %4,%%ecx\n" + "jecxz 1f\n" + + /* Set up alignment of the child stack: + * child_stack = (child_stack & ~0xF) - 20; + */ + "andl $-16,%%ecx\n" + "subl $20,%%ecx\n" + + /* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + "movl %6,%%eax\n" + "movl %%eax,4(%%ecx)\n" + "movl %3,%%eax\n" + "movl %%eax,(%%ecx)\n" + + /* %eax = syscall(%eax = __NR_clone, + * %ebx = flags, + * %ecx = child_stack, + * %edx = parent_tidptr, + * %esi = newtls, + * %edi = child_tidptr) + * Also, make sure that %ebx gets preserved as it is + * used in PIC mode. + */ + "movl %8,%%esi\n" + "movl %7,%%edx\n" + "movl %5,%%eax\n" + "movl %9,%%edi\n" + "pushl %%ebx\n" + "movl %%eax,%%ebx\n" + "movl %2,%%eax\n" + LSS_ENTRYPOINT + + /* In the parent: restore %ebx + * In the child: move "fn" into %ebx + */ + "popl %%ebx\n" + + /* if (%eax != 0) + * return %eax; + */ + "test %%eax,%%eax\n" + "jnz 1f\n" + + /* In the child, now. Terminate frame pointer chain. + */ + "movl $0,%%ebp\n" + + /* Call "fn". "arg" is already on the stack. + */ + "call *%%ebx\n" + + /* Call _exit(%ebx). Unfortunately older versions + * of gcc restrict the number of arguments that can + * be passed to asm(). So, we need to hard-code the + * system call number. + */ + "movl %%eax,%%ebx\n" + "movl $1,%%eax\n" + LSS_ENTRYPOINT + + /* Return to parent. + */ + "1:\n" + : "=a" (__res) + : "0"(-EINVAL), "i"(__NR_clone), + "m"(fn), "m"(child_stack), "m"(flags), "m"(arg), + "m"(parent_tidptr), "m"(newtls), "m"(child_tidptr) + : "esp", "memory", "ecx", "edx", "esi", "edi"); + LSS_RETURN(int, __res); + } + + #define __NR__fadvise64_64 __NR_fadvise64_64 + LSS_INLINE _syscall6(int, _fadvise64_64, int, fd, + unsigned, offset_lo, unsigned, offset_hi, + unsigned, len_lo, unsigned, len_hi, + int, advice) + + LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset, + loff_t len, int advice) { + return LSS_NAME(_fadvise64_64)(fd, + (unsigned)offset, (unsigned)(offset >>32), + (unsigned)len, (unsigned)(len >> 32), + advice); + } + + #define __NR__fallocate __NR_fallocate + LSS_INLINE _syscall6(int, _fallocate, int, fd, + int, mode, + unsigned, offset_lo, unsigned, offset_hi, + unsigned, len_lo, unsigned, len_hi) + + LSS_INLINE int LSS_NAME(fallocate)(int fd, int mode, + loff_t offset, loff_t len) { + union { loff_t off; unsigned w[2]; } o = { offset }, l = { len }; + return LSS_NAME(_fallocate)(fd, mode, o.w[0], o.w[1], l.w[0], l.w[1]); + } + + LSS_INLINE _syscall1(int, set_thread_area, void *, u) + LSS_INLINE _syscall1(int, get_thread_area, void *, u) + + LSS_INLINE void (*LSS_NAME(restore_rt)(void))(void) { + /* On i386, the kernel does not know how to return from a signal + * handler. Instead, it relies on user space to provide a + * restorer function that calls the {rt_,}sigreturn() system call. + * Unfortunately, we cannot just reference the glibc version of this + * function, as glibc goes out of its way to make it inaccessible. + */ + void (*res)(void); + __asm__ __volatile__("call 2f\n" + "0:.align 16\n" + "1:movl %1,%%eax\n" + LSS_ENTRYPOINT + "2:popl %0\n" + "addl $(1b-0b),%0\n" + : "=a" (res) + : "i" (__NR_rt_sigreturn)); + return res; + } + LSS_INLINE void (*LSS_NAME(restore)(void))(void) { + /* On i386, the kernel does not know how to return from a signal + * handler. Instead, it relies on user space to provide a + * restorer function that calls the {rt_,}sigreturn() system call. + * Unfortunately, we cannot just reference the glibc version of this + * function, as glibc goes out of its way to make it inaccessible. + */ + void (*res)(void); + __asm__ __volatile__("call 2f\n" + "0:.align 16\n" + "1:pop %%eax\n" + "movl %1,%%eax\n" + LSS_ENTRYPOINT + "2:popl %0\n" + "addl $(1b-0b),%0\n" + : "=a" (res) + : "i" (__NR_sigreturn)); + return res; + } + #elif defined(__x86_64__) + /* There are no known problems with any of the _syscallX() macros + * currently shipping for x86_64, but we still need to be able to define + * our own version so that we can override the location of the errno + * location (e.g. when using the clone() system call with the CLONE_VM + * option). + */ + #undef LSS_ENTRYPOINT + #ifdef SYS_SYSCALL_ENTRYPOINT + static inline void (**LSS_NAME(get_syscall_entrypoint)(void))(void) { + void (**entrypoint)(void); + asm volatile(".bss\n" + ".align 8\n" + ".globl " SYS_SYSCALL_ENTRYPOINT "\n" + ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" + ".previous\n" + "mov " SYS_SYSCALL_ENTRYPOINT "@GOTPCREL(%%rip), %0\n" + : "=r"(entrypoint)); + return entrypoint; + } + + #define LSS_ENTRYPOINT \ + ".bss\n" \ + ".align 8\n" \ + ".globl " SYS_SYSCALL_ENTRYPOINT "\n" \ + ".common " SYS_SYSCALL_ENTRYPOINT ",8,8\n" \ + ".previous\n" \ + "mov " SYS_SYSCALL_ENTRYPOINT "@GOTPCREL(%%rip), %%rcx\n" \ + "mov 0(%%rcx), %%rcx\n" \ + "test %%rcx, %%rcx\n" \ + "jz 10001f\n" \ + "call *%%rcx\n" \ + "jmp 10002f\n" \ + "10001:syscall\n" \ + "10002:\n" + + #else + #define LSS_ENTRYPOINT "syscall\n" + #endif + + /* The x32 ABI has 32 bit longs, but the syscall interface is 64 bit. + * We need to explicitly cast to an unsigned 64 bit type to avoid implicit + * sign extension. We can't cast pointers directly because those are + * 32 bits, and gcc will dump ugly warnings about casting from a pointer + * to an integer of a different size. + */ + #undef LSS_SYSCALL_ARG + #define LSS_SYSCALL_ARG(a) ((uint64_t)(uintptr_t)(a)) + #undef _LSS_RETURN + #define _LSS_RETURN(type, res, cast) \ + do { \ + if ((uint64_t)(res) >= (uint64_t)(-4095)) { \ + LSS_ERRNO = -(res); \ + res = -1; \ + } \ + return (type)(cast)(res); \ + } while (0) + #undef LSS_RETURN + #define LSS_RETURN(type, res) _LSS_RETURN(type, res, uintptr_t) + + #undef _LSS_BODY + #define _LSS_BODY(nr, type, name, cast, ...) \ + long long __res; \ + __asm__ __volatile__(LSS_BODY_ASM##nr LSS_ENTRYPOINT \ + : "=a" (__res) \ + : "0" (__NR_##name) LSS_BODY_ARG##nr(__VA_ARGS__) \ + : LSS_BODY_CLOBBER##nr "r11", "rcx", "memory"); \ + _LSS_RETURN(type, __res, cast) + #undef LSS_BODY + #define LSS_BODY(nr, type, name, args...) \ + _LSS_BODY(nr, type, name, uintptr_t, ## args) + + #undef LSS_BODY_ASM0 + #undef LSS_BODY_ASM1 + #undef LSS_BODY_ASM2 + #undef LSS_BODY_ASM3 + #undef LSS_BODY_ASM4 + #undef LSS_BODY_ASM5 + #undef LSS_BODY_ASM6 + #define LSS_BODY_ASM0 + #define LSS_BODY_ASM1 LSS_BODY_ASM0 + #define LSS_BODY_ASM2 LSS_BODY_ASM1 + #define LSS_BODY_ASM3 LSS_BODY_ASM2 + #define LSS_BODY_ASM4 LSS_BODY_ASM3 "movq %5,%%r10;" + #define LSS_BODY_ASM5 LSS_BODY_ASM4 "movq %6,%%r8;" + #define LSS_BODY_ASM6 LSS_BODY_ASM5 "movq %7,%%r9;" + + #undef LSS_BODY_CLOBBER0 + #undef LSS_BODY_CLOBBER1 + #undef LSS_BODY_CLOBBER2 + #undef LSS_BODY_CLOBBER3 + #undef LSS_BODY_CLOBBER4 + #undef LSS_BODY_CLOBBER5 + #undef LSS_BODY_CLOBBER6 + #define LSS_BODY_CLOBBER0 + #define LSS_BODY_CLOBBER1 LSS_BODY_CLOBBER0 + #define LSS_BODY_CLOBBER2 LSS_BODY_CLOBBER1 + #define LSS_BODY_CLOBBER3 LSS_BODY_CLOBBER2 + #define LSS_BODY_CLOBBER4 LSS_BODY_CLOBBER3 "r10", + #define LSS_BODY_CLOBBER5 LSS_BODY_CLOBBER4 "r8", + #define LSS_BODY_CLOBBER6 LSS_BODY_CLOBBER5 "r9", + + #undef LSS_BODY_ARG0 + #undef LSS_BODY_ARG1 + #undef LSS_BODY_ARG2 + #undef LSS_BODY_ARG3 + #undef LSS_BODY_ARG4 + #undef LSS_BODY_ARG5 + #undef LSS_BODY_ARG6 + #define LSS_BODY_ARG0() + #define LSS_BODY_ARG1(arg1) \ + LSS_BODY_ARG0(), "D" (arg1) + #define LSS_BODY_ARG2(arg1, arg2) \ + LSS_BODY_ARG1(arg1), "S" (arg2) + #define LSS_BODY_ARG3(arg1, arg2, arg3) \ + LSS_BODY_ARG2(arg1, arg2), "d" (arg3) + #define LSS_BODY_ARG4(arg1, arg2, arg3, arg4) \ + LSS_BODY_ARG3(arg1, arg2, arg3), "r" (arg4) + #define LSS_BODY_ARG5(arg1, arg2, arg3, arg4, arg5) \ + LSS_BODY_ARG4(arg1, arg2, arg3, arg4), "r" (arg5) + #define LSS_BODY_ARG6(arg1, arg2, arg3, arg4, arg5, arg6) \ + LSS_BODY_ARG5(arg1, arg2, arg3, arg4, arg5), "r" (arg6) + + #undef _syscall0 + #define _syscall0(type,name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(0, type, name); \ + } + #undef _syscall1 + #define _syscall1(type,name,type1,arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_BODY(1, type, name, LSS_SYSCALL_ARG(arg1)); \ + } + #undef _syscall2 + #define _syscall2(type,name,type1,arg1,type2,arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_BODY(2, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2));\ + } + #undef _syscall3 + #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_BODY(3, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2), \ + LSS_SYSCALL_ARG(arg3)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_BODY(4, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2), \ + LSS_SYSCALL_ARG(arg3), LSS_SYSCALL_ARG(arg4));\ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_BODY(5, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2), \ + LSS_SYSCALL_ARG(arg3), LSS_SYSCALL_ARG(arg4), \ + LSS_SYSCALL_ARG(arg5)); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_BODY(6, type, name, LSS_SYSCALL_ARG(arg1), LSS_SYSCALL_ARG(arg2), \ + LSS_SYSCALL_ARG(arg3), LSS_SYSCALL_ARG(arg4), \ + LSS_SYSCALL_ARG(arg5), LSS_SYSCALL_ARG(arg6));\ + } + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + long long __res; + { + __asm__ __volatile__(/* if (fn == NULL) + * return -EINVAL; + */ + "testq %4,%4\n" + "jz 1f\n" + + /* if (child_stack == NULL) + * return -EINVAL; + */ + "testq %5,%5\n" + "jz 1f\n" + + /* childstack -= 2*sizeof(void *); + */ + "subq $16,%5\n" + + /* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + "movq %7,8(%5)\n" + "movq %4,0(%5)\n" + + /* %rax = syscall(%rax = __NR_clone, + * %rdi = flags, + * %rsi = child_stack, + * %rdx = parent_tidptr, + * %r8 = new_tls, + * %r10 = child_tidptr) + */ + "movq %2,%%rax\n" + "movq %9,%%r8\n" + "movq %10,%%r10\n" + LSS_ENTRYPOINT + + /* if (%rax != 0) + * return; + */ + "testq %%rax,%%rax\n" + "jnz 1f\n" + + /* In the child. Terminate frame pointer chain. + */ + "xorq %%rbp,%%rbp\n" + + /* Call "fn(arg)". + */ + "popq %%rax\n" + "popq %%rdi\n" + "call *%%rax\n" + + /* Call _exit(%ebx). + */ + "movq %%rax,%%rdi\n" + "movq %3,%%rax\n" + LSS_ENTRYPOINT + + /* Return to parent. + */ + "1:\n" + : "=a" (__res) + : "0"(-EINVAL), "i"(__NR_clone), "i"(__NR_exit), + "r"(LSS_SYSCALL_ARG(fn)), + "S"(LSS_SYSCALL_ARG(child_stack)), + "D"(LSS_SYSCALL_ARG(flags)), + "r"(LSS_SYSCALL_ARG(arg)), + "d"(LSS_SYSCALL_ARG(parent_tidptr)), + "r"(LSS_SYSCALL_ARG(newtls)), + "r"(LSS_SYSCALL_ARG(child_tidptr)) + : "rsp", "memory", "r8", "r10", "r11", "rcx"); + } + LSS_RETURN(int, __res); + } + LSS_INLINE _syscall2(int, arch_prctl, int, c, void *, a) + + /* Need to make sure loff_t isn't truncated to 32-bits under x32. */ + LSS_INLINE int LSS_NAME(fadvise64)(int fd, loff_t offset, loff_t len, + int advice) { + LSS_BODY(4, int, fadvise64, LSS_SYSCALL_ARG(fd), (uint64_t)(offset), + (uint64_t)(len), LSS_SYSCALL_ARG(advice)); + } + + LSS_INLINE void (*LSS_NAME(restore_rt)(void))(void) { + /* On x86-64, the kernel does not know how to return from + * a signal handler. Instead, it relies on user space to provide a + * restorer function that calls the rt_sigreturn() system call. + * Unfortunately, we cannot just reference the glibc version of this + * function, as glibc goes out of its way to make it inaccessible. + */ + long long res; + __asm__ __volatile__("jmp 2f\n" + ".align 16\n" + "1:movq %1,%%rax\n" + LSS_ENTRYPOINT + "2:leaq 1b(%%rip),%0\n" + : "=r" (res) + : "i" (__NR_rt_sigreturn)); + return (void (*)(void))(uintptr_t)res; + } + #elif defined(__ARM_ARCH_3__) + /* Most definitions of _syscallX() neglect to mark "memory" as being + * clobbered. This causes problems with compilers, that do a better job + * at optimizing across __asm__ calls. + * So, we just have to redefine all of the _syscallX() macros. + */ + #undef LSS_REG + #define LSS_REG(r,a) register long __r##r __asm__("r"#r) = (long)a + #undef LSS_BODY + #define LSS_BODY(type,name,args...) \ + register long __res_r0 __asm__("r0"); \ + long __res; \ + __asm__ __volatile__ (__syscall(name) \ + : "=r"(__res_r0) : args : "lr", "memory"); \ + __res = __res_r0; \ + LSS_RETURN(type, __res) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4)); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4), "r"(__r5)); \ + } + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + long __res; + { + register int __flags __asm__("r0") = flags; + register void *__stack __asm__("r1") = child_stack; + register void *__ptid __asm__("r2") = parent_tidptr; + register void *__tls __asm__("r3") = newtls; + register int *__ctid __asm__("r4") = child_tidptr; + __asm__ __volatile__(/* if (fn == NULL || child_stack == NULL) + * return -EINVAL; + */ + "cmp %2,#0\n" + "cmpne %3,#0\n" + "moveq %0,%1\n" + "beq 1f\n" + + /* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + "str %5,[%3,#-4]!\n" + "str %2,[%3,#-4]!\n" + + /* %r0 = syscall(%r0 = flags, + * %r1 = child_stack, + * %r2 = parent_tidptr, + * %r3 = newtls, + * %r4 = child_tidptr) + */ + __syscall(clone)"\n" + + /* if (%r0 != 0) + * return %r0; + */ + "movs %0,r0\n" + "bne 1f\n" + + /* In the child, now. Call "fn(arg)". + */ + "ldr r0,[sp, #4]\n" + "mov lr,pc\n" + "ldr pc,[sp]\n" + + /* Call _exit(%r0). + */ + __syscall(exit)"\n" + "1:\n" + : "=r" (__res) + : "i"(-EINVAL), + "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), + "r"(__ptid), "r"(__tls), "r"(__ctid) + : "cc", "lr", "memory"); + } + LSS_RETURN(int, __res); + } + #elif defined(__ARM_EABI__) + /* Most definitions of _syscallX() neglect to mark "memory" as being + * clobbered. This causes problems with compilers, that do a better job + * at optimizing across __asm__ calls. + * So, we just have to redefine all fo the _syscallX() macros. + */ + #undef LSS_REG + #define LSS_REG(r,a) register long __r##r __asm__("r"#r) = (long)a + #undef LSS_BODY + #define LSS_BODY(type,name,args...) \ + register long __res_r0 __asm__("r0"); \ + long __res; \ + __asm__ __volatile__ ("push {r7}\n" \ + "mov r7, %1\n" \ + "swi 0x0\n" \ + "pop {r7}\n" \ + : "=r"(__res_r0) \ + : "i"(__NR_##name) , ## args \ + : "lr", "memory"); \ + __res = __res_r0; \ + LSS_RETURN(type, __res) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4)); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4), "r"(__r5)); \ + } + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + long __res; + { + register int __flags __asm__("r0") = flags; + register void *__stack __asm__("r1") = child_stack; + register void *__ptid __asm__("r2") = parent_tidptr; + register void *__tls __asm__("r3") = newtls; + register int *__ctid __asm__("r4") = child_tidptr; + __asm__ __volatile__(/* if (fn == NULL || child_stack == NULL) + * return -EINVAL; + */ +#ifdef __thumb2__ + "push {r7}\n" +#endif + "cmp %2,#0\n" + "it ne\n" + "cmpne %3,#0\n" + "it eq\n" + "moveq %0,%1\n" + "beq 1f\n" + + /* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + "str %5,[%3,#-4]!\n" + "str %2,[%3,#-4]!\n" + + /* %r0 = syscall(%r0 = flags, + * %r1 = child_stack, + * %r2 = parent_tidptr, + * %r3 = newtls, + * %r4 = child_tidptr) + */ + "mov r7, %9\n" + "swi 0x0\n" + + /* if (%r0 != 0) + * return %r0; + */ + "movs %0,r0\n" + "bne 1f\n" + + /* In the child, now. Call "fn(arg)". + */ + "ldr r0,[sp, #4]\n" + + /* When compiling for Thumb-2 the "MOV LR,PC" here + * won't work because it loads PC+4 into LR, + * whereas the LDR is a 4-byte instruction. + * This results in the child thread always + * crashing with an "Illegal Instruction" when it + * returned into the middle of the LDR instruction + * The instruction sequence used instead was + * recommended by + * "https://wiki.edubuntu.org/ARM/Thumb2PortingHowto#Quick_Reference". + */ + #ifdef __thumb2__ + "ldr r7,[sp]\n" + "blx r7\n" + #else + "mov lr,pc\n" + "ldr pc,[sp]\n" + #endif + + /* Call _exit(%r0). + */ + "mov r7, %10\n" + "swi 0x0\n" + "1:\n" +#ifdef __thumb2__ + "pop {r7}" +#endif + : "=r" (__res) + : "i"(-EINVAL), + "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), + "r"(__ptid), "r"(__tls), "r"(__ctid), + "i"(__NR_clone), "i"(__NR_exit) +#ifdef __thumb2__ + : "cc", "lr", "memory"); +#else + : "cc", "r7", "lr", "memory"); +#endif + } + LSS_RETURN(int, __res); + } + #elif defined(__aarch64__) + /* Most definitions of _syscallX() neglect to mark "memory" as being + * clobbered. This causes problems with compilers, that do a better job + * at optimizing across __asm__ calls. + * So, we just have to redefine all of the _syscallX() macros. + */ + #undef LSS_REG + #define LSS_REG(r,a) register int64_t __r##r __asm__("x"#r) = (int64_t)a + #undef LSS_BODY + #define LSS_BODY(type,name,args...) \ + register int64_t __res_x0 __asm__("x0"); \ + int64_t __res; \ + __asm__ __volatile__ ("mov x8, %1\n" \ + "svc 0x0\n" \ + : "=r"(__res_x0) \ + : "i"(__NR_##name) , ## args \ + : "x8", "memory"); \ + __res = __res_x0; \ + LSS_RETURN(type, __res) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_REG(0, arg1); LSS_BODY(type, name, "r"(__r0)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3)); \ + } + #undef _syscall5 + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4)); \ + } + #undef _syscall6 + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_REG(0, arg1); LSS_REG(1, arg2); LSS_REG(2, arg3); \ + LSS_REG(3, arg4); LSS_REG(4, arg5); LSS_REG(5, arg6); \ + LSS_BODY(type, name, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), \ + "r"(__r4), "r"(__r5)); \ + } + + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + int64_t __res; + { + register uint64_t __flags __asm__("x0") = flags; + register void *__stack __asm__("x1") = child_stack; + register void *__ptid __asm__("x2") = parent_tidptr; + register void *__tls __asm__("x3") = newtls; + register int *__ctid __asm__("x4") = child_tidptr; + __asm__ __volatile__(/* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + "stp %1, %4, [%2, #-16]!\n" + + /* %x0 = syscall(%x0 = flags, + * %x1 = child_stack, + * %x2 = parent_tidptr, + * %x3 = newtls, + * %x4 = child_tidptr) + */ + "mov x8, %8\n" + "svc 0x0\n" + + /* if (%r0 != 0) + * return %r0; + */ + "mov %0, x0\n" + "cbnz x0, 1f\n" + + /* In the child, now. Call "fn(arg)". + */ + "ldp x1, x0, [sp], #16\n" + "blr x1\n" + + /* Call _exit(%r0). + */ + "mov x8, %9\n" + "svc 0x0\n" + "1:\n" + : "=r" (__res) + : "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), + "r"(__ptid), "r"(__tls), "r"(__ctid), + "i"(__NR_clone), "i"(__NR_exit) + : "cc", "x8", "memory"); + } + LSS_RETURN(int, __res); + } + #elif defined(__mips__) + #undef LSS_REG + #define LSS_REG(r,a) register unsigned long __r##r __asm__("$"#r) = \ + (unsigned long)(a) + #undef LSS_BODY + #undef LSS_SYSCALL_CLOBBERS + #if _MIPS_SIM == _MIPS_SIM_ABI32 + #define LSS_SYSCALL_CLOBBERS "$1", "$3", "$8", "$9", "$10", \ + "$11", "$12", "$13", "$14", "$15", \ + "$24", "$25", "hi", "lo", "memory" + #else + #define LSS_SYSCALL_CLOBBERS "$1", "$3", "$10", "$11", "$12", \ + "$13", "$14", "$15", "$24", "$25", \ + "hi", "lo", "memory" + #endif + #define LSS_BODY(type,name,r7,...) \ + register unsigned long __v0 __asm__("$2") = __NR_##name; \ + __asm__ __volatile__ ("syscall\n" \ + : "+r"(__v0), r7 (__r7) \ + : "0"(__v0), ##__VA_ARGS__ \ + : LSS_SYSCALL_CLOBBERS); \ + LSS_RETURN(type, __v0, __r7) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + register unsigned long __r7 __asm__("$7"); \ + LSS_BODY(type, name, "=r"); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + register unsigned long __r7 __asm__("$7"); \ + LSS_REG(4, arg1); LSS_BODY(type, name, "=r", "r"(__r4)); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + register unsigned long __r7 __asm__("$7"); \ + LSS_REG(4, arg1); LSS_REG(5, arg2); \ + LSS_BODY(type, name, "=r", "r"(__r4), "r"(__r5)); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + register unsigned long __r7 __asm__("$7"); \ + LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ + LSS_BODY(type, name, "=r", "r"(__r4), "r"(__r5), "r"(__r6)); \ + } + #undef _syscall4 + #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ + LSS_REG(7, arg4); \ + LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6)); \ + } + #undef _syscall5 + #if _MIPS_SIM == _MIPS_SIM_ABI32 + /* The old 32bit MIPS system call API passes the fifth and sixth argument + * on the stack, whereas the new APIs use registers "r8" and "r9". + */ + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ + LSS_REG(7, arg4); \ + register unsigned long __v0 __asm__("$2") = __NR_##name; \ + __asm__ __volatile__ (".set noreorder\n" \ + "subu $29, 32\n" \ + "sw %5, 16($29)\n" \ + "syscall\n" \ + "addiu $29, 32\n" \ + ".set reorder\n" \ + : "+r"(__v0), "+r" (__r7) \ + : "r"(__r4), "r"(__r5), \ + "r"(__r6), "r" ((unsigned long)arg5) \ + : "$8", "$9", "$10", "$11", "$12", \ + "$13", "$14", "$15", "$24", "$25", \ + "memory"); \ + LSS_RETURN(type, __v0, __r7); \ + } + #else + #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ + LSS_REG(7, arg4); LSS_REG(8, arg5); \ + LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6), \ + "r"(__r8)); \ + } + #endif + #undef _syscall6 + #if _MIPS_SIM == _MIPS_SIM_ABI32 + /* The old 32bit MIPS system call API passes the fifth and sixth argument + * on the stack, whereas the new APIs use registers "r8" and "r9". + */ + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ + LSS_REG(7, arg4); \ + register unsigned long __v0 __asm__("$2") = __NR_##name; \ + __asm__ __volatile__ (".set noreorder\n" \ + "subu $29, 32\n" \ + "sw %5, 16($29)\n" \ + "sw %6, 20($29)\n" \ + "syscall\n" \ + "addiu $29, 32\n" \ + ".set reorder\n" \ + : "+r"(__v0), "+r" (__r7) \ + : "r"(__r4), "r"(__r5), \ + "r"(__r6), "r" ((unsigned long)arg5), \ + "r" ((unsigned long)arg6) \ + : "$8", "$9", "$10", "$11", "$12", \ + "$13", "$14", "$15", "$24", "$25", \ + "memory"); \ + LSS_RETURN(type, __v0, __r7); \ + } + #else + #define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5,type6,arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5,type6 arg6) { \ + LSS_REG(4, arg1); LSS_REG(5, arg2); LSS_REG(6, arg3); \ + LSS_REG(7, arg4); LSS_REG(8, arg5); LSS_REG(9, arg6); \ + LSS_BODY(type, name, "+r", "r"(__r4), "r"(__r5), "r"(__r6), \ + "r"(__r8), "r"(__r9)); \ + } + #endif + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + register unsigned long __v0 __asm__("$2"); + register unsigned long __r7 __asm__("$7") = (unsigned long)newtls; + { + register int __flags __asm__("$4") = flags; + register void *__stack __asm__("$5") = child_stack; + register void *__ptid __asm__("$6") = parent_tidptr; + register int *__ctid __asm__("$8") = child_tidptr; + __asm__ __volatile__( + #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 + "subu $29,24\n" + #elif _MIPS_SIM == _MIPS_SIM_NABI32 + "sub $29,16\n" + #else + "dsubu $29,16\n" + #endif + + /* if (fn == NULL || child_stack == NULL) + * return -EINVAL; + */ + "li %0,%2\n" + "beqz %5,1f\n" + "beqz %6,1f\n" + + /* Push "arg" and "fn" onto the stack that will be + * used by the child. + */ + #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 + "subu %6,32\n" + "sw %5,0(%6)\n" + "sw %8,4(%6)\n" + #elif _MIPS_SIM == _MIPS_SIM_NABI32 + "sub %6,32\n" + "sw %5,0(%6)\n" + "sw %8,8(%6)\n" + #else + "dsubu %6,32\n" + "sd %5,0(%6)\n" + "sd %8,8(%6)\n" + #endif + + /* $7 = syscall($4 = flags, + * $5 = child_stack, + * $6 = parent_tidptr, + * $7 = newtls, + * $8 = child_tidptr) + */ + "li $2,%3\n" + "syscall\n" + + /* if ($7 != 0) + * return $2; + */ + "bnez $7,1f\n" + "bnez $2,1f\n" + + /* In the child, now. Call "fn(arg)". + */ + #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 + "lw $25,0($29)\n" + "lw $4,4($29)\n" + #elif _MIPS_SIM == _MIPS_SIM_NABI32 + "lw $25,0($29)\n" + "lw $4,8($29)\n" + #else + "ld $25,0($29)\n" + "ld $4,8($29)\n" + #endif + "jalr $25\n" + + /* Call _exit($2) + */ + "move $4,$2\n" + "li $2,%4\n" + "syscall\n" + + "1:\n" + #if _MIPS_SIM == _MIPS_SIM_ABI32 && _MIPS_SZPTR == 32 + "addu $29, 24\n" + #elif _MIPS_SIM == _MIPS_SIM_NABI32 + "add $29, 16\n" + #else + "daddu $29,16\n" + #endif + : "+r" (__v0), "+r" (__r7) + : "i"(-EINVAL), "i"(__NR_clone), "i"(__NR_exit), + "r"(fn), "r"(__stack), "r"(__flags), "r"(arg), + "r"(__ptid), "r"(__r7), "r"(__ctid) + : "$9", "$10", "$11", "$12", "$13", "$14", "$15", + "$24", "$25", "memory"); + } + LSS_RETURN(int, __v0, __r7); + } + #elif defined (__PPC__) + #undef LSS_LOADARGS_0 + #define LSS_LOADARGS_0(name, dummy...) \ + __sc_0 = __NR_##name + #undef LSS_LOADARGS_1 + #define LSS_LOADARGS_1(name, arg1) \ + LSS_LOADARGS_0(name); \ + __sc_3 = (unsigned long) (arg1) + #undef LSS_LOADARGS_2 + #define LSS_LOADARGS_2(name, arg1, arg2) \ + LSS_LOADARGS_1(name, arg1); \ + __sc_4 = (unsigned long) (arg2) + #undef LSS_LOADARGS_3 + #define LSS_LOADARGS_3(name, arg1, arg2, arg3) \ + LSS_LOADARGS_2(name, arg1, arg2); \ + __sc_5 = (unsigned long) (arg3) + #undef LSS_LOADARGS_4 + #define LSS_LOADARGS_4(name, arg1, arg2, arg3, arg4) \ + LSS_LOADARGS_3(name, arg1, arg2, arg3); \ + __sc_6 = (unsigned long) (arg4) + #undef LSS_LOADARGS_5 + #define LSS_LOADARGS_5(name, arg1, arg2, arg3, arg4, arg5) \ + LSS_LOADARGS_4(name, arg1, arg2, arg3, arg4); \ + __sc_7 = (unsigned long) (arg5) + #undef LSS_LOADARGS_6 + #define LSS_LOADARGS_6(name, arg1, arg2, arg3, arg4, arg5, arg6) \ + LSS_LOADARGS_5(name, arg1, arg2, arg3, arg4, arg5); \ + __sc_8 = (unsigned long) (arg6) + #undef LSS_ASMINPUT_0 + #define LSS_ASMINPUT_0 "0" (__sc_0) + #undef LSS_ASMINPUT_1 + #define LSS_ASMINPUT_1 LSS_ASMINPUT_0, "1" (__sc_3) + #undef LSS_ASMINPUT_2 + #define LSS_ASMINPUT_2 LSS_ASMINPUT_1, "2" (__sc_4) + #undef LSS_ASMINPUT_3 + #define LSS_ASMINPUT_3 LSS_ASMINPUT_2, "3" (__sc_5) + #undef LSS_ASMINPUT_4 + #define LSS_ASMINPUT_4 LSS_ASMINPUT_3, "4" (__sc_6) + #undef LSS_ASMINPUT_5 + #define LSS_ASMINPUT_5 LSS_ASMINPUT_4, "5" (__sc_7) + #undef LSS_ASMINPUT_6 + #define LSS_ASMINPUT_6 LSS_ASMINPUT_5, "6" (__sc_8) + #undef LSS_BODY + #define LSS_BODY(nr, type, name, args...) \ + long __sc_ret, __sc_err; \ + { \ + register unsigned long __sc_0 __asm__ ("r0"); \ + register unsigned long __sc_3 __asm__ ("r3"); \ + register unsigned long __sc_4 __asm__ ("r4"); \ + register unsigned long __sc_5 __asm__ ("r5"); \ + register unsigned long __sc_6 __asm__ ("r6"); \ + register unsigned long __sc_7 __asm__ ("r7"); \ + register unsigned long __sc_8 __asm__ ("r8"); \ + \ + LSS_LOADARGS_##nr(name, args); \ + __asm__ __volatile__ \ + ("sc\n\t" \ + "mfcr %0" \ + : "=&r" (__sc_0), \ + "=&r" (__sc_3), "=&r" (__sc_4), \ + "=&r" (__sc_5), "=&r" (__sc_6), \ + "=&r" (__sc_7), "=&r" (__sc_8) \ + : LSS_ASMINPUT_##nr \ + : "cr0", "ctr", "memory", \ + "r9", "r10", "r11", "r12"); \ + __sc_ret = __sc_3; \ + __sc_err = __sc_0; \ + } \ + LSS_RETURN(type, __sc_ret, __sc_err) + #undef _syscall0 + #define _syscall0(type, name) \ + type LSS_NAME(name)(void) { \ + LSS_BODY(0, type, name); \ + } + #undef _syscall1 + #define _syscall1(type, name, type1, arg1) \ + type LSS_NAME(name)(type1 arg1) { \ + LSS_BODY(1, type, name, arg1); \ + } + #undef _syscall2 + #define _syscall2(type, name, type1, arg1, type2, arg2) \ + type LSS_NAME(name)(type1 arg1, type2 arg2) { \ + LSS_BODY(2, type, name, arg1, arg2); \ + } + #undef _syscall3 + #define _syscall3(type, name, type1, arg1, type2, arg2, type3, arg3) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3) { \ + LSS_BODY(3, type, name, arg1, arg2, arg3); \ + } + #undef _syscall4 + #define _syscall4(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + LSS_BODY(4, type, name, arg1, arg2, arg3, arg4); \ + } + #undef _syscall5 + #define _syscall5(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4, type5, arg5) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5) { \ + LSS_BODY(5, type, name, arg1, arg2, arg3, arg4, arg5); \ + } + #undef _syscall6 + #define _syscall6(type, name, type1, arg1, type2, arg2, type3, arg3, \ + type4, arg4, type5, arg5, type6, arg6) \ + type LSS_NAME(name)(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \ + type5 arg5, type6 arg6) { \ + LSS_BODY(6, type, name, arg1, arg2, arg3, arg4, arg5, arg6); \ + } + /* clone function adapted from glibc 2.3.6 clone.S */ + /* TODO(csilvers): consider wrapping some args up in a struct, like we + * do for i386's _syscall6, so we can compile successfully on gcc 2.95 + */ + LSS_INLINE int LSS_NAME(clone)(int (*fn)(void *), void *child_stack, + int flags, void *arg, int *parent_tidptr, + void *newtls, int *child_tidptr) { + long __ret, __err; + { + register int (*__fn)(void *) __asm__ ("r8") = fn; + register void *__cstack __asm__ ("r4") = child_stack; + register int __flags __asm__ ("r3") = flags; + register void * __arg __asm__ ("r9") = arg; + register int * __ptidptr __asm__ ("r5") = parent_tidptr; + register void * __newtls __asm__ ("r6") = newtls; + register int * __ctidptr __asm__ ("r7") = child_tidptr; + __asm__ __volatile__( + /* check for fn == NULL + * and child_stack == NULL + */ + "cmpwi cr0, %6, 0\n\t" + "cmpwi cr1, %7, 0\n\t" + "cror cr0*4+eq, cr1*4+eq, cr0*4+eq\n\t" + "beq- cr0, 1f\n\t" + + /* set up stack frame for child */ + "clrrwi %7, %7, 4\n\t" + "li 0, 0\n\t" + "stwu 0, -16(%7)\n\t" + + /* fn, arg, child_stack are saved across the syscall: r28-30 */ + "mr 28, %6\n\t" + "mr 29, %7\n\t" + "mr 27, %9\n\t" + + /* syscall */ + "li 0, %4\n\t" + /* flags already in r3 + * child_stack already in r4 + * ptidptr already in r5 + * newtls already in r6 + * ctidptr already in r7 + */ + "sc\n\t" + + /* Test if syscall was successful */ + "cmpwi cr1, 3, 0\n\t" + "crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t" + "bne- cr1, 1f\n\t" + + /* Do the function call */ + "mtctr 28\n\t" + "mr 3, 27\n\t" + "bctrl\n\t" + + /* Call _exit(r3) */ + "li 0, %5\n\t" + "sc\n\t" + + /* Return to parent */ + "1:\n" + "mfcr %1\n\t" + "mr %0, 3\n\t" + : "=r" (__ret), "=r" (__err) + : "0" (-1), "1" (EINVAL), + "i" (__NR_clone), "i" (__NR_exit), + "r" (__fn), "r" (__cstack), "r" (__flags), + "r" (__arg), "r" (__ptidptr), "r" (__newtls), + "r" (__ctidptr) + : "cr0", "cr1", "memory", "ctr", + "r0", "r29", "r27", "r28"); + } + LSS_RETURN(int, __ret, __err); + } + #endif + #define __NR__exit __NR_exit + #define __NR__gettid __NR_gettid + #define __NR__mremap __NR_mremap + LSS_INLINE _syscall1(void *, brk, void *, e) + LSS_INLINE _syscall1(int, chdir, const char *,p) + LSS_INLINE _syscall1(int, close, int, f) + LSS_INLINE _syscall2(int, clock_getres, int, c, + struct kernel_timespec*, t) + LSS_INLINE _syscall2(int, clock_gettime, int, c, + struct kernel_timespec*, t) + LSS_INLINE _syscall1(int, dup, int, f) + #if !defined(__aarch64__) + // The dup2 syscall has been deprecated on aarch64. We polyfill it below. + LSS_INLINE _syscall2(int, dup2, int, s, + int, d) + #endif + LSS_INLINE _syscall3(int, execve, const char*, f, + const char*const*,a,const char*const*, e) + LSS_INLINE _syscall1(int, _exit, int, e) + LSS_INLINE _syscall1(int, exit_group, int, e) + LSS_INLINE _syscall3(int, fcntl, int, f, + int, c, long, a) + #if !defined(__aarch64__) + // The fork syscall has been deprecated on aarch64. We polyfill it below. + LSS_INLINE _syscall0(pid_t, fork) + #endif + LSS_INLINE _syscall2(int, fstat, int, f, + struct kernel_stat*, b) + LSS_INLINE _syscall2(int, fstatfs, int, f, + struct kernel_statfs*, b) + #if defined(__x86_64__) + /* Need to make sure off_t isn't truncated to 32-bits under x32. */ + LSS_INLINE int LSS_NAME(ftruncate)(int f, off_t l) { + LSS_BODY(2, int, ftruncate, LSS_SYSCALL_ARG(f), (uint64_t)(l)); + } + #else + LSS_INLINE _syscall2(int, ftruncate, int, f, + off_t, l) + #endif + LSS_INLINE _syscall4(int, futex, int*, a, + int, o, int, v, + struct kernel_timespec*, t) + LSS_INLINE _syscall3(int, getdents, int, f, + struct kernel_dirent*, d, int, c) + LSS_INLINE _syscall3(int, getdents64, int, f, + struct kernel_dirent64*, d, int, c) + LSS_INLINE _syscall0(gid_t, getegid) + LSS_INLINE _syscall0(uid_t, geteuid) + #if !defined(__aarch64__) + // The getgprp syscall has been deprecated on aarch64. + LSS_INLINE _syscall0(pid_t, getpgrp) + #endif + LSS_INLINE _syscall0(pid_t, getpid) + LSS_INLINE _syscall0(pid_t, getppid) + LSS_INLINE _syscall2(int, getpriority, int, a, + int, b) + LSS_INLINE _syscall3(int, getresgid, gid_t *, r, + gid_t *, e, gid_t *, s) + LSS_INLINE _syscall3(int, getresuid, uid_t *, r, + uid_t *, e, uid_t *, s) +#if !defined(__ARM_EABI__) + LSS_INLINE _syscall2(int, getrlimit, int, r, + struct kernel_rlimit*, l) +#endif + LSS_INLINE _syscall1(pid_t, getsid, pid_t, p) + LSS_INLINE _syscall0(pid_t, _gettid) + LSS_INLINE _syscall2(pid_t, gettimeofday, struct kernel_timeval*, t, + void*, tz) + LSS_INLINE _syscall5(int, setxattr, const char *,p, + const char *, n, const void *,v, + size_t, s, int, f) + LSS_INLINE _syscall5(int, lsetxattr, const char *,p, + const char *, n, const void *,v, + size_t, s, int, f) + LSS_INLINE _syscall4(ssize_t, getxattr, const char *,p, + const char *, n, void *, v, size_t, s) + LSS_INLINE _syscall4(ssize_t, lgetxattr, const char *,p, + const char *, n, void *, v, size_t, s) + LSS_INLINE _syscall3(ssize_t, listxattr, const char *,p, + char *, l, size_t, s) + LSS_INLINE _syscall3(ssize_t, llistxattr, const char *,p, + char *, l, size_t, s) + LSS_INLINE _syscall3(int, ioctl, int, d, + int, r, void *, a) + LSS_INLINE _syscall2(int, ioprio_get, int, which, + int, who) + LSS_INLINE _syscall3(int, ioprio_set, int, which, + int, who, int, ioprio) + LSS_INLINE _syscall2(int, kill, pid_t, p, + int, s) + #if defined(__x86_64__) + /* Need to make sure off_t isn't truncated to 32-bits under x32. */ + LSS_INLINE off_t LSS_NAME(lseek)(int f, off_t o, int w) { + _LSS_BODY(3, off_t, lseek, off_t, LSS_SYSCALL_ARG(f), (uint64_t)(o), + LSS_SYSCALL_ARG(w)); + } + #else + LSS_INLINE _syscall3(off_t, lseek, int, f, + off_t, o, int, w) + #endif + LSS_INLINE _syscall2(int, munmap, void*, s, + size_t, l) + LSS_INLINE _syscall6(long, move_pages, pid_t, p, + unsigned long, n, void **,g, int *, d, + int *, s, int, f) + LSS_INLINE _syscall3(int, mprotect, const void *,a, + size_t, l, int, p) + LSS_INLINE _syscall5(void*, _mremap, void*, o, + size_t, os, size_t, ns, + unsigned long, f, void *, a) + #if !defined(__aarch64__) + // The open and poll syscalls have been deprecated on aarch64. We polyfill + // them below. + LSS_INLINE _syscall3(int, open, const char*, p, + int, f, int, m) + LSS_INLINE _syscall3(int, poll, struct kernel_pollfd*, u, + unsigned int, n, int, t) + #endif + LSS_INLINE _syscall5(int, prctl, int, option, + unsigned long, arg2, + unsigned long, arg3, + unsigned long, arg4, + unsigned long, arg5) + LSS_INLINE _syscall4(long, ptrace, int, r, + pid_t, p, void *, a, void *, d) + #if defined(__NR_quotactl) + // Defined on x86_64 / i386 only + LSS_INLINE _syscall4(int, quotactl, int, cmd, const char *, special, + int, id, caddr_t, addr) + #endif + LSS_INLINE _syscall3(ssize_t, read, int, f, + void *, b, size_t, c) + #if !defined(__aarch64__) + // The readlink syscall has been deprecated on aarch64. We polyfill below. + LSS_INLINE _syscall3(int, readlink, const char*, p, + char*, b, size_t, s) + #endif + LSS_INLINE _syscall4(int, rt_sigaction, int, s, + const struct kernel_sigaction*, a, + struct kernel_sigaction*, o, size_t, c) + LSS_INLINE _syscall2(int, rt_sigpending, struct kernel_sigset_t *, s, + size_t, c) + LSS_INLINE _syscall4(int, rt_sigprocmask, int, h, + const struct kernel_sigset_t*, s, + struct kernel_sigset_t*, o, size_t, c) + LSS_INLINE _syscall2(int, rt_sigsuspend, + const struct kernel_sigset_t*, s, size_t, c) + LSS_INLINE _syscall3(int, sched_getaffinity,pid_t, p, + unsigned int, l, unsigned long *, m) + LSS_INLINE _syscall3(int, sched_setaffinity,pid_t, p, + unsigned int, l, unsigned long *, m) + LSS_INLINE _syscall0(int, sched_yield) + LSS_INLINE _syscall1(long, set_tid_address, int *, t) + LSS_INLINE _syscall1(int, setfsgid, gid_t, g) + LSS_INLINE _syscall1(int, setfsuid, uid_t, u) + LSS_INLINE _syscall1(int, setuid, uid_t, u) + LSS_INLINE _syscall1(int, setgid, gid_t, g) + LSS_INLINE _syscall2(int, setpgid, pid_t, p, + pid_t, g) + LSS_INLINE _syscall3(int, setpriority, int, a, + int, b, int, p) + LSS_INLINE _syscall3(int, setresgid, gid_t, r, + gid_t, e, gid_t, s) + LSS_INLINE _syscall3(int, setresuid, uid_t, r, + uid_t, e, uid_t, s) + LSS_INLINE _syscall2(int, setrlimit, int, r, + const struct kernel_rlimit*, l) + LSS_INLINE _syscall0(pid_t, setsid) + LSS_INLINE _syscall2(int, sigaltstack, const stack_t*, s, + const stack_t*, o) + #if defined(__NR_sigreturn) + LSS_INLINE _syscall1(int, sigreturn, unsigned long, u) + #endif + #if !defined(__aarch64__) + // The stat syscall has been deprecated on aarch64. We polyfill it below. + LSS_INLINE _syscall2(int, stat, const char*, f, + struct kernel_stat*, b) + #endif + LSS_INLINE _syscall2(int, statfs, const char*, f, + struct kernel_statfs*, b) + LSS_INLINE _syscall3(int, tgkill, pid_t, p, + pid_t, t, int, s) + LSS_INLINE _syscall2(int, tkill, pid_t, p, + int, s) + #if !defined(__aarch64__) + // The unlink syscall has been deprecated on aarch64. We polyfill it below. + LSS_INLINE _syscall1(int, unlink, const char*, f) + #endif + LSS_INLINE _syscall3(ssize_t, write, int, f, + const void *, b, size_t, c) + LSS_INLINE _syscall3(ssize_t, writev, int, f, + const struct kernel_iovec*, v, size_t, c) + #if defined(__NR_getcpu) + LSS_INLINE _syscall3(long, getcpu, unsigned *, cpu, + unsigned *, node, void *, unused) + #endif + #if defined(__x86_64__) || \ + (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32) + LSS_INLINE _syscall3(int, recvmsg, int, s, + struct kernel_msghdr*, m, int, f) + LSS_INLINE _syscall3(int, sendmsg, int, s, + const struct kernel_msghdr*, m, int, f) + LSS_INLINE _syscall6(int, sendto, int, s, + const void*, m, size_t, l, + int, f, + const struct kernel_sockaddr*, a, int, t) + LSS_INLINE _syscall2(int, shutdown, int, s, + int, h) + LSS_INLINE _syscall3(int, socket, int, d, + int, t, int, p) + LSS_INLINE _syscall4(int, socketpair, int, d, + int, t, int, p, int*, s) + #endif + #if defined(__x86_64__) + /* Need to make sure loff_t isn't truncated to 32-bits under x32. */ + LSS_INLINE int LSS_NAME(fallocate)(int f, int mode, loff_t offset, + loff_t len) { + LSS_BODY(4, int, fallocate, LSS_SYSCALL_ARG(f), LSS_SYSCALL_ARG(mode), + (uint64_t)(offset), (uint64_t)(len)); + } + + LSS_INLINE int LSS_NAME(getresgid32)(gid_t *rgid, + gid_t *egid, + gid_t *sgid) { + return LSS_NAME(getresgid)(rgid, egid, sgid); + } + + LSS_INLINE int LSS_NAME(getresuid32)(uid_t *ruid, + uid_t *euid, + uid_t *suid) { + return LSS_NAME(getresuid)(ruid, euid, suid); + } + + /* Need to make sure __off64_t isn't truncated to 32-bits under x32. */ + LSS_INLINE void* LSS_NAME(mmap)(void *s, size_t l, int p, int f, int d, + int64_t o) { + LSS_BODY(6, void*, mmap, LSS_SYSCALL_ARG(s), LSS_SYSCALL_ARG(l), + LSS_SYSCALL_ARG(p), LSS_SYSCALL_ARG(f), + LSS_SYSCALL_ARG(d), (uint64_t)(o)); + } + + LSS_INLINE _syscall4(int, newfstatat, int, d, + const char *, p, + struct kernel_stat*, b, int, f) + + LSS_INLINE int LSS_NAME(setfsgid32)(gid_t gid) { + return LSS_NAME(setfsgid)(gid); + } + + LSS_INLINE int LSS_NAME(setfsuid32)(uid_t uid) { + return LSS_NAME(setfsuid)(uid); + } + + LSS_INLINE int LSS_NAME(setresgid32)(gid_t rgid, gid_t egid, gid_t sgid) { + return LSS_NAME(setresgid)(rgid, egid, sgid); + } + + LSS_INLINE int LSS_NAME(setresuid32)(uid_t ruid, uid_t euid, uid_t suid) { + return LSS_NAME(setresuid)(ruid, euid, suid); + } + + LSS_INLINE int LSS_NAME(sigaction)(int signum, + const struct kernel_sigaction *act, + struct kernel_sigaction *oldact) { + /* On x86_64, the kernel requires us to always set our own + * SA_RESTORER in order to be able to return from a signal handler. + * This function must have a "magic" signature that the "gdb" + * (and maybe the kernel?) can recognize. + */ + if (act != NULL && !(act->sa_flags & SA_RESTORER)) { + struct kernel_sigaction a = *act; + a.sa_flags |= SA_RESTORER; + a.sa_restorer = LSS_NAME(restore_rt)(); + return LSS_NAME(rt_sigaction)(signum, &a, oldact, + (KERNEL_NSIG+7)/8); + } else { + return LSS_NAME(rt_sigaction)(signum, act, oldact, + (KERNEL_NSIG+7)/8); + } + } + + LSS_INLINE int LSS_NAME(sigpending)(struct kernel_sigset_t *set) { + return LSS_NAME(rt_sigpending)(set, (KERNEL_NSIG+7)/8); + } + + LSS_INLINE int LSS_NAME(sigprocmask)(int how, + const struct kernel_sigset_t *set, + struct kernel_sigset_t *oldset) { + return LSS_NAME(rt_sigprocmask)(how, set, oldset, (KERNEL_NSIG+7)/8); + } + + LSS_INLINE int LSS_NAME(sigsuspend)(const struct kernel_sigset_t *set) { + return LSS_NAME(rt_sigsuspend)(set, (KERNEL_NSIG+7)/8); + } + #endif + #if defined(__x86_64__) || defined(__ARM_ARCH_3__) || \ + defined(__ARM_EABI__) || defined(__aarch64__) || \ + (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI32) + LSS_INLINE _syscall4(pid_t, wait4, pid_t, p, + int*, s, int, o, + struct kernel_rusage*, r) + + LSS_INLINE pid_t LSS_NAME(waitpid)(pid_t pid, int *status, int options){ + return LSS_NAME(wait4)(pid, status, options, 0); + } + #endif + #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) + LSS_INLINE _syscall4(int, openat, int, d, const char *, p, int, f, int, m) + LSS_INLINE _syscall3(int, unlinkat, int, d, const char *, p, int, f) + #endif + #if defined(__i386__) || defined(__ARM_ARCH_3__) || defined(__ARM_EABI__) + #define __NR__getresgid32 __NR_getresgid32 + #define __NR__getresuid32 __NR_getresuid32 + #define __NR__setfsgid32 __NR_setfsgid32 + #define __NR__setfsuid32 __NR_setfsuid32 + #define __NR__setresgid32 __NR_setresgid32 + #define __NR__setresuid32 __NR_setresuid32 +#if defined(__ARM_EABI__) + LSS_INLINE _syscall2(int, ugetrlimit, int, r, + struct kernel_rlimit*, l) +#endif + LSS_INLINE _syscall3(int, _getresgid32, gid_t *, r, + gid_t *, e, gid_t *, s) + LSS_INLINE _syscall3(int, _getresuid32, uid_t *, r, + uid_t *, e, uid_t *, s) + LSS_INLINE _syscall1(int, _setfsgid32, gid_t, f) + LSS_INLINE _syscall1(int, _setfsuid32, uid_t, f) + LSS_INLINE _syscall3(int, _setresgid32, gid_t, r, + gid_t, e, gid_t, s) + LSS_INLINE _syscall3(int, _setresuid32, uid_t, r, + uid_t, e, uid_t, s) + + LSS_INLINE int LSS_NAME(getresgid32)(gid_t *rgid, + gid_t *egid, + gid_t *sgid) { + int rc; + if ((rc = LSS_NAME(_getresgid32)(rgid, egid, sgid)) < 0 && + LSS_ERRNO == ENOSYS) { + if ((rgid == NULL) || (egid == NULL) || (sgid == NULL)) { + return EFAULT; + } + // Clear the high bits first, since getresgid only sets 16 bits + *rgid = *egid = *sgid = 0; + rc = LSS_NAME(getresgid)(rgid, egid, sgid); + } + return rc; + } + + LSS_INLINE int LSS_NAME(getresuid32)(uid_t *ruid, + uid_t *euid, + uid_t *suid) { + int rc; + if ((rc = LSS_NAME(_getresuid32)(ruid, euid, suid)) < 0 && + LSS_ERRNO == ENOSYS) { + if ((ruid == NULL) || (euid == NULL) || (suid == NULL)) { + return EFAULT; + } + // Clear the high bits first, since getresuid only sets 16 bits + *ruid = *euid = *suid = 0; + rc = LSS_NAME(getresuid)(ruid, euid, suid); + } + return rc; + } + + LSS_INLINE int LSS_NAME(setfsgid32)(gid_t gid) { + int rc; + if ((rc = LSS_NAME(_setfsgid32)(gid)) < 0 && + LSS_ERRNO == ENOSYS) { + if ((unsigned int)gid & ~0xFFFFu) { + rc = EINVAL; + } else { + rc = LSS_NAME(setfsgid)(gid); + } + } + return rc; + } + + LSS_INLINE int LSS_NAME(setfsuid32)(uid_t uid) { + int rc; + if ((rc = LSS_NAME(_setfsuid32)(uid)) < 0 && + LSS_ERRNO == ENOSYS) { + if ((unsigned int)uid & ~0xFFFFu) { + rc = EINVAL; + } else { + rc = LSS_NAME(setfsuid)(uid); + } + } + return rc; + } + + LSS_INLINE int LSS_NAME(setresgid32)(gid_t rgid, gid_t egid, gid_t sgid) { + int rc; + if ((rc = LSS_NAME(_setresgid32)(rgid, egid, sgid)) < 0 && + LSS_ERRNO == ENOSYS) { + if ((unsigned int)rgid & ~0xFFFFu || + (unsigned int)egid & ~0xFFFFu || + (unsigned int)sgid & ~0xFFFFu) { + rc = EINVAL; + } else { + rc = LSS_NAME(setresgid)(rgid, egid, sgid); + } + } + return rc; + } + + LSS_INLINE int LSS_NAME(setresuid32)(uid_t ruid, uid_t euid, uid_t suid) { + int rc; + if ((rc = LSS_NAME(_setresuid32)(ruid, euid, suid)) < 0 && + LSS_ERRNO == ENOSYS) { + if ((unsigned int)ruid & ~0xFFFFu || + (unsigned int)euid & ~0xFFFFu || + (unsigned int)suid & ~0xFFFFu) { + rc = EINVAL; + } else { + rc = LSS_NAME(setresuid)(ruid, euid, suid); + } + } + return rc; + } + #endif + LSS_INLINE int LSS_NAME(sigemptyset)(struct kernel_sigset_t *set) { + memset(&set->sig, 0, sizeof(set->sig)); + return 0; + } + + LSS_INLINE int LSS_NAME(sigfillset)(struct kernel_sigset_t *set) { + memset(&set->sig, -1, sizeof(set->sig)); + return 0; + } + + LSS_INLINE int LSS_NAME(sigaddset)(struct kernel_sigset_t *set, + int signum) { + if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { + LSS_ERRNO = EINVAL; + return -1; + } else { + set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] + |= 1UL << ((signum - 1) % (8*sizeof(set->sig[0]))); + return 0; + } + } + + LSS_INLINE int LSS_NAME(sigdelset)(struct kernel_sigset_t *set, + int signum) { + if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { + LSS_ERRNO = EINVAL; + return -1; + } else { + set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] + &= ~(1UL << ((signum - 1) % (8*sizeof(set->sig[0])))); + return 0; + } + } + + LSS_INLINE int LSS_NAME(sigismember)(struct kernel_sigset_t *set, + int signum) { + if (signum < 1 || signum > (int)(8*sizeof(set->sig))) { + LSS_ERRNO = EINVAL; + return -1; + } else { + return !!(set->sig[(signum - 1)/(8*sizeof(set->sig[0]))] & + (1UL << ((signum - 1) % (8*sizeof(set->sig[0]))))); + } + } + #if defined(__i386__) || defined(__ARM_ARCH_3__) || \ + defined(__ARM_EABI__) || \ + (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) || defined(__PPC__) + #define __NR__sigaction __NR_sigaction + #define __NR__sigpending __NR_sigpending + #define __NR__sigprocmask __NR_sigprocmask + #define __NR__sigsuspend __NR_sigsuspend + #define __NR__socketcall __NR_socketcall + LSS_INLINE _syscall2(int, fstat64, int, f, + struct kernel_stat64 *, b) + LSS_INLINE _syscall5(int, _llseek, uint, fd, + unsigned long, hi, unsigned long, lo, + loff_t *, res, uint, wh) +#if !defined(__ARM_EABI__) + LSS_INLINE _syscall1(void*, mmap, void*, a) +#endif + LSS_INLINE _syscall6(void*, mmap2, void*, s, + size_t, l, int, p, + int, f, int, d, + off_t, o) + LSS_INLINE _syscall3(int, _sigaction, int, s, + const struct kernel_old_sigaction*, a, + struct kernel_old_sigaction*, o) + LSS_INLINE _syscall1(int, _sigpending, unsigned long*, s) + LSS_INLINE _syscall3(int, _sigprocmask, int, h, + const unsigned long*, s, + unsigned long*, o) + #ifdef __PPC__ + LSS_INLINE _syscall1(int, _sigsuspend, unsigned long, s) + #else + LSS_INLINE _syscall3(int, _sigsuspend, const void*, a, + int, b, + unsigned long, s) + #endif + LSS_INLINE _syscall2(int, stat64, const char *, p, + struct kernel_stat64 *, b) + + LSS_INLINE int LSS_NAME(sigaction)(int signum, + const struct kernel_sigaction *act, + struct kernel_sigaction *oldact) { + int old_errno = LSS_ERRNO; + int rc; + struct kernel_sigaction a; + if (act != NULL) { + a = *act; + #ifdef __i386__ + /* On i386, the kernel requires us to always set our own + * SA_RESTORER when using realtime signals. Otherwise, it does not + * know how to return from a signal handler. This function must have + * a "magic" signature that the "gdb" (and maybe the kernel?) can + * recognize. + * Apparently, a SA_RESTORER is implicitly set by the kernel, when + * using non-realtime signals. + * + * TODO: Test whether ARM needs a restorer + */ + if (!(a.sa_flags & SA_RESTORER)) { + a.sa_flags |= SA_RESTORER; + a.sa_restorer = (a.sa_flags & SA_SIGINFO) + ? LSS_NAME(restore_rt)() : LSS_NAME(restore)(); + } + #endif + } + rc = LSS_NAME(rt_sigaction)(signum, act ? &a : act, oldact, + (KERNEL_NSIG+7)/8); + if (rc < 0 && LSS_ERRNO == ENOSYS) { + struct kernel_old_sigaction oa, ooa, *ptr_a = &oa, *ptr_oa = &ooa; + if (!act) { + ptr_a = NULL; + } else { + oa.sa_handler_ = act->sa_handler_; + memcpy(&oa.sa_mask, &act->sa_mask, sizeof(oa.sa_mask)); + #ifndef __mips__ + oa.sa_restorer = act->sa_restorer; + #endif + oa.sa_flags = act->sa_flags; + } + if (!oldact) { + ptr_oa = NULL; + } + LSS_ERRNO = old_errno; + rc = LSS_NAME(_sigaction)(signum, ptr_a, ptr_oa); + if (rc == 0 && oldact) { + if (act) { + memcpy(oldact, act, sizeof(*act)); + } else { + memset(oldact, 0, sizeof(*oldact)); + } + oldact->sa_handler_ = ptr_oa->sa_handler_; + oldact->sa_flags = ptr_oa->sa_flags; + memcpy(&oldact->sa_mask, &ptr_oa->sa_mask, sizeof(ptr_oa->sa_mask)); + #ifndef __mips__ + oldact->sa_restorer = ptr_oa->sa_restorer; + #endif + } + } + return rc; + } + + LSS_INLINE int LSS_NAME(sigpending)(struct kernel_sigset_t *set) { + int old_errno = LSS_ERRNO; + int rc = LSS_NAME(rt_sigpending)(set, (KERNEL_NSIG+7)/8); + if (rc < 0 && LSS_ERRNO == ENOSYS) { + LSS_ERRNO = old_errno; + LSS_NAME(sigemptyset)(set); + rc = LSS_NAME(_sigpending)(&set->sig[0]); + } + return rc; + } + + LSS_INLINE int LSS_NAME(sigprocmask)(int how, + const struct kernel_sigset_t *set, + struct kernel_sigset_t *oldset) { + int olderrno = LSS_ERRNO; + int rc = LSS_NAME(rt_sigprocmask)(how, set, oldset, (KERNEL_NSIG+7)/8); + if (rc < 0 && LSS_ERRNO == ENOSYS) { + LSS_ERRNO = olderrno; + if (oldset) { + LSS_NAME(sigemptyset)(oldset); + } + rc = LSS_NAME(_sigprocmask)(how, + set ? &set->sig[0] : NULL, + oldset ? &oldset->sig[0] : NULL); + } + return rc; + } + + LSS_INLINE int LSS_NAME(sigsuspend)(const struct kernel_sigset_t *set) { + int olderrno = LSS_ERRNO; + int rc = LSS_NAME(rt_sigsuspend)(set, (KERNEL_NSIG+7)/8); + if (rc < 0 && LSS_ERRNO == ENOSYS) { + LSS_ERRNO = olderrno; + rc = LSS_NAME(_sigsuspend)( + #ifndef __PPC__ + set, 0, + #endif + set->sig[0]); + } + return rc; + } + #endif + #if defined(__PPC__) + #undef LSS_SC_LOADARGS_0 + #define LSS_SC_LOADARGS_0(dummy...) + #undef LSS_SC_LOADARGS_1 + #define LSS_SC_LOADARGS_1(arg1) \ + __sc_4 = (unsigned long) (arg1) + #undef LSS_SC_LOADARGS_2 + #define LSS_SC_LOADARGS_2(arg1, arg2) \ + LSS_SC_LOADARGS_1(arg1); \ + __sc_5 = (unsigned long) (arg2) + #undef LSS_SC_LOADARGS_3 + #define LSS_SC_LOADARGS_3(arg1, arg2, arg3) \ + LSS_SC_LOADARGS_2(arg1, arg2); \ + __sc_6 = (unsigned long) (arg3) + #undef LSS_SC_LOADARGS_4 + #define LSS_SC_LOADARGS_4(arg1, arg2, arg3, arg4) \ + LSS_SC_LOADARGS_3(arg1, arg2, arg3); \ + __sc_7 = (unsigned long) (arg4) + #undef LSS_SC_LOADARGS_5 + #define LSS_SC_LOADARGS_5(arg1, arg2, arg3, arg4, arg5) \ + LSS_SC_LOADARGS_4(arg1, arg2, arg3, arg4); \ + __sc_8 = (unsigned long) (arg5) + #undef LSS_SC_BODY + #define LSS_SC_BODY(nr, type, opt, args...) \ + long __sc_ret, __sc_err; \ + { \ + register unsigned long __sc_0 __asm__ ("r0") = __NR_socketcall; \ + register unsigned long __sc_3 __asm__ ("r3") = opt; \ + register unsigned long __sc_4 __asm__ ("r4"); \ + register unsigned long __sc_5 __asm__ ("r5"); \ + register unsigned long __sc_6 __asm__ ("r6"); \ + register unsigned long __sc_7 __asm__ ("r7"); \ + register unsigned long __sc_8 __asm__ ("r8"); \ + LSS_SC_LOADARGS_##nr(args); \ + __asm__ __volatile__ \ + ("stwu 1, -48(1)\n\t" \ + "stw 4, 20(1)\n\t" \ + "stw 5, 24(1)\n\t" \ + "stw 6, 28(1)\n\t" \ + "stw 7, 32(1)\n\t" \ + "stw 8, 36(1)\n\t" \ + "addi 4, 1, 20\n\t" \ + "sc\n\t" \ + "mfcr %0" \ + : "=&r" (__sc_0), \ + "=&r" (__sc_3), "=&r" (__sc_4), \ + "=&r" (__sc_5), "=&r" (__sc_6), \ + "=&r" (__sc_7), "=&r" (__sc_8) \ + : LSS_ASMINPUT_##nr \ + : "cr0", "ctr", "memory"); \ + __sc_ret = __sc_3; \ + __sc_err = __sc_0; \ + } \ + LSS_RETURN(type, __sc_ret, __sc_err) + + LSS_INLINE ssize_t LSS_NAME(recvmsg)(int s,struct kernel_msghdr *msg, + int flags){ + LSS_SC_BODY(3, ssize_t, 17, s, msg, flags); + } + + LSS_INLINE ssize_t LSS_NAME(sendmsg)(int s, + const struct kernel_msghdr *msg, + int flags) { + LSS_SC_BODY(3, ssize_t, 16, s, msg, flags); + } + + // TODO(csilvers): why is this ifdef'ed out? +#if 0 + LSS_INLINE ssize_t LSS_NAME(sendto)(int s, const void *buf, size_t len, + int flags, + const struct kernel_sockaddr *to, + unsigned int tolen) { + LSS_BODY(6, ssize_t, 11, s, buf, len, flags, to, tolen); + } +#endif + + LSS_INLINE int LSS_NAME(shutdown)(int s, int how) { + LSS_SC_BODY(2, int, 13, s, how); + } + + LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) { + LSS_SC_BODY(3, int, 1, domain, type, protocol); + } + + LSS_INLINE int LSS_NAME(socketpair)(int d, int type, int protocol, + int sv[2]) { + LSS_SC_BODY(4, int, 8, d, type, protocol, sv); + } + #endif + #if defined(__ARM_EABI__) || defined (__aarch64__) + LSS_INLINE _syscall3(ssize_t, recvmsg, int, s, struct kernel_msghdr*, msg, + int, flags) + LSS_INLINE _syscall3(ssize_t, sendmsg, int, s, const struct kernel_msghdr*, + msg, int, flags) + LSS_INLINE _syscall6(ssize_t, sendto, int, s, const void*, buf, size_t,len, + int, flags, const struct kernel_sockaddr*, to, + unsigned int, tolen) + LSS_INLINE _syscall2(int, shutdown, int, s, int, how) + LSS_INLINE _syscall3(int, socket, int, domain, int, type, int, protocol) + LSS_INLINE _syscall4(int, socketpair, int, d, int, type, int, protocol, + int*, sv) + #endif + #if defined(__i386__) || defined(__ARM_ARCH_3__) || \ + (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) + #define __NR__socketcall __NR_socketcall + LSS_INLINE _syscall2(int, _socketcall, int, c, + va_list, a) + LSS_INLINE int LSS_NAME(socketcall)(int op, ...) { + int rc; + va_list ap; + va_start(ap, op); + rc = LSS_NAME(_socketcall)(op, ap); + va_end(ap); + return rc; + } + + LSS_INLINE ssize_t LSS_NAME(recvmsg)(int s,struct kernel_msghdr *msg, + int flags){ + return (ssize_t)LSS_NAME(socketcall)(17, s, msg, flags); + } + + LSS_INLINE ssize_t LSS_NAME(sendmsg)(int s, + const struct kernel_msghdr *msg, + int flags) { + return (ssize_t)LSS_NAME(socketcall)(16, s, msg, flags); + } + + LSS_INLINE ssize_t LSS_NAME(sendto)(int s, const void *buf, size_t len, + int flags, + const struct kernel_sockaddr *to, + unsigned int tolen) { + return (ssize_t)LSS_NAME(socketcall)(11, s, buf, len, flags, to, tolen); + } + + LSS_INLINE int LSS_NAME(shutdown)(int s, int how) { + return LSS_NAME(socketcall)(13, s, how); + } + + LSS_INLINE int LSS_NAME(socket)(int domain, int type, int protocol) { + return LSS_NAME(socketcall)(1, domain, type, protocol); + } + + LSS_INLINE int LSS_NAME(socketpair)(int d, int type, int protocol, + int sv[2]) { + return LSS_NAME(socketcall)(8, d, type, protocol, sv); + } + #endif + #if defined(__i386__) || defined(__PPC__) + LSS_INLINE _syscall4(int, fstatat64, int, d, + const char *, p, + struct kernel_stat64 *, b, int, f) + #endif + #if defined(__i386__) || defined(__PPC__) || \ + (defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI32) + LSS_INLINE _syscall3(pid_t, waitpid, pid_t, p, + int*, s, int, o) + #endif + #if defined(__mips__) + /* sys_pipe() on MIPS has non-standard calling conventions, as it returns + * both file handles through CPU registers. + */ + LSS_INLINE int LSS_NAME(pipe)(int *p) { + register unsigned long __v0 __asm__("$2") = __NR_pipe; + register unsigned long __v1 __asm__("$3"); + register unsigned long __r7 __asm__("$7"); + __asm__ __volatile__ ("syscall\n" + : "+r"(__v0), "=r"(__v1), "=r" (__r7) + : "0"(__v0) + : "$8", "$9", "$10", "$11", "$12", + "$13", "$14", "$15", "$24", "$25", "memory"); + if (__r7) { + unsigned long __errnovalue = __v0; + LSS_ERRNO = __errnovalue; + return -1; + } else { + p[0] = __v0; + p[1] = __v1; + return 0; + } + } + #elif !defined(__aarch64__) + // The unlink syscall has been deprecated on aarch64. We polyfill it below. + LSS_INLINE _syscall1(int, pipe, int *, p) + #endif + /* TODO(csilvers): see if ppc can/should support this as well */ + #if defined(__i386__) || defined(__ARM_ARCH_3__) || \ + defined(__ARM_EABI__) || \ + (defined(__mips__) && _MIPS_SIM != _MIPS_SIM_ABI64) + #define __NR__statfs64 __NR_statfs64 + #define __NR__fstatfs64 __NR_fstatfs64 + LSS_INLINE _syscall3(int, _statfs64, const char*, p, + size_t, s,struct kernel_statfs64*, b) + LSS_INLINE _syscall3(int, _fstatfs64, int, f, + size_t, s,struct kernel_statfs64*, b) + LSS_INLINE int LSS_NAME(statfs64)(const char *p, + struct kernel_statfs64 *b) { + return LSS_NAME(_statfs64)(p, sizeof(*b), b); + } + LSS_INLINE int LSS_NAME(fstatfs64)(int f,struct kernel_statfs64 *b) { + return LSS_NAME(_fstatfs64)(f, sizeof(*b), b); + } + #endif + + LSS_INLINE int LSS_NAME(execv)(const char *path, const char *const argv[]) { + extern char **environ; + return LSS_NAME(execve)(path, argv, (const char *const *)environ); + } + + LSS_INLINE pid_t LSS_NAME(gettid)(void) { + pid_t tid = LSS_NAME(_gettid)(); + if (tid != -1) { + return tid; + } + return LSS_NAME(getpid)(); + } + + LSS_INLINE void *LSS_NAME(mremap)(void *old_address, size_t old_size, + size_t new_size, int flags, ...) { + va_list ap; + void *new_address, *rc; + va_start(ap, flags); + new_address = va_arg(ap, void *); + rc = LSS_NAME(_mremap)(old_address, old_size, new_size, + flags, new_address); + va_end(ap); + return rc; + } + + LSS_INLINE int LSS_NAME(ptrace_detach)(pid_t pid) { + /* PTRACE_DETACH can sometimes forget to wake up the tracee and it + * then sends job control signals to the real parent, rather than to + * the tracer. We reduce the risk of this happening by starting a + * whole new time slice, and then quickly sending a SIGCONT signal + * right after detaching from the tracee. + * + * We use tkill to ensure that we only issue a wakeup for the thread being + * detached. Large multi threaded apps can take a long time in the kernel + * processing SIGCONT. + */ + int rc, err; + LSS_NAME(sched_yield)(); + rc = LSS_NAME(ptrace)(PTRACE_DETACH, pid, (void *)0, (void *)0); + err = LSS_ERRNO; + LSS_NAME(tkill)(pid, SIGCONT); + /* Old systems don't have tkill */ + if (LSS_ERRNO == ENOSYS) + LSS_NAME(kill)(pid, SIGCONT); + LSS_ERRNO = err; + return rc; + } + + LSS_INLINE int LSS_NAME(raise)(int sig) { + return LSS_NAME(kill)(LSS_NAME(getpid)(), sig); + } + + LSS_INLINE int LSS_NAME(setpgrp)(void) { + return LSS_NAME(setpgid)(0, 0); + } + + LSS_INLINE int LSS_NAME(sysconf)(int name) { + extern int __getpagesize(void); + switch (name) { + case _SC_OPEN_MAX: { + struct kernel_rlimit limit; +#if defined(__ARM_EABI__) + return LSS_NAME(ugetrlimit)(RLIMIT_NOFILE, &limit) < 0 + ? 8192 : limit.rlim_cur; +#else + return LSS_NAME(getrlimit)(RLIMIT_NOFILE, &limit) < 0 + ? 8192 : limit.rlim_cur; +#endif + } + case _SC_PAGESIZE: + return __getpagesize(); + default: + LSS_ERRNO = ENOSYS; + return -1; + } + } + #if defined(__x86_64__) + /* Need to make sure loff_t isn't truncated to 32-bits under x32. */ + LSS_INLINE ssize_t LSS_NAME(pread64)(int f, void *b, size_t c, loff_t o) { + LSS_BODY(4, ssize_t, pread64, LSS_SYSCALL_ARG(f), LSS_SYSCALL_ARG(b), + LSS_SYSCALL_ARG(c), (uint64_t)(o)); + } + + LSS_INLINE ssize_t LSS_NAME(pwrite64)(int f, const void *b, size_t c, + loff_t o) { + LSS_BODY(4, ssize_t, pwrite64, LSS_SYSCALL_ARG(f), LSS_SYSCALL_ARG(b), + LSS_SYSCALL_ARG(c), (uint64_t)(o)); + } + + LSS_INLINE int LSS_NAME(readahead)(int f, loff_t o, unsigned c) { + LSS_BODY(3, int, readahead, LSS_SYSCALL_ARG(f), (uint64_t)(o), + LSS_SYSCALL_ARG(c)); + } + #elif defined(__mips__) && _MIPS_SIM == _MIPS_SIM_ABI64 + LSS_INLINE _syscall4(ssize_t, pread64, int, f, + void *, b, size_t, c, + loff_t, o) + LSS_INLINE _syscall4(ssize_t, pwrite64, int, f, + const void *, b, size_t, c, + loff_t, o) + LSS_INLINE _syscall3(int, readahead, int, f, + loff_t, o, unsigned, c) + #else + #define __NR__pread64 __NR_pread64 + #define __NR__pwrite64 __NR_pwrite64 + #define __NR__readahead __NR_readahead + #if defined(__ARM_EABI__) || defined(__mips__) + /* On ARM and MIPS, a 64-bit parameter has to be in an even-odd register + * pair. Hence these calls ignore their fourth argument (r3) so that their + * fifth and sixth make such a pair (r4,r5). + */ + #define LSS_LLARG_PAD 0, + LSS_INLINE _syscall6(ssize_t, _pread64, int, f, + void *, b, size_t, c, + unsigned, skip, unsigned, o1, unsigned, o2) + LSS_INLINE _syscall6(ssize_t, _pwrite64, int, f, + const void *, b, size_t, c, + unsigned, skip, unsigned, o1, unsigned, o2) + LSS_INLINE _syscall5(int, _readahead, int, f, + unsigned, skip, + unsigned, o1, unsigned, o2, size_t, c) + #else + #define LSS_LLARG_PAD + LSS_INLINE _syscall5(ssize_t, _pread64, int, f, + void *, b, size_t, c, unsigned, o1, + unsigned, o2) + LSS_INLINE _syscall5(ssize_t, _pwrite64, int, f, + const void *, b, size_t, c, unsigned, o1, + long, o2) + LSS_INLINE _syscall4(int, _readahead, int, f, + unsigned, o1, unsigned, o2, size_t, c) + #endif + /* We force 64bit-wide parameters onto the stack, then access each + * 32-bit component individually. This guarantees that we build the + * correct parameters independent of the native byte-order of the + * underlying architecture. + */ + LSS_INLINE ssize_t LSS_NAME(pread64)(int fd, void *buf, size_t count, + loff_t off) { + union { loff_t off; unsigned arg[2]; } o = { off }; + return LSS_NAME(_pread64)(fd, buf, count, + LSS_LLARG_PAD o.arg[0], o.arg[1]); + } + LSS_INLINE ssize_t LSS_NAME(pwrite64)(int fd, const void *buf, + size_t count, loff_t off) { + union { loff_t off; unsigned arg[2]; } o = { off }; + return LSS_NAME(_pwrite64)(fd, buf, count, + LSS_LLARG_PAD o.arg[0], o.arg[1]); + } + LSS_INLINE int LSS_NAME(readahead)(int fd, loff_t off, int len) { + union { loff_t off; unsigned arg[2]; } o = { off }; + return LSS_NAME(_readahead)(fd, LSS_LLARG_PAD o.arg[0], o.arg[1], len); + } + #endif +#endif + +#if defined(__aarch64__) + LSS_INLINE _syscall3(int, dup3, int, s, int, d, int, f) + LSS_INLINE _syscall6(void *, mmap, void *, addr, size_t, length, int, prot, + int, flags, int, fd, int64_t, offset) + LSS_INLINE _syscall4(int, newfstatat, int, dirfd, const char *, pathname, + struct kernel_stat *, buf, int, flags) + LSS_INLINE _syscall2(int, pipe2, int *, pipefd, int, flags) + LSS_INLINE _syscall5(int, ppoll, struct kernel_pollfd *, u, + unsigned int, n, const struct kernel_timespec *, t, + const kernel_sigset_t *, sigmask, size_t, s) + LSS_INLINE _syscall4(int, readlinkat, int, d, const char *, p, char *, b, + size_t, s) +#endif + +/* + * Polyfills for deprecated syscalls. + */ + +#if defined(__aarch64__) + LSS_INLINE int LSS_NAME(dup2)(int s, int d) { + return LSS_NAME(dup3)(s, d, 0); + } + + LSS_INLINE int LSS_NAME(open)(const char *pathname, int flags, int mode) { + return LSS_NAME(openat)(AT_FDCWD, pathname, flags, mode); + } + + LSS_INLINE int LSS_NAME(unlink)(const char *pathname) { + return LSS_NAME(unlinkat)(AT_FDCWD, pathname, 0); + } + + LSS_INLINE int LSS_NAME(readlink)(const char *pathname, char *buffer, + size_t size) { + return LSS_NAME(readlinkat)(AT_FDCWD, pathname, buffer, size); + } + + LSS_INLINE pid_t LSS_NAME(pipe)(int *pipefd) { + return LSS_NAME(pipe2)(pipefd, 0); + } + + LSS_INLINE int LSS_NAME(poll)(struct kernel_pollfd *fds, unsigned int nfds, + int timeout) { + struct kernel_timespec timeout_ts; + struct kernel_timespec *timeout_ts_p = NULL; + + if (timeout >= 0) { + timeout_ts.tv_sec = timeout / 1000; + timeout_ts.tv_nsec = (timeout % 1000) * 1000000; + timeout_ts_p = &timeout_ts; + } + return LSS_NAME(ppoll)(fds, nfds, timeout_ts_p, NULL, 0); + } + + LSS_INLINE int LSS_NAME(stat)(const char *pathname, + struct kernel_stat *buf) { + return LSS_NAME(newfstatat)(AT_FDCWD, pathname, buf, 0); + } + + LSS_INLINE pid_t LSS_NAME(fork)(void) { + // No fork syscall on aarch64 - implement by means of the clone syscall. + // Note that this does not reset glibc's cached view of the PID/TID, so + // some glibc interfaces might go wrong in the forked subprocess. + int flags = SIGCHLD; + void *child_stack = NULL; + void *parent_tidptr = NULL; + void *newtls = NULL; + void *child_tidptr = NULL; + + LSS_REG(0, flags); + LSS_REG(1, child_stack); + LSS_REG(2, parent_tidptr); + LSS_REG(3, newtls); + LSS_REG(4, child_tidptr); + LSS_BODY(pid_t, clone, "r"(__r0), "r"(__r1), "r"(__r2), "r"(__r3), + "r"(__r4)); + } +#endif + +#ifdef __ANDROID__ + /* These restore the original values of these macros saved by the + * corresponding #pragma push_macro near the top of this file. */ +# pragma pop_macro("stat64") +# pragma pop_macro("fstat64") +# pragma pop_macro("lstat64") +#endif + +#if defined(__cplusplus) && !defined(SYS_CPLUSPLUS) +} +#endif + +#endif +#endif diff --git a/TMessagesProj/jni/ffmpeg/COPYING.GPLv2 b/TMessagesProj/jni/ffmpeg/COPYING.GPLv2 new file mode 100644 index 00000000..d159169d --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/COPYING.GPLv2 @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/TMessagesProj/jni/ffmpeg/COPYING.GPLv3 b/TMessagesProj/jni/ffmpeg/COPYING.GPLv3 new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/COPYING.GPLv3 @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/TMessagesProj/jni/ffmpeg/COPYING.LGPLv2.1 b/TMessagesProj/jni/ffmpeg/COPYING.LGPLv2.1 new file mode 100644 index 00000000..58af0d37 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/COPYING.LGPLv2.1 @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/TMessagesProj/jni/ffmpeg/COPYING.LGPLv3 b/TMessagesProj/jni/ffmpeg/COPYING.LGPLv3 new file mode 100644 index 00000000..65c5ca88 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/COPYING.LGPLv3 @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/TMessagesProj/jni/ffmpeg/CREDITS b/TMessagesProj/jni/ffmpeg/CREDITS new file mode 100644 index 00000000..e29f0b85 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/CREDITS @@ -0,0 +1,6 @@ +See the Git history of the project (git://source.ffmpeg.org/ffmpeg) to +get the names of people who have contributed to FFmpeg. + +To check the log, you can type the command "git log" in the FFmpeg +source directory, or browse the online repository at +http://source.ffmpeg.org. diff --git a/TMessagesProj/jni/ffmpeg/LICENSE.md b/TMessagesProj/jni/ffmpeg/LICENSE.md new file mode 100644 index 00000000..4c4a8453 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/LICENSE.md @@ -0,0 +1,114 @@ +#FFmpeg: + +Most files in FFmpeg are under the GNU Lesser General Public License version 2.1 +or later (LGPL v2.1+). Read the file `COPYING.LGPLv2.1` for details. Some other +files have MIT/X11/BSD-style licenses. In combination the LGPL v2.1+ applies to +FFmpeg. + +Some optional parts of FFmpeg are licensed under the GNU General Public License +version 2 or later (GPL v2+). See the file `COPYING.GPLv2` for details. None of +these parts are used by default, you have to explicitly pass `--enable-gpl` to +configure to activate them. In this case, FFmpeg's license changes to GPL v2+. + +Specifically, the GPL parts of FFmpeg are: + +- libpostproc +- optional x86 optimizations in the files + - `libavcodec/x86/flac_dsp_gpl.asm` + - `libavcodec/x86/idct_mmx.c` + - `libavfilter/x86/vf_removegrain.asm` +- libutvideo encoding/decoding wrappers in + `libavcodec/libutvideo*.cpp` +- the X11 grabber in `libavdevice/x11grab.c` +- the swresample test app in + `libswresample/swresample-test.c` +- the `texi2pod.pl` tool +- the following filters in libavfilter: + - `f_ebur128.c` + - `vf_blackframe.c` + - `vf_boxblur.c` + - `vf_colormatrix.c` + - `vf_cover_rect.c` + - `vf_cropdetect.c` + - `vf_delogo.c` + - `vf_eq.c` + - `vf_find_rect.c` + - `vf_fspp.c` + - `vf_geq.c` + - `vf_histeq.c` + - `vf_hqdn3d.c` + - `vf_interlace.c` + - `vf_kerndeint.c` + - `vf_mcdeint.c` + - `vf_mpdecimate.c` + - `vf_owdenoise.c` + - `vf_perspective.c` + - `vf_phase.c` + - `vf_pp.c` + - `vf_pp7.c` + - `vf_pullup.c` + - `vf_sab.c` + - `vf_smartblur.c` + - `vf_repeatfields.c` + - `vf_spp.c` + - `vf_stereo3d.c` + - `vf_super2xsai.c` + - `vf_tinterlace.c` + - `vf_uspp.c` + - `vsrc_mptestsrc.c` + +Should you, for whatever reason, prefer to use version 3 of the (L)GPL, then +the configure parameter `--enable-version3` will activate this licensing option +for you. Read the file `COPYING.LGPLv3` or, if you have enabled GPL parts, +`COPYING.GPLv3` to learn the exact legal terms that apply in this case. + +There are a handful of files under other licensing terms, namely: + +* The files `libavcodec/jfdctfst.c`, `libavcodec/jfdctint_template.c` and + `libavcodec/jrevdct.c` are taken from libjpeg, see the top of the files for + licensing details. Specifically note that you must credit the IJG in the + documentation accompanying your program if you only distribute executables. + You must also indicate any changes including additions and deletions to + those three files in the documentation. +* `tests/reference.pnm` is under the expat license. + + +external libraries +================== + +FFmpeg can be combined with a number of external libraries, which sometimes +affect the licensing of binaries resulting from the combination. + +compatible libraries +-------------------- + +The following libraries are under GPL: +- frei0r +- libcdio +- librubberband +- libutvideo +- libvidstab +- libx264 +- libx265 +- libxavs +- libxvid + +When combining them with FFmpeg, FFmpeg needs to be licensed as GPL as well by +passing `--enable-gpl` to configure. + +The OpenCORE and VisualOn libraries are under the Apache License 2.0. That +license is incompatible with the LGPL v2.1 and the GPL v2, but not with +version 3 of those licenses. So to combine these libraries with FFmpeg, the +license version needs to be upgraded by passing `--enable-version3` to configure. + +incompatible libraries +---------------------- + +The Fraunhofer AAC library, FAAC and aacplus are under licenses which +are incompatible with the GPLv2 and v3. We do not know for certain if their +licenses are compatible with the LGPL. +If you wish to enable these libraries, pass `--enable-nonfree` to configure. +But note that if you enable any of these libraries the resulting binary will +be under a complex license mix that is more restrictive than the LGPL and that +may result in additional obligations. It is possible that these +restrictions cause the resulting binary to be unredistributeable. diff --git a/TMessagesProj/jni/ffmpeg/README.md b/TMessagesProj/jni/ffmpeg/README.md new file mode 100644 index 00000000..24191919 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/README.md @@ -0,0 +1,49 @@ +FFmpeg README +============= + +FFmpeg is a collection of libraries and tools to process multimedia content +such as audio, video, subtitles and related metadata. + +## Libraries + +* `libavcodec` provides implementation of a wider range of codecs. +* `libavformat` implements streaming protocols, container formats and basic I/O access. +* `libavutil` includes hashers, decompressors and miscellaneous utility functions. +* `libavfilter` provides a mean to alter decoded Audio and Video through chain of filters. +* `libavdevice` provides an abstraction to access capture and playback devices. +* `libswresample` implements audio mixing and resampling routines. +* `libswscale` implements color conversion and scaling routines. + +## Tools + +* [ffmpeg](https://ffmpeg.org/ffmpeg.html) is a command line toolbox to + manipulate, convert and stream multimedia content. +* [ffplay](https://ffmpeg.org/ffplay.html) is a minimalistic multimedia player. +* [ffprobe](https://ffmpeg.org/ffprobe.html) is a simple analysis tool to inspect + multimedia content. +* [ffserver](https://ffmpeg.org/ffserver.html) is a multimedia streaming server + for live broadcasts. +* Additional small tools such as `aviocat`, `ismindex` and `qt-faststart`. + +## Documentation + +The offline documentation is available in the **doc/** directory. + +The online documentation is available in the main [website](https://ffmpeg.org) +and in the [wiki](https://trac.ffmpeg.org). + +### Examples + +Coding examples are available in the **doc/examples** directory. + +## License + +FFmpeg codebase is mainly LGPL-licensed with optional components licensed under +GPL. Please refer to the LICENSE file for detailed information. + +## Contributing + +Patches should be submitted to the ffmpeg-devel mailing list using +`git format-patch` or `git send-email`. Github pull requests should be +avoided because they are not part of our review process. Few developers +follow pull requests so they will likely be ignored. diff --git a/TMessagesProj/jni/ffmpeg/armv5te/libavcodec.a b/TMessagesProj/jni/ffmpeg/armv5te/libavcodec.a new file mode 100644 index 00000000..35b5dbdb Binary files /dev/null and b/TMessagesProj/jni/ffmpeg/armv5te/libavcodec.a differ diff --git a/TMessagesProj/jni/ffmpeg/armv5te/libavformat.a b/TMessagesProj/jni/ffmpeg/armv5te/libavformat.a new file mode 100644 index 00000000..a93225ee Binary files /dev/null and b/TMessagesProj/jni/ffmpeg/armv5te/libavformat.a differ diff --git a/TMessagesProj/jni/ffmpeg/armv5te/libavutil.a b/TMessagesProj/jni/ffmpeg/armv5te/libavutil.a new file mode 100644 index 00000000..4131c6c5 Binary files /dev/null and b/TMessagesProj/jni/ffmpeg/armv5te/libavutil.a differ diff --git a/TMessagesProj/jni/ffmpeg/armv7-a/libavcodec.a b/TMessagesProj/jni/ffmpeg/armv7-a/libavcodec.a new file mode 100644 index 00000000..68bc1ddd Binary files /dev/null and b/TMessagesProj/jni/ffmpeg/armv7-a/libavcodec.a differ diff --git a/TMessagesProj/jni/ffmpeg/armv7-a/libavformat.a b/TMessagesProj/jni/ffmpeg/armv7-a/libavformat.a new file mode 100644 index 00000000..080afa5e Binary files /dev/null and b/TMessagesProj/jni/ffmpeg/armv7-a/libavformat.a differ diff --git a/TMessagesProj/jni/ffmpeg/armv7-a/libavutil.a b/TMessagesProj/jni/ffmpeg/armv7-a/libavutil.a new file mode 100644 index 00000000..7136db32 Binary files /dev/null and b/TMessagesProj/jni/ffmpeg/armv7-a/libavutil.a differ diff --git a/TMessagesProj/jni/ffmpeg/build_ffmpeg_android.sh b/TMessagesProj/jni/ffmpeg/build_ffmpeg_android.sh new file mode 100644 index 00000000..7703afa8 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/build_ffmpeg_android.sh @@ -0,0 +1,106 @@ +#!/bin/bash +#apply fix http://permalink.gmane.org/gmane.comp.video.ffmpeg.devel/203198 + +function build_one { + +echo "Cleaning..." +make clean + +echo "Configuring..." + +./configure \ +--cc=$CC \ +--nm=$NM \ +--enable-stripping \ +--arch=$ARCH \ +--cpu=$CPU \ +--target-os=linux \ +--enable-cross-compile \ +--yasmexe=$NDK/prebuilt/darwin-x86_64/bin/yasm \ +--prefix=$PREFIX \ +--enable-pic \ +--disable-shared \ +--enable-static \ +--cross-prefix=$CROSS_PREFIX \ +--sysroot=$PLATFORM \ +--extra-cflags="-Os -DANDROID $OPTIMIZE_CFLAGS -fPIE -pie --static" \ +--extra-ldflags="-Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib -lc -lm -ldl" \ +--extra-libs="-lgcc" \ +\ +--enable-version3 \ +--enable-gpl \ +\ +--disable-doc \ +--disable-avx \ +\ +--disable-everything \ +--disable-network \ +--disable-zlib \ +--disable-avfilter \ +--disable-avdevice \ +--disable-postproc \ +--disable-debug \ +--disable-programs \ +--disable-network \ +\ +--enable-pthreads \ +--enable-protocol=file \ +--enable-decoder=h264 \ +--enable-decoder=gif \ +--enable-demuxer=mov \ +--enable-demuxer=gif \ +--enable-hwaccels \ +--enable-runtime-cpudetect \ +--enable-asm \ +$ADDITIONAL_CONFIGURE_FLAG + +#echo "continue?" +#read +make -j8 install + +} + +NDK=/Applications/sdk/ndk-bundle + +#arm platform +PLATFORM=$NDK/platforms/android-9/arch-arm +PREBUILT=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/darwin-x86_64 +LD=$PREBUILT/bin/arm-linux-androideabi-ld +AR=$PREBUILT/bin/arm-linux-androideabi-ar +NM=$PREBUILT/bin/arm-linux-androideabi-nm +GCCLIB=$PREBUILT/lib/gcc/arm-linux-androideabi/4.8/libgcc.a +ARCH=arm +CC=$PREBUILT/bin/arm-linux-androideabi-gcc +CROSS_PREFIX=$PREBUILT/bin/arm-linux-androideabi- + +#arm v5 +CPU=armv5te +OPTIMIZE_CFLAGS="-marm -march=$CPU" +PREFIX=./android/$CPU +ADDITIONAL_CONFIGURE_FLAG="--disable-armv6 --disable-armv6t2 --disable-vfp --disable-neon" +build_one + +#arm v7n +CPU=armv7-a +OPTIMIZE_CFLAGS="-marm -march=$CPU" +PREFIX=./android/$CPU +ADDITIONAL_CONFIGURE_FLAG=--enable-neon +build_one + +#x86 platform +PLATFORM=$NDK/platforms/android-9/arch-x86 +PREBUILT=$NDK/toolchains/x86-4.8/prebuilt/darwin-x86_64 +LD=$PREBUILT/bin/i686-linux-android-ld +AR=$PREBUILT/bin/i686-linux-android-ar +NM=$PREBUILT/bin/i686-linux-android-nm +GCCLIB=$PREBUILT/lib/gcc/i686-linux-android/4.8/libgcc.a +ARCH=x86 +CC=$PREBUILT/bin/i686-linux-android-gcc +CROSS_PREFIX=$PREBUILT/bin/i686-linux-android- + +CPU=i686 +OPTIMIZE_CFLAGS="-march=$CPU" +PREFIX=./android/$CPU +ADDITIONAL_CONFIGURE_FLAG="--disable-mmx --disable-yasm" +build_one + diff --git a/TMessagesProj/jni/ffmpeg/i686/libavcodec.a b/TMessagesProj/jni/ffmpeg/i686/libavcodec.a new file mode 100644 index 00000000..4fbf65ca Binary files /dev/null and b/TMessagesProj/jni/ffmpeg/i686/libavcodec.a differ diff --git a/TMessagesProj/jni/ffmpeg/i686/libavformat.a b/TMessagesProj/jni/ffmpeg/i686/libavformat.a new file mode 100644 index 00000000..30e6bfad Binary files /dev/null and b/TMessagesProj/jni/ffmpeg/i686/libavformat.a differ diff --git a/TMessagesProj/jni/ffmpeg/i686/libavutil.a b/TMessagesProj/jni/ffmpeg/i686/libavutil.a new file mode 100644 index 00000000..9c0e0f86 Binary files /dev/null and b/TMessagesProj/jni/ffmpeg/i686/libavutil.a differ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/avcodec.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/avcodec.h new file mode 100644 index 00000000..f365775f --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/avcodec.h @@ -0,0 +1,5418 @@ +/* + * copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AVCODEC_H +#define AVCODEC_AVCODEC_H + +/** + * @file + * @ingroup libavc + * Libavcodec external API header + */ + +#include +#include "libavutil/samplefmt.h" +#include "libavutil/attributes.h" +#include "libavutil/avutil.h" +#include "libavutil/buffer.h" +#include "libavutil/cpu.h" +#include "libavutil/channel_layout.h" +#include "libavutil/dict.h" +#include "libavutil/frame.h" +#include "libavutil/log.h" +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" + +#include "version.h" + +/** + * @defgroup libavc Encoding/Decoding Library + * @{ + * + * @defgroup lavc_decoding Decoding + * @{ + * @} + * + * @defgroup lavc_encoding Encoding + * @{ + * @} + * + * @defgroup lavc_codec Codecs + * @{ + * @defgroup lavc_codec_native Native Codecs + * @{ + * @} + * @defgroup lavc_codec_wrappers External library wrappers + * @{ + * @} + * @defgroup lavc_codec_hwaccel Hardware Accelerators bridge + * @{ + * @} + * @} + * @defgroup lavc_internal Internal + * @{ + * @} + * @} + * + */ + +/** + * @defgroup lavc_core Core functions/structures. + * @ingroup libavc + * + * Basic definitions, functions for querying libavcodec capabilities, + * allocating core structures, etc. + * @{ + */ + + +/** + * Identify the syntax and semantics of the bitstream. + * The principle is roughly: + * Two decoders with the same ID can decode the same streams. + * Two encoders with the same ID can encode compatible streams. + * There may be slight deviations from the principle due to implementation + * details. + * + * If you add a codec ID to this list, add it so that + * 1. no value of a existing codec ID changes (that would break ABI), + * 2. it is as close as possible to similar codecs + * + * After adding new codec IDs, do not forget to add an entry to the codec + * descriptor list and bump libavcodec minor version. + */ +enum AVCodecID { + AV_CODEC_ID_NONE, + + /* video codecs */ + AV_CODEC_ID_MPEG1VIDEO, + AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding +#if FF_API_XVMC + AV_CODEC_ID_MPEG2VIDEO_XVMC, +#endif /* FF_API_XVMC */ + AV_CODEC_ID_H261, + AV_CODEC_ID_H263, + AV_CODEC_ID_RV10, + AV_CODEC_ID_RV20, + AV_CODEC_ID_MJPEG, + AV_CODEC_ID_MJPEGB, + AV_CODEC_ID_LJPEG, + AV_CODEC_ID_SP5X, + AV_CODEC_ID_JPEGLS, + AV_CODEC_ID_MPEG4, + AV_CODEC_ID_RAWVIDEO, + AV_CODEC_ID_MSMPEG4V1, + AV_CODEC_ID_MSMPEG4V2, + AV_CODEC_ID_MSMPEG4V3, + AV_CODEC_ID_WMV1, + AV_CODEC_ID_WMV2, + AV_CODEC_ID_H263P, + AV_CODEC_ID_H263I, + AV_CODEC_ID_FLV1, + AV_CODEC_ID_SVQ1, + AV_CODEC_ID_SVQ3, + AV_CODEC_ID_DVVIDEO, + AV_CODEC_ID_HUFFYUV, + AV_CODEC_ID_CYUV, + AV_CODEC_ID_H264, + AV_CODEC_ID_INDEO3, + AV_CODEC_ID_VP3, + AV_CODEC_ID_THEORA, + AV_CODEC_ID_ASV1, + AV_CODEC_ID_ASV2, + AV_CODEC_ID_FFV1, + AV_CODEC_ID_4XM, + AV_CODEC_ID_VCR1, + AV_CODEC_ID_CLJR, + AV_CODEC_ID_MDEC, + AV_CODEC_ID_ROQ, + AV_CODEC_ID_INTERPLAY_VIDEO, + AV_CODEC_ID_XAN_WC3, + AV_CODEC_ID_XAN_WC4, + AV_CODEC_ID_RPZA, + AV_CODEC_ID_CINEPAK, + AV_CODEC_ID_WS_VQA, + AV_CODEC_ID_MSRLE, + AV_CODEC_ID_MSVIDEO1, + AV_CODEC_ID_IDCIN, + AV_CODEC_ID_8BPS, + AV_CODEC_ID_SMC, + AV_CODEC_ID_FLIC, + AV_CODEC_ID_TRUEMOTION1, + AV_CODEC_ID_VMDVIDEO, + AV_CODEC_ID_MSZH, + AV_CODEC_ID_ZLIB, + AV_CODEC_ID_QTRLE, + AV_CODEC_ID_TSCC, + AV_CODEC_ID_ULTI, + AV_CODEC_ID_QDRAW, + AV_CODEC_ID_VIXL, + AV_CODEC_ID_QPEG, + AV_CODEC_ID_PNG, + AV_CODEC_ID_PPM, + AV_CODEC_ID_PBM, + AV_CODEC_ID_PGM, + AV_CODEC_ID_PGMYUV, + AV_CODEC_ID_PAM, + AV_CODEC_ID_FFVHUFF, + AV_CODEC_ID_RV30, + AV_CODEC_ID_RV40, + AV_CODEC_ID_VC1, + AV_CODEC_ID_WMV3, + AV_CODEC_ID_LOCO, + AV_CODEC_ID_WNV1, + AV_CODEC_ID_AASC, + AV_CODEC_ID_INDEO2, + AV_CODEC_ID_FRAPS, + AV_CODEC_ID_TRUEMOTION2, + AV_CODEC_ID_BMP, + AV_CODEC_ID_CSCD, + AV_CODEC_ID_MMVIDEO, + AV_CODEC_ID_ZMBV, + AV_CODEC_ID_AVS, + AV_CODEC_ID_SMACKVIDEO, + AV_CODEC_ID_NUV, + AV_CODEC_ID_KMVC, + AV_CODEC_ID_FLASHSV, + AV_CODEC_ID_CAVS, + AV_CODEC_ID_JPEG2000, + AV_CODEC_ID_VMNC, + AV_CODEC_ID_VP5, + AV_CODEC_ID_VP6, + AV_CODEC_ID_VP6F, + AV_CODEC_ID_TARGA, + AV_CODEC_ID_DSICINVIDEO, + AV_CODEC_ID_TIERTEXSEQVIDEO, + AV_CODEC_ID_TIFF, + AV_CODEC_ID_GIF, + AV_CODEC_ID_DXA, + AV_CODEC_ID_DNXHD, + AV_CODEC_ID_THP, + AV_CODEC_ID_SGI, + AV_CODEC_ID_C93, + AV_CODEC_ID_BETHSOFTVID, + AV_CODEC_ID_PTX, + AV_CODEC_ID_TXD, + AV_CODEC_ID_VP6A, + AV_CODEC_ID_AMV, + AV_CODEC_ID_VB, + AV_CODEC_ID_PCX, + AV_CODEC_ID_SUNRAST, + AV_CODEC_ID_INDEO4, + AV_CODEC_ID_INDEO5, + AV_CODEC_ID_MIMIC, + AV_CODEC_ID_RL2, + AV_CODEC_ID_ESCAPE124, + AV_CODEC_ID_DIRAC, + AV_CODEC_ID_BFI, + AV_CODEC_ID_CMV, + AV_CODEC_ID_MOTIONPIXELS, + AV_CODEC_ID_TGV, + AV_CODEC_ID_TGQ, + AV_CODEC_ID_TQI, + AV_CODEC_ID_AURA, + AV_CODEC_ID_AURA2, + AV_CODEC_ID_V210X, + AV_CODEC_ID_TMV, + AV_CODEC_ID_V210, + AV_CODEC_ID_DPX, + AV_CODEC_ID_MAD, + AV_CODEC_ID_FRWU, + AV_CODEC_ID_FLASHSV2, + AV_CODEC_ID_CDGRAPHICS, + AV_CODEC_ID_R210, + AV_CODEC_ID_ANM, + AV_CODEC_ID_BINKVIDEO, + AV_CODEC_ID_IFF_ILBM, +#define AV_CODEC_ID_IFF_BYTERUN1 AV_CODEC_ID_IFF_ILBM + AV_CODEC_ID_KGV1, + AV_CODEC_ID_YOP, + AV_CODEC_ID_VP8, + AV_CODEC_ID_PICTOR, + AV_CODEC_ID_ANSI, + AV_CODEC_ID_A64_MULTI, + AV_CODEC_ID_A64_MULTI5, + AV_CODEC_ID_R10K, + AV_CODEC_ID_MXPEG, + AV_CODEC_ID_LAGARITH, + AV_CODEC_ID_PRORES, + AV_CODEC_ID_JV, + AV_CODEC_ID_DFA, + AV_CODEC_ID_WMV3IMAGE, + AV_CODEC_ID_VC1IMAGE, + AV_CODEC_ID_UTVIDEO, + AV_CODEC_ID_BMV_VIDEO, + AV_CODEC_ID_VBLE, + AV_CODEC_ID_DXTORY, + AV_CODEC_ID_V410, + AV_CODEC_ID_XWD, + AV_CODEC_ID_CDXL, + AV_CODEC_ID_XBM, + AV_CODEC_ID_ZEROCODEC, + AV_CODEC_ID_MSS1, + AV_CODEC_ID_MSA1, + AV_CODEC_ID_TSCC2, + AV_CODEC_ID_MTS2, + AV_CODEC_ID_CLLC, + AV_CODEC_ID_MSS2, + AV_CODEC_ID_VP9, + AV_CODEC_ID_AIC, + AV_CODEC_ID_ESCAPE130, + AV_CODEC_ID_G2M, + AV_CODEC_ID_WEBP, + AV_CODEC_ID_HNM4_VIDEO, + AV_CODEC_ID_HEVC, +#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC + AV_CODEC_ID_FIC, + AV_CODEC_ID_ALIAS_PIX, + AV_CODEC_ID_BRENDER_PIX, + AV_CODEC_ID_PAF_VIDEO, + AV_CODEC_ID_EXR, + AV_CODEC_ID_VP7, + AV_CODEC_ID_SANM, + AV_CODEC_ID_SGIRLE, + AV_CODEC_ID_MVC1, + AV_CODEC_ID_MVC2, + AV_CODEC_ID_HQX, + AV_CODEC_ID_TDSC, + AV_CODEC_ID_HQ_HQA, + AV_CODEC_ID_HAP, + AV_CODEC_ID_DDS, + AV_CODEC_ID_DXV, + AV_CODEC_ID_SCREENPRESSO, + AV_CODEC_ID_RSCC, + + AV_CODEC_ID_Y41P = 0x8000, + AV_CODEC_ID_AVRP, + AV_CODEC_ID_012V, + AV_CODEC_ID_AVUI, + AV_CODEC_ID_AYUV, + AV_CODEC_ID_TARGA_Y216, + AV_CODEC_ID_V308, + AV_CODEC_ID_V408, + AV_CODEC_ID_YUV4, + AV_CODEC_ID_AVRN, + AV_CODEC_ID_CPIA, + AV_CODEC_ID_XFACE, + AV_CODEC_ID_SNOW, + AV_CODEC_ID_SMVJPEG, + AV_CODEC_ID_APNG, + AV_CODEC_ID_DAALA, + + /* various PCM "codecs" */ + AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs + AV_CODEC_ID_PCM_S16LE = 0x10000, + AV_CODEC_ID_PCM_S16BE, + AV_CODEC_ID_PCM_U16LE, + AV_CODEC_ID_PCM_U16BE, + AV_CODEC_ID_PCM_S8, + AV_CODEC_ID_PCM_U8, + AV_CODEC_ID_PCM_MULAW, + AV_CODEC_ID_PCM_ALAW, + AV_CODEC_ID_PCM_S32LE, + AV_CODEC_ID_PCM_S32BE, + AV_CODEC_ID_PCM_U32LE, + AV_CODEC_ID_PCM_U32BE, + AV_CODEC_ID_PCM_S24LE, + AV_CODEC_ID_PCM_S24BE, + AV_CODEC_ID_PCM_U24LE, + AV_CODEC_ID_PCM_U24BE, + AV_CODEC_ID_PCM_S24DAUD, + AV_CODEC_ID_PCM_ZORK, + AV_CODEC_ID_PCM_S16LE_PLANAR, + AV_CODEC_ID_PCM_DVD, + AV_CODEC_ID_PCM_F32BE, + AV_CODEC_ID_PCM_F32LE, + AV_CODEC_ID_PCM_F64BE, + AV_CODEC_ID_PCM_F64LE, + AV_CODEC_ID_PCM_BLURAY, + AV_CODEC_ID_PCM_LXF, + AV_CODEC_ID_S302M, + AV_CODEC_ID_PCM_S8_PLANAR, + AV_CODEC_ID_PCM_S24LE_PLANAR, + AV_CODEC_ID_PCM_S32LE_PLANAR, + AV_CODEC_ID_PCM_S16BE_PLANAR, + /* new PCM "codecs" should be added right below this line starting with + * an explicit value of for example 0x10800 + */ + + /* various ADPCM codecs */ + AV_CODEC_ID_ADPCM_IMA_QT = 0x11000, + AV_CODEC_ID_ADPCM_IMA_WAV, + AV_CODEC_ID_ADPCM_IMA_DK3, + AV_CODEC_ID_ADPCM_IMA_DK4, + AV_CODEC_ID_ADPCM_IMA_WS, + AV_CODEC_ID_ADPCM_IMA_SMJPEG, + AV_CODEC_ID_ADPCM_MS, + AV_CODEC_ID_ADPCM_4XM, + AV_CODEC_ID_ADPCM_XA, + AV_CODEC_ID_ADPCM_ADX, + AV_CODEC_ID_ADPCM_EA, + AV_CODEC_ID_ADPCM_G726, + AV_CODEC_ID_ADPCM_CT, + AV_CODEC_ID_ADPCM_SWF, + AV_CODEC_ID_ADPCM_YAMAHA, + AV_CODEC_ID_ADPCM_SBPRO_4, + AV_CODEC_ID_ADPCM_SBPRO_3, + AV_CODEC_ID_ADPCM_SBPRO_2, + AV_CODEC_ID_ADPCM_THP, + AV_CODEC_ID_ADPCM_IMA_AMV, + AV_CODEC_ID_ADPCM_EA_R1, + AV_CODEC_ID_ADPCM_EA_R3, + AV_CODEC_ID_ADPCM_EA_R2, + AV_CODEC_ID_ADPCM_IMA_EA_SEAD, + AV_CODEC_ID_ADPCM_IMA_EA_EACS, + AV_CODEC_ID_ADPCM_EA_XAS, + AV_CODEC_ID_ADPCM_EA_MAXIS_XA, + AV_CODEC_ID_ADPCM_IMA_ISS, + AV_CODEC_ID_ADPCM_G722, + AV_CODEC_ID_ADPCM_IMA_APC, + AV_CODEC_ID_ADPCM_VIMA, +#if FF_API_VIMA_DECODER + AV_CODEC_ID_VIMA = AV_CODEC_ID_ADPCM_VIMA, +#endif + + AV_CODEC_ID_ADPCM_AFC = 0x11800, + AV_CODEC_ID_ADPCM_IMA_OKI, + AV_CODEC_ID_ADPCM_DTK, + AV_CODEC_ID_ADPCM_IMA_RAD, + AV_CODEC_ID_ADPCM_G726LE, + AV_CODEC_ID_ADPCM_THP_LE, + AV_CODEC_ID_ADPCM_PSX, + AV_CODEC_ID_ADPCM_AICA, + + /* AMR */ + AV_CODEC_ID_AMR_NB = 0x12000, + AV_CODEC_ID_AMR_WB, + + /* RealAudio codecs*/ + AV_CODEC_ID_RA_144 = 0x13000, + AV_CODEC_ID_RA_288, + + /* various DPCM codecs */ + AV_CODEC_ID_ROQ_DPCM = 0x14000, + AV_CODEC_ID_INTERPLAY_DPCM, + AV_CODEC_ID_XAN_DPCM, + AV_CODEC_ID_SOL_DPCM, + + AV_CODEC_ID_SDX2_DPCM = 0x14800, + + /* audio codecs */ + AV_CODEC_ID_MP2 = 0x15000, + AV_CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3 + AV_CODEC_ID_AAC, + AV_CODEC_ID_AC3, + AV_CODEC_ID_DTS, + AV_CODEC_ID_VORBIS, + AV_CODEC_ID_DVAUDIO, + AV_CODEC_ID_WMAV1, + AV_CODEC_ID_WMAV2, + AV_CODEC_ID_MACE3, + AV_CODEC_ID_MACE6, + AV_CODEC_ID_VMDAUDIO, + AV_CODEC_ID_FLAC, + AV_CODEC_ID_MP3ADU, + AV_CODEC_ID_MP3ON4, + AV_CODEC_ID_SHORTEN, + AV_CODEC_ID_ALAC, + AV_CODEC_ID_WESTWOOD_SND1, + AV_CODEC_ID_GSM, ///< as in Berlin toast format + AV_CODEC_ID_QDM2, + AV_CODEC_ID_COOK, + AV_CODEC_ID_TRUESPEECH, + AV_CODEC_ID_TTA, + AV_CODEC_ID_SMACKAUDIO, + AV_CODEC_ID_QCELP, + AV_CODEC_ID_WAVPACK, + AV_CODEC_ID_DSICINAUDIO, + AV_CODEC_ID_IMC, + AV_CODEC_ID_MUSEPACK7, + AV_CODEC_ID_MLP, + AV_CODEC_ID_GSM_MS, /* as found in WAV */ + AV_CODEC_ID_ATRAC3, +#if FF_API_VOXWARE + AV_CODEC_ID_VOXWARE, +#endif + AV_CODEC_ID_APE, + AV_CODEC_ID_NELLYMOSER, + AV_CODEC_ID_MUSEPACK8, + AV_CODEC_ID_SPEEX, + AV_CODEC_ID_WMAVOICE, + AV_CODEC_ID_WMAPRO, + AV_CODEC_ID_WMALOSSLESS, + AV_CODEC_ID_ATRAC3P, + AV_CODEC_ID_EAC3, + AV_CODEC_ID_SIPR, + AV_CODEC_ID_MP1, + AV_CODEC_ID_TWINVQ, + AV_CODEC_ID_TRUEHD, + AV_CODEC_ID_MP4ALS, + AV_CODEC_ID_ATRAC1, + AV_CODEC_ID_BINKAUDIO_RDFT, + AV_CODEC_ID_BINKAUDIO_DCT, + AV_CODEC_ID_AAC_LATM, + AV_CODEC_ID_QDMC, + AV_CODEC_ID_CELT, + AV_CODEC_ID_G723_1, + AV_CODEC_ID_G729, + AV_CODEC_ID_8SVX_EXP, + AV_CODEC_ID_8SVX_FIB, + AV_CODEC_ID_BMV_AUDIO, + AV_CODEC_ID_RALF, + AV_CODEC_ID_IAC, + AV_CODEC_ID_ILBC, + AV_CODEC_ID_OPUS, + AV_CODEC_ID_COMFORT_NOISE, + AV_CODEC_ID_TAK, + AV_CODEC_ID_METASOUND, + AV_CODEC_ID_PAF_AUDIO, + AV_CODEC_ID_ON2AVC, + AV_CODEC_ID_DSS_SP, + + AV_CODEC_ID_FFWAVESYNTH = 0x15800, + AV_CODEC_ID_SONIC, + AV_CODEC_ID_SONIC_LS, + AV_CODEC_ID_EVRC, + AV_CODEC_ID_SMV, + AV_CODEC_ID_DSD_LSBF, + AV_CODEC_ID_DSD_MSBF, + AV_CODEC_ID_DSD_LSBF_PLANAR, + AV_CODEC_ID_DSD_MSBF_PLANAR, + AV_CODEC_ID_4GV, + AV_CODEC_ID_INTERPLAY_ACM, + AV_CODEC_ID_XMA1, + AV_CODEC_ID_XMA2, + + /* subtitle codecs */ + AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. + AV_CODEC_ID_DVD_SUBTITLE = 0x17000, + AV_CODEC_ID_DVB_SUBTITLE, + AV_CODEC_ID_TEXT, ///< raw UTF-8 text + AV_CODEC_ID_XSUB, + AV_CODEC_ID_SSA, + AV_CODEC_ID_MOV_TEXT, + AV_CODEC_ID_HDMV_PGS_SUBTITLE, + AV_CODEC_ID_DVB_TELETEXT, + AV_CODEC_ID_SRT, + + AV_CODEC_ID_MICRODVD = 0x17800, + AV_CODEC_ID_EIA_608, + AV_CODEC_ID_JACOSUB, + AV_CODEC_ID_SAMI, + AV_CODEC_ID_REALTEXT, + AV_CODEC_ID_STL, + AV_CODEC_ID_SUBVIEWER1, + AV_CODEC_ID_SUBVIEWER, + AV_CODEC_ID_SUBRIP, + AV_CODEC_ID_WEBVTT, + AV_CODEC_ID_MPL2, + AV_CODEC_ID_VPLAYER, + AV_CODEC_ID_PJS, + AV_CODEC_ID_ASS, + AV_CODEC_ID_HDMV_TEXT_SUBTITLE, + + /* other specific kind of codecs (generally used for attachments) */ + AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. + AV_CODEC_ID_TTF = 0x18000, + + AV_CODEC_ID_BINTEXT = 0x18800, + AV_CODEC_ID_XBIN, + AV_CODEC_ID_IDF, + AV_CODEC_ID_OTF, + AV_CODEC_ID_SMPTE_KLV, + AV_CODEC_ID_DVD_NAV, + AV_CODEC_ID_TIMED_ID3, + AV_CODEC_ID_BIN_DATA, + + + AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it + + AV_CODEC_ID_MPEG2TS = 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS + * stream (only used by libavformat) */ + AV_CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems + * stream (only used by libavformat) */ + AV_CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information. + AV_CODEC_ID_WRAPPED_AVFRAME = 0x21001, ///< Passthrough codec, AVFrames wrapped in AVPacket +}; + +/** + * This struct describes the properties of a single codec described by an + * AVCodecID. + * @see avcodec_descriptor_get() + */ +typedef struct AVCodecDescriptor { + enum AVCodecID id; + enum AVMediaType type; + /** + * Name of the codec described by this descriptor. It is non-empty and + * unique for each codec descriptor. It should contain alphanumeric + * characters and '_' only. + */ + const char *name; + /** + * A more descriptive name for this codec. May be NULL. + */ + const char *long_name; + /** + * Codec properties, a combination of AV_CODEC_PROP_* flags. + */ + int props; + /** + * MIME type(s) associated with the codec. + * May be NULL; if not, a NULL-terminated array of MIME types. + * The first item is always non-NULL and is the preferred MIME type. + */ + const char *const *mime_types; + /** + * If non-NULL, an array of profiles recognized for this codec. + * Terminated with FF_PROFILE_UNKNOWN. + */ + const struct AVProfile *profiles; +} AVCodecDescriptor; + +/** + * Codec uses only intra compression. + * Video codecs only. + */ +#define AV_CODEC_PROP_INTRA_ONLY (1 << 0) +/** + * Codec supports lossy compression. Audio and video codecs only. + * @note a codec may support both lossy and lossless + * compression modes + */ +#define AV_CODEC_PROP_LOSSY (1 << 1) +/** + * Codec supports lossless compression. Audio and video codecs only. + */ +#define AV_CODEC_PROP_LOSSLESS (1 << 2) +/** + * Codec supports frame reordering. That is, the coded order (the order in which + * the encoded packets are output by the encoders / stored / input to the + * decoders) may be different from the presentation order of the corresponding + * frames. + * + * For codecs that do not have this property set, PTS and DTS should always be + * equal. + */ +#define AV_CODEC_PROP_REORDER (1 << 3) +/** + * Subtitle codec is bitmap based + * Decoded AVSubtitle data can be read from the AVSubtitleRect->pict field. + */ +#define AV_CODEC_PROP_BITMAP_SUB (1 << 16) +/** + * Subtitle codec is text based. + * Decoded AVSubtitle data can be read from the AVSubtitleRect->ass field. + */ +#define AV_CODEC_PROP_TEXT_SUB (1 << 17) + +/** + * @ingroup lavc_decoding + * Required number of additionally allocated bytes at the end of the input bitstream for decoding. + * This is mainly needed because some optimized bitstream readers read + * 32 or 64 bit at once and could read over the end.
+ * Note: If the first 23 bits of the additional bytes are not 0, then damaged + * MPEG bitstreams could cause overread and segfault. + */ +#define AV_INPUT_BUFFER_PADDING_SIZE 32 + +/** + * @ingroup lavc_encoding + * minimum encoding buffer size + * Used to avoid some checks during header writing. + */ +#define AV_INPUT_BUFFER_MIN_SIZE 16384 + +#if FF_API_WITHOUT_PREFIX +/** + * @deprecated use AV_INPUT_BUFFER_PADDING_SIZE instead + */ +#define FF_INPUT_BUFFER_PADDING_SIZE 32 + +/** + * @deprecated use AV_INPUT_BUFFER_MIN_SIZE instead + */ +#define FF_MIN_BUFFER_SIZE 16384 +#endif /* FF_API_WITHOUT_PREFIX */ + +/** + * @ingroup lavc_encoding + * motion estimation type. + * @deprecated use codec private option instead + */ +#if FF_API_MOTION_EST +enum Motion_Est_ID { + ME_ZERO = 1, ///< no search, that is use 0,0 vector whenever one is needed + ME_FULL, + ME_LOG, + ME_PHODS, + ME_EPZS, ///< enhanced predictive zonal search + ME_X1, ///< reserved for experiments + ME_HEX, ///< hexagon based search + ME_UMH, ///< uneven multi-hexagon search + ME_TESA, ///< transformed exhaustive search algorithm + ME_ITER=50, ///< iterative search +}; +#endif + +/** + * @ingroup lavc_decoding + */ +enum AVDiscard{ + /* We leave some space between them for extensions (drop some + * keyframes for intra-only or drop just some bidir frames). */ + AVDISCARD_NONE =-16, ///< discard nothing + AVDISCARD_DEFAULT = 0, ///< discard useless packets like 0 size packets in avi + AVDISCARD_NONREF = 8, ///< discard all non reference + AVDISCARD_BIDIR = 16, ///< discard all bidirectional frames + AVDISCARD_NONINTRA= 24, ///< discard all non intra frames + AVDISCARD_NONKEY = 32, ///< discard all frames except keyframes + AVDISCARD_ALL = 48, ///< discard all +}; + +enum AVAudioServiceType { + AV_AUDIO_SERVICE_TYPE_MAIN = 0, + AV_AUDIO_SERVICE_TYPE_EFFECTS = 1, + AV_AUDIO_SERVICE_TYPE_VISUALLY_IMPAIRED = 2, + AV_AUDIO_SERVICE_TYPE_HEARING_IMPAIRED = 3, + AV_AUDIO_SERVICE_TYPE_DIALOGUE = 4, + AV_AUDIO_SERVICE_TYPE_COMMENTARY = 5, + AV_AUDIO_SERVICE_TYPE_EMERGENCY = 6, + AV_AUDIO_SERVICE_TYPE_VOICE_OVER = 7, + AV_AUDIO_SERVICE_TYPE_KARAOKE = 8, + AV_AUDIO_SERVICE_TYPE_NB , ///< Not part of ABI +}; + +/** + * @ingroup lavc_encoding + */ +typedef struct RcOverride{ + int start_frame; + int end_frame; + int qscale; // If this is 0 then quality_factor will be used instead. + float quality_factor; +} RcOverride; + +#if FF_API_MAX_BFRAMES +/** + * @deprecated there is no libavcodec-wide limit on the number of B-frames + */ +#define FF_MAX_B_FRAMES 16 +#endif + +/* encoding support + These flags can be passed in AVCodecContext.flags before initialization. + Note: Not everything is supported yet. +*/ + +/** + * Allow decoders to produce frames with data planes that are not aligned + * to CPU requirements (e.g. due to cropping). + */ +#define AV_CODEC_FLAG_UNALIGNED (1 << 0) +/** + * Use fixed qscale. + */ +#define AV_CODEC_FLAG_QSCALE (1 << 1) +/** + * 4 MV per MB allowed / advanced prediction for H.263. + */ +#define AV_CODEC_FLAG_4MV (1 << 2) +/** + * Output even those frames that might be corrupted. + */ +#define AV_CODEC_FLAG_OUTPUT_CORRUPT (1 << 3) +/** + * Use qpel MC. + */ +#define AV_CODEC_FLAG_QPEL (1 << 4) +/** + * Use internal 2pass ratecontrol in first pass mode. + */ +#define AV_CODEC_FLAG_PASS1 (1 << 9) +/** + * Use internal 2pass ratecontrol in second pass mode. + */ +#define AV_CODEC_FLAG_PASS2 (1 << 10) +/** + * loop filter. + */ +#define AV_CODEC_FLAG_LOOP_FILTER (1 << 11) +/** + * Only decode/encode grayscale. + */ +#define AV_CODEC_FLAG_GRAY (1 << 13) +/** + * error[?] variables will be set during encoding. + */ +#define AV_CODEC_FLAG_PSNR (1 << 15) +/** + * Input bitstream might be truncated at a random location + * instead of only at frame boundaries. + */ +#define AV_CODEC_FLAG_TRUNCATED (1 << 16) +/** + * Use interlaced DCT. + */ +#define AV_CODEC_FLAG_INTERLACED_DCT (1 << 18) +/** + * Force low delay. + */ +#define AV_CODEC_FLAG_LOW_DELAY (1 << 19) +/** + * Place global headers in extradata instead of every keyframe. + */ +#define AV_CODEC_FLAG_GLOBAL_HEADER (1 << 22) +/** + * Use only bitexact stuff (except (I)DCT). + */ +#define AV_CODEC_FLAG_BITEXACT (1 << 23) +/* Fx : Flag for h263+ extra options */ +/** + * H.263 advanced intra coding / MPEG-4 AC prediction + */ +#define AV_CODEC_FLAG_AC_PRED (1 << 24) +/** + * interlaced motion estimation + */ +#define AV_CODEC_FLAG_INTERLACED_ME (1 << 29) +#define AV_CODEC_FLAG_CLOSED_GOP (1U << 31) + +/** + * Allow non spec compliant speedup tricks. + */ +#define AV_CODEC_FLAG2_FAST (1 << 0) +/** + * Skip bitstream encoding. + */ +#define AV_CODEC_FLAG2_NO_OUTPUT (1 << 2) +/** + * Place global headers at every keyframe instead of in extradata. + */ +#define AV_CODEC_FLAG2_LOCAL_HEADER (1 << 3) + +/** + * timecode is in drop frame format. DEPRECATED!!!! + */ +#define AV_CODEC_FLAG2_DROP_FRAME_TIMECODE (1 << 13) + +/** + * Input bitstream might be truncated at a packet boundaries + * instead of only at frame boundaries. + */ +#define AV_CODEC_FLAG2_CHUNKS (1 << 15) +/** + * Discard cropping information from SPS. + */ +#define AV_CODEC_FLAG2_IGNORE_CROP (1 << 16) + +/** + * Show all frames before the first keyframe + */ +#define AV_CODEC_FLAG2_SHOW_ALL (1 << 22) +/** + * Export motion vectors through frame side data + */ +#define AV_CODEC_FLAG2_EXPORT_MVS (1 << 28) +/** + * Do not skip samples and export skip information as frame side data + */ +#define AV_CODEC_FLAG2_SKIP_MANUAL (1 << 29) + +/* Unsupported options : + * Syntax Arithmetic coding (SAC) + * Reference Picture Selection + * Independent Segment Decoding */ +/* /Fx */ +/* codec capabilities */ + +/** + * Decoder can use draw_horiz_band callback. + */ +#define AV_CODEC_CAP_DRAW_HORIZ_BAND (1 << 0) +/** + * Codec uses get_buffer() for allocating buffers and supports custom allocators. + * If not set, it might not use get_buffer() at all or use operations that + * assume the buffer was allocated by avcodec_default_get_buffer. + */ +#define AV_CODEC_CAP_DR1 (1 << 1) +#define AV_CODEC_CAP_TRUNCATED (1 << 3) +/** + * Encoder or decoder requires flushing with NULL input at the end in order to + * give the complete and correct output. + * + * NOTE: If this flag is not set, the codec is guaranteed to never be fed with + * with NULL data. The user can still send NULL data to the public encode + * or decode function, but libavcodec will not pass it along to the codec + * unless this flag is set. + * + * Decoders: + * The decoder has a non-zero delay and needs to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to get the delayed data until the decoder no longer + * returns frames. + * + * Encoders: + * The encoder needs to be fed with NULL data at the end of encoding until the + * encoder no longer returns data. + * + * NOTE: For encoders implementing the AVCodec.encode2() function, setting this + * flag also means that the encoder must set the pts and duration for + * each output packet. If this flag is not set, the pts and duration will + * be determined by libavcodec from the input frame. + */ +#define AV_CODEC_CAP_DELAY (1 << 5) +/** + * Codec can be fed a final frame with a smaller size. + * This can be used to prevent truncation of the last audio samples. + */ +#define AV_CODEC_CAP_SMALL_LAST_FRAME (1 << 6) + +#if FF_API_CAP_VDPAU +/** + * Codec can export data for HW decoding (VDPAU). + */ +#define AV_CODEC_CAP_HWACCEL_VDPAU (1 << 7) +#endif + +/** + * Codec can output multiple frames per AVPacket + * Normally demuxers return one frame at a time, demuxers which do not do + * are connected to a parser to split what they return into proper frames. + * This flag is reserved to the very rare category of codecs which have a + * bitstream that cannot be split into frames without timeconsuming + * operations like full decoding. Demuxers carring such bitstreams thus + * may return multiple frames in a packet. This has many disadvantages like + * prohibiting stream copy in many cases thus it should only be considered + * as a last resort. + */ +#define AV_CODEC_CAP_SUBFRAMES (1 << 8) +/** + * Codec is experimental and is thus avoided in favor of non experimental + * encoders + */ +#define AV_CODEC_CAP_EXPERIMENTAL (1 << 9) +/** + * Codec should fill in channel configuration and samplerate instead of container + */ +#define AV_CODEC_CAP_CHANNEL_CONF (1 << 10) +/** + * Codec supports frame-level multithreading. + */ +#define AV_CODEC_CAP_FRAME_THREADS (1 << 12) +/** + * Codec supports slice-based (or partition-based) multithreading. + */ +#define AV_CODEC_CAP_SLICE_THREADS (1 << 13) +/** + * Codec supports changed parameters at any point. + */ +#define AV_CODEC_CAP_PARAM_CHANGE (1 << 14) +/** + * Codec supports avctx->thread_count == 0 (auto). + */ +#define AV_CODEC_CAP_AUTO_THREADS (1 << 15) +/** + * Audio encoder supports receiving a different number of samples in each call. + */ +#define AV_CODEC_CAP_VARIABLE_FRAME_SIZE (1 << 16) +/** + * Codec is intra only. + */ +#define AV_CODEC_CAP_INTRA_ONLY 0x40000000 +/** + * Codec is lossless. + */ +#define AV_CODEC_CAP_LOSSLESS 0x80000000 + + +#if FF_API_WITHOUT_PREFIX +/** + * Allow decoders to produce frames with data planes that are not aligned + * to CPU requirements (e.g. due to cropping). + */ +#define CODEC_FLAG_UNALIGNED AV_CODEC_FLAG_UNALIGNED +#define CODEC_FLAG_QSCALE AV_CODEC_FLAG_QSCALE +#define CODEC_FLAG_4MV AV_CODEC_FLAG_4MV +#define CODEC_FLAG_OUTPUT_CORRUPT AV_CODEC_FLAG_OUTPUT_CORRUPT +#define CODEC_FLAG_QPEL AV_CODEC_FLAG_QPEL +#if FF_API_GMC +/** + * @deprecated use the "gmc" private option of the libxvid encoder + */ +#define CODEC_FLAG_GMC 0x0020 ///< Use GMC. +#endif +#if FF_API_MV0 +/** + * @deprecated use the flag "mv0" in the "mpv_flags" private option of the + * mpegvideo encoders + */ +#define CODEC_FLAG_MV0 0x0040 +#endif +#if FF_API_INPUT_PRESERVED +/** + * @deprecated passing reference-counted frames to the encoders replaces this + * flag + */ +#define CODEC_FLAG_INPUT_PRESERVED 0x0100 +#endif +#define CODEC_FLAG_PASS1 AV_CODEC_FLAG_PASS1 +#define CODEC_FLAG_PASS2 AV_CODEC_FLAG_PASS2 +#define CODEC_FLAG_GRAY AV_CODEC_FLAG_GRAY +#if FF_API_EMU_EDGE +/** + * @deprecated edges are not used/required anymore. I.e. this flag is now always + * set. + */ +#define CODEC_FLAG_EMU_EDGE 0x4000 +#endif +#define CODEC_FLAG_PSNR AV_CODEC_FLAG_PSNR +#define CODEC_FLAG_TRUNCATED AV_CODEC_FLAG_TRUNCATED + +#if FF_API_NORMALIZE_AQP +/** + * @deprecated use the flag "naq" in the "mpv_flags" private option of the + * mpegvideo encoders + */ +#define CODEC_FLAG_NORMALIZE_AQP 0x00020000 +#endif +#define CODEC_FLAG_INTERLACED_DCT AV_CODEC_FLAG_INTERLACED_DCT +#define CODEC_FLAG_LOW_DELAY AV_CODEC_FLAG_LOW_DELAY +#define CODEC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER +#define CODEC_FLAG_BITEXACT AV_CODEC_FLAG_BITEXACT +#define CODEC_FLAG_AC_PRED AV_CODEC_FLAG_AC_PRED +#define CODEC_FLAG_LOOP_FILTER AV_CODEC_FLAG_LOOP_FILTER +#define CODEC_FLAG_INTERLACED_ME AV_CODEC_FLAG_INTERLACED_ME +#define CODEC_FLAG_CLOSED_GOP AV_CODEC_FLAG_CLOSED_GOP +#define CODEC_FLAG2_FAST AV_CODEC_FLAG2_FAST +#define CODEC_FLAG2_NO_OUTPUT AV_CODEC_FLAG2_NO_OUTPUT +#define CODEC_FLAG2_LOCAL_HEADER AV_CODEC_FLAG2_LOCAL_HEADER +#define CODEC_FLAG2_DROP_FRAME_TIMECODE AV_CODEC_FLAG2_DROP_FRAME_TIMECODE +#define CODEC_FLAG2_IGNORE_CROP AV_CODEC_FLAG2_IGNORE_CROP + +#define CODEC_FLAG2_CHUNKS AV_CODEC_FLAG2_CHUNKS +#define CODEC_FLAG2_SHOW_ALL AV_CODEC_FLAG2_SHOW_ALL +#define CODEC_FLAG2_EXPORT_MVS AV_CODEC_FLAG2_EXPORT_MVS +#define CODEC_FLAG2_SKIP_MANUAL AV_CODEC_FLAG2_SKIP_MANUAL + +/* Unsupported options : + * Syntax Arithmetic coding (SAC) + * Reference Picture Selection + * Independent Segment Decoding */ +/* /Fx */ +/* codec capabilities */ + +#define CODEC_CAP_DRAW_HORIZ_BAND AV_CODEC_CAP_DRAW_HORIZ_BAND ///< Decoder can use draw_horiz_band callback. +/** + * Codec uses get_buffer() for allocating buffers and supports custom allocators. + * If not set, it might not use get_buffer() at all or use operations that + * assume the buffer was allocated by avcodec_default_get_buffer. + */ +#define CODEC_CAP_DR1 AV_CODEC_CAP_DR1 +#define CODEC_CAP_TRUNCATED AV_CODEC_CAP_TRUNCATED +#if FF_API_XVMC +/* Codec can export data for HW decoding. This flag indicates that + * the codec would call get_format() with list that might contain HW accelerated + * pixel formats (XvMC, VDPAU, VAAPI, etc). The application can pick any of them + * including raw image format. + * The application can use the passed context to determine bitstream version, + * chroma format, resolution etc. + */ +#define CODEC_CAP_HWACCEL 0x0010 +#endif /* FF_API_XVMC */ +/** + * Encoder or decoder requires flushing with NULL input at the end in order to + * give the complete and correct output. + * + * NOTE: If this flag is not set, the codec is guaranteed to never be fed with + * with NULL data. The user can still send NULL data to the public encode + * or decode function, but libavcodec will not pass it along to the codec + * unless this flag is set. + * + * Decoders: + * The decoder has a non-zero delay and needs to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to get the delayed data until the decoder no longer + * returns frames. + * + * Encoders: + * The encoder needs to be fed with NULL data at the end of encoding until the + * encoder no longer returns data. + * + * NOTE: For encoders implementing the AVCodec.encode2() function, setting this + * flag also means that the encoder must set the pts and duration for + * each output packet. If this flag is not set, the pts and duration will + * be determined by libavcodec from the input frame. + */ +#define CODEC_CAP_DELAY AV_CODEC_CAP_DELAY +/** + * Codec can be fed a final frame with a smaller size. + * This can be used to prevent truncation of the last audio samples. + */ +#define CODEC_CAP_SMALL_LAST_FRAME AV_CODEC_CAP_SMALL_LAST_FRAME +#if FF_API_CAP_VDPAU +/** + * Codec can export data for HW decoding (VDPAU). + */ +#define CODEC_CAP_HWACCEL_VDPAU AV_CODEC_CAP_HWACCEL_VDPAU +#endif +/** + * Codec can output multiple frames per AVPacket + * Normally demuxers return one frame at a time, demuxers which do not do + * are connected to a parser to split what they return into proper frames. + * This flag is reserved to the very rare category of codecs which have a + * bitstream that cannot be split into frames without timeconsuming + * operations like full decoding. Demuxers carring such bitstreams thus + * may return multiple frames in a packet. This has many disadvantages like + * prohibiting stream copy in many cases thus it should only be considered + * as a last resort. + */ +#define CODEC_CAP_SUBFRAMES AV_CODEC_CAP_SUBFRAMES +/** + * Codec is experimental and is thus avoided in favor of non experimental + * encoders + */ +#define CODEC_CAP_EXPERIMENTAL AV_CODEC_CAP_EXPERIMENTAL +/** + * Codec should fill in channel configuration and samplerate instead of container + */ +#define CODEC_CAP_CHANNEL_CONF AV_CODEC_CAP_CHANNEL_CONF +#if FF_API_NEG_LINESIZES +/** + * @deprecated no codecs use this capability + */ +#define CODEC_CAP_NEG_LINESIZES 0x0800 +#endif +/** + * Codec supports frame-level multithreading. + */ +#define CODEC_CAP_FRAME_THREADS AV_CODEC_CAP_FRAME_THREADS +/** + * Codec supports slice-based (or partition-based) multithreading. + */ +#define CODEC_CAP_SLICE_THREADS AV_CODEC_CAP_SLICE_THREADS +/** + * Codec supports changed parameters at any point. + */ +#define CODEC_CAP_PARAM_CHANGE AV_CODEC_CAP_PARAM_CHANGE +/** + * Codec supports avctx->thread_count == 0 (auto). + */ +#define CODEC_CAP_AUTO_THREADS AV_CODEC_CAP_AUTO_THREADS +/** + * Audio encoder supports receiving a different number of samples in each call. + */ +#define CODEC_CAP_VARIABLE_FRAME_SIZE AV_CODEC_CAP_VARIABLE_FRAME_SIZE +/** + * Codec is intra only. + */ +#define CODEC_CAP_INTRA_ONLY AV_CODEC_CAP_INTRA_ONLY +/** + * Codec is lossless. + */ +#define CODEC_CAP_LOSSLESS AV_CODEC_CAP_LOSSLESS + +/** + * HWAccel is experimental and is thus avoided in favor of non experimental + * codecs + */ +#define HWACCEL_CODEC_CAP_EXPERIMENTAL 0x0200 +#endif /* FF_API_WITHOUT_PREFIX */ + +#if FF_API_MB_TYPE +//The following defines may change, don't expect compatibility if you use them. +#define MB_TYPE_INTRA4x4 0x0001 +#define MB_TYPE_INTRA16x16 0x0002 //FIXME H.264-specific +#define MB_TYPE_INTRA_PCM 0x0004 //FIXME H.264-specific +#define MB_TYPE_16x16 0x0008 +#define MB_TYPE_16x8 0x0010 +#define MB_TYPE_8x16 0x0020 +#define MB_TYPE_8x8 0x0040 +#define MB_TYPE_INTERLACED 0x0080 +#define MB_TYPE_DIRECT2 0x0100 //FIXME +#define MB_TYPE_ACPRED 0x0200 +#define MB_TYPE_GMC 0x0400 +#define MB_TYPE_SKIP 0x0800 +#define MB_TYPE_P0L0 0x1000 +#define MB_TYPE_P1L0 0x2000 +#define MB_TYPE_P0L1 0x4000 +#define MB_TYPE_P1L1 0x8000 +#define MB_TYPE_L0 (MB_TYPE_P0L0 | MB_TYPE_P1L0) +#define MB_TYPE_L1 (MB_TYPE_P0L1 | MB_TYPE_P1L1) +#define MB_TYPE_L0L1 (MB_TYPE_L0 | MB_TYPE_L1) +#define MB_TYPE_QUANT 0x00010000 +#define MB_TYPE_CBP 0x00020000 +//Note bits 24-31 are reserved for codec specific use (h264 ref0, mpeg1 0mv, ...) +#endif + +/** + * Pan Scan area. + * This specifies the area which should be displayed. + * Note there may be multiple such areas for one frame. + */ +typedef struct AVPanScan{ + /** + * id + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int id; + + /** + * width and height in 1/16 pel + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int width; + int height; + + /** + * position of the top left corner in 1/16 pel for up to 3 fields/frames + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int16_t position[3][2]; +}AVPanScan; + +/** + * This structure describes the bitrate properties of an encoded bitstream. It + * roughly corresponds to a subset the VBV parameters for MPEG-2 or HRD + * parameters for H.264/HEVC. + */ +typedef struct AVCPBProperties { + /** + * Maximum bitrate of the stream, in bits per second. + * Zero if unknown or unspecified. + */ + int max_bitrate; + /** + * Minimum bitrate of the stream, in bits per second. + * Zero if unknown or unspecified. + */ + int min_bitrate; + /** + * Average bitrate of the stream, in bits per second. + * Zero if unknown or unspecified. + */ + int avg_bitrate; + + /** + * The size of the buffer to which the ratecontrol is applied, in bits. + * Zero if unknown or unspecified. + */ + int buffer_size; + + /** + * The delay between the time the packet this structure is associated with + * is received and the time when it should be decoded, in periods of a 27MHz + * clock. + * + * UINT64_MAX when unknown or unspecified. + */ + uint64_t vbv_delay; +} AVCPBProperties; + +#if FF_API_QSCALE_TYPE +#define FF_QSCALE_TYPE_MPEG1 0 +#define FF_QSCALE_TYPE_MPEG2 1 +#define FF_QSCALE_TYPE_H264 2 +#define FF_QSCALE_TYPE_VP56 3 +#endif + +/** + * The decoder will keep a reference to the frame and may reuse it later. + */ +#define AV_GET_BUFFER_FLAG_REF (1 << 0) + +/** + * @defgroup lavc_packet AVPacket + * + * Types and functions for working with AVPacket. + * @{ + */ +enum AVPacketSideDataType { + AV_PKT_DATA_PALETTE, + AV_PKT_DATA_NEW_EXTRADATA, + + /** + * An AV_PKT_DATA_PARAM_CHANGE side data packet is laid out as follows: + * @code + * u32le param_flags + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT) + * s32le channel_count + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT) + * u64le channel_layout + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) + * s32le sample_rate + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) + * s32le width + * s32le height + * @endcode + */ + AV_PKT_DATA_PARAM_CHANGE, + + /** + * An AV_PKT_DATA_H263_MB_INFO side data packet contains a number of + * structures with info about macroblocks relevant to splitting the + * packet into smaller packets on macroblock edges (e.g. as for RFC 2190). + * That is, it does not necessarily contain info about all macroblocks, + * as long as the distance between macroblocks in the info is smaller + * than the target payload size. + * Each MB info structure is 12 bytes, and is laid out as follows: + * @code + * u32le bit offset from the start of the packet + * u8 current quantizer at the start of the macroblock + * u8 GOB number + * u16le macroblock address within the GOB + * u8 horizontal MV predictor + * u8 vertical MV predictor + * u8 horizontal MV predictor for block number 3 + * u8 vertical MV predictor for block number 3 + * @endcode + */ + AV_PKT_DATA_H263_MB_INFO, + + /** + * This side data should be associated with an audio stream and contains + * ReplayGain information in form of the AVReplayGain struct. + */ + AV_PKT_DATA_REPLAYGAIN, + + /** + * This side data contains a 3x3 transformation matrix describing an affine + * transformation that needs to be applied to the decoded video frames for + * correct presentation. + * + * See libavutil/display.h for a detailed description of the data. + */ + AV_PKT_DATA_DISPLAYMATRIX, + + /** + * This side data should be associated with a video stream and contains + * Stereoscopic 3D information in form of the AVStereo3D struct. + */ + AV_PKT_DATA_STEREO3D, + + /** + * This side data should be associated with an audio stream and corresponds + * to enum AVAudioServiceType. + */ + AV_PKT_DATA_AUDIO_SERVICE_TYPE, + + /** + * This side data contains quality related information from the encoder. + * @code + * u32le quality factor of the compressed frame. Allowed range is between 1 (good) and FF_LAMBDA_MAX (bad). + * u8 picture type + * u8 error count + * u16 reserved + * u64le[error count] sum of squared differences between encoder in and output + * @endcode + */ + AV_PKT_DATA_QUALITY_STATS, + + /** + * This side data contains an integer value representing the stream index + * of a "fallback" track. A fallback track indicates an alternate + * track to use when the current track can not be decoded for some reason. + * e.g. no decoder available for codec. + */ + AV_PKT_DATA_FALLBACK_TRACK, + + /** + * This side data corresponds to the AVCPBProperties struct. + */ + AV_PKT_DATA_CPB_PROPERTIES, + + /** + * Recommmends skipping the specified number of samples + * @code + * u32le number of samples to skip from start of this packet + * u32le number of samples to skip from end of this packet + * u8 reason for start skip + * u8 reason for end skip (0=padding silence, 1=convergence) + * @endcode + */ + AV_PKT_DATA_SKIP_SAMPLES=70, + + /** + * An AV_PKT_DATA_JP_DUALMONO side data packet indicates that + * the packet may contain "dual mono" audio specific to Japanese DTV + * and if it is true, recommends only the selected channel to be used. + * @code + * u8 selected channels (0=mail/left, 1=sub/right, 2=both) + * @endcode + */ + AV_PKT_DATA_JP_DUALMONO, + + /** + * A list of zero terminated key/value strings. There is no end marker for + * the list, so it is required to rely on the side data size to stop. + */ + AV_PKT_DATA_STRINGS_METADATA, + + /** + * Subtitle event position + * @code + * u32le x1 + * u32le y1 + * u32le x2 + * u32le y2 + * @endcode + */ + AV_PKT_DATA_SUBTITLE_POSITION, + + /** + * Data found in BlockAdditional element of matroska container. There is + * no end marker for the data, so it is required to rely on the side data + * size to recognize the end. 8 byte id (as found in BlockAddId) followed + * by data. + */ + AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, + + /** + * The optional first identifier line of a WebVTT cue. + */ + AV_PKT_DATA_WEBVTT_IDENTIFIER, + + /** + * The optional settings (rendering instructions) that immediately + * follow the timestamp specifier of a WebVTT cue. + */ + AV_PKT_DATA_WEBVTT_SETTINGS, + + /** + * A list of zero terminated key/value strings. There is no end marker for + * the list, so it is required to rely on the side data size to stop. This + * side data includes updated metadata which appeared in the stream. + */ + AV_PKT_DATA_METADATA_UPDATE, +}; + +#define AV_PKT_DATA_QUALITY_FACTOR AV_PKT_DATA_QUALITY_STATS //DEPRECATED + +typedef struct AVPacketSideData { + uint8_t *data; + int size; + enum AVPacketSideDataType type; +} AVPacketSideData; + +/** + * This structure stores compressed data. It is typically exported by demuxers + * and then passed as input to decoders, or received as output from encoders and + * then passed to muxers. + * + * For video, it should typically contain one compressed frame. For audio it may + * contain several compressed frames. Encoders are allowed to output empty + * packets, with no compressed data, containing only side data + * (e.g. to update some stream parameters at the end of encoding). + * + * AVPacket is one of the few structs in FFmpeg, whose size is a part of public + * ABI. Thus it may be allocated on stack and no new fields can be added to it + * without libavcodec and libavformat major bump. + * + * The semantics of data ownership depends on the buf field. + * If it is set, the packet data is dynamically allocated and is + * valid indefinitely until a call to av_packet_unref() reduces the + * reference count to 0. + * + * If the buf field is not set av_packet_ref() would make a copy instead + * of increasing the reference count. + * + * The side data is always allocated with av_malloc(), copied by + * av_packet_ref() and freed by av_packet_unref(). + * + * @see av_packet_ref + * @see av_packet_unref + */ +typedef struct AVPacket { + /** + * A reference to the reference-counted buffer where the packet data is + * stored. + * May be NULL, then the packet data is not reference-counted. + */ + AVBufferRef *buf; + /** + * Presentation timestamp in AVStream->time_base units; the time at which + * the decompressed packet will be presented to the user. + * Can be AV_NOPTS_VALUE if it is not stored in the file. + * pts MUST be larger or equal to dts as presentation cannot happen before + * decompression, unless one wants to view hex dumps. Some formats misuse + * the terms dts and pts/cts to mean something different. Such timestamps + * must be converted to true pts/dts before they are stored in AVPacket. + */ + int64_t pts; + /** + * Decompression timestamp in AVStream->time_base units; the time at which + * the packet is decompressed. + * Can be AV_NOPTS_VALUE if it is not stored in the file. + */ + int64_t dts; + uint8_t *data; + int size; + int stream_index; + /** + * A combination of AV_PKT_FLAG values + */ + int flags; + /** + * Additional packet data that can be provided by the container. + * Packet can contain several types of side information. + */ + AVPacketSideData *side_data; + int side_data_elems; + + /** + * Duration of this packet in AVStream->time_base units, 0 if unknown. + * Equals next_pts - this_pts in presentation order. + */ + int64_t duration; + + int64_t pos; ///< byte position in stream, -1 if unknown + +#if FF_API_CONVERGENCE_DURATION + /** + * @deprecated Same as the duration field, but as int64_t. This was required + * for Matroska subtitles, whose duration values could overflow when the + * duration field was still an int. + */ + attribute_deprecated + int64_t convergence_duration; +#endif +} AVPacket; +#define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe +#define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted + +enum AVSideDataParamChangeFlags { + AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT = 0x0001, + AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_LAYOUT = 0x0002, + AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE = 0x0004, + AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS = 0x0008, +}; +/** + * @} + */ + +struct AVCodecInternal; + +enum AVFieldOrder { + AV_FIELD_UNKNOWN, + AV_FIELD_PROGRESSIVE, + AV_FIELD_TT, //< Top coded_first, top displayed first + AV_FIELD_BB, //< Bottom coded first, bottom displayed first + AV_FIELD_TB, //< Top coded first, bottom displayed first + AV_FIELD_BT, //< Bottom coded first, top displayed first +}; + +/** + * main external API structure. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * Please use AVOptions (av_opt* / av_set/get*()) to access these fields from user + * applications. + * sizeof(AVCodecContext) must not be used outside libav*. + */ +typedef struct AVCodecContext { + /** + * information on struct for av_log + * - set by avcodec_alloc_context3 + */ + const AVClass *av_class; + int log_level_offset; + + enum AVMediaType codec_type; /* see AVMEDIA_TYPE_xxx */ + const struct AVCodec *codec; +#if FF_API_CODEC_NAME + /** + * @deprecated this field is not used for anything in libavcodec + */ + attribute_deprecated + char codec_name[32]; +#endif + enum AVCodecID codec_id; /* see AV_CODEC_ID_xxx */ + + /** + * fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). + * This is used to work around some encoder bugs. + * A demuxer should set this to what is stored in the field used to identify the codec. + * If there are multiple such fields in a container then the demuxer should choose the one + * which maximizes the information about the used codec. + * If the codec tag field in a container is larger than 32 bits then the demuxer should + * remap the longer ID to 32 bits with a table or other structure. Alternatively a new + * extra_codec_tag + size could be added but for this a clear advantage must be demonstrated + * first. + * - encoding: Set by user, if not then the default based on codec_id will be used. + * - decoding: Set by user, will be converted to uppercase by libavcodec during init. + */ + unsigned int codec_tag; + +#if FF_API_STREAM_CODEC_TAG + /** + * @deprecated this field is unused + */ + attribute_deprecated + unsigned int stream_codec_tag; +#endif + + void *priv_data; + + /** + * Private context used for internal data. + * + * Unlike priv_data, this is not codec-specific. It is used in general + * libavcodec functions. + */ + struct AVCodecInternal *internal; + + /** + * Private data of the user, can be used to carry app specific stuff. + * - encoding: Set by user. + * - decoding: Set by user. + */ + void *opaque; + + /** + * the average bitrate + * - encoding: Set by user; unused for constant quantizer encoding. + * - decoding: Set by user, may be overwritten by libavcodec + * if this info is available in the stream + */ + int64_t bit_rate; + + /** + * number of bits the bitstream is allowed to diverge from the reference. + * the reference can be CBR (for CBR pass1) or VBR (for pass2) + * - encoding: Set by user; unused for constant quantizer encoding. + * - decoding: unused + */ + int bit_rate_tolerance; + + /** + * Global quality for codecs which cannot change it per frame. + * This should be proportional to MPEG-1/2/4 qscale. + * - encoding: Set by user. + * - decoding: unused + */ + int global_quality; + + /** + * - encoding: Set by user. + * - decoding: unused + */ + int compression_level; +#define FF_COMPRESSION_DEFAULT -1 + + /** + * AV_CODEC_FLAG_*. + * - encoding: Set by user. + * - decoding: Set by user. + */ + int flags; + + /** + * AV_CODEC_FLAG2_* + * - encoding: Set by user. + * - decoding: Set by user. + */ + int flags2; + + /** + * some codecs need / can use extradata like Huffman tables. + * mjpeg: Huffman tables + * rv10: additional flags + * mpeg4: global headers (they can be in the bitstream or here) + * The allocated memory should be AV_INPUT_BUFFER_PADDING_SIZE bytes larger + * than extradata_size to avoid problems if it is read with the bitstream reader. + * The bytewise contents of extradata must not depend on the architecture or CPU endianness. + * - encoding: Set/allocated/freed by libavcodec. + * - decoding: Set/allocated/freed by user. + */ + uint8_t *extradata; + int extradata_size; + + /** + * This is the fundamental unit of time (in seconds) in terms + * of which frame timestamps are represented. For fixed-fps content, + * timebase should be 1/framerate and timestamp increments should be + * identically 1. + * This often, but not always is the inverse of the frame rate or field rate + * for video. + * - encoding: MUST be set by user. + * - decoding: the use of this field for decoding is deprecated. + * Use framerate instead. + */ + AVRational time_base; + + /** + * For some codecs, the time base is closer to the field rate than the frame rate. + * Most notably, H.264 and MPEG-2 specify time_base as half of frame duration + * if no telecine is used ... + * + * Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2. + */ + int ticks_per_frame; + + /** + * Codec delay. + * + * Encoding: Number of frames delay there will be from the encoder input to + * the decoder output. (we assume the decoder matches the spec) + * Decoding: Number of frames delay in addition to what a standard decoder + * as specified in the spec would produce. + * + * Video: + * Number of frames the decoded output will be delayed relative to the + * encoded input. + * + * Audio: + * For encoding, this field is unused (see initial_padding). + * + * For decoding, this is the number of samples the decoder needs to + * output before the decoder's output is valid. When seeking, you should + * start decoding this many samples prior to your desired seek point. + * + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int delay; + + + /* video only */ + /** + * picture width / height. + * + * @note Those fields may not match the values of the last + * AVFrame outputted by avcodec_decode_video2 due frame + * reordering. + * + * - encoding: MUST be set by user. + * - decoding: May be set by the user before opening the decoder if known e.g. + * from the container. Some decoders will require the dimensions + * to be set by the caller. During decoding, the decoder may + * overwrite those values as required while parsing the data. + */ + int width, height; + + /** + * Bitstream width / height, may be different from width/height e.g. when + * the decoded frame is cropped before being output or lowres is enabled. + * + * @note Those field may not match the value of the last + * AVFrame outputted by avcodec_decode_video2 due frame + * reordering. + * + * - encoding: unused + * - decoding: May be set by the user before opening the decoder if known + * e.g. from the container. During decoding, the decoder may + * overwrite those values as required while parsing the data. + */ + int coded_width, coded_height; + +#if FF_API_ASPECT_EXTENDED +#define FF_ASPECT_EXTENDED 15 +#endif + + /** + * the number of pictures in a group of pictures, or 0 for intra_only + * - encoding: Set by user. + * - decoding: unused + */ + int gop_size; + + /** + * Pixel format, see AV_PIX_FMT_xxx. + * May be set by the demuxer if known from headers. + * May be overridden by the decoder if it knows better. + * + * @note This field may not match the value of the last + * AVFrame outputted by avcodec_decode_video2 due frame + * reordering. + * + * - encoding: Set by user. + * - decoding: Set by user if known, overridden by libavcodec while + * parsing the data. + */ + enum AVPixelFormat pix_fmt; + +#if FF_API_MOTION_EST + /** + * This option does nothing + * @deprecated use codec private options instead + */ + attribute_deprecated int me_method; +#endif + + /** + * If non NULL, 'draw_horiz_band' is called by the libavcodec + * decoder to draw a horizontal band. It improves cache usage. Not + * all codecs can do that. You must check the codec capabilities + * beforehand. + * When multithreading is used, it may be called from multiple threads + * at the same time; threads might draw different parts of the same AVFrame, + * or multiple AVFrames, and there is no guarantee that slices will be drawn + * in order. + * The function is also used by hardware acceleration APIs. + * It is called at least once during frame decoding to pass + * the data needed for hardware render. + * In that mode instead of pixel data, AVFrame points to + * a structure specific to the acceleration API. The application + * reads the structure and can change some fields to indicate progress + * or mark state. + * - encoding: unused + * - decoding: Set by user. + * @param height the height of the slice + * @param y the y position of the slice + * @param type 1->top field, 2->bottom field, 3->frame + * @param offset offset into the AVFrame.data from which the slice should be read + */ + void (*draw_horiz_band)(struct AVCodecContext *s, + const AVFrame *src, int offset[AV_NUM_DATA_POINTERS], + int y, int type, int height); + + /** + * callback to negotiate the pixelFormat + * @param fmt is the list of formats which are supported by the codec, + * it is terminated by -1 as 0 is a valid format, the formats are ordered by quality. + * The first is always the native one. + * @note The callback may be called again immediately if initialization for + * the selected (hardware-accelerated) pixel format failed. + * @warning Behavior is undefined if the callback returns a value not + * in the fmt list of formats. + * @return the chosen format + * - encoding: unused + * - decoding: Set by user, if not set the native format will be chosen. + */ + enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt); + + /** + * maximum number of B-frames between non-B-frames + * Note: The output will be delayed by max_b_frames+1 relative to the input. + * - encoding: Set by user. + * - decoding: unused + */ + int max_b_frames; + + /** + * qscale factor between IP and B-frames + * If > 0 then the last P-frame quantizer will be used (q= lastp_q*factor+offset). + * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset). + * - encoding: Set by user. + * - decoding: unused + */ + float b_quant_factor; + +#if FF_API_RC_STRATEGY + /** @deprecated use codec private option instead */ + attribute_deprecated int rc_strategy; +#define FF_RC_STRATEGY_XVID 1 +#endif + + int b_frame_strategy; + + /** + * qscale offset between IP and B-frames + * - encoding: Set by user. + * - decoding: unused + */ + float b_quant_offset; + + /** + * Size of the frame reordering buffer in the decoder. + * For MPEG-2 it is 1 IPB or 0 low delay IP. + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int has_b_frames; + + /** + * 0-> h263 quant 1-> mpeg quant + * - encoding: Set by user. + * - decoding: unused + */ + int mpeg_quant; + + /** + * qscale factor between P and I-frames + * If > 0 then the last p frame quantizer will be used (q= lastp_q*factor+offset). + * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset). + * - encoding: Set by user. + * - decoding: unused + */ + float i_quant_factor; + + /** + * qscale offset between P and I-frames + * - encoding: Set by user. + * - decoding: unused + */ + float i_quant_offset; + + /** + * luminance masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float lumi_masking; + + /** + * temporary complexity masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float temporal_cplx_masking; + + /** + * spatial complexity masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float spatial_cplx_masking; + + /** + * p block masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float p_masking; + + /** + * darkness masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float dark_masking; + + /** + * slice count + * - encoding: Set by libavcodec. + * - decoding: Set by user (or 0). + */ + int slice_count; + /** + * prediction method (needed for huffyuv) + * - encoding: Set by user. + * - decoding: unused + */ + int prediction_method; +#define FF_PRED_LEFT 0 +#define FF_PRED_PLANE 1 +#define FF_PRED_MEDIAN 2 + + /** + * slice offsets in the frame in bytes + * - encoding: Set/allocated by libavcodec. + * - decoding: Set/allocated by user (or NULL). + */ + int *slice_offset; + + /** + * sample aspect ratio (0 if unknown) + * That is the width of a pixel divided by the height of the pixel. + * Numerator and denominator must be relatively prime and smaller than 256 for some video standards. + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + AVRational sample_aspect_ratio; + + /** + * motion estimation comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_cmp; + /** + * subpixel motion estimation comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_sub_cmp; + /** + * macroblock comparison function (not supported yet) + * - encoding: Set by user. + * - decoding: unused + */ + int mb_cmp; + /** + * interlaced DCT comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int ildct_cmp; +#define FF_CMP_SAD 0 +#define FF_CMP_SSE 1 +#define FF_CMP_SATD 2 +#define FF_CMP_DCT 3 +#define FF_CMP_PSNR 4 +#define FF_CMP_BIT 5 +#define FF_CMP_RD 6 +#define FF_CMP_ZERO 7 +#define FF_CMP_VSAD 8 +#define FF_CMP_VSSE 9 +#define FF_CMP_NSSE 10 +#define FF_CMP_W53 11 +#define FF_CMP_W97 12 +#define FF_CMP_DCTMAX 13 +#define FF_CMP_DCT264 14 +#define FF_CMP_CHROMA 256 + + /** + * ME diamond size & shape + * - encoding: Set by user. + * - decoding: unused + */ + int dia_size; + + /** + * amount of previous MV predictors (2a+1 x 2a+1 square) + * - encoding: Set by user. + * - decoding: unused + */ + int last_predictor_count; + + /** + * prepass for motion estimation + * - encoding: Set by user. + * - decoding: unused + */ + int pre_me; + + /** + * motion estimation prepass comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_pre_cmp; + + /** + * ME prepass diamond size & shape + * - encoding: Set by user. + * - decoding: unused + */ + int pre_dia_size; + + /** + * subpel ME quality + * - encoding: Set by user. + * - decoding: unused + */ + int me_subpel_quality; + +#if FF_API_AFD + /** + * DTG active format information (additional aspect ratio + * information only used in DVB MPEG-2 transport streams) + * 0 if not set. + * + * - encoding: unused + * - decoding: Set by decoder. + * @deprecated Deprecated in favor of AVSideData + */ + attribute_deprecated int dtg_active_format; +#define FF_DTG_AFD_SAME 8 +#define FF_DTG_AFD_4_3 9 +#define FF_DTG_AFD_16_9 10 +#define FF_DTG_AFD_14_9 11 +#define FF_DTG_AFD_4_3_SP_14_9 13 +#define FF_DTG_AFD_16_9_SP_14_9 14 +#define FF_DTG_AFD_SP_4_3 15 +#endif /* FF_API_AFD */ + + /** + * maximum motion estimation search range in subpel units + * If 0 then no limit. + * + * - encoding: Set by user. + * - decoding: unused + */ + int me_range; + +#if FF_API_QUANT_BIAS + /** + * @deprecated use encoder private option instead + */ + attribute_deprecated int intra_quant_bias; +#define FF_DEFAULT_QUANT_BIAS 999999 + + /** + * @deprecated use encoder private option instead + */ + attribute_deprecated int inter_quant_bias; +#endif + + /** + * slice flags + * - encoding: unused + * - decoding: Set by user. + */ + int slice_flags; +#define SLICE_FLAG_CODED_ORDER 0x0001 ///< draw_horiz_band() is called in coded order instead of display +#define SLICE_FLAG_ALLOW_FIELD 0x0002 ///< allow draw_horiz_band() with field slices (MPEG2 field pics) +#define SLICE_FLAG_ALLOW_PLANE 0x0004 ///< allow draw_horiz_band() with 1 component at a time (SVQ1) + +#if FF_API_XVMC + /** + * XVideo Motion Acceleration + * - encoding: forbidden + * - decoding: set by decoder + * @deprecated XvMC doesn't need it anymore. + */ + attribute_deprecated int xvmc_acceleration; +#endif /* FF_API_XVMC */ + + /** + * macroblock decision mode + * - encoding: Set by user. + * - decoding: unused + */ + int mb_decision; +#define FF_MB_DECISION_SIMPLE 0 ///< uses mb_cmp +#define FF_MB_DECISION_BITS 1 ///< chooses the one which needs the fewest bits +#define FF_MB_DECISION_RD 2 ///< rate distortion + + /** + * custom intra quantization matrix + * - encoding: Set by user, can be NULL. + * - decoding: Set by libavcodec. + */ + uint16_t *intra_matrix; + + /** + * custom inter quantization matrix + * - encoding: Set by user, can be NULL. + * - decoding: Set by libavcodec. + */ + uint16_t *inter_matrix; + + /** + * scene change detection threshold + * 0 is default, larger means fewer detected scene changes. + * - encoding: Set by user. + * - decoding: unused + */ + int scenechange_threshold; + + /** + * noise reduction strength + * - encoding: Set by user. + * - decoding: unused + */ + int noise_reduction; + +#if FF_API_MPV_OPT + /** + * @deprecated this field is unused + */ + attribute_deprecated + int me_threshold; + + /** + * @deprecated this field is unused + */ + attribute_deprecated + int mb_threshold; +#endif + + /** + * precision of the intra DC coefficient - 8 + * - encoding: Set by user. + * - decoding: Set by libavcodec + */ + int intra_dc_precision; + + /** + * Number of macroblock rows at the top which are skipped. + * - encoding: unused + * - decoding: Set by user. + */ + int skip_top; + + /** + * Number of macroblock rows at the bottom which are skipped. + * - encoding: unused + * - decoding: Set by user. + */ + int skip_bottom; + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + float border_masking; +#endif + + /** + * minimum MB lagrange multipler + * - encoding: Set by user. + * - decoding: unused + */ + int mb_lmin; + + /** + * maximum MB lagrange multipler + * - encoding: Set by user. + * - decoding: unused + */ + int mb_lmax; + + /** + * + * - encoding: Set by user. + * - decoding: unused + */ + int me_penalty_compensation; + + /** + * + * - encoding: Set by user. + * - decoding: unused + */ + int bidir_refine; + + /** + * + * - encoding: Set by user. + * - decoding: unused + */ + int brd_scale; + + /** + * minimum GOP size + * - encoding: Set by user. + * - decoding: unused + */ + int keyint_min; + + /** + * number of reference frames + * - encoding: Set by user. + * - decoding: Set by lavc. + */ + int refs; + + /** + * chroma qp offset from luma + * - encoding: Set by user. + * - decoding: unused + */ + int chromaoffset; + +#if FF_API_UNUSED_MEMBERS + /** + * Multiplied by qscale for each frame and added to scene_change_score. + * - encoding: Set by user. + * - decoding: unused + */ + attribute_deprecated int scenechange_factor; +#endif + + /** + * + * Note: Value depends upon the compare function used for fullpel ME. + * - encoding: Set by user. + * - decoding: unused + */ + int mv0_threshold; + + /** + * Adjust sensitivity of b_frame_strategy 1. + * - encoding: Set by user. + * - decoding: unused + */ + int b_sensitivity; + + /** + * Chromaticity coordinates of the source primaries. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorPrimaries color_primaries; + + /** + * Color Transfer Characteristic. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorTransferCharacteristic color_trc; + + /** + * YUV colorspace type. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorSpace colorspace; + + /** + * MPEG vs JPEG YUV range. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorRange color_range; + + /** + * This defines the location of chroma samples. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVChromaLocation chroma_sample_location; + + /** + * Number of slices. + * Indicates number of picture subdivisions. Used for parallelized + * decoding. + * - encoding: Set by user + * - decoding: unused + */ + int slices; + + /** Field order + * - encoding: set by libavcodec + * - decoding: Set by user. + */ + enum AVFieldOrder field_order; + + /* audio only */ + int sample_rate; ///< samples per second + int channels; ///< number of audio channels + + /** + * audio sample format + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + enum AVSampleFormat sample_fmt; ///< sample format + + /* The following data should not be initialized. */ + /** + * Number of samples per channel in an audio frame. + * + * - encoding: set by libavcodec in avcodec_open2(). Each submitted frame + * except the last must contain exactly frame_size samples per channel. + * May be 0 when the codec has AV_CODEC_CAP_VARIABLE_FRAME_SIZE set, then the + * frame size is not restricted. + * - decoding: may be set by some decoders to indicate constant frame size + */ + int frame_size; + + /** + * Frame counter, set by libavcodec. + * + * - decoding: total number of frames returned from the decoder so far. + * - encoding: total number of frames passed to the encoder so far. + * + * @note the counter is not incremented if encoding/decoding resulted in + * an error. + */ + int frame_number; + + /** + * number of bytes per packet if constant and known or 0 + * Used by some WAV based audio codecs. + */ + int block_align; + + /** + * Audio cutoff bandwidth (0 means "automatic") + * - encoding: Set by user. + * - decoding: unused + */ + int cutoff; + + /** + * Audio channel layout. + * - encoding: set by user. + * - decoding: set by user, may be overwritten by libavcodec. + */ + uint64_t channel_layout; + + /** + * Request decoder to use this channel layout if it can (0 for default) + * - encoding: unused + * - decoding: Set by user. + */ + uint64_t request_channel_layout; + + /** + * Type of service that the audio stream conveys. + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + enum AVAudioServiceType audio_service_type; + + /** + * desired sample format + * - encoding: Not used. + * - decoding: Set by user. + * Decoder will decode to this format if it can. + */ + enum AVSampleFormat request_sample_fmt; + + /** + * This callback is called at the beginning of each frame to get data + * buffer(s) for it. There may be one contiguous buffer for all the data or + * there may be a buffer per each data plane or anything in between. What + * this means is, you may set however many entries in buf[] you feel necessary. + * Each buffer must be reference-counted using the AVBuffer API (see description + * of buf[] below). + * + * The following fields will be set in the frame before this callback is + * called: + * - format + * - width, height (video only) + * - sample_rate, channel_layout, nb_samples (audio only) + * Their values may differ from the corresponding values in + * AVCodecContext. This callback must use the frame values, not the codec + * context values, to calculate the required buffer size. + * + * This callback must fill the following fields in the frame: + * - data[] + * - linesize[] + * - extended_data: + * * if the data is planar audio with more than 8 channels, then this + * callback must allocate and fill extended_data to contain all pointers + * to all data planes. data[] must hold as many pointers as it can. + * extended_data must be allocated with av_malloc() and will be freed in + * av_frame_unref(). + * * otherwise exended_data must point to data + * - buf[] must contain one or more pointers to AVBufferRef structures. Each of + * the frame's data and extended_data pointers must be contained in these. That + * is, one AVBufferRef for each allocated chunk of memory, not necessarily one + * AVBufferRef per data[] entry. See: av_buffer_create(), av_buffer_alloc(), + * and av_buffer_ref(). + * - extended_buf and nb_extended_buf must be allocated with av_malloc() by + * this callback and filled with the extra buffers if there are more + * buffers than buf[] can hold. extended_buf will be freed in + * av_frame_unref(). + * + * If AV_CODEC_CAP_DR1 is not set then get_buffer2() must call + * avcodec_default_get_buffer2() instead of providing buffers allocated by + * some other means. + * + * Each data plane must be aligned to the maximum required by the target + * CPU. + * + * @see avcodec_default_get_buffer2() + * + * Video: + * + * If AV_GET_BUFFER_FLAG_REF is set in flags then the frame may be reused + * (read and/or written to if it is writable) later by libavcodec. + * + * avcodec_align_dimensions2() should be used to find the required width and + * height, as they normally need to be rounded up to the next multiple of 16. + * + * Some decoders do not support linesizes changing between frames. + * + * If frame multithreading is used and thread_safe_callbacks is set, + * this callback may be called from a different thread, but not from more + * than one at once. Does not need to be reentrant. + * + * @see avcodec_align_dimensions2() + * + * Audio: + * + * Decoders request a buffer of a particular size by setting + * AVFrame.nb_samples prior to calling get_buffer2(). The decoder may, + * however, utilize only part of the buffer by setting AVFrame.nb_samples + * to a smaller value in the output frame. + * + * As a convenience, av_samples_get_buffer_size() and + * av_samples_fill_arrays() in libavutil may be used by custom get_buffer2() + * functions to find the required data size and to fill data pointers and + * linesize. In AVFrame.linesize, only linesize[0] may be set for audio + * since all planes must be the same size. + * + * @see av_samples_get_buffer_size(), av_samples_fill_arrays() + * + * - encoding: unused + * - decoding: Set by libavcodec, user can override. + */ + int (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, int flags); + + /** + * If non-zero, the decoded audio and video frames returned from + * avcodec_decode_video2() and avcodec_decode_audio4() are reference-counted + * and are valid indefinitely. The caller must free them with + * av_frame_unref() when they are not needed anymore. + * Otherwise, the decoded frames must not be freed by the caller and are + * only valid until the next decode call. + * + * - encoding: unused + * - decoding: set by the caller before avcodec_open2(). + */ + int refcounted_frames; + + /* - encoding parameters */ + float qcompress; ///< amount of qscale change between easy & hard scenes (0.0-1.0) + float qblur; ///< amount of qscale smoothing over time (0.0-1.0) + + /** + * minimum quantizer + * - encoding: Set by user. + * - decoding: unused + */ + int qmin; + + /** + * maximum quantizer + * - encoding: Set by user. + * - decoding: unused + */ + int qmax; + + /** + * maximum quantizer difference between frames + * - encoding: Set by user. + * - decoding: unused + */ + int max_qdiff; + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + float rc_qsquish; + + attribute_deprecated + float rc_qmod_amp; + attribute_deprecated + int rc_qmod_freq; +#endif + + /** + * decoder bitstream buffer size + * - encoding: Set by user. + * - decoding: unused + */ + int rc_buffer_size; + + /** + * ratecontrol override, see RcOverride + * - encoding: Allocated/set/freed by user. + * - decoding: unused + */ + int rc_override_count; + RcOverride *rc_override; + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + const char *rc_eq; +#endif + + /** + * maximum bitrate + * - encoding: Set by user. + * - decoding: Set by user, may be overwritten by libavcodec. + */ + int64_t rc_max_rate; + + /** + * minimum bitrate + * - encoding: Set by user. + * - decoding: unused + */ + int64_t rc_min_rate; + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + float rc_buffer_aggressivity; + + attribute_deprecated + float rc_initial_cplx; +#endif + + /** + * Ratecontrol attempt to use, at maximum, of what can be used without an underflow. + * - encoding: Set by user. + * - decoding: unused. + */ + float rc_max_available_vbv_use; + + /** + * Ratecontrol attempt to use, at least, times the amount needed to prevent a vbv overflow. + * - encoding: Set by user. + * - decoding: unused. + */ + float rc_min_vbv_overflow_use; + + /** + * Number of bits which should be loaded into the rc buffer before decoding starts. + * - encoding: Set by user. + * - decoding: unused + */ + int rc_initial_buffer_occupancy; + +#if FF_API_CODER_TYPE +#define FF_CODER_TYPE_VLC 0 +#define FF_CODER_TYPE_AC 1 +#define FF_CODER_TYPE_RAW 2 +#define FF_CODER_TYPE_RLE 3 +#if FF_API_UNUSED_MEMBERS +#define FF_CODER_TYPE_DEFLATE 4 +#endif /* FF_API_UNUSED_MEMBERS */ + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + int coder_type; +#endif /* FF_API_CODER_TYPE */ + + /** + * context model + * - encoding: Set by user. + * - decoding: unused + */ + int context_model; + +#if FF_API_MPV_OPT + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + int lmin; + + /** + * @deprecated use encoder private options instead + */ + attribute_deprecated + int lmax; +#endif + + /** + * frame skip threshold + * - encoding: Set by user. + * - decoding: unused + */ + int frame_skip_threshold; + + /** + * frame skip factor + * - encoding: Set by user. + * - decoding: unused + */ + int frame_skip_factor; + + /** + * frame skip exponent + * - encoding: Set by user. + * - decoding: unused + */ + int frame_skip_exp; + + /** + * frame skip comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int frame_skip_cmp; + + /** + * trellis RD quantization + * - encoding: Set by user. + * - decoding: unused + */ + int trellis; + + /** + * - encoding: Set by user. + * - decoding: unused + */ + int min_prediction_order; + + /** + * - encoding: Set by user. + * - decoding: unused + */ + int max_prediction_order; + + /** + * GOP timecode frame start number + * - encoding: Set by user, in non drop frame format + * - decoding: Set by libavcodec (timecode in the 25 bits format, -1 if unset) + */ + int64_t timecode_frame_start; + +#if FF_API_RTP_CALLBACK + /** + * @deprecated unused + */ + /* The RTP callback: This function is called */ + /* every time the encoder has a packet to send. */ + /* It depends on the encoder if the data starts */ + /* with a Start Code (it should). H.263 does. */ + /* mb_nb contains the number of macroblocks */ + /* encoded in the RTP payload. */ + attribute_deprecated + void (*rtp_callback)(struct AVCodecContext *avctx, void *data, int size, int mb_nb); +#endif + + int rtp_payload_size; /* The size of the RTP payload: the coder will */ + /* do its best to deliver a chunk with size */ + /* below rtp_payload_size, the chunk will start */ + /* with a start code on some codecs like H.263. */ + /* This doesn't take account of any particular */ + /* headers inside the transmitted RTP payload. */ + +#if FF_API_STAT_BITS + /* statistics, used for 2-pass encoding */ + attribute_deprecated + int mv_bits; + attribute_deprecated + int header_bits; + attribute_deprecated + int i_tex_bits; + attribute_deprecated + int p_tex_bits; + attribute_deprecated + int i_count; + attribute_deprecated + int p_count; + attribute_deprecated + int skip_count; + attribute_deprecated + int misc_bits; + + /** @deprecated this field is unused */ + attribute_deprecated + int frame_bits; +#endif + + /** + * pass1 encoding statistics output buffer + * - encoding: Set by libavcodec. + * - decoding: unused + */ + char *stats_out; + + /** + * pass2 encoding statistics input buffer + * Concatenated stuff from stats_out of pass1 should be placed here. + * - encoding: Allocated/set/freed by user. + * - decoding: unused + */ + char *stats_in; + + /** + * Work around bugs in encoders which sometimes cannot be detected automatically. + * - encoding: Set by user + * - decoding: Set by user + */ + int workaround_bugs; +#define FF_BUG_AUTODETECT 1 ///< autodetection +#if FF_API_OLD_MSMPEG4 +#define FF_BUG_OLD_MSMPEG4 2 +#endif +#define FF_BUG_XVID_ILACE 4 +#define FF_BUG_UMP4 8 +#define FF_BUG_NO_PADDING 16 +#define FF_BUG_AMV 32 +#if FF_API_AC_VLC +#define FF_BUG_AC_VLC 0 ///< Will be removed, libavcodec can now handle these non-compliant files by default. +#endif +#define FF_BUG_QPEL_CHROMA 64 +#define FF_BUG_STD_QPEL 128 +#define FF_BUG_QPEL_CHROMA2 256 +#define FF_BUG_DIRECT_BLOCKSIZE 512 +#define FF_BUG_EDGE 1024 +#define FF_BUG_HPEL_CHROMA 2048 +#define FF_BUG_DC_CLIP 4096 +#define FF_BUG_MS 8192 ///< Work around various bugs in Microsoft's broken decoders. +#define FF_BUG_TRUNCATED 16384 + + /** + * strictly follow the standard (MPEG4, ...). + * - encoding: Set by user. + * - decoding: Set by user. + * Setting this to STRICT or higher means the encoder and decoder will + * generally do stupid things, whereas setting it to unofficial or lower + * will mean the encoder might produce output that is not supported by all + * spec-compliant decoders. Decoders don't differentiate between normal, + * unofficial and experimental (that is, they always try to decode things + * when they can) unless they are explicitly asked to behave stupidly + * (=strictly conform to the specs) + */ + int strict_std_compliance; +#define FF_COMPLIANCE_VERY_STRICT 2 ///< Strictly conform to an older more strict version of the spec or reference software. +#define FF_COMPLIANCE_STRICT 1 ///< Strictly conform to all the things in the spec no matter what consequences. +#define FF_COMPLIANCE_NORMAL 0 +#define FF_COMPLIANCE_UNOFFICIAL -1 ///< Allow unofficial extensions +#define FF_COMPLIANCE_EXPERIMENTAL -2 ///< Allow nonstandardized experimental things. + + /** + * error concealment flags + * - encoding: unused + * - decoding: Set by user. + */ + int error_concealment; +#define FF_EC_GUESS_MVS 1 +#define FF_EC_DEBLOCK 2 +#define FF_EC_FAVOR_INTER 256 + + /** + * debug + * - encoding: Set by user. + * - decoding: Set by user. + */ + int debug; +#define FF_DEBUG_PICT_INFO 1 +#define FF_DEBUG_RC 2 +#define FF_DEBUG_BITSTREAM 4 +#define FF_DEBUG_MB_TYPE 8 +#define FF_DEBUG_QP 16 +#if FF_API_DEBUG_MV +/** + * @deprecated this option does nothing + */ +#define FF_DEBUG_MV 32 +#endif +#define FF_DEBUG_DCT_COEFF 0x00000040 +#define FF_DEBUG_SKIP 0x00000080 +#define FF_DEBUG_STARTCODE 0x00000100 +#if FF_API_UNUSED_MEMBERS +#define FF_DEBUG_PTS 0x00000200 +#endif /* FF_API_UNUSED_MEMBERS */ +#define FF_DEBUG_ER 0x00000400 +#define FF_DEBUG_MMCO 0x00000800 +#define FF_DEBUG_BUGS 0x00001000 +#if FF_API_DEBUG_MV +#define FF_DEBUG_VIS_QP 0x00002000 ///< only access through AVOptions from outside libavcodec +#define FF_DEBUG_VIS_MB_TYPE 0x00004000 ///< only access through AVOptions from outside libavcodec +#endif +#define FF_DEBUG_BUFFERS 0x00008000 +#define FF_DEBUG_THREADS 0x00010000 +#define FF_DEBUG_GREEN_MD 0x00800000 +#define FF_DEBUG_NOMC 0x01000000 + +#if FF_API_DEBUG_MV + /** + * debug + * Code outside libavcodec should access this field using AVOptions + * - encoding: Set by user. + * - decoding: Set by user. + */ + int debug_mv; +#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames +#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames +#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames +#endif + + /** + * Error recognition; may misdetect some more or less valid parts as errors. + * - encoding: unused + * - decoding: Set by user. + */ + int err_recognition; + +/** + * Verify checksums embedded in the bitstream (could be of either encoded or + * decoded data, depending on the codec) and print an error message on mismatch. + * If AV_EF_EXPLODE is also set, a mismatching checksum will result in the + * decoder returning an error. + */ +#define AV_EF_CRCCHECK (1<<0) +#define AV_EF_BITSTREAM (1<<1) ///< detect bitstream specification deviations +#define AV_EF_BUFFER (1<<2) ///< detect improper bitstream length +#define AV_EF_EXPLODE (1<<3) ///< abort decoding on minor error detection + +#define AV_EF_IGNORE_ERR (1<<15) ///< ignore errors and continue +#define AV_EF_CAREFUL (1<<16) ///< consider things that violate the spec, are fast to calculate and have not been seen in the wild as errors +#define AV_EF_COMPLIANT (1<<17) ///< consider all spec non compliances as errors +#define AV_EF_AGGRESSIVE (1<<18) ///< consider things that a sane encoder should not do as an error + + + /** + * opaque 64bit number (generally a PTS) that will be reordered and + * output in AVFrame.reordered_opaque + * - encoding: unused + * - decoding: Set by user. + */ + int64_t reordered_opaque; + + /** + * Hardware accelerator in use + * - encoding: unused. + * - decoding: Set by libavcodec + */ + struct AVHWAccel *hwaccel; + + /** + * Hardware accelerator context. + * For some hardware accelerators, a global context needs to be + * provided by the user. In that case, this holds display-dependent + * data FFmpeg cannot instantiate itself. Please refer to the + * FFmpeg HW accelerator documentation to know how to fill this + * is. e.g. for VA API, this is a struct vaapi_context. + * - encoding: unused + * - decoding: Set by user + */ + void *hwaccel_context; + + /** + * error + * - encoding: Set by libavcodec if flags & AV_CODEC_FLAG_PSNR. + * - decoding: unused + */ + uint64_t error[AV_NUM_DATA_POINTERS]; + + /** + * DCT algorithm, see FF_DCT_* below + * - encoding: Set by user. + * - decoding: unused + */ + int dct_algo; +#define FF_DCT_AUTO 0 +#define FF_DCT_FASTINT 1 +#define FF_DCT_INT 2 +#define FF_DCT_MMX 3 +#define FF_DCT_ALTIVEC 5 +#define FF_DCT_FAAN 6 + + /** + * IDCT algorithm, see FF_IDCT_* below. + * - encoding: Set by user. + * - decoding: Set by user. + */ + int idct_algo; +#define FF_IDCT_AUTO 0 +#define FF_IDCT_INT 1 +#define FF_IDCT_SIMPLE 2 +#define FF_IDCT_SIMPLEMMX 3 +#define FF_IDCT_ARM 7 +#define FF_IDCT_ALTIVEC 8 +#if FF_API_ARCH_SH4 +#define FF_IDCT_SH4 9 +#endif +#define FF_IDCT_SIMPLEARM 10 +#if FF_API_UNUSED_MEMBERS +#define FF_IDCT_IPP 13 +#endif /* FF_API_UNUSED_MEMBERS */ +#define FF_IDCT_XVID 14 +#if FF_API_IDCT_XVIDMMX +#define FF_IDCT_XVIDMMX 14 +#endif /* FF_API_IDCT_XVIDMMX */ +#define FF_IDCT_SIMPLEARMV5TE 16 +#define FF_IDCT_SIMPLEARMV6 17 +#if FF_API_ARCH_SPARC +#define FF_IDCT_SIMPLEVIS 18 +#endif +#define FF_IDCT_FAAN 20 +#define FF_IDCT_SIMPLENEON 22 +#if FF_API_ARCH_ALPHA +#define FF_IDCT_SIMPLEALPHA 23 +#endif +#define FF_IDCT_SIMPLEAUTO 128 + + /** + * bits per sample/pixel from the demuxer (needed for huffyuv). + * - encoding: Set by libavcodec. + * - decoding: Set by user. + */ + int bits_per_coded_sample; + + /** + * Bits per sample/pixel of internal libavcodec pixel/sample format. + * - encoding: set by user. + * - decoding: set by libavcodec. + */ + int bits_per_raw_sample; + +#if FF_API_LOWRES + /** + * low resolution decoding, 1-> 1/2 size, 2->1/4 size + * - encoding: unused + * - decoding: Set by user. + * Code outside libavcodec should access this field using: + * av_codec_{get,set}_lowres(avctx) + */ + int lowres; +#endif + +#if FF_API_CODED_FRAME + /** + * the picture in the bitstream + * - encoding: Set by libavcodec. + * - decoding: unused + * + * @deprecated use the quality factor packet side data instead + */ + attribute_deprecated AVFrame *coded_frame; +#endif + + /** + * thread count + * is used to decide how many independent tasks should be passed to execute() + * - encoding: Set by user. + * - decoding: Set by user. + */ + int thread_count; + + /** + * Which multithreading methods to use. + * Use of FF_THREAD_FRAME will increase decoding delay by one frame per thread, + * so clients which cannot provide future frames should not use it. + * + * - encoding: Set by user, otherwise the default is used. + * - decoding: Set by user, otherwise the default is used. + */ + int thread_type; +#define FF_THREAD_FRAME 1 ///< Decode more than one frame at once +#define FF_THREAD_SLICE 2 ///< Decode more than one part of a single frame at once + + /** + * Which multithreading methods are in use by the codec. + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int active_thread_type; + + /** + * Set by the client if its custom get_buffer() callback can be called + * synchronously from another thread, which allows faster multithreaded decoding. + * draw_horiz_band() will be called from other threads regardless of this setting. + * Ignored if the default get_buffer() is used. + * - encoding: Set by user. + * - decoding: Set by user. + */ + int thread_safe_callbacks; + + /** + * The codec may call this to execute several independent things. + * It will return only after finishing all tasks. + * The user may replace this with some multithreaded implementation, + * the default implementation will execute the parts serially. + * @param count the number of things to execute + * - encoding: Set by libavcodec, user can override. + * - decoding: Set by libavcodec, user can override. + */ + int (*execute)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg), void *arg2, int *ret, int count, int size); + + /** + * The codec may call this to execute several independent things. + * It will return only after finishing all tasks. + * The user may replace this with some multithreaded implementation, + * the default implementation will execute the parts serially. + * Also see avcodec_thread_init and e.g. the --enable-pthread configure option. + * @param c context passed also to func + * @param count the number of things to execute + * @param arg2 argument passed unchanged to func + * @param ret return values of executed functions, must have space for "count" values. May be NULL. + * @param func function that will be called count times, with jobnr from 0 to count-1. + * threadnr will be in the range 0 to c->thread_count-1 < MAX_THREADS and so that no + * two instances of func executing at the same time will have the same threadnr. + * @return always 0 currently, but code should handle a future improvement where when any call to func + * returns < 0 no further calls to func may be done and < 0 is returned. + * - encoding: Set by libavcodec, user can override. + * - decoding: Set by libavcodec, user can override. + */ + int (*execute2)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg, int jobnr, int threadnr), void *arg2, int *ret, int count); + + /** + * noise vs. sse weight for the nsse comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int nsse_weight; + + /** + * profile + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int profile; +#define FF_PROFILE_UNKNOWN -99 +#define FF_PROFILE_RESERVED -100 + +#define FF_PROFILE_AAC_MAIN 0 +#define FF_PROFILE_AAC_LOW 1 +#define FF_PROFILE_AAC_SSR 2 +#define FF_PROFILE_AAC_LTP 3 +#define FF_PROFILE_AAC_HE 4 +#define FF_PROFILE_AAC_HE_V2 28 +#define FF_PROFILE_AAC_LD 22 +#define FF_PROFILE_AAC_ELD 38 +#define FF_PROFILE_MPEG2_AAC_LOW 128 +#define FF_PROFILE_MPEG2_AAC_HE 131 + +#define FF_PROFILE_DTS 20 +#define FF_PROFILE_DTS_ES 30 +#define FF_PROFILE_DTS_96_24 40 +#define FF_PROFILE_DTS_HD_HRA 50 +#define FF_PROFILE_DTS_HD_MA 60 +#define FF_PROFILE_DTS_EXPRESS 70 + +#define FF_PROFILE_MPEG2_422 0 +#define FF_PROFILE_MPEG2_HIGH 1 +#define FF_PROFILE_MPEG2_SS 2 +#define FF_PROFILE_MPEG2_SNR_SCALABLE 3 +#define FF_PROFILE_MPEG2_MAIN 4 +#define FF_PROFILE_MPEG2_SIMPLE 5 + +#define FF_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag +#define FF_PROFILE_H264_INTRA (1<<11) // 8+3; constraint_set3_flag + +#define FF_PROFILE_H264_BASELINE 66 +#define FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED) +#define FF_PROFILE_H264_MAIN 77 +#define FF_PROFILE_H264_EXTENDED 88 +#define FF_PROFILE_H264_HIGH 100 +#define FF_PROFILE_H264_HIGH_10 110 +#define FF_PROFILE_H264_HIGH_10_INTRA (110|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_HIGH_422 122 +#define FF_PROFILE_H264_HIGH_422_INTRA (122|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_HIGH_444 144 +#define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244 +#define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_CAVLC_444 44 + +#define FF_PROFILE_VC1_SIMPLE 0 +#define FF_PROFILE_VC1_MAIN 1 +#define FF_PROFILE_VC1_COMPLEX 2 +#define FF_PROFILE_VC1_ADVANCED 3 + +#define FF_PROFILE_MPEG4_SIMPLE 0 +#define FF_PROFILE_MPEG4_SIMPLE_SCALABLE 1 +#define FF_PROFILE_MPEG4_CORE 2 +#define FF_PROFILE_MPEG4_MAIN 3 +#define FF_PROFILE_MPEG4_N_BIT 4 +#define FF_PROFILE_MPEG4_SCALABLE_TEXTURE 5 +#define FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6 +#define FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7 +#define FF_PROFILE_MPEG4_HYBRID 8 +#define FF_PROFILE_MPEG4_ADVANCED_REAL_TIME 9 +#define FF_PROFILE_MPEG4_CORE_SCALABLE 10 +#define FF_PROFILE_MPEG4_ADVANCED_CODING 11 +#define FF_PROFILE_MPEG4_ADVANCED_CORE 12 +#define FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13 +#define FF_PROFILE_MPEG4_SIMPLE_STUDIO 14 +#define FF_PROFILE_MPEG4_ADVANCED_SIMPLE 15 + +#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0 0 +#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1 1 +#define FF_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION 2 +#define FF_PROFILE_JPEG2000_DCINEMA_2K 3 +#define FF_PROFILE_JPEG2000_DCINEMA_4K 4 + +#define FF_PROFILE_VP9_0 0 +#define FF_PROFILE_VP9_1 1 +#define FF_PROFILE_VP9_2 2 +#define FF_PROFILE_VP9_3 3 + +#define FF_PROFILE_HEVC_MAIN 1 +#define FF_PROFILE_HEVC_MAIN_10 2 +#define FF_PROFILE_HEVC_MAIN_STILL_PICTURE 3 +#define FF_PROFILE_HEVC_REXT 4 + + /** + * level + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + int level; +#define FF_LEVEL_UNKNOWN -99 + + /** + * Skip loop filtering for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_loop_filter; + + /** + * Skip IDCT/dequantization for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_idct; + + /** + * Skip decoding for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_frame; + + /** + * Header containing style information for text subtitles. + * For SUBTITLE_ASS subtitle type, it should contain the whole ASS + * [Script Info] and [V4+ Styles] section, plus the [Events] line and + * the Format line following. It shouldn't include any Dialogue line. + * - encoding: Set/allocated/freed by user (before avcodec_open2()) + * - decoding: Set/allocated/freed by libavcodec (by avcodec_open2()) + */ + uint8_t *subtitle_header; + int subtitle_header_size; + +#if FF_API_ERROR_RATE + /** + * @deprecated use the 'error_rate' private AVOption of the mpegvideo + * encoders + */ + attribute_deprecated + int error_rate; +#endif + +#if FF_API_VBV_DELAY + /** + * VBV delay coded in the last frame (in periods of a 27 MHz clock). + * Used for compliant TS muxing. + * - encoding: Set by libavcodec. + * - decoding: unused. + * @deprecated this value is now exported as a part of + * AV_PKT_DATA_CPB_PROPERTIES packet side data + */ + attribute_deprecated + uint64_t vbv_delay; +#endif + +#if FF_API_SIDEDATA_ONLY_PKT + /** + * Encoding only and set by default. Allow encoders to output packets + * that do not contain any encoded data, only side data. + * + * Some encoders need to output such packets, e.g. to update some stream + * parameters at the end of encoding. + * + * @deprecated this field disables the default behaviour and + * it is kept only for compatibility. + */ + attribute_deprecated + int side_data_only_packets; +#endif + + /** + * Audio only. The number of "priming" samples (padding) inserted by the + * encoder at the beginning of the audio. I.e. this number of leading + * decoded samples must be discarded by the caller to get the original audio + * without leading padding. + * + * - decoding: unused + * - encoding: Set by libavcodec. The timestamps on the output packets are + * adjusted by the encoder so that they always refer to the + * first sample of the data actually contained in the packet, + * including any added padding. E.g. if the timebase is + * 1/samplerate and the timestamp of the first input sample is + * 0, the timestamp of the first output packet will be + * -initial_padding. + */ + int initial_padding; + + /** + * - decoding: For codecs that store a framerate value in the compressed + * bitstream, the decoder may export it here. { 0, 1} when + * unknown. + * - encoding: unused + */ + AVRational framerate; + + /** + * Nominal unaccelerated pixel format, see AV_PIX_FMT_xxx. + * - encoding: unused. + * - decoding: Set by libavcodec before calling get_format() + */ + enum AVPixelFormat sw_pix_fmt; + + /** + * Timebase in which pkt_dts/pts and AVPacket.dts/pts are. + * Code outside libavcodec should access this field using: + * av_codec_{get,set}_pkt_timebase(avctx) + * - encoding unused. + * - decoding set by user. + */ + AVRational pkt_timebase; + + /** + * AVCodecDescriptor + * Code outside libavcodec should access this field using: + * av_codec_{get,set}_codec_descriptor(avctx) + * - encoding: unused. + * - decoding: set by libavcodec. + */ + const AVCodecDescriptor *codec_descriptor; + +#if !FF_API_LOWRES + /** + * low resolution decoding, 1-> 1/2 size, 2->1/4 size + * - encoding: unused + * - decoding: Set by user. + * Code outside libavcodec should access this field using: + * av_codec_{get,set}_lowres(avctx) + */ + int lowres; +#endif + + /** + * Current statistics for PTS correction. + * - decoding: maintained and used by libavcodec, not intended to be used by user apps + * - encoding: unused + */ + int64_t pts_correction_num_faulty_pts; /// Number of incorrect PTS values so far + int64_t pts_correction_num_faulty_dts; /// Number of incorrect DTS values so far + int64_t pts_correction_last_pts; /// PTS of the last frame + int64_t pts_correction_last_dts; /// DTS of the last frame + + /** + * Character encoding of the input subtitles file. + * - decoding: set by user + * - encoding: unused + */ + char *sub_charenc; + + /** + * Subtitles character encoding mode. Formats or codecs might be adjusting + * this setting (if they are doing the conversion themselves for instance). + * - decoding: set by libavcodec + * - encoding: unused + */ + int sub_charenc_mode; +#define FF_SUB_CHARENC_MODE_DO_NOTHING -1 ///< do nothing (demuxer outputs a stream supposed to be already in UTF-8, or the codec is bitmap for instance) +#define FF_SUB_CHARENC_MODE_AUTOMATIC 0 ///< libavcodec will select the mode itself +#define FF_SUB_CHARENC_MODE_PRE_DECODER 1 ///< the AVPacket data needs to be recoded to UTF-8 before being fed to the decoder, requires iconv + + /** + * Skip processing alpha if supported by codec. + * Note that if the format uses pre-multiplied alpha (common with VP6, + * and recommended due to better video quality/compression) + * the image will look as if alpha-blended onto a black background. + * However for formats that do not use pre-multiplied alpha + * there might be serious artefacts (though e.g. libswscale currently + * assumes pre-multiplied alpha anyway). + * Code outside libavcodec should access this field using AVOptions + * + * - decoding: set by user + * - encoding: unused + */ + int skip_alpha; + + /** + * Number of samples to skip after a discontinuity + * - decoding: unused + * - encoding: set by libavcodec + */ + int seek_preroll; + +#if !FF_API_DEBUG_MV + /** + * debug motion vectors + * Code outside libavcodec should access this field using AVOptions + * - encoding: Set by user. + * - decoding: Set by user. + */ + int debug_mv; +#define FF_DEBUG_VIS_MV_P_FOR 0x00000001 //visualize forward predicted MVs of P frames +#define FF_DEBUG_VIS_MV_B_FOR 0x00000002 //visualize forward predicted MVs of B frames +#define FF_DEBUG_VIS_MV_B_BACK 0x00000004 //visualize backward predicted MVs of B frames +#endif + + /** + * custom intra quantization matrix + * Code outside libavcodec should access this field using av_codec_g/set_chroma_intra_matrix() + * - encoding: Set by user, can be NULL. + * - decoding: unused. + */ + uint16_t *chroma_intra_matrix; + + /** + * dump format separator. + * can be ", " or "\n " or anything else + * Code outside libavcodec should access this field using AVOptions + * (NO direct access). + * - encoding: Set by user. + * - decoding: Set by user. + */ + uint8_t *dump_separator; + + /** + * ',' separated list of allowed decoders. + * If NULL then all are allowed + * - encoding: unused + * - decoding: set by user through AVOPtions (NO direct access) + */ + char *codec_whitelist; + + /* + * Properties of the stream that gets decoded + * To be accessed through av_codec_get_properties() (NO direct access) + * - encoding: unused + * - decoding: set by libavcodec + */ + unsigned properties; +#define FF_CODEC_PROPERTY_LOSSLESS 0x00000001 +#define FF_CODEC_PROPERTY_CLOSED_CAPTIONS 0x00000002 + + /** + * Additional data associated with the entire coded stream. + * + * - decoding: unused + * - encoding: may be set by libavcodec after avcodec_open2(). + */ + AVPacketSideData *coded_side_data; + int nb_coded_side_data; + +} AVCodecContext; + +AVRational av_codec_get_pkt_timebase (const AVCodecContext *avctx); +void av_codec_set_pkt_timebase (AVCodecContext *avctx, AVRational val); + +const AVCodecDescriptor *av_codec_get_codec_descriptor(const AVCodecContext *avctx); +void av_codec_set_codec_descriptor(AVCodecContext *avctx, const AVCodecDescriptor *desc); + +unsigned av_codec_get_codec_properties(const AVCodecContext *avctx); + +int av_codec_get_lowres(const AVCodecContext *avctx); +void av_codec_set_lowres(AVCodecContext *avctx, int val); + +int av_codec_get_seek_preroll(const AVCodecContext *avctx); +void av_codec_set_seek_preroll(AVCodecContext *avctx, int val); + +uint16_t *av_codec_get_chroma_intra_matrix(const AVCodecContext *avctx); +void av_codec_set_chroma_intra_matrix(AVCodecContext *avctx, uint16_t *val); + +/** + * AVProfile. + */ +typedef struct AVProfile { + int profile; + const char *name; ///< short name for the profile +} AVProfile; + +typedef struct AVCodecDefault AVCodecDefault; + +struct AVSubtitle; + +/** + * AVCodec. + */ +typedef struct AVCodec { + /** + * Name of the codec implementation. + * The name is globally unique among encoders and among decoders (but an + * encoder and a decoder can share the same name). + * This is the primary way to find a codec from the user perspective. + */ + const char *name; + /** + * Descriptive name for the codec, meant to be more human readable than name. + * You should use the NULL_IF_CONFIG_SMALL() macro to define it. + */ + const char *long_name; + enum AVMediaType type; + enum AVCodecID id; + /** + * Codec capabilities. + * see AV_CODEC_CAP_* + */ + int capabilities; + const AVRational *supported_framerates; ///< array of supported framerates, or NULL if any, array is terminated by {0,0} + const enum AVPixelFormat *pix_fmts; ///< array of supported pixel formats, or NULL if unknown, array is terminated by -1 + const int *supported_samplerates; ///< array of supported audio samplerates, or NULL if unknown, array is terminated by 0 + const enum AVSampleFormat *sample_fmts; ///< array of supported sample formats, or NULL if unknown, array is terminated by -1 + const uint64_t *channel_layouts; ///< array of support channel layouts, or NULL if unknown. array is terminated by 0 + uint8_t max_lowres; ///< maximum value for lowres supported by the decoder, no direct access, use av_codec_get_max_lowres() + const AVClass *priv_class; ///< AVClass for the private context + const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {FF_PROFILE_UNKNOWN} + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavcodec and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + int priv_data_size; + struct AVCodec *next; + /** + * @name Frame-level threading support functions + * @{ + */ + /** + * If defined, called on thread contexts when they are created. + * If the codec allocates writable tables in init(), re-allocate them here. + * priv_data will be set to a copy of the original. + */ + int (*init_thread_copy)(AVCodecContext *); + /** + * Copy necessary context variables from a previous thread context to the current one. + * If not defined, the next thread will start automatically; otherwise, the codec + * must call ff_thread_finish_setup(). + * + * dst and src will (rarely) point to the same context, in which case memcpy should be skipped. + */ + int (*update_thread_context)(AVCodecContext *dst, const AVCodecContext *src); + /** @} */ + + /** + * Private codec-specific defaults. + */ + const AVCodecDefault *defaults; + + /** + * Initialize codec static data, called from avcodec_register(). + */ + void (*init_static_data)(struct AVCodec *codec); + + int (*init)(AVCodecContext *); + int (*encode_sub)(AVCodecContext *, uint8_t *buf, int buf_size, + const struct AVSubtitle *sub); + /** + * Encode data to an AVPacket. + * + * @param avctx codec context + * @param avpkt output AVPacket (may contain a user-provided buffer) + * @param[in] frame AVFrame containing the raw data to be encoded + * @param[out] got_packet_ptr encoder sets to 0 or 1 to indicate that a + * non-empty packet was returned in avpkt. + * @return 0 on success, negative error code on failure + */ + int (*encode2)(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, + int *got_packet_ptr); + int (*decode)(AVCodecContext *, void *outdata, int *outdata_size, AVPacket *avpkt); + int (*close)(AVCodecContext *); + /** + * Flush buffers. + * Will be called when seeking + */ + void (*flush)(AVCodecContext *); + /** + * Internal codec capabilities. + * See FF_CODEC_CAP_* in internal.h + */ + int caps_internal; +} AVCodec; + +int av_codec_get_max_lowres(const AVCodec *codec); + +struct MpegEncContext; + +/** + * @defgroup lavc_hwaccel AVHWAccel + * @{ + */ +typedef struct AVHWAccel { + /** + * Name of the hardware accelerated codec. + * The name is globally unique among encoders and among decoders (but an + * encoder and a decoder can share the same name). + */ + const char *name; + + /** + * Type of codec implemented by the hardware accelerator. + * + * See AVMEDIA_TYPE_xxx + */ + enum AVMediaType type; + + /** + * Codec implemented by the hardware accelerator. + * + * See AV_CODEC_ID_xxx + */ + enum AVCodecID id; + + /** + * Supported pixel format. + * + * Only hardware accelerated formats are supported here. + */ + enum AVPixelFormat pix_fmt; + + /** + * Hardware accelerated codec capabilities. + * see HWACCEL_CODEC_CAP_* + */ + int capabilities; + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavcodec and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + struct AVHWAccel *next; + + /** + * Allocate a custom buffer + */ + int (*alloc_frame)(AVCodecContext *avctx, AVFrame *frame); + + /** + * Called at the beginning of each frame or field picture. + * + * Meaningful frame information (codec specific) is guaranteed to + * be parsed at this point. This function is mandatory. + * + * Note that buf can be NULL along with buf_size set to 0. + * Otherwise, this means the whole frame is available at this point. + * + * @param avctx the codec context + * @param buf the frame data buffer base + * @param buf_size the size of the frame in bytes + * @return zero if successful, a negative value otherwise + */ + int (*start_frame)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size); + + /** + * Callback for each slice. + * + * Meaningful slice information (codec specific) is guaranteed to + * be parsed at this point. This function is mandatory. + * The only exception is XvMC, that works on MB level. + * + * @param avctx the codec context + * @param buf the slice data buffer base + * @param buf_size the size of the slice in bytes + * @return zero if successful, a negative value otherwise + */ + int (*decode_slice)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size); + + /** + * Called at the end of each frame or field picture. + * + * The whole picture is parsed at this point and can now be sent + * to the hardware accelerator. This function is mandatory. + * + * @param avctx the codec context + * @return zero if successful, a negative value otherwise + */ + int (*end_frame)(AVCodecContext *avctx); + + /** + * Size of per-frame hardware accelerator private data. + * + * Private data is allocated with av_mallocz() before + * AVCodecContext.get_buffer() and deallocated after + * AVCodecContext.release_buffer(). + */ + int frame_priv_data_size; + + /** + * Called for every Macroblock in a slice. + * + * XvMC uses it to replace the ff_mpv_decode_mb(). + * Instead of decoding to raw picture, MB parameters are + * stored in an array provided by the video driver. + * + * @param s the mpeg context + */ + void (*decode_mb)(struct MpegEncContext *s); + + /** + * Initialize the hwaccel private data. + * + * This will be called from ff_get_format(), after hwaccel and + * hwaccel_context are set and the hwaccel private data in AVCodecInternal + * is allocated. + */ + int (*init)(AVCodecContext *avctx); + + /** + * Uninitialize the hwaccel private data. + * + * This will be called from get_format() or avcodec_close(), after hwaccel + * and hwaccel_context are already uninitialized. + */ + int (*uninit)(AVCodecContext *avctx); + + /** + * Size of the private data to allocate in + * AVCodecInternal.hwaccel_priv_data. + */ + int priv_data_size; +} AVHWAccel; + +/** + * Hardware acceleration should be used for decoding even if the codec level + * used is unknown or higher than the maximum supported level reported by the + * hardware driver. + * + * It's generally a good idea to pass this flag unless you have a specific + * reason not to, as hardware tends to under-report supported levels. + */ +#define AV_HWACCEL_FLAG_IGNORE_LEVEL (1 << 0) + +/** + * Hardware acceleration can output YUV pixel formats with a different chroma + * sampling than 4:2:0 and/or other than 8 bits per component. + */ +#define AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH (1 << 1) + +/** + * @} + */ + +#if FF_API_AVPICTURE +/** + * @defgroup lavc_picture AVPicture + * + * Functions for working with AVPicture + * @{ + */ + +/** + * Picture data structure. + * + * Up to four components can be stored into it, the last component is + * alpha. + * @deprecated use AVFrame or imgutils functions instead + */ +typedef struct AVPicture { + attribute_deprecated + uint8_t *data[AV_NUM_DATA_POINTERS]; ///< pointers to the image data planes + attribute_deprecated + int linesize[AV_NUM_DATA_POINTERS]; ///< number of bytes per line +} AVPicture; + +/** + * @} + */ +#endif + +enum AVSubtitleType { + SUBTITLE_NONE, + + SUBTITLE_BITMAP, ///< A bitmap, pict will be set + + /** + * Plain text, the text field must be set by the decoder and is + * authoritative. ass and pict fields may contain approximations. + */ + SUBTITLE_TEXT, + + /** + * Formatted text, the ass field must be set by the decoder and is + * authoritative. pict and text fields may contain approximations. + */ + SUBTITLE_ASS, +}; + +#define AV_SUBTITLE_FLAG_FORCED 0x00000001 + +typedef struct AVSubtitleRect { + int x; ///< top left corner of pict, undefined when pict is not set + int y; ///< top left corner of pict, undefined when pict is not set + int w; ///< width of pict, undefined when pict is not set + int h; ///< height of pict, undefined when pict is not set + int nb_colors; ///< number of colors in pict, undefined when pict is not set + +#if FF_API_AVPICTURE + /** + * @deprecated unused + */ + attribute_deprecated + AVPicture pict; +#endif + /** + * data+linesize for the bitmap of this subtitle. + * Can be set for text/ass as well once they are rendered. + */ + uint8_t *data[4]; + int linesize[4]; + + enum AVSubtitleType type; + + char *text; ///< 0 terminated plain UTF-8 text + + /** + * 0 terminated ASS/SSA compatible event line. + * The presentation of this is unaffected by the other values in this + * struct. + */ + char *ass; + + int flags; +} AVSubtitleRect; + +typedef struct AVSubtitle { + uint16_t format; /* 0 = graphics */ + uint32_t start_display_time; /* relative to packet pts, in ms */ + uint32_t end_display_time; /* relative to packet pts, in ms */ + unsigned num_rects; + AVSubtitleRect **rects; + int64_t pts; ///< Same as packet pts, in AV_TIME_BASE +} AVSubtitle; + +/** + * If c is NULL, returns the first registered codec, + * if c is non-NULL, returns the next registered codec after c, + * or NULL if c is the last one. + */ +AVCodec *av_codec_next(const AVCodec *c); + +/** + * Return the LIBAVCODEC_VERSION_INT constant. + */ +unsigned avcodec_version(void); + +/** + * Return the libavcodec build-time configuration. + */ +const char *avcodec_configuration(void); + +/** + * Return the libavcodec license. + */ +const char *avcodec_license(void); + +/** + * Register the codec codec and initialize libavcodec. + * + * @warning either this function or avcodec_register_all() must be called + * before any other libavcodec functions. + * + * @see avcodec_register_all() + */ +void avcodec_register(AVCodec *codec); + +/** + * Register all the codecs, parsers and bitstream filters which were enabled at + * configuration time. If you do not call this function you can select exactly + * which formats you want to support, by using the individual registration + * functions. + * + * @see avcodec_register + * @see av_register_codec_parser + * @see av_register_bitstream_filter + */ +void avcodec_register_all(void); + +/** + * Allocate an AVCodecContext and set its fields to default values. The + * resulting struct should be freed with avcodec_free_context(). + * + * @param codec if non-NULL, allocate private data and initialize defaults + * for the given codec. It is illegal to then call avcodec_open2() + * with a different codec. + * If NULL, then the codec-specific defaults won't be initialized, + * which may result in suboptimal default settings (this is + * important mainly for encoders, e.g. libx264). + * + * @return An AVCodecContext filled with default values or NULL on failure. + * @see avcodec_get_context_defaults + */ +AVCodecContext *avcodec_alloc_context3(const AVCodec *codec); + +/** + * Free the codec context and everything associated with it and write NULL to + * the provided pointer. + */ +void avcodec_free_context(AVCodecContext **avctx); + +/** + * Set the fields of the given AVCodecContext to default values corresponding + * to the given codec (defaults may be codec-dependent). + * + * Do not call this function if a non-NULL codec has been passed + * to avcodec_alloc_context3() that allocated this AVCodecContext. + * If codec is non-NULL, it is illegal to call avcodec_open2() with a + * different codec on this AVCodecContext. + */ +int avcodec_get_context_defaults3(AVCodecContext *s, const AVCodec *codec); + +/** + * Get the AVClass for AVCodecContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_class(void); + +/** + * Get the AVClass for AVFrame. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_frame_class(void); + +/** + * Get the AVClass for AVSubtitleRect. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_subtitle_rect_class(void); + +/** + * Copy the settings of the source AVCodecContext into the destination + * AVCodecContext. The resulting destination codec context will be + * unopened, i.e. you are required to call avcodec_open2() before you + * can use this AVCodecContext to decode/encode video/audio data. + * + * @param dest target codec context, should be initialized with + * avcodec_alloc_context3(NULL), but otherwise uninitialized + * @param src source codec context + * @return AVERROR() on error (e.g. memory allocation error), 0 on success + */ +int avcodec_copy_context(AVCodecContext *dest, const AVCodecContext *src); + +/** + * Initialize the AVCodecContext to use the given AVCodec. Prior to using this + * function the context has to be allocated with avcodec_alloc_context3(). + * + * The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(), + * avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for + * retrieving a codec. + * + * @warning This function is not thread safe! + * + * @note Always call this function before using decoding routines (such as + * @ref avcodec_decode_video2()). + * + * @code + * avcodec_register_all(); + * av_dict_set(&opts, "b", "2.5M", 0); + * codec = avcodec_find_decoder(AV_CODEC_ID_H264); + * if (!codec) + * exit(1); + * + * context = avcodec_alloc_context3(codec); + * + * if (avcodec_open2(context, codec, opts) < 0) + * exit(1); + * @endcode + * + * @param avctx The context to initialize. + * @param codec The codec to open this context for. If a non-NULL codec has been + * previously passed to avcodec_alloc_context3() or + * avcodec_get_context_defaults3() for this context, then this + * parameter MUST be either NULL or equal to the previously passed + * codec. + * @param options A dictionary filled with AVCodecContext and codec-private options. + * On return this object will be filled with options that were not found. + * + * @return zero on success, a negative value on error + * @see avcodec_alloc_context3(), avcodec_find_decoder(), avcodec_find_encoder(), + * av_dict_set(), av_opt_find(). + */ +int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); + +/** + * Close a given AVCodecContext and free all the data associated with it + * (but not the AVCodecContext itself). + * + * Calling this function on an AVCodecContext that hasn't been opened will free + * the codec-specific data allocated in avcodec_alloc_context3() / + * avcodec_get_context_defaults3() with a non-NULL codec. Subsequent calls will + * do nothing. + */ +int avcodec_close(AVCodecContext *avctx); + +/** + * Free all allocated data in the given subtitle struct. + * + * @param sub AVSubtitle to free. + */ +void avsubtitle_free(AVSubtitle *sub); + +/** + * @} + */ + +/** + * @addtogroup lavc_packet + * @{ + */ + +/** + * Allocate an AVPacket and set its fields to default values. The resulting + * struct must be freed using av_packet_free(). + * + * @return An AVPacket filled with default values or NULL on failure. + * + * @note this only allocates the AVPacket itself, not the data buffers. Those + * must be allocated through other means such as av_new_packet. + * + * @see av_new_packet + */ +AVPacket *av_packet_alloc(void); + +/** + * Create a new packet that references the same data as src. + * + * This is a shortcut for av_packet_alloc()+av_packet_ref(). + * + * @return newly created AVPacket on success, NULL on error. + * + * @see av_packet_alloc + * @see av_packet_ref + */ +AVPacket *av_packet_clone(AVPacket *src); + +/** + * Free the packet, if the packet is reference counted, it will be + * unreferenced first. + * + * @param packet packet to be freed. The pointer will be set to NULL. + * @note passing NULL is a no-op. + */ +void av_packet_free(AVPacket **pkt); + +/** + * Initialize optional fields of a packet with default values. + * + * Note, this does not touch the data and size members, which have to be + * initialized separately. + * + * @param pkt packet + */ +void av_init_packet(AVPacket *pkt); + +/** + * Allocate the payload of a packet and initialize its fields with + * default values. + * + * @param pkt packet + * @param size wanted payload size + * @return 0 if OK, AVERROR_xxx otherwise + */ +int av_new_packet(AVPacket *pkt, int size); + +/** + * Reduce packet size, correctly zeroing padding + * + * @param pkt packet + * @param size new size + */ +void av_shrink_packet(AVPacket *pkt, int size); + +/** + * Increase packet size, correctly zeroing padding + * + * @param pkt packet + * @param grow_by number of bytes by which to increase the size of the packet + */ +int av_grow_packet(AVPacket *pkt, int grow_by); + +/** + * Initialize a reference-counted packet from av_malloc()ed data. + * + * @param pkt packet to be initialized. This function will set the data, size, + * buf and destruct fields, all others are left untouched. + * @param data Data allocated by av_malloc() to be used as packet data. If this + * function returns successfully, the data is owned by the underlying AVBuffer. + * The caller may not access the data through other means. + * @param size size of data in bytes, without the padding. I.e. the full buffer + * size is assumed to be size + AV_INPUT_BUFFER_PADDING_SIZE. + * + * @return 0 on success, a negative AVERROR on error + */ +int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size); + +#if FF_API_AVPACKET_OLD_API +/** + * @warning This is a hack - the packet memory allocation stuff is broken. The + * packet is allocated if it was not really allocated. + * + * @deprecated Use av_packet_ref + */ +attribute_deprecated +int av_dup_packet(AVPacket *pkt); +/** + * Copy packet, including contents + * + * @return 0 on success, negative AVERROR on fail + */ +int av_copy_packet(AVPacket *dst, const AVPacket *src); + +/** + * Copy packet side data + * + * @return 0 on success, negative AVERROR on fail + */ +int av_copy_packet_side_data(AVPacket *dst, const AVPacket *src); + +/** + * Free a packet. + * + * @deprecated Use av_packet_unref + * + * @param pkt packet to free + */ +attribute_deprecated +void av_free_packet(AVPacket *pkt); +#endif +/** + * Allocate new information of a packet. + * + * @param pkt packet + * @param type side information type + * @param size side information size + * @return pointer to fresh allocated data or NULL otherwise + */ +uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int size); + +/** + * Wrap an existing array as a packet side data. + * + * @param pkt packet + * @param type side information type + * @param data the side data array. It must be allocated with the av_malloc() + * family of functions. The ownership of the data is transferred to + * pkt. + * @param size side information size + * @return a non-negative number on success, a negative AVERROR code on + * failure. On failure, the packet is unchanged and the data remains + * owned by the caller. + */ +int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + uint8_t *data, size_t size); + +/** + * Shrink the already allocated side data buffer + * + * @param pkt packet + * @param type side information type + * @param size new side information size + * @return 0 on success, < 0 on failure + */ +int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int size); + +/** + * Get side information from packet. + * + * @param pkt packet + * @param type desired side information type + * @param size pointer for side information size to store (optional) + * @return pointer to data if present or NULL otherwise + */ +uint8_t* av_packet_get_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + int *size); + +int av_packet_merge_side_data(AVPacket *pkt); + +int av_packet_split_side_data(AVPacket *pkt); + +const char *av_packet_side_data_name(enum AVPacketSideDataType type); + +/** + * Pack a dictionary for use in side_data. + * + * @param dict The dictionary to pack. + * @param size pointer to store the size of the returned data + * @return pointer to data if successful, NULL otherwise + */ +uint8_t *av_packet_pack_dictionary(AVDictionary *dict, int *size); +/** + * Unpack a dictionary from side_data. + * + * @param data data from side_data + * @param size size of the data + * @param dict the metadata storage dictionary + * @return 0 on success, < 0 on failure + */ +int av_packet_unpack_dictionary(const uint8_t *data, int size, AVDictionary **dict); + + +/** + * Convenience function to free all the side data stored. + * All the other fields stay untouched. + * + * @param pkt packet + */ +void av_packet_free_side_data(AVPacket *pkt); + +/** + * Setup a new reference to the data described by a given packet + * + * If src is reference-counted, setup dst as a new reference to the + * buffer in src. Otherwise allocate a new buffer in dst and copy the + * data from src into it. + * + * All the other fields are copied from src. + * + * @see av_packet_unref + * + * @param dst Destination packet + * @param src Source packet + * + * @return 0 on success, a negative AVERROR on error. + */ +int av_packet_ref(AVPacket *dst, const AVPacket *src); + +/** + * Wipe the packet. + * + * Unreference the buffer referenced by the packet and reset the + * remaining packet fields to their default values. + * + * @param pkt The packet to be unreferenced. + */ +void av_packet_unref(AVPacket *pkt); + +/** + * Move every field in src to dst and reset src. + * + * @see av_packet_unref + * + * @param src Source packet, will be reset + * @param dst Destination packet + */ +void av_packet_move_ref(AVPacket *dst, AVPacket *src); + +/** + * Copy only "properties" fields from src to dst. + * + * Properties for the purpose of this function are all the fields + * beside those related to the packet data (buf, data, size) + * + * @param dst Destination packet + * @param src Source packet + * + * @return 0 on success AVERROR on failure. + * + */ +int av_packet_copy_props(AVPacket *dst, const AVPacket *src); + +/** + * Convert valid timing fields (timestamps / durations) in a packet from one + * timebase to another. Timestamps with unknown values (AV_NOPTS_VALUE) will be + * ignored. + * + * @param pkt packet on which the conversion will be performed + * @param tb_src source timebase, in which the timing fields in pkt are + * expressed + * @param tb_dst destination timebase, to which the timing fields will be + * converted + */ +void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst); + +/** + * @} + */ + +/** + * @addtogroup lavc_decoding + * @{ + */ + +/** + * Find a registered decoder with a matching codec ID. + * + * @param id AVCodecID of the requested decoder + * @return A decoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_decoder(enum AVCodecID id); + +/** + * Find a registered decoder with the specified name. + * + * @param name name of the requested decoder + * @return A decoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_decoder_by_name(const char *name); + +/** + * The default callback for AVCodecContext.get_buffer2(). It is made public so + * it can be called by custom get_buffer2() implementations for decoders without + * AV_CODEC_CAP_DR1 set. + */ +int avcodec_default_get_buffer2(AVCodecContext *s, AVFrame *frame, int flags); + +#if FF_API_EMU_EDGE +/** + * Return the amount of padding in pixels which the get_buffer callback must + * provide around the edge of the image for codecs which do not have the + * CODEC_FLAG_EMU_EDGE flag. + * + * @return Required padding in pixels. + * + * @deprecated CODEC_FLAG_EMU_EDGE is deprecated, so this function is no longer + * needed + */ +attribute_deprecated +unsigned avcodec_get_edge_width(void); +#endif + +/** + * Modify width and height values so that they will result in a memory + * buffer that is acceptable for the codec if you do not use any horizontal + * padding. + * + * May only be used if a codec with AV_CODEC_CAP_DR1 has been opened. + */ +void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height); + +/** + * Modify width and height values so that they will result in a memory + * buffer that is acceptable for the codec if you also ensure that all + * line sizes are a multiple of the respective linesize_align[i]. + * + * May only be used if a codec with AV_CODEC_CAP_DR1 has been opened. + */ +void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height, + int linesize_align[AV_NUM_DATA_POINTERS]); + +/** + * Converts AVChromaLocation to swscale x/y chroma position. + * + * The positions represent the chroma (0,0) position in a coordinates system + * with luma (0,0) representing the origin and luma(1,1) representing 256,256 + * + * @param xpos horizontal chroma sample position + * @param ypos vertical chroma sample position + */ +int avcodec_enum_to_chroma_pos(int *xpos, int *ypos, enum AVChromaLocation pos); + +/** + * Converts swscale x/y chroma position to AVChromaLocation. + * + * The positions represent the chroma (0,0) position in a coordinates system + * with luma (0,0) representing the origin and luma(1,1) representing 256,256 + * + * @param xpos horizontal chroma sample position + * @param ypos vertical chroma sample position + */ +enum AVChromaLocation avcodec_chroma_pos_to_enum(int xpos, int ypos); + +/** + * Decode the audio frame of size avpkt->size from avpkt->data into frame. + * + * Some decoders may support multiple frames in a single AVPacket. Such + * decoders would then just decode the first frame and the return value would be + * less than the packet size. In this case, avcodec_decode_audio4 has to be + * called again with an AVPacket containing the remaining data in order to + * decode the second frame, etc... Even if no frames are returned, the packet + * needs to be fed to the decoder with remaining data until it is completely + * consumed or an error occurs. + * + * Some decoders (those marked with AV_CODEC_CAP_DELAY) have a delay between input + * and output. This means that for some packets they will not immediately + * produce decoded output and need to be flushed at the end of decoding to get + * all the decoded data. Flushing is done by calling this function with packets + * with avpkt->data set to NULL and avpkt->size set to 0 until it stops + * returning samples. It is safe to flush even those decoders that are not + * marked with AV_CODEC_CAP_DELAY, then no samples will be returned. + * + * @warning The input buffer, avpkt->data must be AV_INPUT_BUFFER_PADDING_SIZE + * larger than the actual read bytes because some optimized bitstream + * readers read 32 or 64 bits at once and could read over the end. + * + * @note The AVCodecContext MUST have been opened with @ref avcodec_open2() + * before packets may be fed to the decoder. + * + * @param avctx the codec context + * @param[out] frame The AVFrame in which to store decoded audio samples. + * The decoder will allocate a buffer for the decoded frame by + * calling the AVCodecContext.get_buffer2() callback. + * When AVCodecContext.refcounted_frames is set to 1, the frame is + * reference counted and the returned reference belongs to the + * caller. The caller must release the frame using av_frame_unref() + * when the frame is no longer needed. The caller may safely write + * to the frame if av_frame_is_writable() returns 1. + * When AVCodecContext.refcounted_frames is set to 0, the returned + * reference belongs to the decoder and is valid only until the + * next call to this function or until closing or flushing the + * decoder. The caller may not write to it. + * @param[out] got_frame_ptr Zero if no frame could be decoded, otherwise it is + * non-zero. Note that this field being set to zero + * does not mean that an error has occurred. For + * decoders with AV_CODEC_CAP_DELAY set, no given decode + * call is guaranteed to produce a frame. + * @param[in] avpkt The input AVPacket containing the input buffer. + * At least avpkt->data and avpkt->size should be set. Some + * decoders might also require additional fields to be set. + * @return A negative error code is returned if an error occurred during + * decoding, otherwise the number of bytes consumed from the input + * AVPacket is returned. + */ +int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame, + int *got_frame_ptr, const AVPacket *avpkt); + +/** + * Decode the video frame of size avpkt->size from avpkt->data into picture. + * Some decoders may support multiple frames in a single AVPacket, such + * decoders would then just decode the first frame. + * + * @warning The input buffer must be AV_INPUT_BUFFER_PADDING_SIZE larger than + * the actual read bytes because some optimized bitstream readers read 32 or 64 + * bits at once and could read over the end. + * + * @warning The end of the input buffer buf should be set to 0 to ensure that + * no overreading happens for damaged MPEG streams. + * + * @note Codecs which have the AV_CODEC_CAP_DELAY capability set have a delay + * between input and output, these need to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to return the remaining frames. + * + * @note The AVCodecContext MUST have been opened with @ref avcodec_open2() + * before packets may be fed to the decoder. + * + * @param avctx the codec context + * @param[out] picture The AVFrame in which the decoded video frame will be stored. + * Use av_frame_alloc() to get an AVFrame. The codec will + * allocate memory for the actual bitmap by calling the + * AVCodecContext.get_buffer2() callback. + * When AVCodecContext.refcounted_frames is set to 1, the frame is + * reference counted and the returned reference belongs to the + * caller. The caller must release the frame using av_frame_unref() + * when the frame is no longer needed. The caller may safely write + * to the frame if av_frame_is_writable() returns 1. + * When AVCodecContext.refcounted_frames is set to 0, the returned + * reference belongs to the decoder and is valid only until the + * next call to this function or until closing or flushing the + * decoder. The caller may not write to it. + * + * @param[in] avpkt The input AVPacket containing the input buffer. + * You can create such packet with av_init_packet() and by then setting + * data and size, some decoders might in addition need other fields like + * flags&AV_PKT_FLAG_KEY. All decoders are designed to use the least + * fields possible. + * @param[in,out] got_picture_ptr Zero if no frame could be decompressed, otherwise, it is nonzero. + * @return On error a negative value is returned, otherwise the number of bytes + * used or zero if no frame could be decompressed. + */ +int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, + int *got_picture_ptr, + const AVPacket *avpkt); + +/** + * Decode a subtitle message. + * Return a negative value on error, otherwise return the number of bytes used. + * If no subtitle could be decompressed, got_sub_ptr is zero. + * Otherwise, the subtitle is stored in *sub. + * Note that AV_CODEC_CAP_DR1 is not available for subtitle codecs. This is for + * simplicity, because the performance difference is expect to be negligible + * and reusing a get_buffer written for video codecs would probably perform badly + * due to a potentially very different allocation pattern. + * + * Some decoders (those marked with CODEC_CAP_DELAY) have a delay between input + * and output. This means that for some packets they will not immediately + * produce decoded output and need to be flushed at the end of decoding to get + * all the decoded data. Flushing is done by calling this function with packets + * with avpkt->data set to NULL and avpkt->size set to 0 until it stops + * returning subtitles. It is safe to flush even those decoders that are not + * marked with CODEC_CAP_DELAY, then no subtitles will be returned. + * + * @note The AVCodecContext MUST have been opened with @ref avcodec_open2() + * before packets may be fed to the decoder. + * + * @param avctx the codec context + * @param[out] sub The Preallocated AVSubtitle in which the decoded subtitle will be stored, + * must be freed with avsubtitle_free if *got_sub_ptr is set. + * @param[in,out] got_sub_ptr Zero if no subtitle could be decompressed, otherwise, it is nonzero. + * @param[in] avpkt The input AVPacket containing the input buffer. + */ +int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, + int *got_sub_ptr, + AVPacket *avpkt); + +/** + * @defgroup lavc_parsing Frame parsing + * @{ + */ + +enum AVPictureStructure { + AV_PICTURE_STRUCTURE_UNKNOWN, //< unknown + AV_PICTURE_STRUCTURE_TOP_FIELD, //< coded as top field + AV_PICTURE_STRUCTURE_BOTTOM_FIELD, //< coded as bottom field + AV_PICTURE_STRUCTURE_FRAME, //< coded as frame +}; + +typedef struct AVCodecParserContext { + void *priv_data; + struct AVCodecParser *parser; + int64_t frame_offset; /* offset of the current frame */ + int64_t cur_offset; /* current offset + (incremented by each av_parser_parse()) */ + int64_t next_frame_offset; /* offset of the next frame */ + /* video info */ + int pict_type; /* XXX: Put it back in AVCodecContext. */ + /** + * This field is used for proper frame duration computation in lavf. + * It signals, how much longer the frame duration of the current frame + * is compared to normal frame duration. + * + * frame_duration = (1 + repeat_pict) * time_base + * + * It is used by codecs like H.264 to display telecined material. + */ + int repeat_pict; /* XXX: Put it back in AVCodecContext. */ + int64_t pts; /* pts of the current frame */ + int64_t dts; /* dts of the current frame */ + + /* private data */ + int64_t last_pts; + int64_t last_dts; + int fetch_timestamp; + +#define AV_PARSER_PTS_NB 4 + int cur_frame_start_index; + int64_t cur_frame_offset[AV_PARSER_PTS_NB]; + int64_t cur_frame_pts[AV_PARSER_PTS_NB]; + int64_t cur_frame_dts[AV_PARSER_PTS_NB]; + + int flags; +#define PARSER_FLAG_COMPLETE_FRAMES 0x0001 +#define PARSER_FLAG_ONCE 0x0002 +/// Set if the parser has a valid file offset +#define PARSER_FLAG_FETCHED_OFFSET 0x0004 +#define PARSER_FLAG_USE_CODEC_TS 0x1000 + + int64_t offset; ///< byte offset from starting packet start + int64_t cur_frame_end[AV_PARSER_PTS_NB]; + + /** + * Set by parser to 1 for key frames and 0 for non-key frames. + * It is initialized to -1, so if the parser doesn't set this flag, + * old-style fallback using AV_PICTURE_TYPE_I picture type as key frames + * will be used. + */ + int key_frame; + +#if FF_API_CONVERGENCE_DURATION + /** + * @deprecated unused + */ + attribute_deprecated + int64_t convergence_duration; +#endif + + // Timestamp generation support: + /** + * Synchronization point for start of timestamp generation. + * + * Set to >0 for sync point, 0 for no sync point and <0 for undefined + * (default). + * + * For example, this corresponds to presence of H.264 buffering period + * SEI message. + */ + int dts_sync_point; + + /** + * Offset of the current timestamp against last timestamp sync point in + * units of AVCodecContext.time_base. + * + * Set to INT_MIN when dts_sync_point unused. Otherwise, it must + * contain a valid timestamp offset. + * + * Note that the timestamp of sync point has usually a nonzero + * dts_ref_dts_delta, which refers to the previous sync point. Offset of + * the next frame after timestamp sync point will be usually 1. + * + * For example, this corresponds to H.264 cpb_removal_delay. + */ + int dts_ref_dts_delta; + + /** + * Presentation delay of current frame in units of AVCodecContext.time_base. + * + * Set to INT_MIN when dts_sync_point unused. Otherwise, it must + * contain valid non-negative timestamp delta (presentation time of a frame + * must not lie in the past). + * + * This delay represents the difference between decoding and presentation + * time of the frame. + * + * For example, this corresponds to H.264 dpb_output_delay. + */ + int pts_dts_delta; + + /** + * Position of the packet in file. + * + * Analogous to cur_frame_pts/dts + */ + int64_t cur_frame_pos[AV_PARSER_PTS_NB]; + + /** + * Byte position of currently parsed frame in stream. + */ + int64_t pos; + + /** + * Previous frame byte position. + */ + int64_t last_pos; + + /** + * Duration of the current frame. + * For audio, this is in units of 1 / AVCodecContext.sample_rate. + * For all other types, this is in units of AVCodecContext.time_base. + */ + int duration; + + enum AVFieldOrder field_order; + + /** + * Indicate whether a picture is coded as a frame, top field or bottom field. + * + * For example, H.264 field_pic_flag equal to 0 corresponds to + * AV_PICTURE_STRUCTURE_FRAME. An H.264 picture with field_pic_flag + * equal to 1 and bottom_field_flag equal to 0 corresponds to + * AV_PICTURE_STRUCTURE_TOP_FIELD. + */ + enum AVPictureStructure picture_structure; + + /** + * Picture number incremented in presentation or output order. + * This field may be reinitialized at the first picture of a new sequence. + * + * For example, this corresponds to H.264 PicOrderCnt. + */ + int output_picture_number; + + /** + * Dimensions of the decoded video intended for presentation. + */ + int width; + int height; + + /** + * Dimensions of the coded video. + */ + int coded_width; + int coded_height; + + /** + * The format of the coded data, corresponds to enum AVPixelFormat for video + * and for enum AVSampleFormat for audio. + * + * Note that a decoder can have considerable freedom in how exactly it + * decodes the data, so the format reported here might be different from the + * one returned by a decoder. + */ + int format; +} AVCodecParserContext; + +typedef struct AVCodecParser { + int codec_ids[5]; /* several codec IDs are permitted */ + int priv_data_size; + int (*parser_init)(AVCodecParserContext *s); + /* This callback never returns an error, a negative value means that + * the frame start was in a previous packet. */ + int (*parser_parse)(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size); + void (*parser_close)(AVCodecParserContext *s); + int (*split)(AVCodecContext *avctx, const uint8_t *buf, int buf_size); + struct AVCodecParser *next; +} AVCodecParser; + +AVCodecParser *av_parser_next(const AVCodecParser *c); + +void av_register_codec_parser(AVCodecParser *parser); +AVCodecParserContext *av_parser_init(int codec_id); + +/** + * Parse a packet. + * + * @param s parser context. + * @param avctx codec context. + * @param poutbuf set to pointer to parsed buffer or NULL if not yet finished. + * @param poutbuf_size set to size of parsed buffer or zero if not yet finished. + * @param buf input buffer. + * @param buf_size input length, to signal EOF, this should be 0 (so that the last frame can be output). + * @param pts input presentation timestamp. + * @param dts input decoding timestamp. + * @param pos input byte position in stream. + * @return the number of bytes of the input bitstream used. + * + * Example: + * @code + * while(in_len){ + * len = av_parser_parse2(myparser, AVCodecContext, &data, &size, + * in_data, in_len, + * pts, dts, pos); + * in_data += len; + * in_len -= len; + * + * if(size) + * decode_frame(data, size); + * } + * @endcode + */ +int av_parser_parse2(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, + int64_t pts, int64_t dts, + int64_t pos); + +/** + * @return 0 if the output buffer is a subset of the input, 1 if it is allocated and must be freed + * @deprecated use AVBitStreamFilter + */ +int av_parser_change(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe); +void av_parser_close(AVCodecParserContext *s); + +/** + * @} + * @} + */ + +/** + * @addtogroup lavc_encoding + * @{ + */ + +/** + * Find a registered encoder with a matching codec ID. + * + * @param id AVCodecID of the requested encoder + * @return An encoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_encoder(enum AVCodecID id); + +/** + * Find a registered encoder with the specified name. + * + * @param name name of the requested encoder + * @return An encoder if one was found, NULL otherwise. + */ +AVCodec *avcodec_find_encoder_by_name(const char *name); + +/** + * Encode a frame of audio. + * + * Takes input samples from frame and writes the next output packet, if + * available, to avpkt. The output packet does not necessarily contain data for + * the most recent frame, as encoders can delay, split, and combine input frames + * internally as needed. + * + * @param avctx codec context + * @param avpkt output AVPacket. + * The user can supply an output buffer by setting + * avpkt->data and avpkt->size prior to calling the + * function, but if the size of the user-provided data is not + * large enough, encoding will fail. If avpkt->data and + * avpkt->size are set, avpkt->destruct must also be set. All + * other AVPacket fields will be reset by the encoder using + * av_init_packet(). If avpkt->data is NULL, the encoder will + * allocate it. The encoder will set avpkt->size to the size + * of the output packet. + * + * If this function fails or produces no output, avpkt will be + * freed using av_packet_unref(). + * @param[in] frame AVFrame containing the raw audio data to be encoded. + * May be NULL when flushing an encoder that has the + * AV_CODEC_CAP_DELAY capability set. + * If AV_CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame + * can have any number of samples. + * If it is not set, frame->nb_samples must be equal to + * avctx->frame_size for all frames except the last. + * The final frame may be smaller than avctx->frame_size. + * @param[out] got_packet_ptr This field is set to 1 by libavcodec if the + * output packet is non-empty, and to 0 if it is + * empty. If the function returns an error, the + * packet can be assumed to be invalid, and the + * value of got_packet_ptr is undefined and should + * not be used. + * @return 0 on success, negative error code on failure + */ +int avcodec_encode_audio2(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr); + +/** + * Encode a frame of video. + * + * Takes input raw video data from frame and writes the next output packet, if + * available, to avpkt. The output packet does not necessarily contain data for + * the most recent frame, as encoders can delay and reorder input frames + * internally as needed. + * + * @param avctx codec context + * @param avpkt output AVPacket. + * The user can supply an output buffer by setting + * avpkt->data and avpkt->size prior to calling the + * function, but if the size of the user-provided data is not + * large enough, encoding will fail. All other AVPacket fields + * will be reset by the encoder using av_init_packet(). If + * avpkt->data is NULL, the encoder will allocate it. + * The encoder will set avpkt->size to the size of the + * output packet. The returned data (if any) belongs to the + * caller, he is responsible for freeing it. + * + * If this function fails or produces no output, avpkt will be + * freed using av_packet_unref(). + * @param[in] frame AVFrame containing the raw video data to be encoded. + * May be NULL when flushing an encoder that has the + * AV_CODEC_CAP_DELAY capability set. + * @param[out] got_packet_ptr This field is set to 1 by libavcodec if the + * output packet is non-empty, and to 0 if it is + * empty. If the function returns an error, the + * packet can be assumed to be invalid, and the + * value of got_packet_ptr is undefined and should + * not be used. + * @return 0 on success, negative error code on failure + */ +int avcodec_encode_video2(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr); + +int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, + const AVSubtitle *sub); + + +/** + * @} + */ + +#if FF_API_AVCODEC_RESAMPLE +/** + * @defgroup lavc_resample Audio resampling + * @ingroup libavc + * @deprecated use libswresample instead + * + * @{ + */ +struct ReSampleContext; +struct AVResampleContext; + +typedef struct ReSampleContext ReSampleContext; + +/** + * Initialize audio resampling context. + * + * @param output_channels number of output channels + * @param input_channels number of input channels + * @param output_rate output sample rate + * @param input_rate input sample rate + * @param sample_fmt_out requested output sample format + * @param sample_fmt_in input sample format + * @param filter_length length of each FIR filter in the filterbank relative to the cutoff frequency + * @param log2_phase_count log2 of the number of entries in the polyphase filterbank + * @param linear if 1 then the used FIR filter will be linearly interpolated + between the 2 closest, if 0 the closest will be used + * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate + * @return allocated ReSampleContext, NULL if error occurred + */ +attribute_deprecated +ReSampleContext *av_audio_resample_init(int output_channels, int input_channels, + int output_rate, int input_rate, + enum AVSampleFormat sample_fmt_out, + enum AVSampleFormat sample_fmt_in, + int filter_length, int log2_phase_count, + int linear, double cutoff); + +attribute_deprecated +int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples); + +/** + * Free resample context. + * + * @param s a non-NULL pointer to a resample context previously + * created with av_audio_resample_init() + */ +attribute_deprecated +void audio_resample_close(ReSampleContext *s); + + +/** + * Initialize an audio resampler. + * Note, if either rate is not an integer then simply scale both rates up so they are. + * @param filter_length length of each FIR filter in the filterbank relative to the cutoff freq + * @param log2_phase_count log2 of the number of entries in the polyphase filterbank + * @param linear If 1 then the used FIR filter will be linearly interpolated + between the 2 closest, if 0 the closest will be used + * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate + */ +attribute_deprecated +struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff); + +/** + * Resample an array of samples using a previously configured context. + * @param src an array of unconsumed samples + * @param consumed the number of samples of src which have been consumed are returned here + * @param src_size the number of unconsumed samples available + * @param dst_size the amount of space in samples available in dst + * @param update_ctx If this is 0 then the context will not be modified, that way several channels can be resampled with the same context. + * @return the number of samples written in dst or -1 if an error occurred + */ +attribute_deprecated +int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx); + + +/** + * Compensate samplerate/timestamp drift. The compensation is done by changing + * the resampler parameters, so no audible clicks or similar distortions occur + * @param compensation_distance distance in output samples over which the compensation should be performed + * @param sample_delta number of output samples which should be output less + * + * example: av_resample_compensate(c, 10, 500) + * here instead of 510 samples only 500 samples would be output + * + * note, due to rounding the actual compensation might be slightly different, + * especially if the compensation_distance is large and the in_rate used during init is small + */ +attribute_deprecated +void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance); +attribute_deprecated +void av_resample_close(struct AVResampleContext *c); + +/** + * @} + */ +#endif + +#if FF_API_AVPICTURE +/** + * @addtogroup lavc_picture + * @{ + */ + +/** + * @deprecated unused + */ +attribute_deprecated +int avpicture_alloc(AVPicture *picture, enum AVPixelFormat pix_fmt, int width, int height); + +/** + * @deprecated unused + */ +attribute_deprecated +void avpicture_free(AVPicture *picture); + +/** + * @deprecated use av_image_fill_arrays() instead. + */ +attribute_deprecated +int avpicture_fill(AVPicture *picture, const uint8_t *ptr, + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * @deprecated use av_image_copy_to_buffer() instead. + */ +attribute_deprecated +int avpicture_layout(const AVPicture *src, enum AVPixelFormat pix_fmt, + int width, int height, + unsigned char *dest, int dest_size); + +/** + * @deprecated use av_image_get_buffer_size() instead. + */ +attribute_deprecated +int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height); + +/** + * @deprecated av_image_copy() instead. + */ +attribute_deprecated +void av_picture_copy(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * @deprecated unused + */ +attribute_deprecated +int av_picture_crop(AVPicture *dst, const AVPicture *src, + enum AVPixelFormat pix_fmt, int top_band, int left_band); + +/** + * @deprecated unused + */ +attribute_deprecated +int av_picture_pad(AVPicture *dst, const AVPicture *src, int height, int width, enum AVPixelFormat pix_fmt, + int padtop, int padbottom, int padleft, int padright, int *color); + +/** + * @} + */ +#endif + +/** + * @defgroup lavc_misc Utility functions + * @ingroup libavc + * + * Miscellaneous utility functions related to both encoding and decoding + * (or neither). + * @{ + */ + +/** + * @defgroup lavc_misc_pixfmt Pixel formats + * + * Functions for working with pixel formats. + * @{ + */ + +/** + * Utility function to access log2_chroma_w log2_chroma_h from + * the pixel format AVPixFmtDescriptor. + * + * This function asserts that pix_fmt is valid. See av_pix_fmt_get_chroma_sub_sample + * for one that returns a failure code and continues in case of invalid + * pix_fmts. + * + * @param[in] pix_fmt the pixel format + * @param[out] h_shift store log2_chroma_w + * @param[out] v_shift store log2_chroma_h + * + * @see av_pix_fmt_get_chroma_sub_sample + */ + +void avcodec_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, int *h_shift, int *v_shift); + +/** + * Return a value representing the fourCC code associated to the + * pixel format pix_fmt, or 0 if no associated fourCC code can be + * found. + */ +unsigned int avcodec_pix_fmt_to_codec_tag(enum AVPixelFormat pix_fmt); + +/** + * @deprecated see av_get_pix_fmt_loss() + */ +int avcodec_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, enum AVPixelFormat src_pix_fmt, + int has_alpha); + +/** + * Find the best pixel format to convert to given a certain source pixel + * format. When converting from one pixel format to another, information loss + * may occur. For example, when converting from RGB24 to GRAY, the color + * information will be lost. Similarly, other losses occur when converting from + * some formats to other formats. avcodec_find_best_pix_fmt_of_2() searches which of + * the given pixel formats should be used to suffer the least amount of loss. + * The pixel formats from which it chooses one, are determined by the + * pix_fmt_list parameter. + * + * + * @param[in] pix_fmt_list AV_PIX_FMT_NONE terminated array of pixel formats to choose from + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @param[out] loss_ptr Combination of flags informing you what kind of losses will occur. + * @return The best pixel format to convert to or -1 if none was found. + */ +enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat *pix_fmt_list, + enum AVPixelFormat src_pix_fmt, + int has_alpha, int *loss_ptr); + +/** + * @deprecated see av_find_best_pix_fmt_of_2() + */ +enum AVPixelFormat avcodec_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); + +attribute_deprecated +#if AV_HAVE_INCOMPATIBLE_LIBAV_ABI +enum AVPixelFormat avcodec_find_best_pix_fmt2(const enum AVPixelFormat *pix_fmt_list, + enum AVPixelFormat src_pix_fmt, + int has_alpha, int *loss_ptr); +#else +enum AVPixelFormat avcodec_find_best_pix_fmt2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); +#endif + + +enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum AVPixelFormat * fmt); + +/** + * @} + */ + +#if FF_API_SET_DIMENSIONS +/** + * @deprecated this function is not supposed to be used from outside of lavc + */ +attribute_deprecated +void avcodec_set_dimensions(AVCodecContext *s, int width, int height); +#endif + +/** + * Put a string representing the codec tag codec_tag in buf. + * + * @param buf buffer to place codec tag in + * @param buf_size size in bytes of buf + * @param codec_tag codec tag to assign + * @return the length of the string that would have been generated if + * enough space had been available, excluding the trailing null + */ +size_t av_get_codec_tag_string(char *buf, size_t buf_size, unsigned int codec_tag); + +void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode); + +/** + * Return a name for the specified profile, if available. + * + * @param codec the codec that is searched for the given profile + * @param profile the profile value for which a name is requested + * @return A name for the profile if found, NULL otherwise. + */ +const char *av_get_profile_name(const AVCodec *codec, int profile); + +/** + * Return a name for the specified profile, if available. + * + * @param codec_id the ID of the codec to which the requested profile belongs + * @param profile the profile value for which a name is requested + * @return A name for the profile if found, NULL otherwise. + * + * @note unlike av_get_profile_name(), which searches a list of profiles + * supported by a specific decoder or encoder implementation, this + * function searches the list of profiles from the AVCodecDescriptor + */ +const char *avcodec_profile_name(enum AVCodecID codec_id, int profile); + +int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2),void *arg, int *ret, int count, int size); +int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2, int, int),void *arg, int *ret, int count); +//FIXME func typedef + +/** + * Fill AVFrame audio data and linesize pointers. + * + * The buffer buf must be a preallocated buffer with a size big enough + * to contain the specified samples amount. The filled AVFrame data + * pointers will point to this buffer. + * + * AVFrame extended_data channel pointers are allocated if necessary for + * planar audio. + * + * @param frame the AVFrame + * frame->nb_samples must be set prior to calling the + * function. This function fills in frame->data, + * frame->extended_data, frame->linesize[0]. + * @param nb_channels channel count + * @param sample_fmt sample format + * @param buf buffer to use for frame data + * @param buf_size size of buffer + * @param align plane size sample alignment (0 = default) + * @return >=0 on success, negative error code on failure + * @todo return the size in bytes required to store the samples in + * case of success, at the next libavutil bump + */ +int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels, + enum AVSampleFormat sample_fmt, const uint8_t *buf, + int buf_size, int align); + +/** + * Reset the internal decoder state / flush internal buffers. Should be called + * e.g. when seeking or when switching to a different stream. + * + * @note when refcounted frames are not used (i.e. avctx->refcounted_frames is 0), + * this invalidates the frames previously returned from the decoder. When + * refcounted frames are used, the decoder just releases any references it might + * keep internally, but the caller's reference remains valid. + */ +void avcodec_flush_buffers(AVCodecContext *avctx); + +/** + * Return codec bits per sample. + * + * @param[in] codec_id the codec + * @return Number of bits per sample or zero if unknown for the given codec. + */ +int av_get_bits_per_sample(enum AVCodecID codec_id); + +/** + * Return the PCM codec associated with a sample format. + * @param be endianness, 0 for little, 1 for big, + * -1 (or anything else) for native + * @return AV_CODEC_ID_PCM_* or AV_CODEC_ID_NONE + */ +enum AVCodecID av_get_pcm_codec(enum AVSampleFormat fmt, int be); + +/** + * Return codec bits per sample. + * Only return non-zero if the bits per sample is exactly correct, not an + * approximation. + * + * @param[in] codec_id the codec + * @return Number of bits per sample or zero if unknown for the given codec. + */ +int av_get_exact_bits_per_sample(enum AVCodecID codec_id); + +/** + * Return audio frame duration. + * + * @param avctx codec context + * @param frame_bytes size of the frame, or 0 if unknown + * @return frame duration, in samples, if known. 0 if not able to + * determine. + */ +int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes); + + +typedef struct AVBitStreamFilterContext { + void *priv_data; + struct AVBitStreamFilter *filter; + AVCodecParserContext *parser; + struct AVBitStreamFilterContext *next; + /** + * Internal default arguments, used if NULL is passed to av_bitstream_filter_filter(). + * Not for access by library users. + */ + char *args; +} AVBitStreamFilterContext; + + +typedef struct AVBitStreamFilter { + const char *name; + int priv_data_size; + int (*filter)(AVBitStreamFilterContext *bsfc, + AVCodecContext *avctx, const char *args, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe); + void (*close)(AVBitStreamFilterContext *bsfc); + struct AVBitStreamFilter *next; +} AVBitStreamFilter; + +/** + * Register a bitstream filter. + * + * The filter will be accessible to the application code through + * av_bitstream_filter_next() or can be directly initialized with + * av_bitstream_filter_init(). + * + * @see avcodec_register_all() + */ +void av_register_bitstream_filter(AVBitStreamFilter *bsf); + +/** + * Create and initialize a bitstream filter context given a bitstream + * filter name. + * + * The returned context must be freed with av_bitstream_filter_close(). + * + * @param name the name of the bitstream filter + * @return a bitstream filter context if a matching filter was found + * and successfully initialized, NULL otherwise + */ +AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); + +/** + * Filter bitstream. + * + * This function filters the buffer buf with size buf_size, and places the + * filtered buffer in the buffer pointed to by poutbuf. + * + * The output buffer must be freed by the caller. + * + * @param bsfc bitstream filter context created by av_bitstream_filter_init() + * @param avctx AVCodecContext accessed by the filter, may be NULL. + * If specified, this must point to the encoder context of the + * output stream the packet is sent to. + * @param args arguments which specify the filter configuration, may be NULL + * @param poutbuf pointer which is updated to point to the filtered buffer + * @param poutbuf_size pointer which is updated to the filtered buffer size in bytes + * @param buf buffer containing the data to filter + * @param buf_size size in bytes of buf + * @param keyframe set to non-zero if the buffer to filter corresponds to a key-frame packet data + * @return >= 0 in case of success, or a negative error code in case of failure + * + * If the return value is positive, an output buffer is allocated and + * is available in *poutbuf, and is distinct from the input buffer. + * + * If the return value is 0, the output buffer is not allocated and + * should be considered identical to the input buffer, or in case + * *poutbuf was set it points to the input buffer (not necessarily to + * its starting address). + */ +int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, + AVCodecContext *avctx, const char *args, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, int keyframe); + +/** + * Release bitstream filter context. + * + * @param bsf the bitstream filter context created with + * av_bitstream_filter_init(), can be NULL + */ +void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); + +/** + * If f is NULL, return the first registered bitstream filter, + * if f is non-NULL, return the next registered bitstream filter + * after f, or NULL if f is the last one. + * + * This function can be used to iterate over all registered bitstream + * filters. + */ +AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f); + +/* memory */ + +/** + * Same behaviour av_fast_malloc but the buffer has additional + * AV_INPUT_BUFFER_PADDING_SIZE at the end which will always be 0. + * + * In addition the whole buffer will initially and after resizes + * be 0-initialized so that no uninitialized data will ever appear. + */ +void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Same behaviour av_fast_padded_malloc except that buffer will always + * be 0-initialized after call. + */ +void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size); + +/** + * Encode extradata length to a buffer. Used by xiph codecs. + * + * @param s buffer to write to; must be at least (v/255+1) bytes long + * @param v size of extradata in bytes + * @return number of bytes written to the buffer. + */ +unsigned int av_xiphlacing(unsigned char *s, unsigned int v); + +#if FF_API_MISSING_SAMPLE +/** + * Log a generic warning message about a missing feature. This function is + * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.) + * only, and would normally not be used by applications. + * @param[in] avc a pointer to an arbitrary struct of which the first field is + * a pointer to an AVClass struct + * @param[in] feature string containing the name of the missing feature + * @param[in] want_sample indicates if samples are wanted which exhibit this feature. + * If want_sample is non-zero, additional verbage will be added to the log + * message which tells the user how to report samples to the development + * mailing list. + * @deprecated Use avpriv_report_missing_feature() instead. + */ +attribute_deprecated +void av_log_missing_feature(void *avc, const char *feature, int want_sample); + +/** + * Log a generic warning message asking for a sample. This function is + * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.) + * only, and would normally not be used by applications. + * @param[in] avc a pointer to an arbitrary struct of which the first field is + * a pointer to an AVClass struct + * @param[in] msg string containing an optional message, or NULL if no message + * @deprecated Use avpriv_request_sample() instead. + */ +attribute_deprecated +void av_log_ask_for_sample(void *avc, const char *msg, ...) av_printf_format(2, 3); +#endif /* FF_API_MISSING_SAMPLE */ + +/** + * Register the hardware accelerator hwaccel. + */ +void av_register_hwaccel(AVHWAccel *hwaccel); + +/** + * If hwaccel is NULL, returns the first registered hardware accelerator, + * if hwaccel is non-NULL, returns the next registered hardware accelerator + * after hwaccel, or NULL if hwaccel is the last one. + */ +AVHWAccel *av_hwaccel_next(const AVHWAccel *hwaccel); + + +/** + * Lock operation used by lockmgr + */ +enum AVLockOp { + AV_LOCK_CREATE, ///< Create a mutex + AV_LOCK_OBTAIN, ///< Lock the mutex + AV_LOCK_RELEASE, ///< Unlock the mutex + AV_LOCK_DESTROY, ///< Free mutex resources +}; + +/** + * Register a user provided lock manager supporting the operations + * specified by AVLockOp. The "mutex" argument to the function points + * to a (void *) where the lockmgr should store/get a pointer to a user + * allocated mutex. It is NULL upon AV_LOCK_CREATE and equal to the + * value left by the last call for all other ops. If the lock manager is + * unable to perform the op then it should leave the mutex in the same + * state as when it was called and return a non-zero value. However, + * when called with AV_LOCK_DESTROY the mutex will always be assumed to + * have been successfully destroyed. If av_lockmgr_register succeeds + * it will return a non-negative value, if it fails it will return a + * negative value and destroy all mutex and unregister all callbacks. + * av_lockmgr_register is not thread-safe, it must be called from a + * single thread before any calls which make use of locking are used. + * + * @param cb User defined callback. av_lockmgr_register invokes calls + * to this callback and the previously registered callback. + * The callback will be used to create more than one mutex + * each of which must be backed by its own underlying locking + * mechanism (i.e. do not use a single static object to + * implement your lock manager). If cb is set to NULL the + * lockmgr will be unregistered. + */ +int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op)); + +/** + * Get the type of the given codec. + */ +enum AVMediaType avcodec_get_type(enum AVCodecID codec_id); + +/** + * Get the name of a codec. + * @return a static string identifying the codec; never NULL + */ +const char *avcodec_get_name(enum AVCodecID id); + +/** + * @return a positive value if s is open (i.e. avcodec_open2() was called on it + * with no corresponding avcodec_close()), 0 otherwise. + */ +int avcodec_is_open(AVCodecContext *s); + +/** + * @return a non-zero number if codec is an encoder, zero otherwise + */ +int av_codec_is_encoder(const AVCodec *codec); + +/** + * @return a non-zero number if codec is a decoder, zero otherwise + */ +int av_codec_is_decoder(const AVCodec *codec); + +/** + * @return descriptor for given codec ID or NULL if no descriptor exists. + */ +const AVCodecDescriptor *avcodec_descriptor_get(enum AVCodecID id); + +/** + * Iterate over all codec descriptors known to libavcodec. + * + * @param prev previous descriptor. NULL to get the first descriptor. + * + * @return next descriptor or NULL after the last descriptor + */ +const AVCodecDescriptor *avcodec_descriptor_next(const AVCodecDescriptor *prev); + +/** + * @return codec descriptor with the given name or NULL if no such descriptor + * exists. + */ +const AVCodecDescriptor *avcodec_descriptor_get_by_name(const char *name); + +/** + * Allocate a CPB properties structure and initialize its fields to default + * values. + * + * @param size if non-NULL, the size of the allocated struct will be written + * here. This is useful for embedding it in side data. + * + * @return the newly allocated struct or NULL on failure + */ +AVCPBProperties *av_cpb_properties_alloc(size_t *size); + +/** + * @} + */ + +#endif /* AVCODEC_AVCODEC_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/avdct.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/avdct.h new file mode 100644 index 00000000..272422e4 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/avdct.h @@ -0,0 +1,84 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AVDCT_H +#define AVCODEC_AVDCT_H + +#include "libavutil/opt.h" + +/** + * AVDCT context. + * @note function pointers can be NULL if the specific features have been + * disabled at build time. + */ +typedef struct AVDCT { + const AVClass *av_class; + + void (*idct)(int16_t *block /* align 16 */); + + /** + * IDCT input permutation. + * Several optimized IDCTs need a permutated input (relative to the + * normal order of the reference IDCT). + * This permutation must be performed before the idct_put/add. + * Note, normally this can be merged with the zigzag/alternate scan
+ * An example to avoid confusion: + * - (->decode coeffs -> zigzag reorder -> dequant -> reference IDCT -> ...) + * - (x -> reference DCT -> reference IDCT -> x) + * - (x -> reference DCT -> simple_mmx_perm = idct_permutation + * -> simple_idct_mmx -> x) + * - (-> decode coeffs -> zigzag reorder -> simple_mmx_perm -> dequant + * -> simple_idct_mmx -> ...) + */ + uint8_t idct_permutation[64]; + + void (*fdct)(int16_t *block /* align 16 */); + + + /** + * DCT algorithm. + * must use AVOptions to set this field. + */ + int dct_algo; + + /** + * IDCT algorithm. + * must use AVOptions to set this field. + */ + int idct_algo; + + void (*get_pixels)(int16_t *block /* align 16 */, + const uint8_t *pixels /* align 8 */, + ptrdiff_t line_size); + + int bits_per_sample; +} AVDCT; + +/** + * Allocates a AVDCT context. + * This needs to be initialized with avcodec_dct_init() after optionally + * configuring it with AVOptions. + * + * To free it use av_free() + */ +AVDCT *avcodec_dct_alloc(void); +int avcodec_dct_init(AVDCT *); + +const AVClass *avcodec_dct_get_class(void); + +#endif /* AVCODEC_AVDCT_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/avfft.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/avfft.h new file mode 100644 index 00000000..0c0f9b8d --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/avfft.h @@ -0,0 +1,118 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AVFFT_H +#define AVCODEC_AVFFT_H + +/** + * @file + * @ingroup lavc_fft + * FFT functions + */ + +/** + * @defgroup lavc_fft FFT functions + * @ingroup lavc_misc + * + * @{ + */ + +typedef float FFTSample; + +typedef struct FFTComplex { + FFTSample re, im; +} FFTComplex; + +typedef struct FFTContext FFTContext; + +/** + * Set up a complex FFT. + * @param nbits log2 of the length of the input array + * @param inverse if 0 perform the forward transform, if 1 perform the inverse + */ +FFTContext *av_fft_init(int nbits, int inverse); + +/** + * Do the permutation needed BEFORE calling ff_fft_calc(). + */ +void av_fft_permute(FFTContext *s, FFTComplex *z); + +/** + * Do a complex FFT with the parameters defined in av_fft_init(). The + * input data must be permuted before. No 1.0/sqrt(n) normalization is done. + */ +void av_fft_calc(FFTContext *s, FFTComplex *z); + +void av_fft_end(FFTContext *s); + +FFTContext *av_mdct_init(int nbits, int inverse, double scale); +void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +void av_mdct_end(FFTContext *s); + +/* Real Discrete Fourier Transform */ + +enum RDFTransformType { + DFT_R2C, + IDFT_C2R, + IDFT_R2C, + DFT_C2R, +}; + +typedef struct RDFTContext RDFTContext; + +/** + * Set up a real FFT. + * @param nbits log2 of the length of the input array + * @param trans the type of transform + */ +RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans); +void av_rdft_calc(RDFTContext *s, FFTSample *data); +void av_rdft_end(RDFTContext *s); + +/* Discrete Cosine Transform */ + +typedef struct DCTContext DCTContext; + +enum DCTTransformType { + DCT_II = 0, + DCT_III, + DCT_I, + DST_I, +}; + +/** + * Set up DCT. + * + * @param nbits size of the input array: + * (1 << nbits) for DCT-II, DCT-III and DST-I + * (1 << nbits) + 1 for DCT-I + * @param type the type of transform + * + * @note the first element of the input of DST-I is ignored + */ +DCTContext *av_dct_init(int nbits, enum DCTTransformType type); +void av_dct_calc(DCTContext *s, FFTSample *data); +void av_dct_end (DCTContext *s); + +/** + * @} + */ + +#endif /* AVCODEC_AVFFT_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/d3d11va.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/d3d11va.h new file mode 100644 index 00000000..6816b6c1 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/d3d11va.h @@ -0,0 +1,112 @@ +/* + * Direct3D11 HW acceleration + * + * copyright (c) 2009 Laurent Aimar + * copyright (c) 2015 Steve Lhomme + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_D3D11VA_H +#define AVCODEC_D3D11VA_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_d3d11va + * Public libavcodec D3D11VA header. + */ + +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0602 +#endif + +#include +#include + +/** + * @defgroup lavc_codec_hwaccel_d3d11va Direct3D11 + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +#define FF_DXVA2_WORKAROUND_SCALING_LIST_ZIGZAG 1 ///< Work around for Direct3D11 and old UVD/UVD+ ATI video cards +#define FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO 2 ///< Work around for Direct3D11 and old Intel GPUs with ClearVideo interface + +/** + * This structure is used to provides the necessary configurations and data + * to the Direct3D11 FFmpeg HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + * + * Use av_d3d11va_alloc_context() exclusively to allocate an AVD3D11VAContext. + */ +typedef struct AVD3D11VAContext { + /** + * D3D11 decoder object + */ + ID3D11VideoDecoder *decoder; + + /** + * D3D11 VideoContext + */ + ID3D11VideoContext *video_context; + + /** + * D3D11 configuration used to create the decoder + */ + D3D11_VIDEO_DECODER_CONFIG *cfg; + + /** + * The number of surface in the surface array + */ + unsigned surface_count; + + /** + * The array of Direct3D surfaces used to create the decoder + */ + ID3D11VideoDecoderOutputView **surface; + + /** + * A bit field configuring the workarounds needed for using the decoder + */ + uint64_t workaround; + + /** + * Private to the FFmpeg AVHWAccel implementation + */ + unsigned report_id; + + /** + * Mutex to access video_context + */ + HANDLE context_mutex; +} AVD3D11VAContext; + +/** + * Allocate an AVD3D11VAContext. + * + * @return Newly-allocated AVD3D11VAContext or NULL on failure. + */ +AVD3D11VAContext *av_d3d11va_alloc_context(void); + +/** + * @} + */ + +#endif /* AVCODEC_D3D11VA_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/dirac.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/dirac.h new file mode 100644 index 00000000..8d7953d9 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/dirac.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2007 Marco Gerards + * Copyright (C) 2009 David Conrad + * Copyright (C) 2011 Jordi Ortiz + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DIRAC_H +#define AVCODEC_DIRAC_H + +/** + * @file + * Interface to Dirac Decoder/Encoder + * @author Marco Gerards + * @author David Conrad + * @author Jordi Ortiz + */ + +#include "avcodec.h" + +/** + * Parse code values: + * + * Dirac Specification -> + * 9.6.1 Table 9.1 + * + * VC-2 Specification -> + * 10.4.1 Table 10.1 + */ + +enum DiracParseCodes { + DIRAC_PCODE_SEQ_HEADER = 0x00, + DIRAC_PCODE_END_SEQ = 0x10, + DIRAC_PCODE_AUX = 0x20, + DIRAC_PCODE_PAD = 0x30, + DIRAC_PCODE_PICTURE_CODED = 0x08, + DIRAC_PCODE_PICTURE_RAW = 0x48, + DIRAC_PCODE_PICTURE_LOW_DEL = 0xC8, + DIRAC_PCODE_PICTURE_HQ = 0xE8, + DIRAC_PCODE_MAGIC = 0x42424344, +}; + +typedef struct DiracVersionInfo { + int major; + int minor; +} DiracVersionInfo; + +typedef struct AVDiracSeqHeader { + unsigned width; + unsigned height; + uint8_t chroma_format; ///< 0: 444 1: 422 2: 420 + + uint8_t interlaced; + uint8_t top_field_first; + + uint8_t frame_rate_index; ///< index into dirac_frame_rate[] + uint8_t aspect_ratio_index; ///< index into dirac_aspect_ratio[] + + uint16_t clean_width; + uint16_t clean_height; + uint16_t clean_left_offset; + uint16_t clean_right_offset; + + uint8_t pixel_range_index; ///< index into dirac_pixel_range_presets[] + uint8_t color_spec_index; ///< index into dirac_color_spec_presets[] + + int profile; + int level; + + AVRational framerate; + AVRational sample_aspect_ratio; + + enum AVPixelFormat pix_fmt; + enum AVColorRange color_range; + enum AVColorPrimaries color_primaries; + enum AVColorTransferCharacteristic color_trc; + enum AVColorSpace colorspace; + + DiracVersionInfo version; + int bit_depth; +} AVDiracSeqHeader; + +/** + * Parse a Dirac sequence header. + * + * @param dsh this function will allocate and fill an AVDiracSeqHeader struct + * and write it into this pointer. The caller must free it with + * av_free(). + * @param buf the data buffer + * @param buf_size the size of the data buffer in bytes + * @param log_ctx if non-NULL, this function will log errors here + * @return 0 on success, a negative AVERROR code on failure + */ +int av_dirac_parse_sequence_header(AVDiracSeqHeader **dsh, + const uint8_t *buf, size_t buf_size, + void *log_ctx); + +#endif /* AVCODEC_DIRAC_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/dv_profile.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/dv_profile.h new file mode 100644 index 00000000..9380a66f --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/dv_profile.h @@ -0,0 +1,83 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DV_PROFILE_H +#define AVCODEC_DV_PROFILE_H + +#include + +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" +#include "avcodec.h" + +/* minimum number of bytes to read from a DV stream in order to + * determine the profile */ +#define DV_PROFILE_BYTES (6 * 80) /* 6 DIF blocks */ + + +/* + * AVDVProfile is used to express the differences between various + * DV flavors. For now it's primarily used for differentiating + * 525/60 and 625/50, but the plans are to use it for various + * DV specs as well (e.g. SMPTE314M vs. IEC 61834). + */ +typedef struct AVDVProfile { + int dsf; /* value of the dsf in the DV header */ + int video_stype; /* stype for VAUX source pack */ + int frame_size; /* total size of one frame in bytes */ + int difseg_size; /* number of DIF segments per DIF channel */ + int n_difchan; /* number of DIF channels per frame */ + AVRational time_base; /* 1/framerate */ + int ltc_divisor; /* FPS from the LTS standpoint */ + int height; /* picture height in pixels */ + int width; /* picture width in pixels */ + AVRational sar[2]; /* sample aspect ratios for 4:3 and 16:9 */ + enum AVPixelFormat pix_fmt; /* picture pixel format */ + int bpm; /* blocks per macroblock */ + const uint8_t *block_sizes; /* AC block sizes, in bits */ + int audio_stride; /* size of audio_shuffle table */ + int audio_min_samples[3]; /* min amount of audio samples */ + /* for 48kHz, 44.1kHz and 32kHz */ + int audio_samples_dist[5]; /* how many samples are supposed to be */ + /* in each frame in a 5 frames window */ + const uint8_t (*audio_shuffle)[9]; /* PCM shuffling table */ +} AVDVProfile; + +/** + * Get a DV profile for the provided compressed frame. + * + * @param sys the profile used for the previous frame, may be NULL + * @param frame the compressed data buffer + * @param buf_size size of the buffer in bytes + * @return the DV profile for the supplied data or NULL on failure + */ +const AVDVProfile *av_dv_frame_profile(const AVDVProfile *sys, + const uint8_t *frame, unsigned buf_size); + +/** + * Get a DV profile for the provided stream parameters. + */ +const AVDVProfile *av_dv_codec_profile(int width, int height, enum AVPixelFormat pix_fmt); + +/** + * Get a DV profile for the provided stream parameters. + * The frame rate is used as a best-effort parameter. + */ +const AVDVProfile *av_dv_codec_profile2(int width, int height, enum AVPixelFormat pix_fmt, AVRational frame_rate); + +#endif /* AVCODEC_DV_PROFILE_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/dxva2.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/dxva2.h new file mode 100644 index 00000000..9e3ab86a --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/dxva2.h @@ -0,0 +1,93 @@ +/* + * DXVA2 HW acceleration + * + * copyright (c) 2009 Laurent Aimar + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_DXVA_H +#define AVCODEC_DXVA_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_dxva2 + * Public libavcodec DXVA2 header. + */ + +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0602 +#endif + +#include +#include +#include + +/** + * @defgroup lavc_codec_hwaccel_dxva2 DXVA2 + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +#define FF_DXVA2_WORKAROUND_SCALING_LIST_ZIGZAG 1 ///< Work around for DXVA2 and old UVD/UVD+ ATI video cards +#define FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO 2 ///< Work around for DXVA2 and old Intel GPUs with ClearVideo interface + +/** + * This structure is used to provides the necessary configurations and data + * to the DXVA2 FFmpeg HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + */ +struct dxva_context { + /** + * DXVA2 decoder object + */ + IDirectXVideoDecoder *decoder; + + /** + * DXVA2 configuration used to create the decoder + */ + const DXVA2_ConfigPictureDecode *cfg; + + /** + * The number of surface in the surface array + */ + unsigned surface_count; + + /** + * The array of Direct3D surfaces used to create the decoder + */ + LPDIRECT3DSURFACE9 *surface; + + /** + * A bit field configuring the workarounds needed for using the decoder + */ + uint64_t workaround; + + /** + * Private to the FFmpeg AVHWAccel implementation + */ + unsigned report_id; +}; + +/** + * @} + */ + +#endif /* AVCODEC_DXVA_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/qsv.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/qsv.h new file mode 100644 index 00000000..b77158ec --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/qsv.h @@ -0,0 +1,107 @@ +/* + * Intel MediaSDK QSV public API + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_QSV_H +#define AVCODEC_QSV_H + +#include + +#include "libavutil/buffer.h" + +/** + * This struct is used for communicating QSV parameters between libavcodec and + * the caller. It is managed by the caller and must be assigned to + * AVCodecContext.hwaccel_context. + * - decoding: hwaccel_context must be set on return from the get_format() + * callback + * - encoding: hwaccel_context must be set before avcodec_open2() + */ +typedef struct AVQSVContext { + /** + * If non-NULL, the session to use for encoding or decoding. + * Otherwise, libavcodec will try to create an internal session. + */ + mfxSession session; + + /** + * The IO pattern to use. + */ + int iopattern; + + /** + * Extra buffers to pass to encoder or decoder initialization. + */ + mfxExtBuffer **ext_buffers; + int nb_ext_buffers; + + /** + * Encoding only. If this field is set to non-zero by the caller, libavcodec + * will create an mfxExtOpaqueSurfaceAlloc extended buffer and pass it to + * the encoder initialization. This only makes sense if iopattern is also + * set to MFX_IOPATTERN_IN_OPAQUE_MEMORY. + * + * The number of allocated opaque surfaces will be the sum of the number + * required by the encoder and the user-provided value nb_opaque_surfaces. + * The array of the opaque surfaces will be exported to the caller through + * the opaque_surfaces field. + */ + int opaque_alloc; + + /** + * Encoding only, and only if opaque_alloc is set to non-zero. Before + * calling avcodec_open2(), the caller should set this field to the number + * of extra opaque surfaces to allocate beyond what is required by the + * encoder. + * + * On return from avcodec_open2(), this field will be set by libavcodec to + * the total number of allocated opaque surfaces. + */ + int nb_opaque_surfaces; + + /** + * Encoding only, and only if opaque_alloc is set to non-zero. On return + * from avcodec_open2(), this field will be used by libavcodec to export the + * array of the allocated opaque surfaces to the caller, so they can be + * passed to other parts of the pipeline. + * + * The buffer reference exported here is owned and managed by libavcodec, + * the callers should make their own reference with av_buffer_ref() and free + * it with av_buffer_unref() when it is no longer needed. + * + * The buffer data is an nb_opaque_surfaces-sized array of mfxFrameSurface1. + */ + AVBufferRef *opaque_surfaces; + + /** + * Encoding only, and only if opaque_alloc is set to non-zero. On return + * from avcodec_open2(), this field will be set to the surface type used in + * the opaque allocation request. + */ + int opaque_alloc_type; +} AVQSVContext; + +/** + * Allocate a new context. + * + * It must be freed by the caller with av_free(). + */ +AVQSVContext *av_qsv_alloc_context(void); + +#endif /* AVCODEC_QSV_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/vaapi.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/vaapi.h new file mode 100644 index 00000000..7a29f6f8 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/vaapi.h @@ -0,0 +1,189 @@ +/* + * Video Acceleration API (shared data between FFmpeg and the video player) + * HW decode acceleration for MPEG-2, MPEG-4, H.264 and VC-1 + * + * Copyright (C) 2008-2009 Splitted-Desktop Systems + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VAAPI_H +#define AVCODEC_VAAPI_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vaapi + * Public libavcodec VA API header. + */ + +#include +#include "libavutil/attributes.h" +#include "version.h" + +/** + * @defgroup lavc_codec_hwaccel_vaapi VA API Decoding + * @ingroup lavc_codec_hwaccel + * @{ + */ + +/** + * This structure is used to share data between the FFmpeg library and + * the client video application. + * This shall be zero-allocated and available as + * AVCodecContext.hwaccel_context. All user members can be set once + * during initialization or through each AVCodecContext.get_buffer() + * function call. In any case, they must be valid prior to calling + * decoding functions. + */ +struct vaapi_context { + /** + * Window system dependent data + * + * - encoding: unused + * - decoding: Set by user + */ + void *display; + + /** + * Configuration ID + * + * - encoding: unused + * - decoding: Set by user + */ + uint32_t config_id; + + /** + * Context ID (video decode pipeline) + * + * - encoding: unused + * - decoding: Set by user + */ + uint32_t context_id; + +#if FF_API_VAAPI_CONTEXT + /** + * VAPictureParameterBuffer ID + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + uint32_t pic_param_buf_id; + + /** + * VAIQMatrixBuffer ID + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + uint32_t iq_matrix_buf_id; + + /** + * VABitPlaneBuffer ID (for VC-1 decoding) + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + uint32_t bitplane_buf_id; + + /** + * Slice parameter/data buffer IDs + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + uint32_t *slice_buf_ids; + + /** + * Number of effective slice buffer IDs to send to the HW + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + unsigned int n_slice_buf_ids; + + /** + * Size of pre-allocated slice_buf_ids + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + unsigned int slice_buf_ids_alloc; + + /** + * Pointer to VASliceParameterBuffers + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + void *slice_params; + + /** + * Size of a VASliceParameterBuffer element + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + unsigned int slice_param_size; + + /** + * Size of pre-allocated slice_params + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + unsigned int slice_params_alloc; + + /** + * Number of slices currently filled in + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + unsigned int slice_count; + + /** + * Pointer to slice data buffer base + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + const uint8_t *slice_data; + + /** + * Current size of slice data + * + * - encoding: unused + * - decoding: Set by libavcodec + */ + attribute_deprecated + uint32_t slice_data_size; +#endif +}; + +/* @} */ + +#endif /* AVCODEC_VAAPI_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/vda.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/vda.h new file mode 100644 index 00000000..bde14e31 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/vda.h @@ -0,0 +1,230 @@ +/* + * VDA HW acceleration + * + * copyright (c) 2011 Sebastien Zwickert + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VDA_H +#define AVCODEC_VDA_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vda + * Public libavcodec VDA header. + */ + +#include "libavcodec/avcodec.h" + +#include + +// emmintrin.h is unable to compile with -std=c99 -Werror=missing-prototypes +// http://openradar.appspot.com/8026390 +#undef __GNUC_STDC_INLINE__ + +#define Picture QuickdrawPicture +#include +#undef Picture + +#include "libavcodec/version.h" + +// extra flags not defined in VDADecoder.h +enum { + kVDADecodeInfo_Asynchronous = 1UL << 0, + kVDADecodeInfo_FrameDropped = 1UL << 1 +}; + +/** + * @defgroup lavc_codec_hwaccel_vda VDA + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +/** + * This structure is used to provide the necessary configurations and data + * to the VDA FFmpeg HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + */ +struct vda_context { + /** + * VDA decoder object. + * + * - encoding: unused + * - decoding: Set/Unset by libavcodec. + */ + VDADecoder decoder; + + /** + * The Core Video pixel buffer that contains the current image data. + * + * encoding: unused + * decoding: Set by libavcodec. Unset by user. + */ + CVPixelBufferRef cv_buffer; + + /** + * Use the hardware decoder in synchronous mode. + * + * encoding: unused + * decoding: Set by user. + */ + int use_sync_decoding; + + /** + * The frame width. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + int width; + + /** + * The frame height. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + int height; + + /** + * The frame format. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + int format; + + /** + * The pixel format for output image buffers. + * + * - encoding: unused + * - decoding: Set/Unset by user. + */ + OSType cv_pix_fmt_type; + + /** + * unused + */ + uint8_t *priv_bitstream; + + /** + * unused + */ + int priv_bitstream_size; + + /** + * unused + */ + int priv_allocated_size; + + /** + * Use av_buffer to manage buffer. + * When the flag is set, the CVPixelBuffers returned by the decoder will + * be released automatically, so you have to retain them if necessary. + * Not setting this flag may cause memory leak. + * + * encoding: unused + * decoding: Set by user. + */ + int use_ref_buffer; +}; + +/** Create the video decoder. */ +int ff_vda_create_decoder(struct vda_context *vda_ctx, + uint8_t *extradata, + int extradata_size); + +/** Destroy the video decoder. */ +int ff_vda_destroy_decoder(struct vda_context *vda_ctx); + +/** + * This struct holds all the information that needs to be passed + * between the caller and libavcodec for initializing VDA decoding. + * Its size is not a part of the public ABI, it must be allocated with + * av_vda_alloc_context() and freed with av_free(). + */ +typedef struct AVVDAContext { + /** + * VDA decoder object. Created and freed by the caller. + */ + VDADecoder decoder; + + /** + * The output callback that must be passed to VDADecoderCreate. + * Set by av_vda_alloc_context(). + */ + VDADecoderOutputCallback output_callback; + + /** + * CVPixelBuffer Format Type that VDA will use for decoded frames; set by + * the caller. + */ + OSType cv_pix_fmt_type; +} AVVDAContext; + +/** + * Allocate and initialize a VDA context. + * + * This function should be called from the get_format() callback when the caller + * selects the AV_PIX_FMT_VDA format. The caller must then create the decoder + * object (using the output callback provided by libavcodec) that will be used + * for VDA-accelerated decoding. + * + * When decoding with VDA is finished, the caller must destroy the decoder + * object and free the VDA context using av_free(). + * + * @return the newly allocated context or NULL on failure + */ +AVVDAContext *av_vda_alloc_context(void); + +/** + * This is a convenience function that creates and sets up the VDA context using + * an internal implementation. + * + * @param avctx the corresponding codec context + * + * @return >= 0 on success, a negative AVERROR code on failure + */ +int av_vda_default_init(AVCodecContext *avctx); + +/** + * This is a convenience function that creates and sets up the VDA context using + * an internal implementation. + * + * @param avctx the corresponding codec context + * @param vdactx the VDA context to use + * + * @return >= 0 on success, a negative AVERROR code on failure + */ +int av_vda_default_init2(AVCodecContext *avctx, AVVDAContext *vdactx); + +/** + * This function must be called to free the VDA context initialized with + * av_vda_default_init(). + * + * @param avctx the corresponding codec context + */ +void av_vda_default_free(AVCodecContext *avctx); + +/** + * @} + */ + +#endif /* AVCODEC_VDA_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/vdpau.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/vdpau.h new file mode 100644 index 00000000..e85e4d9e --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/vdpau.h @@ -0,0 +1,253 @@ +/* + * The Video Decode and Presentation API for UNIX (VDPAU) is used for + * hardware-accelerated decoding of MPEG-1/2, H.264 and VC-1. + * + * Copyright (C) 2008 NVIDIA + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VDPAU_H +#define AVCODEC_VDPAU_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vdpau + * Public libavcodec VDPAU header. + */ + + +/** + * @defgroup lavc_codec_hwaccel_vdpau VDPAU Decoder and Renderer + * @ingroup lavc_codec_hwaccel + * + * VDPAU hardware acceleration has two modules + * - VDPAU decoding + * - VDPAU presentation + * + * The VDPAU decoding module parses all headers using FFmpeg + * parsing mechanisms and uses VDPAU for the actual decoding. + * + * As per the current implementation, the actual decoding + * and rendering (API calls) are done as part of the VDPAU + * presentation (vo_vdpau.c) module. + * + * @{ + */ + +#include +#include +#include "libavutil/avconfig.h" +#include "libavutil/attributes.h" + +#include "avcodec.h" +#include "version.h" + +#if FF_API_BUFS_VDPAU +union AVVDPAUPictureInfo { + VdpPictureInfoH264 h264; + VdpPictureInfoMPEG1Or2 mpeg; + VdpPictureInfoVC1 vc1; + VdpPictureInfoMPEG4Part2 mpeg4; +}; +#endif + +struct AVCodecContext; +struct AVFrame; + +typedef int (*AVVDPAU_Render2)(struct AVCodecContext *, struct AVFrame *, + const VdpPictureInfo *, uint32_t, + const VdpBitstreamBuffer *); + +/** + * This structure is used to share data between the libavcodec library and + * the client video application. + * The user shall allocate the structure via the av_alloc_vdpau_hwaccel + * function and make it available as + * AVCodecContext.hwaccel_context. Members can be set by the user once + * during initialization or through each AVCodecContext.get_buffer() + * function call. In any case, they must be valid prior to calling + * decoding functions. + * + * The size of this structure is not a part of the public ABI and must not + * be used outside of libavcodec. Use av_vdpau_alloc_context() to allocate an + * AVVDPAUContext. + */ +typedef struct AVVDPAUContext { + /** + * VDPAU decoder handle + * + * Set by user. + */ + VdpDecoder decoder; + + /** + * VDPAU decoder render callback + * + * Set by the user. + */ + VdpDecoderRender *render; + +#if FF_API_BUFS_VDPAU + /** + * VDPAU picture information + * + * Set by libavcodec. + */ + attribute_deprecated + union AVVDPAUPictureInfo info; + + /** + * Allocated size of the bitstream_buffers table. + * + * Set by libavcodec. + */ + attribute_deprecated + int bitstream_buffers_allocated; + + /** + * Useful bitstream buffers in the bitstream buffers table. + * + * Set by libavcodec. + */ + attribute_deprecated + int bitstream_buffers_used; + + /** + * Table of bitstream buffers. + * The user is responsible for freeing this buffer using av_freep(). + * + * Set by libavcodec. + */ + attribute_deprecated + VdpBitstreamBuffer *bitstream_buffers; +#endif + AVVDPAU_Render2 render2; +} AVVDPAUContext; + +/** + * @brief allocation function for AVVDPAUContext + * + * Allows extending the struct without breaking API/ABI + */ +AVVDPAUContext *av_alloc_vdpaucontext(void); + +AVVDPAU_Render2 av_vdpau_hwaccel_get_render2(const AVVDPAUContext *); +void av_vdpau_hwaccel_set_render2(AVVDPAUContext *, AVVDPAU_Render2); + +/** + * Associate a VDPAU device with a codec context for hardware acceleration. + * This function is meant to be called from the get_format() codec callback, + * or earlier. It can also be called after avcodec_flush_buffers() to change + * the underlying VDPAU device mid-stream (e.g. to recover from non-transparent + * display preemption). + * + * @note get_format() must return AV_PIX_FMT_VDPAU if this function completes + * successfully. + * + * @param avctx decoding context whose get_format() callback is invoked + * @param device VDPAU device handle to use for hardware acceleration + * @param get_proc_address VDPAU device driver + * @param flags zero of more OR'd AV_HWACCEL_FLAG_* flags + * + * @return 0 on success, an AVERROR code on failure. + */ +int av_vdpau_bind_context(AVCodecContext *avctx, VdpDevice device, + VdpGetProcAddress *get_proc_address, unsigned flags); + +/** + * Gets the parameters to create an adequate VDPAU video surface for the codec + * context using VDPAU hardware decoding acceleration. + * + * @note Behavior is undefined if the context was not successfully bound to a + * VDPAU device using av_vdpau_bind_context(). + * + * @param avctx the codec context being used for decoding the stream + * @param type storage space for the VDPAU video surface chroma type + * (or NULL to ignore) + * @param width storage space for the VDPAU video surface pixel width + * (or NULL to ignore) + * @param height storage space for the VDPAU video surface pixel height + * (or NULL to ignore) + * + * @return 0 on success, a negative AVERROR code on failure. + */ +int av_vdpau_get_surface_parameters(AVCodecContext *avctx, VdpChromaType *type, + uint32_t *width, uint32_t *height); + +/** + * Allocate an AVVDPAUContext. + * + * @return Newly-allocated AVVDPAUContext or NULL on failure. + */ +AVVDPAUContext *av_vdpau_alloc_context(void); + +#if FF_API_VDPAU_PROFILE +/** + * Get a decoder profile that should be used for initializing a VDPAU decoder. + * Should be called from the AVCodecContext.get_format() callback. + * + * @deprecated Use av_vdpau_bind_context() instead. + * + * @param avctx the codec context being used for decoding the stream + * @param profile a pointer into which the result will be written on success. + * The contents of profile are undefined if this function returns + * an error. + * + * @return 0 on success (non-negative), a negative AVERROR on failure. + */ +attribute_deprecated +int av_vdpau_get_profile(AVCodecContext *avctx, VdpDecoderProfile *profile); +#endif + +#if FF_API_CAP_VDPAU +/** @brief The videoSurface is used for rendering. */ +#define FF_VDPAU_STATE_USED_FOR_RENDER 1 + +/** + * @brief The videoSurface is needed for reference/prediction. + * The codec manipulates this. + */ +#define FF_VDPAU_STATE_USED_FOR_REFERENCE 2 + +/** + * @brief This structure is used as a callback between the FFmpeg + * decoder (vd_) and presentation (vo_) module. + * This is used for defining a video frame containing surface, + * picture parameter, bitstream information etc which are passed + * between the FFmpeg decoder and its clients. + */ +struct vdpau_render_state { + VdpVideoSurface surface; ///< Used as rendered surface, never changed. + + int state; ///< Holds FF_VDPAU_STATE_* values. + + /** picture parameter information for all supported codecs */ + union AVVDPAUPictureInfo info; + + /** Describe size/location of the compressed video data. + Set to 0 when freeing bitstream_buffers. */ + int bitstream_buffers_allocated; + int bitstream_buffers_used; + /** The user is responsible for freeing this buffer using av_freep(). */ + VdpBitstreamBuffer *bitstream_buffers; +}; +#endif + +/* @}*/ + +#endif /* AVCODEC_VDPAU_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/version.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/version.h new file mode 100644 index 00000000..9846275e --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/version.h @@ -0,0 +1,210 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VERSION_H +#define AVCODEC_VERSION_H + +/** + * @file + * @ingroup libavc + * Libavcodec version macros. + */ + +#include "libavutil/version.h" + +#define LIBAVCODEC_VERSION_MAJOR 57 +#define LIBAVCODEC_VERSION_MINOR 21 +#define LIBAVCODEC_VERSION_MICRO 100 + +#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, \ + LIBAVCODEC_VERSION_MICRO) +#define LIBAVCODEC_VERSION AV_VERSION(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, \ + LIBAVCODEC_VERSION_MICRO) +#define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT + +#define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + * + * @note, when bumping the major version it is recommended to manually + * disable each FF_API_* in its own commit instead of disabling them all + * at once through the bump. This improves the git bisect-ability of the change. + */ + +#ifndef FF_API_VIMA_DECODER +#define FF_API_VIMA_DECODER (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_AUDIO_CONVERT +#define FF_API_AUDIO_CONVERT (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_AVCODEC_RESAMPLE +#define FF_API_AVCODEC_RESAMPLE FF_API_AUDIO_CONVERT +#endif +#ifndef FF_API_MISSING_SAMPLE +#define FF_API_MISSING_SAMPLE (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_LOWRES +#define FF_API_LOWRES (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_CAP_VDPAU +#define FF_API_CAP_VDPAU (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_BUFS_VDPAU +#define FF_API_BUFS_VDPAU (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_VOXWARE +#define FF_API_VOXWARE (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_SET_DIMENSIONS +#define FF_API_SET_DIMENSIONS (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_DEBUG_MV +#define FF_API_DEBUG_MV (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_AC_VLC +#define FF_API_AC_VLC (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_OLD_MSMPEG4 +#define FF_API_OLD_MSMPEG4 (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_ASPECT_EXTENDED +#define FF_API_ASPECT_EXTENDED (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_ARCH_ALPHA +#define FF_API_ARCH_ALPHA (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_XVMC +#define FF_API_XVMC (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_ERROR_RATE +#define FF_API_ERROR_RATE (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_QSCALE_TYPE +#define FF_API_QSCALE_TYPE (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_MB_TYPE +#define FF_API_MB_TYPE (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_MAX_BFRAMES +#define FF_API_MAX_BFRAMES (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_NEG_LINESIZES +#define FF_API_NEG_LINESIZES (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_EMU_EDGE +#define FF_API_EMU_EDGE (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_ARCH_SH4 +#define FF_API_ARCH_SH4 (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_ARCH_SPARC +#define FF_API_ARCH_SPARC (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_UNUSED_MEMBERS +#define FF_API_UNUSED_MEMBERS (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_IDCT_XVIDMMX +#define FF_API_IDCT_XVIDMMX (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_INPUT_PRESERVED +#define FF_API_INPUT_PRESERVED (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_NORMALIZE_AQP +#define FF_API_NORMALIZE_AQP (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_GMC +#define FF_API_GMC (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_MV0 +#define FF_API_MV0 (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_CODEC_NAME +#define FF_API_CODEC_NAME (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_AFD +#define FF_API_AFD (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_VISMV +/* XXX: don't forget to drop the -vismv documentation */ +#define FF_API_VISMV (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_AUDIOENC_DELAY +#define FF_API_AUDIOENC_DELAY (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_VAAPI_CONTEXT +#define FF_API_VAAPI_CONTEXT (LIBAVCODEC_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_AVCTX_TIMEBASE +#define FF_API_AVCTX_TIMEBASE (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_MPV_OPT +#define FF_API_MPV_OPT (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_STREAM_CODEC_TAG +#define FF_API_STREAM_CODEC_TAG (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_QUANT_BIAS +#define FF_API_QUANT_BIAS (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_RC_STRATEGY +#define FF_API_RC_STRATEGY (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_CODED_FRAME +#define FF_API_CODED_FRAME (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_MOTION_EST +#define FF_API_MOTION_EST (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_WITHOUT_PREFIX +#define FF_API_WITHOUT_PREFIX (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_SIDEDATA_ONLY_PKT +#define FF_API_SIDEDATA_ONLY_PKT (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_VDPAU_PROFILE +#define FF_API_VDPAU_PROFILE (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_CONVERGENCE_DURATION +#define FF_API_CONVERGENCE_DURATION (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_AVPICTURE +#define FF_API_AVPICTURE (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_AVPACKET_OLD_API +#define FF_API_AVPACKET_OLD_API (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_RTP_CALLBACK +#define FF_API_RTP_CALLBACK (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_VBV_DELAY +#define FF_API_VBV_DELAY (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_CODER_TYPE +#define FF_API_CODER_TYPE (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_STAT_BITS +#define FF_API_STAT_BITS (LIBAVCODEC_VERSION_MAJOR < 59) +#endif + +#endif /* AVCODEC_VERSION_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/videotoolbox.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/videotoolbox.h new file mode 100644 index 00000000..a48638e2 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/videotoolbox.h @@ -0,0 +1,126 @@ +/* + * Videotoolbox hardware acceleration + * + * copyright (c) 2012 Sebastien Zwickert + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VIDEOTOOLBOX_H +#define AVCODEC_VIDEOTOOLBOX_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_videotoolbox + * Public libavcodec Videotoolbox header. + */ + +#include + +#define Picture QuickdrawPicture +#include +#undef Picture + +#include "libavcodec/avcodec.h" + +/** + * This struct holds all the information that needs to be passed + * between the caller and libavcodec for initializing Videotoolbox decoding. + * Its size is not a part of the public ABI, it must be allocated with + * av_videotoolbox_alloc_context() and freed with av_free(). + */ +typedef struct AVVideotoolboxContext { + /** + * Videotoolbox decompression session object. + * Created and freed the caller. + */ + VTDecompressionSessionRef session; + + /** + * The output callback that must be passed to the session. + * Set by av_videottoolbox_default_init() + */ + VTDecompressionOutputCallback output_callback; + + /** + * CVPixelBuffer Format Type that Videotoolbox will use for decoded frames. + * set by the caller. + */ + OSType cv_pix_fmt_type; + + /** + * CoreMedia Format Description that Videotoolbox will use to create the decompression session. + * Set by the caller. + */ + CMVideoFormatDescriptionRef cm_fmt_desc; + + /** + * CoreMedia codec type that Videotoolbox will use to create the decompression session. + * Set by the caller. + */ + int cm_codec_type; +} AVVideotoolboxContext; + +/** + * Allocate and initialize a Videotoolbox context. + * + * This function should be called from the get_format() callback when the caller + * selects the AV_PIX_FMT_VIDETOOLBOX format. The caller must then create + * the decoder object (using the output callback provided by libavcodec) that + * will be used for Videotoolbox-accelerated decoding. + * + * When decoding with Videotoolbox is finished, the caller must destroy the decoder + * object and free the Videotoolbox context using av_free(). + * + * @return the newly allocated context or NULL on failure + */ +AVVideotoolboxContext *av_videotoolbox_alloc_context(void); + +/** + * This is a convenience function that creates and sets up the Videotoolbox context using + * an internal implementation. + * + * @param avctx the corresponding codec context + * + * @return >= 0 on success, a negative AVERROR code on failure + */ +int av_videotoolbox_default_init(AVCodecContext *avctx); + +/** + * This is a convenience function that creates and sets up the Videotoolbox context using + * an internal implementation. + * + * @param avctx the corresponding codec context + * @param vtctx the Videotoolbox context to use + * + * @return >= 0 on success, a negative AVERROR code on failure + */ +int av_videotoolbox_default_init2(AVCodecContext *avctx, AVVideotoolboxContext *vtctx); + +/** + * This function must be called to free the Videotoolbox context initialized with + * av_videotoolbox_default_init(). + * + * @param avctx the corresponding codec context + */ +void av_videotoolbox_default_free(AVCodecContext *avctx); + +/** + * @} + */ + +#endif /* AVCODEC_VIDEOTOOLBOX_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/vorbis_parser.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/vorbis_parser.h new file mode 100644 index 00000000..06e48bd3 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/vorbis_parser.h @@ -0,0 +1,78 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * A public API for Vorbis parsing + * + * Determines the duration for each packet. + */ + +#ifndef AVCODEC_VORBIS_PARSE_H +#define AVCODEC_VORBIS_PARSE_H + +#include + +typedef struct AVVorbisParseContext AVVorbisParseContext; + +/** + * Allocate and initialize the Vorbis parser using headers in the extradata. + * + * @param avctx codec context + * @param s Vorbis parser context + */ +AVVorbisParseContext *av_vorbis_parse_init(const uint8_t *extradata, + int extradata_size); + +/** + * Free the parser and everything associated with it. + */ +void av_vorbis_parse_free(AVVorbisParseContext **s); + +#define VORBIS_FLAG_HEADER 0x00000001 +#define VORBIS_FLAG_COMMENT 0x00000002 +#define VORBIS_FLAG_SETUP 0x00000004 + +/** + * Get the duration for a Vorbis packet. + * + * If @p flags is @c NULL, + * special frames are considered invalid. + * + * @param s Vorbis parser context + * @param buf buffer containing a Vorbis frame + * @param buf_size size of the buffer + * @param flags flags for special frames + */ +int av_vorbis_parse_frame_flags(AVVorbisParseContext *s, const uint8_t *buf, + int buf_size, int *flags); + +/** + * Get the duration for a Vorbis packet. + * + * @param s Vorbis parser context + * @param buf buffer containing a Vorbis frame + * @param buf_size size of the buffer + */ +int av_vorbis_parse_frame(AVVorbisParseContext *s, const uint8_t *buf, + int buf_size); + +void av_vorbis_parse_reset(AVVorbisParseContext *s); + +#endif /* AVCODEC_VORBIS_PARSE_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavcodec/xvmc.h b/TMessagesProj/jni/ffmpeg/include/libavcodec/xvmc.h new file mode 100644 index 00000000..465ee78d --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavcodec/xvmc.h @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2003 Ivan Kalvachev + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_XVMC_H +#define AVCODEC_XVMC_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_xvmc + * Public libavcodec XvMC header. + */ + +#include + +#include "libavutil/attributes.h" +#include "version.h" +#include "avcodec.h" + +/** + * @defgroup lavc_codec_hwaccel_xvmc XvMC + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +#define AV_XVMC_ID 0x1DC711C0 /**< special value to ensure that regular pixel routines haven't corrupted the struct + the number is 1337 speak for the letters IDCT MCo (motion compensation) */ + +struct attribute_deprecated xvmc_pix_fmt { + /** The field contains the special constant value AV_XVMC_ID. + It is used as a test that the application correctly uses the API, + and that there is no corruption caused by pixel routines. + - application - set during initialization + - libavcodec - unchanged + */ + int xvmc_id; + + /** Pointer to the block array allocated by XvMCCreateBlocks(). + The array has to be freed by XvMCDestroyBlocks(). + Each group of 64 values represents one data block of differential + pixel information (in MoCo mode) or coefficients for IDCT. + - application - set the pointer during initialization + - libavcodec - fills coefficients/pixel data into the array + */ + short* data_blocks; + + /** Pointer to the macroblock description array allocated by + XvMCCreateMacroBlocks() and freed by XvMCDestroyMacroBlocks(). + - application - set the pointer during initialization + - libavcodec - fills description data into the array + */ + XvMCMacroBlock* mv_blocks; + + /** Number of macroblock descriptions that can be stored in the mv_blocks + array. + - application - set during initialization + - libavcodec - unchanged + */ + int allocated_mv_blocks; + + /** Number of blocks that can be stored at once in the data_blocks array. + - application - set during initialization + - libavcodec - unchanged + */ + int allocated_data_blocks; + + /** Indicate that the hardware would interpret data_blocks as IDCT + coefficients and perform IDCT on them. + - application - set during initialization + - libavcodec - unchanged + */ + int idct; + + /** In MoCo mode it indicates that intra macroblocks are assumed to be in + unsigned format; same as the XVMC_INTRA_UNSIGNED flag. + - application - set during initialization + - libavcodec - unchanged + */ + int unsigned_intra; + + /** Pointer to the surface allocated by XvMCCreateSurface(). + It has to be freed by XvMCDestroySurface() on application exit. + It identifies the frame and its state on the video hardware. + - application - set during initialization + - libavcodec - unchanged + */ + XvMCSurface* p_surface; + +/** Set by the decoder before calling ff_draw_horiz_band(), + needed by the XvMCRenderSurface function. */ +//@{ + /** Pointer to the surface used as past reference + - application - unchanged + - libavcodec - set + */ + XvMCSurface* p_past_surface; + + /** Pointer to the surface used as future reference + - application - unchanged + - libavcodec - set + */ + XvMCSurface* p_future_surface; + + /** top/bottom field or frame + - application - unchanged + - libavcodec - set + */ + unsigned int picture_structure; + + /** XVMC_SECOND_FIELD - 1st or 2nd field in the sequence + - application - unchanged + - libavcodec - set + */ + unsigned int flags; +//}@ + + /** Number of macroblock descriptions in the mv_blocks array + that have already been passed to the hardware. + - application - zeroes it on get_buffer(). + A successful ff_draw_horiz_band() may increment it + with filled_mb_block_num or zero both. + - libavcodec - unchanged + */ + int start_mv_blocks_num; + + /** Number of new macroblock descriptions in the mv_blocks array (after + start_mv_blocks_num) that are filled by libavcodec and have to be + passed to the hardware. + - application - zeroes it on get_buffer() or after successful + ff_draw_horiz_band(). + - libavcodec - increment with one of each stored MB + */ + int filled_mv_blocks_num; + + /** Number of the next free data block; one data block consists of + 64 short values in the data_blocks array. + All blocks before this one have already been claimed by placing their + position into the corresponding block description structure field, + that are part of the mv_blocks array. + - application - zeroes it on get_buffer(). + A successful ff_draw_horiz_band() may zero it together + with start_mb_blocks_num. + - libavcodec - each decoded macroblock increases it by the number + of coded blocks it contains. + */ + int next_free_data_block_num; +}; + +/** + * @} + */ + +#endif /* AVCODEC_XVMC_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavformat/avformat.h b/TMessagesProj/jni/ffmpeg/include/libavformat/avformat.h new file mode 100644 index 00000000..95a645b3 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavformat/avformat.h @@ -0,0 +1,2806 @@ +/* + * copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_AVFORMAT_H +#define AVFORMAT_AVFORMAT_H + +/** + * @file + * @ingroup libavf + * Main libavformat public API header + */ + +/** + * @defgroup libavf I/O and Muxing/Demuxing Library + * @{ + * + * Libavformat (lavf) is a library for dealing with various media container + * formats. Its main two purposes are demuxing - i.e. splitting a media file + * into component streams, and the reverse process of muxing - writing supplied + * data in a specified container format. It also has an @ref lavf_io + * "I/O module" which supports a number of protocols for accessing the data (e.g. + * file, tcp, http and others). Before using lavf, you need to call + * av_register_all() to register all compiled muxers, demuxers and protocols. + * Unless you are absolutely sure you won't use libavformat's network + * capabilities, you should also call avformat_network_init(). + * + * A supported input format is described by an AVInputFormat struct, conversely + * an output format is described by AVOutputFormat. You can iterate over all + * registered input/output formats using the av_iformat_next() / + * av_oformat_next() functions. The protocols layer is not part of the public + * API, so you can only get the names of supported protocols with the + * avio_enum_protocols() function. + * + * Main lavf structure used for both muxing and demuxing is AVFormatContext, + * which exports all information about the file being read or written. As with + * most Libavformat structures, its size is not part of public ABI, so it cannot be + * allocated on stack or directly with av_malloc(). To create an + * AVFormatContext, use avformat_alloc_context() (some functions, like + * avformat_open_input() might do that for you). + * + * Most importantly an AVFormatContext contains: + * @li the @ref AVFormatContext.iformat "input" or @ref AVFormatContext.oformat + * "output" format. It is either autodetected or set by user for input; + * always set by user for output. + * @li an @ref AVFormatContext.streams "array" of AVStreams, which describe all + * elementary streams stored in the file. AVStreams are typically referred to + * using their index in this array. + * @li an @ref AVFormatContext.pb "I/O context". It is either opened by lavf or + * set by user for input, always set by user for output (unless you are dealing + * with an AVFMT_NOFILE format). + * + * @section lavf_options Passing options to (de)muxers + * It is possible to configure lavf muxers and demuxers using the @ref avoptions + * mechanism. Generic (format-independent) libavformat options are provided by + * AVFormatContext, they can be examined from a user program by calling + * av_opt_next() / av_opt_find() on an allocated AVFormatContext (or its AVClass + * from avformat_get_class()). Private (format-specific) options are provided by + * AVFormatContext.priv_data if and only if AVInputFormat.priv_class / + * AVOutputFormat.priv_class of the corresponding format struct is non-NULL. + * Further options may be provided by the @ref AVFormatContext.pb "I/O context", + * if its AVClass is non-NULL, and the protocols layer. See the discussion on + * nesting in @ref avoptions documentation to learn how to access those. + * + * @defgroup lavf_decoding Demuxing + * @{ + * Demuxers read a media file and split it into chunks of data (@em packets). A + * @ref AVPacket "packet" contains one or more encoded frames which belongs to a + * single elementary stream. In the lavf API this process is represented by the + * avformat_open_input() function for opening a file, av_read_frame() for + * reading a single packet and finally avformat_close_input(), which does the + * cleanup. + * + * @section lavf_decoding_open Opening a media file + * The minimum information required to open a file is its URL or filename, which + * is passed to avformat_open_input(), as in the following code: + * @code + * const char *url = "in.mp3"; + * AVFormatContext *s = NULL; + * int ret = avformat_open_input(&s, url, NULL, NULL); + * if (ret < 0) + * abort(); + * @endcode + * The above code attempts to allocate an AVFormatContext, open the + * specified file (autodetecting the format) and read the header, exporting the + * information stored there into s. Some formats do not have a header or do not + * store enough information there, so it is recommended that you call the + * avformat_find_stream_info() function which tries to read and decode a few + * frames to find missing information. + * + * In some cases you might want to preallocate an AVFormatContext yourself with + * avformat_alloc_context() and do some tweaking on it before passing it to + * avformat_open_input(). One such case is when you want to use custom functions + * for reading input data instead of lavf internal I/O layer. + * To do that, create your own AVIOContext with avio_alloc_context(), passing + * your reading callbacks to it. Then set the @em pb field of your + * AVFormatContext to newly created AVIOContext. + * + * Since the format of the opened file is in general not known until after + * avformat_open_input() has returned, it is not possible to set demuxer private + * options on a preallocated context. Instead, the options should be passed to + * avformat_open_input() wrapped in an AVDictionary: + * @code + * AVDictionary *options = NULL; + * av_dict_set(&options, "video_size", "640x480", 0); + * av_dict_set(&options, "pixel_format", "rgb24", 0); + * + * if (avformat_open_input(&s, url, NULL, &options) < 0) + * abort(); + * av_dict_free(&options); + * @endcode + * This code passes the private options 'video_size' and 'pixel_format' to the + * demuxer. They would be necessary for e.g. the rawvideo demuxer, since it + * cannot know how to interpret raw video data otherwise. If the format turns + * out to be something different than raw video, those options will not be + * recognized by the demuxer and therefore will not be applied. Such unrecognized + * options are then returned in the options dictionary (recognized options are + * consumed). The calling program can handle such unrecognized options as it + * wishes, e.g. + * @code + * AVDictionaryEntry *e; + * if (e = av_dict_get(options, "", NULL, AV_DICT_IGNORE_SUFFIX)) { + * fprintf(stderr, "Option %s not recognized by the demuxer.\n", e->key); + * abort(); + * } + * @endcode + * + * After you have finished reading the file, you must close it with + * avformat_close_input(). It will free everything associated with the file. + * + * @section lavf_decoding_read Reading from an opened file + * Reading data from an opened AVFormatContext is done by repeatedly calling + * av_read_frame() on it. Each call, if successful, will return an AVPacket + * containing encoded data for one AVStream, identified by + * AVPacket.stream_index. This packet may be passed straight into the libavcodec + * decoding functions avcodec_decode_video2(), avcodec_decode_audio4() or + * avcodec_decode_subtitle2() if the caller wishes to decode the data. + * + * AVPacket.pts, AVPacket.dts and AVPacket.duration timing information will be + * set if known. They may also be unset (i.e. AV_NOPTS_VALUE for + * pts/dts, 0 for duration) if the stream does not provide them. The timing + * information will be in AVStream.time_base units, i.e. it has to be + * multiplied by the timebase to convert them to seconds. + * + * If AVPacket.buf is set on the returned packet, then the packet is + * allocated dynamically and the user may keep it indefinitely. + * Otherwise, if AVPacket.buf is NULL, the packet data is backed by a + * static storage somewhere inside the demuxer and the packet is only valid + * until the next av_read_frame() call or closing the file. If the caller + * requires a longer lifetime, av_dup_packet() will make an av_malloc()ed copy + * of it. + * In both cases, the packet must be freed with av_packet_unref() when it is no + * longer needed. + * + * @section lavf_decoding_seek Seeking + * @} + * + * @defgroup lavf_encoding Muxing + * @{ + * Muxers take encoded data in the form of @ref AVPacket "AVPackets" and write + * it into files or other output bytestreams in the specified container format. + * + * The main API functions for muxing are avformat_write_header() for writing the + * file header, av_write_frame() / av_interleaved_write_frame() for writing the + * packets and av_write_trailer() for finalizing the file. + * + * At the beginning of the muxing process, the caller must first call + * avformat_alloc_context() to create a muxing context. The caller then sets up + * the muxer by filling the various fields in this context: + * + * - The @ref AVFormatContext.oformat "oformat" field must be set to select the + * muxer that will be used. + * - Unless the format is of the AVFMT_NOFILE type, the @ref AVFormatContext.pb + * "pb" field must be set to an opened IO context, either returned from + * avio_open2() or a custom one. + * - Unless the format is of the AVFMT_NOSTREAMS type, at least one stream must + * be created with the avformat_new_stream() function. The caller should fill + * the @ref AVStream.codec "stream codec context" information, such as the + * codec @ref AVCodecContext.codec_type "type", @ref AVCodecContext.codec_id + * "id" and other parameters (e.g. width / height, the pixel or sample format, + * etc.) as known. The @ref AVStream.time_base "stream timebase" should + * be set to the timebase that the caller desires to use for this stream (note + * that the timebase actually used by the muxer can be different, as will be + * described later). + * - It is advised to manually initialize only the relevant fields in + * AVCodecContext, rather than using @ref avcodec_copy_context() during + * remuxing: there is no guarantee that the codec context values remain valid + * for both input and output format contexts. + * - The caller may fill in additional information, such as @ref + * AVFormatContext.metadata "global" or @ref AVStream.metadata "per-stream" + * metadata, @ref AVFormatContext.chapters "chapters", @ref + * AVFormatContext.programs "programs", etc. as described in the + * AVFormatContext documentation. Whether such information will actually be + * stored in the output depends on what the container format and the muxer + * support. + * + * When the muxing context is fully set up, the caller must call + * avformat_write_header() to initialize the muxer internals and write the file + * header. Whether anything actually is written to the IO context at this step + * depends on the muxer, but this function must always be called. Any muxer + * private options must be passed in the options parameter to this function. + * + * The data is then sent to the muxer by repeatedly calling av_write_frame() or + * av_interleaved_write_frame() (consult those functions' documentation for + * discussion on the difference between them; only one of them may be used with + * a single muxing context, they should not be mixed). Do note that the timing + * information on the packets sent to the muxer must be in the corresponding + * AVStream's timebase. That timebase is set by the muxer (in the + * avformat_write_header() step) and may be different from the timebase + * requested by the caller. + * + * Once all the data has been written, the caller must call av_write_trailer() + * to flush any buffered packets and finalize the output file, then close the IO + * context (if any) and finally free the muxing context with + * avformat_free_context(). + * @} + * + * @defgroup lavf_io I/O Read/Write + * @{ + * @section lavf_io_dirlist Directory listing + * The directory listing API makes it possible to list files on remote servers. + * + * Some of possible use cases: + * - an "open file" dialog to choose files from a remote location, + * - a recursive media finder providing a player with an ability to play all + * files from a given directory. + * + * @subsection lavf_io_dirlist_open Opening a directory + * At first, a directory needs to be opened by calling avio_open_dir() + * supplied with a URL and, optionally, ::AVDictionary containing + * protocol-specific parameters. The function returns zero or positive + * integer and allocates AVIODirContext on success. + * + * @code + * AVIODirContext *ctx = NULL; + * if (avio_open_dir(&ctx, "smb://example.com/some_dir", NULL) < 0) { + * fprintf(stderr, "Cannot open directory.\n"); + * abort(); + * } + * @endcode + * + * This code tries to open a sample directory using smb protocol without + * any additional parameters. + * + * @subsection lavf_io_dirlist_read Reading entries + * Each directory's entry (i.e. file, another directory, anything else + * within ::AVIODirEntryType) is represented by AVIODirEntry. + * Reading consecutive entries from an opened AVIODirContext is done by + * repeatedly calling avio_read_dir() on it. Each call returns zero or + * positive integer if successful. Reading can be stopped right after the + * NULL entry has been read -- it means there are no entries left to be + * read. The following code reads all entries from a directory associated + * with ctx and prints their names to standard output. + * @code + * AVIODirEntry *entry = NULL; + * for (;;) { + * if (avio_read_dir(ctx, &entry) < 0) { + * fprintf(stderr, "Cannot list directory.\n"); + * abort(); + * } + * if (!entry) + * break; + * printf("%s\n", entry->name); + * avio_free_directory_entry(&entry); + * } + * @endcode + * @} + * + * @defgroup lavf_codec Demuxers + * @{ + * @defgroup lavf_codec_native Native Demuxers + * @{ + * @} + * @defgroup lavf_codec_wrappers External library wrappers + * @{ + * @} + * @} + * @defgroup lavf_protos I/O Protocols + * @{ + * @} + * @defgroup lavf_internal Internal + * @{ + * @} + * @} + * + */ + +#include +#include /* FILE */ +#include "libavcodec/avcodec.h" +#include "libavutil/dict.h" +#include "libavutil/log.h" + +#include "avio.h" +#include "libavformat/version.h" + +struct AVFormatContext; + +struct AVDeviceInfoList; +struct AVDeviceCapabilitiesQuery; + +/** + * @defgroup metadata_api Public Metadata API + * @{ + * @ingroup libavf + * The metadata API allows libavformat to export metadata tags to a client + * application when demuxing. Conversely it allows a client application to + * set metadata when muxing. + * + * Metadata is exported or set as pairs of key/value strings in the 'metadata' + * fields of the AVFormatContext, AVStream, AVChapter and AVProgram structs + * using the @ref lavu_dict "AVDictionary" API. Like all strings in FFmpeg, + * metadata is assumed to be UTF-8 encoded Unicode. Note that metadata + * exported by demuxers isn't checked to be valid UTF-8 in most cases. + * + * Important concepts to keep in mind: + * - Keys are unique; there can never be 2 tags with the same key. This is + * also meant semantically, i.e., a demuxer should not knowingly produce + * several keys that are literally different but semantically identical. + * E.g., key=Author5, key=Author6. In this example, all authors must be + * placed in the same tag. + * - Metadata is flat, not hierarchical; there are no subtags. If you + * want to store, e.g., the email address of the child of producer Alice + * and actor Bob, that could have key=alice_and_bobs_childs_email_address. + * - Several modifiers can be applied to the tag name. This is done by + * appending a dash character ('-') and the modifier name in the order + * they appear in the list below -- e.g. foo-eng-sort, not foo-sort-eng. + * - language -- a tag whose value is localized for a particular language + * is appended with the ISO 639-2/B 3-letter language code. + * For example: Author-ger=Michael, Author-eng=Mike + * The original/default language is in the unqualified "Author" tag. + * A demuxer should set a default if it sets any translated tag. + * - sorting -- a modified version of a tag that should be used for + * sorting will have '-sort' appended. E.g. artist="The Beatles", + * artist-sort="Beatles, The". + * - Some protocols and demuxers support metadata updates. After a successful + * call to av_read_packet(), AVFormatContext.event_flags or AVStream.event_flags + * will be updated to indicate if metadata changed. In order to detect metadata + * changes on a stream, you need to loop through all streams in the AVFormatContext + * and check their individual event_flags. + * + * - Demuxers attempt to export metadata in a generic format, however tags + * with no generic equivalents are left as they are stored in the container. + * Follows a list of generic tag names: + * + @verbatim + album -- name of the set this work belongs to + album_artist -- main creator of the set/album, if different from artist. + e.g. "Various Artists" for compilation albums. + artist -- main creator of the work + comment -- any additional description of the file. + composer -- who composed the work, if different from artist. + copyright -- name of copyright holder. + creation_time-- date when the file was created, preferably in ISO 8601. + date -- date when the work was created, preferably in ISO 8601. + disc -- number of a subset, e.g. disc in a multi-disc collection. + encoder -- name/settings of the software/hardware that produced the file. + encoded_by -- person/group who created the file. + filename -- original name of the file. + genre -- . + language -- main language in which the work is performed, preferably + in ISO 639-2 format. Multiple languages can be specified by + separating them with commas. + performer -- artist who performed the work, if different from artist. + E.g for "Also sprach Zarathustra", artist would be "Richard + Strauss" and performer "London Philharmonic Orchestra". + publisher -- name of the label/publisher. + service_name -- name of the service in broadcasting (channel name). + service_provider -- name of the service provider in broadcasting. + title -- name of the work. + track -- number of this work in the set, can be in form current/total. + variant_bitrate -- the total bitrate of the bitrate variant that the current stream is part of + @endverbatim + * + * Look in the examples section for an application example how to use the Metadata API. + * + * @} + */ + +/* packet functions */ + + +/** + * Allocate and read the payload of a packet and initialize its + * fields with default values. + * + * @param s associated IO context + * @param pkt packet + * @param size desired payload size + * @return >0 (read size) if OK, AVERROR_xxx otherwise + */ +int av_get_packet(AVIOContext *s, AVPacket *pkt, int size); + + +/** + * Read data and append it to the current content of the AVPacket. + * If pkt->size is 0 this is identical to av_get_packet. + * Note that this uses av_grow_packet and thus involves a realloc + * which is inefficient. Thus this function should only be used + * when there is no reasonable way to know (an upper bound of) + * the final size. + * + * @param s associated IO context + * @param pkt packet + * @param size amount of data to read + * @return >0 (read size) if OK, AVERROR_xxx otherwise, previous data + * will not be lost even if an error occurs. + */ +int av_append_packet(AVIOContext *s, AVPacket *pkt, int size); + +#if FF_API_LAVF_FRAC +/*************************************************/ +/* fractional numbers for exact pts handling */ + +/** + * The exact value of the fractional number is: 'val + num / den'. + * num is assumed to be 0 <= num < den. + */ +typedef struct AVFrac { + int64_t val, num, den; +} AVFrac; +#endif + +/*************************************************/ +/* input/output formats */ + +struct AVCodecTag; + +/** + * This structure contains the data a format has to probe a file. + */ +typedef struct AVProbeData { + const char *filename; + unsigned char *buf; /**< Buffer must have AVPROBE_PADDING_SIZE of extra allocated bytes filled with zero. */ + int buf_size; /**< Size of buf except extra allocated bytes */ + const char *mime_type; /**< mime_type, when known. */ +} AVProbeData; + +#define AVPROBE_SCORE_RETRY (AVPROBE_SCORE_MAX/4) +#define AVPROBE_SCORE_STREAM_RETRY (AVPROBE_SCORE_MAX/4-1) + +#define AVPROBE_SCORE_EXTENSION 50 ///< score for file extension +#define AVPROBE_SCORE_MIME 75 ///< score for file mime type +#define AVPROBE_SCORE_MAX 100 ///< maximum score + +#define AVPROBE_PADDING_SIZE 32 ///< extra allocated bytes at the end of the probe buffer + +/// Demuxer will use avio_open, no opened file should be provided by the caller. +#define AVFMT_NOFILE 0x0001 +#define AVFMT_NEEDNUMBER 0x0002 /**< Needs '%d' in filename. */ +#define AVFMT_SHOW_IDS 0x0008 /**< Show format stream IDs numbers. */ +#if FF_API_LAVF_FMT_RAWPICTURE +#define AVFMT_RAWPICTURE 0x0020 /**< Format wants AVPicture structure for + raw picture data. @deprecated Not used anymore */ +#endif +#define AVFMT_GLOBALHEADER 0x0040 /**< Format wants global header. */ +#define AVFMT_NOTIMESTAMPS 0x0080 /**< Format does not need / have any timestamps. */ +#define AVFMT_GENERIC_INDEX 0x0100 /**< Use generic index building code. */ +#define AVFMT_TS_DISCONT 0x0200 /**< Format allows timestamp discontinuities. Note, muxers always require valid (monotone) timestamps */ +#define AVFMT_VARIABLE_FPS 0x0400 /**< Format allows variable fps. */ +#define AVFMT_NODIMENSIONS 0x0800 /**< Format does not need width/height */ +#define AVFMT_NOSTREAMS 0x1000 /**< Format does not require any streams */ +#define AVFMT_NOBINSEARCH 0x2000 /**< Format does not allow to fall back on binary search via read_timestamp */ +#define AVFMT_NOGENSEARCH 0x4000 /**< Format does not allow to fall back on generic search */ +#define AVFMT_NO_BYTE_SEEK 0x8000 /**< Format does not allow seeking by bytes */ +#define AVFMT_ALLOW_FLUSH 0x10000 /**< Format allows flushing. If not set, the muxer will not receive a NULL packet in the write_packet function. */ +#define AVFMT_TS_NONSTRICT 0x20000 /**< Format does not require strictly + increasing timestamps, but they must + still be monotonic */ +#define AVFMT_TS_NEGATIVE 0x40000 /**< Format allows muxing negative + timestamps. If not set the timestamp + will be shifted in av_write_frame and + av_interleaved_write_frame so they + start from 0. + The user or muxer can override this through + AVFormatContext.avoid_negative_ts + */ + +#define AVFMT_SEEK_TO_PTS 0x4000000 /**< Seeking is based on PTS */ + +/** + * @addtogroup lavf_encoding + * @{ + */ +typedef struct AVOutputFormat { + const char *name; + /** + * Descriptive name for the format, meant to be more human-readable + * than name. You should use the NULL_IF_CONFIG_SMALL() macro + * to define it. + */ + const char *long_name; + const char *mime_type; + const char *extensions; /**< comma-separated filename extensions */ + /* output support */ + enum AVCodecID audio_codec; /**< default audio codec */ + enum AVCodecID video_codec; /**< default video codec */ + enum AVCodecID subtitle_codec; /**< default subtitle codec */ + /** + * can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, + * AVFMT_GLOBALHEADER, AVFMT_NOTIMESTAMPS, AVFMT_VARIABLE_FPS, + * AVFMT_NODIMENSIONS, AVFMT_NOSTREAMS, AVFMT_ALLOW_FLUSH, + * AVFMT_TS_NONSTRICT + */ + int flags; + + /** + * List of supported codec_id-codec_tag pairs, ordered by "better + * choice first". The arrays are all terminated by AV_CODEC_ID_NONE. + */ + const struct AVCodecTag * const *codec_tag; + + + const AVClass *priv_class; ///< AVClass for the private context + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavformat and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + struct AVOutputFormat *next; + /** + * size of private data so that it can be allocated in the wrapper + */ + int priv_data_size; + + int (*write_header)(struct AVFormatContext *); + /** + * Write a packet. If AVFMT_ALLOW_FLUSH is set in flags, + * pkt can be NULL in order to flush data buffered in the muxer. + * When flushing, return 0 if there still is more data to flush, + * or 1 if everything was flushed and there is no more buffered + * data. + */ + int (*write_packet)(struct AVFormatContext *, AVPacket *pkt); + int (*write_trailer)(struct AVFormatContext *); + /** + * Currently only used to set pixel format if not YUV420P. + */ + int (*interleave_packet)(struct AVFormatContext *, AVPacket *out, + AVPacket *in, int flush); + /** + * Test if the given codec can be stored in this container. + * + * @return 1 if the codec is supported, 0 if it is not. + * A negative number if unknown. + * MKTAG('A', 'P', 'I', 'C') if the codec is only supported as AV_DISPOSITION_ATTACHED_PIC + */ + int (*query_codec)(enum AVCodecID id, int std_compliance); + + void (*get_output_timestamp)(struct AVFormatContext *s, int stream, + int64_t *dts, int64_t *wall); + /** + * Allows sending messages from application to device. + */ + int (*control_message)(struct AVFormatContext *s, int type, + void *data, size_t data_size); + + /** + * Write an uncoded AVFrame. + * + * See av_write_uncoded_frame() for details. + * + * The library will free *frame afterwards, but the muxer can prevent it + * by setting the pointer to NULL. + */ + int (*write_uncoded_frame)(struct AVFormatContext *, int stream_index, + AVFrame **frame, unsigned flags); + /** + * Returns device list with it properties. + * @see avdevice_list_devices() for more details. + */ + int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list); + /** + * Initialize device capabilities submodule. + * @see avdevice_capabilities_create() for more details. + */ + int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); + /** + * Free device capabilities submodule. + * @see avdevice_capabilities_free() for more details. + */ + int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); + enum AVCodecID data_codec; /**< default data codec */ + /** + * Initialize format. May allocate data here, and set any AVFormatContext or + * AVStream parameters that need to be set before packets are sent. + * This method must not write output. + * + * Any allocations made here must be freed in deinit(). + */ + int (*init)(struct AVFormatContext *); + /** + * Deinitialize format. If present, this is called whenever the muxer is being + * destroyed, regardless of whether or not the header has been written. + * + * If a trailer is being written, this is called after write_trailer(). + * + * This is called if init() fails as well. + */ + void (*deinit)(struct AVFormatContext *); + /** + * Set up any necessary bitstream filtering and extract any extra data needed + * for the global header. + * Return 0 if more packets from this stream must be checked; 1 if not. + */ + int (*check_bitstream)(struct AVFormatContext *, const AVPacket *pkt); +} AVOutputFormat; +/** + * @} + */ + +/** + * @addtogroup lavf_decoding + * @{ + */ +typedef struct AVInputFormat { + /** + * A comma separated list of short names for the format. New names + * may be appended with a minor bump. + */ + const char *name; + + /** + * Descriptive name for the format, meant to be more human-readable + * than name. You should use the NULL_IF_CONFIG_SMALL() macro + * to define it. + */ + const char *long_name; + + /** + * Can use flags: AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_SHOW_IDS, + * AVFMT_GENERIC_INDEX, AVFMT_TS_DISCONT, AVFMT_NOBINSEARCH, + * AVFMT_NOGENSEARCH, AVFMT_NO_BYTE_SEEK, AVFMT_SEEK_TO_PTS. + */ + int flags; + + /** + * If extensions are defined, then no probe is done. You should + * usually not use extension format guessing because it is not + * reliable enough + */ + const char *extensions; + + const struct AVCodecTag * const *codec_tag; + + const AVClass *priv_class; ///< AVClass for the private context + + /** + * Comma-separated list of mime types. + * It is used check for matching mime types while probing. + * @see av_probe_input_format2 + */ + const char *mime_type; + + /***************************************************************** + * No fields below this line are part of the public API. They + * may not be used outside of libavformat and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + struct AVInputFormat *next; + + /** + * Raw demuxers store their codec ID here. + */ + int raw_codec_id; + + /** + * Size of private data so that it can be allocated in the wrapper. + */ + int priv_data_size; + + /** + * Tell if a given file has a chance of being parsed as this format. + * The buffer provided is guaranteed to be AVPROBE_PADDING_SIZE bytes + * big so you do not have to check for that unless you need more. + */ + int (*read_probe)(AVProbeData *); + + /** + * Read the format header and initialize the AVFormatContext + * structure. Return 0 if OK. 'avformat_new_stream' should be + * called to create new streams. + */ + int (*read_header)(struct AVFormatContext *); + + /** + * Read one packet and put it in 'pkt'. pts and flags are also + * set. 'avformat_new_stream' can be called only if the flag + * AVFMTCTX_NOHEADER is used and only in the calling thread (not in a + * background thread). + * @return 0 on success, < 0 on error. + * When returning an error, pkt must not have been allocated + * or must be freed before returning + */ + int (*read_packet)(struct AVFormatContext *, AVPacket *pkt); + + /** + * Close the stream. The AVFormatContext and AVStreams are not + * freed by this function + */ + int (*read_close)(struct AVFormatContext *); + + /** + * Seek to a given timestamp relative to the frames in + * stream component stream_index. + * @param stream_index Must not be -1. + * @param flags Selects which direction should be preferred if no exact + * match is available. + * @return >= 0 on success (but not necessarily the new offset) + */ + int (*read_seek)(struct AVFormatContext *, + int stream_index, int64_t timestamp, int flags); + + /** + * Get the next timestamp in stream[stream_index].time_base units. + * @return the timestamp or AV_NOPTS_VALUE if an error occurred + */ + int64_t (*read_timestamp)(struct AVFormatContext *s, int stream_index, + int64_t *pos, int64_t pos_limit); + + /** + * Start/resume playing - only meaningful if using a network-based format + * (RTSP). + */ + int (*read_play)(struct AVFormatContext *); + + /** + * Pause playing - only meaningful if using a network-based format + * (RTSP). + */ + int (*read_pause)(struct AVFormatContext *); + + /** + * Seek to timestamp ts. + * Seeking will be done so that the point from which all active streams + * can be presented successfully will be closest to ts and within min/max_ts. + * Active streams are all streams that have AVStream.discard < AVDISCARD_ALL. + */ + int (*read_seek2)(struct AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags); + + /** + * Returns device list with it properties. + * @see avdevice_list_devices() for more details. + */ + int (*get_device_list)(struct AVFormatContext *s, struct AVDeviceInfoList *device_list); + + /** + * Initialize device capabilities submodule. + * @see avdevice_capabilities_create() for more details. + */ + int (*create_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); + + /** + * Free device capabilities submodule. + * @see avdevice_capabilities_free() for more details. + */ + int (*free_device_capabilities)(struct AVFormatContext *s, struct AVDeviceCapabilitiesQuery *caps); +} AVInputFormat; +/** + * @} + */ + +enum AVStreamParseType { + AVSTREAM_PARSE_NONE, + AVSTREAM_PARSE_FULL, /**< full parsing and repack */ + AVSTREAM_PARSE_HEADERS, /**< Only parse headers, do not repack. */ + AVSTREAM_PARSE_TIMESTAMPS, /**< full parsing and interpolation of timestamps for frames not starting on a packet boundary */ + AVSTREAM_PARSE_FULL_ONCE, /**< full parsing and repack of the first frame only, only implemented for H.264 currently */ + AVSTREAM_PARSE_FULL_RAW=MKTAG(0,'R','A','W'), /**< full parsing and repack with timestamp and position generation by parser for raw + this assumes that each packet in the file contains no demuxer level headers and + just codec level data, otherwise position generation would fail */ +}; + +typedef struct AVIndexEntry { + int64_t pos; + int64_t timestamp; /**< + * Timestamp in AVStream.time_base units, preferably the time from which on correctly decoded frames are available + * when seeking to this entry. That means preferable PTS on keyframe based formats. + * But demuxers can choose to store a different timestamp, if it is more convenient for the implementation or nothing better + * is known + */ +#define AVINDEX_KEYFRAME 0x0001 + int flags:2; + int size:30; //Yeah, trying to keep the size of this small to reduce memory requirements (it is 24 vs. 32 bytes due to possible 8-byte alignment). + int min_distance; /**< Minimum distance between this and the previous keyframe, used to avoid unneeded searching. */ +} AVIndexEntry; + +#define AV_DISPOSITION_DEFAULT 0x0001 +#define AV_DISPOSITION_DUB 0x0002 +#define AV_DISPOSITION_ORIGINAL 0x0004 +#define AV_DISPOSITION_COMMENT 0x0008 +#define AV_DISPOSITION_LYRICS 0x0010 +#define AV_DISPOSITION_KARAOKE 0x0020 + +/** + * Track should be used during playback by default. + * Useful for subtitle track that should be displayed + * even when user did not explicitly ask for subtitles. + */ +#define AV_DISPOSITION_FORCED 0x0040 +#define AV_DISPOSITION_HEARING_IMPAIRED 0x0080 /**< stream for hearing impaired audiences */ +#define AV_DISPOSITION_VISUAL_IMPAIRED 0x0100 /**< stream for visual impaired audiences */ +#define AV_DISPOSITION_CLEAN_EFFECTS 0x0200 /**< stream without voice */ +/** + * The stream is stored in the file as an attached picture/"cover art" (e.g. + * APIC frame in ID3v2). The single packet associated with it will be returned + * among the first few packets read from the file unless seeking takes place. + * It can also be accessed at any time in AVStream.attached_pic. + */ +#define AV_DISPOSITION_ATTACHED_PIC 0x0400 + +typedef struct AVStreamInternal AVStreamInternal; + +/** + * To specify text track kind (different from subtitles default). + */ +#define AV_DISPOSITION_CAPTIONS 0x10000 +#define AV_DISPOSITION_DESCRIPTIONS 0x20000 +#define AV_DISPOSITION_METADATA 0x40000 + +/** + * Options for behavior on timestamp wrap detection. + */ +#define AV_PTS_WRAP_IGNORE 0 ///< ignore the wrap +#define AV_PTS_WRAP_ADD_OFFSET 1 ///< add the format specific offset on wrap detection +#define AV_PTS_WRAP_SUB_OFFSET -1 ///< subtract the format specific offset on wrap detection + +/** + * Stream structure. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * sizeof(AVStream) must not be used outside libav*. + */ +typedef struct AVStream { + int index; /**< stream index in AVFormatContext */ + /** + * Format-specific stream ID. + * decoding: set by libavformat + * encoding: set by the user, replaced by libavformat if left unset + */ + int id; + /** + * Codec context associated with this stream. Allocated and freed by + * libavformat. + * + * - decoding: The demuxer exports codec information stored in the headers + * here. + * - encoding: The user sets codec information, the muxer writes it to the + * output. Mandatory fields as specified in AVCodecContext + * documentation must be set even if this AVCodecContext is + * not actually used for encoding. + */ + AVCodecContext *codec; + void *priv_data; + +#if FF_API_LAVF_FRAC + /** + * @deprecated this field is unused + */ + attribute_deprecated + struct AVFrac pts; +#endif + + /** + * This is the fundamental unit of time (in seconds) in terms + * of which frame timestamps are represented. + * + * decoding: set by libavformat + * encoding: May be set by the caller before avformat_write_header() to + * provide a hint to the muxer about the desired timebase. In + * avformat_write_header(), the muxer will overwrite this field + * with the timebase that will actually be used for the timestamps + * written into the file (which may or may not be related to the + * user-provided one, depending on the format). + */ + AVRational time_base; + + /** + * Decoding: pts of the first frame of the stream in presentation order, in stream time base. + * Only set this if you are absolutely 100% sure that the value you set + * it to really is the pts of the first frame. + * This may be undefined (AV_NOPTS_VALUE). + * @note The ASF header does NOT contain a correct start_time the ASF + * demuxer must NOT set this. + */ + int64_t start_time; + + /** + * Decoding: duration of the stream, in stream time base. + * If a source file does not specify a duration, but does specify + * a bitrate, this value will be estimated from bitrate and file size. + */ + int64_t duration; + + int64_t nb_frames; ///< number of frames in this stream if known or 0 + + int disposition; /**< AV_DISPOSITION_* bit field */ + + enum AVDiscard discard; ///< Selects which packets can be discarded at will and do not need to be demuxed. + + /** + * sample aspect ratio (0 if unknown) + * - encoding: Set by user. + * - decoding: Set by libavformat. + */ + AVRational sample_aspect_ratio; + + AVDictionary *metadata; + + /** + * Average framerate + * + * - demuxing: May be set by libavformat when creating the stream or in + * avformat_find_stream_info(). + * - muxing: May be set by the caller before avformat_write_header(). + */ + AVRational avg_frame_rate; + + /** + * For streams with AV_DISPOSITION_ATTACHED_PIC disposition, this packet + * will contain the attached picture. + * + * decoding: set by libavformat, must not be modified by the caller. + * encoding: unused + */ + AVPacket attached_pic; + + /** + * An array of side data that applies to the whole stream (i.e. the + * container does not allow it to change between packets). + * + * There may be no overlap between the side data in this array and side data + * in the packets. I.e. a given side data is either exported by the muxer + * (demuxing) / set by the caller (muxing) in this array, then it never + * appears in the packets, or the side data is exported / sent through + * the packets (always in the first packet where the value becomes known or + * changes), then it does not appear in this array. + * + * - demuxing: Set by libavformat when the stream is created. + * - muxing: May be set by the caller before avformat_write_header(). + * + * Freed by libavformat in avformat_free_context(). + * + * @see av_format_inject_global_side_data() + */ + AVPacketSideData *side_data; + /** + * The number of elements in the AVStream.side_data array. + */ + int nb_side_data; + + /** + * Flags for the user to detect events happening on the stream. Flags must + * be cleared by the user once the event has been handled. + * A combination of AVSTREAM_EVENT_FLAG_*. + */ + int event_flags; +#define AVSTREAM_EVENT_FLAG_METADATA_UPDATED 0x0001 ///< The call resulted in updated metadata. + + /***************************************************************** + * All fields below this line are not part of the public API. They + * may not be used outside of libavformat and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + + /** + * Stream information used internally by av_find_stream_info() + */ +#define MAX_STD_TIMEBASES (30*12+7+6) + struct { + int64_t last_dts; + int64_t duration_gcd; + int duration_count; + int64_t rfps_duration_sum; + double (*duration_error)[2][MAX_STD_TIMEBASES]; + int64_t codec_info_duration; + int64_t codec_info_duration_fields; + + /** + * 0 -> decoder has not been searched for yet. + * >0 -> decoder found + * <0 -> decoder with codec_id == -found_decoder has not been found + */ + int found_decoder; + + int64_t last_duration; + + /** + * Those are used for average framerate estimation. + */ + int64_t fps_first_dts; + int fps_first_dts_idx; + int64_t fps_last_dts; + int fps_last_dts_idx; + + } *info; + + int pts_wrap_bits; /**< number of bits in pts (used for wrapping control) */ + + // Timestamp generation support: + /** + * Timestamp corresponding to the last dts sync point. + * + * Initialized when AVCodecParserContext.dts_sync_point >= 0 and + * a DTS is received from the underlying container. Otherwise set to + * AV_NOPTS_VALUE by default. + */ + int64_t first_dts; + int64_t cur_dts; + int64_t last_IP_pts; + int last_IP_duration; + + /** + * Number of packets to buffer for codec probing + */ + int probe_packets; + + /** + * Number of frames that have been demuxed during av_find_stream_info() + */ + int codec_info_nb_frames; + + /* av_read_frame() support */ + enum AVStreamParseType need_parsing; + struct AVCodecParserContext *parser; + + /** + * last packet in packet_buffer for this stream when muxing. + */ + struct AVPacketList *last_in_packet_buffer; + AVProbeData probe_data; +#define MAX_REORDER_DELAY 16 + int64_t pts_buffer[MAX_REORDER_DELAY+1]; + + AVIndexEntry *index_entries; /**< Only used if the format does not + support seeking natively. */ + int nb_index_entries; + unsigned int index_entries_allocated_size; + + /** + * Real base framerate of the stream. + * This is the lowest framerate with which all timestamps can be + * represented accurately (it is the least common multiple of all + * framerates in the stream). Note, this value is just a guess! + * For example, if the time base is 1/90000 and all frames have either + * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1. + * + * Code outside avformat should access this field using: + * av_stream_get/set_r_frame_rate(stream) + */ + AVRational r_frame_rate; + + /** + * Stream Identifier + * This is the MPEG-TS stream identifier +1 + * 0 means unknown + */ + int stream_identifier; + + int64_t interleaver_chunk_size; + int64_t interleaver_chunk_duration; + + /** + * stream probing state + * -1 -> probing finished + * 0 -> no probing requested + * rest -> perform probing with request_probe being the minimum score to accept. + * NOT PART OF PUBLIC API + */ + int request_probe; + /** + * Indicates that everything up to the next keyframe + * should be discarded. + */ + int skip_to_keyframe; + + /** + * Number of samples to skip at the start of the frame decoded from the next packet. + */ + int skip_samples; + + /** + * If not 0, the number of samples that should be skipped from the start of + * the stream (the samples are removed from packets with pts==0, which also + * assumes negative timestamps do not happen). + * Intended for use with formats such as mp3 with ad-hoc gapless audio + * support. + */ + int64_t start_skip_samples; + + /** + * If not 0, the first audio sample that should be discarded from the stream. + * This is broken by design (needs global sample count), but can't be + * avoided for broken by design formats such as mp3 with ad-hoc gapless + * audio support. + */ + int64_t first_discard_sample; + + /** + * The sample after last sample that is intended to be discarded after + * first_discard_sample. Works on frame boundaries only. Used to prevent + * early EOF if the gapless info is broken (considered concatenated mp3s). + */ + int64_t last_discard_sample; + + /** + * Number of internally decoded frames, used internally in libavformat, do not access + * its lifetime differs from info which is why it is not in that structure. + */ + int nb_decoded_frames; + + /** + * Timestamp offset added to timestamps before muxing + * NOT PART OF PUBLIC API + */ + int64_t mux_ts_offset; + + /** + * Internal data to check for wrapping of the time stamp + */ + int64_t pts_wrap_reference; + + /** + * Options for behavior, when a wrap is detected. + * + * Defined by AV_PTS_WRAP_ values. + * + * If correction is enabled, there are two possibilities: + * If the first time stamp is near the wrap point, the wrap offset + * will be subtracted, which will create negative time stamps. + * Otherwise the offset will be added. + */ + int pts_wrap_behavior; + + /** + * Internal data to prevent doing update_initial_durations() twice + */ + int update_initial_durations_done; + + /** + * Internal data to generate dts from pts + */ + int64_t pts_reorder_error[MAX_REORDER_DELAY+1]; + uint8_t pts_reorder_error_count[MAX_REORDER_DELAY+1]; + + /** + * Internal data to analyze DTS and detect faulty mpeg streams + */ + int64_t last_dts_for_order_check; + uint8_t dts_ordered; + uint8_t dts_misordered; + + /** + * Internal data to inject global side data + */ + int inject_global_side_data; + + /** + * String containing paris of key and values describing recommended encoder configuration. + * Paris are separated by ','. + * Keys are separated from values by '='. + */ + char *recommended_encoder_configuration; + + /** + * display aspect ratio (0 if unknown) + * - encoding: unused + * - decoding: Set by libavformat to calculate sample_aspect_ratio internally + */ + AVRational display_aspect_ratio; + + struct FFFrac *priv_pts; + + /** + * An opaque field for libavformat internal usage. + * Must not be accessed in any way by callers. + */ + AVStreamInternal *internal; +} AVStream; + +AVRational av_stream_get_r_frame_rate(const AVStream *s); +void av_stream_set_r_frame_rate(AVStream *s, AVRational r); +struct AVCodecParserContext *av_stream_get_parser(const AVStream *s); +char* av_stream_get_recommended_encoder_configuration(const AVStream *s); +void av_stream_set_recommended_encoder_configuration(AVStream *s, char *configuration); + +/** + * Returns the pts of the last muxed packet + its duration + * + * the retuned value is undefined when used with a demuxer. + */ +int64_t av_stream_get_end_pts(const AVStream *st); + +#define AV_PROGRAM_RUNNING 1 + +/** + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * sizeof(AVProgram) must not be used outside libav*. + */ +typedef struct AVProgram { + int id; + int flags; + enum AVDiscard discard; ///< selects which program to discard and which to feed to the caller + unsigned int *stream_index; + unsigned int nb_stream_indexes; + AVDictionary *metadata; + + int program_num; + int pmt_pid; + int pcr_pid; + + /***************************************************************** + * All fields below this line are not part of the public API. They + * may not be used outside of libavformat and can be changed and + * removed at will. + * New public fields should be added right above. + ***************************************************************** + */ + int64_t start_time; + int64_t end_time; + + int64_t pts_wrap_reference; ///< reference dts for wrap detection + int pts_wrap_behavior; ///< behavior on wrap detection +} AVProgram; + +#define AVFMTCTX_NOHEADER 0x0001 /**< signal that no header is present + (streams are added dynamically) */ + +typedef struct AVChapter { + int id; ///< unique ID to identify the chapter + AVRational time_base; ///< time base in which the start/end timestamps are specified + int64_t start, end; ///< chapter start/end time in time_base units + AVDictionary *metadata; +} AVChapter; + + +/** + * Callback used by devices to communicate with application. + */ +typedef int (*av_format_control_message)(struct AVFormatContext *s, int type, + void *data, size_t data_size); + +typedef int (*AVOpenCallback)(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, + const AVIOInterruptCB *int_cb, AVDictionary **options); + +/** + * The duration of a video can be estimated through various ways, and this enum can be used + * to know how the duration was estimated. + */ +enum AVDurationEstimationMethod { + AVFMT_DURATION_FROM_PTS, ///< Duration accurately estimated from PTSes + AVFMT_DURATION_FROM_STREAM, ///< Duration estimated from a stream with a known duration + AVFMT_DURATION_FROM_BITRATE ///< Duration estimated from bitrate (less accurate) +}; + +typedef struct AVFormatInternal AVFormatInternal; + +/** + * Format I/O context. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * sizeof(AVFormatContext) must not be used outside libav*, use + * avformat_alloc_context() to create an AVFormatContext. + */ +typedef struct AVFormatContext { + /** + * A class for logging and @ref avoptions. Set by avformat_alloc_context(). + * Exports (de)muxer private options if they exist. + */ + const AVClass *av_class; + + /** + * The input container format. + * + * Demuxing only, set by avformat_open_input(). + */ + struct AVInputFormat *iformat; + + /** + * The output container format. + * + * Muxing only, must be set by the caller before avformat_write_header(). + */ + struct AVOutputFormat *oformat; + + /** + * Format private data. This is an AVOptions-enabled struct + * if and only if iformat/oformat.priv_class is not NULL. + * + * - muxing: set by avformat_write_header() + * - demuxing: set by avformat_open_input() + */ + void *priv_data; + + /** + * I/O context. + * + * - demuxing: either set by the user before avformat_open_input() (then + * the user must close it manually) or set by avformat_open_input(). + * - muxing: set by the user before avformat_write_header(). The caller must + * take care of closing / freeing the IO context. + * + * Do NOT set this field if AVFMT_NOFILE flag is set in + * iformat/oformat.flags. In such a case, the (de)muxer will handle + * I/O in some other way and this field will be NULL. + */ + AVIOContext *pb; + + /* stream info */ + /** + * Flags signalling stream properties. A combination of AVFMTCTX_*. + * Set by libavformat. + */ + int ctx_flags; + + /** + * Number of elements in AVFormatContext.streams. + * + * Set by avformat_new_stream(), must not be modified by any other code. + */ + unsigned int nb_streams; + /** + * A list of all streams in the file. New streams are created with + * avformat_new_stream(). + * + * - demuxing: streams are created by libavformat in avformat_open_input(). + * If AVFMTCTX_NOHEADER is set in ctx_flags, then new streams may also + * appear in av_read_frame(). + * - muxing: streams are created by the user before avformat_write_header(). + * + * Freed by libavformat in avformat_free_context(). + */ + AVStream **streams; + + /** + * input or output filename + * + * - demuxing: set by avformat_open_input() + * - muxing: may be set by the caller before avformat_write_header() + */ + char filename[1024]; + + /** + * Position of the first frame of the component, in + * AV_TIME_BASE fractional seconds. NEVER set this value directly: + * It is deduced from the AVStream values. + * + * Demuxing only, set by libavformat. + */ + int64_t start_time; + + /** + * Duration of the stream, in AV_TIME_BASE fractional + * seconds. Only set this value if you know none of the individual stream + * durations and also do not set any of them. This is deduced from the + * AVStream values if not set. + * + * Demuxing only, set by libavformat. + */ + int64_t duration; + + /** + * Total stream bitrate in bit/s, 0 if not + * available. Never set it directly if the file_size and the + * duration are known as FFmpeg can compute it automatically. + */ + int64_t bit_rate; + + unsigned int packet_size; + int max_delay; + + /** + * Flags modifying the (de)muxer behaviour. A combination of AVFMT_FLAG_*. + * Set by the user before avformat_open_input() / avformat_write_header(). + */ + int flags; +#define AVFMT_FLAG_GENPTS 0x0001 ///< Generate missing pts even if it requires parsing future frames. +#define AVFMT_FLAG_IGNIDX 0x0002 ///< Ignore index. +#define AVFMT_FLAG_NONBLOCK 0x0004 ///< Do not block when reading packets from input. +#define AVFMT_FLAG_IGNDTS 0x0008 ///< Ignore DTS on frames that contain both DTS & PTS +#define AVFMT_FLAG_NOFILLIN 0x0010 ///< Do not infer any values from other values, just return what is stored in the container +#define AVFMT_FLAG_NOPARSE 0x0020 ///< Do not use AVParsers, you also must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no parsing -> no frames. Also seeking to frames can not work if parsing to find frame boundaries has been disabled +#define AVFMT_FLAG_NOBUFFER 0x0040 ///< Do not buffer frames when possible +#define AVFMT_FLAG_CUSTOM_IO 0x0080 ///< The caller has supplied a custom AVIOContext, don't avio_close() it. +#define AVFMT_FLAG_DISCARD_CORRUPT 0x0100 ///< Discard frames marked corrupted +#define AVFMT_FLAG_FLUSH_PACKETS 0x0200 ///< Flush the AVIOContext every packet. +/** + * When muxing, try to avoid writing any random/volatile data to the output. + * This includes any random IDs, real-time timestamps/dates, muxer version, etc. + * + * This flag is mainly intended for testing. + */ +#define AVFMT_FLAG_BITEXACT 0x0400 +#define AVFMT_FLAG_MP4A_LATM 0x8000 ///< Enable RTP MP4A-LATM payload +#define AVFMT_FLAG_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down) +#define AVFMT_FLAG_PRIV_OPT 0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted) +#define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Don't merge side data but keep it separate. +#define AVFMT_FLAG_FAST_SEEK 0x80000 ///< Enable fast, but inaccurate seeks for some formats + + /** + * Maximum size of the data read from input for determining + * the input container format. + * Demuxing only, set by the caller before avformat_open_input(). + */ + int64_t probesize; + + /** + * Maximum duration (in AV_TIME_BASE units) of the data read + * from input in avformat_find_stream_info(). + * Demuxing only, set by the caller before avformat_find_stream_info(). + * Can be set to 0 to let avformat choose using a heuristic. + */ + int64_t max_analyze_duration; + + const uint8_t *key; + int keylen; + + unsigned int nb_programs; + AVProgram **programs; + + /** + * Forced video codec_id. + * Demuxing: Set by user. + */ + enum AVCodecID video_codec_id; + + /** + * Forced audio codec_id. + * Demuxing: Set by user. + */ + enum AVCodecID audio_codec_id; + + /** + * Forced subtitle codec_id. + * Demuxing: Set by user. + */ + enum AVCodecID subtitle_codec_id; + + /** + * Maximum amount of memory in bytes to use for the index of each stream. + * If the index exceeds this size, entries will be discarded as + * needed to maintain a smaller size. This can lead to slower or less + * accurate seeking (depends on demuxer). + * Demuxers for which a full in-memory index is mandatory will ignore + * this. + * - muxing: unused + * - demuxing: set by user + */ + unsigned int max_index_size; + + /** + * Maximum amount of memory in bytes to use for buffering frames + * obtained from realtime capture devices. + */ + unsigned int max_picture_buffer; + + /** + * Number of chapters in AVChapter array. + * When muxing, chapters are normally written in the file header, + * so nb_chapters should normally be initialized before write_header + * is called. Some muxers (e.g. mov and mkv) can also write chapters + * in the trailer. To write chapters in the trailer, nb_chapters + * must be zero when write_header is called and non-zero when + * write_trailer is called. + * - muxing: set by user + * - demuxing: set by libavformat + */ + unsigned int nb_chapters; + AVChapter **chapters; + + /** + * Metadata that applies to the whole file. + * + * - demuxing: set by libavformat in avformat_open_input() + * - muxing: may be set by the caller before avformat_write_header() + * + * Freed by libavformat in avformat_free_context(). + */ + AVDictionary *metadata; + + /** + * Start time of the stream in real world time, in microseconds + * since the Unix epoch (00:00 1st January 1970). That is, pts=0 in the + * stream was captured at this real world time. + * - muxing: Set by the caller before avformat_write_header(). If set to + * either 0 or AV_NOPTS_VALUE, then the current wall-time will + * be used. + * - demuxing: Set by libavformat. AV_NOPTS_VALUE if unknown. Note that + * the value may become known after some number of frames + * have been received. + */ + int64_t start_time_realtime; + + /** + * The number of frames used for determining the framerate in + * avformat_find_stream_info(). + * Demuxing only, set by the caller before avformat_find_stream_info(). + */ + int fps_probe_size; + + /** + * Error recognition; higher values will detect more errors but may + * misdetect some more or less valid parts as errors. + * Demuxing only, set by the caller before avformat_open_input(). + */ + int error_recognition; + + /** + * Custom interrupt callbacks for the I/O layer. + * + * demuxing: set by the user before avformat_open_input(). + * muxing: set by the user before avformat_write_header() + * (mainly useful for AVFMT_NOFILE formats). The callback + * should also be passed to avio_open2() if it's used to + * open the file. + */ + AVIOInterruptCB interrupt_callback; + + /** + * Flags to enable debugging. + */ + int debug; +#define FF_FDEBUG_TS 0x0001 + + /** + * Maximum buffering duration for interleaving. + * + * To ensure all the streams are interleaved correctly, + * av_interleaved_write_frame() will wait until it has at least one packet + * for each stream before actually writing any packets to the output file. + * When some streams are "sparse" (i.e. there are large gaps between + * successive packets), this can result in excessive buffering. + * + * This field specifies the maximum difference between the timestamps of the + * first and the last packet in the muxing queue, above which libavformat + * will output a packet regardless of whether it has queued a packet for all + * the streams. + * + * Muxing only, set by the caller before avformat_write_header(). + */ + int64_t max_interleave_delta; + + /** + * Allow non-standard and experimental extension + * @see AVCodecContext.strict_std_compliance + */ + int strict_std_compliance; + + /** + * Flags for the user to detect events happening on the file. Flags must + * be cleared by the user once the event has been handled. + * A combination of AVFMT_EVENT_FLAG_*. + */ + int event_flags; +#define AVFMT_EVENT_FLAG_METADATA_UPDATED 0x0001 ///< The call resulted in updated metadata. + + /** + * Maximum number of packets to read while waiting for the first timestamp. + * Decoding only. + */ + int max_ts_probe; + + /** + * Avoid negative timestamps during muxing. + * Any value of the AVFMT_AVOID_NEG_TS_* constants. + * Note, this only works when using av_interleaved_write_frame. (interleave_packet_per_dts is in use) + * - muxing: Set by user + * - demuxing: unused + */ + int avoid_negative_ts; +#define AVFMT_AVOID_NEG_TS_AUTO -1 ///< Enabled when required by target format +#define AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE 1 ///< Shift timestamps so they are non negative +#define AVFMT_AVOID_NEG_TS_MAKE_ZERO 2 ///< Shift timestamps so that they start at 0 + + /** + * Transport stream id. + * This will be moved into demuxer private options. Thus no API/ABI compatibility + */ + int ts_id; + + /** + * Audio preload in microseconds. + * Note, not all formats support this and unpredictable things may happen if it is used when not supported. + * - encoding: Set by user via AVOptions (NO direct access) + * - decoding: unused + */ + int audio_preload; + + /** + * Max chunk time in microseconds. + * Note, not all formats support this and unpredictable things may happen if it is used when not supported. + * - encoding: Set by user via AVOptions (NO direct access) + * - decoding: unused + */ + int max_chunk_duration; + + /** + * Max chunk size in bytes + * Note, not all formats support this and unpredictable things may happen if it is used when not supported. + * - encoding: Set by user via AVOptions (NO direct access) + * - decoding: unused + */ + int max_chunk_size; + + /** + * forces the use of wallclock timestamps as pts/dts of packets + * This has undefined results in the presence of B frames. + * - encoding: unused + * - decoding: Set by user via AVOptions (NO direct access) + */ + int use_wallclock_as_timestamps; + + /** + * avio flags, used to force AVIO_FLAG_DIRECT. + * - encoding: unused + * - decoding: Set by user via AVOptions (NO direct access) + */ + int avio_flags; + + /** + * The duration field can be estimated through various ways, and this field can be used + * to know how the duration was estimated. + * - encoding: unused + * - decoding: Read by user via AVOptions (NO direct access) + */ + enum AVDurationEstimationMethod duration_estimation_method; + + /** + * Skip initial bytes when opening stream + * - encoding: unused + * - decoding: Set by user via AVOptions (NO direct access) + */ + int64_t skip_initial_bytes; + + /** + * Correct single timestamp overflows + * - encoding: unused + * - decoding: Set by user via AVOptions (NO direct access) + */ + unsigned int correct_ts_overflow; + + /** + * Force seeking to any (also non key) frames. + * - encoding: unused + * - decoding: Set by user via AVOptions (NO direct access) + */ + int seek2any; + + /** + * Flush the I/O context after each packet. + * - encoding: Set by user via AVOptions (NO direct access) + * - decoding: unused + */ + int flush_packets; + + /** + * format probing score. + * The maximal score is AVPROBE_SCORE_MAX, its set when the demuxer probes + * the format. + * - encoding: unused + * - decoding: set by avformat, read by user via av_format_get_probe_score() (NO direct access) + */ + int probe_score; + + /** + * number of bytes to read maximally to identify format. + * - encoding: unused + * - decoding: set by user through AVOPtions (NO direct access) + */ + int format_probesize; + + /** + * ',' separated list of allowed decoders. + * If NULL then all are allowed + * - encoding: unused + * - decoding: set by user through AVOptions (NO direct access) + */ + char *codec_whitelist; + + /** + * ',' separated list of allowed demuxers. + * If NULL then all are allowed + * - encoding: unused + * - decoding: set by user through AVOptions (NO direct access) + */ + char *format_whitelist; + + /** + * An opaque field for libavformat internal usage. + * Must not be accessed in any way by callers. + */ + AVFormatInternal *internal; + + /** + * IO repositioned flag. + * This is set by avformat when the underlaying IO context read pointer + * is repositioned, for example when doing byte based seeking. + * Demuxers can use the flag to detect such changes. + */ + int io_repositioned; + + /** + * Forced video codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user via av_format_set_video_codec (NO direct access). + */ + AVCodec *video_codec; + + /** + * Forced audio codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user via av_format_set_audio_codec (NO direct access). + */ + AVCodec *audio_codec; + + /** + * Forced subtitle codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user via av_format_set_subtitle_codec (NO direct access). + */ + AVCodec *subtitle_codec; + + /** + * Forced data codec. + * This allows forcing a specific decoder, even when there are multiple with + * the same codec_id. + * Demuxing: Set by user via av_format_set_data_codec (NO direct access). + */ + AVCodec *data_codec; + + /** + * Number of bytes to be written as padding in a metadata header. + * Demuxing: Unused. + * Muxing: Set by user via av_format_set_metadata_header_padding. + */ + int metadata_header_padding; + + /** + * User data. + * This is a place for some private data of the user. + * Mostly usable with control_message_cb or any future callbacks in device's context. + */ + void *opaque; + + /** + * Callback used by devices to communicate with application. + */ + av_format_control_message control_message_cb; + + /** + * Output timestamp offset, in microseconds. + * Muxing: set by user via AVOptions (NO direct access) + */ + int64_t output_ts_offset; + + /** + * dump format separator. + * can be ", " or "\n " or anything else + * Code outside libavformat should access this field using AVOptions + * (NO direct access). + * - muxing: Set by user. + * - demuxing: Set by user. + */ + uint8_t *dump_separator; + + /** + * Forced Data codec_id. + * Demuxing: Set by user. + */ + enum AVCodecID data_codec_id; + + /** + * Called to open further IO contexts when needed for demuxing. + * + * This can be set by the user application to perform security checks on + * the URLs before opening them. + * The function should behave like avio_open2(), AVFormatContext is provided + * as contextual information and to reach AVFormatContext.opaque. + * + * If NULL then some simple checks are used together with avio_open2(). + * + * Must not be accessed directly from outside avformat. + * @See av_format_set_open_cb() + * + * Demuxing: Set by user. + */ + int (*open_cb)(struct AVFormatContext *s, AVIOContext **p, const char *url, int flags, const AVIOInterruptCB *int_cb, AVDictionary **options); +} AVFormatContext; + +int av_format_get_probe_score(const AVFormatContext *s); +AVCodec * av_format_get_video_codec(const AVFormatContext *s); +void av_format_set_video_codec(AVFormatContext *s, AVCodec *c); +AVCodec * av_format_get_audio_codec(const AVFormatContext *s); +void av_format_set_audio_codec(AVFormatContext *s, AVCodec *c); +AVCodec * av_format_get_subtitle_codec(const AVFormatContext *s); +void av_format_set_subtitle_codec(AVFormatContext *s, AVCodec *c); +AVCodec * av_format_get_data_codec(const AVFormatContext *s); +void av_format_set_data_codec(AVFormatContext *s, AVCodec *c); +int av_format_get_metadata_header_padding(const AVFormatContext *s); +void av_format_set_metadata_header_padding(AVFormatContext *s, int c); +void * av_format_get_opaque(const AVFormatContext *s); +void av_format_set_opaque(AVFormatContext *s, void *opaque); +av_format_control_message av_format_get_control_message_cb(const AVFormatContext *s); +void av_format_set_control_message_cb(AVFormatContext *s, av_format_control_message callback); +AVOpenCallback av_format_get_open_cb(const AVFormatContext *s); +void av_format_set_open_cb(AVFormatContext *s, AVOpenCallback callback); + +/** + * This function will cause global side data to be injected in the next packet + * of each stream as well as after any subsequent seek. + */ +void av_format_inject_global_side_data(AVFormatContext *s); + +/** + * Returns the method used to set ctx->duration. + * + * @return AVFMT_DURATION_FROM_PTS, AVFMT_DURATION_FROM_STREAM, or AVFMT_DURATION_FROM_BITRATE. + */ +enum AVDurationEstimationMethod av_fmt_ctx_get_duration_estimation_method(const AVFormatContext* ctx); + +typedef struct AVPacketList { + AVPacket pkt; + struct AVPacketList *next; +} AVPacketList; + + +/** + * @defgroup lavf_core Core functions + * @ingroup libavf + * + * Functions for querying libavformat capabilities, allocating core structures, + * etc. + * @{ + */ + +/** + * Return the LIBAVFORMAT_VERSION_INT constant. + */ +unsigned avformat_version(void); + +/** + * Return the libavformat build-time configuration. + */ +const char *avformat_configuration(void); + +/** + * Return the libavformat license. + */ +const char *avformat_license(void); + +/** + * Initialize libavformat and register all the muxers, demuxers and + * protocols. If you do not call this function, then you can select + * exactly which formats you want to support. + * + * @see av_register_input_format() + * @see av_register_output_format() + */ +void av_register_all(void); + +void av_register_input_format(AVInputFormat *format); +void av_register_output_format(AVOutputFormat *format); + +/** + * Do global initialization of network components. This is optional, + * but recommended, since it avoids the overhead of implicitly + * doing the setup for each session. + * + * Calling this function will become mandatory if using network + * protocols at some major version bump. + */ +int avformat_network_init(void); + +/** + * Undo the initialization done by avformat_network_init. + */ +int avformat_network_deinit(void); + +/** + * If f is NULL, returns the first registered input format, + * if f is non-NULL, returns the next registered input format after f + * or NULL if f is the last one. + */ +AVInputFormat *av_iformat_next(const AVInputFormat *f); + +/** + * If f is NULL, returns the first registered output format, + * if f is non-NULL, returns the next registered output format after f + * or NULL if f is the last one. + */ +AVOutputFormat *av_oformat_next(const AVOutputFormat *f); + +/** + * Allocate an AVFormatContext. + * avformat_free_context() can be used to free the context and everything + * allocated by the framework within it. + */ +AVFormatContext *avformat_alloc_context(void); + +/** + * Free an AVFormatContext and all its streams. + * @param s context to free + */ +void avformat_free_context(AVFormatContext *s); + +/** + * Get the AVClass for AVFormatContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avformat_get_class(void); + +/** + * Add a new stream to a media file. + * + * When demuxing, it is called by the demuxer in read_header(). If the + * flag AVFMTCTX_NOHEADER is set in s.ctx_flags, then it may also + * be called in read_packet(). + * + * When muxing, should be called by the user before avformat_write_header(). + * + * User is required to call avcodec_close() and avformat_free_context() to + * clean up the allocation by avformat_new_stream(). + * + * @param s media file handle + * @param c If non-NULL, the AVCodecContext corresponding to the new stream + * will be initialized to use this codec. This is needed for e.g. codec-specific + * defaults to be set, so codec should be provided if it is known. + * + * @return newly created stream or NULL on error. + */ +AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c); + +/** + * Allocate new information from stream. + * + * @param stream stream + * @param type desired side information type + * @param size side information size + * @return pointer to fresh allocated data or NULL otherwise + */ +uint8_t *av_stream_new_side_data(AVStream *stream, + enum AVPacketSideDataType type, int size); +/** + * Get side information from stream. + * + * @param stream stream + * @param type desired side information type + * @param size pointer for side information size to store (optional) + * @return pointer to data if present or NULL otherwise + */ +uint8_t *av_stream_get_side_data(AVStream *stream, + enum AVPacketSideDataType type, int *size); + +AVProgram *av_new_program(AVFormatContext *s, int id); + +/** + * @} + */ + + +/** + * Allocate an AVFormatContext for an output format. + * avformat_free_context() can be used to free the context and + * everything allocated by the framework within it. + * + * @param *ctx is set to the created format context, or to NULL in + * case of failure + * @param oformat format to use for allocating the context, if NULL + * format_name and filename are used instead + * @param format_name the name of output format to use for allocating the + * context, if NULL filename is used instead + * @param filename the name of the filename to use for allocating the + * context, may be NULL + * @return >= 0 in case of success, a negative AVERROR code in case of + * failure + */ +int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, + const char *format_name, const char *filename); + +/** + * @addtogroup lavf_decoding + * @{ + */ + +/** + * Find AVInputFormat based on the short name of the input format. + */ +AVInputFormat *av_find_input_format(const char *short_name); + +/** + * Guess the file format. + * + * @param pd data to be probed + * @param is_opened Whether the file is already opened; determines whether + * demuxers with or without AVFMT_NOFILE are probed. + */ +AVInputFormat *av_probe_input_format(AVProbeData *pd, int is_opened); + +/** + * Guess the file format. + * + * @param pd data to be probed + * @param is_opened Whether the file is already opened; determines whether + * demuxers with or without AVFMT_NOFILE are probed. + * @param score_max A probe score larger that this is required to accept a + * detection, the variable is set to the actual detection + * score afterwards. + * If the score is <= AVPROBE_SCORE_MAX / 4 it is recommended + * to retry with a larger probe buffer. + */ +AVInputFormat *av_probe_input_format2(AVProbeData *pd, int is_opened, int *score_max); + +/** + * Guess the file format. + * + * @param is_opened Whether the file is already opened; determines whether + * demuxers with or without AVFMT_NOFILE are probed. + * @param score_ret The score of the best detection. + */ +AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret); + +/** + * Probe a bytestream to determine the input format. Each time a probe returns + * with a score that is too low, the probe buffer size is increased and another + * attempt is made. When the maximum probe size is reached, the input format + * with the highest score is returned. + * + * @param pb the bytestream to probe + * @param fmt the input format is put here + * @param filename the filename of the stream + * @param logctx the log context + * @param offset the offset within the bytestream to probe from + * @param max_probe_size the maximum probe buffer size (zero for default) + * @return the score in case of success, a negative value corresponding to an + * the maximal score is AVPROBE_SCORE_MAX + * AVERROR code otherwise + */ +int av_probe_input_buffer2(AVIOContext *pb, AVInputFormat **fmt, + const char *filename, void *logctx, + unsigned int offset, unsigned int max_probe_size); + +/** + * Like av_probe_input_buffer2() but returns 0 on success + */ +int av_probe_input_buffer(AVIOContext *pb, AVInputFormat **fmt, + const char *filename, void *logctx, + unsigned int offset, unsigned int max_probe_size); + +/** + * Open an input stream and read the header. The codecs are not opened. + * The stream must be closed with avformat_close_input(). + * + * @param ps Pointer to user-supplied AVFormatContext (allocated by avformat_alloc_context). + * May be a pointer to NULL, in which case an AVFormatContext is allocated by this + * function and written into ps. + * Note that a user-supplied AVFormatContext will be freed on failure. + * @param filename Name of the stream to open. + * @param fmt If non-NULL, this parameter forces a specific input format. + * Otherwise the format is autodetected. + * @param options A dictionary filled with AVFormatContext and demuxer-private options. + * On return this parameter will be destroyed and replaced with a dict containing + * options that were not found. May be NULL. + * + * @return 0 on success, a negative AVERROR on failure. + * + * @note If you want to use custom IO, preallocate the format context and set its pb field. + */ +int avformat_open_input(AVFormatContext **ps, const char *filename, AVInputFormat *fmt, AVDictionary **options); + +attribute_deprecated +int av_demuxer_open(AVFormatContext *ic); + +/** + * Read packets of a media file to get stream information. This + * is useful for file formats with no headers such as MPEG. This + * function also computes the real framerate in case of MPEG-2 repeat + * frame mode. + * The logical file position is not changed by this function; + * examined packets may be buffered for later processing. + * + * @param ic media file handle + * @param options If non-NULL, an ic.nb_streams long array of pointers to + * dictionaries, where i-th member contains options for + * codec corresponding to i-th stream. + * On return each dictionary will be filled with options that were not found. + * @return >=0 if OK, AVERROR_xxx on error + * + * @note this function isn't guaranteed to open all the codecs, so + * options being non-empty at return is a perfectly normal behavior. + * + * @todo Let the user decide somehow what information is needed so that + * we do not waste time getting stuff the user does not need. + */ +int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options); + +/** + * Find the programs which belong to a given stream. + * + * @param ic media file handle + * @param last the last found program, the search will start after this + * program, or from the beginning if it is NULL + * @param s stream index + * @return the next program which belongs to s, NULL if no program is found or + * the last program is not among the programs of ic. + */ +AVProgram *av_find_program_from_stream(AVFormatContext *ic, AVProgram *last, int s); + +void av_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int idx); + +/** + * Find the "best" stream in the file. + * The best stream is determined according to various heuristics as the most + * likely to be what the user expects. + * If the decoder parameter is non-NULL, av_find_best_stream will find the + * default decoder for the stream's codec; streams for which no decoder can + * be found are ignored. + * + * @param ic media file handle + * @param type stream type: video, audio, subtitles, etc. + * @param wanted_stream_nb user-requested stream number, + * or -1 for automatic selection + * @param related_stream try to find a stream related (eg. in the same + * program) to this one, or -1 if none + * @param decoder_ret if non-NULL, returns the decoder for the + * selected stream + * @param flags flags; none are currently defined + * @return the non-negative stream number in case of success, + * AVERROR_STREAM_NOT_FOUND if no stream with the requested type + * could be found, + * AVERROR_DECODER_NOT_FOUND if streams were found but no decoder + * @note If av_find_best_stream returns successfully and decoder_ret is not + * NULL, then *decoder_ret is guaranteed to be set to a valid AVCodec. + */ +int av_find_best_stream(AVFormatContext *ic, + enum AVMediaType type, + int wanted_stream_nb, + int related_stream, + AVCodec **decoder_ret, + int flags); + +/** + * Return the next frame of a stream. + * This function returns what is stored in the file, and does not validate + * that what is there are valid frames for the decoder. It will split what is + * stored in the file into frames and return one for each call. It will not + * omit invalid data between valid frames so as to give the decoder the maximum + * information possible for decoding. + * + * If pkt->buf is NULL, then the packet is valid until the next + * av_read_frame() or until avformat_close_input(). Otherwise the packet + * is valid indefinitely. In both cases the packet must be freed with + * av_packet_unref when it is no longer needed. For video, the packet contains + * exactly one frame. For audio, it contains an integer number of frames if each + * frame has a known fixed size (e.g. PCM or ADPCM data). If the audio frames + * have a variable size (e.g. MPEG audio), then it contains one frame. + * + * pkt->pts, pkt->dts and pkt->duration are always set to correct + * values in AVStream.time_base units (and guessed if the format cannot + * provide them). pkt->pts can be AV_NOPTS_VALUE if the video format + * has B-frames, so it is better to rely on pkt->dts if you do not + * decompress the payload. + * + * @return 0 if OK, < 0 on error or end of file + */ +int av_read_frame(AVFormatContext *s, AVPacket *pkt); + +/** + * Seek to the keyframe at timestamp. + * 'timestamp' in 'stream_index'. + * + * @param s media file handle + * @param stream_index If stream_index is (-1), a default + * stream is selected, and timestamp is automatically converted + * from AV_TIME_BASE units to the stream specific time_base. + * @param timestamp Timestamp in AVStream.time_base units + * or, if no stream is specified, in AV_TIME_BASE units. + * @param flags flags which select direction and seeking mode + * @return >= 0 on success + */ +int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, + int flags); + +/** + * Seek to timestamp ts. + * Seeking will be done so that the point from which all active streams + * can be presented successfully will be closest to ts and within min/max_ts. + * Active streams are all streams that have AVStream.discard < AVDISCARD_ALL. + * + * If flags contain AVSEEK_FLAG_BYTE, then all timestamps are in bytes and + * are the file position (this may not be supported by all demuxers). + * If flags contain AVSEEK_FLAG_FRAME, then all timestamps are in frames + * in the stream with stream_index (this may not be supported by all demuxers). + * Otherwise all timestamps are in units of the stream selected by stream_index + * or if stream_index is -1, in AV_TIME_BASE units. + * If flags contain AVSEEK_FLAG_ANY, then non-keyframes are treated as + * keyframes (this may not be supported by all demuxers). + * If flags contain AVSEEK_FLAG_BACKWARD, it is ignored. + * + * @param s media file handle + * @param stream_index index of the stream which is used as time base reference + * @param min_ts smallest acceptable timestamp + * @param ts target timestamp + * @param max_ts largest acceptable timestamp + * @param flags flags + * @return >=0 on success, error code otherwise + * + * @note This is part of the new seek API which is still under construction. + * Thus do not use this yet. It may change at any time, do not expect + * ABI compatibility yet! + */ +int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts, int64_t ts, int64_t max_ts, int flags); + +/** + * Discard all internally buffered data. This can be useful when dealing with + * discontinuities in the byte stream. Generally works only with formats that + * can resync. This includes headerless formats like MPEG-TS/TS but should also + * work with NUT, Ogg and in a limited way AVI for example. + * + * The set of streams, the detected duration, stream parameters and codecs do + * not change when calling this function. If you want a complete reset, it's + * better to open a new AVFormatContext. + * + * This does not flush the AVIOContext (s->pb). If necessary, call + * avio_flush(s->pb) before calling this function. + * + * @param s media file handle + * @return >=0 on success, error code otherwise + */ +int avformat_flush(AVFormatContext *s); + +/** + * Start playing a network-based stream (e.g. RTSP stream) at the + * current position. + */ +int av_read_play(AVFormatContext *s); + +/** + * Pause a network-based stream (e.g. RTSP stream). + * + * Use av_read_play() to resume it. + */ +int av_read_pause(AVFormatContext *s); + +/** + * Close an opened input AVFormatContext. Free it and all its contents + * and set *s to NULL. + */ +void avformat_close_input(AVFormatContext **s); +/** + * @} + */ + +#define AVSEEK_FLAG_BACKWARD 1 ///< seek backward +#define AVSEEK_FLAG_BYTE 2 ///< seeking based on position in bytes +#define AVSEEK_FLAG_ANY 4 ///< seek to any frame, even non-keyframes +#define AVSEEK_FLAG_FRAME 8 ///< seeking based on frame number + +/** + * @addtogroup lavf_encoding + * @{ + */ +/** + * Allocate the stream private data and write the stream header to + * an output media file. + * + * @param s Media file handle, must be allocated with avformat_alloc_context(). + * Its oformat field must be set to the desired output format; + * Its pb field must be set to an already opened AVIOContext. + * @param options An AVDictionary filled with AVFormatContext and muxer-private options. + * On return this parameter will be destroyed and replaced with a dict containing + * options that were not found. May be NULL. + * + * @return 0 on success, negative AVERROR on failure. + * + * @see av_opt_find, av_dict_set, avio_open, av_oformat_next. + */ +av_warn_unused_result +int avformat_write_header(AVFormatContext *s, AVDictionary **options); + +/** + * Write a packet to an output media file. + * + * This function passes the packet directly to the muxer, without any buffering + * or reordering. The caller is responsible for correctly interleaving the + * packets if the format requires it. Callers that want libavformat to handle + * the interleaving should call av_interleaved_write_frame() instead of this + * function. + * + * @param s media file handle + * @param pkt The packet containing the data to be written. Note that unlike + * av_interleaved_write_frame(), this function does not take + * ownership of the packet passed to it (though some muxers may make + * an internal reference to the input packet). + *
+ * This parameter can be NULL (at any time, not just at the end), in + * order to immediately flush data buffered within the muxer, for + * muxers that buffer up data internally before writing it to the + * output. + *
+ * Packet's @ref AVPacket.stream_index "stream_index" field must be + * set to the index of the corresponding stream in @ref + * AVFormatContext.streams "s->streams". + *
+ * The timestamps (@ref AVPacket.pts "pts", @ref AVPacket.dts "dts") + * must be set to correct values in the stream's timebase (unless the + * output format is flagged with the AVFMT_NOTIMESTAMPS flag, then + * they can be set to AV_NOPTS_VALUE). + * The dts for subsequent packets passed to this function must be strictly + * increasing when compared in their respective timebases (unless the + * output format is flagged with the AVFMT_TS_NONSTRICT, then they + * merely have to be nondecreasing). @ref AVPacket.duration + * "duration") should also be set if known. + * @return < 0 on error, = 0 if OK, 1 if flushed and there is no more data to flush + * + * @see av_interleaved_write_frame() + */ +int av_write_frame(AVFormatContext *s, AVPacket *pkt); + +/** + * Write a packet to an output media file ensuring correct interleaving. + * + * This function will buffer the packets internally as needed to make sure the + * packets in the output file are properly interleaved in the order of + * increasing dts. Callers doing their own interleaving should call + * av_write_frame() instead of this function. + * + * @param s media file handle + * @param pkt The packet containing the data to be written. + *
+ * If the packet is reference-counted, this function will take + * ownership of this reference and unreference it later when it sees + * fit. + * The caller must not access the data through this reference after + * this function returns. If the packet is not reference-counted, + * libavformat will make a copy. + *
+ * This parameter can be NULL (at any time, not just at the end), to + * flush the interleaving queues. + *
+ * Packet's @ref AVPacket.stream_index "stream_index" field must be + * set to the index of the corresponding stream in @ref + * AVFormatContext.streams "s->streams". + *
+ * The timestamps (@ref AVPacket.pts "pts", @ref AVPacket.dts "dts") + * must be set to correct values in the stream's timebase (unless the + * output format is flagged with the AVFMT_NOTIMESTAMPS flag, then + * they can be set to AV_NOPTS_VALUE). + * The dts for subsequent packets in one stream must be strictly + * increasing (unless the output format is flagged with the + * AVFMT_TS_NONSTRICT, then they merely have to be nondecreasing). + * @ref AVPacket.duration "duration") should also be set if known. + * + * @return 0 on success, a negative AVERROR on error. Libavformat will always + * take care of freeing the packet, even if this function fails. + * + * @see av_write_frame(), AVFormatContext.max_interleave_delta + */ +int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt); + +/** + * Write a uncoded frame to an output media file. + * + * The frame must be correctly interleaved according to the container + * specification; if not, then av_interleaved_write_frame() must be used. + * + * See av_interleaved_write_frame() for details. + */ +int av_write_uncoded_frame(AVFormatContext *s, int stream_index, + AVFrame *frame); + +/** + * Write a uncoded frame to an output media file. + * + * If the muxer supports it, this function makes it possible to write an AVFrame + * structure directly, without encoding it into a packet. + * It is mostly useful for devices and similar special muxers that use raw + * video or PCM data and will not serialize it into a byte stream. + * + * To test whether it is possible to use it with a given muxer and stream, + * use av_write_uncoded_frame_query(). + * + * The caller gives up ownership of the frame and must not access it + * afterwards. + * + * @return >=0 for success, a negative code on error + */ +int av_interleaved_write_uncoded_frame(AVFormatContext *s, int stream_index, + AVFrame *frame); + +/** + * Test whether a muxer supports uncoded frame. + * + * @return >=0 if an uncoded frame can be written to that muxer and stream, + * <0 if not + */ +int av_write_uncoded_frame_query(AVFormatContext *s, int stream_index); + +/** + * Write the stream trailer to an output media file and free the + * file private data. + * + * May only be called after a successful call to avformat_write_header. + * + * @param s media file handle + * @return 0 if OK, AVERROR_xxx on error + */ +int av_write_trailer(AVFormatContext *s); + +/** + * Return the output format in the list of registered output formats + * which best matches the provided parameters, or return NULL if + * there is no match. + * + * @param short_name if non-NULL checks if short_name matches with the + * names of the registered formats + * @param filename if non-NULL checks if filename terminates with the + * extensions of the registered formats + * @param mime_type if non-NULL checks if mime_type matches with the + * MIME type of the registered formats + */ +AVOutputFormat *av_guess_format(const char *short_name, + const char *filename, + const char *mime_type); + +/** + * Guess the codec ID based upon muxer and filename. + */ +enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, + const char *filename, const char *mime_type, + enum AVMediaType type); + +/** + * Get timing information for the data currently output. + * The exact meaning of "currently output" depends on the format. + * It is mostly relevant for devices that have an internal buffer and/or + * work in real time. + * @param s media file handle + * @param stream stream in the media file + * @param[out] dts DTS of the last packet output for the stream, in stream + * time_base units + * @param[out] wall absolute time when that packet whas output, + * in microsecond + * @return 0 if OK, AVERROR(ENOSYS) if the format does not support it + * Note: some formats or devices may not allow to measure dts and wall + * atomically. + */ +int av_get_output_timestamp(struct AVFormatContext *s, int stream, + int64_t *dts, int64_t *wall); + + +/** + * @} + */ + + +/** + * @defgroup lavf_misc Utility functions + * @ingroup libavf + * @{ + * + * Miscellaneous utility functions related to both muxing and demuxing + * (or neither). + */ + +/** + * Send a nice hexadecimal dump of a buffer to the specified file stream. + * + * @param f The file stream pointer where the dump should be sent to. + * @param buf buffer + * @param size buffer size + * + * @see av_hex_dump_log, av_pkt_dump2, av_pkt_dump_log2 + */ +void av_hex_dump(FILE *f, const uint8_t *buf, int size); + +/** + * Send a nice hexadecimal dump of a buffer to the log. + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message, lower values signifying + * higher importance. + * @param buf buffer + * @param size buffer size + * + * @see av_hex_dump, av_pkt_dump2, av_pkt_dump_log2 + */ +void av_hex_dump_log(void *avcl, int level, const uint8_t *buf, int size); + +/** + * Send a nice dump of a packet to the specified file stream. + * + * @param f The file stream pointer where the dump should be sent to. + * @param pkt packet to dump + * @param dump_payload True if the payload must be displayed, too. + * @param st AVStream that the packet belongs to + */ +void av_pkt_dump2(FILE *f, const AVPacket *pkt, int dump_payload, const AVStream *st); + + +/** + * Send a nice dump of a packet to the log. + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message, lower values signifying + * higher importance. + * @param pkt packet to dump + * @param dump_payload True if the payload must be displayed, too. + * @param st AVStream that the packet belongs to + */ +void av_pkt_dump_log2(void *avcl, int level, const AVPacket *pkt, int dump_payload, + const AVStream *st); + +/** + * Get the AVCodecID for the given codec tag tag. + * If no codec id is found returns AV_CODEC_ID_NONE. + * + * @param tags list of supported codec_id-codec_tag pairs, as stored + * in AVInputFormat.codec_tag and AVOutputFormat.codec_tag + * @param tag codec tag to match to a codec ID + */ +enum AVCodecID av_codec_get_id(const struct AVCodecTag * const *tags, unsigned int tag); + +/** + * Get the codec tag for the given codec id id. + * If no codec tag is found returns 0. + * + * @param tags list of supported codec_id-codec_tag pairs, as stored + * in AVInputFormat.codec_tag and AVOutputFormat.codec_tag + * @param id codec ID to match to a codec tag + */ +unsigned int av_codec_get_tag(const struct AVCodecTag * const *tags, enum AVCodecID id); + +/** + * Get the codec tag for the given codec id. + * + * @param tags list of supported codec_id - codec_tag pairs, as stored + * in AVInputFormat.codec_tag and AVOutputFormat.codec_tag + * @param id codec id that should be searched for in the list + * @param tag A pointer to the found tag + * @return 0 if id was not found in tags, > 0 if it was found + */ +int av_codec_get_tag2(const struct AVCodecTag * const *tags, enum AVCodecID id, + unsigned int *tag); + +int av_find_default_stream_index(AVFormatContext *s); + +/** + * Get the index for a specific timestamp. + * + * @param st stream that the timestamp belongs to + * @param timestamp timestamp to retrieve the index for + * @param flags if AVSEEK_FLAG_BACKWARD then the returned index will correspond + * to the timestamp which is <= the requested one, if backward + * is 0, then it will be >= + * if AVSEEK_FLAG_ANY seek to any frame, only keyframes otherwise + * @return < 0 if no such timestamp could be found + */ +int av_index_search_timestamp(AVStream *st, int64_t timestamp, int flags); + +/** + * Add an index entry into a sorted list. Update the entry if the list + * already contains it. + * + * @param timestamp timestamp in the time base of the given stream + */ +int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp, + int size, int distance, int flags); + + +/** + * Split a URL string into components. + * + * The pointers to buffers for storing individual components may be null, + * in order to ignore that component. Buffers for components not found are + * set to empty strings. If the port is not found, it is set to a negative + * value. + * + * @param proto the buffer for the protocol + * @param proto_size the size of the proto buffer + * @param authorization the buffer for the authorization + * @param authorization_size the size of the authorization buffer + * @param hostname the buffer for the host name + * @param hostname_size the size of the hostname buffer + * @param port_ptr a pointer to store the port number in + * @param path the buffer for the path + * @param path_size the size of the path buffer + * @param url the URL to split + */ +void av_url_split(char *proto, int proto_size, + char *authorization, int authorization_size, + char *hostname, int hostname_size, + int *port_ptr, + char *path, int path_size, + const char *url); + + +/** + * Print detailed information about the input or output format, such as + * duration, bitrate, streams, container, programs, metadata, side data, + * codec and time base. + * + * @param ic the context to analyze + * @param index index of the stream to dump information about + * @param url the URL to print, such as source or destination file + * @param is_output Select whether the specified context is an input(0) or output(1) + */ +void av_dump_format(AVFormatContext *ic, + int index, + const char *url, + int is_output); + +/** + * Return in 'buf' the path with '%d' replaced by a number. + * + * Also handles the '%0nd' format where 'n' is the total number + * of digits and '%%'. + * + * @param buf destination buffer + * @param buf_size destination buffer size + * @param path numbered sequence string + * @param number frame number + * @return 0 if OK, -1 on format error + */ +int av_get_frame_filename(char *buf, int buf_size, + const char *path, int number); + +/** + * Check whether filename actually is a numbered sequence generator. + * + * @param filename possible numbered sequence string + * @return 1 if a valid numbered sequence string, 0 otherwise + */ +int av_filename_number_test(const char *filename); + +/** + * Generate an SDP for an RTP session. + * + * Note, this overwrites the id values of AVStreams in the muxer contexts + * for getting unique dynamic payload types. + * + * @param ac array of AVFormatContexts describing the RTP streams. If the + * array is composed by only one context, such context can contain + * multiple AVStreams (one AVStream per RTP stream). Otherwise, + * all the contexts in the array (an AVCodecContext per RTP stream) + * must contain only one AVStream. + * @param n_files number of AVCodecContexts contained in ac + * @param buf buffer where the SDP will be stored (must be allocated by + * the caller) + * @param size the size of the buffer + * @return 0 if OK, AVERROR_xxx on error + */ +int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size); + +/** + * Return a positive value if the given filename has one of the given + * extensions, 0 otherwise. + * + * @param filename file name to check against the given extensions + * @param extensions a comma-separated list of filename extensions + */ +int av_match_ext(const char *filename, const char *extensions); + +/** + * Test if the given container can store a codec. + * + * @param ofmt container to check for compatibility + * @param codec_id codec to potentially store in container + * @param std_compliance standards compliance level, one of FF_COMPLIANCE_* + * + * @return 1 if codec with ID codec_id can be stored in ofmt, 0 if it cannot. + * A negative number if this information is not available. + */ +int avformat_query_codec(const AVOutputFormat *ofmt, enum AVCodecID codec_id, + int std_compliance); + +/** + * @defgroup riff_fourcc RIFF FourCCs + * @{ + * Get the tables mapping RIFF FourCCs to libavcodec AVCodecIDs. The tables are + * meant to be passed to av_codec_get_id()/av_codec_get_tag() as in the + * following code: + * @code + * uint32_t tag = MKTAG('H', '2', '6', '4'); + * const struct AVCodecTag *table[] = { avformat_get_riff_video_tags(), 0 }; + * enum AVCodecID id = av_codec_get_id(table, tag); + * @endcode + */ +/** + * @return the table mapping RIFF FourCCs for video to libavcodec AVCodecID. + */ +const struct AVCodecTag *avformat_get_riff_video_tags(void); +/** + * @return the table mapping RIFF FourCCs for audio to AVCodecID. + */ +const struct AVCodecTag *avformat_get_riff_audio_tags(void); +/** + * @return the table mapping MOV FourCCs for video to libavcodec AVCodecID. + */ +const struct AVCodecTag *avformat_get_mov_video_tags(void); +/** + * @return the table mapping MOV FourCCs for audio to AVCodecID. + */ +const struct AVCodecTag *avformat_get_mov_audio_tags(void); + +/** + * @} + */ + +/** + * Guess the sample aspect ratio of a frame, based on both the stream and the + * frame aspect ratio. + * + * Since the frame aspect ratio is set by the codec but the stream aspect ratio + * is set by the demuxer, these two may not be equal. This function tries to + * return the value that you should use if you would like to display the frame. + * + * Basic logic is to use the stream aspect ratio if it is set to something sane + * otherwise use the frame aspect ratio. This way a container setting, which is + * usually easy to modify can override the coded value in the frames. + * + * @param format the format context which the stream is part of + * @param stream the stream which the frame is part of + * @param frame the frame with the aspect ratio to be determined + * @return the guessed (valid) sample_aspect_ratio, 0/1 if no idea + */ +AVRational av_guess_sample_aspect_ratio(AVFormatContext *format, AVStream *stream, AVFrame *frame); + +/** + * Guess the frame rate, based on both the container and codec information. + * + * @param ctx the format context which the stream is part of + * @param stream the stream which the frame is part of + * @param frame the frame for which the frame rate should be determined, may be NULL + * @return the guessed (valid) frame rate, 0/1 if no idea + */ +AVRational av_guess_frame_rate(AVFormatContext *ctx, AVStream *stream, AVFrame *frame); + +/** + * Check if the stream st contained in s is matched by the stream specifier + * spec. + * + * See the "stream specifiers" chapter in the documentation for the syntax + * of spec. + * + * @return >0 if st is matched by spec; + * 0 if st is not matched by spec; + * AVERROR code if spec is invalid + * + * @note A stream specifier can match several streams in the format. + */ +int avformat_match_stream_specifier(AVFormatContext *s, AVStream *st, + const char *spec); + +int avformat_queue_attached_pictures(AVFormatContext *s); + +/** + * Apply a list of bitstream filters to a packet. + * + * @param codec AVCodecContext, usually from an AVStream + * @param pkt the packet to apply filters to + * @param bsfc a NULL-terminated list of filters to apply + * @return >=0 on success; + * AVERROR code on failure + */ +int av_apply_bitstream_filters(AVCodecContext *codec, AVPacket *pkt, + AVBitStreamFilterContext *bsfc); + +/** + * @} + */ + +#endif /* AVFORMAT_AVFORMAT_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavformat/avio.h b/TMessagesProj/jni/ffmpeg/include/libavformat/avio.h new file mode 100644 index 00000000..c3c0b73f --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavformat/avio.h @@ -0,0 +1,727 @@ +/* + * copyright (c) 2001 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef AVFORMAT_AVIO_H +#define AVFORMAT_AVIO_H + +/** + * @file + * @ingroup lavf_io + * Buffered I/O operations + */ + +#include + +#include "libavutil/common.h" +#include "libavutil/dict.h" +#include "libavutil/log.h" + +#include "libavformat/version.h" + +#define AVIO_SEEKABLE_NORMAL 0x0001 /**< Seeking works like for a local file */ + +/** + * Callback for checking whether to abort blocking functions. + * AVERROR_EXIT is returned in this case by the interrupted + * function. During blocking operations, callback is called with + * opaque as parameter. If the callback returns 1, the + * blocking operation will be aborted. + * + * No members can be added to this struct without a major bump, if + * new elements have been added after this struct in AVFormatContext + * or AVIOContext. + */ +typedef struct AVIOInterruptCB { + int (*callback)(void*); + void *opaque; +} AVIOInterruptCB; + +/** + * Directory entry types. + */ +enum AVIODirEntryType { + AVIO_ENTRY_UNKNOWN, + AVIO_ENTRY_BLOCK_DEVICE, + AVIO_ENTRY_CHARACTER_DEVICE, + AVIO_ENTRY_DIRECTORY, + AVIO_ENTRY_NAMED_PIPE, + AVIO_ENTRY_SYMBOLIC_LINK, + AVIO_ENTRY_SOCKET, + AVIO_ENTRY_FILE, + AVIO_ENTRY_SERVER, + AVIO_ENTRY_SHARE, + AVIO_ENTRY_WORKGROUP, +}; + +/** + * Describes single entry of the directory. + * + * Only name and type fields are guaranteed be set. + * Rest of fields are protocol or/and platform dependent and might be unknown. + */ +typedef struct AVIODirEntry { + char *name; /**< Filename */ + int type; /**< Type of the entry */ + int utf8; /**< Set to 1 when name is encoded with UTF-8, 0 otherwise. + Name can be encoded with UTF-8 even though 0 is set. */ + int64_t size; /**< File size in bytes, -1 if unknown. */ + int64_t modification_timestamp; /**< Time of last modification in microseconds since unix + epoch, -1 if unknown. */ + int64_t access_timestamp; /**< Time of last access in microseconds since unix epoch, + -1 if unknown. */ + int64_t status_change_timestamp; /**< Time of last status change in microseconds since unix + epoch, -1 if unknown. */ + int64_t user_id; /**< User ID of owner, -1 if unknown. */ + int64_t group_id; /**< Group ID of owner, -1 if unknown. */ + int64_t filemode; /**< Unix file mode, -1 if unknown. */ +} AVIODirEntry; + +typedef struct AVIODirContext { + struct URLContext *url_context; +} AVIODirContext; + +/** + * Bytestream IO Context. + * New fields can be added to the end with minor version bumps. + * Removal, reordering and changes to existing fields require a major + * version bump. + * sizeof(AVIOContext) must not be used outside libav*. + * + * @note None of the function pointers in AVIOContext should be called + * directly, they should only be set by the client application + * when implementing custom I/O. Normally these are set to the + * function pointers specified in avio_alloc_context() + */ +typedef struct AVIOContext { + /** + * A class for private options. + * + * If this AVIOContext is created by avio_open2(), av_class is set and + * passes the options down to protocols. + * + * If this AVIOContext is manually allocated, then av_class may be set by + * the caller. + * + * warning -- this field can be NULL, be sure to not pass this AVIOContext + * to any av_opt_* functions in that case. + */ + const AVClass *av_class; + + /* + * The following shows the relationship between buffer, buf_ptr, buf_end, buf_size, + * and pos, when reading and when writing (since AVIOContext is used for both): + * + ********************************************************************************** + * READING + ********************************************************************************** + * + * | buffer_size | + * |---------------------------------------| + * | | + * + * buffer buf_ptr buf_end + * +---------------+-----------------------+ + * |/ / / / / / / /|/ / / / / / /| | + * read buffer: |/ / consumed / | to be read /| | + * |/ / / / / / / /|/ / / / / / /| | + * +---------------+-----------------------+ + * + * pos + * +-------------------------------------------+-----------------+ + * input file: | | | + * +-------------------------------------------+-----------------+ + * + * + ********************************************************************************** + * WRITING + ********************************************************************************** + * + * | buffer_size | + * |-------------------------------| + * | | + * + * buffer buf_ptr buf_end + * +-------------------+-----------+ + * |/ / / / / / / / / /| | + * write buffer: | / to be flushed / | | + * |/ / / / / / / / / /| | + * +-------------------+-----------+ + * + * pos + * +--------------------------+-----------------------------------+ + * output file: | | | + * +--------------------------+-----------------------------------+ + * + */ + unsigned char *buffer; /**< Start of the buffer. */ + int buffer_size; /**< Maximum buffer size */ + unsigned char *buf_ptr; /**< Current position in the buffer */ + unsigned char *buf_end; /**< End of the data, may be less than + buffer+buffer_size if the read function returned + less data than requested, e.g. for streams where + no more data has been received yet. */ + void *opaque; /**< A private pointer, passed to the read/write/seek/... + functions. */ + int (*read_packet)(void *opaque, uint8_t *buf, int buf_size); + int (*write_packet)(void *opaque, uint8_t *buf, int buf_size); + int64_t (*seek)(void *opaque, int64_t offset, int whence); + int64_t pos; /**< position in the file of the current buffer */ + int must_flush; /**< true if the next seek should flush */ + int eof_reached; /**< true if eof reached */ + int write_flag; /**< true if open for writing */ + int max_packet_size; + unsigned long checksum; + unsigned char *checksum_ptr; + unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size); + int error; /**< contains the error code or 0 if no error happened */ + /** + * Pause or resume playback for network streaming protocols - e.g. MMS. + */ + int (*read_pause)(void *opaque, int pause); + /** + * Seek to a given timestamp in stream with the specified stream_index. + * Needed for some network streaming protocols which don't support seeking + * to byte position. + */ + int64_t (*read_seek)(void *opaque, int stream_index, + int64_t timestamp, int flags); + /** + * A combination of AVIO_SEEKABLE_ flags or 0 when the stream is not seekable. + */ + int seekable; + + /** + * max filesize, used to limit allocations + * This field is internal to libavformat and access from outside is not allowed. + */ + int64_t maxsize; + + /** + * avio_read and avio_write should if possible be satisfied directly + * instead of going through a buffer, and avio_seek will always + * call the underlying seek function directly. + */ + int direct; + + /** + * Bytes read statistic + * This field is internal to libavformat and access from outside is not allowed. + */ + int64_t bytes_read; + + /** + * seek statistic + * This field is internal to libavformat and access from outside is not allowed. + */ + int seek_count; + + /** + * writeout statistic + * This field is internal to libavformat and access from outside is not allowed. + */ + int writeout_count; + + /** + * Original buffer size + * used internally after probing and ensure seekback to reset the buffer size + * This field is internal to libavformat and access from outside is not allowed. + */ + int orig_buffer_size; + + /** + * Threshold to favor readahead over seek. + * This is current internal only, do not use from outside. + */ + int short_seek_threshold; +} AVIOContext; + +/* unbuffered I/O */ + +/** + * Return the name of the protocol that will handle the passed URL. + * + * NULL is returned if no protocol could be found for the given URL. + * + * @return Name of the protocol or NULL. + */ +const char *avio_find_protocol_name(const char *url); + +/** + * Return AVIO_FLAG_* access flags corresponding to the access permissions + * of the resource in url, or a negative value corresponding to an + * AVERROR code in case of failure. The returned access flags are + * masked by the value in flags. + * + * @note This function is intrinsically unsafe, in the sense that the + * checked resource may change its existence or permission status from + * one call to another. Thus you should not trust the returned value, + * unless you are sure that no other processes are accessing the + * checked resource. + */ +int avio_check(const char *url, int flags); + +/** + * Move or rename a resource. + * + * @note url_src and url_dst should share the same protocol and authority. + * + * @param url_src url to resource to be moved + * @param url_dst new url to resource if the operation succeeded + * @return >=0 on success or negative on error. + */ +int avpriv_io_move(const char *url_src, const char *url_dst); + +/** + * Delete a resource. + * + * @param url resource to be deleted. + * @return >=0 on success or negative on error. + */ +int avpriv_io_delete(const char *url); + +/** + * Open directory for reading. + * + * @param s directory read context. Pointer to a NULL pointer must be passed. + * @param url directory to be listed. + * @param options A dictionary filled with protocol-private options. On return + * this parameter will be destroyed and replaced with a dictionary + * containing options that were not found. May be NULL. + * @return >=0 on success or negative on error. + */ +int avio_open_dir(AVIODirContext **s, const char *url, AVDictionary **options); + +/** + * Get next directory entry. + * + * Returned entry must be freed with avio_free_directory_entry(). In particular + * it may outlive AVIODirContext. + * + * @param s directory read context. + * @param[out] next next entry or NULL when no more entries. + * @return >=0 on success or negative on error. End of list is not considered an + * error. + */ +int avio_read_dir(AVIODirContext *s, AVIODirEntry **next); + +/** + * Close directory. + * + * @note Entries created using avio_read_dir() are not deleted and must be + * freeded with avio_free_directory_entry(). + * + * @param s directory read context. + * @return >=0 on success or negative on error. + */ +int avio_close_dir(AVIODirContext **s); + +/** + * Free entry allocated by avio_read_dir(). + * + * @param entry entry to be freed. + */ +void avio_free_directory_entry(AVIODirEntry **entry); + +/** + * Allocate and initialize an AVIOContext for buffered I/O. It must be later + * freed with av_free(). + * + * @param buffer Memory block for input/output operations via AVIOContext. + * The buffer must be allocated with av_malloc() and friends. + * It may be freed and replaced with a new buffer by libavformat. + * AVIOContext.buffer holds the buffer currently in use, + * which must be later freed with av_free(). + * @param buffer_size The buffer size is very important for performance. + * For protocols with fixed blocksize it should be set to this blocksize. + * For others a typical size is a cache page, e.g. 4kb. + * @param write_flag Set to 1 if the buffer should be writable, 0 otherwise. + * @param opaque An opaque pointer to user-specific data. + * @param read_packet A function for refilling the buffer, may be NULL. + * @param write_packet A function for writing the buffer contents, may be NULL. + * The function may not change the input buffers content. + * @param seek A function for seeking to specified byte position, may be NULL. + * + * @return Allocated AVIOContext or NULL on failure. + */ +AVIOContext *avio_alloc_context( + unsigned char *buffer, + int buffer_size, + int write_flag, + void *opaque, + int (*read_packet)(void *opaque, uint8_t *buf, int buf_size), + int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), + int64_t (*seek)(void *opaque, int64_t offset, int whence)); + +void avio_w8(AVIOContext *s, int b); +void avio_write(AVIOContext *s, const unsigned char *buf, int size); +void avio_wl64(AVIOContext *s, uint64_t val); +void avio_wb64(AVIOContext *s, uint64_t val); +void avio_wl32(AVIOContext *s, unsigned int val); +void avio_wb32(AVIOContext *s, unsigned int val); +void avio_wl24(AVIOContext *s, unsigned int val); +void avio_wb24(AVIOContext *s, unsigned int val); +void avio_wl16(AVIOContext *s, unsigned int val); +void avio_wb16(AVIOContext *s, unsigned int val); + +/** + * Write a NULL-terminated string. + * @return number of bytes written. + */ +int avio_put_str(AVIOContext *s, const char *str); + +/** + * Convert an UTF-8 string to UTF-16LE and write it. + * @param s the AVIOContext + * @param str NULL-terminated UTF-8 string + * + * @return number of bytes written. + */ +int avio_put_str16le(AVIOContext *s, const char *str); + +/** + * Convert an UTF-8 string to UTF-16BE and write it. + * @param s the AVIOContext + * @param str NULL-terminated UTF-8 string + * + * @return number of bytes written. + */ +int avio_put_str16be(AVIOContext *s, const char *str); + +/** + * Passing this as the "whence" parameter to a seek function causes it to + * return the filesize without seeking anywhere. Supporting this is optional. + * If it is not supported then the seek function will return <0. + */ +#define AVSEEK_SIZE 0x10000 + +/** + * Oring this flag as into the "whence" parameter to a seek function causes it to + * seek by any means (like reopening and linear reading) or other normally unreasonable + * means that can be extremely slow. + * This may be ignored by the seek code. + */ +#define AVSEEK_FORCE 0x20000 + +/** + * fseek() equivalent for AVIOContext. + * @return new position or AVERROR. + */ +int64_t avio_seek(AVIOContext *s, int64_t offset, int whence); + +/** + * Skip given number of bytes forward + * @return new position or AVERROR. + */ +int64_t avio_skip(AVIOContext *s, int64_t offset); + +/** + * ftell() equivalent for AVIOContext. + * @return position or AVERROR. + */ +static av_always_inline int64_t avio_tell(AVIOContext *s) +{ + return avio_seek(s, 0, SEEK_CUR); +} + +/** + * Get the filesize. + * @return filesize or AVERROR + */ +int64_t avio_size(AVIOContext *s); + +/** + * feof() equivalent for AVIOContext. + * @return non zero if and only if end of file + */ +int avio_feof(AVIOContext *s); +#if FF_API_URL_FEOF +/** + * @deprecated use avio_feof() + */ +attribute_deprecated +int url_feof(AVIOContext *s); +#endif + +/** @warning Writes up to 4 KiB per call */ +int avio_printf(AVIOContext *s, const char *fmt, ...) av_printf_format(2, 3); + +/** + * Force flushing of buffered data. + * + * For write streams, force the buffered data to be immediately written to the output, + * without to wait to fill the internal buffer. + * + * For read streams, discard all currently buffered data, and advance the + * reported file position to that of the underlying stream. This does not + * read new data, and does not perform any seeks. + */ +void avio_flush(AVIOContext *s); + +/** + * Read size bytes from AVIOContext into buf. + * @return number of bytes read or AVERROR + */ +int avio_read(AVIOContext *s, unsigned char *buf, int size); + +/** + * @name Functions for reading from AVIOContext + * @{ + * + * @note return 0 if EOF, so you cannot use it if EOF handling is + * necessary + */ +int avio_r8 (AVIOContext *s); +unsigned int avio_rl16(AVIOContext *s); +unsigned int avio_rl24(AVIOContext *s); +unsigned int avio_rl32(AVIOContext *s); +uint64_t avio_rl64(AVIOContext *s); +unsigned int avio_rb16(AVIOContext *s); +unsigned int avio_rb24(AVIOContext *s); +unsigned int avio_rb32(AVIOContext *s); +uint64_t avio_rb64(AVIOContext *s); +/** + * @} + */ + +/** + * Read a string from pb into buf. The reading will terminate when either + * a NULL character was encountered, maxlen bytes have been read, or nothing + * more can be read from pb. The result is guaranteed to be NULL-terminated, it + * will be truncated if buf is too small. + * Note that the string is not interpreted or validated in any way, it + * might get truncated in the middle of a sequence for multi-byte encodings. + * + * @return number of bytes read (is always <= maxlen). + * If reading ends on EOF or error, the return value will be one more than + * bytes actually read. + */ +int avio_get_str(AVIOContext *pb, int maxlen, char *buf, int buflen); + +/** + * Read a UTF-16 string from pb and convert it to UTF-8. + * The reading will terminate when either a null or invalid character was + * encountered or maxlen bytes have been read. + * @return number of bytes read (is always <= maxlen) + */ +int avio_get_str16le(AVIOContext *pb, int maxlen, char *buf, int buflen); +int avio_get_str16be(AVIOContext *pb, int maxlen, char *buf, int buflen); + + +/** + * @name URL open modes + * The flags argument to avio_open must be one of the following + * constants, optionally ORed with other flags. + * @{ + */ +#define AVIO_FLAG_READ 1 /**< read-only */ +#define AVIO_FLAG_WRITE 2 /**< write-only */ +#define AVIO_FLAG_READ_WRITE (AVIO_FLAG_READ|AVIO_FLAG_WRITE) /**< read-write pseudo flag */ +/** + * @} + */ + +/** + * Use non-blocking mode. + * If this flag is set, operations on the context will return + * AVERROR(EAGAIN) if they can not be performed immediately. + * If this flag is not set, operations on the context will never return + * AVERROR(EAGAIN). + * Note that this flag does not affect the opening/connecting of the + * context. Connecting a protocol will always block if necessary (e.g. on + * network protocols) but never hang (e.g. on busy devices). + * Warning: non-blocking protocols is work-in-progress; this flag may be + * silently ignored. + */ +#define AVIO_FLAG_NONBLOCK 8 + +/** + * Use direct mode. + * avio_read and avio_write should if possible be satisfied directly + * instead of going through a buffer, and avio_seek will always + * call the underlying seek function directly. + */ +#define AVIO_FLAG_DIRECT 0x8000 + +/** + * Create and initialize a AVIOContext for accessing the + * resource indicated by url. + * @note When the resource indicated by url has been opened in + * read+write mode, the AVIOContext can be used only for writing. + * + * @param s Used to return the pointer to the created AVIOContext. + * In case of failure the pointed to value is set to NULL. + * @param url resource to access + * @param flags flags which control how the resource indicated by url + * is to be opened + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code in case of failure + */ +int avio_open(AVIOContext **s, const char *url, int flags); + +/** + * Create and initialize a AVIOContext for accessing the + * resource indicated by url. + * @note When the resource indicated by url has been opened in + * read+write mode, the AVIOContext can be used only for writing. + * + * @param s Used to return the pointer to the created AVIOContext. + * In case of failure the pointed to value is set to NULL. + * @param url resource to access + * @param flags flags which control how the resource indicated by url + * is to be opened + * @param int_cb an interrupt callback to be used at the protocols level + * @param options A dictionary filled with protocol-private options. On return + * this parameter will be destroyed and replaced with a dict containing options + * that were not found. May be NULL. + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code in case of failure + */ +int avio_open2(AVIOContext **s, const char *url, int flags, + const AVIOInterruptCB *int_cb, AVDictionary **options); + +/** + * Close the resource accessed by the AVIOContext s and free it. + * This function can only be used if s was opened by avio_open(). + * + * The internal buffer is automatically flushed before closing the + * resource. + * + * @return 0 on success, an AVERROR < 0 on error. + * @see avio_closep + */ +int avio_close(AVIOContext *s); + +/** + * Close the resource accessed by the AVIOContext *s, free it + * and set the pointer pointing to it to NULL. + * This function can only be used if s was opened by avio_open(). + * + * The internal buffer is automatically flushed before closing the + * resource. + * + * @return 0 on success, an AVERROR < 0 on error. + * @see avio_close + */ +int avio_closep(AVIOContext **s); + + +/** + * Open a write only memory stream. + * + * @param s new IO context + * @return zero if no error. + */ +int avio_open_dyn_buf(AVIOContext **s); + +/** + * Return the written size and a pointer to the buffer. The buffer + * must be freed with av_free(). + * Padding of AV_INPUT_BUFFER_PADDING_SIZE is added to the buffer. + * + * @param s IO context + * @param pbuffer pointer to a byte buffer + * @return the length of the byte buffer + */ +int avio_close_dyn_buf(AVIOContext *s, uint8_t **pbuffer); + +/** + * Iterate through names of available protocols. + * + * @param opaque A private pointer representing current protocol. + * It must be a pointer to NULL on first iteration and will + * be updated by successive calls to avio_enum_protocols. + * @param output If set to 1, iterate over output protocols, + * otherwise over input protocols. + * + * @return A static string containing the name of current protocol or NULL + */ +const char *avio_enum_protocols(void **opaque, int output); + +/** + * Pause and resume playing - only meaningful if using a network streaming + * protocol (e.g. MMS). + * + * @param h IO context from which to call the read_pause function pointer + * @param pause 1 for pause, 0 for resume + */ +int avio_pause(AVIOContext *h, int pause); + +/** + * Seek to a given timestamp relative to some component stream. + * Only meaningful if using a network streaming protocol (e.g. MMS.). + * + * @param h IO context from which to call the seek function pointers + * @param stream_index The stream index that the timestamp is relative to. + * If stream_index is (-1) the timestamp should be in AV_TIME_BASE + * units from the beginning of the presentation. + * If a stream_index >= 0 is used and the protocol does not support + * seeking based on component streams, the call will fail. + * @param timestamp timestamp in AVStream.time_base units + * or if there is no stream specified then in AV_TIME_BASE units. + * @param flags Optional combination of AVSEEK_FLAG_BACKWARD, AVSEEK_FLAG_BYTE + * and AVSEEK_FLAG_ANY. The protocol may silently ignore + * AVSEEK_FLAG_BACKWARD and AVSEEK_FLAG_ANY, but AVSEEK_FLAG_BYTE will + * fail if used and not supported. + * @return >= 0 on success + * @see AVInputFormat::read_seek + */ +int64_t avio_seek_time(AVIOContext *h, int stream_index, + int64_t timestamp, int flags); + +/* Avoid a warning. The header can not be included because it breaks c++. */ +struct AVBPrint; + +/** + * Read contents of h into print buffer, up to max_size bytes, or up to EOF. + * + * @return 0 for success (max_size bytes read or EOF reached), negative error + * code otherwise + */ +int avio_read_to_bprint(AVIOContext *h, struct AVBPrint *pb, size_t max_size); + +/** + * Accept and allocate a client context on a server context. + * @param s the server context + * @param c the client context, must be unallocated + * @return >= 0 on success or a negative value corresponding + * to an AVERROR on failure + */ +int avio_accept(AVIOContext *s, AVIOContext **c); + +/** + * Perform one step of the protocol handshake to accept a new client. + * This function must be called on a client returned by avio_accept() before + * using it as a read/write context. + * It is separate from avio_accept() because it may block. + * A step of the handshake is defined by places where the application may + * decide to change the proceedings. + * For example, on a protocol with a request header and a reply header, each + * one can constitute a step because the application may use the parameters + * from the request to change parameters in the reply; or each individual + * chunk of the request can constitute a step. + * If the handshake is already finished, avio_handshake() does nothing and + * returns 0 immediately. + * + * @param c the client context to perform the handshake on + * @return 0 on a complete and successful handshake + * > 0 if the handshake progressed, but is not complete + * < 0 for an AVERROR code + */ +int avio_handshake(AVIOContext *c); +#endif /* AVFORMAT_AVIO_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavformat/version.h b/TMessagesProj/jni/ffmpeg/include/libavformat/version.h new file mode 100644 index 00000000..a57eb12f --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavformat/version.h @@ -0,0 +1,78 @@ +/* + * Version macros. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_VERSION_H +#define AVFORMAT_VERSION_H + +/** + * @file + * @ingroup libavf + * Libavformat version macros + */ + +#include "libavutil/version.h" + +#define LIBAVFORMAT_VERSION_MAJOR 57 +#define LIBAVFORMAT_VERSION_MINOR 21 +#define LIBAVFORMAT_VERSION_MICRO 100 + +#define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ + LIBAVFORMAT_VERSION_MINOR, \ + LIBAVFORMAT_VERSION_MICRO) +#define LIBAVFORMAT_VERSION AV_VERSION(LIBAVFORMAT_VERSION_MAJOR, \ + LIBAVFORMAT_VERSION_MINOR, \ + LIBAVFORMAT_VERSION_MICRO) +#define LIBAVFORMAT_BUILD LIBAVFORMAT_VERSION_INT + +#define LIBAVFORMAT_IDENT "Lavf" AV_STRINGIFY(LIBAVFORMAT_VERSION) + +/** + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + * + * @note, when bumping the major version it is recommended to manually + * disable each FF_API_* in its own commit instead of disabling them all + * at once through the bump. This improves the git bisect-ability of the change. + * + */ +#ifndef FF_API_LAVF_BITEXACT +#define FF_API_LAVF_BITEXACT (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_LAVF_FRAC +#define FF_API_LAVF_FRAC (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_LAVF_CODEC_TB +#define FF_API_LAVF_CODEC_TB (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_URL_FEOF +#define FF_API_URL_FEOF (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_LAVF_FMT_RAWPICTURE +#define FF_API_LAVF_FMT_RAWPICTURE (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif +#ifndef FF_API_COMPUTE_PKT_FIELDS2 +#define FF_API_COMPUTE_PKT_FIELDS2 (LIBAVFORMAT_VERSION_MAJOR < 58) +#endif + +#ifndef FF_API_R_FRAME_RATE +#define FF_API_R_FRAME_RATE 1 +#endif +#endif /* AVFORMAT_VERSION_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/adler32.h b/TMessagesProj/jni/ffmpeg/include/libavutil/adler32.h new file mode 100644 index 00000000..0dc69ec0 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/adler32.h @@ -0,0 +1,55 @@ +/* + * copyright (c) 2006 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ADLER32_H +#define AVUTIL_ADLER32_H + +#include +#include "attributes.h" + +/** + * @file + * Public header for libavutil Adler32 hasher + * + * @defgroup lavu_adler32 Adler32 + * @ingroup lavu_crypto + * @{ + */ + +/** + * Calculate the Adler32 checksum of a buffer. + * + * Passing the return value to a subsequent av_adler32_update() call + * allows the checksum of multiple buffers to be calculated as though + * they were concatenated. + * + * @param adler initial checksum value + * @param buf pointer to input buffer + * @param len size of input buffer + * @return updated checksum + */ +unsigned long av_adler32_update(unsigned long adler, const uint8_t *buf, + unsigned int len) av_pure; + +/** + * @} + */ + +#endif /* AVUTIL_ADLER32_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/aes.h b/TMessagesProj/jni/ffmpeg/include/libavutil/aes.h new file mode 100644 index 00000000..09efbda1 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/aes.h @@ -0,0 +1,65 @@ +/* + * copyright (c) 2007 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AES_H +#define AVUTIL_AES_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_aes AES + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_aes_size; + +struct AVAES; + +/** + * Allocate an AVAES context. + */ +struct AVAES *av_aes_alloc(void); + +/** + * Initialize an AVAES context. + * @param key_bits 128, 192 or 256 + * @param decrypt 0 for encryption, 1 for decryption + */ +int av_aes_init(struct AVAES *a, const uint8_t *key, int key_bits, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * @param count number of 16 byte blocks + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_aes_crypt(struct AVAES *a, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_AES_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/aes_ctr.h b/TMessagesProj/jni/ffmpeg/include/libavutil/aes_ctr.h new file mode 100644 index 00000000..f596fa6a --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/aes_ctr.h @@ -0,0 +1,83 @@ +/* + * AES-CTR cipher + * Copyright (c) 2015 Eran Kornblau + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AES_CTR_H +#define AVUTIL_AES_CTR_H + +#include + +#include "attributes.h" +#include "version.h" + +#define AES_CTR_KEY_SIZE (16) +#define AES_CTR_IV_SIZE (8) + +struct AVAESCTR; + +/** + * Allocate an AVAESCTR context. + */ +struct AVAESCTR *av_aes_ctr_alloc(void); + +/** + * Initialize an AVAESCTR context. + * @param key encryption key, must have a length of AES_CTR_KEY_SIZE + */ +int av_aes_ctr_init(struct AVAESCTR *a, const uint8_t *key); + +/** + * Release an AVAESCTR context. + */ +void av_aes_ctr_free(struct AVAESCTR *a); + +/** + * Process a buffer using a previously initialized context. + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param size the size of src and dst + */ +void av_aes_ctr_crypt(struct AVAESCTR *a, uint8_t *dst, const uint8_t *src, int size); + +/** + * Get the current iv + */ +const uint8_t* av_aes_ctr_get_iv(struct AVAESCTR *a); + +/** + * Generate a random iv + */ +void av_aes_ctr_set_random_iv(struct AVAESCTR *a); + +/** + * Forcefully change the iv + */ +void av_aes_ctr_set_iv(struct AVAESCTR *a, const uint8_t* iv); + +/** + * Increment the top 64 bit of the iv (performed after each frame) + */ +void av_aes_ctr_increment_iv(struct AVAESCTR *a); + +/** + * @} + */ + +#endif /* AVUTIL_AES_CTR_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/attributes.h b/TMessagesProj/jni/ffmpeg/include/libavutil/attributes.h new file mode 100644 index 00000000..5c6b9dee --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/attributes.h @@ -0,0 +1,168 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Macro definitions for various function/variable attributes + */ + +#ifndef AVUTIL_ATTRIBUTES_H +#define AVUTIL_ATTRIBUTES_H + +#ifdef __GNUC__ +# define AV_GCC_VERSION_AT_LEAST(x,y) (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) +# define AV_GCC_VERSION_AT_MOST(x,y) (__GNUC__ < (x) || __GNUC__ == (x) && __GNUC_MINOR__ <= (y)) +#else +# define AV_GCC_VERSION_AT_LEAST(x,y) 0 +# define AV_GCC_VERSION_AT_MOST(x,y) 0 +#endif + +#ifndef av_always_inline +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define av_always_inline __attribute__((always_inline)) inline +#elif defined(_MSC_VER) +# define av_always_inline __forceinline +#else +# define av_always_inline inline +#endif +#endif + +#ifndef av_extern_inline +#if defined(__ICL) && __ICL >= 1210 || defined(__GNUC_STDC_INLINE__) +# define av_extern_inline extern inline +#else +# define av_extern_inline inline +#endif +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,4) +# define av_warn_unused_result __attribute__((warn_unused_result)) +#else +# define av_warn_unused_result +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define av_noinline __attribute__((noinline)) +#elif defined(_MSC_VER) +# define av_noinline __declspec(noinline) +#else +# define av_noinline +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define av_pure __attribute__((pure)) +#else +# define av_pure +#endif + +#if AV_GCC_VERSION_AT_LEAST(2,6) +# define av_const __attribute__((const)) +#else +# define av_const +#endif + +#if AV_GCC_VERSION_AT_LEAST(4,3) +# define av_cold __attribute__((cold)) +#else +# define av_cold +#endif + +#if AV_GCC_VERSION_AT_LEAST(4,1) && !defined(__llvm__) +# define av_flatten __attribute__((flatten)) +#else +# define av_flatten +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define attribute_deprecated __attribute__((deprecated)) +#elif defined(_MSC_VER) +# define attribute_deprecated __declspec(deprecated) +#else +# define attribute_deprecated +#endif + +/** + * Disable warnings about deprecated features + * This is useful for sections of code kept for backward compatibility and + * scheduled for removal. + */ +#ifndef AV_NOWARN_DEPRECATED +#if AV_GCC_VERSION_AT_LEAST(4,6) +# define AV_NOWARN_DEPRECATED(code) \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \ + code \ + _Pragma("GCC diagnostic pop") +#elif defined(_MSC_VER) +# define AV_NOWARN_DEPRECATED(code) \ + __pragma(warning(push)) \ + __pragma(warning(disable : 4996)) \ + code; \ + __pragma(warning(pop)) +#else +# define AV_NOWARN_DEPRECATED(code) code +#endif +#endif + + +#if defined(__GNUC__) +# define av_unused __attribute__((unused)) +#else +# define av_unused +#endif + +/** + * Mark a variable as used and prevent the compiler from optimizing it + * away. This is useful for variables accessed only from inline + * assembler without the compiler being aware. + */ +#if AV_GCC_VERSION_AT_LEAST(3,1) +# define av_used __attribute__((used)) +#else +# define av_used +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,3) +# define av_alias __attribute__((may_alias)) +#else +# define av_alias +#endif + +#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) +# define av_uninit(x) x=x +#else +# define av_uninit(x) x +#endif + +#ifdef __GNUC__ +# define av_builtin_constant_p __builtin_constant_p +# define av_printf_format(fmtpos, attrpos) __attribute__((__format__(__printf__, fmtpos, attrpos))) +#else +# define av_builtin_constant_p(x) 0 +# define av_printf_format(fmtpos, attrpos) +#endif + +#if AV_GCC_VERSION_AT_LEAST(2,5) +# define av_noreturn __attribute__((noreturn)) +#else +# define av_noreturn +#endif + +#endif /* AVUTIL_ATTRIBUTES_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/audio_fifo.h b/TMessagesProj/jni/ffmpeg/include/libavutil/audio_fifo.h new file mode 100644 index 00000000..24f91dab --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/audio_fifo.h @@ -0,0 +1,170 @@ +/* + * Audio FIFO + * Copyright (c) 2012 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Audio FIFO Buffer + */ + +#ifndef AVUTIL_AUDIO_FIFO_H +#define AVUTIL_AUDIO_FIFO_H + +#include "avutil.h" +#include "fifo.h" +#include "samplefmt.h" + +/** + * @addtogroup lavu_audio + * @{ + * + * @defgroup lavu_audiofifo Audio FIFO Buffer + * @{ + */ + +/** + * Context for an Audio FIFO Buffer. + * + * - Operates at the sample level rather than the byte level. + * - Supports multiple channels with either planar or packed sample format. + * - Automatic reallocation when writing to a full buffer. + */ +typedef struct AVAudioFifo AVAudioFifo; + +/** + * Free an AVAudioFifo. + * + * @param af AVAudioFifo to free + */ +void av_audio_fifo_free(AVAudioFifo *af); + +/** + * Allocate an AVAudioFifo. + * + * @param sample_fmt sample format + * @param channels number of channels + * @param nb_samples initial allocation size, in samples + * @return newly allocated AVAudioFifo, or NULL on error + */ +AVAudioFifo *av_audio_fifo_alloc(enum AVSampleFormat sample_fmt, int channels, + int nb_samples); + +/** + * Reallocate an AVAudioFifo. + * + * @param af AVAudioFifo to reallocate + * @param nb_samples new allocation size, in samples + * @return 0 if OK, or negative AVERROR code on failure + */ +av_warn_unused_result +int av_audio_fifo_realloc(AVAudioFifo *af, int nb_samples); + +/** + * Write data to an AVAudioFifo. + * + * The AVAudioFifo will be reallocated automatically if the available space + * is less than nb_samples. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to write to + * @param data audio data plane pointers + * @param nb_samples number of samples to write + * @return number of samples actually written, or negative AVERROR + * code on failure. If successful, the number of samples + * actually written will always be nb_samples. + */ +int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Peek data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to peek + * @return number of samples actually peek, or negative AVERROR code + * on failure. The number of samples actually peek will not + * be greater than nb_samples, and will only be less than + * nb_samples if av_audio_fifo_size is less than nb_samples. + */ +int av_audio_fifo_peek(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Read data from an AVAudioFifo. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param af AVAudioFifo to read from + * @param data audio data plane pointers + * @param nb_samples number of samples to read + * @return number of samples actually read, or negative AVERROR code + * on failure. The number of samples actually read will not + * be greater than nb_samples, and will only be less than + * nb_samples if av_audio_fifo_size is less than nb_samples. + */ +int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples); + +/** + * Drain data from an AVAudioFifo. + * + * Removes the data without reading it. + * + * @param af AVAudioFifo to drain + * @param nb_samples number of samples to drain + * @return 0 if OK, or negative AVERROR code on failure + */ +int av_audio_fifo_drain(AVAudioFifo *af, int nb_samples); + +/** + * Reset the AVAudioFifo buffer. + * + * This empties all data in the buffer. + * + * @param af AVAudioFifo to reset + */ +void av_audio_fifo_reset(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for reading. + * + * @param af the AVAudioFifo to query + * @return number of samples available for reading + */ +int av_audio_fifo_size(AVAudioFifo *af); + +/** + * Get the current number of samples in the AVAudioFifo available for writing. + * + * @param af the AVAudioFifo to query + * @return number of samples available for writing + */ +int av_audio_fifo_space(AVAudioFifo *af); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_AUDIO_FIFO_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/avassert.h b/TMessagesProj/jni/ffmpeg/include/libavutil/avassert.h new file mode 100644 index 00000000..41f5e0ee --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/avassert.h @@ -0,0 +1,66 @@ +/* + * copyright (c) 2010 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple assert() macros that are a bit more flexible than ISO C assert(). + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_AVASSERT_H +#define AVUTIL_AVASSERT_H + +#include +#include "avutil.h" +#include "log.h" + +/** + * assert() equivalent, that is always enabled. + */ +#define av_assert0(cond) do { \ + if (!(cond)) { \ + av_log(NULL, AV_LOG_PANIC, "Assertion %s failed at %s:%d\n", \ + AV_STRINGIFY(cond), __FILE__, __LINE__); \ + abort(); \ + } \ +} while (0) + + +/** + * assert() equivalent, that does not lie in speed critical code. + * These asserts() thus can be enabled without fearing speedloss. + */ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 0 +#define av_assert1(cond) av_assert0(cond) +#else +#define av_assert1(cond) ((void)0) +#endif + + +/** + * assert() equivalent, that does lie in speed critical code. + */ +#if defined(ASSERT_LEVEL) && ASSERT_LEVEL > 1 +#define av_assert2(cond) av_assert0(cond) +#else +#define av_assert2(cond) ((void)0) +#endif + +#endif /* AVUTIL_AVASSERT_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/avconfig.h b/TMessagesProj/jni/ffmpeg/include/libavutil/avconfig.h new file mode 100644 index 00000000..123b3b28 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/avconfig.h @@ -0,0 +1,7 @@ +/* Generated by ffconf */ +#ifndef AVUTIL_AVCONFIG_H +#define AVUTIL_AVCONFIG_H +#define AV_HAVE_BIGENDIAN 0 +#define AV_HAVE_FAST_UNALIGNED 0 +#define AV_HAVE_INCOMPATIBLE_LIBAV_ABI 0 +#endif /* AVUTIL_AVCONFIG_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/avstring.h b/TMessagesProj/jni/ffmpeg/include/libavutil/avstring.h new file mode 100644 index 00000000..a46d0125 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/avstring.h @@ -0,0 +1,397 @@ +/* + * Copyright (c) 2007 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AVSTRING_H +#define AVUTIL_AVSTRING_H + +#include +#include +#include "attributes.h" + +/** + * @addtogroup lavu_string + * @{ + */ + +/** + * Return non-zero if pfx is a prefix of str. If it is, *ptr is set to + * the address of the first character in str after the prefix. + * + * @param str input string + * @param pfx prefix to test + * @param ptr updated if the prefix is matched inside str + * @return non-zero if the prefix matches, zero otherwise + */ +int av_strstart(const char *str, const char *pfx, const char **ptr); + +/** + * Return non-zero if pfx is a prefix of str independent of case. If + * it is, *ptr is set to the address of the first character in str + * after the prefix. + * + * @param str input string + * @param pfx prefix to test + * @param ptr updated if the prefix is matched inside str + * @return non-zero if the prefix matches, zero otherwise + */ +int av_stristart(const char *str, const char *pfx, const char **ptr); + +/** + * Locate the first case-independent occurrence in the string haystack + * of the string needle. A zero-length string needle is considered to + * match at the start of haystack. + * + * This function is a case-insensitive version of the standard strstr(). + * + * @param haystack string to search in + * @param needle string to search for + * @return pointer to the located match within haystack + * or a null pointer if no match + */ +char *av_stristr(const char *haystack, const char *needle); + +/** + * Locate the first occurrence of the string needle in the string haystack + * where not more than hay_length characters are searched. A zero-length + * string needle is considered to match at the start of haystack. + * + * This function is a length-limited version of the standard strstr(). + * + * @param haystack string to search in + * @param needle string to search for + * @param hay_length length of string to search in + * @return pointer to the located match within haystack + * or a null pointer if no match + */ +char *av_strnstr(const char *haystack, const char *needle, size_t hay_length); + +/** + * Copy the string src to dst, but no more than size - 1 bytes, and + * null-terminate dst. + * + * This function is the same as BSD strlcpy(). + * + * @param dst destination buffer + * @param src source string + * @param size size of destination buffer + * @return the length of src + * + * @warning since the return value is the length of src, src absolutely + * _must_ be a properly 0-terminated string, otherwise this will read beyond + * the end of the buffer and possibly crash. + */ +size_t av_strlcpy(char *dst, const char *src, size_t size); + +/** + * Append the string src to the string dst, but to a total length of + * no more than size - 1 bytes, and null-terminate dst. + * + * This function is similar to BSD strlcat(), but differs when + * size <= strlen(dst). + * + * @param dst destination buffer + * @param src source string + * @param size size of destination buffer + * @return the total length of src and dst + * + * @warning since the return value use the length of src and dst, these + * absolutely _must_ be a properly 0-terminated strings, otherwise this + * will read beyond the end of the buffer and possibly crash. + */ +size_t av_strlcat(char *dst, const char *src, size_t size); + +/** + * Append output to a string, according to a format. Never write out of + * the destination buffer, and always put a terminating 0 within + * the buffer. + * @param dst destination buffer (string to which the output is + * appended) + * @param size total size of the destination buffer + * @param fmt printf-compatible format string, specifying how the + * following parameters are used + * @return the length of the string that would have been generated + * if enough space had been available + */ +size_t av_strlcatf(char *dst, size_t size, const char *fmt, ...) av_printf_format(3, 4); + +/** + * Get the count of continuous non zero chars starting from the beginning. + * + * @param len maximum number of characters to check in the string, that + * is the maximum value which is returned by the function + */ +static inline size_t av_strnlen(const char *s, size_t len) +{ + size_t i; + for (i = 0; i < len && s[i]; i++) + ; + return i; +} + +/** + * Print arguments following specified format into a large enough auto + * allocated buffer. It is similar to GNU asprintf(). + * @param fmt printf-compatible format string, specifying how the + * following parameters are used. + * @return the allocated string + * @note You have to free the string yourself with av_free(). + */ +char *av_asprintf(const char *fmt, ...) av_printf_format(1, 2); + +/** + * Convert a number to a av_malloced string. + */ +char *av_d2str(double d); + +/** + * Unescape the given string until a non escaped terminating char, + * and return the token corresponding to the unescaped string. + * + * The normal \ and ' escaping is supported. Leading and trailing + * whitespaces are removed, unless they are escaped with '\' or are + * enclosed between ''. + * + * @param buf the buffer to parse, buf will be updated to point to the + * terminating char + * @param term a 0-terminated list of terminating chars + * @return the malloced unescaped string, which must be av_freed by + * the user, NULL in case of allocation failure + */ +char *av_get_token(const char **buf, const char *term); + +/** + * Split the string into several tokens which can be accessed by + * successive calls to av_strtok(). + * + * A token is defined as a sequence of characters not belonging to the + * set specified in delim. + * + * On the first call to av_strtok(), s should point to the string to + * parse, and the value of saveptr is ignored. In subsequent calls, s + * should be NULL, and saveptr should be unchanged since the previous + * call. + * + * This function is similar to strtok_r() defined in POSIX.1. + * + * @param s the string to parse, may be NULL + * @param delim 0-terminated list of token delimiters, must be non-NULL + * @param saveptr user-provided pointer which points to stored + * information necessary for av_strtok() to continue scanning the same + * string. saveptr is updated to point to the next character after the + * first delimiter found, or to NULL if the string was terminated + * @return the found token, or NULL when no token is found + */ +char *av_strtok(char *s, const char *delim, char **saveptr); + +/** + * Locale-independent conversion of ASCII isdigit. + */ +static inline av_const int av_isdigit(int c) +{ + return c >= '0' && c <= '9'; +} + +/** + * Locale-independent conversion of ASCII isgraph. + */ +static inline av_const int av_isgraph(int c) +{ + return c > 32 && c < 127; +} + +/** + * Locale-independent conversion of ASCII isspace. + */ +static inline av_const int av_isspace(int c) +{ + return c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || + c == '\v'; +} + +/** + * Locale-independent conversion of ASCII characters to uppercase. + */ +static inline av_const int av_toupper(int c) +{ + if (c >= 'a' && c <= 'z') + c ^= 0x20; + return c; +} + +/** + * Locale-independent conversion of ASCII characters to lowercase. + */ +static inline av_const int av_tolower(int c) +{ + if (c >= 'A' && c <= 'Z') + c ^= 0x20; + return c; +} + +/** + * Locale-independent conversion of ASCII isxdigit. + */ +static inline av_const int av_isxdigit(int c) +{ + c = av_tolower(c); + return av_isdigit(c) || (c >= 'a' && c <= 'f'); +} + +/** + * Locale-independent case-insensitive compare. + * @note This means only ASCII-range characters are case-insensitive + */ +int av_strcasecmp(const char *a, const char *b); + +/** + * Locale-independent case-insensitive compare. + * @note This means only ASCII-range characters are case-insensitive + */ +int av_strncasecmp(const char *a, const char *b, size_t n); + + +/** + * Thread safe basename. + * @param path the path, on DOS both \ and / are considered separators. + * @return pointer to the basename substring. + */ +const char *av_basename(const char *path); + +/** + * Thread safe dirname. + * @param path the path, on DOS both \ and / are considered separators. + * @return the path with the separator replaced by the string terminator or ".". + * @note the function may change the input string. + */ +const char *av_dirname(char *path); + +/** + * Match instances of a name in a comma-separated list of names. + * @param name Name to look for. + * @param names List of names. + * @return 1 on match, 0 otherwise. + */ +int av_match_name(const char *name, const char *names); + +/** + * Append path component to the existing path. + * Path separator '/' is placed between when needed. + * Resulting string have to be freed with av_free(). + * @param path base path + * @param component component to be appended + * @return new path or NULL on error. + */ +char *av_append_path_component(const char *path, const char *component); + +enum AVEscapeMode { + AV_ESCAPE_MODE_AUTO, ///< Use auto-selected escaping mode. + AV_ESCAPE_MODE_BACKSLASH, ///< Use backslash escaping. + AV_ESCAPE_MODE_QUOTE, ///< Use single-quote escaping. +}; + +/** + * Consider spaces special and escape them even in the middle of the + * string. + * + * This is equivalent to adding the whitespace characters to the special + * characters lists, except it is guaranteed to use the exact same list + * of whitespace characters as the rest of libavutil. + */ +#define AV_ESCAPE_FLAG_WHITESPACE (1 << 0) + +/** + * Escape only specified special characters. + * Without this flag, escape also any characters that may be considered + * special by av_get_token(), such as the single quote. + */ +#define AV_ESCAPE_FLAG_STRICT (1 << 1) + +/** + * Escape string in src, and put the escaped string in an allocated + * string in *dst, which must be freed with av_free(). + * + * @param dst pointer where an allocated string is put + * @param src string to escape, must be non-NULL + * @param special_chars string containing the special characters which + * need to be escaped, can be NULL + * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros. + * Any unknown value for mode will be considered equivalent to + * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without + * notice. + * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_ macros + * @return the length of the allocated string, or a negative error code in case of error + * @see av_bprint_escape() + */ +av_warn_unused_result +int av_escape(char **dst, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags); + +#define AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES 1 ///< accept codepoints over 0x10FFFF +#define AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS 2 ///< accept non-characters - 0xFFFE and 0xFFFF +#define AV_UTF8_FLAG_ACCEPT_SURROGATES 4 ///< accept UTF-16 surrogates codes +#define AV_UTF8_FLAG_EXCLUDE_XML_INVALID_CONTROL_CODES 8 ///< exclude control codes not accepted by XML + +#define AV_UTF8_FLAG_ACCEPT_ALL \ + AV_UTF8_FLAG_ACCEPT_INVALID_BIG_CODES|AV_UTF8_FLAG_ACCEPT_NON_CHARACTERS|AV_UTF8_FLAG_ACCEPT_SURROGATES + +/** + * Read and decode a single UTF-8 code point (character) from the + * buffer in *buf, and update *buf to point to the next byte to + * decode. + * + * In case of an invalid byte sequence, the pointer will be updated to + * the next byte after the invalid sequence and the function will + * return an error code. + * + * Depending on the specified flags, the function will also fail in + * case the decoded code point does not belong to a valid range. + * + * @note For speed-relevant code a carefully implemented use of + * GET_UTF8() may be preferred. + * + * @param codep pointer used to return the parsed code in case of success. + * The value in *codep is set even in case the range check fails. + * @param bufp pointer to the address the first byte of the sequence + * to decode, updated by the function to point to the + * byte next after the decoded sequence + * @param buf_end pointer to the end of the buffer, points to the next + * byte past the last in the buffer. This is used to + * avoid buffer overreads (in case of an unfinished + * UTF-8 sequence towards the end of the buffer). + * @param flags a collection of AV_UTF8_FLAG_* flags + * @return >= 0 in case a sequence was successfully read, a negative + * value in case of invalid sequence + */ +av_warn_unused_result +int av_utf8_decode(int32_t *codep, const uint8_t **bufp, const uint8_t *buf_end, + unsigned int flags); + +/** + * Check if a name is in a list. + * @returns 0 if not found, or the 1 based index where it has been found in the + * list. + */ +int av_match_list(const char *name, const char *list, char separator); + +/** + * @} + */ + +#endif /* AVUTIL_AVSTRING_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/avutil.h b/TMessagesProj/jni/ffmpeg/include/libavutil/avutil.h new file mode 100644 index 00000000..9bcf6741 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/avutil.h @@ -0,0 +1,343 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_AVUTIL_H +#define AVUTIL_AVUTIL_H + +/** + * @file + * external API header + */ + +/** + * @mainpage + * + * @section ffmpeg_intro Introduction + * + * This document describes the usage of the different libraries + * provided by FFmpeg. + * + * @li @ref libavc "libavcodec" encoding/decoding library + * @li @ref lavfi "libavfilter" graph-based frame editing library + * @li @ref libavf "libavformat" I/O and muxing/demuxing library + * @li @ref lavd "libavdevice" special devices muxing/demuxing library + * @li @ref lavu "libavutil" common utility library + * @li @ref lswr "libswresample" audio resampling, format conversion and mixing + * @li @ref lpp "libpostproc" post processing library + * @li @ref libsws "libswscale" color conversion and scaling library + * + * @section ffmpeg_versioning Versioning and compatibility + * + * Each of the FFmpeg libraries contains a version.h header, which defines a + * major, minor and micro version number with the + * LIBRARYNAME_VERSION_{MAJOR,MINOR,MICRO} macros. The major version + * number is incremented with backward incompatible changes - e.g. removing + * parts of the public API, reordering public struct members, etc. The minor + * version number is incremented for backward compatible API changes or major + * new features - e.g. adding a new public function or a new decoder. The micro + * version number is incremented for smaller changes that a calling program + * might still want to check for - e.g. changing behavior in a previously + * unspecified situation. + * + * FFmpeg guarantees backward API and ABI compatibility for each library as long + * as its major version number is unchanged. This means that no public symbols + * will be removed or renamed. Types and names of the public struct members and + * values of public macros and enums will remain the same (unless they were + * explicitly declared as not part of the public API). Documented behavior will + * not change. + * + * In other words, any correct program that works with a given FFmpeg snapshot + * should work just as well without any changes with any later snapshot with the + * same major versions. This applies to both rebuilding the program against new + * FFmpeg versions or to replacing the dynamic FFmpeg libraries that a program + * links against. + * + * However, new public symbols may be added and new members may be appended to + * public structs whose size is not part of public ABI (most public structs in + * FFmpeg). New macros and enum values may be added. Behavior in undocumented + * situations may change slightly (and be documented). All those are accompanied + * by an entry in doc/APIchanges and incrementing either the minor or micro + * version number. + */ + +/** + * @defgroup lavu Common utility functions + * + * @brief + * libavutil contains the code shared across all the other FFmpeg + * libraries + * + * @note In order to use the functions provided by avutil you must include + * the specific header. + * + * @{ + * + * @defgroup lavu_crypto Crypto and Hashing + * + * @{ + * @} + * + * @defgroup lavu_math Maths + * @{ + * + * @} + * + * @defgroup lavu_string String Manipulation + * + * @{ + * + * @} + * + * @defgroup lavu_mem Memory Management + * + * @{ + * + * @} + * + * @defgroup lavu_data Data Structures + * @{ + * + * @} + * + * @defgroup lavu_audio Audio related + * + * @{ + * + * @} + * + * @defgroup lavu_error Error Codes + * + * @{ + * + * @} + * + * @defgroup lavu_log Logging Facility + * + * @{ + * + * @} + * + * @defgroup lavu_misc Other + * + * @{ + * + * @defgroup preproc_misc Preprocessor String Macros + * + * @{ + * + * @} + * + * @defgroup version_utils Library Version Macros + * + * @{ + * + * @} + */ + + +/** + * @addtogroup lavu_ver + * @{ + */ + +/** + * Return the LIBAVUTIL_VERSION_INT constant. + */ +unsigned avutil_version(void); + +/** + * Return an informative version string. This usually is the actual release + * version number or a git commit description. This string has no fixed format + * and can change any time. It should never be parsed by code. + */ +const char *av_version_info(void); + +/** + * Return the libavutil build-time configuration. + */ +const char *avutil_configuration(void); + +/** + * Return the libavutil license. + */ +const char *avutil_license(void); + +/** + * @} + */ + +/** + * @addtogroup lavu_media Media Type + * @brief Media Type + */ + +enum AVMediaType { + AVMEDIA_TYPE_UNKNOWN = -1, ///< Usually treated as AVMEDIA_TYPE_DATA + AVMEDIA_TYPE_VIDEO, + AVMEDIA_TYPE_AUDIO, + AVMEDIA_TYPE_DATA, ///< Opaque data information usually continuous + AVMEDIA_TYPE_SUBTITLE, + AVMEDIA_TYPE_ATTACHMENT, ///< Opaque data information usually sparse + AVMEDIA_TYPE_NB +}; + +/** + * Return a string describing the media_type enum, NULL if media_type + * is unknown. + */ +const char *av_get_media_type_string(enum AVMediaType media_type); + +/** + * @defgroup lavu_const Constants + * @{ + * + * @defgroup lavu_enc Encoding specific + * + * @note those definition should move to avcodec + * @{ + */ + +#define FF_LAMBDA_SHIFT 7 +#define FF_LAMBDA_SCALE (1< + +/** + * @defgroup lavu_base64 Base64 + * @ingroup lavu_crypto + * @{ + */ + + +/** + * Decode a base64-encoded string. + * + * @param out buffer for decoded data + * @param in null-terminated input string + * @param out_size size in bytes of the out buffer, must be at + * least 3/4 of the length of in + * @return number of bytes written, or a negative value in case of + * invalid input + */ +int av_base64_decode(uint8_t *out, const char *in, int out_size); + +/** + * Encode data to base64 and null-terminate. + * + * @param out buffer for encoded data + * @param out_size size in bytes of the out buffer (including the + * null terminator), must be at least AV_BASE64_SIZE(in_size) + * @param in input buffer containing the data to encode + * @param in_size size in bytes of the in buffer + * @return out or NULL in case of error + */ +char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size); + +/** + * Calculate the output size needed to base64-encode x bytes to a + * null-terminated string. + */ +#define AV_BASE64_SIZE(x) (((x)+2) / 3 * 4 + 1) + + /** + * @} + */ + +#endif /* AVUTIL_BASE64_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/blowfish.h b/TMessagesProj/jni/ffmpeg/include/libavutil/blowfish.h new file mode 100644 index 00000000..9e289a40 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/blowfish.h @@ -0,0 +1,82 @@ +/* + * Blowfish algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BLOWFISH_H +#define AVUTIL_BLOWFISH_H + +#include + +/** + * @defgroup lavu_blowfish Blowfish + * @ingroup lavu_crypto + * @{ + */ + +#define AV_BF_ROUNDS 16 + +typedef struct AVBlowfish { + uint32_t p[AV_BF_ROUNDS + 2]; + uint32_t s[4][256]; +} AVBlowfish; + +/** + * Allocate an AVBlowfish context. + */ +AVBlowfish *av_blowfish_alloc(void); + +/** + * Initialize an AVBlowfish context. + * + * @param ctx an AVBlowfish context + * @param key a key + * @param key_len length of the key + */ +void av_blowfish_init(struct AVBlowfish *ctx, const uint8_t *key, int key_len); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVBlowfish context + * @param xl left four bytes halves of input to be encrypted + * @param xr right four bytes halves of input to be encrypted + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_blowfish_crypt_ecb(struct AVBlowfish *ctx, uint32_t *xl, uint32_t *xr, + int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVBlowfish context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_blowfish_crypt(struct AVBlowfish *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_BLOWFISH_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/bprint.h b/TMessagesProj/jni/ffmpeg/include/libavutil/bprint.h new file mode 100644 index 00000000..c09b1ac1 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/bprint.h @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2012 Nicolas George + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_BPRINT_H +#define AVUTIL_BPRINT_H + +#include + +#include "attributes.h" +#include "avstring.h" + +/** + * Define a structure with extra padding to a fixed size + * This helps ensuring binary compatibility with future versions. + */ + +#define FF_PAD_STRUCTURE(name, size, ...) \ +struct ff_pad_helper_##name { __VA_ARGS__ }; \ +typedef struct name { \ + __VA_ARGS__ \ + char reserved_padding[size - sizeof(struct ff_pad_helper_##name)]; \ +} name; + +/** + * Buffer to print data progressively + * + * The string buffer grows as necessary and is always 0-terminated. + * The content of the string is never accessed, and thus is + * encoding-agnostic and can even hold binary data. + * + * Small buffers are kept in the structure itself, and thus require no + * memory allocation at all (unless the contents of the buffer is needed + * after the structure goes out of scope). This is almost as lightweight as + * declaring a local "char buf[512]". + * + * The length of the string can go beyond the allocated size: the buffer is + * then truncated, but the functions still keep account of the actual total + * length. + * + * In other words, buf->len can be greater than buf->size and records the + * total length of what would have been to the buffer if there had been + * enough memory. + * + * Append operations do not need to be tested for failure: if a memory + * allocation fails, data stop being appended to the buffer, but the length + * is still updated. This situation can be tested with + * av_bprint_is_complete(). + * + * The size_max field determines several possible behaviours: + * + * size_max = -1 (= UINT_MAX) or any large value will let the buffer be + * reallocated as necessary, with an amortized linear cost. + * + * size_max = 0 prevents writing anything to the buffer: only the total + * length is computed. The write operations can then possibly be repeated in + * a buffer with exactly the necessary size + * (using size_init = size_max = len + 1). + * + * size_max = 1 is automatically replaced by the exact size available in the + * structure itself, thus ensuring no dynamic memory allocation. The + * internal buffer is large enough to hold a reasonable paragraph of text, + * such as the current paragraph. + */ + +FF_PAD_STRUCTURE(AVBPrint, 1024, + char *str; /**< string so far */ + unsigned len; /**< length so far */ + unsigned size; /**< allocated memory */ + unsigned size_max; /**< maximum allocated memory */ + char reserved_internal_buffer[1]; +) + +/** + * Convenience macros for special values for av_bprint_init() size_max + * parameter. + */ +#define AV_BPRINT_SIZE_UNLIMITED ((unsigned)-1) +#define AV_BPRINT_SIZE_AUTOMATIC 1 +#define AV_BPRINT_SIZE_COUNT_ONLY 0 + +/** + * Init a print buffer. + * + * @param buf buffer to init + * @param size_init initial size (including the final 0) + * @param size_max maximum size; + * 0 means do not write anything, just count the length; + * 1 is replaced by the maximum value for automatic storage; + * any large value means that the internal buffer will be + * reallocated as needed up to that limit; -1 is converted to + * UINT_MAX, the largest limit possible. + * Check also AV_BPRINT_SIZE_* macros. + */ +void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max); + +/** + * Init a print buffer using a pre-existing buffer. + * + * The buffer will not be reallocated. + * + * @param buf buffer structure to init + * @param buffer byte buffer to use for the string data + * @param size size of buffer + */ +void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size); + +/** + * Append a formatted string to a print buffer. + */ +void av_bprintf(AVBPrint *buf, const char *fmt, ...) av_printf_format(2, 3); + +/** + * Append a formatted string to a print buffer. + */ +void av_vbprintf(AVBPrint *buf, const char *fmt, va_list vl_arg); + +/** + * Append char c n times to a print buffer. + */ +void av_bprint_chars(AVBPrint *buf, char c, unsigned n); + +/** + * Append data to a print buffer. + * + * param buf bprint buffer to use + * param data pointer to data + * param size size of data + */ +void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size); + +struct tm; +/** + * Append a formatted date and time to a print buffer. + * + * param buf bprint buffer to use + * param fmt date and time format string, see strftime() + * param tm broken-down time structure to translate + * + * @note due to poor design of the standard strftime function, it may + * produce poor results if the format string expands to a very long text and + * the bprint buffer is near the limit stated by the size_max option. + */ +void av_bprint_strftime(AVBPrint *buf, const char *fmt, const struct tm *tm); + +/** + * Allocate bytes in the buffer for external use. + * + * @param[in] buf buffer structure + * @param[in] size required size + * @param[out] mem pointer to the memory area + * @param[out] actual_size size of the memory area after allocation; + * can be larger or smaller than size + */ +void av_bprint_get_buffer(AVBPrint *buf, unsigned size, + unsigned char **mem, unsigned *actual_size); + +/** + * Reset the string to "" but keep internal allocated data. + */ +void av_bprint_clear(AVBPrint *buf); + +/** + * Test if the print buffer is complete (not truncated). + * + * It may have been truncated due to a memory allocation failure + * or the size_max limit (compare size and size_max if necessary). + */ +static inline int av_bprint_is_complete(const AVBPrint *buf) +{ + return buf->len < buf->size; +} + +/** + * Finalize a print buffer. + * + * The print buffer can no longer be used afterwards, + * but the len and size fields are still valid. + * + * @arg[out] ret_str if not NULL, used to return a permanent copy of the + * buffer contents, or NULL if memory allocation fails; + * if NULL, the buffer is discarded and freed + * @return 0 for success or error code (probably AVERROR(ENOMEM)) + */ +int av_bprint_finalize(AVBPrint *buf, char **ret_str); + +/** + * Escape the content in src and append it to dstbuf. + * + * @param dstbuf already inited destination bprint buffer + * @param src string containing the text to escape + * @param special_chars string containing the special characters which + * need to be escaped, can be NULL + * @param mode escape mode to employ, see AV_ESCAPE_MODE_* macros. + * Any unknown value for mode will be considered equivalent to + * AV_ESCAPE_MODE_BACKSLASH, but this behaviour can change without + * notice. + * @param flags flags which control how to escape, see AV_ESCAPE_FLAG_* macros + */ +void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, + enum AVEscapeMode mode, int flags); + +#endif /* AVUTIL_BPRINT_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/bswap.h b/TMessagesProj/jni/ffmpeg/include/libavutil/bswap.h new file mode 100644 index 00000000..91cb7953 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/bswap.h @@ -0,0 +1,109 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * byte swapping routines + */ + +#ifndef AVUTIL_BSWAP_H +#define AVUTIL_BSWAP_H + +#include +#include "libavutil/avconfig.h" +#include "attributes.h" + +#ifdef HAVE_AV_CONFIG_H + +#include "config.h" + +#if ARCH_AARCH64 +# include "aarch64/bswap.h" +#elif ARCH_ARM +# include "arm/bswap.h" +#elif ARCH_AVR32 +# include "avr32/bswap.h" +#elif ARCH_SH4 +# include "sh4/bswap.h" +#elif ARCH_X86 +# include "x86/bswap.h" +#endif + +#endif /* HAVE_AV_CONFIG_H */ + +#define AV_BSWAP16C(x) (((x) << 8 & 0xff00) | ((x) >> 8 & 0x00ff)) +#define AV_BSWAP32C(x) (AV_BSWAP16C(x) << 16 | AV_BSWAP16C((x) >> 16)) +#define AV_BSWAP64C(x) (AV_BSWAP32C(x) << 32 | AV_BSWAP32C((x) >> 32)) + +#define AV_BSWAPC(s, x) AV_BSWAP##s##C(x) + +#ifndef av_bswap16 +static av_always_inline av_const uint16_t av_bswap16(uint16_t x) +{ + x= (x>>8) | (x<<8); + return x; +} +#endif + +#ifndef av_bswap32 +static av_always_inline av_const uint32_t av_bswap32(uint32_t x) +{ + return AV_BSWAP32C(x); +} +#endif + +#ifndef av_bswap64 +static inline uint64_t av_const av_bswap64(uint64_t x) +{ + return (uint64_t)av_bswap32(x) << 32 | av_bswap32(x >> 32); +} +#endif + +// be2ne ... big-endian to native-endian +// le2ne ... little-endian to native-endian + +#if AV_HAVE_BIGENDIAN +#define av_be2ne16(x) (x) +#define av_be2ne32(x) (x) +#define av_be2ne64(x) (x) +#define av_le2ne16(x) av_bswap16(x) +#define av_le2ne32(x) av_bswap32(x) +#define av_le2ne64(x) av_bswap64(x) +#define AV_BE2NEC(s, x) (x) +#define AV_LE2NEC(s, x) AV_BSWAPC(s, x) +#else +#define av_be2ne16(x) av_bswap16(x) +#define av_be2ne32(x) av_bswap32(x) +#define av_be2ne64(x) av_bswap64(x) +#define av_le2ne16(x) (x) +#define av_le2ne32(x) (x) +#define av_le2ne64(x) (x) +#define AV_BE2NEC(s, x) AV_BSWAPC(s, x) +#define AV_LE2NEC(s, x) (x) +#endif + +#define AV_BE2NE16C(x) AV_BE2NEC(16, x) +#define AV_BE2NE32C(x) AV_BE2NEC(32, x) +#define AV_BE2NE64C(x) AV_BE2NEC(64, x) +#define AV_LE2NE16C(x) AV_LE2NEC(16, x) +#define AV_LE2NE32C(x) AV_LE2NEC(32, x) +#define AV_LE2NE64C(x) AV_LE2NEC(64, x) + +#endif /* AVUTIL_BSWAP_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/buffer.h b/TMessagesProj/jni/ffmpeg/include/libavutil/buffer.h new file mode 100644 index 00000000..b4399fd3 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/buffer.h @@ -0,0 +1,274 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_buffer + * refcounted data buffer API + */ + +#ifndef AVUTIL_BUFFER_H +#define AVUTIL_BUFFER_H + +#include + +/** + * @defgroup lavu_buffer AVBuffer + * @ingroup lavu_data + * + * @{ + * AVBuffer is an API for reference-counted data buffers. + * + * There are two core objects in this API -- AVBuffer and AVBufferRef. AVBuffer + * represents the data buffer itself; it is opaque and not meant to be accessed + * by the caller directly, but only through AVBufferRef. However, the caller may + * e.g. compare two AVBuffer pointers to check whether two different references + * are describing the same data buffer. AVBufferRef represents a single + * reference to an AVBuffer and it is the object that may be manipulated by the + * caller directly. + * + * There are two functions provided for creating a new AVBuffer with a single + * reference -- av_buffer_alloc() to just allocate a new buffer, and + * av_buffer_create() to wrap an existing array in an AVBuffer. From an existing + * reference, additional references may be created with av_buffer_ref(). + * Use av_buffer_unref() to free a reference (this will automatically free the + * data once all the references are freed). + * + * The convention throughout this API and the rest of FFmpeg is such that the + * buffer is considered writable if there exists only one reference to it (and + * it has not been marked as read-only). The av_buffer_is_writable() function is + * provided to check whether this is true and av_buffer_make_writable() will + * automatically create a new writable buffer when necessary. + * Of course nothing prevents the calling code from violating this convention, + * however that is safe only when all the existing references are under its + * control. + * + * @note Referencing and unreferencing the buffers is thread-safe and thus + * may be done from multiple threads simultaneously without any need for + * additional locking. + * + * @note Two different references to the same buffer can point to different + * parts of the buffer (i.e. their AVBufferRef.data will not be equal). + */ + +/** + * A reference counted buffer type. It is opaque and is meant to be used through + * references (AVBufferRef). + */ +typedef struct AVBuffer AVBuffer; + +/** + * A reference to a data buffer. + * + * The size of this struct is not a part of the public ABI and it is not meant + * to be allocated directly. + */ +typedef struct AVBufferRef { + AVBuffer *buffer; + + /** + * The data buffer. It is considered writable if and only if + * this is the only reference to the buffer, in which case + * av_buffer_is_writable() returns 1. + */ + uint8_t *data; + /** + * Size of data in bytes. + */ + int size; +} AVBufferRef; + +/** + * Allocate an AVBuffer of the given size using av_malloc(). + * + * @return an AVBufferRef of given size or NULL when out of memory + */ +AVBufferRef *av_buffer_alloc(int size); + +/** + * Same as av_buffer_alloc(), except the returned buffer will be initialized + * to zero. + */ +AVBufferRef *av_buffer_allocz(int size); + +/** + * Always treat the buffer as read-only, even when it has only one + * reference. + */ +#define AV_BUFFER_FLAG_READONLY (1 << 0) + +/** + * Create an AVBuffer from an existing array. + * + * If this function is successful, data is owned by the AVBuffer. The caller may + * only access data through the returned AVBufferRef and references derived from + * it. + * If this function fails, data is left untouched. + * @param data data array + * @param size size of data in bytes + * @param free a callback for freeing this buffer's data + * @param opaque parameter to be got for processing or passed to free + * @param flags a combination of AV_BUFFER_FLAG_* + * + * @return an AVBufferRef referring to data on success, NULL on failure. + */ +AVBufferRef *av_buffer_create(uint8_t *data, int size, + void (*free)(void *opaque, uint8_t *data), + void *opaque, int flags); + +/** + * Default free callback, which calls av_free() on the buffer data. + * This function is meant to be passed to av_buffer_create(), not called + * directly. + */ +void av_buffer_default_free(void *opaque, uint8_t *data); + +/** + * Create a new reference to an AVBuffer. + * + * @return a new AVBufferRef referring to the same AVBuffer as buf or NULL on + * failure. + */ +AVBufferRef *av_buffer_ref(AVBufferRef *buf); + +/** + * Free a given reference and automatically free the buffer if there are no more + * references to it. + * + * @param buf the reference to be freed. The pointer is set to NULL on return. + */ +void av_buffer_unref(AVBufferRef **buf); + +/** + * @return 1 if the caller may write to the data referred to by buf (which is + * true if and only if buf is the only reference to the underlying AVBuffer). + * Return 0 otherwise. + * A positive answer is valid until av_buffer_ref() is called on buf. + */ +int av_buffer_is_writable(const AVBufferRef *buf); + +/** + * @return the opaque parameter set by av_buffer_create. + */ +void *av_buffer_get_opaque(const AVBufferRef *buf); + +int av_buffer_get_ref_count(const AVBufferRef *buf); + +/** + * Create a writable reference from a given buffer reference, avoiding data copy + * if possible. + * + * @param buf buffer reference to make writable. On success, buf is either left + * untouched, or it is unreferenced and a new writable AVBufferRef is + * written in its place. On failure, buf is left untouched. + * @return 0 on success, a negative AVERROR on failure. + */ +int av_buffer_make_writable(AVBufferRef **buf); + +/** + * Reallocate a given buffer. + * + * @param buf a buffer reference to reallocate. On success, buf will be + * unreferenced and a new reference with the required size will be + * written in its place. On failure buf will be left untouched. *buf + * may be NULL, then a new buffer is allocated. + * @param size required new buffer size. + * @return 0 on success, a negative AVERROR on failure. + * + * @note the buffer is actually reallocated with av_realloc() only if it was + * initially allocated through av_buffer_realloc(NULL) and there is only one + * reference to it (i.e. the one passed to this function). In all other cases + * a new buffer is allocated and the data is copied. + */ +int av_buffer_realloc(AVBufferRef **buf, int size); + +/** + * @} + */ + +/** + * @defgroup lavu_bufferpool AVBufferPool + * @ingroup lavu_data + * + * @{ + * AVBufferPool is an API for a lock-free thread-safe pool of AVBuffers. + * + * Frequently allocating and freeing large buffers may be slow. AVBufferPool is + * meant to solve this in cases when the caller needs a set of buffers of the + * same size (the most obvious use case being buffers for raw video or audio + * frames). + * + * At the beginning, the user must call av_buffer_pool_init() to create the + * buffer pool. Then whenever a buffer is needed, call av_buffer_pool_get() to + * get a reference to a new buffer, similar to av_buffer_alloc(). This new + * reference works in all aspects the same way as the one created by + * av_buffer_alloc(). However, when the last reference to this buffer is + * unreferenced, it is returned to the pool instead of being freed and will be + * reused for subsequent av_buffer_pool_get() calls. + * + * When the caller is done with the pool and no longer needs to allocate any new + * buffers, av_buffer_pool_uninit() must be called to mark the pool as freeable. + * Once all the buffers are released, it will automatically be freed. + * + * Allocating and releasing buffers with this API is thread-safe as long as + * either the default alloc callback is used, or the user-supplied one is + * thread-safe. + */ + +/** + * The buffer pool. This structure is opaque and not meant to be accessed + * directly. It is allocated with av_buffer_pool_init() and freed with + * av_buffer_pool_uninit(). + */ +typedef struct AVBufferPool AVBufferPool; + +/** + * Allocate and initialize a buffer pool. + * + * @param size size of each buffer in this pool + * @param alloc a function that will be used to allocate new buffers when the + * pool is empty. May be NULL, then the default allocator will be used + * (av_buffer_alloc()). + * @return newly created buffer pool on success, NULL on error. + */ +AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size)); + +/** + * Mark the pool as being available for freeing. It will actually be freed only + * once all the allocated buffers associated with the pool are released. Thus it + * is safe to call this function while some of the allocated buffers are still + * in use. + * + * @param pool pointer to the pool to be freed. It will be set to NULL. + * @see av_buffer_pool_can_uninit() + */ +void av_buffer_pool_uninit(AVBufferPool **pool); + +/** + * Allocate a new AVBuffer, reusing an old buffer from the pool when available. + * This function may be called simultaneously from multiple threads. + * + * @return a reference to the new buffer on success, NULL on error. + */ +AVBufferRef *av_buffer_pool_get(AVBufferPool *pool); + +/** + * @} + */ + +#endif /* AVUTIL_BUFFER_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/camellia.h b/TMessagesProj/jni/ffmpeg/include/libavutil/camellia.h new file mode 100644 index 00000000..e674c9b9 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/camellia.h @@ -0,0 +1,70 @@ +/* + * An implementation of the CAMELLIA algorithm as mentioned in RFC3713 + * Copyright (c) 2014 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CAMELLIA_H +#define AVUTIL_CAMELLIA_H + +#include + + +/** + * @file + * @brief Public header for libavutil CAMELLIA algorithm + * @defgroup lavu_camellia CAMELLIA + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_camellia_size; + +struct AVCAMELLIA; + +/** + * Allocate an AVCAMELLIA context + * To free the struct: av_free(ptr) + */ +struct AVCAMELLIA *av_camellia_alloc(void); + +/** + * Initialize an AVCAMELLIA context. + * + * @param ctx an AVCAMELLIA context + * @param key a key of 16, 24, 32 bytes used for encryption/decryption + * @param key_bits number of keybits: possible are 128, 192, 256 + */ +int av_camellia_init(struct AVCAMELLIA *ctx, const uint8_t *key, int key_bits); + +/** + * Encrypt or decrypt a buffer using a previously initialized context + * + * @param ctx an AVCAMELLIA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 16 byte blocks + * @paran iv initialization vector for CBC mode, NULL for ECB mode + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_camellia_crypt(struct AVCAMELLIA *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t* iv, int decrypt); + +/** + * @} + */ +#endif /* AVUTIL_CAMELLIA_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/cast5.h b/TMessagesProj/jni/ffmpeg/include/libavutil/cast5.h new file mode 100644 index 00000000..ad5b347e --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/cast5.h @@ -0,0 +1,80 @@ +/* + * An implementation of the CAST128 algorithm as mentioned in RFC2144 + * Copyright (c) 2014 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CAST5_H +#define AVUTIL_CAST5_H + +#include + + +/** + * @file + * @brief Public header for libavutil CAST5 algorithm + * @defgroup lavu_cast5 CAST5 + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_cast5_size; + +struct AVCAST5; + +/** + * Allocate an AVCAST5 context + * To free the struct: av_free(ptr) + */ +struct AVCAST5 *av_cast5_alloc(void); +/** + * Initialize an AVCAST5 context. + * + * @param ctx an AVCAST5 context + * @param key a key of 5,6,...16 bytes used for encryption/decryption + * @param key_bits number of keybits: possible are 40,48,...,128 + * @return 0 on success, less than 0 on failure + */ +int av_cast5_init(struct AVCAST5 *ctx, const uint8_t *key, int key_bits); + +/** + * Encrypt or decrypt a buffer using a previously initialized context, ECB mode only + * + * @param ctx an AVCAST5 context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_cast5_crypt(struct AVCAST5 *ctx, uint8_t *dst, const uint8_t *src, int count, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context + * + * @param ctx an AVCAST5 context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, NULL for ECB mode + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_cast5_crypt2(struct AVCAST5 *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); +/** + * @} + */ +#endif /* AVUTIL_CAST5_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/channel_layout.h b/TMessagesProj/jni/ffmpeg/include/libavutil/channel_layout.h new file mode 100644 index 00000000..ec7effea --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/channel_layout.h @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2006 Michael Niedermayer + * Copyright (c) 2008 Peter Ross + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CHANNEL_LAYOUT_H +#define AVUTIL_CHANNEL_LAYOUT_H + +#include + +/** + * @file + * audio channel layout utility functions + */ + +/** + * @addtogroup lavu_audio + * @{ + */ + +/** + * @defgroup channel_masks Audio channel masks + * + * A channel layout is a 64-bits integer with a bit set for every channel. + * The number of bits set must be equal to the number of channels. + * The value 0 means that the channel layout is not known. + * @note this data structure is not powerful enough to handle channels + * combinations that have the same channel multiple times, such as + * dual-mono. + * + * @{ + */ +#define AV_CH_FRONT_LEFT 0x00000001 +#define AV_CH_FRONT_RIGHT 0x00000002 +#define AV_CH_FRONT_CENTER 0x00000004 +#define AV_CH_LOW_FREQUENCY 0x00000008 +#define AV_CH_BACK_LEFT 0x00000010 +#define AV_CH_BACK_RIGHT 0x00000020 +#define AV_CH_FRONT_LEFT_OF_CENTER 0x00000040 +#define AV_CH_FRONT_RIGHT_OF_CENTER 0x00000080 +#define AV_CH_BACK_CENTER 0x00000100 +#define AV_CH_SIDE_LEFT 0x00000200 +#define AV_CH_SIDE_RIGHT 0x00000400 +#define AV_CH_TOP_CENTER 0x00000800 +#define AV_CH_TOP_FRONT_LEFT 0x00001000 +#define AV_CH_TOP_FRONT_CENTER 0x00002000 +#define AV_CH_TOP_FRONT_RIGHT 0x00004000 +#define AV_CH_TOP_BACK_LEFT 0x00008000 +#define AV_CH_TOP_BACK_CENTER 0x00010000 +#define AV_CH_TOP_BACK_RIGHT 0x00020000 +#define AV_CH_STEREO_LEFT 0x20000000 ///< Stereo downmix. +#define AV_CH_STEREO_RIGHT 0x40000000 ///< See AV_CH_STEREO_LEFT. +#define AV_CH_WIDE_LEFT 0x0000000080000000ULL +#define AV_CH_WIDE_RIGHT 0x0000000100000000ULL +#define AV_CH_SURROUND_DIRECT_LEFT 0x0000000200000000ULL +#define AV_CH_SURROUND_DIRECT_RIGHT 0x0000000400000000ULL +#define AV_CH_LOW_FREQUENCY_2 0x0000000800000000ULL + +/** Channel mask value used for AVCodecContext.request_channel_layout + to indicate that the user requests the channel order of the decoder output + to be the native codec channel order. */ +#define AV_CH_LAYOUT_NATIVE 0x8000000000000000ULL + +/** + * @} + * @defgroup channel_mask_c Audio channel layouts + * @{ + * */ +#define AV_CH_LAYOUT_MONO (AV_CH_FRONT_CENTER) +#define AV_CH_LAYOUT_STEREO (AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT) +#define AV_CH_LAYOUT_2POINT1 (AV_CH_LAYOUT_STEREO|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_2_1 (AV_CH_LAYOUT_STEREO|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_SURROUND (AV_CH_LAYOUT_STEREO|AV_CH_FRONT_CENTER) +#define AV_CH_LAYOUT_3POINT1 (AV_CH_LAYOUT_SURROUND|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_4POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_4POINT1 (AV_CH_LAYOUT_4POINT0|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_2_2 (AV_CH_LAYOUT_STEREO|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) +#define AV_CH_LAYOUT_QUAD (AV_CH_LAYOUT_STEREO|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT0 (AV_CH_LAYOUT_SURROUND|AV_CH_SIDE_LEFT|AV_CH_SIDE_RIGHT) +#define AV_CH_LAYOUT_5POINT1 (AV_CH_LAYOUT_5POINT0|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_5POINT0_BACK (AV_CH_LAYOUT_SURROUND|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_5POINT1_BACK (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_6POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT0_FRONT (AV_CH_LAYOUT_2_2|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_HEXAGONAL (AV_CH_LAYOUT_5POINT0_BACK|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_BACK_CENTER) +#define AV_CH_LAYOUT_6POINT1_FRONT (AV_CH_LAYOUT_6POINT0_FRONT|AV_CH_LOW_FREQUENCY) +#define AV_CH_LAYOUT_7POINT0 (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT0_FRONT (AV_CH_LAYOUT_5POINT0|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_7POINT1 (AV_CH_LAYOUT_5POINT1|AV_CH_BACK_LEFT|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_7POINT1_WIDE (AV_CH_LAYOUT_5POINT1|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_7POINT1_WIDE_BACK (AV_CH_LAYOUT_5POINT1_BACK|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER) +#define AV_CH_LAYOUT_OCTAGONAL (AV_CH_LAYOUT_5POINT0|AV_CH_BACK_LEFT|AV_CH_BACK_CENTER|AV_CH_BACK_RIGHT) +#define AV_CH_LAYOUT_HEXADECAGONAL (AV_CH_LAYOUT_OCTAGONAL|AV_CH_WIDE_LEFT|AV_CH_WIDE_RIGHT|AV_CH_TOP_BACK_LEFT|AV_CH_TOP_BACK_RIGHT|AV_CH_TOP_BACK_CENTER|AV_CH_TOP_FRONT_CENTER|AV_CH_TOP_FRONT_LEFT|AV_CH_TOP_FRONT_RIGHT) +#define AV_CH_LAYOUT_STEREO_DOWNMIX (AV_CH_STEREO_LEFT|AV_CH_STEREO_RIGHT) + +enum AVMatrixEncoding { + AV_MATRIX_ENCODING_NONE, + AV_MATRIX_ENCODING_DOLBY, + AV_MATRIX_ENCODING_DPLII, + AV_MATRIX_ENCODING_DPLIIX, + AV_MATRIX_ENCODING_DPLIIZ, + AV_MATRIX_ENCODING_DOLBYEX, + AV_MATRIX_ENCODING_DOLBYHEADPHONE, + AV_MATRIX_ENCODING_NB +}; + +/** + * Return a channel layout id that matches name, or 0 if no match is found. + * + * name can be one or several of the following notations, + * separated by '+' or '|': + * - the name of an usual channel layout (mono, stereo, 4.0, quad, 5.0, + * 5.0(side), 5.1, 5.1(side), 7.1, 7.1(wide), downmix); + * - the name of a single channel (FL, FR, FC, LFE, BL, BR, FLC, FRC, BC, + * SL, SR, TC, TFL, TFC, TFR, TBL, TBC, TBR, DL, DR); + * - a number of channels, in decimal, optionally followed by 'c', yielding + * the default channel layout for that number of channels (@see + * av_get_default_channel_layout); + * - a channel layout mask, in hexadecimal starting with "0x" (see the + * AV_CH_* macros). + * + * @warning Starting from the next major bump the trailing character + * 'c' to specify a number of channels will be required, while a + * channel layout mask could also be specified as a decimal number + * (if and only if not followed by "c"). + * + * Example: "stereo+FC" = "2c+FC" = "2c+1c" = "0x7" + */ +uint64_t av_get_channel_layout(const char *name); + +/** + * Return a description of a channel layout. + * If nb_channels is <= 0, it is guessed from the channel_layout. + * + * @param buf put here the string containing the channel layout + * @param buf_size size in bytes of the buffer + */ +void av_get_channel_layout_string(char *buf, int buf_size, int nb_channels, uint64_t channel_layout); + +struct AVBPrint; +/** + * Append a description of a channel layout to a bprint buffer. + */ +void av_bprint_channel_layout(struct AVBPrint *bp, int nb_channels, uint64_t channel_layout); + +/** + * Return the number of channels in the channel layout. + */ +int av_get_channel_layout_nb_channels(uint64_t channel_layout); + +/** + * Return default channel layout for a given number of channels. + */ +int64_t av_get_default_channel_layout(int nb_channels); + +/** + * Get the index of a channel in channel_layout. + * + * @param channel a channel layout describing exactly one channel which must be + * present in channel_layout. + * + * @return index of channel in channel_layout on success, a negative AVERROR + * on error. + */ +int av_get_channel_layout_channel_index(uint64_t channel_layout, + uint64_t channel); + +/** + * Get the channel with the given index in channel_layout. + */ +uint64_t av_channel_layout_extract_channel(uint64_t channel_layout, int index); + +/** + * Get the name of a given channel. + * + * @return channel name on success, NULL on error. + */ +const char *av_get_channel_name(uint64_t channel); + +/** + * Get the description of a given channel. + * + * @param channel a channel layout with a single channel + * @return channel description on success, NULL on error + */ +const char *av_get_channel_description(uint64_t channel); + +/** + * Get the value and name of a standard channel layout. + * + * @param[in] index index in an internal list, starting at 0 + * @param[out] layout channel layout mask + * @param[out] name name of the layout + * @return 0 if the layout exists, + * <0 if index is beyond the limits + */ +int av_get_standard_channel_layout(unsigned index, uint64_t *layout, + const char **name); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_CHANNEL_LAYOUT_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/common.h b/TMessagesProj/jni/ffmpeg/include/libavutil/common.h new file mode 100644 index 00000000..6f0f5827 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/common.h @@ -0,0 +1,519 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * common internal and external API header + */ + +#ifndef AVUTIL_COMMON_H +#define AVUTIL_COMMON_H + +#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) && !defined(UINT64_C) +#error missing -D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "attributes.h" +#include "version.h" +#include "libavutil/avconfig.h" + +#if AV_HAVE_BIGENDIAN +# define AV_NE(be, le) (be) +#else +# define AV_NE(be, le) (le) +#endif + +//rounded division & shift +#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b)) +/* assume b>0 */ +#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b)) +/* assume a>0 and b>0 */ +#define FF_CEIL_RSHIFT(a,b) (!av_builtin_constant_p(b) ? -((-(a)) >> (b)) \ + : ((a) + (1<<(b)) - 1) >> (b)) +#define FFUDIV(a,b) (((a)>0 ?(a):(a)-(b)+1) / (b)) +#define FFUMOD(a,b) ((a)-(b)*FFUDIV(a,b)) + +/** + * Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they + * are not representable as absolute values of their type. This is the same + * as with *abs() + * @see FFNABS() + */ +#define FFABS(a) ((a) >= 0 ? (a) : (-(a))) +#define FFSIGN(a) ((a) > 0 ? 1 : -1) + +/** + * Negative Absolute value. + * this works for all integers of all types. + * As with many macros, this evaluates its argument twice, it thus must not have + * a sideeffect, that is FFNABS(x++) has undefined behavior. + */ +#define FFNABS(a) ((a) <= 0 ? (a) : (-(a))) + +/** + * Comparator. + * For two numerical expressions x and y, gives 1 if x > y, -1 if x < y, and 0 + * if x == y. This is useful for instance in a qsort comparator callback. + * Furthermore, compilers are able to optimize this to branchless code, and + * there is no risk of overflow with signed types. + * As with many macros, this evaluates its argument multiple times, it thus + * must not have a side-effect. + */ +#define FFDIFFSIGN(x,y) (((x)>(y)) - ((x)<(y))) + +#define FFMAX(a,b) ((a) > (b) ? (a) : (b)) +#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c) +#define FFMIN(a,b) ((a) > (b) ? (b) : (a)) +#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c) + +#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0) +#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0])) +#define FFALIGN(x, a) (((x)+(a)-1)&~((a)-1)) + +/* misc math functions */ + +#ifdef HAVE_AV_CONFIG_H +# include "config.h" +# include "intmath.h" +#endif + +/* Pull in unguarded fallback defines at the end of this file. */ +#include "common.h" + +#ifndef av_log2 +av_const int av_log2(unsigned v); +#endif + +#ifndef av_log2_16bit +av_const int av_log2_16bit(unsigned v); +#endif + +/** + * Clip a signed integer value into the amin-amax range. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const int av_clip_c(int a, int amin, int amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * Clip a signed 64bit integer value into the amin-amax range. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * Clip a signed integer value into the 0-255 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const uint8_t av_clip_uint8_c(int a) +{ + if (a&(~0xFF)) return (-a)>>31; + else return a; +} + +/** + * Clip a signed integer value into the -128,127 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int8_t av_clip_int8_c(int a) +{ + if ((a+0x80U) & ~0xFF) return (a>>31) ^ 0x7F; + else return a; +} + +/** + * Clip a signed integer value into the 0-65535 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const uint16_t av_clip_uint16_c(int a) +{ + if (a&(~0xFFFF)) return (-a)>>31; + else return a; +} + +/** + * Clip a signed integer value into the -32768,32767 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int16_t av_clip_int16_c(int a) +{ + if ((a+0x8000U) & ~0xFFFF) return (a>>31) ^ 0x7FFF; + else return a; +} + +/** + * Clip a signed 64-bit integer value into the -2147483648,2147483647 range. + * @param a value to clip + * @return clipped value + */ +static av_always_inline av_const int32_t av_clipl_int32_c(int64_t a) +{ + if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (int32_t)((a>>63) ^ 0x7FFFFFFF); + else return (int32_t)a; +} + +/** + * Clip a signed integer into the -(2^p),(2^p-1) range. + * @param a value to clip + * @param p bit position to clip at + * @return clipped value + */ +static av_always_inline av_const int av_clip_intp2_c(int a, int p) +{ + if ((a + (1 << p)) & ~((2 << p) - 1)) + return (a >> 31) ^ ((1 << p) - 1); + else + return a; +} + +/** + * Clip a signed integer to an unsigned power of two range. + * @param a value to clip + * @param p bit position to clip at + * @return clipped value + */ +static av_always_inline av_const unsigned av_clip_uintp2_c(int a, int p) +{ + if (a & ~((1<> 31 & ((1<= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** + * Clip a double value into the amin-amax range. + * @param a value to clip + * @param amin minimum value of the clip range + * @param amax maximum value of the clip range + * @return clipped value + */ +static av_always_inline av_const double av_clipd_c(double a, double amin, double amax) +{ +#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2 + if (amin > amax) abort(); +#endif + if (a < amin) return amin; + else if (a > amax) return amax; + else return a; +} + +/** Compute ceil(log2(x)). + * @param x value used to compute ceil(log2(x)) + * @return computed ceiling of log2(x) + */ +static av_always_inline av_const int av_ceil_log2_c(int x) +{ + return av_log2((x - 1) << 1); +} + +/** + * Count number of bits set to one in x + * @param x value to count bits of + * @return the number of bits set to one in x + */ +static av_always_inline av_const int av_popcount_c(uint32_t x) +{ + x -= (x >> 1) & 0x55555555; + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + x = (x + (x >> 4)) & 0x0F0F0F0F; + x += x >> 8; + return (x + (x >> 16)) & 0x3F; +} + +/** + * Count number of bits set to one in x + * @param x value to count bits of + * @return the number of bits set to one in x + */ +static av_always_inline av_const int av_popcount64_c(uint64_t x) +{ + return av_popcount((uint32_t)x) + av_popcount((uint32_t)(x >> 32)); +} + +#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24)) +#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24)) + +/** + * Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form. + * + * @param val Output value, must be an lvalue of type uint32_t. + * @param GET_BYTE Expression reading one byte from the input. + * Evaluated up to 7 times (4 for the currently + * assigned Unicode range). With a memory buffer + * input, this could be *ptr++. + * @param ERROR Expression to be evaluated on invalid input, + * typically a goto statement. + * + * @warning ERROR should not contain a loop control statement which + * could interact with the internal while loop, and should force an + * exit from the macro code (e.g. through a goto or a return) in order + * to prevent undefined results. + */ +#define GET_UTF8(val, GET_BYTE, ERROR)\ + val= GET_BYTE;\ + {\ + uint32_t top = (val & 128) >> 1;\ + if ((val & 0xc0) == 0x80 || val >= 0xFE)\ + ERROR\ + while (val & top) {\ + int tmp= GET_BYTE - 128;\ + if(tmp>>6)\ + ERROR\ + val= (val<<6) + tmp;\ + top <<= 5;\ + }\ + val &= (top << 1) - 1;\ + } + +/** + * Convert a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form. + * + * @param val Output value, must be an lvalue of type uint32_t. + * @param GET_16BIT Expression returning two bytes of UTF-16 data converted + * to native byte order. Evaluated one or two times. + * @param ERROR Expression to be evaluated on invalid input, + * typically a goto statement. + */ +#define GET_UTF16(val, GET_16BIT, ERROR)\ + val = GET_16BIT;\ + {\ + unsigned int hi = val - 0xD800;\ + if (hi < 0x800) {\ + val = GET_16BIT - 0xDC00;\ + if (val > 0x3FFU || hi > 0x3FFU)\ + ERROR\ + val += (hi<<10) + 0x10000;\ + }\ + }\ + +/** + * @def PUT_UTF8(val, tmp, PUT_BYTE) + * Convert a 32-bit Unicode character to its UTF-8 encoded form (up to 4 bytes long). + * @param val is an input-only argument and should be of type uint32_t. It holds + * a UCS-4 encoded Unicode character that is to be converted to UTF-8. If + * val is given as a function it is executed only once. + * @param tmp is a temporary variable and should be of type uint8_t. It + * represents an intermediate value during conversion that is to be + * output by PUT_BYTE. + * @param PUT_BYTE writes the converted UTF-8 bytes to any proper destination. + * It could be a function or a statement, and uses tmp as the input byte. + * For example, PUT_BYTE could be "*output++ = tmp;" PUT_BYTE will be + * executed up to 4 times for values in the valid UTF-8 range and up to + * 7 times in the general case, depending on the length of the converted + * Unicode character. + */ +#define PUT_UTF8(val, tmp, PUT_BYTE)\ + {\ + int bytes, shift;\ + uint32_t in = val;\ + if (in < 0x80) {\ + tmp = in;\ + PUT_BYTE\ + } else {\ + bytes = (av_log2(in) + 4) / 5;\ + shift = (bytes - 1) * 6;\ + tmp = (256 - (256 >> bytes)) | (in >> shift);\ + PUT_BYTE\ + while (shift >= 6) {\ + shift -= 6;\ + tmp = 0x80 | ((in >> shift) & 0x3f);\ + PUT_BYTE\ + }\ + }\ + } + +/** + * @def PUT_UTF16(val, tmp, PUT_16BIT) + * Convert a 32-bit Unicode character to its UTF-16 encoded form (2 or 4 bytes). + * @param val is an input-only argument and should be of type uint32_t. It holds + * a UCS-4 encoded Unicode character that is to be converted to UTF-16. If + * val is given as a function it is executed only once. + * @param tmp is a temporary variable and should be of type uint16_t. It + * represents an intermediate value during conversion that is to be + * output by PUT_16BIT. + * @param PUT_16BIT writes the converted UTF-16 data to any proper destination + * in desired endianness. It could be a function or a statement, and uses tmp + * as the input byte. For example, PUT_BYTE could be "*output++ = tmp;" + * PUT_BYTE will be executed 1 or 2 times depending on input character. + */ +#define PUT_UTF16(val, tmp, PUT_16BIT)\ + {\ + uint32_t in = val;\ + if (in < 0x10000) {\ + tmp = in;\ + PUT_16BIT\ + } else {\ + tmp = 0xD800 | ((in - 0x10000) >> 10);\ + PUT_16BIT\ + tmp = 0xDC00 | ((in - 0x10000) & 0x3FF);\ + PUT_16BIT\ + }\ + }\ + + + +#include "mem.h" + +#ifdef HAVE_AV_CONFIG_H +# include "internal.h" +#endif /* HAVE_AV_CONFIG_H */ + +#endif /* AVUTIL_COMMON_H */ + +/* + * The following definitions are outside the multiple inclusion guard + * to ensure they are immediately available in intmath.h. + */ + +#ifndef av_ceil_log2 +# define av_ceil_log2 av_ceil_log2_c +#endif +#ifndef av_clip +# define av_clip av_clip_c +#endif +#ifndef av_clip64 +# define av_clip64 av_clip64_c +#endif +#ifndef av_clip_uint8 +# define av_clip_uint8 av_clip_uint8_c +#endif +#ifndef av_clip_int8 +# define av_clip_int8 av_clip_int8_c +#endif +#ifndef av_clip_uint16 +# define av_clip_uint16 av_clip_uint16_c +#endif +#ifndef av_clip_int16 +# define av_clip_int16 av_clip_int16_c +#endif +#ifndef av_clipl_int32 +# define av_clipl_int32 av_clipl_int32_c +#endif +#ifndef av_clip_intp2 +# define av_clip_intp2 av_clip_intp2_c +#endif +#ifndef av_clip_uintp2 +# define av_clip_uintp2 av_clip_uintp2_c +#endif +#ifndef av_mod_uintp2 +# define av_mod_uintp2 av_mod_uintp2_c +#endif +#ifndef av_sat_add32 +# define av_sat_add32 av_sat_add32_c +#endif +#ifndef av_sat_dadd32 +# define av_sat_dadd32 av_sat_dadd32_c +#endif +#ifndef av_clipf +# define av_clipf av_clipf_c +#endif +#ifndef av_clipd +# define av_clipd av_clipd_c +#endif +#ifndef av_popcount +# define av_popcount av_popcount_c +#endif +#ifndef av_popcount64 +# define av_popcount64 av_popcount64_c +#endif diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/cpu.h b/TMessagesProj/jni/ffmpeg/include/libavutil/cpu.h new file mode 100644 index 00000000..bff8518c --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/cpu.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2000, 2001, 2002 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CPU_H +#define AVUTIL_CPU_H + +#include "attributes.h" + +#define AV_CPU_FLAG_FORCE 0x80000000 /* force usage of selected flags (OR) */ + + /* lower 16 bits - CPU features */ +#define AV_CPU_FLAG_MMX 0x0001 ///< standard MMX +#define AV_CPU_FLAG_MMXEXT 0x0002 ///< SSE integer functions or AMD MMX ext +#define AV_CPU_FLAG_MMX2 0x0002 ///< SSE integer functions or AMD MMX ext +#define AV_CPU_FLAG_3DNOW 0x0004 ///< AMD 3DNOW +#define AV_CPU_FLAG_SSE 0x0008 ///< SSE functions +#define AV_CPU_FLAG_SSE2 0x0010 ///< PIV SSE2 functions +#define AV_CPU_FLAG_SSE2SLOW 0x40000000 ///< SSE2 supported, but usually not faster + ///< than regular MMX/SSE (e.g. Core1) +#define AV_CPU_FLAG_3DNOWEXT 0x0020 ///< AMD 3DNowExt +#define AV_CPU_FLAG_SSE3 0x0040 ///< Prescott SSE3 functions +#define AV_CPU_FLAG_SSE3SLOW 0x20000000 ///< SSE3 supported, but usually not faster + ///< than regular MMX/SSE (e.g. Core1) +#define AV_CPU_FLAG_SSSE3 0x0080 ///< Conroe SSSE3 functions +#define AV_CPU_FLAG_ATOM 0x10000000 ///< Atom processor, some SSSE3 instructions are slower +#define AV_CPU_FLAG_SSE4 0x0100 ///< Penryn SSE4.1 functions +#define AV_CPU_FLAG_SSE42 0x0200 ///< Nehalem SSE4.2 functions +#define AV_CPU_FLAG_AESNI 0x80000 ///< Advanced Encryption Standard functions +#define AV_CPU_FLAG_AVX 0x4000 ///< AVX functions: requires OS support even if YMM registers aren't used +#define AV_CPU_FLAG_AVXSLOW 0x8000000 ///< AVX supported, but slow when using YMM registers (e.g. Bulldozer) +#define AV_CPU_FLAG_XOP 0x0400 ///< Bulldozer XOP functions +#define AV_CPU_FLAG_FMA4 0x0800 ///< Bulldozer FMA4 functions +#define AV_CPU_FLAG_CMOV 0x1000 ///< supports cmov instruction +#define AV_CPU_FLAG_AVX2 0x8000 ///< AVX2 functions: requires OS support even if YMM registers aren't used +#define AV_CPU_FLAG_FMA3 0x10000 ///< Haswell FMA3 functions +#define AV_CPU_FLAG_BMI1 0x20000 ///< Bit Manipulation Instruction Set 1 +#define AV_CPU_FLAG_BMI2 0x40000 ///< Bit Manipulation Instruction Set 2 + +#define AV_CPU_FLAG_ALTIVEC 0x0001 ///< standard +#define AV_CPU_FLAG_VSX 0x0002 ///< ISA 2.06 +#define AV_CPU_FLAG_POWER8 0x0004 ///< ISA 2.07 + +#define AV_CPU_FLAG_ARMV5TE (1 << 0) +#define AV_CPU_FLAG_ARMV6 (1 << 1) +#define AV_CPU_FLAG_ARMV6T2 (1 << 2) +#define AV_CPU_FLAG_VFP (1 << 3) +#define AV_CPU_FLAG_VFPV3 (1 << 4) +#define AV_CPU_FLAG_NEON (1 << 5) +#define AV_CPU_FLAG_ARMV8 (1 << 6) +#define AV_CPU_FLAG_SETEND (1 <<16) + +/** + * Return the flags which specify extensions supported by the CPU. + * The returned value is affected by av_force_cpu_flags() if that was used + * before. So av_get_cpu_flags() can easily be used in a application to + * detect the enabled cpu flags. + */ +int av_get_cpu_flags(void); + +/** + * Disables cpu detection and forces the specified flags. + * -1 is a special case that disables forcing of specific flags. + */ +void av_force_cpu_flags(int flags); + +/** + * Set a mask on flags returned by av_get_cpu_flags(). + * This function is mainly useful for testing. + * Please use av_force_cpu_flags() and av_get_cpu_flags() instead which are more flexible + * + * @warning this function is not thread safe. + */ +attribute_deprecated void av_set_cpu_flags_mask(int mask); + +/** + * Parse CPU flags from a string. + * + * The returned flags contain the specified flags as well as related unspecified flags. + * + * This function exists only for compatibility with libav. + * Please use av_parse_cpu_caps() when possible. + * @return a combination of AV_CPU_* flags, negative on error. + */ +attribute_deprecated +int av_parse_cpu_flags(const char *s); + +/** + * Parse CPU caps from a string and update the given AV_CPU_* flags based on that. + * + * @return negative on error. + */ +int av_parse_cpu_caps(unsigned *flags, const char *s); + +/** + * @return the number of logical CPU cores present. + */ +int av_cpu_count(void); + +#endif /* AVUTIL_CPU_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/crc.h b/TMessagesProj/jni/ffmpeg/include/libavutil/crc.h new file mode 100644 index 00000000..ef8a7137 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/crc.h @@ -0,0 +1,91 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_CRC_H +#define AVUTIL_CRC_H + +#include +#include +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_crc32 CRC32 + * @ingroup lavu_crypto + * @{ + */ + +typedef uint32_t AVCRC; + +typedef enum { + AV_CRC_8_ATM, + AV_CRC_16_ANSI, + AV_CRC_16_CCITT, + AV_CRC_32_IEEE, + AV_CRC_32_IEEE_LE, /*< reversed bitorder version of AV_CRC_32_IEEE */ + AV_CRC_16_ANSI_LE, /*< reversed bitorder version of AV_CRC_16_ANSI */ +#if FF_API_CRC_BIG_TABLE + AV_CRC_24_IEEE = 12, +#else + AV_CRC_24_IEEE, +#endif /* FF_API_CRC_BIG_TABLE */ + AV_CRC_MAX, /*< Not part of public API! Do not use outside libavutil. */ +}AVCRCId; + +/** + * Initialize a CRC table. + * @param ctx must be an array of size sizeof(AVCRC)*257 or sizeof(AVCRC)*1024 + * @param le If 1, the lowest bit represents the coefficient for the highest + * exponent of the corresponding polynomial (both for poly and + * actual CRC). + * If 0, you must swap the CRC parameter and the result of av_crc + * if you need the standard representation (can be simplified in + * most cases to e.g. bswap16): + * av_bswap32(crc << (32-bits)) + * @param bits number of bits for the CRC + * @param poly generator polynomial without the x**bits coefficient, in the + * representation as specified by le + * @param ctx_size size of ctx in bytes + * @return <0 on failure + */ +int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size); + +/** + * Get an initialized standard CRC table. + * @param crc_id ID of a standard CRC + * @return a pointer to the CRC table or NULL on failure + */ +const AVCRC *av_crc_get_table(AVCRCId crc_id); + +/** + * Calculate the CRC of a block. + * @param crc CRC of previous blocks if any or initial value for CRC + * @return CRC updated with the data from the given block + * + * @see av_crc_init() "le" parameter + */ +uint32_t av_crc(const AVCRC *ctx, uint32_t crc, + const uint8_t *buffer, size_t length) av_pure; + +/** + * @} + */ + +#endif /* AVUTIL_CRC_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/des.h b/TMessagesProj/jni/ffmpeg/include/libavutil/des.h new file mode 100644 index 00000000..4cf11f5b --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/des.h @@ -0,0 +1,77 @@ +/* + * DES encryption/decryption + * Copyright (c) 2007 Reimar Doeffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DES_H +#define AVUTIL_DES_H + +#include + +/** + * @defgroup lavu_des DES + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVDES { + uint64_t round_keys[3][16]; + int triple_des; +} AVDES; + +/** + * Allocate an AVDES context. + */ +AVDES *av_des_alloc(void); + +/** + * @brief Initializes an AVDES context. + * + * @param key_bits must be 64 or 192 + * @param decrypt 0 for encryption/CBC-MAC, 1 for decryption + * @return zero on success, negative value otherwise + */ +int av_des_init(struct AVDES *d, const uint8_t *key, int key_bits, int decrypt); + +/** + * @brief Encrypts / decrypts using the DES algorithm. + * + * @param count number of 8 byte blocks + * @param dst destination array, can be equal to src, must be 8-byte aligned + * @param src source array, can be equal to dst, must be 8-byte aligned, may be NULL + * @param iv initialization vector for CBC mode, if NULL then ECB will be used, + * must be 8-byte aligned + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_des_crypt(struct AVDES *d, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @brief Calculates CBC-MAC using the DES algorithm. + * + * @param count number of 8 byte blocks + * @param dst destination array, can be equal to src, must be 8-byte aligned + * @param src source array, can be equal to dst, must be 8-byte aligned, may be NULL + */ +void av_des_mac(struct AVDES *d, uint8_t *dst, const uint8_t *src, int count); + +/** + * @} + */ + +#endif /* AVUTIL_DES_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/dict.h b/TMessagesProj/jni/ffmpeg/include/libavutil/dict.h new file mode 100644 index 00000000..5b8d0033 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/dict.h @@ -0,0 +1,198 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Public dictionary API. + * @deprecated + * AVDictionary is provided for compatibility with libav. It is both in + * implementation as well as API inefficient. It does not scale and is + * extremely slow with large dictionaries. + * It is recommended that new code uses our tree container from tree.c/h + * where applicable, which uses AVL trees to achieve O(log n) performance. + */ + +#ifndef AVUTIL_DICT_H +#define AVUTIL_DICT_H + +#include + +#include "version.h" + +/** + * @addtogroup lavu_dict AVDictionary + * @ingroup lavu_data + * + * @brief Simple key:value store + * + * @{ + * Dictionaries are used for storing key:value pairs. To create + * an AVDictionary, simply pass an address of a NULL pointer to + * av_dict_set(). NULL can be used as an empty dictionary wherever + * a pointer to an AVDictionary is required. + * Use av_dict_get() to retrieve an entry or iterate over all + * entries and finally av_dict_free() to free the dictionary + * and all its contents. + * + @code + AVDictionary *d = NULL; // "create" an empty dictionary + AVDictionaryEntry *t = NULL; + + av_dict_set(&d, "foo", "bar", 0); // add an entry + + char *k = av_strdup("key"); // if your strings are already allocated, + char *v = av_strdup("value"); // you can avoid copying them like this + av_dict_set(&d, k, v, AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL); + + while (t = av_dict_get(d, "", t, AV_DICT_IGNORE_SUFFIX)) { + <....> // iterate over all entries in d + } + av_dict_free(&d); + @endcode + * + */ + +#define AV_DICT_MATCH_CASE 1 /**< Only get an entry with exact-case key match. Only relevant in av_dict_get(). */ +#define AV_DICT_IGNORE_SUFFIX 2 /**< Return first entry in a dictionary whose first part corresponds to the search key, + ignoring the suffix of the found key string. Only relevant in av_dict_get(). */ +#define AV_DICT_DONT_STRDUP_KEY 4 /**< Take ownership of a key that's been + allocated with av_malloc() or another memory allocation function. */ +#define AV_DICT_DONT_STRDUP_VAL 8 /**< Take ownership of a value that's been + allocated with av_malloc() or another memory allocation function. */ +#define AV_DICT_DONT_OVERWRITE 16 ///< Don't overwrite existing entries. +#define AV_DICT_APPEND 32 /**< If the entry already exists, append to it. Note that no + delimiter is added, the strings are simply concatenated. */ + +typedef struct AVDictionaryEntry { + char *key; + char *value; +} AVDictionaryEntry; + +typedef struct AVDictionary AVDictionary; + +/** + * Get a dictionary entry with matching key. + * + * The returned entry key or value must not be changed, or it will + * cause undefined behavior. + * + * To iterate through all the dictionary entries, you can set the matching key + * to the null string "" and set the AV_DICT_IGNORE_SUFFIX flag. + * + * @param prev Set to the previous matching element to find the next. + * If set to NULL the first matching element is returned. + * @param key matching key + * @param flags a collection of AV_DICT_* flags controlling how the entry is retrieved + * @return found entry or NULL in case no matching entry was found in the dictionary + */ +AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key, + const AVDictionaryEntry *prev, int flags); + +/** + * Get number of entries in dictionary. + * + * @param m dictionary + * @return number of entries in dictionary + */ +int av_dict_count(const AVDictionary *m); + +/** + * Set the given entry in *pm, overwriting an existing entry. + * + * Note: If AV_DICT_DONT_STRDUP_KEY or AV_DICT_DONT_STRDUP_VAL is set, + * these arguments will be freed on error. + * + * @param pm pointer to a pointer to a dictionary struct. If *pm is NULL + * a dictionary struct is allocated and put in *pm. + * @param key entry key to add to *pm (will be av_strduped depending on flags) + * @param value entry value to add to *pm (will be av_strduped depending on flags). + * Passing a NULL value will cause an existing entry to be deleted. + * @return >= 0 on success otherwise an error code <0 + */ +int av_dict_set(AVDictionary **pm, const char *key, const char *value, int flags); + +/** + * Convenience wrapper for av_dict_set that converts the value to a string + * and stores it. + * + * Note: If AV_DICT_DONT_STRDUP_KEY is set, key will be freed on error. + */ +int av_dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags); + +/** + * Parse the key/value pairs list and add the parsed entries to a dictionary. + * + * In case of failure, all the successfully set entries are stored in + * *pm. You may need to manually free the created dictionary. + * + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @param flags flags to use when adding to dictionary. + * AV_DICT_DONT_STRDUP_KEY and AV_DICT_DONT_STRDUP_VAL + * are ignored since the key/value tokens will always + * be duplicated. + * @return 0 on success, negative AVERROR code on failure + */ +int av_dict_parse_string(AVDictionary **pm, const char *str, + const char *key_val_sep, const char *pairs_sep, + int flags); + +/** + * Copy entries from one AVDictionary struct into another. + * @param dst pointer to a pointer to a AVDictionary struct. If *dst is NULL, + * this function will allocate a struct for you and put it in *dst + * @param src pointer to source AVDictionary struct + * @param flags flags to use when setting entries in *dst + * @note metadata is read using the AV_DICT_IGNORE_SUFFIX flag + * @return 0 on success, negative AVERROR code on failure. If dst was allocated + * by this function, callers should free the associated memory. + */ +int av_dict_copy(AVDictionary **dst, const AVDictionary *src, int flags); + +/** + * Free all the memory allocated for an AVDictionary struct + * and all keys and values. + */ +void av_dict_free(AVDictionary **m); + +/** + * Get dictionary entries as a string. + * + * Create a string containing dictionary's entries. + * Such string may be passed back to av_dict_parse_string(). + * @note String is escaped with backslashes ('\'). + * + * @param[in] m dictionary + * @param[out] buffer Pointer to buffer that will be allocated with string containg entries. + * Buffer must be freed by the caller when is no longer needed. + * @param[in] key_val_sep character used to separate key from value + * @param[in] pairs_sep character used to separate two pairs from each other + * @return >= 0 on success, negative on error + * @warning Separators cannot be neither '\\' nor '\0'. They also cannot be the same. + */ +int av_dict_get_string(const AVDictionary *m, char **buffer, + const char key_val_sep, const char pairs_sep); + +/** + * @} + */ + +#endif /* AVUTIL_DICT_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/display.h b/TMessagesProj/jni/ffmpeg/include/libavutil/display.h new file mode 100644 index 00000000..c0cfee32 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/display.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2014 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DISPLAY_H +#define AVUTIL_DISPLAY_H + +#include + +/** + * The display transformation matrix specifies an affine transformation that + * should be applied to video frames for correct presentation. It is compatible + * with the matrices stored in the ISO/IEC 14496-12 container format. + * + * The data is a 3x3 matrix represented as a 9-element array: + * + * | a b u | + * (a, b, u, c, d, v, x, y, w) -> | c d v | + * | x y w | + * + * All numbers are stored in native endianness, as 16.16 fixed-point values, + * except for u, v and w, which are stored as 2.30 fixed-point values. + * + * The transformation maps a point (p, q) in the source (pre-transformation) + * frame to the point (p', q') in the destination (post-transformation) frame as + * follows: + * | a b u | + * (p, q, 1) . | c d v | = z * (p', q', 1) + * | x y w | + * + * The transformation can also be more explicitly written in components as + * follows: + * p' = (a * p + c * q + x) / z; + * q' = (b * p + d * q + y) / z; + * z = u * p + v * q + w + */ + +/** + * Extract the rotation component of the transformation matrix. + * + * @param matrix the transformation matrix + * @return the angle (in degrees) by which the transformation rotates the frame + * counterclockwise. The angle will be in range [-180.0, 180.0], + * or NaN if the matrix is singular. + * + * @note floating point numbers are inherently inexact, so callers are + * recommended to round the return value to nearest integer before use. + */ +double av_display_rotation_get(const int32_t matrix[9]); + +/** + * Initialize a transformation matrix describing a pure counterclockwise + * rotation by the specified angle (in degrees). + * + * @param matrix an allocated transformation matrix (will be fully overwritten + * by this function) + * @param angle rotation angle in degrees. + */ +void av_display_rotation_set(int32_t matrix[9], double angle); + +/** + * Flip the input matrix horizontally and/or vertically. + * + * @param matrix an allocated transformation matrix + * @param hflip whether the matrix should be flipped horizontally + * @param vflip whether the matrix should be flipped vertically + */ +void av_display_matrix_flip(int32_t matrix[9], int hflip, int vflip); + +#endif /* AVUTIL_DISPLAY_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/downmix_info.h b/TMessagesProj/jni/ffmpeg/include/libavutil/downmix_info.h new file mode 100644 index 00000000..221cf5bf --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/downmix_info.h @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2014 Tim Walker + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_DOWNMIX_INFO_H +#define AVUTIL_DOWNMIX_INFO_H + +#include "frame.h" + +/** + * @file + * audio downmix medatata + */ + +/** + * @addtogroup lavu_audio + * @{ + */ + +/** + * @defgroup downmix_info Audio downmix metadata + * @{ + */ + +/** + * Possible downmix types. + */ +enum AVDownmixType { + AV_DOWNMIX_TYPE_UNKNOWN, /**< Not indicated. */ + AV_DOWNMIX_TYPE_LORO, /**< Lo/Ro 2-channel downmix (Stereo). */ + AV_DOWNMIX_TYPE_LTRT, /**< Lt/Rt 2-channel downmix, Dolby Surround compatible. */ + AV_DOWNMIX_TYPE_DPLII, /**< Lt/Rt 2-channel downmix, Dolby Pro Logic II compatible. */ + AV_DOWNMIX_TYPE_NB /**< Number of downmix types. Not part of ABI. */ +}; + +/** + * This structure describes optional metadata relevant to a downmix procedure. + * + * All fields are set by the decoder to the value indicated in the audio + * bitstream (if present), or to a "sane" default otherwise. + */ +typedef struct AVDownmixInfo { + /** + * Type of downmix preferred by the mastering engineer. + */ + enum AVDownmixType preferred_downmix_type; + + /** + * Absolute scale factor representing the nominal level of the center + * channel during a regular downmix. + */ + double center_mix_level; + + /** + * Absolute scale factor representing the nominal level of the center + * channel during an Lt/Rt compatible downmix. + */ + double center_mix_level_ltrt; + + /** + * Absolute scale factor representing the nominal level of the surround + * channels during a regular downmix. + */ + double surround_mix_level; + + /** + * Absolute scale factor representing the nominal level of the surround + * channels during an Lt/Rt compatible downmix. + */ + double surround_mix_level_ltrt; + + /** + * Absolute scale factor representing the level at which the LFE data is + * mixed into L/R channels during downmixing. + */ + double lfe_mix_level; +} AVDownmixInfo; + +/** + * Get a frame's AV_FRAME_DATA_DOWNMIX_INFO side data for editing. + * + * If the side data is absent, it is created and added to the frame. + * + * @param frame the frame for which the side data is to be obtained or created + * + * @return the AVDownmixInfo structure to be edited by the caller, or NULL if + * the structure cannot be allocated. + */ +AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame); + +/** + * @} + */ + +/** + * @} + */ + +#endif /* AVUTIL_DOWNMIX_INFO_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/error.h b/TMessagesProj/jni/ffmpeg/include/libavutil/error.h new file mode 100644 index 00000000..71df4da3 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/error.h @@ -0,0 +1,126 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * error code definitions + */ + +#ifndef AVUTIL_ERROR_H +#define AVUTIL_ERROR_H + +#include +#include + +/** + * @addtogroup lavu_error + * + * @{ + */ + + +/* error handling */ +#if EDOM > 0 +#define AVERROR(e) (-(e)) ///< Returns a negative error code from a POSIX error code, to return from library functions. +#define AVUNERROR(e) (-(e)) ///< Returns a POSIX error code from a library function error return value. +#else +/* Some platforms have E* and errno already negated. */ +#define AVERROR(e) (e) +#define AVUNERROR(e) (e) +#endif + +#define FFERRTAG(a, b, c, d) (-(int)MKTAG(a, b, c, d)) + +#define AVERROR_BSF_NOT_FOUND FFERRTAG(0xF8,'B','S','F') ///< Bitstream filter not found +#define AVERROR_BUG FFERRTAG( 'B','U','G','!') ///< Internal bug, also see AVERROR_BUG2 +#define AVERROR_BUFFER_TOO_SMALL FFERRTAG( 'B','U','F','S') ///< Buffer too small +#define AVERROR_DECODER_NOT_FOUND FFERRTAG(0xF8,'D','E','C') ///< Decoder not found +#define AVERROR_DEMUXER_NOT_FOUND FFERRTAG(0xF8,'D','E','M') ///< Demuxer not found +#define AVERROR_ENCODER_NOT_FOUND FFERRTAG(0xF8,'E','N','C') ///< Encoder not found +#define AVERROR_EOF FFERRTAG( 'E','O','F',' ') ///< End of file +#define AVERROR_EXIT FFERRTAG( 'E','X','I','T') ///< Immediate exit was requested; the called function should not be restarted +#define AVERROR_EXTERNAL FFERRTAG( 'E','X','T',' ') ///< Generic error in an external library +#define AVERROR_FILTER_NOT_FOUND FFERRTAG(0xF8,'F','I','L') ///< Filter not found +#define AVERROR_INVALIDDATA FFERRTAG( 'I','N','D','A') ///< Invalid data found when processing input +#define AVERROR_MUXER_NOT_FOUND FFERRTAG(0xF8,'M','U','X') ///< Muxer not found +#define AVERROR_OPTION_NOT_FOUND FFERRTAG(0xF8,'O','P','T') ///< Option not found +#define AVERROR_PATCHWELCOME FFERRTAG( 'P','A','W','E') ///< Not yet implemented in FFmpeg, patches welcome +#define AVERROR_PROTOCOL_NOT_FOUND FFERRTAG(0xF8,'P','R','O') ///< Protocol not found + +#define AVERROR_STREAM_NOT_FOUND FFERRTAG(0xF8,'S','T','R') ///< Stream not found +/** + * This is semantically identical to AVERROR_BUG + * it has been introduced in Libav after our AVERROR_BUG and with a modified value. + */ +#define AVERROR_BUG2 FFERRTAG( 'B','U','G',' ') +#define AVERROR_UNKNOWN FFERRTAG( 'U','N','K','N') ///< Unknown error, typically from an external library +#define AVERROR_EXPERIMENTAL (-0x2bb2afa8) ///< Requested feature is flagged experimental. Set strict_std_compliance if you really want to use it. +#define AVERROR_INPUT_CHANGED (-0x636e6701) ///< Input changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_OUTPUT_CHANGED) +#define AVERROR_OUTPUT_CHANGED (-0x636e6702) ///< Output changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_INPUT_CHANGED) +/* HTTP & RTSP errors */ +#define AVERROR_HTTP_BAD_REQUEST FFERRTAG(0xF8,'4','0','0') +#define AVERROR_HTTP_UNAUTHORIZED FFERRTAG(0xF8,'4','0','1') +#define AVERROR_HTTP_FORBIDDEN FFERRTAG(0xF8,'4','0','3') +#define AVERROR_HTTP_NOT_FOUND FFERRTAG(0xF8,'4','0','4') +#define AVERROR_HTTP_OTHER_4XX FFERRTAG(0xF8,'4','X','X') +#define AVERROR_HTTP_SERVER_ERROR FFERRTAG(0xF8,'5','X','X') + +#define AV_ERROR_MAX_STRING_SIZE 64 + +/** + * Put a description of the AVERROR code errnum in errbuf. + * In case of failure the global variable errno is set to indicate the + * error. Even in case of failure av_strerror() will print a generic + * error message indicating the errnum provided to errbuf. + * + * @param errnum error code to describe + * @param errbuf buffer to which description is written + * @param errbuf_size the size in bytes of errbuf + * @return 0 on success, a negative value if a description for errnum + * cannot be found + */ +int av_strerror(int errnum, char *errbuf, size_t errbuf_size); + +/** + * Fill the provided buffer with a string containing an error string + * corresponding to the AVERROR code errnum. + * + * @param errbuf a buffer + * @param errbuf_size size in bytes of errbuf + * @param errnum error code to describe + * @return the buffer in input, filled with the error description + * @see av_strerror() + */ +static inline char *av_make_error_string(char *errbuf, size_t errbuf_size, int errnum) +{ + av_strerror(errnum, errbuf, errbuf_size); + return errbuf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_err2str(errnum) \ + av_make_error_string((char[AV_ERROR_MAX_STRING_SIZE]){0}, AV_ERROR_MAX_STRING_SIZE, errnum) + +/** + * @} + */ + +#endif /* AVUTIL_ERROR_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/eval.h b/TMessagesProj/jni/ffmpeg/include/libavutil/eval.h new file mode 100644 index 00000000..dacd22b9 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/eval.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2002 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * simple arithmetic expression evaluator + */ + +#ifndef AVUTIL_EVAL_H +#define AVUTIL_EVAL_H + +#include "avutil.h" + +typedef struct AVExpr AVExpr; + +/** + * Parse and evaluate an expression. + * Note, this is significantly slower than av_expr_eval(). + * + * @param res a pointer to a double where is put the result value of + * the expression, or NAN in case of error + * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" + * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} + * @param const_values a zero terminated array of values for the identifiers from const_names + * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers + * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument + * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers + * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @param log_ctx parent logging context + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_expr_parse_and_eval(double *res, const char *s, + const char * const *const_names, const double *const_values, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + void *opaque, int log_offset, void *log_ctx); + +/** + * Parse an expression. + * + * @param expr a pointer where is put an AVExpr containing the parsed + * value in case of successful parsing, or NULL otherwise. + * The pointed to AVExpr must be freed with av_expr_free() by the user + * when it is not needed anymore. + * @param s expression as a zero terminated string, for example "1+2^3+5*5+sin(2/3)" + * @param const_names NULL terminated array of zero terminated strings of constant identifiers, for example {"PI", "E", 0} + * @param func1_names NULL terminated array of zero terminated strings of funcs1 identifiers + * @param funcs1 NULL terminated array of function pointers for functions which take 1 argument + * @param func2_names NULL terminated array of zero terminated strings of funcs2 identifiers + * @param funcs2 NULL terminated array of function pointers for functions which take 2 arguments + * @param log_ctx parent logging context + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_expr_parse(AVExpr **expr, const char *s, + const char * const *const_names, + const char * const *func1_names, double (* const *funcs1)(void *, double), + const char * const *func2_names, double (* const *funcs2)(void *, double, double), + int log_offset, void *log_ctx); + +/** + * Evaluate a previously parsed expression. + * + * @param const_values a zero terminated array of values for the identifiers from av_expr_parse() const_names + * @param opaque a pointer which will be passed to all functions from funcs1 and funcs2 + * @return the value of the expression + */ +double av_expr_eval(AVExpr *e, const double *const_values, void *opaque); + +/** + * Free a parsed expression previously created with av_expr_parse(). + */ +void av_expr_free(AVExpr *e); + +/** + * Parse the string in numstr and return its value as a double. If + * the string is empty, contains only whitespaces, or does not contain + * an initial substring that has the expected syntax for a + * floating-point number, no conversion is performed. In this case, + * returns a value of zero and the value returned in tail is the value + * of numstr. + * + * @param numstr a string representing a number, may contain one of + * the International System number postfixes, for example 'K', 'M', + * 'G'. If 'i' is appended after the postfix, powers of 2 are used + * instead of powers of 10. The 'B' postfix multiplies the value by + * 8, and can be appended after another postfix or used alone. This + * allows using for example 'KB', 'MiB', 'G' and 'B' as postfix. + * @param tail if non-NULL puts here the pointer to the char next + * after the last parsed character + */ +double av_strtod(const char *numstr, char **tail); + +#endif /* AVUTIL_EVAL_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/ffversion.h b/TMessagesProj/jni/ffmpeg/include/libavutil/ffversion.h new file mode 100644 index 00000000..e8448981 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/ffversion.h @@ -0,0 +1,5 @@ +/* Automatically generated by version.sh, do not manually edit! */ +#ifndef AVUTIL_FFVERSION_H +#define AVUTIL_FFVERSION_H +#define FFMPEG_VERSION "2.8.git" +#endif /* AVUTIL_FFVERSION_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/fifo.h b/TMessagesProj/jni/ffmpeg/include/libavutil/fifo.h new file mode 100644 index 00000000..dc7bc6f0 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/fifo.h @@ -0,0 +1,179 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * a very simple circular buffer FIFO implementation + */ + +#ifndef AVUTIL_FIFO_H +#define AVUTIL_FIFO_H + +#include +#include "avutil.h" +#include "attributes.h" + +typedef struct AVFifoBuffer { + uint8_t *buffer; + uint8_t *rptr, *wptr, *end; + uint32_t rndx, wndx; +} AVFifoBuffer; + +/** + * Initialize an AVFifoBuffer. + * @param size of FIFO + * @return AVFifoBuffer or NULL in case of memory allocation failure + */ +AVFifoBuffer *av_fifo_alloc(unsigned int size); + +/** + * Initialize an AVFifoBuffer. + * @param nmemb number of elements + * @param size size of the single element + * @return AVFifoBuffer or NULL in case of memory allocation failure + */ +AVFifoBuffer *av_fifo_alloc_array(size_t nmemb, size_t size); + +/** + * Free an AVFifoBuffer. + * @param f AVFifoBuffer to free + */ +void av_fifo_free(AVFifoBuffer *f); + +/** + * Free an AVFifoBuffer and reset pointer to NULL. + * @param f AVFifoBuffer to free + */ +void av_fifo_freep(AVFifoBuffer **f); + +/** + * Reset the AVFifoBuffer to the state right after av_fifo_alloc, in particular it is emptied. + * @param f AVFifoBuffer to reset + */ +void av_fifo_reset(AVFifoBuffer *f); + +/** + * Return the amount of data in bytes in the AVFifoBuffer, that is the + * amount of data you can read from it. + * @param f AVFifoBuffer to read from + * @return size + */ +int av_fifo_size(const AVFifoBuffer *f); + +/** + * Return the amount of space in bytes in the AVFifoBuffer, that is the + * amount of data you can write into it. + * @param f AVFifoBuffer to write into + * @return size + */ +int av_fifo_space(const AVFifoBuffer *f); + +/** + * Feed data at specific position from an AVFifoBuffer to a user-supplied callback. + * Similar as av_fifo_gereric_read but without discarding data. + * @param f AVFifoBuffer to read from + * @param offset offset from current read position + * @param buf_size number of bytes to read + * @param func generic read function + * @param dest data destination + */ +int av_fifo_generic_peek_at(AVFifoBuffer *f, void *dest, int offset, int buf_size, void (*func)(void*, void*, int)); + +/** + * Feed data from an AVFifoBuffer to a user-supplied callback. + * Similar as av_fifo_gereric_read but without discarding data. + * @param f AVFifoBuffer to read from + * @param buf_size number of bytes to read + * @param func generic read function + * @param dest data destination + */ +int av_fifo_generic_peek(AVFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int)); + +/** + * Feed data from an AVFifoBuffer to a user-supplied callback. + * @param f AVFifoBuffer to read from + * @param buf_size number of bytes to read + * @param func generic read function + * @param dest data destination + */ +int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, void (*func)(void*, void*, int)); + +/** + * Feed data from a user-supplied callback to an AVFifoBuffer. + * @param f AVFifoBuffer to write to + * @param src data source; non-const since it may be used as a + * modifiable context by the function defined in func + * @param size number of bytes to write + * @param func generic write function; the first parameter is src, + * the second is dest_buf, the third is dest_buf_size. + * func must return the number of bytes written to dest_buf, or <= 0 to + * indicate no more data available to write. + * If func is NULL, src is interpreted as a simple byte array for source data. + * @return the number of bytes written to the FIFO + */ +int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, int (*func)(void*, void*, int)); + +/** + * Resize an AVFifoBuffer. + * In case of reallocation failure, the old FIFO is kept unchanged. + * + * @param f AVFifoBuffer to resize + * @param size new AVFifoBuffer size in bytes + * @return <0 for failure, >=0 otherwise + */ +int av_fifo_realloc2(AVFifoBuffer *f, unsigned int size); + +/** + * Enlarge an AVFifoBuffer. + * In case of reallocation failure, the old FIFO is kept unchanged. + * The new fifo size may be larger than the requested size. + * + * @param f AVFifoBuffer to resize + * @param additional_space the amount of space in bytes to allocate in addition to av_fifo_size() + * @return <0 for failure, >=0 otherwise + */ +int av_fifo_grow(AVFifoBuffer *f, unsigned int additional_space); + +/** + * Read and discard the specified amount of data from an AVFifoBuffer. + * @param f AVFifoBuffer to read from + * @param size amount of data to read in bytes + */ +void av_fifo_drain(AVFifoBuffer *f, int size); + +/** + * Return a pointer to the data stored in a FIFO buffer at a certain offset. + * The FIFO buffer is not modified. + * + * @param f AVFifoBuffer to peek at, f must be non-NULL + * @param offs an offset in bytes, its absolute value must be less + * than the used buffer size or the returned pointer will + * point outside to the buffer data. + * The used buffer size can be checked with av_fifo_size(). + */ +static inline uint8_t *av_fifo_peek2(const AVFifoBuffer *f, int offs) +{ + uint8_t *ptr = f->rptr + offs; + if (ptr >= f->end) + ptr = f->buffer + (ptr - f->end); + else if (ptr < f->buffer) + ptr = f->end - (f->buffer - ptr); + return ptr; +} + +#endif /* AVUTIL_FIFO_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/file.h b/TMessagesProj/jni/ffmpeg/include/libavutil/file.h new file mode 100644 index 00000000..e931be71 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/file.h @@ -0,0 +1,68 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_FILE_H +#define AVUTIL_FILE_H + +#include + +#include "avutil.h" + +/** + * @file + * Misc file utilities. + */ + +/** + * Read the file with name filename, and put its content in a newly + * allocated buffer or map it with mmap() when available. + * In case of success set *bufptr to the read or mmapped buffer, and + * *size to the size in bytes of the buffer in *bufptr. + * The returned buffer must be released with av_file_unmap(). + * + * @param log_offset loglevel offset used for logging + * @param log_ctx context used for logging + * @return a non negative number in case of success, a negative value + * corresponding to an AVERROR error code in case of failure + */ +av_warn_unused_result +int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, + int log_offset, void *log_ctx); + +/** + * Unmap or free the buffer bufptr created by av_file_map(). + * + * @param size size in bytes of bufptr, must be the same as returned + * by av_file_map() + */ +void av_file_unmap(uint8_t *bufptr, size_t size); + +/** + * Wrapper to work around the lack of mkstemp() on mingw. + * Also, tries to create file in /tmp first, if possible. + * *prefix can be a character constant; *filename will be allocated internally. + * @return file descriptor of opened file (or negative value corresponding to an + * AVERROR code on error) + * and opened file name in **filename. + * @note On very old libcs it is necessary to set a secure umask before + * calling this, av_tempfile() can't call umask itself as it is used in + * libraries and could interfere with the calling application. + */ +int av_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx); + +#endif /* AVUTIL_FILE_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/frame.h b/TMessagesProj/jni/ffmpeg/include/libavutil/frame.h new file mode 100644 index 00000000..9c6061a1 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/frame.h @@ -0,0 +1,713 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu_frame + * reference-counted frame API + */ + +#ifndef AVUTIL_FRAME_H +#define AVUTIL_FRAME_H + +#include + +#include "avutil.h" +#include "buffer.h" +#include "dict.h" +#include "rational.h" +#include "samplefmt.h" +#include "pixfmt.h" +#include "version.h" + + +/** + * @defgroup lavu_frame AVFrame + * @ingroup lavu_data + * + * @{ + * AVFrame is an abstraction for reference-counted raw multimedia data. + */ + +enum AVFrameSideDataType { + /** + * The data is the AVPanScan struct defined in libavcodec. + */ + AV_FRAME_DATA_PANSCAN, + /** + * ATSC A53 Part 4 Closed Captions. + * A53 CC bitstream is stored as uint8_t in AVFrameSideData.data. + * The number of bytes of CC data is AVFrameSideData.size. + */ + AV_FRAME_DATA_A53_CC, + /** + * Stereoscopic 3d metadata. + * The data is the AVStereo3D struct defined in libavutil/stereo3d.h. + */ + AV_FRAME_DATA_STEREO3D, + /** + * The data is the AVMatrixEncoding enum defined in libavutil/channel_layout.h. + */ + AV_FRAME_DATA_MATRIXENCODING, + /** + * Metadata relevant to a downmix procedure. + * The data is the AVDownmixInfo struct defined in libavutil/downmix_info.h. + */ + AV_FRAME_DATA_DOWNMIX_INFO, + /** + * ReplayGain information in the form of the AVReplayGain struct. + */ + AV_FRAME_DATA_REPLAYGAIN, + /** + * This side data contains a 3x3 transformation matrix describing an affine + * transformation that needs to be applied to the frame for correct + * presentation. + * + * See libavutil/display.h for a detailed description of the data. + */ + AV_FRAME_DATA_DISPLAYMATRIX, + /** + * Active Format Description data consisting of a single byte as specified + * in ETSI TS 101 154 using AVActiveFormatDescription enum. + */ + AV_FRAME_DATA_AFD, + /** + * Motion vectors exported by some codecs (on demand through the export_mvs + * flag set in the libavcodec AVCodecContext flags2 option). + * The data is the AVMotionVector struct defined in + * libavutil/motion_vector.h. + */ + AV_FRAME_DATA_MOTION_VECTORS, + /** + * Recommmends skipping the specified number of samples. This is exported + * only if the "skip_manual" AVOption is set in libavcodec. + * This has the same format as AV_PKT_DATA_SKIP_SAMPLES. + * @code + * u32le number of samples to skip from start of this packet + * u32le number of samples to skip from end of this packet + * u8 reason for start skip + * u8 reason for end skip (0=padding silence, 1=convergence) + * @endcode + */ + AV_FRAME_DATA_SKIP_SAMPLES, + + /** + * This side data must be associated with an audio frame and corresponds to + * enum AVAudioServiceType defined in avcodec.h. + */ + AV_FRAME_DATA_AUDIO_SERVICE_TYPE, +}; + +enum AVActiveFormatDescription { + AV_AFD_SAME = 8, + AV_AFD_4_3 = 9, + AV_AFD_16_9 = 10, + AV_AFD_14_9 = 11, + AV_AFD_4_3_SP_14_9 = 13, + AV_AFD_16_9_SP_14_9 = 14, + AV_AFD_SP_4_3 = 15, +}; + + +/** + * Structure to hold side data for an AVFrame. + * + * sizeof(AVFrameSideData) is not a part of the public ABI, so new fields may be added + * to the end with a minor bump. + */ +typedef struct AVFrameSideData { + enum AVFrameSideDataType type; + uint8_t *data; + int size; + AVDictionary *metadata; + AVBufferRef *buf; +} AVFrameSideData; + +/** + * This structure describes decoded (raw) audio or video data. + * + * AVFrame must be allocated using av_frame_alloc(). Note that this only + * allocates the AVFrame itself, the buffers for the data must be managed + * through other means (see below). + * AVFrame must be freed with av_frame_free(). + * + * AVFrame is typically allocated once and then reused multiple times to hold + * different data (e.g. a single AVFrame to hold frames received from a + * decoder). In such a case, av_frame_unref() will free any references held by + * the frame and reset it to its original clean state before it + * is reused again. + * + * The data described by an AVFrame is usually reference counted through the + * AVBuffer API. The underlying buffer references are stored in AVFrame.buf / + * AVFrame.extended_buf. An AVFrame is considered to be reference counted if at + * least one reference is set, i.e. if AVFrame.buf[0] != NULL. In such a case, + * every single data plane must be contained in one of the buffers in + * AVFrame.buf or AVFrame.extended_buf. + * There may be a single buffer for all the data, or one separate buffer for + * each plane, or anything in between. + * + * sizeof(AVFrame) is not a part of the public ABI, so new fields may be added + * to the end with a minor bump. + * Similarly fields that are marked as to be only accessed by + * av_opt_ptr() can be reordered. This allows 2 forks to add fields + * without breaking compatibility with each other. + */ +typedef struct AVFrame { +#define AV_NUM_DATA_POINTERS 8 + /** + * pointer to the picture/channel planes. + * This might be different from the first allocated byte + * + * Some decoders access areas outside 0,0 - width,height, please + * see avcodec_align_dimensions2(). Some filters and swscale can read + * up to 16 bytes beyond the planes, if these filters are to be used, + * then 16 extra bytes must be allocated. + */ + uint8_t *data[AV_NUM_DATA_POINTERS]; + + /** + * For video, size in bytes of each picture line. + * For audio, size in bytes of each plane. + * + * For audio, only linesize[0] may be set. For planar audio, each channel + * plane must be the same size. + * + * For video the linesizes should be multiples of the CPUs alignment + * preference, this is 16 or 32 for modern desktop CPUs. + * Some code requires such alignment other code can be slower without + * correct alignment, for yet other it makes no difference. + * + * @note The linesize may be larger than the size of usable data -- there + * may be extra padding present for performance reasons. + */ + int linesize[AV_NUM_DATA_POINTERS]; + + /** + * pointers to the data planes/channels. + * + * For video, this should simply point to data[]. + * + * For planar audio, each channel has a separate data pointer, and + * linesize[0] contains the size of each channel buffer. + * For packed audio, there is just one data pointer, and linesize[0] + * contains the total size of the buffer for all channels. + * + * Note: Both data and extended_data should always be set in a valid frame, + * but for planar audio with more channels that can fit in data, + * extended_data must be used in order to access all channels. + */ + uint8_t **extended_data; + + /** + * width and height of the video frame + */ + int width, height; + + /** + * number of audio samples (per channel) described by this frame + */ + int nb_samples; + + /** + * format of the frame, -1 if unknown or unset + * Values correspond to enum AVPixelFormat for video frames, + * enum AVSampleFormat for audio) + */ + int format; + + /** + * 1 -> keyframe, 0-> not + */ + int key_frame; + + /** + * Picture type of the frame. + */ + enum AVPictureType pict_type; + + /** + * Sample aspect ratio for the video frame, 0/1 if unknown/unspecified. + */ + AVRational sample_aspect_ratio; + + /** + * Presentation timestamp in time_base units (time when frame should be shown to user). + */ + int64_t pts; + + /** + * PTS copied from the AVPacket that was decoded to produce this frame. + */ + int64_t pkt_pts; + + /** + * DTS copied from the AVPacket that triggered returning this frame. (if frame threading isn't used) + * This is also the Presentation time of this AVFrame calculated from + * only AVPacket.dts values without pts values. + */ + int64_t pkt_dts; + + /** + * picture number in bitstream order + */ + int coded_picture_number; + /** + * picture number in display order + */ + int display_picture_number; + + /** + * quality (between 1 (good) and FF_LAMBDA_MAX (bad)) + */ + int quality; + + /** + * for some private data of the user + */ + void *opaque; + +#if FF_API_ERROR_FRAME + /** + * @deprecated unused + */ + attribute_deprecated + uint64_t error[AV_NUM_DATA_POINTERS]; +#endif + + /** + * When decoding, this signals how much the picture must be delayed. + * extra_delay = repeat_pict / (2*fps) + */ + int repeat_pict; + + /** + * The content of the picture is interlaced. + */ + int interlaced_frame; + + /** + * If the content is interlaced, is top field displayed first. + */ + int top_field_first; + + /** + * Tell user application that palette has changed from previous frame. + */ + int palette_has_changed; + + /** + * reordered opaque 64bit (generally an integer or a double precision float + * PTS but can be anything). + * The user sets AVCodecContext.reordered_opaque to represent the input at + * that time, + * the decoder reorders values as needed and sets AVFrame.reordered_opaque + * to exactly one of the values provided by the user through AVCodecContext.reordered_opaque + * @deprecated in favor of pkt_pts + */ + int64_t reordered_opaque; + + /** + * Sample rate of the audio data. + */ + int sample_rate; + + /** + * Channel layout of the audio data. + */ + uint64_t channel_layout; + + /** + * AVBuffer references backing the data for this frame. If all elements of + * this array are NULL, then this frame is not reference counted. This array + * must be filled contiguously -- if buf[i] is non-NULL then buf[j] must + * also be non-NULL for all j < i. + * + * There may be at most one AVBuffer per data plane, so for video this array + * always contains all the references. For planar audio with more than + * AV_NUM_DATA_POINTERS channels, there may be more buffers than can fit in + * this array. Then the extra AVBufferRef pointers are stored in the + * extended_buf array. + */ + AVBufferRef *buf[AV_NUM_DATA_POINTERS]; + + /** + * For planar audio which requires more than AV_NUM_DATA_POINTERS + * AVBufferRef pointers, this array will hold all the references which + * cannot fit into AVFrame.buf. + * + * Note that this is different from AVFrame.extended_data, which always + * contains all the pointers. This array only contains the extra pointers, + * which cannot fit into AVFrame.buf. + * + * This array is always allocated using av_malloc() by whoever constructs + * the frame. It is freed in av_frame_unref(). + */ + AVBufferRef **extended_buf; + /** + * Number of elements in extended_buf. + */ + int nb_extended_buf; + + AVFrameSideData **side_data; + int nb_side_data; + +/** + * @defgroup lavu_frame_flags AV_FRAME_FLAGS + * Flags describing additional frame properties. + * + * @{ + */ + +/** + * The frame data may be corrupted, e.g. due to decoding errors. + */ +#define AV_FRAME_FLAG_CORRUPT (1 << 0) +/** + * @} + */ + + /** + * Frame flags, a combination of @ref lavu_frame_flags + */ + int flags; + + /** + * MPEG vs JPEG YUV range. + * It must be accessed using av_frame_get_color_range() and + * av_frame_set_color_range(). + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorRange color_range; + + enum AVColorPrimaries color_primaries; + + enum AVColorTransferCharacteristic color_trc; + + /** + * YUV colorspace type. + * It must be accessed using av_frame_get_colorspace() and + * av_frame_set_colorspace(). + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorSpace colorspace; + + enum AVChromaLocation chroma_location; + + /** + * frame timestamp estimated using various heuristics, in stream time base + * Code outside libavutil should access this field using: + * av_frame_get_best_effort_timestamp(frame) + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int64_t best_effort_timestamp; + + /** + * reordered pos from the last AVPacket that has been input into the decoder + * Code outside libavutil should access this field using: + * av_frame_get_pkt_pos(frame) + * - encoding: unused + * - decoding: Read by user. + */ + int64_t pkt_pos; + + /** + * duration of the corresponding packet, expressed in + * AVStream->time_base units, 0 if unknown. + * Code outside libavutil should access this field using: + * av_frame_get_pkt_duration(frame) + * - encoding: unused + * - decoding: Read by user. + */ + int64_t pkt_duration; + + /** + * metadata. + * Code outside libavutil should access this field using: + * av_frame_get_metadata(frame) + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + AVDictionary *metadata; + + /** + * decode error flags of the frame, set to a combination of + * FF_DECODE_ERROR_xxx flags if the decoder produced a frame, but there + * were errors during the decoding. + * Code outside libavutil should access this field using: + * av_frame_get_decode_error_flags(frame) + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int decode_error_flags; +#define FF_DECODE_ERROR_INVALID_BITSTREAM 1 +#define FF_DECODE_ERROR_MISSING_REFERENCE 2 + + /** + * number of audio channels, only used for audio. + * Code outside libavutil should access this field using: + * av_frame_get_channels(frame) + * - encoding: unused + * - decoding: Read by user. + */ + int channels; + + /** + * size of the corresponding packet containing the compressed + * frame. It must be accessed using av_frame_get_pkt_size() and + * av_frame_set_pkt_size(). + * It is set to a negative value if unknown. + * - encoding: unused + * - decoding: set by libavcodec, read by user. + */ + int pkt_size; + +#if FF_API_FRAME_QP + /** + * QP table + * Not to be accessed directly from outside libavutil + */ + attribute_deprecated + int8_t *qscale_table; + /** + * QP store stride + * Not to be accessed directly from outside libavutil + */ + attribute_deprecated + int qstride; + + attribute_deprecated + int qscale_type; + + /** + * Not to be accessed directly from outside libavutil + */ + AVBufferRef *qp_table_buf; +#endif +} AVFrame; + +/** + * Accessors for some AVFrame fields. + * The position of these field in the structure is not part of the ABI, + * they should not be accessed directly outside libavutil. + */ +int64_t av_frame_get_best_effort_timestamp(const AVFrame *frame); +void av_frame_set_best_effort_timestamp(AVFrame *frame, int64_t val); +int64_t av_frame_get_pkt_duration (const AVFrame *frame); +void av_frame_set_pkt_duration (AVFrame *frame, int64_t val); +int64_t av_frame_get_pkt_pos (const AVFrame *frame); +void av_frame_set_pkt_pos (AVFrame *frame, int64_t val); +int64_t av_frame_get_channel_layout (const AVFrame *frame); +void av_frame_set_channel_layout (AVFrame *frame, int64_t val); +int av_frame_get_channels (const AVFrame *frame); +void av_frame_set_channels (AVFrame *frame, int val); +int av_frame_get_sample_rate (const AVFrame *frame); +void av_frame_set_sample_rate (AVFrame *frame, int val); +AVDictionary *av_frame_get_metadata (const AVFrame *frame); +void av_frame_set_metadata (AVFrame *frame, AVDictionary *val); +int av_frame_get_decode_error_flags (const AVFrame *frame); +void av_frame_set_decode_error_flags (AVFrame *frame, int val); +int av_frame_get_pkt_size(const AVFrame *frame); +void av_frame_set_pkt_size(AVFrame *frame, int val); +AVDictionary **avpriv_frame_get_metadatap(AVFrame *frame); +#if FF_API_FRAME_QP +int8_t *av_frame_get_qp_table(AVFrame *f, int *stride, int *type); +int av_frame_set_qp_table(AVFrame *f, AVBufferRef *buf, int stride, int type); +#endif +enum AVColorSpace av_frame_get_colorspace(const AVFrame *frame); +void av_frame_set_colorspace(AVFrame *frame, enum AVColorSpace val); +enum AVColorRange av_frame_get_color_range(const AVFrame *frame); +void av_frame_set_color_range(AVFrame *frame, enum AVColorRange val); + +/** + * Get the name of a colorspace. + * @return a static string identifying the colorspace; can be NULL. + */ +const char *av_get_colorspace_name(enum AVColorSpace val); + +/** + * Allocate an AVFrame and set its fields to default values. The resulting + * struct must be freed using av_frame_free(). + * + * @return An AVFrame filled with default values or NULL on failure. + * + * @note this only allocates the AVFrame itself, not the data buffers. Those + * must be allocated through other means, e.g. with av_frame_get_buffer() or + * manually. + */ +AVFrame *av_frame_alloc(void); + +/** + * Free the frame and any dynamically allocated objects in it, + * e.g. extended_data. If the frame is reference counted, it will be + * unreferenced first. + * + * @param frame frame to be freed. The pointer will be set to NULL. + */ +void av_frame_free(AVFrame **frame); + +/** + * Set up a new reference to the data described by the source frame. + * + * Copy frame properties from src to dst and create a new reference for each + * AVBufferRef from src. + * + * If src is not reference counted, new buffers are allocated and the data is + * copied. + * + * @return 0 on success, a negative AVERROR on error + */ +int av_frame_ref(AVFrame *dst, const AVFrame *src); + +/** + * Create a new frame that references the same data as src. + * + * This is a shortcut for av_frame_alloc()+av_frame_ref(). + * + * @return newly created AVFrame on success, NULL on error. + */ +AVFrame *av_frame_clone(const AVFrame *src); + +/** + * Unreference all the buffers referenced by frame and reset the frame fields. + */ +void av_frame_unref(AVFrame *frame); + +/** + * Move everything contained in src to dst and reset src. + */ +void av_frame_move_ref(AVFrame *dst, AVFrame *src); + +/** + * Allocate new buffer(s) for audio or video data. + * + * The following fields must be set on frame before calling this function: + * - format (pixel format for video, sample format for audio) + * - width and height for video + * - nb_samples and channel_layout for audio + * + * This function will fill AVFrame.data and AVFrame.buf arrays and, if + * necessary, allocate and fill AVFrame.extended_data and AVFrame.extended_buf. + * For planar formats, one buffer will be allocated for each plane. + * + * @param frame frame in which to store the new buffers. + * @param align required buffer size alignment + * + * @return 0 on success, a negative AVERROR on error. + */ +int av_frame_get_buffer(AVFrame *frame, int align); + +/** + * Check if the frame data is writable. + * + * @return A positive value if the frame data is writable (which is true if and + * only if each of the underlying buffers has only one reference, namely the one + * stored in this frame). Return 0 otherwise. + * + * If 1 is returned the answer is valid until av_buffer_ref() is called on any + * of the underlying AVBufferRefs (e.g. through av_frame_ref() or directly). + * + * @see av_frame_make_writable(), av_buffer_is_writable() + */ +int av_frame_is_writable(AVFrame *frame); + +/** + * Ensure that the frame data is writable, avoiding data copy if possible. + * + * Do nothing if the frame is writable, allocate new buffers and copy the data + * if it is not. + * + * @return 0 on success, a negative AVERROR on error. + * + * @see av_frame_is_writable(), av_buffer_is_writable(), + * av_buffer_make_writable() + */ +int av_frame_make_writable(AVFrame *frame); + +/** + * Copy the frame data from src to dst. + * + * This function does not allocate anything, dst must be already initialized and + * allocated with the same parameters as src. + * + * This function only copies the frame data (i.e. the contents of the data / + * extended data arrays), not any other properties. + * + * @return >= 0 on success, a negative AVERROR on error. + */ +int av_frame_copy(AVFrame *dst, const AVFrame *src); + +/** + * Copy only "metadata" fields from src to dst. + * + * Metadata for the purpose of this function are those fields that do not affect + * the data layout in the buffers. E.g. pts, sample rate (for audio) or sample + * aspect ratio (for video), but not width/height or channel layout. + * Side data is also copied. + */ +int av_frame_copy_props(AVFrame *dst, const AVFrame *src); + +/** + * Get the buffer reference a given data plane is stored in. + * + * @param plane index of the data plane of interest in frame->extended_data. + * + * @return the buffer reference that contains the plane or NULL if the input + * frame is not valid. + */ +AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane); + +/** + * Add a new side data to a frame. + * + * @param frame a frame to which the side data should be added + * @param type type of the added side data + * @param size size of the side data + * + * @return newly added side data on success, NULL on error + */ +AVFrameSideData *av_frame_new_side_data(AVFrame *frame, + enum AVFrameSideDataType type, + int size); + +/** + * @return a pointer to the side data of a given type on success, NULL if there + * is no side data with such type in this frame. + */ +AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, + enum AVFrameSideDataType type); + +/** + * If side data of the supplied type exists in the frame, free it and remove it + * from the frame. + */ +void av_frame_remove_side_data(AVFrame *frame, enum AVFrameSideDataType type); + +/** + * @return a string identifying the side data type + */ +const char *av_frame_side_data_name(enum AVFrameSideDataType type); + +/** + * @} + */ + +#endif /* AVUTIL_FRAME_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/hash.h b/TMessagesProj/jni/ffmpeg/include/libavutil/hash.h new file mode 100644 index 00000000..d4bcbf8c --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/hash.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2013 Reimar Döffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HASH_H +#define AVUTIL_HASH_H + +#include + +struct AVHashContext; + +/** + * Allocate a hash context for the algorithm specified by name. + * + * @return >= 0 for success, a negative error code for failure + * @note The context is not initialized, you must call av_hash_init(). + */ +int av_hash_alloc(struct AVHashContext **ctx, const char *name); + +/** + * Get the names of available hash algorithms. + * + * This function can be used to enumerate the algorithms. + * + * @param i index of the hash algorithm, starting from 0 + * @return a pointer to a static string or NULL if i is out of range + */ +const char *av_hash_names(int i); + +/** + * Get the name of the algorithm corresponding to the given hash context. + */ +const char *av_hash_get_name(const struct AVHashContext *ctx); + +/** + * Maximum value that av_hash_get_size will currently return. + * + * You can use this if you absolutely want or need to use static allocation + * and are fine with not supporting hashes newly added to libavutil without + * recompilation. + * Note that you still need to check against av_hash_get_size, adding new hashes + * with larger sizes will not be considered an ABI change and should not cause + * your code to overflow a buffer. + */ +#define AV_HASH_MAX_SIZE 64 + +/** + * Get the size of the resulting hash value in bytes. + * + * The pointer passed to av_hash_final have space for at least this many bytes. + */ +int av_hash_get_size(const struct AVHashContext *ctx); + +/** + * Initialize or reset a hash context. + */ +void av_hash_init(struct AVHashContext *ctx); + +/** + * Update a hash context with additional data. + */ +void av_hash_update(struct AVHashContext *ctx, const uint8_t *src, int len); + +/** + * Finalize a hash context and compute the actual hash value. + */ +void av_hash_final(struct AVHashContext *ctx, uint8_t *dst); + +/** + * Finalize a hash context and compute the actual hash value. + * If size is smaller than the hash size, the hash is truncated; + * if size is larger, the buffer is padded with 0. + */ +void av_hash_final_bin(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Finalize a hash context and compute the actual hash value as a hex string. + * The string is always 0-terminated. + * If size is smaller than 2 * hash_size + 1, the hex string is truncated. + */ +void av_hash_final_hex(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Finalize a hash context and compute the actual hash value as a base64 string. + * The string is always 0-terminated. + * If size is smaller than AV_BASE64_SIZE(hash_size), the base64 string is + * truncated. + */ +void av_hash_final_b64(struct AVHashContext *ctx, uint8_t *dst, int size); + +/** + * Free hash context. + */ +void av_hash_freep(struct AVHashContext **ctx); + +#endif /* AVUTIL_HASH_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/hmac.h b/TMessagesProj/jni/ffmpeg/include/libavutil/hmac.h new file mode 100644 index 00000000..576a0a4f --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/hmac.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2012 Martin Storsjo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HMAC_H +#define AVUTIL_HMAC_H + +#include + +#include "version.h" +/** + * @defgroup lavu_hmac HMAC + * @ingroup lavu_crypto + * @{ + */ + +enum AVHMACType { + AV_HMAC_MD5, + AV_HMAC_SHA1, + AV_HMAC_SHA224, + AV_HMAC_SHA256, + AV_HMAC_SHA384 = 12, + AV_HMAC_SHA512, +}; + +typedef struct AVHMAC AVHMAC; + +/** + * Allocate an AVHMAC context. + * @param type The hash function used for the HMAC. + */ +AVHMAC *av_hmac_alloc(enum AVHMACType type); + +/** + * Free an AVHMAC context. + * @param ctx The context to free, may be NULL + */ +void av_hmac_free(AVHMAC *ctx); + +/** + * Initialize an AVHMAC context with an authentication key. + * @param ctx The HMAC context + * @param key The authentication key + * @param keylen The length of the key, in bytes + */ +void av_hmac_init(AVHMAC *ctx, const uint8_t *key, unsigned int keylen); + +/** + * Hash data with the HMAC. + * @param ctx The HMAC context + * @param data The data to hash + * @param len The length of the data, in bytes + */ +void av_hmac_update(AVHMAC *ctx, const uint8_t *data, unsigned int len); + +/** + * Finish hashing and output the HMAC digest. + * @param ctx The HMAC context + * @param out The output buffer to write the digest into + * @param outlen The length of the out buffer, in bytes + * @return The number of bytes written to out, or a negative error code. + */ +int av_hmac_final(AVHMAC *ctx, uint8_t *out, unsigned int outlen); + +/** + * Hash an array of data with a key. + * @param ctx The HMAC context + * @param data The data to hash + * @param len The length of the data, in bytes + * @param key The authentication key + * @param keylen The length of the key, in bytes + * @param out The output buffer to write the digest into + * @param outlen The length of the out buffer, in bytes + * @return The number of bytes written to out, or a negative error code. + */ +int av_hmac_calc(AVHMAC *ctx, const uint8_t *data, unsigned int len, + const uint8_t *key, unsigned int keylen, + uint8_t *out, unsigned int outlen); + +/** + * @} + */ + +#endif /* AVUTIL_HMAC_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/imgutils.h b/TMessagesProj/jni/ffmpeg/include/libavutil/imgutils.h new file mode 100644 index 00000000..23282a38 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/imgutils.h @@ -0,0 +1,213 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_IMGUTILS_H +#define AVUTIL_IMGUTILS_H + +/** + * @file + * misc image utilities + * + * @addtogroup lavu_picture + * @{ + */ + +#include "avutil.h" +#include "pixdesc.h" +#include "rational.h" + +/** + * Compute the max pixel step for each plane of an image with a + * format described by pixdesc. + * + * The pixel step is the distance in bytes between the first byte of + * the group of bytes which describe a pixel component and the first + * byte of the successive group in the same plane for the same + * component. + * + * @param max_pixsteps an array which is filled with the max pixel step + * for each plane. Since a plane may contain different pixel + * components, the computed max_pixsteps[plane] is relative to the + * component in the plane with the max pixel step. + * @param max_pixstep_comps an array which is filled with the component + * for each plane which has the max pixel step. May be NULL. + */ +void av_image_fill_max_pixsteps(int max_pixsteps[4], int max_pixstep_comps[4], + const AVPixFmtDescriptor *pixdesc); + +/** + * Compute the size of an image line with format pix_fmt and width + * width for the plane plane. + * + * @return the computed size in bytes + */ +int av_image_get_linesize(enum AVPixelFormat pix_fmt, int width, int plane); + +/** + * Fill plane linesizes for an image with pixel format pix_fmt and + * width width. + * + * @param linesizes array to be filled with the linesize for each plane + * @return >= 0 in case of success, a negative error code otherwise + */ +int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width); + +/** + * Fill plane data pointers for an image with pixel format pix_fmt and + * height height. + * + * @param data pointers array to be filled with the pointer for each image plane + * @param ptr the pointer to a buffer which will contain the image + * @param linesizes the array containing the linesize for each + * plane, should be filled by av_image_fill_linesizes() + * @return the size in bytes required for the image buffer, a negative + * error code in case of failure + */ +int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int height, + uint8_t *ptr, const int linesizes[4]); + +/** + * Allocate an image with size w and h and pixel format pix_fmt, and + * fill pointers and linesizes accordingly. + * The allocated image buffer has to be freed by using + * av_freep(&pointers[0]). + * + * @param align the value to use for buffer size alignment + * @return the size in bytes required for the image buffer, a negative + * error code in case of failure + */ +int av_image_alloc(uint8_t *pointers[4], int linesizes[4], + int w, int h, enum AVPixelFormat pix_fmt, int align); + +/** + * Copy image plane from src to dst. + * That is, copy "height" number of lines of "bytewidth" bytes each. + * The first byte of each successive line is separated by *_linesize + * bytes. + * + * bytewidth must be contained by both absolute values of dst_linesize + * and src_linesize, otherwise the function behavior is undefined. + * + * @param dst_linesize linesize for the image plane in dst + * @param src_linesize linesize for the image plane in src + */ +void av_image_copy_plane(uint8_t *dst, int dst_linesize, + const uint8_t *src, int src_linesize, + int bytewidth, int height); + +/** + * Copy image in src_data to dst_data. + * + * @param dst_linesizes linesizes for the image in dst_data + * @param src_linesizes linesizes for the image in src_data + */ +void av_image_copy(uint8_t *dst_data[4], int dst_linesizes[4], + const uint8_t *src_data[4], const int src_linesizes[4], + enum AVPixelFormat pix_fmt, int width, int height); + +/** + * Setup the data pointers and linesizes based on the specified image + * parameters and the provided array. + * + * The fields of the given image are filled in by using the src + * address which points to the image data buffer. Depending on the + * specified pixel format, one or multiple image data pointers and + * line sizes will be set. If a planar format is specified, several + * pointers will be set pointing to the different picture planes and + * the line sizes of the different planes will be stored in the + * lines_sizes array. Call with src == NULL to get the required + * size for the src buffer. + * + * To allocate the buffer and fill in the dst_data and dst_linesize in + * one call, use av_image_alloc(). + * + * @param dst_data data pointers to be filled in + * @param dst_linesizes linesizes for the image in dst_data to be filled in + * @param src buffer which will contain or contains the actual image data, can be NULL + * @param pix_fmt the pixel format of the image + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @param align the value used in src for linesize alignment + * @return the size in bytes required for src, a negative error code + * in case of failure + */ +int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], + const uint8_t *src, + enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Return the size in bytes of the amount of data required to store an + * image with the given parameters. + * + * @param[in] align the assumed linesize alignment + */ +int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Copy image data from an image into a buffer. + * + * av_image_get_buffer_size() can be used to compute the required size + * for the buffer to fill. + * + * @param dst a buffer into which picture data will be copied + * @param dst_size the size in bytes of dst + * @param src_data pointers containing the source image data + * @param src_linesizes linesizes for the image in src_data + * @param pix_fmt the pixel format of the source image + * @param width the width of the source image in pixels + * @param height the height of the source image in pixels + * @param align the assumed linesize alignment for dst + * @return the number of bytes written to dst, or a negative value + * (error code) on error + */ +int av_image_copy_to_buffer(uint8_t *dst, int dst_size, + const uint8_t * const src_data[4], const int src_linesize[4], + enum AVPixelFormat pix_fmt, int width, int height, int align); + +/** + * Check if the given dimension of an image is valid, meaning that all + * bytes of the image can be addressed with a signed int. + * + * @param w the width of the picture + * @param h the height of the picture + * @param log_offset the offset to sum to the log level for logging with log_ctx + * @param log_ctx the parent logging context, it may be NULL + * @return >= 0 if valid, a negative error code otherwise + */ +int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx); + +/** + * Check if the given sample aspect ratio of an image is valid. + * + * It is considered invalid if the denominator is 0 or if applying the ratio + * to the image size would make the smaller dimension less than 1. If the + * sar numerator is 0, it is considered unknown and will return as valid. + * + * @param w width of the image + * @param h height of the image + * @param sar sample aspect ratio of the image + * @return 0 if valid, a negative AVERROR code otherwise + */ +int av_image_check_sar(unsigned int w, unsigned int h, AVRational sar); + +/** + * @} + */ + + +#endif /* AVUTIL_IMGUTILS_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/intfloat.h b/TMessagesProj/jni/ffmpeg/include/libavutil/intfloat.h new file mode 100644 index 00000000..fe3d7ec4 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/intfloat.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 Mans Rullgard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTFLOAT_H +#define AVUTIL_INTFLOAT_H + +#include +#include "attributes.h" + +union av_intfloat32 { + uint32_t i; + float f; +}; + +union av_intfloat64 { + uint64_t i; + double f; +}; + +/** + * Reinterpret a 32-bit integer as a float. + */ +static av_always_inline float av_int2float(uint32_t i) +{ + union av_intfloat32 v; + v.i = i; + return v.f; +} + +/** + * Reinterpret a float as a 32-bit integer. + */ +static av_always_inline uint32_t av_float2int(float f) +{ + union av_intfloat32 v; + v.f = f; + return v.i; +} + +/** + * Reinterpret a 64-bit integer as a double. + */ +static av_always_inline double av_int2double(uint64_t i) +{ + union av_intfloat64 v; + v.i = i; + return v.f; +} + +/** + * Reinterpret a double as a 64-bit integer. + */ +static av_always_inline uint64_t av_double2int(double f) +{ + union av_intfloat64 v; + v.f = f; + return v.i; +} + +#endif /* AVUTIL_INTFLOAT_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/intreadwrite.h b/TMessagesProj/jni/ffmpeg/include/libavutil/intreadwrite.h new file mode 100644 index 00000000..51fbe30a --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/intreadwrite.h @@ -0,0 +1,629 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_INTREADWRITE_H +#define AVUTIL_INTREADWRITE_H + +#include +#include "libavutil/avconfig.h" +#include "attributes.h" +#include "bswap.h" + +typedef union { + uint64_t u64; + uint32_t u32[2]; + uint16_t u16[4]; + uint8_t u8 [8]; + double f64; + float f32[2]; +} av_alias av_alias64; + +typedef union { + uint32_t u32; + uint16_t u16[2]; + uint8_t u8 [4]; + float f32; +} av_alias av_alias32; + +typedef union { + uint16_t u16; + uint8_t u8 [2]; +} av_alias av_alias16; + +/* + * Arch-specific headers can provide any combination of + * AV_[RW][BLN](16|24|32|48|64) and AV_(COPY|SWAP|ZERO)(64|128) macros. + * Preprocessor symbols must be defined, even if these are implemented + * as inline functions. + * + * R/W means read/write, B/L/N means big/little/native endianness. + * The following macros require aligned access, compared to their + * unaligned variants: AV_(COPY|SWAP|ZERO)(64|128), AV_[RW]N[8-64]A. + * Incorrect usage may range from abysmal performance to crash + * depending on the platform. + * + * The unaligned variants are AV_[RW][BLN][8-64] and AV_COPY*U. + */ + +#ifdef HAVE_AV_CONFIG_H + +#include "config.h" + +#if ARCH_ARM +# include "arm/intreadwrite.h" +#elif ARCH_AVR32 +# include "avr32/intreadwrite.h" +#elif ARCH_MIPS +# include "mips/intreadwrite.h" +#elif ARCH_PPC +# include "ppc/intreadwrite.h" +#elif ARCH_TOMI +# include "tomi/intreadwrite.h" +#elif ARCH_X86 +# include "x86/intreadwrite.h" +#endif + +#endif /* HAVE_AV_CONFIG_H */ + +/* + * Map AV_RNXX <-> AV_R[BL]XX for all variants provided by per-arch headers. + */ + +#if AV_HAVE_BIGENDIAN + +# if defined(AV_RN16) && !defined(AV_RB16) +# define AV_RB16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RB16) +# define AV_RN16(p) AV_RB16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WB16) +# define AV_WB16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WB16) +# define AV_WN16(p, v) AV_WB16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RB24) +# define AV_RB24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RB24) +# define AV_RN24(p) AV_RB24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WB24) +# define AV_WB24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WB24) +# define AV_WN24(p, v) AV_WB24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RB32) +# define AV_RB32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RB32) +# define AV_RN32(p) AV_RB32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WB32) +# define AV_WB32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WB32) +# define AV_WN32(p, v) AV_WB32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RB48) +# define AV_RB48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RB48) +# define AV_RN48(p) AV_RB48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WB48) +# define AV_WB48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WB48) +# define AV_WN48(p, v) AV_WB48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RB64) +# define AV_RB64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RB64) +# define AV_RN64(p) AV_RB64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WB64) +# define AV_WB64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WB64) +# define AV_WN64(p, v) AV_WB64(p, v) +# endif + +#else /* AV_HAVE_BIGENDIAN */ + +# if defined(AV_RN16) && !defined(AV_RL16) +# define AV_RL16(p) AV_RN16(p) +# elif !defined(AV_RN16) && defined(AV_RL16) +# define AV_RN16(p) AV_RL16(p) +# endif + +# if defined(AV_WN16) && !defined(AV_WL16) +# define AV_WL16(p, v) AV_WN16(p, v) +# elif !defined(AV_WN16) && defined(AV_WL16) +# define AV_WN16(p, v) AV_WL16(p, v) +# endif + +# if defined(AV_RN24) && !defined(AV_RL24) +# define AV_RL24(p) AV_RN24(p) +# elif !defined(AV_RN24) && defined(AV_RL24) +# define AV_RN24(p) AV_RL24(p) +# endif + +# if defined(AV_WN24) && !defined(AV_WL24) +# define AV_WL24(p, v) AV_WN24(p, v) +# elif !defined(AV_WN24) && defined(AV_WL24) +# define AV_WN24(p, v) AV_WL24(p, v) +# endif + +# if defined(AV_RN32) && !defined(AV_RL32) +# define AV_RL32(p) AV_RN32(p) +# elif !defined(AV_RN32) && defined(AV_RL32) +# define AV_RN32(p) AV_RL32(p) +# endif + +# if defined(AV_WN32) && !defined(AV_WL32) +# define AV_WL32(p, v) AV_WN32(p, v) +# elif !defined(AV_WN32) && defined(AV_WL32) +# define AV_WN32(p, v) AV_WL32(p, v) +# endif + +# if defined(AV_RN48) && !defined(AV_RL48) +# define AV_RL48(p) AV_RN48(p) +# elif !defined(AV_RN48) && defined(AV_RL48) +# define AV_RN48(p) AV_RL48(p) +# endif + +# if defined(AV_WN48) && !defined(AV_WL48) +# define AV_WL48(p, v) AV_WN48(p, v) +# elif !defined(AV_WN48) && defined(AV_WL48) +# define AV_WN48(p, v) AV_WL48(p, v) +# endif + +# if defined(AV_RN64) && !defined(AV_RL64) +# define AV_RL64(p) AV_RN64(p) +# elif !defined(AV_RN64) && defined(AV_RL64) +# define AV_RN64(p) AV_RL64(p) +# endif + +# if defined(AV_WN64) && !defined(AV_WL64) +# define AV_WL64(p, v) AV_WN64(p, v) +# elif !defined(AV_WN64) && defined(AV_WL64) +# define AV_WN64(p, v) AV_WL64(p, v) +# endif + +#endif /* !AV_HAVE_BIGENDIAN */ + +/* + * Define AV_[RW]N helper macros to simplify definitions not provided + * by per-arch headers. + */ + +#if defined(__GNUC__) && !defined(__TI_COMPILER_VERSION__) + +union unaligned_64 { uint64_t l; } __attribute__((packed)) av_alias; +union unaligned_32 { uint32_t l; } __attribute__((packed)) av_alias; +union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; + +# define AV_RN(s, p) (((const union unaligned_##s *) (p))->l) +# define AV_WN(s, p, v) ((((union unaligned_##s *) (p))->l) = (v)) + +#elif defined(__DECC) + +# define AV_RN(s, p) (*((const __unaligned uint##s##_t*)(p))) +# define AV_WN(s, p, v) (*((__unaligned uint##s##_t*)(p)) = (v)) + +#elif AV_HAVE_FAST_UNALIGNED + +# define AV_RN(s, p) (((const av_alias##s*)(p))->u##s) +# define AV_WN(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#else + +#ifndef AV_RB16 +# define AV_RB16(x) \ + ((((const uint8_t*)(x))[0] << 8) | \ + ((const uint8_t*)(x))[1]) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[1] = (d); \ + ((uint8_t*)(p))[0] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RL16 +# define AV_RL16(x) \ + ((((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + } while(0) +#endif + +#ifndef AV_RB32 +# define AV_RB32(x) \ + (((uint32_t)((const uint8_t*)(x))[0] << 24) | \ + (((const uint8_t*)(x))[1] << 16) | \ + (((const uint8_t*)(x))[2] << 8) | \ + ((const uint8_t*)(x))[3]) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[3] = (d); \ + ((uint8_t*)(p))[2] = (d)>>8; \ + ((uint8_t*)(p))[1] = (d)>>16; \ + ((uint8_t*)(p))[0] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RL32 +# define AV_RL32(x) \ + (((uint32_t)((const uint8_t*)(x))[3] << 24) | \ + (((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, darg) do { \ + unsigned d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + } while(0) +#endif + +#ifndef AV_RB64 +# define AV_RB64(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 8) | \ + (uint64_t)((const uint8_t*)(x))[7]) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[7] = (d); \ + ((uint8_t*)(p))[6] = (d)>>8; \ + ((uint8_t*)(p))[5] = (d)>>16; \ + ((uint8_t*)(p))[4] = (d)>>24; \ + ((uint8_t*)(p))[3] = (d)>>32; \ + ((uint8_t*)(p))[2] = (d)>>40; \ + ((uint8_t*)(p))[1] = (d)>>48; \ + ((uint8_t*)(p))[0] = (d)>>56; \ + } while(0) +#endif + +#ifndef AV_RL64 +# define AV_RL64(x) \ + (((uint64_t)((const uint8_t*)(x))[7] << 56) | \ + ((uint64_t)((const uint8_t*)(x))[6] << 48) | \ + ((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + ((uint8_t*)(p))[6] = (d)>>48; \ + ((uint8_t*)(p))[7] = (d)>>56; \ + } while(0) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RN(s, p) AV_RB##s(p) +# define AV_WN(s, p, v) AV_WB##s(p, v) +#else +# define AV_RN(s, p) AV_RL##s(p) +# define AV_WN(s, p, v) AV_WL##s(p, v) +#endif + +#endif /* HAVE_FAST_UNALIGNED */ + +#ifndef AV_RN16 +# define AV_RN16(p) AV_RN(16, p) +#endif + +#ifndef AV_RN32 +# define AV_RN32(p) AV_RN(32, p) +#endif + +#ifndef AV_RN64 +# define AV_RN64(p) AV_RN(64, p) +#endif + +#ifndef AV_WN16 +# define AV_WN16(p, v) AV_WN(16, p, v) +#endif + +#ifndef AV_WN32 +# define AV_WN32(p, v) AV_WN(32, p, v) +#endif + +#ifndef AV_WN64 +# define AV_WN64(p, v) AV_WN(64, p, v) +#endif + +#if AV_HAVE_BIGENDIAN +# define AV_RB(s, p) AV_RN##s(p) +# define AV_WB(s, p, v) AV_WN##s(p, v) +# define AV_RL(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WL(s, p, v) AV_WN##s(p, av_bswap##s(v)) +#else +# define AV_RB(s, p) av_bswap##s(AV_RN##s(p)) +# define AV_WB(s, p, v) AV_WN##s(p, av_bswap##s(v)) +# define AV_RL(s, p) AV_RN##s(p) +# define AV_WL(s, p, v) AV_WN##s(p, v) +#endif + +#define AV_RB8(x) (((const uint8_t*)(x))[0]) +#define AV_WB8(p, d) do { ((uint8_t*)(p))[0] = (d); } while(0) + +#define AV_RL8(x) AV_RB8(x) +#define AV_WL8(p, d) AV_WB8(p, d) + +#ifndef AV_RB16 +# define AV_RB16(p) AV_RB(16, p) +#endif +#ifndef AV_WB16 +# define AV_WB16(p, v) AV_WB(16, p, v) +#endif + +#ifndef AV_RL16 +# define AV_RL16(p) AV_RL(16, p) +#endif +#ifndef AV_WL16 +# define AV_WL16(p, v) AV_WL(16, p, v) +#endif + +#ifndef AV_RB32 +# define AV_RB32(p) AV_RB(32, p) +#endif +#ifndef AV_WB32 +# define AV_WB32(p, v) AV_WB(32, p, v) +#endif + +#ifndef AV_RL32 +# define AV_RL32(p) AV_RL(32, p) +#endif +#ifndef AV_WL32 +# define AV_WL32(p, v) AV_WL(32, p, v) +#endif + +#ifndef AV_RB64 +# define AV_RB64(p) AV_RB(64, p) +#endif +#ifndef AV_WB64 +# define AV_WB64(p, v) AV_WB(64, p, v) +#endif + +#ifndef AV_RL64 +# define AV_RL64(p) AV_RL(64, p) +#endif +#ifndef AV_WL64 +# define AV_WL64(p, v) AV_WL(64, p, v) +#endif + +#ifndef AV_RB24 +# define AV_RB24(x) \ + ((((const uint8_t*)(x))[0] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[2]) +#endif +#ifndef AV_WB24 +# define AV_WB24(p, d) do { \ + ((uint8_t*)(p))[2] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[0] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RL24 +# define AV_RL24(x) \ + ((((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL24 +# define AV_WL24(p, d) do { \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + } while(0) +#endif + +#ifndef AV_RB48 +# define AV_RB48(x) \ + (((uint64_t)((const uint8_t*)(x))[0] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 8) | \ + (uint64_t)((const uint8_t*)(x))[5]) +#endif +#ifndef AV_WB48 +# define AV_WB48(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[5] = (d); \ + ((uint8_t*)(p))[4] = (d)>>8; \ + ((uint8_t*)(p))[3] = (d)>>16; \ + ((uint8_t*)(p))[2] = (d)>>24; \ + ((uint8_t*)(p))[1] = (d)>>32; \ + ((uint8_t*)(p))[0] = (d)>>40; \ + } while(0) +#endif + +#ifndef AV_RL48 +# define AV_RL48(x) \ + (((uint64_t)((const uint8_t*)(x))[5] << 40) | \ + ((uint64_t)((const uint8_t*)(x))[4] << 32) | \ + ((uint64_t)((const uint8_t*)(x))[3] << 24) | \ + ((uint64_t)((const uint8_t*)(x))[2] << 16) | \ + ((uint64_t)((const uint8_t*)(x))[1] << 8) | \ + (uint64_t)((const uint8_t*)(x))[0]) +#endif +#ifndef AV_WL48 +# define AV_WL48(p, darg) do { \ + uint64_t d = (darg); \ + ((uint8_t*)(p))[0] = (d); \ + ((uint8_t*)(p))[1] = (d)>>8; \ + ((uint8_t*)(p))[2] = (d)>>16; \ + ((uint8_t*)(p))[3] = (d)>>24; \ + ((uint8_t*)(p))[4] = (d)>>32; \ + ((uint8_t*)(p))[5] = (d)>>40; \ + } while(0) +#endif + +/* + * The AV_[RW]NA macros access naturally aligned data + * in a type-safe way. + */ + +#define AV_RNA(s, p) (((const av_alias##s*)(p))->u##s) +#define AV_WNA(s, p, v) (((av_alias##s*)(p))->u##s = (v)) + +#ifndef AV_RN16A +# define AV_RN16A(p) AV_RNA(16, p) +#endif + +#ifndef AV_RN32A +# define AV_RN32A(p) AV_RNA(32, p) +#endif + +#ifndef AV_RN64A +# define AV_RN64A(p) AV_RNA(64, p) +#endif + +#ifndef AV_WN16A +# define AV_WN16A(p, v) AV_WNA(16, p, v) +#endif + +#ifndef AV_WN32A +# define AV_WN32A(p, v) AV_WNA(32, p, v) +#endif + +#ifndef AV_WN64A +# define AV_WN64A(p, v) AV_WNA(64, p, v) +#endif + +/* + * The AV_COPYxxU macros are suitable for copying data to/from unaligned + * memory locations. + */ + +#define AV_COPYU(n, d, s) AV_WN##n(d, AV_RN##n(s)); + +#ifndef AV_COPY16U +# define AV_COPY16U(d, s) AV_COPYU(16, d, s) +#endif + +#ifndef AV_COPY32U +# define AV_COPY32U(d, s) AV_COPYU(32, d, s) +#endif + +#ifndef AV_COPY64U +# define AV_COPY64U(d, s) AV_COPYU(64, d, s) +#endif + +#ifndef AV_COPY128U +# define AV_COPY128U(d, s) \ + do { \ + AV_COPY64U(d, s); \ + AV_COPY64U((char *)(d) + 8, (const char *)(s) + 8); \ + } while(0) +#endif + +/* Parameters for AV_COPY*, AV_SWAP*, AV_ZERO* must be + * naturally aligned. They may be implemented using MMX, + * so emms_c() must be called before using any float code + * afterwards. + */ + +#define AV_COPY(n, d, s) \ + (((av_alias##n*)(d))->u##n = ((const av_alias##n*)(s))->u##n) + +#ifndef AV_COPY16 +# define AV_COPY16(d, s) AV_COPY(16, d, s) +#endif + +#ifndef AV_COPY32 +# define AV_COPY32(d, s) AV_COPY(32, d, s) +#endif + +#ifndef AV_COPY64 +# define AV_COPY64(d, s) AV_COPY(64, d, s) +#endif + +#ifndef AV_COPY128 +# define AV_COPY128(d, s) \ + do { \ + AV_COPY64(d, s); \ + AV_COPY64((char*)(d)+8, (char*)(s)+8); \ + } while(0) +#endif + +#define AV_SWAP(n, a, b) FFSWAP(av_alias##n, *(av_alias##n*)(a), *(av_alias##n*)(b)) + +#ifndef AV_SWAP64 +# define AV_SWAP64(a, b) AV_SWAP(64, a, b) +#endif + +#define AV_ZERO(n, d) (((av_alias##n*)(d))->u##n = 0) + +#ifndef AV_ZERO16 +# define AV_ZERO16(d) AV_ZERO(16, d) +#endif + +#ifndef AV_ZERO32 +# define AV_ZERO32(d) AV_ZERO(32, d) +#endif + +#ifndef AV_ZERO64 +# define AV_ZERO64(d) AV_ZERO(64, d) +#endif + +#ifndef AV_ZERO128 +# define AV_ZERO128(d) \ + do { \ + AV_ZERO64(d); \ + AV_ZERO64((char*)(d)+8); \ + } while(0) +#endif + +#endif /* AVUTIL_INTREADWRITE_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/lfg.h b/TMessagesProj/jni/ffmpeg/include/libavutil/lfg.h new file mode 100644 index 00000000..ec90562c --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/lfg.h @@ -0,0 +1,62 @@ +/* + * Lagged Fibonacci PRNG + * Copyright (c) 2008 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LFG_H +#define AVUTIL_LFG_H + +typedef struct AVLFG { + unsigned int state[64]; + int index; +} AVLFG; + +void av_lfg_init(AVLFG *c, unsigned int seed); + +/** + * Get the next random unsigned 32-bit number using an ALFG. + * + * Please also consider a simple LCG like state= state*1664525+1013904223, + * it may be good enough and faster for your specific use case. + */ +static inline unsigned int av_lfg_get(AVLFG *c){ + c->state[c->index & 63] = c->state[(c->index-24) & 63] + c->state[(c->index-55) & 63]; + return c->state[c->index++ & 63]; +} + +/** + * Get the next random unsigned 32-bit number using a MLFG. + * + * Please also consider av_lfg_get() above, it is faster. + */ +static inline unsigned int av_mlfg_get(AVLFG *c){ + unsigned int a= c->state[(c->index-55) & 63]; + unsigned int b= c->state[(c->index-24) & 63]; + return c->state[c->index++ & 63] = 2*a*b+a+b; +} + +/** + * Get the next two numbers generated by a Box-Muller Gaussian + * generator using the random numbers issued by lfg. + * + * @param out array where the two generated numbers are placed + */ +void av_bmg_get(AVLFG *lfg, double out[2]); + +#endif /* AVUTIL_LFG_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/log.h b/TMessagesProj/jni/ffmpeg/include/libavutil/log.h new file mode 100644 index 00000000..321748cd --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/log.h @@ -0,0 +1,359 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_LOG_H +#define AVUTIL_LOG_H + +#include +#include "avutil.h" +#include "attributes.h" +#include "version.h" + +typedef enum { + AV_CLASS_CATEGORY_NA = 0, + AV_CLASS_CATEGORY_INPUT, + AV_CLASS_CATEGORY_OUTPUT, + AV_CLASS_CATEGORY_MUXER, + AV_CLASS_CATEGORY_DEMUXER, + AV_CLASS_CATEGORY_ENCODER, + AV_CLASS_CATEGORY_DECODER, + AV_CLASS_CATEGORY_FILTER, + AV_CLASS_CATEGORY_BITSTREAM_FILTER, + AV_CLASS_CATEGORY_SWSCALER, + AV_CLASS_CATEGORY_SWRESAMPLER, + AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT = 40, + AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, + AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT, + AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT, + AV_CLASS_CATEGORY_DEVICE_OUTPUT, + AV_CLASS_CATEGORY_DEVICE_INPUT, + AV_CLASS_CATEGORY_NB, ///< not part of ABI/API +}AVClassCategory; + +#define AV_IS_INPUT_DEVICE(category) \ + (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_INPUT)) + +#define AV_IS_OUTPUT_DEVICE(category) \ + (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_OUTPUT)) + +struct AVOptionRanges; + +/** + * Describe the class of an AVClass context structure. That is an + * arbitrary struct of which the first field is a pointer to an + * AVClass struct (e.g. AVCodecContext, AVFormatContext etc.). + */ +typedef struct AVClass { + /** + * The name of the class; usually it is the same name as the + * context structure type to which the AVClass is associated. + */ + const char* class_name; + + /** + * A pointer to a function which returns the name of a context + * instance ctx associated with the class. + */ + const char* (*item_name)(void* ctx); + + /** + * a pointer to the first option specified in the class if any or NULL + * + * @see av_set_default_options() + */ + const struct AVOption *option; + + /** + * LIBAVUTIL_VERSION with which this structure was created. + * This is used to allow fields to be added without requiring major + * version bumps everywhere. + */ + + int version; + + /** + * Offset in the structure where log_level_offset is stored. + * 0 means there is no such variable + */ + int log_level_offset_offset; + + /** + * Offset in the structure where a pointer to the parent context for + * logging is stored. For example a decoder could pass its AVCodecContext + * to eval as such a parent context, which an av_log() implementation + * could then leverage to display the parent context. + * The offset can be NULL. + */ + int parent_log_context_offset; + + /** + * Return next AVOptions-enabled child or NULL + */ + void* (*child_next)(void *obj, void *prev); + + /** + * Return an AVClass corresponding to the next potential + * AVOptions-enabled child. + * + * The difference between child_next and this is that + * child_next iterates over _already existing_ objects, while + * child_class_next iterates over _all possible_ children. + */ + const struct AVClass* (*child_class_next)(const struct AVClass *prev); + + /** + * Category used for visualization (like color) + * This is only set if the category is equal for all objects using this class. + * available since version (51 << 16 | 56 << 8 | 100) + */ + AVClassCategory category; + + /** + * Callback to return the category. + * available since version (51 << 16 | 59 << 8 | 100) + */ + AVClassCategory (*get_category)(void* ctx); + + /** + * Callback to return the supported/allowed ranges. + * available since version (52.12) + */ + int (*query_ranges)(struct AVOptionRanges **, void *obj, const char *key, int flags); +} AVClass; + +/** + * @addtogroup lavu_log + * + * @{ + * + * @defgroup lavu_log_constants Logging Constants + * + * @{ + */ + +/** + * Print no output. + */ +#define AV_LOG_QUIET -8 + +/** + * Something went really wrong and we will crash now. + */ +#define AV_LOG_PANIC 0 + +/** + * Something went wrong and recovery is not possible. + * For example, no header was found for a format which depends + * on headers or an illegal combination of parameters is used. + */ +#define AV_LOG_FATAL 8 + +/** + * Something went wrong and cannot losslessly be recovered. + * However, not all future data is affected. + */ +#define AV_LOG_ERROR 16 + +/** + * Something somehow does not look correct. This may or may not + * lead to problems. An example would be the use of '-vstrict -2'. + */ +#define AV_LOG_WARNING 24 + +/** + * Standard information. + */ +#define AV_LOG_INFO 32 + +/** + * Detailed information. + */ +#define AV_LOG_VERBOSE 40 + +/** + * Stuff which is only useful for libav* developers. + */ +#define AV_LOG_DEBUG 48 + +/** + * Extremely verbose debugging, useful for libav* development. + */ +#define AV_LOG_TRACE 56 + +#define AV_LOG_MAX_OFFSET (AV_LOG_TRACE - AV_LOG_QUIET) + +/** + * @} + */ + +/** + * Sets additional colors for extended debugging sessions. + * @code + av_log(ctx, AV_LOG_DEBUG|AV_LOG_C(134), "Message in purple\n"); + @endcode + * Requires 256color terminal support. Uses outside debugging is not + * recommended. + */ +#define AV_LOG_C(x) ((x) << 8) + +/** + * Send the specified message to the log if the level is less than or equal + * to the current av_log_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log_set_callback + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct or NULL if general log. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + */ +void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4); + + +/** + * Send the specified message to the log if the level is less than or equal + * to the current av_log_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log_set_callback + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param vl The arguments referenced by the format string. + */ +void av_vlog(void *avcl, int level, const char *fmt, va_list vl); + +/** + * Get the current log level + * + * @see lavu_log_constants + * + * @return Current log level + */ +int av_log_get_level(void); + +/** + * Set the log level + * + * @see lavu_log_constants + * + * @param level Logging level + */ +void av_log_set_level(int level); + +/** + * Set the logging callback + * + * @note The callback must be thread safe, even if the application does not use + * threads itself as some codecs are multithreaded. + * + * @see av_log_default_callback + * + * @param callback A logging function with a compatible signature. + */ +void av_log_set_callback(void (*callback)(void*, int, const char*, va_list)); + +/** + * Default logging callback + * + * It prints the message to stderr, optionally colorizing it. + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param vl The arguments referenced by the format string. + */ +void av_log_default_callback(void *avcl, int level, const char *fmt, + va_list vl); + +/** + * Return the context name + * + * @param ctx The AVClass context + * + * @return The AVClass class_name + */ +const char* av_default_item_name(void* ctx); +AVClassCategory av_default_get_category(void *ptr); + +/** + * Format a line of log the same way as the default callback. + * @param line buffer to receive the formatted line + * @param line_size size of the buffer + * @param print_prefix used to store whether the prefix must be printed; + * must point to a persistent integer initially set to 1 + */ +void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix); + +#if FF_API_DLOG +/** + * av_dlog macros + * @deprecated unused + * Useful to print debug messages that shouldn't get compiled in normally. + */ + +#ifdef DEBUG +# define av_dlog(pctx, ...) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__) +#else +# define av_dlog(pctx, ...) do { if (0) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0) +#endif +#endif /* FF_API_DLOG */ + +/** + * Skip repeated messages, this requires the user app to use av_log() instead of + * (f)printf as the 2 would otherwise interfere and lead to + * "Last message repeated x times" messages below (f)printf messages with some + * bad luck. + * Also to receive the last, "last repeated" line if any, the user app must + * call av_log(NULL, AV_LOG_QUIET, "%s", ""); at the end + */ +#define AV_LOG_SKIP_REPEATED 1 + +/** + * Include the log severity in messages originating from codecs. + * + * Results in messages such as: + * [rawvideo @ 0xDEADBEEF] [error] encode did not produce valid pts + */ +#define AV_LOG_PRINT_LEVEL 2 + +void av_log_set_flags(int arg); +int av_log_get_flags(void); + +/** + * @} + */ + +#endif /* AVUTIL_LOG_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/macros.h b/TMessagesProj/jni/ffmpeg/include/libavutil/macros.h new file mode 100644 index 00000000..44653237 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/macros.h @@ -0,0 +1,48 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @ingroup lavu + * Utility Preprocessor macros + */ + +#ifndef AVUTIL_MACROS_H +#define AVUTIL_MACROS_H + +/** + * @addtogroup preproc_misc Preprocessor String Macros + * + * String manipulation macros + * + * @{ + */ + +#define AV_STRINGIFY(s) AV_TOSTRING(s) +#define AV_TOSTRING(s) #s + +#define AV_GLUE(a, b) a ## b +#define AV_JOIN(a, b) AV_GLUE(a, b) + +/** + * @} + */ + +#define AV_PRAGMA(s) _Pragma(#s) + +#endif /* AVUTIL_MACROS_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/mathematics.h b/TMessagesProj/jni/ffmpeg/include/libavutil/mathematics.h new file mode 100644 index 00000000..57c44f84 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/mathematics.h @@ -0,0 +1,165 @@ +/* + * copyright (c) 2005-2012 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MATHEMATICS_H +#define AVUTIL_MATHEMATICS_H + +#include +#include +#include "attributes.h" +#include "rational.h" +#include "intfloat.h" + +#ifndef M_E +#define M_E 2.7182818284590452354 /* e */ +#endif +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 /* log_e 2 */ +#endif +#ifndef M_LN10 +#define M_LN10 2.30258509299404568402 /* log_e 10 */ +#endif +#ifndef M_LOG2_10 +#define M_LOG2_10 3.32192809488736234787 /* log_2 10 */ +#endif +#ifndef M_PHI +#define M_PHI 1.61803398874989484820 /* phi / golden ratio */ +#endif +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* pi */ +#endif +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#endif +#ifndef M_SQRT1_2 +#define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */ +#endif +#ifndef M_SQRT2 +#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */ +#endif +#ifndef NAN +#define NAN av_int2float(0x7fc00000) +#endif +#ifndef INFINITY +#define INFINITY av_int2float(0x7f800000) +#endif + +/** + * @addtogroup lavu_math + * @{ + */ + + +enum AVRounding { + AV_ROUND_ZERO = 0, ///< Round toward zero. + AV_ROUND_INF = 1, ///< Round away from zero. + AV_ROUND_DOWN = 2, ///< Round toward -infinity. + AV_ROUND_UP = 3, ///< Round toward +infinity. + AV_ROUND_NEAR_INF = 5, ///< Round to nearest and halfway cases away from zero. + AV_ROUND_PASS_MINMAX = 8192, ///< Flag to pass INT64_MIN/MAX through instead of rescaling, this avoids special cases for AV_NOPTS_VALUE +}; + +/** + * Compute the greatest common divisor of a and b. + * + * @return gcd of a and b up to sign; if a >= 0 and b >= 0, return value is >= 0; + * if a == 0 and b == 0, returns 0. + */ +int64_t av_const av_gcd(int64_t a, int64_t b); + +/** + * Rescale a 64-bit integer with rounding to nearest. + * A simple a*b/c isn't possible as it can overflow. + */ +int64_t av_rescale(int64_t a, int64_t b, int64_t c) av_const; + +/** + * Rescale a 64-bit integer with specified rounding. + * A simple a*b/c isn't possible as it can overflow. + * + * @return rescaled value a, or if AV_ROUND_PASS_MINMAX is set and a is + * INT64_MIN or INT64_MAX then a is passed through unchanged. + */ +int64_t av_rescale_rnd(int64_t a, int64_t b, int64_t c, enum AVRounding) av_const; + +/** + * Rescale a 64-bit integer by 2 rational numbers. + */ +int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq) av_const; + +/** + * Rescale a 64-bit integer by 2 rational numbers with specified rounding. + * + * @return rescaled value a, or if AV_ROUND_PASS_MINMAX is set and a is + * INT64_MIN or INT64_MAX then a is passed through unchanged. + */ +int64_t av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq, + enum AVRounding) av_const; + +/** + * Compare 2 timestamps each in its own timebases. + * The result of the function is undefined if one of the timestamps + * is outside the int64_t range when represented in the others timebase. + * @return -1 if ts_a is before ts_b, 1 if ts_a is after ts_b or 0 if they represent the same position + */ +int av_compare_ts(int64_t ts_a, AVRational tb_a, int64_t ts_b, AVRational tb_b); + +/** + * Compare 2 integers modulo mod. + * That is we compare integers a and b for which only the least + * significant log2(mod) bits are known. + * + * @param mod must be a power of 2 + * @return a negative value if a is smaller than b + * a positive value if a is greater than b + * 0 if a equals b + */ +int64_t av_compare_mod(uint64_t a, uint64_t b, uint64_t mod); + +/** + * Rescale a timestamp while preserving known durations. + * + * @param in_ts Input timestamp + * @param in_tb Input timebase + * @param fs_tb Duration and *last timebase + * @param duration duration till the next call + * @param out_tb Output timebase + */ +int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb); + +/** + * Add a value to a timestamp. + * + * This function guarantees that when the same value is repeatly added that + * no accumulation of rounding errors occurs. + * + * @param ts Input timestamp + * @param ts_tb Input timestamp timebase + * @param inc value to add to ts + * @param inc_tb inc timebase + */ +int64_t av_add_stable(AVRational ts_tb, int64_t ts, AVRational inc_tb, int64_t inc); + + + /** + * @} + */ + +#endif /* AVUTIL_MATHEMATICS_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/md5.h b/TMessagesProj/jni/ffmpeg/include/libavutil/md5.h new file mode 100644 index 00000000..79702c88 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/md5.h @@ -0,0 +1,81 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MD5_H +#define AVUTIL_MD5_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_md5 MD5 + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_md5_size; + +struct AVMD5; + +/** + * Allocate an AVMD5 context. + */ +struct AVMD5 *av_md5_alloc(void); + +/** + * Initialize MD5 hashing. + * + * @param ctx pointer to the function context (of size av_md5_size) + */ +void av_md5_init(struct AVMD5 *ctx); + +/** + * Update hash value. + * + * @param ctx hash function context + * @param src input data to update hash with + * @param len input data length + */ +void av_md5_update(struct AVMD5 *ctx, const uint8_t *src, int len); + +/** + * Finish hashing and output digest value. + * + * @param ctx hash function context + * @param dst buffer where output digest value is stored + */ +void av_md5_final(struct AVMD5 *ctx, uint8_t *dst); + +/** + * Hash an array of data. + * + * @param dst The output buffer to write the digest into + * @param src The data to hash + * @param len The length of the data, in bytes + */ +void av_md5_sum(uint8_t *dst, const uint8_t *src, const int len); + +/** + * @} + */ + +#endif /* AVUTIL_MD5_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/mem.h b/TMessagesProj/jni/ffmpeg/include/libavutil/mem.h new file mode 100644 index 00000000..d25b3229 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/mem.h @@ -0,0 +1,406 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * memory handling functions + */ + +#ifndef AVUTIL_MEM_H +#define AVUTIL_MEM_H + +#include +#include + +#include "attributes.h" +#include "error.h" +#include "avutil.h" + +/** + * @addtogroup lavu_mem + * @{ + */ + + +#if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 1110 || defined(__SUNPRO_C) + #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v + #define DECLARE_ASM_CONST(n,t,v) const t __attribute__ ((aligned (n))) v +#elif defined(__TI_COMPILER_VERSION__) + #define DECLARE_ALIGNED(n,t,v) \ + AV_PRAGMA(DATA_ALIGN(v,n)) \ + t __attribute__((aligned(n))) v + #define DECLARE_ASM_CONST(n,t,v) \ + AV_PRAGMA(DATA_ALIGN(v,n)) \ + static const t __attribute__((aligned(n))) v +#elif defined(__GNUC__) + #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v + #define DECLARE_ASM_CONST(n,t,v) static const t av_used __attribute__ ((aligned (n))) v +#elif defined(_MSC_VER) + #define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v + #define DECLARE_ASM_CONST(n,t,v) __declspec(align(n)) static const t v +#else + #define DECLARE_ALIGNED(n,t,v) t v + #define DECLARE_ASM_CONST(n,t,v) static const t v +#endif + +#if AV_GCC_VERSION_AT_LEAST(3,1) + #define av_malloc_attrib __attribute__((__malloc__)) +#else + #define av_malloc_attrib +#endif + +#if AV_GCC_VERSION_AT_LEAST(4,3) + #define av_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__))) +#else + #define av_alloc_size(...) +#endif + +/** + * Allocate a block of size bytes with alignment suitable for all + * memory accesses (including vectors if available on the CPU). + * @param size Size in bytes for the memory block to be allocated. + * @return Pointer to the allocated block, NULL if the block cannot + * be allocated. + * @see av_mallocz() + */ +void *av_malloc(size_t size) av_malloc_attrib av_alloc_size(1); + +/** + * Allocate a block of size * nmemb bytes with av_malloc(). + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to the allocated block, NULL if the block cannot + * be allocated. + * @see av_malloc() + */ +av_alloc_size(1, 2) static inline void *av_malloc_array(size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_malloc(nmemb * size); +} + +/** + * Allocate or reallocate a block of memory. + * If ptr is NULL and size > 0, allocate a new block. If + * size is zero, free the memory block pointed to by ptr. + * @param ptr Pointer to a memory block already allocated with + * av_realloc() or NULL. + * @param size Size in bytes of the memory block to be allocated or + * reallocated. + * @return Pointer to a newly-reallocated block or NULL if the block + * cannot be reallocated or the function is used to free the memory block. + * @warning Pointers originating from the av_malloc() family of functions must + * not be passed to av_realloc(). The former can be implemented using + * memalign() (or other functions), and there is no guarantee that + * pointers from such functions can be passed to realloc() at all. + * The situation is undefined according to POSIX and may crash with + * some libc implementations. + * @see av_fast_realloc() + */ +void *av_realloc(void *ptr, size_t size) av_alloc_size(2); + +/** + * Allocate or reallocate a block of memory. + * This function does the same thing as av_realloc, except: + * - It takes two arguments and checks the result of the multiplication for + * integer overflow. + * - It frees the input block in case of failure, thus avoiding the memory + * leak with the classic "buf = realloc(buf); if (!buf) return -1;". + */ +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize); + +/** + * Allocate or reallocate a block of memory. + * If *ptr is NULL and size > 0, allocate a new block. If + * size is zero, free the memory block pointed to by ptr. + * @param ptr Pointer to a pointer to a memory block already allocated + * with av_realloc(), or pointer to a pointer to NULL. + * The pointer is updated on success, or freed on failure. + * @param size Size in bytes for the memory block to be allocated or + * reallocated + * @return Zero on success, an AVERROR error code on failure. + * @warning Pointers originating from the av_malloc() family of functions must + * not be passed to av_reallocp(). The former can be implemented using + * memalign() (or other functions), and there is no guarantee that + * pointers from such functions can be passed to realloc() at all. + * The situation is undefined according to POSIX and may crash with + * some libc implementations. + */ +av_warn_unused_result +int av_reallocp(void *ptr, size_t size); + +/** + * Allocate or reallocate an array. + * If ptr is NULL and nmemb > 0, allocate a new block. If + * nmemb is zero, free the memory block pointed to by ptr. + * @param ptr Pointer to a memory block already allocated with + * av_realloc() or NULL. + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to a newly-reallocated block or NULL if the block + * cannot be reallocated or the function is used to free the memory block. + * @warning Pointers originating from the av_malloc() family of functions must + * not be passed to av_realloc(). The former can be implemented using + * memalign() (or other functions), and there is no guarantee that + * pointers from such functions can be passed to realloc() at all. + * The situation is undefined according to POSIX and may crash with + * some libc implementations. + */ +av_alloc_size(2, 3) void *av_realloc_array(void *ptr, size_t nmemb, size_t size); + +/** + * Allocate or reallocate an array through a pointer to a pointer. + * If *ptr is NULL and nmemb > 0, allocate a new block. If + * nmemb is zero, free the memory block pointed to by ptr. + * @param ptr Pointer to a pointer to a memory block already allocated + * with av_realloc(), or pointer to a pointer to NULL. + * The pointer is updated on success, or freed on failure. + * @param nmemb Number of elements + * @param size Size of the single element + * @return Zero on success, an AVERROR error code on failure. + * @warning Pointers originating from the av_malloc() family of functions must + * not be passed to av_realloc(). The former can be implemented using + * memalign() (or other functions), and there is no guarantee that + * pointers from such functions can be passed to realloc() at all. + * The situation is undefined according to POSIX and may crash with + * some libc implementations. + */ +av_alloc_size(2, 3) int av_reallocp_array(void *ptr, size_t nmemb, size_t size); + +/** + * Free a memory block which has been allocated with av_malloc(z)() or + * av_realloc(). + * @param ptr Pointer to the memory block which should be freed. + * @note ptr = NULL is explicitly allowed. + * @note It is recommended that you use av_freep() instead. + * @see av_freep() + */ +void av_free(void *ptr); + +/** + * Allocate a block of size bytes with alignment suitable for all + * memory accesses (including vectors if available on the CPU) and + * zero all the bytes of the block. + * @param size Size in bytes for the memory block to be allocated. + * @return Pointer to the allocated block, NULL if it cannot be allocated. + * @see av_malloc() + */ +void *av_mallocz(size_t size) av_malloc_attrib av_alloc_size(1); + +/** + * Allocate a block of nmemb * size bytes with alignment suitable for all + * memory accesses (including vectors if available on the CPU) and + * zero all the bytes of the block. + * The allocation will fail if nmemb * size is greater than or equal + * to INT_MAX. + * @param nmemb + * @param size + * @return Pointer to the allocated block, NULL if it cannot be allocated. + */ +void *av_calloc(size_t nmemb, size_t size) av_malloc_attrib; + +/** + * Allocate a block of size * nmemb bytes with av_mallocz(). + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to the allocated block, NULL if the block cannot + * be allocated. + * @see av_mallocz() + * @see av_malloc_array() + */ +av_alloc_size(1, 2) static inline void *av_mallocz_array(size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_mallocz(nmemb * size); +} + +/** + * Duplicate the string s. + * @param s string to be duplicated + * @return Pointer to a newly-allocated string containing a + * copy of s or NULL if the string cannot be allocated. + */ +char *av_strdup(const char *s) av_malloc_attrib; + +/** + * Duplicate a substring of the string s. + * @param s string to be duplicated + * @param len the maximum length of the resulting string (not counting the + * terminating byte). + * @return Pointer to a newly-allocated string containing a + * copy of s or NULL if the string cannot be allocated. + */ +char *av_strndup(const char *s, size_t len) av_malloc_attrib; + +/** + * Duplicate the buffer p. + * @param p buffer to be duplicated + * @return Pointer to a newly allocated buffer containing a + * copy of p or NULL if the buffer cannot be allocated. + */ +void *av_memdup(const void *p, size_t size); + +/** + * Free a memory block which has been allocated with av_malloc(z)() or + * av_realloc() and set the pointer pointing to it to NULL. + * @param ptr Pointer to the pointer to the memory block which should + * be freed. + * @note passing a pointer to a NULL pointer is safe and leads to no action. + * @see av_free() + */ +void av_freep(void *ptr); + +/** + * Add an element to a dynamic array. + * + * The array to grow is supposed to be an array of pointers to + * structures, and the element to add must be a pointer to an already + * allocated structure. + * + * The array is reallocated when its size reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the number pointed to by nb_ptr + * is incremented. + * In case of failure, the array is freed, *tab_ptr is set to NULL and + * *nb_ptr is set to 0. + * + * @param tab_ptr pointer to the array to grow + * @param nb_ptr pointer to the number of elements in the array + * @param elem element to add + * @see av_dynarray_add_nofree(), av_dynarray2_add() + */ +void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem); + +/** + * Add an element to a dynamic array. + * + * Function has the same functionality as av_dynarray_add(), + * but it doesn't free memory on fails. It returns error code + * instead and leave current buffer untouched. + * + * @param tab_ptr pointer to the array to grow + * @param nb_ptr pointer to the number of elements in the array + * @param elem element to add + * @return >=0 on success, negative otherwise. + * @see av_dynarray_add(), av_dynarray2_add() + */ +av_warn_unused_result +int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem); + +/** + * Add an element of size elem_size to a dynamic array. + * + * The array is reallocated when its number of elements reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the number pointed to by nb_ptr + * is incremented. + * In case of failure, the array is freed, *tab_ptr is set to NULL and + * *nb_ptr is set to 0. + * + * @param tab_ptr pointer to the array to grow + * @param nb_ptr pointer to the number of elements in the array + * @param elem_size size in bytes of the elements in the array + * @param elem_data pointer to the data of the element to add. If NULL, the space of + * the new added element is not filled. + * @return pointer to the data of the element to copy in the new allocated space. + * If NULL, the new allocated space is left uninitialized." + * @see av_dynarray_add(), av_dynarray_add_nofree() + */ +void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, + const uint8_t *elem_data); + +/** + * Multiply two size_t values checking for overflow. + * @return 0 if success, AVERROR(EINVAL) if overflow. + */ +static inline int av_size_mult(size_t a, size_t b, size_t *r) +{ + size_t t = a * b; + /* Hack inspired from glibc: only try the division if nelem and elsize + * are both greater than sqrt(SIZE_MAX). */ + if ((a | b) >= ((size_t)1 << (sizeof(size_t) * 4)) && a && t / a != b) + return AVERROR(EINVAL); + *r = t; + return 0; +} + +/** + * Set the maximum size that may me allocated in one block. + */ +void av_max_alloc(size_t max); + +/** + * deliberately overlapping memcpy implementation + * @param dst destination buffer + * @param back how many bytes back we start (the initial size of the overlapping window), must be > 0 + * @param cnt number of bytes to copy, must be >= 0 + * + * cnt > back is valid, this will copy the bytes we just copied, + * thus creating a repeating pattern with a period length of back. + */ +void av_memcpy_backptr(uint8_t *dst, int back, int cnt); + +/** + * Reallocate the given block if it is not large enough, otherwise do nothing. + * + * @see av_realloc + */ +void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Allocate a buffer, reusing the given one if large enough. + * + * Contrary to av_fast_realloc the current buffer contents might not be + * preserved and on error the old buffer is freed, thus no special + * handling to avoid memleaks is necessary. + * + * @param ptr pointer to pointer to already allocated buffer, overwritten with pointer to new buffer + * @param size size of the buffer *ptr points to + * @param min_size minimum size of *ptr buffer after returning, *ptr will be NULL and + * *size 0 if an error occurred. + */ +void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Allocate a buffer, reusing the given one if large enough. + * + * All newly allocated space is initially cleared + * Contrary to av_fast_realloc the current buffer contents might not be + * preserved and on error the old buffer is freed, thus no special + * handling to avoid memleaks is necessary. + * + * @param ptr pointer to pointer to already allocated buffer, overwritten with pointer to new buffer + * @param size size of the buffer *ptr points to + * @param min_size minimum size of *ptr buffer after returning, *ptr will be NULL and + * *size 0 if an error occurred. + */ +void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size); + +/** + * @} + */ + +#endif /* AVUTIL_MEM_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/motion_vector.h b/TMessagesProj/jni/ffmpeg/include/libavutil/motion_vector.h new file mode 100644 index 00000000..ec295563 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/motion_vector.h @@ -0,0 +1,57 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MOTION_VECTOR_H +#define AVUTIL_MOTION_VECTOR_H + +#include + +typedef struct AVMotionVector { + /** + * Where the current macroblock comes from; negative value when it comes + * from the past, positive value when it comes from the future. + * XXX: set exact relative ref frame reference instead of a +/- 1 "direction". + */ + int32_t source; + /** + * Width and height of the block. + */ + uint8_t w, h; + /** + * Absolute source position. Can be outside the frame area. + */ + int16_t src_x, src_y; + /** + * Absolute destination position. Can be outside the frame area. + */ + int16_t dst_x, dst_y; + /** + * Extra flag information. + * Currently unused. + */ + uint64_t flags; + /** + * Motion vector + * src_x = dst_x + motion_x / motion_scale + * src_y = dst_y + motion_y / motion_scale + */ + int32_t motion_x, motion_y; + uint16_t motion_scale; +} AVMotionVector; + +#endif /* AVUTIL_MOTION_VECTOR_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/murmur3.h b/TMessagesProj/jni/ffmpeg/include/libavutil/murmur3.h new file mode 100644 index 00000000..f29ed973 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/murmur3.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2013 Reimar Döffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_MURMUR3_H +#define AVUTIL_MURMUR3_H + +#include + +struct AVMurMur3 *av_murmur3_alloc(void); +void av_murmur3_init_seeded(struct AVMurMur3 *c, uint64_t seed); +void av_murmur3_init(struct AVMurMur3 *c); +void av_murmur3_update(struct AVMurMur3 *c, const uint8_t *src, int len); +void av_murmur3_final(struct AVMurMur3 *c, uint8_t dst[16]); + +#endif /* AVUTIL_MURMUR3_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/opt.h b/TMessagesProj/jni/ffmpeg/include/libavutil/opt.h new file mode 100644 index 00000000..753434d6 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/opt.h @@ -0,0 +1,865 @@ +/* + * AVOptions + * copyright (c) 2005 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_OPT_H +#define AVUTIL_OPT_H + +/** + * @file + * AVOptions + */ + +#include "rational.h" +#include "avutil.h" +#include "dict.h" +#include "log.h" +#include "pixfmt.h" +#include "samplefmt.h" +#include "version.h" + +/** + * @defgroup avoptions AVOptions + * @ingroup lavu_data + * @{ + * AVOptions provide a generic system to declare options on arbitrary structs + * ("objects"). An option can have a help text, a type and a range of possible + * values. Options may then be enumerated, read and written to. + * + * @section avoptions_implement Implementing AVOptions + * This section describes how to add AVOptions capabilities to a struct. + * + * All AVOptions-related information is stored in an AVClass. Therefore + * the first member of the struct should be a pointer to an AVClass describing it. + * The option field of the AVClass must be set to a NULL-terminated static array + * of AVOptions. Each AVOption must have a non-empty name, a type, a default + * value and for number-type AVOptions also a range of allowed values. It must + * also declare an offset in bytes from the start of the struct, where the field + * associated with this AVOption is located. Other fields in the AVOption struct + * should also be set when applicable, but are not required. + * + * The following example illustrates an AVOptions-enabled struct: + * @code + * typedef struct test_struct { + * AVClass *class; + * int int_opt; + * char *str_opt; + * uint8_t *bin_opt; + * int bin_len; + * } test_struct; + * + * static const AVOption test_options[] = { + * { "test_int", "This is a test option of int type.", offsetof(test_struct, int_opt), + * AV_OPT_TYPE_INT, { .i64 = -1 }, INT_MIN, INT_MAX }, + * { "test_str", "This is a test option of string type.", offsetof(test_struct, str_opt), + * AV_OPT_TYPE_STRING }, + * { "test_bin", "This is a test option of binary type.", offsetof(test_struct, bin_opt), + * AV_OPT_TYPE_BINARY }, + * { NULL }, + * }; + * + * static const AVClass test_class = { + * .class_name = "test class", + * .item_name = av_default_item_name, + * .option = test_options, + * .version = LIBAVUTIL_VERSION_INT, + * }; + * @endcode + * + * Next, when allocating your struct, you must ensure that the AVClass pointer + * is set to the correct value. Then, av_opt_set_defaults() can be called to + * initialize defaults. After that the struct is ready to be used with the + * AVOptions API. + * + * When cleaning up, you may use the av_opt_free() function to automatically + * free all the allocated string and binary options. + * + * Continuing with the above example: + * + * @code + * test_struct *alloc_test_struct(void) + * { + * test_struct *ret = av_malloc(sizeof(*ret)); + * ret->class = &test_class; + * av_opt_set_defaults(ret); + * return ret; + * } + * void free_test_struct(test_struct **foo) + * { + * av_opt_free(*foo); + * av_freep(foo); + * } + * @endcode + * + * @subsection avoptions_implement_nesting Nesting + * It may happen that an AVOptions-enabled struct contains another + * AVOptions-enabled struct as a member (e.g. AVCodecContext in + * libavcodec exports generic options, while its priv_data field exports + * codec-specific options). In such a case, it is possible to set up the + * parent struct to export a child's options. To do that, simply + * implement AVClass.child_next() and AVClass.child_class_next() in the + * parent struct's AVClass. + * Assuming that the test_struct from above now also contains a + * child_struct field: + * + * @code + * typedef struct child_struct { + * AVClass *class; + * int flags_opt; + * } child_struct; + * static const AVOption child_opts[] = { + * { "test_flags", "This is a test option of flags type.", + * offsetof(child_struct, flags_opt), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX }, + * { NULL }, + * }; + * static const AVClass child_class = { + * .class_name = "child class", + * .item_name = av_default_item_name, + * .option = child_opts, + * .version = LIBAVUTIL_VERSION_INT, + * }; + * + * void *child_next(void *obj, void *prev) + * { + * test_struct *t = obj; + * if (!prev && t->child_struct) + * return t->child_struct; + * return NULL + * } + * const AVClass child_class_next(const AVClass *prev) + * { + * return prev ? NULL : &child_class; + * } + * @endcode + * Putting child_next() and child_class_next() as defined above into + * test_class will now make child_struct's options accessible through + * test_struct (again, proper setup as described above needs to be done on + * child_struct right after it is created). + * + * From the above example it might not be clear why both child_next() + * and child_class_next() are needed. The distinction is that child_next() + * iterates over actually existing objects, while child_class_next() + * iterates over all possible child classes. E.g. if an AVCodecContext + * was initialized to use a codec which has private options, then its + * child_next() will return AVCodecContext.priv_data and finish + * iterating. OTOH child_class_next() on AVCodecContext.av_class will + * iterate over all available codecs with private options. + * + * @subsection avoptions_implement_named_constants Named constants + * It is possible to create named constants for options. Simply set the unit + * field of the option the constants should apply to a string and + * create the constants themselves as options of type AV_OPT_TYPE_CONST + * with their unit field set to the same string. + * Their default_val field should contain the value of the named + * constant. + * For example, to add some named constants for the test_flags option + * above, put the following into the child_opts array: + * @code + * { "test_flags", "This is a test option of flags type.", + * offsetof(child_struct, flags_opt), AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT_MIN, INT_MAX, "test_unit" }, + * { "flag1", "This is a flag with value 16", 0, AV_OPT_TYPE_CONST, { .i64 = 16 }, 0, 0, "test_unit" }, + * @endcode + * + * @section avoptions_use Using AVOptions + * This section deals with accessing options in an AVOptions-enabled struct. + * Such structs in FFmpeg are e.g. AVCodecContext in libavcodec or + * AVFormatContext in libavformat. + * + * @subsection avoptions_use_examine Examining AVOptions + * The basic functions for examining options are av_opt_next(), which iterates + * over all options defined for one object, and av_opt_find(), which searches + * for an option with the given name. + * + * The situation is more complicated with nesting. An AVOptions-enabled struct + * may have AVOptions-enabled children. Passing the AV_OPT_SEARCH_CHILDREN flag + * to av_opt_find() will make the function search children recursively. + * + * For enumerating there are basically two cases. The first is when you want to + * get all options that may potentially exist on the struct and its children + * (e.g. when constructing documentation). In that case you should call + * av_opt_child_class_next() recursively on the parent struct's AVClass. The + * second case is when you have an already initialized struct with all its + * children and you want to get all options that can be actually written or read + * from it. In that case you should call av_opt_child_next() recursively (and + * av_opt_next() on each result). + * + * @subsection avoptions_use_get_set Reading and writing AVOptions + * When setting options, you often have a string read directly from the + * user. In such a case, simply passing it to av_opt_set() is enough. For + * non-string type options, av_opt_set() will parse the string according to the + * option type. + * + * Similarly av_opt_get() will read any option type and convert it to a string + * which will be returned. Do not forget that the string is allocated, so you + * have to free it with av_free(). + * + * In some cases it may be more convenient to put all options into an + * AVDictionary and call av_opt_set_dict() on it. A specific case of this + * are the format/codec open functions in lavf/lavc which take a dictionary + * filled with option as a parameter. This makes it possible to set some options + * that cannot be set otherwise, since e.g. the input file format is not known + * before the file is actually opened. + */ + +enum AVOptionType{ + AV_OPT_TYPE_FLAGS, + AV_OPT_TYPE_INT, + AV_OPT_TYPE_INT64, + AV_OPT_TYPE_DOUBLE, + AV_OPT_TYPE_FLOAT, + AV_OPT_TYPE_STRING, + AV_OPT_TYPE_RATIONAL, + AV_OPT_TYPE_BINARY, ///< offset must point to a pointer immediately followed by an int for the length + AV_OPT_TYPE_DICT, + AV_OPT_TYPE_CONST = 128, + AV_OPT_TYPE_IMAGE_SIZE = MKBETAG('S','I','Z','E'), ///< offset must point to two consecutive integers + AV_OPT_TYPE_PIXEL_FMT = MKBETAG('P','F','M','T'), + AV_OPT_TYPE_SAMPLE_FMT = MKBETAG('S','F','M','T'), + AV_OPT_TYPE_VIDEO_RATE = MKBETAG('V','R','A','T'), ///< offset must point to AVRational + AV_OPT_TYPE_DURATION = MKBETAG('D','U','R',' '), + AV_OPT_TYPE_COLOR = MKBETAG('C','O','L','R'), + AV_OPT_TYPE_CHANNEL_LAYOUT = MKBETAG('C','H','L','A'), + AV_OPT_TYPE_BOOL = MKBETAG('B','O','O','L'), +}; + +/** + * AVOption + */ +typedef struct AVOption { + const char *name; + + /** + * short English help text + * @todo What about other languages? + */ + const char *help; + + /** + * The offset relative to the context structure where the option + * value is stored. It should be 0 for named constants. + */ + int offset; + enum AVOptionType type; + + /** + * the default value for scalar options + */ + union { + int64_t i64; + double dbl; + const char *str; + /* TODO those are unused now */ + AVRational q; + } default_val; + double min; ///< minimum valid value for the option + double max; ///< maximum valid value for the option + + int flags; +#define AV_OPT_FLAG_ENCODING_PARAM 1 ///< a generic parameter which can be set by the user for muxing or encoding +#define AV_OPT_FLAG_DECODING_PARAM 2 ///< a generic parameter which can be set by the user for demuxing or decoding +#if FF_API_OPT_TYPE_METADATA +#define AV_OPT_FLAG_METADATA 4 ///< some data extracted or inserted into the file like title, comment, ... +#endif +#define AV_OPT_FLAG_AUDIO_PARAM 8 +#define AV_OPT_FLAG_VIDEO_PARAM 16 +#define AV_OPT_FLAG_SUBTITLE_PARAM 32 +/** + * The option is inteded for exporting values to the caller. + */ +#define AV_OPT_FLAG_EXPORT 64 +/** + * The option may not be set through the AVOptions API, only read. + * This flag only makes sense when AV_OPT_FLAG_EXPORT is also set. + */ +#define AV_OPT_FLAG_READONLY 128 +#define AV_OPT_FLAG_FILTERING_PARAM (1<<16) ///< a generic parameter which can be set by the user for filtering +//FIXME think about enc-audio, ... style flags + + /** + * The logical unit to which the option belongs. Non-constant + * options and corresponding named constants share the same + * unit. May be NULL. + */ + const char *unit; +} AVOption; + +/** + * A single allowed range of values, or a single allowed value. + */ +typedef struct AVOptionRange { + const char *str; + /** + * Value range. + * For string ranges this represents the min/max length. + * For dimensions this represents the min/max pixel count or width/height in multi-component case. + */ + double value_min, value_max; + /** + * Value's component range. + * For string this represents the unicode range for chars, 0-127 limits to ASCII. + */ + double component_min, component_max; + /** + * Range flag. + * If set to 1 the struct encodes a range, if set to 0 a single value. + */ + int is_range; +} AVOptionRange; + +/** + * List of AVOptionRange structs. + */ +typedef struct AVOptionRanges { + /** + * Array of option ranges. + * + * Most of option types use just one component. + * Following describes multi-component option types: + * + * AV_OPT_TYPE_IMAGE_SIZE: + * component index 0: range of pixel count (width * height). + * component index 1: range of width. + * component index 2: range of height. + * + * @note To obtain multi-component version of this structure, user must + * provide AV_OPT_MULTI_COMPONENT_RANGE to av_opt_query_ranges or + * av_opt_query_ranges_default function. + * + * Multi-component range can be read as in following example: + * + * @code + * int range_index, component_index; + * AVOptionRanges *ranges; + * AVOptionRange *range[3]; //may require more than 3 in the future. + * av_opt_query_ranges(&ranges, obj, key, AV_OPT_MULTI_COMPONENT_RANGE); + * for (range_index = 0; range_index < ranges->nb_ranges; range_index++) { + * for (component_index = 0; component_index < ranges->nb_components; component_index++) + * range[component_index] = ranges->range[ranges->nb_ranges * component_index + range_index]; + * //do something with range here. + * } + * av_opt_freep_ranges(&ranges); + * @endcode + */ + AVOptionRange **range; + /** + * Number of ranges per component. + */ + int nb_ranges; + /** + * Number of componentes. + */ + int nb_components; +} AVOptionRanges; + +/** + * Show the obj options. + * + * @param req_flags requested flags for the options to show. Show only the + * options for which it is opt->flags & req_flags. + * @param rej_flags rejected flags for the options to show. Show only the + * options for which it is !(opt->flags & req_flags). + * @param av_log_obj log context to use for showing the options + */ +int av_opt_show2(void *obj, void *av_log_obj, int req_flags, int rej_flags); + +/** + * Set the values of all AVOption fields to their default values. + * + * @param s an AVOption-enabled struct (its first member must be a pointer to AVClass) + */ +void av_opt_set_defaults(void *s); + +/** + * Set the values of all AVOption fields to their default values. Only these + * AVOption fields for which (opt->flags & mask) == flags will have their + * default applied to s. + * + * @param s an AVOption-enabled struct (its first member must be a pointer to AVClass) + * @param mask combination of AV_OPT_FLAG_* + * @param flags combination of AV_OPT_FLAG_* + */ +void av_opt_set_defaults2(void *s, int mask, int flags); + +/** + * Parse the key/value pairs list in opts. For each key/value pair + * found, stores the value in the field in ctx that is named like the + * key. ctx must be an AVClass context, storing is done using + * AVOptions. + * + * @param opts options string to parse, may be NULL + * @param key_val_sep a 0-terminated list of characters used to + * separate key from value + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other + * @return the number of successfully set key/value pairs, or a negative + * value corresponding to an AVERROR code in case of error: + * AVERROR(EINVAL) if opts cannot be parsed, + * the error code issued by av_opt_set() if a key/value pair + * cannot be set + */ +int av_set_options_string(void *ctx, const char *opts, + const char *key_val_sep, const char *pairs_sep); + +/** + * Parse the key-value pairs list in opts. For each key=value pair found, + * set the value of the corresponding option in ctx. + * + * @param ctx the AVClass object to set options on + * @param opts the options string, key-value pairs separated by a + * delimiter + * @param shorthand a NULL-terminated array of options names for shorthand + * notation: if the first field in opts has no key part, + * the key is taken from the first element of shorthand; + * then again for the second, etc., until either opts is + * finished, shorthand is finished or a named option is + * found; after that, all options must be named + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value, for example '=' + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other, for example ':' or ',' + * @return the number of successfully set key=value pairs, or a negative + * value corresponding to an AVERROR code in case of error: + * AVERROR(EINVAL) if opts cannot be parsed, + * the error code issued by av_set_string3() if a key/value pair + * cannot be set + * + * Options names must use only the following characters: a-z A-Z 0-9 - . / _ + * Separators must use characters distinct from option names and from each + * other. + */ +int av_opt_set_from_string(void *ctx, const char *opts, + const char *const *shorthand, + const char *key_val_sep, const char *pairs_sep); +/** + * Free all allocated objects in obj. + */ +void av_opt_free(void *obj); + +/** + * Check whether a particular flag is set in a flags field. + * + * @param field_name the name of the flag field option + * @param flag_name the name of the flag to check + * @return non-zero if the flag is set, zero if the flag isn't set, + * isn't of the right type, or the flags field doesn't exist. + */ +int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name); + +/** + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict(void *obj, struct AVDictionary **options); + + +/** + * Set all the options from a given dictionary on an object. + * + * @param obj a struct whose first element is a pointer to AVClass + * @param options options to process. This dictionary will be freed and replaced + * by a new one containing all options not found in obj. + * Of course this new dictionary needs to be freed by caller + * with av_dict_free(). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return 0 on success, a negative AVERROR if some option was found in obj, + * but could not be set. + * + * @see av_dict_copy() + */ +int av_opt_set_dict2(void *obj, struct AVDictionary **options, int search_flags); + +/** + * Extract a key-value pair from the beginning of a string. + * + * @param ropts pointer to the options string, will be updated to + * point to the rest of the string (one of the pairs_sep + * or the final NUL) + * @param key_val_sep a 0-terminated list of characters used to separate + * key from value, for example '=' + * @param pairs_sep a 0-terminated list of characters used to separate + * two pairs from each other, for example ':' or ',' + * @param flags flags; see the AV_OPT_FLAG_* values below + * @param rkey parsed key; must be freed using av_free() + * @param rval parsed value; must be freed using av_free() + * + * @return >=0 for success, or a negative value corresponding to an + * AVERROR code in case of error; in particular: + * AVERROR(EINVAL) if no key is present + * + */ +int av_opt_get_key_value(const char **ropts, + const char *key_val_sep, const char *pairs_sep, + unsigned flags, + char **rkey, char **rval); + +enum { + + /** + * Accept to parse a value without a key; the key will then be returned + * as NULL. + */ + AV_OPT_FLAG_IMPLICIT_KEY = 1, +}; + +/** + * @defgroup opt_eval_funcs Evaluating option strings + * @{ + * This group of functions can be used to evaluate option strings + * and get numbers out of them. They do the same thing as av_opt_set(), + * except the result is written into the caller-supplied pointer. + * + * @param obj a struct whose first element is a pointer to AVClass. + * @param o an option for which the string is to be evaluated. + * @param val string to be evaluated. + * @param *_out value of the string will be written here. + * + * @return 0 on success, a negative number on failure. + */ +int av_opt_eval_flags (void *obj, const AVOption *o, const char *val, int *flags_out); +int av_opt_eval_int (void *obj, const AVOption *o, const char *val, int *int_out); +int av_opt_eval_int64 (void *obj, const AVOption *o, const char *val, int64_t *int64_out); +int av_opt_eval_float (void *obj, const AVOption *o, const char *val, float *float_out); +int av_opt_eval_double(void *obj, const AVOption *o, const char *val, double *double_out); +int av_opt_eval_q (void *obj, const AVOption *o, const char *val, AVRational *q_out); +/** + * @} + */ + +#define AV_OPT_SEARCH_CHILDREN (1 << 0) /**< Search in possible children of the + given object first. */ +/** + * The obj passed to av_opt_find() is fake -- only a double pointer to AVClass + * instead of a required pointer to a struct containing AVClass. This is + * useful for searching for options without needing to allocate the corresponding + * object. + */ +#define AV_OPT_SEARCH_FAKE_OBJ (1 << 1) + +/** + * In av_opt_get, return NULL if the option has a pointer type and is set to NULL, + * rather than returning an empty string. + */ +#define AV_OPT_ALLOW_NULL (1 << 2) + +/** + * Allows av_opt_query_ranges and av_opt_query_ranges_default to return more than + * one component for certain option types. + * @see AVOptionRanges for details. + */ +#define AV_OPT_MULTI_COMPONENT_RANGE (1 << 12) + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * Alternatively a double pointer to an AVClass, if + * AV_OPT_SEARCH_FAKE_OBJ search flag is set. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * + * @return A pointer to the option found, or NULL if no option + * was found. + * + * @note Options found with AV_OPT_SEARCH_CHILDREN flag may not be settable + * directly with av_opt_set(). Use special calls which take an options + * AVDictionary (e.g. avformat_open_input()) to set options found with this + * flag. + */ +const AVOption *av_opt_find(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags); + +/** + * Look for an option in an object. Consider only options which + * have all the specified flags set. + * + * @param[in] obj A pointer to a struct whose first element is a + * pointer to an AVClass. + * Alternatively a double pointer to an AVClass, if + * AV_OPT_SEARCH_FAKE_OBJ search flag is set. + * @param[in] name The name of the option to look for. + * @param[in] unit When searching for named constants, name of the unit + * it belongs to. + * @param opt_flags Find only options with all the specified flags set (AV_OPT_FLAG). + * @param search_flags A combination of AV_OPT_SEARCH_*. + * @param[out] target_obj if non-NULL, an object to which the option belongs will be + * written here. It may be different from obj if AV_OPT_SEARCH_CHILDREN is present + * in search_flags. This parameter is ignored if search_flags contain + * AV_OPT_SEARCH_FAKE_OBJ. + * + * @return A pointer to the option found, or NULL if no option + * was found. + */ +const AVOption *av_opt_find2(void *obj, const char *name, const char *unit, + int opt_flags, int search_flags, void **target_obj); + +/** + * Iterate over all AVOptions belonging to obj. + * + * @param obj an AVOptions-enabled struct or a double pointer to an + * AVClass describing it. + * @param prev result of the previous call to av_opt_next() on this object + * or NULL + * @return next AVOption or NULL + */ +const AVOption *av_opt_next(const void *obj, const AVOption *prev); + +/** + * Iterate over AVOptions-enabled children of obj. + * + * @param prev result of a previous call to this function or NULL + * @return next AVOptions-enabled child or NULL + */ +void *av_opt_child_next(void *obj, void *prev); + +/** + * Iterate over potential AVOptions-enabled children of parent. + * + * @param prev result of a previous call to this function or NULL + * @return AVClass corresponding to next potential child or NULL + */ +const AVClass *av_opt_child_class_next(const AVClass *parent, const AVClass *prev); + +/** + * @defgroup opt_set_funcs Option setting functions + * @{ + * Those functions set the field of obj with the given name to value. + * + * @param[in] obj A struct whose first element is a pointer to an AVClass. + * @param[in] name the name of the field to set + * @param[in] val The value to set. In case of av_opt_set() if the field is not + * of a string type, then the given string is parsed. + * SI postfixes and some named scalars are supported. + * If the field is of a numeric type, it has to be a numeric or named + * scalar. Behavior with more than one scalar and +- infix operators + * is undefined. + * If the field is of a flags type, it has to be a sequence of numeric + * scalars or named flags separated by '+' or '-'. Prefixing a flag + * with '+' causes it to be set without affecting the other flags; + * similarly, '-' unsets a flag. + * @param search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN + * is passed here, then the option may be set on a child of obj. + * + * @return 0 if the value has been set, or an AVERROR code in case of + * error: + * AVERROR_OPTION_NOT_FOUND if no matching option exists + * AVERROR(ERANGE) if the value is out of range + * AVERROR(EINVAL) if the value is not valid + */ +int av_opt_set (void *obj, const char *name, const char *val, int search_flags); +int av_opt_set_int (void *obj, const char *name, int64_t val, int search_flags); +int av_opt_set_double (void *obj, const char *name, double val, int search_flags); +int av_opt_set_q (void *obj, const char *name, AVRational val, int search_flags); +int av_opt_set_bin (void *obj, const char *name, const uint8_t *val, int size, int search_flags); +int av_opt_set_image_size(void *obj, const char *name, int w, int h, int search_flags); +int av_opt_set_pixel_fmt (void *obj, const char *name, enum AVPixelFormat fmt, int search_flags); +int av_opt_set_sample_fmt(void *obj, const char *name, enum AVSampleFormat fmt, int search_flags); +int av_opt_set_video_rate(void *obj, const char *name, AVRational val, int search_flags); +int av_opt_set_channel_layout(void *obj, const char *name, int64_t ch_layout, int search_flags); +/** + * @note Any old dictionary present is discarded and replaced with a copy of the new one. The + * caller still owns val is and responsible for freeing it. + */ +int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, int search_flags); + +/** + * Set a binary option to an integer list. + * + * @param obj AVClass object to set options on + * @param name name of the binary option + * @param val pointer to an integer list (must have the correct type with + * regard to the contents of the list) + * @param term list terminator (usually 0 or -1) + * @param flags search flags + */ +#define av_opt_set_int_list(obj, name, val, term, flags) \ + (av_int_list_length(val, term) > INT_MAX / sizeof(*(val)) ? \ + AVERROR(EINVAL) : \ + av_opt_set_bin(obj, name, (const uint8_t *)(val), \ + av_int_list_length(val, term) * sizeof(*(val)), flags)) + +/** + * @} + */ + +/** + * @defgroup opt_get_funcs Option getting functions + * @{ + * Those functions get a value of the option with the given name from an object. + * + * @param[in] obj a struct whose first element is a pointer to an AVClass. + * @param[in] name name of the option to get. + * @param[in] search_flags flags passed to av_opt_find2. I.e. if AV_OPT_SEARCH_CHILDREN + * is passed here, then the option may be found in a child of obj. + * @param[out] out_val value of the option will be written here + * @return >=0 on success, a negative error code otherwise + */ +/** + * @note the returned string will be av_malloc()ed and must be av_free()ed by the caller + * + * @note if AV_OPT_ALLOW_NULL is set in search_flags in av_opt_get, and the option has + * AV_OPT_TYPE_STRING or AV_OPT_TYPE_BINARY and is set to NULL, *out_val will be set + * to NULL instead of an allocated empty string. + */ +int av_opt_get (void *obj, const char *name, int search_flags, uint8_t **out_val); +int av_opt_get_int (void *obj, const char *name, int search_flags, int64_t *out_val); +int av_opt_get_double (void *obj, const char *name, int search_flags, double *out_val); +int av_opt_get_q (void *obj, const char *name, int search_flags, AVRational *out_val); +int av_opt_get_image_size(void *obj, const char *name, int search_flags, int *w_out, int *h_out); +int av_opt_get_pixel_fmt (void *obj, const char *name, int search_flags, enum AVPixelFormat *out_fmt); +int av_opt_get_sample_fmt(void *obj, const char *name, int search_flags, enum AVSampleFormat *out_fmt); +int av_opt_get_video_rate(void *obj, const char *name, int search_flags, AVRational *out_val); +int av_opt_get_channel_layout(void *obj, const char *name, int search_flags, int64_t *ch_layout); +/** + * @param[out] out_val The returned dictionary is a copy of the actual value and must + * be freed with av_dict_free() by the caller + */ +int av_opt_get_dict_val(void *obj, const char *name, int search_flags, AVDictionary **out_val); +/** + * @} + */ +/** + * Gets a pointer to the requested field in a struct. + * This function allows accessing a struct even when its fields are moved or + * renamed since the application making the access has been compiled, + * + * @returns a pointer to the field, it can be cast to the correct type and read + * or written to. + */ +void *av_opt_ptr(const AVClass *avclass, void *obj, const char *name); + +/** + * Free an AVOptionRanges struct and set it to NULL. + */ +void av_opt_freep_ranges(AVOptionRanges **ranges); + +/** + * Get a list of allowed ranges for the given option. + * + * The returned list may depend on other fields in obj like for example profile. + * + * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored + * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance + * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges + * + * The result must be freed with av_opt_freep_ranges. + * + * @return number of compontents returned on success, a negative errro code otherwise + */ +int av_opt_query_ranges(AVOptionRanges **, void *obj, const char *key, int flags); + +/** + * Copy options from src object into dest object. + * + * Options that require memory allocation (e.g. string or binary) are malloc'ed in dest object. + * Original memory allocated for such options is freed unless both src and dest options points to the same memory. + * + * @param dest Object to copy from + * @param src Object to copy into + * @return 0 on success, negative on error + */ +int av_opt_copy(void *dest, const void *src); + +/** + * Get a default list of allowed ranges for the given option. + * + * This list is constructed without using the AVClass.query_ranges() callback + * and can be used as fallback from within the callback. + * + * @param flags is a bitmask of flags, undefined flags should not be set and should be ignored + * AV_OPT_SEARCH_FAKE_OBJ indicates that the obj is a double pointer to a AVClass instead of a full instance + * AV_OPT_MULTI_COMPONENT_RANGE indicates that function may return more than one component, @see AVOptionRanges + * + * The result must be freed with av_opt_free_ranges. + * + * @return number of compontents returned on success, a negative errro code otherwise + */ +int av_opt_query_ranges_default(AVOptionRanges **, void *obj, const char *key, int flags); + +/** + * Check if given option is set to its default value. + * + * Options o must belong to the obj. This function must not be called to check child's options state. + * @see av_opt_is_set_to_default_by_name(). + * + * @param obj AVClass object to check option on + * @param o option to be checked + * @return >0 when option is set to its default, + * 0 when option is not set its default, + * <0 on error + */ +int av_opt_is_set_to_default(void *obj, const AVOption *o); + +/** + * Check if given option is set to its default value. + * + * @param obj AVClass object to check option on + * @param name option name + * @param search_flags combination of AV_OPT_SEARCH_* + * @return >0 when option is set to its default, + * 0 when option is not set its default, + * <0 on error + */ +int av_opt_is_set_to_default_by_name(void *obj, const char *name, int search_flags); + + +#define AV_OPT_SERIALIZE_SKIP_DEFAULTS 0x00000001 ///< Serialize options that are not set to default values only. +#define AV_OPT_SERIALIZE_OPT_FLAGS_EXACT 0x00000002 ///< Serialize options that exactly match opt_flags only. + +/** + * Serialize object's options. + * + * Create a string containing object's serialized options. + * Such string may be passed back to av_opt_set_from_string() in order to restore option values. + * A key/value or pairs separator occurring in the serialized value or + * name string are escaped through the av_escape() function. + * + * @param[in] obj AVClass object to serialize + * @param[in] opt_flags serialize options with all the specified flags set (AV_OPT_FLAG) + * @param[in] flags combination of AV_OPT_SERIALIZE_* flags + * @param[out] buffer Pointer to buffer that will be allocated with string containg serialized options. + * Buffer must be freed by the caller when is no longer needed. + * @param[in] key_val_sep character used to separate key from value + * @param[in] pairs_sep character used to separate two pairs from each other + * @return >= 0 on success, negative on error + * @warning Separators cannot be neither '\\' nor '\0'. They also cannot be the same. + */ +int av_opt_serialize(void *obj, int opt_flags, int flags, char **buffer, + const char key_val_sep, const char pairs_sep); +/** + * @} + */ + +#endif /* AVUTIL_OPT_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/parseutils.h b/TMessagesProj/jni/ffmpeg/include/libavutil/parseutils.h new file mode 100644 index 00000000..e66d24b7 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/parseutils.h @@ -0,0 +1,193 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PARSEUTILS_H +#define AVUTIL_PARSEUTILS_H + +#include + +#include "rational.h" + +/** + * @file + * misc parsing utilities + */ + +/** + * Parse str and store the parsed ratio in q. + * + * Note that a ratio with infinite (1/0) or negative value is + * considered valid, so you should check on the returned value if you + * want to exclude those values. + * + * The undefined value can be expressed using the "0:0" string. + * + * @param[in,out] q pointer to the AVRational which will contain the ratio + * @param[in] str the string to parse: it has to be a string in the format + * num:den, a float number or an expression + * @param[in] max the maximum allowed numerator and denominator + * @param[in] log_offset log level offset which is applied to the log + * level of log_ctx + * @param[in] log_ctx parent logging context + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_ratio(AVRational *q, const char *str, int max, + int log_offset, void *log_ctx); + +#define av_parse_ratio_quiet(rate, str, max) \ + av_parse_ratio(rate, str, max, AV_LOG_MAX_OFFSET, NULL) + +/** + * Parse str and put in width_ptr and height_ptr the detected values. + * + * @param[in,out] width_ptr pointer to the variable which will contain the detected + * width value + * @param[in,out] height_ptr pointer to the variable which will contain the detected + * height value + * @param[in] str the string to parse: it has to be a string in the format + * width x height or a valid video size abbreviation. + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_video_size(int *width_ptr, int *height_ptr, const char *str); + +/** + * Parse str and store the detected values in *rate. + * + * @param[in,out] rate pointer to the AVRational which will contain the detected + * frame rate + * @param[in] str the string to parse: it has to be a string in the format + * rate_num / rate_den, a float number or a valid video rate abbreviation + * @return >= 0 on success, a negative error code otherwise + */ +int av_parse_video_rate(AVRational *rate, const char *str); + +/** + * Put the RGBA values that correspond to color_string in rgba_color. + * + * @param color_string a string specifying a color. It can be the name of + * a color (case insensitive match) or a [0x|#]RRGGBB[AA] sequence, + * possibly followed by "@" and a string representing the alpha + * component. + * The alpha component may be a string composed by "0x" followed by an + * hexadecimal number or a decimal number between 0.0 and 1.0, which + * represents the opacity value (0x00/0.0 means completely transparent, + * 0xff/1.0 completely opaque). + * If the alpha component is not specified then 0xff is assumed. + * The string "random" will result in a random color. + * @param slen length of the initial part of color_string containing the + * color. It can be set to -1 if color_string is a null terminated string + * containing nothing else than the color. + * @return >= 0 in case of success, a negative value in case of + * failure (for example if color_string cannot be parsed). + */ +int av_parse_color(uint8_t *rgba_color, const char *color_string, int slen, + void *log_ctx); + +/** + * Get the name of a color from the internal table of hard-coded named + * colors. + * + * This function is meant to enumerate the color names recognized by + * av_parse_color(). + * + * @param color_idx index of the requested color, starting from 0 + * @param rgbp if not NULL, will point to a 3-elements array with the color value in RGB + * @return the color name string or NULL if color_idx is not in the array + */ +const char *av_get_known_color_name(int color_idx, const uint8_t **rgb); + +/** + * Parse timestr and return in *time a corresponding number of + * microseconds. + * + * @param timeval puts here the number of microseconds corresponding + * to the string in timestr. If the string represents a duration, it + * is the number of microseconds contained in the time interval. If + * the string is a date, is the number of microseconds since 1st of + * January, 1970 up to the time of the parsed date. If timestr cannot + * be successfully parsed, set *time to INT64_MIN. + + * @param timestr a string representing a date or a duration. + * - If a date the syntax is: + * @code + * [{YYYY-MM-DD|YYYYMMDD}[T|t| ]]{{HH:MM:SS[.m...]]]}|{HHMMSS[.m...]]]}}[Z] + * now + * @endcode + * If the value is "now" it takes the current time. + * Time is local time unless Z is appended, in which case it is + * interpreted as UTC. + * If the year-month-day part is not specified it takes the current + * year-month-day. + * - If a duration the syntax is: + * @code + * [-][HH:]MM:SS[.m...] + * [-]S+[.m...] + * @endcode + * @param duration flag which tells how to interpret timestr, if not + * zero timestr is interpreted as a duration, otherwise as a date + * @return >= 0 in case of success, a negative value corresponding to an + * AVERROR code otherwise + */ +int av_parse_time(int64_t *timeval, const char *timestr, int duration); + +/** + * Attempt to find a specific tag in a URL. + * + * syntax: '?tag1=val1&tag2=val2...'. Little URL decoding is done. + * Return 1 if found. + */ +int av_find_info_tag(char *arg, int arg_size, const char *tag1, const char *info); + +/** + * Simplified version of strptime + * + * Parse the input string p according to the format string fmt and + * store its results in the structure dt. + * This implementation supports only a subset of the formats supported + * by the standard strptime(). + * + * The supported input field descriptors are listed below. + * - %H: the hour as a decimal number, using a 24-hour clock, in the + * range '00' through '23' + * - %J: hours as a decimal number, in the range '0' through INT_MAX + * - %M: the minute as a decimal number, using a 24-hour clock, in the + * range '00' through '59' + * - %S: the second as a decimal number, using a 24-hour clock, in the + * range '00' through '59' + * - %Y: the year as a decimal number, using the Gregorian calendar + * - %m: the month as a decimal number, in the range '1' through '12' + * - %d: the day of the month as a decimal number, in the range '1' + * through '31' + * - %T: alias for '%H:%M:%S' + * - %%: a literal '%' + * + * @return a pointer to the first character not processed in this function + * call. In case the input string contains more characters than + * required by the format string the return value points right after + * the last consumed input character. In case the whole input string + * is consumed the return value points to the null byte at the end of + * the string. On failure NULL is returned. + */ +char *av_small_strptime(const char *p, const char *fmt, struct tm *dt); + +/** + * Convert the decomposed UTC time in tm to a time_t value. + */ +time_t av_timegm(struct tm *tm); + +#endif /* AVUTIL_PARSEUTILS_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/pixdesc.h b/TMessagesProj/jni/ffmpeg/include/libavutil/pixdesc.h new file mode 100644 index 00000000..a6056fe1 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/pixdesc.h @@ -0,0 +1,394 @@ +/* + * pixel format descriptor + * Copyright (c) 2009 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXDESC_H +#define AVUTIL_PIXDESC_H + +#include + +#include "attributes.h" +#include "pixfmt.h" +#include "version.h" + +typedef struct AVComponentDescriptor { + /** + * Which of the 4 planes contains the component. + */ + int plane; + + /** + * Number of elements between 2 horizontally consecutive pixels. + * Elements are bits for bitstream formats, bytes otherwise. + */ + int step; + + /** + * Number of elements before the component of the first pixel. + * Elements are bits for bitstream formats, bytes otherwise. + */ + int offset; + + /** + * Number of least significant bits that must be shifted away + * to get the value. + */ + int shift; + + /** + * Number of bits in the component. + */ + int depth; + +#if FF_API_PLUS1_MINUS1 + /** deprecated, use step instead */ + attribute_deprecated int step_minus1; + + /** deprecated, use depth instead */ + attribute_deprecated int depth_minus1; + + /** deprecated, use offset instead */ + attribute_deprecated int offset_plus1; +#endif +} AVComponentDescriptor; + +/** + * Descriptor that unambiguously describes how the bits of a pixel are + * stored in the up to 4 data planes of an image. It also stores the + * subsampling factors and number of components. + * + * @note This is separate of the colorspace (RGB, YCbCr, YPbPr, JPEG-style YUV + * and all the YUV variants) AVPixFmtDescriptor just stores how values + * are stored not what these values represent. + */ +typedef struct AVPixFmtDescriptor { + const char *name; + uint8_t nb_components; ///< The number of components each pixel has, (1-4) + + /** + * Amount to shift the luma width right to find the chroma width. + * For YV12 this is 1 for example. + * chroma_width = -((-luma_width) >> log2_chroma_w) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_w; ///< chroma_width = -((-luma_width )>>log2_chroma_w) + + /** + * Amount to shift the luma height right to find the chroma height. + * For YV12 this is 1 for example. + * chroma_height= -((-luma_height) >> log2_chroma_h) + * The note above is needed to ensure rounding up. + * This value only refers to the chroma components. + */ + uint8_t log2_chroma_h; + + /** + * Combination of AV_PIX_FMT_FLAG_... flags. + */ + uint64_t flags; + + /** + * Parameters that describe how pixels are packed. + * If the format has 1 or 2 components, then luma is 0. + * If the format has 3 or 4 components: + * if the RGB flag is set then 0 is red, 1 is green and 2 is blue; + * otherwise 0 is luma, 1 is chroma-U and 2 is chroma-V. + * + * If present, the Alpha channel is always the last component. + */ + AVComponentDescriptor comp[4]; + + /** + * Alternative comma-separated names. + */ + const char *alias; +} AVPixFmtDescriptor; + +/** + * Pixel format is big-endian. + */ +#define AV_PIX_FMT_FLAG_BE (1 << 0) +/** + * Pixel format has a palette in data[1], values are indexes in this palette. + */ +#define AV_PIX_FMT_FLAG_PAL (1 << 1) +/** + * All values of a component are bit-wise packed end to end. + */ +#define AV_PIX_FMT_FLAG_BITSTREAM (1 << 2) +/** + * Pixel format is an HW accelerated format. + */ +#define AV_PIX_FMT_FLAG_HWACCEL (1 << 3) +/** + * At least one pixel component is not in the first data plane. + */ +#define AV_PIX_FMT_FLAG_PLANAR (1 << 4) +/** + * The pixel format contains RGB-like data (as opposed to YUV/grayscale). + */ +#define AV_PIX_FMT_FLAG_RGB (1 << 5) + +/** + * The pixel format is "pseudo-paletted". This means that it contains a + * fixed palette in the 2nd plane but the palette is fixed/constant for each + * PIX_FMT. This allows interpreting the data as if it was PAL8, which can + * in some cases be simpler. Or the data can be interpreted purely based on + * the pixel format without using the palette. + * An example of a pseudo-paletted format is AV_PIX_FMT_GRAY8 + */ +#define AV_PIX_FMT_FLAG_PSEUDOPAL (1 << 6) + +/** + * The pixel format has an alpha channel. This is set on all formats that + * support alpha in some way. The exception is AV_PIX_FMT_PAL8, which can + * carry alpha as part of the palette. Details are explained in the + * AVPixelFormat enum, and are also encoded in the corresponding + * AVPixFmtDescriptor. + * + * The alpha is always straight, never pre-multiplied. + * + * If a codec or a filter does not support alpha, it should set all alpha to + * opaque, or use the equivalent pixel formats without alpha component, e.g. + * AV_PIX_FMT_RGB0 (or AV_PIX_FMT_RGB24 etc.) instead of AV_PIX_FMT_RGBA. + */ +#define AV_PIX_FMT_FLAG_ALPHA (1 << 7) + +/** + * Read a line from an image, and write the values of the + * pixel format component c to dst. + * + * @param data the array containing the pointers to the planes of the image + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to read + * @param y the vertical coordinate of the first pixel to read + * @param w the width of the line to read, that is the number of + * values to write to dst + * @param read_pal_component if not zero and the format is a paletted + * format writes the values corresponding to the palette + * component c in data[1] to dst, rather than the palette indexes in + * data[0]. The behavior is undefined if the format is not paletted. + */ +void av_read_image_line(uint16_t *dst, const uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w, int read_pal_component); + +/** + * Write the values from src to the pixel format component c of an + * image line. + * + * @param src array containing the values to write + * @param data the array containing the pointers to the planes of the + * image to write into. It is supposed to be zeroed. + * @param linesize the array containing the linesizes of the image + * @param desc the pixel format descriptor for the image + * @param x the horizontal coordinate of the first pixel to write + * @param y the vertical coordinate of the first pixel to write + * @param w the width of the line to write, that is the number of + * values to write to the image line + */ +void av_write_image_line(const uint16_t *src, uint8_t *data[4], + const int linesize[4], const AVPixFmtDescriptor *desc, + int x, int y, int c, int w); + +/** + * Return the pixel format corresponding to name. + * + * If there is no pixel format with name name, then looks for a + * pixel format with the name corresponding to the native endian + * format of name. + * For example in a little-endian system, first looks for "gray16", + * then for "gray16le". + * + * Finally if no pixel format has been found, returns AV_PIX_FMT_NONE. + */ +enum AVPixelFormat av_get_pix_fmt(const char *name); + +/** + * Return the short name for a pixel format, NULL in case pix_fmt is + * unknown. + * + * @see av_get_pix_fmt(), av_get_pix_fmt_string() + */ +const char *av_get_pix_fmt_name(enum AVPixelFormat pix_fmt); + +/** + * Print in buf the string corresponding to the pixel format with + * number pix_fmt, or a header if pix_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param pix_fmt the number of the pixel format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + */ +char *av_get_pix_fmt_string(char *buf, int buf_size, + enum AVPixelFormat pix_fmt); + +/** + * Return the number of bits per pixel used by the pixel format + * described by pixdesc. Note that this is not the same as the number + * of bits per sample. + * + * The returned number of bits refers to the number of bits actually + * used for storing the pixel information, that is padding bits are + * not counted. + */ +int av_get_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * Return the number of bits per pixel for the pixel format + * described by pixdesc, including any padding or unused bits. + */ +int av_get_padded_bits_per_pixel(const AVPixFmtDescriptor *pixdesc); + +/** + * @return a pixel format descriptor for provided pixel format or NULL if + * this pixel format is unknown. + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt); + +/** + * Iterate over all pixel format descriptors known to libavutil. + * + * @param prev previous descriptor. NULL to get the first descriptor. + * + * @return next descriptor or NULL after the last descriptor + */ +const AVPixFmtDescriptor *av_pix_fmt_desc_next(const AVPixFmtDescriptor *prev); + +/** + * @return an AVPixelFormat id described by desc, or AV_PIX_FMT_NONE if desc + * is not a valid pointer to a pixel format descriptor. + */ +enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc); + +/** + * Utility function to access log2_chroma_w log2_chroma_h from + * the pixel format AVPixFmtDescriptor. + * + * See av_get_chroma_sub_sample() for a function that asserts a + * valid pixel format instead of returning an error code. + * Its recommended that you use avcodec_get_chroma_sub_sample unless + * you do check the return code! + * + * @param[in] pix_fmt the pixel format + * @param[out] h_shift store log2_chroma_w + * @param[out] v_shift store log2_chroma_h + * + * @return 0 on success, AVERROR(ENOSYS) on invalid or unknown pixel format + */ +int av_pix_fmt_get_chroma_sub_sample(enum AVPixelFormat pix_fmt, + int *h_shift, int *v_shift); + +/** + * @return number of planes in pix_fmt, a negative AVERROR if pix_fmt is not a + * valid pixel format. + */ +int av_pix_fmt_count_planes(enum AVPixelFormat pix_fmt); + +/** + * Utility function to swap the endianness of a pixel format. + * + * @param[in] pix_fmt the pixel format + * + * @return pixel format with swapped endianness if it exists, + * otherwise AV_PIX_FMT_NONE + */ +enum AVPixelFormat av_pix_fmt_swap_endianness(enum AVPixelFormat pix_fmt); + +#define FF_LOSS_RESOLUTION 0x0001 /**< loss due to resolution change */ +#define FF_LOSS_DEPTH 0x0002 /**< loss due to color depth change */ +#define FF_LOSS_COLORSPACE 0x0004 /**< loss due to color space conversion */ +#define FF_LOSS_ALPHA 0x0008 /**< loss of alpha bits */ +#define FF_LOSS_COLORQUANT 0x0010 /**< loss due to color quantization */ +#define FF_LOSS_CHROMA 0x0020 /**< loss of chroma (e.g. RGB to gray conversion) */ + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +int av_get_pix_fmt_loss(enum AVPixelFormat dst_pix_fmt, + enum AVPixelFormat src_pix_fmt, + int has_alpha); + +/** + * Compute what kind of losses will occur when converting from one specific + * pixel format to another. + * When converting from one pixel format to another, information loss may occur. + * For example, when converting from RGB24 to GRAY, the color information will + * be lost. Similarly, other losses occur when converting from some formats to + * other formats. These losses can involve loss of chroma, but also loss of + * resolution, loss of color depth, loss due to the color space conversion, loss + * of the alpha bits or loss due to color quantization. + * av_get_fix_fmt_loss() informs you about the various types of losses + * which will occur when converting from one pixel format to another. + * + * @param[in] dst_pix_fmt destination pixel format + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @return Combination of flags informing you what kind of losses will occur + * (maximum loss for an invalid dst_pix_fmt). + */ +enum AVPixelFormat av_find_best_pix_fmt_of_2(enum AVPixelFormat dst_pix_fmt1, enum AVPixelFormat dst_pix_fmt2, + enum AVPixelFormat src_pix_fmt, int has_alpha, int *loss_ptr); + +/** + * @return the name for provided color range or NULL if unknown. + */ +const char *av_color_range_name(enum AVColorRange range); + +/** + * @return the name for provided color primaries or NULL if unknown. + */ +const char *av_color_primaries_name(enum AVColorPrimaries primaries); + +/** + * @return the name for provided color transfer or NULL if unknown. + */ +const char *av_color_transfer_name(enum AVColorTransferCharacteristic transfer); + +/** + * @return the name for provided color space or NULL if unknown. + */ +const char *av_color_space_name(enum AVColorSpace space); + +/** + * @return the name for provided chroma location or NULL if unknown. + */ +const char *av_chroma_location_name(enum AVChromaLocation location); + +#endif /* AVUTIL_PIXDESC_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/pixelutils.h b/TMessagesProj/jni/ffmpeg/include/libavutil/pixelutils.h new file mode 100644 index 00000000..a8dbc157 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/pixelutils.h @@ -0,0 +1,52 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXELUTILS_H +#define AVUTIL_PIXELUTILS_H + +#include +#include +#include "common.h" + +/** + * Sum of abs(src1[x] - src2[x]) + */ +typedef int (*av_pixelutils_sad_fn)(const uint8_t *src1, ptrdiff_t stride1, + const uint8_t *src2, ptrdiff_t stride2); + +/** + * Get a potentially optimized pointer to a Sum-of-absolute-differences + * function (see the av_pixelutils_sad_fn prototype). + * + * @param w_bits 1< + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_PIXFMT_H +#define AVUTIL_PIXFMT_H + +/** + * @file + * pixel format definitions + * + */ + +#include "libavutil/avconfig.h" +#include "version.h" + +#define AVPALETTE_SIZE 1024 +#define AVPALETTE_COUNT 256 + +/** + * Pixel format. + * + * @note + * AV_PIX_FMT_RGB32 is handled in an endian-specific manner. An RGBA + * color is put together as: + * (A << 24) | (R << 16) | (G << 8) | B + * This is stored as BGRA on little-endian CPU architectures and ARGB on + * big-endian CPUs. + * + * @par + * When the pixel format is palettized RGB32 (AV_PIX_FMT_PAL8), the palettized + * image data is stored in AVFrame.data[0]. The palette is transported in + * AVFrame.data[1], is 1024 bytes long (256 4-byte entries) and is + * formatted the same as in AV_PIX_FMT_RGB32 described above (i.e., it is + * also endian-specific). Note also that the individual RGB32 palette + * components stored in AVFrame.data[1] should be in the range 0..255. + * This is important as many custom PAL8 video codecs that were designed + * to run on the IBM VGA graphics adapter use 6-bit palette components. + * + * @par + * For all the 8bit per pixel formats, an RGB32 palette is in data[1] like + * for pal8. This palette is filled in automatically by the function + * allocating the picture. + */ +enum AVPixelFormat { + AV_PIX_FMT_NONE = -1, + AV_PIX_FMT_YUV420P, ///< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) + AV_PIX_FMT_YUYV422, ///< packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr + AV_PIX_FMT_RGB24, ///< packed RGB 8:8:8, 24bpp, RGBRGB... + AV_PIX_FMT_BGR24, ///< packed RGB 8:8:8, 24bpp, BGRBGR... + AV_PIX_FMT_YUV422P, ///< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + AV_PIX_FMT_YUV444P, ///< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) + AV_PIX_FMT_YUV410P, ///< planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) + AV_PIX_FMT_YUV411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) + AV_PIX_FMT_GRAY8, ///< Y , 8bpp + AV_PIX_FMT_MONOWHITE, ///< Y , 1bpp, 0 is white, 1 is black, in each byte pixels are ordered from the msb to the lsb + AV_PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black, 1 is white, in each byte pixels are ordered from the msb to the lsb + AV_PIX_FMT_PAL8, ///< 8 bit with AV_PIX_FMT_RGB32 palette + AV_PIX_FMT_YUVJ420P, ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting color_range + AV_PIX_FMT_YUVJ422P, ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting color_range + AV_PIX_FMT_YUVJ444P, ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting color_range +#if FF_API_XVMC + AV_PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing + AV_PIX_FMT_XVMC_MPEG2_IDCT, +#define AV_PIX_FMT_XVMC AV_PIX_FMT_XVMC_MPEG2_IDCT +#endif /* FF_API_XVMC */ + AV_PIX_FMT_UYVY422, ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 + AV_PIX_FMT_UYYVYY411, ///< packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 + AV_PIX_FMT_BGR8, ///< packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb) + AV_PIX_FMT_BGR4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1B 2G 1R(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + AV_PIX_FMT_BGR4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb) + AV_PIX_FMT_RGB8, ///< packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb) + AV_PIX_FMT_RGB4, ///< packed RGB 1:2:1 bitstream, 4bpp, (msb)1R 2G 1B(lsb), a byte contains two pixels, the first pixel in the byte is the one composed by the 4 msb bits + AV_PIX_FMT_RGB4_BYTE, ///< packed RGB 1:2:1, 8bpp, (msb)1R 2G 1B(lsb) + AV_PIX_FMT_NV12, ///< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V) + AV_PIX_FMT_NV21, ///< as above, but U and V bytes are swapped + + AV_PIX_FMT_ARGB, ///< packed ARGB 8:8:8:8, 32bpp, ARGBARGB... + AV_PIX_FMT_RGBA, ///< packed RGBA 8:8:8:8, 32bpp, RGBARGBA... + AV_PIX_FMT_ABGR, ///< packed ABGR 8:8:8:8, 32bpp, ABGRABGR... + AV_PIX_FMT_BGRA, ///< packed BGRA 8:8:8:8, 32bpp, BGRABGRA... + + AV_PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian + AV_PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian + AV_PIX_FMT_YUV440P, ///< planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples) + AV_PIX_FMT_YUVJ440P, ///< planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range + AV_PIX_FMT_YUVA420P, ///< planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples) +#if FF_API_VDPAU + AV_PIX_FMT_VDPAU_H264,///< H.264 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + AV_PIX_FMT_VDPAU_MPEG1,///< MPEG-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + AV_PIX_FMT_VDPAU_MPEG2,///< MPEG-2 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + AV_PIX_FMT_VDPAU_WMV3,///< WMV3 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + AV_PIX_FMT_VDPAU_VC1, ///< VC-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers +#endif + AV_PIX_FMT_RGB48BE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as big-endian + AV_PIX_FMT_RGB48LE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as little-endian + + AV_PIX_FMT_RGB565BE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), big-endian + AV_PIX_FMT_RGB565LE, ///< packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), little-endian + AV_PIX_FMT_RGB555BE, ///< packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), big-endian , X=unused/undefined + AV_PIX_FMT_RGB555LE, ///< packed RGB 5:5:5, 16bpp, (msb)1X 5R 5G 5B(lsb), little-endian, X=unused/undefined + + AV_PIX_FMT_BGR565BE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), big-endian + AV_PIX_FMT_BGR565LE, ///< packed BGR 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), little-endian + AV_PIX_FMT_BGR555BE, ///< packed BGR 5:5:5, 16bpp, (msb)1X 5B 5G 5R(lsb), big-endian , X=unused/undefined + AV_PIX_FMT_BGR555LE, ///< packed BGR 5:5:5, 16bpp, (msb)1X 5B 5G 5R(lsb), little-endian, X=unused/undefined + +#if FF_API_VAAPI + /** @name Deprecated pixel formats */ + /**@{*/ + AV_PIX_FMT_VAAPI_MOCO, ///< HW acceleration through VA API at motion compensation entry-point, Picture.data[3] contains a vaapi_render_state struct which contains macroblocks as well as various fields extracted from headers + AV_PIX_FMT_VAAPI_IDCT, ///< HW acceleration through VA API at IDCT entry-point, Picture.data[3] contains a vaapi_render_state struct which contains fields extracted from headers + AV_PIX_FMT_VAAPI_VLD, ///< HW decoding through VA API, Picture.data[3] contains a vaapi_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers + /**@}*/ + AV_PIX_FMT_VAAPI = AV_PIX_FMT_VAAPI_VLD, +#else + /** + * Hardware acceleration through VA-API, data[3] contains a + * VASurfaceID. + */ + AV_PIX_FMT_VAAPI, +#endif + + AV_PIX_FMT_YUV420P16LE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P16BE, ///< planar YUV 4:2:0, 24bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV422P16LE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV422P16BE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV444P16LE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian +#if FF_API_VDPAU + AV_PIX_FMT_VDPAU_MPEG4, ///< MPEG4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers +#endif + AV_PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer + + AV_PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4X 4R 4G 4B(lsb), little-endian, X=unused/undefined + AV_PIX_FMT_RGB444BE, ///< packed RGB 4:4:4, 16bpp, (msb)4X 4R 4G 4B(lsb), big-endian, X=unused/undefined + AV_PIX_FMT_BGR444LE, ///< packed BGR 4:4:4, 16bpp, (msb)4X 4B 4G 4R(lsb), little-endian, X=unused/undefined + AV_PIX_FMT_BGR444BE, ///< packed BGR 4:4:4, 16bpp, (msb)4X 4B 4G 4R(lsb), big-endian, X=unused/undefined + AV_PIX_FMT_YA8, ///< 8bit gray, 8bit alpha + + AV_PIX_FMT_Y400A = AV_PIX_FMT_YA8, ///< alias for AV_PIX_FMT_YA8 + AV_PIX_FMT_GRAY8A= AV_PIX_FMT_YA8, ///< alias for AV_PIX_FMT_YA8 + + AV_PIX_FMT_BGR48BE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as big-endian + AV_PIX_FMT_BGR48LE, ///< packed RGB 16:16:16, 48bpp, 16B, 16G, 16R, the 2-byte value for each R/G/B component is stored as little-endian + + /** + * The following 12 formats have the disadvantage of needing 1 format for each bit depth. + * Notice that each 9/10 bits sample is stored in 16 bits with extra padding. + * If you want to support multiple bit depths, then using AV_PIX_FMT_YUV420P16* with the bpp stored separately is better. + */ + AV_PIX_FMT_YUV420P9BE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P9LE, ///< planar YUV 4:2:0, 13.5bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P10BE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P10LE,///< planar YUV 4:2:0, 15bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV422P10BE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P10LE,///< planar YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV444P9BE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P9LE, ///< planar YUV 4:4:4, 27bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P10BE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P10LE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV422P9BE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P9LE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_VDA_VLD, ///< hardware decoding through VDA + AV_PIX_FMT_GBRP, ///< planar GBR 4:4:4 24bpp + AV_PIX_FMT_GBRP9BE, ///< planar GBR 4:4:4 27bpp, big-endian + AV_PIX_FMT_GBRP9LE, ///< planar GBR 4:4:4 27bpp, little-endian + AV_PIX_FMT_GBRP10BE, ///< planar GBR 4:4:4 30bpp, big-endian + AV_PIX_FMT_GBRP10LE, ///< planar GBR 4:4:4 30bpp, little-endian + AV_PIX_FMT_GBRP16BE, ///< planar GBR 4:4:4 48bpp, big-endian + AV_PIX_FMT_GBRP16LE, ///< planar GBR 4:4:4 48bpp, little-endian + AV_PIX_FMT_YUVA422P, ///< planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples) + AV_PIX_FMT_YUVA444P, ///< planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples) + AV_PIX_FMT_YUVA420P9BE, ///< planar YUV 4:2:0 22.5bpp, (1 Cr & Cb sample per 2x2 Y & A samples), big-endian + AV_PIX_FMT_YUVA420P9LE, ///< planar YUV 4:2:0 22.5bpp, (1 Cr & Cb sample per 2x2 Y & A samples), little-endian + AV_PIX_FMT_YUVA422P9BE, ///< planar YUV 4:2:2 27bpp, (1 Cr & Cb sample per 2x1 Y & A samples), big-endian + AV_PIX_FMT_YUVA422P9LE, ///< planar YUV 4:2:2 27bpp, (1 Cr & Cb sample per 2x1 Y & A samples), little-endian + AV_PIX_FMT_YUVA444P9BE, ///< planar YUV 4:4:4 36bpp, (1 Cr & Cb sample per 1x1 Y & A samples), big-endian + AV_PIX_FMT_YUVA444P9LE, ///< planar YUV 4:4:4 36bpp, (1 Cr & Cb sample per 1x1 Y & A samples), little-endian + AV_PIX_FMT_YUVA420P10BE, ///< planar YUV 4:2:0 25bpp, (1 Cr & Cb sample per 2x2 Y & A samples, big-endian) + AV_PIX_FMT_YUVA420P10LE, ///< planar YUV 4:2:0 25bpp, (1 Cr & Cb sample per 2x2 Y & A samples, little-endian) + AV_PIX_FMT_YUVA422P10BE, ///< planar YUV 4:2:2 30bpp, (1 Cr & Cb sample per 2x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA422P10LE, ///< planar YUV 4:2:2 30bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA444P10BE, ///< planar YUV 4:4:4 40bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA444P10LE, ///< planar YUV 4:4:4 40bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA420P16BE, ///< planar YUV 4:2:0 40bpp, (1 Cr & Cb sample per 2x2 Y & A samples, big-endian) + AV_PIX_FMT_YUVA420P16LE, ///< planar YUV 4:2:0 40bpp, (1 Cr & Cb sample per 2x2 Y & A samples, little-endian) + AV_PIX_FMT_YUVA422P16BE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA422P16LE, ///< planar YUV 4:2:2 48bpp, (1 Cr & Cb sample per 2x1 Y & A samples, little-endian) + AV_PIX_FMT_YUVA444P16BE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, big-endian) + AV_PIX_FMT_YUVA444P16LE, ///< planar YUV 4:4:4 64bpp, (1 Cr & Cb sample per 1x1 Y & A samples, little-endian) + + AV_PIX_FMT_VDPAU, ///< HW acceleration through VDPAU, Picture.data[3] contains a VdpVideoSurface + + AV_PIX_FMT_XYZ12LE, ///< packed XYZ 4:4:4, 36 bpp, (msb) 12X, 12Y, 12Z (lsb), the 2-byte value for each X/Y/Z is stored as little-endian, the 4 lower bits are set to 0 + AV_PIX_FMT_XYZ12BE, ///< packed XYZ 4:4:4, 36 bpp, (msb) 12X, 12Y, 12Z (lsb), the 2-byte value for each X/Y/Z is stored as big-endian, the 4 lower bits are set to 0 + AV_PIX_FMT_NV16, ///< interleaved chroma YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + AV_PIX_FMT_NV20LE, ///< interleaved chroma YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_NV20BE, ///< interleaved chroma YUV 4:2:2, 20bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + + AV_PIX_FMT_RGBA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_RGBA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16R, 16G, 16B, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + AV_PIX_FMT_BGRA64BE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as big-endian + AV_PIX_FMT_BGRA64LE, ///< packed RGBA 16:16:16:16, 64bpp, 16B, 16G, 16R, 16A, the 2-byte value for each R/G/B/A component is stored as little-endian + + AV_PIX_FMT_YVYU422, ///< packed YUV 4:2:2, 16bpp, Y0 Cr Y1 Cb + + AV_PIX_FMT_VDA, ///< HW acceleration through VDA, data[3] contains a CVPixelBufferRef + + AV_PIX_FMT_YA16BE, ///< 16bit gray, 16bit alpha (big-endian) + AV_PIX_FMT_YA16LE, ///< 16bit gray, 16bit alpha (little-endian) + + AV_PIX_FMT_GBRAP, ///< planar GBRA 4:4:4:4 32bpp + AV_PIX_FMT_GBRAP16BE, ///< planar GBRA 4:4:4:4 64bpp, big-endian + AV_PIX_FMT_GBRAP16LE, ///< planar GBRA 4:4:4:4 64bpp, little-endian + /** + * HW acceleration through QSV, data[3] contains a pointer to the + * mfxFrameSurface1 structure. + */ + AV_PIX_FMT_QSV, + /** + * HW acceleration though MMAL, data[3] contains a pointer to the + * MMAL_BUFFER_HEADER_T structure. + */ + AV_PIX_FMT_MMAL, + + AV_PIX_FMT_D3D11VA_VLD, ///< HW decoding through Direct3D11, Picture.data[3] contains a ID3D11VideoDecoderOutputView pointer + + AV_PIX_FMT_0RGB=0x123+4,///< packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined + AV_PIX_FMT_RGB0, ///< packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined + AV_PIX_FMT_0BGR, ///< packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined + AV_PIX_FMT_BGR0, ///< packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined + + AV_PIX_FMT_YUV420P12BE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P12LE, ///< planar YUV 4:2:0,18bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV420P14BE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), big-endian + AV_PIX_FMT_YUV420P14LE, ///< planar YUV 4:2:0,21bpp, (1 Cr & Cb sample per 2x2 Y samples), little-endian + AV_PIX_FMT_YUV422P12BE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P12LE, ///< planar YUV 4:2:2,24bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV422P14BE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian + AV_PIX_FMT_YUV422P14LE, ///< planar YUV 4:2:2,28bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian + AV_PIX_FMT_YUV444P12BE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P12LE, ///< planar YUV 4:4:4,36bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_YUV444P14BE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian + AV_PIX_FMT_YUV444P14LE, ///< planar YUV 4:4:4,42bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian + AV_PIX_FMT_GBRP12BE, ///< planar GBR 4:4:4 36bpp, big-endian + AV_PIX_FMT_GBRP12LE, ///< planar GBR 4:4:4 36bpp, little-endian + AV_PIX_FMT_GBRP14BE, ///< planar GBR 4:4:4 42bpp, big-endian + AV_PIX_FMT_GBRP14LE, ///< planar GBR 4:4:4 42bpp, little-endian + AV_PIX_FMT_YUVJ411P, ///< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV411P and setting color_range + + AV_PIX_FMT_BAYER_BGGR8, ///< bayer, BGBG..(odd line), GRGR..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_RGGB8, ///< bayer, RGRG..(odd line), GBGB..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_GBRG8, ///< bayer, GBGB..(odd line), RGRG..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_GRBG8, ///< bayer, GRGR..(odd line), BGBG..(even line), 8-bit samples */ + AV_PIX_FMT_BAYER_BGGR16LE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_BGGR16BE, ///< bayer, BGBG..(odd line), GRGR..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_RGGB16LE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_RGGB16BE, ///< bayer, RGRG..(odd line), GBGB..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_GBRG16LE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_GBRG16BE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, big-endian */ + AV_PIX_FMT_BAYER_GRBG16LE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, little-endian */ + AV_PIX_FMT_BAYER_GRBG16BE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, big-endian */ +#if !FF_API_XVMC + AV_PIX_FMT_XVMC,///< XVideo Motion Acceleration via common packet passing +#endif /* !FF_API_XVMC */ + AV_PIX_FMT_YUV440P10LE, ///< planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian + AV_PIX_FMT_YUV440P10BE, ///< planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), big-endian + AV_PIX_FMT_YUV440P12LE, ///< planar YUV 4:4:0,24bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian + AV_PIX_FMT_YUV440P12BE, ///< planar YUV 4:4:0,24bpp, (1 Cr & Cb sample per 1x2 Y samples), big-endian + AV_PIX_FMT_AYUV64LE, ///< packed AYUV 4:4:4,64bpp (1 Cr & Cb sample per 1x1 Y & A samples), little-endian + AV_PIX_FMT_AYUV64BE, ///< packed AYUV 4:4:4,64bpp (1 Cr & Cb sample per 1x1 Y & A samples), big-endian + + AV_PIX_FMT_VIDEOTOOLBOX, ///< hardware decoding through Videotoolbox + + AV_PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions +}; + +#define AV_PIX_FMT_Y400A AV_PIX_FMT_GRAY8A +#define AV_PIX_FMT_GBR24P AV_PIX_FMT_GBRP + +#if AV_HAVE_BIGENDIAN +# define AV_PIX_FMT_NE(be, le) AV_PIX_FMT_##be +#else +# define AV_PIX_FMT_NE(be, le) AV_PIX_FMT_##le +#endif + +#define AV_PIX_FMT_RGB32 AV_PIX_FMT_NE(ARGB, BGRA) +#define AV_PIX_FMT_RGB32_1 AV_PIX_FMT_NE(RGBA, ABGR) +#define AV_PIX_FMT_BGR32 AV_PIX_FMT_NE(ABGR, RGBA) +#define AV_PIX_FMT_BGR32_1 AV_PIX_FMT_NE(BGRA, ARGB) +#define AV_PIX_FMT_0RGB32 AV_PIX_FMT_NE(0RGB, BGR0) +#define AV_PIX_FMT_0BGR32 AV_PIX_FMT_NE(0BGR, RGB0) + +#define AV_PIX_FMT_GRAY16 AV_PIX_FMT_NE(GRAY16BE, GRAY16LE) +#define AV_PIX_FMT_YA16 AV_PIX_FMT_NE(YA16BE, YA16LE) +#define AV_PIX_FMT_RGB48 AV_PIX_FMT_NE(RGB48BE, RGB48LE) +#define AV_PIX_FMT_RGB565 AV_PIX_FMT_NE(RGB565BE, RGB565LE) +#define AV_PIX_FMT_RGB555 AV_PIX_FMT_NE(RGB555BE, RGB555LE) +#define AV_PIX_FMT_RGB444 AV_PIX_FMT_NE(RGB444BE, RGB444LE) +#define AV_PIX_FMT_RGBA64 AV_PIX_FMT_NE(RGBA64BE, RGBA64LE) +#define AV_PIX_FMT_BGR48 AV_PIX_FMT_NE(BGR48BE, BGR48LE) +#define AV_PIX_FMT_BGR565 AV_PIX_FMT_NE(BGR565BE, BGR565LE) +#define AV_PIX_FMT_BGR555 AV_PIX_FMT_NE(BGR555BE, BGR555LE) +#define AV_PIX_FMT_BGR444 AV_PIX_FMT_NE(BGR444BE, BGR444LE) +#define AV_PIX_FMT_BGRA64 AV_PIX_FMT_NE(BGRA64BE, BGRA64LE) + +#define AV_PIX_FMT_YUV420P9 AV_PIX_FMT_NE(YUV420P9BE , YUV420P9LE) +#define AV_PIX_FMT_YUV422P9 AV_PIX_FMT_NE(YUV422P9BE , YUV422P9LE) +#define AV_PIX_FMT_YUV444P9 AV_PIX_FMT_NE(YUV444P9BE , YUV444P9LE) +#define AV_PIX_FMT_YUV420P10 AV_PIX_FMT_NE(YUV420P10BE, YUV420P10LE) +#define AV_PIX_FMT_YUV422P10 AV_PIX_FMT_NE(YUV422P10BE, YUV422P10LE) +#define AV_PIX_FMT_YUV440P10 AV_PIX_FMT_NE(YUV440P10BE, YUV440P10LE) +#define AV_PIX_FMT_YUV444P10 AV_PIX_FMT_NE(YUV444P10BE, YUV444P10LE) +#define AV_PIX_FMT_YUV420P12 AV_PIX_FMT_NE(YUV420P12BE, YUV420P12LE) +#define AV_PIX_FMT_YUV422P12 AV_PIX_FMT_NE(YUV422P12BE, YUV422P12LE) +#define AV_PIX_FMT_YUV440P12 AV_PIX_FMT_NE(YUV440P12BE, YUV440P12LE) +#define AV_PIX_FMT_YUV444P12 AV_PIX_FMT_NE(YUV444P12BE, YUV444P12LE) +#define AV_PIX_FMT_YUV420P14 AV_PIX_FMT_NE(YUV420P14BE, YUV420P14LE) +#define AV_PIX_FMT_YUV422P14 AV_PIX_FMT_NE(YUV422P14BE, YUV422P14LE) +#define AV_PIX_FMT_YUV444P14 AV_PIX_FMT_NE(YUV444P14BE, YUV444P14LE) +#define AV_PIX_FMT_YUV420P16 AV_PIX_FMT_NE(YUV420P16BE, YUV420P16LE) +#define AV_PIX_FMT_YUV422P16 AV_PIX_FMT_NE(YUV422P16BE, YUV422P16LE) +#define AV_PIX_FMT_YUV444P16 AV_PIX_FMT_NE(YUV444P16BE, YUV444P16LE) + +#define AV_PIX_FMT_GBRP9 AV_PIX_FMT_NE(GBRP9BE , GBRP9LE) +#define AV_PIX_FMT_GBRP10 AV_PIX_FMT_NE(GBRP10BE, GBRP10LE) +#define AV_PIX_FMT_GBRP12 AV_PIX_FMT_NE(GBRP12BE, GBRP12LE) +#define AV_PIX_FMT_GBRP14 AV_PIX_FMT_NE(GBRP14BE, GBRP14LE) +#define AV_PIX_FMT_GBRP16 AV_PIX_FMT_NE(GBRP16BE, GBRP16LE) +#define AV_PIX_FMT_GBRAP16 AV_PIX_FMT_NE(GBRAP16BE, GBRAP16LE) + +#define AV_PIX_FMT_BAYER_BGGR16 AV_PIX_FMT_NE(BAYER_BGGR16BE, BAYER_BGGR16LE) +#define AV_PIX_FMT_BAYER_RGGB16 AV_PIX_FMT_NE(BAYER_RGGB16BE, BAYER_RGGB16LE) +#define AV_PIX_FMT_BAYER_GBRG16 AV_PIX_FMT_NE(BAYER_GBRG16BE, BAYER_GBRG16LE) +#define AV_PIX_FMT_BAYER_GRBG16 AV_PIX_FMT_NE(BAYER_GRBG16BE, BAYER_GRBG16LE) + + +#define AV_PIX_FMT_YUVA420P9 AV_PIX_FMT_NE(YUVA420P9BE , YUVA420P9LE) +#define AV_PIX_FMT_YUVA422P9 AV_PIX_FMT_NE(YUVA422P9BE , YUVA422P9LE) +#define AV_PIX_FMT_YUVA444P9 AV_PIX_FMT_NE(YUVA444P9BE , YUVA444P9LE) +#define AV_PIX_FMT_YUVA420P10 AV_PIX_FMT_NE(YUVA420P10BE, YUVA420P10LE) +#define AV_PIX_FMT_YUVA422P10 AV_PIX_FMT_NE(YUVA422P10BE, YUVA422P10LE) +#define AV_PIX_FMT_YUVA444P10 AV_PIX_FMT_NE(YUVA444P10BE, YUVA444P10LE) +#define AV_PIX_FMT_YUVA420P16 AV_PIX_FMT_NE(YUVA420P16BE, YUVA420P16LE) +#define AV_PIX_FMT_YUVA422P16 AV_PIX_FMT_NE(YUVA422P16BE, YUVA422P16LE) +#define AV_PIX_FMT_YUVA444P16 AV_PIX_FMT_NE(YUVA444P16BE, YUVA444P16LE) + +#define AV_PIX_FMT_XYZ12 AV_PIX_FMT_NE(XYZ12BE, XYZ12LE) +#define AV_PIX_FMT_NV20 AV_PIX_FMT_NE(NV20BE, NV20LE) +#define AV_PIX_FMT_AYUV64 AV_PIX_FMT_NE(AYUV64BE, AYUV64LE) + +/** + * Chromaticity coordinates of the source primaries. + */ +enum AVColorPrimaries { + AVCOL_PRI_RESERVED0 = 0, + AVCOL_PRI_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP177 Annex B + AVCOL_PRI_UNSPECIFIED = 2, + AVCOL_PRI_RESERVED = 3, + AVCOL_PRI_BT470M = 4, ///< also FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + + AVCOL_PRI_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM + AVCOL_PRI_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_PRI_SMPTE240M = 7, ///< functionally identical to above + AVCOL_PRI_FILM = 8, ///< colour filters using Illuminant C + AVCOL_PRI_BT2020 = 9, ///< ITU-R BT2020 + AVCOL_PRI_SMPTEST428_1= 10, ///< SMPTE ST 428-1 (CIE 1931 XYZ) + AVCOL_PRI_NB, ///< Not part of ABI +}; + +/** + * Color Transfer Characteristic. + */ +enum AVColorTransferCharacteristic { + AVCOL_TRC_RESERVED0 = 0, + AVCOL_TRC_BT709 = 1, ///< also ITU-R BT1361 + AVCOL_TRC_UNSPECIFIED = 2, + AVCOL_TRC_RESERVED = 3, + AVCOL_TRC_GAMMA22 = 4, ///< also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM + AVCOL_TRC_GAMMA28 = 5, ///< also ITU-R BT470BG + AVCOL_TRC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 NTSC + AVCOL_TRC_SMPTE240M = 7, + AVCOL_TRC_LINEAR = 8, ///< "Linear transfer characteristics" + AVCOL_TRC_LOG = 9, ///< "Logarithmic transfer characteristic (100:1 range)" + AVCOL_TRC_LOG_SQRT = 10, ///< "Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range)" + AVCOL_TRC_IEC61966_2_4 = 11, ///< IEC 61966-2-4 + AVCOL_TRC_BT1361_ECG = 12, ///< ITU-R BT1361 Extended Colour Gamut + AVCOL_TRC_IEC61966_2_1 = 13, ///< IEC 61966-2-1 (sRGB or sYCC) + AVCOL_TRC_BT2020_10 = 14, ///< ITU-R BT2020 for 10 bit system + AVCOL_TRC_BT2020_12 = 15, ///< ITU-R BT2020 for 12 bit system + AVCOL_TRC_SMPTEST2084 = 16, ///< SMPTE ST 2084 for 10, 12, 14 and 16 bit systems + AVCOL_TRC_SMPTEST428_1 = 17, ///< SMPTE ST 428-1 + AVCOL_TRC_NB, ///< Not part of ABI +}; + +/** + * YUV colorspace type. + */ +enum AVColorSpace { + AVCOL_SPC_RGB = 0, ///< order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB) + AVCOL_SPC_BT709 = 1, ///< also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B + AVCOL_SPC_UNSPECIFIED = 2, + AVCOL_SPC_RESERVED = 3, + AVCOL_SPC_FCC = 4, ///< FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + AVCOL_SPC_BT470BG = 5, ///< also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / IEC 61966-2-4 xvYCC601 + AVCOL_SPC_SMPTE170M = 6, ///< also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC / functionally identical to above + AVCOL_SPC_SMPTE240M = 7, + AVCOL_SPC_YCOCG = 8, ///< Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16 + AVCOL_SPC_BT2020_NCL = 9, ///< ITU-R BT2020 non-constant luminance system + AVCOL_SPC_BT2020_CL = 10, ///< ITU-R BT2020 constant luminance system + AVCOL_SPC_NB, ///< Not part of ABI +}; +#define AVCOL_SPC_YCGCO AVCOL_SPC_YCOCG + + +/** + * MPEG vs JPEG YUV range. + */ +enum AVColorRange { + AVCOL_RANGE_UNSPECIFIED = 0, + AVCOL_RANGE_MPEG = 1, ///< the normal 219*2^(n-8) "MPEG" YUV ranges + AVCOL_RANGE_JPEG = 2, ///< the normal 2^n-1 "JPEG" YUV ranges + AVCOL_RANGE_NB, ///< Not part of ABI +}; + +/** + * Location of chroma samples. + * + * Illustration showing the location of the first (top left) chroma sample of the + * image, the left shows only luma, the right + * shows the location of the chroma sample, the 2 could be imagined to overlay + * each other but are drawn separately due to limitations of ASCII + * + * 1st 2nd 1st 2nd horizontal luma sample positions + * v v v v + * ______ ______ + *1st luma line > |X X ... |3 4 X ... X are luma samples, + * | |1 2 1-6 are possible chroma positions + *2nd luma line > |X X ... |5 6 X ... 0 is undefined/unknown position + */ +enum AVChromaLocation { + AVCHROMA_LOC_UNSPECIFIED = 0, + AVCHROMA_LOC_LEFT = 1, ///< mpeg2/4 4:2:0, h264 default for 4:2:0 + AVCHROMA_LOC_CENTER = 2, ///< mpeg1 4:2:0, jpeg 4:2:0, h263 4:2:0 + AVCHROMA_LOC_TOPLEFT = 3, ///< ITU-R 601, SMPTE 274M 296M S314M(DV 4:1:1), mpeg2 4:2:2 + AVCHROMA_LOC_TOP = 4, + AVCHROMA_LOC_BOTTOMLEFT = 5, + AVCHROMA_LOC_BOTTOM = 6, + AVCHROMA_LOC_NB, ///< Not part of ABI +}; + +#endif /* AVUTIL_PIXFMT_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/random_seed.h b/TMessagesProj/jni/ffmpeg/include/libavutil/random_seed.h new file mode 100644 index 00000000..0462a048 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/random_seed.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2009 Baptiste Coudurier + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RANDOM_SEED_H +#define AVUTIL_RANDOM_SEED_H + +#include +/** + * @addtogroup lavu_crypto + * @{ + */ + +/** + * Get a seed to use in conjunction with random functions. + * This function tries to provide a good seed at a best effort bases. + * Its possible to call this function multiple times if more bits are needed. + * It can be quite slow, which is why it should only be used as seed for a faster + * PRNG. The quality of the seed depends on the platform. + */ +uint32_t av_get_random_seed(void); + +/** + * @} + */ + +#endif /* AVUTIL_RANDOM_SEED_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/rational.h b/TMessagesProj/jni/ffmpeg/include/libavutil/rational.h new file mode 100644 index 00000000..28974696 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/rational.h @@ -0,0 +1,173 @@ +/* + * rational numbers + * Copyright (c) 2003 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * rational numbers + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_RATIONAL_H +#define AVUTIL_RATIONAL_H + +#include +#include +#include "attributes.h" + +/** + * @addtogroup lavu_math + * @{ + */ + +/** + * rational number numerator/denominator + */ +typedef struct AVRational{ + int num; ///< numerator + int den; ///< denominator +} AVRational; + +/** + * Create a rational. + * Useful for compilers that do not support compound literals. + * @note The return value is not reduced. + */ +static inline AVRational av_make_q(int num, int den) +{ + AVRational r = { num, den }; + return r; +} + +/** + * Compare two rationals. + * @param a first rational + * @param b second rational + * @return 0 if a==b, 1 if a>b, -1 if a>63)|1; + else if(b.den && a.den) return 0; + else if(a.num && b.num) return (a.num>>31) - (b.num>>31); + else return INT_MIN; +} + +/** + * Convert rational to double. + * @param a rational to convert + * @return (double) a + */ +static inline double av_q2d(AVRational a){ + return a.num / (double) a.den; +} + +/** + * Reduce a fraction. + * This is useful for framerate calculations. + * @param dst_num destination numerator + * @param dst_den destination denominator + * @param num source numerator + * @param den source denominator + * @param max the maximum allowed for dst_num & dst_den + * @return 1 if exact, 0 otherwise + */ +int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max); + +/** + * Multiply two rationals. + * @param b first rational + * @param c second rational + * @return b*c + */ +AVRational av_mul_q(AVRational b, AVRational c) av_const; + +/** + * Divide one rational by another. + * @param b first rational + * @param c second rational + * @return b/c + */ +AVRational av_div_q(AVRational b, AVRational c) av_const; + +/** + * Add two rationals. + * @param b first rational + * @param c second rational + * @return b+c + */ +AVRational av_add_q(AVRational b, AVRational c) av_const; + +/** + * Subtract one rational from another. + * @param b first rational + * @param c second rational + * @return b-c + */ +AVRational av_sub_q(AVRational b, AVRational c) av_const; + +/** + * Invert a rational. + * @param q value + * @return 1 / q + */ +static av_always_inline AVRational av_inv_q(AVRational q) +{ + AVRational r = { q.den, q.num }; + return r; +} + +/** + * Convert a double precision floating point number to a rational. + * inf is expressed as {1,0} or {-1,0} depending on the sign. + * + * @param d double to convert + * @param max the maximum allowed numerator and denominator + * @return (AVRational) d + */ +AVRational av_d2q(double d, int max) av_const; + +/** + * @return 1 if q1 is nearer to q than q2, -1 if q2 is nearer + * than q1, 0 if they have the same distance. + */ +int av_nearer_q(AVRational q, AVRational q1, AVRational q2); + +/** + * Find the nearest value in q_list to q. + * @param q_list an array of rationals terminated by {0, 0} + * @return the index of the nearest value found in the array + */ +int av_find_nearest_q_idx(AVRational q, const AVRational* q_list); + +/** + * Converts a AVRational to a IEEE 32bit float. + * + * The float is returned in a uint32_t and its value is platform indepenant. + */ +uint32_t av_q2intfloat(AVRational q); + +/** + * @} + */ + +#endif /* AVUTIL_RATIONAL_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/rc4.h b/TMessagesProj/jni/ffmpeg/include/libavutil/rc4.h new file mode 100644 index 00000000..029cd2ad --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/rc4.h @@ -0,0 +1,66 @@ +/* + * RC4 encryption/decryption/pseudo-random number generator + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RC4_H +#define AVUTIL_RC4_H + +#include + +/** + * @defgroup lavu_rc4 RC4 + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVRC4 { + uint8_t state[256]; + int x, y; +} AVRC4; + +/** + * Allocate an AVRC4 context. + */ +AVRC4 *av_rc4_alloc(void); + +/** + * @brief Initializes an AVRC4 context. + * + * @param key_bits must be a multiple of 8 + * @param decrypt 0 for encryption, 1 for decryption, currently has no effect + * @return zero on success, negative value otherwise + */ +int av_rc4_init(struct AVRC4 *d, const uint8_t *key, int key_bits, int decrypt); + +/** + * @brief Encrypts / decrypts using the RC4 algorithm. + * + * @param count number of bytes + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst, may be NULL + * @param iv not (yet) used for RC4, should be NULL + * @param decrypt 0 for encryption, 1 for decryption, not (yet) used + */ +void av_rc4_crypt(struct AVRC4 *d, uint8_t *dst, const uint8_t *src, int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_RC4_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/replaygain.h b/TMessagesProj/jni/ffmpeg/include/libavutil/replaygain.h new file mode 100644 index 00000000..5c03e199 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/replaygain.h @@ -0,0 +1,51 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_REPLAYGAIN_H +#define AVUTIL_REPLAYGAIN_H + +#include + +/** + * ReplayGain information (see + * http://wiki.hydrogenaudio.org/index.php?title=ReplayGain_1.0_specification). + * The size of this struct is a part of the public ABI. + */ +typedef struct AVReplayGain { + /** + * Track replay gain in microbels (divide by 100000 to get the value in dB). + * Should be set to INT32_MIN when unknown. + */ + int32_t track_gain; + /** + * Peak track amplitude, with 100000 representing full scale (but values + * may overflow). 0 when unknown. + */ + uint32_t track_peak; + /** + * Same as track_gain, but for the whole album. + */ + int32_t album_gain; + /** + * Same as track_peak, but for the whole album, + */ + uint32_t album_peak; +} AVReplayGain; + +#endif /* AVUTIL_REPLAYGAIN_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/ripemd.h b/TMessagesProj/jni/ffmpeg/include/libavutil/ripemd.h new file mode 100644 index 00000000..7b0c8bc8 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/ripemd.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2013 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_RIPEMD_H +#define AVUTIL_RIPEMD_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_ripemd RIPEMD + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_ripemd_size; + +struct AVRIPEMD; + +/** + * Allocate an AVRIPEMD context. + */ +struct AVRIPEMD *av_ripemd_alloc(void); + +/** + * Initialize RIPEMD hashing. + * + * @param context pointer to the function context (of size av_ripemd_size) + * @param bits number of bits in digest (128, 160, 256 or 320 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_ripemd_init(struct AVRIPEMD* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_ripemd_update(struct AVRIPEMD* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_ripemd_final(struct AVRIPEMD* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_RIPEMD_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/samplefmt.h b/TMessagesProj/jni/ffmpeg/include/libavutil/samplefmt.h new file mode 100644 index 00000000..6a8a031c --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/samplefmt.h @@ -0,0 +1,271 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SAMPLEFMT_H +#define AVUTIL_SAMPLEFMT_H + +#include + +#include "avutil.h" +#include "attributes.h" + +/** + * @addtogroup lavu_audio + * @{ + * + * @defgroup lavu_sampfmts Audio sample formats + * + * Audio sample format enumeration and related convenience functions. + * @{ + * + */ + +/** + * Audio sample formats + * + * - The data described by the sample format is always in native-endian order. + * Sample values can be expressed by native C types, hence the lack of a signed + * 24-bit sample format even though it is a common raw audio data format. + * + * - The floating-point formats are based on full volume being in the range + * [-1.0, 1.0]. Any values outside this range are beyond full volume level. + * + * - The data layout as used in av_samples_fill_arrays() and elsewhere in FFmpeg + * (such as AVFrame in libavcodec) is as follows: + * + * @par + * For planar sample formats, each audio channel is in a separate data plane, + * and linesize is the buffer size, in bytes, for a single plane. All data + * planes must be the same size. For packed sample formats, only the first data + * plane is used, and samples for each channel are interleaved. In this case, + * linesize is the buffer size, in bytes, for the 1 plane. + * + */ +enum AVSampleFormat { + AV_SAMPLE_FMT_NONE = -1, + AV_SAMPLE_FMT_U8, ///< unsigned 8 bits + AV_SAMPLE_FMT_S16, ///< signed 16 bits + AV_SAMPLE_FMT_S32, ///< signed 32 bits + AV_SAMPLE_FMT_FLT, ///< float + AV_SAMPLE_FMT_DBL, ///< double + + AV_SAMPLE_FMT_U8P, ///< unsigned 8 bits, planar + AV_SAMPLE_FMT_S16P, ///< signed 16 bits, planar + AV_SAMPLE_FMT_S32P, ///< signed 32 bits, planar + AV_SAMPLE_FMT_FLTP, ///< float, planar + AV_SAMPLE_FMT_DBLP, ///< double, planar + + AV_SAMPLE_FMT_NB ///< Number of sample formats. DO NOT USE if linking dynamically +}; + +/** + * Return the name of sample_fmt, or NULL if sample_fmt is not + * recognized. + */ +const char *av_get_sample_fmt_name(enum AVSampleFormat sample_fmt); + +/** + * Return a sample format corresponding to name, or AV_SAMPLE_FMT_NONE + * on error. + */ +enum AVSampleFormat av_get_sample_fmt(const char *name); + +/** + * Return the planar<->packed alternative form of the given sample format, or + * AV_SAMPLE_FMT_NONE on error. If the passed sample_fmt is already in the + * requested planar/packed format, the format returned is the same as the + * input. + */ +enum AVSampleFormat av_get_alt_sample_fmt(enum AVSampleFormat sample_fmt, int planar); + +/** + * Get the packed alternative form of the given sample format. + * + * If the passed sample_fmt is already in packed format, the format returned is + * the same as the input. + * + * @return the packed alternative form of the given sample format or + AV_SAMPLE_FMT_NONE on error. + */ +enum AVSampleFormat av_get_packed_sample_fmt(enum AVSampleFormat sample_fmt); + +/** + * Get the planar alternative form of the given sample format. + * + * If the passed sample_fmt is already in planar format, the format returned is + * the same as the input. + * + * @return the planar alternative form of the given sample format or + AV_SAMPLE_FMT_NONE on error. + */ +enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt); + +/** + * Generate a string corresponding to the sample format with + * sample_fmt, or a header if sample_fmt is negative. + * + * @param buf the buffer where to write the string + * @param buf_size the size of buf + * @param sample_fmt the number of the sample format to print the + * corresponding info string, or a negative value to print the + * corresponding header. + * @return the pointer to the filled buffer or NULL if sample_fmt is + * unknown or in case of other errors + */ +char *av_get_sample_fmt_string(char *buf, int buf_size, enum AVSampleFormat sample_fmt); + +/** + * Return number of bytes per sample. + * + * @param sample_fmt the sample format + * @return number of bytes per sample or zero if unknown for the given + * sample format + */ +int av_get_bytes_per_sample(enum AVSampleFormat sample_fmt); + +/** + * Check if the sample format is planar. + * + * @param sample_fmt the sample format to inspect + * @return 1 if the sample format is planar, 0 if it is interleaved + */ +int av_sample_fmt_is_planar(enum AVSampleFormat sample_fmt); + +/** + * Get the required buffer size for the given audio parameters. + * + * @param[out] linesize calculated linesize, may be NULL + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return required buffer size, or negative error code on failure + */ +int av_samples_get_buffer_size(int *linesize, int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * @} + * + * @defgroup lavu_sampmanip Samples manipulation + * + * Functions that manipulate audio samples + * @{ + */ + +/** + * Fill plane data pointers and linesize for samples with sample + * format sample_fmt. + * + * The audio_data array is filled with the pointers to the samples data planes: + * for planar, set the start point of each channel's data within the buffer, + * for packed, set the start point of the entire buffer only. + * + * The value pointed to by linesize is set to the aligned size of each + * channel's data buffer for planar layout, or to the aligned size of the + * buffer for all channels for packed layout. + * + * The buffer in buf must be big enough to contain all the samples + * (use av_samples_get_buffer_size() to compute its minimum size), + * otherwise the audio_data pointers will point to invalid data. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize calculated linesize, may be NULL + * @param buf the pointer to a buffer containing the samples + * @param nb_channels the number of channels + * @param nb_samples the number of samples in a single channel + * @param sample_fmt the sample format + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return >=0 on success or a negative error code on failure + * @todo return minimum size in bytes required for the buffer in case + * of success at the next bump + */ +int av_samples_fill_arrays(uint8_t **audio_data, int *linesize, + const uint8_t *buf, + int nb_channels, int nb_samples, + enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a samples buffer for nb_samples samples, and fill data pointers and + * linesize accordingly. + * The allocated samples buffer can be freed by using av_freep(&audio_data[0]) + * Allocated data will be initialized to silence. + * + * @see enum AVSampleFormat + * The documentation for AVSampleFormat describes the data layout. + * + * @param[out] audio_data array to be filled with the pointer for each channel + * @param[out] linesize aligned size for audio buffer(s), may be NULL + * @param nb_channels number of audio channels + * @param nb_samples number of samples per channel + * @param align buffer size alignment (0 = default, 1 = no alignment) + * @return >=0 on success or a negative error code on failure + * @todo return the size of the allocated buffer in case of success at the next bump + * @see av_samples_fill_arrays() + * @see av_samples_alloc_array_and_samples() + */ +int av_samples_alloc(uint8_t **audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +/** + * Allocate a data pointers array, samples buffer for nb_samples + * samples, and fill data pointers and linesize accordingly. + * + * This is the same as av_samples_alloc(), but also allocates the data + * pointers array. + * + * @see av_samples_alloc() + */ +int av_samples_alloc_array_and_samples(uint8_t ***audio_data, int *linesize, int nb_channels, + int nb_samples, enum AVSampleFormat sample_fmt, int align); + +/** + * Copy samples from src to dst. + * + * @param dst destination array of pointers to data planes + * @param src source array of pointers to data planes + * @param dst_offset offset in samples at which the data will be written to dst + * @param src_offset offset in samples at which the data will be read from src + * @param nb_samples number of samples to be copied + * @param nb_channels number of audio channels + * @param sample_fmt audio sample format + */ +int av_samples_copy(uint8_t **dst, uint8_t * const *src, int dst_offset, + int src_offset, int nb_samples, int nb_channels, + enum AVSampleFormat sample_fmt); + +/** + * Fill an audio buffer with silence. + * + * @param audio_data array of pointers to data planes + * @param offset offset in samples at which to start filling + * @param nb_samples number of samples to fill + * @param nb_channels number of audio channels + * @param sample_fmt audio sample format + */ +int av_samples_set_silence(uint8_t **audio_data, int offset, int nb_samples, + int nb_channels, enum AVSampleFormat sample_fmt); + +/** + * @} + * @} + */ +#endif /* AVUTIL_SAMPLEFMT_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/sha.h b/TMessagesProj/jni/ffmpeg/include/libavutil/sha.h new file mode 100644 index 00000000..bf4377e5 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/sha.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SHA_H +#define AVUTIL_SHA_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_sha SHA + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_sha_size; + +struct AVSHA; + +/** + * Allocate an AVSHA context. + */ +struct AVSHA *av_sha_alloc(void); + +/** + * Initialize SHA-1 or SHA-2 hashing. + * + * @param context pointer to the function context (of size av_sha_size) + * @param bits number of bits in digest (SHA-1 - 160 bits, SHA-2 224 or 256 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_sha_init(struct AVSHA* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_sha_update(struct AVSHA* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_sha_final(struct AVSHA* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_SHA_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/sha512.h b/TMessagesProj/jni/ffmpeg/include/libavutil/sha512.h new file mode 100644 index 00000000..7b087014 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/sha512.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * Copyright (C) 2013 James Almer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_SHA512_H +#define AVUTIL_SHA512_H + +#include + +#include "attributes.h" +#include "version.h" + +/** + * @defgroup lavu_sha512 SHA512 + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_sha512_size; + +struct AVSHA512; + +/** + * Allocate an AVSHA512 context. + */ +struct AVSHA512 *av_sha512_alloc(void); + +/** + * Initialize SHA-2 512 hashing. + * + * @param context pointer to the function context (of size av_sha512_size) + * @param bits number of bits in digest (224, 256, 384 or 512 bits) + * @return zero if initialization succeeded, -1 otherwise + */ +int av_sha512_init(struct AVSHA512* context, int bits); + +/** + * Update hash value. + * + * @param context hash function context + * @param data input data to update hash with + * @param len input data length + */ +void av_sha512_update(struct AVSHA512* context, const uint8_t* data, unsigned int len); + +/** + * Finish hashing and output digest value. + * + * @param context hash function context + * @param digest buffer where output digest value is stored + */ +void av_sha512_final(struct AVSHA512* context, uint8_t *digest); + +/** + * @} + */ + +#endif /* AVUTIL_SHA512_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/stereo3d.h b/TMessagesProj/jni/ffmpeg/include/libavutil/stereo3d.h new file mode 100644 index 00000000..1135dc9d --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/stereo3d.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2013 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_STEREO3D_H +#define AVUTIL_STEREO3D_H + +#include + +#include "frame.h" + +/** + * List of possible 3D Types + */ +enum AVStereo3DType { + /** + * Video is not stereoscopic (and metadata has to be there). + */ + AV_STEREO3D_2D, + + /** + * Views are next to each other. + * + * LLLLRRRR + * LLLLRRRR + * LLLLRRRR + * ... + */ + AV_STEREO3D_SIDEBYSIDE, + + /** + * Views are on top of each other. + * + * LLLLLLLL + * LLLLLLLL + * RRRRRRRR + * RRRRRRRR + */ + AV_STEREO3D_TOPBOTTOM, + + /** + * Views are alternated temporally. + * + * frame0 frame1 frame2 ... + * LLLLLLLL RRRRRRRR LLLLLLLL + * LLLLLLLL RRRRRRRR LLLLLLLL + * LLLLLLLL RRRRRRRR LLLLLLLL + * ... ... ... + */ + AV_STEREO3D_FRAMESEQUENCE, + + /** + * Views are packed in a checkerboard-like structure per pixel. + * + * LRLRLRLR + * RLRLRLRL + * LRLRLRLR + * ... + */ + AV_STEREO3D_CHECKERBOARD, + + /** + * Views are next to each other, but when upscaling + * apply a checkerboard pattern. + * + * LLLLRRRR L L L L R R R R + * LLLLRRRR => L L L L R R R R + * LLLLRRRR L L L L R R R R + * LLLLRRRR L L L L R R R R + */ + AV_STEREO3D_SIDEBYSIDE_QUINCUNX, + + /** + * Views are packed per line, as if interlaced. + * + * LLLLLLLL + * RRRRRRRR + * LLLLLLLL + * ... + */ + AV_STEREO3D_LINES, + + /** + * Views are packed per column. + * + * LRLRLRLR + * LRLRLRLR + * LRLRLRLR + * ... + */ + AV_STEREO3D_COLUMNS, +}; + + +/** + * Inverted views, Right/Bottom represents the left view. + */ +#define AV_STEREO3D_FLAG_INVERT (1 << 0) + +/** + * Stereo 3D type: this structure describes how two videos are packed + * within a single video surface, with additional information as needed. + * + * @note The struct must be allocated with av_stereo3d_alloc() and + * its size is not a part of the public ABI. + */ +typedef struct AVStereo3D { + /** + * How views are packed within the video. + */ + enum AVStereo3DType type; + + /** + * Additional information about the frame packing. + */ + int flags; +} AVStereo3D; + +/** + * Allocate an AVStereo3D structure and set its fields to default values. + * The resulting struct can be freed using av_freep(). + * + * @return An AVStereo3D filled with default values or NULL on failure. + */ +AVStereo3D *av_stereo3d_alloc(void); + +/** + * Allocate a complete AVFrameSideData and add it to the frame. + * + * @param frame The frame which side data is added to. + * + * @return The AVStereo3D structure to be filled by caller. + */ +AVStereo3D *av_stereo3d_create_side_data(AVFrame *frame); + +#endif /* AVUTIL_STEREO3D_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/tea.h b/TMessagesProj/jni/ffmpeg/include/libavutil/tea.h new file mode 100644 index 00000000..dd929bda --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/tea.h @@ -0,0 +1,71 @@ +/* + * A 32-bit implementation of the TEA algorithm + * Copyright (c) 2015 Vesselin Bontchev + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TEA_H +#define AVUTIL_TEA_H + +#include + +/** + * @file + * @brief Public header for libavutil TEA algorithm + * @defgroup lavu_tea TEA + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_tea_size; + +struct AVTEA; + +/** + * Allocate an AVTEA context + * To free the struct: av_free(ptr) + */ +struct AVTEA *av_tea_alloc(void); + +/** + * Initialize an AVTEA context. + * + * @param ctx an AVTEA context + * @param key a key of 16 bytes used for encryption/decryption + * @param rounds the number of rounds in TEA (64 is the "standard") + */ +void av_tea_init(struct AVTEA *ctx, const uint8_t key[16], int rounds); + +/** + * Encrypt or decrypt a buffer using a previously initialized context. + * + * @param ctx an AVTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_tea_crypt(struct AVTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_TEA_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/threadmessage.h b/TMessagesProj/jni/ffmpeg/include/libavutil/threadmessage.h new file mode 100644 index 00000000..e256cae9 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/threadmessage.h @@ -0,0 +1,107 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_THREADMESSAGE_H +#define AVUTIL_THREADMESSAGE_H + +typedef struct AVThreadMessageQueue AVThreadMessageQueue; + +typedef enum AVThreadMessageFlags { + + /** + * Perform non-blocking operation. + * If this flag is set, send and recv operations are non-blocking and + * return AVERROR(EAGAIN) immediately if they can not proceed. + */ + AV_THREAD_MESSAGE_NONBLOCK = 1, + +} AVThreadMessageFlags; + +/** + * Allocate a new message queue. + * + * @param mq pointer to the message queue + * @param nelem maximum number of elements in the queue + * @param elsize size of each element in the queue + * @return >=0 for success; <0 for error, in particular AVERROR(ENOSYS) if + * lavu was built without thread support + */ +int av_thread_message_queue_alloc(AVThreadMessageQueue **mq, + unsigned nelem, + unsigned elsize); + +/** + * Free a message queue. + * + * The message queue must no longer be in use by another thread. + */ +void av_thread_message_queue_free(AVThreadMessageQueue **mq); + +/** + * Send a message on the queue. + */ +int av_thread_message_queue_send(AVThreadMessageQueue *mq, + void *msg, + unsigned flags); + +/** + * Receive a message from the queue. + */ +int av_thread_message_queue_recv(AVThreadMessageQueue *mq, + void *msg, + unsigned flags); + +/** + * Set the sending error code. + * + * If the error code is set to non-zero, av_thread_message_queue_recv() will + * return it immediately when there are no longer available messages. + * Conventional values, such as AVERROR_EOF or AVERROR(EAGAIN), can be used + * to cause the receiving thread to stop or suspend its operation. + */ +void av_thread_message_queue_set_err_send(AVThreadMessageQueue *mq, + int err); + +/** + * Set the receiving error code. + * + * If the error code is set to non-zero, av_thread_message_queue_send() will + * return it immediately. Conventional values, such as AVERROR_EOF or + * AVERROR(EAGAIN), can be used to cause the sending thread to stop or + * suspend its operation. + */ +void av_thread_message_queue_set_err_recv(AVThreadMessageQueue *mq, + int err); + +/** + * Set the optional free message callback function which will be called if an + * operation is removing messages from the queue. + */ +void av_thread_message_queue_set_free_func(AVThreadMessageQueue *mq, + void (*free_func)(void *msg)); + +/** + * Flush the message queue + * + * This function is mostly equivalent to reading and free-ing every message + * except that it will be done in a single operation (no lock/unlock between + * reads). + */ +void av_thread_message_flush(AVThreadMessageQueue *mq); + +#endif /* AVUTIL_THREADMESSAGE_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/time.h b/TMessagesProj/jni/ffmpeg/include/libavutil/time.h new file mode 100644 index 00000000..dc169b06 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/time.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2000-2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TIME_H +#define AVUTIL_TIME_H + +#include + +/** + * Get the current time in microseconds. + */ +int64_t av_gettime(void); + +/** + * Get the current time in microseconds since some unspecified starting point. + * On platforms that support it, the time comes from a monotonic clock + * This property makes this time source ideal for measuring relative time. + * The returned values may not be monotonic on platforms where a monotonic + * clock is not available. + */ +int64_t av_gettime_relative(void); + +/** + * Indicates with a boolean result if the av_gettime_relative() time source + * is monotonic. + */ +int av_gettime_relative_is_monotonic(void); + +/** + * Sleep for a period of time. Although the duration is expressed in + * microseconds, the actual delay may be rounded to the precision of the + * system timer. + * + * @param usec Number of microseconds to sleep. + * @return zero on success or (negative) error code. + */ +int av_usleep(unsigned usec); + +#endif /* AVUTIL_TIME_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/timecode.h b/TMessagesProj/jni/ffmpeg/include/libavutil/timecode.h new file mode 100644 index 00000000..56e3975f --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/timecode.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier + * Copyright (c) 2011-2012 Smartjog S.A.S, Clément Bœsch + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Timecode helpers header + */ + +#ifndef AVUTIL_TIMECODE_H +#define AVUTIL_TIMECODE_H + +#include +#include "rational.h" + +#define AV_TIMECODE_STR_SIZE 16 + +enum AVTimecodeFlag { + AV_TIMECODE_FLAG_DROPFRAME = 1<<0, ///< timecode is drop frame + AV_TIMECODE_FLAG_24HOURSMAX = 1<<1, ///< timecode wraps after 24 hours + AV_TIMECODE_FLAG_ALLOWNEGATIVE = 1<<2, ///< negative time values are allowed +}; + +typedef struct { + int start; ///< timecode frame start (first base frame number) + uint32_t flags; ///< flags such as drop frame, +24 hours support, ... + AVRational rate; ///< frame rate in rational form + unsigned fps; ///< frame per second; must be consistent with the rate field +} AVTimecode; + +/** + * Adjust frame number for NTSC drop frame time code. + * + * @param framenum frame number to adjust + * @param fps frame per second, 30 or 60 + * @return adjusted frame number + * @warning adjustment is only valid in NTSC 29.97 and 59.94 + */ +int av_timecode_adjust_ntsc_framenum2(int framenum, int fps); + +/** + * Convert frame number to SMPTE 12M binary representation. + * + * @param tc timecode data correctly initialized + * @param framenum frame number + * @return the SMPTE binary representation + * + * @note Frame number adjustment is automatically done in case of drop timecode, + * you do NOT have to call av_timecode_adjust_ntsc_framenum2(). + * @note The frame number is relative to tc->start. + * @note Color frame (CF), binary group flags (BGF) and biphase mark polarity + * correction (PC) bits are set to zero. + */ +uint32_t av_timecode_get_smpte_from_framenum(const AVTimecode *tc, int framenum); + +/** + * Load timecode string in buf. + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tc timecode data correctly initialized + * @param framenum frame number + * @return the buf parameter + * + * @note Timecode representation can be a negative timecode and have more than + * 24 hours, but will only be honored if the flags are correctly set. + * @note The frame number is relative to tc->start. + */ +char *av_timecode_make_string(const AVTimecode *tc, char *buf, int framenum); + +/** + * Get the timecode string from the SMPTE timecode format. + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tcsmpte the 32-bit SMPTE timecode + * @param prevent_df prevent the use of a drop flag when it is known the DF bit + * is arbitrary + * @return the buf parameter + */ +char *av_timecode_make_smpte_tc_string(char *buf, uint32_t tcsmpte, int prevent_df); + +/** + * Get the timecode string from the 25-bit timecode format (MPEG GOP format). + * + * @param buf destination buffer, must be at least AV_TIMECODE_STR_SIZE long + * @param tc25bit the 25-bits timecode + * @return the buf parameter + */ +char *av_timecode_make_mpeg_tc_string(char *buf, uint32_t tc25bit); + +/** + * Init a timecode struct with the passed parameters. + * + * @param log_ctx a pointer to an arbitrary struct of which the first field + * is a pointer to an AVClass struct (used for av_log) + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param flags miscellaneous flags such as drop frame, +24 hours, ... + * (see AVTimecodeFlag) + * @param frame_start the first frame number + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init(AVTimecode *tc, AVRational rate, int flags, int frame_start, void *log_ctx); + +/** + * Parse timecode representation (hh:mm:ss[:;.]ff). + * + * @param log_ctx a pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct (used for av_log). + * @param tc pointer to an allocated AVTimecode + * @param rate frame rate in rational form + * @param str timecode string which will determine the frame start + * @return 0 on success, AVERROR otherwise + */ +int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *str, void *log_ctx); + +/** + * Check if the timecode feature is available for the given frame rate + * + * @return 0 if supported, <0 otherwise + */ +int av_timecode_check_frame_rate(AVRational rate); + +#endif /* AVUTIL_TIMECODE_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/timestamp.h b/TMessagesProj/jni/ffmpeg/include/libavutil/timestamp.h new file mode 100644 index 00000000..f010a7ee --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/timestamp.h @@ -0,0 +1,78 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * timestamp utils, mostly useful for debugging/logging purposes + */ + +#ifndef AVUTIL_TIMESTAMP_H +#define AVUTIL_TIMESTAMP_H + +#include "common.h" + +#if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS) && !defined(PRId64) +#error missing -D__STDC_FORMAT_MACROS / #define __STDC_FORMAT_MACROS +#endif + +#define AV_TS_MAX_STRING_SIZE 32 + +/** + * Fill the provided buffer with a string containing a timestamp + * representation. + * + * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE + * @param ts the timestamp to represent + * @return the buffer in input + */ +static inline char *av_ts_make_string(char *buf, int64_t ts) +{ + if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS"); + else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%"PRId64, ts); + return buf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_ts2str(ts) av_ts_make_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts) + +/** + * Fill the provided buffer with a string containing a timestamp time + * representation. + * + * @param buf a buffer with size in bytes of at least AV_TS_MAX_STRING_SIZE + * @param ts the timestamp to represent + * @param tb the timebase of the timestamp + * @return the buffer in input + */ +static inline char *av_ts_make_time_string(char *buf, int64_t ts, AVRational *tb) +{ + if (ts == AV_NOPTS_VALUE) snprintf(buf, AV_TS_MAX_STRING_SIZE, "NOPTS"); + else snprintf(buf, AV_TS_MAX_STRING_SIZE, "%.6g", av_q2d(*tb) * ts); + return buf; +} + +/** + * Convenience macro, the return value should be used only directly in + * function arguments but never stand-alone. + */ +#define av_ts2timestr(ts, tb) av_ts_make_time_string((char[AV_TS_MAX_STRING_SIZE]){0}, ts, tb) + +#endif /* AVUTIL_TIMESTAMP_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/tree.h b/TMessagesProj/jni/ffmpeg/include/libavutil/tree.h new file mode 100644 index 00000000..e1aefaa9 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/tree.h @@ -0,0 +1,138 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * A tree container. + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_TREE_H +#define AVUTIL_TREE_H + +#include "attributes.h" +#include "version.h" + +/** + * @addtogroup lavu_tree AVTree + * @ingroup lavu_data + * + * Low-complexity tree container + * + * Insertion, removal, finding equal, largest which is smaller than and + * smallest which is larger than, all have O(log n) worst-case complexity. + * @{ + */ + + +struct AVTreeNode; +extern const int av_tree_node_size; + +/** + * Allocate an AVTreeNode. + */ +struct AVTreeNode *av_tree_node_alloc(void); + +/** + * Find an element. + * @param root a pointer to the root node of the tree + * @param next If next is not NULL, then next[0] will contain the previous + * element and next[1] the next element. If either does not exist, + * then the corresponding entry in next is unchanged. + * @param cmp compare function used to compare elements in the tree, + * API identical to that of Standard C's qsort + * It is guranteed that the first and only the first argument to cmp() + * will be the key parameter to av_tree_find(), thus it could if the + * user wants, be a different type (like an opaque context). + * @return An element with cmp(key, elem) == 0 or NULL if no such element + * exists in the tree. + */ +void *av_tree_find(const struct AVTreeNode *root, void *key, + int (*cmp)(const void *key, const void *b), void *next[2]); + +/** + * Insert or remove an element. + * + * If *next is NULL, then the supplied element will be removed if it exists. + * If *next is non-NULL, then the supplied element will be inserted, unless + * it already exists in the tree. + * + * @param rootp A pointer to a pointer to the root node of the tree; note that + * the root node can change during insertions, this is required + * to keep the tree balanced. + * @param key pointer to the element key to insert in the tree + * @param next Used to allocate and free AVTreeNodes. For insertion the user + * must set it to an allocated and zeroed object of at least + * av_tree_node_size bytes size. av_tree_insert() will set it to + * NULL if it has been consumed. + * For deleting elements *next is set to NULL by the user and + * av_tree_insert() will set it to the AVTreeNode which was + * used for the removed element. + * This allows the use of flat arrays, which have + * lower overhead compared to many malloced elements. + * You might want to define a function like: + * @code + * void *tree_insert(struct AVTreeNode **rootp, void *key, + * int (*cmp)(void *key, const void *b), + * AVTreeNode **next) + * { + * if (!*next) + * *next = av_mallocz(av_tree_node_size); + * return av_tree_insert(rootp, key, cmp, next); + * } + * void *tree_remove(struct AVTreeNode **rootp, void *key, + * int (*cmp)(void *key, const void *b, AVTreeNode **next)) + * { + * av_freep(next); + * return av_tree_insert(rootp, key, cmp, next); + * } + * @endcode + * @param cmp compare function used to compare elements in the tree, API identical + * to that of Standard C's qsort + * @return If no insertion happened, the found element; if an insertion or + * removal happened, then either key or NULL will be returned. + * Which one it is depends on the tree state and the implementation. You + * should make no assumptions that it's one or the other in the code. + */ +void *av_tree_insert(struct AVTreeNode **rootp, void *key, + int (*cmp)(const void *key, const void *b), + struct AVTreeNode **next); + +void av_tree_destroy(struct AVTreeNode *t); + +/** + * Apply enu(opaque, &elem) to all the elements in the tree in a given range. + * + * @param cmp a comparison function that returns < 0 for a element below the + * range, > 0 for a element above the range and == 0 for a + * element inside the range + * + * @note The cmp function should use the same ordering used to construct the + * tree. + */ +void av_tree_enumerate(struct AVTreeNode *t, void *opaque, + int (*cmp)(void *opaque, void *elem), + int (*enu)(void *opaque, void *elem)); + +/** + * @} + */ + +#endif /* AVUTIL_TREE_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/twofish.h b/TMessagesProj/jni/ffmpeg/include/libavutil/twofish.h new file mode 100644 index 00000000..813cfecd --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/twofish.h @@ -0,0 +1,70 @@ +/* + * An implementation of the TwoFish algorithm + * Copyright (c) 2015 Supraja Meedinti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_TWOFISH_H +#define AVUTIL_TWOFISH_H + +#include + + +/** + * @file + * @brief Public header for libavutil TWOFISH algorithm + * @defgroup lavu_twofish TWOFISH + * @ingroup lavu_crypto + * @{ + */ + +extern const int av_twofish_size; + +struct AVTWOFISH; + +/** + * Allocate an AVTWOFISH context + * To free the struct: av_free(ptr) + */ +struct AVTWOFISH *av_twofish_alloc(void); + +/** + * Initialize an AVTWOFISH context. + * + * @param ctx an AVTWOFISH context + * @param key a key of size ranging from 1 to 32 bytes used for encryption/decryption + * @param key_bits number of keybits: 128, 192, 256 If less than the required, padded with zeroes to nearest valid value; return value is 0 if key_bits is 128/192/256, -1 if less than 0, 1 otherwise + */ +int av_twofish_init(struct AVTWOFISH *ctx, const uint8_t *key, int key_bits); + +/** + * Encrypt or decrypt a buffer using a previously initialized context + * + * @param ctx an AVTWOFISH context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 16 byte blocks + * @paran iv initialization vector for CBC mode, NULL for ECB mode + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_twofish_crypt(struct AVTWOFISH *ctx, uint8_t *dst, const uint8_t *src, int count, uint8_t* iv, int decrypt); + +/** + * @} + */ +#endif /* AVUTIL_TWOFISH_H */ diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/version.h b/TMessagesProj/jni/ffmpeg/include/libavutil/version.h new file mode 100644 index 00000000..22cd66b5 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/version.h @@ -0,0 +1,129 @@ +/* + * copyright (c) 2003 Fabrice Bellard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_VERSION_H +#define AVUTIL_VERSION_H + +#include "macros.h" + +/** + * @addtogroup version_utils + * + * Useful to check and match library version in order to maintain + * backward compatibility. + * + * @{ + */ + +#define AV_VERSION_INT(a, b, c) ((a)<<16 | (b)<<8 | (c)) +#define AV_VERSION_DOT(a, b, c) a ##.## b ##.## c +#define AV_VERSION(a, b, c) AV_VERSION_DOT(a, b, c) + +/** + * Extract version components from the full ::AV_VERSION_INT int as returned + * by functions like ::avformat_version() and ::avcodec_version() + */ +#define AV_VERSION_MAJOR(a) ((a) >> 16) +#define AV_VERSION_MINOR(a) (((a) & 0x00FF00) >> 8) +#define AV_VERSION_MICRO(a) ((a) & 0xFF) + +/** + * @} + */ + +/** + * @file + * @ingroup lavu + * Libavutil version macros + */ + +/** + * @defgroup lavu_ver Version and Build diagnostics + * + * Macros and function useful to check at compiletime and at runtime + * which version of libavutil is in use. + * + * @{ + */ + +#define LIBAVUTIL_VERSION_MAJOR 55 +#define LIBAVUTIL_VERSION_MINOR 11 +#define LIBAVUTIL_VERSION_MICRO 100 + +#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, \ + LIBAVUTIL_VERSION_MICRO) +#define LIBAVUTIL_VERSION AV_VERSION(LIBAVUTIL_VERSION_MAJOR, \ + LIBAVUTIL_VERSION_MINOR, \ + LIBAVUTIL_VERSION_MICRO) +#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT + +#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION) + +/** + * @} + * + * @defgroup depr_guards Deprecation guards + * FF_API_* defines may be placed below to indicate public API that will be + * dropped at a future version bump. The defines themselves are not part of + * the public API and may change, break or disappear at any time. + * + * @note, when bumping the major version it is recommended to manually + * disable each FF_API_* in its own commit instead of disabling them all + * at once through the bump. This improves the git bisect-ability of the change. + * + * @{ + */ + +#ifndef FF_API_VDPAU +#define FF_API_VDPAU (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_XVMC +#define FF_API_XVMC (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_OPT_TYPE_METADATA +#define FF_API_OPT_TYPE_METADATA (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_DLOG +#define FF_API_DLOG (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_VAAPI +#define FF_API_VAAPI (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_FRAME_QP +#define FF_API_FRAME_QP (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_PLUS1_MINUS1 +#define FF_API_PLUS1_MINUS1 (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_ERROR_FRAME +#define FF_API_ERROR_FRAME (LIBAVUTIL_VERSION_MAJOR < 56) +#endif +#ifndef FF_API_CRC_BIG_TABLE +#define FF_API_CRC_BIG_TABLE (LIBAVUTIL_VERSION_MAJOR < 56) +#endif + + +/** + * @} + */ + +#endif /* AVUTIL_VERSION_H */ + diff --git a/TMessagesProj/jni/ffmpeg/include/libavutil/xtea.h b/TMessagesProj/jni/ffmpeg/include/libavutil/xtea.h new file mode 100644 index 00000000..735427c1 --- /dev/null +++ b/TMessagesProj/jni/ffmpeg/include/libavutil/xtea.h @@ -0,0 +1,94 @@ +/* + * A 32-bit implementation of the XTEA algorithm + * Copyright (c) 2012 Samuel Pitoiset + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_XTEA_H +#define AVUTIL_XTEA_H + +#include + +/** + * @file + * @brief Public header for libavutil XTEA algorithm + * @defgroup lavu_xtea XTEA + * @ingroup lavu_crypto + * @{ + */ + +typedef struct AVXTEA { + uint32_t key[16]; +} AVXTEA; + +/** + * Allocate an AVXTEA context. + */ +AVXTEA *av_xtea_alloc(void); + +/** + * Initialize an AVXTEA context. + * + * @param ctx an AVXTEA context + * @param key a key of 16 bytes used for encryption/decryption, + * interpreted as big endian 32 bit numbers + */ +void av_xtea_init(struct AVXTEA *ctx, const uint8_t key[16]); + +/** + * Initialize an AVXTEA context. + * + * @param ctx an AVXTEA context + * @param key a key of 16 bytes used for encryption/decryption, + * interpreted as little endian 32 bit numbers + */ +void av_xtea_le_init(struct AVXTEA *ctx, const uint8_t key[16]); + +/** + * Encrypt or decrypt a buffer using a previously initialized context, + * in big endian format. + * + * @param ctx an AVXTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_xtea_crypt(struct AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * Encrypt or decrypt a buffer using a previously initialized context, + * in little endian format. + * + * @param ctx an AVXTEA context + * @param dst destination array, can be equal to src + * @param src source array, can be equal to dst + * @param count number of 8 byte blocks + * @param iv initialization vector for CBC mode, if NULL then ECB will be used + * @param decrypt 0 for encryption, 1 for decryption + */ +void av_xtea_le_crypt(struct AVXTEA *ctx, uint8_t *dst, const uint8_t *src, + int count, uint8_t *iv, int decrypt); + +/** + * @} + */ + +#endif /* AVUTIL_XTEA_H */ diff --git a/TMessagesProj/jni/gifvideo.cpp b/TMessagesProj/jni/gifvideo.cpp new file mode 100644 index 00000000..10e4c2d0 --- /dev/null +++ b/TMessagesProj/jni/gifvideo.cpp @@ -0,0 +1,266 @@ +#include +#include +#include +#include +#include +#include +#include +extern "C" { +#include + +static const std::string av_make_error_str(int errnum) { + char errbuf[AV_ERROR_MAX_STRING_SIZE]; + av_strerror(errnum, errbuf, AV_ERROR_MAX_STRING_SIZE); + return (std::string) errbuf; +} + +#undef av_err2str +#define av_err2str(errnum) av_make_error_str(errnum).c_str() + +typedef struct VideoInfo { + + ~VideoInfo() { + if (video_dec_ctx) { + avcodec_close(video_dec_ctx); + video_dec_ctx = nullptr; + } + if (fmt_ctx) { + avformat_close_input(&fmt_ctx); + fmt_ctx = nullptr; + } + if (frame) { + av_frame_free(&frame); + frame = nullptr; + } + if (src) { + delete [] src; + src = nullptr; + } + av_free_packet(&orig_pkt); + + video_stream_idx = -1; + video_stream = nullptr; + } + + AVFormatContext *fmt_ctx = nullptr; + char *src = nullptr; + int video_stream_idx = -1; + AVStream *video_stream = nullptr; + AVCodecContext *video_dec_ctx = nullptr; + AVFrame *frame = nullptr; + bool has_decoded_frames = false; + AVPacket pkt; + AVPacket orig_pkt; +}; + +jobject makeGlobarRef(JNIEnv *env, jobject object) { + if (object) { + return env->NewGlobalRef(object); + } + return 0; +} + +int gifvideoOnJNILoad(JavaVM *vm, JNIEnv *env) { + av_register_all(); + return 0; +} + +int open_codec_context(int *stream_idx, AVFormatContext *fmt_ctx, enum AVMediaType type) { + int ret; + AVStream *st; + AVCodecContext *dec_ctx = NULL; + AVCodec *dec = NULL; + AVDictionary *opts = NULL; + + ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0); + if (ret < 0) { + LOGE("can't find %s stream in input file\n", av_get_media_type_string(type)); + return ret; + } else { + *stream_idx = ret; + st = fmt_ctx->streams[*stream_idx]; + + dec_ctx = st->codec; + dec = avcodec_find_decoder(dec_ctx->codec_id); + if (!dec) { + LOGE("failed to find %s codec\n", av_get_media_type_string(type)); + return ret; + } + + av_dict_set(&opts, "refcounted_frames", "1", 0); + if ((ret = avcodec_open2(dec_ctx, dec, &opts)) < 0) { + LOGE("failed to open %s codec\n", av_get_media_type_string(type)); + return ret; + } + } + + return 0; +} + +int decode_packet(VideoInfo *info, int *got_frame) { + int ret = 0; + int decoded = info->pkt.size; + + *got_frame = 0; + if (info->pkt.stream_index == info->video_stream_idx) { + ret = avcodec_decode_video2(info->video_dec_ctx, info->frame, got_frame, &info->pkt); + if (ret != 0) { + return ret; + } + } + + return decoded; +} + +jint Java_org_telegram_ui_Components_AnimatedFileDrawable_createDecoder(JNIEnv *env, jclass clazz, jstring src, jintArray data) { + VideoInfo *info = new VideoInfo(); + + char const *srcString = env->GetStringUTFChars(src, 0); + int len = strlen(srcString); + info->src = new char[len + 1]; + memcpy(info->src, srcString, len); + info->src[len] = '\0'; + if (srcString != 0) { + env->ReleaseStringUTFChars(src, srcString); + } + + int ret; + if ((ret = avformat_open_input(&info->fmt_ctx, info->src, NULL, NULL)) < 0) { + LOGE("can't open source file %s, %s", info->src, av_err2str(ret)); + delete info; + return 0; + } + + if ((ret = avformat_find_stream_info(info->fmt_ctx, NULL)) < 0) { + LOGE("can't find stream information %s, %s", info->src, av_err2str(ret)); + delete info; + return 0; + } + + if (open_codec_context(&info->video_stream_idx, info->fmt_ctx, AVMEDIA_TYPE_VIDEO) >= 0) { + info->video_stream = info->fmt_ctx->streams[info->video_stream_idx]; + info->video_dec_ctx = info->video_stream->codec; + } + + if (info->video_stream <= 0) { + LOGE("can't find video stream in the input, aborting %s", info->src); + delete info; + return 0; + } + + info->frame = av_frame_alloc(); + if (info->frame == nullptr) { + LOGE("can't allocate frame %s", info->src); + delete info; + return 0; + } + + av_init_packet(&info->pkt); + info->pkt.data = NULL; + info->pkt.size = 0; + + jint *dataArr = env->GetIntArrayElements(data, 0); + if (dataArr != nullptr) { + dataArr[0] = info->video_dec_ctx->width; + dataArr[1] = info->video_dec_ctx->height; + env->ReleaseIntArrayElements(data, dataArr, 0); + } + + //LOGD("successfully opened file %s", info->src); + + return (int) info; +} + +void Java_org_telegram_ui_Components_AnimatedFileDrawable_destroyDecoder(JNIEnv *env, jclass clazz, jobject ptr) { + if (ptr == NULL) { + return; + } + VideoInfo *info = (VideoInfo *) ptr; + delete info; +} + + +jint Java_org_telegram_ui_Components_AnimatedFileDrawable_getVideoFrame(JNIEnv *env, jclass clazz, jobject ptr, jobject bitmap, jintArray data) { + if (ptr == NULL || bitmap == nullptr) { + return 0; + } + VideoInfo *info = (VideoInfo *) ptr; + int ret = 0; + int got_frame = 0; + + while (true) { + if (info->pkt.size == 0) { + ret = av_read_frame(info->fmt_ctx, &info->pkt); + //LOGD("got packet with size %d", info->pkt.size); + if (ret >= 0) { + info->orig_pkt = info->pkt; + } + } + + if (info->pkt.size > 0) { + ret = decode_packet(info, &got_frame); + if (ret < 0) { + if (info->has_decoded_frames) { + ret = 0; + } + info->pkt.size = 0; + } else { + //LOGD("read size %d from packet", ret); + info->pkt.data += ret; + info->pkt.size -= ret; + } + + if (info->pkt.size == 0) { + av_free_packet(&info->orig_pkt); + } + } else { + info->pkt.data = NULL; + info->pkt.size = 0; + ret = decode_packet(info, &got_frame); + if (ret < 0) { + LOGE("can't decode packet flushed %s", info->src); + return 0; + } + if (got_frame == 0) { + if (info->has_decoded_frames) { + //LOGD("file end reached %s", info->src); + if ((ret = avformat_seek_file(info->fmt_ctx, -1, std::numeric_limits::min(), 0, std::numeric_limits::max(), 0)) < 0) { + LOGE("can't seek to begin of file %s, %s", info->src, av_err2str(ret)); + return 0; + } else { + avcodec_flush_buffers(info->video_dec_ctx); + } + } + } + } + if (ret < 0) { + return 0; + } + if (got_frame) { + //LOGD("decoded frame with w = %d, h = %d, format = %d", info->frame->width, info->frame->height, info->frame->format); + if (info->frame->format == AV_PIX_FMT_YUV420P || info->frame->format == AV_PIX_FMT_BGRA) { + jint *dataArr = env->GetIntArrayElements(data, 0); + if (dataArr != nullptr) { + dataArr[2] = (int) (1000 * info->frame->pkt_pts * av_q2d(info->video_stream->time_base)); + env->ReleaseIntArrayElements(data, dataArr, 0); + } + + void *pixels; + if (AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0) { + if (info->frame->format == AV_PIX_FMT_YUV420P) { + //LOGD("y %d, u %d, v %d, width %d, height %d", info->frame->linesize[0], info->frame->linesize[2], info->frame->linesize[1], info->frame->width, info->frame->height); + libyuv::I420ToARGB(info->frame->data[0], info->frame->linesize[0], info->frame->data[2], info->frame->linesize[2], info->frame->data[1], info->frame->linesize[1], (uint8_t *) pixels, info->frame->width * 4, info->frame->width, info->frame->height); + } else if (info->frame->format == AV_PIX_FMT_BGRA) { + libyuv::ABGRToARGB(info->frame->data[0], info->frame->linesize[0], (uint8_t *) pixels, info->frame->width * 4, info->frame->width, info->frame->height); + } + AndroidBitmap_unlockPixels(env, bitmap); + } + } + info->has_decoded_frames = true; + av_frame_unref(info->frame); + return 1; + } + } + return 0; +} +} diff --git a/TMessagesProj/jni/image.c b/TMessagesProj/jni/image.c index f7a2cfef..5f1d78de 100644 --- a/TMessagesProj/jni/image.c +++ b/TMessagesProj/jni/image.c @@ -397,13 +397,13 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_calcCDT(JNIEnv *env, jclass JNIEXPORT int Java_org_telegram_messenger_Utilities_pinBitmap(JNIEnv *env, jclass class, jobject bitmap) { if (bitmap == NULL) { - return; + return 0; } unsigned char *pixels; return AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0 ? 1 : 0; } -JNIEXPORT int Java_org_telegram_messenger_Utilities_unpinBitmap(JNIEnv *env, jclass class, jobject bitmap) { +JNIEXPORT void Java_org_telegram_messenger_Utilities_unpinBitmap(JNIEnv *env, jclass class, jobject bitmap) { if (bitmap == NULL) { return; } diff --git a/TMessagesProj/jni/jni.c b/TMessagesProj/jni/jni.c index f300f8e7..711b91c9 100644 --- a/TMessagesProj/jni/jni.c +++ b/TMessagesProj/jni/jni.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "utils.h" #include "sqlite.h" #include "image.h" @@ -59,3 +60,16 @@ JNIEXPORT void Java_org_telegram_messenger_Utilities_aesIgeEncryption(JNIEnv *en (*env)->ReleaseByteArrayElements(env, key, keyBuff, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, iv, ivBuff, 0); } + +JNIEXPORT jstring Java_org_telegram_messenger_Utilities_readlink(JNIEnv *env, jclass class, jstring path) { + static char buf[1000]; + char *fileName = (*env)->GetStringUTFChars(env, path, NULL); + int result = readlink(fileName, buf, 999); + jstring value = 0; + if (result != -1) { + buf[result] = '\0'; + value = (*env)->NewStringUTF(env, buf); + } + (*env)->ReleaseStringUTFChars(env, path, fileName); + return value; +} diff --git a/TMessagesProj/jni/libjpeg/NOTICE b/TMessagesProj/jni/libjpeg/NOTICE new file mode 100644 index 00000000..70e356f7 --- /dev/null +++ b/TMessagesProj/jni/libjpeg/NOTICE @@ -0,0 +1,94 @@ +This software is based in part on the work of the Independent JPEG Group. + +---------------------- + +The authors make NO WARRANTY or representation, either express or implied, +with respect to this software, its quality, accuracy, merchantability, or +fitness for a particular purpose. This software is provided "AS IS", and you, +its user, assume the entire risk as to its quality and accuracy. + +This software is copyright (C) 1991-1998, Thomas G. Lane. +All Rights Reserved except as specified below. + +Permission is hereby granted to use, copy, modify, and distribute this +software (or portions thereof) for any purpose, without fee, subject to these +conditions: +(1) If any part of the source code for this software is distributed, then this +README file must be included, with this copyright and no-warranty notice +unaltered; and any additions, deletions, or changes to the original files +must be clearly indicated in accompanying documentation. +(2) If only executable code is distributed, then the accompanying +documentation must state that "this software is based in part on the work of +the Independent JPEG Group". +(3) Permission for use of this software is granted only if the user accepts +full responsibility for any undesirable consequences; the authors accept +NO LIABILITY for damages of any kind. + +These conditions apply to any software derived from or based on the IJG code, +not just to the unmodified library. If you use our work, you ought to +acknowledge us. + +Permission is NOT granted for the use of any IJG author's name or company name +in advertising or publicity relating to this software or products derived from +it. This software may be referred to only as "the Independent JPEG Group's +software". + +We specifically permit and encourage the use of this software as the basis of +commercial products, provided that all warranty or liability claims are +assumed by the product vendor. + + +---------------------- + + + ARM NEON optimizations for libjpeg-turbo + + Copyright (C) 2009-2011 Nokia Corporation and/or its subsidiary(-ies). + All rights reserved. + Contact: Alexander Bokovoy + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + + ---------------------- + + + Copyright (c) 2011, NVIDIA CORPORATION. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of the NVIDIA CORPORATION nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS 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 COPYRIGHT HOLDER OR 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. diff --git a/TMessagesProj/jni/libwebp/AUTHORS b/TMessagesProj/jni/libwebp/AUTHORS new file mode 100644 index 00000000..f0a85f9b --- /dev/null +++ b/TMessagesProj/jni/libwebp/AUTHORS @@ -0,0 +1,24 @@ +Contributors: +- Charles Munger (clm at google dot com) +- Christian Duvivier (cduvivier at google dot com) +- Djordje Pesut (djordje dot pesut at imgtec dot com) +- James Zern (jzern at google dot com) +- Jan Engelhardt (jengelh at medozas dot de) +- Johann (johann dot koenig at duck dot com) +- Jovan Zelincevic (jovan dot zelincevic at imgtec dot com) +- Jyrki Alakuijala (jyrki at google dot com) +- levytamar82 (tamar dot levy at intel dot com) +- Lou Quillio (louquillio at google dot com) +- Mans Rullgard (mans at mansr dot com) +- Martin Olsson (mnemo at minimum dot se) +- Mikołaj Zalewski (mikolajz at google dot com) +- Noel Chromium (noel at chromium dot org) +- Pascal Massimino (pascal dot massimino at gmail dot com) +- Paweł Hajdan, Jr (phajdan dot jr at chromium dot org) +- Pierre Joye (pierre dot php at gmail dot com) +- Scott LaVarnway (slavarnway at google dot com) +- Scott Talbot (s at chikachow dot org) +- Slobodan Prijic (slobodan dot prijic at imgtec dot com) +- Somnath Banerjee (somnath dot banerjee at gmail dot com) +- Urvang Joshi (urvang at google dot com) +- Vikas Arora (vikasa at google dot com) diff --git a/TMessagesProj/jni/libwebp/COPYING b/TMessagesProj/jni/libwebp/COPYING new file mode 100644 index 00000000..7a6f9954 --- /dev/null +++ b/TMessagesProj/jni/libwebp/COPYING @@ -0,0 +1,30 @@ +Copyright (c) 2010, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of Google nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS 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 COPYRIGHT +HOLDER OR 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. + diff --git a/TMessagesProj/jni/libwebp/PATENTS b/TMessagesProj/jni/libwebp/PATENTS new file mode 100644 index 00000000..caedf607 --- /dev/null +++ b/TMessagesProj/jni/libwebp/PATENTS @@ -0,0 +1,23 @@ +Additional IP Rights Grant (Patents) +------------------------------------ + +"These implementations" means the copyrightable works that implement the WebM +codecs distributed by Google as part of the WebM Project. + +Google hereby grants to you a perpetual, worldwide, non-exclusive, no-charge, +royalty-free, irrevocable (except as stated in this section) patent license to +make, have made, use, offer to sell, sell, import, transfer, and otherwise +run, modify and propagate the contents of these implementations of WebM, where +such license applies only to those patent claims, both currently owned by +Google and acquired in the future, licensable by Google that are necessarily +infringed by these implementations of WebM. This grant does not include claims +that would be infringed only as a consequence of further modification of these +implementations. If you or your agent or exclusive licensee institute or order +or agree to the institution of patent litigation or any other patent +enforcement activity against any entity (including a cross-claim or +counterclaim in a lawsuit) alleging that any of these implementations of WebM +or any code incorporated within any of these implementations of WebM +constitute direct or contributory patent infringement, or inducement of +patent infringement, then any patent rights granted to you under this License +for these implementations of WebM shall terminate as of the date such +litigation is filed. diff --git a/TMessagesProj/jni/libyuv/AUTHORS b/TMessagesProj/jni/libyuv/AUTHORS new file mode 100644 index 00000000..9686ac13 --- /dev/null +++ b/TMessagesProj/jni/libyuv/AUTHORS @@ -0,0 +1,4 @@ +# Names should be added to this file like so: +# Name or Organization + +Google Inc. diff --git a/TMessagesProj/jni/libyuv/LICENSE b/TMessagesProj/jni/libyuv/LICENSE new file mode 100644 index 00000000..c911747a --- /dev/null +++ b/TMessagesProj/jni/libyuv/LICENSE @@ -0,0 +1,29 @@ +Copyright 2011 The LibYuv Project Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * 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. + + * Neither the name of Google nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS 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 COPYRIGHT +HOLDER OR 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. diff --git a/TMessagesProj/jni/libyuv/LICENSE_THIRD_PARTY b/TMessagesProj/jni/libyuv/LICENSE_THIRD_PARTY new file mode 100644 index 00000000..a71591e7 --- /dev/null +++ b/TMessagesProj/jni/libyuv/LICENSE_THIRD_PARTY @@ -0,0 +1,8 @@ +This source tree contains third party source code which is governed by third +party licenses. This file contains references to files which are under other +licenses than the one provided in the LICENSE file in the root of the source +tree. + +Files governed by third party licenses: +source/x86inc.asm + diff --git a/TMessagesProj/jni/libyuv/PATENTS b/TMessagesProj/jni/libyuv/PATENTS new file mode 100644 index 00000000..64aa5c90 --- /dev/null +++ b/TMessagesProj/jni/libyuv/PATENTS @@ -0,0 +1,24 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the LibYuv code package. + +Google hereby grants to you a perpetual, worldwide, non-exclusive, +no-charge, irrevocable (except as stated in this section) patent +license to make, have made, use, offer to sell, sell, import, +transfer, and otherwise run, modify and propagate the contents of this +implementation of the LibYuv code package, where such license applies +only to those patent claims, both currently owned by Google and +acquired in the future, licensable by Google that are necessarily +infringed by this implementation of the LibYuv code package. This +grant does not include claims that would be infringed only as a +consequence of further modification of this implementation. If you or +your agent or exclusive licensee institute or order or agree to the +institution of patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that this +implementation of the LibYuv code package or any code incorporated +within this implementation of the LibYuv code package constitutes +direct or contributory patent infringement, or inducement of patent +infringement, then any patent rights granted to you under this License +for this implementation of the LibYuv code package shall terminate as +of the date such litigation is filed. \ No newline at end of file diff --git a/TMessagesProj/jni/libyuv/include/libyuv/compare_row.h b/TMessagesProj/jni/libyuv/include/libyuv/compare_row.h new file mode 100644 index 00000000..4562da04 --- /dev/null +++ b/TMessagesProj/jni/libyuv/include/libyuv/compare_row.h @@ -0,0 +1,77 @@ +/* + * Copyright 2013 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_COMPARE_ROW_H_ // NOLINT +#define INCLUDE_LIBYUV_COMPARE_ROW_H_ + +#include "libyuv/basic_types.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +#if defined(__pnacl__) || defined(__CLR_VER) || \ + (defined(__i386__) && !defined(__SSE2__)) +#define LIBYUV_DISABLE_X86 +#endif + +// Visual C 2012 required for AVX2. +#if defined(_M_IX86) && !defined(__clang__) && \ + defined(_MSC_VER) && _MSC_VER >= 1700 +#define VISUALC_HAS_AVX2 1 +#endif // VisualStudio >= 2012 + +// clang >= 3.4.0 required for AVX2. +#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__)) +#if (__clang_major__ > 3) || (__clang_major__ == 3 && (__clang_minor__ >= 4)) +#define CLANG_HAS_AVX2 1 +#endif // clang >= 3.4 +#endif // __clang__ + +#if defined(_M_IX86) && (defined(VISUALC_HAS_AVX2) || defined(CLANG_HAS_AVX2)) +#define HAS_HASHDJB2_AVX2 +#endif + +// The following are available for Visual C and GCC: +#if !defined(LIBYUV_DISABLE_X86) && \ + (defined(__x86_64__) || (defined(__i386__) || defined(_M_IX86))) +#define HAS_HASHDJB2_SSE41 +#define HAS_SUMSQUAREERROR_SSE2 +#endif + +// The following are available for Visual C and clangcl 32 bit: +#if !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && \ + (defined(VISUALC_HAS_AVX2) || defined(CLANG_HAS_AVX2)) +#define HAS_HASHDJB2_AVX2 +#define HAS_SUMSQUAREERROR_AVX2 +#endif + +// The following are available for Neon: +#if !defined(LIBYUV_DISABLE_NEON) && \ + (defined(__ARM_NEON__) || defined(LIBYUV_NEON) || defined(__aarch64__)) +#define HAS_SUMSQUAREERROR_NEON +#endif + +uint32 SumSquareError_C(const uint8* src_a, const uint8* src_b, int count); +uint32 SumSquareError_SSE2(const uint8* src_a, const uint8* src_b, int count); +uint32 SumSquareError_AVX2(const uint8* src_a, const uint8* src_b, int count); +uint32 SumSquareError_NEON(const uint8* src_a, const uint8* src_b, int count); + +uint32 HashDjb2_C(const uint8* src, int count, uint32 seed); +uint32 HashDjb2_SSE41(const uint8* src, int count, uint32 seed); +uint32 HashDjb2_AVX2(const uint8* src, int count, uint32 seed); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_COMPARE_ROW_H_ NOLINT diff --git a/TMessagesProj/jni/libyuv/include/libyuv/rotate_row.h b/TMessagesProj/jni/libyuv/include/libyuv/rotate_row.h new file mode 100644 index 00000000..e3838295 --- /dev/null +++ b/TMessagesProj/jni/libyuv/include/libyuv/rotate_row.h @@ -0,0 +1,116 @@ +/* + * Copyright 2013 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef INCLUDE_LIBYUV_ROTATE_ROW_H_ // NOLINT +#define INCLUDE_LIBYUV_ROTATE_ROW_H_ + +#include "libyuv/basic_types.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +#if defined(__pnacl__) || defined(__CLR_VER) || \ + (defined(__i386__) && !defined(__SSE2__)) +#define LIBYUV_DISABLE_X86 +#endif + +// The following are available for Visual C and clangcl 32 bit: +#if !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) +#define HAS_TRANSPOSEWX8_SSSE3 +#define HAS_TRANSPOSEUVWX8_SSE2 +#endif + +// The following are available for GCC 32 or 64 bit but not NaCL for 64 bit: +#if !defined(LIBYUV_DISABLE_X86) && \ + (defined(__i386__) || (defined(__x86_64__) && !defined(__native_client__))) +#define HAS_TRANSPOSEWX8_SSSE3 +#endif + +// The following are available for 64 bit GCC but not NaCL: +#if !defined(LIBYUV_DISABLE_X86) && !defined(__native_client__) && \ + defined(__x86_64__) +#define HAS_TRANSPOSEWX8_FAST_SSSE3 +#define HAS_TRANSPOSEUVWX8_SSE2 +#endif + +#if !defined(LIBYUV_DISABLE_NEON) && !defined(__native_client__) && \ + (defined(__ARM_NEON__) || defined(LIBYUV_NEON) || defined(__aarch64__)) +#define HAS_TRANSPOSEWX8_NEON +#define HAS_TRANSPOSEUVWX8_NEON +#endif + +#if !defined(LIBYUV_DISABLE_MIPS) && !defined(__native_client__) && \ + defined(__mips__) && \ + defined(__mips_dsp) && (__mips_dsp_rev >= 2) +#define HAS_TRANSPOSEWX8_MIPS_DSPR2 +#define HAS_TRANSPOSEUVWX8_MIPS_DSPR2 +#endif // defined(__mips__) + +void TransposeWxH_C(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width, int height); + +void TransposeWx8_C(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width); +void TransposeWx8_NEON(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width); +void TransposeWx8_SSSE3(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width); +void TransposeWx8_Fast_SSSE3(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width); +void TransposeWx8_MIPS_DSPR2(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width); +void TransposeWx8_Fast_MIPS_DSPR2(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width); + +void TransposeWx8_Any_NEON(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width); +void TransposeWx8_Any_SSSE3(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width); +void TransposeWx8_Fast_Any_SSSE3(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width); +void TransposeWx8_Any_MIPS_DSPR2(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width); + +void TransposeUVWxH_C(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, + int width, int height); + +void TransposeUVWx8_C(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, int width); +void TransposeUVWx8_SSE2(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, int width); +void TransposeUVWx8_NEON(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, int width); +void TransposeUVWx8_MIPS_DSPR2(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, int width); + +void TransposeUVWx8_Any_SSE2(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, int width); +void TransposeUVWx8_Any_NEON(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, int width); +void TransposeUVWx8_Any_MIPS_DSPR2(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, int width); + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + +#endif // INCLUDE_LIBYUV_ROTATE_ROW_H_ NOLINT diff --git a/TMessagesProj/jni/libyuv/source/compare_gcc.cc b/TMessagesProj/jni/libyuv/source/compare_gcc.cc new file mode 100644 index 00000000..1b83edb1 --- /dev/null +++ b/TMessagesProj/jni/libyuv/source/compare_gcc.cc @@ -0,0 +1,151 @@ +/* + * Copyright 2012 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "libyuv/basic_types.h" + +#include "libyuv/compare_row.h" +#include "libyuv/row.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// This module is for GCC x86 and x64. +#if !defined(LIBYUV_DISABLE_X86) && \ + (defined(__x86_64__) || (defined(__i386__) && !defined(_MSC_VER))) + +uint32 SumSquareError_SSE2(const uint8* src_a, const uint8* src_b, int count) { + uint32 sse; + asm volatile ( + "pxor %%xmm0,%%xmm0 \n" + "pxor %%xmm5,%%xmm5 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm1 \n" + "lea " MEMLEA(0x10, 0) ",%0 \n" + "movdqu " MEMACCESS(1) ",%%xmm2 \n" + "lea " MEMLEA(0x10, 1) ",%1 \n" + "movdqa %%xmm1,%%xmm3 \n" + "psubusb %%xmm2,%%xmm1 \n" + "psubusb %%xmm3,%%xmm2 \n" + "por %%xmm2,%%xmm1 \n" + "movdqa %%xmm1,%%xmm2 \n" + "punpcklbw %%xmm5,%%xmm1 \n" + "punpckhbw %%xmm5,%%xmm2 \n" + "pmaddwd %%xmm1,%%xmm1 \n" + "pmaddwd %%xmm2,%%xmm2 \n" + "paddd %%xmm1,%%xmm0 \n" + "paddd %%xmm2,%%xmm0 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + + "pshufd $0xee,%%xmm0,%%xmm1 \n" + "paddd %%xmm1,%%xmm0 \n" + "pshufd $0x1,%%xmm0,%%xmm1 \n" + "paddd %%xmm1,%%xmm0 \n" + "movd %%xmm0,%3 \n" + + : "+r"(src_a), // %0 + "+r"(src_b), // %1 + "+r"(count), // %2 + "=g"(sse) // %3 + :: "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" + ); + return sse; +} + +static uvec32 kHash16x33 = { 0x92d9e201, 0, 0, 0 }; // 33 ^ 16 +static uvec32 kHashMul0 = { + 0x0c3525e1, // 33 ^ 15 + 0xa3476dc1, // 33 ^ 14 + 0x3b4039a1, // 33 ^ 13 + 0x4f5f0981, // 33 ^ 12 +}; +static uvec32 kHashMul1 = { + 0x30f35d61, // 33 ^ 11 + 0x855cb541, // 33 ^ 10 + 0x040a9121, // 33 ^ 9 + 0x747c7101, // 33 ^ 8 +}; +static uvec32 kHashMul2 = { + 0xec41d4e1, // 33 ^ 7 + 0x4cfa3cc1, // 33 ^ 6 + 0x025528a1, // 33 ^ 5 + 0x00121881, // 33 ^ 4 +}; +static uvec32 kHashMul3 = { + 0x00008c61, // 33 ^ 3 + 0x00000441, // 33 ^ 2 + 0x00000021, // 33 ^ 1 + 0x00000001, // 33 ^ 0 +}; + +uint32 HashDjb2_SSE41(const uint8* src, int count, uint32 seed) { + uint32 hash; + asm volatile ( + "movd %2,%%xmm0 \n" + "pxor %%xmm7,%%xmm7 \n" + "movdqa %4,%%xmm6 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm1 \n" + "lea " MEMLEA(0x10, 0) ",%0 \n" + "pmulld %%xmm6,%%xmm0 \n" + "movdqa %5,%%xmm5 \n" + "movdqa %%xmm1,%%xmm2 \n" + "punpcklbw %%xmm7,%%xmm2 \n" + "movdqa %%xmm2,%%xmm3 \n" + "punpcklwd %%xmm7,%%xmm3 \n" + "pmulld %%xmm5,%%xmm3 \n" + "movdqa %6,%%xmm5 \n" + "movdqa %%xmm2,%%xmm4 \n" + "punpckhwd %%xmm7,%%xmm4 \n" + "pmulld %%xmm5,%%xmm4 \n" + "movdqa %7,%%xmm5 \n" + "punpckhbw %%xmm7,%%xmm1 \n" + "movdqa %%xmm1,%%xmm2 \n" + "punpcklwd %%xmm7,%%xmm2 \n" + "pmulld %%xmm5,%%xmm2 \n" + "movdqa %8,%%xmm5 \n" + "punpckhwd %%xmm7,%%xmm1 \n" + "pmulld %%xmm5,%%xmm1 \n" + "paddd %%xmm4,%%xmm3 \n" + "paddd %%xmm2,%%xmm1 \n" + "paddd %%xmm3,%%xmm1 \n" + "pshufd $0xe,%%xmm1,%%xmm2 \n" + "paddd %%xmm2,%%xmm1 \n" + "pshufd $0x1,%%xmm1,%%xmm2 \n" + "paddd %%xmm2,%%xmm1 \n" + "paddd %%xmm1,%%xmm0 \n" + "sub $0x10,%1 \n" + "jg 1b \n" + "movd %%xmm0,%3 \n" + : "+r"(src), // %0 + "+r"(count), // %1 + "+rm"(seed), // %2 + "=g"(hash) // %3 + : "m"(kHash16x33), // %4 + "m"(kHashMul0), // %5 + "m"(kHashMul1), // %6 + "m"(kHashMul2), // %7 + "m"(kHashMul3) // %8 + : "memory", "cc" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); + return hash; +} +#endif // defined(__x86_64__) || (defined(__i386__) && !defined(__pic__))) + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + diff --git a/TMessagesProj/jni/libyuv/source/compare_neon64.cc b/TMessagesProj/jni/libyuv/source/compare_neon64.cc new file mode 100644 index 00000000..f9c7df98 --- /dev/null +++ b/TMessagesProj/jni/libyuv/source/compare_neon64.cc @@ -0,0 +1,64 @@ +/* + * Copyright 2012 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "libyuv/basic_types.h" + +#include "libyuv/compare_row.h" +#include "libyuv/row.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +#if !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__) + +uint32 SumSquareError_NEON(const uint8* src_a, const uint8* src_b, int count) { + volatile uint32 sse; + asm volatile ( + "eor v16.16b, v16.16b, v16.16b \n" + "eor v18.16b, v18.16b, v18.16b \n" + "eor v17.16b, v17.16b, v17.16b \n" + "eor v19.16b, v19.16b, v19.16b \n" + + "1: \n" + MEMACCESS(0) + "ld1 {v0.16b}, [%0], #16 \n" + MEMACCESS(1) + "ld1 {v1.16b}, [%1], #16 \n" + "subs %w2, %w2, #16 \n" + "usubl v2.8h, v0.8b, v1.8b \n" + "usubl2 v3.8h, v0.16b, v1.16b \n" + "smlal v16.4s, v2.4h, v2.4h \n" + "smlal v17.4s, v3.4h, v3.4h \n" + "smlal2 v18.4s, v2.8h, v2.8h \n" + "smlal2 v19.4s, v3.8h, v3.8h \n" + "b.gt 1b \n" + + "add v16.4s, v16.4s, v17.4s \n" + "add v18.4s, v18.4s, v19.4s \n" + "add v19.4s, v16.4s, v18.4s \n" + "addv s0, v19.4s \n" + "fmov %w3, s0 \n" + : "+r"(src_a), + "+r"(src_b), + "+r"(count), + "=r"(sse) + : + : "cc", "v0", "v1", "v2", "v3", "v16", "v17", "v18", "v19"); + return sse; +} + +#endif // !defined(LIBYUV_DISABLE_NEON) && defined(__aarch64__) + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif diff --git a/TMessagesProj/jni/libyuv/source/rotate_any.cc b/TMessagesProj/jni/libyuv/source/rotate_any.cc new file mode 100644 index 00000000..d12bad5d --- /dev/null +++ b/TMessagesProj/jni/libyuv/source/rotate_any.cc @@ -0,0 +1,80 @@ +/* + * Copyright 2015 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "libyuv/rotate.h" +#include "libyuv/rotate_row.h" + +#include "libyuv/basic_types.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +#define TANY(NAMEANY, TPOS_SIMD, MASK) \ + void NAMEANY(const uint8* src, int src_stride, \ + uint8* dst, int dst_stride, int width) { \ + int r = width & MASK; \ + int n = width - r; \ + if (n > 0) { \ + TPOS_SIMD(src, src_stride, dst, dst_stride, n); \ + } \ + TransposeWx8_C(src + n, src_stride, dst + n * dst_stride, dst_stride, r);\ + } + +#ifdef HAS_TRANSPOSEWX8_NEON +TANY(TransposeWx8_Any_NEON, TransposeWx8_NEON, 7) +#endif +#ifdef HAS_TRANSPOSEWX8_SSSE3 +TANY(TransposeWx8_Any_SSSE3, TransposeWx8_SSSE3, 7) +#endif +#ifdef HAS_TRANSPOSEWX8_FAST_SSSE3 +TANY(TransposeWx8_Fast_Any_SSSE3, TransposeWx8_Fast_SSSE3, 15) +#endif +#ifdef HAS_TRANSPOSEWX8_MIPS_DSPR2 +TANY(TransposeWx8_Any_MIPS_DSPR2, TransposeWx8_MIPS_DSPR2, 7) +#endif +#undef TANY + +#define TUVANY(NAMEANY, TPOS_SIMD, MASK) \ + void NAMEANY(const uint8* src, int src_stride, \ + uint8* dst_a, int dst_stride_a, \ + uint8* dst_b, int dst_stride_b, int width) { \ + int r = width & MASK; \ + int n = width - r; \ + if (n > 0) { \ + TPOS_SIMD(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b, \ + n); \ + } \ + TransposeUVWx8_C(src + n * 2, src_stride, \ + dst_a + n * dst_stride_a, dst_stride_a, \ + dst_b + n * dst_stride_b, dst_stride_b, r); \ + } + +#ifdef HAS_TRANSPOSEUVWX8_NEON +TUVANY(TransposeUVWx8_Any_NEON, TransposeUVWx8_NEON, 7) +#endif +#ifdef HAS_TRANSPOSEUVWX8_SSE2 +TUVANY(TransposeUVWx8_Any_SSE2, TransposeUVWx8_SSE2, 7) +#endif +#ifdef HAS_TRANSPOSEUVWX8_MIPS_DSPR2 +TUVANY(TransposeUVWx8_Any_MIPS_DSPR2, TransposeUVWx8_MIPS_DSPR2, 7) +#endif +#undef TUVANY + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + + + + + diff --git a/TMessagesProj/jni/libyuv/source/rotate_common.cc b/TMessagesProj/jni/libyuv/source/rotate_common.cc new file mode 100644 index 00000000..b33a9a0c --- /dev/null +++ b/TMessagesProj/jni/libyuv/source/rotate_common.cc @@ -0,0 +1,92 @@ +/* + * Copyright 2011 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "libyuv/row.h" +#include "libyuv/rotate_row.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +void TransposeWx8_C(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width) { + int i; + for (i = 0; i < width; ++i) { + dst[0] = src[0 * src_stride]; + dst[1] = src[1 * src_stride]; + dst[2] = src[2 * src_stride]; + dst[3] = src[3 * src_stride]; + dst[4] = src[4 * src_stride]; + dst[5] = src[5 * src_stride]; + dst[6] = src[6 * src_stride]; + dst[7] = src[7 * src_stride]; + ++src; + dst += dst_stride; + } +} + +void TransposeUVWx8_C(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, int width) { + int i; + for (i = 0; i < width; ++i) { + dst_a[0] = src[0 * src_stride + 0]; + dst_b[0] = src[0 * src_stride + 1]; + dst_a[1] = src[1 * src_stride + 0]; + dst_b[1] = src[1 * src_stride + 1]; + dst_a[2] = src[2 * src_stride + 0]; + dst_b[2] = src[2 * src_stride + 1]; + dst_a[3] = src[3 * src_stride + 0]; + dst_b[3] = src[3 * src_stride + 1]; + dst_a[4] = src[4 * src_stride + 0]; + dst_b[4] = src[4 * src_stride + 1]; + dst_a[5] = src[5 * src_stride + 0]; + dst_b[5] = src[5 * src_stride + 1]; + dst_a[6] = src[6 * src_stride + 0]; + dst_b[6] = src[6 * src_stride + 1]; + dst_a[7] = src[7 * src_stride + 0]; + dst_b[7] = src[7 * src_stride + 1]; + src += 2; + dst_a += dst_stride_a; + dst_b += dst_stride_b; + } +} + +void TransposeWxH_C(const uint8* src, int src_stride, + uint8* dst, int dst_stride, + int width, int height) { + int i; + for (i = 0; i < width; ++i) { + int j; + for (j = 0; j < height; ++j) { + dst[i * dst_stride + j] = src[j * src_stride + i]; + } + } +} + +void TransposeUVWxH_C(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, + int width, int height) { + int i; + for (i = 0; i < width * 2; i += 2) { + int j; + for (j = 0; j < height; ++j) { + dst_a[j + ((i >> 1) * dst_stride_a)] = src[i + (j * src_stride)]; + dst_b[j + ((i >> 1) * dst_stride_b)] = src[i + (j * src_stride) + 1]; + } + } +} + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif diff --git a/TMessagesProj/jni/libyuv/source/rotate_gcc.cc b/TMessagesProj/jni/libyuv/source/rotate_gcc.cc new file mode 100644 index 00000000..cbe870ca --- /dev/null +++ b/TMessagesProj/jni/libyuv/source/rotate_gcc.cc @@ -0,0 +1,368 @@ +/* + * Copyright 2015 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "libyuv/row.h" +#include "libyuv/rotate_row.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// This module is for GCC x86 and x64. +#if !defined(LIBYUV_DISABLE_X86) && \ + (defined(__x86_64__) || (defined(__i386__) && !defined(_MSC_VER))) + +// Transpose 8x8. 32 or 64 bit, but not NaCL for 64 bit. +#if defined(HAS_TRANSPOSEWX8_SSSE3) +void TransposeWx8_SSSE3(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width) { + asm volatile ( + // Read in the data from the source pointer. + // First round of bit swap. + LABELALIGN + "1: \n" + "movq (%0),%%xmm0 \n" + "movq (%0,%3),%%xmm1 \n" + "lea (%0,%3,2),%0 \n" + "punpcklbw %%xmm1,%%xmm0 \n" + "movq (%0),%%xmm2 \n" + "movdqa %%xmm0,%%xmm1 \n" + "palignr $0x8,%%xmm1,%%xmm1 \n" + "movq (%0,%3),%%xmm3 \n" + "lea (%0,%3,2),%0 \n" + "punpcklbw %%xmm3,%%xmm2 \n" + "movdqa %%xmm2,%%xmm3 \n" + "movq (%0),%%xmm4 \n" + "palignr $0x8,%%xmm3,%%xmm3 \n" + "movq (%0,%3),%%xmm5 \n" + "lea (%0,%3,2),%0 \n" + "punpcklbw %%xmm5,%%xmm4 \n" + "movdqa %%xmm4,%%xmm5 \n" + "movq (%0),%%xmm6 \n" + "palignr $0x8,%%xmm5,%%xmm5 \n" + "movq (%0,%3),%%xmm7 \n" + "lea (%0,%3,2),%0 \n" + "punpcklbw %%xmm7,%%xmm6 \n" + "neg %3 \n" + "movdqa %%xmm6,%%xmm7 \n" + "lea 0x8(%0,%3,8),%0 \n" + "palignr $0x8,%%xmm7,%%xmm7 \n" + "neg %3 \n" + // Second round of bit swap. + "punpcklwd %%xmm2,%%xmm0 \n" + "punpcklwd %%xmm3,%%xmm1 \n" + "movdqa %%xmm0,%%xmm2 \n" + "movdqa %%xmm1,%%xmm3 \n" + "palignr $0x8,%%xmm2,%%xmm2 \n" + "palignr $0x8,%%xmm3,%%xmm3 \n" + "punpcklwd %%xmm6,%%xmm4 \n" + "punpcklwd %%xmm7,%%xmm5 \n" + "movdqa %%xmm4,%%xmm6 \n" + "movdqa %%xmm5,%%xmm7 \n" + "palignr $0x8,%%xmm6,%%xmm6 \n" + "palignr $0x8,%%xmm7,%%xmm7 \n" + // Third round of bit swap. + // Write to the destination pointer. + "punpckldq %%xmm4,%%xmm0 \n" + "movq %%xmm0,(%1) \n" + "movdqa %%xmm0,%%xmm4 \n" + "palignr $0x8,%%xmm4,%%xmm4 \n" + "movq %%xmm4,(%1,%4) \n" + "lea (%1,%4,2),%1 \n" + "punpckldq %%xmm6,%%xmm2 \n" + "movdqa %%xmm2,%%xmm6 \n" + "movq %%xmm2,(%1) \n" + "palignr $0x8,%%xmm6,%%xmm6 \n" + "punpckldq %%xmm5,%%xmm1 \n" + "movq %%xmm6,(%1,%4) \n" + "lea (%1,%4,2),%1 \n" + "movdqa %%xmm1,%%xmm5 \n" + "movq %%xmm1,(%1) \n" + "palignr $0x8,%%xmm5,%%xmm5 \n" + "movq %%xmm5,(%1,%4) \n" + "lea (%1,%4,2),%1 \n" + "punpckldq %%xmm7,%%xmm3 \n" + "movq %%xmm3,(%1) \n" + "movdqa %%xmm3,%%xmm7 \n" + "palignr $0x8,%%xmm7,%%xmm7 \n" + "sub $0x8,%2 \n" + "movq %%xmm7,(%1,%4) \n" + "lea (%1,%4,2),%1 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : "r"((intptr_t)(src_stride)), // %3 + "r"((intptr_t)(dst_stride)) // %4 + : "memory", "cc", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} +#endif // defined(HAS_TRANSPOSEWX8_SSSE3) + +// Transpose 16x8. 64 bit +#if defined(HAS_TRANSPOSEWX8_FAST_SSSE3) +void TransposeWx8_Fast_SSSE3(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width) { + asm volatile ( + // Read in the data from the source pointer. + // First round of bit swap. + LABELALIGN + "1: \n" + "movdqu (%0),%%xmm0 \n" + "movdqu (%0,%3),%%xmm1 \n" + "lea (%0,%3,2),%0 \n" + "movdqa %%xmm0,%%xmm8 \n" + "punpcklbw %%xmm1,%%xmm0 \n" + "punpckhbw %%xmm1,%%xmm8 \n" + "movdqu (%0),%%xmm2 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm8,%%xmm9 \n" + "palignr $0x8,%%xmm1,%%xmm1 \n" + "palignr $0x8,%%xmm9,%%xmm9 \n" + "movdqu (%0,%3),%%xmm3 \n" + "lea (%0,%3,2),%0 \n" + "movdqa %%xmm2,%%xmm10 \n" + "punpcklbw %%xmm3,%%xmm2 \n" + "punpckhbw %%xmm3,%%xmm10 \n" + "movdqa %%xmm2,%%xmm3 \n" + "movdqa %%xmm10,%%xmm11 \n" + "movdqu (%0),%%xmm4 \n" + "palignr $0x8,%%xmm3,%%xmm3 \n" + "palignr $0x8,%%xmm11,%%xmm11 \n" + "movdqu (%0,%3),%%xmm5 \n" + "lea (%0,%3,2),%0 \n" + "movdqa %%xmm4,%%xmm12 \n" + "punpcklbw %%xmm5,%%xmm4 \n" + "punpckhbw %%xmm5,%%xmm12 \n" + "movdqa %%xmm4,%%xmm5 \n" + "movdqa %%xmm12,%%xmm13 \n" + "movdqu (%0),%%xmm6 \n" + "palignr $0x8,%%xmm5,%%xmm5 \n" + "palignr $0x8,%%xmm13,%%xmm13 \n" + "movdqu (%0,%3),%%xmm7 \n" + "lea (%0,%3,2),%0 \n" + "movdqa %%xmm6,%%xmm14 \n" + "punpcklbw %%xmm7,%%xmm6 \n" + "punpckhbw %%xmm7,%%xmm14 \n" + "neg %3 \n" + "movdqa %%xmm6,%%xmm7 \n" + "movdqa %%xmm14,%%xmm15 \n" + "lea 0x10(%0,%3,8),%0 \n" + "palignr $0x8,%%xmm7,%%xmm7 \n" + "palignr $0x8,%%xmm15,%%xmm15 \n" + "neg %3 \n" + // Second round of bit swap. + "punpcklwd %%xmm2,%%xmm0 \n" + "punpcklwd %%xmm3,%%xmm1 \n" + "movdqa %%xmm0,%%xmm2 \n" + "movdqa %%xmm1,%%xmm3 \n" + "palignr $0x8,%%xmm2,%%xmm2 \n" + "palignr $0x8,%%xmm3,%%xmm3 \n" + "punpcklwd %%xmm6,%%xmm4 \n" + "punpcklwd %%xmm7,%%xmm5 \n" + "movdqa %%xmm4,%%xmm6 \n" + "movdqa %%xmm5,%%xmm7 \n" + "palignr $0x8,%%xmm6,%%xmm6 \n" + "palignr $0x8,%%xmm7,%%xmm7 \n" + "punpcklwd %%xmm10,%%xmm8 \n" + "punpcklwd %%xmm11,%%xmm9 \n" + "movdqa %%xmm8,%%xmm10 \n" + "movdqa %%xmm9,%%xmm11 \n" + "palignr $0x8,%%xmm10,%%xmm10 \n" + "palignr $0x8,%%xmm11,%%xmm11 \n" + "punpcklwd %%xmm14,%%xmm12 \n" + "punpcklwd %%xmm15,%%xmm13 \n" + "movdqa %%xmm12,%%xmm14 \n" + "movdqa %%xmm13,%%xmm15 \n" + "palignr $0x8,%%xmm14,%%xmm14 \n" + "palignr $0x8,%%xmm15,%%xmm15 \n" + // Third round of bit swap. + // Write to the destination pointer. + "punpckldq %%xmm4,%%xmm0 \n" + "movq %%xmm0,(%1) \n" + "movdqa %%xmm0,%%xmm4 \n" + "palignr $0x8,%%xmm4,%%xmm4 \n" + "movq %%xmm4,(%1,%4) \n" + "lea (%1,%4,2),%1 \n" + "punpckldq %%xmm6,%%xmm2 \n" + "movdqa %%xmm2,%%xmm6 \n" + "movq %%xmm2,(%1) \n" + "palignr $0x8,%%xmm6,%%xmm6 \n" + "punpckldq %%xmm5,%%xmm1 \n" + "movq %%xmm6,(%1,%4) \n" + "lea (%1,%4,2),%1 \n" + "movdqa %%xmm1,%%xmm5 \n" + "movq %%xmm1,(%1) \n" + "palignr $0x8,%%xmm5,%%xmm5 \n" + "movq %%xmm5,(%1,%4) \n" + "lea (%1,%4,2),%1 \n" + "punpckldq %%xmm7,%%xmm3 \n" + "movq %%xmm3,(%1) \n" + "movdqa %%xmm3,%%xmm7 \n" + "palignr $0x8,%%xmm7,%%xmm7 \n" + "movq %%xmm7,(%1,%4) \n" + "lea (%1,%4,2),%1 \n" + "punpckldq %%xmm12,%%xmm8 \n" + "movq %%xmm8,(%1) \n" + "movdqa %%xmm8,%%xmm12 \n" + "palignr $0x8,%%xmm12,%%xmm12 \n" + "movq %%xmm12,(%1,%4) \n" + "lea (%1,%4,2),%1 \n" + "punpckldq %%xmm14,%%xmm10 \n" + "movdqa %%xmm10,%%xmm14 \n" + "movq %%xmm10,(%1) \n" + "palignr $0x8,%%xmm14,%%xmm14 \n" + "punpckldq %%xmm13,%%xmm9 \n" + "movq %%xmm14,(%1,%4) \n" + "lea (%1,%4,2),%1 \n" + "movdqa %%xmm9,%%xmm13 \n" + "movq %%xmm9,(%1) \n" + "palignr $0x8,%%xmm13,%%xmm13 \n" + "movq %%xmm13,(%1,%4) \n" + "lea (%1,%4,2),%1 \n" + "punpckldq %%xmm15,%%xmm11 \n" + "movq %%xmm11,(%1) \n" + "movdqa %%xmm11,%%xmm15 \n" + "palignr $0x8,%%xmm15,%%xmm15 \n" + "sub $0x10,%2 \n" + "movq %%xmm15,(%1,%4) \n" + "lea (%1,%4,2),%1 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : "r"((intptr_t)(src_stride)), // %3 + "r"((intptr_t)(dst_stride)) // %4 + : "memory", "cc", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", + "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" + ); +} +#endif // defined(HAS_TRANSPOSEWX8_FAST_SSSE3) + +// Transpose UV 8x8. 64 bit. +#if defined(HAS_TRANSPOSEUVWX8_SSE2) +void TransposeUVWx8_SSE2(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, int width) { + asm volatile ( + // Read in the data from the source pointer. + // First round of bit swap. + LABELALIGN + "1: \n" + "movdqu (%0),%%xmm0 \n" + "movdqu (%0,%4),%%xmm1 \n" + "lea (%0,%4,2),%0 \n" + "movdqa %%xmm0,%%xmm8 \n" + "punpcklbw %%xmm1,%%xmm0 \n" + "punpckhbw %%xmm1,%%xmm8 \n" + "movdqa %%xmm8,%%xmm1 \n" + "movdqu (%0),%%xmm2 \n" + "movdqu (%0,%4),%%xmm3 \n" + "lea (%0,%4,2),%0 \n" + "movdqa %%xmm2,%%xmm8 \n" + "punpcklbw %%xmm3,%%xmm2 \n" + "punpckhbw %%xmm3,%%xmm8 \n" + "movdqa %%xmm8,%%xmm3 \n" + "movdqu (%0),%%xmm4 \n" + "movdqu (%0,%4),%%xmm5 \n" + "lea (%0,%4,2),%0 \n" + "movdqa %%xmm4,%%xmm8 \n" + "punpcklbw %%xmm5,%%xmm4 \n" + "punpckhbw %%xmm5,%%xmm8 \n" + "movdqa %%xmm8,%%xmm5 \n" + "movdqu (%0),%%xmm6 \n" + "movdqu (%0,%4),%%xmm7 \n" + "lea (%0,%4,2),%0 \n" + "movdqa %%xmm6,%%xmm8 \n" + "punpcklbw %%xmm7,%%xmm6 \n" + "neg %4 \n" + "lea 0x10(%0,%4,8),%0 \n" + "punpckhbw %%xmm7,%%xmm8 \n" + "movdqa %%xmm8,%%xmm7 \n" + "neg %4 \n" + // Second round of bit swap. + "movdqa %%xmm0,%%xmm8 \n" + "movdqa %%xmm1,%%xmm9 \n" + "punpckhwd %%xmm2,%%xmm8 \n" + "punpckhwd %%xmm3,%%xmm9 \n" + "punpcklwd %%xmm2,%%xmm0 \n" + "punpcklwd %%xmm3,%%xmm1 \n" + "movdqa %%xmm8,%%xmm2 \n" + "movdqa %%xmm9,%%xmm3 \n" + "movdqa %%xmm4,%%xmm8 \n" + "movdqa %%xmm5,%%xmm9 \n" + "punpckhwd %%xmm6,%%xmm8 \n" + "punpckhwd %%xmm7,%%xmm9 \n" + "punpcklwd %%xmm6,%%xmm4 \n" + "punpcklwd %%xmm7,%%xmm5 \n" + "movdqa %%xmm8,%%xmm6 \n" + "movdqa %%xmm9,%%xmm7 \n" + // Third round of bit swap. + // Write to the destination pointer. + "movdqa %%xmm0,%%xmm8 \n" + "punpckldq %%xmm4,%%xmm0 \n" + "movlpd %%xmm0,(%1) \n" // Write back U channel + "movhpd %%xmm0,(%2) \n" // Write back V channel + "punpckhdq %%xmm4,%%xmm8 \n" + "movlpd %%xmm8,(%1,%5) \n" + "lea (%1,%5,2),%1 \n" + "movhpd %%xmm8,(%2,%6) \n" + "lea (%2,%6,2),%2 \n" + "movdqa %%xmm2,%%xmm8 \n" + "punpckldq %%xmm6,%%xmm2 \n" + "movlpd %%xmm2,(%1) \n" + "movhpd %%xmm2,(%2) \n" + "punpckhdq %%xmm6,%%xmm8 \n" + "movlpd %%xmm8,(%1,%5) \n" + "lea (%1,%5,2),%1 \n" + "movhpd %%xmm8,(%2,%6) \n" + "lea (%2,%6,2),%2 \n" + "movdqa %%xmm1,%%xmm8 \n" + "punpckldq %%xmm5,%%xmm1 \n" + "movlpd %%xmm1,(%1) \n" + "movhpd %%xmm1,(%2) \n" + "punpckhdq %%xmm5,%%xmm8 \n" + "movlpd %%xmm8,(%1,%5) \n" + "lea (%1,%5,2),%1 \n" + "movhpd %%xmm8,(%2,%6) \n" + "lea (%2,%6,2),%2 \n" + "movdqa %%xmm3,%%xmm8 \n" + "punpckldq %%xmm7,%%xmm3 \n" + "movlpd %%xmm3,(%1) \n" + "movhpd %%xmm3,(%2) \n" + "punpckhdq %%xmm7,%%xmm8 \n" + "sub $0x8,%3 \n" + "movlpd %%xmm8,(%1,%5) \n" + "lea (%1,%5,2),%1 \n" + "movhpd %%xmm8,(%2,%6) \n" + "lea (%2,%6,2),%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst_a), // %1 + "+r"(dst_b), // %2 + "+r"(width) // %3 + : "r"((intptr_t)(src_stride)), // %4 + "r"((intptr_t)(dst_stride_a)), // %5 + "r"((intptr_t)(dst_stride_b)) // %6 + : "memory", "cc", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", + "xmm8", "xmm9" + ); +} +#endif // defined(HAS_TRANSPOSEUVWX8_SSE2) +#endif // defined(__x86_64__) || defined(__i386__) + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif diff --git a/TMessagesProj/jni/libyuv/source/rotate_win.cc b/TMessagesProj/jni/libyuv/source/rotate_win.cc new file mode 100644 index 00000000..1300fc0f --- /dev/null +++ b/TMessagesProj/jni/libyuv/source/rotate_win.cc @@ -0,0 +1,247 @@ +/* + * Copyright 2013 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "libyuv/row.h" +#include "libyuv/rotate_row.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// This module is for 32 bit Visual C x86 and clangcl +#if !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) + +__declspec(naked) +void TransposeWx8_SSSE3(const uint8* src, int src_stride, + uint8* dst, int dst_stride, int width) { + __asm { + push edi + push esi + push ebp + mov eax, [esp + 12 + 4] // src + mov edi, [esp + 12 + 8] // src_stride + mov edx, [esp + 12 + 12] // dst + mov esi, [esp + 12 + 16] // dst_stride + mov ecx, [esp + 12 + 20] // width + + // Read in the data from the source pointer. + // First round of bit swap. + align 4 + convertloop: + movq xmm0, qword ptr [eax] + lea ebp, [eax + 8] + movq xmm1, qword ptr [eax + edi] + lea eax, [eax + 2 * edi] + punpcklbw xmm0, xmm1 + movq xmm2, qword ptr [eax] + movdqa xmm1, xmm0 + palignr xmm1, xmm1, 8 + movq xmm3, qword ptr [eax + edi] + lea eax, [eax + 2 * edi] + punpcklbw xmm2, xmm3 + movdqa xmm3, xmm2 + movq xmm4, qword ptr [eax] + palignr xmm3, xmm3, 8 + movq xmm5, qword ptr [eax + edi] + punpcklbw xmm4, xmm5 + lea eax, [eax + 2 * edi] + movdqa xmm5, xmm4 + movq xmm6, qword ptr [eax] + palignr xmm5, xmm5, 8 + movq xmm7, qword ptr [eax + edi] + punpcklbw xmm6, xmm7 + mov eax, ebp + movdqa xmm7, xmm6 + palignr xmm7, xmm7, 8 + // Second round of bit swap. + punpcklwd xmm0, xmm2 + punpcklwd xmm1, xmm3 + movdqa xmm2, xmm0 + movdqa xmm3, xmm1 + palignr xmm2, xmm2, 8 + palignr xmm3, xmm3, 8 + punpcklwd xmm4, xmm6 + punpcklwd xmm5, xmm7 + movdqa xmm6, xmm4 + movdqa xmm7, xmm5 + palignr xmm6, xmm6, 8 + palignr xmm7, xmm7, 8 + // Third round of bit swap. + // Write to the destination pointer. + punpckldq xmm0, xmm4 + movq qword ptr [edx], xmm0 + movdqa xmm4, xmm0 + palignr xmm4, xmm4, 8 + movq qword ptr [edx + esi], xmm4 + lea edx, [edx + 2 * esi] + punpckldq xmm2, xmm6 + movdqa xmm6, xmm2 + palignr xmm6, xmm6, 8 + movq qword ptr [edx], xmm2 + punpckldq xmm1, xmm5 + movq qword ptr [edx + esi], xmm6 + lea edx, [edx + 2 * esi] + movdqa xmm5, xmm1 + movq qword ptr [edx], xmm1 + palignr xmm5, xmm5, 8 + punpckldq xmm3, xmm7 + movq qword ptr [edx + esi], xmm5 + lea edx, [edx + 2 * esi] + movq qword ptr [edx], xmm3 + movdqa xmm7, xmm3 + palignr xmm7, xmm7, 8 + sub ecx, 8 + movq qword ptr [edx + esi], xmm7 + lea edx, [edx + 2 * esi] + jg convertloop + + pop ebp + pop esi + pop edi + ret + } +} + +__declspec(naked) +void TransposeUVWx8_SSE2(const uint8* src, int src_stride, + uint8* dst_a, int dst_stride_a, + uint8* dst_b, int dst_stride_b, + int w) { + __asm { + push ebx + push esi + push edi + push ebp + mov eax, [esp + 16 + 4] // src + mov edi, [esp + 16 + 8] // src_stride + mov edx, [esp + 16 + 12] // dst_a + mov esi, [esp + 16 + 16] // dst_stride_a + mov ebx, [esp + 16 + 20] // dst_b + mov ebp, [esp + 16 + 24] // dst_stride_b + mov ecx, esp + sub esp, 4 + 16 + and esp, ~15 + mov [esp + 16], ecx + mov ecx, [ecx + 16 + 28] // w + + align 4 + convertloop: + // Read in the data from the source pointer. + // First round of bit swap. + movdqu xmm0, [eax] + movdqu xmm1, [eax + edi] + lea eax, [eax + 2 * edi] + movdqa xmm7, xmm0 // use xmm7 as temp register. + punpcklbw xmm0, xmm1 + punpckhbw xmm7, xmm1 + movdqa xmm1, xmm7 + movdqu xmm2, [eax] + movdqu xmm3, [eax + edi] + lea eax, [eax + 2 * edi] + movdqa xmm7, xmm2 + punpcklbw xmm2, xmm3 + punpckhbw xmm7, xmm3 + movdqa xmm3, xmm7 + movdqu xmm4, [eax] + movdqu xmm5, [eax + edi] + lea eax, [eax + 2 * edi] + movdqa xmm7, xmm4 + punpcklbw xmm4, xmm5 + punpckhbw xmm7, xmm5 + movdqa xmm5, xmm7 + movdqu xmm6, [eax] + movdqu xmm7, [eax + edi] + lea eax, [eax + 2 * edi] + movdqu [esp], xmm5 // backup xmm5 + neg edi + movdqa xmm5, xmm6 // use xmm5 as temp register. + punpcklbw xmm6, xmm7 + punpckhbw xmm5, xmm7 + movdqa xmm7, xmm5 + lea eax, [eax + 8 * edi + 16] + neg edi + // Second round of bit swap. + movdqa xmm5, xmm0 + punpcklwd xmm0, xmm2 + punpckhwd xmm5, xmm2 + movdqa xmm2, xmm5 + movdqa xmm5, xmm1 + punpcklwd xmm1, xmm3 + punpckhwd xmm5, xmm3 + movdqa xmm3, xmm5 + movdqa xmm5, xmm4 + punpcklwd xmm4, xmm6 + punpckhwd xmm5, xmm6 + movdqa xmm6, xmm5 + movdqu xmm5, [esp] // restore xmm5 + movdqu [esp], xmm6 // backup xmm6 + movdqa xmm6, xmm5 // use xmm6 as temp register. + punpcklwd xmm5, xmm7 + punpckhwd xmm6, xmm7 + movdqa xmm7, xmm6 + // Third round of bit swap. + // Write to the destination pointer. + movdqa xmm6, xmm0 + punpckldq xmm0, xmm4 + punpckhdq xmm6, xmm4 + movdqa xmm4, xmm6 + movdqu xmm6, [esp] // restore xmm6 + movlpd qword ptr [edx], xmm0 + movhpd qword ptr [ebx], xmm0 + movlpd qword ptr [edx + esi], xmm4 + lea edx, [edx + 2 * esi] + movhpd qword ptr [ebx + ebp], xmm4 + lea ebx, [ebx + 2 * ebp] + movdqa xmm0, xmm2 // use xmm0 as the temp register. + punpckldq xmm2, xmm6 + movlpd qword ptr [edx], xmm2 + movhpd qword ptr [ebx], xmm2 + punpckhdq xmm0, xmm6 + movlpd qword ptr [edx + esi], xmm0 + lea edx, [edx + 2 * esi] + movhpd qword ptr [ebx + ebp], xmm0 + lea ebx, [ebx + 2 * ebp] + movdqa xmm0, xmm1 // use xmm0 as the temp register. + punpckldq xmm1, xmm5 + movlpd qword ptr [edx], xmm1 + movhpd qword ptr [ebx], xmm1 + punpckhdq xmm0, xmm5 + movlpd qword ptr [edx + esi], xmm0 + lea edx, [edx + 2 * esi] + movhpd qword ptr [ebx + ebp], xmm0 + lea ebx, [ebx + 2 * ebp] + movdqa xmm0, xmm3 // use xmm0 as the temp register. + punpckldq xmm3, xmm7 + movlpd qword ptr [edx], xmm3 + movhpd qword ptr [ebx], xmm3 + punpckhdq xmm0, xmm7 + sub ecx, 8 + movlpd qword ptr [edx + esi], xmm0 + lea edx, [edx + 2 * esi] + movhpd qword ptr [ebx + ebp], xmm0 + lea ebx, [ebx + 2 * ebp] + jg convertloop + + mov esp, [esp + 16] + pop ebp + pop edi + pop esi + pop ebx + ret + } +} + +#endif // !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif diff --git a/TMessagesProj/jni/libyuv/source/row_gcc.cc b/TMessagesProj/jni/libyuv/source/row_gcc.cc new file mode 100644 index 00000000..80b2a95a --- /dev/null +++ b/TMessagesProj/jni/libyuv/source/row_gcc.cc @@ -0,0 +1,5452 @@ +// VERSION 2 +/* + * Copyright 2011 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "libyuv/row.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// This module is for GCC x86 and x64. +#if !defined(LIBYUV_DISABLE_X86) && \ + (defined(__x86_64__) || (defined(__i386__) && !defined(_MSC_VER))) + +#if defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_ARGBGRAYROW_SSSE3) + +// Constants for ARGB +static vec8 kARGBToY = { + 13, 65, 33, 0, 13, 65, 33, 0, 13, 65, 33, 0, 13, 65, 33, 0 +}; + +// JPeg full range. +static vec8 kARGBToYJ = { + 15, 75, 38, 0, 15, 75, 38, 0, 15, 75, 38, 0, 15, 75, 38, 0 +}; +#endif // defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_ARGBGRAYROW_SSSE3) + +#if defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_I422TOARGBROW_SSSE3) + +static vec8 kARGBToU = { + 112, -74, -38, 0, 112, -74, -38, 0, 112, -74, -38, 0, 112, -74, -38, 0 +}; + +static vec8 kARGBToUJ = { + 127, -84, -43, 0, 127, -84, -43, 0, 127, -84, -43, 0, 127, -84, -43, 0 +}; + +static vec8 kARGBToV = { + -18, -94, 112, 0, -18, -94, 112, 0, -18, -94, 112, 0, -18, -94, 112, 0, +}; + +static vec8 kARGBToVJ = { + -20, -107, 127, 0, -20, -107, 127, 0, -20, -107, 127, 0, -20, -107, 127, 0 +}; + +// Constants for BGRA +static vec8 kBGRAToY = { + 0, 33, 65, 13, 0, 33, 65, 13, 0, 33, 65, 13, 0, 33, 65, 13 +}; + +static vec8 kBGRAToU = { + 0, -38, -74, 112, 0, -38, -74, 112, 0, -38, -74, 112, 0, -38, -74, 112 +}; + +static vec8 kBGRAToV = { + 0, 112, -94, -18, 0, 112, -94, -18, 0, 112, -94, -18, 0, 112, -94, -18 +}; + +// Constants for ABGR +static vec8 kABGRToY = { + 33, 65, 13, 0, 33, 65, 13, 0, 33, 65, 13, 0, 33, 65, 13, 0 +}; + +static vec8 kABGRToU = { + -38, -74, 112, 0, -38, -74, 112, 0, -38, -74, 112, 0, -38, -74, 112, 0 +}; + +static vec8 kABGRToV = { + 112, -94, -18, 0, 112, -94, -18, 0, 112, -94, -18, 0, 112, -94, -18, 0 +}; + +// Constants for RGBA. +static vec8 kRGBAToY = { + 0, 13, 65, 33, 0, 13, 65, 33, 0, 13, 65, 33, 0, 13, 65, 33 +}; + +static vec8 kRGBAToU = { + 0, 112, -74, -38, 0, 112, -74, -38, 0, 112, -74, -38, 0, 112, -74, -38 +}; + +static vec8 kRGBAToV = { + 0, -18, -94, 112, 0, -18, -94, 112, 0, -18, -94, 112, 0, -18, -94, 112 +}; + +static uvec8 kAddY16 = { + 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u +}; + +// 7 bit fixed point 0.5. +static vec16 kAddYJ64 = { + 64, 64, 64, 64, 64, 64, 64, 64 +}; + +static uvec8 kAddUV128 = { + 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u, + 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u +}; + +static uvec16 kAddUVJ128 = { + 0x8080u, 0x8080u, 0x8080u, 0x8080u, 0x8080u, 0x8080u, 0x8080u, 0x8080u +}; +#endif // defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_I422TOARGBROW_SSSE3) + +#ifdef HAS_RGB24TOARGBROW_SSSE3 + +// Shuffle table for converting RGB24 to ARGB. +static uvec8 kShuffleMaskRGB24ToARGB = { + 0u, 1u, 2u, 12u, 3u, 4u, 5u, 13u, 6u, 7u, 8u, 14u, 9u, 10u, 11u, 15u +}; + +// Shuffle table for converting RAW to ARGB. +static uvec8 kShuffleMaskRAWToARGB = { + 2u, 1u, 0u, 12u, 5u, 4u, 3u, 13u, 8u, 7u, 6u, 14u, 11u, 10u, 9u, 15u +}; + +// Shuffle table for converting RAW to RGB24. First 8. +static const uvec8 kShuffleMaskRAWToRGB24_0 = { + 2u, 1u, 0u, 5u, 4u, 3u, 8u, 7u, + 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u +}; + +// Shuffle table for converting RAW to RGB24. Middle 8. +static const uvec8 kShuffleMaskRAWToRGB24_1 = { + 2u, 7u, 6u, 5u, 10u, 9u, 8u, 13u, + 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u +}; + +// Shuffle table for converting RAW to RGB24. Last 8. +static const uvec8 kShuffleMaskRAWToRGB24_2 = { + 8u, 7u, 12u, 11u, 10u, 15u, 14u, 13u, + 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u +}; + +// Shuffle table for converting ARGB to RGB24. +static uvec8 kShuffleMaskARGBToRGB24 = { + 0u, 1u, 2u, 4u, 5u, 6u, 8u, 9u, 10u, 12u, 13u, 14u, 128u, 128u, 128u, 128u +}; + +// Shuffle table for converting ARGB to RAW. +static uvec8 kShuffleMaskARGBToRAW = { + 2u, 1u, 0u, 6u, 5u, 4u, 10u, 9u, 8u, 14u, 13u, 12u, 128u, 128u, 128u, 128u +}; + +// Shuffle table for converting ARGBToRGB24 for I422ToRGB24. First 8 + next 4 +static uvec8 kShuffleMaskARGBToRGB24_0 = { + 0u, 1u, 2u, 4u, 5u, 6u, 8u, 9u, 128u, 128u, 128u, 128u, 10u, 12u, 13u, 14u +}; + +// YUY2 shuf 16 Y to 32 Y. +static const lvec8 kShuffleYUY2Y = { + 0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14, + 0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14 +}; + +// YUY2 shuf 8 UV to 16 UV. +static const lvec8 kShuffleYUY2UV = { + 1, 3, 1, 3, 5, 7, 5, 7, 9, 11, 9, 11, 13, 15, 13, 15, + 1, 3, 1, 3, 5, 7, 5, 7, 9, 11, 9, 11, 13, 15, 13, 15 +}; + +// UYVY shuf 16 Y to 32 Y. +static const lvec8 kShuffleUYVYY = { + 1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15, + 1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15 +}; + +// UYVY shuf 8 UV to 16 UV. +static const lvec8 kShuffleUYVYUV = { + 0, 2, 0, 2, 4, 6, 4, 6, 8, 10, 8, 10, 12, 14, 12, 14, + 0, 2, 0, 2, 4, 6, 4, 6, 8, 10, 8, 10, 12, 14, 12, 14 +}; + +// NV21 shuf 8 VU to 16 UV. +static const lvec8 kShuffleNV21 = { + 1, 0, 1, 0, 3, 2, 3, 2, 5, 4, 5, 4, 7, 6, 7, 6, + 1, 0, 1, 0, 3, 2, 3, 2, 5, 4, 5, 4, 7, 6, 7, 6, +}; +#endif // HAS_RGB24TOARGBROW_SSSE3 + +#ifdef HAS_J400TOARGBROW_SSE2 +void J400ToARGBRow_SSE2(const uint8* src_y, uint8* dst_argb, int width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" + "pslld $0x18,%%xmm5 \n" + LABELALIGN + "1: \n" + "movq " MEMACCESS(0) ",%%xmm0 \n" + "lea " MEMLEA(0x8,0) ",%0 \n" + "punpcklbw %%xmm0,%%xmm0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpcklwd %%xmm0,%%xmm0 \n" + "punpckhwd %%xmm1,%%xmm1 \n" + "por %%xmm5,%%xmm0 \n" + "por %%xmm5,%%xmm1 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + : "+r"(src_y), // %0 + "+r"(dst_argb), // %1 + "+r"(width) // %2 + :: "memory", "cc", "xmm0", "xmm1", "xmm5" + ); +} +#endif // HAS_J400TOARGBROW_SSE2 + +#ifdef HAS_RGB24TOARGBROW_SSSE3 +void RGB24ToARGBRow_SSSE3(const uint8* src_rgb24, uint8* dst_argb, int width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" // generate mask 0xff000000 + "pslld $0x18,%%xmm5 \n" + "movdqa %3,%%xmm4 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm3 \n" + "lea " MEMLEA(0x30,0) ",%0 \n" + "movdqa %%xmm3,%%xmm2 \n" + "palignr $0x8,%%xmm1,%%xmm2 \n" + "pshufb %%xmm4,%%xmm2 \n" + "por %%xmm5,%%xmm2 \n" + "palignr $0xc,%%xmm0,%%xmm1 \n" + "pshufb %%xmm4,%%xmm0 \n" + "movdqu %%xmm2," MEMACCESS2(0x20,1) " \n" + "por %%xmm5,%%xmm0 \n" + "pshufb %%xmm4,%%xmm1 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "por %%xmm5,%%xmm1 \n" + "palignr $0x4,%%xmm3,%%xmm3 \n" + "pshufb %%xmm4,%%xmm3 \n" + "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" + "por %%xmm5,%%xmm3 \n" + "movdqu %%xmm3," MEMACCESS2(0x30,1) " \n" + "lea " MEMLEA(0x40,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src_rgb24), // %0 + "+r"(dst_argb), // %1 + "+r"(width) // %2 + : "m"(kShuffleMaskRGB24ToARGB) // %3 + : "memory", "cc" , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +void RAWToARGBRow_SSSE3(const uint8* src_raw, uint8* dst_argb, int width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" // generate mask 0xff000000 + "pslld $0x18,%%xmm5 \n" + "movdqa %3,%%xmm4 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm3 \n" + "lea " MEMLEA(0x30,0) ",%0 \n" + "movdqa %%xmm3,%%xmm2 \n" + "palignr $0x8,%%xmm1,%%xmm2 \n" + "pshufb %%xmm4,%%xmm2 \n" + "por %%xmm5,%%xmm2 \n" + "palignr $0xc,%%xmm0,%%xmm1 \n" + "pshufb %%xmm4,%%xmm0 \n" + "movdqu %%xmm2," MEMACCESS2(0x20,1) " \n" + "por %%xmm5,%%xmm0 \n" + "pshufb %%xmm4,%%xmm1 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "por %%xmm5,%%xmm1 \n" + "palignr $0x4,%%xmm3,%%xmm3 \n" + "pshufb %%xmm4,%%xmm3 \n" + "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" + "por %%xmm5,%%xmm3 \n" + "movdqu %%xmm3," MEMACCESS2(0x30,1) " \n" + "lea " MEMLEA(0x40,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src_raw), // %0 + "+r"(dst_argb), // %1 + "+r"(width) // %2 + : "m"(kShuffleMaskRAWToARGB) // %3 + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +void RAWToRGB24Row_SSSE3(const uint8* src_raw, uint8* dst_rgb24, int width) { + asm volatile ( + "movdqa %3,%%xmm3 \n" + "movdqa %4,%%xmm4 \n" + "movdqa %5,%%xmm5 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x4,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x8,0) ",%%xmm2 \n" + "lea " MEMLEA(0x18,0) ",%0 \n" + "pshufb %%xmm3,%%xmm0 \n" + "pshufb %%xmm4,%%xmm1 \n" + "pshufb %%xmm5,%%xmm2 \n" + "movq %%xmm0," MEMACCESS(1) " \n" + "movq %%xmm1," MEMACCESS2(0x8,1) " \n" + "movq %%xmm2," MEMACCESS2(0x10,1) " \n" + "lea " MEMLEA(0x18,1) ",%1 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + : "+r"(src_raw), // %0 + "+r"(dst_rgb24), // %1 + "+r"(width) // %2 + : "m"(kShuffleMaskRAWToRGB24_0), // %3 + "m"(kShuffleMaskRAWToRGB24_1), // %4 + "m"(kShuffleMaskRAWToRGB24_2) // %5 + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +void RGB565ToARGBRow_SSE2(const uint8* src, uint8* dst, int width) { + asm volatile ( + "mov $0x1080108,%%eax \n" + "movd %%eax,%%xmm5 \n" + "pshufd $0x0,%%xmm5,%%xmm5 \n" + "mov $0x20802080,%%eax \n" + "movd %%eax,%%xmm6 \n" + "pshufd $0x0,%%xmm6,%%xmm6 \n" + "pcmpeqb %%xmm3,%%xmm3 \n" + "psllw $0xb,%%xmm3 \n" + "pcmpeqb %%xmm4,%%xmm4 \n" + "psllw $0xa,%%xmm4 \n" + "psrlw $0x5,%%xmm4 \n" + "pcmpeqb %%xmm7,%%xmm7 \n" + "psllw $0x8,%%xmm7 \n" + "sub %0,%1 \n" + "sub %0,%1 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm0,%%xmm2 \n" + "pand %%xmm3,%%xmm1 \n" + "psllw $0xb,%%xmm2 \n" + "pmulhuw %%xmm5,%%xmm1 \n" + "pmulhuw %%xmm5,%%xmm2 \n" + "psllw $0x8,%%xmm1 \n" + "por %%xmm2,%%xmm1 \n" + "pand %%xmm4,%%xmm0 \n" + "pmulhuw %%xmm6,%%xmm0 \n" + "por %%xmm7,%%xmm0 \n" + "movdqa %%xmm1,%%xmm2 \n" + "punpcklbw %%xmm0,%%xmm1 \n" + "punpckhbw %%xmm0,%%xmm2 \n" + MEMOPMEM(movdqu,xmm1,0x00,1,0,2) // movdqu %%xmm1,(%1,%0,2) + MEMOPMEM(movdqu,xmm2,0x10,1,0,2) // movdqu %%xmm2,0x10(%1,%0,2) + "lea " MEMLEA(0x10,0) ",%0 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : + : "memory", "cc", "eax", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} + +void ARGB1555ToARGBRow_SSE2(const uint8* src, uint8* dst, int width) { + asm volatile ( + "mov $0x1080108,%%eax \n" + "movd %%eax,%%xmm5 \n" + "pshufd $0x0,%%xmm5,%%xmm5 \n" + "mov $0x42004200,%%eax \n" + "movd %%eax,%%xmm6 \n" + "pshufd $0x0,%%xmm6,%%xmm6 \n" + "pcmpeqb %%xmm3,%%xmm3 \n" + "psllw $0xb,%%xmm3 \n" + "movdqa %%xmm3,%%xmm4 \n" + "psrlw $0x6,%%xmm4 \n" + "pcmpeqb %%xmm7,%%xmm7 \n" + "psllw $0x8,%%xmm7 \n" + "sub %0,%1 \n" + "sub %0,%1 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm0,%%xmm2 \n" + "psllw $0x1,%%xmm1 \n" + "psllw $0xb,%%xmm2 \n" + "pand %%xmm3,%%xmm1 \n" + "pmulhuw %%xmm5,%%xmm2 \n" + "pmulhuw %%xmm5,%%xmm1 \n" + "psllw $0x8,%%xmm1 \n" + "por %%xmm2,%%xmm1 \n" + "movdqa %%xmm0,%%xmm2 \n" + "pand %%xmm4,%%xmm0 \n" + "psraw $0x8,%%xmm2 \n" + "pmulhuw %%xmm6,%%xmm0 \n" + "pand %%xmm7,%%xmm2 \n" + "por %%xmm2,%%xmm0 \n" + "movdqa %%xmm1,%%xmm2 \n" + "punpcklbw %%xmm0,%%xmm1 \n" + "punpckhbw %%xmm0,%%xmm2 \n" + MEMOPMEM(movdqu,xmm1,0x00,1,0,2) // movdqu %%xmm1,(%1,%0,2) + MEMOPMEM(movdqu,xmm2,0x10,1,0,2) // movdqu %%xmm2,0x10(%1,%0,2) + "lea " MEMLEA(0x10,0) ",%0 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : + : "memory", "cc", "eax", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} + +void ARGB4444ToARGBRow_SSE2(const uint8* src, uint8* dst, int width) { + asm volatile ( + "mov $0xf0f0f0f,%%eax \n" + "movd %%eax,%%xmm4 \n" + "pshufd $0x0,%%xmm4,%%xmm4 \n" + "movdqa %%xmm4,%%xmm5 \n" + "pslld $0x4,%%xmm5 \n" + "sub %0,%1 \n" + "sub %0,%1 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqa %%xmm0,%%xmm2 \n" + "pand %%xmm4,%%xmm0 \n" + "pand %%xmm5,%%xmm2 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm2,%%xmm3 \n" + "psllw $0x4,%%xmm1 \n" + "psrlw $0x4,%%xmm3 \n" + "por %%xmm1,%%xmm0 \n" + "por %%xmm3,%%xmm2 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpcklbw %%xmm2,%%xmm0 \n" + "punpckhbw %%xmm2,%%xmm1 \n" + MEMOPMEM(movdqu,xmm0,0x00,1,0,2) // movdqu %%xmm0,(%1,%0,2) + MEMOPMEM(movdqu,xmm1,0x10,1,0,2) // movdqu %%xmm1,0x10(%1,%0,2) + "lea " MEMLEA(0x10,0) ",%0 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : + : "memory", "cc", "eax", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +void ARGBToRGB24Row_SSSE3(const uint8* src, uint8* dst, int width) { + asm volatile ( + "movdqa %3,%%xmm6 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "pshufb %%xmm6,%%xmm0 \n" + "pshufb %%xmm6,%%xmm1 \n" + "pshufb %%xmm6,%%xmm2 \n" + "pshufb %%xmm6,%%xmm3 \n" + "movdqa %%xmm1,%%xmm4 \n" + "psrldq $0x4,%%xmm1 \n" + "pslldq $0xc,%%xmm4 \n" + "movdqa %%xmm2,%%xmm5 \n" + "por %%xmm4,%%xmm0 \n" + "pslldq $0x8,%%xmm5 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "por %%xmm5,%%xmm1 \n" + "psrldq $0x8,%%xmm2 \n" + "pslldq $0x4,%%xmm3 \n" + "por %%xmm3,%%xmm2 \n" + "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" + "movdqu %%xmm2," MEMACCESS2(0x20,1) " \n" + "lea " MEMLEA(0x30,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : "m"(kShuffleMaskARGBToRGB24) // %3 + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" + ); +} + +void ARGBToRAWRow_SSSE3(const uint8* src, uint8* dst, int width) { + asm volatile ( + "movdqa %3,%%xmm6 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "pshufb %%xmm6,%%xmm0 \n" + "pshufb %%xmm6,%%xmm1 \n" + "pshufb %%xmm6,%%xmm2 \n" + "pshufb %%xmm6,%%xmm3 \n" + "movdqa %%xmm1,%%xmm4 \n" + "psrldq $0x4,%%xmm1 \n" + "pslldq $0xc,%%xmm4 \n" + "movdqa %%xmm2,%%xmm5 \n" + "por %%xmm4,%%xmm0 \n" + "pslldq $0x8,%%xmm5 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "por %%xmm5,%%xmm1 \n" + "psrldq $0x8,%%xmm2 \n" + "pslldq $0x4,%%xmm3 \n" + "por %%xmm3,%%xmm2 \n" + "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" + "movdqu %%xmm2," MEMACCESS2(0x20,1) " \n" + "lea " MEMLEA(0x30,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : "m"(kShuffleMaskARGBToRAW) // %3 + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" + ); +} + +void ARGBToRGB565Row_SSE2(const uint8* src, uint8* dst, int width) { + asm volatile ( + "pcmpeqb %%xmm3,%%xmm3 \n" + "psrld $0x1b,%%xmm3 \n" + "pcmpeqb %%xmm4,%%xmm4 \n" + "psrld $0x1a,%%xmm4 \n" + "pslld $0x5,%%xmm4 \n" + "pcmpeqb %%xmm5,%%xmm5 \n" + "pslld $0xb,%%xmm5 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm0,%%xmm2 \n" + "pslld $0x8,%%xmm0 \n" + "psrld $0x3,%%xmm1 \n" + "psrld $0x5,%%xmm2 \n" + "psrad $0x10,%%xmm0 \n" + "pand %%xmm3,%%xmm1 \n" + "pand %%xmm4,%%xmm2 \n" + "pand %%xmm5,%%xmm0 \n" + "por %%xmm2,%%xmm1 \n" + "por %%xmm1,%%xmm0 \n" + "packssdw %%xmm0,%%xmm0 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "movq %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x4,%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + :: "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +void ARGBToRGB565DitherRow_SSE2(const uint8* src, uint8* dst, + const uint32 dither4, int width) { + asm volatile ( + "movd %3,%%xmm6 \n" + "punpcklbw %%xmm6,%%xmm6 \n" + "movdqa %%xmm6,%%xmm7 \n" + "punpcklwd %%xmm6,%%xmm6 \n" + "punpckhwd %%xmm7,%%xmm7 \n" + "pcmpeqb %%xmm3,%%xmm3 \n" + "psrld $0x1b,%%xmm3 \n" + "pcmpeqb %%xmm4,%%xmm4 \n" + "psrld $0x1a,%%xmm4 \n" + "pslld $0x5,%%xmm4 \n" + "pcmpeqb %%xmm5,%%xmm5 \n" + "pslld $0xb,%%xmm5 \n" + + LABELALIGN + "1: \n" + "movdqu (%0),%%xmm0 \n" + "paddusb %%xmm6,%%xmm0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm0,%%xmm2 \n" + "pslld $0x8,%%xmm0 \n" + "psrld $0x3,%%xmm1 \n" + "psrld $0x5,%%xmm2 \n" + "psrad $0x10,%%xmm0 \n" + "pand %%xmm3,%%xmm1 \n" + "pand %%xmm4,%%xmm2 \n" + "pand %%xmm5,%%xmm0 \n" + "por %%xmm2,%%xmm1 \n" + "por %%xmm1,%%xmm0 \n" + "packssdw %%xmm0,%%xmm0 \n" + "lea 0x10(%0),%0 \n" + "movq %%xmm0,(%1) \n" + "lea 0x8(%1),%1 \n" + "sub $0x4,%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : "m"(dither4) // %3 + : "memory", "cc", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} + +#ifdef HAS_ARGBTORGB565DITHERROW_AVX2 +void ARGBToRGB565DitherRow_AVX2(const uint8* src, uint8* dst, + const uint32 dither4, int width) { + asm volatile ( + "vbroadcastss %3,%%xmm6 \n" + "vpunpcklbw %%xmm6,%%xmm6,%%xmm6 \n" + "vpermq $0xd8,%%ymm6,%%ymm6 \n" + "vpunpcklwd %%ymm6,%%ymm6,%%ymm6 \n" + "vpcmpeqb %%ymm3,%%ymm3,%%ymm3 \n" + "vpsrld $0x1b,%%ymm3,%%ymm3 \n" + "vpcmpeqb %%ymm4,%%ymm4,%%ymm4 \n" + "vpsrld $0x1a,%%ymm4,%%ymm4 \n" + "vpslld $0x5,%%ymm4,%%ymm4 \n" + "vpslld $0xb,%%ymm3,%%ymm5 \n" + + LABELALIGN + "1: \n" + "vmovdqu (%0),%%ymm0 \n" + "vpaddusb %%ymm6,%%ymm0,%%ymm0 \n" + "vpsrld $0x5,%%ymm0,%%ymm2 \n" + "vpsrld $0x3,%%ymm0,%%ymm1 \n" + "vpsrld $0x8,%%ymm0,%%ymm0 \n" + "vpand %%ymm4,%%ymm2,%%ymm2 \n" + "vpand %%ymm3,%%ymm1,%%ymm1 \n" + "vpand %%ymm5,%%ymm0,%%ymm0 \n" + "vpor %%ymm2,%%ymm1,%%ymm1 \n" + "vpor %%ymm1,%%ymm0,%%ymm0 \n" + "vpackusdw %%ymm0,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "lea 0x20(%0),%0 \n" + "vmovdqu %%xmm0,(%1) \n" + "lea 0x10(%1),%1 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : "m"(dither4) // %3 + : "memory", "cc", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} +#endif // HAS_ARGBTORGB565DITHERROW_AVX2 + + +void ARGBToARGB1555Row_SSE2(const uint8* src, uint8* dst, int width) { + asm volatile ( + "pcmpeqb %%xmm4,%%xmm4 \n" + "psrld $0x1b,%%xmm4 \n" + "movdqa %%xmm4,%%xmm5 \n" + "pslld $0x5,%%xmm5 \n" + "movdqa %%xmm4,%%xmm6 \n" + "pslld $0xa,%%xmm6 \n" + "pcmpeqb %%xmm7,%%xmm7 \n" + "pslld $0xf,%%xmm7 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm0,%%xmm2 \n" + "movdqa %%xmm0,%%xmm3 \n" + "psrad $0x10,%%xmm0 \n" + "psrld $0x3,%%xmm1 \n" + "psrld $0x6,%%xmm2 \n" + "psrld $0x9,%%xmm3 \n" + "pand %%xmm7,%%xmm0 \n" + "pand %%xmm4,%%xmm1 \n" + "pand %%xmm5,%%xmm2 \n" + "pand %%xmm6,%%xmm3 \n" + "por %%xmm1,%%xmm0 \n" + "por %%xmm3,%%xmm2 \n" + "por %%xmm2,%%xmm0 \n" + "packssdw %%xmm0,%%xmm0 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "movq %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x4,%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + :: "memory", "cc", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} + +void ARGBToARGB4444Row_SSE2(const uint8* src, uint8* dst, int width) { + asm volatile ( + "pcmpeqb %%xmm4,%%xmm4 \n" + "psllw $0xc,%%xmm4 \n" + "movdqa %%xmm4,%%xmm3 \n" + "psrlw $0x8,%%xmm3 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "pand %%xmm3,%%xmm0 \n" + "pand %%xmm4,%%xmm1 \n" + "psrlq $0x4,%%xmm0 \n" + "psrlq $0x8,%%xmm1 \n" + "por %%xmm1,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "movq %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x4,%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + :: "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4" + ); +} +#endif // HAS_RGB24TOARGBROW_SSSE3 + +#ifdef HAS_ARGBTOYROW_SSSE3 +// Convert 16 ARGB pixels (64 bytes) to 16 Y values. +void ARGBToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int width) { + asm volatile ( + "movdqa %3,%%xmm4 \n" + "movdqa %4,%%xmm5 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm1 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm4,%%xmm3 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "phaddw %%xmm1,%%xmm0 \n" + "phaddw %%xmm3,%%xmm2 \n" + "psrlw $0x7,%%xmm0 \n" + "psrlw $0x7,%%xmm2 \n" + "packuswb %%xmm2,%%xmm0 \n" + "paddb %%xmm5,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(dst_y), // %1 + "+r"(width) // %2 + : "m"(kARGBToY), // %3 + "m"(kAddY16) // %4 + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_ARGBTOYROW_SSSE3 + +#ifdef HAS_ARGBTOYJROW_SSSE3 +// Convert 16 ARGB pixels (64 bytes) to 16 YJ values. +// Same as ARGBToYRow but different coefficients, no add 16, but do rounding. +void ARGBToYJRow_SSSE3(const uint8* src_argb, uint8* dst_y, int width) { + asm volatile ( + "movdqa %3,%%xmm4 \n" + "movdqa %4,%%xmm5 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm1 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm4,%%xmm3 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "phaddw %%xmm1,%%xmm0 \n" + "phaddw %%xmm3,%%xmm2 \n" + "paddw %%xmm5,%%xmm0 \n" + "paddw %%xmm5,%%xmm2 \n" + "psrlw $0x7,%%xmm0 \n" + "psrlw $0x7,%%xmm2 \n" + "packuswb %%xmm2,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(dst_y), // %1 + "+r"(width) // %2 + : "m"(kARGBToYJ), // %3 + "m"(kAddYJ64) // %4 + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_ARGBTOYJROW_SSSE3 + +#ifdef HAS_ARGBTOYROW_AVX2 +// vpermd for vphaddw + vpackuswb vpermd. +static const lvec32 kPermdARGBToY_AVX = { + 0, 4, 1, 5, 2, 6, 3, 7 +}; + +// Convert 32 ARGB pixels (128 bytes) to 32 Y values. +void ARGBToYRow_AVX2(const uint8* src_argb, uint8* dst_y, int width) { + asm volatile ( + "vbroadcastf128 %3,%%ymm4 \n" + "vbroadcastf128 %4,%%ymm5 \n" + "vmovdqu %5,%%ymm6 \n" + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + "vmovdqu " MEMACCESS2(0x40,0) ",%%ymm2 \n" + "vmovdqu " MEMACCESS2(0x60,0) ",%%ymm3 \n" + "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" + "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" + "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" + "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" + "lea " MEMLEA(0x80,0) ",%0 \n" + "vphaddw %%ymm1,%%ymm0,%%ymm0 \n" // mutates. + "vphaddw %%ymm3,%%ymm2,%%ymm2 \n" + "vpsrlw $0x7,%%ymm0,%%ymm0 \n" + "vpsrlw $0x7,%%ymm2,%%ymm2 \n" + "vpackuswb %%ymm2,%%ymm0,%%ymm0 \n" // mutates. + "vpermd %%ymm0,%%ymm6,%%ymm0 \n" // unmutate. + "vpaddb %%ymm5,%%ymm0,%%ymm0 \n" // add 16 for Y + "vmovdqu %%ymm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x20,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_argb), // %0 + "+r"(dst_y), // %1 + "+r"(width) // %2 + : "m"(kARGBToY), // %3 + "m"(kAddY16), // %4 + "m"(kPermdARGBToY_AVX) // %5 + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" + ); +} +#endif // HAS_ARGBTOYROW_AVX2 + +#ifdef HAS_ARGBTOYJROW_AVX2 +// Convert 32 ARGB pixels (128 bytes) to 32 Y values. +void ARGBToYJRow_AVX2(const uint8* src_argb, uint8* dst_y, int width) { + asm volatile ( + "vbroadcastf128 %3,%%ymm4 \n" + "vbroadcastf128 %4,%%ymm5 \n" + "vmovdqu %5,%%ymm6 \n" + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + "vmovdqu " MEMACCESS2(0x40,0) ",%%ymm2 \n" + "vmovdqu " MEMACCESS2(0x60,0) ",%%ymm3 \n" + "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" + "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" + "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" + "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" + "lea " MEMLEA(0x80,0) ",%0 \n" + "vphaddw %%ymm1,%%ymm0,%%ymm0 \n" // mutates. + "vphaddw %%ymm3,%%ymm2,%%ymm2 \n" + "vpaddw %%ymm5,%%ymm0,%%ymm0 \n" // Add .5 for rounding. + "vpaddw %%ymm5,%%ymm2,%%ymm2 \n" + "vpsrlw $0x7,%%ymm0,%%ymm0 \n" + "vpsrlw $0x7,%%ymm2,%%ymm2 \n" + "vpackuswb %%ymm2,%%ymm0,%%ymm0 \n" // mutates. + "vpermd %%ymm0,%%ymm6,%%ymm0 \n" // unmutate. + "vmovdqu %%ymm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x20,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_argb), // %0 + "+r"(dst_y), // %1 + "+r"(width) // %2 + : "m"(kARGBToYJ), // %3 + "m"(kAddYJ64), // %4 + "m"(kPermdARGBToY_AVX) // %5 + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" + ); +} +#endif // HAS_ARGBTOYJROW_AVX2 + +#ifdef HAS_ARGBTOUVROW_SSSE3 +void ARGBToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "movdqa %5,%%xmm3 \n" + "movdqa %6,%%xmm4 \n" + "movdqa %7,%%xmm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" + MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm6 \n" + + "lea " MEMLEA(0x40,0) ",%0 \n" + "movdqa %%xmm0,%%xmm7 \n" + "shufps $0x88,%%xmm1,%%xmm0 \n" + "shufps $0xdd,%%xmm1,%%xmm7 \n" + "pavgb %%xmm7,%%xmm0 \n" + "movdqa %%xmm2,%%xmm7 \n" + "shufps $0x88,%%xmm6,%%xmm2 \n" + "shufps $0xdd,%%xmm6,%%xmm7 \n" + "pavgb %%xmm7,%%xmm2 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm2,%%xmm6 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm3,%%xmm1 \n" + "pmaddubsw %%xmm3,%%xmm6 \n" + "phaddw %%xmm2,%%xmm0 \n" + "phaddw %%xmm6,%%xmm1 \n" + "psraw $0x8,%%xmm0 \n" + "psraw $0x8,%%xmm1 \n" + "packsswb %%xmm1,%%xmm0 \n" + "paddb %%xmm5,%%xmm0 \n" + "movlps %%xmm0," MEMACCESS(1) " \n" + MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1) + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_argb0), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+rm"(width) // %3 + : "r"((intptr_t)(src_stride_argb)), // %4 + "m"(kARGBToV), // %5 + "m"(kARGBToU), // %6 + "m"(kAddUV128) // %7 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm6", "xmm7" + ); +} +#endif // HAS_ARGBTOUVROW_SSSE3 + +#ifdef HAS_ARGBTOUVROW_AVX2 +// vpshufb for vphaddw + vpackuswb packed to shorts. +static const lvec8 kShufARGBToUV_AVX = { + 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15, + 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15 +}; +void ARGBToUVRow_AVX2(const uint8* src_argb0, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "vbroadcastf128 %5,%%ymm5 \n" + "vbroadcastf128 %6,%%ymm6 \n" + "vbroadcastf128 %7,%%ymm7 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + "vmovdqu " MEMACCESS2(0x40,0) ",%%ymm2 \n" + "vmovdqu " MEMACCESS2(0x60,0) ",%%ymm3 \n" + VMEMOPREG(vpavgb,0x00,0,4,1,ymm0,ymm0) // vpavgb (%0,%4,1),%%ymm0,%%ymm0 + VMEMOPREG(vpavgb,0x20,0,4,1,ymm1,ymm1) + VMEMOPREG(vpavgb,0x40,0,4,1,ymm2,ymm2) + VMEMOPREG(vpavgb,0x60,0,4,1,ymm3,ymm3) + "lea " MEMLEA(0x80,0) ",%0 \n" + "vshufps $0x88,%%ymm1,%%ymm0,%%ymm4 \n" + "vshufps $0xdd,%%ymm1,%%ymm0,%%ymm0 \n" + "vpavgb %%ymm4,%%ymm0,%%ymm0 \n" + "vshufps $0x88,%%ymm3,%%ymm2,%%ymm4 \n" + "vshufps $0xdd,%%ymm3,%%ymm2,%%ymm2 \n" + "vpavgb %%ymm4,%%ymm2,%%ymm2 \n" + + "vpmaddubsw %%ymm7,%%ymm0,%%ymm1 \n" + "vpmaddubsw %%ymm7,%%ymm2,%%ymm3 \n" + "vpmaddubsw %%ymm6,%%ymm0,%%ymm0 \n" + "vpmaddubsw %%ymm6,%%ymm2,%%ymm2 \n" + "vphaddw %%ymm3,%%ymm1,%%ymm1 \n" + "vphaddw %%ymm2,%%ymm0,%%ymm0 \n" + "vpsraw $0x8,%%ymm1,%%ymm1 \n" + "vpsraw $0x8,%%ymm0,%%ymm0 \n" + "vpacksswb %%ymm0,%%ymm1,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vpshufb %8,%%ymm0,%%ymm0 \n" + "vpaddb %%ymm5,%%ymm0,%%ymm0 \n" + + "vextractf128 $0x0,%%ymm0," MEMACCESS(1) " \n" + VEXTOPMEM(vextractf128,1,ymm0,0x0,1,2,1) // vextractf128 $1,%%ymm0,(%1,%2,1) + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x20,%3 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_argb0), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+rm"(width) // %3 + : "r"((intptr_t)(src_stride_argb)), // %4 + "m"(kAddUV128), // %5 + "m"(kARGBToV), // %6 + "m"(kARGBToU), // %7 + "m"(kShufARGBToUV_AVX) // %8 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} +#endif // HAS_ARGBTOUVROW_AVX2 + +#ifdef HAS_ARGBTOUVJROW_SSSE3 +void ARGBToUVJRow_SSSE3(const uint8* src_argb0, int src_stride_argb, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "movdqa %5,%%xmm3 \n" + "movdqa %6,%%xmm4 \n" + "movdqa %7,%%xmm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" + MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm6 \n" + + "lea " MEMLEA(0x40,0) ",%0 \n" + "movdqa %%xmm0,%%xmm7 \n" + "shufps $0x88,%%xmm1,%%xmm0 \n" + "shufps $0xdd,%%xmm1,%%xmm7 \n" + "pavgb %%xmm7,%%xmm0 \n" + "movdqa %%xmm2,%%xmm7 \n" + "shufps $0x88,%%xmm6,%%xmm2 \n" + "shufps $0xdd,%%xmm6,%%xmm7 \n" + "pavgb %%xmm7,%%xmm2 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm2,%%xmm6 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm3,%%xmm1 \n" + "pmaddubsw %%xmm3,%%xmm6 \n" + "phaddw %%xmm2,%%xmm0 \n" + "phaddw %%xmm6,%%xmm1 \n" + "paddw %%xmm5,%%xmm0 \n" + "paddw %%xmm5,%%xmm1 \n" + "psraw $0x8,%%xmm0 \n" + "psraw $0x8,%%xmm1 \n" + "packsswb %%xmm1,%%xmm0 \n" + "movlps %%xmm0," MEMACCESS(1) " \n" + MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1) + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_argb0), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+rm"(width) // %3 + : "r"((intptr_t)(src_stride_argb)), // %4 + "m"(kARGBToVJ), // %5 + "m"(kARGBToUJ), // %6 + "m"(kAddUVJ128) // %7 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm6", "xmm7" + ); +} +#endif // HAS_ARGBTOUVJROW_SSSE3 + +#ifdef HAS_ARGBTOUV444ROW_SSSE3 +void ARGBToUV444Row_SSSE3(const uint8* src_argb, uint8* dst_u, uint8* dst_v, + int width) { + asm volatile ( + "movdqa %4,%%xmm3 \n" + "movdqa %5,%%xmm4 \n" + "movdqa %6,%%xmm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm1 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm4,%%xmm6 \n" + "phaddw %%xmm1,%%xmm0 \n" + "phaddw %%xmm6,%%xmm2 \n" + "psraw $0x8,%%xmm0 \n" + "psraw $0x8,%%xmm2 \n" + "packsswb %%xmm2,%%xmm0 \n" + "paddb %%xmm5,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" + "pmaddubsw %%xmm3,%%xmm0 \n" + "pmaddubsw %%xmm3,%%xmm1 \n" + "pmaddubsw %%xmm3,%%xmm2 \n" + "pmaddubsw %%xmm3,%%xmm6 \n" + "phaddw %%xmm1,%%xmm0 \n" + "phaddw %%xmm6,%%xmm2 \n" + "psraw $0x8,%%xmm0 \n" + "psraw $0x8,%%xmm2 \n" + "packsswb %%xmm2,%%xmm0 \n" + "paddb %%xmm5,%%xmm0 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + MEMOPMEM(movdqu,xmm0,0x00,1,2,1) // movdqu %%xmm0,(%1,%2,1) + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+rm"(width) // %3 + : "m"(kARGBToV), // %4 + "m"(kARGBToU), // %5 + "m"(kAddUV128) // %6 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm6" + ); +} +#endif // HAS_ARGBTOUV444ROW_SSSE3 + +#ifdef HAS_ARGBTOUV422ROW_SSSE3 +void ARGBToUV422Row_SSSE3(const uint8* src_argb0, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "movdqa %4,%%xmm3 \n" + "movdqa %5,%%xmm4 \n" + "movdqa %6,%%xmm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "movdqa %%xmm0,%%xmm7 \n" + "shufps $0x88,%%xmm1,%%xmm0 \n" + "shufps $0xdd,%%xmm1,%%xmm7 \n" + "pavgb %%xmm7,%%xmm0 \n" + "movdqa %%xmm2,%%xmm7 \n" + "shufps $0x88,%%xmm6,%%xmm2 \n" + "shufps $0xdd,%%xmm6,%%xmm7 \n" + "pavgb %%xmm7,%%xmm2 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm2,%%xmm6 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm3,%%xmm1 \n" + "pmaddubsw %%xmm3,%%xmm6 \n" + "phaddw %%xmm2,%%xmm0 \n" + "phaddw %%xmm6,%%xmm1 \n" + "psraw $0x8,%%xmm0 \n" + "psraw $0x8,%%xmm1 \n" + "packsswb %%xmm1,%%xmm0 \n" + "paddb %%xmm5,%%xmm0 \n" + "movlps %%xmm0," MEMACCESS(1) " \n" + MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1) + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_argb0), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+rm"(width) // %3 + : "m"(kARGBToV), // %4 + "m"(kARGBToU), // %5 + "m"(kAddUV128) // %6 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm6", "xmm7" + ); +} +#endif // HAS_ARGBTOUV422ROW_SSSE3 + +void BGRAToYRow_SSSE3(const uint8* src_bgra, uint8* dst_y, int width) { + asm volatile ( + "movdqa %4,%%xmm5 \n" + "movdqa %3,%%xmm4 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm1 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm4,%%xmm3 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "phaddw %%xmm1,%%xmm0 \n" + "phaddw %%xmm3,%%xmm2 \n" + "psrlw $0x7,%%xmm0 \n" + "psrlw $0x7,%%xmm2 \n" + "packuswb %%xmm2,%%xmm0 \n" + "paddb %%xmm5,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src_bgra), // %0 + "+r"(dst_y), // %1 + "+r"(width) // %2 + : "m"(kBGRAToY), // %3 + "m"(kAddY16) // %4 + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +void BGRAToUVRow_SSSE3(const uint8* src_bgra0, int src_stride_bgra, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "movdqa %5,%%xmm3 \n" + "movdqa %6,%%xmm4 \n" + "movdqa %7,%%xmm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" + MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm6 \n" + + "lea " MEMLEA(0x40,0) ",%0 \n" + "movdqa %%xmm0,%%xmm7 \n" + "shufps $0x88,%%xmm1,%%xmm0 \n" + "shufps $0xdd,%%xmm1,%%xmm7 \n" + "pavgb %%xmm7,%%xmm0 \n" + "movdqa %%xmm2,%%xmm7 \n" + "shufps $0x88,%%xmm6,%%xmm2 \n" + "shufps $0xdd,%%xmm6,%%xmm7 \n" + "pavgb %%xmm7,%%xmm2 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm2,%%xmm6 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm3,%%xmm1 \n" + "pmaddubsw %%xmm3,%%xmm6 \n" + "phaddw %%xmm2,%%xmm0 \n" + "phaddw %%xmm6,%%xmm1 \n" + "psraw $0x8,%%xmm0 \n" + "psraw $0x8,%%xmm1 \n" + "packsswb %%xmm1,%%xmm0 \n" + "paddb %%xmm5,%%xmm0 \n" + "movlps %%xmm0," MEMACCESS(1) " \n" + MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1) + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_bgra0), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+rm"(width) // %3 + : "r"((intptr_t)(src_stride_bgra)), // %4 + "m"(kBGRAToV), // %5 + "m"(kBGRAToU), // %6 + "m"(kAddUV128) // %7 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm6", "xmm7" + ); +} + +void ABGRToYRow_SSSE3(const uint8* src_abgr, uint8* dst_y, int width) { + asm volatile ( + "movdqa %4,%%xmm5 \n" + "movdqa %3,%%xmm4 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm1 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm4,%%xmm3 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "phaddw %%xmm1,%%xmm0 \n" + "phaddw %%xmm3,%%xmm2 \n" + "psrlw $0x7,%%xmm0 \n" + "psrlw $0x7,%%xmm2 \n" + "packuswb %%xmm2,%%xmm0 \n" + "paddb %%xmm5,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src_abgr), // %0 + "+r"(dst_y), // %1 + "+r"(width) // %2 + : "m"(kABGRToY), // %3 + "m"(kAddY16) // %4 + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +void RGBAToYRow_SSSE3(const uint8* src_rgba, uint8* dst_y, int width) { + asm volatile ( + "movdqa %4,%%xmm5 \n" + "movdqa %3,%%xmm4 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm1 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm4,%%xmm3 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "phaddw %%xmm1,%%xmm0 \n" + "phaddw %%xmm3,%%xmm2 \n" + "psrlw $0x7,%%xmm0 \n" + "psrlw $0x7,%%xmm2 \n" + "packuswb %%xmm2,%%xmm0 \n" + "paddb %%xmm5,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src_rgba), // %0 + "+r"(dst_y), // %1 + "+r"(width) // %2 + : "m"(kRGBAToY), // %3 + "m"(kAddY16) // %4 + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +void ABGRToUVRow_SSSE3(const uint8* src_abgr0, int src_stride_abgr, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "movdqa %5,%%xmm3 \n" + "movdqa %6,%%xmm4 \n" + "movdqa %7,%%xmm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" + MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm6 \n" + + "lea " MEMLEA(0x40,0) ",%0 \n" + "movdqa %%xmm0,%%xmm7 \n" + "shufps $0x88,%%xmm1,%%xmm0 \n" + "shufps $0xdd,%%xmm1,%%xmm7 \n" + "pavgb %%xmm7,%%xmm0 \n" + "movdqa %%xmm2,%%xmm7 \n" + "shufps $0x88,%%xmm6,%%xmm2 \n" + "shufps $0xdd,%%xmm6,%%xmm7 \n" + "pavgb %%xmm7,%%xmm2 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm2,%%xmm6 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm3,%%xmm1 \n" + "pmaddubsw %%xmm3,%%xmm6 \n" + "phaddw %%xmm2,%%xmm0 \n" + "phaddw %%xmm6,%%xmm1 \n" + "psraw $0x8,%%xmm0 \n" + "psraw $0x8,%%xmm1 \n" + "packsswb %%xmm1,%%xmm0 \n" + "paddb %%xmm5,%%xmm0 \n" + "movlps %%xmm0," MEMACCESS(1) " \n" + MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1) + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_abgr0), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+rm"(width) // %3 + : "r"((intptr_t)(src_stride_abgr)), // %4 + "m"(kABGRToV), // %5 + "m"(kABGRToU), // %6 + "m"(kAddUV128) // %7 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm6", "xmm7" + ); +} + +void RGBAToUVRow_SSSE3(const uint8* src_rgba0, int src_stride_rgba, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "movdqa %5,%%xmm3 \n" + "movdqa %6,%%xmm4 \n" + "movdqa %7,%%xmm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n" + MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7 + "pavgb %%xmm7,%%xmm6 \n" + + "lea " MEMLEA(0x40,0) ",%0 \n" + "movdqa %%xmm0,%%xmm7 \n" + "shufps $0x88,%%xmm1,%%xmm0 \n" + "shufps $0xdd,%%xmm1,%%xmm7 \n" + "pavgb %%xmm7,%%xmm0 \n" + "movdqa %%xmm2,%%xmm7 \n" + "shufps $0x88,%%xmm6,%%xmm2 \n" + "shufps $0xdd,%%xmm6,%%xmm7 \n" + "pavgb %%xmm7,%%xmm2 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm2,%%xmm6 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm3,%%xmm1 \n" + "pmaddubsw %%xmm3,%%xmm6 \n" + "phaddw %%xmm2,%%xmm0 \n" + "phaddw %%xmm6,%%xmm1 \n" + "psraw $0x8,%%xmm0 \n" + "psraw $0x8,%%xmm1 \n" + "packsswb %%xmm1,%%xmm0 \n" + "paddb %%xmm5,%%xmm0 \n" + "movlps %%xmm0," MEMACCESS(1) " \n" + MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1) + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_rgba0), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+rm"(width) // %3 + : "r"((intptr_t)(src_stride_rgba)), // %4 + "m"(kRGBAToV), // %5 + "m"(kRGBAToU), // %6 + "m"(kAddUV128) // %7 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm6", "xmm7" + ); +} + +#if defined(HAS_I422TOARGBROW_SSSE3) || defined(HAS_I422TOARGBROW_AVX2) + +// Read 8 UV from 411 +#define READYUV444 \ + "movq " MEMACCESS([u_buf]) ",%%xmm0 \n" \ + MEMOPREG(movq, 0x00, [u_buf], [v_buf], 1, xmm1) \ + "lea " MEMLEA(0x8, [u_buf]) ",%[u_buf] \n" \ + "punpcklbw %%xmm1,%%xmm0 \n" \ + "movq " MEMACCESS([y_buf]) ",%%xmm4 \n" \ + "punpcklbw %%xmm4,%%xmm4 \n" \ + "lea " MEMLEA(0x8, [y_buf]) ",%[y_buf] \n" + +// Read 4 UV from 422, upsample to 8 UV +#define READYUV422 \ + "movd " MEMACCESS([u_buf]) ",%%xmm0 \n" \ + MEMOPREG(movd, 0x00, [u_buf], [v_buf], 1, xmm1) \ + "lea " MEMLEA(0x4, [u_buf]) ",%[u_buf] \n" \ + "punpcklbw %%xmm1,%%xmm0 \n" \ + "punpcklwd %%xmm0,%%xmm0 \n" \ + "movq " MEMACCESS([y_buf]) ",%%xmm4 \n" \ + "punpcklbw %%xmm4,%%xmm4 \n" \ + "lea " MEMLEA(0x8, [y_buf]) ",%[y_buf] \n" + +// Read 4 UV from 422, upsample to 8 UV. With 8 Alpha. +#define READYUVA422 \ + "movd " MEMACCESS([u_buf]) ",%%xmm0 \n" \ + MEMOPREG(movd, 0x00, [u_buf], [v_buf], 1, xmm1) \ + "lea " MEMLEA(0x4, [u_buf]) ",%[u_buf] \n" \ + "punpcklbw %%xmm1,%%xmm0 \n" \ + "punpcklwd %%xmm0,%%xmm0 \n" \ + "movq " MEMACCESS([y_buf]) ",%%xmm4 \n" \ + "punpcklbw %%xmm4,%%xmm4 \n" \ + "lea " MEMLEA(0x8, [y_buf]) ",%[y_buf] \n" \ + "movq " MEMACCESS([a_buf]) ",%%xmm5 \n" \ + "lea " MEMLEA(0x8, [a_buf]) ",%[a_buf] \n" + +// Read 2 UV from 411, upsample to 8 UV. +// reading 4 bytes is an msan violation. +// "movd " MEMACCESS([u_buf]) ",%%xmm0 \n" +// MEMOPREG(movd, 0x00, [u_buf], [v_buf], 1, xmm1) +// pinsrw fails with drmemory +// __asm pinsrw xmm0, [esi], 0 /* U */ +// __asm pinsrw xmm1, [esi + edi], 0 /* V */ +#define READYUV411_TEMP \ + "movzwl " MEMACCESS([u_buf]) ",%[temp] \n" \ + "movd %[temp],%%xmm0 \n" \ + MEMOPARG(movzwl,0x00,[u_buf],[v_buf],1,[temp]) " \n" \ + "movd %[temp],%%xmm1 \n" \ + "lea " MEMLEA(0x2, [u_buf]) ",%[u_buf] \n" \ + "punpcklbw %%xmm1,%%xmm0 \n" \ + "punpcklwd %%xmm0,%%xmm0 \n" \ + "punpckldq %%xmm0,%%xmm0 \n" \ + "movq " MEMACCESS([y_buf]) ",%%xmm4 \n" \ + "punpcklbw %%xmm4,%%xmm4 \n" \ + "lea " MEMLEA(0x8, [y_buf]) ",%[y_buf] \n" + +// Read 4 UV from NV12, upsample to 8 UV +#define READNV12 \ + "movq " MEMACCESS([uv_buf]) ",%%xmm0 \n" \ + "lea " MEMLEA(0x8, [uv_buf]) ",%[uv_buf] \n" \ + "punpcklwd %%xmm0,%%xmm0 \n" \ + "movq " MEMACCESS([y_buf]) ",%%xmm4 \n" \ + "punpcklbw %%xmm4,%%xmm4 \n" \ + "lea " MEMLEA(0x8, [y_buf]) ",%[y_buf] \n" + +// Read 4 VU from NV21, upsample to 8 UV +#define READNV21 \ + "movq " MEMACCESS([vu_buf]) ",%%xmm0 \n" \ + "lea " MEMLEA(0x8, [vu_buf]) ",%[vu_buf] \n" \ + "pshufb %[kShuffleNV21], %%xmm0 \n" \ + "movq " MEMACCESS([y_buf]) ",%%xmm4 \n" \ + "punpcklbw %%xmm4,%%xmm4 \n" \ + "lea " MEMLEA(0x8, [y_buf]) ",%[y_buf] \n" + +// Read 4 YUY2 with 8 Y and update 4 UV to 8 UV. +#define READYUY2 \ + "movdqu " MEMACCESS([yuy2_buf]) ",%%xmm4 \n" \ + "pshufb %[kShuffleYUY2Y], %%xmm4 \n" \ + "movdqu " MEMACCESS([yuy2_buf]) ",%%xmm0 \n" \ + "pshufb %[kShuffleYUY2UV], %%xmm0 \n" \ + "lea " MEMLEA(0x10, [yuy2_buf]) ",%[yuy2_buf] \n" + +// Read 4 UYVY with 8 Y and update 4 UV to 8 UV. +#define READUYVY \ + "movdqu " MEMACCESS([uyvy_buf]) ",%%xmm4 \n" \ + "pshufb %[kShuffleUYVYY], %%xmm4 \n" \ + "movdqu " MEMACCESS([uyvy_buf]) ",%%xmm0 \n" \ + "pshufb %[kShuffleUYVYUV], %%xmm0 \n" \ + "lea " MEMLEA(0x10, [uyvy_buf]) ",%[uyvy_buf] \n" + +#if defined(__x86_64__) +#define YUVTORGB_SETUP(yuvconstants) \ + "movdqa " MEMACCESS([yuvconstants]) ",%%xmm8 \n" \ + "movdqa " MEMACCESS2(32, [yuvconstants]) ",%%xmm9 \n" \ + "movdqa " MEMACCESS2(64, [yuvconstants]) ",%%xmm10 \n" \ + "movdqa " MEMACCESS2(96, [yuvconstants]) ",%%xmm11 \n" \ + "movdqa " MEMACCESS2(128, [yuvconstants]) ",%%xmm12 \n" \ + "movdqa " MEMACCESS2(160, [yuvconstants]) ",%%xmm13 \n" \ + "movdqa " MEMACCESS2(192, [yuvconstants]) ",%%xmm14 \n" +// Convert 8 pixels: 8 UV and 8 Y +#define YUVTORGB(yuvconstants) \ + "movdqa %%xmm0,%%xmm1 \n" \ + "movdqa %%xmm0,%%xmm2 \n" \ + "movdqa %%xmm0,%%xmm3 \n" \ + "movdqa %%xmm11,%%xmm0 \n" \ + "pmaddubsw %%xmm8,%%xmm1 \n" \ + "psubw %%xmm1,%%xmm0 \n" \ + "movdqa %%xmm12,%%xmm1 \n" \ + "pmaddubsw %%xmm9,%%xmm2 \n" \ + "psubw %%xmm2,%%xmm1 \n" \ + "movdqa %%xmm13,%%xmm2 \n" \ + "pmaddubsw %%xmm10,%%xmm3 \n" \ + "psubw %%xmm3,%%xmm2 \n" \ + "pmulhuw %%xmm14,%%xmm4 \n" \ + "paddsw %%xmm4,%%xmm0 \n" \ + "paddsw %%xmm4,%%xmm1 \n" \ + "paddsw %%xmm4,%%xmm2 \n" \ + "psraw $0x6,%%xmm0 \n" \ + "psraw $0x6,%%xmm1 \n" \ + "psraw $0x6,%%xmm2 \n" \ + "packuswb %%xmm0,%%xmm0 \n" \ + "packuswb %%xmm1,%%xmm1 \n" \ + "packuswb %%xmm2,%%xmm2 \n" +#define YUVTORGB_REGS \ + "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", + +#else +#define YUVTORGB_SETUP(yuvconstants) +// Convert 8 pixels: 8 UV and 8 Y +#define YUVTORGB(yuvconstants) \ + "movdqa %%xmm0,%%xmm1 \n" \ + "movdqa %%xmm0,%%xmm2 \n" \ + "movdqa %%xmm0,%%xmm3 \n" \ + "movdqa " MEMACCESS2(96, [yuvconstants]) ",%%xmm0 \n" \ + "pmaddubsw " MEMACCESS([yuvconstants]) ",%%xmm1 \n" \ + "psubw %%xmm1,%%xmm0 \n" \ + "movdqa " MEMACCESS2(128, [yuvconstants]) ",%%xmm1 \n" \ + "pmaddubsw " MEMACCESS2(32, [yuvconstants]) ",%%xmm2 \n" \ + "psubw %%xmm2,%%xmm1 \n" \ + "movdqa " MEMACCESS2(160, [yuvconstants]) ",%%xmm2 \n" \ + "pmaddubsw " MEMACCESS2(64, [yuvconstants]) ",%%xmm3 \n" \ + "psubw %%xmm3,%%xmm2 \n" \ + "pmulhuw " MEMACCESS2(192, [yuvconstants]) ",%%xmm4 \n" \ + "paddsw %%xmm4,%%xmm0 \n" \ + "paddsw %%xmm4,%%xmm1 \n" \ + "paddsw %%xmm4,%%xmm2 \n" \ + "psraw $0x6,%%xmm0 \n" \ + "psraw $0x6,%%xmm1 \n" \ + "psraw $0x6,%%xmm2 \n" \ + "packuswb %%xmm0,%%xmm0 \n" \ + "packuswb %%xmm1,%%xmm1 \n" \ + "packuswb %%xmm2,%%xmm2 \n" +#define YUVTORGB_REGS +#endif + +// Store 8 ARGB values. +#define STOREARGB \ + "punpcklbw %%xmm1,%%xmm0 \n" \ + "punpcklbw %%xmm5,%%xmm2 \n" \ + "movdqa %%xmm0,%%xmm1 \n" \ + "punpcklwd %%xmm2,%%xmm0 \n" \ + "punpckhwd %%xmm2,%%xmm1 \n" \ + "movdqu %%xmm0," MEMACCESS([dst_argb]) " \n" \ + "movdqu %%xmm1," MEMACCESS2(0x10, [dst_argb]) " \n" \ + "lea " MEMLEA(0x20, [dst_argb]) ", %[dst_argb] \n" + +// Store 8 RGBA values. +#define STORERGBA \ + "pcmpeqb %%xmm5,%%xmm5 \n" \ + "punpcklbw %%xmm2,%%xmm1 \n" \ + "punpcklbw %%xmm0,%%xmm5 \n" \ + "movdqa %%xmm5,%%xmm0 \n" \ + "punpcklwd %%xmm1,%%xmm5 \n" \ + "punpckhwd %%xmm1,%%xmm0 \n" \ + "movdqu %%xmm5," MEMACCESS([dst_rgba]) " \n" \ + "movdqu %%xmm0," MEMACCESS2(0x10, [dst_rgba]) " \n" \ + "lea " MEMLEA(0x20, [dst_rgba]) ",%[dst_rgba] \n" + +void OMITFP I444ToARGBRow_SSSE3(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP(yuvconstants) + "sub %[u_buf],%[v_buf] \n" + "pcmpeqb %%xmm5,%%xmm5 \n" + LABELALIGN + "1: \n" + READYUV444 + YUVTORGB(yuvconstants) + STOREARGB + "sub $0x8,%[width] \n" + "jg 1b \n" + : [y_buf]"+r"(y_buf), // %[y_buf] + [u_buf]"+r"(u_buf), // %[u_buf] + [v_buf]"+r"(v_buf), // %[v_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] + [width]"+rm"(width) // %[width] + : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] + : "memory", "cc", NACL_R14 YUVTORGB_REGS + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +void OMITFP I422ToRGB24Row_SSSE3(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* dst_rgb24, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP(yuvconstants) + "movdqa %[kShuffleMaskARGBToRGB24_0],%%xmm5 \n" + "movdqa %[kShuffleMaskARGBToRGB24],%%xmm6 \n" + "sub %[u_buf],%[v_buf] \n" + LABELALIGN + "1: \n" + READYUV422 + YUVTORGB(yuvconstants) + "punpcklbw %%xmm1,%%xmm0 \n" + "punpcklbw %%xmm2,%%xmm2 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpcklwd %%xmm2,%%xmm0 \n" + "punpckhwd %%xmm2,%%xmm1 \n" + "pshufb %%xmm5,%%xmm0 \n" + "pshufb %%xmm6,%%xmm1 \n" + "palignr $0xc,%%xmm0,%%xmm1 \n" + "movq %%xmm0," MEMACCESS([dst_rgb24]) "\n" + "movdqu %%xmm1," MEMACCESS2(0x8,[dst_rgb24]) "\n" + "lea " MEMLEA(0x18,[dst_rgb24]) ",%[dst_rgb24] \n" + "subl $0x8,%[width] \n" + "jg 1b \n" + : [y_buf]"+r"(y_buf), // %[y_buf] + [u_buf]"+r"(u_buf), // %[u_buf] + [v_buf]"+r"(v_buf), // %[v_buf] + [dst_rgb24]"+r"(dst_rgb24), // %[dst_rgb24] +#if defined(__i386__) && defined(__pic__) + [width]"+m"(width) // %[width] +#else + [width]"+rm"(width) // %[width] +#endif + : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] + [kShuffleMaskARGBToRGB24_0]"m"(kShuffleMaskARGBToRGB24_0), + [kShuffleMaskARGBToRGB24]"m"(kShuffleMaskARGBToRGB24) + : "memory", "cc", NACL_R14 YUVTORGB_REGS + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" + ); +} + +void OMITFP I422ToARGBRow_SSSE3(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP(yuvconstants) + "sub %[u_buf],%[v_buf] \n" + "pcmpeqb %%xmm5,%%xmm5 \n" + LABELALIGN + "1: \n" + READYUV422 + YUVTORGB(yuvconstants) + STOREARGB + "sub $0x8,%[width] \n" + "jg 1b \n" + : [y_buf]"+r"(y_buf), // %[y_buf] + [u_buf]"+r"(u_buf), // %[u_buf] + [v_buf]"+r"(v_buf), // %[v_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] + [width]"+rm"(width) // %[width] + : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] + : "memory", "cc", NACL_R14 YUVTORGB_REGS + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +#ifdef HAS_I422ALPHATOARGBROW_SSSE3 +void OMITFP I422AlphaToARGBRow_SSSE3(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + const uint8* a_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP(yuvconstants) + "sub %[u_buf],%[v_buf] \n" + LABELALIGN + "1: \n" + READYUVA422 + YUVTORGB(yuvconstants) + STOREARGB + "subl $0x8,%[width] \n" + "jg 1b \n" + : [y_buf]"+r"(y_buf), // %[y_buf] + [u_buf]"+r"(u_buf), // %[u_buf] + [v_buf]"+r"(v_buf), // %[v_buf] + [a_buf]"+r"(a_buf), // %[a_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] +#if defined(__i386__) && defined(__pic__) + [width]"+m"(width) // %[width] +#else + [width]"+rm"(width) // %[width] +#endif + : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] + : "memory", "cc", NACL_R14 YUVTORGB_REGS + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_I422ALPHATOARGBROW_SSSE3 + +#ifdef HAS_I411TOARGBROW_SSSE3 +void OMITFP I411ToARGBRow_SSSE3(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + int temp = 0; + asm volatile ( + YUVTORGB_SETUP(yuvconstants) + "sub %[u_buf],%[v_buf] \n" + "pcmpeqb %%xmm5,%%xmm5 \n" + LABELALIGN + "1: \n" + READYUV411_TEMP + YUVTORGB(yuvconstants) + STOREARGB + "subl $0x8,%[width] \n" + "jg 1b \n" + : [y_buf]"+r"(y_buf), // %[y_buf] + [u_buf]"+r"(u_buf), // %[u_buf] + [v_buf]"+r"(v_buf), // %[v_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] + [temp]"+r"(temp), // %[temp] +#if defined(__i386__) && defined(__pic__) + [width]"+m"(width) // %[width] +#else + [width]"+rm"(width) // %[width] +#endif + : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] + : "memory", "cc", NACL_R14 YUVTORGB_REGS + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif + +void OMITFP NV12ToARGBRow_SSSE3(const uint8* y_buf, + const uint8* uv_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP(yuvconstants) + "pcmpeqb %%xmm5,%%xmm5 \n" + LABELALIGN + "1: \n" + READNV12 + YUVTORGB(yuvconstants) + STOREARGB + "sub $0x8,%[width] \n" + "jg 1b \n" + : [y_buf]"+r"(y_buf), // %[y_buf] + [uv_buf]"+r"(uv_buf), // %[uv_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] + [width]"+rm"(width) // %[width] + : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] + : "memory", "cc", YUVTORGB_REGS // Does not use r14. + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +void OMITFP NV21ToARGBRow_SSSE3(const uint8* y_buf, + const uint8* vu_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP(yuvconstants) + "pcmpeqb %%xmm5,%%xmm5 \n" + LABELALIGN + "1: \n" + READNV21 + YUVTORGB(yuvconstants) + STOREARGB + "sub $0x8,%[width] \n" + "jg 1b \n" + : [y_buf]"+r"(y_buf), // %[y_buf] + [vu_buf]"+r"(vu_buf), // %[vu_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] + [width]"+rm"(width) // %[width] + : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] + [kShuffleNV21]"m"(kShuffleNV21) + : "memory", "cc", YUVTORGB_REGS // Does not use r14. + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +void OMITFP YUY2ToARGBRow_SSSE3(const uint8* yuy2_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP(yuvconstants) + "pcmpeqb %%xmm5,%%xmm5 \n" + LABELALIGN + "1: \n" + READYUY2 + YUVTORGB(yuvconstants) + STOREARGB + "sub $0x8,%[width] \n" + "jg 1b \n" + : [yuy2_buf]"+r"(yuy2_buf), // %[yuy2_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] + [width]"+rm"(width) // %[width] + : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] + [kShuffleYUY2Y]"m"(kShuffleYUY2Y), + [kShuffleYUY2UV]"m"(kShuffleYUY2UV) + : "memory", "cc", YUVTORGB_REGS // Does not use r14. + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +void OMITFP UYVYToARGBRow_SSSE3(const uint8* uyvy_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP(yuvconstants) + "pcmpeqb %%xmm5,%%xmm5 \n" + LABELALIGN + "1: \n" + READUYVY + YUVTORGB(yuvconstants) + STOREARGB + "sub $0x8,%[width] \n" + "jg 1b \n" + : [uyvy_buf]"+r"(uyvy_buf), // %[uyvy_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] + [width]"+rm"(width) // %[width] + : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] + [kShuffleUYVYY]"m"(kShuffleUYVYY), + [kShuffleUYVYUV]"m"(kShuffleUYVYUV) + : "memory", "cc", YUVTORGB_REGS // Does not use r14. + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +void OMITFP I422ToRGBARow_SSSE3(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* dst_rgba, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP(yuvconstants) + "sub %[u_buf],%[v_buf] \n" + "pcmpeqb %%xmm5,%%xmm5 \n" + LABELALIGN + "1: \n" + READYUV422 + YUVTORGB(yuvconstants) + STORERGBA + "sub $0x8,%[width] \n" + "jg 1b \n" + : [y_buf]"+r"(y_buf), // %[y_buf] + [u_buf]"+r"(u_buf), // %[u_buf] + [v_buf]"+r"(v_buf), // %[v_buf] + [dst_rgba]"+r"(dst_rgba), // %[dst_rgba] + [width]"+rm"(width) // %[width] + : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] + : "memory", "cc", NACL_R14 YUVTORGB_REGS + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +#endif // HAS_I422TOARGBROW_SSSE3 + +// Read 16 UV from 444 +#define READYUV444_AVX2 \ + "vmovdqu " MEMACCESS([u_buf]) ",%%xmm0 \n" \ + MEMOPREG(vmovdqu, 0x00, [u_buf], [v_buf], 1, xmm1) \ + "lea " MEMLEA(0x10, [u_buf]) ",%[u_buf] \n" \ + "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ + "vpermq $0xd8,%%ymm1,%%ymm1 \n" \ + "vpunpcklbw %%ymm1,%%ymm0,%%ymm0 \n" \ + "vmovdqu " MEMACCESS([y_buf]) ",%%xmm4 \n" \ + "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ + "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ + "lea " MEMLEA(0x10, [y_buf]) ",%[y_buf] \n" + +// Read 8 UV from 422, upsample to 16 UV. +#define READYUV422_AVX2 \ + "vmovq " MEMACCESS([u_buf]) ",%%xmm0 \n" \ + MEMOPREG(vmovq, 0x00, [u_buf], [v_buf], 1, xmm1) \ + "lea " MEMLEA(0x8, [u_buf]) ",%[u_buf] \n" \ + "vpunpcklbw %%ymm1,%%ymm0,%%ymm0 \n" \ + "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ + "vpunpcklwd %%ymm0,%%ymm0,%%ymm0 \n" \ + "vmovdqu " MEMACCESS([y_buf]) ",%%xmm4 \n" \ + "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ + "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ + "lea " MEMLEA(0x10, [y_buf]) ",%[y_buf] \n" + +// Read 8 UV from 422, upsample to 16 UV. With 16 Alpha. +#define READYUVA422_AVX2 \ + "vmovq " MEMACCESS([u_buf]) ",%%xmm0 \n" \ + MEMOPREG(vmovq, 0x00, [u_buf], [v_buf], 1, xmm1) \ + "lea " MEMLEA(0x8, [u_buf]) ",%[u_buf] \n" \ + "vpunpcklbw %%ymm1,%%ymm0,%%ymm0 \n" \ + "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ + "vpunpcklwd %%ymm0,%%ymm0,%%ymm0 \n" \ + "vmovdqu " MEMACCESS([y_buf]) ",%%xmm4 \n" \ + "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ + "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ + "lea " MEMLEA(0x10, [y_buf]) ",%[y_buf] \n" \ + "vmovdqu " MEMACCESS([a_buf]) ",%%xmm5 \n" \ + "vpermq $0xd8,%%ymm5,%%ymm5 \n" \ + "lea " MEMLEA(0x10, [a_buf]) ",%[a_buf] \n" + +// Read 8 UV from NV12, upsample to 16 UV. +#define READNV12_AVX2 \ + "vmovdqu " MEMACCESS([uv_buf]) ",%%xmm0 \n" \ + "lea " MEMLEA(0x10, [uv_buf]) ",%[uv_buf] \n" \ + "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ + "vpunpcklwd %%ymm0,%%ymm0,%%ymm0 \n" \ + "vmovdqu " MEMACCESS([y_buf]) ",%%xmm4 \n" \ + "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ + "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ + "lea " MEMLEA(0x10, [y_buf]) ",%[y_buf] \n" + +// Read 8 VU from NV21, upsample to 16 UV. +#define READNV21_AVX2 \ + "vmovdqu " MEMACCESS([vu_buf]) ",%%xmm0 \n" \ + "lea " MEMLEA(0x10, [vu_buf]) ",%[vu_buf] \n" \ + "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ + "vpshufb %[kShuffleNV21], %%ymm0, %%ymm0 \n" \ + "vmovdqu " MEMACCESS([y_buf]) ",%%xmm4 \n" \ + "vpermq $0xd8,%%ymm4,%%ymm4 \n" \ + "vpunpcklbw %%ymm4,%%ymm4,%%ymm4 \n" \ + "lea " MEMLEA(0x10, [y_buf]) ",%[y_buf] \n" + +// Read 8 YUY2 with 16 Y and upsample 8 UV to 16 UV. +#define READYUY2_AVX2 \ + "vmovdqu " MEMACCESS([yuy2_buf]) ",%%ymm4 \n" \ + "vpshufb %[kShuffleYUY2Y], %%ymm4, %%ymm4 \n" \ + "vmovdqu " MEMACCESS([yuy2_buf]) ",%%ymm0 \n" \ + "vpshufb %[kShuffleYUY2UV], %%ymm0, %%ymm0 \n" \ + "lea " MEMLEA(0x20, [yuy2_buf]) ",%[yuy2_buf] \n" + +// Read 8 UYVY with 16 Y and upsample 8 UV to 16 UV. +#define READUYVY_AVX2 \ + "vmovdqu " MEMACCESS([uyvy_buf]) ",%%ymm4 \n" \ + "vpshufb %[kShuffleUYVYY], %%ymm4, %%ymm4 \n" \ + "vmovdqu " MEMACCESS([uyvy_buf]) ",%%ymm0 \n" \ + "vpshufb %[kShuffleUYVYUV], %%ymm0, %%ymm0 \n" \ + "lea " MEMLEA(0x20, [uyvy_buf]) ",%[uyvy_buf] \n" + +#if defined(__x86_64__) +#define YUVTORGB_SETUP_AVX2(yuvconstants) \ + "vmovdqa " MEMACCESS([yuvconstants]) ",%%ymm8 \n" \ + "vmovdqa " MEMACCESS2(32, [yuvconstants]) ",%%ymm9 \n" \ + "vmovdqa " MEMACCESS2(64, [yuvconstants]) ",%%ymm10 \n" \ + "vmovdqa " MEMACCESS2(96, [yuvconstants]) ",%%ymm11 \n" \ + "vmovdqa " MEMACCESS2(128, [yuvconstants]) ",%%ymm12 \n" \ + "vmovdqa " MEMACCESS2(160, [yuvconstants]) ",%%ymm13 \n" \ + "vmovdqa " MEMACCESS2(192, [yuvconstants]) ",%%ymm14 \n" +#define YUVTORGB_AVX2(yuvconstants) \ + "vpmaddubsw %%ymm10,%%ymm0,%%ymm2 \n" \ + "vpmaddubsw %%ymm9,%%ymm0,%%ymm1 \n" \ + "vpmaddubsw %%ymm8,%%ymm0,%%ymm0 \n" \ + "vpsubw %%ymm2,%%ymm13,%%ymm2 \n" \ + "vpsubw %%ymm1,%%ymm12,%%ymm1 \n" \ + "vpsubw %%ymm0,%%ymm11,%%ymm0 \n" \ + "vpmulhuw %%ymm14,%%ymm4,%%ymm4 \n" \ + "vpaddsw %%ymm4,%%ymm0,%%ymm0 \n" \ + "vpaddsw %%ymm4,%%ymm1,%%ymm1 \n" \ + "vpaddsw %%ymm4,%%ymm2,%%ymm2 \n" \ + "vpsraw $0x6,%%ymm0,%%ymm0 \n" \ + "vpsraw $0x6,%%ymm1,%%ymm1 \n" \ + "vpsraw $0x6,%%ymm2,%%ymm2 \n" \ + "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" \ + "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" \ + "vpackuswb %%ymm2,%%ymm2,%%ymm2 \n" +#define YUVTORGB_REGS_AVX2 \ + "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", +#else// Convert 16 pixels: 16 UV and 16 Y. +#define YUVTORGB_SETUP_AVX2(yuvconstants) +#define YUVTORGB_AVX2(yuvconstants) \ + "vpmaddubsw " MEMACCESS2(64, [yuvconstants]) ",%%ymm0,%%ymm2 \n" \ + "vpmaddubsw " MEMACCESS2(32, [yuvconstants]) ",%%ymm0,%%ymm1 \n" \ + "vpmaddubsw " MEMACCESS([yuvconstants]) ",%%ymm0,%%ymm0 \n" \ + "vmovdqu " MEMACCESS2(160, [yuvconstants]) ",%%ymm3 \n" \ + "vpsubw %%ymm2,%%ymm3,%%ymm2 \n" \ + "vmovdqu " MEMACCESS2(128, [yuvconstants]) ",%%ymm3 \n" \ + "vpsubw %%ymm1,%%ymm3,%%ymm1 \n" \ + "vmovdqu " MEMACCESS2(96, [yuvconstants]) ",%%ymm3 \n" \ + "vpsubw %%ymm0,%%ymm3,%%ymm0 \n" \ + "vpmulhuw " MEMACCESS2(192, [yuvconstants]) ",%%ymm4,%%ymm4 \n" \ + "vpaddsw %%ymm4,%%ymm0,%%ymm0 \n" \ + "vpaddsw %%ymm4,%%ymm1,%%ymm1 \n" \ + "vpaddsw %%ymm4,%%ymm2,%%ymm2 \n" \ + "vpsraw $0x6,%%ymm0,%%ymm0 \n" \ + "vpsraw $0x6,%%ymm1,%%ymm1 \n" \ + "vpsraw $0x6,%%ymm2,%%ymm2 \n" \ + "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" \ + "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" \ + "vpackuswb %%ymm2,%%ymm2,%%ymm2 \n" +#define YUVTORGB_REGS_AVX2 +#endif + +// Store 16 ARGB values. +#define STOREARGB_AVX2 \ + "vpunpcklbw %%ymm1,%%ymm0,%%ymm0 \n" \ + "vpermq $0xd8,%%ymm0,%%ymm0 \n" \ + "vpunpcklbw %%ymm5,%%ymm2,%%ymm2 \n" \ + "vpermq $0xd8,%%ymm2,%%ymm2 \n" \ + "vpunpcklwd %%ymm2,%%ymm0,%%ymm1 \n" \ + "vpunpckhwd %%ymm2,%%ymm0,%%ymm0 \n" \ + "vmovdqu %%ymm1," MEMACCESS([dst_argb]) " \n" \ + "vmovdqu %%ymm0," MEMACCESS2(0x20, [dst_argb]) " \n" \ + "lea " MEMLEA(0x40, [dst_argb]) ", %[dst_argb] \n" + +#ifdef HAS_I444TOARGBROW_AVX2 +// 16 pixels +// 16 UV values with 16 Y producing 16 ARGB (64 bytes). +void OMITFP I444ToARGBRow_AVX2(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP_AVX2(yuvconstants) + "sub %[u_buf],%[v_buf] \n" + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + LABELALIGN + "1: \n" + READYUV444_AVX2 + YUVTORGB_AVX2(yuvconstants) + STOREARGB_AVX2 + "sub $0x10,%[width] \n" + "jg 1b \n" + "vzeroupper \n" + : [y_buf]"+r"(y_buf), // %[y_buf] + [u_buf]"+r"(u_buf), // %[u_buf] + [v_buf]"+r"(v_buf), // %[v_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] + [width]"+rm"(width) // %[width] + : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] + : "memory", "cc", NACL_R14 YUVTORGB_REGS_AVX2 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_I444TOARGBROW_AVX2 + +#if defined(HAS_I422TOARGBROW_AVX2) +// 16 pixels +// 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes). +void OMITFP I422ToARGBRow_AVX2(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP_AVX2(yuvconstants) + "sub %[u_buf],%[v_buf] \n" + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + LABELALIGN + "1: \n" + READYUV422_AVX2 + YUVTORGB_AVX2(yuvconstants) + STOREARGB_AVX2 + "sub $0x10,%[width] \n" + "jg 1b \n" + "vzeroupper \n" + : [y_buf]"+r"(y_buf), // %[y_buf] + [u_buf]"+r"(u_buf), // %[u_buf] + [v_buf]"+r"(v_buf), // %[v_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] + [width]"+rm"(width) // %[width] + : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] + : "memory", "cc", NACL_R14 YUVTORGB_REGS_AVX2 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_I422TOARGBROW_AVX2 + +#if defined(HAS_I422ALPHATOARGBROW_AVX2) +// 16 pixels +// 8 UV values upsampled to 16 UV, mixed with 16 Y and 16 A producing 16 ARGB. +void OMITFP I422AlphaToARGBRow_AVX2(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + const uint8* a_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP_AVX2(yuvconstants) + "sub %[u_buf],%[v_buf] \n" + LABELALIGN + "1: \n" + READYUVA422_AVX2 + YUVTORGB_AVX2(yuvconstants) + STOREARGB_AVX2 + "subl $0x10,%[width] \n" + "jg 1b \n" + "vzeroupper \n" + : [y_buf]"+r"(y_buf), // %[y_buf] + [u_buf]"+r"(u_buf), // %[u_buf] + [v_buf]"+r"(v_buf), // %[v_buf] + [a_buf]"+r"(a_buf), // %[a_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] +#if defined(__i386__) && defined(__pic__) + [width]"+m"(width) // %[width] +#else + [width]"+rm"(width) // %[width] +#endif + : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] + : "memory", "cc", NACL_R14 YUVTORGB_REGS_AVX2 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_I422ALPHATOARGBROW_AVX2 + +#if defined(HAS_I422TORGBAROW_AVX2) +// 16 pixels +// 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 RGBA (64 bytes). +void OMITFP I422ToRGBARow_AVX2(const uint8* y_buf, + const uint8* u_buf, + const uint8* v_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP_AVX2(yuvconstants) + "sub %[u_buf],%[v_buf] \n" + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + LABELALIGN + "1: \n" + READYUV422_AVX2 + YUVTORGB_AVX2(yuvconstants) + + // Step 3: Weave into RGBA + "vpunpcklbw %%ymm2,%%ymm1,%%ymm1 \n" + "vpermq $0xd8,%%ymm1,%%ymm1 \n" + "vpunpcklbw %%ymm0,%%ymm5,%%ymm2 \n" + "vpermq $0xd8,%%ymm2,%%ymm2 \n" + "vpunpcklwd %%ymm1,%%ymm2,%%ymm0 \n" + "vpunpckhwd %%ymm1,%%ymm2,%%ymm1 \n" + "vmovdqu %%ymm0," MEMACCESS([dst_argb]) "\n" + "vmovdqu %%ymm1," MEMACCESS2(0x20,[dst_argb]) "\n" + "lea " MEMLEA(0x40,[dst_argb]) ",%[dst_argb] \n" + "sub $0x10,%[width] \n" + "jg 1b \n" + "vzeroupper \n" + : [y_buf]"+r"(y_buf), // %[y_buf] + [u_buf]"+r"(u_buf), // %[u_buf] + [v_buf]"+r"(v_buf), // %[v_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] + [width]"+rm"(width) // %[width] + : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] + : "memory", "cc", NACL_R14 YUVTORGB_REGS_AVX2 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_I422TORGBAROW_AVX2 + +#if defined(HAS_NV12TOARGBROW_AVX2) +// 16 pixels. +// 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes). +void OMITFP NV12ToARGBRow_AVX2(const uint8* y_buf, + const uint8* uv_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP_AVX2(yuvconstants) + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + LABELALIGN + "1: \n" + READNV12_AVX2 + YUVTORGB_AVX2(yuvconstants) + STOREARGB_AVX2 + "sub $0x10,%[width] \n" + "jg 1b \n" + "vzeroupper \n" + : [y_buf]"+r"(y_buf), // %[y_buf] + [uv_buf]"+r"(uv_buf), // %[uv_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] + [width]"+rm"(width) // %[width] + : [yuvconstants]"r"(yuvconstants) // %[yuvconstants] + : "memory", "cc", YUVTORGB_REGS_AVX2 // Does not use r14. + "xmm0", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_NV12TOARGBROW_AVX2 + +#if defined(HAS_NV21TOARGBROW_AVX2) +// 16 pixels. +// 8 VU values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes). +void OMITFP NV21ToARGBRow_AVX2(const uint8* y_buf, + const uint8* vu_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP_AVX2(yuvconstants) + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + LABELALIGN + "1: \n" + READNV21_AVX2 + YUVTORGB_AVX2(yuvconstants) + STOREARGB_AVX2 + "sub $0x10,%[width] \n" + "jg 1b \n" + "vzeroupper \n" + : [y_buf]"+r"(y_buf), // %[y_buf] + [vu_buf]"+r"(vu_buf), // %[vu_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] + [width]"+rm"(width) // %[width] + : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] + [kShuffleNV21]"m"(kShuffleNV21) + : "memory", "cc", YUVTORGB_REGS_AVX2 // Does not use r14. + "xmm0", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_NV21TOARGBROW_AVX2 + +#if defined(HAS_YUY2TOARGBROW_AVX2) +// 16 pixels. +// 8 YUY2 values with 16 Y and 8 UV producing 16 ARGB (64 bytes). +void OMITFP YUY2ToARGBRow_AVX2(const uint8* yuy2_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP_AVX2(yuvconstants) + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + LABELALIGN + "1: \n" + READYUY2_AVX2 + YUVTORGB_AVX2(yuvconstants) + STOREARGB_AVX2 + "sub $0x10,%[width] \n" + "jg 1b \n" + "vzeroupper \n" + : [yuy2_buf]"+r"(yuy2_buf), // %[yuy2_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] + [width]"+rm"(width) // %[width] + : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] + [kShuffleYUY2Y]"m"(kShuffleYUY2Y), + [kShuffleYUY2UV]"m"(kShuffleYUY2UV) + : "memory", "cc", YUVTORGB_REGS_AVX2 // Does not use r14. + "xmm0", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_YUY2TOARGBROW_AVX2 + +#if defined(HAS_UYVYTOARGBROW_AVX2) +// 16 pixels. +// 8 UYVY values with 16 Y and 8 UV producing 16 ARGB (64 bytes). +void OMITFP UYVYToARGBRow_AVX2(const uint8* uyvy_buf, + uint8* dst_argb, + const struct YuvConstants* yuvconstants, + int width) { + asm volatile ( + YUVTORGB_SETUP_AVX2(yuvconstants) + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + LABELALIGN + "1: \n" + READUYVY_AVX2 + YUVTORGB_AVX2(yuvconstants) + STOREARGB_AVX2 + "sub $0x10,%[width] \n" + "jg 1b \n" + "vzeroupper \n" + : [uyvy_buf]"+r"(uyvy_buf), // %[uyvy_buf] + [dst_argb]"+r"(dst_argb), // %[dst_argb] + [width]"+rm"(width) // %[width] + : [yuvconstants]"r"(yuvconstants), // %[yuvconstants] + [kShuffleUYVYY]"m"(kShuffleUYVYY), + [kShuffleUYVYUV]"m"(kShuffleUYVYUV) + : "memory", "cc", YUVTORGB_REGS_AVX2 // Does not use r14. + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_UYVYTOARGBROW_AVX2 + +#ifdef HAS_I400TOARGBROW_SSE2 +void I400ToARGBRow_SSE2(const uint8* y_buf, uint8* dst_argb, int width) { + asm volatile ( + "mov $0x4a354a35,%%eax \n" // 4a35 = 18997 = 1.164 + "movd %%eax,%%xmm2 \n" + "pshufd $0x0,%%xmm2,%%xmm2 \n" + "mov $0x04880488,%%eax \n" // 0488 = 1160 = 1.164 * 16 + "movd %%eax,%%xmm3 \n" + "pshufd $0x0,%%xmm3,%%xmm3 \n" + "pcmpeqb %%xmm4,%%xmm4 \n" + "pslld $0x18,%%xmm4 \n" + LABELALIGN + "1: \n" + // Step 1: Scale Y contribution to 8 G values. G = (y - 16) * 1.164 + "movq " MEMACCESS(0) ",%%xmm0 \n" + "lea " MEMLEA(0x8,0) ",%0 \n" + "punpcklbw %%xmm0,%%xmm0 \n" + "pmulhuw %%xmm2,%%xmm0 \n" + "psubusw %%xmm3,%%xmm0 \n" + "psrlw $6, %%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + + // Step 2: Weave into ARGB + "punpcklbw %%xmm0,%%xmm0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpcklwd %%xmm0,%%xmm0 \n" + "punpckhwd %%xmm1,%%xmm1 \n" + "por %%xmm4,%%xmm0 \n" + "por %%xmm4,%%xmm1 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + + "sub $0x8,%2 \n" + "jg 1b \n" + : "+r"(y_buf), // %0 + "+r"(dst_argb), // %1 + "+rm"(width) // %2 + : + : "memory", "cc", "eax" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4" + ); +} +#endif // HAS_I400TOARGBROW_SSE2 + +#ifdef HAS_I400TOARGBROW_AVX2 +// 16 pixels of Y converted to 16 pixels of ARGB (64 bytes). +// note: vpunpcklbw mutates and vpackuswb unmutates. +void I400ToARGBRow_AVX2(const uint8* y_buf, uint8* dst_argb, int width) { + asm volatile ( + "mov $0x4a354a35,%%eax \n" // 0488 = 1160 = 1.164 * 16 + "vmovd %%eax,%%xmm2 \n" + "vbroadcastss %%xmm2,%%ymm2 \n" + "mov $0x4880488,%%eax \n" // 4a35 = 18997 = 1.164 + "vmovd %%eax,%%xmm3 \n" + "vbroadcastss %%xmm3,%%ymm3 \n" + "vpcmpeqb %%ymm4,%%ymm4,%%ymm4 \n" + "vpslld $0x18,%%ymm4,%%ymm4 \n" + + LABELALIGN + "1: \n" + // Step 1: Scale Y contribution to 16 G values. G = (y - 16) * 1.164 + "vmovdqu " MEMACCESS(0) ",%%xmm0 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vpunpcklbw %%ymm0,%%ymm0,%%ymm0 \n" + "vpmulhuw %%ymm2,%%ymm0,%%ymm0 \n" + "vpsubusw %%ymm3,%%ymm0,%%ymm0 \n" + "vpsrlw $0x6,%%ymm0,%%ymm0 \n" + "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" + "vpunpcklbw %%ymm0,%%ymm0,%%ymm1 \n" + "vpermq $0xd8,%%ymm1,%%ymm1 \n" + "vpunpcklwd %%ymm1,%%ymm1,%%ymm0 \n" + "vpunpckhwd %%ymm1,%%ymm1,%%ymm1 \n" + "vpor %%ymm4,%%ymm0,%%ymm0 \n" + "vpor %%ymm4,%%ymm1,%%ymm1 \n" + "vmovdqu %%ymm0," MEMACCESS(1) " \n" + "vmovdqu %%ymm1," MEMACCESS2(0x20,1) " \n" + "lea " MEMLEA(0x40,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(y_buf), // %0 + "+r"(dst_argb), // %1 + "+rm"(width) // %2 + : + : "memory", "cc", "eax" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4" + ); +} +#endif // HAS_I400TOARGBROW_AVX2 + +#ifdef HAS_MIRRORROW_SSSE3 +// Shuffle table for reversing the bytes. +static uvec8 kShuffleMirror = { + 15u, 14u, 13u, 12u, 11u, 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u +}; + +void MirrorRow_SSSE3(const uint8* src, uint8* dst, int width) { + intptr_t temp_width = (intptr_t)(width); + asm volatile ( + "movdqa %3,%%xmm5 \n" + LABELALIGN + "1: \n" + MEMOPREG(movdqu,-0x10,0,2,1,xmm0) // movdqu -0x10(%0,%2),%%xmm0 + "pshufb %%xmm5,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(temp_width) // %2 + : "m"(kShuffleMirror) // %3 + : "memory", "cc", NACL_R14 + "xmm0", "xmm5" + ); +} +#endif // HAS_MIRRORROW_SSSE3 + +#ifdef HAS_MIRRORROW_AVX2 +void MirrorRow_AVX2(const uint8* src, uint8* dst, int width) { + intptr_t temp_width = (intptr_t)(width); + asm volatile ( + "vbroadcastf128 %3,%%ymm5 \n" + LABELALIGN + "1: \n" + MEMOPREG(vmovdqu,-0x20,0,2,1,ymm0) // vmovdqu -0x20(%0,%2),%%ymm0 + "vpshufb %%ymm5,%%ymm0,%%ymm0 \n" + "vpermq $0x4e,%%ymm0,%%ymm0 \n" + "vmovdqu %%ymm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x20,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(temp_width) // %2 + : "m"(kShuffleMirror) // %3 + : "memory", "cc", NACL_R14 + "xmm0", "xmm5" + ); +} +#endif // HAS_MIRRORROW_AVX2 + +#ifdef HAS_MIRRORROW_UV_SSSE3 +// Shuffle table for reversing the bytes of UV channels. +static uvec8 kShuffleMirrorUV = { + 14u, 12u, 10u, 8u, 6u, 4u, 2u, 0u, 15u, 13u, 11u, 9u, 7u, 5u, 3u, 1u +}; +void MirrorUVRow_SSSE3(const uint8* src, uint8* dst_u, uint8* dst_v, + int width) { + intptr_t temp_width = (intptr_t)(width); + asm volatile ( + "movdqa %4,%%xmm1 \n" + "lea " MEMLEA4(-0x10,0,3,2) ",%0 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "lea " MEMLEA(-0x10,0) ",%0 \n" + "pshufb %%xmm1,%%xmm0 \n" + "movlpd %%xmm0," MEMACCESS(1) " \n" + MEMOPMEM(movhpd,xmm0,0x00,1,2,1) // movhpd %%xmm0,(%1,%2) + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $8,%3 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+r"(temp_width) // %3 + : "m"(kShuffleMirrorUV) // %4 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1" + ); +} +#endif // HAS_MIRRORROW_UV_SSSE3 + +#ifdef HAS_ARGBMIRRORROW_SSE2 + +void ARGBMirrorRow_SSE2(const uint8* src, uint8* dst, int width) { + intptr_t temp_width = (intptr_t)(width); + asm volatile ( + "lea " MEMLEA4(-0x10,0,2,4) ",%0 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "pshufd $0x1b,%%xmm0,%%xmm0 \n" + "lea " MEMLEA(-0x10,0) ",%0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x4,%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(temp_width) // %2 + : + : "memory", "cc" + , "xmm0" + ); +} +#endif // HAS_ARGBMIRRORROW_SSE2 + +#ifdef HAS_ARGBMIRRORROW_AVX2 +// Shuffle table for reversing the bytes. +static const ulvec32 kARGBShuffleMirror_AVX2 = { + 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u +}; +void ARGBMirrorRow_AVX2(const uint8* src, uint8* dst, int width) { + intptr_t temp_width = (intptr_t)(width); + asm volatile ( + "vmovdqu %3,%%ymm5 \n" + LABELALIGN + "1: \n" + VMEMOPREG(vpermd,-0x20,0,2,4,ymm5,ymm0) // vpermd -0x20(%0,%2,4),ymm5,ymm0 + "vmovdqu %%ymm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(temp_width) // %2 + : "m"(kARGBShuffleMirror_AVX2) // %3 + : "memory", "cc", NACL_R14 + "xmm0", "xmm5" + ); +} +#endif // HAS_ARGBMIRRORROW_AVX2 + +#ifdef HAS_SPLITUVROW_AVX2 +void SplitUVRow_AVX2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, + int width) { + asm volatile ( + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + "vpsrlw $0x8,%%ymm5,%%ymm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "vpsrlw $0x8,%%ymm0,%%ymm2 \n" + "vpsrlw $0x8,%%ymm1,%%ymm3 \n" + "vpand %%ymm5,%%ymm0,%%ymm0 \n" + "vpand %%ymm5,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + "vpackuswb %%ymm3,%%ymm2,%%ymm2 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm2,%%ymm2 \n" + "vmovdqu %%ymm0," MEMACCESS(1) " \n" + MEMOPMEM(vmovdqu,ymm2,0x00,1,2,1) // vmovdqu %%ymm2,(%1,%2) + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x20,%3 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_uv), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+r"(width) // %3 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" + ); +} +#endif // HAS_SPLITUVROW_AVX2 + +#ifdef HAS_SPLITUVROW_SSE2 +void SplitUVRow_SSE2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, + int width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" + "psrlw $0x8,%%xmm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "movdqa %%xmm0,%%xmm2 \n" + "movdqa %%xmm1,%%xmm3 \n" + "pand %%xmm5,%%xmm0 \n" + "pand %%xmm5,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "psrlw $0x8,%%xmm2 \n" + "psrlw $0x8,%%xmm3 \n" + "packuswb %%xmm3,%%xmm2 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + MEMOPMEM(movdqu,xmm2,0x00,1,2,1) // movdqu %%xmm2,(%1,%2) + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_uv), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+r"(width) // %3 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" + ); +} +#endif // HAS_SPLITUVROW_SSE2 + +#ifdef HAS_MERGEUVROW_AVX2 +void MergeUVRow_AVX2(const uint8* src_u, const uint8* src_v, uint8* dst_uv, + int width) { + asm volatile ( + "sub %0,%1 \n" + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + MEMOPREG(vmovdqu,0x00,0,1,1,ymm1) // vmovdqu (%0,%1,1),%%ymm1 + "lea " MEMLEA(0x20,0) ",%0 \n" + "vpunpcklbw %%ymm1,%%ymm0,%%ymm2 \n" + "vpunpckhbw %%ymm1,%%ymm0,%%ymm0 \n" + "vextractf128 $0x0,%%ymm2," MEMACCESS(2) " \n" + "vextractf128 $0x0,%%ymm0," MEMACCESS2(0x10,2) "\n" + "vextractf128 $0x1,%%ymm2," MEMACCESS2(0x20,2) "\n" + "vextractf128 $0x1,%%ymm0," MEMACCESS2(0x30,2) "\n" + "lea " MEMLEA(0x40,2) ",%2 \n" + "sub $0x20,%3 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_u), // %0 + "+r"(src_v), // %1 + "+r"(dst_uv), // %2 + "+r"(width) // %3 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2" + ); +} +#endif // HAS_MERGEUVROW_AVX2 + +#ifdef HAS_MERGEUVROW_SSE2 +void MergeUVRow_SSE2(const uint8* src_u, const uint8* src_v, uint8* dst_uv, + int width) { + asm volatile ( + "sub %0,%1 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(movdqu,0x00,0,1,1,xmm1) // movdqu (%0,%1,1),%%xmm1 + "lea " MEMLEA(0x10,0) ",%0 \n" + "movdqa %%xmm0,%%xmm2 \n" + "punpcklbw %%xmm1,%%xmm0 \n" + "punpckhbw %%xmm1,%%xmm2 \n" + "movdqu %%xmm0," MEMACCESS(2) " \n" + "movdqu %%xmm2," MEMACCESS2(0x10,2) " \n" + "lea " MEMLEA(0x20,2) ",%2 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_u), // %0 + "+r"(src_v), // %1 + "+r"(dst_uv), // %2 + "+r"(width) // %3 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2" + ); +} +#endif // HAS_MERGEUVROW_SSE2 + +#ifdef HAS_COPYROW_SSE2 +void CopyRow_SSE2(const uint8* src, uint8* dst, int count) { + asm volatile ( + "test $0xf,%0 \n" + "jne 2f \n" + "test $0xf,%1 \n" + "jne 2f \n" + LABELALIGN + "1: \n" + "movdqa " MEMACCESS(0) ",%%xmm0 \n" + "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "movdqa %%xmm0," MEMACCESS(1) " \n" + "movdqa %%xmm1," MEMACCESS2(0x10,1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x20,%2 \n" + "jg 1b \n" + "jmp 9f \n" + LABELALIGN + "2: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x20,%2 \n" + "jg 2b \n" + "9: \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(count) // %2 + : + : "memory", "cc" + , "xmm0", "xmm1" + ); +} +#endif // HAS_COPYROW_SSE2 + +#ifdef HAS_COPYROW_AVX +void CopyRow_AVX(const uint8* src, uint8* dst, int count) { + asm volatile ( + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "vmovdqu %%ymm0," MEMACCESS(1) " \n" + "vmovdqu %%ymm1," MEMACCESS2(0x20,1) " \n" + "lea " MEMLEA(0x40,1) ",%1 \n" + "sub $0x40,%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(count) // %2 + : + : "memory", "cc" + , "xmm0", "xmm1" + ); +} +#endif // HAS_COPYROW_AVX + +#ifdef HAS_COPYROW_ERMS +// Multiple of 1. +void CopyRow_ERMS(const uint8* src, uint8* dst, int width) { + size_t width_tmp = (size_t)(width); + asm volatile ( + "rep movsb " MEMMOVESTRING(0,1) " \n" + : "+S"(src), // %0 + "+D"(dst), // %1 + "+c"(width_tmp) // %2 + : + : "memory", "cc" + ); +} +#endif // HAS_COPYROW_ERMS + +#ifdef HAS_ARGBCOPYALPHAROW_SSE2 +// width in pixels +void ARGBCopyAlphaRow_SSE2(const uint8* src, uint8* dst, int width) { + asm volatile ( + "pcmpeqb %%xmm0,%%xmm0 \n" + "pslld $0x18,%%xmm0 \n" + "pcmpeqb %%xmm1,%%xmm1 \n" + "psrld $0x8,%%xmm1 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm2 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm3 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "movdqu " MEMACCESS(1) ",%%xmm4 \n" + "movdqu " MEMACCESS2(0x10,1) ",%%xmm5 \n" + "pand %%xmm0,%%xmm2 \n" + "pand %%xmm0,%%xmm3 \n" + "pand %%xmm1,%%xmm4 \n" + "pand %%xmm1,%%xmm5 \n" + "por %%xmm4,%%xmm2 \n" + "por %%xmm5,%%xmm3 \n" + "movdqu %%xmm2," MEMACCESS(1) " \n" + "movdqu %%xmm3," MEMACCESS2(0x10,1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : + : "memory", "cc" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_ARGBCOPYALPHAROW_SSE2 + +#ifdef HAS_ARGBCOPYALPHAROW_AVX2 +// width in pixels +void ARGBCopyAlphaRow_AVX2(const uint8* src, uint8* dst, int width) { + asm volatile ( + "vpcmpeqb %%ymm0,%%ymm0,%%ymm0 \n" + "vpsrld $0x8,%%ymm0,%%ymm0 \n" + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm1 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm2 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "vpblendvb %%ymm0," MEMACCESS(1) ",%%ymm1,%%ymm1 \n" + "vpblendvb %%ymm0," MEMACCESS2(0x20,1) ",%%ymm2,%%ymm2 \n" + "vmovdqu %%ymm1," MEMACCESS(1) " \n" + "vmovdqu %%ymm2," MEMACCESS2(0x20,1) " \n" + "lea " MEMLEA(0x40,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : + : "memory", "cc" + , "xmm0", "xmm1", "xmm2" + ); +} +#endif // HAS_ARGBCOPYALPHAROW_AVX2 + +#ifdef HAS_ARGBCOPYYTOALPHAROW_SSE2 +// width in pixels +void ARGBCopyYToAlphaRow_SSE2(const uint8* src, uint8* dst, int width) { + asm volatile ( + "pcmpeqb %%xmm0,%%xmm0 \n" + "pslld $0x18,%%xmm0 \n" + "pcmpeqb %%xmm1,%%xmm1 \n" + "psrld $0x8,%%xmm1 \n" + LABELALIGN + "1: \n" + "movq " MEMACCESS(0) ",%%xmm2 \n" + "lea " MEMLEA(0x8,0) ",%0 \n" + "punpcklbw %%xmm2,%%xmm2 \n" + "punpckhwd %%xmm2,%%xmm3 \n" + "punpcklwd %%xmm2,%%xmm2 \n" + "movdqu " MEMACCESS(1) ",%%xmm4 \n" + "movdqu " MEMACCESS2(0x10,1) ",%%xmm5 \n" + "pand %%xmm0,%%xmm2 \n" + "pand %%xmm0,%%xmm3 \n" + "pand %%xmm1,%%xmm4 \n" + "pand %%xmm1,%%xmm5 \n" + "por %%xmm4,%%xmm2 \n" + "por %%xmm5,%%xmm3 \n" + "movdqu %%xmm2," MEMACCESS(1) " \n" + "movdqu %%xmm3," MEMACCESS2(0x10,1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : + : "memory", "cc" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_ARGBCOPYYTOALPHAROW_SSE2 + +#ifdef HAS_ARGBCOPYYTOALPHAROW_AVX2 +// width in pixels +void ARGBCopyYToAlphaRow_AVX2(const uint8* src, uint8* dst, int width) { + asm volatile ( + "vpcmpeqb %%ymm0,%%ymm0,%%ymm0 \n" + "vpsrld $0x8,%%ymm0,%%ymm0 \n" + LABELALIGN + "1: \n" + "vpmovzxbd " MEMACCESS(0) ",%%ymm1 \n" + "vpmovzxbd " MEMACCESS2(0x8,0) ",%%ymm2 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "vpslld $0x18,%%ymm1,%%ymm1 \n" + "vpslld $0x18,%%ymm2,%%ymm2 \n" + "vpblendvb %%ymm0," MEMACCESS(1) ",%%ymm1,%%ymm1 \n" + "vpblendvb %%ymm0," MEMACCESS2(0x20,1) ",%%ymm2,%%ymm2 \n" + "vmovdqu %%ymm1," MEMACCESS(1) " \n" + "vmovdqu %%ymm2," MEMACCESS2(0x20,1) " \n" + "lea " MEMLEA(0x40,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src), // %0 + "+r"(dst), // %1 + "+r"(width) // %2 + : + : "memory", "cc" + , "xmm0", "xmm1", "xmm2" + ); +} +#endif // HAS_ARGBCOPYYTOALPHAROW_AVX2 + +#ifdef HAS_SETROW_X86 +void SetRow_X86(uint8* dst, uint8 v8, int width) { + size_t width_tmp = (size_t)(width >> 2); + const uint32 v32 = v8 * 0x01010101; // Duplicate byte to all bytes. + asm volatile ( + "rep stosl " MEMSTORESTRING(eax,0) " \n" + : "+D"(dst), // %0 + "+c"(width_tmp) // %1 + : "a"(v32) // %2 + : "memory", "cc"); +} + +void SetRow_ERMS(uint8* dst, uint8 v8, int width) { + size_t width_tmp = (size_t)(width); + asm volatile ( + "rep stosb " MEMSTORESTRING(al,0) " \n" + : "+D"(dst), // %0 + "+c"(width_tmp) // %1 + : "a"(v8) // %2 + : "memory", "cc"); +} + +void ARGBSetRow_X86(uint8* dst_argb, uint32 v32, int width) { + size_t width_tmp = (size_t)(width); + asm volatile ( + "rep stosl " MEMSTORESTRING(eax,0) " \n" + : "+D"(dst_argb), // %0 + "+c"(width_tmp) // %1 + : "a"(v32) // %2 + : "memory", "cc"); +} +#endif // HAS_SETROW_X86 + +#ifdef HAS_YUY2TOYROW_SSE2 +void YUY2ToYRow_SSE2(const uint8* src_yuy2, uint8* dst_y, int width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" + "psrlw $0x8,%%xmm5 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "pand %%xmm5,%%xmm0 \n" + "pand %%xmm5,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src_yuy2), // %0 + "+r"(dst_y), // %1 + "+r"(width) // %2 + : + : "memory", "cc" + , "xmm0", "xmm1", "xmm5" + ); +} + +void YUY2ToUVRow_SSE2(const uint8* src_yuy2, int stride_yuy2, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" + "psrlw $0x8,%%xmm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + MEMOPREG(movdqu,0x00,0,4,1,xmm2) // movdqu (%0,%4,1),%%xmm2 + MEMOPREG(movdqu,0x10,0,4,1,xmm3) // movdqu 0x10(%0,%4,1),%%xmm3 + "lea " MEMLEA(0x20,0) ",%0 \n" + "pavgb %%xmm2,%%xmm0 \n" + "pavgb %%xmm3,%%xmm1 \n" + "psrlw $0x8,%%xmm0 \n" + "psrlw $0x8,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "pand %%xmm5,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "psrlw $0x8,%%xmm1 \n" + "packuswb %%xmm1,%%xmm1 \n" + "movq %%xmm0," MEMACCESS(1) " \n" + MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2) + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_yuy2), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+r"(width) // %3 + : "r"((intptr_t)(stride_yuy2)) // %4 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" + ); +} + +void YUY2ToUV422Row_SSE2(const uint8* src_yuy2, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" + "psrlw $0x8,%%xmm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "psrlw $0x8,%%xmm0 \n" + "psrlw $0x8,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "pand %%xmm5,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "psrlw $0x8,%%xmm1 \n" + "packuswb %%xmm1,%%xmm1 \n" + "movq %%xmm0," MEMACCESS(1) " \n" + MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2) + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_yuy2), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+r"(width) // %3 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm5" + ); +} + +void UYVYToYRow_SSE2(const uint8* src_uyvy, uint8* dst_y, int width) { + asm volatile ( + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "psrlw $0x8,%%xmm0 \n" + "psrlw $0x8,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src_uyvy), // %0 + "+r"(dst_y), // %1 + "+r"(width) // %2 + : + : "memory", "cc" + , "xmm0", "xmm1" + ); +} + +void UYVYToUVRow_SSE2(const uint8* src_uyvy, int stride_uyvy, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" + "psrlw $0x8,%%xmm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + MEMOPREG(movdqu,0x00,0,4,1,xmm2) // movdqu (%0,%4,1),%%xmm2 + MEMOPREG(movdqu,0x10,0,4,1,xmm3) // movdqu 0x10(%0,%4,1),%%xmm3 + "lea " MEMLEA(0x20,0) ",%0 \n" + "pavgb %%xmm2,%%xmm0 \n" + "pavgb %%xmm3,%%xmm1 \n" + "pand %%xmm5,%%xmm0 \n" + "pand %%xmm5,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "pand %%xmm5,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "psrlw $0x8,%%xmm1 \n" + "packuswb %%xmm1,%%xmm1 \n" + "movq %%xmm0," MEMACCESS(1) " \n" + MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2) + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_uyvy), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+r"(width) // %3 + : "r"((intptr_t)(stride_uyvy)) // %4 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" + ); +} + +void UYVYToUV422Row_SSE2(const uint8* src_uyvy, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" + "psrlw $0x8,%%xmm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "pand %%xmm5,%%xmm0 \n" + "pand %%xmm5,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "pand %%xmm5,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "psrlw $0x8,%%xmm1 \n" + "packuswb %%xmm1,%%xmm1 \n" + "movq %%xmm0," MEMACCESS(1) " \n" + MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2) + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_uyvy), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+r"(width) // %3 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm5" + ); +} +#endif // HAS_YUY2TOYROW_SSE2 + +#ifdef HAS_YUY2TOYROW_AVX2 +void YUY2ToYRow_AVX2(const uint8* src_yuy2, uint8* dst_y, int width) { + asm volatile ( + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + "vpsrlw $0x8,%%ymm5,%%ymm5 \n" + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "vpand %%ymm5,%%ymm0,%%ymm0 \n" + "vpand %%ymm5,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vmovdqu %%ymm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x20,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_yuy2), // %0 + "+r"(dst_y), // %1 + "+r"(width) // %2 + : + : "memory", "cc" + , "xmm0", "xmm1", "xmm5" + ); +} + +void YUY2ToUVRow_AVX2(const uint8* src_yuy2, int stride_yuy2, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + "vpsrlw $0x8,%%ymm5,%%ymm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + VMEMOPREG(vpavgb,0x00,0,4,1,ymm0,ymm0) // vpavgb (%0,%4,1),%%ymm0,%%ymm0 + VMEMOPREG(vpavgb,0x20,0,4,1,ymm1,ymm1) + "lea " MEMLEA(0x40,0) ",%0 \n" + "vpsrlw $0x8,%%ymm0,%%ymm0 \n" + "vpsrlw $0x8,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vpand %%ymm5,%%ymm0,%%ymm1 \n" + "vpsrlw $0x8,%%ymm0,%%ymm0 \n" + "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm1,%%ymm1 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vextractf128 $0x0,%%ymm1," MEMACCESS(1) " \n" + VEXTOPMEM(vextractf128,0,ymm0,0x00,1,2,1) // vextractf128 $0x0,%%ymm0,(%1,%2,1) + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x20,%3 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_yuy2), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+r"(width) // %3 + : "r"((intptr_t)(stride_yuy2)) // %4 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm5" + ); +} + +void YUY2ToUV422Row_AVX2(const uint8* src_yuy2, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + "vpsrlw $0x8,%%ymm5,%%ymm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "vpsrlw $0x8,%%ymm0,%%ymm0 \n" + "vpsrlw $0x8,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vpand %%ymm5,%%ymm0,%%ymm1 \n" + "vpsrlw $0x8,%%ymm0,%%ymm0 \n" + "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm1,%%ymm1 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vextractf128 $0x0,%%ymm1," MEMACCESS(1) " \n" + VEXTOPMEM(vextractf128,0,ymm0,0x00,1,2,1) // vextractf128 $0x0,%%ymm0,(%1,%2,1) + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x20,%3 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_yuy2), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+r"(width) // %3 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm5" + ); +} + +void UYVYToYRow_AVX2(const uint8* src_uyvy, uint8* dst_y, int width) { + asm volatile ( + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "vpsrlw $0x8,%%ymm0,%%ymm0 \n" + "vpsrlw $0x8,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vmovdqu %%ymm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x20,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_uyvy), // %0 + "+r"(dst_y), // %1 + "+r"(width) // %2 + : + : "memory", "cc" + , "xmm0", "xmm1", "xmm5" + ); +} +void UYVYToUVRow_AVX2(const uint8* src_uyvy, int stride_uyvy, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + "vpsrlw $0x8,%%ymm5,%%ymm5 \n" + "sub %1,%2 \n" + + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + VMEMOPREG(vpavgb,0x00,0,4,1,ymm0,ymm0) // vpavgb (%0,%4,1),%%ymm0,%%ymm0 + VMEMOPREG(vpavgb,0x20,0,4,1,ymm1,ymm1) + "lea " MEMLEA(0x40,0) ",%0 \n" + "vpand %%ymm5,%%ymm0,%%ymm0 \n" + "vpand %%ymm5,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vpand %%ymm5,%%ymm0,%%ymm1 \n" + "vpsrlw $0x8,%%ymm0,%%ymm0 \n" + "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm1,%%ymm1 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vextractf128 $0x0,%%ymm1," MEMACCESS(1) " \n" + VEXTOPMEM(vextractf128,0,ymm0,0x00,1,2,1) // vextractf128 $0x0,%%ymm0,(%1,%2,1) + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x20,%3 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_uyvy), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+r"(width) // %3 + : "r"((intptr_t)(stride_uyvy)) // %4 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm5" + ); +} + +void UYVYToUV422Row_AVX2(const uint8* src_uyvy, + uint8* dst_u, uint8* dst_v, int width) { + asm volatile ( + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + "vpsrlw $0x8,%%ymm5,%%ymm5 \n" + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "vpand %%ymm5,%%ymm0,%%ymm0 \n" + "vpand %%ymm5,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vpand %%ymm5,%%ymm0,%%ymm1 \n" + "vpsrlw $0x8,%%ymm0,%%ymm0 \n" + "vpackuswb %%ymm1,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm1,%%ymm1 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vextractf128 $0x0,%%ymm1," MEMACCESS(1) " \n" + VEXTOPMEM(vextractf128,0,ymm0,0x00,1,2,1) // vextractf128 $0x0,%%ymm0,(%1,%2,1) + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x20,%3 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_uyvy), // %0 + "+r"(dst_u), // %1 + "+r"(dst_v), // %2 + "+r"(width) // %3 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm5" + ); +} +#endif // HAS_YUY2TOYROW_AVX2 + +#ifdef HAS_ARGBBLENDROW_SSSE3 +// Shuffle table for isolating alpha. +static uvec8 kShuffleAlpha = { + 3u, 0x80, 3u, 0x80, 7u, 0x80, 7u, 0x80, + 11u, 0x80, 11u, 0x80, 15u, 0x80, 15u, 0x80 +}; + +// Blend 8 pixels at a time +void ARGBBlendRow_SSSE3(const uint8* src_argb0, const uint8* src_argb1, + uint8* dst_argb, int width) { + asm volatile ( + "pcmpeqb %%xmm7,%%xmm7 \n" + "psrlw $0xf,%%xmm7 \n" + "pcmpeqb %%xmm6,%%xmm6 \n" + "psrlw $0x8,%%xmm6 \n" + "pcmpeqb %%xmm5,%%xmm5 \n" + "psllw $0x8,%%xmm5 \n" + "pcmpeqb %%xmm4,%%xmm4 \n" + "pslld $0x18,%%xmm4 \n" + "sub $0x4,%3 \n" + "jl 49f \n" + + // 4 pixel loop. + LABELALIGN + "40: \n" + "movdqu " MEMACCESS(0) ",%%xmm3 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "movdqa %%xmm3,%%xmm0 \n" + "pxor %%xmm4,%%xmm3 \n" + "movdqu " MEMACCESS(1) ",%%xmm2 \n" + "pshufb %4,%%xmm3 \n" + "pand %%xmm6,%%xmm2 \n" + "paddw %%xmm7,%%xmm3 \n" + "pmullw %%xmm3,%%xmm2 \n" + "movdqu " MEMACCESS(1) ",%%xmm1 \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "psrlw $0x8,%%xmm1 \n" + "por %%xmm4,%%xmm0 \n" + "pmullw %%xmm3,%%xmm1 \n" + "psrlw $0x8,%%xmm2 \n" + "paddusb %%xmm2,%%xmm0 \n" + "pand %%xmm5,%%xmm1 \n" + "paddusb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x10,2) ",%2 \n" + "sub $0x4,%3 \n" + "jge 40b \n" + + "49: \n" + "add $0x3,%3 \n" + "jl 99f \n" + + // 1 pixel loop. + "91: \n" + "movd " MEMACCESS(0) ",%%xmm3 \n" + "lea " MEMLEA(0x4,0) ",%0 \n" + "movdqa %%xmm3,%%xmm0 \n" + "pxor %%xmm4,%%xmm3 \n" + "movd " MEMACCESS(1) ",%%xmm2 \n" + "pshufb %4,%%xmm3 \n" + "pand %%xmm6,%%xmm2 \n" + "paddw %%xmm7,%%xmm3 \n" + "pmullw %%xmm3,%%xmm2 \n" + "movd " MEMACCESS(1) ",%%xmm1 \n" + "lea " MEMLEA(0x4,1) ",%1 \n" + "psrlw $0x8,%%xmm1 \n" + "por %%xmm4,%%xmm0 \n" + "pmullw %%xmm3,%%xmm1 \n" + "psrlw $0x8,%%xmm2 \n" + "paddusb %%xmm2,%%xmm0 \n" + "pand %%xmm5,%%xmm1 \n" + "paddusb %%xmm1,%%xmm0 \n" + "movd %%xmm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x4,2) ",%2 \n" + "sub $0x1,%3 \n" + "jge 91b \n" + "99: \n" + : "+r"(src_argb0), // %0 + "+r"(src_argb1), // %1 + "+r"(dst_argb), // %2 + "+r"(width) // %3 + : "m"(kShuffleAlpha) // %4 + : "memory", "cc" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} +#endif // HAS_ARGBBLENDROW_SSSE3 + +#ifdef HAS_BLENDPLANEROW_SSSE3 +// Blend 8 pixels at a time. +// unsigned version of math +// =((A2*C2)+(B2*(255-C2))+255)/256 +// signed version of math +// =(((A2-128)*C2)+((B2-128)*(255-C2))+32768+127)/256 +void BlendPlaneRow_SSSE3(const uint8* src0, const uint8* src1, + const uint8* alpha, uint8* dst, int width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" + "psllw $0x8,%%xmm5 \n" + "mov $0x80808080,%%eax \n" + "movd %%eax,%%xmm6 \n" + "pshufd $0x0,%%xmm6,%%xmm6 \n" + "mov $0x807f807f,%%eax \n" + "movd %%eax,%%xmm7 \n" + "pshufd $0x0,%%xmm7,%%xmm7 \n" + "sub %2,%0 \n" + "sub %2,%1 \n" + "sub %2,%3 \n" + + // 8 pixel loop. + LABELALIGN + "1: \n" + "movq (%2),%%xmm0 \n" + "punpcklbw %%xmm0,%%xmm0 \n" + "pxor %%xmm5,%%xmm0 \n" + "movq (%0,%2,1),%%xmm1 \n" + "movq (%1,%2,1),%%xmm2 \n" + "punpcklbw %%xmm2,%%xmm1 \n" + "psubb %%xmm6,%%xmm1 \n" + "pmaddubsw %%xmm1,%%xmm0 \n" + "paddw %%xmm7,%%xmm0 \n" + "psrlw $0x8,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movq %%xmm0,(%3,%2,1) \n" + "lea 0x8(%2),%2 \n" + "sub $0x8,%4 \n" + "jg 1b \n" + : "+r"(src0), // %0 + "+r"(src1), // %1 + "+r"(alpha), // %2 + "+r"(dst), // %3 + "+r"(width) // %4 + :: "memory", "cc", "eax", "xmm0", "xmm1", "xmm2", "xmm5", "xmm6", "xmm7" + ); +} +#endif // HAS_BLENDPLANEROW_SSSE3 + +#ifdef HAS_BLENDPLANEROW_AVX2 +// Blend 32 pixels at a time. +// unsigned version of math +// =((A2*C2)+(B2*(255-C2))+255)/256 +// signed version of math +// =(((A2-128)*C2)+((B2-128)*(255-C2))+32768+127)/256 +void BlendPlaneRow_AVX2(const uint8* src0, const uint8* src1, + const uint8* alpha, uint8* dst, int width) { + asm volatile ( + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + "vpsllw $0x8,%%ymm5,%%ymm5 \n" + "mov $0x80808080,%%eax \n" + "vmovd %%eax,%%xmm6 \n" + "vbroadcastss %%xmm6,%%ymm6 \n" + "mov $0x807f807f,%%eax \n" + "vmovd %%eax,%%xmm7 \n" + "vbroadcastss %%xmm7,%%ymm7 \n" + "sub %2,%0 \n" + "sub %2,%1 \n" + "sub %2,%3 \n" + + // 32 pixel loop. + LABELALIGN + "1: \n" + "vmovdqu (%2),%%ymm0 \n" + "vpunpckhbw %%ymm0,%%ymm0,%%ymm3 \n" + "vpunpcklbw %%ymm0,%%ymm0,%%ymm0 \n" + "vpxor %%ymm5,%%ymm3,%%ymm3 \n" + "vpxor %%ymm5,%%ymm0,%%ymm0 \n" + "vmovdqu (%0,%2,1),%%ymm1 \n" + "vmovdqu (%1,%2,1),%%ymm2 \n" + "vpunpckhbw %%ymm2,%%ymm1,%%ymm4 \n" + "vpunpcklbw %%ymm2,%%ymm1,%%ymm1 \n" + "vpsubb %%ymm6,%%ymm4,%%ymm4 \n" + "vpsubb %%ymm6,%%ymm1,%%ymm1 \n" + "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" + "vpmaddubsw %%ymm1,%%ymm0,%%ymm0 \n" + "vpaddw %%ymm7,%%ymm3,%%ymm3 \n" + "vpaddw %%ymm7,%%ymm0,%%ymm0 \n" + "vpsrlw $0x8,%%ymm3,%%ymm3 \n" + "vpsrlw $0x8,%%ymm0,%%ymm0 \n" + "vpackuswb %%ymm3,%%ymm0,%%ymm0 \n" + "vmovdqu %%ymm0,(%3,%2,1) \n" + "lea 0x20(%2),%2 \n" + "sub $0x20,%4 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src0), // %0 + "+r"(src1), // %1 + "+r"(alpha), // %2 + "+r"(dst), // %3 + "+r"(width) // %4 + :: "memory", "cc", "eax", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} +#endif // HAS_BLENDPLANEROW_AVX2 + +#ifdef HAS_ARGBATTENUATEROW_SSSE3 +// Shuffle table duplicating alpha +static uvec8 kShuffleAlpha0 = { + 3u, 3u, 3u, 3u, 3u, 3u, 128u, 128u, 7u, 7u, 7u, 7u, 7u, 7u, 128u, 128u +}; +static uvec8 kShuffleAlpha1 = { + 11u, 11u, 11u, 11u, 11u, 11u, 128u, 128u, + 15u, 15u, 15u, 15u, 15u, 15u, 128u, 128u +}; +// Attenuate 4 pixels at a time. +void ARGBAttenuateRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width) { + asm volatile ( + "pcmpeqb %%xmm3,%%xmm3 \n" + "pslld $0x18,%%xmm3 \n" + "movdqa %3,%%xmm4 \n" + "movdqa %4,%%xmm5 \n" + + // 4 pixel loop. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "pshufb %%xmm4,%%xmm0 \n" + "movdqu " MEMACCESS(0) ",%%xmm1 \n" + "punpcklbw %%xmm1,%%xmm1 \n" + "pmulhuw %%xmm1,%%xmm0 \n" + "movdqu " MEMACCESS(0) ",%%xmm1 \n" + "pshufb %%xmm5,%%xmm1 \n" + "movdqu " MEMACCESS(0) ",%%xmm2 \n" + "punpckhbw %%xmm2,%%xmm2 \n" + "pmulhuw %%xmm2,%%xmm1 \n" + "movdqu " MEMACCESS(0) ",%%xmm2 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "pand %%xmm3,%%xmm2 \n" + "psrlw $0x8,%%xmm0 \n" + "psrlw $0x8,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "por %%xmm2,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x4,%2 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+r"(width) // %2 + : "m"(kShuffleAlpha0), // %3 + "m"(kShuffleAlpha1) // %4 + : "memory", "cc" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_ARGBATTENUATEROW_SSSE3 + +#ifdef HAS_ARGBATTENUATEROW_AVX2 +// Shuffle table duplicating alpha. +static const uvec8 kShuffleAlpha_AVX2 = { + 6u, 7u, 6u, 7u, 6u, 7u, 128u, 128u, 14u, 15u, 14u, 15u, 14u, 15u, 128u, 128u +}; +// Attenuate 8 pixels at a time. +void ARGBAttenuateRow_AVX2(const uint8* src_argb, uint8* dst_argb, int width) { + asm volatile ( + "vbroadcastf128 %3,%%ymm4 \n" + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + "vpslld $0x18,%%ymm5,%%ymm5 \n" + "sub %0,%1 \n" + + // 8 pixel loop. + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm6 \n" + "vpunpcklbw %%ymm6,%%ymm6,%%ymm0 \n" + "vpunpckhbw %%ymm6,%%ymm6,%%ymm1 \n" + "vpshufb %%ymm4,%%ymm0,%%ymm2 \n" + "vpshufb %%ymm4,%%ymm1,%%ymm3 \n" + "vpmulhuw %%ymm2,%%ymm0,%%ymm0 \n" + "vpmulhuw %%ymm3,%%ymm1,%%ymm1 \n" + "vpand %%ymm5,%%ymm6,%%ymm6 \n" + "vpsrlw $0x8,%%ymm0,%%ymm0 \n" + "vpsrlw $0x8,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + "vpor %%ymm6,%%ymm0,%%ymm0 \n" + MEMOPMEM(vmovdqu,ymm0,0x00,0,1,1) // vmovdqu %%ymm0,(%0,%1) + "lea " MEMLEA(0x20,0) ",%0 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+r"(width) // %2 + : "m"(kShuffleAlpha_AVX2) // %3 + : "memory", "cc" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" + ); +} +#endif // HAS_ARGBATTENUATEROW_AVX2 + +#ifdef HAS_ARGBUNATTENUATEROW_SSE2 +// Unattenuate 4 pixels at a time. +void ARGBUnattenuateRow_SSE2(const uint8* src_argb, uint8* dst_argb, + int width) { + uintptr_t alpha = 0; + asm volatile ( + // 4 pixel loop. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movzb " MEMACCESS2(0x03,0) ",%3 \n" + "punpcklbw %%xmm0,%%xmm0 \n" + MEMOPREG(movd,0x00,4,3,4,xmm2) // movd 0x0(%4,%3,4),%%xmm2 + "movzb " MEMACCESS2(0x07,0) ",%3 \n" + MEMOPREG(movd,0x00,4,3,4,xmm3) // movd 0x0(%4,%3,4),%%xmm3 + "pshuflw $0x40,%%xmm2,%%xmm2 \n" + "pshuflw $0x40,%%xmm3,%%xmm3 \n" + "movlhps %%xmm3,%%xmm2 \n" + "pmulhuw %%xmm2,%%xmm0 \n" + "movdqu " MEMACCESS(0) ",%%xmm1 \n" + "movzb " MEMACCESS2(0x0b,0) ",%3 \n" + "punpckhbw %%xmm1,%%xmm1 \n" + MEMOPREG(movd,0x00,4,3,4,xmm2) // movd 0x0(%4,%3,4),%%xmm2 + "movzb " MEMACCESS2(0x0f,0) ",%3 \n" + MEMOPREG(movd,0x00,4,3,4,xmm3) // movd 0x0(%4,%3,4),%%xmm3 + "pshuflw $0x40,%%xmm2,%%xmm2 \n" + "pshuflw $0x40,%%xmm3,%%xmm3 \n" + "movlhps %%xmm3,%%xmm2 \n" + "pmulhuw %%xmm2,%%xmm1 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x4,%2 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+r"(width), // %2 + "+r"(alpha) // %3 + : "r"(fixed_invtbl8) // %4 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_ARGBUNATTENUATEROW_SSE2 + +#ifdef HAS_ARGBUNATTENUATEROW_AVX2 +// Shuffle table duplicating alpha. +static const uvec8 kUnattenShuffleAlpha_AVX2 = { + 0u, 1u, 0u, 1u, 0u, 1u, 6u, 7u, 8u, 9u, 8u, 9u, 8u, 9u, 14u, 15u +}; +// Unattenuate 8 pixels at a time. +void ARGBUnattenuateRow_AVX2(const uint8* src_argb, uint8* dst_argb, + int width) { + uintptr_t alpha = 0; + asm volatile ( + "sub %0,%1 \n" + "vbroadcastf128 %5,%%ymm5 \n" + + // 8 pixel loop. + LABELALIGN + "1: \n" + // replace VPGATHER + "movzb " MEMACCESS2(0x03,0) ",%3 \n" + MEMOPREG(vmovd,0x00,4,3,4,xmm0) // vmovd 0x0(%4,%3,4),%%xmm0 + "movzb " MEMACCESS2(0x07,0) ",%3 \n" + MEMOPREG(vmovd,0x00,4,3,4,xmm1) // vmovd 0x0(%4,%3,4),%%xmm1 + "movzb " MEMACCESS2(0x0b,0) ",%3 \n" + "vpunpckldq %%xmm1,%%xmm0,%%xmm6 \n" + MEMOPREG(vmovd,0x00,4,3,4,xmm2) // vmovd 0x0(%4,%3,4),%%xmm2 + "movzb " MEMACCESS2(0x0f,0) ",%3 \n" + MEMOPREG(vmovd,0x00,4,3,4,xmm3) // vmovd 0x0(%4,%3,4),%%xmm3 + "movzb " MEMACCESS2(0x13,0) ",%3 \n" + "vpunpckldq %%xmm3,%%xmm2,%%xmm7 \n" + MEMOPREG(vmovd,0x00,4,3,4,xmm0) // vmovd 0x0(%4,%3,4),%%xmm0 + "movzb " MEMACCESS2(0x17,0) ",%3 \n" + MEMOPREG(vmovd,0x00,4,3,4,xmm1) // vmovd 0x0(%4,%3,4),%%xmm1 + "movzb " MEMACCESS2(0x1b,0) ",%3 \n" + "vpunpckldq %%xmm1,%%xmm0,%%xmm0 \n" + MEMOPREG(vmovd,0x00,4,3,4,xmm2) // vmovd 0x0(%4,%3,4),%%xmm2 + "movzb " MEMACCESS2(0x1f,0) ",%3 \n" + MEMOPREG(vmovd,0x00,4,3,4,xmm3) // vmovd 0x0(%4,%3,4),%%xmm3 + "vpunpckldq %%xmm3,%%xmm2,%%xmm2 \n" + "vpunpcklqdq %%xmm7,%%xmm6,%%xmm3 \n" + "vpunpcklqdq %%xmm2,%%xmm0,%%xmm0 \n" + "vinserti128 $0x1,%%xmm0,%%ymm3,%%ymm3 \n" + // end of VPGATHER + + "vmovdqu " MEMACCESS(0) ",%%ymm6 \n" + "vpunpcklbw %%ymm6,%%ymm6,%%ymm0 \n" + "vpunpckhbw %%ymm6,%%ymm6,%%ymm1 \n" + "vpunpcklwd %%ymm3,%%ymm3,%%ymm2 \n" + "vpunpckhwd %%ymm3,%%ymm3,%%ymm3 \n" + "vpshufb %%ymm5,%%ymm2,%%ymm2 \n" + "vpshufb %%ymm5,%%ymm3,%%ymm3 \n" + "vpmulhuw %%ymm2,%%ymm0,%%ymm0 \n" + "vpmulhuw %%ymm3,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + MEMOPMEM(vmovdqu,ymm0,0x00,0,1,1) // vmovdqu %%ymm0,(%0,%1) + "lea " MEMLEA(0x20,0) ",%0 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+r"(width), // %2 + "+r"(alpha) // %3 + : "r"(fixed_invtbl8), // %4 + "m"(kUnattenShuffleAlpha_AVX2) // %5 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} +#endif // HAS_ARGBUNATTENUATEROW_AVX2 + +#ifdef HAS_ARGBGRAYROW_SSSE3 +// Convert 8 ARGB pixels (64 bytes) to 8 Gray ARGB pixels +void ARGBGrayRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width) { + asm volatile ( + "movdqa %3,%%xmm4 \n" + "movdqa %4,%%xmm5 \n" + + // 8 pixel loop. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm1 \n" + "phaddw %%xmm1,%%xmm0 \n" + "paddw %%xmm5,%%xmm0 \n" + "psrlw $0x7,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movdqu " MEMACCESS(0) ",%%xmm2 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm3 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "psrld $0x18,%%xmm2 \n" + "psrld $0x18,%%xmm3 \n" + "packuswb %%xmm3,%%xmm2 \n" + "packuswb %%xmm2,%%xmm2 \n" + "movdqa %%xmm0,%%xmm3 \n" + "punpcklbw %%xmm0,%%xmm0 \n" + "punpcklbw %%xmm2,%%xmm3 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpcklwd %%xmm3,%%xmm0 \n" + "punpckhwd %%xmm3,%%xmm1 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+r"(width) // %2 + : "m"(kARGBToYJ), // %3 + "m"(kAddYJ64) // %4 + : "memory", "cc" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_ARGBGRAYROW_SSSE3 + +#ifdef HAS_ARGBSEPIAROW_SSSE3 +// b = (r * 35 + g * 68 + b * 17) >> 7 +// g = (r * 45 + g * 88 + b * 22) >> 7 +// r = (r * 50 + g * 98 + b * 24) >> 7 +// Constant for ARGB color to sepia tone +static vec8 kARGBToSepiaB = { + 17, 68, 35, 0, 17, 68, 35, 0, 17, 68, 35, 0, 17, 68, 35, 0 +}; + +static vec8 kARGBToSepiaG = { + 22, 88, 45, 0, 22, 88, 45, 0, 22, 88, 45, 0, 22, 88, 45, 0 +}; + +static vec8 kARGBToSepiaR = { + 24, 98, 50, 0, 24, 98, 50, 0, 24, 98, 50, 0, 24, 98, 50, 0 +}; + +// Convert 8 ARGB pixels (32 bytes) to 8 Sepia ARGB pixels. +void ARGBSepiaRow_SSSE3(uint8* dst_argb, int width) { + asm volatile ( + "movdqa %2,%%xmm2 \n" + "movdqa %3,%%xmm3 \n" + "movdqa %4,%%xmm4 \n" + + // 8 pixel loop. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm6 \n" + "pmaddubsw %%xmm2,%%xmm0 \n" + "pmaddubsw %%xmm2,%%xmm6 \n" + "phaddw %%xmm6,%%xmm0 \n" + "psrlw $0x7,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movdqu " MEMACCESS(0) ",%%xmm5 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "pmaddubsw %%xmm3,%%xmm5 \n" + "pmaddubsw %%xmm3,%%xmm1 \n" + "phaddw %%xmm1,%%xmm5 \n" + "psrlw $0x7,%%xmm5 \n" + "packuswb %%xmm5,%%xmm5 \n" + "punpcklbw %%xmm5,%%xmm0 \n" + "movdqu " MEMACCESS(0) ",%%xmm5 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "pmaddubsw %%xmm4,%%xmm5 \n" + "pmaddubsw %%xmm4,%%xmm1 \n" + "phaddw %%xmm1,%%xmm5 \n" + "psrlw $0x7,%%xmm5 \n" + "packuswb %%xmm5,%%xmm5 \n" + "movdqu " MEMACCESS(0) ",%%xmm6 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "psrld $0x18,%%xmm6 \n" + "psrld $0x18,%%xmm1 \n" + "packuswb %%xmm1,%%xmm6 \n" + "packuswb %%xmm6,%%xmm6 \n" + "punpcklbw %%xmm6,%%xmm5 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpcklwd %%xmm5,%%xmm0 \n" + "punpckhwd %%xmm5,%%xmm1 \n" + "movdqu %%xmm0," MEMACCESS(0) " \n" + "movdqu %%xmm1," MEMACCESS2(0x10,0) " \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "sub $0x8,%1 \n" + "jg 1b \n" + : "+r"(dst_argb), // %0 + "+r"(width) // %1 + : "m"(kARGBToSepiaB), // %2 + "m"(kARGBToSepiaG), // %3 + "m"(kARGBToSepiaR) // %4 + : "memory", "cc" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" + ); +} +#endif // HAS_ARGBSEPIAROW_SSSE3 + +#ifdef HAS_ARGBCOLORMATRIXROW_SSSE3 +// Tranform 8 ARGB pixels (32 bytes) with color matrix. +// Same as Sepia except matrix is provided. +void ARGBColorMatrixRow_SSSE3(const uint8* src_argb, uint8* dst_argb, + const int8* matrix_argb, int width) { + asm volatile ( + "movdqu " MEMACCESS(3) ",%%xmm5 \n" + "pshufd $0x00,%%xmm5,%%xmm2 \n" + "pshufd $0x55,%%xmm5,%%xmm3 \n" + "pshufd $0xaa,%%xmm5,%%xmm4 \n" + "pshufd $0xff,%%xmm5,%%xmm5 \n" + + // 8 pixel loop. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm7 \n" + "pmaddubsw %%xmm2,%%xmm0 \n" + "pmaddubsw %%xmm2,%%xmm7 \n" + "movdqu " MEMACCESS(0) ",%%xmm6 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "pmaddubsw %%xmm3,%%xmm6 \n" + "pmaddubsw %%xmm3,%%xmm1 \n" + "phaddsw %%xmm7,%%xmm0 \n" + "phaddsw %%xmm1,%%xmm6 \n" + "psraw $0x6,%%xmm0 \n" + "psraw $0x6,%%xmm6 \n" + "packuswb %%xmm0,%%xmm0 \n" + "packuswb %%xmm6,%%xmm6 \n" + "punpcklbw %%xmm6,%%xmm0 \n" + "movdqu " MEMACCESS(0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm7 \n" + "pmaddubsw %%xmm4,%%xmm1 \n" + "pmaddubsw %%xmm4,%%xmm7 \n" + "phaddsw %%xmm7,%%xmm1 \n" + "movdqu " MEMACCESS(0) ",%%xmm6 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm7 \n" + "pmaddubsw %%xmm5,%%xmm6 \n" + "pmaddubsw %%xmm5,%%xmm7 \n" + "phaddsw %%xmm7,%%xmm6 \n" + "psraw $0x6,%%xmm1 \n" + "psraw $0x6,%%xmm6 \n" + "packuswb %%xmm1,%%xmm1 \n" + "packuswb %%xmm6,%%xmm6 \n" + "punpcklbw %%xmm6,%%xmm1 \n" + "movdqa %%xmm0,%%xmm6 \n" + "punpcklwd %%xmm1,%%xmm0 \n" + "punpckhwd %%xmm1,%%xmm6 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "movdqu %%xmm6," MEMACCESS2(0x10,1) " \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+r"(width) // %2 + : "r"(matrix_argb) // %3 + : "memory", "cc" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} +#endif // HAS_ARGBCOLORMATRIXROW_SSSE3 + +#ifdef HAS_ARGBQUANTIZEROW_SSE2 +// Quantize 4 ARGB pixels (16 bytes). +void ARGBQuantizeRow_SSE2(uint8* dst_argb, int scale, int interval_size, + int interval_offset, int width) { + asm volatile ( + "movd %2,%%xmm2 \n" + "movd %3,%%xmm3 \n" + "movd %4,%%xmm4 \n" + "pshuflw $0x40,%%xmm2,%%xmm2 \n" + "pshufd $0x44,%%xmm2,%%xmm2 \n" + "pshuflw $0x40,%%xmm3,%%xmm3 \n" + "pshufd $0x44,%%xmm3,%%xmm3 \n" + "pshuflw $0x40,%%xmm4,%%xmm4 \n" + "pshufd $0x44,%%xmm4,%%xmm4 \n" + "pxor %%xmm5,%%xmm5 \n" + "pcmpeqb %%xmm6,%%xmm6 \n" + "pslld $0x18,%%xmm6 \n" + + // 4 pixel loop. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "punpcklbw %%xmm5,%%xmm0 \n" + "pmulhuw %%xmm2,%%xmm0 \n" + "movdqu " MEMACCESS(0) ",%%xmm1 \n" + "punpckhbw %%xmm5,%%xmm1 \n" + "pmulhuw %%xmm2,%%xmm1 \n" + "pmullw %%xmm3,%%xmm0 \n" + "movdqu " MEMACCESS(0) ",%%xmm7 \n" + "pmullw %%xmm3,%%xmm1 \n" + "pand %%xmm6,%%xmm7 \n" + "paddw %%xmm4,%%xmm0 \n" + "paddw %%xmm4,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "por %%xmm7,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(0) " \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "sub $0x4,%1 \n" + "jg 1b \n" + : "+r"(dst_argb), // %0 + "+r"(width) // %1 + : "r"(scale), // %2 + "r"(interval_size), // %3 + "r"(interval_offset) // %4 + : "memory", "cc" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} +#endif // HAS_ARGBQUANTIZEROW_SSE2 + +#ifdef HAS_ARGBSHADEROW_SSE2 +// Shade 4 pixels at a time by specified value. +void ARGBShadeRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width, + uint32 value) { + asm volatile ( + "movd %3,%%xmm2 \n" + "punpcklbw %%xmm2,%%xmm2 \n" + "punpcklqdq %%xmm2,%%xmm2 \n" + + // 4 pixel loop. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpcklbw %%xmm0,%%xmm0 \n" + "punpckhbw %%xmm1,%%xmm1 \n" + "pmulhuw %%xmm2,%%xmm0 \n" + "pmulhuw %%xmm2,%%xmm1 \n" + "psrlw $0x8,%%xmm0 \n" + "psrlw $0x8,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x4,%2 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+r"(width) // %2 + : "r"(value) // %3 + : "memory", "cc" + , "xmm0", "xmm1", "xmm2" + ); +} +#endif // HAS_ARGBSHADEROW_SSE2 + +#ifdef HAS_ARGBMULTIPLYROW_SSE2 +// Multiply 2 rows of ARGB pixels together, 4 pixels at a time. +void ARGBMultiplyRow_SSE2(const uint8* src_argb0, const uint8* src_argb1, + uint8* dst_argb, int width) { + asm volatile ( + "pxor %%xmm5,%%xmm5 \n" + + // 4 pixel loop. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "movdqu " MEMACCESS(1) ",%%xmm2 \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "movdqu %%xmm0,%%xmm1 \n" + "movdqu %%xmm2,%%xmm3 \n" + "punpcklbw %%xmm0,%%xmm0 \n" + "punpckhbw %%xmm1,%%xmm1 \n" + "punpcklbw %%xmm5,%%xmm2 \n" + "punpckhbw %%xmm5,%%xmm3 \n" + "pmulhuw %%xmm2,%%xmm0 \n" + "pmulhuw %%xmm3,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x10,2) ",%2 \n" + "sub $0x4,%3 \n" + "jg 1b \n" + : "+r"(src_argb0), // %0 + "+r"(src_argb1), // %1 + "+r"(dst_argb), // %2 + "+r"(width) // %3 + : + : "memory", "cc" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" + ); +} +#endif // HAS_ARGBMULTIPLYROW_SSE2 + +#ifdef HAS_ARGBMULTIPLYROW_AVX2 +// Multiply 2 rows of ARGB pixels together, 8 pixels at a time. +void ARGBMultiplyRow_AVX2(const uint8* src_argb0, const uint8* src_argb1, + uint8* dst_argb, int width) { + asm volatile ( + "vpxor %%ymm5,%%ymm5,%%ymm5 \n" + + // 4 pixel loop. + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "vmovdqu " MEMACCESS(1) ",%%ymm3 \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "vpunpcklbw %%ymm1,%%ymm1,%%ymm0 \n" + "vpunpckhbw %%ymm1,%%ymm1,%%ymm1 \n" + "vpunpcklbw %%ymm5,%%ymm3,%%ymm2 \n" + "vpunpckhbw %%ymm5,%%ymm3,%%ymm3 \n" + "vpmulhuw %%ymm2,%%ymm0,%%ymm0 \n" + "vpmulhuw %%ymm3,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + "vmovdqu %%ymm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x20,2) ",%2 \n" + "sub $0x8,%3 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_argb0), // %0 + "+r"(src_argb1), // %1 + "+r"(dst_argb), // %2 + "+r"(width) // %3 + : + : "memory", "cc" +#if defined(__AVX2__) + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" +#endif + ); +} +#endif // HAS_ARGBMULTIPLYROW_AVX2 + +#ifdef HAS_ARGBADDROW_SSE2 +// Add 2 rows of ARGB pixels together, 4 pixels at a time. +void ARGBAddRow_SSE2(const uint8* src_argb0, const uint8* src_argb1, + uint8* dst_argb, int width) { + asm volatile ( + // 4 pixel loop. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "movdqu " MEMACCESS(1) ",%%xmm1 \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "paddusb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x10,2) ",%2 \n" + "sub $0x4,%3 \n" + "jg 1b \n" + : "+r"(src_argb0), // %0 + "+r"(src_argb1), // %1 + "+r"(dst_argb), // %2 + "+r"(width) // %3 + : + : "memory", "cc" + , "xmm0", "xmm1" + ); +} +#endif // HAS_ARGBADDROW_SSE2 + +#ifdef HAS_ARGBADDROW_AVX2 +// Add 2 rows of ARGB pixels together, 4 pixels at a time. +void ARGBAddRow_AVX2(const uint8* src_argb0, const uint8* src_argb1, + uint8* dst_argb, int width) { + asm volatile ( + // 4 pixel loop. + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "vpaddusb " MEMACCESS(1) ",%%ymm0,%%ymm0 \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "vmovdqu %%ymm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x20,2) ",%2 \n" + "sub $0x8,%3 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_argb0), // %0 + "+r"(src_argb1), // %1 + "+r"(dst_argb), // %2 + "+r"(width) // %3 + : + : "memory", "cc" + , "xmm0" + ); +} +#endif // HAS_ARGBADDROW_AVX2 + +#ifdef HAS_ARGBSUBTRACTROW_SSE2 +// Subtract 2 rows of ARGB pixels, 4 pixels at a time. +void ARGBSubtractRow_SSE2(const uint8* src_argb0, const uint8* src_argb1, + uint8* dst_argb, int width) { + asm volatile ( + // 4 pixel loop. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "movdqu " MEMACCESS(1) ",%%xmm1 \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "psubusb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x10,2) ",%2 \n" + "sub $0x4,%3 \n" + "jg 1b \n" + : "+r"(src_argb0), // %0 + "+r"(src_argb1), // %1 + "+r"(dst_argb), // %2 + "+r"(width) // %3 + : + : "memory", "cc" + , "xmm0", "xmm1" + ); +} +#endif // HAS_ARGBSUBTRACTROW_SSE2 + +#ifdef HAS_ARGBSUBTRACTROW_AVX2 +// Subtract 2 rows of ARGB pixels, 8 pixels at a time. +void ARGBSubtractRow_AVX2(const uint8* src_argb0, const uint8* src_argb1, + uint8* dst_argb, int width) { + asm volatile ( + // 4 pixel loop. + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "vpsubusb " MEMACCESS(1) ",%%ymm0,%%ymm0 \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "vmovdqu %%ymm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x20,2) ",%2 \n" + "sub $0x8,%3 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_argb0), // %0 + "+r"(src_argb1), // %1 + "+r"(dst_argb), // %2 + "+r"(width) // %3 + : + : "memory", "cc" + , "xmm0" + ); +} +#endif // HAS_ARGBSUBTRACTROW_AVX2 + +#ifdef HAS_SOBELXROW_SSE2 +// SobelX as a matrix is +// -1 0 1 +// -2 0 2 +// -1 0 1 +void SobelXRow_SSE2(const uint8* src_y0, const uint8* src_y1, + const uint8* src_y2, uint8* dst_sobelx, int width) { + asm volatile ( + "sub %0,%1 \n" + "sub %0,%2 \n" + "sub %0,%3 \n" + "pxor %%xmm5,%%xmm5 \n" + + // 8 pixel loop. + LABELALIGN + "1: \n" + "movq " MEMACCESS(0) ",%%xmm0 \n" + "movq " MEMACCESS2(0x2,0) ",%%xmm1 \n" + "punpcklbw %%xmm5,%%xmm0 \n" + "punpcklbw %%xmm5,%%xmm1 \n" + "psubw %%xmm1,%%xmm0 \n" + MEMOPREG(movq,0x00,0,1,1,xmm1) // movq (%0,%1,1),%%xmm1 + MEMOPREG(movq,0x02,0,1,1,xmm2) // movq 0x2(%0,%1,1),%%xmm2 + "punpcklbw %%xmm5,%%xmm1 \n" + "punpcklbw %%xmm5,%%xmm2 \n" + "psubw %%xmm2,%%xmm1 \n" + MEMOPREG(movq,0x00,0,2,1,xmm2) // movq (%0,%2,1),%%xmm2 + MEMOPREG(movq,0x02,0,2,1,xmm3) // movq 0x2(%0,%2,1),%%xmm3 + "punpcklbw %%xmm5,%%xmm2 \n" + "punpcklbw %%xmm5,%%xmm3 \n" + "psubw %%xmm3,%%xmm2 \n" + "paddw %%xmm2,%%xmm0 \n" + "paddw %%xmm1,%%xmm0 \n" + "paddw %%xmm1,%%xmm0 \n" + "pxor %%xmm1,%%xmm1 \n" + "psubw %%xmm0,%%xmm1 \n" + "pmaxsw %%xmm1,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + MEMOPMEM(movq,xmm0,0x00,0,3,1) // movq %%xmm0,(%0,%3,1) + "lea " MEMLEA(0x8,0) ",%0 \n" + "sub $0x8,%4 \n" + "jg 1b \n" + : "+r"(src_y0), // %0 + "+r"(src_y1), // %1 + "+r"(src_y2), // %2 + "+r"(dst_sobelx), // %3 + "+r"(width) // %4 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" + ); +} +#endif // HAS_SOBELXROW_SSE2 + +#ifdef HAS_SOBELYROW_SSE2 +// SobelY as a matrix is +// -1 -2 -1 +// 0 0 0 +// 1 2 1 +void SobelYRow_SSE2(const uint8* src_y0, const uint8* src_y1, + uint8* dst_sobely, int width) { + asm volatile ( + "sub %0,%1 \n" + "sub %0,%2 \n" + "pxor %%xmm5,%%xmm5 \n" + + // 8 pixel loop. + LABELALIGN + "1: \n" + "movq " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(movq,0x00,0,1,1,xmm1) // movq (%0,%1,1),%%xmm1 + "punpcklbw %%xmm5,%%xmm0 \n" + "punpcklbw %%xmm5,%%xmm1 \n" + "psubw %%xmm1,%%xmm0 \n" + "movq " MEMACCESS2(0x1,0) ",%%xmm1 \n" + MEMOPREG(movq,0x01,0,1,1,xmm2) // movq 0x1(%0,%1,1),%%xmm2 + "punpcklbw %%xmm5,%%xmm1 \n" + "punpcklbw %%xmm5,%%xmm2 \n" + "psubw %%xmm2,%%xmm1 \n" + "movq " MEMACCESS2(0x2,0) ",%%xmm2 \n" + MEMOPREG(movq,0x02,0,1,1,xmm3) // movq 0x2(%0,%1,1),%%xmm3 + "punpcklbw %%xmm5,%%xmm2 \n" + "punpcklbw %%xmm5,%%xmm3 \n" + "psubw %%xmm3,%%xmm2 \n" + "paddw %%xmm2,%%xmm0 \n" + "paddw %%xmm1,%%xmm0 \n" + "paddw %%xmm1,%%xmm0 \n" + "pxor %%xmm1,%%xmm1 \n" + "psubw %%xmm0,%%xmm1 \n" + "pmaxsw %%xmm1,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + MEMOPMEM(movq,xmm0,0x00,0,2,1) // movq %%xmm0,(%0,%2,1) + "lea " MEMLEA(0x8,0) ",%0 \n" + "sub $0x8,%3 \n" + "jg 1b \n" + : "+r"(src_y0), // %0 + "+r"(src_y1), // %1 + "+r"(dst_sobely), // %2 + "+r"(width) // %3 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" + ); +} +#endif // HAS_SOBELYROW_SSE2 + +#ifdef HAS_SOBELROW_SSE2 +// Adds Sobel X and Sobel Y and stores Sobel into ARGB. +// A = 255 +// R = Sobel +// G = Sobel +// B = Sobel +void SobelRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely, + uint8* dst_argb, int width) { + asm volatile ( + "sub %0,%1 \n" + "pcmpeqb %%xmm5,%%xmm5 \n" + "pslld $0x18,%%xmm5 \n" + + // 8 pixel loop. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(movdqu,0x00,0,1,1,xmm1) // movdqu (%0,%1,1),%%xmm1 + "lea " MEMLEA(0x10,0) ",%0 \n" + "paddusb %%xmm1,%%xmm0 \n" + "movdqa %%xmm0,%%xmm2 \n" + "punpcklbw %%xmm0,%%xmm2 \n" + "punpckhbw %%xmm0,%%xmm0 \n" + "movdqa %%xmm2,%%xmm1 \n" + "punpcklwd %%xmm2,%%xmm1 \n" + "punpckhwd %%xmm2,%%xmm2 \n" + "por %%xmm5,%%xmm1 \n" + "por %%xmm5,%%xmm2 \n" + "movdqa %%xmm0,%%xmm3 \n" + "punpcklwd %%xmm0,%%xmm3 \n" + "punpckhwd %%xmm0,%%xmm0 \n" + "por %%xmm5,%%xmm3 \n" + "por %%xmm5,%%xmm0 \n" + "movdqu %%xmm1," MEMACCESS(2) " \n" + "movdqu %%xmm2," MEMACCESS2(0x10,2) " \n" + "movdqu %%xmm3," MEMACCESS2(0x20,2) " \n" + "movdqu %%xmm0," MEMACCESS2(0x30,2) " \n" + "lea " MEMLEA(0x40,2) ",%2 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_sobelx), // %0 + "+r"(src_sobely), // %1 + "+r"(dst_argb), // %2 + "+r"(width) // %3 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" + ); +} +#endif // HAS_SOBELROW_SSE2 + +#ifdef HAS_SOBELTOPLANEROW_SSE2 +// Adds Sobel X and Sobel Y and stores Sobel into a plane. +void SobelToPlaneRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely, + uint8* dst_y, int width) { + asm volatile ( + "sub %0,%1 \n" + "pcmpeqb %%xmm5,%%xmm5 \n" + "pslld $0x18,%%xmm5 \n" + + // 8 pixel loop. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(movdqu,0x00,0,1,1,xmm1) // movdqu (%0,%1,1),%%xmm1 + "lea " MEMLEA(0x10,0) ",%0 \n" + "paddusb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x10,2) ",%2 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_sobelx), // %0 + "+r"(src_sobely), // %1 + "+r"(dst_y), // %2 + "+r"(width) // %3 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1" + ); +} +#endif // HAS_SOBELTOPLANEROW_SSE2 + +#ifdef HAS_SOBELXYROW_SSE2 +// Mixes Sobel X, Sobel Y and Sobel into ARGB. +// A = 255 +// R = Sobel X +// G = Sobel +// B = Sobel Y +void SobelXYRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely, + uint8* dst_argb, int width) { + asm volatile ( + "sub %0,%1 \n" + "pcmpeqb %%xmm5,%%xmm5 \n" + + // 8 pixel loop. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(movdqu,0x00,0,1,1,xmm1) // movdqu (%0,%1,1),%%xmm1 + "lea " MEMLEA(0x10,0) ",%0 \n" + "movdqa %%xmm0,%%xmm2 \n" + "paddusb %%xmm1,%%xmm2 \n" + "movdqa %%xmm0,%%xmm3 \n" + "punpcklbw %%xmm5,%%xmm3 \n" + "punpckhbw %%xmm5,%%xmm0 \n" + "movdqa %%xmm1,%%xmm4 \n" + "punpcklbw %%xmm2,%%xmm4 \n" + "punpckhbw %%xmm2,%%xmm1 \n" + "movdqa %%xmm4,%%xmm6 \n" + "punpcklwd %%xmm3,%%xmm6 \n" + "punpckhwd %%xmm3,%%xmm4 \n" + "movdqa %%xmm1,%%xmm7 \n" + "punpcklwd %%xmm0,%%xmm7 \n" + "punpckhwd %%xmm0,%%xmm1 \n" + "movdqu %%xmm6," MEMACCESS(2) " \n" + "movdqu %%xmm4," MEMACCESS2(0x10,2) " \n" + "movdqu %%xmm7," MEMACCESS2(0x20,2) " \n" + "movdqu %%xmm1," MEMACCESS2(0x30,2) " \n" + "lea " MEMLEA(0x40,2) ",%2 \n" + "sub $0x10,%3 \n" + "jg 1b \n" + : "+r"(src_sobelx), // %0 + "+r"(src_sobely), // %1 + "+r"(dst_argb), // %2 + "+r"(width) // %3 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} +#endif // HAS_SOBELXYROW_SSE2 + +#ifdef HAS_COMPUTECUMULATIVESUMROW_SSE2 +// Creates a table of cumulative sums where each value is a sum of all values +// above and to the left of the value, inclusive of the value. +void ComputeCumulativeSumRow_SSE2(const uint8* row, int32* cumsum, + const int32* previous_cumsum, int width) { + asm volatile ( + "pxor %%xmm0,%%xmm0 \n" + "pxor %%xmm1,%%xmm1 \n" + "sub $0x4,%3 \n" + "jl 49f \n" + "test $0xf,%1 \n" + "jne 49f \n" + + // 4 pixel loop \n" + LABELALIGN + "40: \n" + "movdqu " MEMACCESS(0) ",%%xmm2 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "movdqa %%xmm2,%%xmm4 \n" + "punpcklbw %%xmm1,%%xmm2 \n" + "movdqa %%xmm2,%%xmm3 \n" + "punpcklwd %%xmm1,%%xmm2 \n" + "punpckhwd %%xmm1,%%xmm3 \n" + "punpckhbw %%xmm1,%%xmm4 \n" + "movdqa %%xmm4,%%xmm5 \n" + "punpcklwd %%xmm1,%%xmm4 \n" + "punpckhwd %%xmm1,%%xmm5 \n" + "paddd %%xmm2,%%xmm0 \n" + "movdqu " MEMACCESS(2) ",%%xmm2 \n" + "paddd %%xmm0,%%xmm2 \n" + "paddd %%xmm3,%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,2) ",%%xmm3 \n" + "paddd %%xmm0,%%xmm3 \n" + "paddd %%xmm4,%%xmm0 \n" + "movdqu " MEMACCESS2(0x20,2) ",%%xmm4 \n" + "paddd %%xmm0,%%xmm4 \n" + "paddd %%xmm5,%%xmm0 \n" + "movdqu " MEMACCESS2(0x30,2) ",%%xmm5 \n" + "lea " MEMLEA(0x40,2) ",%2 \n" + "paddd %%xmm0,%%xmm5 \n" + "movdqu %%xmm2," MEMACCESS(1) " \n" + "movdqu %%xmm3," MEMACCESS2(0x10,1) " \n" + "movdqu %%xmm4," MEMACCESS2(0x20,1) " \n" + "movdqu %%xmm5," MEMACCESS2(0x30,1) " \n" + "lea " MEMLEA(0x40,1) ",%1 \n" + "sub $0x4,%3 \n" + "jge 40b \n" + + "49: \n" + "add $0x3,%3 \n" + "jl 19f \n" + + // 1 pixel loop \n" + LABELALIGN + "10: \n" + "movd " MEMACCESS(0) ",%%xmm2 \n" + "lea " MEMLEA(0x4,0) ",%0 \n" + "punpcklbw %%xmm1,%%xmm2 \n" + "punpcklwd %%xmm1,%%xmm2 \n" + "paddd %%xmm2,%%xmm0 \n" + "movdqu " MEMACCESS(2) ",%%xmm2 \n" + "lea " MEMLEA(0x10,2) ",%2 \n" + "paddd %%xmm0,%%xmm2 \n" + "movdqu %%xmm2," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x1,%3 \n" + "jge 10b \n" + + "19: \n" + : "+r"(row), // %0 + "+r"(cumsum), // %1 + "+r"(previous_cumsum), // %2 + "+r"(width) // %3 + : + : "memory", "cc" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_COMPUTECUMULATIVESUMROW_SSE2 + +#ifdef HAS_CUMULATIVESUMTOAVERAGEROW_SSE2 +void CumulativeSumToAverageRow_SSE2(const int32* topleft, const int32* botleft, + int width, int area, uint8* dst, + int count) { + asm volatile ( + "movd %5,%%xmm5 \n" + "cvtdq2ps %%xmm5,%%xmm5 \n" + "rcpss %%xmm5,%%xmm4 \n" + "pshufd $0x0,%%xmm4,%%xmm4 \n" + "sub $0x4,%3 \n" + "jl 49f \n" + "cmpl $0x80,%5 \n" + "ja 40f \n" + + "pshufd $0x0,%%xmm5,%%xmm5 \n" + "pcmpeqb %%xmm6,%%xmm6 \n" + "psrld $0x10,%%xmm6 \n" + "cvtdq2ps %%xmm6,%%xmm6 \n" + "addps %%xmm6,%%xmm5 \n" + "mulps %%xmm4,%%xmm5 \n" + "cvtps2dq %%xmm5,%%xmm5 \n" + "packssdw %%xmm5,%%xmm5 \n" + + // 4 pixel small loop \n" + LABELALIGN + "4: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" + MEMOPREG(psubd,0x00,0,4,4,xmm0) // psubd 0x00(%0,%4,4),%%xmm0 + MEMOPREG(psubd,0x10,0,4,4,xmm1) // psubd 0x10(%0,%4,4),%%xmm1 + MEMOPREG(psubd,0x20,0,4,4,xmm2) // psubd 0x20(%0,%4,4),%%xmm2 + MEMOPREG(psubd,0x30,0,4,4,xmm3) // psubd 0x30(%0,%4,4),%%xmm3 + "lea " MEMLEA(0x40,0) ",%0 \n" + "psubd " MEMACCESS(1) ",%%xmm0 \n" + "psubd " MEMACCESS2(0x10,1) ",%%xmm1 \n" + "psubd " MEMACCESS2(0x20,1) ",%%xmm2 \n" + "psubd " MEMACCESS2(0x30,1) ",%%xmm3 \n" + MEMOPREG(paddd,0x00,1,4,4,xmm0) // paddd 0x00(%1,%4,4),%%xmm0 + MEMOPREG(paddd,0x10,1,4,4,xmm1) // paddd 0x10(%1,%4,4),%%xmm1 + MEMOPREG(paddd,0x20,1,4,4,xmm2) // paddd 0x20(%1,%4,4),%%xmm2 + MEMOPREG(paddd,0x30,1,4,4,xmm3) // paddd 0x30(%1,%4,4),%%xmm3 + "lea " MEMLEA(0x40,1) ",%1 \n" + "packssdw %%xmm1,%%xmm0 \n" + "packssdw %%xmm3,%%xmm2 \n" + "pmulhuw %%xmm5,%%xmm0 \n" + "pmulhuw %%xmm5,%%xmm2 \n" + "packuswb %%xmm2,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x10,2) ",%2 \n" + "sub $0x4,%3 \n" + "jge 4b \n" + "jmp 49f \n" + + // 4 pixel loop \n" + LABELALIGN + "40: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n" + "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n" + MEMOPREG(psubd,0x00,0,4,4,xmm0) // psubd 0x00(%0,%4,4),%%xmm0 + MEMOPREG(psubd,0x10,0,4,4,xmm1) // psubd 0x10(%0,%4,4),%%xmm1 + MEMOPREG(psubd,0x20,0,4,4,xmm2) // psubd 0x20(%0,%4,4),%%xmm2 + MEMOPREG(psubd,0x30,0,4,4,xmm3) // psubd 0x30(%0,%4,4),%%xmm3 + "lea " MEMLEA(0x40,0) ",%0 \n" + "psubd " MEMACCESS(1) ",%%xmm0 \n" + "psubd " MEMACCESS2(0x10,1) ",%%xmm1 \n" + "psubd " MEMACCESS2(0x20,1) ",%%xmm2 \n" + "psubd " MEMACCESS2(0x30,1) ",%%xmm3 \n" + MEMOPREG(paddd,0x00,1,4,4,xmm0) // paddd 0x00(%1,%4,4),%%xmm0 + MEMOPREG(paddd,0x10,1,4,4,xmm1) // paddd 0x10(%1,%4,4),%%xmm1 + MEMOPREG(paddd,0x20,1,4,4,xmm2) // paddd 0x20(%1,%4,4),%%xmm2 + MEMOPREG(paddd,0x30,1,4,4,xmm3) // paddd 0x30(%1,%4,4),%%xmm3 + "lea " MEMLEA(0x40,1) ",%1 \n" + "cvtdq2ps %%xmm0,%%xmm0 \n" + "cvtdq2ps %%xmm1,%%xmm1 \n" + "mulps %%xmm4,%%xmm0 \n" + "mulps %%xmm4,%%xmm1 \n" + "cvtdq2ps %%xmm2,%%xmm2 \n" + "cvtdq2ps %%xmm3,%%xmm3 \n" + "mulps %%xmm4,%%xmm2 \n" + "mulps %%xmm4,%%xmm3 \n" + "cvtps2dq %%xmm0,%%xmm0 \n" + "cvtps2dq %%xmm1,%%xmm1 \n" + "cvtps2dq %%xmm2,%%xmm2 \n" + "cvtps2dq %%xmm3,%%xmm3 \n" + "packssdw %%xmm1,%%xmm0 \n" + "packssdw %%xmm3,%%xmm2 \n" + "packuswb %%xmm2,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x10,2) ",%2 \n" + "sub $0x4,%3 \n" + "jge 40b \n" + + "49: \n" + "add $0x3,%3 \n" + "jl 19f \n" + + // 1 pixel loop \n" + LABELALIGN + "10: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(psubd,0x00,0,4,4,xmm0) // psubd 0x00(%0,%4,4),%%xmm0 + "lea " MEMLEA(0x10,0) ",%0 \n" + "psubd " MEMACCESS(1) ",%%xmm0 \n" + MEMOPREG(paddd,0x00,1,4,4,xmm0) // paddd 0x00(%1,%4,4),%%xmm0 + "lea " MEMLEA(0x10,1) ",%1 \n" + "cvtdq2ps %%xmm0,%%xmm0 \n" + "mulps %%xmm4,%%xmm0 \n" + "cvtps2dq %%xmm0,%%xmm0 \n" + "packssdw %%xmm0,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movd %%xmm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x4,2) ",%2 \n" + "sub $0x1,%3 \n" + "jge 10b \n" + "19: \n" + : "+r"(topleft), // %0 + "+r"(botleft), // %1 + "+r"(dst), // %2 + "+rm"(count) // %3 + : "r"((intptr_t)(width)), // %4 + "rm"(area) // %5 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" + ); +} +#endif // HAS_CUMULATIVESUMTOAVERAGEROW_SSE2 + +#ifdef HAS_ARGBAFFINEROW_SSE2 +// Copy ARGB pixels from source image with slope to a row of destination. +LIBYUV_API +void ARGBAffineRow_SSE2(const uint8* src_argb, int src_argb_stride, + uint8* dst_argb, const float* src_dudv, int width) { + intptr_t src_argb_stride_temp = src_argb_stride; + intptr_t temp = 0; + asm volatile ( + "movq " MEMACCESS(3) ",%%xmm2 \n" + "movq " MEMACCESS2(0x08,3) ",%%xmm7 \n" + "shl $0x10,%1 \n" + "add $0x4,%1 \n" + "movd %1,%%xmm5 \n" + "sub $0x4,%4 \n" + "jl 49f \n" + + "pshufd $0x44,%%xmm7,%%xmm7 \n" + "pshufd $0x0,%%xmm5,%%xmm5 \n" + "movdqa %%xmm2,%%xmm0 \n" + "addps %%xmm7,%%xmm0 \n" + "movlhps %%xmm0,%%xmm2 \n" + "movdqa %%xmm7,%%xmm4 \n" + "addps %%xmm4,%%xmm4 \n" + "movdqa %%xmm2,%%xmm3 \n" + "addps %%xmm4,%%xmm3 \n" + "addps %%xmm4,%%xmm4 \n" + + // 4 pixel loop \n" + LABELALIGN + "40: \n" + "cvttps2dq %%xmm2,%%xmm0 \n" // x, y float to int first 2 + "cvttps2dq %%xmm3,%%xmm1 \n" // x, y float to int next 2 + "packssdw %%xmm1,%%xmm0 \n" // x, y as 8 shorts + "pmaddwd %%xmm5,%%xmm0 \n" // off = x * 4 + y * stride + "movd %%xmm0,%k1 \n" + "pshufd $0x39,%%xmm0,%%xmm0 \n" + "movd %%xmm0,%k5 \n" + "pshufd $0x39,%%xmm0,%%xmm0 \n" + MEMOPREG(movd,0x00,0,1,1,xmm1) // movd (%0,%1,1),%%xmm1 + MEMOPREG(movd,0x00,0,5,1,xmm6) // movd (%0,%5,1),%%xmm6 + "punpckldq %%xmm6,%%xmm1 \n" + "addps %%xmm4,%%xmm2 \n" + "movq %%xmm1," MEMACCESS(2) " \n" + "movd %%xmm0,%k1 \n" + "pshufd $0x39,%%xmm0,%%xmm0 \n" + "movd %%xmm0,%k5 \n" + MEMOPREG(movd,0x00,0,1,1,xmm0) // movd (%0,%1,1),%%xmm0 + MEMOPREG(movd,0x00,0,5,1,xmm6) // movd (%0,%5,1),%%xmm6 + "punpckldq %%xmm6,%%xmm0 \n" + "addps %%xmm4,%%xmm3 \n" + "movq %%xmm0," MEMACCESS2(0x08,2) " \n" + "lea " MEMLEA(0x10,2) ",%2 \n" + "sub $0x4,%4 \n" + "jge 40b \n" + + "49: \n" + "add $0x3,%4 \n" + "jl 19f \n" + + // 1 pixel loop \n" + LABELALIGN + "10: \n" + "cvttps2dq %%xmm2,%%xmm0 \n" + "packssdw %%xmm0,%%xmm0 \n" + "pmaddwd %%xmm5,%%xmm0 \n" + "addps %%xmm7,%%xmm2 \n" + "movd %%xmm0,%k1 \n" + MEMOPREG(movd,0x00,0,1,1,xmm0) // movd (%0,%1,1),%%xmm0 + "movd %%xmm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x04,2) ",%2 \n" + "sub $0x1,%4 \n" + "jge 10b \n" + "19: \n" + : "+r"(src_argb), // %0 + "+r"(src_argb_stride_temp), // %1 + "+r"(dst_argb), // %2 + "+r"(src_dudv), // %3 + "+rm"(width), // %4 + "+r"(temp) // %5 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} +#endif // HAS_ARGBAFFINEROW_SSE2 + +#ifdef HAS_INTERPOLATEROW_SSSE3 +// Bilinear filter 16x2 -> 16x1 +void InterpolateRow_SSSE3(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride, int dst_width, + int source_y_fraction) { + asm volatile ( + "sub %1,%0 \n" + "cmp $0x0,%3 \n" + "je 100f \n" + "cmp $0x80,%3 \n" + "je 50f \n" + + "movd %3,%%xmm0 \n" + "neg %3 \n" + "add $0x100,%3 \n" + "movd %3,%%xmm5 \n" + "punpcklbw %%xmm0,%%xmm5 \n" + "punpcklwd %%xmm5,%%xmm5 \n" + "pshufd $0x0,%%xmm5,%%xmm5 \n" + "mov $0x80808080,%%eax \n" + "movd %%eax,%%xmm4 \n" + "pshufd $0x0,%%xmm4,%%xmm4 \n" + + // General purpose row blend. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(1) ",%%xmm0 \n" + MEMOPREG(movdqu,0x00,1,4,1,xmm2) + "movdqa %%xmm0,%%xmm1 \n" + "punpcklbw %%xmm2,%%xmm0 \n" + "punpckhbw %%xmm2,%%xmm1 \n" + "psubb %%xmm4,%%xmm0 \n" + "psubb %%xmm4,%%xmm1 \n" + "movdqa %%xmm5,%%xmm2 \n" + "movdqa %%xmm5,%%xmm3 \n" + "pmaddubsw %%xmm0,%%xmm2 \n" + "pmaddubsw %%xmm1,%%xmm3 \n" + "paddw %%xmm4,%%xmm2 \n" + "paddw %%xmm4,%%xmm3 \n" + "psrlw $0x8,%%xmm2 \n" + "psrlw $0x8,%%xmm3 \n" + "packuswb %%xmm3,%%xmm2 \n" + MEMOPMEM(movdqu,xmm2,0x00,1,0,1) + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + "jmp 99f \n" + + // Blend 50 / 50. + LABELALIGN + "50: \n" + "movdqu " MEMACCESS(1) ",%%xmm0 \n" + MEMOPREG(movdqu,0x00,1,4,1,xmm1) + "pavgb %%xmm1,%%xmm0 \n" + MEMOPMEM(movdqu,xmm0,0x00,1,0,1) + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 50b \n" + "jmp 99f \n" + + // Blend 100 / 0 - Copy row unchanged. + LABELALIGN + "100: \n" + "movdqu " MEMACCESS(1) ",%%xmm0 \n" + MEMOPMEM(movdqu,xmm0,0x00,1,0,1) + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 100b \n" + + "99: \n" + : "+r"(dst_ptr), // %0 + "+r"(src_ptr), // %1 + "+r"(dst_width), // %2 + "+r"(source_y_fraction) // %3 + : "r"((intptr_t)(src_stride)) // %4 + : "memory", "cc", "eax", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_INTERPOLATEROW_SSSE3 + +#ifdef HAS_INTERPOLATEROW_AVX2 +// Bilinear filter 32x2 -> 32x1 +void InterpolateRow_AVX2(uint8* dst_ptr, const uint8* src_ptr, + ptrdiff_t src_stride, int dst_width, + int source_y_fraction) { + asm volatile ( + "cmp $0x0,%3 \n" + "je 100f \n" + "sub %1,%0 \n" + "cmp $0x80,%3 \n" + "je 50f \n" + + "vmovd %3,%%xmm0 \n" + "neg %3 \n" + "add $0x100,%3 \n" + "vmovd %3,%%xmm5 \n" + "vpunpcklbw %%xmm0,%%xmm5,%%xmm5 \n" + "vpunpcklwd %%xmm5,%%xmm5,%%xmm5 \n" + "vbroadcastss %%xmm5,%%ymm5 \n" + "mov $0x80808080,%%eax \n" + "vmovd %%eax,%%xmm4 \n" + "vbroadcastss %%xmm4,%%ymm4 \n" + + // General purpose row blend. + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(1) ",%%ymm0 \n" + MEMOPREG(vmovdqu,0x00,1,4,1,ymm2) + "vpunpckhbw %%ymm2,%%ymm0,%%ymm1 \n" + "vpunpcklbw %%ymm2,%%ymm0,%%ymm0 \n" + "vpsubb %%ymm4,%%ymm1,%%ymm1 \n" + "vpsubb %%ymm4,%%ymm0,%%ymm0 \n" + "vpmaddubsw %%ymm1,%%ymm5,%%ymm1 \n" + "vpmaddubsw %%ymm0,%%ymm5,%%ymm0 \n" + "vpaddw %%ymm4,%%ymm1,%%ymm1 \n" + "vpaddw %%ymm4,%%ymm0,%%ymm0 \n" + "vpsrlw $0x8,%%ymm1,%%ymm1 \n" + "vpsrlw $0x8,%%ymm0,%%ymm0 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + MEMOPMEM(vmovdqu,ymm0,0x00,1,0,1) + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x20,%2 \n" + "jg 1b \n" + "jmp 99f \n" + + // Blend 50 / 50. + LABELALIGN + "50: \n" + "vmovdqu " MEMACCESS(1) ",%%ymm0 \n" + VMEMOPREG(vpavgb,0x00,1,4,1,ymm0,ymm0) // vpavgb (%1,%4,1),%%ymm0,%%ymm0 + MEMOPMEM(vmovdqu,ymm0,0x00,1,0,1) + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x20,%2 \n" + "jg 50b \n" + "jmp 99f \n" + + // Blend 100 / 0 - Copy row unchanged. + LABELALIGN + "100: \n" + "rep movsb " MEMMOVESTRING(1,0) " \n" + "jmp 999f \n" + + "99: \n" + "vzeroupper \n" + "999: \n" + : "+D"(dst_ptr), // %0 + "+S"(src_ptr), // %1 + "+c"(dst_width), // %2 + "+r"(source_y_fraction) // %3 + : "r"((intptr_t)(src_stride)) // %4 + : "memory", "cc", "eax", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm4", "xmm5" + ); +} +#endif // HAS_INTERPOLATEROW_AVX2 + +#ifdef HAS_ARGBSHUFFLEROW_SSSE3 +// For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA. +void ARGBShuffleRow_SSSE3(const uint8* src_argb, uint8* dst_argb, + const uint8* shuffler, int width) { + asm volatile ( + "movdqu " MEMACCESS(3) ",%%xmm5 \n" + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "pshufb %%xmm5,%%xmm0 \n" + "pshufb %%xmm5,%%xmm1 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+r"(width) // %2 + : "r"(shuffler) // %3 + : "memory", "cc" + , "xmm0", "xmm1", "xmm5" + ); +} +#endif // HAS_ARGBSHUFFLEROW_SSSE3 + +#ifdef HAS_ARGBSHUFFLEROW_AVX2 +// For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA. +void ARGBShuffleRow_AVX2(const uint8* src_argb, uint8* dst_argb, + const uint8* shuffler, int width) { + asm volatile ( + "vbroadcastf128 " MEMACCESS(3) ",%%ymm5 \n" + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "vpshufb %%ymm5,%%ymm0,%%ymm0 \n" + "vpshufb %%ymm5,%%ymm1,%%ymm1 \n" + "vmovdqu %%ymm0," MEMACCESS(1) " \n" + "vmovdqu %%ymm1," MEMACCESS2(0x20,1) " \n" + "lea " MEMLEA(0x40,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+r"(width) // %2 + : "r"(shuffler) // %3 + : "memory", "cc" + , "xmm0", "xmm1", "xmm5" + ); +} +#endif // HAS_ARGBSHUFFLEROW_AVX2 + +#ifdef HAS_ARGBSHUFFLEROW_SSE2 +// For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA. +void ARGBShuffleRow_SSE2(const uint8* src_argb, uint8* dst_argb, + const uint8* shuffler, int width) { + uintptr_t pixel_temp = 0u; + asm volatile ( + "pxor %%xmm5,%%xmm5 \n" + "mov " MEMACCESS(4) ",%k2 \n" + "cmp $0x3000102,%k2 \n" + "je 3012f \n" + "cmp $0x10203,%k2 \n" + "je 123f \n" + "cmp $0x30201,%k2 \n" + "je 321f \n" + "cmp $0x2010003,%k2 \n" + "je 2103f \n" + + LABELALIGN + "1: \n" + "movzb " MEMACCESS(4) ",%2 \n" + MEMOPARG(movzb,0x00,0,2,1,2) " \n" // movzb (%0,%2,1),%2 + "mov %b2," MEMACCESS(1) " \n" + "movzb " MEMACCESS2(0x1,4) ",%2 \n" + MEMOPARG(movzb,0x00,0,2,1,2) " \n" // movzb (%0,%2,1),%2 + "mov %b2," MEMACCESS2(0x1,1) " \n" + "movzb " MEMACCESS2(0x2,4) ",%2 \n" + MEMOPARG(movzb,0x00,0,2,1,2) " \n" // movzb (%0,%2,1),%2 + "mov %b2," MEMACCESS2(0x2,1) " \n" + "movzb " MEMACCESS2(0x3,4) ",%2 \n" + MEMOPARG(movzb,0x00,0,2,1,2) " \n" // movzb (%0,%2,1),%2 + "mov %b2," MEMACCESS2(0x3,1) " \n" + "lea " MEMLEA(0x4,0) ",%0 \n" + "lea " MEMLEA(0x4,1) ",%1 \n" + "sub $0x1,%3 \n" + "jg 1b \n" + "jmp 99f \n" + + LABELALIGN + "123: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpcklbw %%xmm5,%%xmm0 \n" + "punpckhbw %%xmm5,%%xmm1 \n" + "pshufhw $0x1b,%%xmm0,%%xmm0 \n" + "pshuflw $0x1b,%%xmm0,%%xmm0 \n" + "pshufhw $0x1b,%%xmm1,%%xmm1 \n" + "pshuflw $0x1b,%%xmm1,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x4,%3 \n" + "jg 123b \n" + "jmp 99f \n" + + LABELALIGN + "321: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpcklbw %%xmm5,%%xmm0 \n" + "punpckhbw %%xmm5,%%xmm1 \n" + "pshufhw $0x39,%%xmm0,%%xmm0 \n" + "pshuflw $0x39,%%xmm0,%%xmm0 \n" + "pshufhw $0x39,%%xmm1,%%xmm1 \n" + "pshuflw $0x39,%%xmm1,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x4,%3 \n" + "jg 321b \n" + "jmp 99f \n" + + LABELALIGN + "2103: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpcklbw %%xmm5,%%xmm0 \n" + "punpckhbw %%xmm5,%%xmm1 \n" + "pshufhw $0x93,%%xmm0,%%xmm0 \n" + "pshuflw $0x93,%%xmm0,%%xmm0 \n" + "pshufhw $0x93,%%xmm1,%%xmm1 \n" + "pshuflw $0x93,%%xmm1,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x4,%3 \n" + "jg 2103b \n" + "jmp 99f \n" + + LABELALIGN + "3012: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpcklbw %%xmm5,%%xmm0 \n" + "punpckhbw %%xmm5,%%xmm1 \n" + "pshufhw $0xc6,%%xmm0,%%xmm0 \n" + "pshuflw $0xc6,%%xmm0,%%xmm0 \n" + "pshufhw $0xc6,%%xmm1,%%xmm1 \n" + "pshuflw $0xc6,%%xmm1,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x4,%3 \n" + "jg 3012b \n" + + "99: \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+d"(pixel_temp), // %2 + "+r"(width) // %3 + : "r"(shuffler) // %4 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm5" + ); +} +#endif // HAS_ARGBSHUFFLEROW_SSE2 + +#ifdef HAS_I422TOYUY2ROW_SSE2 +void I422ToYUY2Row_SSE2(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_frame, int width) { + asm volatile ( + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movq " MEMACCESS(1) ",%%xmm2 \n" + MEMOPREG(movq,0x00,1,2,1,xmm3) // movq (%1,%2,1),%%xmm3 + "lea " MEMLEA(0x8,1) ",%1 \n" + "punpcklbw %%xmm3,%%xmm2 \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpcklbw %%xmm2,%%xmm0 \n" + "punpckhbw %%xmm2,%%xmm1 \n" + "movdqu %%xmm0," MEMACCESS(3) " \n" + "movdqu %%xmm1," MEMACCESS2(0x10,3) " \n" + "lea " MEMLEA(0x20,3) ",%3 \n" + "sub $0x10,%4 \n" + "jg 1b \n" + : "+r"(src_y), // %0 + "+r"(src_u), // %1 + "+r"(src_v), // %2 + "+r"(dst_frame), // %3 + "+rm"(width) // %4 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3" + ); +} +#endif // HAS_I422TOYUY2ROW_SSE2 + +#ifdef HAS_I422TOUYVYROW_SSE2 +void I422ToUYVYRow_SSE2(const uint8* src_y, + const uint8* src_u, + const uint8* src_v, + uint8* dst_frame, int width) { + asm volatile ( + "sub %1,%2 \n" + LABELALIGN + "1: \n" + "movq " MEMACCESS(1) ",%%xmm2 \n" + MEMOPREG(movq,0x00,1,2,1,xmm3) // movq (%1,%2,1),%%xmm3 + "lea " MEMLEA(0x8,1) ",%1 \n" + "punpcklbw %%xmm3,%%xmm2 \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqa %%xmm2,%%xmm1 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" + "punpcklbw %%xmm0,%%xmm1 \n" + "punpckhbw %%xmm0,%%xmm2 \n" + "movdqu %%xmm1," MEMACCESS(3) " \n" + "movdqu %%xmm2," MEMACCESS2(0x10,3) " \n" + "lea " MEMLEA(0x20,3) ",%3 \n" + "sub $0x10,%4 \n" + "jg 1b \n" + : "+r"(src_y), // %0 + "+r"(src_u), // %1 + "+r"(src_v), // %2 + "+r"(dst_frame), // %3 + "+rm"(width) // %4 + : + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3" + ); +} +#endif // HAS_I422TOUYVYROW_SSE2 + +#ifdef HAS_ARGBPOLYNOMIALROW_SSE2 +void ARGBPolynomialRow_SSE2(const uint8* src_argb, + uint8* dst_argb, const float* poly, + int width) { + asm volatile ( + "pxor %%xmm3,%%xmm3 \n" + + // 2 pixel loop. + LABELALIGN + "1: \n" + "movq " MEMACCESS(0) ",%%xmm0 \n" + "lea " MEMLEA(0x8,0) ",%0 \n" + "punpcklbw %%xmm3,%%xmm0 \n" + "movdqa %%xmm0,%%xmm4 \n" + "punpcklwd %%xmm3,%%xmm0 \n" + "punpckhwd %%xmm3,%%xmm4 \n" + "cvtdq2ps %%xmm0,%%xmm0 \n" + "cvtdq2ps %%xmm4,%%xmm4 \n" + "movdqa %%xmm0,%%xmm1 \n" + "movdqa %%xmm4,%%xmm5 \n" + "mulps " MEMACCESS2(0x10,3) ",%%xmm0 \n" + "mulps " MEMACCESS2(0x10,3) ",%%xmm4 \n" + "addps " MEMACCESS(3) ",%%xmm0 \n" + "addps " MEMACCESS(3) ",%%xmm4 \n" + "movdqa %%xmm1,%%xmm2 \n" + "movdqa %%xmm5,%%xmm6 \n" + "mulps %%xmm1,%%xmm2 \n" + "mulps %%xmm5,%%xmm6 \n" + "mulps %%xmm2,%%xmm1 \n" + "mulps %%xmm6,%%xmm5 \n" + "mulps " MEMACCESS2(0x20,3) ",%%xmm2 \n" + "mulps " MEMACCESS2(0x20,3) ",%%xmm6 \n" + "mulps " MEMACCESS2(0x30,3) ",%%xmm1 \n" + "mulps " MEMACCESS2(0x30,3) ",%%xmm5 \n" + "addps %%xmm2,%%xmm0 \n" + "addps %%xmm6,%%xmm4 \n" + "addps %%xmm1,%%xmm0 \n" + "addps %%xmm5,%%xmm4 \n" + "cvttps2dq %%xmm0,%%xmm0 \n" + "cvttps2dq %%xmm4,%%xmm4 \n" + "packuswb %%xmm4,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movq %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x2,%2 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+r"(width) // %2 + : "r"(poly) // %3 + : "memory", "cc" + , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" + ); +} +#endif // HAS_ARGBPOLYNOMIALROW_SSE2 + +#ifdef HAS_ARGBPOLYNOMIALROW_AVX2 +void ARGBPolynomialRow_AVX2(const uint8* src_argb, + uint8* dst_argb, const float* poly, + int width) { + asm volatile ( + "vbroadcastf128 " MEMACCESS(3) ",%%ymm4 \n" + "vbroadcastf128 " MEMACCESS2(0x10,3) ",%%ymm5 \n" + "vbroadcastf128 " MEMACCESS2(0x20,3) ",%%ymm6 \n" + "vbroadcastf128 " MEMACCESS2(0x30,3) ",%%ymm7 \n" + + // 2 pixel loop. + LABELALIGN + "1: \n" + "vpmovzxbd " MEMACCESS(0) ",%%ymm0 \n" // 2 ARGB pixels + "lea " MEMLEA(0x8,0) ",%0 \n" + "vcvtdq2ps %%ymm0,%%ymm0 \n" // X 8 floats + "vmulps %%ymm0,%%ymm0,%%ymm2 \n" // X * X + "vmulps %%ymm7,%%ymm0,%%ymm3 \n" // C3 * X + "vfmadd132ps %%ymm5,%%ymm4,%%ymm0 \n" // result = C0 + C1 * X + "vfmadd231ps %%ymm6,%%ymm2,%%ymm0 \n" // result += C2 * X * X + "vfmadd231ps %%ymm3,%%ymm2,%%ymm0 \n" // result += C3 * X * X * X + "vcvttps2dq %%ymm0,%%ymm0 \n" + "vpackusdw %%ymm0,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vpackuswb %%xmm0,%%xmm0,%%xmm0 \n" + "vmovq %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x2,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+r"(width) // %2 + : "r"(poly) // %3 + : "memory", "cc", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} +#endif // HAS_ARGBPOLYNOMIALROW_AVX2 + +#ifdef HAS_ARGBCOLORTABLEROW_X86 +// Tranform ARGB pixels with color table. +void ARGBColorTableRow_X86(uint8* dst_argb, const uint8* table_argb, + int width) { + uintptr_t pixel_temp = 0u; + asm volatile ( + // 1 pixel loop. + LABELALIGN + "1: \n" + "movzb " MEMACCESS(0) ",%1 \n" + "lea " MEMLEA(0x4,0) ",%0 \n" + MEMOPARG(movzb,0x00,3,1,4,1) " \n" // movzb (%3,%1,4),%1 + "mov %b1," MEMACCESS2(-0x4,0) " \n" + "movzb " MEMACCESS2(-0x3,0) ",%1 \n" + MEMOPARG(movzb,0x01,3,1,4,1) " \n" // movzb 0x1(%3,%1,4),%1 + "mov %b1," MEMACCESS2(-0x3,0) " \n" + "movzb " MEMACCESS2(-0x2,0) ",%1 \n" + MEMOPARG(movzb,0x02,3,1,4,1) " \n" // movzb 0x2(%3,%1,4),%1 + "mov %b1," MEMACCESS2(-0x2,0) " \n" + "movzb " MEMACCESS2(-0x1,0) ",%1 \n" + MEMOPARG(movzb,0x03,3,1,4,1) " \n" // movzb 0x3(%3,%1,4),%1 + "mov %b1," MEMACCESS2(-0x1,0) " \n" + "dec %2 \n" + "jg 1b \n" + : "+r"(dst_argb), // %0 + "+d"(pixel_temp), // %1 + "+r"(width) // %2 + : "r"(table_argb) // %3 + : "memory", "cc"); +} +#endif // HAS_ARGBCOLORTABLEROW_X86 + +#ifdef HAS_RGBCOLORTABLEROW_X86 +// Tranform RGB pixels with color table. +void RGBColorTableRow_X86(uint8* dst_argb, const uint8* table_argb, int width) { + uintptr_t pixel_temp = 0u; + asm volatile ( + // 1 pixel loop. + LABELALIGN + "1: \n" + "movzb " MEMACCESS(0) ",%1 \n" + "lea " MEMLEA(0x4,0) ",%0 \n" + MEMOPARG(movzb,0x00,3,1,4,1) " \n" // movzb (%3,%1,4),%1 + "mov %b1," MEMACCESS2(-0x4,0) " \n" + "movzb " MEMACCESS2(-0x3,0) ",%1 \n" + MEMOPARG(movzb,0x01,3,1,4,1) " \n" // movzb 0x1(%3,%1,4),%1 + "mov %b1," MEMACCESS2(-0x3,0) " \n" + "movzb " MEMACCESS2(-0x2,0) ",%1 \n" + MEMOPARG(movzb,0x02,3,1,4,1) " \n" // movzb 0x2(%3,%1,4),%1 + "mov %b1," MEMACCESS2(-0x2,0) " \n" + "dec %2 \n" + "jg 1b \n" + : "+r"(dst_argb), // %0 + "+d"(pixel_temp), // %1 + "+r"(width) // %2 + : "r"(table_argb) // %3 + : "memory", "cc"); +} +#endif // HAS_RGBCOLORTABLEROW_X86 + +#ifdef HAS_ARGBLUMACOLORTABLEROW_SSSE3 +// Tranform RGB pixels with luma table. +void ARGBLumaColorTableRow_SSSE3(const uint8* src_argb, uint8* dst_argb, + int width, + const uint8* luma, uint32 lumacoeff) { + uintptr_t pixel_temp = 0u; + uintptr_t table_temp = 0u; + asm volatile ( + "movd %6,%%xmm3 \n" + "pshufd $0x0,%%xmm3,%%xmm3 \n" + "pcmpeqb %%xmm4,%%xmm4 \n" + "psllw $0x8,%%xmm4 \n" + "pxor %%xmm5,%%xmm5 \n" + + // 4 pixel loop. + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(2) ",%%xmm0 \n" + "pmaddubsw %%xmm3,%%xmm0 \n" + "phaddw %%xmm0,%%xmm0 \n" + "pand %%xmm4,%%xmm0 \n" + "punpcklwd %%xmm5,%%xmm0 \n" + "movd %%xmm0,%k1 \n" // 32 bit offset + "add %5,%1 \n" + "pshufd $0x39,%%xmm0,%%xmm0 \n" + + "movzb " MEMACCESS(2) ",%0 \n" + MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 + "mov %b0," MEMACCESS(3) " \n" + "movzb " MEMACCESS2(0x1,2) ",%0 \n" + MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 + "mov %b0," MEMACCESS2(0x1,3) " \n" + "movzb " MEMACCESS2(0x2,2) ",%0 \n" + MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 + "mov %b0," MEMACCESS2(0x2,3) " \n" + "movzb " MEMACCESS2(0x3,2) ",%0 \n" + "mov %b0," MEMACCESS2(0x3,3) " \n" + + "movd %%xmm0,%k1 \n" // 32 bit offset + "add %5,%1 \n" + "pshufd $0x39,%%xmm0,%%xmm0 \n" + + "movzb " MEMACCESS2(0x4,2) ",%0 \n" + MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 + "mov %b0," MEMACCESS2(0x4,3) " \n" + "movzb " MEMACCESS2(0x5,2) ",%0 \n" + MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 + "mov %b0," MEMACCESS2(0x5,3) " \n" + "movzb " MEMACCESS2(0x6,2) ",%0 \n" + MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 + "mov %b0," MEMACCESS2(0x6,3) " \n" + "movzb " MEMACCESS2(0x7,2) ",%0 \n" + "mov %b0," MEMACCESS2(0x7,3) " \n" + + "movd %%xmm0,%k1 \n" // 32 bit offset + "add %5,%1 \n" + "pshufd $0x39,%%xmm0,%%xmm0 \n" + + "movzb " MEMACCESS2(0x8,2) ",%0 \n" + MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 + "mov %b0," MEMACCESS2(0x8,3) " \n" + "movzb " MEMACCESS2(0x9,2) ",%0 \n" + MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 + "mov %b0," MEMACCESS2(0x9,3) " \n" + "movzb " MEMACCESS2(0xa,2) ",%0 \n" + MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 + "mov %b0," MEMACCESS2(0xa,3) " \n" + "movzb " MEMACCESS2(0xb,2) ",%0 \n" + "mov %b0," MEMACCESS2(0xb,3) " \n" + + "movd %%xmm0,%k1 \n" // 32 bit offset + "add %5,%1 \n" + + "movzb " MEMACCESS2(0xc,2) ",%0 \n" + MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 + "mov %b0," MEMACCESS2(0xc,3) " \n" + "movzb " MEMACCESS2(0xd,2) ",%0 \n" + MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 + "mov %b0," MEMACCESS2(0xd,3) " \n" + "movzb " MEMACCESS2(0xe,2) ",%0 \n" + MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0 + "mov %b0," MEMACCESS2(0xe,3) " \n" + "movzb " MEMACCESS2(0xf,2) ",%0 \n" + "mov %b0," MEMACCESS2(0xf,3) " \n" + "lea " MEMLEA(0x10,2) ",%2 \n" + "lea " MEMLEA(0x10,3) ",%3 \n" + "sub $0x4,%4 \n" + "jg 1b \n" + : "+d"(pixel_temp), // %0 + "+a"(table_temp), // %1 + "+r"(src_argb), // %2 + "+r"(dst_argb), // %3 + "+rm"(width) // %4 + : "r"(luma), // %5 + "rm"(lumacoeff) // %6 + : "memory", "cc", "xmm0", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_ARGBLUMACOLORTABLEROW_SSSE3 + +#endif // defined(__x86_64__) || defined(__i386__) + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif diff --git a/TMessagesProj/jni/libyuv/source/scale_any.cc b/TMessagesProj/jni/libyuv/source/scale_any.cc new file mode 100644 index 00000000..1da4dacd --- /dev/null +++ b/TMessagesProj/jni/libyuv/source/scale_any.cc @@ -0,0 +1,200 @@ +/* + * Copyright 2015 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "libyuv/scale.h" +#include "libyuv/scale_row.h" + +#include "libyuv/basic_types.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// Definition for ScaleFilterCols, ScaleARGBCols and ScaleARGBFilterCols +#define CANY(NAMEANY, TERP_SIMD, TERP_C, BPP, MASK) \ + void NAMEANY(uint8* dst_ptr, const uint8* src_ptr, \ + int dst_width, int x, int dx) { \ + int n = dst_width & ~MASK; \ + if (n > 0) { \ + TERP_SIMD(dst_ptr, src_ptr, n, x, dx); \ + } \ + TERP_C(dst_ptr + n * BPP, src_ptr, \ + dst_width & MASK, x + n * dx, dx); \ + } + +#ifdef HAS_SCALEFILTERCOLS_NEON +CANY(ScaleFilterCols_Any_NEON, ScaleFilterCols_NEON, ScaleFilterCols_C, 1, 7) +#endif +#ifdef HAS_SCALEARGBCOLS_NEON +CANY(ScaleARGBCols_Any_NEON, ScaleARGBCols_NEON, ScaleARGBCols_C, 4, 7) +#endif +#ifdef HAS_SCALEARGBFILTERCOLS_NEON +CANY(ScaleARGBFilterCols_Any_NEON, ScaleARGBFilterCols_NEON, + ScaleARGBFilterCols_C, 4, 3) +#endif +#undef CANY + +// Fixed scale down. +#define SDANY(NAMEANY, SCALEROWDOWN_SIMD, SCALEROWDOWN_C, FACTOR, BPP, MASK) \ + void NAMEANY(const uint8* src_ptr, ptrdiff_t src_stride, \ + uint8* dst_ptr, int dst_width) { \ + int r = (int)((unsigned int)dst_width % (MASK + 1)); \ + int n = dst_width - r; \ + if (n > 0) { \ + SCALEROWDOWN_SIMD(src_ptr, src_stride, dst_ptr, n); \ + } \ + SCALEROWDOWN_C(src_ptr + (n * FACTOR) * BPP, src_stride, \ + dst_ptr + n * BPP, r); \ + } + +#ifdef HAS_SCALEROWDOWN2_SSSE3 +SDANY(ScaleRowDown2_Any_SSSE3, ScaleRowDown2_SSSE3, ScaleRowDown2_C, 2, 1, 15) +SDANY(ScaleRowDown2Linear_Any_SSSE3, ScaleRowDown2Linear_SSSE3, + ScaleRowDown2Linear_C, 2, 1, 15) +SDANY(ScaleRowDown2Box_Any_SSSE3, ScaleRowDown2Box_SSSE3, ScaleRowDown2Box_C, + 2, 1, 15) +#endif +#ifdef HAS_SCALEROWDOWN2_AVX2 +SDANY(ScaleRowDown2_Any_AVX2, ScaleRowDown2_AVX2, ScaleRowDown2_C, 2, 1, 31) +SDANY(ScaleRowDown2Linear_Any_AVX2, ScaleRowDown2Linear_AVX2, + ScaleRowDown2Linear_C, 2, 1, 31) +SDANY(ScaleRowDown2Box_Any_AVX2, ScaleRowDown2Box_AVX2, ScaleRowDown2Box_C, + 2, 1, 31) +#endif +#ifdef HAS_SCALEROWDOWN2_NEON +SDANY(ScaleRowDown2_Any_NEON, ScaleRowDown2_NEON, ScaleRowDown2_C, 2, 1, 15) +SDANY(ScaleRowDown2Linear_Any_NEON, ScaleRowDown2Linear_NEON, + ScaleRowDown2Linear_C, 2, 1, 15) +SDANY(ScaleRowDown2Box_Any_NEON, ScaleRowDown2Box_NEON, + ScaleRowDown2Box_C, 2, 1, 15) +#endif +#ifdef HAS_SCALEROWDOWN4_SSSE3 +SDANY(ScaleRowDown4_Any_SSSE3, ScaleRowDown4_SSSE3, ScaleRowDown4_C, 4, 1, 7) +SDANY(ScaleRowDown4Box_Any_SSSE3, ScaleRowDown4Box_SSSE3, ScaleRowDown4Box_C, + 4, 1, 7) +#endif +#ifdef HAS_SCALEROWDOWN4_AVX2 +SDANY(ScaleRowDown4_Any_AVX2, ScaleRowDown4_AVX2, ScaleRowDown4_C, 4, 1, 15) +SDANY(ScaleRowDown4Box_Any_AVX2, ScaleRowDown4Box_AVX2, ScaleRowDown4Box_C, + 4, 1, 15) +#endif +#ifdef HAS_SCALEROWDOWN4_NEON +SDANY(ScaleRowDown4_Any_NEON, ScaleRowDown4_NEON, ScaleRowDown4_C, 4, 1, 7) +SDANY(ScaleRowDown4Box_Any_NEON, ScaleRowDown4Box_NEON, ScaleRowDown4Box_C, + 4, 1, 7) +#endif +#ifdef HAS_SCALEROWDOWN34_SSSE3 +SDANY(ScaleRowDown34_Any_SSSE3, ScaleRowDown34_SSSE3, + ScaleRowDown34_C, 4 / 3, 1, 23) +SDANY(ScaleRowDown34_0_Box_Any_SSSE3, ScaleRowDown34_0_Box_SSSE3, + ScaleRowDown34_0_Box_C, 4 / 3, 1, 23) +SDANY(ScaleRowDown34_1_Box_Any_SSSE3, ScaleRowDown34_1_Box_SSSE3, + ScaleRowDown34_1_Box_C, 4 / 3, 1, 23) +#endif +#ifdef HAS_SCALEROWDOWN34_NEON +SDANY(ScaleRowDown34_Any_NEON, ScaleRowDown34_NEON, + ScaleRowDown34_C, 4 / 3, 1, 23) +SDANY(ScaleRowDown34_0_Box_Any_NEON, ScaleRowDown34_0_Box_NEON, + ScaleRowDown34_0_Box_C, 4 / 3, 1, 23) +SDANY(ScaleRowDown34_1_Box_Any_NEON, ScaleRowDown34_1_Box_NEON, + ScaleRowDown34_1_Box_C, 4 / 3, 1, 23) +#endif +#ifdef HAS_SCALEROWDOWN38_SSSE3 +SDANY(ScaleRowDown38_Any_SSSE3, ScaleRowDown38_SSSE3, + ScaleRowDown38_C, 8 / 3, 1, 11) +SDANY(ScaleRowDown38_3_Box_Any_SSSE3, ScaleRowDown38_3_Box_SSSE3, + ScaleRowDown38_3_Box_C, 8 / 3, 1, 5) +SDANY(ScaleRowDown38_2_Box_Any_SSSE3, ScaleRowDown38_2_Box_SSSE3, + ScaleRowDown38_2_Box_C, 8 / 3, 1, 5) +#endif +#ifdef HAS_SCALEROWDOWN38_NEON +SDANY(ScaleRowDown38_Any_NEON, ScaleRowDown38_NEON, + ScaleRowDown38_C, 8 / 3, 1, 11) +SDANY(ScaleRowDown38_3_Box_Any_NEON, ScaleRowDown38_3_Box_NEON, + ScaleRowDown38_3_Box_C, 8 / 3, 1, 11) +SDANY(ScaleRowDown38_2_Box_Any_NEON, ScaleRowDown38_2_Box_NEON, + ScaleRowDown38_2_Box_C, 8 / 3, 1, 11) +#endif + +#ifdef HAS_SCALEARGBROWDOWN2_SSE2 +SDANY(ScaleARGBRowDown2_Any_SSE2, ScaleARGBRowDown2_SSE2, + ScaleARGBRowDown2_C, 2, 4, 3) +SDANY(ScaleARGBRowDown2Linear_Any_SSE2, ScaleARGBRowDown2Linear_SSE2, + ScaleARGBRowDown2Linear_C, 2, 4, 3) +SDANY(ScaleARGBRowDown2Box_Any_SSE2, ScaleARGBRowDown2Box_SSE2, + ScaleARGBRowDown2Box_C, 2, 4, 3) +#endif +#ifdef HAS_SCALEARGBROWDOWN2_NEON +SDANY(ScaleARGBRowDown2_Any_NEON, ScaleARGBRowDown2_NEON, + ScaleARGBRowDown2_C, 2, 4, 7) +SDANY(ScaleARGBRowDown2Linear_Any_NEON, ScaleARGBRowDown2Linear_NEON, + ScaleARGBRowDown2Linear_C, 2, 4, 7) +SDANY(ScaleARGBRowDown2Box_Any_NEON, ScaleARGBRowDown2Box_NEON, + ScaleARGBRowDown2Box_C, 2, 4, 7) +#endif +#undef SDANY + +// Scale down by even scale factor. +#define SDAANY(NAMEANY, SCALEROWDOWN_SIMD, SCALEROWDOWN_C, BPP, MASK) \ + void NAMEANY(const uint8* src_ptr, ptrdiff_t src_stride, int src_stepx, \ + uint8* dst_ptr, int dst_width) { \ + int r = (int)((unsigned int)dst_width % (MASK + 1)); \ + int n = dst_width - r; \ + if (n > 0) { \ + SCALEROWDOWN_SIMD(src_ptr, src_stride, src_stepx, dst_ptr, n); \ + } \ + SCALEROWDOWN_C(src_ptr + (n * src_stepx) * BPP, src_stride, \ + src_stepx, dst_ptr + n * BPP, r); \ + } + +#ifdef HAS_SCALEARGBROWDOWNEVEN_SSE2 +SDAANY(ScaleARGBRowDownEven_Any_SSE2, ScaleARGBRowDownEven_SSE2, + ScaleARGBRowDownEven_C, 4, 3) +SDAANY(ScaleARGBRowDownEvenBox_Any_SSE2, ScaleARGBRowDownEvenBox_SSE2, + ScaleARGBRowDownEvenBox_C, 4, 3) +#endif +#ifdef HAS_SCALEARGBROWDOWNEVEN_NEON +SDAANY(ScaleARGBRowDownEven_Any_NEON, ScaleARGBRowDownEven_NEON, + ScaleARGBRowDownEven_C, 4, 3) +SDAANY(ScaleARGBRowDownEvenBox_Any_NEON, ScaleARGBRowDownEvenBox_NEON, + ScaleARGBRowDownEvenBox_C, 4, 3) +#endif + +// Add rows box filter scale down. +#define SAANY(NAMEANY, SCALEADDROW_SIMD, SCALEADDROW_C, MASK) \ + void NAMEANY(const uint8* src_ptr, uint16* dst_ptr, int src_width) { \ + int n = src_width & ~MASK; \ + if (n > 0) { \ + SCALEADDROW_SIMD(src_ptr, dst_ptr, n); \ + } \ + SCALEADDROW_C(src_ptr + n, dst_ptr + n, src_width & MASK); \ + } + +#ifdef HAS_SCALEADDROW_SSE2 +SAANY(ScaleAddRow_Any_SSE2, ScaleAddRow_SSE2, ScaleAddRow_C, 15) +#endif +#ifdef HAS_SCALEADDROW_AVX2 +SAANY(ScaleAddRow_Any_AVX2, ScaleAddRow_AVX2, ScaleAddRow_C, 31) +#endif +#ifdef HAS_SCALEADDROW_NEON +SAANY(ScaleAddRow_Any_NEON, ScaleAddRow_NEON, ScaleAddRow_C, 15) +#endif +#undef SAANY + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif + + + + + diff --git a/TMessagesProj/jni/libyuv/source/scale_gcc.cc b/TMessagesProj/jni/libyuv/source/scale_gcc.cc new file mode 100644 index 00000000..a1ae4e27 --- /dev/null +++ b/TMessagesProj/jni/libyuv/source/scale_gcc.cc @@ -0,0 +1,1292 @@ +/* + * Copyright 2013 The LibYuv Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "libyuv/row.h" +#include "libyuv/scale_row.h" + +#ifdef __cplusplus +namespace libyuv { +extern "C" { +#endif + +// This module is for GCC x86 and x64. +#if !defined(LIBYUV_DISABLE_X86) && \ + (defined(__x86_64__) || (defined(__i386__) && !defined(_MSC_VER))) + +// Offsets for source bytes 0 to 9 +static uvec8 kShuf0 = + { 0, 1, 3, 4, 5, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 128 }; + +// Offsets for source bytes 11 to 20 with 8 subtracted = 3 to 12. +static uvec8 kShuf1 = + { 3, 4, 5, 7, 8, 9, 11, 12, 128, 128, 128, 128, 128, 128, 128, 128 }; + +// Offsets for source bytes 21 to 31 with 16 subtracted = 5 to 31. +static uvec8 kShuf2 = + { 5, 7, 8, 9, 11, 12, 13, 15, 128, 128, 128, 128, 128, 128, 128, 128 }; + +// Offsets for source bytes 0 to 10 +static uvec8 kShuf01 = + { 0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10 }; + +// Offsets for source bytes 10 to 21 with 8 subtracted = 3 to 13. +static uvec8 kShuf11 = + { 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10, 10, 11, 12, 13 }; + +// Offsets for source bytes 21 to 31 with 16 subtracted = 5 to 31. +static uvec8 kShuf21 = + { 5, 6, 6, 7, 8, 9, 9, 10, 10, 11, 12, 13, 13, 14, 14, 15 }; + +// Coefficients for source bytes 0 to 10 +static uvec8 kMadd01 = + { 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2 }; + +// Coefficients for source bytes 10 to 21 +static uvec8 kMadd11 = + { 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1 }; + +// Coefficients for source bytes 21 to 31 +static uvec8 kMadd21 = + { 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3 }; + +// Coefficients for source bytes 21 to 31 +static vec16 kRound34 = + { 2, 2, 2, 2, 2, 2, 2, 2 }; + +static uvec8 kShuf38a = + { 0, 3, 6, 8, 11, 14, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }; + +static uvec8 kShuf38b = + { 128, 128, 128, 128, 128, 128, 0, 3, 6, 8, 11, 14, 128, 128, 128, 128 }; + +// Arrange words 0,3,6 into 0,1,2 +static uvec8 kShufAc = + { 0, 1, 6, 7, 12, 13, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }; + +// Arrange words 0,3,6 into 3,4,5 +static uvec8 kShufAc3 = + { 128, 128, 128, 128, 128, 128, 0, 1, 6, 7, 12, 13, 128, 128, 128, 128 }; + +// Scaling values for boxes of 3x3 and 2x3 +static uvec16 kScaleAc33 = + { 65536 / 9, 65536 / 9, 65536 / 6, 65536 / 9, 65536 / 9, 65536 / 6, 0, 0 }; + +// Arrange first value for pixels 0,1,2,3,4,5 +static uvec8 kShufAb0 = + { 0, 128, 3, 128, 6, 128, 8, 128, 11, 128, 14, 128, 128, 128, 128, 128 }; + +// Arrange second value for pixels 0,1,2,3,4,5 +static uvec8 kShufAb1 = + { 1, 128, 4, 128, 7, 128, 9, 128, 12, 128, 15, 128, 128, 128, 128, 128 }; + +// Arrange third value for pixels 0,1,2,3,4,5 +static uvec8 kShufAb2 = + { 2, 128, 5, 128, 128, 128, 10, 128, 13, 128, 128, 128, 128, 128, 128, 128 }; + +// Scaling values for boxes of 3x2 and 2x2 +static uvec16 kScaleAb2 = + { 65536 / 3, 65536 / 3, 65536 / 2, 65536 / 3, 65536 / 3, 65536 / 2, 0, 0 }; + +// GCC versions of row functions are verbatim conversions from Visual C. +// Generated using gcc disassembly on Visual C object file: +// objdump -D yuvscaler.obj >yuvscaler.txt + +void ScaleRowDown2_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "psrlw $0x8,%%xmm0 \n" + "psrlw $0x8,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + :: "memory", "cc", "xmm0", "xmm1" + ); +} + +void ScaleRowDown2Linear_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "pcmpeqb %%xmm4,%%xmm4 \n" + "psrlw $0xf,%%xmm4 \n" + "packuswb %%xmm4,%%xmm4 \n" + "pxor %%xmm5,%%xmm5 \n" + + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10, 0) ",%%xmm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm1 \n" + "pavgw %%xmm5,%%xmm0 \n" + "pavgw %%xmm5,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + :: "memory", "cc", "xmm0", "xmm1", "xmm4", "xmm5" + ); +} + +void ScaleRowDown2Box_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "pcmpeqb %%xmm4,%%xmm4 \n" + "psrlw $0xf,%%xmm4 \n" + "packuswb %%xmm4,%%xmm4 \n" + "pxor %%xmm5,%%xmm5 \n" + + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + MEMOPREG(movdqu,0x00,0,3,1,xmm2) // movdqu (%0,%3,1),%%xmm2 + MEMOPREG(movdqu,0x10,0,3,1,xmm3) // movdqu 0x10(%0,%3,1),%%xmm3 + "lea " MEMLEA(0x20,0) ",%0 \n" + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm1 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm4,%%xmm3 \n" + "paddw %%xmm2,%%xmm0 \n" + "paddw %%xmm3,%%xmm1 \n" + "psrlw $0x1,%%xmm0 \n" + "psrlw $0x1,%%xmm1 \n" + "pavgw %%xmm5,%%xmm0 \n" + "pavgw %%xmm5,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)) // %3 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" + ); +} + +#ifdef HAS_SCALEROWDOWN2_AVX2 +void ScaleRowDown2_AVX2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "vpsrlw $0x8,%%ymm0,%%ymm0 \n" + "vpsrlw $0x8,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vmovdqu %%ymm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x20,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + :: "memory", "cc", "xmm0", "xmm1" + ); +} + +void ScaleRowDown2Linear_AVX2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "vpcmpeqb %%ymm4,%%ymm4,%%ymm4 \n" + "vpsrlw $0xf,%%ymm4,%%ymm4 \n" + "vpackuswb %%ymm4,%%ymm4,%%ymm4 \n" + "vpxor %%ymm5,%%ymm5,%%ymm5 \n" + + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20, 0) ",%%ymm1 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" + "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" + "vpavgw %%ymm5,%%ymm0,%%ymm0 \n" + "vpavgw %%ymm5,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vmovdqu %%ymm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x20,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + :: "memory", "cc", "xmm0", "xmm1", "xmm4", "xmm5" + ); +} + +void ScaleRowDown2Box_AVX2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "vpcmpeqb %%ymm4,%%ymm4,%%ymm4 \n" + "vpsrlw $0xf,%%ymm4,%%ymm4 \n" + "vpackuswb %%ymm4,%%ymm4,%%ymm4 \n" + "vpxor %%ymm5,%%ymm5,%%ymm5 \n" + + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + MEMOPREG(vmovdqu,0x00,0,3,1,ymm2) // vmovdqu (%0,%3,1),%%ymm2 + MEMOPREG(vmovdqu,0x20,0,3,1,ymm3) // vmovdqu 0x20(%0,%3,1),%%ymm3 + "lea " MEMLEA(0x40,0) ",%0 \n" + "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" + "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" + "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" + "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" + "vpaddw %%ymm2,%%ymm0,%%ymm0 \n" + "vpaddw %%ymm3,%%ymm1,%%ymm1 \n" + "vpsrlw $0x1,%%ymm0,%%ymm0 \n" + "vpsrlw $0x1,%%ymm1,%%ymm1 \n" + "vpavgw %%ymm5,%%ymm0,%%ymm0 \n" + "vpavgw %%ymm5,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vmovdqu %%ymm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x20,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)) // %3 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" + ); +} +#endif // HAS_SCALEROWDOWN2_AVX2 + +void ScaleRowDown4_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "pcmpeqb %%xmm5,%%xmm5 \n" + "psrld $0x18,%%xmm5 \n" + "pslld $0x10,%%xmm5 \n" + + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "pand %%xmm5,%%xmm0 \n" + "pand %%xmm5,%%xmm1 \n" + "packuswb %%xmm1,%%xmm0 \n" + "psrlw $0x8,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movq %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + :: "memory", "cc", "xmm0", "xmm1", "xmm5" + ); +} + +void ScaleRowDown4Box_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + intptr_t stridex3 = 0; + asm volatile ( + "pcmpeqb %%xmm4,%%xmm4 \n" + "psrlw $0xf,%%xmm4 \n" + "movdqa %%xmm4,%%xmm5 \n" + "packuswb %%xmm4,%%xmm4 \n" + "psllw $0x3,%%xmm5 \n" + "lea " MEMLEA4(0x00,4,4,2) ",%3 \n" + + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + MEMOPREG(movdqu,0x00,0,4,1,xmm2) // movdqu (%0,%4,1),%%xmm2 + MEMOPREG(movdqu,0x10,0,4,1,xmm3) // movdqu 0x10(%0,%4,1),%%xmm3 + "pmaddubsw %%xmm4,%%xmm0 \n" + "pmaddubsw %%xmm4,%%xmm1 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm4,%%xmm3 \n" + "paddw %%xmm2,%%xmm0 \n" + "paddw %%xmm3,%%xmm1 \n" + MEMOPREG(movdqu,0x00,0,4,2,xmm2) // movdqu (%0,%4,2),%%xmm2 + MEMOPREG(movdqu,0x10,0,4,2,xmm3) // movdqu 0x10(%0,%4,2),%%xmm3 + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm4,%%xmm3 \n" + "paddw %%xmm2,%%xmm0 \n" + "paddw %%xmm3,%%xmm1 \n" + MEMOPREG(movdqu,0x00,0,3,1,xmm2) // movdqu (%0,%3,1),%%xmm2 + MEMOPREG(movdqu,0x10,0,3,1,xmm3) // movdqu 0x10(%0,%3,1),%%xmm3 + "lea " MEMLEA(0x20,0) ",%0 \n" + "pmaddubsw %%xmm4,%%xmm2 \n" + "pmaddubsw %%xmm4,%%xmm3 \n" + "paddw %%xmm2,%%xmm0 \n" + "paddw %%xmm3,%%xmm1 \n" + "phaddw %%xmm1,%%xmm0 \n" + "paddw %%xmm5,%%xmm0 \n" + "psrlw $0x4,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movq %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x8,1) ",%1 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width), // %2 + "+r"(stridex3) // %3 + : "r"((intptr_t)(src_stride)) // %4 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + + +#ifdef HAS_SCALEROWDOWN4_AVX2 +void ScaleRowDown4_AVX2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "vpcmpeqb %%ymm5,%%ymm5,%%ymm5 \n" + "vpsrld $0x18,%%ymm5,%%ymm5 \n" + "vpslld $0x10,%%ymm5,%%ymm5 \n" + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + "lea " MEMLEA(0x40,0) ",%0 \n" + "vpand %%ymm5,%%ymm0,%%ymm0 \n" + "vpand %%ymm5,%%ymm1,%%ymm1 \n" + "vpackuswb %%ymm1,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vpsrlw $0x8,%%ymm0,%%ymm0 \n" + "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vmovdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + :: "memory", "cc", "xmm0", "xmm1", "xmm5" + ); +} + +void ScaleRowDown4Box_AVX2(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "vpcmpeqb %%ymm4,%%ymm4,%%ymm4 \n" + "vpsrlw $0xf,%%ymm4,%%ymm4 \n" + "vpsllw $0x3,%%ymm4,%%ymm5 \n" + "vpackuswb %%ymm4,%%ymm4,%%ymm4 \n" + + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm0 \n" + "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n" + MEMOPREG(vmovdqu,0x00,0,3,1,ymm2) // vmovdqu (%0,%3,1),%%ymm2 + MEMOPREG(vmovdqu,0x20,0,3,1,ymm3) // vmovdqu 0x20(%0,%3,1),%%ymm3 + "vpmaddubsw %%ymm4,%%ymm0,%%ymm0 \n" + "vpmaddubsw %%ymm4,%%ymm1,%%ymm1 \n" + "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" + "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" + "vpaddw %%ymm2,%%ymm0,%%ymm0 \n" + "vpaddw %%ymm3,%%ymm1,%%ymm1 \n" + MEMOPREG(vmovdqu,0x00,0,3,2,ymm2) // vmovdqu (%0,%3,2),%%ymm2 + MEMOPREG(vmovdqu,0x20,0,3,2,ymm3) // vmovdqu 0x20(%0,%3,2),%%ymm3 + "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" + "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" + "vpaddw %%ymm2,%%ymm0,%%ymm0 \n" + "vpaddw %%ymm3,%%ymm1,%%ymm1 \n" + MEMOPREG(vmovdqu,0x00,0,4,1,ymm2) // vmovdqu (%0,%4,1),%%ymm2 + MEMOPREG(vmovdqu,0x20,0,4,1,ymm3) // vmovdqu 0x20(%0,%4,1),%%ymm3 + "lea " MEMLEA(0x40,0) ",%0 \n" + "vpmaddubsw %%ymm4,%%ymm2,%%ymm2 \n" + "vpmaddubsw %%ymm4,%%ymm3,%%ymm3 \n" + "vpaddw %%ymm2,%%ymm0,%%ymm0 \n" + "vpaddw %%ymm3,%%ymm1,%%ymm1 \n" + "vphaddw %%ymm1,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vpaddw %%ymm5,%%ymm0,%%ymm0 \n" + "vpsrlw $0x4,%%ymm0,%%ymm0 \n" + "vpackuswb %%ymm0,%%ymm0,%%ymm0 \n" + "vpermq $0xd8,%%ymm0,%%ymm0 \n" + "vmovdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)), // %3 + "r"((intptr_t)(src_stride * 3)) // %4 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} +#endif // HAS_SCALEROWDOWN4_AVX2 + +void ScaleRowDown34_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "movdqa %0,%%xmm3 \n" + "movdqa %1,%%xmm4 \n" + "movdqa %2,%%xmm5 \n" + : + : "m"(kShuf0), // %0 + "m"(kShuf1), // %1 + "m"(kShuf2) // %2 + ); + asm volatile ( + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm2 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "movdqa %%xmm2,%%xmm1 \n" + "palignr $0x8,%%xmm0,%%xmm1 \n" + "pshufb %%xmm3,%%xmm0 \n" + "pshufb %%xmm4,%%xmm1 \n" + "pshufb %%xmm5,%%xmm2 \n" + "movq %%xmm0," MEMACCESS(1) " \n" + "movq %%xmm1," MEMACCESS2(0x8,1) " \n" + "movq %%xmm2," MEMACCESS2(0x10,1) " \n" + "lea " MEMLEA(0x18,1) ",%1 \n" + "sub $0x18,%2 \n" + "jg 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + :: "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" + ); +} + +void ScaleRowDown34_1_Box_SSSE3(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "movdqa %0,%%xmm2 \n" // kShuf01 + "movdqa %1,%%xmm3 \n" // kShuf11 + "movdqa %2,%%xmm4 \n" // kShuf21 + : + : "m"(kShuf01), // %0 + "m"(kShuf11), // %1 + "m"(kShuf21) // %2 + ); + asm volatile ( + "movdqa %0,%%xmm5 \n" // kMadd01 + "movdqa %1,%%xmm0 \n" // kMadd11 + "movdqa %2,%%xmm1 \n" // kRound34 + : + : "m"(kMadd01), // %0 + "m"(kMadd11), // %1 + "m"(kRound34) // %2 + ); + asm volatile ( + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm6 \n" + MEMOPREG(movdqu,0x00,0,3,1,xmm7) // movdqu (%0,%3),%%xmm7 + "pavgb %%xmm7,%%xmm6 \n" + "pshufb %%xmm2,%%xmm6 \n" + "pmaddubsw %%xmm5,%%xmm6 \n" + "paddsw %%xmm1,%%xmm6 \n" + "psrlw $0x2,%%xmm6 \n" + "packuswb %%xmm6,%%xmm6 \n" + "movq %%xmm6," MEMACCESS(1) " \n" + "movdqu " MEMACCESS2(0x8,0) ",%%xmm6 \n" + MEMOPREG(movdqu,0x8,0,3,1,xmm7) // movdqu 0x8(%0,%3),%%xmm7 + "pavgb %%xmm7,%%xmm6 \n" + "pshufb %%xmm3,%%xmm6 \n" + "pmaddubsw %%xmm0,%%xmm6 \n" + "paddsw %%xmm1,%%xmm6 \n" + "psrlw $0x2,%%xmm6 \n" + "packuswb %%xmm6,%%xmm6 \n" + "movq %%xmm6," MEMACCESS2(0x8,1) " \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm6 \n" + MEMOPREG(movdqu,0x10,0,3,1,xmm7) // movdqu 0x10(%0,%3),%%xmm7 + "lea " MEMLEA(0x20,0) ",%0 \n" + "pavgb %%xmm7,%%xmm6 \n" + "pshufb %%xmm4,%%xmm6 \n" + "pmaddubsw %4,%%xmm6 \n" + "paddsw %%xmm1,%%xmm6 \n" + "psrlw $0x2,%%xmm6 \n" + "packuswb %%xmm6,%%xmm6 \n" + "movq %%xmm6," MEMACCESS2(0x10,1) " \n" + "lea " MEMLEA(0x18,1) ",%1 \n" + "sub $0x18,%2 \n" + "jg 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)), // %3 + "m"(kMadd21) // %4 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} + +void ScaleRowDown34_0_Box_SSSE3(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "movdqa %0,%%xmm2 \n" // kShuf01 + "movdqa %1,%%xmm3 \n" // kShuf11 + "movdqa %2,%%xmm4 \n" // kShuf21 + : + : "m"(kShuf01), // %0 + "m"(kShuf11), // %1 + "m"(kShuf21) // %2 + ); + asm volatile ( + "movdqa %0,%%xmm5 \n" // kMadd01 + "movdqa %1,%%xmm0 \n" // kMadd11 + "movdqa %2,%%xmm1 \n" // kRound34 + : + : "m"(kMadd01), // %0 + "m"(kMadd11), // %1 + "m"(kRound34) // %2 + ); + + asm volatile ( + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm6 \n" + MEMOPREG(movdqu,0x00,0,3,1,xmm7) // movdqu (%0,%3,1),%%xmm7 + "pavgb %%xmm6,%%xmm7 \n" + "pavgb %%xmm7,%%xmm6 \n" + "pshufb %%xmm2,%%xmm6 \n" + "pmaddubsw %%xmm5,%%xmm6 \n" + "paddsw %%xmm1,%%xmm6 \n" + "psrlw $0x2,%%xmm6 \n" + "packuswb %%xmm6,%%xmm6 \n" + "movq %%xmm6," MEMACCESS(1) " \n" + "movdqu " MEMACCESS2(0x8,0) ",%%xmm6 \n" + MEMOPREG(movdqu,0x8,0,3,1,xmm7) // movdqu 0x8(%0,%3,1),%%xmm7 + "pavgb %%xmm6,%%xmm7 \n" + "pavgb %%xmm7,%%xmm6 \n" + "pshufb %%xmm3,%%xmm6 \n" + "pmaddubsw %%xmm0,%%xmm6 \n" + "paddsw %%xmm1,%%xmm6 \n" + "psrlw $0x2,%%xmm6 \n" + "packuswb %%xmm6,%%xmm6 \n" + "movq %%xmm6," MEMACCESS2(0x8,1) " \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm6 \n" + MEMOPREG(movdqu,0x10,0,3,1,xmm7) // movdqu 0x10(%0,%3,1),%%xmm7 + "lea " MEMLEA(0x20,0) ",%0 \n" + "pavgb %%xmm6,%%xmm7 \n" + "pavgb %%xmm7,%%xmm6 \n" + "pshufb %%xmm4,%%xmm6 \n" + "pmaddubsw %4,%%xmm6 \n" + "paddsw %%xmm1,%%xmm6 \n" + "psrlw $0x2,%%xmm6 \n" + "packuswb %%xmm6,%%xmm6 \n" + "movq %%xmm6," MEMACCESS2(0x10,1) " \n" + "lea " MEMLEA(0x18,1) ",%1 \n" + "sub $0x18,%2 \n" + "jg 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)), // %3 + "m"(kMadd21) // %4 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} + +void ScaleRowDown38_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "movdqa %3,%%xmm4 \n" + "movdqa %4,%%xmm5 \n" + + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "pshufb %%xmm4,%%xmm0 \n" + "pshufb %%xmm5,%%xmm1 \n" + "paddusb %%xmm1,%%xmm0 \n" + "movq %%xmm0," MEMACCESS(1) " \n" + "movhlps %%xmm0,%%xmm1 \n" + "movd %%xmm1," MEMACCESS2(0x8,1) " \n" + "lea " MEMLEA(0xc,1) ",%1 \n" + "sub $0xc,%2 \n" + "jg 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "m"(kShuf38a), // %3 + "m"(kShuf38b) // %4 + : "memory", "cc", "xmm0", "xmm1", "xmm4", "xmm5" + ); +} + +void ScaleRowDown38_2_Box_SSSE3(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "movdqa %0,%%xmm2 \n" + "movdqa %1,%%xmm3 \n" + "movdqa %2,%%xmm4 \n" + "movdqa %3,%%xmm5 \n" + : + : "m"(kShufAb0), // %0 + "m"(kShufAb1), // %1 + "m"(kShufAb2), // %2 + "m"(kScaleAb2) // %3 + ); + asm volatile ( + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(movdqu,0x00,0,3,1,xmm1) // movdqu (%0,%3,1),%%xmm1 + "lea " MEMLEA(0x10,0) ",%0 \n" + "pavgb %%xmm1,%%xmm0 \n" + "movdqa %%xmm0,%%xmm1 \n" + "pshufb %%xmm2,%%xmm1 \n" + "movdqa %%xmm0,%%xmm6 \n" + "pshufb %%xmm3,%%xmm6 \n" + "paddusw %%xmm6,%%xmm1 \n" + "pshufb %%xmm4,%%xmm0 \n" + "paddusw %%xmm0,%%xmm1 \n" + "pmulhuw %%xmm5,%%xmm1 \n" + "packuswb %%xmm1,%%xmm1 \n" + "movd %%xmm1," MEMACCESS(1) " \n" + "psrlq $0x10,%%xmm1 \n" + "movd %%xmm1," MEMACCESS2(0x2,1) " \n" + "lea " MEMLEA(0x6,1) ",%1 \n" + "sub $0x6,%2 \n" + "jg 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)) // %3 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" + ); +} + +void ScaleRowDown38_3_Box_SSSE3(const uint8* src_ptr, + ptrdiff_t src_stride, + uint8* dst_ptr, int dst_width) { + asm volatile ( + "movdqa %0,%%xmm2 \n" + "movdqa %1,%%xmm3 \n" + "movdqa %2,%%xmm4 \n" + "pxor %%xmm5,%%xmm5 \n" + : + : "m"(kShufAc), // %0 + "m"(kShufAc3), // %1 + "m"(kScaleAc33) // %2 + ); + asm volatile ( + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(movdqu,0x00,0,3,1,xmm6) // movdqu (%0,%3,1),%%xmm6 + "movhlps %%xmm0,%%xmm1 \n" + "movhlps %%xmm6,%%xmm7 \n" + "punpcklbw %%xmm5,%%xmm0 \n" + "punpcklbw %%xmm5,%%xmm1 \n" + "punpcklbw %%xmm5,%%xmm6 \n" + "punpcklbw %%xmm5,%%xmm7 \n" + "paddusw %%xmm6,%%xmm0 \n" + "paddusw %%xmm7,%%xmm1 \n" + MEMOPREG(movdqu,0x00,0,3,2,xmm6) // movdqu (%0,%3,2),%%xmm6 + "lea " MEMLEA(0x10,0) ",%0 \n" + "movhlps %%xmm6,%%xmm7 \n" + "punpcklbw %%xmm5,%%xmm6 \n" + "punpcklbw %%xmm5,%%xmm7 \n" + "paddusw %%xmm6,%%xmm0 \n" + "paddusw %%xmm7,%%xmm1 \n" + "movdqa %%xmm0,%%xmm6 \n" + "psrldq $0x2,%%xmm0 \n" + "paddusw %%xmm0,%%xmm6 \n" + "psrldq $0x2,%%xmm0 \n" + "paddusw %%xmm0,%%xmm6 \n" + "pshufb %%xmm2,%%xmm6 \n" + "movdqa %%xmm1,%%xmm7 \n" + "psrldq $0x2,%%xmm1 \n" + "paddusw %%xmm1,%%xmm7 \n" + "psrldq $0x2,%%xmm1 \n" + "paddusw %%xmm1,%%xmm7 \n" + "pshufb %%xmm3,%%xmm7 \n" + "paddusw %%xmm7,%%xmm6 \n" + "pmulhuw %%xmm4,%%xmm6 \n" + "packuswb %%xmm6,%%xmm6 \n" + "movd %%xmm6," MEMACCESS(1) " \n" + "psrlq $0x10,%%xmm6 \n" + "movd %%xmm6," MEMACCESS2(0x2,1) " \n" + "lea " MEMLEA(0x6,1) ",%1 \n" + "sub $0x6,%2 \n" + "jg 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)) // %3 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} + +// Reads 16xN bytes and produces 16 shorts at a time. +void ScaleAddRow_SSE2(const uint8* src_ptr, uint16* dst_ptr, int src_width) { + asm volatile ( + "pxor %%xmm5,%%xmm5 \n" + + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm3 \n" + "lea " MEMLEA(0x10,0) ",%0 \n" // src_ptr += 16 + "movdqu " MEMACCESS(1) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,1) ",%%xmm1 \n" + "movdqa %%xmm3,%%xmm2 \n" + "punpcklbw %%xmm5,%%xmm2 \n" + "punpckhbw %%xmm5,%%xmm3 \n" + "paddusw %%xmm2,%%xmm0 \n" + "paddusw %%xmm3,%%xmm1 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n" + "lea " MEMLEA(0x20,1) ",%1 \n" + "sub $0x10,%2 \n" + "jg 1b \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(src_width) // %2 + : + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" + ); +} + + +#ifdef HAS_SCALEADDROW_AVX2 +// Reads 32 bytes and accumulates to 32 shorts at a time. +void ScaleAddRow_AVX2(const uint8* src_ptr, uint16* dst_ptr, int src_width) { + asm volatile ( + "vpxor %%ymm5,%%ymm5,%%ymm5 \n" + + LABELALIGN + "1: \n" + "vmovdqu " MEMACCESS(0) ",%%ymm3 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" // src_ptr += 32 + "vpermq $0xd8,%%ymm3,%%ymm3 \n" + "vpunpcklbw %%ymm5,%%ymm3,%%ymm2 \n" + "vpunpckhbw %%ymm5,%%ymm3,%%ymm3 \n" + "vpaddusw " MEMACCESS(1) ",%%ymm2,%%ymm0 \n" + "vpaddusw " MEMACCESS2(0x20,1) ",%%ymm3,%%ymm1 \n" + "vmovdqu %%ymm0," MEMACCESS(1) " \n" + "vmovdqu %%ymm1," MEMACCESS2(0x20,1) " \n" + "lea " MEMLEA(0x40,1) ",%1 \n" + "sub $0x20,%2 \n" + "jg 1b \n" + "vzeroupper \n" + : "+r"(src_ptr), // %0 + "+r"(dst_ptr), // %1 + "+r"(src_width) // %2 + : + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm5" + ); +} +#endif // HAS_SCALEADDROW_AVX2 + +// Bilinear column filtering. SSSE3 version. +void ScaleFilterCols_SSSE3(uint8* dst_ptr, const uint8* src_ptr, + int dst_width, int x, int dx) { + intptr_t x0 = 0, x1 = 0, temp_pixel = 0; + asm volatile ( + "movd %6,%%xmm2 \n" + "movd %7,%%xmm3 \n" + "movl $0x04040000,%k2 \n" + "movd %k2,%%xmm5 \n" + "pcmpeqb %%xmm6,%%xmm6 \n" + "psrlw $0x9,%%xmm6 \n" + "pextrw $0x1,%%xmm2,%k3 \n" + "subl $0x2,%5 \n" + "jl 29f \n" + "movdqa %%xmm2,%%xmm0 \n" + "paddd %%xmm3,%%xmm0 \n" + "punpckldq %%xmm0,%%xmm2 \n" + "punpckldq %%xmm3,%%xmm3 \n" + "paddd %%xmm3,%%xmm3 \n" + "pextrw $0x3,%%xmm2,%k4 \n" + + LABELALIGN + "2: \n" + "movdqa %%xmm2,%%xmm1 \n" + "paddd %%xmm3,%%xmm2 \n" + MEMOPARG(movzwl,0x00,1,3,1,k2) // movzwl (%1,%3,1),%k2 + "movd %k2,%%xmm0 \n" + "psrlw $0x9,%%xmm1 \n" + MEMOPARG(movzwl,0x00,1,4,1,k2) // movzwl (%1,%4,1),%k2 + "movd %k2,%%xmm4 \n" + "pshufb %%xmm5,%%xmm1 \n" + "punpcklwd %%xmm4,%%xmm0 \n" + "pxor %%xmm6,%%xmm1 \n" + "pmaddubsw %%xmm1,%%xmm0 \n" + "pextrw $0x1,%%xmm2,%k3 \n" + "pextrw $0x3,%%xmm2,%k4 \n" + "psrlw $0x7,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movd %%xmm0,%k2 \n" + "mov %w2," MEMACCESS(0) " \n" + "lea " MEMLEA(0x2,0) ",%0 \n" + "sub $0x2,%5 \n" + "jge 2b \n" + + LABELALIGN + "29: \n" + "addl $0x1,%5 \n" + "jl 99f \n" + MEMOPARG(movzwl,0x00,1,3,1,k2) // movzwl (%1,%3,1),%k2 + "movd %k2,%%xmm0 \n" + "psrlw $0x9,%%xmm2 \n" + "pshufb %%xmm5,%%xmm2 \n" + "pxor %%xmm6,%%xmm2 \n" + "pmaddubsw %%xmm2,%%xmm0 \n" + "psrlw $0x7,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movd %%xmm0,%k2 \n" + "mov %b2," MEMACCESS(0) " \n" + "99: \n" + : "+r"(dst_ptr), // %0 + "+r"(src_ptr), // %1 + "+a"(temp_pixel), // %2 + "+r"(x0), // %3 + "+r"(x1), // %4 + "+rm"(dst_width) // %5 + : "rm"(x), // %6 + "rm"(dx) // %7 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" + ); +} + +// Reads 4 pixels, duplicates them and writes 8 pixels. +// Alignment requirement: src_argb 16 byte aligned, dst_argb 16 byte aligned. +void ScaleColsUp2_SSE2(uint8* dst_ptr, const uint8* src_ptr, + int dst_width, int x, int dx) { + asm volatile ( + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(1) ",%%xmm0 \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpcklbw %%xmm0,%%xmm0 \n" + "punpckhbw %%xmm1,%%xmm1 \n" + "movdqu %%xmm0," MEMACCESS(0) " \n" + "movdqu %%xmm1," MEMACCESS2(0x10,0) " \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "sub $0x20,%2 \n" + "jg 1b \n" + + : "+r"(dst_ptr), // %0 + "+r"(src_ptr), // %1 + "+r"(dst_width) // %2 + :: "memory", "cc", "xmm0", "xmm1" + ); +} + +void ScaleARGBRowDown2_SSE2(const uint8* src_argb, + ptrdiff_t src_stride, + uint8* dst_argb, int dst_width) { + asm volatile ( + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "shufps $0xdd,%%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x4,%2 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+r"(dst_width) // %2 + :: "memory", "cc", "xmm0", "xmm1" + ); +} + +void ScaleARGBRowDown2Linear_SSE2(const uint8* src_argb, + ptrdiff_t src_stride, + uint8* dst_argb, int dst_width) { + asm volatile ( + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "movdqa %%xmm0,%%xmm2 \n" + "shufps $0x88,%%xmm1,%%xmm0 \n" + "shufps $0xdd,%%xmm1,%%xmm2 \n" + "pavgb %%xmm2,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x4,%2 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+r"(dst_width) // %2 + :: "memory", "cc", "xmm0", "xmm1" + ); +} + +void ScaleARGBRowDown2Box_SSE2(const uint8* src_argb, + ptrdiff_t src_stride, + uint8* dst_argb, int dst_width) { + asm volatile ( + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(0) ",%%xmm0 \n" + "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n" + MEMOPREG(movdqu,0x00,0,3,1,xmm2) // movdqu (%0,%3,1),%%xmm2 + MEMOPREG(movdqu,0x10,0,3,1,xmm3) // movdqu 0x10(%0,%3,1),%%xmm3 + "lea " MEMLEA(0x20,0) ",%0 \n" + "pavgb %%xmm2,%%xmm0 \n" + "pavgb %%xmm3,%%xmm1 \n" + "movdqa %%xmm0,%%xmm2 \n" + "shufps $0x88,%%xmm1,%%xmm0 \n" + "shufps $0xdd,%%xmm1,%%xmm2 \n" + "pavgb %%xmm2,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(1) " \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "sub $0x4,%2 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(dst_argb), // %1 + "+r"(dst_width) // %2 + : "r"((intptr_t)(src_stride)) // %3 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3" + ); +} + +// Reads 4 pixels at a time. +// Alignment requirement: dst_argb 16 byte aligned. +void ScaleARGBRowDownEven_SSE2(const uint8* src_argb, ptrdiff_t src_stride, + int src_stepx, uint8* dst_argb, int dst_width) { + intptr_t src_stepx_x4 = (intptr_t)(src_stepx); + intptr_t src_stepx_x12 = 0; + asm volatile ( + "lea " MEMLEA3(0x00,1,4) ",%1 \n" + "lea " MEMLEA4(0x00,1,1,2) ",%4 \n" + LABELALIGN + "1: \n" + "movd " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(movd,0x00,0,1,1,xmm1) // movd (%0,%1,1),%%xmm1 + "punpckldq %%xmm1,%%xmm0 \n" + MEMOPREG(movd,0x00,0,1,2,xmm2) // movd (%0,%1,2),%%xmm2 + MEMOPREG(movd,0x00,0,4,1,xmm3) // movd (%0,%4,1),%%xmm3 + "lea " MEMLEA4(0x00,0,1,4) ",%0 \n" + "punpckldq %%xmm3,%%xmm2 \n" + "punpcklqdq %%xmm2,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x10,2) ",%2 \n" + "sub $0x4,%3 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(src_stepx_x4), // %1 + "+r"(dst_argb), // %2 + "+r"(dst_width), // %3 + "+r"(src_stepx_x12) // %4 + :: "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3" + ); +} + +// Blends four 2x2 to 4x1. +// Alignment requirement: dst_argb 16 byte aligned. +void ScaleARGBRowDownEvenBox_SSE2(const uint8* src_argb, + ptrdiff_t src_stride, int src_stepx, + uint8* dst_argb, int dst_width) { + intptr_t src_stepx_x4 = (intptr_t)(src_stepx); + intptr_t src_stepx_x12 = 0; + intptr_t row1 = (intptr_t)(src_stride); + asm volatile ( + "lea " MEMLEA3(0x00,1,4) ",%1 \n" + "lea " MEMLEA4(0x00,1,1,2) ",%4 \n" + "lea " MEMLEA4(0x00,0,5,1) ",%5 \n" + + LABELALIGN + "1: \n" + "movq " MEMACCESS(0) ",%%xmm0 \n" + MEMOPREG(movhps,0x00,0,1,1,xmm0) // movhps (%0,%1,1),%%xmm0 + MEMOPREG(movq,0x00,0,1,2,xmm1) // movq (%0,%1,2),%%xmm1 + MEMOPREG(movhps,0x00,0,4,1,xmm1) // movhps (%0,%4,1),%%xmm1 + "lea " MEMLEA4(0x00,0,1,4) ",%0 \n" + "movq " MEMACCESS(5) ",%%xmm2 \n" + MEMOPREG(movhps,0x00,5,1,1,xmm2) // movhps (%5,%1,1),%%xmm2 + MEMOPREG(movq,0x00,5,1,2,xmm3) // movq (%5,%1,2),%%xmm3 + MEMOPREG(movhps,0x00,5,4,1,xmm3) // movhps (%5,%4,1),%%xmm3 + "lea " MEMLEA4(0x00,5,1,4) ",%5 \n" + "pavgb %%xmm2,%%xmm0 \n" + "pavgb %%xmm3,%%xmm1 \n" + "movdqa %%xmm0,%%xmm2 \n" + "shufps $0x88,%%xmm1,%%xmm0 \n" + "shufps $0xdd,%%xmm1,%%xmm2 \n" + "pavgb %%xmm2,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x10,2) ",%2 \n" + "sub $0x4,%3 \n" + "jg 1b \n" + : "+r"(src_argb), // %0 + "+r"(src_stepx_x4), // %1 + "+r"(dst_argb), // %2 + "+rm"(dst_width), // %3 + "+r"(src_stepx_x12), // %4 + "+r"(row1) // %5 + :: "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3" + ); +} + +void ScaleARGBCols_SSE2(uint8* dst_argb, const uint8* src_argb, + int dst_width, int x, int dx) { + intptr_t x0 = 0, x1 = 0; + asm volatile ( + "movd %5,%%xmm2 \n" + "movd %6,%%xmm3 \n" + "pshufd $0x0,%%xmm2,%%xmm2 \n" + "pshufd $0x11,%%xmm3,%%xmm0 \n" + "paddd %%xmm0,%%xmm2 \n" + "paddd %%xmm3,%%xmm3 \n" + "pshufd $0x5,%%xmm3,%%xmm0 \n" + "paddd %%xmm0,%%xmm2 \n" + "paddd %%xmm3,%%xmm3 \n" + "pshufd $0x0,%%xmm3,%%xmm3 \n" + "pextrw $0x1,%%xmm2,%k0 \n" + "pextrw $0x3,%%xmm2,%k1 \n" + "cmp $0x0,%4 \n" + "jl 99f \n" + "sub $0x4,%4 \n" + "jl 49f \n" + + LABELALIGN + "40: \n" + MEMOPREG(movd,0x00,3,0,4,xmm0) // movd (%3,%0,4),%%xmm0 + MEMOPREG(movd,0x00,3,1,4,xmm1) // movd (%3,%1,4),%%xmm1 + "pextrw $0x5,%%xmm2,%k0 \n" + "pextrw $0x7,%%xmm2,%k1 \n" + "paddd %%xmm3,%%xmm2 \n" + "punpckldq %%xmm1,%%xmm0 \n" + MEMOPREG(movd,0x00,3,0,4,xmm1) // movd (%3,%0,4),%%xmm1 + MEMOPREG(movd,0x00,3,1,4,xmm4) // movd (%3,%1,4),%%xmm4 + "pextrw $0x1,%%xmm2,%k0 \n" + "pextrw $0x3,%%xmm2,%k1 \n" + "punpckldq %%xmm4,%%xmm1 \n" + "punpcklqdq %%xmm1,%%xmm0 \n" + "movdqu %%xmm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x10,2) ",%2 \n" + "sub $0x4,%4 \n" + "jge 40b \n" + + "49: \n" + "test $0x2,%4 \n" + "je 29f \n" + MEMOPREG(movd,0x00,3,0,4,xmm0) // movd (%3,%0,4),%%xmm0 + MEMOPREG(movd,0x00,3,1,4,xmm1) // movd (%3,%1,4),%%xmm1 + "pextrw $0x5,%%xmm2,%k0 \n" + "punpckldq %%xmm1,%%xmm0 \n" + "movq %%xmm0," MEMACCESS(2) " \n" + "lea " MEMLEA(0x8,2) ",%2 \n" + "29: \n" + "test $0x1,%4 \n" + "je 99f \n" + MEMOPREG(movd,0x00,3,0,4,xmm0) // movd (%3,%0,4),%%xmm0 + "movd %%xmm0," MEMACCESS(2) " \n" + "99: \n" + : "+a"(x0), // %0 + "+d"(x1), // %1 + "+r"(dst_argb), // %2 + "+r"(src_argb), // %3 + "+r"(dst_width) // %4 + : "rm"(x), // %5 + "rm"(dx) // %6 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4" + ); +} + +// Reads 4 pixels, duplicates them and writes 8 pixels. +// Alignment requirement: src_argb 16 byte aligned, dst_argb 16 byte aligned. +void ScaleARGBColsUp2_SSE2(uint8* dst_argb, const uint8* src_argb, + int dst_width, int x, int dx) { + asm volatile ( + LABELALIGN + "1: \n" + "movdqu " MEMACCESS(1) ",%%xmm0 \n" + "lea " MEMLEA(0x10,1) ",%1 \n" + "movdqa %%xmm0,%%xmm1 \n" + "punpckldq %%xmm0,%%xmm0 \n" + "punpckhdq %%xmm1,%%xmm1 \n" + "movdqu %%xmm0," MEMACCESS(0) " \n" + "movdqu %%xmm1," MEMACCESS2(0x10,0) " \n" + "lea " MEMLEA(0x20,0) ",%0 \n" + "sub $0x8,%2 \n" + "jg 1b \n" + + : "+r"(dst_argb), // %0 + "+r"(src_argb), // %1 + "+r"(dst_width) // %2 + :: "memory", "cc", NACL_R14 + "xmm0", "xmm1" + ); +} + +// Shuffle table for arranging 2 pixels into pairs for pmaddubsw +static uvec8 kShuffleColARGB = { + 0u, 4u, 1u, 5u, 2u, 6u, 3u, 7u, // bbggrraa 1st pixel + 8u, 12u, 9u, 13u, 10u, 14u, 11u, 15u // bbggrraa 2nd pixel +}; + +// Shuffle table for duplicating 2 fractions into 8 bytes each +static uvec8 kShuffleFractions = { + 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, +}; + +// Bilinear row filtering combines 4x2 -> 4x1. SSSE3 version +void ScaleARGBFilterCols_SSSE3(uint8* dst_argb, const uint8* src_argb, + int dst_width, int x, int dx) { + intptr_t x0 = 0, x1 = 0; + asm volatile ( + "movdqa %0,%%xmm4 \n" + "movdqa %1,%%xmm5 \n" + : + : "m"(kShuffleColARGB), // %0 + "m"(kShuffleFractions) // %1 + ); + + asm volatile ( + "movd %5,%%xmm2 \n" + "movd %6,%%xmm3 \n" + "pcmpeqb %%xmm6,%%xmm6 \n" + "psrlw $0x9,%%xmm6 \n" + "pextrw $0x1,%%xmm2,%k3 \n" + "sub $0x2,%2 \n" + "jl 29f \n" + "movdqa %%xmm2,%%xmm0 \n" + "paddd %%xmm3,%%xmm0 \n" + "punpckldq %%xmm0,%%xmm2 \n" + "punpckldq %%xmm3,%%xmm3 \n" + "paddd %%xmm3,%%xmm3 \n" + "pextrw $0x3,%%xmm2,%k4 \n" + + LABELALIGN + "2: \n" + "movdqa %%xmm2,%%xmm1 \n" + "paddd %%xmm3,%%xmm2 \n" + MEMOPREG(movq,0x00,1,3,4,xmm0) // movq (%1,%3,4),%%xmm0 + "psrlw $0x9,%%xmm1 \n" + MEMOPREG(movhps,0x00,1,4,4,xmm0) // movhps (%1,%4,4),%%xmm0 + "pshufb %%xmm5,%%xmm1 \n" + "pshufb %%xmm4,%%xmm0 \n" + "pxor %%xmm6,%%xmm1 \n" + "pmaddubsw %%xmm1,%%xmm0 \n" + "psrlw $0x7,%%xmm0 \n" + "pextrw $0x1,%%xmm2,%k3 \n" + "pextrw $0x3,%%xmm2,%k4 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movq %%xmm0," MEMACCESS(0) " \n" + "lea " MEMLEA(0x8,0) ",%0 \n" + "sub $0x2,%2 \n" + "jge 2b \n" + + LABELALIGN + "29: \n" + "add $0x1,%2 \n" + "jl 99f \n" + "psrlw $0x9,%%xmm2 \n" + MEMOPREG(movq,0x00,1,3,4,xmm0) // movq (%1,%3,4),%%xmm0 + "pshufb %%xmm5,%%xmm2 \n" + "pshufb %%xmm4,%%xmm0 \n" + "pxor %%xmm6,%%xmm2 \n" + "pmaddubsw %%xmm2,%%xmm0 \n" + "psrlw $0x7,%%xmm0 \n" + "packuswb %%xmm0,%%xmm0 \n" + "movd %%xmm0," MEMACCESS(0) " \n" + + LABELALIGN + "99: \n" + : "+r"(dst_argb), // %0 + "+r"(src_argb), // %1 + "+rm"(dst_width), // %2 + "+r"(x0), // %3 + "+r"(x1) // %4 + : "rm"(x), // %5 + "rm"(dx) // %6 + : "memory", "cc", NACL_R14 + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6" + ); +} + +// Divide num by div and return as 16.16 fixed point result. +int FixedDiv_X86(int num, int div) { + asm volatile ( + "cdq \n" + "shld $0x10,%%eax,%%edx \n" + "shl $0x10,%%eax \n" + "idiv %1 \n" + "mov %0, %%eax \n" + : "+a"(num) // %0 + : "c"(div) // %1 + : "memory", "cc", "edx" + ); + return num; +} + +// Divide num - 1 by div - 1 and return as 16.16 fixed point result. +int FixedDiv1_X86(int num, int div) { + asm volatile ( + "cdq \n" + "shld $0x10,%%eax,%%edx \n" + "shl $0x10,%%eax \n" + "sub $0x10001,%%eax \n" + "sbb $0x0,%%edx \n" + "sub $0x1,%1 \n" + "idiv %1 \n" + "mov %0, %%eax \n" + : "+a"(num) // %0 + : "c"(div) // %1 + : "memory", "cc", "edx" + ); + return num; +} + +#endif // defined(__x86_64__) || defined(__i386__) + +#ifdef __cplusplus +} // extern "C" +} // namespace libyuv +#endif diff --git a/TMessagesProj/jni/opus/AUTHORS b/TMessagesProj/jni/opus/AUTHORS new file mode 100644 index 00000000..b3d22a20 --- /dev/null +++ b/TMessagesProj/jni/opus/AUTHORS @@ -0,0 +1,6 @@ +Jean-Marc Valin (jmvalin@jmvalin.ca) +Koen Vos (koenvos74@gmail.com) +Timothy Terriberry (tterribe@xiph.org) +Karsten Vandborg Sorensen (karsten.vandborg.sorensen@skype.net) +Soren Skak Jensen (ssjensen@gn.com) +Gregory Maxwell (greg@xiph.org) diff --git a/TMessagesProj/jni/opus/COPYING b/TMessagesProj/jni/opus/COPYING new file mode 100644 index 00000000..9c739c34 --- /dev/null +++ b/TMessagesProj/jni/opus/COPYING @@ -0,0 +1,44 @@ +Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic, + Jean-Marc Valin, Timothy B. Terriberry, + CSIRO, Gregory Maxwell, Mark Borgerding, + Erik de Castro Lopo + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- 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. + +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS 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 COPYRIGHT OWNER +OR 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. + +Opus is subject to the royalty-free patent licenses which are +specified at: + +Xiph.Org Foundation: +https://datatracker.ietf.org/ipr/1524/ + +Microsoft Corporation: +https://datatracker.ietf.org/ipr/1914/ + +Broadcom Corporation: +https://datatracker.ietf.org/ipr/1526/ diff --git a/TMessagesProj/jni/sqlite_statement.c b/TMessagesProj/jni/sqlite_statement.c index 2fc4ef33..4957f790 100644 --- a/TMessagesProj/jni/sqlite_statement.c +++ b/TMessagesProj/jni/sqlite_statement.c @@ -8,8 +8,8 @@ jint sqliteOnJNILoad(JavaVM *vm, void *reserved, JNIEnv *env) { return JNI_VERSION_1_6; } -int Java_org_telegram_SQLite_SQLitePreparedStatement_step(JNIEnv* env, jobject object, int statementHandle) { - sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle; +int Java_org_telegram_SQLite_SQLitePreparedStatement_step(JNIEnv *env, jobject object, int statementHandle) { + sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle; int errcode = sqlite3_step(handle); if (errcode == SQLITE_ROW) { @@ -23,7 +23,7 @@ int Java_org_telegram_SQLite_SQLitePreparedStatement_step(JNIEnv* env, jobject o } int Java_org_telegram_SQLite_SQLitePreparedStatement_prepare(JNIEnv *env, jobject object, int sqliteHandle, jstring sql) { - sqlite3* handle = (sqlite3 *)sqliteHandle; + sqlite3 *handle = (sqlite3 *) sqliteHandle; char const *sqlStr = (*env)->GetStringUTFChars(env, sql, 0); @@ -41,11 +41,11 @@ int Java_org_telegram_SQLite_SQLitePreparedStatement_prepare(JNIEnv *env, jobjec (*env)->ReleaseStringUTFChars(env, sql, sqlStr); } - return (int)stmt_handle; + return (int) stmt_handle; } void Java_org_telegram_SQLite_SQLitePreparedStatement_reset(JNIEnv *env, jobject object, int statementHandle) { - sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle; + sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle; int errcode = sqlite3_reset(handle); if (SQLITE_OK != errcode) { @@ -54,16 +54,11 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_reset(JNIEnv *env, jobject } void Java_org_telegram_SQLite_SQLitePreparedStatement_finalize(JNIEnv *env, jobject object, int statementHandle) { - sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle; - - int errcode = sqlite3_finalize (handle); - if (SQLITE_OK != errcode) { - throw_sqlite3_exception(env, sqlite3_db_handle(handle), errcode); - } + sqlite3_finalize((sqlite3_stmt *) statementHandle); } void Java_org_telegram_SQLite_SQLitePreparedStatement_bindByteBuffer(JNIEnv *env, jobject object, int statementHandle, int index, jobject value, int length) { - sqlite3_stmt *handle = (sqlite3_stmt *)statementHandle; + sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle; jbyte *buf = (*env)->GetDirectBufferAddress(env, value); int errcode = sqlite3_bind_blob(handle, index, buf, length, SQLITE_STATIC); @@ -73,7 +68,7 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindByteBuffer(JNIEnv *env } void Java_org_telegram_SQLite_SQLitePreparedStatement_bindString(JNIEnv *env, jobject object, int statementHandle, int index, jstring value) { - sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle; + sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle; char const *valueStr = (*env)->GetStringUTFChars(env, value, 0); @@ -88,7 +83,7 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindString(JNIEnv *env, jo } void Java_org_telegram_SQLite_SQLitePreparedStatement_bindInt(JNIEnv *env, jobject object, int statementHandle, int index, int value) { - sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle; + sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle; int errcode = sqlite3_bind_int(handle, index, value); if (SQLITE_OK != errcode) { @@ -97,7 +92,7 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindInt(JNIEnv *env, jobje } void Java_org_telegram_SQLite_SQLitePreparedStatement_bindLong(JNIEnv *env, jobject object, int statementHandle, int index, long long value) { - sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle; + sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle; int errcode = sqlite3_bind_int64(handle, index, value); if (SQLITE_OK != errcode) { @@ -105,8 +100,8 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindLong(JNIEnv *env, jobj } } -void Java_org_telegram_SQLite_SQLitePreparedStatement_bindDouble(JNIEnv* env, jobject object, int statementHandle, int index, double value) { - sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle; +void Java_org_telegram_SQLite_SQLitePreparedStatement_bindDouble(JNIEnv *env, jobject object, int statementHandle, int index, double value) { + sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle; int errcode = sqlite3_bind_double(handle, index, value); if (SQLITE_OK != errcode) { @@ -114,8 +109,8 @@ void Java_org_telegram_SQLite_SQLitePreparedStatement_bindDouble(JNIEnv* env, jo } } -void Java_org_telegram_SQLite_SQLitePreparedStatement_bindNull(JNIEnv* env, jobject object, int statementHandle, int index) { - sqlite3_stmt *handle = (sqlite3_stmt*)statementHandle; +void Java_org_telegram_SQLite_SQLitePreparedStatement_bindNull(JNIEnv *env, jobject object, int statementHandle, int index) { + sqlite3_stmt *handle = (sqlite3_stmt *) statementHandle; int errcode = sqlite3_bind_null(handle, index); if (SQLITE_OK != errcode) { diff --git a/TMessagesProj/jni/tgnet/BuffersStorage.cpp b/TMessagesProj/jni/tgnet/BuffersStorage.cpp new file mode 100644 index 00000000..7d7395bc --- /dev/null +++ b/TMessagesProj/jni/tgnet/BuffersStorage.cpp @@ -0,0 +1,123 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include "BuffersStorage.h" +#include "FileLog.h" +#include "NativeByteBuffer.h" + +BuffersStorage &BuffersStorage::getInstance() { + static BuffersStorage instance(true); + return instance; +} + +BuffersStorage::BuffersStorage(bool threadSafe) { + isThreadSafe = threadSafe; + if (isThreadSafe) { + pthread_mutex_init(&mutex, NULL); + } + for (uint32_t a = 0; a < 4; a++) { + freeBuffers8.push_back(new NativeByteBuffer((uint32_t) 8)); + } + for (uint32_t a = 0; a < 5; a++) { + freeBuffers128.push_back(new NativeByteBuffer((uint32_t) 128)); + } +} + +NativeByteBuffer *BuffersStorage::getFreeBuffer(uint32_t size) { + uint32_t byteCount = 0; + std::vector *arrayToGetFrom = nullptr; + NativeByteBuffer *buffer = nullptr; + if (size <= 8) { + arrayToGetFrom = &freeBuffers8; + byteCount = 8; + } else if (size <= 128) { + arrayToGetFrom = &freeBuffers128; + byteCount = 128; + } else if (size <= 1024 + 200) { + arrayToGetFrom = &freeBuffers1024; + byteCount = 1024 + 200; + } else if (size <= 4096 + 200) { + arrayToGetFrom = &freeBuffers4096; + byteCount = 4096 + 200; + } else if (size <= 16384 + 200) { + arrayToGetFrom = &freeBuffers16384; + byteCount = 16384 + 200; + } else if (size <= 40000) { + arrayToGetFrom = &freeBuffers32768; + byteCount = 40000; + } else if (size <= 160000) { + arrayToGetFrom = &freeBuffersBig; + byteCount = 160000; + } else { + buffer = new NativeByteBuffer(size); + } + + if (arrayToGetFrom != nullptr) { + if (isThreadSafe) { + pthread_mutex_lock(&mutex); + } + if (arrayToGetFrom->size() > 0) { + buffer = (*arrayToGetFrom)[0]; + arrayToGetFrom->erase(arrayToGetFrom->begin()); + } + if (isThreadSafe) { + pthread_mutex_unlock(&mutex); + } + if (buffer == nullptr) { + buffer = new NativeByteBuffer(byteCount); + DEBUG_D("create new %u buffer", byteCount); + } + } + if (buffer != nullptr) { + buffer->limit(size); + buffer->rewind(); + } + return buffer; +} + +void BuffersStorage::reuseFreeBuffer(NativeByteBuffer *buffer) { + if (buffer == nullptr) { + return; + } + std::vector *arrayToReuse = nullptr; + uint32_t capacity = buffer->capacity(); + uint32_t maxCount = 10; + if (capacity == 8) { + arrayToReuse = &freeBuffers8; + maxCount = 80; + } else if (capacity == 128) { + arrayToReuse = &freeBuffers128; + maxCount = 80; + } else if (capacity == 1024 + 200) { + arrayToReuse = &freeBuffers1024; + } else if (capacity == 4096 + 200) { + arrayToReuse = &freeBuffers4096; + } else if (capacity == 16384 + 200) { + arrayToReuse = &freeBuffers16384; + } else if (capacity == 40000) { + arrayToReuse = &freeBuffers32768; + } else if (capacity == 160000) { + arrayToReuse = &freeBuffersBig; + } + if (arrayToReuse != nullptr) { + if (isThreadSafe) { + pthread_mutex_lock(&mutex); + } + if (arrayToReuse->size() < maxCount) { + arrayToReuse->push_back(buffer); + } else { + DEBUG_D("too more %d buffers", capacity); + delete buffer; + } + if (isThreadSafe) { + pthread_mutex_unlock(&mutex); + } + } else { + delete buffer; + } +} diff --git a/TMessagesProj/jni/tgnet/BuffersStorage.h b/TMessagesProj/jni/tgnet/BuffersStorage.h new file mode 100644 index 00000000..57c4f3f8 --- /dev/null +++ b/TMessagesProj/jni/tgnet/BuffersStorage.h @@ -0,0 +1,38 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef BUFFERSSTORAGE_H +#define BUFFERSSTORAGE_H + +#include +#include +#include + +class NativeByteBuffer; + +class BuffersStorage { + +public: + BuffersStorage(bool threadSafe); + NativeByteBuffer *getFreeBuffer(uint32_t size); + void reuseFreeBuffer(NativeByteBuffer *buffer); + static BuffersStorage &getInstance(); + +private: + std::vector freeBuffers8; + std::vector freeBuffers128; + std::vector freeBuffers1024; + std::vector freeBuffers4096; + std::vector freeBuffers16384; + std::vector freeBuffers32768; + std::vector freeBuffersBig; + bool isThreadSafe = true; + pthread_mutex_t mutex; +}; + +#endif diff --git a/TMessagesProj/jni/tgnet/ByteArray.cpp b/TMessagesProj/jni/tgnet/ByteArray.cpp new file mode 100644 index 00000000..3be5b36f --- /dev/null +++ b/TMessagesProj/jni/tgnet/ByteArray.cpp @@ -0,0 +1,71 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include +#include +#include "ByteArray.h" +#include "FileLog.h" + +ByteArray::ByteArray() { + bytes = nullptr; + length = 0; +} + +ByteArray::ByteArray(uint32_t len) { + bytes = new uint8_t[len]; + if (bytes == nullptr) { + DEBUG_E("unable to allocate byte buffer %u", len); + exit(1); + } + length = len; +} + + +ByteArray::ByteArray(ByteArray *byteArray) { + bytes = new uint8_t[byteArray->length]; + if (bytes == nullptr) { + DEBUG_E("unable to allocate byte buffer %u", byteArray->length); + exit(1); + } + length = byteArray->length; + memcpy(bytes, byteArray->bytes, length); +} + +ByteArray::ByteArray(uint8_t *buffer, uint32_t len) { + bytes = new uint8_t[len]; + if (bytes == nullptr) { + DEBUG_E("unable to allocate byte buffer %u", len); + exit(1); + } + length = len; + memcpy(bytes, buffer, length); +} + +ByteArray::~ByteArray() { + if (bytes != nullptr) { + delete[] bytes; + bytes = nullptr; + } +} + +void ByteArray::alloc(uint32_t len) { + if (bytes != nullptr) { + delete[] bytes; + bytes = nullptr; + } + bytes = new uint8_t[len]; + if (bytes == nullptr) { + DEBUG_E("unable to allocate byte buffer %u", len); + exit(1); + } + length = len; +} + +bool ByteArray::isEqualTo(ByteArray *byteArray) { + return byteArray->length == length && !memcmp(byteArray->bytes, bytes, length); +} diff --git a/TMessagesProj/jni/tgnet/ByteArray.h b/TMessagesProj/jni/tgnet/ByteArray.h new file mode 100644 index 00000000..2bb6f13f --- /dev/null +++ b/TMessagesProj/jni/tgnet/ByteArray.h @@ -0,0 +1,31 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef BYTEARRAY_H +#define BYTEARRAY_H + +#include + +class ByteArray { + +public: + ByteArray(); + ByteArray(uint32_t len); + ByteArray(ByteArray *byteArray); + ByteArray(uint8_t *buffer, uint32_t len); + ~ByteArray(); + void alloc(uint32_t len); + + uint32_t length; + uint8_t *bytes; + + bool isEqualTo(ByteArray *byteArray); + +}; + +#endif diff --git a/TMessagesProj/jni/tgnet/ByteStream.cpp b/TMessagesProj/jni/tgnet/ByteStream.cpp new file mode 100644 index 00000000..2b2209d7 --- /dev/null +++ b/TMessagesProj/jni/tgnet/ByteStream.cpp @@ -0,0 +1,83 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include "ByteStream.h" +#include "NativeByteBuffer.h" + +ByteStream::ByteStream() { + +} + +ByteStream::~ByteStream() { + +} + +void ByteStream::append(NativeByteBuffer *buffer) { + if (buffer == nullptr) { + return; + } + buffersQueue.push_back(buffer); +} + +bool ByteStream::hasData() { + size_t size = buffersQueue.size(); + for (uint32_t a = 0; a < size; a++) { + if (buffersQueue[a]->hasRemaining()) { + return true; + } + } + return false; +} + +void ByteStream::get(NativeByteBuffer *dst) { + if (dst == nullptr) { + return; + } + + size_t size = buffersQueue.size(); + NativeByteBuffer *buffer; + for (uint32_t a = 0; a < size; a++) { + buffer = buffersQueue[a]; + if (buffer->remaining() > dst->remaining()) { + dst->writeBytes(buffer->bytes(), buffer->position(), dst->remaining()); + break; + } + dst->writeBytes(buffer->bytes(), buffer->position(), buffer->remaining()); + if (!dst->hasRemaining()) { + break; + } + } +} + +void ByteStream::discard(uint32_t count) { + uint32_t remaining; + NativeByteBuffer *buffer; + while (count > 0) { + buffer = buffersQueue[0]; + remaining = buffer->remaining(); + if (count < remaining) { + buffer->position(buffer->position() + count); + break; + } + buffer->reuse(); + buffersQueue.erase(buffersQueue.begin()); + count -= remaining; + } +} + +void ByteStream::clean() { + if (buffersQueue.empty()) { + return; + } + size_t size = buffersQueue.size(); + for (uint32_t a = 0; a < size; a++) { + NativeByteBuffer *buffer = buffersQueue[a]; + buffer->reuse(); + } + buffersQueue.clear(); +} diff --git a/TMessagesProj/jni/tgnet/ByteStream.h b/TMessagesProj/jni/tgnet/ByteStream.h new file mode 100644 index 00000000..56c3e440 --- /dev/null +++ b/TMessagesProj/jni/tgnet/ByteStream.h @@ -0,0 +1,32 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef BYTESTREAM_H +#define BYTESTREAM_H + +#include +#include + +class NativeByteBuffer; + +class ByteStream { + +public: + ByteStream(); + ~ByteStream(); + void append(NativeByteBuffer *buffer); + bool hasData(); + void get(NativeByteBuffer *dst); + void discard(uint32_t count); + void clean(); + +private: + std::vector buffersQueue; +}; + +#endif diff --git a/TMessagesProj/jni/tgnet/Config.cpp b/TMessagesProj/jni/tgnet/Config.cpp new file mode 100644 index 00000000..6da1995e --- /dev/null +++ b/TMessagesProj/jni/tgnet/Config.cpp @@ -0,0 +1,125 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include +#include +#include "Config.h" +#include "ConnectionsManager.h" +#include "FileLog.h" +#include "BuffersStorage.h" + +Config::Config(std::string fileName) { + configPath = ConnectionsManager::getInstance().currentConfigPath + fileName; + backupPath = configPath + ".bak"; + FILE *backup = fopen(backupPath.c_str(), "rb"); + if (backup != nullptr) { + DEBUG_D("Config(%p, %s) backup file found %s", this, configPath.c_str(), backupPath.c_str()); + fclose(backup); + remove(configPath.c_str()); + rename(backupPath.c_str(), configPath.c_str()); + } +} + +NativeByteBuffer *Config::readConfig() { + NativeByteBuffer *buffer = nullptr; + FILE *file = fopen(configPath.c_str(), "rb"); + if (file != nullptr) { + fseek(file, 0, SEEK_END); + long fileSize = ftell(file); + if (fseek(file, 0, SEEK_SET)) { + DEBUG_E("Config(%p, %s) failed fseek to begin, reopen it", this, configPath.c_str()); + fclose(file); + file = fopen(configPath.c_str(), "rb"); + } + uint32_t size = 0; + int bytesRead = fread(&size, sizeof(uint32_t), 1, file); + DEBUG_D("Config(%p, %s) load, size = %u, fileSize = %u", this, configPath.c_str(), size, (uint32_t) fileSize); + if (bytesRead > 0 && size > 0 && (int32_t) size < fileSize) { + buffer = BuffersStorage::getInstance().getFreeBuffer(size); + if (fread(buffer->bytes(), sizeof(uint8_t), size, file) != size) { + buffer->reuse(); + buffer = nullptr; + } + } + fclose(file); + } + return buffer; +} + +void Config::writeConfig(NativeByteBuffer *buffer) { + DEBUG_D("Config(%p, %s) start write config", this, configPath.c_str()); + FILE *file = fopen(configPath.c_str(), "rb"); + FILE *backup = fopen(backupPath.c_str(), "rb"); + bool error = false; + if (file != nullptr) { + if (backup == nullptr) { + fclose(file); + if (rename(configPath.c_str(), backupPath.c_str()) != 0) { + DEBUG_E("Config(%p) unable to rename file %s to backup file %s", this, configPath.c_str(), backupPath.c_str()); + error = true; + } + } else { + fclose(file); + fclose(backup); + remove(configPath.c_str()); + } + } + if (error) { + return; + } + file = fopen(configPath.c_str(), "wb"); + if (chmod(configPath.c_str(), 0660)) { + DEBUG_E("Config(%p, %s) chmod failed", this, configPath.c_str()); + } + if (file == nullptr) { + DEBUG_E("Config(%p, %s) unable to open file for writing", this, configPath.c_str()); + return; + } + uint32_t size = buffer->position(); + if (fwrite(&size, sizeof(uint32_t), 1, file) == 1) { + if (fwrite(buffer->bytes(), sizeof(uint8_t), size, file) != size) { + DEBUG_E("Config(%p, %s) failed to write config data to file", this, configPath.c_str()); + error = true; + } + } else { + DEBUG_E("Config(%p, %s) failed to write config size to file", this, configPath.c_str()); + error = true; + } + if (fflush(file)) { + DEBUG_E("Config(%p, %s) fflush failed", this, configPath.c_str()); + error = true; + } + int fd = fileno(file); + if (fd == -1) { + DEBUG_E("Config(%p, %s) fileno failed", this, configPath.c_str()); + error = true; + } else { + DEBUG_D("Config(%p, %s) fileno = %d", this, configPath.c_str(), fd); + } + if (fd != -1 && fsync(fd) == -1) { + DEBUG_E("Config(%p, %s) fsync failed", this, configPath.c_str()); + error = true; + } + if (fclose(file)) { + DEBUG_E("Config(%p, %s) fclose failed", this, configPath.c_str()); + error = true; + } + if (error) { + DEBUG_E("Config(%p, %s) failed to write config", this, configPath.c_str()); + if (remove(configPath.c_str())) { + DEBUG_E("Config(%p, %s) remove config failed", this, configPath.c_str()); + } + } else { + if (remove(backupPath.c_str())) { + DEBUG_E("Config(%p, %s) remove backup failed failed", this, configPath.c_str()); + } + } + if (!error) { + DEBUG_D("Config(%p, %s) config write ok", this, configPath.c_str()); + } +} diff --git a/TMessagesProj/jni/tgnet/Config.h b/TMessagesProj/jni/tgnet/Config.h new file mode 100644 index 00000000..783ec65f --- /dev/null +++ b/TMessagesProj/jni/tgnet/Config.h @@ -0,0 +1,28 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef CONFIG_H +#define CONFIG_H + +#include +#include "NativeByteBuffer.h" + +class Config { + +public: + Config(std::string fileName); + + NativeByteBuffer *readConfig(); + void writeConfig(NativeByteBuffer *buffer); + +private: + std::string configPath; + std::string backupPath; +}; + +#endif diff --git a/TMessagesProj/jni/tgnet/Connection.cpp b/TMessagesProj/jni/tgnet/Connection.cpp new file mode 100644 index 00000000..9ea752b8 --- /dev/null +++ b/TMessagesProj/jni/tgnet/Connection.cpp @@ -0,0 +1,438 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include +#include +#include "Connection.h" +#include "ConnectionsManager.h" +#include "BuffersStorage.h" +#include "FileLog.h" +#include "Timer.h" +#include "Datacenter.h" +#include "NativeByteBuffer.h" + +static uint32_t lastConnectionToken = 1; + +Connection::Connection(Datacenter *datacenter, ConnectionType type) { + currentDatacenter = datacenter; + connectionType = type; + genereateNewSessionId(); + connectionState = TcpConnectionStageIdle; + reconnectTimer = new Timer([&] { + reconnectTimer->stop(); + connect(); + }); +} + +Connection::~Connection() { + if (reconnectTimer != nullptr) { + reconnectTimer->stop(); + delete reconnectTimer; + reconnectTimer = nullptr; + } +} + +void Connection::suspendConnection() { + reconnectTimer->stop(); + if (connectionState == TcpConnectionStageIdle || connectionState == TcpConnectionStageSuspended) { + return; + } + DEBUG_D("connection(%p, dc%u, type %d) suspend", this, currentDatacenter->getDatacenterId(), connectionType); + connectionState = TcpConnectionStageSuspended; + dropConnection(); + ConnectionsManager::getInstance().onConnectionClosed(this); + firstPacketSent = false; + if (restOfTheData != nullptr) { + restOfTheData->reuse(); + restOfTheData = nullptr; + } + lastPacketLength = 0; + connectionToken = 0; + wasConnected = false; +} + +void Connection::onReceivedData(NativeByteBuffer *buffer) { + AES_ctr128_encrypt(buffer->bytes(), buffer->bytes(), buffer->limit(), &decryptKey, decryptIv, decryptCount, &decryptNum); + + failedConnectionCount = 0; + + NativeByteBuffer *parseLaterBuffer = nullptr; + if (restOfTheData != nullptr) { + if (lastPacketLength == 0) { + if (restOfTheData->capacity() - restOfTheData->position() >= buffer->limit()) { + restOfTheData->limit(restOfTheData->position() + buffer->limit()); + restOfTheData->writeBytes(buffer); + buffer = restOfTheData; + } else { + NativeByteBuffer *newBuffer = BuffersStorage::getInstance().getFreeBuffer(restOfTheData->limit() + buffer->limit()); + restOfTheData->rewind(); + newBuffer->writeBytes(restOfTheData); + newBuffer->writeBytes(buffer); + buffer = newBuffer; + restOfTheData->reuse(); + restOfTheData = newBuffer; + } + } else { + uint32_t len; + if (lastPacketLength - restOfTheData->position() <= buffer->limit()) { + len = lastPacketLength - restOfTheData->position(); + } else { + len = buffer->limit(); + } + uint32_t oldLimit = buffer->limit(); + buffer->limit(len); + restOfTheData->writeBytes(buffer); + buffer->limit(oldLimit); + if (restOfTheData->position() == lastPacketLength) { + parseLaterBuffer = buffer->hasRemaining() ? buffer : nullptr; + buffer = restOfTheData; + } else { + return; + } + } + } + + buffer->rewind(); + + while (buffer->hasRemaining()) { + if (!hasSomeDataSinceLastConnect) { + currentDatacenter->storeCurrentAddressAndPortNum(); + isTryingNextPort = false; + if (connectionType == ConnectionTypePush) { + setTimeout(60 * 15); + } else { + setTimeout(25); + } + } + hasSomeDataSinceLastConnect = true; + + uint32_t currentPacketLength = 0; + uint32_t mark = buffer->position(); + uint8_t fByte = buffer->readByte(nullptr); + + if ((fByte & (1 << 7)) != 0) { + buffer->position(mark); + if (buffer->remaining() < 4) { + NativeByteBuffer *reuseLater = restOfTheData; + restOfTheData = BuffersStorage::getInstance().getFreeBuffer(16384); + restOfTheData->writeBytes(buffer); + restOfTheData->limit(restOfTheData->position()); + lastPacketLength = 0; + if (reuseLater != nullptr) { + reuseLater->reuse(); + } + break; + } + int32_t ackId = buffer->readBigInt32(nullptr) & (~(1 << 31)); + ConnectionsManager::getInstance().onConnectionQuickAckReceived(this, ackId); + continue; + } + + if (fByte != 0x7f) { + currentPacketLength = ((uint32_t) fByte) * 4; + } else { + buffer->position(mark); + if (buffer->remaining() < 4) { + if (restOfTheData == nullptr || (restOfTheData != nullptr && restOfTheData->position() != 0)) { + NativeByteBuffer *reuseLater = restOfTheData; + restOfTheData = BuffersStorage::getInstance().getFreeBuffer(16384); + restOfTheData->writeBytes(buffer); + restOfTheData->limit(restOfTheData->position()); + lastPacketLength = 0; + if (reuseLater != nullptr) { + reuseLater->reuse(); + } + } else { + restOfTheData->position(restOfTheData->limit()); + } + break; + } + currentPacketLength = ((uint32_t) buffer->readInt32(nullptr) >> 8) * 4; + } + + if (currentPacketLength % 4 != 0 || currentPacketLength > 2 * 1024 * 1024) { + DEBUG_E("connection(%p, dc%u, type %d) received invalid packet length", this, currentDatacenter->getDatacenterId(), connectionType); + reconnect(); + return; + } + + if (currentPacketLength < buffer->remaining()) { + DEBUG_E("connection(%p, dc%u, type %d) received message len %u but packet larger %u", this, currentDatacenter->getDatacenterId(), connectionType, currentPacketLength, buffer->remaining()); + } else if (currentPacketLength == buffer->remaining()) { + DEBUG_E("connection(%p, dc%u, type %d) received message len %u equal to packet size", this, currentDatacenter->getDatacenterId(), connectionType, currentPacketLength); + } else { + DEBUG_E("connection(%p, dc%u, type %d) received packet size less(%u) then message size(%u)", this, currentDatacenter->getDatacenterId(), connectionType, buffer->remaining(), currentPacketLength); + + NativeByteBuffer *reuseLater = nullptr; + uint32_t len = currentPacketLength + (fByte != 0x7f ? 1 : 4); + if (restOfTheData != nullptr && restOfTheData->capacity() < len) { + reuseLater = restOfTheData; + restOfTheData = nullptr; + } + if (restOfTheData == nullptr) { + buffer->position(mark); + restOfTheData = BuffersStorage::getInstance().getFreeBuffer(len); + restOfTheData->writeBytes(buffer); + } else { + restOfTheData->position(restOfTheData->limit()); + restOfTheData->limit(len); + } + lastPacketLength = len; + if (reuseLater != nullptr) { + reuseLater->reuse(); + } + return; + } + + uint32_t old = buffer->limit(); + buffer->limit(buffer->position() + currentPacketLength); + ConnectionsManager::getInstance().onConnectionDataReceived(this, buffer, currentPacketLength); + buffer->position(buffer->limit()); + buffer->limit(old); + + if (restOfTheData != nullptr) { + if ((lastPacketLength != 0 && restOfTheData->position() == lastPacketLength) || (lastPacketLength == 0 && !restOfTheData->hasRemaining())) { + restOfTheData->reuse(); + restOfTheData = nullptr; + } else { + DEBUG_E("compact occured"); + restOfTheData->compact(); + restOfTheData->limit(restOfTheData->position()); + restOfTheData->position(0); + } + } + + if (parseLaterBuffer != nullptr) { + buffer = parseLaterBuffer; + parseLaterBuffer = nullptr; + } + } +} + +void Connection::connect() { + if (!ConnectionsManager::getInstance().isNetworkAvailable()) { + ConnectionsManager::getInstance().onConnectionClosed(this); + return; + } + if ((connectionState == TcpConnectionStageConnected || connectionState == TcpConnectionStageConnecting)) { + return; + } + connectionState = TcpConnectionStageConnecting; + bool ipv6 = ConnectionsManager::getInstance().isIpv6Enabled(); + if (connectionType == ConnectionTypeDownload) { + currentAddressFlags = 2; + hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags | (ipv6 ? 1 : 0)); + if (hostAddress.empty()) { + currentAddressFlags = 0; + hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags | (ipv6 ? 1 : 0)); + } + if (hostAddress.empty() && ipv6) { + currentAddressFlags = 2; + hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags); + if (hostAddress.empty()) { + currentAddressFlags = 0; + hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags); + } + } + } else { + currentAddressFlags = 0; + hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags | (ipv6 ? 1 : 0)); + if (ipv6 && hostAddress.empty()) { + hostAddress = currentDatacenter->getCurrentAddress(currentAddressFlags); + } + } + hostPort = (uint16_t) currentDatacenter->getCurrentPort(currentAddressFlags); + + reconnectTimer->stop(); + + DEBUG_D("connection(%p, dc%u, type %d) connecting (%s:%hu)", this, currentDatacenter->getDatacenterId(), connectionType, hostAddress.c_str(), hostPort); + firstPacketSent = false; + if (restOfTheData != nullptr) { + restOfTheData->reuse(); + restOfTheData = nullptr; + } + lastPacketLength = 0; + wasConnected = false; + hasSomeDataSinceLastConnect = false; + openConnection(hostAddress, hostPort, ipv6); + if (connectionType == ConnectionTypePush) { + if (isTryingNextPort) { + setTimeout(20); + } else { + setTimeout(30); + } + } else { + if (isTryingNextPort) { + setTimeout(8); + } else { + if (connectionType == ConnectionTypeUpload) { + setTimeout(25); + } else { + setTimeout(15); + } + } + } +} + +void Connection::reconnect() { + suspendConnection(); + connectionState = TcpConnectionStageReconnecting; + connect(); +} + +void Connection::sendData(NativeByteBuffer *buff, bool reportAck) { + if (buff == nullptr) { + return; + } + buff->rewind(); + if (connectionState == TcpConnectionStageIdle || connectionState == TcpConnectionStageReconnecting || connectionState == TcpConnectionStageSuspended) { + connect(); + } + + if (isDisconnected()) { + buff->reuse(); + DEBUG_D("connection(%p, dc%u, type %d) disconnected, don't send data", this, currentDatacenter->getDatacenterId(), connectionType); + return; + } + + uint32_t bufferLen = 0; + uint32_t packetLength = buff->limit() / 4; + + if (packetLength < 0x7f) { + bufferLen++; + } else { + bufferLen += 4; + } + if (!firstPacketSent) { + bufferLen += 64; + } + + NativeByteBuffer *buffer = BuffersStorage::getInstance().getFreeBuffer(bufferLen); + uint8_t *bytes = buffer->bytes(); + + if (!firstPacketSent) { + buffer->position(64); + static uint8_t temp[64]; + while (true) { + RAND_bytes(bytes, 64); + uint32_t val = (bytes[3] << 24) | (bytes[2] << 16) | (bytes[1] << 8) | (bytes[0]); + uint32_t val2 = (bytes[7] << 24) | (bytes[6] << 16) | (bytes[5] << 8) | (bytes[4]); + if (bytes[0] != 0xef && val != 0x44414548 && val != 0x54534f50 && val != 0x20544547 && val != 0x4954504f && val != 0xeeeeeeee && val2 != 0x00000000) { + bytes[56] = bytes[57] = bytes[58] = bytes[59] = 0xef; + break; + } + } + for (int a = 0; a < 48; a++) { + temp[a] = bytes[55 - a]; + } + + encryptNum = decryptNum = 0; + memset(encryptCount, 0, 16); + memset(decryptCount, 0, 16); + + if (AES_set_encrypt_key(bytes + 8, 256, &encryptKey) < 0) { + DEBUG_E("unable to set encryptKey"); + exit(1); + } + memcpy(encryptIv, bytes + 40, 16); + + if (AES_set_encrypt_key(temp, 256, &decryptKey) < 0) { + DEBUG_E("unable to set decryptKey"); + exit(1); + } + memcpy(decryptIv, temp + 32, 16); + + AES_ctr128_encrypt(bytes, temp, 64, &encryptKey, encryptIv, encryptCount, &encryptNum); + memcpy(bytes + 56, temp + 56, 8); + + firstPacketSent = true; + } + if (packetLength < 0x7f) { + if (reportAck) { + packetLength |= (1 << 7); + } + buffer->writeByte((uint8_t) packetLength); + bytes += (buffer->limit() - 1); + AES_ctr128_encrypt(bytes, bytes, 1, &encryptKey, encryptIv, encryptCount, &encryptNum); + } else { + packetLength = (packetLength << 8) + 0x7f; + if (reportAck) { + packetLength |= (1 << 7); + } + buffer->writeInt32(packetLength); + bytes += (buffer->limit() - 4); + AES_ctr128_encrypt(bytes, bytes, 4, &encryptKey, encryptIv, encryptCount, &encryptNum); + } + + buffer->rewind(); + writeBuffer(buffer); + buff->rewind(); + AES_ctr128_encrypt(buff->bytes(), buff->bytes(), buff->limit(), &encryptKey, encryptIv, encryptCount, &encryptNum); + writeBuffer(buff); +} + +void Connection::onDisconnected(int reason) { + reconnectTimer->stop(); + DEBUG_D("connection(%p, dc%u, type %d) disconnected with reason %d", this, currentDatacenter->getDatacenterId(), connectionType, reason); + bool switchToNextPort = wasConnected && !hasSomeDataSinceLastConnect && reason == 2; + firstPacketSent = false; + if (restOfTheData != nullptr) { + restOfTheData->reuse(); + restOfTheData = nullptr; + } + connectionToken = 0; + lastPacketLength = 0; + wasConnected = false; + if (connectionState != TcpConnectionStageSuspended && connectionState != TcpConnectionStageIdle) { + connectionState = TcpConnectionStageIdle; + } + ConnectionsManager::getInstance().onConnectionClosed(this); + + uint32_t datacenterId = currentDatacenter->getDatacenterId(); + if (connectionState == TcpConnectionStageIdle && connectionType == ConnectionTypeGeneric && (currentDatacenter->isHandshaking() || datacenterId == ConnectionsManager::getInstance().currentDatacenterId || datacenterId == ConnectionsManager::getInstance().movingToDatacenterId)) { + connectionState = TcpConnectionStageReconnecting; + failedConnectionCount++; + if (failedConnectionCount == 1) { + if (hasSomeDataSinceLastConnect) { + willRetryConnectCount = 5; + } else { + willRetryConnectCount = 1; + } + } + if (ConnectionsManager::getInstance().isNetworkAvailable()) { + isTryingNextPort = true; + if (failedConnectionCount > willRetryConnectCount || switchToNextPort) { + currentDatacenter->nextAddressOrPort(currentAddressFlags); + failedConnectionCount = 0; + } + } + DEBUG_D("connection(%p, dc%u, type %d) reconnect %s:%hu", this, currentDatacenter->getDatacenterId(), connectionType, hostAddress.c_str(), hostPort); + reconnectTimer->setTimeout(1000, false); + reconnectTimer->start(); + } +} + +void Connection::onConnected() { + connectionState = TcpConnectionStageConnected; + connectionToken = lastConnectionToken++; + wasConnected = true; + DEBUG_D("connection(%p, dc%u, type %d) connected to %s:%hu", this, currentDatacenter->getDatacenterId(), connectionType, hostAddress.c_str(), hostPort); + ConnectionsManager::getInstance().onConnectionConnected(this); +} + +Datacenter *Connection::getDatacenter() { + return currentDatacenter; +} + +ConnectionType Connection::getConnectionType() { + return connectionType; +} + +uint32_t Connection::getConnectionToken() { + return connectionToken; +} diff --git a/TMessagesProj/jni/tgnet/Connection.h b/TMessagesProj/jni/tgnet/Connection.h new file mode 100644 index 00000000..76da54f4 --- /dev/null +++ b/TMessagesProj/jni/tgnet/Connection.h @@ -0,0 +1,85 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef CONNECTION_H +#define CONNECTION_H + +#include +#include +#include +#include +#include "ConnectionSession.h" +#include "ConnectionSocket.h" +#include "Defines.h" + +class Datacenter; +class Timer; +class ByteStream; + +class Connection : public ConnectionSession, public ConnectionSocket { + +public: + + Connection(Datacenter *datacenter, ConnectionType type); + ~Connection(); + + void connect(); + void suspendConnection(); + void sendData(NativeByteBuffer *buffer, bool reportAck); + uint32_t getConnectionToken(); + ConnectionType getConnectionType(); + Datacenter *getDatacenter(); + +protected: + + void onReceivedData(NativeByteBuffer *buffer) override; + void onDisconnected(int reason) override; + void onConnected() override; + void reconnect(); + +private: + + enum TcpConnectionState { + TcpConnectionStageIdle, + TcpConnectionStageConnecting, + TcpConnectionStageReconnecting, + TcpConnectionStageConnected, + TcpConnectionStageSuspended + }; + + TcpConnectionState connectionState = TcpConnectionStageIdle; + uint32_t connectionToken = 0; + std::string hostAddress; + uint16_t hostPort; + uint16_t failedConnectionCount; + Datacenter *currentDatacenter; + uint32_t currentAddressFlags; + ConnectionType connectionType; + bool firstPacketSent = false; + NativeByteBuffer *restOfTheData = nullptr; + uint32_t lastPacketLength = 0; + bool hasSomeDataSinceLastConnect = false; + bool isTryingNextPort = false; + bool wasConnected = false; + uint32_t willRetryConnectCount = 5; + Timer *reconnectTimer; + + AES_KEY encryptKey; + uint8_t encryptIv[16]; + uint32_t encryptNum; + uint8_t encryptCount[16]; + + AES_KEY decryptKey; + uint8_t decryptIv[16]; + uint32_t decryptNum; + uint8_t decryptCount[16]; + + friend class ConnectionsManager; +}; + +#endif diff --git a/TMessagesProj/jni/tgnet/ConnectionSession.cpp b/TMessagesProj/jni/tgnet/ConnectionSession.cpp new file mode 100644 index 00000000..8a215e40 --- /dev/null +++ b/TMessagesProj/jni/tgnet/ConnectionSession.cpp @@ -0,0 +1,99 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include +#include +#include "ConnectionSession.h" +#include "MTProtoScheme.h" +#include "ConnectionsManager.h" +#include "NativeByteBuffer.h" + +void ConnectionSession::recreateSession() { + processedMessageIds.clear(); + messagesIdsForConfirmation.clear(); + processedSessionChanges.clear(); + nextSeqNo = 0; + + genereateNewSessionId(); +} + +void ConnectionSession::genereateNewSessionId() { + int64_t newSessionId; + RAND_bytes((uint8_t *) &newSessionId, 8); +#if USE_DEBUG_SESSION + sessionId = (0xabcd000000000000L | (newSessionId & 0x0000ffffffffffffL)); +#else + sessionId = newSessionId; +#endif +} + +void ConnectionSession::setSessionId(int64_t id) { + sessionId = id; +} + +int64_t ConnectionSession::getSissionId() { + return sessionId; +} + +uint32_t ConnectionSession::generateMessageSeqNo(bool increment) { + uint32_t value = nextSeqNo; + if (increment) { + nextSeqNo++; + } + return value * 2 + (increment ? 1 : 0); +} + +bool ConnectionSession::isMessageIdProcessed(int64_t messageId) { + return std::find(processedMessageIds.begin(), processedMessageIds.end(), messageId) != processedMessageIds.end(); +} + +void ConnectionSession::addProcessedMessageId(int64_t messageId) { + if (processedMessageIds.size() > 300) { + processedMessageIds.erase(processedMessageIds.begin(), processedMessageIds.begin() + 100); + } + processedMessageIds.push_back(messageId); +} + +bool ConnectionSession::hasMessagesToConfirm() { + return !messagesIdsForConfirmation.empty(); +} + +void ConnectionSession::addMessageToConfirm(int64_t messageId) { + if (std::find(processedMessageIds.begin(), processedMessageIds.end(), messageId) != processedMessageIds.end()) { + return; + } + messagesIdsForConfirmation.push_back(messageId); +} + +NetworkMessage *ConnectionSession::generateConfirmationRequest() { + NetworkMessage *networkMessage = nullptr; + + if (!messagesIdsForConfirmation.empty()) { + TL_msgs_ack *msgAck = new TL_msgs_ack(); + msgAck->msg_ids.insert(msgAck->msg_ids.begin(), messagesIdsForConfirmation.begin(), messagesIdsForConfirmation.end()); + NativeByteBuffer *os = new NativeByteBuffer(true); + msgAck->serializeToStream(os); + networkMessage = new NetworkMessage(); + networkMessage->message = std::unique_ptr(new TL_message); + networkMessage->message->msg_id = ConnectionsManager::getInstance().generateMessageId(); + networkMessage->message->seqno = generateMessageSeqNo(false); + networkMessage->message->bytes = os->capacity(); + networkMessage->message->body = std::unique_ptr(msgAck); + messagesIdsForConfirmation.clear(); + } + + return networkMessage; +} + +bool ConnectionSession::isSessionProcessed(int64_t sessionId) { + return std::find(processedSessionChanges.begin(), processedSessionChanges.end(), sessionId) != processedSessionChanges.end(); +} + +void ConnectionSession::addProcessedSession(int64_t sessionId) { + processedSessionChanges.push_back(sessionId); +} diff --git a/TMessagesProj/jni/tgnet/ConnectionSession.h b/TMessagesProj/jni/tgnet/ConnectionSession.h new file mode 100644 index 00000000..380304a9 --- /dev/null +++ b/TMessagesProj/jni/tgnet/ConnectionSession.h @@ -0,0 +1,42 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef CONNECTIONSESSION_H +#define CONNECTIONSESSION_H + +#include +#include +#include "Defines.h" + +class ConnectionSession { + +public: + void recreateSession(); + void genereateNewSessionId(); + void setSessionId(int64_t id); + int64_t getSissionId(); + uint32_t generateMessageSeqNo(bool increment); + bool isMessageIdProcessed(int64_t messageId); + void addProcessedMessageId(int64_t messageId); + bool hasMessagesToConfirm(); + void addMessageToConfirm(int64_t messageId); + NetworkMessage *generateConfirmationRequest(); + bool isSessionProcessed(int64_t sessionId); + void addProcessedSession(int64_t sessionId); + +private: + int64_t sessionId; + uint32_t nextSeqNo = 0; + + std::vector processedMessageIds; + std::vector messagesIdsForConfirmation; + std::vector processedSessionChanges; +}; + + +#endif diff --git a/TMessagesProj/jni/tgnet/ConnectionSocket.cpp b/TMessagesProj/jni/tgnet/ConnectionSocket.cpp new file mode 100644 index 00000000..095ecd48 --- /dev/null +++ b/TMessagesProj/jni/tgnet/ConnectionSocket.cpp @@ -0,0 +1,226 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ByteStream.h" +#include "ConnectionSocket.h" +#include "FileLog.h" +#include "Defines.h" +#include "ConnectionsManager.h" +#include "EventObject.h" +#include "Timer.h" +#include "NativeByteBuffer.h" + +#ifndef EPOLLRDHUP +#define EPOLLRDHUP 0x2000 +#endif + +ConnectionSocket::ConnectionSocket() { + outgoingByteStream = new ByteStream(); + lastEventTime = ConnectionsManager::getInstance().getCurrentTimeMillis(); + eventObject = new EventObject(this, EventObjectTypeConnection); +} + +ConnectionSocket::~ConnectionSocket() { + if (outgoingByteStream != nullptr) { + delete outgoingByteStream; + outgoingByteStream = nullptr; + } + if (eventObject != nullptr) { + delete eventObject; + eventObject = nullptr; + } +} + +void ConnectionSocket::openConnection(std::string address, uint16_t port, bool ipv6) { + int epolFd = ConnectionsManager::getInstance().epolFd; + + if ((socketFd = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0)) < 0) { + DEBUG_E("connection(%p) can't create socket", this); + closeSocket(1); + return; + } + + memset(&socketAddress, 0, sizeof(sockaddr_in)); + memset(&socketAddress6, 0, sizeof(sockaddr_in6)); + + if (ipv6) { + socketAddress6.sin6_family = AF_INET6; + socketAddress6.sin6_port = htons(port); + if (inet_pton(AF_INET6, address.c_str(), &socketAddress6.sin6_addr.s6_addr) != 1) { + DEBUG_E("connection(%p) bad ipv6 %s", this, address.c_str()); + closeSocket(1); + return; + } + } else { + socketAddress.sin_family = AF_INET; + socketAddress.sin_port = htons(port); + if (inet_pton(AF_INET, address.c_str(), &socketAddress.sin_addr.s_addr) != 1) { + DEBUG_E("connection(%p) bad ipv4 %s", this, address.c_str()); + closeSocket(1); + return; + } + } + + int yes = 1; + if (setsockopt(socketFd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(int))) { + DEBUG_E("connection(%p) set TCP_NODELAY failed", this); + } + + if (fcntl(socketFd, F_SETFL, O_NONBLOCK) == -1) { + DEBUG_E("connection(%p) set O_NONBLOCK failed", this); + closeSocket(1); + return; + } + + if (connect(socketFd, (ipv6 ? (sockaddr *) &socketAddress6 : (sockaddr *) &socketAddress), (socklen_t) (ipv6 ? sizeof(sockaddr_in6) : sizeof(sockaddr_in))) == -1 && errno != EINPROGRESS) { + closeSocket(1); + } else { + eventMask.events = EPOLLOUT | EPOLLIN | EPOLLRDHUP | EPOLLERR | EPOLLET; + eventMask.data.ptr = eventObject; + if (epoll_ctl(epolFd, EPOLL_CTL_ADD, socketFd, &eventMask) != 0) { + DEBUG_E("connection(%p) epoll_ctl, adding socket failed", this); + closeSocket(1); + } + } +} + +bool ConnectionSocket::checkSocketError() { + if (socketFd < 0) { + return true; + } + int ret; + int code; + socklen_t len = sizeof(int); + ret = getsockopt(socketFd, SOL_SOCKET, SO_ERROR, &code, &len); + return (ret || code) != 0; +} + +void ConnectionSocket::closeSocket(int reason) { + lastEventTime = ConnectionsManager::getInstance().getCurrentTimeMillis(); + ConnectionsManager::getInstance().detachConnection(this); + if (socketFd >= 0) { + epoll_ctl(ConnectionsManager::getInstance().epolFd, EPOLL_CTL_DEL, socketFd, NULL); + if (close(socketFd) != 0) { + DEBUG_E("connection(%p) unable to close socket", this); + } + socketFd = -1; + } + onConnectedSent = false; + outgoingByteStream->clean(); + onDisconnected(reason); +} + +void ConnectionSocket::onEvent(uint32_t events) { + if (events & EPOLLIN) { + if (checkSocketError()) { + closeSocket(1); + return; + } else { + ssize_t readCount; + NativeByteBuffer *buffer = ConnectionsManager::getInstance().networkBuffer; + while (true) { + buffer->rewind(); + readCount = recv(socketFd, buffer->bytes(), READ_BUFFER_SIZE, 0); + if (readCount < 0) { + closeSocket(1); + DEBUG_E("connection(%p) recv failed", this); + return; + } + if (readCount > 0) { + buffer->limit((uint32_t) readCount); + lastEventTime = ConnectionsManager::getInstance().getCurrentTimeMillis(); + onReceivedData(buffer); + } + if (readCount != READ_BUFFER_SIZE) { + break; + } + } + } + } + if (events & EPOLLOUT) { + if (checkSocketError() != 0) { + closeSocket(1); + return; + } else { + if (!onConnectedSent) { + ConnectionsManager::getInstance().attachConnection(this); + lastEventTime = ConnectionsManager::getInstance().getCurrentTimeMillis(); + onConnected(); + onConnectedSent = true; + } + NativeByteBuffer *buffer = ConnectionsManager::getInstance().networkBuffer; + buffer->clear(); + outgoingByteStream->get(buffer); + buffer->flip(); + + uint32_t remaining = buffer->remaining(); + if (remaining) { + ssize_t sentLength; + if ((sentLength = send(socketFd, buffer->bytes(), remaining, 0)) < 0) { + DEBUG_E("connection(%p) send failed", this); + closeSocket(1); + return; + } else { + outgoingByteStream->discard((uint32_t) sentLength); + adjustWriteOp(); + } + } + } + } + if ((events & EPOLLRDHUP) || (events & EPOLLHUP)) { + closeSocket(1); + return; + } + if (events & EPOLLERR) { + DEBUG_E("connection(%p) epoll error", this); + return; + } +} + +void ConnectionSocket::writeBuffer(NativeByteBuffer *buffer) { + outgoingByteStream->append(buffer); + adjustWriteOp(); +} + +void ConnectionSocket::adjustWriteOp() { + eventMask.events = EPOLLIN | EPOLLRDHUP | EPOLLERR | EPOLLET; + if (outgoingByteStream->hasData()) { + eventMask.events |= EPOLLOUT; + } + eventMask.data.ptr = eventObject; + if (epoll_ctl(ConnectionsManager::getInstance().epolFd, EPOLL_CTL_MOD, socketFd, &eventMask) != 0) { + DEBUG_E("connection(%p) epoll_ctl, modify socket failed", this); + closeSocket(1); + } +} + +void ConnectionSocket::setTimeout(time_t time) { + timeout = time; + lastEventTime = ConnectionsManager::getInstance().getCurrentTimeMillis(); +} + +void ConnectionSocket::checkTimeout(int64_t now) { + if (timeout != 0 && (now - lastEventTime) > (int64_t) timeout * 1000) { + closeSocket(2); + } +} + +bool ConnectionSocket::isDisconnected() { + return socketFd < 0; +} + +void ConnectionSocket::dropConnection() { + closeSocket(0); +} diff --git a/TMessagesProj/jni/tgnet/ConnectionSocket.h b/TMessagesProj/jni/tgnet/ConnectionSocket.h new file mode 100644 index 00000000..ca452fae --- /dev/null +++ b/TMessagesProj/jni/tgnet/ConnectionSocket.h @@ -0,0 +1,59 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef CONNECTIONSOCKET_H +#define CONNECTIONSOCKET_H + +#include +#include +#include + +class NativeByteBuffer; +class ConnectionsManager; +class ByteStream; +class EventObject; + +class ConnectionSocket { + +public: + ConnectionSocket(); + virtual ~ConnectionSocket(); + + void writeBuffer(NativeByteBuffer *buffer); + void openConnection(std::string address, uint16_t port, bool ipv6); + void setTimeout(time_t timeout); + bool isDisconnected(); + void dropConnection(); + +protected: + void onEvent(uint32_t events); + void checkTimeout(int64_t now); + virtual void onReceivedData(NativeByteBuffer *buffer) = 0; + virtual void onDisconnected(int reason) = 0; + virtual void onConnected() = 0; + +private: + ByteStream *outgoingByteStream = nullptr; + struct epoll_event eventMask; + struct sockaddr_in socketAddress; + struct sockaddr_in6 socketAddress6; + int socketFd = -1; + time_t timeout = 15; + bool onConnectedSent = false; + int64_t lastEventTime = 0; + EventObject *eventObject; + + bool checkSocketError(); + void closeSocket(int reason); + void adjustWriteOp(); + + friend class EventObject; + friend class ConnectionsManager; +}; + +#endif diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.cpp b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp new file mode 100644 index 00000000..3e6f0768 --- /dev/null +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.cpp @@ -0,0 +1,2535 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ConnectionsManager.h" +#include "FileLog.h" +#include "EventObject.h" +#include "MTProtoScheme.h" +#include "NativeByteBuffer.h" +#include "Connection.h" +#include "Datacenter.h" +#include "Request.h" +#include "BuffersStorage.h" +#include "ByteArray.h" +#include "Config.h" + +#ifdef ANDROID +#include +JavaVM *javaVm = nullptr; +JNIEnv *jniEnv = nullptr; +jclass jclass_ByteBuffer = nullptr; +jmethodID jclass_ByteBuffer_allocateDirect = 0; +#endif + +static bool done = false; + +ConnectionsManager::ConnectionsManager() { + if ((epolFd = epoll_create(128)) == -1) { + DEBUG_E("unable to create epoll instance"); + exit(1); + } + int flags; + if ((flags = fcntl(epolFd, F_GETFD, NULL)) < 0) { + DEBUG_W("fcntl(%d, F_GETFD)", epolFd); + } + if (!(flags & FD_CLOEXEC)) { + if (fcntl(epolFd, F_SETFD, flags | FD_CLOEXEC) == -1) { + DEBUG_W("fcntl(%d, F_SETFD)", epolFd); + } + } + + if ((epollEvents = new epoll_event[128]) == nullptr) { + DEBUG_E("unable to allocate epoll events"); + exit(1); + } + + pipeFd = new int[2]; + if (pipe(pipeFd) != 0) { + DEBUG_E("unable to create pipe"); + exit(1); + } + + flags = fcntl(pipeFd[0], F_GETFL); + if (flags == -1) { + DEBUG_E("fcntl get pipefds[0] failed"); + exit(1); + } + if (fcntl(pipeFd[0], F_SETFL, flags | O_NONBLOCK) == -1) { + DEBUG_E("fcntl set pipefds[0] failed"); + exit(1); + } + + flags = fcntl(pipeFd[1], F_GETFL); + if (flags == -1) { + DEBUG_E("fcntl get pipefds[1] failed"); + exit(1); + } + if (fcntl(pipeFd[1], F_SETFL, flags | O_NONBLOCK) == -1) { + DEBUG_E("fcntl set pipefds[1] failed"); + exit(1); + } + + EventObject *eventObject = new EventObject(pipeFd, EventObjectPipe); + + epoll_event eventMask = {}; + eventMask.events = EPOLLIN; + eventMask.data.ptr = eventObject; + if (epoll_ctl(epolFd, EPOLL_CTL_ADD, pipeFd[0], &eventMask) != 0) { + DEBUG_E("can't add pipe to epoll"); + exit(1); + } + + networkBuffer = new NativeByteBuffer((uint32_t) READ_BUFFER_SIZE); + if (networkBuffer == nullptr) { + DEBUG_E("unable to allocate read buffer"); + exit(1); + } + + pthread_mutex_init(&mutex, NULL); +} + +ConnectionsManager::~ConnectionsManager() { + if (epolFd != 0) { + close(epolFd); + epolFd = 0; + } + pthread_mutex_destroy(&mutex); +} + +ConnectionsManager& ConnectionsManager::getInstance() { + static ConnectionsManager instance; + return instance; +} + +int ConnectionsManager::callEvents(int64_t now) { + if (!events.empty()) { + for (std::list::iterator iter = events.begin(); iter != events.end();) { + EventObject *eventObject = (*iter); + if (eventObject->time <= now) { + iter = events.erase(iter); + eventObject->onEvent(0); + } else { + int diff = (int) (eventObject->time - now); + return diff > 1000 ? 1000 : diff; + } + } + } + if (!networkPaused) { + return 1000; + } + int32_t timeToPushPing = (sendingPushPing ? 30000 : 60000 * 3) - abs(now - lastPushPingTime); + if (timeToPushPing <= 0) { + return 1000; + } + DEBUG_D("schedule next epoll wakeup in %d ms", timeToPushPing); + return timeToPushPing; +} + +void ConnectionsManager::checkPendingTasks() { + while (true) { + std::function task; + pthread_mutex_lock(&mutex); + if (pendingTasks.empty()) { + pthread_mutex_unlock(&mutex); + return; + } + task = pendingTasks.front(); + pendingTasks.pop(); + pthread_mutex_unlock(&mutex); + task(); + } +} + +void ConnectionsManager::select() { + checkPendingTasks(); + int eventsCount = epoll_wait(epolFd, epollEvents, 128, callEvents(getCurrentTimeMillis())); + checkPendingTasks(); + int64_t now = getCurrentTimeMillis(); + callEvents(now); + for (int32_t a = 0; a < eventsCount; a++) { + EventObject *eventObject = (EventObject *) epollEvents[a].data.ptr; + eventObject->onEvent(epollEvents[a].events); + } + size_t count = activeConnections.size(); + for (uint32_t a = 0; a < count; a++) { + activeConnections[a]->checkTimeout(now); + } + + Datacenter *datacenter = getDatacenterWithId(currentDatacenterId); + if (pushConnectionEnabled) { + if ((sendingPushPing && abs(now - lastPushPingTime) >= 30000) || abs(now - lastPushPingTime) >= 60000 * 3 + 10000) { + lastPushPingTime = 0; + sendingPushPing = false; + if (datacenter != nullptr) { + Connection *connection = datacenter->getPushConnection(false); + if (connection != nullptr) { + connection->suspendConnection(); + } + } + DEBUG_D("push ping timeout"); + } + if (abs(now - lastPushPingTime) >= 60000 * 3) { + DEBUG_D("time for push ping"); + lastPushPingTime = now; + if (datacenter != nullptr) { + sendPing(datacenter, true); + } + } + } + + if (lastPauseTime != 0 && abs(now - lastPauseTime) >= nextSleepTimeout) { + bool dontSleep = !requestingSaltsForDc.empty(); + if (!dontSleep) { + for (requestsIter iter = runningRequests.begin(); iter != runningRequests.end(); iter++) { + Request *request = iter->get(); + if (request->connectionType & ConnectionTypeDownload || request->connectionType & ConnectionTypeUpload) { + dontSleep = true; + break; + } + } + } + if (!dontSleep) { + for (requestsIter iter = requestsQueue.begin(); iter != requestsQueue.end(); iter++) { + Request *request = iter->get(); + if (request->connectionType & ConnectionTypeDownload || request->connectionType & ConnectionTypeUpload) { + dontSleep = true; + break; + } + } + } + if (!dontSleep) { + if (!networkPaused) { + DEBUG_D("pausing network and timers by sleep time = %d", nextSleepTimeout); + for (std::map::iterator iter = datacenters.begin(); iter != datacenters.end(); iter++) { + iter->second->suspendConnections(); + } + } + networkPaused = true; + return; + } else { + lastPauseTime = now; + DEBUG_D("don't sleep because of salt, upload or download request"); + } + } + if (networkPaused) { + networkPaused = false; + DEBUG_D("resume network and timers"); + } + + if (delegate != nullptr) { + delegate->onUpdate(); + } + if (datacenter != nullptr) { + if (datacenter->hasAuthKey()) { + if (abs(now - lastPingTime) >= 19000) { + lastPingTime = now; + sendPing(datacenter, false); + } + if (abs((int32_t) (now / 1000) - lastDcUpdateTime) >= DC_UPDATE_TIME) { + updateDcSettings(0); + } + processRequestQueue(0, 0); + } else if (!datacenter->isHandshaking()) { + datacenter->beginHandshake(true); + } + } +} + +void ConnectionsManager::scheduleTask(std::function task) { + pthread_mutex_lock(&mutex); + pendingTasks.push(task); + pthread_mutex_unlock(&mutex); + wakeup(); +} + +void ConnectionsManager::scheduleEvent(EventObject *eventObject, uint32_t time) { + eventObject->time = getCurrentTimeMillis() + time; + std::list::iterator iter; + for (iter = events.begin(); iter != events.end(); iter++) { + if ((*iter)->time > eventObject->time) { + break; + } + } + events.insert(iter, eventObject); +} + +void ConnectionsManager::removeEvent(EventObject *eventObject) { + for (std::list::iterator iter = events.begin(); iter != events.end(); iter++) { + if (*iter == eventObject) { + events.erase(iter); + break; + } + } +} + +void ConnectionsManager::wakeup() { + char ch = 'x'; + write(pipeFd[1], &ch, 1); +} + +void *ConnectionsManager::ThreadProc(void *data) { + DEBUG_D("network thread started"); +#ifdef ANDROID + javaVm->AttachCurrentThread(&jniEnv, NULL); +#endif + ConnectionsManager *networkManager = (ConnectionsManager *) (data); + if (networkManager->currentUserId != 0 && networkManager->pushConnectionEnabled) { + Datacenter *datacenter = networkManager->getDatacenterWithId(networkManager->currentDatacenterId); + if (datacenter != nullptr) { + datacenter->createPushConnection()->setSessionId(networkManager->pushSessionId); + networkManager->sendPing(datacenter, true); + } + } + do { + networkManager->select(); + } while (!done); + return nullptr; +} + +void ConnectionsManager::loadConfig() { + if (config == nullptr) { + config = new Config("tgnet.dat"); + } + NativeByteBuffer *buffer = config->readConfig(); + if (buffer != nullptr) { + uint32_t version = buffer->readUint32(nullptr); + DEBUG_D("config version = %u", version); + if (version <= configVersion) { + testBackend = buffer->readBool(nullptr); + if (buffer->readBool(nullptr)) { + currentDatacenterId = buffer->readUint32(nullptr); + timeDifference = buffer->readInt32(nullptr); + lastDcUpdateTime = buffer->readInt32(nullptr); + pushSessionId = buffer->readInt64(nullptr); + if (version >= 2) { + registeredForInternalPush = buffer->readBool(nullptr); + } + + DEBUG_D("current dc id = %u, time difference = %d, registered for push = %d", currentDatacenterId, timeDifference, (int32_t) registeredForInternalPush); + + uint32_t count = buffer->readUint32(nullptr); + for (uint32_t a = 0; a < count; a++) { + sessionsToDestroy.push_back(buffer->readInt64(nullptr)); + } + + count = buffer->readUint32(nullptr); + for (uint32_t a = 0; a < count; a++) { + Datacenter *datacenter = new Datacenter(buffer); + datacenters[datacenter->getDatacenterId()] = datacenter; + DEBUG_D("datacenter(%p) %u loaded (hasAuthKey = %d)", datacenter, datacenter->getDatacenterId(), (int) datacenter->hasAuthKey()); + } + } + } + buffer->reuse(); + } + + if (currentDatacenterId != 0 && currentUserId) { + Datacenter *datacenter = getDatacenterWithId(currentDatacenterId); + if (datacenter == nullptr || !datacenter->hasAuthKey()) { + if (datacenter != nullptr) { + DEBUG_D("reset authorization because of dc %p", datacenter); + } + currentDatacenterId = 0; + datacenters.clear(); + scheduleTask([&] { + if (delegate != nullptr) { + delegate->onLogout(); + } + }); + } + } + + initDatacenters(); + + if ((datacenters.size() != 0 && currentDatacenterId == 0) || pushSessionId == 0) { + if (pushSessionId == 0) { + RAND_bytes((uint8_t *) &pushSessionId, 8); + } + if (currentDatacenterId == 0) { + currentDatacenterId = 2; + } + saveConfig(); + } + movingToDatacenterId = DEFAULT_DATACENTER_ID; +} + +void ConnectionsManager::saveConfig() { + if (config == nullptr) { + config = new Config("tgnet.dat"); + } + NativeByteBuffer *buffer = BuffersStorage::getInstance().getFreeBuffer(32 * 1024); + buffer->writeInt32(configVersion); + buffer->writeBool(testBackend); + Datacenter *currentDatacenter = getDatacenterWithId(currentDatacenterId); + buffer->writeBool(currentDatacenter != nullptr); + if (currentDatacenter != nullptr) { + buffer->writeInt32(currentDatacenterId); + buffer->writeInt32(timeDifference); + buffer->writeInt32(lastDcUpdateTime); + buffer->writeInt64(pushSessionId); + buffer->writeBool(registeredForInternalPush); + + std::vector sessions; + currentDatacenter->getSessions(sessions); + + uint32_t count = (uint32_t) sessions.size(); + buffer->writeInt32(count); + for (uint32_t a = 0; a < count; a++) { + buffer->writeInt64(sessions[a]); + } + count = (uint32_t) datacenters.size(); + buffer->writeInt32(count); + for (std::map::iterator iter = datacenters.begin(); iter != datacenters.end(); iter++) { + iter->second->serializeToStream(buffer); + } + } + config->writeConfig(buffer); + buffer->reuse(); +} + +inline NativeByteBuffer *decompressGZip(NativeByteBuffer *data) { + int retCode; + z_stream stream; + + memset(&stream, 0, sizeof(z_stream)); + stream.avail_in = data->limit(); + stream.next_in = data->bytes(); + + retCode = inflateInit2(&stream, 15 + 32); + if (retCode != Z_OK) { + DEBUG_E("can't decompress data"); + exit(1); + } + NativeByteBuffer *result = BuffersStorage::getInstance().getFreeBuffer(data->limit() * 4); + stream.avail_out = result->capacity(); + stream.next_out = result->bytes(); + while (1) { + retCode = inflate(&stream, Z_NO_FLUSH); + if (retCode == Z_STREAM_END) { + break; + } + if (retCode == Z_OK) { + NativeByteBuffer *newResult = BuffersStorage::getInstance().getFreeBuffer(result->capacity() * 2); + memcpy(newResult->bytes(), result->bytes(), result->capacity()); + stream.avail_out = newResult->capacity() - result->capacity(); + stream.next_out = newResult->bytes() + result->capacity(); + result->reuse(); + result = newResult; + } else { + DEBUG_E("can't decompress data"); + exit(1); + } + } + result->limit((uint32_t) stream.total_out); + inflateEnd(&stream); + return result; +} + +inline NativeByteBuffer *compressGZip(NativeByteBuffer *buffer) { + if (buffer == nullptr || buffer->limit() == 0) { + return nullptr; + } + z_stream stream; + int retCode; + + memset(&stream, 0, sizeof(z_stream)); + stream.avail_in = buffer->limit(); + stream.next_in = buffer->bytes(); + + retCode = deflateInit2(&stream, Z_BEST_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); + if (retCode != Z_OK) { + DEBUG_E("%s: deflateInit2() failed with error %i", __PRETTY_FUNCTION__, retCode); + return nullptr; + } + + NativeByteBuffer *result = BuffersStorage::getInstance().getFreeBuffer(buffer->limit()); + stream.avail_out = result->limit(); + stream.next_out = result->bytes(); + retCode = deflate(&stream, Z_FINISH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + DEBUG_E("%s: deflate() failed with error %i", __PRETTY_FUNCTION__, retCode); + deflateEnd(&stream); + result->reuse(); + return nullptr; + } + if (retCode != Z_STREAM_END || stream.total_out >= buffer->limit() - 4) { + deflateEnd(&stream); + result->reuse(); + return nullptr; + } + result->limit((uint32_t) stream.total_out); + deflateEnd(&stream); + return result; +} + +int64_t ConnectionsManager::getCurrentTimeMillis() { + clock_gettime(CLOCK_REALTIME, &timeSpec); + return (int64_t) timeSpec.tv_sec * 1000 + (int64_t) timeSpec.tv_nsec / 1000000; +} + +int32_t ConnectionsManager::getCurrentTime() { + return (int32_t) (getCurrentTimeMillis() / 1000) + timeDifference; +} + +int32_t ConnectionsManager::getTimeDifference() { + return timeDifference; +} + +int64_t ConnectionsManager::generateMessageId() { + int64_t messageId = (int64_t) ((((double) getCurrentTimeMillis() + ((double) timeDifference) * 1000) * 4294967296.0) / 1000.0); + if (messageId <= lastOutgoingMessageId) { + messageId = lastOutgoingMessageId + 1; + } + while (messageId % 4 != 0) { + messageId++; + } + lastOutgoingMessageId = messageId; + return messageId; +} + +bool ConnectionsManager::isNetworkAvailable() { + return networkAvailable; +} + +void ConnectionsManager::cleanUp() { + scheduleTask([&] { + for (requestsIter iter = requestsQueue.begin(); iter != requestsQueue.end();) { + Request *request = iter->get(); + if (request->requestFlags & RequestFlagWithoutLogin) { + iter++; + continue; + } + if (request->onCompleteRequestCallback != nullptr) { + TL_error *error = new TL_error(); + error->code = -1000; + error->text = ""; + request->onComplete(nullptr, error); + delete error; + } + iter = requestsQueue.erase(iter); + } + for (requestsIter iter = runningRequests.begin(); iter != runningRequests.end();) { + Request *request = iter->get(); + if (request->requestFlags & RequestFlagWithoutLogin) { + iter++; + continue; + } + if (request->onCompleteRequestCallback != nullptr) { + TL_error *error = new TL_error(); + error->code = -1000; + error->text = ""; + request->onComplete(nullptr, error); + delete error; + } + iter = runningRequests.erase(iter); + } + quickAckIdToRequestIds.clear(); + + for (std::map::iterator iter = datacenters.begin(); iter != datacenters.end(); iter++) { + iter->second->recreateSessions(); + iter->second->authorized = false; + } + sessionsToDestroy.clear(); + currentUserId = 0; + registeredForInternalPush = false; + saveConfig(); + }); +} + +void ConnectionsManager::onConnectionClosed(Connection *connection) { + Datacenter *datacenter = connection->getDatacenter(); + if (connection->getConnectionType() == ConnectionTypeGeneric) { + if (datacenter->isHandshaking()) { + datacenter->onHandshakeConnectionClosed(connection); + } + if (datacenter->getDatacenterId() == currentDatacenterId) { + if (networkAvailable) { + if (connectionState != ConnectionStateConnecting) { + connectionState = ConnectionStateConnecting; + if (delegate != nullptr) { + delegate->onConnectionStateChanged(connectionState); + } + } + } else { + if (connectionState != ConnectionStateWaitingForNetwork) { + connectionState = ConnectionStateWaitingForNetwork; + if (delegate != nullptr) { + delegate->onConnectionStateChanged(connectionState); + } + } + } + } + } else if (connection->getConnectionType() == ConnectionTypePush) { + DEBUG_D("connection(%p) push connection closed", connection); + sendingPushPing = false; + lastPushPingTime = getCurrentTimeMillis() - 60000 * 3 + 4000; + } +} + +void ConnectionsManager::onConnectionConnected(Connection *connection) { + Datacenter *datacenter = connection->getDatacenter(); + if (connection->getConnectionType() == ConnectionTypeGeneric) { + if (datacenter->isHandshaking()) { + datacenter->onHandshakeConnectionConnected(connection); + return; + } + } + + if (datacenter->hasAuthKey()) { + if (connection->getConnectionType() == ConnectionTypePush) { + sendingPushPing = false; + lastPushPingTime = getCurrentTimeMillis(); + sendPing(datacenter, true); + } else { + if (networkPaused && lastPauseTime != 0) { + lastPauseTime = getCurrentTimeMillis(); + } + processRequestQueue(connection->getConnectionType(), datacenter->getDatacenterId()); + } + } +} + +void ConnectionsManager::onConnectionQuickAckReceived(Connection *connection, int32_t ack) { + std::map>::iterator iter = quickAckIdToRequestIds.find(ack); + if (iter == quickAckIdToRequestIds.end()) { + return; + } + for (requestsIter iter2 = runningRequests.begin(); iter2 != runningRequests.end(); iter2++) { + Request *request = iter2->get(); + if (std::find(iter->second.begin(), iter->second.end(), request->requestToken) != iter->second.end()) { + request->onQuickAck(); + } + } + quickAckIdToRequestIds.erase(iter); +} + +void ConnectionsManager::onConnectionDataReceived(Connection *connection, NativeByteBuffer *data, uint32_t length) { + bool error = false; + if (length == 4) { + int32_t code = data->readInt32(&error); + DEBUG_E("mtproto error = %d", code); + connection->reconnect(); + return; + } + uint32_t mark = data->position(); + + int64_t keyId = data->readInt64(&error); + + if (error) { + connection->reconnect(); + return; + } + + Datacenter *datacenter = connection->getDatacenter(); + + if (connectionState != ConnectionStateConnected && connection->getConnectionType() == ConnectionTypeGeneric && datacenter->getDatacenterId() == currentDatacenterId) { + connectionState = ConnectionStateConnected; + if (delegate != nullptr) { + delegate->onConnectionStateChanged(connectionState); + } + } + + if (keyId == 0) { + int64_t messageId = data->readInt64(&error); + if (error) { + connection->reconnect(); + return; + } + + if (connection->isMessageIdProcessed(messageId)) { + return; + } + + uint32_t messageLength = data->readUint32(&error); + if (error) { + connection->reconnect(); + return; + } + + if (messageLength != data->remaining()) { + DEBUG_E("connection(%p) received incorrect message length", connection); + connection->reconnect(); + return; + } + TLObject *request; + if (datacenter->isHandshaking()) { + request = datacenter->getCurrentHandshakeRequest(); + } else { + request = getRequestWithMessageId(messageId); + } + + TLObject *object = TLdeserialize(request, messageLength, data); + + if (object != nullptr) { + if (datacenter->isHandshaking()) { + datacenter->processHandshakeResponse(object, messageId); + } else { + processServerResponse(object, messageId, 0, 0, connection, 0, 0); + connection->addProcessedMessageId(messageId); + } + delete object; + } + } else { + if (length < 24 + 32 || !datacenter->decryptServerResponse(keyId, data->bytes() + mark + 8, data->bytes() + mark + 24, length - 24)) { + DEBUG_E("connection(%p) unable to decrypt server response", connection); + datacenter->switchTo443Port(); + connection->suspendConnection(); + connection->connect(); + return; + } + data->position(mark + 24); + + int64_t messageServerSalt = data->readInt64(&error); + int64_t messageSessionId = data->readInt64(&error); + + if (messageSessionId != connection->getSissionId()) { + DEBUG_E("connection(%p) received invalid message session id (0x%llx instead of 0x%llx)", connection, (uint64_t) messageSessionId, (uint64_t) connection->getSissionId()); + return; + } + + bool doNotProcess = false; + + int64_t messageId = data->readInt64(&error); + int32_t messageSeqNo = data->readInt32(&error); + uint32_t messageLength = data->readUint32(&error); + + if (connection->isMessageIdProcessed(messageId)) { + doNotProcess = true; + } + + if (messageSeqNo % 2 != 0) { + connection->addMessageToConfirm(messageId); + } + + if (!doNotProcess) { + TLObject *object = TLdeserialize(nullptr, messageLength, data); + if (object != nullptr) { + DEBUG_D("connection(%p, dc%u, type %d) received object %s", connection, datacenter->getDatacenterId(), connection->getConnectionType(), typeid(*object).name()); + processServerResponse(object, messageId, messageSeqNo, messageServerSalt, connection, 0, 0); + connection->addProcessedMessageId(messageId); + delete object; + if (connection->getConnectionType() == ConnectionTypePush) { + std::vector> messages; + sendMessagesToConnectionWithConfirmation(messages, connection, false); + } + } else { + if (delegate != nullptr) { + delegate->onUnparsedMessageReceived(0, data, connection->getConnectionType()); + } + } + } else { + std::vector> messages; + sendMessagesToConnectionWithConfirmation(messages, connection, false); + } + } +} + +TLObject *ConnectionsManager::getRequestWithMessageId(int64_t messageId) { + for (requestsIter iter = runningRequests.begin(); iter != runningRequests.end(); iter++) { + Request *request = iter->get(); + if (request->messageId == messageId) { + return request->rawRequest; + } + } + return nullptr; +} + +TLObject *ConnectionsManager::TLdeserialize(TLObject *request, uint32_t bytes, NativeByteBuffer *data) { + bool error = false; + uint32_t position = data->position(); + uint32_t constructor = data->readUint32(&error); + if (error) { + data->position(position); + return nullptr; + } + + TLObject *object = TLClassStore::TLdeserialize(data, bytes, constructor, error); + + if (error) { + if (object != nullptr) { + delete object; + } + data->position(position); + return nullptr; + } + + if (object == nullptr) { + if (request != nullptr) { + TL_api_request *apiRequest = dynamic_cast(request); + if (apiRequest != nullptr) { + object = apiRequest->deserializeResponse(data, bytes, error); + DEBUG_D("api request constructor 0x%x, don't parse", constructor); + } else { + object = request->deserializeResponse(data, constructor, error); + if (object != nullptr && error) { + delete object; + object = nullptr; + } + } + } else { + DEBUG_D("not found request to parse constructor 0x%x", constructor); + } + } + if (object == nullptr) { + data->position(position); + } + return object; +} + +void ConnectionsManager::processServerResponse(TLObject *message, int64_t messageId, int32_t messageSeqNo, int64_t messageSalt, Connection *connection, int64_t innerMsgId, int64_t containerMessageId) { + const std::type_info &typeInfo = typeid(*message); + + Datacenter *datacenter = connection->getDatacenter(); + + if (typeInfo == typeid(TL_new_session_created)) { + TL_new_session_created *response = (TL_new_session_created *) message; + + if (!connection->isSessionProcessed(response->unique_id)) { + DEBUG_D("connection(%p, dc%u, type %d) new session created (first message id: 0x%llx, server salt: 0x%llx, unique id: 0x%llx)", connection, datacenter->getDatacenterId(), connection->getConnectionType(), (uint64_t) response->first_msg_id, (uint64_t) response->server_salt, (uint64_t) response->unique_id); + + std::unique_ptr salt = std::unique_ptr(new TL_future_salt()); + salt->valid_until = salt->valid_since = getCurrentTime(); + salt->valid_until += 30 * 60; + salt->salt = response->server_salt; + datacenter->addServerSalt(salt); + + for (requestsIter iter = runningRequests.begin(); iter != runningRequests.end(); iter++) { + Request *request = iter->get(); + Datacenter *requestDatacenter = getDatacenterWithId(request->datacenterId); + if (request->messageId < response->first_msg_id && request->connectionType & connection->getConnectionType() && requestDatacenter != nullptr && requestDatacenter->getDatacenterId() == datacenter->getDatacenterId()) { + DEBUG_D("clear request %p - %s", request->rawRequest, typeid(*request->rawRequest).name()); + request->clear(true); + } + } + + saveConfig(); + + if (datacenter->getDatacenterId() == currentDatacenterId && currentUserId) { + if (connection->getConnectionType() == ConnectionTypePush) { + registerForInternalPushUpdates(); + } else if (connection->getConnectionType() == ConnectionTypeGeneric) { + if (delegate != nullptr) { + delegate->onSessionCreated(); + } + } + } + connection->addProcessedSession(response->unique_id); + } + } else if (typeInfo == typeid(TL_msg_container)) { + TL_msg_container *response = (TL_msg_container *) message; + size_t count = response->messages.size(); + for (uint32_t a = 0; a < count; a++) { + TL_message *innerMessage = response->messages[a].get(); + int64_t innerMessageId = innerMessage->msg_id; + if (innerMessage->seqno % 2 != 0) { + connection->addMessageToConfirm(innerMessageId); + } + if (connection->isMessageIdProcessed(innerMessageId)) { + continue; + } + if (innerMessage->unparsedBody != nullptr) { + if (delegate != nullptr) { + delegate->onUnparsedMessageReceived(0, innerMessage->unparsedBody.get(), connection->getConnectionType()); + } + } else { + processServerResponse(innerMessage->body.get(), 0, innerMessage->seqno, messageSalt, connection, innerMessageId, messageId); + } + connection->addProcessedMessageId(innerMessageId); + } + } else if (typeInfo == typeid(TL_pong)) { + if (connection->getConnectionType() == ConnectionTypePush) { + if (!registeredForInternalPush) { + registerForInternalPushUpdates(); + } + DEBUG_D("connection(%p, dc%u, type %d) received push ping", connection, datacenter->getDatacenterId(), connection->getConnectionType()); + sendingPushPing = false; + } else { + TL_pong *response = (TL_pong *) message; + if (response->ping_id == lastPingId) { + int64_t currentTime = getCurrentTimeMillis(); + int32_t diff = (int32_t) (currentTime / 1000) - pingTime; + + if (abs(diff) < 10) { + currentPingTime = (diff + currentPingTime) / 2; + if (messageId != 0) { + int64_t timeMessage = (int64_t) (messageId / 4294967296.0 * 1000); + timeDifference = (int32_t) ((timeMessage - currentTime) / 1000 - currentPingTime / 2); + } + } + } + } + } else if (typeInfo == typeid(TL_future_salts)) { + TL_future_salts *response = (TL_future_salts *) message; + int64_t requestMid = response->req_msg_id; + for (requestsIter iter = runningRequests.begin(); iter != runningRequests.end(); iter++) { + Request *request = iter->get(); + if (request->respondsToMessageId(requestMid)) { + request->onComplete(response, nullptr); + request->completed = true; + runningRequests.erase(iter); + break; + } + } + } else if (dynamic_cast(message)) { + DestroySessionRes *response = (DestroySessionRes *) message; + DEBUG_D("destroyed session 0x%llx (%s)", (uint64_t) response->session_id, typeInfo == typeid(TL_destroy_session_ok) ? "ok" : "not found"); + } else if (typeInfo == typeid(TL_rpc_result)) { + TL_rpc_result *response = (TL_rpc_result *) message; + int64_t resultMid = response->req_msg_id; + + bool hasResult = response->result.get() != nullptr; + bool ignoreResult = false; + if (hasResult) { + TLObject *object = response->result.get(); + DEBUG_D("connection(%p, dc%u, type %d) received rpc_result with %s", connection, datacenter->getDatacenterId(), connection->getConnectionType(), typeid(*object).name()); + } + RpcError *error = hasResult ? dynamic_cast(response->result.get()) : nullptr; + if (error != nullptr) { + DEBUG_E("connection(%p, dc%u, type %d) rpc error %d: %s", connection, datacenter->getDatacenterId(), connection->getConnectionType(), error->error_code, error->error_message.c_str()); + if (error->error_code == 303) { + uint32_t migrateToDatacenterId = DEFAULT_DATACENTER_ID; + + static std::vector migrateErrors; + if (migrateErrors.empty()) { + migrateErrors.push_back("NETWORK_MIGRATE_"); + migrateErrors.push_back("PHONE_MIGRATE_"); + migrateErrors.push_back("USER_MIGRATE_"); + } + + size_t count = migrateErrors.size(); + for (uint32_t a = 0; a < count; a++) { + std::string &possibleError = migrateErrors[a]; + if (error->error_message.find(possibleError) != std::string::npos) { + std::string num = error->error_message.substr(possibleError.size(), error->error_message.size() - possibleError.size()); + uint32_t val = (uint32_t) atoi(num.c_str()); + migrateToDatacenterId = val; + } + } + + if (migrateToDatacenterId != DEFAULT_DATACENTER_ID) { + ignoreResult = true; + moveToDatacenter(migrateToDatacenterId); + } + } + } + + uint32_t retryRequestsFromDatacenter = DEFAULT_DATACENTER_ID - 1; + uint32_t retryRequestsConnections = 0; + + if (!ignoreResult) { + for (requestsIter iter = runningRequests.begin(); iter != runningRequests.end(); iter++) { + Request *request = iter->get(); + if (request->respondsToMessageId(resultMid)) { + DEBUG_D("got response for request %p - %s", request->rawRequest, typeid(*request->rawRequest).name()); + bool discardResponse = false; + bool isError = false; + bool allowInitConnection = true; + + if (request->onCompleteRequestCallback != nullptr) { + TL_error *implicitError = nullptr; + NativeByteBuffer *unpacked_data = nullptr; + TLObject *result = response->result.get(); + if (typeid(*result) == typeid(TL_gzip_packed)) { + TL_gzip_packed *innerResponse = (TL_gzip_packed *) result; + unpacked_data = decompressGZip(innerResponse->packed_data.get()); + TLObject *object = TLdeserialize(request->rawRequest, unpacked_data->limit(), unpacked_data); + if (object != nullptr) { + response->result = std::unique_ptr(object); + } else { + response->result = std::unique_ptr(nullptr); + } + } + + hasResult = response->result.get() != nullptr; + error = hasResult ? dynamic_cast(response->result.get()) : nullptr; + TL_error *error2 = hasResult ? dynamic_cast(response->result.get()) : nullptr; + if (error != nullptr) { + allowInitConnection = false; + DEBUG_E("request %p rpc error %d: %s", request, error->error_code, error->error_message.c_str()); + + if ((request->requestFlags & RequestFlagFailOnServerErrors) == 0) { + if (error->error_code == 500 || error->error_code < 0) { + discardResponse = true; + request->minStartTime = request->startTime + (request->serverFailureCount > 10 ? 10 : request->serverFailureCount); + request->serverFailureCount++; + } else if (error->error_code == 420) { + int32_t waitTime = 2; + static std::string floodWait = "FLOOD_WAIT_"; + if (error->error_message.find(floodWait) != std::string::npos) { + std::string num = error->error_message.substr(floodWait.size(), error->error_message.size() - floodWait.size()); + waitTime = atoi(num.c_str()); + if (waitTime <= 0) { + waitTime = 2; + } + } + + discardResponse = true; + request->failedByFloodWait = waitTime; + request->startTime = 0; + request->minStartTime = (int32_t) (getCurrentTimeMillis() / 1000 + waitTime); + } else if (error->error_code == 400) { + static std::string waitFailed = "MSG_WAIT_FAILED"; + if (error->error_message.find(waitFailed) != std::string::npos) { + discardResponse = true; + request->minStartTime = (int32_t) (getCurrentTimeMillis() / 1000 + 1); + request->startTime = 0; + } + } + } + if (!discardResponse) { + implicitError = new TL_error(); + implicitError->code = error->error_code; + implicitError->text = error->error_message; + } + } else if (error2 == nullptr) { + if (request->rawRequest == nullptr || response->result == nullptr) { + allowInitConnection = false; + DEBUG_E("rawRequest is null"); + implicitError = new TL_error(); + implicitError->code = -1000; + implicitError->text = ""; + } + } + + if (!discardResponse) { + if (implicitError != nullptr || error2 != nullptr) { + isError = true; + request->onComplete(nullptr, implicitError != nullptr ? implicitError : error2); + if (error2 != nullptr) { + delete error2; + } + } else { + request->onComplete(response->result.get(), nullptr); + } + } + + if (implicitError != nullptr && implicitError->code == 401) { + allowInitConnection = false; + isError = true; + static std::string sessionPasswordNeeded = "SESSION_PASSWORD_NEEDED"; + if (implicitError->text.find(sessionPasswordNeeded) != std::string::npos) { + //ignore this error + } else if (datacenter->getDatacenterId() == currentDatacenterId || datacenter->getDatacenterId() == movingToDatacenterId) { + if (request->connectionType & ConnectionTypeGeneric && currentUserId) { + currentUserId = 0; + if (delegate != nullptr) { + delegate->onLogout(); + } + cleanUp(); + } + } else { + datacenter->authorized = false; + saveConfig(); + discardResponse = true; + if (request->connectionType & ConnectionTypeDownload || request->connectionType & ConnectionTypeUpload) { + retryRequestsFromDatacenter = datacenter->datacenterId; + retryRequestsConnections = request->connectionType; + } + } + } + + if (unpacked_data != nullptr) { + unpacked_data->reuse(); + } + if (implicitError != nullptr) { + delete implicitError; + } + } + + if (!discardResponse) { + if (allowInitConnection && request->isInitRequest && !isError) { + if (datacenter->lastInitVersion != currentVersion) { + datacenter->lastInitVersion = currentVersion; + saveConfig(); + DEBUG_D("dc%d init connection completed", datacenter->getDatacenterId()); + } else { + DEBUG_D("dc%d rpc is init, but init connection already completed", datacenter->getDatacenterId()); + } + } + request->completed = true; + removeRequestFromGuid(request->requestToken); + runningRequests.erase(iter); + } else { + request->messageId = 0; + request->messageSeqNo = 0; + request->connectionToken = 0; + } + break; + } + } + } + + if (retryRequestsFromDatacenter != DEFAULT_DATACENTER_ID - 1) { + processRequestQueue(retryRequestsConnections, retryRequestsFromDatacenter); + } else { + processRequestQueue(0, 0); + } + } else if (typeInfo == typeid(TL_msgs_ack)) { + + } else if (typeInfo == typeid(TL_bad_msg_notification)) { + TL_bad_msg_notification *result = (TL_bad_msg_notification *) message; + DEBUG_E("bad message: %d", result->error_code); + switch (result->error_code) { + case 16: + case 17: + case 19: + case 32: + case 33: + case 64: { + int64_t realId = messageId != 0 ? messageId : containerMessageId; + if (realId == 0) { + realId = innerMsgId; + } + + if (realId != 0) { + int64_t time = (int64_t) (messageId / 4294967296.0 * 1000); + int64_t currentTime = getCurrentTimeMillis(); + timeDifference = (int32_t) ((time - currentTime) / 1000 - currentPingTime / 2); + } + + datacenter->recreateSessions(); + saveConfig(); + + lastOutgoingMessageId = 0; + clearRequestsForDatacenter(datacenter); + break; + } + default: + break; + } + } else if (typeInfo == typeid(TL_bad_server_salt)) { + TL_bad_server_salt *response = (TL_bad_server_salt *) message; + if (messageId != 0) { + int64_t time = (int64_t) (messageId / 4294967296.0 * 1000); + int64_t currentTime = getCurrentTimeMillis(); + timeDifference = (int32_t) ((time - currentTime) / 1000 - currentPingTime / 2); + lastOutgoingMessageId = messageId > (lastOutgoingMessageId ? messageId : lastOutgoingMessageId); + } + int64_t resultMid = response->bad_msg_id; + if (resultMid != 0) { + for (requestsIter iter = runningRequests.begin(); iter != runningRequests.end(); iter++) { + Request *request = iter->get(); + if ((request->connectionType & ConnectionTypeDownload) == 0) { + continue; + } + Datacenter *requestDatacenter = getDatacenterWithId(request->datacenterId); + if (requestDatacenter != nullptr && requestDatacenter->getDatacenterId() == datacenter->getDatacenterId()) { + request->retryCount = 0; + request->failedBySalt = true; + } + } + } + + datacenter->clearServerSalts(); + + std::unique_ptr salt = std::unique_ptr(new TL_future_salt()); + salt->valid_until = salt->valid_since = getCurrentTime(); + salt->valid_until += 30 * 60; + salt->salt = messageSalt; + datacenter->addServerSalt(salt); + saveConfig(); + + requestSaltsForDatacenter(datacenter); + if (datacenter->hasAuthKey()) { + processRequestQueue(AllConnectionTypes, datacenter->getDatacenterId()); + } + } else if (dynamic_cast(message)) { + MsgDetailedInfo *response = (MsgDetailedInfo *) message; + + bool requestResend = false; + bool confirm = true; + + if (typeInfo == typeid(TL_msg_detailed_info)) { + for (requestsIter iter = runningRequests.begin(); iter != runningRequests.end(); iter++) { + Request *request = iter->get(); + if (request->respondsToMessageId(response->msg_id)) { + if (request->completed) { + break; + } + int32_t currentTime = (int32_t) (getCurrentTimeMillis() / 1000); + if (request->lastResendTime == 0 || abs(currentTime - request->lastResendTime) >= 60) { + request->lastResendTime = currentTime; + requestResend = true; + } else { + confirm = false; + } + break; + } + } + } else { + if (!connection->isMessageIdProcessed(messageId)) { + requestResend = true; + } + } + + if (requestResend) { + TL_msg_resend_req *request = new TL_msg_resend_req(); + request->msg_ids.push_back(response->answer_msg_id); + NetworkMessage *networkMessage = new NetworkMessage(); + networkMessage->message = std::unique_ptr(new TL_message()); + networkMessage->message->msg_id = generateMessageId(); + networkMessage->message->bytes = request->getObjectSize(); + networkMessage->message->body = std::unique_ptr(request); + networkMessage->message->seqno = connection->generateMessageSeqNo(false); + + std::vector> array; + array.push_back(std::unique_ptr(networkMessage)); + + sendMessagesToConnection(array, connection, false); + } else if (confirm) { + connection->addMessageToConfirm(response->answer_msg_id); + } + } else if (typeInfo == typeid(TL_gzip_packed)) { + TL_gzip_packed *response = (TL_gzip_packed *) message; + NativeByteBuffer *data = decompressGZip(response->packed_data.get()); + TLObject *object = TLdeserialize(getRequestWithMessageId(messageId), data->limit(), data); + if (object != nullptr) { + DEBUG_D("connection(%p, dc%u, type %d) received object %s", connection, datacenter->getDatacenterId(), connection->getConnectionType(), typeid(*object).name()); + processServerResponse(object, messageId, messageSeqNo, messageSalt, connection, innerMsgId, containerMessageId); + delete object; + } else { + if (delegate != nullptr) { + delegate->onUnparsedMessageReceived(messageId, data, connection->getConnectionType()); + } + } + data->reuse(); + } else if (typeInfo == typeid(TL_updatesTooLong)) { + if (connection->connectionType == ConnectionTypePush) { + if (networkPaused) { + lastPauseTime = getCurrentTimeMillis(); + DEBUG_D("received internal push: wakeup network in background"); + } else if (lastPauseTime != 0) { + lastPauseTime = getCurrentTimeMillis(); + DEBUG_D("received internal push: reset sleep timeout"); + } else { + DEBUG_D("received internal push"); + } + if (delegate != nullptr) { + delegate->onInternalPushReceived(); + } + } else { + if (delegate != nullptr) { + NativeByteBuffer *data = BuffersStorage::getInstance().getFreeBuffer(message->getObjectSize()); + message->serializeToStream(data); + data->position(0); + delegate->onUnparsedMessageReceived(0, data, connection->getConnectionType()); + data->reuse(); + } + } + } +} + +void ConnectionsManager::sendPing(Datacenter *datacenter, bool usePushConnection) { + if (usePushConnection && (currentUserId == 0 || !usePushConnection)) { + return; + } + Connection *connection = nullptr; + if (usePushConnection) { + connection = datacenter->getPushConnection(true); + } else { + connection = datacenter->getGenericConnection(true); + } + if (connection == nullptr || (!usePushConnection && connection->getConnectionToken() == 0)) { + return; + } + TL_ping_delay_disconnect *request = new TL_ping_delay_disconnect(); + request->ping_id = ++lastPingId; + if (usePushConnection) { + request->disconnect_delay = 60 * 7; + } else { + request->disconnect_delay = 35; + pingTime = (int32_t) (getCurrentTimeMillis() / 1000); + } + + NetworkMessage *networkMessage = new NetworkMessage(); + networkMessage->message = std::unique_ptr(new TL_message()); + networkMessage->message->msg_id = generateMessageId(); + networkMessage->message->bytes = request->getObjectSize(); + networkMessage->message->body = std::unique_ptr(request); + networkMessage->message->seqno = connection->generateMessageSeqNo(false); + + std::vector> array; + array.push_back(std::unique_ptr(networkMessage)); + NativeByteBuffer *transportData = datacenter->createRequestsData(array, nullptr, connection); + if (usePushConnection) { + DEBUG_D("dc%d send ping to push connection", datacenter->getDatacenterId()); + sendingPushPing = true; + } + connection->sendData(transportData, false); +} + +bool ConnectionsManager::isIpv6Enabled() { + return ipv6Enabled; +} + +void ConnectionsManager::initDatacenters() { + Datacenter *datacenter; + if (!testBackend) { + if (datacenters.find(1) == datacenters.end()) { + datacenter = new Datacenter(1); + datacenter->addAddressAndPort("149.154.175.50", 443, 0); + datacenter->addAddressAndPort("2001:b28:f23d:f001:0000:0000:0000:000a", 443, 1); + datacenters[1] = datacenter; + } + + if (datacenters.find(2) == datacenters.end()) { + datacenter = new Datacenter(2); + datacenter->addAddressAndPort("149.154.167.51", 443, 0); + datacenter->addAddressAndPort("2001:67c:4e8:f002:0000:0000:0000:000a", 443, 1); + datacenters[2] = datacenter; + } + + if (datacenters.find(3) == datacenters.end()) { + datacenter = new Datacenter(3); + datacenter->addAddressAndPort("149.154.175.100", 443, 0); + datacenter->addAddressAndPort("2001:b28:f23d:f003:0000:0000:0000:000a", 443, 1); + datacenters[3] = datacenter; + } + + if (datacenters.find(4) == datacenters.end()) { + datacenter = new Datacenter(4); + datacenter->addAddressAndPort("149.154.167.91", 443, 0); + datacenter->addAddressAndPort("2001:67c:4e8:f004:0000:0000:0000:000a", 443, 1); + datacenters[4] = datacenter; + } + + if (datacenters.find(5) == datacenters.end()) { + datacenter = new Datacenter(5); + datacenter->addAddressAndPort("149.154.171.5", 443, 0); + datacenter->addAddressAndPort("2001:b28:f23f:f005:0000:0000:0000:000a", 443, 1); + datacenters[5] = datacenter; + } + } else { + if (datacenters.find(1) == datacenters.end()) { + datacenter = new Datacenter(1); + datacenter->addAddressAndPort("149.154.175.10", 443, 0); + datacenter->addAddressAndPort("2001:b28:f23d:f001:0000:0000:0000:000e", 443, 1); + datacenters[1] = datacenter; + } + + if (datacenters.find(2) == datacenters.end()) { + datacenter = new Datacenter(2); + datacenter->addAddressAndPort("149.154.167.40", 443, 0); + datacenter->addAddressAndPort("2001:67c:4e8:f002:0000:0000:0000:000e", 443, 1); + datacenters[2] = datacenter; + } + + if (datacenters.find(3) == datacenters.end()) { + datacenter = new Datacenter(3); + datacenter->addAddressAndPort("149.154.175.117", 443, 0); + datacenter->addAddressAndPort("2001:b28:f23d:f003:0000:0000:0000:000e", 443, 1); + datacenters[3] = datacenter; + } + } +} + +void ConnectionsManager::attachConnection(ConnectionSocket *connection) { + if (std::find(activeConnections.begin(), activeConnections.end(), connection) != activeConnections.end()) { + return; + } + activeConnections.push_back(connection); +} + +void ConnectionsManager::detachConnection(ConnectionSocket *connection) { + std::vector::iterator iter = std::find(activeConnections.begin(), activeConnections.end(), connection); + if (iter != activeConnections.end()) { + activeConnections.erase(iter); + } +} + +int32_t ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate) { + int32_t requestToken = lastRequestToken++; + sendRequest(object, onComplete, onQuickAck, flags, datacenterId, connetionType, immediate, requestToken); + return requestToken; +} + +void ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken) { + if (!currentUserId && !(flags & RequestFlagWithoutLogin)) { + DEBUG_D("can't do request without login %s", typeid(*object).name()); + delete object; + return; + } + scheduleTask([&, requestToken, object, onComplete, onQuickAck, flags, datacenterId, connetionType, immediate] { + Request *request = new Request(requestToken, connetionType, flags, datacenterId, onComplete, onQuickAck); + request->rawRequest = object; + request->rpcRequest = wrapInLayer(object, getDatacenterWithId(datacenterId), request); + requestsQueue.push_back(std::unique_ptr(request)); + if (immediate) { + processRequestQueue(0, 0); + } + }); +} + +#ifdef ANDROID +void ConnectionsManager::sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken, jobject ptr1, jobject ptr2) { + if (!currentUserId && !(flags & RequestFlagWithoutLogin)) { + DEBUG_D("can't do request without login %s", typeid(*object).name()); + delete object; + JNIEnv *env = 0; + if (javaVm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { + DEBUG_E("can't get jnienv"); + exit(1); + } + if (ptr1 != nullptr) { + env->DeleteGlobalRef(ptr1); + ptr1 = nullptr; + } + if (ptr2 != nullptr) { + env->DeleteGlobalRef(ptr2); + ptr2 = nullptr; + } + return; + } + scheduleTask([&, requestToken, object, onComplete, onQuickAck, flags, datacenterId, connetionType, immediate, ptr1, ptr2] { + DEBUG_D("send request %p - %s", object, typeid(*object).name()); + Request *request = new Request(requestToken, connetionType, flags, datacenterId, onComplete, onQuickAck); + request->rawRequest = object; + request->ptr1 = ptr1; + request->ptr2 = ptr2; + request->rpcRequest = wrapInLayer(object, getDatacenterWithId(datacenterId), request); + DEBUG_D("send request wrapped %p - %s", request->rpcRequest.get(), typeid(*(request->rpcRequest.get())).name()); + requestsQueue.push_back(std::unique_ptr(request)); + if (immediate) { + processRequestQueue(0, 0); + } + }); +} +#endif + +void ConnectionsManager::cancelRequestsForGuid(int32_t guid) { + scheduleTask([&, guid] { + std::map>::iterator iter = requestsByGuids.find(guid); + if (iter != requestsByGuids.end()) { + std::vector &requests = iter->second; + size_t count = requests.size(); + for (uint32_t a = 0; a < count; a++) { + cancelRequestInternal(requests[a], true, false); + std::map::iterator iter2 = guidsByRequests.find(requests[a]); + if (iter2 != guidsByRequests.end()) { + guidsByRequests.erase(iter2); + } + } + requestsByGuids.erase(iter); + } + }); +} + +void ConnectionsManager::bindRequestToGuid(int32_t requestToken, int32_t guid) { + scheduleTask([&, requestToken, guid] { + std::map>::iterator iter = requestsByGuids.find(guid); + if (iter != requestsByGuids.end()) { + iter->second.push_back(requestToken); + } else { + std::vector array; + array.push_back(requestToken); + requestsByGuids[guid] = array; + } + guidsByRequests[requestToken] = guid; + }); +} + +void ConnectionsManager::setUserId(int32_t userId) { + scheduleTask([&, userId] { + int32_t oldUserId = currentUserId; + currentUserId = userId; + if (oldUserId == userId && userId != 0) { + registerForInternalPushUpdates(); + } + if (currentUserId != userId && userId != 0) { + updateDcSettings(0); + } + if (currentUserId != 0 && pushConnectionEnabled) { + Datacenter *datacenter = getDatacenterWithId(currentDatacenterId); + if (datacenter != nullptr) { + datacenter->createPushConnection()->setSessionId(pushSessionId); + sendPing(datacenter, true); + } + } + }); +} + +void ConnectionsManager::switchBackend() { + scheduleTask([&] { + testBackend = !testBackend; + datacenters.clear(); + initDatacenters(); + saveConfig(); + exit(1); + }); +} + +void ConnectionsManager::removeRequestFromGuid(int32_t requestToken) { + std::map::iterator iter2 = guidsByRequests.find(requestToken); + if (iter2 != guidsByRequests.end()) { + std::map>::iterator iter = requestsByGuids.find(iter2->first); + if (iter != requestsByGuids.end()) { + std::vector::iterator iter3 = std::find(iter->second.begin(), iter->second.end(), iter->first); + if (iter3 != iter->second.end()) { + iter->second.erase(iter3); + if (iter->second.empty()) { + requestsByGuids.erase(iter); + } + } + } + guidsByRequests.erase(iter2); + } +} + +void ConnectionsManager::cancelRequestInternal(int32_t token, bool notifyServer, bool removeFromClass) { + for (requestsIter iter = requestsQueue.begin(); iter != requestsQueue.end(); iter++) { + Request *request = iter->get(); + if (request->requestToken == token) { + request->cancelled = true; + DEBUG_D("cancelled queued rpc request %p - %s", request->rawRequest, typeid(*request->rawRequest).name()); + requestsQueue.erase(iter); + if (removeFromClass) { + removeRequestFromGuid(token); + } + return; + } + } + + for (requestsIter iter = runningRequests.begin(); iter != runningRequests.end(); iter++) { + Request *request = iter->get(); + if (request->requestToken == token) { + if (notifyServer) { + TL_rpc_drop_answer *dropAnswer = new TL_rpc_drop_answer(); + dropAnswer->req_msg_id = request->messageId; + sendRequest(dropAnswer, nullptr, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin | RequestFlagFailOnServerErrors, request->datacenterId, request->connectionType, true); + } + request->cancelled = true; + DEBUG_D("cancelled running rpc request %p - %s", request->rawRequest, typeid(*request->rawRequest).name()); + runningRequests.erase(iter); + if (removeFromClass) { + removeRequestFromGuid(token); + } + return; + } + } +} + +void ConnectionsManager::cancelRequest(int32_t token, bool notifyServer) { + if (token == 0) { + return; + } + scheduleTask([&, token, notifyServer] { + cancelRequestInternal(token, notifyServer, true); + }); +} + +void ConnectionsManager::onDatacenterHandshakeComplete(Datacenter *datacenter, int32_t timeDiff) { + saveConfig(); + uint32_t datacenterId = datacenter->getDatacenterId(); + if (datacenterId == currentDatacenterId || datacenterId == movingToDatacenterId) { + timeDifference = timeDiff; + datacenter->recreateSessions(); + clearRequestsForDatacenter(datacenter); + } + processRequestQueue(AllConnectionTypes, datacenterId); +} + +void ConnectionsManager::onDatacenterExportAuthorizationComplete(Datacenter *datacenter) { + saveConfig(); + processRequestQueue(AllConnectionTypes, datacenter->getDatacenterId()); +} + +void ConnectionsManager::sendMessagesToConnection(std::vector> &messages, Connection *connection, bool reportAck) { + if (messages.empty() || connection == nullptr) { + return; + } + + std::vector> currentMessages; + Datacenter *datacenter = connection->getDatacenter(); + + uint32_t currentSize = 0; + size_t count = messages.size(); + for (uint32_t a = 0; a < count; a++) { + NetworkMessage *networkMessage = messages[a].get(); + currentMessages.push_back(std::move(messages[a])); + currentSize += networkMessage->message->bytes; + + if (currentSize >= 3 * 1024 || a == count - 1) { + int32_t quickAckId = 0; + NativeByteBuffer *transportData = datacenter->createRequestsData(currentMessages, reportAck ? &quickAckId : nullptr, connection); + + if (transportData != nullptr) { + if (reportAck && quickAckId != 0) { + std::vector requestIds; + + size_t count2 = currentMessages.size(); + for (uint32_t b = 0; b < count2; b++) { + NetworkMessage *message = currentMessages[b].get(); + if (message->requestId != 0) { + requestIds.push_back(message->requestId); + } + } + + if (!requestIds.empty()) { + std::map>::iterator iter = quickAckIdToRequestIds.find(quickAckId); + if (iter == quickAckIdToRequestIds.end()) { + quickAckIdToRequestIds[quickAckId] = requestIds; + } else { + iter->second.insert(iter->second.end(), requestIds.begin(), requestIds.end()); + } + } + } + + connection->sendData(transportData, reportAck); + } else { + DEBUG_E("connection(%p) connection data is empty", connection); + } + + currentSize = 0; + currentMessages.clear(); + } + } +} + +void ConnectionsManager::sendMessagesToConnectionWithConfirmation(std::vector> &messages, Connection *connection, bool reportAck) { + NetworkMessage *networkMessage = connection->generateConfirmationRequest(); + if (networkMessage != nullptr) { + messages.push_back(std::unique_ptr(networkMessage)); + } + sendMessagesToConnection(messages, connection, reportAck); +} + +void ConnectionsManager::requestSaltsForDatacenter(Datacenter *datacenter) { + if (std::find(requestingSaltsForDc.begin(), requestingSaltsForDc.end(), datacenter->getDatacenterId()) != requestingSaltsForDc.end()) { + return; + } + requestingSaltsForDc.push_back(datacenter->getDatacenterId()); + TL_get_future_salts *request = new TL_get_future_salts(); + request->num = 32; + sendRequest(request, [&, datacenter](TLObject *response, TL_error *error) { + std::vector::iterator iter = std::find(requestingSaltsForDc.begin(), requestingSaltsForDc.end(), datacenter->getDatacenterId()); + if (iter != requestingSaltsForDc.end()) { + requestingSaltsForDc.erase(iter); + } + if (error == nullptr) { + TL_future_salts *res = (TL_future_salts *) response; + datacenter->mergeServerSalts(res->salts); + saveConfig(); + } + }, nullptr, RequestFlagWithoutLogin | RequestFlagEnableUnauthorized, datacenter->getDatacenterId(), ConnectionTypeGeneric, true); +} + +void ConnectionsManager::clearRequestsForDatacenter(Datacenter *datacenter) { + for (requestsIter iter = runningRequests.begin(); iter != runningRequests.end(); iter++) { + Request *request = iter->get(); + Datacenter *requestDatacenter = getDatacenterWithId(request->datacenterId); + if (requestDatacenter->getDatacenterId() == datacenter->getDatacenterId()) { + request->clear(true); + } + } +} + +void ConnectionsManager::registerForInternalPushUpdates() { + if (registeringForPush || !currentUserId) { + return; + } + registeredForInternalPush = false; + registeringForPush = true; + TL_account_registerDevice *request = new TL_account_registerDevice(); + request->token_type = 7; + request->token = to_string_uint64(pushSessionId); + request->app_sandbox = false; + + request->app_version = currentAppVersion; + request->device_model = currentDeviceModel; + request->lang_code = currentLangCode; + request->system_version = currentSystemVersion; + if (request->lang_code.empty()) { + request->lang_code = "en"; + } + if (request->device_model.empty()) { + request->device_model = "device model unknown"; + } + if (request->app_version.empty()) { + request->app_version = "app version unknown"; + } + if (request->system_version.empty()) { + request->system_version = "system version unknown"; + } + + sendRequest(request, [&](TLObject *response, TL_error *error) { + if (error == nullptr) { + registeredForInternalPush = true; + DEBUG_D("registered for internal push"); + } else { + registeredForInternalPush = false; + DEBUG_E("unable to registering for internal push"); + } + saveConfig(); + registeringForPush = false; + }, nullptr, 0, DEFAULT_DATACENTER_ID, ConnectionTypeGeneric, true); +} + + +inline void addMessageToDatacenter(uint32_t datacenterId, NetworkMessage *networkMessage, std::map>> &genericMessagesToDatacenters) { + std::map>>::iterator iter = genericMessagesToDatacenters.find(datacenterId); + if (iter == genericMessagesToDatacenters.end()) { + std::vector> &array = genericMessagesToDatacenters[datacenterId] = std::vector>(); + array.push_back(std::unique_ptr(networkMessage)); + } else { + iter->second.push_back(std::unique_ptr(networkMessage)); + } +} + +void ConnectionsManager::processRequestQueue(uint32_t connectionTypes, uint32_t dc) { + static std::map>> genericMessagesToDatacenters; + static std::vector unknownDatacenterIds; + static std::vector neededDatacenters; + static std::vector unauthorizedDatacenters; + + genericMessagesToDatacenters.clear(); + unknownDatacenterIds.clear(); + neededDatacenters.clear(); + unauthorizedDatacenters.clear(); + + Connection *genericConnection = nullptr; + Datacenter *defaultDatacenter = getDatacenterWithId(currentDatacenterId); + if (defaultDatacenter != nullptr) { + genericConnection = defaultDatacenter->getGenericConnection(true); + } + + int32_t currentTime = (int32_t) (getCurrentTimeMillis() / 1000); + uint32_t genericRunningRequestCount = 0; + uint32_t uploadRunningRequestCount = 0; + uint32_t downloadRunningRequestCount = 0; + + for (requestsIter iter = runningRequests.begin(); iter != runningRequests.end();) { + Request *request = iter->get(); + const std::type_info &typeInfo = typeid(*request->rawRequest); + + switch (request->connectionType & 0x0000ffff) { + case ConnectionTypeGeneric: + genericRunningRequestCount++; + break; + case ConnectionTypeDownload: + downloadRunningRequestCount++; + break; + case ConnectionTypeUpload: + uploadRunningRequestCount++; + break; + default: + break; + } + + uint32_t datacenterId = request->datacenterId; + if (datacenterId == DEFAULT_DATACENTER_ID) { + if (movingToDatacenterId != DEFAULT_DATACENTER_ID) { + iter++; + continue; + } + datacenterId = currentDatacenterId; + } + + if (request->requestFlags & RequestFlagTryDifferentDc) { + int32_t requestStartTime = request->startTime; + int32_t timeout = 30; + if (updatingDcSettings && dynamic_cast(request->rawRequest)) { + requestStartTime = updatingDcStartTime; + updatingDcStartTime = currentTime; + timeout = 60; + } + if (request->startTime != 0 && abs(currentTime - requestStartTime) >= timeout) { + DEBUG_D("move %s to requestsQueue", typeid(*request->rawRequest).name()); + requestsQueue.push_back(std::move(*iter)); + iter = runningRequests.erase(iter); + continue; + } + } + + Datacenter *requestDatacenter = getDatacenterWithId(datacenterId); + if (requestDatacenter->lastInitVersion != currentVersion && !request->isInitRequest) { + request->rpcRequest.release(); + request->rpcRequest = wrapInLayer(request->rawRequest, requestDatacenter, request); + request->serializedLength = request->getRpcRequest()->getObjectSize(); + } + + if (requestDatacenter == nullptr) { + if (std::find(unknownDatacenterIds.begin(), unknownDatacenterIds.end(), datacenterId) == unknownDatacenterIds.end()) { + unknownDatacenterIds.push_back(datacenterId); + } + iter++; + continue; + } else if (!requestDatacenter->hasAuthKey()) { + if (std::find(neededDatacenters.begin(), neededDatacenters.end(), requestDatacenter) == neededDatacenters.end()) { + neededDatacenters.push_back(requestDatacenter); + } + iter++; + continue; + } else if (!(request->requestFlags & RequestFlagEnableUnauthorized) && !requestDatacenter->authorized && request->datacenterId != DEFAULT_DATACENTER_ID && request->datacenterId != currentDatacenterId) { + if (std::find(unauthorizedDatacenters.begin(), unauthorizedDatacenters.end(), requestDatacenter) == unauthorizedDatacenters.end()) { + unauthorizedDatacenters.push_back(requestDatacenter); + } + iter++; + continue; + } + + Connection *connection = requestDatacenter->getConnectionByType(request->connectionType, true); + int32_t maxTimeout = request->connectionType & ConnectionTypeGeneric ? 8 : 30; + if (!networkAvailable || connection->getConnectionToken() == 0) { + iter++; + continue; + } + + uint32_t requestConnectionType = request->connectionType & 0x0000ffff; + + bool forceThisRequest = (connectionTypes & requestConnectionType) && requestDatacenter->getDatacenterId() == dc; + + if (typeInfo == typeid(TL_get_future_salts) || typeInfo == typeid(TL_destroy_session)) { + if (request->messageId != 0) { + request->addRespondMessageId(request->messageId); + } + request->clear(false); + forceThisRequest = false; + } + + if (forceThisRequest || (abs(currentTime - request->startTime) > maxTimeout && + (currentTime >= request->minStartTime || + (request->failedByFloodWait != 0 && (request->minStartTime - currentTime) > request->failedByFloodWait) || + (request->failedByFloodWait == 0 && abs(currentTime - request->minStartTime) >= 60)) + ) + ) { + if (!forceThisRequest && request->connectionToken > 0) { + if (request->connectionType & ConnectionTypeGeneric && request->connectionToken == connection->getConnectionToken()) { + DEBUG_D("request token is valid, not retrying %s", typeInfo.name()); + iter++; + continue; + } else { + if (connection->getConnectionToken() != 0 && request->connectionToken == connection->getConnectionToken()) { + DEBUG_D("request download token is valid, not retrying %s", typeInfo.name()); + iter++; + continue; + } + } + } + + if (request->connectionToken != 0 && request->connectionToken != connection->getConnectionToken()) { + request->lastResendTime = 0; + } + + request->retryCount++; + + if (!request->failedBySalt) { + if (request->connectionType & ConnectionTypeDownload) { + uint32_t retryMax = 10; + if (!(request->requestFlags & RequestFlagForceDownload)) { + if (request->failedByFloodWait) { + retryMax = 1; + } else { + retryMax = 6; + } + } + if (request->retryCount >= retryMax) { + DEBUG_E("timed out %s", typeInfo.name()); + TL_error *error = new TL_error(); + error->code = -123; + error->text = "RETRY_LIMIT"; + request->onComplete(nullptr, error); + delete error; + iter = runningRequests.erase(iter); + continue; + } + } + } else { + request->failedBySalt = false; + } + + if (request->messageSeqNo == 0) { + request->messageSeqNo = connection->generateMessageSeqNo(true); + request->messageId = generateMessageId(); + } + request->startTime = currentTime; + + NetworkMessage *networkMessage = new NetworkMessage(); + networkMessage->message = std::unique_ptr(new TL_message()); + networkMessage->message->msg_id = request->messageId; + networkMessage->message->bytes = request->serializedLength; + networkMessage->message->outgoingBody = request->getRpcRequest(); + networkMessage->message->seqno = request->messageSeqNo; + networkMessage->requestId = request->requestToken; + networkMessage->invokeAfter = (request->requestFlags & RequestFlagInvokeAfter) != 0; + networkMessage->needQuickAck = (request->requestFlags & RequestFlagNeedQuickAck) != 0; + + request->connectionToken = connection->getConnectionToken(); + switch (requestConnectionType) { + case ConnectionTypeGeneric: + addMessageToDatacenter(requestDatacenter->getDatacenterId(), networkMessage, genericMessagesToDatacenters); + break; + case ConnectionTypeDownload: + case ConnectionTypeUpload: { + std::vector> array; + array.push_back(std::unique_ptr(networkMessage)); + sendMessagesToConnectionWithConfirmation(array, connection, false); + break; + } + default: + delete networkMessage; + } + } + iter++; + } + + if (genericConnection != nullptr && !sessionsToDestroy.empty() && genericConnection->getConnectionToken() != 0) { + std::vector::iterator iter = sessionsToDestroy.begin(); + + sessionsToDestroy.erase(iter); + + if (abs(currentTime - lastDestroySessionRequestTime) > 2) { + lastDestroySessionRequestTime = currentTime; + TL_destroy_session *request = new TL_destroy_session(); + request->session_id = *iter; + + NetworkMessage *networkMessage = new NetworkMessage(); + networkMessage->message = std::unique_ptr(new TL_message()); + networkMessage->message->msg_id = generateMessageId(); + networkMessage->message->bytes = request->getObjectSize(); + networkMessage->message->body = std::unique_ptr(request); + networkMessage->message->seqno = genericConnection->generateMessageSeqNo(false); + addMessageToDatacenter(defaultDatacenter->getDatacenterId(), networkMessage, genericMessagesToDatacenters); + } + } + + for (requestsIter iter = requestsQueue.begin(); iter != requestsQueue.end();) { + Request *request = iter->get(); + if (request->cancelled) { + iter = requestsQueue.erase(iter); + continue; + } + + uint32_t datacenterId = request->datacenterId; + if (datacenterId == DEFAULT_DATACENTER_ID) { + if (movingToDatacenterId != DEFAULT_DATACENTER_ID) { + iter++; + continue; + } + datacenterId = currentDatacenterId; + } + + if (request->requestFlags & RequestFlagTryDifferentDc) { + int32_t requestStartTime = request->startTime; + int32_t timeout = 30; + if (updatingDcSettings && dynamic_cast(request->rawRequest)) { + requestStartTime = updatingDcStartTime; + timeout = 60; + } else { + request->startTime = 0; + } + if (requestStartTime != 0 && abs(currentTime - requestStartTime) >= timeout) { + std::vector allDc; + for (std::map::iterator iter2 = datacenters.begin(); iter2 != datacenters.end(); iter2++) { + if (iter2->first == datacenterId) { + continue; + } + allDc.push_back(iter2->first); + } + uint8_t index; + RAND_bytes(&index, 1); + datacenterId = allDc[index % allDc.size()]; + if (dynamic_cast(request->rawRequest)) { + updatingDcStartTime = currentTime; + request->datacenterId = datacenterId; + } else { + currentDatacenterId = datacenterId; + } + } + } + + Datacenter *requestDatacenter = getDatacenterWithId(datacenterId); + if (requestDatacenter->lastInitVersion != currentVersion && !request->isInitRequest) { + request->rpcRequest.release(); + request->rpcRequest = wrapInLayer(request->rawRequest, requestDatacenter, request); + } + + if (requestDatacenter == nullptr) { + if (std::find(unknownDatacenterIds.begin(), unknownDatacenterIds.end(), datacenterId) == unknownDatacenterIds.end()) { + unknownDatacenterIds.push_back(datacenterId); + } + iter++; + continue; + } else if (!requestDatacenter->hasAuthKey()) { + if (std::find(neededDatacenters.begin(), neededDatacenters.end(), requestDatacenter) == neededDatacenters.end()) { + neededDatacenters.push_back(requestDatacenter); + } + iter++; + continue; + } else if (!(request->requestFlags & RequestFlagEnableUnauthorized) && !requestDatacenter->authorized && request->datacenterId != DEFAULT_DATACENTER_ID && request->datacenterId != currentDatacenterId) { + if (std::find(unauthorizedDatacenters.begin(), unauthorizedDatacenters.end(), requestDatacenter) == unauthorizedDatacenters.end()) { + unauthorizedDatacenters.push_back(requestDatacenter); + } + iter++; + continue; + } + + Connection *connection = requestDatacenter->getConnectionByType(request->connectionType, true); + + if (request->connectionType & ConnectionTypeGeneric && connection->getConnectionToken() == 0) { + iter++; + continue; + } + + switch (request->connectionType & 0x0000ffff) { + case ConnectionTypeGeneric: + if (genericRunningRequestCount >= 60) { + iter++; + continue; + } + genericRunningRequestCount++; + break; + case ConnectionTypeDownload: + if (!networkAvailable || downloadRunningRequestCount >= 5) { + iter++; + continue; + } + downloadRunningRequestCount++; + break; + case ConnectionTypeUpload: + if (!networkAvailable || uploadRunningRequestCount >= 5) { + iter++; + continue; + } + uploadRunningRequestCount++; + break; + default: + break; + } + + uint32_t requestLength = request->rpcRequest->getObjectSize(); + if (request->requestFlags & RequestFlagCanCompress) { + request->requestFlags &= ~RequestFlagCanCompress; + NativeByteBuffer *original = BuffersStorage::getInstance().getFreeBuffer(requestLength); + request->rpcRequest->serializeToStream(original); + NativeByteBuffer *buffer = compressGZip(original); + if (buffer != nullptr) { + TL_gzip_packed *packed = new TL_gzip_packed(); + packed->originalRequest = std::move(request->rpcRequest); + packed->packed_data_to_send = buffer; + request->rpcRequest = std::unique_ptr(packed); + requestLength = packed->getObjectSize(); + } + original->reuse(); + } + request->messageId = generateMessageId(); + request->serializedLength = requestLength; + request->messageSeqNo = connection->generateMessageSeqNo(true); + request->startTime = (int32_t) (getCurrentTimeMillis() / 1000); + request->connectionToken = connection->getConnectionToken(); + + NetworkMessage *networkMessage = new NetworkMessage(); + networkMessage->message = std::unique_ptr(new TL_message()); + networkMessage->message->msg_id = request->messageId; + networkMessage->message->bytes = request->serializedLength; + networkMessage->message->outgoingBody = request->getRpcRequest(); + networkMessage->message->seqno = request->messageSeqNo; + networkMessage->requestId = request->requestToken; + networkMessage->invokeAfter = (request->requestFlags & RequestFlagInvokeAfter) != 0; + networkMessage->needQuickAck = (request->requestFlags & RequestFlagNeedQuickAck) != 0; + + runningRequests.push_back(std::move(*iter)); + + switch (request->connectionType & 0x0000ffff) { + case ConnectionTypeGeneric: + addMessageToDatacenter(requestDatacenter->getDatacenterId(), networkMessage, genericMessagesToDatacenters); + break; + case ConnectionTypeDownload: + case ConnectionTypeUpload: { + std::vector> array; + array.push_back(std::unique_ptr(networkMessage)); + sendMessagesToConnectionWithConfirmation(array, connection, false); + break; + } + default: + delete networkMessage; + } + + iter = requestsQueue.erase(iter); + } + + for (std::map::iterator iter = datacenters.begin(); iter != datacenters.end(); iter++) { + Datacenter *datacenter = iter->second; + std::map>>::iterator iter2 = genericMessagesToDatacenters.find(datacenter->getDatacenterId()); + if (iter2 == genericMessagesToDatacenters.end()) { + Connection *connection = datacenter->getGenericConnection(false); + if (connection != nullptr && connection->getConnectionToken() != 0 && connection->hasMessagesToConfirm()) { + genericMessagesToDatacenters[datacenter->getDatacenterId()] = std::vector>(); + } + } + } + + for (std::map>>::iterator iter = genericMessagesToDatacenters.begin(); iter != genericMessagesToDatacenters.end(); iter++) { + Datacenter *datacenter = getDatacenterWithId(iter->first); + if (datacenter != nullptr) { + bool scannedPreviousRequests = false; + int64_t lastSentMessageRpcId = 0; + bool needQuickAck = false; + std::vector> &array = iter->second; + size_t count = array.size(); + for (uint32_t b = 0; b < count; b++) { + NetworkMessage *networkMessage = array[b].get(); + if (networkMessage->needQuickAck) { + needQuickAck = true; + } + if (networkMessage->invokeAfter) { + if (!scannedPreviousRequests) { + scannedPreviousRequests = true; + + std::vector currentRequests; + for (uint32_t a = 0; a < count; a++) { + NetworkMessage *currentNetworkMessage = array[a].get(); + TL_message *currentMessage = currentNetworkMessage->message.get(); + if (currentNetworkMessage->invokeAfter) { + currentRequests.push_back(currentMessage->msg_id); + } + } + + int64_t maxRequestId = 0; + for (requestsIter iter2 = runningRequests.begin(); iter2 != runningRequests.end(); iter2++) { + Request *request = iter2->get(); + if (request->requestFlags & RequestFlagInvokeAfter) { + if (request->messageId > maxRequestId && std::find(currentRequests.begin(), currentRequests.end(), request->messageId) == currentRequests.end()) { + maxRequestId = request->messageId; + } + } + } + + lastSentMessageRpcId = maxRequestId; + } + + TL_message *message = networkMessage->message.get(); + + if (lastSentMessageRpcId != 0 && lastSentMessageRpcId != message->msg_id) { + TL_invokeAfterMsg *request = new TL_invokeAfterMsg(); + request->msg_id = lastSentMessageRpcId; + if (message->outgoingBody != nullptr) { + DEBUG_D("wrap outgoingBody(%p, %s) to TL_invokeAfterMsg", message->outgoingBody, typeid(*message->outgoingBody).name()); + request->outgoingQuery = message->outgoingBody; + message->outgoingBody = nullptr; + } else { + DEBUG_D("wrap body(%p, %s) to TL_invokeAfterMsg", message->body.get(), typeid(*(message->body.get())).name()); + request->query = std::move(message->body); + } + message->body = std::unique_ptr(request); + message->bytes += 4 + 8; + } + + lastSentMessageRpcId = message->msg_id; + } + } + + sendMessagesToConnectionWithConfirmation(array, datacenter->getGenericConnection(true), needQuickAck); + } + } + + if (connectionTypes == ConnectionTypeGeneric && dc == currentDatacenterId) { + std::map>>::iterator iter2 = genericMessagesToDatacenters.find(currentDatacenterId); + if (iter2 == genericMessagesToDatacenters.end()) { + sendPing(getDatacenterWithId(currentDatacenterId), false); + } + } + + if (!unknownDatacenterIds.empty()) { + updateDcSettings(0); + } + + size_t count = neededDatacenters.size(); + for (uint32_t a = 0; a < count; a++) { + Datacenter *datacenter = neededDatacenters[a]; + if (datacenter->getDatacenterId() != movingToDatacenterId && !datacenter->isHandshaking() && !datacenter->hasAuthKey()) { + datacenter->beginHandshake(true); + } + } + + if (currentUserId) { + count = unauthorizedDatacenters.size(); + for (uint32_t a = 0; a < count; a++) { + Datacenter *datacenter = unauthorizedDatacenters[a]; + uint32_t id = datacenter->getDatacenterId(); + if (id != currentDatacenterId && id != movingToDatacenterId && !datacenter->isExportingAuthorization()) { + datacenter->exportAuthorization(); + } + } + } +} + +Datacenter *ConnectionsManager::getDatacenterWithId(uint32_t datacenterId) { + if (datacenterId == DEFAULT_DATACENTER_ID) { + return datacenters[currentDatacenterId]; + } + std::map::iterator iter = datacenters.find(datacenterId); + return iter != datacenters.end() ? iter->second : nullptr; +} + +std::unique_ptr ConnectionsManager::wrapInLayer(TLObject *object, Datacenter *datacenter, Request *baseRequest) { + if (object->isNeedLayer()) { + if (datacenter == nullptr || datacenter->lastInitVersion != currentVersion) { + if (datacenter->getDatacenterId() == currentDatacenterId) { + registerForInternalPushUpdates(); + } + baseRequest->isInitRequest = true; + initConnection *request = new initConnection(); + request->query = std::unique_ptr(object); + request->api_id = currentApiId; + request->app_version = currentAppVersion; + request->device_model = currentDeviceModel; + request->lang_code = currentLangCode; + request->system_version = currentSystemVersion; + if (request->lang_code.empty()) { + request->lang_code = "en"; + } + if (request->device_model.empty()) { + request->device_model = "device model unknown"; + } + if (request->app_version.empty()) { + request->app_version = "app version unknown"; + } + if (request->system_version.empty()) { + request->system_version = "system version unknown"; + } + invokeWithLayer *request2 = new invokeWithLayer(); + request2->layer = currentLayer; + request2->query = std::unique_ptr(request); + DEBUG_D("wrap in layer %s", typeid(*object).name()); + return std::unique_ptr(request2); + } + } + return std::unique_ptr(object); +} + +void ConnectionsManager::updateDcSettings(uint32_t dcNum) { + if (updatingDcSettings) { + return; + } + updatingDcStartTime = (int32_t) (getCurrentTimeMillis() / 1000); + updatingDcSettings = true; + TL_help_getConfig *request = new TL_help_getConfig(); + + sendRequest(request, [&](TLObject *response, TL_error *error) { + if (!updatingDcSettings) { + return; + } + + if (response != nullptr) { + TL_config *config = (TL_config *) response; + int32_t updateIn = config->expires - getCurrentTime(); + if (updateIn <= 0) { + updateIn = 120; + } + lastDcUpdateTime = (int32_t) (getCurrentTimeMillis() / 1000) - DC_UPDATE_TIME + updateIn; + + struct DatacenterInfo { + std::vector addressesIpv4; + std::vector addressesIpv6; + std::vector addressesIpv4Download; + std::vector addressesIpv6Download; + std::map ports; + + void addAddressAndPort(std::string address, uint32_t port, uint32_t flags) { + std::vector *addresses; + if ((flags & 2) != 0) { + if ((flags & 1) != 0) { + addresses = &addressesIpv6Download; + } else { + addresses = &addressesIpv4Download; + } + } else { + if ((flags & 1) != 0) { + addresses = &addressesIpv6; + } else { + addresses = &addressesIpv4; + } + } + if (std::find(addresses->begin(), addresses->end(), address) != addresses->end()) { + return; + } + addresses->push_back(address); + ports[address] = port; + } + }; + + std::map> map; + size_t count = config->dc_options.size(); + for (uint32_t a = 0; a < count; a++) { + TL_dcOption *dcOption = config->dc_options[a].get(); + std::map>::iterator iter = map.find((uint32_t) dcOption->id); + DatacenterInfo *info; + if (iter == map.end()) { + map[dcOption->id] = std::unique_ptr(info = new DatacenterInfo); + } else { + info = iter->second.get(); + } + info->addAddressAndPort(dcOption->ip_address, (uint32_t) dcOption->port, (uint32_t) dcOption->flags); + } + + if (!map.empty()) { + for (std::map>::iterator iter = map.begin(); iter != map.end(); iter++) { + Datacenter *datacenter = getDatacenterWithId(iter->first); + DatacenterInfo *info = iter->second.get(); + if (datacenter == nullptr) { + datacenter = new Datacenter(iter->first); + datacenters[iter->first] = datacenter; + } + datacenter->replaceAddressesAndPorts(info->addressesIpv4, info->ports, 0); + datacenter->replaceAddressesAndPorts(info->addressesIpv6, info->ports, 1); + datacenter->replaceAddressesAndPorts(info->addressesIpv4Download, info->ports, 2); + datacenter->replaceAddressesAndPorts(info->addressesIpv6Download, info->ports, 3); + if (iter->first == movingToDatacenterId) { + movingToDatacenterId = DEFAULT_DATACENTER_ID; + moveToDatacenter(iter->first); + } + } + saveConfig(); + processRequestQueue(AllConnectionTypes, 0); + } + if (delegate != nullptr) { + delegate->onUpdateConfig(config); + } + } + updatingDcSettings = false; + }, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin | RequestFlagTryDifferentDc, dcNum == 0 ? currentDatacenterId : dcNum, ConnectionTypeGeneric, true); +} + +void ConnectionsManager::moveToDatacenter(uint32_t datacenterId) { + if (movingToDatacenterId == datacenterId) { + return; + } + movingToDatacenterId = datacenterId; + + Datacenter *currentDatacenter = getDatacenterWithId(currentDatacenterId); + clearRequestsForDatacenter(currentDatacenter); + + if (currentUserId) { + TL_auth_exportAuthorization *request = new TL_auth_exportAuthorization(); + request->dc_id = datacenterId; + sendRequest(request, [&, datacenterId](TLObject *response, TL_error *error) { + if (error == nullptr) { + movingAuthorization = std::move(((TL_auth_exportedAuthorization *) response)->bytes); + authorizeOnMovingDatacenter(); + } else { + moveToDatacenter(datacenterId); + } + }, nullptr, RequestFlagWithoutLogin, DEFAULT_DATACENTER_ID, ConnectionTypeGeneric, true); + } else { + authorizeOnMovingDatacenter(); + } +} + +void ConnectionsManager::authorizeOnMovingDatacenter() { + Datacenter *datacenter = getDatacenterWithId(movingToDatacenterId); + if (datacenter == nullptr) { + updateDcSettings(0); + return; + } + datacenter->recreateSessions(); + clearRequestsForDatacenter(datacenter); + + if (!datacenter->hasAuthKey() && !datacenter->isHandshaking()) { + datacenter->clearServerSalts(); + datacenter->beginHandshake(true); + } + + if (movingAuthorization != nullptr) { + TL_auth_importAuthorization *request = new TL_auth_importAuthorization(); + request->id = currentUserId; + request->bytes = std::move(movingAuthorization); + sendRequest(request, [&](TLObject *response, TL_error *error) { + if (error == nullptr) { + authorizedOnMovingDatacenter(); + } else { + moveToDatacenter(movingToDatacenterId); + } + }, nullptr, RequestFlagWithoutLogin, datacenter->getDatacenterId(), ConnectionTypeGeneric, true); + } else { + authorizedOnMovingDatacenter(); + } +} + +void ConnectionsManager::authorizedOnMovingDatacenter() { + movingAuthorization.reset(); + currentDatacenterId = movingToDatacenterId; + movingToDatacenterId = DEFAULT_DATACENTER_ID; + saveConfig(); + processRequestQueue(0, 0); +} + +void ConnectionsManager::applyDatacenterAddress(uint32_t datacenterId, std::string ipAddress, uint32_t port) { + scheduleTask([&, datacenterId, ipAddress, port] { + Datacenter *datacenter = getDatacenterWithId(datacenterId); + if (datacenter != nullptr) { + std::vector addresses; + std::map ports; + addresses.push_back(ipAddress); + ports[ipAddress] = port; + datacenter->replaceAddressesAndPorts(addresses, ports, 0); + datacenter->suspendConnections(); + updateDcSettings(datacenterId); + } + }); +} + +ConnectionState ConnectionsManager::getConnectionState() { + return connectionState; +} + +void ConnectionsManager::setDelegate(ConnectiosManagerDelegate *connectiosManagerDelegate) { + delegate = connectiosManagerDelegate; +} + +void ConnectionsManager::setPushConnectionEnabled(bool value) { + pushConnectionEnabled = value; + Datacenter *datacenter = getDatacenterWithId(currentDatacenterId); + if (datacenter != nullptr) { + if (!pushConnectionEnabled) { + Connection *connection = datacenter->getPushConnection(false); + if (connection != nullptr) { + connection->suspendConnection(); + } + } else { + datacenter->createPushConnection()->setSessionId(pushSessionId); + sendPing(datacenter, true); + } + } +} + +void ConnectionsManager::init(uint32_t version, int32_t layer, int32_t apiId, std::string deviceModel, std::string systemVersion, std::string appVersion, std::string langCode, std::string configPath, std::string logPath, int32_t userId, bool isPaused, bool enablePushConnection) { + currentVersion = version; + currentLayer = layer; + currentApiId = apiId; + currentConfigPath = configPath; + currentDeviceModel = deviceModel; + currentSystemVersion = systemVersion; + currentAppVersion = appVersion; + currentLangCode = langCode; + currentUserId = userId; + currentLogPath = logPath; + pushConnectionEnabled = enablePushConnection; + if (isPaused) { + lastPauseTime = getCurrentTimeMillis(); + } + + if (!currentConfigPath.empty() && currentConfigPath.find_last_of('/') != currentConfigPath.size() - 1) { + currentConfigPath += "/"; + } + + if (!logPath.empty()) { + FileLog::init(logPath); + } + + loadConfig(); + + pthread_create(&networkThread, NULL, (ConnectionsManager::ThreadProc), this); +} + +void ConnectionsManager::resumeNetwork(bool partial) { + scheduleTask([&, partial] { + if (partial) { + if (networkPaused) { + lastPauseTime = getCurrentTimeMillis(); + networkPaused = false; + DEBUG_D("wakeup network in background"); + } else if (lastPauseTime != 0) { + lastPauseTime = getCurrentTimeMillis(); + networkPaused = false; + DEBUG_D("reset sleep timeout"); + } + } else { + lastPauseTime = 0; + networkPaused = false; + } + }); +} + +void ConnectionsManager::pauseNetwork() { + if (lastPauseTime != 0) { + return; + } + lastPauseTime = getCurrentTimeMillis(); +} + +void ConnectionsManager::setNetworkAvailable(bool value) { + scheduleTask([&, value] { + networkAvailable = value; + if (!networkAvailable) { + connectionState = ConnectionStateWaitingForNetwork; + } else { + for (std::map::iterator iter = datacenters.begin(); iter != datacenters.end(); iter++) { + if (iter->second->isHandshaking()) { + iter->second->createGenericConnection()->connect(); + } + } + } + if (delegate != nullptr) { + delegate->onConnectionStateChanged(connectionState); + } + }); +} + +void ConnectionsManager::setUseIpv6(bool value) { + scheduleTask([&, value] { + ipv6Enabled = value; + }); +} + +#ifdef ANDROID +void ConnectionsManager::useJavaVM(JavaVM *vm, bool useJavaByteBuffers) { + javaVm = vm; + if (useJavaByteBuffers) { + JNIEnv *env = 0; + if (javaVm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { + DEBUG_E("can't get jnienv"); + exit(1); + } + jclass_ByteBuffer = (jclass) env->NewGlobalRef(env->FindClass("java/nio/ByteBuffer")); + if (jclass_ByteBuffer == 0) { + DEBUG_E("can't find java ByteBuffer class"); + exit(1); + } + jclass_ByteBuffer_allocateDirect = env->GetStaticMethodID(jclass_ByteBuffer, "allocateDirect", "(I)Ljava/nio/ByteBuffer;"); + if (jclass_ByteBuffer_allocateDirect == 0) { + DEBUG_E("can't find java ByteBuffer allocateDirect"); + exit(1); + } + DEBUG_D("using java ByteBuffer"); + } +} +#endif + +/* + public void applyCountryPortNumber(final String phone) { + if (phone == null || phone.length() == 0) { + return; + } + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (phone.startsWith("968")) { + for (HashMap.Entry entry : datacenters.entrySet()) { + Datacenter datacenter = entry.getValue(); + datacenter.overridePort = 8888; + datacenter.suspendConnections(); + } + } else { + for (HashMap.Entry entry : datacenters.entrySet()) { + Datacenter datacenter = entry.getValue(); + datacenter.overridePort = -1; + } + } + } + }); + } +*/ diff --git a/TMessagesProj/jni/tgnet/ConnectionsManager.h b/TMessagesProj/jni/tgnet/ConnectionsManager.h new file mode 100644 index 00000000..ecfad29d --- /dev/null +++ b/TMessagesProj/jni/tgnet/ConnectionsManager.h @@ -0,0 +1,197 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef CONNECTIONSMANAGER_H +#define CONNECTIONSMANAGER_H + +#include +#include +#include +#include +#include +#include +#include +#include "Defines.h" + +#ifdef ANDROID +#include +#endif + +class NativeByteBuffer; +class Connection; +class Datacenter; +class Request; +class DatacenterHandshake; +class TLObject; +class ConnectionSocket; +class TL_auth_exportedAuthorization; +class ByteArray; +class TL_config; +class EventObject; +class Config; + +class ConnectionsManager { + +public: + ConnectionsManager(); + ~ConnectionsManager(); + + static ConnectionsManager &getInstance(); + int64_t getCurrentTimeMillis(); + int32_t getCurrentTime(); + int32_t getTimeDifference(); + int32_t sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate); + void sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken); + void cancelRequest(int32_t token, bool notifyServer); + void cleanUp(); + void cancelRequestsForGuid(int32_t guid); + void bindRequestToGuid(int32_t requestToken, int32_t guid); + void applyDatacenterAddress(uint32_t datacenterId, std::string ipAddress, uint32_t port); + void setDelegate(ConnectiosManagerDelegate *connectiosManagerDelegate); + ConnectionState getConnectionState(); + void setUserId(int32_t userId); + void switchBackend(); + void resumeNetwork(bool partial); + void pauseNetwork(); + void setNetworkAvailable(bool value); + void setUseIpv6(bool value); + void init(uint32_t version, int32_t layer, int32_t apiId, std::string deviceModel, std::string systemVersion, std::string appVersion, std::string langCode, std::string configPath, std::string logPath, int32_t userId, bool isPaused, bool enablePushConnection); + void updateDcSettings(uint32_t datacenterId); + void setPushConnectionEnabled(bool value); + +#ifdef ANDROID + void sendRequest(TLObject *object, onCompleteFunc onComplete, onQuickAckFunc onQuickAck, uint32_t flags, uint32_t datacenterId, ConnectionType connetionType, bool immediate, int32_t requestToken, jobject ptr1, jobject ptr2); + static void useJavaVM(JavaVM *vm, bool useJavaByteBuffers); +#endif + +private: + static void *ThreadProc(void *data); + + void initDatacenters(); + void loadConfig(); + void saveConfig(); + void select(); + void wakeup(); + void processServerResponse(TLObject *message, int64_t messageId, int32_t messageSeqNo, int64_t messageSalt, Connection *connection, int64_t innerMsgId, int64_t containerMessageId); + void sendPing(Datacenter *datacenter, bool usePushConnection); + void sendMessagesToConnection(std::vector> &messages, Connection *connection, bool reportAck); + void sendMessagesToConnectionWithConfirmation(std::vector> &messages, Connection *connection, bool reportAck); + void requestSaltsForDatacenter(Datacenter *datacenter); + void clearRequestsForDatacenter(Datacenter *datacenter); + void registerForInternalPushUpdates(); + void processRequestQueue(uint32_t connectionType, uint32_t datacenterId); + void moveToDatacenter(uint32_t datacenterId); + void authorizeOnMovingDatacenter(); + void authorizedOnMovingDatacenter(); + Datacenter *getDatacenterWithId(uint32_t datacenterId); + std::unique_ptr wrapInLayer(TLObject *object, Datacenter *datacenter, Request *baseRequest); + void removeRequestFromGuid(int32_t requestToken); + void cancelRequestInternal(int32_t token, bool notifyServer, bool removeFromClass); + int callEvents(int64_t now); + + void checkPendingTasks(); + void scheduleTask(std::function task); + void scheduleEvent(EventObject *eventObject, uint32_t time); + void removeEvent(EventObject *eventObject); + void onConnectionClosed(Connection *connection); + void onConnectionConnected(Connection *connection); + void onConnectionQuickAckReceived(Connection *connection, int32_t ack); + void onConnectionDataReceived(Connection *connection, NativeByteBuffer *data, uint32_t length); + void attachConnection(ConnectionSocket *connection); + void detachConnection(ConnectionSocket *connection); + TLObject *TLdeserialize(TLObject *request, uint32_t bytes, NativeByteBuffer *data); + TLObject *getRequestWithMessageId(int64_t messageId); + void onDatacenterHandshakeComplete(Datacenter *datacenter, int32_t timeDiff); + void onDatacenterExportAuthorizationComplete(Datacenter *datacenter); + int64_t generateMessageId(); + bool isIpv6Enabled(); + bool isNetworkAvailable(); + + uint32_t configVersion = 2; + Config *config = nullptr; + + std::list events; + + std::map datacenters; + std::map> quickAckIdToRequestIds; + int32_t pingTime; + bool testBackend = false; + std::atomic lastRequestToken{1}; + uint32_t currentDatacenterId = 0; + uint32_t movingToDatacenterId = DEFAULT_DATACENTER_ID; + int64_t pushSessionId = 0; + int32_t currentPingTime = 0; + bool registeringForPush = false; + int64_t lastPushPingTime = 0; + bool sendingPushPing = false; + bool updatingDcSettings = false; + int32_t updatingDcStartTime = 0; + int32_t lastDcUpdateTime = 0; + int64_t lastPingTime = getCurrentTimeMillis(); + bool networkPaused = false; + int32_t nextSleepTimeout = CONNECTION_BACKGROUND_KEEP_TIME; + int64_t lastPauseTime = 0; + ConnectionState connectionState = ConnectionStateConnecting; + std::unique_ptr movingAuthorization; + std::vector sessionsToDestroy; + int32_t lastDestroySessionRequestTime; + std::map> requestsByGuids; + std::map guidsByRequests; + + pthread_t networkThread; + pthread_mutex_t mutex; + std::queue> pendingTasks; + struct epoll_event *epollEvents; + timespec timeSpec; + int32_t timeDifference = 0; + int64_t lastOutgoingMessageId = 0; + bool networkAvailable = true; + bool ipv6Enabled = false; + std::vector activeConnections; + int epolFd; + int *pipeFd; + NativeByteBuffer *networkBuffer; + + requestsList requestsQueue; + requestsList runningRequests; + std::vector requestingSaltsForDc; + int32_t lastPingId = 0; + + uint32_t currentVersion = 1; + int32_t currentLayer = 34; + int32_t currentApiId = 6; + std::string currentDeviceModel; + std::string currentSystemVersion; + std::string currentAppVersion; + std::string currentLangCode; + std::string currentConfigPath; + std::string currentLogPath; + int32_t currentUserId = 0; + bool registeredForInternalPush = false; + bool pushConnectionEnabled = true; + + ConnectiosManagerDelegate *delegate; + + friend class ConnectionSocket; + friend class ConnectionSession; + friend class Connection; + friend class Timer; + friend class Datacenter; + friend class TL_message; + friend class TL_rpc_result; + friend class Config; +}; + +#ifdef ANDROID +extern JavaVM *javaVm; +extern JNIEnv *jniEnv; +extern jclass jclass_ByteBuffer; +extern jmethodID jclass_ByteBuffer_allocateDirect; +#endif + +#endif diff --git a/TMessagesProj/jni/tgnet/Datacenter.cpp b/TMessagesProj/jni/tgnet/Datacenter.cpp new file mode 100644 index 00000000..d5256199 --- /dev/null +++ b/TMessagesProj/jni/tgnet/Datacenter.cpp @@ -0,0 +1,1590 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "Datacenter.h" +#include "Connection.h" +#include "MTProtoScheme.h" +#include "FileLog.h" +#include "NativeByteBuffer.h" +#include "ByteArray.h" +#include "BuffersStorage.h" +#include "ConnectionsManager.h" +#include "Config.h" + +static std::vector serverPublicKeys; +static std::vector serverPublicKeysFingerprints; +static BN_CTX *bnContext; + +Datacenter::Datacenter(uint32_t id) { + datacenterId = id; + for (uint32_t a = 0; a < DOWNLOAD_CONNECTIONS_COUNT; a++) { + downloadConnections[a] = nullptr; + } +} + +Datacenter::Datacenter(NativeByteBuffer *data) { + for (uint32_t a = 0; a < DOWNLOAD_CONNECTIONS_COUNT; a++) { + downloadConnections[a] = nullptr; + } + uint32_t currentVersion = data->readUint32(nullptr); + if (currentVersion >= 2 && currentVersion <= 5) { + datacenterId = data->readUint32(nullptr); + if (currentVersion >= 3) { + lastInitVersion = data->readUint32(nullptr); + } + uint32_t len = data->readUint32(nullptr); + for (uint32_t a = 0; a < len; a++) { + std::string address = data->readString(nullptr); + addressesIpv4.push_back(address); + ports[address] = data->readUint32(nullptr); + } + if (currentVersion >= 5) { + len = data->readUint32(nullptr); + for (uint32_t a = 0; a < len; a++) { + std::string address = data->readString(nullptr); + addressesIpv6.push_back(address); + ports[address] = data->readUint32(nullptr); + } + len = data->readUint32(nullptr); + for (uint32_t a = 0; a < len; a++) { + std::string address = data->readString(nullptr); + addressesIpv4Download.push_back(address); + ports[address] = data->readUint32(nullptr); + } + len = data->readUint32(nullptr); + for (uint32_t a = 0; a < len; a++) { + std::string address = data->readString(nullptr); + addressesIpv6Download.push_back(address); + ports[address] = data->readUint32(nullptr); + } + } + len = data->readUint32(nullptr); + if (len != 0) { + authKey = data->readBytes(len, nullptr); + } + if (currentVersion >= 4) { + authKeyId = data->readInt64(nullptr); + } else { + len = data->readUint32(nullptr); + if (len != 0) { + authKeyId = data->readInt64(nullptr); + } + } + authorized = data->readInt32(nullptr) != 0; + len = data->readUint32(nullptr); + for (uint32_t a = 0; a < len; a++) { + TL_future_salt *salt = new TL_future_salt(); + salt->valid_since = data->readInt32(nullptr); + salt->valid_until = data->readInt32(nullptr); + salt->salt = data->readInt64(nullptr); + serverSalts.push_back(std::unique_ptr(salt)); + } + } + + if (config == nullptr) { + config = new Config("dc" + to_string_int32(datacenterId) + "conf.dat"); + } + NativeByteBuffer *buffer = config->readConfig(); + if (buffer != nullptr) { + uint32_t version = buffer->readUint32(nullptr); + if (version <= paramsConfigVersion) { + currentPortNumIpv4 = buffer->readUint32(nullptr); + currentAddressNumIpv4 = buffer->readUint32(nullptr); + currentPortNumIpv6 = buffer->readUint32(nullptr); + currentAddressNumIpv6 = buffer->readUint32(nullptr); + currentPortNumIpv4Download = buffer->readUint32(nullptr); + currentAddressNumIpv4Download = buffer->readUint32(nullptr); + currentPortNumIpv6Download = buffer->readUint32(nullptr); + currentAddressNumIpv6Download = buffer->readUint32(nullptr); + } + buffer->reuse(); + } else { + currentPortNumIpv4 = 0; + currentAddressNumIpv4 = 0; + currentPortNumIpv6 = 0; + currentAddressNumIpv6 = 0; + currentPortNumIpv4Download = 0; + currentAddressNumIpv4Download = 0; + currentPortNumIpv6Download = 0; + currentAddressNumIpv6Download = 0; + } +} + +void Datacenter::switchTo443Port() { + for (uint32_t a = 0; a < addressesIpv4.size(); a++) { + if (ports[addressesIpv4[a]] == 443) { + currentAddressNumIpv4 = a; + currentPortNumIpv4 = 0; + break; + } + } + for (uint32_t a = 0; a < addressesIpv6.size(); a++) { + if (ports[addressesIpv6[a]] == 443) { + currentAddressNumIpv6 = a; + currentPortNumIpv6 = 0; + break; + } + } + for (uint32_t a = 0; a < addressesIpv4Download.size(); a++) { + if (ports[addressesIpv4Download[a]] == 443) { + currentAddressNumIpv4Download = a; + currentPortNumIpv4Download = 0; + break; + } + } + for (uint32_t a = 0; a < addressesIpv6Download.size(); a++) { + if (ports[addressesIpv6Download[a]] == 443) { + currentAddressNumIpv6Download = a; + currentPortNumIpv6Download = 0; + break; + } + } +} + +std::string Datacenter::getCurrentAddress(uint32_t flags) { + uint32_t currentAddressNum; + std::vector *addresses; + if ((flags & 2) != 0) { + if ((flags & 1) != 0) { + currentAddressNum = currentAddressNumIpv6Download; + addresses = &addressesIpv6Download; + } else { + currentAddressNum = currentAddressNumIpv4Download; + addresses = &addressesIpv4Download; + } + } else { + if ((flags & 1) != 0) { + currentAddressNum = currentAddressNumIpv6; + addresses = &addressesIpv6; + } else { + currentAddressNum = currentAddressNumIpv4; + addresses = &addressesIpv4; + } + } + if (addresses->empty()) { + return std::string(""); + } + if (currentAddressNum >= addresses->size()) { + currentAddressNum = 0; + if ((flags & 2) != 0) { + if ((flags & 1) != 0) { + currentAddressNumIpv6Download = currentAddressNum; + } else { + currentAddressNumIpv4Download = currentAddressNum; + } + } else { + if ((flags & 1) != 0) { + currentAddressNumIpv6 = currentAddressNum; + } else { + currentAddressNumIpv4 = currentAddressNum; + } + } + } + return (*addresses)[currentAddressNum]; +} + +int32_t Datacenter::getCurrentPort(uint32_t flags) { + if (ports.empty()) { + return overridePort == -1 ? 443 : overridePort; + } + + const int32_t *portsArray = overridePort == 8888 ? defaultPorts8888 : defaultPorts; + + uint32_t currentPortNum; + if ((flags & 2) != 0) { + if ((flags & 1) != 0) { + currentPortNum = currentPortNumIpv6Download; + } else { + currentPortNum = currentPortNumIpv4Download; + } + } else { + if ((flags & 1) != 0) { + currentPortNum = currentPortNumIpv6; + } else { + currentPortNum = currentPortNumIpv4; + } + } + + if (currentPortNum >= 11) { + currentPortNum = 0; + if ((flags & 2) != 0) { + if ((flags & 1) != 0) { + currentPortNumIpv6Download = currentPortNum; + } else { + currentPortNumIpv4Download = currentPortNum; + } + } else { + if ((flags & 1) != 0) { + currentPortNumIpv6 = currentPortNum; + } else { + currentPortNumIpv4 = currentPortNum; + } + } + } + int32_t port = portsArray[currentPortNum]; + if (port == -1) { + if (overridePort != -1) { + return overridePort; + } + std::string address = getCurrentAddress(flags); + return ports[address]; + } + return port; +} + +void Datacenter::addAddressAndPort(std::string address, uint32_t port, uint32_t flags) { + std::vector *addresses; + if ((flags & 2) != 0) { + if ((flags & 1) != 0) { + addresses = &addressesIpv6Download; + } else { + addresses = &addressesIpv4Download; + } + } else { + if ((flags & 1) != 0) { + addresses = &addressesIpv6; + } else { + addresses = &addressesIpv4; + } + } + if (std::find(addresses->begin(), addresses->end(), address) != addresses->end()) { + return; + } + addresses->push_back(address); + ports[address] = port; +} + +void Datacenter::nextAddressOrPort(uint32_t flags) { + uint32_t currentPortNum; + uint32_t currentAddressNum; + std::vector *addresses; + if ((flags & 2) != 0) { + if ((flags & 1) != 0) { + currentPortNum = currentPortNumIpv6Download; + currentAddressNum = currentAddressNumIpv6Download; + addresses = &addressesIpv6Download; + } else { + currentPortNum = currentPortNumIpv4Download; + currentAddressNum = currentAddressNumIpv4Download; + addresses = &addressesIpv4Download; + } + } else { + if ((flags & 1) != 0) { + currentPortNum = currentPortNumIpv6; + currentAddressNum = currentAddressNumIpv6; + addresses = &addressesIpv6; + } else { + currentPortNum = currentPortNumIpv4; + currentAddressNum = currentAddressNumIpv4; + addresses = &addressesIpv4; + } + } + if (currentPortNum + 1 < 11) { + currentPortNum++; + } else { + if (currentAddressNum + 1 < addresses->size()) { + currentAddressNum++; + } else { + currentAddressNum = 0; + } + currentPortNum = 0; + } + if ((flags & 2) != 0) { + if ((flags & 1) != 0) { + currentPortNumIpv6Download = currentPortNum; + currentAddressNumIpv6Download = currentAddressNum; + } else { + currentPortNumIpv4Download = currentPortNum; + currentAddressNumIpv4Download = currentAddressNum; + } + } else { + if ((flags & 1) != 0) { + currentPortNumIpv6 = currentPortNum; + currentAddressNumIpv6 = currentAddressNum; + } else { + currentPortNumIpv4 = currentPortNum; + currentAddressNumIpv4 = currentAddressNum; + } + } +} + +void Datacenter::storeCurrentAddressAndPortNum() { + if (config == nullptr) { + config = new Config("dc" + to_string_int32(datacenterId) + "conf.dat"); + } + NativeByteBuffer *buffer = BuffersStorage::getInstance().getFreeBuffer(128); + buffer->writeInt32(paramsConfigVersion); + buffer->writeInt32(currentPortNumIpv4); + buffer->writeInt32(currentAddressNumIpv4); + buffer->writeInt32(currentPortNumIpv6); + buffer->writeInt32(currentAddressNumIpv6); + buffer->writeInt32(currentPortNumIpv4Download); + buffer->writeInt32(currentAddressNumIpv4Download); + buffer->writeInt32(currentPortNumIpv6Download); + buffer->writeInt32(currentAddressNumIpv6Download); + config->writeConfig(buffer); + buffer->reuse(); +} + +void Datacenter::replaceAddressesAndPorts(std::vector &newAddresses, std::map &newPorts, uint32_t flags) { + std::vector *addresses; + if ((flags & 2) != 0) { + if ((flags & 1) != 0) { + addresses = &addressesIpv6Download; + } else { + addresses = &addressesIpv4Download; + } + } else { + if ((flags & 1) != 0) { + addresses = &addressesIpv6; + } else { + addresses = &addressesIpv4; + } + } + size_t size = addresses->size(); + for (uint32_t a = 0; a < size; a++) { + std::map::iterator iter = ports.find((*addresses)[a]); + if (iter != ports.end()) { + ports.erase(iter); + } + } + if ((flags & 2) != 0) { + if ((flags & 1) != 0) { + addressesIpv6Download = newAddresses; + } else { + addressesIpv4Download = newAddresses; + } + } else { + if ((flags & 1) != 0) { + addressesIpv6 = newAddresses; + } else { + addressesIpv4 = newAddresses; + } + } + ports.insert(newPorts.begin(), newPorts.end()); +} + +void Datacenter::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(configVersion); + stream->writeInt32(datacenterId); + stream->writeInt32(lastInitVersion); + size_t size; + stream->writeInt32((int32_t) (size = addressesIpv4.size())); + for (uint32_t a = 0; a < size; a++) { + stream->writeString(addressesIpv4[a]); + stream->writeInt32(ports[addressesIpv4[a]]); + } + stream->writeInt32((int32_t) (size = addressesIpv6.size())); + for (uint32_t a = 0; a < size; a++) { + stream->writeString(addressesIpv6[a]); + stream->writeInt32(ports[addressesIpv6[a]]); + } + stream->writeInt32((int32_t) (size = addressesIpv4Download.size())); + for (uint32_t a = 0; a < size; a++) { + stream->writeString(addressesIpv4Download[a]); + stream->writeInt32(ports[addressesIpv4Download[a]]); + } + stream->writeInt32((int32_t) (size = addressesIpv6Download.size())); + for (uint32_t a = 0; a < size; a++) { + stream->writeString(addressesIpv6Download[a]); + stream->writeInt32(ports[addressesIpv6Download[a]]); + } + if (authKey != nullptr) { + stream->writeInt32(authKey->length); + stream->writeBytes(authKey); + } else { + stream->writeInt32(0); + } + stream->writeInt64(authKeyId); + stream->writeInt32(authorized ? 1 : 0); + stream->writeInt32((int32_t) (size = serverSalts.size())); + for (uint32_t a = 0; a < size; a++) { + stream->writeInt32(serverSalts[a]->valid_since); + stream->writeInt32(serverSalts[a]->valid_until); + stream->writeInt64(serverSalts[a]->salt); + } +} + +void Datacenter::clear() { + authKey = nullptr; + authKeyId = 0; + authorized = false; + serverSalts.clear(); +} + +void Datacenter::clearServerSalts() { + serverSalts.clear(); +} + +int64_t Datacenter::getServerSalt() { + int32_t date = ConnectionsManager::getInstance().getCurrentTime(); + + bool cleanupNeeded = false; + + int64_t result = 0; + int32_t maxRemainingInterval = 0; + + size_t size = serverSalts.size(); + for (uint32_t a = 0; a < size; a++) { + TL_future_salt *salt = serverSalts[a].get(); + if (salt->valid_until < date) { + cleanupNeeded = true; + } else if (salt->valid_since <= date && salt->valid_until > date) { + if (maxRemainingInterval == 0 || abs(salt->valid_until - date) > maxRemainingInterval) { + maxRemainingInterval = abs(salt->valid_until - date); + result = salt->salt; + } + } + } + + if (cleanupNeeded) { + size = serverSalts.size(); + for (uint32_t i = 0; i < size; i++) { + if (serverSalts[i]->valid_until < date) { + serverSalts.erase(serverSalts.begin() + i); + size--; + i--; + } + } + } + + if (result == 0) { + DEBUG_D("dc%u valid salt not found", datacenterId); + } + + return result; +} + +void Datacenter::mergeServerSalts(std::vector> &salts) { + if (salts.empty()) { + return; + } + int32_t date = ConnectionsManager::getInstance().getCurrentTime(); + std::vector existingSalts(serverSalts.size()); + size_t size = serverSalts.size(); + for (uint32_t a = 0; a < size; a++) { + existingSalts.push_back(serverSalts[a]->salt); + } + bool added = false; + size = salts.size(); + for (uint32_t a = 0; a < size; a++) { + int64_t value = salts[a]->salt; + if (std::find(existingSalts.begin(), existingSalts.end(), value) == existingSalts.end() && salts[a]->valid_until > date) { + serverSalts.push_back(std::unique_ptr(std::move(salts[a]))); + added = true; + } + } + if (added) { + std::sort(serverSalts.begin(), serverSalts.end(), [](const std::unique_ptr &x, const std::unique_ptr &y) { return x->valid_since < y->valid_since; }); + } +} + +void Datacenter::addServerSalt(std::unique_ptr &serverSalt) { + size_t size = serverSalts.size(); + for (uint32_t a = 0; a < size; a++) { + if (serverSalts[a]->salt == serverSalt->salt) { + return; + } + } + serverSalts.push_back(std::move(serverSalt)); + std::sort(serverSalts.begin(), serverSalts.end(), [](const std::unique_ptr &x, const std::unique_ptr &y) { return x->valid_since < y->valid_since; }); +} + +bool Datacenter::containsServerSalt(int64_t value) { + size_t size = serverSalts.size(); + for (uint32_t a = 0; a < size; a++) { + if (serverSalts[a]->salt == value) { + return true; + } + } + return false; +} + +void Datacenter::suspendConnections() { + if (genericConnection != nullptr) { + genericConnection->suspendConnection(); + } + if (uploadConnection != nullptr) { + uploadConnection->suspendConnection(); + } + for (uint32_t a = 0; a < DOWNLOAD_CONNECTIONS_COUNT; a++) { + if (downloadConnections[a] != nullptr) { + downloadConnections[a]->suspendConnection(); + } + } +} + +void Datacenter::getSessions(std::vector &sessions) { + if (genericConnection != nullptr) { + sessions.push_back(genericConnection->getSissionId()); + } + if (uploadConnection != nullptr) { + sessions.push_back(uploadConnection->getSissionId()); + } + for (uint32_t a = 0; a < DOWNLOAD_CONNECTIONS_COUNT; a++) { + if (downloadConnections[a] != nullptr) { + sessions.push_back(downloadConnections[a]->getSissionId()); + } + } +} + +void Datacenter::recreateSessions() { + if (genericConnection != nullptr) { + genericConnection->recreateSession(); + } + if (uploadConnection != nullptr) { + uploadConnection->recreateSession(); + } + for (uint32_t a = 0; a < DOWNLOAD_CONNECTIONS_COUNT; a++) { + if (downloadConnections[a] != nullptr) { + downloadConnections[a]->recreateSession(); + } + } +} + +Connection *Datacenter::createDownloadConnection(uint32_t num) { + if (downloadConnections[num] == nullptr) { + downloadConnections[num] = new Connection(this, ConnectionTypeDownload); + } + return downloadConnections[num]; +} + +Connection *Datacenter::createUploadConnection() { + if (uploadConnection == nullptr) { + uploadConnection = new Connection(this, ConnectionTypeUpload); + } + return uploadConnection; +} + +Connection *Datacenter::createGenericConnection() { + if (genericConnection == nullptr) { + genericConnection = new Connection(this, ConnectionTypeGeneric); + } + return genericConnection; +} + +Connection *Datacenter::createPushConnection() { + if (pushConnection == nullptr) { + pushConnection = new Connection(this, ConnectionTypePush); + } + return pushConnection; +} + +uint32_t Datacenter::getDatacenterId() { + return datacenterId; +} + +bool Datacenter::isHandshaking() { + return handshakeState != 0; +} + +void Datacenter::beginHandshake(bool reconnect) { + DEBUG_D("dc%u handshake: begin", datacenterId); + cleanupHandshake(); + createGenericConnection()->recreateSession(); + handshakeState = 1; + + if (reconnect) { + createGenericConnection()->suspendConnection(); + createGenericConnection()->connect(); + } + + TL_req_pq *request = new TL_req_pq(); + request->nonce = std::unique_ptr(new ByteArray(16)); + RAND_bytes(request->nonce->bytes, 16); + authNonce = new ByteArray(request->nonce.get()); + sendRequestData(request, true); +} + +void Datacenter::cleanupHandshake() { + handshakeState = 0; + if (handshakeRequest != nullptr) { + delete handshakeRequest; + handshakeRequest = nullptr; + } + if (handshakeServerSalt != nullptr) { + delete handshakeServerSalt; + handshakeServerSalt = nullptr; + } + if (authNonce != nullptr) { + delete authNonce; + authNonce = nullptr; + } + if (authServerNonce != nullptr) { + delete authServerNonce; + authServerNonce = nullptr; + } + if (authNewNonce != nullptr) { + delete authNewNonce; + authNewNonce = nullptr; + } + if (handshakeAuthKey != nullptr) { + delete handshakeAuthKey; + handshakeAuthKey = nullptr; + } +} + +void Datacenter::sendRequestData(TLObject *object, bool important) { + uint32_t messageLength = object->getObjectSize(); + NativeByteBuffer *buffer = BuffersStorage::getInstance().getFreeBuffer(20 + messageLength); + buffer->writeInt64(0); + buffer->writeInt64(ConnectionsManager::getInstance().generateMessageId()); + buffer->writeInt32(messageLength); + object->serializeToStream(buffer); + createGenericConnection()->sendData(buffer, false); + if (important) { + if (handshakeRequest != object) { + if (handshakeRequest != nullptr) { + delete handshakeRequest; + } + handshakeRequest = object; + } + } else { + delete object; + } +} + +void Datacenter::onHandshakeConnectionClosed(Connection *connection) { + if (handshakeState == 0) { + return; + } + needResendData = true; +} + +void Datacenter::onHandshakeConnectionConnected(Connection *connection) { + if (handshakeState == 0 || !needResendData) { + return; + } + beginHandshake(false); +} + +inline uint64_t gcd(uint64_t a, uint64_t b) { + while (a != 0 && b != 0) { + while ((b & 1) == 0) { + b >>= 1; + } + while ((a & 1) == 0) { + a >>= 1; + } + if (a > b) { + a -= b; + } else { + b -= a; + } + } + return b == 0 ? a : b; +} + +inline bool factorizeValue(uint64_t what, uint32_t &p, uint32_t &q) { + int32_t it = 0, i, j; + uint64_t g = 0; + for (i = 0; i < 3 || it < 1000; i++) { + uint64_t t = ((lrand48() & 15) + 17) % what; + uint64_t x = (long long) lrand48() % (what - 1) + 1, y = x; + int32_t lim = 1 << (i + 18); + for (j = 1; j < lim; j++) { + ++it; + uint64_t a = x, b = x, c = t; + while (b) { + if (b & 1) { + c += a; + if (c >= what) { + c -= what; + } + } + a += a; + if (a >= what) { + a -= what; + } + b >>= 1; + } + x = c; + uint64_t z = x < y ? what + x - y : x - y; + g = gcd(z, what); + if (g != 1) { + break; + } + if (!(j & (j - 1))) { + y = x; + } + } + if (g > 1 && g < what) { + break; + } + } + + if (g > 1 && g < what) { + p = (uint32_t) g; + q = (uint32_t) (what / g); + if (p > q) { + uint32_t tmp = p; + p = q; + q = tmp; + } + return true; + } else { + DEBUG_E("factorization failed for %llu", what); + p = 0; + q = 0; + return false; + } +} + +inline bool check_prime(BIGNUM *p) { + int result = 0; + if (!BN_primality_test(&result, p, BN_prime_checks, bnContext, 0, NULL)) { + DEBUG_E("OpenSSL error at BN_primality_test"); + return false; + } + return result != 0; +} + +inline bool isGoodPrime(BIGNUM *p, uint32_t g) { + //TODO check against known good primes + if (g < 2 || g > 7 || BN_num_bits(p) != 2048) { + return false; + } + + BIGNUM *t = BN_new(); + BIGNUM *dh_g = BN_new(); + + if (!BN_set_word(dh_g, 4 * g)) { + DEBUG_E("OpenSSL error at BN_set_word(dh_g, 4 * g)"); + BN_free(t); + BN_free(dh_g); + return false; + } + if (!BN_mod(t, p, dh_g, bnContext)) { + DEBUG_E("OpenSSL error at BN_mod"); + BN_free(t); + BN_free(dh_g); + return false; + } + uint64_t x = BN_get_word(t); + if (x >= 4 * g) { + DEBUG_E("OpenSSL error at BN_get_word"); + BN_free(t); + BN_free(dh_g); + return false; + } + + BN_free(dh_g); + + bool result = true; + switch (g) { + case 2: + if (x != 7) { + result = false; + } + break; + case 3: + if (x % 3 != 2) { + result = false; + } + break; + case 5: + if (x % 5 != 1 && x % 5 != 4) { + result = false; + } + break; + case 6: + if (x != 19 && x != 23) { + result = false; + } + break; + case 7: + if (x % 7 != 3 && x % 7 != 5 && x % 7 != 6) { + result = false; + } + break; + default: + break; + } + + char *prime = BN_bn2hex(p); + static const char *goodPrime = "c71caeb9c6b1c9048e6c522f70f13f73980d40238e3e21c14934d037563d930f48198a0aa7c14058229493d22530f4dbfa336f6e0ac925139543aed44cce7c3720fd51f69458705ac68cd4fe6b6b13abdc9746512969328454f18faf8c595f642477fe96bb2a941d5bcd1d4ac8cc49880708fa9b378e3c4f3a9060bee67cf9a4a4a695811051907e162753b56b0f6b410dba74d8a84b2a14b3144e0ef1284754fd17ed950d5965b4b9dd46582db1178d169c6bc465b0d6ff9ca3928fef5b9ae4e418fc15e83ebea0f87fa9ff5eed70050ded2849f47bf959d956850ce929851f0d8115f635b105ee2e4e15d04b2454bf6f4fadf034b10403119cd8e3b92fcc5b"; + if (!strcasecmp(prime, goodPrime)) { + delete [] prime; + BN_free(t); + return true; + } + delete [] prime; + + if (!result || !check_prime(p)) { + BN_free(t); + return false; + } + + BIGNUM *b = BN_new(); + if (!BN_set_word(b, 2)) { + DEBUG_E("OpenSSL error at BN_set_word(b, 2)"); + BN_free(b); + BN_free(t); + return false; + } + if (!BN_div(t, 0, p, b, bnContext)) { + DEBUG_E("OpenSSL error at BN_div"); + BN_free(b); + BN_free(t); + return false; + } + if (!check_prime(t)) { + result = false; + } + BN_free(b); + BN_free(t); + return result; +} + +inline bool isGoodGaAndGb(BIGNUM *g_a, BIGNUM *p) { + if (BN_num_bytes(g_a) > 256 || BN_num_bits(g_a) < 2048 - 64 || BN_cmp(p, g_a) <= 0) { + return false; + } + BIGNUM *dif = BN_new(); + BN_sub(dif, p, g_a); + if (BN_num_bits(dif) < 2048 - 64) { + BN_free(dif); + return false; + } + BN_free(dif); + return true; +} + +void Datacenter::aesIgeEncryption(uint8_t *buffer, uint8_t *key, uint8_t *iv, bool encrypt, bool changeIv, uint32_t length) { + uint8_t *ivBytes = iv; + if (!changeIv) { + ivBytes = new uint8_t[32]; + memcpy(ivBytes, iv, 32); + } + AES_KEY akey; + if (!encrypt) { + AES_set_decrypt_key(key, 32 * 8, &akey); + AES_ige_encrypt(buffer, buffer, length, &akey, ivBytes, AES_DECRYPT); + } else { + AES_set_encrypt_key(key, 32 * 8, &akey); + AES_ige_encrypt(buffer, buffer, length, &akey, ivBytes, AES_ENCRYPT); + } + if (!changeIv) { + delete [] ivBytes; + } +} + +int32_t Datacenter::selectPublicKey(std::vector &fingerprints) { + if (serverPublicKeys.empty()) { + serverPublicKeys.push_back("-----BEGIN RSA PUBLIC KEY-----\n" + "MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6\n" + "lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS\n" + "an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw\n" + "Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+\n" + "8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n\n" + "Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB\n" + "-----END RSA PUBLIC KEY-----"); + serverPublicKeysFingerprints.push_back(0xc3b42b026ce86b21LL); + + serverPublicKeys.push_back("-----BEGIN RSA PUBLIC KEY-----\n" + "MIIBCgKCAQEAxq7aeLAqJR20tkQQMfRn+ocfrtMlJsQ2Uksfs7Xcoo77jAid0bRt\n" + "ksiVmT2HEIJUlRxfABoPBV8wY9zRTUMaMA654pUX41mhyVN+XoerGxFvrs9dF1Ru\n" + "vCHbI02dM2ppPvyytvvMoefRoL5BTcpAihFgm5xCaakgsJ/tH5oVl74CdhQw8J5L\n" + "xI/K++KJBUyZ26Uba1632cOiq05JBUW0Z2vWIOk4BLysk7+U9z+SxynKiZR3/xdi\n" + "XvFKk01R3BHV+GUKM2RYazpS/P8v7eyKhAbKxOdRcFpHLlVwfjyM1VlDQrEZxsMp\n" + "NTLYXb6Sce1Uov0YtNx5wEowlREH1WOTlwIDAQAB\n" + "-----END RSA PUBLIC KEY-----"); + serverPublicKeysFingerprints.push_back(0x9a996a1db11c729bLL); + + serverPublicKeys.push_back("-----BEGIN RSA PUBLIC KEY-----\n" + "MIIBCgKCAQEAsQZnSWVZNfClk29RcDTJQ76n8zZaiTGuUsi8sUhW8AS4PSbPKDm+\n" + "DyJgdHDWdIF3HBzl7DHeFrILuqTs0vfS7Pa2NW8nUBwiaYQmPtwEa4n7bTmBVGsB\n" + "1700/tz8wQWOLUlL2nMv+BPlDhxq4kmJCyJfgrIrHlX8sGPcPA4Y6Rwo0MSqYn3s\n" + "g1Pu5gOKlaT9HKmE6wn5Sut6IiBjWozrRQ6n5h2RXNtO7O2qCDqjgB2vBxhV7B+z\n" + "hRbLbCmW0tYMDsvPpX5M8fsO05svN+lKtCAuz1leFns8piZpptpSCFn7bWxiA9/f\n" + "x5x17D7pfah3Sy2pA+NDXyzSlGcKdaUmwQIDAQAB\n" + "-----END RSA PUBLIC KEY-----"); + serverPublicKeysFingerprints.push_back(0xb05b2a6f70cdea78LL); + + serverPublicKeys.push_back("-----BEGIN RSA PUBLIC KEY-----\n" + "MIIBCgKCAQEAwqjFW0pi4reKGbkc9pK83Eunwj/k0G8ZTioMMPbZmW99GivMibwa\n" + "xDM9RDWabEMyUtGoQC2ZcDeLWRK3W8jMP6dnEKAlvLkDLfC4fXYHzFO5KHEqF06i\n" + "qAqBdmI1iBGdQv/OQCBcbXIWCGDY2AsiqLhlGQfPOI7/vvKc188rTriocgUtoTUc\n" + "/n/sIUzkgwTqRyvWYynWARWzQg0I9olLBBC2q5RQJJlnYXZwyTL3y9tdb7zOHkks\n" + "WV9IMQmZmyZh/N7sMbGWQpt4NMchGpPGeJ2e5gHBjDnlIf2p1yZOYeUYrdbwcS0t\n" + "UiggS4UeE8TzIuXFQxw7fzEIlmhIaq3FnwIDAQAB\n" + "-----END RSA PUBLIC KEY-----"); + serverPublicKeysFingerprints.push_back(0x71e025b6c76033e3LL); + } + + size_t count1 = fingerprints.size(); + size_t count2 = serverPublicKeysFingerprints.size(); + for (uint32_t a = 0; a < count1; a++) { + for (uint32_t b = 0; b < count2; b++) { + if ((uint64_t) fingerprints[a] == serverPublicKeysFingerprints[b]) { + return b; + } + } + } + return -1; +} + +void Datacenter::processHandshakeResponse(TLObject *message, int64_t messageId) { + if (handshakeState == 0) { + return; + } + const std::type_info &typeInfo = typeid(*message); + if (typeInfo == typeid(TL_resPQ)) { + if (handshakeState != 1) { + sendAckRequest(messageId); + return; + } + + handshakeState = 2; + TL_resPQ *result = (TL_resPQ *) message; + if (authNonce->isEqualTo(result->nonce.get())) { + int32_t keyIndex = selectPublicKey(result->server_public_key_fingerprints); + if (keyIndex < 0) { + DEBUG_E("dc%u handshake: can't find valid server public key", datacenterId); + beginHandshake(false); + return; + } + + authServerNonce = new ByteArray(result->server_nonce.get()); + + //TODO run in different thread? + uint64_t pq = ((uint64_t) (result->pq->bytes[0] & 0xff) << 56) | + ((uint64_t) (result->pq->bytes[1] & 0xff) << 48) | + ((uint64_t) (result->pq->bytes[2] & 0xff) << 40) | + ((uint64_t) (result->pq->bytes[3] & 0xff) << 32) | + ((uint64_t) (result->pq->bytes[4] & 0xff) << 24) | + ((uint64_t) (result->pq->bytes[5] & 0xff) << 16) | + ((uint64_t) (result->pq->bytes[6] & 0xff) << 8) | + ((uint64_t) (result->pq->bytes[7] & 0xff)); + uint32_t p, q; + if (!factorizeValue(pq, p, q)) { + beginHandshake(false); + return; + } + + TL_req_DH_params *request = new TL_req_DH_params(); + request->nonce = std::unique_ptr(new ByteArray(authNonce)); + request->server_nonce = std::unique_ptr(new ByteArray(authServerNonce)); + request->p = std::unique_ptr(new ByteArray(4)); + request->p->bytes[3] = (uint8_t) p; + request->p->bytes[2] = (uint8_t) (p >> 8); + request->p->bytes[1] = (uint8_t) (p >> 16); + request->p->bytes[0] = (uint8_t) (p >> 24); + request->q = std::unique_ptr(new ByteArray(4)); + request->q->bytes[3] = (uint8_t) q; + request->q->bytes[2] = (uint8_t) (q >> 8); + request->q->bytes[1] = (uint8_t) (q >> 16); + request->q->bytes[0] = (uint8_t) (q >> 24); + request->public_key_fingerprint = (int64_t) serverPublicKeysFingerprints[keyIndex]; + + TL_p_q_inner_data *innerData = new TL_p_q_inner_data(); + innerData->nonce = std::unique_ptr(new ByteArray(authNonce)); + innerData->server_nonce = std::unique_ptr(new ByteArray(authServerNonce)); + innerData->pq = std::unique_ptr(new ByteArray(result->pq.get())); + innerData->p = std::unique_ptr(new ByteArray(request->p.get())); + innerData->q = std::unique_ptr(new ByteArray(request->q.get())); + innerData->new_nonce = std::unique_ptr(new ByteArray(32)); + RAND_bytes(innerData->new_nonce->bytes, 32); + authNewNonce = new ByteArray(innerData->new_nonce.get()); + + uint32_t innerDataSize = innerData->getObjectSize(); + uint32_t additionalSize = innerDataSize + SHA_DIGEST_LENGTH < 255 ? 255 - (innerDataSize + SHA_DIGEST_LENGTH) : 0; + NativeByteBuffer *innerDataBuffer = BuffersStorage::getInstance().getFreeBuffer(innerDataSize + additionalSize + SHA_DIGEST_LENGTH); + innerDataBuffer->position(SHA_DIGEST_LENGTH); + innerData->serializeToStream(innerDataBuffer); + delete innerData; + + SHA1(innerDataBuffer->bytes() + SHA_DIGEST_LENGTH, innerDataSize, innerDataBuffer->bytes()); + if (additionalSize != 0) { + RAND_bytes(innerDataBuffer->bytes() + SHA_DIGEST_LENGTH + innerDataSize, additionalSize); + } + + std::string &key = serverPublicKeys[keyIndex]; + + BIO *keyBio = BIO_new(BIO_s_mem()); + BIO_write(keyBio, key.c_str(), (int) key.length()); + RSA *rsaKey = PEM_read_bio_RSAPublicKey(keyBio, NULL, NULL, NULL); + BIO_free(keyBio); + if (bnContext == nullptr) { + bnContext = BN_CTX_new(); + } + BIGNUM *a = BN_bin2bn(innerDataBuffer->bytes(), innerDataBuffer->limit(), NULL); + BIGNUM *r = BN_new(); + BN_mod_exp(r, a, rsaKey->e, rsaKey->n, bnContext); + uint32_t size = BN_num_bytes(r); + ByteArray *rsaEncryptedData = new ByteArray(size >= 256 ? size : 256); + size_t resLen = BN_bn2bin(r, rsaEncryptedData->bytes); + if (256 - resLen > 0) { + memset(rsaEncryptedData + resLen, 0, 256 - resLen); + } + BN_free(a); + BN_free(r); + RSA_free(rsaKey); + innerDataBuffer->reuse(); + + request->encrypted_data = std::unique_ptr(rsaEncryptedData); + + sendAckRequest(messageId); + sendRequestData(request, true); + } else { + DEBUG_E("dc%u handshake: invalid client nonce", datacenterId); + beginHandshake(false); + } + } else if (dynamic_cast(message)) { + if (typeInfo == typeid(TL_server_DH_params_ok)) { + if (handshakeState != 2) { + sendAckRequest(messageId); + return; + } + + handshakeState = 3; + + TL_server_DH_params_ok *result = (TL_server_DH_params_ok *) message; + + NativeByteBuffer *tmpAesKeyAndIv = BuffersStorage::getInstance().getFreeBuffer(84); + + NativeByteBuffer *newNonceAndServerNonce = BuffersStorage::getInstance().getFreeBuffer(authNewNonce->length + authServerNonce->length); + newNonceAndServerNonce->writeBytes(authNewNonce); + newNonceAndServerNonce->writeBytes(authServerNonce); + SHA1(newNonceAndServerNonce->bytes(), newNonceAndServerNonce->limit(), tmpAesKeyAndIv->bytes()); + newNonceAndServerNonce->reuse(); + + NativeByteBuffer *serverNonceAndNewNonce = BuffersStorage::getInstance().getFreeBuffer(authServerNonce->length + authNewNonce->length); + serverNonceAndNewNonce->writeBytes(authServerNonce); + serverNonceAndNewNonce->writeBytes(authNewNonce); + SHA1(serverNonceAndNewNonce->bytes(), serverNonceAndNewNonce->limit(), tmpAesKeyAndIv->bytes() + 20); + serverNonceAndNewNonce->reuse(); + + NativeByteBuffer *newNonceAndNewNonce = BuffersStorage::getInstance().getFreeBuffer(authNewNonce->length + authNewNonce->length); + newNonceAndNewNonce->writeBytes(authNewNonce); + newNonceAndNewNonce->writeBytes(authNewNonce); + SHA1(newNonceAndNewNonce->bytes(), newNonceAndNewNonce->limit(), tmpAesKeyAndIv->bytes() + 40); + newNonceAndNewNonce->reuse(); + + memcpy(tmpAesKeyAndIv->bytes() + 60, authNewNonce->bytes, 4); + aesIgeEncryption(result->encrypted_answer->bytes, tmpAesKeyAndIv->bytes(), tmpAesKeyAndIv->bytes() + 32, false, false, result->encrypted_answer->length); + + bool hashVerified = false; + for (uint32_t i = 0; i < 16; i++) { + SHA1(result->encrypted_answer->bytes + SHA_DIGEST_LENGTH, result->encrypted_answer->length - i - SHA_DIGEST_LENGTH, tmpAesKeyAndIv->bytes() + 64); + if (!memcmp(tmpAesKeyAndIv->bytes() + 64, result->encrypted_answer->bytes, SHA_DIGEST_LENGTH)) { + hashVerified = true; + break; + } + } + + if (!hashVerified) { + DEBUG_E("dc%u handshake: can't decode DH params", datacenterId); + beginHandshake(false); + return; + } + + bool error = false; + NativeByteBuffer *answerWithHash = new NativeByteBuffer(result->encrypted_answer->bytes + SHA_DIGEST_LENGTH, result->encrypted_answer->length - SHA_DIGEST_LENGTH); + uint32_t constructor = answerWithHash->readUint32(&error); + TL_server_DH_inner_data *dhInnerData = TL_server_DH_inner_data::TLdeserialize(answerWithHash, constructor, error); + delete answerWithHash; + + if (error) { + DEBUG_E("dc%u handshake: can't parse decoded DH params", datacenterId); + beginHandshake(false); + return; + } + + if (!authNonce->isEqualTo(dhInnerData->nonce.get())) { + DEBUG_E("dc%u handshake: invalid DH nonce", datacenterId); + beginHandshake(false); + return; + } + + if (!authServerNonce->isEqualTo(dhInnerData->server_nonce.get())) { + DEBUG_E("dc%u handshake: invalid DH server nonce", datacenterId); + beginHandshake(false); + return; + } + + BIGNUM *p = BN_bin2bn(dhInnerData->dh_prime->bytes, dhInnerData->dh_prime->length, NULL); + if (p == nullptr) { + DEBUG_E("can't allocate BIGNUM p"); + exit(1); + } + if (!isGoodPrime(p, dhInnerData->g)) { + DEBUG_E("dc%u handshake: bad prime", datacenterId); + beginHandshake(false); + BN_free(p); + return; + } + + BIGNUM *g_a = BN_new(); + if (g_a == nullptr) { + DEBUG_E("can't allocate BIGNUM g_a"); + exit(1); + } + BN_bin2bn(dhInnerData->g_a->bytes, dhInnerData->g_a->length, g_a); + if (!isGoodGaAndGb(g_a, p)) { + DEBUG_E("dc%u handshake: bad prime and g_a", datacenterId); + beginHandshake(false); + BN_free(p); + BN_free(g_a); + return; + } + + BIGNUM *g = BN_new(); + if (g == nullptr) { + DEBUG_E("can't allocate BIGNUM g"); + exit(1); + } + if (!BN_set_word(g, dhInnerData->g)) { + DEBUG_E("OpenSSL error at BN_set_word(g_b, dhInnerData->g)"); + beginHandshake(false); + BN_free(g); + BN_free(g_a); + BN_free(p); + return; + } + static uint8_t bytes[256]; + RAND_bytes(bytes, 256); + BIGNUM *b = BN_bin2bn(bytes, 256, NULL); + if (b == nullptr) { + DEBUG_E("can't allocate BIGNUM b"); + exit(1); + } + + BIGNUM *g_b = BN_new(); + if (!BN_mod_exp(g_b, g, b, p, bnContext)) { + DEBUG_E("OpenSSL error at BN_mod_exp(g_b, g, b, p, bnContext)"); + beginHandshake(false); + BN_free(g); + BN_free(g_a); + BN_free(g_b); + BN_free(b); + BN_free(p); + return; + } + + TL_client_DH_inner_data *clientInnerData = new TL_client_DH_inner_data(); + clientInnerData->g_b = std::unique_ptr(new ByteArray(BN_num_bytes(g_b))); + BN_bn2bin(g_b, clientInnerData->g_b->bytes); + clientInnerData->nonce = std::unique_ptr(new ByteArray(authNonce)); + clientInnerData->server_nonce = std::unique_ptr(new ByteArray(authServerNonce)); + clientInnerData->retry_id = 0; + BN_free(g_b); + BN_free(g); + + BIGNUM *authKeyNum = BN_new(); + BN_mod_exp(authKeyNum, g_a, b, p, bnContext); + size_t l = BN_num_bytes(authKeyNum); + handshakeAuthKey = new ByteArray(256); + BN_bn2bin(authKeyNum, handshakeAuthKey->bytes); + if (l < 256) { + memmove(handshakeAuthKey->bytes + 256 - l, handshakeAuthKey->bytes, l); + memset(handshakeAuthKey->bytes, 0, 256 - l); + } + + BN_free(authKeyNum); + BN_free(g_a); + BN_free(b); + BN_free(p); + + uint32_t clientInnerDataSize = clientInnerData->getObjectSize(); + uint32_t additionalSize = (clientInnerDataSize + SHA_DIGEST_LENGTH) % 16; + if (additionalSize != 0) { + additionalSize = 16 - additionalSize; + } + NativeByteBuffer *clientInnerDataBuffer = BuffersStorage::getInstance().getFreeBuffer(clientInnerDataSize + additionalSize + SHA_DIGEST_LENGTH); + clientInnerDataBuffer->position(SHA_DIGEST_LENGTH); + clientInnerData->serializeToStream(clientInnerDataBuffer); + delete clientInnerData; + + SHA1(clientInnerDataBuffer->bytes() + SHA_DIGEST_LENGTH, clientInnerDataSize, clientInnerDataBuffer->bytes()); + + if (additionalSize != 0) { + RAND_bytes(clientInnerDataBuffer->bytes() + SHA_DIGEST_LENGTH + clientInnerDataSize, additionalSize); + } + + TL_set_client_DH_params *setClientDhParams = new TL_set_client_DH_params(); + setClientDhParams->nonce = std::unique_ptr(new ByteArray(authNonce)); + setClientDhParams->server_nonce = std::unique_ptr(new ByteArray(authServerNonce)); + aesIgeEncryption(clientInnerDataBuffer->bytes(), tmpAesKeyAndIv->bytes(), tmpAesKeyAndIv->bytes() + 32, true, false, clientInnerDataBuffer->limit()); + setClientDhParams->encrypted_data = std::unique_ptr(new ByteArray(clientInnerDataBuffer->bytes(), clientInnerDataBuffer->limit())); + clientInnerDataBuffer->reuse(); + tmpAesKeyAndIv->reuse(); + + sendAckRequest(messageId); + sendRequestData(setClientDhParams, true); + + int32_t currentTime = (int32_t) (ConnectionsManager::getInstance().getCurrentTimeMillis() / 1000); + timeDifference = dhInnerData->server_time - currentTime; + + handshakeServerSalt = new TL_future_salt(); + handshakeServerSalt->valid_since = currentTime + timeDifference - 5; + handshakeServerSalt->valid_until = handshakeServerSalt->valid_since + 30 * 60; + for (int32_t a = 7; a >= 0; a--) { + handshakeServerSalt->salt <<= 8; + handshakeServerSalt->salt |= (authNewNonce->bytes[a] ^ authServerNonce->bytes[a]); + } + } else { + DEBUG_E("dc%u handshake: can't set DH params", datacenterId); + beginHandshake(false); + } + } else if (dynamic_cast(message)) { + if (handshakeState != 3) { + sendAckRequest(messageId); + return; + } + + handshakeState = 4; + + Set_client_DH_params_answer *result = (Set_client_DH_params_answer *) message; + + if (!authNonce->isEqualTo(result->nonce.get())) { + DEBUG_E("dc%u handshake: invalid DH answer nonce", datacenterId); + beginHandshake(false); + return; + } + if (!authServerNonce->isEqualTo(result->server_nonce.get())) { + DEBUG_E("dc%u handshake: invalid DH answer server nonce", datacenterId); + beginHandshake(false); + return; + } + + sendAckRequest(messageId); + + uint32_t authKeyAuxHashLength = authNewNonce->length + SHA_DIGEST_LENGTH + 1; + NativeByteBuffer *authKeyAuxHashBuffer = BuffersStorage::getInstance().getFreeBuffer(authKeyAuxHashLength + SHA_DIGEST_LENGTH); + authKeyAuxHashBuffer->writeBytes(authNewNonce); + SHA1(handshakeAuthKey->bytes, handshakeAuthKey->length, authKeyAuxHashBuffer->bytes() + authNewNonce->length + 1); + + if (typeInfo == typeid(TL_dh_gen_ok)) { + authKeyAuxHashBuffer->writeByte(1); + SHA1(authKeyAuxHashBuffer->bytes(), authKeyAuxHashLength - 12, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength); + + if (memcmp(result->new_nonce_hash1->bytes, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength + SHA_DIGEST_LENGTH - 16, 16)) { + DEBUG_E("dc%u handshake: invalid DH answer nonce hash 1", datacenterId); + authKeyAuxHashBuffer->reuse(); + beginHandshake(false); + } else { + DEBUG_D("dc%u handshake: completed, time difference = %d", datacenterId, timeDifference); + authKey = handshakeAuthKey; + handshakeAuthKey = nullptr; + authKeyAuxHashBuffer->position(authNewNonce->length + 1 + 12); + authKeyId = authKeyAuxHashBuffer->readInt64(nullptr); + std::unique_ptr salt = std::unique_ptr(handshakeServerSalt); + addServerSalt(salt); + handshakeServerSalt = nullptr; + ConnectionsManager::getInstance().onDatacenterHandshakeComplete(this, timeDifference); + cleanupHandshake(); + } + authKeyAuxHashBuffer->reuse(); + } else if (typeInfo == typeid(TL_dh_gen_retry)) { + authKeyAuxHashBuffer->writeByte(2); + SHA1(authKeyAuxHashBuffer->bytes(), authKeyAuxHashLength - 12, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength); + + if (memcmp(result->new_nonce_hash2->bytes, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength + SHA_DIGEST_LENGTH - 16, 16)) { + DEBUG_E("dc%u handshake: invalid DH answer nonce hash 2", datacenterId); + beginHandshake(false); + } else { + DEBUG_D("dc%u handshake: retry DH", datacenterId); + beginHandshake(false); + } + authKeyAuxHashBuffer->reuse(); + } else if (typeInfo == typeid(TL_dh_gen_fail)) { + authKeyAuxHashBuffer->writeByte(3); + SHA1(authKeyAuxHashBuffer->bytes(), authKeyAuxHashLength - 12, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength); + + if (memcmp(result->new_nonce_hash3->bytes, authKeyAuxHashBuffer->bytes() + authKeyAuxHashLength + SHA_DIGEST_LENGTH - 16, 16)) { + DEBUG_E("dc%u handshake: invalid DH answer nonce hash 3", datacenterId); + beginHandshake(false); + } else { + DEBUG_E("dc%u handshake: server declined DH params", datacenterId); + beginHandshake(false); + } + authKeyAuxHashBuffer->reuse(); + } + } +} + +TLObject *Datacenter::getCurrentHandshakeRequest() { + return handshakeRequest; +} + +void Datacenter::sendAckRequest(int64_t messageId) { + TL_msgs_ack *msgsAck = new TL_msgs_ack(); + msgsAck->msg_ids.push_back(messageId); + sendRequestData(msgsAck, false); +} + +inline void generateMessageKey(uint8_t *authKey, uint8_t *messageKey, uint8_t *result, bool incoming) { + uint32_t x = incoming ? 8 : 0; + + static uint8_t sha[68]; + + memcpy(sha + 20, messageKey, 16); + memcpy(sha + 20 + 16, authKey + x, 32); + SHA1(sha + 20, 48, sha); + memcpy(result, sha, 8); + memcpy(result + 32, sha + 8, 12); + + memcpy(sha + 20, authKey + 32 + x, 16); + memcpy(sha + 20 + 16, messageKey, 16); + memcpy(sha + 20 + 16 + 16, authKey + 48 + x, 16); + SHA1(sha + 20, 48, sha); + memcpy(result + 8, sha + 8, 12); + memcpy(result + 32 + 12, sha, 8); + + memcpy(sha + 20, authKey + 64 + x, 32); + memcpy(sha + 20 + 32, messageKey, 16); + SHA1(sha + 20, 48, sha); + memcpy(result + 8 + 12, sha + 4, 12); + memcpy(result + 32 + 12 + 8, sha + 16, 4); + + memcpy(sha + 20, messageKey, 16); + memcpy(sha + 20 + 16, authKey + 96 + x, 32); + SHA1(sha + 20, 48, sha); + memcpy(result + 32 + 12 + 8 + 4, sha, 8); +} + +NativeByteBuffer *Datacenter::createRequestsData(std::vector> &requests, int32_t *quickAckId, Connection *connection) { + if (authKey == nullptr || connection == nullptr) { + return nullptr; + } + + int64_t messageId; + TLObject *messageBody; + bool freeMessageBody = false; + int32_t messageSeqNo; + + if (requests.size() == 1) { + NetworkMessage *networkMessage = requests[0].get(); + + if (networkMessage->message->outgoingBody != nullptr) { + messageBody = networkMessage->message->outgoingBody; + } else { + messageBody = networkMessage->message->body.get(); + } + DEBUG_D("connection(%p, dc%u, type %d) send message (session: 0x%llx, seqno: %d, messageid: 0x%llx): %s(%p)", connection, datacenterId, connection->getConnectionType(), (uint64_t) connection->getSissionId(), networkMessage->message->seqno, (uint64_t) networkMessage->message->msg_id, typeid(*messageBody).name(), messageBody); + + int64_t messageTime = (int64_t) (networkMessage->message->msg_id / 4294967296.0 * 1000); + int64_t currentTime = ConnectionsManager::getInstance().getCurrentTimeMillis() + (int64_t) timeDifference * 1000; + + if (messageTime < currentTime - 30000 || messageTime > currentTime + 25000) { + DEBUG_D("wrap message in container"); + TL_msg_container *messageContainer = new TL_msg_container(); + messageContainer->messages.push_back(std::move(networkMessage->message)); + + messageId = ConnectionsManager::getInstance().generateMessageId(); + messageBody = messageContainer; + messageSeqNo = connection->generateMessageSeqNo(false); + freeMessageBody = true; + } else { + messageId = networkMessage->message->msg_id; + messageSeqNo = networkMessage->message->seqno; + } + } else { + DEBUG_D("start write messages to container"); + TL_msg_container *messageContainer = new TL_msg_container(); + size_t count = requests.size(); + for (uint32_t a = 0; a < count; a++) { + NetworkMessage *networkMessage = requests[a].get(); + if (networkMessage->message->outgoingBody != nullptr) { + messageBody = networkMessage->message->outgoingBody; + } else { + messageBody = networkMessage->message->body.get(); + } + DEBUG_D("connection(%p, dc%u, type %d) send message (session: 0x%llx, seqno: %d, messageid: 0x%llx): %s(%p)", connection, datacenterId, connection->getConnectionType(), (uint64_t) connection->getSissionId(), networkMessage->message->seqno, (uint64_t) networkMessage->message->msg_id, typeid(*messageBody).name(), messageBody); + messageContainer->messages.push_back(std::unique_ptr(std::move(networkMessage->message))); + } + messageId = ConnectionsManager::getInstance().generateMessageId(); + messageBody = messageContainer; + freeMessageBody = true; + messageSeqNo = connection->generateMessageSeqNo(false); + } + + uint32_t messageSize = messageBody->getObjectSize(); + uint32_t additionalSize = (32 + messageSize) % 16; + if (additionalSize != 0) { + additionalSize = 16 - additionalSize; + } + NativeByteBuffer *buffer = BuffersStorage::getInstance().getFreeBuffer(24 + 32 + messageSize + additionalSize); + buffer->writeInt64(authKeyId); + buffer->position(24); + + int64_t serverSalt = getServerSalt(); + buffer->writeInt64(serverSalt); + buffer->writeInt64(connection->getSissionId()); + buffer->writeInt64(messageId); + buffer->writeInt32(messageSeqNo); + buffer->writeInt32(messageSize); + messageBody->serializeToStream(buffer); + if (freeMessageBody) { + delete messageBody; + } + + if (additionalSize != 0) { + RAND_bytes(buffer->bytes() + 24 + 32 + messageSize, additionalSize); + } + static uint8_t messageKey[84]; + SHA1(buffer->bytes() + 24, 32 + messageSize, messageKey); + memcpy(buffer->bytes() + 8, messageKey + 4, 16); + + if (quickAckId != nullptr) { + *quickAckId = (((messageKey[0] & 0xff)) | + ((messageKey[1] & 0xff) << 8) | + ((messageKey[2] & 0xff) << 16) | + ((messageKey[3] & 0xff) << 24)) & 0x7fffffff; + } + + generateMessageKey(authKey->bytes, messageKey + 4, messageKey + 20, false); + aesIgeEncryption(buffer->bytes() + 24, messageKey + 20, messageKey + 52, true, false, buffer->limit() - 24); + + return buffer; +} + +bool Datacenter::decryptServerResponse(int64_t keyId, uint8_t *key, uint8_t *data, uint32_t length) { + if (authKeyId != keyId || length % 16 != 0) { + return false; + } + static uint8_t messageKey[84]; + generateMessageKey(authKey->bytes, key, messageKey + 20, true); + aesIgeEncryption(data, messageKey + 20, messageKey + 52, false, false, length); + + uint32_t messageLength; + memcpy(&messageLength, data + 28, sizeof(uint32_t)); + if (messageLength > length - 32) { + return false; + } + messageLength += 32; + if (messageLength > length) { + messageLength = length; + } + + SHA1(data, messageLength, messageKey); + + return memcmp(messageKey + 4, key, 16) == 0; +} + +bool Datacenter::hasAuthKey() { + return authKey != nullptr; +} + +Connection *Datacenter::createConnectionByType(uint32_t connectionType) { + uint32_t connectionNum = connectionType >> 16; + connectionType = connectionType & 0x0000ffff; + switch (connectionType) { + case ConnectionTypeGeneric: + return createGenericConnection(); + case ConnectionTypeDownload: + return createDownloadConnection(connectionNum); + case ConnectionTypeUpload: + return createUploadConnection(); + case ConnectionTypePush: + return createPushConnection(); + default: + return nullptr; + } +} + +Connection *Datacenter::getDownloadConnection(uint32_t num, bool create) { + if (authKey == nullptr) { + return nullptr; + } + if (create) { + createDownloadConnection(num)->connect(); + } + return downloadConnections[num]; +} + +Connection *Datacenter::getUploadConnection(bool create) { + if (authKey == nullptr) { + return nullptr; + } + if (create) { + createUploadConnection()->connect(); + } + return uploadConnection; +} + +Connection *Datacenter::getGenericConnection(bool create) { + if (authKey == nullptr) { + return nullptr; + } + if (create) { + createGenericConnection()->connect(); + } + return genericConnection; +} + +Connection *Datacenter::getPushConnection(bool create) { + if (authKey == nullptr) { + return nullptr; + } + if (create) { + createPushConnection()->connect(); + } + return pushConnection; +} + +Connection *Datacenter::getConnectionByType(uint32_t connectionType, bool create) { + uint32_t connectionNum = connectionType >> 16; + connectionType = connectionType & 0x0000ffff; + switch (connectionType) { + case ConnectionTypeGeneric: + return getGenericConnection(create); + case ConnectionTypeDownload: + return getDownloadConnection(connectionNum, create); + case ConnectionTypeUpload: + return getUploadConnection(create); + case ConnectionTypePush: + return getPushConnection(create); + default: + return nullptr; + } +} + +void Datacenter::exportAuthorization() { + if (exportingAuthorization) { + return; + } + exportingAuthorization = true; + TL_auth_exportAuthorization *request = new TL_auth_exportAuthorization(); + request->dc_id = datacenterId; + DEBUG_D("dc%u begin export authorization", datacenterId); + ConnectionsManager::getInstance().sendRequest(request, [&](TLObject *response, TL_error *error) { + if (error == nullptr) { + TL_auth_exportedAuthorization *res = (TL_auth_exportedAuthorization *) response; + TL_auth_importAuthorization *request2 = new TL_auth_importAuthorization(); + request2->bytes = std::move(res->bytes); + request2->id = res->id; + DEBUG_D("dc%u begin import authorization", datacenterId); + ConnectionsManager::getInstance().sendRequest(request2, [&](TLObject *response2, TL_error *error2) { + if (error2 == nullptr) { + authorized = true; + ConnectionsManager::getInstance().onDatacenterExportAuthorizationComplete(this); + } else { + DEBUG_D("dc%u failed import authorization", datacenterId); + } + exportingAuthorization = false; + }, nullptr, RequestFlagEnableUnauthorized | RequestFlagWithoutLogin, datacenterId, ConnectionTypeGeneric, true); + } else { + DEBUG_D("dc%u failed export authorization", datacenterId); + exportingAuthorization = false; + } + }, nullptr, 0, DEFAULT_DATACENTER_ID, ConnectionTypeGeneric, true); +} + +bool Datacenter::isExportingAuthorization() { + return exportingAuthorization; +} diff --git a/TMessagesProj/jni/tgnet/Datacenter.h b/TMessagesProj/jni/tgnet/Datacenter.h new file mode 100644 index 00000000..d7b70aa8 --- /dev/null +++ b/TMessagesProj/jni/tgnet/Datacenter.h @@ -0,0 +1,129 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef DATACENTER_H +#define DATACENTER_H + +#include +#include +#include +#include +#include "Defines.h" + +class TL_future_salt; +class Connection; +class NativeByteBuffer; +class TL_future_salt; +class ByteArray; +class TLObject; +class Config; + +class Datacenter { + +public: + Datacenter(uint32_t id); + Datacenter(NativeByteBuffer *data); + void switchTo443Port(); + uint32_t getDatacenterId(); + std::string getCurrentAddress(uint32_t flags); + int32_t getCurrentPort(uint32_t flags); + void addAddressAndPort(std::string address, uint32_t port, uint32_t flags); + void nextAddressOrPort(uint32_t flags); + void storeCurrentAddressAndPortNum(); + void replaceAddressesAndPorts(std::vector &newAddresses, std::map &newPorts, uint32_t flags); + void serializeToStream(NativeByteBuffer *stream); + void clear(); + void clearServerSalts(); + int64_t getServerSalt(); + void mergeServerSalts(std::vector> &salts); + void addServerSalt(std::unique_ptr &serverSalt); + bool containsServerSalt(int64_t value); + void suspendConnections(); + void getSessions(std::vector &sessions); + void recreateSessions(); + bool isHandshaking(); + bool hasAuthKey(); + bool isExportingAuthorization(); + + Connection *getDownloadConnection(uint32_t num, bool create); + Connection *getUploadConnection(bool create); + Connection *getGenericConnection(bool create); + Connection *getPushConnection(bool create); + Connection *getConnectionByType(uint32_t connectionType, bool create); + +private: + void onHandshakeConnectionClosed(Connection *connection); + void onHandshakeConnectionConnected(Connection *connection); + void processHandshakeResponse(TLObject *message, int64_t messageId); + void aesIgeEncryption(uint8_t *buffer, uint8_t *key, uint8_t *iv, bool encrypt, bool changeIv, uint32_t length); + NativeByteBuffer *createRequestsData(std::vector> &requests, int32_t *quickAckId, Connection *connection); + bool decryptServerResponse(int64_t keyId, uint8_t *key, uint8_t *data, uint32_t length); + TLObject *getCurrentHandshakeRequest(); + + const int32_t *defaultPorts = new int32_t[11] {-1, 80, -1, 443, -1, 443, -1, 80, -1, 443, -1}; + const int32_t *defaultPorts8888 = new int32_t[11] {-1, 8888, -1, 443, -1, 8888, -1, 80, -1, 8888, -1}; + + uint32_t datacenterId; + Connection *genericConnection = nullptr; + Connection *downloadConnections[DOWNLOAD_CONNECTIONS_COUNT]; + Connection *uploadConnection = nullptr; + Connection *pushConnection = nullptr; + + uint32_t lastInitVersion = 0; + bool authorized = false; + + std::vector addressesIpv4; + std::vector addressesIpv6; + std::vector addressesIpv4Download; + std::vector addressesIpv6Download; + std::map ports; + std::vector> serverSalts; + uint32_t currentPortNumIpv4 = 0; + uint32_t currentAddressNumIpv4 = 0; + uint32_t currentPortNumIpv6 = 0; + uint32_t currentAddressNumIpv6 = 0; + uint32_t currentPortNumIpv4Download = 0; + uint32_t currentAddressNumIpv4Download = 0; + uint32_t currentPortNumIpv6Download = 0; + uint32_t currentAddressNumIpv6Download = 0; + ByteArray *authKey = nullptr; + int64_t authKeyId = 0; + int32_t overridePort = -1; + Config *config = nullptr; + + const uint32_t configVersion = 5; + const uint32_t paramsConfigVersion = 1; + + Connection *createDownloadConnection(uint32_t num); + Connection *createUploadConnection(); + Connection *createGenericConnection(); + Connection *createPushConnection(); + Connection *createConnectionByType(uint32_t connectionType); + + uint8_t handshakeState = 0; + TLObject *handshakeRequest = nullptr; + ByteArray *authNonce = nullptr; + ByteArray *authServerNonce = nullptr; + ByteArray *authNewNonce = nullptr; + ByteArray *handshakeAuthKey = nullptr; + TL_future_salt *handshakeServerSalt = nullptr; + int32_t timeDifference = 0; + bool needResendData = false; + void beginHandshake(bool reconnect); + void sendRequestData(TLObject *object, bool important); + void cleanupHandshake(); + void sendAckRequest(int64_t messageId); + int32_t selectPublicKey(std::vector &fingerprints); + + bool exportingAuthorization = false; + void exportAuthorization(); + + friend class ConnectionsManager; +}; + +#endif diff --git a/TMessagesProj/jni/tgnet/Defines.h b/TMessagesProj/jni/tgnet/Defines.h new file mode 100644 index 00000000..168199bd --- /dev/null +++ b/TMessagesProj/jni/tgnet/Defines.h @@ -0,0 +1,99 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef DEFINES_H +#define DEFINES_H + +#include +#include +#include +#include +#include + +#define USE_DEBUG_SESSION false +#define READ_BUFFER_SIZE 1024 * 128 +//#define DEBUG_VERSION +#define DEFAULT_DATACENTER_ID INT_MAX +#define DC_UPDATE_TIME 60 * 60 +#define DOWNLOAD_CONNECTIONS_COUNT 2 +#define CONNECTION_BACKGROUND_KEEP_TIME 10000 + +class TLObject; +class TL_error; +class Request; +class TL_message; +class TL_config; +class NativeByteBuffer; + +typedef std::function onCompleteFunc; +typedef std::function onQuickAckFunc; +typedef std::list> requestsList; +typedef requestsList::iterator requestsIter; + +typedef struct NetworkMessage { + std::unique_ptr message; + bool invokeAfter = false; + bool needQuickAck = false; + int32_t requestId; +} NetworkMessage; + +enum ConnectionType { + ConnectionTypeGeneric = 1, + ConnectionTypeDownload = 2, + ConnectionTypeUpload = 4, + ConnectionTypePush = 8, +}; + +enum ConnectionState { + ConnectionStateConnecting = 1, + ConnectionStateWaitingForNetwork = 2, + ConnectionStateConnected = 3 +}; + +enum EventObjectType { + EventObjectTypeConnection, + EventObjectTypeTimer, + EventObjectPipe +}; + +typedef struct ConnectiosManagerDelegate { + virtual void onUpdate() = 0; + virtual void onSessionCreated() = 0; + virtual void onConnectionStateChanged(ConnectionState state) = 0; + virtual void onUnparsedMessageReceived(int64_t reqMessageId, NativeByteBuffer *buffer, ConnectionType connectionType) = 0; + virtual void onLogout() = 0; + virtual void onUpdateConfig(TL_config *config) = 0; + virtual void onInternalPushReceived() = 0; +} ConnectiosManagerDelegate; + +#define AllConnectionTypes ConnectionTypeGeneric | ConnectionTypeDownload | ConnectionTypeUpload + +enum RequestFlag { + RequestFlagEnableUnauthorized = 1, + RequestFlagFailOnServerErrors = 2, + RequestFlagCanCompress = 4, + RequestFlagWithoutLogin = 8, + RequestFlagTryDifferentDc = 16, + RequestFlagForceDownload = 32, + RequestFlagInvokeAfter = 64, + RequestFlagNeedQuickAck = 128 +}; + +inline std::string to_string_int32(int32_t value) { + char buf[30]; + int len = sprintf(buf, "%d", value); + return std::string(buf, len); +} + +inline std::string to_string_uint64(uint64_t value) { + char buf[30]; + int len = sprintf(buf, "%llu", value); + return std::string(buf, len); +} + +#endif diff --git a/TMessagesProj/jni/tgnet/EventObject.cpp b/TMessagesProj/jni/tgnet/EventObject.cpp new file mode 100644 index 00000000..490ab8b0 --- /dev/null +++ b/TMessagesProj/jni/tgnet/EventObject.cpp @@ -0,0 +1,43 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include +#include "EventObject.h" +#include "Connection.h" +#include "Timer.h" + +EventObject::EventObject(void *object, EventObjectType type) { + eventObject = object; + eventType = type; +} + +void EventObject::onEvent(uint32_t events) { + switch (eventType) { + case EventObjectTypeConnection: { + Connection *connection = (Connection *) eventObject; + connection->onEvent(events); + break; + } + case EventObjectTypeTimer: { + Timer *timer = (Timer *) eventObject; + timer->onEvent(); + break; + } + case EventObjectPipe: { + int *pipe = (int *) eventObject; + char ch; + ssize_t size = 1; + while (size > 0) { + size = read(pipe[0], &ch, 1); + } + break; + } + default: + break; + } +} diff --git a/TMessagesProj/jni/tgnet/EventObject.h b/TMessagesProj/jni/tgnet/EventObject.h new file mode 100644 index 00000000..18b803a4 --- /dev/null +++ b/TMessagesProj/jni/tgnet/EventObject.h @@ -0,0 +1,26 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef EVENTOBJECT_H +#define EVENTOBJECT_H + +#include +#include "Defines.h" + +class EventObject { + +public: + EventObject(void *object, EventObjectType type); + void onEvent(uint32_t events); + + int64_t time; + void *eventObject; + EventObjectType eventType; +}; + +#endif diff --git a/TMessagesProj/jni/tgnet/FileLog.cpp b/TMessagesProj/jni/tgnet/FileLog.cpp new file mode 100644 index 00000000..044a1dc8 --- /dev/null +++ b/TMessagesProj/jni/tgnet/FileLog.cpp @@ -0,0 +1,93 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include +#include +#include +#include "FileLog.h" + +#ifdef ANDROID +#include +#endif + +FILE *logFile = nullptr; + +void FileLog::init(std::string path) { + if (path.size() > 0) { + logFile = fopen(path.c_str(), "w"); + } +} + +void FileLog::e(const char *message, ...) { + va_list argptr; + va_start(argptr, message); + time_t t = time(0); + struct tm *now = localtime(&t); +#ifdef ANDROID + __android_log_vprint(ANDROID_LOG_ERROR, "tgnet", message, argptr); +#else + printf("%d-%d %02d:%02d:%02d error: ", now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); + vprintf(message, argptr); + printf("\n"); + fflush(stdout); +#endif + if (logFile) { + fprintf(logFile, "%d-%d %02d:%02d:%02d error: ", now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); + vfprintf(logFile, message, argptr); + fprintf(logFile, "\n"); + fflush(logFile); + } + + va_end(argptr); +} + +void FileLog::w(const char *message, ...) { + va_list argptr; + va_start(argptr, message); + time_t t = time(0); + struct tm *now = localtime(&t); +#ifdef ANDROID + __android_log_vprint(ANDROID_LOG_WARN, "tgnet", message, argptr); +#else + printf("%d-%d %02d:%02d:%02d warning: ", now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); + vprintf(message, argptr); + printf("\n"); + fflush(stdout); +#endif + if (logFile) { + fprintf(logFile, "%d-%d %02d:%02d:%02d warning: ", now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); + vfprintf(logFile, message, argptr); + fprintf(logFile, "\n"); + fflush(logFile); + } + + va_end(argptr); +} + +void FileLog::d(const char *message, ...) { + va_list argptr; + va_start(argptr, message); + time_t t = time(0); + struct tm *now = localtime(&t); +#ifdef ANDROID + __android_log_vprint(ANDROID_LOG_DEBUG, "tgnet", message, argptr); +#else + printf("%d-%d %02d:%02d:%02d debug: ", now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); + vprintf(message, argptr); + printf("\n"); + fflush(stdout); +#endif + if (logFile) { + fprintf(logFile, "%d-%d %02d:%02d:%02d debug: ", now->tm_mon + 1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); + vfprintf(logFile, message, argptr); + fprintf(logFile, "\n"); + fflush(logFile); + } + + va_end(argptr); +} diff --git a/TMessagesProj/jni/tgnet/FileLog.h b/TMessagesProj/jni/tgnet/FileLog.h new file mode 100644 index 00000000..7cf8ce34 --- /dev/null +++ b/TMessagesProj/jni/tgnet/FileLog.h @@ -0,0 +1,32 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef FILELOG_H +#define FILELOG_H + +#include "Defines.h" + +class FileLog { +public: + static void init(std::string path); + static void e(const char *message, ...) __attribute__((format (printf, 1, 2))); + static void w(const char *message, ...) __attribute__((format (printf, 1, 2))); + static void d(const char *message, ...) __attribute__((format (printf, 1, 2))); +}; + +#ifdef DEBUG_VERSION +#define DEBUG_E FileLog::e +#define DEBUG_W FileLog::w +#define DEBUG_D FileLog::d +#else +#define DEBUG_E +#define DEBUG_W +#define DEBUG_D +#endif + +#endif diff --git a/TMessagesProj/jni/tgnet/MTProtoScheme.cpp b/TMessagesProj/jni/tgnet/MTProtoScheme.cpp new file mode 100644 index 00000000..7921031d --- /dev/null +++ b/TMessagesProj/jni/tgnet/MTProtoScheme.cpp @@ -0,0 +1,1421 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include +#include "MTProtoScheme.h" +#include "FileLog.h" +#include "ByteArray.h" +#include "NativeByteBuffer.h" +#include "BuffersStorage.h" +#include "ConnectionsManager.h" + +TLObject *TLClassStore::TLdeserialize(NativeByteBuffer *stream, uint32_t bytes, uint32_t constructor, bool &error) { + TLObject *object = nullptr; + switch (constructor) { + case TL_msgs_ack::constructor: + object = new TL_msgs_ack(); + break; + case TL_msg_container::constructor: + object = new TL_msg_container(); + break; + case TL_pong::constructor: + object = new TL_pong(); + break; + case TL_new_session_created::constructor: + object = new TL_new_session_created(); + break; + case TL_rpc_result::constructor: + object = new TL_rpc_result(); + ((TL_rpc_result *) object)->readParamsEx(stream, bytes, error); + return object; + case TL_bad_msg_notification::constructor: + object = new TL_bad_msg_notification(); + break; + case TL_bad_server_salt::constructor: + object = new TL_bad_server_salt(); + break; + case TL_msg_detailed_info::constructor: + object = new TL_msg_detailed_info(); + break; + case TL_msg_new_detailed_info::constructor: + object = new TL_msg_new_detailed_info(); + break; + case TL_gzip_packed::constructor: + object = new TL_gzip_packed(); + break; + case TL_error::constructor: + object = new TL_error(); + break; + case TL_rpc_error::constructor: + object = new TL_rpc_error(); + break; + case TL_rpc_req_error::constructor: + object = new TL_rpc_req_error(); + break; + case TL_future_salts::constructor: + object = new TL_future_salts(); + break; + case TL_destroy_session_ok::constructor: + object = new TL_destroy_session_ok(); + break; + case TL_destroy_session_none::constructor: + object = new TL_destroy_session_none(); + break; + case TL_updatesTooLong::constructor: + object = new TL_updatesTooLong(); + break; + default: + return nullptr; + } + object->readParams(stream, error); + return object; +} + +TL_api_request::~TL_api_request() { + if (request != nullptr) { + request->reuse(); + request = nullptr; + } +} + +bool TL_api_request::isNeedLayer() { + return true; +} + +TLObject *TL_api_request::deserializeResponse(NativeByteBuffer *stream, uint32_t bytes, bool &error) { + TL_api_response *result = new TL_api_response(); + result->readParamsEx(stream, bytes, error); + return result; +} + +void TL_api_request::serializeToStream(NativeByteBuffer *stream) { + request->rewind(); + stream->writeBytes(request); +} + +void TL_api_response::readParamsEx(NativeByteBuffer *stream, uint32_t bytes, bool &error) { + response = std::unique_ptr(new NativeByteBuffer(stream->bytes() + stream->position() - 4, bytes)); + stream->skip((uint32_t) (bytes - 4)); +} + +TL_future_salt *TL_future_salt::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_future_salt::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_future_salt", constructor); + return nullptr; + } + TL_future_salt *result = new TL_future_salt(); + result->readParams(stream, error); + return result; +} + +void TL_future_salt::readParams(NativeByteBuffer *stream, bool &error) { + valid_since = stream->readInt32(&error); + valid_until = stream->readInt32(&error); + salt = stream->readInt64(&error); +} + +TL_msgs_state_info *TL_msgs_state_info::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_msgs_state_info::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_msgs_state_info", constructor); + return nullptr; + } + TL_msgs_state_info *result = new TL_msgs_state_info(); + result->readParams(stream, error); + return result; +} + +void TL_msgs_state_info::readParams(NativeByteBuffer *stream, bool &error) { + req_msg_id = stream->readInt64(&error); + info = std::unique_ptr(stream->readByteArray(&error)); +} + +void TL_msgs_state_info::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt64(req_msg_id); + stream->writeByteArray(info.get()); +} + +Server_DH_Params *Server_DH_Params::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + Server_DH_Params *result = nullptr; + switch (constructor) { + case 0x79cb045d: + result = new TL_server_DH_params_fail(); + break; + case 0xd0e8075c: + result = new TL_server_DH_params_ok(); + break; + default: + error = true; + DEBUG_E("can't parse magic %x in Server_DH_Params", constructor); + return nullptr; + } + result->readParams(stream, error); + return result; +} + +void TL_server_DH_params_fail::readParams(NativeByteBuffer *stream, bool &error) { + nonce = std::unique_ptr(stream->readBytes(16, &error)); + server_nonce = std::unique_ptr(stream->readBytes(16, &error)); + new_nonce_hash = std::unique_ptr(stream->readBytes(16, &error)); +} + +void TL_server_DH_params_ok::readParams(NativeByteBuffer *stream, bool &error) { + nonce = std::unique_ptr(stream->readBytes(16, &error)); + server_nonce = std::unique_ptr(stream->readBytes(16, &error)); + encrypted_answer = std::unique_ptr(stream->readByteArray(&error)); +} + +TL_resPQ *TL_resPQ::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_resPQ::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_resPQ", constructor); + return nullptr; + } + TL_resPQ *result = new TL_resPQ(); + result->readParams(stream, error); + return result; +} + +void TL_resPQ::readParams(NativeByteBuffer *stream, bool &error) { + nonce = std::unique_ptr(stream->readBytes(16, &error)); + server_nonce = std::unique_ptr(stream->readBytes(16, &error)); + pq = std::unique_ptr(stream->readByteArray(&error)); + uint32_t magic = stream->readUint32(&error); + if (magic != 0x1cb5c415) { + error = true; + DEBUG_E("wrong Vector magic, got %x", magic); + return; + } + uint32_t count = stream->readUint32(&error); + if (count * sizeof(int64_t) + stream->position() > stream->limit()) { + error = true; + return; + } + for (uint32_t a = 0; a < count; a++) { + server_public_key_fingerprints.push_back(stream->readInt64(&error)); + } +} + +void TL_p_q_inner_data::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeByteArray(pq.get()); + stream->writeByteArray(p.get()); + stream->writeByteArray(q.get()); + stream->writeBytes(nonce.get()); + stream->writeBytes(server_nonce.get()); + stream->writeBytes(new_nonce.get()); +} + +TL_pong *TL_pong::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_pong::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_pong", constructor); + return nullptr; + } + TL_pong *result = new TL_pong(); + result->readParams(stream, error); + return result; +} + +void TL_pong::readParams(NativeByteBuffer *stream, bool &error) { + msg_id = stream->readInt64(&error); + ping_id = stream->readInt64(&error); +} + +TL_future_salts *TL_future_salts::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_future_salts::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_future_salts", constructor); + return nullptr; + } + TL_future_salts *result = new TL_future_salts(); + result->readParams(stream, error); + return result; +} + +void TL_future_salts::readParams(NativeByteBuffer *stream, bool &error) { + req_msg_id = stream->readInt64(&error); + now = stream->readInt32(&error); + uint32_t count = stream->readUint32(&error); + for (uint32_t a = 0; a < count; a++) { + TL_future_salt *object = new TL_future_salt(); + object->readParams(stream, error); + if (error) { + return; + } + salts.push_back(std::unique_ptr(object)); + } +} + +RpcDropAnswer *RpcDropAnswer::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + RpcDropAnswer *result = nullptr; + switch (constructor) { + case 0x5e2ad36e: + result = new TL_rpc_answer_unknown(); + break; + case 0xa43ad8b7: + result = new TL_rpc_answer_dropped(); + break; + case 0xcd78e586: + result = new TL_rpc_answer_dropped_running(); + break; + default: + error = true; + DEBUG_E("can't parse magic %x in RpcDropAnswer", constructor); + return nullptr; + } + result->readParams(stream, error); + return result; +} + +void TL_rpc_answer_unknown::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); +} + +void TL_rpc_answer_dropped::readParams(NativeByteBuffer *stream, bool &error) { + msg_id = stream->readInt64(&error); + seq_no = stream->readInt32(&error); + bytes = stream->readInt32(&error); +} + +void TL_rpc_answer_dropped_running::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); +} + +Set_client_DH_params_answer *Set_client_DH_params_answer::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + Set_client_DH_params_answer *result = nullptr; + switch (constructor) { + case 0x46dc1fb9: + result = new TL_dh_gen_retry(); + break; + case 0xa69dae02: + result = new TL_dh_gen_fail(); + break; + case 0x3bcbf734: + result = new TL_dh_gen_ok(); + break; + default: + error = true; + DEBUG_E("can't parse magic %x in Set_client_DH_params_answer", constructor); + return nullptr; + } + result->readParams(stream, error); + return result; +} + +void TL_dh_gen_retry::readParams(NativeByteBuffer *stream, bool &error) { + nonce = std::unique_ptr(stream->readBytes(16, &error)); + server_nonce = std::unique_ptr(stream->readBytes(16, &error)); + new_nonce_hash2 = std::unique_ptr(stream->readBytes(16, &error)); +} + +void TL_dh_gen_fail::readParams(NativeByteBuffer *stream, bool &error) { + nonce = std::unique_ptr(stream->readBytes(16, &error)); + server_nonce = std::unique_ptr(stream->readBytes(16, &error)); + new_nonce_hash3 = std::unique_ptr(stream->readBytes(16, &error)); +} + +void TL_dh_gen_ok::readParams(NativeByteBuffer *stream, bool &error) { + nonce = std::unique_ptr(stream->readBytes(16, &error)); + server_nonce = std::unique_ptr(stream->readBytes(16, &error)); + new_nonce_hash1 = std::unique_ptr(stream->readBytes(16, &error)); +} + +BadMsgNotification *BadMsgNotification::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + BadMsgNotification *result = nullptr; + switch (constructor) { + case 0xa7eff811: + result = new TL_bad_msg_notification(); + break; + case 0xedab447b: + result = new TL_bad_server_salt(); + break; + default: + error = true; + DEBUG_E("can't parse magic %x in BadMsgNotification", constructor); + return nullptr; + } + result->readParams(stream, error); + return result; +} + +void TL_bad_msg_notification::readParams(NativeByteBuffer *stream, bool &error) { + bad_msg_id = stream->readInt64(&error); + bad_msg_seqno = stream->readInt32(&error); + error_code = stream->readInt32(&error); +} + +void TL_bad_server_salt::readParams(NativeByteBuffer *stream, bool &error) { + bad_msg_id = stream->readInt64(&error); + bad_msg_seqno = stream->readInt32(&error); + error_code = stream->readInt32(&error); + new_server_salt = stream->readInt64(&error); +} + +TL_msgs_state_req *TL_msgs_state_req::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_msgs_state_req::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_msgs_state_req", constructor); + return nullptr; + } + TL_msgs_state_req *result = new TL_msgs_state_req(); + result->readParams(stream, error); + return result; +} + +void TL_msgs_state_req::readParams(NativeByteBuffer *stream, bool &error) { + uint32_t magic = stream->readUint32(&error); + if (magic != 0x1cb5c415) { + error = true; + DEBUG_E("wrong Vector magic, got %x", magic); + return; + } + uint32_t count = stream->readUint32(&error); + if (count * sizeof(int64_t) + stream->position() > stream->limit()) { + error = true; + return; + } + for (uint32_t a = 0; a < count; a++) { + msg_ids.push_back(stream->readInt64(&error)); + } +} + +void TL_msgs_state_req::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(0x1cb5c415); + uint32_t count = (uint32_t) msg_ids.size(); + stream->writeInt32(count); + for (uint32_t a = 0; a < count; a++) { + stream->writeInt64(msg_ids[a]); + } +} + +MsgDetailedInfo *MsgDetailedInfo::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + MsgDetailedInfo *result = nullptr; + switch (constructor) { + case 0x809db6df: + result = new TL_msg_new_detailed_info(); + break; + case 0x276d3ec6: + result = new TL_msg_detailed_info(); + break; + default: + error = true; + DEBUG_E("can't parse magic %x in MsgDetailedInfo", constructor); + return nullptr; + } + result->readParams(stream, error); + return result; +} + +void TL_msg_new_detailed_info::readParams(NativeByteBuffer *stream, bool &error) { + answer_msg_id = stream->readInt64(&error); + bytes = stream->readInt32(&error); + status = stream->readInt32(&error); +} + +void TL_msg_detailed_info::readParams(NativeByteBuffer *stream, bool &error) { + msg_id = stream->readInt64(&error); + answer_msg_id = stream->readInt64(&error); + bytes = stream->readInt32(&error); + status = stream->readInt32(&error); +} + +TL_msg_copy *TL_msg_copy::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_msg_copy::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_msg_copy", constructor); + return nullptr; + } + TL_msg_copy *result = new TL_msg_copy(); + result->readParams(stream, error); + return result; +} + +void TL_msg_copy::readParams(NativeByteBuffer *stream, bool &error) { + orig_message = std::unique_ptr(TL_message::TLdeserialize(stream, stream->readUint32(&error), error)); +} + +void TL_msg_copy::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + orig_message->serializeToStream(stream); +} + +TL_msgs_all_info *TL_msgs_all_info::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_msgs_all_info::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_msgs_all_info", constructor); + return nullptr; + } + TL_msgs_all_info *result = new TL_msgs_all_info(); + result->readParams(stream, error); + return result; +} + +void TL_msgs_all_info::readParams(NativeByteBuffer *stream, bool &error) { + uint32_t magic = stream->readUint32(&error); + if (magic != 0x1cb5c415) { + error = true; + DEBUG_E("wrong Vector magic, got %x", magic); + return; + } + uint32_t count = stream->readUint32(&error); + if (count * sizeof(int64_t) + stream->position() > stream->limit()) { + error = true; + return; + } + for (uint32_t a = 0; a < count; a++) { + msg_ids.push_back(stream->readInt64(&error)); + } + info = std::unique_ptr(stream->readByteArray(&error)); +} + +void TL_rpc_result::readParamsEx(NativeByteBuffer *stream, uint32_t bytes, bool &error) { + req_msg_id = stream->readInt64(&error); + TLObject *object = ConnectionsManager::getInstance().TLdeserialize(ConnectionsManager::getInstance().getRequestWithMessageId(req_msg_id), bytes - 12, stream); + if (object != nullptr) { + result = std::unique_ptr(object); + } else { + error = true; + } +} + +void TL_new_session_created::readParams(NativeByteBuffer *stream, bool &error) { + first_msg_id = stream->readInt64(&error); + unique_id = stream->readInt64(&error); + server_salt = stream->readInt64(&error); +} + +DestroySessionRes *DestroySessionRes::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + DestroySessionRes *result = nullptr; + switch (constructor) { + case 0xe22045fc: + result = new TL_destroy_session_ok(); + break; + case 0x62d350c9: + result = new TL_destroy_session_none(); + break; + default: + error = true; + DEBUG_E("can't parse magic %x in DestroySessionRes", constructor); + return nullptr; + } + result->readParams(stream, error); + return result; +} + +void TL_destroy_session_ok::readParams(NativeByteBuffer *stream, bool &error) { + session_id = stream->readInt64(&error); +} + +void TL_destroy_session_none::readParams(NativeByteBuffer *stream, bool &error) { + session_id = stream->readInt64(&error); +} + +TL_msgs_ack *TL_msgs_ack::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_msgs_ack::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_msgs_ack", constructor); + return nullptr; + } + TL_msgs_ack *result = new TL_msgs_ack(); + result->readParams(stream, error); + return result; +} + +void TL_msgs_ack::readParams(NativeByteBuffer *stream, bool &error) { + uint32_t magic = stream->readUint32(&error); + if (magic != 0x1cb5c415) { + error = true; + DEBUG_E("wrong Vector magic, got %x", magic); + return; + } + uint32_t count = stream->readUint32(&error); + if (count * sizeof(int64_t) + stream->position() > stream->limit()) { + error = true; + return; + } + for (uint32_t a = 0; a < count; a++) { + msg_ids.push_back(stream->readInt64(&error)); + } +} + +void TL_msgs_ack::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(0x1cb5c415); + uint32_t count = (uint32_t) msg_ids.size(); + stream->writeInt32(count); + for (uint32_t a = 0; a < count; a++) { + stream->writeInt64(msg_ids[a]); + } +} + +TL_msg_container *TL_msg_container::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_msg_container::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_msg_container", constructor); + return nullptr; + } + TL_msg_container *result = new TL_msg_container(); + result->readParams(stream, error); + return result; +} + +void TL_msg_container::readParams(NativeByteBuffer *stream, bool &error) { + uint32_t count = stream->readUint32(&error); + for (uint32_t a = 0; a < count; a++) { + TL_message *object = new TL_message(); + object->readParams(stream, error); + if (error) { + return; + } + messages.push_back(std::unique_ptr(object)); + } +} + +void TL_msg_container::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + uint32_t count = (uint32_t) messages.size(); + stream->writeInt32(count); + for (uint32_t a = 0; a < count; a++) { + messages[a]->serializeToStream(stream); + } +} + +TL_message *TL_message::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_message::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_message", constructor); + return nullptr; + } + TL_message *result = new TL_message(); + result->readParams(stream, error); + return result; +} + +void TL_message::readParams(NativeByteBuffer *stream, bool &error) { + msg_id = stream->readInt64(&error); + seqno = stream->readInt32(&error); + bytes = stream->readInt32(&error); + TLObject *object = ConnectionsManager::getInstance().TLdeserialize(nullptr, (uint32_t) bytes, stream); + if (object == nullptr) { + unparsedBody = std::unique_ptr(new NativeByteBuffer(stream->bytes() + stream->position(), (uint32_t) bytes)); + stream->skip((uint32_t) bytes); + } else { + body = std::unique_ptr(object); + } +} + +void TL_message::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt64(msg_id); + stream->writeInt32(seqno); + stream->writeInt32(bytes); + if (outgoingBody != nullptr) { + outgoingBody->serializeToStream(stream); + } else { + body->serializeToStream(stream); + } +} + +TL_msg_resend_req *TL_msg_resend_req::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_msg_resend_req::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_msg_resend_req", constructor); + return nullptr; + } + TL_msg_resend_req *result = new TL_msg_resend_req(); + result->readParams(stream, error); + return result; +} + +void TL_msg_resend_req::readParams(NativeByteBuffer *stream, bool &error) { + uint32_t magic = stream->readUint32(&error); + if (magic != 0x1cb5c415) { + error = true; + DEBUG_E("wrong Vector magic, got %x", magic); + return; + } + uint32_t count = stream->readUint32(&error); + if (count * sizeof(int64_t) + stream->position() > stream->limit()) { + error = true; + return; + } + for (uint32_t a = 0; a < count; a++) { + msg_ids.push_back(stream->readInt64(&error)); + } +} + +void TL_msg_resend_req::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(0x1cb5c415); + uint32_t count = (uint32_t) msg_ids.size(); + stream->writeInt32(count); + for (uint32_t a = 0; a < count; a++) { + stream->writeInt64(msg_ids[a]); + } +} + +void TL_rpc_error::readParams(NativeByteBuffer *stream, bool &error) { + error_code = stream->readInt32(&error); + error_message = stream->readString(&error); +} + +void TL_rpc_req_error::readParams(NativeByteBuffer *stream, bool &error) { + query_id = stream->readInt64(&error); + error_code = stream->readInt32(&error); + error_message = stream->readString(&error); +} + +void TL_client_DH_inner_data::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeBytes(nonce.get()); + stream->writeBytes(server_nonce.get()); + stream->writeInt64(retry_id); + stream->writeByteArray(g_b.get()); +} + +TL_server_DH_inner_data *TL_server_DH_inner_data::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_server_DH_inner_data::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_server_DH_inner_data", constructor); + return nullptr; + } + TL_server_DH_inner_data *result = new TL_server_DH_inner_data(); + result->readParams(stream, error); + return result; +} + +void TL_server_DH_inner_data::readParams(NativeByteBuffer *stream, bool &error) { + nonce = std::unique_ptr(stream->readBytes(16, &error)); + server_nonce = std::unique_ptr(stream->readBytes(16, &error)); + g = stream->readUint32(&error); + dh_prime = std::unique_ptr(stream->readByteArray(&error)); + g_a = std::unique_ptr(stream->readByteArray(&error)); + server_time = stream->readInt32(&error); +} + +void TL_server_DH_inner_data::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeBytes(nonce.get()); + stream->writeBytes(server_nonce.get()); + stream->writeInt32(g); + stream->writeByteArray(dh_prime.get()); + stream->writeByteArray(g_a.get()); + stream->writeInt32(server_time); +} + +TLObject *TL_req_pq::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + return TL_resPQ::TLdeserialize(stream, constructor, error); +} + +void TL_req_pq::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeBytes(nonce.get()); +} + +TLObject *TL_req_DH_params::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + return Server_DH_Params::TLdeserialize(stream, constructor, error); +} + +void TL_req_DH_params::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeBytes(nonce.get()); + stream->writeBytes(server_nonce.get()); + stream->writeByteArray(p.get()); + stream->writeByteArray(q.get()); + stream->writeInt64(public_key_fingerprint); + stream->writeByteArray(encrypted_data.get()); +} + +TLObject *TL_set_client_DH_params::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + return Set_client_DH_params_answer::TLdeserialize(stream, constructor, error); +} + +void TL_set_client_DH_params::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeBytes(nonce.get()); + stream->writeBytes(server_nonce.get()); + stream->writeByteArray(encrypted_data.get()); +} + +TLObject *TL_rpc_drop_answer::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + return RpcDropAnswer::TLdeserialize(stream, constructor, error); +} + +void TL_rpc_drop_answer::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt64(req_msg_id); +} + +TLObject *TL_get_future_salts::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + return TL_future_salts::TLdeserialize(stream, constructor, error); +} + +void TL_get_future_salts::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(num); +} + +TLObject *TL_ping::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + return TL_pong::TLdeserialize(stream, constructor, error); +} + +void TL_ping::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt64(ping_id); +} + +TLObject *TL_ping_delay_disconnect::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + return TL_pong::TLdeserialize(stream, constructor, error); +} + +void TL_ping_delay_disconnect::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt64(ping_id); + stream->writeInt32(disconnect_delay); +} + +TLObject *TL_destroy_session::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + return DestroySessionRes::TLdeserialize(stream, constructor, error); +} + +void TL_destroy_session::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt64(session_id); +} + +TL_gzip_packed::~TL_gzip_packed() { + if (packed_data_to_send != nullptr) { + packed_data_to_send->reuse(); + packed_data_to_send = nullptr; + } +} + +void TL_gzip_packed::readParams(NativeByteBuffer *stream, bool &error) { + packed_data = std::unique_ptr(stream->readByteBuffer(false, &error)); +} + +void TL_gzip_packed::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeByteArray(packed_data_to_send); +} + +TL_error *TL_error::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_error::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_error", constructor); + return nullptr; + } + TL_error *result = new TL_error(); + result->readParams(stream, error); + return result; +} + +void TL_error::readParams(NativeByteBuffer *stream, bool &error) { + code = stream->readInt32(&error); + text = stream->readString(&error); +} + +void TL_error::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(code); + stream->writeString(text); +} + +void TL_invokeAfterMsg::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt64(msg_id); + if (outgoingQuery != nullptr) { + outgoingQuery->serializeToStream(stream); + } else { + query->serializeToStream(stream); + } +} + +void invokeWithLayer::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(layer); + query->serializeToStream(stream); +} + +void initConnection::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(api_id); + stream->writeString(device_model); + stream->writeString(system_version); + stream->writeString(app_version); + stream->writeString(lang_code); + query->serializeToStream(stream); +} + +TL_dcOption *TL_dcOption::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_dcOption::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_dcOption", constructor); + return nullptr; + } + TL_dcOption *result = new TL_dcOption(); + result->readParams(stream, error); + return result; +} + +void TL_dcOption::readParams(NativeByteBuffer *stream, bool &error) { + flags = stream->readInt32(&error); + id = stream->readInt32(&error); + ip_address = stream->readString(&error); + port = stream->readInt32(&error); +} + +void TL_dcOption::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(flags); + stream->writeInt32(id); + stream->writeString(ip_address); + stream->writeInt32(port); +} + +TL_disabledFeature *TL_disabledFeature::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_disabledFeature::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_disabledFeature", constructor); + return nullptr; + } + TL_disabledFeature *result = new TL_disabledFeature(); + result->readParams(stream, error); + return result; +} + +void TL_disabledFeature::readParams(NativeByteBuffer *stream, bool &error) { + feature = stream->readString(&error); + description = stream->readString(&error); +} + +void TL_disabledFeature::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeString(feature); + stream->writeString(description); +} + +TL_config *TL_config::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_config::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_config", constructor); + return nullptr; + } + TL_config *result = new TL_config(); + result->readParams(stream, error); + return result; +} + +void TL_config::readParams(NativeByteBuffer *stream, bool &error) { + date = stream->readInt32(&error); + expires = stream->readInt32(&error); + test_mode = stream->readBool(&error); + this_dc = stream->readInt32(&error); + uint32_t magic = stream->readUint32(&error); + if (magic != 0x1cb5c415) { + error = true; + DEBUG_E("wrong Vector magic, got %x", magic); + return; + } + int32_t count = stream->readInt32(&error); + for (int32_t a = 0; a < count; a++) { + TL_dcOption *object = TL_dcOption::TLdeserialize(stream, stream->readUint32(&error), error); + if (object == nullptr) { + return; + } + dc_options.push_back(std::unique_ptr(object)); + } + chat_size_max = stream->readInt32(&error); + megagroup_size_max = stream->readInt32(&error); + forwarded_count_max = stream->readInt32(&error); + online_update_period_ms = stream->readInt32(&error); + offline_blur_timeout_ms = stream->readInt32(&error); + offline_idle_timeout_ms = stream->readInt32(&error); + online_cloud_timeout_ms = stream->readInt32(&error); + notify_cloud_delay_ms = stream->readInt32(&error); + notify_default_delay_ms = stream->readInt32(&error); + chat_big_size = stream->readInt32(&error); + push_chat_period_ms = stream->readInt32(&error); + push_chat_limit = stream->readInt32(&error); + saved_gifs_limit = stream->readInt32(&error); + edit_time_limit = stream->readInt32(&error); + magic = stream->readUint32(&error); + if (magic != 0x1cb5c415) { + error = true; + DEBUG_E("wrong Vector magic, got %x", magic); + return; + } + count = stream->readInt32(&error); + for (int32_t a = 0; a < count; a++) { + TL_disabledFeature *object = TL_disabledFeature::TLdeserialize(stream, stream->readUint32(&error), error); + if (object == nullptr) { + return; + } + disabled_features.push_back(std::unique_ptr(object)); + } +} + +void TL_config::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(date); + stream->writeInt32(expires); + stream->writeBool(test_mode); + stream->writeInt32(this_dc); + stream->writeInt32(0x1cb5c415); + uint32_t count = (uint32_t) dc_options.size(); + stream->writeInt32(count); + for (uint32_t a = 0; a < count; a++) { + dc_options[a]->serializeToStream(stream); + } + stream->writeInt32(chat_size_max); + stream->writeInt32(megagroup_size_max); + stream->writeInt32(forwarded_count_max); + stream->writeInt32(online_update_period_ms); + stream->writeInt32(offline_blur_timeout_ms); + stream->writeInt32(offline_idle_timeout_ms); + stream->writeInt32(online_cloud_timeout_ms); + stream->writeInt32(notify_cloud_delay_ms); + stream->writeInt32(notify_default_delay_ms); + stream->writeInt32(chat_big_size); + stream->writeInt32(push_chat_period_ms); + stream->writeInt32(push_chat_limit); + stream->writeInt32(saved_gifs_limit); + stream->writeInt32(edit_time_limit); + stream->writeInt32(0x1cb5c415); + count = (uint32_t) disabled_features.size(); + stream->writeInt32(count); + for (uint32_t a = 0; a < count; a++) { + disabled_features[a]->serializeToStream(stream); + } +} + +TLObject *TL_help_getConfig::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + return TL_config::TLdeserialize(stream, constructor, error); +} + +void TL_help_getConfig::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); +} + +bool TL_help_getConfig::isNeedLayer() { + return true; +} + +Bool *Bool::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + Bool *result = nullptr; + switch (constructor) { + case 0x997275b5: + result = new TL_boolTrue(); + break; + case 0xbc799737: + result = new TL_boolFalse(); + break; + default: + error = true; + DEBUG_E("can't parse magic %x in Bool", constructor); + return nullptr; + } + result->readParams(stream, error); + return result; +} + +void TL_boolTrue::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); +} + +void TL_boolFalse::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); +} + +bool TL_account_registerDevice::isNeedLayer() { + return true; +} + +TLObject *TL_account_registerDevice::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + return Bool::TLdeserialize(stream, constructor, error); +} + +void TL_account_registerDevice::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(token_type); + stream->writeString(token); + stream->writeString(device_model); + stream->writeString(system_version); + stream->writeString(app_version); + stream->writeBool(app_sandbox); + stream->writeString(lang_code); +} + +User *User::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + User *result = nullptr; + switch (constructor) { + case 0x200250ba: + result = new TL_userEmpty(); + break; + case 0xd10d979a: + result = new TL_user(); + break; + default: + error = true; + DEBUG_E("can't parse magic %x in User", constructor); + return nullptr; + } + result->readParams(stream, error); + return result; +} + +void TL_userEmpty::readParams(NativeByteBuffer *stream, bool &error) { + id = stream->readInt32(&error); +} + +void TL_userEmpty::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(id); +} + +void TL_user::readParams(NativeByteBuffer *stream, bool &error) { + flags = stream->readInt32(&error); + id = stream->readInt32(&error); + if ((flags & 1) != 0) { + access_hash = stream->readInt64(&error); + } + if ((flags & 2) != 0) { + first_name = stream->readString(&error); + } + if ((flags & 4) != 0) { + last_name = stream->readString(&error); + } + if ((flags & 8) != 0) { + username = stream->readString(&error); + } + if ((flags & 16) != 0) { + phone = stream->readString(&error); + } + if ((flags & 32) != 0) { + photo = std::unique_ptr(UserProfilePhoto::TLdeserialize(stream, stream->readUint32(&error), error)); + } + if ((flags & 64) != 0) { + status = std::unique_ptr(UserStatus::TLdeserialize(stream, stream->readUint32(&error), error)); + } + if ((flags & 16384) != 0) { + bot_info_version = stream->readInt32(&error); + } + if ((flags & 262144) != 0) { + restriction_reason = stream->readString(&error); + } + if ((flags & 524288) != 0) { + bot_inline_placeholder = stream->readString(&error); + } +} + +void TL_user::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(flags); + stream->writeInt32(id); + if ((flags & 1) != 0) { + stream->writeInt64(access_hash); + } + if ((flags & 2) != 0) { + stream->writeString(first_name); + } + if ((flags & 4) != 0) { + stream->writeString(last_name); + } + if ((flags & 8) != 0) { + stream->writeString(username); + } + if ((flags & 16) != 0) { + stream->writeString(phone); + } + if ((flags & 32) != 0) { + photo->serializeToStream(stream); + } + if ((flags & 64) != 0) { + status->serializeToStream(stream); + } + if ((flags & 16384) != 0) { + stream->writeInt32(bot_info_version); + } + if ((flags & 262144) != 0) { + stream->writeString(restriction_reason); + } + if ((flags & 524288) != 0) { + stream->writeString(bot_inline_placeholder); + } +} + +TL_auth_authorization *TL_auth_authorization::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_auth_authorization::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_auth_authorization", constructor); + return nullptr; + } + TL_auth_authorization *result = new TL_auth_authorization(); + result->readParams(stream, error); + return result; +} + +void TL_auth_authorization::readParams(NativeByteBuffer *stream, bool &error) { + user = std::unique_ptr(User::TLdeserialize(stream, stream->readUint32(&error), error)); +} + +TL_auth_exportedAuthorization *TL_auth_exportedAuthorization::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + if (TL_auth_exportedAuthorization::constructor != constructor) { + error = true; + DEBUG_E("can't parse magic %x in TL_auth_exportedAuthorization", constructor); + return nullptr; + } + TL_auth_exportedAuthorization *result = new TL_auth_exportedAuthorization(); + result->readParams(stream, error); + return result; +} + +void TL_auth_exportedAuthorization::readParams(NativeByteBuffer *stream, bool &error) { + id = stream->readInt32(&error); + bytes = std::unique_ptr(stream->readByteArray(&error)); +} + +bool TL_auth_exportAuthorization::isNeedLayer() { + return true; +} + +TLObject *TL_auth_exportAuthorization::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + return TL_auth_exportedAuthorization::TLdeserialize(stream, constructor, error); +} + +void TL_auth_exportAuthorization::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(dc_id); +} + +bool TL_auth_importAuthorization::isNeedLayer() { + return true; +} + +TLObject *TL_auth_importAuthorization::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + return TL_auth_authorization::TLdeserialize(stream, constructor, error); +} + +void TL_auth_importAuthorization::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(id); + stream->writeByteArray(bytes.get()); +} + +UserStatus *UserStatus::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + UserStatus *result = nullptr; + switch (constructor) { + case 0x8c703f: + result = new TL_userStatusOffline(); + break; + case 0x7bf09fc: + result = new TL_userStatusLastWeek(); + break; + case 0x9d05049: + result = new TL_userStatusEmpty(); + break; + case 0x77ebc742: + result = new TL_userStatusLastMonth(); + break; + case 0xedb93949: + result = new TL_userStatusOnline(); + break; + case 0xe26f42f1: + result = new TL_userStatusRecently(); + break; + default: + error = true; + DEBUG_E("can't parse magic %x in UserStatus", constructor); + return nullptr; + } + result->readParams(stream, error); + return result; +} + +void TL_userStatusOffline::readParams(NativeByteBuffer *stream, bool &error) { + expires = stream->readInt32(&error); +} + +void TL_userStatusOffline::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(expires); +} + +void TL_userStatusLastWeek::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); +} + +void TL_userStatusEmpty::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); +} + +void TL_userStatusLastMonth::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); +} + +void TL_userStatusOnline::readParams(NativeByteBuffer *stream, bool &error) { + expires = stream->readInt32(&error); +} + +void TL_userStatusOnline::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(expires); +} + +void TL_userStatusRecently::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); +} + +FileLocation *FileLocation::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + FileLocation *result = nullptr; + switch (constructor) { + case 0x53d69076: + result = new TL_fileLocation(); + break; + case 0x7c596b46: + result = new TL_fileLocationUnavailable(); + break; + default: + error = true; + DEBUG_E("can't parse magic %x in FileLocation", constructor); + return nullptr; + } + result->readParams(stream, error); + return result; +} + +void TL_fileLocation::readParams(NativeByteBuffer *stream, bool &error) { + dc_id = stream->readInt32(&error); + volume_id = stream->readInt64(&error); + local_id = stream->readInt32(&error); + secret = stream->readInt64(&error); +} + +void TL_fileLocation::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt32(dc_id); + stream->writeInt64(volume_id); + stream->writeInt32(local_id); + stream->writeInt64(secret); +} + +void TL_fileLocationUnavailable::readParams(NativeByteBuffer *stream, bool &error) { + volume_id = stream->readInt64(&error); + local_id = stream->readInt32(&error); + secret = stream->readInt64(&error); +} + +void TL_fileLocationUnavailable::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt64(volume_id); + stream->writeInt32(local_id); + stream->writeInt64(secret); +} + +UserProfilePhoto *UserProfilePhoto::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + UserProfilePhoto *result = nullptr; + switch (constructor) { + case 0x4f11bae1: + result = new TL_userProfilePhotoEmpty(); + break; + case 0xd559d8c8: + result = new TL_userProfilePhoto(); + break; + default: + error = true; + DEBUG_E("can't parse magic %x in UserProfilePhoto", constructor); + return nullptr; + } + result->readParams(stream, error); + return result; +} + +void TL_userProfilePhotoEmpty::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); +} + +void TL_userProfilePhoto::readParams(NativeByteBuffer *stream, bool &error) { + photo_id = stream->readInt64(&error); + photo_small = std::unique_ptr(FileLocation::TLdeserialize(stream, stream->readUint32(&error), error)); + photo_big = std::unique_ptr(FileLocation::TLdeserialize(stream, stream->readUint32(&error), error)); +} + +void TL_userProfilePhoto::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeInt64(photo_id); + photo_small->serializeToStream(stream); + photo_big->serializeToStream(stream); +} + +auth_SentCode *auth_SentCode::TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + auth_SentCode *result = nullptr; + switch (constructor) { + case 0xe325edcf: + result = new TL_auth_sentAppCode(); + break; + case 0xefed51d9: + result = new TL_auth_sentCode(); + break; + default: + error = true; + DEBUG_E("can't parse magic %x in auth_SentCode", constructor); + return nullptr; + } + result->readParams(stream, error); + return result; +} + +void TL_auth_sentAppCode::readParams(NativeByteBuffer *stream, bool &error) { + phone_registered = stream->readBool(&error); + phone_code_hash = stream->readString(&error); + send_call_timeout = stream->readInt32(&error); + is_password = stream->readBool(&error); +} + +void TL_auth_sentAppCode::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeBool(phone_registered); + stream->writeString(phone_code_hash); + stream->writeInt32(send_call_timeout); + stream->writeBool(is_password); +} + +void TL_auth_sentCode::readParams(NativeByteBuffer *stream, bool &error) { + phone_registered = stream->readBool(&error); + phone_code_hash = stream->readString(&error); + send_call_timeout = stream->readInt32(&error); + is_password = stream->readBool(&error); +} + +void TL_auth_sentCode::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeBool(phone_registered); + stream->writeString(phone_code_hash); + stream->writeInt32(send_call_timeout); + stream->writeBool(is_password); +} + +TLObject *TL_auth_sendCode::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + return auth_SentCode::TLdeserialize(stream, constructor, error); +} + +void TL_auth_sendCode::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); + stream->writeString(phone_number); + stream->writeInt32(sms_type); + stream->writeInt32(api_id); + stream->writeString(api_hash); + stream->writeString(lang_code); +} + +void TL_updatesTooLong::serializeToStream(NativeByteBuffer *stream) { + stream->writeInt32(constructor); +} diff --git a/TMessagesProj/jni/tgnet/MTProtoScheme.h b/TMessagesProj/jni/tgnet/MTProtoScheme.h new file mode 100644 index 00000000..75922fef --- /dev/null +++ b/TMessagesProj/jni/tgnet/MTProtoScheme.h @@ -0,0 +1,989 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef MTPROTOSCHEME_H +#define MTPROTOSCHEME_H + +#include +#include +#include +#include +#include "TLObject.h" + +class ByteArray; +class NativeByteBuffer; + +class TLClassStore { + +public: + static TLObject *TLdeserialize(NativeByteBuffer *stream, uint32_t bytes, uint32_t constructor, bool &error); + +}; + +class TL_api_request : public TLObject { + +public: + NativeByteBuffer *request = nullptr; + + ~TL_api_request(); + bool isNeedLayer(); + TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t bytes, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_api_response : public TLObject { + +public: + std::unique_ptr response; + + void readParamsEx(NativeByteBuffer *stream, uint32_t bytes, bool &error); +}; + +class TL_future_salt : public TLObject { + +public: + static const uint32_t constructor = 0x0949d9dc; + + int32_t valid_since; + int32_t valid_until; + int64_t salt; + + static TL_future_salt *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_msgs_state_info : public TLObject { + +public: + static const uint32_t constructor = 0x04deb57d; + + int64_t req_msg_id; + std::unique_ptr info; + + static TL_msgs_state_info *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class Server_DH_Params : public TLObject { + +public: + std::unique_ptr nonce; + std::unique_ptr server_nonce; + std::unique_ptr new_nonce_hash; + std::unique_ptr encrypted_answer; + + static Server_DH_Params *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); +}; + +class TL_server_DH_params_fail : public Server_DH_Params { + +public: + static const uint32_t constructor = 0x79cb045d; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_server_DH_params_ok : public Server_DH_Params { + +public: + static const uint32_t constructor = 0xd0e8075c; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_resPQ : public TLObject { + +public: + static const uint32_t constructor = 0x05162463; + + std::unique_ptr nonce; + std::unique_ptr server_nonce; + std::unique_ptr pq; + std::vector server_public_key_fingerprints; + + static TL_resPQ *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_p_q_inner_data : public TLObject { + +public: + static const uint32_t constructor = 0x83c95aec; + + std::unique_ptr pq; + std::unique_ptr p; + std::unique_ptr q; + std::unique_ptr nonce; + std::unique_ptr server_nonce; + std::unique_ptr new_nonce; + + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_pong : public TLObject { + +public: + static const uint32_t constructor = 0x347773c5; + + int64_t msg_id; + int64_t ping_id; + + static TL_pong *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_future_salts : public TLObject { + +public: + static const uint32_t constructor = 0xae500895; + + int64_t req_msg_id; + int32_t now; + std::vector> salts; + + static TL_future_salts *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class RpcDropAnswer : public TLObject { + +public: + int64_t msg_id; + int32_t seq_no; + int32_t bytes; + + static RpcDropAnswer *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); +}; + +class TL_rpc_answer_unknown : public RpcDropAnswer { + +public: + static const uint32_t constructor = 0x5e2ad36e; + + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_rpc_answer_dropped : public RpcDropAnswer { + +public: + static const uint32_t constructor = 0xa43ad8b7; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_rpc_answer_dropped_running : public RpcDropAnswer { + +public: + static const uint32_t constructor = 0xcd78e586; + + void serializeToStream(NativeByteBuffer *stream); +}; + +class Set_client_DH_params_answer : public TLObject { + +public: + std::unique_ptr nonce; + std::unique_ptr server_nonce; + std::unique_ptr new_nonce_hash2; + std::unique_ptr new_nonce_hash3; + std::unique_ptr new_nonce_hash1; + + static Set_client_DH_params_answer *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); +}; + +class TL_message : public TLObject { + +public: + static const uint32_t constructor = 0x5bb8e511; + + int64_t msg_id; + int32_t seqno; + int32_t bytes; + std::unique_ptr body; + TLObject *outgoingBody = nullptr; + std::unique_ptr unparsedBody; + + static TL_message *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_dh_gen_retry : public Set_client_DH_params_answer { + +public: + static const uint32_t constructor = 0x46dc1fb9; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_dh_gen_fail : public Set_client_DH_params_answer { + +public: + static const uint32_t constructor = 0xa69dae02; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_dh_gen_ok : public Set_client_DH_params_answer { + +public: + static const uint32_t constructor = 0x3bcbf734; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class BadMsgNotification : public TLObject { + +public: + int64_t bad_msg_id; + int32_t bad_msg_seqno; + int32_t error_code; + int64_t new_server_salt; + + static BadMsgNotification *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); +}; + +class TL_bad_msg_notification : public BadMsgNotification { + +public: + static const uint32_t constructor = 0xa7eff811; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_bad_server_salt : public BadMsgNotification { + +public: + static const uint32_t constructor = 0xedab447b; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_msgs_state_req : public TLObject { + +public: + static const uint32_t constructor = 0xda69fb52; + + std::vector msg_ids; + + static TL_msgs_state_req *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class MsgDetailedInfo : public TLObject { + +public: + int64_t answer_msg_id; + int32_t bytes; + int32_t status; + int64_t msg_id; + + static MsgDetailedInfo *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); +}; + +class TL_msg_new_detailed_info : public MsgDetailedInfo { + +public: + static const uint32_t constructor = 0x809db6df; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_msg_detailed_info : public MsgDetailedInfo { + +public: + static const uint32_t constructor = 0x276d3ec6; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_msg_copy : public TLObject { + +public: + static const uint32_t constructor = 0xe06046b2; + + std::unique_ptr orig_message; + + static TL_msg_copy *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_msgs_all_info : public TLObject { + +public: + static const uint32_t constructor = 0x8cc0d131; + + std::vector msg_ids; + std::unique_ptr info; + + static TL_msgs_all_info *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_rpc_result : public TLObject { + +public: + static const uint32_t constructor = 0xf35c6d01; + + int64_t req_msg_id; + std::unique_ptr result; + + void readParamsEx(NativeByteBuffer *stream, uint32_t bytes, bool &error); +}; + +class TL_new_session_created : public TLObject { + +public: + static const uint32_t constructor = 0x9ec20908; + + int64_t first_msg_id; + int64_t unique_id; + int64_t server_salt; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class DestroySessionRes : public TLObject { + +public: + int64_t session_id; + + static DestroySessionRes *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); +}; + +class TL_destroy_session_ok : public DestroySessionRes { + +public: + static const uint32_t constructor = 0xe22045fc; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_destroy_session_none : public DestroySessionRes { + +public: + static const uint32_t constructor = 0x62d350c9; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_msgs_ack : public TLObject { + +public: + static const uint32_t constructor = 0x62d6b459; + + std::vector msg_ids; + + static TL_msgs_ack *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_msg_container : public TLObject { + +public: + static const uint32_t constructor = 0x73f1f8dc; + + std::vector> messages; + + static TL_msg_container *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_msg_resend_req : public TLObject { + +public: + static const uint32_t constructor = 0x7d861a08; + + std::vector msg_ids; + + static TL_msg_resend_req *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class RpcError : public TLObject { + +public: + int32_t error_code; + std::string error_message; + int64_t query_id; +}; + +class TL_rpc_error : public RpcError { + +public: + static const uint32_t constructor = 0x2144ca19; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_rpc_req_error : public RpcError { + +public: + static const uint32_t constructor = 0x7ae432f5; + + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_client_DH_inner_data : public TLObject { + +public: + static const uint32_t constructor = 0x6643b654; + + std::unique_ptr nonce; + std::unique_ptr server_nonce; + int64_t retry_id; + std::unique_ptr g_b; + + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_server_DH_inner_data : public TLObject { + +public: + static const uint32_t constructor = 0xb5890dba; + + std::unique_ptr nonce; + std::unique_ptr server_nonce; + uint32_t g; + std::unique_ptr dh_prime; + std::unique_ptr g_a; + int32_t server_time; + + static TL_server_DH_inner_data *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_req_pq : public TLObject { + +public: + static const uint32_t constructor = 0x60469778; + + std::unique_ptr nonce; + + TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_req_DH_params : public TLObject { + +public: + static const uint32_t constructor = 0xd712e4be; + + std::unique_ptr nonce; + std::unique_ptr server_nonce; + std::unique_ptr p; + std::unique_ptr q; + int64_t public_key_fingerprint; + std::unique_ptr encrypted_data; + + TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_set_client_DH_params : public TLObject { + +public: + static const uint32_t constructor = 0xf5045f1f; + + std::unique_ptr nonce; + std::unique_ptr server_nonce; + std::unique_ptr encrypted_data; + + TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_rpc_drop_answer : public TLObject { + +public: + static const uint32_t constructor = 0x58e4a740; + + int64_t req_msg_id; + + TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_get_future_salts : public TLObject { + +public: + static const uint32_t constructor = 0xb921bd04; + + int32_t num; + + TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_ping : public TLObject { + +public: + static const uint32_t constructor = 0x7abe77ec; + + int64_t ping_id; + + TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_ping_delay_disconnect : public TLObject { + +public: + static const uint32_t constructor = 0xf3427b8c; + + int64_t ping_id; + int32_t disconnect_delay; + + TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_destroy_session : public TLObject { + +public: + static const uint32_t constructor = 0xe7512126; + + int64_t session_id; + + TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_gzip_packed : public TLObject { + +public: + static const uint32_t constructor = 0x3072cfa1; + + NativeByteBuffer *packed_data_to_send = nullptr; + std::unique_ptr packed_data; + std::unique_ptr originalRequest; + + ~TL_gzip_packed(); + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_error : public TLObject { + +public: + static const uint32_t constructor = 0xc4b9f9bb; + + int32_t code; + std::string text; + + static TL_error *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_invokeAfterMsg : public TLObject { + +public: + static const uint32_t constructor = 0xcb9f372d; + + int64_t msg_id; + TLObject *outgoingQuery = nullptr; + std::unique_ptr query; + + void serializeToStream(NativeByteBuffer *stream); +}; + +class invokeWithLayer : public TLObject { + +public: + static const uint32_t constructor = 0xda9b0d0d; + + int32_t layer; + std::unique_ptr query; + + void serializeToStream(NativeByteBuffer *stream); +}; + +class initConnection : public TLObject { + +public: + static const uint32_t constructor = 0x69796de9; + + int32_t api_id; + std::string device_model; + std::string system_version; + std::string app_version; + std::string lang_code; + std::unique_ptr query; + + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_dcOption : public TLObject { + +public: + static const uint32_t constructor = 0x5d8c6cc; + + int32_t flags; + int32_t id; + std::string ip_address; + int32_t port; + + static TL_dcOption *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_disabledFeature : public TLObject { + +public: + static const uint32_t constructor = 0xae636f24; + + std::string feature; + std::string description; + + static TL_disabledFeature *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_config : public TLObject { + +public: + static const uint32_t constructor = 0x317ceef4; + + int32_t date; + int32_t expires; + bool test_mode; + int32_t this_dc; + std::vector> dc_options; + int32_t chat_size_max; + int32_t megagroup_size_max; + int32_t forwarded_count_max; + int32_t online_update_period_ms; + int32_t offline_blur_timeout_ms; + int32_t offline_idle_timeout_ms; + int32_t online_cloud_timeout_ms; + int32_t notify_cloud_delay_ms; + int32_t notify_default_delay_ms; + int32_t chat_big_size; + int32_t push_chat_period_ms; + int32_t push_chat_limit; + int32_t saved_gifs_limit; + int32_t edit_time_limit; + std::vector> disabled_features; + + static TL_config *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_help_getConfig : public TLObject { + +public: + static const uint32_t constructor = 0xc4f9186b; + + bool isNeedLayer(); + TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class Bool : public TLObject { + +public: + static Bool *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); +}; + +class TL_boolTrue : public Bool { + +public: + static const uint32_t constructor = 0x997275b5; + + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_boolFalse : public Bool { + +public: + static const uint32_t constructor = 0xbc799737; + + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_account_registerDevice : public TLObject { + +public: + static const uint32_t constructor = 0x446c712c; + + int32_t token_type; + std::string token; + std::string device_model; + std::string system_version; + std::string app_version; + bool app_sandbox; + std::string lang_code; + + bool isNeedLayer(); + TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class UserStatus : public TLObject { + +public: + int32_t expires; + + static UserStatus *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); +}; + +class TL_userStatusOffline : public UserStatus { + +public: + static const uint32_t constructor = 0x8c703f; + + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_userStatusLastWeek : public UserStatus { + +public: + static const uint32_t constructor = 0x7bf09fc; + + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_userStatusEmpty : public UserStatus { + +public: + static const uint32_t constructor = 0x9d05049; + + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_userStatusLastMonth : public UserStatus { + +public: + static const uint32_t constructor = 0x77ebc742; + + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_userStatusOnline : public UserStatus { + +public: + static const uint32_t constructor = 0xedb93949; + + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_userStatusRecently : public UserStatus { + +public: + static const uint32_t constructor = 0xe26f42f1; + + void serializeToStream(NativeByteBuffer *stream); +}; + +class FileLocation : public TLObject { + +public: + int32_t dc_id; + int64_t volume_id; + int32_t local_id; + int64_t secret; + + static FileLocation *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); +}; + +class TL_fileLocation : public FileLocation { + +public: + static const uint32_t constructor = 0x53d69076; + + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_fileLocationUnavailable : public FileLocation { + +public: + static const uint32_t constructor = 0x7c596b46; + + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class UserProfilePhoto : public TLObject { + +public: + int64_t photo_id; + std::unique_ptr photo_small; + std::unique_ptr photo_big; + + static UserProfilePhoto *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); +}; + +class TL_userProfilePhotoEmpty : public UserProfilePhoto { + +public: + static const uint32_t constructor = 0x4f11bae1; + + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_userProfilePhoto : public UserProfilePhoto { + +public: + static const uint32_t constructor = 0xd559d8c8; + + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class User : public TLObject { + +public: + int32_t id; + std::string first_name; + std::string last_name; + std::string username; + int64_t access_hash; + std::string phone; + std::unique_ptr photo; + std::unique_ptr status; + int32_t flags; + int32_t bot_info_version; + std::string restriction_reason; + std::string bot_inline_placeholder; + + static User *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); +}; + +class TL_userEmpty : public User { + +public: + static const uint32_t constructor = 0x200250ba; + + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_user : public User { + +public: + static const uint32_t constructor = 0xd10d979a; + + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_auth_authorization : public TLObject { + +public: + static const uint32_t constructor = 0xff036af1; + + std::unique_ptr user; + + static TL_auth_authorization *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_auth_exportedAuthorization : public TLObject { + +public: + static const uint32_t constructor = 0xdf969c2d; + + int32_t id; + std::unique_ptr bytes; + + static TL_auth_exportedAuthorization *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void readParams(NativeByteBuffer *stream, bool &error); +}; + +class TL_auth_exportAuthorization : public TLObject { + +public: + static const uint32_t constructor = 0xe5bfffcd; + + int32_t dc_id; + + bool isNeedLayer(); + TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_auth_importAuthorization : public TLObject { + +public: + static const uint32_t constructor = 0xe3ef9613; + + int32_t id; + std::unique_ptr bytes; + + bool isNeedLayer(); + TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class auth_SentCode : public TLObject { + +public: + bool phone_registered; + std::string phone_code_hash; + int32_t send_call_timeout; + bool is_password; + + static auth_SentCode *TLdeserialize(NativeByteBuffer *stream, uint32_t constructor, bool &error); +}; + +class TL_auth_sentAppCode : public auth_SentCode { + +public: + static const uint32_t constructor = 0xe325edcf; + + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_auth_sentCode : public auth_SentCode { + +public: + static const uint32_t constructor = 0xefed51d9; + + void readParams(NativeByteBuffer *stream, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_auth_sendCode : public TLObject { + +public: + static const uint32_t constructor = 0x768d5f4d; + + std::string phone_number; + int32_t sms_type; + int32_t api_id; + std::string api_hash; + std::string lang_code; + + TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error); + void serializeToStream(NativeByteBuffer *stream); +}; + +class TL_updatesTooLong : public TLObject { + +public: + static const uint32_t constructor = 0xe317af7e; + + void serializeToStream(NativeByteBuffer *stream); +}; + +#endif diff --git a/TMessagesProj/jni/tgnet/NativeByteBuffer.cpp b/TMessagesProj/jni/tgnet/NativeByteBuffer.cpp new file mode 100644 index 00000000..19f36f06 --- /dev/null +++ b/TMessagesProj/jni/tgnet/NativeByteBuffer.cpp @@ -0,0 +1,703 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include +#include +#include "NativeByteBuffer.h" +#include "FileLog.h" +#include "ByteArray.h" +#include "ConnectionsManager.h" +#include "BuffersStorage.h" + +NativeByteBuffer::NativeByteBuffer(uint32_t size) { +#ifdef ANDROID + if (jclass_ByteBuffer != nullptr) { + JNIEnv *env = 0; + if (javaVm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { + DEBUG_E("can't get jnienv"); + exit(1); + } + javaByteBuffer = env->CallStaticObjectMethod(jclass_ByteBuffer, jclass_ByteBuffer_allocateDirect, size); + if (javaByteBuffer == nullptr) { + DEBUG_E("can't create javaByteBuffer"); + exit(1); + } + jobject globalRef = env->NewGlobalRef(javaByteBuffer); + env->DeleteLocalRef(javaByteBuffer); + javaByteBuffer = globalRef; + buffer = (uint8_t *) env->GetDirectBufferAddress(javaByteBuffer); + bufferOwner = false; + } else { +#endif + buffer = new uint8_t[size]; + bufferOwner = true; +#ifdef ANDROID + } +#endif + if (buffer == nullptr) { + DEBUG_E("can't allocate NativeByteBuffer buffer"); + exit(1); + } + _limit = _capacity = size; +} + +NativeByteBuffer::NativeByteBuffer(bool calculate) { + calculateSizeOnly = calculate; +} + +NativeByteBuffer::NativeByteBuffer(uint8_t *buff, uint32_t length) { + buffer = buff; + sliced = true; + _limit = _capacity = length; +} + +NativeByteBuffer::~NativeByteBuffer() { +#ifdef ANDROID + if (javaByteBuffer != nullptr) { + JNIEnv *env = 0; + if (javaVm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { + DEBUG_E("can't get jnienv"); + exit(1); + } + env->DeleteGlobalRef(javaByteBuffer); + javaByteBuffer = nullptr; + } +#endif + if (bufferOwner && !sliced && buffer != nullptr) { + delete[] buffer; + buffer = nullptr; + } +} + +uint32_t NativeByteBuffer::position() { + return _position; +} + +void NativeByteBuffer::position(uint32_t position) { + if (position > _limit) { + return; + } + _position = position; +} + +uint32_t NativeByteBuffer::capacity() { + return _capacity; +} + +uint32_t NativeByteBuffer::limit() { + return _limit; +} + +uint32_t NativeByteBuffer::remaining() { + return _limit - _position; +} + +void NativeByteBuffer::clearCapacity() { + if (!calculateSizeOnly) { + return; + } + _capacity = 0; +} + +void NativeByteBuffer::limit(uint32_t limit) { + if (limit > _capacity) { + return; + } + if (_position > limit) { + _position = limit; + } + _limit = limit; +} + +void NativeByteBuffer::flip() { + _limit = _position; + _position = 0; +} + +void NativeByteBuffer::clear() { + _position = 0; + _limit = _capacity; +} + +uint8_t *NativeByteBuffer::bytes() { + return buffer; +} + +void NativeByteBuffer::rewind() { + _position = 0; +} + +void NativeByteBuffer::compact() { + if (_position == _limit) { + return; + } + memmove(buffer, buffer + _position, sizeof(uint8_t) * (_limit - _position)); + _position = (_limit - _position); + _limit = _capacity; +} + +bool NativeByteBuffer::hasRemaining() { + return _position < _limit; +} + +void NativeByteBuffer::skip(uint32_t length) { + if (!calculateSizeOnly) { + if (_position + length > _limit) { + return; + } + _position += length; + } else { + _capacity += length; + } +} + +void NativeByteBuffer::writeInt32(int32_t x, bool *error) { + if (!calculateSizeOnly) { + if (_position + 4 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("write int32 error"); + return; + } + buffer[_position++] = (uint8_t) x; + buffer[_position++] = (uint8_t) (x >> 8); + buffer[_position++] = (uint8_t) (x >> 16); + buffer[_position++] = (uint8_t) (x >> 24); + } else { + _capacity += 4; + } +} + +void NativeByteBuffer::writeInt64(int64_t x, bool *error) { + if (!calculateSizeOnly) { + if (_position + 8 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("write int64 error"); + return; + } + buffer[_position++] = (uint8_t) x; + buffer[_position++] = (uint8_t) (x >> 8); + buffer[_position++] = (uint8_t) (x >> 16); + buffer[_position++] = (uint8_t) (x >> 24); + buffer[_position++] = (uint8_t) (x >> 32); + buffer[_position++] = (uint8_t) (x >> 40); + buffer[_position++] = (uint8_t) (x >> 48); + buffer[_position++] = (uint8_t) (x >> 56); + } else { + _capacity += 8; + } +} + +void NativeByteBuffer::writeBool(bool value, bool *error) { + if (!calculateSizeOnly) { + if (value) { + writeInt32(0x997275b5, error); + } else { + writeInt32(0xbc799737, error); + } + } else { + _capacity += 4; + } +} + +void NativeByteBuffer::writeBytes(uint8_t *b, uint32_t length, bool *error) { + if (!calculateSizeOnly) { + if (_position + length > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("write bytes error"); + return; + } + writeBytesInternal(b, 0, length); + } else { + _capacity += length; + } +} + +void NativeByteBuffer::writeBytes(uint8_t *b, uint32_t offset, uint32_t length, bool *error) { + if (!calculateSizeOnly) { + if (_position + length > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("write bytes error"); + return; + } + writeBytesInternal(b, offset, length); + } else { + _capacity += length; + } +} + +void NativeByteBuffer::writeBytes(NativeByteBuffer *b, bool *error) { + uint32_t length = b->_limit - b->_position; + if (length == 0) { + return; + } + if (!calculateSizeOnly) { + if (_position + length > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("write bytes error"); + return; + } + writeBytesInternal(b->buffer + b->_position, 0, length); + b->position(b->limit()); + } else { + _capacity += length; + } +} + +void NativeByteBuffer::writeBytes(ByteArray *b, bool *error) { + if (!calculateSizeOnly) { + if (_position + b->length > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("write bytes error"); + return; + } + writeBytesInternal(b->bytes, 0, b->length); + } else { + _capacity += b->length; + } +} + +void NativeByteBuffer::writeBytesInternal(uint8_t *b, uint32_t offset, uint32_t length) { + memcpy(buffer + _position, b + offset, sizeof(uint8_t) * length); + _position += length; +} + +void NativeByteBuffer::writeByte(uint8_t i, bool *error) { + if (!calculateSizeOnly) { + if (_position + 1 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("write byte error"); + return; + } + buffer[_position++] = i; + } else { + _capacity += 1; + } +} + +void NativeByteBuffer::writeString(std::string s, bool *error) { + writeByteArray((uint8_t *) s.c_str(), (uint32_t) s.length(), error); +} + +void NativeByteBuffer::writeByteArray(uint8_t *b, uint32_t offset, uint32_t length, bool *error) { + if (length <= 253) { + if (!calculateSizeOnly) { + if (_position + 1 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("write byte array error"); + return; + } + buffer[_position++] = (uint8_t) length; + } else { + _capacity += 1; + } + } else { + if (!calculateSizeOnly) { + if (_position + 4 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("write byte array error"); + return; + } + buffer[_position++] = (uint8_t) 254; + buffer[_position++] = (uint8_t) length; + buffer[_position++] = (uint8_t) (length >> 8); + buffer[_position++] = (uint8_t) (length >> 16); + } else { + _capacity += 4; + } + } + if (!calculateSizeOnly) { + if (_position + length > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("write byte array error"); + return; + } + writeBytesInternal(b, offset, length); + } else { + _capacity += length; + } + uint32_t addition = (length + (length <= 253 ? 1 : 4)) % 4; + if (addition != 0) { + addition = 4 - addition; + } + if (!calculateSizeOnly && _position + addition > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("write byte array error"); + return; + } + for (uint32_t a = 0; a < addition; a++) { + if (!calculateSizeOnly) { + buffer[_position++] = (uint8_t) 0; + } else { + _capacity += 1; + } + } +} + +void NativeByteBuffer::writeByteArray(uint8_t *b, uint32_t length, bool *error) { + writeByteArray(b, 0, length, error); +} + +void NativeByteBuffer::writeByteArray(NativeByteBuffer *b, bool *error) { + b->rewind(); + writeByteArray(b->buffer, 0, b->limit(), error); +} + +void NativeByteBuffer::writeByteArray(ByteArray *b, bool *error) { + writeByteArray(b->bytes, 0, b->length, error); +} + +void NativeByteBuffer::writeDouble(double d, bool *error) { + int64_t value; + memcpy(&value, &d, sizeof(int64_t)); + writeInt64(value, error); +} + +void NativeByteBuffer::writeInt32(int32_t x) { + writeInt32(x, nullptr); +} + +void NativeByteBuffer::writeInt64(int64_t x) { + writeInt64(x, nullptr); +} + +void NativeByteBuffer::writeBool(bool value) { + writeBool(value, nullptr); +} + +void NativeByteBuffer::writeBytes(uint8_t *b, uint32_t length) { + writeBytes(b, length, nullptr); +} + +void NativeByteBuffer::writeBytes(uint8_t *b, uint32_t offset, uint32_t length) { + writeBytes(b, offset, length, nullptr); +} + +void NativeByteBuffer::writeBytes(ByteArray *b) { + writeBytes(b, nullptr); +} + +void NativeByteBuffer::writeBytes(NativeByteBuffer *b) { + writeBytes(b, nullptr); +} + +void NativeByteBuffer::writeByte(uint8_t i) { + writeByte(i, nullptr); +} + +void NativeByteBuffer::writeString(std::string s) { + writeString(s, nullptr); +} + +void NativeByteBuffer::writeByteArray(uint8_t *b, uint32_t offset, uint32_t length) { + writeByteArray(b, offset, length, nullptr); +} + +void NativeByteBuffer::writeByteArray(uint8_t *b, uint32_t length) { + writeByteArray(b, length, nullptr); +} + +void NativeByteBuffer::writeByteArray(NativeByteBuffer *b) { + writeByteArray(b, nullptr); +} + +void NativeByteBuffer::writeByteArray(ByteArray *b) { + writeByteArray(b->bytes, b->length, nullptr); +} + +void NativeByteBuffer::writeDouble(double d) { + writeDouble(d, nullptr); +} + +int32_t NativeByteBuffer::readInt32(bool *error) { + if (_position + 4 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read int32 error"); + return 0; + } + int32_t result = ((buffer[_position] & 0xff)) | + ((buffer[_position + 1] & 0xff) << 8) | + ((buffer[_position + 2] & 0xff) << 16) | + ((buffer[_position + 3] & 0xff) << 24); + _position += 4; + return result; +} + +uint32_t NativeByteBuffer::readUint32(bool *error) { + return (uint32_t) readInt32(error); +} + +uint64_t NativeByteBuffer::readUint64(bool *error) { + return (uint64_t) readInt64(error); +} + +int32_t NativeByteBuffer::readBigInt32(bool *error) { + if (_position + 4 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read big int32 error"); + return 0; + } + int32_t result = ((buffer[_position] & 0xff) << 24) | + ((buffer[_position + 1] & 0xff) << 16) | + ((buffer[_position + 2] & 0xff) << 8) | + ((buffer[_position + 3] & 0xff)); + _position += 4; + return result; +} + +int64_t NativeByteBuffer::readInt64(bool *error) { + if (_position + 4 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read int64 error"); + return 0; + } + int64_t result = ((int64_t) (buffer[_position] & 0xff)) | + ((int64_t) (buffer[_position + 1] & 0xff) << 8) | + ((int64_t) (buffer[_position + 2] & 0xff) << 16) | + ((int64_t) (buffer[_position + 3] & 0xff) << 24) | + ((int64_t) (buffer[_position + 4] & 0xff) << 32) | + ((int64_t) (buffer[_position + 5] & 0xff) << 40) | + ((int64_t) (buffer[_position + 6] & 0xff) << 48) | + ((int64_t) (buffer[_position + 7] & 0xff) << 56); + _position += 8; + return result; +} + +uint8_t NativeByteBuffer::readByte(bool *error) { + if (_position + 1 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read byte error"); + return 0; + } + return buffer[_position++]; +} + +bool NativeByteBuffer::readBool(bool *error) { + uint32_t consructor = readUint32(error); + if (consructor == 0x997275b5) { + return true; + } else if (consructor == 0xbc799737) { + return false; + } + if (error != nullptr) { + *error = true; + DEBUG_E("read bool error"); + } + return false; +} + +void NativeByteBuffer::readBytes(uint8_t *b, uint32_t length, bool *error) { + if (_position + length > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read bytes error"); + return; + } + memcpy(b, buffer + _position, length); + _position += length; +} + +ByteArray *NativeByteBuffer::readBytes(uint32_t length, bool *error) { + if (_position + length > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read bytes error"); + return nullptr; + } + ByteArray *byteArray = new ByteArray(length); + memcpy(byteArray->bytes, buffer + _position, sizeof(uint8_t) * length); + _position += length; + return byteArray; +} + +std::string NativeByteBuffer::readString(bool *error) { + uint32_t sl = 1; + if (_position + 1 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read string error"); + return std::string(""); + } + uint32_t l = buffer[_position++]; + if (l >= 254) { + if (_position + 3 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read string error"); + return std::string(""); + } + l = buffer[_position] | (buffer[_position + 1] << 8) | (buffer[_position + 2] << 16); + _position += 3; + sl = 4; + } + uint32_t addition = (l + sl) % 4; + if (addition != 0) { + addition = 4 - addition; + } + if (_position + l + addition > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read string error"); + return std::string(""); + } + std::string result = std::string((const char *) (buffer + _position), l); + _position += l + addition; + return result; +} + +ByteArray *NativeByteBuffer::readByteArray(bool *error) { + uint32_t sl = 1; + if (_position + 1 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read byte array error"); + return nullptr; + } + uint32_t l = buffer[_position++]; + if (l >= 254) { + if (_position + 3 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read byte array error"); + return nullptr; + } + l = buffer[_position] | (buffer[_position + 1] << 8) | (buffer[_position + 2] << 16); + _position += 3; + sl = 4; + } + uint32_t addition = (l + sl) % 4; + if (addition != 0) { + addition = 4 - addition; + } + if (_position + l + addition > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read byte array error"); + return nullptr; + } + ByteArray *result = new ByteArray(l); + memcpy(result->bytes, buffer + _position, sizeof(uint8_t) * l); + _position += l + addition; + return result; +} + +NativeByteBuffer *NativeByteBuffer::readByteBuffer(bool copy, bool *error) { + uint32_t sl = 1; + if (_position + 1 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read byte buffer error"); + return nullptr; + } + uint32_t l = buffer[_position++]; + if (l >= 254) { + if (_position + 3 > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read byte buffer error"); + return nullptr; + } + l = buffer[_position] | (buffer[_position + 1] << 8) | (buffer[_position + 2] << 16); + _position += 3; + sl = 4; + } + uint32_t addition = (l + sl) % 4; + if (addition != 0) { + addition = 4 - addition; + } + if (_position + l + addition > _limit) { + if (error != nullptr) { + *error = true; + } + DEBUG_E("read byte buffer error"); + return nullptr; + } + NativeByteBuffer *result = nullptr; + if (copy) { + result = BuffersStorage::getInstance().getFreeBuffer(l); + memcpy(result->buffer, buffer + _position, sizeof(uint8_t) * l); + } else { + result = new NativeByteBuffer(buffer + _position, l); + } + _position += l + addition; + return result; +} + +double NativeByteBuffer::readDouble(bool *error) { + double value; + int64_t value2 = readInt64(error); + memcpy(&value, &value2, sizeof(double)); + return value; +} + +void NativeByteBuffer::reuse() { + if (sliced) { + return; + } + BuffersStorage::getInstance().reuseFreeBuffer(this); +} + +#ifdef ANDROID +jobject NativeByteBuffer::getJavaByteBuffer() { + if (javaByteBuffer == nullptr && javaVm != nullptr) { + JNIEnv *env = 0; + if (javaVm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) { + DEBUG_E("can't get jnienv"); + exit(1); + } + javaByteBuffer = env->NewDirectByteBuffer(buffer, _capacity); + if (javaByteBuffer == nullptr) { + DEBUG_E("can't allocate NativeByteBuffer buffer"); + exit(1); + } + jobject globalRef = env->NewGlobalRef(javaByteBuffer); + env->DeleteLocalRef(javaByteBuffer); + javaByteBuffer = globalRef; + } + return javaByteBuffer; +} +#endif diff --git a/TMessagesProj/jni/tgnet/NativeByteBuffer.h b/TMessagesProj/jni/tgnet/NativeByteBuffer.h new file mode 100644 index 00000000..1abbbef1 --- /dev/null +++ b/TMessagesProj/jni/tgnet/NativeByteBuffer.h @@ -0,0 +1,107 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef NATIVEBYTEBUFFER_H +#define NATIVEBYTEBUFFER_H + +#include +#include + +#ifdef ANDROID +#include +#endif + +class ByteArray; + +class NativeByteBuffer { + +public: + NativeByteBuffer(uint32_t size); + NativeByteBuffer(bool calculate); + NativeByteBuffer(uint8_t *buff, uint32_t length); + ~NativeByteBuffer(); + + uint32_t position(); + void position(uint32_t position); + uint32_t limit(); + void limit(uint32_t limit); + uint32_t capacity(); + uint32_t remaining(); + bool hasRemaining(); + void rewind(); + void compact(); + void flip(); + void clear(); + void skip(uint32_t length); + void clearCapacity(); + uint8_t *bytes(); + + void writeInt32(int32_t x, bool *error); + void writeInt64(int64_t x, bool *error); + void writeBool(bool value, bool *error); + void writeBytes(uint8_t *b, uint32_t length, bool *error); + void writeBytes(uint8_t *b, uint32_t offset, uint32_t length, bool *error); + void writeBytes(ByteArray *b, bool *error); + void writeBytes(NativeByteBuffer *b, bool *error); + void writeByte(uint8_t i, bool *error); + void writeString(std::string s, bool *error); + void writeByteArray(uint8_t *b, uint32_t offset, uint32_t length, bool *error); + void writeByteArray(uint8_t *b, uint32_t length, bool *error); + void writeByteArray(NativeByteBuffer *b, bool *error); + void writeByteArray(ByteArray *b, bool *error); + void writeDouble(double d, bool *error); + void writeInt32(int32_t x); + void writeInt64(int64_t x); + void writeBool(bool value); + void writeBytes(uint8_t *b, uint32_t length); + void writeBytes(uint8_t *b, uint32_t offset, uint32_t length); + void writeBytes(ByteArray *b); + void writeBytes(NativeByteBuffer *b); + void writeByte(uint8_t i); + void writeString(std::string s); + void writeByteArray(uint8_t *b, uint32_t offset, uint32_t length); + void writeByteArray(uint8_t *b, uint32_t length); + void writeByteArray(NativeByteBuffer *b); + void writeByteArray(ByteArray *b); + void writeDouble(double d); + + uint32_t readUint32(bool *error); + uint64_t readUint64(bool *error); + int32_t readInt32(bool *error); + int32_t readBigInt32(bool *error); + int64_t readInt64(bool *error); + uint8_t readByte(bool *error); + bool readBool(bool *error); + void readBytes(uint8_t *b, uint32_t length, bool *error); + ByteArray *readBytes(uint32_t length, bool *error); + std::string readString(bool *error); + ByteArray *readByteArray(bool *error); + NativeByteBuffer *readByteBuffer(bool copy, bool *error); + double readDouble(bool *error); + + void reuse(); +#ifdef ANDROID + jobject getJavaByteBuffer(); +#endif + +private: + void writeBytesInternal(uint8_t *b, uint32_t offset, uint32_t length); + + uint8_t *buffer = nullptr; + bool calculateSizeOnly = false; + bool sliced = false; + uint32_t _position = 0; + uint32_t _limit = 0; + uint32_t _capacity = 0; + bool bufferOwner = true; +#ifdef ANDROID + jobject javaByteBuffer = nullptr; +#endif +}; + +#endif diff --git a/TMessagesProj/jni/tgnet/Request.cpp b/TMessagesProj/jni/tgnet/Request.cpp new file mode 100644 index 00000000..583e8ffe --- /dev/null +++ b/TMessagesProj/jni/tgnet/Request.cpp @@ -0,0 +1,69 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include +#include "Request.h" +#include "TLObject.h" +#include "MTProtoScheme.h" +#include "ConnectionsManager.h" + +Request::Request(int32_t token, ConnectionType type, uint32_t flags, uint32_t datacenter, onCompleteFunc completeFunc, onQuickAckFunc quickAckFunc) { + requestToken = token; + connectionType = type; + requestFlags = flags; + datacenterId = datacenter; + onCompleteRequestCallback = completeFunc; + onQuickAckCallback = quickAckFunc; +} + +Request::~Request() { +#ifdef ANDROID + if (ptr1 != nullptr) { + jniEnv->DeleteGlobalRef(ptr1); + ptr1 = nullptr; + } + if (ptr2 != nullptr) { + jniEnv->DeleteGlobalRef(ptr2); + ptr2 = nullptr; + } +#endif +} + +void Request::addRespondMessageId(int64_t id) { + respondsToMessageIds.push_back(messageId); +} + +bool Request::respondsToMessageId(int64_t id) { + return messageId == id || std::find(respondsToMessageIds.begin(), respondsToMessageIds.end(), id) != respondsToMessageIds.end(); +} + +void Request::clear(bool time) { + messageId = 0; + messageSeqNo = 0; + connectionToken = 0; + if (time) { + startTime = 0; + minStartTime = 0; + } +} + +void Request::onComplete(TLObject *result, TL_error *error) { + if (onCompleteRequestCallback != nullptr && (result != nullptr || error != nullptr)) { + onCompleteRequestCallback(result, error); + } +} + +void Request::onQuickAck() { + if (onQuickAckCallback != nullptr) { + onQuickAckCallback(); + } +} + +TLObject *Request::getRpcRequest() { + return rpcRequest.get(); +} diff --git a/TMessagesProj/jni/tgnet/Request.h b/TMessagesProj/jni/tgnet/Request.h new file mode 100644 index 00000000..5ab9a093 --- /dev/null +++ b/TMessagesProj/jni/tgnet/Request.h @@ -0,0 +1,69 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef REQUEST_H +#define REQUEST_H + +#include +#include +#include +#include "Defines.h" + +#ifdef ANDROID +#include +#endif + +class TLObject; +class TL_error; + +class Request { + +public: + Request(int32_t token, ConnectionType type, uint32_t flags, uint32_t datacenter, onCompleteFunc completeFunc, onQuickAckFunc quickAckFunc); + ~Request(); + + int64_t messageId = 0; + int32_t messageSeqNo = 0; + uint32_t datacenterId = 0; + uint32_t connectionToken = 0; + int32_t requestToken; + uint32_t retryCount = 0; + bool failedBySalt = false; + int32_t failedByFloodWait = 0; + ConnectionType connectionType; + uint32_t requestFlags; + bool completed = false; + bool cancelled = false; + bool isInitRequest = false; + int32_t serializedLength = 0; + int32_t startTime = 0; + int32_t minStartTime = 0; + int32_t lastResendTime = 0; + uint32_t serverFailureCount = 0; + TLObject *rawRequest; + std::unique_ptr rpcRequest; + onCompleteFunc onCompleteRequestCallback; + onQuickAckFunc onQuickAckCallback; + + void addRespondMessageId(int64_t id); + bool respondsToMessageId(int64_t id); + void clear(bool time); + void onComplete(TLObject *result, TL_error *error); + void onQuickAck(); + TLObject *getRpcRequest(); + +#ifdef ANDROID + jobject ptr1 = nullptr; + jobject ptr2 = nullptr; +#endif + +private: + std::vector respondsToMessageIds; +}; + +#endif diff --git a/TMessagesProj/jni/tgnet/TLObject.cpp b/TMessagesProj/jni/tgnet/TLObject.cpp new file mode 100644 index 00000000..ebb7f8f8 --- /dev/null +++ b/TMessagesProj/jni/tgnet/TLObject.cpp @@ -0,0 +1,38 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include "TLObject.h" +#include "NativeByteBuffer.h" + +thread_local NativeByteBuffer *sizeCalculatorBuffer = new NativeByteBuffer(true); + +TLObject::~TLObject() { + +} + +void TLObject::readParams(NativeByteBuffer *stream, bool &error) { + +} + +void TLObject::serializeToStream(NativeByteBuffer *stream) { + +} + +TLObject *TLObject::deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error) { + return nullptr; +} + +uint32_t TLObject::getObjectSize() { + sizeCalculatorBuffer->clearCapacity(); + serializeToStream(sizeCalculatorBuffer); + return sizeCalculatorBuffer->capacity(); +} + +bool TLObject::isNeedLayer() { + return false; +} diff --git a/TMessagesProj/jni/tgnet/TLObject.h b/TMessagesProj/jni/tgnet/TLObject.h new file mode 100644 index 00000000..58b972c6 --- /dev/null +++ b/TMessagesProj/jni/tgnet/TLObject.h @@ -0,0 +1,27 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef TLOBJECT_H +#define TLOBJECT_H + +#include + +class NativeByteBuffer; + +class TLObject { + +public: + virtual ~TLObject(); + virtual void readParams(NativeByteBuffer *stream, bool &error); + virtual void serializeToStream(NativeByteBuffer *stream); + virtual TLObject *deserializeResponse(NativeByteBuffer *stream, uint32_t constructor, bool &error); + uint32_t getObjectSize(); + virtual bool isNeedLayer(); +}; + +#endif diff --git a/TMessagesProj/jni/tgnet/Timer.cpp b/TMessagesProj/jni/tgnet/Timer.cpp new file mode 100644 index 00000000..0f905780 --- /dev/null +++ b/TMessagesProj/jni/tgnet/Timer.cpp @@ -0,0 +1,61 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#include "Timer.h" +#include "FileLog.h" +#include "EventObject.h" +#include "ConnectionsManager.h" + +Timer::Timer(std::function function) { + eventObject = new EventObject(this, EventObjectTypeTimer); + callback = function; +} + +Timer::~Timer() { + stop(); + if (eventObject != nullptr) { + delete eventObject; + eventObject = nullptr; + } +} + +void Timer::start() { + if (started || timeout == 0) { + return; + } + started = true; + ConnectionsManager::getInstance().scheduleEvent(eventObject, timeout); +} + +void Timer::stop() { + if (!started) { + return; + } + started = false; + ConnectionsManager::getInstance().removeEvent(eventObject); +} + +void Timer::setTimeout(uint32_t ms, bool repeat) { + if (ms == timeout) { + return; + } + repeatable = repeat; + timeout = ms; + if (started) { + ConnectionsManager::getInstance().removeEvent(eventObject); + ConnectionsManager::getInstance().scheduleEvent(eventObject, timeout); + } +} + +void Timer::onEvent() { + callback(); + DEBUG_D("timer(%p) call", this); + if (started && repeatable && timeout != 0) { + ConnectionsManager::getInstance().scheduleEvent(eventObject, timeout); + } +} diff --git a/TMessagesProj/jni/tgnet/Timer.h b/TMessagesProj/jni/tgnet/Timer.h new file mode 100644 index 00000000..7146cc08 --- /dev/null +++ b/TMessagesProj/jni/tgnet/Timer.h @@ -0,0 +1,40 @@ +/* + * This is the source code of tgnet library v. 1.0 + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2015. + */ + +#ifndef TIMER_H +#define TIMER_H + +#include +#include +#include + +class EventObject; + +class Timer { + +public: + Timer(std::function function); + ~Timer(); + + void start(); + void stop(); + void setTimeout(uint32_t ms, bool repeat); + +private: + void onEvent(); + + bool started = false; + bool repeatable = false; + uint32_t timeout = 0; + std::function callback; + EventObject *eventObject; + + friend class EventObject; +}; + +#endif diff --git a/TMessagesProj/src/main/AndroidManifest.xml b/TMessagesProj/src/main/AndroidManifest.xml index 057df939..387593c4 100644 --- a/TMessagesProj/src/main/AndroidManifest.xml +++ b/TMessagesProj/src/main/AndroidManifest.xml @@ -37,17 +37,23 @@ - + + + + + + + + + @@ -130,18 +138,28 @@ android:windowSoftInputMode="adjustResize|stateHidden"> - + - + + + + + + + @@ -201,6 +219,7 @@ + @@ -208,8 +227,8 @@ - + + diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_0.jpg new file mode 100644 index 00000000..fa0923f6 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_1.jpg new file mode 100644 index 00000000..ed5a5d67 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_2.jpg new file mode 100644 index 00000000..9c835601 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_3.jpg new file mode 100644 index 00000000..78637adc Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_0_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_0.jpg new file mode 100644 index 00000000..da6c51df Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_1.jpg new file mode 100644 index 00000000..454a6b2c Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_2.jpg new file mode 100644 index 00000000..5e589bd6 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_3.jpg new file mode 100644 index 00000000..5f266035 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_1_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_0.jpg new file mode 100644 index 00000000..47ac6724 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_1.jpg new file mode 100644 index 00000000..cd48e267 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_2.jpg new file mode 100644 index 00000000..01ae27b0 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_3.jpg new file mode 100644 index 00000000..1189e43b Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_2_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_0.jpg new file mode 100644 index 00000000..de71960a Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_1.jpg new file mode 100644 index 00000000..f9d3f664 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_2.jpg new file mode 100644 index 00000000..14284844 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_3.jpg new file mode 100644 index 00000000..6de0df8e Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_3_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_0.jpg new file mode 100644 index 00000000..4ed59bed Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_1.jpg new file mode 100644 index 00000000..7cd44246 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_2.jpg new file mode 100644 index 00000000..0169deb5 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_3.jpg new file mode 100644 index 00000000..2a68beec Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_4_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_0.jpg new file mode 100644 index 00000000..714e186a Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_1.jpg new file mode 100644 index 00000000..c659dad0 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_2.jpg new file mode 100644 index 00000000..1e308bdb Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_3.jpg new file mode 100644 index 00000000..ca39a7d1 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_0_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_0.jpg new file mode 100644 index 00000000..29556f69 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_1.jpg new file mode 100644 index 00000000..015563d4 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_2.jpg new file mode 100644 index 00000000..86306574 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_3.jpg new file mode 100644 index 00000000..30b5a927 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_1_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_0.jpg new file mode 100644 index 00000000..2ff8348b Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_1.jpg new file mode 100644 index 00000000..1398cf95 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_2.jpg new file mode 100644 index 00000000..d5843711 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_3.jpg new file mode 100644 index 00000000..103f7693 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_2_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_0.jpg new file mode 100644 index 00000000..0616f296 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_1.jpg new file mode 100644 index 00000000..7a6d2e3f Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_2.jpg new file mode 100644 index 00000000..bef04e68 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_3.jpg new file mode 100644 index 00000000..1ce93089 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_3_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_0.jpg new file mode 100644 index 00000000..684965e7 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_1.jpg new file mode 100644 index 00000000..eef5ec53 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_2.jpg new file mode 100644 index 00000000..6d147857 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_3.jpg new file mode 100644 index 00000000..d08f80b7 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji2.0x_a_4_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_0.jpg new file mode 100644 index 00000000..2048549a Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_1.jpg new file mode 100644 index 00000000..f712e4bb Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_2.jpg new file mode 100644 index 00000000..9225aa23 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_3.jpg new file mode 100644 index 00000000..76657809 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_0_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_0.jpg new file mode 100644 index 00000000..ba950bff Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_1.jpg new file mode 100644 index 00000000..d1266580 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_2.jpg new file mode 100644 index 00000000..c394f814 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_3.jpg new file mode 100644 index 00000000..fdfd98d7 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_1_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_0.jpg new file mode 100644 index 00000000..e19f186a Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_1.jpg new file mode 100644 index 00000000..af66cb3c Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_2.jpg new file mode 100644 index 00000000..59785974 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_3.jpg new file mode 100644 index 00000000..476c9ed3 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_2_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_0.jpg new file mode 100644 index 00000000..29758492 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_1.jpg new file mode 100644 index 00000000..c9613022 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_2.jpg new file mode 100644 index 00000000..16d5bbfd Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_3.jpg new file mode 100644 index 00000000..f6db0ff3 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_3_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_0.jpg new file mode 100644 index 00000000..59b6c198 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_1.jpg new file mode 100644 index 00000000..d285314a Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_2.jpg new file mode 100644 index 00000000..afd77513 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_3.jpg new file mode 100644 index 00000000..81468d01 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_4_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_0.jpg new file mode 100644 index 00000000..3e62257d Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_1.jpg new file mode 100644 index 00000000..6eff5418 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_2.jpg new file mode 100644 index 00000000..ff866c72 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_3.jpg new file mode 100644 index 00000000..1006fa4c Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_0_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_0.jpg new file mode 100644 index 00000000..74448ec6 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_1.jpg new file mode 100644 index 00000000..e9a64601 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_2.jpg new file mode 100644 index 00000000..f9d6c78b Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_3.jpg new file mode 100644 index 00000000..c27537c2 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_1_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_0.jpg new file mode 100644 index 00000000..c5453757 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_1.jpg new file mode 100644 index 00000000..deaf755a Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_2.jpg new file mode 100644 index 00000000..4f06199e Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_3.jpg new file mode 100644 index 00000000..aa1261b5 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_2_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_0.jpg new file mode 100644 index 00000000..ec2ce25c Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_1.jpg new file mode 100644 index 00000000..f73bfb8c Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_2.jpg new file mode 100644 index 00000000..e81151b9 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_3.jpg new file mode 100644 index 00000000..cb60b76c Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_3_3.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_0.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_0.jpg new file mode 100644 index 00000000..fb85fee4 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_0.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_1.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_1.jpg new file mode 100644 index 00000000..65f0a2bf Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_1.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_2.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_2.jpg new file mode 100644 index 00000000..b5aa9c17 Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_2.jpg differ diff --git a/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_3.jpg b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_3.jpg new file mode 100644 index 00000000..28d5ef5b Binary files /dev/null and b/TMessagesProj/src/main/assets/emoji/v7_emoji3.0x_a_4_3.jpg differ diff --git a/TMessagesProj/src/main/assets/fonts/ritalic.ttf b/TMessagesProj/src/main/assets/fonts/ritalic.ttf new file mode 100644 index 00000000..ff6046d5 Binary files /dev/null and b/TMessagesProj/src/main/assets/fonts/ritalic.ttf differ diff --git a/TMessagesProj/src/main/java/org/telegram/SQLite/DatabaseHandler.java b/TMessagesProj/src/main/java/org/telegram/SQLite/DatabaseHandler.java new file mode 100644 index 00000000..bbe88ada --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/SQLite/DatabaseHandler.java @@ -0,0 +1,121 @@ +package org.telegram.SQLite; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; + +import org.telegram.messenger.FileLog; +import org.telegram.ui.Components.Favourite; + +public class DatabaseHandler extends SQLiteOpenHelper { + + private static final int DATABASE_VERSION = 1; + private static final String DATABASE_NAME = "favourites"; + private static final String TABLE_FAVS = "tbl_favs"; + + private static final String KEY_ID = "id"; + private static final String KEY_CHAT_ID = "chat_id"; + + public DatabaseHandler(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) { + String CREATE_FAVS_TABLE = "CREATE TABLE " + TABLE_FAVS + "(" + + KEY_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + KEY_CHAT_ID + " INTEGER" + ")"; + db.execSQL(CREATE_FAVS_TABLE); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + db.execSQL("DROP TABLE IF EXISTS " + TABLE_FAVS); + onCreate(db); + } + + public void addFavourite(Favourite favourite) { + SQLiteDatabase db = this.getWritableDatabase(); + + ContentValues values = new ContentValues(); + values.put(KEY_CHAT_ID, favourite.getChatID()); + db.insert(TABLE_FAVS, null, values); + db.close(); + } + + public Favourite getFavouriteByChatId(long chat_id) { + SQLiteDatabase db = this.getReadableDatabase(); + Cursor cursor = null; + try { + + String [] projection = { + KEY_ID, + KEY_CHAT_ID + }; + + String whereClause = KEY_CHAT_ID+"=?"; + String [] whereArgs = {String.valueOf(chat_id)}; + + cursor = db.query( + TABLE_FAVS, + projection, + whereClause, + whereArgs, + null, + null, + null + ); + + if( cursor != null && cursor.moveToFirst() ){ + return new Favourite(cursor.getLong(1)); + } + } catch (Exception e) { + if(cursor != null) + cursor.close(); + FileLog.e("tmessages", e); + return null; + } finally { + if(cursor != null) + cursor.close(); + } + return null; + } + + public void deleteFavourite(Long chat_id) { + SQLiteDatabase db = this.getWritableDatabase(); + db.delete(TABLE_FAVS, KEY_CHAT_ID + " = ?", new String[] { String.valueOf(chat_id) }); + db.close(); + } + + /*public List getAllFavourites() { + List favsList = new ArrayList(); + + String selectQuery = "SELECT * FROM " + TABLE_FAVS; + + SQLiteDatabase db = this.getWritableDatabase(); + Cursor cursor = db.rawQuery(selectQuery, null); + + if (cursor.moveToFirst()) { + do { + Favourite favourite = new Favourite(); + favourite.setID(Integer.parseInt(cursor.getString(0))); + favourite.setChatID(cursor.getLong(1)); + + favsList.add(favourite); + } while (cursor.moveToNext()); + } + + return favsList; + } + + public int getFavouritesCount() { + String countQuery = "SELECT * FROM " + TABLE_FAVS; + SQLiteDatabase db = this.getReadableDatabase(); + Cursor cursor = db.rawQuery(countQuery, null); + cursor.close(); + + return cursor.getCount(); + }*/ + +} diff --git a/TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteDatabase.java b/TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteDatabase.java index c68c62db..6ab2e575 100644 --- a/TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteDatabase.java +++ b/TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteDatabase.java @@ -77,7 +77,6 @@ public class SQLiteDatabase { close(); } - private StackTraceElement[] temp; public void beginTransaction() throws SQLiteException { if (inTransaction) { throw new SQLiteException("database already in transaction"); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java new file mode 100644 index 00000000..e7005fbc --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java @@ -0,0 +1,1550 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlertDialog; +import android.content.ContentUris; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Point; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.provider.DocumentsContract; +import android.provider.MediaStore; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.ForegroundColorSpan; +import android.util.DisplayMetrics; +import android.util.StateSet; +import android.view.Display; +import android.view.Surface; +import android.view.View; +import android.view.WindowManager; +import android.view.inputmethod.InputMethodManager; +import android.widget.AbsListView; +import android.widget.EdgeEffect; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import net.hockeyapp.android.CrashManager; +import net.hockeyapp.android.CrashManagerListener; +import net.hockeyapp.android.UpdateManager; + +import org.telegram.messenger.AnimationCompat.AnimatorListenerAdapterProxy; +import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; +import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; +import org.telegram.messenger.AnimationCompat.ViewProxy; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Components.ForegroundDetector; +import org.telegram.ui.Components.NumberPicker; +import org.telegram.ui.Components.TypefaceSpan; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Hashtable; +import java.util.List; +import java.util.Locale; +import java.util.regex.Pattern; + +public class AndroidUtilities { + + private static final Hashtable typefaceCache = new Hashtable<>(); + private static int prevOrientation = -10; + private static boolean waitingForSms = false; + private static boolean waitingForCall = false; + private static final Object smsLock = new Object(); + private static final Object callLock = new Object(); + + public static int statusBarHeight = 0; + public static float density = 1; + public static Point displaySize = new Point(); + public static Integer photoSize = null; + public static DisplayMetrics displayMetrics = new DisplayMetrics(); + public static int leftBaseline; + public static boolean usingHardwareInput; + private static Boolean isTablet = null; + private static int adjustOwnerClassGuid = 0; + + public static Pattern WEB_URL = null; + + public static final String THEME_PREFS = "theme"; + public static final int THEME_PREFS_MODE = Activity.MODE_PRIVATE; + + public static final int defColor = 0xff009688;//0xff58BCD5;//0xff43C3DB;//0xff2f8cc9;58BCD5//0xff55abd2 + public static int themeColor = getIntColor("themeColor"); + + public static boolean needRestart = false; + + public static boolean themeUpdated = false; + + static long lastCheck = -1; + + static { + try { + final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF"; + final Pattern IP_ADDRESS = Pattern.compile( + "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]" + + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]" + + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}" + + "|[1-9][0-9]|[0-9]))"); + final String IRI = "[" + GOOD_IRI_CHAR + "]([" + GOOD_IRI_CHAR + "\\-]{0,61}[" + GOOD_IRI_CHAR + "]){0,1}"; + final String GOOD_GTLD_CHAR = "a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF"; + final String GTLD = "[" + GOOD_GTLD_CHAR + "]{2,63}"; + final String HOST_NAME = "(" + IRI + "\\.)+" + GTLD; + final Pattern DOMAIN_NAME = Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")"); + WEB_URL = Pattern.compile( + "((?:(http|https|Http|Https):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" + + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_" + + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?" + + "(?:" + DOMAIN_NAME + ")" + + "(?:\\:\\d{1,5})?)" // plus option port number + + "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params + + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?" + + "(?:\\b|$)"); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + + + static { + density = ApplicationLoader.applicationContext.getResources().getDisplayMetrics().density; + leftBaseline = isTablet() ? 80 : 72; + checkDisplaySize(); + } + + public static int[] calcDrawableColor(Drawable drawable) { + int bitmapColor = 0xff000000; + int result[] = new int[2]; + try { + if (drawable instanceof BitmapDrawable) { + Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); + if (bitmap != null) { + Bitmap b = Bitmaps.createScaledBitmap(bitmap, 1, 1, true); + if (b != null) { + bitmapColor = b.getPixel(0, 0); + b.recycle(); + } + } + } else if (drawable instanceof ColorDrawable) { + if (Build.VERSION.SDK_INT >= 11) { + bitmapColor = ((ColorDrawable) drawable).getColor(); + } else { + bitmapColor = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).getInt("selectedColor", 0xff000000); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + double[] hsv = rgbToHsv((bitmapColor >> 16) & 0xff, (bitmapColor >> 8) & 0xff, bitmapColor & 0xff); + hsv[1] = Math.min(1.0, hsv[1] + 0.05 + 0.1 * (1.0 - hsv[1])); + hsv[2] = Math.max(0, hsv[2] * 0.65); + int rgb[] = hsvToRgb(hsv[0], hsv[1], hsv[2]); + result[0] = Color.argb(0x66, rgb[0], rgb[1], rgb[2]); + result[1] = Color.argb(0x88, rgb[0], rgb[1], rgb[2]); + return result; + } + + private static double[] rgbToHsv(int r, int g, int b) { + double rf = r / 255.0; + double gf = g / 255.0; + double bf = b / 255.0; + double max = (rf > gf && rf > bf) ? rf : (gf > bf) ? gf : bf; + double min = (rf < gf && rf < bf) ? rf : (gf < bf) ? gf : bf; + double h, s; + double d = max - min; + s = max == 0 ? 0 : d / max; + if (max == min) { + h = 0; + } else { + if (rf > gf && rf > bf) { + h = (gf - bf) / d + (gf < bf ? 6 : 0); + } else if (gf > bf) { + h = (bf - rf) / d + 2; + } else { + h = (rf - gf) / d + 4; + } + h /= 6; + } + return new double[]{h, s, max}; + } + + private static int[] hsvToRgb(double h, double s, double v) { + double r = 0, g = 0, b = 0; + double i = (int) Math.floor(h * 6); + double f = h * 6 - i; + double p = v * (1 - s); + double q = v * (1 - f * s); + double t = v * (1 - (1 - f) * s); + switch ((int) i % 6) { + case 0: + r = v; + g = t; + b = p; + break; + case 1: + r = q; + g = v; + b = p; + break; + case 2: + r = p; + g = v; + b = t; + break; + case 3: + r = p; + g = q; + b = v; + break; + case 4: + r = t; + g = p; + b = v; + break; + case 5: + r = v; + g = p; + b = q; + break; + } + return new int[]{(int) (r * 255), (int) (g * 255), (int) (b * 255)}; + } + + public static void requestAdjustResize(Activity activity, int classGuid) { + if (activity == null || isTablet()) { + return; + } + activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + adjustOwnerClassGuid = classGuid; + } + + public static void removeAdjustResize(Activity activity, int classGuid) { + if (activity == null || isTablet()) { + return; + } + if (adjustOwnerClassGuid == classGuid) { + activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); + } + } + + public static boolean isGoogleMapsInstalled(final BaseFragment fragment) { + try { + ApplicationLoader.applicationContext.getPackageManager().getApplicationInfo("com.google.android.apps.maps", 0); + return true; + } catch (PackageManager.NameNotFoundException e) { + if (fragment.getParentActivity() == null) { + return false; + } + AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getParentActivity()); + builder.setMessage("Install Google Maps?"); + builder.setCancelable(true); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.google.android.apps.maps")); + fragment.getParentActivity().startActivityForResult(intent, 500); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + fragment.showDialog(builder.create()); + return false; + } + } + + public static void lockOrientation(Activity activity) { + if (activity == null || prevOrientation != -10) { + return; + } + try { + prevOrientation = activity.getRequestedOrientation(); + WindowManager manager = (WindowManager)activity.getSystemService(Activity.WINDOW_SERVICE); + if (manager != null && manager.getDefaultDisplay() != null) { + int rotation = manager.getDefaultDisplay().getRotation(); + int orientation = activity.getResources().getConfiguration().orientation; + + if (rotation == Surface.ROTATION_270) { + if (orientation == Configuration.ORIENTATION_PORTRAIT) { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } else { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); + } + } else if (rotation == Surface.ROTATION_90) { + if (orientation == Configuration.ORIENTATION_PORTRAIT) { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); + } else { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } + } else if (rotation == Surface.ROTATION_0) { + if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); + } else { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); + } + } else { + if (orientation == Configuration.ORIENTATION_LANDSCAPE) { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE); + } else { + activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT); + } + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public static void unlockOrientation(Activity activity) { + if (activity == null) { + return; + } + try { + if (prevOrientation != -10) { + activity.setRequestedOrientation(prevOrientation); + prevOrientation = -10; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public static Typeface getTypeface(String assetPath) { + synchronized (typefaceCache) { + if (!typefaceCache.containsKey(assetPath)) { + try { + Typeface t = Typeface.createFromAsset(ApplicationLoader.applicationContext.getAssets(), assetPath); + typefaceCache.put(assetPath, t); + } catch (Exception e) { + FileLog.e("Typefaces", "Could not get typeface '" + assetPath + "' because " + e.getMessage()); + return null; + } + } + if(ApplicationLoader.USE_DEVICE_FONT)return null; + return typefaceCache.get(assetPath); + } + } + + public static boolean isWaitingForSms() { + boolean value; + synchronized (smsLock) { + value = waitingForSms; + } + return value; + } + + public static void setWaitingForSms(boolean value) { + synchronized (smsLock) { + waitingForSms = value; + } + } + + public static boolean isWaitingForCall() { + boolean value; + synchronized (callLock) { + value = waitingForCall; + } + return value; + } + + public static void setWaitingForCall(boolean value) { + synchronized (callLock) { + waitingForCall = value; + } + } + + public static void showKeyboard(View view) { + if (view == null) { + return; + } + InputMethodManager inputManager = (InputMethodManager)view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + inputManager.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT); + } + + public static boolean isKeyboardShowed(View view) { + if (view == null) { + return false; + } + InputMethodManager inputManager = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + return inputManager.isActive(view); + } + + public static void hideKeyboard(View view) { + if (view == null) { + return; + } + InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + if (!imm.isActive()) { + return; + } + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + + public static File getCacheDir() { + String state = null; + try { + state = Environment.getExternalStorageState(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (state == null || state.startsWith(Environment.MEDIA_MOUNTED)) { + try { + File file = ApplicationLoader.applicationContext.getExternalCacheDir(); + if (file != null) { + return file; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + try { + File file = ApplicationLoader.applicationContext.getCacheDir(); + if (file != null) { + return file; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return new File(""); + } + + public static int dp(float value) { + if (value == 0) { + return 0; + } + return (int) Math.ceil(density * value); + } + + public static int compare(int lhs, int rhs) { + if (lhs == rhs) { + return 0; + } else if (lhs > rhs) { + return 1; + } + return -1; + } + + public static float dpf2(float value) { + if (value == 0) { + return 0; + } + return density * value; + } + + public static void checkDisplaySize() { + try { + Configuration configuration = ApplicationLoader.applicationContext.getResources().getConfiguration(); + usingHardwareInput = configuration.keyboard != Configuration.KEYBOARD_NOKEYS && configuration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO; + WindowManager manager = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); + if (manager != null) { + Display display = manager.getDefaultDisplay(); + if (display != null) { + display.getMetrics(displayMetrics); + if (android.os.Build.VERSION.SDK_INT < 13) { + displaySize.set(display.getWidth(), display.getHeight()); + } else { + display.getSize(displaySize); + } + FileLog.e("tmessages", "display size = " + displaySize.x + " " + displaySize.y + " " + displayMetrics.xdpi + "x" + displayMetrics.ydpi); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public static float getPixelsInCM(float cm, boolean isX) { + return (cm / 2.54f) * (isX ? displayMetrics.xdpi : displayMetrics.ydpi); + } + + public static long makeBroadcastId(int id) { + return 0x0000000100000000L | ((long)id & 0x00000000FFFFFFFFL); + } + + public static int getMyLayerVersion(int layer) { + return layer & 0xffff; + } + + public static int getPeerLayerVersion(int layer) { + return (layer >> 16) & 0xffff; + } + + public static int setMyLayerVersion(int layer, int version) { + return layer & 0xffff0000 | version; + } + + public static int setPeerLayerVersion(int layer, int version) { + return layer & 0x0000ffff | (version << 16); + } + + public static void runOnUIThread(Runnable runnable) { + runOnUIThread(runnable, 0); + } + + public static void runOnUIThread(Runnable runnable, long delay) { + if (delay == 0) { + ApplicationLoader.applicationHandler.post(runnable); + } else { + ApplicationLoader.applicationHandler.postDelayed(runnable, delay); + } + } + + public static void cancelRunOnUIThread(Runnable runnable) { + ApplicationLoader.applicationHandler.removeCallbacks(runnable); + } + + public static boolean isTablet() { + if (isTablet == null) { + isTablet = ApplicationLoader.applicationContext.getResources().getBoolean(R.bool.isTablet); + } + return isTablet; + } + + public static boolean isSmallTablet() { + float minSide = Math.min(displaySize.x, displaySize.y) / density; + return minSide <= 700; + } + + public static int getMinTabletSide() { + if (!isSmallTablet()) { + int smallSide = Math.min(displaySize.x, displaySize.y); + int leftSide = smallSide * 35 / 100; + if (leftSide < dp(320)) { + leftSide = dp(320); + } + return smallSide - leftSide; + } else { + int smallSide = Math.min(displaySize.x, displaySize.y); + int maxSide = Math.max(displaySize.x, displaySize.y); + int leftSide = maxSide * 35 / 100; + if (leftSide < dp(320)) { + leftSide = dp(320); + } + return Math.min(smallSide, maxSide - leftSide); + } + } + + public static int getPhotoSize() { + if (photoSize == null) { + if (Build.VERSION.SDK_INT >= 16) { + photoSize = 1280; + } else { + photoSize = 800; + } + } + return photoSize; + } + + public static String formatTTLString(int ttl) { + if (ttl < 60) { + return LocaleController.formatPluralString("Seconds", ttl); + } else if (ttl < 60 * 60) { + return LocaleController.formatPluralString("Minutes", ttl / 60); + } else if (ttl < 60 * 60 * 24) { + return LocaleController.formatPluralString("Hours", ttl / 60 / 60); + } else if (ttl < 60 * 60 * 24 * 7) { + return LocaleController.formatPluralString("Days", ttl / 60 / 60 / 24); + } else { + int days = ttl / 60 / 60 / 24; + if (ttl % 7 == 0) { + return LocaleController.formatPluralString("Weeks", days / 7); + } else { + return String.format("%s %s", LocaleController.formatPluralString("Weeks", days / 7), LocaleController.formatPluralString("Days", days % 7)); + } + } + } + + public static AlertDialog.Builder buildTTLAlert(final Context context, final TLRPC.EncryptedChat encryptedChat) { + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(LocaleController.getString("MessageLifetime", R.string.MessageLifetime)); + final NumberPicker numberPicker = new NumberPicker(context); + numberPicker.setMinValue(0); + numberPicker.setMaxValue(20); + if (encryptedChat.ttl > 0 && encryptedChat.ttl < 16) { + numberPicker.setValue(encryptedChat.ttl); + } else if (encryptedChat.ttl == 30) { + numberPicker.setValue(16); + } else if (encryptedChat.ttl == 60) { + numberPicker.setValue(17); + } else if (encryptedChat.ttl == 60 * 60) { + numberPicker.setValue(18); + } else if (encryptedChat.ttl == 60 * 60 * 24) { + numberPicker.setValue(19); + } else if (encryptedChat.ttl == 60 * 60 * 24 * 7) { + numberPicker.setValue(20); + } else if (encryptedChat.ttl == 0) { + numberPicker.setValue(0); + } + numberPicker.setFormatter(new NumberPicker.Formatter() { + @Override + public String format(int value) { + if (value == 0) { + return LocaleController.getString("ShortMessageLifetimeForever", R.string.ShortMessageLifetimeForever); + } else if (value >= 1 && value < 16) { + return AndroidUtilities.formatTTLString(value); + } else if (value == 16) { + return AndroidUtilities.formatTTLString(30); + } else if (value == 17) { + return AndroidUtilities.formatTTLString(60); + } else if (value == 18) { + return AndroidUtilities.formatTTLString(60 * 60); + } else if (value == 19) { + return AndroidUtilities.formatTTLString(60 * 60 * 24); + } else if (value == 20) { + return AndroidUtilities.formatTTLString(60 * 60 * 24 * 7); + } + return ""; + } + }); + builder.setView(numberPicker); + builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + int oldValue = encryptedChat.ttl; + which = numberPicker.getValue(); + if (which >= 0 && which < 16) { + encryptedChat.ttl = which; + } else if (which == 16) { + encryptedChat.ttl = 30; + } else if (which == 17) { + encryptedChat.ttl = 60; + } else if (which == 18) { + encryptedChat.ttl = 60 * 60; + } else if (which == 19) { + encryptedChat.ttl = 60 * 60 * 24; + } else if (which == 20) { + encryptedChat.ttl = 60 * 60 * 24 * 7; + } + if (oldValue != encryptedChat.ttl) { + SecretChatHelper.getInstance().sendTTLMessage(encryptedChat, null); + MessagesStorage.getInstance().updateEncryptedChatTTL(encryptedChat); + } + } + }); + return builder; + } + + public static void clearCursorDrawable(EditText editText) { + if (editText == null || Build.VERSION.SDK_INT < 12) { + return; + } + try { + Field mCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes"); + mCursorDrawableRes.setAccessible(true); + mCursorDrawableRes.setInt(editText, 0); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + /*public static void setCursorDrawableColor(EditText editText, int color) { + try { + Field fCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes"); + fCursorDrawableRes.setAccessible(true); + int mCursorDrawableRes = fCursorDrawableRes.getInt(editText); + Field fEditor = TextView.class.getDeclaredField("mEditor"); + fEditor.setAccessible(true); + Object editor = fEditor.get(editText); + Class clazz = editor.getClass(); + Field fCursorDrawable = clazz.getDeclaredField("mCursorDrawable"); + fCursorDrawable.setAccessible(true); + Drawable[] drawables = new Drawable[2]; + drawables[0] = editText.getContext().getResources().getDrawable(mCursorDrawableRes); + drawables[1] = editText.getContext().getResources().getDrawable(mCursorDrawableRes); + drawables[0].setColorFilter(color, PorterDuff.Mode.SRC_IN); + drawables[1].setColorFilter(color, PorterDuff.Mode.SRC_IN); + fCursorDrawable.set(editor, drawables); + } catch (Throwable ignored) { + } + }*/ + + public static void setProgressBarAnimationDuration(ProgressBar progressBar, int duration) { + if (progressBar == null) { + return; + } + try { + Field mCursorDrawableRes = ProgressBar.class.getDeclaredField("mDuration"); + mCursorDrawableRes.setAccessible(true); + mCursorDrawableRes.setInt(progressBar, duration); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public static int getViewInset(View view) { + if (view == null || Build.VERSION.SDK_INT < 21 || view.getHeight() == AndroidUtilities.displaySize.y || view.getHeight() == AndroidUtilities.displaySize.y - statusBarHeight) { + return 0; + } + try { + Field mAttachInfoField = View.class.getDeclaredField("mAttachInfo"); + mAttachInfoField.setAccessible(true); + Object mAttachInfo = mAttachInfoField.get(view); + if (mAttachInfo != null) { + Field mStableInsetsField = mAttachInfo.getClass().getDeclaredField("mStableInsets"); + mStableInsetsField.setAccessible(true); + Rect insets = (Rect)mStableInsetsField.get(mAttachInfo); + return insets.bottom; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return 0; + } + + public static Point getRealScreenSize() { + Point size = new Point(); + try { + WindowManager windowManager = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + windowManager.getDefaultDisplay().getRealSize(size); + } else { + try { + Method mGetRawW = Display.class.getMethod("getRawWidth"); + Method mGetRawH = Display.class.getMethod("getRawHeight"); + size.set((Integer) mGetRawW.invoke(windowManager.getDefaultDisplay()), (Integer) mGetRawH.invoke(windowManager.getDefaultDisplay())); + } catch (Exception e) { + size.set(windowManager.getDefaultDisplay().getWidth(), windowManager.getDefaultDisplay().getHeight()); + FileLog.e("tmessages", e); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return size; + } + + public static void setListViewEdgeEffectColor(AbsListView listView, int color) { + if (Build.VERSION.SDK_INT >= 21) { + try { + Field field = AbsListView.class.getDeclaredField("mEdgeGlowTop"); + field.setAccessible(true); + EdgeEffect mEdgeGlowTop = (EdgeEffect) field.get(listView); + if (mEdgeGlowTop != null) { + mEdgeGlowTop.setColor(color); + } + + field = AbsListView.class.getDeclaredField("mEdgeGlowBottom"); + field.setAccessible(true); + EdgeEffect mEdgeGlowBottom = (EdgeEffect) field.get(listView); + if (mEdgeGlowBottom != null) { + mEdgeGlowBottom.setColor(color); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + @SuppressLint("NewApi") + public static void clearDrawableAnimation(View view) { + if (Build.VERSION.SDK_INT < 21 || view == null) { + return; + } + Drawable drawable; + if (view instanceof ListView) { + drawable = ((ListView) view).getSelector(); + if (drawable != null) { + drawable.setState(StateSet.NOTHING); + } + } else { + drawable = view.getBackground(); + if (drawable != null) { + drawable.setState(StateSet.NOTHING); + drawable.jumpToCurrentState(); + } + } + } + + public static final int FLAG_TAG_BR = 1; + public static final int FLAG_TAG_BOLD = 2; + public static final int FLAG_TAG_COLOR = 4; + public static final int FLAG_TAG_ALL = FLAG_TAG_BR | FLAG_TAG_BOLD | FLAG_TAG_COLOR; + + public static SpannableStringBuilder replaceTags(String str) { + return replaceTags(str, FLAG_TAG_ALL); + } + + public static SpannableStringBuilder replaceTags(String str, int flag) { + try { + int start; + int end; + StringBuilder stringBuilder = new StringBuilder(str); + if ((flag & FLAG_TAG_BR) != 0) { + while ((start = stringBuilder.indexOf("
")) != -1) { + stringBuilder.replace(start, start + 4, "\n"); + } + while ((start = stringBuilder.indexOf("
")) != -1) { + stringBuilder.replace(start, start + 5, "\n"); + } + } + ArrayList bolds = new ArrayList<>(); + if ((flag & FLAG_TAG_BOLD) != 0) { + while ((start = stringBuilder.indexOf("")) != -1) { + stringBuilder.replace(start, start + 3, ""); + end = stringBuilder.indexOf(""); + if (end == -1) { + end = stringBuilder.indexOf(""); + } + stringBuilder.replace(end, end + 4, ""); + bolds.add(start); + bolds.add(end); + } + } + ArrayList colors = new ArrayList<>(); + if ((flag & FLAG_TAG_COLOR) != 0) { + while ((start = stringBuilder.indexOf("", start); + int color = Color.parseColor(stringBuilder.substring(start, end)); + stringBuilder.replace(start, end + 1, ""); + end = stringBuilder.indexOf(""); + stringBuilder.replace(end, end + 4, ""); + colors.add(start); + colors.add(end); + colors.add(color); + } + } + SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder(stringBuilder); + for (int a = 0; a < bolds.size() / 2; a++) { + spannableStringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), bolds.get(a * 2), bolds.get(a * 2 + 1), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + for (int a = 0; a < colors.size() / 3; a++) { + spannableStringBuilder.setSpan(new ForegroundColorSpan(colors.get(a * 3 + 2)), colors.get(a * 3), colors.get(a * 3 + 1), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + return spannableStringBuilder; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return new SpannableStringBuilder(str); + } + + public static boolean needShowPasscode(boolean reset) { + boolean wasInBackground; + if (Build.VERSION.SDK_INT >= 14) { + wasInBackground = ForegroundDetector.getInstance().isWasInBackground(reset); + if (reset) { + ForegroundDetector.getInstance().resetBackgroundVar(); + } + } else { + wasInBackground = UserConfig.lastPauseTime != 0; + } + return UserConfig.passcodeHash.length() > 0 && wasInBackground && + (UserConfig.appLocked || UserConfig.autoLockIn != 0 && UserConfig.lastPauseTime != 0 && !UserConfig.appLocked && (UserConfig.lastPauseTime + UserConfig.autoLockIn) <= ConnectionsManager.getInstance().getCurrentTime()); + } + + public static void shakeView(final View view, final float x, final int num) { + if (num == 6) { + ViewProxy.setTranslationX(view, 0); + view.clearAnimation(); + return; + } + AnimatorSetProxy animatorSetProxy = new AnimatorSetProxy(); + animatorSetProxy.playTogether(ObjectAnimatorProxy.ofFloat(view, "translationX", AndroidUtilities.dp(x))); + animatorSetProxy.setDuration(50); + animatorSetProxy.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + shakeView(view, num == 5 ? 0 : -x, num + 1); + } + }); + animatorSetProxy.start(); + } + + + + /*public static String ellipsize(String text, int maxLines, int maxWidth, TextPaint paint) { + if (text == null || paint == null) { + return null; + } + int count; + int offset = 0; + StringBuilder result = null; + TextView + for (int a = 0; a < maxLines; a++) { + count = paint.breakText(text, true, maxWidth, null); + if (a != maxLines - 1) { + if (result == null) { + result = new StringBuilder(count * maxLines + 1); + } + boolean foundSpace = false; + for (int c = count - 1; c >= offset; c--) { + if (text.charAt(c) == ' ') { + foundSpace = true; + result.append(text.substring(offset, c - 1)); + offset = c - 1; + } + } + if (!foundSpace) { + offset = count; + } + text = text.substring(0, offset); + } else if (maxLines == 1) { + return text.substring(0, count); + } else { + result.append(text.substring(0, count)); + } + } + return result.toString(); + }*/ + + /*public static void turnOffHardwareAcceleration(Window window) { + if (window == null || Build.MODEL == null || Build.VERSION.SDK_INT < 11) { + return; + } + if (Build.MODEL.contains("GT-S5301") || + Build.MODEL.contains("GT-S5303") || + Build.MODEL.contains("GT-B5330") || + Build.MODEL.contains("GT-S5302") || + Build.MODEL.contains("GT-S6012B") || + Build.MODEL.contains("MegaFon_SP-AI")) { + window.clearFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED); + } + }*/ + + public static void checkForCrashes(Activity context) { + CrashManager.register(context, BuildVars.DEBUG_VERSION ? BuildVars.HOCKEY_APP_HASH_DEBUG : BuildVars.HOCKEY_APP_HASH, new CrashManagerListener() { + @Override + public boolean includeDeviceData() { + return true; + } + }); + } + + public static void checkForUpdates(Activity context) { + if (BuildVars.DEBUG_VERSION) { + UpdateManager.register(context, BuildVars.DEBUG_VERSION ? BuildVars.HOCKEY_APP_HASH_DEBUG : BuildVars.HOCKEY_APP_HASH); + } + } + + public static void unregisterUpdates() { + if (BuildVars.DEBUG_VERSION) { + UpdateManager.unregister(); + } + } + + public static void addMediaToGallery(String fromPath) { + if (fromPath == null) { + return; + } + File f = new File(fromPath); + Uri contentUri = Uri.fromFile(f); + addMediaToGallery(contentUri); + } + + public static void addMediaToGallery(Uri uri) { + if (uri == null) { + return; + } + try { + Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); + mediaScanIntent.setData(uri); + ApplicationLoader.applicationContext.sendBroadcast(mediaScanIntent); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + private static File getAlbumDir() { + if (Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + return FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE); + } + File storageDir = null; + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { + storageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "Telegram"); + if (!storageDir.mkdirs()) { + if (!storageDir.exists()){ + FileLog.d("tmessages", "failed to create directory"); + return null; + } + } + } else { + FileLog.d("tmessages", "External storage is not mounted READ/WRITE."); + } + + return storageDir; + } + + @SuppressLint("NewApi") + public static String getPath(final Uri uri) { + try { + final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; + if (isKitKat && DocumentsContract.isDocumentUri(ApplicationLoader.applicationContext, uri)) { + if (isExternalStorageDocument(uri)) { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + if ("primary".equalsIgnoreCase(type)) { + return Environment.getExternalStorageDirectory() + "/" + split[1]; + } + } else if (isDownloadsDocument(uri)) { + final String id = DocumentsContract.getDocumentId(uri); + final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); + return getDataColumn(ApplicationLoader.applicationContext, contentUri, null, null); + } else if (isMediaDocument(uri)) { + final String docId = DocumentsContract.getDocumentId(uri); + final String[] split = docId.split(":"); + final String type = split[0]; + + Uri contentUri = null; + switch (type) { + case "image": + contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; + break; + case "video": + contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; + break; + case "audio": + contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; + break; + } + + final String selection = "_id=?"; + final String[] selectionArgs = new String[] { + split[1] + }; + + return getDataColumn(ApplicationLoader.applicationContext, contentUri, selection, selectionArgs); + } + } else if ("content".equalsIgnoreCase(uri.getScheme())) { + return getDataColumn(ApplicationLoader.applicationContext, uri, null, null); + } else if ("file".equalsIgnoreCase(uri.getScheme())) { + return uri.getPath(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return null; + } + + public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) { + + Cursor cursor = null; + final String column = "_data"; + final String[] projection = { + column + }; + + try { + cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); + if (cursor != null && cursor.moveToFirst()) { + final int column_index = cursor.getColumnIndexOrThrow(column); + String value = cursor.getString(column_index); + if (value.startsWith("content://") || !value.startsWith("/") && !value.startsWith("file://")) { + return null; + } + return value; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (cursor != null) { + cursor.close(); + } + } + return null; + } + + public static boolean isExternalStorageDocument(Uri uri) { + return "com.android.externalstorage.documents".equals(uri.getAuthority()); + } + + public static boolean isDownloadsDocument(Uri uri) { + return "com.android.providers.downloads.documents".equals(uri.getAuthority()); + } + + public static boolean isMediaDocument(Uri uri) { + return "com.android.providers.media.documents".equals(uri.getAuthority()); + } + + public static File generatePicturePath() { + try { + File storageDir = getAlbumDir(); + String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date()); + return new File(storageDir, "IMG_" + timeStamp + ".jpg"); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return null; + } + + public static CharSequence generateSearchName(String name, String name2, String q) { + if (name == null && name2 == null) { + return ""; + } + SpannableStringBuilder builder = new SpannableStringBuilder(); + String wholeString = name; + if (wholeString == null || wholeString.length() == 0) { + wholeString = name2; + } else if (name2 != null && name2.length() != 0) { + wholeString += " " + name2; + } + wholeString = wholeString.trim(); + String lower = " " + wholeString.toLowerCase(); + //String hexDarkColor = String.format("#%08X", (0xFFFFFFFF & AndroidUtilities.getIntDarkerColor("chatsNameColor", -0x40)));/*Search Name*/ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int darkColor = AndroidUtilities.getIntDarkerColor("themeColor", -0x40); + int hColor = themePrefs.getInt("chatsHighlightSearchColor", darkColor); + String hexDarkColor = String.format("#%08X", (0xFFFFFFFF & hColor)); + int index; + int lastIndex = 0; + while ((index = lower.indexOf(" " + q, lastIndex)) != -1) { + int idx = index - (index == 0 ? 0 : 1); + int end = q.length() + (index == 0 ? 0 : 1) + idx; + + if (lastIndex != 0 && lastIndex != idx + 1) { + builder.append(wholeString.substring(lastIndex, idx)); + } else if (lastIndex == 0 && idx != 0) { + builder.append(wholeString.substring(0, idx)); + } + + String query = wholeString.substring(idx, end); + if (query.startsWith(" ")) { + builder.append(" "); + } + query = query.trim(); + //builder.append(AndroidUtilities.replaceTags("" + query + "")); + builder.append(AndroidUtilities.replaceTags("" + query + "")); + + lastIndex = end; + } + + if (lastIndex != -1 && lastIndex != wholeString.length()) { + builder.append(wholeString.substring(lastIndex, wholeString.length())); + } + + return builder; + } + + public static File generateVideoPath() { + try { + File storageDir = getAlbumDir(); + String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date()); + return new File(storageDir, "VID_" + timeStamp + ".mp4"); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return null; + } + + public static String formatFileSize(long size) { + if (size < 1024) { + return String.format("%d B", size); + } else if (size < 1024 * 1024) { + return String.format("%.1f KB", size / 1024.0f); + } else if (size < 1024 * 1024 * 1024) { + return String.format("%.1f MB", size / 1024.0f / 1024.0f); + } else { + return String.format("%.1f GB", size / 1024.0f / 1024.0f / 1024.0f); + } + } + + public static byte[] decodeQuotedPrintable(final byte[] bytes) { + if (bytes == null) { + return null; + } + final ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + for (int i = 0; i < bytes.length; i++) { + final int b = bytes[i]; + if (b == '=') { + try { + final int u = Character.digit((char) bytes[++i], 16); + final int l = Character.digit((char) bytes[++i], 16); + buffer.write((char) ((u << 4) + l)); + } catch (Exception e) { + FileLog.e("tmessages", e); + return null; + } + } else { + buffer.write(b); + } + } + byte[] array = buffer.toByteArray(); + try { + buffer.close(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return array; + } + + public static boolean copyFile(InputStream sourceFile, File destFile) throws IOException { + OutputStream out = new FileOutputStream(destFile); + byte[] buf = new byte[4096]; + int len; + while ((len = sourceFile.read(buf)) > 0) { + Thread.yield(); + out.write(buf, 0, len); + } + out.close(); + return true; + } + + public static boolean copyFile(File sourceFile, File destFile) throws IOException { + if (!destFile.exists()) { + destFile.createNewFile(); + } + FileInputStream source = null; + FileOutputStream destination = null; + try { + source = new FileInputStream(sourceFile); + destination = new FileOutputStream(destFile); + destination.getChannel().transferFrom(source.getChannel(), 0, source.getChannel().size()); + } catch (Exception e) { + FileLog.e("tmessages", e); + return false; + } finally { + if (source != null) { + source.close(); + } + if (destination != null) { + destination.close(); + } + } + return true; + } + + public static byte[] calcAuthKeyHash(byte[] auth_key) { + byte[] sha1 = Utilities.computeSHA1(auth_key); + byte[] key_hash = new byte[16]; + System.arraycopy(sha1, 0, key_hash, 0, 16); + return key_hash; + } + + //PLUS + + public static void brandGlowEffect(Context context, int brandColor) { + //glow + int glowDrawableId = context.getResources().getIdentifier("overscroll_glow", "drawable", "android"); + Drawable androidGlow = context.getResources().getDrawable(glowDrawableId); + androidGlow.setColorFilter(brandColor, PorterDuff.Mode.SRC_IN); + //edge + int edgeDrawableId = context.getResources().getIdentifier("overscroll_edge", "drawable", "android"); + Drawable androidEdge = context.getResources().getDrawable(edgeDrawableId); + androidEdge.setColorFilter(brandColor, PorterDuff.Mode.SRC_IN); + } + + public static int getIntColor(String key){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(THEME_PREFS, THEME_PREFS_MODE); + return themePrefs.getInt(key, defColor);//Def color is Teal + } + + public static int getIntTColor(String key){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(THEME_PREFS, THEME_PREFS_MODE); + int def = themePrefs.getInt("themeColor", defColor); + return themePrefs.getInt(key, def);//Def color is theme color + } + + public static int getIntDef(String key, int def){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(THEME_PREFS, THEME_PREFS_MODE); + return themePrefs.getInt(key, def); + } + + public static int getIntAlphaColor(String key, int def, float factor){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(THEME_PREFS, THEME_PREFS_MODE); + int color = themePrefs.getInt(key, def); + int alpha = Math.round(Color.alpha(color) * factor); + int red = Color.red(color); + int green = Color.green(color); + int blue = Color.blue(color); + return Color.argb(alpha, red, green, blue); + } + + public static int getIntDarkerColor(String key, int factor){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(THEME_PREFS, THEME_PREFS_MODE); + int color = themePrefs.getInt(key, defColor); + return setDarkColor(color, factor); + } + + public static int setDarkColor(int color, int factor){ + int alpha = Color.alpha(color); + int red = Color.red(color) - factor; + int green = Color.green(color) - factor; + int blue = Color.blue(color) - factor; + if(factor < 0){ + red = (red > 0xff) ? 0xff : red; + green = (green > 0xff) ? 0xff : green; + blue = (blue > 0xff) ? 0xff : blue; + if(red == 0xff && green == 0xff && blue == 0xff){ + red = factor; + green = factor; + blue = factor; + } + } + if(factor > 0){ + red = (red < 0) ? 0 : red; + green = (green < 0) ? 0 : green; + blue = (blue < 0) ? 0 : blue; + if(red == 0 && green == 0 && blue == 0){ + red = factor; + green = factor; + blue = factor; + } + } + //return Color.argb(0xff, red, green, blue); + return Color.argb(alpha, red, green, blue); + } + //Same as setDarkColor but maintains alpha + /*public static int setDarkWithAlphaColor(int color, int factor){ + int alpha = Color.alpha(color); + int red = Color.red(color) - factor; + int green = Color.green(color) - factor; + int blue = Color.blue(color) - factor; + if(factor < 0){ + red = (red > 0xff) ? 0xff : red; + green = (green > 0xff) ? 0xff : green; + blue = (blue > 0xff) ? 0xff : blue; + if(red == 0xff && green == 0xff && blue == 0xff){ + red = factor; + green = factor; + blue = factor; + } + } + if(factor > 0){ + red = (red < 0) ? 0 : red; + green = (green < 0) ? 0 : green; + blue = (blue < 0) ? 0 : blue; + if(red == 0 && green == 0 && blue == 0){ + red = factor; + green = factor; + blue = factor; + } + } + return Color.argb(alpha, red, green, blue); + } + + public static void setIntColor(String key, int value){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(THEME_PREFS, THEME_PREFS_MODE); + SharedPreferences.Editor e = themePrefs.edit(); + e.putInt(key, value); + e.commit(); + } + + public static void setBoolPref(Context context, String key, Boolean b){ + SharedPreferences sharedPref = context.getSharedPreferences(THEME_PREFS, 0); + SharedPreferences.Editor e = sharedPref.edit(); + e.putBoolean(key, b); + e.commit(); + }*/ + + public static void setStringPref(Context context, String key, String s){ + SharedPreferences sharedPref = context.getSharedPreferences(THEME_PREFS, 0); + SharedPreferences.Editor e = sharedPref.edit(); + e.putString(key, s); + e.commit(); + } + + public static boolean getBoolPref(String key){ + boolean s = false; + if (ApplicationLoader.applicationContext.getSharedPreferences(THEME_PREFS, 0).getBoolean(key, false)) s=true; + return s; + } + + public static boolean getBoolMain(String key){ + boolean s = false; + if (ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).getBoolean(key, false)) s=true; + return s; + } +/* + public static int getIntPref(Context context,String key){ + int i=0; + if(key.contains("picker")){ + int intColor = context.getSharedPreferences(THEME_PREFS, 0).getInt(key, Color.WHITE ); + i=intColor; + } + return i; + } + + public static int getIntColorDef(Context context, String key, int def){ + int i=def; + if(context.getSharedPreferences(THEME_PREFS, 0).getBoolean(key, false)){ + i = context.getSharedPreferences(THEME_PREFS, 0).getInt(key.replace("_check", "_picker"), def); + } + return i; + } + + public static void setTVTextColor(Context ctx, TextView tv, String key, int def){ + if(tv==null)return; + if(getBoolPref(ctx, key)) + def = getIntPref(ctx, key.replace("_check", "_picker")); + tv.setTextColor(def); + } + + public static int getSizePref(Context context,String key, int def){ + if(key.contains("picker"))return context.getSharedPreferences(THEME_PREFS, 0).getInt(key, def); + return def; + } + + public static void paintActionBarHeader(Activity a, ActionBar ab, String hdCheck, String gdMode){ + if(ab==null)return; + ab.setBackgroundDrawable(new ColorDrawable(Color.parseColor("#54759E"))); + if(getBoolPref(a, hdCheck)){ + int i = getIntPref(a, hdCheck.replace("_check", "_picker")); + Drawable d = new ColorDrawable(i); + try{ + ab.setBackgroundDrawable(d); + d = paintGradient(a,i,gdMode.replace("mode","color_picker"),gdMode); + if(d!=null)ab.setBackgroundDrawable(d); + } catch (Exception e) { + Log.e(TAG, e.toString()); + } + } + } + + public static Drawable paintGradient(Context c, int mainColor, String gColor, String g){ + GradientDrawable gd = null; + int[] a ={mainColor,getIntPref(c,gColor)}; + int gType = Integer.parseInt(c.getSharedPreferences(THEME_PREFS, 0).getString(g, "0")); + if(gType==2) gd = new GradientDrawable(GradientDrawable.Orientation.LEFT_RIGHT,a); + if(gType==1) gd = new GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM ,a); + return gd; + } + + public static Drawable paintDrawable(Context c, int resId, int resIdW, String color){ + Drawable d = c.getResources().getDrawable(resId); + if(color.contains("_check")){ + if(getBoolPref(color)){ + d = c.getResources().getDrawable(resIdW); + d.setColorFilter(getIntPref(c, color.replace("_check", "_picker")), PorterDuff.Mode.MULTIPLY); + } + } + return d; + }*/ + + public static int getDefBubbleColor(){ + int color = 0xffb2dfdb;//0xff80cbc4; + if(getIntColor("themeColor") != 0xff009688){ + color = AndroidUtilities.getIntDarkerColor("themeColor", -0x50); + } + return color; + } + + public static void checkForThemes(final Activity context) { + //if (!BuildConfig.DEBUG) { + //} + try { + long myDelay = (30L * 24L * 60L * 60L * 1000L); + String packageName = "es.rafalense.themes"; + if(BuildConfig.DEBUG)packageName = "es.rafalense.themes.beta"; + Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName); + if(intent != null){ + return; + } else { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + //long last = preferences.getLong("lastTimeActionDone", 0); + //Log.e("checkForThemes0", ":lastCheck:" + lastCheck); + //Log.e("checkForThemes0", System.currentTimeMillis() - lastCheck + ":" + myDelay); + if (lastCheck < 0 || ( System.currentTimeMillis() - lastCheck < myDelay && lastCheck > 0 ) ) { + //lastCheck++; + lastCheck = preferences.getLong("lastTime", 0); + //Log.e("checkForThemes1", ":lastCheck:" + lastCheck); + return; + } else { + SharedPreferences.Editor editor = preferences.edit(); + editor.putLong("lastTime", System.currentTimeMillis()); + editor.apply(); + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(LocaleController.getString("Themes", R.string.Themes)); + builder.setMessage(LocaleController.getString("ThemesAppMsg", R.string.ThemesAppMsg)); + final String pck = packageName; + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try{ + Intent in = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + pck)); + if (BuildConfig.DEBUG)in = new Intent(Intent.ACTION_VIEW, Uri.parse("https://rink.hockeyapp.net/apps/b5860b775ca122d3335685f39917e68f")); + context.startActivityForResult(in, 503); + } catch (Exception e) { + Intent in = new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=es.rafalense.themes")); + context.startActivityForResult(in, 503); + FileLog.e("tmessages", e); + } + } + }); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.create().show(); + lastCheck = preferences.getLong("lastTime", 0); + //Log.e("checkForThemes2", ":lastCheck:" + lastCheck); + } + } + + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + +/* + static void modifyXMLfile(File preffile,String sname){ + try { + File file = preffile; + //Log.e("modifyXMLfile",preffile.getAbsolutePath()); + //Log.e("modifyXMLfile",preffile.exists()+""); + List lines = new ArrayList(); + // first, read the file and store the changes + BufferedReader in = new BufferedReader(new FileReader(file)); + String line = in.readLine(); + while (line != null) { + if (!line.contains(sname))lines.add(line); + //Log.e("modifyXMLfile",line); + line = in.readLine(); + } + in.close(); + // now, write the file again with the changes + PrintWriter out = new PrintWriter(file); + for (String l : lines) + out.println(l); + out.close(); + } catch (Exception e) { + e.printStackTrace(); + } + }*/ +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/Animator10.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/Animator10.java new file mode 100644 index 00000000..6defed84 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/Animator10.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.Animation; + +import android.view.animation.Interpolator; + +import java.util.ArrayList; + +public abstract class Animator10 implements Cloneable { + + ArrayList mListeners = null; + ArrayList mPauseListeners = null; + boolean mPaused = false; + + public abstract long getStartDelay(); + + public abstract void setStartDelay(long startDelay); + + public abstract Animator10 setDuration(long duration); + + public abstract long getDuration(); + + public abstract void setInterpolator(Interpolator value); + + public abstract boolean isRunning(); + + public void start() { + + } + + public void cancel() { + + } + + public void end() { + + } + + @SuppressWarnings("unchecked") + public void pause() { + if (isStarted() && !mPaused) { + mPaused = true; + if (mPauseListeners != null) { + ArrayList tmpListeners = (ArrayList) mPauseListeners.clone(); + int numListeners = tmpListeners.size(); + for (AnimatorPauseListener tmpListener : tmpListeners) { + tmpListener.onAnimationPause(this); + } + } + } + } + + @SuppressWarnings("unchecked") + public void resume() { + if (mPaused) { + mPaused = false; + if (mPauseListeners != null) { + ArrayList tmpListeners = (ArrayList) mPauseListeners.clone(); + int numListeners = tmpListeners.size(); + for (AnimatorPauseListener tmpListener : tmpListeners) { + tmpListener.onAnimationResume(this); + } + } + } + } + + public boolean isPaused() { + return mPaused; + } + + public boolean isStarted() { + return isRunning(); + } + + public Interpolator getInterpolator() { + return null; + } + + public void addListener(AnimatorListener listener) { + if (mListeners == null) { + mListeners = new ArrayList(); + } + mListeners.add(listener); + } + + public void removeListener(AnimatorListener listener) { + if (mListeners == null) { + return; + } + mListeners.remove(listener); + if (mListeners.size() == 0) { + mListeners = null; + } + } + + public ArrayList getListeners() { + return mListeners; + } + + public void addPauseListener(AnimatorPauseListener listener) { + if (mPauseListeners == null) { + mPauseListeners = new ArrayList(); + } + mPauseListeners.add(listener); + } + + public void removePauseListener(AnimatorPauseListener listener) { + if (mPauseListeners == null) { + return; + } + mPauseListeners.remove(listener); + if (mPauseListeners.size() == 0) { + mPauseListeners = null; + } + } + + public void removeAllListeners() { + if (mListeners != null) { + mListeners.clear(); + mListeners = null; + } + if (mPauseListeners != null) { + mPauseListeners.clear(); + mPauseListeners = null; + } + } + + @Override + public Animator10 clone() { + try { + final Animator10 anim = (Animator10) super.clone(); + if (mListeners != null) { + ArrayList oldListeners = mListeners; + anim.mListeners = new ArrayList(); + int numListeners = oldListeners.size(); + for (AnimatorListener oldListener : oldListeners) { + anim.mListeners.add(oldListener); + } + } + if (mPauseListeners != null) { + ArrayList oldListeners = mPauseListeners; + anim.mPauseListeners = new ArrayList(); + int numListeners = oldListeners.size(); + for (AnimatorPauseListener oldListener : oldListeners) { + anim.mPauseListeners.add(oldListener); + } + } + return anim; + } catch (CloneNotSupportedException e) { + throw new AssertionError(); + } + } + + public void setupStartValues() { + + } + + public void setupEndValues() { + + } + + public void setTarget(Object target) { + + } + + public interface AnimatorListener { + void onAnimationStart(Animator10 animation); + void onAnimationEnd(Animator10 animation); + void onAnimationCancel(Animator10 animation); + void onAnimationRepeat(Animator10 animation); + } + + public interface AnimatorPauseListener { + void onAnimationPause(Animator10 animation); + void onAnimationResume(Animator10 animation); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/AnimatorListenerAdapter10.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/AnimatorListenerAdapter10.java new file mode 100644 index 00000000..f5aefe9a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/AnimatorListenerAdapter10.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.Animation; + +public abstract class AnimatorListenerAdapter10 implements Animator10.AnimatorListener, Animator10.AnimatorPauseListener { + + @Override + public void onAnimationCancel(Animator10 animation) { + + } + + @Override + public void onAnimationEnd(Animator10 animation) { + + } + + @Override + public void onAnimationRepeat(Animator10 animation) { + + } + + @Override + public void onAnimationStart(Animator10 animation) { + + } + + @Override + public void onAnimationPause(Animator10 animation) { + + } + + @Override + public void onAnimationResume(Animator10 animation) { + + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/AnimatorSet10.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/AnimatorSet10.java new file mode 100644 index 00000000..2f749f2f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/AnimatorSet10.java @@ -0,0 +1,705 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.Animation; + +import android.view.animation.Interpolator; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; + +public final class AnimatorSet10 extends Animator10 { + + private ArrayList mPlayingSet = new ArrayList<>(); + private HashMap mNodeMap = new HashMap<>(); + private ArrayList mNodes = new ArrayList<>(); + private ArrayList mSortedNodes = new ArrayList<>(); + private boolean mNeedsSort = true; + private AnimatorSetListener mSetListener = null; + boolean mTerminated = false; + private boolean mStarted = false; + private long mStartDelay = 0; + private ValueAnimator mDelayAnim = null; + private long mDuration = -1; + private Interpolator mInterpolator = null; + + public void playTogether(Animator10... items) { + if (items != null) { + mNeedsSort = true; + Builder builder = play(items[0]); + for (int i = 1; i < items.length; ++i) { + builder.with(items[i]); + } + } + } + + public void playTogether(Collection items) { + if (items != null && items.size() > 0) { + mNeedsSort = true; + Builder builder = null; + for (Animator10 anim : items) { + if (builder == null) { + builder = play(anim); + } else { + builder.with(anim); + } + } + } + } + + public void playSequentially(Animator10... items) { + if (items != null) { + mNeedsSort = true; + if (items.length == 1) { + play(items[0]); + } else { + for (int i = 0; i < items.length - 1; ++i) { + play(items[i]).before(items[i+1]); + } + } + } + } + + public void playSequentially(List items) { + if (items != null && items.size() > 0) { + mNeedsSort = true; + if (items.size() == 1) { + play(items.get(0)); + } else { + for (int i = 0; i < items.size() - 1; ++i) { + play(items.get(i)).before(items.get(i+1)); + } + } + } + } + + public ArrayList getChildAnimations() { + ArrayList childList = new ArrayList<>(); + for (Node node : mNodes) { + childList.add(node.animation); + } + return childList; + } + + @Override + public void setTarget(Object target) { + for (Node node : mNodes) { + Animator10 animation = node.animation; + if (animation instanceof AnimatorSet10) { + animation.setTarget(target); + } else if (animation instanceof ObjectAnimator10) { + animation.setTarget(target); + } + } + } + + @Override + public void setInterpolator(Interpolator interpolator) { + mInterpolator = interpolator; + } + + @Override + public Interpolator getInterpolator() { + return mInterpolator; + } + + public Builder play(Animator10 anim) { + if (anim != null) { + mNeedsSort = true; + return new Builder(anim); + } + return null; + } + + @SuppressWarnings("unchecked") + @Override + public void cancel() { + mTerminated = true; + if (isStarted()) { + ArrayList tmpListeners = null; + if (mListeners != null) { + tmpListeners = (ArrayList) mListeners.clone(); + for (AnimatorListener listener : tmpListeners) { + listener.onAnimationCancel(this); + } + } + if (mDelayAnim != null && mDelayAnim.isRunning()) { + mDelayAnim.cancel(); + } else if (mSortedNodes.size() > 0) { + for (Node node : mSortedNodes) { + node.animation.cancel(); + } + } + if (tmpListeners != null) { + for (AnimatorListener listener : tmpListeners) { + listener.onAnimationEnd(this); + } + } + mStarted = false; + } + } + + @SuppressWarnings("unchecked") + @Override + public void end() { + mTerminated = true; + if (isStarted()) { + if (mSortedNodes.size() != mNodes.size()) { + // hasn't been started yet - sort the nodes now, then end them + sortNodes(); + for (Node node : mSortedNodes) { + if (mSetListener == null) { + mSetListener = new AnimatorSetListener(this); + } + node.animation.addListener(mSetListener); + } + } + if (mDelayAnim != null) { + mDelayAnim.cancel(); + } + if (mSortedNodes.size() > 0) { + for (Node node : mSortedNodes) { + node.animation.end(); + } + } + if (mListeners != null) { + ArrayList tmpListeners = (ArrayList) mListeners.clone(); + for (AnimatorListener listener : tmpListeners) { + listener.onAnimationEnd(this); + } + } + mStarted = false; + } + } + + @Override + public boolean isRunning() { + for (Node node : mNodes) { + if (node.animation.isRunning()) { + return true; + } + } + return false; + } + + @Override + public boolean isStarted() { + return mStarted; + } + + @Override + public long getStartDelay() { + return mStartDelay; + } + + @Override + public void setStartDelay(long startDelay) { + mStartDelay = startDelay; + } + + @Override + public long getDuration() { + return mDuration; + } + + @Override + public AnimatorSet10 setDuration(long duration) { + if (duration < 0) { + throw new IllegalArgumentException("duration must be a value of zero or greater"); + } + mDuration = duration; + return this; + } + + @Override + public void setupStartValues() { + for (Node node : mNodes) { + node.animation.setupStartValues(); + } + } + + @Override + public void setupEndValues() { + for (Node node : mNodes) { + node.animation.setupEndValues(); + } + } + + @Override + public void pause() { + boolean previouslyPaused = mPaused; + super.pause(); + if (!previouslyPaused && mPaused) { + if (mDelayAnim != null) { + mDelayAnim.pause(); + } else { + for (Node node : mNodes) { + node.animation.pause(); + } + } + } + } + + @Override + public void resume() { + boolean previouslyPaused = mPaused; + super.resume(); + if (previouslyPaused && !mPaused) { + if (mDelayAnim != null) { + mDelayAnim.resume(); + } else { + for (Node node : mNodes) { + node.animation.resume(); + } + } + } + } + + @SuppressWarnings("unchecked") + @Override + public void start() { + mTerminated = false; + mStarted = true; + mPaused = false; + + if (mDuration >= 0) { + for (Node node : mNodes) { + node.animation.setDuration(mDuration); + } + } + if (mInterpolator != null) { + for (Node node : mNodes) { + node.animation.setInterpolator(mInterpolator); + } + } + + sortNodes(); + + int numSortedNodes = mSortedNodes.size(); + for (Node node : mSortedNodes) { + ArrayList oldListeners = node.animation.getListeners(); + if (oldListeners != null && oldListeners.size() > 0) { + final ArrayList clonedListeners = new + ArrayList<>(oldListeners); + + for (AnimatorListener listener : clonedListeners) { + if (listener instanceof DependencyListener || + listener instanceof AnimatorSetListener) { + node.animation.removeListener(listener); + } + } + } + } + + final ArrayList nodesToStart = new ArrayList<>(); + for (Node node : mSortedNodes) { + if (mSetListener == null) { + mSetListener = new AnimatorSetListener(this); + } + if (node.dependencies == null || node.dependencies.size() == 0) { + nodesToStart.add(node); + } else { + int numDependencies = node.dependencies.size(); + for (int j = 0; j < numDependencies; ++j) { + Dependency dependency = node.dependencies.get(j); + dependency.node.animation.addListener( + new DependencyListener(this, node, dependency.rule)); + } + node.tmpDependencies = (ArrayList) node.dependencies.clone(); + } + node.animation.addListener(mSetListener); + } + + if (mStartDelay <= 0) { + for (Node node : nodesToStart) { + node.animation.start(); + mPlayingSet.add(node.animation); + } + } else { + mDelayAnim = ValueAnimator.ofFloat(0f, 1f); + mDelayAnim.setDuration(mStartDelay); + mDelayAnim.addListener(new AnimatorListenerAdapter10() { + boolean canceled = false; + public void onAnimationCancel(Animator10 anim) { + canceled = true; + } + public void onAnimationEnd(Animator10 anim) { + if (!canceled) { + int numNodes = nodesToStart.size(); + for (Node node : nodesToStart) { + node.animation.start(); + mPlayingSet.add(node.animation); + } + } + mDelayAnim = null; + } + }); + mDelayAnim.start(); + } + if (mListeners != null) { + ArrayList tmpListeners = + (ArrayList) mListeners.clone(); + int numListeners = tmpListeners.size(); + for (AnimatorListener tmpListener : tmpListeners) { + tmpListener.onAnimationStart(this); + } + } + if (mNodes.size() == 0 && mStartDelay == 0) { + mStarted = false; + if (mListeners != null) { + ArrayList tmpListeners = + (ArrayList) mListeners.clone(); + int numListeners = tmpListeners.size(); + for (AnimatorListener tmpListener : tmpListeners) { + tmpListener.onAnimationEnd(this); + } + } + } + } + + @Override + public AnimatorSet10 clone() { + final AnimatorSet10 anim = (AnimatorSet10) super.clone(); + + anim.mNeedsSort = true; + anim.mTerminated = false; + anim.mStarted = false; + anim.mPlayingSet = new ArrayList<>(); + anim.mNodeMap = new HashMap<>(); + anim.mNodes = new ArrayList<>(); + anim.mSortedNodes = new ArrayList<>(); + + HashMap nodeCloneMap = new HashMap<>(); + for (Node node : mNodes) { + Node nodeClone = node.clone(); + nodeCloneMap.put(node, nodeClone); + anim.mNodes.add(nodeClone); + anim.mNodeMap.put(nodeClone.animation, nodeClone); + nodeClone.dependencies = null; + nodeClone.tmpDependencies = null; + nodeClone.nodeDependents = null; + nodeClone.nodeDependencies = null; + ArrayList cloneListeners = nodeClone.animation.getListeners(); + if (cloneListeners != null) { + ArrayList listenersToRemove = null; + for (AnimatorListener listener : cloneListeners) { + if (listener instanceof AnimatorSetListener) { + if (listenersToRemove == null) { + listenersToRemove = new ArrayList<>(); + } + listenersToRemove.add(listener); + } + } + if (listenersToRemove != null) { + for (AnimatorListener listener : listenersToRemove) { + cloneListeners.remove(listener); + } + } + } + } + for (Node node : mNodes) { + Node nodeClone = nodeCloneMap.get(node); + if (node.dependencies != null) { + for (Dependency dependency : node.dependencies) { + Node clonedDependencyNode = nodeCloneMap.get(dependency.node); + Dependency cloneDependency = new Dependency(clonedDependencyNode, dependency.rule); + nodeClone.addDependency(cloneDependency); + } + } + } + return anim; + } + + private static class DependencyListener implements AnimatorListener { + + private AnimatorSet10 mAnimatorSet; + private Node mNode; + private int mRule; + + public DependencyListener(AnimatorSet10 animatorSet, Node node, int rule) { + this.mAnimatorSet = animatorSet; + this.mNode = node; + this.mRule = rule; + } + + public void onAnimationCancel(Animator10 animation) { + + } + + public void onAnimationEnd(Animator10 animation) { + if (mRule == Dependency.AFTER) { + startIfReady(animation); + } + } + + public void onAnimationRepeat(Animator10 animation) { + + } + + public void onAnimationStart(Animator10 animation) { + if (mRule == Dependency.WITH) { + startIfReady(animation); + } + } + + private void startIfReady(Animator10 dependencyAnimation) { + if (mAnimatorSet.mTerminated) { + return; + } + Dependency dependencyToRemove = null; + int numDependencies = mNode.tmpDependencies.size(); + for (int i = 0; i < numDependencies; ++i) { + Dependency dependency = mNode.tmpDependencies.get(i); + if (dependency.rule == mRule && dependency.node.animation == dependencyAnimation) { + dependencyToRemove = dependency; + dependencyAnimation.removeListener(this); + break; + } + } + mNode.tmpDependencies.remove(dependencyToRemove); + if (mNode.tmpDependencies.size() == 0) { + mNode.animation.start(); + mAnimatorSet.mPlayingSet.add(mNode.animation); + } + } + } + + private class AnimatorSetListener implements AnimatorListener { + + private AnimatorSet10 mAnimatorSet; + + AnimatorSetListener(AnimatorSet10 animatorSet) { + mAnimatorSet = animatorSet; + } + + public void onAnimationCancel(Animator10 animation) { + if (!mTerminated) { + if (mPlayingSet.size() == 0) { + if (mListeners != null) { + int numListeners = mListeners.size(); + for (AnimatorListener mListener : mListeners) { + mListener.onAnimationCancel(mAnimatorSet); + } + } + } + } + } + + @SuppressWarnings("unchecked") + public void onAnimationEnd(Animator10 animation) { + animation.removeListener(this); + mPlayingSet.remove(animation); + Node animNode = mAnimatorSet.mNodeMap.get(animation); + animNode.done = true; + if (!mTerminated) { + ArrayList sortedNodes = mAnimatorSet.mSortedNodes; + boolean allDone = true; + int numSortedNodes = sortedNodes.size(); + for (Node sortedNode : sortedNodes) { + if (!sortedNode.done) { + allDone = false; + break; + } + } + if (allDone) { + if (mListeners != null) { + ArrayList tmpListeners = + (ArrayList) mListeners.clone(); + int numListeners = tmpListeners.size(); + for (AnimatorListener tmpListener : tmpListeners) { + tmpListener.onAnimationEnd(mAnimatorSet); + } + } + mAnimatorSet.mStarted = false; + mAnimatorSet.mPaused = false; + } + } + } + + public void onAnimationRepeat(Animator10 animation) { + + } + + public void onAnimationStart(Animator10 animation) { + + } + } + + private void sortNodes() { + if (mNeedsSort) { + mSortedNodes.clear(); + ArrayList roots = new ArrayList<>(); + int numNodes = mNodes.size(); + for (Node node : mNodes) { + if (node.dependencies == null || node.dependencies.size() == 0) { + roots.add(node); + } + } + ArrayList tmpRoots = new ArrayList<>(); + while (roots.size() > 0) { + int numRoots = roots.size(); + for (Node root : roots) { + mSortedNodes.add(root); + if (root.nodeDependents != null) { + int numDependents = root.nodeDependents.size(); + for (int j = 0; j < numDependents; ++j) { + Node node = root.nodeDependents.get(j); + node.nodeDependencies.remove(root); + if (node.nodeDependencies.size() == 0) { + tmpRoots.add(node); + } + } + } + } + roots.clear(); + roots.addAll(tmpRoots); + tmpRoots.clear(); + } + mNeedsSort = false; + if (mSortedNodes.size() != mNodes.size()) { + throw new IllegalStateException("Circular dependencies cannot exist in AnimatorSet"); + } + } else { + int numNodes = mNodes.size(); + for (Node node : mNodes) { + if (node.dependencies != null && node.dependencies.size() > 0) { + int numDependencies = node.dependencies.size(); + for (int j = 0; j < numDependencies; ++j) { + Dependency dependency = node.dependencies.get(j); + if (node.nodeDependencies == null) { + node.nodeDependencies = new ArrayList<>(); + } + if (!node.nodeDependencies.contains(dependency.node)) { + node.nodeDependencies.add(dependency.node); + } + } + } + node.done = false; + } + } + } + + private static class Dependency { + static final int WITH = 0; + static final int AFTER = 1; + public Node node; + public int rule; + + public Dependency(Node node, int rule) { + this.node = node; + this.rule = rule; + } + } + + private static class Node implements Cloneable { + public Animator10 animation; + public ArrayList dependencies = null; + public ArrayList tmpDependencies = null; + public ArrayList nodeDependencies = null; + public ArrayList nodeDependents = null; + public boolean done = false; + + public Node(Animator10 animation) { + this.animation = animation; + } + + public void addDependency(Dependency dependency) { + if (dependencies == null) { + dependencies = new ArrayList<>(); + nodeDependencies = new ArrayList<>(); + } + dependencies.add(dependency); + if (!nodeDependencies.contains(dependency.node)) { + nodeDependencies.add(dependency.node); + } + Node dependencyNode = dependency.node; + if (dependencyNode.nodeDependents == null) { + dependencyNode.nodeDependents = new ArrayList<>(); + } + dependencyNode.nodeDependents.add(this); + } + + @Override + public Node clone() { + try { + Node node = (Node) super.clone(); + node.animation = animation.clone(); + return node; + } catch (CloneNotSupportedException e) { + throw new AssertionError(); + } + } + } + + public class Builder { + + private Node mCurrentNode; + + Builder(Animator10 anim) { + mCurrentNode = mNodeMap.get(anim); + if (mCurrentNode == null) { + mCurrentNode = new Node(anim); + mNodeMap.put(anim, mCurrentNode); + mNodes.add(mCurrentNode); + } + } + + public Builder with(Animator10 anim) { + Node node = mNodeMap.get(anim); + if (node == null) { + node = new Node(anim); + mNodeMap.put(anim, node); + mNodes.add(node); + } + Dependency dependency = new Dependency(mCurrentNode, Dependency.WITH); + node.addDependency(dependency); + return this; + } + + public Builder before(Animator10 anim) { + Node node = mNodeMap.get(anim); + if (node == null) { + node = new Node(anim); + mNodeMap.put(anim, node); + mNodes.add(node); + } + Dependency dependency = new Dependency(mCurrentNode, Dependency.AFTER); + node.addDependency(dependency); + return this; + } + + public Builder after(Animator10 anim) { + Node node = mNodeMap.get(anim); + if (node == null) { + node = new Node(anim); + mNodeMap.put(anim, node); + mNodes.add(node); + } + Dependency dependency = new Dependency(node, Dependency.AFTER); + mCurrentNode.addDependency(dependency); + return this; + } + + public Builder after(long delay) { + ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); + anim.setDuration(delay); + after(anim); + return this; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/FloatEvaluator.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/FloatEvaluator.java new file mode 100644 index 00000000..31d28939 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/FloatEvaluator.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.Animation; + +public class FloatEvaluator implements TypeEvaluator { + public Float evaluate(float fraction, Number startValue, Number endValue) { + float startFloat = startValue.floatValue(); + return startFloat + fraction * (endValue.floatValue() - startFloat); + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/FloatKeyframeSet.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/FloatKeyframeSet.java new file mode 100644 index 00000000..e7865e05 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/FloatKeyframeSet.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.Animation; + +import android.view.animation.Interpolator; + +import org.telegram.messenger.Animation.Keyframe.FloatKeyframe; + +import java.util.ArrayList; + +class FloatKeyframeSet extends KeyframeSet { + private float firstValue; + private float lastValue; + private float deltaValue; + private boolean firstTime = true; + + public FloatKeyframeSet(FloatKeyframe... keyframes) { + super(keyframes); + } + + @Override + public Object getValue(float fraction) { + return getFloatValue(fraction); + } + + @Override + public FloatKeyframeSet clone() { + ArrayList keyframes = mKeyframes; + int numKeyframes = mKeyframes.size(); + FloatKeyframe[] newKeyframes = new FloatKeyframe[numKeyframes]; + for (int i = 0; i < numKeyframes; ++i) { + newKeyframes[i] = (FloatKeyframe) keyframes.get(i).clone(); + } + return new FloatKeyframeSet(newKeyframes); + } + + @SuppressWarnings("unchecked") + public float getFloatValue(float fraction) { + if (mNumKeyframes == 2) { + if (firstTime) { + firstTime = false; + firstValue = ((FloatKeyframe) mKeyframes.get(0)).getFloatValue(); + lastValue = ((FloatKeyframe) mKeyframes.get(1)).getFloatValue(); + deltaValue = lastValue - firstValue; + } + if (mInterpolator != null) { + fraction = mInterpolator.getInterpolation(fraction); + } + if (mEvaluator == null) { + return firstValue + fraction * deltaValue; + } else { + return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).floatValue(); + } + } + if (fraction <= 0f) { + final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0); + final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(1); + float prevValue = prevKeyframe.getFloatValue(); + float nextValue = nextKeyframe.getFloatValue(); + float prevFraction = prevKeyframe.getFraction(); + float nextFraction = nextKeyframe.getFraction(); + final Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction); + return mEvaluator == null ? prevValue + intervalFraction * (nextValue - prevValue) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).floatValue(); + } else if (fraction >= 1f) { + final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 2); + final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 1); + float prevValue = prevKeyframe.getFloatValue(); + float nextValue = nextKeyframe.getFloatValue(); + float prevFraction = prevKeyframe.getFraction(); + float nextFraction = nextKeyframe.getFraction(); + final Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction); + return mEvaluator == null ? prevValue + intervalFraction * (nextValue - prevValue) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).floatValue(); + } + FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0); + for (int i = 1; i < mNumKeyframes; ++i) { + FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i); + if (fraction < nextKeyframe.getFraction()) { + final Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + float intervalFraction = (fraction - prevKeyframe.getFraction()) / + (nextKeyframe.getFraction() - prevKeyframe.getFraction()); + float prevValue = prevKeyframe.getFloatValue(); + float nextValue = nextKeyframe.getFloatValue(); + return mEvaluator == null ? prevValue + intervalFraction * (nextValue - prevValue) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).floatValue(); + } + prevKeyframe = nextKeyframe; + } + return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/FloatProperty10.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/FloatProperty10.java new file mode 100644 index 00000000..1a3b6d79 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/FloatProperty10.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.Animation; + +public abstract class FloatProperty10 extends Property { + + public FloatProperty10(String name) { + super(Float.class, name); + } + + public abstract void setValue(T object, float value); + + @Override + final public void set(T object, Float value) { + setValue(object, value.floatValue()); + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/IntEvaluator.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/IntEvaluator.java new file mode 100644 index 00000000..2b43e077 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/IntEvaluator.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.Animation; + +public class IntEvaluator implements TypeEvaluator { + public Integer evaluate(float fraction, Integer startValue, Integer endValue) { + int startInt = startValue; + return (int)(startInt + fraction * (endValue - startInt)); + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/IntKeyframeSet.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/IntKeyframeSet.java new file mode 100644 index 00000000..2224f212 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/IntKeyframeSet.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.Animation; + +import android.view.animation.Interpolator; + +import org.telegram.messenger.Animation.Keyframe.IntKeyframe; + +import java.util.ArrayList; + +class IntKeyframeSet extends KeyframeSet { + private int firstValue; + private int lastValue; + private int deltaValue; + private boolean firstTime = true; + + public IntKeyframeSet(IntKeyframe... keyframes) { + super(keyframes); + } + + @Override + public Object getValue(float fraction) { + return getIntValue(fraction); + } + + @Override + public IntKeyframeSet clone() { + ArrayList keyframes = mKeyframes; + int numKeyframes = mKeyframes.size(); + IntKeyframe[] newKeyframes = new IntKeyframe[numKeyframes]; + for (int i = 0; i < numKeyframes; ++i) { + newKeyframes[i] = (IntKeyframe) keyframes.get(i).clone(); + } + return new IntKeyframeSet(newKeyframes); + } + + @SuppressWarnings("unchecked") + public int getIntValue(float fraction) { + if (mNumKeyframes == 2) { + if (firstTime) { + firstTime = false; + firstValue = ((IntKeyframe) mKeyframes.get(0)).getIntValue(); + lastValue = ((IntKeyframe) mKeyframes.get(1)).getIntValue(); + deltaValue = lastValue - firstValue; + } + if (mInterpolator != null) { + fraction = mInterpolator.getInterpolation(fraction); + } + if (mEvaluator == null) { + return firstValue + (int)(fraction * deltaValue); + } else { + return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue(); + } + } + if (fraction <= 0f) { + final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0); + final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(1); + int prevValue = prevKeyframe.getIntValue(); + int nextValue = nextKeyframe.getIntValue(); + float prevFraction = prevKeyframe.getFraction(); + float nextFraction = nextKeyframe.getFraction(); + final Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction); + return mEvaluator == null ? prevValue + (int)(intervalFraction * (nextValue - prevValue)) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).intValue(); + } else if (fraction >= 1f) { + final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 2); + final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 1); + int prevValue = prevKeyframe.getIntValue(); + int nextValue = nextKeyframe.getIntValue(); + float prevFraction = prevKeyframe.getFraction(); + float nextFraction = nextKeyframe.getFraction(); + final Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction); + return mEvaluator == null ? prevValue + (int)(intervalFraction * (nextValue - prevValue)) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).intValue(); + } + IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0); + for (int i = 1; i < mNumKeyframes; ++i) { + IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(i); + if (fraction < nextKeyframe.getFraction()) { + final Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + float intervalFraction = (fraction - prevKeyframe.getFraction()) / (nextKeyframe.getFraction() - prevKeyframe.getFraction()); + int prevValue = prevKeyframe.getIntValue(); + int nextValue = nextKeyframe.getIntValue(); + return mEvaluator == null ? prevValue + (int)(intervalFraction * (nextValue - prevValue)) : ((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).intValue(); + } + prevKeyframe = nextKeyframe; + } + return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).intValue(); + } +} + diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/IntProperty.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/IntProperty.java new file mode 100644 index 00000000..175704cf --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/IntProperty.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.Animation; + +public abstract class IntProperty extends Property { + + public IntProperty(String name) { + super(Integer.class, name); + } + + public abstract void setValue(T object, int value); + + @Override + final public void set(T object, Integer value) { + setValue(object, value.intValue()); + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/Keyframe.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/Keyframe.java new file mode 100644 index 00000000..b65ddaf4 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/Keyframe.java @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.Animation; + +import android.view.animation.Interpolator; + +public abstract class Keyframe implements Cloneable { + + float mFraction; + Class mValueType; + private Interpolator mInterpolator = null; + boolean mHasValue = false; + + public static Keyframe ofInt(float fraction, int value) { + return new IntKeyframe(fraction, value); + } + + public static Keyframe ofInt(float fraction) { + return new IntKeyframe(fraction); + } + + public static Keyframe ofFloat(float fraction, float value) { + return new FloatKeyframe(fraction, value); + } + + public static Keyframe ofFloat(float fraction) { + return new FloatKeyframe(fraction); + } + + public static Keyframe ofObject(float fraction, Object value) { + return new ObjectKeyframe(fraction, value); + } + + public static Keyframe ofObject(float fraction) { + return new ObjectKeyframe(fraction, null); + } + + public boolean hasValue() { + return mHasValue; + } + + public abstract Object getValue(); + public abstract void setValue(Object value); + + public float getFraction() { + return mFraction; + } + + public void setFraction(float fraction) { + mFraction = fraction; + } + + public Interpolator getInterpolator() { + return mInterpolator; + } + + public void setInterpolator(Interpolator interpolator) { + mInterpolator = interpolator; + } + + public Class getType() { + return mValueType; + } + + @Override + public abstract Keyframe clone(); + + static class ObjectKeyframe extends Keyframe { + + Object mValue; + + ObjectKeyframe(float fraction, Object value) { + mFraction = fraction; + mValue = value; + mHasValue = (value != null); + mValueType = mHasValue ? value.getClass() : Object.class; + } + + public Object getValue() { + return mValue; + } + + public void setValue(Object value) { + mValue = value; + mHasValue = (value != null); + } + + @Override + public ObjectKeyframe clone() { + ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), mHasValue ? mValue : null); + kfClone.setInterpolator(getInterpolator()); + return kfClone; + } + } + + static class IntKeyframe extends Keyframe { + + int mValue; + + IntKeyframe(float fraction, int value) { + mFraction = fraction; + mValue = value; + mValueType = int.class; + mHasValue = true; + } + + IntKeyframe(float fraction) { + mFraction = fraction; + mValueType = int.class; + } + + public int getIntValue() { + return mValue; + } + + public Object getValue() { + return mValue; + } + + public void setValue(Object value) { + if (value != null && value.getClass() == Integer.class) { + mValue = (Integer) value; + mHasValue = true; + } + } + + @Override + public IntKeyframe clone() { + IntKeyframe kfClone = mHasValue ? new IntKeyframe(getFraction(), mValue) : new IntKeyframe(getFraction()); + kfClone.setInterpolator(getInterpolator()); + return kfClone; + } + } + + static class FloatKeyframe extends Keyframe { + + float mValue; + + FloatKeyframe(float fraction, float value) { + mFraction = fraction; + mValue = value; + mValueType = float.class; + mHasValue = true; + } + + FloatKeyframe(float fraction) { + mFraction = fraction; + mValueType = float.class; + } + + public float getFloatValue() { + return mValue; + } + + public Object getValue() { + return mValue; + } + + public void setValue(Object value) { + if (value != null && value.getClass() == Float.class) { + mValue = (Float) value; + mHasValue = true; + } + } + + @Override + public FloatKeyframe clone() { + FloatKeyframe kfClone = mHasValue ? new FloatKeyframe(getFraction(), mValue) : new FloatKeyframe(getFraction()); + kfClone.setInterpolator(getInterpolator()); + return kfClone; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/KeyframeSet.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/KeyframeSet.java new file mode 100644 index 00000000..2e86dc87 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/KeyframeSet.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.Animation; + +import java.util.ArrayList; +import java.util.Arrays; +import android.util.Log; +import android.view.animation.Interpolator; + +import org.telegram.messenger.Animation.Keyframe.IntKeyframe; +import org.telegram.messenger.Animation.Keyframe.FloatKeyframe; +import org.telegram.messenger.Animation.Keyframe.ObjectKeyframe; + +class KeyframeSet { + + int mNumKeyframes; + + Keyframe mFirstKeyframe; + Keyframe mLastKeyframe; + Interpolator mInterpolator; + ArrayList mKeyframes; + TypeEvaluator mEvaluator; + + public KeyframeSet(Keyframe... keyframes) { + mNumKeyframes = keyframes.length; + mKeyframes = new ArrayList(); + mKeyframes.addAll(Arrays.asList(keyframes)); + mFirstKeyframe = mKeyframes.get(0); + mLastKeyframe = mKeyframes.get(mNumKeyframes - 1); + mInterpolator = mLastKeyframe.getInterpolator(); + } + + public static KeyframeSet ofInt(int... values) { + int numKeyframes = values.length; + IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)]; + if (numKeyframes == 1) { + keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f); + keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]); + } else { + keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]); + for (int i = 1; i < numKeyframes; ++i) { + keyframes[i] = (IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]); + } + } + return new IntKeyframeSet(keyframes); + } + + public static KeyframeSet ofFloat(float... values) { + boolean badValue = false; + int numKeyframes = values.length; + FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)]; + if (numKeyframes == 1) { + keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f); + keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]); + if (Float.isNaN(values[0])) { + badValue = true; + } + } else { + keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]); + for (int i = 1; i < numKeyframes; ++i) { + keyframes[i] = (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]); + if (Float.isNaN(values[i])) { + badValue = true; + } + } + } + if (badValue) { + Log.w("Animator", "Bad value (NaN) in float animator"); + } + return new FloatKeyframeSet(keyframes); + } + + public static KeyframeSet ofKeyframe(Keyframe... keyframes) { + int numKeyframes = keyframes.length; + boolean hasFloat = false; + boolean hasInt = false; + boolean hasOther = false; + for (Keyframe keyframe : keyframes) { + if (keyframe instanceof FloatKeyframe) { + hasFloat = true; + } else if (keyframe instanceof IntKeyframe) { + hasInt = true; + } else { + hasOther = true; + } + } + if (hasFloat && !hasInt && !hasOther) { + FloatKeyframe floatKeyframes[] = new FloatKeyframe[numKeyframes]; + for (int i = 0; i < numKeyframes; ++i) { + floatKeyframes[i] = (FloatKeyframe) keyframes[i]; + } + return new FloatKeyframeSet(floatKeyframes); + } else if (hasInt && !hasFloat && !hasOther) { + IntKeyframe intKeyframes[] = new IntKeyframe[numKeyframes]; + for (int i = 0; i < numKeyframes; ++i) { + intKeyframes[i] = (IntKeyframe) keyframes[i]; + } + return new IntKeyframeSet(intKeyframes); + } else { + return new KeyframeSet(keyframes); + } + } + + public static KeyframeSet ofObject(Object... values) { + int numKeyframes = values.length; + ObjectKeyframe keyframes[] = new ObjectKeyframe[Math.max(numKeyframes,2)]; + if (numKeyframes == 1) { + keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f); + keyframes[1] = (ObjectKeyframe) Keyframe.ofObject(1f, values[0]); + } else { + keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f, values[0]); + for (int i = 1; i < numKeyframes; ++i) { + keyframes[i] = (ObjectKeyframe) Keyframe.ofObject((float) i / (numKeyframes - 1), values[i]); + } + } + return new KeyframeSet(keyframes); + } + + public void setEvaluator(TypeEvaluator evaluator) { + mEvaluator = evaluator; + } + + @Override + public KeyframeSet clone() { + ArrayList keyframes = mKeyframes; + int numKeyframes = mKeyframes.size(); + Keyframe[] newKeyframes = new Keyframe[numKeyframes]; + for (int i = 0; i < numKeyframes; ++i) { + newKeyframes[i] = keyframes.get(i).clone(); + } + return new KeyframeSet(newKeyframes); + } + + @SuppressWarnings("unchecked") + public Object getValue(float fraction) { + if (mNumKeyframes == 2) { + if (mInterpolator != null) { + fraction = mInterpolator.getInterpolation(fraction); + } + return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(), mLastKeyframe.getValue()); + } + if (fraction <= 0f) { + final Keyframe nextKeyframe = mKeyframes.get(1); + final Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + final float prevFraction = mFirstKeyframe.getFraction(); + float intervalFraction = (fraction - prevFraction) / (nextKeyframe.getFraction() - prevFraction); + return mEvaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(), nextKeyframe.getValue()); + } else if (fraction >= 1f) { + final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2); + final Interpolator interpolator = mLastKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + final float prevFraction = prevKeyframe.getFraction(); + float intervalFraction = (fraction - prevFraction) / (mLastKeyframe.getFraction() - prevFraction); + return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(), mLastKeyframe.getValue()); + } + Keyframe prevKeyframe = mFirstKeyframe; + for (int i = 1; i < mNumKeyframes; ++i) { + Keyframe nextKeyframe = mKeyframes.get(i); + if (fraction < nextKeyframe.getFraction()) { + final Interpolator interpolator = nextKeyframe.getInterpolator(); + if (interpolator != null) { + fraction = interpolator.getInterpolation(fraction); + } + final float prevFraction = prevKeyframe.getFraction(); + float intervalFraction = (fraction - prevFraction) / (nextKeyframe.getFraction() - prevFraction); + return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(), nextKeyframe.getValue()); + } + prevKeyframe = nextKeyframe; + } + return mLastKeyframe.getValue(); + } + + @Override + public String toString() { + String returnVal = " "; + for (int i = 0; i < mNumKeyframes; ++i) { + returnVal += mKeyframes.get(i).getValue() + " "; + } + return returnVal; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/NoSuchPropertyException.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/NoSuchPropertyException.java new file mode 100644 index 00000000..11466028 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/NoSuchPropertyException.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.Animation; + +public class NoSuchPropertyException extends RuntimeException { + + public NoSuchPropertyException(String s) { + super(s); + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/ObjectAnimator10.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/ObjectAnimator10.java new file mode 100644 index 00000000..fef5f185 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/ObjectAnimator10.java @@ -0,0 +1,488 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.Animation; + +import android.view.View; + +import java.util.HashMap; + +public final class ObjectAnimator10 extends ValueAnimator { + + private static final HashMap PROXY_PROPERTIES = new HashMap(); + + static { + Property ALPHA = new FloatProperty10("alpha") { + @Override + public void setValue(View object, float value) { + View10.wrap(object).setAlpha(value); + } + + @Override + public Float get(View object) { + return View10.wrap(object).getAlpha(); + } + }; + + Property PIVOT_X = new FloatProperty10("pivotX") { + @Override + public void setValue(View object, float value) { + View10.wrap(object).setPivotX(value); + } + + @Override + public Float get(View object) { + return View10.wrap(object).getPivotX(); + } + }; + + Property PIVOT_Y = new FloatProperty10("pivotY") { + @Override + public void setValue(View object, float value) { + View10.wrap(object).setPivotY(value); + } + + @Override + public Float get(View object) { + return View10.wrap(object).getPivotY(); + } + }; + + Property TRANSLATION_X = new FloatProperty10("translationX") { + @Override + public void setValue(View object, float value) { + View10.wrap(object).setTranslationX(value); + } + + @Override + public Float get(View object) { + return View10.wrap(object).getTranslationX(); + } + }; + + Property TRANSLATION_Y = new FloatProperty10("translationY") { + @Override + public void setValue(View object, float value) { + View10.wrap(object).setTranslationY(value); + } + + @Override + public Float get(View object) { + return View10.wrap(object).getTranslationY(); + } + }; + + Property ROTATION = new FloatProperty10("rotation") { + @Override + public void setValue(View object, float value) { + View10.wrap(object).setRotation(value); + } + + @Override + public Float get(View object) { + return View10.wrap(object).getRotation(); + } + }; + + Property ROTATION_X = new FloatProperty10("rotationX") { + @Override + public void setValue(View object, float value) { + View10.wrap(object).setRotationX(value); + } + + @Override + public Float get(View object) { + return View10.wrap(object).getRotationX(); + } + }; + + Property ROTATION_Y = new FloatProperty10("rotationY") { + @Override + public void setValue(View object, float value) { + View10.wrap(object).setRotationY(value); + } + + @Override + public Float get(View object) { + return View10.wrap(object).getRotationY(); + } + }; + + Property SCALE_X = new FloatProperty10("scaleX") { + @Override + public void setValue(View object, float value) { + View10.wrap(object).setScaleX(value); + } + + @Override + public Float get(View object) { + return View10.wrap(object).getScaleX(); + } + }; + + Property SCALE_Y = new FloatProperty10("scaleY") { + @Override + public void setValue(View object, float value) { + View10.wrap(object).setScaleY(value); + } + + @Override + public Float get(View object) { + return View10.wrap(object).getScaleY(); + } + }; + + Property SCROLL_X = new IntProperty("scrollX") { + @Override + public void setValue(View object, int value) { + View10.wrap(object).setScrollX(value); + } + + @Override + public Integer get(View object) { + return View10.wrap(object).getScrollX(); + } + }; + + Property SCROLL_Y = new IntProperty("scrollY") { + @Override + public void setValue(View object, int value) { + View10.wrap(object).setScrollY(value); + } + + @Override + public Integer get(View object) { + return View10.wrap(object).getScrollY(); + } + }; + + Property X = new FloatProperty10("x") { + @Override + public void setValue(View object, float value) { + View10.wrap(object).setX(value); + } + + @Override + public Float get(View object) { + return View10.wrap(object).getX(); + } + }; + + Property Y = new FloatProperty10("y") { + @Override + public void setValue(View object, float value) { + View10.wrap(object).setY(value); + } + + @Override + public Float get(View object) { + return View10.wrap(object).getY(); + } + }; + + PROXY_PROPERTIES.put("alpha", ALPHA); + PROXY_PROPERTIES.put("pivotX", PIVOT_X); + PROXY_PROPERTIES.put("pivotY", PIVOT_Y); + PROXY_PROPERTIES.put("translationX", TRANSLATION_X); + PROXY_PROPERTIES.put("translationY", TRANSLATION_Y); + PROXY_PROPERTIES.put("rotation", ROTATION); + PROXY_PROPERTIES.put("rotationX", ROTATION_X); + PROXY_PROPERTIES.put("rotationY", ROTATION_Y); + PROXY_PROPERTIES.put("scaleX", SCALE_X); + PROXY_PROPERTIES.put("scaleY", SCALE_Y); + PROXY_PROPERTIES.put("scrollX", SCROLL_X); + PROXY_PROPERTIES.put("scrollY", SCROLL_Y); + PROXY_PROPERTIES.put("x", X); + PROXY_PROPERTIES.put("y", Y); + } + + private Object mTarget; + private String mPropertyName; + private Property mProperty; + private boolean mAutoCancel = false; + + public void setPropertyName(String propertyName) { + if (mValues != null) { + PropertyValuesHolder valuesHolder = mValues[0]; + String oldName = valuesHolder.getPropertyName(); + valuesHolder.setPropertyName(propertyName); + mValuesMap.remove(oldName); + mValuesMap.put(propertyName, valuesHolder); + } + mPropertyName = propertyName; + mInitialized = false; + } + + public void setProperty(Property property) { + if (mValues != null) { + PropertyValuesHolder valuesHolder = mValues[0]; + String oldName = valuesHolder.getPropertyName(); + valuesHolder.setProperty(property); + mValuesMap.remove(oldName); + mValuesMap.put(mPropertyName, valuesHolder); + } + if (mProperty != null) { + mPropertyName = property.getName(); + } + mProperty = property; + mInitialized = false; + } + + public String getPropertyName() { + String propertyName = null; + if (mPropertyName != null) { + propertyName = mPropertyName; + } else if (mProperty != null) { + propertyName = mProperty.getName(); + } else if (mValues != null && mValues.length > 0) { + for (int i = 0; i < mValues.length; ++i) { + if (i == 0) { + propertyName = ""; + } else { + propertyName += ","; + } + propertyName += mValues[i].getPropertyName(); + } + } + return propertyName; + } + + public ObjectAnimator10() { + + } + + private ObjectAnimator10(Object target, String propertyName) { + mTarget = target; + setPropertyName(propertyName); + } + + private ObjectAnimator10(T target, Property property) { + mTarget = target; + setProperty(property); + } + + public static ObjectAnimator10 ofInt(Object target, String propertyName, int... values) { + ObjectAnimator10 anim = new ObjectAnimator10(target, propertyName); + anim.setIntValues(values); + return anim; + } + + public static ObjectAnimator10 ofInt(T target, Property property, int... values) { + ObjectAnimator10 anim = new ObjectAnimator10(target, property); + anim.setIntValues(values); + return anim; + } + + public static ObjectAnimator10 ofFloat(Object target, String propertyName, float... values) { + ObjectAnimator10 anim = new ObjectAnimator10(target, propertyName); + anim.setFloatValues(values); + return anim; + } + + public static ObjectAnimator10 ofFloat(T target, Property property, float... values) { + ObjectAnimator10 anim = new ObjectAnimator10(target, property); + anim.setFloatValues(values); + return anim; + } + + public static ObjectAnimator10 ofObject(Object target, String propertyName, TypeEvaluator evaluator, Object... values) { + ObjectAnimator10 anim = new ObjectAnimator10(target, propertyName); + anim.setObjectValues(values); + anim.setEvaluator(evaluator); + return anim; + } + + public static ObjectAnimator10 ofObject(T target, Property property, TypeEvaluator evaluator, V... values) { + ObjectAnimator10 anim = new ObjectAnimator10(target, property); + anim.setObjectValues(values); + anim.setEvaluator(evaluator); + return anim; + } + + public static ObjectAnimator10 ofPropertyValuesHolder(Object target, PropertyValuesHolder... values) { + ObjectAnimator10 anim = new ObjectAnimator10(); + anim.mTarget = target; + anim.setValues(values); + return anim; + } + + @SuppressWarnings("unchecked") + @Override + public void setIntValues(int... values) { + if (mValues == null || mValues.length == 0) { + if (mProperty != null) { + setValues(PropertyValuesHolder.ofInt(mProperty, values)); + } else { + setValues(PropertyValuesHolder.ofInt(mPropertyName, values)); + } + } else { + super.setIntValues(values); + } + } + + @SuppressWarnings("unchecked") + @Override + public void setFloatValues(float... values) { + if (mValues == null || mValues.length == 0) { + if (mProperty != null) { + setValues(PropertyValuesHolder.ofFloat(mProperty, values)); + } else { + setValues(PropertyValuesHolder.ofFloat(mPropertyName, values)); + } + } else { + super.setFloatValues(values); + } + } + + @Override + public void setObjectValues(Object... values) { + if (mValues == null || mValues.length == 0) { + if (mProperty != null) { + setValues(PropertyValuesHolder.ofObject(mProperty, null, values)); + } else { + setValues(PropertyValuesHolder.ofObject(mPropertyName, null, values)); + } + } else { + super.setObjectValues(values); + } + } + + public void setAutoCancel(boolean cancel) { + mAutoCancel = cancel; + } + + private boolean hasSameTargetAndProperties(Animator10 anim) { + if (anim instanceof ObjectAnimator10) { + PropertyValuesHolder[] theirValues = ((ObjectAnimator10) anim).getValues(); + if (((ObjectAnimator10) anim).getTarget() == mTarget && + mValues.length == theirValues.length) { + for (int i = 0; i < mValues.length; ++i) { + PropertyValuesHolder pvhMine = mValues[i]; + PropertyValuesHolder pvhTheirs = theirValues[i]; + if (pvhMine.getPropertyName() == null || + !pvhMine.getPropertyName().equals(pvhTheirs.getPropertyName())) { + return false; + } + } + return true; + } + } + return false; + } + + @Override + public void start() { + AnimationHandler handler = sAnimationHandler.get(); + if (handler != null) { + int numAnims = handler.mAnimations.size(); + for (int i = numAnims - 1; i >= 0; i--) { + if (handler.mAnimations.get(i) instanceof ObjectAnimator10) { + ObjectAnimator10 anim = (ObjectAnimator10) handler.mAnimations.get(i); + if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) { + anim.cancel(); + } + } + } + numAnims = handler.mPendingAnimations.size(); + for (int i = numAnims - 1; i >= 0; i--) { + if (handler.mPendingAnimations.get(i) instanceof ObjectAnimator10) { + ObjectAnimator10 anim = (ObjectAnimator10) handler.mPendingAnimations.get(i); + if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) { + anim.cancel(); + } + } + } + numAnims = handler.mDelayedAnims.size(); + for (int i = numAnims - 1; i >= 0; i--) { + if (handler.mDelayedAnims.get(i) instanceof ObjectAnimator10) { + ObjectAnimator10 anim = (ObjectAnimator10) handler.mDelayedAnims.get(i); + if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) { + anim.cancel(); + } + } + } + } + super.start(); + } + + @Override + void initAnimation() { + if (!mInitialized) { + if ((mProperty == null) && (mTarget instanceof View) && PROXY_PROPERTIES.containsKey(mPropertyName)) { + setProperty(PROXY_PROPERTIES.get(mPropertyName)); + } + int numValues = mValues.length; + for (PropertyValuesHolder mValue : mValues) { + mValue.setupSetterAndGetter(mTarget); + } + super.initAnimation(); + } + } + + @Override + public ObjectAnimator10 setDuration(long duration) { + super.setDuration(duration); + return this; + } + + public Object getTarget() { + return mTarget; + } + + @Override + public void setTarget(Object target) { + if (mTarget != target) { + final Object oldTarget = mTarget; + mTarget = target; + if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) { + return; + } + mInitialized = false; + } + } + + @Override + public void setupStartValues() { + initAnimation(); + int numValues = mValues.length; + for (PropertyValuesHolder mValue : mValues) { + mValue.setupStartValue(mTarget); + } + } + + @Override + public void setupEndValues() { + initAnimation(); + int numValues = mValues.length; + for (PropertyValuesHolder mValue : mValues) { + mValue.setupEndValue(mTarget); + } + } + + @Override + void animateValue(float fraction) { + super.animateValue(fraction); + int numValues = mValues.length; + for (PropertyValuesHolder mValue : mValues) { + mValue.setAnimatedValue(mTarget); + } + } + + @Override + public ObjectAnimator10 clone() { + return (ObjectAnimator10) super.clone(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/Property.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/Property.java new file mode 100644 index 00000000..98983e16 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/Property.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.Animation; + +public abstract class Property { + + private final String mName; + private final Class mType; + + public static Property of(Class hostType, Class valueType, String name) { + return new ReflectiveProperty(hostType, valueType, name); + } + + public Property(Class type, String name) { + mName = name; + mType = type; + } + + public boolean isReadOnly() { + return false; + } + + public void set(T object, V value) { + throw new UnsupportedOperationException("Property " + getName() +" is read-only"); + } + + public abstract V get(T object); + + public String getName() { + return mName; + } + + public Class getType() { + return mType; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/PropertyValuesHolder.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/PropertyValuesHolder.java new file mode 100644 index 00000000..c4ab83b4 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/PropertyValuesHolder.java @@ -0,0 +1,545 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.Animation; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public class PropertyValuesHolder implements Cloneable { + + String mPropertyName; + protected Property mProperty; + Method mSetter = null; + private Method mGetter = null; + Class mValueType; + KeyframeSet mKeyframeSet = null; + + private static final TypeEvaluator sIntEvaluator = new IntEvaluator(); + private static final TypeEvaluator sFloatEvaluator = new FloatEvaluator(); + + private static Class[] FLOAT_VARIANTS = {float.class, Float.class, double.class, int.class, Double.class, Integer.class}; + private static Class[] INTEGER_VARIANTS = {int.class, Integer.class, float.class, double.class, Float.class, Double.class}; + private static Class[] DOUBLE_VARIANTS = {double.class, Double.class, float.class, int.class, Float.class, Integer.class}; + + private static final HashMap> sSetterPropertyMap = new HashMap>(); + private static final HashMap> sGetterPropertyMap = new HashMap>(); + + final ReentrantReadWriteLock mPropertyMapLock = new ReentrantReadWriteLock(); + final Object[] mTmpValueArray = new Object[1]; + + private TypeEvaluator mEvaluator; + + private Object mAnimatedValue; + + private PropertyValuesHolder(String propertyName) { + mPropertyName = propertyName; + } + + private PropertyValuesHolder(Property property) { + mProperty = property; + if (property != null) { + mPropertyName = property.getName(); + } + } + + public static PropertyValuesHolder ofInt(String propertyName, int... values) { + return new IntPropertyValuesHolder(propertyName, values); + } + + public static PropertyValuesHolder ofInt(Property property, int... values) { + return new IntPropertyValuesHolder(property, values); + } + + public static PropertyValuesHolder ofFloat(String propertyName, float... values) { + return new FloatPropertyValuesHolder(propertyName, values); + } + + public static PropertyValuesHolder ofFloat(Property property, float... values) { + return new FloatPropertyValuesHolder(property, values); + } + + public static PropertyValuesHolder ofObject(String propertyName, TypeEvaluator evaluator, + Object... values) { + PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName); + pvh.setObjectValues(values); + pvh.setEvaluator(evaluator); + return pvh; + } + + public static PropertyValuesHolder ofObject(Property property, + TypeEvaluator evaluator, V... values) { + PropertyValuesHolder pvh = new PropertyValuesHolder(property); + pvh.setObjectValues(values); + pvh.setEvaluator(evaluator); + return pvh; + } + + public static PropertyValuesHolder ofKeyframe(String propertyName, Keyframe... values) { + KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values); + if (keyframeSet instanceof IntKeyframeSet) { + return new IntPropertyValuesHolder(propertyName, (IntKeyframeSet) keyframeSet); + } else if (keyframeSet instanceof FloatKeyframeSet) { + return new FloatPropertyValuesHolder(propertyName, (FloatKeyframeSet) keyframeSet); + } else { + PropertyValuesHolder pvh = new PropertyValuesHolder(propertyName); + pvh.mKeyframeSet = keyframeSet; + pvh.mValueType = values[0].getType(); + return pvh; + } + } + + public static PropertyValuesHolder ofKeyframe(Property property, Keyframe... values) { + KeyframeSet keyframeSet = KeyframeSet.ofKeyframe(values); + if (keyframeSet instanceof IntKeyframeSet) { + return new IntPropertyValuesHolder(property, (IntKeyframeSet) keyframeSet); + } else if (keyframeSet instanceof FloatKeyframeSet) { + return new FloatPropertyValuesHolder(property, (FloatKeyframeSet) keyframeSet); + } else { + PropertyValuesHolder pvh = new PropertyValuesHolder(property); + pvh.mKeyframeSet = keyframeSet; + pvh.mValueType = values[0].getType(); + return pvh; + } + } + + public void setIntValues(int... values) { + mValueType = int.class; + mKeyframeSet = KeyframeSet.ofInt(values); + } + + public void setFloatValues(float... values) { + mValueType = float.class; + mKeyframeSet = KeyframeSet.ofFloat(values); + } + + public void setKeyframes(Keyframe... values) { + int numKeyframes = values.length; + Keyframe keyframes[] = new Keyframe[Math.max(numKeyframes, 2)]; + mValueType = values[0].getType(); + System.arraycopy(values, 0, keyframes, 0, numKeyframes); + mKeyframeSet = new KeyframeSet(keyframes); + } + + public void setObjectValues(Object... values) { + mValueType = values[0].getClass(); + mKeyframeSet = KeyframeSet.ofObject(values); + } + + @SuppressWarnings("unchecked") + private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) { + Method returnVal = null; + String methodName = getMethodName(prefix, mPropertyName); + Class args[] = null; + if (valueType == null) { + try { + returnVal = targetClass.getMethod(methodName); + } catch (Throwable e) { + try { + returnVal = targetClass.getDeclaredMethod(methodName); + returnVal.setAccessible(true); + } catch (Throwable e2) { + e2.printStackTrace(); + } + } + } else { + args = new Class[1]; + Class typeVariants[]; + if (mValueType.equals(Float.class)) { + typeVariants = FLOAT_VARIANTS; + } else if (mValueType.equals(Integer.class)) { + typeVariants = INTEGER_VARIANTS; + } else if (mValueType.equals(Double.class)) { + typeVariants = DOUBLE_VARIANTS; + } else { + typeVariants = new Class[1]; + typeVariants[0] = mValueType; + } + for (Class typeVariant : typeVariants) { + args[0] = typeVariant; + try { + returnVal = targetClass.getMethod(methodName, args); + mValueType = typeVariant; + return returnVal; + } catch (Throwable e) { + try { + returnVal = targetClass.getDeclaredMethod(methodName, args); + returnVal.setAccessible(true); + mValueType = typeVariant; + return returnVal; + } catch (Throwable e2) { + // Swallow the error and keep trying other variants + } + } + } + } + + return returnVal; + } + + private Method setupSetterOrGetter(Class targetClass, HashMap> propertyMapMap, String prefix, Class valueType) { + Method setterOrGetter = null; + try { + mPropertyMapLock.writeLock().lock(); + HashMap propertyMap = propertyMapMap.get(targetClass); + if (propertyMap != null) { + setterOrGetter = propertyMap.get(mPropertyName); + } + if (setterOrGetter == null) { + setterOrGetter = getPropertyFunction(targetClass, prefix, valueType); + if (propertyMap == null) { + propertyMap = new HashMap(); + propertyMapMap.put(targetClass, propertyMap); + } + propertyMap.put(mPropertyName, setterOrGetter); + } + } finally { + mPropertyMapLock.writeLock().unlock(); + } + return setterOrGetter; + } + + void setupSetter(Class targetClass) { + mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", mValueType); + } + + private void setupGetter(Class targetClass) { + mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null); + } + + @SuppressWarnings("unchecked") + void setupSetterAndGetter(Object target) { + if (mProperty != null) { + try { + Object testValue = mProperty.get(target); + for (Keyframe kf : mKeyframeSet.mKeyframes) { + if (!kf.hasValue()) { + kf.setValue(mProperty.get(target)); + } + } + return; + } catch (Throwable e) { + mProperty = null; + } + } + Class targetClass = target.getClass(); + if (mSetter == null) { + setupSetter(targetClass); + } + for (Keyframe kf : mKeyframeSet.mKeyframes) { + if (!kf.hasValue()) { + if (mGetter == null) { + setupGetter(targetClass); + if (mGetter == null) { + return; + } + } + try { + kf.setValue(mGetter.invoke(target)); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + } + + @SuppressWarnings("unchecked") + private void setupValue(Object target, Keyframe kf) { + if (mProperty != null) { + kf.setValue(mProperty.get(target)); + } + try { + if (mGetter == null) { + Class targetClass = target.getClass(); + setupGetter(targetClass); + if (mGetter == null) { + return; + } + } + kf.setValue(mGetter.invoke(target)); + } catch (Throwable e) { + e.printStackTrace(); + } + } + + void setupStartValue(Object target) { + setupValue(target, mKeyframeSet.mKeyframes.get(0)); + } + + void setupEndValue(Object target) { + setupValue(target, mKeyframeSet.mKeyframes.get(mKeyframeSet.mKeyframes.size() - 1)); + } + + @Override + public PropertyValuesHolder clone() { + try { + PropertyValuesHolder newPVH = (PropertyValuesHolder) super.clone(); + newPVH.mPropertyName = mPropertyName; + newPVH.mProperty = mProperty; + newPVH.mKeyframeSet = mKeyframeSet.clone(); + newPVH.mEvaluator = mEvaluator; + return newPVH; + } catch (CloneNotSupportedException e) { + return null; + } + } + + @SuppressWarnings("unchecked") + void setAnimatedValue(Object target) { + if (mProperty != null) { + mProperty.set(target, getAnimatedValue()); + } + if (mSetter != null) { + try { + mTmpValueArray[0] = getAnimatedValue(); + mSetter.invoke(target, mTmpValueArray); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + void init() { + if (mEvaluator == null) { + mEvaluator = (mValueType == Integer.class) ? sIntEvaluator : (mValueType == Float.class) ? sFloatEvaluator : null; + } + if (mEvaluator != null) { + mKeyframeSet.setEvaluator(mEvaluator); + } + } + + public void setEvaluator(TypeEvaluator evaluator) { + mEvaluator = evaluator; + mKeyframeSet.setEvaluator(evaluator); + } + + void calculateValue(float fraction) { + mAnimatedValue = mKeyframeSet.getValue(fraction); + } + + public void setPropertyName(String propertyName) { + mPropertyName = propertyName; + } + + public void setProperty(Property property) { + mProperty = property; + } + + public String getPropertyName() { + return mPropertyName; + } + + Object getAnimatedValue() { + return mAnimatedValue; + } + + @Override + public String toString() { + return mPropertyName + ": " + mKeyframeSet.toString(); + } + + static String getMethodName(String prefix, String propertyName) { + if (propertyName == null || propertyName.length() == 0) { + return prefix; + } + char firstLetter = Character.toUpperCase(propertyName.charAt(0)); + String theRest = propertyName.substring(1); + return prefix + firstLetter + theRest; + } + + static class IntPropertyValuesHolder extends PropertyValuesHolder { + private static final HashMap> sJNISetterPropertyMap = new HashMap>(); + private IntProperty mIntProperty; + + IntKeyframeSet mIntKeyframeSet; + int mIntAnimatedValue; + + public IntPropertyValuesHolder(String propertyName, IntKeyframeSet keyframeSet) { + super(propertyName); + mValueType = int.class; + mKeyframeSet = keyframeSet; + mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet; + } + + public IntPropertyValuesHolder(Property property, IntKeyframeSet keyframeSet) { + super(property); + mValueType = int.class; + mKeyframeSet = keyframeSet; + mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet; + if (property instanceof IntProperty) { + mIntProperty = (IntProperty) mProperty; + } + } + + public IntPropertyValuesHolder(String propertyName, int... values) { + super(propertyName); + setIntValues(values); + } + + public IntPropertyValuesHolder(Property property, int... values) { + super(property); + setIntValues(values); + if (property instanceof IntProperty) { + mIntProperty = (IntProperty) mProperty; + } + } + + @Override + public void setIntValues(int... values) { + super.setIntValues(values); + mIntKeyframeSet = (IntKeyframeSet) mKeyframeSet; + } + + @Override + void calculateValue(float fraction) { + mIntAnimatedValue = mIntKeyframeSet.getIntValue(fraction); + } + + @Override + Object getAnimatedValue() { + return mIntAnimatedValue; + } + + @Override + public IntPropertyValuesHolder clone() { + IntPropertyValuesHolder newPVH = (IntPropertyValuesHolder) super.clone(); + newPVH.mIntKeyframeSet = (IntKeyframeSet) newPVH.mKeyframeSet; + return newPVH; + } + + @SuppressWarnings("unchecked") + @Override + void setAnimatedValue(Object target) { + if (mIntProperty != null) { + mIntProperty.setValue(target, mIntAnimatedValue); + return; + } + if (mProperty != null) { + mProperty.set(target, mIntAnimatedValue); + return; + } + if (mSetter != null) { + try { + mTmpValueArray[0] = mIntAnimatedValue; + mSetter.invoke(target, mTmpValueArray); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + @Override + void setupSetter(Class targetClass) { + if (mProperty != null) { + return; + } + + super.setupSetter(targetClass); + } + } + + static class FloatPropertyValuesHolder extends PropertyValuesHolder { + + private static final HashMap> sJNISetterPropertyMap = new HashMap>(); + private FloatProperty10 mFloatProperty; + + FloatKeyframeSet mFloatKeyframeSet; + float mFloatAnimatedValue; + + public FloatPropertyValuesHolder(String propertyName, FloatKeyframeSet keyframeSet) { + super(propertyName); + mValueType = float.class; + mKeyframeSet = keyframeSet; + mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet; + } + + public FloatPropertyValuesHolder(Property property, FloatKeyframeSet keyframeSet) { + super(property); + mValueType = float.class; + mKeyframeSet = keyframeSet; + mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet; + if (property instanceof FloatProperty10) { + mFloatProperty = (FloatProperty10) mProperty; + } + } + + public FloatPropertyValuesHolder(String propertyName, float... values) { + super(propertyName); + setFloatValues(values); + } + + public FloatPropertyValuesHolder(Property property, float... values) { + super(property); + setFloatValues(values); + if (property instanceof FloatProperty10) { + mFloatProperty = (FloatProperty10) mProperty; + } + } + + @Override + public void setFloatValues(float... values) { + super.setFloatValues(values); + mFloatKeyframeSet = (FloatKeyframeSet) mKeyframeSet; + } + + @Override + void calculateValue(float fraction) { + mFloatAnimatedValue = mFloatKeyframeSet.getFloatValue(fraction); + } + + @Override + Object getAnimatedValue() { + return mFloatAnimatedValue; + } + + @Override + public FloatPropertyValuesHolder clone() { + FloatPropertyValuesHolder newPVH = (FloatPropertyValuesHolder) super.clone(); + newPVH.mFloatKeyframeSet = (FloatKeyframeSet) newPVH.mKeyframeSet; + return newPVH; + } + + @SuppressWarnings("unchecked") + @Override + void setAnimatedValue(Object target) { + if (mFloatProperty != null) { + mFloatProperty.setValue(target, mFloatAnimatedValue); + return; + } + if (mProperty != null) { + mProperty.set(target, mFloatAnimatedValue); + return; + } + if (mSetter != null) { + try { + mTmpValueArray[0] = mFloatAnimatedValue; + mSetter.invoke(target, mTmpValueArray); + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + @Override + void setupSetter(Class targetClass) { + if (mProperty != null) { + return; + } + super.setupSetter(targetClass); + } + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/ReflectiveProperty.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/ReflectiveProperty.java new file mode 100644 index 00000000..47b65aac --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/ReflectiveProperty.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.Animation; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Internal class to automatically generate a Property for a given class/name pair, given the + * specification of {@link Property#of(java.lang.Class, java.lang.Class, java.lang.String)} + */ +class ReflectiveProperty extends Property { + + private static final String PREFIX_GET = "get"; + private static final String PREFIX_IS = "is"; + private static final String PREFIX_SET = "set"; + private Method mSetter; + private Method mGetter; + private Field mField; + + /** + * For given property name 'name', look for getName/isName method or 'name' field. + * Also look for setName method (optional - could be readonly). Failing method getters and + * field results in throwing NoSuchPropertyException. + * + * @param propertyHolder The class on which the methods or field are found + * @param name The name of the property, where this name is capitalized and appended to + * "get" and "is to search for the appropriate methods. If the get/is methods are not found, + * the constructor will search for a field with that exact name. + */ + public ReflectiveProperty(Class propertyHolder, Class valueType, String name) { + // TODO: cache reflection info for each new class/name pair + super(valueType, name); + char firstLetter = Character.toUpperCase(name.charAt(0)); + String theRest = name.substring(1); + String capitalizedName = firstLetter + theRest; + String getterName = PREFIX_GET + capitalizedName; + try { + mGetter = propertyHolder.getMethod(getterName, (Class[]) null); + } catch (NoSuchMethodException e) { + try { + /* The native implementation uses JNI to do reflection, which allows access to private methods. + * getDeclaredMethod(..) does not find superclass methods, so it's implemented as a fallback. + */ + mGetter = propertyHolder.getDeclaredMethod(getterName, (Class[]) null); + mGetter.setAccessible(true); + } catch (NoSuchMethodException e2) { + // getName() not available - try isName() instead + getterName = PREFIX_IS + capitalizedName; + try { + mGetter = propertyHolder.getMethod(getterName, (Class[]) null); + } catch (NoSuchMethodException e3) { + try { + /* The native implementation uses JNI to do reflection, which allows access to private methods. + * getDeclaredMethod(..) does not find superclass methods, so it's implemented as a fallback. + */ + mGetter = propertyHolder.getDeclaredMethod(getterName, (Class[]) null); + mGetter.setAccessible(true); + } catch (NoSuchMethodException e4) { + // Try public field instead + try { + mField = propertyHolder.getField(name); + Class fieldType = mField.getType(); + if (!typesMatch(valueType, fieldType)) { + throw new NoSuchPropertyException("Underlying type (" + fieldType + ") " + + "does not match Property type (" + valueType + ")"); + } + return; + } catch (NoSuchFieldException e5) { + // no way to access property - throw appropriate exception + throw new NoSuchPropertyException("No accessor method or field found for" + + " property with name " + name); + } + } + } + } + } + Class getterType = mGetter.getReturnType(); + // Check to make sure our getter type matches our valueType + if (!typesMatch(valueType, getterType)) { + throw new NoSuchPropertyException("Underlying type (" + getterType + ") " + + "does not match Property type (" + valueType + ")"); + } + String setterName = PREFIX_SET + capitalizedName; + try { + // mSetter = propertyHolder.getMethod(setterName, getterType); + // The native implementation uses JNI to do reflection, which allows access to private methods. + mSetter = propertyHolder.getDeclaredMethod(setterName, getterType); + mSetter.setAccessible(true); + } catch (NoSuchMethodException ignored) { + // Okay to not have a setter - just a readonly property + } + } + + /** + * Utility method to check whether the type of the underlying field/method on the target + * object matches the type of the Property. The extra checks for primitive types are because + * generics will force the Property type to be a class, whereas the type of the underlying + * method/field will probably be a primitive type instead. Accept float as matching Float, + * etc. + */ + private boolean typesMatch(Class valueType, Class getterType) { + if (getterType != valueType) { + if (getterType.isPrimitive()) { + return (getterType == float.class && valueType == Float.class) || + (getterType == int.class && valueType == Integer.class) || + (getterType == boolean.class && valueType == Boolean.class) || + (getterType == long.class && valueType == Long.class) || + (getterType == double.class && valueType == Double.class) || + (getterType == short.class && valueType == Short.class) || + (getterType == byte.class && valueType == Byte.class) || + (getterType == char.class && valueType == Character.class); + } + return false; + } + return true; + } + + @Override + public void set(T object, V value) { + if (mSetter != null) { + try { + mSetter.invoke(object, value); + } catch (IllegalAccessException e) { + throw new AssertionError(); + } catch (InvocationTargetException e) { + throw new RuntimeException(e.getCause()); + } + } else if (mField != null) { + try { + mField.set(object, value); + } catch (IllegalAccessException e) { + throw new AssertionError(); + } + } else { + throw new UnsupportedOperationException("Property " + getName() +" is read-only"); + } + } + + @Override + public V get(T object) { + if (mGetter != null) { + try { + return (V) mGetter.invoke(object, (Object[])null); + } catch (IllegalAccessException e) { + throw new AssertionError(); + } catch (InvocationTargetException e) { + throw new RuntimeException(e.getCause()); + } + } else if (mField != null) { + try { + return (V) mField.get(object); + } catch (IllegalAccessException e) { + throw new AssertionError(); + } + } + // Should not get here: there should always be a non-null getter or field + throw new AssertionError(); + } + + /** + * Returns false if there is no setter or public field underlying this Property. + */ + @Override + public boolean isReadOnly() { + return (mSetter == null && mField == null); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/TypeEvaluator.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/TypeEvaluator.java new file mode 100644 index 00000000..305f8ad8 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/TypeEvaluator.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.Animation; + +public interface TypeEvaluator { + T evaluate(float fraction, T startValue, T endValue); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/ValueAnimator.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/ValueAnimator.java new file mode 100644 index 00000000..ec464888 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/ValueAnimator.java @@ -0,0 +1,675 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.Animation; + +import android.os.Looper; +import android.util.AndroidRuntimeException; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; + +import org.telegram.messenger.AndroidUtilities; + +import java.util.ArrayList; +import java.util.HashMap; + +public class ValueAnimator extends Animator10 { + + private static float sDurationScale = 1.0f; + static final int STOPPED = 0; + static final int RUNNING = 1; + static final int SEEKED = 2; + + long mStartTime; + long mSeekTime = -1; + private long mPauseTime; + private boolean mResumed = false; + protected static ThreadLocal sAnimationHandler = new ThreadLocal(); + private static final Interpolator sDefaultInterpolator = new AccelerateDecelerateInterpolator(); + private boolean mPlayingBackwards = false; + private int mCurrentIteration = 0; + private float mCurrentFraction = 0f; + private boolean mStartedDelay = false; + private long mDelayStartTime; + int mPlayingState = STOPPED; + private boolean mRunning = false; + private boolean mStarted = false; + private boolean mStartListenersCalled = false; + boolean mInitialized = false; + + private long mDuration = (long)(300 * sDurationScale); + private long mUnscaledDuration = 300; + private long mStartDelay = 0; + private long mUnscaledStartDelay = 0; + private int mRepeatCount = 0; + private int mRepeatMode = RESTART; + private Interpolator mInterpolator = sDefaultInterpolator; + private ArrayList mUpdateListeners = null; + PropertyValuesHolder[] mValues; + HashMap mValuesMap; + + public static final int RESTART = 1; + public static final int REVERSE = 2; + public static final int INFINITE = -1; + + public static void setDurationScale(float durationScale) { + sDurationScale = durationScale; + } + + public static float getDurationScale() { + return sDurationScale; + } + + public ValueAnimator() { + + } + + public static ValueAnimator ofInt(int... values) { + ValueAnimator anim = new ValueAnimator(); + anim.setIntValues(values); + return anim; + } + + public static ValueAnimator ofFloat(float... values) { + ValueAnimator anim = new ValueAnimator(); + anim.setFloatValues(values); + return anim; + } + + public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values) { + ValueAnimator anim = new ValueAnimator(); + anim.setValues(values); + return anim; + } + + public static ValueAnimator ofObject(TypeEvaluator evaluator, Object... values) { + ValueAnimator anim = new ValueAnimator(); + anim.setObjectValues(values); + anim.setEvaluator(evaluator); + return anim; + } + + public void setIntValues(int... values) { + if (values == null || values.length == 0) { + return; + } + if (mValues == null || mValues.length == 0) { + setValues(PropertyValuesHolder.ofInt("", values)); + } else { + PropertyValuesHolder valuesHolder = mValues[0]; + valuesHolder.setIntValues(values); + } + mInitialized = false; + } + + public void setFloatValues(float... values) { + if (values == null || values.length == 0) { + return; + } + if (mValues == null || mValues.length == 0) { + setValues(PropertyValuesHolder.ofFloat("", values)); + } else { + PropertyValuesHolder valuesHolder = mValues[0]; + valuesHolder.setFloatValues(values); + } + mInitialized = false; + } + + public void setObjectValues(Object... values) { + if (values == null || values.length == 0) { + return; + } + if (mValues == null || mValues.length == 0) { + setValues(PropertyValuesHolder.ofObject("", null, values)); + } else { + PropertyValuesHolder valuesHolder = mValues[0]; + valuesHolder.setObjectValues(values); + } + mInitialized = false; + } + + public void setValues(PropertyValuesHolder... values) { + int numValues = values.length; + mValues = values; + mValuesMap = new HashMap(numValues); + for (PropertyValuesHolder valuesHolder : values) { + mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder); + } + mInitialized = false; + } + + public PropertyValuesHolder[] getValues() { + return mValues; + } + + void initAnimation() { + if (!mInitialized) { + int numValues = mValues.length; + for (PropertyValuesHolder mValue : mValues) { + mValue.init(); + } + mInitialized = true; + } + } + + public ValueAnimator setDuration(long duration) { + if (duration < 0) { + throw new IllegalArgumentException("Animators cannot have negative duration: " + duration); + } + mUnscaledDuration = duration; + mDuration = (long)(duration * sDurationScale); + return this; + } + + public long getDuration() { + return mUnscaledDuration; + } + + public void setCurrentPlayTime(long playTime) { + initAnimation(); + long currentTime = AnimationUtils.currentAnimationTimeMillis(); + if (mPlayingState != RUNNING) { + mSeekTime = playTime; + mPlayingState = SEEKED; + } + mStartTime = currentTime - playTime; + doAnimationFrame(currentTime); + } + + public long getCurrentPlayTime() { + if (!mInitialized || mPlayingState == STOPPED) { + return 0; + } + return AnimationUtils.currentAnimationTimeMillis() - mStartTime; + } + + @SuppressWarnings("unchecked") + protected static class AnimationHandler implements Runnable { + + protected final ArrayList mAnimations = new ArrayList(); + private final ArrayList mTmpAnimations = new ArrayList(); + protected final ArrayList mPendingAnimations = new ArrayList(); + protected final ArrayList mDelayedAnims = new ArrayList(); + private final ArrayList mEndingAnims = new ArrayList(); + private final ArrayList mReadyAnims = new ArrayList(); + + private boolean mAnimationScheduled; + + public void start() { + scheduleAnimation(); + } + + private void doAnimationFrame(long frameTime) { + while (mPendingAnimations.size() > 0) { + ArrayList pendingCopy = (ArrayList) mPendingAnimations.clone(); + mPendingAnimations.clear(); + int count = pendingCopy.size(); + for (ValueAnimator anim : pendingCopy) { + if (anim.mStartDelay == 0) { + anim.startAnimation(this); + } else { + mDelayedAnims.add(anim); + } + } + } + + int numDelayedAnims = mDelayedAnims.size(); + for (ValueAnimator anim : mDelayedAnims) { + if (anim.delayedAnimationFrame(frameTime)) { + mReadyAnims.add(anim); + } + } + int numReadyAnims = mReadyAnims.size(); + if (numReadyAnims > 0) { + for (ValueAnimator anim : mReadyAnims) { + anim.startAnimation(this); + anim.mRunning = true; + mDelayedAnims.remove(anim); + } + mReadyAnims.clear(); + } + + int numAnims = mAnimations.size(); + for (ValueAnimator mAnimation : mAnimations) { + mTmpAnimations.add(mAnimation); + } + for (int i = 0; i < numAnims; ++i) { + ValueAnimator anim = mTmpAnimations.get(i); + if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) { + mEndingAnims.add(anim); + } + } + mTmpAnimations.clear(); + if (mEndingAnims.size() > 0) { + for (ValueAnimator mEndingAnim : mEndingAnims) { + mEndingAnim.endAnimation(this); + } + mEndingAnims.clear(); + } + + if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) { + scheduleAnimation(); + } + } + + @Override + public void run() { + mAnimationScheduled = false; + doAnimationFrame(System.nanoTime() / 1000000); + } + + private void scheduleAnimation() { + if (!mAnimationScheduled) { + AndroidUtilities.runOnUIThread(this); + mAnimationScheduled = true; + } + } + } + + public long getStartDelay() { + return mUnscaledStartDelay; + } + + public void setStartDelay(long startDelay) { + this.mStartDelay = (long)(startDelay * sDurationScale); + mUnscaledStartDelay = startDelay; + } + + public Object getAnimatedValue() { + if (mValues != null && mValues.length > 0) { + return mValues[0].getAnimatedValue(); + } + return null; + } + + public Object getAnimatedValue(String propertyName) { + PropertyValuesHolder valuesHolder = mValuesMap.get(propertyName); + if (valuesHolder != null) { + return valuesHolder.getAnimatedValue(); + } else { + return null; + } + } + + public void setRepeatCount(int value) { + mRepeatCount = value; + } + + public int getRepeatCount() { + return mRepeatCount; + } + + public void setRepeatMode(int value) { + mRepeatMode = value; + } + + public int getRepeatMode() { + return mRepeatMode; + } + + public void addUpdateListener(AnimatorUpdateListener listener) { + if (mUpdateListeners == null) { + mUpdateListeners = new ArrayList(); + } + mUpdateListeners.add(listener); + } + + public void removeAllUpdateListeners() { + if (mUpdateListeners == null) { + return; + } + mUpdateListeners.clear(); + mUpdateListeners = null; + } + + public void removeUpdateListener(AnimatorUpdateListener listener) { + if (mUpdateListeners == null) { + return; + } + mUpdateListeners.remove(listener); + if (mUpdateListeners.size() == 0) { + mUpdateListeners = null; + } + } + + @Override + public void setInterpolator(Interpolator value) { + if (value != null) { + mInterpolator = value; + } else { + mInterpolator = new LinearInterpolator(); + } + } + + @Override + public Interpolator getInterpolator() { + return mInterpolator; + } + + public void setEvaluator(TypeEvaluator value) { + if (value != null && mValues != null && mValues.length > 0) { + mValues[0].setEvaluator(value); + } + } + + @SuppressWarnings("unchecked") + private void notifyStartListeners() { + if (mListeners != null && !mStartListenersCalled) { + ArrayList tmpListeners = (ArrayList) mListeners.clone(); + int numListeners = tmpListeners.size(); + for (AnimatorListener tmpListener : tmpListeners) { + tmpListener.onAnimationStart(this); + } + } + mStartListenersCalled = true; + } + + private void start(boolean playBackwards) { + if (Looper.myLooper() == null) { + throw new AndroidRuntimeException("Animators may only be run on Looper threads"); + } + mPlayingBackwards = playBackwards; + mCurrentIteration = 0; + mPlayingState = STOPPED; + mStarted = true; + mStartedDelay = false; + mPaused = false; + AnimationHandler animationHandler = getOrCreateAnimationHandler(); + animationHandler.mPendingAnimations.add(this); + if (mStartDelay == 0) { + setCurrentPlayTime(0); + mPlayingState = STOPPED; + mRunning = true; + notifyStartListeners(); + } + animationHandler.start(); + } + + @Override + public void start() { + start(false); + } + + @SuppressWarnings("unchecked") + @Override + public void cancel() { + AnimationHandler handler = getOrCreateAnimationHandler(); + if (mPlayingState != STOPPED || handler.mPendingAnimations.contains(this) || handler.mDelayedAnims.contains(this)) { + if ((mStarted || mRunning) && mListeners != null) { + if (!mRunning) { + notifyStartListeners(); + } + ArrayList tmpListeners = (ArrayList) mListeners.clone(); + for (AnimatorListener listener : tmpListeners) { + listener.onAnimationCancel(this); + } + } + endAnimation(handler); + } + } + + @Override + public void end() { + AnimationHandler handler = getOrCreateAnimationHandler(); + if (!handler.mAnimations.contains(this) && !handler.mPendingAnimations.contains(this)) { + mStartedDelay = false; + startAnimation(handler); + mStarted = true; + } else if (!mInitialized) { + initAnimation(); + } + animateValue(mPlayingBackwards ? 0f : 1f); + endAnimation(handler); + } + + @Override + public void resume() { + if (mPaused) { + mResumed = true; + } + super.resume(); + } + + @Override + public void pause() { + boolean previouslyPaused = mPaused; + super.pause(); + if (!previouslyPaused && mPaused) { + mPauseTime = -1; + mResumed = false; + } + } + + @Override + public boolean isRunning() { + return (mPlayingState == RUNNING || mRunning); + } + + @Override + public boolean isStarted() { + return mStarted; + } + + public void reverse() { + mPlayingBackwards = !mPlayingBackwards; + if (mPlayingState == RUNNING) { + long currentTime = AnimationUtils.currentAnimationTimeMillis(); + long currentPlayTime = currentTime - mStartTime; + long timeLeft = mDuration - currentPlayTime; + mStartTime = currentTime - timeLeft; + } else if (mStarted) { + end(); + } else { + start(true); + } + } + + @SuppressWarnings("unchecked") + private void endAnimation(AnimationHandler handler) { + handler.mAnimations.remove(this); + handler.mPendingAnimations.remove(this); + handler.mDelayedAnims.remove(this); + mPlayingState = STOPPED; + mPaused = false; + if ((mStarted || mRunning) && mListeners != null) { + if (!mRunning) { + notifyStartListeners(); + } + ArrayList tmpListeners = (ArrayList) mListeners.clone(); + int numListeners = tmpListeners.size(); + for (AnimatorListener tmpListener : tmpListeners) { + tmpListener.onAnimationEnd(this); + } + } + mRunning = false; + mStarted = false; + mStartListenersCalled = false; + mPlayingBackwards = false; + } + + private void startAnimation(AnimationHandler handler) { + initAnimation(); + handler.mAnimations.add(this); + if (mStartDelay > 0 && mListeners != null) { + notifyStartListeners(); + } + } + + private boolean delayedAnimationFrame(long currentTime) { + if (!mStartedDelay) { + mStartedDelay = true; + mDelayStartTime = currentTime; + } else { + if (mPaused) { + if (mPauseTime < 0) { + mPauseTime = currentTime; + } + return false; + } else if (mResumed) { + mResumed = false; + if (mPauseTime > 0) { + mDelayStartTime += (currentTime - mPauseTime); + } + } + long deltaTime = currentTime - mDelayStartTime; + if (deltaTime > mStartDelay) { + mStartTime = currentTime - (deltaTime - mStartDelay); + mPlayingState = RUNNING; + return true; + } + } + return false; + } + + boolean animationFrame(long currentTime) { + boolean done = false; + switch (mPlayingState) { + case RUNNING: + case SEEKED: + float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f; + if (fraction >= 1f) { + if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) { + if (mListeners != null) { + int numListeners = mListeners.size(); + for (AnimatorListener mListener : mListeners) { + mListener.onAnimationRepeat(this); + } + } + if (mRepeatMode == REVERSE) { + mPlayingBackwards = !mPlayingBackwards; + } + mCurrentIteration += (int)fraction; + fraction = fraction % 1f; + mStartTime += mDuration; + } else { + done = true; + fraction = Math.min(fraction, 1.0f); + } + } + if (mPlayingBackwards) { + fraction = 1f - fraction; + } + animateValue(fraction); + break; + } + + return done; + } + + final boolean doAnimationFrame(long frameTime) { + if (mPlayingState == STOPPED) { + mPlayingState = RUNNING; + if (mSeekTime < 0) { + mStartTime = frameTime; + } else { + mStartTime = frameTime - mSeekTime; + mSeekTime = -1; + } + } + if (mPaused) { + if (mPauseTime < 0) { + mPauseTime = frameTime; + } + return false; + } else if (mResumed) { + mResumed = false; + if (mPauseTime > 0) { + mStartTime += (frameTime - mPauseTime); + } + } + final long currentTime = Math.max(frameTime, mStartTime); + return animationFrame(currentTime); + } + + public float getAnimatedFraction() { + return mCurrentFraction; + } + + void animateValue(float fraction) { + fraction = mInterpolator.getInterpolation(fraction); + mCurrentFraction = fraction; + int numValues = mValues.length; + for (PropertyValuesHolder mValue : mValues) { + mValue.calculateValue(fraction); + } + if (mUpdateListeners != null) { + int numListeners = mUpdateListeners.size(); + for (AnimatorUpdateListener mUpdateListener : mUpdateListeners) { + mUpdateListener.onAnimationUpdate(this); + } + } + } + + @Override + public ValueAnimator clone() { + final ValueAnimator anim = (ValueAnimator) super.clone(); + if (mUpdateListeners != null) { + ArrayList oldListeners = mUpdateListeners; + anim.mUpdateListeners = new ArrayList(); + int numListeners = oldListeners.size(); + for (AnimatorUpdateListener oldListener : oldListeners) { + anim.mUpdateListeners.add(oldListener); + } + } + anim.mSeekTime = -1; + anim.mPlayingBackwards = false; + anim.mCurrentIteration = 0; + anim.mInitialized = false; + anim.mPlayingState = STOPPED; + anim.mStartedDelay = false; + PropertyValuesHolder[] oldValues = mValues; + if (oldValues != null) { + int numValues = oldValues.length; + anim.mValues = new PropertyValuesHolder[numValues]; + anim.mValuesMap = new HashMap(numValues); + for (int i = 0; i < numValues; ++i) { + PropertyValuesHolder newValuesHolder = oldValues[i].clone(); + anim.mValues[i] = newValuesHolder; + anim.mValuesMap.put(newValuesHolder.getPropertyName(), newValuesHolder); + } + } + return anim; + } + + public interface AnimatorUpdateListener { + void onAnimationUpdate(ValueAnimator animation); + } + + public static int getCurrentAnimationsCount() { + AnimationHandler handler = sAnimationHandler.get(); + return handler != null ? handler.mAnimations.size() : 0; + } + + public static void clearAllAnimations() { + AnimationHandler handler = sAnimationHandler.get(); + if (handler != null) { + handler.mAnimations.clear(); + handler.mPendingAnimations.clear(); + handler.mDelayedAnims.clear(); + } + } + + private static AnimationHandler getOrCreateAnimationHandler() { + AnimationHandler handler = sAnimationHandler.get(); + if (handler == null) { + handler = new AnimationHandler(); + sAnimationHandler.set(handler); + } + return handler; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Animation/View10.java b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/View10.java new file mode 100644 index 00000000..540b61a9 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Animation/View10.java @@ -0,0 +1,349 @@ +/* + Copyright 2012 Jake Wharton + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ + +package org.telegram.messenger.Animation; + +import android.graphics.Camera; +import android.graphics.Matrix; +import android.graphics.RectF; +import android.os.Build; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.Transformation; + +import java.lang.ref.WeakReference; +import java.util.WeakHashMap; + +public class View10 extends Animation { + + public static boolean NEED_PROXY = Build.VERSION.SDK_INT < 11; + + private static final WeakHashMap PROXIES = new WeakHashMap<>(); + + public static View10 wrap(View view) { + View10 proxy = PROXIES.get(view); + Animation animation = view.getAnimation(); + if (proxy == null || proxy != animation && animation != null) { + proxy = new View10(view); + PROXIES.put(view, proxy); + } else if (animation == null) { + view.setAnimation(proxy); + } + return proxy; + } + + private final WeakReference mView; + private final Camera mCamera = new Camera(); + private boolean mHasPivot; + + private float mAlpha = 1; + private float mPivotX; + private float mPivotY; + private float mRotationX; + private float mRotationY; + private float mRotationZ; + private float mScaleX = 1; + private float mScaleY = 1; + private float mTranslationX; + private float mTranslationY; + + private final RectF mBefore = new RectF(); + private final RectF mAfter = new RectF(); + private final Matrix mTempMatrix = new Matrix(); + + private View10(View view) { + setDuration(0); + setFillAfter(true); + view.setAnimation(this); + mView = new WeakReference<>(view); + } + + public float getAlpha() { + return mAlpha; + } + + public void setAlpha(float alpha) { + if (mAlpha != alpha) { + mAlpha = alpha; + View view = mView.get(); + if (view != null) { + view.invalidate(); + } + } + } + + public float getPivotX() { + return mPivotX; + } + + public void setPivotX(float pivotX) { + if (!mHasPivot || mPivotX != pivotX) { + prepareForUpdate(); + mHasPivot = true; + mPivotX = pivotX; + invalidateAfterUpdate(); + } + } + + public float getPivotY() { + return mPivotY; + } + + public void setPivotY(float pivotY) { + if (!mHasPivot || mPivotY != pivotY) { + prepareForUpdate(); + mHasPivot = true; + mPivotY = pivotY; + invalidateAfterUpdate(); + } + } + + public float getRotation() { + return mRotationZ; + } + + public void setRotation(float rotation) { + if (mRotationZ != rotation) { + prepareForUpdate(); + mRotationZ = rotation; + invalidateAfterUpdate(); + } + } + + public float getRotationX() { + return mRotationX; + } + + public void setRotationX(float rotationX) { + if (mRotationX != rotationX) { + prepareForUpdate(); + mRotationX = rotationX; + invalidateAfterUpdate(); + } + } + + public float getRotationY() { + return mRotationY; + } + + public void setRotationY(float rotationY) { + if (mRotationY != rotationY) { + prepareForUpdate(); + mRotationY = rotationY; + invalidateAfterUpdate(); + } + } + + public float getScaleX() { + return mScaleX; + } + + public void setScaleX(float scaleX) { + if (mScaleX != scaleX) { + prepareForUpdate(); + mScaleX = scaleX; + invalidateAfterUpdate(); + } + } + + public float getScaleY() { + return mScaleY; + } + + public void setScaleY(float scaleY) { + if (mScaleY != scaleY) { + prepareForUpdate(); + mScaleY = scaleY; + invalidateAfterUpdate(); + } + } + + public int getScrollX() { + View view = mView.get(); + if (view == null) { + return 0; + } + return view.getScrollX(); + } + + public void setScrollX(int value) { + View view = mView.get(); + if (view != null) { + view.scrollTo(value, view.getScrollY()); + } + } + + public int getScrollY() { + View view = mView.get(); + if (view == null) { + return 0; + } + return view.getScrollY(); + } + + public void setScrollY(int value) { + View view = mView.get(); + if (view != null) { + view.scrollTo(view.getScrollX(), value); + } + } + + public float getTranslationX() { + return mTranslationX; + } + + public void setTranslationX(float translationX) { + if (mTranslationX != translationX) { + prepareForUpdate(); + mTranslationX = translationX; + invalidateAfterUpdate(); + } + } + + public float getTranslationY() { + return mTranslationY; + } + + public void setTranslationY(float translationY) { + if (mTranslationY != translationY) { + prepareForUpdate(); + mTranslationY = translationY; + invalidateAfterUpdate(); + } + } + + public float getX() { + View view = mView.get(); + if (view == null) { + return 0; + } + return view.getLeft() + mTranslationX; + } + + public void setX(float x) { + View view = mView.get(); + if (view != null) { + setTranslationX(x - view.getLeft()); + } + } + + public float getY() { + View view = mView.get(); + if (view == null) { + return 0; + } + return view.getTop() + mTranslationY; + } + + public void setY(float y) { + View view = mView.get(); + if (view != null) { + setTranslationY(y - view.getTop()); + } + } + + private void prepareForUpdate() { + View view = mView.get(); + if (view != null) { + computeRect(mBefore, view); + } + } + + private void invalidateAfterUpdate() { + View view = mView.get(); + if (view == null || view.getParent() == null) { + return; + } + + final RectF after = mAfter; + computeRect(after, view); + after.union(mBefore); + + ((View) view.getParent()).invalidate( + (int) Math.floor(after.left), + (int) Math.floor(after.top), + (int) Math.ceil(after.right), + (int) Math.ceil(after.bottom)); + } + + private void computeRect(final RectF r, View view) { + final float w = view.getWidth(); + final float h = view.getHeight(); + + r.set(0, 0, w, h); + + final Matrix m = mTempMatrix; + m.reset(); + transformMatrix(m, view); + mTempMatrix.mapRect(r); + + r.offset(view.getLeft(), view.getTop()); + + if (r.right < r.left) { + final float f = r.right; + r.right = r.left; + r.left = f; + } + if (r.bottom < r.top) { + final float f = r.top; + r.top = r.bottom; + r.bottom = f; + } + } + + private void transformMatrix(Matrix m, View view) { + final float w = view.getWidth(); + final float h = view.getHeight(); + final boolean hasPivot = mHasPivot; + final float pX = hasPivot ? mPivotX : w / 2f; + final float pY = hasPivot ? mPivotY : h / 2f; + + final float rX = mRotationX; + final float rY = mRotationY; + final float rZ = mRotationZ; + if ((rX != 0) || (rY != 0) || (rZ != 0)) { + final Camera camera = mCamera; + camera.save(); + camera.rotateX(rX); + camera.rotateY(rY); + camera.rotateZ(-rZ); + camera.getMatrix(m); + camera.restore(); + m.preTranslate(-pX, -pY); + m.postTranslate(pX, pY); + } + + final float sX = mScaleX; + final float sY = mScaleY; + if ((sX != 1.0f) || (sY != 1.0f)) { + m.postScale(sX, sY); + final float sPX = -(pX / w) * ((sX * w) - w); + final float sPY = -(pY / h) * ((sY * h) - h); + m.postTranslate(sPX, sPY); + } + + m.postTranslate(mTranslationX, mTranslationY); + } + + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + View view = mView.get(); + if (view != null) { + t.setAlpha(mAlpha); + transformMatrix(t.getMatrix(), view); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/AnimatorListenerAdapterProxy.java b/TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/AnimatorListenerAdapterProxy.java new file mode 100644 index 00000000..4a5c55a1 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/AnimatorListenerAdapterProxy.java @@ -0,0 +1,112 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger.AnimationCompat; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; + +import org.telegram.messenger.Animation.Animator10; +import org.telegram.messenger.Animation.AnimatorListenerAdapter10; +import org.telegram.messenger.Animation.View10; + +public class AnimatorListenerAdapterProxy { + protected Object animatorListenerAdapter; + + public AnimatorListenerAdapterProxy() { + if (View10.NEED_PROXY) { + animatorListenerAdapter = new AnimatorListenerAdapter10() { + @Override + public void onAnimationCancel(Animator10 animation) { + AnimatorListenerAdapterProxy.this.onAnimationCancel(animation); + } + + @Override + public void onAnimationEnd(Animator10 animation) { + AnimatorListenerAdapterProxy.this.onAnimationEnd(animation); + } + + @Override + public void onAnimationRepeat(Animator10 animation) { + AnimatorListenerAdapterProxy.this.onAnimationRepeat(animation); + } + + @Override + public void onAnimationStart(Animator10 animation) { + AnimatorListenerAdapterProxy.this.onAnimationStart(animation); + } + + @Override + public void onAnimationPause(Animator10 animation) { + AnimatorListenerAdapterProxy.this.onAnimationPause(animation); + } + + @Override + public void onAnimationResume(Animator10 animation) { + AnimatorListenerAdapterProxy.this.onAnimationResume(animation); + } + }; + } else { + animatorListenerAdapter = new AnimatorListenerAdapter() { + @Override + public void onAnimationCancel(Animator animation) { + AnimatorListenerAdapterProxy.this.onAnimationCancel(animation); + } + + @Override + public void onAnimationEnd(Animator animation) { + AnimatorListenerAdapterProxy.this.onAnimationEnd(animation); + } + + @Override + public void onAnimationRepeat(Animator animation) { + AnimatorListenerAdapterProxy.this.onAnimationRepeat(animation); + } + + @Override + public void onAnimationStart(Animator animation) { + AnimatorListenerAdapterProxy.this.onAnimationStart(animation); + } + + @Override + public void onAnimationPause(Animator animation) { + AnimatorListenerAdapterProxy.this.onAnimationPause(animation); + } + + @Override + public void onAnimationResume(Animator animation) { + AnimatorListenerAdapterProxy.this.onAnimationResume(animation); + } + }; + } + } + + public void onAnimationCancel(Object animation) { + + } + + public void onAnimationEnd(Object animation) { + + } + + public void onAnimationRepeat(Object animation) { + + } + + public void onAnimationStart(Object animation) { + + } + + public void onAnimationPause(Object animation) { + + } + + public void onAnimationResume(Object animation) { + + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/AnimatorSetProxy.java b/TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/AnimatorSetProxy.java new file mode 100644 index 00000000..e6cccb0a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/AnimatorSetProxy.java @@ -0,0 +1,137 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger.AnimationCompat; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.view.animation.Interpolator; + +import org.telegram.messenger.Animation.Animator10; +import org.telegram.messenger.Animation.AnimatorListenerAdapter10; +import org.telegram.messenger.Animation.AnimatorSet10; +import org.telegram.messenger.Animation.View10; + +import java.lang.reflect.Array; +import java.util.ArrayList; + +public class AnimatorSetProxy { + + private Object animatorSet; + + public static T[] copyOf(U[] original, int newLength, Class newType) { + return copyOfRange(original, 0, newLength, newType); + } + + @SuppressWarnings("unchecked") + public static T[] copyOfRange(U[] original, int start, int end, Class newType) { + if (start > end) { + throw new IllegalArgumentException(); + } + int originalLength = original.length; + if (start < 0 || start > originalLength) { + throw new ArrayIndexOutOfBoundsException(); + } + int resultLength = end - start; + int copyLength = Math.min(resultLength, originalLength - start); + T[] result = (T[]) Array.newInstance(newType.getComponentType(), resultLength); + System.arraycopy(original, start, result, 0, copyLength); + return result; + } + + public AnimatorSetProxy() { + if (View10.NEED_PROXY) { + animatorSet = new AnimatorSet10(); + } else { + animatorSet = new AnimatorSet(); + } + } + + @SuppressWarnings("unchecked") + public void playTogether(Object... items) { + if (View10.NEED_PROXY) { + Animator10[] animators = copyOf(items, items.length, Animator10[].class); + ((AnimatorSet10) animatorSet).playTogether(animators); + } else { + Animator[] animators = copyOf(items, items.length, Animator[].class); + ((AnimatorSet) animatorSet).playTogether(animators); + } + } + + public void playTogether(ArrayList items) { + if (View10.NEED_PROXY) { + ArrayList animators = new ArrayList<>(); + for (Object obj : items) { + animators.add((Animator10)obj); + } + ((AnimatorSet10) animatorSet).playTogether(animators); + } else { + ArrayList animators = new ArrayList<>(); + for (Object obj : items) { + animators.add((Animator)obj); + } + ((AnimatorSet) animatorSet).playTogether(animators); + } + } + + public AnimatorSetProxy setDuration(long duration) { + if (View10.NEED_PROXY) { + ((AnimatorSet10) animatorSet).setDuration(duration); + } else { + ((AnimatorSet) animatorSet).setDuration(duration); + } + return this; + } + + public AnimatorSetProxy setStartDelay(long delay) { + if (View10.NEED_PROXY) { + ((AnimatorSet10) animatorSet).setStartDelay(delay); + } else { + ((AnimatorSet) animatorSet).setStartDelay(delay); + } + return this; + } + + public void start() { + if (View10.NEED_PROXY) { + ((AnimatorSet10) animatorSet).start(); + } else { + ((AnimatorSet) animatorSet).start(); + } + } + + public void cancel() { + if (View10.NEED_PROXY) { + ((AnimatorSet10) animatorSet).cancel(); + } else { + ((AnimatorSet) animatorSet).cancel(); + } + } + + public void addListener(AnimatorListenerAdapterProxy listener) { + if (View10.NEED_PROXY) { + ((AnimatorSet10) animatorSet).addListener((AnimatorListenerAdapter10) listener.animatorListenerAdapter); + } else { + ((AnimatorSet) animatorSet).addListener((AnimatorListenerAdapter) listener.animatorListenerAdapter); + } + } + + public void setInterpolator(Interpolator interpolator) { + if (View10.NEED_PROXY) { + ((AnimatorSet10) animatorSet).setInterpolator(interpolator); + } else { + ((AnimatorSet) animatorSet).setInterpolator(interpolator); + } + } + + @Override + public boolean equals(Object o) { + return animatorSet == o; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/ObjectAnimatorProxy.java b/TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/ObjectAnimatorProxy.java new file mode 100644 index 00000000..8bf69db6 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/ObjectAnimatorProxy.java @@ -0,0 +1,130 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger.AnimationCompat; + +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; +import android.view.animation.Interpolator; + +import org.telegram.messenger.Animation.AnimatorListenerAdapter10; +import org.telegram.messenger.Animation.ObjectAnimator10; +import org.telegram.messenger.Animation.View10; + +public class ObjectAnimatorProxy { + + private Object objectAnimator; + + public ObjectAnimatorProxy(Object animator) { + objectAnimator = animator; + } + + public static Object ofFloat(Object target, String propertyName, float... values) { + if (View10.NEED_PROXY) { + return ObjectAnimator10.ofFloat(target, propertyName, values); + } else { + return ObjectAnimator.ofFloat(target, propertyName, values); + } + } + + public static Object ofInt(Object target, String propertyName, int... values) { + if (View10.NEED_PROXY) { + return ObjectAnimator10.ofInt(target, propertyName, values); + } else { + return ObjectAnimator.ofInt(target, propertyName, values); + } + } + + public static ObjectAnimatorProxy ofFloatProxy(Object target, String propertyName, float... values) { + if (View10.NEED_PROXY) { + return new ObjectAnimatorProxy(ObjectAnimator10.ofFloat(target, propertyName, values)); + } else { + return new ObjectAnimatorProxy(ObjectAnimator.ofFloat(target, propertyName, values)); + } + } + + public static ObjectAnimatorProxy ofIntProxy(Object target, String propertyName, int... values) { + if (View10.NEED_PROXY) { + return new ObjectAnimatorProxy(ObjectAnimator10.ofInt(target, propertyName, values)); + } else { + return new ObjectAnimatorProxy(ObjectAnimator.ofInt(target, propertyName, values)); + } + } + + public ObjectAnimatorProxy setDuration(long duration) { + if (View10.NEED_PROXY) { + ((ObjectAnimator10) objectAnimator).setDuration(duration); + } else { + ((ObjectAnimator) objectAnimator).setDuration(duration); + } + return this; + } + + public void setInterpolator(Interpolator value) { + if (View10.NEED_PROXY) { + ((ObjectAnimator10) objectAnimator).setInterpolator(value); + } else { + ((ObjectAnimator) objectAnimator).setInterpolator(value); + } + } + + public ObjectAnimatorProxy start() { + if (View10.NEED_PROXY) { + ((ObjectAnimator10) objectAnimator).start(); + } else { + ((ObjectAnimator) objectAnimator).start(); + } + return this; + } + + public void setAutoCancel(boolean cancel) { + if (View10.NEED_PROXY) { + ((ObjectAnimator10) objectAnimator).setAutoCancel(cancel); + } else { + ((ObjectAnimator) objectAnimator).setAutoCancel(cancel); + } + } + + public boolean isRunning() { + if (View10.NEED_PROXY) { + return ((ObjectAnimator10) objectAnimator).isRunning(); + } else { + return ((ObjectAnimator) objectAnimator).isRunning(); + } + } + + public void end() { + if (View10.NEED_PROXY) { + ((ObjectAnimator10) objectAnimator).end(); + } else { + ((ObjectAnimator) objectAnimator).end(); + } + } + + public void cancel() { + if (View10.NEED_PROXY) { + ((ObjectAnimator10) objectAnimator).cancel(); + } else { + ((ObjectAnimator) objectAnimator).cancel(); + } + } + + public ObjectAnimatorProxy addListener(AnimatorListenerAdapterProxy listener) { + if (View10.NEED_PROXY) { + ((ObjectAnimator10) objectAnimator).addListener((AnimatorListenerAdapter10) listener.animatorListenerAdapter); + } else { + ((ObjectAnimator) objectAnimator).addListener((AnimatorListenerAdapter) listener.animatorListenerAdapter); + } + return this; + } + + @Override + public boolean equals(Object o) { + return objectAnimator == o; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/ViewProxy.java b/TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/ViewProxy.java new file mode 100644 index 00000000..50a2690f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AnimationCompat/ViewProxy.java @@ -0,0 +1,248 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger.AnimationCompat; + +import android.view.View; + +import org.telegram.messenger.Animation.View10; + +public class ViewProxy { + + public static float getAlpha(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view).getAlpha(); + } else { + return view.getAlpha(); + } + } + + public static void setAlpha(View view, float alpha) { + if (View10.NEED_PROXY) { + View10.wrap(view).setAlpha(alpha); + } else { + view.setAlpha(alpha); + } + } + + public static float getPivotX(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view).getPivotX(); + } else { + return view.getPivotX(); + } + } + + public static void setPivotX(View view, float pivotX) { + if (View10.NEED_PROXY) { + View10.wrap(view).setPivotX(pivotX); + } else { + view.setPivotX(pivotX); + } + } + + public static float getPivotY(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view).getPivotY(); + } else { + return view.getPivotY(); + } + } + + public static void setPivotY(View view, float pivotY) { + if (View10.NEED_PROXY) { + View10.wrap(view).setPivotY(pivotY); + } else { + view.setPivotY(pivotY); + } + } + + public static float getRotation(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view).getRotation(); + } else { + return view.getRotation(); + } + } + + public static void setRotation(View view, float rotation) { + if (View10.NEED_PROXY) { + View10.wrap(view).setRotation(rotation); + } else { + view.setRotation(rotation); + } + } + + public static float getRotationX(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view).getRotationX(); + } else { + return view.getRotationX(); + } + } + + public void setRotationX(View view, float rotationX) { + if (View10.NEED_PROXY) { + View10.wrap(view).setRotationX(rotationX); + } else { + view.setRotationX(rotationX); + } + } + + public static float getRotationY(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view).getRotationY(); + } else { + return view.getRotationY(); + } + } + + public void setRotationY(View view, float rotationY) { + if (View10.NEED_PROXY) { + View10.wrap(view).setRotationY(rotationY); + } else { + view.setRotationY(rotationY); + } + } + + public static float getScaleX(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view).getScaleX(); + } else { + return view.getScaleX(); + } + } + + public static void setScaleX(View view, float scaleX) { + if (View10.NEED_PROXY) { + View10.wrap(view).setScaleX(scaleX); + } else { + view.setScaleX(scaleX); + } + } + + public static float getScaleY(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view).getScaleY(); + } else { + return view.getScaleY(); + } + } + + public static void setScaleY(View view, float scaleY) { + if (View10.NEED_PROXY) { + View10.wrap(view).setScaleY(scaleY); + } else { + view.setScaleY(scaleY); + } + } + + public static int getScrollX(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view).getScrollX(); + } else { + return view.getScrollX(); + } + } + + public static void setScrollX(View view, int value) { + if (View10.NEED_PROXY) { + View10.wrap(view).setScrollX(value); + } else { + view.setScrollX(value); + } + } + + public static int getScrollY(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view).getScrollY(); + } else { + return view.getScrollY(); + } + } + + public static void setScrollY(View view, int value) { + if (View10.NEED_PROXY) { + View10.wrap(view).setScrollY(value); + } else { + view.setScrollY(value); + } + } + + public static float getTranslationX(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view).getTranslationX(); + } else { + return view.getTranslationX(); + } + } + + public static void setTranslationX(View view, float translationX) { + if (View10.NEED_PROXY) { + View10.wrap(view).setTranslationX(translationX); + } else { + view.setTranslationX(translationX); + } + } + + public static float getTranslationY(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view).getTranslationY(); + } else { + return view.getTranslationY(); + } + } + + public static void setTranslationY(View view, float translationY) { + if (View10.NEED_PROXY) { + View10.wrap(view).setTranslationY(translationY); + } else { + view.setTranslationY(translationY); + } + } + + public static float getX(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view).getX(); + } else { + return view.getX(); + } + } + + public static void setX(View view, float x) { + if (View10.NEED_PROXY) { + View10.wrap(view).setX(x); + } else { + view.setX(x); + } + } + + public static float getY(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view).getY(); + } else { + return view.getY(); + } + } + + public static void setY(View view, float y) { + if (View10.NEED_PROXY) { + View10.wrap(view).setY(y); + } else { + view.setY(y); + } + } + + public static Object wrap(View view) { + if (View10.NEED_PROXY) { + return View10.wrap(view); + } else { + return view; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AppStartReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/AppStartReceiver.java new file mode 100644 index 00000000..4a398085 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AppStartReceiver.java @@ -0,0 +1,24 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class AppStartReceiver extends BroadcastReceiver { + public void onReceive(Context context, Intent intent) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + ApplicationLoader.startPushService(); + } + }); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java index d569158f..f097bdec 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ApplicationLoader.java @@ -38,17 +38,17 @@ import org.telegram.ui.Components.ForegroundDetector; import java.io.File; import java.io.RandomAccessFile; -import java.util.Calendar; public class ApplicationLoader extends Application { - private static NetworkAlarm networkAlarm = null; - private static PendingIntent pendingIntent; private static Drawable cachedWallpaper; private static int selectedColor; private static boolean isCustomTheme; private static final Object sync = new Object(); + private static int serviceMessageColor; + private static int serviceSelectedMessageColor; + public static volatile Context applicationContext; public static volatile Handler applicationHandler; private static volatile boolean applicationInited = false; @@ -60,6 +60,7 @@ public class ApplicationLoader extends Application { public static boolean SHOW_ANDROID_EMOJI; public static boolean KEEP_ORIGINAL_FILENAME; public static boolean USE_DEVICE_FONT; + public static boolean ENABLE_TAGS = true; public static boolean isCustomTheme() { return isCustomTheme; @@ -71,9 +72,27 @@ public class ApplicationLoader extends Application { public static void reloadWallpaper() { cachedWallpaper = null; + serviceMessageColor = 0; + ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).edit().remove("serviceMessageColor").commit(); loadWallpaper(); } + private static void calcBackgroundColor() { + int result[] = AndroidUtilities.calcDrawableColor(cachedWallpaper); + serviceMessageColor = result[0]; + serviceSelectedMessageColor = result[1]; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + preferences.edit().putInt("serviceMessageColor", serviceMessageColor).putInt("serviceSelectedMessageColor", serviceSelectedMessageColor).commit(); + } + + public static int getServiceMessageColor() { + return serviceMessageColor; + } + + public static int getServiceSelectedMessageColor() { + return serviceSelectedMessageColor; + } + public static void loadWallpaper() { if (cachedWallpaper != null) { return; @@ -87,6 +106,8 @@ public class ApplicationLoader extends Application { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); int selectedBackground = preferences.getInt("selectedBackground", 1000001); selectedColor = preferences.getInt("selectedColor", 0); + serviceMessageColor = preferences.getInt("serviceMessageColor", 0); + serviceSelectedMessageColor = preferences.getInt("serviceSelectedMessageColor", 0); if (selectedColor == 0) { if (selectedBackground == 1000001) { cachedWallpaper = applicationContext.getResources().getDrawable(R.drawable.background_hd); @@ -111,6 +132,9 @@ public class ApplicationLoader extends Application { } cachedWallpaper = new ColorDrawable(selectedColor); } + if (serviceMessageColor == 0) { + calcBackgroundColor(); + } } } }); @@ -223,7 +247,7 @@ public class ApplicationLoader extends Application { String configPath = getFilesDirFixed().toString(); try { - langCode = LocaleController.getLocaleString(LocaleController.getInstance().getSystemDefaultLocale()); + langCode = LocaleController.getLocaleStringIso639(); deviceModel = Build.MANUFACTURER + Build.MODEL; PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); appVersion = pInfo.versionName + " (" + pInfo.versionCode + ")"; @@ -247,8 +271,11 @@ public class ApplicationLoader extends Application { systemVersion = "SDK Unknown"; } + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + boolean enablePushConnection = preferences.getBoolean("pushConnection", true); + MessagesController.getInstance(); - ConnectionsManager.getInstance().init(BuildVars.BUILD_VERSION, TLRPC.LAYER, BuildVars.APP_ID, deviceModel, systemVersion, appVersion, langCode, configPath, FileLog.getNetworkLogPath(), UserConfig.getClientUserId()); + ConnectionsManager.getInstance().init(BuildVars.BUILD_VERSION, TLRPC.LAYER, BuildVars.APP_ID, deviceModel, systemVersion, appVersion, langCode, configPath, FileLog.getNetworkLogPath(), UserConfig.getClientUserId(), enablePushConnection); if (UserConfig.getCurrentUser() != null) { MessagesController.getInstance().putUser(UserConfig.getCurrentUser(), true); ConnectionsManager.getInstance().applyCountryPortNumber(UserConfig.getCurrentUser().phone); @@ -275,11 +302,7 @@ public class ApplicationLoader extends Application { applicationContext = getApplicationContext(); NativeLoader.initNativeLibs(ApplicationLoader.applicationContext); - try{ - ConnectionsManager.native_setJava(Build.VERSION.SDK_INT == 14 || Build.VERSION.SDK_INT == 15); - } catch (Exception e) { - FileLog.e("tmessages", e); - } + ConnectionsManager.native_setJava(Build.VERSION.SDK_INT == 14 || Build.VERSION.SDK_INT == 15); if (Build.VERSION.SDK_INT >= 14) { new ForegroundDetector(this); @@ -288,7 +311,6 @@ public class ApplicationLoader extends Application { applicationHandler = new Handler(applicationContext.getMainLooper()); //plus databaseHandler = new DatabaseHandler(applicationContext); - //SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); SHOW_ANDROID_EMOJI = plusPreferences.getBoolean("showAndroidEmoji", false); KEEP_ORIGINAL_FILENAME = plusPreferences.getBoolean("keepOriginalFilename", false); @@ -301,53 +323,31 @@ public class ApplicationLoader extends Application { SharedPreferences preferences = applicationContext.getSharedPreferences("Notifications", MODE_PRIVATE); if (preferences.getBoolean("pushService", true)) { - networkAlarm = new NetworkAlarm(); - /*} else { - AlarmManager am = (AlarmManager) applicationContext.getSystemService(Context.ALARM_SERVICE); - Intent i = new Intent(applicationContext, ApplicationLoader.class); - pendingIntent = PendingIntent.getBroadcast(applicationContext, 0, i, 0); - - am.cancel(pendingIntent); - am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), 60000, pendingIntent); - }*/ applicationContext.startService(new Intent(applicationContext, NotificationsService.class)); - //if (android.os.Build.VERSION.SDK_INT >= 19) { - ///FileLog.e("ApplicationLoader", "startPushService"); - ///Calendar cal = Calendar.getInstance(); - ///PendingIntent pintent = PendingIntent.getService(applicationContext, 0, new Intent(applicationContext, NotificationsService.class), 0); - ///AlarmManager alarm = (AlarmManager) applicationContext.getSystemService(Context.ALARM_SERVICE); - ///alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 30000, pintent); - //PendingIntent pintent = PendingIntent.getService(applicationContext, 0, new Intent(applicationContext, NotificationsService.class), 0); - //AlarmManager alarm = (AlarmManager)applicationContext.getSystemService(Context.ALARM_SERVICE); - //alarm.cancel(pintent); - //} + if (android.os.Build.VERSION.SDK_INT >= 19) { +// Calendar cal = Calendar.getInstance(); +// PendingIntent pintent = PendingIntent.getService(applicationContext, 0, new Intent(applicationContext, NotificationsService.class), 0); +// AlarmManager alarm = (AlarmManager) applicationContext.getSystemService(Context.ALARM_SERVICE); +// alarm.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), 30000, pintent); + + PendingIntent pintent = PendingIntent.getService(applicationContext, 0, new Intent(applicationContext, NotificationsService.class), 0); + AlarmManager alarm = (AlarmManager)applicationContext.getSystemService(Context.ALARM_SERVICE); + alarm.cancel(pintent); + } } else { stopPushService(); } } public static void stopPushService() { - if (networkAlarm != null) { - networkAlarm = null; - }// else { - // AlarmManager am = (AlarmManager) applicationContext.getSystemService(Context.ALARM_SERVICE); - // am.cancel(pendingIntent); - //} applicationContext.stopService(new Intent(applicationContext, NotificationsService.class)); - ///PendingIntent pintent = PendingIntent.getService(applicationContext, 0, new Intent(applicationContext, NotificationsService.class), 0); - ///AlarmManager alarm = (AlarmManager)applicationContext.getSystemService(Context.ALARM_SERVICE); - ///alarm.cancel(pintent); + PendingIntent pintent = PendingIntent.getService(applicationContext, 0, new Intent(applicationContext, NotificationsService.class), 0); + AlarmManager alarm = (AlarmManager)applicationContext.getSystemService(Context.ALARM_SERVICE); + alarm.cancel(pintent); } - public static void setAlarm(int timeout) { - FileLog.d("tmessages", "setting alarm to wake us in " + String.valueOf(timeout) + "ms"); - - if (networkAlarm != null) { - networkAlarm.setAlarm(applicationContext, timeout); - } - } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); @@ -363,16 +363,23 @@ public class ApplicationLoader extends Application { AndroidUtilities.runOnUIThread(new Runnable() { @Override public void run() { - if (checkPlayServices()) { - if (UserConfig.pushString == null || UserConfig.pushString.length() == 0) { + if (checkPlayServices()) { + if (UserConfig.pushString != null && UserConfig.pushString.length() != 0) { + FileLog.d("tmessages", "GCM regId = " + UserConfig.pushString); + } else { FileLog.d("tmessages", "GCM Registration not found."); + } + + //if (UserConfig.pushString == null || UserConfig.pushString.length() == 0) { Intent intent = new Intent(applicationContext, GcmRegistrationIntentService.class); startService(intent); + //} else { + // FileLog.d("tmessages", "GCM regId = " + UserConfig.pushString); + //} + } else { + FileLog.d("tmessages", "No valid Google Play Services APK found."); + } } - } else { - FileLog.d("tmessages", "No valid Google Play Services APK found."); - } - } }, 1000); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AuthenticatorService.java b/TMessagesProj/src/main/java/org/telegram/messenger/AuthenticatorService.java new file mode 100644 index 00000000..82bd4f4b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AuthenticatorService.java @@ -0,0 +1,97 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.accounts.AbstractAccountAuthenticator; +import android.accounts.Account; +import android.accounts.AccountAuthenticatorResponse; +import android.accounts.AccountManager; +import android.accounts.NetworkErrorException; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.IBinder; + +public class AuthenticatorService extends Service { + + private static class Authenticator extends AbstractAccountAuthenticator { + private final Context context; + + public Authenticator(Context context) { + super(context); + this.context = context; + } + + @Override + public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) + throws NetworkErrorException { + return null; + } + + @Override + public Bundle getAccountRemovalAllowed(AccountAuthenticatorResponse response, Account account) throws NetworkErrorException { + return super.getAccountRemovalAllowed(response, account); + } + + @Override + public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException { + return null; + } + + @Override + public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { + return null; + } + + @Override + public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) + throws NetworkErrorException { + return null; + } + + @Override + public String getAuthTokenLabel(String authTokenType) { + return null; + } + + @Override + public Bundle hasFeatures(AccountAuthenticatorResponse response, + Account account, String[] features) + throws NetworkErrorException { + return null; + } + + @Override + public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) + throws NetworkErrorException { + return null; + } + + } + + private static Authenticator authenticator = null; + + protected Authenticator getAuthenticator() { + if (authenticator == null) { + authenticator = new Authenticator(this); + } + return authenticator; + } + + + @Override + public IBinder onBind(Intent intent) { + if (intent.getAction().equals(AccountManager.ACTION_AUTHENTICATOR_INTENT)) { + return getAuthenticator().getIBinder(); + } else { + return null; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AutoMessageHeardReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/AutoMessageHeardReceiver.java new file mode 100644 index 00000000..a00576b7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AutoMessageHeardReceiver.java @@ -0,0 +1,27 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class AutoMessageHeardReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + ApplicationLoader.postInitApplication(); + long dialog_id = intent.getLongExtra("dialog_id", 0); + int max_id = intent.getIntExtra("max_id", 0); + if (dialog_id == 0 || max_id == 0) { + return; + } + MessagesController.getInstance().markDialogAsRead(dialog_id, max_id, max_id, 0, true, false); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/AutoMessageReplyReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/AutoMessageReplyReceiver.java new file mode 100644 index 00000000..1635bd37 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/AutoMessageReplyReceiver.java @@ -0,0 +1,38 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.RemoteInput; + +public class AutoMessageReplyReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + ApplicationLoader.postInitApplication(); + Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); + if (remoteInput == null) { + return; + } + CharSequence text = remoteInput.getCharSequence(NotificationsController.EXTRA_VOICE_REPLY); + if (text == null || text.length() == 0) { + return; + } + long dialog_id = intent.getLongExtra("dialog_id", 0); + int max_id = intent.getIntExtra("max_id", 0); + if (dialog_id == 0 || max_id == 0) { + return; + } + SendMessagesHelper.getInstance().sendMessage(text.toString(), dialog_id, null, null, true, false, null, null, null); + MessagesController.getInstance().markDialogAsRead(dialog_id, max_id, max_id, 0, true, false); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Bitmaps.java b/TMessagesProj/src/main/java/org/telegram/messenger/Bitmaps.java new file mode 100644 index 00000000..fe372462 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Bitmaps.java @@ -0,0 +1,257 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; +import android.os.Build; + +public class Bitmaps { + + private static volatile Matrix sScaleMatrix; + + private static final ThreadLocal jpegData = new ThreadLocal() { + @Override + protected byte[] initialValue() { + return new byte[]{ + (byte) 0xff, (byte) 0xd8, (byte) 0xff, (byte) 0xdb, (byte) 0x00, (byte) 0x43, (byte) 0x00, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xc0, (byte) 0x00, (byte) 0x11, (byte) 0x08, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x01, (byte) 0x22, (byte) 0x00, + (byte) 0x02, (byte) 0x11, (byte) 0x00, (byte) 0x03, (byte) 0x11, (byte) 0x00, (byte) 0xff, + (byte) 0xc4, (byte) 0x00, (byte) 0x1f, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x05, + (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, + (byte) 0x08, (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0xff, (byte) 0xc4, (byte) 0x00, + (byte) 0xb5, (byte) 0x10, (byte) 0x00, (byte) 0x02, (byte) 0x01, (byte) 0x03, (byte) 0x03, + (byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x05, (byte) 0x05, (byte) 0x04, (byte) 0x04, + (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x7d, (byte) 0x01, (byte) 0x02, (byte) 0x03, + (byte) 0x00, (byte) 0x04, (byte) 0x11, (byte) 0x05, (byte) 0x12, (byte) 0x21, (byte) 0x31, + (byte) 0x41, (byte) 0x06, (byte) 0x13, (byte) 0x51, (byte) 0x61, (byte) 0x07, (byte) 0x22, + (byte) 0x71, (byte) 0x14, (byte) 0x32, (byte) 0x81, (byte) 0x91, (byte) 0xa1, (byte) 0x08, + (byte) 0x23, (byte) 0x42, (byte) 0xb1, (byte) 0xc1, (byte) 0x15, (byte) 0x52, (byte) 0xd1, + (byte) 0xf0, (byte) 0x24, (byte) 0x33, (byte) 0x62, (byte) 0x72, (byte) 0x82, (byte) 0x09, + (byte) 0x0a, (byte) 0x16, (byte) 0x17, (byte) 0x18, (byte) 0x19, (byte) 0x1a, (byte) 0x25, + (byte) 0x26, (byte) 0x27, (byte) 0x28, (byte) 0x29, (byte) 0x2a, (byte) 0x34, (byte) 0x35, + (byte) 0x36, (byte) 0x37, (byte) 0x38, (byte) 0x39, (byte) 0x3a, (byte) 0x43, (byte) 0x44, + (byte) 0x45, (byte) 0x46, (byte) 0x47, (byte) 0x48, (byte) 0x49, (byte) 0x4a, (byte) 0x53, + (byte) 0x54, (byte) 0x55, (byte) 0x56, (byte) 0x57, (byte) 0x58, (byte) 0x59, (byte) 0x5a, + (byte) 0x63, (byte) 0x64, (byte) 0x65, (byte) 0x66, (byte) 0x67, (byte) 0x68, (byte) 0x69, + (byte) 0x6a, (byte) 0x73, (byte) 0x74, (byte) 0x75, (byte) 0x76, (byte) 0x77, (byte) 0x78, + (byte) 0x79, (byte) 0x7a, (byte) 0x83, (byte) 0x84, (byte) 0x85, (byte) 0x86, (byte) 0x87, + (byte) 0x88, (byte) 0x89, (byte) 0x8a, (byte) 0x92, (byte) 0x93, (byte) 0x94, (byte) 0x95, + (byte) 0x96, (byte) 0x97, (byte) 0x98, (byte) 0x99, (byte) 0x9a, (byte) 0xa2, (byte) 0xa3, + (byte) 0xa4, (byte) 0xa5, (byte) 0xa6, (byte) 0xa7, (byte) 0xa8, (byte) 0xa9, (byte) 0xaa, + (byte) 0xb2, (byte) 0xb3, (byte) 0xb4, (byte) 0xb5, (byte) 0xb6, (byte) 0xb7, (byte) 0xb8, + (byte) 0xb9, (byte) 0xba, (byte) 0xc2, (byte) 0xc3, (byte) 0xc4, (byte) 0xc5, (byte) 0xc6, + (byte) 0xc7, (byte) 0xc8, (byte) 0xc9, (byte) 0xca, (byte) 0xd2, (byte) 0xd3, (byte) 0xd4, + (byte) 0xd5, (byte) 0xd6, (byte) 0xd7, (byte) 0xd8, (byte) 0xd9, (byte) 0xda, (byte) 0xe1, + (byte) 0xe2, (byte) 0xe3, (byte) 0xe4, (byte) 0xe5, (byte) 0xe6, (byte) 0xe7, (byte) 0xe8, + (byte) 0xe9, (byte) 0xea, (byte) 0xf1, (byte) 0xf2, (byte) 0xf3, (byte) 0xf4, (byte) 0xf5, + (byte) 0xf6, (byte) 0xf7, (byte) 0xf8, (byte) 0xf9, (byte) 0xfa, (byte) 0xff, (byte) 0xc4, + (byte) 0x00, (byte) 0x1f, (byte) 0x01, (byte) 0x00, (byte) 0x03, (byte) 0x01, (byte) 0x01, + (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, + (byte) 0x02, (byte) 0x03, (byte) 0x04, (byte) 0x05, (byte) 0x06, (byte) 0x07, (byte) 0x08, + (byte) 0x09, (byte) 0x0a, (byte) 0x0b, (byte) 0xff, (byte) 0xc4, (byte) 0x00, (byte) 0xb5, + (byte) 0x11, (byte) 0x00, (byte) 0x02, (byte) 0x01, (byte) 0x02, (byte) 0x04, (byte) 0x04, + (byte) 0x03, (byte) 0x04, (byte) 0x07, (byte) 0x05, (byte) 0x04, (byte) 0x04, (byte) 0x00, + (byte) 0x01, (byte) 0x02, (byte) 0x77, (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, + (byte) 0x11, (byte) 0x04, (byte) 0x05, (byte) 0x21, (byte) 0x31, (byte) 0x06, (byte) 0x12, + (byte) 0x41, (byte) 0x51, (byte) 0x07, (byte) 0x61, (byte) 0x71, (byte) 0x13, (byte) 0x22, + (byte) 0x32, (byte) 0x81, (byte) 0x08, (byte) 0x14, (byte) 0x42, (byte) 0x91, (byte) 0xa1, + (byte) 0xb1, (byte) 0xc1, (byte) 0x09, (byte) 0x23, (byte) 0x33, (byte) 0x52, (byte) 0xf0, + (byte) 0x15, (byte) 0x62, (byte) 0x72, (byte) 0xd1, (byte) 0x0a, (byte) 0x16, (byte) 0x24, + (byte) 0x34, (byte) 0xe1, (byte) 0x25, (byte) 0xf1, (byte) 0x17, (byte) 0x18, (byte) 0x19, + (byte) 0x1a, (byte) 0x26, (byte) 0x27, (byte) 0x28, (byte) 0x29, (byte) 0x2a, (byte) 0x35, + (byte) 0x36, (byte) 0x37, (byte) 0x38, (byte) 0x39, (byte) 0x3a, (byte) 0x43, (byte) 0x44, + (byte) 0x45, (byte) 0x46, (byte) 0x47, (byte) 0x48, (byte) 0x49, (byte) 0x4a, (byte) 0x53, + (byte) 0x54, (byte) 0x55, (byte) 0x56, (byte) 0x57, (byte) 0x58, (byte) 0x59, (byte) 0x5a, + (byte) 0x63, (byte) 0x64, (byte) 0x65, (byte) 0x66, (byte) 0x67, (byte) 0x68, (byte) 0x69, + (byte) 0x6a, (byte) 0x73, (byte) 0x74, (byte) 0x75, (byte) 0x76, (byte) 0x77, (byte) 0x78, + (byte) 0x79, (byte) 0x7a, (byte) 0x82, (byte) 0x83, (byte) 0x84, (byte) 0x85, (byte) 0x86, + (byte) 0x87, (byte) 0x88, (byte) 0x89, (byte) 0x8a, (byte) 0x92, (byte) 0x93, (byte) 0x94, + (byte) 0x95, (byte) 0x96, (byte) 0x97, (byte) 0x98, (byte) 0x99, (byte) 0x9a, (byte) 0xa2, + (byte) 0xa3, (byte) 0xa4, (byte) 0xa5, (byte) 0xa6, (byte) 0xa7, (byte) 0xa8, (byte) 0xa9, + (byte) 0xaa, (byte) 0xb2, (byte) 0xb3, (byte) 0xb4, (byte) 0xb5, (byte) 0xb6, (byte) 0xb7, + (byte) 0xb8, (byte) 0xb9, (byte) 0xba, (byte) 0xc2, (byte) 0xc3, (byte) 0xc4, (byte) 0xc5, + (byte) 0xc6, (byte) 0xc7, (byte) 0xc8, (byte) 0xc9, (byte) 0xca, (byte) 0xd2, (byte) 0xd3, + (byte) 0xd4, (byte) 0xd5, (byte) 0xd6, (byte) 0xd7, (byte) 0xd8, (byte) 0xd9, (byte) 0xda, + (byte) 0xe2, (byte) 0xe3, (byte) 0xe4, (byte) 0xe5, (byte) 0xe6, (byte) 0xe7, (byte) 0xe8, + (byte) 0xe9, (byte) 0xea, (byte) 0xf2, (byte) 0xf3, (byte) 0xf4, (byte) 0xf5, (byte) 0xf6, + (byte) 0xf7, (byte) 0xf8, (byte) 0xf9, (byte) 0xfa, (byte) 0xff, (byte) 0xda, (byte) 0x00, + (byte) 0x0c, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x11, (byte) 0x03, + (byte) 0x11, (byte) 0x00, (byte) 0x3f, (byte) 0x00, (byte) 0x8e, (byte) 0x8a, (byte) 0x28, + (byte) 0xa0, (byte) 0x0f, (byte) 0xff, (byte) 0xd9 + }; + } + }; + + public static Bitmap createBitmap(int width, int height, Bitmap.Config config) { + Bitmap bitmap; + if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 21) { + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inDither = true; + options.inPreferredConfig = config; + options.inPurgeable = true; + options.inSampleSize = 1; + options.inMutable = true; + byte[] array = jpegData.get(); + array[76] = (byte) (height >> 8); + array[77] = (byte) (height & 0x00ff); + array[78] = (byte) (width >> 8); + array[79] = (byte) (width & 0x00ff); + bitmap = BitmapFactory.decodeByteArray(array, 0, array.length, options); + Utilities.pinBitmap(bitmap); + bitmap.setHasAlpha(true); + bitmap.eraseColor(0); + } else { + bitmap = Bitmap.createBitmap(width, height, config); + } + if (config == Bitmap.Config.ARGB_8888 || config == Bitmap.Config.ARGB_4444) { + bitmap.eraseColor(Color.TRANSPARENT); + } + return bitmap; + } + + private static void checkXYSign(int x, int y) { + if (x < 0) { + throw new IllegalArgumentException("x must be >= 0"); + } + if (y < 0) { + throw new IllegalArgumentException("y must be >= 0"); + } + } + + private static void checkWidthHeight(int width, int height) { + if (width <= 0) { + throw new IllegalArgumentException("width must be > 0"); + } + if (height <= 0) { + throw new IllegalArgumentException("height must be > 0"); + } + } + + public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter) { + checkXYSign(x, y); + checkWidthHeight(width, height); + if (x + width > source.getWidth()) { + throw new IllegalArgumentException("x + width must be <= bitmap.width()"); + } + if (y + height > source.getHeight()) { + throw new IllegalArgumentException("y + height must be <= bitmap.height()"); + } + if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() && height == source.getHeight() && (m == null || m.isIdentity())) { + return source; + } + + int neww = width; + int newh = height; + Canvas canvas = new Canvas(); + Bitmap bitmap; + Paint paint; + + Rect srcR = new Rect(x, y, x + width, y + height); + RectF dstR = new RectF(0, 0, width, height); + + Bitmap.Config newConfig = Bitmap.Config.ARGB_8888; + final Bitmap.Config config = source.getConfig(); + if (config != null) { + switch (config) { + case RGB_565: + newConfig = Bitmap.Config.RGB_565; + break; + case ALPHA_8: + newConfig = Bitmap.Config.ALPHA_8; + break; + case ARGB_4444: + case ARGB_8888: + default: + newConfig = Bitmap.Config.ARGB_8888; + break; + } + } + + if (m == null || m.isIdentity()) { + bitmap = createBitmap(neww, newh, newConfig); + paint = null; + } else { + final boolean transformed = !m.rectStaysRect(); + RectF deviceR = new RectF(); + m.mapRect(deviceR, dstR); + neww = Math.round(deviceR.width()); + newh = Math.round(deviceR.height()); + bitmap = createBitmap(neww, newh, transformed ? Bitmap.Config.ARGB_8888 : newConfig); + canvas.translate(-deviceR.left, -deviceR.top); + canvas.concat(m); + paint = new Paint(); + paint.setFilterBitmap(filter); + if (transformed) { + paint.setAntiAlias(true); + } + } + bitmap.setDensity(source.getDensity()); + if (Build.VERSION.SDK_INT >= 12) { + bitmap.setHasAlpha(source.hasAlpha()); + } + if (Build.VERSION.SDK_INT >= 19) { + bitmap.setPremultiplied(source.isPremultiplied()); + } + canvas.setBitmap(bitmap); + canvas.drawBitmap(source, srcR, dstR, paint); + try { + canvas.setBitmap(null); + } catch (Exception e) { + //don't promt, this will crash on 2.x + } + return bitmap; + } + + public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height) { + return createBitmap(source, x, y, width, height, null, false); + } + + public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) { + Matrix m; + synchronized (Bitmap.class) { + m = sScaleMatrix; + sScaleMatrix = null; + } + if (m == null) { + m = new Matrix(); + } + final int width = src.getWidth(); + final int height = src.getHeight(); + final float sx = dstWidth / (float) width; + final float sy = dstHeight / (float) height; + m.setScale(sx, sy); + Bitmap b = createBitmap(src, 0, 0, width, height, m, filter); + synchronized (Bitmap.class) { + if (sScaleMatrix == null) { + sScaleMatrix = m; + } + } + return b; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/CallReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/CallReceiver.java new file mode 100644 index 00000000..58eeacd2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/CallReceiver.java @@ -0,0 +1,34 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyManager; + +import org.telegram.PhoneFormat.PhoneFormat; + +public class CallReceiver extends BroadcastReceiver { + + @Override + public void onReceive(final Context context, Intent intent) { + TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + telephony.listen(new PhoneStateListener() { + @Override + public void onCallStateChanged(int state, String incomingNumber) { + super.onCallStateChanged(state, incomingNumber); + if (state == 1 && incomingNumber != null && incomingNumber.length() > 0) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReceiveCall, PhoneFormat.stripExceptNumbers(incomingNumber)); + } + } + }, PhoneStateListener.LISTEN_CALL_STATE); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java new file mode 100644 index 00000000..b3b58216 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ChatObject.java @@ -0,0 +1,59 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import org.telegram.tgnet.TLRPC; + +public class ChatObject { + + public static final int CHAT_TYPE_CHAT = 0; + public static final int CHAT_TYPE_BROADCAST = 1; + public static final int CHAT_TYPE_CHANNEL = 2; + public static final int CHAT_TYPE_USER = 3; + public static final int CHAT_TYPE_MEGAGROUP = 4; + + public static boolean isLeftFromChat(TLRPC.Chat chat) { + return chat == null || chat instanceof TLRPC.TL_chatEmpty || chat instanceof TLRPC.TL_chatForbidden || chat instanceof TLRPC.TL_channelForbidden || chat.left || chat.deactivated; + } + + public static boolean isKickedFromChat(TLRPC.Chat chat) { + return chat == null || chat instanceof TLRPC.TL_chatEmpty || chat instanceof TLRPC.TL_chatForbidden || chat instanceof TLRPC.TL_channelForbidden || chat.kicked || chat.deactivated; + } + + public static boolean isNotInChat(TLRPC.Chat chat) { + return chat == null || chat instanceof TLRPC.TL_chatEmpty || chat instanceof TLRPC.TL_chatForbidden || chat instanceof TLRPC.TL_channelForbidden || chat.left || chat.kicked || chat.deactivated; + } + + public static boolean isChannel(TLRPC.Chat chat) { + return chat instanceof TLRPC.TL_channel || chat instanceof TLRPC.TL_channelForbidden; + } + + public static boolean isChannel(int chatId) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(chatId); + return chat instanceof TLRPC.TL_channel || chat instanceof TLRPC.TL_channelForbidden; + } + + public static boolean isCanWriteToChannel(int chatId) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(chatId); + return chat != null && (chat.creator || chat.editor || chat.megagroup); + } + + public static boolean canWriteToChat(TLRPC.Chat chat) { + return !isChannel(chat) || chat.creator || chat.editor || !chat.broadcast; + } + + public static TLRPC.Chat getChatByDialog(long did) { + int lower_id = (int) did; + int high_id = (int) (did >> 32); + if (lower_id < 0) { + return MessagesController.getInstance().getChat(-lower_id); + } + return null; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ClearCacheService.java b/TMessagesProj/src/main/java/org/telegram/messenger/ClearCacheService.java new file mode 100644 index 00000000..fb45992d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ClearCacheService.java @@ -0,0 +1,82 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.app.Activity; +import android.app.IntentService; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Build; +import android.system.Os; +import android.system.StructStat; + +import java.io.File; +import java.util.HashMap; + +public class ClearCacheService extends IntentService { + + public ClearCacheService() { + super("ClearCacheService"); + } + + @Override + protected void onHandleIntent(Intent intent) { + ApplicationLoader.postInitApplication(); + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + final int keepMedia = preferences.getInt("keep_media", 2); + if (keepMedia == 2) { + return; + } + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + long currentTime = System.currentTimeMillis(); + long diff = 60 * 60 * 1000 * 24 * (keepMedia == 0 ? 7 : 30); + final HashMap paths = ImageLoader.getInstance().createMediaPaths(); + for (HashMap.Entry entry : paths.entrySet()) { + if (entry.getKey() == FileLoader.MEDIA_DIR_CACHE) { + continue; + } + try { + File[] array = entry.getValue().listFiles(); + if (array != null) { + for (int b = 0; b < array.length; b++) { + File f = array[b]; + if (f.isFile()) { + if (f.getName().equals(".nomedia")) { + continue; + } + if (Build.VERSION.SDK_INT >= 21) { + try { + StructStat stat = Os.stat(f.getPath()); + if (stat.st_atime != 0) { + if (stat.st_atime + diff < currentTime) { + f.delete(); + } + } else if (stat.st_mtime + diff < currentTime) { + f.delete(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else if (f.lastModified() + diff < currentTime) { + f.delete(); + } + } + } + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + } + }); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java new file mode 100644 index 00000000..7a4f0b6c --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsController.java @@ -0,0 +1,1966 @@ +/* + * This is the source code of Telegram for Android v. 1.3.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.app.Activity; +import android.content.ContentProviderOperation; +import android.content.ContentProviderResult; +import android.content.ContentResolver; +import android.content.ContentValues; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.provider.BaseColumns; +import android.provider.ContactsContract; +import android.text.TextUtils; +import android.util.SparseArray; + +import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; + +public class ContactsController { + + private Account currentAccount; + private boolean loadingContacts = false; + private static final Object loadContactsSync = new Object(); + private boolean ignoreChanges = false; + private boolean contactsSyncInProgress = false; + private final Object observerLock = new Object(); + public boolean contactsLoaded = false; + private boolean contactsBookLoaded = false; + private String lastContactsVersions = ""; + private ArrayList delayedContactsUpdate = new ArrayList<>(); + private String inviteText; + private boolean updatingInviteText = false; + private HashMap sectionsToReplace = new HashMap<>(); + + private int loadingDeleteInfo = 0; + private int deleteAccountTTL; + private int loadingLastSeenInfo = 0; + private int loadingGroupInfo = 0; + private ArrayList privacyRules = null; + private ArrayList groupPrivacyRules = null; + + public static class Contact { + public int id; + public ArrayList phones = new ArrayList<>(); + public ArrayList phoneTypes = new ArrayList<>(); + public ArrayList shortPhones = new ArrayList<>(); + public ArrayList phoneDeleted = new ArrayList<>(); + public String first_name; + public String last_name; + } + + private String[] projectionPhones = { + ContactsContract.CommonDataKinds.Phone.CONTACT_ID, + ContactsContract.CommonDataKinds.Phone.NUMBER, + ContactsContract.CommonDataKinds.Phone.TYPE, + ContactsContract.CommonDataKinds.Phone.LABEL + }; + private String[] projectionNames = { + ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID, + ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, + ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, + ContactsContract.Data.DISPLAY_NAME, + ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME + }; + + public HashMap contactsBook = new HashMap<>(); + public HashMap contactsBookSPhones = new HashMap<>(); + public ArrayList phoneBookContacts = new ArrayList<>(); + + public ArrayList contacts = new ArrayList<>(); + public SparseArray contactsDict = new SparseArray<>(); + public HashMap> usersSectionsDict = new HashMap<>(); + public ArrayList sortedUsersSectionsArray = new ArrayList<>(); + + public HashMap> usersMutualSectionsDict = new HashMap<>(); + public ArrayList sortedUsersMutualSectionsArray = new ArrayList<>(); + + public HashMap contactsByPhone = new HashMap<>(); + + private static volatile ContactsController Instance = null; + public static ContactsController getInstance() { + ContactsController localInstance = Instance; + if (localInstance == null) { + synchronized (ContactsController.class) { + localInstance = Instance; + if (localInstance == null) { + Instance = localInstance = new ContactsController(); + } + } + } + return localInstance; + } + + public ContactsController() { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + if (preferences.getBoolean("needGetStatuses", false)) { + reloadContactsStatuses(); + } + + sectionsToReplace.put("À", "A"); + sectionsToReplace.put("Á", "A"); + sectionsToReplace.put("Ä", "A"); + sectionsToReplace.put("Ù", "U"); + sectionsToReplace.put("Ú", "U"); + sectionsToReplace.put("Ü", "U"); + sectionsToReplace.put("Ì", "I"); + sectionsToReplace.put("Í", "I"); + sectionsToReplace.put("Ï", "I"); + sectionsToReplace.put("È", "E"); + sectionsToReplace.put("É", "E"); + sectionsToReplace.put("Ê", "E"); + sectionsToReplace.put("Ë", "E"); + sectionsToReplace.put("Ò", "O"); + sectionsToReplace.put("Ó", "O"); + sectionsToReplace.put("Ö", "O"); + sectionsToReplace.put("Ç", "C"); + sectionsToReplace.put("Ñ", "N"); + sectionsToReplace.put("Ÿ", "Y"); + sectionsToReplace.put("Ý", "Y"); + sectionsToReplace.put("Ţ", "Y"); + } + + public void cleanup() { + contactsBook.clear(); + contactsBookSPhones.clear(); + phoneBookContacts.clear(); + contacts.clear(); + contactsDict.clear(); + usersSectionsDict.clear(); + usersMutualSectionsDict.clear(); + sortedUsersSectionsArray.clear(); + sortedUsersMutualSectionsArray.clear(); + delayedContactsUpdate.clear(); + contactsByPhone.clear(); + + loadingContacts = false; + contactsSyncInProgress = false; + contactsLoaded = false; + contactsBookLoaded = false; + lastContactsVersions = ""; + loadingDeleteInfo = 0; + deleteAccountTTL = 0; + loadingLastSeenInfo = 0; + loadingGroupInfo = 0; + privacyRules = null; + } + + public void checkInviteText() { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + inviteText = preferences.getString("invitetext", null); + int time = preferences.getInt("invitetexttime", 0); + if (!updatingInviteText && (inviteText == null || time + 86400 < (int)(System.currentTimeMillis() / 1000))) { + updatingInviteText = true; + TLRPC.TL_help_getInviteText req = new TLRPC.TL_help_getInviteText(); + req.lang_code = LocaleController.getLocaleStringIso639(); + if (req.lang_code.length() == 0) { + req.lang_code = "en"; + } + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (response != null) { + final TLRPC.TL_help_inviteText res = (TLRPC.TL_help_inviteText) response; + if (res.message.length() != 0) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + updatingInviteText = false; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString("invitetext", res.message); + editor.putInt("invitetexttime", (int) (System.currentTimeMillis() / 1000)); + editor.commit(); + } + }); + } + } + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + } + } + + public String getInviteText() { + //return inviteText != null ? inviteText : LocaleController.getString("InviteText", R.string.InviteText); + return LocaleController.getString("InviteText", R.string.InviteText); + } + + public void checkAppAccount() { + AccountManager am = AccountManager.get(ApplicationLoader.applicationContext); + Account[] accounts; + try { + accounts = am.getAccountsByType("org.telegram.account"); + if (accounts != null && accounts.length > 0) { + for (int a = 0; a < accounts.length; a++) { + am.removeAccount(accounts[a], null, null); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + accounts = am.getAccountsByType("org.telegram.messenger"); + boolean recreateAccount = false; + if (UserConfig.isClientActivated()) { + if (accounts.length == 1) { + Account acc = accounts[0]; + if (!acc.name.equals("" + UserConfig.getClientUserId())) { + recreateAccount = true; + } else { + currentAccount = acc; + } + } else { + recreateAccount = true; + } + readContacts(); + } else { + if (accounts.length > 0) { + recreateAccount = true; + } + } + if (recreateAccount) { + try { + for (int a = 0; a < accounts.length; a++) { + am.removeAccount(accounts[a], null, null); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (UserConfig.isClientActivated()) { + try { + currentAccount = new Account("" + UserConfig.getClientUserId(), "org.telegram.messenger"); + am.addAccountExplicitly(currentAccount, "", null); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + } + + public void deleteAllAppAccounts() { + try { + AccountManager am = AccountManager.get(ApplicationLoader.applicationContext); + Account[] accounts = am.getAccountsByType("org.telegram.messenger"); + for (int a = 0; a < accounts.length; a++) { + am.removeAccount(accounts[a], null, null); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void checkContacts() { + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (checkContactsInternal()) { + FileLog.e("tmessages", "detected contacts change"); + ContactsController.getInstance().performSyncPhoneBook(ContactsController.getInstance().getContactsCopy(ContactsController.getInstance().contactsBook), true, false, true); + } + } + }); + } + + private boolean checkContactsInternal() { + boolean reload = false; + try { + if (!hasContactsPermission()) { + return false; + } + ContentResolver cr = ApplicationLoader.applicationContext.getContentResolver(); + Cursor pCur = null; + try { + pCur = cr.query(ContactsContract.RawContacts.CONTENT_URI, new String[]{ContactsContract.RawContacts.VERSION}, null, null, null); + if (pCur != null) { + StringBuilder currentVersion = new StringBuilder(); + while (pCur.moveToNext()) { + int col = pCur.getColumnIndex(ContactsContract.RawContacts.VERSION); + currentVersion.append(pCur.getString(col)); + } + String newContactsVersion = currentVersion.toString(); + if (lastContactsVersions.length() != 0 && !lastContactsVersions.equals(newContactsVersion)) { + reload = true; + } + lastContactsVersions = newContactsVersion; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (pCur != null) { + pCur.close(); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return reload; + } + + public void readContacts() { + synchronized (loadContactsSync) { + if (loadingContacts) { + return; + } + loadingContacts = true; + } + + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (!contacts.isEmpty() || contactsLoaded) { + synchronized (loadContactsSync) { + loadingContacts = false; + } + return; + } + loadContacts(true, false); + } + }); + } + + private HashMap readContactsFromPhoneBook() { + HashMap contactsMap = new HashMap<>(); + try { + if (!hasContactsPermission()) { + return contactsMap; + } + ContentResolver cr = ApplicationLoader.applicationContext.getContentResolver(); + + HashMap shortContacts = new HashMap<>(); + ArrayList idsArr = new ArrayList<>(); + Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projectionPhones, null, null, null); + if (pCur != null) { + if (pCur.getCount() > 0) { + while (pCur.moveToNext()) { + String number = pCur.getString(1); + if (number == null || number.length() == 0) { + continue; + } + number = PhoneFormat.stripExceptNumbers(number, true); + if (number.length() == 0) { + continue; + } + + String shortNumber = number; + + if (number.startsWith("+")) { + shortNumber = number.substring(1); + } + + if (shortContacts.containsKey(shortNumber)) { + continue; + } + + Integer id = pCur.getInt(0); + if (!idsArr.contains(id)) { + idsArr.add(id); + } + + int type = pCur.getInt(2); + Contact contact = contactsMap.get(id); + if (contact == null) { + contact = new Contact(); + contact.first_name = ""; + contact.last_name = ""; + contact.id = id; + contactsMap.put(id, contact); + } + + contact.shortPhones.add(shortNumber); + contact.phones.add(number); + contact.phoneDeleted.add(0); + + if (type == ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM) { + contact.phoneTypes.add(pCur.getString(3)); + } else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_HOME) { + contact.phoneTypes.add(LocaleController.getString("PhoneHome", R.string.PhoneHome)); + } else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE) { + contact.phoneTypes.add(LocaleController.getString("PhoneMobile", R.string.PhoneMobile)); + } else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_WORK) { + contact.phoneTypes.add(LocaleController.getString("PhoneWork", R.string.PhoneWork)); + } else if (type == ContactsContract.CommonDataKinds.Phone.TYPE_MAIN) { + contact.phoneTypes.add(LocaleController.getString("PhoneMain", R.string.PhoneMain)); + } else { + contact.phoneTypes.add(LocaleController.getString("PhoneOther", R.string.PhoneOther)); + } + shortContacts.put(shortNumber, contact); + } + } + pCur.close(); + } + String ids = TextUtils.join(",", idsArr); + + pCur = cr.query(ContactsContract.Data.CONTENT_URI, projectionNames, ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " IN (" + ids + ") AND " + ContactsContract.Data.MIMETYPE + " = '" + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE + "'", null, null); + if (pCur != null && pCur.getCount() > 0) { + while (pCur.moveToNext()) { + int id = pCur.getInt(0); + String fname = pCur.getString(1); + String sname = pCur.getString(2); + String sname2 = pCur.getString(3); + String mname = pCur.getString(4); + Contact contact = contactsMap.get(id); + if (contact != null && contact.first_name.length() == 0 && contact.last_name.length() == 0) { + contact.first_name = fname; + contact.last_name = sname; + if (contact.first_name == null) { + contact.first_name = ""; + } + if (mname != null && mname.length() != 0) { + if (contact.first_name.length() != 0) { + contact.first_name += " " + mname; + } else { + contact.first_name = mname; + } + } + if (contact.last_name == null) { + contact.last_name = ""; + } + if (contact.last_name.length() == 0 && contact.first_name.length() == 0 && sname2 != null && sname2.length() != 0) { + contact.first_name = sname2; + } + } + } + pCur.close(); + } + + try { + pCur = cr.query(ContactsContract.RawContacts.CONTENT_URI, new String[] { "display_name", ContactsContract.RawContacts.SYNC1, ContactsContract.RawContacts.CONTACT_ID }, ContactsContract.RawContacts.ACCOUNT_TYPE + " = " + "'com.whatsapp'", null, null); + if (pCur != null) { + while ((pCur.moveToNext())) { + String phone = pCur.getString(1); + if (phone == null || phone.length() == 0) { + continue; + } + boolean withPlus = phone.startsWith("+"); + phone = Utilities.parseIntToString(phone); + if (phone == null || phone.length() == 0) { + continue; + } + String shortPhone = phone; + if (!withPlus) { + phone = "+" + phone; + } + + if (shortContacts.containsKey(shortPhone)) { + continue; + } + + String name = pCur.getString(0); + if (name == null || name.length() == 0) { + name = PhoneFormat.getInstance().format(phone); + } + + Contact contact = new Contact(); + contact.first_name = name; + contact.last_name = ""; + contact.id = pCur.getInt(2); + contactsMap.put(contact.id, contact); + + contact.phoneDeleted.add(0); + contact.shortPhones.add(shortPhone); + contact.phones.add(phone); + contact.phoneTypes.add(LocaleController.getString("PhoneMobile", R.string.PhoneMobile)); + shortContacts.put(shortPhone, contact); + } + pCur.close(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + contactsMap.clear(); + } + /*if (BuildVars.DEBUG_VERSION) { + for (HashMap.Entry entry : contactsMap.entrySet()) { + Contact contact = entry.getValue(); + FileLog.e("tmessages", "contact = " + contact.first_name + " " + contact.last_name); + if (contact.first_name.length() == 0 && contact.last_name.length() == 0 && contact.phones.size() > 0) { + FileLog.e("tmessages", "warning, empty name for contact = " + contact.id); + } + FileLog.e("tmessages", "phones:"); + for (String s : contact.phones) { + FileLog.e("tmessages", "phone = " + s); + } + FileLog.e("tmessages", "short phones:"); + for (String s : contact.shortPhones) { + FileLog.e("tmessages", "short phone = " + s); + } + } + }*/ + return contactsMap; + } + + public HashMap getContactsCopy(HashMap original) { + HashMap ret = new HashMap<>(); + for (HashMap.Entry entry : original.entrySet()) { + Contact copyContact = new Contact(); + Contact originalContact = entry.getValue(); + copyContact.phoneDeleted.addAll(originalContact.phoneDeleted); + copyContact.phones.addAll(originalContact.phones); + copyContact.phoneTypes.addAll(originalContact.phoneTypes); + copyContact.shortPhones.addAll(originalContact.shortPhones); + copyContact.first_name = originalContact.first_name; + copyContact.last_name = originalContact.last_name; + copyContact.id = originalContact.id; + ret.put(copyContact.id, copyContact); + } + return ret; + } + + public void performSyncPhoneBook(final HashMap contactHashMap, final boolean requ, final boolean first, final boolean schedule) { + if (!first && !contactsBookLoaded) { + return; + } + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + + boolean disableDeletion = true; //disable contacts deletion, because phone numbers can't be compared due to different numbers format + /*if (schedule) { + try { + AccountManager am = AccountManager.get(ApplicationLoader.applicationContext); + Account[] accounts = am.getAccountsByType("org.telegram.account"); + boolean recreateAccount = false; + if (UserConfig.isClientActivated()) { + if (accounts.length != 1) { + FileLog.e("tmessages", "detected account deletion!"); + currentAccount = new Account(UserConfig.getCurrentUser().phone, "org.telegram.account"); + am.addAccountExplicitly(currentAccount, "", null); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + performWriteContactsToPhoneBook(); + } + }); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + }*/ + + boolean request = requ; + if (request && first) { + if (UserConfig.importHash != null && UserConfig.importHash.length() != 0 || UserConfig.contactsVersion != 1) { + UserConfig.importHash = ""; + UserConfig.contactsVersion = 1; + UserConfig.saveConfig(false); + request = false; + } + } + + HashMap contactShortHashMap = new HashMap<>(); + for (HashMap.Entry entry : contactHashMap.entrySet()) { + Contact c = entry.getValue(); + for (String sphone : c.shortPhones) { + contactShortHashMap.put(sphone, c); + } + } + + FileLog.e("tmessages", "start read contacts from phone"); + if (!schedule) { + checkContactsInternal(); + } + final HashMap contactsMap = readContactsFromPhoneBook(); + final HashMap contactsBookShort = new HashMap<>(); + int oldCount = contactHashMap.size(); + + ArrayList toImport = new ArrayList<>(); + if (!contactHashMap.isEmpty()) { + for (HashMap.Entry pair : contactsMap.entrySet()) { + Integer id = pair.getKey(); + Contact value = pair.getValue(); + Contact existing = contactHashMap.get(id); + if (existing == null) { + for (String s : value.shortPhones) { + Contact c = contactShortHashMap.get(s); + if (c != null) { + existing = c; + id = existing.id; + break; + } + } + } + + boolean nameChanged = existing != null && (value.first_name != null && value.first_name.length() != 0 && !existing.first_name.equals(value.first_name) || value.last_name != null && existing.last_name != null && !existing.last_name.equals(value.last_name)); + if (existing == null || nameChanged) { + for (int a = 0; a < value.phones.size(); a++) { + String sphone = value.shortPhones.get(a); + contactsBookShort.put(sphone, value); + if (existing != null) { + int index = existing.shortPhones.indexOf(sphone); + if (index != -1) { + Integer deleted = existing.phoneDeleted.get(index); + value.phoneDeleted.set(a, deleted); + if (deleted == 1) { + continue; + } + } + } + if (request) { + if (!nameChanged && contactsByPhone.containsKey(sphone)) { + continue; + } + + TLRPC.TL_inputPhoneContact imp = new TLRPC.TL_inputPhoneContact(); + imp.client_id = value.id; + imp.first_name = value.first_name; + imp.last_name = value.last_name; + imp.phone = value.phones.get(a); + toImport.add(imp); + } + } + if (existing != null) { + contactHashMap.remove(id); + } + } else { + for (int a = 0; a < value.phones.size(); a++) { + String sphone = value.shortPhones.get(a); + contactsBookShort.put(sphone, value); + int index = existing.shortPhones.indexOf(sphone); + if (index == -1) { + if (request) { + TLRPC.TL_contact contact = contactsByPhone.get(sphone); + if (contact != null) { + TLRPC.User user = MessagesController.getInstance().getUser(contact.user_id); + if (user == null || user.first_name != null && user.first_name.length() != 0 || user.last_name != null && user.last_name.length() != 0) { + continue; + } + } + + TLRPC.TL_inputPhoneContact imp = new TLRPC.TL_inputPhoneContact(); + imp.client_id = value.id; + imp.first_name = value.first_name; + imp.last_name = value.last_name; + imp.phone = value.phones.get(a); + toImport.add(imp); + } + } else { + value.phoneDeleted.set(a, existing.phoneDeleted.get(index)); + existing.phones.remove(index); + existing.shortPhones.remove(index); + existing.phoneDeleted.remove(index); + existing.phoneTypes.remove(index); + } + } + if (existing.phones.isEmpty()) { + contactHashMap.remove(id); + } + } + } + if (!first && contactHashMap.isEmpty() && toImport.isEmpty() && oldCount == contactsMap.size()) { + FileLog.e("tmessages", "contacts not changed!"); + return; + } + if (request && !contactHashMap.isEmpty() && !contactsMap.isEmpty()) { + if (toImport.isEmpty()) { + MessagesStorage.getInstance().putCachedPhoneBook(contactsMap); + } + if (!disableDeletion && !contactHashMap.isEmpty()) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + /*if (BuildVars.DEBUG_VERSION) { + FileLog.e("tmessages", "need delete contacts"); + for (HashMap.Entry c : contactHashMap.entrySet()) { + Contact contact = c.getValue(); + FileLog.e("tmessages", "delete contact " + contact.first_name + " " + contact.last_name); + for (String phone : contact.phones) { + FileLog.e("tmessages", phone); + } + } + }*/ + + final ArrayList toDelete = new ArrayList<>(); + if (contactHashMap != null && !contactHashMap.isEmpty()) { + try { + final HashMap contactsPhonesShort = new HashMap<>(); + + for (TLRPC.TL_contact value : contacts) { + TLRPC.User user = MessagesController.getInstance().getUser(value.user_id); + if (user == null || user.phone == null || user.phone.length() == 0) { + continue; + } + contactsPhonesShort.put(user.phone, user); + } + int removed = 0; + for (HashMap.Entry entry : contactHashMap.entrySet()) { + Contact contact = entry.getValue(); + boolean was = false; + for (int a = 0; a < contact.shortPhones.size(); a++) { + String phone = contact.shortPhones.get(a); + TLRPC.User user = contactsPhonesShort.get(phone); + if (user != null) { + was = true; + toDelete.add(user); + contact.shortPhones.remove(a); + a--; + } + } + if (!was || contact.shortPhones.size() == 0) { + removed++; + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + if (!toDelete.isEmpty()) { + deleteContact(toDelete); + } + } + }); + } + } + } else if (request) { + for (HashMap.Entry pair : contactsMap.entrySet()) { + Contact value = pair.getValue(); + int id = pair.getKey(); + for (int a = 0; a < value.phones.size(); a++) { + String phone = value.shortPhones.get(a); + TLRPC.TL_contact contact = contactsByPhone.get(phone); + if (contact != null) { + TLRPC.User user = MessagesController.getInstance().getUser(contact.user_id); + if (user == null || user.first_name != null && user.first_name.length() != 0 || user.last_name != null && user.last_name.length() != 0) { + continue; + } + } + TLRPC.TL_inputPhoneContact imp = new TLRPC.TL_inputPhoneContact(); + imp.client_id = id; + imp.first_name = value.first_name; + imp.last_name = value.last_name; + imp.phone = value.phones.get(a); + toImport.add(imp); + } + } + } + + FileLog.e("tmessages", "done processing contacts"); + + if (request) { + if (!toImport.isEmpty()) { + /*if (BuildVars.DEBUG_VERSION) { + FileLog.e("tmessages", "start import contacts"); + for (TLRPC.TL_inputPhoneContact contact : toImport) { + FileLog.e("tmessages", "add contact " + contact.first_name + " " + contact.last_name + " " + contact.phone); + } + }*/ + final int count = (int)Math.ceil(toImport.size() / 500.0f); + for (int a = 0; a < count; a++) { + ArrayList finalToImport = new ArrayList<>(); + finalToImport.addAll(toImport.subList(a * 500, Math.min((a + 1) * 500, toImport.size()))); + TLRPC.TL_contacts_importContacts req = new TLRPC.TL_contacts_importContacts(); + req.contacts = finalToImport; + req.replace = false; + final boolean isLastQuery = a == count - 1; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + FileLog.e("tmessages", "contacts imported"); + if (isLastQuery && !contactsMap.isEmpty()) { + MessagesStorage.getInstance().putCachedPhoneBook(contactsMap); + } + TLRPC.TL_contacts_importedContacts res = (TLRPC.TL_contacts_importedContacts)response; + /*if (BuildVars.DEBUG_VERSION) { + for (TLRPC.User user : res.users) { + FileLog.e("tmessages", "received user " + user.first_name + " " + user.last_name + " " + user.phone); + } + }*/ + MessagesStorage.getInstance().putUsersAndChats(res.users, null, true, true); + ArrayList cArr = new ArrayList<>(); + for (TLRPC.TL_importedContact c : res.imported) { + TLRPC.TL_contact contact = new TLRPC.TL_contact(); + contact.user_id = c.user_id; + cArr.add(contact); + } + processLoadedContacts(cArr, res.users, 2); + } else { + FileLog.e("tmessages", "import contacts error " + error.text); + } + if (isLastQuery) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + contactsBookSPhones = contactsBookShort; + contactsBook = contactsMap; + contactsSyncInProgress = false; + contactsBookLoaded = true; + if (first) { + contactsLoaded = true; + } + if (!delayedContactsUpdate.isEmpty() && contactsLoaded) { + applyContactsUpdates(delayedContactsUpdate, null, null, null); + delayedContactsUpdate.clear(); + } + } + }); + } + } + }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagCanCompress); + } + } else { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + contactsBookSPhones = contactsBookShort; + contactsBook = contactsMap; + contactsSyncInProgress = false; + contactsBookLoaded = true; + if (first) { + contactsLoaded = true; + } + if (!delayedContactsUpdate.isEmpty() && contactsLoaded) { + applyContactsUpdates(delayedContactsUpdate, null, null, null); + delayedContactsUpdate.clear(); + } + } + }); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + updateUnregisteredContacts(contacts); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.contactsDidLoaded); + } + }); + } + } else { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + contactsBookSPhones = contactsBookShort; + contactsBook = contactsMap; + contactsSyncInProgress = false; + contactsBookLoaded = true; + if (first) { + contactsLoaded = true; + } + if (!delayedContactsUpdate.isEmpty() && contactsLoaded && contactsBookLoaded) { + applyContactsUpdates(delayedContactsUpdate, null, null, null); + delayedContactsUpdate.clear(); + } + } + }); + if (!contactsMap.isEmpty()) { + MessagesStorage.getInstance().putCachedPhoneBook(contactsMap); + } + } + } + }); + } + + public boolean isLoadingContacts() { + synchronized (loadContactsSync) { + return loadingContacts; + } + } + + public void loadContacts(boolean fromCache, boolean cacheEmpty) { + synchronized (loadContactsSync) { + loadingContacts = true; + } + if (fromCache) { + FileLog.e("tmessages", "load contacts from cache"); + MessagesStorage.getInstance().getContacts(); + } else { + FileLog.e("tmessages", "load contacts from server"); + TLRPC.TL_contacts_getContacts req = new TLRPC.TL_contacts_getContacts(); + req.hash = cacheEmpty ? "" : UserConfig.contactsHash; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.contacts_Contacts res = (TLRPC.contacts_Contacts)response; + if (res instanceof TLRPC.TL_contacts_contactsNotModified) { + contactsLoaded = true; + if (!delayedContactsUpdate.isEmpty() && contactsBookLoaded) { + applyContactsUpdates(delayedContactsUpdate, null, null, null); + delayedContactsUpdate.clear(); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + synchronized (loadContactsSync) { + loadingContacts = false; + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.contactsDidLoaded); + } + }); + FileLog.e("tmessages", "load contacts don't change"); + return; + } + processLoadedContacts(res.contacts, res.users, 0); + } + } + }); + } + } + + public void processLoadedContacts(final ArrayList contactsArr, final ArrayList usersArr, final int from) { + //from: 0 - from server, 1 - from db, 2 - from imported contacts + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().putUsers(usersArr, from == 1); + + final HashMap usersDict = new HashMap<>(); + + final boolean isEmpty = contactsArr.isEmpty(); + + if (!contacts.isEmpty()) { + for (int a = 0; a < contactsArr.size(); a++) { + TLRPC.TL_contact contact = contactsArr.get(a); + if (contactsDict.get(contact.user_id) != null) { + contactsArr.remove(a); + a--; + } + } + contactsArr.addAll(contacts); + } + + for (TLRPC.TL_contact contact : contactsArr) { + TLRPC.User user = MessagesController.getInstance().getUser(contact.user_id); + if (user != null) { + usersDict.put(user.id, user); + + //if (BuildVars.DEBUG_VERSION) { + // FileLog.e("tmessages", "loaded user contact " + user.first_name + " " + user.last_name + " " + user.phone); + //} + } + } + + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + FileLog.e("tmessages", "done loading contacts"); + if (from == 1 && (contactsArr.isEmpty() || UserConfig.lastContactsSyncTime < (int) (System.currentTimeMillis() / 1000) - 24 * 60 * 60)) { + loadContacts(false, true); + return; + } + if (from == 0) { + UserConfig.lastContactsSyncTime = (int) (System.currentTimeMillis() / 1000); + UserConfig.saveConfig(false); + } + + for (TLRPC.TL_contact contact : contactsArr) { + if (usersDict.get(contact.user_id) == null && contact.user_id != UserConfig.getClientUserId()) { + loadContacts(false, true); + FileLog.e("tmessages", "contacts are broken, load from server"); + return; + } + } + + if (from != 1) { + MessagesStorage.getInstance().putUsersAndChats(usersArr, null, true, true); + MessagesStorage.getInstance().putContacts(contactsArr, from != 2); + Collections.sort(contactsArr, new Comparator() { + @Override + public int compare(TLRPC.TL_contact tl_contact, TLRPC.TL_contact tl_contact2) { + if (tl_contact.user_id > tl_contact2.user_id) { + return 1; + } else if (tl_contact.user_id < tl_contact2.user_id) { + return -1; + } + return 0; + } + }); + StringBuilder ids = new StringBuilder(); + for (TLRPC.TL_contact aContactsArr : contactsArr) { + if (ids.length() != 0) { + ids.append(","); + } + ids.append(aContactsArr.user_id); + } + UserConfig.contactsHash = Utilities.MD5(ids.toString()); + UserConfig.saveConfig(false); + } + + Collections.sort(contactsArr, new Comparator() { + @Override + public int compare(TLRPC.TL_contact tl_contact, TLRPC.TL_contact tl_contact2) { + TLRPC.User user1 = usersDict.get(tl_contact.user_id); + TLRPC.User user2 = usersDict.get(tl_contact2.user_id); + String name1 = UserObject.getFirstName(user1); + String name2 = UserObject.getFirstName(user2); + return name1.compareTo(name2); + } + }); + + final SparseArray contactsDictionary = new SparseArray<>(); + final HashMap> sectionsDict = new HashMap<>(); + final HashMap> sectionsDictMutual = new HashMap<>(); + final ArrayList sortedSectionsArray = new ArrayList<>(); + final ArrayList sortedSectionsArrayMutual = new ArrayList<>(); + HashMap contactsByPhonesDict = null; + + if (!contactsBookLoaded) { + contactsByPhonesDict = new HashMap<>(); + } + + final HashMap contactsByPhonesDictFinal = contactsByPhonesDict; + + for (TLRPC.TL_contact value : contactsArr) { + TLRPC.User user = usersDict.get(value.user_id); + if (user == null) { + continue; + } + contactsDictionary.put(value.user_id, value); + if (contactsByPhonesDict != null) { + contactsByPhonesDict.put(user.phone, value); + } + + String key = UserObject.getFirstName(user); + if (key.length() > 1) { + key = key.substring(0, 1); + } + if (key.length() == 0) { + key = "#"; + } else { + key = key.toUpperCase(); + } + String replace = sectionsToReplace.get(key); + if (replace != null) { + key = replace; + } + ArrayList arr = sectionsDict.get(key); + if (arr == null) { + arr = new ArrayList<>(); + sectionsDict.put(key, arr); + sortedSectionsArray.add(key); + } + arr.add(value); + if (user.mutual_contact) { + arr = sectionsDictMutual.get(key); + if (arr == null) { + arr = new ArrayList<>(); + sectionsDictMutual.put(key, arr); + sortedSectionsArrayMutual.add(key); + } + arr.add(value); + } + } + + Collections.sort(sortedSectionsArray, new Comparator() { + @Override + public int compare(String s, String s2) { + char cv1 = s.charAt(0); + char cv2 = s2.charAt(0); + if (cv1 == '#') { + return 1; + } else if (cv2 == '#') { + return -1; + } + return s.compareTo(s2); + } + }); + + Collections.sort(sortedSectionsArrayMutual, new Comparator() { + @Override + public int compare(String s, String s2) { + char cv1 = s.charAt(0); + char cv2 = s2.charAt(0); + if (cv1 == '#') { + return 1; + } else if (cv2 == '#') { + return -1; + } + return s.compareTo(s2); + } + }); + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + contacts = contactsArr; + contactsDict = contactsDictionary; + usersSectionsDict = sectionsDict; + usersMutualSectionsDict = sectionsDictMutual; + sortedUsersSectionsArray = sortedSectionsArray; + sortedUsersMutualSectionsArray = sortedSectionsArrayMutual; + if (from != 2) { + synchronized (loadContactsSync) { + loadingContacts = false; + } + } + performWriteContactsToPhoneBook(); + updateUnregisteredContacts(contactsArr); + + NotificationCenter.getInstance().postNotificationName(NotificationCenter.contactsDidLoaded); + + if (from != 1 && !isEmpty) { + saveContactsLoadTime(); + } else { + reloadContactsStatusesMaybe(); + } + } + }); + + if (!delayedContactsUpdate.isEmpty() && contactsLoaded && contactsBookLoaded) { + applyContactsUpdates(delayedContactsUpdate, null, null, null); + delayedContactsUpdate.clear(); + } + + if (contactsByPhonesDictFinal != null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + contactsByPhone = contactsByPhonesDictFinal; + } + }); + if (contactsSyncInProgress) { + return; + } + contactsSyncInProgress = true; + MessagesStorage.getInstance().getCachedPhoneBook(); + } + }); + } else { + contactsLoaded = true; + } + } + }); + } + }); + } + + private void reloadContactsStatusesMaybe() { + try { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + long lastReloadStatusTime = preferences.getLong("lastReloadStatusTime", 0); + if (lastReloadStatusTime < System.currentTimeMillis() - 1000 * 60 * 60 * 24) { + reloadContactsStatuses(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + private void saveContactsLoadTime() { + try { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + preferences.edit().putLong("lastReloadStatusTime", System.currentTimeMillis()).commit(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + private void updateUnregisteredContacts(final ArrayList contactsArr) { + final HashMap contactsPhonesShort = new HashMap<>(); + + for (TLRPC.TL_contact value : contactsArr) { + TLRPC.User user = MessagesController.getInstance().getUser(value.user_id); + if (user == null || user.phone == null || user.phone.length() == 0) { + continue; + } + contactsPhonesShort.put(user.phone, value); + } + + final ArrayList sortedPhoneBookContacts = new ArrayList<>(); + for (HashMap.Entry pair : contactsBook.entrySet()) { + Contact value = pair.getValue(); + int id = pair.getKey(); + + boolean skip = false; + for (int a = 0; a < value.phones.size(); a++) { + String sphone = value.shortPhones.get(a); + if (contactsPhonesShort.containsKey(sphone) || value.phoneDeleted.get(a) == 1) { + skip = true; + break; + } + } + if (skip) { + continue; + } + + sortedPhoneBookContacts.add(value); + } + Collections.sort(sortedPhoneBookContacts, new Comparator() { + @Override + public int compare(Contact contact, Contact contact2) { + String toComapre1 = contact.first_name; + if (toComapre1.length() == 0) { + toComapre1 = contact.last_name; + } + String toComapre2 = contact2.first_name; + if (toComapre2.length() == 0) { + toComapre2 = contact2.last_name; + } + return toComapre1.compareTo(toComapre2); + } + }); + + phoneBookContacts = sortedPhoneBookContacts; + } + + private void buildContactsSectionsArrays(boolean sort) { + if (sort) { + Collections.sort(contacts, new Comparator() { + @Override + public int compare(TLRPC.TL_contact tl_contact, TLRPC.TL_contact tl_contact2) { + TLRPC.User user1 = MessagesController.getInstance().getUser(tl_contact.user_id); + TLRPC.User user2 = MessagesController.getInstance().getUser(tl_contact2.user_id); + String name1 = UserObject.getFirstName(user1); + String name2 = UserObject.getFirstName(user2); + return name1.compareTo(name2); + } + }); + } + + StringBuilder ids = new StringBuilder(); + final HashMap> sectionsDict = new HashMap<>(); + final ArrayList sortedSectionsArray = new ArrayList<>(); + + for (TLRPC.TL_contact value : contacts) { + TLRPC.User user = MessagesController.getInstance().getUser(value.user_id); + if (user == null) { + continue; + } + + String key = UserObject.getFirstName(user); + if (key.length() > 1) { + key = key.substring(0, 1); + } + if (key.length() == 0) { + key = "#"; + } else { + key = key.toUpperCase(); + } + String replace = sectionsToReplace.get(key); + if (replace != null) { + key = replace; + } + ArrayList arr = sectionsDict.get(key); + if (arr == null) { + arr = new ArrayList<>(); + sectionsDict.put(key, arr); + sortedSectionsArray.add(key); + } + arr.add(value); + if (ids.length() != 0) { + ids.append(","); + } + ids.append(value.user_id); + } + UserConfig.contactsHash = Utilities.MD5(ids.toString()); + UserConfig.saveConfig(false); + + Collections.sort(sortedSectionsArray, new Comparator() { + @Override + public int compare(String s, String s2) { + char cv1 = s.charAt(0); + char cv2 = s2.charAt(0); + if (cv1 == '#') { + return 1; + } else if (cv2 == '#') { + return -1; + } + return s.compareTo(s2); + } + }); + + usersSectionsDict = sectionsDict; + sortedUsersSectionsArray = sortedSectionsArray; + } + + private boolean hasContactsPermission() { + if (Build.VERSION.SDK_INT >= 23) { + return ApplicationLoader.applicationContext.checkSelfPermission(android.Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED; + } + Cursor cursor = null; + try { + ContentResolver cr = ApplicationLoader.applicationContext.getContentResolver(); + cursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, projectionPhones, null, null, null); + if (cursor == null || cursor.getCount() == 0) { + return false; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + try { + if (cursor != null) { + cursor.close(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + return true; + } + + private void performWriteContactsToPhoneBookInternal(ArrayList contactsArray) { + try { + if (!hasContactsPermission()) { + return; + } + Uri rawContactUri = ContactsContract.RawContacts.CONTENT_URI.buildUpon().appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, currentAccount.name).appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, currentAccount.type).build(); + Cursor c1 = ApplicationLoader.applicationContext.getContentResolver().query(rawContactUri, new String[]{BaseColumns._ID, ContactsContract.RawContacts.SYNC2}, null, null, null); + HashMap bookContacts = new HashMap<>(); + if (c1 != null) { + while (c1.moveToNext()) { + bookContacts.put(c1.getInt(1), c1.getLong(0)); + } + c1.close(); + + for (int a = 0; a < contactsArray.size(); a++) { + TLRPC.TL_contact u = contactsArray.get(a); + if (!bookContacts.containsKey(u.user_id)) { + TLRPC.User user = MessagesController.getInstance().getUser(u.user_id); + addContactToPhoneBook(user, false); + } + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + private void performWriteContactsToPhoneBook() { + final ArrayList contactsArray = new ArrayList<>(); + contactsArray.addAll(contacts); + Utilities.phoneBookQueue.postRunnable(new Runnable() { + @Override + public void run() { + performWriteContactsToPhoneBookInternal(contactsArray); + } + }); + } + + private void applyContactsUpdates(ArrayList ids, ConcurrentHashMap userDict, ArrayList newC, ArrayList contactsTD) { + if (newC == null || contactsTD == null) { + newC = new ArrayList<>(); + contactsTD = new ArrayList<>(); + for (Integer uid : ids) { + if (uid > 0) { + TLRPC.TL_contact contact = new TLRPC.TL_contact(); + contact.user_id = uid; + newC.add(contact); + } else if (uid < 0) { + contactsTD.add(-uid); + } + } + } + FileLog.e("tmessages", "process update - contacts add = " + newC.size() + " delete = " + contactsTD.size()); + + StringBuilder toAdd = new StringBuilder(); + StringBuilder toDelete = new StringBuilder(); + boolean reloadContacts = false; + + for (TLRPC.TL_contact newContact : newC) { + TLRPC.User user = null; + if (userDict != null) { + user = userDict.get(newContact.user_id); + } + if (user == null) { + user = MessagesController.getInstance().getUser(newContact.user_id); + } else { + MessagesController.getInstance().putUser(user, true); + } + if (user == null || user.phone == null || user.phone.length() == 0) { + reloadContacts = true; + continue; + } + + Contact contact = contactsBookSPhones.get(user.phone); + if (contact != null) { + int index = contact.shortPhones.indexOf(user.phone); + if (index != -1) { + contact.phoneDeleted.set(index, 0); + } + } + if (toAdd.length() != 0) { + toAdd.append(","); + } + toAdd.append(user.phone); + } + + for (final Integer uid : contactsTD) { + Utilities.phoneBookQueue.postRunnable(new Runnable() { + @Override + public void run() { + deleteContactFromPhoneBook(uid); + } + }); + + TLRPC.User user = null; + if (userDict != null) { + user = userDict.get(uid); + } + if (user == null) { + user = MessagesController.getInstance().getUser(uid); + } else { + MessagesController.getInstance().putUser(user, true); + } + if (user == null) { + reloadContacts = true; + continue; + } + + if (user.phone != null && user.phone.length() > 0) { + Contact contact = contactsBookSPhones.get(user.phone); + if (contact != null) { + int index = contact.shortPhones.indexOf(user.phone); + if (index != -1) { + contact.phoneDeleted.set(index, 1); + } + } + if (toDelete.length() != 0) { + toDelete.append(","); + } + toDelete.append(user.phone); + } + } + + if (toAdd.length() != 0 || toDelete.length() != 0) { + MessagesStorage.getInstance().applyPhoneBookUpdates(toAdd.toString(), toDelete.toString()); + } + + if (reloadContacts) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + loadContacts(false, true); + } + }); + } else { + final ArrayList newContacts = newC; + final ArrayList contactsToDelete = contactsTD; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + for (TLRPC.TL_contact contact : newContacts) { + if (contactsDict.get(contact.user_id) == null) { + contacts.add(contact); + contactsDict.put(contact.user_id, contact); + } + } + for (Integer uid : contactsToDelete) { + TLRPC.TL_contact contact = contactsDict.get(uid); + if (contact != null) { + contacts.remove(contact); + contactsDict.remove(uid); + } + } + if (!newContacts.isEmpty()) { + updateUnregisteredContacts(contacts); + performWriteContactsToPhoneBook(); + } + performSyncPhoneBook(getContactsCopy(contactsBook), false, false, false); + buildContactsSectionsArrays(!newContacts.isEmpty()); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.contactsDidLoaded); + } + }); + } + } + + public void processContactsUpdates(ArrayList ids, ConcurrentHashMap userDict) { + final ArrayList newContacts = new ArrayList<>(); + final ArrayList contactsToDelete = new ArrayList<>(); + for (Integer uid : ids) { + if (uid > 0) { + TLRPC.TL_contact contact = new TLRPC.TL_contact(); + contact.user_id = uid; + newContacts.add(contact); + if (!delayedContactsUpdate.isEmpty()) { + int idx = delayedContactsUpdate.indexOf(-uid); + if (idx != -1) { + delayedContactsUpdate.remove(idx); + } + } + } else if (uid < 0) { + contactsToDelete.add(-uid); + if (!delayedContactsUpdate.isEmpty()) { + int idx = delayedContactsUpdate.indexOf(-uid); + if (idx != -1) { + delayedContactsUpdate.remove(idx); + } + } + } + } + if (!contactsToDelete.isEmpty()) { + MessagesStorage.getInstance().deleteContacts(contactsToDelete); + } + if (!newContacts.isEmpty()) { + MessagesStorage.getInstance().putContacts(newContacts, false); + } + if (!contactsLoaded || !contactsBookLoaded) { + delayedContactsUpdate.addAll(ids); + FileLog.e("tmessages", "delay update - contacts add = " + newContacts.size() + " delete = " + contactsToDelete.size()); + } else { + applyContactsUpdates(ids, userDict, newContacts, contactsToDelete); + } + } + + public long addContactToPhoneBook(TLRPC.User user, boolean check) { + if (currentAccount == null || user == null || user.phone == null || user.phone.length() == 0) { + return -1; + } + if (!hasContactsPermission()) { + return -1; + } + long res = -1; + synchronized (observerLock) { + ignoreChanges = true; + } + ContentResolver contentResolver = ApplicationLoader.applicationContext.getContentResolver(); + if (check) { + try { + Uri rawContactUri = ContactsContract.RawContacts.CONTENT_URI.buildUpon().appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, currentAccount.name).appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, currentAccount.type).build(); + int value = contentResolver.delete(rawContactUri, ContactsContract.RawContacts.SYNC2 + " = " + user.id, null); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + ArrayList query = new ArrayList<>(); + + ContentProviderOperation.Builder builder = ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI); + builder.withValue(ContactsContract.RawContacts.ACCOUNT_NAME, currentAccount.name); + builder.withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, currentAccount.type); + builder.withValue(ContactsContract.RawContacts.SYNC1, user.phone); + builder.withValue(ContactsContract.RawContacts.SYNC2, user.id); + query.add(builder.build()); + + builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI); + builder.withValueBackReference(ContactsContract.CommonDataKinds.StructuredName.RAW_CONTACT_ID, 0); + builder.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE); + builder.withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, user.first_name); + builder.withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, user.last_name); + query.add(builder.build()); + +// builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI); +// builder.withValueBackReference(ContactsContract.CommonDataKinds.StructuredName.RAW_CONTACT_ID, 0); +// builder.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE); +// builder.withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, "+" + user.phone); +// builder.withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE); +// query.add(builder.build()); + + builder = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI); + builder.withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0); + builder.withValue(ContactsContract.Data.MIMETYPE, "vnd.android.cursor.item/vnd.org.telegram.messenger.android.profile"); + builder.withValue(ContactsContract.Data.DATA1, user.id); + builder.withValue(ContactsContract.Data.DATA2, "Telegram Profile"); + builder.withValue(ContactsContract.Data.DATA3, "+" + user.phone); + builder.withValue(ContactsContract.Data.DATA4, user.id); + query.add(builder.build()); + try { + ContentProviderResult[] result = contentResolver.applyBatch(ContactsContract.AUTHORITY, query); + if (result != null && result.length > 0 && result[0].uri != null) { + res = Long.parseLong(result[0].uri.getLastPathSegment()); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + synchronized (observerLock) { + ignoreChanges = false; + } + return res; + } + + private void deleteContactFromPhoneBook(int uid) { + if (!hasContactsPermission()) { + return; + } + synchronized (observerLock) { + ignoreChanges = true; + } + try { + ContentResolver contentResolver = ApplicationLoader.applicationContext.getContentResolver(); + Uri rawContactUri = ContactsContract.RawContacts.CONTENT_URI.buildUpon().appendQueryParameter(ContactsContract.CALLER_IS_SYNCADAPTER, "true").appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_NAME, currentAccount.name).appendQueryParameter(ContactsContract.RawContacts.ACCOUNT_TYPE, currentAccount.type).build(); + int value = contentResolver.delete(rawContactUri, ContactsContract.RawContacts.SYNC2 + " = " + uid, null); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + synchronized (observerLock) { + ignoreChanges = false; + } + } + + protected void markAsContacted(final String contactId) { + if (contactId == null) { + return; + } + Utilities.phoneBookQueue.postRunnable(new Runnable() { + @Override + public void run() { + Uri uri = Uri.parse(contactId); + ContentValues values = new ContentValues(); + values.put(ContactsContract.Contacts.LAST_TIME_CONTACTED, System.currentTimeMillis()); + ContentResolver cr = ApplicationLoader.applicationContext.getContentResolver(); + cr.update(uri, values, null, null); + } + }); + } + + public void addContact(TLRPC.User user) { + if (user == null || user.phone == null) { + return; + } + + TLRPC.TL_contacts_importContacts req = new TLRPC.TL_contacts_importContacts(); + ArrayList contactsParams = new ArrayList<>(); + TLRPC.TL_inputPhoneContact c = new TLRPC.TL_inputPhoneContact(); + c.phone = user.phone; + if (!c.phone.startsWith("+")) { + c.phone = "+" + c.phone; + } + c.first_name = user.first_name; + c.last_name = user.last_name; + c.client_id = 0; + contactsParams.add(c); + req.contacts = contactsParams; + req.replace = false; + /*if (BuildVars.DEBUG_VERSION) { + FileLog.e("tmessages", "add contact " + user.first_name + " " + user.last_name + " " + user.phone); + }*/ + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error != null) { + return; + } + final TLRPC.TL_contacts_importedContacts res = (TLRPC.TL_contacts_importedContacts)response; + MessagesStorage.getInstance().putUsersAndChats(res.users, null, true, true); + + /*if (BuildVars.DEBUG_VERSION) { + for (TLRPC.User user : res.users) { + FileLog.e("tmessages", "received user " + user.first_name + " " + user.last_name + " " + user.phone); + } + }*/ + + for (int a = 0; a < res.users.size(); a++) { + final TLRPC.User u = res.users.get(a); + Utilities.phoneBookQueue.postRunnable(new Runnable() { + @Override + public void run() { + addContactToPhoneBook(u, true); + } + }); + TLRPC.TL_contact newContact = new TLRPC.TL_contact(); + newContact.user_id = u.id; + ArrayList arrayList = new ArrayList<>(); + arrayList.add(newContact); + MessagesStorage.getInstance().putContacts(arrayList, false); + + if (u.phone != null && u.phone.length() > 0) { + CharSequence name = formatName(u.first_name, u.last_name); + MessagesStorage.getInstance().applyPhoneBookUpdates(u.phone, ""); + Contact contact = contactsBookSPhones.get(u.phone); + if (contact != null) { + int index = contact.shortPhones.indexOf(u.phone); + if (index != -1) { + contact.phoneDeleted.set(index, 0); + } + } + } + } + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + for (TLRPC.User u : res.users) { + MessagesController.getInstance().putUser(u, false); + if (contactsDict.get(u.id) == null) { + TLRPC.TL_contact newContact = new TLRPC.TL_contact(); + newContact.user_id = u.id; + contacts.add(newContact); + contactsDict.put(newContact.user_id, newContact); + } + } + buildContactsSectionsArrays(true); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.contactsDidLoaded); + } + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagCanCompress); + } + + public void deleteContact(final ArrayList users) { + if (users == null || users.isEmpty()) { + return; + } + TLRPC.TL_contacts_deleteContacts req = new TLRPC.TL_contacts_deleteContacts(); + final ArrayList uids = new ArrayList<>(); + for (TLRPC.User user : users) { + TLRPC.InputUser inputUser = MessagesController.getInputUser(user); + if (inputUser == null) { + continue; + } + uids.add(user.id); + req.id.add(inputUser); + } + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error != null) { + return; + } + MessagesStorage.getInstance().deleteContacts(uids); + Utilities.phoneBookQueue.postRunnable(new Runnable() { + @Override + public void run() { + for (TLRPC.User user : users) { + deleteContactFromPhoneBook(user.id); + } + } + }); + + for (TLRPC.User user : users) { + if (user.phone != null && user.phone.length() > 0) { + CharSequence name = UserObject.getUserName(user); + MessagesStorage.getInstance().applyPhoneBookUpdates(user.phone, ""); + Contact contact = contactsBookSPhones.get(user.phone); + if (contact != null) { + int index = contact.shortPhones.indexOf(user.phone); + if (index != -1) { + contact.phoneDeleted.set(index, 1); + } + } + } + } + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + boolean remove = false; + for (TLRPC.User user : users) { + TLRPC.TL_contact contact = contactsDict.get(user.id); + if (contact != null) { + remove = true; + contacts.remove(contact); + contactsDict.remove(user.id); + } + } + if (remove) { + buildContactsSectionsArrays(false); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_NAME); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.contactsDidLoaded); + } + }); + } + }); + } + + public void reloadContactsStatuses() { + saveContactsLoadTime(); + MessagesController.getInstance().clearFullUsers(); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + final SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("needGetStatuses", true).commit(); + TLRPC.TL_contacts_getStatuses req = new TLRPC.TL_contacts_getStatuses(); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, TLRPC.TL_error error) { + if (error == null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + editor.remove("needGetStatuses").commit(); + TLRPC.Vector vector = (TLRPC.Vector) response; + if (!vector.objects.isEmpty()) { + ArrayList dbUsersStatus = new ArrayList<>(); + for (Object object : vector.objects) { + TLRPC.User toDbUser = new TLRPC.User(); + TLRPC.TL_contactStatus status = (TLRPC.TL_contactStatus) object; + + if (status == null) { + continue; + } + if (status.status instanceof TLRPC.TL_userStatusRecently) { + status.status.expires = -100; + } else if (status.status instanceof TLRPC.TL_userStatusLastWeek) { + status.status.expires = -101; + } else if (status.status instanceof TLRPC.TL_userStatusLastMonth) { + status.status.expires = -102; + } + + TLRPC.User user = MessagesController.getInstance().getUser(status.user_id); + if (user != null) { + user.status = status.status; + } + toDbUser.status = status.status; + dbUsersStatus.add(toDbUser); + } + MessagesStorage.getInstance().updateUsers(dbUsersStatus, true, true, true); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_STATUS); + } + }); + } + } + }); + } + + public void loadPrivacySettings() { + if (loadingDeleteInfo == 0) { + loadingDeleteInfo = 1; + TLRPC.TL_account_getAccountTTL req = new TLRPC.TL_account_getAccountTTL(); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (error == null) { + TLRPC.TL_accountDaysTTL ttl = (TLRPC.TL_accountDaysTTL) response; + deleteAccountTTL = ttl.days; + loadingDeleteInfo = 2; + } else { + loadingDeleteInfo = 0; + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated); + } + }); + } + }); + } + if (loadingLastSeenInfo == 0) { + loadingLastSeenInfo = 1; + TLRPC.TL_account_getPrivacy req = new TLRPC.TL_account_getPrivacy(); + req.key = new TLRPC.TL_inputPrivacyKeyStatusTimestamp(); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (error == null) { + TLRPC.TL_account_privacyRules rules = (TLRPC.TL_account_privacyRules) response; + MessagesController.getInstance().putUsers(rules.users, false); + privacyRules = rules.rules; + loadingLastSeenInfo = 2; + } else { + loadingLastSeenInfo = 0; + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated); + } + }); + } + }); + } + if (loadingGroupInfo == 0) { + loadingGroupInfo = 1; + TLRPC.TL_account_getPrivacy req = new TLRPC.TL_account_getPrivacy(); + req.key = new TLRPC.TL_inputPrivacyKeyChatInvite(); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (error == null) { + TLRPC.TL_account_privacyRules rules = (TLRPC.TL_account_privacyRules) response; + MessagesController.getInstance().putUsers(rules.users, false); + groupPrivacyRules = rules.rules; + loadingGroupInfo = 2; + } else { + loadingGroupInfo = 0; + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated); + } + }); + } + }); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated); + } + + public void setDeleteAccountTTL(int ttl) { + deleteAccountTTL = ttl; + } + + public int getDeleteAccountTTL() { + return deleteAccountTTL; + } + + public boolean getLoadingDeleteInfo() { + return loadingDeleteInfo != 2; + } + + public boolean getLoadingLastSeenInfo() { + return loadingLastSeenInfo != 2; + } + + public boolean getLoadingGroupInfo() { + return loadingGroupInfo != 2; + } + + public ArrayList getPrivacyRules(boolean isGroup) { + if (isGroup) { + return groupPrivacyRules; + } else { + return privacyRules; + } + } + + public void setPrivacyRules(ArrayList rules, boolean isGroup) { + if (isGroup) { + groupPrivacyRules = rules; + } else { + privacyRules = rules; + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.privacyRulesUpdated); + reloadContactsStatuses(); + } + + public static String formatName(String firstName, String lastName) { + /*if ((firstName == null || firstName.length() == 0) && (lastName == null || lastName.length() == 0)) { + return LocaleController.getString("HiddenName", R.string.HiddenName); + }*/ + if (firstName != null) { + firstName = firstName.trim(); + } + if (lastName != null) { + lastName = lastName.trim(); + } + StringBuilder result = new StringBuilder((firstName != null ? firstName.length() : 0) + (lastName != null ? lastName.length() : 0) + 1); + if (LocaleController.nameDisplayOrder == 1) { + if (firstName != null && firstName.length() > 0) { + result.append(firstName); + if (lastName != null && lastName.length() > 0) { + result.append(" "); + result.append(lastName); + } + } else if (lastName != null && lastName.length() > 0) { + result.append(lastName); + } + } else { + if (lastName != null && lastName.length() > 0) { + result.append(lastName); + if (firstName != null && firstName.length() > 0) { + result.append(" "); + result.append(firstName); + } + } else if (firstName != null && firstName.length() > 0) { + result.append(firstName); + } + } + return result.toString(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ContactsSyncAdapterService.java b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsSyncAdapterService.java new file mode 100644 index 00000000..6a08d0f8 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ContactsSyncAdapterService.java @@ -0,0 +1,63 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.accounts.Account; +import android.accounts.OperationCanceledException; +import android.app.Service; +import android.content.AbstractThreadedSyncAdapter; +import android.content.ContentProviderClient; +import android.content.Context; +import android.content.Intent; +import android.content.SyncResult; +import android.os.Bundle; +import android.os.IBinder; + +public class ContactsSyncAdapterService extends Service { + private static SyncAdapterImpl sSyncAdapter = null; + + public ContactsSyncAdapterService() { + super(); + } + + private static class SyncAdapterImpl extends AbstractThreadedSyncAdapter { + private Context mContext; + + public SyncAdapterImpl(Context context) { + super(context, true); + mContext = context; + } + + @Override + public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { + try { + ContactsSyncAdapterService.performSync(mContext, account, extras, authority, provider, syncResult); + } catch (OperationCanceledException e) { + FileLog.e("tmessages", e); + } + } + } + + @Override + public IBinder onBind(Intent intent) { + return getSyncAdapter().getSyncAdapterBinder(); + } + + private SyncAdapterImpl getSyncAdapter() { + if (sSyncAdapter == null) { + sSyncAdapter = new SyncAdapterImpl(this); + } + return sSyncAdapter; + } + + private static void performSync(Context context, Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) + throws OperationCanceledException { + FileLog.d("telegram", "performSync: " + account.toString()); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/DownloadObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/DownloadObject.java new file mode 100644 index 00000000..2a48e1c0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/DownloadObject.java @@ -0,0 +1,17 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import org.telegram.tgnet.TLObject; + +public class DownloadObject { + public TLObject object; + public int type; + public long id; +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java b/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java new file mode 100644 index 00000000..2c948667 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Emoji.java @@ -0,0 +1,510 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.text.Spannable; +import android.text.Spanned; +import android.text.style.DynamicDrawableSpan; +import android.text.style.ImageSpan; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import java.io.File; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Locale; + +public class Emoji { + private static HashMap rects = new HashMap<>(); + private static int drawImgSize; + private static int bigImgSize; + private static boolean inited = false; + private static Paint placeholderPaint; + private static final int splitCount = 4; + private static Bitmap emojiBmp[][] = new Bitmap[5][splitCount]; + private static boolean loadingEmoji[][] = new boolean[5][splitCount]; + + private static final int[][] cols = { + {11, 11, 11, 11}, + {6, 6, 6, 6}, + {9, 9, 9, 9}, + {9, 9, 9, 9}, + {8, 8, 8, 7} + }; + + static { + int emojiFullSize; + if (AndroidUtilities.density <= 1.0f) { + emojiFullSize = 32; + } else if (AndroidUtilities.density <= 1.5f) { + emojiFullSize = 48; + } else if (AndroidUtilities.density <= 2.0f) { + emojiFullSize = 64; + } else { + emojiFullSize = 64; + } + drawImgSize = AndroidUtilities.dp(20); + bigImgSize = AndroidUtilities.dp(AndroidUtilities.isTablet() ? 40 : 32); + + for (int j = 0; j < EmojiData.data.length; j++) { + int count2 = (int) Math.ceil(EmojiData.data[j].length / (float) splitCount); + int position; + for (int i = 0; i < EmojiData.data[j].length; i++) { + int page = i / count2; + position = i - page * count2; + Rect rect = new Rect((position % cols[j][page]) * emojiFullSize, (position / cols[j][page]) * emojiFullSize, (position % cols[j][page] + 1) * emojiFullSize, (position / cols[j][page] + 1) * emojiFullSize); + rects.put(EmojiData.data[j][i], new DrawableInfo(rect, (byte) j, (byte) page)); + } + } + placeholderPaint = new Paint(); + placeholderPaint.setColor(0x00000000); + } + + private static void loadEmoji(final int page, final int page2) { + try { + float scale; + int imageResize = 1; + if (AndroidUtilities.density <= 1.0f) { + scale = 2.0f; + imageResize = 2; + } else if (AndroidUtilities.density <= 1.5f) { + scale = 3.0f; + imageResize = 2; + } else if (AndroidUtilities.density <= 2.0f) { + scale = 2.0f; + } else { + scale = 2.0f; + } + + String imageName; + File imageFile; + + try { + for (int a = 4; a < 6; a++) { + imageName = String.format(Locale.US, "v%d_emoji%.01fx_%d.jpg", a, scale, page); + imageFile = ApplicationLoader.applicationContext.getFileStreamPath(imageName); + if (imageFile.exists()) { + imageFile.delete(); + } + imageName = String.format(Locale.US, "v%d_emoji%.01fx_a_%d.jpg", a, scale, page); + imageFile = ApplicationLoader.applicationContext.getFileStreamPath(imageName); + if (imageFile.exists()) { + imageFile.delete(); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + + imageName = String.format(Locale.US, "v7_emoji%.01fx_%d_%d.jpg", scale, page, page2); + imageFile = ApplicationLoader.applicationContext.getFileStreamPath(imageName); + if (!imageFile.exists()) { + InputStream is = ApplicationLoader.applicationContext.getAssets().open("emoji/" + imageName); + AndroidUtilities.copyFile(is, imageFile); + is.close(); + } + + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inJustDecodeBounds = true; + BitmapFactory.decodeFile(imageFile.getAbsolutePath(), opts); + + int width = opts.outWidth / imageResize; + int height = opts.outHeight / imageResize; + int stride = width * 4; + + final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Utilities.loadBitmap(imageFile.getAbsolutePath(), bitmap, imageResize, width, height, stride); + + imageName = String.format(Locale.US, "v7_emoji%.01fx_a_%d_%d.jpg", scale, page, page2); + imageFile = ApplicationLoader.applicationContext.getFileStreamPath(imageName); + if (!imageFile.exists()) { + InputStream is = ApplicationLoader.applicationContext.getAssets().open("emoji/" + imageName); + AndroidUtilities.copyFile(is, imageFile); + is.close(); + } + + Utilities.loadBitmap(imageFile.getAbsolutePath(), bitmap, imageResize, width, height, stride); + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + emojiBmp[page][page2] = bitmap; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.emojiDidLoaded); + } + }); + } catch (Throwable x) { + FileLog.e("tmessages", "Error loading emoji", x); + } + } + + public static void invalidateAll(View view) { + if (view instanceof ViewGroup) { + ViewGroup g = (ViewGroup) view; + for (int i = 0; i < g.getChildCount(); i++) { + invalidateAll(g.getChildAt(i)); + } + } else if (view instanceof TextView) { + view.invalidate(); + } + } + + public static String fixEmoji(String emoji) { + char ch; + int lenght = emoji.length(); + for (int a = 0; a < lenght; a++) { + ch = emoji.charAt(a); + if (ch >= 0xD83C && ch <= 0xD83E) { + if (ch == 0xD83C && a < lenght - 1) { + ch = emoji.charAt(a + 1); + if (ch == 0xDE2F || ch == 0xDC04 || ch == 0xDE1A || ch == 0xDD7F) { + emoji = emoji.substring(0, a + 2) + "\uFE0F" + emoji.substring(a + 2); + lenght++; + a += 2; + } else { + a++; + } + } else { + a++; + } + } else if (ch == 0x20E3) { + return emoji; + } else if (ch >= 0x203C && ch <= 0x3299) { + if (EmojiData.emojiToFE0FMap.containsKey(ch)) { + emoji = emoji.substring(0, a + 1) + "\uFE0F" + emoji.substring(a + 1); + lenght++; + a++; + } + } + } + return emoji; + } + + public static EmojiDrawable getEmojiDrawable(CharSequence code) { + DrawableInfo info = rects.get(code); + if (info == null) { + FileLog.e("tmessages", "No drawable for emoji " + code); + return null; + } + EmojiDrawable ed = new EmojiDrawable(info); + ed.setBounds(0, 0, drawImgSize, drawImgSize); + return ed; + } + + public static Drawable getEmojiBigDrawable(String code) { + EmojiDrawable ed = getEmojiDrawable(code); + if (ed == null) { + return null; + } + ed.setBounds(0, 0, bigImgSize, bigImgSize); + ed.fullSize = true; + return ed; + } + + public static class EmojiDrawable extends Drawable { + private DrawableInfo info; + private boolean fullSize = false; + private static Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG); + private static Rect rect = new Rect(); + + public EmojiDrawable(DrawableInfo i) { + info = i; + } + + public DrawableInfo getDrawableInfo() { + return info; + } + + public Rect getDrawRect() { + Rect original = getBounds(); + int cX = original.centerX(), cY = original.centerY(); + rect.left = cX - (fullSize ? bigImgSize : drawImgSize) / 2; + rect.right = cX + (fullSize ? bigImgSize : drawImgSize) / 2; + rect.top = cY - (fullSize ? bigImgSize : drawImgSize) / 2; + rect.bottom = cY + (fullSize ? bigImgSize : drawImgSize) / 2; + return rect; + } + + @Override + public void draw(Canvas canvas) { + if (emojiBmp[info.page][info.page2] == null) { + if (loadingEmoji[info.page][info.page2]) { + return; + } + loadingEmoji[info.page][info.page2] = true; + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + loadEmoji(info.page, info.page2); + loadingEmoji[info.page][info.page2] = false; + } + }); + canvas.drawRect(getBounds(), placeholderPaint); + return; + } + + Rect b; + if (fullSize) { + b = getDrawRect(); + } else { + b = getBounds(); + } + + //if (!canvas.quickReject(b.left, b.top, b.right, b.bottom, Canvas.EdgeType.AA)) { + canvas.drawBitmap(emojiBmp[info.page][info.page2], info.rect, b, paint); + //} + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(ColorFilter cf) { + + } + } + + private static class DrawableInfo { + public Rect rect; + public byte page; + public byte page2; + + public DrawableInfo(Rect r, byte p, byte p2) { + rect = r; + page = p; + page2 = p2; + } + } + + private static boolean inArray(char c, char[] a) { + for (char cc : a) { + if (cc == c) { + return true; + } + } + return false; + } + + public static CharSequence replaceEmoji(CharSequence cs, Paint.FontMetricsInt fontMetrics, int size, boolean createNew) { + if (cs == null || cs.length() == 0) { + return cs; + } + /*if (ApplicationLoader.ENABLE_TAGS){ + String s = cs.toString(); + Pattern pattern = Pattern.compile("([*])"); //case insensitive, use [g] for only lower + Matcher matcher = pattern.matcher(s); + int count = 0; + while (matcher.find()) count++; + boolean b = false; + if(count >= 2){ + s = s.replaceAll("\\*(.+?)\\*", "$1"); + b = true; + } + //pattern = Pattern.compile("([_])"); //case insensitive, use [g] for only lower + //matcher = pattern.matcher(s); + //count = 0; + //while (matcher.find()) count++; + //if(count >= 2) { + // s = s.replaceAll("\\_(.+?)\\_", "$1"); + // b = true; + //} + if(b)cs = Html.fromHtml(s); + /*String s = cs.toString(); + boolean b = false; + if(s.contains("*")){ + s = s.replaceAll("\\*(.+?)\\*", "$1"); + b = true; + } + //if(s.contains("_")) { + // s = s.replaceAll("\\_(.+?)\\_", "$1"); + // b = true; + //} + if(b)cs = AndroidUtilities.replaceBoldItalicTags(s); + }*/ + //SpannableStringLight.isFieldsAvailable(); + //SpannableStringLight s = new SpannableStringLight(cs.toString()); + Spannable s; + if (!createNew && cs instanceof Spannable) { + s = (Spannable) cs; + } else { + s = Spannable.Factory.getInstance().newSpannable(cs.toString()); + } + + // If showAndroidEmoji is enabled don't replace anything + if (android.os.Build.VERSION.SDK_INT >= 19 && ApplicationLoader.SHOW_ANDROID_EMOJI) { + return s; + } + long buf = 0; + int emojiCount = 0; + char c; + int startIndex = -1; + int startLength = 0; + int previousGoodIndex = 0; + StringBuilder emojiCode = new StringBuilder(16); + boolean nextIsSkinTone; + EmojiDrawable drawable; + EmojiSpan span; + int length = cs.length(); + boolean doneEmoji = false; + //s.setSpansCount(emojiCount); + + try { + for (int i = 0; i < length; i++) { + c = cs.charAt(i); + if (c >= 0xD83C && c <= 0xD83E || (buf != 0 && (buf & 0xFFFFFFFF00000000L) == 0 && (buf & 0xFFFF) == 0xD83C && (c >= 0xDDE6 && c <= 0xDDFF))) { + if (startIndex == -1) { + startIndex = i; + } + emojiCode.append(c); + startLength++; + buf <<= 16; + buf |= c; + } else if (buf > 0 && (c & 0xF000) == 0xD000) { + emojiCode.append(c); + startLength++; + buf = 0; + doneEmoji = true; + } else if (c == 0x20E3) { + if (i > 0) { + char c2 = cs.charAt(previousGoodIndex); + if ((c2 >= '0' && c2 <= '9') || c2 == '#' || c2 == '*') { + startIndex = previousGoodIndex; + startLength = i - previousGoodIndex + 1; + emojiCode.append(c2); + emojiCode.append(c); + doneEmoji = true; + } + } + } else if ((c == 0x00A9 || c == 0x00AE || c >= 0x203C && c <= 0x3299) && EmojiData.dataCharsMap.containsKey(c)) { + if (startIndex == -1) { + startIndex = i; + } + startLength++; + emojiCode.append(c); + doneEmoji = true; + } else if (startIndex != -1) { + emojiCode.setLength(0); + startIndex = -1; + startLength = 0; + doneEmoji = false; + } + previousGoodIndex = i; + for (int a = 0; a < 3; a++) { + if (i + 1 < length) { + c = cs.charAt(i + 1); + if (a == 1) { + if (c == 0x200D) { + emojiCode.append(c); + i++; + startLength++; + doneEmoji = false; + } + } else { + if (c >= 0xFE00 && c <= 0xFE0F) { + i++; + startLength++; + } + } + } + } + if (doneEmoji) { + if (i + 2 < length) { + if (cs.charAt(i + 1) == 0xD83C && cs.charAt(i + 2) >= 0xDFFB && cs.charAt(i + 2) <= 0xDFFF) { + emojiCode.append(cs.subSequence(i + 1, i + 3)); + startLength += 2; + i += 2; + } + } + drawable = Emoji.getEmojiDrawable(emojiCode.subSequence(0, emojiCode.length())); + if (drawable != null) { + span = new EmojiSpan(drawable, DynamicDrawableSpan.ALIGN_BOTTOM, size, fontMetrics); + s.setSpan(span, startIndex, startIndex + startLength, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + emojiCount++; + } + startLength = 0; + startIndex = -1; + emojiCode.setLength(0); + doneEmoji = false; + } + if (emojiCount >= 50) { //654 new + break; + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + return cs; + } + return s; + } + + public static class EmojiSpan extends ImageSpan { + private Paint.FontMetricsInt fontMetrics = null; + private int size = AndroidUtilities.dp(20); + + public EmojiSpan(EmojiDrawable d, int verticalAlignment, int s, Paint.FontMetricsInt original) { + super(d, verticalAlignment); + fontMetrics = original; + if (original != null) { + size = Math.abs(fontMetrics.descent) + Math.abs(fontMetrics.ascent); + if (size == 0) { + size = AndroidUtilities.dp(20); + } + } + } + + @Override + public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { + if (fm == null) { + fm = new Paint.FontMetricsInt(); + } + + if (fontMetrics == null) { + int sz = super.getSize(paint, text, start, end, fm); + + int offset = AndroidUtilities.dp(8); + int w = AndroidUtilities.dp(10); + fm.top = -w - offset; + fm.bottom = w - offset; + fm.ascent = -w - offset; + fm.leading = 0; + fm.descent = w - offset; + + return sz; + } else { + if (fm != null) { + fm.ascent = fontMetrics.ascent; + fm.descent = fontMetrics.descent; + + fm.top = fontMetrics.top; + fm.bottom = fontMetrics.bottom; + } + if (getDrawable() != null) { + getDrawable().setBounds(0, 0, size, size); + } + return size; + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/EmojiData.java b/TMessagesProj/src/main/java/org/telegram/messenger/EmojiData.java new file mode 100644 index 00000000..b45f53b4 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/EmojiData.java @@ -0,0 +1,348 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import java.util.HashMap; + +public class EmojiData { + + public static final char[] emojiToFE0F = { + 0x2B50, 0x2600, 0x26C5, 0x2601, 0x26A1, 0x2744, 0x26C4, 0x2614, 0x2708, 0x26F5, + 0x2693, 0x26FD, 0x26F2, 0x26FA, 0x26EA, 0x2615, 0x26BD, 0x26BE, 0x26F3, 0x231A, + 0x260E, 0x231B, 0x2709, 0x2702, 0x2712, 0x270F, 0x2648, 0x2649, 0x264A, 0x264B, + 0x264C, 0x264D, 0x264E, 0x264F, 0x2650, 0x2651, 0x2652, 0x2653, 0x2734, 0x3299, + 0x3297, 0x26D4, 0x2B55, 0x2668, 0x2757, 0x203C, 0x2049, 0x303D, 0x26A0, 0x267B, + 0x2747, 0x2733, 0x24C2, 0x267F, 0x25B6, 0x25C0, 0x27A1, 0x2B05, 0x2B06, 0x2B07, + 0x2197, 0x2198, 0x2199, 0x2196, 0x2195, 0x2194, 0x21AA, 0x21A9, 0x2934, 0x2935, + 0x2139, 0x2714, 0x2716, 0x2611, 0x26AA, 0x26AB, 0x25AA, 0x25AB, 0x2B1B, 0x2B1C, + 0x25FC, 0x25FB, 0x25FE, 0x25FD, 0x2660, 0x2663, 0x2665, 0x2666, 0x263A, 0x2639, + 0x270C, 0x261D, 0x2764 + }; + //0xD83CDE2F, 0xD83CDC04, 0xD83CDE1A, 0xD83CDD7F + + public static final char[] dataChars = { + 0x262E, 0x271D, 0x262A, 0x2638, 0x2721, 0x262F, 0x2626, 0x26CE, 0x2648, 0x2649, + 0x264A, 0x264B, 0x264C, 0x264D, 0x264E, 0x264F, 0x2650, 0x2651, 0x2652, 0x2653, + 0x269B, 0x2622, 0x2623, 0x2734, 0x3299, 0x3297, 0x26D4, 0x274C, 0x2B55, 0x2668, + 0x2757, 0x2755, 0x2753, 0x2754, 0x203C, 0x2049, 0x269C, 0x303D, 0x26A0, 0x267B, + 0x2747, 0x2733, 0x274E, 0x2705, 0x27BF, 0x24C2, 0x267F, 0x25B6, 0x23F8, 0x23EF, + 0x23F9, 0x23FA, 0x23ED, 0x23EE, 0x23E9, 0x23EA, 0x25C0, 0x23EB, 0x23EC, 0x27A1, + 0x2B05, 0x2B06, 0x2B07, 0x2197, 0x2198, 0x2199, 0x2196, 0x2195, 0x2194, 0x21AA, + 0x21A9, 0x2934, 0x2935, 0x2139, 0x3030, 0x27B0, 0x2714, 0x2795, 0x2796, 0x2797, + 0x2716, 0x00A9, 0x00AE, 0x2122, 0x2611, 0x26AA, 0x26AB, 0x25AA, 0x25AB, 0x2B1B, + 0x2B1C, 0x25FC, 0x25FB, 0x25FE, 0x25FD, 0x2660, 0x2663, 0x2665, 0x2666, 0x263A, + 0x2639, 0x270A, 0x270C, 0x270B, 0x261D, 0x270D, 0x26D1, 0x2764, 0x2763, 0x2615, + 0x26BD, 0x26BE, 0x26F3, 0x26F7, 0x26F8, 0x26F9, 0x231A, 0x2328, 0x260E, 0x23F1, + 0x23F2, 0x23F0, 0x23F3, 0x231B, 0x2696, 0x2692, 0x26CF, 0x2699, 0x26D3, 0x2694, + 0x2620, 0x26B0, 0x26B1, 0x2697, 0x26F1, 0x2709, 0x2702, 0x2712, 0x270F, 0x2708, + 0x26F5, 0x26F4, 0x2693, 0x26FD, 0x26F2, 0x26F0, 0x26FA, 0x26EA, 0x26E9, 0x2618, + 0x2B50, 0x2728, 0x2604, 0x2600, 0x26C5, 0x2601, 0x26C8, 0x26A1, 0x2744, 0x2603, + 0x26C4, 0x2602, 0x2614 + }; + + public static final String[] emojiColored = { + "🙌", "👏", "👋", "👍", "👎", "👊", "✊", "✌", "👌", "✋", + "👐", "💪", "🙏", "☝", "👆", "👇", "👈", "👉", "🖕", "🖐", + "🤘", "🖖", "✍", "💅", "👂", "👃", "👶", "👦", "👧", "👨", + "👩", "👱", "👴", "👵", "👲", "👳", "👮", "👷", "💂", "🎅", + "👼", "👸", "👰", "🚶", "🏃", "💃", "🙇", "💁", "🙅", "🙆", + "🙋", "🙎", "🙍", "💇", "💆", "🚣", "🏊", "🏄", "🛀", "⛹", + "🏋", "🚴", "🚵", "🏇", + }; + + public static final String[][] dataColored = { + new String[]{ + "😀", "😬", "😁", "😂", "😃", "😄", "😅", "😆", "😇", "😉", "😊", + "🙂", "🙃", "☺", "😋", "😌", "😍", "😘", "😗", "😙", "😚", + "😜", "😝", "😛", "🤑", "🤓", "😎", "🤗", "😏", "😶", "😐", + "😑", "😒", "🙄", "🤔", "😳", "😞", "😟", "😠", "😡", "😔", + "😕", "🙁", "☹", "😣", "😖", "😫", "😩", "😤", "😮", "😱", + "😨", "😰", "😯", "😦", "😧", "😢", "😥", "😪", "😓", "😭", + "😵", "😲", "🤐", "😷", "🤒", "🤕", "😴", "💤", "💩", "😈", + "👿", "👹", "👺", "💀", "👻", "👽", "🤖", "😺", "😸", "😹", + "😻", "😼", "😽", "🙀", "😿", "😾", "🙌", + "👏", "👋", + "👍", + "👎", "👊", + "✊", "✌", + "👌", + "✋", "👐", + "💪", "🙏", + "☝", + "👆", "👇", + "👈", "👉", + "🖕", + "🖐", "🤘", + "🖖", "✍", + "💅", + "👄", "👅", "👂", "👃", + "👁", "👀", "👤", "👥", "🗣", "👶", + "👦", + "👧", "👨", + "👩", "👱", + "👴", + "👵", "👲", + "👳", "👮", + "👷", + "💂", "🕵", "🎅", + "👼", + "👸", "👰", + "🚶", "🏃", + "💃", + "👯", "👫", "👬", "👭", "🙇", + "💁", "🙅", + "🙆", "🙋", + "🙎", + "🙍", "💇", + "💆", "💑", "👩‍❤‍👩", + "👨‍❤‍👨", "💏", "👩‍❤‍💋‍👩", "👨‍❤‍💋‍👨", "👪", "👨‍👩‍👧", "👨‍👩‍👧‍👦", "👨‍👩‍👦‍👦", "👨‍👩‍👧‍👧", "👩‍👩‍👦", + "👩‍👩‍👧", "👩‍👩‍👧‍👦", "👩‍👩‍👦‍👦", "👩‍👩‍👧‍👧", "👨‍👨‍👦", "👨‍👨‍👧", "👨‍👨‍👧‍👦", "👨‍👨‍👦‍👦", "👨‍👨‍👧‍👧", "👚", + "👕", "👖", "👔", "👗", "👙", "👘", "💄", "💋", "👣", "👠", + "👡", "👢", "👞", "👟", "👒", "🎩", "🎓", "👑", "⛑", "🎒", + "👝", "👛", "👜", "💼", "👓", "🕶", "💍", "🌂", "❤", "💛", + "💚", "💙", "💜", "💔", "❣", "💕", "💞", "💓", "💗", "💖", + "💘", "💝", + }, + null, + new String[]{ + "🍏", "🍎", "🍐", "🍊", "🍋", "🍌", "🍉", "🍇", "🍓", "🍈", "🍒", + "🍑", "🍍", "🍅", "🍆", "🌶", "🌽", "🍠", "🍯", "🍞", "🧀", + "🍗", "🍖", "🍤", "🍳", "🍔", "🍟", "🌭", "🍕", "🍝", "🌮", + "🌯", "🍜", "🍲", "🍥", "🍣", "🍱", "🍛", "🍙", "🍚", "🍘", + "🍢", "🍡", "🍧", "🍨", "🍦", "🍰", "🎂", "🍮", "🍬", "🍭", + "🍫", "🍿", "🍩", "🍪", "🍺", "🍻", "🍷", "🍸", "🍹", "🍾", + "🍶", "🍵", "☕", "🍼", "🍴", "🍽", "⚽", "🏀", "🏈", "⚾", + "🎾", "🏐", "🏉", "🎱", "⛳", "🏌", "🏓", "🏸", "🏒", "🏑", + "🏏", "🎿", "⛷", "🏂", "⛸", "🏹", "🎣", "🚣", + "🏊", "🏄", + "🛀", + "⛹", "🏋", + "🚴", "🚵", + "🏇", + "🕴", "🏆", "🎽", "🏅", "🎖", "🎗", "🏵", "🎫", "🎟", + "🎭", "🎨", "🎪", "🎤", "🎧", "🎼", "🎹", "🎷", "🎺", "🎸", + "🎻", "🎬", "🎮", "👾", "🎯", "🎲", "🎰", "🎳", "⌚", "📱", + "📲", "💻", "⌨", "🖥", "🖨", "🖱", "🖲", "🕹", "🗜", "💽", + "💾", "💿", "📀", "📼", "📷", "📸", "📹", "🎥", "📽", "🎞", + "📞", "☎", "📟", "🎛", "⏱", "⏲", "⏰", "🕰", "⏳", "⌛", + "📡", "🔋", "🔌", "💡", "🔦", "🕯", "🗑", "🛢", "💸", "💵", + "💴", "💶", "💷", "💰", "💳", "💎", "⚖", "🔧", "🔨", "⚒", + "🛠", "⛏", "🔩", "⚙", "⛓", "🔫", "💣", "🔪", "🗡", "⚔", + "🛡", "🚬", "☠", "⚰", "⚱", "🏺", "🔮", "📿", "💈", "⚗", + "🔭", "🔬", "🕳", "💊", "💉", "🌡", "🏷", "🔖", "🚽", "🚿", + "🛁", "🔑", "🗝", "🛋", "🛌", "🛏", "🚪", "🛎", "🖼", "🗺", + "⛱", "🗿", "🛍", "🎈", "🎏", "🎀", "🎁", "🎊", "🎉", "🎎", + "🎐", "🎌", "🏮", "✉", "📩", "📨", "📧", "💌", "📮", "📪", + "📫", "📬", "📭", "📦", "📯", "📥", "📤", "📜", "📃", "📑", + "📊", "📈", "📉", "📄", "📅", "📆", "🗓", "📇", "🗃", "🗳", + "🗄", "📋", "🗒", "📁", "📂", "🗂", "🗞", "📰", "📓", "📕", + "📗", "📘", "📙", "📔", "📒", "📚", "📖", "🔗", "📎", "🖇", + "✂", "📐", "📏", "📌", "📍", "🚩", "🏳", "🏴", "🔐", "🔒", + "🔓", "🔏", "🖊", "🖋", "✒", "📝", "✏", "🖍", "🖌", "🔍", + "🔎", + }, + null, + null + }; + + public static final String[][] data = { + new String[]{ + "😀", "😬", "😁", "😂", "😃", "😄", "😅", "😆", "😇", "😉", "😊", + "🙂", "🙃", "☺", "😋", "😌", "😍", "😘", "😗", "😙", "😚", + "😜", "😝", "😛", "🤑", "🤓", "😎", "🤗", "😏", "😶", "😐", + "😑", "😒", "🙄", "🤔", "😳", "😞", "😟", "😠", "😡", "😔", + "😕", "🙁", "☹", "😣", "😖", "😫", "😩", "😤", "😮", "😱", + "😨", "😰", "😯", "😦", "😧", "😢", "😥", "😪", "😓", "😭", + "😵", "😲", "🤐", "😷", "🤒", "🤕", "😴", "💤", "💩", "😈", + "👿", "👹", "👺", "💀", "👻", "👽", "🤖", "😺", "😸", "😹", + "😻", "😼", "😽", "🙀", "😿", "😾", "🙌", "🙌🏻", "🙌🏼", "🙌🏽", + "🙌🏾", "🙌🏿", "👏", "👏🏻", "👏🏼", "👏🏽", "👏🏾", "👏🏿", "👋", "👋🏻", + "👋🏼", "👋🏽", "👋🏾", "👋🏿", "👍", "👍🏻", "👍🏼", "👍🏽", "👍🏾", "👍🏿", + "👎", "👎🏻", "👎🏼", "👎🏽", "👎🏾", "👎🏿", "👊", "👊🏻", "👊🏼", "👊🏽", + "👊🏾", "👊🏿", "✊", "✊🏻", "✊🏼", "✊🏽", "✊🏾", "✊🏿", "✌", "✌🏻", + "✌🏼", "✌🏽", "✌🏾", "✌🏿", "👌", "👌🏻", "👌🏼", "👌🏽", "👌🏾", "👌🏿", + "✋", "✋🏻", "✋🏼", "✋🏽", "✋🏾", "✋🏿", "👐", "👐🏻", "👐🏼", "👐🏽", + "👐🏾", "👐🏿", "💪", "💪🏻", "💪🏼", "💪🏽", "💪🏾", "💪🏿", "🙏", "🙏🏻", + "🙏🏼", "🙏🏽", "🙏🏾", "🙏🏿", "☝", "☝🏻", "☝🏼", "☝🏽", "☝🏾", "☝🏿", + "👆", "👆🏻", "👆🏼", "👆🏽", "👆🏾", "👆🏿", "👇", "👇🏻", "👇🏼", "👇🏽", + "👇🏾", "👇🏿", "👈", "👈🏻", "👈🏼", "👈🏽", "👈🏾", "👈🏿", "👉", "👉🏻", + "👉🏼", "👉🏽", "👉🏾", "👉🏿", "🖕", "🖕🏻", "🖕🏼", "🖕🏽", "🖕🏾", "🖕🏿", + "🖐", "🖐🏻", "🖐🏼", "🖐🏽", "🖐🏾", "🖐🏿", "🤘", "🤘🏻", "🤘🏼", "🤘🏽", + "🤘🏾", "🤘🏿", "🖖", "🖖🏻", "🖖🏼", "🖖🏽", "🖖🏾", "🖖🏿", "✍", "✍🏻", + "✍🏼", "✍🏽", "✍🏾", "✍🏿", "💅", "💅🏻", "💅🏼", "💅🏽", "💅🏾", "💅🏿", + "👄", "👅", "👂", "👂🏻", "👂🏼", "👂🏽", "👂🏾", "👂🏿", "👃", "👃🏻", + "👃🏼", "👃🏽", "👃🏾", "👃🏿", "👁", "👀", "👤", "👥", "🗣", "👶", + "👶🏻", "👶🏼", "👶🏽", "👶🏾", "👶🏿", "👦", "👦🏻", "👦🏼", "👦🏽", "👦🏾", + "👦🏿", "👧", "👧🏻", "👧🏼", "👧🏽", "👧🏾", "👧🏿", "👨", "👨🏻", "👨🏼", + "👨🏽", "👨🏾", "👨🏿", "👩", "👩🏻", "👩🏼", "👩🏽", "👩🏾", "👩🏿", "👱", + "👱🏻", "👱🏼", "👱🏽", "👱🏾", "👱🏿", "👴", "👴🏻", "👴🏼", "👴🏽", "👴🏾", + "👴🏿", "👵", "👵🏻", "👵🏼", "👵🏽", "👵🏾", "👵🏿", "👲", "👲🏻", "👲🏼", + "👲🏽", "👲🏾", "👲🏿", "👳", "👳🏻", "👳🏼", "👳🏽", "👳🏾", "👳🏿", "👮", + "👮🏻", "👮🏼", "👮🏽", "👮🏾", "👮🏿", "👷", "👷🏻", "👷🏼", "👷🏽", "👷🏾", + "👷🏿", "💂", "💂🏻", "💂🏼", "💂🏽", "💂🏾", "💂🏿", "🕵", "🎅", "🎅🏻", + "🎅🏼", "🎅🏽", "🎅🏾", "🎅🏿", "👼", "👼🏻", "👼🏼", "👼🏽", "👼🏾", "👼🏿", + "👸", "👸🏻", "👸🏼", "👸🏽", "👸🏾", "👸🏿", "👰", "👰🏻", "👰🏼", "👰🏽", + "👰🏾", "👰🏿", "🚶", "🚶🏻", "🚶🏼", "🚶🏽", "🚶🏾", "🚶🏿", "🏃", "🏃🏻", + "🏃🏼", "🏃🏽", "🏃🏾", "🏃🏿", "💃", "💃🏻", "💃🏼", "💃🏽", "💃🏾", "💃🏿", + "👯", "👫", "👬", "👭", "🙇", "🙇🏻", "🙇🏼", "🙇🏽", "🙇🏾", "🙇🏿", + "💁", "💁🏻", "💁🏼", "💁🏽", "💁🏾", "💁🏿", "🙅", "🙅🏻", "🙅🏼", "🙅🏽", + "🙅🏾", "🙅🏿", "🙆", "🙆🏻", "🙆🏼", "🙆🏽", "🙆🏾", "🙆🏿", "🙋", "🙋🏻", + "🙋🏼", "🙋🏽", "🙋🏾", "🙋🏿", "🙎", "🙎🏻", "🙎🏼", "🙎🏽", "🙎🏾", "🙎🏿", + "🙍", "🙍🏻", "🙍🏼", "🙍🏽", "🙍🏾", "🙍🏿", "💇", "💇🏻", "💇🏼", "💇🏽", + "💇🏾", "💇🏿", "💆", "💆🏻", "💆🏼", "💆🏽", "💆🏾", "💆🏿", "💑", "👩‍❤‍👩", + "👨‍❤‍👨", "💏", "👩‍❤‍💋‍👩", "👨‍❤‍💋‍👨", "👪", "👨‍👩‍👧", "👨‍👩‍👧‍👦", "👨‍👩‍👦‍👦", "👨‍👩‍👧‍👧", "👩‍👩‍👦", + "👩‍👩‍👧", "👩‍👩‍👧‍👦", "👩‍👩‍👦‍👦", "👩‍👩‍👧‍👧", "👨‍👨‍👦", "👨‍👨‍👧", "👨‍👨‍👧‍👦", "👨‍👨‍👦‍👦", "👨‍👨‍👧‍👧", "👚", + "👕", "👖", "👔", "👗", "👙", "👘", "💄", "💋", "👣", "👠", + "👡", "👢", "👞", "👟", "👒", "🎩", "🎓", "👑", "⛑", "🎒", + "👝", "👛", "👜", "💼", "👓", "🕶", "💍", "🌂", "❤", "💛", + "💚", "💙", "💜", "💔", "❣", "💕", "💞", "💓", "💗", "💖", + "💘", "💝" + }, + new String[]{ + "🐶", "🐱", "🐭", "🐹", "🐰", "🐻", "🐼", "🐨", "🐯", "🦁", "🐮", + "🐷", "🐽", "🐸", "🐙", "🐵", "🙈", "🙉", "🙊", "🐒", "🐔", + "🐧", "🐦", "🐤", "🐣", "🐥", "🐺", "🐗", "🐴", "🦄", "🐝", + "🐛", "🐌", "🐞", "🐜", "🕷", "🦂", "🦀", "🐍", "🐢", "🐠", + "🐟", "🐡", "🐬", "🐳", "🐋", "🐊", "🐆", "🐅", "🐃", "🐂", + "🐄", "🐪", "🐫", "🐘", "🐐", "🐏", "🐑", "🐎", "🐖", "🐀", + "🐁", "🐓", "🦃", "🕊", "🐕", "🐩", "🐈", "🐇", "🐿", "🐾", + "🐉", "🐲", "🌵", "🎄", "🌲", "🌳", "🌴", "🌱", "🌿", "☘", + "🍀", "🎍", "🎋", "🍃", "🍂", "🍁", "🌾", "🌺", "🌻", "🌹", + "🌷", "🌼", "🌸", "💐", "🍄", "🌰", "🎃", "🐚", "🕸", "🌎", + "🌍", "🌏", "🌕", "🌖", "🌗", "🌘", "🌑", "🌒", "🌓", "🌔", + "🌚", "🌝", "🌛", "🌜", "🌞", "🌙", "⭐", "🌟", "💫", "✨", + "☄", "☀", "🌤", "⛅", "🌥", "🌦", "☁", "🌧", "⛈", "🌩", + "⚡", "🔥", "💥", "❄", "🌨", "☃", "⛄", "🌬", "💨", "🌪", + "🌫", "☂", "☔", "💧", "💦", "🌊" + }, + new String[]{ + "🍏", "🍎", "🍐", "🍊", "🍋", "🍌", "🍉", "🍇", "🍓", "🍈", "🍒", + "🍑", "🍍", "🍅", "🍆", "🌶", "🌽", "🍠", "🍯", "🍞", "🧀", + "🍗", "🍖", "🍤", "🍳", "🍔", "🍟", "🌭", "🍕", "🍝", "🌮", + "🌯", "🍜", "🍲", "🍥", "🍣", "🍱", "🍛", "🍙", "🍚", "🍘", + "🍢", "🍡", "🍧", "🍨", "🍦", "🍰", "🎂", "🍮", "🍬", "🍭", + "🍫", "🍿", "🍩", "🍪", "🍺", "🍻", "🍷", "🍸", "🍹", "🍾", + "🍶", "🍵", "☕", "🍼", "🍴", "🍽", "⚽", "🏀", "🏈", "⚾", + "🎾", "🏐", "🏉", "🎱", "⛳", "🏌", "🏓", "🏸", "🏒", "🏑", + "🏏", "🎿", "⛷", "🏂", "⛸", "🏹", "🎣", "🚣", "🚣🏻", "🚣🏼", + "🚣🏽", "🚣🏾", "🚣🏿", "🏊", "🏊🏻", "🏊🏼", "🏊🏽", "🏊🏾", "🏊🏿", "🏄", + "🏄🏻", "🏄🏼", "🏄🏽", "🏄🏾", "🏄🏿", "🛀", "🛀🏻", "🛀🏼", "🛀🏽", "🛀🏾", + "🛀🏿", "⛹", "⛹🏻", "⛹🏼", "⛹🏽", "⛹🏾", "⛹🏿", "🏋", "🏋🏻", "🏋🏼", + "🏋🏽", "🏋🏾", "🏋🏿", "🚴", "🚴🏻", "🚴🏼", "🚴🏽", "🚴🏾", "🚴🏿", "🚵", + "🚵🏻", "🚵🏼", "🚵🏽", "🚵🏾", "🚵🏿", "🏇", "🏇🏻", "🏇🏼", "🏇🏽", "🏇🏾", + "🏇🏿", "🕴", "🏆", "🎽", "🏅", "🎖", "🎗", "🏵", "🎫", "🎟", + "🎭", "🎨", "🎪", "🎤", "🎧", "🎼", "🎹", "🎷", "🎺", "🎸", + "🎻", "🎬", "🎮", "👾", "🎯", "🎲", "🎰", "🎳", "⌚", "📱", + "📲", "💻", "⌨", "🖥", "🖨", "🖱", "🖲", "🕹", "🗜", "💽", + "💾", "💿", "📀", "📼", "📷", "📸", "📹", "🎥", "📽", "🎞", + "📞", "☎", "📟", "🎛", "⏱", "⏲", "⏰", "🕰", "⏳", "⌛", + "📡", "🔋", "🔌", "💡", "🔦", "🕯", "🗑", "🛢", "💸", "💵", + "💴", "💶", "💷", "💰", "💳", "💎", "⚖", "🔧", "🔨", "⚒", + "🛠", "⛏", "🔩", "⚙", "⛓", "🔫", "💣", "🔪", "🗡", "⚔", + "🛡", "🚬", "☠", "⚰", "⚱", "🏺", "🔮", "📿", "💈", "⚗", + "🔭", "🔬", "🕳", "💊", "💉", "🌡", "🏷", "🔖", "🚽", "🚿", + "🛁", "🔑", "🗝", "🛋", "🛌", "🛏", "🚪", "🛎", "🖼", "🗺", + "⛱", "🗿", "🛍", "🎈", "🎏", "🎀", "🎁", "🎊", "🎉", "🎎", + "🎐", "🎌", "🏮", "✉", "📩", "📨", "📧", "💌", "📮", "📪", + "📫", "📬", "📭", "📦", "📯", "📥", "📤", "📜", "📃", "📑", + "📊", "📈", "📉", "📄", "📅", "📆", "🗓", "📇", "🗃", "🗳", + "🗄", "📋", "🗒", "📁", "📂", "🗂", "🗞", "📰", "📓", "📕", + "📗", "📘", "📙", "📔", "📒", "📚", "📖", "🔗", "📎", "🖇", + "✂", "📐", "📏", "📌", "📍", "🚩", "🏳", "🏴", "🔐", "🔒", + "🔓", "🔏", "🖊", "🖋", "✒", "📝", "✏", "🖍", "🖌", "🔍", + "🔎" + }, + new String[]{ + "🚗", "🚕", "🚙", "🚌", "🚎", "🏎", "🚓", "🚑", "🚒", "🚐", "🚚", + "🚛", "🚜", "🏍", "🚲", "🚨", "🚔", "🚍", "🚘", "🚖", "🚡", + "🚠", "🚟", "🚃", "🚋", "🚝", "🚄", "🚅", "🚈", "🚞", "🚂", + "🚆", "🚇", "🚊", "🚉", "🚁", "🛩", "✈", "🛫", "🛬", "⛵", + "🛥", "🚤", "⛴", "🛳", "🚀", "🛰", "💺", "⚓", "🚧", "⛽", + "🚏", "🚦", "🚥", "🏁", "🚢", "🎡", "🎢", "🎠", "🏗", "🌁", + "🗼", "🏭", "⛲", "🎑", "⛰", "🏔", "🗻", "🌋", "🗾", "🏕", + "⛺", "🏞", "🛣", "🛤", "🌅", "🌄", "🏜", "🏖", "🏝", "🌇", + "🌆", "🏙", "🌃", "🌉", "🌌", "🌠", "🎇", "🎆", "🌈", "🏘", + "🏰", "🏯", "🏟", "🗽", "🏠", "🏡", "🏚", "🏢", "🏬", "🏣", + "🏤", "🏥", "🏦", "🏨", "🏪", "🏫", "🏩", "💒", "🏛", "⛪", + "🕌", "🕍", "🕋", "⛩", "🇦🇺", "🇦🇹", "🇦🇿", "🇦🇽", "🇦🇱", "🇩🇿", + "🇦🇸", "🇦🇮", "🇦🇴", "🇦🇩", "🇦🇶", "🇦🇬", "🇦🇷", "🇦🇲", "🇦🇼", "🇦🇫", + "🇧🇸", "🇧🇩", "🇧🇧", "🇧🇭", "🇧🇾", "🇧🇿", "🇧🇪", "🇧🇯", "🇧🇲", "🇧🇬", + "🇧🇴", "🇧🇶", "🇧🇦", "🇧🇼", "🇧🇷", "🇮🇴", "🇧🇳", "🇧🇫", "🇧🇮", "🇧🇹", + "🇻🇺", "🇻🇦", "🇬🇧", "🇭🇺", "🇻🇪", "🇻🇬", "🇻🇮", "🇹🇱", "🇻🇳", "🇬🇦", + "🇭🇹", "🇬🇾", "🇬🇲", "🇬🇭", "🇬🇵", "🇬🇹", "🇬🇳", "🇬🇼", "🇩🇪", "🇬🇬", + "🇬🇮", "🇭🇳", "🇭🇰", "🇬🇩", "🇬🇱", "🇬🇷", "🇬🇪", "🇬🇺", "🇩🇰", "🇯🇪", + "🇩🇯", "🇩🇲", "🇩🇴", "🇪🇺", "🇪🇬", "🇿🇲", "🇪🇭", "🇿🇼", "🇮🇱", "🇮🇳", + "🇮🇩", "🇯🇴", "🇮🇶", "🇮🇷", "🇮🇪", "🇮🇸", "🇪🇸", "🇮🇹", "🇾🇪", "🇨🇻", + "🇰🇿", "🇰🇾", "🇰🇭", "🇨🇲", "🇨🇦", "🇮🇨", "🇶🇦", "🇰🇪", "🇨🇾", "🇰🇬", + "🇰🇮", "🇨🇳", "🇰🇵", "🇨🇨", "🇨🇴", "🇰🇲", "🇨🇬", "🇨🇩", "🇽🇰", "🇨🇷", + "🇨🇮", "🇨🇺", "🇰🇼", "🇨🇼", "🇱🇦", "🇱🇻", "🇱🇸", "🇱🇷", "🇱🇧", "🇱🇾", + "🇱🇹", "🇱🇮", "🇱🇺", "🇲🇺", "🇲🇷", "🇲🇬", "🇾🇹", "🇲🇴", "🇲🇰", "🇲🇼", + "🇲🇾", "🇲🇱", "🇲🇻", "🇲🇹", "🇲🇦", "🇲🇶", "🇲🇭", "🇲🇽", "🇫🇲", "🇲🇿", + "🇲🇩", "🇲🇨", "🇲🇳", "🇲🇸", "🇲🇲", "🇳🇦", "🇳🇷", "🇳🇵", "🇳🇪", "🇳🇬", + "🇳🇱", "🇳🇮", "🇳🇺", "🇳🇿", "🇳🇨", "🇳🇴", "🇮🇲", "🇳🇫", "🇨🇽", "🇸🇭", + "🇨🇰", "🇹🇨", "🇦🇪", "🇴🇲", "🇵🇰", "🇵🇼", "🇵🇸", "🇵🇦", "🇵🇬", "🇵🇾", + "🇵🇪", "🇵🇳", "🇵🇱", "🇵🇹", "🇵🇷", "🇰🇷", "🇷🇪", "🇷🇺", "🇷🇼", "🇷🇴", + "🇸🇻", "🇼🇸", "🇸🇲", "🇸🇹", "🇸🇦", "🇸🇿", "🇲🇵", "🇸🇨", "🇧🇱", "🇵🇲", + "🇸🇳", "🇻🇨", "🇰🇳", "🇱🇨", "🇷🇸", "🇸🇬", "🇸🇽", "🇸🇾", "🇸🇰", "🇸🇮", + "🇺🇸", "🇸🇧", "🇸🇴", "🇸🇩", "🇸🇷", "🇸🇱", "🇹🇯", "🇹🇭", "🇹🇼", "🇹🇿", + "🇹🇬", "🇹🇰", "🇹🇴", "🇹🇹", "🇹🇻", "🇹🇳", "🇹🇲", "🇹🇷", "🇺🇬", "🇺🇿", + "🇺🇦", "🇼🇫", "🇺🇾", "🇫🇴", "🇫🇯", "🇵🇭", "🇫🇮", "🇫🇰", "🇫🇷", "🇬🇫", + "🇵🇫", "🇹🇫", "🇭🇷", "🇨🇫", "🇹🇩", "🇲🇪", "🇨🇿", "🇨🇱", "🇨🇭", "🇸🇪", + "🇱🇰", "🇪🇨", "🇬🇶", "🇪🇷", "🇪🇪", "🇪🇹", "🇿🇦", "🇬🇸", "🇸🇸", "🇯🇲", + "🇯🇵" + }, + new String[]{ + "💟", "☮", "✝", "☪", "🕉", "☸", "✡", "🔯", "🕎", "☯", "☦", + "🛐", "⛎", "♈", "♉", "♊", "♋", "♌", "♍", "♎", "♏", + "♐", "♑", "♒", "♓", "🆔", "⚛", "🈳", "🈹", "☢", "☣", + "📴", "📳", "🈶", "🈚", "🈸", "🈺", "🈷", "✴", "🆚", "🉑", + "💮", "🉐", "㊙", "㊗", "🈴", "🈵", "🈲", "🅰", "🅱", "🆎", + "🆑", "🅾", "🆘", "⛔", "📛", "🚫", "❌", "⭕", "💢", "♨", + "🚷", "🚯", "🚳", "🚱", "🔞", "📵", "❗", "❕", "❓", "❔", + "‼", "⁉", "💯", "🔅", "🔆", "🔱", "⚜", "〽", "⚠", "🚸", + "🔰", "♻", "🈯", "💹", "❇", "✳", "❎", "✅", "💠", "🌀", + "➿", "🌐", "Ⓜ", "🏧", "🈂", "🛂", "🛃", "🛄", "🛅", "♿", + "🚭", "🚾", "🅿", "🚰", "🚹", "🚺", "🚼", "🚻", "🚮", "🎦", + "📶", "🈁", "🆖", "🆗", "🆙", "🆒", "🆕", "🆓", "0⃣", "1⃣", + "2⃣", "3⃣", "4⃣", "5⃣", "6⃣", "7⃣", "8⃣", "9⃣", "🔟", "🔢", + "▶", "⏸", "⏯", "⏹", "⏺", "⏭", "⏮", "⏩", "⏪", "🔀", + "🔁", "🔂", "◀", "🔼", "🔽", "⏫", "⏬", "➡", "⬅", "⬆", + "⬇", "↗", "↘", "↙", "↖", "↕", "↔", "🔄", "↪", "↩", + "⤴", "⤵", "#⃣", "*⃣", "ℹ", "🔤", "🔡", "🔠", "🔣", "🎵", + "🎶", "〰", "➰", "✔", "🔃", "➕", "➖", "➗", "✖", "💲", + "💱", "©", "®", "™", "🔚", "🔙", "🔛", "🔝", "🔜", "☑", + "🔘", "⚪", "⚫", "🔴", "🔵", "🔸", "🔹", "🔶", "🔷", "🔺", + "▪", "▫", "⬛", "⬜", "🔻", "◼", "◻", "◾", "◽", "🔲", + "🔳", "🔈", "🔉", "🔊", "🔇", "📣", "📢", "🔔", "🔕", "🃏", + "🀄", "♠", "♣", "♥", "♦", "🎴", "👁‍🗨", "💭", "🗯", "💬", + "🕐", "🕑", "🕒", "🕓", "🕔", "🕕", "🕖", "🕗", "🕘", "🕙", + "🕚", "🕛", "🕜", "🕝", "🕞", "🕟", "🕠", "🕡", "🕢", "🕣", + "🕤", "🕥", "🕦", "🕧" + } + }; + + public static final HashMap emojiToFE0FMap = new HashMap<>(emojiToFE0F.length); + public static final HashMap dataCharsMap = new HashMap<>(dataChars.length); + public static final HashMap emojiColoredMap = new HashMap<>(emojiColored.length); + + static { + for (int a = 0; a < emojiToFE0F.length; a++) { + emojiToFE0FMap.put(emojiToFE0F[a], true); + } + for (int a = 0; a < dataChars.length; a++) { + dataCharsMap.put(dataChars[a], true); + } + for (int a = 0; a < emojiColored.length; a++) { + emojiColoredMap.put(emojiColored[a], true); + } + dataColored[1] = data[1]; + dataColored[3] = data[3]; + dataColored[4] = data[4]; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java index 4e18382e..7bbb5cd6 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoadOperation.java @@ -8,13 +8,15 @@ package org.telegram.messenger; +import android.util.Log; + import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; -import java.io.File; import java.io.RandomAccessFile; +import java.io.File; import java.nio.channels.FileChannel; import java.util.ArrayList; import java.util.Scanner; @@ -97,77 +99,63 @@ public class FileLoadOperation { orgName = null; } - public FileLoadOperation(TLRPC.Video videoLocation) { - if (videoLocation instanceof TLRPC.TL_videoEncrypted) { - location = new TLRPC.TL_inputEncryptedFileLocation(); - location.id = videoLocation.id; - location.access_hash = videoLocation.access_hash; - datacenter_id = videoLocation.dc_id; - iv = new byte[32]; - System.arraycopy(videoLocation.iv, 0, iv, 0, iv.length); - key = videoLocation.key; - } else if (videoLocation instanceof TLRPC.TL_video) { - location = new TLRPC.TL_inputVideoFileLocation(); - datacenter_id = videoLocation.dc_id; - location.id = videoLocation.id; - location.access_hash = videoLocation.access_hash; - } - totalBytesCount = videoLocation.size; - ext = ".mp4"; - } - - public FileLoadOperation(TLRPC.Audio audioLocation) { - if (audioLocation instanceof TLRPC.TL_audioEncrypted) { - location = new TLRPC.TL_inputEncryptedFileLocation(); - location.id = audioLocation.id; - location.access_hash = audioLocation.access_hash; - datacenter_id = audioLocation.dc_id; - iv = new byte[32]; - System.arraycopy(audioLocation.iv, 0, iv, 0, iv.length); - key = audioLocation.key; - } else if (audioLocation instanceof TLRPC.TL_audio) { - location = new TLRPC.TL_inputAudioFileLocation(); - datacenter_id = audioLocation.dc_id; - location.id = audioLocation.id; - location.access_hash = audioLocation.access_hash; - } - totalBytesCount = audioLocation.size; - ext = ".ogg"; - } - public FileLoadOperation(TLRPC.Document documentLocation) { - if (documentLocation instanceof TLRPC.TL_documentEncrypted) { - location = new TLRPC.TL_inputEncryptedFileLocation(); - location.id = documentLocation.id; - location.access_hash = documentLocation.access_hash; - datacenter_id = documentLocation.dc_id; - iv = new byte[32]; - System.arraycopy(documentLocation.iv, 0, iv, 0, iv.length); - key = documentLocation.key; - } else if (documentLocation instanceof TLRPC.TL_document) { - location = new TLRPC.TL_inputDocumentFileLocation(); - location.id = documentLocation.id; - location.access_hash = documentLocation.access_hash; - datacenter_id = documentLocation.dc_id; - } - if (totalBytesCount <= 0) { - totalBytesCount = documentLocation.size; - } - if (ext == null) { + try { + if (documentLocation instanceof TLRPC.TL_documentEncrypted) { + location = new TLRPC.TL_inputEncryptedFileLocation(); + location.id = documentLocation.id; + location.access_hash = documentLocation.access_hash; + datacenter_id = documentLocation.dc_id; + iv = new byte[32]; + System.arraycopy(documentLocation.iv, 0, iv, 0, iv.length); + key = documentLocation.key; + } else if (documentLocation instanceof TLRPC.TL_document) { + location = new TLRPC.TL_inputDocumentFileLocation(); + location.id = documentLocation.id; + location.access_hash = documentLocation.access_hash; + datacenter_id = documentLocation.dc_id; + } + if (totalBytesCount <= 0) { + totalBytesCount = documentLocation.size; + } ext = FileLoader.getDocumentFileName(documentLocation); int idx; - if (ext == null || (idx = ext.lastIndexOf(".")) == -1) { + if (ext == null || (idx = ext.lastIndexOf('.')) == -1) { ext = ""; } else { ext = ext.substring(idx); - if (ext.length() <= 1) { + } + if (ext.length() <= 1) { + if (documentLocation.mime_type != null) { + switch (documentLocation.mime_type) { + case "video/mp4": + ext = ".mp4"; + break; + case "audio/ogg": + ext = ".ogg"; + break; + default: + ext = ""; + break; + } + } else { ext = ""; } } - if(ApplicationLoader.KEEP_ORIGINAL_FILENAME && !ext.contains("webp") && !FileLoader.isGif(documentLocation)) { + if(ext.length() > 1 && ApplicationLoader.KEEP_ORIGINAL_FILENAME && !ext.contains("webp") && !ext.contains(".mp4") && !ext.contains(".gif") && !ext.contains(".ogg")) { orgName = FileLoader.getDocName(documentLocation); } + } catch (Exception e) { + FileLog.e("tmessages", e); + state = stateFailed; + cleanup(); + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + delegate.didFailedLoadingFile(FileLoadOperation.this, 0); + } + }); } } @@ -194,6 +182,7 @@ public class FileLoadOperation { delayedRequestInfos = new ArrayList<>(currentMaxDownloadRequests - 1); state = stateDownloading; if (location == null) { + cleanup(); Utilities.stageQueue.postRunnable(new Runnable() { @Override public void run() { @@ -332,7 +321,8 @@ public class FileLoadOperation { state = stateFailed; cleanup(); if (requestInfos != null) { - for (RequestInfo requestInfo : requestInfos) { + for (int a = 0; a < requestInfos.size(); a++) { + RequestInfo requestInfo = requestInfos.get(a); if (requestInfo.requestToken != 0) { ConnectionsManager.getInstance().cancelRequest(requestInfo.requestToken, true); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java index da37a22c..852d1aa7 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLoader.java @@ -278,50 +278,37 @@ public class FileLoader { }); } - public void cancelLoadFile(TLRPC.Video video) { - cancelLoadFile(video, null, null, null, null); - } - public void cancelLoadFile(TLRPC.Document document) { - cancelLoadFile(null, document, null, null, null); - } - - public void cancelLoadFile(TLRPC.Audio audio) { - cancelLoadFile(null, null, audio, null, null); + cancelLoadFile(document, null, null); } public void cancelLoadFile(TLRPC.PhotoSize photo) { - cancelLoadFile(null, null, null, photo.location, null); + cancelLoadFile(null, photo.location, null); } public void cancelLoadFile(TLRPC.FileLocation location, String ext) { - cancelLoadFile(null, null, null, location, ext); + cancelLoadFile(null, location, ext); } - private void cancelLoadFile(final TLRPC.Video video, final TLRPC.Document document, final TLRPC.Audio audio, final TLRPC.FileLocation location, final String locationExt) { - if (video == null && location == null && document == null && audio == null) { + private void cancelLoadFile(final TLRPC.Document document, final TLRPC.FileLocation location, final String locationExt) { + if (location == null && document == null) { return; } fileLoaderQueue.postRunnable(new Runnable() { @Override public void run() { String fileName = null; - if (video != null) { - fileName = getAttachFileName(video); - } else if (location != null) { + if (location != null) { fileName = getAttachFileName(location, locationExt); } else if (document != null) { fileName = getAttachFileName(document); - } else if (audio != null) { - fileName = getAttachFileName(audio); } if (fileName == null) { return; } - FileLoadOperation operation = loadOperationPaths.get(fileName); + FileLoadOperation operation = loadOperationPaths.remove(fileName); if (operation != null) { - loadOperationPaths.remove(fileName); - if (audio != null) { + if (MessageObject.isVoiceDocument(document)) { audioLoadOperationQueue.remove(operation); } else if (location != null) { photoLoadOperationQueue.remove(operation); @@ -352,39 +339,27 @@ public class FileLoader { return result[0]; } - public void loadFile(TLRPC.Video video, boolean force) { - loadFile(video, null, null, null, null, 0, force, video != null && video.key != null); - } - public void loadFile(TLRPC.PhotoSize photo, String ext, boolean cacheOnly) { - loadFile(null, null, null, photo.location, ext, photo.size, false, cacheOnly || (photo != null && photo.size == 0 || photo.location.key != null)); + loadFile(null, photo.location, ext, photo.size, false, cacheOnly || (photo != null && photo.size == 0 || photo.location.key != null)); } public void loadFile(TLRPC.Document document, boolean force, boolean cacheOnly) { - loadFile(null, document, null, null, null, 0, force, cacheOnly || document != null && document.key != null); - } - - public void loadFile(TLRPC.Audio audio, boolean force) { - loadFile(null, null, audio, null, null, 0, false, audio != null && audio.key != null); + loadFile(document, null, null, 0, force, cacheOnly || document != null && document.key != null); } public void loadFile(TLRPC.FileLocation location, String ext, int size, boolean cacheOnly) { - loadFile(null, null, null, location, ext, size, true, cacheOnly || size == 0 || (location != null && location.key != null)); + loadFile(null, location, ext, size, true, cacheOnly || size == 0 || (location != null && location.key != null)); } - private void loadFile(final TLRPC.Video video, final TLRPC.Document document, final TLRPC.Audio audio, final TLRPC.FileLocation location, final String locationExt, final int locationSize, final boolean force, final boolean cacheOnly) { + private void loadFile(final TLRPC.Document document, final TLRPC.FileLocation location, final String locationExt, final int locationSize, final boolean force, final boolean cacheOnly) { fileLoaderQueue.postRunnable(new Runnable() { @Override public void run() { String fileName = null; - if (video != null) { - fileName = getAttachFileName(video); - } else if (location != null) { + if (location != null) { fileName = getAttachFileName(location, locationExt); } else if (document != null) { fileName = getAttachFileName(document); - } else if (audio != null) { - fileName = getAttachFileName(audio); } if (fileName == null || fileName.contains("" + Integer.MIN_VALUE)) { return; @@ -395,7 +370,7 @@ public class FileLoader { if (operation != null) { if (force) { LinkedList downloadQueue; - if (audio != null) { + if (MessageObject.isVoiceDocument(document)) { downloadQueue = audioLoadOperationQueue; } else if (location != null) { downloadQueue = photoLoadOperationQueue; @@ -418,18 +393,18 @@ public class FileLoader { File storeDir = tempDir; int type = MEDIA_DIR_CACHE; - if (video != null) { - operation = new FileLoadOperation(video); - type = MEDIA_DIR_VIDEO; - } else if (location != null) { + if (location != null) { operation = new FileLoadOperation(location, locationExt, locationSize); type = MEDIA_DIR_IMAGE; } else if (document != null) { operation = new FileLoadOperation(document); - type = MEDIA_DIR_DOCUMENT; - } else if (audio != null) { - operation = new FileLoadOperation(audio); - type = MEDIA_DIR_AUDIO; + if (MessageObject.isVoiceDocument(document)) { + type = MEDIA_DIR_AUDIO; + } else if (MessageObject.isVideoDocument(document)) { + type = MEDIA_DIR_VIDEO; + } else { + type = MEDIA_DIR_DOCUMENT; + } } if (!cacheOnly) { storeDir = getDirectory(type); @@ -445,12 +420,12 @@ public class FileLoader { if (delegate != null) { delegate.fileDidLoaded(finalFileName, finalFile, finalType); } - checkDownloadQueue(audio, location, finalFileName); + checkDownloadQueue(document, location, finalFileName); } @Override public void didFailedLoadingFile(FileLoadOperation operation, int canceled) { - checkDownloadQueue(audio, location, finalFileName); + checkDownloadQueue(document, location, finalFileName); if (delegate != null) { delegate.fileDidFailedLoad(finalFileName, canceled); } @@ -464,7 +439,7 @@ public class FileLoader { } }); int maxCount = force ? 3 : 1; - if (audio != null) { + if (type == MEDIA_DIR_AUDIO) { if (currentAudioLoadOperationsCount < maxCount) { currentAudioLoadOperationsCount++; operation.start(); @@ -502,13 +477,13 @@ public class FileLoader { }); } - private void checkDownloadQueue(final TLRPC.Audio audio, final TLRPC.FileLocation location, final String arg1) { + private void checkDownloadQueue(final TLRPC.Document document, final TLRPC.FileLocation location, final String arg1) { fileLoaderQueue.postRunnable(new Runnable() { @Override public void run() { loadOperationPaths.remove(arg1); FileLoadOperation operation; - if (audio != null) { + if (MessageObject.isVoiceDocument(document)) { currentAudioLoadOperationsCount--; if (!audioLoadOperationQueue.isEmpty()) { operation = audioLoadOperationQueue.get(0); @@ -556,6 +531,48 @@ public class FileLoader { this.delegate = delegate; } + public static String getMessageFileName(TLRPC.Message message) { + if (message == null) { + return ""; + } + if (message instanceof TLRPC.TL_messageService) { + if (message.action.photo != null) { + ArrayList sizes = message.action.photo.sizes; + if (sizes.size() > 0) { + TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize()); + if (sizeFull != null) { + return getAttachFileName(sizeFull); + } + } + } + } else { + if (message.media instanceof TLRPC.TL_messageMediaDocument) { + return getAttachFileName(message.media.document); + } else if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + ArrayList sizes = message.media.photo.sizes; + if (sizes.size() > 0) { + TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize()); + if (sizeFull != null) { + return getAttachFileName(sizeFull); + } + } + } else if (message.media instanceof TLRPC.TL_messageMediaWebPage) { + if (message.media.webpage.photo != null) { + ArrayList sizes = message.media.webpage.photo.sizes; + if (sizes.size() > 0) { + TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize()); + if (sizeFull != null) { + return getAttachFileName(sizeFull); + } + } + } else if (message.media.webpage.document != null) { + return getAttachFileName(message.media.webpage.document); + } + } + } + return ""; + } + public static File getPathToMessage(TLRPC.Message message) { if (message == null) { return new File(""); @@ -571,12 +588,8 @@ public class FileLoader { } } } else { - if (message.media instanceof TLRPC.TL_messageMediaVideo) { - return getPathToAttach(message.media.video); - } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { + if (message.media instanceof TLRPC.TL_messageMediaDocument) { return getPathToAttach(message.media.document); - } else if (message.media instanceof TLRPC.TL_messageMediaAudio) { - return getPathToAttach(message.media.audio); } else if (message.media instanceof TLRPC.TL_messageMediaPhoto) { ArrayList sizes = message.media.photo.sizes; if (sizes.size() > 0) { @@ -585,7 +598,10 @@ public class FileLoader { return getPathToAttach(sizeFull); } } - } else if (message.media instanceof TLRPC.TL_messageMediaWebPage && message.media.webpage.photo != null) { + } else if (message.media instanceof TLRPC.TL_messageMediaWebPage) { + if (message.media.webpage.document != null) { + return getPathToAttach(message.media.webpage.document); + } else if (message.media.webpage.photo != null) { ArrayList sizes = message.media.webpage.photo.sizes; if (sizes.size() > 0) { TLRPC.PhotoSize sizeFull = getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize()); @@ -593,21 +609,12 @@ public class FileLoader { return getPathToAttach(sizeFull); } } - } + } + } } return new File(""); } - public static File getExistPathToAttach(TLObject attach) { - File path = getInstance().getDirectory(MEDIA_DIR_CACHE); - String fileName = getAttachFileName(attach); - File attachPath = new File(path, fileName); - if (attachPath.exists()) { - return attachPath; - } - return getPathToAttach(attach); - } - public static File getPathToAttach(TLObject attach) { return getPathToAttach(attach, null, false); } @@ -621,20 +628,19 @@ public class FileLoader { if (forceCache) { dir = getInstance().getDirectory(MEDIA_DIR_CACHE); } else { - if (attach instanceof TLRPC.Video) { - TLRPC.Video video = (TLRPC.Video) attach; - if (video.key != null) { - dir = getInstance().getDirectory(MEDIA_DIR_CACHE); - } else { - dir = getInstance().getDirectory(MEDIA_DIR_VIDEO); - } - } else if (attach instanceof TLRPC.Document) { + if (attach instanceof TLRPC.Document) { TLRPC.Document document = (TLRPC.Document) attach; if (document.key != null) { dir = getInstance().getDirectory(MEDIA_DIR_CACHE); } else { + if (MessageObject.isVoiceDocument(document)) { + dir = getInstance().getDirectory(MEDIA_DIR_AUDIO); + } else if (MessageObject.isVideoDocument(document)) { + dir = getInstance().getDirectory(MEDIA_DIR_VIDEO); + } else { dir = getInstance().getDirectory(MEDIA_DIR_DOCUMENT); } + } } else if (attach instanceof TLRPC.PhotoSize) { TLRPC.PhotoSize photoSize = (TLRPC.PhotoSize) attach; if (photoSize.location == null || photoSize.location.key != null || photoSize.location.volume_id == Integer.MIN_VALUE && photoSize.location.local_id < 0 || photoSize.size < 0) { @@ -642,13 +648,6 @@ public class FileLoader { } else { dir = getInstance().getDirectory(MEDIA_DIR_IMAGE); } - } else if (attach instanceof TLRPC.Audio) { - TLRPC.Audio audio = (TLRPC.Audio) attach; - if (audio.key != null) { - dir = getInstance().getDirectory(MEDIA_DIR_CACHE); - } else { - dir = getInstance().getDirectory(MEDIA_DIR_AUDIO); - } } else if (attach instanceof TLRPC.FileLocation) { TLRPC.FileLocation fileLocation = (TLRPC.FileLocation) attach; if (fileLocation.key != null || fileLocation.volume_id == Integer.MIN_VALUE && fileLocation.local_id < 0) { @@ -674,7 +673,8 @@ public class FileLoader { } int lastSide = 0; TLRPC.PhotoSize closestObject = null; - for (TLRPC.PhotoSize obj : sizes) { + for (int a = 0; a < sizes.size(); a++) { + TLRPC.PhotoSize obj = sizes.get(a); if (obj == null) { continue; } @@ -698,7 +698,7 @@ public class FileLoader { public static String getFileExtension(File file) { String name = file.getName(); try { - return name.substring(name.lastIndexOf(".") + 1); + return name.substring(name.lastIndexOf('.') + 1); } catch (Exception e) { return ""; } @@ -719,28 +719,59 @@ public class FileLoader { return ""; } + public static String getDocumentExtension(TLRPC.Document document) { + String fileName = getDocumentFileName(document); + int idx = fileName.lastIndexOf('.'); + String ext = null; + if (idx != -1) { + ext = fileName.substring(idx + 1); + } + if (ext == null || ext.length() == 0) { + ext = document.mime_type; + } + if (ext == null) { + ext = ""; + } + ext = ext.toUpperCase(); + return ext; + } + public static String getAttachFileName(TLObject attach) { return getAttachFileName(attach, null); } public static String getAttachFileName(TLObject attach, String ext) { - if (attach instanceof TLRPC.Video) { - TLRPC.Video video = (TLRPC.Video) attach; - return video.dc_id + "_" + video.id + "." + (ext != null ? ext : "mp4"); - } else if (attach instanceof TLRPC.Document) { + if (attach instanceof TLRPC.Document) { TLRPC.Document document = (TLRPC.Document) attach; String docExt = null; if (docExt == null) { docExt = getDocumentFileName(document); int idx; - if (docExt == null || (idx = docExt.lastIndexOf(".")) == -1) { + if (docExt == null || (idx = docExt.lastIndexOf('.')) == -1) { docExt = ""; } else { docExt = docExt.substring(idx); } } + if (docExt.length() <= 1) { + if (document.mime_type != null) { + switch (document.mime_type) { + case "video/mp4": + docExt = ".mp4"; + break; + case "audio/ogg": + docExt = ".ogg"; + break; + default: + docExt = ""; + break; + } + } else { + docExt = ""; + } + } if (docExt.length() > 1) { - if(ApplicationLoader.KEEP_ORIGINAL_FILENAME && !docExt.contains("webp") && !isGif(document))return getDocName(document); //Plus + if(ApplicationLoader.KEEP_ORIGINAL_FILENAME && !docExt.contains("webp") && !docExt.contains(".mp4") && !docExt.contains(".gif") && !docExt.contains(".ogg"))return getDocName(document); //Plus return document.dc_id + "_" + document.id + docExt; } else { return document.dc_id + "_" + document.id; @@ -751,9 +782,6 @@ public class FileLoader { return ""; } return photo.location.volume_id + "_" + photo.location.local_id + "." + (ext != null ? ext : "jpg"); - } else if (attach instanceof TLRPC.Audio) { - TLRPC.Audio audio = (TLRPC.Audio) attach; - return audio.dc_id + "_" + audio.id + "." + (ext != null ? ext : "ogg"); } else if (attach instanceof TLRPC.FileLocation) { if (attach instanceof TLRPC.TL_fileLocationUnavailable) { return ""; @@ -774,12 +802,9 @@ public class FileLoader { } return false; } - + //Plus public static String getAttachFileName(TLObject attach, String ext, boolean out) { - if (attach instanceof TLRPC.Video) { - TLRPC.Video video = (TLRPC.Video) attach; - return video.dc_id + "_" + video.id + "." + (ext != null ? ext : "mp4"); - } else if (attach instanceof TLRPC.Document) { + if (attach instanceof TLRPC.Document) { TLRPC.Document document = (TLRPC.Document) attach; String docExt = null; if (docExt == null) { @@ -791,8 +816,26 @@ public class FileLoader { docExt = docExt.substring(idx); } } + if (docExt.length() <= 1) { + if (document.mime_type != null) { + switch (document.mime_type) { + case "video/mp4": + docExt = ".mp4"; + break; + case "audio/ogg": + docExt = ".ogg"; + break; + default: + docExt = ""; + break; + } + } else { + docExt = ""; + } + } if (docExt.length() > 1) { - if(!out && ApplicationLoader.KEEP_ORIGINAL_FILENAME && !docExt.contains("webp") && !isGif(document))return getDocName(document); + //Log.e("FileLoader","1 docExt " + docExt + " mime_type " + document.mime_type + " getDocumentFileName " + getDocumentFileName(document)); + if(!out && ApplicationLoader.KEEP_ORIGINAL_FILENAME && !docExt.contains("webp") && !docExt.contains(".mp4") && !docExt.contains(".gif") && !docExt.contains(".ogg"))return getDocName(document); return document.dc_id + "_" + document.id + docExt; } else { return document.dc_id + "_" + document.id; @@ -803,9 +846,6 @@ public class FileLoader { return ""; } return photo.location.volume_id + "_" + photo.location.local_id + "." + (ext != null ? ext : "jpg"); - } else if (attach instanceof TLRPC.Audio) { - TLRPC.Audio audio = (TLRPC.Audio) attach; - return audio.dc_id + "_" + audio.id + "." + (ext != null ? ext : "ogg"); } else if (attach instanceof TLRPC.FileLocation) { if (attach instanceof TLRPC.TL_fileLocationUnavailable) { return ""; @@ -816,9 +856,9 @@ public class FileLoader { return ""; } - //Plus public static String getDocName(TLRPC.Document document) { String name = getDocumentFileName(document); + //Log.e("FileLoader","name " + name); //boolean org = false; //if(org)return name; String date = document.date +""; diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java b/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java index 0f372983..e58b121a 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/FileLog.java @@ -139,8 +139,8 @@ public class FileLog { try { getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " E/" + tag + "﹕ " + e + "\n"); StackTraceElement[] stack = e.getStackTrace(); - for (StackTraceElement el : stack) { - getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " E/" + tag + "﹕ " + el + "\n"); + for (int a = 0; a < stack.length; a++) { + getInstance().streamWriter.write(getInstance().dateFormat.format(System.currentTimeMillis()) + " E/" + tag + "﹕ " + stack[a] + "\n"); } getInstance().streamWriter.flush(); } catch (Exception e) { @@ -195,9 +195,14 @@ public class FileLog { public static void cleanupLogs() { File sdCard = ApplicationLoader.applicationContext.getExternalFilesDir(null); + if (sdCard == null) { + return; + } File dir = new File (sdCard.getAbsolutePath() + "/logs"); File[] files = dir.listFiles(); - for (File file : files) { + if (files != null) { + for (int a = 0; a < files.length; a++) { + File file = files[a]; if (getInstance().currentFile != null && file.getAbsolutePath().equals(getInstance().currentFile.getAbsolutePath())) { continue; } @@ -215,5 +220,6 @@ public class FileLog { toast.show(); } }); + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/GcmInstanceIDListenerService.java b/TMessagesProj/src/main/java/org/telegram/messenger/GcmInstanceIDListenerService.java new file mode 100644 index 00000000..71f9cff7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/GcmInstanceIDListenerService.java @@ -0,0 +1,28 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.content.Intent; + +import com.google.android.gms.iid.InstanceIDListenerService; + +public class GcmInstanceIDListenerService extends InstanceIDListenerService { + + @Override + public void onTokenRefresh() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + ApplicationLoader.postInitApplication(); + Intent intent = new Intent(ApplicationLoader.applicationContext, GcmRegistrationIntentService.class); + startService(intent); + } + }); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/GcmPushListenerService.java b/TMessagesProj/src/main/java/org/telegram/messenger/GcmPushListenerService.java new file mode 100644 index 00000000..e02a2d1e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/GcmPushListenerService.java @@ -0,0 +1,54 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.os.Bundle; + +import com.google.android.gms.gcm.GcmListenerService; + +import org.json.JSONObject; +import org.telegram.tgnet.ConnectionsManager; + +public class GcmPushListenerService extends GcmListenerService { + + public static final int NOTIFICATION_ID = 1; + + @Override + public void onMessageReceived(String from, final Bundle bundle) { + FileLog.d("tmessages", "GCM received bundle: " + bundle + " from: " + from); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + ApplicationLoader.postInitApplication(); + + try { + String key = bundle.getString("loc_key"); + if ("DC_UPDATE".equals(key)) { + String data = bundle.getString("custom"); + JSONObject object = new JSONObject(data); + int dc = object.getInt("dc"); + String addr = object.getString("addr"); + String[] parts = addr.split(":"); + if (parts.length != 2) { + return; + } + String ip = parts[0]; + int port = Integer.parseInt(parts[1]); + ConnectionsManager.getInstance().applyDatacenterAddress(dc, ip, port); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + ConnectionsManager.onInternalPushReceived(); + ConnectionsManager.getInstance().resumeNetworkMaybe(); + } + }); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/GcmRegistrationIntentService.java b/TMessagesProj/src/main/java/org/telegram/messenger/GcmRegistrationIntentService.java new file mode 100644 index 00000000..7b3360d3 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/GcmRegistrationIntentService.java @@ -0,0 +1,75 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.app.IntentService; +import android.content.Intent; + +import com.google.android.gms.gcm.GoogleCloudMessaging; +import com.google.android.gms.iid.InstanceID; + +public class GcmRegistrationIntentService extends IntentService { + + public GcmRegistrationIntentService() { + super("GcmRegistrationIntentService"); + } + + @Override + protected void onHandleIntent(Intent intent) { + try { + InstanceID instanceID = InstanceID.getInstance(this); + //final String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId), GoogleCloudMessaging.INSTANCE_ID_SCOPE, null); + final String token = instanceID.getToken(BuildVars.GCM_SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null); + FileLog.d("tmessages", "GCM Registration Token: " + token); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + ApplicationLoader.postInitApplication(); + sendRegistrationToServer(token); + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + final int failCount = intent.getIntExtra("failCount", 0); + if (failCount < 60) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + Intent intent = new Intent(ApplicationLoader.applicationContext, GcmRegistrationIntentService.class); + intent.putExtra("failCount", failCount + 1); + startService(intent); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }, failCount < 20 ? 10000 : 60000 * 30); + } + } + } + + private void sendRegistrationToServer(final String token) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + UserConfig.pushString = token; + UserConfig.registeredForPush = false; + UserConfig.saveConfig(false); + if (UserConfig.getClientUserId() != 0) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().registerForPush(token); + } + }); + } + } + }); + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java new file mode 100644 index 00000000..0037abf4 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageLoader.java @@ -0,0 +1,2375 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.app.ActivityManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Matrix; +import android.graphics.drawable.BitmapDrawable; +import android.media.ExifInterface; +import android.media.ThumbnailUtils; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Environment; +import android.os.ParcelFileDescriptor; +import android.provider.MediaStore; + +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AnimatedFileDrawable; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.RandomAccessFile; +import java.lang.reflect.Method; +import java.net.HttpURLConnection; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.net.URLConnection; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class ImageLoader { + + private HashMap bitmapUseCounts = new HashMap<>(); + private LruCache memCache; + private HashMap imageLoadingByUrl = new HashMap<>(); + private HashMap imageLoadingByKeys = new HashMap<>(); + private HashMap imageLoadingByTag = new HashMap<>(); + private HashMap waitingForQualityThumb = new HashMap<>(); + private HashMap waitingForQualityThumbByTag = new HashMap<>(); + private LinkedList httpTasks = new LinkedList<>(); + private DispatchQueue cacheOutQueue = new DispatchQueue("cacheOutQueue"); + private DispatchQueue cacheThumbOutQueue = new DispatchQueue("cacheThumbOutQueue"); + private DispatchQueue thumbGeneratingQueue = new DispatchQueue("thumbGeneratingQueue"); + private DispatchQueue imageLoadQueue = new DispatchQueue("imageLoadQueue"); + private ConcurrentHashMap fileProgresses = new ConcurrentHashMap<>(); + private HashMap thumbGenerateTasks = new HashMap<>(); + private static byte[] bytes; + private static byte[] bytesThumb; + private static byte[] header = new byte[12]; + private static byte[] headerThumb = new byte[12]; + private int currentHttpTasksCount = 0; + + private LinkedList httpFileLoadTasks = new LinkedList<>(); + private HashMap httpFileLoadTasksByKeys = new HashMap<>(); + private HashMap retryHttpsTasks = new HashMap<>(); + private int currentHttpFileLoadTasksCount = 0; + + public VMRuntimeHack runtimeHack = null; + private String ignoreRemoval = null; + + private volatile long lastCacheOutTime = 0; + private int lastImageNum = 0; + private long lastProgressUpdateTime = 0; + + private File telegramPath = null; + + private class ThumbGenerateInfo { + private int count; + private TLRPC.FileLocation fileLocation; + private String filter; + } + + private class HttpFileTask extends AsyncTask { + + private String url; + private File tempFile; + private String ext; + private RandomAccessFile fileOutputStream = null; + private boolean canRetry = true; + + public HttpFileTask(String url, File tempFile, String ext) { + this.url = url; + this.tempFile = tempFile; + this.ext = ext; + } + + protected Boolean doInBackground(Void... voids) { + InputStream httpConnectionStream = null; + boolean done = false; + + URLConnection httpConnection = null; + try { + URL downloadUrl = new URL(url); + httpConnection = downloadUrl.openConnection(); + httpConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (Linux; Android 4.4; Nexus 5 Build/_BuildID_) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36"); + httpConnection.addRequestProperty("Referer", "google.com"); + httpConnection.setConnectTimeout(5000); + httpConnection.setReadTimeout(5000); + if (httpConnection instanceof HttpURLConnection) { + HttpURLConnection httpURLConnection = (HttpURLConnection) httpConnection; + httpURLConnection.setInstanceFollowRedirects(true); + int status = httpURLConnection.getResponseCode(); + if (status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM || status == HttpURLConnection.HTTP_SEE_OTHER) { + String newUrl = httpURLConnection.getHeaderField("Location"); + String cookies = httpURLConnection.getHeaderField("Set-Cookie"); + downloadUrl = new URL(newUrl); + httpConnection = downloadUrl.openConnection(); + httpConnection.setRequestProperty("Cookie", cookies); + httpConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (Linux; Android 4.4; Nexus 5 Build/_BuildID_) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36"); + httpConnection.addRequestProperty("Referer", "google.com"); + } + } + httpConnection.connect(); + httpConnectionStream = httpConnection.getInputStream(); + + fileOutputStream = new RandomAccessFile(tempFile, "rws"); + } catch (Throwable e) { + if (e instanceof UnknownHostException) { + canRetry = false; + } + FileLog.e("tmessages", e); + } + + if (canRetry) { + try { + if (httpConnection != null && httpConnection instanceof HttpURLConnection) { + int code = ((HttpURLConnection) httpConnection).getResponseCode(); + if (code != HttpURLConnection.HTTP_OK && code != HttpURLConnection.HTTP_ACCEPTED && code != HttpURLConnection.HTTP_NOT_MODIFIED) { + canRetry = false; + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + if (httpConnectionStream != null) { + try { + byte[] data = new byte[1024 * 4]; + while (true) { + if (isCancelled()) { + break; + } + try { + int read = httpConnectionStream.read(data); + if (read > 0) { + fileOutputStream.write(data, 0, read); + } else if (read == -1) { + done = true; + break; + } else { + break; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + break; + } + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + + try { + if (fileOutputStream != null) { + fileOutputStream.close(); + fileOutputStream = null; + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + + try { + if (httpConnectionStream != null) { + httpConnectionStream.close(); + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + + return done; + } + + @Override + protected void onPostExecute(Boolean result) { + runHttpFileLoadTasks(this, result ? 2 : 1); + } + + @Override + protected void onCancelled() { + runHttpFileLoadTasks(this, 2); + } + } + + private class HttpImageTask extends AsyncTask { + + private CacheImage cacheImage = null; + private RandomAccessFile fileOutputStream = null; + private int imageSize; + private long lastProgressTime; + private boolean canRetry = true; + private URLConnection httpConnection = null; + + public HttpImageTask(CacheImage cacheImage, int size) { + this.cacheImage = cacheImage; + imageSize = size; + } + + private void reportProgress(final float progress) { + long currentTime = System.currentTimeMillis(); + if (progress == 1 || lastProgressTime == 0 || lastProgressTime < currentTime - 500) { + lastProgressTime = currentTime; + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + fileProgresses.put(cacheImage.url, progress); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileLoadProgressChanged, cacheImage.url, progress); + } + }); + } + }); + } + } + + protected Boolean doInBackground(Void... voids) { + InputStream httpConnectionStream = null; + boolean done = false; + + if (!isCancelled()) { + try { + URL downloadUrl = new URL(cacheImage.httpUrl); + httpConnection = downloadUrl.openConnection(); + httpConnection.addRequestProperty("User-Agent", "Mozilla/5.0 (Linux; Android 4.4; Nexus 5 Build/_BuildID_) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36"); + httpConnection.addRequestProperty("Referer", "google.com"); + httpConnection.setConnectTimeout(5000); + httpConnection.setReadTimeout(5000); + if (httpConnection instanceof HttpURLConnection) { + ((HttpURLConnection) httpConnection).setInstanceFollowRedirects(true); + } + if (!isCancelled()) { + httpConnection.connect(); + httpConnectionStream = httpConnection.getInputStream(); + fileOutputStream = new RandomAccessFile(cacheImage.tempFilePath, "rws"); + } + } catch (Throwable e) { + if (e instanceof SocketTimeoutException) { + if (ConnectionsManager.isNetworkOnline()) { + canRetry = false; + } + } else if (e instanceof UnknownHostException) { + canRetry = false; + } else if (e instanceof SocketException) { + if (e.getMessage() != null && e.getMessage().contains("ECONNRESET")) { + canRetry = false; + } + } + FileLog.e("tmessages", e); + } + } + + if (!isCancelled()) { + try { + if (httpConnection != null && httpConnection instanceof HttpURLConnection) { + int code = ((HttpURLConnection) httpConnection).getResponseCode(); + if (code != HttpURLConnection.HTTP_OK && code != HttpURLConnection.HTTP_ACCEPTED && code != HttpURLConnection.HTTP_NOT_MODIFIED) { + canRetry = false; + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (imageSize == 0 && httpConnection != null) { + try { + Map> headerFields = httpConnection.getHeaderFields(); + if (headerFields != null) { + List values = headerFields.get("content-Length"); + if (values != null && !values.isEmpty()) { + String length = (String) values.get(0); + if (length != null) { + imageSize = Utilities.parseInt(length); + } + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + if (httpConnectionStream != null) { + try { + byte[] data = new byte[1024 * 8]; + int totalLoaded = 0; + while (true) { + if (isCancelled()) { + break; + } + try { + int read = httpConnectionStream.read(data); + if (read > 0) { + totalLoaded += read; + fileOutputStream.write(data, 0, read); + if (imageSize != 0) { + reportProgress(totalLoaded / (float) imageSize); + } + } else if (read == -1) { + done = true; + if (imageSize != 0) { + reportProgress(1.0f); + } + break; + } else { + break; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + break; + } + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + } + + try { + if (fileOutputStream != null) { + fileOutputStream.close(); + fileOutputStream = null; + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + + try { + if (httpConnectionStream != null) { + httpConnectionStream.close(); + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + + if (done) { + if (cacheImage.tempFilePath != null) { + if (!cacheImage.tempFilePath.renameTo(cacheImage.finalFilePath)) { + cacheImage.finalFilePath = cacheImage.tempFilePath; + } + } + } + + return done; + } + + @Override + protected void onPostExecute(final Boolean result) { + if (result || !canRetry) { + fileDidLoaded(cacheImage.url, cacheImage.finalFilePath, FileLoader.MEDIA_DIR_IMAGE); + } else { + httpFileLoadError(cacheImage.url); + } + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + fileProgresses.remove(cacheImage.url); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (result) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileDidLoaded, cacheImage.url); + } else { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileDidFailedLoad, cacheImage.url, 2); + } + } + }); + } + }); + imageLoadQueue.postRunnable(new Runnable() { + @Override + public void run() { + runHttpTasks(true); + } + }); + } + + @Override + protected void onCancelled() { + imageLoadQueue.postRunnable(new Runnable() { + @Override + public void run() { + runHttpTasks(true); + } + }); + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + fileProgresses.remove(cacheImage.url); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileDidFailedLoad, cacheImage.url, 1); + } + }); + } + }); + } + } + + private class ThumbGenerateTask implements Runnable { + + private File originalPath; + private int mediaType; + private TLRPC.FileLocation thumbLocation; + private String filter; + + public ThumbGenerateTask(int type, File path, TLRPC.FileLocation location, String f) { + mediaType = type; + originalPath = path; + thumbLocation = location; + filter = f; + } + + private void removeTask() { + if (thumbLocation == null) { + return; + } + final String name = FileLoader.getAttachFileName(thumbLocation); + imageLoadQueue.postRunnable(new Runnable() { + @Override + public void run() { + thumbGenerateTasks.remove(name); + } + }); + } + + @Override + public void run() { + try { + if (thumbLocation == null) { + removeTask(); + return; + } + final String key = thumbLocation.volume_id + "_" + thumbLocation.local_id; + File thumbFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), "q_" + key + ".jpg"); + if (thumbFile.exists() || !originalPath.exists()) { + removeTask(); + return; + } + int size = Math.min(180, Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) / 4); + Bitmap originalBitmap = null; + if (mediaType == FileLoader.MEDIA_DIR_IMAGE) { + originalBitmap = ImageLoader.loadBitmap(originalPath.toString(), null, size, size, false); + } else if (mediaType == FileLoader.MEDIA_DIR_VIDEO) { + originalBitmap = ThumbnailUtils.createVideoThumbnail(originalPath.toString(), MediaStore.Video.Thumbnails.MINI_KIND); + } else if (mediaType == FileLoader.MEDIA_DIR_DOCUMENT) { + String path = originalPath.toString().toLowerCase(); + if (!path.endsWith(".jpg") && !path.endsWith(".jpeg") && !path.endsWith(".png") && !path.endsWith(".gif")) { + removeTask(); + return; + } + originalBitmap = ImageLoader.loadBitmap(path, null, size, size, false); + } + if (originalBitmap == null) { + removeTask(); + return; + } + + int w = originalBitmap.getWidth(); + int h = originalBitmap.getHeight(); + if (w == 0 || h == 0) { + removeTask(); + return; + } + float scaleFactor = Math.min((float) w / size, (float) h / size); + Bitmap scaledBitmap = Bitmaps.createScaledBitmap(originalBitmap, (int) (w / scaleFactor), (int) (h / scaleFactor), true); + if (scaledBitmap != originalBitmap) { + originalBitmap.recycle(); + } + originalBitmap = scaledBitmap; + FileOutputStream stream = new FileOutputStream(thumbFile); + originalBitmap.compress(Bitmap.CompressFormat.JPEG, 60, stream); + try { + stream.close(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + final BitmapDrawable bitmapDrawable = new BitmapDrawable(originalBitmap); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + removeTask(); + + String kf = key; + if (filter != null) { + kf += "@" + filter; + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageThumbGenerated, bitmapDrawable, kf); + /*BitmapDrawable old = memCache.get(kf); + if (old != null) { + Bitmap image = old.getBitmap(); + if (runtimeHack != null) { + runtimeHack.trackAlloc(image.getRowBytes() * image.getHeight()); + } + if (!image.isRecycled()) { + image.recycle(); + } + }*/ + memCache.put(kf, bitmapDrawable); + } + }); + } catch (Throwable e) { + FileLog.e("tmessages", e); + removeTask(); + } + } + } + + private class CacheOutTask implements Runnable { + private Thread runningThread; + private final Object sync = new Object(); + + private CacheImage cacheImage; + private boolean isCancelled; + + public CacheOutTask(CacheImage image) { + cacheImage = image; + } + + @Override + public void run() { + synchronized (sync) { + runningThread = Thread.currentThread(); + Thread.interrupted(); + if (isCancelled) { + return; + } + } + + if (cacheImage.animatedFile) { + synchronized (sync) { + if (isCancelled) { + return; + } + } + AnimatedFileDrawable fileDrawable = new AnimatedFileDrawable(cacheImage.finalFilePath, cacheImage.filter != null && cacheImage.filter.equals("d")); + Thread.interrupted(); + onPostExecute(fileDrawable); + } else { + Long mediaId = null; + boolean mediaIsVideo = false; + Bitmap image = null; + File cacheFileFinal = cacheImage.finalFilePath; + boolean canDeleteFile = true; + boolean useNativeWebpLoaded = false; + + if (Build.VERSION.SDK_INT < 19) { + RandomAccessFile randomAccessFile = null; + try { + randomAccessFile = new RandomAccessFile(cacheFileFinal, "r"); + byte[] bytes; + if (cacheImage.thumb) { + bytes = headerThumb; + } else { + bytes = header; + } + randomAccessFile.readFully(bytes, 0, bytes.length); + String str = new String(bytes).toLowerCase(); + str = str.toLowerCase(); + if (str.startsWith("riff") && str.endsWith("webp")) { + useNativeWebpLoaded = true; + } + randomAccessFile.close(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (randomAccessFile != null) { + try { + randomAccessFile.close(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + } + + if (cacheImage.thumb) { + int blurType = 0; + if (cacheImage.filter != null) { + if (cacheImage.filter.contains("b2")) { + blurType = 3; + } else if (cacheImage.filter.contains("b1")) { + blurType = 2; + } else if (cacheImage.filter.contains("b")) { + blurType = 1; + } + } + + try { + lastCacheOutTime = System.currentTimeMillis(); + synchronized (sync) { + if (isCancelled) { + return; + } + } + + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inSampleSize = 1; + + if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 21) { + opts.inPurgeable = true; + } + + if (useNativeWebpLoaded) { + RandomAccessFile file = new RandomAccessFile(cacheFileFinal, "r"); + ByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, cacheFileFinal.length()); + + BitmapFactory.Options bmOptions = new BitmapFactory.Options(); + bmOptions.inJustDecodeBounds = true; + Utilities.loadWebpImage(null, buffer, buffer.limit(), bmOptions, true); + image = Bitmaps.createBitmap(bmOptions.outWidth, bmOptions.outHeight, Bitmap.Config.ARGB_8888); + + Utilities.loadWebpImage(image, buffer, buffer.limit(), null, !opts.inPurgeable); + file.close(); + } else { + if (opts.inPurgeable) { + RandomAccessFile f = new RandomAccessFile(cacheFileFinal, "r"); + int len = (int) f.length(); + byte[] data = bytesThumb != null && bytesThumb.length >= len ? bytesThumb : null; + if (data == null) { + bytesThumb = data = new byte[len]; + } + f.readFully(data, 0, len); + image = BitmapFactory.decodeByteArray(data, 0, len, opts); + } else { + FileInputStream is = new FileInputStream(cacheFileFinal); + image = BitmapFactory.decodeStream(is, null, opts); + is.close(); + } + } + + if (image == null) { + if (cacheFileFinal.length() == 0 || cacheImage.filter == null) { + cacheFileFinal.delete(); + } + } else { + if (blurType == 1) { + if (image.getConfig() == Bitmap.Config.ARGB_8888) { + Utilities.blurBitmap(image, 3, opts.inPurgeable ? 0 : 1, image.getWidth(), image.getHeight(), image.getRowBytes()); + } + } else if (blurType == 2) { + if (image.getConfig() == Bitmap.Config.ARGB_8888) { + Utilities.blurBitmap(image, 1, opts.inPurgeable ? 0 : 1, image.getWidth(), image.getHeight(), image.getRowBytes()); + } + } else if (blurType == 3) { + if (image.getConfig() == Bitmap.Config.ARGB_8888) { + Utilities.blurBitmap(image, 7, opts.inPurgeable ? 0 : 1, image.getWidth(), image.getHeight(), image.getRowBytes()); + Utilities.blurBitmap(image, 7, opts.inPurgeable ? 0 : 1, image.getWidth(), image.getHeight(), image.getRowBytes()); + Utilities.blurBitmap(image, 7, opts.inPurgeable ? 0 : 1, image.getWidth(), image.getHeight(), image.getRowBytes()); + } + } else if (blurType == 0 && opts.inPurgeable) { + Utilities.pinBitmap(image); + } + if (runtimeHack != null) { + runtimeHack.trackFree(image.getRowBytes() * image.getHeight()); + } + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } else { + try { + if (cacheImage.httpUrl != null) { + if (cacheImage.httpUrl.startsWith("thumb://")) { + int idx = cacheImage.httpUrl.indexOf(":", 8); + if (idx >= 0) { + mediaId = Long.parseLong(cacheImage.httpUrl.substring(8, idx)); + mediaIsVideo = false; + } + canDeleteFile = false; + } else if (cacheImage.httpUrl.startsWith("vthumb://")) { + int idx = cacheImage.httpUrl.indexOf(":", 9); + if (idx >= 0) { + mediaId = Long.parseLong(cacheImage.httpUrl.substring(9, idx)); + mediaIsVideo = true; + } + canDeleteFile = false; + } else if (!cacheImage.httpUrl.startsWith("http")) { + canDeleteFile = false; + } + } + + int delay = 20; + if (runtimeHack != null) { + delay = 60; + } + if (mediaId != null) { + delay = 0; + } + if (delay != 0 && lastCacheOutTime != 0 && lastCacheOutTime > System.currentTimeMillis() - delay && Build.VERSION.SDK_INT < 21) { + Thread.sleep(delay); + } + lastCacheOutTime = System.currentTimeMillis(); + synchronized (sync) { + if (isCancelled) { + return; + } + } + + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inSampleSize = 1; + + float w_filter = 0; + float h_filter = 0; + boolean blur = false; + if (cacheImage.filter != null) { + String args[] = cacheImage.filter.split("_"); + if (args.length >= 2) { + w_filter = Float.parseFloat(args[0]) * AndroidUtilities.density; + h_filter = Float.parseFloat(args[1]) * AndroidUtilities.density; + } + if (cacheImage.filter.contains("b")) { + blur = true; + } + if (w_filter != 0 && h_filter != 0) { + opts.inJustDecodeBounds = true; + + if (mediaId != null) { + if (mediaIsVideo) { + MediaStore.Video.Thumbnails.getThumbnail(ApplicationLoader.applicationContext.getContentResolver(), mediaId, MediaStore.Video.Thumbnails.MINI_KIND, opts); + } else { + MediaStore.Images.Thumbnails.getThumbnail(ApplicationLoader.applicationContext.getContentResolver(), mediaId, MediaStore.Images.Thumbnails.MINI_KIND, opts); + } + } else { + FileInputStream is = new FileInputStream(cacheFileFinal); + image = BitmapFactory.decodeStream(is, null, opts); + is.close(); + } + + float photoW = opts.outWidth; + float photoH = opts.outHeight; + float scaleFactor = Math.max(photoW / w_filter, photoH / h_filter); + if (scaleFactor < 1) { + scaleFactor = 1; + } + opts.inJustDecodeBounds = false; + opts.inSampleSize = (int) scaleFactor; + } + } + synchronized (sync) { + if (isCancelled) { + return; + } + } + + if (cacheImage.filter == null || blur || cacheImage.httpUrl != null) { + opts.inPreferredConfig = Bitmap.Config.ARGB_8888; + } else { + opts.inPreferredConfig = Bitmap.Config.RGB_565; + } + if (Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 21) { + opts.inPurgeable = true; + } + + opts.inDither = false; + if (mediaId != null) { + if (mediaIsVideo) { + image = MediaStore.Video.Thumbnails.getThumbnail(ApplicationLoader.applicationContext.getContentResolver(), mediaId, MediaStore.Video.Thumbnails.MINI_KIND, opts); + } else { + image = MediaStore.Images.Thumbnails.getThumbnail(ApplicationLoader.applicationContext.getContentResolver(), mediaId, MediaStore.Images.Thumbnails.MINI_KIND, opts); + } + } + if (image == null) { + if (useNativeWebpLoaded) { + RandomAccessFile file = new RandomAccessFile(cacheFileFinal, "r"); + ByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, cacheFileFinal.length()); + + BitmapFactory.Options bmOptions = new BitmapFactory.Options(); + bmOptions.inJustDecodeBounds = true; + Utilities.loadWebpImage(null, buffer, buffer.limit(), bmOptions, true); + image = Bitmaps.createBitmap(bmOptions.outWidth, bmOptions.outHeight, Bitmap.Config.ARGB_8888); + + Utilities.loadWebpImage(image, buffer, buffer.limit(), null, !opts.inPurgeable); + file.close(); + } else { + if (opts.inPurgeable) { + RandomAccessFile f = new RandomAccessFile(cacheFileFinal, "r"); + int len = (int) f.length(); + byte[] data = bytes != null && bytes.length >= len ? bytes : null; + if (data == null) { + bytes = data = new byte[len]; + } + f.readFully(data, 0, len); + image = BitmapFactory.decodeByteArray(data, 0, len, opts); + } else { + FileInputStream is = new FileInputStream(cacheFileFinal); + image = BitmapFactory.decodeStream(is, null, opts); + is.close(); + } + } + } + if (image == null) { + if (canDeleteFile && (cacheFileFinal.length() == 0 || cacheImage.filter == null)) { + cacheFileFinal.delete(); + } + } else { + boolean blured = false; + if (cacheImage.filter != null) { + float bitmapW = image.getWidth(); + float bitmapH = image.getHeight(); + if (!opts.inPurgeable && w_filter != 0 && bitmapW != w_filter && bitmapW > w_filter + 20) { + float scaleFactor = bitmapW / w_filter; + Bitmap scaledBitmap = Bitmaps.createScaledBitmap(image, (int) w_filter, (int) (bitmapH / scaleFactor), true); + if (image != scaledBitmap) { + image.recycle(); + image = scaledBitmap; + } + } + if (image != null && blur && bitmapH < 100 && bitmapW < 100) { + if (image.getConfig() == Bitmap.Config.ARGB_8888) { + Utilities.blurBitmap(image, 3, opts.inPurgeable ? 0 : 1, image.getWidth(), image.getHeight(), image.getRowBytes()); + } + blured = true; + } + } + if (!blured && opts.inPurgeable) { + Utilities.pinBitmap(image); + } + if (runtimeHack != null && image != null) { + runtimeHack.trackFree(image.getRowBytes() * image.getHeight()); + } + } + } catch (Throwable e) { + //don't promt + } + } + Thread.interrupted(); + onPostExecute(image != null ? new BitmapDrawable(image) : null); + } + } + + private void onPostExecute(final BitmapDrawable bitmapDrawable) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + BitmapDrawable toSet = null; + if (bitmapDrawable instanceof AnimatedFileDrawable) { + toSet = bitmapDrawable; + } else if (bitmapDrawable != null) { + toSet = memCache.get(cacheImage.key); + if (toSet == null) { + memCache.put(cacheImage.key, bitmapDrawable); + toSet = bitmapDrawable; + } else { + Bitmap image = bitmapDrawable.getBitmap(); + if (runtimeHack != null) { + runtimeHack.trackAlloc(image.getRowBytes() * image.getHeight()); + } + image.recycle(); + } + } + final BitmapDrawable toSetFinal = toSet; + imageLoadQueue.postRunnable(new Runnable() { + @Override + public void run() { + cacheImage.setImageAndClear(toSetFinal); + } + }); + } + }); + } + + public void cancel() { + synchronized (sync) { + try { + isCancelled = true; + if (runningThread != null) { + runningThread.interrupt(); + } + } catch (Exception e) { + //don't promt + } + } + } + } + + public class VMRuntimeHack { + private Object runtime = null; + private Method trackAllocation = null; + private Method trackFree = null; + + public boolean trackAlloc(long size) { + if (runtime == null) { + return false; + } + try { + Object res = trackAllocation.invoke(runtime, size); + return (res instanceof Boolean) ? (Boolean) res : true; + } catch (Exception e) { + return false; + } + } + + public boolean trackFree(long size) { + if (runtime == null) { + return false; + } + try { + Object res = trackFree.invoke(runtime, size); + return (res instanceof Boolean) ? (Boolean) res : true; + } catch (Exception e) { + return false; + } + } + + @SuppressWarnings("unchecked") + public VMRuntimeHack() { + try { + Class cl = Class.forName("dalvik.system.VMRuntime"); + Method getRt = cl.getMethod("getRuntime", new Class[0]); + Object[] objects = new Object[0]; + runtime = getRt.invoke(null, objects); + trackAllocation = cl.getMethod("trackExternalAllocation", new Class[]{long.class}); + trackFree = cl.getMethod("trackExternalFree", new Class[]{long.class}); + } catch (Exception e) { + FileLog.e("tmessages", e); + runtime = null; + trackAllocation = null; + trackFree = null; + } + } + } + + private class CacheImage { + protected String key; + protected String url; + protected String filter; + protected String ext; + protected TLObject location; + protected boolean animatedFile; + + protected File finalFilePath; + protected File tempFilePath; + protected boolean thumb; + + protected String httpUrl; + protected HttpImageTask httpTask; + protected CacheOutTask cacheTask; + + protected ArrayList imageReceiverArray = new ArrayList<>(); + + public void addImageReceiver(ImageReceiver imageReceiver) { + boolean exist = false; + for (ImageReceiver v : imageReceiverArray) { + if (v == imageReceiver) { + exist = true; + break; + } + } + if (!exist) { + imageReceiverArray.add(imageReceiver); + imageLoadingByTag.put(imageReceiver.getTag(thumb), this); + } + } + + public void removeImageReceiver(ImageReceiver imageReceiver) { + for (int a = 0; a < imageReceiverArray.size(); a++) { + ImageReceiver obj = imageReceiverArray.get(a); + if (obj == null || obj == imageReceiver) { + imageReceiverArray.remove(a); + if (obj != null) { + imageLoadingByTag.remove(obj.getTag(thumb)); + } + a--; + } + } + if (imageReceiverArray.size() == 0) { + for (int a = 0; a < imageReceiverArray.size(); a++) { + imageLoadingByTag.remove(imageReceiverArray.get(a).getTag(thumb)); + } + imageReceiverArray.clear(); + if (location != null) { + if (location instanceof TLRPC.FileLocation) { + FileLoader.getInstance().cancelLoadFile((TLRPC.FileLocation) location, ext); + } else if (location instanceof TLRPC.Document) { + FileLoader.getInstance().cancelLoadFile((TLRPC.Document) location); + } + } + if (cacheTask != null) { + if (thumb) { + cacheThumbOutQueue.cancelRunnable(cacheTask); + } else { + cacheOutQueue.cancelRunnable(cacheTask); + } + cacheTask.cancel(); + cacheTask = null; + } + if (httpTask != null) { + httpTasks.remove(httpTask); + httpTask.cancel(true); + httpTask = null; + } + if (url != null) { + imageLoadingByUrl.remove(url); + } + if (key != null) { + imageLoadingByKeys.remove(key); + } + } + } + + public void setImageAndClear(final BitmapDrawable image) { + if (image != null) { + final ArrayList finalImageReceiverArray = new ArrayList<>(imageReceiverArray); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (image instanceof AnimatedFileDrawable) { + boolean imageSet = false; + AnimatedFileDrawable fileDrawable = (AnimatedFileDrawable) image; + for (int a = 0; a < finalImageReceiverArray.size(); a++) { + ImageReceiver imgView = finalImageReceiverArray.get(a); + if (imgView.setImageBitmapByKey(a == 0 ? fileDrawable : fileDrawable.makeCopy(), key, thumb, false)) { + imageSet = true; + } + } + if (!imageSet) { + ((AnimatedFileDrawable) image).recycle(); + } + } else { + for (int a = 0; a < finalImageReceiverArray.size(); a++) { + ImageReceiver imgView = finalImageReceiverArray.get(a); + imgView.setImageBitmapByKey(image, key, thumb, false); + } + } + } + }); + } + for (int a = 0; a < imageReceiverArray.size(); a++) { + ImageReceiver imageReceiver = imageReceiverArray.get(a); + imageLoadingByTag.remove(imageReceiver.getTag(thumb)); + } + imageReceiverArray.clear(); + if (url != null) { + imageLoadingByUrl.remove(url); + } + if (key != null) { + imageLoadingByKeys.remove(key); + } + } + } + + private static volatile ImageLoader Instance = null; + + public static ImageLoader getInstance() { + ImageLoader localInstance = Instance; + if (localInstance == null) { + synchronized (ImageLoader.class) { + localInstance = Instance; + if (localInstance == null) { + Instance = localInstance = new ImageLoader(); + } + } + } + return localInstance; + } + + public ImageLoader() { + + cacheOutQueue.setPriority(Thread.MIN_PRIORITY); + cacheThumbOutQueue.setPriority(Thread.MIN_PRIORITY); + thumbGeneratingQueue.setPriority(Thread.MIN_PRIORITY); + imageLoadQueue.setPriority(Thread.MIN_PRIORITY); + + int cacheSize = Math.min(15, ((ActivityManager) ApplicationLoader.applicationContext.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass() / 7) * 1024 * 1024; + + if (Build.VERSION.SDK_INT < 11) { + runtimeHack = new VMRuntimeHack(); + cacheSize = 1024 * 1024 * 3; + } + memCache = new LruCache(cacheSize) { + @Override + protected int sizeOf(String key, BitmapDrawable value) { + Bitmap b = value.getBitmap(); + if (Build.VERSION.SDK_INT < 12) { + return b.getRowBytes() * b.getHeight(); + } else { + return b.getByteCount(); + } + } + + @Override + protected void entryRemoved(boolean evicted, String key, final BitmapDrawable oldValue, BitmapDrawable newValue) { + if (ignoreRemoval != null && key != null && ignoreRemoval.equals(key)) { + return; + } + final Integer count = bitmapUseCounts.get(key); + if (count == null || count == 0) { + Bitmap b = oldValue.getBitmap(); + if (runtimeHack != null) { + runtimeHack.trackAlloc(b.getRowBytes() * b.getHeight()); + } + if (!b.isRecycled()) { + b.recycle(); + } + } + } + }; + + FileLoader.getInstance().setDelegate(new FileLoader.FileLoaderDelegate() { + @Override + public void fileUploadProgressChanged(final String location, final float progress, final boolean isEncrypted) { + fileProgresses.put(location, progress); + long currentTime = System.currentTimeMillis(); + if (lastProgressUpdateTime == 0 || lastProgressUpdateTime < currentTime - 500) { + lastProgressUpdateTime = currentTime; + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileUploadProgressChanged, location, progress, isEncrypted); + } + }); + } + } + + @Override + public void fileDidUploaded(final String location, final TLRPC.InputFile inputFile, final TLRPC.InputEncryptedFile inputEncryptedFile, final byte[] key, final byte[] iv, final long totalFileSize) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileDidUpload, location, inputFile, inputEncryptedFile, key, iv, totalFileSize); + } + }); + fileProgresses.remove(location); + } + }); + } + + @Override + public void fileDidFailedUpload(final String location, final boolean isEncrypted) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileDidFailUpload, location, isEncrypted); + } + }); + fileProgresses.remove(location); + } + }); + } + + @Override + public void fileDidLoaded(final String location, final File finalFile, final int type) { + fileProgresses.remove(location); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (MediaController.getInstance().canSaveToGallery() && telegramPath != null && finalFile != null && (location.endsWith(".mp4") || location.endsWith(".jpg"))) { + if (finalFile.toString().startsWith(telegramPath.toString())) { + AndroidUtilities.addMediaToGallery(finalFile.toString()); + } + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileDidLoaded, location); + ImageLoader.this.fileDidLoaded(location, finalFile, type); + } + }); + } + + @Override + public void fileDidFailedLoad(final String location, final int canceled) { + fileProgresses.remove(location); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + ImageLoader.this.fileDidFailedLoad(location, canceled); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileDidFailedLoad, location, canceled); + } + }); + } + + @Override + public void fileLoadProgressChanged(final String location, final float progress) { + fileProgresses.put(location, progress); + long currentTime = System.currentTimeMillis(); + if (lastProgressUpdateTime == 0 || lastProgressUpdateTime < currentTime - 500) { + lastProgressUpdateTime = currentTime; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileLoadProgressChanged, location, progress); + } + }); + } + } + }); + + BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context arg0, Intent intent) { + FileLog.e("tmessages", "file system changed"); + Runnable r = new Runnable() { + public void run() { + checkMediaPaths(); + } + }; + if (Intent.ACTION_MEDIA_UNMOUNTED.equals(intent.getAction())) { + AndroidUtilities.runOnUIThread(r, 1000); + } else { + r.run(); + } + } + }; + + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_MEDIA_BAD_REMOVAL); + filter.addAction(Intent.ACTION_MEDIA_CHECKING); + filter.addAction(Intent.ACTION_MEDIA_EJECT); + filter.addAction(Intent.ACTION_MEDIA_MOUNTED); + filter.addAction(Intent.ACTION_MEDIA_NOFS); + filter.addAction(Intent.ACTION_MEDIA_REMOVED); + filter.addAction(Intent.ACTION_MEDIA_SHARED); + filter.addAction(Intent.ACTION_MEDIA_UNMOUNTABLE); + filter.addAction(Intent.ACTION_MEDIA_UNMOUNTED); + filter.addDataScheme("file"); + ApplicationLoader.applicationContext.registerReceiver(receiver, filter); + + HashMap mediaDirs = new HashMap<>(); + File cachePath = AndroidUtilities.getCacheDir(); + if (!cachePath.isDirectory()) { + try { + cachePath.mkdirs(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + try { + new File(cachePath, ".nomedia").createNewFile(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + mediaDirs.put(FileLoader.MEDIA_DIR_CACHE, cachePath); + FileLoader.getInstance().setMediaDirs(mediaDirs); + + checkMediaPaths(); + } + + public void checkMediaPaths() { + cacheOutQueue.postRunnable(new Runnable() { + @Override + public void run() { + final HashMap paths = createMediaPaths(); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + FileLoader.getInstance().setMediaDirs(paths); + } + }); + } + }); + } + + public HashMap createMediaPaths() { + HashMap mediaDirs = new HashMap<>(); + File cachePath = AndroidUtilities.getCacheDir(); + if (!cachePath.isDirectory()) { + try { + cachePath.mkdirs(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + try { + new File(cachePath, ".nomedia").createNewFile(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + mediaDirs.put(FileLoader.MEDIA_DIR_CACHE, cachePath); + FileLog.e("tmessages", "cache path = " + cachePath); + + try { + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { + telegramPath = new File(Environment.getExternalStorageDirectory(), "Telegram"); + telegramPath.mkdirs(); + + if (telegramPath.isDirectory()) { + try { + File imagePath = new File(telegramPath, "Telegram Images"); + imagePath.mkdir(); + if (imagePath.isDirectory() && canMoveFiles(cachePath, imagePath, FileLoader.MEDIA_DIR_IMAGE)) { + mediaDirs.put(FileLoader.MEDIA_DIR_IMAGE, imagePath); + FileLog.e("tmessages", "image path = " + imagePath); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + try { + File videoPath = new File(telegramPath, "Telegram Video"); + videoPath.mkdir(); + if (videoPath.isDirectory() && canMoveFiles(cachePath, videoPath, FileLoader.MEDIA_DIR_VIDEO)) { + mediaDirs.put(FileLoader.MEDIA_DIR_VIDEO, videoPath); + FileLog.e("tmessages", "video path = " + videoPath); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + try { + File audioPath = new File(telegramPath, "Telegram Audio"); + audioPath.mkdir(); + if (audioPath.isDirectory() && canMoveFiles(cachePath, audioPath, FileLoader.MEDIA_DIR_AUDIO)) { + new File(audioPath, ".nomedia").createNewFile(); + mediaDirs.put(FileLoader.MEDIA_DIR_AUDIO, audioPath); + FileLog.e("tmessages", "audio path = " + audioPath); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + try { + File documentPath = new File(telegramPath, "Telegram Documents"); + documentPath.mkdir(); + if (documentPath.isDirectory() && canMoveFiles(cachePath, documentPath, FileLoader.MEDIA_DIR_DOCUMENT)) { + new File(documentPath, ".nomedia").createNewFile(); + mediaDirs.put(FileLoader.MEDIA_DIR_DOCUMENT, documentPath); + FileLog.e("tmessages", "documents path = " + documentPath); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + // Themes + try { + File themesPath = new File(telegramPath, "Themes"); + themesPath.mkdir(); + if (themesPath.isDirectory() && canMoveFiles(cachePath, themesPath, FileLoader.MEDIA_DIR_THEME)) { + new File(themesPath, ".nomedia").createNewFile(); + mediaDirs.put(FileLoader.MEDIA_DIR_THEME, themesPath); + FileLog.e("tmessages", "themes path = " + themesPath); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + // + } + } else { + FileLog.e("tmessages", "this Android can't rename files"); + } + MediaController.getInstance().checkSaveToGalleryFiles(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + return mediaDirs; + } + + private boolean canMoveFiles(File from, File to, int type) { + RandomAccessFile file = null; + try { + File srcFile = null; + File dstFile = null; + if (type == FileLoader.MEDIA_DIR_IMAGE) { + srcFile = new File(from, "000000000_999999_temp.jpg"); + dstFile = new File(to, "000000000_999999.jpg"); + } else if (type == FileLoader.MEDIA_DIR_DOCUMENT) { + srcFile = new File(from, "000000000_999999_temp.doc"); + dstFile = new File(to, "000000000_999999.doc"); + } else if (type == FileLoader.MEDIA_DIR_AUDIO) { + srcFile = new File(from, "000000000_999999_temp.ogg"); + dstFile = new File(to, "000000000_999999.ogg"); + } else if (type == FileLoader.MEDIA_DIR_VIDEO) { + srcFile = new File(from, "000000000_999999_temp.mp4"); + dstFile = new File(to, "000000000_999999.mp4"); + } else if (type == FileLoader.MEDIA_DIR_THEME) { + srcFile = new File(from, "000000000_999999_temp.xml"); + dstFile = new File(to, "000000000_999999.xml"); + } + byte[] buffer = new byte[1024]; + srcFile.createNewFile(); + file = new RandomAccessFile(srcFile, "rws"); + file.write(buffer); + file.close(); + file = null; + boolean canRename = srcFile.renameTo(dstFile); + srcFile.delete(); + dstFile.delete(); + if (canRename) { + return true; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + try { + if (file != null) { + file.close(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + return false; + } + + public Float getFileProgress(String location) { + if (location == null) { + return null; + } + return fileProgresses.get(location); + } + + private void performReplace(String oldKey, String newKey) { + BitmapDrawable b = memCache.get(oldKey); + if (b != null) { + ignoreRemoval = oldKey; + memCache.remove(oldKey); + memCache.put(newKey, b); + ignoreRemoval = null; + } + Integer val = bitmapUseCounts.get(oldKey); + if (val != null) { + bitmapUseCounts.put(newKey, val); + bitmapUseCounts.remove(oldKey); + } + } + + public void incrementUseCount(String key) { + Integer count = bitmapUseCounts.get(key); + if (count == null) { + bitmapUseCounts.put(key, 1); + } else { + bitmapUseCounts.put(key, count + 1); + } + } + + public boolean decrementUseCount(String key) { + Integer count = bitmapUseCounts.get(key); + if (count == null) { + return true; + } + if (count == 1) { + bitmapUseCounts.remove(key); + return true; + } else { + bitmapUseCounts.put(key, count - 1); + } + return false; + } + + public void removeImage(String key) { + bitmapUseCounts.remove(key); + memCache.remove(key); + } + + public boolean isInCache(String key) { + return memCache.get(key) != null; + } + + public void clearMemory() { + memCache.evictAll(); + } + + private void removeFromWaitingForThumb(Integer TAG) { + String location = waitingForQualityThumbByTag.get(TAG); + if (location != null) { + ThumbGenerateInfo info = waitingForQualityThumb.get(location); + if (info != null) { + info.count--; + if (info.count == 0) { + waitingForQualityThumb.remove(location); + } + } + waitingForQualityThumbByTag.remove(TAG); + } + } + + public void cancelLoadingForImageReceiver(final ImageReceiver imageReceiver, final int type) { + if (imageReceiver == null) { + return; + } + imageLoadQueue.postRunnable(new Runnable() { + @Override + public void run() { + int start = 0; + int count = 2; + if (type == 1) { + count = 1; + } else if (type == 2) { + start = 1; + } + for (int a = start; a < count; a++) { + Integer TAG = imageReceiver.getTag(a == 0); + if (a == 0) { + removeFromWaitingForThumb(TAG); + } + if (TAG != null) { + CacheImage ei = imageLoadingByTag.get(TAG); + if (ei != null) { + ei.removeImageReceiver(imageReceiver); + } + } + } + } + }); + } + + public BitmapDrawable getImageFromMemory(String key) { + return memCache.get(key); + } + + public BitmapDrawable getImageFromMemory(TLObject fileLocation, String httpUrl, String filter) { + if (fileLocation == null && httpUrl == null) { + return null; + } + String key = null; + if (httpUrl != null) { + key = Utilities.MD5(httpUrl); + } else { + if (fileLocation instanceof TLRPC.FileLocation) { + TLRPC.FileLocation location = (TLRPC.FileLocation) fileLocation; + key = location.volume_id + "_" + location.local_id; + } else if (fileLocation instanceof TLRPC.Document) { + TLRPC.Document location = (TLRPC.Document) fileLocation; + key = location.dc_id + "_" + location.id; + } + } + if (filter != null) { + key += "@" + filter; + } + return memCache.get(key); + } + + private void replaceImageInCacheInternal(final String oldKey, final String newKey, final TLRPC.FileLocation newLocation) { + ArrayList arr = memCache.getFilterKeys(oldKey); + if (arr != null) { + for (int a = 0; a < arr.size(); a++) { + String filter = arr.get(a); + String oldK = oldKey + "@" + filter; + String newK = newKey + "@" + filter; + performReplace(oldK, newK); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReplacedPhotoInMemCache, oldK, newK, newLocation); + } + } else { + performReplace(oldKey, newKey); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReplacedPhotoInMemCache, oldKey, newKey, newLocation); + } + } + + public void replaceImageInCache(final String oldKey, final String newKey, final TLRPC.FileLocation newLocation, boolean post) { + if (post) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + replaceImageInCacheInternal(oldKey, newKey, newLocation); + } + }); + } else { + replaceImageInCacheInternal(oldKey, newKey, newLocation); + } + } + + public void putImageToCache(BitmapDrawable bitmap, String key) { + memCache.put(key, bitmap); + } + + private void generateThumb(int mediaType, File originalPath, TLRPC.FileLocation thumbLocation, String filter) { + if (mediaType != FileLoader.MEDIA_DIR_IMAGE && mediaType != FileLoader.MEDIA_DIR_VIDEO && mediaType != FileLoader.MEDIA_DIR_DOCUMENT || originalPath == null || thumbLocation == null) { + return; + } + String name = FileLoader.getAttachFileName(thumbLocation); + ThumbGenerateTask task = thumbGenerateTasks.get(name); + if (task == null) { + task = new ThumbGenerateTask(mediaType, originalPath, thumbLocation, filter); + thumbGeneratingQueue.postRunnable(task); + } + } + + private void createLoadOperationForImageReceiver(final ImageReceiver imageReceiver, final String key, final String url, final String ext, final TLObject imageLocation, final String httpLocation, final String filter, final int size, final boolean cacheOnly, final int thumb) { + if (imageReceiver == null || url == null || key == null) { + return; + } + Integer TAG = imageReceiver.getTag(thumb != 0); + if (TAG == null) { + imageReceiver.setTag(TAG = lastImageNum, thumb != 0); + lastImageNum++; + if (lastImageNum == Integer.MAX_VALUE) { + lastImageNum = 0; + } + } + + final Integer finalTag = TAG; + final boolean finalIsNeedsQualityThumb = imageReceiver.isNeedsQualityThumb(); + final MessageObject parentMessageObject = imageReceiver.getParentMessageObject(); + final boolean shouldGenerateQualityThumb = imageReceiver.isShouldGenerateQualityThumb(); + imageLoadQueue.postRunnable(new Runnable() { + @Override + public void run() { + boolean added = false; + if (thumb != 2) { + CacheImage alreadyLoadingUrl = imageLoadingByUrl.get(url); + CacheImage alreadyLoadingCache = imageLoadingByKeys.get(key); + CacheImage alreadyLoadingImage = imageLoadingByTag.get(finalTag); + if (alreadyLoadingImage != null) { + if (alreadyLoadingImage == alreadyLoadingUrl || alreadyLoadingImage == alreadyLoadingCache) { + added = true; + } else { + alreadyLoadingImage.removeImageReceiver(imageReceiver); + } + } + + if (!added && alreadyLoadingCache != null) { + alreadyLoadingCache.addImageReceiver(imageReceiver); + added = true; + } + if (!added && alreadyLoadingUrl != null) { + alreadyLoadingUrl.addImageReceiver(imageReceiver); + added = true; + } + } + + if (!added) { + boolean onlyCache = false; + boolean isQuality = false; + File cacheFile = null; + + if (httpLocation != null) { + if (!httpLocation.startsWith("http")) { + onlyCache = true; + if (httpLocation.startsWith("thumb://")) { + int idx = httpLocation.indexOf(":", 8); + if (idx >= 0) { + cacheFile = new File(httpLocation.substring(idx + 1)); + } + } else if (httpLocation.startsWith("vthumb://")) { + int idx = httpLocation.indexOf(":", 9); + if (idx >= 0) { + cacheFile = new File(httpLocation.substring(idx + 1)); + } + } else { + cacheFile = new File(httpLocation); + } + } + } else if (thumb != 0) { + if (finalIsNeedsQualityThumb) { + cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), "q_" + url); + if (!cacheFile.exists()) { + cacheFile = null; + } + } + + if (parentMessageObject != null) { + File attachPath = null; + if (parentMessageObject.messageOwner.attachPath != null && parentMessageObject.messageOwner.attachPath.length() > 0) { + attachPath = new File(parentMessageObject.messageOwner.attachPath); + if (!attachPath.exists()) { + attachPath = null; + } + } + if (attachPath == null) { + attachPath = FileLoader.getPathToMessage(parentMessageObject.messageOwner); + } + if (finalIsNeedsQualityThumb && cacheFile == null) { + String location = parentMessageObject.getFileName(); + ThumbGenerateInfo info = waitingForQualityThumb.get(location); + if (info == null) { + info = new ThumbGenerateInfo(); + info.fileLocation = (TLRPC.TL_fileLocation) imageLocation; + info.filter = filter; + waitingForQualityThumb.put(location, info); + } + info.count++; + waitingForQualityThumbByTag.put(finalTag, location); + } + if (attachPath.exists() && shouldGenerateQualityThumb) { + generateThumb(parentMessageObject.getFileType(), attachPath, (TLRPC.TL_fileLocation) imageLocation, filter); + } + } + } + + if (thumb != 2) { + CacheImage img = new CacheImage(); + if (httpLocation != null && !httpLocation.startsWith("vthumb") && !httpLocation.startsWith("thumb") && (httpLocation.endsWith("mp4") || httpLocation.endsWith("gif")) || imageLocation instanceof TLRPC.Document && MessageObject.isGifDocument((TLRPC.Document) imageLocation)) { + img.animatedFile = true; + } + + if (cacheFile == null) { + if (cacheOnly || size == 0 || httpLocation != null) { + cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), url); + } else if (imageLocation instanceof TLRPC.Document) { + cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_DOCUMENT), url); + } else { + cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_IMAGE), url); + } + } + + img.thumb = thumb != 0; + img.key = key; + img.filter = filter; + img.httpUrl = httpLocation; + img.ext = ext; + img.addImageReceiver(imageReceiver); + if (onlyCache || cacheFile.exists()) { + img.finalFilePath = cacheFile; + img.cacheTask = new CacheOutTask(img); + imageLoadingByKeys.put(key, img); + if (thumb != 0) { + cacheThumbOutQueue.postRunnable(img.cacheTask); + } else { + cacheOutQueue.postRunnable(img.cacheTask); + } + } else { + img.url = url; + img.location = imageLocation; + imageLoadingByUrl.put(url, img); + if (httpLocation == null) { + if (imageLocation instanceof TLRPC.FileLocation) { + TLRPC.FileLocation location = (TLRPC.FileLocation) imageLocation; + FileLoader.getInstance().loadFile(location, ext, size, size == 0 || location.key != null || cacheOnly); + } else if (imageLocation instanceof TLRPC.Document) { + FileLoader.getInstance().loadFile((TLRPC.Document) imageLocation, true, cacheOnly); + } + } else { + String file = Utilities.MD5(httpLocation); + File cacheDir = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE); + img.tempFilePath = new File(cacheDir, file + "_temp.jpg"); + img.finalFilePath = cacheFile; + img.httpTask = new HttpImageTask(img, size); + httpTasks.add(img.httpTask); + runHttpTasks(false); + } + } + } + } + } + }); + } + + public void loadImageForImageReceiver(ImageReceiver imageReceiver) { + if (imageReceiver == null) { + return; + } + + String key = imageReceiver.getKey(); + if (key != null) { + BitmapDrawable bitmapDrawable = memCache.get(key); + if (bitmapDrawable != null) { + cancelLoadingForImageReceiver(imageReceiver, 0); + if (!imageReceiver.isForcePreview()) { + imageReceiver.setImageBitmapByKey(bitmapDrawable, key, false, true); + return; + } + } + } + boolean thumbSet = false; + String thumbKey = imageReceiver.getThumbKey(); + if (thumbKey != null) { + BitmapDrawable bitmapDrawable = memCache.get(thumbKey); + if (bitmapDrawable != null) { + imageReceiver.setImageBitmapByKey(bitmapDrawable, thumbKey, true, true); + cancelLoadingForImageReceiver(imageReceiver, 1); + thumbSet = true; + } + } + + TLRPC.FileLocation thumbLocation = imageReceiver.getThumbLocation(); + TLObject imageLocation = imageReceiver.getImageLocation(); + String httpLocation = imageReceiver.getHttpImageLocation(); + + boolean saveImageToCache = false; + + String url = null; + String thumbUrl = null; + key = null; + thumbKey = null; + String ext = imageReceiver.getExt(); + if (ext == null) { + ext = "jpg"; + } + if (httpLocation != null) { + key = Utilities.MD5(httpLocation); + url = key + "." + getHttpUrlExtension(httpLocation, "jpg"); + } else if (imageLocation != null) { + if (imageLocation instanceof TLRPC.FileLocation) { + TLRPC.FileLocation location = (TLRPC.FileLocation) imageLocation; + key = location.volume_id + "_" + location.local_id; + url = key + "." + ext; + if (imageReceiver.getExt() != null || location.key != null || location.volume_id == Integer.MIN_VALUE && location.local_id < 0) { + saveImageToCache = true; + } + } else if (imageLocation instanceof TLRPC.Document) { + TLRPC.Document document = (TLRPC.Document) imageLocation; + if (document.id == 0 || document.dc_id == 0) { + return; + } + key = document.dc_id + "_" + document.id; + String docExt = FileLoader.getDocumentFileName(document); + int idx; + if (docExt == null || (idx = docExt.lastIndexOf('.')) == -1) { + docExt = ""; + } else { + docExt = docExt.substring(idx); + } + if (docExt.length() <= 1) { + if (document.mime_type != null && document.mime_type.equals("video/mp4")) { + docExt = ".mp4"; + } else { + docExt = ""; + } + } + url = key + docExt; + if (thumbKey != null) { + thumbUrl = thumbKey + "." + ext; + } + saveImageToCache = !MessageObject.isGifDocument(document); + } + if (imageLocation == thumbLocation) { + imageLocation = null; + key = null; + url = null; + } + } + + if (thumbLocation != null) { + thumbKey = thumbLocation.volume_id + "_" + thumbLocation.local_id; + thumbUrl = thumbKey + "." + ext; + } + + String filter = imageReceiver.getFilter(); + String thumbFilter = imageReceiver.getThumbFilter(); + if (key != null && filter != null) { + key += "@" + filter; + } + if (thumbKey != null && thumbFilter != null) { + thumbKey += "@" + thumbFilter; + } + + if (httpLocation != null) { + createLoadOperationForImageReceiver(imageReceiver, thumbKey, thumbUrl, ext, thumbLocation, null, thumbFilter, 0, true, thumbSet ? 2 : 1); + createLoadOperationForImageReceiver(imageReceiver, key, url, ext, null, httpLocation, filter, 0, true, 0); + } else { + createLoadOperationForImageReceiver(imageReceiver, thumbKey, thumbUrl, ext, thumbLocation, null, thumbFilter, 0, true, thumbSet ? 2 : 1); + createLoadOperationForImageReceiver(imageReceiver, key, url, ext, imageLocation, null, filter, imageReceiver.getSize(), saveImageToCache || imageReceiver.getCacheOnly(), 0); + } + } + + private void httpFileLoadError(final String location) { + imageLoadQueue.postRunnable(new Runnable() { + @Override + public void run() { + CacheImage img = imageLoadingByUrl.get(location); + if (img == null) { + return; + } + HttpImageTask oldTask = img.httpTask; + img.httpTask = new HttpImageTask(oldTask.cacheImage, oldTask.imageSize); + httpTasks.add(img.httpTask); + runHttpTasks(false); + } + }); + } + + private void fileDidLoaded(final String location, final File finalFile, final int type) { + imageLoadQueue.postRunnable(new Runnable() { + @Override + public void run() { + ThumbGenerateInfo info = waitingForQualityThumb.get(location); + if (info != null) { + generateThumb(type, finalFile, info.fileLocation, info.filter); + waitingForQualityThumb.remove(location); + } + CacheImage img = imageLoadingByUrl.get(location); + if (img == null) { + return; + } + imageLoadingByUrl.remove(location); + CacheOutTask task = null; + for (int a = 0; a < img.imageReceiverArray.size(); a++) { + ImageReceiver imageReceiver = img.imageReceiverArray.get(a); + CacheImage cacheImage = imageLoadingByKeys.get(img.key); + if (cacheImage == null) { + cacheImage = new CacheImage(); + cacheImage.finalFilePath = finalFile; + cacheImage.key = img.key; + cacheImage.httpUrl = img.httpUrl; + cacheImage.thumb = img.thumb; + cacheImage.ext = img.ext; + cacheImage.cacheTask = task = new CacheOutTask(cacheImage); + cacheImage.filter = img.filter; + cacheImage.animatedFile = img.animatedFile; + imageLoadingByKeys.put(cacheImage.key, cacheImage); + } + cacheImage.addImageReceiver(imageReceiver); + } + if (task != null) { + if (img.thumb) { + cacheThumbOutQueue.postRunnable(task); + } else { + cacheOutQueue.postRunnable(task); + } + } + } + }); + } + + private void fileDidFailedLoad(final String location, int canceled) { + if (canceled == 1) { + return; + } + imageLoadQueue.postRunnable(new Runnable() { + @Override + public void run() { + CacheImage img = imageLoadingByUrl.get(location); + if (img != null) { + img.setImageAndClear(null); + } + } + }); + } + + private void runHttpTasks(boolean complete) { + if (complete) { + currentHttpTasksCount--; + } + while (currentHttpTasksCount < 4 && !httpTasks.isEmpty()) { + HttpImageTask task = httpTasks.poll(); + if (android.os.Build.VERSION.SDK_INT >= 11) { + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null); + } else { + task.execute(null, null, null); + } + currentHttpTasksCount++; + } + } + + public void loadHttpFile(String url, String defaultExt) { + if (url == null || url.length() == 0 || httpFileLoadTasksByKeys.containsKey(url)) { + return; + } + String ext = getHttpUrlExtension(url, defaultExt); + File file = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(url) + "_temp." + ext); + file.delete(); + + HttpFileTask task = new HttpFileTask(url, file, ext); + httpFileLoadTasks.add(task); + httpFileLoadTasksByKeys.put(url, task); + runHttpFileLoadTasks(null, 0); + } + + public void cancelLoadHttpFile(String url) { + HttpFileTask task = httpFileLoadTasksByKeys.get(url); + if (task != null) { + task.cancel(true); + httpFileLoadTasksByKeys.remove(url); + httpFileLoadTasks.remove(task); + } + Runnable runnable = retryHttpsTasks.get(url); + if (runnable != null) { + AndroidUtilities.cancelRunOnUIThread(runnable); + } + runHttpFileLoadTasks(null, 0); + } + + private void runHttpFileLoadTasks(final HttpFileTask oldTask, final int reason) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (oldTask != null) { + currentHttpFileLoadTasksCount--; + } + if (oldTask != null) { + if (reason == 1) { + if (oldTask.canRetry) { + final HttpFileTask newTask = new HttpFileTask(oldTask.url, oldTask.tempFile, oldTask.ext); + Runnable runnable = new Runnable() { + @Override + public void run() { + httpFileLoadTasks.add(newTask); + runHttpFileLoadTasks(null, 0); + } + }; + retryHttpsTasks.put(oldTask.url, runnable); + AndroidUtilities.runOnUIThread(runnable, 1000); + } else { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.httpFileDidFailedLoad, oldTask.url); + } + } else if (reason == 2) { + httpFileLoadTasksByKeys.remove(oldTask.url); + File file = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(oldTask.url) + "." + oldTask.ext); + String result = oldTask.tempFile.renameTo(file) ? file.toString() : oldTask.tempFile.toString(); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.httpFileDidLoaded, oldTask.url, result); + } + } + while (currentHttpFileLoadTasksCount < 2 && !httpFileLoadTasks.isEmpty()) { + HttpFileTask task = httpFileLoadTasks.poll(); + if (android.os.Build.VERSION.SDK_INT >= 11) { + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null, null, null); + } else { + task.execute(null, null, null); + } + currentHttpFileLoadTasksCount++; + } + } + }); + } + + public static Bitmap loadBitmap(String path, Uri uri, float maxWidth, float maxHeight, boolean useMaxScale) { + BitmapFactory.Options bmOptions = new BitmapFactory.Options(); + bmOptions.inJustDecodeBounds = true; + InputStream inputStream = null; + + if (path == null && uri != null && uri.getScheme() != null) { + String imageFilePath = null; + if (uri.getScheme().contains("file")) { + path = uri.getPath(); + } else { + try { + path = AndroidUtilities.getPath(uri); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + } + + if (path != null) { + BitmapFactory.decodeFile(path, bmOptions); + } else if (uri != null) { + boolean error = false; + try { + inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri); + BitmapFactory.decodeStream(inputStream, null, bmOptions); + inputStream.close(); + inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri); + } catch (Throwable e) { + FileLog.e("tmessages", e); + return null; + } + } + float photoW = bmOptions.outWidth; + float photoH = bmOptions.outHeight; + float scaleFactor = useMaxScale ? Math.max(photoW / maxWidth, photoH / maxHeight) : Math.min(photoW / maxWidth, photoH / maxHeight); + if (scaleFactor < 1) { + scaleFactor = 1; + } + bmOptions.inJustDecodeBounds = false; + bmOptions.inSampleSize = (int) scaleFactor; + bmOptions.inPurgeable = Build.VERSION.SDK_INT >= 14 && Build.VERSION.SDK_INT < 21; + + String exifPath = null; + if (path != null) { + exifPath = path; + } else if (uri != null) { + exifPath = AndroidUtilities.getPath(uri); + } + + Matrix matrix = null; + + if (exifPath != null) { + ExifInterface exif; + try { + exif = new ExifInterface(exifPath); + int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1); + matrix = new Matrix(); + switch (orientation) { + case ExifInterface.ORIENTATION_ROTATE_90: + matrix.postRotate(90); + break; + case ExifInterface.ORIENTATION_ROTATE_180: + matrix.postRotate(180); + break; + case ExifInterface.ORIENTATION_ROTATE_270: + matrix.postRotate(270); + break; + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + + Bitmap b = null; + if (path != null) { + try { + b = BitmapFactory.decodeFile(path, bmOptions); + if (b != null) { + if (bmOptions.inPurgeable) { + Utilities.pinBitmap(b); + } + Bitmap newBitmap = Bitmaps.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, true); + if (newBitmap != b) { + b.recycle(); + b = newBitmap; + } + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + ImageLoader.getInstance().clearMemory(); + try { + if (b == null) { + b = BitmapFactory.decodeFile(path, bmOptions); + if (b != null && bmOptions.inPurgeable) { + Utilities.pinBitmap(b); + } + } + if (b != null) { + Bitmap newBitmap = Bitmaps.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, true); + if (newBitmap != b) { + b.recycle(); + b = newBitmap; + } + } + } catch (Throwable e2) { + FileLog.e("tmessages", e2); + } + } + } else if (uri != null) { + try { + b = BitmapFactory.decodeStream(inputStream, null, bmOptions); + if (b != null) { + if (bmOptions.inPurgeable) { + Utilities.pinBitmap(b); + } + Bitmap newBitmap = Bitmaps.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), matrix, true); + if (newBitmap != b) { + b.recycle(); + b = newBitmap; + } + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } finally { + try { + inputStream.close(); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + } + + return b; + } + + public static void fillPhotoSizeWithBytes(TLRPC.PhotoSize photoSize) { + if (photoSize == null || photoSize.bytes != null) { + return; + } + File file = FileLoader.getPathToAttach(photoSize, true); + try { + RandomAccessFile f = new RandomAccessFile(file, "r"); + int len = (int) f.length(); + if (len < 20000) { + photoSize.bytes = new byte[(int) f.length()]; + f.readFully(photoSize.bytes, 0, photoSize.bytes.length); + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + + private static TLRPC.PhotoSize scaleAndSaveImageInternal(Bitmap bitmap, int w, int h, float photoW, float photoH, float scaleFactor, int quality, boolean cache, boolean scaleAnyway) throws Exception { + Bitmap scaledBitmap; + if (scaleFactor > 1 || scaleAnyway) { + scaledBitmap = Bitmaps.createScaledBitmap(bitmap, w, h, true); + } else { + scaledBitmap = bitmap; + } + + TLRPC.TL_fileLocation location = new TLRPC.TL_fileLocation(); + location.volume_id = Integer.MIN_VALUE; + location.dc_id = Integer.MIN_VALUE; + location.local_id = UserConfig.lastLocalId; + UserConfig.lastLocalId--; + TLRPC.PhotoSize size = new TLRPC.TL_photoSize(); + size.location = location; + size.w = scaledBitmap.getWidth(); + size.h = scaledBitmap.getHeight(); + if (size.w <= 100 && size.h <= 100) { + size.type = "s"; + } else if (size.w <= 320 && size.h <= 320) { + size.type = "m"; + } else if (size.w <= 800 && size.h <= 800) { + size.type = "x"; + } else if (size.w <= 1280 && size.h <= 1280) { + size.type = "y"; + } else { + size.type = "w"; + } + + String fileName = location.volume_id + "_" + location.local_id + ".jpg"; + final File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); + FileOutputStream stream = new FileOutputStream(cacheFile); + scaledBitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream); + if (cache) { + ByteArrayOutputStream stream2 = new ByteArrayOutputStream(); + scaledBitmap.compress(Bitmap.CompressFormat.JPEG, quality, stream2); + size.bytes = stream2.toByteArray(); + size.size = size.bytes.length; + stream2.close(); + } else { + size.size = (int) stream.getChannel().size(); + } + stream.close(); + if (scaledBitmap != bitmap) { + scaledBitmap.recycle(); + } + + return size; + } + + public static TLRPC.PhotoSize scaleAndSaveImage(Bitmap bitmap, float maxWidth, float maxHeight, int quality, boolean cache) { + return scaleAndSaveImage(bitmap, maxWidth, maxHeight, quality, cache, 0, 0); + } + + public static TLRPC.PhotoSize scaleAndSaveImage(Bitmap bitmap, float maxWidth, float maxHeight, int quality, boolean cache, int minWidth, int minHeight) { + if (bitmap == null) { + return null; + } + float photoW = bitmap.getWidth(); + float photoH = bitmap.getHeight(); + if (photoW == 0 || photoH == 0) { + return null; + } + boolean scaleAnyway = false; + float scaleFactor = Math.max(photoW / maxWidth, photoH / maxHeight); + if (minWidth != 0 && minHeight != 0 && (photoW < minWidth || photoH < minHeight)) { + if (photoW < minWidth && photoH > minHeight) { + scaleFactor = photoW / minWidth; + } else if (photoW > minWidth && photoH < minHeight) { + scaleFactor = photoH / minHeight; + } else { + scaleFactor = Math.max(photoW / minWidth, photoH / minHeight); + } + scaleAnyway = true; + } + int w = (int) (photoW / scaleFactor); + int h = (int) (photoH / scaleFactor); + if (h == 0 || w == 0) { + return null; + } + + try { + return scaleAndSaveImageInternal(bitmap, w, h, photoW, photoH, scaleFactor, quality, cache, scaleAnyway); + } catch (Throwable e) { + FileLog.e("tmessages", e); + ImageLoader.getInstance().clearMemory(); + System.gc(); + try { + return scaleAndSaveImageInternal(bitmap, w, h, photoW, photoH, scaleFactor, quality, cache, scaleAnyway); + } catch (Throwable e2) { + FileLog.e("tmessages", e2); + return null; + } + } + } + + public static String getHttpUrlExtension(String url, String defaultExt) { + String ext = null; + int idx = url.lastIndexOf('.'); + if (idx != -1) { + ext = url.substring(idx + 1); + } + if (ext == null || ext.length() == 0 || ext.length() > 4) { + ext = defaultExt; + } + return ext; + } + + public static void saveMessageThumbs(TLRPC.Message message) { + TLRPC.PhotoSize photoSize = null; + if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + for (TLRPC.PhotoSize size : message.media.photo.sizes) { + if (size instanceof TLRPC.TL_photoCachedSize) { + photoSize = size; + break; + } + } + } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { + if (message.media.document.thumb instanceof TLRPC.TL_photoCachedSize) { + photoSize = message.media.document.thumb; + } + } else if (message.media instanceof TLRPC.TL_messageMediaWebPage) { + if (message.media.webpage.photo != null) { + for (TLRPC.PhotoSize size : message.media.webpage.photo.sizes) { + if (size instanceof TLRPC.TL_photoCachedSize) { + photoSize = size; + break; + } + } + } + } + if (photoSize != null && photoSize.bytes != null && photoSize.bytes.length != 0) { + if (photoSize.location instanceof TLRPC.TL_fileLocationUnavailable) { + photoSize.location = new TLRPC.TL_fileLocation(); + photoSize.location.volume_id = Integer.MIN_VALUE; + photoSize.location.dc_id = Integer.MIN_VALUE; + photoSize.location.local_id = UserConfig.lastLocalId; + UserConfig.lastLocalId--; + } + File file = FileLoader.getPathToAttach(photoSize, true); + if (!file.exists()) { + try { + RandomAccessFile writeFile = new RandomAccessFile(file, "rws"); + writeFile.write(photoSize.bytes); + writeFile.close(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + TLRPC.TL_photoSize newPhotoSize = new TLRPC.TL_photoSize(); + newPhotoSize.w = photoSize.w; + newPhotoSize.h = photoSize.h; + newPhotoSize.location = photoSize.location; + newPhotoSize.size = photoSize.size; + newPhotoSize.type = photoSize.type; + + if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + for (int a = 0; a < message.media.photo.sizes.size(); a++) { + if (message.media.photo.sizes.get(a) instanceof TLRPC.TL_photoCachedSize) { + message.media.photo.sizes.set(a, newPhotoSize); + break; + } + } + } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { + message.media.document.thumb = newPhotoSize; + } else if (message.media instanceof TLRPC.TL_messageMediaWebPage) { + for (int a = 0; a < message.media.webpage.photo.sizes.size(); a++) { + if (message.media.webpage.photo.sizes.get(a) instanceof TLRPC.TL_photoCachedSize) { + message.media.webpage.photo.sizes.set(a, newPhotoSize); + break; + } + } + } + } + } + + public static void saveMessagesThumbs(ArrayList messages) { + if (messages == null || messages.isEmpty()) { + return; + } + for (int a = 0; a < messages.size(); a++) { + TLRPC.Message message = messages.get(a); + saveMessageThumbs(message); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java new file mode 100644 index 00000000..b15ccb15 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ImageReceiver.java @@ -0,0 +1,1069 @@ +/* + * This is the source code of Telegram for Android v. 1.3.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.view.View; + +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AnimatedFileDrawable; + +public class ImageReceiver implements NotificationCenter.NotificationCenterDelegate { + + public interface ImageReceiverDelegate { + void didSetImage(ImageReceiver imageReceiver, boolean set, boolean thumb); + } + + private class SetImageBackup { + public TLObject fileLocation; + public String httpUrl; + public String filter; + public Drawable thumb; + public TLRPC.FileLocation thumbLocation; + public String thumbFilter; + public int size; + public boolean cacheOnly; + public String ext; + } + + private View parentView; + private Integer tag; + private Integer thumbTag; + private MessageObject parentMessageObject; + private boolean canceledLoading; + private static PorterDuffColorFilter selectedColorFilter = new PorterDuffColorFilter(0xffdddddd, PorterDuff.Mode.MULTIPLY); + + private SetImageBackup setImageBackup; + + private TLObject currentImageLocation; + private String currentKey; + private String currentThumbKey; + private String currentHttpUrl; + private String currentFilter; + private String currentThumbFilter; + private String currentExt; + private TLRPC.FileLocation currentThumbLocation; + private int currentSize; + private boolean currentCacheOnly; + private Drawable currentImage; + private Drawable currentThumb; + private Drawable staticThumb; + private boolean allowStartAnimation = true; + + private boolean needsQualityThumb; + private boolean shouldGenerateQualityThumb; + private boolean invalidateAll; + + private int imageX, imageY, imageW, imageH; + private Rect drawRegion = new Rect(); + private boolean isVisible = true; + private boolean isAspectFit; + private boolean forcePreview; + private int roundRadius; + private BitmapShader bitmapShader; + private BitmapShader bitmapShaderThumb; + private static Paint roundPaint; + private RectF roundRect = new RectF(); + private RectF bitmapRect = new RectF(); + private Matrix shaderMatrix = new Matrix(); + private float overrideAlpha = 1.0f; + private boolean isPressed; + private int orientation; + private boolean centerRotation; + private ImageReceiverDelegate delegate; + private float currentAlpha; + private long lastUpdateAlphaTime; + private byte crossfadeAlpha = 1; + private boolean crossfadeWithThumb; + private ColorFilter colorFilter; + + public ImageReceiver() { + this(null); + } + + public ImageReceiver(View view) { + parentView = view; + if (roundPaint == null) { + roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + } + } + + public void cancelLoadImage() { + ImageLoader.getInstance().cancelLoadingForImageReceiver(this, 0); + canceledLoading = true; + } + + public void setImage(TLObject path, String filter, Drawable thumb, String ext, boolean cacheOnly) { + setImage(path, null, filter, thumb, null, null, 0, ext, cacheOnly); + } + + public void setImage(TLObject path, String filter, Drawable thumb, int size, String ext, boolean cacheOnly) { + setImage(path, null, filter, thumb, null, null, size, ext, cacheOnly); + } + + public void setImage(String httpUrl, String filter, Drawable thumb, String ext, int size) { + setImage(null, httpUrl, filter, thumb, null, null, size, ext, true); + } + + public void setImage(TLObject fileLocation, String filter, TLRPC.FileLocation thumbLocation, String thumbFilter, String ext, boolean cacheOnly) { + setImage(fileLocation, null, filter, null, thumbLocation, thumbFilter, 0, ext, cacheOnly); + } + + public void setImage(TLObject fileLocation, String filter, TLRPC.FileLocation thumbLocation, String thumbFilter, int size, String ext, boolean cacheOnly) { + setImage(fileLocation, null, filter, null, thumbLocation, thumbFilter, size, ext, cacheOnly); + } + + public void setImage(TLObject fileLocation, String httpUrl, String filter, Drawable thumb, TLRPC.FileLocation thumbLocation, String thumbFilter, int size, String ext, boolean cacheOnly) { + if (setImageBackup != null) { + setImageBackup.fileLocation = null; + setImageBackup.httpUrl = null; + setImageBackup.thumbLocation = null; + setImageBackup.thumb = null; + } + + if ((fileLocation == null && httpUrl == null && thumbLocation == null) + || (fileLocation != null && !(fileLocation instanceof TLRPC.TL_fileLocation) + && !(fileLocation instanceof TLRPC.TL_fileEncryptedLocation) + && !(fileLocation instanceof TLRPC.TL_document) + && !(fileLocation instanceof TLRPC.TL_documentEncrypted))) { + recycleBitmap(null, false); + recycleBitmap(null, true); + currentKey = null; + currentExt = ext; + currentThumbKey = null; + currentThumbFilter = null; + currentImageLocation = null; + currentHttpUrl = null; + currentFilter = null; + currentCacheOnly = false; + staticThumb = thumb; + currentAlpha = 1; + currentThumbLocation = null; + currentSize = 0; + currentImage = null; + bitmapShader = null; + bitmapShaderThumb = null; + ImageLoader.getInstance().cancelLoadingForImageReceiver(this, 0); + if (parentView != null) { + if (invalidateAll) { + parentView.invalidate(); + } else { + parentView.invalidate(imageX, imageY, imageX + imageW, imageY + imageH); + } + } + if (delegate != null) { + delegate.didSetImage(this, currentImage != null || currentThumb != null || staticThumb != null, currentImage == null); + } + return; + } + + if (!(thumbLocation instanceof TLRPC.TL_fileLocation)) { + thumbLocation = null; + } + + String key = null; + if (fileLocation != null) { + if (fileLocation instanceof TLRPC.FileLocation) { + TLRPC.FileLocation location = (TLRPC.FileLocation) fileLocation; + key = location.volume_id + "_" + location.local_id; + } else { + TLRPC.Document location = (TLRPC.Document) fileLocation; + if (location.dc_id != 0) { + key = location.dc_id + "_" + location.id; + } else { + fileLocation = null; + } + } + } else if (httpUrl != null) { + key = Utilities.MD5(httpUrl); + } + if (key != null) { + if (filter != null) { + key += "@" + filter; + } + } + + if (currentKey != null && key != null && currentKey.equals(key)) { + if (delegate != null) { + delegate.didSetImage(this, currentImage != null || currentThumb != null || staticThumb != null, currentImage == null); + } + if (!canceledLoading && !forcePreview) { + return; + } + } + + String thumbKey = null; + if (thumbLocation != null) { + thumbKey = thumbLocation.volume_id + "_" + thumbLocation.local_id; + if (thumbFilter != null) { + thumbKey += "@" + thumbFilter; + } + } + + recycleBitmap(key, false); + recycleBitmap(thumbKey, true); + + currentThumbKey = thumbKey; + currentKey = key; + currentExt = ext; + currentImageLocation = fileLocation; + currentHttpUrl = httpUrl; + currentFilter = filter; + currentThumbFilter = thumbFilter; + currentSize = size; + currentCacheOnly = cacheOnly; + currentThumbLocation = thumbLocation; + staticThumb = thumb; + bitmapShader = null; + bitmapShaderThumb = null; + currentAlpha = 1.0f; + + if (delegate != null) { + delegate.didSetImage(this, currentImage != null || currentThumb != null || staticThumb != null, currentImage == null); + } + + ImageLoader.getInstance().loadImageForImageReceiver(this); + if (parentView != null) { + if (invalidateAll) { + parentView.invalidate(); + } else { + parentView.invalidate(imageX, imageY, imageX + imageW, imageY + imageH); + } + } + } + + public void setColorFilter(ColorFilter filter) { + colorFilter = filter; + } + + public void setDelegate(ImageReceiverDelegate delegate) { + this.delegate = delegate; + } + + public void setPressed(boolean value) { + isPressed = value; + } + + public boolean getPressed() { + return isPressed; + } + + public void setOrientation(int angle, boolean center) { + while (angle < 0) { + angle += 360; + } + while (angle > 360) { + angle -= 360; + } + orientation = angle; + centerRotation = center; + } + + public void setInvalidateAll(boolean value) { + invalidateAll = value; + } + + public int getOrientation() { + return orientation; + } + + public void setImageBitmap(Bitmap bitmap) { + setImageBitmap(bitmap != null ? new BitmapDrawable(null, bitmap) : null); + } + + public void setImageBitmap(Drawable bitmap) { + ImageLoader.getInstance().cancelLoadingForImageReceiver(this, 0); + recycleBitmap(null, false); + recycleBitmap(null, true); + staticThumb = bitmap; + currentThumbLocation = null; + currentKey = null; + currentExt = null; + currentThumbKey = null; + currentImage = null; + currentThumbFilter = null; + currentImageLocation = null; + currentHttpUrl = null; + currentFilter = null; + currentSize = 0; + currentCacheOnly = false; + bitmapShader = null; + bitmapShaderThumb = null; + if (setImageBackup != null) { + setImageBackup.fileLocation = null; + setImageBackup.httpUrl = null; + setImageBackup.thumbLocation = null; + setImageBackup.thumb = null; + } + currentAlpha = 1; + if (delegate != null) { + delegate.didSetImage(this, currentThumb != null || staticThumb != null, true); + } + if (parentView != null) { + if (invalidateAll) { + parentView.invalidate(); + } else { + parentView.invalidate(imageX, imageY, imageX + imageW, imageY + imageH); + } + } + } + + public void clearImage() { + recycleBitmap(null, false); + recycleBitmap(null, true); + if (needsQualityThumb) { + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messageThumbGenerated); + ImageLoader.getInstance().cancelLoadingForImageReceiver(this, 0); + } + } + + public void onDetachedFromWindow() { + if (currentImageLocation != null || currentHttpUrl != null || currentThumbLocation != null || staticThumb != null) { + if (setImageBackup == null) { + setImageBackup = new SetImageBackup(); + } + setImageBackup.fileLocation = currentImageLocation; + setImageBackup.httpUrl = currentHttpUrl; + setImageBackup.filter = currentFilter; + setImageBackup.thumb = staticThumb; + setImageBackup.thumbLocation = currentThumbLocation; + setImageBackup.thumbFilter = currentThumbFilter; + setImageBackup.size = currentSize; + setImageBackup.ext = currentExt; + setImageBackup.cacheOnly = currentCacheOnly; + } + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReplacedPhotoInMemCache); + clearImage(); + } + + public boolean onAttachedToWindow() { + NotificationCenter.getInstance().addObserver(this, NotificationCenter.didReplacedPhotoInMemCache); + if (setImageBackup != null && (setImageBackup.fileLocation != null || setImageBackup.httpUrl != null || setImageBackup.thumbLocation != null || setImageBackup.thumb != null)) { + setImage(setImageBackup.fileLocation, setImageBackup.httpUrl, setImageBackup.filter, setImageBackup.thumb, setImageBackup.thumbLocation, setImageBackup.thumbFilter, setImageBackup.size, setImageBackup.ext, setImageBackup.cacheOnly); + return true; + } + return false; + } + + private void drawDrawable(Canvas canvas, Drawable drawable, int alpha, BitmapShader shader) { + if (drawable instanceof BitmapDrawable) { + BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; + + Paint paint; + if (shader != null) { + paint = roundPaint; + } else { + paint = bitmapDrawable.getPaint(); + } + boolean hasFilter = paint != null && paint.getColorFilter() != null; + if (hasFilter && !isPressed) { + if (shader != null) { + roundPaint.setColorFilter(null); + } else { + bitmapDrawable.setColorFilter(null); + } + } else if (!hasFilter && isPressed) { + if (shader != null) { + roundPaint.setColorFilter(selectedColorFilter); + } else { + bitmapDrawable.setColorFilter(selectedColorFilter); + } + } + if (colorFilter != null) { + if (shader != null) { + roundPaint.setColorFilter(colorFilter); + } else { + bitmapDrawable.setColorFilter(colorFilter); + } + } + int bitmapW; + int bitmapH; + if (bitmapDrawable instanceof AnimatedFileDrawable) { + if (orientation % 360 == 90 || orientation % 360 == 270) { + bitmapW = bitmapDrawable.getIntrinsicHeight(); + bitmapH = bitmapDrawable.getIntrinsicWidth(); + } else { + bitmapW = bitmapDrawable.getIntrinsicWidth(); + bitmapH = bitmapDrawable.getIntrinsicHeight(); + } + } else { + if (orientation % 360 == 90 || orientation % 360 == 270) { + bitmapW = bitmapDrawable.getBitmap().getHeight(); + bitmapH = bitmapDrawable.getBitmap().getWidth(); + } else { + bitmapW = bitmapDrawable.getBitmap().getWidth(); + bitmapH = bitmapDrawable.getBitmap().getHeight(); + } + } + float scaleW = bitmapW / (float) imageW; + float scaleH = bitmapH / (float) imageH; + + if (shader != null) { + roundPaint.setShader(shader); + float scale = Math.min(scaleW, scaleH); + roundRect.set(imageX, imageY, imageX + imageW, imageY + imageH); + shaderMatrix.reset(); + if (Math.abs(scaleW - scaleH) > 0.00001f) { + if (bitmapW / scaleH > imageW) { + drawRegion.set(imageX - ((int) (bitmapW / scaleH) - imageW) / 2, imageY, imageX + ((int) (bitmapW / scaleH) + imageW) / 2, imageY + imageH); + } else { + drawRegion.set(imageX, imageY - ((int) (bitmapH / scaleW) - imageH) / 2, imageX + imageW, imageY + ((int) (bitmapH / scaleW) + imageH) / 2); + } + } else { + drawRegion.set(imageX, imageY, imageX + imageW, imageY + imageH); + } + if (isVisible) { + if (Math.abs(scaleW - scaleH) > 0.00001f) { + int w = (int) Math.floor(imageW * scale); + int h = (int) Math.floor(imageH * scale); + bitmapRect.set((bitmapW - w) / 2, (bitmapH - h) / 2, (bitmapW + w) / 2, (bitmapH + h) / 2); + shaderMatrix.setRectToRect(bitmapRect, roundRect, Matrix.ScaleToFit.START); + } else { + bitmapRect.set(0, 0, bitmapW, bitmapH); + shaderMatrix.setRectToRect(bitmapRect, roundRect, Matrix.ScaleToFit.FILL); + } + shader.setLocalMatrix(shaderMatrix); + roundPaint.setAlpha(alpha); + canvas.drawRoundRect(roundRect, roundRadius, roundRadius, roundPaint); + } + } else { + if (isAspectFit) { + float scale = Math.max(scaleW, scaleH); + canvas.save(); + bitmapW /= scale; + bitmapH /= scale; + drawRegion.set(imageX + (imageW - bitmapW) / 2, imageY + (imageH - bitmapH) / 2, imageX + (imageW + bitmapW) / 2, imageY + (imageH + bitmapH) / 2); + bitmapDrawable.setBounds(drawRegion); + try { + bitmapDrawable.setAlpha(alpha); + bitmapDrawable.draw(canvas); + } catch (Exception e) { + if (bitmapDrawable == currentImage && currentKey != null) { + ImageLoader.getInstance().removeImage(currentKey); + currentKey = null; + } else if (bitmapDrawable == currentThumb && currentThumbKey != null) { + ImageLoader.getInstance().removeImage(currentThumbKey); + currentThumbKey = null; + } + setImage(currentImageLocation, currentHttpUrl, currentFilter, currentThumb, currentThumbLocation, currentThumbFilter, currentSize, currentExt, currentCacheOnly); + FileLog.e("tmessages", e); + } + canvas.restore(); + } else { + if (Math.abs(scaleW - scaleH) > 0.00001f) { + canvas.save(); + canvas.clipRect(imageX, imageY, imageX + imageW, imageY + imageH); + + if (orientation % 360 != 0) { + if (centerRotation) { + canvas.rotate(orientation, imageW / 2, imageH / 2); + } else { + canvas.rotate(orientation, 0, 0); + } + } + + if (bitmapDrawable instanceof AnimatedFileDrawable) { + drawRegion.set(imageX, imageY, imageX + imageW, imageY + imageH); + } else { + if (bitmapW / scaleH > imageW) { + bitmapW /= scaleH; + drawRegion.set(imageX - (bitmapW - imageW) / 2, imageY, imageX + (bitmapW + imageW) / 2, imageY + imageH); + } else { + bitmapH /= scaleW; + drawRegion.set(imageX, imageY - (bitmapH - imageH) / 2, imageX + imageW, imageY + (bitmapH + imageH) / 2); + } + } + if (orientation % 360 == 90 || orientation % 360 == 270) { + int width = (drawRegion.right - drawRegion.left) / 2; + int height = (drawRegion.bottom - drawRegion.top) / 2; + int centerX = (drawRegion.right + drawRegion.left) / 2; + int centerY = (drawRegion.top + drawRegion.bottom) / 2; + bitmapDrawable.setBounds(centerX - height, centerY - width, centerX + height, centerY + width); + } else { + bitmapDrawable.setBounds(drawRegion); + } + if (isVisible) { + try { + bitmapDrawable.setAlpha(alpha); + bitmapDrawable.draw(canvas); + } catch (Exception e) { + if (bitmapDrawable == currentImage && currentKey != null) { + ImageLoader.getInstance().removeImage(currentKey); + currentKey = null; + } else if (bitmapDrawable == currentThumb && currentThumbKey != null) { + ImageLoader.getInstance().removeImage(currentThumbKey); + currentThumbKey = null; + } + setImage(currentImageLocation, currentHttpUrl, currentFilter, currentThumb, currentThumbLocation, currentThumbFilter, currentSize, currentExt, currentCacheOnly); + FileLog.e("tmessages", e); + } + } + + canvas.restore(); + } else { + canvas.save(); + if (orientation % 360 != 0) { + if (centerRotation) { + canvas.rotate(orientation, imageW / 2, imageH / 2); + } else { + canvas.rotate(orientation, 0, 0); + } + } + drawRegion.set(imageX, imageY, imageX + imageW, imageY + imageH); + if (orientation % 360 == 90 || orientation % 360 == 270) { + int width = (drawRegion.right - drawRegion.left) / 2; + int height = (drawRegion.bottom - drawRegion.top) / 2; + int centerX = (drawRegion.right + drawRegion.left) / 2; + int centerY = (drawRegion.top + drawRegion.bottom) / 2; + bitmapDrawable.setBounds(centerX - height, centerY - width, centerX + height, centerY + width); + } else { + bitmapDrawable.setBounds(drawRegion); + } + if (isVisible) { + try { + bitmapDrawable.setAlpha(alpha); + bitmapDrawable.draw(canvas); + } catch (Exception e) { + if (bitmapDrawable == currentImage && currentKey != null) { + ImageLoader.getInstance().removeImage(currentKey); + currentKey = null; + } else if (bitmapDrawable == currentThumb && currentThumbKey != null) { + ImageLoader.getInstance().removeImage(currentThumbKey); + currentThumbKey = null; + } + setImage(currentImageLocation, currentHttpUrl, currentFilter, currentThumb, currentThumbLocation, currentThumbFilter, currentSize, currentExt, currentCacheOnly); + FileLog.e("tmessages", e); + } + } + canvas.restore(); + } + } + } + } else { + drawRegion.set(imageX, imageY, imageX + imageW, imageY + imageH); + drawable.setBounds(drawRegion); + if (isVisible) { + try { + drawable.setAlpha(alpha); + drawable.draw(canvas); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + } + + private void checkAlphaAnimation(boolean skip) { + if (currentAlpha != 1) { + if (!skip) { + long currentTime = System.currentTimeMillis(); + long dt = currentTime - lastUpdateAlphaTime; + if (dt > 18) { + dt = 18; + } + currentAlpha += dt / 150.0f; + if (currentAlpha > 1) { + currentAlpha = 1; + } + } + lastUpdateAlphaTime = System.currentTimeMillis(); + if (parentView != null) { + if (invalidateAll) { + parentView.invalidate(); + } else { + parentView.invalidate(imageX, imageY, imageX + imageW, imageY + imageH); + } + } + } + } + + public boolean draw(Canvas canvas) { + try { + Drawable drawable = null; + boolean animationNotReady = currentImage instanceof AnimatedFileDrawable && !((AnimatedFileDrawable) currentImage).hasBitmap(); + boolean isThumb = false; + if (!forcePreview && currentImage != null && !animationNotReady) { + drawable = currentImage; + } else if (staticThumb instanceof BitmapDrawable) { + drawable = staticThumb; + isThumb = true; + } else if (currentThumb != null) { + drawable = currentThumb; + isThumb = true; + } + if (drawable != null) { + if (crossfadeAlpha != 0) { + if (crossfadeWithThumb && animationNotReady) { + drawDrawable(canvas, drawable, (int) (overrideAlpha * 255), bitmapShaderThumb); + } else { + if (crossfadeWithThumb && currentAlpha != 1.0f) { + Drawable thumbDrawable = null; + if (drawable == currentImage) { + if (staticThumb != null) { + thumbDrawable = staticThumb; + } else if (currentThumb != null) { + thumbDrawable = currentThumb; + } + } else if (drawable == currentThumb) { + if (staticThumb != null) { + thumbDrawable = staticThumb; + } + } + if (thumbDrawable != null) { + drawDrawable(canvas, thumbDrawable, (int) (overrideAlpha * 255), bitmapShaderThumb); + } + } + drawDrawable(canvas, drawable, (int) (overrideAlpha * currentAlpha * 255), isThumb ? bitmapShaderThumb : bitmapShader); + } + } else { + drawDrawable(canvas, drawable, (int) (overrideAlpha * 255), isThumb ? bitmapShaderThumb : bitmapShader); + } + + checkAlphaAnimation(animationNotReady && crossfadeWithThumb); + return true; + } else if (staticThumb != null) { + drawDrawable(canvas, staticThumb, 255, null); + checkAlphaAnimation(animationNotReady); + return true; + } else { + checkAlphaAnimation(animationNotReady); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return false; + } + + public Bitmap getBitmap() { + if (currentImage instanceof AnimatedFileDrawable) { + return ((AnimatedFileDrawable) currentImage).getAnimatedBitmap(); + } else if (currentImage instanceof BitmapDrawable) { + return ((BitmapDrawable) currentImage).getBitmap(); + } else if (currentThumb instanceof BitmapDrawable) { + return ((BitmapDrawable) currentThumb).getBitmap(); + } else if (staticThumb instanceof BitmapDrawable) { + return ((BitmapDrawable) staticThumb).getBitmap(); + } + return null; + } + + public int getBitmapWidth() { + if (currentImage instanceof AnimatedFileDrawable) { + return orientation % 360 == 0 || orientation % 360 == 180 ? currentImage.getIntrinsicWidth() : currentImage.getIntrinsicHeight(); + } + Bitmap bitmap = getBitmap(); + return orientation % 360 == 0 || orientation % 360 == 180 ? bitmap.getWidth() : bitmap.getHeight(); + } + + public int getBitmapHeight() { + if (currentImage instanceof AnimatedFileDrawable) { + return orientation % 360 == 0 || orientation % 360 == 180 ? currentImage.getIntrinsicHeight() : currentImage.getIntrinsicWidth(); + } + Bitmap bitmap = getBitmap(); + return orientation % 360 == 0 || orientation % 360 == 180 ? bitmap.getHeight() : bitmap.getWidth(); + } + + public void setVisible(boolean value, boolean invalidate) { + if (isVisible == value) { + return; + } + isVisible = value; + if (invalidate && parentView != null) { + if (invalidateAll) { + parentView.invalidate(); + } else { + parentView.invalidate(imageX, imageY, imageX + imageW, imageY + imageH); + } + } + } + + public boolean getVisible() { + return isVisible; + } + + public void setAlpha(float value) { + overrideAlpha = value; + } + + public void setCrossfadeAlpha(byte value) { + crossfadeAlpha = value; + } + + public boolean hasImage() { + return currentImage != null || currentThumb != null || currentKey != null || currentHttpUrl != null || staticThumb != null; + } + + public boolean hasBitmapImage() { + return currentImage != null || currentThumb != null || staticThumb != null; + } + + public void setAspectFit(boolean value) { + isAspectFit = value; + } + + public void setParentView(View view) { + parentView = view; + if (currentImage instanceof AnimatedFileDrawable) { + AnimatedFileDrawable fileDrawable = (AnimatedFileDrawable) currentImage; + fileDrawable.setParentView(parentView); + } + } + + public void setImageCoords(int x, int y, int width, int height) { + imageX = x; + imageY = y; + imageW = width; + imageH = height; + } + + public int getImageX() { + return imageX; + } + + public int getImageX2() { + return imageX + imageW; + } + + public int getImageY() { + return imageY; + } + + public int getImageY2() { + return imageY + imageH; + } + + public int getImageWidth() { + return imageW; + } + + public int getImageHeight() { + return imageH; + } + + public String getExt() { + return currentExt; + } + + public boolean isInsideImage(float x, float y) { + return x >= imageX && x <= imageX + imageW && y >= imageY && y <= imageY + imageH; + } + + public Rect getDrawRegion() { + return drawRegion; + } + + public String getFilter() { + return currentFilter; + } + + public String getThumbFilter() { + return currentThumbFilter; + } + + public String getKey() { + return currentKey; + } + + public String getThumbKey() { + return currentThumbKey; + } + + public int getSize() { + return currentSize; + } + + public TLObject getImageLocation() { + return currentImageLocation; + } + + public TLRPC.FileLocation getThumbLocation() { + return currentThumbLocation; + } + + public String getHttpImageLocation() { + return currentHttpUrl; + } + + public boolean getCacheOnly() { + return currentCacheOnly; + } + + public void setForcePreview(boolean value) { + forcePreview = value; + } + + public boolean isForcePreview() { + return forcePreview; + } + + public void setRoundRadius(int value) { + roundRadius = value; + } + + public int getRoundRadius() { + return roundRadius; + } + + public void setParentMessageObject(MessageObject messageObject) { + parentMessageObject = messageObject; + } + + public MessageObject getParentMessageObject() { + return parentMessageObject; + } + + public void setNeedsQualityThumb(boolean value) { + needsQualityThumb = value; + if (needsQualityThumb) { + NotificationCenter.getInstance().addObserver(this, NotificationCenter.messageThumbGenerated); + } else { + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messageThumbGenerated); + } + } + + public boolean isNeedsQualityThumb() { + return needsQualityThumb; + } + + public void setShouldGenerateQualityThumb(boolean value) { + shouldGenerateQualityThumb = value; + } + + public boolean isShouldGenerateQualityThumb() { + return shouldGenerateQualityThumb; + } + + public void setAllowStartAnimation(boolean value) { + allowStartAnimation = value; + } + + public boolean isAllowStartAnimation() { + return allowStartAnimation; + } + + public void startAnimation() { + if (currentImage instanceof AnimatedFileDrawable) { + ((AnimatedFileDrawable) currentImage).start(); + } + } + + public void stopAnimation() { + if (currentImage instanceof AnimatedFileDrawable) { + ((AnimatedFileDrawable) currentImage).stop(); + } + } + + public boolean isAnimationRunning() { + return currentImage instanceof AnimatedFileDrawable && ((AnimatedFileDrawable) currentImage).isRunning(); + } + + protected Integer getTag(boolean thumb) { + if (thumb) { + return thumbTag; + } else { + return tag; + } + } + + protected void setTag(Integer value, boolean thumb) { + if (thumb) { + thumbTag = value; + } else { + tag = value; + } + } + + protected boolean setImageBitmapByKey(BitmapDrawable bitmap, String key, boolean thumb, boolean memCache) { + if (bitmap == null || key == null) { + return false; + } + if (!thumb) { + if (currentKey == null || !key.equals(currentKey)) { + return false; + } + if (!(bitmap instanceof AnimatedFileDrawable)) { + ImageLoader.getInstance().incrementUseCount(currentKey); + } + currentImage = bitmap; + if (roundRadius != 0 && bitmap instanceof BitmapDrawable) { + if (bitmap instanceof AnimatedFileDrawable) { + ((AnimatedFileDrawable) bitmap).setRoundRadius(roundRadius); + } else { + Bitmap object = bitmap.getBitmap(); + bitmapShader = new BitmapShader(object, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + } + } else { + bitmapShader = null; + } + + if (!memCache && !forcePreview) { + if (currentThumb == null && staticThumb == null || currentAlpha == 1.0f) { + currentAlpha = 0.0f; + lastUpdateAlphaTime = System.currentTimeMillis(); + crossfadeWithThumb = currentThumb != null || staticThumb != null; + } + } else { + currentAlpha = 1.0f; + } + if (bitmap instanceof AnimatedFileDrawable) { + AnimatedFileDrawable fileDrawable = (AnimatedFileDrawable) bitmap; + fileDrawable.setParentView(parentView); + if (allowStartAnimation) { + fileDrawable.start(); + } + } + + if (parentView != null) { + if (invalidateAll) { + parentView.invalidate(); + } else { + parentView.invalidate(imageX, imageY, imageX + imageW, imageY + imageH); + } + } + } else if (currentThumb == null && (currentImage == null || (currentImage instanceof AnimatedFileDrawable && !((AnimatedFileDrawable) currentImage).hasBitmap()) || forcePreview)) { + if (currentThumbKey == null || !key.equals(currentThumbKey)) { + return false; + } + ImageLoader.getInstance().incrementUseCount(currentThumbKey); + + currentThumb = bitmap; + + if (roundRadius != 0 && currentImage == null && bitmap instanceof BitmapDrawable) { + if (bitmap instanceof AnimatedFileDrawable) { + ((AnimatedFileDrawable) bitmap).setRoundRadius(roundRadius); + } else { + Bitmap object = bitmap.getBitmap(); + bitmapShaderThumb = new BitmapShader(object, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + } + } else { + bitmapShaderThumb = null; + } + + if (!memCache && crossfadeAlpha != 2) { + currentAlpha = 0.0f; + lastUpdateAlphaTime = System.currentTimeMillis(); + crossfadeWithThumb = staticThumb != null && currentKey == null; + } else { + currentAlpha = 1.0f; + } + + if (!(staticThumb instanceof BitmapDrawable) && parentView != null) { + if (invalidateAll) { + parentView.invalidate(); + } else { + parentView.invalidate(imageX, imageY, imageX + imageW, imageY + imageH); + } + } + } + + if (delegate != null) { + delegate.didSetImage(this, currentImage != null || currentThumb != null || staticThumb != null, currentImage == null); + } + return true; + } + + private void recycleBitmap(String newKey, boolean thumb) { + String key; + Drawable image; + if (thumb) { + key = currentThumbKey; + image = currentThumb; + } else { + key = currentKey; + image = currentImage; + } + if (key != null && (newKey == null || !newKey.equals(key)) && image != null) { + if (image instanceof AnimatedFileDrawable) { + AnimatedFileDrawable fileDrawable = (AnimatedFileDrawable) image; + fileDrawable.stop(); + fileDrawable.recycle(); + } else if (image instanceof BitmapDrawable) { + Bitmap bitmap = ((BitmapDrawable) image).getBitmap(); + boolean canDelete = ImageLoader.getInstance().decrementUseCount(key); + if (!ImageLoader.getInstance().isInCache(key)) { + if (ImageLoader.getInstance().runtimeHack != null) { + ImageLoader.getInstance().runtimeHack.trackAlloc(bitmap.getRowBytes() * bitmap.getHeight()); + } + if (canDelete) { + bitmap.recycle(); + } + } + } + } + if (thumb) { + currentThumb = null; + currentThumbKey = null; + } else { + currentImage = null; + currentKey = null; + } + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.messageThumbGenerated) { + String key = (String) args[1]; + if (currentThumbKey != null && currentThumbKey.equals(key)) { + if (currentThumb == null) { + ImageLoader.getInstance().incrementUseCount(currentThumbKey); + } + currentThumb = (BitmapDrawable) args[0]; + if (roundRadius != 0 && currentImage == null && currentThumb instanceof BitmapDrawable && !(currentThumb instanceof AnimatedFileDrawable)) { + Bitmap object = ((BitmapDrawable) currentThumb).getBitmap(); + bitmapShaderThumb = new BitmapShader(object, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + } else { + bitmapShaderThumb = null; + } + if (staticThumb instanceof BitmapDrawable) { + staticThumb = null; + } + if (parentView != null) { + if (invalidateAll) { + parentView.invalidate(); + } else { + parentView.invalidate(imageX, imageY, imageX + imageW, imageY + imageH); + } + } + } + } else if (id == NotificationCenter.didReplacedPhotoInMemCache) { + String oldKey = (String) args[0]; + if (currentKey != null && currentKey.equals(oldKey)) { + currentKey = (String) args[1]; + currentImageLocation = (TLRPC.FileLocation) args[2]; + } + if (currentThumbKey != null && currentThumbKey.equals(oldKey)) { + currentThumbKey = (String) args[1]; + currentThumbLocation = (TLRPC.FileLocation) args[2]; + } + if (setImageBackup != null) { + if (currentKey != null && currentKey.equals(oldKey)) { + currentKey = (String) args[1]; + currentImageLocation = (TLRPC.FileLocation) args[2]; + } + if (currentThumbKey != null && currentThumbKey.equals(oldKey)) { + currentThumbKey = (String) args[1]; + currentThumbLocation = (TLRPC.FileLocation) args[2]; + } + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java new file mode 100644 index 00000000..6e99a81f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LocaleController.java @@ -0,0 +1,1844 @@ +/* + * This is the source code of Telegram for Android v. 1.3.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.text.format.DateFormat; +import android.util.Xml; + +import org.telegram.messenger.time.FastDateFormat; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.xmlpull.v1.XmlPullParser; + +import java.io.File; +import java.io.FileInputStream; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.TimeZone; + +public class LocaleController { + + static final int QUANTITY_OTHER = 0x0000; + static final int QUANTITY_ZERO = 0x0001; + static final int QUANTITY_ONE = 0x0002; + static final int QUANTITY_TWO = 0x0004; + static final int QUANTITY_FEW = 0x0008; + static final int QUANTITY_MANY = 0x0010; + + public static boolean isRTL = false; + public static int nameDisplayOrder = 1; + private static boolean is24HourFormat = false; + public FastDateFormat formatterDay; + public FastDateFormat formatterWeek; + public FastDateFormat formatterMonth; + public FastDateFormat formatterYear; + public FastDateFormat formatterMonthYear; + public FastDateFormat formatterYearMax; + public FastDateFormat chatDate; + public FastDateFormat chatFullDate; + + private HashMap allRules = new HashMap<>(); + + private Locale currentLocale; + private Locale systemDefaultLocale; + private PluralRules currentPluralRules; + private LocaleInfo currentLocaleInfo; + private LocaleInfo defaultLocalInfo; + private HashMap localeValues = new HashMap<>(); + private String languageOverride; + private boolean changingConfiguration = false; + + private HashMap translitChars; + + private class TimeZoneChangedReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + ApplicationLoader.applicationHandler.post(new Runnable() { + @Override + public void run() { + if (!formatterMonth.getTimeZone().equals(TimeZone.getDefault())) { + LocaleController.getInstance().recreateFormatters(); + } + } + }); + } + } + + public static class LocaleInfo { + public String name; + public String nameEnglish; + public String shortName; + public String pathToFile; + + public String getSaveString() { + return name + "|" + nameEnglish + "|" + shortName + "|" + pathToFile; + } + + public static LocaleInfo createWithString(String string) { + if (string == null || string.length() == 0) { + return null; + } + String[] args = string.split("\\|"); + if (args.length != 4) { + return null; + } + LocaleInfo localeInfo = new LocaleInfo(); + localeInfo.name = args[0]; + localeInfo.nameEnglish = args[1]; + localeInfo.shortName = args[2]; + localeInfo.pathToFile = args[3]; + return localeInfo; + } + } + + public ArrayList sortedLanguages = new ArrayList<>(); + public HashMap languagesDict = new HashMap<>(); + + private ArrayList otherLanguages = new ArrayList<>(); + + private static volatile LocaleController Instance = null; + public static LocaleController getInstance() { + LocaleController localInstance = Instance; + if (localInstance == null) { + synchronized (LocaleController.class) { + localInstance = Instance; + if (localInstance == null) { + Instance = localInstance = new LocaleController(); + } + } + } + return localInstance; + } + + public LocaleController() { + addRules(new String[]{"bem", "brx", "da", "de", "el", "en", "eo", "es", "et", "fi", "fo", "gl", "he", "iw", "it", "nb", + "nl", "nn", "no", "sv", "af", "bg", "bn", "ca", "eu", "fur", "fy", "gu", "ha", "is", "ku", + "lb", "ml", "mr", "nah", "ne", "om", "or", "pa", "pap", "ps", "so", "sq", "sw", "ta", "te", + "tk", "ur", "zu", "mn", "gsw", "chr", "rm", "pt", "an", "ast"}, new PluralRules_One()); + addRules(new String[]{"cs", "sk"}, new PluralRules_Czech()); + addRules(new String[]{"ff", "fr", "kab"}, new PluralRules_French()); + addRules(new String[]{"hr", "ru", "sr", "uk", "be", "bs", "sh"}, new PluralRules_Balkan()); + addRules(new String[]{"lv"}, new PluralRules_Latvian()); + addRules(new String[]{"lt"}, new PluralRules_Lithuanian()); + addRules(new String[]{"pl"}, new PluralRules_Polish()); + addRules(new String[]{"ro", "mo"}, new PluralRules_Romanian()); + addRules(new String[]{"sl"}, new PluralRules_Slovenian()); + addRules(new String[]{"ar"}, new PluralRules_Arabic()); + addRules(new String[]{"mk"}, new PluralRules_Macedonian()); + addRules(new String[]{"cy"}, new PluralRules_Welsh()); + addRules(new String[]{"br"}, new PluralRules_Breton()); + addRules(new String[]{"lag"}, new PluralRules_Langi()); + addRules(new String[]{"shi"}, new PluralRules_Tachelhit()); + addRules(new String[]{"mt"}, new PluralRules_Maltese()); + addRules(new String[]{"ga", "se", "sma", "smi", "smj", "smn", "sms"}, new PluralRules_Two()); + addRules(new String[]{"ak", "am", "bh", "fil", "tl", "guw", "hi", "ln", "mg", "nso", "ti", "wa"}, new PluralRules_Zero()); + addRules(new String[]{"az", "bm", "fa", "ig", "hu", "ja", "kde", "kea", "ko", "my", "ses", "sg", "to", + "tr", "vi", "wo", "yo", "zh", "bo", "dz", "id", "jv", "ka", "km", "kn", "ms", "th"}, new PluralRules_None()); + + LocaleInfo localeInfo = new LocaleInfo(); + localeInfo.name = "English"; + localeInfo.nameEnglish = "English"; + localeInfo.shortName = "en"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Italiano"; + localeInfo.nameEnglish = "Italian"; + localeInfo.shortName = "it"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Español"; + localeInfo.nameEnglish = "Spanish"; + localeInfo.shortName = "es"; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Deutsch"; + localeInfo.nameEnglish = "German"; + localeInfo.shortName = "de"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Nederlands"; + localeInfo.nameEnglish = "Dutch"; + localeInfo.shortName = "nl"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "العربية"; + localeInfo.nameEnglish = "Arabic"; + localeInfo.shortName = "ar"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "پارسی"; + localeInfo.nameEnglish = "Parsi"; + localeInfo.shortName = "fa_IR"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "अंग्रेजी"; + localeInfo.nameEnglish = "Hindi"; + localeInfo.shortName = "hi"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Català"; + localeInfo.nameEnglish = "Catalan"; + localeInfo.shortName = "ca"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Esperanto"; + localeInfo.nameEnglish = "Esperanto"; + localeInfo.shortName = "eo"; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "正體中文(台灣)"; + localeInfo.nameEnglish = "Chinese Traditional (Taiwan)"; + localeInfo.shortName = "zh_TW"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "简体中文"; + localeInfo.nameEnglish = "Simplified Chinese"; + localeInfo.shortName = "zh_CN"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "日本語"; + localeInfo.nameEnglish = "Japanese"; + localeInfo.shortName = "ja"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Hrvatski"; + localeInfo.nameEnglish = "Croatian"; + localeInfo.shortName = "hr"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Euskara"; + localeInfo.nameEnglish = "Basque"; + localeInfo.shortName = "eu"; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Français"; + localeInfo.nameEnglish = "French"; + localeInfo.shortName = "fr"; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Galego"; + localeInfo.nameEnglish = "Galician"; + localeInfo.shortName = "gl"; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "עברית"; + localeInfo.nameEnglish = "hebrew"; + localeInfo.shortName = "he"; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "עברית"; + localeInfo.nameEnglish = "Hebrew"; + localeInfo.shortName = "iw"; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Polski"; + localeInfo.nameEnglish = "Polish"; + localeInfo.shortName = "pl"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Русский"; + localeInfo.nameEnglish = "Russian"; + localeInfo.shortName = "ru"; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Türkçe"; + localeInfo.nameEnglish = "Turkish"; + localeInfo.shortName = "tr"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Português (Brasil)"; + localeInfo.nameEnglish = "Portuguese (Brazil)"; + localeInfo.shortName = "pt_BR"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Português (Portugal)"; + localeInfo.nameEnglish = "Portuguese (Portugal)"; + localeInfo.shortName = "pt_PT"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "한국어"; + localeInfo.nameEnglish = "Korean"; + localeInfo.shortName = "ko"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + localeInfo = new LocaleInfo(); + localeInfo.name = "Українська"; + localeInfo.nameEnglish = "Ukrainian"; + localeInfo.shortName = "uk"; + localeInfo.pathToFile = null; + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + + loadOtherLanguages(); + + for (LocaleInfo locale : otherLanguages) { + sortedLanguages.add(locale); + languagesDict.put(locale.shortName, locale); + } + + Collections.sort(sortedLanguages, new Comparator() { + @Override + public int compare(LocaleController.LocaleInfo o, LocaleController.LocaleInfo o2) { + return o.name.compareTo(o2.name); + } + }); + + defaultLocalInfo = localeInfo = new LocaleController.LocaleInfo(); + localeInfo.name = "System default"; + localeInfo.nameEnglish = "System default"; + localeInfo.shortName = null; + localeInfo.pathToFile = null; + sortedLanguages.add(0, localeInfo); + + systemDefaultLocale = Locale.getDefault(); + is24HourFormat = DateFormat.is24HourFormat(ApplicationLoader.applicationContext); + LocaleInfo currentInfo = null; + boolean override = false; + + try { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + String lang = preferences.getString("language", null); + if (lang != null) { + currentInfo = languagesDict.get(lang); + if (currentInfo != null) { + override = true; + } + } + + if (currentInfo == null && systemDefaultLocale.getLanguage() != null) { + currentInfo = languagesDict.get(systemDefaultLocale.getLanguage()); + } + if (currentInfo == null) { + currentInfo = languagesDict.get(getLocaleString(systemDefaultLocale)); + } + if (currentInfo == null) { + currentInfo = languagesDict.get("en"); + } + applyLanguage(currentInfo, override); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + try { + IntentFilter timezoneFilter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED); + ApplicationLoader.applicationContext.registerReceiver(new TimeZoneChangedReceiver(), timezoneFilter); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + private void addRules(String[] languages, PluralRules rules) { + for (String language : languages) { + allRules.put(language, rules); + } + } + + private String stringForQuantity(int quantity) { + switch (quantity) { + case QUANTITY_ZERO: + return "zero"; + case QUANTITY_ONE: + return "one"; + case QUANTITY_TWO: + return "two"; + case QUANTITY_FEW: + return "few"; + case QUANTITY_MANY: + return "many"; + default: + return "other"; + } + } + + public Locale getSystemDefaultLocale() { + return systemDefaultLocale; + } + + private String getLocaleString(Locale locale) { + if (locale == null) { + return "en"; + } + String languageCode = locale.getLanguage(); + String countryCode = locale.getCountry(); + String variantCode = locale.getVariant(); + if (languageCode.length() == 0 && countryCode.length() == 0) { + return "en"; + } + StringBuilder result = new StringBuilder(11); + result.append(languageCode); + if (countryCode.length() > 0 || variantCode.length() > 0) { + //result.append('-'); + result.append('_'); + } + result.append(countryCode); + if (variantCode.length() > 0) { + result.append('_'); + } + result.append(variantCode); + return result.toString(); + } + + public static String getLocaleStringIso639() { + Locale locale = getInstance().getSystemDefaultLocale(); + if (locale == null) { + return "en"; + } + String languageCode = locale.getLanguage(); + String countryCode = locale.getCountry(); + String variantCode = locale.getVariant(); + if (languageCode.length() == 0 && countryCode.length() == 0) { + return "en"; + } + StringBuilder result = new StringBuilder(11); + result.append(languageCode); + if (countryCode.length() > 0 || variantCode.length() > 0) { + result.append('-'); + } + result.append(countryCode); + if (variantCode.length() > 0) { + result.append('_'); + } + result.append(variantCode); + return result.toString(); + } + + public boolean applyLanguageFile(File file) { + try { + HashMap stringMap = getLocaleFileStrings(file); + + String languageName = stringMap.get("LanguageName"); + String languageNameInEnglish = stringMap.get("LanguageNameInEnglish"); + String languageCode = stringMap.get("LanguageCode"); + + String theming = stringMap.get("Theming"); + + if (languageName != null && languageName.length() > 0 && + languageNameInEnglish != null && languageNameInEnglish.length() > 0 && + languageCode != null && languageCode.length() > 0 + || theming != null && theming.length() > 0) { + + if(theming == null) { + if (languageName.contains("&") || languageName.contains("|")) { + return false; + } + if (languageNameInEnglish.contains("&") || languageNameInEnglish.contains("|")) { + return false; + } + if (languageCode.contains("&") || languageCode.contains("|")) { + return false; + } + } + File finalFile = new File(ApplicationLoader.getFilesDirFixed(), languageCode + ".xml"); + if (!AndroidUtilities.copyFile(file, finalFile)) { + return false; + } + + LocaleInfo localeInfo = languagesDict.get(languageCode); + if (localeInfo == null) { + localeInfo = new LocaleInfo(); + localeInfo.name = languageName; + localeInfo.nameEnglish = languageNameInEnglish; + localeInfo.shortName = languageCode; + + localeInfo.pathToFile = finalFile.getAbsolutePath(); + sortedLanguages.add(localeInfo); + languagesDict.put(localeInfo.shortName, localeInfo); + otherLanguages.add(localeInfo); + + Collections.sort(sortedLanguages, new Comparator() { + @Override + public int compare(LocaleController.LocaleInfo o, LocaleController.LocaleInfo o2) { + if (o.shortName == null) { + return -1; + } else if (o2.shortName == null) { + return 1; + } + return o.name.compareTo(o2.name); + } + }); + saveOtherLanguages(); + } + localeValues = stringMap; + applyLanguage(localeInfo, true, true); + return true; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return false; + } + + private void saveOtherLanguages() { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("langconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + String locales = ""; + for (LocaleInfo localeInfo : otherLanguages) { + String loc = localeInfo.getSaveString(); + if (loc != null) { + if (locales.length() != 0) { + locales += "&"; + } + locales += loc; + } + } + editor.putString("locales", locales); + editor.commit(); + } + + public boolean deleteLanguage(LocaleInfo localeInfo) { + if (localeInfo.pathToFile == null) { + return false; + } + if (currentLocaleInfo == localeInfo) { + applyLanguage(defaultLocalInfo, true); + } + + otherLanguages.remove(localeInfo); + sortedLanguages.remove(localeInfo); + languagesDict.remove(localeInfo.shortName); + File file = new File(localeInfo.pathToFile); + file.delete(); + saveOtherLanguages(); + return true; + } + + private void loadOtherLanguages() { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("langconfig", Activity.MODE_PRIVATE); + String locales = preferences.getString("locales", null); + if (locales == null || locales.length() == 0) { + return; + } + String[] localesArr = locales.split("&"); + for (String locale : localesArr) { + LocaleInfo localeInfo = LocaleInfo.createWithString(locale); + if (localeInfo != null) { + otherLanguages.add(localeInfo); + } + } + } + + private HashMap getLocaleFileStrings(File file) { + FileInputStream stream = null; + try { + HashMap stringMap = new HashMap<>(); + XmlPullParser parser = Xml.newPullParser(); + stream = new FileInputStream(file); + parser.setInput(stream, "UTF-8"); + int eventType = parser.getEventType(); + String name = null; + String value = null; + String attrName = null; + while (eventType != XmlPullParser.END_DOCUMENT) { + if(eventType == XmlPullParser.START_TAG) { + name = parser.getName(); + int c = parser.getAttributeCount(); + if (c > 0) { + attrName = parser.getAttributeValue(0); + } + } else if(eventType == XmlPullParser.TEXT) { + if (attrName != null) { + value = parser.getText(); + if (value != null) { + value = value.trim(); + value = value.replace("\\n", "\n"); + value = value.replace("\\", ""); + } + } + } else if (eventType == XmlPullParser.END_TAG) { + value = null; + attrName = null; + name = null; + } + if (name != null && name.equals("string") && value != null && attrName != null && value.length() != 0 && attrName.length() != 0) { + stringMap.put(attrName, value); + name = null; + value = null; + attrName = null; + } + eventType = parser.next(); + } + return stringMap; + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + try { + if (stream != null) { + stream.close(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + return new HashMap<>(); + } + + public void applyLanguage(LocaleInfo localeInfo, boolean override) { + applyLanguage(localeInfo, override, false); + } + + public void applyLanguage(LocaleInfo localeInfo, boolean override, boolean fromFile) { + if (localeInfo == null) { + return; + } + try { + Locale newLocale; + if (localeInfo.shortName != null) { + String[] args = localeInfo.shortName.split("_"); + if (args.length == 1) { + newLocale = new Locale(localeInfo.shortName); + } else { + newLocale = new Locale(args[0], args[1]); + } + if (newLocale != null) { + if (override) { + languageOverride = localeInfo.shortName; + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString("language", localeInfo.shortName); + editor.commit(); + } + } + } else { + newLocale = systemDefaultLocale; + languageOverride = null; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.remove("language"); + editor.commit(); + + if (newLocale != null) { + LocaleInfo info = null; + if (newLocale.getLanguage() != null) { + info = languagesDict.get(newLocale.getLanguage()); + } + if (info == null) { + info = languagesDict.get(getLocaleString(newLocale)); + } + if (info == null) { + newLocale = Locale.US; + } + } + } + if (newLocale != null) { + if (localeInfo.pathToFile == null) { + localeValues.clear(); + } else if (!fromFile) { + localeValues = getLocaleFileStrings(new File(localeInfo.pathToFile)); + } + currentLocale = newLocale; + currentLocaleInfo = localeInfo; + currentPluralRules = allRules.get(currentLocale.getLanguage()); + if (currentPluralRules == null) { + currentPluralRules = allRules.get("en"); + } + changingConfiguration = true; + Locale.setDefault(currentLocale); + android.content.res.Configuration config = new android.content.res.Configuration(); + config.locale = currentLocale; + ApplicationLoader.applicationContext.getResources().updateConfiguration(config, ApplicationLoader.applicationContext.getResources().getDisplayMetrics()); + changingConfiguration = false; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + changingConfiguration = false; + } + recreateFormatters(); + } + + private void loadCurrentLocale() { + localeValues.clear(); + } + + public static String getCurrentLanguageName() { + return getString("LanguageName", R.string.LanguageName); + } + + private String getStringInternal(String key, int res) { + String value = localeValues.get(key); + if (value == null) { + try { + value = ApplicationLoader.applicationContext.getString(res); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + if (value == null) { + value = "LOC_ERR:" + key; + } + return value; + } + + public static String getString(String key, int res) { + return getInstance().getStringInternal(key, res); + } + + public static String formatPluralString(String key, int plural) { + if (key == null || key.length() == 0 || getInstance().currentPluralRules == null) { + return "LOC_ERR:" + key; + } + String param = getInstance().stringForQuantity(getInstance().currentPluralRules.quantityForNumber(plural)); + param = key + "_" + param; + int resourceId = ApplicationLoader.applicationContext.getResources().getIdentifier(param, "string", ApplicationLoader.applicationContext.getPackageName()); + return formatString(param, resourceId, plural); + } + + public static String formatString(String key, int res, Object... args) { + try { + String value = getInstance().localeValues.get(key); + if (value == null) { + value = ApplicationLoader.applicationContext.getString(res); + } + + if (getInstance().currentLocale != null) { + return String.format(getInstance().currentLocale, value, args); + } else { + return String.format(value, args); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + return "LOC_ERR: " + key; + } + } + + public static String formatStringSimple(String string, Object... args) { + try { + if (getInstance().currentLocale != null) { + return String.format(getInstance().currentLocale, string, args); + } else { + return String.format(string, args); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + return "LOC_ERR: " + string; + } + } + + public void onDeviceConfigurationChange(Configuration newConfig) { + if (changingConfiguration) { + return; + } + is24HourFormat = DateFormat.is24HourFormat(ApplicationLoader.applicationContext); + systemDefaultLocale = newConfig.locale; + if (languageOverride != null) { + LocaleInfo toSet = currentLocaleInfo; + currentLocaleInfo = null; + applyLanguage(toSet, false); + } else { + Locale newLocale = newConfig.locale; + if (newLocale != null) { + String d1 = newLocale.getDisplayName(); + String d2 = currentLocale.getDisplayName(); + if (d1 != null && d2 != null && !d1.equals(d2)) { + recreateFormatters(); + } + currentLocale = newLocale; + currentPluralRules = allRules.get(currentLocale.getLanguage()); + if (currentPluralRules == null) { + currentPluralRules = allRules.get("en"); + } + } + } + } + + public static String formatDateChat(long date) { + try { + Calendar rightNow = Calendar.getInstance(); + int year = rightNow.get(Calendar.YEAR); + + rightNow.setTimeInMillis(date * 1000); + int dateYear = rightNow.get(Calendar.YEAR); + + if (year == dateYear) { + return getInstance().chatDate.format(date * 1000); + } + return getInstance().chatFullDate.format(date * 1000); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return "LOC_ERR: formatDateChat"; + } + + public static String formatDate(long date) { + try { + Calendar rightNow = Calendar.getInstance(); + int day = rightNow.get(Calendar.DAY_OF_YEAR); + int year = rightNow.get(Calendar.YEAR); + rightNow.setTimeInMillis(date * 1000); + int dateDay = rightNow.get(Calendar.DAY_OF_YEAR); + int dateYear = rightNow.get(Calendar.YEAR); + + if (dateDay == day && year == dateYear) { + return getInstance().formatterDay.format(new Date(date * 1000)); + } else if (dateDay + 1 == day && year == dateYear) { + return getString("Yesterday", R.string.Yesterday); + } else if (year == dateYear) { + return getInstance().formatterMonth.format(new Date(date * 1000)); + } else { + return getInstance().formatterYear.format(new Date(date * 1000)); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return "LOC_ERR: formatDate"; + } + + public static String formatDateAudio(long date) { + try { + Calendar rightNow = Calendar.getInstance(); + int day = rightNow.get(Calendar.DAY_OF_YEAR); + int year = rightNow.get(Calendar.YEAR); + rightNow.setTimeInMillis(date * 1000); + int dateDay = rightNow.get(Calendar.DAY_OF_YEAR); + int dateYear = rightNow.get(Calendar.YEAR); + + if (dateDay == day && year == dateYear) { + return String.format("%s %s", LocaleController.getString("TodayAt", R.string.TodayAt), getInstance().formatterDay.format(new Date(date * 1000))); + } else if (dateDay + 1 == day && year == dateYear) { + return String.format("%s %s", LocaleController.getString("YesterdayAt", R.string.YesterdayAt), getInstance().formatterDay.format(new Date(date * 1000))); + } else if (year == dateYear) { + return LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().formatterMonth.format(new Date(date * 1000)), getInstance().formatterDay.format(new Date(date * 1000))); + } else { + return LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().formatterYear.format(new Date(date * 1000)), getInstance().formatterDay.format(new Date(date * 1000))); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return "LOC_ERR"; + } + + public static String formatDateOnline(long date) { + try { + Calendar rightNow = Calendar.getInstance(); + int day = rightNow.get(Calendar.DAY_OF_YEAR); + int year = rightNow.get(Calendar.YEAR); + rightNow.setTimeInMillis(date * 1000); + int dateDay = rightNow.get(Calendar.DAY_OF_YEAR); + int dateYear = rightNow.get(Calendar.YEAR); + + if (dateDay == day && year == dateYear) { + return String.format("%s %s %s", LocaleController.getString("LastSeen", R.string.LastSeen), LocaleController.getString("TodayAt", R.string.TodayAt), getInstance().formatterDay.format(new Date(date * 1000))); + /*int diff = (int) (ConnectionsManager.getInstance().getCurrentTime() - date) / 60; + if (diff < 1) { + return LocaleController.getString("LastSeenNow", R.string.LastSeenNow); + } else if (diff < 60) { + return LocaleController.formatPluralString("LastSeenMinutes", diff); + } else { + return LocaleController.formatPluralString("LastSeenHours", (int) Math.ceil(diff / 60.0f)); + }*/ + } else if (dateDay + 1 == day && year == dateYear) { + return String.format("%s %s %s", LocaleController.getString("LastSeen", R.string.LastSeen), LocaleController.getString("YesterdayAt", R.string.YesterdayAt), getInstance().formatterDay.format(new Date(date * 1000))); + } else if (year == dateYear) { + String format = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().formatterMonth.format(new Date(date * 1000)), getInstance().formatterDay.format(new Date(date * 1000))); + return String.format("%s %s", LocaleController.getString("LastSeenDate", R.string.LastSeenDate), format); + } else { + String format = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, getInstance().formatterYear.format(new Date(date * 1000)), getInstance().formatterDay.format(new Date(date * 1000))); + return String.format("%s %s", LocaleController.getString("LastSeenDate", R.string.LastSeenDate), format); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return "LOC_ERR"; + } + + private FastDateFormat createFormatter(Locale locale, String format, String defaultFormat) { + if (format == null || format.length() == 0) { + format = defaultFormat; + } + FastDateFormat formatter; + try { + formatter = FastDateFormat.getInstance(format, locale); + } catch (Exception e) { + format = defaultFormat; + formatter = FastDateFormat.getInstance(format, locale); + } + return formatter; + } + + public void recreateFormatters() { + Locale locale = currentLocale; + if (locale == null) { + locale = Locale.getDefault(); + } + String lang = locale.getLanguage(); + if (lang == null) { + lang = "en"; + } + isRTL = lang.toLowerCase().equals("ar"); + nameDisplayOrder = lang.toLowerCase().equals("ko") ? 2 : 1; + + formatterMonth = createFormatter(locale, getStringInternal("formatterMonth", R.string.formatterMonth), "dd MMM"); + formatterYear = createFormatter(locale, getStringInternal("formatterYear", R.string.formatterYear), "dd.MM.yy"); + formatterYearMax = createFormatter(locale, getStringInternal("formatterYearMax", R.string.formatterYearMax), "dd.MM.yyyy"); + chatDate = createFormatter(locale, getStringInternal("chatDate", R.string.chatDate), "d MMMM"); + chatFullDate = createFormatter(locale, getStringInternal("chatFullDate", R.string.chatFullDate), "d MMMM yyyy"); + formatterWeek = createFormatter(locale, getStringInternal("formatterWeek", R.string.formatterWeek), "EEE"); + formatterMonthYear = createFormatter(locale, getStringInternal("formatterMonthYear", R.string.formatterMonthYear), "MMMM yyyy"); + formatterDay = createFormatter(lang.toLowerCase().equals("ar") || lang.toLowerCase().equals("ko") ? locale : Locale.US, is24HourFormat ? getStringInternal("formatterDay24H", R.string.formatterDay24H) : getStringInternal("formatterDay12H", R.string.formatterDay12H), is24HourFormat ? "HH:mm" : "h:mm a"); + } + + public static String stringForMessageListDate(long date) { + try { + Calendar rightNow = Calendar.getInstance(); + int day = rightNow.get(Calendar.DAY_OF_YEAR); + int year = rightNow.get(Calendar.YEAR); + rightNow.setTimeInMillis(date * 1000); + int dateDay = rightNow.get(Calendar.DAY_OF_YEAR); + int dateYear = rightNow.get(Calendar.YEAR); + + if (year != dateYear) { + return getInstance().formatterYear.format(new Date(date * 1000)); + } else { + int dayDiff = dateDay - day; + if(dayDiff == 0 || dayDiff == -1 && (int)(System.currentTimeMillis() / 1000) - date < 60 * 60 * 8) { + return getInstance().formatterDay.format(new Date(date * 1000)); + } else if(dayDiff > -7 && dayDiff <= -1) { + return getInstance().formatterWeek.format(new Date(date * 1000)); + } else { + return getInstance().formatterMonth.format(new Date(date * 1000)); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return "LOC_ERR"; + } + + public static String formatShortNumber(int number, int[] rounded) { + String K = ""; + //plus + if(true)return String.format(Locale.US, "%d%s", number, K); + int lastDec = 0; + int KCount = 0; + while (number / 1000 > 0) { + K += "K"; + lastDec = (number % 1000) / 100; + number /= 1000; + } + if (rounded != null) { + double value = number + lastDec / 10.0; + for (int a = 0; a < K.length(); a++) { + value *= 1000; + } + rounded[0] = (int) value; + } + if (lastDec != 0 && K.length() > 0) { + if (K.length() == 2) { + return String.format(Locale.US, "%d.%dM", number, lastDec); + } else { + return String.format(Locale.US, "%d.%d%s", number, lastDec, K); + } + } + if (K.length() == 2) { + return String.format(Locale.US, "%dM", number); + } else { + return String.format(Locale.US, "%d%s", number, K); + } + } + + public static String formatUserStatus(TLRPC.User user) { + if (user != null && user.status != null && user.status.expires == 0) { + if (user.status instanceof TLRPC.TL_userStatusRecently) { + user.status.expires = -100; + } else if (user.status instanceof TLRPC.TL_userStatusLastWeek) { + user.status.expires = -101; + } else if (user.status instanceof TLRPC.TL_userStatusLastMonth) { + user.status.expires = -102; + } + } + if (user != null && user.status != null && user.status.expires <= 0) { + if (MessagesController.getInstance().onlinePrivacy.containsKey(user.id)) { + return getString("Online", R.string.Online); + } + } + if (user == null || user.status == null || user.status.expires == 0 || UserObject.isDeleted(user) || user instanceof TLRPC.TL_userEmpty) { + return getString("ALongTimeAgo", R.string.ALongTimeAgo); + } else { + int currentTime = ConnectionsManager.getInstance().getCurrentTime(); + if (user.status.expires > currentTime) { + return getString("Online", R.string.Online); + } else { + if (user.status.expires == -1) { + return getString("Invisible", R.string.Invisible); + } else if (user.status.expires == -100) { + return getString("Lately", R.string.Lately); + } else if (user.status.expires == -101) { + return getString("WithinAWeek", R.string.WithinAWeek); + } else if (user.status.expires == -102) { + return getString("WithinAMonth", R.string.WithinAMonth); + } else { + return formatDateOnline(user.status.expires); + } + } + } + } + + public String getTranslitString(String src) { + if (translitChars == null) { + translitChars = new HashMap<>(520); + translitChars.put("ȼ", "c"); + translitChars.put("ᶇ", "n"); + translitChars.put("ɖ", "d"); + translitChars.put("ỿ", "y"); + translitChars.put("ᴓ", "o"); + translitChars.put("ø", "o"); + translitChars.put("ḁ", "a"); + translitChars.put("ʯ", "h"); + translitChars.put("ŷ", "y"); + translitChars.put("ʞ", "k"); + translitChars.put("ừ", "u"); + translitChars.put("ꜳ", "aa"); + translitChars.put("ij", "ij"); + translitChars.put("ḽ", "l"); + translitChars.put("ɪ", "i"); + translitChars.put("ḇ", "b"); + translitChars.put("ʀ", "r"); + translitChars.put("ě", "e"); + translitChars.put("ffi", "ffi"); + translitChars.put("ơ", "o"); + translitChars.put("ⱹ", "r"); + translitChars.put("ồ", "o"); + translitChars.put("ǐ", "i"); + translitChars.put("ꝕ", "p"); + translitChars.put("ý", "y"); + translitChars.put("ḝ", "e"); + translitChars.put("ₒ", "o"); + translitChars.put("ⱥ", "a"); + translitChars.put("ʙ", "b"); + translitChars.put("ḛ", "e"); + translitChars.put("ƈ", "c"); + translitChars.put("ɦ", "h"); + translitChars.put("ᵬ", "b"); + translitChars.put("ṣ", "s"); + translitChars.put("đ", "d"); + translitChars.put("ỗ", "o"); + translitChars.put("ɟ", "j"); + translitChars.put("ẚ", "a"); + translitChars.put("ɏ", "y"); + translitChars.put("л", "l"); + translitChars.put("ʌ", "v"); + translitChars.put("ꝓ", "p"); + translitChars.put("fi", "fi"); + translitChars.put("ᶄ", "k"); + translitChars.put("ḏ", "d"); + translitChars.put("ᴌ", "l"); + translitChars.put("ė", "e"); + translitChars.put("ё", "yo"); + translitChars.put("ᴋ", "k"); + translitChars.put("ċ", "c"); + translitChars.put("ʁ", "r"); + translitChars.put("ƕ", "hv"); + translitChars.put("ƀ", "b"); + translitChars.put("ṍ", "o"); + translitChars.put("ȣ", "ou"); + translitChars.put("ǰ", "j"); + translitChars.put("ᶃ", "g"); + translitChars.put("ṋ", "n"); + translitChars.put("ɉ", "j"); + translitChars.put("ǧ", "g"); + translitChars.put("dz", "dz"); + translitChars.put("ź", "z"); + translitChars.put("ꜷ", "au"); + translitChars.put("ǖ", "u"); + translitChars.put("ᵹ", "g"); + translitChars.put("ȯ", "o"); + translitChars.put("ɐ", "a"); + translitChars.put("ą", "a"); + translitChars.put("õ", "o"); + translitChars.put("ɻ", "r"); + translitChars.put("ꝍ", "o"); + translitChars.put("ǟ", "a"); + translitChars.put("ȴ", "l"); + translitChars.put("ʂ", "s"); + translitChars.put("fl", "fl"); + translitChars.put("ȉ", "i"); + translitChars.put("ⱻ", "e"); + translitChars.put("ṉ", "n"); + translitChars.put("ï", "i"); + translitChars.put("ñ", "n"); + translitChars.put("ᴉ", "i"); + translitChars.put("ʇ", "t"); + translitChars.put("ẓ", "z"); + translitChars.put("ỷ", "y"); + translitChars.put("ȳ", "y"); + translitChars.put("ṩ", "s"); + translitChars.put("ɽ", "r"); + translitChars.put("ĝ", "g"); + translitChars.put("в", "v"); + translitChars.put("ᴝ", "u"); + translitChars.put("ḳ", "k"); + translitChars.put("ꝫ", "et"); + translitChars.put("ī", "i"); + translitChars.put("ť", "t"); + translitChars.put("ꜿ", "c"); + translitChars.put("ʟ", "l"); + translitChars.put("ꜹ", "av"); + translitChars.put("û", "u"); + translitChars.put("æ", "ae"); + translitChars.put("и", "i"); + translitChars.put("ă", "a"); + translitChars.put("ǘ", "u"); + translitChars.put("ꞅ", "s"); + translitChars.put("ᵣ", "r"); + translitChars.put("ᴀ", "a"); + translitChars.put("ƃ", "b"); + translitChars.put("ḩ", "h"); + translitChars.put("ṧ", "s"); + translitChars.put("ₑ", "e"); + translitChars.put("ʜ", "h"); + translitChars.put("ẋ", "x"); + translitChars.put("ꝅ", "k"); + translitChars.put("ḋ", "d"); + translitChars.put("ƣ", "oi"); + translitChars.put("ꝑ", "p"); + translitChars.put("ħ", "h"); + translitChars.put("ⱴ", "v"); + translitChars.put("ẇ", "w"); + translitChars.put("ǹ", "n"); + translitChars.put("ɯ", "m"); + translitChars.put("ɡ", "g"); + translitChars.put("ɴ", "n"); + translitChars.put("ᴘ", "p"); + translitChars.put("ᵥ", "v"); + translitChars.put("ū", "u"); + translitChars.put("ḃ", "b"); + translitChars.put("ṗ", "p"); + translitChars.put("ь", ""); + translitChars.put("å", "a"); + translitChars.put("ɕ", "c"); + translitChars.put("ọ", "o"); + translitChars.put("ắ", "a"); + translitChars.put("ƒ", "f"); + translitChars.put("ǣ", "ae"); + translitChars.put("ꝡ", "vy"); + translitChars.put("ff", "ff"); + translitChars.put("ᶉ", "r"); + translitChars.put("ô", "o"); + translitChars.put("ǿ", "o"); + translitChars.put("ṳ", "u"); + translitChars.put("ȥ", "z"); + translitChars.put("ḟ", "f"); + translitChars.put("ḓ", "d"); + translitChars.put("ȇ", "e"); + translitChars.put("ȕ", "u"); + translitChars.put("п", "p"); + translitChars.put("ȵ", "n"); + translitChars.put("ʠ", "q"); + translitChars.put("ấ", "a"); + translitChars.put("ǩ", "k"); + translitChars.put("ĩ", "i"); + translitChars.put("ṵ", "u"); + translitChars.put("ŧ", "t"); + translitChars.put("ɾ", "r"); + translitChars.put("ƙ", "k"); + translitChars.put("ṫ", "t"); + translitChars.put("ꝗ", "q"); + translitChars.put("ậ", "a"); + translitChars.put("н", "n"); + translitChars.put("ʄ", "j"); + translitChars.put("ƚ", "l"); + translitChars.put("ᶂ", "f"); + translitChars.put("д", "d"); + translitChars.put("ᵴ", "s"); + translitChars.put("ꞃ", "r"); + translitChars.put("ᶌ", "v"); + translitChars.put("ɵ", "o"); + translitChars.put("ḉ", "c"); + translitChars.put("ᵤ", "u"); + translitChars.put("ẑ", "z"); + translitChars.put("ṹ", "u"); + translitChars.put("ň", "n"); + translitChars.put("ʍ", "w"); + translitChars.put("ầ", "a"); + translitChars.put("lj", "lj"); + translitChars.put("ɓ", "b"); + translitChars.put("ɼ", "r"); + translitChars.put("ò", "o"); + translitChars.put("ẘ", "w"); + translitChars.put("ɗ", "d"); + translitChars.put("ꜽ", "ay"); + translitChars.put("ư", "u"); + translitChars.put("ᶀ", "b"); + translitChars.put("ǜ", "u"); + translitChars.put("ẹ", "e"); + translitChars.put("ǡ", "a"); + translitChars.put("ɥ", "h"); + translitChars.put("ṏ", "o"); + translitChars.put("ǔ", "u"); + translitChars.put("ʎ", "y"); + translitChars.put("ȱ", "o"); + translitChars.put("ệ", "e"); + translitChars.put("ế", "e"); + translitChars.put("ĭ", "i"); + translitChars.put("ⱸ", "e"); + translitChars.put("ṯ", "t"); + translitChars.put("ᶑ", "d"); + translitChars.put("ḧ", "h"); + translitChars.put("ṥ", "s"); + translitChars.put("ë", "e"); + translitChars.put("ᴍ", "m"); + translitChars.put("ö", "o"); + translitChars.put("é", "e"); + translitChars.put("ı", "i"); + translitChars.put("ď", "d"); + translitChars.put("ᵯ", "m"); + translitChars.put("ỵ", "y"); + translitChars.put("я", "ya"); + translitChars.put("ŵ", "w"); + translitChars.put("ề", "e"); + translitChars.put("ứ", "u"); + translitChars.put("ƶ", "z"); + translitChars.put("ĵ", "j"); + translitChars.put("ḍ", "d"); + translitChars.put("ŭ", "u"); + translitChars.put("ʝ", "j"); + translitChars.put("ж", "zh"); + translitChars.put("ê", "e"); + translitChars.put("ǚ", "u"); + translitChars.put("ġ", "g"); + translitChars.put("ṙ", "r"); + translitChars.put("ƞ", "n"); + translitChars.put("ъ", ""); + translitChars.put("ḗ", "e"); + translitChars.put("ẝ", "s"); + translitChars.put("ᶁ", "d"); + translitChars.put("ķ", "k"); + translitChars.put("ᴂ", "ae"); + translitChars.put("ɘ", "e"); + translitChars.put("ợ", "o"); + translitChars.put("ḿ", "m"); + translitChars.put("ꜰ", "f"); + translitChars.put("а", "a"); + translitChars.put("ẵ", "a"); + translitChars.put("ꝏ", "oo"); + translitChars.put("ᶆ", "m"); + translitChars.put("ᵽ", "p"); + translitChars.put("ц", "ts"); + translitChars.put("ữ", "u"); + translitChars.put("ⱪ", "k"); + translitChars.put("ḥ", "h"); + translitChars.put("ţ", "t"); + translitChars.put("ᵱ", "p"); + translitChars.put("ṁ", "m"); + translitChars.put("á", "a"); + translitChars.put("ᴎ", "n"); + translitChars.put("ꝟ", "v"); + translitChars.put("è", "e"); + translitChars.put("ᶎ", "z"); + translitChars.put("ꝺ", "d"); + translitChars.put("ᶈ", "p"); + translitChars.put("м", "m"); + translitChars.put("ɫ", "l"); + translitChars.put("ᴢ", "z"); + translitChars.put("ɱ", "m"); + translitChars.put("ṝ", "r"); + translitChars.put("ṽ", "v"); + translitChars.put("ũ", "u"); + translitChars.put("ß", "ss"); + translitChars.put("т", "t"); + translitChars.put("ĥ", "h"); + translitChars.put("ᵵ", "t"); + translitChars.put("ʐ", "z"); + translitChars.put("ṟ", "r"); + translitChars.put("ɲ", "n"); + translitChars.put("à", "a"); + translitChars.put("ẙ", "y"); + translitChars.put("ỳ", "y"); + translitChars.put("ᴔ", "oe"); + translitChars.put("ы", "i"); + translitChars.put("ₓ", "x"); + translitChars.put("ȗ", "u"); + translitChars.put("ⱼ", "j"); + translitChars.put("ẫ", "a"); + translitChars.put("ʑ", "z"); + translitChars.put("ẛ", "s"); + translitChars.put("ḭ", "i"); + translitChars.put("ꜵ", "ao"); + translitChars.put("ɀ", "z"); + translitChars.put("ÿ", "y"); + translitChars.put("ǝ", "e"); + translitChars.put("ǭ", "o"); + translitChars.put("ᴅ", "d"); + translitChars.put("ᶅ", "l"); + translitChars.put("ù", "u"); + translitChars.put("ạ", "a"); + translitChars.put("ḅ", "b"); + translitChars.put("ụ", "u"); + translitChars.put("к", "k"); + translitChars.put("ằ", "a"); + translitChars.put("ᴛ", "t"); + translitChars.put("ƴ", "y"); + translitChars.put("ⱦ", "t"); + translitChars.put("з", "z"); + translitChars.put("ⱡ", "l"); + translitChars.put("ȷ", "j"); + translitChars.put("ᵶ", "z"); + translitChars.put("ḫ", "h"); + translitChars.put("ⱳ", "w"); + translitChars.put("ḵ", "k"); + translitChars.put("ờ", "o"); + translitChars.put("î", "i"); + translitChars.put("ģ", "g"); + translitChars.put("ȅ", "e"); + translitChars.put("ȧ", "a"); + translitChars.put("ẳ", "a"); + translitChars.put("щ", "sch"); + translitChars.put("ɋ", "q"); + translitChars.put("ṭ", "t"); + translitChars.put("ꝸ", "um"); + translitChars.put("ᴄ", "c"); + translitChars.put("ẍ", "x"); + translitChars.put("ủ", "u"); + translitChars.put("ỉ", "i"); + translitChars.put("ᴚ", "r"); + translitChars.put("ś", "s"); + translitChars.put("ꝋ", "o"); + translitChars.put("ỹ", "y"); + translitChars.put("ṡ", "s"); + translitChars.put("nj", "nj"); + translitChars.put("ȁ", "a"); + translitChars.put("ẗ", "t"); + translitChars.put("ĺ", "l"); + translitChars.put("ž", "z"); + translitChars.put("ᵺ", "th"); + translitChars.put("ƌ", "d"); + translitChars.put("ș", "s"); + translitChars.put("š", "s"); + translitChars.put("ᶙ", "u"); + translitChars.put("ẽ", "e"); + translitChars.put("ẜ", "s"); + translitChars.put("ɇ", "e"); + translitChars.put("ṷ", "u"); + translitChars.put("ố", "o"); + translitChars.put("ȿ", "s"); + translitChars.put("ᴠ", "v"); + translitChars.put("ꝭ", "is"); + translitChars.put("ᴏ", "o"); + translitChars.put("ɛ", "e"); + translitChars.put("ǻ", "a"); + translitChars.put("ffl", "ffl"); + translitChars.put("ⱺ", "o"); + translitChars.put("ȋ", "i"); + translitChars.put("ᵫ", "ue"); + translitChars.put("ȡ", "d"); + translitChars.put("ⱬ", "z"); + translitChars.put("ẁ", "w"); + translitChars.put("ᶏ", "a"); + translitChars.put("ꞇ", "t"); + translitChars.put("ğ", "g"); + translitChars.put("ɳ", "n"); + translitChars.put("ʛ", "g"); + translitChars.put("ᴜ", "u"); + translitChars.put("ф", "f"); + translitChars.put("ẩ", "a"); + translitChars.put("ṅ", "n"); + translitChars.put("ɨ", "i"); + translitChars.put("ᴙ", "r"); + translitChars.put("ǎ", "a"); + translitChars.put("ſ", "s"); + translitChars.put("у", "u"); + translitChars.put("ȫ", "o"); + translitChars.put("ɿ", "r"); + translitChars.put("ƭ", "t"); + translitChars.put("ḯ", "i"); + translitChars.put("ǽ", "ae"); + translitChars.put("ⱱ", "v"); + translitChars.put("ɶ", "oe"); + translitChars.put("ṃ", "m"); + translitChars.put("ż", "z"); + translitChars.put("ĕ", "e"); + translitChars.put("ꜻ", "av"); + translitChars.put("ở", "o"); + translitChars.put("ễ", "e"); + translitChars.put("ɬ", "l"); + translitChars.put("ị", "i"); + translitChars.put("ᵭ", "d"); + translitChars.put("st", "st"); + translitChars.put("ḷ", "l"); + translitChars.put("ŕ", "r"); + translitChars.put("ᴕ", "ou"); + translitChars.put("ʈ", "t"); + translitChars.put("ā", "a"); + translitChars.put("э", "e"); + translitChars.put("ḙ", "e"); + translitChars.put("ᴑ", "o"); + translitChars.put("ç", "c"); + translitChars.put("ᶊ", "s"); + translitChars.put("ặ", "a"); + translitChars.put("ų", "u"); + translitChars.put("ả", "a"); + translitChars.put("ǥ", "g"); + translitChars.put("р", "r"); + translitChars.put("ꝁ", "k"); + translitChars.put("ẕ", "z"); + translitChars.put("ŝ", "s"); + translitChars.put("ḕ", "e"); + translitChars.put("ɠ", "g"); + translitChars.put("ꝉ", "l"); + translitChars.put("ꝼ", "f"); + translitChars.put("ᶍ", "x"); + translitChars.put("х", "h"); + translitChars.put("ǒ", "o"); + translitChars.put("ę", "e"); + translitChars.put("ổ", "o"); + translitChars.put("ƫ", "t"); + translitChars.put("ǫ", "o"); + translitChars.put("i̇", "i"); + translitChars.put("ṇ", "n"); + translitChars.put("ć", "c"); + translitChars.put("ᵷ", "g"); + translitChars.put("ẅ", "w"); + translitChars.put("ḑ", "d"); + translitChars.put("ḹ", "l"); + translitChars.put("ч", "ch"); + translitChars.put("œ", "oe"); + translitChars.put("ᵳ", "r"); + translitChars.put("ļ", "l"); + translitChars.put("ȑ", "r"); + translitChars.put("ȭ", "o"); + translitChars.put("ᵰ", "n"); + translitChars.put("ᴁ", "ae"); + translitChars.put("ŀ", "l"); + translitChars.put("ä", "a"); + translitChars.put("ƥ", "p"); + translitChars.put("ỏ", "o"); + translitChars.put("į", "i"); + translitChars.put("ȓ", "r"); + translitChars.put("dž", "dz"); + translitChars.put("ḡ", "g"); + translitChars.put("ṻ", "u"); + translitChars.put("ō", "o"); + translitChars.put("ľ", "l"); + translitChars.put("ẃ", "w"); + translitChars.put("ț", "t"); + translitChars.put("ń", "n"); + translitChars.put("ɍ", "r"); + translitChars.put("ȃ", "a"); + translitChars.put("ü", "u"); + translitChars.put("ꞁ", "l"); + translitChars.put("ᴐ", "o"); + translitChars.put("ớ", "o"); + translitChars.put("ᴃ", "b"); + translitChars.put("ɹ", "r"); + translitChars.put("ᵲ", "r"); + translitChars.put("ʏ", "y"); + translitChars.put("ᵮ", "f"); + translitChars.put("ⱨ", "h"); + translitChars.put("ŏ", "o"); + translitChars.put("ú", "u"); + translitChars.put("ṛ", "r"); + translitChars.put("ʮ", "h"); + translitChars.put("ó", "o"); + translitChars.put("ů", "u"); + translitChars.put("ỡ", "o"); + translitChars.put("ṕ", "p"); + translitChars.put("ᶖ", "i"); + translitChars.put("ự", "u"); + translitChars.put("ã", "a"); + translitChars.put("ᵢ", "i"); + translitChars.put("ṱ", "t"); + translitChars.put("ể", "e"); + translitChars.put("ử", "u"); + translitChars.put("í", "i"); + translitChars.put("ɔ", "o"); + translitChars.put("с", "s"); + translitChars.put("й", "i"); + translitChars.put("ɺ", "r"); + translitChars.put("ɢ", "g"); + translitChars.put("ř", "r"); + translitChars.put("ẖ", "h"); + translitChars.put("ű", "u"); + translitChars.put("ȍ", "o"); + translitChars.put("ш", "sh"); + translitChars.put("ḻ", "l"); + translitChars.put("ḣ", "h"); + translitChars.put("ȶ", "t"); + translitChars.put("ņ", "n"); + translitChars.put("ᶒ", "e"); + translitChars.put("ì", "i"); + translitChars.put("ẉ", "w"); + translitChars.put("б", "b"); + translitChars.put("ē", "e"); + translitChars.put("ᴇ", "e"); + translitChars.put("ł", "l"); + translitChars.put("ộ", "o"); + translitChars.put("ɭ", "l"); + translitChars.put("ẏ", "y"); + translitChars.put("ᴊ", "j"); + translitChars.put("ḱ", "k"); + translitChars.put("ṿ", "v"); + translitChars.put("ȩ", "e"); + translitChars.put("â", "a"); + translitChars.put("ş", "s"); + translitChars.put("ŗ", "r"); + translitChars.put("ʋ", "v"); + translitChars.put("ₐ", "a"); + translitChars.put("ↄ", "c"); + translitChars.put("ᶓ", "e"); + translitChars.put("ɰ", "m"); + translitChars.put("е", "e"); + translitChars.put("ᴡ", "w"); + translitChars.put("ȏ", "o"); + translitChars.put("č", "c"); + translitChars.put("ǵ", "g"); + translitChars.put("ĉ", "c"); + translitChars.put("ю", "yu"); + translitChars.put("ᶗ", "o"); + translitChars.put("ꝃ", "k"); + translitChars.put("ꝙ", "q"); + translitChars.put("г", "g"); + translitChars.put("ṑ", "o"); + translitChars.put("ꜱ", "s"); + translitChars.put("ṓ", "o"); + translitChars.put("ȟ", "h"); + translitChars.put("ő", "o"); + translitChars.put("ꜩ", "tz"); + translitChars.put("ẻ", "e"); + translitChars.put("о", "o"); + } + StringBuilder dst = new StringBuilder(src.length()); + int len = src.length(); + for (int a = 0; a < len; a++) { + String ch = src.substring(a, a + 1); + String tch = translitChars.get(ch); + if (tch != null) { + dst.append(tch); + } else { + dst.append(ch); + } + } + return dst.toString(); + } + + abstract public static class PluralRules { + abstract int quantityForNumber(int n); + } + + public static class PluralRules_Zero extends PluralRules { + public int quantityForNumber(int count) { + if (count == 0 || count == 1) { + return QUANTITY_ONE; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_Welsh extends PluralRules { + public int quantityForNumber(int count) { + if (count == 0) { + return QUANTITY_ZERO; + } else if (count == 1) { + return QUANTITY_ONE; + } else if (count == 2) { + return QUANTITY_TWO; + } else if (count == 3) { + return QUANTITY_FEW; + } else if (count == 6) { + return QUANTITY_MANY; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_Two extends PluralRules { + public int quantityForNumber(int count) { + if (count == 1) { + return QUANTITY_ONE; + } else if (count == 2) { + return QUANTITY_TWO; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_Tachelhit extends PluralRules { + public int quantityForNumber(int count) { + if (count >= 0 && count <= 1) { + return QUANTITY_ONE; + } else if (count >= 2 && count <= 10) { + return QUANTITY_FEW; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_Slovenian extends PluralRules { + public int quantityForNumber(int count) { + int rem100 = count % 100; + if (rem100 == 1) { + return QUANTITY_ONE; + } else if (rem100 == 2) { + return QUANTITY_TWO; + } else if (rem100 >= 3 && rem100 <= 4) { + return QUANTITY_FEW; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_Romanian extends PluralRules { + public int quantityForNumber(int count) { + int rem100 = count % 100; + if (count == 1) { + return QUANTITY_ONE; + } else if ((count == 0 || (rem100 >= 1 && rem100 <= 19))) { + return QUANTITY_FEW; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_Polish extends PluralRules { + public int quantityForNumber(int count) { + int rem100 = count % 100; + int rem10 = count % 10; + if (count == 1) { + return QUANTITY_ONE; + } else if (rem10 >= 2 && rem10 <= 4 && !(rem100 >= 12 && rem100 <= 14) && !(rem100 >= 22 && rem100 <= 24)) { + return QUANTITY_FEW; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_One extends PluralRules { + public int quantityForNumber(int count) { + return count == 1 ? QUANTITY_ONE : QUANTITY_OTHER; + } + } + + public static class PluralRules_None extends PluralRules { + public int quantityForNumber(int count) { + return QUANTITY_OTHER; + } + } + + public static class PluralRules_Maltese extends PluralRules { + public int quantityForNumber(int count) { + int rem100 = count % 100; + if (count == 1) { + return QUANTITY_ONE; + } else if (count == 0 || (rem100 >= 2 && rem100 <= 10)) { + return QUANTITY_FEW; + } else if (rem100 >= 11 && rem100 <= 19) { + return QUANTITY_MANY; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_Macedonian extends PluralRules { + public int quantityForNumber(int count) { + if (count % 10 == 1 && count != 11) { + return QUANTITY_ONE; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_Lithuanian extends PluralRules { + public int quantityForNumber(int count) { + int rem100 = count % 100; + int rem10 = count % 10; + if (rem10 == 1 && !(rem100 >= 11 && rem100 <= 19)) { + return QUANTITY_ONE; + } else if (rem10 >= 2 && rem10 <= 9 && !(rem100 >= 11 && rem100 <= 19)) { + return QUANTITY_FEW; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_Latvian extends PluralRules { + public int quantityForNumber(int count) { + if (count == 0) { + return QUANTITY_ZERO; + } else if (count % 10 == 1 && count % 100 != 11) { + return QUANTITY_ONE; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_Langi extends PluralRules { + public int quantityForNumber(int count) { + if (count == 0) { + return QUANTITY_ZERO; + } else if (count > 0 && count < 2) { + return QUANTITY_ONE; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_French extends PluralRules { + public int quantityForNumber(int count) { + if (count >= 0 && count < 2) { + return QUANTITY_ONE; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_Czech extends PluralRules { + public int quantityForNumber(int count) { + if (count == 1) { + return QUANTITY_ONE; + } else if (count >= 2 && count <= 4) { + return QUANTITY_FEW; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_Breton extends PluralRules { + public int quantityForNumber(int count) { + if (count == 0) { + return QUANTITY_ZERO; + } else if (count == 1) { + return QUANTITY_ONE; + } else if (count == 2) { + return QUANTITY_TWO; + } else if (count == 3) { + return QUANTITY_FEW; + } else if (count == 6) { + return QUANTITY_MANY; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_Balkan extends PluralRules { + public int quantityForNumber(int count) { + int rem100 = count % 100; + int rem10 = count % 10; + if (rem10 == 1 && rem100 != 11) { + return QUANTITY_ONE; + } else if (rem10 >= 2 && rem10 <= 4 && !(rem100 >= 12 && rem100 <= 14)) { + return QUANTITY_FEW; + } else if ((rem10 == 0 || (rem10 >= 5 && rem10 <= 9) || (rem100 >= 11 && rem100 <= 14))) { + return QUANTITY_MANY; + } else { + return QUANTITY_OTHER; + } + } + } + + public static class PluralRules_Arabic extends PluralRules { + public int quantityForNumber(int count) { + int rem100 = count % 100; + if (count == 0) { + return QUANTITY_ZERO; + } else if (count == 1) { + return QUANTITY_ONE; + } else if (count == 2) { + return QUANTITY_TWO; + } else if (rem100 >= 3 && rem100 <= 10) { + return QUANTITY_FEW; + } else if (rem100 >= 11 && rem100 <= 99) { + return QUANTITY_MANY; + } else { + return QUANTITY_OTHER; + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/LruCache.java b/TMessagesProj/src/main/java/org/telegram/messenger/LruCache.java new file mode 100644 index 00000000..0b894cf2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/LruCache.java @@ -0,0 +1,253 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.graphics.drawable.BitmapDrawable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; + +/** + * Static library version of {@link android.util.LruCache}. Used to write apps + * that run on API levels prior to 12. When running on API level 12 or above, + * this implementation is still used; it does not try to switch to the + * framework's implementation. See the framework SDK documentation for a class + * overview. + */ +public class LruCache { + private final LinkedHashMap map; + private final LinkedHashMap> mapFilters; + + /** Size of this cache in units. Not necessarily the number of elements. */ + private int size; + private int maxSize; + + /** + * @param maxSize for caches that do not override {@link #sizeOf}, this is + * the maximum number of entries in the cache. For all other caches, + * this is the maximum sum of the sizes of the entries in this cache. + */ + public LruCache(int maxSize) { + if (maxSize <= 0) { + throw new IllegalArgumentException("maxSize <= 0"); + } + this.maxSize = maxSize; + this.map = new LinkedHashMap<>(0, 0.75f, true); + this.mapFilters = new LinkedHashMap<>(); + } + + /** + * Returns the value for {@code key} if it exists in the cache or can be + * created by {@code #create}. If a value was returned, it is moved to the + * head of the queue. This returns null if a value is not cached and cannot + * be created. + */ + public final BitmapDrawable get(String key) { + if (key == null) { + throw new NullPointerException("key == null"); + } + + BitmapDrawable mapValue; + synchronized (this) { + mapValue = map.get(key); + if (mapValue != null) { + return mapValue; + } + } + return null; + } + + public ArrayList getFilterKeys(String key) { + ArrayList arr = mapFilters.get(key); + if (arr != null) { + return new ArrayList<>(arr); + } + return null; + } + + /** + * Caches {@code value} for {@code key}. The value is moved to the head of + * the queue. + * + * @return the previous value mapped by {@code key}. + */ + public BitmapDrawable put(String key, BitmapDrawable value) { + if (key == null || value == null) { + throw new NullPointerException("key == null || value == null"); + } + + BitmapDrawable previous; + synchronized (this) { + size += safeSizeOf(key, value); + previous = map.put(key, value); + if (previous != null) { + size -= safeSizeOf(key, previous); + } + } + + String[] args = key.split("@"); + if (args.length > 1) { + ArrayList arr = mapFilters.get(args[0]); + if (arr == null) { + arr = new ArrayList<>(); + mapFilters.put(args[0], arr); + } + if (!arr.contains(args[1])) { + arr.add(args[1]); + } + } + + if (previous != null) { + entryRemoved(false, key, previous, value); + } + + trimToSize(maxSize, key); + return previous; + } + + /** + * @param maxSize the maximum size of the cache before returning. May be -1 + * to evict even 0-sized elements. + */ + private void trimToSize(int maxSize, String justAdded) { + synchronized (this) { + Iterator> iterator = map.entrySet().iterator(); + while (iterator.hasNext()) { + if (size <= maxSize || map.isEmpty()) { + break; + } + HashMap.Entry entry = iterator.next(); + + String key = entry.getKey(); + if (justAdded != null && justAdded.equals(key)) { + continue; + } + BitmapDrawable value = entry.getValue(); + size -= safeSizeOf(key, value); + iterator.remove(); + + String[] args = key.split("@"); + if (args.length > 1) { + ArrayList arr = mapFilters.get(args[0]); + if (arr != null) { + arr.remove(args[1]); + if (arr.isEmpty()) { + mapFilters.remove(args[0]); + } + } + } + + entryRemoved(true, key, value, null); + } + } + } + + /** + * Removes the entry for {@code key} if it exists. + * + * @return the previous value mapped by {@code key}. + */ + public final BitmapDrawable remove(String key) { + if (key == null) { + throw new NullPointerException("key == null"); + } + + BitmapDrawable previous; + synchronized (this) { + previous = map.remove(key); + if (previous != null) { + size -= safeSizeOf(key, previous); + } + } + + if (previous != null) { + String[] args = key.split("@"); + if (args.length > 1) { + ArrayList arr = mapFilters.get(args[0]); + if (arr != null) { + arr.remove(args[1]); + if (arr.isEmpty()) { + mapFilters.remove(args[0]); + } + } + } + + entryRemoved(false, key, previous, null); + } + + return previous; + } + + public boolean contains(String key){ + return map.containsKey(key); + } + + /** + * Called for entries that have been evicted or removed. This method is + * invoked when a value is evicted to make space, removed by a call to + * {@link #remove}, or replaced by a call to {@link #put}. The default + * implementation does nothing. + * + *

The method is called without synchronization: other threads may + * access the cache while this method is executing. + * + * @param evicted true if the entry is being removed to make space, false + * if the removal was caused by a {@link #put} or {@link #remove}. + * @param newValue the new value for {@code key}, if it exists. If non-null, + * this removal was caused by a {@link #put}. Otherwise it was caused by + * an eviction or a {@link #remove}. + */ + protected void entryRemoved(boolean evicted, String key, BitmapDrawable oldValue, BitmapDrawable newValue) {} + + private int safeSizeOf(String key, BitmapDrawable value) { + int result = sizeOf(key, value); + if (result < 0) { + throw new IllegalStateException("Negative size: " + key + "=" + value); + } + return result; + } + + /** + * Returns the size of the entry for {@code key} and {@code value} in + * user-defined units. The default implementation returns 1 so that size + * is the number of entries and max size is the maximum number of entries. + * + *

An entry's size must not change while it is in the cache. + */ + protected int sizeOf(String key, BitmapDrawable value) { + return 1; + } + + /** + * Clear the cache, calling {@link #entryRemoved} on each removed entry. + */ + public final void evictAll() { + trimToSize(-1, null); // -1 will evict 0-sized elements + } + + /** + * For caches that do not override {@link #sizeOf}, this returns the number + * of entries in the cache. For all other caches, this returns the sum of + * the sizes of the entries in this cache. + */ + public synchronized final int size() { + return size; + } + + /** + * For caches that do not override {@link #sizeOf}, this returns the maximum + * number of entries in the cache. For all other caches, this returns the + * maximum sum of the sizes of the entries in this cache. + */ + public synchronized final int maxSize() { + return maxSize; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java new file mode 100644 index 00000000..8c6e707a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java @@ -0,0 +1,3882 @@ +/* + * This is the source code of Telegram for Android v. 1.3.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.DownloadManager; +import android.app.ProgressDialog; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.database.ContentObserver; +import android.database.Cursor; +import android.graphics.BitmapFactory; +import android.graphics.Point; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.media.AudioFormat; +import android.media.AudioManager; +import android.media.AudioRecord; +import android.media.AudioTrack; +import android.media.MediaCodec; +import android.media.MediaCodecInfo; +import android.media.MediaCodecList; +import android.media.MediaExtractor; +import android.media.MediaFormat; +import android.media.MediaPlayer; +import android.media.MediaRecorder; +import android.net.ConnectivityManager; +import android.net.Uri; +import android.os.Build; +import android.os.Environment; +import android.os.ParcelFileDescriptor; +import android.os.PowerManager; +import android.os.Vibrator; +import android.provider.MediaStore; +import android.provider.OpenableColumns; +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyManager; +import android.util.Log; + +import org.telegram.messenger.audioinfo.AudioInfo; +import org.telegram.messenger.query.SharedMediaQuery; +import org.telegram.messenger.video.InputSurface; +import org.telegram.messenger.video.MP4Builder; +import org.telegram.messenger.video.Mp4Movie; +import org.telegram.messenger.video.OutputSurface; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.PhotoViewer; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.lang.ref.WeakReference; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.Semaphore; + +public class MediaController implements AudioManager.OnAudioFocusChangeListener, NotificationCenter.NotificationCenterDelegate, SensorEventListener { + + public static String iFilter = "*"; + + private native int startRecord(String path); + private native int writeFrame(ByteBuffer frame, int len); + private native void stopRecord(); + private native int openOpusFile(String path); + private native int seekOpusFile(float position); + private native int isOpusFile(String path); + private native void closeOpusFile(); + private native void readOpusFile(ByteBuffer buffer, int capacity, int[] args); + private native long getTotalPcmDuration(); + public native byte[] getWaveform(String path); + public native byte[] getWaveform2(short[] array, int length); + + public static int[] readArgs = new int[3]; + + public interface FileDownloadProgressListener { + void onFailedDownload(String fileName); + void onSuccessDownload(String fileName); + void onProgressDownload(String fileName, float progress); + void onProgressUpload(String fileName, float progress, boolean isEncrypted); + int getObserverTag(); + } + + private class AudioBuffer { + public AudioBuffer(int capacity) { + buffer = ByteBuffer.allocateDirect(capacity); + bufferBytes = new byte[capacity]; + } + + ByteBuffer buffer; + byte[] bufferBytes; + int size; + int finished; + long pcmOffset; + } + + private static final String[] projectionPhotos = { + MediaStore.Images.Media._ID, + MediaStore.Images.Media.BUCKET_ID, + MediaStore.Images.Media.BUCKET_DISPLAY_NAME, + MediaStore.Images.Media.DATA, + MediaStore.Images.Media.DATE_TAKEN, + MediaStore.Images.Media.ORIENTATION + }; + + private static final String[] projectionVideo = { + MediaStore.Video.Media._ID, + MediaStore.Video.Media.BUCKET_ID, + MediaStore.Video.Media.BUCKET_DISPLAY_NAME, + MediaStore.Video.Media.DATA, + MediaStore.Video.Media.DATE_TAKEN + }; + + public static class AudioEntry { + public long id; + public String author; + public String title; + public String genre; + public int duration; + public String path; + public MessageObject messageObject; + } + + public static class AlbumEntry { + public int bucketId; + public String bucketName; + public PhotoEntry coverPhoto; + public ArrayList photos = new ArrayList<>(); + public HashMap photosByIds = new HashMap<>(); + public boolean isVideo; + + public AlbumEntry(int bucketId, String bucketName, PhotoEntry coverPhoto, boolean isVideo) { + this.bucketId = bucketId; + this.bucketName = bucketName; + this.coverPhoto = coverPhoto; + this.isVideo = isVideo; + } + + public void addPhoto(PhotoEntry photoEntry) { + photos.add(photoEntry); + photosByIds.put(photoEntry.imageId, photoEntry); + } + } + + public static class PhotoEntry { + public int bucketId; + public int imageId; + public long dateTaken; + public String path; + public int orientation; + public String thumbPath; + public String imagePath; + public boolean isVideo; + public CharSequence caption; + + public PhotoEntry(int bucketId, int imageId, long dateTaken, String path, int orientation, boolean isVideo) { + this.bucketId = bucketId; + this.imageId = imageId; + this.dateTaken = dateTaken; + this.path = path; + this.orientation = orientation; + this.isVideo = isVideo; + } + } + + public static class SearchImage { + public String id; + public String imageUrl; + public String thumbUrl; + public String localUrl; + public int width; + public int height; + public int size; + public int type; + public int date; + public String thumbPath; + public String imagePath; + public CharSequence caption; + public TLRPC.Document document; + } + + public final static String MIME_TYPE = "video/avc"; + private final static int PROCESSOR_TYPE_OTHER = 0; + private final static int PROCESSOR_TYPE_QCOM = 1; + private final static int PROCESSOR_TYPE_INTEL = 2; + private final static int PROCESSOR_TYPE_MTK = 3; + private final static int PROCESSOR_TYPE_SEC = 4; + private final static int PROCESSOR_TYPE_TI = 5; + private final Object videoConvertSync = new Object(); + + private HashMap typingTimes = new HashMap<>(); + + private SensorManager sensorManager; + private boolean ignoreProximity; + private PowerManager.WakeLock proximityWakeLock; + private Sensor proximitySensor; + private Sensor accelerometerSensor; + private Sensor linearSensor; + private Sensor gravitySensor; + private boolean raiseToEarRecord; + private ChatActivity raiseChat; + private boolean accelerometerVertical; + private int raisedToTop; + private int raisedToBack; + private int countLess; + private long timeSinceRaise; + private long lastTimestamp = 0; + private boolean proximityTouched; + private boolean proximityHasDifferentValues; + private float lastProximityValue = -100; + private boolean useFrontSpeaker; + private boolean inputFieldHasText; + private boolean allowStartRecord; + private boolean ignoreOnPause; + private boolean sensorsStarted; + private float previousAccValue; + private float[] gravity = new float[3]; + private float[] gravityFast = new float[3]; + private float[] linearAcceleration = new float[3]; + + private int hasAudioFocus; + private boolean callInProgress; + + private ArrayList videoConvertQueue = new ArrayList<>(); + private final Object videoQueueSync = new Object(); + private boolean cancelCurrentVideoConversion = false; + private boolean videoConvertFirstWrite = true; + private HashMap generatingWaveform = new HashMap<>(); + + private boolean voiceMessagesPlaylistUnread; + private ArrayList voiceMessagesPlaylist; + private HashMap voiceMessagesPlaylistMap; + + public static final int AUTODOWNLOAD_MASK_PHOTO = 1; + public static final int AUTODOWNLOAD_MASK_AUDIO = 2; + public static final int AUTODOWNLOAD_MASK_VIDEO = 4; + public static final int AUTODOWNLOAD_MASK_DOCUMENT = 8; + public static final int AUTODOWNLOAD_MASK_MUSIC = 16; + public static final int AUTODOWNLOAD_MASK_GIF = 32; + public int mobileDataDownloadMask = 0; + public int wifiDownloadMask = 0; + public int roamingDownloadMask = 0; + private int lastCheckMask = 0; + private ArrayList photoDownloadQueue = new ArrayList<>(); + private ArrayList audioDownloadQueue = new ArrayList<>(); + private ArrayList documentDownloadQueue = new ArrayList<>(); + private ArrayList musicDownloadQueue = new ArrayList<>(); + private ArrayList gifDownloadQueue = new ArrayList<>(); + private ArrayList videoDownloadQueue = new ArrayList<>(); + private HashMap downloadQueueKeys = new HashMap<>(); + + private boolean saveToGallery = true; + private boolean autoplayGifs = true; + private boolean raiseToSpeak = true; + private boolean customTabs = true; + private boolean directShare = true; + private boolean shuffleMusic; + private int repeatMode; + + private Runnable refreshGalleryRunnable; + public static AlbumEntry allPhotosAlbumEntry; + + private HashMap>> loadingFileObservers = new HashMap<>(); + private HashMap> loadingFileMessagesObservers = new HashMap<>(); + private HashMap observersByTag = new HashMap<>(); + private boolean listenerInProgress = false; + private HashMap addLaterArray = new HashMap<>(); + private ArrayList deleteLaterArray = new ArrayList<>(); + private int lastTag = 0; + + private boolean isPaused = false; + private MediaPlayer audioPlayer = null; + private AudioTrack audioTrackPlayer = null; + private int lastProgress = 0; + private MessageObject playingMessageObject; + private int playerBufferSize = 0; + private boolean decodingFinished = false; + private long currentTotalPcmDuration; + private long lastPlayPcm; + private int ignoreFirstProgress = 0; + private Timer progressTimer = null; + private final Object progressTimerSync = new Object(); + private int buffersWrited; + private ArrayList playlist = new ArrayList<>(); + private ArrayList shuffledPlaylist = new ArrayList<>(); + private int currentPlaylistNum; + private boolean downloadingCurrentMessage; + private boolean playMusicAgain; + private AudioInfo audioInfo; + + private AudioRecord audioRecorder = null; + private TLRPC.TL_document recordingAudio = null; + private File recordingAudioFile = null; + private long recordStartTime; + private long recordTimeCount; + private long recordDialogId; + private MessageObject recordReplyingMessageObject; + private boolean recordAsAdmin; + private DispatchQueue fileDecodingQueue; + private DispatchQueue playerQueue; + private ArrayList usedPlayerBuffers = new ArrayList<>(); + private ArrayList freePlayerBuffers = new ArrayList<>(); + private final Object playerSync = new Object(); + private final Object playerObjectSync = new Object(); + private short[] recordSamples = new short[1024]; + private long samplesCount; + + private final Object sync = new Object(); + + private ArrayList recordBuffers = new ArrayList<>(); + private ByteBuffer fileBuffer; + private int recordBufferSize; + private int sendAfterDone; + + private Runnable recordStartRunnable; + private DispatchQueue recordQueue; + private DispatchQueue fileEncodingQueue; + private Runnable recordRunnable = new Runnable() { + @Override + public void run() { + if (audioRecorder != null) { + ByteBuffer buffer; + if (!recordBuffers.isEmpty()) { + buffer = recordBuffers.get(0); + recordBuffers.remove(0); + } else { + buffer = ByteBuffer.allocateDirect(recordBufferSize); + buffer.order(ByteOrder.nativeOrder()); + } + buffer.rewind(); + int len = audioRecorder.read(buffer, buffer.capacity()); + if (len > 0) { + buffer.limit(len); + double sum = 0; + try { + long newSamplesCount = samplesCount + len / 2; + int currentPart = (int) (((double) samplesCount / (double) newSamplesCount) * recordSamples.length); + int newPart = recordSamples.length - currentPart; + float sampleStep; + if (currentPart != 0) { + sampleStep = (float) recordSamples.length / (float) currentPart; + float currentNum = 0; + for (int a = 0; a < currentPart; a++) { + recordSamples[a] = recordSamples[(int) currentNum]; + currentNum += sampleStep; + } + } + int currentNum = currentPart; + float nextNum = 0; + sampleStep = (float) len / 2 / (float) newPart; + for (int i = 0; i < len / 2; i++) { + short peak = buffer.getShort(); + sum += peak * peak; + if (i == (int) nextNum && currentNum < recordSamples.length) { + recordSamples[currentNum] = peak; + nextNum += sampleStep; + currentNum++; + } + } + samplesCount = newSamplesCount; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + buffer.position(0); + final double amplitude = Math.sqrt(sum / len / 2); + final ByteBuffer finalBuffer = buffer; + final boolean flush = len != buffer.capacity(); + if (len != 0) { + fileEncodingQueue.postRunnable(new Runnable() { + @Override + public void run() { + while (finalBuffer.hasRemaining()) { + int oldLimit = -1; + if (finalBuffer.remaining() > fileBuffer.remaining()) { + oldLimit = finalBuffer.limit(); + finalBuffer.limit(fileBuffer.remaining() + finalBuffer.position()); + } + fileBuffer.put(finalBuffer); + if (fileBuffer.position() == fileBuffer.limit() || flush) { + if (writeFrame(fileBuffer, !flush ? fileBuffer.limit() : finalBuffer.position()) != 0) { + fileBuffer.rewind(); + recordTimeCount += fileBuffer.limit() / 2 / 16; + } + } + if (oldLimit != -1) { + finalBuffer.limit(oldLimit); + } + } + recordQueue.postRunnable(new Runnable() { + @Override + public void run() { + recordBuffers.add(finalBuffer); + } + }); + } + }); + } + recordQueue.postRunnable(recordRunnable); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordProgressChanged, System.currentTimeMillis() - recordStartTime, amplitude); + } + }); + } else { + recordBuffers.add(buffer); + stopRecordingInternal(sendAfterDone); + } + } + } + }; + + private class InternalObserver extends ContentObserver { + public InternalObserver() { + super(null); + } + + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + processMediaObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI); + } + } + + private class ExternalObserver extends ContentObserver { + public ExternalObserver() { + super(null); + } + + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + processMediaObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI); + } + } + + private class GalleryObserverInternal extends ContentObserver { + public GalleryObserverInternal() { + super(null); + } + + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + if (refreshGalleryRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(refreshGalleryRunnable); + } + AndroidUtilities.runOnUIThread(refreshGalleryRunnable = new Runnable() { + @Override + public void run() { + refreshGalleryRunnable = null; + loadGalleryPhotosAlbums(0); + } + }, 2000); + } + } + + private class GalleryObserverExternal extends ContentObserver { + public GalleryObserverExternal() { + super(null); + } + + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + if (refreshGalleryRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(refreshGalleryRunnable); + } + AndroidUtilities.runOnUIThread(refreshGalleryRunnable = new Runnable() { + @Override + public void run() { + refreshGalleryRunnable = null; + loadGalleryPhotosAlbums(0); + } + }, 2000); + } + } + + private ExternalObserver externalObserver = null; + private InternalObserver internalObserver = null; + private long lastSecretChatEnterTime = 0; + private long lastSecretChatLeaveTime = 0; + private long lastMediaCheckTime = 0; + private TLRPC.EncryptedChat lastSecretChat = null; + private ArrayList lastSecretChatVisibleMessages = null; + private int startObserverToken = 0; + private StopMediaObserverRunnable stopMediaObserverRunnable = null; + + private final class StopMediaObserverRunnable implements Runnable { + public int currentObserverToken = 0; + + @Override + public void run() { + if (currentObserverToken == startObserverToken) { + try { + if (internalObserver != null) { + ApplicationLoader.applicationContext.getContentResolver().unregisterContentObserver(internalObserver); + internalObserver = null; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + if (externalObserver != null) { + ApplicationLoader.applicationContext.getContentResolver().unregisterContentObserver(externalObserver); + externalObserver = null; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + } + + private String[] mediaProjections = null; + + private static volatile MediaController Instance = null; + + public static MediaController getInstance() { + MediaController localInstance = Instance; + if (localInstance == null) { + synchronized (MediaController.class) { + localInstance = Instance; + if (localInstance == null) { + Instance = localInstance = new MediaController(); + } + } + } + return localInstance; + } + + public MediaController() { + try { + recordBufferSize = AudioRecord.getMinBufferSize(16000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); + if (recordBufferSize <= 0) { + recordBufferSize = 1280; + } + playerBufferSize = AudioTrack.getMinBufferSize(48000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT); + if (playerBufferSize <= 0) { + playerBufferSize = 3840; + } + for (int a = 0; a < 5; a++) { + ByteBuffer buffer = ByteBuffer.allocateDirect(4096); + buffer.order(ByteOrder.nativeOrder()); + recordBuffers.add(buffer); + } + for (int a = 0; a < 3; a++) { + freePlayerBuffers.add(new AudioBuffer(playerBufferSize)); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + sensorManager = (SensorManager) ApplicationLoader.applicationContext.getSystemService(Context.SENSOR_SERVICE); + linearSensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION); + gravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY); + if (linearSensor == null || gravitySensor == null) { + FileLog.e("tmessages", "gravity or linear sensor not found"); + accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); + linearSensor = null; + gravitySensor = null; + } + proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY); + PowerManager powerManager = (PowerManager) ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE); + proximityWakeLock = powerManager.newWakeLock(0x00000020, "proximity"); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + fileBuffer = ByteBuffer.allocateDirect(1920); + recordQueue = new DispatchQueue("recordQueue"); + recordQueue.setPriority(Thread.MAX_PRIORITY); + fileEncodingQueue = new DispatchQueue("fileEncodingQueue"); + fileEncodingQueue.setPriority(Thread.MAX_PRIORITY); + playerQueue = new DispatchQueue("playerQueue"); + fileDecodingQueue = new DispatchQueue("fileDecodingQueue"); + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + mobileDataDownloadMask = preferences.getInt("mobileDataDownloadMask", AUTODOWNLOAD_MASK_PHOTO | AUTODOWNLOAD_MASK_AUDIO | AUTODOWNLOAD_MASK_MUSIC | (Build.VERSION.SDK_INT >= 11 ? AUTODOWNLOAD_MASK_GIF : 0)); + wifiDownloadMask = preferences.getInt("wifiDownloadMask", AUTODOWNLOAD_MASK_PHOTO | AUTODOWNLOAD_MASK_AUDIO | AUTODOWNLOAD_MASK_MUSIC | (Build.VERSION.SDK_INT >= 11 ? AUTODOWNLOAD_MASK_GIF : 0)); + roamingDownloadMask = preferences.getInt("roamingDownloadMask", 0); + saveToGallery = preferences.getBoolean("save_gallery", false); + autoplayGifs = preferences.getBoolean("autoplay_gif", true) && Build.VERSION.SDK_INT >= 11; + raiseToSpeak = preferences.getBoolean("raise_to_speak", true) && Build.VERSION.SDK_INT >= 11; + customTabs = preferences.getBoolean("custom_tabs", true); + directShare = preferences.getBoolean("direct_share", true); + shuffleMusic = preferences.getBoolean("shuffleMusic", false); + repeatMode = preferences.getInt("repeatMode", 0); + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.FileDidFailedLoad); + NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.didReceivedNewMessages); + NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.messagesDeleted); + NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.FileDidLoaded); + NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.FileLoadProgressChanged); + NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.FileUploadProgressChanged); + NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.removeAllMessagesFromDialog); + NotificationCenter.getInstance().addObserver(MediaController.this, NotificationCenter.musicDidLoaded); + } + }); + + BroadcastReceiver networkStateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + checkAutodownloadSettings(); + } + }; + IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); + ApplicationLoader.applicationContext.registerReceiver(networkStateReceiver, filter); + + if (UserConfig.isClientActivated()) { + checkAutodownloadSettings(); + } + + if (Build.VERSION.SDK_INT >= 16) { + mediaProjections = new String[]{ + MediaStore.Images.ImageColumns.DATA, + MediaStore.Images.ImageColumns.DISPLAY_NAME, + MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, + MediaStore.Images.ImageColumns.DATE_TAKEN, + MediaStore.Images.ImageColumns.TITLE, + MediaStore.Images.ImageColumns.WIDTH, + MediaStore.Images.ImageColumns.HEIGHT + }; + } else { + mediaProjections = new String[]{ + MediaStore.Images.ImageColumns.DATA, + MediaStore.Images.ImageColumns.DISPLAY_NAME, + MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, + MediaStore.Images.ImageColumns.DATE_TAKEN, + MediaStore.Images.ImageColumns.TITLE + }; + } + + try { + ApplicationLoader.applicationContext.getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, new GalleryObserverExternal()); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + ApplicationLoader.applicationContext.getContentResolver().registerContentObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI, false, new GalleryObserverInternal()); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + try { + PhoneStateListener phoneStateListener = new PhoneStateListener() { + @Override + public void onCallStateChanged(int state, String incomingNumber) { + if (state == TelephonyManager.CALL_STATE_RINGING) { + if (MediaController.getInstance().isPlayingAudio(MediaController.getInstance().getPlayingMessageObject()) && !MediaController.getInstance().isAudioPaused()) { + MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject()); + } else if (recordStartRunnable != null || recordingAudio != null) { + stopRecording(2); + } + callInProgress = true; + } else if (state == TelephonyManager.CALL_STATE_IDLE) { + callInProgress = false; + } else if (state == TelephonyManager.CALL_STATE_OFFHOOK) { + callInProgress = true; + } + } + }; + TelephonyManager mgr = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); + if (mgr != null) { + mgr.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + @Override + public void onAudioFocusChange(int focusChange) { + if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { + if (MediaController.getInstance().isPlayingAudio(MediaController.getInstance().getPlayingMessageObject()) && !MediaController.getInstance().isAudioPaused()) { + MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject()); + } + hasAudioFocus = 0; + } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { + //MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject()); + } + } + + private void startProgressTimer(final MessageObject currentPlayingMessageObject) { + synchronized (progressTimerSync) { + if (progressTimer != null) { + try { + progressTimer.cancel(); + progressTimer = null; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + progressTimer = new Timer(); + progressTimer.schedule(new TimerTask() { + @Override + public void run() { + synchronized (sync) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (currentPlayingMessageObject != null && (audioPlayer != null || audioTrackPlayer != null) && !isPaused) { + try { + if (ignoreFirstProgress != 0) { + ignoreFirstProgress--; + return; + } + int progress; + float value; + if (audioPlayer != null) { + progress = audioPlayer.getCurrentPosition(); + value = (float) lastProgress / (float) audioPlayer.getDuration(); + if (progress <= lastProgress) { + return; + } + } else { + progress = (int) (lastPlayPcm / 48.0f); + value = (float) lastPlayPcm / (float) currentTotalPcmDuration; + if (progress == lastProgress) { + return; + } + } + lastProgress = progress; + currentPlayingMessageObject.audioProgress = value; + currentPlayingMessageObject.audioProgressSec = lastProgress / 1000; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioProgressDidChanged, currentPlayingMessageObject.getId(), value); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + }); + } + } + }, 0, 17); + } + } + + private void stopProgressTimer() { + synchronized (progressTimerSync) { + if (progressTimer != null) { + try { + progressTimer.cancel(); + progressTimer = null; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + } + + public void cleanup() { + cleanupPlayer(false, true); + audioInfo = null; + playMusicAgain = false; + photoDownloadQueue.clear(); + audioDownloadQueue.clear(); + documentDownloadQueue.clear(); + videoDownloadQueue.clear(); + musicDownloadQueue.clear(); + gifDownloadQueue.clear(); + downloadQueueKeys.clear(); + videoConvertQueue.clear(); + playlist.clear(); + shuffledPlaylist.clear(); + generatingWaveform.clear(); + typingTimes.clear(); + voiceMessagesPlaylist = null; + voiceMessagesPlaylistMap = null; + cancelVideoConvert(null); + } + + protected int getAutodownloadMask() { + int mask = 0; + if ((mobileDataDownloadMask & AUTODOWNLOAD_MASK_PHOTO) != 0 || (wifiDownloadMask & AUTODOWNLOAD_MASK_PHOTO) != 0 || (roamingDownloadMask & AUTODOWNLOAD_MASK_PHOTO) != 0) { + mask |= AUTODOWNLOAD_MASK_PHOTO; + } + if ((mobileDataDownloadMask & AUTODOWNLOAD_MASK_AUDIO) != 0 || (wifiDownloadMask & AUTODOWNLOAD_MASK_AUDIO) != 0 || (roamingDownloadMask & AUTODOWNLOAD_MASK_AUDIO) != 0) { + mask |= AUTODOWNLOAD_MASK_AUDIO; + } + if ((mobileDataDownloadMask & AUTODOWNLOAD_MASK_VIDEO) != 0 || (wifiDownloadMask & AUTODOWNLOAD_MASK_VIDEO) != 0 || (roamingDownloadMask & AUTODOWNLOAD_MASK_VIDEO) != 0) { + mask |= AUTODOWNLOAD_MASK_VIDEO; + } + if ((mobileDataDownloadMask & AUTODOWNLOAD_MASK_DOCUMENT) != 0 || (wifiDownloadMask & AUTODOWNLOAD_MASK_DOCUMENT) != 0 || (roamingDownloadMask & AUTODOWNLOAD_MASK_DOCUMENT) != 0) { + mask |= AUTODOWNLOAD_MASK_DOCUMENT; + } + if ((mobileDataDownloadMask & AUTODOWNLOAD_MASK_MUSIC) != 0 || (wifiDownloadMask & AUTODOWNLOAD_MASK_MUSIC) != 0 || (roamingDownloadMask & AUTODOWNLOAD_MASK_MUSIC) != 0) { + mask |= AUTODOWNLOAD_MASK_MUSIC; + } + if ((mobileDataDownloadMask & AUTODOWNLOAD_MASK_GIF) != 0 || (wifiDownloadMask & AUTODOWNLOAD_MASK_GIF) != 0 || (roamingDownloadMask & AUTODOWNLOAD_MASK_GIF) != 0) { + mask |= AUTODOWNLOAD_MASK_GIF; + } + return mask; + } + + public void checkAutodownloadSettings() { + int currentMask = getCurrentDownloadMask(); + if (currentMask == lastCheckMask) { + return; + } + lastCheckMask = currentMask; + if ((currentMask & AUTODOWNLOAD_MASK_PHOTO) != 0) { + if (photoDownloadQueue.isEmpty()) { + newDownloadObjectsAvailable(AUTODOWNLOAD_MASK_PHOTO); + } + } else { + for (int a = 0; a < photoDownloadQueue.size(); a++) { + DownloadObject downloadObject = photoDownloadQueue.get(a); + FileLoader.getInstance().cancelLoadFile((TLRPC.PhotoSize) downloadObject.object); + } + photoDownloadQueue.clear(); + } + if ((currentMask & AUTODOWNLOAD_MASK_AUDIO) != 0) { + if (audioDownloadQueue.isEmpty()) { + newDownloadObjectsAvailable(AUTODOWNLOAD_MASK_AUDIO); + } + } else { + for (int a = 0; a < audioDownloadQueue.size(); a++) { + DownloadObject downloadObject = audioDownloadQueue.get(a); + FileLoader.getInstance().cancelLoadFile((TLRPC.Document) downloadObject.object); + } + audioDownloadQueue.clear(); + } + if ((currentMask & AUTODOWNLOAD_MASK_DOCUMENT) != 0) { + if (documentDownloadQueue.isEmpty()) { + newDownloadObjectsAvailable(AUTODOWNLOAD_MASK_DOCUMENT); + } + } else { + for (int a = 0; a < documentDownloadQueue.size(); a++) { + DownloadObject downloadObject = documentDownloadQueue.get(a); + TLRPC.Document document = (TLRPC.Document) downloadObject.object; + FileLoader.getInstance().cancelLoadFile(document); + } + documentDownloadQueue.clear(); + } + if ((currentMask & AUTODOWNLOAD_MASK_VIDEO) != 0) { + if (videoDownloadQueue.isEmpty()) { + newDownloadObjectsAvailable(AUTODOWNLOAD_MASK_VIDEO); + } + } else { + for (int a = 0; a < videoDownloadQueue.size(); a++) { + DownloadObject downloadObject = videoDownloadQueue.get(a); + FileLoader.getInstance().cancelLoadFile((TLRPC.Document) downloadObject.object); + } + videoDownloadQueue.clear(); + } + if ((currentMask & AUTODOWNLOAD_MASK_MUSIC) != 0) { + if (musicDownloadQueue.isEmpty()) { + newDownloadObjectsAvailable(AUTODOWNLOAD_MASK_MUSIC); + } + } else { + for (int a = 0; a < musicDownloadQueue.size(); a++) { + DownloadObject downloadObject = musicDownloadQueue.get(a); + TLRPC.Document document = (TLRPC.Document) downloadObject.object; + FileLoader.getInstance().cancelLoadFile(document); + } + musicDownloadQueue.clear(); + } + if ((currentMask & AUTODOWNLOAD_MASK_GIF) != 0) { + if (gifDownloadQueue.isEmpty()) { + newDownloadObjectsAvailable(AUTODOWNLOAD_MASK_GIF); + } + } else { + for (int a = 0; a < gifDownloadQueue.size(); a++) { + DownloadObject downloadObject = gifDownloadQueue.get(a); + TLRPC.Document document = (TLRPC.Document) downloadObject.object; + FileLoader.getInstance().cancelLoadFile(document); + } + gifDownloadQueue.clear(); + } + + int mask = getAutodownloadMask(); + if (mask == 0) { + MessagesStorage.getInstance().clearDownloadQueue(0); + } else { + if ((mask & AUTODOWNLOAD_MASK_PHOTO) == 0) { + MessagesStorage.getInstance().clearDownloadQueue(AUTODOWNLOAD_MASK_PHOTO); + } + if ((mask & AUTODOWNLOAD_MASK_AUDIO) == 0) { + MessagesStorage.getInstance().clearDownloadQueue(AUTODOWNLOAD_MASK_AUDIO); + } + if ((mask & AUTODOWNLOAD_MASK_VIDEO) == 0) { + MessagesStorage.getInstance().clearDownloadQueue(AUTODOWNLOAD_MASK_VIDEO); + } + if ((mask & AUTODOWNLOAD_MASK_DOCUMENT) == 0) { + MessagesStorage.getInstance().clearDownloadQueue(AUTODOWNLOAD_MASK_DOCUMENT); + } + if ((mask & AUTODOWNLOAD_MASK_MUSIC) == 0) { + MessagesStorage.getInstance().clearDownloadQueue(AUTODOWNLOAD_MASK_MUSIC); + } + if ((mask & AUTODOWNLOAD_MASK_GIF) == 0) { + MessagesStorage.getInstance().clearDownloadQueue(AUTODOWNLOAD_MASK_GIF); + } + } + } + + public boolean canDownloadMedia(int type) { + return (getCurrentDownloadMask() & type) != 0; + } + + private int getCurrentDownloadMask() { + if (ConnectionsManager.isConnectedToWiFi()) { + return wifiDownloadMask; + } else if (ConnectionsManager.isRoaming()) { + return roamingDownloadMask; + } else { + return mobileDataDownloadMask; + } + } + + protected void processDownloadObjects(int type, ArrayList objects) { + if (objects.isEmpty()) { + return; + } + ArrayList queue = null; + if (type == AUTODOWNLOAD_MASK_PHOTO) { + queue = photoDownloadQueue; + } else if (type == AUTODOWNLOAD_MASK_AUDIO) { + queue = audioDownloadQueue; + } else if (type == AUTODOWNLOAD_MASK_VIDEO) { + queue = videoDownloadQueue; + } else if (type == AUTODOWNLOAD_MASK_DOCUMENT) { + queue = documentDownloadQueue; + } else if (type == AUTODOWNLOAD_MASK_MUSIC) { + queue = musicDownloadQueue; + } else if (type == AUTODOWNLOAD_MASK_GIF) { + queue = gifDownloadQueue; + } + for (int a = 0; a < objects.size(); a++) { + DownloadObject downloadObject = objects.get(a); + String path; + if (downloadObject.object instanceof TLRPC.Document) { + TLRPC.Document document = (TLRPC.Document) downloadObject.object; + path = FileLoader.getAttachFileName(document); + } else { + path = FileLoader.getAttachFileName(downloadObject.object); + } + if (downloadQueueKeys.containsKey(path)) { + continue; + } + + boolean added = true; + if (downloadObject.object instanceof TLRPC.PhotoSize) { + FileLoader.getInstance().loadFile((TLRPC.PhotoSize) downloadObject.object, null, false); + } else if (downloadObject.object instanceof TLRPC.Document) { + TLRPC.Document document = (TLRPC.Document) downloadObject.object; + FileLoader.getInstance().loadFile(document, false, false); + } else { + added = false; + } + if (added) { + queue.add(downloadObject); + downloadQueueKeys.put(path, downloadObject); + } + } + } + + protected void newDownloadObjectsAvailable(int downloadMask) { + int mask = getCurrentDownloadMask(); + if ((mask & AUTODOWNLOAD_MASK_PHOTO) != 0 && (downloadMask & AUTODOWNLOAD_MASK_PHOTO) != 0 && photoDownloadQueue.isEmpty()) { + MessagesStorage.getInstance().getDownloadQueue(AUTODOWNLOAD_MASK_PHOTO); + } + if ((mask & AUTODOWNLOAD_MASK_AUDIO) != 0 && (downloadMask & AUTODOWNLOAD_MASK_AUDIO) != 0 && audioDownloadQueue.isEmpty()) { + MessagesStorage.getInstance().getDownloadQueue(AUTODOWNLOAD_MASK_AUDIO); + } + if ((mask & AUTODOWNLOAD_MASK_VIDEO) != 0 && (downloadMask & AUTODOWNLOAD_MASK_VIDEO) != 0 && videoDownloadQueue.isEmpty()) { + MessagesStorage.getInstance().getDownloadQueue(AUTODOWNLOAD_MASK_VIDEO); + } + if ((mask & AUTODOWNLOAD_MASK_DOCUMENT) != 0 && (downloadMask & AUTODOWNLOAD_MASK_DOCUMENT) != 0 && documentDownloadQueue.isEmpty()) { + MessagesStorage.getInstance().getDownloadQueue(AUTODOWNLOAD_MASK_DOCUMENT); + } + if ((mask & AUTODOWNLOAD_MASK_MUSIC) != 0 && (downloadMask & AUTODOWNLOAD_MASK_MUSIC) != 0 && musicDownloadQueue.isEmpty()) { + MessagesStorage.getInstance().getDownloadQueue(AUTODOWNLOAD_MASK_MUSIC); + } + if ((mask & AUTODOWNLOAD_MASK_GIF) != 0 && (downloadMask & AUTODOWNLOAD_MASK_GIF) != 0 && gifDownloadQueue.isEmpty()) { + MessagesStorage.getInstance().getDownloadQueue(AUTODOWNLOAD_MASK_GIF); + } + } + + private void checkDownloadFinished(String fileName, int state) { + DownloadObject downloadObject = downloadQueueKeys.get(fileName); + if (downloadObject != null) { + downloadQueueKeys.remove(fileName); + if (state == 0 || state == 2) { + MessagesStorage.getInstance().removeFromDownloadQueue(downloadObject.id, downloadObject.type, false /*state != 0*/); + } + if (downloadObject.type == AUTODOWNLOAD_MASK_PHOTO) { + photoDownloadQueue.remove(downloadObject); + if (photoDownloadQueue.isEmpty()) { + newDownloadObjectsAvailable(AUTODOWNLOAD_MASK_PHOTO); + } + } else if (downloadObject.type == AUTODOWNLOAD_MASK_AUDIO) { + audioDownloadQueue.remove(downloadObject); + if (audioDownloadQueue.isEmpty()) { + newDownloadObjectsAvailable(AUTODOWNLOAD_MASK_AUDIO); + } + } else if (downloadObject.type == AUTODOWNLOAD_MASK_VIDEO) { + videoDownloadQueue.remove(downloadObject); + if (videoDownloadQueue.isEmpty()) { + newDownloadObjectsAvailable(AUTODOWNLOAD_MASK_VIDEO); + } + } else if (downloadObject.type == AUTODOWNLOAD_MASK_DOCUMENT) { + documentDownloadQueue.remove(downloadObject); + if (documentDownloadQueue.isEmpty()) { + newDownloadObjectsAvailable(AUTODOWNLOAD_MASK_DOCUMENT); + } + } else if (downloadObject.type == AUTODOWNLOAD_MASK_MUSIC) { + musicDownloadQueue.remove(downloadObject); + if (musicDownloadQueue.isEmpty()) { + newDownloadObjectsAvailable(AUTODOWNLOAD_MASK_MUSIC); + } + } else if (downloadObject.type == AUTODOWNLOAD_MASK_GIF) { + gifDownloadQueue.remove(downloadObject); + if (gifDownloadQueue.isEmpty()) { + newDownloadObjectsAvailable(AUTODOWNLOAD_MASK_GIF); + } + } + } + } + + public void startMediaObserver() { + if (android.os.Build.VERSION.SDK_INT < 14) { + return; + } + ApplicationLoader.applicationHandler.removeCallbacks(stopMediaObserverRunnable); + startObserverToken++; + try { + if (internalObserver == null) { + ApplicationLoader.applicationContext.getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, externalObserver = new ExternalObserver()); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + if (externalObserver == null) { + ApplicationLoader.applicationContext.getContentResolver().registerContentObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI, false, internalObserver = new InternalObserver()); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void stopMediaObserver() { + if (android.os.Build.VERSION.SDK_INT < 14) { + return; + } + if (stopMediaObserverRunnable == null) { + stopMediaObserverRunnable = new StopMediaObserverRunnable(); + } + stopMediaObserverRunnable.currentObserverToken = startObserverToken; + ApplicationLoader.applicationHandler.postDelayed(stopMediaObserverRunnable, 5000); + } + + public void processMediaObserver(Uri uri) { + try { + Point size = AndroidUtilities.getRealScreenSize(); + + Cursor cursor = ApplicationLoader.applicationContext.getContentResolver().query(uri, mediaProjections, null, null, "date_added DESC LIMIT 1"); + final ArrayList screenshotDates = new ArrayList<>(); + if (cursor != null) { + while (cursor.moveToNext()) { + String val = ""; + String data = cursor.getString(0); + String display_name = cursor.getString(1); + String album_name = cursor.getString(2); + long date = cursor.getLong(3); + String title = cursor.getString(4); + int photoW = 0; + int photoH = 0; + if (Build.VERSION.SDK_INT >= 16) { + photoW = cursor.getInt(5); + photoH = cursor.getInt(6); + } + if (data != null && data.toLowerCase().contains("screenshot") || + display_name != null && display_name.toLowerCase().contains("screenshot") || + album_name != null && album_name.toLowerCase().contains("screenshot") || + title != null && title.toLowerCase().contains("screenshot")) { + try { + if (photoW == 0 || photoH == 0) { + BitmapFactory.Options bmOptions = new BitmapFactory.Options(); + bmOptions.inJustDecodeBounds = true; + BitmapFactory.decodeFile(data, bmOptions); + photoW = bmOptions.outWidth; + photoH = bmOptions.outHeight; + } + if (photoW <= 0 || photoH <= 0 || (photoW == size.x && photoH == size.y || photoH == size.x && photoW == size.y)) { + screenshotDates.add(date); + } + } catch (Exception e) { + screenshotDates.add(date); + } + } + } + cursor.close(); + } + if (!screenshotDates.isEmpty()) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.screenshotTook); + checkScreenshots(screenshotDates); + } + }); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + private void checkScreenshots(ArrayList dates) { + if (dates == null || dates.isEmpty() || lastSecretChatEnterTime == 0 || lastSecretChat == null || !(lastSecretChat instanceof TLRPC.TL_encryptedChat)) { + return; + } + long dt = 2000; + boolean send = false; + for (Long date : dates) { + if (lastMediaCheckTime != 0 && date <= lastMediaCheckTime) { + continue; + } + + if (date >= lastSecretChatEnterTime) { + if (lastSecretChatLeaveTime == 0 || date <= lastSecretChatLeaveTime + dt) { + lastMediaCheckTime = Math.max(lastMediaCheckTime, date); + send = true; + } + } + } + if (send) { + SecretChatHelper.getInstance().sendScreenshotMessage(lastSecretChat, lastSecretChatVisibleMessages, null); + } + } + + public void setLastEncryptedChatParams(long enterTime, long leaveTime, TLRPC.EncryptedChat encryptedChat, ArrayList visibleMessages) { + lastSecretChatEnterTime = enterTime; + lastSecretChatLeaveTime = leaveTime; + lastSecretChat = encryptedChat; + lastSecretChatVisibleMessages = visibleMessages; + } + + public int generateObserverTag() { + return lastTag++; + } + + public void addLoadingFileObserver(String fileName, FileDownloadProgressListener observer) { + addLoadingFileObserver(fileName, null, observer); + } + + public void addLoadingFileObserver(String fileName, MessageObject messageObject, FileDownloadProgressListener observer) { + if (listenerInProgress) { + addLaterArray.put(fileName, observer); + return; + } + removeLoadingFileObserver(observer); + + ArrayList> arrayList = loadingFileObservers.get(fileName); + if (arrayList == null) { + arrayList = new ArrayList<>(); + loadingFileObservers.put(fileName, arrayList); + } + arrayList.add(new WeakReference<>(observer)); + if (messageObject != null) { + ArrayList messageObjects = loadingFileMessagesObservers.get(fileName); + if (messageObjects == null) { + messageObjects = new ArrayList<>(); + loadingFileMessagesObservers.put(fileName, messageObjects); + } + messageObjects.add(messageObject); + } + + observersByTag.put(observer.getObserverTag(), fileName); + } + + public void removeLoadingFileObserver(FileDownloadProgressListener observer) { + if (listenerInProgress) { + deleteLaterArray.add(observer); + return; + } + String fileName = observersByTag.get(observer.getObserverTag()); + if (fileName != null) { + ArrayList> arrayList = loadingFileObservers.get(fileName); + if (arrayList != null) { + for (int a = 0; a < arrayList.size(); a++) { + WeakReference reference = arrayList.get(a); + if (reference.get() == null || reference.get() == observer) { + arrayList.remove(a); + a--; + } + } + if (arrayList.isEmpty()) { + loadingFileObservers.remove(fileName); + } + } + observersByTag.remove(observer.getObserverTag()); + } + } + + private void processLaterArrays() { + for (HashMap.Entry listener : addLaterArray.entrySet()) { + addLoadingFileObserver(listener.getKey(), listener.getValue()); //TODO + } + addLaterArray.clear(); + for (FileDownloadProgressListener listener : deleteLaterArray) { + removeLoadingFileObserver(listener); + } + deleteLaterArray.clear(); + } + + @SuppressWarnings("unchecked") + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.FileDidFailedLoad) { + listenerInProgress = true; + String fileName = (String) args[0]; + loadingFileMessagesObservers.get(fileName); + ArrayList> arrayList = loadingFileObservers.get(fileName); + if (arrayList != null) { + for (int a = 0; a < arrayList.size(); a++) { + WeakReference reference = arrayList.get(a); + if (reference.get() != null) { + reference.get().onFailedDownload(fileName); + observersByTag.remove(reference.get().getObserverTag()); + } + } + loadingFileObservers.remove(fileName); + } + listenerInProgress = false; + processLaterArrays(); + checkDownloadFinished(fileName, (Integer) args[1]); + } else if (id == NotificationCenter.FileDidLoaded) { + listenerInProgress = true; + String fileName = (String) args[0]; + if (downloadingCurrentMessage && playingMessageObject != null) { + String file = FileLoader.getAttachFileName(playingMessageObject.getDocument()); + if (file.equals(fileName)) { + playMusicAgain = true; + playAudio(playingMessageObject); + } + } + ArrayList messageObjects = loadingFileMessagesObservers.get(fileName); + if (messageObjects != null) { + for (int a = 0; a < messageObjects.size(); a++) { + MessageObject messageObject = messageObjects.get(a); + messageObject.mediaExists = true; + } + loadingFileMessagesObservers.remove(fileName); + } + ArrayList> arrayList = loadingFileObservers.get(fileName); + if (arrayList != null) { + for (int a = 0; a < arrayList.size(); a++) { + WeakReference reference = arrayList.get(a); + if (reference.get() != null) { + reference.get().onSuccessDownload(fileName); + observersByTag.remove(reference.get().getObserverTag()); + } + } + loadingFileObservers.remove(fileName); + } + listenerInProgress = false; + processLaterArrays(); + checkDownloadFinished(fileName, 0); + } else if (id == NotificationCenter.FileLoadProgressChanged) { + listenerInProgress = true; + String fileName = (String) args[0]; + ArrayList> arrayList = loadingFileObservers.get(fileName); + if (arrayList != null) { + Float progress = (Float) args[1]; + for (WeakReference reference : arrayList) { + if (reference.get() != null) { + reference.get().onProgressDownload(fileName, progress); + } + } + } + listenerInProgress = false; + processLaterArrays(); + } else if (id == NotificationCenter.FileUploadProgressChanged) { + listenerInProgress = true; + String fileName = (String) args[0]; + ArrayList> arrayList = loadingFileObservers.get(fileName); + if (arrayList != null) { + Float progress = (Float) args[1]; + Boolean enc = (Boolean) args[2]; + for (WeakReference reference : arrayList) { + if (reference.get() != null) { + reference.get().onProgressUpload(fileName, progress, enc); + } + } + } + listenerInProgress = false; + processLaterArrays(); + try { + ArrayList delayedMessages = SendMessagesHelper.getInstance().getDelayedMessages(fileName); + if (delayedMessages != null) { + for (int a = 0; a < delayedMessages.size(); a++) { + SendMessagesHelper.DelayedMessage delayedMessage = delayedMessages.get(a); + if (delayedMessage.encryptedChat == null) { + long dialog_id = delayedMessage.obj.getDialogId(); + Long lastTime = typingTimes.get(dialog_id); + if (lastTime == null || lastTime + 4000 < System.currentTimeMillis()) { + if (MessageObject.isVideoDocument(delayedMessage.documentLocation)) { + MessagesController.getInstance().sendTyping(dialog_id, 5, 0); + } else if (delayedMessage.documentLocation != null) { + MessagesController.getInstance().sendTyping(dialog_id, 3, 0); + } else if (delayedMessage.location != null) { + MessagesController.getInstance().sendTyping(dialog_id, 4, 0); + } + typingTimes.put(dialog_id, System.currentTimeMillis()); + } + } + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else if (id == NotificationCenter.messagesDeleted) { + int channelId = (Integer) args[1]; + ArrayList markAsDeletedMessages = (ArrayList) args[0]; + if (playingMessageObject != null) { + if (channelId == playingMessageObject.messageOwner.to_id.channel_id) { + if (markAsDeletedMessages.contains(playingMessageObject.getId())) { + cleanupPlayer(true, true); + } + } + } + if (voiceMessagesPlaylist != null && !voiceMessagesPlaylist.isEmpty()) { + MessageObject messageObject = voiceMessagesPlaylist.get(0); + if (channelId == messageObject.messageOwner.to_id.channel_id) { + for (int a = 0; a < markAsDeletedMessages.size(); a++) { + messageObject = voiceMessagesPlaylistMap.remove(markAsDeletedMessages.get(a)); + if (messageObject != null) { + voiceMessagesPlaylist.remove(messageObject); + } + } + } + } + } else if (id == NotificationCenter.removeAllMessagesFromDialog) { + long did = (Long) args[0]; + if (playingMessageObject != null && playingMessageObject.getDialogId() == did) { + cleanupPlayer(false, true); + } + } else if (id == NotificationCenter.musicDidLoaded) { + long did = (Long) args[0]; + if (playingMessageObject != null && playingMessageObject.isMusic() && playingMessageObject.getDialogId() == did) { + ArrayList arrayList = (ArrayList) args[1]; + playlist.addAll(0, arrayList); + if (shuffleMusic) { + buildShuffledPlayList(); + currentPlaylistNum = 0; + } else { + currentPlaylistNum += arrayList.size(); + } + } + } else if (id == NotificationCenter.didReceivedNewMessages) { + if (voiceMessagesPlaylist != null && !voiceMessagesPlaylist.isEmpty()) { + MessageObject messageObject = voiceMessagesPlaylist.get(0); + long did = (Long) args[0]; + if (did == messageObject.getDialogId()) { + ArrayList arr = (ArrayList) args[1]; + for (int a = 0; a < arr.size(); a++) { + messageObject = arr.get(a); + if (messageObject.isVoice() && (!voiceMessagesPlaylistUnread || messageObject.isContentUnread() && !messageObject.isOut())) { + voiceMessagesPlaylist.add(messageObject); + voiceMessagesPlaylistMap.put(messageObject.getId(), messageObject); + } + } + } + } + } + } + + private void checkDecoderQueue() { + fileDecodingQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (decodingFinished) { + checkPlayerQueue(); + return; + } + boolean was = false; + while (true) { + AudioBuffer buffer = null; + synchronized (playerSync) { + if (!freePlayerBuffers.isEmpty()) { + buffer = freePlayerBuffers.get(0); + freePlayerBuffers.remove(0); + } + if (!usedPlayerBuffers.isEmpty()) { + was = true; + } + } + if (buffer != null) { + readOpusFile(buffer.buffer, playerBufferSize, readArgs); + buffer.size = readArgs[0]; + buffer.pcmOffset = readArgs[1]; + buffer.finished = readArgs[2]; + if (buffer.finished == 1) { + decodingFinished = true; + } + if (buffer.size != 0) { + buffer.buffer.rewind(); + buffer.buffer.get(buffer.bufferBytes); + synchronized (playerSync) { + usedPlayerBuffers.add(buffer); + } + } else { + synchronized (playerSync) { + freePlayerBuffers.add(buffer); + break; + } + } + was = true; + } else { + break; + } + } + if (was) { + checkPlayerQueue(); + } + } + }); + } + + private void checkPlayerQueue() { + playerQueue.postRunnable(new Runnable() { + @Override + public void run() { + synchronized (playerObjectSync) { + if (audioTrackPlayer == null || audioTrackPlayer.getPlayState() != AudioTrack.PLAYSTATE_PLAYING) { + return; + } + } + AudioBuffer buffer = null; + synchronized (playerSync) { + if (!usedPlayerBuffers.isEmpty()) { + buffer = usedPlayerBuffers.get(0); + usedPlayerBuffers.remove(0); + } + } + + if (buffer != null) { + int count = 0; + try { + count = audioTrackPlayer.write(buffer.bufferBytes, 0, buffer.size); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + buffersWrited++; + + if (count > 0) { + final long pcm = buffer.pcmOffset; + final int marker = buffer.finished == 1 ? count : -1; + final int finalBuffersWrited = buffersWrited; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + lastPlayPcm = pcm; + if (marker != -1) { + if (audioTrackPlayer != null) { + audioTrackPlayer.setNotificationMarkerPosition(1); + } + if (finalBuffersWrited == 1) { + cleanupPlayer(true, true, true); + } + } + } + }); + } + + if (buffer.finished != 1) { + checkPlayerQueue(); + } + } + if (buffer == null || buffer != null && buffer.finished != 1) { + checkDecoderQueue(); + } + + if (buffer != null) { + synchronized (playerSync) { + freePlayerBuffers.add(buffer); + } + } + } + }); + } + + protected boolean isRecordingAudio() { + return recordStartRunnable != null || recordingAudio != null; + } + + private boolean isNearToSensor(float value) { + return value < 5.0f && value != proximitySensor.getMaximumRange(); + } + + @Override + public void onSensorChanged(SensorEvent event) { + if (!sensorsStarted) { + return; + } + if (event.sensor == proximitySensor) { + FileLog.e("tmessages", "proximity changed to " + event.values[0]); + if (lastProximityValue == -100) { + lastProximityValue = event.values[0]; + } else if (lastProximityValue != event.values[0]) { + proximityHasDifferentValues = true; + } + if (proximityHasDifferentValues) { + proximityTouched = isNearToSensor(event.values[0]); + } + } else if (event.sensor == accelerometerSensor) { + //0.98039215f + final double alpha = lastTimestamp == 0 ? 0.98f : 1.0 / (1.0 + (event.timestamp - lastTimestamp) / 1000000000.0); + final float alphaFast = 0.8f; + lastTimestamp = event.timestamp; + gravity[0] = (float) (alpha * gravity[0] + (1.0 - alpha) * event.values[0]); + gravity[1] = (float) (alpha * gravity[1] + (1.0 - alpha) * event.values[1]); + gravity[2] = (float) (alpha * gravity[2] + (1.0 - alpha) * event.values[2]); + gravityFast[0] = (alphaFast * gravity[0] + (1.0f - alphaFast) * event.values[0]); + gravityFast[1] = (alphaFast * gravity[1] + (1.0f - alphaFast) * event.values[1]); + gravityFast[2] = (alphaFast * gravity[2] + (1.0f - alphaFast) * event.values[2]); + + linearAcceleration[0] = event.values[0] - gravity[0]; + linearAcceleration[1] = event.values[1] - gravity[1]; + linearAcceleration[2] = event.values[2] - gravity[2]; + } else if (event.sensor == linearSensor) { + linearAcceleration[0] = event.values[0]; + linearAcceleration[1] = event.values[1]; + linearAcceleration[2] = event.values[2]; + } else if (event.sensor == gravitySensor) { + gravityFast[0] = gravity[0] = event.values[0]; + gravityFast[1] = gravity[1] = event.values[1]; + gravityFast[2] = gravity[2] = event.values[2]; + } + final float minDist = 15.0f; + final int minCount = 6; + final int countLessMax = 10; + if (event.sensor == linearSensor || event.sensor == gravitySensor || event.sensor == accelerometerSensor) { + float val = gravity[0] * linearAcceleration[0] + gravity[1] * linearAcceleration[1] + gravity[2] * linearAcceleration[2]; + if (raisedToBack != minCount) { + if (val > 0 && previousAccValue > 0) { + if (val > minDist && raisedToBack == 0) { + if (raisedToTop < minCount && !proximityTouched) { + raisedToTop++; + if (raisedToTop == minCount) { + countLess = 0; + } + } + } else { + if (val < minDist) { + countLess++; + } + if (countLess == countLessMax || raisedToTop != minCount || raisedToBack != 0) { + raisedToBack = 0; + raisedToTop = 0; + countLess = 0; + } + } + } else if (val < 0 && previousAccValue < 0) { + if (raisedToTop == minCount && val < -minDist) { + if (raisedToBack < minCount) { + raisedToBack++; + if (raisedToBack == minCount) { + raisedToTop = 0; + countLess = 0; + timeSinceRaise = System.currentTimeMillis(); + //FileLog.e("tmessages", "motion detected"); + } + } + } else { + if (val > -minDist) { + countLess++; + } + if (countLess == countLessMax || raisedToTop != minCount || raisedToBack != 0) { + raisedToTop = 0; + raisedToBack = 0; + countLess = 0; + } + } + } + } + previousAccValue = val; + accelerometerVertical = gravityFast[1] > 2.5f && Math.abs(gravityFast[2]) < 4.0f && /*Math.abs(gravityFast[0]) < 9.0f &&*/ Math.abs(gravityFast[0]) > 1.5f; + //FileLog.e("tmessages", accelerometerVertical + " val = " + val + " acc (" + linearAcceleration[0] + ", " + linearAcceleration[1] + ", " + linearAcceleration[2] + ") grav (" + gravityFast[0] + ", " + gravityFast[1] + ", " + gravityFast[2] + ")"); + } + if (raisedToBack == minCount && accelerometerVertical && proximityTouched && !NotificationsController.getInstance().audioManager.isWiredHeadsetOn()) { + FileLog.e("tmessages", "sensor values reached"); + if (playingMessageObject == null && recordStartRunnable == null && recordingAudio == null && !PhotoViewer.getInstance().isVisible() && ApplicationLoader.isScreenOn && !inputFieldHasText && allowStartRecord && raiseChat != null && !callInProgress) { + if (!raiseToEarRecord) { + FileLog.e("tmessages", "start record"); + useFrontSpeaker = true; + if (!raiseChat.playFirstUnreadVoiceMessage()) { + raiseToEarRecord = true; + useFrontSpeaker = false; + startRecording(raiseChat.getDialogId(), null, false); + } + ignoreOnPause = true; + if (proximityHasDifferentValues && proximityWakeLock != null && !proximityWakeLock.isHeld()) { + proximityWakeLock.acquire(); + } + } + } else if (playingMessageObject != null && playingMessageObject.isVoice()) { + if (!useFrontSpeaker) { + FileLog.e("tmessages", "start listen"); + if (proximityHasDifferentValues && proximityWakeLock != null && !proximityWakeLock.isHeld()) { + proximityWakeLock.acquire(); + } + useFrontSpeaker = true; + startAudioAgain(false); + ignoreOnPause = true; + } + } + raisedToBack = 0; + raisedToTop = 0; + countLess = 0; + } else if (proximityTouched) { + if (playingMessageObject != null && playingMessageObject.isVoice()) { + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + //if (!useFrontSpeaker) { + if (!useFrontSpeaker && !plusPreferences.getBoolean("disableAudioStop", false)) { + FileLog.e("tmessages", "start listen by proximity only"); + if (proximityHasDifferentValues && proximityWakeLock != null && !proximityWakeLock.isHeld()) { + proximityWakeLock.acquire(); + } + useFrontSpeaker = true; + startAudioAgain(false); + ignoreOnPause = true; + } + } + } else if (!proximityTouched) { + if (raiseToEarRecord) { + FileLog.e("tmessages", "stop record"); + stopRecording(2); + raiseToEarRecord = false; + ignoreOnPause = false; + if (proximityHasDifferentValues && proximityWakeLock != null && proximityWakeLock.isHeld()) { + proximityWakeLock.release(); + } + } else if (useFrontSpeaker) { + FileLog.e("tmessages", "stop listen"); + useFrontSpeaker = false; + startAudioAgain(true); + ignoreOnPause = false; + if (proximityHasDifferentValues && proximityWakeLock != null && proximityWakeLock.isHeld()) { + proximityWakeLock.release(); + } + } + } + if (timeSinceRaise != 0 && raisedToBack == minCount && Math.abs(System.currentTimeMillis() - timeSinceRaise) > 1000) { + raisedToBack = 0; + raisedToTop = 0; + countLess = 0; + timeSinceRaise = 0; + } + } + + public void startRecordingIfFromSpeaker() { + if (!useFrontSpeaker || raiseChat == null || !allowStartRecord) { + return; + } + raiseToEarRecord = true; + startRecording(raiseChat.getDialogId(), null, false); + ignoreOnPause = true; + } + + private void startAudioAgain(boolean paused) { + if (playingMessageObject == null) { + return; + } + boolean post = audioPlayer != null; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioRouteChanged, useFrontSpeaker); + final MessageObject currentMessageObject = playingMessageObject; + float progress = playingMessageObject.audioProgress; + cleanupPlayer(false, true); + currentMessageObject.audioProgress = progress; + playAudio(currentMessageObject); + if (paused) { + if (post) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + pauseAudio(currentMessageObject); + } + }, 100); + } else { + pauseAudio(currentMessageObject); + } + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + + } + + public void setInputFieldHasText(boolean value) { + inputFieldHasText = value; + } + + public void setAllowStartRecord(boolean value) { + allowStartRecord = value; + } + + public void startRaiseToEarSensors(ChatActivity chatActivity) { + if (chatActivity == null || accelerometerSensor == null && (gravitySensor == null || linearAcceleration == null) || proximitySensor == null) { + return; + } + raiseChat = chatActivity; + if (!raiseToSpeak && (playingMessageObject == null || !playingMessageObject.isVoice())) { + return; + } + if (!sensorsStarted) { + gravity[0] = gravity[1] = gravity[2] = 0; + linearAcceleration[0] = linearAcceleration[1] = linearAcceleration[2] = 0; + gravityFast[0] = gravityFast[1] = gravityFast[2] = 0; + lastTimestamp = 0; + previousAccValue = 0; + raisedToTop = 0; + countLess = 0; + raisedToBack = 0; + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (gravitySensor != null) { + sensorManager.registerListener(MediaController.this, gravitySensor, 30000); + } + if (linearSensor != null) { + sensorManager.registerListener(MediaController.this, linearSensor, 30000); + } + if (accelerometerSensor != null) { + sensorManager.registerListener(MediaController.this, accelerometerSensor, 30000); + } + sensorManager.registerListener(MediaController.this, proximitySensor, SensorManager.SENSOR_DELAY_NORMAL); + } + }); + sensorsStarted = true; + } + } + + public void stopRaiseToEarSensors(ChatActivity chatActivity) { + if (ignoreOnPause) { + ignoreOnPause = false; + return; + } + if (!sensorsStarted || ignoreOnPause || accelerometerSensor == null && (gravitySensor == null || linearAcceleration == null) || proximitySensor == null || raiseChat != chatActivity) { + return; + } + raiseChat = null; + stopRecording(0); + sensorsStarted = false; + accelerometerVertical = false; + proximityTouched = false; + raiseToEarRecord = false; + useFrontSpeaker = false; + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (linearSensor != null) { + sensorManager.unregisterListener(MediaController.this, linearSensor); + } + if (gravitySensor != null) { + sensorManager.unregisterListener(MediaController.this, gravitySensor); + } + if (accelerometerSensor != null) { + sensorManager.unregisterListener(MediaController.this, accelerometerSensor); + } + sensorManager.unregisterListener(MediaController.this, proximitySensor); + } + }); + if (proximityHasDifferentValues && proximityWakeLock != null && proximityWakeLock.isHeld()) { + proximityWakeLock.release(); + } + } + + public void cleanupPlayer(boolean notify, boolean stopService) { + cleanupPlayer(notify, stopService, false); + } + + public void cleanupPlayer(boolean notify, boolean stopService, boolean byVoiceEnd) { + if (audioPlayer != null) { + try { + audioPlayer.reset(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + audioPlayer.stop(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + audioPlayer.release(); + audioPlayer = null; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else if (audioTrackPlayer != null) { + synchronized (playerObjectSync) { + try { + audioTrackPlayer.pause(); + audioTrackPlayer.flush(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + audioTrackPlayer.release(); + audioTrackPlayer = null; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + stopProgressTimer(); + lastProgress = 0; + buffersWrited = 0; + isPaused = false; + if (playingMessageObject != null) { + if (downloadingCurrentMessage) { + FileLoader.getInstance().cancelLoadFile(playingMessageObject.getDocument()); + } + MessageObject lastFile = playingMessageObject; + playingMessageObject.audioProgress = 0.0f; + playingMessageObject.audioProgressSec = 0; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioProgressDidChanged, playingMessageObject.getId(), 0); + playingMessageObject = null; + downloadingCurrentMessage = false; + if (notify) { + NotificationsController.getInstance().audioManager.abandonAudioFocus(this); + hasAudioFocus = 0; + if (voiceMessagesPlaylist != null) { + if (byVoiceEnd && voiceMessagesPlaylist.get(0) == lastFile) { + voiceMessagesPlaylist.remove(0); + voiceMessagesPlaylistMap.remove(lastFile.getId()); + if (voiceMessagesPlaylist.isEmpty()) { + voiceMessagesPlaylist = null; + voiceMessagesPlaylistMap = null; + } + } else { + voiceMessagesPlaylist = null; + voiceMessagesPlaylistMap = null; + } + } + boolean next = false; + if (voiceMessagesPlaylist != null) { + MessageObject nextVoiceMessage = voiceMessagesPlaylist.get(0); + playAudio(nextVoiceMessage); + } else { + if (lastFile.isVoice() && lastFile.getId() != 0) { + startRecordingIfFromSpeaker(); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioDidReset, lastFile.getId(), stopService); + } + } + if (stopService) { + Intent intent = new Intent(ApplicationLoader.applicationContext, MusicPlayerService.class); + ApplicationLoader.applicationContext.stopService(intent); + } + } + if (!useFrontSpeaker && !raiseToSpeak) { + ChatActivity chat = raiseChat; + stopRaiseToEarSensors(raiseChat); + raiseChat = chat; + } + } + + private void seekOpusPlayer(final float progress) { + if (progress == 1.0f) { + return; + } + if (!isPaused) { + audioTrackPlayer.pause(); + } + audioTrackPlayer.flush(); + fileDecodingQueue.postRunnable(new Runnable() { + @Override + public void run() { + seekOpusFile(progress); + synchronized (playerSync) { + freePlayerBuffers.addAll(usedPlayerBuffers); + usedPlayerBuffers.clear(); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (!isPaused) { + ignoreFirstProgress = 3; + lastPlayPcm = (long) (currentTotalPcmDuration * progress); + if (audioTrackPlayer != null) { + audioTrackPlayer.play(); + } + lastProgress = (int) (currentTotalPcmDuration / 48.0f * progress); + checkPlayerQueue(); + } + } + }); + } + }); + } + + public boolean seekToProgress(MessageObject messageObject, float progress) { + if (audioTrackPlayer == null && audioPlayer == null || messageObject == null || playingMessageObject == null || playingMessageObject != null && playingMessageObject.getId() != messageObject.getId()) { + return false; + } + try { + if (audioPlayer != null) { + int seekTo = (int) (audioPlayer.getDuration() * progress); + audioPlayer.seekTo(seekTo); + lastProgress = seekTo; + } else if (audioTrackPlayer != null) { + seekOpusPlayer(progress); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + return false; + } + return true; + } + + public MessageObject getPlayingMessageObject() { + return playingMessageObject; + } + + private void buildShuffledPlayList() { + if (playlist.isEmpty()) { + return; + } + ArrayList all = new ArrayList<>(playlist); + shuffledPlaylist.clear(); + + MessageObject messageObject = playlist.get(currentPlaylistNum); + all.remove(currentPlaylistNum); + shuffledPlaylist.add(messageObject); + + int count = all.size(); + for (int a = 0; a < count; a++) { + int index = Utilities.random.nextInt(all.size()); + shuffledPlaylist.add(all.get(index)); + all.remove(index); + } + } + + public boolean setPlaylist(ArrayList messageObjects, MessageObject current) { + if (playingMessageObject == current) { + return playAudio(current); + } + playMusicAgain = !playlist.isEmpty(); + playlist.clear(); + for (int a = messageObjects.size() - 1; a >= 0; a--) { + MessageObject messageObject = messageObjects.get(a); + if (messageObject.isMusic()) { + playlist.add(messageObject); + } + } + currentPlaylistNum = playlist.indexOf(current); + if (currentPlaylistNum == -1) { + playlist.clear(); + shuffledPlaylist.clear(); + playlist.add(current); + } + if (current.isMusic()) { + if (shuffleMusic) { + buildShuffledPlayList(); + currentPlaylistNum = 0; + } + SharedMediaQuery.loadMusic(current.getDialogId(), playlist.get(0).getId()); + } + return playAudio(current); + } + + public void playNextMessage() { + playNextMessage(false); + } + + private void playNextMessage(boolean byStop) { + ArrayList currentPlayList = shuffleMusic ? shuffledPlaylist : playlist; + + if (byStop && repeatMode == 2) { + cleanupPlayer(false, false); + playAudio(currentPlayList.get(currentPlaylistNum)); + return; + } + currentPlaylistNum++; + if (currentPlaylistNum >= currentPlayList.size()) { + currentPlaylistNum = 0; + if (byStop && repeatMode == 0) { + if (audioPlayer != null || audioTrackPlayer != null) { + if (audioPlayer != null) { + try { + audioPlayer.reset(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + audioPlayer.stop(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + audioPlayer.release(); + audioPlayer = null; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else if (audioTrackPlayer != null) { + synchronized (playerObjectSync) { + try { + audioTrackPlayer.pause(); + audioTrackPlayer.flush(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + audioTrackPlayer.release(); + audioTrackPlayer = null; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + stopProgressTimer(); + lastProgress = 0; + buffersWrited = 0; + isPaused = true; + playingMessageObject.audioProgress = 0.0f; + playingMessageObject.audioProgressSec = 0; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioProgressDidChanged, playingMessageObject.getId(), 0); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioPlayStateChanged, playingMessageObject.getId()); + } + return; + } + } + if (currentPlaylistNum < 0 || currentPlaylistNum >= currentPlayList.size()) { + return; + } + playMusicAgain = true; + playAudio(currentPlayList.get(currentPlaylistNum)); + } + + public void playPreviousMessage() { + ArrayList currentPlayList = shuffleMusic ? shuffledPlaylist : playlist; + + currentPlaylistNum--; + if (currentPlaylistNum < 0) { + currentPlaylistNum = currentPlayList.size() - 1; + } + if (currentPlaylistNum < 0 || currentPlaylistNum >= currentPlayList.size()) { + return; + } + playMusicAgain = true; + playAudio(currentPlayList.get(currentPlaylistNum)); + } + + private void checkIsNextMusicFileDownloaded() { + if ((getCurrentDownloadMask() & AUTODOWNLOAD_MASK_MUSIC) == 0) { + return; + } + ArrayList currentPlayList = shuffleMusic ? shuffledPlaylist : playlist; + if (currentPlayList == null || currentPlayList.size() < 2) { + return; + } + int nextIndex = currentPlaylistNum + 1; + if (nextIndex >= currentPlayList.size()) { + nextIndex = 0; + } + MessageObject nextAudio = currentPlayList.get(nextIndex); + File file = null; + if (nextAudio.messageOwner.attachPath != null && nextAudio.messageOwner.attachPath.length() > 0) { + file = new File(nextAudio.messageOwner.attachPath); + if (!file.exists()) { + file = null; + } + } + final File cacheFile = file != null ? file : FileLoader.getPathToMessage(nextAudio.messageOwner); + boolean exist = cacheFile != null && cacheFile.exists(); + if (cacheFile != null && cacheFile != file && !cacheFile.exists() && nextAudio.isMusic()) { + FileLoader.getInstance().loadFile(nextAudio.getDocument(), false, false); + } + } + + public void setVoiceMessagesPlaylist(ArrayList playlist, boolean unread) { + voiceMessagesPlaylist = playlist; + if (voiceMessagesPlaylist != null) { + voiceMessagesPlaylistUnread = unread; + voiceMessagesPlaylistMap = new HashMap<>(); + for (int a = 0; a < voiceMessagesPlaylist.size(); a++) { + MessageObject messageObject = voiceMessagesPlaylist.get(a); + voiceMessagesPlaylistMap.put(messageObject.getId(), messageObject); + } + } + } + + private void checkAudioFocus(MessageObject messageObject) { + int neededAudioFocus; + if (messageObject.isVoice()) { + if (useFrontSpeaker) { + neededAudioFocus = 3; + } else { + neededAudioFocus = 2; + } + } else { + neededAudioFocus = 1; + } + if (hasAudioFocus != neededAudioFocus) { + hasAudioFocus = neededAudioFocus; + if (neededAudioFocus == 3) { + NotificationsController.getInstance().audioManager.requestAudioFocus(this, AudioManager.STREAM_VOICE_CALL, AudioManager.AUDIOFOCUS_GAIN); + } else { + NotificationsController.getInstance().audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, neededAudioFocus == 2 ? AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK : AudioManager.AUDIOFOCUS_GAIN); + } + } + } + + public boolean playAudio(final MessageObject messageObject) { + if (messageObject == null) { + return false; + } + if ((audioTrackPlayer != null || audioPlayer != null) && playingMessageObject != null && messageObject.getId() == playingMessageObject.getId()) { + if (isPaused) { + resumeAudio(messageObject); + } + if (!raiseToSpeak) { + startRaiseToEarSensors(raiseChat); + } + return true; + } + if (!messageObject.isOut() && messageObject.isContentUnread() && messageObject.messageOwner.to_id.channel_id == 0) { + MessagesController.getInstance().markMessageContentAsRead(messageObject); + } + boolean notify = !playMusicAgain; + if (playingMessageObject != null) { + notify = false; + } + cleanupPlayer(notify, false); + playMusicAgain = false; + File file = null; + if (messageObject.messageOwner.attachPath != null && messageObject.messageOwner.attachPath.length() > 0) { + file = new File(messageObject.messageOwner.attachPath); + if (!file.exists()) { + file = null; + } + } + final File cacheFile = file != null ? file : FileLoader.getPathToMessage(messageObject.messageOwner); + if (cacheFile != null && cacheFile != file && !cacheFile.exists() && messageObject.isMusic()) { + FileLoader.getInstance().loadFile(messageObject.getDocument(), false, false); + downloadingCurrentMessage = true; + isPaused = false; + lastProgress = 0; + lastPlayPcm = 0; + audioInfo = null; + playingMessageObject = messageObject; + if (playingMessageObject.getDocument() != null) { + Intent intent = new Intent(ApplicationLoader.applicationContext, MusicPlayerService.class); + ApplicationLoader.applicationContext.startService(intent); + } else { + Intent intent = new Intent(ApplicationLoader.applicationContext, MusicPlayerService.class); + ApplicationLoader.applicationContext.stopService(intent); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioPlayStateChanged, playingMessageObject.getId()); + return true; + } else { + downloadingCurrentMessage = false; + } + if (messageObject.isMusic()) { + checkIsNextMusicFileDownloaded(); + } + + if (isOpusFile(cacheFile.getAbsolutePath()) == 1) { + playlist.clear(); + shuffledPlaylist.clear(); + synchronized (playerObjectSync) { + try { + ignoreFirstProgress = 3; + final Semaphore semaphore = new Semaphore(0); + final Boolean[] result = new Boolean[1]; + fileDecodingQueue.postRunnable(new Runnable() { + @Override + public void run() { + result[0] = openOpusFile(cacheFile.getAbsolutePath()) != 0; + semaphore.release(); + } + }); + semaphore.acquire(); + + if (!result[0]) { + return false; + } + currentTotalPcmDuration = getTotalPcmDuration(); + + audioTrackPlayer = new AudioTrack(useFrontSpeaker ? AudioManager.STREAM_VOICE_CALL : AudioManager.STREAM_MUSIC, 48000, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT, playerBufferSize, AudioTrack.MODE_STREAM); + audioTrackPlayer.setStereoVolume(1.0f, 1.0f); + audioTrackPlayer.setPlaybackPositionUpdateListener(new AudioTrack.OnPlaybackPositionUpdateListener() { + @Override + public void onMarkerReached(AudioTrack audioTrack) { + cleanupPlayer(true, true, true); + } + + @Override + public void onPeriodicNotification(AudioTrack audioTrack) { + + } + }); + audioTrackPlayer.play(); + } catch (Exception e) { + FileLog.e("tmessages", e); + if (audioTrackPlayer != null) { + audioTrackPlayer.release(); + audioTrackPlayer = null; + isPaused = false; + playingMessageObject = null; + downloadingCurrentMessage = false; + } + return false; + } + } + } else { + try { + audioPlayer = new MediaPlayer(); + audioPlayer.setAudioStreamType(useFrontSpeaker ? AudioManager.STREAM_VOICE_CALL : AudioManager.STREAM_MUSIC); + audioPlayer.setDataSource(cacheFile.getAbsolutePath()); + audioPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { + @Override + public void onCompletion(MediaPlayer mediaPlayer) { + if (!playlist.isEmpty() && playlist.size() > 1) { + playNextMessage(true); + } else { + cleanupPlayer(true, true, messageObject != null && messageObject.isVoice()); + } + } + }); + audioPlayer.prepare(); + audioPlayer.start(); + if (messageObject.isVoice()) { + audioInfo = null; + playlist.clear(); + shuffledPlaylist.clear(); + } else { + try { + audioInfo = AudioInfo.getAudioInfo(cacheFile); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioPlayStateChanged, playingMessageObject != null ? playingMessageObject.getId() : 0); + if (audioPlayer != null) { + audioPlayer.release(); + audioPlayer = null; + isPaused = false; + playingMessageObject = null; + downloadingCurrentMessage = false; + } + return false; + } + } + checkAudioFocus(messageObject); + + isPaused = false; + lastProgress = 0; + lastPlayPcm = 0; + playingMessageObject = messageObject; + if (!raiseToSpeak) { + startRaiseToEarSensors(raiseChat); + } + startProgressTimer(playingMessageObject); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioDidStarted, messageObject); + + if (audioPlayer != null) { + try { + if (playingMessageObject.audioProgress != 0) { + int seekTo = (int) (audioPlayer.getDuration() * playingMessageObject.audioProgress); + audioPlayer.seekTo(seekTo); + } + } catch (Exception e2) { + playingMessageObject.audioProgress = 0; + playingMessageObject.audioProgressSec = 0; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioProgressDidChanged, playingMessageObject.getId(), 0); + FileLog.e("tmessages", e2); + } + } else if (audioTrackPlayer != null) { + if (playingMessageObject.audioProgress == 1) { + playingMessageObject.audioProgress = 0; + } + fileDecodingQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (playingMessageObject != null && playingMessageObject.audioProgress != 0) { + lastPlayPcm = (long) (currentTotalPcmDuration * playingMessageObject.audioProgress); + seekOpusFile(playingMessageObject.audioProgress); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + synchronized (playerSync) { + freePlayerBuffers.addAll(usedPlayerBuffers); + usedPlayerBuffers.clear(); + } + decodingFinished = false; + checkPlayerQueue(); + } + }); + } + + if (playingMessageObject.isMusic()) { + Intent intent = new Intent(ApplicationLoader.applicationContext, MusicPlayerService.class); + ApplicationLoader.applicationContext.startService(intent); + } else { + Intent intent = new Intent(ApplicationLoader.applicationContext, MusicPlayerService.class); + ApplicationLoader.applicationContext.stopService(intent); + } + + return true; + } + + public void stopAudio() { + if (audioTrackPlayer == null && audioPlayer == null || playingMessageObject == null) { + return; + } + try { + if (audioPlayer != null) { + try { + audioPlayer.reset(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + audioPlayer.stop(); + } else if (audioTrackPlayer != null) { + audioTrackPlayer.pause(); + audioTrackPlayer.flush(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + if (audioPlayer != null) { + audioPlayer.release(); + audioPlayer = null; + } else if (audioTrackPlayer != null) { + synchronized (playerObjectSync) { + audioTrackPlayer.release(); + audioTrackPlayer = null; + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + stopProgressTimer(); + playingMessageObject = null; + downloadingCurrentMessage = false; + isPaused = false; + + Intent intent = new Intent(ApplicationLoader.applicationContext, MusicPlayerService.class); + ApplicationLoader.applicationContext.stopService(intent); + } + + public AudioInfo getAudioInfo() { + return audioInfo; + } + + public boolean isShuffleMusic() { + return shuffleMusic; + } + + public int getRepeatMode() { + return repeatMode; + } + + public void toggleShuffleMusic() { + shuffleMusic = !shuffleMusic; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("shuffleMusic", shuffleMusic); + editor.commit(); + if (shuffleMusic) { + buildShuffledPlayList(); + currentPlaylistNum = 0; + } else { + if (playingMessageObject != null) { + currentPlaylistNum = playlist.indexOf(playingMessageObject); + if (currentPlaylistNum == -1) { + playlist.clear(); + shuffledPlaylist.clear(); + cleanupPlayer(true, true); + } + } + } + } + + public void toggleRepeatMode() { + repeatMode++; + if (repeatMode > 2) { + repeatMode = 0; + } + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("repeatMode", repeatMode); + editor.commit(); + } + + public boolean pauseAudio(MessageObject messageObject) { + if (audioTrackPlayer == null && audioPlayer == null || messageObject == null || playingMessageObject == null || playingMessageObject != null && playingMessageObject.getId() != messageObject.getId()) { + return false; + } + stopProgressTimer(); + try { + if (audioPlayer != null) { + audioPlayer.pause(); + } else if (audioTrackPlayer != null) { + audioTrackPlayer.pause(); + } + isPaused = true; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioPlayStateChanged, playingMessageObject.getId()); + } catch (Exception e) { + FileLog.e("tmessages", e); + isPaused = false; + return false; + } + return true; + } + + public boolean resumeAudio(MessageObject messageObject) { + if (audioTrackPlayer == null && audioPlayer == null || messageObject == null || playingMessageObject == null || playingMessageObject != null && playingMessageObject.getId() != messageObject.getId()) { + return false; + } + + try { + startProgressTimer(messageObject); + if (audioPlayer != null) { + audioPlayer.start(); + } else if (audioTrackPlayer != null) { + audioTrackPlayer.play(); + checkPlayerQueue(); + } + checkAudioFocus(messageObject); + isPaused = false; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioPlayStateChanged, playingMessageObject.getId()); + } catch (Exception e) { + FileLog.e("tmessages", e); + return false; + } + return true; + } + + public boolean isPlayingAudio(MessageObject messageObject) { + return !(audioTrackPlayer == null && audioPlayer == null || messageObject == null || playingMessageObject == null || playingMessageObject != null && (playingMessageObject.getId() != messageObject.getId() || downloadingCurrentMessage)); + } + + public boolean isAudioPaused() { + return isPaused || downloadingCurrentMessage; + } + + public boolean isDownloadingCurrentMessage() { + return downloadingCurrentMessage; + } + + public void startRecording(final long dialog_id, final MessageObject reply_to_msg, final boolean asAdmin) { + boolean paused = false; + if (playingMessageObject != null && isPlayingAudio(playingMessageObject) && !isAudioPaused()) { + paused = true; + pauseAudio(playingMessageObject); + } + + try { + Vibrator v = (Vibrator) ApplicationLoader.applicationContext.getSystemService(Context.VIBRATOR_SERVICE); + v.vibrate(50); + //NotificationsController.getInstance().playRecordSound(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + recordQueue.postRunnable(recordStartRunnable = new Runnable() { + @Override + public void run() { + if (audioRecorder != null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + recordStartRunnable = null; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStartError); + } + }); + return; + } + + recordingAudio = new TLRPC.TL_document(); + recordingAudio.dc_id = Integer.MIN_VALUE; + recordingAudio.id = UserConfig.lastLocalId; + recordingAudio.user_id = UserConfig.getClientUserId(); + recordingAudio.mime_type = "audio/ogg"; + recordingAudio.thumb = new TLRPC.TL_photoSizeEmpty(); + recordingAudio.thumb.type = "s"; + UserConfig.lastLocalId--; + UserConfig.saveConfig(false); + + recordingAudioFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), FileLoader.getAttachFileName(recordingAudio)); + + try { + if (startRecord(recordingAudioFile.getAbsolutePath()) == 0) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + recordStartRunnable = null; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStartError); + } + }); + return; + } + //if (Build.VERSION.SDK_INT >= 11) { + // audioRecorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, 16000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, recordBufferSize * 10); + //} else { + audioRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, 16000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, recordBufferSize * 10); + //} + recordStartTime = System.currentTimeMillis(); + recordTimeCount = 0; + samplesCount = 0; + recordDialogId = dialog_id; + recordReplyingMessageObject = reply_to_msg; + recordAsAdmin = asAdmin; + fileBuffer.rewind(); + + audioRecorder.startRecording(); + } catch (Exception e) { + FileLog.e("tmessages", e); + recordingAudio = null; + stopRecord(); + recordingAudioFile.delete(); + recordingAudioFile = null; + try { + audioRecorder.release(); + audioRecorder = null; + } catch (Exception e2) { + FileLog.e("tmessages", e2); + } + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + recordStartRunnable = null; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStartError); + } + }); + return; + } + + recordQueue.postRunnable(recordRunnable); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + recordStartRunnable = null; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStarted); + } + }); + } + }, paused ? 500 : 50); + } + + public void generateWaveform(MessageObject messageObject) { + final String id = messageObject.getId() + "_" + messageObject.getDialogId(); + final String path = FileLoader.getPathToMessage(messageObject.messageOwner).getAbsolutePath(); + if (generatingWaveform.containsKey(id)) { + return; + } + generatingWaveform.put(id, messageObject); + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + final byte[] waveform = MediaController.getInstance().getWaveform(path); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessageObject messageObject = generatingWaveform.remove(id); + if (messageObject == null) { + return; + } + if (waveform != null) { + for (int a = 0; a < messageObject.getDocument().attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = messageObject.getDocument().attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + attribute.waveform = waveform; + attribute.flags |= 4; + break; + } + } + TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); + messagesRes.messages.add(messageObject.messageOwner); + MessagesStorage.getInstance().putMessages(messagesRes, messageObject.getDialogId(), -1, 0, 0, false); + ArrayList arrayList = new ArrayList<>(); + arrayList.add(messageObject); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.replaceMessagesObjects, messageObject.getDialogId(), arrayList); + } + } + }); + } + }); + } + + private void stopRecordingInternal(final int send) { + if (send != 0) { + final TLRPC.TL_document audioToSend = recordingAudio; + final File recordingAudioFileToSend = recordingAudioFile; + fileEncodingQueue.postRunnable(new Runnable() { + @Override + public void run() { + stopRecord(); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + audioToSend.date = ConnectionsManager.getInstance().getCurrentTime(); + audioToSend.size = (int) recordingAudioFileToSend.length(); + TLRPC.TL_documentAttributeAudio attributeAudio = new TLRPC.TL_documentAttributeAudio(); + attributeAudio.voice = true; + attributeAudio.waveform = getWaveform2(recordSamples, recordSamples.length); //getWaveform(recordingAudioFileToSend.getAbsolutePath()); + if (attributeAudio.waveform != null) { + attributeAudio.flags |= 4; + } + long duration = recordTimeCount; + attributeAudio.duration = (int) (recordTimeCount / 1000); + audioToSend.attributes.add(attributeAudio); + if (duration > 700) { + if (send == 1) { + SendMessagesHelper.getInstance().sendMessage(audioToSend, null, recordingAudioFileToSend.getAbsolutePath(), recordDialogId, recordReplyingMessageObject, recordAsAdmin, null, null); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.audioDidSent, send == 2 ? audioToSend : null, send == 2 ? recordingAudioFileToSend.getAbsolutePath() : null); + } else { + recordingAudioFileToSend.delete(); + } + } + }); + } + }); + } + try { + if (audioRecorder != null) { + audioRecorder.release(); + audioRecorder = null; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + recordingAudio = null; + recordingAudioFile = null; + } + + public void stopRecording(final int send) { + if (recordStartRunnable != null) { + recordQueue.cancelRunnable(recordStartRunnable); + recordStartRunnable = null; + } + recordQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (audioRecorder == null) { + return; + } + try { + sendAfterDone = send; + audioRecorder.stop(); + } catch (Exception e) { + FileLog.e("tmessages", e); + if (recordingAudioFile != null) { + recordingAudioFile.delete(); + } + } + if (send == 0) { + stopRecordingInternal(0); + } + try { + Vibrator v = (Vibrator) ApplicationLoader.applicationContext.getSystemService(Context.VIBRATOR_SERVICE); + v.vibrate(50); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.recordStopped); + } + }); + } + }); + } + + public static void saveFile(String fullPath, Context context, final int type, final String name, final String mime) { + if (fullPath == null) { + return; + } + + File file = null; + if (fullPath != null && fullPath.length() != 0) { + file = new File(fullPath); + if (!file.exists()) { + file = null; + } + } + + if (file == null) { + return; + } + + final File sourceFile = file; + if (sourceFile.exists()) { + ProgressDialog progressDialog = null; + if (context != null) { + try { + progressDialog = new ProgressDialog(context); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); + progressDialog.setMax(100); + progressDialog.show(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + final ProgressDialog finalProgress = progressDialog; + + new Thread(new Runnable() { + @Override + public void run() { + try { + File destFile = null; + if (type == 0) { + destFile = AndroidUtilities.generatePicturePath(); + } else if (type == 1) { + destFile = AndroidUtilities.generateVideoPath(); + } else if (type == 2) { + File f = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); + f.mkdir(); + destFile = new File(f, name); + } else if (type == 3) { + File f = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC); + f.mkdirs(); + destFile = new File(f, name); + } + + if (!destFile.exists()) { + destFile.createNewFile(); + } + FileChannel source = null; + FileChannel destination = null; + boolean result = true; + long lastProgress = System.currentTimeMillis() - 500; + try { + source = new FileInputStream(sourceFile).getChannel(); + destination = new FileOutputStream(destFile).getChannel(); + long size = source.size(); + for (long a = 0; a < size; a += 4096) { + destination.transferFrom(source, a, Math.min(4096, size - a)); + if (finalProgress != null) { + if (lastProgress <= System.currentTimeMillis() - 500) { + lastProgress = System.currentTimeMillis(); + final int progress = (int) ((float) a / (float) size * 100); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + finalProgress.setProgress(progress); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + result = false; + } finally { + if (source != null) { + source.close(); + } + if (destination != null) { + destination.close(); + } + } + + if (result) { + if (type == 2) { + if (Build.VERSION.SDK_INT >= 12) { + DownloadManager downloadManager = (DownloadManager) ApplicationLoader.applicationContext.getSystemService(Context.DOWNLOAD_SERVICE); + downloadManager.addCompletedDownload(destFile.getName(), destFile.getName(), false, mime, destFile.getAbsolutePath(), destFile.length(), true); + } + } else { + AndroidUtilities.addMediaToGallery(Uri.fromFile(destFile)); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (finalProgress != null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + finalProgress.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + } + }).start(); + } + } + + public static boolean isWebp(Uri uri) { + InputStream inputStream = null; + try { + inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri); + byte[] header = new byte[12]; + if (inputStream.read(header, 0, 12) == 12) { + String str = new String(header); + if (str != null) { + str = str.toLowerCase(); + if (str.startsWith("riff") && str.endsWith("webp")) { + return true; + } + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (Exception e2) { + FileLog.e("tmessages", e2); + } + } + return false; + } + + public static boolean isGif(Uri uri) { + InputStream inputStream = null; + try { + inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri); + byte[] header = new byte[3]; + if (inputStream.read(header, 0, 3) == 3) { + String str = new String(header); + if (str != null && str.equalsIgnoreCase("gif")) { + return true; + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (Exception e2) { + FileLog.e("tmessages", e2); + } + } + return false; + } + + public static String getFileName(Uri uri) { + String result = null; + if (uri.getScheme().equals("content")) { + Cursor cursor = ApplicationLoader.applicationContext.getContentResolver().query(uri, null, null, null, null); + try { + if (cursor.moveToFirst()) { + result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + if (result == null) { + result = uri.getPath(); + int cut = result.lastIndexOf('/'); + if (cut != -1) { + result = result.substring(cut + 1); + } + } + return result; + } + + public static String copyFileToCache(Uri uri, String ext) { + InputStream inputStream = null; + FileOutputStream output = null; + try { + String name = getFileName(uri); + if (name == null) { + int id = UserConfig.lastLocalId; + UserConfig.lastLocalId--; + UserConfig.saveConfig(false); + name = String.format(Locale.US, "%d.%s", id, ext); + } + inputStream = ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri); + File f = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), name); + output = new FileOutputStream(f); + byte[] buffer = new byte[1024 * 20]; + int len; + while ((len = inputStream.read(buffer)) != -1) { + output.write(buffer, 0, len); + } + return f.getAbsolutePath(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + try { + if (inputStream != null) { + inputStream.close(); + } + } catch (Exception e2) { + FileLog.e("tmessages", e2); + } + try { + if (output != null) { + output.close(); + } + } catch (Exception e2) { + FileLog.e("tmessages", e2); + } + } + return null; + } + + public void toggleSaveToGallery() { + saveToGallery = !saveToGallery; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("save_gallery", saveToGallery); + editor.commit(); + checkSaveToGalleryFiles(); + } + + public void toggleAutoplayGifs() { + autoplayGifs = !autoplayGifs; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("autoplay_gif", autoplayGifs); + editor.commit(); + } + + public void toogleRaiseToSpeak() { + raiseToSpeak = !raiseToSpeak; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("raise_to_speak", raiseToSpeak); + editor.commit(); + } + + public void toggleCustomTabs() { + customTabs = !customTabs; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("custom_tabs", customTabs); + editor.commit(); + } + + public void toggleDirectShare() { + directShare = !directShare; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("direct_share", directShare); + editor.commit(); + } + + public void checkSaveToGalleryFiles() { + try { + File telegramPath = new File(Environment.getExternalStorageDirectory(), "Telegram"); + File imagePath = new File(telegramPath, "Telegram Images"); + imagePath.mkdir(); + File videoPath = new File(telegramPath, "Telegram Video"); + videoPath.mkdir(); + + if (saveToGallery) { + if (imagePath.isDirectory()) { + new File(imagePath, ".nomedia").delete(); + } + if (videoPath.isDirectory()) { + new File(videoPath, ".nomedia").delete(); + } + } else { + if (imagePath.isDirectory()) { + new File(imagePath, ".nomedia").createNewFile(); + } + if (videoPath.isDirectory()) { + new File(videoPath, ".nomedia").createNewFile(); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public boolean canSaveToGallery() { + return saveToGallery; + } + + public boolean canAutoplayGifs() { + return autoplayGifs; + } + + public boolean canRaiseToSpeak() { + return raiseToSpeak; + } + + public boolean canCustomTabs() { + return customTabs; + } + + public boolean canDirectShare() { + return directShare; + } + + public static void loadGalleryPhotosAlbums(final int guid) { + Thread thread = new Thread(new Runnable() { + @Override + public void run() { + final ArrayList albumsSorted = new ArrayList<>(); + final ArrayList videoAlbumsSorted = new ArrayList<>(); + HashMap albums = new HashMap<>(); + AlbumEntry allPhotosAlbum = null; + String cameraFolder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath() + "/" + "Camera/"; + Integer cameraAlbumId = null; + Integer cameraAlbumVideoId = null; + + Cursor cursor = null; + try { + if (Build.VERSION.SDK_INT < 23 || Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + cursor = MediaStore.Images.Media.query(ApplicationLoader.applicationContext.getContentResolver(), MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projectionPhotos, null, null, MediaStore.Images.Media.DATE_TAKEN + " DESC"); + if (cursor != null) { + int imageIdColumn = cursor.getColumnIndex(MediaStore.Images.Media._ID); + int bucketIdColumn = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_ID); + int bucketNameColumn = cursor.getColumnIndex(MediaStore.Images.Media.BUCKET_DISPLAY_NAME); + int dataColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATA); + int dateColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATE_TAKEN); + int orientationColumn = cursor.getColumnIndex(MediaStore.Images.Media.ORIENTATION); + + while (cursor.moveToNext()) { + int imageId = cursor.getInt(imageIdColumn); + int bucketId = cursor.getInt(bucketIdColumn); + String bucketName = cursor.getString(bucketNameColumn); + String path = cursor.getString(dataColumn); + long dateTaken = cursor.getLong(dateColumn); + int orientation = cursor.getInt(orientationColumn); + //Plus + if (path == null || path.length() == 0 || !iFilter.equals("*") && !path.toLowerCase().endsWith(iFilter)) {//|| !path.contains(".webp") + continue; + } + + PhotoEntry photoEntry = new PhotoEntry(bucketId, imageId, dateTaken, path, orientation, false); + + if (allPhotosAlbum == null) { + allPhotosAlbum = new AlbumEntry(0, LocaleController.getString("AllPhotos", R.string.AllPhotos), photoEntry, false); + albumsSorted.add(0, allPhotosAlbum); + } + if (allPhotosAlbum != null) { + allPhotosAlbum.addPhoto(photoEntry); + } + + AlbumEntry albumEntry = albums.get(bucketId); + if (albumEntry == null) { + albumEntry = new AlbumEntry(bucketId, bucketName, photoEntry, false); + albums.put(bucketId, albumEntry); + if (cameraAlbumId == null && cameraFolder != null && path != null && path.startsWith(cameraFolder)) { + albumsSorted.add(0, albumEntry); + cameraAlbumId = bucketId; + } else { + albumsSorted.add(albumEntry); + } + } + + albumEntry.addPhoto(photoEntry); + } + } + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } finally { + if (cursor != null) { + try { + cursor.close(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + try { + if (Build.VERSION.SDK_INT < 23 || Build.VERSION.SDK_INT >= 23 && ApplicationLoader.applicationContext.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + albums.clear(); + AlbumEntry allVideosAlbum = null; + cursor = MediaStore.Images.Media.query(ApplicationLoader.applicationContext.getContentResolver(), MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projectionVideo, null, null, MediaStore.Video.Media.DATE_TAKEN + " DESC"); + if (cursor != null) { + int imageIdColumn = cursor.getColumnIndex(MediaStore.Video.Media._ID); + int bucketIdColumn = cursor.getColumnIndex(MediaStore.Video.Media.BUCKET_ID); + int bucketNameColumn = cursor.getColumnIndex(MediaStore.Video.Media.BUCKET_DISPLAY_NAME); + int dataColumn = cursor.getColumnIndex(MediaStore.Video.Media.DATA); + int dateColumn = cursor.getColumnIndex(MediaStore.Video.Media.DATE_TAKEN); + + while (cursor.moveToNext()) { + int imageId = cursor.getInt(imageIdColumn); + int bucketId = cursor.getInt(bucketIdColumn); + String bucketName = cursor.getString(bucketNameColumn); + String path = cursor.getString(dataColumn); + long dateTaken = cursor.getLong(dateColumn); + + if (path == null || path.length() == 0) { + continue; + } + + PhotoEntry photoEntry = new PhotoEntry(bucketId, imageId, dateTaken, path, 0, true); + + if (allVideosAlbum == null) { + allVideosAlbum = new AlbumEntry(0, LocaleController.getString("AllVideo", R.string.AllVideo), photoEntry, true); + videoAlbumsSorted.add(0, allVideosAlbum); + } + if (allVideosAlbum != null) { + allVideosAlbum.addPhoto(photoEntry); + } + + AlbumEntry albumEntry = albums.get(bucketId); + if (albumEntry == null) { + albumEntry = new AlbumEntry(bucketId, bucketName, photoEntry, true); + albums.put(bucketId, albumEntry); + if (cameraAlbumVideoId == null && cameraFolder != null && path != null && path.startsWith(cameraFolder)) { + videoAlbumsSorted.add(0, albumEntry); + cameraAlbumVideoId = bucketId; + } else { + videoAlbumsSorted.add(albumEntry); + } + } + + albumEntry.addPhoto(photoEntry); + } + } + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } finally { + if (cursor != null) { + try { + cursor.close(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + final Integer cameraAlbumIdFinal = cameraAlbumId; + final Integer cameraAlbumVideoIdFinal = cameraAlbumVideoId; + final AlbumEntry allPhotosAlbumFinal = allPhotosAlbum; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + allPhotosAlbumEntry = allPhotosAlbumFinal; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.albumsDidLoaded, guid, albumsSorted, cameraAlbumIdFinal, videoAlbumsSorted, cameraAlbumVideoIdFinal); + } + }); + } + }); + thread.setPriority(Thread.MIN_PRIORITY); + thread.start(); + } + + public void scheduleVideoConvert(MessageObject messageObject) { + videoConvertQueue.add(messageObject); + if (videoConvertQueue.size() == 1) { + startVideoConvertFromQueue(); + } + } + + public void cancelVideoConvert(MessageObject messageObject) { + if (messageObject == null) { + synchronized (videoConvertSync) { + cancelCurrentVideoConversion = true; + } + } else { + if (!videoConvertQueue.isEmpty()) { + if (videoConvertQueue.get(0) == messageObject) { + synchronized (videoConvertSync) { + cancelCurrentVideoConversion = true; + } + } + videoConvertQueue.remove(messageObject); + } + } + } + + private void startVideoConvertFromQueue() { + if (!videoConvertQueue.isEmpty()) { + synchronized (videoConvertSync) { + cancelCurrentVideoConversion = false; + } + MessageObject messageObject = videoConvertQueue.get(0); + Intent intent = new Intent(ApplicationLoader.applicationContext, VideoEncodingService.class); + intent.putExtra("path", messageObject.messageOwner.attachPath); + ApplicationLoader.applicationContext.startService(intent); + VideoConvertRunnable.runConversion(messageObject); + } + } + + @SuppressLint("NewApi") + public static MediaCodecInfo selectCodec(String mimeType) { + int numCodecs = MediaCodecList.getCodecCount(); + MediaCodecInfo lastCodecInfo = null; + for (int i = 0; i < numCodecs; i++) { + MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i); + if (!codecInfo.isEncoder()) { + continue; + } + String[] types = codecInfo.getSupportedTypes(); + for (String type : types) { + if (type.equalsIgnoreCase(mimeType)) { + lastCodecInfo = codecInfo; + if (!lastCodecInfo.getName().equals("OMX.SEC.avc.enc")) { + return lastCodecInfo; + } else if (lastCodecInfo.getName().equals("OMX.SEC.AVC.Encoder")) { + return lastCodecInfo; + } + } + } + } + return lastCodecInfo; + } + + private static boolean isRecognizedFormat(int colorFormat) { + switch (colorFormat) { + case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar: + case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar: + case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar: + case MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar: + case MediaCodecInfo.CodecCapabilities.COLOR_TI_FormatYUV420PackedSemiPlanar: + return true; + default: + return false; + } + } + + @SuppressLint("NewApi") + public static int selectColorFormat(MediaCodecInfo codecInfo, String mimeType) { + MediaCodecInfo.CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(mimeType); + int lastColorFormat = 0; + for (int i = 0; i < capabilities.colorFormats.length; i++) { + int colorFormat = capabilities.colorFormats[i]; + if (isRecognizedFormat(colorFormat)) { + lastColorFormat = colorFormat; + if (!(codecInfo.getName().equals("OMX.SEC.AVC.Encoder") && colorFormat == 19)) { + return colorFormat; + } + } + } + return lastColorFormat; + } + + @TargetApi(16) + private int selectTrack(MediaExtractor extractor, boolean audio) { + int numTracks = extractor.getTrackCount(); + for (int i = 0; i < numTracks; i++) { + MediaFormat format = extractor.getTrackFormat(i); + String mime = format.getString(MediaFormat.KEY_MIME); + if (audio) { + if (mime.startsWith("audio/")) { + return i; + } + } else { + if (mime.startsWith("video/")) { + return i; + } + } + } + return -5; + } + + private void didWriteData(final MessageObject messageObject, final File file, final boolean last, final boolean error) { + final boolean firstWrite = videoConvertFirstWrite; + if (firstWrite) { + videoConvertFirstWrite = false; + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (error) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.FilePreparingFailed, messageObject, file.toString()); + } else { + if (firstWrite) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.FilePreparingStarted, messageObject, file.toString()); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.FileNewChunkAvailable, messageObject, file.toString(), last ? file.length() : 0); + } + if (error || last) { + synchronized (videoConvertSync) { + cancelCurrentVideoConversion = false; + } + videoConvertQueue.remove(messageObject); + startVideoConvertFromQueue(); + } + } + }); + } + + @TargetApi(16) + private long readAndWriteTrack(final MessageObject messageObject, MediaExtractor extractor, MP4Builder mediaMuxer, MediaCodec.BufferInfo info, long start, long end, File file, boolean isAudio) throws Exception { + int trackIndex = selectTrack(extractor, isAudio); + if (trackIndex >= 0) { + extractor.selectTrack(trackIndex); + MediaFormat trackFormat = extractor.getTrackFormat(trackIndex); + int muxerTrackIndex = mediaMuxer.addTrack(trackFormat, isAudio); + int maxBufferSize = trackFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE); + boolean inputDone = false; + if (start > 0) { + extractor.seekTo(start, MediaExtractor.SEEK_TO_PREVIOUS_SYNC); + } else { + extractor.seekTo(0, MediaExtractor.SEEK_TO_PREVIOUS_SYNC); + } + ByteBuffer buffer = ByteBuffer.allocateDirect(maxBufferSize); + long startTime = -1; + + checkConversionCanceled(); + long lastTimestamp = -100; + + while (!inputDone) { + checkConversionCanceled(); + + boolean eof = false; + int index = extractor.getSampleTrackIndex(); + if (index == trackIndex) { + info.size = extractor.readSampleData(buffer, 0); + if (info.size >= 0) { + info.presentationTimeUs = extractor.getSampleTime(); + } else { + info.size = 0; + eof = true; + } + + if (info.size > 0 && !eof) { + if (start > 0 && startTime == -1) { + startTime = info.presentationTimeUs; + } + if (end < 0 || info.presentationTimeUs < end) { + if (info.presentationTimeUs > lastTimestamp) { + info.offset = 0; + info.flags = extractor.getSampleFlags(); + if (mediaMuxer.writeSampleData(muxerTrackIndex, buffer, info, isAudio)) { + didWriteData(messageObject, file, false, false); + } + } + lastTimestamp = info.presentationTimeUs; + } else { + eof = true; + } + } + if (!eof) { + extractor.advance(); + } + } else if (index == -1) { + eof = true; + } else { + extractor.advance(); + } + if (eof) { + inputDone = true; + } + } + + extractor.unselectTrack(trackIndex); + return startTime; + } + return -1; + } + + private static class VideoConvertRunnable implements Runnable { + + private MessageObject messageObject; + + private VideoConvertRunnable(MessageObject message) { + messageObject = message; + } + + @Override + public void run() { + MediaController.getInstance().convertVideo(messageObject); + } + + public static void runConversion(final MessageObject obj) { + new Thread(new Runnable() { + @Override + public void run() { + try { + VideoConvertRunnable wrapper = new VideoConvertRunnable(obj); + Thread th = new Thread(wrapper, "VideoConvertRunnable"); + th.start(); + th.join(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }).start(); + } + } + + private void checkConversionCanceled() throws Exception { + boolean cancelConversion; + synchronized (videoConvertSync) { + cancelConversion = cancelCurrentVideoConversion; + } + if (cancelConversion) { + throw new RuntimeException("canceled conversion"); + } + } + + @TargetApi(16) + private boolean convertVideo(final MessageObject messageObject) { + String videoPath = messageObject.videoEditedInfo.originalPath; + long startTime = messageObject.videoEditedInfo.startTime; + long endTime = messageObject.videoEditedInfo.endTime; + int resultWidth = messageObject.videoEditedInfo.resultWidth; + int resultHeight = messageObject.videoEditedInfo.resultHeight; + int rotationValue = messageObject.videoEditedInfo.rotationValue; + int originalWidth = messageObject.videoEditedInfo.originalWidth; + int originalHeight = messageObject.videoEditedInfo.originalHeight; + int bitrate = messageObject.videoEditedInfo.bitrate; + int rotateRender = 0; + File cacheFile = new File(messageObject.messageOwner.attachPath); + + if (Build.VERSION.SDK_INT < 18 && resultHeight > resultWidth && resultWidth != originalWidth && resultHeight != originalHeight) { + int temp = resultHeight; + resultHeight = resultWidth; + resultWidth = temp; + rotationValue = 90; + rotateRender = 270; + } else if (Build.VERSION.SDK_INT > 20) { + if (rotationValue == 90) { + int temp = resultHeight; + resultHeight = resultWidth; + resultWidth = temp; + rotationValue = 0; + rotateRender = 270; + } else if (rotationValue == 180) { + rotateRender = 180; + rotationValue = 0; + } else if (rotationValue == 270) { + int temp = resultHeight; + resultHeight = resultWidth; + resultWidth = temp; + rotationValue = 0; + rotateRender = 90; + } + } + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("videoconvert", Activity.MODE_PRIVATE); + boolean isPreviousOk = preferences.getBoolean("isPreviousOk", true); + preferences.edit().putBoolean("isPreviousOk", false).commit(); + + File inputFile = new File(videoPath); + if (!inputFile.canRead() || !isPreviousOk) { + didWriteData(messageObject, cacheFile, true, true); + preferences.edit().putBoolean("isPreviousOk", true).commit(); + return false; + } + + videoConvertFirstWrite = true; + boolean error = false; + long videoStartTime = startTime; + + long time = System.currentTimeMillis(); + + if (resultWidth != 0 && resultHeight != 0) { + MP4Builder mediaMuxer = null; + MediaExtractor extractor = null; + + try { + MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); + Mp4Movie movie = new Mp4Movie(); + movie.setCacheFile(cacheFile); + movie.setRotation(rotationValue); + movie.setSize(resultWidth, resultHeight); + mediaMuxer = new MP4Builder().createMovie(movie); + extractor = new MediaExtractor(); + extractor.setDataSource(inputFile.toString()); + + checkConversionCanceled(); + + //if (resultWidth != originalWidth || resultHeight != originalHeight) { + if (resultWidth != originalWidth || resultHeight != originalHeight || inputFile.length() - messageObject.messageOwner.media.document.size > 5) { + int videoIndex; + videoIndex = selectTrack(extractor, false); + if (videoIndex >= 0) { + MediaCodec decoder = null; + MediaCodec encoder = null; + InputSurface inputSurface = null; + OutputSurface outputSurface = null; + + try { + long videoTime = -1; + boolean outputDone = false; + boolean inputDone = false; + boolean decoderDone = false; + int swapUV = 0; + int videoTrackIndex = -5; + + int colorFormat; + int processorType = PROCESSOR_TYPE_OTHER; + String manufacturer = Build.MANUFACTURER.toLowerCase(); + if (Build.VERSION.SDK_INT < 18) { + MediaCodecInfo codecInfo = selectCodec(MIME_TYPE); + colorFormat = selectColorFormat(codecInfo, MIME_TYPE); + if (colorFormat == 0) { + throw new RuntimeException("no supported color format"); + } + String codecName = codecInfo.getName(); + if (codecName.contains("OMX.qcom.")) { + processorType = PROCESSOR_TYPE_QCOM; + if (Build.VERSION.SDK_INT == 16) { + if (manufacturer.equals("lge") || manufacturer.equals("nokia")) { + swapUV = 1; + } + } + } else if (codecName.contains("OMX.Intel.")) { + processorType = PROCESSOR_TYPE_INTEL; + } else if (codecName.equals("OMX.MTK.VIDEO.ENCODER.AVC")) { + processorType = PROCESSOR_TYPE_MTK; + } else if (codecName.equals("OMX.SEC.AVC.Encoder")) { + processorType = PROCESSOR_TYPE_SEC; + swapUV = 1; + } else if (codecName.equals("OMX.TI.DUCATI1.VIDEO.H264E")) { + processorType = PROCESSOR_TYPE_TI; + } + FileLog.e("tmessages", "codec = " + codecInfo.getName() + " manufacturer = " + manufacturer + "device = " + Build.MODEL); + } else { + colorFormat = MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface; + } + FileLog.e("tmessages", "colorFormat = " + colorFormat); + + int resultHeightAligned = resultHeight; + int padding = 0; + int bufferSize = resultWidth * resultHeight * 3 / 2; + if (processorType == PROCESSOR_TYPE_OTHER) { + if (resultHeight % 16 != 0) { + resultHeightAligned += (16 - (resultHeight % 16)); + padding = resultWidth * (resultHeightAligned - resultHeight); + bufferSize += padding * 5 / 4; + } + } else if (processorType == PROCESSOR_TYPE_QCOM) { + if (!manufacturer.toLowerCase().equals("lge")) { + int uvoffset = (resultWidth * resultHeight + 2047) & ~2047; + padding = uvoffset - (resultWidth * resultHeight); + bufferSize += padding; + } + } else if (processorType == PROCESSOR_TYPE_TI) { + //resultHeightAligned = 368; + //bufferSize = resultWidth * resultHeightAligned * 3 / 2; + //resultHeightAligned += (16 - (resultHeight % 16)); + //padding = resultWidth * (resultHeightAligned - resultHeight); + //bufferSize += padding * 5 / 4; + } else if (processorType == PROCESSOR_TYPE_MTK) { + if (manufacturer.equals("baidu")) { + resultHeightAligned += (16 - (resultHeight % 16)); + padding = resultWidth * (resultHeightAligned - resultHeight); + bufferSize += padding * 5 / 4; + } + } + + extractor.selectTrack(videoIndex); + if (startTime > 0) { + extractor.seekTo(startTime, MediaExtractor.SEEK_TO_PREVIOUS_SYNC); + } else { + extractor.seekTo(0, MediaExtractor.SEEK_TO_PREVIOUS_SYNC); + } + MediaFormat inputFormat = extractor.getTrackFormat(videoIndex); + + MediaFormat outputFormat = MediaFormat.createVideoFormat(MIME_TYPE, resultWidth, resultHeight); + outputFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat); + outputFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitrate != 0 ? bitrate : 921600); + outputFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 25); + outputFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10); + if (Build.VERSION.SDK_INT < 18) { + outputFormat.setInteger("stride", resultWidth + 32); + outputFormat.setInteger("slice-height", resultHeight); + } + + encoder = MediaCodec.createEncoderByType(MIME_TYPE); + encoder.configure(outputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); + if (Build.VERSION.SDK_INT >= 18) { + inputSurface = new InputSurface(encoder.createInputSurface()); + inputSurface.makeCurrent(); + } + encoder.start(); + + decoder = MediaCodec.createDecoderByType(inputFormat.getString(MediaFormat.KEY_MIME)); + if (Build.VERSION.SDK_INT >= 18) { + outputSurface = new OutputSurface(); + } else { + outputSurface = new OutputSurface(resultWidth, resultHeight, rotateRender); + } + decoder.configure(inputFormat, outputSurface.getSurface(), null, 0); + decoder.start(); + + final int TIMEOUT_USEC = 2500; + ByteBuffer[] decoderInputBuffers = null; + ByteBuffer[] encoderOutputBuffers = null; + ByteBuffer[] encoderInputBuffers = null; + if (Build.VERSION.SDK_INT < 21) { + decoderInputBuffers = decoder.getInputBuffers(); + encoderOutputBuffers = encoder.getOutputBuffers(); + if (Build.VERSION.SDK_INT < 18) { + encoderInputBuffers = encoder.getInputBuffers(); + } + } + + checkConversionCanceled(); + + while (!outputDone) { + checkConversionCanceled(); + if (!inputDone) { + boolean eof = false; + int index = extractor.getSampleTrackIndex(); + if (index == videoIndex) { + int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC); + if (inputBufIndex >= 0) { + ByteBuffer inputBuf; + if (Build.VERSION.SDK_INT < 21) { + inputBuf = decoderInputBuffers[inputBufIndex]; + } else { + inputBuf = decoder.getInputBuffer(inputBufIndex); + } + int chunkSize = extractor.readSampleData(inputBuf, 0); + if (chunkSize < 0) { + decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM); + inputDone = true; + } else { + decoder.queueInputBuffer(inputBufIndex, 0, chunkSize, extractor.getSampleTime(), 0); + extractor.advance(); + } + } + } else if (index == -1) { + eof = true; + } + if (eof) { + int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC); + if (inputBufIndex >= 0) { + decoder.queueInputBuffer(inputBufIndex, 0, 0, 0L, MediaCodec.BUFFER_FLAG_END_OF_STREAM); + inputDone = true; + } + } + } + + boolean decoderOutputAvailable = !decoderDone; + boolean encoderOutputAvailable = true; + while (decoderOutputAvailable || encoderOutputAvailable) { + checkConversionCanceled(); + int encoderStatus = encoder.dequeueOutputBuffer(info, TIMEOUT_USEC); + if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { + encoderOutputAvailable = false; + } else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { + if (Build.VERSION.SDK_INT < 21) { + encoderOutputBuffers = encoder.getOutputBuffers(); + } + } else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { + MediaFormat newFormat = encoder.getOutputFormat(); + if (videoTrackIndex == -5) { + videoTrackIndex = mediaMuxer.addTrack(newFormat, false); + } + } else if (encoderStatus < 0) { + throw new RuntimeException("unexpected result from encoder.dequeueOutputBuffer: " + encoderStatus); + } else { + ByteBuffer encodedData; + if (Build.VERSION.SDK_INT < 21) { + encodedData = encoderOutputBuffers[encoderStatus]; + } else { + encodedData = encoder.getOutputBuffer(encoderStatus); + } + if (encodedData == null) { + throw new RuntimeException("encoderOutputBuffer " + encoderStatus + " was null"); + } + if (info.size > 1) { + if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) { + if (mediaMuxer.writeSampleData(videoTrackIndex, encodedData, info, false)) { + didWriteData(messageObject, cacheFile, false, false); + } + } else if (videoTrackIndex == -5) { + byte[] csd = new byte[info.size]; + encodedData.limit(info.offset + info.size); + encodedData.position(info.offset); + encodedData.get(csd); + ByteBuffer sps = null; + ByteBuffer pps = null; + for (int a = info.size - 1; a >= 0; a--) { + if (a > 3) { + if (csd[a] == 1 && csd[a - 1] == 0 && csd[a - 2] == 0 && csd[a - 3] == 0) { + sps = ByteBuffer.allocate(a - 3); + pps = ByteBuffer.allocate(info.size - (a - 3)); + sps.put(csd, 0, a - 3).position(0); + pps.put(csd, a - 3, info.size - (a - 3)).position(0); + break; + } + } else { + break; + } + } + + MediaFormat newFormat = MediaFormat.createVideoFormat(MIME_TYPE, resultWidth, resultHeight); + if (sps != null && pps != null) { + newFormat.setByteBuffer("csd-0", sps); + newFormat.setByteBuffer("csd-1", pps); + } + videoTrackIndex = mediaMuxer.addTrack(newFormat, false); + } + } + outputDone = (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0; + encoder.releaseOutputBuffer(encoderStatus, false); + } + if (encoderStatus != MediaCodec.INFO_TRY_AGAIN_LATER) { + continue; + } + + if (!decoderDone) { + int decoderStatus = decoder.dequeueOutputBuffer(info, TIMEOUT_USEC); + if (decoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) { + decoderOutputAvailable = false; + } else if (decoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { + + } else if (decoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { + MediaFormat newFormat = decoder.getOutputFormat(); + FileLog.e("tmessages", "newFormat = " + newFormat); + } else if (decoderStatus < 0) { + throw new RuntimeException("unexpected result from decoder.dequeueOutputBuffer: " + decoderStatus); + } else { + boolean doRender; + if (Build.VERSION.SDK_INT >= 18) { + doRender = info.size != 0; + } else { + doRender = info.size != 0 || info.presentationTimeUs != 0; + } + if (endTime > 0 && info.presentationTimeUs >= endTime) { + inputDone = true; + decoderDone = true; + doRender = false; + info.flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM; + } + if (startTime > 0 && videoTime == -1) { + if (info.presentationTimeUs < startTime) { + doRender = false; + FileLog.e("tmessages", "drop frame startTime = " + startTime + " present time = " + info.presentationTimeUs); + } else { + videoTime = info.presentationTimeUs; + } + } + decoder.releaseOutputBuffer(decoderStatus, doRender); + if (doRender) { + boolean errorWait = false; + try { + outputSurface.awaitNewImage(); + } catch (Exception e) { + errorWait = true; + FileLog.e("tmessages", e); + } + if (!errorWait) { + if (Build.VERSION.SDK_INT >= 18) { + outputSurface.drawImage(false); + inputSurface.setPresentationTime(info.presentationTimeUs * 1000); + inputSurface.swapBuffers(); + } else { + int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC); + if (inputBufIndex >= 0) { + outputSurface.drawImage(true); + ByteBuffer rgbBuf = outputSurface.getFrame(); + ByteBuffer yuvBuf = encoderInputBuffers[inputBufIndex]; + yuvBuf.clear(); + Utilities.convertVideoFrame(rgbBuf, yuvBuf, colorFormat, resultWidth, resultHeight, padding, swapUV); + encoder.queueInputBuffer(inputBufIndex, 0, bufferSize, info.presentationTimeUs, 0); + } else { + FileLog.e("tmessages", "input buffer not available"); + } + } + } + } + if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { + decoderOutputAvailable = false; + FileLog.e("tmessages", "decoder stream end"); + if (Build.VERSION.SDK_INT >= 18) { + encoder.signalEndOfInputStream(); + } else { + int inputBufIndex = encoder.dequeueInputBuffer(TIMEOUT_USEC); + if (inputBufIndex >= 0) { + encoder.queueInputBuffer(inputBufIndex, 0, 1, info.presentationTimeUs, MediaCodec.BUFFER_FLAG_END_OF_STREAM); + } + } + } + } + } + } + } + if (videoTime != -1) { + videoStartTime = videoTime; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + error = true; + } + + extractor.unselectTrack(videoIndex); + + if (outputSurface != null) { + outputSurface.release(); + } + if (inputSurface != null) { + inputSurface.release(); + } + if (decoder != null) { + decoder.stop(); + decoder.release(); + } + if (encoder != null) { + encoder.stop(); + encoder.release(); + } + + checkConversionCanceled(); + } + } else { + long videoTime = readAndWriteTrack(messageObject, extractor, mediaMuxer, info, startTime, endTime, cacheFile, false); + if (videoTime != -1) { + videoStartTime = videoTime; + } + } + if (!error) { + readAndWriteTrack(messageObject, extractor, mediaMuxer, info, videoStartTime, endTime, cacheFile, true); + } + } catch (Exception e) { + error = true; + FileLog.e("tmessages", e); + } finally { + if (extractor != null) { + extractor.release(); + } + if (mediaMuxer != null) { + try { + mediaMuxer.finishMovie(false); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + FileLog.e("tmessages", "time = " + (System.currentTimeMillis() - time)); + } + } else { + preferences.edit().putBoolean("isPreviousOk", true).commit(); + didWriteData(messageObject, cacheFile, true, true); + return false; + } + preferences.edit().putBoolean("isPreviousOk", true).commit(); + didWriteData(messageObject, cacheFile, true, error); + return true; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java new file mode 100644 index 00000000..b41d0256 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessageObject.java @@ -0,0 +1,1769 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.content.SharedPreferences; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.text.Layout; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.text.style.URLSpan; +import android.text.util.Linkify; + +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.TypefaceSpan; +import org.telegram.ui.Components.URLSpanBotCommand; +import org.telegram.ui.Components.URLSpanNoUnderline; +import org.telegram.ui.Components.URLSpanNoUnderlineBold; +import org.telegram.ui.Components.URLSpanReplacement; + +import java.io.File; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class MessageObject { + + public static final int MESSAGE_SEND_STATE_SENDING = 1; + public static final int MESSAGE_SEND_STATE_SENT = 0; + public static final int MESSAGE_SEND_STATE_SEND_ERROR = 2; + + public TLRPC.Message messageOwner; + public CharSequence messageText; + public CharSequence linkDescription; + public CharSequence caption; + public MessageObject replyMessageObject; + public int type = 1000; + public int contentType; + public String dateKey; + public String monthKey; + public boolean deleted; + public float audioProgress; + public int audioProgressSec; + public ArrayList photoThumbs; + public VideoEditedInfo videoEditedInfo; + public boolean viewsReloaded; + public int wantedBotKeyboardWidth; + public boolean attachPathExists; + public boolean mediaExists; + + public boolean forceUpdate; + + public static TextPaint textPaint; + private static TextPaint botButtonPaint; + public static TextPaint textPaintRight = new TextPaint(Paint.ANTI_ALIAS_FLAG); + public static TextPaint textPaintLeft = new TextPaint(Paint.ANTI_ALIAS_FLAG); + public int lastLineWidth; + public int textWidth; + public int textHeight; + public int blockHeight = Integer.MAX_VALUE; + + protected int leftBound = 52;//52 + public boolean showAvatar = false; + public boolean showMyAvatar = false; + public boolean showMyAvatarGroup = true; + + private boolean layoutCreated; + + public static Pattern urlPattern; + + public static class TextLayoutBlock { + public StaticLayout textLayout; + public float textXOffset; + public float textYOffset; + public int charactersOffset; + public int height; + } + + private static final int LINES_PER_BLOCK = 10; + + public ArrayList textLayoutBlocks; + + public MessageObject(TLRPC.Message message, AbstractMap users, boolean generateLayout) { + this(message, users, null, generateLayout); + } + + public MessageObject(TLRPC.Message message, AbstractMap users, AbstractMap chats, boolean generateLayout) { + if (textPaint == null) { + textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + textPaint.setColor(Theme.MSG_TEXT_COLOR); + textPaint.linkColor = Theme.MSG_LINK_TEXT_COLOR; + } + + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + + textPaint.setTextSize(AndroidUtilities.dp(MessagesController.getInstance().fontSize)); + + textPaintLeft.setColor(themePrefs.getInt("chatLTextColor", 0xff000000)); + textPaintLeft.linkColor = themePrefs.getInt("chatLLinkColor", def); + textPaintLeft.setTextSize(AndroidUtilities.dp(MessagesController.getInstance().fontSize)); + textPaint = textPaintLeft; + + textPaintRight.setColor(themePrefs.getInt("chatRTextColor", 0xff000000)); + textPaintRight.linkColor = themePrefs.getInt("chatRLinkColor", def); + textPaintRight.setTextSize(AndroidUtilities.dp(MessagesController.getInstance().fontSize)); + + showMyAvatar = themePrefs.getBoolean("chatShowOwnAvatar", false); + showMyAvatarGroup = themePrefs.getBoolean("chatShowOwnAvatarGroup", false); + showAvatar = themePrefs.getBoolean("chatShowContactAvatar", false); + int aSize = themePrefs.getInt("chatAvatarSize", 42); + leftBound = aSize + AndroidUtilities.dp(3); + + messageOwner = message; + + if (message.replyMessage != null) { + replyMessageObject = new MessageObject(message.replyMessage, users, chats, false); + } + + if(isOut()){ + textPaint = textPaintRight; + textPaint.linkColor = textPaintRight.linkColor; + }else{ + if(isReply()){ + textPaint = textPaintLeft; + textPaint.linkColor = textPaintLeft.linkColor; + } + } + + //if channel, always left + if(message.to_id != null && message.to_id.channel_id != 0 && !isMegagroup() && !isOutOwner()){ + textPaint = textPaintLeft; + textPaint.linkColor = textPaintLeft.linkColor; + } + + TLRPC.User fromUser = null; + if (message.from_id > 0) { + if (users != null) { + fromUser = users.get(message.from_id); + } + if (fromUser == null) { + fromUser = MessagesController.getInstance().getUser(message.from_id); + } + } + + if (message instanceof TLRPC.TL_messageService) { + if (message.action != null) { + if (message.action instanceof TLRPC.TL_messageActionChatCreate) { + if (isOut()) { + messageText = LocaleController.getString("ActionYouCreateGroup", R.string.ActionYouCreateGroup); + } else { + messageText = replaceWithLink(LocaleController.getString("ActionCreateGroup", R.string.ActionCreateGroup), "un1", fromUser); + } + } else if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) { + if (message.action.user_id == message.from_id) { + if (isOut()) { + messageText = LocaleController.getString("ActionYouLeftUser", R.string.ActionYouLeftUser); + } else { + messageText = replaceWithLink(LocaleController.getString("ActionLeftUser", R.string.ActionLeftUser), "un1", fromUser); + } + } else { + TLRPC.User whoUser = null; + if (users != null) { + whoUser = users.get(message.action.user_id); + } + if (whoUser == null) { + whoUser = MessagesController.getInstance().getUser(message.action.user_id); + } + if (isOut()) { + messageText = replaceWithLink(LocaleController.getString("ActionYouKickUser", R.string.ActionYouKickUser), "un2", whoUser); + } else if (message.action.user_id == UserConfig.getClientUserId()) { + messageText = replaceWithLink(LocaleController.getString("ActionKickUserYou", R.string.ActionKickUserYou), "un1", fromUser); + } else { + messageText = replaceWithLink(LocaleController.getString("ActionKickUser", R.string.ActionKickUser), "un2", whoUser); + messageText = replaceWithLink(messageText, "un1", fromUser); + } + } + } else if (message.action instanceof TLRPC.TL_messageActionChatAddUser) { + int singleUserId = messageOwner.action.user_id; + if (singleUserId == 0 && messageOwner.action.users.size() == 1) { + singleUserId = messageOwner.action.users.get(0); + } + if (singleUserId != 0) { + TLRPC.User whoUser = null; + if (users != null) { + whoUser = users.get(singleUserId); + } + if (whoUser == null) { + whoUser = MessagesController.getInstance().getUser(singleUserId); + } + if (singleUserId == message.from_id) { + if (message.to_id.channel_id != 0 && !isMegagroup()) { + messageText = LocaleController.getString("ChannelJoined", R.string.ChannelJoined); + } else { + if (message.to_id.channel_id != 0 && isMegagroup()) { + if (singleUserId == UserConfig.getClientUserId()) { + messageText = LocaleController.getString("ChannelMegaJoined", R.string.ChannelMegaJoined); + } else { + messageText = replaceWithLink(LocaleController.getString("ActionAddUserSelfMega", R.string.ActionAddUserSelfMega), "un1", fromUser); + } + } else if (isOut()) { + messageText = LocaleController.getString("ActionAddUserSelfYou", R.string.ActionAddUserSelfYou); + } else { + messageText = replaceWithLink(LocaleController.getString("ActionAddUserSelf", R.string.ActionAddUserSelf), "un1", fromUser); + } + } + } else { + if (isOut()) { + messageText = replaceWithLink(LocaleController.getString("ActionYouAddUser", R.string.ActionYouAddUser), "un2", whoUser); + } else if (singleUserId == UserConfig.getClientUserId()) { + if (message.to_id.channel_id != 0) { + if (isMegagroup()) { + messageText = replaceWithLink(LocaleController.getString("MegaAddedBy", R.string.MegaAddedBy), "un1", fromUser); + } else { + messageText = replaceWithLink(LocaleController.getString("ChannelAddedBy", R.string.ChannelAddedBy), "un1", fromUser); + } + } else { + messageText = replaceWithLink(LocaleController.getString("ActionAddUserYou", R.string.ActionAddUserYou), "un1", fromUser); + } + } else { + messageText = replaceWithLink(LocaleController.getString("ActionAddUser", R.string.ActionAddUser), "un2", whoUser); + messageText = replaceWithLink(messageText, "un1", fromUser); + } + } + } else { + if (isOut()) { + messageText = replaceWithLink(LocaleController.getString("ActionYouAddUser", R.string.ActionYouAddUser), "un2", message.action.users, users); + } else { + messageText = replaceWithLink(LocaleController.getString("ActionAddUser", R.string.ActionAddUser), "un2", message.action.users, users); + messageText = replaceWithLink(messageText, "un1", fromUser); + } + } + } else if (message.action instanceof TLRPC.TL_messageActionChatJoinedByLink) { + if (isOut()) { + messageText = LocaleController.getString("ActionInviteYou", R.string.ActionInviteYou); + } else { + messageText = replaceWithLink(LocaleController.getString("ActionInviteUser", R.string.ActionInviteUser), "un1", fromUser); + } + } else if (message.action instanceof TLRPC.TL_messageActionChatEditPhoto) { + if (message.to_id.channel_id != 0 && !isMegagroup()) { + messageText = LocaleController.getString("ActionChannelChangedPhoto", R.string.ActionChannelChangedPhoto); + } else { + if (isOut()) { + messageText = LocaleController.getString("ActionYouChangedPhoto", R.string.ActionYouChangedPhoto); + } else { + messageText = replaceWithLink(LocaleController.getString("ActionChangedPhoto", R.string.ActionChangedPhoto), "un1", fromUser); + } + } + } else if (message.action instanceof TLRPC.TL_messageActionChatEditTitle) { + if (message.to_id.channel_id != 0 && !isMegagroup()) { + messageText = LocaleController.getString("ActionChannelChangedTitle", R.string.ActionChannelChangedTitle).replace("un2", message.action.title); + } else { + if (isOut()) { + messageText = LocaleController.getString("ActionYouChangedTitle", R.string.ActionYouChangedTitle).replace("un2", message.action.title); + } else { + messageText = replaceWithLink(LocaleController.getString("ActionChangedTitle", R.string.ActionChangedTitle).replace("un2", message.action.title), "un1", fromUser); + } + } + } else if (message.action instanceof TLRPC.TL_messageActionChatDeletePhoto) { + if (message.to_id.channel_id != 0 && !isMegagroup()) { + messageText = LocaleController.getString("ActionChannelRemovedPhoto", R.string.ActionChannelRemovedPhoto); + } else { + if (isOut()) { + messageText = LocaleController.getString("ActionYouRemovedPhoto", R.string.ActionYouRemovedPhoto); + } else { + messageText = replaceWithLink(LocaleController.getString("ActionRemovedPhoto", R.string.ActionRemovedPhoto), "un1", fromUser); + } + } + } else if (message.action instanceof TLRPC.TL_messageActionTTLChange) { + if (message.action.ttl != 0) { + if (isOut()) { + messageText = LocaleController.formatString("MessageLifetimeChangedOutgoing", R.string.MessageLifetimeChangedOutgoing, AndroidUtilities.formatTTLString(message.action.ttl)); + } else { + messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, UserObject.getFirstName(fromUser), AndroidUtilities.formatTTLString(message.action.ttl)); + } + } else { + if (isOut()) { + messageText = LocaleController.getString("MessageLifetimeYouRemoved", R.string.MessageLifetimeYouRemoved); + } else { + messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, UserObject.getFirstName(fromUser)); + } + } + } else if (message.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) { + String date; + long time = ((long) message.date) * 1000; + if (LocaleController.getInstance().formatterDay != null && LocaleController.getInstance().formatterYear != null) { + date = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.getInstance().formatterYear.format(time), LocaleController.getInstance().formatterDay.format(time)); + } else { + date = "" + message.date; + } + TLRPC.User to_user = UserConfig.getCurrentUser(); + if (to_user == null) { + if (users != null) { + to_user = users.get(messageOwner.to_id.user_id); + } + if (to_user == null) { + to_user = MessagesController.getInstance().getUser(messageOwner.to_id.user_id); + } + } + String name = to_user != null ? UserObject.getFirstName(to_user) : ""; + messageText = LocaleController.formatString("NotificationUnrecognizedDevice", R.string.NotificationUnrecognizedDevice, name, date, message.action.title, message.action.address); + } else if (message.action instanceof TLRPC.TL_messageActionUserJoined) { + messageText = LocaleController.formatString("NotificationContactJoined", R.string.NotificationContactJoined, UserObject.getUserName(fromUser)); + } else if (message.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { + messageText = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, UserObject.getUserName(fromUser)); + } else if (message.action instanceof TLRPC.TL_messageEncryptedAction) { + if (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) { + if (isOut()) { + messageText = LocaleController.formatString("ActionTakeScreenshootYou", R.string.ActionTakeScreenshootYou); + } else { + messageText = replaceWithLink(LocaleController.getString("ActionTakeScreenshoot", R.string.ActionTakeScreenshoot), "un1", fromUser); + } + } else if (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { + TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL) message.action.encryptedAction; + if (action.ttl_seconds != 0) { + if (isOut()) { + messageText = LocaleController.formatString("MessageLifetimeChangedOutgoing", R.string.MessageLifetimeChangedOutgoing, AndroidUtilities.formatTTLString(action.ttl_seconds)); + } else { + messageText = LocaleController.formatString("MessageLifetimeChanged", R.string.MessageLifetimeChanged, UserObject.getFirstName(fromUser), AndroidUtilities.formatTTLString(action.ttl_seconds)); + } + } else { + if (isOut()) { + messageText = LocaleController.getString("MessageLifetimeYouRemoved", R.string.MessageLifetimeYouRemoved); + } else { + messageText = LocaleController.formatString("MessageLifetimeRemoved", R.string.MessageLifetimeRemoved, UserObject.getFirstName(fromUser)); + } + } + } + } else if (message.action instanceof TLRPC.TL_messageActionCreatedBroadcastList) { + messageText = LocaleController.formatString("YouCreatedBroadcastList", R.string.YouCreatedBroadcastList); + } else if (message.action instanceof TLRPC.TL_messageActionChannelCreate) { + if (isMegagroup()) { + messageText = LocaleController.getString("ActionCreateMega", R.string.ActionCreateMega); + } else { + messageText = LocaleController.getString("ActionCreateChannel", R.string.ActionCreateChannel); + } + } else if (message.action instanceof TLRPC.TL_messageActionChatMigrateTo) { + messageText = LocaleController.getString("ActionMigrateFromGroup", R.string.ActionMigrateFromGroup); + } else if (message.action instanceof TLRPC.TL_messageActionChannelMigrateFrom) { + messageText = LocaleController.getString("ActionMigrateFromGroup", R.string.ActionMigrateFromGroup); + } else if (message.action instanceof TLRPC.TL_messageActionPinMessage) { + generatePinMessageText(fromUser, fromUser == null ? chats.get(message.to_id.channel_id) : null); + } + } + } else if (!isMediaEmpty()) { + if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + messageText = LocaleController.getString("AttachPhoto", R.string.AttachPhoto); + } else if (isVideo()) { + messageText = LocaleController.getString("AttachVideo", R.string.AttachVideo); + } else if (isVoice()) { + messageText = LocaleController.getString("AttachAudio", R.string.AttachAudio); + } else if (message.media instanceof TLRPC.TL_messageMediaGeo || message.media instanceof TLRPC.TL_messageMediaVenue) { + messageText = LocaleController.getString("AttachLocation", R.string.AttachLocation); + } else if (message.media instanceof TLRPC.TL_messageMediaContact) { + messageText = LocaleController.getString("AttachContact", R.string.AttachContact); + } else if (message.media instanceof TLRPC.TL_messageMediaUnsupported) { + messageText = LocaleController.getString("UnsupportedMedia", R.string.UnsupportedMedia); + } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { + if (isSticker()) { + String sch = getStrickerChar(); + if (sch != null && sch.length() > 0) { + messageText = String.format("%s %s", sch, LocaleController.getString("AttachSticker", R.string.AttachSticker)); + } else { + messageText = LocaleController.getString("AttachSticker", R.string.AttachSticker); + } + } else if (isMusic()) { + messageText = LocaleController.getString("AttachMusic", R.string.AttachMusic); + } else if (isGif()) { + messageText = LocaleController.getString("AttachGif", R.string.AttachGif); + } else { + String name = FileLoader.getDocumentFileName(message.media.document); + if (name != null && name.length() > 0) { + messageText = name; + } else { + messageText = LocaleController.getString("AttachDocument", R.string.AttachDocument); + } + } + } + } else { + messageText = message.message; + } + if (messageText == null) { + messageText = ""; + } + + setType(); + measureInlineBotButtons(); + + Calendar rightNow = new GregorianCalendar(); + rightNow.setTimeInMillis((long) (messageOwner.date) * 1000); + int dateDay = rightNow.get(Calendar.DAY_OF_YEAR); + int dateYear = rightNow.get(Calendar.YEAR); + int dateMonth = rightNow.get(Calendar.MONTH); + dateKey = String.format("%d_%02d_%02d", dateYear, dateMonth, dateDay); + monthKey = String.format("%d_%02d", dateYear, dateMonth); + + if (messageOwner.message != null && messageOwner.id < 0 && messageOwner.message.length() > 6 && isVideo()) { + videoEditedInfo = new VideoEditedInfo(); + videoEditedInfo.parseString(messageOwner.message); + } + + generateCaption(); + if (generateLayout) { + messageText = Emoji.replaceEmoji(messageText, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); + generateLayout(fromUser); + } + layoutCreated = generateLayout; + generateThumbs(false); + checkMediaExistance(); + } + + public static TextPaint getTextPaint() { + if (textPaint == null) { + textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + textPaint.setColor(Theme.MSG_TEXT_COLOR); + textPaint.linkColor = Theme.MSG_LINK_TEXT_COLOR; + textPaint.setTextSize(AndroidUtilities.dp(MessagesController.getInstance().fontSize)); + } + return textPaint; + } + + public TextPaint getEditTextPaint(){ + return textPaintRight; + } + + public void generatePinMessageText(TLRPC.User fromUser, TLRPC.Chat chat) { + if (fromUser == null && chat == null) { + if (messageOwner.from_id > 0) { + fromUser = MessagesController.getInstance().getUser(messageOwner.from_id); + } + if (fromUser == null) { + chat = MessagesController.getInstance().getChat(messageOwner.to_id.channel_id); + } + } + if (replyMessageObject == null) { + messageText = replaceWithLink(LocaleController.getString("ActionPinnedNoText", R.string.ActionPinnedNoText), "un1", fromUser != null ? fromUser : chat); + } else { + if (replyMessageObject.isMusic()) { + messageText = replaceWithLink(LocaleController.getString("ActionPinnedMusic", R.string.ActionPinnedMusic), "un1", fromUser != null ? fromUser : chat); + } else if (replyMessageObject.isVideo()) { + messageText = replaceWithLink(LocaleController.getString("ActionPinnedVideo", R.string.ActionPinnedVideo), "un1", fromUser != null ? fromUser : chat); + } else if (replyMessageObject.isGif()) { + messageText = replaceWithLink(LocaleController.getString("ActionPinnedGif", R.string.ActionPinnedGif), "un1", fromUser != null ? fromUser : chat); + } else if (replyMessageObject.isVoice()) { + messageText = replaceWithLink(LocaleController.getString("ActionPinnedVoice", R.string.ActionPinnedVoice), "un1", fromUser != null ? fromUser : chat); + } else if (replyMessageObject.isSticker()) { + messageText = replaceWithLink(LocaleController.getString("ActionPinnedSticker", R.string.ActionPinnedSticker), "un1", fromUser != null ? fromUser : chat); + } else if (replyMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + messageText = replaceWithLink(LocaleController.getString("ActionPinnedFile", R.string.ActionPinnedFile), "un1", fromUser != null ? fromUser : chat); + } else if (replyMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo) { + messageText = replaceWithLink(LocaleController.getString("ActionPinnedGeo", R.string.ActionPinnedGeo), "un1", fromUser != null ? fromUser : chat); + } else if (replyMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { + messageText = replaceWithLink(LocaleController.getString("ActionPinnedContact", R.string.ActionPinnedContact), "un1", fromUser != null ? fromUser : chat); + } else if (replyMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { + messageText = replaceWithLink(LocaleController.getString("ActionPinnedPhoto", R.string.ActionPinnedPhoto), "un1", fromUser != null ? fromUser : chat); + } else if (replyMessageObject.messageText != null && replyMessageObject.messageText.length() > 0) { + CharSequence mess = replyMessageObject.messageText; + if (mess.length() > 20) { + mess = mess.subSequence(0, 20) + "..."; + } + mess = Emoji.replaceEmoji(mess, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); + messageText = replaceWithLink(LocaleController.formatString("ActionPinnedText", R.string.ActionPinnedText, mess), "un1", fromUser != null ? fromUser : chat); + } else { + messageText = replaceWithLink(LocaleController.getString("ActionPinnedNoText", R.string.ActionPinnedNoText), "un1", fromUser != null ? fromUser : chat); + } + } + } + + private void measureInlineBotButtons() { + wantedBotKeyboardWidth = 0; + if (!(messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup)) { + return; + } + if (botButtonPaint == null) { + botButtonPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + botButtonPaint.setTextSize(AndroidUtilities.dp(15)); + botButtonPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + } + for (int a = 0; a < messageOwner.reply_markup.rows.size(); a++) { + TLRPC.TL_keyboardButtonRow row = messageOwner.reply_markup.rows.get(a); + int maxButtonSize = 0; + int size = row.buttons.size(); + for (int b = 0; b < size; b++) { + CharSequence text = Emoji.replaceEmoji(row.buttons.get(b).text, botButtonPaint.getFontMetricsInt(), AndroidUtilities.dp(15), false); + StaticLayout staticLayout = new StaticLayout(text, botButtonPaint, AndroidUtilities.dp(2000), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + if (staticLayout.getLineCount() > 0) { + maxButtonSize = Math.max(maxButtonSize, (int) Math.ceil(staticLayout.getLineWidth(0) - staticLayout.getLineLeft(0)) + AndroidUtilities.dp(4)); + } + } + wantedBotKeyboardWidth = Math.max(wantedBotKeyboardWidth, (maxButtonSize + AndroidUtilities.dp(12)) * size + AndroidUtilities.dp(5) * (size - 1)); + } + } + + public void setType() { + if (messageOwner instanceof TLRPC.TL_message || messageOwner instanceof TLRPC.TL_messageForwarded_old2) { + if (isMediaEmpty()) { + type = 0; + if (messageText == null || messageText.length() == 0) { + messageText = "Empty message"; + } + } else if (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { + type = 1; + } else if (messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageOwner.media instanceof TLRPC.TL_messageMediaVenue) { + type = 4; + } else if (isVideo()) { + type = 3; + } else if (isVoice()) { + type = 2; + } else if (isMusic()) { + type = 14; + } else if (messageOwner.media instanceof TLRPC.TL_messageMediaContact) { + type = 12; + } else if (messageOwner.media instanceof TLRPC.TL_messageMediaUnsupported) { + type = 0; + } else if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + if (messageOwner.media.document.mime_type != null) { + if (isGifDocument(messageOwner.media.document)) { + type = 8; + } else if (messageOwner.media.document.mime_type.equals("image/webp") && isSticker()) { + type = 13; + } else { + type = 9; + } + } else { + type = 9; + } + } + } else if (messageOwner instanceof TLRPC.TL_messageService) { + if (messageOwner.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) { + type = 0; + } else if (messageOwner.action instanceof TLRPC.TL_messageActionChatEditPhoto || messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { + contentType = 1; + type = 11; + } else if (messageOwner.action instanceof TLRPC.TL_messageEncryptedAction) { + if (messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { + contentType = 1; + type = 10; + } else { + contentType = -1; + type = -1; + } + } else { + contentType = 1; + type = 10; + } + } + } + + public void checkLayout() { + if (!layoutCreated) { + layoutCreated = true; + TLRPC.User fromUser = null; + if (isFromUser()) { + fromUser = MessagesController.getInstance().getUser(messageOwner.from_id); + } + messageText = Emoji.replaceEmoji(messageText, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); + generateLayout(fromUser); + } + } + + public static boolean isGifDocument(TLRPC.Document document) { + return document != null && document.thumb != null && document.mime_type != null && (document.mime_type.equals("image/gif") || isNewGifDocument(document)); + } + + public static boolean isNewGifDocument(TLRPC.Document document) { + if (document != null && document.mime_type != null && document.mime_type.equals("video/mp4")) { + for (int a = 0; a < document.attributes.size(); a++) { + if (document.attributes.get(a) instanceof TLRPC.TL_documentAttributeAnimated) { + return true; + } + } + } + return false; + } + + public void generateThumbs(boolean update) { + if (messageOwner instanceof TLRPC.TL_messageService) { + if (messageOwner.action instanceof TLRPC.TL_messageActionChatEditPhoto) { + if (!update) { + photoThumbs = new ArrayList<>(messageOwner.action.photo.sizes); + } else if (photoThumbs != null && !photoThumbs.isEmpty()) { + for (int a = 0; a < photoThumbs.size(); a++) { + TLRPC.PhotoSize photoObject = photoThumbs.get(a); + for (int b = 0; b < messageOwner.action.photo.sizes.size(); b++) { + TLRPC.PhotoSize size = messageOwner.action.photo.sizes.get(b); + if (size instanceof TLRPC.TL_photoSizeEmpty) { + continue; + } + if (size.type.equals(photoObject.type)) { + photoObject.location = size.location; + break; + } + } + } + } + } + } else if (messageOwner.media != null && !(messageOwner.media instanceof TLRPC.TL_messageMediaEmpty)) { + if (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { + if (!update || photoThumbs != null && photoThumbs.size() != messageOwner.media.photo.sizes.size()) { + photoThumbs = new ArrayList<>(messageOwner.media.photo.sizes); + } else if (photoThumbs != null && !photoThumbs.isEmpty()) { + for (int a = 0; a < photoThumbs.size(); a++) { + TLRPC.PhotoSize photoObject = photoThumbs.get(a); + for (int b = 0; b < messageOwner.media.photo.sizes.size(); b++) { + TLRPC.PhotoSize size = messageOwner.media.photo.sizes.get(b); + if (size instanceof TLRPC.TL_photoSizeEmpty) { + continue; + } + if (size.type.equals(photoObject.type)) { + photoObject.location = size.location; + break; + } + } + } + } + } else if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + if (!(messageOwner.media.document.thumb instanceof TLRPC.TL_photoSizeEmpty)) { + if (!update) { + photoThumbs = new ArrayList<>(); + photoThumbs.add(messageOwner.media.document.thumb); + } else if (photoThumbs != null && !photoThumbs.isEmpty() && messageOwner.media.document.thumb != null) { + TLRPC.PhotoSize photoObject = photoThumbs.get(0); + photoObject.location = messageOwner.media.document.thumb.location; + photoObject.w = messageOwner.media.document.thumb.w; + photoObject.h = messageOwner.media.document.thumb.h; + } + } + } else if (messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { + if (messageOwner.media.webpage.photo != null) { + if (!update || photoThumbs == null) { + photoThumbs = new ArrayList<>(messageOwner.media.webpage.photo.sizes); + } else if (!photoThumbs.isEmpty()) { + for (int a = 0; a < photoThumbs.size(); a++) { + TLRPC.PhotoSize photoObject = photoThumbs.get(a); + for (int b = 0; b < messageOwner.media.webpage.photo.sizes.size(); b++) { + TLRPC.PhotoSize size = messageOwner.media.webpage.photo.sizes.get(b); + if (size instanceof TLRPC.TL_photoSizeEmpty) { + continue; + } + if (size.type.equals(photoObject.type)) { + photoObject.location = size.location; + break; + } + } + } + } + } else if (messageOwner.media.webpage.document != null) { + if (!(messageOwner.media.webpage.document.thumb instanceof TLRPC.TL_photoSizeEmpty)) { + if (!update) { + photoThumbs = new ArrayList<>(); + photoThumbs.add(messageOwner.media.webpage.document.thumb); + } else if (photoThumbs != null && !photoThumbs.isEmpty() && messageOwner.media.webpage.document.thumb != null) { + TLRPC.PhotoSize photoObject = photoThumbs.get(0); + photoObject.location = messageOwner.media.webpage.document.thumb.location; + } + } + } + } + } + } + + public CharSequence replaceWithLink(CharSequence source, String param, ArrayList uids, AbstractMap usersDict) { + int start = TextUtils.indexOf(source, param); + if (start >= 0) { + SpannableStringBuilder names = new SpannableStringBuilder(""); + for (int a = 0; a < uids.size(); a++) { + TLRPC.User user = null; + if (usersDict != null) { + user = usersDict.get(uids.get(a)); + } + if (user == null) { + user = MessagesController.getInstance().getUser(uids.get(a)); + } + if (user != null) { + String name = UserObject.getUserName(user); + start = names.length(); + if (names.length() != 0) { + names.append(", "); + } + names.append(name); + names.setSpan(new URLSpanNoUnderlineBold("" + user.id), start, start + name.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + return TextUtils.replace(source, new String[]{param}, new CharSequence[]{names}); + } + return source; + } + + public CharSequence replaceWithLink(CharSequence source, String param, TLObject object) { + int start = TextUtils.indexOf(source, param); + if (start >= 0) { + String name; + int id; + if (object instanceof TLRPC.User) { + name = UserObject.getUserName((TLRPC.User) object); + id = ((TLRPC.User) object).id; + } else if (object instanceof TLRPC.Chat) { + name = ((TLRPC.Chat) object).title; + id = -((TLRPC.Chat) object).id; + } else { + name = ""; + id = 0; + } + SpannableStringBuilder builder = new SpannableStringBuilder(TextUtils.replace(source, new String[]{param}, new String[]{name})); + builder.setSpan(new URLSpanNoUnderlineBold("" + id), start, start + name.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + return builder; + } + return source; + } + + public String getExtension() { + String fileName = getFileName(); + int idx = fileName.lastIndexOf('.'); + String ext = null; + if (idx != -1) { + ext = fileName.substring(idx + 1); + } + if (ext == null || ext.length() == 0) { + ext = messageOwner.media.document.mime_type; + } + if (ext == null) { + ext = ""; + } + ext = ext.toUpperCase(); + return ext; + } + + public String getFileName() { + if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + return FileLoader.getAttachFileName(messageOwner.media.document); + } else if (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { + ArrayList sizes = messageOwner.media.photo.sizes; + if (sizes.size() > 0) { + TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(sizes, AndroidUtilities.getPhotoSize()); + if (sizeFull != null) { + return FileLoader.getAttachFileName(sizeFull); + } + } + } else if (messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { + return FileLoader.getAttachFileName(messageOwner.media.webpage.document); + } + return ""; + } + + public int getFileType() { + if (isVideo()) { + return FileLoader.MEDIA_DIR_VIDEO; + } else if (isVoice()) { + return FileLoader.MEDIA_DIR_AUDIO; + } else if (messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + return FileLoader.MEDIA_DIR_DOCUMENT; + } else if (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { + return FileLoader.MEDIA_DIR_IMAGE; + } + return FileLoader.MEDIA_DIR_CACHE; + } + + private static boolean containsUrls(CharSequence message) { + if (message == null || message.length() < 2 || message.length() > 1024 * 20) { + return false; + } + + int length = message.length(); + + int digitsInRow = 0; + int schemeSequence = 0; + int dotSequence = 0; + + char lastChar = 0; + + for (int i = 0; i < length; i++) { + char c = message.charAt(i); + + if (c >= '0' && c <= '9') { + digitsInRow++; + if (digitsInRow >= 6) { + return true; + } + schemeSequence = 0; + dotSequence = 0; + } else if (!(c != ' ' && digitsInRow > 0)) { + digitsInRow = 0; + } + if ((c == '@' || c == '#' || c == '/') && i == 0 || i != 0 && (message.charAt(i - 1) == ' ' || message.charAt(i - 1) == '\n')) { + return true; + } + if (c == ':') { + if (schemeSequence == 0) { + schemeSequence = 1; + } else { + schemeSequence = 0; + } + } else if (c == '/') { + if (schemeSequence == 2) { + return true; + } + if (schemeSequence == 1) { + schemeSequence++; + } else { + schemeSequence = 0; + } + } else if (c == '.') { + if (dotSequence == 0 && lastChar != ' ') { + dotSequence++; + } else { + dotSequence = 0; + } + } else if (c != ' ' && lastChar == '.' && dotSequence == 1) { + return true; + } else { + dotSequence = 0; + } + lastChar = c; + } + return false; + } + + public void generateLinkDescription() { + if (linkDescription != null) { + return; + } + if (messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && messageOwner.media.webpage instanceof TLRPC.TL_webPage && messageOwner.media.webpage.description != null) { + linkDescription = Spannable.Factory.getInstance().newSpannable(messageOwner.media.webpage.description); + if (containsUrls(linkDescription)) { + try { + Linkify.addLinks((Spannable) linkDescription, Linkify.WEB_URLS); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + linkDescription = Emoji.replaceEmoji(linkDescription, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); + } + } + + public void generateCaption() { + if (caption != null) { + return; + } + if (messageOwner.media != null && messageOwner.media.caption != null && messageOwner.media.caption.length() > 0) { + caption = Emoji.replaceEmoji(messageOwner.media.caption, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); + if (containsUrls(caption)) { + try { + Linkify.addLinks((Spannable) caption, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + addUsernamesAndHashtags(caption, true); + } + } + } + + private static void addUsernamesAndHashtags(CharSequence charSequence, boolean botCommands) { + try { + if (urlPattern == null) { + urlPattern = Pattern.compile("(^|\\s)/[a-zA-Z@\\d_]{1,255}|(^|\\s)@[a-zA-Z\\d_]{1,32}|(^|\\s)#[\\w\\.]+"); + } + Matcher matcher = urlPattern.matcher(charSequence); + while (matcher.find()) { + int start = matcher.start(); + int end = matcher.end(); + if (charSequence.charAt(start) != '@' && charSequence.charAt(start) != '#' && charSequence.charAt(start) != '/') { + start++; + } + URLSpanNoUnderline url = null; + if (charSequence.charAt(start) == '/') { + if (botCommands) { + url = new URLSpanBotCommand(charSequence.subSequence(start, end).toString()); + } + } else { + url = new URLSpanNoUnderline(charSequence.subSequence(start, end).toString()); + } + if (url != null) { + ((Spannable) charSequence).setSpan(url, start, end, 0); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + + public static void addLinks(CharSequence messageText) { + addLinks(messageText, true); + } + + public static void addLinks(CharSequence messageText, boolean botCommands) { + if (messageText instanceof Spannable && containsUrls(messageText)) { + if (messageText.length() < 200) { + try { + Linkify.addLinks((Spannable) messageText, Linkify.WEB_URLS | Linkify.PHONE_NUMBERS); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else { + try { + Linkify.addLinks((Spannable) messageText, Linkify.WEB_URLS); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + addUsernamesAndHashtags(messageText, botCommands); + } + } + + private void generateLayout(TLRPC.User fromUser) { + if (type != 0 || messageOwner.to_id == null || messageText == null || messageText.length() == 0) { + return; + } + // + //TLRPC.MessageEntity ent = new TLRPC.TL_messageEntityCode();//TL_messageEntityBold(); + //ent.offset = 0; + //ent.length = messageText.length(); + //messageOwner.entities.add(ent); + // + generateLinkDescription(); + textLayoutBlocks = new ArrayList<>(); + + boolean useManualParse = messageOwner.entities.isEmpty() && ( + messageOwner instanceof TLRPC.TL_message_old || + messageOwner instanceof TLRPC.TL_message_old2 || + messageOwner instanceof TLRPC.TL_message_old3 || + messageOwner instanceof TLRPC.TL_message_old4 || + messageOwner instanceof TLRPC.TL_messageForwarded_old || + messageOwner instanceof TLRPC.TL_messageForwarded_old2 || + messageOwner instanceof TLRPC.TL_message_secret || + isOut() && messageOwner.send_state != MESSAGE_SEND_STATE_SENT || + messageOwner.id < 0 || messageOwner.media instanceof TLRPC.TL_messageMediaUnsupported); + //Log.e("MessageObject","useManualParse " + useManualParse); + if (useManualParse) { + addLinks(messageText); + //Log.e("MessageObject","addLinks"); + } else { + if (messageText instanceof Spannable && messageText.length() < 200) { + try { + Linkify.addLinks((Spannable) messageText, Linkify.PHONE_NUMBERS); + //Log.e("MessageObject","Linkify"); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + } + + if (messageText instanceof Spannable) { + Spannable spannable = (Spannable) messageText; + int count = messageOwner.entities.size(); + URLSpan[] spans = spannable.getSpans(0, messageText.length(), URLSpan.class); + for (int a = 0; a < count; a++) { + TLRPC.MessageEntity entity = messageOwner.entities.get(a); + if (entity.length <= 0 || entity.offset < 0 || entity.offset >= messageOwner.message.length()) { + continue; + } else if (entity.offset + entity.length > messageOwner.message.length()) { + entity.length = messageOwner.message.length() - entity.offset; + } + if (spans != null && spans.length > 0) { + for (int b = 0; b < spans.length; b++) { + if (spans[b] == null) { + continue; + } + int start = spannable.getSpanStart(spans[b]); + int end = spannable.getSpanEnd(spans[b]); + if (entity.offset <= start && entity.offset + entity.length >= start || entity.offset <= end && entity.offset + entity.length >= end) { + spannable.removeSpan(spans[b]); + spans[b] = null; + } + } + } + //Log.e("MessageObject","entity " + entity.toString() + " offset " + entity.offset + " length " + entity.length + " type " + type); + if (entity instanceof TLRPC.TL_messageEntityBold) { + //Log.e("MessageObject","TL_messageEntityBold offset " + entity.offset + " length " + entity.length); + spannable.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else if (entity instanceof TLRPC.TL_messageEntityItalic) { + spannable.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/ritalic.ttf")), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else if (entity instanceof TLRPC.TL_messageEntityCode || entity instanceof TLRPC.TL_messageEntityPre) { + spannable.setSpan(new TypefaceSpan(Typeface.MONOSPACE, AndroidUtilities.dp(MessagesController.getInstance().fontSize - 1)), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else if (!useManualParse) { + String url = messageOwner.message.substring(entity.offset, entity.offset + entity.length); + if (entity instanceof TLRPC.TL_messageEntityBotCommand) { + spannable.setSpan(new URLSpanBotCommand(url), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else if (entity instanceof TLRPC.TL_messageEntityHashtag || entity instanceof TLRPC.TL_messageEntityMention) { + spannable.setSpan(new URLSpanNoUnderline(url), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else if (entity instanceof TLRPC.TL_messageEntityEmail) { + spannable.setSpan(new URLSpanReplacement("mailto:" + url), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else if (entity instanceof TLRPC.TL_messageEntityUrl) { + if (!url.toLowerCase().startsWith("http")) { + spannable.setSpan(new URLSpan("http://" + url), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } else { + //Log.e("MessageObject","url " + url + " offset " + entity.offset + " length " + entity.length); + spannable.setSpan(new URLSpan(url), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } else if (entity instanceof TLRPC.TL_messageEntityTextUrl) { + spannable.setSpan(new URLSpanReplacement(entity.url), entity.offset, entity.offset + entity.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + } + } + + int maxWidth; + if (AndroidUtilities.isTablet()) { + if (messageOwner.from_id > 0 && (messageOwner.to_id.channel_id != 0 || messageOwner.to_id.chat_id != 0) && !isOut()) { + //maxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(122); + maxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(leftBound + 70); + } else { + maxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(80); + } + } else { + /*if (messageOwner.from_id > 0 && (messageOwner.to_id.channel_id != 0 || messageOwner.to_id.chat_id != 0) && !isOut()) { + maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(122);*/ + if (messageOwner.from_id > 0 && (messageOwner.to_id.channel_id != 0 || messageOwner.to_id.chat_id != 0) && !isOut() + || messageOwner.from_id > 0 && showMyAvatar && isOut() + || (messageOwner.to_id.chat_id > 0 || messageOwner.to_id.channel_id > 0) && showMyAvatarGroup && isOut() + || messageOwner.from_id > 0 && showAvatar && !isOutOwner()) { + maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(leftBound + 70); + } else { + maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(80); + } + } + if (fromUser != null && fromUser.bot) { + maxWidth -= AndroidUtilities.dp(20); + } + + StaticLayout textLayout; + + try { + textLayout = new StaticLayout(messageText, textPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + } catch (Exception e) { + FileLog.e("tmessages", e); + return; + } + + textHeight = textLayout.getHeight(); + int linesCount = textLayout.getLineCount(); + + int blocksCount = (int) Math.ceil((float) linesCount / LINES_PER_BLOCK); + int linesOffset = 0; + float prevOffset = 0; + + for (int a = 0; a < blocksCount; a++) { + int currentBlockLinesCount = Math.min(LINES_PER_BLOCK, linesCount - linesOffset); + TextLayoutBlock block = new TextLayoutBlock(); + + if (blocksCount == 1) { + block.textLayout = textLayout; + block.textYOffset = 0; + block.charactersOffset = 0; + block.height = textHeight; + } else { + int startCharacter = textLayout.getLineStart(linesOffset); + int endCharacter = textLayout.getLineEnd(linesOffset + currentBlockLinesCount - 1); + if (endCharacter < startCharacter) { + continue; + } + block.charactersOffset = startCharacter; + try { + CharSequence str = messageText.subSequence(startCharacter, endCharacter); + block.textLayout = new StaticLayout(str, textPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + block.textYOffset = textLayout.getLineTop(linesOffset); + if (a != 0) { + block.height = (int) (block.textYOffset - prevOffset); + } + block.height = Math.max(block.height, block.textLayout.getLineBottom(block.textLayout.getLineCount() - 1)); + prevOffset = block.textYOffset; + } catch (Exception e) { + FileLog.e("tmessages", e); + continue; + } + if (a == blocksCount - 1) { + currentBlockLinesCount = Math.max(currentBlockLinesCount, block.textLayout.getLineCount()); + try { + textHeight = Math.max(textHeight, (int) (block.textYOffset + block.textLayout.getHeight())); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + textLayoutBlocks.add(block); + + float lastLeft = block.textXOffset = 0; + try { + lastLeft = block.textXOffset = block.textLayout.getLineLeft(currentBlockLinesCount - 1); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + float lastLine = 0; + try { + lastLine = block.textLayout.getLineWidth(currentBlockLinesCount - 1); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + int linesMaxWidth = (int) Math.ceil(lastLine); + int lastLineWidthWithLeft; + int linesMaxWidthWithLeft; + boolean hasNonRTL = false; + + if (a == blocksCount - 1) { + lastLineWidth = linesMaxWidth; + } + + linesMaxWidthWithLeft = lastLineWidthWithLeft = (int) Math.ceil(lastLine + lastLeft); + if (lastLeft == 0) { + hasNonRTL = true; + } + + if (currentBlockLinesCount > 1) { + float textRealMaxWidth = 0, textRealMaxWidthWithLeft = 0, lineWidth, lineLeft; + for (int n = 0; n < currentBlockLinesCount; n++) { + try { + lineWidth = block.textLayout.getLineWidth(n); + } catch (Exception e) { + FileLog.e("tmessages", e); + lineWidth = 0; + } + + if (lineWidth > maxWidth + 100) { + lineWidth = maxWidth; + } + + try { + lineLeft = block.textLayout.getLineLeft(n); + } catch (Exception e) { + FileLog.e("tmessages", e); + lineLeft = 0; + } + + block.textXOffset = Math.min(block.textXOffset, lineLeft); + + if (lineLeft == 0) { + hasNonRTL = true; + } + textRealMaxWidth = Math.max(textRealMaxWidth, lineWidth); + textRealMaxWidthWithLeft = Math.max(textRealMaxWidthWithLeft, lineWidth + lineLeft); + linesMaxWidth = Math.max(linesMaxWidth, (int) Math.ceil(lineWidth)); + linesMaxWidthWithLeft = Math.max(linesMaxWidthWithLeft, (int) Math.ceil(lineWidth + lineLeft)); + } + if (hasNonRTL) { + textRealMaxWidth = textRealMaxWidthWithLeft; + if (a == blocksCount - 1) { + lastLineWidth = lastLineWidthWithLeft; + } + } else if (a == blocksCount - 1) { + lastLineWidth = linesMaxWidth; + } + textWidth = Math.max(textWidth, (int) Math.ceil(textRealMaxWidth)); + } else { + textWidth = Math.max(textWidth, Math.min(maxWidth, linesMaxWidth)); + } + + if (hasNonRTL) { + block.textXOffset = 0; + } + + linesOffset += currentBlockLinesCount; + } + } + + public boolean isOut() { + return messageOwner.out; + } + + public boolean isOutOwner() { + return messageOwner.out && messageOwner.from_id > 0 && !messageOwner.post; + } + + public boolean isFromUser() { + return messageOwner.from_id > 0 && !messageOwner.post; + } + + public boolean isUnread() { + return messageOwner.unread; + } + + public boolean isContentUnread() { + return messageOwner.media_unread; + } + + public void setIsRead() { + messageOwner.unread = false; + } + + public int getUnradFlags() { + return getUnreadFlags(messageOwner); + } + + public static int getUnreadFlags(TLRPC.Message message) { + int flags = 0; + if (!message.unread) { + flags |= 1; + } + if (!message.media_unread) { + flags |= 2; + } + return flags; + } + + public void setContentIsRead() { + messageOwner.media_unread = false; + } + + public int getId() { + return messageOwner.id; + } + + public boolean isSecretPhoto() { + return messageOwner instanceof TLRPC.TL_message_secret && messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl > 0 && messageOwner.ttl <= 60; + } + + public boolean isSecretMedia() { + return messageOwner instanceof TLRPC.TL_message_secret && + (messageOwner.media instanceof TLRPC.TL_messageMediaPhoto && messageOwner.ttl > 0 && messageOwner.ttl <= 60 || isVoice() || isVideo()); + } + + public static void setUnreadFlags(TLRPC.Message message, int flag) { + message.unread = (flag & 1) == 0; + message.media_unread = (flag & 2) == 0; + } + + public static boolean isUnread(TLRPC.Message message) { + return message.unread; + } + + public static boolean isContentUnread(TLRPC.Message message) { + return message.media_unread; + } + + public boolean isImportant() { + return isImportant(messageOwner); + } + + public boolean isMegagroup() { + return isMegagroup(messageOwner); + } + + public static boolean isImportant(TLRPC.Message message) { + if (isMegagroup(message)) { + return message.post; + } + if (message.to_id.channel_id != 0) { + if (message instanceof TLRPC.TL_message_layer47 || message instanceof TLRPC.TL_message_old7) { + return message.to_id.channel_id != 0 && (message.from_id <= 0 || message.mentioned || message.out || (message.flags & TLRPC.MESSAGE_FLAG_HAS_FROM_ID) == 0); + } + return message.post; + } + return false; + } + + public static boolean isMegagroup(TLRPC.Message message) { + return (message.flags & TLRPC.MESSAGE_FLAG_MEGAGROUP) != 0; + } + + public static boolean isOut(TLRPC.Message message) { + return message.out; + } + + public long getDialogId() { + return getDialogId(messageOwner); + } + + public static long getDialogId(TLRPC.Message message) { + if (message.dialog_id == 0 && message.to_id != null) { + if (message.to_id.chat_id != 0) { + if (message.to_id.chat_id < 0) { + message.dialog_id = AndroidUtilities.makeBroadcastId(message.to_id.chat_id); + } else { + message.dialog_id = -message.to_id.chat_id; + } + } else if (message.to_id.channel_id != 0) { + message.dialog_id = -message.to_id.channel_id; + } else if (isOut(message)) { + message.dialog_id = message.to_id.user_id; + } else { + message.dialog_id = message.from_id; + } + } + return message.dialog_id; + } + + public boolean isSending() { + return messageOwner.send_state == MESSAGE_SEND_STATE_SENDING && messageOwner.id < 0; + } + + public boolean isSendError() { + return messageOwner.send_state == MESSAGE_SEND_STATE_SEND_ERROR && messageOwner.id < 0; + } + + public boolean isSent() { + return messageOwner.send_state == MESSAGE_SEND_STATE_SENT || messageOwner.id > 0; + } + + public String getSecretTimeString() { + if (!isSecretMedia()) { + return null; + } + int secondsLeft = messageOwner.ttl; + if (messageOwner.destroyTime != 0) { + secondsLeft = Math.max(0, messageOwner.destroyTime - ConnectionsManager.getInstance().getCurrentTime()); + } + String str; + if (secondsLeft < 60) { + str = secondsLeft + "s"; + } else { + str = secondsLeft / 60 + "m"; + } + return str; + } + + public String getDocumentName() { + if (messageOwner.media != null && messageOwner.media.document != null) { + return FileLoader.getDocumentFileName(messageOwner.media.document); + } + return ""; + } + + public static boolean isStickerDocument(TLRPC.Document document) { + if (document != null) { + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeSticker) { + return true; + } + } + } + return false; + } + + public static boolean isVoiceDocument(TLRPC.Document document) { + if (document != null) { + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + return attribute.voice; + } + } + } + return false; + } + + public static boolean isMusicDocument(TLRPC.Document document) { + if (document != null) { + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + return !attribute.voice; + } + } + } + return false; + } + + public static boolean isVideoDocument(TLRPC.Document document) { + if (document != null) { + boolean isAnimated = false; + boolean isVideo = false; + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeVideo) { + isVideo = true; + } else if (attribute instanceof TLRPC.TL_documentAttributeAnimated) { + isAnimated = true; + } + } + return isVideo && !isAnimated; + } + return false; + } + + public TLRPC.Document getDocument() { + if (messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { + return messageOwner.media.webpage.document; + } + return messageOwner.media != null ? messageOwner.media.document : null; + } + + public static boolean isStickerMessage(TLRPC.Message message) { + return message.media != null && message.media.document != null && isStickerDocument(message.media.document); + } + + public static boolean isMusicMessage(TLRPC.Message message) { + if (message.media instanceof TLRPC.TL_messageMediaWebPage) { + return isMusicDocument(message.media.webpage.document); + } + return message.media != null && message.media.document != null && isMusicDocument(message.media.document); + } + + public static boolean isVoiceMessage(TLRPC.Message message) { + if (message.media instanceof TLRPC.TL_messageMediaWebPage) { + return isVoiceDocument(message.media.webpage.document); + } + return message.media != null && message.media.document != null && isVoiceDocument(message.media.document); + } + + public static boolean isVideoMessage(TLRPC.Message message) { + if (message.media instanceof TLRPC.TL_messageMediaWebPage) { + return isVideoDocument(message.media.webpage.document); + } + return message.media != null && message.media.document != null && isVideoDocument(message.media.document); + } + + public static TLRPC.InputStickerSet getInputStickerSet(TLRPC.Message message) { + if (message.media != null && message.media.document != null) { + for (TLRPC.DocumentAttribute attribute : message.media.document.attributes) { + if (attribute instanceof TLRPC.TL_documentAttributeSticker) { + if (attribute.stickerset instanceof TLRPC.TL_inputStickerSetEmpty) { + return null; + } + return attribute.stickerset; + } + } + } + return null; + } + + public String getStrickerChar() { + if (messageOwner.media != null && messageOwner.media.document != null) { + for (TLRPC.DocumentAttribute attribute : messageOwner.media.document.attributes) { + if (attribute instanceof TLRPC.TL_documentAttributeSticker) { + return attribute.alt; + } + } + } + return null; + } + + public int getApproximateHeight() { + if (type == 0) { + int height = textHeight + (messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && messageOwner.media.webpage instanceof TLRPC.TL_webPage ? AndroidUtilities.dp(100) : 0); + if (isReply()) { + height += AndroidUtilities.dp(42); + } + return height; + } else if (type == 2) { + return AndroidUtilities.dp(72); + } else if (type == 12) { + return AndroidUtilities.dp(71); + } else if (type == 9) { + return AndroidUtilities.dp(100); + } else if (type == 4) { + return AndroidUtilities.dp(114); + } else if (type == 14) { + return AndroidUtilities.dp(82); + } else if (type == 10) { + return AndroidUtilities.dp(30); + } else if (type == 11) { + return AndroidUtilities.dp(50); + } else if (type == 13) { + float maxHeight = AndroidUtilities.displaySize.y * 0.4f; + float maxWidth; + if (AndroidUtilities.isTablet()) { + maxWidth = AndroidUtilities.getMinTabletSide() * 0.5f; + } else { + maxWidth = AndroidUtilities.displaySize.x * 0.5f; + } + int photoHeight = 0; + int photoWidth = 0; + for (TLRPC.DocumentAttribute attribute : messageOwner.media.document.attributes) { + if (attribute instanceof TLRPC.TL_documentAttributeImageSize) { + photoWidth = attribute.w; + photoHeight = attribute.h; + break; + } + } + if (photoWidth == 0) { + photoHeight = (int) maxHeight; + photoWidth = photoHeight + AndroidUtilities.dp(100); + } + if (photoHeight > maxHeight) { + photoWidth *= maxHeight / photoHeight; + photoHeight = (int)maxHeight; + } + if (photoWidth > maxWidth) { + photoHeight *= maxWidth / photoWidth; + } + return photoHeight + AndroidUtilities.dp(14); + } else { + int photoHeight; + int photoWidth; + + if (AndroidUtilities.isTablet()) { + photoWidth = (int) (AndroidUtilities.getMinTabletSide() * 0.7f); + } else { + photoWidth = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.7f); + } + photoHeight = photoWidth + AndroidUtilities.dp(100); + if (photoWidth > AndroidUtilities.getPhotoSize()) { + photoWidth = AndroidUtilities.getPhotoSize(); + } + if (photoHeight > AndroidUtilities.getPhotoSize()) { + photoHeight = AndroidUtilities.getPhotoSize(); + } + TLRPC.PhotoSize currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(photoThumbs, AndroidUtilities.getPhotoSize()); + + if (currentPhotoObject != null) { + float scale = (float) currentPhotoObject.w / (float) photoWidth; + int h = (int) (currentPhotoObject.h / scale); + if (h == 0) { + h = AndroidUtilities.dp(100); + } + if (h > photoHeight) { + h = photoHeight; + } else if (h < AndroidUtilities.dp(120)) { + h = AndroidUtilities.dp(120); + } + if (isSecretPhoto()) { + if (AndroidUtilities.isTablet()) { + h = (int) (AndroidUtilities.getMinTabletSide() * 0.5f); + } else { + h = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.5f); + } + } + photoHeight = h; + } + return photoHeight + AndroidUtilities.dp(14); + } + } + + public boolean isSticker() { + if (type != 1000) { + return type == 13; + } + return isStickerMessage(messageOwner); + } + + public boolean isMusic() { + return isMusicMessage(messageOwner); + } + + public boolean isVoice() { + return isVoiceMessage(messageOwner); + } + + public boolean isVideo() { + return isVideoMessage(messageOwner); + } + + public boolean isGif() { + return messageOwner.media instanceof TLRPC.TL_messageMediaDocument && isGifDocument(messageOwner.media.document); + } + + public boolean isWebpageDocument() { + return messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && messageOwner.media.webpage.document != null && !isGifDocument(messageOwner.media.webpage.document); + } + + public boolean isNewGif() { + return messageOwner.media != null && isNewGifDocument(messageOwner.media.document); + } + + public String getMusicTitle() { + TLRPC.Document document; + if (type == 0) { + document = messageOwner.media.webpage.document; + } else { + document = messageOwner.media.document; + } + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.voice) { + return LocaleController.formatDateAudio(messageOwner.date); + } + String title = attribute.title; + if (title == null || title.length() == 0) { + title = FileLoader.getDocumentFileName(document); + if (title == null || title.length() == 0) { + title = LocaleController.getString("AudioUnknownTitle", R.string.AudioUnknownTitle); + } + } + return title; + } + } + return ""; + } + + public String getMusicAuthor() { + TLRPC.Document document; + if (type == 0) { + document = messageOwner.media.webpage.document; + } else { + document = messageOwner.media.document; + } + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.voice) { + if (isOutOwner() || messageOwner.fwd_from != null && messageOwner.fwd_from.from_id == UserConfig.getClientUserId()) { + return LocaleController.getString("FromYou", R.string.FromYou); + } + TLRPC.User user = null; + TLRPC.Chat chat = null; + if (messageOwner.fwd_from != null && messageOwner.fwd_from.channel_id != 0) { + chat = MessagesController.getInstance().getChat(messageOwner.fwd_from.channel_id); + } else if (messageOwner.fwd_from != null && messageOwner.fwd_from.from_id != 0) { + user = MessagesController.getInstance().getUser(messageOwner.fwd_from.from_id); + } else if (messageOwner.from_id < 0) { + chat = MessagesController.getInstance().getChat(-messageOwner.from_id); + } else { + user = MessagesController.getInstance().getUser(messageOwner.from_id); + } + if (user != null) { + return UserObject.getUserName(user); + } else if (chat != null) { + return chat.title; + } + } + String performer = attribute.performer; + if (performer == null || performer.length() == 0) { + performer = LocaleController.getString("AudioUnknownArtist", R.string.AudioUnknownArtist); + } + return performer; + } + } + return ""; + } + + public TLRPC.InputStickerSet getInputStickerSet() { + return getInputStickerSet(messageOwner); + } + + public boolean isForwarded() { + return isForwardedMessage(messageOwner); + } + + public static boolean isForwardedMessage(TLRPC.Message message) { + return (message.flags & TLRPC.MESSAGE_FLAG_FWD) != 0; + } + + public boolean isReply() { + return !(replyMessageObject != null && replyMessageObject.messageOwner instanceof TLRPC.TL_messageEmpty) && (messageOwner.reply_to_msg_id != 0 || messageOwner.reply_to_random_id != 0) && (messageOwner.flags & TLRPC.MESSAGE_FLAG_REPLY) != 0; + } + + public boolean isMediaEmpty() { + return isMediaEmpty(messageOwner); + } + + public static boolean isMediaEmpty(TLRPC.Message message) { + return message == null || message.media == null || message.media instanceof TLRPC.TL_messageMediaEmpty || message.media instanceof TLRPC.TL_messageMediaWebPage; + } + + public boolean canEditMessage(TLRPC.Chat chat) { + return canEditMessage(messageOwner, chat); + } + + public static boolean canEditMessage(TLRPC.Message message, TLRPC.Chat chat) { + if (message == null || message.to_id == null || message.action != null && !(message.action instanceof TLRPC.TL_messageActionEmpty) || isForwardedMessage(message) || message.via_bot_id != 0 || message.id < 0 || Math.abs(message.date - ConnectionsManager.getInstance().getCurrentTime()) > MessagesController.getInstance().maxEditTime) { + return false; + } + if (message.to_id.channel_id == 0) { + return message.out && (message.media instanceof TLRPC.TL_messageMediaPhoto || + message.media instanceof TLRPC.TL_messageMediaDocument && (isVideoMessage(message) || isGifDocument(message.media.document)) || + message.media instanceof TLRPC.TL_messageMediaEmpty || + message.media instanceof TLRPC.TL_messageMediaWebPage || + message.media == null); + } + if (chat == null && message.to_id.channel_id != 0) { + chat = MessagesController.getInstance().getChat(message.to_id.channel_id); + if (chat == null) { + return false; + } + } + if (chat.megagroup && message.out || !chat.megagroup && (chat.creator || chat.editor && isOut(message)) && isImportant(message)) { + if (message.media instanceof TLRPC.TL_messageMediaPhoto || + message.media instanceof TLRPC.TL_messageMediaDocument && (isVideoMessage(message) || isGifDocument(message.media.document)) || + message.media instanceof TLRPC.TL_messageMediaEmpty || + message.media instanceof TLRPC.TL_messageMediaWebPage || + message.media == null) { + return true; + } + } + return false; + } + + public boolean canDeleteMessage(TLRPC.Chat chat) { + return canDeleteMessage(messageOwner, chat); + } + + public static boolean canDeleteMessage(TLRPC.Message message, TLRPC.Chat chat) { + if (message.id < 0) { + return true; + } + if (chat == null && message.to_id.channel_id != 0) { + chat = MessagesController.getInstance().getChat(message.to_id.channel_id); + } + if (ChatObject.isChannel(chat)) { + if (message.id == 1) { + return false; + } + if (chat.creator) { + return true; + } else if (chat.editor) { + if (isOut(message) || message.from_id > 0 && !message.post) { + return true; + } + } else if (chat.moderator) { + if (message.from_id > 0 && !message.post) { + return true; + } + } else if (isOut(message) && message.from_id > 0) { + return true; + } + } + return isOut(message) || !ChatObject.isChannel(chat); + } + + public String getForwardedName() { + if (messageOwner.fwd_from != null) { + if (messageOwner.fwd_from.channel_id != 0) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(messageOwner.fwd_from.channel_id); + if (chat != null) { + return chat.title; + } + } else if (messageOwner.fwd_from.from_id != 0) { + TLRPC.User user = MessagesController.getInstance().getUser(messageOwner.fwd_from.from_id); + if (user != null) { + return UserObject.getUserName(user); + } + } + } + return null; + } + + public void checkMediaExistance() { + File cacheFile = null; + attachPathExists = false; + mediaExists = false; + if (type == 1) { + TLRPC.PhotoSize currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(photoThumbs, AndroidUtilities.getPhotoSize()); + if (currentPhotoObject != null) { + mediaExists = FileLoader.getPathToMessage(messageOwner).exists(); + } + } else if (type == 8 || type == 3 || type == 9 || type == 2 || type == 14) { + if (messageOwner.attachPath != null && messageOwner.attachPath.length() > 0) { + File f = new File(messageOwner.attachPath); + attachPathExists = f.exists(); + } + if (!attachPathExists) { + mediaExists = FileLoader.getPathToMessage(messageOwner).exists(); + } + } else { + TLRPC.Document document = getDocument(); + if (document != null) { + mediaExists = FileLoader.getPathToAttach(document).exists(); + } else if (type == 0) { + TLRPC.PhotoSize currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(photoThumbs, AndroidUtilities.getPhotoSize()); + if (currentPhotoObject == null) { + return; + } + if (currentPhotoObject != null) { + mediaExists = FileLoader.getPathToAttach(currentPhotoObject, true).exists(); + } + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java new file mode 100644 index 00000000..5984b50c --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesController.java @@ -0,0 +1,7173 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.util.Base64; +import android.util.Log; +import android.util.SparseArray; +import android.util.SparseIntArray; +import android.widget.Toast; + +import org.telegram.SQLite.SQLiteCursor; +import org.telegram.messenger.query.BotQuery; +import org.telegram.messenger.query.MessagesQuery; +import org.telegram.messenger.query.StickersQuery; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.SerializedData; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.Favourite; +import org.telegram.ui.ProfileActivity; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Locale; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Semaphore; + +public class MessagesController implements NotificationCenter.NotificationCenterDelegate { + + private ConcurrentHashMap chats = new ConcurrentHashMap<>(100, 1.0f, 2); + private ConcurrentHashMap encryptedChats = new ConcurrentHashMap<>(10, 1.0f, 2); + private ConcurrentHashMap users = new ConcurrentHashMap<>(100, 1.0f, 2); + private ConcurrentHashMap usersByUsernames = new ConcurrentHashMap<>(100, 1.0f, 2); + + private ArrayList joiningToChannels = new ArrayList<>(); + + private HashMap exportedChats = new HashMap<>(); + + public ArrayList dialogs = new ArrayList<>(); + public ArrayList dialogsServerOnly = new ArrayList<>(); + public ArrayList dialogsGroupsOnly = new ArrayList<>(); + //plus + public ArrayList dialogsUsers = new ArrayList<>(); + public ArrayList dialogsGroups = new ArrayList<>(); + public ArrayList dialogsGroupsAll = new ArrayList<>(); + public ArrayList dialogsChannels = new ArrayList<>(); + public ArrayList dialogsMegaGroups = new ArrayList<>(); + public ArrayList dialogsBots = new ArrayList<>(); + public ArrayList dialogsFavs = new ArrayList<>(); + // + public int nextDialogsCacheOffset; + public ConcurrentHashMap dialogs_read_inbox_max = new ConcurrentHashMap<>(100, 1.0f, 2); + public ConcurrentHashMap dialogs_dict = new ConcurrentHashMap<>(100, 1.0f, 2); + public HashMap dialogMessage = new HashMap<>(); + public HashMap dialogMessagesByRandomIds = new HashMap<>(); + public HashMap dialogMessagesByIds = new HashMap<>(); + public ConcurrentHashMap> printingUsers = new ConcurrentHashMap<>(20, 1.0f, 2); + public HashMap printingStrings = new HashMap<>(); + public HashMap printingStringsTypes = new HashMap<>(); + public HashMap> sendingTypings = new HashMap<>(); + public ConcurrentHashMap onlinePrivacy = new ConcurrentHashMap<>(20, 1.0f, 2); + private int lastPrintingStringCount = 0; + + private HashMap loadingPeerSettings = new HashMap<>(); + + private ArrayList createdDialogIds = new ArrayList<>(); + + private SparseIntArray shortPollChannels = new SparseIntArray(); + private SparseIntArray needShortPollChannels = new SparseIntArray(); + + public boolean loadingBlockedUsers = false; + public ArrayList blockedUsers = new ArrayList<>(); + + private SparseArray> channelViewsToSend = new SparseArray<>(); + private SparseArray> channelViewsToReload = new SparseArray<>(); + private long lastViewsCheckTime; + + private HashMap> updatesQueueChannels = new HashMap<>(); + private HashMap updatesStartWaitTimeChannels = new HashMap<>(); + private HashMap channelsPts = new HashMap<>(); + private HashMap gettingDifferenceChannels = new HashMap<>(); + + private ArrayList updatesQueueSeq = new ArrayList<>(); + private ArrayList updatesQueuePts = new ArrayList<>(); + private ArrayList updatesQueueQts = new ArrayList<>(); + private long updatesStartWaitTimeSeq = 0; + private long updatesStartWaitTimePts = 0; + private long updatesStartWaitTimeQts = 0; + private HashMap fullUsersAbout = new HashMap<>(); + private ArrayList loadingFullUsers = new ArrayList<>(); + private ArrayList loadedFullUsers = new ArrayList<>(); + private ArrayList loadingFullChats = new ArrayList<>(); + private ArrayList loadingFullParticipants = new ArrayList<>(); + private ArrayList loadedFullParticipants = new ArrayList<>(); + private ArrayList loadedFullChats = new ArrayList<>(); + + private HashMap> reloadingWebpages = new HashMap<>(); + private HashMap> reloadingWebpagesPending = new HashMap<>(); + + private HashMap> reloadingMessages = new HashMap<>(); + + private boolean gettingNewDeleteTask = false; + private int currentDeletingTaskTime = 0; + private ArrayList currentDeletingTaskMids = null; + private Runnable currentDeleteTaskRunnable = null; + + public boolean loadingDialogs = false; + private boolean migratingDialogs = false; + public boolean dialogsEndReached = false; + public boolean gettingDifference = false; + public boolean updatingState = false; + public boolean firstGettingTask = false; + public boolean registeringForPush = false; + + public int secretWebpagePreview = 2; + + private long lastStatusUpdateTime = 0; + private int statusRequest = 0; + private int statusSettingState = 0; + private boolean offlineSent = false; + private String uploadingAvatar = null; + + public boolean enableJoined = true; + public int fontSize = AndroidUtilities.dp(16); + public int maxGroupCount = 200; + public int maxBroadcastCount = 100; + public int maxMegagroupCount = 5000; + public int minGroupConvertSize = 200; + public int maxEditTime = 172800; + public int groupBigSize; + private ArrayList disabledFeatures = new ArrayList<>(); + //plus + public boolean hideLeftGroup; + public boolean hideJoinedGroup; + // + private class UserActionUpdatesSeq extends TLRPC.Updates { + + } + + private class UserActionUpdatesPts extends TLRPC.Updates { + + } + + public static final int UPDATE_MASK_NAME = 1; + public static final int UPDATE_MASK_AVATAR = 2; + public static final int UPDATE_MASK_STATUS = 4; + public static final int UPDATE_MASK_CHAT_AVATAR = 8; + public static final int UPDATE_MASK_CHAT_NAME = 16; + public static final int UPDATE_MASK_CHAT_MEMBERS = 32; + public static final int UPDATE_MASK_USER_PRINT = 64; + public static final int UPDATE_MASK_USER_PHONE = 128; + public static final int UPDATE_MASK_READ_DIALOG_MESSAGE = 256; + public static final int UPDATE_MASK_SELECT_DIALOG = 512; + public static final int UPDATE_MASK_PHONE = 1024; + public static final int UPDATE_MASK_NEW_MESSAGE = 2048; + public static final int UPDATE_MASK_SEND_STATE = 4096; + public static final int UPDATE_MASK_CHANNEL = 8192; + public static final int UPDATE_MASK_CHAT_ADMINS = 16384; + public static final int UPDATE_MASK_ALL = UPDATE_MASK_AVATAR | UPDATE_MASK_STATUS | UPDATE_MASK_NAME | UPDATE_MASK_CHAT_AVATAR | UPDATE_MASK_CHAT_NAME | UPDATE_MASK_CHAT_MEMBERS | UPDATE_MASK_USER_PRINT | UPDATE_MASK_USER_PHONE | UPDATE_MASK_READ_DIALOG_MESSAGE | UPDATE_MASK_PHONE; + + public static class PrintingUser { + public long lastTime; + public int userId; + public TLRPC.SendMessageAction action; + } + + private static volatile MessagesController Instance = null; + + public static MessagesController getInstance() { + MessagesController localInstance = Instance; + if (localInstance == null) { + synchronized (MessagesController.class) { + localInstance = Instance; + if (localInstance == null) { + Instance = localInstance = new MessagesController(); + } + } + } + return localInstance; + } + + public MessagesController() { + ImageLoader.getInstance(); + MessagesStorage.getInstance(); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidUpload); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidFailUpload); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidLoaded); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidFailedLoad); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.messageReceivedByServer); + addSupportUser(); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + enableJoined = preferences.getBoolean("EnableContactJoined", true); + //plus + SharedPreferences plusPrefs = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + hideLeftGroup = plusPrefs.getBoolean("hideLeftGroup", false); + hideJoinedGroup = plusPrefs.getBoolean("hideJoinedGroup", false); + // + preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + secretWebpagePreview = preferences.getInt("secretWebpage2", 2); + maxGroupCount = preferences.getInt("maxGroupCount", 200); + maxMegagroupCount = preferences.getInt("maxMegagroupCount", 1000); + maxEditTime = preferences.getInt("maxEditTime", 3600); + groupBigSize = preferences.getInt("groupBigSize", 10); + //fontSize = preferences.getInt("fons_size", AndroidUtilities.isTablet() ? 18 : 16); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + fontSize = themePrefs.getInt("chatTextSize", AndroidUtilities.isTablet() ? 18 : 16); + String disabledFeaturesString = preferences.getString("disabledFeatures", null); + if (disabledFeaturesString != null && disabledFeaturesString.length() != 0) { + try { + byte[] bytes = Base64.decode(disabledFeaturesString, Base64.DEFAULT); + if (bytes != null) { + SerializedData data = new SerializedData(bytes); + int count = data.readInt32(false); + for (int a = 0; a < count; a++) { + TLRPC.TL_disabledFeature feature = TLRPC.TL_disabledFeature.TLdeserialize(data, data.readInt32(false), false); + if (feature != null && feature.feature != null && feature.description != null) { + disabledFeatures.add(feature); + } + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + public void updateConfig(final TLRPC.TL_config config) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + //maxBroadcastCount = config.broadcast_size_max; + maxMegagroupCount = config.megagroup_size_max; + maxGroupCount = config.chat_size_max; + groupBigSize = config.chat_big_size; + disabledFeatures = config.disabled_features; + maxEditTime = config.edit_time_limit; + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("maxGroupCount", maxGroupCount); + //editor.putInt("maxBroadcastCount", maxBroadcastCount); + editor.putInt("maxMegagroupCount", maxMegagroupCount); + editor.putInt("groupBigSize", groupBigSize); + editor.putInt("maxEditTime", maxEditTime); + try { + SerializedData data = new SerializedData(); + data.writeInt32(disabledFeatures.size()); + for (TLRPC.TL_disabledFeature disabledFeature : disabledFeatures) { + disabledFeature.serializeToStream(data); + } + String string = Base64.encodeToString(data.toByteArray(), Base64.DEFAULT); + if (string.length() != 0) { + editor.putString("disabledFeatures", string); + } + } catch (Exception e) { + editor.remove("disabledFeatures"); + FileLog.e("tmessages", e); + } + editor.commit(); + } + }); + } + + public static boolean isFeatureEnabled(String feature, BaseFragment fragment) { + if (feature == null || feature.length() == 0 || getInstance().disabledFeatures.isEmpty() || fragment == null) { + return true; + } + for (TLRPC.TL_disabledFeature disabledFeature : getInstance().disabledFeatures) { + if (disabledFeature.feature.equals(feature)) { + if (fragment.getParentActivity() != null) { + AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getParentActivity()); + builder.setTitle("Oops!"); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + builder.setMessage(disabledFeature.description); + fragment.showDialog(builder.create()); + } + return false; + } + } + return true; + } + + public void addSupportUser() { + TLRPC.TL_userForeign_old2 user = new TLRPC.TL_userForeign_old2(); + user.phone = "333"; + user.id = 333000; + user.first_name = "Telegram"; + user.last_name = ""; + user.status = null; + user.photo = new TLRPC.TL_userProfilePhotoEmpty(); + putUser(user, true); + + user = new TLRPC.TL_userForeign_old2(); + user.phone = "42777"; + user.id = 777000; + user.first_name = "Telegram"; + user.last_name = "Notifications"; + user.status = null; + user.photo = new TLRPC.TL_userProfilePhotoEmpty(); + putUser(user, true); + } + + public static TLRPC.InputUser getInputUser(TLRPC.User user) { + if (user == null) { + return new TLRPC.TL_inputUserEmpty(); + } + TLRPC.InputUser inputUser; + if (user.id == UserConfig.getClientUserId()) { + inputUser = new TLRPC.TL_inputUserSelf(); + } else { + inputUser = new TLRPC.TL_inputUser(); + inputUser.user_id = user.id; + inputUser.access_hash = user.access_hash; + } + return inputUser; + } + + public static TLRPC.InputUser getInputUser(int user_id) { + TLRPC.User user = getInstance().getUser(user_id); + return getInputUser(user); + } + + public static TLRPC.InputChannel getInputChannel(TLRPC.Chat chat) { + if (chat instanceof TLRPC.TL_channel || chat instanceof TLRPC.TL_channelForbidden) { + TLRPC.InputChannel inputChat = new TLRPC.TL_inputChannel(); + inputChat.channel_id = chat.id; + inputChat.access_hash = chat.access_hash; + return inputChat; + } else { + return new TLRPC.TL_inputChannelEmpty(); + } + } + + public static TLRPC.InputChannel getInputChannel(int chatId) { + return getInputChannel(getInstance().getChat(chatId)); + } + + public static TLRPC.InputPeer getInputPeer(int id) { + TLRPC.InputPeer inputPeer; + if (id < 0) { + TLRPC.Chat chat = getInstance().getChat(-id); + if (ChatObject.isChannel(chat)) { + inputPeer = new TLRPC.TL_inputPeerChannel(); + inputPeer.channel_id = -id; + inputPeer.access_hash = chat.access_hash; + } else { + inputPeer = new TLRPC.TL_inputPeerChat(); + inputPeer.chat_id = -id; + } + } else { + TLRPC.User user = getInstance().getUser(id); + inputPeer = new TLRPC.TL_inputPeerUser(); + inputPeer.user_id = id; + if (user != null) { + inputPeer.access_hash = user.access_hash; + } + } + return inputPeer; + } + + public static TLRPC.Peer getPeer(int id) { + TLRPC.Peer inputPeer; + if (id < 0) { + TLRPC.Chat chat = getInstance().getChat(-id); + if (chat instanceof TLRPC.TL_channel || chat instanceof TLRPC.TL_channelForbidden) { + inputPeer = new TLRPC.TL_peerChannel(); + inputPeer.channel_id = -id; + } else { + inputPeer = new TLRPC.TL_peerChat(); + inputPeer.chat_id = -id; + } + } else { + TLRPC.User user = getInstance().getUser(id); + inputPeer = new TLRPC.TL_peerUser(); + inputPeer.user_id = id; + } + return inputPeer; + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.FileDidUpload) { + final String location = (String) args[0]; + final TLRPC.InputFile file = (TLRPC.InputFile) args[1]; + + if (uploadingAvatar != null && uploadingAvatar.equals(location)) { + TLRPC.TL_photos_uploadProfilePhoto req = new TLRPC.TL_photos_uploadProfilePhoto(); + req.caption = ""; + req.crop = new TLRPC.TL_inputPhotoCropAuto(); + req.file = file; + req.geo_point = new TLRPC.TL_inputGeoPointEmpty(); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.User user = getUser(UserConfig.getClientUserId()); + if (user == null) { + user = UserConfig.getCurrentUser(); + putUser(user, true); + } else { + UserConfig.setCurrentUser(user); + } + if (user == null) { + return; + } + TLRPC.TL_photos_photo photo = (TLRPC.TL_photos_photo) response; + ArrayList sizes = photo.photo.sizes; + TLRPC.PhotoSize smallSize = FileLoader.getClosestPhotoSizeWithSize(sizes, 100); + TLRPC.PhotoSize bigSize = FileLoader.getClosestPhotoSizeWithSize(sizes, 1000); + user.photo = new TLRPC.TL_userProfilePhoto(); + user.photo.photo_id = photo.photo.id; + if (smallSize != null) { + user.photo.photo_small = smallSize.location; + } + if (bigSize != null) { + user.photo.photo_big = bigSize.location; + } else if (smallSize != null) { + user.photo.photo_small = smallSize.location; + } + MessagesStorage.getInstance().clearUserPhotos(user.id); + ArrayList users = new ArrayList<>(); + users.add(user); + MessagesStorage.getInstance().putUsersAndChats(users, null, false, true); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_AVATAR); + UserConfig.saveConfig(true); + } + }); + } + } + }); + } + } else if (id == NotificationCenter.FileDidFailUpload) { + final String location = (String) args[0]; + if (uploadingAvatar != null && uploadingAvatar.equals(location)) { + uploadingAvatar = null; + } + } else if (id == NotificationCenter.messageReceivedByServer) { + Integer msgId = (Integer) args[0]; + Integer newMsgId = (Integer) args[1]; + Long did = (Long) args[3]; + MessageObject obj = dialogMessage.get(did); + if (obj != null && obj.getId() == msgId) { + obj.messageOwner.id = newMsgId; + obj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + TLRPC.Dialog dialog = dialogs_dict.get(did); + if (dialog != null) { + if (dialog.top_message == msgId) { + dialog.top_message = newMsgId; + } + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + } + obj = dialogMessagesByIds.remove(msgId); + if (obj != null) { + dialogMessagesByIds.put(newMsgId, obj); + } + } + } + + public void cleanUp() { + ContactsController.getInstance().cleanup(); + MediaController.getInstance().cleanup(); + NotificationsController.getInstance().cleanup(); + SendMessagesHelper.getInstance().cleanUp(); + SecretChatHelper.getInstance().cleanUp(); + StickersQuery.cleanup(); + + reloadingWebpages.clear(); + reloadingWebpagesPending.clear(); + dialogs_dict.clear(); + dialogs_read_inbox_max.clear(); + exportedChats.clear(); + fullUsersAbout.clear(); + dialogs.clear(); + joiningToChannels.clear(); + channelViewsToSend.clear(); + channelViewsToReload.clear(); + dialogsServerOnly.clear(); + dialogsGroupsOnly.clear(); + //plus + dialogsUsers.clear(); + dialogsGroups.clear(); + dialogsGroupsAll.clear(); + dialogsChannels.clear(); + dialogsMegaGroups.clear(); + dialogsBots.clear(); + dialogsFavs.clear(); + // + dialogMessagesByIds.clear(); + dialogMessagesByRandomIds.clear(); + users.clear(); + usersByUsernames.clear(); + chats.clear(); + dialogMessage.clear(); + printingUsers.clear(); + printingStrings.clear(); + printingStringsTypes.clear(); + onlinePrivacy.clear(); + loadingPeerSettings.clear(); + lastPrintingStringCount = 0; + nextDialogsCacheOffset = 0; + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + updatesQueueSeq.clear(); + updatesQueuePts.clear(); + updatesQueueQts.clear(); + updatesStartWaitTimeSeq = 0; + updatesStartWaitTimePts = 0; + updatesStartWaitTimeQts = 0; + createdDialogIds.clear(); + gettingDifference = false; + } + }); + blockedUsers.clear(); + sendingTypings.clear(); + loadingFullUsers.clear(); + loadedFullUsers.clear(); + reloadingMessages.clear(); + loadingFullChats.clear(); + loadingFullParticipants.clear(); + loadedFullParticipants.clear(); + loadedFullChats.clear(); + + currentDeletingTaskTime = 0; + currentDeletingTaskMids = null; + gettingNewDeleteTask = false; + loadingDialogs = false; + dialogsEndReached = false; + loadingBlockedUsers = false; + firstGettingTask = false; + updatingState = false; + lastStatusUpdateTime = 0; + offlineSent = false; + registeringForPush = false; + uploadingAvatar = null; + statusRequest = 0; + statusSettingState = 0; + + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + ConnectionsManager.getInstance().setIsUpdating(false); + updatesQueueChannels.clear(); + updatesStartWaitTimeChannels.clear(); + gettingDifferenceChannels.clear(); + channelsPts.clear(); + shortPollChannels.clear(); + needShortPollChannels.clear(); + } + }); + + if (currentDeleteTaskRunnable != null) { + Utilities.stageQueue.cancelRunnable(currentDeleteTaskRunnable); + currentDeleteTaskRunnable = null; + } + + addSupportUser(); + } + + public TLRPC.User getUser(Integer id) { + return users.get(id); + } + + public TLRPC.User getUser(String username) { + if (username == null || username.length() == 0) { + return null; + } + return usersByUsernames.get(username.toLowerCase()); + } + + public ConcurrentHashMap getUsers() { + return users; + } + + public TLRPC.Chat getChat(Integer id) { + return chats.get(id); + } + + public TLRPC.EncryptedChat getEncryptedChat(Integer id) { + return encryptedChats.get(id); + } + + public TLRPC.EncryptedChat getEncryptedChatDB(int chat_id) { + TLRPC.EncryptedChat chat = encryptedChats.get(chat_id); + if (chat == null) { + Semaphore semaphore = new Semaphore(0); + ArrayList result = new ArrayList<>(); + MessagesStorage.getInstance().getEncryptedChat(chat_id, semaphore, result); + try { + semaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (result.size() == 2) { + chat = (TLRPC.EncryptedChat) result.get(0); + TLRPC.User user = (TLRPC.User) result.get(1); + putEncryptedChat(chat, false); + putUser(user, true); + } + } + return chat; + } + + public void setLastCreatedDialogId(final long dialog_id, final boolean set) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (set) { + createdDialogIds.add(dialog_id); + } else { + createdDialogIds.remove(dialog_id); + } + } + }); + } + + public TLRPC.ExportedChatInvite getExportedInvite(int chat_id) { + return exportedChats.get(chat_id); + } + + public boolean putUser(TLRPC.User user, boolean fromCache) { + if (user == null) { + return false; + } + fromCache = fromCache && user.id / 1000 != 333 && user.id != 777000; + TLRPC.User oldUser = users.get(user.id); + if (oldUser != null && oldUser.username != null && oldUser.username.length() > 0) { + usersByUsernames.remove(oldUser.username); + } + if (user.username != null && user.username.length() > 0) { + usersByUsernames.put(user.username.toLowerCase(), user); + } + if (user.min) { + if (oldUser != null) { + if (!fromCache) { + if (user.username != null) { + oldUser.username = user.username; + oldUser.flags |= 8; + } else { + oldUser.username = null; + oldUser.flags = oldUser.flags &~ 8; + } + if (user.photo != null) { + oldUser.photo = user.photo; + oldUser.flags |= 32; + } else { + oldUser.photo = null; + oldUser.flags = oldUser.flags &~ 32; + } + } + } else { + users.put(user.id, user); + } + } else { + if (!fromCache) { + users.put(user.id, user); + if (user.id == UserConfig.getClientUserId()) { + UserConfig.setCurrentUser(user); + UserConfig.saveConfig(true); + } + if (oldUser != null && user.status != null && oldUser.status != null && user.status.expires != oldUser.status.expires) { + return true; + } + } else if (oldUser == null) { + users.put(user.id, user); + } else if (oldUser.min) { + user.min = false; + if (oldUser.username != null) { + user.username = oldUser.username; + user.flags |= 8; + } else { + user.username = null; + user.flags = user.flags &~ 8; + } + if (oldUser.photo != null) { + user.photo = oldUser.photo; + user.flags |= 32; + } else { + user.photo = null; + user.flags = user.flags &~ 32; + } + users.put(user.id, user); + } + } + return false; + } + + public void putUsers(ArrayList users, boolean fromCache) { + if (users == null || users.isEmpty()) { + return; + } + boolean updateStatus = false; + int count = users.size(); + for (int a = 0; a < count; a++) { + TLRPC.User user = users.get(a); + if (putUser(user, fromCache)) { + updateStatus = true; + } + } + if (updateStatus) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_STATUS); + } + }); + } + } + + public void putChat(TLRPC.Chat chat, boolean fromCache) { + if (chat == null) { + return; + } + TLRPC.Chat oldChat = chats.get(chat.id); + + if (chat.min) { + if (oldChat != null) { + if (!fromCache) { + oldChat.title = chat.title; + oldChat.photo = chat.photo; + oldChat.broadcast = chat.broadcast; + oldChat.verified = chat.verified; + oldChat.megagroup = chat.megagroup; + oldChat.democracy = chat.democracy; + if (chat.username != null) { + oldChat.username = chat.username; + oldChat.flags |= 64; + } else { + oldChat.username = null; + oldChat.flags = oldChat.flags &~ 64; + } + } + } else { + chats.put(chat.id, chat); + } + } else { + if (!fromCache) { + if (oldChat != null && chat.version != oldChat.version) { + loadedFullChats.remove((Integer) chat.id); + } + chats.put(chat.id, chat); + } else if (oldChat == null) { + chats.put(chat.id, chat); + } else if (oldChat.min) { + chat.min = false; + chat.title = oldChat.title; + chat.photo = oldChat.photo; + chat.broadcast = oldChat.broadcast; + chat.verified = oldChat.verified; + chat.megagroup = oldChat.megagroup; + chat.democracy = oldChat.democracy; + if (oldChat.username != null) { + chat.username = oldChat.username; + chat.flags |= 64; + } else { + chat.username = null; + chat.flags = chat.flags &~ 64; + } + chats.put(chat.id, chat); + } + } + } + + public void putChats(ArrayList chats, boolean fromCache) { + if (chats == null || chats.isEmpty()) { + return; + } + int count = chats.size(); + for (int a = 0; a < count; a++) { + TLRPC.Chat chat = chats.get(a); + putChat(chat, fromCache); + } + } + + public void putEncryptedChat(TLRPC.EncryptedChat encryptedChat, boolean fromCache) { + if (encryptedChat == null) { + return; + } + if (fromCache) { + encryptedChats.putIfAbsent(encryptedChat.id, encryptedChat); + } else { + encryptedChats.put(encryptedChat.id, encryptedChat); + } + } + + public void putEncryptedChats(ArrayList encryptedChats, boolean fromCache) { + if (encryptedChats == null || encryptedChats.isEmpty()) { + return; + } + int count = encryptedChats.size(); + for (int a = 0; a < count; a++) { + TLRPC.EncryptedChat encryptedChat = encryptedChats.get(a); + putEncryptedChat(encryptedChat, fromCache); + } + } + + public String getUserAbout(int uid) { + return fullUsersAbout.get(uid); + } + + public void cancelLoadFullUser(int uid) { + loadingFullUsers.remove((Integer) uid); + } + + public void cancelLoadFullChat(int cid) { + loadingFullChats.remove((Integer) cid); + } + + protected void clearFullUsers() { + loadedFullUsers.clear(); + loadedFullChats.clear(); + } + + public void loadFullChat(final int chat_id, final int classGuid, boolean force) { + if (loadingFullChats.contains(chat_id) || !force && loadedFullChats.contains(chat_id)) { + return; + } + loadingFullChats.add(chat_id); + TLObject request; + final TLRPC.Chat chat = getChat(chat_id); + if (ChatObject.isChannel(chat_id)) { + TLRPC.TL_channels_getFullChannel req = new TLRPC.TL_channels_getFullChannel(); + req.channel = getInputChannel(chat_id); + request = req; + } else { + TLRPC.TL_messages_getFullChat req = new TLRPC.TL_messages_getFullChat(); + req.chat_id = chat_id; + request = req; + } + int reqId = ConnectionsManager.getInstance().sendRequest(request, new RequestDelegate() { + @Override + public void run(TLObject response, final TLRPC.TL_error error) { + if (error == null) { + final TLRPC.TL_messages_chatFull res = (TLRPC.TL_messages_chatFull) response; + if (chat != null && chat.megagroup) { + res.full_chat.unread_important_count = Math.max(res.full_chat.unread_important_count, res.full_chat.unread_count); + } + MessagesStorage.getInstance().putUsersAndChats(res.users, res.chats, true, true); + MessagesStorage.getInstance().updateChatInfo(res.full_chat, false); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + applyDialogNotificationsSettings(-chat_id, res.full_chat.notify_settings); + for (int a = 0; a < res.full_chat.bot_info.size(); a++) { + TLRPC.BotInfo botInfo = res.full_chat.bot_info.get(a); + BotQuery.putBotInfo(botInfo); + } + exportedChats.put(chat_id, res.full_chat.exported_invite); + loadingFullChats.remove((Integer) chat_id); + loadedFullChats.add(chat_id); + if (!res.chats.isEmpty()) { + TLRPC.Chat chat = res.chats.get(0); + chat.address = res.full_chat.about; + } + + putUsers(res.users, false); + putChats(res.chats, false); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, res.full_chat, classGuid, false, null); + } + }); + } else { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + checkChannelError(error.text, chat_id); + loadingFullChats.remove((Integer) chat_id); + } + }); + } + } + }); + if (classGuid != 0) { + ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); + } + } + + public void loadFullUser(final TLRPC.User user, final int classGuid, boolean force) { + if (user == null || loadingFullUsers.contains(user.id) || !force && loadedFullUsers.contains(user.id)) { + return; + } + loadingFullUsers.add(user.id); + TLRPC.TL_users_getFullUser req = new TLRPC.TL_users_getFullUser(); + req.id = getInputUser(user); + int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, TLRPC.TL_error error) { + if (error == null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + TLRPC.TL_userFull userFull = (TLRPC.TL_userFull) response; + applyDialogNotificationsSettings(user.id, userFull.notify_settings); + if (userFull.bot_info instanceof TLRPC.TL_botInfo) { + BotQuery.putBotInfo(userFull.bot_info); + } + if (userFull.about != null && userFull.about.length() > 0) { + fullUsersAbout.put(user.id, userFull.about); + } else { + fullUsersAbout.remove(user.id); + } + loadingFullUsers.remove((Integer) user.id); + loadedFullUsers.add(user.id); + String names = user.first_name + user.last_name + user.username; + ArrayList users = new ArrayList<>(); + users.add(userFull.user); + putUsers(users, false); + MessagesStorage.getInstance().putUsersAndChats(users, null, false, true); + if (names != null && !names.equals(userFull.user.first_name + userFull.user.last_name + userFull.user.username)) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_NAME); + } + if (userFull.bot_info instanceof TLRPC.TL_botInfo) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.botInfoDidLoaded, userFull.bot_info, classGuid); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.userInfoDidLoaded, user.id); + } + }); + } else { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + loadingFullUsers.remove((Integer) user.id); + } + }); + } + } + }); + ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); + } + + private void reloadMessages(final ArrayList mids, final long dialog_id) { + if (mids.isEmpty()) { + return; + } + TLObject request; + final ArrayList result = new ArrayList<>(); + final TLRPC.Chat chat = ChatObject.getChatByDialog(dialog_id); + if (ChatObject.isChannel(chat)) { + TLRPC.TL_channels_getMessages req = new TLRPC.TL_channels_getMessages(); + req.channel = getInputChannel(chat); + req.id = result; + request = req; + } else { + TLRPC.TL_messages_getMessages req = new TLRPC.TL_messages_getMessages(); + req.id = result; + request = req; + } + ArrayList arrayList = reloadingMessages.get(dialog_id); + for (int a = 0; a < mids.size(); a++) { + Integer mid = mids.get(a); + if (arrayList != null && arrayList.contains(mid)) { + continue; + } + result.add(mid); + } + if (result.isEmpty()) { + return; + } + if (arrayList == null) { + arrayList = new ArrayList<>(); + reloadingMessages.put(dialog_id, arrayList); + } + arrayList.addAll(result); + ConnectionsManager.getInstance().sendRequest(request, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; + + final HashMap usersLocal = new HashMap<>(); + for (int a = 0; a < messagesRes.users.size(); a++) { + TLRPC.User u = messagesRes.users.get(a); + usersLocal.put(u.id, u); + } + final HashMap chatsLocal = new HashMap<>(); + for (int a = 0; a < messagesRes.chats.size(); a++) { + TLRPC.Chat c = messagesRes.chats.get(a); + chatsLocal.put(c.id, c); + } + + final ArrayList objects = new ArrayList<>(); + for (int a = 0; a < messagesRes.messages.size(); a++) { + TLRPC.Message message = messagesRes.messages.get(a); + if (chat != null && chat.megagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + message.dialog_id = dialog_id; + objects.add(new MessageObject(message, usersLocal, chatsLocal, true)); + } + + ImageLoader.saveMessagesThumbs(messagesRes.messages); + MessagesStorage.getInstance().putMessages(messagesRes, dialog_id, -1, 0, 0, false); + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + ArrayList arrayList = reloadingMessages.get(dialog_id); + if (arrayList != null) { + arrayList.removeAll(result); + if (arrayList.isEmpty()) { + reloadingMessages.remove(dialog_id); + } + } + MessageObject dialogObj = dialogMessage.get(dialog_id); + if (dialogObj != null) { + for (int a = 0; a < objects.size(); a++) { + MessageObject obj = objects.get(a); + if (dialogObj != null && dialogObj.getId() == obj.getId()) { + dialogMessage.put(dialog_id, obj); + if (obj.messageOwner.to_id.channel_id == 0) { + obj = dialogMessagesByIds.remove(obj.getId()); + if (obj != null) { + dialogMessagesByIds.put(obj.getId(), obj); + } + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + break; + } + } + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, objects); + } + }); + } + } + }); + } + + public void hideReportSpam(final long dialogId, TLRPC.User currentUser, TLRPC.Chat currentChat) { + if (currentUser == null && currentChat == null) { + return; + } + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("spam3_" + dialogId, 1); + editor.commit(); + TLRPC.TL_messages_hideReportSpam req = new TLRPC.TL_messages_hideReportSpam(); + if (currentUser != null) { + req.peer = MessagesController.getInputPeer(currentUser.id); + } else if (currentChat != null) { + req.peer = MessagesController.getInputPeer(-currentChat.id); + } + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }); + } + + public void reportSpam(final long dialogId, TLRPC.User currentUser, TLRPC.Chat currentChat) { + if (currentUser == null && currentChat == null) { + return; + } + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("spam3_" + dialogId, 1); + editor.commit(); + TLRPC.TL_messages_reportSpam req = new TLRPC.TL_messages_reportSpam(); + if (currentChat != null) { + req.peer = MessagesController.getInputPeer(-currentChat.id); + } else if (currentUser != null) { + req.peer = MessagesController.getInputPeer(currentUser.id); + } + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + } + + public void loadPeerSettings(final long dialogId, TLRPC.User currentUser, TLRPC.Chat currentChat) { + if (loadingPeerSettings.containsKey(dialogId) || currentUser == null && currentChat == null) { + return; + } + loadingPeerSettings.put(dialogId, true); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + if (preferences.getInt("spam3_" + dialogId, 0) == 1) { + return; + } + boolean hidden = preferences.getBoolean("spam_" + dialogId, false); + if (hidden) { + TLRPC.TL_messages_hideReportSpam req = new TLRPC.TL_messages_hideReportSpam(); + if (currentUser != null) { + req.peer = MessagesController.getInputPeer(currentUser.id); + } else if (currentChat != null) { + req.peer = MessagesController.getInputPeer(-currentChat.id); + } + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + loadingPeerSettings.remove(dialogId); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.remove("spam_" + dialogId); + editor.putInt("spam3_" + dialogId, 1); + editor.commit(); + } + }); + } + }); + return; + } + TLRPC.TL_messages_getPeerSettings req = new TLRPC.TL_messages_getPeerSettings(); + if (currentUser != null) { + req.peer = MessagesController.getInputPeer(currentUser.id); + } else if (currentChat != null) { + req.peer = MessagesController.getInputPeer(-currentChat.id); + } + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + loadingPeerSettings.remove(dialogId); + if (response != null) { + TLRPC.TL_peerSettings res = (TLRPC.TL_peerSettings) response; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + if (!res.report_spam) { + editor.putInt("spam3_" + dialogId, 1); + } else { + editor.putInt("spam3_" + dialogId, 2); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.peerSettingsDidLoaded, dialogId); + } + editor.commit(); + } + } + }); + } + }); + } + + protected void processNewChannelDifferenceParams(int pts, int pts_count, int channelId) { + FileLog.e("tmessages", "processNewChannelDifferenceParams pts = " + pts + " pts_count = " + pts_count + " channeldId = " + channelId); + TLRPC.Dialog dialog = dialogs_dict.get((long) -channelId); + if (dialog instanceof TLRPC.TL_dialogChannel) { + Integer channelPts = channelsPts.get(channelId); + if (channelPts == null) { + channelPts = MessagesStorage.getInstance().getChannelPtsSync(channelId); + if (channelPts == 0) { + channelPts = 1; + } + channelsPts.put(channelId, channelPts); + } + if (channelPts + pts_count == pts) { + FileLog.e("tmessages", "APPLY CHANNEL PTS"); + channelsPts.put(channelId, pts); + MessagesStorage.getInstance().saveChannelPts(channelId, pts); + } else if (channelPts != pts) { + Long updatesStartWaitTime = updatesStartWaitTimeChannels.get(channelId); + Boolean gettingDifferenceChannel = gettingDifferenceChannels.get(channelId); + if (gettingDifferenceChannel == null) { + gettingDifferenceChannel = false; + } + if (gettingDifferenceChannel || updatesStartWaitTime == null || Math.abs(System.currentTimeMillis() - updatesStartWaitTime) <= 1500) { + FileLog.e("tmessages", "ADD CHANNEL UPDATE TO QUEUE pts = " + pts + " pts_count = " + pts_count); + if (updatesStartWaitTime == null) { + updatesStartWaitTimeChannels.put(channelId, System.currentTimeMillis()); + } + UserActionUpdatesPts updates = new UserActionUpdatesPts(); + updates.pts = pts; + updates.pts_count = pts_count; + updates.chat_id = channelId; + ArrayList arrayList = updatesQueueChannels.get(channelId); + if (arrayList == null) { + arrayList = new ArrayList<>(); + updatesQueueChannels.put(channelId, arrayList); + } + arrayList.add(updates); + } else { + getChannelDifference(channelId); + } + } + } + } + + protected void processNewDifferenceParams(int seq, int pts, int date, int pts_count) { + FileLog.e("tmessages", "processNewDifferenceParams seq = " + seq + " pts = " + pts + " date = " + date + " pts_count = " + pts_count); + if (pts != -1) { + if (MessagesStorage.lastPtsValue + pts_count == pts) { + FileLog.e("tmessages", "APPLY PTS"); + MessagesStorage.lastPtsValue = pts; + MessagesStorage.getInstance().saveDiffParams(MessagesStorage.lastSeqValue, MessagesStorage.lastPtsValue, MessagesStorage.lastDateValue, MessagesStorage.lastQtsValue); + } else if (MessagesStorage.lastPtsValue != pts) { + if (gettingDifference || updatesStartWaitTimePts == 0 || Math.abs(System.currentTimeMillis() - updatesStartWaitTimePts) <= 1500) { + FileLog.e("tmessages", "ADD UPDATE TO QUEUE pts = " + pts + " pts_count = " + pts_count); + if (updatesStartWaitTimePts == 0) { + updatesStartWaitTimePts = System.currentTimeMillis(); + } + UserActionUpdatesPts updates = new UserActionUpdatesPts(); + updates.pts = pts; + updates.pts_count = pts_count; + updatesQueuePts.add(updates); + } else { + getDifference(); + } + } + } + if (seq != -1) { + if (MessagesStorage.lastSeqValue + 1 == seq) { + FileLog.e("tmessages", "APPLY SEQ"); + MessagesStorage.lastSeqValue = seq; + if (date != -1) { + MessagesStorage.lastDateValue = date; + } + MessagesStorage.getInstance().saveDiffParams(MessagesStorage.lastSeqValue, MessagesStorage.lastPtsValue, MessagesStorage.lastDateValue, MessagesStorage.lastQtsValue); + } else if (MessagesStorage.lastSeqValue != seq) { + if (gettingDifference || updatesStartWaitTimeSeq == 0 || Math.abs(System.currentTimeMillis() - updatesStartWaitTimeSeq) <= 1500) { + FileLog.e("tmessages", "ADD UPDATE TO QUEUE seq = " + seq); + if (updatesStartWaitTimeSeq == 0) { + updatesStartWaitTimeSeq = System.currentTimeMillis(); + } + UserActionUpdatesSeq updates = new UserActionUpdatesSeq(); + updates.seq = seq; + updatesQueueSeq.add(updates); + } else { + getDifference(); + } + } + } + } + + public void didAddedNewTask(final int minDate, final SparseArray> mids) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (currentDeletingTaskMids == null && !gettingNewDeleteTask || currentDeletingTaskTime != 0 && minDate < currentDeletingTaskTime) { + getNewDeleteTask(null); + } + } + }); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didCreatedNewDeleteTask, mids); + } + }); + } + + public void getNewDeleteTask(final ArrayList oldTask) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + gettingNewDeleteTask = true; + MessagesStorage.getInstance().getNewTask(oldTask); + } + }); + } + + private boolean checkDeletingTask(boolean runnable) { + int currentServerTime = ConnectionsManager.getInstance().getCurrentTime(); + + if (currentDeletingTaskMids != null && (runnable || currentDeletingTaskTime != 0 && currentDeletingTaskTime <= currentServerTime)) { + currentDeletingTaskTime = 0; + if (currentDeleteTaskRunnable != null && !runnable) { + Utilities.stageQueue.cancelRunnable(currentDeleteTaskRunnable); + } + currentDeleteTaskRunnable = null; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + deleteMessages(currentDeletingTaskMids, null, null, 0); + + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + getNewDeleteTask(currentDeletingTaskMids); + currentDeletingTaskTime = 0; + currentDeletingTaskMids = null; + } + }); + } + }); + return true; + } + return false; + } + + public void processLoadedDeleteTask(final int taskTime, final ArrayList messages) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + gettingNewDeleteTask = false; + if (messages != null) { + currentDeletingTaskTime = taskTime; + currentDeletingTaskMids = messages; + + if (currentDeleteTaskRunnable != null) { + Utilities.stageQueue.cancelRunnable(currentDeleteTaskRunnable); + currentDeleteTaskRunnable = null; + } + + if (!checkDeletingTask(false)) { + currentDeleteTaskRunnable = new Runnable() { + @Override + public void run() { + checkDeletingTask(true); + } + }; + int currentServerTime = ConnectionsManager.getInstance().getCurrentTime(); + Utilities.stageQueue.postRunnable(currentDeleteTaskRunnable, (long) Math.abs(currentServerTime - currentDeletingTaskTime) * 1000); + } + } else { + currentDeletingTaskTime = 0; + currentDeletingTaskMids = null; + } + } + }); + } + + public void loadUserPhotos(final int uid, final int offset, final int count, final long max_id, final boolean fromCache, final int classGuid) { + if (fromCache) { + MessagesStorage.getInstance().getUserPhotos(uid, offset, count, max_id, classGuid); + } else { + TLRPC.User user = getUser(uid); + if (user == null) { + return; + } + TLRPC.TL_photos_getUserPhotos req = new TLRPC.TL_photos_getUserPhotos(); + req.limit = count; + req.offset = offset; + req.max_id = (int) max_id; + req.user_id = getInputUser(user); + int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.photos_Photos res = (TLRPC.photos_Photos) response; + processLoadedUserPhotos(res, uid, offset, count, max_id, false, classGuid); + } + } + }); + ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); + } + } + + public void blockUser(int user_id) { + final TLRPC.User user = getUser(user_id); + if (user == null || blockedUsers.contains(user_id)) { + return; + } + blockedUsers.add(user_id); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.blockedUsersDidLoaded); + TLRPC.TL_contacts_block req = new TLRPC.TL_contacts_block(); + req.id = getInputUser(user); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + ArrayList ids = new ArrayList<>(); + ids.add(user.id); + MessagesStorage.getInstance().putBlockedUsers(ids, false); + } + } + }); + } + + public void unblockUser(int user_id) { + TLRPC.TL_contacts_unblock req = new TLRPC.TL_contacts_unblock(); + final TLRPC.User user = getUser(user_id); + if (user == null) { + return; + } + blockedUsers.remove((Integer) user.id); + req.id = getInputUser(user); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.blockedUsersDidLoaded); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + MessagesStorage.getInstance().deleteBlockedUser(user.id); + } + }); + } + + public void getBlockedUsers(boolean cache) { + if (!UserConfig.isClientActivated() || loadingBlockedUsers) { + return; + } + loadingBlockedUsers = true; + if (cache) { + MessagesStorage.getInstance().getBlockedUsers(); + } else { + TLRPC.TL_contacts_getBlocked req = new TLRPC.TL_contacts_getBlocked(); + req.offset = 0; + req.limit = 200; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + ArrayList blocked = new ArrayList<>(); + ArrayList users = null; + if (error == null) { + final TLRPC.contacts_Blocked res = (TLRPC.contacts_Blocked) response; + for (TLRPC.TL_contactBlocked contactBlocked : res.blocked) { + blocked.add(contactBlocked.user_id); + } + users = res.users; + MessagesStorage.getInstance().putUsersAndChats(res.users, null, true, true); + MessagesStorage.getInstance().putBlockedUsers(blocked, true); + } + processLoadedBlockedUsers(blocked, users, false); + } + }); + } + } + + public void processLoadedBlockedUsers(final ArrayList ids, final ArrayList users, final boolean cache) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (users != null) { + putUsers(users, cache); + } + loadingBlockedUsers = false; + if (ids.isEmpty() && cache && !UserConfig.blockedUsersLoaded) { + getBlockedUsers(false); + return; + } else if (!cache) { + UserConfig.blockedUsersLoaded = true; + UserConfig.saveConfig(false); + } + blockedUsers = ids; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.blockedUsersDidLoaded); + } + }); + } + + public void deleteUserPhoto(TLRPC.InputPhoto photo) { + if (photo == null) { + TLRPC.TL_photos_updateProfilePhoto req = new TLRPC.TL_photos_updateProfilePhoto(); + req.id = new TLRPC.TL_inputPhotoEmpty(); + req.crop = new TLRPC.TL_inputPhotoCropAuto(); + UserConfig.getCurrentUser().photo = new TLRPC.TL_userProfilePhotoEmpty(); + TLRPC.User user = getUser(UserConfig.getClientUserId()); + if (user == null) { + user = UserConfig.getCurrentUser(); + } + if (user == null) { + return; + } + user.photo = UserConfig.getCurrentUser().photo; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.mainUserInfoChanged); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_ALL); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.User user = getUser(UserConfig.getClientUserId()); + if (user == null) { + user = UserConfig.getCurrentUser(); + putUser(user, false); + } else { + UserConfig.setCurrentUser(user); + } + if (user == null) { + return; + } + MessagesStorage.getInstance().clearUserPhotos(user.id); + ArrayList users = new ArrayList<>(); + users.add(user); + MessagesStorage.getInstance().putUsersAndChats(users, null, false, true); + user.photo = (TLRPC.UserProfilePhoto) response; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.mainUserInfoChanged); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_ALL); + UserConfig.saveConfig(true); + } + }); + } + } + }); + } else { + TLRPC.TL_photos_deletePhotos req = new TLRPC.TL_photos_deletePhotos(); + req.id.add(photo); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }); + } + } + + public void processLoadedUserPhotos(final TLRPC.photos_Photos res, final int uid, final int offset, final int count, final long max_id, final boolean fromCache, final int classGuid) { + if (!fromCache) { + MessagesStorage.getInstance().putUsersAndChats(res.users, null, true, true); + MessagesStorage.getInstance().putUserPhotos(uid, res); + } else if (res == null || res.photos.isEmpty()) { + loadUserPhotos(uid, offset, count, max_id, false, classGuid); + return; + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + putUsers(res.users, fromCache); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.userPhotosLoaded, uid, offset, count, fromCache, classGuid, res.photos); + } + }); + } + + public void uploadAndApplyUserAvatar(TLRPC.PhotoSize bigPhoto) { + if (bigPhoto != null) { + uploadingAvatar = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + bigPhoto.location.volume_id + "_" + bigPhoto.location.local_id + ".jpg"; + FileLoader.getInstance().uploadFile(uploadingAvatar, false, true); + } + } + + public void markChannelDialogMessageAsDeleted(ArrayList messages, final int channelId) { + MessageObject obj = dialogMessage.get((long) -channelId); + if (obj != null) { + for (int a = 0; a < messages.size(); a++) { + Integer id = messages.get(a); + if (obj.getId() == id) { + obj.deleted = true; + break; + } + } + } + } + + public void deleteMessages(ArrayList messages, ArrayList randoms, TLRPC.EncryptedChat encryptedChat, final int channelId) { + if (messages == null || messages.isEmpty()) { + return; + } + if (channelId == 0) { + for (int a = 0; a < messages.size(); a++) { + Integer id = messages.get(a); + MessageObject obj = dialogMessagesByIds.get(id); + if (obj != null) { + obj.deleted = true; + } + } + } else { + markChannelDialogMessageAsDeleted(messages, channelId); + } + ArrayList toSend = new ArrayList<>(); + for (int a = 0; a < messages.size(); a++) { + Integer mid = messages.get(a); + if (mid > 0) { + toSend.add(mid); + } + } + MessagesStorage.getInstance().markMessagesAsDeleted(messages, true, channelId); + MessagesStorage.getInstance().updateDialogsWithDeletedMessages(messages, true, channelId); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDeleted, messages, channelId); + if (channelId != 0) { + TLRPC.TL_channels_deleteMessages req = new TLRPC.TL_channels_deleteMessages(); + req.id = toSend; + req.channel = getInputChannel(channelId); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; + processNewChannelDifferenceParams(res.pts, res.pts_count, channelId); + } + } + }); + } else { + if (randoms != null && encryptedChat != null && !randoms.isEmpty()) { + SecretChatHelper.getInstance().sendMessagesDeleteMessage(encryptedChat, randoms, null); + } + TLRPC.TL_messages_deleteMessages req = new TLRPC.TL_messages_deleteMessages(); + req.id = toSend; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; + processNewDifferenceParams(-1, res.pts, -1, res.pts_count); + } + } + }); + } + } + + public void pinChannelMessage(TLRPC.Chat chat, int id, boolean notify) { + TLRPC.TL_channels_updatePinnedMessage req = new TLRPC.TL_channels_updatePinnedMessage(); + req.channel = getInputChannel(chat); + req.id = id; + req.silent = !notify; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.Updates updates = (TLRPC.Updates) response; + processUpdates(updates, false); + } + } + }); + } + + public void deleteDialog(final long did, final int onlyHistory) { + deleteDialog(did, true, onlyHistory, 0); + } + + public void deleteUserChannelHistory(final TLRPC.Chat chat, final TLRPC.User user, int offset) { + if (offset == 0) { + MessagesStorage.getInstance().deleteUserChannelHistory(chat.id, user.id); + } + TLRPC.TL_channels_deleteUserHistory req = new TLRPC.TL_channels_deleteUserHistory(); + req.channel = getInputChannel(chat); + req.user_id = getInputUser(user); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.TL_messages_affectedHistory res = (TLRPC.TL_messages_affectedHistory) response; + if (res.offset > 0) { + deleteUserChannelHistory(chat, user, res.offset); + } + processNewChannelDifferenceParams(res.pts, res.pts_count, chat.id); + } + } + }); + } + + private void deleteDialog(final long did, final boolean first, final int onlyHistory, final int max_id) { + int lower_part = (int) did; + int high_id = (int) (did >> 32); + int max_id_delete = max_id; + + if (onlyHistory == 2) { + MessagesStorage.getInstance().deleteDialog(did, onlyHistory); + return; + } + + if (first) { + TLRPC.Dialog dialog = dialogs_dict.get(did); + if (dialog != null) { + if (max_id_delete == 0) { + max_id_delete = Math.max(0, dialog.top_message); + } + if (onlyHistory == 0) { + dialogs.remove(dialog); + if (dialogsServerOnly.remove(dialog)) { + if (dialog instanceof TLRPC.TL_dialogChannel) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + channelsPts.remove(-(int) did); + shortPollChannels.delete(-(int) did); + needShortPollChannels.delete(-(int) did); + } + }); + } + } + dialogsGroupsOnly.remove(dialog); + //plus + dialogsUsers.remove(dialog); + dialogsGroups.remove(dialog); + dialogsGroupsAll.remove(dialog); + dialogsChannels.remove(dialog); + dialogsMegaGroups.remove(dialog); + dialogsBots.remove(dialog); + dialogsFavs.remove(dialog); + // + dialogs_dict.remove(did); + dialogs_read_inbox_max.remove(did); + nextDialogsCacheOffset--; + } else { + dialog.unread_count = 0; + } + dialogMessage.remove(dialog.id); + MessageObject object = dialogMessagesByIds.remove(dialog.top_message); + if (object != null && object.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(object.messageOwner.random_id); + } + dialog.top_message = 0; + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.removeAllMessagesFromDialog, did, false); + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationsController.getInstance().removeNotificationsForDialog(did); + } + }); + } + }); + + MessagesStorage.getInstance().deleteDialog(did, onlyHistory); + } + + if (high_id == 1) { + return; + } + + if (lower_part != 0) { + TLRPC.InputPeer peer = getInputPeer(lower_part); + if (peer == null || peer instanceof TLRPC.TL_inputPeerChannel) { + return; + } + TLRPC.TL_messages_deleteHistory req = new TLRPC.TL_messages_deleteHistory(); + req.peer = peer; + req.max_id = max_id_delete; + final int max_id_delete_final = max_id_delete; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.TL_messages_affectedHistory res = (TLRPC.TL_messages_affectedHistory) response; + if (res.offset > 0) { + deleteDialog(did, false, onlyHistory, max_id_delete_final); + } + processNewDifferenceParams(-1, res.pts, -1, res.pts_count); + } + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } else { + if (onlyHistory == 1) { + SecretChatHelper.getInstance().sendClearHistoryMessage(getEncryptedChat(high_id), null); + } else { + SecretChatHelper.getInstance().declineSecretChat(high_id); + } + } + } + + public MediaController.SearchImage saveGif(TLRPC.Document document) { + MediaController.SearchImage searchImage = new MediaController.SearchImage(); + searchImage.type = 2; + searchImage.document = document; + searchImage.date = (int) (System.currentTimeMillis() / 1000); + searchImage.id = "" + searchImage.document.id; + + ArrayList arrayList = new ArrayList<>(); + arrayList.add(searchImage); + MessagesStorage.getInstance().putWebRecent(arrayList); + TLRPC.TL_messages_saveGif req = new TLRPC.TL_messages_saveGif(); + req.id = new TLRPC.TL_inputDocument(); + req.id.id = searchImage.document.id; + req.id.access_hash = searchImage.document.access_hash; + req.unsave = false; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }); + return searchImage; + } + + public void loadChannelParticipants(final Integer chat_id) { + if (loadingFullParticipants.contains(chat_id) || loadedFullParticipants.contains(chat_id)) { + return; + } + loadingFullParticipants.add(chat_id); + + final TLRPC.TL_channels_getParticipants req = new TLRPC.TL_channels_getParticipants(); + req.channel = getInputChannel(chat_id); + req.filter = new TLRPC.TL_channelParticipantsRecent(); + req.offset = 0; + req.limit = 32; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (error == null) { + TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; + putUsers(res.users, false); + MessagesStorage.getInstance().putUsersAndChats(res.users, null, true, true); + MessagesStorage.getInstance().updateChannelUsers(chat_id, res.participants); + loadedFullParticipants.add(chat_id); + } + loadingFullParticipants.remove(chat_id); + } + }); + } + }); + } + + public void loadChatInfo(final int chat_id, Semaphore semaphore, boolean force) { + MessagesStorage.getInstance().loadChatInfo(chat_id, semaphore, force, false); + } + + public void processChatInfo(int chat_id, final TLRPC.ChatFull info, final ArrayList usersArr, final boolean fromCache, boolean force, final boolean byChannelUsers, final MessageObject pinnedMessageObject) { + if (fromCache && chat_id > 0 && !byChannelUsers) { + loadFullChat(chat_id, 0, force); + } + if (info != null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + putUsers(usersArr, fromCache); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, info, 0, byChannelUsers, pinnedMessageObject); + } + }); + } + } + + public void updateTimerProc() { + long currentTime = System.currentTimeMillis(); + + checkDeletingTask(false); + + if (UserConfig.isClientActivated()) { + if (ConnectionsManager.getInstance().getPauseTime() == 0 && ApplicationLoader.isScreenOn && !ApplicationLoader.mainInterfacePaused) { + if (statusSettingState != 1 && (lastStatusUpdateTime == 0 || Math.abs(System.currentTimeMillis() - lastStatusUpdateTime) >= 55000 || offlineSent)) { + statusSettingState = 1; + + if (statusRequest != 0) { + ConnectionsManager.getInstance().cancelRequest(statusRequest, true); + } + + TLRPC.TL_account_updateStatus req = new TLRPC.TL_account_updateStatus(); + req.offline = false; + statusRequest = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + lastStatusUpdateTime = System.currentTimeMillis(); + offlineSent = false; + statusSettingState = 0; + } else { + if (lastStatusUpdateTime != 0) { + lastStatusUpdateTime += 5000; + } + } + statusRequest = 0; + } + }); + } + } else if (statusSettingState != 2 && !offlineSent && Math.abs(System.currentTimeMillis() - ConnectionsManager.getInstance().getPauseTime()) >= 2000) { + statusSettingState = 2; + if (statusRequest != 0) { + ConnectionsManager.getInstance().cancelRequest(statusRequest, true); + } + TLRPC.TL_account_updateStatus req = new TLRPC.TL_account_updateStatus(); + req.offline = true; + statusRequest = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + offlineSent = true; + } else { + if (lastStatusUpdateTime != 0) { + lastStatusUpdateTime += 5000; + } + } + statusRequest = 0; + } + }); + } + + if (!updatesQueueChannels.isEmpty()) { + ArrayList keys = new ArrayList<>(updatesQueueChannels.keySet()); + for (int a = 0; a < keys.size(); a++) { + int key = keys.get(a); + Long updatesStartWaitTime = updatesStartWaitTimeChannels.get(key); + if (updatesStartWaitTime != null && updatesStartWaitTime + 1500 < currentTime) { + FileLog.e("tmessages", "QUEUE CHANNEL " + key + " UPDATES WAIT TIMEOUT - CHECK QUEUE"); + processChannelsUpdatesQueue(key, 0); + } + } + } + + for (int a = 0; a < 3; a++) { + if (getUpdatesStartTime(a) != 0 && getUpdatesStartTime(a) + 1500 < currentTime) { + FileLog.e("tmessages", a + " QUEUE UPDATES WAIT TIMEOUT - CHECK QUEUE"); + processUpdatesQueue(a, 0); + } + } + } + if ((channelViewsToSend.size() != 0 || channelViewsToReload.size() != 0) && Math.abs(System.currentTimeMillis() - lastViewsCheckTime) >= 5000) { + lastViewsCheckTime = System.currentTimeMillis(); + for (int b = 0; b < 2; b++) { + SparseArray> array = b == 0 ? channelViewsToSend : channelViewsToReload; + if (array.size() == 0) { + continue; + } + for (int a = 0; a < array.size(); a++) { + final int key = array.keyAt(a); + final TLRPC.TL_messages_getMessagesViews req = new TLRPC.TL_messages_getMessagesViews(); + req.peer = getInputPeer(key); + req.id = array.get(key); + req.increment = a == 0; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.Vector vector = (TLRPC.Vector) response; + final SparseArray channelViews = new SparseArray<>(); + SparseIntArray array = channelViews.get(key); + if (array == null) { + array = new SparseIntArray(); + channelViews.put(key, array); + } + for (int a = 0; a < req.id.size(); a++) { + if (a >= vector.objects.size()) { + break; + } + array.put(req.id.get(a), (Integer) vector.objects.get(a)); + } + MessagesStorage.getInstance().putChannelViews(channelViews, req.peer instanceof TLRPC.TL_inputPeerChannel); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didUpdatedMessagesViews, channelViews); + } + }); + } + } + }); + } + array.clear(); + } + } + if (!onlinePrivacy.isEmpty()) { + ArrayList toRemove = null; + int currentServerTime = ConnectionsManager.getInstance().getCurrentTime(); + for (ConcurrentHashMap.Entry entry : onlinePrivacy.entrySet()) { + if (entry.getValue() < currentServerTime - 30) { + if (toRemove == null) { + toRemove = new ArrayList<>(); + } + toRemove.add(entry.getKey()); + } + } + if (toRemove != null) { + for (Integer uid : toRemove) { + onlinePrivacy.remove(uid); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_STATUS); + } + }); + } + } + if (shortPollChannels.size() != 0) { + for (int a = 0; a < shortPollChannels.size(); a++) { + int key = shortPollChannels.keyAt(a); + int timeout = shortPollChannels.get(key); + if (timeout < System.currentTimeMillis() / 1000) { + shortPollChannels.delete(key); + if (needShortPollChannels.indexOfKey(key) >= 0) { + getChannelDifference(key); + } + } + } + } + if (!printingUsers.isEmpty() || lastPrintingStringCount != printingUsers.size()) { + boolean updated = false; + ArrayList keys = new ArrayList<>(printingUsers.keySet()); + for (int b = 0; b < keys.size(); b++) { + Long key = keys.get(b); + ArrayList arr = printingUsers.get(key); + for (int a = 0; a < arr.size(); a++) { + PrintingUser user = arr.get(a); + if (user.lastTime + 5900 < currentTime) { + updated = true; + arr.remove(user); + a--; + } + } + if (arr.isEmpty()) { + printingUsers.remove(key); + keys.remove(b); + b--; + } + } + + updatePrintingStrings(); + + if (updated) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_USER_PRINT); + } + }); + } + } + } + + private String getUserNameForTyping(TLRPC.User user) { + if (user == null) { + return ""; + } + if (user.first_name != null && user.first_name.length() > 0) { + return user.first_name; + } else if (user.last_name != null && user.last_name.length() > 0) { + return user.last_name; + } + return ""; + } + + private void updatePrintingStrings() { + final HashMap newPrintingStrings = new HashMap<>(); + final HashMap newPrintingStringsTypes = new HashMap<>(); + + ArrayList keys = new ArrayList<>(printingUsers.keySet()); + for (HashMap.Entry> entry : printingUsers.entrySet()) { + long key = entry.getKey(); + ArrayList arr = entry.getValue(); + + int lower_id = (int) key; + + if (lower_id > 0 || lower_id == 0 || arr.size() == 1) { + PrintingUser pu = arr.get(0); + TLRPC.User user = getUser(pu.userId); + if (user == null) { + return; + } + if (pu.action instanceof TLRPC.TL_sendMessageRecordAudioAction) { + if (lower_id < 0) { + newPrintingStrings.put(key, LocaleController.formatString("IsRecordingAudio", R.string.IsRecordingAudio, getUserNameForTyping(user))); + } else { + newPrintingStrings.put(key, LocaleController.getString("RecordingAudio", R.string.RecordingAudio)); + } + newPrintingStringsTypes.put(key, 1); + } else if (pu.action instanceof TLRPC.TL_sendMessageUploadAudioAction) { + if (lower_id < 0) { + newPrintingStrings.put(key, LocaleController.formatString("IsSendingAudio", R.string.IsSendingAudio, getUserNameForTyping(user))); + } else { + newPrintingStrings.put(key, LocaleController.getString("SendingAudio", R.string.SendingAudio)); + } + newPrintingStringsTypes.put(key, 2); + } else if (pu.action instanceof TLRPC.TL_sendMessageUploadVideoAction || pu.action instanceof TLRPC.TL_sendMessageRecordVideoAction) { + if (lower_id < 0) { + newPrintingStrings.put(key, LocaleController.formatString("IsSendingVideo", R.string.IsSendingVideo, getUserNameForTyping(user))); + } else { + newPrintingStrings.put(key, LocaleController.getString("SendingVideoStatus", R.string.SendingVideoStatus)); + } + newPrintingStringsTypes.put(key, 2); + } else if (pu.action instanceof TLRPC.TL_sendMessageUploadDocumentAction) { + if (lower_id < 0) { + newPrintingStrings.put(key, LocaleController.formatString("IsSendingFile", R.string.IsSendingFile, getUserNameForTyping(user))); + } else { + newPrintingStrings.put(key, LocaleController.getString("SendingFile", R.string.SendingFile)); + } + newPrintingStringsTypes.put(key, 2); + } else if (pu.action instanceof TLRPC.TL_sendMessageUploadPhotoAction) { + if (lower_id < 0) { + newPrintingStrings.put(key, LocaleController.formatString("IsSendingPhoto", R.string.IsSendingPhoto, getUserNameForTyping(user))); + } else { + newPrintingStrings.put(key, LocaleController.getString("SendingPhoto", R.string.SendingPhoto)); + } + newPrintingStringsTypes.put(key, 2); + } else { + if (lower_id < 0) { + newPrintingStrings.put(key, String.format("%s %s", getUserNameForTyping(user), LocaleController.getString("IsTyping", R.string.IsTyping))); + } else { + newPrintingStrings.put(key, LocaleController.getString("Typing", R.string.Typing)); + } + newPrintingStringsTypes.put(key, 0); + } + } else { + int count = 0; + String label = ""; + for (PrintingUser pu : arr) { + TLRPC.User user = getUser(pu.userId); + if (user != null) { + if (label.length() != 0) { + label += ", "; + } + label += getUserNameForTyping(user); + count++; + } + if (count == 2) { + break; + } + } + if (label.length() != 0) { + if (count == 1) { + newPrintingStrings.put(key, String.format("%s %s", label, LocaleController.getString("IsTyping", R.string.IsTyping))); + } else { + if (arr.size() > 2) { + newPrintingStrings.put(key, String.format("%s %s", label, LocaleController.formatPluralString("AndMoreTyping", arr.size() - 2))); + } else { + newPrintingStrings.put(key, String.format("%s %s", label, LocaleController.getString("AreTyping", R.string.AreTyping))); + } + } + newPrintingStringsTypes.put(key, 0); + } + } + } + + lastPrintingStringCount = newPrintingStrings.size(); + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + printingStrings = newPrintingStrings; + printingStringsTypes = newPrintingStringsTypes; + } + }); + } + + public void cancelTyping(int action, long dialog_id) { + HashMap typings = sendingTypings.get(action); + if (typings != null) { + typings.remove(dialog_id); + } + } + + public void sendTyping(final long dialog_id, final int action, int classGuid) { + if (dialog_id == 0) { + return; + } + HashMap typings = sendingTypings.get(action); + if (typings != null && typings.get(dialog_id) != null) { + return; + } + if (typings == null) { + typings = new HashMap<>(); + sendingTypings.put(action, typings); + } + int lower_part = (int) dialog_id; + int high_id = (int) (dialog_id >> 32); + if (lower_part != 0) { + if (high_id == 1) { + return; + } + + TLRPC.TL_messages_setTyping req = new TLRPC.TL_messages_setTyping(); + req.peer = getInputPeer(lower_part); + if (req.peer instanceof TLRPC.TL_inputPeerChannel) { + TLRPC.Chat chat = getChat(req.peer.channel_id); + if (chat == null || !chat.megagroup) { + return; + } + } + if (req.peer == null) { + return; + } + if (action == 0) { + req.action = new TLRPC.TL_sendMessageTypingAction(); + } else if (action == 1) { + req.action = new TLRPC.TL_sendMessageRecordAudioAction(); + } else if (action == 2) { + req.action = new TLRPC.TL_sendMessageCancelAction(); + } else if (action == 3) { + req.action = new TLRPC.TL_sendMessageUploadDocumentAction(); + } else if (action == 4) { + req.action = new TLRPC.TL_sendMessageUploadPhotoAction(); + } else if (action == 5) { + req.action = new TLRPC.TL_sendMessageUploadVideoAction(); + } + typings.put(dialog_id, true); + int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + HashMap typings = sendingTypings.get(action); + if (typings != null) { + typings.remove(dialog_id); + } + } + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + if (classGuid != 0) { + ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); + } + } else { + if (action != 0) { + return; + } + TLRPC.EncryptedChat chat = getEncryptedChat(high_id); + if (chat.auth_key != null && chat.auth_key.length > 1 && chat instanceof TLRPC.TL_encryptedChat) { + TLRPC.TL_messages_setEncryptedTyping req = new TLRPC.TL_messages_setEncryptedTyping(); + req.peer = new TLRPC.TL_inputEncryptedChat(); + req.peer.chat_id = chat.id; + req.peer.access_hash = chat.access_hash; + req.typing = true; + typings.put(dialog_id, true); + int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + HashMap typings = sendingTypings.get(action); + if (typings != null) { + typings.remove(dialog_id); + } + } + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + if (classGuid != 0) { + ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); + } + } + } + } + + public void loadMessages(final long dialog_id, final int count, final int max_id, boolean fromCache, int midDate, final int classGuid, final int load_type, final int last_message_id, final int important, final int loadIndex) { + loadMessages(dialog_id, count, max_id, fromCache, midDate, classGuid, load_type, last_message_id, important, loadIndex, 0, 0, 0, false); + } + + public void loadMessages(final long dialog_id, final int count, final int max_id, boolean fromCache, int midDate, final int classGuid, final int load_type, final int last_message_id, final int important, final int loadIndex, final int first_unread, final int unread_count, final int last_date, final boolean queryFromServer) { + FileLog.e("tmessages", "load messages in chat " + dialog_id + " count " + count + " max_id " + max_id + " cache " + fromCache + " mindate = " + midDate + " guid " + classGuid + " load_type " + load_type + " last_message_id " + last_message_id + " imp " + important + " index " + loadIndex + " firstUnread " + first_unread + " underad count " + unread_count + " last_date " + last_date + " queryFromServer " + queryFromServer); + int lower_part = (int) dialog_id; + if (fromCache || lower_part == 0) { + MessagesStorage.getInstance().getMessages(dialog_id, count, max_id, midDate, classGuid, load_type, important, loadIndex); + } else { + TLObject request; + if (important == 2) { + TLRPC.TL_channels_getImportantHistory req = new TLRPC.TL_channels_getImportantHistory(); + req.channel = getInputChannel(-lower_part); + if (load_type == 3) { + req.add_offset = -count / 2; + } else if (load_type == 1) { + req.add_offset = -count - 1; + } else if (load_type == 2 && max_id != 0) { + req.add_offset = -count + 6; + } else { + if (max_id != 0) { + req.add_offset = -1; + req.limit += 1; + } + } + req.limit += count; + req.offset_id = max_id; + request = req; + } else { + TLRPC.TL_messages_getHistory req = new TLRPC.TL_messages_getHistory(); + req.peer = getInputPeer(lower_part); + if (load_type == 3) { + req.add_offset = -count / 2; + } else if (load_type == 1) { + req.add_offset = -count - 1; + } else if (load_type == 2 && max_id != 0) { + req.add_offset = -count + 6; + } else { + req.add_offset = 0; + } + req.limit = count; + req.offset_id = max_id; + request = req; + } + int reqId = ConnectionsManager.getInstance().sendRequest(request, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + final TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + if (res.messages.size() > count) { + res.messages.remove(0); + } + processLoadedMessages(res, dialog_id, count, max_id, false, classGuid, first_unread, last_message_id, unread_count, last_date, load_type, important, false, loadIndex, queryFromServer); + } + } + }); + ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); + } + } + + public void reloadWebPages(final long dialog_id, HashMap> webpagesToReload) { + for (HashMap.Entry> entry : webpagesToReload.entrySet()) { + final String url = entry.getKey(); + final ArrayList messages = entry.getValue(); + ArrayList arrayList = reloadingWebpages.get(url); + if (arrayList == null) { + arrayList = new ArrayList<>(); + reloadingWebpages.put(url, arrayList); + } + arrayList.addAll(messages); + TLRPC.TL_messages_getWebPagePreview req = new TLRPC.TL_messages_getWebPagePreview(); + req.message = url; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + ArrayList arrayList = reloadingWebpages.remove(url); + if (arrayList == null) { + return; + } + TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); + if (!(response instanceof TLRPC.TL_messageMediaWebPage)) { + for (int a = 0; a < arrayList.size(); a++) { + arrayList.get(a).messageOwner.media.webpage = new TLRPC.TL_webPageEmpty(); + messagesRes.messages.add(arrayList.get(a).messageOwner); + } + } else { + TLRPC.TL_messageMediaWebPage media = (TLRPC.TL_messageMediaWebPage) response; + if (media.webpage instanceof TLRPC.TL_webPage || media.webpage instanceof TLRPC.TL_webPageEmpty) { + for (int a = 0; a < arrayList.size(); a++) { + arrayList.get(a).messageOwner.media.webpage = media.webpage; + if (a == 0) { + ImageLoader.saveMessageThumbs(arrayList.get(a).messageOwner); + } + messagesRes.messages.add(arrayList.get(a).messageOwner); + } + } else { + reloadingWebpagesPending.put(media.webpage.id, arrayList); + } + } + if (!messagesRes.messages.isEmpty()) { + MessagesStorage.getInstance().putMessages(messagesRes, dialog_id, -2, 0, 0, false); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, arrayList); + } + } + }); + } + }); + } + } + + public void processLoadedMessages(final TLRPC.messages_Messages messagesRes, final long dialog_id, final int count, final int max_id, final boolean isCache, final int classGuid, + final int first_unread, final int last_message_id, final int unread_count, final int last_date, final int load_type, final int important, final boolean isEnd, final int loadIndex, final boolean queryFromServer) { + FileLog.e("tmessages", "processLoadedMessages size " + messagesRes.messages.size() + " in chat " + dialog_id + " count " + count + " max_id " + max_id + " cache " + isCache + " guid " + classGuid + " load_type " + load_type + " last_message_id " + last_message_id + " imp " + important + " index " + loadIndex + " firstUnread " + first_unread + " underad count " + unread_count + " last_date " + last_date + " queryFromServer " + queryFromServer); + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + boolean createDialog = false; + boolean isMegagroup = false; + if (messagesRes instanceof TLRPC.TL_messages_channelMessages) { + int channelId = -(int) dialog_id; + Integer channelPts = channelsPts.get(channelId); + if (channelPts == null) { + channelPts = MessagesStorage.getInstance().getChannelPtsSync(channelId); + if (channelPts == 0) { + channelsPts.put(channelId, messagesRes.pts); + createDialog = true; + if (needShortPollChannels.indexOfKey(channelId) >= 0 && shortPollChannels.indexOfKey(channelId) < 0) { + getChannelDifference(channelId, 2); + } else { + getChannelDifference(channelId); + } + } + } + for (int a = 0; a < messagesRes.chats.size(); a++) { + TLRPC.Chat chat = messagesRes.chats.get(a); + if (chat.id == channelId) { + isMegagroup = chat.megagroup; + break; + } + } + } + int lower_id = (int) dialog_id; + int high_id = (int) (dialog_id >> 32); + if (!isCache) { + ImageLoader.saveMessagesThumbs(messagesRes.messages); + } + if (high_id != 1 && lower_id != 0 && isCache && messagesRes.messages.size() == 0) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + loadMessages(dialog_id, count, load_type == 2 && queryFromServer ? first_unread : max_id, false, 0, classGuid, load_type, last_message_id, important, loadIndex, first_unread, unread_count, last_date, queryFromServer); + } + }); + return; + } + final HashMap usersDict = new HashMap<>(); + final HashMap chatsDict = new HashMap<>(); + for (int a = 0; a < messagesRes.users.size(); a++) { + TLRPC.User u = messagesRes.users.get(a); + usersDict.put(u.id, u); + } + for (int a = 0; a < messagesRes.chats.size(); a++) { + TLRPC.Chat c = messagesRes.chats.get(a); + chatsDict.put(c.id, c); + } + int size = messagesRes.messages.size(); + if (!isCache) { + for (int a = 0; a < size; a++) { + TLRPC.Message message = messagesRes.messages.get(a); + if (!isCache && message.post && !message.out) { + message.media_unread = true; + } + if (isMegagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) { + //plus + if(hideLeftGroup && message.action.user_id == message.from_id){ + continue; + }// + TLRPC.User user = usersDict.get(message.action.user_id); + if (user != null && user.bot) { + message.reply_markup = new TLRPC.TL_replyKeyboardHide(); + } + } else if (message.action instanceof TLRPC.TL_messageActionChatMigrateTo || message.action instanceof TLRPC.TL_messageActionChannelCreate) { + message.unread = false; + message.media_unread = false; + } + } + MessagesStorage.getInstance().putMessages(messagesRes, dialog_id, load_type, max_id, important, createDialog); + } + final ArrayList objects = new ArrayList<>(); + final ArrayList messagesToReload = new ArrayList<>(); + final HashMap> webpagesToReload = new HashMap<>(); + TLRPC.InputChannel inputChannel = null; + for (int a = 0; a < size; a++) { + TLRPC.Message message = messagesRes.messages.get(a); + message.dialog_id = dialog_id; + MessageObject messageObject = new MessageObject(message, usersDict, chatsDict, true); + objects.add(messageObject); + if (isCache) { + if (message.media instanceof TLRPC.TL_messageMediaUnsupported) { + if (message.media.bytes != null && (message.media.bytes.length == 0 || message.media.bytes.length == 1 && message.media.bytes[0] < TLRPC.LAYER)) { + messagesToReload.add(message.id); + } + } else if (message.media instanceof TLRPC.TL_messageMediaWebPage) { + if (message.media.webpage instanceof TLRPC.TL_webPagePending && message.media.webpage.date <= ConnectionsManager.getInstance().getCurrentTime()) { + messagesToReload.add(message.id); + } else if (message.media.webpage instanceof TLRPC.TL_webPageUrlPending) { + ArrayList arrayList = webpagesToReload.get(message.media.webpage.url); + if (arrayList == null) { + arrayList = new ArrayList<>(); + webpagesToReload.put(message.media.webpage.url, arrayList); + } + arrayList.add(messageObject); + } + } + } + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + putUsers(messagesRes.users, isCache); + putChats(messagesRes.chats, isCache); + int first_unread_final = Integer.MAX_VALUE; + if (queryFromServer && load_type == 2) { + for (int a = 0; a < messagesRes.messages.size(); a++) { + TLRPC.Message message = messagesRes.messages.get(a); + if (!message.out && message.id > first_unread && message.id < first_unread_final) { + first_unread_final = message.id; + } + } + } + if (first_unread_final == Integer.MAX_VALUE) { + first_unread_final = first_unread; + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDidLoaded, dialog_id, count, objects, isCache, first_unread_final, last_message_id, unread_count, last_date, load_type, messagesRes.collapsed, isEnd, classGuid, loadIndex); + if (!messagesToReload.isEmpty()) { + reloadMessages(messagesToReload, dialog_id); + } + if (!webpagesToReload.isEmpty()) { + reloadWebPages(dialog_id, webpagesToReload); + } + } + }); + } + }); + } + + public void loadDialogs(final int offset, final int count, boolean fromCache) { + if (loadingDialogs) { + return; + } + loadingDialogs = true; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + FileLog.e("tmessages", "load cacheOffset = " + offset + " count = " + count + " cache = " + fromCache); + if (fromCache) { + MessagesStorage.getInstance().getDialogs(offset == 0 ? 0 : nextDialogsCacheOffset, count); + } else { + TLRPC.TL_messages_getDialogs req = new TLRPC.TL_messages_getDialogs(); + req.limit = count; + boolean found = false; + for (int a = dialogs.size() - 1; a >= 0; a--) { + TLRPC.Dialog dialog = dialogs.get(a); + int lower_id = (int) dialog.id; + int high_id = (int) (dialog.id >> 32); + if (lower_id != 0 && high_id != 1 && dialog.top_message > 0) { + MessageObject message = dialogMessage.get(dialog.id); + if (message != null && message.getId() > 0) { + req.offset_date = Math.max(dialog.last_message_date_i, message.messageOwner.date); + req.offset_id = message.messageOwner.id; + int id; + if (message.messageOwner.to_id.channel_id != 0) { + id = -message.messageOwner.to_id.channel_id; + } else if (message.messageOwner.to_id.chat_id != 0) { + id = -message.messageOwner.to_id.chat_id; + } else { + id = message.messageOwner.to_id.user_id; + } + req.offset_peer = getInputPeer(id); + found = true; + break; + } + } + } + if (!found) { + req.offset_peer = new TLRPC.TL_inputPeerEmpty(); + } + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + final TLRPC.messages_Dialogs dialogsRes = (TLRPC.messages_Dialogs) response; + processLoadedDialogs(dialogsRes, null, 0, count, false, false, false); + } + } + }); + } + } + + private void migrateDialogs(final int offset, final int offsetDate, final int offsetUser, final int offsetChat, final int offsetChannel, final long accessPeer) { + if (migratingDialogs || offset == -1) { + return; + } + migratingDialogs = true; + + TLRPC.TL_messages_getDialogs req = new TLRPC.TL_messages_getDialogs(); + req.limit = 100; + req.offset_id = offset; + req.offset_date = offsetDate; + if (offset == 0) { + req.offset_peer = new TLRPC.TL_inputPeerEmpty(); + } else { + if (offsetChannel != 0) { + req.offset_peer = new TLRPC.TL_inputPeerChannel(); + req.offset_peer.channel_id = offsetChannel; + } else if (offsetUser != 0) { + req.offset_peer = new TLRPC.TL_inputPeerUser(); + req.offset_peer.user_id = offsetUser; + } else { + req.offset_peer = new TLRPC.TL_inputPeerChat(); + req.offset_peer.chat_id = offsetChat; + } + req.offset_peer.access_hash = accessPeer; + } + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + final TLRPC.messages_Dialogs dialogsRes = (TLRPC.messages_Dialogs) response; + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + int offsetId; + if (dialogsRes.dialogs.size() == 100) { + TLRPC.Message lastMessage = null; + for (int a = 0; a < dialogsRes.messages.size(); a++) { + TLRPC.Message message = dialogsRes.messages.get(a); + if (lastMessage == null || message.date < lastMessage.date) { + lastMessage = message; + } + } + offsetId = lastMessage.id; + UserConfig.migrateOffsetDate = lastMessage.date; + if (lastMessage.to_id.channel_id != 0) { + UserConfig.migrateOffsetChannelId = lastMessage.to_id.channel_id; + UserConfig.migrateOffsetChatId = 0; + UserConfig.migrateOffsetUserId = 0; + for (int a = 0; a < dialogsRes.chats.size(); a++) { + TLRPC.Chat chat = dialogsRes.chats.get(a); + if (chat.id == UserConfig.migrateOffsetChannelId) { + UserConfig.migrateOffsetAccess = chat.access_hash; + break; + } + } + } else if (lastMessage.to_id.chat_id != 0) { + UserConfig.migrateOffsetChatId = lastMessage.to_id.chat_id; + UserConfig.migrateOffsetChannelId = 0; + UserConfig.migrateOffsetUserId = 0; + for (int a = 0; a < dialogsRes.chats.size(); a++) { + TLRPC.Chat chat = dialogsRes.chats.get(a); + if (chat.id == UserConfig.migrateOffsetChatId) { + UserConfig.migrateOffsetAccess = chat.access_hash; + break; + } + } + } else if (lastMessage.to_id.user_id != 0) { + UserConfig.migrateOffsetUserId = lastMessage.to_id.user_id; + UserConfig.migrateOffsetChatId = 0; + UserConfig.migrateOffsetChannelId = 0; + for (int a = 0; a < dialogsRes.users.size(); a++) { + TLRPC.User user = dialogsRes.users.get(a); + if (user.id == UserConfig.migrateOffsetUserId) { + UserConfig.migrateOffsetAccess = user.access_hash; + break; + } + } + } + } else { + offsetId = -1; + } + + StringBuilder dids = new StringBuilder(dialogsRes.dialogs.size() * 12); + HashMap dialogHashMap = new HashMap<>(); + for (int a = 0; a < dialogsRes.dialogs.size(); a++) { + TLRPC.Dialog dialog = dialogsRes.dialogs.get(a); + if (dialog.peer.channel_id != 0) { + dialog.id = -dialog.peer.channel_id; + } else if (dialog.peer.chat_id != 0) { + dialog.id = -dialog.peer.chat_id; + } else { + dialog.id = dialog.peer.user_id; + } + if (dids.length() > 0) { + dids.append(","); + } + dids.append(dialog.id); + dialogHashMap.put(dialog.id, dialog); + } + SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT did FROM dialogs WHERE did IN (%s)", dids.toString())); + while (cursor.next()) { + long did = cursor.longValue(0); + TLRPC.Dialog dialog = dialogHashMap.remove(did); + if (dialog != null) { + dialogsRes.dialogs.remove(dialog); + for (int a = 0; a < dialogsRes.messages.size(); a++) { + TLRPC.Message message = dialogsRes.messages.get(a); + if (MessageObject.getDialogId(message) != did) { + continue; + } + dialogsRes.messages.remove(a); + a--; + if (message.id == dialog.top_message) { + dialog.top_message = 0; + } + if (message.id == dialog.top_not_important_message) { + dialog.top_not_important_message = 0; + } + if (dialog.top_message == 0 && dialog.top_not_important_message == 0) { + break; + } + } + } + } + cursor.dispose(); + cursor = MessagesStorage.getInstance().getDatabase().queryFinalized("SELECT min(date) FROM dialogs WHERE date != 0 AND did >> 32 IN (0, -1)"); + if (cursor.next()) { + int date = Math.max(1441062000, cursor.intValue(0)); + for (int a = 0; a < dialogsRes.messages.size(); a++) { + TLRPC.Message message = dialogsRes.messages.get(a); + if (message.date < date) { + offsetId = -1; + dialogsRes.messages.remove(a); + a--; + TLRPC.Dialog dialog = dialogHashMap.remove(MessageObject.getDialogId(message)); + if (dialog != null) { + dialogsRes.dialogs.remove(dialog); + } + } + } + } + cursor.dispose(); + + processLoadedDialogs(dialogsRes, null, offsetId, 0, false, false, true); + } catch (Exception e) { + FileLog.e("tmessages", e); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + migratingDialogs = false; + } + }); + } + } + }); + } else { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + migratingDialogs = false; + } + }); + } + } + }); + + } + + public void processLoadedDialogs(final TLRPC.messages_Dialogs dialogsRes, final ArrayList encChats, final int offset, final int count, final boolean isCache, final boolean resetEnd, final boolean migrate) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + FileLog.e("tmessages", "loaded from " + isCache + " count " + dialogsRes.dialogs.size()); + if (isCache && dialogsRes.dialogs.size() == 0) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + putUsers(dialogsRes.users, true); + loadingDialogs = false; + if (resetEnd) { + dialogsEndReached = false; + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + loadDialogs(0, count, false); + } + }); + return; + } + + final HashMap new_dialogs_dict = new HashMap<>(); + final HashMap new_dialogMessage = new HashMap<>(); + final HashMap notImportantDates = new HashMap<>(); + final HashMap usersDict = new HashMap<>(); + final HashMap chatsDict = new HashMap<>(); + + for (int a = 0; a < dialogsRes.users.size(); a++) { + TLRPC.User u = dialogsRes.users.get(a); + usersDict.put(u.id, u); + } + for (int a = 0; a < dialogsRes.chats.size(); a++) { + TLRPC.Chat c = dialogsRes.chats.get(a); + chatsDict.put(c.id, c); + } + if (isCache) { + nextDialogsCacheOffset = offset + count; + } + + for (int a = 0; a < dialogsRes.messages.size(); a++) { + TLRPC.Message message = dialogsRes.messages.get(a); + if (message.to_id.channel_id != 0) { + if (!MessageObject.isImportant(message)) { + notImportantDates.put(-message.to_id.channel_id, message.date); + } + TLRPC.Chat chat = chatsDict.get(message.to_id.channel_id); + if (chat != null && chat.left/* && !chat.megagroup*/) { + continue; + } + if (chat != null && chat.megagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + } else if (message.to_id.chat_id != 0) { + TLRPC.Chat chat = chatsDict.get(message.to_id.chat_id); + if (chat != null && chat.migrated_to != null) { + continue; + } + } + if (!isCache && message.post && !message.out) { + message.media_unread = true; + } + MessageObject messageObject = new MessageObject(message, usersDict, chatsDict, false); + MessageObject currentMessage = new_dialogMessage.get(messageObject.getDialogId()); + if (currentMessage == null || messageObject.isMegagroup() || messageObject.isImportant()) { + new_dialogMessage.put(messageObject.getDialogId(), messageObject); + } + } + + for (int a = 0; a < dialogsRes.dialogs.size(); a++) { + TLRPC.Dialog d = dialogsRes.dialogs.get(a); + if (d.id == 0 && d.peer != null) { + if (d.peer.user_id != 0) { + d.id = d.peer.user_id; + } else if (d.peer.chat_id != 0) { + d.id = -d.peer.chat_id; + } else if (d.peer.channel_id != 0) { + d.id = -d.peer.channel_id; + } + } + if (d.id == 0) { + continue; + } + if (d.last_message_date == 0) { + MessageObject mess = new_dialogMessage.get(d.id); + if (mess != null) { + d.last_message_date = mess.messageOwner.date; + } + } + if (d.last_message_date_i == 0 && d.top_not_important_message != 0) { + Integer date = notImportantDates.get((int) d.id); + if (date != null) { + d.last_message_date_i = date; + } + } + if (d instanceof TLRPC.TL_dialogChannel) { + TLRPC.Chat chat = chatsDict.get(-(int) d.id); + if (chat != null && chat.megagroup) { + d.top_message = Math.max(d.top_message, d.top_not_important_message); + d.unread_count = Math.max(d.unread_count, d.unread_not_important_count); + } + if (chat != null && chat.left/* && !chat.megagroup*/) { + continue; + } + channelsPts.put(-(int) d.id, d.pts); + } else if ((int) d.id < 0) { + TLRPC.Chat chat = chatsDict.get(-(int) d.id); + if (chat != null && chat.migrated_to != null) { + continue; + } + } + new_dialogs_dict.put(d.id, d); + + Integer value = dialogs_read_inbox_max.get(d.id); + if (value == null) { + value = 0; + } + dialogs_read_inbox_max.put(d.id, Math.max(value, d.read_inbox_max_id)); + } + + if (!isCache) { + ImageLoader.saveMessagesThumbs(dialogsRes.messages); + + for (int a = 0; a < dialogsRes.messages.size(); a++) { + TLRPC.Message message = dialogsRes.messages.get(a); + if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) { + //plus + if(hideLeftGroup && message.action.user_id == message.from_id){ + continue; + }// + TLRPC.User user = usersDict.get(message.action.user_id); + if (user != null && user.bot) { + message.reply_markup = new TLRPC.TL_replyKeyboardHide(); + } + } else if (message.action instanceof TLRPC.TL_messageActionChatMigrateTo || message.action instanceof TLRPC.TL_messageActionChannelCreate) { + message.unread = false; + message.media_unread = false; + } + } + MessagesStorage.getInstance().putDialogs(dialogsRes); + } + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (!isCache) { + applyDialogsNotificationsSettings(dialogsRes.dialogs); + } + putUsers(dialogsRes.users, isCache); + putChats(dialogsRes.chats, isCache); + if (encChats != null) { + for (int a = 0; a < encChats.size(); a++) { + TLRPC.EncryptedChat encryptedChat = encChats.get(a); + if (encryptedChat instanceof TLRPC.TL_encryptedChat && AndroidUtilities.getMyLayerVersion(encryptedChat.layer) < SecretChatHelper.CURRENT_SECRET_CHAT_LAYER) { + SecretChatHelper.getInstance().sendNotifyLayerMessage(encryptedChat, null); + } + putEncryptedChat(encryptedChat, true); + } + } + if (!migrate) { + loadingDialogs = false; + } + boolean added = false; + + int lastDialogDate = migrate && !dialogs.isEmpty() ? dialogs.get(dialogs.size() - 1).last_message_date : 0; + for (HashMap.Entry pair : new_dialogs_dict.entrySet()) { + Long key = pair.getKey(); + TLRPC.Dialog value = pair.getValue(); + if (migrate && lastDialogDate != 0 && value.last_message_date < lastDialogDate) { + continue; + } + TLRPC.Dialog currentDialog = dialogs_dict.get(key); + if (currentDialog == null) { + added = true; + dialogs_dict.put(key, value); + MessageObject messageObject = new_dialogMessage.get(value.id); + dialogMessage.put(key, messageObject); + if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(messageObject.getId(), messageObject); + if (messageObject.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); + } + } + } else { + if (!isCache) { + currentDialog.notify_settings = value.notify_settings; + } + MessageObject oldMsg = dialogMessage.get(key); + if (oldMsg != null && oldMsg.deleted || oldMsg == null || currentDialog.top_message > 0) { + if (value.top_message >= currentDialog.top_message) { + dialogs_dict.put(key, value); + MessageObject messageObject = new_dialogMessage.get(value.id); + dialogMessage.put(key, messageObject); + if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(messageObject.getId(), messageObject); + if (messageObject != null && messageObject.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); + } + } + if (oldMsg != null) { + dialogMessagesByIds.remove(oldMsg.getId()); + if (oldMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); + } + } + } + } else { + MessageObject newMsg = new_dialogMessage.get(value.id); + if (oldMsg.deleted || newMsg == null || newMsg.messageOwner.date > oldMsg.messageOwner.date) { + dialogs_dict.put(key, value); + dialogMessage.put(key, newMsg); + if (newMsg != null && newMsg.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(newMsg.getId(), newMsg); + if (newMsg != null && newMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); + } + } + dialogMessagesByIds.remove(oldMsg.getId()); + if (oldMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); + } + } + } + } + } + + dialogs.clear(); + dialogsServerOnly.clear(); + dialogsGroupsOnly.clear(); + //plus + dialogsUsers.clear(); + dialogsGroups.clear(); + dialogsGroupsAll.clear(); + dialogsChannels.clear(); + dialogsMegaGroups.clear(); + dialogsBots.clear(); + dialogsFavs.clear(); + // + dialogs.addAll(dialogs_dict.values()); + Collections.sort(dialogs, new Comparator() { + @Override + public int compare(TLRPC.Dialog tl_dialog, TLRPC.Dialog tl_dialog2) { + if (tl_dialog.last_message_date == tl_dialog2.last_message_date) { + return 0; + } else if (tl_dialog.last_message_date < tl_dialog2.last_message_date) { + return 1; + } else { + return -1; + } + } + }); + for (int a = 0; a < dialogs.size(); a++) { + TLRPC.Dialog d = dialogs.get(a); + + int high_id = (int) (d.id >> 32); + if ((int) d.id != 0 && high_id != 1) { + if (d instanceof TLRPC.TL_dialog) { + if (d.id < 0) { + if (migrate) { + TLRPC.Chat chat = chatsDict.get(-(int) d.id); + if (chat != null && chat.migrated_to != null) { + dialogs.remove(a); + a--; + continue; + } + } + dialogsGroupsOnly.add(d); + //plus + dialogsGroups.add(d); + dialogsGroupsAll.add(d); + // + } + //plus + else { + TLRPC.User user = getUser((int) d.id); + if (user != null) { + if (user.bot) { + dialogsBots.add(d); + } else { + dialogsUsers.add(d); + } + } + } + // + } else if (d instanceof TLRPC.TL_dialogChannel) { + int lower_id = (int) d.id; + TLRPC.Chat chat = getChat(-lower_id); + if (chat != null && (chat.megagroup && chat.editor || chat.creator)) { + dialogsGroupsOnly.add(d); + } + //plus + if (chat != null) { + if (chat.megagroup) { + dialogsMegaGroups.add(d); + dialogsGroupsAll.add(d); + } else { + dialogsChannels.add(d); + } + } + // + } + dialogsServerOnly.add(d); + } + + TLRPC.EncryptedChat chat = getEncryptedChat(high_id); + if (chat instanceof TLRPC.TL_encryptedChat) { + dialogsUsers.add(d); + } + if (Favourite.isFavourite(d.id)) { + dialogsFavs.add(d); + } + } + + if (!migrate) { + dialogsEndReached = (dialogsRes.dialogs.size() == 0 || dialogsRes.dialogs.size() != count) && !isCache; + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + + if (migrate) { + UserConfig.migrateOffsetId = offset; + UserConfig.saveConfig(false); + migratingDialogs = false; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.needReloadRecentDialogsSearch); + } else { + generateUpdateMessage(); + if (!added && isCache) { + loadDialogs(0, count, false); + } + } + migrateDialogs(UserConfig.migrateOffsetId, UserConfig.migrateOffsetDate, UserConfig.migrateOffsetUserId, UserConfig.migrateOffsetChatId, UserConfig.migrateOffsetChannelId, UserConfig.migrateOffsetAccess); + } + }); + } + }); + } + + private void applyDialogNotificationsSettings(long dialog_id, TLRPC.PeerNotifySettings notify_settings) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + int currentValue = preferences.getInt("notify2_" + dialog_id, 0); + int currentValue2 = preferences.getInt("notifyuntil_" + dialog_id, 0); + SharedPreferences.Editor editor = preferences.edit(); + boolean updated = false; + TLRPC.Dialog dialog = dialogs_dict.get(dialog_id); + if (dialog != null) { + dialog.notify_settings = notify_settings; + } + editor.putBoolean("silent_" + dialog_id, notify_settings.silent); + if (notify_settings.mute_until > ConnectionsManager.getInstance().getCurrentTime()) { + int until = 0; + if (notify_settings.mute_until > ConnectionsManager.getInstance().getCurrentTime() + 60 * 60 * 24 * 365) { + if (currentValue != 2) { + updated = true; + editor.putInt("notify2_" + dialog_id, 2); + if (dialog != null) { + dialog.notify_settings.mute_until = Integer.MAX_VALUE; + } + } + } else { + if (currentValue != 3 || currentValue2 != notify_settings.mute_until) { + updated = true; + until = notify_settings.mute_until; + editor.putInt("notify2_" + dialog_id, 3); + editor.putInt("notifyuntil_" + dialog_id, notify_settings.mute_until); + if (dialog != null) { + dialog.notify_settings.mute_until = until; + } + } + } + MessagesStorage.getInstance().setDialogFlags(dialog_id, ((long) until << 32) | 1); + NotificationsController.getInstance().removeNotificationsForDialog(dialog_id); + } else { + if (currentValue != 0 && currentValue != 1) { + updated = true; + if (dialog != null) { + dialog.notify_settings.mute_until = 0; + } + editor.remove("notify2_" + dialog_id); + } + MessagesStorage.getInstance().setDialogFlags(dialog_id, 0); + } + editor.commit(); + if (updated) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.notificationsSettingsUpdated); + } + } + + private void applyDialogsNotificationsSettings(ArrayList dialogs) { + SharedPreferences.Editor editor = null; + for (int a = 0; a < dialogs.size(); a++) { + TLRPC.Dialog dialog = dialogs.get(a); + if (dialog.peer != null && dialog.notify_settings instanceof TLRPC.TL_peerNotifySettings) { + if (editor == null) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + editor = preferences.edit(); + } + int dialog_id; + if (dialog.peer.user_id != 0) { + dialog_id = dialog.peer.user_id; + } else if (dialog.peer.chat_id != 0) { + dialog_id = -dialog.peer.chat_id; + } else { + dialog_id = -dialog.peer.channel_id; + } + editor.putBoolean("silent_" + dialog_id, dialog.notify_settings.silent); + if (dialog.notify_settings.mute_until != 0) { + if (dialog.notify_settings.mute_until > ConnectionsManager.getInstance().getCurrentTime() + 60 * 60 * 24 * 365) { + editor.putInt("notify2_" + dialog_id, 2); + dialog.notify_settings.mute_until = Integer.MAX_VALUE; + } else { + editor.putInt("notify2_" + dialog_id, 3); + editor.putInt("notifyuntil_" + dialog_id, dialog.notify_settings.mute_until); + } + } else { + editor.remove("notify2_" + dialog_id); + } + } + } + if (editor != null) { + editor.commit(); + } + } + + public void processDialogsUpdateRead(final HashMap dialogsToUpdate) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + for (HashMap.Entry entry : dialogsToUpdate.entrySet()) { + TLRPC.Dialog currentDialog = dialogs_dict.get(entry.getKey()); + if (currentDialog != null) { + currentDialog.unread_count = entry.getValue(); + } + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_READ_DIALOG_MESSAGE); + NotificationsController.getInstance().processDialogsUpdateRead(dialogsToUpdate); + } + }); + } + + public void processDialogsUpdate(final TLRPC.messages_Dialogs dialogsRes, ArrayList encChats) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + final HashMap new_dialogs_dict = new HashMap<>(); + final HashMap new_dialogMessage = new HashMap<>(); + final HashMap usersDict = new HashMap<>(); + final HashMap chatsDict = new HashMap<>(); + final HashMap dialogsToUpdate = new HashMap<>(); + + for (int a = 0; a < dialogsRes.users.size(); a++) { + TLRPC.User u = dialogsRes.users.get(a); + usersDict.put(u.id, u); + } + for (int a = 0; a < dialogsRes.chats.size(); a++) { + TLRPC.Chat c = dialogsRes.chats.get(a); + chatsDict.put(c.id, c); + } + + for (int a = 0; a < dialogsRes.messages.size(); a++) { + TLRPC.Message message = dialogsRes.messages.get(a); + if (message.to_id.channel_id != 0) { + TLRPC.Chat chat = chatsDict.get(message.to_id.channel_id); + if (chat != null && chat.left/* && !chat.megagroup*/) { + continue; + } + } else if (message.to_id.chat_id != 0) { + TLRPC.Chat chat = chatsDict.get(message.to_id.chat_id); + if (chat != null && chat.migrated_to != null) { + continue; + } + } + MessageObject messageObject = new MessageObject(message, usersDict, chatsDict, false); + new_dialogMessage.put(messageObject.getDialogId(), messageObject); + } + for (int a = 0; a < dialogsRes.dialogs.size(); a++) { + TLRPC.Dialog d = dialogsRes.dialogs.get(a); + if (d.id == 0) { + if (d.peer.user_id != 0) { + d.id = d.peer.user_id; + } else if (d.peer.chat_id != 0) { + d.id = -d.peer.chat_id; + } else if (d.peer.channel_id != 0) { + d.id = -d.peer.channel_id; + } + } + if (d instanceof TLRPC.TL_dialogChannel) { + TLRPC.Chat chat = chatsDict.get(-(int) d.id); + if (chat != null && chat.left/* && !chat.megagroup*/) { + continue; + } + } else if ((int) d.id < 0) { + TLRPC.Chat chat = chatsDict.get(-(int) d.id); + if (chat != null && chat.migrated_to != null) { + continue; + } + } + if (d.last_message_date == 0) { + MessageObject mess = new_dialogMessage.get(d.id); + if (mess != null) { + d.last_message_date = mess.messageOwner.date; + } + } + new_dialogs_dict.put(d.id, d); + dialogsToUpdate.put(d.id, d.unread_count); + + Integer value = dialogs_read_inbox_max.get(d.id); + if (value == null) { + value = 0; + } + dialogs_read_inbox_max.put(d.id, Math.max(value, d.read_inbox_max_id)); + } + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + putUsers(dialogsRes.users, true); + putChats(dialogsRes.chats, true); + + for (HashMap.Entry pair : new_dialogs_dict.entrySet()) { + Long key = pair.getKey(); + TLRPC.Dialog value = pair.getValue(); + TLRPC.Dialog currentDialog = dialogs_dict.get(key); + if (currentDialog == null) { + nextDialogsCacheOffset++; + dialogs_dict.put(key, value); + MessageObject messageObject = new_dialogMessage.get(value.id); + dialogMessage.put(key, messageObject); + if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(messageObject.getId(), messageObject); + if (messageObject.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); + } + } + } else { + currentDialog.unread_count = value.unread_count; + MessageObject oldMsg = dialogMessage.get(key); + if (oldMsg == null || currentDialog.top_message > 0) { + if (oldMsg != null && oldMsg.deleted || value.top_message > currentDialog.top_message) { + dialogs_dict.put(key, value); + MessageObject messageObject = new_dialogMessage.get(value.id); + dialogMessage.put(key, messageObject); + if (messageObject != null && messageObject.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(messageObject.getId(), messageObject); + if (messageObject.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(messageObject.messageOwner.random_id, messageObject); + } + } + if (oldMsg != null) { + dialogMessagesByIds.remove(oldMsg.getId()); + if (oldMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); + } + } + } + } else { + MessageObject newMsg = new_dialogMessage.get(value.id); + if (oldMsg.deleted || newMsg == null || newMsg.messageOwner.date > oldMsg.messageOwner.date) { + dialogs_dict.put(key, value); + dialogMessage.put(key, newMsg); + if (newMsg != null && newMsg.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(newMsg.getId(), newMsg); + if (newMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(newMsg.messageOwner.random_id, newMsg); + } + } + dialogMessagesByIds.remove(oldMsg.getId()); + if (oldMsg.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(oldMsg.messageOwner.random_id); + } + } + } + } + } + + dialogs.clear(); + dialogsServerOnly.clear(); + dialogsGroupsOnly.clear(); + //plus + dialogsUsers.clear(); + dialogsGroups.clear(); + dialogsGroupsAll.clear(); + dialogsChannels.clear(); + dialogsMegaGroups.clear(); + dialogsBots.clear(); + dialogsFavs.clear(); + // + dialogs.addAll(dialogs_dict.values()); + Collections.sort(dialogs, new Comparator() { + @Override + public int compare(TLRPC.Dialog dialog, TLRPC.Dialog dialog2) { + if (dialog.last_message_date == dialog2.last_message_date) { + return 0; + } else if (dialog.last_message_date < dialog2.last_message_date) { + return 1; + } else { + return -1; + } + } + }); + for (int a = 0; a < dialogs.size(); a++) { + TLRPC.Dialog d = dialogs.get(a); + int high_id = (int) (d.id >> 32); + if ((int) d.id != 0 && high_id != 1) { + dialogsServerOnly.add(d); + if (d instanceof TLRPC.TL_dialog) { + if (d.id < 0) { + dialogsGroupsOnly.add(d); + //plus + dialogsGroups.add(d); + dialogsGroupsAll.add(d); + //plus + } + //plus + else{ + TLRPC.User user = getUser((int) d.id); + if(user != null){ + if(user.bot){ + dialogsBots.add(d); + }else{ + dialogsUsers.add(d); + } + } + } + // + } else if (d instanceof TLRPC.TL_dialogChannel) { + int lower_id = (int) d.id; + TLRPC.Chat chat = getChat(-lower_id); + if (chat != null && (chat.megagroup && chat.editor || chat.creator)) { + dialogsGroupsOnly.add(d); + } + //plus + if (chat != null) { + if (chat.megagroup) { + dialogsMegaGroups.add(d); + dialogsGroupsAll.add(d); + } else { + dialogsChannels.add(d); + } + } + // + } + //plus + TLRPC.EncryptedChat chat = getEncryptedChat(high_id); + if(chat instanceof TLRPC.TL_encryptedChat) { + dialogsUsers.add(d); + } + if(Favourite.isFavourite(d.id)){ + dialogsFavs.add(d); + } + // + } + + TLRPC.EncryptedChat chat = getEncryptedChat(high_id); + if(chat instanceof TLRPC.TL_encryptedChat) { + dialogsUsers.add(d); + } + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + NotificationsController.getInstance().processDialogsUpdateRead(dialogsToUpdate); + } + }); + } + }); + } + + public void addToViewsQueue(final TLRPC.Message message, final boolean reload) { + ArrayList arrayList = new ArrayList<>(); + long messageId = message.id; + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; + } + arrayList.add(messageId); + MessagesStorage.getInstance().markMessagesContentAsRead(arrayList); + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + SparseArray> array = channelViewsToSend;//reload ? channelViewsToReload : channelViewsToSend; + int peer; + if (message.to_id.channel_id != 0) { + peer = -message.to_id.channel_id; + } else if (message.to_id.chat_id != 0) { + peer = -message.to_id.chat_id; + } else { + peer = message.to_id.user_id; + } + ArrayList ids = array.get(peer); + if (ids == null) { + ids = new ArrayList<>(); + array.put(peer, ids); + } + if (!ids.contains(message.id)) { + ids.add(message.id); + } + } + }); + } + + public void markMessageContentAsRead(final MessageObject messageObject) { + ArrayList arrayList = new ArrayList<>(); + long messageId = messageObject.getId(); + if (messageObject.messageOwner.to_id.channel_id != 0) { + messageId |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; + } + arrayList.add(messageId); + MessagesStorage.getInstance().markMessagesContentAsRead(arrayList); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesReadContent, arrayList); + if (messageObject.getId() < 0) { + markMessageAsRead(messageObject.getDialogId(), messageObject.messageOwner.random_id, Integer.MIN_VALUE); + } else { + TLRPC.TL_messages_readMessageContents req = new TLRPC.TL_messages_readMessageContents(); + req.id.add(messageObject.getId()); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; + processNewDifferenceParams(-1, res.pts, -1, res.pts_count); + } + } + }); + } + } + + public void markMessageAsRead(final long dialog_id, final long random_id, int ttl) { + if (random_id == 0 || dialog_id == 0 || ttl <= 0 && ttl != Integer.MIN_VALUE) { + return; + } + int lower_part = (int) dialog_id; + int high_id = (int) (dialog_id >> 32); + if (lower_part != 0) { + return; + } + TLRPC.EncryptedChat chat = getEncryptedChat(high_id); + if (chat == null) { + return; + } + ArrayList random_ids = new ArrayList<>(); + random_ids.add(random_id); + SecretChatHelper.getInstance().sendMessagesReadMessage(chat, random_ids, null); + if (ttl > 0) { + int time = ConnectionsManager.getInstance().getCurrentTime(); + MessagesStorage.getInstance().createTaskForSecretChat(chat.id, time, time, 0, random_ids); + } + } + + public void markDialogAsRead(final long dialog_id, final int max_id, final int max_positive_id, final int max_date, final boolean was, final boolean popup) { + int lower_part = (int) dialog_id; + int high_id = (int) (dialog_id >> 32); + + if (lower_part != 0) { + if (max_positive_id == 0 || high_id == 1) { + return; + } + TLRPC.InputPeer inputPeer = getInputPeer(lower_part); + TLObject req; + long messageId = max_positive_id; + if (inputPeer instanceof TLRPC.TL_inputPeerChannel) { + TLRPC.TL_channels_readHistory request = new TLRPC.TL_channels_readHistory(); + request.channel = getInputChannel(-lower_part); + request.max_id = max_positive_id; + req = request; + messageId |= ((long) -lower_part) << 32; + } else { + TLRPC.TL_messages_readHistory request = new TLRPC.TL_messages_readHistory(); + request.peer = inputPeer; + request.max_id = max_positive_id; + req = request; + } + Integer value = dialogs_read_inbox_max.get(dialog_id); + if (value == null) { + value = 0; + } + dialogs_read_inbox_max.put(dialog_id, Math.max(value, max_positive_id)); + + MessagesStorage.getInstance().processPendingRead(dialog_id, messageId, max_date, false); + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + TLRPC.Dialog dialog = dialogs_dict.get(dialog_id); + if (dialog != null) { + dialog.unread_count = 0; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_READ_DIALOG_MESSAGE); + } + if (!popup) { + NotificationsController.getInstance().processReadMessages(null, dialog_id, 0, max_positive_id, false); + HashMap dialogsToUpdate = new HashMap<>(); + dialogsToUpdate.put(dialog_id, 0); + NotificationsController.getInstance().processDialogsUpdateRead(dialogsToUpdate); + } else { + NotificationsController.getInstance().processReadMessages(null, dialog_id, 0, max_positive_id, true); + HashMap dialogsToUpdate = new HashMap<>(); + dialogsToUpdate.put(dialog_id, -1); + NotificationsController.getInstance().processDialogsUpdateRead(dialogsToUpdate); + } + } + }); + } + }); + + if (max_positive_id != Integer.MAX_VALUE) { + final long messageIdFinal = messageId; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + MessagesStorage.getInstance().processPendingRead(dialog_id, messageIdFinal, max_date, true); + if (response instanceof TLRPC.TL_messages_affectedMessages) { + TLRPC.TL_messages_affectedMessages res = (TLRPC.TL_messages_affectedMessages) response; + processNewDifferenceParams(-1, res.pts, -1, res.pts_count); + } + } + } + }); + } + } else { + if (max_date == 0) { + return; + } + TLRPC.EncryptedChat chat = getEncryptedChat(high_id); + if (chat.auth_key != null && chat.auth_key.length > 1 && chat instanceof TLRPC.TL_encryptedChat) { + TLRPC.TL_messages_readEncryptedHistory req = new TLRPC.TL_messages_readEncryptedHistory(); + req.peer = new TLRPC.TL_inputEncryptedChat(); + req.peer.chat_id = chat.id; + req.peer.access_hash = chat.access_hash; + req.max_date = max_date; + + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + //MessagesStorage.getInstance().processPendingRead(dialog_id, max_id, max_date, true); + } + }); + } + MessagesStorage.getInstance().processPendingRead(dialog_id, max_id, max_date, false); + + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationsController.getInstance().processReadMessages(null, dialog_id, max_date, 0, popup); + TLRPC.Dialog dialog = dialogs_dict.get(dialog_id); + if (dialog != null) { + dialog.unread_count = 0; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_READ_DIALOG_MESSAGE); + } + HashMap dialogsToUpdate = new HashMap<>(); + dialogsToUpdate.put(dialog_id, 0); + NotificationsController.getInstance().processDialogsUpdateRead(dialogsToUpdate); + } + }); + } + }); + + if (chat.ttl > 0 && was) { + int serverTime = Math.max(ConnectionsManager.getInstance().getCurrentTime(), max_date); + MessagesStorage.getInstance().createTaskForSecretChat(chat.id, serverTime, serverTime, 0, null); + } + } + } + + public int createChat(String title, ArrayList selectedContacts, final String about, int type, final BaseFragment fragment) { + if (type == ChatObject.CHAT_TYPE_BROADCAST) { + TLRPC.TL_chat chat = new TLRPC.TL_chat(); + chat.id = UserConfig.lastBroadcastId; + chat.title = title; + chat.photo = new TLRPC.TL_chatPhotoEmpty(); + chat.participants_count = selectedContacts.size(); + chat.date = (int) (System.currentTimeMillis() / 1000); + chat.version = 1; + UserConfig.lastBroadcastId--; + putChat(chat, false); + ArrayList chatsArrays = new ArrayList<>(); + chatsArrays.add(chat); + MessagesStorage.getInstance().putUsersAndChats(null, chatsArrays, true, true); + + TLRPC.TL_chatFull chatFull = new TLRPC.TL_chatFull(); + chatFull.id = chat.id; + chatFull.chat_photo = new TLRPC.TL_photoEmpty(); + chatFull.notify_settings = new TLRPC.TL_peerNotifySettingsEmpty(); + chatFull.exported_invite = new TLRPC.TL_chatInviteEmpty(); + chatFull.participants = new TLRPC.TL_chatParticipants(); + chatFull.participants.chat_id = chat.id; + chatFull.participants.admin_id = UserConfig.getClientUserId(); + chatFull.participants.version = 1; + for (int a = 0; a < selectedContacts.size(); a++) { + TLRPC.TL_chatParticipant participant = new TLRPC.TL_chatParticipant(); + participant.user_id = selectedContacts.get(a); + participant.inviter_id = UserConfig.getClientUserId(); + participant.date = (int) (System.currentTimeMillis() / 1000); + chatFull.participants.participants.add(participant); + } + MessagesStorage.getInstance().updateChatInfo(chatFull, false); + + TLRPC.TL_messageService newMsg = new TLRPC.TL_messageService(); + newMsg.action = new TLRPC.TL_messageActionCreatedBroadcastList(); + newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); + newMsg.from_id = UserConfig.getClientUserId(); + newMsg.dialog_id = AndroidUtilities.makeBroadcastId(chat.id); + newMsg.to_id = new TLRPC.TL_peerChat(); + newMsg.to_id.chat_id = chat.id; + newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); + newMsg.random_id = 0; + newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + UserConfig.saveConfig(false); + MessageObject newMsgObj = new MessageObject(newMsg, users, true); + newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + + ArrayList objArr = new ArrayList<>(); + objArr.add(newMsgObj); + ArrayList arr = new ArrayList<>(); + arr.add(newMsg); + MessagesStorage.getInstance().putMessages(arr, false, true, false, 0); + updateInterfaceWithMessages(newMsg.dialog_id, objArr); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatDidCreated, chat.id); + + return 0; + } else if (type == ChatObject.CHAT_TYPE_CHAT) { + TLRPC.TL_messages_createChat req = new TLRPC.TL_messages_createChat(); + req.title = title; + for (int a = 0; a < selectedContacts.size(); a++) { + TLRPC.User user = getUser(selectedContacts.get(a)); + if (user == null) { + continue; + } + req.users.add(getInputUser(user)); + } + return ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, final TLRPC.TL_error error) { + if (error != null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (error.text.startsWith("FLOOD_WAIT")) { + AlertsCreator.showFloodWaitAlert(error.text, fragment); + } else { + AlertsCreator.showAddUserAlert(error.text, fragment, false); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatDidFailCreate); + } + }); + return; + } + final TLRPC.Updates updates = (TLRPC.Updates) response; + processUpdates(updates, false); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + putUsers(updates.users, false); + putChats(updates.chats, false); + if (updates.chats != null && !updates.chats.isEmpty()) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatDidCreated, updates.chats.get(0).id); + } else { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatDidFailCreate); + } + } + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + } else if (type == ChatObject.CHAT_TYPE_CHANNEL || type == ChatObject.CHAT_TYPE_MEGAGROUP) { + TLRPC.TL_channels_createChannel req = new TLRPC.TL_channels_createChannel(); + req.title = title; + req.about = about; + if (type == ChatObject.CHAT_TYPE_MEGAGROUP) { + req.megagroup = true; + } else { + req.broadcast = true; + } + return ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, final TLRPC.TL_error error) { + if (error != null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (error.text.startsWith("FLOOD_WAIT")) { + AlertsCreator.showFloodWaitAlert(error.text, fragment); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatDidFailCreate); + } + }); + return; + } + final TLRPC.Updates updates = (TLRPC.Updates) response; + processUpdates(updates, false); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + putUsers(updates.users, false); + putChats(updates.chats, false); + if (updates.chats != null && !updates.chats.isEmpty()) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatDidCreated, updates.chats.get(0).id); + } else { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatDidFailCreate); + } + } + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + } + return 0; + } + + public void convertToMegaGroup(final Context context, int chat_id) { + TLRPC.TL_messages_migrateChat req = new TLRPC.TL_messages_migrateChat(); + req.chat_id = chat_id; + final ProgressDialog progressDialog = new ProgressDialog(context); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + final int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (!((Activity) context).isFinishing()) { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + }); + TLRPC.Updates updates = (TLRPC.Updates) response; + processUpdates((TLRPC.Updates) response, false); + } else { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (!((Activity) context).isFinishing()) { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + builder.show().setCanceledOnTouchOutside(true); + } + } + }); + } + } + }); + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + ConnectionsManager.getInstance().cancelRequest(reqId, true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + try { + progressDialog.show(); + } catch (Exception e) { + //don't promt + } + } + + public void addUsersToChannel(int chat_id, ArrayList users, final BaseFragment fragment) { + if (users == null || users.isEmpty()) { + return; + } + TLRPC.TL_channels_inviteToChannel req = new TLRPC.TL_channels_inviteToChannel(); + req.channel = getInputChannel(chat_id); + req.users = users; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, final TLRPC.TL_error error) { + if (error != null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (fragment != null) { + AlertsCreator.showAddUserAlert(error.text, fragment, true); + } else if (error.text.equals("PEER_FLOOD")) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.needShowAlert, 1); + } + } + }); + return; + } + processUpdates((TLRPC.Updates) response, false); + } + }); + } + + public void toogleChannelInvites(int chat_id, boolean enabled) { + TLRPC.TL_channels_toggleInvites req = new TLRPC.TL_channels_toggleInvites(); + req.channel = getInputChannel(chat_id); + req.enabled = enabled; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (response != null) { + processUpdates((TLRPC.Updates) response, false); + } + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } + + public void toogleChannelComments(int chat_id, boolean enabled) { + TLRPC.TL_channels_toggleComments req = new TLRPC.TL_channels_toggleComments(); + req.channel = getInputChannel(chat_id); + req.enabled = enabled; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (response != null) { + processUpdates((TLRPC.Updates) response, false); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHANNEL); + } + }); + } + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } + + public void toogleChannelSignatures(int chat_id, boolean enabled) { + TLRPC.TL_channels_toggleSignatures req = new TLRPC.TL_channels_toggleSignatures(); + req.channel = getInputChannel(chat_id); + req.enabled = enabled; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (response != null) { + processUpdates((TLRPC.Updates) response, false); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHANNEL); + } + }); + } + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } + + public void updateChannelAbout(int chat_id, final String about, final TLRPC.ChatFull info) { + if (info == null) { + return; + } + TLRPC.TL_channels_editAbout req = new TLRPC.TL_channels_editAbout(); + req.channel = getInputChannel(chat_id); + req.about = about; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (response instanceof TLRPC.TL_boolTrue) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + info.about = about; + MessagesStorage.getInstance().updateChatInfo(info, false); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, info, 0, false, null); + } + }); + } + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } + + public void updateChannelUserName(final int chat_id, final String userName) { + TLRPC.TL_channels_updateUsername req = new TLRPC.TL_channels_updateUsername(); + req.channel = getInputChannel(chat_id); + req.username = userName; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (response instanceof TLRPC.TL_boolTrue) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + TLRPC.Chat chat = getChat(chat_id); + if (userName.length() != 0) { + chat.flags |= TLRPC.CHAT_FLAG_IS_PUBLIC; + } else { + chat.flags &= ~TLRPC.CHAT_FLAG_IS_PUBLIC; + } + chat.username = userName; + ArrayList arrayList = new ArrayList<>(); + arrayList.add(chat); + MessagesStorage.getInstance().putUsersAndChats(null, arrayList, true, true); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHANNEL); + } + }); + } + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } + + public void sendBotStart(final TLRPC.User user, String botHash) { + if (user == null) { + return; + } + TLRPC.TL_messages_startBot req = new TLRPC.TL_messages_startBot(); + req.bot = getInputUser(user); + req.peer = getInputPeer(user.id); + req.start_param = botHash; + req.random_id = Utilities.random.nextLong(); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error != null) { + return; + } + processUpdates((TLRPC.Updates) response, false); + } + }); + } + + public void toggleAdminMode(final int chat_id, boolean enabled) { + TLRPC.TL_messages_toggleChatAdmins req = new TLRPC.TL_messages_toggleChatAdmins(); + req.chat_id = chat_id; + req.enabled = enabled; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + processUpdates((TLRPC.Updates) response, false); + loadFullChat(chat_id, 0, true); + } + } + }); + } + + public void toggleUserAdmin(final int chat_id, int user_id, boolean admin) { + TLRPC.TL_messages_editChatAdmin req = new TLRPC.TL_messages_editChatAdmin(); + req.chat_id = chat_id; + req.user_id = getInputUser(user_id); + req.is_admin = admin; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }); + } + + public void addUserToChat(final int chat_id, final TLRPC.User user, final TLRPC.ChatFull info, int count_fwd, String botHash, final BaseFragment fragment) { + if (user == null) { + return; + } + + if (chat_id > 0) { + TLObject request; + + final boolean isChannel = ChatObject.isChannel(chat_id); + final boolean isMegagroup = isChannel && getChat(chat_id).megagroup; + final TLRPC.InputUser inputUser = getInputUser(user); + if (botHash == null || isChannel && !isMegagroup) { + if (isChannel) { + if (inputUser instanceof TLRPC.TL_inputUserSelf) { + if (joiningToChannels.contains(chat_id)) { + return; + } + TLRPC.TL_channels_joinChannel req = new TLRPC.TL_channels_joinChannel(); + req.channel = getInputChannel(chat_id); + request = req; + joiningToChannels.add(chat_id); + } else { + if (user.bot && !isMegagroup) { + TLRPC.TL_channels_editAdmin req = new TLRPC.TL_channels_editAdmin(); + req.channel = getInputChannel(chat_id); + req.user_id = getInputUser(user); + req.role = new TLRPC.TL_channelRoleEditor(); + request = req; + } else { + TLRPC.TL_channels_inviteToChannel req = new TLRPC.TL_channels_inviteToChannel(); + req.channel = getInputChannel(chat_id); + req.users.add(inputUser); + request = req; + } + } + } else { + TLRPC.TL_messages_addChatUser req = new TLRPC.TL_messages_addChatUser(); + req.chat_id = chat_id; + req.fwd_limit = count_fwd; + req.user_id = inputUser; + request = req; + } + } else { + TLRPC.TL_messages_startBot req = new TLRPC.TL_messages_startBot(); + req.bot = inputUser; + if (isChannel) { + req.peer = getInputPeer(-chat_id); + } else { + req.peer = new TLRPC.TL_inputPeerChat(); + req.peer.chat_id = chat_id; + } + req.start_param = botHash; + req.random_id = Utilities.random.nextLong(); + request = req; + } + + ConnectionsManager.getInstance().sendRequest(request, new RequestDelegate() { + @Override + public void run(TLObject response, final TLRPC.TL_error error) { + if (isChannel && inputUser instanceof TLRPC.TL_inputUserSelf) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + joiningToChannels.remove((Integer) chat_id); + } + }); + } + if (error != null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (fragment != null) { + AlertsCreator.showAddUserAlert(error.text, fragment, isChannel && !isMegagroup); + } else { + if (error.text.equals("PEER_FLOOD")) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.needShowAlert, 1); + } + } + } + }); + return; + } + boolean hasJoinMessage = false; + TLRPC.Updates updates = (TLRPC.Updates) response; + for (int a = 0; a < updates.updates.size(); a++) { + TLRPC.Update update = updates.updates.get(a); + if (update instanceof TLRPC.TL_updateNewChannelMessage) { + if (((TLRPC.TL_updateNewChannelMessage) update).message.action instanceof TLRPC.TL_messageActionChatAddUser) { + hasJoinMessage = true; + break; + } + } + } + processUpdates(updates, false); + if (isChannel) { + if (!hasJoinMessage && inputUser instanceof TLRPC.TL_inputUserSelf) { + generateJoinMessage(chat_id, true); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + loadFullChat(chat_id, 0, true); + } + }, 1000); + } + if (isChannel && inputUser instanceof TLRPC.TL_inputUserSelf) { + MessagesStorage.getInstance().updateDialogsWithDeletedMessages(new ArrayList(), true, chat_id); + } + } + }); + } else { + if (info instanceof TLRPC.TL_chatFull) { + for (int a = 0; a < info.participants.participants.size(); a++) { + if (info.participants.participants.get(a).user_id == user.id) { + return; + } + } + + TLRPC.Chat chat = getChat(chat_id); + chat.participants_count++; + ArrayList chatArrayList = new ArrayList<>(); + chatArrayList.add(chat); + MessagesStorage.getInstance().putUsersAndChats(null, chatArrayList, true, true); + + TLRPC.TL_chatParticipant newPart = new TLRPC.TL_chatParticipant(); + newPart.user_id = user.id; + newPart.inviter_id = UserConfig.getClientUserId(); + newPart.date = ConnectionsManager.getInstance().getCurrentTime(); + info.participants.participants.add(0, newPart); + MessagesStorage.getInstance().updateChatInfo(info, true); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, info, 0, false, null); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHAT_MEMBERS); + } + } + } + + public void deleteUserFromChat(final int chat_id, final TLRPC.User user, final TLRPC.ChatFull info) { + if (user == null) { + return; + } + if (chat_id > 0) { + final TLRPC.InputUser inputUser = getInputUser(user); + TLObject request; + TLRPC.Chat chat = getChat(chat_id); + final boolean isChannel = ChatObject.isChannel(chat); + if (isChannel) { + if (inputUser instanceof TLRPC.TL_inputUserSelf) { + if (chat.creator) { + TLRPC.TL_channels_deleteChannel req = new TLRPC.TL_channels_deleteChannel(); + req.channel = getInputChannel(chat); + request = req; + } else { + TLRPC.TL_channels_leaveChannel req = new TLRPC.TL_channels_leaveChannel(); + req.channel = getInputChannel(chat); + request = req; + } + } else { + TLRPC.TL_channels_kickFromChannel req = new TLRPC.TL_channels_kickFromChannel(); + req.channel = getInputChannel(chat); + req.user_id = inputUser; + req.kicked = true; + request = req; + } + } else { + TLRPC.TL_messages_deleteChatUser req = new TLRPC.TL_messages_deleteChatUser(); + req.chat_id = chat_id; + req.user_id = getInputUser(user); + request = req; + } + ConnectionsManager.getInstance().sendRequest(request, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (user.id == UserConfig.getClientUserId()) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + deleteDialog(-chat_id, 0); + } + }); + } + if (error != null) { + return; + } + final TLRPC.Updates updates = (TLRPC.Updates) response; + processUpdates(updates, false); + if (isChannel && !(inputUser instanceof TLRPC.TL_inputUserSelf)) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + loadFullChat(chat_id, 0, true); + } + }, 1000); + } + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } else { + if (info instanceof TLRPC.TL_chatFull) { + TLRPC.Chat chat = getChat(chat_id); + chat.participants_count--; + ArrayList chatArrayList = new ArrayList<>(); + chatArrayList.add(chat); + MessagesStorage.getInstance().putUsersAndChats(null, chatArrayList, true, true); + + boolean changed = false; + for (int a = 0; a < info.participants.participants.size(); a++) { + TLRPC.ChatParticipant p = info.participants.participants.get(a); + if (p.user_id == user.id) { + info.participants.participants.remove(a); + changed = true; + break; + } + } + if (changed) { + MessagesStorage.getInstance().updateChatInfo(info, true); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, info, 0, false, null); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHAT_MEMBERS); + } + } + } + + public void changeChatTitle(int chat_id, String title) { + if (chat_id > 0) { + TLObject request; + if (ChatObject.isChannel(chat_id)) { + TLRPC.TL_channels_editTitle req = new TLRPC.TL_channels_editTitle(); + req.channel = getInputChannel(chat_id); + req.title = title; + request = req; + } else { + TLRPC.TL_messages_editChatTitle req = new TLRPC.TL_messages_editChatTitle(); + req.chat_id = chat_id; + req.title = title; + request = req; + } + ConnectionsManager.getInstance().sendRequest(request, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error != null) { + return; + } + processUpdates((TLRPC.Updates) response, false); + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } else { + TLRPC.Chat chat = getChat(chat_id); + chat.title = title; + ArrayList chatArrayList = new ArrayList<>(); + chatArrayList.add(chat); + MessagesStorage.getInstance().putUsersAndChats(null, chatArrayList, true, true); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_CHAT_NAME); + } + } + + public void changeChatAvatar(int chat_id, TLRPC.InputFile uploadedAvatar) { + TLObject request; + if (ChatObject.isChannel(chat_id)) { + TLRPC.TL_channels_editPhoto req = new TLRPC.TL_channels_editPhoto(); + req.channel = getInputChannel(chat_id); + if (uploadedAvatar != null) { + req.photo = new TLRPC.TL_inputChatUploadedPhoto(); + req.photo.file = uploadedAvatar; + req.photo.crop = new TLRPC.TL_inputPhotoCropAuto(); + } else { + req.photo = new TLRPC.TL_inputChatPhotoEmpty(); + } + request = req; + } else { + TLRPC.TL_messages_editChatPhoto req = new TLRPC.TL_messages_editChatPhoto(); + req.chat_id = chat_id; + if (uploadedAvatar != null) { + req.photo = new TLRPC.TL_inputChatUploadedPhoto(); + req.photo.file = uploadedAvatar; + req.photo.crop = new TLRPC.TL_inputPhotoCropAuto(); + } else { + req.photo = new TLRPC.TL_inputChatPhotoEmpty(); + } + request = req; + } + ConnectionsManager.getInstance().sendRequest(request, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error != null) { + return; + } + processUpdates((TLRPC.Updates) response, false); + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } + + public void unregistedPush() { + if (UserConfig.registeredForPush && UserConfig.pushString.length() == 0) { + TLRPC.TL_account_unregisterDevice req = new TLRPC.TL_account_unregisterDevice(); + req.token = UserConfig.pushString; + req.token_type = 2; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }); + } + } + + public void performLogout(boolean byUser) { + SharedPreferences.Editor editor = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).edit(); + editor.clear().commit(); + editor = ApplicationLoader.applicationContext.getSharedPreferences("emoji", Activity.MODE_PRIVATE).edit(); + editor.putLong("lastGifLoadTime", 0).commit(); + editor = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).edit(); + editor.remove("gifhint").commit(); + + if (byUser) { + unregistedPush(); + TLRPC.TL_auth_logOut req = new TLRPC.TL_auth_logOut(); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + ConnectionsManager.getInstance().cleanUp(); + } + }); + } else { + ConnectionsManager.getInstance().cleanUp(); + } + UserConfig.clearConfig(); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.appDidLogout); + MessagesStorage.getInstance().cleanUp(false); + cleanUp(); + ContactsController.getInstance().deleteAllAppAccounts(); + } + + public void generateUpdateMessage() { + if (UserConfig.lastUpdateVersion == null || UserConfig.lastUpdateVersion.equals(BuildVars.BUILD_VERSION_STRING)) { + return; + } + TLRPC.TL_help_getAppChangelog req = new TLRPC.TL_help_getAppChangelog(); + req.app_version = BuildVars.BUILD_VERSION_STRING; + try { + req.lang_code = LocaleController.getLocaleStringIso639(); + req.device_model = Build.MANUFACTURER + Build.MODEL; + req.system_version = "SDK " + Build.VERSION.SDK_INT; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (req.lang_code == null || req.lang_code.trim().length() == 0) { + req.lang_code = "en"; + } + if (req.device_model == null || req.device_model.trim().length() == 0) { + req.device_model = "Android unknown"; + } + if (req.system_version == null || req.system_version.trim().length() == 0) { + req.system_version = "SDK Unknown"; + } + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + UserConfig.lastUpdateVersion = BuildVars.BUILD_VERSION_STRING; + UserConfig.saveConfig(false); + } + if (response instanceof TLRPC.TL_help_appChangelog) { + TLRPC.TL_updateServiceNotification update = new TLRPC.TL_updateServiceNotification(); + update.message = ((TLRPC.TL_help_appChangelog) response).text; + update.media = new TLRPC.TL_messageMediaEmpty(); + update.type = "update"; + update.popup = false; + ArrayList updates = new ArrayList<>(); + updates.add(update); + processUpdateArray(updates, null, null); + } + else{ + TLRPC.TL_updateServiceNotification update = new TLRPC.TL_updateServiceNotification(); + update.message = LocaleController.getString("updatePlusText", R.string.updatePlusText); + //+ LocaleController.getString("JoinChannel", R.string.JoinChannel); + update.media = new TLRPC.TL_messageMediaEmpty(); + update.type = "update"; + update.popup = false; + ArrayList updates = new ArrayList<>(); + updates.add(update); + processUpdateArray(updates, null, null); + } + } + }); + } + + public void registerForPush(final String regid) { + if (regid == null || regid.length() == 0 || registeringForPush || UserConfig.getClientUserId() == 0) { + return; + } + if (UserConfig.registeredForPush && regid.equals(UserConfig.pushString)) { + return; + } + registeringForPush = true; + TLRPC.TL_account_registerDevice req = new TLRPC.TL_account_registerDevice(); + req.token_type = 2; + req.token = regid; + req.app_sandbox = false; + try { + req.lang_code = LocaleController.getLocaleStringIso639(); + if (req.lang_code.length() == 0) { + req.lang_code = "en"; + } + req.device_model = Build.MANUFACTURER + Build.MODEL; + req.system_version = "SDK " + Build.VERSION.SDK_INT; + PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); + req.app_version = pInfo.versionName + " (" + pInfo.versionCode + ")"; + } catch (Exception e) { + FileLog.e("tmessages", e); + req.lang_code = "en"; + req.device_model = "Android unknown"; + req.system_version = "SDK " + Build.VERSION.SDK_INT; + req.app_version = "App version unknown"; + } + + if (req.lang_code == null || req.lang_code.trim().length() == 0) { + req.lang_code = "en"; + } + if (req.device_model == null || req.device_model.trim().length() == 0) { + req.device_model = "Android unknown"; + } + if (req.app_version == null || req.app_version.trim().length() == 0) { + req.app_version = "App version unknown"; + } + if (req.system_version == null || req.system_version.trim().length() == 0) { + req.system_version = "SDK Unknown"; + } + + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (response instanceof TLRPC.TL_boolTrue) { + FileLog.e("tmessages", "registered for push"); + UserConfig.registeredForPush = true; + UserConfig.pushString = regid; + UserConfig.saveConfig(false); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + registeringForPush = false; + } + }); + } + }); + } + + public void loadCurrentState() { + if (updatingState) { + return; + } + updatingState = true; + TLRPC.TL_updates_getState req = new TLRPC.TL_updates_getState(); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + updatingState = false; + if (error == null) { + TLRPC.TL_updates_state res = (TLRPC.TL_updates_state) response; + MessagesStorage.lastDateValue = res.date; + MessagesStorage.lastPtsValue = res.pts; + MessagesStorage.lastSeqValue = res.seq; + MessagesStorage.lastQtsValue = res.qts; + for (int a = 0; a < 3; a++) { + processUpdatesQueue(a, 2); + } + MessagesStorage.getInstance().saveDiffParams(MessagesStorage.lastSeqValue, MessagesStorage.lastPtsValue, MessagesStorage.lastDateValue, MessagesStorage.lastQtsValue); + } else { + if (error.code != 401) { + loadCurrentState(); + } + } + } + }); + } + + private int getUpdateSeq(TLRPC.Updates updates) { + if (updates instanceof TLRPC.TL_updatesCombined) { + return updates.seq_start; + } else { + return updates.seq; + } + } + + private void setUpdatesStartTime(int type, long time) { + if (type == 0) { + updatesStartWaitTimeSeq = time; + } else if (type == 1) { + updatesStartWaitTimePts = time; + } else if (type == 2) { + updatesStartWaitTimeQts = time; + } + } + + public long getUpdatesStartTime(int type) { + if (type == 0) { + return updatesStartWaitTimeSeq; + } else if (type == 1) { + return updatesStartWaitTimePts; + } else if (type == 2) { + return updatesStartWaitTimeQts; + } + return 0; + } + + private int isValidUpdate(TLRPC.Updates updates, int type) { + if (type == 0) { + int seq = getUpdateSeq(updates); + if (MessagesStorage.lastSeqValue + 1 == seq || MessagesStorage.lastSeqValue == seq) { + return 0; + } else if (MessagesStorage.lastSeqValue < seq) { + return 1; + } else { + return 2; + } + } else if (type == 1) { + if (updates.pts <= MessagesStorage.lastPtsValue) { + return 2; + } else if (MessagesStorage.lastPtsValue + updates.pts_count == updates.pts) { + return 0; + } else { + return 1; + } + } else if (type == 2) { + if (updates.pts <= MessagesStorage.lastQtsValue) { + return 2; + } else if (MessagesStorage.lastQtsValue + updates.updates.size() == updates.pts) { + return 0; + } else { + return 1; + } + } + return 0; + } + + private void processChannelsUpdatesQueue(int channelId, int state) { + ArrayList updatesQueue = updatesQueueChannels.get(channelId); + if (updatesQueue == null) { + return; + } + Integer channelPts = channelsPts.get(channelId); + if (updatesQueue.isEmpty() || channelPts == null) { + updatesQueueChannels.remove(channelId); + return; + } + Collections.sort(updatesQueue, new Comparator() { + @Override + public int compare(TLRPC.Updates updates, TLRPC.Updates updates2) { + return AndroidUtilities.compare(updates.pts, updates2.pts); + } + }); + boolean anyProceed = false; + if (state == 2) { + channelsPts.put(channelId, updatesQueue.get(0).pts); + } + for (int a = 0; a < updatesQueue.size(); a++) { + TLRPC.Updates updates = updatesQueue.get(a); + int updateState; + if (updates.pts <= channelPts) { + updateState = 2; + } else if (channelPts + updates.pts_count == updates.pts) { + updateState = 0; + } else { + updateState = 1; + } + if (updateState == 0) { + processUpdates(updates, true); + anyProceed = true; + updatesQueue.remove(a); + a--; + } else if (updateState == 1) { + Long updatesStartWaitTime = updatesStartWaitTimeChannels.get(channelId); + if (updatesStartWaitTime != null && (anyProceed || Math.abs(System.currentTimeMillis() - updatesStartWaitTime) <= 1500)) { + FileLog.e("tmessages", "HOLE IN CHANNEL " + channelId + " UPDATES QUEUE - will wait more time"); + if (anyProceed) { + updatesStartWaitTimeChannels.put(channelId, System.currentTimeMillis()); + } + return; + } else { + FileLog.e("tmessages", "HOLE IN CHANNEL " + channelId + " UPDATES QUEUE - getChannelDifference "); + updatesStartWaitTimeChannels.remove(channelId); + updatesQueueChannels.remove(channelId); + getChannelDifference(channelId); + return; + } + } else { + updatesQueue.remove(a); + a--; + } + } + updatesQueueChannels.remove(channelId); + updatesStartWaitTimeChannels.remove(channelId); + FileLog.e("tmessages", "UPDATES CHANNEL " + channelId + " QUEUE PROCEED - OK"); + } + + private void processUpdatesQueue(int type, int state) { + ArrayList updatesQueue = null; + if (type == 0) { + updatesQueue = updatesQueueSeq; + Collections.sort(updatesQueue, new Comparator() { + @Override + public int compare(TLRPC.Updates updates, TLRPC.Updates updates2) { + return AndroidUtilities.compare(getUpdateSeq(updates), getUpdateSeq(updates2)); + } + }); + } else if (type == 1) { + updatesQueue = updatesQueuePts; + Collections.sort(updatesQueue, new Comparator() { + @Override + public int compare(TLRPC.Updates updates, TLRPC.Updates updates2) { + return AndroidUtilities.compare(updates.pts, updates2.pts); + } + }); + } else if (type == 2) { + updatesQueue = updatesQueueQts; + Collections.sort(updatesQueue, new Comparator() { + @Override + public int compare(TLRPC.Updates updates, TLRPC.Updates updates2) { + return AndroidUtilities.compare(updates.pts, updates2.pts); + } + }); + } + if (updatesQueue != null && !updatesQueue.isEmpty()) { + boolean anyProceed = false; + if (state == 2) { + TLRPC.Updates updates = updatesQueue.get(0); + if (type == 0) { + MessagesStorage.lastSeqValue = getUpdateSeq(updates); + } else if (type == 1) { + MessagesStorage.lastPtsValue = updates.pts; + } else { + MessagesStorage.lastQtsValue = updates.pts; + } + } + for (int a = 0; a < updatesQueue.size(); a++) { + TLRPC.Updates updates = updatesQueue.get(a); + int updateState = isValidUpdate(updates, type); + if (updateState == 0) { + processUpdates(updates, true); + anyProceed = true; + updatesQueue.remove(a); + a--; + } else if (updateState == 1) { + if (getUpdatesStartTime(type) != 0 && (anyProceed || Math.abs(System.currentTimeMillis() - getUpdatesStartTime(type)) <= 1500)) { + FileLog.e("tmessages", "HOLE IN UPDATES QUEUE - will wait more time"); + if (anyProceed) { + setUpdatesStartTime(type, System.currentTimeMillis()); + } + return; + } else { + FileLog.e("tmessages", "HOLE IN UPDATES QUEUE - getDifference"); + setUpdatesStartTime(type, 0); + updatesQueue.clear(); + getDifference(); + return; + } + } else { + updatesQueue.remove(a); + a--; + } + } + updatesQueue.clear(); + FileLog.e("tmessages", "UPDATES QUEUE PROCEED - OK"); + } + setUpdatesStartTime(type, 0); + } + + public void startShortPoll(final int channelId, final boolean stop) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (stop) { + needShortPollChannels.delete(channelId); + } else { + needShortPollChannels.put(channelId, 0); + if (shortPollChannels.indexOfKey(channelId) < 0) { + getChannelDifference(channelId, 2); + } + } + } + }); + } + + public void getChannelDifference(final int channelId) { + getChannelDifference(channelId, 0); + } + + public void getChannelDifference(final int channelId, final int newDialogType) { + Boolean gettingDifferenceChannel = gettingDifferenceChannels.get(channelId); + if (gettingDifferenceChannel == null) { + gettingDifferenceChannel = false; + } + if (gettingDifferenceChannel) { + return; + } + int limit = 100; + Integer channelPts; + if (newDialogType == 1) { + channelPts = channelsPts.get(channelId); + if (channelPts != null) { + return; + } + channelPts = 1; + limit = 1; + } else { + channelPts = channelsPts.get(channelId); + if (channelPts == null) { + channelPts = MessagesStorage.getInstance().getChannelPtsSync(channelId); + if (channelPts != 0) { + channelsPts.put(channelId, channelPts); + } + if (channelPts == 0 && newDialogType == 2) { + return; + } + } + if (channelPts == 0) { + return; + } + } + gettingDifferenceChannels.put(channelId, true); + TLRPC.TL_updates_getChannelDifference req = new TLRPC.TL_updates_getChannelDifference(); + req.channel = getInputChannel(channelId); + req.filter = new TLRPC.TL_channelMessagesFilterEmpty(); + req.pts = channelPts; + req.limit = limit; + FileLog.e("tmessages", "start getChannelDifference with pts = " + channelPts + " channelId = " + channelId); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, final TLRPC.TL_error error) { + + if (error == null) { + final TLRPC.updates_ChannelDifference res = (TLRPC.updates_ChannelDifference) response; + + final HashMap usersDict = new HashMap<>(); + for (int a = 0; a < res.users.size(); a++) { + TLRPC.User user = res.users.get(a); + usersDict.put(user.id, user); + } + TLRPC.Chat channel = null; + for (int a = 0; a < res.chats.size(); a++) { + TLRPC.Chat chat = res.chats.get(a); + if (chat.id == channelId) { + channel = chat; + break; + } + } + final TLRPC.Chat channelFinal = channel; + + final ArrayList msgUpdates = new ArrayList<>(); + if (!res.other_updates.isEmpty()) { + for (int a = 0; a < res.other_updates.size(); a++) { + TLRPC.Update upd = res.other_updates.get(a); + if (upd instanceof TLRPC.TL_updateMessageID) { + msgUpdates.add((TLRPC.TL_updateMessageID) upd); + res.other_updates.remove(a); + a--; + } + } + } + + MessagesStorage.getInstance().putUsersAndChats(res.users, res.chats, true, true); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + putUsers(res.users, false); + putChats(res.chats, false); + } + }); + + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + if (!msgUpdates.isEmpty()) { + final HashMap corrected = new HashMap<>(); + for (TLRPC.TL_updateMessageID update : msgUpdates) { + long[] ids = MessagesStorage.getInstance().updateMessageStateAndId(update.random_id, null, update.id, 0, false, channelId); + if (ids != null) { + corrected.put(update.id, ids); + } + } + + if (!corrected.isEmpty()) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + for (HashMap.Entry entry : corrected.entrySet()) { + Integer newId = entry.getKey(); + long[] ids = entry.getValue(); + Integer oldId = (int) ids[1]; + SendMessagesHelper.getInstance().processSentMessage(oldId); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newId, null, ids[0]); + } + } + }); + } + } + + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (res instanceof TLRPC.TL_updates_channelDifference || res instanceof TLRPC.TL_updates_channelDifferenceEmpty) { + if (!res.new_messages.isEmpty()) { + final HashMap> messages = new HashMap<>(); + ImageLoader.saveMessagesThumbs(res.new_messages); + + final ArrayList pushMessages = new ArrayList<>(); + for (int a = 0; a < res.new_messages.size(); a++) { + TLRPC.Message message = res.new_messages.get(a); + if (!message.out) { + message.unread = true; + if (message.post || channelFinal != null && channelFinal.megagroup) { + message.media_unread = true; + } + } + if (message.action instanceof TLRPC.TL_messageActionChannelCreate) { + message.unread = false; + message.media_unread = false; + } + if (channelFinal != null && channelFinal.megagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + + long dialog_id = -channelId; + Integer value = dialogs_read_inbox_max.get(dialog_id); + if (value == null) { + value = MessagesStorage.getInstance().getChannelReadInboxMax(channelId); + } + + MessageObject obj = new MessageObject(message, usersDict, createdDialogIds.contains(dialog_id)); + if (channelFinal != null && channelFinal.left || value >= obj.getId()) { + obj.setIsRead(); + obj.setContentIsRead(); + } + + if (!obj.isOut() && obj.isContentUnread()) { + pushMessages.add(obj); + } + + long uid = -channelId; + ArrayList arr = messages.get(uid); + if (arr == null) { + arr = new ArrayList<>(); + messages.put(uid, arr); + } + arr.add(obj); + } + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + for (HashMap.Entry> pair : messages.entrySet()) { + Long key = pair.getKey(); + ArrayList value = pair.getValue(); + updateInterfaceWithMessages(key, value); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + } + }); + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + if (!pushMessages.isEmpty()) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationsController.getInstance().processNewMessages(pushMessages, true); + } + }); + } + MessagesStorage.getInstance().putMessages(res.new_messages, true, false, false, MediaController.getInstance().getAutodownloadMask()); + } + }); + } + + if (!res.other_updates.isEmpty()) { + processUpdateArray(res.other_updates, res.users, res.chats); + } + processChannelsUpdatesQueue(channelId, 1); + MessagesStorage.getInstance().saveChannelPts(channelId, res.pts); + } else if (res instanceof TLRPC.TL_updates_channelDifferenceTooLong) { + for (int a = 0; a < res.messages.size(); a++) { + TLRPC.Message message = res.messages.get(a); + message.dialog_id = -channelId; + if (!message.out) { + message.unread = true; + if (message.post || channelFinal != null && channelFinal.megagroup) { + message.media_unread = true; + } + } + if (message.action instanceof TLRPC.TL_messageActionChannelCreate) { + message.unread = false; + message.media_unread = false; + } + if (channelFinal != null && channelFinal.megagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + + if (channelFinal != null && channelFinal.left || res.read_inbox_max_id >= message.id) { + message.unread = false; + message.media_unread = false; + } + if (channelFinal != null && channelFinal.megagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + } + if (channelFinal != null && channelFinal.megagroup) { + res.unread_important_count = Math.max(res.unread_count, res.unread_important_count); + res.top_important_message = Math.max(res.top_important_message, res.top_message); + } + MessagesStorage.getInstance().overwriteChannel(channelId, (TLRPC.TL_updates_channelDifferenceTooLong) res, newDialogType); + } + gettingDifferenceChannels.remove(channelId); + channelsPts.put(channelId, res.pts); + + if ((res.flags & 2) != 0) { + shortPollChannels.put(channelId, (int) (System.currentTimeMillis() / 1000) + res.timeout); + } + if (!res.isFinal) { + getChannelDifference(channelId); + } + FileLog.e("tmessages", "received channel difference with pts = " + res.pts + " channelId = " + channelId); + FileLog.e("tmessages", "messages = " + res.new_messages.size() + " users = " + res.users.size() + " chats = " + res.chats.size() + " other updates = " + res.other_updates.size()); + } + }); + } + }); + } else { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + checkChannelError(error.text, channelId); + } + }); + gettingDifferenceChannels.remove(channelId); + } + } + }); + } + + private void checkChannelError(String text, int channelId) { + switch (text) { + case "CHANNEL_PRIVATE": + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoCantLoad, channelId, 0); + break; + case "CHANNEL_PUBLIC_GROUP_NA": + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoCantLoad, channelId, 1); + break; + case "USER_BANNED_IN_CHANNEL": + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoCantLoad, channelId, 2); + break; + } + } + + public void getDifference() { + getDifference(MessagesStorage.lastPtsValue, MessagesStorage.lastDateValue, MessagesStorage.lastQtsValue, false); + } + + public void getDifference(int pts, int date, int qts, boolean slice) { + registerForPush(UserConfig.pushString); + if (MessagesStorage.lastPtsValue == 0) { + loadCurrentState(); + return; + } + if (!slice && gettingDifference) { + return; + } + if (!firstGettingTask) { + getNewDeleteTask(null); + firstGettingTask = true; + } + gettingDifference = true; + TLRPC.TL_updates_getDifference req = new TLRPC.TL_updates_getDifference(); + req.pts = pts; + req.date = date; + req.qts = qts; + if (req.date == 0) { + req.date = ConnectionsManager.getInstance().getCurrentTime(); + } + FileLog.e("tmessages", "start getDifference with date = " + MessagesStorage.lastDateValue + " pts = " + MessagesStorage.lastPtsValue + " seq = " + MessagesStorage.lastSeqValue); + ConnectionsManager.getInstance().setIsUpdating(true); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + final TLRPC.updates_Difference res = (TLRPC.updates_Difference) response; + + if (res instanceof TLRPC.TL_updates_differenceSlice) { + getDifference(res.intermediate_state.pts, res.intermediate_state.date, res.intermediate_state.qts, true); + } + + final HashMap usersDict = new HashMap<>(); + final HashMap chatsDict = new HashMap<>(); + for (int a = 0; a < res.users.size(); a++) { + TLRPC.User user = res.users.get(a); + usersDict.put(user.id, user); + } + for (int a = 0; a < res.chats.size(); a++) { + TLRPC.Chat chat = res.chats.get(a); + chatsDict.put(chat.id, chat); + } + + final ArrayList msgUpdates = new ArrayList<>(); + if (!res.other_updates.isEmpty()) { + for (int a = 0; a < res.other_updates.size(); a++) { + TLRPC.Update upd = res.other_updates.get(a); + if (upd instanceof TLRPC.TL_updateMessageID) { + msgUpdates.add((TLRPC.TL_updateMessageID) upd); + res.other_updates.remove(a); + a--; + } + } + } + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + putUsers(res.users, false); + putChats(res.chats, false); + } + }); + + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + MessagesStorage.getInstance().putUsersAndChats(res.users, res.chats, true, false); + if (!msgUpdates.isEmpty()) { + final HashMap corrected = new HashMap<>(); + for (TLRPC.TL_updateMessageID update : msgUpdates) { + long[] ids = MessagesStorage.getInstance().updateMessageStateAndId(update.random_id, null, update.id, 0, false, 0); + if (ids != null) { + corrected.put(update.id, ids); + } + } + + if (!corrected.isEmpty()) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + for (HashMap.Entry entry : corrected.entrySet()) { + Integer newId = entry.getKey(); + long[] ids = entry.getValue(); + Integer oldId = (int) ids[1]; + SendMessagesHelper.getInstance().processSentMessage(oldId); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newId, null, ids[0]); + } + } + }); + } + } + + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (!res.new_messages.isEmpty() || !res.new_encrypted_messages.isEmpty()) { + final HashMap> messages = new HashMap<>(); + for (TLRPC.EncryptedMessage encryptedMessage : res.new_encrypted_messages) { + ArrayList decryptedMessages = SecretChatHelper.getInstance().decryptMessage(encryptedMessage); + if (decryptedMessages != null && !decryptedMessages.isEmpty()) { + for (TLRPC.Message message : decryptedMessages) { + res.new_messages.add(message); + } + } + } + + ImageLoader.saveMessagesThumbs(res.new_messages); + + final ArrayList pushMessages = new ArrayList<>(); + for (int a = 0; a < res.new_messages.size(); a++) { + TLRPC.Message message = res.new_messages.get(a); + + if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) { + //plus + if(hideLeftGroup && message.action.user_id == message.from_id){ + continue; + }// + TLRPC.User user = usersDict.get(message.action.user_id); + if (user != null && user.bot) { + message.reply_markup = new TLRPC.TL_replyKeyboardHide(); + } + } else if (message.action instanceof TLRPC.TL_messageActionChatMigrateTo || message.action instanceof TLRPC.TL_messageActionChannelCreate) { + message.unread = false; + message.media_unread = false; + } + + long uid; + if (message.dialog_id != 0) { + uid = message.dialog_id; + } else { + if (message.to_id.chat_id != 0) { + uid = -message.to_id.chat_id; + } else { + if (message.to_id.user_id == UserConfig.getClientUserId()) { + message.to_id.user_id = message.from_id; + } + uid = message.to_id.user_id; + } + } + + MessageObject obj = new MessageObject(message, usersDict, chatsDict, createdDialogIds.contains(uid)); + + if (!obj.isOut() && obj.isUnread()) { + pushMessages.add(obj); + } + + ArrayList arr = messages.get(uid); + if (arr == null) { + arr = new ArrayList<>(); + messages.put(uid, arr); + } + arr.add(obj); + } + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + for (HashMap.Entry> pair : messages.entrySet()) { + Long key = pair.getKey(); + ArrayList value = pair.getValue(); + updateInterfaceWithMessages(key, value); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + } + }); + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + if (!pushMessages.isEmpty()) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationsController.getInstance().processNewMessages(pushMessages, !(res instanceof TLRPC.TL_updates_differenceSlice)); + } + }); + } + MessagesStorage.getInstance().putMessages(res.new_messages, true, false, false, MediaController.getInstance().getAutodownloadMask()); + } + }); + + SecretChatHelper.getInstance().processPendingEncMessages(); + } + + if (!res.other_updates.isEmpty()) { + processUpdateArray(res.other_updates, res.users, res.chats); + } + + if (res instanceof TLRPC.TL_updates_difference) { + gettingDifference = false; + MessagesStorage.lastSeqValue = res.state.seq; + MessagesStorage.lastDateValue = res.state.date; + MessagesStorage.lastPtsValue = res.state.pts; + MessagesStorage.lastQtsValue = res.state.qts; + ConnectionsManager.getInstance().setIsUpdating(false); + for (int a = 0; a < 3; a++) { + processUpdatesQueue(a, 1); + } + } else if (res instanceof TLRPC.TL_updates_differenceSlice) { + MessagesStorage.lastDateValue = res.intermediate_state.date; + MessagesStorage.lastPtsValue = res.intermediate_state.pts; + MessagesStorage.lastQtsValue = res.intermediate_state.qts; + } else if (res instanceof TLRPC.TL_updates_differenceEmpty) { + gettingDifference = false; + MessagesStorage.lastSeqValue = res.seq; + MessagesStorage.lastDateValue = res.date; + ConnectionsManager.getInstance().setIsUpdating(false); + for (int a = 0; a < 3; a++) { + processUpdatesQueue(a, 1); + } + } + MessagesStorage.getInstance().saveDiffParams(MessagesStorage.lastSeqValue, MessagesStorage.lastPtsValue, MessagesStorage.lastDateValue, MessagesStorage.lastQtsValue); + FileLog.e("tmessages", "received difference with date = " + MessagesStorage.lastDateValue + " pts = " + MessagesStorage.lastPtsValue + " seq = " + MessagesStorage.lastSeqValue + " messages = " + res.new_messages.size() + " users = " + res.users.size() + " chats = " + res.chats.size() + " other updates = " + res.other_updates.size()); + } + }); + } + }); + } else { + gettingDifference = false; + ConnectionsManager.getInstance().setIsUpdating(false); + } + } + }); + } + + public void generateJoinMessage(final int chat_id, boolean ignoreLeft) { + TLRPC.Chat chat = getChat(chat_id); + if (chat == null || !ChatObject.isChannel(chat_id) || (chat.left || chat.kicked) && !ignoreLeft) { + return; + } + + TLRPC.TL_messageService message = new TLRPC.TL_messageService(); + message.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + message.local_id = message.id = UserConfig.getNewMessageId(); + message.date = ConnectionsManager.getInstance().getCurrentTime(); + message.from_id = UserConfig.getClientUserId(); + message.to_id = new TLRPC.TL_peerChannel(); + message.to_id.channel_id = chat_id; + message.dialog_id = -chat_id; + message.post = true; + message.action = new TLRPC.TL_messageActionChatAddUser(); + message.action.users.add(UserConfig.getClientUserId()); + if (chat.megagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + UserConfig.saveConfig(false); + + final ArrayList pushMessages = new ArrayList<>(); + final ArrayList messagesArr = new ArrayList<>(); + + messagesArr.add(message); + MessageObject obj = new MessageObject(message, null, true); + pushMessages.add(obj); + + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationsController.getInstance().processNewMessages(pushMessages, true); + } + }); + } + }); + MessagesStorage.getInstance().putMessages(messagesArr, true, true, false, MediaController.getInstance().getAutodownloadMask()); + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + updateInterfaceWithMessages(-chat_id, pushMessages); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + } + }); + } + + public void convertGroup() { + + } + + public void checkChannelInviter(final int chat_id) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + final TLRPC.Chat chat = getChat(chat_id); + if (chat == null || !ChatObject.isChannel(chat_id) || chat.creator) { + return; + } + TLRPC.TL_channels_getParticipant req = new TLRPC.TL_channels_getParticipant(); + req.channel = getInputChannel(chat_id); + req.user_id = new TLRPC.TL_inputUserSelf(); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + final TLRPC.TL_channels_channelParticipant res = (TLRPC.TL_channels_channelParticipant) response; + if (res != null && res.participant instanceof TLRPC.TL_channelParticipantSelf && res.participant.inviter_id != UserConfig.getClientUserId()) { + if (chat.megagroup && MessagesStorage.getInstance().isMigratedChat(chat.id)) { + return; + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + putUsers(res.users, false); + } + }); + MessagesStorage.getInstance().putUsersAndChats(res.users, null, true, true); + + TLRPC.TL_messageService message = new TLRPC.TL_messageService(); + message.media_unread = true; + message.unread = true; + message.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + message.post = true; + if (chat.megagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + message.local_id = message.id = UserConfig.getNewMessageId(); + message.date = res.participant.date; + message.action = new TLRPC.TL_messageActionChatAddUser(); + message.from_id = res.participant.inviter_id; + message.action.users.add(UserConfig.getClientUserId()); + message.to_id = new TLRPC.TL_peerChannel(); + message.to_id.channel_id = chat_id; + message.dialog_id = -chat_id; + UserConfig.saveConfig(false); + + final ArrayList pushMessages = new ArrayList<>(); + final ArrayList messagesArr = new ArrayList<>(); + + ConcurrentHashMap usersDict = new ConcurrentHashMap<>(); + for (int a = 0; a < res.users.size(); a++) { + TLRPC.User user = res.users.get(a); + usersDict.put(user.id, user); + } + + messagesArr.add(message); + MessageObject obj = new MessageObject(message, usersDict, true); + pushMessages.add(obj); + + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationsController.getInstance().processNewMessages(pushMessages, true); + } + }); + } + }); + MessagesStorage.getInstance().putMessages(messagesArr, true, true, false, MediaController.getInstance().getAutodownloadMask()); + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + updateInterfaceWithMessages(-chat_id, pushMessages); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + } + }); + } + } + }); + } + }); + } + + private int getUpdateType(TLRPC.Update update) { + if (update instanceof TLRPC.TL_updateNewMessage || update instanceof TLRPC.TL_updateReadMessagesContents || update instanceof TLRPC.TL_updateReadHistoryInbox || + update instanceof TLRPC.TL_updateReadHistoryOutbox || update instanceof TLRPC.TL_updateDeleteMessages || update instanceof TLRPC.TL_updateWebPage || + update instanceof TLRPC.TL_updateEditMessage) { + return 0; + } else if (update instanceof TLRPC.TL_updateNewEncryptedMessage) { + return 1; + } else if (update instanceof TLRPC.TL_updateNewChannelMessage || update instanceof TLRPC.TL_updateDeleteChannelMessages || update instanceof TLRPC.TL_updateEditChannelMessage) { + return 2; + } else { + return 3; + } + } + + public void processUpdates(final TLRPC.Updates updates, boolean fromQueue) { + ArrayList needGetChannelsDiff = null; + boolean needGetDiff = false; + boolean needReceivedQueue = false; + boolean updateStatus = false; + if (updates instanceof TLRPC.TL_updateShort) { + ArrayList arr = new ArrayList<>(); + arr.add(updates.update); + processUpdateArray(arr, null, null); + } else if (updates instanceof TLRPC.TL_updateShortChatMessage || updates instanceof TLRPC.TL_updateShortMessage) { + final int user_id = updates instanceof TLRPC.TL_updateShortChatMessage ? updates.from_id : updates.user_id; + TLRPC.User user = getUser(user_id); + TLRPC.User user2 = null; + TLRPC.User user3 = null; + TLRPC.Chat channel = null; + + if (user == null || user.min) { //TODO + user = MessagesStorage.getInstance().getUserSync(user_id); + if (user != null && user.min) { + user = null; + } + putUser(user, true); + } + + boolean needFwdUser = false; + if (updates.fwd_from != null) { + if (updates.fwd_from.from_id != 0) { + user2 = getUser(updates.fwd_from.from_id); + if (user2 == null) { + user2 = MessagesStorage.getInstance().getUserSync(updates.fwd_from.from_id); + putUser(user2, true); + } + needFwdUser = true; + } + if (updates.fwd_from.channel_id != 0) { + channel = getChat(updates.fwd_from.channel_id); + if (channel == null) { + channel = MessagesStorage.getInstance().getChatSync(updates.fwd_from.channel_id); + putChat(channel, true); + } + needFwdUser = true; + } + } + + boolean needBotUser = false; + if (updates.via_bot_id != 0) { + user3 = getUser(updates.via_bot_id); + if (user3 == null) { + user3 = MessagesStorage.getInstance().getUserSync(updates.via_bot_id); + putUser(user3, true); + } + needBotUser = true; + } + + boolean missingData; + if (updates instanceof TLRPC.TL_updateShortMessage) { + missingData = user == null || needFwdUser && user2 == null && channel == null || needBotUser && user3 == null; + } else { + TLRPC.Chat chat = getChat(updates.chat_id); + if (chat == null) { + chat = MessagesStorage.getInstance().getChatSync(updates.chat_id); + putChat(chat, true); + } + missingData = chat == null || user == null || needFwdUser && user2 == null && channel == null || needBotUser && user3 == null; + } + if (user != null && user.status != null && user.status.expires <= 0) { + onlinePrivacy.put(user.id, ConnectionsManager.getInstance().getCurrentTime()); + updateStatus = true; + } + + if (missingData) { + needGetDiff = true; + } else { + if (MessagesStorage.lastPtsValue + updates.pts_count == updates.pts) { + TLRPC.TL_message message = new TLRPC.TL_message(); + message.id = updates.id; + if (updates instanceof TLRPC.TL_updateShortMessage) { + if (updates.out) { + message.from_id = UserConfig.getClientUserId(); + } else { + message.from_id = user_id; + } + message.to_id = new TLRPC.TL_peerUser(); + message.to_id.user_id = user_id; + message.dialog_id = user_id; + } else { + message.from_id = user_id; + message.to_id = new TLRPC.TL_peerChat(); + message.to_id.chat_id = updates.chat_id; + message.dialog_id = -updates.chat_id; + } + message.fwd_from = updates.fwd_from; + message.silent = updates.silent; + message.out = updates.out; + message.unread = updates.unread; + message.mentioned = updates.mentioned; + message.media_unread = updates.media_unread; + message.entities = updates.entities; + message.message = updates.message; + message.date = updates.date; + message.via_bot_id = updates.via_bot_id; + message.flags = updates.flags | TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + message.reply_to_msg_id = updates.reply_to_msg_id; + message.media = new TLRPC.TL_messageMediaEmpty(); + MessagesStorage.lastPtsValue = updates.pts; + final MessageObject obj = new MessageObject(message, null, createdDialogIds.contains(message.dialog_id)); + final ArrayList objArr = new ArrayList<>(); + objArr.add(obj); + ArrayList arr = new ArrayList<>(); + arr.add(message); + if (updates instanceof TLRPC.TL_updateShortMessage) { + final boolean printUpdate = !updates.out && updatePrintingUsersWithNewMessages(updates.user_id, objArr); + if (printUpdate) { + updatePrintingStrings(); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (printUpdate) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_USER_PRINT); + } + updateInterfaceWithMessages(user_id, objArr); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + } + }); + } else { + final boolean printUpdate = updatePrintingUsersWithNewMessages(-updates.chat_id, objArr); + if (printUpdate) { + updatePrintingStrings(); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (printUpdate) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_USER_PRINT); + } + + updateInterfaceWithMessages(-updates.chat_id, objArr); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + } + }); + } + + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (!obj.isOut()) { + NotificationsController.getInstance().processNewMessages(objArr, true); + } + } + }); + } + }); + MessagesStorage.getInstance().putMessages(arr, false, true, false, 0); + } else if (MessagesStorage.lastPtsValue != updates.pts) { + FileLog.e("tmessages", "need get diff short message, pts: " + MessagesStorage.lastPtsValue + " " + updates.pts + " count = " + updates.pts_count); + if (gettingDifference || updatesStartWaitTimePts == 0 || Math.abs(System.currentTimeMillis() - updatesStartWaitTimePts) <= 1500) { + if (updatesStartWaitTimePts == 0) { + updatesStartWaitTimePts = System.currentTimeMillis(); + } + FileLog.e("tmessages", "add to queue"); + updatesQueuePts.add(updates); + } else { + needGetDiff = true; + } + } + } + } else if (updates instanceof TLRPC.TL_updatesCombined || updates instanceof TLRPC.TL_updates) { + HashMap minChannels = null; + for (int a = 0; a < updates.chats.size(); a++) { + TLRPC.Chat chat = updates.chats.get(a); + if (chat instanceof TLRPC.TL_channel && chat.min) { + TLRPC.Chat existChat = getChat(chat.id); + if (existChat == null || existChat.min) { + TLRPC.Chat cacheChat = MessagesStorage.getInstance().getChatSync(updates.chat_id); + if (existChat == null) { + putChat(cacheChat, true); + } + existChat = cacheChat; + } + if (existChat == null || existChat.min) { + if (minChannels == null) { + minChannels = new HashMap<>(); + } + minChannels.put(chat.id, chat); + } + } + } + if (minChannels != null) { + for (int a = 0; a < updates.updates.size(); a++) { + TLRPC.Update update = updates.updates.get(a); + if (update instanceof TLRPC.TL_updateNewChannelMessage) { + int channelId = ((TLRPC.TL_updateNewChannelMessage) update).message.to_id.channel_id; + if (minChannels.containsKey(channelId)) { + FileLog.e("tmessages", "need get diff because of min channel " + channelId); + needGetDiff = true; + break; + } + } + } + } + if (!needGetDiff) { + MessagesStorage.getInstance().putUsersAndChats(updates.users, updates.chats, true, true); + Collections.sort(updates.updates, new Comparator() { + @Override + public int compare(TLRPC.Update lhs, TLRPC.Update rhs) { + int ltype = getUpdateType(lhs); + int rtype = getUpdateType(rhs); + if (ltype != rtype) { + return AndroidUtilities.compare(ltype, rtype); + } else if (ltype == 0 || ltype == 2) { + return AndroidUtilities.compare(lhs.pts, rhs.pts); + } else if (ltype == 1) { + return AndroidUtilities.compare(lhs.qts, rhs.qts); + } + return 0; + } + }); + for (int a = 0; a < updates.updates.size(); a++) { + TLRPC.Update update = updates.updates.get(a); + if (getUpdateType(update) == 0) { + TLRPC.TL_updates updatesNew = new TLRPC.TL_updates(); + updatesNew.updates.add(update); + updatesNew.pts = update.pts; + updatesNew.pts_count = update.pts_count; + for (int b = a + 1; b < updates.updates.size(); b++) { + TLRPC.Update update2 = updates.updates.get(b); + if (getUpdateType(update2) == 0 && updatesNew.pts + update2.pts_count == update2.pts) { + updatesNew.updates.add(update2); + updatesNew.pts = update2.pts; + updatesNew.pts_count += update2.pts_count; + updates.updates.remove(b); + b--; + } else { + break; + } + } + if (MessagesStorage.lastPtsValue + updatesNew.pts_count == updatesNew.pts) { + if (!processUpdateArray(updatesNew.updates, updates.users, updates.chats)) { + FileLog.e("tmessages", "need get diff inner TL_updates, seq: " + MessagesStorage.lastSeqValue + " " + updates.seq); + needGetDiff = true; + } else { + MessagesStorage.lastPtsValue = updatesNew.pts; + } + } else if (MessagesStorage.lastPtsValue != updatesNew.pts) { + FileLog.e("tmessages", update + " need get diff, pts: " + MessagesStorage.lastPtsValue + " " + updatesNew.pts + " count = " + updatesNew.pts_count); + if (gettingDifference || updatesStartWaitTimePts == 0 || updatesStartWaitTimePts != 0 && Math.abs(System.currentTimeMillis() - updatesStartWaitTimePts) <= 1500) { + if (updatesStartWaitTimePts == 0) { + updatesStartWaitTimePts = System.currentTimeMillis(); + } + FileLog.e("tmessages", "add to queue"); + updatesQueuePts.add(updatesNew); + } else { + needGetDiff = true; + } + } + } else if (getUpdateType(update) == 1) { + TLRPC.TL_updates updatesNew = new TLRPC.TL_updates(); + updatesNew.updates.add(update); + updatesNew.pts = update.qts; + for (int b = a + 1; b < updates.updates.size(); b++) { + TLRPC.Update update2 = updates.updates.get(b); + if (getUpdateType(update2) == 1 && updatesNew.pts + 1 == update2.qts) { + updatesNew.updates.add(update2); + updatesNew.pts = update2.qts; + updates.updates.remove(b); + b--; + } else { + break; + } + } + if (MessagesStorage.lastQtsValue == 0 || MessagesStorage.lastQtsValue + updatesNew.updates.size() == updatesNew.pts) { + processUpdateArray(updatesNew.updates, updates.users, updates.chats); + MessagesStorage.lastQtsValue = updatesNew.pts; + needReceivedQueue = true; + } else if (MessagesStorage.lastPtsValue != updatesNew.pts) { + FileLog.e("tmessages", update + " need get diff, qts: " + MessagesStorage.lastQtsValue + " " + updatesNew.pts); + if (gettingDifference || updatesStartWaitTimeQts == 0 || updatesStartWaitTimeQts != 0 && Math.abs(System.currentTimeMillis() - updatesStartWaitTimeQts) <= 1500) { + if (updatesStartWaitTimeQts == 0) { + updatesStartWaitTimeQts = System.currentTimeMillis(); + } + FileLog.e("tmessages", "add to queue"); + updatesQueueQts.add(updatesNew); + } else { + needGetDiff = true; + } + } + } else if (getUpdateType(update) == 2) { + int channelId; + if (update instanceof TLRPC.TL_updateNewChannelMessage) { + channelId = ((TLRPC.TL_updateNewChannelMessage) update).message.to_id.channel_id; + } else if (update instanceof TLRPC.TL_updateEditChannelMessage) { + channelId = ((TLRPC.TL_updateEditChannelMessage) update).message.to_id.channel_id; + } else { + channelId = update.channel_id; + } + Integer channelPts = channelsPts.get(channelId); + if (channelPts == null) { + channelPts = MessagesStorage.getInstance().getChannelPtsSync(channelId); + if (channelPts == 0) { + channelPts = update.pts - update.pts_count; + } + channelsPts.put(channelId, channelPts); + } + TLRPC.TL_updates updatesNew = new TLRPC.TL_updates(); + updatesNew.updates.add(update); + updatesNew.pts = update.pts; + updatesNew.pts_count = update.pts_count; + for (int b = a + 1; b < updates.updates.size(); b++) { + TLRPC.Update update2 = updates.updates.get(b); + if (getUpdateType(update2) == 2 && updatesNew.pts + update2.pts_count == update2.pts) { + updatesNew.updates.add(update2); + updatesNew.pts = update2.pts; + updatesNew.pts_count += update2.pts_count; + updates.updates.remove(b); + b--; + } else { + break; + } + } + if (channelPts + updatesNew.pts_count == updatesNew.pts) { + if (!processUpdateArray(updatesNew.updates, updates.users, updates.chats)) { + FileLog.e("tmessages", "need get channel diff inner TL_updates, channel_id = " + channelId); + if (needGetChannelsDiff == null) { + needGetChannelsDiff = new ArrayList<>(); + } else if (!needGetChannelsDiff.contains(channelId)) { + needGetChannelsDiff.add(channelId); + } + } else { + channelsPts.put(channelId, updatesNew.pts); + MessagesStorage.getInstance().saveChannelPts(channelId, updatesNew.pts); + } + } else if (channelPts != updatesNew.pts) { + FileLog.e("tmessages", update + " need get channel diff, pts: " + channelPts + " " + updatesNew.pts + " count = " + updatesNew.pts_count + " channelId = " + channelId); + Long updatesStartWaitTime = updatesStartWaitTimeChannels.get(channelId); + Boolean gettingDifferenceChannel = gettingDifferenceChannels.get(channelId); + if (gettingDifferenceChannel == null) { + gettingDifferenceChannel = false; + } + if (gettingDifferenceChannel || updatesStartWaitTime == null || Math.abs(System.currentTimeMillis() - updatesStartWaitTime) <= 1500) { + if (updatesStartWaitTime == null) { + updatesStartWaitTimeChannels.put(channelId, System.currentTimeMillis()); + } + FileLog.e("tmessages", "add to queue"); + ArrayList arrayList = updatesQueueChannels.get(channelId); + if (arrayList == null) { + arrayList = new ArrayList<>(); + updatesQueueChannels.put(channelId, arrayList); + } + arrayList.add(updatesNew); + } else { + if (needGetChannelsDiff == null) { + needGetChannelsDiff = new ArrayList<>(); + } else if (!needGetChannelsDiff.contains(channelId)) { + needGetChannelsDiff.add(channelId); + } + } + } + } else { + break; + } + updates.updates.remove(a); + a--; + } + + boolean processUpdate; + if (updates instanceof TLRPC.TL_updatesCombined) { + processUpdate = MessagesStorage.lastSeqValue + 1 == updates.seq_start || MessagesStorage.lastSeqValue == updates.seq_start; + } else { + processUpdate = MessagesStorage.lastSeqValue + 1 == updates.seq || updates.seq == 0 || updates.seq == MessagesStorage.lastSeqValue; + } + if (processUpdate) { + processUpdateArray(updates.updates, updates.users, updates.chats); + if (updates.date != 0) { + MessagesStorage.lastDateValue = updates.date; + } + if (updates.seq != 0) { + MessagesStorage.lastSeqValue = updates.seq; + } + } else { + if (updates instanceof TLRPC.TL_updatesCombined) { + FileLog.e("tmessages", "need get diff TL_updatesCombined, seq: " + MessagesStorage.lastSeqValue + " " + updates.seq_start); + } else { + FileLog.e("tmessages", "need get diff TL_updates, seq: " + MessagesStorage.lastSeqValue + " " + updates.seq); + } + + if (gettingDifference || updatesStartWaitTimeSeq == 0 || Math.abs(System.currentTimeMillis() - updatesStartWaitTimeSeq) <= 1500) { + if (updatesStartWaitTimeSeq == 0) { + updatesStartWaitTimeSeq = System.currentTimeMillis(); + } + FileLog.e("tmessages", "add TL_updates/Combined to queue"); + updatesQueueSeq.add(updates); + } else { + needGetDiff = true; + } + } + } + } else if (updates instanceof TLRPC.TL_updatesTooLong) { + FileLog.e("tmessages", "need get diff TL_updatesTooLong"); + needGetDiff = true; + } else if (updates instanceof UserActionUpdatesSeq) { + MessagesStorage.lastSeqValue = updates.seq; + } else if (updates instanceof UserActionUpdatesPts) { + if (updates.chat_id != 0) { + channelsPts.put(updates.chat_id, updates.pts); + MessagesStorage.getInstance().saveChannelPts(updates.chat_id, updates.pts); + } else { + MessagesStorage.lastPtsValue = updates.pts; + } + } + SecretChatHelper.getInstance().processPendingEncMessages(); + if (!fromQueue) { + ArrayList keys = new ArrayList<>(updatesQueueChannels.keySet()); + for (int a = 0; a < keys.size(); a++) { + Integer key = keys.get(a); + if (needGetChannelsDiff != null && needGetChannelsDiff.contains(key)) { + getChannelDifference(key); + } else { + processChannelsUpdatesQueue(key, 0); + } + } + if (needGetDiff) { + getDifference(); + } else { + for (int a = 0; a < 3; a++) { + processUpdatesQueue(a, 0); + } + } + } + if (needReceivedQueue) { + TLRPC.TL_messages_receivedQueue req = new TLRPC.TL_messages_receivedQueue(); + req.max_qts = MessagesStorage.lastQtsValue; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }); + } + if (updateStatus) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, UPDATE_MASK_STATUS); + } + }); + } + MessagesStorage.getInstance().saveDiffParams(MessagesStorage.lastSeqValue, MessagesStorage.lastPtsValue, MessagesStorage.lastDateValue, MessagesStorage.lastQtsValue); + } + + public boolean processUpdateArray(ArrayList updates, final ArrayList usersArr, final ArrayList chatsArr) { + if (updates.isEmpty()) { + if (usersArr != null || chatsArr != null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + putUsers(usersArr, false); + putChats(chatsArr, false); + } + }); + } + return true; + } + long currentTime = System.currentTimeMillis(); + + final HashMap> messages = new HashMap<>(); + final HashMap webPages = new HashMap<>(); + final ArrayList pushMessages = new ArrayList<>(); + final ArrayList messagesArr = new ArrayList<>(); + final HashMap> editingMessages = new HashMap<>(); + final SparseArray channelViews = new SparseArray<>(); + final SparseArray> channelsGroups = new SparseArray<>(); + final SparseArray markAsReadMessagesInbox = new SparseArray<>(); + final SparseIntArray markAsReadMessagesOutbox = new SparseIntArray(); + final ArrayList markAsReadMessages = new ArrayList<>(); + final HashMap markAsReadEncrypted = new HashMap<>(); + final SparseArray> deletedMessages = new SparseArray<>(); + boolean printChanged = false; + final ArrayList chatInfoToUpdate = new ArrayList<>(); + final ArrayList updatesOnMainThread = new ArrayList<>(); + final ArrayList tasks = new ArrayList<>(); + final ArrayList contactsIds = new ArrayList<>(); + + boolean checkForUsers = true; + ConcurrentHashMap usersDict; + ConcurrentHashMap chatsDict; + if (usersArr != null) { + usersDict = new ConcurrentHashMap<>(); + for (int a = 0; a < usersArr.size(); a++) { + TLRPC.User user = usersArr.get(a); + usersDict.put(user.id, user); + } + } else { + checkForUsers = false; + usersDict = users; + } + if (chatsArr != null) { + chatsDict = new ConcurrentHashMap<>(); + for (int a = 0; a < chatsArr.size(); a++) { + TLRPC.Chat chat = chatsArr.get(a); + chatsDict.put(chat.id, chat); + } + } else { + checkForUsers = false; + chatsDict = chats; + } + + if (usersArr != null || chatsArr != null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + putUsers(usersArr, false); + putChats(chatsArr, false); + } + }); + } + + int interfaceUpdateMask = 0; + + for (int c = 0; c < updates.size(); c++) { + TLRPC.Update update = updates.get(c); + if (update instanceof TLRPC.TL_updateNewMessage || update instanceof TLRPC.TL_updateNewChannelMessage) { + TLRPC.Message message; + if (update instanceof TLRPC.TL_updateNewMessage) { + message = ((TLRPC.TL_updateNewMessage) update).message; + } else { + message = ((TLRPC.TL_updateNewChannelMessage) update).message; + if (!message.out && message.from_id == UserConfig.getClientUserId()) { //TODO remove later + message.out = true; + } + } + TLRPC.Chat chat = null; + if (checkForUsers) { + int chat_id = 0; + int user_id = 0; + if (message.to_id.channel_id != 0) { + chat_id = message.to_id.channel_id; + } else if (message.to_id.chat_id != 0) { + chat_id = message.to_id.chat_id; + } else if (message.to_id.user_id != 0) { + user_id = message.to_id.user_id; + } + if (chat_id != 0) { + chat = chatsDict.get(chat_id); + if (chat == null) { + chat = getChat(chat_id); + } + if (chat == null) { + chat = MessagesStorage.getInstance().getChatSync(chat_id); + putChat(chat, true); + } + if (chat == null) { + return false; + } + if (chat.megagroup) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + } + + for (int a = 0; a < 3; a++) { + if (a != 0) { + user_id = a == 1 ? message.from_id : (message.fwd_from != null ? message.fwd_from.from_id : 0); + } + if (user_id > 0) { + TLRPC.User user = usersDict.get(user_id); + if (user == null || user.min) { + user = getUser(user_id); + } + if (user == null || user.min) { + user = MessagesStorage.getInstance().getUserSync(user_id); + if (user != null && user.min) { + user = null; + } + putUser(user, true); + } + if (user == null) { + return false; + } + if (a == 1 && user.status != null && user.status.expires <= 0) { + onlinePrivacy.put(user_id, ConnectionsManager.getInstance().getCurrentTime()); + interfaceUpdateMask |= UPDATE_MASK_STATUS; + } + } + } + } + if (message.action instanceof TLRPC.TL_messageActionChatDeleteUser) { + //plus + if(hideLeftGroup && message.action.user_id == message.from_id){ + continue; + }// + TLRPC.User user = usersDict.get(message.action.user_id); + if (user != null && user.bot) { + message.reply_markup = new TLRPC.TL_replyKeyboardHide(); + } else if (message.from_id == UserConfig.getClientUserId() && message.action.user_id == UserConfig.getClientUserId()) { + continue; + } + } else if (message.action instanceof TLRPC.TL_messageActionChatMigrateTo || message.action instanceof TLRPC.TL_messageActionChannelCreate) { + message.unread = false; + message.media_unread = false; + } + if (update instanceof TLRPC.TL_updateNewChannelMessage) { + if (message.to_id.channel_id != 0 && !message.out) { + message.unread = true; + if (message.post || (message.flags & TLRPC.MESSAGE_FLAG_MEGAGROUP) != 0) { + message.media_unread = true; + } + } + + long dialog_id = -update.channel_id; + Integer value = dialogs_read_inbox_max.get(dialog_id); + if (value == null) { + value = MessagesStorage.getInstance().getChannelReadInboxMax(update.channel_id); + } + if (value >= message.id || ChatObject.isNotInChat(chat)) { + message.unread = false; + message.media_unread = false; + } + } + messagesArr.add(message); + ImageLoader.saveMessageThumbs(message); + if (message.to_id.chat_id != 0) { + message.dialog_id = -message.to_id.chat_id; + } else if (message.to_id.channel_id != 0) { + message.dialog_id = -message.to_id.channel_id; + } else { + if (message.to_id.user_id == UserConfig.getClientUserId()) { + message.to_id.user_id = message.from_id; + } + message.dialog_id = message.to_id.user_id; + } + MessageObject obj = new MessageObject(message, usersDict, chatsDict, createdDialogIds.contains(message.dialog_id)); + if (obj.type == 11) { + interfaceUpdateMask |= UPDATE_MASK_CHAT_AVATAR; + } else if (obj.type == 10) { + interfaceUpdateMask |= UPDATE_MASK_CHAT_NAME; + } + ArrayList arr = messages.get(message.dialog_id); + if (arr == null) { + arr = new ArrayList<>(); + messages.put(message.dialog_id, arr); + } + arr.add(obj); + if (!obj.isOut() && (obj.isUnread() && message.to_id.channel_id == 0 || obj.isContentUnread())) { + pushMessages.add(obj); + } + } else if (update instanceof TLRPC.TL_updateReadMessagesContents) { + for (int a = 0; a < update.messages.size(); a++) { + long id = update.messages.get(a); + markAsReadMessages.add(id); + } + } else if (update instanceof TLRPC.TL_updateReadHistoryInbox) { + TLRPC.Peer peer = ((TLRPC.TL_updateReadHistoryInbox) update).peer; + if (peer.chat_id != 0) { + markAsReadMessagesInbox.put(-peer.chat_id, (long) update.max_id); + } else { + markAsReadMessagesInbox.put(peer.user_id, (long) update.max_id); + } + } else if (update instanceof TLRPC.TL_updateReadHistoryOutbox) { + TLRPC.Peer peer = ((TLRPC.TL_updateReadHistoryOutbox) update).peer; + if (peer.chat_id != 0) { + markAsReadMessagesOutbox.put(-peer.chat_id, update.max_id); + } else { + markAsReadMessagesOutbox.put(peer.user_id, update.max_id); + } + } else if (update instanceof TLRPC.TL_updateDeleteMessages) { + ArrayList arrayList = deletedMessages.get(0); + if (arrayList == null) { + arrayList = new ArrayList<>(); + deletedMessages.put(0, arrayList); + } + arrayList.addAll(update.messages); + } else if (update instanceof TLRPC.TL_updateUserTyping || update instanceof TLRPC.TL_updateChatUserTyping) { + if (update.user_id != UserConfig.getClientUserId()) { + long uid = -update.chat_id; + if (uid == 0) { + uid = update.user_id; + } + ArrayList arr = printingUsers.get(uid); + if (update.action instanceof TLRPC.TL_sendMessageCancelAction) { + if (arr != null) { + for (int a = 0; a < arr.size(); a++) { + PrintingUser pu = arr.get(a); + if (pu.userId == update.user_id) { + arr.remove(a); + printChanged = true; + break; + } + } + if (arr.isEmpty()) { + printingUsers.remove(uid); + } + } + } else { + if (arr == null) { + arr = new ArrayList<>(); + printingUsers.put(uid, arr); + } + boolean exist = false; + for (PrintingUser u : arr) { + if (u.userId == update.user_id) { + exist = true; + u.lastTime = currentTime; + if (u.action.getClass() != update.action.getClass()) { + printChanged = true; + } + u.action = update.action; + break; + } + } + if (!exist) { + PrintingUser newUser = new PrintingUser(); + newUser.userId = update.user_id; + newUser.lastTime = currentTime; + newUser.action = update.action; + arr.add(newUser); + printChanged = true; + } + } + onlinePrivacy.put(update.user_id, ConnectionsManager.getInstance().getCurrentTime()); + } + } else if (update instanceof TLRPC.TL_updateChatParticipants) { + interfaceUpdateMask |= UPDATE_MASK_CHAT_MEMBERS; + chatInfoToUpdate.add(update.participants); + } else if (update instanceof TLRPC.TL_updateUserStatus) { + interfaceUpdateMask |= UPDATE_MASK_STATUS; + updatesOnMainThread.add(update); + } else if (update instanceof TLRPC.TL_updateUserName) { + interfaceUpdateMask |= UPDATE_MASK_NAME; + updatesOnMainThread.add(update); + } else if (update instanceof TLRPC.TL_updateUserPhoto) { + interfaceUpdateMask |= UPDATE_MASK_AVATAR; + MessagesStorage.getInstance().clearUserPhotos(update.user_id); + updatesOnMainThread.add(update); + } else if (update instanceof TLRPC.TL_updateUserPhone) { + interfaceUpdateMask |= UPDATE_MASK_PHONE; + updatesOnMainThread.add(update); + } else if (update instanceof TLRPC.TL_updateContactRegistered) { + if (enableJoined && usersDict.containsKey(update.user_id) && !MessagesStorage.getInstance().isDialogHasMessages(update.user_id)) { + TLRPC.TL_messageService newMessage = new TLRPC.TL_messageService(); + newMessage.action = new TLRPC.TL_messageActionUserJoined(); + newMessage.local_id = newMessage.id = UserConfig.getNewMessageId(); + UserConfig.saveConfig(false); + newMessage.unread = false; + newMessage.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + newMessage.date = update.date; + newMessage.from_id = update.user_id; + newMessage.to_id = new TLRPC.TL_peerUser(); + newMessage.to_id.user_id = UserConfig.getClientUserId(); + newMessage.dialog_id = update.user_id; + + messagesArr.add(newMessage); + MessageObject obj = new MessageObject(newMessage, usersDict, chatsDict, createdDialogIds.contains(newMessage.dialog_id)); + ArrayList arr = messages.get(newMessage.dialog_id); + if (arr == null) { + arr = new ArrayList<>(); + messages.put(newMessage.dialog_id, arr); + } + arr.add(obj); + } + } else if (update instanceof TLRPC.TL_updateContactLink) { + if (update.my_link instanceof TLRPC.TL_contactLinkContact) { + int idx = contactsIds.indexOf(-update.user_id); + if (idx != -1) { + contactsIds.remove(idx); + } + if (!contactsIds.contains(update.user_id)) { + contactsIds.add(update.user_id); + } + } else { + int idx = contactsIds.indexOf(update.user_id); + if (idx != -1) { + contactsIds.remove(idx); + } + if (!contactsIds.contains(update.user_id)) { + contactsIds.add(-update.user_id); + } + } + } else if (update instanceof TLRPC.TL_updateNewAuthorization) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.newSessionReceived); + } + }); + TLRPC.TL_messageService newMessage = new TLRPC.TL_messageService(); + newMessage.action = new TLRPC.TL_messageActionLoginUnknownLocation(); + newMessage.action.title = update.device; + newMessage.action.address = update.location; + newMessage.local_id = newMessage.id = UserConfig.getNewMessageId(); + UserConfig.saveConfig(false); + newMessage.unread = true; + newMessage.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + newMessage.date = update.date; + newMessage.from_id = 777000; + newMessage.to_id = new TLRPC.TL_peerUser(); + newMessage.to_id.user_id = UserConfig.getClientUserId(); + newMessage.dialog_id = 777000; + + messagesArr.add(newMessage); + MessageObject obj = new MessageObject(newMessage, usersDict, chatsDict, createdDialogIds.contains(newMessage.dialog_id)); + ArrayList arr = messages.get(newMessage.dialog_id); + if (arr == null) { + arr = new ArrayList<>(); + messages.put(newMessage.dialog_id, arr); + } + arr.add(obj); + pushMessages.add(obj); + } else if (update instanceof TLRPC.TL_updateNewGeoChatMessage) { + //DEPRECATED + } else if (update instanceof TLRPC.TL_updateNewEncryptedMessage) { + ArrayList decryptedMessages = SecretChatHelper.getInstance().decryptMessage(((TLRPC.TL_updateNewEncryptedMessage) update).message); + if (decryptedMessages != null && !decryptedMessages.isEmpty()) { + int cid = ((TLRPC.TL_updateNewEncryptedMessage) update).message.chat_id; + long uid = ((long) cid) << 32; + ArrayList arr = messages.get(uid); + if (arr == null) { + arr = new ArrayList<>(); + messages.put(uid, arr); + } + for (int a = 0; a < decryptedMessages.size(); a++) { + TLRPC.Message message = decryptedMessages.get(a); + ImageLoader.saveMessageThumbs(message); + messagesArr.add(message); + MessageObject obj = new MessageObject(message, usersDict, chatsDict, createdDialogIds.contains(uid)); + arr.add(obj); + pushMessages.add(obj); + } + } + } else if (update instanceof TLRPC.TL_updateEncryptedChatTyping) { + TLRPC.EncryptedChat encryptedChat = getEncryptedChatDB(update.chat_id); + if (encryptedChat != null) { + update.user_id = encryptedChat.user_id; + long uid = ((long) update.chat_id) << 32; + ArrayList arr = printingUsers.get(uid); + if (arr == null) { + arr = new ArrayList<>(); + printingUsers.put(uid, arr); + } + boolean exist = false; + for (PrintingUser u : arr) { + if (u.userId == update.user_id) { + exist = true; + u.lastTime = currentTime; + u.action = new TLRPC.TL_sendMessageTypingAction(); + break; + } + } + if (!exist) { + PrintingUser newUser = new PrintingUser(); + newUser.userId = update.user_id; + newUser.lastTime = currentTime; + newUser.action = new TLRPC.TL_sendMessageTypingAction(); + arr.add(newUser); + printChanged = true; + } + onlinePrivacy.put(update.user_id, ConnectionsManager.getInstance().getCurrentTime()); + } + } else if (update instanceof TLRPC.TL_updateEncryptedMessagesRead) { + markAsReadEncrypted.put(update.chat_id, Math.max(update.max_date, update.date)); + tasks.add((TLRPC.TL_updateEncryptedMessagesRead) update); + } else if (update instanceof TLRPC.TL_updateChatParticipantAdd) { + MessagesStorage.getInstance().updateChatInfo(update.chat_id, update.user_id, 0, update.inviter_id, update.version); + } else if (update instanceof TLRPC.TL_updateChatParticipantDelete) { + MessagesStorage.getInstance().updateChatInfo(update.chat_id, update.user_id, 1, 0, update.version); + } else if (update instanceof TLRPC.TL_updateDcOptions) { + ConnectionsManager.getInstance().updateDcSettings(); + } else if (update instanceof TLRPC.TL_updateEncryption) { + SecretChatHelper.getInstance().processUpdateEncryption((TLRPC.TL_updateEncryption) update, usersDict); + } else if (update instanceof TLRPC.TL_updateUserBlocked) { + final TLRPC.TL_updateUserBlocked finalUpdate = (TLRPC.TL_updateUserBlocked) update; + if (finalUpdate.blocked) { + ArrayList ids = new ArrayList<>(); + ids.add(finalUpdate.user_id); + MessagesStorage.getInstance().putBlockedUsers(ids, false); + } else { + MessagesStorage.getInstance().deleteBlockedUser(finalUpdate.user_id); + } + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (finalUpdate.blocked) { + if (!blockedUsers.contains(finalUpdate.user_id)) { + blockedUsers.add(finalUpdate.user_id); + } + } else { + blockedUsers.remove((Integer) finalUpdate.user_id); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.blockedUsersDidLoaded); + } + }); + } + }); + } else if (update instanceof TLRPC.TL_updateNotifySettings) { + updatesOnMainThread.add(update); + } else if (update instanceof TLRPC.TL_updateServiceNotification) { + TLRPC.TL_updateServiceNotification notification = (TLRPC.TL_updateServiceNotification) update; + if (notification.popup && notification.message != null && notification.message.length() > 0) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.needShowAlert, 2, notification.message); + } + TLRPC.TL_message newMessage = new TLRPC.TL_message(); + newMessage.local_id = newMessage.id = UserConfig.getNewMessageId(); + UserConfig.saveConfig(false); + newMessage.unread = true; + newMessage.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + newMessage.date = ConnectionsManager.getInstance().getCurrentTime(); + newMessage.from_id = 777000; + newMessage.to_id = new TLRPC.TL_peerUser(); + newMessage.to_id.user_id = UserConfig.getClientUserId(); + newMessage.dialog_id = 777000; + newMessage.media = update.media; + newMessage.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; + newMessage.message = notification.message; + + messagesArr.add(newMessage); + MessageObject obj = new MessageObject(newMessage, usersDict, chatsDict, createdDialogIds.contains(newMessage.dialog_id)); + ArrayList arr = messages.get(newMessage.dialog_id); + if (arr == null) { + arr = new ArrayList<>(); + messages.put(newMessage.dialog_id, arr); + } + arr.add(obj); + pushMessages.add(obj); + } else if (update instanceof TLRPC.TL_updatePrivacy) { + updatesOnMainThread.add(update); + } else if (update instanceof TLRPC.TL_updateWebPage) { + webPages.put(update.webpage.id, update.webpage); + } else if (update instanceof TLRPC.TL_updateChannelTooLong) { + if ((update.flags & 1) != 0) { + Integer channelPts = channelsPts.get(update.channel_id); + if (channelPts == null) { + channelPts = MessagesStorage.getInstance().getChannelPtsSync(update.channel_id); + if (channelPts == 0) { + channelPts = 1; + } + channelsPts.put(update.channel_id, channelPts); + } + if (update.pts > channelPts) { + getChannelDifference(update.channel_id); + } + } else { + getChannelDifference(update.channel_id); + } + } else if (update instanceof TLRPC.TL_updateChannelGroup) { + ArrayList arrayList = channelsGroups.get(update.channel_id); + if (arrayList == null) { + arrayList = new ArrayList<>(); + channelsGroups.put(update.channel_id, arrayList); + } + arrayList.add(update.group); + } else if (update instanceof TLRPC.TL_updateReadChannelInbox) { + long message_id = update.max_id; + message_id |= ((long) update.channel_id) << 32; + markAsReadMessagesInbox.put(-update.channel_id, message_id); + + long dialog_id = -update.channel_id; + Integer value = dialogs_read_inbox_max.get(dialog_id); + if (value == null) { + value = MessagesStorage.getInstance().getChannelReadInboxMax(update.channel_id); + } + dialogs_read_inbox_max.put(dialog_id, Math.max(value, update.max_id)); + } else if (update instanceof TLRPC.TL_updateDeleteChannelMessages) { + ArrayList arrayList = deletedMessages.get(update.channel_id); + if (arrayList == null) { + arrayList = new ArrayList<>(); + deletedMessages.put(update.channel_id, arrayList); + } + arrayList.addAll(update.messages); + } else if (update instanceof TLRPC.TL_updateChannel) { + updatesOnMainThread.add(update); + } else if (update instanceof TLRPC.TL_updateChannelMessageViews) { + TLRPC.TL_updateChannelMessageViews updateChannelMessageViews = (TLRPC.TL_updateChannelMessageViews) update; + SparseIntArray array = channelViews.get(update.channel_id); + if (array == null) { + array = new SparseIntArray(); + channelViews.put(update.channel_id, array); + } + array.put(updateChannelMessageViews.id, update.views); + } else if (update instanceof TLRPC.TL_updateChatParticipantAdmin) { + MessagesStorage.getInstance().updateChatInfo(update.chat_id, update.user_id, 2, update.is_admin ? 1 : 0, update.version); + } else if (update instanceof TLRPC.TL_updateChatAdmins) { + updatesOnMainThread.add(update); + } else if (update instanceof TLRPC.TL_updateStickerSets) { + updatesOnMainThread.add(update); + } else if (update instanceof TLRPC.TL_updateStickerSetsOrder) { + updatesOnMainThread.add(update); + } else if (update instanceof TLRPC.TL_updateNewStickerSet) { + updatesOnMainThread.add(update); + } else if (update instanceof TLRPC.TL_updateSavedGifs) { + updatesOnMainThread.add(update); + } else if (update instanceof TLRPC.TL_updateEditChannelMessage || update instanceof TLRPC.TL_updateEditMessage) { + TLRPC.Message message; + if (update instanceof TLRPC.TL_updateEditChannelMessage) { + message = ((TLRPC.TL_updateEditChannelMessage) update).message; + } else { + message = ((TLRPC.TL_updateEditMessage) update).message; + } + if (message.to_id.channel_id != 0 && !message.out) { + message.unread = true; + if (message.post || (message.flags & TLRPC.MESSAGE_FLAG_MEGAGROUP) != 0) { + message.media_unread = true; + } + } + + if (update instanceof TLRPC.TL_updateEditChannelMessage) { + long dialog_id = -update.channel_id; + Integer value = dialogs_read_inbox_max.get(dialog_id); + if (value == null) { + value = MessagesStorage.getInstance().getChannelReadInboxMax(update.channel_id); + } + if (value >= message.id) { + message.unread = false; + message.media_unread = false; + } //TODO unread for updateEditMessage? + } + + ImageLoader.saveMessageThumbs(message); + + if (message.to_id.chat_id != 0) { + message.dialog_id = -message.to_id.chat_id; + } else if (message.to_id.channel_id != 0) { + message.dialog_id = -message.to_id.channel_id; + } else { + if (message.to_id.user_id == UserConfig.getClientUserId()) { + message.to_id.user_id = message.from_id; + } + message.dialog_id = message.to_id.user_id; + } + MessageObject obj = new MessageObject(message, usersDict, chatsDict, createdDialogIds.contains(message.dialog_id)); + + ArrayList arr = editingMessages.get(message.dialog_id); + if (arr == null) { + arr = new ArrayList<>(); + editingMessages.put(message.dialog_id, arr); + } + arr.add(obj); + } else if (update instanceof TLRPC.TL_updateChannelPinnedMessage) { + TLRPC.TL_updateChannelPinnedMessage updateChannelPinnedMessage = (TLRPC.TL_updateChannelPinnedMessage) update; + MessagesStorage.getInstance().updateChannelPinnedMessage(update.channel_id, updateChannelPinnedMessage.id); + } + } + if (!messages.isEmpty()) { + for (HashMap.Entry> pair : messages.entrySet()) { + Long key = pair.getKey(); + ArrayList value = pair.getValue(); + if (updatePrintingUsersWithNewMessages(key, value)) { + printChanged = true; + } + } + } + + if (printChanged) { + updatePrintingStrings(); + } + + final int interfaceUpdateMaskFinal = interfaceUpdateMask; + final boolean printChangedArg = printChanged; + + if (!contactsIds.isEmpty()) { + ContactsController.getInstance().processContactsUpdates(contactsIds, usersDict); + } + + if (!pushMessages.isEmpty()) { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationsController.getInstance().processNewMessages(pushMessages, true); + } + }); + } + }); + } + + if (!messagesArr.isEmpty()) { + MessagesStorage.getInstance().putMessages(messagesArr, true, true, false, MediaController.getInstance().getAutodownloadMask()); + } + if (!editingMessages.isEmpty()) { + for (HashMap.Entry> pair : editingMessages.entrySet()) { + TLRPC.TL_messages_messages messagesRes = new TLRPC.TL_messages_messages(); + ArrayList messageObjects = pair.getValue(); + for (int a = 0; a < messageObjects.size(); a++) { + messagesRes.messages.add(messageObjects.get(a).messageOwner); + } + MessagesStorage.getInstance().putMessages(messagesRes, pair.getKey(), -2, 0, 0, false); + } + } + + if (channelViews.size() != 0) { + MessagesStorage.getInstance().putChannelViews(channelViews, true); + } + if (channelsGroups.size() != 0) { + //MessagesStorage.getInstance().applyNewChannelsGroups(channelsGroups); + } + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + int updateMask = interfaceUpdateMaskFinal; + + if (!updatesOnMainThread.isEmpty()) { + ArrayList dbUsers = new ArrayList<>(); + ArrayList dbUsersStatus = new ArrayList<>(); + SharedPreferences.Editor editor = null; + for (int a = 0; a < updatesOnMainThread.size(); a++) { + final TLRPC.Update update = updatesOnMainThread.get(a); + final TLRPC.User toDbUser = new TLRPC.User(); + toDbUser.id = update.user_id; + final TLRPC.User currentUser = getUser(update.user_id); + if (update instanceof TLRPC.TL_updatePrivacy) { + if (update.key instanceof TLRPC.TL_privacyKeyStatusTimestamp) { + ContactsController.getInstance().setPrivacyRules(update.rules, false); + } else if (update.key instanceof TLRPC.TL_privacyKeyChatInvite) { + ContactsController.getInstance().setPrivacyRules(update.rules, true); + } + } else if (update instanceof TLRPC.TL_updateUserStatus) { + if (update.status instanceof TLRPC.TL_userStatusRecently) { + update.status.expires = -100; + } else if (update.status instanceof TLRPC.TL_userStatusLastWeek) { + update.status.expires = -101; + } else if (update.status instanceof TLRPC.TL_userStatusLastMonth) { + update.status.expires = -102; + } + if (currentUser != null) { + currentUser.id = update.user_id; + currentUser.status = update.status; + } + toDbUser.status = update.status; + dbUsersStatus.add(toDbUser); + if (update.user_id == UserConfig.getClientUserId()) { + NotificationsController.getInstance().setLastOnlineFromOtherDevice(update.status.expires); + } + } else if (update instanceof TLRPC.TL_updateUserName) { + if (currentUser != null) { + if (!UserObject.isContact(currentUser)) { + currentUser.first_name = update.first_name; + currentUser.last_name = update.last_name; + } + if (currentUser.username != null && currentUser.username.length() > 0) { + usersByUsernames.remove(currentUser.username); + } + if (update.username != null && update.username.length() > 0) { + usersByUsernames.put(update.username, currentUser); + } + currentUser.username = update.username; + } + toDbUser.first_name = update.first_name; + toDbUser.last_name = update.last_name; + toDbUser.username = update.username; + dbUsers.add(toDbUser); + } else if (update instanceof TLRPC.TL_updateUserPhoto) { + if (currentUser != null) { + currentUser.photo = update.photo; + } + toDbUser.photo = update.photo; + dbUsers.add(toDbUser); + } else if (update instanceof TLRPC.TL_updateUserPhone) { + if (currentUser != null) { + currentUser.phone = update.phone; + Utilities.phoneBookQueue.postRunnable(new Runnable() { + @Override + public void run() { + ContactsController.getInstance().addContactToPhoneBook(currentUser, true); + } + }); + } + toDbUser.phone = update.phone; + dbUsers.add(toDbUser); + } else if (update instanceof TLRPC.TL_updateNotifySettings) { + TLRPC.TL_updateNotifySettings updateNotifySettings = (TLRPC.TL_updateNotifySettings) update; + if (update.notify_settings instanceof TLRPC.TL_peerNotifySettings && updateNotifySettings.peer instanceof TLRPC.TL_notifyPeer) { + if (editor == null) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + editor = preferences.edit(); + } + long dialog_id; + if (updateNotifySettings.peer.peer.user_id != 0) { + dialog_id = updateNotifySettings.peer.peer.user_id; + } else if (updateNotifySettings.peer.peer.chat_id != 0) { + dialog_id = -updateNotifySettings.peer.peer.chat_id; + } else { + dialog_id = -updateNotifySettings.peer.peer.channel_id; + } + + TLRPC.Dialog dialog = dialogs_dict.get(dialog_id); + if (dialog != null) { + dialog.notify_settings = update.notify_settings; + } + editor.putBoolean("silent_" + dialog_id, update.notify_settings.silent); + if (update.notify_settings.mute_until > ConnectionsManager.getInstance().getCurrentTime()) { + int until = 0; + if (update.notify_settings.mute_until > ConnectionsManager.getInstance().getCurrentTime() + 60 * 60 * 24 * 365) { + editor.putInt("notify2_" + dialog_id, 2); + if (dialog != null) { + dialog.notify_settings.mute_until = Integer.MAX_VALUE; + } + } else { + until = update.notify_settings.mute_until; + editor.putInt("notify2_" + dialog_id, 3); + editor.putInt("notifyuntil_" + dialog_id, update.notify_settings.mute_until); + if (dialog != null) { + dialog.notify_settings.mute_until = until; + } + } + MessagesStorage.getInstance().setDialogFlags(dialog_id, ((long) until << 32) | 1); + NotificationsController.getInstance().removeNotificationsForDialog(dialog_id); + } else { + if (dialog != null) { + dialog.notify_settings.mute_until = 0; + } + editor.remove("notify2_" + dialog_id); + MessagesStorage.getInstance().setDialogFlags(dialog_id, 0); + } + } + } else if (update instanceof TLRPC.TL_updateChannel) { + TLRPC.Dialog dialog = dialogs_dict.get(-(long) update.channel_id); + TLRPC.Chat chat = getChat(update.channel_id); + if (dialog == null && chat instanceof TLRPC.TL_channel && !chat.left) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + getChannelDifference(update.channel_id, 1); + } + }); + } else if (chat.left && dialog != null) { + deleteDialog(dialog.id, 0); + } + updateMask |= UPDATE_MASK_CHANNEL; + loadFullChat(update.channel_id, 0, true); + } else if (update instanceof TLRPC.TL_updateChatAdmins) { + updateMask |= UPDATE_MASK_CHAT_ADMINS; + } else if (update instanceof TLRPC.TL_updateStickerSets) { + StickersQuery.loadStickers(false, true); + } else if (update instanceof TLRPC.TL_updateStickerSetsOrder) { + StickersQuery.reorderStickers(update.order); + } else if (update instanceof TLRPC.TL_updateNewStickerSet) { + StickersQuery.addNewStickerSet(update.stickerset); + } else if (update instanceof TLRPC.TL_updateSavedGifs) { + SharedPreferences.Editor editor2 = ApplicationLoader.applicationContext.getSharedPreferences("emoji", Activity.MODE_PRIVATE).edit(); + editor2.putLong("lastGifLoadTime", 0).commit(); + } + } + if (editor != null) { + editor.commit(); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.notificationsSettingsUpdated); + } + MessagesStorage.getInstance().updateUsers(dbUsersStatus, true, true, true); + MessagesStorage.getInstance().updateUsers(dbUsers, false, true, true); + } + + if (!webPages.isEmpty()) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReceivedWebpagesInUpdates, webPages); + for (HashMap.Entry entry : webPages.entrySet()) { + ArrayList arrayList = reloadingWebpagesPending.remove(entry.getKey()); + if (arrayList != null) { + TLRPC.WebPage webpage = entry.getValue(); + ArrayList messagesArr = new ArrayList<>(); + long dialog_id = 0; + if (webpage instanceof TLRPC.TL_webPage || webpage instanceof TLRPC.TL_webPageEmpty) { + for (int a = 0; a < arrayList.size(); a++) { + arrayList.get(a).messageOwner.media.webpage = webpage; + if (a == 0) { + dialog_id = arrayList.get(a).getDialogId(); + ImageLoader.saveMessageThumbs(arrayList.get(a).messageOwner); + } + messagesArr.add(arrayList.get(a).messageOwner); + } + } else { + reloadingWebpagesPending.put(webpage.id, arrayList); + } + if (!messagesArr.isEmpty()) { + MessagesStorage.getInstance().putMessages(messagesArr, true, true, false, MediaController.getInstance().getAutodownloadMask()); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, arrayList); + } + } + } + } + + boolean updateDialogs = false; + if (!editingMessages.isEmpty()) { + for (HashMap.Entry> pair : editingMessages.entrySet()) { + Long dialog_id = pair.getKey(); + ArrayList arrayList = pair.getValue(); + MessageObject oldObject = dialogMessage.get(dialog_id); + if (oldObject != null) { + for (int a = 0; a < arrayList.size(); a++) { + MessageObject newMessage = arrayList.get(a); + if (oldObject.getId() == newMessage.getId()) { + dialogMessage.put(dialog_id, newMessage); + updateDialogs = true; + break; + } + } + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.replaceMessagesObjects, dialog_id, arrayList); + } + } + if (!messages.isEmpty()) { + for (HashMap.Entry> entry : messages.entrySet()) { + Long key = entry.getKey(); + ArrayList value = entry.getValue(); + updateInterfaceWithMessages(key, value); + } + updateDialogs = true; + } + if (updateDialogs) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + } + + if (printChangedArg) { + updateMask |= UPDATE_MASK_USER_PRINT; + } + if (!contactsIds.isEmpty()) { + updateMask |= UPDATE_MASK_NAME; + updateMask |= UPDATE_MASK_USER_PHONE; + } + if (!chatInfoToUpdate.isEmpty()) { + for (int a = 0; a < chatInfoToUpdate.size(); a++) { + TLRPC.ChatParticipants info = chatInfoToUpdate.get(a); + MessagesStorage.getInstance().updateChatParticipants(info); + } + } + if (channelViews.size() != 0) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didUpdatedMessagesViews, channelViews); + } + if (updateMask != 0) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, updateMask); + } + } + }); + + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + int updateMask = 0; + if (markAsReadMessagesInbox.size() != 0 || markAsReadMessagesOutbox.size() != 0) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesRead, markAsReadMessagesInbox, markAsReadMessagesOutbox); + NotificationsController.getInstance().processReadMessages(markAsReadMessagesInbox, 0, 0, 0, false); + for (int b = 0; b < markAsReadMessagesInbox.size(); b++) { + int key = markAsReadMessagesInbox.keyAt(b); + long messageId = markAsReadMessagesInbox.get(key); + TLRPC.Dialog dialog = dialogs_dict.get((long) key); + if (dialog != null && dialog.top_message <= (int) messageId) { + MessageObject obj = dialogMessage.get(dialog.id); + if (obj != null) { + obj.setIsRead(); + updateMask |= UPDATE_MASK_READ_DIALOG_MESSAGE; + } + } + } + for (int b = 0; b < markAsReadMessagesOutbox.size(); b++) { + int key = markAsReadMessagesOutbox.keyAt(b); + int messageId = markAsReadMessagesOutbox.get(key); + TLRPC.Dialog dialog = dialogs_dict.get((long) key); + if (dialog != null && dialog.top_message <= messageId) { + MessageObject obj = dialogMessage.get(dialog.id); + if (obj != null) { + obj.setIsRead(); + updateMask |= UPDATE_MASK_READ_DIALOG_MESSAGE; + } + } + } + } + if (!markAsReadEncrypted.isEmpty()) { + for (HashMap.Entry entry : markAsReadEncrypted.entrySet()) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesReadEncrypted, entry.getKey(), entry.getValue()); + long dialog_id = (long) (entry.getKey()) << 32; + TLRPC.Dialog dialog = dialogs_dict.get(dialog_id); + if (dialog != null) { + MessageObject message = dialogMessage.get(dialog_id); + if (message != null && message.messageOwner.date <= entry.getValue()) { + message.setIsRead(); + updateMask |= UPDATE_MASK_READ_DIALOG_MESSAGE; + } + } + } + } + if (!markAsReadMessages.isEmpty()) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesReadContent, markAsReadMessages); + } + if (deletedMessages.size() != 0) { + for (int a = 0; a < deletedMessages.size(); a++) { + int key = deletedMessages.keyAt(a); + ArrayList arrayList = deletedMessages.get(key); + if (arrayList == null) { + continue; + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDeleted, arrayList, key); + if (key == 0) { + for (int b = 0; b < arrayList.size(); b++) { + Integer id = arrayList.get(b); + MessageObject obj = dialogMessagesByIds.get(id); + if (obj != null) { + obj.deleted = true; + } + } + } else { + MessageObject obj = dialogMessage.get((long) -key); + if (obj != null) { + for (int b = 0; b < arrayList.size(); b++) { + if (obj.getId() == arrayList.get(b)) { + obj.deleted = true; + break; + } + } + } + } + } + NotificationsController.getInstance().removeDeletedMessagesFromNotifications(deletedMessages); + } + if (updateMask != 0) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, updateMask); + } + } + }); + } + }); + + if (!webPages.isEmpty()) { + MessagesStorage.getInstance().putWebPages(webPages); + } + if (markAsReadMessagesInbox.size() != 0 || markAsReadMessagesOutbox.size() != 0 || !markAsReadEncrypted.isEmpty()) { + if (markAsReadMessagesInbox.size() != 0) { + MessagesStorage.getInstance().updateDialogsWithReadMessages(markAsReadMessagesInbox, true); + } + MessagesStorage.getInstance().markMessagesAsRead(markAsReadMessagesInbox, markAsReadMessagesOutbox, markAsReadEncrypted, true); + } + if (!markAsReadMessages.isEmpty()) { + MessagesStorage.getInstance().markMessagesContentAsRead(markAsReadMessages); + } + if (deletedMessages.size() != 0) { + for (int a = 0; a < deletedMessages.size(); a++) { + int key = deletedMessages.keyAt(a); + ArrayList arrayList = deletedMessages.get(key); + MessagesStorage.getInstance().markMessagesAsDeleted(arrayList, true, key); + MessagesStorage.getInstance().updateDialogsWithDeletedMessages(arrayList, true, key); + } + } + if (!tasks.isEmpty()) { + for (int a = 0; a < tasks.size(); a++) { + TLRPC.TL_updateEncryptedMessagesRead update = tasks.get(a); + MessagesStorage.getInstance().createTaskForSecretChat(update.chat_id, update.max_date, update.date, 1, null); + } + } + + return true; + } + + private boolean isNotifySettingsMuted(TLRPC.PeerNotifySettings settings) { + return settings instanceof TLRPC.TL_peerNotifySettings && settings.mute_until > ConnectionsManager.getInstance().getCurrentTime(); + } + + public boolean isDialogMuted(long dialog_id) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + int mute_type = preferences.getInt("notify2_" + dialog_id, 0); + if (mute_type == 2) { + return true; + } else if (mute_type == 3) { + int mute_until = preferences.getInt("notifyuntil_" + dialog_id, 0); + if (mute_until >= ConnectionsManager.getInstance().getCurrentTime()) { + return true; + } + } + return false; + } + + private boolean updatePrintingUsersWithNewMessages(long uid, ArrayList messages) { + if (uid > 0) { + ArrayList arr = printingUsers.get(uid); + if (arr != null) { + printingUsers.remove(uid); + return true; + } + } else if (uid < 0) { + ArrayList messagesUsers = new ArrayList<>(); + for (MessageObject message : messages) { + if (!messagesUsers.contains(message.messageOwner.from_id)) { + messagesUsers.add(message.messageOwner.from_id); + } + } + + ArrayList arr = printingUsers.get(uid); + boolean changed = false; + if (arr != null) { + for (int a = 0; a < arr.size(); a++) { + PrintingUser user = arr.get(a); + if (messagesUsers.contains(user.userId)) { + arr.remove(a); + a--; + if (arr.isEmpty()) { + printingUsers.remove(uid); + } + changed = true; + } + } + } + if (changed) { + return true; + } + } + return false; + } + + protected void updateInterfaceWithMessages(long uid, ArrayList messages) { + updateInterfaceWithMessages(uid, messages, false); + } + + protected static void addNewGifToRecent(TLRPC.Document document, int date) { + ArrayList arrayList = new ArrayList<>(); + MediaController.SearchImage searchImage = new MediaController.SearchImage(); + searchImage.type = 2; + searchImage.document = document; + searchImage.date = date; + searchImage.id = "" + searchImage.document.id; + arrayList.add(searchImage); + MessagesStorage.getInstance().putWebRecent(arrayList); + } + + protected void updateInterfaceWithMessages(final long uid, final ArrayList messages, boolean isBroadcast) { + if (messages == null || messages.isEmpty()) { + return; + } + + boolean isEncryptedChat = ((int) uid) == 0; + MessageObject lastMessage = null; + int channelId = 0; + for (int a = 0; a < messages.size(); a++) { + MessageObject message = messages.get(a); + if (lastMessage == null || (!isEncryptedChat && message.getId() > lastMessage.getId() || (isEncryptedChat || message.getId() < 0 && lastMessage.getId() < 0) && message.getId() < lastMessage.getId()) || message.messageOwner.date > lastMessage.messageOwner.date) { + if (message.messageOwner.to_id.channel_id == 0 || message.isMegagroup() || message.isImportant()) { + lastMessage = message; + } + if (message.messageOwner.to_id.channel_id != 0) { + channelId = message.messageOwner.to_id.channel_id; + } + } + if (message.isOut() && message.isNewGif() && !message.isSending() && !message.isForwarded()) { + addNewGifToRecent(message.messageOwner.media.document, message.messageOwner.date); + } + } + MessagesQuery.loadReplyMessagesForMessages(messages, uid); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReceivedNewMessages, uid, messages); + + if (lastMessage == null) { + return; + } + TLRPC.Dialog dialog = dialogs_dict.get(uid); + if (lastMessage.messageOwner.action instanceof TLRPC.TL_messageActionChatMigrateTo) { + if (dialog != null) { + dialogs.remove(dialog); + dialogsServerOnly.remove(dialog); + dialogsGroupsOnly.remove(dialog); + //plus + dialogsUsers.remove(dialog); + dialogsGroups.remove(dialog); + dialogsGroupsAll.remove(dialog); + dialogsChannels.remove(dialog); + dialogsMegaGroups.remove(dialog); + dialogsBots.remove(dialog); + dialogsFavs.remove(dialog); + // + dialogs_dict.remove(dialog.id); + dialogs_read_inbox_max.remove(dialog.id); + nextDialogsCacheOffset--; + dialogMessage.remove(dialog.id); + MessageObject object = dialogMessagesByIds.remove(dialog.top_message); + if (object != null && object.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(object.messageOwner.random_id); + } + dialog.top_message = 0; + NotificationsController.getInstance().removeNotificationsForDialog(dialog.id); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.needReloadRecentDialogsSearch); + } + return; + } + + boolean changed = false; + + if (dialog == null) { + if (!isBroadcast) { + TLRPC.Chat chat = getChat(channelId); + if (channelId != 0 && chat == null || chat != null && chat.left) { + return; + } + if (!ChatObject.isChannel(chat)) { + dialog = new TLRPC.TL_dialog(); + } else { + dialog = new TLRPC.TL_dialogChannel(); + } + dialog.id = uid; + dialog.unread_count = 0; + dialog.top_message = lastMessage.getId(); + dialog.last_message_date = lastMessage.messageOwner.date; + dialogs_dict.put(uid, dialog); + dialogs.add(dialog); + dialogMessage.put(uid, lastMessage); + if (lastMessage.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(lastMessage.getId(), lastMessage); + if (lastMessage.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(lastMessage.messageOwner.random_id, lastMessage); + } + } + nextDialogsCacheOffset++; + changed = true; + } + } else { + if ((dialog.top_message > 0 && lastMessage.getId() > 0 && lastMessage.getId() > dialog.top_message) || + (dialog.top_message < 0 && lastMessage.getId() < 0 && lastMessage.getId() < dialog.top_message) || + !dialogMessage.containsKey(uid) || dialog.top_message < 0 || dialog.last_message_date <= lastMessage.messageOwner.date) { + MessageObject object = dialogMessagesByIds.remove(dialog.top_message); + if (object != null && object.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.remove(object.messageOwner.random_id); + } + dialog.top_message = lastMessage.getId(); + if (!isBroadcast) { + dialog.last_message_date = lastMessage.messageOwner.date; + changed = true; + } + dialogMessage.put(uid, lastMessage); + if (lastMessage.messageOwner.to_id.channel_id == 0) { + dialogMessagesByIds.put(lastMessage.getId(), lastMessage); + if (lastMessage.messageOwner.random_id != 0) { + dialogMessagesByRandomIds.put(lastMessage.messageOwner.random_id, lastMessage); + } + } + } + } + + if (changed) { + dialogsServerOnly.clear(); + dialogsGroupsOnly.clear(); + //plus + dialogsUsers.clear(); + dialogsGroups.clear(); + dialogsGroupsAll.clear(); + dialogsChannels.clear(); + dialogsMegaGroups.clear(); + dialogsBots.clear(); + dialogsFavs.clear(); + // + Collections.sort(dialogs, new Comparator() { + @Override + public int compare(TLRPC.Dialog tl_dialog, TLRPC.Dialog tl_dialog2) { + if (tl_dialog.last_message_date == tl_dialog2.last_message_date) { + return 0; + } else if (tl_dialog.last_message_date < tl_dialog2.last_message_date) { + return 1; + } else { + return -1; + } + } + }); + for (int a = 0; a < dialogs.size(); a++) { + TLRPC.Dialog d = dialogs.get(a); + int high_id = (int) (d.id >> 32); + if ((int) d.id != 0 && high_id != 1) { + dialogsServerOnly.add(d); + if (d instanceof TLRPC.TL_dialog) { + if (d.id < 0) { + dialogsGroupsOnly.add(d); + //plus + dialogsGroups.add(d); + dialogsGroupsAll.add(d); + // + } + //plus + else{ + TLRPC.User user = getUser((int) d.id); + if(user != null){ + if(user.bot){ + dialogsBots.add(d); + }else{ + dialogsUsers.add(d); + } + } + } + // + } else if (d instanceof TLRPC.TL_dialogChannel) { + int lower_id = (int) d.id; + TLRPC.Chat chat = getChat(-lower_id); + if (chat != null && (chat.megagroup && chat.editor || chat.creator)) { + dialogsGroupsOnly.add(d); + } + //plus + if (chat != null) { + if (chat.megagroup) { + dialogsMegaGroups.add(d); + dialogsGroupsAll.add(d); + } else { + dialogsChannels.add(d); + } + } + // + } + } + TLRPC.EncryptedChat chat = getEncryptedChat(high_id); + if(chat instanceof TLRPC.TL_encryptedChat) { + dialogsUsers.add(d); + } + if(Favourite.isFavourite(d.id)){ + dialogsFavs.add(d); + } + } + } + } + + private static String getRestrictionReason(String reason) { + if (reason == null || reason.length() == 0) { + return null; + } + int index = reason.indexOf(": "); + if (index > 0) { + String type = reason.substring(0, index); + if (type.contains("-all") || type.contains("-android")) { + return reason.substring(index + 2); + } + } + return null; + } + + private static void showCantOpenAlert(BaseFragment fragment, String reason) { + AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + builder.setMessage(reason); + fragment.showDialog(builder.create()); + } + + public static boolean checkCanOpenChat(Bundle bundle, BaseFragment fragment) { + if (bundle == null || fragment == null) { + return true; + } + TLRPC.User user = null; + TLRPC.Chat chat = null; + int user_id = bundle.getInt("user_id", 0); + int chat_id = bundle.getInt("chat_id", 0); + if (user_id != 0) { + user = MessagesController.getInstance().getUser(user_id); + } else if (chat_id != 0) { + chat = MessagesController.getInstance().getChat(chat_id); + } + if (user == null && chat == null) { + return true; + } + String reason = null; + if (chat != null) { + reason = getRestrictionReason(chat.restriction_reason); + } else if (user != null) { + reason = getRestrictionReason(user.restriction_reason); + } + if (reason != null) { + showCantOpenAlert(fragment, reason); + return false; + } + return true; + } + + public static void openChatOrProfileWith(TLRPC.User user, TLRPC.Chat chat, BaseFragment fragment, int type) { + if (user == null && chat == null || fragment == null) { + return; + } + String reason = null; + boolean closeLast = false; + if (chat != null) { + reason = getRestrictionReason(chat.restriction_reason); + } else if (user != null) { + reason = getRestrictionReason(user.restriction_reason); + if (user.bot) { + type = 1; + closeLast = true; + } + } + if (reason != null) { + showCantOpenAlert(fragment, reason); + } else { + Bundle args = new Bundle(); + if (chat != null) { + args.putInt("chat_id", chat.id); + } else { + args.putInt("user_id", user.id); + } + if (type == 0) { + fragment.presentFragment(new ProfileActivity(args)); + } else { + fragment.presentFragment(new ChatActivity(args), closeLast); + } + } + } + + public static void openByUserName(String username, final BaseFragment fragment, final int type) { + if (username == null || fragment == null) { + return; + } + TLRPC.User user = getInstance().getUser(username); + if (user != null) { + openChatOrProfileWith(user, null, fragment, type); + } else { + if (fragment.getParentActivity() == null) { + return; + } + final ProgressDialog progressDialog = new ProgressDialog(fragment.getParentActivity()); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + + TLRPC.TL_contacts_resolveUsername req = new TLRPC.TL_contacts_resolveUsername(); + req.username = username; + final String un = username; + final int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + fragment.setVisibleDialog(null); + if (error == null) { + TLRPC.TL_contacts_resolvedPeer res = (TLRPC.TL_contacts_resolvedPeer) response; + getInstance().putUsers(res.users, false); + getInstance().putChats(res.chats, false); + MessagesStorage.getInstance().putUsersAndChats(res.users, res.chats, false, true); + if (!res.chats.isEmpty()) { + openChatOrProfileWith(null, res.chats.get(0), fragment, 1); + } else if (!res.users.isEmpty()) { + openChatOrProfileWith(res.users.get(0), null, fragment, type); + } + } else { + if (fragment != null && fragment.getParentActivity() != null) { + try { + Toast.makeText(fragment.getParentActivity(), LocaleController.getString("NoUsernameFound", R.string.NoUsernameFound), Toast.LENGTH_SHORT).show(); + //Try on twitter if user doesn't exists + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + if(preferences.getBoolean("searchOnTwitter", true)) { + try { + fragment.getParentActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("twitter://user?screen_name=" + un))); + } catch (Exception e) { + fragment.getParentActivity().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://twitter.com/" + un))); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + } + }); + } + }); + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + ConnectionsManager.getInstance().cancelRequest(reqId, true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (fragment != null) { + fragment.setVisibleDialog(null); + } + } + }); + fragment.setVisibleDialog(progressDialog); + progressDialog.show(); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java new file mode 100644 index 00000000..f2e2ac6c --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MessagesStorage.java @@ -0,0 +1,5866 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.content.Context; +import android.content.SharedPreferences; +import android.text.TextUtils; +import android.util.SparseArray; +import android.util.SparseIntArray; + +import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.SQLite.SQLiteCursor; +import org.telegram.SQLite.SQLiteDatabase; +import org.telegram.SQLite.SQLitePreparedStatement; +import org.telegram.messenger.query.BotQuery; +import org.telegram.messenger.query.MessagesQuery; +import org.telegram.messenger.query.SharedMediaQuery; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.NativeByteBuffer; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.Semaphore; + +public class MessagesStorage { + private DispatchQueue storageQueue = new DispatchQueue("storageQueue"); + private SQLiteDatabase database; + private File cacheFile; + public static int lastDateValue = 0; + public static int lastPtsValue = 0; + public static int lastQtsValue = 0; + public static int lastSeqValue = 0; + public static int lastSecretVersion = 0; + public static byte[] secretPBytes = null; + public static int secretG = 0; + + private int lastSavedSeq = 0; + private int lastSavedPts = 0; + private int lastSavedDate = 0; + private int lastSavedQts = 0; + + private static volatile MessagesStorage Instance = null; + public static MessagesStorage getInstance() { + MessagesStorage localInstance = Instance; + if (localInstance == null) { + synchronized (MessagesStorage.class) { + localInstance = Instance; + if (localInstance == null) { + Instance = localInstance = new MessagesStorage(); + } + } + } + return localInstance; + } + + public MessagesStorage() { + storageQueue.setPriority(Thread.MAX_PRIORITY); + openDatabase(); + } + + public SQLiteDatabase getDatabase() { + return database; + } + + public DispatchQueue getStorageQueue() { + return storageQueue; + } + + public void openDatabase() { + cacheFile = new File(ApplicationLoader.getFilesDirFixed(), "cache4.db"); + + boolean createTable = false; + //cacheFile.delete(); + if (!cacheFile.exists()) { + createTable = true; + } + try { + database = new SQLiteDatabase(cacheFile.getPath()); + database.executeFast("PRAGMA secure_delete = ON").stepThis().dispose(); + database.executeFast("PRAGMA temp_store = 1").stepThis().dispose(); + if (createTable) { + database.executeFast("CREATE TABLE channel_group(uid INTEGER, start INTEGER, end INTEGER, count INTEGER, PRIMARY KEY(uid, start));").stepThis().dispose(); + + database.executeFast("CREATE TABLE messages_holes(uid INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, start));").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_messages_holes ON messages_holes(uid, end);").stepThis().dispose(); + database.executeFast("CREATE TABLE messages_imp_holes(uid INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, start));").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_messages_imp_holes ON messages_imp_holes(uid, end);").stepThis().dispose(); + + database.executeFast("CREATE TABLE media_holes_v2(uid INTEGER, type INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, type, start));").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_media_holes_v2 ON media_holes_v2(uid, type, end);").stepThis().dispose(); + + database.executeFast("CREATE TABLE messages(mid INTEGER PRIMARY KEY, uid INTEGER, read_state INTEGER, send_state INTEGER, date INTEGER, data BLOB, out INTEGER, ttl INTEGER, media INTEGER, replydata BLOB, imp INTEGER)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_mid_idx_messages ON messages(uid, mid);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_messages ON messages(uid, date, mid);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_mid_idx_imp_messages ON messages(uid, mid, imp) WHERE imp = 1;").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_imp_idx_messages ON messages(uid, date, mid, imp) WHERE imp = 1;").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose(); + + database.executeFast("CREATE TABLE download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS type_date_idx_download_queue ON download_queue(type, date);").stepThis().dispose(); + + database.executeFast("CREATE TABLE user_phones_v6(uid INTEGER, phone TEXT, sphone TEXT, deleted INTEGER, PRIMARY KEY (uid, phone))").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS sphone_deleted_idx_user_phones ON user_phones_v6(sphone, deleted);").stepThis().dispose(); + + database.executeFast("CREATE TABLE dialogs(did INTEGER PRIMARY KEY, date INTEGER, unread_count INTEGER, last_mid INTEGER, inbox_max INTEGER, outbox_max INTEGER, last_mid_i INTEGER, unread_count_i INTEGER, pts INTEGER, date_i INTEGER)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_dialogs ON dialogs(date);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS last_mid_idx_dialogs ON dialogs(last_mid);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_idx_dialogs ON dialogs(unread_count);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS last_mid_i_idx_dialogs ON dialogs(last_mid_i);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_i_idx_dialogs ON dialogs(unread_count_i);").stepThis().dispose(); + + database.executeFast("CREATE TABLE randoms(random_id INTEGER, mid INTEGER, PRIMARY KEY (random_id, mid))").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_randoms ON randoms(mid);").stepThis().dispose(); + + database.executeFast("CREATE TABLE enc_tasks_v2(mid INTEGER PRIMARY KEY, date INTEGER)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_enc_tasks_v2 ON enc_tasks_v2(date);").stepThis().dispose(); + + database.executeFast("CREATE TABLE messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS seq_idx_messages_seq ON messages_seq(seq_in, seq_out);").stepThis().dispose(); + + database.executeFast("CREATE TABLE params(id INTEGER PRIMARY KEY, seq INTEGER, pts INTEGER, date INTEGER, qts INTEGER, lsv INTEGER, sg INTEGER, pbytes BLOB)").stepThis().dispose(); + database.executeFast("INSERT INTO params VALUES(1, 0, 0, 0, 0, 0, 0, NULL)").stepThis().dispose(); + + database.executeFast("CREATE TABLE media_v2(mid INTEGER PRIMARY KEY, uid INTEGER, date INTEGER, type INTEGER, data BLOB)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_mid_type_date_idx_media ON media_v2(uid, mid, type, date);").stepThis().dispose(); + + database.executeFast("CREATE TABLE bot_keyboard(uid INTEGER PRIMARY KEY, mid INTEGER, info BLOB)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS bot_keyboard_idx_mid ON bot_keyboard(mid);").stepThis().dispose(); + + database.executeFast("CREATE TABLE chat_settings_v2(uid INTEGER PRIMARY KEY, info BLOB, pinned INTEGER)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS chat_settings_pinned_idx ON chat_settings_v2(uid, pinned) WHERE pinned != 0;").stepThis().dispose(); + + database.executeFast("CREATE TABLE chat_pinned(uid INTEGER PRIMARY KEY, pinned INTEGER, data BLOB)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS chat_pinned_mid_idx ON chat_pinned(uid, pinned) WHERE pinned != 0;").stepThis().dispose(); + + database.executeFast("CREATE TABLE users_data(uid INTEGER PRIMARY KEY, about TEXT)").stepThis().dispose(); + database.executeFast("CREATE TABLE users(uid INTEGER PRIMARY KEY, name TEXT, status INTEGER, data BLOB)").stepThis().dispose(); + database.executeFast("CREATE TABLE chats(uid INTEGER PRIMARY KEY, name TEXT, data BLOB)").stepThis().dispose(); + database.executeFast("CREATE TABLE enc_chats(uid INTEGER PRIMARY KEY, user INTEGER, name TEXT, data BLOB, g BLOB, authkey BLOB, ttl INTEGER, layer INTEGER, seq_in INTEGER, seq_out INTEGER, use_count INTEGER, exchange_id INTEGER, key_date INTEGER, fprint INTEGER, fauthkey BLOB, khash BLOB)").stepThis().dispose(); + database.executeFast("CREATE TABLE channel_users_v2(did INTEGER, uid INTEGER, date INTEGER, data BLOB, PRIMARY KEY(did, uid))").stepThis().dispose(); + database.executeFast("CREATE TABLE contacts(uid INTEGER PRIMARY KEY, mutual INTEGER)").stepThis().dispose(); + database.executeFast("CREATE TABLE pending_read(uid INTEGER PRIMARY KEY, max_id INTEGER)").stepThis().dispose(); + database.executeFast("CREATE TABLE wallpapers(uid INTEGER PRIMARY KEY, data BLOB)").stepThis().dispose(); + database.executeFast("CREATE TABLE user_photos(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose(); + database.executeFast("CREATE TABLE blocked_users(uid INTEGER PRIMARY KEY)").stepThis().dispose(); + database.executeFast("CREATE TABLE dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose(); + database.executeFast("CREATE TABLE web_recent_v3(id TEXT, type INTEGER, image_url TEXT, thumb_url TEXT, local_url TEXT, width INTEGER, height INTEGER, size INTEGER, date INTEGER, document BLOB, PRIMARY KEY (id, type));").stepThis().dispose(); + database.executeFast("CREATE TABLE bot_recent(id INTEGER PRIMARY KEY, date INTEGER);").stepThis().dispose(); + database.executeFast("CREATE TABLE stickers_v2(id INTEGER PRIMARY KEY, data BLOB, date INTEGER, hash TEXT);").stepThis().dispose(); + database.executeFast("CREATE TABLE hashtag_recent_v2(id TEXT PRIMARY KEY, date INTEGER);").stepThis().dispose(); + database.executeFast("CREATE TABLE webpage_pending(id INTEGER, mid INTEGER, PRIMARY KEY (id, mid));").stepThis().dispose(); + database.executeFast("CREATE TABLE user_contacts_v6(uid INTEGER PRIMARY KEY, fname TEXT, sname TEXT)").stepThis().dispose(); + database.executeFast("CREATE TABLE sent_files_v2(uid TEXT, type INTEGER, data BLOB, PRIMARY KEY (uid, type))").stepThis().dispose(); + database.executeFast("CREATE TABLE search_recent(did INTEGER PRIMARY KEY, date INTEGER);").stepThis().dispose(); + database.executeFast("CREATE TABLE media_counts_v2(uid INTEGER, type INTEGER, count INTEGER, PRIMARY KEY(uid, type))").stepThis().dispose(); + database.executeFast("CREATE TABLE keyvalue(id TEXT PRIMARY KEY, value TEXT)").stepThis().dispose(); + database.executeFast("CREATE TABLE bot_info(uid INTEGER PRIMARY KEY, info BLOB)").stepThis().dispose(); + + //version + database.executeFast("PRAGMA user_version = 31").stepThis().dispose(); + + //database.executeFast("CREATE TABLE secret_holes(uid INTEGER, seq_in INTEGER, seq_out INTEGER, data BLOB, PRIMARY KEY (uid, seq_in, seq_out));").stepThis().dispose(); + //database.executeFast("CREATE TABLE attach_data(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose(); + } else { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT seq, pts, date, qts, lsv, sg, pbytes FROM params WHERE id = 1"); + if (cursor.next()) { + lastSeqValue = cursor.intValue(0); + lastPtsValue = cursor.intValue(1); + lastDateValue = cursor.intValue(2); + lastQtsValue = cursor.intValue(3); + lastSecretVersion = cursor.intValue(4); + secretG = cursor.intValue(5); + if (cursor.isNull(6)) { + secretPBytes = null; + } else { + secretPBytes = cursor.byteArrayValue(6); + if (secretPBytes != null && secretPBytes.length == 1) { + secretPBytes = null; + } + } + } + cursor.dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + try { + database.executeFast("CREATE TABLE IF NOT EXISTS params(id INTEGER PRIMARY KEY, seq INTEGER, pts INTEGER, date INTEGER, qts INTEGER, lsv INTEGER, sg INTEGER, pbytes BLOB)").stepThis().dispose(); + database.executeFast("INSERT INTO params VALUES(1, 0, 0, 0, 0, 0, 0, NULL)").stepThis().dispose(); + } catch (Exception e2) { + FileLog.e("tmessages", e2); + } + } + int version = database.executeInt("PRAGMA user_version"); + if (version < 31) { + updateDbToLastVersion(version); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + loadUnreadMessages(); + } + + public void updateDbToLastVersion(final int currentVersion) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + int version = currentVersion; + if (version < 4) { + database.executeFast("CREATE TABLE IF NOT EXISTS user_photos(uid INTEGER, id INTEGER, data BLOB, PRIMARY KEY (uid, id))").stepThis().dispose(); + + database.executeFast("DROP INDEX IF EXISTS read_state_out_idx_messages;").stepThis().dispose(); + database.executeFast("DROP INDEX IF EXISTS ttl_idx_messages;").stepThis().dispose(); + database.executeFast("DROP INDEX IF EXISTS date_idx_messages;").stepThis().dispose(); + + database.executeFast("CREATE INDEX IF NOT EXISTS mid_out_idx_messages ON messages(mid, out);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS task_idx_messages ON messages(uid, out, read_state, ttl, date, send_state);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_idx_messages ON messages(uid, date, mid);").stepThis().dispose(); + + database.executeFast("CREATE TABLE IF NOT EXISTS user_contacts_v6(uid INTEGER PRIMARY KEY, fname TEXT, sname TEXT)").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS user_phones_v6(uid INTEGER, phone TEXT, sphone TEXT, deleted INTEGER, PRIMARY KEY (uid, phone))").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS sphone_deleted_idx_user_phones ON user_phones_v6(sphone, deleted);").stepThis().dispose(); + + database.executeFast("CREATE INDEX IF NOT EXISTS mid_idx_randoms ON randoms(mid);").stepThis().dispose(); + + database.executeFast("CREATE TABLE IF NOT EXISTS sent_files_v2(uid TEXT, type INTEGER, data BLOB, PRIMARY KEY (uid, type))").stepThis().dispose(); + + database.executeFast("CREATE TABLE IF NOT EXISTS blocked_users(uid INTEGER PRIMARY KEY)").stepThis().dispose(); + + database.executeFast("CREATE TABLE IF NOT EXISTS download_queue(uid INTEGER, type INTEGER, date INTEGER, data BLOB, PRIMARY KEY (uid, type));").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS type_date_idx_download_queue ON download_queue(type, date);").stepThis().dispose(); + + database.executeFast("CREATE TABLE IF NOT EXISTS dialog_settings(did INTEGER PRIMARY KEY, flags INTEGER);").stepThis().dispose(); + + database.executeFast("CREATE INDEX IF NOT EXISTS send_state_idx_messages ON messages(mid, send_state, date) WHERE mid < 0 AND send_state = 1;").stepThis().dispose(); + + database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_idx_dialogs ON dialogs(unread_count);").stepThis().dispose(); + + database.executeFast("UPDATE messages SET send_state = 2 WHERE mid < 0 AND send_state = 1").stepThis().dispose(); + + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + ArrayList ids = new ArrayList<>(); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); + Map values = preferences.getAll(); + for (Map.Entry entry : values.entrySet()) { + String key = entry.getKey(); + if (key.startsWith("notify2_")) { + Integer value = (Integer) entry.getValue(); + if (value == 2) { + key = key.replace("notify2_", ""); + try { + ids.add(Integer.parseInt(key)); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + try { + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO dialog_settings VALUES(?, ?)"); + for (Integer id : ids) { + state.requery(); + state.bindLong(1, id); + state.bindInteger(2, 1); + state.step(); + } + state.dispose(); + database.commitTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + database.executeFast("PRAGMA user_version = 4").stepThis().dispose(); + version = 4; + } + if (version == 4) { + database.executeFast("CREATE TABLE IF NOT EXISTS enc_tasks_v2(mid INTEGER PRIMARY KEY, date INTEGER)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS date_idx_enc_tasks_v2 ON enc_tasks_v2(date);").stepThis().dispose(); + database.beginTransaction(); + SQLiteCursor cursor = database.queryFinalized("SELECT date, data FROM enc_tasks WHERE 1"); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_tasks_v2 VALUES(?, ?)"); + if (cursor.next()) { + int date = cursor.intValue(0); + int length; + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(1)); + if ((length = cursor.byteBufferValue(1, data)) != 0) { + for (int a = 0; a < length / 4; a++) { + state.requery(); + state.bindInteger(1, data.readInt32(false)); + state.bindInteger(2, date); + state.step(); + } + } + data.reuse(); + } + state.dispose(); + cursor.dispose(); + database.commitTransaction(); + + database.executeFast("DROP INDEX IF EXISTS date_idx_enc_tasks;").stepThis().dispose(); + database.executeFast("DROP TABLE IF EXISTS enc_tasks;").stepThis().dispose(); + + database.executeFast("ALTER TABLE messages ADD COLUMN media INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 6").stepThis().dispose(); + version = 6; + } + if (version == 6) { + database.executeFast("CREATE TABLE IF NOT EXISTS messages_seq(mid INTEGER PRIMARY KEY, seq_in INTEGER, seq_out INTEGER);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS seq_idx_messages_seq ON messages_seq(seq_in, seq_out);").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN layer INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_in INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN seq_out INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 7").stepThis().dispose(); + version = 7; + } + /*if (version == 7 && version < 8) { + database.executeFast("CREATE TABLE IF NOT EXISTS secret_holes(uid INTEGER, seq_in INTEGER, seq_out INTEGER, data BLOB, PRIMARY KEY (uid, seq_in, seq_out));").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 8").stepThis().dispose(); + version = 8; + }*/ + if (version == 7 || version == 8 || version == 9) { + database.executeFast("ALTER TABLE enc_chats ADD COLUMN use_count INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN exchange_id INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN key_date INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN fprint INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN fauthkey BLOB default NULL").stepThis().dispose(); + database.executeFast("ALTER TABLE enc_chats ADD COLUMN khash BLOB default NULL").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 10").stepThis().dispose(); + version = 10; + } + if (version == 10) { + database.executeFast("CREATE TABLE IF NOT EXISTS web_recent_v3(id TEXT, type INTEGER, image_url TEXT, thumb_url TEXT, local_url TEXT, width INTEGER, height INTEGER, size INTEGER, date INTEGER, PRIMARY KEY (id, type));").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 11").stepThis().dispose(); + version = 11; + } + if (version == 11) { + version = 12; + } + if (version == 12) { + database.executeFast("DROP INDEX IF EXISTS uid_mid_idx_media;").stepThis().dispose(); + database.executeFast("DROP INDEX IF EXISTS mid_idx_media;").stepThis().dispose(); + database.executeFast("DROP INDEX IF EXISTS uid_date_mid_idx_media;").stepThis().dispose(); + database.executeFast("DROP TABLE IF EXISTS media;").stepThis().dispose(); + database.executeFast("DROP TABLE IF EXISTS media_counts;").stepThis().dispose(); + + database.executeFast("CREATE TABLE IF NOT EXISTS media_v2(mid INTEGER PRIMARY KEY, uid INTEGER, date INTEGER, type INTEGER, data BLOB)").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS media_counts_v2(uid INTEGER, type INTEGER, count INTEGER, PRIMARY KEY(uid, type))").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_mid_type_date_idx_media ON media_v2(uid, mid, type, date);").stepThis().dispose(); + + database.executeFast("CREATE TABLE IF NOT EXISTS keyvalue(id TEXT PRIMARY KEY, value TEXT)").stepThis().dispose(); + + database.executeFast("PRAGMA user_version = 13").stepThis().dispose(); + version = 13; + } + if (version == 13) { + database.executeFast("ALTER TABLE messages ADD COLUMN replydata BLOB default NULL").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 14").stepThis().dispose(); + version = 14; + } + if (version == 14) { + database.executeFast("CREATE TABLE IF NOT EXISTS hashtag_recent_v2(id TEXT PRIMARY KEY, date INTEGER);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 15").stepThis().dispose(); + version = 15; + } + if (version == 15) { + database.executeFast("CREATE TABLE IF NOT EXISTS webpage_pending(id INTEGER, mid INTEGER, PRIMARY KEY (id, mid));").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 16").stepThis().dispose(); + version = 16; + } + if (version == 16) { + database.executeFast("ALTER TABLE dialogs ADD COLUMN inbox_max INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE dialogs ADD COLUMN outbox_max INTEGER default 0").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 17").stepThis().dispose(); + version = 17; + } + if (version == 17) { + database.executeFast("CREATE TABLE bot_info(uid INTEGER PRIMARY KEY, info BLOB)").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 18").stepThis().dispose(); + version = 18; + } + if (version == 18) { + database.executeFast("DROP TABLE IF EXISTS stickers;").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS stickers_v2(id INTEGER PRIMARY KEY, data BLOB, date INTEGER, hash TEXT);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 19").stepThis().dispose(); + version = 19; + } + if (version == 19) { + database.executeFast("CREATE TABLE IF NOT EXISTS bot_keyboard(uid INTEGER PRIMARY KEY, mid INTEGER, info BLOB)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS bot_keyboard_idx_mid ON bot_keyboard(mid);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 20").stepThis().dispose(); + version = 20; + } + if (version == 20) { + database.executeFast("CREATE TABLE search_recent(did INTEGER PRIMARY KEY, date INTEGER);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 21").stepThis().dispose(); + version = 21; + } + if (version == 21) { + database.executeFast("CREATE TABLE IF NOT EXISTS chat_settings_v2(uid INTEGER PRIMARY KEY, info BLOB)").stepThis().dispose(); + + SQLiteCursor cursor = database.queryFinalized("SELECT uid, participants FROM chat_settings WHERE uid < 0"); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?)"); + while (cursor.next()) { + int chat_id = cursor.intValue(0); + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(1)); + if (cursor.byteBufferValue(1, data) != 0) { + TLRPC.ChatParticipants participants = TLRPC.ChatParticipants.TLdeserialize(data, data.readInt32(false), false); + if (participants != null) { + TLRPC.TL_chatFull chatFull = new TLRPC.TL_chatFull(); + chatFull.id = chat_id; + chatFull.chat_photo = new TLRPC.TL_photoEmpty(); + chatFull.notify_settings = new TLRPC.TL_peerNotifySettingsEmpty(); + chatFull.exported_invite = new TLRPC.TL_chatInviteEmpty(); + chatFull.participants = participants; + NativeByteBuffer data2 = new NativeByteBuffer(chatFull.getObjectSize()); + chatFull.serializeToStream(data2); + state.requery(); + state.bindInteger(1, chat_id); + state.bindByteBuffer(2, data2); + state.step(); + data2.reuse(); + } + } + data.reuse(); + } + state.dispose(); + cursor.dispose(); + + database.executeFast("DROP TABLE IF EXISTS chat_settings;").stepThis().dispose(); + database.executeFast("ALTER TABLE dialogs ADD COLUMN last_mid_i INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE dialogs ADD COLUMN unread_count_i INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE dialogs ADD COLUMN pts INTEGER default 0").stepThis().dispose(); + database.executeFast("ALTER TABLE dialogs ADD COLUMN date_i INTEGER default 0").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS last_mid_i_idx_dialogs ON dialogs(last_mid_i);").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS unread_count_i_idx_dialogs ON dialogs(unread_count_i);").stepThis().dispose(); + database.executeFast("ALTER TABLE messages ADD COLUMN imp INTEGER default 0").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_mid_idx_imp_messages ON messages(uid, mid, imp) WHERE imp = 1;").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_date_mid_imp_idx_messages ON messages(uid, date, mid, imp) WHERE imp = 1;").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS channel_group(uid INTEGER, start INTEGER, end INTEGER, count INTEGER, PRIMARY KEY(uid, start));").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS messages_holes(uid INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, start));").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_messages_holes ON messages_holes(uid, end);").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS messages_imp_holes(uid INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, start));").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_messages_imp_holes ON messages_imp_holes(uid, end);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 22").stepThis().dispose(); + version = 22; + } + if (version == 22) { + database.executeFast("CREATE TABLE IF NOT EXISTS media_holes_v2(uid INTEGER, type INTEGER, start INTEGER, end INTEGER, PRIMARY KEY(uid, type, start));").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS uid_end_media_holes_v2 ON media_holes_v2(uid, type, end);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 23").stepThis().dispose(); + version = 23; + } + if (version == 24) { + database.executeFast("DELETE FROM media_holes_v2 WHERE uid != 0 AND type >= 0 AND start IN (0, 1)").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 25").stepThis().dispose(); + version = 25; + } + if (version == 25 || version == 26) { + database.executeFast("CREATE TABLE IF NOT EXISTS channel_users_v2(did INTEGER, uid INTEGER, date INTEGER, data BLOB, PRIMARY KEY(did, uid))").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 27").stepThis().dispose(); + version = 27; + } + if (version == 27) { + database.executeFast("ALTER TABLE web_recent_v3 ADD COLUMN document BLOB default NULL").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 28").stepThis().dispose(); + version = 28; + } + if (version == 28) { + database.executeFast("CREATE TABLE IF NOT EXISTS bot_recent(id INTEGER PRIMARY KEY, date INTEGER);").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 29").stepThis().dispose(); + version = 29; + } + if (version == 29) { + database.executeFast("DELETE FROM sent_files_v2 WHERE 1").stepThis().dispose(); + database.executeFast("DELETE FROM download_queue WHERE 1").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 30").stepThis().dispose(); + version = 30; + } + if (version == 30) { + database.executeFast("ALTER TABLE chat_settings_v2 ADD COLUMN pinned INTEGER default 0").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS chat_settings_pinned_idx ON chat_settings_v2(uid, pinned) WHERE pinned != 0;").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS chat_pinned(uid INTEGER PRIMARY KEY, pinned INTEGER, data BLOB)").stepThis().dispose(); + database.executeFast("CREATE INDEX IF NOT EXISTS chat_pinned_mid_idx ON chat_pinned(uid, pinned) WHERE pinned != 0;").stepThis().dispose(); + database.executeFast("CREATE TABLE IF NOT EXISTS users_data(uid INTEGER PRIMARY KEY, about TEXT)").stepThis().dispose(); + database.executeFast("PRAGMA user_version = 31").stepThis().dispose(); + //version = 31; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void cleanUp(final boolean isLogin) { + storageQueue.cleanupQueue(); + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + lastDateValue = 0; + lastSeqValue = 0; + lastPtsValue = 0; + lastQtsValue = 0; + lastSecretVersion = 0; + + lastSavedSeq = 0; + lastSavedPts = 0; + lastSavedDate = 0; + lastSavedQts = 0; + + secretPBytes = null; + secretG = 0; + if (database != null) { + database.close(); + database = null; + } + if (cacheFile != null) { + cacheFile.delete(); + cacheFile = null; + } + openDatabase(); + if (isLogin) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().getDifference(); + } + }); + } + } + }); + } + + public void saveSecretParams(final int lsv, final int sg, final byte[] pbytes) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLitePreparedStatement state = database.executeFast("UPDATE params SET lsv = ?, sg = ?, pbytes = ? WHERE id = 1"); + state.bindInteger(1, lsv); + state.bindInteger(2, sg); + NativeByteBuffer data = new NativeByteBuffer(pbytes != null ? pbytes.length : 1); + if (pbytes != null) { + data.writeBytes(pbytes); + } + state.bindByteBuffer(3, data); + state.step(); + state.dispose(); + data.reuse(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void saveChannelPts(final int channelId, final int pts) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET pts = ? WHERE did = ?"); + state.bindInteger(1, pts); + state.bindInteger(2, -channelId); + state.step(); + state.dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void saveDiffParams(final int seq, final int pts, final int date, final int qts) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (lastSavedSeq == seq && lastSavedPts == pts && lastSavedDate == date && lastQtsValue == qts) { + return; + } + SQLitePreparedStatement state = database.executeFast("UPDATE params SET seq = ?, pts = ?, date = ?, qts = ? WHERE id = 1"); + state.bindInteger(1, seq); + state.bindInteger(2, pts); + state.bindInteger(3, date); + state.bindInteger(4, qts); + state.step(); + state.dispose(); + lastSavedSeq = seq; + lastSavedPts = pts; + lastSavedDate = date; + lastSavedQts = qts; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void setDialogFlags(final long did, final long flags) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + database.executeFast(String.format(Locale.US, "REPLACE INTO dialog_settings VALUES(%d, %d)", did, flags)).stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void loadUnreadMessages() { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + final HashMap pushDialogs = new HashMap<>(); + SQLiteCursor cursor = database.queryFinalized("SELECT d.did, d.unread_count, s.flags FROM dialogs as d LEFT JOIN dialog_settings as s ON d.did = s.did WHERE d.unread_count != 0"); + StringBuilder ids = new StringBuilder(); + while (cursor.next()) { + if (cursor.isNull(2) || cursor.intValue(2) != 1) { + long did = cursor.longValue(0); + int count = cursor.intValue(1); + pushDialogs.put(did, count); + if (ids.length() != 0) { + ids.append(","); + } + ids.append(did); + } + } + cursor.dispose(); + + final ArrayList messages = new ArrayList<>(); + final ArrayList users = new ArrayList<>(); + final ArrayList chats = new ArrayList<>(); + final ArrayList encryptedChats = new ArrayList<>(); + if (ids.length() > 0) { + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + ArrayList encryptedChatIds = new ArrayList<>(); + + cursor = database.queryFinalized("SELECT read_state, data, send_state, mid, date, uid FROM messages WHERE uid IN (" + ids.toString() + ") AND out = 0 AND read_state IN(0,2) ORDER BY date DESC LIMIT 50"); + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(1)); + if (cursor.byteBufferValue(1, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + MessageObject.setUnreadFlags(message, cursor.intValue(0)); + message.id = cursor.intValue(3); + message.date = cursor.intValue(4); + message.dialog_id = cursor.longValue(5); + messages.add(message); + + int lower_id = (int)message.dialog_id; + int high_id = (int)(message.dialog_id >> 32); + + if (lower_id != 0) { + if (lower_id < 0) { + if (!chatsToLoad.contains(-lower_id)) { + chatsToLoad.add(-lower_id); + } + } else { + if (!usersToLoad.contains(lower_id)) { + usersToLoad.add(lower_id); + } + } + } else { + if (!encryptedChatIds.contains(high_id)) { + encryptedChatIds.add(high_id); + } + } + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + message.send_state = cursor.intValue(2); + if (message.to_id.channel_id == 0 && !MessageObject.isUnread(message) && lower_id != 0 || message.id > 0) { + message.send_state = 0; + } + if (lower_id == 0 && !cursor.isNull(5)) { + message.random_id = cursor.longValue(5); + } + } + data.reuse(); + } + cursor.dispose(); + + if (!encryptedChatIds.isEmpty()) { + getEncryptedChatsInternal(TextUtils.join(",", encryptedChatIds), encryptedChats, usersToLoad); + } + + if (!usersToLoad.isEmpty()) { + getUsersInternal(TextUtils.join(",", usersToLoad), users); + } + + if (!chatsToLoad.isEmpty()) { + getChatsInternal(TextUtils.join(",", chatsToLoad), chats); + for (int a = 0; a < chats.size(); a++) { + TLRPC.Chat chat = chats.get(a); + if (chat != null && (chat.left || chat.migrated_to != null)) { + long did = -chat.id; + database.executeFast("UPDATE dialogs SET unread_count = 0, unread_count_i = 0 WHERE did = " + did).stepThis().dispose(); + database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = 3 WHERE uid = %d AND mid > 0 AND read_state IN(0,2) AND out = 0", did)).stepThis().dispose(); + chats.remove(a); + a--; + pushDialogs.remove((long) -chat.id); + for (int b = 0; b < messages.size(); b++) { + TLRPC.Message message = messages.get(b); + if (message.dialog_id == -chat.id) { + messages.remove(b); + b--; + } + } + } + } + } + } + Collections.reverse(messages); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationsController.getInstance().processLoadedUnreadMessages(pushDialogs, messages, users, chats, encryptedChats); + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void putWallpapers(final ArrayList wallPapers) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + int num = 0; + database.executeFast("DELETE FROM wallpapers WHERE 1").stepThis().dispose(); + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO wallpapers VALUES(?, ?)"); + for (TLRPC.WallPaper wallPaper : wallPapers) { + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(wallPaper.getObjectSize()); + wallPaper.serializeToStream(data); + state.bindInteger(1, num); + state.bindByteBuffer(2, data); + state.step(); + num++; + data.reuse(); + } + state.dispose(); + database.commitTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void loadWebRecent(final int type) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT id, image_url, thumb_url, local_url, width, height, size, date, document FROM web_recent_v3 WHERE type = " + type + " ORDER BY date DESC"); + final ArrayList arrayList = new ArrayList<>(); + while (cursor.next()) { + MediaController.SearchImage searchImage = new MediaController.SearchImage(); + searchImage.id = cursor.stringValue(0); + searchImage.imageUrl = cursor.stringValue(1); + searchImage.thumbUrl = cursor.stringValue(2); + searchImage.localUrl = cursor.stringValue(3); + searchImage.width = cursor.intValue(4); + searchImage.height = cursor.intValue(5); + searchImage.size = cursor.intValue(6); + searchImage.date = cursor.intValue(7); + if (!cursor.isNull(8)) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(8)); + if (cursor.byteBufferValue(8, data) != 0) { + searchImage.document = TLRPC.Document.TLdeserialize(data, data.readInt32(false), false); + } + data.reuse(); + } + searchImage.type = type; + arrayList.add(searchImage); + } + cursor.dispose(); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.recentImagesDidLoaded, type, arrayList); + } + }); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void addRecentLocalFile(final String imageUrl, final String localUrl, final TLRPC.Document document) { + if (imageUrl == null || imageUrl.length() == 0 || ((localUrl == null || localUrl.length() == 0) && document == null)) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (document != null) { + SQLitePreparedStatement state = database.executeFast("UPDATE web_recent_v3 SET document = ? WHERE image_url = ?"); + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(document.getObjectSize()); + document.serializeToStream(data); + state.bindByteBuffer(1, data); + state.bindString(2, imageUrl); + state.step(); + state.dispose(); + data.reuse(); + } else { + SQLitePreparedStatement state = database.executeFast("UPDATE web_recent_v3 SET local_url = ? WHERE image_url = ?"); + state.requery(); + state.bindString(1, localUrl); + state.bindString(2, imageUrl); + state.step(); + state.dispose(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void removeWebRecent(final MediaController.SearchImage searchImage) { + if (searchImage == null) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + database.executeFast("DELETE FROM web_recent_v3 WHERE id = '" + searchImage.id + "'").stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void clearWebRecent(final int type) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + database.executeFast("DELETE FROM web_recent_v3 WHERE type = " + type).stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void putWebRecent(final ArrayList arrayList) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO web_recent_v3 VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + for (int a = 0; a < arrayList.size(); a++) { + if (a == 200) { + break; + } + MediaController.SearchImage searchImage = arrayList.get(a); + state.requery(); + state.bindString(1, searchImage.id); + state.bindInteger(2, searchImage.type); + state.bindString(3, searchImage.imageUrl != null ? searchImage.imageUrl : ""); + state.bindString(4, searchImage.thumbUrl != null ? searchImage.thumbUrl : ""); + state.bindString(5, searchImage.localUrl != null ? searchImage.localUrl : ""); + state.bindInteger(6, searchImage.width); + state.bindInteger(7, searchImage.height); + state.bindInteger(8, searchImage.size); + state.bindInteger(9, searchImage.date); + NativeByteBuffer data = null; + if (searchImage.document != null) { + data = new NativeByteBuffer(searchImage.document.getObjectSize()); + searchImage.document.serializeToStream(data); + state.bindByteBuffer(10, data); + } else { + state.bindNull(10); + } + state.step(); + if (data != null) { + data.reuse(); + } + } + state.dispose(); + database.commitTransaction(); + if (arrayList.size() >= 200) { + database.beginTransaction(); + for (int a = 200; a < arrayList.size(); a++) { + database.executeFast("DELETE FROM web_recent_v3 WHERE id = '" + arrayList.get(a).id + "'").stepThis().dispose(); + } + database.commitTransaction(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void getWallpapers() { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT data FROM wallpapers WHERE 1"); + final ArrayList wallPapers = new ArrayList<>(); + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + TLRPC.WallPaper wallPaper = TLRPC.WallPaper.TLdeserialize(data, data.readInt32(false), false); + wallPapers.add(wallPaper); + } + data.reuse(); + } + cursor.dispose(); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.wallpapersDidLoaded, wallPapers); + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void getBlockedUsers() { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + ArrayList ids = new ArrayList<>(); + ArrayList users = new ArrayList<>(); + SQLiteCursor cursor = database.queryFinalized("SELECT * FROM blocked_users WHERE 1"); + StringBuilder usersToLoad = new StringBuilder(); + while (cursor.next()) { + int user_id = cursor.intValue(0); + ids.add(user_id); + if (usersToLoad.length() != 0) { + usersToLoad.append(","); + } + usersToLoad.append(user_id); + } + cursor.dispose(); + + if (usersToLoad.length() != 0) { + getUsersInternal(usersToLoad.toString(), users); + } + + MessagesController.getInstance().processLoadedBlockedUsers(ids, users, true); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void deleteBlockedUser(final int id) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + database.executeFast("DELETE FROM blocked_users WHERE uid = " + id).stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void putBlockedUsers(final ArrayList ids, final boolean replace) { + if (ids == null || ids.isEmpty()) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (replace) { + database.executeFast("DELETE FROM blocked_users WHERE 1").stepThis().dispose(); + } + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO blocked_users VALUES(?)"); + for (Integer id : ids) { + state.requery(); + state.bindInteger(1, id); + state.step(); + } + state.dispose(); + database.commitTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void deleteUserChannelHistory(final int channelId, final int uid) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + long did = -channelId; + final ArrayList mids = new ArrayList<>(); + SQLiteCursor cursor = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did); + ArrayList filesToDelete = new ArrayList<>(); + try { + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + if (message != null && message.from_id == uid && message.id != 1) { + mids.add(message.id); + if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) { + File file = FileLoader.getPathToAttach(photoSize); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + } + } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { + File file = FileLoader.getPathToAttach(message.media.document); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + file = FileLoader.getPathToAttach(message.media.document.thumb); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + } + } + } + data.reuse(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + cursor.dispose(); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().markChannelDialogMessageAsDeleted(mids, channelId); + } + }); + markMessagesAsDeletedInternal(mids, channelId); + updateDialogsWithDeletedMessagesInternal(mids, channelId); + FileLoader.getInstance().deleteFiles(filesToDelete, 0); + if (!mids.isEmpty()) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDeleted, mids, channelId); + } + }); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void deleteDialog(final long did, final int messagesOnly) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if ((int) did == 0 || messagesOnly == 2) { + SQLiteCursor cursor = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did); + ArrayList filesToDelete = new ArrayList<>(); + try { + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + if (message != null && message.media != null) { + if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) { + File file = FileLoader.getPathToAttach(photoSize); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + } + } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { + File file = FileLoader.getPathToAttach(message.media.document); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + file = FileLoader.getPathToAttach(message.media.document.thumb); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + } + } + } + data.reuse(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + cursor.dispose(); + FileLoader.getInstance().deleteFiles(filesToDelete, messagesOnly); + } + + if (messagesOnly == 0) { + database.executeFast("DELETE FROM dialogs WHERE did = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM chat_settings_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM chat_pinned WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM channel_users_v2 WHERE did = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM search_recent WHERE did = " + did).stepThis().dispose(); + int lower_id = (int)did; + int high_id = (int)(did >> 32); + if (lower_id != 0) { + if (high_id == 1) { + database.executeFast("DELETE FROM chats WHERE uid = " + lower_id).stepThis().dispose(); + } else if (lower_id < 0) { + //database.executeFast("DELETE FROM chats WHERE uid = " + (-lower_id)).stepThis().dispose(); + } + } else { + database.executeFast("DELETE FROM enc_chats WHERE uid = " + high_id).stepThis().dispose(); + //database.executeFast("DELETE FROM secret_holes WHERE uid = " + high_id).stepThis().dispose(); + } + } else if (messagesOnly == 2) { + SQLiteCursor cursor = database.queryFinalized("SELECT last_mid_i, last_mid FROM dialogs WHERE did = " + did); + ArrayList arrayList = new ArrayList<>(); + if (cursor.next()) { + long last_mid_i = cursor.longValue(0); + long last_mid = cursor.longValue(1); + SQLiteCursor cursor2 = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did + " AND mid IN (" + last_mid_i + "," + last_mid + ")"); + try { + while (cursor2.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor2.byteArrayLength(0)); + if (cursor2.byteBufferValue(0, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + if (message != null) { + arrayList.add(message); + } + } + data.reuse(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + cursor2.dispose(); + + database.executeFast("DELETE FROM messages WHERE uid = " + did + " AND mid != " + last_mid_i + " AND mid != " + last_mid).stepThis().dispose(); + database.executeFast("DELETE FROM channel_group WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM messages_holes WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM messages_imp_holes WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM bot_keyboard WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_counts_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_holes_v2 WHERE uid = " + did).stepThis().dispose(); + BotQuery.clearBotKeyboard(did, null); + + SQLitePreparedStatement state5 = database.executeFast("REPLACE INTO messages_holes VALUES(?, ?, ?)"); + SQLitePreparedStatement state6 = database.executeFast("REPLACE INTO media_holes_v2 VALUES(?, ?, ?, ?)"); + SQLitePreparedStatement state7 = database.executeFast("REPLACE INTO messages_imp_holes VALUES(?, ?, ?)"); + SQLitePreparedStatement state8 = database.executeFast("REPLACE INTO channel_group VALUES(?, ?, ?, ?)"); + createFirstHoles(did, state5, state6, state7, state8, arrayList); + state5.dispose(); + state6.dispose(); + state7.dispose(); + state8.dispose(); + } + cursor.dispose(); + return; + } + + database.executeFast("UPDATE dialogs SET unread_count = 0, unread_count_i = 0 WHERE did = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM messages WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM channel_group WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM bot_keyboard WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_counts_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM messages_holes WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM messages_imp_holes WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_holes_v2 WHERE uid = " + did).stepThis().dispose(); + BotQuery.clearBotKeyboard(did, null); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.needReloadRecentDialogsSearch); + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void getUserPhotos(final int uid, final int offset, final int count, final long max_id, final int classGuid) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLiteCursor cursor; + + if (max_id != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM user_photos WHERE uid = %d AND id < %d ORDER BY id DESC LIMIT %d", uid, max_id, count)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM user_photos WHERE uid = %d ORDER BY id DESC LIMIT %d,%d", uid, offset, count)); + } + + final TLRPC.photos_Photos res = new TLRPC.photos_Photos(); + + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + TLRPC.Photo photo = TLRPC.Photo.TLdeserialize(data, data.readInt32(false), false); + res.photos.add(photo); + } + data.reuse(); + } + cursor.dispose(); + + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().processLoadedUserPhotos(res, uid, offset, count, max_id, true, classGuid); + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void clearUserPhotos(final int uid) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + database.executeFast("DELETE FROM user_photos WHERE uid = " + uid).stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void clearUserPhoto(final int uid, final long pid) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + database.executeFast("DELETE FROM user_photos WHERE uid = " + uid + " AND id = " + pid).stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void putUserPhotos(final int uid, final TLRPC.photos_Photos photos) { + if (photos == null || photos.photos.isEmpty()) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLitePreparedStatement state = database.executeFast("REPLACE INTO user_photos VALUES(?, ?, ?)"); + for (TLRPC.Photo photo : photos.photos) { + if (photo instanceof TLRPC.TL_photoEmpty) { + continue; + } + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(photo.getObjectSize()); + photo.serializeToStream(data); + state.bindInteger(1, uid); + state.bindLong(2, photo.id); + state.bindByteBuffer(3, data); + state.step(); + data.reuse(); + } + state.dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void getNewTask(final ArrayList oldTask) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (oldTask != null) { + String ids = TextUtils.join(",", oldTask); + database.executeFast(String.format(Locale.US, "DELETE FROM enc_tasks_v2 WHERE mid IN(%s)", ids)).stepThis().dispose(); + } + int date = 0; + ArrayList arr = null; + SQLiteCursor cursor = database.queryFinalized("SELECT mid, date FROM enc_tasks_v2 WHERE date = (SELECT min(date) FROM enc_tasks_v2)"); + while (cursor.next()) { + Integer mid = cursor.intValue(0); + date = cursor.intValue(1); + if (arr == null) { + arr = new ArrayList<>(); + } + arr.add(mid); + } + cursor.dispose(); + MessagesController.getInstance().processLoadedDeleteTask(date, arr); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void createTaskForSecretChat(final int chat_id, final int time, final int readTime, final int isOut, final ArrayList random_ids) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + int minDate = Integer.MAX_VALUE; + SparseArray> messages = new SparseArray<>(); + final ArrayList midsArray = new ArrayList<>(); + StringBuilder mids = new StringBuilder(); + SQLiteCursor cursor; + if (random_ids == null) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, ttl FROM messages WHERE uid = %d AND out = %d AND read_state != 0 AND ttl > 0 AND date <= %d AND send_state = 0 AND media != 1", ((long) chat_id) << 32, isOut, time)); + } else { + String ids = TextUtils.join(",", random_ids); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.mid, m.ttl FROM messages as m INNER JOIN randoms as r ON m.mid = r.mid WHERE r.random_id IN (%s)", ids)); + } + while (cursor.next()) { + int ttl = cursor.intValue(1); + int mid = cursor.intValue(0); + if (random_ids != null) { + midsArray.add((long) mid); + } + if (ttl <= 0) { + continue; + } + int date = Math.min(readTime, time) + ttl; + minDate = Math.min(minDate, date); + ArrayList arr = messages.get(date); + if (arr == null) { + arr = new ArrayList<>(); + messages.put(date, arr); + } + if (mids.length() != 0) { + mids.append(","); + } + mids.append(mid); + arr.add(mid); + } + cursor.dispose(); + + if (random_ids != null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesStorage.getInstance().markMessagesContentAsRead(midsArray); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesReadContent, midsArray); + } + }); + } + + if (messages.size() != 0) { + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_tasks_v2 VALUES(?, ?)"); + for (int a = 0; a < messages.size(); a++) { + int key = messages.keyAt(a); + ArrayList arr = messages.get(key); + for (int b = 0; b < arr.size(); b++) { + state.requery(); + state.bindInteger(1, arr.get(b)); + state.bindInteger(2, key); + state.step(); + } + } + state.dispose(); + database.commitTransaction(); + database.executeFast(String.format(Locale.US, "UPDATE messages SET ttl = 0 WHERE mid IN(%s)", mids.toString())).stepThis().dispose(); + MessagesController.getInstance().didAddedNewTask(minDate, messages); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + private void updateDialogsWithReadMessagesInternal(final ArrayList messages, final SparseArray inbox) { + try { + HashMap dialogsToUpdate = new HashMap<>(); + + if (messages != null && !messages.isEmpty()) { + String ids = TextUtils.join(",", messages); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid, read_state, out FROM messages WHERE mid IN(%s)", ids)); + while (cursor.next()) { + int out = cursor.intValue(2); + if (out != 0) { + continue; + } + int read_state = cursor.intValue(1); + if (read_state != 0) { + continue; + } + long uid = cursor.longValue(0); + Integer currentCount = dialogsToUpdate.get(uid); + if (currentCount == null) { + dialogsToUpdate.put(uid, 1); + } else { + dialogsToUpdate.put(uid, currentCount + 1); + } + } + cursor.dispose(); + } else if (inbox != null && inbox.size() != 0) { + for (int b = 0; b < inbox.size(); b++) { + int key = inbox.keyAt(b); + long messageId = inbox.get(key); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(mid) FROM messages WHERE uid = %d AND mid > %d AND read_state IN(0,2) AND out = 0", key, messageId)); + if (cursor.next()) { + int count = cursor.intValue(0); + dialogsToUpdate.put((long) key, count); + } + cursor.dispose(); + + SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET inbox_max = max((SELECT inbox_max FROM dialogs WHERE did = ?), ?) WHERE did = ?"); + state.requery(); + state.bindLong(1, key); + state.bindInteger(2, (int) messageId); + state.bindLong(3, key); + state.step(); + state.dispose(); + } + } + + if (!dialogsToUpdate.isEmpty()) { + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET unread_count = ? WHERE did = ?"); + for (HashMap.Entry entry : dialogsToUpdate.entrySet()) { + state.requery(); + state.bindInteger(1, entry.getValue()); + state.bindLong(2, entry.getKey()); + state.step(); + } + state.dispose(); + database.commitTransaction(); + } + + if (!dialogsToUpdate.isEmpty()) { + MessagesController.getInstance().processDialogsUpdateRead(dialogsToUpdate); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void updateDialogsWithReadMessages(final SparseArray inbox, boolean useQueue) { + if (inbox.size() == 0) { + return; + } + if (useQueue) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + updateDialogsWithReadMessagesInternal(null, inbox); + } + }); + } else { + updateDialogsWithReadMessagesInternal(null, inbox); + } + } + + public void updateChatParticipants(final TLRPC.ChatParticipants participants) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + participants.chat_id); + TLRPC.ChatFull info = null; + ArrayList loadedUsers = new ArrayList<>(); + if (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); + info.pinned_msg_id = cursor.intValue(1); + } + data.reuse(); + } + cursor.dispose(); + if (info instanceof TLRPC.TL_chatFull) { + info.participants = participants; + final TLRPC.ChatFull finalInfo = info; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null); + } + }); + + SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)"); + NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); + info.serializeToStream(data); + state.bindInteger(1, info.id); + state.bindByteBuffer(2, data); + state.bindInteger(3, info.pinned_msg_id); + state.step(); + state.dispose(); + data.reuse(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void updateChannelUsers(final int channel_id, final ArrayList participants) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + long did = -channel_id; + database.executeFast("DELETE FROM channel_users_v2 WHERE did = " + did).stepThis().dispose(); + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO channel_users_v2 VALUES(?, ?, ?, ?)"); + NativeByteBuffer data; + int date = (int) (System.currentTimeMillis() / 1000); + for (int a = 0; a < participants.size(); a++) { + TLRPC.ChannelParticipant participant = participants.get(a); + state.requery(); + state.bindLong(1, did); + state.bindInteger(2, participant.user_id); + state.bindInteger(3, date); + data = new NativeByteBuffer(participant.getObjectSize()); + participant.serializeToStream(data); + state.bindByteBuffer(4, data); + data.reuse(); + state.step(); + date--; + } + state.dispose(); + database.commitTransaction(); + loadChatInfo(channel_id, null, false, true); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void updateChatInfo(final TLRPC.ChatFull info, final boolean ifExist) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (ifExist) { + boolean dontExist = true; + SQLiteCursor cursor = database.queryFinalized("SELECT uid FROM chat_settings_v2 WHERE uid = " + info.id); + if (cursor.next()) { + dontExist = false; + } + cursor.dispose(); + if (dontExist) { + return; + } + } + SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)"); + NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); + info.serializeToStream(data); + state.bindInteger(1, info.id); + state.bindByteBuffer(2, data); + state.bindInteger(3, info.pinned_msg_id); + state.step(); + state.dispose(); + data.reuse(); + + if (info instanceof TLRPC.TL_channelFull) { + SQLiteCursor cursor = database.queryFinalized("SELECT date, last_mid_i, pts, date_i, last_mid FROM dialogs WHERE did = " + (-info.id)); + if (cursor.next()) { + int dialog_date = cursor.intValue(0); + long last_mid_i = cursor.longValue(1); + int pts = cursor.intValue(2); + int dialog_date_i = cursor.intValue(3); + long last_mid = cursor.longValue(4); + + state = database.executeFast("REPLACE INTO dialogs VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + state.bindLong(1, -info.id); + state.bindInteger(2, dialog_date); + state.bindInteger(3, info.unread_important_count); + state.bindLong(4, last_mid); + state.bindInteger(5, info.read_inbox_max_id); + state.bindInteger(6, 0); + state.bindLong(7, last_mid_i); + state.bindInteger(8, info.unread_count); + state.bindInteger(9, pts); + state.bindInteger(10, dialog_date_i); + state.step(); + state.dispose(); + } + cursor.dispose(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void updateChannelPinnedMessage(final int channelId, final int messageId) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + channelId); + TLRPC.ChatFull info = null; + ArrayList loadedUsers = new ArrayList<>(); + if (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); + info.pinned_msg_id = cursor.intValue(1); + } + data.reuse(); + } + cursor.dispose(); + if (info instanceof TLRPC.TL_channelFull) { + info.pinned_msg_id = messageId; + info.flags |= 32; + + final TLRPC.ChatFull finalInfo = info; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null); + } + }); + + SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)"); + NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); + info.serializeToStream(data); + state.bindInteger(1, channelId); + state.bindByteBuffer(2, data); + state.bindInteger(3, info.pinned_msg_id); + state.step(); + state.dispose(); + data.reuse(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void updateChatInfo(final int chat_id, final int user_id, final int what, final int invited_id, final int version) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + chat_id); + TLRPC.ChatFull info = null; + ArrayList loadedUsers = new ArrayList<>(); + if (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); + info.pinned_msg_id = cursor.intValue(1); + } + data.reuse(); + } + cursor.dispose(); + if (info instanceof TLRPC.TL_chatFull) { + if (what == 1) { + for (int a = 0; a < info.participants.participants.size(); a++) { + TLRPC.ChatParticipant participant = info.participants.participants.get(a); + if (participant.user_id == user_id) { + info.participants.participants.remove(a); + break; + } + } + } else if (what == 0) { + for (TLRPC.ChatParticipant part : info.participants.participants) { + if (part.user_id == user_id) { + return; + } + } + TLRPC.TL_chatParticipant participant = new TLRPC.TL_chatParticipant(); + participant.user_id = user_id; + participant.inviter_id = invited_id; + participant.date = ConnectionsManager.getInstance().getCurrentTime(); + info.participants.participants.add(participant); + } else if (what == 2) { + for (int a = 0; a < info.participants.participants.size(); a++) { + TLRPC.ChatParticipant participant = info.participants.participants.get(a); + if (participant.user_id == user_id) { + TLRPC.ChatParticipant newParticipant; + if (invited_id == 1) { + newParticipant = new TLRPC.TL_chatParticipantAdmin(); + newParticipant.user_id = participant.user_id; + newParticipant.date = participant.date; + newParticipant.inviter_id = participant.inviter_id; + } else { + newParticipant = new TLRPC.TL_chatParticipant(); + newParticipant.user_id = participant.user_id; + newParticipant.date = participant.date; + newParticipant.inviter_id = participant.inviter_id; + } + info.participants.participants.set(a, newParticipant); + break; + } + } + } + info.participants.version = version; + + final TLRPC.ChatFull finalInfo = info; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatInfoDidLoaded, finalInfo, 0, false, null); + } + }); + + SQLitePreparedStatement state = database.executeFast("REPLACE INTO chat_settings_v2 VALUES(?, ?, ?)"); + NativeByteBuffer data = new NativeByteBuffer(info.getObjectSize()); + info.serializeToStream(data); + state.bindInteger(1, chat_id); + state.bindByteBuffer(2, data); + state.bindInteger(3, info.pinned_msg_id); + state.step(); + state.dispose(); + data.reuse(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public boolean isMigratedChat(final int chat_id) { + final Semaphore semaphore = new Semaphore(0); + final boolean result[] = new boolean[1]; + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLiteCursor cursor = database.queryFinalized("SELECT info FROM chat_settings_v2 WHERE uid = " + chat_id); + TLRPC.ChatFull info = null; + ArrayList loadedUsers = new ArrayList<>(); + if (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); + } + data.reuse(); + } + cursor.dispose(); + result[0] = info instanceof TLRPC.TL_channelFull && info.migrated_from_chat_id != 0; + if (semaphore != null) { + semaphore.release(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (semaphore != null) { + semaphore.release(); + } + } + } + }); + try { + semaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return result[0]; + } + + public void loadChatInfo(final int chat_id, final Semaphore semaphore, final boolean force, final boolean byChannelUsers) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + MessageObject pinnedMessageObject = null; + TLRPC.ChatFull info = null; + ArrayList loadedUsers = new ArrayList<>(); + try { + SQLiteCursor cursor = database.queryFinalized("SELECT info, pinned FROM chat_settings_v2 WHERE uid = " + chat_id); + if (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + info = TLRPC.ChatFull.TLdeserialize(data, data.readInt32(false), false); + info.pinned_msg_id = cursor.intValue(1); + } + data.reuse(); + } + cursor.dispose(); + + if (info instanceof TLRPC.TL_chatFull) { + StringBuilder usersToLoad = new StringBuilder(); + for (int a = 0; a < info.participants.participants.size(); a++) { + TLRPC.ChatParticipant c = info.participants.participants.get(a); + if (usersToLoad.length() != 0) { + usersToLoad.append(","); + } + usersToLoad.append(c.user_id); + } + if (usersToLoad.length() != 0) { + getUsersInternal(usersToLoad.toString(), loadedUsers); + } + } else if (info instanceof TLRPC.TL_channelFull) { + cursor = database.queryFinalized("SELECT us.data, us.status, cu.data, cu.date FROM channel_users_v2 as cu LEFT JOIN users as us ON us.uid = cu.uid WHERE cu.did = " + (-chat_id) + " ORDER BY cu.date DESC"); + info.participants = new TLRPC.TL_chatParticipants(); + while (cursor.next()) { + try { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + NativeByteBuffer data2 = new NativeByteBuffer(cursor.byteArrayLength(2)); + if (cursor.byteBufferValue(0, data) != 0 && cursor.byteBufferValue(2, data2) != 0) { + TLRPC.User user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); + TLRPC.ChannelParticipant participant = TLRPC.ChannelParticipant.TLdeserialize(data2, data2.readInt32(false), false); + if (user != null && participant != null) { + if (user.status != null) { + user.status.expires = cursor.intValue(1); + } + loadedUsers.add(user); + participant.date = cursor.intValue(3); + TLRPC.TL_chatChannelParticipant chatChannelParticipant = new TLRPC.TL_chatChannelParticipant(); + chatChannelParticipant.user_id = participant.user_id; + chatChannelParticipant.date = participant.date; + chatChannelParticipant.inviter_id = participant.inviter_id; + chatChannelParticipant.channelParticipant = participant; + info.participants.participants.add(chatChannelParticipant); + } + } + data.reuse(); + data2.reuse(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + cursor.dispose(); + StringBuilder usersToLoad = new StringBuilder(); + for (int a = 0; a < info.bot_info.size(); a++) { + TLRPC.BotInfo botInfo = info.bot_info.get(a); + if (usersToLoad.length() != 0) { + usersToLoad.append(","); + } + usersToLoad.append(botInfo.user_id); + } + if (usersToLoad.length() != 0) { + getUsersInternal(usersToLoad.toString(), loadedUsers); + } + } + if (semaphore != null) { + semaphore.release(); + } + if (info instanceof TLRPC.TL_channelFull && info.pinned_msg_id != 0) { + pinnedMessageObject = MessagesQuery.loadPinnedMessage(chat_id, info.pinned_msg_id, false); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + MessagesController.getInstance().processChatInfo(chat_id, info, loadedUsers, true, force, byChannelUsers, pinnedMessageObject); + if (semaphore != null) { + semaphore.release(); + } + } + } + }); + } + + public void processPendingRead(final long dialog_id, final long max_id, final int max_date, final boolean delete) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (delete) { + //database.executeFast("DELETE FROM pending_read WHERE uid = " + dialog_id).stepThis().dispose(); + } else { + database.beginTransaction(); + SQLitePreparedStatement state;/* = database.executeFast("REPLACE INTO pending_read VALUES(?, ?)"); + state.requery(); + state.bindLong(1, dialog_id); + state.bindInteger(2, max_id); + state.step(); + state.dispose();*/ + + int lower_id = (int) dialog_id; + + if (lower_id != 0) { + state = database.executeFast("UPDATE messages SET read_state = read_state | 1 WHERE uid = ? AND mid <= ? AND read_state IN(0,2) AND out = 0"); + state.requery(); + state.bindLong(1, dialog_id); + state.bindLong(2, max_id); + state.step(); + state.dispose(); + } else { + state = database.executeFast("UPDATE messages SET read_state = read_state | 1 WHERE uid = ? AND date <= ? AND read_state IN(0,2) AND out = 0"); + state.requery(); + state.bindLong(1, dialog_id); + state.bindInteger(2, max_date); + state.step(); + state.dispose(); + } + + int currentMaxId = 0; + SQLiteCursor cursor = database.queryFinalized("SELECT inbox_max FROM dialogs WHERE did = " + dialog_id); + if (cursor.next()) { + currentMaxId = cursor.intValue(0); + } + cursor.dispose(); + currentMaxId = Math.max(currentMaxId, (int) max_id); + + state = database.executeFast("UPDATE dialogs SET unread_count = 0, unread_count_i = 0, inbox_max = ? WHERE did = ?"); + state.requery(); + state.bindInteger(1, currentMaxId); + state.bindLong(2, dialog_id); + state.step(); + state.dispose(); + + database.commitTransaction(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void putContacts(ArrayList contacts, final boolean deleteAll) { + if (contacts.isEmpty()) { + return; + } + final ArrayList contactsCopy = new ArrayList<>(contacts); + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (deleteAll) { + database.executeFast("DELETE FROM contacts WHERE 1").stepThis().dispose(); + } + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO contacts VALUES(?, ?)"); + for (int a = 0; a < contactsCopy.size(); a++) { + TLRPC.TL_contact contact = contactsCopy.get(a); + state.requery(); + state.bindInteger(1, contact.user_id); + state.bindInteger(2, contact.mutual ? 1 : 0); + state.step(); + } + state.dispose(); + database.commitTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void deleteContacts(final ArrayList uids) { + if (uids == null || uids.isEmpty()) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + String ids = TextUtils.join(",", uids); + database.executeFast("DELETE FROM contacts WHERE uid IN(" + ids + ")").stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void applyPhoneBookUpdates(final String adds, final String deletes) { + if (adds.length() == 0 && deletes.length() == 0) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (adds.length() != 0) { + database.executeFast(String.format(Locale.US, "UPDATE user_phones_v6 SET deleted = 0 WHERE sphone IN(%s)", adds)).stepThis().dispose(); + } + if (deletes.length() != 0) { + database.executeFast(String.format(Locale.US, "UPDATE user_phones_v6 SET deleted = 1 WHERE sphone IN(%s)", deletes)).stepThis().dispose(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void putCachedPhoneBook(final HashMap contactHashMap) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO user_contacts_v6 VALUES(?, ?, ?)"); + SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO user_phones_v6 VALUES(?, ?, ?, ?)"); + for (HashMap.Entry entry : contactHashMap.entrySet()) { + ContactsController.Contact contact = entry.getValue(); + if (contact.phones.isEmpty() || contact.shortPhones.isEmpty()) { + continue; + } + state.requery(); + state.bindInteger(1, contact.id); + state.bindString(2, contact.first_name); + state.bindString(3, contact.last_name); + state.step(); + for (int a = 0; a < contact.phones.size(); a++) { + state2.requery(); + state2.bindInteger(1, contact.id); + state2.bindString(2, contact.phones.get(a)); + state2.bindString(3, contact.shortPhones.get(a)); + state2.bindInteger(4, contact.phoneDeleted.get(a)); + state2.step(); + } + } + state.dispose(); + state2.dispose(); + database.commitTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void getCachedPhoneBook() { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + HashMap contactHashMap = new HashMap<>(); + try { + SQLiteCursor cursor = database.queryFinalized("SELECT us.uid, us.fname, us.sname, up.phone, up.sphone, up.deleted FROM user_contacts_v6 as us LEFT JOIN user_phones_v6 as up ON us.uid = up.uid WHERE 1"); + while (cursor.next()) { + int uid = cursor.intValue(0); + ContactsController.Contact contact = contactHashMap.get(uid); + if (contact == null) { + contact = new ContactsController.Contact(); + contact.first_name = cursor.stringValue(1); + contact.last_name = cursor.stringValue(2); + contact.id = uid; + contactHashMap.put(uid, contact); + } + String phone = cursor.stringValue(3); + if (phone == null) { + continue; + } + contact.phones.add(phone); + String sphone = cursor.stringValue(4); + if (sphone == null) { + continue; + } + if (sphone.length() == 8 && phone.length() != 8) { + sphone = PhoneFormat.stripExceptNumbers(phone); + } + contact.shortPhones.add(sphone); + contact.phoneDeleted.add(cursor.intValue(5)); + contact.phoneTypes.add(""); + } + cursor.dispose(); + } catch (Exception e) { + contactHashMap.clear(); + FileLog.e("tmessages", e); + } + ContactsController.getInstance().performSyncPhoneBook(contactHashMap, true, true, false); + } + }); + } + + public void getContacts() { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + ArrayList contacts = new ArrayList<>(); + ArrayList users = new ArrayList<>(); + try { + SQLiteCursor cursor = database.queryFinalized("SELECT * FROM contacts WHERE 1"); + StringBuilder uids = new StringBuilder(); + while (cursor.next()) { + int user_id = cursor.intValue(0); + TLRPC.TL_contact contact = new TLRPC.TL_contact(); + contact.user_id = user_id; + contact.mutual = cursor.intValue(1) == 1; + if (uids.length() != 0) { + uids.append(","); + } + contacts.add(contact); + uids.append(contact.user_id); + } + cursor.dispose(); + + if (uids.length() != 0) { + getUsersInternal(uids.toString(), users); + } + } catch (Exception e) { + contacts.clear(); + users.clear(); + FileLog.e("tmessages", e); + } + ContactsController.getInstance().processLoadedContacts(contacts, users, 1); + } + }); + } + + public void getUnsentMessages(final int count) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + HashMap messageHashMap = new HashMap<>(); + ArrayList messages = new ArrayList<>(); + ArrayList users = new ArrayList<>(); + ArrayList chats = new ArrayList<>(); + ArrayList encryptedChats = new ArrayList<>(); + + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + ArrayList broadcastIds = new ArrayList<>(); + ArrayList encryptedChatIds = new ArrayList<>(); + SQLiteCursor cursor = database.queryFinalized("SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.uid, s.seq_in, s.seq_out, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid LEFT JOIN messages_seq as s ON m.mid = s.mid WHERE m.mid < 0 AND m.send_state = 1 ORDER BY m.mid DESC LIMIT " + count); + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(1)); + if (cursor.byteBufferValue(1, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + if (!messageHashMap.containsKey(message.id)) { + MessageObject.setUnreadFlags(message, cursor.intValue(0)); + message.id = cursor.intValue(3); + message.date = cursor.intValue(4); + if (!cursor.isNull(5)) { + message.random_id = cursor.longValue(5); + } + message.dialog_id = cursor.longValue(6); + message.seq_in = cursor.intValue(7); + message.seq_out = cursor.intValue(8); + message.ttl = cursor.intValue(9); + messages.add(message); + messageHashMap.put(message.id, message); + + int lower_id = (int) message.dialog_id; + int high_id = (int) (message.dialog_id >> 32); + + if (lower_id != 0) { + if (high_id == 1) { + if (!broadcastIds.contains(lower_id)) { + broadcastIds.add(lower_id); + } + } else { + if (lower_id < 0) { + if (!chatsToLoad.contains(-lower_id)) { + chatsToLoad.add(-lower_id); + } + } else { + if (!usersToLoad.contains(lower_id)) { + usersToLoad.add(lower_id); + } + } + } + } else { + if (!encryptedChatIds.contains(high_id)) { + encryptedChatIds.add(high_id); + } + } + + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + + message.send_state = cursor.intValue(2); + if (message.to_id.channel_id == 0 && !MessageObject.isUnread(message) && lower_id != 0 || message.id > 0) { + message.send_state = 0; + } + if (lower_id == 0 && !cursor.isNull(5)) { + message.random_id = cursor.longValue(5); + } + } + } + data.reuse(); + } + cursor.dispose(); + + + if (!encryptedChatIds.isEmpty()) { + getEncryptedChatsInternal(TextUtils.join(",", encryptedChatIds), encryptedChats, usersToLoad); + } + + if (!usersToLoad.isEmpty()) { + getUsersInternal(TextUtils.join(",", usersToLoad), users); + } + + if (!chatsToLoad.isEmpty() || !broadcastIds.isEmpty()) { + StringBuilder stringToLoad = new StringBuilder(); + for (int a = 0; a < chatsToLoad.size(); a++) { + Integer cid = chatsToLoad.get(a); + if (stringToLoad.length() != 0) { + stringToLoad.append(","); + } + stringToLoad.append(cid); + } + for (int a = 0; a < broadcastIds.size(); a++) { + Integer cid = broadcastIds.get(a); + if (stringToLoad.length() != 0) { + stringToLoad.append(","); + } + stringToLoad.append(-cid); + } + getChatsInternal(stringToLoad.toString(), chats); + } + + SendMessagesHelper.getInstance().processUnsentMessages(messages, users, chats, encryptedChats); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public boolean checkMessageId(final long dialog_id, final int mid) { + final boolean[] result = new boolean[1]; + final Semaphore semaphore = new Semaphore(0); + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + SQLiteCursor cursor = null; + try { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM messages WHERE uid = %d AND mid = %d", dialog_id, mid)); + if (cursor.next()) { + result[0] = true; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + semaphore.release(); + } + }); + try { + semaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return result[0]; + } + + public void getMessages(final long dialog_id, final int count, final int max_id, final int minDate, final int classGuid, final int load_type, final int important, final int loadIndex) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + TLRPC.TL_messages_messages res = new TLRPC.TL_messages_messages(); + int count_unread = 0; + int count_query = count; + int offset_query = 0; + int min_unread_id = 0; + int last_message_id = 0; + boolean queryFromServer = false; + int max_unread_date = 0; + long messageMaxId = max_id; + int max_id_query = max_id; + int channelId = 0; + if (important != 0) { + channelId = -(int) dialog_id; + } + if (messageMaxId != 0 && channelId != 0) { + messageMaxId |= ((long) channelId) << 32; + } + boolean isEnd = false; + int num = dialog_id == 777000 ? 4 : 1; + try { + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + ArrayList replyMessages = new ArrayList<>(); + HashMap> replyMessageOwners = new HashMap<>(); + HashMap> replyMessageRandomOwners = new HashMap<>(); + + SQLiteCursor cursor; + int lower_id = (int) dialog_id; + if (lower_id != 0) { + String imp = important == 2 ? " AND imp = 1 " : ""; + String holesTable = important == 2 ? "messages_imp_holes" : "messages_holes"; + + if (load_type != 1 && load_type != 3 && minDate == 0) { + if (load_type == 2) { + cursor = database.queryFinalized("SELECT inbox_max, unread_count, date FROM dialogs WHERE did = " + dialog_id); + if (cursor.next()) { + messageMaxId = max_id_query = min_unread_id = cursor.intValue(0); + count_unread = cursor.intValue(1); + max_unread_date = cursor.intValue(2); + queryFromServer = true; + if (messageMaxId != 0 && channelId != 0) { + messageMaxId |= ((long) channelId) << 32; + } + } + cursor.dispose(); + if (!queryFromServer) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid), max(date) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid > 0" + imp, dialog_id)); + if (cursor.next()) { + min_unread_id = cursor.intValue(0); + max_unread_date = cursor.intValue(1); + } + cursor.dispose(); + if (min_unread_id != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid >= %d " + imp + "AND out = 0 AND read_state IN(0,2)", dialog_id, min_unread_id)); + if (cursor.next()) { + count_unread = cursor.intValue(0); + } + cursor.dispose(); + } + } else if (max_id_query == 0) { + int existingUnreadCount = 0; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid > 0 " + imp + "AND out = 0 AND read_state IN(0,2)", dialog_id)); + if (cursor.next()) { + existingUnreadCount = cursor.intValue(0); + } + cursor.dispose(); + if (existingUnreadCount == count_unread) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid > 0" + imp, dialog_id)); + if (cursor.next()) { + messageMaxId = max_id_query = min_unread_id = cursor.intValue(0); + } + cursor.dispose(); + } + } + } + + if (count_query > count_unread || count_unread < num) { + count_query = Math.max(count_query, count_unread + 10); + if (count_unread < num) { + count_unread = 0; + min_unread_id = 0; + messageMaxId = 0; + last_message_id = 0; + queryFromServer = false; + } + } else { + offset_query = count_unread - count_query; + count_query += 10; + } + } + + cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM " + holesTable + " WHERE uid = %d AND start IN (0, 1)", dialog_id)); + if (cursor.next()) { + isEnd = cursor.intValue(0) == 1; + cursor.dispose(); + } else { + cursor.dispose(); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid > 0", dialog_id)); + if (cursor.next()) { + int mid = cursor.intValue(0); + if (mid != 0) { + SQLitePreparedStatement state = database.executeFast("REPLACE INTO " + holesTable + " VALUES(?, ?, ?)"); + state.requery(); + state.bindLong(1, dialog_id); + state.bindInteger(2, 0); + state.bindInteger(3, mid); + state.step(); + state.dispose(); + } + } + cursor.dispose(); + } + + if (load_type == 3 || queryFromServer && load_type == 2) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid) FROM messages WHERE uid = %d AND mid > 0", dialog_id)); + if (cursor.next()) { + last_message_id = cursor.intValue(0); + } + cursor.dispose(); + + boolean containMessage = max_id_query != 0; + if (containMessage) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM " + holesTable + " WHERE uid = %d AND start < %d AND end > %d", dialog_id, max_id_query, max_id_query)); + if (cursor.next()) { + containMessage = false; + } + cursor.dispose(); + } + + if (containMessage) { + long holeMessageMaxId = 0; + long holeMessageMinId = 1; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM " + holesTable + " WHERE uid = %d AND start >= %d ORDER BY start ASC LIMIT 1", dialog_id, max_id_query)); + if (cursor.next()) { + holeMessageMaxId = cursor.intValue(0); + if (channelId != 0) { + holeMessageMaxId |= ((long) channelId) << 32; + } + } + cursor.dispose(); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT end FROM " + holesTable + " WHERE uid = %d AND end <= %d ORDER BY end DESC LIMIT 1", dialog_id, max_id_query)); + if (cursor.next()) { + holeMessageMinId = cursor.intValue(0); + if (channelId != 0) { + holeMessageMinId |= ((long) channelId) << 32; + } + } + /*if (holeMessageMaxId == holeMessageMinId) { + holeMessageMaxId = 0; + holeMessageMinId = 1; + }*/ + cursor.dispose(); + if (holeMessageMaxId != 0 || holeMessageMinId != 1) { + if (holeMessageMaxId == 0) { + holeMessageMaxId = 1000000000; + if (channelId != 0) { + holeMessageMaxId |= ((long) channelId) << 32; + } + } + cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid <= %d AND m.mid >= %d " + imp + "ORDER BY m.date DESC, m.mid DESC LIMIT %d) UNION " + + "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d AND m.mid <= %d " + imp + "ORDER BY m.date ASC, m.mid ASC LIMIT %d)", dialog_id, messageMaxId, holeMessageMinId, count_query / 2, dialog_id, messageMaxId, holeMessageMaxId, count_query / 2)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid <= %d " + imp + "ORDER BY m.date DESC, m.mid DESC LIMIT %d) UNION " + + "SELECT * FROM (SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d " + imp + "ORDER BY m.date ASC, m.mid ASC LIMIT %d)", dialog_id, messageMaxId, count_query / 2, dialog_id, messageMaxId, count_query / 2)); + } + } else { + cursor = null; + } + } else if (load_type == 1) { + long holeMessageId = 0; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT start, end FROM " + holesTable + " WHERE uid = %d AND start >= %d AND start != 1 AND end != 1 ORDER BY start ASC LIMIT 1", dialog_id, max_id)); + if (cursor.next()) { + holeMessageId = cursor.intValue(0); + if (channelId != 0) { + holeMessageId |= ((long) channelId) << 32; + } + } + cursor.dispose(); + if (holeMessageId != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date >= %d AND m.mid > %d AND m.mid <= %d " + imp + "ORDER BY m.date ASC, m.mid ASC LIMIT %d", dialog_id, minDate, messageMaxId, holeMessageId, count_query)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date >= %d AND m.mid > %d " + imp + "ORDER BY m.date ASC, m.mid ASC LIMIT %d", dialog_id, minDate, messageMaxId, count_query)); + } + } else if (minDate != 0) { + if (messageMaxId != 0) { + long holeMessageId = 0; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT end FROM " + holesTable + " WHERE uid = %d AND end <= %d ORDER BY end DESC LIMIT 1", dialog_id, max_id)); + if (cursor.next()) { + holeMessageId = cursor.intValue(0); + if (channelId != 0) { + holeMessageId |= ((long) channelId) << 32; + } + } + cursor.dispose(); + if (holeMessageId != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d AND m.mid < %d AND (m.mid >= %d OR m.mid < 0) " + imp + "ORDER BY m.date DESC, m.mid DESC LIMIT %d", dialog_id, minDate, messageMaxId, holeMessageId, count_query)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d AND m.mid < %d " + imp + "ORDER BY m.date DESC, m.mid DESC LIMIT %d", dialog_id, minDate, messageMaxId, count_query)); + } + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d " + imp + "ORDER BY m.date DESC, m.mid DESC LIMIT %d,%d", dialog_id, minDate, offset_query, count_query)); + } + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid) FROM messages WHERE uid = %d AND mid > 0", dialog_id)); + if (cursor.next()) { + last_message_id = cursor.intValue(0); + } + cursor.dispose(); + + long holeMessageId = 0; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(end) FROM " + holesTable + " WHERE uid = %d", dialog_id)); + if (cursor.next()) { + holeMessageId = cursor.intValue(0); + if (channelId != 0) { + holeMessageId |= ((long) channelId) << 32; + } + } + cursor.dispose(); + if (holeMessageId != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND (m.mid >= %d OR m.mid < 0) " + imp + "ORDER BY m.date DESC, m.mid DESC LIMIT %d,%d", dialog_id, holeMessageId, offset_query, count_query)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d " + imp + "ORDER BY m.date DESC, m.mid DESC LIMIT %d,%d", dialog_id, offset_query, count_query)); + } + } + } else { + isEnd = true; + if (load_type == 1) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid < %d ORDER BY m.mid DESC LIMIT %d", dialog_id, max_id, count_query)); + } else if (minDate != 0) { + if (max_id != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d ORDER BY m.mid ASC LIMIT %d", dialog_id, max_id, count_query)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.date <= %d ORDER BY m.mid ASC LIMIT %d,%d", dialog_id, minDate, offset_query, count_query)); + } + } else { + if (load_type == 2) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM messages WHERE uid = %d AND mid < 0", dialog_id)); + if (cursor.next()) { + last_message_id = cursor.intValue(0); + } + cursor.dispose(); + + cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(mid), max(date) FROM messages WHERE uid = %d AND out = 0 AND read_state IN(0,2) AND mid < 0", dialog_id)); + if (cursor.next()) { + min_unread_id = cursor.intValue(0); + max_unread_date = cursor.intValue(1); + } + cursor.dispose(); + if (min_unread_id != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT COUNT(*) FROM messages WHERE uid = %d AND mid <= %d AND out = 0 AND read_state IN(0,2)", dialog_id, min_unread_id)); + if (cursor.next()) { + count_unread = cursor.intValue(0); + } + cursor.dispose(); + } + } + + if (count_query > count_unread || count_unread < num) { + count_query = Math.max(count_query, count_unread + 10); + if (count_unread < num) { + count_unread = 0; + min_unread_id = 0; + last_message_id = 0; + } + } else { + offset_query = count_unread - count_query; + count_query += 10; + } + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.read_state, m.data, m.send_state, m.mid, m.date, r.random_id, m.replydata, m.media, m.ttl FROM messages as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d ORDER BY m.mid ASC LIMIT %d,%d", dialog_id, offset_query, count_query)); + } + } + if (cursor != null) { + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(1)); + if (cursor.byteBufferValue(1, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + MessageObject.setUnreadFlags(message, cursor.intValue(0)); + message.id = cursor.intValue(3); + message.date = cursor.intValue(4); + message.dialog_id = dialog_id; + if ((message.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { + message.views = cursor.intValue(7); + } + message.ttl = cursor.intValue(8); + res.messages.add(message); + + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + + if (message.reply_to_msg_id != 0 || message.reply_to_random_id != 0) { + if (!cursor.isNull(6)) { + NativeByteBuffer data2 = new NativeByteBuffer(cursor.byteArrayLength(6)); + if (cursor.byteBufferValue(6, data2) != 0) { + message.replyMessage = TLRPC.Message.TLdeserialize(data2, data2.readInt32(false), false); + if (message.replyMessage != null) { + addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad); + } + } + data2.reuse(); + } + if (message.replyMessage == null) { + if (message.reply_to_msg_id != 0) { + long messageId = message.reply_to_msg_id; + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; + } + if (!replyMessages.contains(messageId)) { + replyMessages.add(messageId); + } + ArrayList messages = replyMessageOwners.get(message.reply_to_msg_id); + if (messages == null) { + messages = new ArrayList<>(); + replyMessageOwners.put(message.reply_to_msg_id, messages); + } + messages.add(message); + } else { + if (!replyMessages.contains(message.reply_to_random_id)) { + replyMessages.add(message.reply_to_random_id); + } + ArrayList messages = replyMessageRandomOwners.get(message.reply_to_random_id); + if (messages == null) { + messages = new ArrayList<>(); + replyMessageRandomOwners.put(message.reply_to_random_id, messages); + } + messages.add(message); + } + } + } + message.send_state = cursor.intValue(2); + if (message.id > 0 && message.send_state != 0) { + message.send_state = 0; + } + if (lower_id == 0 && !cursor.isNull(5)) { + message.random_id = cursor.longValue(5); + } + if ((int) dialog_id == 0 && message.media != null && message.media.photo != null) { + try { + SQLiteCursor cursor2 = database.queryFinalized(String.format(Locale.US, "SELECT date FROM enc_tasks_v2 WHERE mid = %d", message.id)); + if (cursor2.next()) { + message.destroyTime = cursor2.intValue(0); + } + cursor2.dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + data.reuse(); + } + cursor.dispose(); + } + + Collections.sort(res.messages, new Comparator() { + @Override + public int compare(TLRPC.Message lhs, TLRPC.Message rhs) { + if (lhs.id > 0 && rhs.id > 0) { + if (lhs.id > rhs.id) { + return -1; + } else if (lhs.id < rhs.id) { + return 1; + } + } else if (lhs.id < 0 && rhs.id < 0) { + if (lhs.id < rhs.id) { + return -1; + } else if (lhs.id > rhs.id) { + return 1; + } + } else { + if (lhs.date > rhs.date) { + return -1; + } else if (lhs.date < rhs.date) { + return 1; + } + } + return 0; + } + }); + + if ((load_type == 3 || load_type == 2 && queryFromServer) && !res.messages.isEmpty()) { + int minId = res.messages.get(res.messages.size() - 1).id; + int maxId = res.messages.get(0).id; + if (!(minId <= max_id_query && maxId >= max_id_query)) { + replyMessages.clear(); + usersToLoad.clear(); + chatsToLoad.clear(); + res.messages.clear(); + } + } + if (load_type == 3 && res.messages.size() == 1) { + res.messages.clear(); + } + + if (important == 2 && !res.messages.isEmpty()) { + if (max_id != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT start, end, count FROM channel_group WHERE uid = %d AND ((start >= %d AND end <= %d) OR (start = %d))", dialog_id, res.messages.get(res.messages.size() - 1).id, res.messages.get(0).id, res.messages.get(0).id)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT start, end, count FROM channel_group WHERE uid = %d AND start >= %d", dialog_id, res.messages.get(res.messages.size() - 1).id)); + } + while (cursor.next()) { + TLRPC.TL_messageGroup group = new TLRPC.TL_messageGroup(); + group.min_id = cursor.intValue(0); + group.max_id = cursor.intValue(1); + group.count = cursor.intValue(2); + res.collapsed.add(group); + } + cursor.dispose(); + } + + if (!replyMessages.isEmpty()) { + if (!replyMessageOwners.isEmpty()) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date FROM messages WHERE mid IN(%s)", TextUtils.join(",", replyMessages))); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.data, m.mid, m.date, r.random_id FROM randoms as r INNER JOIN messages as m ON r.mid = m.mid WHERE r.random_id IN(%s)", TextUtils.join(",", replyMessages))); + } + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.id = cursor.intValue(1); + message.date = cursor.intValue(2); + message.dialog_id = dialog_id; + + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + + if (!replyMessageOwners.isEmpty()) { + ArrayList arrayList = replyMessageOwners.get(message.id); + if (arrayList != null) { + for (int a = 0; a < arrayList.size(); a++) { + arrayList.get(a).replyMessage = message; + } + } + } else { + ArrayList arrayList = replyMessageRandomOwners.remove(cursor.longValue(3)); + if (arrayList != null) { + for (int a = 0; a < arrayList.size(); a++) { + TLRPC.Message object = arrayList.get(a); + object.replyMessage = message; + object.reply_to_msg_id = message.id; + } + } + } + } + data.reuse(); + } + cursor.dispose(); + if (!replyMessageRandomOwners.isEmpty()) { + for (HashMap.Entry> entry : replyMessageRandomOwners.entrySet()) { + ArrayList arrayList = entry.getValue(); + for (int a = 0; a < arrayList.size(); a++) { + arrayList.get(a).reply_to_random_id = 0; + } + } + } + } + + if (!usersToLoad.isEmpty()) { + getUsersInternal(TextUtils.join(",", usersToLoad), res.users); + } + if (!chatsToLoad.isEmpty()) { + getChatsInternal(TextUtils.join(",", chatsToLoad), res.chats); + } + } catch (Exception e) { + res.messages.clear(); + res.chats.clear(); + res.users.clear(); + res.collapsed.clear(); + FileLog.e("tmessages", e); + } finally { + MessagesController.getInstance().processLoadedMessages(res, dialog_id, count_query, max_id, true, classGuid, min_unread_id, last_message_id, count_unread, max_unread_date, load_type, important, isEnd, loadIndex, queryFromServer); + } + } + }); + } + + public void startTransaction(boolean useQueue) { + if (useQueue) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + database.beginTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } else { + try { + database.beginTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + public void commitTransaction(boolean useQueue) { + if (useQueue) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + database.commitTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } else { + try { + database.commitTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + public TLObject getSentFile(final String path, final int type) { + if (path == null) { + return null; + } + final Semaphore semaphore = new Semaphore(0); + final ArrayList result = new ArrayList<>(); + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + String id = Utilities.MD5(path); + if (id != null) { + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM sent_files_v2 WHERE uid = '%s' AND type = %d", id, type)); + if (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + TLObject file = TLRPC.MessageMedia.TLdeserialize(data, data.readInt32(false), false); + if (file instanceof TLRPC.TL_messageMediaDocument) { + result.add(((TLRPC.TL_messageMediaDocument) file).document); + } else if (file instanceof TLRPC.TL_messageMediaPhoto) { + result.add(((TLRPC.TL_messageMediaDocument) file).photo); + } + } + data.reuse(); + } + cursor.dispose(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + semaphore.release(); + } + } + }); + try { + semaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return !result.isEmpty() ? result.get(0) : null; + } + + public void putSentFile(final String path, final TLObject file, final int type) { + if (path == null || file == null) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + SQLitePreparedStatement state = null; + try { + String id = Utilities.MD5(path); + if (id != null) { + TLRPC.MessageMedia messageMedia = null; + if (file instanceof TLRPC.Photo) { + messageMedia = new TLRPC.TL_messageMediaPhoto(); + messageMedia.caption = ""; + messageMedia.photo = (TLRPC.Photo) file; + } else if (file instanceof TLRPC.Document) { + messageMedia = new TLRPC.TL_messageMediaDocument(); + messageMedia.caption = ""; + messageMedia.document = (TLRPC.Document) file; + } + if (messageMedia == null) { + return; + } + state = database.executeFast("REPLACE INTO sent_files_v2 VALUES(?, ?, ?)"); + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(messageMedia.getObjectSize()); + messageMedia.serializeToStream(data); + state.bindString(1, id); + state.bindInteger(2, type); + state.bindByteBuffer(3, data); + state.step(); + data.reuse(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (state != null) { + state.dispose(); + } + } + } + }); + } + + public void updateEncryptedChatSeq(final TLRPC.EncryptedChat chat) { + if (chat == null) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + SQLitePreparedStatement state = null; + try { + state = database.executeFast("UPDATE enc_chats SET seq_in = ?, seq_out = ?, use_count = ? WHERE uid = ?"); + state.bindInteger(1, chat.seq_in); + state.bindInteger(2, chat.seq_out); + state.bindInteger(3, (int)chat.key_use_count_in << 16 | chat.key_use_count_out); + state.bindInteger(4, chat.id); + state.step(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (state != null) { + state.dispose(); + } + } + } + }); + } + + public void updateEncryptedChatTTL(final TLRPC.EncryptedChat chat) { + if (chat == null) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + SQLitePreparedStatement state = null; + try { + state = database.executeFast("UPDATE enc_chats SET ttl = ? WHERE uid = ?"); + state.bindInteger(1, chat.ttl); + state.bindInteger(2, chat.id); + state.step(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (state != null) { + state.dispose(); + } + } + } + }); + } + + public void updateEncryptedChatLayer(final TLRPC.EncryptedChat chat) { + if (chat == null) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + SQLitePreparedStatement state = null; + try { + state = database.executeFast("UPDATE enc_chats SET layer = ? WHERE uid = ?"); + state.bindInteger(1, chat.layer); + state.bindInteger(2, chat.id); + state.step(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (state != null) { + state.dispose(); + } + } + } + }); + } + + public void updateEncryptedChat(final TLRPC.EncryptedChat chat) { + if (chat == null) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + SQLitePreparedStatement state = null; + try { + if ((chat.key_hash == null || chat.key_hash.length < 16) && chat.auth_key != null) { + chat.key_hash = AndroidUtilities.calcAuthKeyHash(chat.auth_key); + } + + state = database.executeFast("UPDATE enc_chats SET data = ?, g = ?, authkey = ?, ttl = ?, layer = ?, seq_in = ?, seq_out = ?, use_count = ?, exchange_id = ?, key_date = ?, fprint = ?, fauthkey = ?, khash = ? WHERE uid = ?"); + NativeByteBuffer data = new NativeByteBuffer(chat.getObjectSize()); + NativeByteBuffer data2 = new NativeByteBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1); + NativeByteBuffer data3 = new NativeByteBuffer(chat.auth_key != null ? chat.auth_key.length : 1); + NativeByteBuffer data4 = new NativeByteBuffer(chat.future_auth_key != null ? chat.future_auth_key.length : 1); + NativeByteBuffer data5 = new NativeByteBuffer(chat.key_hash != null ? chat.key_hash.length : 1); + chat.serializeToStream(data); + state.bindByteBuffer(1, data); + if (chat.a_or_b != null) { + data2.writeBytes(chat.a_or_b); + } + if (chat.auth_key != null) { + data3.writeBytes(chat.auth_key); + } + if (chat.future_auth_key != null) { + data4.writeBytes(chat.future_auth_key); + } + if (chat.key_hash != null) { + data5.writeBytes(chat.key_hash); + } + state.bindByteBuffer(2, data2); + state.bindByteBuffer(3, data3); + state.bindInteger(4, chat.ttl); + state.bindInteger(5, chat.layer); + state.bindInteger(6, chat.seq_in); + state.bindInteger(7, chat.seq_out); + state.bindInteger(8, (int) chat.key_use_count_in << 16 | chat.key_use_count_out); + state.bindLong(9, chat.exchange_id); + state.bindInteger(10, chat.key_create_date); + state.bindLong(11, chat.future_key_fingerprint); + state.bindByteBuffer(12, data4); + state.bindByteBuffer(13, data5); + state.bindInteger(14, chat.id); + + state.step(); + data.reuse(); + data2.reuse(); + data3.reuse(); + data4.reuse(); + data5.reuse(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (state != null) { + state.dispose(); + } + } + } + }); + } + + public boolean isDialogHasMessages(final long did) { + final Semaphore semaphore = new Semaphore(0); + final boolean result[] = new boolean[1]; + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM messages WHERE uid = %d LIMIT 1", did)); + result[0] = cursor.next(); + cursor.dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + semaphore.release(); + } + } + }); + try { + semaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return result[0]; + } + + public void getEncryptedChat(final int chat_id, final Semaphore semaphore, final ArrayList result) { + if (semaphore == null || result == null) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + ArrayList usersToLoad = new ArrayList<>(); + ArrayList encryptedChats = new ArrayList<>(); + getEncryptedChatsInternal("" + chat_id, encryptedChats, usersToLoad); + if (!encryptedChats.isEmpty() && !usersToLoad.isEmpty()) { + ArrayList users = new ArrayList<>(); + getUsersInternal(TextUtils.join(",", usersToLoad), users); + if (!users.isEmpty()) { + result.add(encryptedChats.get(0)); + result.add(users.get(0)); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + semaphore.release(); + } + } + }); + } + + public void putEncryptedChat(final TLRPC.EncryptedChat chat, final TLRPC.User user, final TLRPC.Dialog dialog) { + if (chat == null) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if ((chat.key_hash == null || chat.key_hash.length < 16) && chat.auth_key != null) { + chat.key_hash = AndroidUtilities.calcAuthKeyHash(chat.auth_key); + } + SQLitePreparedStatement state = database.executeFast("REPLACE INTO enc_chats VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + NativeByteBuffer data = new NativeByteBuffer(chat.getObjectSize()); + NativeByteBuffer data2 = new NativeByteBuffer(chat.a_or_b != null ? chat.a_or_b.length : 1); + NativeByteBuffer data3 = new NativeByteBuffer(chat.auth_key != null ? chat.auth_key.length : 1); + NativeByteBuffer data4 = new NativeByteBuffer(chat.future_auth_key != null ? chat.future_auth_key.length : 1); + NativeByteBuffer data5 = new NativeByteBuffer(chat.key_hash != null ? chat.key_hash.length : 1); + + chat.serializeToStream(data); + state.bindInteger(1, chat.id); + state.bindInteger(2, user.id); + state.bindString(3, formatUserSearchName(user)); + state.bindByteBuffer(4, data); + if (chat.a_or_b != null) { + data2.writeBytes(chat.a_or_b); + } + if (chat.auth_key != null) { + data3.writeBytes(chat.auth_key); + } + if (chat.future_auth_key != null) { + data4.writeBytes(chat.future_auth_key); + } + if (chat.key_hash != null) { + data5.writeBytes(chat.key_hash); + } + state.bindByteBuffer(5, data2); + state.bindByteBuffer(6, data3); + state.bindInteger(7, chat.ttl); + state.bindInteger(8, chat.layer); + state.bindInteger(9, chat.seq_in); + state.bindInteger(10, chat.seq_out); + state.bindInteger(11, (int) chat.key_use_count_in << 16 | chat.key_use_count_out); + state.bindLong(12, chat.exchange_id); + state.bindInteger(13, chat.key_create_date); + state.bindLong(14, chat.future_key_fingerprint); + state.bindByteBuffer(15, data4); + state.bindByteBuffer(16, data5); + + state.step(); + state.dispose(); + data.reuse(); + data2.reuse(); + data3.reuse(); + data4.reuse(); + data5.reuse(); + if (dialog != null) { + state = database.executeFast("REPLACE INTO dialogs VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + state.bindLong(1, dialog.id); + state.bindInteger(2, dialog.last_message_date); + state.bindInteger(3, dialog.unread_count); + state.bindInteger(4, dialog.top_message); + state.bindInteger(5, dialog.read_inbox_max_id); + state.bindInteger(6, 0); + state.bindInteger(7, dialog.top_not_important_message); + state.bindInteger(8, dialog.unread_not_important_count); + state.bindInteger(9, dialog.pts); + state.bindInteger(10, 0); + state.step(); + state.dispose(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + private String formatUserSearchName(TLRPC.User user) { + StringBuilder str = new StringBuilder(""); + if (user.first_name != null && user.first_name.length() > 0) { + str.append(user.first_name); + } + if (user.last_name != null && user.last_name.length() > 0) { + if (str.length() > 0) { + str.append(" "); + } + str.append(user.last_name); + } + str.append(";;;"); + if (user.username != null && user.username.length() > 0) { + str.append(user.username); + } + return str.toString().toLowerCase(); + } + + private void putUsersInternal(ArrayList users) throws Exception { + if (users == null || users.isEmpty()) { + return; + } + SQLitePreparedStatement state = database.executeFast("REPLACE INTO users VALUES(?, ?, ?, ?)"); + for (int a = 0; a < users.size(); a++) { + TLRPC.User user = users.get(a); + if (user.min) { + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM users WHERE uid = %d", user.id)); + if (cursor.next()) { + try { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + TLRPC.User oldUser = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); + if (oldUser != null) { + if (user.username != null) { + oldUser.username = user.username; + oldUser.flags |= 8; + } else { + oldUser.username = null; + oldUser.flags = oldUser.flags &~ 8; + } + if (user.photo != null) { + oldUser.photo = user.photo; + oldUser.flags |= 32; + } else { + oldUser.photo = null; + oldUser.flags = oldUser.flags &~ 32; + } + user = oldUser; + } + } + data.reuse(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(user.getObjectSize()); + user.serializeToStream(data); + state.bindInteger(1, user.id); + state.bindString(2, formatUserSearchName(user)); + if (user.status != null) { + if (user.status instanceof TLRPC.TL_userStatusRecently) { + user.status.expires = -100; + } else if (user.status instanceof TLRPC.TL_userStatusLastWeek) { + user.status.expires = -101; + } else if (user.status instanceof TLRPC.TL_userStatusLastMonth) { + user.status.expires = -102; + } + state.bindInteger(3, user.status.expires); + } else { + state.bindInteger(3, 0); + } + state.bindByteBuffer(4, data); + state.step(); + data.reuse(); + } + state.dispose(); + } + + private void putChatsInternal(ArrayList chats) throws Exception { + if (chats == null || chats.isEmpty()) { + return; + } + SQLitePreparedStatement state = database.executeFast("REPLACE INTO chats VALUES(?, ?, ?)"); + for (int a = 0; a < chats.size(); a++) { + TLRPC.Chat chat = chats.get(a); + if (chat.min) { + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid = %d", chat.id)); + if (cursor.next()) { + try { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + TLRPC.Chat oldChat = TLRPC.Chat.TLdeserialize(data, data.readInt32(false), false); + if (oldChat != null) { + oldChat.title = chat.title; + oldChat.photo = chat.photo; + oldChat.broadcast = chat.broadcast; + oldChat.verified = chat.verified; + oldChat.megagroup = chat.megagroup; + oldChat.democracy = chat.democracy; + if (chat.username != null) { + oldChat.username = chat.username; + oldChat.flags |= 64; + } else { + oldChat.username = null; + oldChat.flags = oldChat.flags &~ 64; + } + chat = oldChat; + } + } + data.reuse(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(chat.getObjectSize()); + chat.serializeToStream(data); + state.bindInteger(1, chat.id); + if (chat.title != null) { + String name = chat.title.toLowerCase(); + state.bindString(2, name); + } else { + state.bindString(2, ""); + } + state.bindByteBuffer(3, data); + state.step(); + data.reuse(); + } + state.dispose(); + } + + public void getUsersInternal(String usersToLoad, ArrayList result) throws Exception { + if (usersToLoad == null || usersToLoad.length() == 0 || result == null) { + return; + } + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, status FROM users WHERE uid IN(%s)", usersToLoad)); + while (cursor.next()) { + try { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + TLRPC.User user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); + if (user != null) { + if (user.status != null) { + user.status.expires = cursor.intValue(1); + } + result.add(user); + } + } + data.reuse(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + cursor.dispose(); + } + + public void getChatsInternal(String chatsToLoad, ArrayList result) throws Exception { + if (chatsToLoad == null || chatsToLoad.length() == 0 || result == null) { + return; + } + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data FROM chats WHERE uid IN(%s)", chatsToLoad)); + while (cursor.next()) { + try { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + TLRPC.Chat chat = TLRPC.Chat.TLdeserialize(data, data.readInt32(false), false); + if (chat != null) { + result.add(chat); + } + } + data.reuse(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + cursor.dispose(); + } + + public void getEncryptedChatsInternal(String chatsToLoad, ArrayList result, ArrayList usersToLoad) throws Exception { + if (chatsToLoad == null || chatsToLoad.length() == 0 || result == null) { + return; + } + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, user, g, authkey, ttl, layer, seq_in, seq_out, use_count, exchange_id, key_date, fprint, fauthkey, khash FROM enc_chats WHERE uid IN(%s)", chatsToLoad)); + while (cursor.next()) { + try { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + TLRPC.EncryptedChat chat = TLRPC.EncryptedChat.TLdeserialize(data, data.readInt32(false), false); + if (chat != null) { + chat.user_id = cursor.intValue(1); + if (usersToLoad != null && !usersToLoad.contains(chat.user_id)) { + usersToLoad.add(chat.user_id); + } + chat.a_or_b = cursor.byteArrayValue(2); + chat.auth_key = cursor.byteArrayValue(3); + chat.ttl = cursor.intValue(4); + chat.layer = cursor.intValue(5); + chat.seq_in = cursor.intValue(6); + chat.seq_out = cursor.intValue(7); + int use_count = cursor.intValue(8); + chat.key_use_count_in = (short)(use_count >> 16); + chat.key_use_count_out = (short)(use_count); + chat.exchange_id = cursor.longValue(9); + chat.key_create_date = cursor.intValue(10); + chat.future_key_fingerprint = cursor.longValue(11); + chat.future_auth_key = cursor.byteArrayValue(12); + chat.key_hash = cursor.byteArrayValue(13); + result.add(chat); + } + } + data.reuse(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + cursor.dispose(); + } + + private void putUsersAndChatsInternal(final ArrayList users, final ArrayList chats, final boolean withTransaction) { + try { + if (withTransaction) { + database.beginTransaction(); + } + putUsersInternal(users); + putChatsInternal(chats); + if (withTransaction) { + database.commitTransaction(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void putUsersAndChats(final ArrayList users, final ArrayList chats, final boolean withTransaction, boolean useQueue) { + if (users != null && users.isEmpty() && chats != null && chats.isEmpty()) { + return; + } + if (useQueue) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + putUsersAndChatsInternal(users, chats, withTransaction); + } + }); + } else { + putUsersAndChatsInternal(users, chats, withTransaction); + } + } + + public void removeFromDownloadQueue(final long id, final int type, final boolean move) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (move) { + int minDate = -1; + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(date) FROM download_queue WHERE type = %d", type)); + if (cursor.next()) { + minDate = cursor.intValue(0); + } + cursor.dispose(); + if (minDate != -1) { + database.executeFast(String.format(Locale.US, "UPDATE download_queue SET date = %d WHERE uid = %d AND type = %d", minDate - 1, id, type)).stepThis().dispose(); + } + } else { + database.executeFast(String.format(Locale.US, "DELETE FROM download_queue WHERE uid = %d AND type = %d", id, type)).stepThis().dispose(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void clearDownloadQueue(final int type) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (type == 0) { + database.executeFast("DELETE FROM download_queue WHERE 1").stepThis().dispose(); + } else { + database.executeFast(String.format(Locale.US, "DELETE FROM download_queue WHERE type = %d", type)).stepThis().dispose(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void getDownloadQueue(final int type) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + final ArrayList objects = new ArrayList<>(); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid, type, data FROM download_queue WHERE type = %d ORDER BY date DESC LIMIT 3", type)); + while (cursor.next()) { + DownloadObject downloadObject = new DownloadObject(); + downloadObject.type = cursor.intValue(1); + downloadObject.id = cursor.longValue(0); + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(2)); + if (cursor.byteBufferValue(2, data) != 0) { + TLRPC.MessageMedia messageMedia = TLRPC.MessageMedia.TLdeserialize(data, data.readInt32(false), false); + if (messageMedia.document != null) { + downloadObject.object = messageMedia.document; + } else if (messageMedia.photo != null) { + downloadObject.object = FileLoader.getClosestPhotoSizeWithSize(messageMedia.photo.sizes, AndroidUtilities.getPhotoSize()); + } + } + data.reuse(); + objects.add(downloadObject); + } + cursor.dispose(); + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MediaController.getInstance().processDownloadObjects(type, objects); + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + private int getMessageMediaType(TLRPC.Message message) { + if (message instanceof TLRPC.TL_message_secret && ( + message.media instanceof TLRPC.TL_messageMediaPhoto && message.ttl > 0 && message.ttl <= 60 || + MessageObject.isVoiceMessage(message) || + MessageObject.isVideoMessage(message))) { + return 1; + } else if (message.media instanceof TLRPC.TL_messageMediaPhoto || MessageObject.isVideoMessage(message)) { + return 0; + } + return -1; + } + + public void putWebPages(final HashMap webPages) { + if (webPages == null || webPages.isEmpty()) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + String ids = TextUtils.join(",", webPages.keySet()); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM webpage_pending WHERE id IN (%s)", ids)); + ArrayList mids = new ArrayList<>(); + while (cursor.next()) { + mids.add(cursor.longValue(0)); + } + cursor.dispose(); + + if (mids.isEmpty()) { + return; + } + final ArrayList messages = new ArrayList<>(); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid, data FROM messages WHERE mid IN (%s)", TextUtils.join(",", mids))); + while (cursor.next()) { + int mid = cursor.intValue(0); + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(1)); + if (cursor.byteBufferValue(1, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + if (message.media instanceof TLRPC.TL_messageMediaWebPage) { + message.id = mid; + message.media.webpage = webPages.get(message.media.webpage.id); + messages.add(message); + } + } + data.reuse(); + } + cursor.dispose(); + + database.executeFast(String.format(Locale.US, "DELETE FROM webpage_pending WHERE id IN (%s)", ids)).stepThis().dispose(); + + if (messages.isEmpty()) { + return; + } + + database.beginTransaction(); + + SQLitePreparedStatement state = database.executeFast("UPDATE messages SET data = ? WHERE mid = ?"); + SQLitePreparedStatement state2 = database.executeFast("UPDATE media_v2 SET data = ? WHERE mid = ?"); + for (TLRPC.Message message : messages) { + NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); + message.serializeToStream(data); + + long messageId = message.id; + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; + } + + state.requery(); + state.bindByteBuffer(1, data); + state.bindLong(2, messageId); + state.step(); + + state2.requery(); + state2.bindByteBuffer(1, data); + state2.bindLong(2, messageId); + state2.step(); + + data.reuse(); + } + state.dispose(); + state2.dispose(); + + database.commitTransaction(); + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReceivedWebpages, messages); + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void overwriteChannel(final int channel_id, final TLRPC.TL_updates_channelDifferenceTooLong difference, final int newDialogType) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + boolean checkInvite = false; + final long did = -channel_id; + if (newDialogType != 0) { + SQLiteCursor cursor = database.queryFinalized("SELECT pts FROM dialogs WHERE did = " + did); + if (!cursor.next()) { + checkInvite = true; + } + cursor.dispose(); + } + + database.executeFast("DELETE FROM messages WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM channel_group WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM bot_keyboard WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_counts_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM messages_holes WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM messages_imp_holes WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_holes_v2 WHERE uid = " + did).stepThis().dispose(); + BotQuery.clearBotKeyboard(did, null); + + TLRPC.TL_messages_dialogs dialogs = new TLRPC.TL_messages_dialogs(); + dialogs.chats.addAll(difference.chats); + dialogs.users.addAll(difference.users); + dialogs.messages.addAll(difference.messages); + TLRPC.TL_dialogChannel dialog = new TLRPC.TL_dialogChannel(); + dialog.id = did; + dialog.peer = new TLRPC.TL_peerChannel(); + dialog.peer.channel_id = channel_id; + dialog.top_not_important_message = difference.top_message; + dialog.top_message = difference.top_important_message; + dialog.read_inbox_max_id = difference.read_inbox_max_id; + dialog.unread_not_important_count = difference.unread_count; + dialog.unread_count = difference.unread_important_count; + dialog.notify_settings = null; + dialog.pts = difference.pts; + dialogs.dialogs.add(dialog); + putDialogsInternal(dialogs); + + MessagesStorage.getInstance().updateDialogsWithDeletedMessages(new ArrayList(), false, channel_id); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.removeAllMessagesFromDialog, did, true); + } + }); + if (checkInvite) { + if (newDialogType == 1) { + MessagesController.getInstance().checkChannelInviter(channel_id); + } else { + MessagesController.getInstance().generateJoinMessage(channel_id, false); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void putChannelViews(final SparseArray channelViews, final boolean isChannel) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + database.beginTransaction(); + SQLitePreparedStatement state = database.executeFast("UPDATE messages SET media = max((SELECT media FROM messages WHERE mid = ?), ?) WHERE mid = ?"); + for (int a = 0; a < channelViews.size(); a++) { + int peer = channelViews.keyAt(a); + SparseIntArray messages = channelViews.get(peer); + for (int b = 0; b < messages.size(); b++) { + int views = messages.get(messages.keyAt(b)); + long messageId = messages.keyAt(b); + if (isChannel) { + messageId |= ((long) -peer) << 32; + } + state.requery(); + state.bindLong(1, messageId); + state.bindInteger(2, views); + state.bindLong(3, messageId); + state.step(); + } + } + state.dispose(); + database.commitTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + private boolean isValidKeyboardToSave(TLRPC.Message message) { + return message.reply_markup != null && !(message.reply_markup instanceof TLRPC.TL_replyInlineMarkup) && (!message.reply_markup.selective || message.mentioned); + } + + private void putMessagesInternal(final ArrayList messages, final boolean withTransaction, final boolean doNotUpdateDialogDate, final int downloadMask) { + try { + if (withTransaction) { + database.beginTransaction(); + } + HashMap messagesMap = new HashMap<>(); + HashMap messagesMapNotImportant = new HashMap<>(); + HashMap messagesCounts = new HashMap<>(); + HashMap messagesCountsNotImportant = new HashMap<>(); + HashMap> mediaCounts = null; + HashMap botKeyboards = new HashMap<>(); + + HashMap messagesMediaIdsMap = null; + StringBuilder messageMediaIds = null; + HashMap mediaTypes = null; + StringBuilder messageIds = new StringBuilder(); + HashMap dialogsReadMax = new HashMap<>(); + HashMap messagesIdsMap = new HashMap<>(); + HashMap messagesIdsMapNotImportant = new HashMap<>(); + + SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?)"); + SQLitePreparedStatement state2 = null; + SQLitePreparedStatement state3 = database.executeFast("REPLACE INTO randoms VALUES(?, ?)"); + SQLitePreparedStatement state4 = database.executeFast("REPLACE INTO download_queue VALUES(?, ?, ?, ?)"); + SQLitePreparedStatement state5 = database.executeFast("REPLACE INTO webpage_pending VALUES(?, ?)"); + + for (int a = 0; a < messages.size(); a++) { + TLRPC.Message message = messages.get(a); + + long messageId = message.id; + if (message.dialog_id == 0) { + if (message.to_id.user_id != 0) { + message.dialog_id = message.to_id.user_id; + } else if (message.to_id.chat_id != 0) { + message.dialog_id = -message.to_id.chat_id; + } else { + message.dialog_id = -message.to_id.channel_id; + } + } + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; + } + + if ((message.to_id.channel_id == 0 && MessageObject.isUnread(message) || MessageObject.isContentUnread(message)) && !MessageObject.isOut(message)) { + Integer currentMaxId = dialogsReadMax.get(message.dialog_id); + if (currentMaxId == null) { + SQLiteCursor cursor = database.queryFinalized("SELECT inbox_max FROM dialogs WHERE did = " + message.dialog_id); + if (cursor.next()) { + currentMaxId = cursor.intValue(0); + } else { + currentMaxId = 0; + } + cursor.dispose(); + dialogsReadMax.put(message.dialog_id, currentMaxId); + } + if (message.id < 0 || currentMaxId < message.id) { + if (messageIds.length() > 0) { + messageIds.append(","); + } + messageIds.append(messageId); + if (message.to_id.channel_id == 0 || MessageObject.isMegagroup(message) || MessageObject.isImportant(message)) { + messagesIdsMap.put(messageId, message.dialog_id); + } else if (message.to_id.channel_id != 0) { + messagesIdsMapNotImportant.put(messageId, message.dialog_id); + } + } + } + if (SharedMediaQuery.canAddMessageToMedia(message)) { + if (messageMediaIds == null) { + messageMediaIds = new StringBuilder(); + messagesMediaIdsMap = new HashMap<>(); + mediaTypes = new HashMap<>(); + } + if (messageMediaIds.length() > 0) { + messageMediaIds.append(","); + } + messageMediaIds.append(messageId); + messagesMediaIdsMap.put(messageId, message.dialog_id); + mediaTypes.put(messageId, SharedMediaQuery.getMediaType(message)); + } + if (isValidKeyboardToSave(message)) { + TLRPC.Message oldMessage = botKeyboards.get(message.dialog_id); + if (oldMessage == null || oldMessage.id < message.id) { + botKeyboards.put(message.dialog_id, message); + } + } + } + + for (HashMap.Entry entry : botKeyboards.entrySet()) { + BotQuery.putBotKeyboard(entry.getKey(), entry.getValue()); + } + + if (messageMediaIds != null) { + SQLiteCursor cursor = database.queryFinalized("SELECT mid FROM media_v2 WHERE mid IN(" + messageMediaIds.toString() + ")"); + while (cursor.next()) { + long mid = cursor.longValue(0); + messagesMediaIdsMap.remove(mid); + } + cursor.dispose(); + mediaCounts = new HashMap<>(); + for (HashMap.Entry entry : messagesMediaIdsMap.entrySet()) { + Integer type = mediaTypes.get(entry.getKey()); + HashMap counts = mediaCounts.get(type); + Integer count; + if (counts == null) { + counts = new HashMap<>(); + count = 0; + mediaCounts.put(type, counts); + } else { + count = counts.get(entry.getValue()); + } + if (count == null) { + count = 0; + } + count++; + counts.put(entry.getValue(), count); + } + } + + if (messageIds.length() > 0) { + SQLiteCursor cursor = database.queryFinalized("SELECT mid FROM messages WHERE mid IN(" + messageIds.toString() + ")"); + while (cursor.next()) { + messagesIdsMap.remove(cursor.longValue(0)); + messagesIdsMapNotImportant.remove(cursor.longValue(0)); + } + cursor.dispose(); + for (Long dialog_id : messagesIdsMap.values()) { + Integer count = messagesCounts.get(dialog_id); + if (count == null) { + count = 0; + } + count++; + messagesCounts.put(dialog_id, count); + } + for (Long dialog_id : messagesIdsMapNotImportant.values()) { + Integer count = messagesCountsNotImportant.get(dialog_id); + if (count == null) { + count = 0; + } + count++; + messagesCountsNotImportant.put(dialog_id, count); + } + } + + int downloadMediaMask = 0; + for (int a = 0; a < messages.size(); a++) { + TLRPC.Message message = messages.get(a); + fixUnsupportedMedia(message); + + state.requery(); + long messageId = message.id; + if (message.local_id != 0) { + messageId = message.local_id; + } + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; + } + + NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); + message.serializeToStream(data); + + boolean updateDialog = true; + if (message.action != null && message.action instanceof TLRPC.TL_messageEncryptedAction && !(message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL || message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages)) { + updateDialog = false; + } + + if (updateDialog) { + TLRPC.Message lastMessage; + if (message.to_id.channel_id == 0 || MessageObject.isMegagroup(message) || MessageObject.isImportant(message)) { + lastMessage = messagesMap.get(message.dialog_id); + if (lastMessage == null || message.date > lastMessage.date || message.id > 0 && lastMessage.id > 0 && message.id > lastMessage.id || message.id < 0 && lastMessage.id < 0 && message.id < lastMessage.id) { + messagesMap.put(message.dialog_id, message); + } + } else if (message.to_id.channel_id != 0) { + lastMessage = messagesMapNotImportant.get(message.dialog_id); + if (lastMessage == null || message.date > lastMessage.date || message.id > 0 && lastMessage.id > 0 && message.id > lastMessage.id || message.id < 0 && lastMessage.id < 0 && message.id < lastMessage.id) { + messagesMapNotImportant.put(message.dialog_id, message); + } + } + } + + state.bindLong(1, messageId); + state.bindLong(2, message.dialog_id); + state.bindInteger(3, MessageObject.getUnreadFlags(message)); + state.bindInteger(4, message.send_state); + state.bindInteger(5, message.date); + state.bindByteBuffer(6, data); + state.bindInteger(7, (MessageObject.isOut(message) ? 1 : 0)); + state.bindInteger(8, message.ttl); + if ((message.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { + state.bindInteger(9, message.views); + } else { + state.bindInteger(9, getMessageMediaType(message)); + } + state.bindInteger(10, MessageObject.isImportant(message) ? 1 : 0); + state.step(); + + if (message.random_id != 0) { + state3.requery(); + state3.bindLong(1, message.random_id); + state3.bindLong(2, messageId); + state3.step(); + } + + if (SharedMediaQuery.canAddMessageToMedia(message)) { + if (state2 == null) { + state2 = database.executeFast("REPLACE INTO media_v2 VALUES(?, ?, ?, ?, ?)"); + } + state2.requery(); + state2.bindLong(1, messageId); + state2.bindLong(2, message.dialog_id); + state2.bindInteger(3, message.date); + state2.bindInteger(4, SharedMediaQuery.getMediaType(message)); + state2.bindByteBuffer(5, data); + state2.step(); + } + + if (message.media instanceof TLRPC.TL_messageMediaWebPage && message.media.webpage instanceof TLRPC.TL_webPagePending) { + state5.requery(); + state5.bindLong(1, message.media.webpage.id); + state5.bindLong(2, messageId); + state5.step(); + } + + data.reuse(); + + if ((message.to_id.channel_id == 0 || MessageObject.isImportant(message)) && message.date >= ConnectionsManager.getInstance().getCurrentTime() - 60 * 60 && downloadMask != 0) { + if (message.media instanceof TLRPC.TL_messageMediaPhoto || message.media instanceof TLRPC.TL_messageMediaDocument) { + int type = 0; + long id = 0; + TLRPC.MessageMedia object = null; + if (MessageObject.isVoiceMessage(message)) { + if ((downloadMask & MediaController.AUTODOWNLOAD_MASK_AUDIO) != 0 && message.media.document.size < 1024 * 1024 * 5) { + id = message.media.document.id; + type = MediaController.AUTODOWNLOAD_MASK_AUDIO; + object = new TLRPC.TL_messageMediaDocument(); + object.caption = ""; + object.document = message.media.document; + } + } else if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + if ((downloadMask & MediaController.AUTODOWNLOAD_MASK_PHOTO) != 0) { + TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(message.media.photo.sizes, AndroidUtilities.getPhotoSize()); + if (photoSize != null) { + id = message.media.photo.id; + type = MediaController.AUTODOWNLOAD_MASK_PHOTO; + object = new TLRPC.TL_messageMediaPhoto(); + object.caption = ""; + object.photo = message.media.photo; + } + } + } else if (MessageObject.isVideoMessage(message)) { + if ((downloadMask & MediaController.AUTODOWNLOAD_MASK_VIDEO) != 0) { + id = message.media.document.id; + type = MediaController.AUTODOWNLOAD_MASK_VIDEO; + object = new TLRPC.TL_messageMediaDocument(); + object.caption = ""; + object.document = message.media.document; + } + } else if (message.media instanceof TLRPC.TL_messageMediaDocument && !MessageObject.isMusicMessage(message) && !MessageObject.isGifDocument(message.media.document)) { + if ((downloadMask & MediaController.AUTODOWNLOAD_MASK_DOCUMENT) != 0) { + id = message.media.document.id; + type = MediaController.AUTODOWNLOAD_MASK_DOCUMENT; + object = new TLRPC.TL_messageMediaDocument(); + object.caption = ""; + object.document = message.media.document; + } + } + if (object != null) { + downloadMediaMask |= type; + state4.requery(); + data = new NativeByteBuffer(object.getObjectSize()); + object.serializeToStream(data); + state4.bindLong(1, id); + state4.bindInteger(2, type); + state4.bindInteger(3, message.date); + state4.bindByteBuffer(4, data); + state4.step(); + data.reuse(); + } + } + } + } + state.dispose(); + if (state2 != null) { + state2.dispose(); + } + state3.dispose(); + state4.dispose(); + state5.dispose(); + + state = database.executeFast("REPLACE INTO dialogs VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + HashMap dids = new HashMap<>(); + dids.putAll(messagesMap); + dids.putAll(messagesMapNotImportant); + + for (HashMap.Entry pair : dids.entrySet()) { + Long key = pair.getKey(); + if (key == 0) { + continue; + } + TLRPC.Message message = messagesMap.get(key); + TLRPC.Message messageNotImportant = messagesMapNotImportant.get(key); + + int channelId = 0; + if (message != null) { + channelId = message.to_id.channel_id; + } + if (messageNotImportant != null) { + channelId = messageNotImportant.to_id.channel_id; + } + + SQLiteCursor cursor = database.queryFinalized("SELECT date, unread_count, last_mid_i, unread_count_i, pts, date_i, last_mid, inbox_max FROM dialogs WHERE did = " + key); + int dialog_date = 0; + int last_mid = 0; + int old_unread_count = 0; + int last_mid_i = 0; + int old_unread_count_i = 0; + int pts = channelId != 0 ? 1 : 0; + int dialog_date_i = 0; + int inbox_max = 0; + if (cursor.next()) { + dialog_date = cursor.intValue(0); + old_unread_count = cursor.intValue(1); + last_mid_i = cursor.intValue(2); + old_unread_count_i = cursor.intValue(3); + pts = cursor.intValue(4); + dialog_date_i = cursor.intValue(5); + last_mid = cursor.intValue(6); + inbox_max = cursor.intValue(7); + } else if (channelId != 0) { + MessagesController.getInstance().checkChannelInviter(channelId); + } + cursor.dispose(); + + Integer unread_count = messagesCounts.get(key); + if (unread_count == null) { + unread_count = 0; + } else { + messagesCounts.put(key, unread_count + old_unread_count); + } + Integer unread_count_i = messagesCountsNotImportant.get(key); + if (unread_count_i == null) { + unread_count_i = 0; + } else { + messagesCountsNotImportant.put(key, unread_count_i + old_unread_count_i); + } + long messageId = message != null ? message.id : last_mid; + if (message != null) { + if (message.local_id != 0) { + messageId = message.local_id; + } + } + long messageIdNotImportant = messageNotImportant != null ? messageNotImportant.id : last_mid_i; + if (messageNotImportant != null) { + if (messageNotImportant.local_id != 0) { + messageIdNotImportant = messageNotImportant.local_id; + } + } + + if (channelId != 0) { + messageId |= ((long) channelId) << 32; + messageIdNotImportant |= ((long) channelId) << 32; + } + + state.requery(); + state.bindLong(1, key); + if (message != null && (!doNotUpdateDialogDate || dialog_date == 0)) { + state.bindInteger(2, message.date); + } else { + state.bindInteger(2, dialog_date); + } + state.bindInteger(3, old_unread_count + unread_count); + state.bindLong(4, messageId); + state.bindInteger(5, inbox_max); + state.bindInteger(6, 0); + state.bindLong(7, messageIdNotImportant); + state.bindInteger(8, unread_count_i + old_unread_count_i); + state.bindInteger(9, pts); + if (messageNotImportant != null && (!doNotUpdateDialogDate || dialog_date == 0)) { + state.bindInteger(10, messageNotImportant.date); + } else { + state.bindInteger(10, dialog_date_i); + } + state.step(); + } + state.dispose(); + + if (mediaCounts != null) { + state3 = database.executeFast("REPLACE INTO media_counts_v2 VALUES(?, ?, ?)"); + for (HashMap.Entry> counts : mediaCounts.entrySet()) { + Integer type = counts.getKey(); + for (HashMap.Entry pair : counts.getValue().entrySet()) { + long uid = pair.getKey(); + int lower_part = (int) uid; + int count = -1; + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT count FROM media_counts_v2 WHERE uid = %d AND type = %d LIMIT 1", uid, type)); + if (cursor.next()) { + count = cursor.intValue(0); + } + cursor.dispose(); + if (count != -1) { + state3.requery(); + count += pair.getValue(); + state3.bindLong(1, uid); + state3.bindInteger(2, type); + state3.bindInteger(3, count); + state3.step(); + } + } + } + state3.dispose(); + } + if (withTransaction) { + database.commitTransaction(); + } + MessagesController.getInstance().processDialogsUpdateRead(messagesCounts); + + if (downloadMediaMask != 0) { + final int downloadMediaMaskFinal = downloadMediaMask; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MediaController.getInstance().newDownloadObjectsAvailable(downloadMediaMaskFinal); + } + }); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void putMessages(final ArrayList messages, final boolean withTransaction, boolean useQueue, final boolean doNotUpdateDialogDate, final int downloadMask) { + if (messages.size() == 0) { + return; + } + if (useQueue) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + putMessagesInternal(messages, withTransaction, doNotUpdateDialogDate, downloadMask); + } + }); + } else { + putMessagesInternal(messages, withTransaction, doNotUpdateDialogDate, downloadMask); + } + } + + public void markMessageAsSendError(final TLRPC.Message message) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + long messageId = message.id; + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; + } + database.executeFast("UPDATE messages SET send_state = 2 WHERE mid = " + messageId).stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + /*public void getHoleMessages() { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void clearHoleMessages(final int enc_id) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + database.executeFast("DELETE FROM secret_holes WHERE uid = " + enc_id).stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void putHoleMessage(final int enc_id, final TLRPC.Message message) { + if (message == null) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLitePreparedStatement state = database.executeFast("REPLACE INTO secret_holes VALUES(?, ?, ?, ?)"); + + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); + message.serializeToStream(data); + state.bindInteger(1, enc_id); + state.bindInteger(2, message.seq_in); + state.bindInteger(3, message.seq_out); + state.bindByteBuffer(4, data); + state.step(); + data.reuse(); + + state.dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + }*/ + + public void setMessageSeq(final int mid, final int seq_in, final int seq_out) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages_seq VALUES(?, ?, ?)"); + state.requery(); + state.bindInteger(1, mid); + state.bindInteger(2, seq_in); + state.bindInteger(3, seq_out); + state.step(); + state.dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + private long[] updateMessageStateAndIdInternal(long random_id, Integer _oldId, int newId, int date, int channelId) { + SQLiteCursor cursor = null; + long oldMessageId; + long newMessageId = newId; + + if (_oldId == null) { + try { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM randoms WHERE random_id = %d LIMIT 1", random_id)); + if (cursor.next()) { + _oldId = cursor.intValue(0); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + if (_oldId == null) { + return null; + } + } + oldMessageId = _oldId; + if (channelId != 0) { + oldMessageId |= ((long) channelId) << 32; + newMessageId |= ((long) channelId) << 32; + } + + long did = 0; + try { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid FROM messages WHERE mid = %d LIMIT 1", oldMessageId)); + if (cursor.next()) { + did = cursor.longValue(0); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + + if (did == 0) { + return null; + } + if (oldMessageId == newMessageId && date != 0) { + SQLitePreparedStatement state = null; + try { + state = database.executeFast("UPDATE messages SET send_state = 0, date = ? WHERE mid = ?"); + state.bindInteger(1, date); + state.bindLong(2, newMessageId); + state.step(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (state != null) { + state.dispose(); + } + } + + return new long[] {did, newId}; + } else { + SQLitePreparedStatement state = null; + try { + state = database.executeFast("UPDATE messages SET mid = ?, send_state = 0 WHERE mid = ?"); + state.bindLong(1, newMessageId); + state.bindLong(2, oldMessageId); + state.step(); + } catch (Exception e) { + try { + database.executeFast(String.format(Locale.US, "DELETE FROM messages WHERE mid = %d", oldMessageId)).stepThis().dispose(); + database.executeFast(String.format(Locale.US, "DELETE FROM messages_seq WHERE mid = %d", oldMessageId)).stepThis().dispose(); + } catch (Exception e2) { + FileLog.e("tmessages", e2); + } + } finally { + if (state != null) { + state.dispose(); + state = null; + } + } + + try { + state = database.executeFast("UPDATE media_v2 SET mid = ? WHERE mid = ?"); + state.bindLong(1, newMessageId); + state.bindLong(2, oldMessageId); + state.step(); + } catch (Exception e) { + try { + database.executeFast(String.format(Locale.US, "DELETE FROM media_v2 WHERE mid = %d", oldMessageId)).stepThis().dispose(); + } catch (Exception e2) { + FileLog.e("tmessages", e2); + } + } finally { + if (state != null) { + state.dispose(); + state = null; + } + } + + try { + state = database.executeFast("UPDATE dialogs SET last_mid = ? WHERE last_mid = ?"); + state.bindLong(1, newMessageId); + state.bindLong(2, oldMessageId); + state.step(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (state != null) { + state.dispose(); + } + } + + return new long[] {did, _oldId}; + } + } + + public long[] updateMessageStateAndId(final long random_id, final Integer _oldId, final int newId, final int date, boolean useQueue, final int channelId) { + if (useQueue) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + updateMessageStateAndIdInternal(random_id, _oldId, newId, date, channelId); + } + }); + } else { + return updateMessageStateAndIdInternal(random_id, _oldId, newId, date, channelId); + } + return null; + } + + private void updateUsersInternal(final ArrayList users, final boolean onlyStatus, final boolean withTransaction) { + if (Thread.currentThread().getId() != storageQueue.getId()) { + throw new RuntimeException("wrong db thread"); + } + try { + if (onlyStatus) { + if (withTransaction) { + database.beginTransaction(); + } + SQLitePreparedStatement state = database.executeFast("UPDATE users SET status = ? WHERE uid = ?"); + for (TLRPC.User user : users) { + state.requery(); + if (user.status != null) { + state.bindInteger(1, user.status.expires); + } else { + state.bindInteger(1, 0); + } + state.bindInteger(2, user.id); + state.step(); + } + state.dispose(); + if (withTransaction) { + database.commitTransaction(); + } + } else { + StringBuilder ids = new StringBuilder(); + HashMap usersDict = new HashMap<>(); + for (TLRPC.User user : users) { + if (ids.length() != 0) { + ids.append(","); + } + ids.append(user.id); + usersDict.put(user.id, user); + } + ArrayList loadedUsers = new ArrayList<>(); + getUsersInternal(ids.toString(), loadedUsers); + for (TLRPC.User user : loadedUsers) { + TLRPC.User updateUser = usersDict.get(user.id); + if (updateUser != null) { + if (updateUser.first_name != null && updateUser.last_name != null) { + if (!UserObject.isContact(user)) { + user.first_name = updateUser.first_name; + user.last_name = updateUser.last_name; + } + user.username = updateUser.username; + } else if (updateUser.photo != null) { + user.photo = updateUser.photo; + } else if (updateUser.phone != null) { + user.phone = updateUser.phone; + } + } + } + + if (!loadedUsers.isEmpty()) { + if (withTransaction) { + database.beginTransaction(); + } + putUsersInternal(loadedUsers); + if (withTransaction) { + database.commitTransaction(); + } + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void updateUsers(final ArrayList users, final boolean onlyStatus, final boolean withTransaction, boolean useQueue) { + if (users.isEmpty()) { + return; + } + if (useQueue) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + updateUsersInternal(users, onlyStatus, withTransaction); + } + }); + } else { + updateUsersInternal(users, onlyStatus, withTransaction); + } + } + + private void markMessagesAsReadInternal(SparseArray inbox, SparseIntArray outbox, HashMap encryptedMessages) { + try { + if (inbox != null) { + for (int b = 0; b < inbox.size(); b++) { + int key = inbox.keyAt(b); + long messageId = inbox.get(key); + database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = read_state | 1 WHERE uid = %d AND mid > 0 AND mid <= %d AND read_state IN(0,2) AND out = 0", key, messageId)).stepThis().dispose(); + } + } + if (outbox != null) { + for (int b = 0; b < outbox.size(); b++) { + int key = outbox.keyAt(b); + int messageId = outbox.get(key); + database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = read_state | 1 WHERE uid = %d AND mid > 0 AND mid <= %d AND read_state IN(0,2) AND out = 1", key, messageId)).stepThis().dispose(); + } + } + if (encryptedMessages != null && !encryptedMessages.isEmpty()) { + for (HashMap.Entry entry : encryptedMessages.entrySet()) { + long dialog_id = ((long)entry.getKey()) << 32; + int max_date = entry.getValue(); + SQLitePreparedStatement state = database.executeFast("UPDATE messages SET read_state = read_state | 1 WHERE uid = ? AND date <= ? AND read_state IN(0,2) AND out = 1"); + state.requery(); + state.bindLong(1, dialog_id); + state.bindInteger(2, max_date); + state.step(); + state.dispose(); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void markMessagesContentAsRead(final ArrayList mids) { + if (mids == null || mids.isEmpty()) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + database.executeFast(String.format(Locale.US, "UPDATE messages SET read_state = read_state | 2 WHERE mid IN (%s)", TextUtils.join(",", mids))).stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void markMessagesAsRead(final SparseArray inbox, final SparseIntArray outbox, final HashMap encryptedMessages, boolean useQueue) { + if (useQueue) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + markMessagesAsReadInternal(inbox, outbox, encryptedMessages); + } + }); + } else { + markMessagesAsReadInternal(inbox, outbox, encryptedMessages); + } + } + + public void markMessagesAsDeletedByRandoms(final ArrayList messages) { + if (messages.isEmpty()) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + String ids = TextUtils.join(",", messages); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM randoms WHERE random_id IN(%s)", ids)); + final ArrayList mids = new ArrayList<>(); + while (cursor.next()) { + mids.add(cursor.intValue(0)); + } + cursor.dispose(); + if (!mids.isEmpty()) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messagesDeleted, mids, 0); + } + }); + MessagesStorage.getInstance().updateDialogsWithReadMessagesInternal(mids, null); + MessagesStorage.getInstance().markMessagesAsDeletedInternal(mids, 0); + MessagesStorage.getInstance().updateDialogsWithDeletedMessagesInternal(mids, 0); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + private void markMessagesAsDeletedInternal(final ArrayList messages, int channelId) { + try { + String ids; + int unread_count = 0; + if (channelId != 0) { + StringBuilder builder = new StringBuilder(messages.size()); + for (int a = 0; a < messages.size(); a++) { + long messageId = messages.get(a); + messageId |= ((long) channelId) << 32; + if (builder.length() > 0) { + builder.append(','); + } + builder.append(messageId); + } + ids = builder.toString(); + } else { + ids = TextUtils.join(",", messages); + } + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT uid, data, read_state FROM messages WHERE mid IN(%s)", ids)); + ArrayList filesToDelete = new ArrayList<>(); + try { + while (cursor.next()) { + long did = cursor.longValue(0); + if (channelId != 0 && cursor.intValue(2) == 0) { + unread_count++; + } + if ((int) did != 0) { + continue; + } + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(1)); + if (cursor.byteBufferValue(1, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + if (message != null && message.media != null) { + if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + for (TLRPC.PhotoSize photoSize : message.media.photo.sizes) { + File file = FileLoader.getPathToAttach(photoSize); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + } + } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { + File file = FileLoader.getPathToAttach(message.media.document); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + file = FileLoader.getPathToAttach(message.media.document.thumb); + if (file != null && file.toString().length() > 0) { + filesToDelete.add(file); + } + } + } + } + data.reuse(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + cursor.dispose(); + FileLoader.getInstance().deleteFiles(filesToDelete, 0); + + if (channelId != 0 && unread_count != 0) { + long did = -channelId; + SQLitePreparedStatement state = database.executeFast("UPDATE dialogs SET unread_count = ((SELECT unread_count FROM dialogs WHERE did = ?) - ?) WHERE did = ?"); + state.requery(); + state.bindLong(1, did); + state.bindInteger(2, unread_count); + state.bindLong(3, did); + state.step(); + state.dispose(); + } + + database.executeFast(String.format(Locale.US, "DELETE FROM messages WHERE mid IN(%s)", ids)).stepThis().dispose(); + database.executeFast(String.format(Locale.US, "DELETE FROM bot_keyboard WHERE mid IN(%s)", ids)).stepThis().dispose(); + database.executeFast(String.format(Locale.US, "DELETE FROM messages_seq WHERE mid IN(%s)", ids)).stepThis().dispose(); + database.executeFast(String.format(Locale.US, "DELETE FROM media_v2 WHERE mid IN(%s)", ids)).stepThis().dispose(); + database.executeFast("DELETE FROM media_counts_v2 WHERE 1").stepThis().dispose(); + BotQuery.clearBotKeyboard(0, messages); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + private void updateDialogsWithDeletedMessagesInternal(final ArrayList messages, int channelId) { + if (Thread.currentThread().getId() != storageQueue.getId()) { + throw new RuntimeException("wrong db thread"); + } + try { + String ids; + if (!messages.isEmpty()) { + SQLitePreparedStatement state; + ArrayList dialogsToUpdate = new ArrayList<>(); + if (channelId != 0) { + dialogsToUpdate.add((long) -channelId); + state = database.executeFast("UPDATE dialogs SET last_mid = (SELECT mid FROM messages WHERE uid = ? AND date = (SELECT MAX(date) FROM messages WHERE uid = ? )) WHERE did = ?"); + } else { + ids = TextUtils.join(",", messages); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT did FROM dialogs WHERE last_mid IN(%s)", ids)); + while (cursor.next()) { + dialogsToUpdate.add(cursor.longValue(0)); + } + cursor.dispose(); + state = database.executeFast("UPDATE dialogs SET unread_count = 0, unread_count_i = 0, last_mid = (SELECT mid FROM messages WHERE uid = ? AND date = (SELECT MAX(date) FROM messages WHERE uid = ? AND date != 0)) WHERE did = ?"); + } + database.beginTransaction(); + for (int a = 0; a < dialogsToUpdate.size(); a++) { + long did = dialogsToUpdate.get(a); + state.requery(); + state.bindLong(1, did); + state.bindLong(2, did); + state.bindLong(3, did); + state.step(); + } + state.dispose(); + database.commitTransaction(); + + ids = TextUtils.join(",", dialogsToUpdate); + } else { + ids = "" + (-channelId); + } + + TLRPC.messages_Dialogs dialogs = new TLRPC.messages_Dialogs(); + ArrayList encryptedChats = new ArrayList<>(); + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + ArrayList encryptedToLoad = new ArrayList<>(); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT d.did, d.last_mid, d.unread_count, d.date, m.data, m.read_state, m.mid, m.send_state, m.date, d.last_mid_i, d.unread_count_i, d.pts, d.inbox_max FROM dialogs as d LEFT JOIN messages as m ON d.last_mid = m.mid WHERE d.did IN(%s)", ids)); + while (cursor.next()) { + TLRPC.Dialog dialog; + if (channelId == 0) { + dialog = new TLRPC.TL_dialog(); + } else { + dialog = new TLRPC.TL_dialogChannel(); + } + dialog.id = cursor.longValue(0); + dialog.top_message = cursor.intValue(1); + dialog.read_inbox_max_id = cursor.intValue(13); + dialog.unread_count = cursor.intValue(2); + dialog.last_message_date = cursor.intValue(3); + dialog.pts = cursor.intValue(11); + dialog.top_not_important_message = cursor.intValue(9); + dialog.unread_not_important_count = cursor.intValue(10); + + dialogs.dialogs.add(dialog); + + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(4)); + if (cursor.byteBufferValue(4, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + MessageObject.setUnreadFlags(message, cursor.intValue(5)); + message.id = cursor.intValue(6); + message.send_state = cursor.intValue(7); + int date = cursor.intValue(8); + if (date != 0) { + dialog.last_message_date = date; + } + message.dialog_id = dialog.id; + dialogs.messages.add(message); + + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + } + data.reuse(); + + int lower_id = (int)dialog.id; + int high_id = (int)(dialog.id >> 32); + if (lower_id != 0) { + if (high_id == 1) { + if (!chatsToLoad.contains(lower_id)) { + chatsToLoad.add(lower_id); + } + } else { + if (lower_id > 0) { + if (!usersToLoad.contains(lower_id)) { + usersToLoad.add(lower_id); + } + } else { + if (!chatsToLoad.contains(-lower_id)) { + chatsToLoad.add(-lower_id); + } + } + } + } else { + if (!encryptedToLoad.contains(high_id)) { + encryptedToLoad.add(high_id); + } + } + } + cursor.dispose(); + + if (!encryptedToLoad.isEmpty()) { + getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, usersToLoad); + } + + if (!chatsToLoad.isEmpty()) { + getChatsInternal(TextUtils.join(",", chatsToLoad), dialogs.chats); + } + + if (!usersToLoad.isEmpty()) { + getUsersInternal(TextUtils.join(",", usersToLoad), dialogs.users); + } + + if (!dialogs.dialogs.isEmpty() || !encryptedChats.isEmpty()) { + MessagesController.getInstance().processDialogsUpdate(dialogs, encryptedChats); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void updateDialogsWithDeletedMessages(final ArrayList messages, boolean useQueue, final int channelId) { + if (messages.isEmpty() && channelId == 0) { + return; + } + if (useQueue) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + updateDialogsWithDeletedMessagesInternal(messages, channelId); + } + }); + } else { + updateDialogsWithDeletedMessagesInternal(messages, channelId); + } + } + + public void markMessagesAsDeleted(final ArrayList messages, boolean useQueue, final int channelId) { + if (messages.isEmpty()) { + return; + } + if (useQueue) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + markMessagesAsDeletedInternal(messages, channelId); + } + }); + } else { + markMessagesAsDeletedInternal(messages, channelId); + } + } + + private void fixUnsupportedMedia(TLRPC.Message message) { + if (message == null) { + return; + } + boolean ok = false; + if (message.media instanceof TLRPC.TL_messageMediaUnsupported_old) { + if (message.media.bytes.length == 0) { + message.media.bytes = new byte[1]; + message.media.bytes[0] = TLRPC.LAYER; + } + } else if (message.media instanceof TLRPC.TL_messageMediaUnsupported) { + message.media = new TLRPC.TL_messageMediaUnsupported_old(); + message.media.bytes = new byte[1]; + message.media.bytes[0] = TLRPC.LAYER; + message.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; + } + } + + private void doneHolesInTable(String table, long did, int max_id) throws Exception { + if (max_id == 0) { + database.executeFast(String.format(Locale.US, "DELETE FROM " + table + " WHERE uid = %d", did)).stepThis().dispose(); + } else { + database.executeFast(String.format(Locale.US, "DELETE FROM " + table + " WHERE uid = %d AND start = 0", did)).stepThis().dispose(); + } + SQLitePreparedStatement state = database.executeFast("REPLACE INTO " + table + " VALUES(?, ?, ?)"); + state.requery(); + state.bindLong(1, did); + state.bindInteger(2, 1); + state.bindInteger(3, 1); + state.step(); + state.dispose(); + } + + public void doneHolesInMedia(long did, int max_id, int type) throws Exception { + if (type == -1) { + if (max_id == 0) { + database.executeFast(String.format(Locale.US, "DELETE FROM media_holes_v2 WHERE uid = %d", did)).stepThis().dispose(); + } else { + database.executeFast(String.format(Locale.US, "DELETE FROM media_holes_v2 WHERE uid = %d AND start = 0", did)).stepThis().dispose(); + } + SQLitePreparedStatement state = database.executeFast("REPLACE INTO media_holes_v2 VALUES(?, ?, ?, ?)"); + for (int a = 0; a < SharedMediaQuery.MEDIA_TYPES_COUNT; a++) { + state.requery(); + state.bindLong(1, did); + state.bindInteger(2, a); + state.bindInteger(3, 1); + state.bindInteger(4, 1); + state.step(); + } + state.dispose(); + } else { + if (max_id == 0) { + database.executeFast(String.format(Locale.US, "DELETE FROM media_holes_v2 WHERE uid = %d AND type = %d", did, type)).stepThis().dispose(); + } else { + database.executeFast(String.format(Locale.US, "DELETE FROM media_holes_v2 WHERE uid = %d AND type = %d AND start = 0", did, type)).stepThis().dispose(); + } + SQLitePreparedStatement state = database.executeFast("REPLACE INTO media_holes_v2 VALUES(?, ?, ?, ?)"); + state.requery(); + state.bindLong(1, did); + state.bindInteger(2, type); + state.bindInteger(3, 1); + state.bindInteger(4, 1); + state.step(); + state.dispose(); + } + } + + private class Hole { + + public Hole(int s, int e) { + start = s; + end = e; + } + + public Hole(int t, int s, int e) { + type = t; + start = s; + end = e; + } + + public int start; + public int end; + public int type; + } + + public void closeHolesInMedia(long did, int minId, int maxId, int type) throws Exception { + try { + boolean ok = false; + SQLiteCursor cursor; + if (type < 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT type, start, end FROM media_holes_v2 WHERE uid = %d AND type >= 0 AND ((end >= %d AND end <= %d) OR (start >= %d AND start <= %d) OR (start >= %d AND end <= %d) OR (start <= %d AND end >= %d))", did, minId, maxId, minId, maxId, minId, maxId, minId, maxId)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT type, start, end FROM media_holes_v2 WHERE uid = %d AND type = %d AND ((end >= %d AND end <= %d) OR (start >= %d AND start <= %d) OR (start >= %d AND end <= %d) OR (start <= %d AND end >= %d))", did, type, minId, maxId, minId, maxId, minId, maxId, minId, maxId)); + } + ArrayList holes = null; + while (cursor.next()) { + if (holes == null) { + holes = new ArrayList<>(); + } + int holeType = cursor.intValue(0); + int start = cursor.intValue(1); + int end = cursor.intValue(2); + if (start == end && start == 1) { + continue; + } + holes.add(new Hole(holeType, start, end)); + } + cursor.dispose(); + if (holes != null) { + for (int a = 0; a < holes.size(); a++) { + Hole hole = holes.get(a); + if (maxId >= hole.end - 1 && minId <= hole.start + 1) { + database.executeFast(String.format(Locale.US, "DELETE FROM media_holes_v2 WHERE uid = %d AND type = %d AND start = %d AND end = %d", did, hole.type, hole.start, hole.end)).stepThis().dispose(); + } else if (maxId >= hole.end - 1) { + if (hole.end != minId) { + try { + database.executeFast(String.format(Locale.US, "UPDATE media_holes_v2 SET end = %d WHERE uid = %d AND type = %d AND start = %d AND end = %d", minId, did, hole.type, hole.start, hole.end)).stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } else if (minId <= hole.start + 1) { + if (hole.start != maxId) { + try { + database.executeFast(String.format(Locale.US, "UPDATE media_holes_v2 SET start = %d WHERE uid = %d AND type = %d AND start = %d AND end = %d", maxId, did, hole.type, hole.start, hole.end)).stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } else { + database.executeFast(String.format(Locale.US, "DELETE FROM media_holes_v2 WHERE uid = %d AND type = %d AND start = %d AND end = %d", did, hole.type, hole.start, hole.end)).stepThis().dispose(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO media_holes_v2 VALUES(?, ?, ?, ?)"); + state.requery(); + state.bindLong(1, did); + state.bindInteger(2, hole.type); + state.bindInteger(3, hole.start); + state.bindInteger(4, minId); + state.step(); + state.requery(); + state.bindLong(1, did); + state.bindInteger(2, hole.type); + state.bindInteger(3, maxId); + state.bindInteger(4, hole.end); + state.step(); + state.dispose(); + } + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + private void closeHolesInTable(String table, long did, int minId, int maxId) throws Exception { + try { + boolean ok = false; + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT start, end FROM " + table + " WHERE uid = %d AND ((end >= %d AND end <= %d) OR (start >= %d AND start <= %d) OR (start >= %d AND end <= %d) OR (start <= %d AND end >= %d))", did, minId, maxId, minId, maxId, minId, maxId, minId, maxId)); + ArrayList holes = null; + while (cursor.next()) { + if (holes == null) { + holes = new ArrayList<>(); + } + int start = cursor.intValue(0); + int end = cursor.intValue(1); + if (start == end && start == 1) { + continue; + } + holes.add(new Hole(start, end)); + } + cursor.dispose(); + if (holes != null) { + for (int a = 0; a < holes.size(); a++) { + Hole hole = holes.get(a); + if (maxId >= hole.end - 1 && minId <= hole.start + 1) { + database.executeFast(String.format(Locale.US, "DELETE FROM " + table + " WHERE uid = %d AND start = %d AND end = %d", did, hole.start, hole.end)).stepThis().dispose(); + } else if (maxId >= hole.end - 1) { + if (hole.end != minId) { + try { + database.executeFast(String.format(Locale.US, "UPDATE " + table + " SET end = %d WHERE uid = %d AND start = %d AND end = %d", minId, did, hole.start, hole.end)).stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } else if (minId <= hole.start + 1) { + if (hole.start != maxId) { + try { + database.executeFast(String.format(Locale.US, "UPDATE " + table + " SET start = %d WHERE uid = %d AND start = %d AND end = %d", maxId, did, hole.start, hole.end)).stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } else { + database.executeFast(String.format(Locale.US, "DELETE FROM " + table + " WHERE uid = %d AND start = %d AND end = %d", did, hole.start, hole.end)).stepThis().dispose(); + SQLitePreparedStatement state = database.executeFast("REPLACE INTO " + table + " VALUES(?, ?, ?)"); + state.requery(); + state.bindLong(1, did); + state.bindInteger(2, hole.start); + state.bindInteger(3, minId); + state.step(); + state.requery(); + state.bindLong(1, did); + state.bindInteger(2, maxId); + state.bindInteger(3, hole.end); + state.step(); + state.dispose(); + } + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void putMessages(final TLRPC.messages_Messages messages, final long dialog_id, final int load_type, final int max_id, final int important, final boolean createDialog) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (messages.messages.isEmpty()) { + if (load_type == 0) { + if (important != 2) { + doneHolesInTable("messages_holes", dialog_id, max_id); + doneHolesInMedia(dialog_id, max_id, -1); + } + if (important != 0) { + doneHolesInTable("messages_imp_holes", dialog_id, max_id); + } + } + return; + } + database.beginTransaction(); + + if (!messages.collapsed.isEmpty() && important == 2) { + int maxId, minId; + int count = messages.collapsed.size(); + for (int a = 0; a < count; a++) { + TLRPC.TL_messageGroup group = messages.collapsed.get(a); + if (a < count - 1) { + minId = group.max_id; + maxId = messages.collapsed.get(a + 1).min_id; + closeHolesInTable("messages_holes", dialog_id, minId, maxId); + closeHolesInMedia(dialog_id, minId, maxId, -1); + } + if (a == 0) { + minId = messages.messages.get(messages.messages.size() - 1).id; + maxId = minId > group.min_id ? group.max_id : group.min_id; + closeHolesInTable("messages_holes", dialog_id, minId, maxId); + closeHolesInMedia(dialog_id, minId, maxId, -1); + } + if (a == count - 1) { + maxId = messages.messages.get(0).id; + minId = maxId < group.max_id ? group.min_id : group.max_id; + closeHolesInTable("messages_holes", dialog_id, minId, maxId); + closeHolesInMedia(dialog_id, minId, maxId, -1); + } + } + } + if (load_type == 0) { + int minId = messages.messages.get(messages.messages.size() - 1).id; + if (important != 2 || messages.collapsed.isEmpty()) { + closeHolesInTable("messages_holes", dialog_id, minId, max_id); + closeHolesInMedia(dialog_id, minId, max_id, -1); + } + if (important != 0) { + closeHolesInTable("messages_imp_holes", dialog_id, minId, max_id); + } + } else if (load_type == 1) { + int maxId = messages.messages.get(0).id; + if (important != 2 || messages.collapsed.isEmpty()) { + closeHolesInTable("messages_holes", dialog_id, max_id, maxId); + closeHolesInMedia(dialog_id, max_id, maxId, -1); + } + if (important != 0) { + closeHolesInTable("messages_imp_holes", dialog_id, max_id, maxId); + } + } else if (load_type == 3 || load_type == 2) { + int maxId = max_id == 0 ? Integer.MAX_VALUE : messages.messages.get(0).id; + int minId = messages.messages.get(messages.messages.size() - 1).id; + if (important != 2 || messages.collapsed.isEmpty()) { + closeHolesInTable("messages_holes", dialog_id, minId, maxId); + closeHolesInMedia(dialog_id, minId, maxId, -1); + } + if (important != 0) { + closeHolesInTable("messages_imp_holes", dialog_id, minId, maxId); + } + } + int count = messages.messages.size(); + + //load_type == 0 ? backward loading + //load_type == 1 ? forward loading + //load_type == 2 ? load from first unread + //load_type == 3 ? load around message + + SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?)"); + SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO media_v2 VALUES(?, ?, ?, ?, ?)"); + TLRPC.Message botKeyboard = null; + int countBeforeImportant = 0; + int countAfterImportant = 0; + int minChannelMessageId = Integer.MAX_VALUE; + int maxChannelMessageId = 0; + int lastChannelImportantId = -1; + int channelId = 0; + for (int a = 0; a < count; a++) { + TLRPC.Message message = messages.messages.get(a); + + long messageId = message.id; + if (channelId == 0) { + channelId = message.to_id.channel_id; + } + if (message.to_id.channel_id != 0) { + messageId |= ((long) channelId) << 32; + } + + if (load_type == -2) { + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT mid FROM messages WHERE mid = %d", messageId)); + boolean exist = cursor.next(); + cursor.dispose(); + if (!exist) { + continue; + } + } + + if (a == 0 && createDialog) { + SQLitePreparedStatement state3 = database.executeFast("REPLACE INTO dialogs VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + state3.bindLong(1, dialog_id); + state3.bindInteger(2, message.date); + state3.bindInteger(3, 0); + state3.bindLong(4, messageId); + state3.bindInteger(5, message.id); + state3.bindInteger(6, 0); + state3.bindLong(7, messageId); + state3.bindInteger(8, message.ttl); + state3.bindInteger(9, messages.pts); + state3.bindInteger(10, message.date); + state3.step(); + state3.dispose(); + } + + boolean isImportant = MessageObject.isImportant(message); + if (load_type >= 0 && important == 1) { + if (isImportant) { + minChannelMessageId = Math.min(minChannelMessageId, message.id); + maxChannelMessageId = Math.max(maxChannelMessageId, message.id); + if (lastChannelImportantId == -1) { + countBeforeImportant = countAfterImportant; + } else { + if (countAfterImportant != 0) { + TLRPC.TL_messageGroup group = new TLRPC.TL_messageGroup(); + group.max_id = lastChannelImportantId; + group.min_id = message.id; + group.count = countAfterImportant; + messages.collapsed.add(group); + } + } + countAfterImportant = 0; + lastChannelImportantId = message.id; + } else { + countAfterImportant++; + } + } + + fixUnsupportedMedia(message); + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); + message.serializeToStream(data); + state.bindLong(1, messageId); + state.bindLong(2, dialog_id); + state.bindInteger(3, MessageObject.getUnreadFlags(message)); + state.bindInteger(4, message.send_state); + state.bindInteger(5, message.date); + state.bindByteBuffer(6, data); + state.bindInteger(7, (MessageObject.isOut(message) ? 1 : 0)); + state.bindInteger(8, 0); + if ((message.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { + state.bindInteger(9, message.views); + } else { + state.bindInteger(9, 0); + } + state.bindInteger(10, isImportant ? 1 : 0); + state.step(); + + if (SharedMediaQuery.canAddMessageToMedia(message)) { + state2.requery(); + state2.bindLong(1, messageId); + state2.bindLong(2, dialog_id); + state2.bindInteger(3, message.date); + state2.bindInteger(4, SharedMediaQuery.getMediaType(message)); + state2.bindByteBuffer(5, data); + state2.step(); + } + data.reuse(); + + if (load_type == 0 && isValidKeyboardToSave(message)) { + if (botKeyboard == null || botKeyboard.id < message.id) { + botKeyboard = message; + } + } + } + state.dispose(); + state2.dispose(); + if (botKeyboard != null) { + BotQuery.putBotKeyboard(dialog_id, botKeyboard); + } + + if (load_type >= 0 && important != 0) { + /*if ((messages.flags & 1) == 0) { + if (countBeforeImportant != 0) { + if (load_type == 0) { + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT start, count FROM channel_group WHERE uid = %d AND start <= %d ORDER BY start ASC LIMIT 1", dialog_id, maxChannelMessageId)); + if (cursor.next()) { + int currentStart = cursor.intValue(0); + int currentCount = cursor.intValue(1); + database.executeFast(String.format(Locale.US, "UPDATE channel_group SET start = %d, count = %d WHERE uid = %d AND start = %d", maxChannelMessageId, cursor.intValue(1) + countBeforeImportant, dialog_id, cursor.intValue(0))).stepThis().dispose(); + } else { + TLRPC.TL_messageGroup group = new TLRPC.TL_messageGroup(); + group.max_id = max_id != 0 ? max_id : Integer.MAX_VALUE; + group.min_id = maxChannelMessageId; + group.count = countBeforeImportant; + messages.collapsed.add(group); + } + cursor.dispose(); + } + } + if (countAfterImportant != 0) { + if (load_type == 0) { + TLRPC.TL_messageGroup group = new TLRPC.TL_messageGroup(); + group.max_id = minChannelMessageId; + group.min_id = 0; + group.count = countBeforeImportant; + messages.collapsed.add(group); + } + } + }*/ + if (!messages.collapsed.isEmpty()) { + state = database.executeFast("REPLACE INTO channel_group VALUES(?, ?, ?, ?)"); + for (int a = 0; a < messages.collapsed.size(); a++) { + TLRPC.TL_messageGroup group = messages.collapsed.get(a); + if (group.min_id > group.max_id) { + int temp = group.min_id; + group.min_id = group.max_id; + group.max_id = temp; + } + state.requery(); + state.bindLong(1, dialog_id); + state.bindInteger(2, group.min_id); + state.bindInteger(3, group.max_id); + state.bindInteger(4, group.count); + state.step(); + } + state.dispose(); + } + if (important == 1) { + messages.collapsed.clear(); + } + } + + putUsersInternal(messages.users); + putChatsInternal(messages.chats); + + database.commitTransaction(); + + if (createDialog) { + MessagesStorage.getInstance().updateDialogsWithDeletedMessages(new ArrayList(), false, channelId); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public static void addUsersAndChatsFromMessage(TLRPC.Message message, ArrayList usersToLoad, ArrayList chatsToLoad) { + if (message.from_id != 0) { + if (message.from_id > 0) { + if (!usersToLoad.contains(message.from_id)) { + usersToLoad.add(message.from_id); + } + } else { + if (!chatsToLoad.contains(-message.from_id)) { + chatsToLoad.add(-message.from_id); + } + } + } + if (message.via_bot_id != 0 && !usersToLoad.contains(message.via_bot_id)) { + usersToLoad.add(message.via_bot_id); + } + if (message.action != null) { + if (message.action.user_id != 0 && !usersToLoad.contains(message.action.user_id)) { + usersToLoad.add(message.action.user_id); + } + if (message.action.channel_id != 0 && !chatsToLoad.contains(message.action.channel_id)) { + chatsToLoad.add(message.action.channel_id); + } + if (message.action.chat_id != 0 && !chatsToLoad.contains(message.action.chat_id)) { + chatsToLoad.add(message.action.chat_id); + } + if (!message.action.users.isEmpty()) { + for (int a = 0; a < message.action.users.size(); a++) { + Integer uid = message.action.users.get(a); + if (!usersToLoad.contains(uid)) { + usersToLoad.add(uid); + } + } + } + } + if (message.media != null) { + if (message.media.user_id != 0 && !usersToLoad.contains(message.media.user_id)) { + usersToLoad.add(message.media.user_id); + } + } + if (message.fwd_from != null) { + if (message.fwd_from.from_id != 0) { + if (!usersToLoad.contains(message.fwd_from.from_id)) { + usersToLoad.add(message.fwd_from.from_id); + } + } + if (message.fwd_from.channel_id != 0) { + if (!chatsToLoad.contains(message.fwd_from.channel_id)) { + chatsToLoad.add(message.fwd_from.channel_id); + } + } + } + if (message.ttl < 0) { + if (!chatsToLoad.contains(-message.ttl)) { + chatsToLoad.add(-message.ttl); + } + } + } + + public void getDialogs(final int offset, final int count) { + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + TLRPC.messages_Dialogs dialogs = new TLRPC.messages_Dialogs(); + ArrayList encryptedChats = new ArrayList<>(); + try { + ArrayList usersToLoad = new ArrayList<>(); + usersToLoad.add(UserConfig.getClientUserId()); + ArrayList chatsToLoad = new ArrayList<>(); + ArrayList encryptedToLoad = new ArrayList<>(); + ArrayList replyMessages = new ArrayList<>(); + HashMap replyMessageOwners = new HashMap<>(); + SQLiteCursor cursor = database.queryFinalized(String.format(Locale.US, "SELECT d.did, d.last_mid, d.unread_count, d.date, m.data, m.read_state, m.mid, m.send_state, s.flags, m.date, d.last_mid_i, d.unread_count_i, d.pts, d.inbox_max, d.date_i, m.replydata FROM dialogs as d LEFT JOIN messages as m ON d.last_mid = m.mid LEFT JOIN dialog_settings as s ON d.did = s.did ORDER BY d.date DESC LIMIT %d,%d", offset, count)); + while (cursor.next()) { + TLRPC.Dialog dialog; + int pts = cursor.intValue(12); + long id = cursor.longValue(0); + if (pts == 0 || (int) id > 0) { + dialog = new TLRPC.TL_dialog(); + } else { + dialog = new TLRPC.TL_dialogChannel(); + } + dialog.id = id; + dialog.top_message = cursor.intValue(1); + dialog.unread_count = cursor.intValue(2); + dialog.last_message_date = cursor.intValue(3); + dialog.pts = pts; + dialog.read_inbox_max_id = cursor.intValue(13); + dialog.last_message_date_i = cursor.intValue(14); + dialog.top_not_important_message = cursor.intValue(10); + dialog.unread_not_important_count = cursor.intValue(11); + long flags = cursor.longValue(8); + int low_flags = (int)flags; + dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); + if ((low_flags & 1) != 0) { + dialog.notify_settings.mute_until = (int)(flags >> 32); + if (dialog.notify_settings.mute_until == 0) { + dialog.notify_settings.mute_until = Integer.MAX_VALUE; + } + } + dialogs.dialogs.add(dialog); + + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(4)); + if (cursor.byteBufferValue(4, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + if (message != null) { + MessageObject.setUnreadFlags(message, cursor.intValue(5)); + message.id = cursor.intValue(6); + int date = cursor.intValue(9); + if (date != 0) { + dialog.last_message_date = date; + } + message.send_state = cursor.intValue(7); + message.dialog_id = dialog.id; + dialogs.messages.add(message); + + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + + try { + if (message.reply_to_msg_id != 0 && message.action instanceof TLRPC.TL_messageActionPinMessage) { + if (!cursor.isNull(15)) { + NativeByteBuffer data2 = new NativeByteBuffer(cursor.byteArrayLength(15)); + if (cursor.byteBufferValue(15, data2) != 0) { + message.replyMessage = TLRPC.Message.TLdeserialize(data2, data2.readInt32(false), false); + if (message.replyMessage != null) { + addUsersAndChatsFromMessage(message.replyMessage, usersToLoad, chatsToLoad); + } + } + data2.reuse(); + } + if (message.replyMessage == null) { + long messageId = message.reply_to_msg_id; + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; + } + if (!replyMessages.contains(messageId)) { + replyMessages.add(messageId); + } + replyMessageOwners.put(dialog.id, message); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + data.reuse(); + + int lower_id = (int)dialog.id; + int high_id = (int)(dialog.id >> 32); + if (lower_id != 0) { + if (high_id == 1) { + if (!chatsToLoad.contains(lower_id)) { + chatsToLoad.add(lower_id); + } + } else { + if (lower_id > 0) { + if (!usersToLoad.contains(lower_id)) { + usersToLoad.add(lower_id); + } + } else { + if (!chatsToLoad.contains(-lower_id)) { + chatsToLoad.add(-lower_id); + } + } + } + } else { + if (!encryptedToLoad.contains(high_id)) { + encryptedToLoad.add(high_id); + } + } + } + cursor.dispose(); + + if (!replyMessages.isEmpty()) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid, date, uid FROM messages WHERE mid IN(%s)", TextUtils.join(",", replyMessages))); + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (cursor.byteBufferValue(0, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.id = cursor.intValue(1); + message.date = cursor.intValue(2); + message.dialog_id = cursor.longValue(3); + + addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + + TLRPC.Message owner = replyMessageOwners.get(message.dialog_id); + if (owner != null) { + owner.replyMessage = message; + message.dialog_id = owner.dialog_id; + } + } + data.reuse(); + } + cursor.dispose(); + } + + if (!encryptedToLoad.isEmpty()) { + getEncryptedChatsInternal(TextUtils.join(",", encryptedToLoad), encryptedChats, usersToLoad); + } + + if (!chatsToLoad.isEmpty()) { + getChatsInternal(TextUtils.join(",", chatsToLoad), dialogs.chats); + } + if (!usersToLoad.isEmpty()) { + getUsersInternal(TextUtils.join(",", usersToLoad), dialogs.users); + } + MessagesController.getInstance().processLoadedDialogs(dialogs, encryptedChats, offset, count, true, false, false); + } catch (Exception e) { + dialogs.dialogs.clear(); + dialogs.users.clear(); + dialogs.chats.clear(); + encryptedChats.clear(); + FileLog.e("tmessages", e); + MessagesController.getInstance().processLoadedDialogs(dialogs, encryptedChats, 0, 100, true, true, false); + } + } + }); + } + + public static void createFirstHoles(long did, SQLitePreparedStatement state5, SQLitePreparedStatement state6, SQLitePreparedStatement state7, SQLitePreparedStatement state8, ArrayList arrayList) throws Exception { + int impMessageId = 0; + int notImpMessageId = 0; + for (int a = 0; a < arrayList.size(); a++) { + TLRPC.Message message = arrayList.get(a); + + if (MessageObject.isImportant(message)) { + state7.requery(); + state7.bindLong(1, did); + state7.bindInteger(2, message.id == 1 ? 1 : 0); + state7.bindInteger(3, message.id); + state7.step(); + impMessageId = Math.max(message.id, impMessageId); + } else { + notImpMessageId = Math.max(message.id, notImpMessageId); + } + } + + if (impMessageId != 0 && notImpMessageId == 0) { + notImpMessageId = impMessageId; + impMessageId = 0; + } + + if (arrayList.size() == 1) { + int messageId = arrayList.get(0).id; + + state5.requery(); + state5.bindLong(1, did); + state5.bindInteger(2, messageId == 1 ? 1 : 0); + state5.bindInteger(3, messageId); + state5.step(); + + for (int b = 0; b < SharedMediaQuery.MEDIA_TYPES_COUNT; b++) { + state6.requery(); + state6.bindLong(1, did); + state6.bindInteger(2, b); + state6.bindInteger(3, messageId == 1 ? 1 : 0); + state6.bindInteger(4, messageId); + state6.step(); + } + } else if (arrayList.size() == 2) { + int firstId = arrayList.get(0).id; + int lastId = arrayList.get(1).id; + if (firstId > lastId) { + int temp = firstId; + firstId = lastId; + lastId = temp; + } + + state5.requery(); + state5.bindLong(1, did); + state5.bindInteger(2, firstId == 1 ? 1 : 0); + state5.bindInteger(3, firstId); + state5.step(); + + state5.requery(); + state5.bindLong(1, did); + state5.bindInteger(2, firstId); + state5.bindInteger(3, lastId); + state5.step(); + + for (int b = 0; b < SharedMediaQuery.MEDIA_TYPES_COUNT; b++) { + state6.requery(); + state6.bindLong(1, did); + state6.bindInteger(2, b); + state6.bindInteger(3, firstId == 1 ? 1 : 0); + state6.bindInteger(4, firstId); + state6.step(); + + state6.requery(); + state6.bindLong(1, did); + state6.bindInteger(2, b); + state6.bindInteger(3, firstId); + state6.bindInteger(4, lastId); + state6.step(); + } + + if (impMessageId != 0 && impMessageId < notImpMessageId) { + state8.requery(); + state8.bindLong(1, did); + state8.bindInteger(2, impMessageId); + state8.bindInteger(3, Integer.MAX_VALUE); + state8.bindInteger(4, notImpMessageId - impMessageId); + state8.step(); + } + } + } + + private void putDialogsInternal(final TLRPC.messages_Dialogs dialogs) { + try { + database.beginTransaction(); + final HashMap> new_dialogMessage = new HashMap<>(); + for (int a = 0; a < dialogs.messages.size(); a++) { + TLRPC.Message message = dialogs.messages.get(a); + ArrayList arrayList = new_dialogMessage.get(message.dialog_id); + if (arrayList == null) { + arrayList = new ArrayList<>(); + new_dialogMessage.put(message.dialog_id, arrayList); + } + arrayList.add(message); + } + + if (!dialogs.dialogs.isEmpty()) { + SQLitePreparedStatement state = database.executeFast("REPLACE INTO messages VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?)"); + SQLitePreparedStatement state2 = database.executeFast("REPLACE INTO dialogs VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + SQLitePreparedStatement state3 = database.executeFast("REPLACE INTO media_v2 VALUES(?, ?, ?, ?, ?)"); + SQLitePreparedStatement state4 = database.executeFast("REPLACE INTO dialog_settings VALUES(?, ?)"); + SQLitePreparedStatement state5 = database.executeFast("REPLACE INTO messages_holes VALUES(?, ?, ?)"); + SQLitePreparedStatement state6 = database.executeFast("REPLACE INTO media_holes_v2 VALUES(?, ?, ?, ?)"); + SQLitePreparedStatement state7 = database.executeFast("REPLACE INTO messages_imp_holes VALUES(?, ?, ?)"); + SQLitePreparedStatement state8 = database.executeFast("REPLACE INTO channel_group VALUES(?, ?, ?, ?)"); + + for (int a = 0; a < dialogs.dialogs.size(); a++) { + TLRPC.Dialog dialog = dialogs.dialogs.get(a); + + if (dialog.id == 0) { + if (dialog.peer.user_id != 0) { + dialog.id = dialog.peer.user_id; + } else if (dialog.peer.chat_id != 0) { + dialog.id = -dialog.peer.chat_id; + } else { + dialog.id = -dialog.peer.channel_id; + } + } + int messageDate = 0; + int messageDateI = 0; + + boolean isMegagroup = false; + ArrayList arrayList = new_dialogMessage.get(dialog.id); + if (arrayList != null) { + for (int b = 0; b < arrayList.size(); b++) { + TLRPC.Message message = arrayList.get(b); + if (message.to_id.channel_id == 0 || MessageObject.isImportant(message)) { + messageDate = Math.max(message.date, messageDate); + } else { + messageDateI = Math.max(message.date, messageDateI); + } + isMegagroup = MessageObject.isMegagroup(message); + + if (isValidKeyboardToSave(message)) { + BotQuery.putBotKeyboard(dialog.id, message); + } + + fixUnsupportedMedia(message); + NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); + message.serializeToStream(data); + + long messageId = message.id; + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; + } + + state.requery(); + state.bindLong(1, messageId); + state.bindLong(2, dialog.id); + state.bindInteger(3, MessageObject.getUnreadFlags(message)); + state.bindInteger(4, message.send_state); + state.bindInteger(5, message.date); + state.bindByteBuffer(6, data); + state.bindInteger(7, (MessageObject.isOut(message) ? 1 : 0)); + state.bindInteger(8, 0); + if ((message.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { + state.bindInteger(9, message.views); + } else { + state.bindInteger(9, 0); + } + state.bindInteger(10, MessageObject.isImportant(message) ? 1 : 0); + state.step(); + + if (SharedMediaQuery.canAddMessageToMedia(message)) { + state3.requery(); + state3.bindLong(1, messageId); + state3.bindLong(2, dialog.id); + state3.bindInteger(3, message.date); + state3.bindInteger(4, SharedMediaQuery.getMediaType(message)); + state3.bindByteBuffer(5, data); + state3.step(); + } + data.reuse(); + } + + createFirstHoles(dialog.id, state5, state6, state7, state8, arrayList); + } + + long topMessage = dialog.top_message; + long topMessageI = dialog.top_not_important_message; + if (dialog.peer.channel_id != 0) { + if (isMegagroup) { + topMessage = topMessageI = Math.max(topMessage, topMessageI); + messageDate = messageDateI = Math.max(messageDate, messageDateI); + } + topMessage |= ((long) dialog.peer.channel_id) << 32; + topMessageI |= ((long) dialog.peer.channel_id) << 32; + } + + state2.requery(); + state2.bindLong(1, dialog.id); + state2.bindInteger(2, messageDate); + state2.bindInteger(3, dialog.unread_count); + state2.bindLong(4, topMessage); + state2.bindInteger(5, dialog.read_inbox_max_id); + state2.bindInteger(6, 0); + state2.bindLong(7, topMessageI); + state2.bindInteger(8, dialog.unread_not_important_count); + state2.bindInteger(9, dialog.pts); + state2.bindInteger(10, messageDateI); + state2.step(); + + if (dialog.notify_settings != null) { + state4.requery(); + state4.bindLong(1, dialog.id); + state4.bindInteger(2, dialog.notify_settings.mute_until != 0 ? 1 : 0); + state4.step(); + } + } + state.dispose(); + state2.dispose(); + state3.dispose(); + state4.dispose(); + state5.dispose(); + state6.dispose(); + state7.dispose(); + state8.dispose(); + } + + putUsersInternal(dialogs.users); + putChatsInternal(dialogs.chats); + + database.commitTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void putDialogs(final TLRPC.messages_Dialogs dialogs) { + if (dialogs.dialogs.isEmpty()) { + return; + } + storageQueue.postRunnable(new Runnable() { + @Override + public void run() { + putDialogsInternal(dialogs); + loadUnreadMessages(); + } + }); + } + + public int getChannelReadInboxMax(final int channelId) { + final Semaphore semaphore = new Semaphore(0); + final Integer[] max = new Integer[] {0}; + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + SQLiteCursor cursor = null; + try { + cursor = database.queryFinalized("SELECT inbox_max FROM dialogs WHERE did = " + (-channelId)); + if (cursor.next()) { + max[0] = cursor.intValue(0); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + semaphore.release(); + } + }); + try { + semaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return max[0]; + } + + public int getChannelPtsSync(final int channelId) { + final Semaphore semaphore = new Semaphore(0); + final Integer[] pts = new Integer[] {0}; + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + SQLiteCursor cursor = null; + try { + cursor = database.queryFinalized("SELECT pts FROM dialogs WHERE did = " + (-channelId)); + if (cursor.next()) { + pts[0] = cursor.intValue(0); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + try { + if (semaphore != null) { + semaphore.release(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + try { + semaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return pts[0]; + } + + public TLRPC.User getUserSync(final int user_id) { + final Semaphore semaphore = new Semaphore(0); + final TLRPC.User[] user = new TLRPC.User[1]; + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + user[0] = getUser(user_id); + semaphore.release(); + } + }); + try { + semaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return user[0]; + } + + public TLRPC.Chat getChatSync(final int user_id) { + final Semaphore semaphore = new Semaphore(0); + final TLRPC.Chat[] chat = new TLRPC.Chat[1]; + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + chat[0] = getChat(user_id); + semaphore.release(); + } + }); + try { + semaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return chat[0]; + } + + public TLRPC.User getUser(final int user_id) { + TLRPC.User user = null; + try { + ArrayList users = new ArrayList<>(); + getUsersInternal("" + user_id, users); + if (!users.isEmpty()) { + user = users.get(0); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return user; + } + + public ArrayList getUsers(final ArrayList uids) { + ArrayList users = new ArrayList<>(); + try { + getUsersInternal(TextUtils.join(",", uids), users); + } catch (Exception e) { + users.clear(); + FileLog.e("tmessages", e); + } + return users; + } + + public TLRPC.Chat getChat(final int chat_id) { + TLRPC.Chat chat = null; + try { + ArrayList chats = new ArrayList<>(); + getChatsInternal("" + chat_id, chats); + if (!chats.isEmpty()) { + chat = chats.get(0); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return chat; + } + + public TLRPC.EncryptedChat getEncryptedChat(final int chat_id) { + TLRPC.EncryptedChat chat = null; + try { + ArrayList encryptedChats = new ArrayList<>(); + getEncryptedChatsInternal("" + chat_id, encryptedChats, null); + if (!encryptedChats.isEmpty()) { + chat = encryptedChats.get(0); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return chat; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ModuleContentProvider.java b/TMessagesProj/src/main/java/org/telegram/messenger/ModuleContentProvider.java new file mode 100644 index 00000000..062cde02 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ModuleContentProvider.java @@ -0,0 +1,125 @@ +package org.telegram.messenger; + +import android.app.Activity; +import android.content.ContentProvider; +import android.content.ContentValues; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.net.Uri; +import android.os.Environment; +import android.util.Log; + +import java.io.File; + +public class ModuleContentProvider extends ContentProvider { + private static final String TAG = "ModuleContentProvider"; + + private static final String AUTHORITY = "org.telegram.plus.android.provider.content"; + private static final String AUTHORITY_BETA = "org.telegram.plus.beta.android.provider.content"; + + public static Uri THEME_URI = Uri.parse("content://" + AUTHORITY + "/theme"); + public static Uri GET_NAME = Uri.parse("content://" + AUTHORITY + "/name"); + public static Uri SET_NAME = Uri.parse("content://" + AUTHORITY + "/newname"); + + /*private static final UriMatcher sUriMatcher; + static { + sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); + sUriMatcher.addURI(AUTHORITY, "theme", 1); + sUriMatcher.addURI(AUTHORITY, "name", 2); + }*/ + + @Override + public boolean onCreate() { + //Log.d(TAG, "onCreate"); + return true; + } + + @Override + public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String orderBy) { + Log.d(TAG, "query with uri: " + uri.toString()); + return null; + } + + @Override + public String getType(Uri uri) { + if(BuildConfig.DEBUG)GET_NAME = Uri.parse("content://" + AUTHORITY_BETA + "/name"); + if(uri.equals(GET_NAME)){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences("theme", Activity.MODE_PRIVATE); + return themePrefs.getString("themeName","empty"); + }else{ + throw new IllegalArgumentException("Unknown URI " + uri); + } + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + Log.d(TAG, "insert uri: " + uri.toString()); + if(BuildConfig.DEBUG)SET_NAME = Uri.parse("content://" + AUTHORITY_BETA + "/newname"); + if(uri.toString().contains(SET_NAME.toString())){ + /*String sName = uri.toString(); + sName = sName.substring(sName.lastIndexOf(":")+1, sName.length()); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + SharedPreferences.Editor editor = themePrefs.edit(); + editor.putString("themeName", sName); + editor.commit();*/ + + AndroidUtilities.themeUpdated = true; + }else{ + throw new UnsupportedOperationException(); + } + return uri; + } + + @Override + public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { + //Log.d(TAG, "update uri: " + uri.toString()); + if(BuildConfig.DEBUG)THEME_URI = Uri.parse("content://" + AUTHORITY_BETA + "/theme"); + if(uri.toString().contains(THEME_URI.toString())){ + String theme = uri.toString(); + theme = theme.substring(theme.lastIndexOf(":")+1, theme.length()); + //Log.d(TAG, theme); + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { + File themeFile = new File(theme); + if(themeFile.exists()){ + applyTheme(theme); + return 10; + } + return 20;//theme doesn't exists + } + return 30;// MEDIA no mounted + }else{ + throw new UnsupportedOperationException(); + } + } + + @Override + public int delete(Uri uri, String where, String[] selectionArgs) { + //Log.d(TAG, "delete uri: " + uri.toString()); + throw new UnsupportedOperationException(); + } + + private void applyTheme(final String xmlFile){ + String sName = xmlFile.substring(0, xmlFile.lastIndexOf(".")); + String wName = sName + "_wallpaper.jpg"; + File wFile = new File(wName); + if(wFile.exists()){ + //Change Stock Background to set Custom Wallpaper + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + int selectedBackground = preferences.getInt("selectedBackground", 1000001); + if (selectedBackground == 1000001) { + //File toFile = new File(ApplicationLoader.applicationContext.getFilesDir(), "wallpaper.jpg"); + //if (!toFile.exists()) { + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("selectedBackground", 113); + editor.putInt("selectedColor", 0); + editor.commit(); + //} + } + } + if(Utilities.loadPrefFromSD(ApplicationLoader.applicationContext, xmlFile) == 4){ + //Utilities.loadWallpaperFromSDPath(ApplicationLoader.applicationContext, wName); + Utilities.applyWallpaper(wName); + AndroidUtilities.needRestart = true; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerReceiver.java new file mode 100644 index 00000000..5af30d3e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerReceiver.java @@ -0,0 +1,69 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.view.KeyEvent; + +public class MusicPlayerReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_MEDIA_BUTTON)) { + if (intent.getExtras() == null) { + return; + } + KeyEvent keyEvent = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT); + if (keyEvent == null) { + return; + } + if (keyEvent.getAction() != KeyEvent.ACTION_DOWN) + return; + + switch (keyEvent.getKeyCode()) { + case KeyEvent.KEYCODE_HEADSETHOOK: + case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: + if (MediaController.getInstance().isAudioPaused()) { + MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject()); + } else { + MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject()); + } + break; + case KeyEvent.KEYCODE_MEDIA_PLAY: + MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject()); + break; + case KeyEvent.KEYCODE_MEDIA_PAUSE: + MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject()); + break; + case KeyEvent.KEYCODE_MEDIA_STOP: + break; + case KeyEvent.KEYCODE_MEDIA_NEXT: + MediaController.getInstance().playNextMessage(); + break; + case KeyEvent.KEYCODE_MEDIA_PREVIOUS: + MediaController.getInstance().playPreviousMessage(); + break; + } + } else { + if (intent.getAction().equals(MusicPlayerService.NOTIFY_PLAY)) { + MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject()); + } else if (intent.getAction().equals(MusicPlayerService.NOTIFY_PAUSE) || intent.getAction().equals(android.media.AudioManager.ACTION_AUDIO_BECOMING_NOISY)) { + MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject()); + } else if (intent.getAction().equals(MusicPlayerService.NOTIFY_NEXT)) { + MediaController.getInstance().playNextMessage(); + } else if (intent.getAction().equals(MusicPlayerService.NOTIFY_CLOSE)) { + MediaController.getInstance().cleanupPlayer(true, true); + } else if (intent.getAction().equals(MusicPlayerService.NOTIFY_PREVIOUS)) { + MediaController.getInstance().playPreviousMessage(); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerService.java b/TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerService.java new file mode 100644 index 00000000..e1bbf951 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/MusicPlayerService.java @@ -0,0 +1,237 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.annotation.SuppressLint; +import android.app.Notification; +import android.app.PendingIntent; +import android.app.Service; +import android.content.ComponentName; +import android.content.Intent; +import android.graphics.Bitmap; +import android.media.AudioManager; +import android.media.MediaMetadataRetriever; +import android.media.RemoteControlClient; +import android.os.Build; +import android.os.IBinder; +import android.support.v4.app.NotificationCompat; +import android.view.View; +import android.widget.RemoteViews; + +import org.telegram.messenger.audioinfo.AudioInfo; +import org.telegram.ui.LaunchActivity; + +public class MusicPlayerService extends Service implements NotificationCenter.NotificationCenterDelegate { + + public static final String NOTIFY_PREVIOUS = "org.telegram.android.musicplayer.previous"; + public static final String NOTIFY_CLOSE = "org.telegram.android.musicplayer.close"; + public static final String NOTIFY_PAUSE = "org.telegram.android.musicplayer.pause"; + public static final String NOTIFY_PLAY = "org.telegram.android.musicplayer.play"; + public static final String NOTIFY_NEXT = "org.telegram.android.musicplayer.next"; + + private RemoteControlClient remoteControlClient; + private AudioManager audioManager; + + private static boolean supportBigNotifications = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; + private static boolean supportLockScreenControls = Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH; + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public void onCreate() { + audioManager = (AudioManager) getSystemService(AUDIO_SERVICE); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioProgressDidChanged); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioPlayStateChanged); + super.onCreate(); + } + + @SuppressLint("NewApi") + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + try { + MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); + if (messageObject == null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + stopSelf(); + } + }); + return START_STICKY; + } + if (supportLockScreenControls) { + ComponentName remoteComponentName = new ComponentName(getApplicationContext(), MusicPlayerReceiver.class.getName()); + try { + if (remoteControlClient == null) { + audioManager.registerMediaButtonEventReceiver(remoteComponentName); + Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); + mediaButtonIntent.setComponent(remoteComponentName); + PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(this, 0, mediaButtonIntent, 0); + remoteControlClient = new RemoteControlClient(mediaPendingIntent); + audioManager.registerRemoteControlClient(remoteControlClient); + } + remoteControlClient.setTransportControlFlags(RemoteControlClient.FLAG_KEY_MEDIA_PLAY | RemoteControlClient.FLAG_KEY_MEDIA_PAUSE | RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE | + RemoteControlClient.FLAG_KEY_MEDIA_STOP | RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS | RemoteControlClient.FLAG_KEY_MEDIA_NEXT); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + createNotification(messageObject); + } catch (Exception e) { + e.printStackTrace(); + } + return START_STICKY; + } + + @SuppressLint("NewApi") + private void createNotification(MessageObject messageObject) { + String songName = messageObject.getMusicTitle(); + String authorName = messageObject.getMusicAuthor(); + AudioInfo audioInfo = MediaController.getInstance().getAudioInfo(); + + RemoteViews simpleContentView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.player_small_notification); + RemoteViews expandedView = null; + if (supportBigNotifications) { + expandedView = new RemoteViews(getApplicationContext().getPackageName(), R.layout.player_big_notification); + } + + Intent intent = new Intent(ApplicationLoader.applicationContext, LaunchActivity.class); + intent.setAction("com.tmessages.openplayer"); + intent.setFlags(32768); + PendingIntent contentIntent = PendingIntent.getActivity(ApplicationLoader.applicationContext, 0, intent, 0); + + Notification notification = new NotificationCompat.Builder(getApplicationContext()) + .setSmallIcon(R.drawable.player) + .setContentIntent(contentIntent) + .setContentTitle(songName).build(); + + notification.contentView = simpleContentView; + if (supportBigNotifications) { + notification.bigContentView = expandedView; + } + + setListeners(simpleContentView); + if (supportBigNotifications) { + setListeners(expandedView); + } + + Bitmap albumArt = audioInfo != null ? audioInfo.getSmallCover() : null; + if (albumArt != null) { + notification.contentView.setImageViewBitmap(R.id.player_album_art, albumArt); + if (supportBigNotifications) { + notification.bigContentView.setImageViewBitmap(R.id.player_album_art, albumArt); + } + } else { + notification.contentView.setImageViewResource(R.id.player_album_art, R.drawable.nocover_small); + if (supportBigNotifications) { + notification.bigContentView.setImageViewResource(R.id.player_album_art, R.drawable.nocover_big); + } + } + if (MediaController.getInstance().isDownloadingCurrentMessage()) { + notification.contentView.setViewVisibility(R.id.player_pause, View.GONE); + notification.contentView.setViewVisibility(R.id.player_play, View.GONE); + notification.contentView.setViewVisibility(R.id.player_next, View.GONE); + notification.contentView.setViewVisibility(R.id.player_previous, View.GONE); + notification.contentView.setViewVisibility(R.id.player_progress_bar, View.VISIBLE); + if (supportBigNotifications) { + notification.bigContentView.setViewVisibility(R.id.player_pause, View.GONE); + notification.bigContentView.setViewVisibility(R.id.player_play, View.GONE); + notification.bigContentView.setViewVisibility(R.id.player_next, View.GONE); + notification.bigContentView.setViewVisibility(R.id.player_previous, View.GONE); + notification.bigContentView.setViewVisibility(R.id.player_progress_bar, View.VISIBLE); + } + } else { + notification.contentView.setViewVisibility(R.id.player_progress_bar, View.GONE); + notification.contentView.setViewVisibility(R.id.player_next, View.VISIBLE); + notification.contentView.setViewVisibility(R.id.player_previous, View.VISIBLE); + if (supportBigNotifications) { + notification.bigContentView.setViewVisibility(R.id.player_next, View.VISIBLE); + notification.bigContentView.setViewVisibility(R.id.player_previous, View.VISIBLE); + notification.bigContentView.setViewVisibility(R.id.player_progress_bar, View.GONE); + } + + if (MediaController.getInstance().isAudioPaused()) { + notification.contentView.setViewVisibility(R.id.player_pause, View.GONE); + notification.contentView.setViewVisibility(R.id.player_play, View.VISIBLE); + if (supportBigNotifications) { + notification.bigContentView.setViewVisibility(R.id.player_pause, View.GONE); + notification.bigContentView.setViewVisibility(R.id.player_play, View.VISIBLE); + } + } else { + notification.contentView.setViewVisibility(R.id.player_pause, View.VISIBLE); + notification.contentView.setViewVisibility(R.id.player_play, View.GONE); + if (supportBigNotifications) { + notification.bigContentView.setViewVisibility(R.id.player_pause, View.VISIBLE); + notification.bigContentView.setViewVisibility(R.id.player_play, View.GONE); + } + } + } + + notification.contentView.setTextViewText(R.id.player_song_name, songName); + notification.contentView.setTextViewText(R.id.player_author_name, authorName); + if (supportBigNotifications) { + notification.bigContentView.setTextViewText(R.id.player_song_name, songName); + notification.bigContentView.setTextViewText(R.id.player_author_name, authorName); + } + notification.flags |= Notification.FLAG_ONGOING_EVENT; + startForeground(5, notification); + + if (remoteControlClient != null) { + RemoteControlClient.MetadataEditor metadataEditor = remoteControlClient.editMetadata(true); + metadataEditor.putString(MediaMetadataRetriever.METADATA_KEY_ARTIST, authorName); + metadataEditor.putString(MediaMetadataRetriever.METADATA_KEY_TITLE, songName); + if (audioInfo != null && audioInfo.getCover() != null) { + metadataEditor.putBitmap(RemoteControlClient.MetadataEditor.BITMAP_KEY_ARTWORK, audioInfo.getCover()); + } + metadataEditor.apply(); + } + } + + public void setListeners(RemoteViews view) { + PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, new Intent(NOTIFY_PREVIOUS), PendingIntent.FLAG_UPDATE_CURRENT); + view.setOnClickPendingIntent(R.id.player_previous, pendingIntent); + pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, new Intent(NOTIFY_CLOSE), PendingIntent.FLAG_UPDATE_CURRENT); + view.setOnClickPendingIntent(R.id.player_close, pendingIntent); + pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, new Intent(NOTIFY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT); + view.setOnClickPendingIntent(R.id.player_pause, pendingIntent); + pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, new Intent(NOTIFY_NEXT), PendingIntent.FLAG_UPDATE_CURRENT); + view.setOnClickPendingIntent(R.id.player_next, pendingIntent); + pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, new Intent(NOTIFY_PLAY), PendingIntent.FLAG_UPDATE_CURRENT); + view.setOnClickPendingIntent(R.id.player_play, pendingIntent); + } + + @SuppressLint("NewApi") + @Override + public void onDestroy() { + super.onDestroy(); + if (remoteControlClient != null) { + RemoteControlClient.MetadataEditor metadataEditor = remoteControlClient.editMetadata(true); + metadataEditor.clear(); + metadataEditor.apply(); + audioManager.unregisterRemoteControlClient(remoteControlClient); + } + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioProgressDidChanged); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioPlayStateChanged); + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.audioPlayStateChanged) { + MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); + if (messageObject != null) { + createNotification(messageObject); + } else { + stopSelf(); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NativeCrashManager.java b/TMessagesProj/src/main/java/org/telegram/messenger/NativeCrashManager.java new file mode 100644 index 00000000..e72e551f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NativeCrashManager.java @@ -0,0 +1,123 @@ +package org.telegram.messenger; + +import android.app.Activity; +import android.net.Uri; +import android.util.Log; + +import net.hockeyapp.android.Constants; +import net.hockeyapp.android.utils.SimpleMultipartEntity; + +import java.io.BufferedOutputStream; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Date; +import java.util.UUID; + +public class NativeCrashManager { + + public static void handleDumpFiles(Activity activity) { + String[] filenames = searchForDumpFiles(); + for (String dumpFilename : filenames) { + String logFilename = createLogFile(); + if (logFilename != null) { + uploadDumpAndLog(activity, BuildVars.DEBUG_VERSION ? BuildVars.HOCKEY_APP_HASH_DEBUG : BuildVars.HOCKEY_APP_HASH, dumpFilename, logFilename); + } + } + } + + public static String createLogFile() { + final Date now = new Date(); + + try { + String filename = UUID.randomUUID().toString(); + String path = Constants.FILES_PATH + "/" + filename + ".faketrace"; + //Log.d(Constants.TAG, "Writing unhandled exception to: " + path); + Log.d("NativeCrashManager", "Writing unhandled exception to: " + path); + BufferedWriter write = new BufferedWriter(new FileWriter(path)); + write.write("Package: " + Constants.APP_PACKAGE + "\n"); + write.write("Version Code: " + Constants.APP_VERSION + "\n"); + write.write("Version Name: " + Constants.APP_VERSION_NAME + "\n"); + write.write("Android: " + Constants.ANDROID_VERSION + "\n"); + write.write("Manufacturer: " + Constants.PHONE_MANUFACTURER + "\n"); + write.write("Model: " + Constants.PHONE_MODEL + "\n"); + write.write("Date: " + now + "\n"); + write.write("\n"); + write.write("MinidumpContainer"); + write.flush(); + write.close(); + return filename + ".faketrace"; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + return null; + } + + public static void uploadDumpAndLog(final Activity activity, final String identifier, final String dumpFilename, final String logFilename) { + new Thread() { + @Override + public void run() { + try { + SimpleMultipartEntity entity = new SimpleMultipartEntity(); + entity.writeFirstBoundaryIfNeeds(); + + Uri attachmentUri = Uri.fromFile(new File(Constants.FILES_PATH, dumpFilename)); + InputStream input = activity.getContentResolver().openInputStream(attachmentUri); + entity.addPart("attachment0", attachmentUri.getLastPathSegment(), input, false); + + attachmentUri = Uri.fromFile(new File(Constants.FILES_PATH, logFilename)); + input = activity.getContentResolver().openInputStream(attachmentUri); + entity.addPart("log", attachmentUri.getLastPathSegment(), input, true); + + entity.writeLastBoundaryIfNeeds(); + + HttpURLConnection urlConnection = (HttpURLConnection) new URL("https://rink.hockeyapp.net/api/2/apps/" + identifier + "/crashes/upload").openConnection(); + urlConnection.setDoOutput(true); + urlConnection.setRequestMethod("POST"); + urlConnection.setRequestProperty("Content-Type", entity.getContentType()); + urlConnection.setRequestProperty("Content-Length", String.valueOf(entity.getContentLength())); + + BufferedOutputStream outputStream = new BufferedOutputStream(urlConnection.getOutputStream()); + outputStream.write(entity.getOutputStream().toByteArray()); + outputStream.flush(); + outputStream.close(); + + urlConnection.connect(); + + FileLog.e("tmessages", "response code = " + urlConnection.getResponseCode() + " message = " + urlConnection.getResponseMessage()); + } catch (IOException e) { + e.printStackTrace(); + } finally { + activity.deleteFile(logFilename); + activity.deleteFile(dumpFilename); + } + } + }.start(); + } + + private static String[] searchForDumpFiles() { + if (Constants.FILES_PATH != null) { + File dir = new File(Constants.FILES_PATH + "/"); + boolean created = dir.mkdir(); + if (!created && !dir.exists()) { + return new String[0]; + } + FilenameFilter filter = new FilenameFilter() { + public boolean accept(File dir, String name) { + return name.endsWith(".dmp"); + } + }; + return dir.list(filter); + } else { + //FileLog.d(Constants.TAG, "Can't search for exception as file path is null."); + FileLog.d("NativeCrashManager", "Can't search for exception as file path is null."); + return new String[0]; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java b/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java new file mode 100644 index 00000000..48baf950 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NativeLoader.java @@ -0,0 +1,224 @@ +/* + * This is the source code of Telegram for Android v. 1.3.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.os.Build; + +import net.hockeyapp.android.Constants; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +public class NativeLoader { + + private final static int LIB_VERSION = 21; + private final static String LIB_NAME = "tmessages." + LIB_VERSION; + private final static String LIB_SO_NAME = "lib" + LIB_NAME + ".so"; + private final static String LOCALE_LIB_SO_NAME = "lib" + LIB_NAME + "loc.so"; + private String crashPath = ""; + + private static volatile boolean nativeLoaded = false; + + private static File getNativeLibraryDir(Context context) { + File f = null; + if (context != null) { + try { + f = new File((String)ApplicationInfo.class.getField("nativeLibraryDir").get(context.getApplicationInfo())); + } catch (Throwable th) { + th.printStackTrace(); + } + } + if (f == null) { + f = new File(context.getApplicationInfo().dataDir, "lib"); + } + if (f.isDirectory()) { + return f; + } + return null; + } + + private static boolean loadFromZip(Context context, File destDir, File destLocalFile, String folder) { + try { + for (File file : destDir.listFiles()) { + file.delete(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + ZipFile zipFile = null; + InputStream stream = null; + try { + zipFile = new ZipFile(context.getApplicationInfo().sourceDir); + ZipEntry entry = zipFile.getEntry("lib/" + folder + "/" + LIB_SO_NAME); + if (entry == null) { + throw new Exception("Unable to find file in apk:" + "lib/" + folder + "/" + LIB_NAME); + } + stream = zipFile.getInputStream(entry); + + OutputStream out = new FileOutputStream(destLocalFile); + byte[] buf = new byte[4096]; + int len; + while ((len = stream.read(buf)) > 0) { + Thread.yield(); + out.write(buf, 0, len); + } + out.close(); + + if (Build.VERSION.SDK_INT >= 9) { + destLocalFile.setReadable(true, false); + destLocalFile.setExecutable(true, false); + destLocalFile.setWritable(true); + } + + try { + System.load(destLocalFile.getAbsolutePath()); + init(Constants.FILES_PATH, BuildVars.DEBUG_VERSION); + nativeLoaded = true; + } catch (Error e) { + FileLog.e("tmessages", e); + } + return true; + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + if (zipFile != null) { + try { + zipFile.close(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + return false; + } + + public static synchronized void initNativeLibs(Context context) { + if (nativeLoaded) { + return; + } + + Constants.loadFromContext(context); + + try { + String folder; + try { + if (Build.CPU_ABI.equalsIgnoreCase("armeabi-v7a")) { + folder = "armeabi-v7a"; + } else if (Build.CPU_ABI.equalsIgnoreCase("armeabi")) { + folder = "armeabi"; + } else if (Build.CPU_ABI.equalsIgnoreCase("x86")) { + folder = "x86"; + } else if (Build.CPU_ABI.equalsIgnoreCase("mips")) { + folder = "mips"; + } else { + folder = "armeabi"; + FileLog.e("tmessages", "Unsupported arch: " + Build.CPU_ABI); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + folder = "armeabi"; + } + + String javaArch = System.getProperty("os.arch"); + if (javaArch != null && javaArch.contains("686")) { + folder = "x86"; + } + + if (Build.VERSION.SDK_INT == 8) { + File destFile = new File(context.getApplicationInfo().dataDir + "/lib", LIB_SO_NAME); + if (destFile.exists()) { + FileLog.d("tmessages", "Load normal lib"); + try { + System.loadLibrary(LIB_NAME); + init(Constants.FILES_PATH, BuildVars.DEBUG_VERSION); + nativeLoaded = true; + return; + } catch (Error e) { + FileLog.e("tmessages", e); + } + } else { + try { + System.loadLibrary(LIB_NAME); + init(Constants.FILES_PATH, BuildVars.DEBUG_VERSION); + nativeLoaded = true; + return; + } catch (Error e) { + FileLog.e("tmessages", e); + } + } + } else { + File destFile = getNativeLibraryDir(context); + if (destFile != null) { + destFile = new File(destFile, LIB_SO_NAME); + if (destFile.exists()) { + FileLog.d("tmessages", "load normal lib"); + try { + System.loadLibrary(LIB_NAME); + init(Constants.FILES_PATH, BuildVars.DEBUG_VERSION); + nativeLoaded = true; + return; + } catch (Error e) { + FileLog.e("tmessages", e); + } + } + } + } + + File destDir = new File(context.getFilesDir(), "lib"); + destDir.mkdirs(); + + File destLocalFile = new File(destDir, LOCALE_LIB_SO_NAME); + if (destLocalFile.exists()) { + try { + FileLog.d("tmessages", "Load local lib"); + System.load(destLocalFile.getAbsolutePath()); + init(Constants.FILES_PATH, BuildVars.DEBUG_VERSION); + nativeLoaded = true; + return; + } catch (Error e) { + FileLog.e("tmessages", e); + } + destLocalFile.delete(); + } + + FileLog.e("tmessages", "Library not found, arch = " + folder); + + if (loadFromZip(context, destDir, destLocalFile, folder)) { + return; + } + } catch (Throwable e) { + e.printStackTrace(); + } + + try { + System.loadLibrary(LIB_NAME); + init(Constants.FILES_PATH, BuildVars.DEBUG_VERSION); + nativeLoaded = true; + } catch (Error e) { + FileLog.e("tmessages", e); + } + } + + private static native void init(String path, boolean enable); + //public static native void crash(); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java new file mode 100644 index 00000000..34805eec --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationCenter.java @@ -0,0 +1,273 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.util.SparseArray; + +import java.util.ArrayList; + +public class NotificationCenter { + + private static int totalEvents = 1; + + public static final int didReceivedNewMessages = totalEvents++; + public static final int updateInterfaces = totalEvents++; + public static final int dialogsNeedReload = totalEvents++; + public static final int closeChats = totalEvents++; + public static final int messagesDeleted = totalEvents++; + public static final int messagesRead = totalEvents++; + public static final int messagesDidLoaded = totalEvents++; + public static final int messageReceivedByAck = totalEvents++; + public static final int messageReceivedByServer = totalEvents++; + public static final int messageSendError = totalEvents++; + public static final int contactsDidLoaded = totalEvents++; + public static final int chatDidCreated = totalEvents++; + public static final int chatDidFailCreate = totalEvents++; + public static final int chatInfoDidLoaded = totalEvents++; + public static final int chatInfoCantLoad = totalEvents++; + public static final int mediaDidLoaded = totalEvents++; + public static final int mediaCountDidLoaded = totalEvents++; + public static final int encryptedChatUpdated = totalEvents++; + public static final int messagesReadEncrypted = totalEvents++; + public static final int encryptedChatCreated = totalEvents++; + public static final int userPhotosLoaded = totalEvents++; + public static final int removeAllMessagesFromDialog = totalEvents++; + public static final int notificationsSettingsUpdated = totalEvents++; + public static final int pushMessagesUpdated = totalEvents++; + public static final int blockedUsersDidLoaded = totalEvents++; + public static final int openedChatChanged = totalEvents++; + public static final int stopEncodingService = totalEvents++; + public static final int didCreatedNewDeleteTask = totalEvents++; + public static final int mainUserInfoChanged = totalEvents++; + public static final int privacyRulesUpdated = totalEvents++; + public static final int updateMessageMedia = totalEvents++; + public static final int recentImagesDidLoaded = totalEvents++; + public static final int replaceMessagesObjects = totalEvents++; + public static final int didSetPasscode = totalEvents++; + public static final int didSetTwoStepPassword = totalEvents++; + public static final int screenStateChanged = totalEvents++; + public static final int didLoadedReplyMessages = totalEvents++; + public static final int didLoadedPinnedMessage = totalEvents++; + public static final int newSessionReceived = totalEvents++; + public static final int didReceivedWebpages = totalEvents++; + public static final int didReceivedWebpagesInUpdates = totalEvents++; + public static final int stickersDidLoaded = totalEvents++; + public static final int didReplacedPhotoInMemCache = totalEvents++; + public static final int messagesReadContent = totalEvents++; + public static final int botInfoDidLoaded = totalEvents++; + public static final int userInfoDidLoaded = totalEvents++; + public static final int botKeyboardDidLoaded = totalEvents++; + public static final int chatSearchResultsAvailable = totalEvents++; + public static final int musicDidLoaded = totalEvents++; + public static final int needShowAlert = totalEvents++; + public static final int didUpdatedMessagesViews = totalEvents++; + public static final int needReloadRecentDialogsSearch = totalEvents++; + public static final int locationPermissionGranted = totalEvents++; + public static final int peerSettingsDidLoaded = totalEvents++; + public static final int wasUnableToFindCurrentLocation = totalEvents++; + + public static final int httpFileDidLoaded = totalEvents++; + public static final int httpFileDidFailedLoad = totalEvents++; + + public static final int messageThumbGenerated = totalEvents++; + + public static final int wallpapersDidLoaded = totalEvents++; + public static final int closeOtherAppActivities = totalEvents++; + public static final int didUpdatedConnectionState = totalEvents++; + public static final int didReceiveSmsCode = totalEvents++; + public static final int didReceiveCall = totalEvents++; + public static final int emojiDidLoaded = totalEvents++; + public static final int appDidLogout = totalEvents++; + + public static final int FileDidUpload = totalEvents++; + public static final int FileDidFailUpload = totalEvents++; + public static final int FileUploadProgressChanged = totalEvents++; + public static final int FileLoadProgressChanged = totalEvents++; + public static final int FileDidLoaded = totalEvents++; + public static final int FileDidFailedLoad = totalEvents++; + public static final int FilePreparingStarted = totalEvents++; + public static final int FileNewChunkAvailable = totalEvents++; + public static final int FilePreparingFailed = totalEvents++; + + public static final int audioProgressDidChanged = totalEvents++; + public static final int audioDidReset = totalEvents++; + public static final int audioPlayStateChanged = totalEvents++; + public static final int recordProgressChanged = totalEvents++; + public static final int recordStarted = totalEvents++; + public static final int recordStartError = totalEvents++; + public static final int recordStopped = totalEvents++; + public static final int screenshotTook = totalEvents++; + public static final int albumsDidLoaded = totalEvents++; + public static final int audioDidSent = totalEvents++; + public static final int audioDidStarted = totalEvents++; + public static final int audioRouteChanged = totalEvents++; + + public static final int wallpaperChanged = totalEvents++; + public static final int refreshTabs = totalEvents++; + + private SparseArray> observers = new SparseArray<>(); + private SparseArray> removeAfterBroadcast = new SparseArray<>(); + private SparseArray> addAfterBroadcast = new SparseArray<>(); + private ArrayList delayedPosts = new ArrayList<>(10); + + private int broadcasting = 0; + private boolean animationInProgress; + + private int[] allowedNotifications; + + public interface NotificationCenterDelegate { + void didReceivedNotification(int id, Object... args); + } + + private class DelayedPost { + + private DelayedPost(int id, Object[] args) { + this.id = id; + this.args = args; + } + + private int id; + private Object[] args; + } + + private static volatile NotificationCenter Instance = null; + + public static NotificationCenter getInstance() { + NotificationCenter localInstance = Instance; + if (localInstance == null) { + synchronized (NotificationCenter.class) { + localInstance = Instance; + if (localInstance == null) { + Instance = localInstance = new NotificationCenter(); + } + } + } + return localInstance; + } + + public void setAllowedNotificationsDutingAnimation(int notifications[]) { + allowedNotifications = notifications; + } + + public void setAnimationInProgress(boolean value) { + animationInProgress = value; + if (!animationInProgress && !delayedPosts.isEmpty()) { + for (DelayedPost delayedPost : delayedPosts) { + postNotificationNameInternal(delayedPost.id, true, delayedPost.args); + } + delayedPosts.clear(); + } + } + + public void postNotificationName(int id, Object... args) { + boolean allowDuringAnimation = false; + if (allowedNotifications != null) { + for (int a = 0; a < allowedNotifications.length; a++) { + if (allowedNotifications[a] == id) { + allowDuringAnimation = true; + break; + } + } + } + postNotificationNameInternal(id, allowDuringAnimation, args); + } + + public void postNotificationNameInternal(int id, boolean allowDuringAnimation, Object... args) { + if (BuildVars.DEBUG_VERSION) { + if (Thread.currentThread() != ApplicationLoader.applicationHandler.getLooper().getThread()) { + throw new RuntimeException("postNotificationName allowed only from MAIN thread"); + } + } + if (!allowDuringAnimation && animationInProgress) { + DelayedPost delayedPost = new DelayedPost(id, args); + delayedPosts.add(delayedPost); + if (BuildVars.DEBUG_VERSION) { + FileLog.e("tmessages", "delay post notification " + id + " with args count = " + args.length); + } + return; + } + broadcasting++; + ArrayList objects = observers.get(id); + if (objects != null && !objects.isEmpty()) { + for (int a = 0; a < objects.size(); a++) { + Object obj = objects.get(a); + ((NotificationCenterDelegate) obj).didReceivedNotification(id, args); + } + } + broadcasting--; + if (broadcasting == 0) { + if (removeAfterBroadcast.size() != 0) { + for (int a = 0; a < removeAfterBroadcast.size(); a++) { + int key = removeAfterBroadcast.keyAt(a); + ArrayList arrayList = removeAfterBroadcast.get(key); + for (int b = 0; b < arrayList.size(); b++) { + removeObserver(arrayList.get(b), key); + } + } + removeAfterBroadcast.clear(); + } + if (addAfterBroadcast.size() != 0) { + for (int a = 0; a < addAfterBroadcast.size(); a++) { + int key = addAfterBroadcast.keyAt(a); + ArrayList arrayList = addAfterBroadcast.get(key); + for (int b = 0; b < arrayList.size(); b++) { + addObserver(arrayList.get(b), key); + } + } + addAfterBroadcast.clear(); + } + } + } + + public void addObserver(Object observer, int id) { + if (BuildVars.DEBUG_VERSION) { + if (Thread.currentThread() != ApplicationLoader.applicationHandler.getLooper().getThread()) { + throw new RuntimeException("addObserver allowed only from MAIN thread"); + } + } + if (broadcasting != 0) { + ArrayList arrayList = addAfterBroadcast.get(id); + if (arrayList == null) { + arrayList = new ArrayList<>(); + addAfterBroadcast.put(id, arrayList); + } + arrayList.add(observer); + return; + } + ArrayList objects = observers.get(id); + if (objects == null) { + observers.put(id, (objects = new ArrayList<>())); + } + if (objects.contains(observer)) { + return; + } + objects.add(observer); + } + + public void removeObserver(Object observer, int id) { + if (BuildVars.DEBUG_VERSION) { + if (Thread.currentThread() != ApplicationLoader.applicationHandler.getLooper().getThread()) { + throw new RuntimeException("removeObserver allowed only from MAIN thread"); + } + } + if (broadcasting != 0) { + ArrayList arrayList = removeAfterBroadcast.get(id); + if (arrayList == null) { + arrayList = new ArrayList<>(); + removeAfterBroadcast.put(id, arrayList); + } + arrayList.add(observer); + return; + } + ArrayList objects = observers.get(id); + if (objects != null) { + objects.remove(observer); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationRepeat.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationRepeat.java new file mode 100644 index 00000000..c1e87f8b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationRepeat.java @@ -0,0 +1,29 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.app.IntentService; +import android.content.Intent; + +public class NotificationRepeat extends IntentService { + + public NotificationRepeat() { + super("NotificationRepeat"); + } + + @Override + protected void onHandleIntent(Intent intent) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationsController.getInstance().repeatNotificationMaybe(); + } + }); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java new file mode 100644 index 00000000..50b17de1 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsController.java @@ -0,0 +1,1835 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.Point; +import android.graphics.drawable.BitmapDrawable; +import android.media.AudioManager; +import android.media.SoundPool; +import android.net.Uri; +import android.os.Build; +import android.os.PowerManager; +import android.os.SystemClock; +import android.provider.Settings; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.NotificationManagerCompat; +import android.support.v4.app.RemoteInput; +import android.util.SparseArray; + +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.LaunchActivity; +import org.telegram.ui.PopupNotificationActivity; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; + +public class NotificationsController { + + public static final String EXTRA_VOICE_REPLY = "extra_voice_reply"; + + private DispatchQueue notificationsQueue = new DispatchQueue("notificationsQueue"); + private ArrayList pushMessages = new ArrayList<>(); + private ArrayList delayedPushMessages = new ArrayList<>(); + private HashMap pushMessagesDict = new HashMap<>(); + private HashMap smartNotificationsDialogs = new HashMap<>(); + private NotificationManagerCompat notificationManager = null; + private HashMap pushDialogs = new HashMap<>(); + private HashMap wearNotificationsIds = new HashMap<>(); + private HashMap autoNotificationsIds = new HashMap<>(); + private HashMap pushDialogsOverrideMention = new HashMap<>(); + private int wearNotificationId = 10000; + private int autoNotificationId = 20000; + public ArrayList popupMessages = new ArrayList<>(); + private long opened_dialog_id = 0; + private int total_unread_count = 0; + private int personal_count = 0; + private boolean notifyCheck = false; + private int lastOnlineFromOtherDevice = 0; + private boolean inChatSoundEnabled = true; + private int lastBadgeCount; + private String launcherClassName; + + private Runnable notificationDelayRunnable; + private PowerManager.WakeLock notificationDelayWakelock; + + private long lastSoundPlay; + private long lastSoundOutPlay; + private SoundPool soundPool; + private int soundIn; + private int soundOut; + private int soundRecord; + private boolean soundInLoaded; + private boolean soundOutLoaded; + private boolean soundRecordLoaded; + protected AudioManager audioManager; + private AlarmManager alarmManager; + + private boolean invertMsgsOrder; + + private static volatile NotificationsController Instance = null; + public static NotificationsController getInstance() { + NotificationsController localInstance = Instance; + if (localInstance == null) { + synchronized (MessagesController.class) { + localInstance = Instance; + if (localInstance == null) { + Instance = localInstance = new NotificationsController(); + } + } + } + return localInstance; + } + + public NotificationsController() { + notificationManager = NotificationManagerCompat.from(ApplicationLoader.applicationContext); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); + inChatSoundEnabled = preferences.getBoolean("EnableInChatSound", true); + SharedPreferences plusPrefs = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + invertMsgsOrder = plusPrefs.getBoolean("invertMessagesOrder", false); + try { + audioManager = (AudioManager) ApplicationLoader.applicationContext.getSystemService(Context.AUDIO_SERVICE); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + alarmManager = (AlarmManager) ApplicationLoader.applicationContext.getSystemService(Context.ALARM_SERVICE); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + try { + PowerManager pm = (PowerManager) ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE); + notificationDelayWakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "lock"); + notificationDelayWakelock.setReferenceCounted(false); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + notificationDelayRunnable = new Runnable() { + @Override + public void run() { + FileLog.e("tmessages", "delay reached"); + if (!delayedPushMessages.isEmpty()) { + showOrUpdateNotification(true); + delayedPushMessages.clear(); + } + try { + if (notificationDelayWakelock.isHeld()) { + notificationDelayWakelock.release(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }; + } + + public void cleanup() { + popupMessages.clear(); + notificationsQueue.postRunnable(new Runnable() { + @Override + public void run() { + opened_dialog_id = 0; + total_unread_count = 0; + personal_count = 0; + pushMessages.clear(); + pushMessagesDict.clear(); + pushDialogs.clear(); + wearNotificationsIds.clear(); + autoNotificationsIds.clear(); + delayedPushMessages.clear(); + notifyCheck = false; + lastBadgeCount = 0; + try { + if (notificationDelayWakelock.isHeld()) { + notificationDelayWakelock.release(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + setBadge(0); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.clear(); + editor.commit(); + } + }); + } + + public void setInChatSoundEnabled(boolean value) { + inChatSoundEnabled = value; + } + + public void setOpenedDialogId(final long dialog_id) { + notificationsQueue.postRunnable(new Runnable() { + @Override + public void run() { + opened_dialog_id = dialog_id; + } + }); + } + + public void setLastOnlineFromOtherDevice(final int time) { + notificationsQueue.postRunnable(new Runnable() { + @Override + public void run() { + FileLog.e("tmessages", "set last online from other device = " + time); + lastOnlineFromOtherDevice = time; + } + }); + } + + public void removeNotificationsForDialog(long did) { + NotificationsController.getInstance().processReadMessages(null, did, 0, Integer.MAX_VALUE, false); + HashMap dialogsToUpdate = new HashMap<>(); + dialogsToUpdate.put(did, 0); + NotificationsController.getInstance().processDialogsUpdateRead(dialogsToUpdate); + } + + public void removeDeletedMessagesFromNotifications(final SparseArray> deletedMessages) { + final ArrayList popupArray = popupMessages.isEmpty() ? null : new ArrayList<>(popupMessages); + notificationsQueue.postRunnable(new Runnable() { + @Override + public void run() { + int old_unread_count = total_unread_count; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); + for (int a = 0; a < deletedMessages.size(); a++) { + int key = deletedMessages.keyAt(a); + long dialog_id = -key; + ArrayList mids = deletedMessages.get(key); + Integer currentCount = pushDialogs.get(dialog_id); + if (currentCount == null) { + currentCount = 0; + } + Integer newCount = currentCount; + for (int b = 0; b < mids.size(); b++) { + long mid = mids.get(b); + mid |= ((long) key) << 32; + MessageObject messageObject = pushMessagesDict.get(mid); + if (messageObject != null) { + pushMessagesDict.remove(mid); + delayedPushMessages.remove(messageObject); + pushMessages.remove(messageObject); + if (isPersonalMessage(messageObject)) { + personal_count--; + } + if (popupArray != null) { + popupArray.remove(messageObject); + } + newCount--; + } + } + if (newCount <= 0) { + newCount = 0; + smartNotificationsDialogs.remove(dialog_id); + } + if (!newCount.equals(currentCount)) { + total_unread_count -= currentCount; + total_unread_count += newCount; + pushDialogs.put(dialog_id, newCount); + } + if (newCount == 0) { + pushDialogs.remove(dialog_id); + pushDialogsOverrideMention.remove(dialog_id); + if (popupArray != null && pushMessages.isEmpty() && !popupArray.isEmpty()) { + popupArray.clear(); + } + } + } + if (popupArray != null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + popupMessages = popupArray; + } + }); + } + if (old_unread_count != total_unread_count) { + if (!notifyCheck) { + delayedPushMessages.clear(); + showOrUpdateNotification(notifyCheck); + } else { + scheduleNotificationDelay(lastOnlineFromOtherDevice > ConnectionsManager.getInstance().getCurrentTime()); + } + } + notifyCheck = false; + if (preferences.getBoolean("badgeNumber", true)) { + setBadge(total_unread_count); + } + } + }); + } + + public void processReadMessages(final SparseArray inbox, final long dialog_id, final int max_date, final int max_id, final boolean isPopup) { + final ArrayList popupArray = popupMessages.isEmpty() ? null : new ArrayList<>(popupMessages); + notificationsQueue.postRunnable(new Runnable() { + @Override + public void run() { + int oldCount = popupArray != null ? popupArray.size() : 0; + if (inbox != null) { + for (int b = 0; b < inbox.size(); b++) { + int key = inbox.keyAt(b); + long messageId = inbox.get(key); + for (int a = 0; a < pushMessages.size(); a++) { + MessageObject messageObject = pushMessages.get(a); + if (messageObject.getDialogId() == key && messageObject.getId() <= (int) messageId) { + if (isPersonalMessage(messageObject)) { + personal_count--; + } + if (popupArray != null) { + popupArray.remove(messageObject); + } + long mid = messageObject.messageOwner.id; + if (messageObject.messageOwner.to_id.channel_id != 0) { + mid |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; + } + pushMessagesDict.remove(mid); + delayedPushMessages.remove(messageObject); + pushMessages.remove(a); + a--; + } + } + } + if (popupArray != null && pushMessages.isEmpty() && !popupArray.isEmpty()) { + popupArray.clear(); + } + } + if (dialog_id != 0 && (max_id != 0 || max_date != 0)) { + for (int a = 0; a < pushMessages.size(); a++) { + MessageObject messageObject = pushMessages.get(a); + if (messageObject.getDialogId() == dialog_id) { + boolean remove = false; + if (max_date != 0) { + if (messageObject.messageOwner.date <= max_date) { + remove = true; + } + } else { + if (!isPopup) { + if (messageObject.getId() <= max_id || max_id < 0) { + remove = true; + } + } else { + if (messageObject.getId() == max_id || max_id < 0) { + remove = true; + } + } + } + if (remove) { + if (isPersonalMessage(messageObject)) { + personal_count--; + } + pushMessages.remove(a); + delayedPushMessages.remove(messageObject); + if (popupArray != null) { + popupArray.remove(messageObject); + } + long mid = messageObject.messageOwner.id; + if (messageObject.messageOwner.to_id.channel_id != 0) { + mid |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; + } + pushMessagesDict.remove(mid); + a--; + } + } + } + if (popupArray != null && pushMessages.isEmpty() && !popupArray.isEmpty()) { + popupArray.clear(); + } + } + if (popupArray != null && oldCount != popupArray.size()) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + popupMessages = popupArray; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.pushMessagesUpdated); + } + }); + } + } + }); + } + + public void processNewMessages(final ArrayList messageObjects, final boolean isLast) { + if (messageObjects.isEmpty()) { + return; + } + final ArrayList popupArray = new ArrayList<>(popupMessages); + notificationsQueue.postRunnable(new Runnable() { + @Override + public void run() { + boolean added = false; + + int oldCount = popupArray.size(); + HashMap settingsCache = new HashMap<>(); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); + int popup = 0; + + for (int a = 0; a < messageObjects.size(); a++) { + MessageObject messageObject = messageObjects.get(a); + long mid = messageObject.messageOwner.id; + if (messageObject.messageOwner.to_id.channel_id != 0) { + mid |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; + } + if (pushMessagesDict.containsKey(mid)) { + continue; + } + long dialog_id = messageObject.getDialogId(); + long original_dialog_id = dialog_id; + if (dialog_id == opened_dialog_id && ApplicationLoader.isScreenOn) { + playInChatSound(); + continue; + } + if (messageObject.messageOwner.mentioned) { + dialog_id = messageObject.messageOwner.from_id; + } + if (isPersonalMessage(messageObject)) { + personal_count++; + } + added = true; + + Boolean value = settingsCache.get(dialog_id); + boolean isChat = (int) dialog_id < 0; + popup = (int)dialog_id == 0 ? 0 : preferences.getInt(isChat ? "popupGroup" : "popupAll", 0); + if (value == null) { + int notifyOverride = getNotifyOverride(preferences, dialog_id); + value = !(notifyOverride == 2 || (!preferences.getBoolean("EnableAll", true) || isChat && !preferences.getBoolean("EnableGroup", true)) && notifyOverride == 0); + settingsCache.put(dialog_id, value); + } + if (value) { + if (popup != 0) { + //popupArray.add(0, messageObject); + if (invertMsgsOrder) { + popupArray.add(messageObject); + } else { + popupArray.add(0, messageObject); + } + } + delayedPushMessages.add(messageObject); + //pushMessages.add(0, messageObject); + if (invertMsgsOrder) { + pushMessages.add(messageObject); + } else { + pushMessages.add(0, messageObject); + } + pushMessagesDict.put(mid, messageObject); + if (original_dialog_id != dialog_id) { + pushDialogsOverrideMention.put(original_dialog_id, 1); + } + } + } + + if (added) { + notifyCheck = isLast; + } + + if (!popupArray.isEmpty() && oldCount != popupArray.size() && !AndroidUtilities.needShowPasscode(false)) { + final int popupFinal = popup; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + popupMessages = popupArray; + if (ApplicationLoader.mainInterfacePaused || !ApplicationLoader.isScreenOn && !UserConfig.isWaitingForPasscodeEnter) { + MessageObject messageObject = messageObjects.get(0); + if (popupFinal == 3 || popupFinal == 1 && ApplicationLoader.isScreenOn || popupFinal == 2 && !ApplicationLoader.isScreenOn) { + Intent popupIntent = new Intent(ApplicationLoader.applicationContext, PopupNotificationActivity.class); + popupIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_USER_ACTION | Intent.FLAG_FROM_BACKGROUND); + ApplicationLoader.applicationContext.startActivity(popupIntent); + } + } + } + }); + } + } + }); + } + + public void processDialogsUpdateRead(final HashMap dialogsToUpdate) { + final ArrayList popupArray = popupMessages.isEmpty() ? null : new ArrayList<>(popupMessages); + notificationsQueue.postRunnable(new Runnable() { + @Override + public void run() { + int old_unread_count = total_unread_count; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); + for (HashMap.Entry entry : dialogsToUpdate.entrySet()) { + long dialog_id = entry.getKey(); + + int notifyOverride = getNotifyOverride(preferences, dialog_id); + if (notifyCheck) { + Integer override = pushDialogsOverrideMention.get(dialog_id); + if (override != null && override == 1) { + pushDialogsOverrideMention.put(dialog_id, 0); + notifyOverride = 1; + } + } + boolean canAddValue = !(notifyOverride == 2 || (!preferences.getBoolean("EnableAll", true) || ((int)dialog_id < 0) && !preferences.getBoolean("EnableGroup", true)) && notifyOverride == 0); + + Integer currentCount = pushDialogs.get(dialog_id); + Integer newCount = entry.getValue(); + if (newCount == 0) { + smartNotificationsDialogs.remove(dialog_id); + } + + if (newCount < 0) { + if (currentCount == null) { + continue; + } + newCount = currentCount + newCount; + } + if (canAddValue || newCount == 0) { + if (currentCount != null) { + total_unread_count -= currentCount; + } + } + if (newCount == 0) { + pushDialogs.remove(dialog_id); + pushDialogsOverrideMention.remove(dialog_id); + for (int a = 0; a < pushMessages.size(); a++) { + MessageObject messageObject = pushMessages.get(a); + if (messageObject.getDialogId() == dialog_id) { + if (isPersonalMessage(messageObject)) { + personal_count--; + } + pushMessages.remove(a); + a--; + delayedPushMessages.remove(messageObject); + long mid = messageObject.messageOwner.id; + if (messageObject.messageOwner.to_id.channel_id != 0) { + mid |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; + } + pushMessagesDict.remove(mid); + if (popupArray != null) { + popupArray.remove(messageObject); + } + } + } + if (popupArray != null && pushMessages.isEmpty() && !popupArray.isEmpty()) { + popupArray.clear(); + } + } else if (canAddValue) { + total_unread_count += newCount; + pushDialogs.put(dialog_id, newCount); + } + } + if (popupArray != null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + popupMessages = popupArray; + } + }); + } + if (old_unread_count != total_unread_count) { + if (!notifyCheck) { + delayedPushMessages.clear(); + showOrUpdateNotification(notifyCheck); + } else { + scheduleNotificationDelay(lastOnlineFromOtherDevice > ConnectionsManager.getInstance().getCurrentTime()); + } + } + notifyCheck = false; + if (preferences.getBoolean("badgeNumber", true)) { + setBadge(total_unread_count); + } + } + }); + } + + public void processLoadedUnreadMessages(final HashMap dialogs, final ArrayList messages, final ArrayList users, final ArrayList chats, final ArrayList encryptedChats) { + MessagesController.getInstance().putUsers(users, true); + MessagesController.getInstance().putChats(chats, true); + MessagesController.getInstance().putEncryptedChats(encryptedChats, true); + + notificationsQueue.postRunnable(new Runnable() { + @Override + public void run() { + pushDialogs.clear(); + pushMessages.clear(); + pushMessagesDict.clear(); + total_unread_count = 0; + personal_count = 0; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); + HashMap settingsCache = new HashMap<>(); + + if (messages != null) { + for (TLRPC.Message message : messages) { + long mid = message.id; + if (message.to_id.channel_id != 0) { + mid |= ((long) message.to_id.channel_id) << 32; + } + if (pushMessagesDict.containsKey(mid)) { + continue; + } + MessageObject messageObject = new MessageObject(message, null, false); + if (isPersonalMessage(messageObject)) { + personal_count++; + } + long dialog_id = messageObject.getDialogId(); + long original_dialog_id = dialog_id; + if (messageObject.messageOwner.mentioned) { + dialog_id = messageObject.messageOwner.from_id; + } + Boolean value = settingsCache.get(dialog_id); + if (value == null) { + int notifyOverride = getNotifyOverride(preferences, dialog_id); + value = !(notifyOverride == 2 || (!preferences.getBoolean("EnableAll", true) || ((int) dialog_id < 0) && !preferences.getBoolean("EnableGroup", true)) && notifyOverride == 0); + settingsCache.put(dialog_id, value); + } + if (!value || dialog_id == opened_dialog_id && ApplicationLoader.isScreenOn) { + continue; + } + pushMessagesDict.put(mid, messageObject); + //pushMessages.add(0, messageObject); + if (invertMsgsOrder) { + pushMessages.add(messageObject); + } else { + pushMessages.add(0, messageObject); + } + if (original_dialog_id != dialog_id) { + pushDialogsOverrideMention.put(original_dialog_id, 1); + } + } + } + for (HashMap.Entry entry : dialogs.entrySet()) { + long dialog_id = entry.getKey(); + Boolean value = settingsCache.get(dialog_id); + if (value == null) { + int notifyOverride = getNotifyOverride(preferences, dialog_id); + Integer override = pushDialogsOverrideMention.get(dialog_id); + if (override != null && override == 1) { + pushDialogsOverrideMention.put(dialog_id, 0); + notifyOverride = 1; + } + value = !(notifyOverride == 2 || (!preferences.getBoolean("EnableAll", true) || ((int) dialog_id < 0) && !preferences.getBoolean("EnableGroup", true)) && notifyOverride == 0); + settingsCache.put(dialog_id, value); + } + if (!value) { + continue; + } + int count = entry.getValue(); + pushDialogs.put(dialog_id, count); + total_unread_count += count; + } + if (total_unread_count == 0) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + popupMessages.clear(); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.pushMessagesUpdated); + } + }); + } + showOrUpdateNotification(SystemClock.uptimeMillis() / 1000 < 60); + + if (preferences.getBoolean("badgeNumber", true)) { + setBadge(total_unread_count); + } + } + }); + } + + public void setBadgeEnabled(boolean enabled) { + setBadge(enabled ? total_unread_count : 0); + } + + private void setBadge(final int count) { + notificationsQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (lastBadgeCount == count) { + return; + } + lastBadgeCount = count; + try { + ContentValues cv = new ContentValues(); + //cv.put("tag", "org.telegram.messenger/org.telegram.ui.LaunchActivity"); + cv.put("tag", ApplicationLoader.applicationContext.getPackageName() + "/org.telegram.ui.LaunchActivity"); //Plus + cv.put("count", count); + ApplicationLoader.applicationContext.getContentResolver().insert(Uri.parse("content://com.teslacoilsw.notifier/unread_count"), cv); + } catch (Throwable e) { + //ignore + } + try { + if (launcherClassName == null) { + launcherClassName = getLauncherClassName(ApplicationLoader.applicationContext); + } + if (launcherClassName == null) { + return; + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE"); + intent.putExtra("badge_count", count); + intent.putExtra("badge_count_package_name", ApplicationLoader.applicationContext.getPackageName()); + intent.putExtra("badge_count_class_name", launcherClassName); + //intent.setFlags(32768); + ApplicationLoader.applicationContext.sendBroadcast(intent); + //Log.e("Plus", "NotificationsController count " + count); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + }); + } + + private String getStringForMessage(MessageObject messageObject, boolean shortMessage) { + long dialog_id = messageObject.messageOwner.dialog_id; + int chat_id = messageObject.messageOwner.to_id.chat_id != 0 ? messageObject.messageOwner.to_id.chat_id : messageObject.messageOwner.to_id.channel_id; + int from_id = messageObject.messageOwner.to_id.user_id; + if (from_id == 0) { + if (messageObject.isFromUser()) { + from_id = messageObject.messageOwner.from_id; + } else { + from_id = -chat_id; + } + } else if (from_id == UserConfig.getClientUserId()) { + from_id = messageObject.messageOwner.from_id; + } + + if (dialog_id == 0) { + if (chat_id != 0) { + dialog_id = -chat_id; + } else if (from_id != 0) { + dialog_id = from_id; + } + } + + String name = null; + if (from_id > 0) { + TLRPC.User user = MessagesController.getInstance().getUser(from_id); + if (user != null) { + name = UserObject.getUserName(user); + } + } else { + TLRPC.Chat chat = MessagesController.getInstance().getChat(-from_id); + if (chat != null) { + name = chat.title; + } + } + + if (name == null) { + return null; + } + TLRPC.Chat chat = null; + if (chat_id != 0) { + chat = MessagesController.getInstance().getChat(chat_id); + if (chat == null) { + return null; + } + } + + String msg = null; + if ((int)dialog_id == 0 || AndroidUtilities.needShowPasscode(false) || UserConfig.isWaitingForPasscodeEnter) { + msg = LocaleController.getString("YouHaveNewMessage", R.string.YouHaveNewMessage); + } else { + if (chat_id == 0 && from_id != 0) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); + if (preferences.getBoolean("EnablePreviewAll", true)) { + if (messageObject.messageOwner instanceof TLRPC.TL_messageService) { + if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserJoined) { + msg = LocaleController.formatString("NotificationContactJoined", R.string.NotificationContactJoined, name); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { + msg = LocaleController.formatString("NotificationContactNewPhoto", R.string.NotificationContactNewPhoto, name); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionLoginUnknownLocation) { + String date = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.getInstance().formatterYear.format(((long) messageObject.messageOwner.date) * 1000), LocaleController.getInstance().formatterDay.format(((long) messageObject.messageOwner.date) * 1000)); + msg = LocaleController.formatString("NotificationUnrecognizedDevice", R.string.NotificationUnrecognizedDevice, UserConfig.getCurrentUser().first_name, date, messageObject.messageOwner.action.title, messageObject.messageOwner.action.address); + } + } else { + if (messageObject.isMediaEmpty()) { + if (!shortMessage) { + if (messageObject.messageOwner.message != null && messageObject.messageOwner.message.length() != 0) { + msg = LocaleController.formatString("NotificationMessageText", R.string.NotificationMessageText, name, messageObject.messageOwner.message); + } else { + msg = LocaleController.formatString("NotificationMessageNoText", R.string.NotificationMessageNoText, name); + } + } else { + msg = LocaleController.formatString("NotificationMessageNoText", R.string.NotificationMessageNoText, name); + } + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { + msg = LocaleController.formatString("NotificationMessagePhoto", R.string.NotificationMessagePhoto, name); + } else if (messageObject.isVideo()) { + msg = LocaleController.formatString("NotificationMessageVideo", R.string.NotificationMessageVideo, name); + } else if (messageObject.isVoice()) { + msg = LocaleController.formatString("NotificationMessageAudio", R.string.NotificationMessageAudio, name); + } else if (messageObject.isMusic()) { + msg = LocaleController.formatString("NotificationMessageMusic", R.string.NotificationMessageMusic, name); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { + msg = LocaleController.formatString("NotificationMessageContact", R.string.NotificationMessageContact, name); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) { + msg = LocaleController.formatString("NotificationMessageMap", R.string.NotificationMessageMap, name); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + if (messageObject.isSticker()) { + msg = LocaleController.formatString("NotificationMessageSticker", R.string.NotificationMessageSticker, name); + } else if (messageObject.isGif()) { + msg = LocaleController.formatString("NotificationMessageGif", R.string.NotificationMessageGif, name); + } else { + msg = LocaleController.formatString("NotificationMessageDocument", R.string.NotificationMessageDocument, name); + } + } + } + } else { + msg = LocaleController.formatString("NotificationMessageNoText", R.string.NotificationMessageNoText, name); + } + } else if (chat_id != 0) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); + if (preferences.getBoolean("EnablePreviewGroup", true)) { + if (messageObject.messageOwner instanceof TLRPC.TL_messageService) { + if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatAddUser) { + int singleUserId = messageObject.messageOwner.action.user_id; + if (singleUserId == 0 && messageObject.messageOwner.action.users.size() == 1) { + singleUserId = messageObject.messageOwner.action.users.get(0); + } + if (singleUserId != 0) { + if (messageObject.messageOwner.to_id.channel_id != 0 && !messageObject.isMegagroup()) { + TLRPC.User user = MessagesController.getInstance().getUser(singleUserId); + if (user != null) { + name = UserObject.getUserName(user); + } else { + name = ""; + } + msg = LocaleController.formatString("ChannelAddedByNotification", R.string.ChannelAddedByNotification, name, chat.title); + } else { + if (singleUserId == UserConfig.getClientUserId()) { + msg = LocaleController.formatString("NotificationInvitedToGroup", R.string.NotificationInvitedToGroup, name, chat.title); + } else { + TLRPC.User u2 = MessagesController.getInstance().getUser(singleUserId); + if (u2 == null) { + return null; + } + if (from_id == u2.id) { + if (messageObject.isMegagroup()) { + msg = LocaleController.formatString("NotificationGroupAddSelfMega", R.string.NotificationGroupAddSelfMega, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationGroupAddSelf", R.string.NotificationGroupAddSelf, name, chat.title); + } + } else { + msg = LocaleController.formatString("NotificationGroupAddMember", R.string.NotificationGroupAddMember, name, chat.title, UserObject.getUserName(u2)); + } + } + } + } else { + StringBuilder names = new StringBuilder(""); + for (int a = 0; a < messageObject.messageOwner.action.users.size(); a++) { + TLRPC.User user = MessagesController.getInstance().getUser(messageObject.messageOwner.action.users.get(a)); + if (user != null) { + String name2 = UserObject.getUserName(user); + if (names.length() != 0) { + names.append(", "); + } + names.append(name2); + } + } + msg = LocaleController.formatString("NotificationGroupAddMember", R.string.NotificationGroupAddMember, name, chat.title, names.toString()); + } + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatJoinedByLink) { + msg = LocaleController.formatString("NotificationInvitedToGroupByLink", R.string.NotificationInvitedToGroupByLink, name, chat.title); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatEditTitle) { + msg = LocaleController.formatString("NotificationEditedGroupName", R.string.NotificationEditedGroupName, name, messageObject.messageOwner.action.title); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatEditPhoto || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatDeletePhoto) { + if (messageObject.messageOwner.to_id.channel_id != 0 && !messageObject.isMegagroup()) { + msg = LocaleController.formatString("ChannelPhotoEditNotification", R.string.ChannelPhotoEditNotification, chat.title); + } else { + msg = LocaleController.formatString("NotificationEditedGroupPhoto", R.string.NotificationEditedGroupPhoto, name, chat.title); + } + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatDeleteUser) { + if (messageObject.messageOwner.action.user_id == UserConfig.getClientUserId()) { + msg = LocaleController.formatString("NotificationGroupKickYou", R.string.NotificationGroupKickYou, name, chat.title); + } else if (messageObject.messageOwner.action.user_id == from_id) { + msg = LocaleController.formatString("NotificationGroupLeftMember", R.string.NotificationGroupLeftMember, name, chat.title); + } else { + TLRPC.User u2 = MessagesController.getInstance().getUser(messageObject.messageOwner.action.user_id); + if (u2 == null) { + return null; + } + msg = LocaleController.formatString("NotificationGroupKickMember", R.string.NotificationGroupKickMember, name, chat.title, UserObject.getUserName(u2)); + } + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatCreate) { + msg = messageObject.messageText.toString(); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChannelCreate) { + msg = messageObject.messageText.toString(); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatMigrateTo) { + msg = LocaleController.formatString("ActionMigrateFromGroupNotify", R.string.ActionMigrateFromGroupNotify, chat.title); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChannelMigrateFrom) { + msg = LocaleController.formatString("ActionMigrateFromGroupNotify", R.string.ActionMigrateFromGroupNotify, messageObject.messageOwner.action.title); + } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) { + if (messageObject.replyMessageObject == null) { + if (!ChatObject.isChannel(chat) || chat.megagroup) { + msg = LocaleController.formatString("NotificationActionPinnedNoText", R.string.NotificationActionPinnedNoText, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationActionPinnedNoTextChannel", R.string.NotificationActionPinnedNoTextChannel, name, chat.title); + } + } else { + MessageObject object = messageObject.replyMessageObject; + if (object.isMusic()) { + if (!ChatObject.isChannel(chat) || chat.megagroup) { + msg = LocaleController.formatString("NotificationActionPinnedMusic", R.string.NotificationActionPinnedMusic, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationActionPinnedMusicChannel", R.string.NotificationActionPinnedMusicChannel, chat.title); + } + } else if (object.isVideo()) { + if (!ChatObject.isChannel(chat) || chat.megagroup) { + msg = LocaleController.formatString("NotificationActionPinnedVideo", R.string.NotificationActionPinnedVideo, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationActionPinnedVideoChannel", R.string.NotificationActionPinnedVideoChannel, chat.title); + } + } else if (object.isGif()) { + if (!ChatObject.isChannel(chat) || chat.megagroup) { + msg = LocaleController.formatString("NotificationActionPinnedGif", R.string.NotificationActionPinnedGif, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationActionPinnedGifChannel", R.string.NotificationActionPinnedGifChannel, chat.title); + } + } else if (object.isVoice()) { + if (!ChatObject.isChannel(chat) || chat.megagroup) { + msg = LocaleController.formatString("NotificationActionPinnedVoice", R.string.NotificationActionPinnedVoice, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationActionPinnedVoiceChannel", R.string.NotificationActionPinnedVoiceChannel, chat.title); + } + } else if (object.isSticker()) { + if (!ChatObject.isChannel(chat) || chat.megagroup) { + msg = LocaleController.formatString("NotificationActionPinnedSticker", R.string.NotificationActionPinnedSticker, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationActionPinnedStickerChannel", R.string.NotificationActionPinnedStickerChannel, chat.title); + } + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + if (!ChatObject.isChannel(chat) || chat.megagroup) { + msg = LocaleController.formatString("NotificationActionPinnedFile", R.string.NotificationActionPinnedFile, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationActionPinnedFileChannel", R.string.NotificationActionPinnedFileChannel, chat.title); + } + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaGeo) { + if (!ChatObject.isChannel(chat) || chat.megagroup) { + msg = LocaleController.formatString("NotificationActionPinnedGeo", R.string.NotificationActionPinnedGeo, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationActionPinnedGeoChannel", R.string.NotificationActionPinnedGeoChannel, chat.title); + } + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { + if (!ChatObject.isChannel(chat) || chat.megagroup) { + msg = LocaleController.formatString("NotificationActionPinnedContact", R.string.NotificationActionPinnedContact, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationActionPinnedContactChannel", R.string.NotificationActionPinnedContactChannel, chat.title); + } + } else if (object.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { + if (!ChatObject.isChannel(chat) || chat.megagroup) { + msg = LocaleController.formatString("NotificationActionPinnedPhoto", R.string.NotificationActionPinnedPhoto, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationActionPinnedPhotoChannel", R.string.NotificationActionPinnedPhotoChannel, chat.title); + } + } else if (object.messageText != null && object.messageText.length() > 0) { + CharSequence message = object.messageText; + if (message.length() > 20) { + message = message.subSequence(0, 20) + "..."; + } + if (!ChatObject.isChannel(chat) || chat.megagroup) { + msg = LocaleController.formatString("NotificationActionPinnedText", R.string.NotificationActionPinnedText, name, message, chat.title); + } else { + msg = LocaleController.formatString("NotificationActionPinnedTextChannel", R.string.NotificationActionPinnedTextChannel, chat.title, message); + } + } else { + if (!ChatObject.isChannel(chat) || chat.megagroup) { + msg = LocaleController.formatString("NotificationActionPinnedNoText", R.string.NotificationActionPinnedNoText, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationActionPinnedNoTextChannel", R.string.NotificationActionPinnedNoTextChannel, chat.title); + } + } + } + } + } else { + if (ChatObject.isChannel(chat) && !chat.megagroup) { + if (messageObject.isImportant()) { + if (messageObject.isMediaEmpty()) { + if (!shortMessage && messageObject.messageOwner.message != null && messageObject.messageOwner.message.length() != 0) { + msg = LocaleController.formatString("NotificationMessageGroupText", R.string.NotificationMessageGroupText, name, chat.title, messageObject.messageOwner.message); + } else { + msg = LocaleController.formatString("ChannelMessageNoText", R.string.ChannelMessageNoText, name, chat.title); + } + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { + msg = LocaleController.formatString("ChannelMessagePhoto", R.string.ChannelMessagePhoto, name, chat.title); + } else if (messageObject.isVideo()) { + msg = LocaleController.formatString("ChannelMessageVideo", R.string.ChannelMessageVideo, name, chat.title); + } else if (messageObject.isVoice()) { + msg = LocaleController.formatString("ChannelMessageAudio", R.string.ChannelMessageAudio, name, chat.title); + } else if (messageObject.isMusic()) { + msg = LocaleController.formatString("ChannelMessageMusic", R.string.ChannelMessageMusic, name, chat.title); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { + msg = LocaleController.formatString("ChannelMessageContact", R.string.ChannelMessageContact, name, chat.title); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) { + msg = LocaleController.formatString("ChannelMessageMap", R.string.ChannelMessageMap, name, chat.title); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + if (messageObject.isSticker()) { + msg = LocaleController.formatString("ChannelMessageSticker", R.string.ChannelMessageSticker, name, chat.title); + } else if (messageObject.isGif()) { + msg = LocaleController.formatString("ChannelMessageGIF", R.string.ChannelMessageGIF, name, chat.title); + } else { + msg = LocaleController.formatString("ChannelMessageDocument", R.string.ChannelMessageDocument, name, chat.title); + } + } + } else { + if (messageObject.isMediaEmpty()) { + if (!shortMessage && messageObject.messageOwner.message != null && messageObject.messageOwner.message.length() != 0) { + msg = LocaleController.formatString("NotificationMessageGroupText", R.string.NotificationMessageGroupText, name, chat.title, messageObject.messageOwner.message); + } else { + msg = LocaleController.formatString("ChannelMessageGroupNoText", R.string.ChannelMessageGroupNoText, name, chat.title); + } + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { + msg = LocaleController.formatString("ChannelMessageGroupPhoto", R.string.ChannelMessageGroupPhoto, name, chat.title); + } else if (messageObject.isVideo()) { + msg = LocaleController.formatString("ChannelMessageGroupVideo", R.string.ChannelMessageGroupVideo, name, chat.title); + } else if (messageObject.isVoice()) { + msg = LocaleController.formatString("ChannelMessageGroupAudio", R.string.ChannelMessageGroupAudio, name, chat.title); + } else if (messageObject.isMusic()) { + msg = LocaleController.formatString("ChannelMessageGroupMusic", R.string.ChannelMessageGroupMusic, name, chat.title); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { + msg = LocaleController.formatString("ChannelMessageGroupContact", R.string.ChannelMessageGroupContact, name, chat.title); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) { + msg = LocaleController.formatString("ChannelMessageGroupMap", R.string.ChannelMessageGroupMap, name, chat.title); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + if (messageObject.isSticker()) { + msg = LocaleController.formatString("ChannelMessageGroupSticker", R.string.ChannelMessageGroupSticker, name, chat.title); + } else if (messageObject.isGif()) { + msg = LocaleController.formatString("ChannelMessageGroupGif", R.string.ChannelMessageGroupGif, name, chat.title); + } else { + msg = LocaleController.formatString("ChannelMessageGroupDocument", R.string.ChannelMessageGroupDocument, name, chat.title); + } + } + } + } else { + if (messageObject.isMediaEmpty()) { + if (!shortMessage && messageObject.messageOwner.message != null && messageObject.messageOwner.message.length() != 0) { + msg = LocaleController.formatString("NotificationMessageGroupText", R.string.NotificationMessageGroupText, name, chat.title, messageObject.messageOwner.message); + } else { + msg = LocaleController.formatString("NotificationMessageGroupNoText", R.string.NotificationMessageGroupNoText, name, chat.title); + } + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto) { + msg = LocaleController.formatString("NotificationMessageGroupPhoto", R.string.NotificationMessageGroupPhoto, name, chat.title); + } else if (messageObject.isVideo()) { + msg = LocaleController.formatString("NotificationMessageGroupVideo", R.string.NotificationMessageGroupVideo, name, chat.title); + } else if (messageObject.isVoice()) { + msg = LocaleController.formatString("NotificationMessageGroupAudio", R.string.NotificationMessageGroupAudio, name, chat.title); + } else if (messageObject.isMusic()) { + msg = LocaleController.formatString("NotificationMessageGroupMusic", R.string.NotificationMessageGroupMusic, name, chat.title); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaContact) { + msg = LocaleController.formatString("NotificationMessageGroupContact", R.string.NotificationMessageGroupContact, name, chat.title); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue) { + msg = LocaleController.formatString("NotificationMessageGroupMap", R.string.NotificationMessageGroupMap, name, chat.title); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { + if (messageObject.isSticker()) { + msg = LocaleController.formatString("NotificationMessageGroupSticker", R.string.NotificationMessageGroupSticker, name, chat.title); + } else if (messageObject.isGif()) { + msg = LocaleController.formatString("NotificationMessageGroupGif", R.string.NotificationMessageGroupGif, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationMessageGroupDocument", R.string.NotificationMessageGroupDocument, name, chat.title); + } + } + } + } + } else { + if (ChatObject.isChannel(chat) && !chat.megagroup) { + msg = LocaleController.formatString("ChannelMessageNoText", R.string.ChannelMessageNoText, name, chat.title); + } else { + msg = LocaleController.formatString("NotificationMessageGroupNoText", R.string.NotificationMessageGroupNoText, name, chat.title); + } + } + } + } + return msg; + } + + private void scheduleNotificationRepeat() { + try { + PendingIntent pintent = PendingIntent.getService(ApplicationLoader.applicationContext, 0, new Intent(ApplicationLoader.applicationContext, NotificationRepeat.class), 0); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + int minutes = preferences.getInt("repeat_messages", 60); + if (minutes > 0 && personal_count > 0) { + alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + minutes * 60 * 1000, pintent); + } else { + alarmManager.cancel(pintent); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + private static String getLauncherClassName(Context context) { + try { + PackageManager pm = context.getPackageManager(); + + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + + List resolveInfos = pm.queryIntentActivities(intent, 0); + for (ResolveInfo resolveInfo : resolveInfos) { + String pkgName = resolveInfo.activityInfo.applicationInfo.packageName; + if (pkgName.equalsIgnoreCase(context.getPackageName())) { + return resolveInfo.activityInfo.name; + } + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + return null; + } + + private boolean isPersonalMessage(MessageObject messageObject) { + return messageObject.messageOwner.to_id != null && messageObject.messageOwner.to_id.chat_id == 0 && messageObject.messageOwner.to_id.channel_id == 0 + && (messageObject.messageOwner.action == null || messageObject.messageOwner.action instanceof TLRPC.TL_messageActionEmpty); + } + + private int getNotifyOverride(SharedPreferences preferences, long dialog_id) { + int notifyOverride = preferences.getInt("notify2_" + dialog_id, 0); + if (notifyOverride == 3) { + int muteUntil = preferences.getInt("notifyuntil_" + dialog_id, 0); + if (muteUntil >= ConnectionsManager.getInstance().getCurrentTime()) { + notifyOverride = 2; + } + } + return notifyOverride; + } + + private void dismissNotification() { + try { + notificationManager.cancel(1); + pushMessages.clear(); + pushMessagesDict.clear(); + for (HashMap.Entry entry : autoNotificationsIds.entrySet()) { + notificationManager.cancel(entry.getValue()); + } + autoNotificationsIds.clear(); + for (HashMap.Entry entry : wearNotificationsIds.entrySet()) { + notificationManager.cancel(entry.getValue()); + } + wearNotificationsIds.clear(); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.pushMessagesUpdated); + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + /*public void playRecordSound() { + try { + if (audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) { + return; + } + notificationsQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (soundPool == null) { + soundPool = new SoundPool(3, AudioManager.STREAM_SYSTEM, 0); + soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() { + @Override + public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { + if (status == 0) { + soundPool.play(sampleId, 1.0f, 1.0f, 1, 0, 1.0f); + } + } + }); + } + if (soundRecord == 0 && !soundRecordLoaded) { + soundRecordLoaded = true; + soundRecord = soundPool.load(ApplicationLoader.applicationContext, R.raw.sound_record, 1); + } + if (soundRecord != 0) { + soundPool.play(soundRecord, 1.0f, 1.0f, 1, 0, 1.0f); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + }*/ + + private void playInChatSound() { + if (!inChatSoundEnabled || MediaController.getInstance().isRecordingAudio()) { + return; + } + try { + if (audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) { + return; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + try { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); + int notifyOverride = getNotifyOverride(preferences, opened_dialog_id); + if (notifyOverride == 2) { + return; + } + notificationsQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (Math.abs(System.currentTimeMillis() - lastSoundPlay) <= 500) { + return; + } + try { + if (soundPool == null) { + soundPool = new SoundPool(3, AudioManager.STREAM_SYSTEM, 0); + soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() { + @Override + public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { + if (status == 0) { + soundPool.play(sampleId, 1.0f, 1.0f, 1, 0, 1.0f); + } + } + }); + } + if (soundIn == 0 && !soundInLoaded) { + soundInLoaded = true; + soundIn = soundPool.load(ApplicationLoader.applicationContext, R.raw.sound_in, 1); + } + if (soundIn != 0) { + soundPool.play(soundIn, 1.0f, 1.0f, 1, 0, 1.0f); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + private void scheduleNotificationDelay(boolean onlineReason) { + try { + FileLog.e("tmessages", "delay notification start, onlineReason = " + onlineReason); + notificationDelayWakelock.acquire(10000); + AndroidUtilities.cancelRunOnUIThread(notificationDelayRunnable); + AndroidUtilities.runOnUIThread(notificationDelayRunnable, (onlineReason ? 3 * 1000 : 1000)); + } catch (Exception e) { + FileLog.e("tmessages", e); + showOrUpdateNotification(notifyCheck); + } + } + + protected void repeatNotificationMaybe() { + notificationsQueue.postRunnable(new Runnable() { + @Override + public void run() { + int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY); + if (hour >= 11 && hour <= 22) { + notificationManager.cancel(1); + showOrUpdateNotification(true); + } else { + scheduleNotificationRepeat(); + } + } + }); + } + + private void showOrUpdateNotification(boolean notifyAboutLast) { + if (!UserConfig.isClientActivated() || pushMessages.isEmpty()) { + dismissNotification(); + return; + } + try { + ConnectionsManager.getInstance().resumeNetworkMaybe(); + + MessageObject lastMessageObject = pushMessages.get(0); + + long dialog_id = lastMessageObject.getDialogId(); + long override_dialog_id = dialog_id; + if (lastMessageObject.messageOwner.mentioned) { + override_dialog_id = lastMessageObject.messageOwner.from_id; + } + int mid = lastMessageObject.getId(); + int chat_id = lastMessageObject.messageOwner.to_id.chat_id != 0 ? lastMessageObject.messageOwner.to_id.chat_id : lastMessageObject.messageOwner.to_id.channel_id; + int user_id = lastMessageObject.messageOwner.to_id.user_id; + if (user_id == 0) { + user_id = lastMessageObject.messageOwner.from_id; + } else if (user_id == UserConfig.getClientUserId()) { + user_id = lastMessageObject.messageOwner.from_id; + } + + TLRPC.User user = MessagesController.getInstance().getUser(user_id); + TLRPC.Chat chat = null; + if (chat_id != 0) { + chat = MessagesController.getInstance().getChat(chat_id); + } + TLRPC.FileLocation photoPath = null; + + boolean notifyDisabled = false; + int needVibrate = 0; + String choosenSoundPath = null; + int ledColor = 0xff00ff00; + boolean inAppSounds; + boolean inAppVibrate; + boolean inAppPreview = false; + boolean inAppPriority; + int priority = 0; + int priorityOverride; + int vibrateOverride; + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Context.MODE_PRIVATE); + int notifyOverride = getNotifyOverride(preferences, override_dialog_id); + if (!notifyAboutLast || notifyOverride == 2 || (!preferences.getBoolean("EnableAll", true) || chat_id != 0 && !preferences.getBoolean("EnableGroup", true)) && notifyOverride == 0) { + notifyDisabled = true; + } + + if (!notifyDisabled && dialog_id == override_dialog_id && chat != null) { + int notifyMaxCount = preferences.getInt("smart_max_count_" + dialog_id, 2); + int notifyDelay = preferences.getInt("smart_delay_" + dialog_id, 3 * 60); + if (notifyMaxCount != 0) { + Point dialogInfo = smartNotificationsDialogs.get(dialog_id); + if (dialogInfo == null) { + dialogInfo = new Point(1, (int) (System.currentTimeMillis() / 1000)); + smartNotificationsDialogs.put(dialog_id, dialogInfo); + } else { + int lastTime = dialogInfo.y; + if (lastTime + notifyDelay < System.currentTimeMillis() / 1000) { + dialogInfo.set(1, (int) (System.currentTimeMillis() / 1000)); + } else { + int count = dialogInfo.x; + if (count < notifyMaxCount) { + dialogInfo.set(count + 1, (int) (System.currentTimeMillis() / 1000)); + } else { + notifyDisabled = true; + } + } + } + } + } + + String defaultPath = Settings.System.DEFAULT_NOTIFICATION_URI.getPath(); + if (!notifyDisabled) { + inAppSounds = preferences.getBoolean("EnableInAppSounds", true); + inAppVibrate = preferences.getBoolean("EnableInAppVibrate", true); + inAppPreview = preferences.getBoolean("EnableInAppPreview", true); + inAppPriority = preferences.getBoolean("EnableInAppPriority", false); + vibrateOverride = preferences.getInt("vibrate_" + dialog_id, 0); + priorityOverride = preferences.getInt("priority_" + dialog_id, 3); + boolean vibrateOnlyIfSilent = false; + + choosenSoundPath = preferences.getString("sound_path_" + dialog_id, null); + if (chat_id != 0) { + if (choosenSoundPath != null && choosenSoundPath.equals(defaultPath)) { + choosenSoundPath = null; + } else if (choosenSoundPath == null) { + choosenSoundPath = preferences.getString("GroupSoundPath", defaultPath); + } + needVibrate = preferences.getInt("vibrate_group", 0); + priority = preferences.getInt("priority_group", 1); + ledColor = preferences.getInt("GroupLed", 0xff00ff00); + } else if (user_id != 0) { + if (choosenSoundPath != null && choosenSoundPath.equals(defaultPath)) { + choosenSoundPath = null; + } else if (choosenSoundPath == null) { + choosenSoundPath = preferences.getString("GlobalSoundPath", defaultPath); + } + needVibrate = preferences.getInt("vibrate_messages", 0); + priority = preferences.getInt("priority_group", 1); + ledColor = preferences.getInt("MessagesLed", 0xff00ff00); + } + if (preferences.contains("color_" + dialog_id)) { + ledColor = preferences.getInt("color_" + dialog_id, 0); + } + + if (priorityOverride != 3) { + priority = priorityOverride; + } + + if (needVibrate == 4) { + vibrateOnlyIfSilent = true; + needVibrate = 0; + } + if (needVibrate == 2 && (vibrateOverride == 1 || vibrateOverride == 3 || vibrateOverride == 5) || needVibrate != 2 && vibrateOverride == 2 || vibrateOverride != 0) { + needVibrate = vibrateOverride; + } + if (!ApplicationLoader.mainInterfacePaused) { + if (!inAppSounds) { + choosenSoundPath = null; + } + if (!inAppVibrate) { + needVibrate = 2; + } + if (!inAppPriority) { + priority = 0; + } else if (priority == 2) { + priority = 1; + } + } + if (vibrateOnlyIfSilent && needVibrate != 2) { + try { + int mode = audioManager.getRingerMode(); + if (mode != AudioManager.RINGER_MODE_SILENT && mode != AudioManager.RINGER_MODE_VIBRATE) { + needVibrate = 2; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + Intent intent = new Intent(ApplicationLoader.applicationContext, LaunchActivity.class); + intent.setAction("com.tmessages.openchat" + Math.random() + Integer.MAX_VALUE); + intent.setFlags(32768); + if ((int)dialog_id != 0) { + if (pushDialogs.size() == 1) { + if (chat_id != 0) { + intent.putExtra("chatId", chat_id); + } else if (user_id != 0) { + intent.putExtra("userId", user_id); + } + } + if (AndroidUtilities.needShowPasscode(false) || UserConfig.isWaitingForPasscodeEnter) { + photoPath = null; + } else { + if (pushDialogs.size() == 1) { + if (chat != null) { + if (chat.photo != null && chat.photo.photo_small != null && chat.photo.photo_small.volume_id != 0 && chat.photo.photo_small.local_id != 0) { + photoPath = chat.photo.photo_small; + } + } else if (user != null) { + if (user.photo != null && user.photo.photo_small != null && user.photo.photo_small.volume_id != 0 && user.photo.photo_small.local_id != 0) { + photoPath = user.photo.photo_small; + } + } + } + } + } else { + if (pushDialogs.size() == 1) { + intent.putExtra("encId", (int) (dialog_id >> 32)); + } + } + PendingIntent contentIntent = PendingIntent.getActivity(ApplicationLoader.applicationContext, 0, intent, PendingIntent.FLAG_ONE_SHOT); + + String name; + boolean replace = true; + if ((int) dialog_id == 0 || pushDialogs.size() > 1 || AndroidUtilities.needShowPasscode(false) || UserConfig.isWaitingForPasscodeEnter) { + //name = LocaleController.getString("AppName", R.string.AppName); + name = BuildVars.DEBUG_VERSION ? LocaleController.getString("AppNameBeta", R.string.AppNameBeta) : LocaleController.getString("AppName", R.string.AppName); + replace = false; + } else { + if (chat != null) { + name = chat.title; + } else { + name = UserObject.getUserName(user); + } + } + + String detailText; + if (pushDialogs.size() == 1) { + detailText = LocaleController.formatPluralString("NewMessages", total_unread_count); + } else { + detailText = LocaleController.formatString("NotificationMessagesPeopleDisplayOrder", R.string.NotificationMessagesPeopleDisplayOrder, LocaleController.formatPluralString("NewMessages", total_unread_count), LocaleController.formatPluralString("FromChats", pushDialogs.size())); + } + + NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ApplicationLoader.applicationContext) + .setContentTitle(name) + .setSmallIcon(R.drawable.notification) + .setAutoCancel(true) + .setNumber(total_unread_count) + .setContentIntent(contentIntent) + .setGroup("messages") + .setGroupSummary(true) + //.setColor(0xff2ca5e0); + .setColor(AndroidUtilities.getIntColor("themeColor")); //Plus + + mBuilder.setCategory(NotificationCompat.CATEGORY_MESSAGE); + if (chat == null && user != null && user.phone != null && user.phone.length() > 0) { + mBuilder.addPerson("tel:+" + user.phone); + } + + int silent = 2; + String lastMessage = null; + if (pushMessages.size() == 1) { + MessageObject messageObject = pushMessages.get(0); + String message = lastMessage = getStringForMessage(messageObject, false); + silent = messageObject.messageOwner.silent ? 1 : 0; + if (message == null) { + return; + } + if (replace) { + if (chat != null) { + message = message.replace(" @ " + name, ""); + } else { + message = message.replace(name + ": ", "").replace(name + " ", ""); + } + } + mBuilder.setContentText(message); + mBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(message)); + } else { + mBuilder.setContentText(detailText); + NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(); + inboxStyle.setBigContentTitle(name); + int count = Math.min(10, pushMessages.size()); + for (int i = 0; i < count; i++) { + MessageObject messageObject = pushMessages.get(i); + String message = getStringForMessage(messageObject, false); + if (message == null) { + continue; + } + if (silent == 2) { + lastMessage = message; + silent = messageObject.messageOwner.silent ? 1 : 0; + } + if (pushDialogs.size() == 1) { + if (replace) { + if (chat != null) { + message = message.replace(" @ " + name, ""); + } else { + message = message.replace(name + ": ", "").replace(name + " ", ""); + } + } + } + inboxStyle.addLine(message); + } + inboxStyle.setSummaryText(detailText); + mBuilder.setStyle(inboxStyle); + } + + if (photoPath != null) { + BitmapDrawable img = ImageLoader.getInstance().getImageFromMemory(photoPath, null, "50_50"); + if (img != null) { + mBuilder.setLargeIcon(img.getBitmap()); + } + } + + if (!notifyAboutLast || silent == 1) { + mBuilder.setPriority(NotificationCompat.PRIORITY_LOW); + } else { + if (priority == 0) { + mBuilder.setPriority(NotificationCompat.PRIORITY_DEFAULT); + } else if (priority == 1) { + mBuilder.setPriority(NotificationCompat.PRIORITY_HIGH); + } else if (priority == 2) { + mBuilder.setPriority(NotificationCompat.PRIORITY_MAX); + } + } + + if (silent != 1 && !notifyDisabled) { + if (ApplicationLoader.mainInterfacePaused || inAppPreview) { + if (lastMessage.length() > 100) { + lastMessage = lastMessage.substring(0, 100).replace("\n", " ").trim() + "..."; + } + mBuilder.setTicker(lastMessage); + } + if (!MediaController.getInstance().isRecordingAudio()) { + if (choosenSoundPath != null && !choosenSoundPath.equals("NoSound")) { + if (choosenSoundPath.equals(defaultPath)) { + mBuilder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI, AudioManager.STREAM_NOTIFICATION); + } else { + mBuilder.setSound(Uri.parse(choosenSoundPath), AudioManager.STREAM_NOTIFICATION); + } + } + } + if (ledColor != 0) { + mBuilder.setLights(ledColor, 1000, 1000); + } + if (needVibrate == 2 || MediaController.getInstance().isRecordingAudio()) { + mBuilder.setVibrate(new long[]{0, 0}); + } else if (needVibrate == 1) { + mBuilder.setVibrate(new long[]{0, 100, 0, 100}); + } else if (needVibrate == 0 || needVibrate == 4) { + mBuilder.setDefaults(NotificationCompat.DEFAULT_VIBRATE); + } else if (needVibrate == 3) { + mBuilder.setVibrate(new long[]{0, 1000}); + } + } else { + mBuilder.setVibrate(new long[]{0, 0}); + } + + showExtraNotifications(mBuilder, notifyAboutLast); + notificationManager.notify(1, mBuilder.build()); + + scheduleNotificationRepeat(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + @SuppressLint("InlinedApi") + private void showExtraNotifications(NotificationCompat.Builder notificationBuilder, boolean notifyAboutLast) { + if (Build.VERSION.SDK_INT < 18) { + return; + } + + ArrayList sortedDialogs = new ArrayList<>(); + HashMap> messagesByDialogs = new HashMap<>(); + for (int a = 0; a < pushMessages.size(); a++) { + MessageObject messageObject = pushMessages.get(a); + long dialog_id = messageObject.getDialogId(); + if ((int)dialog_id == 0) { + continue; + } + + ArrayList arrayList = messagesByDialogs.get(dialog_id); + if (arrayList == null) { + arrayList = new ArrayList<>(); + messagesByDialogs.put(dialog_id, arrayList); + sortedDialogs.add(0, dialog_id); + } + arrayList.add(messageObject); + } + + HashMap oldIdsWear = new HashMap<>(); + oldIdsWear.putAll(wearNotificationsIds); + wearNotificationsIds.clear(); + + HashMap oldIdsAuto = new HashMap<>(); + oldIdsAuto.putAll(autoNotificationsIds); + autoNotificationsIds.clear(); + + for (int b = 0; b < sortedDialogs.size(); b++) { + long dialog_id = sortedDialogs.get(b); + ArrayList messageObjects = messagesByDialogs.get(dialog_id); + int max_id = messageObjects.get(0).getId(); + int max_date = messageObjects.get(0).messageOwner.date; + TLRPC.Chat chat = null; + TLRPC.User user = null; + String name; + if (dialog_id > 0) { + user = MessagesController.getInstance().getUser((int)dialog_id); + if (user == null) { + continue; + } + } else { + chat = MessagesController.getInstance().getChat(-(int)dialog_id); + if (chat == null) { + continue; + } + } + TLRPC.FileLocation photoPath = null; + if (AndroidUtilities.needShowPasscode(false) || UserConfig.isWaitingForPasscodeEnter) { + //name = LocaleController.getString("AppName", R.string.AppName); + name = BuildVars.DEBUG_VERSION ? LocaleController.getString("AppNameBeta", R.string.AppNameBeta) : LocaleController.getString("AppName", R.string.AppName); + } else { + if (chat != null) { + name = chat.title; + } else { + name = UserObject.getUserName(user); + } + if (chat != null) { + if (chat.photo != null && chat.photo.photo_small != null && chat.photo.photo_small.volume_id != 0 && chat.photo.photo_small.local_id != 0) { + photoPath = chat.photo.photo_small; + } + } else { + if (user.photo != null && user.photo.photo_small != null && user.photo.photo_small.volume_id != 0 && user.photo.photo_small.local_id != 0) { + photoPath = user.photo.photo_small; + } + } + } + + Integer notificationIdWear = oldIdsWear.get(dialog_id); + if (notificationIdWear == null) { + notificationIdWear = wearNotificationId++; + } else { + oldIdsWear.remove(dialog_id); + } + + Integer notificationIdAuto = oldIdsAuto.get(dialog_id); + if (notificationIdAuto == null) { + notificationIdAuto = autoNotificationId++; + } else { + oldIdsAuto.remove(dialog_id); + } + + NotificationCompat.CarExtender.UnreadConversation.Builder unreadConvBuilder = new NotificationCompat.CarExtender.UnreadConversation.Builder(name).setLatestTimestamp((long) max_date * 1000); + + Intent msgHeardIntent = new Intent(); + msgHeardIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + msgHeardIntent.setAction("org.telegram.messenger.ACTION_MESSAGE_HEARD"); + msgHeardIntent.putExtra("dialog_id", dialog_id); + msgHeardIntent.putExtra("max_id", max_id); + PendingIntent msgHeardPendingIntent = PendingIntent.getBroadcast(ApplicationLoader.applicationContext, notificationIdAuto, msgHeardIntent, PendingIntent.FLAG_UPDATE_CURRENT); + unreadConvBuilder.setReadPendingIntent(msgHeardPendingIntent); + + NotificationCompat.Action wearReplyAction = null; + + if (!ChatObject.isChannel(chat) && !AndroidUtilities.needShowPasscode(false) && !UserConfig.isWaitingForPasscodeEnter) { + Intent msgReplyIntent = new Intent(); + msgReplyIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + msgReplyIntent.setAction("org.telegram.messenger.ACTION_MESSAGE_REPLY"); + msgReplyIntent.putExtra("dialog_id", dialog_id); + msgReplyIntent.putExtra("max_id", max_id); + PendingIntent msgReplyPendingIntent = PendingIntent.getBroadcast(ApplicationLoader.applicationContext, notificationIdAuto, msgReplyIntent, PendingIntent.FLAG_UPDATE_CURRENT); + RemoteInput remoteInputAuto = new RemoteInput.Builder(NotificationsController.EXTRA_VOICE_REPLY).setLabel(LocaleController.getString("Reply", R.string.Reply)).build(); + unreadConvBuilder.setReplyAction(msgReplyPendingIntent, remoteInputAuto); + + Intent replyIntent = new Intent(ApplicationLoader.applicationContext, WearReplyReceiver.class); + replyIntent.putExtra("dialog_id", dialog_id); + replyIntent.putExtra("max_id", max_id); + PendingIntent replyPendingIntent = PendingIntent.getBroadcast(ApplicationLoader.applicationContext, notificationIdWear, replyIntent, PendingIntent.FLAG_UPDATE_CURRENT); + RemoteInput remoteInputWear = new RemoteInput.Builder(EXTRA_VOICE_REPLY).setLabel(LocaleController.getString("Reply", R.string.Reply)).build(); + String replyToString; + if (chat != null) { + replyToString = LocaleController.formatString("ReplyToGroup", R.string.ReplyToGroup, name); + } else { + replyToString = LocaleController.formatString("ReplyToUser", R.string.ReplyToUser, name); + } + wearReplyAction = new NotificationCompat.Action.Builder(R.drawable.ic_reply_icon, replyToString, replyPendingIntent).addRemoteInput(remoteInputWear).build(); + } + + String text = ""; + for (int a = messageObjects.size() - 1; a >= 0; a--) { + MessageObject messageObject = messageObjects.get(a); + String message = getStringForMessage(messageObject, false); + if (message == null) { + continue; + } + if (chat != null) { + message = message.replace(" @ " + name, ""); + } else { + message = message.replace(name + ": ", "").replace(name + " ", ""); + } + if (text.length() > 0) { + text += "\n\n"; + } + text += message; + + unreadConvBuilder.addMessage(message); + } + + Intent intent = new Intent(ApplicationLoader.applicationContext, LaunchActivity.class); + intent.setAction("com.tmessages.openchat" + Math.random() + Integer.MAX_VALUE); + intent.setFlags(32768); + if (chat != null) { + intent.putExtra("chatId", chat.id); + } else if (user != null) { + intent.putExtra("userId", user.id); + } + PendingIntent contentIntent = PendingIntent.getActivity(ApplicationLoader.applicationContext, 0, intent, PendingIntent.FLAG_ONE_SHOT); + + NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender(); + if (wearReplyAction != null) { + wearableExtender.addAction(wearReplyAction); + } + + NotificationCompat.Builder builder = new NotificationCompat.Builder(ApplicationLoader.applicationContext) + .setContentTitle(name) + .setSmallIcon(R.drawable.notification) + .setGroup("messages") + .setContentText(text) + .setColor(0xff2ca5e0) + .setGroupSummary(false) + .setContentIntent(contentIntent) + .extend(wearableExtender) + .extend(new NotificationCompat.CarExtender().setUnreadConversation(unreadConvBuilder.build())) + .setCategory(NotificationCompat.CATEGORY_MESSAGE); + if (photoPath != null) { + BitmapDrawable img = ImageLoader.getInstance().getImageFromMemory(photoPath, null, "50_50"); + if (img != null) { + builder.setLargeIcon(img.getBitmap()); + } + } + + if (chat == null && user != null && user.phone != null && user.phone.length() > 0) { + builder.addPerson("tel:+" + user.phone); + } + + notificationManager.notify(notificationIdWear, builder.build()); + wearNotificationsIds.put(dialog_id, notificationIdWear); + } + + for (HashMap.Entry entry : oldIdsWear.entrySet()) { + notificationManager.cancel(entry.getValue()); + } + } + + public void playOutChatSound() { + if (!inChatSoundEnabled || MediaController.getInstance().isRecordingAudio()) { + return; + } + try { + if (audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) { + return; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + notificationsQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + if (Math.abs(System.currentTimeMillis() - lastSoundOutPlay) <= 100) { + return; + } + lastSoundOutPlay = System.currentTimeMillis(); + if (soundPool == null) { + soundPool = new SoundPool(3, AudioManager.STREAM_SYSTEM, 0); + soundPool.setOnLoadCompleteListener(new SoundPool.OnLoadCompleteListener() { + @Override + public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { + if (status == 0) { + soundPool.play(sampleId, 1.0f, 1.0f, 1, 0, 1.0f); + } + } + }); + } + if (soundOut == 0 && !soundOutLoaded) { + soundOutLoaded = true; + soundOut = soundPool.load(ApplicationLoader.applicationContext, R.raw.sound_out, 1); + } + if (soundOut != 0) { + soundPool.play(soundOut, 1.0f, 1.0f, 1, 0, 1.0f); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public static void updateServerNotificationsSettings(long dialog_id) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.notificationsSettingsUpdated); + if ((int) dialog_id == 0) { + return; + } + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + TLRPC.TL_account_updateNotifySettings req = new TLRPC.TL_account_updateNotifySettings(); + req.settings = new TLRPC.TL_inputPeerNotifySettings(); + req.settings.sound = "default"; + int mute_type = preferences.getInt("notify2_" + dialog_id, 0); + if (mute_type == 3) { + req.settings.mute_until = preferences.getInt("notifyuntil_" + dialog_id, 0); + } else { + req.settings.mute_until = mute_type != 2 ? 0 : Integer.MAX_VALUE; + } + req.settings.show_previews = preferences.getBoolean("preview_" + dialog_id, true); + req.settings.silent = preferences.getBoolean("silent_" + dialog_id, false); + req.peer = new TLRPC.TL_inputNotifyPeer(); + ((TLRPC.TL_inputNotifyPeer) req.peer).peer = MessagesController.getInputPeer((int) dialog_id); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsService.java b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsService.java new file mode 100644 index 00000000..1398bcdf --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/NotificationsService.java @@ -0,0 +1,43 @@ +/* + * This is the source code of Telegram for Android v. 1.3.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.app.Service; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.IBinder; + +public class NotificationsService extends Service { + + @Override + public void onCreate() { + FileLog.e("tmessages", "service started"); + ApplicationLoader.postInitApplication(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return START_STICKY; + } + + @Override + public IBinder onBind(Intent intent) { + return null; + } + + public void onDestroy() { + FileLog.e("tmessages", "service destroyed"); + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", MODE_PRIVATE); + if (preferences.getBoolean("pushService", true)) { + Intent intent = new Intent("org.telegram.plus.start"); + sendBroadcast(intent); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ScreenReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ScreenReceiver.java new file mode 100644 index 00000000..77f678de --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ScreenReceiver.java @@ -0,0 +1,32 @@ +/* + * This is the source code of Telegram for Android v. 1.3.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import org.telegram.tgnet.ConnectionsManager; + +public class ScreenReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { + FileLog.e("tmessages", "screen off"); + ConnectionsManager.getInstance().setAppPaused(true, true); + ApplicationLoader.isScreenOn = false; + } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) { + FileLog.e("tmessages", "screen on"); + ConnectionsManager.getInstance().setAppPaused(false, true); + ApplicationLoader.isScreenOn = true; + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.screenStateChanged); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java new file mode 100644 index 00000000..1420bf6a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SecretChatHelper.java @@ -0,0 +1,1904 @@ +/* + * This is the source code of Telegram for Android v. 2.0.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; + +import org.telegram.tgnet.AbstractSerializedData; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.NativeByteBuffer; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLClassStore; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; + +import java.io.File; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; + +public class SecretChatHelper { + + public static class TL_decryptedMessageHolder extends TLObject { + public static int constructor = 0x555555F9; + + public long random_id; + public int date; + public TLRPC.TL_decryptedMessageLayer layer; + public TLRPC.EncryptedFile file; + public boolean new_key_used; + + public void readParams(AbstractSerializedData stream, boolean exception) { + random_id = stream.readInt64(exception); + date = stream.readInt32(exception); + layer = TLRPC.TL_decryptedMessageLayer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (stream.readBool(exception)) { + file = TLRPC.EncryptedFile.TLdeserialize(stream, stream.readInt32(exception), exception); + } + new_key_used = stream.readBool(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(random_id); + stream.writeInt32(date); + layer.serializeToStream(stream); + stream.writeBool(file != null); + if (file != null) { + file.serializeToStream(stream); + } + stream.writeBool(new_key_used); + } + } + + public static final int CURRENT_SECRET_CHAT_LAYER = 46; + + private ArrayList sendingNotifyLayer = new ArrayList<>(); + private HashMap> secretHolesQueue = new HashMap<>(); + private HashMap acceptingChats = new HashMap<>(); + public ArrayList delayedEncryptedChatUpdates = new ArrayList<>(); + private ArrayList pendingEncMessagesToDelete = new ArrayList<>(); + private boolean startingSecretChat = false; + + private static volatile SecretChatHelper Instance = null; + + public static SecretChatHelper getInstance() { + SecretChatHelper localInstance = Instance; + if (localInstance == null) { + synchronized (SecretChatHelper.class) { + localInstance = Instance; + if (localInstance == null) { + Instance = localInstance = new SecretChatHelper(); + } + } + } + return localInstance; + } + + public void cleanUp() { + sendingNotifyLayer.clear(); + acceptingChats.clear(); + secretHolesQueue.clear(); + delayedEncryptedChatUpdates.clear(); + pendingEncMessagesToDelete.clear(); + + startingSecretChat = false; + } + + protected void processPendingEncMessages() { + if (!pendingEncMessagesToDelete.isEmpty()) { + final ArrayList pendingEncMessagesToDeleteCopy = new ArrayList<>(pendingEncMessagesToDelete); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + for (int a = 0; a < pendingEncMessagesToDeleteCopy.size(); a++) { + MessageObject messageObject = MessagesController.getInstance().dialogMessagesByRandomIds.get(pendingEncMessagesToDeleteCopy.get(a)); + if (messageObject != null) { + messageObject.deleted = true; + } + } + } + }); + ArrayList arr = new ArrayList<>(pendingEncMessagesToDelete); + MessagesStorage.getInstance().markMessagesAsDeletedByRandoms(arr); + pendingEncMessagesToDelete.clear(); + } + } + + private TLRPC.TL_messageService createServiceSecretMessage(final TLRPC.EncryptedChat encryptedChat, TLRPC.DecryptedMessageAction decryptedMessage) { + TLRPC.TL_messageService newMsg = new TLRPC.TL_messageService(); + + newMsg.action = new TLRPC.TL_messageEncryptedAction(); + newMsg.action.encryptedAction = decryptedMessage; + newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); + newMsg.from_id = UserConfig.getClientUserId(); + newMsg.unread = true; + newMsg.out = true; + newMsg.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + newMsg.dialog_id = ((long) encryptedChat.id) << 32; + newMsg.to_id = new TLRPC.TL_peerUser(); + newMsg.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING; + if (encryptedChat.participant_id == UserConfig.getClientUserId()) { + newMsg.to_id.user_id = encryptedChat.admin_id; + } else { + newMsg.to_id.user_id = encryptedChat.participant_id; + } + if (decryptedMessage instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || decryptedMessage instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { + newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); + } else { + newMsg.date = 0; + } + newMsg.random_id = SendMessagesHelper.getInstance().getNextRandomId(); + UserConfig.saveConfig(false); + + ArrayList arr = new ArrayList<>(); + arr.add(newMsg); + MessagesStorage.getInstance().putMessages(arr, false, true, true, 0); + + return newMsg; + } + + public void sendMessagesReadMessage(TLRPC.EncryptedChat encryptedChat, ArrayList random_ids, TLRPC.Message resendMessage) { + if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { + return; + } + TLRPC.TL_decryptedMessageService reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); + reqSend.random_bytes = new byte[15]; + Utilities.random.nextBytes(reqSend.random_bytes); + } + + TLRPC.Message message; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionReadMessages(); + reqSend.action.random_ids = random_ids; + message = createServiceSecretMessage(encryptedChat, reqSend.action); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); + } + + protected void processUpdateEncryption(TLRPC.TL_updateEncryption update, ConcurrentHashMap usersDict) { + final TLRPC.EncryptedChat newChat = update.chat; + long dialog_id = ((long) newChat.id) << 32; + TLRPC.EncryptedChat existingChat = MessagesController.getInstance().getEncryptedChatDB(newChat.id); + + if (newChat instanceof TLRPC.TL_encryptedChatRequested && existingChat == null) { + int user_id = newChat.participant_id; + if (user_id == UserConfig.getClientUserId()) { + user_id = newChat.admin_id; + } + TLRPC.User user = MessagesController.getInstance().getUser(user_id); + if (user == null) { + user = usersDict.get(user_id); + } + newChat.user_id = user_id; + final TLRPC.Dialog dialog = new TLRPC.TL_dialog(); + dialog.id = dialog_id; + dialog.unread_count = 0; + dialog.top_message = 0; + dialog.last_message_date = update.date; + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().dialogs_dict.put(dialog.id, dialog); + MessagesController.getInstance().dialogs.add(dialog); + MessagesController.getInstance().putEncryptedChat(newChat, false); + Collections.sort(MessagesController.getInstance().dialogs, new Comparator() { + @Override + public int compare(TLRPC.Dialog tl_dialog, TLRPC.Dialog tl_dialog2) { + if (tl_dialog.last_message_date == tl_dialog2.last_message_date) { + return 0; + } else if (tl_dialog.last_message_date < tl_dialog2.last_message_date) { + return 1; + } else { + return -1; + } + } + }); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + } + }); + MessagesStorage.getInstance().putEncryptedChat(newChat, user, dialog); + SecretChatHelper.getInstance().acceptSecretChat(newChat); + } else if (newChat instanceof TLRPC.TL_encryptedChat) { + if (existingChat != null && existingChat instanceof TLRPC.TL_encryptedChatWaiting && (existingChat.auth_key == null || existingChat.auth_key.length == 1)) { + newChat.a_or_b = existingChat.a_or_b; + newChat.user_id = existingChat.user_id; + SecretChatHelper.getInstance().processAcceptedSecretChat(newChat); + } else if (existingChat == null && startingSecretChat) { + delayedEncryptedChatUpdates.add(update); + } + } else { + final TLRPC.EncryptedChat exist = existingChat; + if (exist != null) { + newChat.user_id = exist.user_id; + newChat.auth_key = exist.auth_key; + newChat.key_create_date = exist.key_create_date; + newChat.key_use_count_in = exist.key_use_count_in; + newChat.key_use_count_out = exist.key_use_count_out; + newChat.ttl = exist.ttl; + newChat.seq_in = exist.seq_in; + newChat.seq_out = exist.seq_out; + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (exist != null) { + MessagesController.getInstance().putEncryptedChat(newChat, false); + } + MessagesStorage.getInstance().updateEncryptedChat(newChat); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); + } + }); + } + } + + public void sendMessagesDeleteMessage(TLRPC.EncryptedChat encryptedChat, ArrayList random_ids, TLRPC.Message resendMessage) { + if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { + return; + } + TLRPC.TL_decryptedMessageService reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); + reqSend.random_bytes = new byte[15]; + Utilities.random.nextBytes(reqSend.random_bytes); + } + + TLRPC.Message message; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionDeleteMessages(); + reqSend.action.random_ids = random_ids; + message = createServiceSecretMessage(encryptedChat, reqSend.action); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); + } + + public void sendClearHistoryMessage(TLRPC.EncryptedChat encryptedChat, TLRPC.Message resendMessage) { + if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { + return; + } + TLRPC.TL_decryptedMessageService reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); + reqSend.random_bytes = new byte[15]; + Utilities.random.nextBytes(reqSend.random_bytes); + } + + TLRPC.Message message; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionFlushHistory(); + message = createServiceSecretMessage(encryptedChat, reqSend.action); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); + } + + public void sendNotifyLayerMessage(final TLRPC.EncryptedChat encryptedChat, TLRPC.Message resendMessage) { + if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { + return; + } + if (sendingNotifyLayer.contains(encryptedChat.id)) { + return; + } + sendingNotifyLayer.add(encryptedChat.id); + TLRPC.TL_decryptedMessageService reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); + reqSend.random_bytes = new byte[15]; + Utilities.random.nextBytes(reqSend.random_bytes); + } + + TLRPC.Message message; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionNotifyLayer(); + reqSend.action.layer = CURRENT_SECRET_CHAT_LAYER; + message = createServiceSecretMessage(encryptedChat, reqSend.action); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); + } + + public void sendRequestKeyMessage(final TLRPC.EncryptedChat encryptedChat, TLRPC.Message resendMessage) { + if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { + return; + } + + TLRPC.TL_decryptedMessageService reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); + reqSend.random_bytes = new byte[15]; + Utilities.random.nextBytes(reqSend.random_bytes); + } + + TLRPC.Message message; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionRequestKey(); + reqSend.action.exchange_id = encryptedChat.exchange_id; + reqSend.action.g_a = encryptedChat.g_a; + + message = createServiceSecretMessage(encryptedChat, reqSend.action); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); + } + + public void sendAcceptKeyMessage(final TLRPC.EncryptedChat encryptedChat, TLRPC.Message resendMessage) { + if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { + return; + } + + TLRPC.TL_decryptedMessageService reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); + reqSend.random_bytes = new byte[15]; + Utilities.random.nextBytes(reqSend.random_bytes); + } + + TLRPC.Message message; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionAcceptKey(); + reqSend.action.exchange_id = encryptedChat.exchange_id; + reqSend.action.key_fingerprint = encryptedChat.future_key_fingerprint; + reqSend.action.g_b = encryptedChat.g_a_or_b; + + message = createServiceSecretMessage(encryptedChat, reqSend.action); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); + } + + public void sendCommitKeyMessage(final TLRPC.EncryptedChat encryptedChat, TLRPC.Message resendMessage) { + if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { + return; + } + + TLRPC.TL_decryptedMessageService reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); + reqSend.random_bytes = new byte[15]; + Utilities.random.nextBytes(reqSend.random_bytes); + } + + TLRPC.Message message; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionCommitKey(); + reqSend.action.exchange_id = encryptedChat.exchange_id; + reqSend.action.key_fingerprint = encryptedChat.future_key_fingerprint; + + message = createServiceSecretMessage(encryptedChat, reqSend.action); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); + } + + public void sendAbortKeyMessage(final TLRPC.EncryptedChat encryptedChat, TLRPC.Message resendMessage, long excange_id) { + if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { + return; + } + + TLRPC.TL_decryptedMessageService reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); + reqSend.random_bytes = new byte[15]; + Utilities.random.nextBytes(reqSend.random_bytes); + } + + TLRPC.Message message; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionAbortKey(); + reqSend.action.exchange_id = excange_id; + + message = createServiceSecretMessage(encryptedChat, reqSend.action); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); + } + + public void sendNoopMessage(final TLRPC.EncryptedChat encryptedChat, TLRPC.Message resendMessage) { + if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { + return; + } + + TLRPC.TL_decryptedMessageService reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); + reqSend.random_bytes = new byte[15]; + Utilities.random.nextBytes(reqSend.random_bytes); + } + + TLRPC.Message message; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionNoop(); + message = createServiceSecretMessage(encryptedChat, reqSend.action); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); + } + + public void sendTTLMessage(TLRPC.EncryptedChat encryptedChat, TLRPC.Message resendMessage) { + if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { + return; + } + + TLRPC.TL_decryptedMessageService reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); + reqSend.random_bytes = new byte[15]; + Utilities.random.nextBytes(reqSend.random_bytes); + } + + TLRPC.Message message; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionSetMessageTTL(); + reqSend.action.ttl_seconds = encryptedChat.ttl; + message = createServiceSecretMessage(encryptedChat, reqSend.action); + + MessageObject newMsgObj = new MessageObject(message, null, false); + newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING; + ArrayList objArr = new ArrayList<>(); + objArr.add(newMsgObj); + MessagesController.getInstance().updateInterfaceWithMessages(message.dialog_id, objArr); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); + } + + public void sendScreenshotMessage(TLRPC.EncryptedChat encryptedChat, ArrayList random_ids, TLRPC.Message resendMessage) { + if (!(encryptedChat instanceof TLRPC.TL_encryptedChat)) { + return; + } + + TLRPC.TL_decryptedMessageService reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessageService(); + } else { + reqSend = new TLRPC.TL_decryptedMessageService_layer8(); + reqSend.random_bytes = new byte[15]; + Utilities.random.nextBytes(reqSend.random_bytes); + } + + TLRPC.Message message; + + if (resendMessage != null) { + message = resendMessage; + reqSend.action = message.action.encryptedAction; + } else { + reqSend.action = new TLRPC.TL_decryptedMessageActionScreenshotMessages(); + reqSend.action.random_ids = random_ids; + message = createServiceSecretMessage(encryptedChat, reqSend.action); + + MessageObject newMsgObj = new MessageObject(message, null, false); + newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING; + ArrayList objArr = new ArrayList<>(); + objArr.add(newMsgObj); + MessagesController.getInstance().updateInterfaceWithMessages(message.dialog_id, objArr); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + } + reqSend.random_id = message.random_id; + + performSendEncryptedRequest(reqSend, message, encryptedChat, null, null); + } + + private void processSentMessage(TLRPC.Message newMsg, TLRPC.EncryptedFile file, TLRPC.DecryptedMessage decryptedMessage, String originalPath) { + if (file != null) { + if (newMsg.media instanceof TLRPC.TL_messageMediaPhoto && newMsg.media.photo != null) { + TLRPC.PhotoSize size = newMsg.media.photo.sizes.get(newMsg.media.photo.sizes.size() - 1); + String fileName = size.location.volume_id + "_" + size.location.local_id; + size.location = new TLRPC.TL_fileEncryptedLocation(); + size.location.key = decryptedMessage.media.key; + size.location.iv = decryptedMessage.media.iv; + size.location.dc_id = file.dc_id; + size.location.volume_id = file.id; + size.location.secret = file.access_hash; + size.location.local_id = file.key_fingerprint; + String fileName2 = size.location.volume_id + "_" + size.location.local_id; + File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName + ".jpg"); + File cacheFile2 = FileLoader.getPathToAttach(size); + cacheFile.renameTo(cacheFile2); + ImageLoader.getInstance().replaceImageInCache(fileName, fileName2, size.location, true); + ArrayList arr = new ArrayList<>(); + arr.add(newMsg); + MessagesStorage.getInstance().putMessages(arr, false, true, false, 0); + + //MessagesStorage.getInstance().putSentFile(originalPath, newMsg.media.photo, 3); + } else if (newMsg.media instanceof TLRPC.TL_messageMediaDocument && newMsg.media.document != null) { + TLRPC.Document document = newMsg.media.document; + newMsg.media.document = new TLRPC.TL_documentEncrypted(); + newMsg.media.document.id = file.id; + newMsg.media.document.access_hash = file.access_hash; + newMsg.media.document.date = document.date; + newMsg.media.document.attributes = document.attributes; + newMsg.media.document.mime_type = document.mime_type; + newMsg.media.document.size = file.size; + newMsg.media.document.key = decryptedMessage.media.key; + newMsg.media.document.iv = decryptedMessage.media.iv; + newMsg.media.document.thumb = document.thumb; + newMsg.media.document.dc_id = file.dc_id; + newMsg.media.document.caption = document.caption != null ? document.caption : ""; + + if (newMsg.attachPath != null && newMsg.attachPath.startsWith(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE).getAbsolutePath())) { + File cacheFile = new File(newMsg.attachPath); + File cacheFile2 = FileLoader.getPathToAttach(newMsg.media.document); + if (cacheFile.renameTo(cacheFile2)) { + newMsg.attachPath = ""; + } + } + + /*String fileName = audio.dc_id + "_" + audio.id + ".ogg"; TODO check + String fileName2 = newMsg.media.audio.dc_id + "_" + newMsg.media.audio.id + ".ogg"; + if (!fileName.equals(fileName2)) { + File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); + File cacheFile2 = FileLoader.getPathToAttach(newMsg.media.audio); + if (cacheFile.renameTo(cacheFile2)) { + newMsg.attachPath = ""; + } + }*/ + + ArrayList arr = new ArrayList<>(); + arr.add(newMsg); + MessagesStorage.getInstance().putMessages(arr, false, true, false, 0); + + //MessagesStorage.getInstance().putSentFile(originalPath, newMsg.media.document, 4); document + //MessagesStorage.getInstance().putSentFile(originalPath, newMsg.media.video, 5); video + } + } + } + + public static boolean isSecretVisibleMessage(TLRPC.Message message) { + return message.action instanceof TLRPC.TL_messageEncryptedAction && (message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL); + } + + public static boolean isSecretInvisibleMessage(TLRPC.Message message) { + return message.action instanceof TLRPC.TL_messageEncryptedAction && !(message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages || message.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL); + } + + protected void performSendEncryptedRequest(final TLRPC.DecryptedMessage req, final TLRPC.Message newMsgObj, final TLRPC.EncryptedChat chat, final TLRPC.InputEncryptedFile encryptedFile, final String originalPath) { + if (req == null || chat.auth_key == null || chat instanceof TLRPC.TL_encryptedChatRequested || chat instanceof TLRPC.TL_encryptedChatWaiting) { + return; + } + SendMessagesHelper.getInstance().putToSendingMessages(newMsgObj); + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + try { + TLObject toEncryptObject; + if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) { + TLRPC.TL_decryptedMessageLayer layer = new TLRPC.TL_decryptedMessageLayer(); + int myLayer = Math.max(17, AndroidUtilities.getMyLayerVersion(chat.layer)); + layer.layer = Math.min(myLayer, AndroidUtilities.getPeerLayerVersion(chat.layer)); + layer.message = req; + layer.random_bytes = new byte[15]; + Utilities.random.nextBytes(layer.random_bytes); + toEncryptObject = layer; + + if (chat.seq_in == 0 && chat.seq_out == 0) { + if (chat.admin_id == UserConfig.getClientUserId()) { + chat.seq_out = 1; + } else { + chat.seq_in = 1; + } + } + + if (newMsgObj.seq_in == 0 && newMsgObj.seq_out == 0) { + layer.in_seq_no = chat.seq_in; + layer.out_seq_no = chat.seq_out; + chat.seq_out += 2; + if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 20) { + if (chat.key_create_date == 0) { + chat.key_create_date = ConnectionsManager.getInstance().getCurrentTime(); + } + chat.key_use_count_out++; + if ((chat.key_use_count_out >= 100 || chat.key_create_date < ConnectionsManager.getInstance().getCurrentTime() - 60 * 60 * 24 * 7) && chat.exchange_id == 0 && chat.future_key_fingerprint == 0) { + requestNewSecretChatKey(chat); + } + } + MessagesStorage.getInstance().updateEncryptedChatSeq(chat); + if (newMsgObj != null) { + newMsgObj.seq_in = layer.in_seq_no; + newMsgObj.seq_out = layer.out_seq_no; + MessagesStorage.getInstance().setMessageSeq(newMsgObj.id, newMsgObj.seq_in, newMsgObj.seq_out); + } + } else { + layer.in_seq_no = newMsgObj.seq_in; + layer.out_seq_no = newMsgObj.seq_out; + } + FileLog.e("tmessages", req + " send message with in_seq = " + layer.in_seq_no + " out_seq = " + layer.out_seq_no); + } else { + toEncryptObject = req; + } + + + int len = toEncryptObject.getObjectSize(); + NativeByteBuffer toEncrypt = new NativeByteBuffer(4 + len); + toEncrypt.writeInt32(len); + toEncryptObject.serializeToStream(toEncrypt); + + byte[] messageKeyFull = Utilities.computeSHA1(toEncrypt.buffer); + byte[] messageKey = new byte[16]; + if (messageKeyFull.length != 0) { + System.arraycopy(messageKeyFull, messageKeyFull.length - 16, messageKey, 0, 16); + } + + MessageKeyData keyData = MessageKeyData.generateMessageKeyData(chat.auth_key, messageKey, false); + + len = toEncrypt.length(); + int extraLen = len % 16 != 0 ? 16 - len % 16 : 0; + NativeByteBuffer dataForEncryption = new NativeByteBuffer(len + extraLen); + toEncrypt.position(0); + dataForEncryption.writeBytes(toEncrypt); + if (extraLen != 0) { + byte[] b = new byte[extraLen]; + Utilities.random.nextBytes(b); + dataForEncryption.writeBytes(b); + } + toEncrypt.reuse(); + + Utilities.aesIgeEncryption(dataForEncryption.buffer, keyData.aesKey, keyData.aesIv, true, false, 0, dataForEncryption.limit()); + + NativeByteBuffer data = new NativeByteBuffer(8 + messageKey.length + dataForEncryption.length()); + dataForEncryption.position(0); + data.writeInt64(chat.key_fingerprint); + data.writeBytes(messageKey); + data.writeBytes(dataForEncryption); + dataForEncryption.reuse(); + data.position(0); + + TLObject reqToSend; + + if (encryptedFile == null) { + if (req instanceof TLRPC.TL_decryptedMessageService) { + TLRPC.TL_messages_sendEncryptedService req2 = new TLRPC.TL_messages_sendEncryptedService(); + req2.data = data; + req2.random_id = req.random_id; + req2.peer = new TLRPC.TL_inputEncryptedChat(); + req2.peer.chat_id = chat.id; + req2.peer.access_hash = chat.access_hash; + reqToSend = req2; + } else { + TLRPC.TL_messages_sendEncrypted req2 = new TLRPC.TL_messages_sendEncrypted(); + req2.data = data; + req2.random_id = req.random_id; + req2.peer = new TLRPC.TL_inputEncryptedChat(); + req2.peer.chat_id = chat.id; + req2.peer.access_hash = chat.access_hash; + reqToSend = req2; + } + } else { + TLRPC.TL_messages_sendEncryptedFile req2 = new TLRPC.TL_messages_sendEncryptedFile(); + req2.data = data; + req2.random_id = req.random_id; + req2.peer = new TLRPC.TL_inputEncryptedChat(); + req2.peer.chat_id = chat.id; + req2.peer.access_hash = chat.access_hash; + req2.file = encryptedFile; + reqToSend = req2; + } + ConnectionsManager.getInstance().sendRequest(reqToSend, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + if (req.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) { + TLRPC.EncryptedChat currentChat = MessagesController.getInstance().getEncryptedChat(chat.id); + if (currentChat == null) { + currentChat = chat; + } + + if (currentChat.key_hash == null) { + currentChat.key_hash = AndroidUtilities.calcAuthKeyHash(currentChat.auth_key); + } + + if (AndroidUtilities.getPeerLayerVersion(currentChat.layer) >= 46 && currentChat.key_hash.length == 16) { + try { + byte[] sha256 = Utilities.computeSHA256(chat.auth_key, 0, chat.auth_key.length); + byte[] key_hash = new byte[36]; + System.arraycopy(chat.key_hash, 0, key_hash, 0, 16); + System.arraycopy(sha256, 0, key_hash, 16, 20); + currentChat.key_hash = key_hash; + MessagesStorage.getInstance().updateEncryptedChat(currentChat); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + + sendingNotifyLayer.remove((Integer) currentChat.id); + currentChat.layer = AndroidUtilities.setMyLayerVersion(currentChat.layer, CURRENT_SECRET_CHAT_LAYER); + MessagesStorage.getInstance().updateEncryptedChatLayer(currentChat); + } + } + if (newMsgObj != null) { + if (error == null) { + final String attachPath = newMsgObj.attachPath; + final TLRPC.messages_SentEncryptedMessage res = (TLRPC.messages_SentEncryptedMessage) response; + if (isSecretVisibleMessage(newMsgObj)) { + newMsgObj.date = res.date; + } + if (res.file instanceof TLRPC.TL_encryptedFile) { + processSentMessage(newMsgObj, res.file, req, originalPath); + } + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + if (isSecretInvisibleMessage(newMsgObj)) { + res.date = 0; + } + MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.random_id, newMsgObj.id, newMsgObj.id, res.date, false, 0); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, newMsgObj.id, newMsgObj.id, newMsgObj, newMsgObj.dialog_id); + SendMessagesHelper.getInstance().processSentMessage(newMsgObj.id); + if (MessageObject.isVideoMessage(newMsgObj)) { + SendMessagesHelper.getInstance().stopVideoService(attachPath); + } + SendMessagesHelper.getInstance().removeFromSendingMessages(newMsgObj.id); + } + }); + } + }); + } else { + MessagesStorage.getInstance().markMessageAsSendError(newMsgObj); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); + SendMessagesHelper.getInstance().processSentMessage(newMsgObj.id); + if (MessageObject.isVideoMessage(newMsgObj)) { + SendMessagesHelper.getInstance().stopVideoService(newMsgObj.attachPath); + } + SendMessagesHelper.getInstance().removeFromSendingMessages(newMsgObj.id); + } + }); + } + } + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + private void applyPeerLayer(final TLRPC.EncryptedChat chat, int newPeerLayer) { + int currentPeerLayer = AndroidUtilities.getPeerLayerVersion(chat.layer); + if (newPeerLayer <= currentPeerLayer) { + return; + } + if (chat.key_hash.length == 16 && currentPeerLayer >= 46) { + try { + byte[] sha256 = Utilities.computeSHA256(chat.auth_key, 0, chat.auth_key.length); + byte[] key_hash = new byte[36]; + System.arraycopy(chat.key_hash, 0, key_hash, 0, 16); + System.arraycopy(sha256, 0, key_hash, 16, 20); + chat.key_hash = key_hash; + MessagesStorage.getInstance().updateEncryptedChat(chat); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + chat.layer = AndroidUtilities.setPeerLayerVersion(chat.layer, newPeerLayer); + MessagesStorage.getInstance().updateEncryptedChatLayer(chat); + if (currentPeerLayer < CURRENT_SECRET_CHAT_LAYER) { + sendNotifyLayerMessage(chat, null); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, chat); + } + }); + } + + public TLRPC.Message processDecryptedObject(final TLRPC.EncryptedChat chat, final TLRPC.EncryptedFile file, int date, long random_id, TLObject object, boolean new_key_used) { + if (object != null) { + int from_id = chat.admin_id; + if (from_id == UserConfig.getClientUserId()) { + from_id = chat.participant_id; + } + + if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 20 && chat.exchange_id == 0 && chat.future_key_fingerprint == 0 && chat.key_use_count_in >= 120) { + requestNewSecretChatKey(chat); + } + + if (chat.exchange_id == 0 && chat.future_key_fingerprint != 0 && !new_key_used) { + chat.future_auth_key = new byte[256]; + chat.future_key_fingerprint = 0; + MessagesStorage.getInstance().updateEncryptedChat(chat); + } else if (chat.exchange_id != 0 && new_key_used) { + chat.key_fingerprint = chat.future_key_fingerprint; + chat.auth_key = chat.future_auth_key; + chat.key_create_date = ConnectionsManager.getInstance().getCurrentTime(); + chat.future_auth_key = new byte[256]; + chat.future_key_fingerprint = 0; + chat.key_use_count_in = 0; + chat.key_use_count_out = 0; + chat.exchange_id = 0; + + MessagesStorage.getInstance().updateEncryptedChat(chat); + } + + if (object instanceof TLRPC.TL_decryptedMessage) { + TLRPC.TL_decryptedMessage decryptedMessage = (TLRPC.TL_decryptedMessage) object; + TLRPC.TL_message newMessage; + if (AndroidUtilities.getPeerLayerVersion(chat.layer) >= 17) { + newMessage = new TLRPC.TL_message_secret(); + newMessage.ttl = decryptedMessage.ttl; + newMessage.entities = decryptedMessage.entities; + } else { + newMessage = new TLRPC.TL_message(); + newMessage.ttl = chat.ttl; + } + newMessage.message = decryptedMessage.message; + newMessage.date = date; + newMessage.local_id = newMessage.id = UserConfig.getNewMessageId(); + UserConfig.saveConfig(false); + newMessage.from_id = from_id; + newMessage.to_id = new TLRPC.TL_peerUser(); + newMessage.random_id = random_id; + newMessage.to_id.user_id = UserConfig.getClientUserId(); + newMessage.unread = true; + newMessage.flags = TLRPC.MESSAGE_FLAG_HAS_MEDIA | TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + if (decryptedMessage.via_bot_name != null && decryptedMessage.via_bot_name.length() > 0) { + newMessage.via_bot_name = decryptedMessage.via_bot_name; + newMessage.flags |= TLRPC.MESSAGE_FLAG_HAS_BOT_ID; + } + newMessage.dialog_id = ((long) chat.id) << 32; + if (decryptedMessage.reply_to_random_id != 0) { + newMessage.reply_to_random_id = decryptedMessage.reply_to_random_id; + newMessage.flags |= TLRPC.MESSAGE_FLAG_REPLY; + } + if (decryptedMessage.media == null || decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaEmpty) { + newMessage.media = new TLRPC.TL_messageMediaEmpty(); + } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaWebPage) { + newMessage.media = new TLRPC.TL_messageMediaWebPage(); + newMessage.media.webpage = new TLRPC.TL_webPageUrlPending(); + newMessage.media.webpage.url = decryptedMessage.media.url; + } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaContact) { + newMessage.media = new TLRPC.TL_messageMediaContact(); + newMessage.media.last_name = decryptedMessage.media.last_name; + newMessage.media.first_name = decryptedMessage.media.first_name; + newMessage.media.phone_number = decryptedMessage.media.phone_number; + newMessage.media.user_id = decryptedMessage.media.user_id; + } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaGeoPoint) { + newMessage.media = new TLRPC.TL_messageMediaGeo(); + newMessage.media.geo = new TLRPC.TL_geoPoint(); + newMessage.media.geo.lat = decryptedMessage.media.lat; + newMessage.media.geo._long = decryptedMessage.media._long; + } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaPhoto) { + if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) { + return null; + } + newMessage.media = new TLRPC.TL_messageMediaPhoto(); + newMessage.media.caption = decryptedMessage.media.caption != null ? decryptedMessage.media.caption : ""; + newMessage.media.photo = new TLRPC.TL_photo(); + newMessage.media.photo.date = newMessage.date; + byte[] thumb = ((TLRPC.TL_decryptedMessageMediaPhoto) decryptedMessage.media).thumb; + if (thumb != null && thumb.length != 0 && thumb.length <= 6000 && decryptedMessage.media.thumb_w <= 100 && decryptedMessage.media.thumb_h <= 100) { + TLRPC.TL_photoCachedSize small = new TLRPC.TL_photoCachedSize(); + small.w = decryptedMessage.media.thumb_w; + small.h = decryptedMessage.media.thumb_h; + small.bytes = thumb; + small.type = "s"; + small.location = new TLRPC.TL_fileLocationUnavailable(); + newMessage.media.photo.sizes.add(small); + } + + TLRPC.TL_photoSize big = new TLRPC.TL_photoSize(); + big.w = decryptedMessage.media.w; + big.h = decryptedMessage.media.h; + big.type = "x"; + big.size = file.size; + big.location = new TLRPC.TL_fileEncryptedLocation(); + big.location.key = decryptedMessage.media.key; + big.location.iv = decryptedMessage.media.iv; + big.location.dc_id = file.dc_id; + big.location.volume_id = file.id; + big.location.secret = file.access_hash; + big.location.local_id = file.key_fingerprint; + newMessage.media.photo.sizes.add(big); + } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaVideo) { + if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) { + return null; + } + newMessage.media = new TLRPC.TL_messageMediaDocument(); + newMessage.media.document = new TLRPC.TL_documentEncrypted(); + newMessage.media.document.key = decryptedMessage.media.key; + newMessage.media.document.iv = decryptedMessage.media.iv; + newMessage.media.document.dc_id = file.dc_id; + newMessage.media.caption = decryptedMessage.media.caption != null ? decryptedMessage.media.caption : ""; + newMessage.media.document.date = date; + newMessage.media.document.size = file.size; + newMessage.media.document.id = file.id; + newMessage.media.document.access_hash = file.access_hash; + newMessage.media.document.mime_type = decryptedMessage.media.mime_type; + if (newMessage.media.document.mime_type == null) { + newMessage.media.document.mime_type = "video/mp4"; + } + byte[] thumb = ((TLRPC.TL_decryptedMessageMediaVideo) decryptedMessage.media).thumb; + if (thumb != null && thumb.length != 0 && thumb.length <= 6000 && decryptedMessage.media.thumb_w <= 100 && decryptedMessage.media.thumb_h <= 100) { + newMessage.media.document.thumb = new TLRPC.TL_photoCachedSize(); + newMessage.media.document.thumb.bytes = thumb; + newMessage.media.document.thumb.w = decryptedMessage.media.thumb_w; + newMessage.media.document.thumb.h = decryptedMessage.media.thumb_h; + newMessage.media.document.thumb.type = "s"; + newMessage.media.document.thumb.location = new TLRPC.TL_fileLocationUnavailable(); + } else { + newMessage.media.document.thumb = new TLRPC.TL_photoSizeEmpty(); + newMessage.media.document.thumb.type = "s"; + } + TLRPC.TL_documentAttributeVideo attributeVideo = new TLRPC.TL_documentAttributeVideo(); + attributeVideo.w = decryptedMessage.media.w; + attributeVideo.h = decryptedMessage.media.h; + attributeVideo.duration = decryptedMessage.media.duration; + newMessage.media.document.attributes.add(attributeVideo); + if (newMessage.ttl != 0) { + newMessage.ttl = Math.max(decryptedMessage.media.duration + 2, newMessage.ttl); + } + } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaDocument) { + if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) { + return null; + } + newMessage.media = new TLRPC.TL_messageMediaDocument(); + newMessage.media.caption = decryptedMessage.media.caption != null ? decryptedMessage.media.caption : ""; + newMessage.media.document = new TLRPC.TL_documentEncrypted(); + newMessage.media.document.id = file.id; + newMessage.media.document.access_hash = file.access_hash; + newMessage.media.document.date = date; + if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaDocument_layer8) { + TLRPC.TL_documentAttributeFilename fileName = new TLRPC.TL_documentAttributeFilename(); + fileName.file_name = decryptedMessage.media.file_name; + newMessage.media.document.attributes.add(fileName); + } else { + newMessage.media.document.attributes = decryptedMessage.media.attributes; + } + newMessage.media.document.mime_type = decryptedMessage.media.mime_type; + newMessage.media.document.size = file.size; + newMessage.media.document.key = decryptedMessage.media.key; + newMessage.media.document.iv = decryptedMessage.media.iv; + if (newMessage.media.document.mime_type == null) { + newMessage.media.document.mime_type = ""; + } + byte[] thumb = ((TLRPC.TL_decryptedMessageMediaDocument) decryptedMessage.media).thumb; + if (thumb != null && thumb.length != 0 && thumb.length <= 6000 && decryptedMessage.media.thumb_w <= 100 && decryptedMessage.media.thumb_h <= 100) { + newMessage.media.document.thumb = new TLRPC.TL_photoCachedSize(); + newMessage.media.document.thumb.bytes = thumb; + newMessage.media.document.thumb.w = decryptedMessage.media.thumb_w; + newMessage.media.document.thumb.h = decryptedMessage.media.thumb_h; + newMessage.media.document.thumb.type = "s"; + newMessage.media.document.thumb.location = new TLRPC.TL_fileLocationUnavailable(); + } else { + newMessage.media.document.thumb = new TLRPC.TL_photoSizeEmpty(); + newMessage.media.document.thumb.type = "s"; + } + newMessage.media.document.dc_id = file.dc_id; + if (MessageObject.isVoiceMessage(newMessage)) { + newMessage.media_unread = true; + } + } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaExternalDocument) { + newMessage.media = new TLRPC.TL_messageMediaDocument(); + newMessage.media.caption = ""; + newMessage.media.document = new TLRPC.TL_document(); + newMessage.media.document.id = decryptedMessage.media.id; + newMessage.media.document.access_hash = decryptedMessage.media.access_hash; + newMessage.media.document.date = decryptedMessage.media.date; + newMessage.media.document.attributes = decryptedMessage.media.attributes; + newMessage.media.document.mime_type = decryptedMessage.media.mime_type; + newMessage.media.document.dc_id = decryptedMessage.media.dc_id; + newMessage.media.document.size = decryptedMessage.media.size; + newMessage.media.document.thumb = ((TLRPC.TL_decryptedMessageMediaExternalDocument) decryptedMessage.media).thumb; + if (newMessage.media.document.mime_type == null) { + newMessage.media.document.mime_type = ""; + } + } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaAudio) { + if (decryptedMessage.media.key == null || decryptedMessage.media.key.length != 32 || decryptedMessage.media.iv == null || decryptedMessage.media.iv.length != 32) { + return null; + } + newMessage.media = new TLRPC.TL_messageMediaDocument(); + newMessage.media.document = new TLRPC.TL_documentEncrypted(); + newMessage.media.document.key = decryptedMessage.media.key; + newMessage.media.document.iv = decryptedMessage.media.iv; + newMessage.media.document.id = file.id; + newMessage.media.document.access_hash = file.access_hash; + newMessage.media.document.date = date; + newMessage.media.document.size = file.size; + newMessage.media.document.dc_id = file.dc_id; + newMessage.media.document.mime_type = decryptedMessage.media.mime_type; + newMessage.media.document.thumb = new TLRPC.TL_photoSizeEmpty(); + newMessage.media.document.thumb.type = "s"; + newMessage.media.caption = decryptedMessage.media.caption != null ? decryptedMessage.media.caption : ""; + if (newMessage.media.document.mime_type == null) { + newMessage.media.document.mime_type = "audio/ogg"; + } + TLRPC.TL_documentAttributeAudio attributeAudio = new TLRPC.TL_documentAttributeAudio(); + attributeAudio.duration = decryptedMessage.media.duration; + attributeAudio.voice = true; + newMessage.media.document.attributes.add(attributeAudio); + if (newMessage.ttl != 0) { + newMessage.ttl = Math.max(decryptedMessage.media.duration + 1, newMessage.ttl); + } + } else if (decryptedMessage.media instanceof TLRPC.TL_decryptedMessageMediaVenue) { + newMessage.media = new TLRPC.TL_messageMediaVenue(); + newMessage.media.geo = new TLRPC.TL_geoPoint(); + newMessage.media.geo.lat = decryptedMessage.media.lat; + newMessage.media.geo._long = decryptedMessage.media._long; + newMessage.media.title = decryptedMessage.media.title; + newMessage.media.address = decryptedMessage.media.address; + newMessage.media.provider = decryptedMessage.media.provider; + newMessage.media.venue_id = decryptedMessage.media.venue_id; + } else { + return null; + } + return newMessage; + } else if (object instanceof TLRPC.TL_decryptedMessageService) { + final TLRPC.TL_decryptedMessageService serviceMessage = (TLRPC.TL_decryptedMessageService) object; + if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL || serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) { + TLRPC.TL_messageService newMessage = new TLRPC.TL_messageService(); + if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { + newMessage.action = new TLRPC.TL_messageEncryptedAction(); + if (serviceMessage.action.ttl_seconds < 0 || serviceMessage.action.ttl_seconds > 60 * 60 * 24 * 365) { + serviceMessage.action.ttl_seconds = 60 * 60 * 24 * 365; + } + chat.ttl = serviceMessage.action.ttl_seconds; + newMessage.action.encryptedAction = serviceMessage.action; + MessagesStorage.getInstance().updateEncryptedChatTTL(chat); + } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) { + newMessage.action = new TLRPC.TL_messageEncryptedAction(); + newMessage.action.encryptedAction = serviceMessage.action; + } + newMessage.local_id = newMessage.id = UserConfig.getNewMessageId(); + UserConfig.saveConfig(false); + newMessage.unread = true; + newMessage.flags = TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + newMessage.date = date; + newMessage.from_id = from_id; + newMessage.to_id = new TLRPC.TL_peerUser(); + newMessage.to_id.user_id = UserConfig.getClientUserId(); + newMessage.dialog_id = ((long) chat.id) << 32; + return newMessage; + } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionFlushHistory) { + final long did = ((long) chat.id) << 32; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + TLRPC.Dialog dialog = MessagesController.getInstance().dialogs_dict.get(did); + if (dialog != null) { + dialog.unread_count = 0; + MessagesController.getInstance().dialogMessage.remove(dialog.id); + } + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationsController.getInstance().processReadMessages(null, did, 0, Integer.MAX_VALUE, false); + HashMap dialogsToUpdate = new HashMap<>(); + dialogsToUpdate.put(did, 0); + NotificationsController.getInstance().processDialogsUpdateRead(dialogsToUpdate); + } + }); + } + }); + MessagesStorage.getInstance().deleteDialog(did, 1); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.removeAllMessagesFromDialog, did, false); + } + }); + return null; + } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionDeleteMessages) { + if (!serviceMessage.action.random_ids.isEmpty()) { + pendingEncMessagesToDelete.addAll(serviceMessage.action.random_ids); + } + return null; + } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionReadMessages) { + if (!serviceMessage.action.random_ids.isEmpty()) { + int time = ConnectionsManager.getInstance().getCurrentTime(); + MessagesStorage.getInstance().createTaskForSecretChat(chat.id, time, time, 1, serviceMessage.action.random_ids); + } + } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) { + applyPeerLayer(chat, serviceMessage.action.layer); + } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionRequestKey) { + if (chat.exchange_id != 0) { + if (chat.exchange_id > serviceMessage.action.exchange_id) { + FileLog.e("tmessages", "we already have request key with higher exchange_id"); + return null; + } else { + sendAbortKeyMessage(chat, null, chat.exchange_id); + } + } + + byte[] salt = new byte[256]; + Utilities.random.nextBytes(salt); + BigInteger p = new BigInteger(1, MessagesStorage.secretPBytes); + BigInteger g_b = BigInteger.valueOf(MessagesStorage.secretG); + g_b = g_b.modPow(new BigInteger(1, salt), p); + BigInteger g_a = new BigInteger(1, serviceMessage.action.g_a); + + if (!Utilities.isGoodGaAndGb(g_a, p)) { + sendAbortKeyMessage(chat, null, serviceMessage.action.exchange_id); + return null; + } + + byte[] g_b_bytes = g_b.toByteArray(); + if (g_b_bytes.length > 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(g_b_bytes, 1, correctedAuth, 0, 256); + g_b_bytes = correctedAuth; + } + + g_a = g_a.modPow(new BigInteger(1, salt), p); + + byte[] authKey = g_a.toByteArray(); + if (authKey.length > 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(authKey, authKey.length - 256, correctedAuth, 0, 256); + authKey = correctedAuth; + } else if (authKey.length < 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(authKey, 0, correctedAuth, 256 - authKey.length, authKey.length); + for (int a = 0; a < 256 - authKey.length; a++) { + authKey[a] = 0; + } + authKey = correctedAuth; + } + byte[] authKeyHash = Utilities.computeSHA1(authKey); + byte[] authKeyId = new byte[8]; + System.arraycopy(authKeyHash, authKeyHash.length - 8, authKeyId, 0, 8); + + chat.exchange_id = serviceMessage.action.exchange_id; + chat.future_auth_key = authKey; + chat.future_key_fingerprint = Utilities.bytesToLong(authKeyId); + chat.g_a_or_b = g_b_bytes; + + MessagesStorage.getInstance().updateEncryptedChat(chat); + + sendAcceptKeyMessage(chat, null); + } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionAcceptKey) { + if (chat.exchange_id == serviceMessage.action.exchange_id) { + + BigInteger p = new BigInteger(1, MessagesStorage.secretPBytes); + BigInteger i_authKey = new BigInteger(1, serviceMessage.action.g_b); + + if (!Utilities.isGoodGaAndGb(i_authKey, p)) { + chat.future_auth_key = new byte[256]; + chat.future_key_fingerprint = 0; + chat.exchange_id = 0; + MessagesStorage.getInstance().updateEncryptedChat(chat); + + sendAbortKeyMessage(chat, null, serviceMessage.action.exchange_id); + return null; + } + + i_authKey = i_authKey.modPow(new BigInteger(1, chat.a_or_b), p); + + byte[] authKey = i_authKey.toByteArray(); + if (authKey.length > 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(authKey, authKey.length - 256, correctedAuth, 0, 256); + authKey = correctedAuth; + } else if (authKey.length < 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(authKey, 0, correctedAuth, 256 - authKey.length, authKey.length); + for (int a = 0; a < 256 - authKey.length; a++) { + authKey[a] = 0; + } + authKey = correctedAuth; + } + byte[] authKeyHash = Utilities.computeSHA1(authKey); + byte[] authKeyId = new byte[8]; + System.arraycopy(authKeyHash, authKeyHash.length - 8, authKeyId, 0, 8); + long fingerprint = Utilities.bytesToLong(authKeyId); + if (serviceMessage.action.key_fingerprint == fingerprint) { + chat.future_auth_key = authKey; + chat.future_key_fingerprint = fingerprint; + MessagesStorage.getInstance().updateEncryptedChat(chat); + sendCommitKeyMessage(chat, null); + } else { + chat.future_auth_key = new byte[256]; + chat.future_key_fingerprint = 0; + chat.exchange_id = 0; + MessagesStorage.getInstance().updateEncryptedChat(chat); + sendAbortKeyMessage(chat, null, serviceMessage.action.exchange_id); + } + } else { + chat.future_auth_key = new byte[256]; + chat.future_key_fingerprint = 0; + chat.exchange_id = 0; + MessagesStorage.getInstance().updateEncryptedChat(chat); + sendAbortKeyMessage(chat, null, serviceMessage.action.exchange_id); + } + } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionCommitKey) { + if (chat.exchange_id == serviceMessage.action.exchange_id && chat.future_key_fingerprint == serviceMessage.action.key_fingerprint) { + long old_fingerpring = chat.key_fingerprint; + byte[] old_key = chat.auth_key; + chat.key_fingerprint = chat.future_key_fingerprint; + chat.auth_key = chat.future_auth_key; + chat.key_create_date = ConnectionsManager.getInstance().getCurrentTime(); + chat.future_auth_key = old_key; + chat.future_key_fingerprint = old_fingerpring; + chat.key_use_count_in = 0; + chat.key_use_count_out = 0; + chat.exchange_id = 0; + + MessagesStorage.getInstance().updateEncryptedChat(chat); + + sendNoopMessage(chat, null); + } else { + chat.future_auth_key = new byte[256]; + chat.future_key_fingerprint = 0; + chat.exchange_id = 0; + MessagesStorage.getInstance().updateEncryptedChat(chat); + sendAbortKeyMessage(chat, null, serviceMessage.action.exchange_id); + } + } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionAbortKey) { + if (chat.exchange_id == serviceMessage.action.exchange_id) { + chat.future_auth_key = new byte[256]; + chat.future_key_fingerprint = 0; + chat.exchange_id = 0; + MessagesStorage.getInstance().updateEncryptedChat(chat); + } + } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionNoop) { + //do nothing + } else if (serviceMessage.action instanceof TLRPC.TL_decryptedMessageActionResend) { + final TLRPC.TL_encryptedChatDiscarded newChat = new TLRPC.TL_encryptedChatDiscarded(); + newChat.id = chat.id; + newChat.user_id = chat.user_id; + newChat.auth_key = chat.auth_key; + newChat.key_create_date = chat.key_create_date; + newChat.key_use_count_in = chat.key_use_count_in; + newChat.key_use_count_out = chat.key_use_count_out; + newChat.seq_in = chat.seq_in; + newChat.seq_out = chat.seq_out; + MessagesStorage.getInstance().updateEncryptedChat(newChat); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().putEncryptedChat(newChat, false); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); + } + }); + declineSecretChat(chat.id); + } else { + return null; + } + } else { + FileLog.e("tmessages", "unknown message " + object); + } + } else { + FileLog.e("tmessages", "unknown TLObject"); + } + return null; + } + + public void checkSecretHoles(TLRPC.EncryptedChat chat, ArrayList messages) { + ArrayList holes = secretHolesQueue.get(chat.id); + if (holes == null) { + return; + } + Collections.sort(holes, new Comparator() { + @Override + public int compare(TL_decryptedMessageHolder lhs, TL_decryptedMessageHolder rhs) { + if (lhs.layer.out_seq_no > rhs.layer.out_seq_no) { + return 1; + } else if (lhs.layer.out_seq_no < rhs.layer.out_seq_no) { + return -1; + } + return 0; + } + }); + + boolean update = false; + for (int a = 0; a < holes.size(); a++) { + TL_decryptedMessageHolder holder = holes.get(a); + if (holder.layer.out_seq_no == chat.seq_in || chat.seq_in == holder.layer.out_seq_no - 2) { + applyPeerLayer(chat, holder.layer.layer); + chat.seq_in = holder.layer.out_seq_no; + holes.remove(a); + a--; + update = true; + + TLRPC.Message message = processDecryptedObject(chat, holder.file, holder.date, holder.random_id, holder.layer.message, holder.new_key_used); + if (message != null) { + messages.add(message); + } + } else { + break; + } + } + if (holes.isEmpty()) { + secretHolesQueue.remove(chat.id); + } + if (update) { + MessagesStorage.getInstance().updateEncryptedChatSeq(chat); + } + } + + protected ArrayList decryptMessage(TLRPC.EncryptedMessage message) { + final TLRPC.EncryptedChat chat = MessagesController.getInstance().getEncryptedChatDB(message.chat_id); + if (chat == null || chat instanceof TLRPC.TL_encryptedChatDiscarded) { + return null; + } + + try { + NativeByteBuffer is = new NativeByteBuffer(message.bytes.length); + is.writeBytes(message.bytes); + is.position(0); + long fingerprint = is.readInt64(false); + byte[] keyToDecrypt = null; + boolean new_key_used = false; + if (chat.key_fingerprint == fingerprint) { + keyToDecrypt = chat.auth_key; + } else if (chat.future_key_fingerprint != 0 && chat.future_key_fingerprint == fingerprint) { + keyToDecrypt = chat.future_auth_key; + new_key_used = true; + } + + if (keyToDecrypt != null) { + byte[] messageKey = is.readData(16, false); + MessageKeyData keyData = MessageKeyData.generateMessageKeyData(keyToDecrypt, messageKey, false); + + Utilities.aesIgeEncryption(is.buffer, keyData.aesKey, keyData.aesIv, false, false, 24, is.limit() - 24); + + int len = is.readInt32(false); + if (len < 0 || len > is.limit() - 28) { + return null; + } + byte[] messageKeyFull = Utilities.computeSHA1(is.buffer, 24, Math.min(len + 4 + 24, is.buffer.limit())); + if (!Utilities.arraysEquals(messageKey, 0, messageKeyFull, messageKeyFull.length - 16)) { + return null; + } + + TLObject object = TLClassStore.Instance().TLdeserialize(is, is.readInt32(false), false); + + is.reuse(); + if (!new_key_used && AndroidUtilities.getPeerLayerVersion(chat.layer) >= 20) { + chat.key_use_count_in++; + } + if (object instanceof TLRPC.TL_decryptedMessageLayer) { + final TLRPC.TL_decryptedMessageLayer layer = (TLRPC.TL_decryptedMessageLayer) object; + if (chat.seq_in == 0 && chat.seq_out == 0) { + if (chat.admin_id == UserConfig.getClientUserId()) { + chat.seq_out = 1; + } else { + chat.seq_in = 1; + } + } + if (layer.random_bytes.length < 15) { + FileLog.e("tmessages", "got random bytes less than needed"); + return null; + } + FileLog.e("tmessages", "current chat in_seq = " + chat.seq_in + " out_seq = " + chat.seq_out); + FileLog.e("tmessages", "got message with in_seq = " + layer.in_seq_no + " out_seq = " + layer.out_seq_no); + if (layer.out_seq_no < chat.seq_in) { + return null; + } + if (chat.seq_in != layer.out_seq_no && chat.seq_in != layer.out_seq_no - 2) { + FileLog.e("tmessages", "got hole"); + ArrayList arr = secretHolesQueue.get(chat.id); + if (arr == null) { + arr = new ArrayList<>(); + secretHolesQueue.put(chat.id, arr); + } + if (arr.size() >= 4) { + secretHolesQueue.remove(chat.id); + final TLRPC.TL_encryptedChatDiscarded newChat = new TLRPC.TL_encryptedChatDiscarded(); + newChat.id = chat.id; + newChat.user_id = chat.user_id; + newChat.auth_key = chat.auth_key; + newChat.key_create_date = chat.key_create_date; + newChat.key_use_count_in = chat.key_use_count_in; + newChat.key_use_count_out = chat.key_use_count_out; + newChat.seq_in = chat.seq_in; + newChat.seq_out = chat.seq_out; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().putEncryptedChat(newChat, false); + MessagesStorage.getInstance().updateEncryptedChat(newChat); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); + } + }); + declineSecretChat(chat.id); + return null; + } + + TL_decryptedMessageHolder holder = new TL_decryptedMessageHolder(); + holder.layer = layer; + holder.file = message.file; + holder.random_id = message.random_id; + holder.date = message.date; + holder.new_key_used = new_key_used; + arr.add(holder); + return null; + } + applyPeerLayer(chat, layer.layer); + chat.seq_in = layer.out_seq_no; + MessagesStorage.getInstance().updateEncryptedChatSeq(chat); + object = layer.message; + } + ArrayList messages = new ArrayList<>(); + TLRPC.Message decryptedMessage = processDecryptedObject(chat, message.file, message.date, message.random_id, object, new_key_used); + if (decryptedMessage != null) { + messages.add(decryptedMessage); + } + checkSecretHoles(chat, messages); + return messages; + } else { + is.reuse(); + FileLog.e("tmessages", "fingerprint mismatch " + fingerprint); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + return null; + } + + public void requestNewSecretChatKey(final TLRPC.EncryptedChat encryptedChat) { + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) < 20) { + return; + } + final byte[] salt = new byte[256]; + Utilities.random.nextBytes(salt); + + BigInteger i_g_a = BigInteger.valueOf(MessagesStorage.secretG); + i_g_a = i_g_a.modPow(new BigInteger(1, salt), new BigInteger(1, MessagesStorage.secretPBytes)); + byte[] g_a = i_g_a.toByteArray(); + if (g_a.length > 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(g_a, 1, correctedAuth, 0, 256); + g_a = correctedAuth; + } + + encryptedChat.exchange_id = SendMessagesHelper.getInstance().getNextRandomId(); + encryptedChat.a_or_b = salt; + encryptedChat.g_a = g_a; + + MessagesStorage.getInstance().updateEncryptedChat(encryptedChat); + + sendRequestKeyMessage(encryptedChat, null); + } + + public void processAcceptedSecretChat(final TLRPC.EncryptedChat encryptedChat) { + BigInteger p = new BigInteger(1, MessagesStorage.secretPBytes); + BigInteger i_authKey = new BigInteger(1, encryptedChat.g_a_or_b); + + if (!Utilities.isGoodGaAndGb(i_authKey, p)) { + declineSecretChat(encryptedChat.id); + return; + } + + i_authKey = i_authKey.modPow(new BigInteger(1, encryptedChat.a_or_b), p); + + byte[] authKey = i_authKey.toByteArray(); + if (authKey.length > 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(authKey, authKey.length - 256, correctedAuth, 0, 256); + authKey = correctedAuth; + } else if (authKey.length < 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(authKey, 0, correctedAuth, 256 - authKey.length, authKey.length); + for (int a = 0; a < 256 - authKey.length; a++) { + authKey[a] = 0; + } + authKey = correctedAuth; + } + byte[] authKeyHash = Utilities.computeSHA1(authKey); + byte[] authKeyId = new byte[8]; + System.arraycopy(authKeyHash, authKeyHash.length - 8, authKeyId, 0, 8); + long fingerprint = Utilities.bytesToLong(authKeyId); + if (encryptedChat.key_fingerprint == fingerprint) { + encryptedChat.auth_key = authKey; + encryptedChat.key_create_date = ConnectionsManager.getInstance().getCurrentTime(); + encryptedChat.seq_in = 0; + encryptedChat.seq_out = 1; + MessagesStorage.getInstance().updateEncryptedChat(encryptedChat); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().putEncryptedChat(encryptedChat, false); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, encryptedChat); + sendNotifyLayerMessage(encryptedChat, null); + } + }); + } else { + final TLRPC.TL_encryptedChatDiscarded newChat = new TLRPC.TL_encryptedChatDiscarded(); + newChat.id = encryptedChat.id; + newChat.user_id = encryptedChat.user_id; + newChat.auth_key = encryptedChat.auth_key; + newChat.key_create_date = encryptedChat.key_create_date; + newChat.key_use_count_in = encryptedChat.key_use_count_in; + newChat.key_use_count_out = encryptedChat.key_use_count_out; + newChat.seq_in = encryptedChat.seq_in; + newChat.seq_out = encryptedChat.seq_out; + MessagesStorage.getInstance().updateEncryptedChat(newChat); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().putEncryptedChat(newChat, false); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); + } + }); + declineSecretChat(encryptedChat.id); + } + } + + public void declineSecretChat(int chat_id) { + TLRPC.TL_messages_discardEncryption req = new TLRPC.TL_messages_discardEncryption(); + req.chat_id = chat_id; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }); + } + + public void acceptSecretChat(final TLRPC.EncryptedChat encryptedChat) { + if (acceptingChats.get(encryptedChat.id) != null) { + return; + } + acceptingChats.put(encryptedChat.id, encryptedChat); + TLRPC.TL_messages_getDhConfig req = new TLRPC.TL_messages_getDhConfig(); + req.random_length = 256; + req.version = MessagesStorage.lastSecretVersion; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.messages_DhConfig res = (TLRPC.messages_DhConfig) response; + if (response instanceof TLRPC.TL_messages_dhConfig) { + if (!Utilities.isGoodPrime(res.p, res.g)) { + acceptingChats.remove(encryptedChat.id); + declineSecretChat(encryptedChat.id); + return; + } + + MessagesStorage.secretPBytes = res.p; + MessagesStorage.secretG = res.g; + MessagesStorage.lastSecretVersion = res.version; + MessagesStorage.getInstance().saveSecretParams(MessagesStorage.lastSecretVersion, MessagesStorage.secretG, MessagesStorage.secretPBytes); + } + byte[] salt = new byte[256]; + for (int a = 0; a < 256; a++) { + salt[a] = (byte) ((byte) (Utilities.random.nextDouble() * 256) ^ res.random[a]); + } + encryptedChat.a_or_b = salt; + encryptedChat.seq_in = 1; + encryptedChat.seq_out = 0; + BigInteger p = new BigInteger(1, MessagesStorage.secretPBytes); + BigInteger g_b = BigInteger.valueOf(MessagesStorage.secretG); + g_b = g_b.modPow(new BigInteger(1, salt), p); + BigInteger g_a = new BigInteger(1, encryptedChat.g_a); + + if (!Utilities.isGoodGaAndGb(g_a, p)) { + acceptingChats.remove(encryptedChat.id); + declineSecretChat(encryptedChat.id); + return; + } + + byte[] g_b_bytes = g_b.toByteArray(); + if (g_b_bytes.length > 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(g_b_bytes, 1, correctedAuth, 0, 256); + g_b_bytes = correctedAuth; + } + + g_a = g_a.modPow(new BigInteger(1, salt), p); + + byte[] authKey = g_a.toByteArray(); + if (authKey.length > 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(authKey, authKey.length - 256, correctedAuth, 0, 256); + authKey = correctedAuth; + } else if (authKey.length < 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(authKey, 0, correctedAuth, 256 - authKey.length, authKey.length); + for (int a = 0; a < 256 - authKey.length; a++) { + authKey[a] = 0; + } + authKey = correctedAuth; + } + byte[] authKeyHash = Utilities.computeSHA1(authKey); + byte[] authKeyId = new byte[8]; + System.arraycopy(authKeyHash, authKeyHash.length - 8, authKeyId, 0, 8); + encryptedChat.auth_key = authKey; + encryptedChat.key_create_date = ConnectionsManager.getInstance().getCurrentTime(); + + TLRPC.TL_messages_acceptEncryption req2 = new TLRPC.TL_messages_acceptEncryption(); + req2.g_b = g_b_bytes; + req2.peer = new TLRPC.TL_inputEncryptedChat(); + req2.peer.chat_id = encryptedChat.id; + req2.peer.access_hash = encryptedChat.access_hash; + req2.key_fingerprint = Utilities.bytesToLong(authKeyId); + ConnectionsManager.getInstance().sendRequest(req2, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + acceptingChats.remove(encryptedChat.id); + if (error == null) { + final TLRPC.EncryptedChat newChat = (TLRPC.EncryptedChat) response; + newChat.auth_key = encryptedChat.auth_key; + newChat.user_id = encryptedChat.user_id; + newChat.seq_in = encryptedChat.seq_in; + newChat.seq_out = encryptedChat.seq_out; + newChat.key_create_date = encryptedChat.key_create_date; + newChat.key_use_count_in = encryptedChat.key_use_count_in; + newChat.key_use_count_out = encryptedChat.key_use_count_out; + MessagesStorage.getInstance().updateEncryptedChat(newChat); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().putEncryptedChat(newChat, false); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatUpdated, newChat); + sendNotifyLayerMessage(newChat, null); + } + }); + } + } + }); + } else { + acceptingChats.remove(encryptedChat.id); + } + } + }); + } + + public void startSecretChat(final Context context, final TLRPC.User user) { + if (user == null || context == null) { + return; + } + startingSecretChat = true; + final ProgressDialog progressDialog = new ProgressDialog(context); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + TLRPC.TL_messages_getDhConfig req = new TLRPC.TL_messages_getDhConfig(); + req.random_length = 256; + req.version = MessagesStorage.lastSecretVersion; + final int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.messages_DhConfig res = (TLRPC.messages_DhConfig) response; + if (response instanceof TLRPC.TL_messages_dhConfig) { + if (!Utilities.isGoodPrime(res.p, res.g)) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + if (!((Activity) context).isFinishing()) { + progressDialog.dismiss(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + return; + } + MessagesStorage.secretPBytes = res.p; + MessagesStorage.secretG = res.g; + MessagesStorage.lastSecretVersion = res.version; + MessagesStorage.getInstance().saveSecretParams(MessagesStorage.lastSecretVersion, MessagesStorage.secretG, MessagesStorage.secretPBytes); + } + final byte[] salt = new byte[256]; + for (int a = 0; a < 256; a++) { + salt[a] = (byte) ((byte) (Utilities.random.nextDouble() * 256) ^ res.random[a]); + } + + BigInteger i_g_a = BigInteger.valueOf(MessagesStorage.secretG); + i_g_a = i_g_a.modPow(new BigInteger(1, salt), new BigInteger(1, MessagesStorage.secretPBytes)); + byte[] g_a = i_g_a.toByteArray(); + if (g_a.length > 256) { + byte[] correctedAuth = new byte[256]; + System.arraycopy(g_a, 1, correctedAuth, 0, 256); + g_a = correctedAuth; + } + + TLRPC.TL_messages_requestEncryption req2 = new TLRPC.TL_messages_requestEncryption(); + req2.g_a = g_a; + req2.user_id = MessagesController.getInputUser(user); + req2.random_id = Utilities.random.nextInt(); + ConnectionsManager.getInstance().sendRequest(req2, new RequestDelegate() { + @Override + public void run(final TLObject response, TLRPC.TL_error error) { + if (error == null) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + startingSecretChat = false; + if (!((Activity) context).isFinishing()) { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat) response; + chat.user_id = chat.participant_id; + chat.seq_in = 0; + chat.seq_out = 1; + chat.a_or_b = salt; + MessagesController.getInstance().putEncryptedChat(chat, false); + TLRPC.Dialog dialog = new TLRPC.TL_dialog(); + dialog.id = ((long) chat.id) << 32; + dialog.unread_count = 0; + dialog.top_message = 0; + dialog.last_message_date = ConnectionsManager.getInstance().getCurrentTime(); + MessagesController.getInstance().dialogs_dict.put(dialog.id, dialog); + MessagesController.getInstance().dialogs.add(dialog); + Collections.sort(MessagesController.getInstance().dialogs, new Comparator() { + @Override + public int compare(TLRPC.Dialog tl_dialog, TLRPC.Dialog tl_dialog2) { + if (tl_dialog.last_message_date == tl_dialog2.last_message_date) { + return 0; + } else if (tl_dialog.last_message_date < tl_dialog2.last_message_date) { + return 1; + } else { + return -1; + } + } + }); + MessagesStorage.getInstance().putEncryptedChat(chat, user, dialog); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.encryptedChatCreated, chat); + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (!delayedEncryptedChatUpdates.isEmpty()) { + MessagesController.getInstance().processUpdateArray(delayedEncryptedChatUpdates, null, null); + delayedEncryptedChatUpdates.clear(); + } + } + }); + } + }); + } else { + delayedEncryptedChatUpdates.clear(); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (!((Activity) context).isFinishing()) { + startingSecretChat = false; + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("CreateEncryptedChatError", R.string.CreateEncryptedChatError)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + builder.show().setCanceledOnTouchOutside(true); + } + } + }); + } + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + } else { + delayedEncryptedChatUpdates.clear(); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + startingSecretChat = false; + if (!((Activity) context).isFinishing()) { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + }); + } + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + ConnectionsManager.getInstance().cancelRequest(reqId, true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + try { + progressDialog.show(); + } catch (Exception e) { + //don't promt + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java new file mode 100644 index 00000000..a916fee3 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SendMessagesHelper.java @@ -0,0 +1,3486 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.media.MediaMetadataRetriever; +import android.media.MediaPlayer; +import android.media.ThumbnailUtils; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.provider.MediaStore; +import android.webkit.MimeTypeMap; +import android.widget.Toast; + +import org.telegram.messenger.audioinfo.AudioInfo; +import org.telegram.messenger.query.StickersQuery; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.QuickAckDelegate; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ChatActivity; + +import java.io.File; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.ArrayList; +import java.util.HashMap; + +public class SendMessagesHelper implements NotificationCenter.NotificationCenterDelegate { + + private TLRPC.ChatFull currentChatInfo = null; + private HashMap> delayedMessages = new HashMap<>(); + private HashMap unsentMessages = new HashMap<>(); + private HashMap sendingMessages = new HashMap<>(); + private HashMap waitingForLocation = new HashMap<>(); + private HashMap waitingForCallback = new HashMap<>(); + + private LocationProvider locationProvider = new LocationProvider(new LocationProvider.LocationProviderDelegate() { + @Override + public void onLocationAcquired(Location location) { + sendLocation(location); + waitingForLocation.clear(); + } + + @Override + public void onUnableLocationAcquire() { + HashMap waitingForLocationCopy = new HashMap<>(waitingForLocation); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.wasUnableToFindCurrentLocation, waitingForLocationCopy); + waitingForLocation.clear(); + } + }); + + public static class LocationProvider { + + public interface LocationProviderDelegate { + void onLocationAcquired(Location location); + void onUnableLocationAcquire(); + } + + private LocationProviderDelegate delegate; + private LocationManager locationManager; + private GpsLocationListener gpsLocationListener = new GpsLocationListener(); + private GpsLocationListener networkLocationListener = new GpsLocationListener(); + private Runnable locationQueryCancelRunnable; + private Location lastKnownLocation; + + private class GpsLocationListener implements LocationListener { + + @Override + public void onLocationChanged(Location location) { + if (location == null || locationQueryCancelRunnable == null) { + return; + } + FileLog.e("tmessages", "found location " + location); + lastKnownLocation = location; + if (location.getAccuracy() < 100) { + if (delegate != null) { + delegate.onLocationAcquired(location); + } + if (locationQueryCancelRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(locationQueryCancelRunnable); + } + cleanup(); + } + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + + } + + @Override + public void onProviderEnabled(String provider) { + + } + + @Override + public void onProviderDisabled(String provider) { + + } + } + + public LocationProvider() { + + } + + public LocationProvider(LocationProviderDelegate locationProviderDelegate) { + delegate = locationProviderDelegate; + } + + public void setDelegate(LocationProviderDelegate locationProviderDelegate) { + delegate = locationProviderDelegate; + } + + private void cleanup() { + locationManager.removeUpdates(gpsLocationListener); + locationManager.removeUpdates(networkLocationListener); + lastKnownLocation = null; + locationQueryCancelRunnable = null; + } + + public void start() { + if (locationManager == null) { + locationManager = (LocationManager) ApplicationLoader.applicationContext.getSystemService(Context.LOCATION_SERVICE); + } + try { + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1, 0, gpsLocationListener); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 0, networkLocationListener); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER); + if (lastKnownLocation == null) { + lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (locationQueryCancelRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(locationQueryCancelRunnable); + } + locationQueryCancelRunnable = new Runnable() { + @Override + public void run() { + if (locationQueryCancelRunnable != this) { + return; + } + if (delegate != null) { + if (lastKnownLocation != null) { + delegate.onLocationAcquired(lastKnownLocation); + } else { + delegate.onUnableLocationAcquire(); + } + } + cleanup(); + } + }; + AndroidUtilities.runOnUIThread(locationQueryCancelRunnable, 5000); + } + + public void stop() { + if (locationManager == null) { + return; + } + if (locationQueryCancelRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(locationQueryCancelRunnable); + + } + cleanup(); + } + } + + protected class DelayedMessage { + public TLObject sendRequest; + public TLRPC.TL_decryptedMessage sendEncryptedRequest; + public int type; + public String originalPath; + public TLRPC.FileLocation location; + public TLRPC.TL_document documentLocation; + public String httpLocation; + public MessageObject obj; + public TLRPC.EncryptedChat encryptedChat; + public VideoEditedInfo videoEditedInfo; + } + + private static volatile SendMessagesHelper Instance = null; + + public static SendMessagesHelper getInstance() { + SendMessagesHelper localInstance = Instance; + if (localInstance == null) { + synchronized (SendMessagesHelper.class) { + localInstance = Instance; + if (localInstance == null) { + Instance = localInstance = new SendMessagesHelper(); + } + } + } + return localInstance; + } + + public SendMessagesHelper() { + NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidUpload); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidFailUpload); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.FilePreparingStarted); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileNewChunkAvailable); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.FilePreparingFailed); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.httpFileDidFailedLoad); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.httpFileDidLoaded); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidLoaded); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidFailedLoad); + } + + public void cleanUp() { + delayedMessages.clear(); + unsentMessages.clear(); + sendingMessages.clear(); + waitingForLocation.clear(); + waitingForCallback.clear(); + currentChatInfo = null; + locationProvider.stop(); + } + + public void setCurrentChatInfo(TLRPC.ChatFull info) { + currentChatInfo = info; + } + + @Override + public void didReceivedNotification(int id, final Object... args) { + if (id == NotificationCenter.FileDidUpload) { + final String location = (String) args[0]; + final TLRPC.InputFile file = (TLRPC.InputFile) args[1]; + final TLRPC.InputEncryptedFile encryptedFile = (TLRPC.InputEncryptedFile) args[2]; + ArrayList arr = delayedMessages.get(location); + if (arr != null) { + for (int a = 0; a < arr.size(); a++) { + DelayedMessage message = arr.get(a); + TLRPC.InputMedia media = null; + if (message.sendRequest instanceof TLRPC.TL_messages_sendMedia) { + media = ((TLRPC.TL_messages_sendMedia) message.sendRequest).media; + } else if (message.sendRequest instanceof TLRPC.TL_messages_sendBroadcast) { + media = ((TLRPC.TL_messages_sendBroadcast) message.sendRequest).media; + } + + if (file != null && media != null) { + if (message.type == 0) { + media.file = file; + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + } else if (message.type == 1) { + if (media.file == null) { + media.file = file; + if (media.thumb == null && message.location != null) { + performSendDelayedMessage(message); + } else { + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + } + } else { + media.thumb = file; + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + } + } else if (message.type == 2) { + if (media.file == null) { + media.file = file; + if (media.thumb == null && message.location != null) { + performSendDelayedMessage(message); + } else { + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + } + } else { + media.thumb = file; + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + } + } else if (message.type == 3) { + media.file = file; + performSendMessageRequest(message.sendRequest, message.obj, message.originalPath); + } + arr.remove(a); + a--; + } else if (encryptedFile != null && message.sendEncryptedRequest != null) { + if (message.sendEncryptedRequest.media instanceof TLRPC.TL_decryptedMessageMediaVideo || message.sendEncryptedRequest.media instanceof TLRPC.TL_decryptedMessageMediaPhoto) { + long size = (Long) args[5]; + message.sendEncryptedRequest.media.size = (int) size; + } + message.sendEncryptedRequest.media.key = (byte[]) args[3]; + message.sendEncryptedRequest.media.iv = (byte[]) args[4]; + SecretChatHelper.getInstance().performSendEncryptedRequest(message.sendEncryptedRequest, message.obj.messageOwner, message.encryptedChat, encryptedFile, message.originalPath); + arr.remove(a); + a--; + } + } + if (arr.isEmpty()) { + delayedMessages.remove(location); + } + } + } else if (id == NotificationCenter.FileDidFailUpload) { + final String location = (String) args[0]; + final boolean enc = (Boolean) args[1]; + ArrayList arr = delayedMessages.get(location); + if (arr != null) { + for (int a = 0; a < arr.size(); a++) { + DelayedMessage obj = arr.get(a); + if (enc && obj.sendEncryptedRequest != null || !enc && obj.sendRequest != null) { + MessagesStorage.getInstance().markMessageAsSendError(obj.obj.messageOwner); + obj.obj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + arr.remove(a); + a--; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, obj.obj.getId()); + processSentMessage(obj.obj.getId()); + } + } + if (arr.isEmpty()) { + delayedMessages.remove(location); + } + } + } else if (id == NotificationCenter.FilePreparingStarted) { + MessageObject messageObject = (MessageObject) args[0]; + String finalPath = (String) args[1]; + + ArrayList arr = delayedMessages.get(messageObject.messageOwner.attachPath); + if (arr != null) { + for (int a = 0; a < arr.size(); a++) { + DelayedMessage message = arr.get(a); + if (message.obj == messageObject) { + message.videoEditedInfo = null; + performSendDelayedMessage(message); + arr.remove(a); + break; + } + } + if (arr.isEmpty()) { + delayedMessages.remove(messageObject.messageOwner.attachPath); + } + } + } else if (id == NotificationCenter.FileNewChunkAvailable) { + MessageObject messageObject = (MessageObject) args[0]; + String finalPath = (String) args[1]; + long finalSize = (Long) args[2]; + boolean isEncrypted = ((int) messageObject.getDialogId()) == 0; + FileLoader.getInstance().checkUploadNewDataAvailable(finalPath, isEncrypted, finalSize); + if (finalSize != 0) { + ArrayList arr = delayedMessages.get(messageObject.messageOwner.attachPath); + if (arr != null) { + for (int a = 0; a < arr.size(); a++) { + DelayedMessage message = arr.get(a); + if (message.obj == messageObject) { + message.obj.videoEditedInfo = null; + message.obj.messageOwner.message = "-1"; + message.obj.messageOwner.media.document.size = (int) finalSize; + + ArrayList messages = new ArrayList<>(); + messages.add(message.obj.messageOwner); + MessagesStorage.getInstance().putMessages(messages, false, true, false, 0); + break; + } + } + if (arr.isEmpty()) { + delayedMessages.remove(messageObject.messageOwner.attachPath); + } + } + } + } else if (id == NotificationCenter.FilePreparingFailed) { + MessageObject messageObject = (MessageObject) args[0]; + String finalPath = (String) args[1]; + stopVideoService(messageObject.messageOwner.attachPath); + + ArrayList arr = delayedMessages.get(finalPath); + if (arr != null) { + for (int a = 0; a < arr.size(); a++) { + DelayedMessage message = arr.get(a); + if (message.obj == messageObject) { + MessagesStorage.getInstance().markMessageAsSendError(message.obj.messageOwner); + message.obj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + arr.remove(a); + a--; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, message.obj.getId()); + processSentMessage(message.obj.getId()); + } + } + if (arr.isEmpty()) { + delayedMessages.remove(finalPath); + } + } + } else if (id == NotificationCenter.httpFileDidLoaded) { + String path = (String) args[0]; + ArrayList arr = delayedMessages.get(path); + if (arr != null) { + for (int a = 0; a < arr.size(); a++) { + final DelayedMessage message = arr.get(a); + if (message.type == 0) { + String md5 = Utilities.MD5(message.httpLocation) + "." + ImageLoader.getHttpUrlExtension(message.httpLocation, "file"); + final File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + final TLRPC.TL_photo photo = SendMessagesHelper.getInstance().generatePhotoSizes(cacheFile.toString(), null); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (photo != null) { + message.httpLocation = null; + message.obj.messageOwner.media.photo = photo; + message.obj.messageOwner.attachPath = cacheFile.toString(); + message.location = photo.sizes.get(photo.sizes.size() - 1).location; + ArrayList messages = new ArrayList<>(); + messages.add(message.obj.messageOwner); + MessagesStorage.getInstance().putMessages(messages, false, true, false, 0); + performSendDelayedMessage(message); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateMessageMedia, message.obj); + } else { + FileLog.e("tmessages", "can't load image " + message.httpLocation + " to file " + cacheFile.toString()); + MessagesStorage.getInstance().markMessageAsSendError(message.obj.messageOwner); + message.obj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, message.obj.getId()); + processSentMessage(message.obj.getId()); + } + } + }); + } + }); + } else if (message.type == 2) { + String md5 = Utilities.MD5(message.httpLocation) + ".gif"; + final File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (message.documentLocation.thumb.location instanceof TLRPC.TL_fileLocationUnavailable) { + try { + Bitmap bitmap = ImageLoader.loadBitmap(cacheFile.getAbsolutePath(), null, 90, 90, true); + if (bitmap != null) { + message.documentLocation.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, message.sendEncryptedRequest != null); + bitmap.recycle(); + } + } catch (Exception e) { + message.documentLocation.thumb = null; + FileLog.e("tmessages", e); + } + if (message.documentLocation.thumb == null) { + message.documentLocation.thumb = new TLRPC.TL_photoSizeEmpty(); + message.documentLocation.thumb.type = "s"; + } + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + message.httpLocation = null; + message.obj.messageOwner.attachPath = cacheFile.toString(); + message.location = message.documentLocation.thumb.location; + ArrayList messages = new ArrayList<>(); + messages.add(message.obj.messageOwner); + MessagesStorage.getInstance().putMessages(messages, false, true, false, 0); + performSendDelayedMessage(message); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateMessageMedia, message.obj); + } + }); + } + }); + } + } + delayedMessages.remove(path); + } + } else if (id == NotificationCenter.FileDidLoaded) { + String path = (String) args[0]; + ArrayList arr = delayedMessages.get(path); + if (arr != null) { + for (int a = 0; a < arr.size(); a++) { + performSendDelayedMessage(arr.get(a)); + } + delayedMessages.remove(path); + } + } else if (id == NotificationCenter.httpFileDidFailedLoad || id == NotificationCenter.FileDidFailedLoad) { + String path = (String) args[0]; + + ArrayList arr = delayedMessages.get(path); + if (arr != null) { + for (DelayedMessage message : arr) { + MessagesStorage.getInstance().markMessageAsSendError(message.obj.messageOwner); + message.obj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, message.obj.getId()); + processSentMessage(message.obj.getId()); + } + delayedMessages.remove(path); + } + } + } + + public void cancelSendingMessage(MessageObject object) { + String keyToRemvoe = null; + boolean enc = false; + for (HashMap.Entry> entry : delayedMessages.entrySet()) { + ArrayList messages = entry.getValue(); + for (int a = 0; a < messages.size(); a++) { + DelayedMessage message = messages.get(a); + if (message.obj.getId() == object.getId()) { + messages.remove(a); + MediaController.getInstance().cancelVideoConvert(message.obj); + if (messages.size() == 0) { + keyToRemvoe = entry.getKey(); + if (message.sendEncryptedRequest != null) { + enc = true; + } + } + break; + } + } + } + if (keyToRemvoe != null) { + if (keyToRemvoe.startsWith("http")) { + ImageLoader.getInstance().cancelLoadHttpFile(keyToRemvoe); + } else { + FileLoader.getInstance().cancelUploadFile(keyToRemvoe, enc); + } + stopVideoService(keyToRemvoe); + } + ArrayList messages = new ArrayList<>(); + messages.add(object.getId()); + MessagesController.getInstance().deleteMessages(messages, null, null, object.messageOwner.to_id.channel_id); + } + + public boolean retrySendMessage(MessageObject messageObject, boolean unsent) { + if (messageObject.getId() >= 0) { + return false; + } + if (messageObject.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction) { + int enc_id = (int) (messageObject.getDialogId() >> 32); + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(enc_id); + if (encryptedChat == null) { + MessagesStorage.getInstance().markMessageAsSendError(messageObject.messageOwner); + messageObject.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, messageObject.getId()); + processSentMessage(messageObject.getId()); + return false; + } + if (messageObject.messageOwner.random_id == 0) { + messageObject.messageOwner.random_id = getNextRandomId(); + } + if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { + SecretChatHelper.getInstance().sendTTLMessage(encryptedChat, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionDeleteMessages) { + SecretChatHelper.getInstance().sendMessagesDeleteMessage(encryptedChat, null, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionFlushHistory) { + SecretChatHelper.getInstance().sendClearHistoryMessage(encryptedChat, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionNotifyLayer) { + SecretChatHelper.getInstance().sendNotifyLayerMessage(encryptedChat, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionReadMessages) { + SecretChatHelper.getInstance().sendMessagesReadMessage(encryptedChat, null, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionScreenshotMessages) { + SecretChatHelper.getInstance().sendScreenshotMessage(encryptedChat, null, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionTyping) { + + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionResend) { + + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionCommitKey) { + SecretChatHelper.getInstance().sendCommitKeyMessage(encryptedChat, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionAbortKey) { + SecretChatHelper.getInstance().sendAbortKeyMessage(encryptedChat, messageObject.messageOwner, 0); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionRequestKey) { + SecretChatHelper.getInstance().sendRequestKeyMessage(encryptedChat, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionAcceptKey) { + SecretChatHelper.getInstance().sendAcceptKeyMessage(encryptedChat, messageObject.messageOwner); + } else if (messageObject.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionNoop) { + SecretChatHelper.getInstance().sendNoopMessage(encryptedChat, messageObject.messageOwner); + } + return true; + } + if (unsent) { + unsentMessages.put(messageObject.getId(), messageObject); + } + sendMessage(messageObject, messageObject.messageOwner.post); + return true; + } + + protected void processSentMessage(int id) { + int prevSize = unsentMessages.size(); + unsentMessages.remove(id); + if (prevSize != 0 && unsentMessages.size() == 0) { + checkUnsentMessages(); + } + } + + public void processForwardFromMyName(MessageObject messageObject, long did, boolean asAdmin) { + if (messageObject == null) { + return; + } + if (messageObject.messageOwner.media != null && !(messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaEmpty) && !(messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage)) { + if (messageObject.messageOwner.media.photo instanceof TLRPC.TL_photo) { + sendMessage((TLRPC.TL_photo) messageObject.messageOwner.media.photo, null, did, messageObject.replyMessageObject, asAdmin, null, null); + } else if (messageObject.messageOwner.media.document instanceof TLRPC.TL_document) { + sendMessage((TLRPC.TL_document) messageObject.messageOwner.media.document, null, messageObject.messageOwner.attachPath, did, messageObject.replyMessageObject, asAdmin, null, null); + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVenue || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaGeo) { + sendMessage(messageObject.messageOwner.media, did, messageObject.replyMessageObject, asAdmin, null, null); + } else if (messageObject.messageOwner.media.phone_number != null) { + TLRPC.User user = new TLRPC.TL_userContact_old2(); + user.phone = messageObject.messageOwner.media.phone_number; + user.first_name = messageObject.messageOwner.media.first_name; + user.last_name = messageObject.messageOwner.media.last_name; + user.id = messageObject.messageOwner.media.user_id; + sendMessage(user, did, messageObject.replyMessageObject, asAdmin, null, null); + } else { + ArrayList arrayList = new ArrayList<>(); + arrayList.add(messageObject); + sendMessage(arrayList, did, asAdmin); + } + } else if (messageObject.messageOwner.message != null) { + TLRPC.WebPage webPage = null; + if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { + webPage = messageObject.messageOwner.media.webpage; + } + sendMessage(messageObject.messageOwner.message, did, messageObject.replyMessageObject, webPage, true, asAdmin, messageObject.messageOwner.entities, null, null); + } else { + ArrayList arrayList = new ArrayList<>(); + arrayList.add(messageObject); + sendMessage(arrayList, did, asAdmin); + } + } + + public void sendSticker(TLRPC.Document document, long peer, MessageObject replyingMessageObject, boolean asAdmin) { + if (document == null) { + return; + } + if ((int) peer == 0) { + int high_id = (int) (peer >> 32); + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(high_id); + if (encryptedChat == null) { + return; + } + if (document.thumb instanceof TLRPC.TL_photoSize) { + File file = FileLoader.getPathToAttach(document.thumb, true); + if (file.exists()) { + try { + int len = (int) file.length(); + byte[] arr = new byte[(int) file.length()]; + RandomAccessFile reader = new RandomAccessFile(file, "r"); + reader.readFully(arr); + TLRPC.TL_document newDocument = new TLRPC.TL_document(); + newDocument.thumb = new TLRPC.TL_photoCachedSize(); + newDocument.thumb.location = document.thumb.location; + newDocument.thumb.size = document.thumb.size; + newDocument.thumb.w = document.thumb.w; + newDocument.thumb.h = document.thumb.h; + newDocument.thumb.type = document.thumb.type; + newDocument.thumb.bytes = arr; + + newDocument.id = document.id; + newDocument.access_hash = document.access_hash; + newDocument.date = document.date; + newDocument.mime_type = document.mime_type; + newDocument.size = document.size; + newDocument.dc_id = document.dc_id; + newDocument.attributes = document.attributes; + if (newDocument.mime_type == null) { + newDocument.mime_type = ""; + } + document = newDocument; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + } + SendMessagesHelper.getInstance().sendMessage((TLRPC.TL_document) document, null, null, peer, replyingMessageObject, asAdmin, null, null); + } + + public void sendMessage(ArrayList messages, final long peer, boolean asAdmin) { + if ((int) peer == 0 || messages == null || messages.isEmpty()) { + return; + } + int lower_id = (int) peer; + final TLRPC.Peer to_id = MessagesController.getPeer((int) peer); + boolean isMegagroup = false; + boolean isSignature = false; + if (lower_id > 0) { + TLRPC.User sendToUser = MessagesController.getInstance().getUser(lower_id); + if (sendToUser == null) { + return; + } + } else { + TLRPC.Chat chat = MessagesController.getInstance().getChat(-lower_id); + if (ChatObject.isChannel(chat)) { + isMegagroup = chat.megagroup; + isSignature = chat.signatures; + } + } + + ArrayList objArr = new ArrayList<>(); + ArrayList arr = new ArrayList<>(); + ArrayList randomIds = new ArrayList<>(); + ArrayList ids = new ArrayList<>(); + HashMap messagesByRandomIds = new HashMap<>(); + TLRPC.InputPeer inputPeer = MessagesController.getInputPeer(lower_id); + long lastDialogId = 0; + for (int a = 0; a < messages.size(); a++) { + MessageObject msgObj = messages.get(a); + if (msgObj.getId() <= 0) { + continue; + } + + final TLRPC.Message newMsg = new TLRPC.TL_message(); + if (msgObj.isForwarded()) { + newMsg.fwd_from = msgObj.messageOwner.fwd_from; + } else { + newMsg.fwd_from = new TLRPC.TL_messageFwdHeader(); + if (msgObj.isFromUser()) { + newMsg.fwd_from.from_id = msgObj.messageOwner.from_id; + newMsg.fwd_from.flags |= 1; + } else { + newMsg.fwd_from.channel_id = msgObj.messageOwner.to_id.channel_id; + newMsg.fwd_from.flags |= 2; + if (msgObj.messageOwner.post) { + newMsg.fwd_from.channel_post = msgObj.getId(); + newMsg.fwd_from.flags |= 4; + if (msgObj.messageOwner.from_id > 0) { + newMsg.fwd_from.from_id = msgObj.messageOwner.from_id; + newMsg.fwd_from.flags |= 1; + } + } + } + newMsg.date = msgObj.messageOwner.date; + } + newMsg.media = msgObj.messageOwner.media; + newMsg.flags = TLRPC.MESSAGE_FLAG_FWD; + if (newMsg.media != null) { + newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; + } + if (isMegagroup) { + newMsg.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + if (msgObj.messageOwner.via_bot_id != 0) { + newMsg.via_bot_id = msgObj.messageOwner.via_bot_id; + newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_BOT_ID; + } + newMsg.message = msgObj.messageOwner.message; + newMsg.fwd_msg_id = msgObj.getId(); + newMsg.attachPath = msgObj.messageOwner.attachPath; + newMsg.entities = msgObj.messageOwner.entities; + if (!newMsg.entities.isEmpty()) { + newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_ENTITIES; + } + if (newMsg.attachPath == null) { + newMsg.attachPath = ""; + } + newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); + newMsg.out = true; + if (asAdmin && to_id.channel_id != 0 && !isMegagroup) { + newMsg.from_id = isSignature ? UserConfig.getClientUserId() : -to_id.channel_id; + newMsg.post = true; + } else { + newMsg.from_id = UserConfig.getClientUserId(); + newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + } + if (newMsg.random_id == 0) { + newMsg.random_id = getNextRandomId(); + } + randomIds.add(newMsg.random_id); + messagesByRandomIds.put(newMsg.random_id, newMsg); + ids.add(newMsg.fwd_msg_id); + newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); + if (inputPeer instanceof TLRPC.TL_inputPeerChannel) { + if (asAdmin && !isMegagroup) { + newMsg.views = 1; + newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_VIEWS; + } + } else { + if ((msgObj.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { + newMsg.views = msgObj.messageOwner.views; + newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_VIEWS; + } + newMsg.unread = true; + } + newMsg.dialog_id = peer; + newMsg.to_id = to_id; + if (MessageObject.isVoiceMessage(newMsg) && newMsg.to_id.channel_id == 0) { + newMsg.media_unread = true; + } + if (msgObj.messageOwner.to_id instanceof TLRPC.TL_peerChannel) { + newMsg.ttl = -msgObj.messageOwner.to_id.channel_id; + } + MessageObject newMsgObj = new MessageObject(newMsg, null, true); + newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING; + objArr.add(newMsgObj); + arr.add(newMsg); + + putToSendingMessages(newMsg); + boolean differentDialog = false; + + if (BuildVars.DEBUG_VERSION) { + FileLog.e("tmessages", "forward message user_id = " + inputPeer.user_id + " chat_id = " + inputPeer.chat_id + " channel_id = " + inputPeer.channel_id + " access_hash = " + inputPeer.access_hash); + } + + if (arr.size() == 100 || a == messages.size() - 1 || a != messages.size() - 1 && messages.get(a + 1).getDialogId() != msgObj.getDialogId()) { + MessagesStorage.getInstance().putMessages(new ArrayList<>(arr), false, true, false, 0); + MessagesController.getInstance().updateInterfaceWithMessages(peer, objArr); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + UserConfig.saveConfig(false); + + TLRPC.TL_messages_forwardMessages req = new TLRPC.TL_messages_forwardMessages(); + req.to_peer = inputPeer; + if (req.to_peer instanceof TLRPC.TL_inputPeerChannel) { + req.silent = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).getBoolean("silent_" + peer, false); + } + if (msgObj.messageOwner.to_id instanceof TLRPC.TL_peerChannel) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(msgObj.messageOwner.to_id.channel_id); + req.from_peer = new TLRPC.TL_inputPeerChannel(); + req.from_peer.channel_id = msgObj.messageOwner.to_id.channel_id; + if (chat != null) { + req.from_peer.access_hash = chat.access_hash; + } + } else { + req.from_peer = new TLRPC.TL_inputPeerEmpty(); + } + req.random_id = randomIds; + req.id = ids; + + if (asAdmin && req.to_peer.channel_id != 0 && !isMegagroup) { + req.broadcast = true; + } + + final ArrayList newMsgObjArr = arr; + final ArrayList newMsgArr = objArr; + final HashMap messagesByRandomIdsFinal = messagesByRandomIds; + final boolean isMegagroupFinal = isMegagroup; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, final TLRPC.TL_error error) { + if (error == null) { + HashMap newMessagesByIds = new HashMap<>(); + TLRPC.Updates updates = (TLRPC.Updates) response; + for (int a = 0; a < updates.updates.size(); a++) { + TLRPC.Update update = updates.updates.get(a); + if (update instanceof TLRPC.TL_updateMessageID) { + TLRPC.TL_updateMessageID updateMessageID = (TLRPC.TL_updateMessageID) update; + newMessagesByIds.put(updateMessageID.id, updateMessageID.random_id); + updates.updates.remove(a); + a--; + } + } + for (int a = 0; a < updates.updates.size(); a++) { + TLRPC.Update update = updates.updates.get(a); + if (update instanceof TLRPC.TL_updateNewMessage || update instanceof TLRPC.TL_updateNewChannelMessage) { + TLRPC.Message message; + if (update instanceof TLRPC.TL_updateNewMessage) { + message = ((TLRPC.TL_updateNewMessage) update).message; + MessagesController.getInstance().processNewDifferenceParams(-1, update.pts, -1, update.pts_count); + } else { + message = ((TLRPC.TL_updateNewChannelMessage) update).message; + MessagesController.getInstance().processNewChannelDifferenceParams(update.pts, update.pts_count, message.to_id.channel_id); + if (isMegagroupFinal) { + message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + } + Long random_id = newMessagesByIds.get(message.id); + if (random_id != null) { + final TLRPC.Message newMsgObj = messagesByRandomIdsFinal.get(random_id); + if (newMsgObj == null) { + continue; + } + MessageObject msgObj = newMsgArr.get(newMsgObjArr.indexOf(newMsgObj)); + newMsgObjArr.remove(newMsgObj); + final int oldId = newMsgObj.id; + final ArrayList sentMessages = new ArrayList<>(); + sentMessages.add(message); + newMsgObj.id = message.id; + updateMediaPaths(msgObj, message, null, true); + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.random_id, oldId, newMsgObj.id, 0, false, to_id.channel_id); + MessagesStorage.getInstance().putMessages(sentMessages, true, false, false, 0); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, newMsgObj.id, newMsgObj, peer); + processSentMessage(oldId); + removeFromSendingMessages(oldId); + } + }); + if (MessageObject.isVideoMessage(newMsgObj)) { + stopVideoService(newMsgObj.attachPath); + } + } + }); + } + } + } + } else { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (error.text.equals("PEER_FLOOD")) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.needShowAlert, 0); + } + } + }); + } + for (int a = 0; a < newMsgObjArr.size(); a++) { + final TLRPC.Message newMsgObj = newMsgObjArr.get(a); + MessagesStorage.getInstance().markMessageAsSendError(newMsgObj); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); + processSentMessage(newMsgObj.id); + if (MessageObject.isVideoMessage(newMsgObj)) { + stopVideoService(newMsgObj.attachPath); + } + removeFromSendingMessages(newMsgObj.id); + } + }); + } + } + }, ConnectionsManager.RequestFlagCanCompress | ConnectionsManager.RequestFlagInvokeAfter); + + if (a != messages.size() - 1) { + objArr = new ArrayList<>(); + arr = new ArrayList<>(); + randomIds = new ArrayList<>(); + ids = new ArrayList<>(); + messagesByRandomIds = new HashMap<>(); + } + } + } + } + + public void editMessage(MessageObject messageObject, String message, boolean searchLinks, final BaseFragment fragment) { + if (fragment == null || fragment.getParentActivity() == null) { + return; + } + final ProgressDialog progressDialog = new ProgressDialog(fragment.getParentActivity()); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + + TLRPC.TL_messages_editMessage req = new TLRPC.TL_messages_editMessage(); + req.peer = MessagesController.getInputPeer((int) messageObject.getDialogId()); + req.message = message; + req.flags |= 2048; + req.id = messageObject.getId(); + req.no_webpage = !searchLinks; + final int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + if (!fragment.getParentActivity().isFinishing()) { + progressDialog.dismiss(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + if (error == null) { + MessagesController.getInstance().processUpdates((TLRPC.Updates) response, false); + } else { + if (!error.text.equals("MESSAGE_NOT_MODIFIED")) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("EditMessageError", R.string.EditMessageError)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + fragment.showDialog(builder.create()); + } + }); + } + } + } + }); + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + ConnectionsManager.getInstance().cancelRequest(reqId, true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + try { + progressDialog.show(); + } catch (Exception e) { + //don't promt + } + } + + private void sendLocation(Location location) { + TLRPC.TL_messageMediaGeo mediaGeo = new TLRPC.TL_messageMediaGeo(); + mediaGeo.geo = new TLRPC.TL_geoPoint(); + mediaGeo.geo.lat = location.getLatitude(); + mediaGeo.geo._long = location.getLongitude(); + for (HashMap.Entry entry : waitingForLocation.entrySet()) { + MessageObject messageObject = entry.getValue(); + SendMessagesHelper.getInstance().sendMessage(mediaGeo, messageObject.getDialogId(), messageObject, false, null, null); + } + } + + public void sendCurrentLocation(final MessageObject messageObject, final TLRPC.KeyboardButton button) { + final String key = messageObject.getId() + "_" + Utilities.bytesToHex(button.data); + waitingForLocation.put(key, messageObject); + locationProvider.start(); + } + + public boolean isSendingCurrentLocation(MessageObject messageObject, TLRPC.KeyboardButton button) { + return !(messageObject == null || button == null) && waitingForLocation.containsKey(messageObject.getId() + "_" + Utilities.bytesToHex(button.data)); + } + + public void sendCallback(final MessageObject messageObject, final TLRPC.KeyboardButton button, final ChatActivity parentFragment) { + if (messageObject == null || button == null || parentFragment == null) { + return; + } + final String key = messageObject.getId() + "_" + Utilities.bytesToHex(button.data); + waitingForCallback.put(key, messageObject); + TLRPC.TL_messages_getBotCallbackAnswer req = new TLRPC.TL_messages_getBotCallbackAnswer(); + req.peer = MessagesController.getInputPeer((int) messageObject.getDialogId()); + req.msg_id = messageObject.getId(); + req.data = button.data; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (response != null) { + TLRPC.TL_messages_botCallbackAnswer res = (TLRPC.TL_messages_botCallbackAnswer) response; + if (res.message != null) { + if (res.alert) { + if (parentFragment.getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(parentFragment.getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + builder.setMessage(res.message); + parentFragment.showDialog(builder.create()); + } else { + int uid = messageObject.messageOwner.from_id; + if (messageObject.messageOwner.via_bot_id != 0) { + uid = messageObject.messageOwner.via_bot_id; + } + TLRPC.User user = MessagesController.getInstance().getUser(uid); + if (user == null) { + return; + } + parentFragment.showAlert(user, res.message); + } + } + } + waitingForCallback.remove(key); + } + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + } + + public boolean isSendingCallback(MessageObject messageObject, TLRPC.KeyboardButton button) { + return !(messageObject == null || button == null) && waitingForCallback.containsKey(messageObject.getId() + "_" + Utilities.bytesToHex(button.data)); + } + + public void sendMessage(MessageObject retryMessageObject, boolean asAdmin) { + sendMessage(null, null, null, null, null, null, retryMessageObject.getDialogId(), retryMessageObject.messageOwner.attachPath, null, null, true, asAdmin, retryMessageObject, null, retryMessageObject.messageOwner.reply_markup, retryMessageObject.messageOwner.params); + } + + public void sendMessage(TLRPC.User user, long peer, MessageObject reply_to_msg, boolean asAdmin, TLRPC.ReplyMarkup replyMarkup, HashMap params) { + sendMessage(null, null, null, null, user, null, peer, null, reply_to_msg, null, true, asAdmin, null, null, replyMarkup, params); + } + + public void sendMessage(TLRPC.TL_document document, VideoEditedInfo videoEditedInfo, String path, long peer, MessageObject reply_to_msg, boolean asAdmin, TLRPC.ReplyMarkup replyMarkup, HashMap params) { + sendMessage(null, null, null, videoEditedInfo, null, document, peer, path, reply_to_msg, null, true, asAdmin, null, null, replyMarkup, params); + } + + public void sendMessage(String message, long peer, MessageObject reply_to_msg, TLRPC.WebPage webPage, boolean searchLinks, boolean asAdmin, ArrayList entities, TLRPC.ReplyMarkup replyMarkup, HashMap params) { + sendMessage(message, null, null, null, null, null, peer, null, reply_to_msg, webPage, searchLinks, asAdmin, null, entities, replyMarkup, params); + } + + public void sendMessage(TLRPC.MessageMedia location, long peer, MessageObject reply_to_msg, boolean asAdmin, TLRPC.ReplyMarkup replyMarkup, HashMap params) { + sendMessage(null, location, null, null, null, null, peer, null, reply_to_msg, null, true, asAdmin, null, null, replyMarkup, params); + } + + public void sendMessage(TLRPC.TL_photo photo, String path, long peer, MessageObject reply_to_msg, boolean asAdmin, TLRPC.ReplyMarkup replyMarkup, HashMap params) { + sendMessage(null, null, photo, null, null, null, peer, path, reply_to_msg, null, true, asAdmin, null, null, replyMarkup, params); + } + + private void sendMessage(String message, TLRPC.MessageMedia location, TLRPC.TL_photo photo, VideoEditedInfo videoEditedInfo, TLRPC.User user, TLRPC.TL_document document, long peer, String path, MessageObject reply_to_msg, TLRPC.WebPage webPage, boolean searchLinks, boolean asAdmin, MessageObject retryMessageObject, ArrayList entities, TLRPC.ReplyMarkup replyMarkup, HashMap params) { + if (peer == 0) { + return; + } + + String originalPath = null; + if (params != null && params.containsKey("originalPath")) { + originalPath = params.get("originalPath"); + } + + TLRPC.Message newMsg = null; + MessageObject newMsgObj = null; + int type = -1; + int lower_id = (int) peer; + int high_id = (int) (peer >> 32); + TLRPC.EncryptedChat encryptedChat = null; + TLRPC.InputPeer sendToPeer = lower_id != 0 ? MessagesController.getInputPeer(lower_id) : null; + ArrayList sendToPeers = null; + if (lower_id == 0) { + encryptedChat = MessagesController.getInstance().getEncryptedChat(high_id); + if (encryptedChat == null) { + if (retryMessageObject != null) { + MessagesStorage.getInstance().markMessageAsSendError(retryMessageObject.messageOwner); + retryMessageObject.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, retryMessageObject.getId()); + processSentMessage(retryMessageObject.getId()); + } + return; + } + } else if (asAdmin && sendToPeer instanceof TLRPC.TL_inputPeerChannel) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(sendToPeer.channel_id); + if (chat.megagroup) { + asAdmin = false; + } + } + + try { + if (retryMessageObject != null) { + newMsg = retryMessageObject.messageOwner; + if (retryMessageObject.isForwarded()) { + type = 4; + } else { + if (retryMessageObject.type == 0) { + message = newMsg.message; + type = 0; + } else if (retryMessageObject.type == 4) { + location = newMsg.media; + type = 1; + } else if (retryMessageObject.type == 1) { + photo = (TLRPC.TL_photo) newMsg.media.photo; + type = 2; + } else if (retryMessageObject.type == 3) { + type = 3; + document = (TLRPC.TL_document) newMsg.media.document; + } else if (retryMessageObject.type == 12) { + user = new TLRPC.TL_userRequest_old2(); + user.phone = newMsg.media.phone_number; + user.first_name = newMsg.media.first_name; + user.last_name = newMsg.media.last_name; + user.id = newMsg.media.user_id; + type = 6; + } else if (retryMessageObject.type == 8 || retryMessageObject.type == 9 || retryMessageObject.type == 13 || retryMessageObject.type == 14) { + document = (TLRPC.TL_document) newMsg.media.document; + type = 7; + } else if (retryMessageObject.type == 2) { + document = (TLRPC.TL_document) newMsg.media.document; + type = 8; + } + if (params != null && params.containsKey("query_id")) { + type = 9; + } + } + } else { + if (message != null) { + if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + newMsg = new TLRPC.TL_message_secret(); + } else { + newMsg = new TLRPC.TL_message(); + } + if (entities != null && !entities.isEmpty()) { + newMsg.entities = entities; + } + if (encryptedChat != null && webPage instanceof TLRPC.TL_webPagePending) { + if (webPage.url != null) { + TLRPC.WebPage newWebPage = new TLRPC.TL_webPageUrlPending(); + newWebPage.url = webPage.url; + webPage = newWebPage; + } else { + webPage = null; + } + } + if (webPage == null) { + newMsg.media = new TLRPC.TL_messageMediaEmpty(); + } else { + newMsg.media = new TLRPC.TL_messageMediaWebPage(); + newMsg.media.webpage = webPage; + } + if (params != null && params.containsKey("query_id")) { + type = 9; + } else { + type = 0; + } + newMsg.message = message; + } else if (location != null) { + if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + newMsg = new TLRPC.TL_message_secret(); + } else { + newMsg = new TLRPC.TL_message(); + } + newMsg.media = location; + newMsg.message = ""; + if (params != null && params.containsKey("query_id")) { + type = 9; + } else { + type = 1; + } + } else if (photo != null) { + if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + newMsg = new TLRPC.TL_message_secret(); + } else { + newMsg = new TLRPC.TL_message(); + } + newMsg.media = new TLRPC.TL_messageMediaPhoto(); + newMsg.media.caption = photo.caption != null ? photo.caption : ""; + newMsg.media.photo = photo; + if (params != null && params.containsKey("query_id")) { + type = 9; + } else { + type = 2; + } + newMsg.message = "-1"; + if (path != null && path.length() > 0 && path.startsWith("http")) { + newMsg.attachPath = path; + } else { + TLRPC.FileLocation location1 = photo.sizes.get(photo.sizes.size() - 1).location; + newMsg.attachPath = FileLoader.getPathToAttach(location1, true).toString(); + } + } else if (user != null) { + if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + newMsg = new TLRPC.TL_message_secret(); + } else { + newMsg = new TLRPC.TL_message(); + } + newMsg.media = new TLRPC.TL_messageMediaContact(); + newMsg.media.phone_number = user.phone; + newMsg.media.first_name = user.first_name; + newMsg.media.last_name = user.last_name; + newMsg.media.user_id = user.id; + if (newMsg.media.first_name == null) { + user.first_name = newMsg.media.first_name = ""; + } + if (newMsg.media.last_name == null) { + user.last_name = newMsg.media.last_name = ""; + } + newMsg.message = ""; + if (params != null && params.containsKey("query_id")) { + type = 9; + } else { + type = 6; + } + } else if (document != null) { + if (encryptedChat != null && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + newMsg = new TLRPC.TL_message_secret(); + } else { + newMsg = new TLRPC.TL_message(); + } + newMsg.media = new TLRPC.TL_messageMediaDocument(); + newMsg.media.caption = document.caption != null ? document.caption : ""; + newMsg.media.document = document; + if (params != null && params.containsKey("query_id")) { + type = 9; + } else if (MessageObject.isVideoDocument(document)) { + type = 3; + } else if (MessageObject.isVoiceDocument(document)) { + type = 8; + } else { + type = 7; + } + if (videoEditedInfo == null) { + newMsg.message = "-1"; + } else { + newMsg.message = videoEditedInfo.getString(); + } + if (encryptedChat != null && document.dc_id > 0 && !MessageObject.isStickerDocument(document)) { + newMsg.attachPath = FileLoader.getPathToAttach(document).toString(); + } else { + newMsg.attachPath = path; + } + if (encryptedChat != null && MessageObject.isStickerDocument(document)) { + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeSticker) { + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) < 46) { + document.attributes.remove(a); + document.attributes.add(new TLRPC.TL_documentAttributeSticker_old()); + } else { + if (attribute.stickerset != null) { + String name = StickersQuery.getStickerSetName(attribute.stickerset.id); + if (name != null && name.length() > 0) { + attribute.stickerset = new TLRPC.TL_inputStickerSetShortName(); + attribute.stickerset.short_name = name; + } else { + attribute.stickerset = new TLRPC.TL_inputStickerSetEmpty(); + } + } else { + attribute.stickerset = new TLRPC.TL_inputStickerSetEmpty(); + } + } + break; + } + } + } + } + if (newMsg.attachPath == null) { + newMsg.attachPath = ""; + } + newMsg.local_id = newMsg.id = UserConfig.getNewMessageId(); + newMsg.out = true; + if (asAdmin && sendToPeer != null && sendToPeer.channel_id != 0) { + newMsg.from_id = -sendToPeer.channel_id; + } else { + newMsg.from_id = UserConfig.getClientUserId(); + newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + } + UserConfig.saveConfig(false); + } + if (newMsg.random_id == 0) { + newMsg.random_id = getNextRandomId(); + } + if (params != null && params.containsKey("bot")) { + if (encryptedChat != null) { + newMsg.via_bot_name = params.get("bot_name"); + if (newMsg.via_bot_name == null) { + newMsg.via_bot_name = ""; + } + } else { + newMsg.via_bot_id = Utilities.parseInt(params.get("bot")); + } + newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_BOT_ID; + } + newMsg.params = params; + newMsg.date = ConnectionsManager.getInstance().getCurrentTime(); + newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; + if (sendToPeer instanceof TLRPC.TL_inputPeerChannel) { + if (asAdmin) { + newMsg.views = 1; + newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_VIEWS; + } + TLRPC.Chat chat = MessagesController.getInstance().getChat(sendToPeer.channel_id); + if (chat != null) { + if (chat.megagroup) { + newMsg.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } else { + newMsg.post = true; + if (chat.signatures) { + newMsg.from_id = UserConfig.getClientUserId(); + } + } + } + } else { + newMsg.unread = true; + } + newMsg.dialog_id = peer; + if (reply_to_msg != null) { + if (encryptedChat != null && reply_to_msg.messageOwner.random_id != 0) { + newMsg.reply_to_random_id = reply_to_msg.messageOwner.random_id; + newMsg.flags |= TLRPC.MESSAGE_FLAG_REPLY; + } else { + newMsg.flags |= TLRPC.MESSAGE_FLAG_REPLY; + } + newMsg.reply_to_msg_id = reply_to_msg.getId(); + } + if (replyMarkup != null && encryptedChat == null) { + newMsg.flags |= TLRPC.MESSAGE_FLAG_HAS_MARKUP; + newMsg.reply_markup = replyMarkup; + } + if (lower_id != 0) { + if (high_id == 1) { + if (currentChatInfo == null) { + MessagesStorage.getInstance().markMessageAsSendError(newMsg); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsg.id); + processSentMessage(newMsg.id); + return; + } + sendToPeers = new ArrayList<>(); + for (TLRPC.ChatParticipant participant : currentChatInfo.participants.participants) { + TLRPC.User sendToUser = MessagesController.getInstance().getUser(participant.user_id); + TLRPC.InputUser peerUser = MessagesController.getInputUser(sendToUser); + if (peerUser != null) { + sendToPeers.add(peerUser); + } + } + newMsg.to_id = new TLRPC.TL_peerChat(); + newMsg.to_id.chat_id = lower_id; + } else { + newMsg.to_id = MessagesController.getPeer(lower_id); + if (lower_id > 0) { + TLRPC.User sendToUser = MessagesController.getInstance().getUser(lower_id); + if (sendToUser == null) { + processSentMessage(newMsg.id); + return; + } + if (sendToUser.bot) { + newMsg.unread = false; + } + } + } + } else { + newMsg.to_id = new TLRPC.TL_peerUser(); + if (encryptedChat.participant_id == UserConfig.getClientUserId()) { + newMsg.to_id.user_id = encryptedChat.admin_id; + } else { + newMsg.to_id.user_id = encryptedChat.participant_id; + } + newMsg.ttl = encryptedChat.ttl; + if (newMsg.ttl != 0) { + if (MessageObject.isVoiceMessage(newMsg)) { + int duration = 0; + for (int a = 0; a < newMsg.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = newMsg.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + duration = attribute.duration; + break; + } + } + newMsg.ttl = Math.max(encryptedChat.ttl, duration + 1); + } else if (MessageObject.isVideoMessage(newMsg)) { + int duration = 0; + for (int a = 0; a < newMsg.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = newMsg.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeVideo) { + duration = attribute.duration; + break; + } + } + newMsg.ttl = Math.max(encryptedChat.ttl, duration + 1); + } + } + } + if ((encryptedChat == null || AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) && high_id != 1 && MessageObject.isVoiceMessage(newMsg) && newMsg.to_id.channel_id == 0) { + newMsg.media_unread = true; + } + + newMsgObj = new MessageObject(newMsg, null, true); + newMsgObj.replyMessageObject = reply_to_msg; + newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENDING; + + ArrayList objArr = new ArrayList<>(); + objArr.add(newMsgObj); + ArrayList arr = new ArrayList<>(); + arr.add(newMsg); + MessagesStorage.getInstance().putMessages(arr, false, true, false, 0); + MessagesController.getInstance().updateInterfaceWithMessages(peer, objArr); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + + if (BuildVars.DEBUG_VERSION) { + if (sendToPeer != null) { + FileLog.e("tmessages", "send message user_id = " + sendToPeer.user_id + " chat_id = " + sendToPeer.chat_id + " channel_id = " + sendToPeer.channel_id + " access_hash = " + sendToPeer.access_hash); + } + } + + if (type == 0 || type == 9 && message != null && encryptedChat != null) { + if (encryptedChat == null) { + if (sendToPeers != null) { + TLRPC.TL_messages_sendBroadcast reqSend = new TLRPC.TL_messages_sendBroadcast(); + ArrayList random_ids = new ArrayList<>(); + for (int a = 0; a < sendToPeers.size(); a++) { + random_ids.add(Utilities.random.nextLong()); + } + reqSend.message = message; + reqSend.contacts = sendToPeers; + reqSend.media = new TLRPC.TL_inputMediaEmpty(); + reqSend.random_id = random_ids; + performSendMessageRequest(reqSend, newMsgObj, null); + } else { + TLRPC.TL_messages_sendMessage reqSend = new TLRPC.TL_messages_sendMessage(); + reqSend.message = message; + + if (newMsg.to_id instanceof TLRPC.TL_peerChannel) { + reqSend.silent = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).getBoolean("silent_" + peer, false); + } + reqSend.peer = sendToPeer; + reqSend.random_id = newMsg.random_id; + if (asAdmin && sendToPeer instanceof TLRPC.TL_inputPeerChannel) { + reqSend.broadcast = true; + } + if (reply_to_msg != null) { + reqSend.flags |= 1; + reqSend.reply_to_msg_id = reply_to_msg.getId(); + } + if (!searchLinks) { + reqSend.no_webpage = true; + } + performSendMessageRequest(reqSend, newMsgObj, null); + } + } else { + TLRPC.TL_decryptedMessage reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { + reqSend = new TLRPC.TL_decryptedMessage(); + reqSend.ttl = newMsg.ttl; + if (entities != null && !entities.isEmpty()) { + reqSend.entities = entities; + reqSend.flags |= TLRPC.MESSAGE_FLAG_HAS_ENTITIES; + } + if (reply_to_msg != null && reply_to_msg.messageOwner.random_id != 0) { + reqSend.reply_to_random_id = reply_to_msg.messageOwner.random_id; + reqSend.flags |= TLRPC.MESSAGE_FLAG_REPLY; + } + } else if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessage_layer17(); + reqSend.ttl = newMsg.ttl; + } else { + reqSend = new TLRPC.TL_decryptedMessage_layer8(); + reqSend.random_bytes = new byte[15]; + Utilities.random.nextBytes(reqSend.random_bytes); + } + if (params != null && params.get("bot_name") != null) { + reqSend.via_bot_name = params.get("bot_name"); + reqSend.flags |= TLRPC.MESSAGE_FLAG_HAS_BOT_ID; + } + reqSend.random_id = newMsg.random_id; + reqSend.message = message; + if (webPage != null && webPage.url != null) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaWebPage(); + reqSend.media.url = webPage.url; + reqSend.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; + } else { + reqSend.media = new TLRPC.TL_decryptedMessageMediaEmpty(); + } + SecretChatHelper.getInstance().performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, null, null); + } + } else if (type >= 1 && type <= 3 || type >= 5 && type <= 8 || type == 9 && encryptedChat != null) { + if (encryptedChat == null) { + TLRPC.InputMedia inputMedia = null; + DelayedMessage delayedMessage = null; + if (type == 1) { + if (location instanceof TLRPC.TL_messageMediaVenue) { + inputMedia = new TLRPC.TL_inputMediaVenue(); + inputMedia.address = location.address; + inputMedia.title = location.title; + inputMedia.provider = location.provider; + inputMedia.venue_id = location.venue_id; + } else { + inputMedia = new TLRPC.TL_inputMediaGeoPoint(); + } + inputMedia.geo_point = new TLRPC.TL_inputGeoPoint(); + inputMedia.geo_point.lat = location.geo.lat; + inputMedia.geo_point._long = location.geo._long; + } else if (type == 2 || type == 9 && photo != null) { + if (photo.access_hash == 0) { + inputMedia = new TLRPC.TL_inputMediaUploadedPhoto(); + inputMedia.caption = photo.caption != null ? photo.caption : ""; + delayedMessage = new DelayedMessage(); + delayedMessage.originalPath = originalPath; + delayedMessage.type = 0; + delayedMessage.obj = newMsgObj; + if (path != null && path.length() > 0 && path.startsWith("http")) { + delayedMessage.httpLocation = path; + } else { + delayedMessage.location = photo.sizes.get(photo.sizes.size() - 1).location; + } + } else { + TLRPC.TL_inputMediaPhoto media = new TLRPC.TL_inputMediaPhoto(); + media.id = new TLRPC.TL_inputPhoto(); + media.caption = photo.caption != null ? photo.caption : ""; + media.id.id = photo.id; + media.id.access_hash = photo.access_hash; + inputMedia = media; + } + } else if (type == 3) { + if (document.access_hash == 0) { + if (document.thumb.location != null) { + inputMedia = new TLRPC.TL_inputMediaUploadedThumbDocument(); + } else { + inputMedia = new TLRPC.TL_inputMediaUploadedDocument(); + } + inputMedia.caption = document.caption != null ? document.caption : ""; + inputMedia.mime_type = document.mime_type; + inputMedia.attributes = document.attributes; + delayedMessage = new DelayedMessage(); + delayedMessage.originalPath = originalPath; + delayedMessage.type = 1; + delayedMessage.obj = newMsgObj; + delayedMessage.location = document.thumb.location; + delayedMessage.documentLocation = document; + delayedMessage.videoEditedInfo = videoEditedInfo; + } else { + TLRPC.TL_inputMediaDocument media = new TLRPC.TL_inputMediaDocument(); + media.id = new TLRPC.TL_inputDocument(); + media.caption = document.caption != null ? document.caption : ""; + media.id.id = document.id; + media.id.access_hash = document.access_hash; + inputMedia = media; + } + } else if (type == 6) { + inputMedia = new TLRPC.TL_inputMediaContact(); + inputMedia.phone_number = user.phone; + inputMedia.first_name = user.first_name; + inputMedia.last_name = user.last_name; + } else if (type == 7 || type == 9) { + if (document.access_hash == 0) { + if (encryptedChat == null && originalPath != null && originalPath.length() > 0 && originalPath.startsWith("http") && params != null) { + inputMedia = new TLRPC.TL_inputMediaGifExternal(); + String args[] = params.get("url").split("\\|"); + if (args.length == 2) { + inputMedia.url = args[0]; + inputMedia.q = args[1]; + } + } else { + if (document.thumb.location != null && document.thumb.location instanceof TLRPC.TL_fileLocation) { + inputMedia = new TLRPC.TL_inputMediaUploadedThumbDocument(); + } else { + inputMedia = new TLRPC.TL_inputMediaUploadedDocument(); + } + delayedMessage = new DelayedMessage(); + delayedMessage.originalPath = originalPath; + delayedMessage.type = 2; + delayedMessage.obj = newMsgObj; + delayedMessage.documentLocation = document; + delayedMessage.location = document.thumb.location; + } + inputMedia.mime_type = document.mime_type; + inputMedia.attributes = document.attributes; + inputMedia.caption = document.caption != null ? document.caption : ""; + } else { + TLRPC.TL_inputMediaDocument media = new TLRPC.TL_inputMediaDocument(); + media.id = new TLRPC.TL_inputDocument(); + media.id.id = document.id; + media.id.access_hash = document.access_hash; + media.caption = document.caption != null ? document.caption : ""; + inputMedia = media; + } + } else if (type == 8) { + if (document.access_hash == 0) { + inputMedia = new TLRPC.TL_inputMediaUploadedDocument(); + inputMedia.mime_type = document.mime_type; + inputMedia.attributes = document.attributes; + inputMedia.caption = document.caption != null ? document.caption : ""; + delayedMessage = new DelayedMessage(); + delayedMessage.type = 3; + delayedMessage.obj = newMsgObj; + delayedMessage.documentLocation = document; + } else { + TLRPC.TL_inputMediaDocument media = new TLRPC.TL_inputMediaDocument(); + media.id = new TLRPC.TL_inputDocument(); + media.caption = document.caption != null ? document.caption : ""; + media.id.id = document.id; + media.id.access_hash = document.access_hash; + inputMedia = media; + } + } + + TLObject reqSend; + + if (sendToPeers != null) { + TLRPC.TL_messages_sendBroadcast request = new TLRPC.TL_messages_sendBroadcast(); + ArrayList random_ids = new ArrayList<>(); + for (int a = 0; a < sendToPeers.size(); a++) { + random_ids.add(Utilities.random.nextLong()); + } + request.contacts = sendToPeers; + request.media = inputMedia; + request.random_id = random_ids; + request.message = ""; + if (delayedMessage != null) { + delayedMessage.sendRequest = request; + } + reqSend = request; + } else { + TLRPC.TL_messages_sendMedia request = new TLRPC.TL_messages_sendMedia(); + request.peer = sendToPeer; + if (newMsg.to_id instanceof TLRPC.TL_peerChannel) { + request.silent = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).getBoolean("silent_" + peer, false); + } + request.random_id = newMsg.random_id; + request.media = inputMedia; + if (asAdmin && sendToPeer instanceof TLRPC.TL_inputPeerChannel) { + request.broadcast = true; + } + if (reply_to_msg != null) { + request.flags |= 1; + request.reply_to_msg_id = reply_to_msg.getId(); + } + if (delayedMessage != null) { + delayedMessage.sendRequest = request; + } + reqSend = request; + } + if (type == 1) { + performSendMessageRequest(reqSend, newMsgObj, null); + } else if (type == 2) { + if (photo.access_hash == 0) { + performSendDelayedMessage(delayedMessage); + } else { + performSendMessageRequest(reqSend, newMsgObj, null); + } + } else if (type == 3) { + if (document.access_hash == 0) { + performSendDelayedMessage(delayedMessage); + } else { + performSendMessageRequest(reqSend, newMsgObj, null); + } + } else if (type == 6) { + performSendMessageRequest(reqSend, newMsgObj, null); + } else if (type == 7) { + if (document.access_hash == 0 && delayedMessage != null) { + performSendDelayedMessage(delayedMessage); + } else { + performSendMessageRequest(reqSend, newMsgObj, originalPath); + } + } else if (type == 8) { + if (document.access_hash == 0) { + performSendDelayedMessage(delayedMessage); + } else { + performSendMessageRequest(reqSend, newMsgObj, null); + } + } + } else { + TLRPC.TL_decryptedMessage reqSend; + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { + reqSend = new TLRPC.TL_decryptedMessage(); + reqSend.ttl = newMsg.ttl; + if (entities != null && !entities.isEmpty()) { + reqSend.entities = entities; + reqSend.flags |= TLRPC.MESSAGE_FLAG_HAS_ENTITIES; + } + if (reply_to_msg != null && reply_to_msg.messageOwner.random_id != 0) { + reqSend.reply_to_random_id = reply_to_msg.messageOwner.random_id; + reqSend.flags |= TLRPC.MESSAGE_FLAG_REPLY; + } + reqSend.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; + } else if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend = new TLRPC.TL_decryptedMessage_layer17(); + reqSend.ttl = newMsg.ttl; + } else { + reqSend = new TLRPC.TL_decryptedMessage_layer8(); + reqSend.random_bytes = new byte[15]; + Utilities.random.nextBytes(reqSend.random_bytes); + } + if (params != null && params.get("bot_name") != null) { + reqSend.via_bot_name = params.get("bot_name"); + reqSend.flags |= TLRPC.MESSAGE_FLAG_HAS_BOT_ID; + } + reqSend.random_id = newMsg.random_id; + reqSend.message = ""; + if (type == 1) { + if (location instanceof TLRPC.TL_messageMediaVenue && AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaVenue(); + reqSend.media.address = location.address; + reqSend.media.title = location.title; + reqSend.media.provider = location.provider; + reqSend.media.venue_id = location.venue_id; + } else { + reqSend.media = new TLRPC.TL_decryptedMessageMediaGeoPoint(); + } + reqSend.media.lat = location.geo.lat; + reqSend.media._long = location.geo._long; + SecretChatHelper.getInstance().performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, null, null); + } else if (type == 2 || type == 9 && photo != null) { + TLRPC.PhotoSize small = photo.sizes.get(0); + TLRPC.PhotoSize big = photo.sizes.get(photo.sizes.size() - 1); + ImageLoader.fillPhotoSizeWithBytes(small); + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaPhoto(); + reqSend.media.caption = photo.caption != null ? photo.caption : ""; + if (small.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaPhoto) reqSend.media).thumb = small.bytes; + } else { + ((TLRPC.TL_decryptedMessageMediaPhoto) reqSend.media).thumb = new byte[0]; + } + } else { + reqSend.media = new TLRPC.TL_decryptedMessageMediaPhoto_layer8(); + if (small.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaPhoto_layer8) reqSend.media).thumb = small.bytes; + } else { + ((TLRPC.TL_decryptedMessageMediaPhoto_layer8) reqSend.media).thumb = new byte[0]; + } + } + reqSend.media.thumb_h = small.h; + reqSend.media.thumb_w = small.w; + reqSend.media.w = big.w; + reqSend.media.h = big.h; + reqSend.media.size = big.size; + if (big.location.key == null) { + DelayedMessage delayedMessage = new DelayedMessage(); + delayedMessage.originalPath = originalPath; + delayedMessage.sendEncryptedRequest = reqSend; + delayedMessage.type = 0; + delayedMessage.obj = newMsgObj; + delayedMessage.encryptedChat = encryptedChat; + if (path != null && path.length() > 0 && path.startsWith("http")) { + delayedMessage.httpLocation = path; + } else { + delayedMessage.location = photo.sizes.get(photo.sizes.size() - 1).location; + } + performSendDelayedMessage(delayedMessage); + } else { + TLRPC.TL_inputEncryptedFile encryptedFile = new TLRPC.TL_inputEncryptedFile(); + encryptedFile.id = big.location.volume_id; + encryptedFile.access_hash = big.location.secret; + reqSend.media.key = big.location.key; + reqSend.media.iv = big.location.iv; + SecretChatHelper.getInstance().performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, encryptedFile, null); + } + } else if (type == 3) { + ImageLoader.fillPhotoSizeWithBytes(document.thumb); + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaVideo(); + if (document.thumb != null && document.thumb.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaVideo) reqSend.media).thumb = document.thumb.bytes; + } else { + ((TLRPC.TL_decryptedMessageMediaVideo) reqSend.media).thumb = new byte[0]; + } + } else if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaVideo_layer17(); + if (document.thumb != null && document.thumb.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaVideo_layer17) reqSend.media).thumb = document.thumb.bytes; + } else { + ((TLRPC.TL_decryptedMessageMediaVideo_layer17) reqSend.media).thumb = new byte[0]; + } + } else { + reqSend.media = new TLRPC.TL_decryptedMessageMediaVideo_layer8(); + if (document.thumb != null && document.thumb.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaVideo_layer8) reqSend.media).thumb = document.thumb.bytes; + } else { + ((TLRPC.TL_decryptedMessageMediaVideo_layer8) reqSend.media).thumb = new byte[0]; + } + } + reqSend.media.caption = document.caption != null ? document.caption : ""; + reqSend.media.mime_type = "video/mp4"; + reqSend.media.size = document.size; + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeVideo) { + reqSend.media.w = attribute.w; + reqSend.media.h = attribute.h; + reqSend.media.duration = attribute.duration; + break; + } + } + reqSend.media.thumb_h = document.thumb.h; + reqSend.media.thumb_w = document.thumb.w; + if (document.access_hash == 0) { + DelayedMessage delayedMessage = new DelayedMessage(); + delayedMessage.originalPath = originalPath; + delayedMessage.sendEncryptedRequest = reqSend; + delayedMessage.type = 1; + delayedMessage.obj = newMsgObj; + delayedMessage.encryptedChat = encryptedChat; + delayedMessage.documentLocation = document; + delayedMessage.videoEditedInfo = videoEditedInfo; + performSendDelayedMessage(delayedMessage); + } else { + TLRPC.TL_inputEncryptedFile encryptedFile = new TLRPC.TL_inputEncryptedFile(); + encryptedFile.id = document.id; + encryptedFile.access_hash = document.access_hash; + reqSend.media.key = document.key; + reqSend.media.iv = document.iv; + SecretChatHelper.getInstance().performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, encryptedFile, null); + } + } else if (type == 6) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaContact(); + reqSend.media.phone_number = user.phone; + reqSend.media.first_name = user.first_name; + reqSend.media.last_name = user.last_name; + reqSend.media.user_id = user.id; + SecretChatHelper.getInstance().performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, null, null); + } else if (type == 7 || type == 9 && document != null) { + if (MessageObject.isStickerDocument(document)) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaExternalDocument(); + reqSend.media.id = document.id; + reqSend.media.date = document.date; + reqSend.media.access_hash = document.access_hash; + reqSend.media.mime_type = document.mime_type; + reqSend.media.size = document.size; + reqSend.media.dc_id = document.dc_id; + reqSend.media.attributes = document.attributes; + if (document.thumb == null) { + ((TLRPC.TL_decryptedMessageMediaExternalDocument) reqSend.media).thumb = new TLRPC.TL_photoSizeEmpty(); + ((TLRPC.TL_decryptedMessageMediaExternalDocument) reqSend.media).thumb.type = "s"; + } else { + ((TLRPC.TL_decryptedMessageMediaExternalDocument) reqSend.media).thumb = document.thumb; + } + SecretChatHelper.getInstance().performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, null, null); + } else { + ImageLoader.fillPhotoSizeWithBytes(document.thumb); + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaDocument(); + reqSend.media.attributes = document.attributes; + reqSend.media.caption = document.caption != null ? document.caption : ""; + if (document.thumb != null && document.thumb.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaDocument) reqSend.media).thumb = document.thumb.bytes; + reqSend.media.thumb_h = document.thumb.h; + reqSend.media.thumb_w = document.thumb.w; + } else { + ((TLRPC.TL_decryptedMessageMediaDocument) reqSend.media).thumb = new byte[0]; + reqSend.media.thumb_h = 0; + reqSend.media.thumb_w = 0; + } + } else { + reqSend.media = new TLRPC.TL_decryptedMessageMediaDocument_layer8(); + reqSend.media.file_name = FileLoader.getDocumentFileName(document); + if (document.thumb != null && document.thumb.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaDocument_layer8) reqSend.media).thumb = document.thumb.bytes; + reqSend.media.thumb_h = document.thumb.h; + reqSend.media.thumb_w = document.thumb.w; + } else { + ((TLRPC.TL_decryptedMessageMediaDocument_layer8) reqSend.media).thumb = new byte[0]; + reqSend.media.thumb_h = 0; + reqSend.media.thumb_w = 0; + } + } + reqSend.media.size = document.size; + reqSend.media.mime_type = document.mime_type; + + if (document.key == null) { + DelayedMessage delayedMessage = new DelayedMessage(); + delayedMessage.originalPath = originalPath; + delayedMessage.sendEncryptedRequest = reqSend; + delayedMessage.type = 2; + delayedMessage.obj = newMsgObj; + delayedMessage.encryptedChat = encryptedChat; + if (path != null && path.length() > 0 && path.startsWith("http")) { + delayedMessage.httpLocation = path; + } + delayedMessage.documentLocation = document; + performSendDelayedMessage(delayedMessage); + } else { + TLRPC.TL_inputEncryptedFile encryptedFile = new TLRPC.TL_inputEncryptedFile(); + encryptedFile.id = document.id; + encryptedFile.access_hash = document.access_hash; + reqSend.media.key = document.key; + reqSend.media.iv = document.iv; + SecretChatHelper.getInstance().performSendEncryptedRequest(reqSend, newMsgObj.messageOwner, encryptedChat, encryptedFile, null); + } + } + } else if (type == 8) { + DelayedMessage delayedMessage = new DelayedMessage(); + delayedMessage.encryptedChat = encryptedChat; + delayedMessage.sendEncryptedRequest = reqSend; + delayedMessage.obj = newMsgObj; + delayedMessage.documentLocation = document; + delayedMessage.type = 3; + + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaDocument(); + reqSend.media.attributes = document.attributes; + reqSend.media.caption = document.caption != null ? document.caption : ""; + if (document.thumb != null && document.thumb.bytes != null) { + ((TLRPC.TL_decryptedMessageMediaDocument) reqSend.media).thumb = document.thumb.bytes; + reqSend.media.thumb_h = document.thumb.h; + reqSend.media.thumb_w = document.thumb.w; + } else { + ((TLRPC.TL_decryptedMessageMediaDocument) reqSend.media).thumb = new byte[0]; + reqSend.media.thumb_h = 0; + reqSend.media.thumb_w = 0; + } + reqSend.media.mime_type = document.mime_type; + reqSend.media.size = document.size; + delayedMessage.originalPath = originalPath; + } else { + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 17) { + reqSend.media = new TLRPC.TL_decryptedMessageMediaAudio(); + } else { + reqSend.media = new TLRPC.TL_decryptedMessageMediaAudio_layer8(); + } + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + reqSend.media.duration = attribute.duration; + break; + } + } + reqSend.media.mime_type = "audio/ogg"; + reqSend.media.size = document.size; + delayedMessage.type = 3; + } + performSendDelayedMessage(delayedMessage); + } + } + } else if (type == 4) { + TLRPC.TL_messages_forwardMessages reqSend = new TLRPC.TL_messages_forwardMessages(); + reqSend.to_peer = sendToPeer; + if (retryMessageObject.messageOwner.ttl != 0) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(-retryMessageObject.messageOwner.ttl); + reqSend.from_peer = new TLRPC.TL_inputPeerChannel(); + reqSend.from_peer.channel_id = -retryMessageObject.messageOwner.ttl; + if (chat != null) { + reqSend.from_peer.access_hash = chat.access_hash; + } + } else { + reqSend.from_peer = new TLRPC.TL_inputPeerEmpty(); + } + if (retryMessageObject.messageOwner.to_id instanceof TLRPC.TL_peerChannel) { + reqSend.silent = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).getBoolean("silent_" + peer, false); + } + reqSend.random_id.add(newMsg.random_id); + if (retryMessageObject.getId() >= 0) { + reqSend.id.add(retryMessageObject.getId()); + } else { + reqSend.id.add(retryMessageObject.messageOwner.fwd_msg_id); + } + if (asAdmin && reqSend.to_peer.channel_id != 0) { + reqSend.broadcast = true; + } + performSendMessageRequest(reqSend, newMsgObj, null); + } else if (type == 9) { + TLRPC.TL_messages_sendInlineBotResult reqSend = new TLRPC.TL_messages_sendInlineBotResult(); + reqSend.peer = sendToPeer; + if (asAdmin && sendToPeer instanceof TLRPC.TL_inputPeerChannel) { + reqSend.broadcast = true; + } + reqSend.random_id = newMsg.random_id; + if (reply_to_msg != null) { + reqSend.flags |= 1; + reqSend.reply_to_msg_id = reply_to_msg.getId(); + } + if (newMsg.to_id instanceof TLRPC.TL_peerChannel) { + reqSend.silent = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).getBoolean("silent_" + peer, false); + } + reqSend.query_id = Utilities.parseLong(params.get("query_id")); + reqSend.id = params.get("id"); + performSendMessageRequest(reqSend, newMsgObj, null); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + MessagesStorage.getInstance().markMessageAsSendError(newMsg); + if (newMsgObj != null) { + newMsgObj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsg.id); + processSentMessage(newMsg.id); + } + } + + private void performSendDelayedMessage(final DelayedMessage message) { + if (message.type == 0) { + if (message.httpLocation != null) { + putToDelayedMessages(message.httpLocation, message); + ImageLoader.getInstance().loadHttpFile(message.httpLocation, "file"); + } else { + if (message.sendRequest != null) { + String location = FileLoader.getPathToAttach(message.location).toString(); + putToDelayedMessages(location, message); + FileLoader.getInstance().uploadFile(location, false, true); + } else { + String location = FileLoader.getPathToAttach(message.location).toString(); + if (message.sendEncryptedRequest != null && message.location.dc_id != 0) { + File file = new File(location); + if (!file.exists()) { + putToDelayedMessages(FileLoader.getAttachFileName(message.location), message); + FileLoader.getInstance().loadFile(message.location, "jpg", 0, false); + return; + } + } + putToDelayedMessages(location, message); + FileLoader.getInstance().uploadFile(location, true, true); + } + } + } else if (message.type == 1) { + if (message.videoEditedInfo != null) { + String location = message.obj.messageOwner.attachPath; + if (location == null) { + location = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.documentLocation.id + ".mp4"; + } + putToDelayedMessages(location, message); + MediaController.getInstance().scheduleVideoConvert(message.obj); + } else { + if (message.sendRequest != null) { + TLRPC.InputMedia media; + if (message.sendRequest instanceof TLRPC.TL_messages_sendMedia) { + media = ((TLRPC.TL_messages_sendMedia) message.sendRequest).media; + } else { + media = ((TLRPC.TL_messages_sendBroadcast) message.sendRequest).media; + } + if (media.file == null) { + String location = message.obj.messageOwner.attachPath; + if (location == null) { + location = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.documentLocation.id + ".mp4"; + } + putToDelayedMessages(location, message); + if (message.obj.videoEditedInfo != null) { + FileLoader.getInstance().uploadFile(location, false, false, message.documentLocation.size); + } else { + FileLoader.getInstance().uploadFile(location, false, false); + } + } else { + String location = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.location.volume_id + "_" + message.location.local_id + ".jpg"; + putToDelayedMessages(location, message); + FileLoader.getInstance().uploadFile(location, false, true); + } + } else { + String location = message.obj.messageOwner.attachPath; + if (location == null) { + location = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.documentLocation.id + ".mp4"; + } + putToDelayedMessages(location, message); + if (message.obj.videoEditedInfo != null) { + FileLoader.getInstance().uploadFile(location, true, false, message.documentLocation.size); + } else { + FileLoader.getInstance().uploadFile(location, true, false); + } + } + } + } else if (message.type == 2) { + if (message.httpLocation != null) { + putToDelayedMessages(message.httpLocation, message); + ImageLoader.getInstance().loadHttpFile(message.httpLocation, "gif"); + } else { + if (message.sendRequest != null) { + TLRPC.InputMedia media; + if (message.sendRequest instanceof TLRPC.TL_messages_sendMedia) { + media = ((TLRPC.TL_messages_sendMedia) message.sendRequest).media; + } else { + media = ((TLRPC.TL_messages_sendBroadcast) message.sendRequest).media; + } + if (media.file == null) { + String location = message.obj.messageOwner.attachPath; + putToDelayedMessages(location, message); + if (message.sendRequest != null) { + FileLoader.getInstance().uploadFile(location, false, false); + } else { + FileLoader.getInstance().uploadFile(location, true, false); + } + } else if (media.thumb == null && message.location != null) { + String location = FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE) + "/" + message.location.volume_id + "_" + message.location.local_id + ".jpg"; + putToDelayedMessages(location, message); + FileLoader.getInstance().uploadFile(location, false, true); + } + } else { + String location = message.obj.messageOwner.attachPath; + if (message.sendEncryptedRequest != null && message.documentLocation.dc_id != 0) { + File file = new File(location); + if (!file.exists()) { + putToDelayedMessages(FileLoader.getAttachFileName(message.documentLocation), message); + FileLoader.getInstance().loadFile(message.documentLocation, true, false); + return; + } + } + putToDelayedMessages(location, message); + FileLoader.getInstance().uploadFile(location, true, false); + } + } + } else if (message.type == 3) { + String location = message.obj.messageOwner.attachPath; + putToDelayedMessages(location, message); + if (message.sendRequest != null) { + FileLoader.getInstance().uploadFile(location, false, true); + } else { + FileLoader.getInstance().uploadFile(location, true, true); + } + } + } + + protected void stopVideoService(final String path) { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.stopEncodingService, path); + } + }); + } + }); + } + + protected void putToSendingMessages(TLRPC.Message message) { + sendingMessages.put(message.id, message); + } + + protected void removeFromSendingMessages(int mid) { + sendingMessages.remove(mid); + } + + public boolean isSendingMessage(int mid) { + return sendingMessages.containsKey(mid); + } + + private void performSendMessageRequest(final TLObject req, final MessageObject msgObj, final String originalPath) { + final TLRPC.Message newMsgObj = msgObj.messageOwner; + putToSendingMessages(newMsgObj); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + boolean isSentError = false; + if (error == null) { + final int oldId = newMsgObj.id; + final boolean isBroadcast = req instanceof TLRPC.TL_messages_sendBroadcast; + final ArrayList sentMessages = new ArrayList<>(); + final String attachPath = newMsgObj.attachPath; + if (response instanceof TLRPC.TL_updateShortSentMessage) { + final TLRPC.TL_updateShortSentMessage res = (TLRPC.TL_updateShortSentMessage) response; + newMsgObj.local_id = newMsgObj.id = res.id; + newMsgObj.date = res.date; + newMsgObj.entities = res.entities; + newMsgObj.out = res.out; + if (res.media != null) { + newMsgObj.media = res.media; + newMsgObj.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA; + } + if (!newMsgObj.entities.isEmpty()) { + newMsgObj.flags |= TLRPC.MESSAGE_FLAG_HAS_ENTITIES; + } + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().processNewDifferenceParams(-1, res.pts, res.date, res.pts_count); + } + }); + sentMessages.add(newMsgObj); + } else if (response instanceof TLRPC.Updates) { + ArrayList updates = ((TLRPC.Updates) response).updates; + TLRPC.Message message = null; + for (int a = 0; a < updates.size(); a++) { + TLRPC.Update update = updates.get(a); + if (update instanceof TLRPC.TL_updateNewMessage) { + final TLRPC.TL_updateNewMessage newMessage = (TLRPC.TL_updateNewMessage) update; + sentMessages.add(message = newMessage.message); + newMsgObj.id = newMessage.message.id; + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().processNewDifferenceParams(-1, newMessage.pts, -1, newMessage.pts_count); + } + }); + break; + } else if (update instanceof TLRPC.TL_updateNewChannelMessage) { + final TLRPC.TL_updateNewChannelMessage newMessage = (TLRPC.TL_updateNewChannelMessage) update; + sentMessages.add(message = newMessage.message); + if ((newMsgObj.flags & TLRPC.MESSAGE_FLAG_MEGAGROUP) != 0) { + newMessage.message.flags |= TLRPC.MESSAGE_FLAG_MEGAGROUP; + } + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().processNewChannelDifferenceParams(newMessage.pts, newMessage.pts_count, newMessage.message.to_id.channel_id); + } + }); + break; + } + } + if (message != null) { + newMsgObj.id = message.id; + updateMediaPaths(msgObj, message, originalPath, false); + } else { + isSentError = true; + } + } + + if (!isSentError) { + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, (isBroadcast ? oldId : newMsgObj.id), newMsgObj, newMsgObj.dialog_id); //TODO remove later? + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + MessagesStorage.getInstance().updateMessageStateAndId(newMsgObj.random_id, oldId, (isBroadcast ? oldId : newMsgObj.id), 0, false, newMsgObj.to_id.channel_id); + MessagesStorage.getInstance().putMessages(sentMessages, true, false, isBroadcast, 0); + if (isBroadcast) { + ArrayList currentMessage = new ArrayList<>(); + currentMessage.add(newMsgObj); + MessagesStorage.getInstance().putMessages(currentMessage, true, false, false, 0); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (isBroadcast) { + for (int a = 0; a < sentMessages.size(); a++) { + TLRPC.Message message = sentMessages.get(a); + ArrayList arr = new ArrayList<>(); + MessageObject messageObject = new MessageObject(message, null, false); + arr.add(messageObject); + MessagesController.getInstance().updateInterfaceWithMessages(messageObject.getDialogId(), arr, true); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.dialogsNeedReload); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByServer, oldId, (isBroadcast ? oldId : newMsgObj.id), newMsgObj, newMsgObj.dialog_id); + processSentMessage(oldId); + removeFromSendingMessages(oldId); + } + }); + if (MessageObject.isVideoMessage(newMsgObj)) { + stopVideoService(attachPath); + } + } + }); + } + } else { + if (error.text.equals("PEER_FLOOD")) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.needShowAlert, 0); + } + isSentError = true; + } + if (isSentError) { + MessagesStorage.getInstance().markMessageAsSendError(newMsgObj); + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SEND_ERROR; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageSendError, newMsgObj.id); + processSentMessage(newMsgObj.id); + if (MessageObject.isVideoMessage(newMsgObj)) { + stopVideoService(newMsgObj.attachPath); + } + removeFromSendingMessages(newMsgObj.id); + } + } + }); + } + }, new QuickAckDelegate() { + @Override + public void run() { + final int msg_id = newMsgObj.id; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + newMsgObj.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.messageReceivedByAck, msg_id); + } + }); + } + }, ConnectionsManager.RequestFlagCanCompress | ConnectionsManager.RequestFlagInvokeAfter | (req instanceof TLRPC.TL_messages_sendMessage ? ConnectionsManager.RequestFlagNeedQuickAck : 0)); + } + + private void updateMediaPaths(MessageObject newMsgObj, TLRPC.Message sentMessage, String originalPath, boolean post) { + TLRPC.Message newMsg = newMsgObj.messageOwner; + if (sentMessage == null) { + return; + } + if (sentMessage.media instanceof TLRPC.TL_messageMediaPhoto && sentMessage.media.photo != null && newMsg.media instanceof TLRPC.TL_messageMediaPhoto && newMsg.media.photo != null) { + MessagesStorage.getInstance().putSentFile(originalPath, sentMessage.media.photo, 0); + + if (newMsg.media.photo.sizes.size() == 1 && newMsg.media.photo.sizes.get(0).location instanceof TLRPC.TL_fileLocationUnavailable) { + newMsg.media.photo.sizes = sentMessage.media.photo.sizes; + } else { + for (int a = 0; a < sentMessage.media.photo.sizes.size(); a++) { + TLRPC.PhotoSize size = sentMessage.media.photo.sizes.get(a); + if (size == null || size.location == null || size instanceof TLRPC.TL_photoSizeEmpty || size.type == null) { + continue; + } + for (int b = 0; b < newMsg.media.photo.sizes.size(); b++) { + TLRPC.PhotoSize size2 = newMsg.media.photo.sizes.get(b); + if (size2 == null || size2.location == null || size2.type == null) { + continue; + } + if (size2.location.volume_id == Integer.MIN_VALUE && size.type.equals(size2.type) || size.w == size2.w && size.h == size2.h) { + String fileName = size2.location.volume_id + "_" + size2.location.local_id; + String fileName2 = size.location.volume_id + "_" + size.location.local_id; + if (fileName.equals(fileName2)) { + break; + } + File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName + ".jpg"); + File cacheFile2; + if (sentMessage.media.photo.sizes.size() == 1 || size.w > 90 || size.h > 90) { + cacheFile2 = FileLoader.getPathToAttach(size); + } else { + cacheFile2 = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName2 + ".jpg"); + } + cacheFile.renameTo(cacheFile2); + ImageLoader.getInstance().replaceImageInCache(fileName, fileName2, size.location, post); + size2.location = size.location; + size2.size = size.size; + break; + } + } + } + } + sentMessage.message = newMsg.message; + sentMessage.attachPath = newMsg.attachPath; + newMsg.media.photo.id = sentMessage.media.photo.id; + newMsg.media.photo.access_hash = sentMessage.media.photo.access_hash; + } else if (sentMessage.media instanceof TLRPC.TL_messageMediaDocument && sentMessage.media.document != null && newMsg.media instanceof TLRPC.TL_messageMediaDocument && newMsg.media.document != null) { + if (MessageObject.isVideoMessage(sentMessage)) { + MessagesStorage.getInstance().putSentFile(originalPath, sentMessage.media.document, 2); + sentMessage.attachPath = newMsg.attachPath; + } else if (!MessageObject.isVoiceMessage(sentMessage)) { + MessagesStorage.getInstance().putSentFile(originalPath, sentMessage.media.document, 1); + } + + TLRPC.PhotoSize size2 = newMsg.media.document.thumb; + TLRPC.PhotoSize size = sentMessage.media.document.thumb; + if (size2 != null && size2.location != null && size2.location.volume_id == Integer.MIN_VALUE && size != null && size.location != null && !(size instanceof TLRPC.TL_photoSizeEmpty) && !(size2 instanceof TLRPC.TL_photoSizeEmpty)) { + String fileName = size2.location.volume_id + "_" + size2.location.local_id; + String fileName2 = size.location.volume_id + "_" + size.location.local_id; + if (!fileName.equals(fileName2)) { + File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName + ".jpg"); + File cacheFile2 = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName2 + ".jpg"); + cacheFile.renameTo(cacheFile2); + ImageLoader.getInstance().replaceImageInCache(fileName, fileName2, size.location, post); + size2.location = size.location; + size2.size = size.size; + } + } else if (size2 != null && MessageObject.isStickerMessage(sentMessage) && size2.location != null) { + size.location = size2.location; + } else if (size2 != null && size2.location instanceof TLRPC.TL_fileLocationUnavailable) { + newMsg.media.document.thumb = sentMessage.media.document.thumb; + } + + newMsg.media.document.dc_id = sentMessage.media.document.dc_id; + newMsg.media.document.id = sentMessage.media.document.id; + newMsg.media.document.access_hash = sentMessage.media.document.access_hash; + byte[] oldWaveform = null; + for (int a = 0; a < newMsg.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = newMsg.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + oldWaveform = attribute.waveform; + } + } + newMsg.media.document.attributes = sentMessage.media.document.attributes; + if (oldWaveform != null) { + for (int a = 0; a < newMsg.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = newMsg.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + attribute.waveform = oldWaveform; + attribute.flags |= 4; + } + } + } + newMsg.media.document.size = sentMessage.media.document.size; + newMsg.media.document.mime_type = sentMessage.media.document.mime_type; + + if ((sentMessage.flags & TLRPC.MESSAGE_FLAG_FWD) == 0 && MessageObject.isOut(sentMessage) && MessageObject.isNewGifDocument(sentMessage.media.document)) { + MessagesController.addNewGifToRecent(sentMessage.media.document, sentMessage.date); + } + + if (newMsg.attachPath != null && newMsg.attachPath.startsWith(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE).getAbsolutePath())) { + File cacheFile = new File(newMsg.attachPath); + File cacheFile2 = FileLoader.getPathToAttach(sentMessage.media.document); + if (!cacheFile.renameTo(cacheFile2)) { + sentMessage.attachPath = newMsg.attachPath; + sentMessage.message = newMsg.message; + } else if (!MessageObject.isVideoMessage(sentMessage)) { + newMsgObj.mediaExists = newMsgObj.attachPathExists; + newMsgObj.attachPathExists = false; + newMsg.attachPath = ""; + if (originalPath != null && originalPath.startsWith("http")) { + MessagesStorage.getInstance().addRecentLocalFile(originalPath, cacheFile2.toString(), newMsg.media.document); + } + } + } else { + sentMessage.attachPath = newMsg.attachPath; + sentMessage.message = newMsg.message; + } + } else if (sentMessage.media instanceof TLRPC.TL_messageMediaContact && newMsg.media instanceof TLRPC.TL_messageMediaContact) { + newMsg.media = sentMessage.media; + } else if (sentMessage.media instanceof TLRPC.TL_messageMediaWebPage) { + newMsg.media = sentMessage.media; + } + } + + private void putToDelayedMessages(String location, DelayedMessage message) { + ArrayList arrayList = delayedMessages.get(location); + if (arrayList == null) { + arrayList = new ArrayList<>(); + delayedMessages.put(location, arrayList); + } + arrayList.add(message); + } + + protected ArrayList getDelayedMessages(String location) { + return delayedMessages.get(location); + } + + protected long getNextRandomId() { + long val = 0; + while (val == 0) { + val = Utilities.random.nextLong(); + } + return val; + } + + public void checkUnsentMessages() { + MessagesStorage.getInstance().getUnsentMessages(1000); + } + + protected void processUnsentMessages(final ArrayList messages, final ArrayList users, final ArrayList chats, final ArrayList encryptedChats) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().putUsers(users, true); + MessagesController.getInstance().putChats(chats, true); + MessagesController.getInstance().putEncryptedChats(encryptedChats, true); + for (int a = 0; a < messages.size(); a++) { + TLRPC.Message message = messages.get(a); + MessageObject messageObject = new MessageObject(message, null, false); + retrySendMessage(messageObject, true); + } + } + }); + } + + public TLRPC.TL_photo generatePhotoSizes(String path, Uri imageUri) { + Bitmap bitmap = ImageLoader.loadBitmap(path, imageUri, AndroidUtilities.getPhotoSize(), AndroidUtilities.getPhotoSize(), true); + if (bitmap == null && AndroidUtilities.getPhotoSize() != 800) { + bitmap = ImageLoader.loadBitmap(path, imageUri, 800, 800, true); + } + ArrayList sizes = new ArrayList<>(); + TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, true); + if (size != null) { + sizes.add(size); + } + size = ImageLoader.scaleAndSaveImage(bitmap, AndroidUtilities.getPhotoSize(), AndroidUtilities.getPhotoSize(), 80, false, 101, 101); + if (size != null) { + sizes.add(size); + } + if (bitmap != null) { + bitmap.recycle(); + } + if (sizes.isEmpty()) { + return null; + } else { + UserConfig.saveConfig(false); + TLRPC.TL_photo photo = new TLRPC.TL_photo(); + photo.date = ConnectionsManager.getInstance().getCurrentTime(); + photo.sizes = sizes; + return photo; + } + } + + private static boolean prepareSendingDocumentInternal(String path, String originalPath, Uri uri, String mime, final long dialog_id, final MessageObject reply_to_msg, final boolean asAdmin, String caption) { + if ((path == null || path.length() == 0) && uri == null) { + return false; + } + MimeTypeMap myMime = MimeTypeMap.getSingleton(); + TLRPC.TL_documentAttributeAudio attributeAudio = null; + if (uri != null) { + String extension = null; + if (mime != null) { + extension = myMime.getExtensionFromMimeType(mime); + } + if (extension == null) { + extension = "txt"; + } + path = MediaController.copyFileToCache(uri, extension); + if (path == null) { + return false; + } + } + final File f = new File(path); + if (!f.exists() || f.length() == 0) { + return false; + } + + boolean isEncrypted = (int) dialog_id == 0; + boolean allowSticker = !isEncrypted; + + String name = f.getName(); + String ext = ""; + int idx = path.lastIndexOf('.'); + if (idx != -1) { + ext = path.substring(idx + 1); + } + if (ext.toLowerCase().equals("mp3") || ext.toLowerCase().equals("m4a")) { + AudioInfo audioInfo = AudioInfo.getAudioInfo(f); + if (audioInfo != null && audioInfo.getDuration() != 0) { + if (isEncrypted) { + int high_id = (int) (dialog_id >> 32); + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(high_id); + if (encryptedChat == null) { + return false; + } + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) >= 46) { + attributeAudio = new TLRPC.TL_documentAttributeAudio(); + } else { + attributeAudio = new TLRPC.TL_documentAttributeAudio_old(); + } + } else { + attributeAudio = new TLRPC.TL_documentAttributeAudio(); + } + attributeAudio.duration = (int) (audioInfo.getDuration() / 1000); + attributeAudio.title = audioInfo.getTitle(); + attributeAudio.performer = audioInfo.getArtist(); + if (attributeAudio.title == null) { + attributeAudio.title = ""; + attributeAudio.flags |= 1; + } + if (attributeAudio.performer == null) { + attributeAudio.performer = ""; + attributeAudio.flags |= 2; + } + } + } + if (originalPath != null) { + if (attributeAudio != null) { + originalPath += "audio" + f.length(); + } else { + originalPath += "" + f.length(); + } + } + + TLRPC.TL_document document = null; + if (!isEncrypted) { + document = (TLRPC.TL_document) MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 1 : 4); + if (document == null && !path.equals(originalPath) && !isEncrypted) { + document = (TLRPC.TL_document) MessagesStorage.getInstance().getSentFile(path + f.length(), !isEncrypted ? 1 : 4); + } + } + if (document == null) { + document = new TLRPC.TL_document(); + document.id = 0; + document.date = ConnectionsManager.getInstance().getCurrentTime(); + TLRPC.TL_documentAttributeFilename fileName = new TLRPC.TL_documentAttributeFilename(); + fileName.file_name = name; + document.attributes.add(fileName); + document.size = (int) f.length(); + document.dc_id = 0; + if (attributeAudio != null) { + document.attributes.add(attributeAudio); + } + if (ext.length() != 0) { + if (ext.toLowerCase().equals("webp")) { + document.mime_type = "image/webp"; + } else { + String mimeType = myMime.getMimeTypeFromExtension(ext.toLowerCase()); + if (mimeType != null) { + document.mime_type = mimeType; + } else { + document.mime_type = "application/octet-stream"; + } + } + } else { + document.mime_type = "application/octet-stream"; + } + if (document.mime_type.equals("image/gif")) { + try { + Bitmap bitmap = ImageLoader.loadBitmap(f.getAbsolutePath(), null, 90, 90, true); + if (bitmap != null) { + fileName.file_name = "animation.gif"; + document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, isEncrypted); + bitmap.recycle(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + if (document.mime_type.equals("image/webp") && allowSticker) { + BitmapFactory.Options bmOptions = new BitmapFactory.Options(); + try { + bmOptions.inJustDecodeBounds = true; + RandomAccessFile file = new RandomAccessFile(path, "r"); + ByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, path.length()); + Utilities.loadWebpImage(null, buffer, buffer.limit(), bmOptions, true); + file.close(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (bmOptions.outWidth != 0 && bmOptions.outHeight != 0 && bmOptions.outWidth <= 800 && bmOptions.outHeight <= 800) { + TLRPC.TL_documentAttributeSticker attributeSticker = new TLRPC.TL_documentAttributeSticker(); + attributeSticker.alt = ""; + attributeSticker.stickerset = new TLRPC.TL_inputStickerSetEmpty(); + document.attributes.add(attributeSticker); + TLRPC.TL_documentAttributeImageSize attributeImageSize = new TLRPC.TL_documentAttributeImageSize(); + attributeImageSize.w = bmOptions.outWidth; + attributeImageSize.h = bmOptions.outHeight; + document.attributes.add(attributeImageSize); + } + } + if (document.thumb == null) { + document.thumb = new TLRPC.TL_photoSizeEmpty(); + document.thumb.type = "s"; + } + } + document.caption = caption; + + final HashMap params = new HashMap<>(); + if (originalPath != null) { + params.put("originalPath", originalPath); + } + final TLRPC.TL_document documentFinal = document; + final String pathFinal = path; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + SendMessagesHelper.getInstance().sendMessage(documentFinal, null, pathFinal, dialog_id, reply_to_msg, asAdmin, null, params); + } + }); + return true; + } + + public static void prepareSendingDocument(String path, String originalPath, Uri uri, String mine, long dialog_id, MessageObject reply_to_msg, boolean asAdmin) { + if ((path == null || originalPath == null) && uri == null) { + return; + } + ArrayList paths = new ArrayList<>(); + ArrayList originalPaths = new ArrayList<>(); + ArrayList uris = null; + if (uri != null) { + uris = new ArrayList<>(); + } + paths.add(path); + originalPaths.add(originalPath); + prepareSendingDocuments(paths, originalPaths, uris, mine, dialog_id, reply_to_msg, asAdmin); + } + + public static void prepareSendingAudioDocuments(final ArrayList messageObjects, final long dialog_id, final MessageObject reply_to_msg, final boolean asAdmin) { + new Thread(new Runnable() { + @Override + public void run() { + int size = messageObjects.size(); + for (int a = 0; a < size; a++) { + final MessageObject messageObject = messageObjects.get(a); + String originalPath = messageObject.messageOwner.attachPath; + final File f = new File(originalPath); + + boolean isEncrypted = (int) dialog_id == 0; + + + if (originalPath != null) { + originalPath += "audio" + f.length(); + } + + TLRPC.TL_document document = null; + if (!isEncrypted) { + document = (TLRPC.TL_document) MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 1 : 4); + } + if (document == null) { + document = (TLRPC.TL_document) messageObject.messageOwner.media.document; + } + + if (isEncrypted) { + int high_id = (int) (dialog_id >> 32); + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(high_id); + if (encryptedChat == null) { + return; + } + if (AndroidUtilities.getPeerLayerVersion(encryptedChat.layer) < 46) { + for (int b = 0; b < document.attributes.size(); b++) { + if (document.attributes.get(b) instanceof TLRPC.TL_documentAttributeAudio) { + TLRPC.TL_documentAttributeAudio_old old = new TLRPC.TL_documentAttributeAudio_old(); + old.duration = document.attributes.get(b).duration; + document.attributes.remove(b); + document.attributes.add(old); + break; + } + } + } + } + + final HashMap params = new HashMap<>(); + if (originalPath != null) { + params.put("originalPath", originalPath); + } + final TLRPC.TL_document documentFinal = document; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + SendMessagesHelper.getInstance().sendMessage(documentFinal, null, messageObject.messageOwner.attachPath, dialog_id, reply_to_msg, asAdmin, null, params); + } + }); + } + } + }).start(); + } + + public static void prepareSendingDocuments(final ArrayList paths, final ArrayList originalPaths, final ArrayList uris, final String mime, final long dialog_id, final MessageObject reply_to_msg, final boolean asAdmin) { + if (paths == null && originalPaths == null && uris == null || paths != null && originalPaths != null && paths.size() != originalPaths.size()) { + return; + } + new Thread(new Runnable() { + @Override + public void run() { + boolean error = false; + if (paths != null) { + for (int a = 0; a < paths.size(); a++) { + if (!prepareSendingDocumentInternal(paths.get(a), originalPaths.get(a), null, mime, dialog_id, reply_to_msg, asAdmin, null)) { + error = true; + } + } + } + if (uris != null) { + for (int a = 0; a < uris.size(); a++) { + if (!prepareSendingDocumentInternal(null, null, uris.get(a), mime, dialog_id, reply_to_msg, asAdmin, null)) { + error = true; + } + } + } + if (error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + Toast toast = Toast.makeText(ApplicationLoader.applicationContext, LocaleController.getString("UnsupportedAttachment", R.string.UnsupportedAttachment), Toast.LENGTH_SHORT); + toast.show(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + } + }).start(); + } + + public static void prepareSendingPhoto(String imageFilePath, Uri imageUri, long dialog_id, MessageObject reply_to_msg, CharSequence caption, boolean asAdmin) { + ArrayList paths = null; + ArrayList uris = null; + ArrayList captions = null; + if (imageFilePath != null && imageFilePath.length() != 0) { + paths = new ArrayList<>(); + paths.add(imageFilePath); + } + if (imageUri != null) { + uris = new ArrayList<>(); + uris.add(imageUri); + } + if (caption != null) { + captions = new ArrayList<>(); + captions.add(caption.toString()); + } + prepareSendingPhotos(paths, uris, dialog_id, reply_to_msg, captions, asAdmin); + } + + public static void prepareSendingBotContextResult(final TLRPC.BotInlineResult result, final HashMap params, final long dialog_id, final MessageObject reply_to_msg, final boolean asAdmin) { + if (result == null) { + return; + } + if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaAuto) { + new Thread(new Runnable() { + @Override + public void run() { + String finalPath = null; + TLRPC.TL_document document = null; + TLRPC.TL_photo photo = null; + if (result instanceof TLRPC.TL_botInlineMediaResult) { + if (result.document != null) { + if (result.document instanceof TLRPC.TL_document) { + document = (TLRPC.TL_document) result.document; + } + } else if (result.photo != null) { + if (result.photo instanceof TLRPC.TL_photo) { + photo = (TLRPC.TL_photo) result.photo; + } + } + } else { + if (result.content_url != null) { + File f = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(result.content_url) + "." + ImageLoader.getHttpUrlExtension(result.content_url, "file")); + if (f.exists()) { + finalPath = f.getAbsolutePath(); + } else { + finalPath = result.content_url; + } + switch (result.type) { + case "audio": + case "voice": + case "file": + case "video": + case "sticker": + case "gif": { + document = new TLRPC.TL_document(); + document.id = 0; + document.size = 0; + document.dc_id = 0; + document.mime_type = result.content_type; + document.date = ConnectionsManager.getInstance().getCurrentTime(); + TLRPC.TL_documentAttributeFilename fileName = new TLRPC.TL_documentAttributeFilename(); + document.attributes.add(fileName); + + switch (result.type) { + case "gif": { + fileName.file_name = "animation.gif"; + if (finalPath.endsWith("mp4")) { + document.mime_type = "video/mp4"; + document.attributes.add(new TLRPC.TL_documentAttributeAnimated()); + } else { + document.mime_type = "image/gif"; + } + try { + Bitmap bitmap; + if (finalPath.endsWith("mp4")) { + bitmap = ThumbnailUtils.createVideoThumbnail(finalPath, MediaStore.Video.Thumbnails.MINI_KIND); + } else { + bitmap = ImageLoader.loadBitmap(finalPath, null, 90, 90, true); + } + if (bitmap != null) { + document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, false); + bitmap.recycle(); + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + break; + } + case "voice": { + TLRPC.TL_documentAttributeAudio audio = new TLRPC.TL_documentAttributeAudio(); + audio.duration = result.duration; + audio.voice = true; + fileName.file_name = "audio.ogg"; + document.attributes.add(audio); + + document.thumb = new TLRPC.TL_photoSizeEmpty(); + document.thumb.type = "s"; + + break; + } + case "audio": { + TLRPC.TL_documentAttributeAudio audio = new TLRPC.TL_documentAttributeAudio(); + audio.duration = result.duration; + audio.title = result.title; + audio.flags |= 1; + if (result.description != null) { + audio.performer = result.description; + audio.flags |= 2; + } + fileName.file_name = "audio.mp3"; + document.attributes.add(audio); + + document.thumb = new TLRPC.TL_photoSizeEmpty(); + document.thumb.type = "s"; + + break; + } + case "file": { + int idx = result.content_type.indexOf('/'); + if (idx != -1) { + fileName.file_name = "file." + result.content_type.substring(idx + 1); + } else { + fileName.file_name = "file"; + } + break; + } + case "video": { + fileName.file_name = "video.mp4"; + TLRPC.TL_documentAttributeVideo attributeVideo = new TLRPC.TL_documentAttributeVideo(); + attributeVideo.w = result.w; + attributeVideo.h = result.h; + attributeVideo.duration = result.duration; + document.attributes.add(attributeVideo); + try { + String thumbPath = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(result.thumb_url) + "." + ImageLoader.getHttpUrlExtension(result.thumb_url, "jpg")).getAbsolutePath(); + Bitmap bitmap = ImageLoader.loadBitmap(thumbPath, null, 90, 90, true); + if (bitmap != null) { + document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, false); + bitmap.recycle(); + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + break; + } + case "sticker": { + TLRPC.TL_documentAttributeSticker attributeSticker = new TLRPC.TL_documentAttributeSticker(); + attributeSticker.alt = ""; + attributeSticker.stickerset = new TLRPC.TL_inputStickerSetEmpty(); + document.attributes.add(attributeSticker); + TLRPC.TL_documentAttributeImageSize attributeImageSize = new TLRPC.TL_documentAttributeImageSize(); + attributeImageSize.w = result.w; + attributeImageSize.h = result.h; + document.attributes.add(attributeImageSize); + fileName.file_name = "sticker.webp"; + try { + String thumbPath = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), Utilities.MD5(result.thumb_url) + "." + ImageLoader.getHttpUrlExtension(result.thumb_url, "webp")).getAbsolutePath(); + Bitmap bitmap = ImageLoader.loadBitmap(thumbPath, null, 90, 90, true); //TODO support on old androids + if (bitmap != null) { + document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, false); + bitmap.recycle(); + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + break; + } + } + if (fileName.file_name == null) { + fileName.file_name = "file"; + } + if (document.mime_type == null) { + document.mime_type = "application/octet-stream"; + } + if (document.thumb == null) { + document.thumb = new TLRPC.TL_photoSize(); + document.thumb.w = result.w; + document.thumb.h = result.h; + document.thumb.size = 0; + document.thumb.location = new TLRPC.TL_fileLocationUnavailable(); + document.thumb.type = "x"; + } + break; + } + case "photo": { + if (f.exists()) { + photo = SendMessagesHelper.getInstance().generatePhotoSizes(finalPath, null); + } + if (photo == null) { + photo = new TLRPC.TL_photo(); + photo.date = ConnectionsManager.getInstance().getCurrentTime(); + TLRPC.TL_photoSize photoSize = new TLRPC.TL_photoSize(); + photoSize.w = result.w; + photoSize.h = result.h; + photoSize.size = 1; + photoSize.location = new TLRPC.TL_fileLocationUnavailable(); + photoSize.type = "x"; + photo.sizes.add(photoSize); + } + break; + } + } + } + } + final String finalPathFinal = finalPath; + final TLRPC.TL_document finalDocument = document; + final TLRPC.TL_photo finalPhoto = photo; + if (params != null && result.content_url != null) { + params.put("originalPath", result.content_url); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (finalDocument != null) { + finalDocument.caption = result.send_message.caption; + SendMessagesHelper.getInstance().sendMessage(finalDocument, null, finalPathFinal, dialog_id, reply_to_msg, asAdmin, result.send_message.reply_markup, params); + } else if (finalPhoto != null) { + finalPhoto.caption = result.send_message.caption; + SendMessagesHelper.getInstance().sendMessage(finalPhoto, result.content_url, dialog_id, reply_to_msg, asAdmin, result.send_message.reply_markup, params); + } + } + }); + } + }).run(); + } else if (result.send_message instanceof TLRPC.TL_botInlineMessageText) { + SendMessagesHelper.getInstance().sendMessage(result.send_message.message, dialog_id, reply_to_msg, null, !result.send_message.no_webpage, asAdmin, result.send_message.entities, result.send_message.reply_markup, params); + } else if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaVenue) { + TLRPC.TL_messageMediaVenue venue = new TLRPC.TL_messageMediaVenue(); + venue.geo = result.send_message.geo; + venue.address = result.send_message.address; + venue.title = result.send_message.title; + venue.provider = result.send_message.provider; + venue.venue_id = result.send_message.venue_id; + SendMessagesHelper.getInstance().sendMessage(venue, dialog_id, reply_to_msg, asAdmin, result.send_message.reply_markup, params); + } else if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaGeo) { + TLRPC.TL_messageMediaGeo location = new TLRPC.TL_messageMediaGeo(); + location.geo = result.send_message.geo; + SendMessagesHelper.getInstance().sendMessage(location, dialog_id, reply_to_msg, asAdmin, result.send_message.reply_markup, params); + } else if (result.send_message instanceof TLRPC.TL_botInlineMessageMediaContact) { + TLRPC.User user = new TLRPC.TL_user(); + user.phone = result.send_message.phone_number; + user.first_name = result.send_message.first_name; + user.last_name = result.send_message.last_name; + SendMessagesHelper.getInstance().sendMessage(user, dialog_id, reply_to_msg, asAdmin, result.send_message.reply_markup, params); + } + } + + public static void prepareSendingPhotosSearch(final ArrayList photos, final long dialog_id, final MessageObject reply_to_msg, final boolean asAdmin) { + if (photos == null || photos.isEmpty()) { + return; + } + new Thread(new Runnable() { + @Override + public void run() { + boolean isEncrypted = (int) dialog_id == 0; + for (int a = 0; a < photos.size(); a++) { + final MediaController.SearchImage searchImage = photos.get(a); + if (searchImage.type == 1) { + final HashMap params = new HashMap<>(); + TLRPC.TL_document document = null; + File cacheFile; + if (searchImage.document instanceof TLRPC.TL_document) { + document = (TLRPC.TL_document) searchImage.document; + cacheFile = FileLoader.getPathToAttach(document, true); + } else { + if (!isEncrypted) { + TLRPC.Document doc = (TLRPC.Document) MessagesStorage.getInstance().getSentFile(searchImage.imageUrl, !isEncrypted ? 1 : 4); + if (doc instanceof TLRPC.TL_document) { + document = (TLRPC.TL_document) doc; + } + } + String md5 = Utilities.MD5(searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.imageUrl, "jpg"); + cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); + } + if (document == null) { + if (searchImage.localUrl != null) { + params.put("url", searchImage.localUrl); + } + File thumbFile = null; + document = new TLRPC.TL_document(); + document.id = 0; + document.date = ConnectionsManager.getInstance().getCurrentTime(); + TLRPC.TL_documentAttributeFilename fileName = new TLRPC.TL_documentAttributeFilename(); + fileName.file_name = "animation.gif"; + document.attributes.add(fileName); + document.size = searchImage.size; + document.dc_id = 0; + if (cacheFile.toString().endsWith("mp4")) { + document.mime_type = "video/mp4"; + document.attributes.add(new TLRPC.TL_documentAttributeAnimated()); + } else { + document.mime_type = "image/gif"; + } + if (cacheFile.exists()) { + thumbFile = cacheFile; + } else { + cacheFile = null; + } + if (thumbFile == null) { + String thumb = Utilities.MD5(searchImage.thumbUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.thumbUrl, "jpg"); + thumbFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), thumb); + if (!thumbFile.exists()) { + thumbFile = null; + } + } + if (thumbFile != null) { + try { + Bitmap bitmap; + if (thumbFile.getAbsolutePath().endsWith("mp4")) { + bitmap = ThumbnailUtils.createVideoThumbnail(thumbFile.getAbsolutePath(), MediaStore.Video.Thumbnails.MINI_KIND); + } else { + bitmap = ImageLoader.loadBitmap(thumbFile.getAbsolutePath(), null, 90, 90, true); + } + if (bitmap != null) { + document.thumb = ImageLoader.scaleAndSaveImage(bitmap, 90, 90, 55, isEncrypted); + bitmap.recycle(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + if (document.thumb == null) { + document.thumb = new TLRPC.TL_photoSize(); + document.thumb.w = searchImage.width; + document.thumb.h = searchImage.height; + document.thumb.size = 0; + document.thumb.location = new TLRPC.TL_fileLocationUnavailable(); + document.thumb.type = "x"; + } + } + + if (searchImage.caption != null) { + document.caption = searchImage.caption.toString(); + } + final TLRPC.TL_document documentFinal = document; + final String originalPathFinal = searchImage.imageUrl; + final String pathFinal = cacheFile == null ? searchImage.imageUrl : cacheFile.toString(); + if (params != null && searchImage.imageUrl != null) { + params.put("originalPath", searchImage.imageUrl); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + SendMessagesHelper.getInstance().sendMessage(documentFinal, null, pathFinal, dialog_id, reply_to_msg, asAdmin, null, params); + } + }); + } else { + boolean needDownloadHttp = true; + TLRPC.TL_photo photo = null; + if (!isEncrypted) { + photo = (TLRPC.TL_photo) MessagesStorage.getInstance().getSentFile(searchImage.imageUrl, !isEncrypted ? 0 : 3); + } + if (photo == null) { + String md5 = Utilities.MD5(searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.imageUrl, "jpg"); + File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); + if (cacheFile.exists() && cacheFile.length() != 0) { + photo = SendMessagesHelper.getInstance().generatePhotoSizes(cacheFile.toString(), null); + if (photo != null) { + needDownloadHttp = false; + } + } + if (photo == null) { + md5 = Utilities.MD5(searchImage.thumbUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.thumbUrl, "jpg"); + cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), md5); + if (cacheFile.exists()) { + photo = SendMessagesHelper.getInstance().generatePhotoSizes(cacheFile.toString(), null); + } + if (photo == null) { + photo = new TLRPC.TL_photo(); + photo.date = ConnectionsManager.getInstance().getCurrentTime(); + TLRPC.TL_photoSize photoSize = new TLRPC.TL_photoSize(); + photoSize.w = searchImage.width; + photoSize.h = searchImage.height; + photoSize.size = 0; + photoSize.location = new TLRPC.TL_fileLocationUnavailable(); + photoSize.type = "x"; + photo.sizes.add(photoSize); + } + } + } + if (photo != null) { + if (searchImage.caption != null) { + photo.caption = searchImage.caption.toString(); + } + final TLRPC.TL_photo photoFinal = photo; + final boolean needDownloadHttpFinal = needDownloadHttp; + final HashMap params = new HashMap<>(); + if (searchImage.imageUrl != null) { + params.put("originalPath", searchImage.imageUrl); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + SendMessagesHelper.getInstance().sendMessage(photoFinal, needDownloadHttpFinal ? searchImage.imageUrl : null, dialog_id, reply_to_msg, asAdmin, null, params); + } + }); + } + } + } + } + }).start(); + } + + private static String getTrimmedString(String src) { + String result = src.trim(); + if (result.length() == 0) { + return result; + } + while (src.startsWith("\n")) { + src = src.substring(1); + } + while (src.endsWith("\n")) { + src = src.substring(0, src.length() - 1); + } + return src; + } + + public static void prepareSendingText(final String text, final long dialog_id, final boolean asAdmin) { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + String textFinal = getTrimmedString(text); + if (textFinal.length() != 0) { + int count = (int) Math.ceil(textFinal.length() / 4096.0f); + for (int a = 0; a < count; a++) { + String mess = textFinal.substring(a * 4096, Math.min((a + 1) * 4096, textFinal.length())); + SendMessagesHelper.getInstance().sendMessage(mess, dialog_id, null, null, true, asAdmin, null, null, null); + } + } + } + }); + } + }); + } + }); + } + + public static void prepareSendingPhotos(ArrayList paths, ArrayList uris, final long dialog_id, final MessageObject reply_to_msg, final ArrayList captions, final boolean asAdmin) { + if (paths == null && uris == null || paths != null && paths.isEmpty() || uris != null && uris.isEmpty()) { + return; + } + final ArrayList pathsCopy = new ArrayList<>(); + final ArrayList urisCopy = new ArrayList<>(); + if (paths != null) { + pathsCopy.addAll(paths); + } + if (uris != null) { + urisCopy.addAll(uris); + } + new Thread(new Runnable() { + @Override + public void run() { + boolean isEncrypted = (int) dialog_id == 0; + + ArrayList sendAsDocuments = null; + ArrayList sendAsDocumentsOriginal = null; + ArrayList sendAsDocumentsCaptions = null; + int count = !pathsCopy.isEmpty() ? pathsCopy.size() : urisCopy.size(); + String path = null; + Uri uri = null; + String extension = null; + for (int a = 0; a < count; a++) { + if (!pathsCopy.isEmpty()) { + path = pathsCopy.get(a); + } else if (!urisCopy.isEmpty()) { + uri = urisCopy.get(a); + } + + String originalPath = path; + String tempPath = path; + if (tempPath == null && uri != null) { + tempPath = AndroidUtilities.getPath(uri); + originalPath = uri.toString(); + } + + boolean isDocument = false; + if (tempPath != null && (tempPath.endsWith(".gif") || tempPath.endsWith(".webp"))) { + if (tempPath.endsWith(".gif")) { + extension = "gif"; + } else { + extension = "webp"; + } + isDocument = true; + } else if (tempPath == null && uri != null) { + if (MediaController.isGif(uri)) { + isDocument = true; + originalPath = uri.toString(); + tempPath = MediaController.copyFileToCache(uri, "gif"); + extension = "gif"; + } else if (MediaController.isWebp(uri)) { + isDocument = true; + originalPath = uri.toString(); + tempPath = MediaController.copyFileToCache(uri, "webp"); + extension = "webp"; + } + } + + if (isDocument) { + if (sendAsDocuments == null) { + sendAsDocuments = new ArrayList<>(); + sendAsDocumentsOriginal = new ArrayList<>(); + sendAsDocumentsCaptions = new ArrayList<>(); + } + sendAsDocuments.add(tempPath); + sendAsDocumentsOriginal.add(originalPath); + sendAsDocumentsCaptions.add(captions != null ? captions.get(a) : null); + } else { + if (tempPath != null) { + File temp = new File(tempPath); + originalPath += temp.length() + "_" + temp.lastModified(); + } else { + originalPath = null; + } + TLRPC.TL_photo photo = null; + if (!isEncrypted) { + photo = (TLRPC.TL_photo) MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 0 : 3); + if (photo == null && uri != null) { + photo = (TLRPC.TL_photo) MessagesStorage.getInstance().getSentFile(AndroidUtilities.getPath(uri), !isEncrypted ? 0 : 3); + } + } + if (photo == null) { + photo = SendMessagesHelper.getInstance().generatePhotoSizes(path, uri); + } + if (photo != null) { + if (captions != null) { + photo.caption = captions.get(a); + } + final TLRPC.TL_photo photoFinal = photo; + final HashMap params = new HashMap<>(); + if (originalPath != null) { + params.put("originalPath", originalPath); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + SendMessagesHelper.getInstance().sendMessage(photoFinal, null, dialog_id, reply_to_msg, asAdmin, null, params); + } + }); + } + } + } + if (sendAsDocuments != null && !sendAsDocuments.isEmpty()) { + for (int a = 0; a < sendAsDocuments.size(); a++) { + prepareSendingDocumentInternal(sendAsDocuments.get(a), sendAsDocumentsOriginal.get(a), null, extension, dialog_id, reply_to_msg, asAdmin, sendAsDocumentsCaptions.get(a)); + } + } + } + }).start(); + } + + public static void prepareSendingVideo(final String videoPath, final long estimatedSize, final long duration, final int width, final int height, final VideoEditedInfo videoEditedInfo, final long dialog_id, final MessageObject reply_to_msg, final boolean asAdmin) { + if (videoPath == null || videoPath.length() == 0) { + return; + } + new Thread(new Runnable() { + @Override + public void run() { + + boolean isEncrypted = (int) dialog_id == 0; + + if (videoEditedInfo != null || videoPath.endsWith("mp4")) { + String path = videoPath; + String originalPath = videoPath; + File temp = new File(originalPath); + originalPath += temp.length() + "_" + temp.lastModified(); + if (videoEditedInfo != null) { + originalPath += duration + "_" + videoEditedInfo.startTime + "_" + videoEditedInfo.endTime; + if (videoEditedInfo.resultWidth == videoEditedInfo.originalWidth) { + originalPath += "_" + videoEditedInfo.resultWidth; + } + } + TLRPC.TL_document document = null; + if (!isEncrypted) { + //document = (TLRPC.TL_document) MessagesStorage.getInstance().getSentFile(originalPath, !isEncrypted ? 2 : 5); + } + if (document == null) { + Bitmap thumb = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Video.Thumbnails.MINI_KIND); + TLRPC.PhotoSize size = ImageLoader.scaleAndSaveImage(thumb, 90, 90, 55, isEncrypted); + document = new TLRPC.TL_document(); + document.thumb = size; + if (document.thumb == null) { + document.thumb = new TLRPC.TL_photoSizeEmpty(); + document.thumb.type = "s"; + } else { + document.thumb.type = "s"; + } + document.mime_type = "video/mp4"; + UserConfig.saveConfig(false); + TLRPC.TL_documentAttributeVideo attributeVideo = new TLRPC.TL_documentAttributeVideo(); + document.attributes.add(attributeVideo); + if (videoEditedInfo != null) { + attributeVideo.duration = (int) (duration / 1000); + if (videoEditedInfo.rotationValue == 90 || videoEditedInfo.rotationValue == 270) { + attributeVideo.w = height; + attributeVideo.h = width; + } else { + attributeVideo.w = width; + attributeVideo.h = height; + } + document.size = (int) estimatedSize; + String fileName = Integer.MIN_VALUE + "_" + UserConfig.lastLocalId + ".mp4"; + UserConfig.lastLocalId--; + File cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); + UserConfig.saveConfig(false); + path = cacheFile.getAbsolutePath(); + } else { + if (temp.exists()) { + document.size = (int) temp.length(); + } + boolean infoObtained = false; + if (Build.VERSION.SDK_INT >= 14) { + MediaMetadataRetriever mediaMetadataRetriever = null; + try { + mediaMetadataRetriever = new MediaMetadataRetriever(); + mediaMetadataRetriever.setDataSource(videoPath); + String width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH); + if (width != null) { + attributeVideo.w = Integer.parseInt(width); + } + String height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT); + if (height != null) { + attributeVideo.h = Integer.parseInt(height); + } + String duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); + if (duration != null) { + attributeVideo.duration = (int) Math.ceil(Long.parseLong(duration) / 1000.0f); + } + infoObtained = true; + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + try { + if (mediaMetadataRetriever != null) { + mediaMetadataRetriever.release(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + if (!infoObtained) { + try { + MediaPlayer mp = MediaPlayer.create(ApplicationLoader.applicationContext, Uri.fromFile(new File(videoPath))); + if (mp != null) { + attributeVideo.duration = (int) Math.ceil(mp.getDuration() / 1000.0f); + attributeVideo.w = mp.getVideoWidth(); + attributeVideo.h = mp.getVideoHeight(); + mp.release(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + } + final TLRPC.TL_document videoFinal = document; + final String originalPathFinal = originalPath; + final String finalPath = path; + final HashMap params = new HashMap<>(); + if (originalPath != null) { + params.put("originalPath", originalPath); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + SendMessagesHelper.getInstance().sendMessage(videoFinal, videoEditedInfo, finalPath, dialog_id, reply_to_msg, asAdmin, null, params); + } + }); + } else { + prepareSendingDocumentInternal(videoPath, videoPath, null, null, dialog_id, reply_to_msg, asAdmin, null); + } + } + }).start(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/ShareBroadcastReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/ShareBroadcastReceiver.java new file mode 100644 index 00000000..ab6b1163 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/ShareBroadcastReceiver.java @@ -0,0 +1,29 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class ShareBroadcastReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + String url = intent.getDataString(); + if (url != null) { + Intent shareIntent = new Intent(Intent.ACTION_SEND); + shareIntent.setType("text/plain"); + shareIntent.putExtra(Intent.EXTRA_TEXT, url); + Intent chooserIntent = Intent.createChooser(shareIntent, LocaleController.getString("ShareLink", R.string.ShareLink)); + chooserIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(chooserIntent); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/SmsListener.java b/TMessagesProj/src/main/java/org/telegram/messenger/SmsListener.java new file mode 100644 index 00000000..816939e2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/SmsListener.java @@ -0,0 +1,67 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.telephony.SmsMessage; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class SmsListener extends BroadcastReceiver { + + private SharedPreferences preferences; + + @Override + public void onReceive(Context context, Intent intent) { + if(intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) { + if (!AndroidUtilities.isWaitingForSms()) { + return; + } + Bundle bundle = intent.getExtras(); + SmsMessage[] msgs; + if (bundle != null) { + try { + Object[] pdus = (Object[]) bundle.get("pdus"); + msgs = new SmsMessage[pdus.length]; + String wholeString = ""; + for(int i = 0; i < msgs.length; i++){ + msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]); + wholeString += msgs[i].getMessageBody(); + } + + try { + Pattern pattern = Pattern.compile("[0-9]+"); + final Matcher matcher = pattern.matcher(wholeString); + if (matcher.find()) { + String str = matcher.group(0); + if (str.length() >= 3) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didReceiveSmsCode, matcher.group(0)); + } + }); + } + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + + } catch(Throwable e) { + FileLog.e("tmessages", e); + } + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/TgChooserTargetService.java b/TMessagesProj/src/main/java/org/telegram/messenger/TgChooserTargetService.java new file mode 100644 index 00000000..7f89fcb8 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/TgChooserTargetService.java @@ -0,0 +1,184 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.ComponentName; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.Icon; +import android.os.Build; +import android.os.Bundle; +import android.service.chooser.ChooserTarget; +import android.service.chooser.ChooserTargetService; +import android.text.TextUtils; + +import org.telegram.SQLite.SQLiteCursor; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.LaunchActivity; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.Semaphore; + +@TargetApi(Build.VERSION_CODES.M) +public class TgChooserTargetService extends ChooserTargetService { + + private Paint roundPaint; + private RectF bitmapRect; + + @Override + public List onGetChooserTargets(ComponentName targetActivityName, IntentFilter matchedFilter) { + final List targets = new ArrayList<>(); + if (!UserConfig.isClientActivated()) { + return targets; + } + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + if (!preferences.getBoolean("direct_share", true)) { + return targets; + } + + ImageLoader imageLoader = ImageLoader.getInstance(); + final Semaphore semaphore = new Semaphore(0); + final ComponentName componentName = new ComponentName(getPackageName(), LaunchActivity.class.getCanonicalName()); + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + ArrayList dialogs = new ArrayList<>(); + ArrayList chats = new ArrayList<>(); + ArrayList users = new ArrayList<>(); + try { + ArrayList usersToLoad = new ArrayList<>(); + usersToLoad.add(UserConfig.getClientUserId()); + ArrayList chatsToLoad = new ArrayList<>(); + SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT did FROM dialogs ORDER BY date DESC LIMIT %d,%d", 0, 30)); + while (cursor.next()) { + long id = cursor.longValue(0); + + int lower_id = (int) id; + int high_id = (int) (id >> 32); + if (lower_id != 0) { + if (high_id == 1) { + continue; + } else { + if (lower_id > 0) { + if (!usersToLoad.contains(lower_id)) { + usersToLoad.add(lower_id); + } + } else { + if (!chatsToLoad.contains(-lower_id)) { + chatsToLoad.add(-lower_id); + } + } + } + } else { + continue; + } + dialogs.add(lower_id); + if (dialogs.size() == 8) { + break; + } + } + cursor.dispose(); + if (!chatsToLoad.isEmpty()) { + MessagesStorage.getInstance().getChatsInternal(TextUtils.join(",", chatsToLoad), chats); + } + if (!usersToLoad.isEmpty()) { + MessagesStorage.getInstance().getUsersInternal(TextUtils.join(",", usersToLoad), users); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + for (int a = 0; a < dialogs.size(); a++) { + Bundle extras = new Bundle(); + Icon icon = null; + String name = null; + int id = dialogs.get(a); + if (id > 0) { + for (int b = 0; b < users.size(); b++) { + TLRPC.User user = users.get(b); + if (user.id == id) { + if (!user.bot) { + extras.putLong("dialogId", (long) id); + if (user.photo != null && user.photo.photo_small != null) { + icon = createRoundBitmap(FileLoader.getPathToAttach(user.photo.photo_small, true)); + } + name = ContactsController.formatName(user.first_name, user.last_name); + } + break; + } + } + } else { + for (int b = 0; b < chats.size(); b++) { + TLRPC.Chat chat = chats.get(b); + if (chat.id == -id) { + if (!ChatObject.isNotInChat(chat) && (!ChatObject.isChannel(chat) || chat.megagroup)) { + extras.putLong("dialogId", (long) id); + if (chat.photo != null && chat.photo.photo_small != null) { + icon = createRoundBitmap(FileLoader.getPathToAttach(chat.photo.photo_small, true)); + } + name = chat.title; + } + break; + } + } + } + if (name != null) { + if (icon == null) { + icon = Icon.createWithResource(ApplicationLoader.applicationContext, R.drawable.logo_avatar); + } + targets.add(new ChooserTarget(name, icon, 1.0f, componentName, extras)); + } + } + semaphore.release(); + } + }); + try { + semaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return targets; + } + + private Icon createRoundBitmap(File path) { + try { + Bitmap bitmap = BitmapFactory.decodeFile(path.toString()); + if (bitmap != null) { + Bitmap result = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); + result.eraseColor(Color.TRANSPARENT); + Canvas canvas = new Canvas(result); + BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + if (roundPaint == null) { + roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + bitmapRect = new RectF(); + } + roundPaint.setShader(shader); + bitmapRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight()); + canvas.drawRoundRect(bitmapRect, bitmap.getWidth(), bitmap.getHeight(), roundPaint); + return Icon.createWithBitmap(result); + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + return null; + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java index 6cda1ba7..ea10ee13 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserConfig.java @@ -39,7 +39,7 @@ public class UserConfig { public static int lastPauseTime = 0; public static boolean isWaitingForPasscodeEnter = false; public static boolean useFingerprint = true; - public static int lastUpdateVersion; + public static String lastUpdateVersion; public static int lastContactsSyncTime; public static int migrateOffsetId = -1; @@ -83,7 +83,7 @@ public class UserConfig { editor.putInt("passcodeType", passcodeType); editor.putInt("autoLockIn", autoLockIn); editor.putInt("lastPauseTime", lastPauseTime); - editor.putInt("lastUpdateVersion", lastUpdateVersion); + editor.putString("lastUpdateVersion2", lastUpdateVersion); editor.putInt("lastContactsSyncTime", lastContactsSyncTime); editor.putBoolean("useFingerprint", useFingerprint); @@ -224,7 +224,7 @@ public class UserConfig { autoLockIn = preferences.getInt("autoLockIn", 60 * 60); lastPauseTime = preferences.getInt("lastPauseTime", 0); useFingerprint = preferences.getBoolean("useFingerprint", true); - lastUpdateVersion = preferences.getInt("lastUpdateVersion", 511); + lastUpdateVersion = preferences.getString("lastUpdateVersion2", "3.5"); lastContactsSyncTime = preferences.getInt("lastContactsSyncTime", (int) (System.currentTimeMillis() / 1000) - 23 * 60 * 60); migrateOffsetId = preferences.getInt("migrateOffsetId", 0); @@ -314,7 +314,7 @@ public class UserConfig { lastPauseTime = 0; useFingerprint = true; isWaitingForPasscodeEnter = false; - lastUpdateVersion = BuildVars.BUILD_VERSION; + lastUpdateVersion = BuildVars.BUILD_VERSION_STRING; lastContactsSyncTime = (int) (System.currentTimeMillis() / 1000) - 23 * 60 * 60; saveConfig(true); } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java new file mode 100644 index 00000000..15b22cc0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/UserObject.java @@ -0,0 +1,111 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.util.Log; + +import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.tgnet.TLRPC; + +public class UserObject { + + public static boolean isDeleted(TLRPC.User user) { + return user == null || user instanceof TLRPC.TL_userDeleted_old2 || user instanceof TLRPC.TL_userEmpty || user.deleted; + } + + public static boolean isContact(TLRPC.User user) { + return user instanceof TLRPC.TL_userContact_old2 || user.contact || user.mutual_contact; + } + + public static boolean isUserSelf(TLRPC.User user) { + return user instanceof TLRPC.TL_userSelf_old3 || user.self; + } + + public static String getUserName(TLRPC.User user) { + if (user == null || isDeleted(user)) { + return LocaleController.getString("HiddenName", R.string.HiddenName); + } + String name = ContactsController.formatName(user.first_name, user.last_name); + return name.length() != 0 || user.phone == null || user.phone.length() == 0 ? name : PhoneFormat.getInstance().format("+" + user.phone); + } + + public static String getFirstName(TLRPC.User user) { + if (user == null || isDeleted(user)) { + return "DELETED"; + } + String name = user.first_name; + if (name == null || name.length() == 0) { + name = user.last_name; + } + return name != null && name.length() > 0 ? name : LocaleController.getString("HiddenName", R.string.HiddenName); + } + + /*private static final int lastSize = 150; + + public static String getLastName(String last) { + if (last == null || last.length() == 0) { + return ""; + } + //int lastSize = 260; + if(last.length() > lastSize && last.charAt(last.length() -1) == '\u00A0') { + //Log.e("UserObject","getLastName YES " + last + " : " + last.length()); + last = last.substring(0, lastSize - 1); + //last = last.substring(0, lastSize - 2); + last = last.replaceAll("\\s+$", ""); + //last = last.replaceAll(" +$", ""); + } + return last; + } + + public static String getUserStatus(String status) { + if (status == null || status.length() == 0) { + return ""; + } + //int lastSize = 253; + if(status.length() > lastSize && status.charAt(status.length() -1) == '\u00A0') { + //Log.e("UserObject","getUserStatus YES " + status.length()); + status = status.substring(lastSize, status.length() - 1); + status = status.replaceAll("\\s+$", ""); + //status = status.replaceAll(" +$", ""); + return status; + } + //Log.e("UserObject","getUserStatus NO "+ status + " / "+ status.length()); + return null; + } + + public static String setStatus(String newLast, String newStatus){ + //int lastSize = 253; + StringBuilder buffer = new StringBuilder(lastSize + newStatus.length()); + //char c = '\n'; + try{ + int x = 0; + if(newLast.length() == 0){ + buffer.append('\u00A0'); //Ok, malo en pc + buffer.append('\n'); + //buffer.append(' '); + x = 2; + } + for (int i = x; i < lastSize + newStatus.length(); i++){ + if(i < lastSize){// 0 99 + //buffer.append(newLast.length() > i ? newLast.charAt(i) : " "); + buffer.append(newLast.length() > i ? newLast.charAt(i) : newLast.length() == i ? '\n' : '\t'); + } + else{ // 100 + buffer.append(newStatus.length() > i - lastSize ? newStatus.charAt(i - lastSize) : " "); + } + } + buffer.append('\u00A0'); + return buffer.toString(); + } catch(Exception e) { + FileLog.e("ChangeName", e.toString()); + } + return newLast; + }*/ + +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java index ca7279cb..7143db19 100644 --- a/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java +++ b/TMessagesProj/src/main/java/org/telegram/messenger/Utilities.java @@ -64,12 +64,13 @@ public class Utilities { public native static void loadBitmap(String path, Bitmap bitmap, int scale, int width, int height, int stride); public native static int pinBitmap(Bitmap bitmap); - public native static int unpinBitmap(Bitmap bitmap); + public native static void unpinBitmap(Bitmap bitmap); public native static void blurBitmap(Object bitmap, int radius, int unpin, int width, int height, int stride); public native static void calcCDT(ByteBuffer hsvBuffer, int width, int height, ByteBuffer buffer); public native static boolean loadWebpImage(Bitmap bitmap, ByteBuffer buffer, int len, BitmapFactory.Options options, boolean unpin); public native static int convertVideoFrame(ByteBuffer src, ByteBuffer dest, int destFormat, int width, int height, int padding, int swap); private native static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, int offset, int length); + public native static String readlink(String path); public static void aesIgeEncryption(ByteBuffer buffer, byte[] key, byte[] iv, boolean encrypt, boolean changeIv, int offset, int length) { aesIgeEncryption(buffer, key, changeIv ? iv : iv.clone(), encrypt, offset, length); @@ -271,8 +272,8 @@ public class Utilities { java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5"); byte[] array = md.digest(md5.getBytes()); StringBuilder sb = new StringBuilder(); - for (byte anArray : array) { - sb.append(Integer.toHexString((anArray & 0xFF) | 0x100).substring(1, 3)); + for (int a = 0; a < array.length; a++) { + sb.append(Integer.toHexString((array[a] & 0xFF) | 0x100).substring(1, 3)); } return sb.toString(); } catch (java.security.NoSuchAlgorithmException e) { @@ -292,8 +293,8 @@ public class Utilities { System.exit(0); } - public static void savePreferencesToSD(Context context, String prefName, String tName, boolean toast){ - String folder = "/Telegram/Themes"; + public static void savePreferencesToSD(Context context, String folder, String prefName, String tName, boolean toast){ + //String folder = "/Telegram/Themes"; File dataF = new File (findPrefFolder(context),prefName); if(checkSDStatus() > 1){ File f = new File (Environment.getExternalStorageDirectory(), folder); @@ -464,6 +465,18 @@ public class Utilities { return Integer.parseInt(s); } + public static int loadPrefFromSD(Context context, String prefPath, String name){ + File dataF = new File (findPrefFolder(context), name + ".xml"); + Log.e("Utilities","dataF " + dataF.getAbsolutePath()); + File prefFile = new File (prefPath); + Log.e("Utilities","prefFile " + prefFile.getAbsolutePath()); + String s = getError(copyFile(prefFile, dataF, false)); + if (!s.contains("4")) { + Toast.makeText(context, "ERROR: "+s+"\n"+ context.getString(R.string.restoreErrorMsg, prefFile.getAbsolutePath()), Toast.LENGTH_LONG).show(); + } + return Integer.parseInt(s); + } + public static String applyThemeFile(File file) { try { HashMap stringMap = getXmlFileStrings(file); diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java new file mode 100644 index 00000000..12c8666a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEditedInfo.java @@ -0,0 +1,51 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import java.util.Locale; + +public class VideoEditedInfo { + public long startTime; + public long endTime; + public int rotationValue; + public int originalWidth; + public int originalHeight; + public int resultWidth; + public int resultHeight; + public int bitrate; + public String originalPath; + + public String getString() { + return String.format(Locale.US, "-1_%d_%d_%d_%d_%d_%d_%d_%d_%s", startTime, endTime, rotationValue, originalWidth, originalHeight, bitrate, resultWidth, resultHeight, originalPath); + } + + public void parseString(String string) { + if (string.length() < 6) { + return; + } + String args[] = string.split("_"); + if (args.length >= 10) { + startTime = Long.parseLong(args[1]); + endTime = Long.parseLong(args[2]); + rotationValue = Integer.parseInt(args[3]); + originalWidth = Integer.parseInt(args[4]); + originalHeight = Integer.parseInt(args[5]); + bitrate = Integer.parseInt(args[6]); + resultWidth = Integer.parseInt(args[7]); + resultHeight = Integer.parseInt(args[8]); + for (int a = 9; a < args.length; a++) { + if (originalPath == null) { + originalPath = args[a]; + } else { + originalPath += "_" + args[a]; + } + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java new file mode 100644 index 00000000..704c8871 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/VideoEncodingService.java @@ -0,0 +1,80 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.support.v4.app.NotificationCompat; +import android.support.v4.app.NotificationManagerCompat; + +public class VideoEncodingService extends Service implements NotificationCenter.NotificationCenterDelegate { + + private NotificationCompat.Builder builder = null; + private String path = null; + private int currentProgress = 0; + + public VideoEncodingService() { + super(); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileUploadProgressChanged); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.stopEncodingService); + } + + public IBinder onBind(Intent arg2) { + return null; + } + + public void onDestroy() { + stopForeground(true); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.FileUploadProgressChanged); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.stopEncodingService); + FileLog.e("tmessages", "destroy video service"); + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.FileUploadProgressChanged) { + String fileName = (String)args[0]; + if (path != null && path.equals(fileName)) { + Float progress = (Float) args[1]; + Boolean enc = (Boolean) args[2]; + currentProgress = (int)(progress * 100); + builder.setProgress(100, currentProgress, currentProgress == 0); + NotificationManagerCompat.from(ApplicationLoader.applicationContext).notify(4, builder.build()); + } + } else if (id == NotificationCenter.stopEncodingService) { + String filepath = (String)args[0]; + if (filepath == null || filepath.equals(path)) { + stopSelf(); + } + } + } + + public int onStartCommand(Intent intent, int flags, int startId) { + path = intent.getStringExtra("path"); + if (path == null) { + stopSelf(); + return Service.START_NOT_STICKY; + } + FileLog.e("tmessages", "start video service"); + if (builder == null) { + builder = new NotificationCompat.Builder(ApplicationLoader.applicationContext); + builder.setSmallIcon(android.R.drawable.stat_sys_upload); + builder.setWhen(System.currentTimeMillis()); + builder.setContentTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setTicker(LocaleController.getString("SendingVideo", R.string.SendingVideo)); + builder.setContentText(LocaleController.getString("SendingVideo", R.string.SendingVideo)); + } + currentProgress = 0; + builder.setProgress(100, currentProgress, currentProgress == 0); + startForeground(4, builder.build()); + NotificationManagerCompat.from(ApplicationLoader.applicationContext).notify(4, builder.build()); + return Service.START_NOT_STICKY; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/WearReplyReceiver.java b/TMessagesProj/src/main/java/org/telegram/messenger/WearReplyReceiver.java new file mode 100644 index 00000000..911daf07 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/WearReplyReceiver.java @@ -0,0 +1,38 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.RemoteInput; + +public class WearReplyReceiver extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + ApplicationLoader.postInitApplication(); + Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); + if (remoteInput == null) { + return; + } + CharSequence text = remoteInput.getCharSequence(NotificationsController.EXTRA_VOICE_REPLY); + if (text == null || text.length() == 0) { + return; + } + long dialog_id = intent.getLongExtra("dialog_id", 0); + int max_id = intent.getIntExtra("max_id", 0); + if (dialog_id == 0 || max_id == 0) { + return; + } + SendMessagesHelper.getInstance().sendMessage(text.toString(), dialog_id, null, null, true, false, null, null, null); + MessagesController.getInstance().markDialogAsRead(dialog_id, max_id, max_id, 0, true, false); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/AudioInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/AudioInfo.java new file mode 100644 index 00000000..dd1181ca --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/AudioInfo.java @@ -0,0 +1,154 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo; + +import android.graphics.Bitmap; + +import org.telegram.messenger.audioinfo.m4a.M4AInfo; +import org.telegram.messenger.audioinfo.mp3.MP3Info; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.RandomAccessFile; + +public abstract class AudioInfo { + protected String brand; // brand, e.g. "M4A", "ID3", ... + protected String version; // version, e.g. "0", "2.3.0", ... + + protected long duration; // track duration (milliseconds) + + protected String title; // track title + protected String artist; // track artist + protected String albumArtist; // album artist + protected String album; // album title + protected short year; // year... + protected String genre; // genre name + protected String comment; // comment... + protected short track; // track number + protected short tracks; // number of tracks + protected short disc; // disc number + protected short discs; // number of discs + protected String copyright; // copyright notice + protected String composer; // composer name + protected String grouping; // track grouping + protected boolean compilation; // compilation flag + protected String lyrics; // song lyrics + protected Bitmap cover; // cover image data + protected Bitmap smallCover; // cover image data + + public String getBrand() { + return brand; + } + + public String getVersion() { + return version; + } + + public long getDuration() { + return duration; + } + + public String getTitle() { + return title; + } + + public String getArtist() { + return artist; + } + + public String getAlbumArtist() { + return albumArtist; + } + + public String getAlbum() { + return album; + } + + public short getYear() { + return year; + } + + public String getGenre() { + return genre; + } + + public String getComment() { + return comment; + } + + public short getTrack() { + return track; + } + + public short getTracks() { + return tracks; + } + + public short getDisc() { + return disc; + } + + public short getDiscs() { + return discs; + } + + public String getCopyright() { + return copyright; + } + + public String getComposer() { + return composer; + } + + public String getGrouping() { + return grouping; + } + + public boolean isCompilation() { + return compilation; + } + + public String getLyrics() { + return lyrics; + } + + public Bitmap getCover() { + return cover; + } + + public Bitmap getSmallCover() { + return smallCover; + } + + public static AudioInfo getAudioInfo(File file) { + try { + byte header[] = new byte[12]; + RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r"); + randomAccessFile.readFully(header, 0, 8); + randomAccessFile.close(); + InputStream input = new BufferedInputStream(new FileInputStream(file)); + if (header[4] == 'f' && header[5] == 't' && header[6] == 'y' && header[7] == 'p') { + return new M4AInfo(input); + } else { + return new MP3Info(input, file.length()); + } + } catch (Exception e) { + return null; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/M4AInfo.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/M4AInfo.java new file mode 100644 index 00000000..51813bea --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/M4AInfo.java @@ -0,0 +1,325 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.m4a; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; + +import org.telegram.messenger.audioinfo.AudioInfo; +import org.telegram.messenger.audioinfo.mp3.ID3v1Genre; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class M4AInfo extends AudioInfo { + static final Logger LOGGER = Logger.getLogger(M4AInfo.class.getName()); + + private static final String ASCII = "ISO8859_1"; + private static final String UTF_8 = "UTF-8"; + + private BigDecimal volume; // normal = 1.0 + private BigDecimal speed; // normal = 1.0 + + private short tempo; + private byte rating; // none = 0, clean = 2, explicit = 4 + + private final Level debugLevel; + + public M4AInfo(InputStream input) throws IOException { + this(input, Level.FINEST); + } + + public M4AInfo(InputStream input, Level debugLevel) throws IOException { + this.debugLevel = debugLevel; + MP4Input mp4 = new MP4Input(input); + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, mp4.toString()); + } + ftyp(mp4.nextChild("ftyp")); + moov(mp4.nextChildUpTo("moov")); + } + + void ftyp(MP4Atom atom) throws IOException { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, atom.toString()); + } + brand = atom.readString(4, ASCII).trim(); + if (brand.matches("M4V|MP4|mp42|isom")) { // experimental file types + LOGGER.warning(atom.getPath() + ": brand=" + brand + " (experimental)"); + } else if (!brand.matches("M4A|M4P")) { + LOGGER.warning(atom.getPath() + ": brand=" + brand + " (expected M4A or M4P)"); + } + version = String.valueOf(atom.readInt()); + } + + void moov(MP4Atom atom) throws IOException { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, atom.toString()); + } + while (atom.hasMoreChildren()) { + MP4Atom child = atom.nextChild(); + switch (child.getType()) { + case "mvhd": + mvhd(child); + break; + case "trak": + trak(child); + break; + case "udta": + udta(child); + break; + default: + break; + } + } + } + + void mvhd(MP4Atom atom) throws IOException { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, atom.toString()); + } + byte version = atom.readByte(); + atom.skip(3); // flags + atom.skip(version == 1 ? 16 : 8); // created/modified date + int scale = atom.readInt(); + long units = version == 1 ? atom.readLong() : atom.readInt(); + if (duration == 0) { + duration = 1000 * units / scale; + } else if (LOGGER.isLoggable(debugLevel) && Math.abs(duration - 1000 * units / scale) > 2) { + LOGGER.log(debugLevel, "mvhd: duration " + duration + " -> " + (1000 * units / scale)); + } + speed = atom.readIntegerFixedPoint(); + volume = atom.readShortFixedPoint(); + } + + void trak(MP4Atom atom) throws IOException { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, atom.toString()); + } + mdia(atom.nextChildUpTo("mdia")); + } + + void mdia(MP4Atom atom) throws IOException { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, atom.toString()); + } + mdhd(atom.nextChild("mdhd")); + } + + void mdhd(MP4Atom atom) throws IOException { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, atom.toString()); + } + byte version = atom.readByte(); + atom.skip(3); + atom.skip(version == 1 ? 16 : 8); // created/modified date + int sampleRate = atom.readInt(); + long samples = version == 1 ? atom.readLong() : atom.readInt(); + if (duration == 0) { + duration = 1000 * samples / sampleRate; + } else if (LOGGER.isLoggable(debugLevel) && Math.abs(duration - 1000 * samples / sampleRate) > 2) { + LOGGER.log(debugLevel, "mdhd: duration " + duration + " -> " + (1000 * samples / sampleRate)); + } + } + + void udta(MP4Atom atom) throws IOException { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, atom.toString()); + } + while (atom.hasMoreChildren()) { + MP4Atom child = atom.nextChild(); + if ("meta".equals(child.getType())) { + meta(child); + break; + } + } + } + + void meta(MP4Atom atom) throws IOException { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, atom.toString()); + } + atom.skip(4); // version/flags + while (atom.hasMoreChildren()) { + MP4Atom child = atom.nextChild(); + if ("ilst".equals(child.getType())) { + ilst(child); + break; + } + } + } + + void ilst(MP4Atom atom) throws IOException { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, atom.toString()); + } + while (atom.hasMoreChildren()) { + MP4Atom child = atom.nextChild(); + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, child.toString()); + } + if (child.getRemaining() == 0) { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, child.getPath() + ": contains no value"); + } + continue; + } + data(child.nextChildUpTo("data")); + } + } + + void data(MP4Atom atom) throws IOException { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, atom.toString()); + } + atom.skip(4); // version & flags + atom.skip(4); // reserved + switch (atom.getParent().getType()) { + case "©alb": + album = atom.readString(UTF_8); + break; + case "aART": + albumArtist = atom.readString(UTF_8); + break; + case "©ART": + artist = atom.readString(UTF_8); + break; + case "©cmt": + comment = atom.readString(UTF_8); + break; + case "©com": + case "©wrt": + if (composer == null || composer.trim().length() == 0) { + composer = atom.readString(UTF_8); + } + break; + case "covr": + try { + byte[] bytes = atom.readBytes(); + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inJustDecodeBounds = true; + opts.inSampleSize = 1; + BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts); + if (opts.outWidth > 800 || opts.outHeight > 800) { + int size = Math.max(opts.outWidth, opts.outHeight); + while (size > 800) { + opts.inSampleSize *= 2; + size /= 2; + } + } + opts.inJustDecodeBounds = false; + cover = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts); + if (cover != null) { + float scale = Math.max(cover.getWidth(), cover.getHeight()) / 120.0f; + if (scale > 0) { + smallCover = Bitmap.createScaledBitmap(cover, (int) (cover.getWidth() / scale), (int) (cover.getHeight() / scale), true); + } else { + smallCover = cover; + } + if (smallCover == null) { + smallCover = cover; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + break; + case "cpil": + compilation = atom.readBoolean(); + break; + case "cprt": + case "©cpy": + if (copyright == null || copyright.trim().length() == 0) { + copyright = atom.readString(UTF_8); + } + break; + case "©day": + String day = atom.readString(UTF_8).trim(); + if (day.length() >= 4) { + try { + year = Short.valueOf(day.substring(0, 4)); + } catch (NumberFormatException e) { + // ignore + } + } + break; + case "disk": + atom.skip(2); // padding? + disc = atom.readShort(); + discs = atom.readShort(); + break; + case "gnre": + if (genre == null || genre.trim().length() == 0) { + if (atom.getRemaining() == 2) { // id3v1 genre? + int index = atom.readShort() - 1; + ID3v1Genre id3v1Genre = ID3v1Genre.getGenre(index); + if (id3v1Genre != null) { + genre = id3v1Genre.getDescription(); + } + } else { + genre = atom.readString(UTF_8); + } + } + break; + case "©gen": + if (genre == null || genre.trim().length() == 0) { + genre = atom.readString(UTF_8); + } + break; + case "©grp": + grouping = atom.readString(UTF_8); + break; + case "©lyr": + lyrics = atom.readString(UTF_8); + break; + case "©nam": + title = atom.readString(UTF_8); + break; + case "rtng": + rating = atom.readByte(); + break; + case "tmpo": + tempo = atom.readShort(); + break; + case "trkn": + atom.skip(2); // padding? + track = atom.readShort(); + tracks = atom.readShort(); + break; + default: + break; + } + } + + public short getTempo() { + return tempo; + } + + public byte getRating() { + return rating; + } + + public BigDecimal getSpeed() { + return speed; + } + + public BigDecimal getVolume() { + return volume; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/MP4Atom.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/MP4Atom.java new file mode 100644 index 00000000..1520b8b1 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/MP4Atom.java @@ -0,0 +1,151 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.m4a; + +import org.telegram.messenger.audioinfo.util.RangeInputStream; + +import java.io.EOFException; +import java.io.IOException; +import java.math.BigDecimal; + +public class MP4Atom extends MP4Box { + public MP4Atom(RangeInputStream input, MP4Box parent, String type) { + super(input, parent, type); + } + + public long getLength() { + return getInput().getPosition() + getInput().getRemainingLength(); + } + + public long getOffset() { + return getParent().getPosition() - getPosition(); + } + + public long getRemaining() { + return getInput().getRemainingLength(); + } + + public boolean hasMoreChildren() { + return (getChild() != null ? getChild().getRemaining() : 0) < getRemaining(); + } + + public MP4Atom nextChildUpTo(String expectedTypeExpression) throws IOException { + while (getRemaining() > 0) { + MP4Atom atom = nextChild(); + if (atom.getType().matches(expectedTypeExpression)) { + return atom; + } + } + throw new IOException("atom type mismatch, not found: " + expectedTypeExpression); + } + + public boolean readBoolean() throws IOException { + return data.readBoolean(); + } + + public byte readByte() throws IOException { + return data.readByte(); + } + + public short readShort() throws IOException { + return data.readShort(); + } + + public int readInt() throws IOException { + return data.readInt(); + } + + public long readLong() throws IOException { + return data.readLong(); + } + + public byte[] readBytes(int len) throws IOException { + byte[] bytes = new byte[len]; + data.readFully(bytes); + return bytes; + } + + public byte[] readBytes() throws IOException { + return readBytes((int) getRemaining()); + } + + public BigDecimal readShortFixedPoint() throws IOException { + int integer = data.readByte(); + int decimal = data.readUnsignedByte(); + return new BigDecimal(String.valueOf(integer) + "" + String.valueOf(decimal)); + } + + public BigDecimal readIntegerFixedPoint() throws IOException { + int integer = data.readShort(); + int decimal = data.readUnsignedShort(); + return new BigDecimal(String.valueOf(integer) + "" + String.valueOf(decimal)); + } + + public String readString(int len, String enc) throws IOException { + String s = new String(readBytes(len), enc); + int end = s.indexOf(0); + return end < 0 ? s : s.substring(0, end); + } + + public String readString(String enc) throws IOException { + return readString((int) getRemaining(), enc); + } + + public void skip(int len) throws IOException { + int total = 0; + while (total < len) { + int current = data.skipBytes(len - total); + if (current > 0) { + total += current; + } else { + throw new EOFException(); + } + } + } + + public void skip() throws IOException { + while (getRemaining() > 0) { + if (getInput().skip(getRemaining()) == 0) { + throw new EOFException("Cannot skip atom"); + } + } + } + + private StringBuffer appendPath(StringBuffer s, MP4Box box) { + if (box.getParent() != null) { + appendPath(s, box.getParent()); + s.append("/"); + } + return s.append(box.getType()); + } + + public String getPath() { + return appendPath(new StringBuffer(), this).toString(); + } + + public String toString() { + StringBuffer s = new StringBuffer(); + appendPath(s, this); + s.append("[off="); + s.append(getOffset()); + s.append(",pos="); + s.append(getPosition()); + s.append(",len="); + s.append(getLength()); + s.append("]"); + return s.toString(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/MP4Box.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/MP4Box.java new file mode 100644 index 00000000..b8fae44e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/MP4Box.java @@ -0,0 +1,87 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.m4a; + +import org.telegram.messenger.audioinfo.util.PositionInputStream; +import org.telegram.messenger.audioinfo.util.RangeInputStream; + +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.IOException; + +public class MP4Box { + protected static final String ASCII = "ISO8859_1"; + + private final I input; + private final MP4Box parent; + private final String type; + + protected final DataInput data; + + private MP4Atom child; + + public MP4Box(I input, MP4Box parent, String type) { + this.input = input; + this.parent = parent; + this.type = type; + this.data = new DataInputStream(input); + } + + public String getType() { + return type; + } + + public MP4Box getParent() { + return parent; + } + + public long getPosition() { + return input.getPosition(); + } + + public I getInput() { + return input; + } + + protected MP4Atom getChild() { + return child; + } + + public MP4Atom nextChild() throws IOException { + if (child != null) { + child.skip(); + } + int atomLength = data.readInt(); + byte[] typeBytes = new byte[4]; + data.readFully(typeBytes); + String atomType = new String(typeBytes, ASCII); + RangeInputStream atomInput; + if (atomLength == 1) { // extended length + atomInput = new RangeInputStream(input, 16, data.readLong() - 16); + } else { + atomInput = new RangeInputStream(input, 8, atomLength - 8); + } + return child = new MP4Atom(atomInput, this, atomType); + } + + public MP4Atom nextChild(String expectedTypeExpression) throws IOException { + MP4Atom atom = nextChild(); + if (atom.getType().matches(expectedTypeExpression)) { + return atom; + } + throw new IOException("atom type mismatch, expected " + expectedTypeExpression + ", got " + atom.getType()); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/MP4Input.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/MP4Input.java new file mode 100644 index 00000000..bd149171 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/m4a/MP4Input.java @@ -0,0 +1,41 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.m4a; + +import org.telegram.messenger.audioinfo.util.PositionInputStream; + +import java.io.IOException; +import java.io.InputStream; + +public final class MP4Input extends MP4Box { + + public MP4Input(InputStream delegate) { + super(new PositionInputStream(delegate), null, ""); + } + + public MP4Atom nextChildUpTo(String expectedTypeExpression) throws IOException { + while (true) { + MP4Atom atom = nextChild(); + if (atom.getType().matches(expectedTypeExpression)) { + return atom; + } + } + } + + public String toString() { + return "mp4[pos=" + getPosition() + "]"; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v1Genre.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v1Genre.java new file mode 100644 index 00000000..6b6f5587 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v1Genre.java @@ -0,0 +1,171 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.mp3; + +public enum ID3v1Genre { + /* + * The following genres is defined in ID3v1 (0-79) + */ + Blues("Blues"), + ClassicRock("Classic Rock"), + Country("Country"), + Dance("Dance"), + Disco("Disco"), + Funk("Funk"), + Grunge("Grunge"), + HipHop("Hip-Hop"), + Jazz("Jazz"), + Metal("Metal"), + NewAge("New Age"), + Oldies("Oldies"), + Other("Other"), + Pop("Pop"), + RnB("R&B"), + Rap("Rap"), + Reggae("Reggae"), + Rock("Rock"), + Techno("Techno"), + Industrial("Industrial"), + Alternative("Alternative"), + Ska("Ska"), + DeathMetal("Death Metal"), + Pranks("Pranks"), + Soundtrack("Soundtrack"), + EuroTechno("Euro-Techno"), + Ambient("Ambient"), + TripHop("Trip-Hop"), + Vocal("Vocal"), + JazzFunk("Jazz+Funk"), + Fusion("Fusion"), + Trance("Trance"), + Classical("Classical"), + Instrumental("Instrumental"), + Acid("Acid"), + House("House"), + Game("Game"), + SoundClip("Sound Clip"), + Gospel("Gospel"), + Noise("Noise"), + AlternRock("AlternRock"), + Bass("Bass"), + Soul("Soul"), + Punk("Punk"), + Space("Space"), + Meditative("Meditative"), + InstrumentalPop("Instrumental Pop"), + InstrumentalRock("Instrumental Rock"), + Ethnic("Ethnic"), + Gothic("Gothic"), + Darkwave("Darkwave"), + TechnoIndustrial("Techno-Industrial"), + Electronic("Electronic"), + PopFolk("Pop-Folk"), + Eurodance("Eurodance"), + Dream("Dream"), + SouthernRock("Southern Rock"), + Comedy("Comedy"), + Cult("Cult"), + Gangsta("Gangsta"), + Top40("Top 40"), + ChristianRap("Christian Rap"), + PopFunk("Pop/Funk"), + Jungle("Jungle"), + NativeAmerican("Native American"), + Cabaret("Cabaret"), + NewWave("New Wave"), + Psychadelic("Psychadelic"), + Rave("Rave"), + Showtunes("Showtunes"), + Trailer("Trailer"), + LoFi("Lo-Fi"), + Tribal("Tribal"), + AcidPunk("Acid Punk"), + AcidJazz("Acid Jazz"), + Polka("Polka"), + Retro("Retro"), + Musical("Musical"), + RockAndRoll("Rock & Roll"), + HardRock("Hard Rock"), + + /* + * The following genres are Winamp extensions (80-125) + */ + Folk("Folk"), + FolkRock("Folk-Rock"), + NationalFolk("National Folk"), + Swing("Swing"), + FastFusion("Fast Fusion"), + Bebop("Bebop"), + Latin("Latin"), + Revival("Revival"), + Celtic("Celtic"), + Bluegrass("Bluegrass"), + Avantgarde("Avantgarde"), + GothicRock("Gothic Rock"), + ProgressiveRock("Progressive Rock"), + PsychedelicRock("Psychedelic Rock"), + SymphonicRock("Symphonic Rock"), + SlowRock("Slow Rock"), + BigBand("Big Band"), + Chorus("Chorus"), + EasyListening("Easy Listening"), + Acoustic("Acoustic"), + Humour("Humour"), + Speech("Speech"), + Chanson("Chanson"), + Opera("Opera"), + ChamberMusic("Chamber Music"), + Sonata("Sonata"), + Symphony("Symphony"), + BootyBass("Booty Bass"), + Primus("Primus"), + PornGroove("Porn Groove"), + Satire("Satire"), + SlowJam("Slow Jam"), + Club("Club"), + Tango("Tango"), + Samba("Samba"), + Folklore("Folklore"), + Ballad("Ballad"), + PowerBallad("Power Ballad"), + RhytmicSoul("Rhythmic Soul"), + Freestyle("Freestyle"), + Duet("Duet"), + PunkRock("Punk Rock"), + DrumSolo("Drum Solo"), + ACapella("A capella"), + EuroHouse("Euro-House"), + DanceHall("Dance Hall"); + + public static ID3v1Genre getGenre(int id) { + ID3v1Genre[] values = values(); + return id >= 0 && id < values.length ? values[id] : null; + } + + private final String description; + + ID3v1Genre(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } + + public int getId() { + return ordinal(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v1Info.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v1Info.java new file mode 100644 index 00000000..eb99c504 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v1Info.java @@ -0,0 +1,86 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.mp3; + +import org.telegram.messenger.audioinfo.AudioInfo; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +public class ID3v1Info extends AudioInfo { + public static boolean isID3v1StartPosition(InputStream input) throws IOException { + input.mark(3); + try { + return input.read() == 'T' && input.read() == 'A' && input.read() == 'G'; + } finally { + input.reset(); + } + } + + public ID3v1Info(InputStream input) throws IOException { + if (isID3v1StartPosition(input)) { + brand = "ID3"; + version = "1.0"; + byte[] bytes = readBytes(input, 128); + title = extractString(bytes, 3, 30); + artist = extractString(bytes, 33, 30); + album = extractString(bytes, 63, 30); + try { + year = Short.parseShort(extractString(bytes, 93, 4)); + } catch (NumberFormatException e) { + year = 0; + } + comment = extractString(bytes, 97, 30); + ID3v1Genre id3v1Genre = ID3v1Genre.getGenre(bytes[127]); + if (id3v1Genre != null) { + genre = id3v1Genre.getDescription(); + } + + /* + * ID3v1.1 + */ + if (bytes[125] == 0 && bytes[126] != 0) { + version = "1.1"; + track = (short) (bytes[126] & 0xFF); + } + } + } + + byte[] readBytes(InputStream input, int len) throws IOException { + int total = 0; + byte[] bytes = new byte[len]; + while (total < len) { + int current = input.read(bytes, total, len - total); + if (current > 0) { + total += current; + } else { + throw new EOFException(); + } + } + return bytes; + } + + String extractString(byte[] bytes, int offset, int length) { + try { + String text = new String(bytes, offset, length, "ISO-8859-1"); + int zeroIndex = text.indexOf(0); + return zeroIndex < 0 ? text : text.substring(0, zeroIndex); + } catch (Exception e) { + return ""; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2DataInput.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2DataInput.java new file mode 100644 index 00000000..08b23e53 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2DataInput.java @@ -0,0 +1,74 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.mp3; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +public class ID3v2DataInput { + private final InputStream input; + + public ID3v2DataInput(InputStream in) { + this.input = in; + } + + public final void readFully(byte b[], int off, int len) throws IOException { + int total = 0; + while (total < len) { + int current = input.read(b, off + total, len - total); + if (current > 0) { + total += current; + } else { + throw new EOFException(); + } + } + } + + public byte[] readFully(int len) throws IOException { + byte[] bytes = new byte[len]; + readFully(bytes, 0, len); + return bytes; + } + + public void skipFully(long len) throws IOException { + long total = 0; + while (total < len) { + long current = input.skip(len - total); + if (current > 0) { + total += current; + } else { + throw new EOFException(); + } + } + } + + public byte readByte() throws IOException { + int b = input.read(); + if (b < 0) { + throw new EOFException(); + } + return (byte) b; + } + + public int readInt() throws IOException { + return ((readByte() & 0xFF) << 24) | ((readByte() & 0xFF) << 16) | ((readByte() & 0xFF) << 8) | (readByte() & 0xFF); + } + + public int readSyncsafeInt() throws IOException { + return ((readByte() & 0x7F) << 21) | ((readByte() & 0x7F) << 14) | ((readByte() & 0x7F) << 7) | (readByte() & 0x7F); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Encoding.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Encoding.java new file mode 100644 index 00000000..8024d6f7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Encoding.java @@ -0,0 +1,41 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.mp3; + +import java.nio.charset.Charset; + +public enum ID3v2Encoding { + ISO_8859_1(Charset.forName("ISO-8859-1"), 1), + UTF_16(Charset.forName("UTF-16"), 2), + UTF_16BE(Charset.forName("UTF-16BE"), 2), + UTF_8(Charset.forName("UTF-8"), 1); + + private final Charset charset; + private final int zeroBytes; + + ID3v2Encoding(Charset charset, int zeroBytes) { + this.charset = charset; + this.zeroBytes = zeroBytes; + } + + public Charset getCharset() { + return charset; + } + + public int getZeroBytes() { + return zeroBytes; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Exception.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Exception.java new file mode 100644 index 00000000..a61e8da5 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Exception.java @@ -0,0 +1,24 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.mp3; + +public class ID3v2Exception extends Exception { + private static final long serialVersionUID = 1L; + + public ID3v2Exception(String message) { + super(message); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2FrameBody.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2FrameBody.java new file mode 100644 index 00000000..d003f064 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2FrameBody.java @@ -0,0 +1,155 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.mp3; + +import org.telegram.messenger.audioinfo.util.RangeInputStream; + +import java.io.IOException; +import java.io.InputStream; + +public class ID3v2FrameBody { + + static final class Buffer { + byte[] bytes; + + Buffer(int initialLength) { + bytes = new byte[initialLength]; + } + + byte[] bytes(int minLength) { + if (minLength > bytes.length) { + int length = bytes.length * 2; + while (minLength > length) { + length *= 2; + } + bytes = new byte[length]; + } + return bytes; + } + } + + static final ThreadLocal textBuffer = new ThreadLocal() { + @Override + protected Buffer initialValue() { + return new Buffer(4096); + } + }; + + private final RangeInputStream input; + private final ID3v2TagHeader tagHeader; + private final ID3v2FrameHeader frameHeader; + private final ID3v2DataInput data; + + ID3v2FrameBody(InputStream delegate, long position, int dataLength, ID3v2TagHeader tagHeader, ID3v2FrameHeader frameHeader) throws IOException { + this.input = new RangeInputStream(delegate, position, dataLength); + this.data = new ID3v2DataInput(input); + this.tagHeader = tagHeader; + this.frameHeader = frameHeader; + } + + public ID3v2DataInput getData() { + return data; + } + + public long getPosition() { + return input.getPosition(); + } + + public long getRemainingLength() { + return input.getRemainingLength(); + } + + public ID3v2TagHeader getTagHeader() { + return tagHeader; + } + + public ID3v2FrameHeader getFrameHeader() { + return frameHeader; + } + + private String extractString(byte[] bytes, int offset, int length, ID3v2Encoding encoding, boolean searchZeros) { + if (searchZeros) { + int zeros = 0; + for (int i = 0; i < length; i++) { + // UTF-16LE may have a zero byte as second byte of a 2-byte character -> skip first zero at odd index + if (bytes[offset + i] == 0 && (encoding != ID3v2Encoding.UTF_16 || zeros != 0 || (offset + i) % 2 == 0)) { + if (++zeros == encoding.getZeroBytes()) { + length = i + 1 - encoding.getZeroBytes(); + break; + } + } else { + zeros = 0; + } + } + } + try { + String string = new String(bytes, offset, length, encoding.getCharset().name()); + if (string.length() > 0 && string.charAt(0) == '\uFEFF') { // remove BOM + string = string.substring(1); + } + return string; + } catch (Exception e) { + return ""; + } + } + + public String readZeroTerminatedString(int maxLength, ID3v2Encoding encoding) throws IOException, ID3v2Exception { + int zeros = 0; + int length = Math.min(maxLength, (int) getRemainingLength()); + byte[] bytes = textBuffer.get().bytes(length); + for (int i = 0; i < length; i++) { + // UTF-16LE may have a zero byte as second byte of a 2-byte character -> skip first zero at odd index + if ((bytes[i] = data.readByte()) == 0 && (encoding != ID3v2Encoding.UTF_16 || zeros != 0 || i % 2 == 0)) { + if (++zeros == encoding.getZeroBytes()) { + return extractString(bytes, 0, i + 1 - encoding.getZeroBytes(), encoding, false); + } + } else { + zeros = 0; + } + } + throw new ID3v2Exception("Could not read zero-termiated string"); + } + + public String readFixedLengthString(int length, ID3v2Encoding encoding) throws IOException, ID3v2Exception { + if (length > getRemainingLength()) { + throw new ID3v2Exception("Could not read fixed-length string of length: " + length); + } + byte[] bytes = textBuffer.get().bytes(length); + data.readFully(bytes, 0, length); + return extractString(bytes, 0, length, encoding, true); + } + + public ID3v2Encoding readEncoding() throws IOException, ID3v2Exception { + byte value = data.readByte(); + switch (value) { + case 0: + return ID3v2Encoding.ISO_8859_1; + case 1: + return ID3v2Encoding.UTF_16; + case 2: + return ID3v2Encoding.UTF_16BE; + case 3: + return ID3v2Encoding.UTF_8; + default: + break; + } + throw new ID3v2Exception("Invalid encoding: " + value); + } + + public String toString() { + return "id3v2frame[pos=" + getPosition() + ", " + getRemainingLength() + " left]"; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2FrameHeader.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2FrameHeader.java new file mode 100644 index 00000000..bb8ce760 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2FrameHeader.java @@ -0,0 +1,165 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.mp3; + +import java.io.IOException; + +public class ID3v2FrameHeader { + private String frameId; + private int headerSize; + private int bodySize; + private boolean unsynchronization; + private boolean compression; + private boolean encryption; + private int dataLengthIndicator; + + public ID3v2FrameHeader(ID3v2TagBody input) throws IOException, ID3v2Exception { + long startPosition = input.getPosition(); + + ID3v2DataInput data = input.getData(); + + /* + * Frame Id + */ + if (input.getTagHeader().getVersion() == 2) { // $xx xx xx (three characters) + frameId = new String(data.readFully(3), "ISO-8859-1"); + } else { // $xx xx xx xx (four characters) + frameId = new String(data.readFully(4), "ISO-8859-1"); + } + + /* + * Size + */ + if (input.getTagHeader().getVersion() == 2) { // $xx xx xx + bodySize = ((data.readByte() & 0xFF) << 16) | ((data.readByte() & 0xFF) << 8) | (data.readByte() & 0xFF); + } else if (input.getTagHeader().getVersion() == 3) { // $xx xx xx xx + bodySize = data.readInt(); + } else { // 4 * %0xxxxxxx (sync-save integer) + bodySize = data.readSyncsafeInt(); + } + + /* + * Flags + */ + if (input.getTagHeader().getVersion() > 2) { // $xx xx + data.readByte(); // status flags + byte formatFlags = data.readByte(); + int compressionMask; + int encryptionMask; + int groupingIdentityMask; + int unsynchronizationMask = 0x00; + int dataLengthIndicatorMask = 0x00; + if (input.getTagHeader().getVersion() == 3) { // %(compression)(encryption)(groupingIdentity)00000 + compressionMask = 0x80; + encryptionMask = 0x40; + groupingIdentityMask = 0x20; + } else { // %0(groupingIdentity)00(compression)(encryption)(unsynchronization)(dataLengthIndicator) + groupingIdentityMask = 0x40; + compressionMask = 0x08; + encryptionMask = 0x04; + unsynchronizationMask = 0x02; + dataLengthIndicatorMask = 0x01; + } + compression = (formatFlags & compressionMask) != 0; + unsynchronization = (formatFlags & unsynchronizationMask) != 0; + encryption = (formatFlags & encryptionMask) != 0; + + /* + * Read flag attachments in the order of the flags (version dependent). + */ + if (input.getTagHeader().getVersion() == 3) { + if (compression) { + dataLengthIndicator = data.readInt(); + bodySize -= 4; + } + if (encryption) { + data.readByte(); // just skip + bodySize -= 1; + } + if ((formatFlags & groupingIdentityMask) != 0) { + data.readByte(); // just skip + bodySize -= 1; + } + } else { + if ((formatFlags & groupingIdentityMask) != 0) { + data.readByte(); // just skip + bodySize -= 1; + } + if (encryption) { + data.readByte(); // just skip + bodySize -= 1; + } + if ((formatFlags & dataLengthIndicatorMask) != 0) { + dataLengthIndicator = data.readSyncsafeInt(); + bodySize -= 4; + } + } + } + + headerSize = (int) (input.getPosition() - startPosition); + } + + public String getFrameId() { + return frameId; + } + + public int getHeaderSize() { + return headerSize; + } + + public int getBodySize() { + return bodySize; + } + + public boolean isCompression() { + return compression; + } + + public boolean isEncryption() { + return encryption; + } + + public boolean isUnsynchronization() { + return unsynchronization; + } + + public int getDataLengthIndicator() { + return dataLengthIndicator; + } + + public boolean isValid() { + for (int i = 0; i < frameId.length(); i++) { + if ((frameId.charAt(i) < 'A' || frameId.charAt(i) > 'Z') && (frameId.charAt(i) < '0' || frameId.charAt(i) > '9')) { + return false; + } + } + return bodySize > 0; + } + + public boolean isPadding() { + for (int i = 0; i < frameId.length(); i++) { + if (frameId.charAt(0) != 0) { + return false; + } + } + return bodySize == 0; + } + + @Override + public String toString() { + return String.format("%s[id=%s, bodysize=%d]", getClass().getSimpleName(), frameId, bodySize); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Info.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Info.java new file mode 100644 index 00000000..4ea6b886 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2Info.java @@ -0,0 +1,376 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.mp3; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; + +import org.telegram.messenger.audioinfo.AudioInfo; + +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class ID3v2Info extends AudioInfo { + static final Logger LOGGER = Logger.getLogger(ID3v2Info.class.getName()); + + static class AttachedPicture { + static final byte TYPE_OTHER = 0x00; + static final byte TYPE_COVER_FRONT = 0x03; + + final byte type; + final String description; + final String imageType; + final byte[] imageData; + + public AttachedPicture(byte type, String description, String imageType, byte[] imageData) { + this.type = type; + this.description = description; + this.imageType = imageType; + this.imageData = imageData; + } + } + + static class CommentOrUnsynchronizedLyrics { + final String language; + final String description; + final String text; + + public CommentOrUnsynchronizedLyrics(String language, String description, String text) { + this.language = language; + this.description = description; + this.text = text; + } + } + + public static boolean isID3v2StartPosition(InputStream input) throws IOException { + input.mark(3); + try { + return input.read() == 'I' && input.read() == 'D' && input.read() == '3'; + } finally { + input.reset(); + } + } + + private final Level debugLevel; + + private byte coverPictureType; + + public ID3v2Info(InputStream input) throws IOException, ID3v2Exception { + this(input, Level.FINEST); + } + + public ID3v2Info(InputStream input, Level debugLevel) throws IOException, ID3v2Exception { + this.debugLevel = debugLevel; + if (isID3v2StartPosition(input)) { + ID3v2TagHeader tagHeader = new ID3v2TagHeader(input); + brand = "ID3"; + version = String.format("2.%d.%d", tagHeader.getVersion(), tagHeader.getRevision()); + ID3v2TagBody tagBody = tagHeader.tagBody(input); + try { + while (tagBody.getRemainingLength() > 10) { // TODO > tag.minimumFrameSize() + ID3v2FrameHeader frameHeader = new ID3v2FrameHeader(tagBody); + if (frameHeader.isPadding()) { // we ran into padding + break; + } + if (frameHeader.getBodySize() > tagBody.getRemainingLength()) { // something wrong... + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, "ID3 frame claims to extend frames area"); + } + break; + } + if (frameHeader.isValid() && !frameHeader.isEncryption()) { + ID3v2FrameBody frameBody = tagBody.frameBody(frameHeader); + try { + parseFrame(frameBody); + } catch (ID3v2Exception e) { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, String.format("ID3 exception occured in frame %s: %s", frameHeader.getFrameId(), e.getMessage())); + } + } finally { + frameBody.getData().skipFully(frameBody.getRemainingLength()); + } + } else { + tagBody.getData().skipFully(frameHeader.getBodySize()); + } + } + } catch (ID3v2Exception e) { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, "ID3 exception occured: " + e.getMessage()); + } + } + tagBody.getData().skipFully(tagBody.getRemainingLength()); + if (tagHeader.getFooterSize() > 0) { + input.skip(tagHeader.getFooterSize()); + } + } + } + + void parseFrame(ID3v2FrameBody frame) throws IOException, ID3v2Exception { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, "Parsing frame: " + frame.getFrameHeader().getFrameId()); + } + switch (frame.getFrameHeader().getFrameId()) { + case "PIC": + case "APIC": // cover: prefer TYPE_COVER_FRONT, then TYPE_OTHER, then anything else + if (cover == null || coverPictureType != AttachedPicture.TYPE_COVER_FRONT) { + AttachedPicture picture = parseAttachedPictureFrame(frame); + if (cover == null || picture.type == AttachedPicture.TYPE_COVER_FRONT || picture.type == AttachedPicture.TYPE_OTHER) { + try { + byte[] bytes = picture.imageData; + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inJustDecodeBounds = true; + opts.inSampleSize = 1; + BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts); + if (opts.outWidth > 800 || opts.outHeight > 800) { + int size = Math.max(opts.outWidth, opts.outHeight); + while (size > 800) { + opts.inSampleSize *= 2; + size /= 2; + } + } + opts.inJustDecodeBounds = false; + cover = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts); + if (cover != null) { + float scale = Math.max(cover.getWidth(), cover.getHeight()) / 120.0f; + if (scale > 0) { + smallCover = Bitmap.createScaledBitmap(cover, (int) (cover.getWidth() / scale), (int) (cover.getHeight() / scale), true); + } else { + smallCover = cover; + } + if (smallCover == null) { + smallCover = cover; + } + } + } catch (Throwable e) { + e.printStackTrace(); + } + coverPictureType = picture.type; + } + } + break; + case "COM": + case "COMM": + CommentOrUnsynchronizedLyrics comm = parseCommentOrUnsynchronizedLyricsFrame(frame); + if (comment == null || comm.description == null || "".equals(comm.description)) { // prefer "default" comment (without description) + comment = comm.text; + } + break; + case "TAL": + case "TALB": + album = parseTextFrame(frame); + break; + case "TCP": + case "TCMP": + compilation = "1".equals(parseTextFrame(frame)); + break; + case "TCM": + case "TCOM": + composer = parseTextFrame(frame); + break; + case "TCO": + case "TCON": + String tcon = parseTextFrame(frame); + if (tcon.length() > 0) { + genre = tcon; + try { + ID3v1Genre id3v1Genre = null; + if (tcon.charAt(0) == '(') { + int pos = tcon.indexOf(')'); + if (pos > 1) { // (123) + id3v1Genre = ID3v1Genre.getGenre(Integer.parseInt(tcon.substring(1, pos))); + if (id3v1Genre == null && tcon.length() > pos + 1) { // (789)Special + genre = tcon.substring(pos + 1); + } + } + } else { // 123 + id3v1Genre = ID3v1Genre.getGenre(Integer.parseInt(tcon)); + } + if (id3v1Genre != null) { + genre = id3v1Genre.getDescription(); + } + } catch (NumberFormatException e) { + // ignore + } + } + break; + case "TCR": + case "TCOP": + copyright = parseTextFrame(frame); + break; + case "TDRC": // v2.4, replaces TYER + String tdrc = parseTextFrame(frame); + if (tdrc.length() >= 4) { + try { + year = Short.valueOf(tdrc.substring(0, 4)); + } catch (NumberFormatException e) { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, "Could not parse year from: " + tdrc); + } + } + } + break; + case "TLE": + case "TLEN": + String tlen = parseTextFrame(frame); + try { + duration = Long.valueOf(tlen); + } catch (NumberFormatException e) { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, "Could not parse track duration: " + tlen); + } + } + break; + case "TP1": + case "TPE1": + artist = parseTextFrame(frame); + break; + case "TP2": + case "TPE2": + albumArtist = parseTextFrame(frame); + break; + case "TPA": + case "TPOS": + String tpos = parseTextFrame(frame); + if (tpos.length() > 0) { + int index = tpos.indexOf('/'); + if (index < 0) { + try { + disc = Short.valueOf(tpos); + } catch (NumberFormatException e) { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, "Could not parse disc number: " + tpos); + } + } + } else { + try { + disc = Short.valueOf(tpos.substring(0, index)); + } catch (NumberFormatException e) { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, "Could not parse disc number: " + tpos); + } + } + try { + discs = Short.valueOf(tpos.substring(index + 1)); + } catch (NumberFormatException e) { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, "Could not parse number of discs: " + tpos); + } + } + } + } + break; + case "TRK": + case "TRCK": + String trck = parseTextFrame(frame); + if (trck.length() > 0) { + int index = trck.indexOf('/'); + if (index < 0) { + try { + track = Short.valueOf(trck); + } catch (NumberFormatException e) { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, "Could not parse track number: " + trck); + } + } + } else { + try { + track = Short.valueOf(trck.substring(0, index)); + } catch (NumberFormatException e) { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, "Could not parse track number: " + trck); + } + } + try { + tracks = Short.valueOf(trck.substring(index + 1)); + } catch (NumberFormatException e) { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, "Could not parse number of tracks: " + trck); + } + } + } + } + break; + case "TT1": + case "TIT1": + grouping = parseTextFrame(frame); + break; + case "TT2": + case "TIT2": + title = parseTextFrame(frame); + break; + case "TYE": + case "TYER": + String tyer = parseTextFrame(frame); + if (tyer.length() > 0) { + try { + year = Short.valueOf(tyer); + } catch (NumberFormatException e) { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, "Could not parse year: " + tyer); + } + } + } + break; + case "ULT": + case "USLT": + if (lyrics == null) { + lyrics = parseCommentOrUnsynchronizedLyricsFrame(frame).text; + } + break; + default: + break; + } + } + + String parseTextFrame(ID3v2FrameBody frame) throws IOException, ID3v2Exception { + ID3v2Encoding encoding = frame.readEncoding(); + return frame.readFixedLengthString((int) frame.getRemainingLength(), encoding); + } + + CommentOrUnsynchronizedLyrics parseCommentOrUnsynchronizedLyricsFrame(ID3v2FrameBody data) throws IOException, ID3v2Exception { + ID3v2Encoding encoding = data.readEncoding(); + String language = data.readFixedLengthString(3, ID3v2Encoding.ISO_8859_1); + String description = data.readZeroTerminatedString(200, encoding); + String text = data.readFixedLengthString((int) data.getRemainingLength(), encoding); + return new CommentOrUnsynchronizedLyrics(language, description, text); + } + + AttachedPicture parseAttachedPictureFrame(ID3v2FrameBody data) throws IOException, ID3v2Exception { + ID3v2Encoding encoding = data.readEncoding(); + String imageType; + if (data.getTagHeader().getVersion() == 2) { // file type, e.g. "JPG" + String fileType = data.readFixedLengthString(3, ID3v2Encoding.ISO_8859_1); + switch (fileType.toUpperCase()) { + case "PNG": + imageType = "image/png"; + break; + case "JPG": + imageType = "image/jpeg"; + break; + default: + imageType = "image/unknown"; + } + } else { // mime type, e.g. "image/jpeg" + imageType = data.readZeroTerminatedString(20, ID3v2Encoding.ISO_8859_1); + } + byte pictureType = data.getData().readByte(); + String description = data.readZeroTerminatedString(200, encoding); + byte[] imageData = data.getData().readFully((int) data.getRemainingLength()); + return new AttachedPicture(pictureType, description, imageType, imageData); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2TagBody.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2TagBody.java new file mode 100644 index 00000000..c6c52f2d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2TagBody.java @@ -0,0 +1,81 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.mp3; + +import org.telegram.messenger.audioinfo.util.RangeInputStream; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.zip.InflaterInputStream; + +public class ID3v2TagBody { + private final RangeInputStream input; + private final ID3v2TagHeader tagHeader; + private final ID3v2DataInput data; + + ID3v2TagBody(InputStream delegate, long position, int length, ID3v2TagHeader tagHeader) throws IOException { + this.input = new RangeInputStream(delegate, position, length); + this.data = new ID3v2DataInput(input); + this.tagHeader = tagHeader; + } + + public ID3v2DataInput getData() { + return data; + } + + public long getPosition() { + return input.getPosition(); + } + + public long getRemainingLength() { + return input.getRemainingLength(); + } + + public ID3v2TagHeader getTagHeader() { + return tagHeader; + } + + public ID3v2FrameBody frameBody(ID3v2FrameHeader frameHeader) throws IOException, ID3v2Exception { + int dataLength = frameHeader.getBodySize(); + InputStream input = this.input; + if (frameHeader.isUnsynchronization()) { + byte[] bytes = data.readFully(frameHeader.getBodySize()); + boolean ff = false; + int len = 0; + for (byte b : bytes) { + if (!ff || b != 0) { + bytes[len++] = b; + } + ff = (b == 0xFF); + } + dataLength = len; + input = new ByteArrayInputStream(bytes, 0, len); + } + if (frameHeader.isEncryption()) { + throw new ID3v2Exception("Frame encryption is not supported"); + } + if (frameHeader.isCompression()) { + dataLength = frameHeader.getDataLengthIndicator(); + input = new InflaterInputStream(input); + } + return new ID3v2FrameBody(input, frameHeader.getHeaderSize(), dataLength, tagHeader, frameHeader); + } + + public String toString() { + return "id3v2tag[pos=" + getPosition() + ", " + getRemainingLength() + " left]"; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2TagHeader.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2TagHeader.java new file mode 100644 index 00000000..79adf8d3 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/ID3v2TagHeader.java @@ -0,0 +1,191 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.mp3; + +import org.telegram.messenger.audioinfo.util.PositionInputStream; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class ID3v2TagHeader { + private int version = 0; + private int revision = 0; + private int headerSize = 0; // size of header, including extended header (with attachments) + private int totalTagSize = 0; // everything, i.e. inluding tag header, extended header, footer & padding + private int paddingSize = 0; // size of zero padding after frames + private int footerSize = 0; // size of footer (version 4 only) + private boolean unsynchronization; + private boolean compression; + + public ID3v2TagHeader(InputStream input) throws IOException, ID3v2Exception { + this(new PositionInputStream(input)); + } + + ID3v2TagHeader(PositionInputStream input) throws IOException, ID3v2Exception { + long startPosition = input.getPosition(); + + ID3v2DataInput data = new ID3v2DataInput(input); + + /* + * Identifier: "ID3" + */ + String id = new String(data.readFully(3), "ISO-8859-1"); + if (!"ID3".equals(id)) { + throw new ID3v2Exception("Invalid ID3 identifier: " + id); + } + + /* + * Version: $02, $03 or $04 + */ + version = data.readByte(); + if (version != 2 && version != 3 && version != 4) { + throw new ID3v2Exception("Unsupported ID3v2 version: " + version); + } + + /* + * Revision: $xx + */ + revision = data.readByte(); + + /* + * Flags (evaluated below) + */ + byte flags = data.readByte(); + + /* + * Size: 4 * %0xxxxxxx (sync-save integer) + */ + totalTagSize = 10 + data.readSyncsafeInt(); + + /* + * Evaluate flags + */ + if (version == 2) { // %(unsynchronisation)(compression)000000 + unsynchronization = (flags & 0x80) != 0; + compression = (flags & 0x40) != 0; + } else { // %(unsynchronisation)(extendedHeader)(experimentalIndicator)(version == 3 ? 0 : footerPresent)0000 + unsynchronization = (flags & 0x80) != 0; + + /* + * Extended Header + */ + if ((flags & 0x40) != 0) { + if (version == 3) { + /* + * Extended header size: $xx xx xx xx (6 or 10 if CRC data present) + * In version 3, the size excludes itself. + */ + int extendedHeaderSize = data.readInt(); + + /* + * Extended Flags: $xx xx (skip) + */ + data.readByte(); // flags... + data.readByte(); // more flags... + + /* + * Size of padding: $xx xx xx xx + */ + paddingSize = data.readInt(); + + /* + * consume the rest + */ + data.skipFully(extendedHeaderSize - 6); + } else { + /* + * Extended header size: 4 * %0xxxxxxx (sync-save integer) + * In version 4, the size includes itself. + */ + int extendedHeaderSize = data.readSyncsafeInt(); + + /* + * consume the rest + */ + data.skipFully(extendedHeaderSize - 4); + } + } + + /* + * Footer Present + */ + if (version >= 4 && (flags & 0x10) != 0) { // footer present + footerSize = 10; + totalTagSize += 10; + } + } + + headerSize = (int) (input.getPosition() - startPosition); + } + + public ID3v2TagBody tagBody(InputStream input) throws IOException, ID3v2Exception { + if (compression) { + throw new ID3v2Exception("Tag compression is not supported"); + } + if (version < 4 && unsynchronization) { + byte[] bytes = new ID3v2DataInput(input).readFully(totalTagSize - headerSize); + boolean ff = false; + int len = 0; + for (byte b : bytes) { + if (!ff || b != 0) { + bytes[len++] = b; + } + ff = (b == 0xFF); + } + return new ID3v2TagBody(new ByteArrayInputStream(bytes, 0, len), headerSize, len, this); + } else { + return new ID3v2TagBody(input, headerSize, totalTagSize - headerSize - footerSize, this); + } + } + + public int getVersion() { + return version; + } + + public int getRevision() { + return revision; + } + + public int getTotalTagSize() { + return totalTagSize; + } + + public boolean isUnsynchronization() { + return unsynchronization; + } + + public boolean isCompression() { + return compression; + } + + public int getHeaderSize() { + return headerSize; + } + + public int getFooterSize() { + return footerSize; + } + + public int getPaddingSize() { + return paddingSize; + } + + @Override + public String toString() { + return String.format("%s[version=%s, totalTagSize=%d]", getClass().getSimpleName(), version, totalTagSize); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Exception.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Exception.java new file mode 100644 index 00000000..b5cf5f50 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Exception.java @@ -0,0 +1,24 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.mp3; + +public class MP3Exception extends Exception { + private static final long serialVersionUID = 1L; + + public MP3Exception(String message) { + super(message); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Frame.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Frame.java new file mode 100644 index 00000000..6d30612a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Frame.java @@ -0,0 +1,315 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.mp3; + + +public class MP3Frame { + static final class CRC16 { + private short crc = (short) 0xFFFF; + + public void update(int value, int length) { + int mask = 1 << (length - 1); + do { + if (((crc & 0x8000) == 0) ^ ((value & mask) == 0)) { + crc <<= 1; + crc ^= 0x8005; + } else { + crc <<= 1; + } + } while ((mask >>>= 1) != 0); + } + + public void update(byte value) { + update(value, 8); + } + + public short getValue() { + return crc; + } + + public void reset() { + crc = (short) 0xFFFF; + } + } + + public static class Header { + private static final int MPEG_LAYER_RESERVED = 0; + private static final int MPEG_VERSION_RESERVED = 1; + private static final int MPEG_BITRATE_FREE = 0; + private static final int MPEG_BITRATE_RESERVED = 15; + private static final int MPEG_FRQUENCY_RESERVED = 3; + + // [frequency][version] + private static final int[][] FREQUENCIES = new int[][] { + // 2.5 reserved 2 1 + { 11025, -1, 22050, 44100 }, + { 12000, -1, 24000, 48000 }, + { 8000, -1, 16000, 32000 }, + { -1, -1, -1, -1 } // reserved + }; + + // [bitrate][version,layer] + private static final int[][] BITRATES = new int[][] { + { 0, 0, 0, 0, 0 }, // free + { 32000, 32000, 32000, 32000, 8000 }, + { 64000, 48000, 40000, 48000, 16000 }, + { 96000, 56000, 48000, 56000, 24000 }, + { 128000, 64000, 56000, 64000, 32000 }, + { 160000, 80000, 64000, 80000, 40000 }, + { 192000, 96000, 80000, 96000, 48000 }, + { 224000, 112000, 96000, 112000, 56000 }, + { 256000, 128000, 112000, 128000, 64000 }, + { 288000, 160000, 128000, 144000, 80000 }, + { 320000, 192000, 160000, 160000, 96000 }, + { 352000, 224000, 192000, 176000, 112000 }, + { 384000, 256000, 224000, 192000, 128000 }, + { 416000, 320000, 256000, 224000, 144000 }, + { 448000, 384000, 320000, 256000, 160000 }, + { -1, -1, -1, -1, -1 } // reserved + }; + + // [version][layer] + private static final int[][] BITRATES_COLUMN = new int[][] { + // reserved III II I + { -1, 4, 4, 3 }, // 2.5 + { -1, -1, -1, -1 }, // reserved + { -1, 4, 4, 3 }, // 2 + { -1, 2, 1, 0 } // 1 + }; + + // [version][layer] + private static final int[][] SIZE_COEFFICIENTS = new int[][] { + // reserved III II I + { -1, 72, 144, 12 }, // 2.5 + { -1, -1, -1, -1 }, // reserved + { -1, 72, 144, 12 }, // 2 + { -1, 144, 144, 12 } // 1 + }; + + // [layer] + private static final int[] SLOT_SIZES = new int[] { + // reserved III II I + -1, 1, 1, 4 + }; + + // [channelMode][version] + private static final int[][] SIDE_INFO_SIZES = new int[][] { + // 2.5 reserved 2 1 + { 17, -1, 17, 32 }, // stereo + { 17, -1, 17, 32 }, // joint stereo + { 17, -1, 17, 32 }, // dual channel + { 9, -1, 9, 17 }, // mono + }; + + public static final int MPEG_LAYER_1 = 3; + public static final int MPEG_LAYER_2 = 2; + public static final int MPEG_LAYER_3 = 1; + + public static final int MPEG_VERSION_1 = 3; + public static final int MPEG_VERSION_2 = 2; + public static final int MPEG_VERSION_2_5 = 0; + + public static final int MPEG_CHANNEL_MODE_MONO = 3; + public static final int MPEG_PROTECTION_CRC = 0; + + private final int version; + private final int layer; + private final int frequency; + private final int bitrate; + private final int channelMode; + private final int padding; + private final int protection; + + public Header(int b1, int b2, int b3) throws MP3Exception { + version = b1 >> 3 & 0x3; + if (version == MPEG_VERSION_RESERVED) { + throw new MP3Exception("Reserved version"); + } + layer = b1 >> 1 & 0x3; + if (layer == MPEG_LAYER_RESERVED) { + throw new MP3Exception("Reserved layer"); + } + bitrate = b2 >> 4 & 0xF; + if (bitrate == MPEG_BITRATE_RESERVED) { + throw new MP3Exception("Reserved bitrate"); + } + if (bitrate == MPEG_BITRATE_FREE) { + throw new MP3Exception("Free bitrate"); + } + frequency = b2 >> 2 & 0x3; + if (frequency == MPEG_FRQUENCY_RESERVED) { + throw new MP3Exception("Reserved frequency"); + } + channelMode = b3 >> 6 & 0x3; + padding = b2 >> 1 & 0x1; + protection = b1 & 0x1; + + int minFrameSize = 4; + if (protection == MPEG_PROTECTION_CRC) { + minFrameSize += 2; + } + if (layer == MPEG_LAYER_3) { + minFrameSize += getSideInfoSize(); + } + if (getFrameSize() < minFrameSize) { + throw new MP3Exception("Frame size must be at least " + minFrameSize); + } + } + + public int getVersion() { + return version; + } + + public int getLayer() { + return layer; + } + + public int getFrequency() { + return FREQUENCIES[frequency][version]; + } + + public int getChannelMode() { + return channelMode; + } + + public int getProtection() { + return protection; + } + + public int getSampleCount() { + if (layer == MPEG_LAYER_1) { + return 384; + } else { // TODO correct? + return 1152; + } + } + + public int getFrameSize() { + return ((SIZE_COEFFICIENTS[version][layer] * getBitrate() / getFrequency()) + padding) * SLOT_SIZES[layer]; + } + + public int getBitrate() { + return BITRATES[bitrate][BITRATES_COLUMN[version][layer]]; + } + + public int getDuration() { + return (int)getTotalDuration(getFrameSize()); + } + + public long getTotalDuration(long totalSize) { + long duration = 1000L * (getSampleCount() * totalSize) / (getFrameSize() * getFrequency()); + if (getVersion() != MPEG_VERSION_1 && getChannelMode() == MPEG_CHANNEL_MODE_MONO) { + duration /= 2; + } + return duration; + } + + public boolean isCompatible(Header header) { + return layer == header.layer && version == header.version && frequency == header.frequency && channelMode == header.channelMode; + } + + public int getSideInfoSize() { + return SIDE_INFO_SIZES[channelMode][version]; + } + + public int getXingOffset() { + return 4 + getSideInfoSize(); + } + + public int getVBRIOffset() { + return 4 + 32; + } + } + + private final byte[] bytes; + private final Header header; + + MP3Frame(Header header, byte[] bytes) { + this.header = header; + this.bytes = bytes; + } + + boolean isChecksumError() { + if (header.getProtection() == Header.MPEG_PROTECTION_CRC) { + if (header.getLayer() == Header.MPEG_LAYER_3) { + CRC16 crc16 = new CRC16(); + crc16.update(bytes[2]); + crc16.update(bytes[3]); + // skip crc bytes 4+5 + int sideInfoSize = header.getSideInfoSize(); + for (int i = 0; i < sideInfoSize; i++) { + crc16.update(bytes[6 + i]); + } + int crc = ((bytes[4] & 0xFF) << 8) | (bytes[5] & 0xFF); + return crc != crc16.getValue(); + } + } + return false; + } + + public int getSize() { + return bytes.length; + } + + public Header getHeader() { + return header; + } + + boolean isXingFrame() { + int xingOffset = header.getXingOffset(); + if (bytes.length < xingOffset + 12) { // minimum Xing header size == 12 + return false; + } + if (xingOffset < 0 || bytes.length < xingOffset + 8) { + return false; + } + if (bytes[xingOffset] == 'X' && bytes[xingOffset + 1] == 'i' && bytes[xingOffset + 2] == 'n' && bytes[xingOffset + 3] == 'g') { + return true; + } + if (bytes[xingOffset] == 'I' && bytes[xingOffset + 1] == 'n' && bytes[xingOffset + 2] == 'f' && bytes[xingOffset + 3] == 'o') { + return true; + } + return false; + } + + boolean isVBRIFrame() { + int vbriOffset = header.getVBRIOffset(); + if (bytes.length < vbriOffset + 26) { // minimum VBRI header size == 26 + return false; + } + return bytes[vbriOffset] == 'V' && bytes[vbriOffset + 1] == 'B' && bytes[vbriOffset + 2] == 'R' && bytes[vbriOffset + 3] == 'I'; + } + + public int getNumberOfFrames() { + if (isXingFrame()) { + int xingOffset = header.getXingOffset(); + byte flags = bytes[xingOffset + 7]; + if ((flags & 0x01) != 0) { + return ((bytes[xingOffset + 8] & 0xFF) << 24) | + ((bytes[xingOffset + 9] & 0xFF) << 16) | + ((bytes[xingOffset + 10] & 0xFF) << 8) | + ( bytes[xingOffset + 11] & 0xFF); + } + } else if (isVBRIFrame()) { + int vbriOffset = header.getVBRIOffset(); + return ((bytes[vbriOffset + 14] & 0xFF) << 24) | + ((bytes[vbriOffset + 15] & 0xFF) << 16) | + ((bytes[vbriOffset + 16] & 0xFF) << 8) | + ( bytes[vbriOffset + 17] & 0xFF); + } + return -1; + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Info.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Info.java new file mode 100644 index 00000000..32e6c663 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Info.java @@ -0,0 +1,270 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.mp3; + +import org.telegram.messenger.audioinfo.AudioInfo; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class MP3Info extends AudioInfo { + static final Logger LOGGER = Logger.getLogger(MP3Info.class.getName()); + + interface StopReadCondition { + boolean stopRead(MP3Input data) throws IOException; + } + + public MP3Info(InputStream input, long fileLength) throws IOException, ID3v2Exception, MP3Exception { + this(input, fileLength, Level.FINEST); + } + + public MP3Info(InputStream input, final long fileLength, Level debugLevel) throws IOException, ID3v2Exception, MP3Exception { + brand = "MP3"; + version = "0"; + MP3Input data = new MP3Input(input); + if (ID3v2Info.isID3v2StartPosition(data)) { + ID3v2Info info = new ID3v2Info(data, debugLevel); + album = info.getAlbum(); + albumArtist = info.getAlbumArtist(); + artist = info.getArtist(); + comment = info.getComment(); + cover = info.getCover(); + smallCover = info.getSmallCover(); + compilation = info.isCompilation(); + composer = info.getComposer(); + copyright = info.getCopyright(); + disc = info.getDisc(); + discs = info.getDiscs(); + duration = info.getDuration(); + genre = info.getGenre(); + grouping = info.getGrouping(); + lyrics = info.getLyrics(); + title = info.getTitle(); + track = info.getTrack(); + tracks = info.getTracks(); + year = info.getYear(); + } + if (duration <= 0 || duration >= 3600000L) { // don't trust strange durations (e.g. old lame versions always write TLEN 97391548) + try { + duration = calculateDuration(data, fileLength, new StopReadCondition() { + final long stopPosition = fileLength - 128; + + @Override + public boolean stopRead(MP3Input data) throws IOException { + return (data.getPosition() == stopPosition) && ID3v1Info.isID3v1StartPosition(data); + } + }); + } catch (MP3Exception e) { + if (LOGGER.isLoggable(debugLevel)) { + LOGGER.log(debugLevel, "Could not determine MP3 duration", e); + } + } + } + if (title == null || album == null || artist == null) { + if (data.getPosition() <= fileLength - 128) { // position to last 128 bytes + data.skipFully(fileLength - 128 - data.getPosition()); + if (ID3v1Info.isID3v1StartPosition(input)) { + ID3v1Info info = new ID3v1Info(input); + if (album == null) { + album = info.getAlbum(); + } + if (artist == null) { + artist = info.getArtist(); + } + if (comment == null) { + comment = info.getComment(); + } + if (genre == null) { + genre = info.getGenre(); + } + if (title == null) { + title = info.getTitle(); + } + if (track == 0) { + track = info.getTrack(); + } + if (year == 0) { + year = info.getYear(); + } + } + } + } + } + + MP3Frame readFirstFrame(MP3Input data, StopReadCondition stopCondition) throws IOException { + int b0 = 0; + int b1 = stopCondition.stopRead(data) ? -1 : data.read(); + while (b1 != -1) { + if (b0 == 0xFF && (b1 & 0xE0) == 0xE0) { // first 11 bits should be 1 + data.mark(2); // set mark at b2 + int b2 = stopCondition.stopRead(data) ? -1 : data.read(); + if (b2 == -1) { + break; + } + int b3 = stopCondition.stopRead(data) ? -1 : data.read(); + if (b3 == -1) { + break; + } + MP3Frame.Header header = null; + try { + header = new MP3Frame.Header(b1, b2, b3); + } catch (MP3Exception e) { + // not a valid frame header + } + if (header != null) { // we have a candidate + /* + * The code gets a bit complex here, because we need to be able to reset() to b2 if + * the check fails. Thus, we have to reset() to b2 before doing a call to mark(). + */ + data.reset(); // reset input to b2 + data.mark(header.getFrameSize() + 2); // rest of frame (size - 2) + next header + /* + * read frame data + */ + byte[] frameBytes = new byte[header.getFrameSize()]; + frameBytes[0] = (byte) 0xFF; + frameBytes[1] = (byte) b1; + try { + data.readFully(frameBytes, 2, frameBytes.length - 2); // may throw EOFException + } catch (EOFException e) { + break; + } + + MP3Frame frame = new MP3Frame(header, frameBytes); + /* + * read next header + */ + if (!frame.isChecksumError()) { + int nextB0 = stopCondition.stopRead(data) ? -1 : data.read(); + int nextB1 = stopCondition.stopRead(data) ? -1 : data.read(); + if (nextB0 == -1 || nextB1 == -1) { + return frame; + } + if (nextB0 == 0xFF && (nextB1 & 0xFE) == (b1 & 0xFE)) { // quick check: nextB1 must match b1's version & layer + int nextB2 = stopCondition.stopRead(data) ? -1 : data.read(); + int nextB3 = stopCondition.stopRead(data) ? -1 : data.read(); + if (nextB2 == -1 || nextB3 == -1) { + return frame; + } + try { + if (new MP3Frame.Header(nextB1, nextB2, nextB3).isCompatible(header)) { + data.reset(); // reset input to b2 + data.skipFully(frameBytes.length - 2); // skip to end of frame + return frame; + } + } catch (MP3Exception e) { + // not a valid frame header + } + } + } + } + + /* + * seems to be a false sync... + */ + data.reset(); // reset input to b2 + } + + /* + * read next byte + */ + b0 = b1; + b1 = stopCondition.stopRead(data) ? -1 : data.read(); + } + return null; + } + + MP3Frame readNextFrame(MP3Input data, StopReadCondition stopCondition, MP3Frame previousFrame) throws IOException { + MP3Frame.Header previousHeader = previousFrame.getHeader(); + data.mark(4); + int b0 = stopCondition.stopRead(data) ? -1 : data.read(); + int b1 = stopCondition.stopRead(data) ? -1 : data.read(); + if (b0 == -1 || b1 == -1) { + return null; + } + if (b0 == 0xFF && (b1 & 0xE0) == 0xE0) { // first 11 bits should be 1 + int b2 = stopCondition.stopRead(data) ? -1 : data.read(); + int b3 = stopCondition.stopRead(data) ? -1 : data.read(); + if (b2 == -1 || b3 == -1) { + return null; + } + MP3Frame.Header nextHeader = null; + try { + nextHeader = new MP3Frame.Header(b1, b2, b3); + } catch (MP3Exception e) { + // not a valid frame header + } + if (nextHeader != null && nextHeader.isCompatible(previousHeader)) { + byte[] frameBytes = new byte[nextHeader.getFrameSize()]; + frameBytes[0] = (byte) b0; + frameBytes[1] = (byte) b1; + frameBytes[2] = (byte) b2; + frameBytes[3] = (byte) b3; + try { + data.readFully(frameBytes, 4, frameBytes.length - 4); + } catch (EOFException e) { + return null; + } + return new MP3Frame(nextHeader, frameBytes); + } + } + data.reset(); + return null; + } + + long calculateDuration(MP3Input data, long totalLength, StopReadCondition stopCondition) throws IOException, MP3Exception { + MP3Frame frame = readFirstFrame(data, stopCondition); + if (frame != null) { + // check for Xing header + int numberOfFrames = frame.getNumberOfFrames(); + if (numberOfFrames > 0) { // from Xing/VBRI header + return frame.getHeader().getTotalDuration(numberOfFrames * frame.getSize()); + } else { // scan file + numberOfFrames = 1; + + long firstFramePosition = data.getPosition() - frame.getSize(); + long frameSizeSum = frame.getSize(); + + int firstFrameBitrate = frame.getHeader().getBitrate(); + long bitrateSum = firstFrameBitrate; + boolean vbr = false; + int cbrThreshold = 10000 / frame.getHeader().getDuration(); // assume CBR after 10 seconds + + while (true) { + if (numberOfFrames == cbrThreshold && !vbr && totalLength > 0) { + return frame.getHeader().getTotalDuration(totalLength - firstFramePosition); + } + if ((frame = readNextFrame(data, stopCondition, frame)) == null) { + break; + } + int bitrate = frame.getHeader().getBitrate(); + if (bitrate != firstFrameBitrate) { + vbr = true; + } + bitrateSum += bitrate; + frameSizeSum += frame.getSize(); + numberOfFrames++; + } + return 1000L * frameSizeSum * numberOfFrames * 8 / bitrateSum; + } + } else { + throw new MP3Exception("No audio frame"); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Input.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Input.java new file mode 100644 index 00000000..8cd70c40 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/mp3/MP3Input.java @@ -0,0 +1,60 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.mp3; + +import org.telegram.messenger.audioinfo.util.PositionInputStream; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +public class MP3Input extends PositionInputStream { + public MP3Input(InputStream delegate) throws IOException { + super(delegate); + } + + public MP3Input(InputStream delegate, long position) { + super(delegate, position); + } + + public final void readFully(byte b[], int off, int len) throws IOException { + int total = 0; + while (total < len) { + int current = read(b, off + total, len - total); + if (current > 0) { + total += current; + } else { + throw new EOFException(); + } + } + } + + public void skipFully(long len) throws IOException { + long total = 0; + while (total < len) { + long current = skip(len - total); + if (current > 0) { + total += current; + } else { + throw new EOFException(); + } + } + } + + public String toString() { + return "mp3[pos=" + getPosition() + "]"; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/util/PositionInputStream.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/util/PositionInputStream.java new file mode 100644 index 00000000..8e1c60f0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/util/PositionInputStream.java @@ -0,0 +1,79 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.util; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +public class PositionInputStream extends FilterInputStream { + private long position; + private long positionMark; + + public PositionInputStream(InputStream delegate) { + this(delegate, 0L); + } + + public PositionInputStream(InputStream delegate, long position) { + super(delegate); + this.position = position; + } + + @Override + public synchronized void mark(int readlimit) { + positionMark = position; + super.mark(readlimit); + } + + @Override + public synchronized void reset() throws IOException { + super.reset(); + position = positionMark; + } + + public int read() throws IOException { + int data = super.read(); + if (data >= 0) { + position++; + } + return data; + } + + public int read(byte[] b, int off, int len) throws IOException { + long p = position; + int read = super.read(b, off, len); + if (read > 0) { + position = p + read; + } + return read; + } + + @Override + public final int read(byte[] b) throws IOException { + return read(b, 0, b.length); + } + + public long skip(long n) throws IOException { + long p = position; + long skipped = super.skip(n); + position = p + skipped; + return skipped; + } + + public long getPosition() { + return position; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/util/RangeInputStream.java b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/util/RangeInputStream.java new file mode 100644 index 00000000..a9fa6da7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/audioinfo/util/RangeInputStream.java @@ -0,0 +1,63 @@ +/* + * Copyright 2013-2014 Odysseus Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.audioinfo.util; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Input stream filter that keeps track of the current read position + * and has a read length limit. + */ +public class RangeInputStream extends PositionInputStream { + private final long endPosition; + + public RangeInputStream(InputStream delegate, long position, long length) throws IOException { + super(delegate, position); + this.endPosition = position + length; + } + + public long getRemainingLength() { + return endPosition - getPosition(); + } + + @Override + public int read() throws IOException { + if (getPosition() == endPosition) { + return -1; + } + return super.read(); + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (getPosition() + len > endPosition) { + len = (int)(endPosition - getPosition()); + if (len == 0) { + return -1; + } + } + return super.read(b, off, len); + } + + @Override + public long skip(long n) throws IOException { + if (getPosition() + n > endPosition) { + n = (int)(endPosition - getPosition()); + } + return super.skip(n); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java new file mode 100644 index 00000000..d1962890 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/browser/Browser.java @@ -0,0 +1,199 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger.browser; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.R; +import org.telegram.messenger.ShareBroadcastReceiver; +import org.telegram.messenger.support.customtabs.CustomTabsCallback; +import org.telegram.messenger.support.customtabs.CustomTabsClient; +import org.telegram.messenger.support.customtabs.CustomTabsIntent; +import org.telegram.messenger.support.customtabs.CustomTabsServiceConnection; +import org.telegram.messenger.support.customtabs.CustomTabsSession; +import org.telegram.messenger.support.customtabsclient.shared.CustomTabsHelper; +import org.telegram.messenger.support.customtabsclient.shared.ServiceConnection; +import org.telegram.messenger.support.customtabsclient.shared.ServiceConnectionCallback; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.LaunchActivity; + +import java.lang.ref.WeakReference; + +public class Browser { + + private static WeakReference customTabsCurrentSession; + private static CustomTabsSession customTabsSession; + private static CustomTabsClient customTabsClient; + private static CustomTabsServiceConnection customTabsServiceConnection; + private static String customTabsPackageToBind; + private static WeakReference currentCustomTabsActivity; + + private static CustomTabsSession getCurrentSession() { + return customTabsCurrentSession == null ? null : customTabsCurrentSession.get(); + } + + private static void setCurrentSession(CustomTabsSession session) { + customTabsCurrentSession = new WeakReference<>(session); + } + + private static CustomTabsSession getSession() { + if (customTabsClient == null) { + customTabsSession = null; + } else if (customTabsSession == null) { + customTabsSession = customTabsClient.newSession(new NavigationCallback()); + setCurrentSession(customTabsSession); + } + return customTabsSession; + } + + public static void bindCustomTabsService(Activity activity) { + if (Build.VERSION.SDK_INT < 15) { + return; + } + Activity currentActivity = currentCustomTabsActivity == null ? null : currentCustomTabsActivity.get(); + if (currentActivity != null && currentActivity != activity) { + unbindCustomTabsService(currentActivity); + } + if (customTabsClient != null) { + return; + } + currentCustomTabsActivity = new WeakReference<>(activity); + try { + if (TextUtils.isEmpty(customTabsPackageToBind)) { + customTabsPackageToBind = CustomTabsHelper.getPackageNameToUse(activity); + if (customTabsPackageToBind == null) { + return; + } + } + customTabsServiceConnection = new ServiceConnection(new ServiceConnectionCallback() { + @Override + public void onServiceConnected(CustomTabsClient client) { + customTabsClient = client; + if (customTabsClient != null) { + customTabsClient.warmup(0); + } + } + + @Override + public void onServiceDisconnected() { + customTabsClient = null; + } + }); + if (!CustomTabsClient.bindCustomTabsService(activity, customTabsPackageToBind, customTabsServiceConnection)) { + customTabsServiceConnection = null; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public static void unbindCustomTabsService(Activity activity) { + if (Build.VERSION.SDK_INT < 15 || customTabsServiceConnection == null) { + return; + } + Activity currentActivity = currentCustomTabsActivity == null ? null : currentCustomTabsActivity.get(); + if (currentActivity == activity) { + currentCustomTabsActivity.clear(); + } + try { + activity.unbindService(customTabsServiceConnection); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + customTabsClient = null; + customTabsSession = null; + } + + private static class NavigationCallback extends CustomTabsCallback { + @Override + public void onNavigationEvent(int navigationEvent, Bundle extras) { + FileLog.e("tmessages", "code = " + navigationEvent + " extras " + extras); + } + } + + public static void openUrl(Context context, String url) { + openUrl(context, Uri.parse(url), true); + } + + public static void openUrl(Context context, Uri uri) { + openUrl(context, uri, true); + } + + public static void openUrl(Context context, String url, boolean allowCustom) { + if (context == null || url == null) { + return; + } + openUrl(context, Uri.parse(url), allowCustom); + } + + public static void openUrl(Context context, Uri uri, boolean allowCustom) { + if (context == null || uri == null) { + return; + } + + try { + //plus to open themes in themes app + if(uri.toString().contains("plusmessenger.org/theme/")){ + allowCustom = false; + }// + boolean internalUri = isInternalUri(uri); + if (Build.VERSION.SDK_INT >= 15 && allowCustom && MediaController.getInstance().canCustomTabs() && !internalUri) { + Intent share = new Intent(ApplicationLoader.applicationContext, ShareBroadcastReceiver.class); + share.setAction(Intent.ACTION_SEND); + + CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder(getSession()); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int color = themePrefs.getInt("chatHeaderColor", themePrefs.getInt("themeColor", AndroidUtilities.defColor)); + color = color == 0xffffffff ? AndroidUtilities.setDarkColor(color, 0x20) : color; + builder.setToolbarColor(Theme.ACTION_BAR_COLOR); + builder.setToolbarColor(color); + builder.setShowTitle(true); + builder.setActionButton(BitmapFactory.decodeResource(context.getResources(), R.drawable.abc_ic_menu_share_mtrl_alpha), LocaleController.getString("ShareFile", R.string.ShareFile), PendingIntent.getBroadcast(ApplicationLoader.applicationContext, 0, share, 0), false); + CustomTabsIntent intent = builder.build(); + intent.launchUrl((Activity) context, uri); + } else { + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + if (internalUri) { + ComponentName componentName = new ComponentName(context.getPackageName(), LaunchActivity.class.getName()); + intent.setComponent(componentName); + } + intent.putExtra(android.provider.Browser.EXTRA_APPLICATION_ID, context.getPackageName()); + context.startActivity(intent); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public static boolean isInternalUrl(String url) { + return isInternalUri(Uri.parse(url)); + } + + public static boolean isInternalUri(Uri uri) { + String host = uri.getHost(); + host = host != null ? host.toLowerCase() : ""; + return "tg".equals(uri.getScheme()) || "telegram.me".equals(host) || "telegram.dog".equals(host); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/query/BotQuery.java b/TMessagesProj/src/main/java/org/telegram/messenger/query/BotQuery.java new file mode 100644 index 00000000..03646523 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/query/BotQuery.java @@ -0,0 +1,205 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger.query; + +import org.telegram.SQLite.SQLiteCursor; +import org.telegram.SQLite.SQLitePreparedStatement; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.FileLog; +import org.telegram.tgnet.NativeByteBuffer; +import org.telegram.tgnet.TLRPC; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; + +public class BotQuery { + + private static HashMap botInfos = new HashMap<>(); + private static HashMap botKeyboards = new HashMap<>(); + private static HashMap botKeyboardsByMids = new HashMap<>(); + + public static void cleanup() { + botInfos.clear(); + } + + public static void clearBotKeyboard(final long did, final ArrayList messages) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (messages != null) { + for (int a = 0; a < messages.size(); a++) { + Long did = botKeyboardsByMids.get(messages.get(a)); + if (did != null) { + botKeyboards.remove(did); + botKeyboardsByMids.remove(messages.get(a)); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.botKeyboardDidLoaded, null, did); + } + } + } else { + botKeyboards.remove(did); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.botKeyboardDidLoaded, null, did); + } + } + }); + } + + public static void loadBotKeyboard(final long did) { + TLRPC.Message keyboard = botKeyboards.get(did); + if (keyboard != null) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.botKeyboardDidLoaded, keyboard, did); + return; + } + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + TLRPC.Message botKeyboard = null; + SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT info FROM bot_keyboard WHERE uid = %d", did)); + if (cursor.next()) { + NativeByteBuffer data; + + if (!cursor.isNull(0)) { + data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + botKeyboard = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + } + data.reuse(); + } + } + cursor.dispose(); + + if (botKeyboard != null) { + final TLRPC.Message botKeyboardFinal = botKeyboard; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.botKeyboardDidLoaded, botKeyboardFinal, did); + } + }); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public static void loadBotInfo(final int uid, boolean cache, final int classGuid) { + if (cache) { + TLRPC.BotInfo botInfo = botInfos.get(uid); + if (botInfo != null) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.botInfoDidLoaded, botInfo, classGuid); + return; + } + } + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + TLRPC.BotInfo botInfo = null; + SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT info FROM bot_info WHERE uid = %d", uid)); + if (cursor.next()) { + NativeByteBuffer data; + + if (!cursor.isNull(0)) { + data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + botInfo = TLRPC.BotInfo.TLdeserialize(data, data.readInt32(false), false); + } + data.reuse(); + } + } + cursor.dispose(); + + if (botInfo != null) { + final TLRPC.BotInfo botInfoFinal = botInfo; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.botInfoDidLoaded, botInfoFinal, classGuid); + } + }); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public static void putBotKeyboard(final long did, final TLRPC.Message message) { + if (message == null) { + return; + } + try { + int mid = 0; + SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT mid FROM bot_keyboard WHERE uid = %d", did)); + if (cursor.next()) { + mid = cursor.intValue(0); + } + cursor.dispose(); + if (mid >= message.id) { + return; + } + + SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("REPLACE INTO bot_keyboard VALUES(?, ?, ?)"); + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); + message.serializeToStream(data); + state.bindLong(1, did); + state.bindInteger(2, message.id); + state.bindByteBuffer(3, data); + state.step(); + data.reuse(); + state.dispose(); + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + TLRPC.Message old = botKeyboards.put(did, message); + if (old != null) { + botKeyboardsByMids.remove(old.id); + } + botKeyboardsByMids.put(message.id, did); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.botKeyboardDidLoaded, message, did); + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public static void putBotInfo(final TLRPC.BotInfo botInfo) { + if (botInfo == null) { + return; + } + botInfos.put(botInfo.user_id, botInfo); + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("REPLACE INTO bot_info(uid, info) VALUES(?, ?)"); + state.requery(); + NativeByteBuffer data = new NativeByteBuffer(botInfo.getObjectSize()); + botInfo.serializeToStream(data); + state.bindInteger(1, botInfo.user_id); + state.bindByteBuffer(2, data); + state.step(); + data.reuse(); + state.dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/query/MessagesQuery.java b/TMessagesProj/src/main/java/org/telegram/messenger/query/MessagesQuery.java new file mode 100644 index 00000000..d7e767ab --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/query/MessagesQuery.java @@ -0,0 +1,440 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger.query; + +import android.text.TextUtils; + +import org.telegram.SQLite.SQLiteCursor; +import org.telegram.SQLite.SQLitePreparedStatement; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ImageLoader; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.FileLog; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.NativeByteBuffer; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; + +public class MessagesQuery { + + public static MessageObject loadPinnedMessage(final int channelId, final int mid, boolean useQueue) { + if (useQueue) { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + loadPinnedMessageInternal(channelId, mid, false); + } + }); + } else { + return loadPinnedMessageInternal(channelId, mid, true); + } + return null; + } + + private static MessageObject loadPinnedMessageInternal(final int channelId, final int mid, boolean returnValue) { + try { + long messageId = ((long) mid) | ((long) channelId) << 32; + + TLRPC.Message result = null; + final ArrayList users = new ArrayList<>(); + final ArrayList chats = new ArrayList<>(); + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + + SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, mid, date FROM messages WHERE mid = %d", messageId)); + if (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + result = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + result.id = cursor.intValue(1); + result.date = cursor.intValue(2); + result.dialog_id = -channelId; + MessagesStorage.addUsersAndChatsFromMessage(result, usersToLoad, chatsToLoad); + } + data.reuse(); + } + cursor.dispose(); + + if (result == null) { + cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data FROM chat_pinned WHERE uid = %d", channelId)); + if (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + result = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + if (result.id != mid) { + result = null; + } else { + result.dialog_id = -channelId; + MessagesStorage.addUsersAndChatsFromMessage(result, usersToLoad, chatsToLoad); + } + } + data.reuse(); + } + cursor.dispose(); + } + + if (result == null) { + final TLRPC.TL_channels_getMessages req = new TLRPC.TL_channels_getMessages(); + req.channel = MessagesController.getInputChannel(channelId); + req.id.add(mid); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + boolean ok = false; + if (error == null) { + TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; + if (!messagesRes.messages.isEmpty()) { + ImageLoader.saveMessagesThumbs(messagesRes.messages); + broadcastPinnedMessage(messagesRes.messages.get(0), messagesRes.users, messagesRes.chats, false, false); + MessagesStorage.getInstance().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true); + savePinnedMessage(messagesRes.messages.get(0)); + ok = true; + } + } + if (!ok) { + MessagesStorage.getInstance().updateChannelPinnedMessage(channelId, 0); + } + } + }); + } else { + if (returnValue) { + return broadcastPinnedMessage(result, users, chats, true, returnValue); + } else { + if (!usersToLoad.isEmpty()) { + MessagesStorage.getInstance().getUsersInternal(TextUtils.join(",", usersToLoad), users); + } + if (!chatsToLoad.isEmpty()) { + MessagesStorage.getInstance().getChatsInternal(TextUtils.join(",", chatsToLoad), chats); + } + broadcastPinnedMessage(result, users, chats, true, false); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return null; + } + + private static void savePinnedMessage(final TLRPC.Message result) { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + MessagesStorage.getInstance().getDatabase().beginTransaction(); + SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("REPLACE INTO chat_pinned VALUES(?, ?, ?)"); + NativeByteBuffer data = new NativeByteBuffer(result.getObjectSize()); + result.serializeToStream(data); + state.requery(); + state.bindInteger(1, result.to_id.channel_id); + state.bindInteger(2, result.id); + state.bindByteBuffer(3, data); + state.step(); + data.reuse(); + state.dispose(); + MessagesStorage.getInstance().getDatabase().commitTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + private static MessageObject broadcastPinnedMessage(final TLRPC.Message result, final ArrayList users, final ArrayList chats, final boolean isCache, boolean returnValue) { + final HashMap usersDict = new HashMap<>(); + for (int a = 0; a < users.size(); a++) { + TLRPC.User user = users.get(a); + usersDict.put(user.id, user); + } + final HashMap chatsDict = new HashMap<>(); + for (int a = 0; a < chats.size(); a++) { + TLRPC.Chat chat = chats.get(a); + chatsDict.put(chat.id, chat); + } + if (returnValue) { + return new MessageObject(result, usersDict, chatsDict, false); + } else { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().putUsers(users, isCache); + MessagesController.getInstance().putChats(chats, isCache); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didLoadedPinnedMessage, new MessageObject(result, usersDict, chatsDict, false)); + } + }); + } + return null; + } + + public static void loadReplyMessagesForMessages(final ArrayList messages, final long dialogId) { + if ((int) dialogId == 0) { + final ArrayList replyMessages = new ArrayList<>(); + final HashMap> replyMessageRandomOwners = new HashMap<>(); + final StringBuilder stringBuilder = new StringBuilder(); + for (int a = 0; a < messages.size(); a++) { + MessageObject messageObject = messages.get(a); + if (messageObject.isReply() && messageObject.replyMessageObject == null) { + Long id = messageObject.messageOwner.reply_to_random_id; + if (stringBuilder.length() > 0) { + stringBuilder.append(','); + } + stringBuilder.append(id); + ArrayList messageObjects = replyMessageRandomOwners.get(id); + if (messageObjects == null) { + messageObjects = new ArrayList<>(); + replyMessageRandomOwners.put(id, messageObjects); + } + messageObjects.add(messageObject); + if (!replyMessages.contains(id)) { + replyMessages.add(id); + } + } + } + if (replyMessages.isEmpty()) { + return; + } + + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT m.data, m.mid, m.date, r.random_id FROM randoms as r INNER JOIN messages as m ON r.mid = m.mid WHERE r.random_id IN(%s)", TextUtils.join(",", replyMessages))); + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.id = cursor.intValue(1); + message.date = cursor.intValue(2); + message.dialog_id = dialogId; + + + ArrayList arrayList = replyMessageRandomOwners.remove(cursor.longValue(3)); + if (arrayList != null) { + MessageObject messageObject = new MessageObject(message, null, null, false); + for (int b = 0; b < arrayList.size(); b++) { + MessageObject object = arrayList.get(b); + object.replyMessageObject = messageObject; + object.messageOwner.reply_to_msg_id = messageObject.getId(); + } + } + } + data.reuse(); + } + cursor.dispose(); + if (!replyMessageRandomOwners.isEmpty()) { + for (HashMap.Entry> entry : replyMessageRandomOwners.entrySet()) { + ArrayList arrayList = entry.getValue(); + for (int a = 0; a < arrayList.size(); a++) { + arrayList.get(a).messageOwner.reply_to_random_id = 0; + } + } + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didLoadedReplyMessages, dialogId); + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } else { + final ArrayList replyMessages = new ArrayList<>(); + final HashMap> replyMessageOwners = new HashMap<>(); + final StringBuilder stringBuilder = new StringBuilder(); + int channelId = 0; + for (int a = 0; a < messages.size(); a++) { + MessageObject messageObject = messages.get(a); + if (messageObject.getId() > 0 && messageObject.isReply() && messageObject.replyMessageObject == null) { + Integer id = messageObject.messageOwner.reply_to_msg_id; + long messageId = id; + if (messageObject.messageOwner.to_id.channel_id != 0) { + messageId |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; + channelId = messageObject.messageOwner.to_id.channel_id; + } + if (stringBuilder.length() > 0) { + stringBuilder.append(','); + } + stringBuilder.append(messageId); + ArrayList messageObjects = replyMessageOwners.get(id); + if (messageObjects == null) { + messageObjects = new ArrayList<>(); + replyMessageOwners.put(id, messageObjects); + } + messageObjects.add(messageObject); + if (!replyMessages.contains(id)) { + replyMessages.add(id); + } + } + } + if (replyMessages.isEmpty()) { + return; + } + + final int channelIdFinal = channelId; + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + final ArrayList result = new ArrayList<>(); + final ArrayList users = new ArrayList<>(); + final ArrayList chats = new ArrayList<>(); + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + + SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, mid, date FROM messages WHERE mid IN(%s)", stringBuilder.toString())); + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.id = cursor.intValue(1); + message.date = cursor.intValue(2); + message.dialog_id = dialogId; + MessagesStorage.addUsersAndChatsFromMessage(message, usersToLoad, chatsToLoad); + result.add(message); + replyMessages.remove((Integer) message.id); + } + data.reuse(); + } + cursor.dispose(); + + if (!usersToLoad.isEmpty()) { + MessagesStorage.getInstance().getUsersInternal(TextUtils.join(",", usersToLoad), users); + } + if (!chatsToLoad.isEmpty()) { + MessagesStorage.getInstance().getChatsInternal(TextUtils.join(",", chatsToLoad), chats); + } + broadcastReplyMessages(result, replyMessageOwners, users, chats, dialogId, true); + + if (!replyMessages.isEmpty()) { + if (channelIdFinal != 0) { + final TLRPC.TL_channels_getMessages req = new TLRPC.TL_channels_getMessages(); + req.channel = MessagesController.getInputChannel(channelIdFinal); + req.id = replyMessages; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; + ImageLoader.saveMessagesThumbs(messagesRes.messages); + broadcastReplyMessages(messagesRes.messages, replyMessageOwners, messagesRes.users, messagesRes.chats, dialogId, false); + MessagesStorage.getInstance().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true); + saveReplyMessages(replyMessageOwners, messagesRes.messages); + } + } + }); + } else { + TLRPC.TL_messages_getMessages req = new TLRPC.TL_messages_getMessages(); + req.id = replyMessages; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + TLRPC.messages_Messages messagesRes = (TLRPC.messages_Messages) response; + ImageLoader.saveMessagesThumbs(messagesRes.messages); + broadcastReplyMessages(messagesRes.messages, replyMessageOwners, messagesRes.users, messagesRes.chats, dialogId, false); + MessagesStorage.getInstance().putUsersAndChats(messagesRes.users, messagesRes.chats, true, true); + saveReplyMessages(replyMessageOwners, messagesRes.messages); + } + } + }); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + } + + private static void saveReplyMessages(final HashMap> replyMessageOwners, final ArrayList result) { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + MessagesStorage.getInstance().getDatabase().beginTransaction(); + SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("UPDATE messages SET replydata = ? WHERE mid = ?"); + for (int a = 0; a < result.size(); a++) { + TLRPC.Message message = result.get(a); + ArrayList messageObjects = replyMessageOwners.get(message.id); + if (messageObjects != null) { + NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); + message.serializeToStream(data); + for (int b = 0; b < messageObjects.size(); b++) { + MessageObject messageObject = messageObjects.get(b); + state.requery(); + long messageId = messageObject.getId(); + if (messageObject.messageOwner.to_id.channel_id != 0) { + messageId |= ((long) messageObject.messageOwner.to_id.channel_id) << 32; + } + state.bindByteBuffer(1, data); + state.bindLong(2, messageId); + state.step(); + } + data.reuse(); + } + } + state.dispose(); + MessagesStorage.getInstance().getDatabase().commitTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + private static void broadcastReplyMessages(final ArrayList result, final HashMap> replyMessageOwners, final ArrayList users, final ArrayList chats, final long dialog_id, final boolean isCache) { + final HashMap usersDict = new HashMap<>(); + for (int a = 0; a < users.size(); a++) { + TLRPC.User user = users.get(a); + usersDict.put(user.id, user); + } + final HashMap chatsDict = new HashMap<>(); + for (int a = 0; a < chats.size(); a++) { + TLRPC.Chat chat = chats.get(a); + chatsDict.put(chat.id, chat); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().putUsers(users, isCache); + MessagesController.getInstance().putChats(chats, isCache); + boolean changed = false; + for (int a = 0; a < result.size(); a++) { + TLRPC.Message message = result.get(a); + ArrayList arrayList = replyMessageOwners.get(message.id); + if (arrayList != null) { + MessageObject messageObject = new MessageObject(message, usersDict, chatsDict, false); + for (int b = 0; b < arrayList.size(); b++) { + MessageObject m = arrayList.get(b); + m.replyMessageObject = messageObject; + if (m.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) { + m.generatePinMessageText(null, null); + } + } + changed = true; + } + } + if (changed) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didLoadedReplyMessages, dialog_id); + } + } + }); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/query/MessagesSearchQuery.java b/TMessagesProj/src/main/java/org/telegram/messenger/query/MessagesSearchQuery.java new file mode 100644 index 00000000..55132778 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/query/MessagesSearchQuery.java @@ -0,0 +1,160 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger.query; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; + +import java.util.ArrayList; + +@SuppressWarnings("unchecked") +public class MessagesSearchQuery { + + private static int reqId; + private static int lastReqId; + private static boolean messagesSearchEndReached[] = new boolean[] {false, false}; + private static ArrayList searchResultMessages = new ArrayList<>(); + private static String lastSearchQuery; + private static int lastReturnedNum; + + private static int getMask() { + int mask = 0; + if (lastReturnedNum < searchResultMessages.size() - 1 || !messagesSearchEndReached[0] || !messagesSearchEndReached[1]) { + mask |= 1; + } + if (lastReturnedNum > 0) { + mask |= 2; + } + return mask; + } + + public static void searchMessagesInChat(String query, final long dialog_id, final long mergeDialogId, final int guid, int direction) { + if (reqId != 0) { + ConnectionsManager.getInstance().cancelRequest(reqId, true); + reqId = 0; + } + int max_id = 0; + long queryWithDialog = dialog_id; + if (query == null || query.length() == 0) { + if (direction == 1) { + lastReturnedNum++; + if (lastReturnedNum < searchResultMessages.size()) { + MessageObject messageObject = searchResultMessages.get(lastReturnedNum); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatSearchResultsAvailable, guid, messageObject.getId(), getMask(), messageObject.getDialogId()); + return; + } else { + if (messagesSearchEndReached[0] && mergeDialogId == 0 || messagesSearchEndReached[1]) { + lastReturnedNum--; + return; + } + if (searchResultMessages.isEmpty()) { + return; + } + query = lastSearchQuery; + MessageObject messageObject = searchResultMessages.get(searchResultMessages.size() - 1); + if (messageObject.getDialogId() == dialog_id && !messagesSearchEndReached[0]) { + max_id = messageObject.getId(); + queryWithDialog = dialog_id; + } else { + if (messageObject.getDialogId() == mergeDialogId) { + max_id = messageObject.getId(); + } + queryWithDialog = mergeDialogId; + messagesSearchEndReached[1] = false; + } + } + } else if (direction == 2) { + lastReturnedNum--; + if (lastReturnedNum < 0) { + lastReturnedNum = 0; + return; + } + if (lastReturnedNum >= searchResultMessages.size()) { + lastReturnedNum = searchResultMessages.size() - 1; + } + MessageObject messageObject = searchResultMessages.get(lastReturnedNum); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatSearchResultsAvailable, guid, messageObject.getId(), getMask(), messageObject.getDialogId()); + return; + } else { + return; + } + } + if (messagesSearchEndReached[0] && !messagesSearchEndReached[1] && mergeDialogId != 0) { + queryWithDialog = mergeDialogId; + } + final TLRPC.TL_messages_search req = new TLRPC.TL_messages_search(); + req.limit = 21; + int lower_part = (int) queryWithDialog; + req.peer = MessagesController.getInputPeer(lower_part); + if (req.peer == null) { + return; + } + req.q = query; + req.max_id = max_id; + req.filter = new TLRPC.TL_inputMessagesFilterEmpty(); + final int currentReqId = ++lastReqId; + lastSearchQuery = query; + final long queryWithDialogFinal = queryWithDialog; + reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + reqId = 0; + if (currentReqId == lastReqId) { + if (error == null) { + TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + MessagesStorage.getInstance().putUsersAndChats(res.users, res.chats, true, true); + MessagesController.getInstance().putUsers(res.users, false); + MessagesController.getInstance().putChats(res.chats, false); + if (req.max_id == 0 && queryWithDialogFinal == dialog_id) { + lastReturnedNum = 0; + searchResultMessages.clear(); + } + boolean added = false; + for (int a = 0; a < Math.min(res.messages.size(), 20); a++) { + TLRPC.Message message = res.messages.get(a); + added = true; + searchResultMessages.add(new MessageObject(message, null, false)); + } + messagesSearchEndReached[queryWithDialogFinal == dialog_id ? 0 : 1] = res.messages.size() != 21; + if (mergeDialogId == 0) { + messagesSearchEndReached[1] = messagesSearchEndReached[0]; + } + if (searchResultMessages.isEmpty()) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatSearchResultsAvailable, guid, 0, getMask(), (long) 0); + } else { + if (added) { + if (lastReturnedNum >= searchResultMessages.size()) { + lastReturnedNum = searchResultMessages.size() - 1; + } + MessageObject messageObject = searchResultMessages.get(lastReturnedNum); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.chatSearchResultsAvailable, guid, messageObject.getId(), getMask(), messageObject.getDialogId()); + } + } + if (queryWithDialogFinal == dialog_id && messagesSearchEndReached[0] && mergeDialogId != 0) { + messagesSearchEndReached[1] = false; + searchMessagesInChat(lastSearchQuery, dialog_id, mergeDialogId, guid, 0); + } + } + } + } + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/query/SharedMediaQuery.java b/TMessagesProj/src/main/java/org/telegram/messenger/query/SharedMediaQuery.java new file mode 100644 index 00000000..2a184178 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/query/SharedMediaQuery.java @@ -0,0 +1,508 @@ +/* + * This is the source code of Telegram for Android v. 2.0.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger.query; + +import android.text.TextUtils; + +import org.telegram.SQLite.SQLiteCursor; +import org.telegram.SQLite.SQLiteDatabase; +import org.telegram.SQLite.SQLitePreparedStatement; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.ImageLoader; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.FileLog; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.NativeByteBuffer; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; + +public class SharedMediaQuery { + + public final static int MEDIA_PHOTOVIDEO = 0; + public final static int MEDIA_FILE = 1; + public final static int MEDIA_AUDIO = 2; + public final static int MEDIA_URL = 3; + public final static int MEDIA_MUSIC = 4; + public final static int MEDIA_TYPES_COUNT = 5; + + public static void loadMedia(final long uid, final int offset, final int count, final int max_id, final int type, final boolean fromCache, final int classGuid) { + final boolean isChannel = (int) uid < 0 && ChatObject.isChannel(-(int) uid); + + int lower_part = (int)uid; + if (fromCache || lower_part == 0) { + loadMediaDatabase(uid, offset, count, max_id, type, classGuid, isChannel); + } else { + TLRPC.TL_messages_search req = new TLRPC.TL_messages_search(); + req.offset = offset; + req.limit = count + 1; + req.max_id = max_id; + if (type == MEDIA_PHOTOVIDEO) { + req.filter = new TLRPC.TL_inputMessagesFilterPhotoVideo(); + } else if (type == MEDIA_FILE) { + req.filter = new TLRPC.TL_inputMessagesFilterDocument(); + } else if (type == MEDIA_AUDIO) { + req.filter = new TLRPC.TL_inputMessagesFilterVoice(); + } else if (type == MEDIA_URL) { + req.filter = new TLRPC.TL_inputMessagesFilterUrl(); + } else if (type == MEDIA_MUSIC) { + req.filter = new TLRPC.TL_inputMessagesFilterMusic(); + } + req.q = ""; + req.peer = MessagesController.getInputPeer(lower_part); + if (req.peer == null) { + return; + } + int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + final TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + boolean topReached; + if (res.messages.size() > count) { + topReached = false; + res.messages.remove(res.messages.size() - 1); + } else { + topReached = true; + } + processLoadedMedia(res, uid, offset, count, max_id, type, false, classGuid, isChannel, topReached); + } + } + }); + ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); + } + } + + public static void getMediaCount(final long uid, final int type, final int classGuid, boolean fromCache) { + int lower_part = (int)uid; + if (fromCache || lower_part == 0) { + getMediaCountDatabase(uid, type, classGuid); + } else { + TLRPC.TL_messages_search req = new TLRPC.TL_messages_search(); + req.offset = 0; + req.limit = 1; + req.max_id = 0; + if (type == MEDIA_PHOTOVIDEO) { + req.filter = new TLRPC.TL_inputMessagesFilterPhotoVideo(); + } else if (type == MEDIA_FILE) { + req.filter = new TLRPC.TL_inputMessagesFilterDocument(); + } else if (type == MEDIA_AUDIO) { + req.filter = new TLRPC.TL_inputMessagesFilterVoice(); + } else if (type == MEDIA_URL) { + req.filter = new TLRPC.TL_inputMessagesFilterUrl(); + } else if (type == MEDIA_MUSIC) { + req.filter = new TLRPC.TL_inputMessagesFilterMusic(); + } + req.q = ""; + req.peer = MessagesController.getInputPeer(lower_part); + if (req.peer == null) { + return; + } + int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (error == null) { + final TLRPC.messages_Messages res = (TLRPC.messages_Messages) response; + MessagesStorage.getInstance().putUsersAndChats(res.users, res.chats, true, true); + int count; + if (res instanceof TLRPC.TL_messages_messages) { + count = res.messages.size(); + } else { + count = res.count; + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().putUsers(res.users, false); + MessagesController.getInstance().putChats(res.chats, false); + } + }); + + processLoadedMediaCount(count, uid, type, classGuid, false); + } + } + }); + ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); + } + } + + public static int getMediaType(TLRPC.Message message) { + if (message == null) { + return -1; + } + if (message.media instanceof TLRPC.TL_messageMediaPhoto) { + return MEDIA_PHOTOVIDEO; + } else if (message.media instanceof TLRPC.TL_messageMediaDocument) { + if (MessageObject.isVoiceMessage(message)) { + return MEDIA_AUDIO; + } else if (MessageObject.isVideoMessage(message)) { + return MEDIA_PHOTOVIDEO; + } else if (MessageObject.isStickerMessage(message)) { + return -1; + } else if (MessageObject.isMusicMessage(message)) { + return MEDIA_MUSIC; + } else { + return MEDIA_FILE; + } + } else if (!message.entities.isEmpty()) { + for (int a = 0; a < message.entities.size(); a++) { + TLRPC.MessageEntity entity = message.entities.get(a); + if (entity instanceof TLRPC.TL_messageEntityUrl || entity instanceof TLRPC.TL_messageEntityTextUrl || entity instanceof TLRPC.TL_messageEntityEmail) { + return MEDIA_URL; + } + } + } + return -1; + } + + public static boolean canAddMessageToMedia(TLRPC.Message message) { + if (message instanceof TLRPC.TL_message_secret && message.media instanceof TLRPC.TL_messageMediaPhoto && message.ttl != 0 && message.ttl <= 60) { + return false; + } else if (message.media instanceof TLRPC.TL_messageMediaPhoto || + message.media instanceof TLRPC.TL_messageMediaDocument && !MessageObject.isGifDocument(message.media.document)) { + return true; + } else if (!message.entities.isEmpty()) { + for (int a = 0; a < message.entities.size(); a++) { + TLRPC.MessageEntity entity = message.entities.get(a); + if (entity instanceof TLRPC.TL_messageEntityUrl || entity instanceof TLRPC.TL_messageEntityTextUrl || entity instanceof TLRPC.TL_messageEntityEmail) { + return true; + } + } + } + return false; + } + + private static void processLoadedMedia(final TLRPC.messages_Messages res, final long uid, int offset, int count, int max_id, final int type, final boolean fromCache, final int classGuid, final boolean isChannel, final boolean topReached) { + int lower_part = (int)uid; + if (fromCache && res.messages.isEmpty() && lower_part != 0) { + loadMedia(uid, offset, count, max_id, type, false, classGuid); + } else { + if (!fromCache) { + ImageLoader.saveMessagesThumbs(res.messages); + MessagesStorage.getInstance().putUsersAndChats(res.users, res.chats, true, true); + putMediaDatabase(uid, type, res.messages, max_id, topReached); + } + + final HashMap usersDict = new HashMap<>(); + for (int a = 0; a < res.users.size(); a++) { + TLRPC.User u = res.users.get(a); + usersDict.put(u.id, u); + } + final ArrayList objects = new ArrayList<>(); + for (int a = 0; a < res.messages.size(); a++) { + TLRPC.Message message = res.messages.get(a); + objects.add(new MessageObject(message, usersDict, true)); + } + + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + int totalCount = res.count; + MessagesController.getInstance().putUsers(res.users, fromCache); + MessagesController.getInstance().putChats(res.chats, fromCache); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.mediaDidLoaded, uid, totalCount, objects, classGuid, type, topReached); + } + }); + } + } + + private static void processLoadedMediaCount(final int count, final long uid, final int type, final int classGuid, final boolean fromCache) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + int lower_part = (int) uid; + if (fromCache && count == -1 && lower_part != 0) { + getMediaCount(uid, type, classGuid, false); + } else { + if (!fromCache) { + putMediaCountDatabase(uid, type, count); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.mediaCountDidLoaded, uid, (fromCache && count == -1 ? 0 : count), fromCache, type); + } + } + }); + } + + private static void putMediaCountDatabase(final long uid, final int type, final int count) { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLitePreparedStatement state2 = MessagesStorage.getInstance().getDatabase().executeFast("REPLACE INTO media_counts_v2 VALUES(?, ?, ?)"); + state2.requery(); + state2.bindLong(1, uid); + state2.bindInteger(2, type); + state2.bindInteger(3, count); + state2.step(); + state2.dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + private static void getMediaCountDatabase(final long uid, final int type, final int classGuid) { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + int count = -1; + SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT count FROM media_counts_v2 WHERE uid = %d AND type = %d LIMIT 1", uid, type)); + if (cursor.next()) { + count = cursor.intValue(0); + } + cursor.dispose(); + int lower_part = (int)uid; + if (count == -1 && lower_part == 0) { + cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT COUNT(mid) FROM media_v2 WHERE uid = %d AND type = %d LIMIT 1", uid, type)); + if (cursor.next()) { + count = cursor.intValue(0); + } + cursor.dispose(); + + if (count != -1) { + putMediaCountDatabase(uid, type, count); + } + } + processLoadedMediaCount(count, uid, type, classGuid, true); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + private static void loadMediaDatabase(final long uid, final int offset, final int count, final int max_id, final int type, final int classGuid, final boolean isChannel) { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + boolean topReached = false; + TLRPC.TL_messages_messages res = new TLRPC.TL_messages_messages(); + try { + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + int countToLoad = count + 1; + + SQLiteCursor cursor; + SQLiteDatabase database = MessagesStorage.getInstance().getDatabase(); + boolean isEnd = false; + if ((int) uid != 0) { + int channelId = 0; + long messageMaxId = max_id; + if (isChannel) { + channelId = -(int) uid; + } + if (messageMaxId != 0 && channelId != 0) { + messageMaxId |= ((long) channelId) << 32; + } + + cursor = database.queryFinalized(String.format(Locale.US, "SELECT start FROM media_holes_v2 WHERE uid = %d AND type = %d AND start IN (0, 1)", uid, type)); + if (cursor.next()) { + isEnd = cursor.intValue(0) == 1; + cursor.dispose(); + } else { + cursor.dispose(); + cursor = database.queryFinalized(String.format(Locale.US, "SELECT min(mid) FROM media_v2 WHERE uid = %d AND type = %d AND mid > 0", uid, type)); + if (cursor.next()) { + int mid = cursor.intValue(0); + if (mid != 0) { + SQLitePreparedStatement state = database.executeFast("REPLACE INTO media_holes_v2 VALUES(?, ?, ?, ?)"); + state.requery(); + state.bindLong(1, uid); + state.bindInteger(2, type); + state.bindInteger(3, 0); + state.bindInteger(4, mid); + state.step(); + state.dispose(); + } + } + cursor.dispose(); + } + + if (messageMaxId != 0) { + long holeMessageId = 0; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT end FROM media_holes_v2 WHERE uid = %d AND type = %d AND end <= %d ORDER BY end DESC LIMIT 1", uid, type, max_id)); + if (cursor.next()) { + holeMessageId = cursor.intValue(0); + if (channelId != 0) { + holeMessageId |= ((long) channelId) << 32; + } + } + cursor.dispose(); + if (holeMessageId > 1) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid FROM media_v2 WHERE uid = %d AND mid > 0 AND mid < %d AND mid >= %d AND type = %d ORDER BY date DESC, mid DESC LIMIT %d", uid, messageMaxId, holeMessageId, type, countToLoad)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid FROM media_v2 WHERE uid = %d AND mid > 0 AND mid < %d AND type = %d ORDER BY date DESC, mid DESC LIMIT %d", uid, messageMaxId, type, countToLoad)); + } + } else { + long holeMessageId = 0; + cursor = database.queryFinalized(String.format(Locale.US, "SELECT max(end) FROM media_holes_v2 WHERE uid = %d AND type = %d", uid, type)); + if (cursor.next()) { + holeMessageId = cursor.intValue(0); + if (channelId != 0) { + holeMessageId |= ((long) channelId) << 32; + } + } + cursor.dispose(); + if (holeMessageId > 1) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid FROM media_v2 WHERE uid = %d AND mid >= %d AND type = %d ORDER BY date DESC, mid DESC LIMIT %d,%d", uid, holeMessageId, type, offset, countToLoad)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT data, mid FROM media_v2 WHERE uid = %d AND mid > 0 AND type = %d ORDER BY date DESC, mid DESC LIMIT %d,%d", uid, type, offset, countToLoad)); + } + } + } else { + isEnd = true; + if (max_id != 0) { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.data, m.mid, r.random_id FROM media_v2 as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND m.mid > %d AND type = %d ORDER BY m.mid ASC LIMIT %d", uid, max_id, type, countToLoad)); + } else { + cursor = database.queryFinalized(String.format(Locale.US, "SELECT m.data, m.mid, r.random_id FROM media_v2 as m LEFT JOIN randoms as r ON r.mid = m.mid WHERE m.uid = %d AND type = %d ORDER BY m.mid ASC LIMIT %d,%d", uid, type, offset, countToLoad)); + } + } + + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + message.id = cursor.intValue(1); + message.dialog_id = uid; + if ((int) uid == 0) { + message.random_id = cursor.longValue(2); + } + res.messages.add(message); + if (message.from_id > 0) { + if (!usersToLoad.contains(message.from_id)) { + usersToLoad.add(message.from_id); + } + } else { + if (!chatsToLoad.contains(-message.from_id)) { + chatsToLoad.add(-message.from_id); + } + } + } + data.reuse(); + } + cursor.dispose(); + + if (!usersToLoad.isEmpty()) { + MessagesStorage.getInstance().getUsersInternal(TextUtils.join(",", usersToLoad), res.users); + } + if (!chatsToLoad.isEmpty()) { + MessagesStorage.getInstance().getChatsInternal(TextUtils.join(",", chatsToLoad), res.chats); + } + if (res.messages.size() > count) { + topReached = false; + res.messages.remove(res.messages.size() - 1); + } else { + topReached = isEnd; + } + } catch (Exception e) { + res.messages.clear(); + res.chats.clear(); + res.users.clear(); + FileLog.e("tmessages", e); + } finally { + processLoadedMedia(res, uid, offset, count, max_id, type, true, classGuid, isChannel, topReached); + } + } + }); + } + + private static void putMediaDatabase(final long uid, final int type, final ArrayList messages, final int max_id, final boolean topReached) { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + if (messages.isEmpty() || topReached) { + MessagesStorage.getInstance().doneHolesInMedia(uid, max_id, type); + if (messages.isEmpty()) { + return; + } + } + MessagesStorage.getInstance().getDatabase().beginTransaction(); + SQLitePreparedStatement state2 = MessagesStorage.getInstance().getDatabase().executeFast("REPLACE INTO media_v2 VALUES(?, ?, ?, ?, ?)"); + for (TLRPC.Message message : messages) { + if (canAddMessageToMedia(message)) { + + long messageId = message.id; + if (message.to_id.channel_id != 0) { + messageId |= ((long) message.to_id.channel_id) << 32; + } + + state2.requery(); + NativeByteBuffer data = new NativeByteBuffer(message.getObjectSize()); + message.serializeToStream(data); + state2.bindLong(1, messageId); + state2.bindLong(2, uid); + state2.bindInteger(3, message.date); + state2.bindInteger(4, type); + state2.bindByteBuffer(5, data); + state2.step(); + data.reuse(); + } + } + state2.dispose(); + if (!topReached || max_id != 0) { + int minId = topReached ? 1 : messages.get(messages.size() - 1).id; + if (max_id != 0) { + MessagesStorage.getInstance().closeHolesInMedia(uid, minId, max_id, type); + } else { + MessagesStorage.getInstance().closeHolesInMedia(uid, minId, Integer.MAX_VALUE, type); + } + } + MessagesStorage.getInstance().getDatabase().commitTransaction(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public static void loadMusic(final long uid, final int max_id) { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + final ArrayList arrayList = new ArrayList<>(); + try { + SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, mid FROM media_v2 WHERE uid = %d AND mid < %d AND type = %d ORDER BY date DESC, mid DESC LIMIT 1000", uid, max_id, MEDIA_MUSIC)); + + while (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + if (MessageObject.isMusicMessage(message)) { + message.id = cursor.intValue(1); + message.dialog_id = uid; + arrayList.add(0, new MessageObject(message, null, false)); + } + } + data.reuse(); + } + cursor.dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.musicDidLoaded, uid, arrayList); + } + }); + } + }); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/query/StickersQuery.java b/TMessagesProj/src/main/java/org/telegram/messenger/query/StickersQuery.java new file mode 100644 index 00000000..bbc794bb --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/query/StickersQuery.java @@ -0,0 +1,512 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger.query; + +import android.content.Context; +import android.widget.Toast; + +import org.telegram.SQLite.SQLiteCursor; +import org.telegram.SQLite.SQLitePreparedStatement; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.R; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.NativeByteBuffer; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.messenger.Utilities; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; + +public class StickersQuery { + + private static int loadHash; + private static int loadDate; + private static ArrayList stickerSets = new ArrayList<>(); + private static HashMap stickerSetsById = new HashMap<>(); + private static HashMap stickerSetsByName = new HashMap<>(); + private static HashMap stickersByEmoji = new HashMap<>(); + private static HashMap stickersById = new HashMap<>(); + private static HashMap> allStickers = new HashMap<>(); + + private static boolean loadingStickers; + private static boolean stickersLoaded; + + public static void cleanup() { + loadHash = 0; + loadDate = 0; + allStickers.clear(); + stickerSets.clear(); + stickersByEmoji.clear(); + stickerSetsById.clear(); + stickerSetsByName.clear(); + loadingStickers = false; + stickersLoaded = false; + } + + public static void checkStickers() { + if (!loadingStickers && (!stickersLoaded || Math.abs(System.currentTimeMillis() / 1000 - loadDate) >= 60 * 60)) { + loadStickers(true, false); + } + } + + public static boolean isLoadingStickers() { + return loadingStickers; + } + + public static TLRPC.Document getStickerById(long id) { + TLRPC.Document document = stickersById.get(id); + if (document != null) { + long setId = getStickerSetId(document); + TLRPC.TL_messages_stickerSet stickerSet = stickerSetsById.get(setId); + if (stickerSet != null && stickerSet.set.disabled) { + return null; + } + } + return document; + } + + public static TLRPC.TL_messages_stickerSet getStickerSetByName(String name) { + return stickerSetsByName.get(name); + } + + public static TLRPC.TL_messages_stickerSet getStickerSetById(Long id) { + return stickerSetsById.get(id); + } + + public static HashMap> getAllStickers() { + return allStickers; + } + + public static ArrayList getStickerSets() { + return stickerSets; + } + + public static boolean isStickerPackInstalled(long id) { + return stickerSetsById.containsKey(id); + } + + public static boolean isStickerPackInstalled(String name) { + return stickerSetsByName.containsKey(name); + } + + public static String getEmojiForSticker(long id) { + String value = stickersByEmoji.get(id); + return value != null ? value : ""; + } + + public static void reorderStickers(final ArrayList order) { + Collections.sort(stickerSets, new Comparator() { + @Override + public int compare(TLRPC.TL_messages_stickerSet lhs, TLRPC.TL_messages_stickerSet rhs) { + int index1 = order.indexOf(lhs.set.id); + int index2 = order.indexOf(rhs.set.id); + if (index1 > index2) { + return 1; + } else if (index1 < index2) { + return -1; + } + return 0; + } + }); + loadHash = calcStickersHash(stickerSets); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.stickersDidLoaded); + StickersQuery.loadStickers(false, true); + } + + public static void calcNewHash() { + loadHash = calcStickersHash(stickerSets); + } + + public static void addNewStickerSet(final TLRPC.TL_messages_stickerSet set) { + if (stickerSetsById.containsKey(set.set.id) || stickerSetsByName.containsKey(set.set.short_name)) { + return; + } + stickerSets.add(0, set); + stickerSetsById.put(set.set.id, set); + stickerSetsByName.put(set.set.short_name, set); + for (int a = 0; a < set.documents.size(); a++) { + TLRPC.Document document = set.documents.get(a); + stickersById.put(document.id, document); + } + for (int a = 0; a < set.packs.size(); a++) { + TLRPC.TL_stickerPack stickerPack = set.packs.get(a); + stickerPack.emoticon = stickerPack.emoticon.replace("\uFE0F", ""); + ArrayList arrayList = allStickers.get(stickerPack.emoticon); + if (arrayList == null) { + arrayList = new ArrayList<>(); + allStickers.put(stickerPack.emoticon, arrayList); + } + for (int c = 0; c < stickerPack.documents.size(); c++) { + Long id = stickerPack.documents.get(c); + if (!stickersByEmoji.containsKey(id)) { + stickersByEmoji.put(id, stickerPack.emoticon); + } + arrayList.add(stickersById.get(id)); + } + } + loadHash = calcStickersHash(stickerSets); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.stickersDidLoaded); + StickersQuery.loadStickers(false, true); + } + + public static void loadStickers(boolean cache, boolean force) { + if (loadingStickers) { + return; + } + loadingStickers = true; + if (cache) { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + ArrayList newStickerArray = null; + int date = 0; + int hash = 0; + SQLiteCursor cursor = null; + try { + cursor = MessagesStorage.getInstance().getDatabase().queryFinalized("SELECT data, date, hash FROM stickers_v2 WHERE 1"); + if (cursor.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + newStickerArray = new ArrayList<>(); + int count = data.readInt32(false); + for (int a = 0; a < count; a++) { + TLRPC.TL_messages_stickerSet stickerSet = TLRPC.TL_messages_stickerSet.TLdeserialize(data, data.readInt32(false), false); + newStickerArray.add(stickerSet); + } + } + date = cursor.intValue(1); + hash = calcStickersHash(newStickerArray); + data.reuse(); + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } finally { + if (cursor != null) { + cursor.dispose(); + } + } + processLoadedStickers(newStickerArray, true, date, hash); + } + }); + } else { + final TLRPC.TL_messages_getAllStickers req = new TLRPC.TL_messages_getAllStickers(); + req.hash = force ? 0 : loadHash; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (response instanceof TLRPC.TL_messages_allStickers) { + final HashMap newStickerSets = new HashMap<>(); + final ArrayList newStickerArray = new ArrayList<>(); + final TLRPC.TL_messages_allStickers res = (TLRPC.TL_messages_allStickers) response; + + for (int a = 0; a < res.sets.size(); a++) { + final TLRPC.StickerSet stickerSet = res.sets.get(a); + + TLRPC.TL_messages_stickerSet oldSet = stickerSetsById.get(stickerSet.id); + if (oldSet != null && oldSet.set.hash == stickerSet.hash) { + oldSet.set.disabled = stickerSet.disabled; + oldSet.set.installed = stickerSet.installed; + oldSet.set.official = stickerSet.official; + newStickerSets.put(oldSet.set.id, oldSet); + newStickerArray.add(oldSet); + + if (newStickerSets.size() == res.sets.size()) { + processLoadedStickers(newStickerArray, false, (int) (System.currentTimeMillis() / 1000), res.hash); + } + continue; + } + + newStickerArray.add(null); + final int index = a; + + TLRPC.TL_messages_getStickerSet req = new TLRPC.TL_messages_getStickerSet(); + req.stickerset = new TLRPC.TL_inputStickerSetID(); + req.stickerset.id = stickerSet.id; + req.stickerset.access_hash = stickerSet.access_hash; + + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + TLRPC.TL_messages_stickerSet res1 = (TLRPC.TL_messages_stickerSet) response; + newStickerArray.set(index, res1); + newStickerSets.put(stickerSet.id, res1); + if (newStickerSets.size() == res.sets.size()) { + processLoadedStickers(newStickerArray, false, (int) (System.currentTimeMillis() / 1000), res.hash); + } + } + }); + } + }); + } + } else { + processLoadedStickers(null, false, (int) (System.currentTimeMillis() / 1000), req.hash); + } + } + }); + } + }); + } + } + + private static void putStickersToCache(ArrayList stickers, final int date, final int hash) { + final ArrayList stickersFinal = stickers != null ? new ArrayList<>(stickers) : null; + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + if (stickersFinal != null) { + SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("REPLACE INTO stickers_v2 VALUES(?, ?, ?, ?)"); + state.requery(); + int size = 4; + for (int a = 0; a < stickersFinal.size(); a++) { + size += stickersFinal.get(a).getObjectSize(); + } + NativeByteBuffer data = new NativeByteBuffer(size); + data.writeInt32(stickersFinal.size()); + for (int a = 0; a < stickersFinal.size(); a++) { + stickersFinal.get(a).serializeToStream(data); + } + state.bindInteger(1, 1); + state.bindByteBuffer(2, data); + state.bindInteger(3, date); + state.bindInteger(4, hash); + state.step(); + data.reuse(); + state.dispose(); + } else { + SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("UPDATE stickers_v2 SET date = ?"); + state.requery(); + state.bindInteger(1, date); + state.step(); + state.dispose(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public static String getStickerSetName(long setId) { + TLRPC.TL_messages_stickerSet stickerSet = stickerSetsById.get(setId); + return stickerSet != null ? stickerSet.set.short_name : null; + } + + public static long getStickerSetId(TLRPC.Document document) { + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeSticker) { + if (attribute.stickerset instanceof TLRPC.TL_inputStickerSetID) { + return attribute.stickerset.id; + } + break; + } + } + return -1; + } + + private static int calcStickersHash(ArrayList sets) { + long acc = 0; + for (int a = 0; a < sets.size(); a++) { + TLRPC.StickerSet set = sets.get(a).set; + if (set.disabled) { + continue; + } + acc = ((acc * 20261) + 0x80000000L + set.hash) % 0x80000000L; + } + return (int) acc; + } + + private static void processLoadedStickers(final ArrayList res, final boolean cache, final int date, final int hash) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + loadingStickers = false; + stickersLoaded = true; + } + }); + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + if (cache && (res == null || Math.abs(System.currentTimeMillis() / 1000 - date) >= 60 * 60) || !cache && res == null && hash == 0) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (res != null && hash != 0) { + loadHash = hash; + } + loadStickers(false, false); + } + }, res == null && !cache ? 1000 : 0); + if (res == null) { + return; + } + } + if (res != null) { + try { + final ArrayList stickerSetsNew = new ArrayList<>(); + final HashMap stickerSetsByIdNew = new HashMap<>(); + final HashMap stickerSetsByNameNew = new HashMap<>(); + final HashMap stickersByEmojiNew = new HashMap<>(); + final HashMap stickersByIdNew = new HashMap<>(); + final HashMap> allStickersNew = new HashMap<>(); + + for (int a = 0; a < res.size(); a++) { + TLRPC.TL_messages_stickerSet stickerSet = res.get(a); + if (stickerSet == null) { + continue; + } + stickerSetsNew.add(stickerSet); + stickerSetsByIdNew.put(stickerSet.set.id, stickerSet); + stickerSetsByNameNew.put(stickerSet.set.short_name, stickerSet); + + for (int b = 0; b < stickerSet.documents.size(); b++) { + TLRPC.Document document = stickerSet.documents.get(b); + if (document == null || document instanceof TLRPC.TL_documentEmpty) { + continue; + } + stickersByIdNew.put(document.id, document); + } + if (!stickerSet.set.disabled) { + for (int b = 0; b < stickerSet.packs.size(); b++) { + TLRPC.TL_stickerPack stickerPack = stickerSet.packs.get(b); + if (stickerPack == null || stickerPack.emoticon == null) { + continue; + } + stickerPack.emoticon = stickerPack.emoticon.replace("\uFE0F", ""); + ArrayList arrayList = allStickersNew.get(stickerPack.emoticon); + if (arrayList == null) { + arrayList = new ArrayList<>(); + allStickersNew.put(stickerPack.emoticon, arrayList); + } + for (int c = 0; c < stickerPack.documents.size(); c++) { + Long id = stickerPack.documents.get(c); + if (!stickersByEmojiNew.containsKey(id)) { + stickersByEmojiNew.put(id, stickerPack.emoticon); + } + arrayList.add(stickersByIdNew.get(id)); + } + } + } + } + + if (!cache) { + putStickersToCache(stickerSetsNew, date, hash); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + stickersById = stickersByIdNew; + stickerSetsById = stickerSetsByIdNew; + stickerSetsByName = stickerSetsByNameNew; + stickerSets = stickerSetsNew; + allStickers = allStickersNew; + stickersByEmoji = stickersByEmojiNew; + loadHash = hash; + loadDate = date; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.stickersDidLoaded); + } + }); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } else if (!cache) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + loadDate = date; + } + }); + putStickersToCache(null, date, 0); + } + } + }); + } + + public static void removeStickersSet(final Context context, TLRPC.StickerSet stickerSet, int hide) { + TLRPC.TL_inputStickerSetID stickerSetID = new TLRPC.TL_inputStickerSetID(); + stickerSetID.access_hash = stickerSet.access_hash; + stickerSetID.id = stickerSet.id; + if (hide != 0) { + stickerSet.disabled = hide == 1; + for (int a = 0; a < stickerSets.size(); a++) { + TLRPC.TL_messages_stickerSet set = stickerSets.get(a); + if (set.set.id == stickerSet.id) { + stickerSets.remove(a); + if (hide == 2) { + stickerSets.add(0, set); + } else { + for (int b = stickerSets.size() - 1; b >= 0; b--) { + if (stickerSets.get(b).set.disabled) { + continue; + } + stickerSets.add(b + 1, set); + break; + } + } + break; + } + } + loadHash = calcStickersHash(stickerSets); + putStickersToCache(stickerSets, loadDate, loadHash); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.stickersDidLoaded); + TLRPC.TL_messages_installStickerSet req = new TLRPC.TL_messages_installStickerSet(); + req.stickerset = stickerSetID; + req.disabled = hide == 1; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + loadStickers(false, false); + } + }, 1000); + } + }); + } else { + TLRPC.TL_messages_uninstallStickerSet req = new TLRPC.TL_messages_uninstallStickerSet(); + req.stickerset = stickerSetID; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + if (error == null) { + Toast.makeText(context, LocaleController.getString("StickersRemoved", R.string.StickersRemoved), Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(context, LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred), Toast.LENGTH_SHORT).show(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + loadStickers(false, true); + } + }); + } + }); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsCallback.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsCallback.java new file mode 100644 index 00000000..f5cb4a32 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsCallback.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.customtabs; + +import android.os.Bundle; + +/** + * A callback class for custom tabs client to get messages regarding events in their custom tabs. + */ +public class CustomTabsCallback { + public static final int NAVIGATION_STARTED = 1; + public static final int NAVIGATION_FINISHED = 2; + public static final int NAVIGATION_FAILED = 3; + public static final int NAVIGATION_ABORTED = 4; + public static final int TAB_SHOWN = 5; + public static final int TAB_HIDDEN = 6; + + public CustomTabsCallback() { + } + + public void onNavigationEvent(int navigationEvent, Bundle extras) { + } + + public void extraCallback(String callbackName, Bundle args) { + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsClient.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsClient.java new file mode 100644 index 00000000..d80d30b5 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsClient.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.customtabs; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.RemoteException; +import android.text.TextUtils; + +public class CustomTabsClient { + private final ICustomTabsService mService; + private final ComponentName mServiceComponentName; + + CustomTabsClient(ICustomTabsService service, ComponentName componentName) { + this.mService = service; + this.mServiceComponentName = componentName; + } + + public static boolean bindCustomTabsService(Context context, String packageName, CustomTabsServiceConnection connection) { + Intent intent = new Intent("android.support.customtabs.action.CustomTabsService"); + if (!TextUtils.isEmpty(packageName)) { + intent.setPackage(packageName); + } + + return context.bindService(intent, connection, 33); + } + + public boolean warmup(long flags) { + try { + return this.mService.warmup(flags); + } catch (RemoteException var4) { + return false; + } + } + + public CustomTabsSession newSession(final CustomTabsCallback callback) { + ICustomTabsCallback.Stub wrapper = new ICustomTabsCallback.Stub() { + public void onNavigationEvent(int navigationEvent, Bundle extras) { + if (callback != null) { + callback.onNavigationEvent(navigationEvent, extras); + } + + } + + public void extraCallback(String callbackName, Bundle args) throws RemoteException { + if (callback != null) { + callback.extraCallback(callbackName, args); + } + + } + }; + + try { + if (!this.mService.newSession(wrapper)) { + return null; + } + } catch (RemoteException var4) { + return null; + } + + return new CustomTabsSession(this.mService, wrapper, this.mServiceComponentName); + } + + public Bundle extraCommand(String commandName, Bundle args) { + try { + return this.mService.extraCommand(commandName, args); + } catch (RemoteException var4) { + return null; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsIntent.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsIntent.java new file mode 100644 index 00000000..16bf9526 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsIntent.java @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.customtabs; + +import android.app.Activity; +import android.app.PendingIntent; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.support.annotation.AnimRes; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.ActivityCompat; +import android.support.v4.app.ActivityOptionsCompat; +import android.support.v4.app.BundleCompat; + +import java.util.ArrayList; + +/** + * Class holding the {@link Intent} and start bundle for a Custom Tabs Activity. + * + *

+ * Note: The constants below are public for the browser implementation's benefit. + * You are strongly encouraged to use {@link CustomTabsIntent.Builder}.

+ */ +public final class CustomTabsIntent { + public static final String EXTRA_SESSION = "android.support.customtabs.extra.SESSION"; + public static final String EXTRA_TOOLBAR_COLOR = "android.support.customtabs.extra.TOOLBAR_COLOR"; + public static final String EXTRA_ENABLE_URLBAR_HIDING = "android.support.customtabs.extra.ENABLE_URLBAR_HIDING"; + public static final String EXTRA_CLOSE_BUTTON_ICON = "android.support.customtabs.extra.CLOSE_BUTTON_ICON"; + public static final String EXTRA_TITLE_VISIBILITY_STATE = "android.support.customtabs.extra.TITLE_VISIBILITY"; + public static final int NO_TITLE = 0; + public static final int SHOW_PAGE_TITLE = 1; + public static final String EXTRA_ACTION_BUTTON_BUNDLE = "android.support.customtabs.extra.ACTION_BUTTON_BUNDLE"; + public static final String EXTRA_TOOLBAR_ITEMS = "android.support.customtabs.extra.TOOLBAR_ITEMS"; + public static final String EXTRA_SECONDARY_TOOLBAR_COLOR = "android.support.customtabs.extra.SECONDARY_TOOLBAR_COLOR"; + public static final String KEY_ICON = "android.support.customtabs.customaction.ICON"; + public static final String KEY_DESCRIPTION = "android.support.customtabs.customaction.DESCRIPTION"; + public static final String KEY_PENDING_INTENT = "android.support.customtabs.customaction.PENDING_INTENT"; + public static final String EXTRA_TINT_ACTION_BUTTON = "android.support.customtabs.extra.TINT_ACTION_BUTTON"; + public static final String EXTRA_MENU_ITEMS = "android.support.customtabs.extra.MENU_ITEMS"; + public static final String KEY_MENU_ITEM_TITLE = "android.support.customtabs.customaction.MENU_ITEM_TITLE"; + public static final String EXTRA_EXIT_ANIMATION_BUNDLE = "android.support.customtabs.extra.EXIT_ANIMATION_BUNDLE"; + public static final String EXTRA_DEFAULT_SHARE_MENU_ITEM = "android.support.customtabs.extra.SHARE_MENU_ITEM"; + public static final String KEY_ID = "android.support.customtabs.customaction.ID"; + public static final int TOOLBAR_ACTION_BUTTON_ID = 0; + private static final int MAX_TOOLBAR_ITEMS = 5; + @NonNull + public final Intent intent; + @Nullable + public final Bundle startAnimationBundle; + + public void launchUrl(Activity context, Uri url) { + this.intent.setData(url); + ActivityCompat.startActivity(context, this.intent, this.startAnimationBundle); + } + + private CustomTabsIntent(Intent intent, Bundle startAnimationBundle) { + this.intent = intent; + this.startAnimationBundle = startAnimationBundle; + } + + public static int getMaxToolbarItems() { + return 5; + } + + public static final class Builder { + private final Intent mIntent; + private ArrayList mMenuItems; + private Bundle mStartAnimationBundle; + private ArrayList mActionButtons; + + public Builder() { + this(null); + } + + public Builder(@Nullable CustomTabsSession session) { + this.mIntent = new Intent("android.intent.action.VIEW"); + this.mMenuItems = null; + this.mStartAnimationBundle = null; + this.mActionButtons = null; + if (session != null) { + this.mIntent.setPackage(session.getComponentName().getPackageName()); + } + + Bundle bundle = new Bundle(); + BundleCompat.putBinder(bundle, "android.support.customtabs.extra.SESSION", session == null ? null : session.getBinder()); + this.mIntent.putExtras(bundle); + } + + public CustomTabsIntent.Builder setToolbarColor(@ColorInt int color) { + this.mIntent.putExtra("android.support.customtabs.extra.TOOLBAR_COLOR", color); + return this; + } + + public CustomTabsIntent.Builder enableUrlBarHiding() { + this.mIntent.putExtra("android.support.customtabs.extra.ENABLE_URLBAR_HIDING", true); + return this; + } + + public CustomTabsIntent.Builder setCloseButtonIcon(@NonNull Bitmap icon) { + this.mIntent.putExtra("android.support.customtabs.extra.CLOSE_BUTTON_ICON", icon); + return this; + } + + public CustomTabsIntent.Builder setShowTitle(boolean showTitle) { + this.mIntent.putExtra("android.support.customtabs.extra.TITLE_VISIBILITY", showTitle ? 1 : 0); + return this; + } + + public CustomTabsIntent.Builder addMenuItem(@NonNull String label, @NonNull PendingIntent pendingIntent) { + if (this.mMenuItems == null) { + this.mMenuItems = new ArrayList(); + } + + Bundle bundle = new Bundle(); + bundle.putString("android.support.customtabs.customaction.MENU_ITEM_TITLE", label); + bundle.putParcelable("android.support.customtabs.customaction.PENDING_INTENT", pendingIntent); + this.mMenuItems.add(bundle); + return this; + } + + public CustomTabsIntent.Builder addDefaultShareMenuItem() { + this.mIntent.putExtra("android.support.customtabs.extra.SHARE_MENU_ITEM", true); + return this; + } + + public CustomTabsIntent.Builder setActionButton(@NonNull Bitmap icon, @NonNull String description, @NonNull PendingIntent pendingIntent, boolean shouldTint) { + Bundle bundle = new Bundle(); + bundle.putInt("android.support.customtabs.customaction.ID", 0); + bundle.putParcelable("android.support.customtabs.customaction.ICON", icon); + bundle.putString("android.support.customtabs.customaction.DESCRIPTION", description); + bundle.putParcelable("android.support.customtabs.customaction.PENDING_INTENT", pendingIntent); + this.mIntent.putExtra("android.support.customtabs.extra.ACTION_BUTTON_BUNDLE", bundle); + this.mIntent.putExtra("android.support.customtabs.extra.TINT_ACTION_BUTTON", shouldTint); + return this; + } + + public CustomTabsIntent.Builder setActionButton(@NonNull Bitmap icon, @NonNull String description, @NonNull PendingIntent pendingIntent) { + return this.setActionButton(icon, description, pendingIntent, false); + } + + public CustomTabsIntent.Builder addToolbarItem(int id, @NonNull Bitmap icon, @NonNull String description, PendingIntent pendingIntent) throws IllegalStateException { + if (this.mActionButtons == null) { + this.mActionButtons = new ArrayList(); + } + + if (this.mActionButtons.size() >= 5) { + throw new IllegalStateException("Exceeded maximum toolbar item count of 5"); + } else { + Bundle bundle = new Bundle(); + bundle.putInt("android.support.customtabs.customaction.ID", id); + bundle.putParcelable("android.support.customtabs.customaction.ICON", icon); + bundle.putString("android.support.customtabs.customaction.DESCRIPTION", description); + bundle.putParcelable("android.support.customtabs.customaction.PENDING_INTENT", pendingIntent); + this.mActionButtons.add(bundle); + return this; + } + } + + public CustomTabsIntent.Builder setSecondaryToolbarColor(@ColorInt int color) { + this.mIntent.putExtra("android.support.customtabs.extra.SECONDARY_TOOLBAR_COLOR", color); + return this; + } + + public CustomTabsIntent.Builder setStartAnimations(@NonNull Context context, @AnimRes int enterResId, @AnimRes int exitResId) { + this.mStartAnimationBundle = ActivityOptionsCompat.makeCustomAnimation(context, enterResId, exitResId).toBundle(); + return this; + } + + public CustomTabsIntent.Builder setExitAnimations(@NonNull Context context, @AnimRes int enterResId, @AnimRes int exitResId) { + Bundle bundle = ActivityOptionsCompat.makeCustomAnimation(context, enterResId, exitResId).toBundle(); + this.mIntent.putExtra("android.support.customtabs.extra.EXIT_ANIMATION_BUNDLE", bundle); + return this; + } + + public CustomTabsIntent build() { + if (this.mMenuItems != null) { + this.mIntent.putParcelableArrayListExtra("android.support.customtabs.extra.MENU_ITEMS", this.mMenuItems); + } + + if (this.mActionButtons != null) { + this.mIntent.putParcelableArrayListExtra("android.support.customtabs.extra.TOOLBAR_ITEMS", this.mActionButtons); + } + + return new CustomTabsIntent(this.mIntent, this.mStartAnimationBundle); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsService.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsService.java new file mode 100644 index 00000000..aa60199f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsService.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.customtabs; + +import android.app.Service; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.IBinder; +import android.os.IBinder.DeathRecipient; +import android.os.RemoteException; +import android.support.v4.util.ArrayMap; + +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; + +public abstract class CustomTabsService extends Service { + public static final String ACTION_CUSTOM_TABS_CONNECTION = "android.support.customtabs.action.CustomTabsService"; + public static final String KEY_URL = "android.support.customtabs.otherurls.URL"; + private final Map mDeathRecipientMap = new ArrayMap(); + private ICustomTabsService.Stub mBinder = new ICustomTabsService.Stub() { + public boolean warmup(long flags) { + return CustomTabsService.this.warmup(flags); + } + + public boolean newSession(ICustomTabsCallback callback) { + final CustomTabsSessionToken sessionToken = new CustomTabsSessionToken(callback); + + try { + DeathRecipient e = new DeathRecipient() { + public void binderDied() { + CustomTabsService.this.cleanUpSession(sessionToken); + } + }; + synchronized (CustomTabsService.this.mDeathRecipientMap) { + callback.asBinder().linkToDeath(e, 0); + CustomTabsService.this.mDeathRecipientMap.put(callback.asBinder(), e); + } + + return CustomTabsService.this.newSession(sessionToken); + } catch (RemoteException var7) { + return false; + } + } + + public boolean mayLaunchUrl(ICustomTabsCallback callback, Uri url, Bundle extras, List otherLikelyBundles) { + return CustomTabsService.this.mayLaunchUrl(new CustomTabsSessionToken(callback), url, extras, otherLikelyBundles); + } + + public Bundle extraCommand(String commandName, Bundle args) { + return CustomTabsService.this.extraCommand(commandName, args); + } + + public boolean updateVisuals(ICustomTabsCallback callback, Bundle bundle) { + return CustomTabsService.this.updateVisuals(new CustomTabsSessionToken(callback), bundle); + } + }; + + public CustomTabsService() { + } + + public IBinder onBind(Intent intent) { + return this.mBinder; + } + + protected boolean cleanUpSession(CustomTabsSessionToken sessionToken) { + try { + Map e = this.mDeathRecipientMap; + synchronized (this.mDeathRecipientMap) { + IBinder binder = sessionToken.getCallbackBinder(); + DeathRecipient deathRecipient = this.mDeathRecipientMap.get(binder); + binder.unlinkToDeath(deathRecipient, 0); + this.mDeathRecipientMap.remove(binder); + return true; + } + } catch (NoSuchElementException var7) { + return false; + } + } + + protected abstract boolean warmup(long var1); + + protected abstract boolean newSession(CustomTabsSessionToken var1); + + protected abstract boolean mayLaunchUrl(CustomTabsSessionToken var1, Uri var2, Bundle var3, List var4); + + protected abstract Bundle extraCommand(String var1, Bundle var2); + + protected abstract boolean updateVisuals(CustomTabsSessionToken var1, Bundle var2); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsServiceConnection.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsServiceConnection.java new file mode 100644 index 00000000..7998b02d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsServiceConnection.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.customtabs; + +import android.content.ComponentName; +import android.content.ServiceConnection; +import android.os.IBinder; + +public abstract class CustomTabsServiceConnection implements ServiceConnection { + public CustomTabsServiceConnection() { + } + + public final void onServiceConnected(final ComponentName name, IBinder service) { + this.onCustomTabsServiceConnected(name, new CustomTabsClient(ICustomTabsService.Stub.asInterface(service), name) { + }); + } + + public abstract void onCustomTabsServiceConnected(ComponentName var1, CustomTabsClient var2); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsSession.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsSession.java new file mode 100644 index 00000000..a84755a4 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsSession.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.customtabs; + +import android.content.ComponentName; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.support.annotation.NonNull; + +import java.util.List; + +/** + * A class to be used for Custom Tabs related communication. Clients that want to launch Custom Tabs + * can use this class exclusively to handle all related communication. + */ +public final class CustomTabsSession { + private static final String TAG = "CustomTabsSession"; + private final ICustomTabsService mService; + private final ICustomTabsCallback mCallback; + private final ComponentName mComponentName; + + CustomTabsSession(ICustomTabsService service, ICustomTabsCallback callback, ComponentName componentName) { + this.mService = service; + this.mCallback = callback; + this.mComponentName = componentName; + } + + public boolean mayLaunchUrl(Uri url, Bundle extras, List otherLikelyBundles) { + try { + return this.mService.mayLaunchUrl(this.mCallback, url, extras, otherLikelyBundles); + } catch (RemoteException var5) { + return false; + } + } + + public boolean setActionButton(@NonNull Bitmap icon, @NonNull String description) { + return this.setToolbarItem(0, icon, description); + } + + public boolean setToolbarItem(int id, @NonNull Bitmap icon, @NonNull String description) { + Bundle bundle = new Bundle(); + bundle.putInt("android.support.customtabs.customaction.ID", id); + bundle.putParcelable("android.support.customtabs.customaction.ICON", icon); + bundle.putString("android.support.customtabs.customaction.DESCRIPTION", description); + Bundle metaBundle = new Bundle(); + metaBundle.putBundle("android.support.customtabs.extra.ACTION_BUTTON_BUNDLE", bundle); + + try { + return this.mService.updateVisuals(this.mCallback, metaBundle); + } catch (RemoteException var7) { + return false; + } + } + + IBinder getBinder() { + return this.mCallback.asBinder(); + } + + ComponentName getComponentName() { + return this.mComponentName; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsSessionToken.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsSessionToken.java new file mode 100644 index 00000000..00708177 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/CustomTabsSessionToken.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.customtabs; + +import android.content.Intent; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.support.v4.app.BundleCompat; +import android.util.Log; + +/** + * Wrapper class that can be used as a unique identifier for a session. Also contains an accessor + * for the {@link CustomTabsCallback} for the session if there was any. + */ +public class CustomTabsSessionToken { + private static final String TAG = "CustomTabsSessionToken"; + private final ICustomTabsCallback mCallbackBinder; + private final CustomTabsCallback mCallback; + + public static CustomTabsSessionToken getSessionTokenFromIntent(Intent intent) { + Bundle b = intent.getExtras(); + IBinder binder = BundleCompat.getBinder(b, "android.support.customtabs.extra.SESSION"); + return binder == null ? null : new CustomTabsSessionToken(ICustomTabsCallback.Stub.asInterface(binder)); + } + + CustomTabsSessionToken(ICustomTabsCallback callbackBinder) { + this.mCallbackBinder = callbackBinder; + this.mCallback = new CustomTabsCallback() { + public void onNavigationEvent(int navigationEvent, Bundle extras) { + try { + CustomTabsSessionToken.this.mCallbackBinder.onNavigationEvent(navigationEvent, extras); + } catch (RemoteException var4) { + Log.e("CustomTabsSessionToken", "RemoteException during ICustomTabsCallback transaction"); + } + + } + }; + } + + IBinder getCallbackBinder() { + return this.mCallbackBinder.asBinder(); + } + + public int hashCode() { + return this.getCallbackBinder().hashCode(); + } + + public boolean equals(Object o) { + if (!(o instanceof CustomTabsSessionToken)) { + return false; + } else { + CustomTabsSessionToken token = (CustomTabsSessionToken) o; + return token.getCallbackBinder().equals(this.mCallbackBinder.asBinder()); + } + } + + public CustomTabsCallback getCallback() { + return this.mCallback; + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/ICustomTabsCallback.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/ICustomTabsCallback.java new file mode 100644 index 00000000..2d311a4d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/ICustomTabsCallback.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.customtabs; + +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.os.IInterface; +import android.os.Parcel; +import android.os.RemoteException; + +public interface ICustomTabsCallback extends IInterface { + void onNavigationEvent(int var1, Bundle var2) throws RemoteException; + + void extraCallback(String var1, Bundle var2) throws RemoteException; + + abstract class Stub extends Binder implements ICustomTabsCallback { + private static final String DESCRIPTOR = "android.support.customtabs.ICustomTabsCallback"; + static final int TRANSACTION_onNavigationEvent = 2; + static final int TRANSACTION_extraCallback = 3; + + public Stub() { + this.attachInterface(this, "android.support.customtabs.ICustomTabsCallback"); + } + + public static ICustomTabsCallback asInterface(IBinder obj) { + if (obj == null) { + return null; + } else { + IInterface iin = obj.queryLocalInterface("android.support.customtabs.ICustomTabsCallback"); + return (iin != null && iin instanceof ICustomTabsCallback ? (ICustomTabsCallback) iin : new ICustomTabsCallback.Stub.Proxy(obj)); + } + } + + public IBinder asBinder() { + return this; + } + + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { + Bundle _arg1; + switch (code) { + case 2: + data.enforceInterface("android.support.customtabs.ICustomTabsCallback"); + int _arg01 = data.readInt(); + if (0 != data.readInt()) { + _arg1 = Bundle.CREATOR.createFromParcel(data); + } else { + _arg1 = null; + } + + this.onNavigationEvent(_arg01, _arg1); + return true; + case 3: + data.enforceInterface("android.support.customtabs.ICustomTabsCallback"); + String _arg0 = data.readString(); + if (0 != data.readInt()) { + _arg1 = Bundle.CREATOR.createFromParcel(data); + } else { + _arg1 = null; + } + + this.extraCallback(_arg0, _arg1); + return true; + case 1598968902: + reply.writeString("android.support.customtabs.ICustomTabsCallback"); + return true; + default: + return super.onTransact(code, data, reply, flags); + } + } + + private static class Proxy implements ICustomTabsCallback { + private IBinder mRemote; + + Proxy(IBinder remote) { + this.mRemote = remote; + } + + public IBinder asBinder() { + return this.mRemote; + } + + public String getInterfaceDescriptor() { + return "android.support.customtabs.ICustomTabsCallback"; + } + + public void onNavigationEvent(int navigationEvent, Bundle extras) throws RemoteException { + Parcel _data = Parcel.obtain(); + + try { + _data.writeInterfaceToken("android.support.customtabs.ICustomTabsCallback"); + _data.writeInt(navigationEvent); + if (extras != null) { + _data.writeInt(1); + extras.writeToParcel(_data, 0); + } else { + _data.writeInt(0); + } + + this.mRemote.transact(2, _data, null, 1); + } finally { + _data.recycle(); + } + + } + + public void extraCallback(String callbackName, Bundle args) throws RemoteException { + Parcel _data = Parcel.obtain(); + + try { + _data.writeInterfaceToken("android.support.customtabs.ICustomTabsCallback"); + _data.writeString(callbackName); + if (args != null) { + _data.writeInt(1); + args.writeToParcel(_data, 0); + } else { + _data.writeInt(0); + } + + this.mRemote.transact(3, _data, null, 1); + } finally { + _data.recycle(); + } + + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/ICustomTabsService.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/ICustomTabsService.java new file mode 100644 index 00000000..fefde366 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabs/ICustomTabsService.java @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.customtabs; + +import android.net.Uri; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.os.IInterface; +import android.os.Parcel; +import android.os.RemoteException; + +import java.util.ArrayList; +import java.util.List; + +public interface ICustomTabsService extends IInterface { + boolean warmup(long var1) throws RemoteException; + + boolean newSession(ICustomTabsCallback var1) throws RemoteException; + + boolean mayLaunchUrl(ICustomTabsCallback var1, Uri var2, Bundle var3, List var4) throws RemoteException; + + Bundle extraCommand(String var1, Bundle var2) throws RemoteException; + + boolean updateVisuals(ICustomTabsCallback var1, Bundle var2) throws RemoteException; + + abstract class Stub extends Binder implements ICustomTabsService { + private static final String DESCRIPTOR = "android.support.customtabs.ICustomTabsService"; + static final int TRANSACTION_warmup = 2; + static final int TRANSACTION_newSession = 3; + static final int TRANSACTION_mayLaunchUrl = 4; + static final int TRANSACTION_extraCommand = 5; + static final int TRANSACTION_updateVisuals = 6; + + public Stub() { + this.attachInterface(this, "android.support.customtabs.ICustomTabsService"); + } + + public static ICustomTabsService asInterface(IBinder obj) { + if (obj == null) { + return null; + } else { + IInterface iin = obj.queryLocalInterface("android.support.customtabs.ICustomTabsService"); + return (iin != null && iin instanceof ICustomTabsService ? (ICustomTabsService) iin : new ICustomTabsService.Stub.Proxy(obj)); + } + } + + public IBinder asBinder() { + return this; + } + + public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { + ICustomTabsCallback _arg0; + Bundle _arg1; + boolean _result; + Bundle _result2; + switch (code) { + case 2: + data.enforceInterface("android.support.customtabs.ICustomTabsService"); + long _arg02 = data.readLong(); + _result = this.warmup(_arg02); + reply.writeNoException(); + reply.writeInt(_result ? 1 : 0); + return true; + case 3: + data.enforceInterface("android.support.customtabs.ICustomTabsService"); + _arg0 = ICustomTabsCallback.Stub.asInterface(data.readStrongBinder()); + boolean _arg12 = this.newSession(_arg0); + reply.writeNoException(); + reply.writeInt(_arg12 ? 1 : 0); + return true; + case 4: + data.enforceInterface("android.support.customtabs.ICustomTabsService"); + _arg0 = ICustomTabsCallback.Stub.asInterface(data.readStrongBinder()); + Uri _arg11; + if (0 != data.readInt()) { + _arg11 = Uri.CREATOR.createFromParcel(data); + } else { + _arg11 = null; + } + + if (0 != data.readInt()) { + _result2 = Bundle.CREATOR.createFromParcel(data); + } else { + _result2 = null; + } + + ArrayList _arg3 = data.createTypedArrayList(Bundle.CREATOR); + boolean _result1 = this.mayLaunchUrl(_arg0, _arg11, _result2, _arg3); + reply.writeNoException(); + reply.writeInt(_result1 ? 1 : 0); + return true; + case 5: + data.enforceInterface("android.support.customtabs.ICustomTabsService"); + String _arg01 = data.readString(); + if (0 != data.readInt()) { + _arg1 = Bundle.CREATOR.createFromParcel(data); + } else { + _arg1 = null; + } + + _result2 = this.extraCommand(_arg01, _arg1); + reply.writeNoException(); + if (_result2 != null) { + reply.writeInt(1); + _result2.writeToParcel(reply, 1); + } else { + reply.writeInt(0); + } + + return true; + case 6: + data.enforceInterface("android.support.customtabs.ICustomTabsService"); + _arg0 = ICustomTabsCallback.Stub.asInterface(data.readStrongBinder()); + if (0 != data.readInt()) { + _arg1 = Bundle.CREATOR.createFromParcel(data); + } else { + _arg1 = null; + } + + _result = this.updateVisuals(_arg0, _arg1); + reply.writeNoException(); + reply.writeInt(_result ? 1 : 0); + return true; + case 1598968902: + reply.writeString("android.support.customtabs.ICustomTabsService"); + return true; + default: + return super.onTransact(code, data, reply, flags); + } + } + + private static class Proxy implements ICustomTabsService { + private IBinder mRemote; + + Proxy(IBinder remote) { + this.mRemote = remote; + } + + public IBinder asBinder() { + return this.mRemote; + } + + public String getInterfaceDescriptor() { + return "android.support.customtabs.ICustomTabsService"; + } + + public boolean warmup(long flags) throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + + boolean _result; + try { + _data.writeInterfaceToken("android.support.customtabs.ICustomTabsService"); + _data.writeLong(flags); + this.mRemote.transact(2, _data, _reply, 0); + _reply.readException(); + _result = 0 != _reply.readInt(); + } finally { + _reply.recycle(); + _data.recycle(); + } + + return _result; + } + + public boolean newSession(ICustomTabsCallback callback) throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + + boolean _result; + try { + _data.writeInterfaceToken("android.support.customtabs.ICustomTabsService"); + _data.writeStrongBinder(callback != null ? callback.asBinder() : null); + this.mRemote.transact(3, _data, _reply, 0); + _reply.readException(); + _result = 0 != _reply.readInt(); + } finally { + _reply.recycle(); + _data.recycle(); + } + + return _result; + } + + public boolean mayLaunchUrl(ICustomTabsCallback callback, Uri url, Bundle extras, List otherLikelyBundles) throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + + boolean _result; + try { + _data.writeInterfaceToken("android.support.customtabs.ICustomTabsService"); + _data.writeStrongBinder(callback != null ? callback.asBinder() : null); + if (url != null) { + _data.writeInt(1); + url.writeToParcel(_data, 0); + } else { + _data.writeInt(0); + } + + if (extras != null) { + _data.writeInt(1); + extras.writeToParcel(_data, 0); + } else { + _data.writeInt(0); + } + + _data.writeTypedList(otherLikelyBundles); + this.mRemote.transact(4, _data, _reply, 0); + _reply.readException(); + _result = 0 != _reply.readInt(); + } finally { + _reply.recycle(); + _data.recycle(); + } + + return _result; + } + + public Bundle extraCommand(String commandName, Bundle args) throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + + Bundle _result; + try { + _data.writeInterfaceToken("android.support.customtabs.ICustomTabsService"); + _data.writeString(commandName); + if (args != null) { + _data.writeInt(1); + args.writeToParcel(_data, 0); + } else { + _data.writeInt(0); + } + + this.mRemote.transact(5, _data, _reply, 0); + _reply.readException(); + if (0 != _reply.readInt()) { + _result = Bundle.CREATOR.createFromParcel(_reply); + } else { + _result = null; + } + } finally { + _reply.recycle(); + _data.recycle(); + } + + return _result; + } + + public boolean updateVisuals(ICustomTabsCallback callback, Bundle bundle) throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + + boolean _result; + try { + _data.writeInterfaceToken("android.support.customtabs.ICustomTabsService"); + _data.writeStrongBinder(callback != null ? callback.asBinder() : null); + if (bundle != null) { + _data.writeInt(1); + bundle.writeToParcel(_data, 0); + } else { + _data.writeInt(0); + } + + this.mRemote.transact(6, _data, _reply, 0); + _reply.readException(); + _result = 0 != _reply.readInt(); + } finally { + _reply.recycle(); + _data.recycle(); + } + + return _result; + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/CustomTabsHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/CustomTabsHelper.java new file mode 100644 index 00000000..e40bcd4f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/CustomTabsHelper.java @@ -0,0 +1,142 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.telegram.messenger.support.customtabsclient.shared; + +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.net.Uri; +import android.text.TextUtils; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * Helper class for Custom Tabs. + */ +public class CustomTabsHelper { + private static final String TAG = "CustomTabsHelper"; + static final String STABLE_PACKAGE = "com.android.chrome"; + static final String BETA_PACKAGE = "com.chrome.beta"; + static final String DEV_PACKAGE = "com.chrome.dev"; + static final String LOCAL_PACKAGE = "com.google.android.apps.chrome"; + private static final String EXTRA_CUSTOM_TABS_KEEP_ALIVE = + "android.support.customtabs.extra.KEEP_ALIVE"; + private static final String ACTION_CUSTOM_TABS_CONNECTION = + "android.support.customtabs.action.CustomTabsService"; + + private static String sPackageNameToUse; + + private CustomTabsHelper() {} + + public static void addKeepAliveExtra(Context context, Intent intent) { + Intent keepAliveIntent = new Intent().setClassName( + context.getPackageName(), KeepAliveService.class.getCanonicalName()); + intent.putExtra(EXTRA_CUSTOM_TABS_KEEP_ALIVE, keepAliveIntent); + } + + /** + * Goes through all apps that handle VIEW intents and have a warmup service. Picks + * the one chosen by the user if there is one, otherwise makes a best effort to return a + * valid package name. + * + * This is not threadsafe. + * + * @param context {@link Context} to use for accessing {@link PackageManager}. + * @return The package name recommended to use for connecting to custom tabs related components. + */ + public static String getPackageNameToUse(Context context) { + if (sPackageNameToUse != null) return sPackageNameToUse; + + PackageManager pm = context.getPackageManager(); + // Get default VIEW intent handler. + Intent activityIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.example.com")); + ResolveInfo defaultViewHandlerInfo = pm.resolveActivity(activityIntent, 0); + String defaultViewHandlerPackageName = null; + if (defaultViewHandlerInfo != null) { + defaultViewHandlerPackageName = defaultViewHandlerInfo.activityInfo.packageName; + } + + // Get all apps that can handle VIEW intents. + List resolvedActivityList = pm.queryIntentActivities(activityIntent, 0); + List packagesSupportingCustomTabs = new ArrayList<>(); + for (ResolveInfo info : resolvedActivityList) { + Intent serviceIntent = new Intent(); + serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION); + serviceIntent.setPackage(info.activityInfo.packageName); + if (pm.resolveService(serviceIntent, 0) != null) { + packagesSupportingCustomTabs.add(info.activityInfo.packageName); + } + } + + // Now packagesSupportingCustomTabs contains all apps that can handle both VIEW intents + // and service calls. + if (packagesSupportingCustomTabs.isEmpty()) { + sPackageNameToUse = null; + } else if (packagesSupportingCustomTabs.size() == 1) { + sPackageNameToUse = packagesSupportingCustomTabs.get(0); + } else if (!TextUtils.isEmpty(defaultViewHandlerPackageName) + && !hasSpecializedHandlerIntents(context, activityIntent) + && packagesSupportingCustomTabs.contains(defaultViewHandlerPackageName)) { + sPackageNameToUse = defaultViewHandlerPackageName; + } else if (packagesSupportingCustomTabs.contains(STABLE_PACKAGE)) { + sPackageNameToUse = STABLE_PACKAGE; + } else if (packagesSupportingCustomTabs.contains(BETA_PACKAGE)) { + sPackageNameToUse = BETA_PACKAGE; + } else if (packagesSupportingCustomTabs.contains(DEV_PACKAGE)) { + sPackageNameToUse = DEV_PACKAGE; + } else if (packagesSupportingCustomTabs.contains(LOCAL_PACKAGE)) { + sPackageNameToUse = LOCAL_PACKAGE; + } + return sPackageNameToUse; + } + + /** + * Used to check whether there is a specialized handler for a given intent. + * @param intent The intent to check with. + * @return Whether there is a specialized handler for the given intent. + */ + private static boolean hasSpecializedHandlerIntents(Context context, Intent intent) { + try { + PackageManager pm = context.getPackageManager(); + List handlers = pm.queryIntentActivities( + intent, + PackageManager.GET_RESOLVED_FILTER); + if (handlers == null || handlers.size() == 0) { + return false; + } + for (ResolveInfo resolveInfo : handlers) { + IntentFilter filter = resolveInfo.filter; + if (filter == null) continue; + if (filter.countDataAuthorities() == 0 || filter.countDataPaths() == 0) continue; + if (resolveInfo.activityInfo == null) continue; + return true; + } + } catch (RuntimeException e) { + Log.e(TAG, "Runtime exception while getting specialized handlers"); + } + return false; + } + + /** + * @return All possible chrome package names that provide custom tabs feature. + */ + public static String[] getPackages() { + return new String[]{"", STABLE_PACKAGE, BETA_PACKAGE, DEV_PACKAGE, LOCAL_PACKAGE}; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/KeepAliveService.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/KeepAliveService.java new file mode 100644 index 00000000..0285190e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/KeepAliveService.java @@ -0,0 +1,29 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.telegram.messenger.support.customtabsclient.shared; + +import android.app.Service; +import android.content.Intent; +import android.os.Binder; +import android.os.IBinder; + +public class KeepAliveService extends Service { + private static final Binder sBinder = new Binder(); + + @Override + public IBinder onBind(Intent intent) { + return sBinder; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/ServiceConnection.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/ServiceConnection.java new file mode 100644 index 00000000..86f1b879 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/ServiceConnection.java @@ -0,0 +1,42 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.telegram.messenger.support.customtabsclient.shared; + +import android.content.ComponentName; + +import org.telegram.messenger.support.customtabs.CustomTabsClient; +import org.telegram.messenger.support.customtabs.CustomTabsServiceConnection; + +import java.lang.ref.WeakReference; + +public class ServiceConnection extends CustomTabsServiceConnection { + private WeakReference mConnectionCallback; + + public ServiceConnection(ServiceConnectionCallback connectionCallback) { + mConnectionCallback = new WeakReference<>(connectionCallback); + } + + @Override + public void onCustomTabsServiceConnected(ComponentName name, CustomTabsClient client) { + ServiceConnectionCallback connectionCallback = mConnectionCallback.get(); + if (connectionCallback != null) connectionCallback.onServiceConnected(client); + } + + @Override + public void onServiceDisconnected(ComponentName name) { + ServiceConnectionCallback connectionCallback = mConnectionCallback.get(); + if (connectionCallback != null) connectionCallback.onServiceDisconnected(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/ServiceConnectionCallback.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/ServiceConnectionCallback.java new file mode 100644 index 00000000..7f9ade6b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/customtabsclient/shared/ServiceConnectionCallback.java @@ -0,0 +1,33 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package org.telegram.messenger.support.customtabsclient.shared; + +import org.telegram.messenger.support.customtabs.CustomTabsClient; + +/** + * Callback for events when connecting and disconnecting from Custom Tabs Service. + */ +public interface ServiceConnectionCallback { + /** + * Called when the service is connected. + * @param client a CustomTabsClient + */ + void onServiceConnected(CustomTabsClient client); + + /** + * Called when the service is disconnected. + */ + void onServiceDisconnected(); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/util/AsyncListUtil.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/util/AsyncListUtil.java new file mode 100644 index 00000000..70e53dd4 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/util/AsyncListUtil.java @@ -0,0 +1,592 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.util; + +import android.support.annotation.UiThread; +import android.support.annotation.WorkerThread; +import android.util.Log; +import android.util.SparseBooleanArray; +import android.util.SparseIntArray; + +/** + * A utility class that supports asynchronous content loading. + *

+ * It can be used to load Cursor data in chunks without querying the Cursor on the UI Thread while + * keeping UI and cache synchronous for better user experience. + *

+ * It loads the data on a background thread and keeps only a limited number of fixed sized + * chunks in memory at all times. + *

+ * {@link AsyncListUtil} queries the currently visible range through {@link ViewCallback}, + * loads the required data items in the background through {@link DataCallback}, and notifies a + * {@link ViewCallback} when the data is loaded. It may load some extra items for smoother + * scrolling. + *

+ * Note that this class uses a single thread to load the data, so it suitable to load data from + * secondary storage such as disk, but not from network. + *

+ * This class is designed to work with {@link android.support.v7.widget.RecyclerView}, but it does + * not depend on it and can be used with other list views. + * + */ +public class AsyncListUtil { + private static final String TAG = "AsyncListUtil"; + + private static final boolean DEBUG = false; + + final Class mTClass; + final int mTileSize; + final DataCallback mDataCallback; + final ViewCallback mViewCallback; + + final TileList mTileList; + + final ThreadUtil.MainThreadCallback mMainThreadProxy; + final ThreadUtil.BackgroundCallback mBackgroundProxy; + + final int[] mTmpRange = new int[2]; + final int[] mPrevRange = new int[2]; + final int[] mTmpRangeExtended = new int[2]; + + private boolean mAllowScrollHints; + private int mScrollHint = ViewCallback.HINT_SCROLL_NONE; + + private int mItemCount = 0; + + int mDisplayedGeneration = 0; + int mRequestedGeneration = mDisplayedGeneration; + + final private SparseIntArray mMissingPositions = new SparseIntArray(); + + private void log(String s, Object... args) { + Log.d(TAG, "[MAIN] " + String.format(s, args)); + } + + /** + * Creates an AsyncListUtil. + * + * @param klass Class of the data item. + * @param tileSize Number of item per chunk loaded at once. + * @param dataCallback Data access callback. + * @param viewCallback Callback for querying visible item range and update notifications. + */ + public AsyncListUtil(Class klass, int tileSize, DataCallback dataCallback, + ViewCallback viewCallback) { + mTClass = klass; + mTileSize = tileSize; + mDataCallback = dataCallback; + mViewCallback = viewCallback; + + mTileList = new TileList(mTileSize); + + ThreadUtil threadUtil = new MessageThreadUtil(); + mMainThreadProxy = threadUtil.getMainThreadProxy(mMainThreadCallback); + mBackgroundProxy = threadUtil.getBackgroundProxy(mBackgroundCallback); + + refresh(); + } + + private boolean isRefreshPending() { + return mRequestedGeneration != mDisplayedGeneration; + } + + /** + * Updates the currently visible item range. + * + *

+ * Identifies the data items that have not been loaded yet and initiates loading them in the + * background. Should be called from the view's scroll listener (such as + * {@link android.support.v7.widget.RecyclerView.OnScrollListener#onScrolled}). + */ + public void onRangeChanged() { + if (isRefreshPending()) { + return; // Will update range will the refresh result arrives. + } + updateRange(); + mAllowScrollHints = true; + } + + /** + * Forces reloading the data. + *

+ * Discards all the cached data and reloads all required data items for the currently visible + * range. To be called when the data item count and/or contents has changed. + */ + public void refresh() { + mMissingPositions.clear(); + mBackgroundProxy.refresh(++mRequestedGeneration); + } + + /** + * Returns the data item at the given position or null if it has not been loaded + * yet. + * + *

+ * If this method has been called for a specific position and returned null, then + * {@link ViewCallback#onItemLoaded(int)} will be called when it finally loads. Note that if + * this position stays outside of the cached item range (as defined by + * {@link ViewCallback#extendRangeInto} method), then the callback will never be called for + * this position. + * + * @param position Item position. + * + * @return The data item at the given position or null if it has not been loaded + * yet. + */ + public T getItem(int position) { + if (position < 0 || position >= mItemCount) { + throw new IndexOutOfBoundsException(position + " is not within 0 and " + mItemCount); + } + T item = mTileList.getItemAt(position); + if (item == null && !isRefreshPending()) { + mMissingPositions.put(position, 0); + } + return item; + } + + /** + * Returns the number of items in the data set. + * + *

+ * This is the number returned by a recent call to + * {@link DataCallback#refreshData()}. + * + * @return Number of items. + */ + public int getItemCount() { + return mItemCount; + } + + private void updateRange() { + mViewCallback.getItemRangeInto(mTmpRange); + if (mTmpRange[0] > mTmpRange[1] || mTmpRange[0] < 0) { + return; + } + if (mTmpRange[1] >= mItemCount) { + // Invalid range may arrive soon after the refresh. + return; + } + + if (!mAllowScrollHints) { + mScrollHint = ViewCallback.HINT_SCROLL_NONE; + } else if (mTmpRange[0] > mPrevRange[1] || mPrevRange[0] > mTmpRange[1]) { + // Ranges do not intersect, long leap not a scroll. + mScrollHint = ViewCallback.HINT_SCROLL_NONE; + } else if (mTmpRange[0] < mPrevRange[0]) { + mScrollHint = ViewCallback.HINT_SCROLL_DESC; + } else if (mTmpRange[0] > mPrevRange[0]) { + mScrollHint = ViewCallback.HINT_SCROLL_ASC; + } + + mPrevRange[0] = mTmpRange[0]; + mPrevRange[1] = mTmpRange[1]; + + mViewCallback.extendRangeInto(mTmpRange, mTmpRangeExtended, mScrollHint); + mTmpRangeExtended[0] = Math.min(mTmpRange[0], Math.max(mTmpRangeExtended[0], 0)); + mTmpRangeExtended[1] = + Math.max(mTmpRange[1], Math.min(mTmpRangeExtended[1], mItemCount - 1)); + + mBackgroundProxy.updateRange(mTmpRange[0], mTmpRange[1], + mTmpRangeExtended[0], mTmpRangeExtended[1], mScrollHint); + } + + private final ThreadUtil.MainThreadCallback + mMainThreadCallback = new ThreadUtil.MainThreadCallback() { + @Override + public void updateItemCount(int generation, int itemCount) { + if (DEBUG) { + log("updateItemCount: size=%d, gen #%d", itemCount, generation); + } + if (!isRequestedGeneration(generation)) { + return; + } + mItemCount = itemCount; + mViewCallback.onDataRefresh(); + mDisplayedGeneration = mRequestedGeneration; + recycleAllTiles(); + + mAllowScrollHints = false; // Will be set to true after a first real scroll. + // There will be no scroll event if the size change does not affect the current range. + updateRange(); + } + + @Override + public void addTile(int generation, TileList.Tile tile) { + if (!isRequestedGeneration(generation)) { + if (DEBUG) { + log("recycling an older generation tile @%d", tile.mStartPosition); + } + mBackgroundProxy.recycleTile(tile); + return; + } + TileList.Tile duplicate = mTileList.addOrReplace(tile); + if (duplicate != null) { + Log.e(TAG, "duplicate tile @" + duplicate.mStartPosition); + mBackgroundProxy.recycleTile(duplicate); + } + if (DEBUG) { + log("gen #%d, added tile @%d, total tiles: %d", + generation, tile.mStartPosition, mTileList.size()); + } + int endPosition = tile.mStartPosition + tile.mItemCount; + int index = 0; + while (index < mMissingPositions.size()) { + final int position = mMissingPositions.keyAt(index); + if (tile.mStartPosition <= position && position < endPosition) { + mMissingPositions.removeAt(index); + mViewCallback.onItemLoaded(position); + } else { + index++; + } + } + } + + @Override + public void removeTile(int generation, int position) { + if (!isRequestedGeneration(generation)) { + return; + } + TileList.Tile tile = mTileList.removeAtPos(position); + if (tile == null) { + Log.e(TAG, "tile not found @" + position); + return; + } + if (DEBUG) { + log("recycling tile @%d, total tiles: %d", tile.mStartPosition, mTileList.size()); + } + mBackgroundProxy.recycleTile(tile); + } + + private void recycleAllTiles() { + if (DEBUG) { + log("recycling all %d tiles", mTileList.size()); + } + for (int i = 0; i < mTileList.size(); i++) { + mBackgroundProxy.recycleTile(mTileList.getAtIndex(i)); + } + mTileList.clear(); + } + + private boolean isRequestedGeneration(int generation) { + return generation == mRequestedGeneration; + } + }; + + private final ThreadUtil.BackgroundCallback + mBackgroundCallback = new ThreadUtil.BackgroundCallback() { + + private TileList.Tile mRecycledRoot; + + final SparseBooleanArray mLoadedTiles = new SparseBooleanArray(); + + private int mGeneration; + private int mItemCount; + + private int mFirstRequiredTileStart; + private int mLastRequiredTileStart; + + @Override + public void refresh(int generation) { + mGeneration = generation; + mLoadedTiles.clear(); + mItemCount = mDataCallback.refreshData(); + mMainThreadProxy.updateItemCount(mGeneration, mItemCount); + } + + @Override + public void updateRange(int rangeStart, int rangeEnd, int extRangeStart, int extRangeEnd, + int scrollHint) { + if (DEBUG) { + log("updateRange: %d..%d extended to %d..%d, scroll hint: %d", + rangeStart, rangeEnd, extRangeStart, extRangeEnd, scrollHint); + } + + if (rangeStart > rangeEnd) { + return; + } + + final int firstVisibleTileStart = getTileStart(rangeStart); + final int lastVisibleTileStart = getTileStart(rangeEnd); + + mFirstRequiredTileStart = getTileStart(extRangeStart); + mLastRequiredTileStart = getTileStart(extRangeEnd); + if (DEBUG) { + log("requesting tile range: %d..%d", + mFirstRequiredTileStart, mLastRequiredTileStart); + } + + // All pending tile requests are removed by ThreadUtil at this point. + // Re-request all required tiles in the most optimal order. + if (scrollHint == ViewCallback.HINT_SCROLL_DESC) { + requestTiles(mFirstRequiredTileStart, lastVisibleTileStart, scrollHint, true); + requestTiles(lastVisibleTileStart + mTileSize, mLastRequiredTileStart, scrollHint, + false); + } else { + requestTiles(firstVisibleTileStart, mLastRequiredTileStart, scrollHint, false); + requestTiles(mFirstRequiredTileStart, firstVisibleTileStart - mTileSize, scrollHint, + true); + } + } + + private int getTileStart(int position) { + return position - position % mTileSize; + } + + private void requestTiles(int firstTileStart, int lastTileStart, int scrollHint, + boolean backwards) { + for (int i = firstTileStart; i <= lastTileStart; i += mTileSize) { + int tileStart = backwards ? (lastTileStart + firstTileStart - i) : i; + if (DEBUG) { + log("requesting tile @%d", tileStart); + } + mBackgroundProxy.loadTile(tileStart, scrollHint); + } + } + + @Override + public void loadTile(int position, int scrollHint) { + if (isTileLoaded(position)) { + if (DEBUG) { + log("already loaded tile @%d", position); + } + return; + } + TileList.Tile tile = acquireTile(); + tile.mStartPosition = position; + tile.mItemCount = Math.min(mTileSize, mItemCount - tile.mStartPosition); + mDataCallback.fillData(tile.mItems, tile.mStartPosition, tile.mItemCount); + flushTileCache(scrollHint); + addTile(tile); + } + + @Override + public void recycleTile(TileList.Tile tile) { + if (DEBUG) { + log("recycling tile @%d", tile.mStartPosition); + } + mDataCallback.recycleData(tile.mItems, tile.mItemCount); + + tile.mNext = mRecycledRoot; + mRecycledRoot = tile; + } + + private TileList.Tile acquireTile() { + if (mRecycledRoot != null) { + TileList.Tile result = mRecycledRoot; + mRecycledRoot = mRecycledRoot.mNext; + return result; + } + return new TileList.Tile(mTClass, mTileSize); + } + + private boolean isTileLoaded(int position) { + return mLoadedTiles.get(position); + } + + private void addTile(TileList.Tile tile) { + mLoadedTiles.put(tile.mStartPosition, true); + mMainThreadProxy.addTile(mGeneration, tile); + if (DEBUG) { + log("loaded tile @%d, total tiles: %d", tile.mStartPosition, mLoadedTiles.size()); + } + } + + private void removeTile(int position) { + mLoadedTiles.delete(position); + mMainThreadProxy.removeTile(mGeneration, position); + if (DEBUG) { + log("flushed tile @%d, total tiles: %s", position, mLoadedTiles.size()); + } + } + + private void flushTileCache(int scrollHint) { + final int cacheSizeLimit = mDataCallback.getMaxCachedTiles(); + while (mLoadedTiles.size() >= cacheSizeLimit) { + int firstLoadedTileStart = mLoadedTiles.keyAt(0); + int lastLoadedTileStart = mLoadedTiles.keyAt(mLoadedTiles.size() - 1); + int startMargin = mFirstRequiredTileStart - firstLoadedTileStart; + int endMargin = lastLoadedTileStart - mLastRequiredTileStart; + if (startMargin > 0 && (startMargin >= endMargin || + (scrollHint == ViewCallback.HINT_SCROLL_ASC))) { + removeTile(firstLoadedTileStart); + } else if (endMargin > 0 && (startMargin < endMargin || + (scrollHint == ViewCallback.HINT_SCROLL_DESC))){ + removeTile(lastLoadedTileStart); + } else { + // Could not flush on either side, bail out. + return; + } + } + } + + private void log(String s, Object... args) { + Log.d(TAG, "[BKGR] " + String.format(s, args)); + } + }; + + /** + * The callback that provides data access for {@link AsyncListUtil}. + * + *

+ * All methods are called on the background thread. + */ + public static abstract class DataCallback { + + /** + * Refresh the data set and return the new data item count. + * + *

+ * If the data is being accessed through {@link android.database.Cursor} this is where + * the new cursor should be created. + * + * @return Data item count. + */ + @WorkerThread + public abstract int refreshData(); + + /** + * Fill the given tile. + * + *

+ * The provided tile might be a recycled tile, in which case it will already have objects. + * It is suggested to re-use these objects if possible in your use case. + * + * @param startPosition The start position in the list. + * @param itemCount The data item count. + * @param data The data item array to fill into. Should not be accessed beyond + * itemCount. + */ + @WorkerThread + public abstract void fillData(T[] data, int startPosition, int itemCount); + + /** + * Recycle the objects created in {@link #fillData} if necessary. + * + * + * @param data Array of data items. Should not be accessed beyond itemCount. + * @param itemCount The data item count. + */ + @WorkerThread + public void recycleData(T[] data, int itemCount) { + } + + /** + * Returns tile cache size limit (in tiles). + * + *

+ * The actual number of cached tiles will be the maximum of this value and the number of + * tiles that is required to cover the range returned by + * {@link ViewCallback#extendRangeInto(int[], int[], int)}. + *

+ * For example, if this method returns 10, and the most + * recent call to {@link ViewCallback#extendRangeInto(int[], int[], int)} returned + * {100, 179}, and the tile size is 5, then the maximum number of cached tiles will be 16. + *

+ * However, if the tile size is 20, then the maximum number of cached tiles will be 10. + *

+ * The default implementation returns 10. + * + * @return Maximum cache size. + */ + @WorkerThread + public int getMaxCachedTiles() { + return 10; + } + } + + /** + * The callback that links {@link AsyncListUtil} with the list view. + * + *

+ * All methods are called on the main thread. + */ + public static abstract class ViewCallback { + + /** + * No scroll direction hint available. + */ + public static final int HINT_SCROLL_NONE = 0; + + /** + * Scrolling in descending order (from higher to lower positions in the order of the backing + * storage). + */ + public static final int HINT_SCROLL_DESC = 1; + + /** + * Scrolling in ascending order (from lower to higher positions in the order of the backing + * storage). + */ + public static final int HINT_SCROLL_ASC = 2; + + /** + * Compute the range of visible item positions. + *

+ * outRange[0] is the position of the first visible item (in the order of the backing + * storage). + *

+ * outRange[1] is the position of the last visible item (in the order of the backing + * storage). + *

+ * Negative positions and positions greater or equal to {@link #getItemCount} are invalid. + * If the returned range contains invalid positions it is ignored (no item will be loaded). + * + * @param outRange The visible item range. + */ + @UiThread + public abstract void getItemRangeInto(int[] outRange); + + /** + * Compute a wider range of items that will be loaded for smoother scrolling. + * + *

+ * If there is no scroll hint, the default implementation extends the visible range by half + * its length in both directions. If there is a scroll hint, the range is extended by + * its full length in the scroll direction, and by half in the other direction. + *

+ * For example, if range is {100, 200} and scrollHint + * is {@link #HINT_SCROLL_ASC}, then outRange will be {50, 300}. + *

+ * However, if scrollHint is {@link #HINT_SCROLL_NONE}, then + * outRange will be {50, 250} + * + * @param range Visible item range. + * @param outRange Extended range. + * @param scrollHint The scroll direction hint. + */ + @UiThread + public void extendRangeInto(int[] range, int[] outRange, int scrollHint) { + final int fullRange = range[1] - range[0] + 1; + final int halfRange = fullRange / 2; + outRange[0] = range[0] - (scrollHint == HINT_SCROLL_DESC ? fullRange : halfRange); + outRange[1] = range[1] + (scrollHint == HINT_SCROLL_ASC ? fullRange : halfRange); + } + + /** + * Called when the entire data set has changed. + */ + @UiThread + public abstract void onDataRefresh(); + + /** + * Called when an item at the given position is loaded. + * @param position Item position. + */ + @UiThread + public abstract void onItemLoaded(int position); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/util/MessageThreadUtil.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/util/MessageThreadUtil.java new file mode 100644 index 00000000..bf78e6aa --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/util/MessageThreadUtil.java @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.util; + +import android.os.Handler; +import android.os.Looper; +import android.support.v4.content.ParallelExecutorCompat; +import android.util.Log; + +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; + +class MessageThreadUtil implements ThreadUtil { + + public MainThreadCallback getMainThreadProxy(final MainThreadCallback callback) { + return new MainThreadCallback() { + final private MessageQueue mQueue = new MessageQueue(); + final private Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); + + private static final int UPDATE_ITEM_COUNT = 1; + private static final int ADD_TILE = 2; + private static final int REMOVE_TILE = 3; + + @Override + public void updateItemCount(int generation, int itemCount) { + sendMessage(SyncQueueItem.obtainMessage(UPDATE_ITEM_COUNT, generation, itemCount)); + } + + @Override + public void addTile(int generation, TileList.Tile tile) { + sendMessage(SyncQueueItem.obtainMessage(ADD_TILE, generation, tile)); + } + + @Override + public void removeTile(int generation, int position) { + sendMessage(SyncQueueItem.obtainMessage(REMOVE_TILE, generation, position)); + } + + private void sendMessage(SyncQueueItem msg) { + mQueue.sendMessage(msg); + mMainThreadHandler.post(mMainThreadRunnable); + } + + private Runnable mMainThreadRunnable = new Runnable() { + @Override + public void run() { + SyncQueueItem msg = mQueue.next(); + while (msg != null) { + switch (msg.what) { + case UPDATE_ITEM_COUNT: + callback.updateItemCount(msg.arg1, msg.arg2); + break; + case ADD_TILE: + //noinspection unchecked + callback.addTile(msg.arg1, (TileList.Tile) msg.data); + break; + case REMOVE_TILE: + callback.removeTile(msg.arg1, msg.arg2); + break; + default: + Log.e("ThreadUtil", "Unsupported message, what=" + msg.what); + } + msg = mQueue.next(); + } + } + }; + }; + } + + public BackgroundCallback getBackgroundProxy(final BackgroundCallback callback) { + return new BackgroundCallback() { + final private MessageQueue mQueue = new MessageQueue(); + final private Executor mExecutor = ParallelExecutorCompat.getParallelExecutor(); + AtomicBoolean mBackgroundRunning = new AtomicBoolean(false); + + private static final int REFRESH = 1; + private static final int UPDATE_RANGE = 2; + private static final int LOAD_TILE = 3; + private static final int RECYCLE_TILE = 4; + + @Override + public void refresh(int generation) { + sendMessageAtFrontOfQueue(SyncQueueItem.obtainMessage(REFRESH, generation, null)); + } + + @Override + public void updateRange(int rangeStart, int rangeEnd, + int extRangeStart, int extRangeEnd, int scrollHint) { + sendMessageAtFrontOfQueue(SyncQueueItem.obtainMessage(UPDATE_RANGE, + rangeStart, rangeEnd, extRangeStart, extRangeEnd, scrollHint, null)); + } + + @Override + public void loadTile(int position, int scrollHint) { + sendMessage(SyncQueueItem.obtainMessage(LOAD_TILE, position, scrollHint)); + } + + @Override + public void recycleTile(TileList.Tile tile) { + sendMessage(SyncQueueItem.obtainMessage(RECYCLE_TILE, 0, tile)); + } + + private void sendMessage(SyncQueueItem msg) { + mQueue.sendMessage(msg); + maybeExecuteBackgroundRunnable(); + } + + private void sendMessageAtFrontOfQueue(SyncQueueItem msg) { + mQueue.sendMessageAtFrontOfQueue(msg); + maybeExecuteBackgroundRunnable(); + } + + private void maybeExecuteBackgroundRunnable() { + if (mBackgroundRunning.compareAndSet(false, true)) { + mExecutor.execute(mBackgroundRunnable); + } + } + + private Runnable mBackgroundRunnable = new Runnable() { + @Override + public void run() { + while (true) { + SyncQueueItem msg = mQueue.next(); + if (msg == null) { + break; + } + switch (msg.what) { + case REFRESH: + mQueue.removeMessages(REFRESH); + callback.refresh(msg.arg1); + break; + case UPDATE_RANGE: + mQueue.removeMessages(UPDATE_RANGE); + mQueue.removeMessages(LOAD_TILE); + callback.updateRange( + msg.arg1, msg.arg2, msg.arg3, msg.arg4, msg.arg5); + break; + case LOAD_TILE: + callback.loadTile(msg.arg1, msg.arg2); + break; + case RECYCLE_TILE: + //noinspection unchecked + callback.recycleTile((TileList.Tile) msg.data); + break; + default: + Log.e("ThreadUtil", "Unsupported message, what=" + msg.what); + } + } + mBackgroundRunning.set(false); + } + }; + }; + } + + /** + * Replica of android.os.Message. Unfortunately, cannot use it without a Handler and don't want + * to create a thread just for this component. + */ + static class SyncQueueItem { + + private static SyncQueueItem sPool; + private static final Object sPoolLock = new Object(); + private SyncQueueItem next; + public int what; + public int arg1; + public int arg2; + public int arg3; + public int arg4; + public int arg5; + public Object data; + + void recycle() { + next = null; + what = arg1 = arg2 = arg3 = arg4 = arg5 = 0; + data = null; + synchronized (sPoolLock) { + if (sPool != null) { + next = sPool; + } + sPool = this; + } + } + + static SyncQueueItem obtainMessage(int what, int arg1, int arg2, int arg3, int arg4, + int arg5, Object data) { + synchronized (sPoolLock) { + final SyncQueueItem item; + if (sPool == null) { + item = new SyncQueueItem(); + } else { + item = sPool; + sPool = sPool.next; + item.next = null; + } + item.what = what; + item.arg1 = arg1; + item.arg2 = arg2; + item.arg3 = arg3; + item.arg4 = arg4; + item.arg5 = arg5; + item.data = data; + return item; + } + } + + static SyncQueueItem obtainMessage(int what, int arg1, int arg2) { + return obtainMessage(what, arg1, arg2, 0, 0, 0, null); + } + + static SyncQueueItem obtainMessage(int what, int arg1, Object data) { + return obtainMessage(what, arg1, 0, 0, 0, 0, data); + } + } + + static class MessageQueue { + + private SyncQueueItem mRoot; + + synchronized SyncQueueItem next() { + if (mRoot == null) { + return null; + } + final SyncQueueItem next = mRoot; + mRoot = mRoot.next; + return next; + } + + synchronized void sendMessageAtFrontOfQueue(SyncQueueItem item) { + item.next = mRoot; + mRoot = item; + } + + synchronized void sendMessage(SyncQueueItem item) { + if (mRoot == null) { + mRoot = item; + return; + } + SyncQueueItem last = mRoot; + while (last.next != null) { + last = last.next; + } + last.next = item; + } + + synchronized void removeMessages(int what) { + while (mRoot != null && mRoot.what == what) { + SyncQueueItem item = mRoot; + mRoot = mRoot.next; + item.recycle(); + } + if (mRoot != null) { + SyncQueueItem prev = mRoot; + SyncQueueItem item = prev.next; + while (item != null) { + SyncQueueItem next = item.next; + if (item.what == what) { + prev.next = next; + item.recycle(); + } else { + prev = item; + } + item = next; + } + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/util/SortedList.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/util/SortedList.java new file mode 100644 index 00000000..82c555d0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/util/SortedList.java @@ -0,0 +1,891 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.util; + +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; + +/** + * A Sorted list implementation that can keep items in order and also notify for changes in the + * list + * such that it can be bound to a {@link android.support.v7.widget.RecyclerView.Adapter + * RecyclerView.Adapter}. + *

+ * It keeps items ordered using the {@link Callback#compare(Object, Object)} method and uses + * binary search to retrieve items. If the sorting criteria of your items may change, make sure you + * call appropriate methods while editing them to avoid data inconsistencies. + *

+ * You can control the order of items and change notifications via the {@link Callback} parameter. + */ +@SuppressWarnings("unchecked") +public class SortedList { + + /** + * Used by {@link #indexOf(Object)} when he item cannot be found in the list. + */ + public static final int INVALID_POSITION = -1; + + private static final int MIN_CAPACITY = 10; + private static final int CAPACITY_GROWTH = MIN_CAPACITY; + private static final int INSERTION = 1; + private static final int DELETION = 1 << 1; + private static final int LOOKUP = 1 << 2; + T[] mData; + + /** + * A copy of the previous list contents used during the merge phase of addAll. + */ + private T[] mOldData; + private int mOldDataStart; + private int mOldDataSize; + + /** + * The size of the valid portion of mData during the merge phase of addAll. + */ + private int mMergedSize; + + + /** + * The callback instance that controls the behavior of the SortedList and get notified when + * changes happen. + */ + private Callback mCallback; + + private BatchedCallback mBatchedCallback; + + private int mSize; + private final Class mTClass; + + /** + * Creates a new SortedList of type T. + * + * @param klass The class of the contents of the SortedList. + * @param callback The callback that controls the behavior of SortedList. + */ + public SortedList(Class klass, Callback callback) { + this(klass, callback, MIN_CAPACITY); + } + + /** + * Creates a new SortedList of type T. + * + * @param klass The class of the contents of the SortedList. + * @param callback The callback that controls the behavior of SortedList. + * @param initialCapacity The initial capacity to hold items. + */ + public SortedList(Class klass, Callback callback, int initialCapacity) { + mTClass = klass; + mData = (T[]) Array.newInstance(klass, initialCapacity); + mCallback = callback; + mSize = 0; + } + + /** + * The number of items in the list. + * + * @return The number of items in the list. + */ + public int size() { + return mSize; + } + + /** + * Adds the given item to the list. If this is a new item, SortedList calls + * {@link Callback#onInserted(int, int)}. + *

+ * If the item already exists in the list and its sorting criteria is not changed, it is + * replaced with the existing Item. SortedList uses + * {@link Callback#areItemsTheSame(Object, Object)} to check if two items are the same item + * and uses {@link Callback#areContentsTheSame(Object, Object)} to decide whether it should + * call {@link Callback#onChanged(int, int)} or not. In both cases, it always removes the + * reference to the old item and puts the new item into the backing array even if + * {@link Callback#areContentsTheSame(Object, Object)} returns false. + *

+ * If the sorting criteria of the item is changed, SortedList won't be able to find + * its duplicate in the list which will result in having a duplicate of the Item in the list. + * If you need to update sorting criteria of an item that already exists in the list, + * use {@link #updateItemAt(int, Object)}. You can find the index of the item using + * {@link #indexOf(Object)} before you update the object. + * + * @param item The item to be added into the list. + * + * @return The index of the newly added item. + * @see {@link Callback#compare(Object, Object)} + * @see {@link Callback#areItemsTheSame(Object, Object)} + * @see {@link Callback#areContentsTheSame(Object, Object)}} + */ + public int add(T item) { + throwIfMerging(); + return add(item, true); + } + + /** + * Adds the given items to the list. Equivalent to calling {@link SortedList#add} in a loop, + * except the callback events may be in a different order/granularity since addAll can batch + * them for better performance. + *

+ * If allowed, may modify the input array and even take the ownership over it in order + * to avoid extra memory allocation during sorting and deduplication. + *

+ * @param items Array of items to be added into the list. + * @param mayModifyInput If true, SortedList is allowed to modify the input. + * @see {@link SortedList#addAll(T[] items)}. + */ + public void addAll(T[] items, boolean mayModifyInput) { + throwIfMerging(); + if (items.length == 0) { + return; + } + if (mayModifyInput) { + addAllInternal(items); + } else { + T[] copy = (T[]) Array.newInstance(mTClass, items.length); + System.arraycopy(items, 0, copy, 0, items.length); + addAllInternal(copy); + } + + } + + /** + * Adds the given items to the list. Does not modify the input. + * + * @see {@link SortedList#addAll(T[] items, boolean mayModifyInput)} + * + * @param items Array of items to be added into the list. + */ + public void addAll(T... items) { + addAll(items, false); + } + + /** + * Adds the given items to the list. Does not modify the input. + * + * @see {@link SortedList#addAll(T[] items, boolean mayModifyInput)} + * + * @param items Collection of items to be added into the list. + */ + public void addAll(Collection items) { + T[] copy = (T[]) Array.newInstance(mTClass, items.size()); + addAll(items.toArray(copy), true); + } + + private void addAllInternal(T[] newItems) { + final boolean forceBatchedUpdates = !(mCallback instanceof BatchedCallback); + if (forceBatchedUpdates) { + beginBatchedUpdates(); + } + + mOldData = mData; + mOldDataStart = 0; + mOldDataSize = mSize; + + Arrays.sort(newItems, mCallback); // Arrays.sort is stable. + + final int newSize = deduplicate(newItems); + if (mSize == 0) { + mData = newItems; + mSize = newSize; + mMergedSize = newSize; + mCallback.onInserted(0, newSize); + } else { + merge(newItems, newSize); + } + + mOldData = null; + + if (forceBatchedUpdates) { + endBatchedUpdates(); + } + } + + /** + * Remove duplicate items, leaving only the last item from each group of "same" items. + * Move the remaining items to the beginning of the array. + * + * @return Number of deduplicated items at the beginning of the array. + */ + private int deduplicate(T[] items) { + if (items.length == 0) { + throw new IllegalArgumentException("Input array must be non-empty"); + } + + // Keep track of the range of equal items at the end of the output. + // Start with the range containing just the first item. + int rangeStart = 0; + int rangeEnd = 1; + + for (int i = 1; i < items.length; ++i) { + T currentItem = items[i]; + + int compare = mCallback.compare(items[rangeStart], currentItem); + if (compare > 0) { + throw new IllegalArgumentException("Input must be sorted in ascending order."); + } + + if (compare == 0) { + // The range of equal items continues, update it. + final int sameItemPos = findSameItem(currentItem, items, rangeStart, rangeEnd); + if (sameItemPos != INVALID_POSITION) { + // Replace the duplicate item. + items[sameItemPos] = currentItem; + } else { + // Expand the range. + if (rangeEnd != i) { // Avoid redundant copy. + items[rangeEnd] = currentItem; + } + rangeEnd++; + } + } else { + // The range has ended. Reset it to contain just the current item. + if (rangeEnd != i) { // Avoid redundant copy. + items[rangeEnd] = currentItem; + } + rangeStart = rangeEnd++; + } + } + return rangeEnd; + } + + + private int findSameItem(T item, T[] items, int from, int to) { + for (int pos = from; pos < to; pos++) { + if (mCallback.areItemsTheSame(items[pos], item)) { + return pos; + } + } + return INVALID_POSITION; + } + + /** + * This method assumes that newItems are sorted and deduplicated. + */ + private void merge(T[] newData, int newDataSize) { + final int mergedCapacity = mSize + newDataSize + CAPACITY_GROWTH; + mData = (T[]) Array.newInstance(mTClass, mergedCapacity); + mMergedSize = 0; + + int newDataStart = 0; + while (mOldDataStart < mOldDataSize || newDataStart < newDataSize) { + if (mOldDataStart == mOldDataSize) { + // No more old items, copy the remaining new items. + int itemCount = newDataSize - newDataStart; + System.arraycopy(newData, newDataStart, mData, mMergedSize, itemCount); + mMergedSize += itemCount; + mSize += itemCount; + mCallback.onInserted(mMergedSize - itemCount, itemCount); + break; + } + + if (newDataStart == newDataSize) { + // No more new items, copy the remaining old items. + int itemCount = mOldDataSize - mOldDataStart; + System.arraycopy(mOldData, mOldDataStart, mData, mMergedSize, itemCount); + mMergedSize += itemCount; + break; + } + + T oldItem = mOldData[mOldDataStart]; + T newItem = newData[newDataStart]; + int compare = mCallback.compare(oldItem, newItem); + if (compare > 0) { + // New item is lower, output it. + mData[mMergedSize++] = newItem; + mSize++; + newDataStart++; + mCallback.onInserted(mMergedSize - 1, 1); + } else if (compare == 0 && mCallback.areItemsTheSame(oldItem, newItem)) { + // Items are the same. Output the new item, but consume both. + mData[mMergedSize++] = newItem; + newDataStart++; + mOldDataStart++; + if (!mCallback.areContentsTheSame(oldItem, newItem)) { + mCallback.onChanged(mMergedSize - 1, 1); + } + } else { + // Old item is lower than or equal to (but not the same as the new). Output it. + // New item with the same sort order will be inserted later. + mData[mMergedSize++] = oldItem; + mOldDataStart++; + } + } + } + + private void throwIfMerging() { + if (mOldData != null) { + throw new IllegalStateException("Cannot call this method from within addAll"); + } + } + + /** + * Batches adapter updates that happen between calling this method until calling + * {@link #endBatchedUpdates()}. For example, if you add multiple items in a loop + * and they are placed into consecutive indices, SortedList calls + * {@link Callback#onInserted(int, int)} only once with the proper item count. If an event + * cannot be merged with the previous event, the previous event is dispatched + * to the callback instantly. + *

+ * After running your data updates, you must call {@link #endBatchedUpdates()} + * which will dispatch any deferred data change event to the current callback. + *

+ * A sample implementation may look like this: + *

+     *     mSortedList.beginBatchedUpdates();
+     *     try {
+     *         mSortedList.add(item1)
+     *         mSortedList.add(item2)
+     *         mSortedList.remove(item3)
+     *         ...
+     *     } finally {
+     *         mSortedList.endBatchedUpdates();
+     *     }
+     * 
+ *

+ * Instead of using this method to batch calls, you can use a Callback that extends + * {@link BatchedCallback}. In that case, you must make sure that you are manually calling + * {@link BatchedCallback#dispatchLastEvent()} right after you complete your data changes. + * Failing to do so may create data inconsistencies with the Callback. + *

+ * If the current Callback in an instance of {@link BatchedCallback}, calling this method + * has no effect. + */ + public void beginBatchedUpdates() { + throwIfMerging(); + if (mCallback instanceof BatchedCallback) { + return; + } + if (mBatchedCallback == null) { + mBatchedCallback = new BatchedCallback(mCallback); + } + mCallback = mBatchedCallback; + } + + /** + * Ends the update transaction and dispatches any remaining event to the callback. + */ + public void endBatchedUpdates() { + throwIfMerging(); + if (mCallback instanceof BatchedCallback) { + ((BatchedCallback) mCallback).dispatchLastEvent(); + } + if (mCallback == mBatchedCallback) { + mCallback = mBatchedCallback.mWrappedCallback; + } + } + + private int add(T item, boolean notify) { + int index = findIndexOf(item, mData, 0, mSize, INSERTION); + if (index == INVALID_POSITION) { + index = 0; + } else if (index < mSize) { + T existing = mData[index]; + if (mCallback.areItemsTheSame(existing, item)) { + if (mCallback.areContentsTheSame(existing, item)) { + //no change but still replace the item + mData[index] = item; + return index; + } else { + mData[index] = item; + mCallback.onChanged(index, 1); + return index; + } + } + } + addToData(index, item); + if (notify) { + mCallback.onInserted(index, 1); + } + return index; + } + + /** + * Removes the provided item from the list and calls {@link Callback#onRemoved(int, int)}. + * + * @param item The item to be removed from the list. + * + * @return True if item is removed, false if item cannot be found in the list. + */ + public boolean remove(T item) { + throwIfMerging(); + return remove(item, true); + } + + /** + * Removes the item at the given index and calls {@link Callback#onRemoved(int, int)}. + * + * @param index The index of the item to be removed. + * + * @return The removed item. + */ + public T removeItemAt(int index) { + throwIfMerging(); + T item = get(index); + removeItemAtIndex(index, true); + return item; + } + + private boolean remove(T item, boolean notify) { + int index = findIndexOf(item, mData, 0, mSize, DELETION); + if (index == INVALID_POSITION) { + return false; + } + removeItemAtIndex(index, notify); + return true; + } + + private void removeItemAtIndex(int index, boolean notify) { + System.arraycopy(mData, index + 1, mData, index, mSize - index - 1); + mSize--; + mData[mSize] = null; + if (notify) { + mCallback.onRemoved(index, 1); + } + } + + /** + * Updates the item at the given index and calls {@link Callback#onChanged(int, int)} and/or + * {@link Callback#onMoved(int, int)} if necessary. + *

+ * You can use this method if you need to change an existing Item such that its position in the + * list may change. + *

+ * If the new object is a different object (get(index) != item) and + * {@link Callback#areContentsTheSame(Object, Object)} returns true, SortedList + * avoids calling {@link Callback#onChanged(int, int)} otherwise it calls + * {@link Callback#onChanged(int, int)}. + *

+ * If the new position of the item is different than the provided index, + * SortedList + * calls {@link Callback#onMoved(int, int)}. + * + * @param index The index of the item to replace + * @param item The item to replace the item at the given Index. + * @see #add(Object) + */ + public void updateItemAt(int index, T item) { + throwIfMerging(); + final T existing = get(index); + // assume changed if the same object is given back + boolean contentsChanged = existing == item || !mCallback.areContentsTheSame(existing, item); + if (existing != item) { + // different items, we can use comparison and may avoid lookup + final int cmp = mCallback.compare(existing, item); + if (cmp == 0) { + mData[index] = item; + if (contentsChanged) { + mCallback.onChanged(index, 1); + } + return; + } + } + if (contentsChanged) { + mCallback.onChanged(index, 1); + } + // TODO this done in 1 pass to avoid shifting twice. + removeItemAtIndex(index, false); + int newIndex = add(item, false); + if (index != newIndex) { + mCallback.onMoved(index, newIndex); + } + } + + /** + * This method can be used to recalculate the position of the item at the given index, without + * triggering an {@link Callback#onChanged(int, int)} callback. + *

+ * If you are editing objects in the list such that their position in the list may change but + * you don't want to trigger an onChange animation, you can use this method to re-position it. + * If the item changes position, SortedList will call {@link Callback#onMoved(int, int)} + * without + * calling {@link Callback#onChanged(int, int)}. + *

+ * A sample usage may look like: + * + *

+     *     final int position = mSortedList.indexOf(item);
+     *     item.incrementPriority(); // assume items are sorted by priority
+     *     mSortedList.recalculatePositionOfItemAt(position);
+     * 
+ * In the example above, because the sorting criteria of the item has been changed, + * mSortedList.indexOf(item) will not be able to find the item. This is why the code above + * first + * gets the position before editing the item, edits it and informs the SortedList that item + * should be repositioned. + * + * @param index The current index of the Item whose position should be re-calculated. + * @see #updateItemAt(int, Object) + * @see #add(Object) + */ + public void recalculatePositionOfItemAt(int index) { + throwIfMerging(); + // TODO can be improved + final T item = get(index); + removeItemAtIndex(index, false); + int newIndex = add(item, false); + if (index != newIndex) { + mCallback.onMoved(index, newIndex); + } + } + + /** + * Returns the item at the given index. + * + * @param index The index of the item to retrieve. + * + * @return The item at the given index. + * @throws java.lang.IndexOutOfBoundsException if provided index is negative or larger than the + * size of the list. + */ + public T get(int index) throws IndexOutOfBoundsException { + if (index >= mSize || index < 0) { + throw new IndexOutOfBoundsException("Asked to get item at " + index + " but size is " + + mSize); + } + if (mOldData != null) { + // The call is made from a callback during addAll execution. The data is split + // between mData and mOldData. + if (index >= mMergedSize) { + return mOldData[index - mMergedSize + mOldDataStart]; + } + } + return mData[index]; + } + + /** + * Returns the position of the provided item. + * + * @param item The item to query for position. + * + * @return The position of the provided item or {@link #INVALID_POSITION} if item is not in the + * list. + */ + public int indexOf(T item) { + if (mOldData != null) { + int index = findIndexOf(item, mData, 0, mMergedSize, LOOKUP); + if (index != INVALID_POSITION) { + return index; + } + index = findIndexOf(item, mOldData, mOldDataStart, mOldDataSize, LOOKUP); + if (index != INVALID_POSITION) { + return index - mOldDataStart + mMergedSize; + } + return INVALID_POSITION; + } + return findIndexOf(item, mData, 0, mSize, LOOKUP); + } + + private int findIndexOf(T item, T[] mData, int left, int right, int reason) { + while (left < right) { + final int middle = (left + right) / 2; + T myItem = mData[middle]; + final int cmp = mCallback.compare(myItem, item); + if (cmp < 0) { + left = middle + 1; + } else if (cmp == 0) { + if (mCallback.areItemsTheSame(myItem, item)) { + return middle; + } else { + int exact = linearEqualitySearch(item, middle, left, right); + if (reason == INSERTION) { + return exact == INVALID_POSITION ? middle : exact; + } else { + return exact; + } + } + } else { + right = middle; + } + } + return reason == INSERTION ? left : INVALID_POSITION; + } + + private int linearEqualitySearch(T item, int middle, int left, int right) { + // go left + for (int next = middle - 1; next >= left; next--) { + T nextItem = mData[next]; + int cmp = mCallback.compare(nextItem, item); + if (cmp != 0) { + break; + } + if (mCallback.areItemsTheSame(nextItem, item)) { + return next; + } + } + for (int next = middle + 1; next < right; next++) { + T nextItem = mData[next]; + int cmp = mCallback.compare(nextItem, item); + if (cmp != 0) { + break; + } + if (mCallback.areItemsTheSame(nextItem, item)) { + return next; + } + } + return INVALID_POSITION; + } + + private void addToData(int index, T item) { + if (index > mSize) { + throw new IndexOutOfBoundsException( + "cannot add item to " + index + " because size is " + mSize); + } + if (mSize == mData.length) { + // we are at the limit enlarge + T[] newData = (T[]) Array.newInstance(mTClass, mData.length + CAPACITY_GROWTH); + System.arraycopy(mData, 0, newData, 0, index); + newData[index] = item; + System.arraycopy(mData, index, newData, index + 1, mSize - index); + mData = newData; + } else { + // just shift, we fit + System.arraycopy(mData, index, mData, index + 1, mSize - index); + mData[index] = item; + } + mSize++; + } + + /** + * Removes all items from the SortedList. + */ + public void clear() { + throwIfMerging(); + if (mSize == 0) { + return; + } + final int prevSize = mSize; + Arrays.fill(mData, 0, prevSize, null); + mSize = 0; + mCallback.onRemoved(0, prevSize); + } + + /** + * The class that controls the behavior of the {@link SortedList}. + *

+ * It defines how items should be sorted and how duplicates should be handled. + *

+ * SortedList calls the callback methods on this class to notify changes about the underlying + * data. + */ + public static abstract class Callback implements Comparator { + + /** + * Similar to {@link java.util.Comparator#compare(Object, Object)}, should compare two and + * return how they should be ordered. + * + * @param o1 The first object to compare. + * @param o2 The second object to compare. + * + * @return a negative integer, zero, or a positive integer as the + * first argument is less than, equal to, or greater than the + * second. + */ + abstract public int compare(T2 o1, T2 o2); + + /** + * Called by the SortedList when an item is inserted at the given position. + * + * @param position The position of the new item. + * @param count The number of items that have been added. + */ + abstract public void onInserted(int position, int count); + + /** + * Called by the SortedList when an item is removed from the given position. + * + * @param position The position of the item which has been removed. + * @param count The number of items which have been removed. + */ + abstract public void onRemoved(int position, int count); + + /** + * Called by the SortedList when an item changes its position in the list. + * + * @param fromPosition The previous position of the item before the move. + * @param toPosition The new position of the item. + */ + abstract public void onMoved(int fromPosition, int toPosition); + + /** + * Called by the SortedList when the item at the given position is updated. + * + * @param position The position of the item which has been updated. + * @param count The number of items which has changed. + */ + abstract public void onChanged(int position, int count); + + /** + * Called by the SortedList when it wants to check whether two items have the same data + * or not. SortedList uses this information to decide whether it should call + * {@link #onChanged(int, int)} or not. + *

+ * SortedList uses this method to check equality instead of {@link Object#equals(Object)} + * so + * that you can change its behavior depending on your UI. + *

+ * For example, if you are using SortedList with a {@link android.support.v7.widget.RecyclerView.Adapter + * RecyclerView.Adapter}, you should + * return whether the items' visual representations are the same or not. + * + * @param oldItem The previous representation of the object. + * @param newItem The new object that replaces the previous one. + * + * @return True if the contents of the items are the same or false if they are different. + */ + abstract public boolean areContentsTheSame(T2 oldItem, T2 newItem); + + /** + * Called by the SortedList to decide whether two object represent the same Item or not. + *

+ * For example, if your items have unique ids, this method should check their equality. + * + * @param item1 The first item to check. + * @param item2 The second item to check. + * + * @return True if the two items represent the same object or false if they are different. + */ + abstract public boolean areItemsTheSame(T2 item1, T2 item2); + } + + /** + * A callback implementation that can batch notify events dispatched by the SortedList. + *

+ * This class can be useful if you want to do multiple operations on a SortedList but don't + * want to dispatch each event one by one, which may result in a performance issue. + *

+ * For example, if you are going to add multiple items to a SortedList, BatchedCallback call + * convert individual onInserted(index, 1) calls into one + * onInserted(index, N) if items are added into consecutive indices. This change + * can help RecyclerView resolve changes much more easily. + *

+ * If consecutive changes in the SortedList are not suitable for batching, BatchingCallback + * dispatches them as soon as such case is detected. After your edits on the SortedList is + * complete, you must always call {@link BatchedCallback#dispatchLastEvent()} to flush + * all changes to the Callback. + */ + public static class BatchedCallback extends Callback { + + private final Callback mWrappedCallback; + static final int TYPE_NONE = 0; + static final int TYPE_ADD = 1; + static final int TYPE_REMOVE = 2; + static final int TYPE_CHANGE = 3; + static final int TYPE_MOVE = 4; + + int mLastEventType = TYPE_NONE; + int mLastEventPosition = -1; + int mLastEventCount = -1; + + /** + * Creates a new BatchedCallback that wraps the provided Callback. + * + * @param wrappedCallback The Callback which should received the data change callbacks. + * Other method calls (e.g. {@link #compare(Object, Object)} from + * the SortedList are directly forwarded to this Callback. + */ + public BatchedCallback(Callback wrappedCallback) { + mWrappedCallback = wrappedCallback; + } + + @Override + public int compare(T2 o1, T2 o2) { + return mWrappedCallback.compare(o1, o2); + } + + @Override + public void onInserted(int position, int count) { + if (mLastEventType == TYPE_ADD && position >= mLastEventPosition + && position <= mLastEventPosition + mLastEventCount) { + mLastEventCount += count; + mLastEventPosition = Math.min(position, mLastEventPosition); + return; + } + dispatchLastEvent(); + mLastEventPosition = position; + mLastEventCount = count; + mLastEventType = TYPE_ADD; + } + + @Override + public void onRemoved(int position, int count) { + if (mLastEventType == TYPE_REMOVE && mLastEventPosition == position) { + mLastEventCount += count; + return; + } + dispatchLastEvent(); + mLastEventPosition = position; + mLastEventCount = count; + mLastEventType = TYPE_REMOVE; + } + + @Override + public void onMoved(int fromPosition, int toPosition) { + dispatchLastEvent();//moves are not merged + mWrappedCallback.onMoved(fromPosition, toPosition); + } + + @Override + public void onChanged(int position, int count) { + if (mLastEventType == TYPE_CHANGE && + !(position > mLastEventPosition + mLastEventCount + || position + count < mLastEventPosition)) { + // take potential overlap into account + int previousEnd = mLastEventPosition + mLastEventCount; + mLastEventPosition = Math.min(position, mLastEventPosition); + mLastEventCount = Math.max(previousEnd, position + count) - mLastEventPosition; + return; + } + dispatchLastEvent(); + mLastEventPosition = position; + mLastEventCount = count; + mLastEventType = TYPE_CHANGE; + } + + @Override + public boolean areContentsTheSame(T2 oldItem, T2 newItem) { + return mWrappedCallback.areContentsTheSame(oldItem, newItem); + } + + @Override + public boolean areItemsTheSame(T2 item1, T2 item2) { + return mWrappedCallback.areItemsTheSame(item1, item2); + } + + + /** + * This method dispatches any pending event notifications to the wrapped Callback. + * You must always call this method after you are done with editing the SortedList. + */ + public void dispatchLastEvent() { + if (mLastEventType == TYPE_NONE) { + return; + } + switch (mLastEventType) { + case TYPE_ADD: + mWrappedCallback.onInserted(mLastEventPosition, mLastEventCount); + break; + case TYPE_REMOVE: + mWrappedCallback.onRemoved(mLastEventPosition, mLastEventCount); + break; + case TYPE_CHANGE: + mWrappedCallback.onChanged(mLastEventPosition, mLastEventCount); + break; + } + mLastEventType = TYPE_NONE; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/util/ThreadUtil.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/util/ThreadUtil.java new file mode 100644 index 00000000..cdb8689f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/util/ThreadUtil.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.util; + +interface ThreadUtil { + + interface MainThreadCallback { + + void updateItemCount(int generation, int itemCount); + + void addTile(int generation, TileList.Tile tile); + + void removeTile(int generation, int position); + } + + interface BackgroundCallback { + + void refresh(int generation); + + void updateRange(int rangeStart, int rangeEnd, int extRangeStart, int extRangeEnd, + int scrollHint); + + void loadTile(int position, int scrollHint); + + void recycleTile(TileList.Tile tile); + } + + MainThreadCallback getMainThreadProxy(MainThreadCallback callback); + + BackgroundCallback getBackgroundProxy(BackgroundCallback callback); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/util/TileList.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/util/TileList.java new file mode 100644 index 00000000..1b943d90 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/util/TileList.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.util; + +import android.util.SparseArray; + +import java.lang.reflect.Array; + +/** + * A sparse collection of tiles sorted for efficient access. + */ +class TileList { + + final int mTileSize; + + // Keyed by start position. + private final SparseArray> mTiles = new SparseArray>(10); + + Tile mLastAccessedTile; + + public TileList(int tileSize) { + mTileSize = tileSize; + } + + public T getItemAt(int pos) { + if (mLastAccessedTile == null || !mLastAccessedTile.containsPosition(pos)) { + final int startPosition = pos - (pos % mTileSize); + final int index = mTiles.indexOfKey(startPosition); + if (index < 0) { + return null; + } + mLastAccessedTile = mTiles.valueAt(index); + } + return mLastAccessedTile.getByPosition(pos); + } + + public int size() { + return mTiles.size(); + } + + public void clear() { + mTiles.clear(); + } + + public Tile getAtIndex(int index) { + return mTiles.valueAt(index); + } + + public Tile addOrReplace(Tile newTile) { + final int index = mTiles.indexOfKey(newTile.mStartPosition); + if (index < 0) { + mTiles.put(newTile.mStartPosition, newTile); + return null; + } + Tile oldTile = mTiles.valueAt(index); + mTiles.setValueAt(index, newTile); + if (mLastAccessedTile == oldTile) { + mLastAccessedTile = newTile; + } + return oldTile; + } + + public Tile removeAtPos(int startPosition) { + Tile tile = mTiles.get(startPosition); + if (mLastAccessedTile == tile) { + mLastAccessedTile = null; + } + mTiles.delete(startPosition); + return tile; + } + + public static class Tile { + public final T[] mItems; + public int mStartPosition; + public int mItemCount; + Tile mNext; // Used only for pooling recycled tiles. + + public Tile(Class klass, int size) { + //noinspection unchecked + mItems = (T[]) Array.newInstance(klass, size); + } + + boolean containsPosition(int pos) { + return mStartPosition <= pos && pos < mStartPosition + mItemCount; + } + + T getByPosition(int pos) { + return mItems[pos - mStartPosition]; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/AdapterHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/AdapterHelper.java new file mode 100644 index 00000000..1c40eafc --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/AdapterHelper.java @@ -0,0 +1,768 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.widget; + +import android.support.v4.util.Pools; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.telegram.messenger.support.widget.RecyclerView.*; + +/** + * Helper class that can enqueue and process adapter update operations. + *

+ * To support animations, RecyclerView presents an older version the Adapter to best represent + * previous state of the layout. Sometimes, this is not trivial when items are removed that were + * not laid out, in which case, RecyclerView has no way of providing that item's view for + * animations. + *

+ * AdapterHelper creates an UpdateOp for each adapter data change then pre-processes them. During + * pre processing, AdapterHelper finds out which UpdateOps can be deferred to second layout pass + * and which cannot. For the UpdateOps that cannot be deferred, AdapterHelper will change them + * according to previously deferred operation and dispatch them before the first layout pass. It + * also takes care of updating deferred UpdateOps since order of operations is changed by this + * process. + *

+ * Although operations may be forwarded to LayoutManager in different orders, resulting data set + * is guaranteed to be the consistent. + */ +class AdapterHelper implements OpReorderer.Callback { + + final static int POSITION_TYPE_INVISIBLE = 0; + + final static int POSITION_TYPE_NEW_OR_LAID_OUT = 1; + + private static final boolean DEBUG = false; + + private static final String TAG = "AHT"; + + private Pools.Pool mUpdateOpPool = new Pools.SimplePool(UpdateOp.POOL_SIZE); + + final ArrayList mPendingUpdates = new ArrayList(); + + final ArrayList mPostponedList = new ArrayList(); + + final Callback mCallback; + + Runnable mOnItemProcessedCallback; + + final boolean mDisableRecycler; + + final OpReorderer mOpReorderer; + + private int mExistingUpdateTypes = 0; + + AdapterHelper(Callback callback) { + this(callback, false); + } + + AdapterHelper(Callback callback, boolean disableRecycler) { + mCallback = callback; + mDisableRecycler = disableRecycler; + mOpReorderer = new OpReorderer(this); + } + + AdapterHelper addUpdateOp(UpdateOp... ops) { + Collections.addAll(mPendingUpdates, ops); + return this; + } + + void reset() { + recycleUpdateOpsAndClearList(mPendingUpdates); + recycleUpdateOpsAndClearList(mPostponedList); + mExistingUpdateTypes = 0; + } + + void preProcess() { + mOpReorderer.reorderOps(mPendingUpdates); + final int count = mPendingUpdates.size(); + for (int i = 0; i < count; i++) { + UpdateOp op = mPendingUpdates.get(i); + switch (op.cmd) { + case UpdateOp.ADD: + applyAdd(op); + break; + case UpdateOp.REMOVE: + applyRemove(op); + break; + case UpdateOp.UPDATE: + applyUpdate(op); + break; + case UpdateOp.MOVE: + applyMove(op); + break; + } + if (mOnItemProcessedCallback != null) { + mOnItemProcessedCallback.run(); + } + } + mPendingUpdates.clear(); + } + + void consumePostponedUpdates() { + final int count = mPostponedList.size(); + for (int i = 0; i < count; i++) { + mCallback.onDispatchSecondPass(mPostponedList.get(i)); + } + recycleUpdateOpsAndClearList(mPostponedList); + mExistingUpdateTypes = 0; + } + + private void applyMove(UpdateOp op) { + // MOVE ops are pre-processed so at this point, we know that item is still in the adapter. + // otherwise, it would be converted into a REMOVE operation + postponeAndUpdateViewHolders(op); + } + + private void applyRemove(UpdateOp op) { + int tmpStart = op.positionStart; + int tmpCount = 0; + int tmpEnd = op.positionStart + op.itemCount; + int type = -1; + for (int position = op.positionStart; position < tmpEnd; position++) { + boolean typeChanged = false; + ViewHolder vh = mCallback.findViewHolder(position); + if (vh != null || canFindInPreLayout(position)) { + // If a ViewHolder exists or this is a newly added item, we can defer this update + // to post layout stage. + // * For existing ViewHolders, we'll fake its existence in the pre-layout phase. + // * For items that are added and removed in the same process cycle, they won't + // have any effect in pre-layout since their add ops are already deferred to + // post-layout pass. + if (type == POSITION_TYPE_INVISIBLE) { + // Looks like we have other updates that we cannot merge with this one. + // Create an UpdateOp and dispatch it to LayoutManager. + UpdateOp newOp = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null); + dispatchAndUpdateViewHolders(newOp); + typeChanged = true; + } + type = POSITION_TYPE_NEW_OR_LAID_OUT; + } else { + // This update cannot be recovered because we don't have a ViewHolder representing + // this position. Instead, post it to LayoutManager immediately + if (type == POSITION_TYPE_NEW_OR_LAID_OUT) { + // Looks like we have other updates that we cannot merge with this one. + // Create UpdateOp op and dispatch it to LayoutManager. + UpdateOp newOp = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null); + postponeAndUpdateViewHolders(newOp); + typeChanged = true; + } + type = POSITION_TYPE_INVISIBLE; + } + if (typeChanged) { + position -= tmpCount; // also equal to tmpStart + tmpEnd -= tmpCount; + tmpCount = 1; + } else { + tmpCount++; + } + } + if (tmpCount != op.itemCount) { // all 1 effect + recycleUpdateOp(op); + op = obtainUpdateOp(UpdateOp.REMOVE, tmpStart, tmpCount, null); + } + if (type == POSITION_TYPE_INVISIBLE) { + dispatchAndUpdateViewHolders(op); + } else { + postponeAndUpdateViewHolders(op); + } + } + + private void applyUpdate(UpdateOp op) { + int tmpStart = op.positionStart; + int tmpCount = 0; + int tmpEnd = op.positionStart + op.itemCount; + int type = -1; + for (int position = op.positionStart; position < tmpEnd; position++) { + ViewHolder vh = mCallback.findViewHolder(position); + if (vh != null || canFindInPreLayout(position)) { // deferred + if (type == POSITION_TYPE_INVISIBLE) { + UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount, + op.payload); + dispatchAndUpdateViewHolders(newOp); + tmpCount = 0; + tmpStart = position; + } + type = POSITION_TYPE_NEW_OR_LAID_OUT; + } else { // applied + if (type == POSITION_TYPE_NEW_OR_LAID_OUT) { + UpdateOp newOp = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount, + op.payload); + postponeAndUpdateViewHolders(newOp); + tmpCount = 0; + tmpStart = position; + } + type = POSITION_TYPE_INVISIBLE; + } + tmpCount++; + } + if (tmpCount != op.itemCount) { // all 1 effect + Object payload = op.payload; + recycleUpdateOp(op); + op = obtainUpdateOp(UpdateOp.UPDATE, tmpStart, tmpCount, payload); + } + if (type == POSITION_TYPE_INVISIBLE) { + dispatchAndUpdateViewHolders(op); + } else { + postponeAndUpdateViewHolders(op); + } + } + + private void dispatchAndUpdateViewHolders(UpdateOp op) { + // tricky part. + // traverse all postpones and revert their changes on this op if necessary, apply updated + // dispatch to them since now they are after this op. + if (op.cmd == UpdateOp.ADD || op.cmd == UpdateOp.MOVE) { + throw new IllegalArgumentException("should not dispatch add or move for pre layout"); + } + if (DEBUG) { + Log.d(TAG, "dispatch (pre)" + op); + Log.d(TAG, "postponed state before:"); + for (UpdateOp updateOp : mPostponedList) { + Log.d(TAG, updateOp.toString()); + } + Log.d(TAG, "----"); + } + + // handle each pos 1 by 1 to ensure continuity. If it breaks, dispatch partial + // TODO Since move ops are pushed to end, we should not need this anymore + int tmpStart = updatePositionWithPostponed(op.positionStart, op.cmd); + if (DEBUG) { + Log.d(TAG, "pos:" + op.positionStart + ",updatedPos:" + tmpStart); + } + int tmpCnt = 1; + int offsetPositionForPartial = op.positionStart; + final int positionMultiplier; + switch (op.cmd) { + case UpdateOp.UPDATE: + positionMultiplier = 1; + break; + case UpdateOp.REMOVE: + positionMultiplier = 0; + break; + default: + throw new IllegalArgumentException("op should be remove or update." + op); + } + for (int p = 1; p < op.itemCount; p++) { + final int pos = op.positionStart + (positionMultiplier * p); + int updatedPos = updatePositionWithPostponed(pos, op.cmd); + if (DEBUG) { + Log.d(TAG, "pos:" + pos + ",updatedPos:" + updatedPos); + } + boolean continuous = false; + switch (op.cmd) { + case UpdateOp.UPDATE: + continuous = updatedPos == tmpStart + 1; + break; + case UpdateOp.REMOVE: + continuous = updatedPos == tmpStart; + break; + } + if (continuous) { + tmpCnt++; + } else { + // need to dispatch this separately + UpdateOp tmp = obtainUpdateOp(op.cmd, tmpStart, tmpCnt, op.payload); + if (DEBUG) { + Log.d(TAG, "need to dispatch separately " + tmp); + } + dispatchFirstPassAndUpdateViewHolders(tmp, offsetPositionForPartial); + recycleUpdateOp(tmp); + if (op.cmd == UpdateOp.UPDATE) { + offsetPositionForPartial += tmpCnt; + } + tmpStart = updatedPos;// need to remove previously dispatched + tmpCnt = 1; + } + } + Object payload = op.payload; + recycleUpdateOp(op); + if (tmpCnt > 0) { + UpdateOp tmp = obtainUpdateOp(op.cmd, tmpStart, tmpCnt, payload); + if (DEBUG) { + Log.d(TAG, "dispatching:" + tmp); + } + dispatchFirstPassAndUpdateViewHolders(tmp, offsetPositionForPartial); + recycleUpdateOp(tmp); + } + if (DEBUG) { + Log.d(TAG, "post dispatch"); + Log.d(TAG, "postponed state after:"); + for (UpdateOp updateOp : mPostponedList) { + Log.d(TAG, updateOp.toString()); + } + Log.d(TAG, "----"); + } + } + + void dispatchFirstPassAndUpdateViewHolders(UpdateOp op, int offsetStart) { + mCallback.onDispatchFirstPass(op); + switch (op.cmd) { + case UpdateOp.REMOVE: + mCallback.offsetPositionsForRemovingInvisible(offsetStart, op.itemCount); + break; + case UpdateOp.UPDATE: + mCallback.markViewHoldersUpdated(offsetStart, op.itemCount, op.payload); + break; + default: + throw new IllegalArgumentException("only remove and update ops can be dispatched" + + " in first pass"); + } + } + + private int updatePositionWithPostponed(int pos, int cmd) { + final int count = mPostponedList.size(); + for (int i = count - 1; i >= 0; i--) { + UpdateOp postponed = mPostponedList.get(i); + if (postponed.cmd == UpdateOp.MOVE) { + int start, end; + if (postponed.positionStart < postponed.itemCount) { + start = postponed.positionStart; + end = postponed.itemCount; + } else { + start = postponed.itemCount; + end = postponed.positionStart; + } + if (pos >= start && pos <= end) { + //i'm affected + if (start == postponed.positionStart) { + if (cmd == UpdateOp.ADD) { + postponed.itemCount++; + } else if (cmd == UpdateOp.REMOVE) { + postponed.itemCount--; + } + // op moved to left, move it right to revert + pos++; + } else { + if (cmd == UpdateOp.ADD) { + postponed.positionStart++; + } else if (cmd == UpdateOp.REMOVE) { + postponed.positionStart--; + } + // op was moved right, move left to revert + pos--; + } + } else if (pos < postponed.positionStart) { + // postponed MV is outside the dispatched OP. if it is before, offset + if (cmd == UpdateOp.ADD) { + postponed.positionStart++; + postponed.itemCount++; + } else if (cmd == UpdateOp.REMOVE) { + postponed.positionStart--; + postponed.itemCount--; + } + } + } else { + if (postponed.positionStart <= pos) { + if (postponed.cmd == UpdateOp.ADD) { + pos -= postponed.itemCount; + } else if (postponed.cmd == UpdateOp.REMOVE) { + pos += postponed.itemCount; + } + } else { + if (cmd == UpdateOp.ADD) { + postponed.positionStart++; + } else if (cmd == UpdateOp.REMOVE) { + postponed.positionStart--; + } + } + } + if (DEBUG) { + Log.d(TAG, "dispath (step" + i + ")"); + Log.d(TAG, "postponed state:" + i + ", pos:" + pos); + for (UpdateOp updateOp : mPostponedList) { + Log.d(TAG, updateOp.toString()); + } + Log.d(TAG, "----"); + } + } + for (int i = mPostponedList.size() - 1; i >= 0; i--) { + UpdateOp op = mPostponedList.get(i); + if (op.cmd == UpdateOp.MOVE) { + if (op.itemCount == op.positionStart || op.itemCount < 0) { + mPostponedList.remove(i); + recycleUpdateOp(op); + } + } else if (op.itemCount <= 0) { + mPostponedList.remove(i); + recycleUpdateOp(op); + } + } + return pos; + } + + private boolean canFindInPreLayout(int position) { + final int count = mPostponedList.size(); + for (int i = 0; i < count; i++) { + UpdateOp op = mPostponedList.get(i); + if (op.cmd == UpdateOp.MOVE) { + if (findPositionOffset(op.itemCount, i + 1) == position) { + return true; + } + } else if (op.cmd == UpdateOp.ADD) { + // TODO optimize. + final int end = op.positionStart + op.itemCount; + for (int pos = op.positionStart; pos < end; pos++) { + if (findPositionOffset(pos, i + 1) == position) { + return true; + } + } + } + } + return false; + } + + private void applyAdd(UpdateOp op) { + postponeAndUpdateViewHolders(op); + } + + private void postponeAndUpdateViewHolders(UpdateOp op) { + if (DEBUG) { + Log.d(TAG, "postponing " + op); + } + mPostponedList.add(op); + switch (op.cmd) { + case UpdateOp.ADD: + mCallback.offsetPositionsForAdd(op.positionStart, op.itemCount); + break; + case UpdateOp.MOVE: + mCallback.offsetPositionsForMove(op.positionStart, op.itemCount); + break; + case UpdateOp.REMOVE: + mCallback.offsetPositionsForRemovingLaidOutOrNewView(op.positionStart, + op.itemCount); + break; + case UpdateOp.UPDATE: + mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount, op.payload); + break; + default: + throw new IllegalArgumentException("Unknown update op type for " + op); + } + } + + boolean hasPendingUpdates() { + return mPendingUpdates.size() > 0; + } + + boolean hasAnyUpdateTypes(int updateTypes) { + return (mExistingUpdateTypes & updateTypes) != 0; + } + + int findPositionOffset(int position) { + return findPositionOffset(position, 0); + } + + int findPositionOffset(int position, int firstPostponedItem) { + int count = mPostponedList.size(); + for (int i = firstPostponedItem; i < count; ++i) { + UpdateOp op = mPostponedList.get(i); + if (op.cmd == UpdateOp.MOVE) { + if (op.positionStart == position) { + position = op.itemCount; + } else { + if (op.positionStart < position) { + position--; // like a remove + } + if (op.itemCount <= position) { + position++; // like an add + } + } + } else if (op.positionStart <= position) { + if (op.cmd == UpdateOp.REMOVE) { + if (position < op.positionStart + op.itemCount) { + return -1; + } + position -= op.itemCount; + } else if (op.cmd == UpdateOp.ADD) { + position += op.itemCount; + } + } + } + return position; + } + + /** + * @return True if updates should be processed. + */ + boolean onItemRangeChanged(int positionStart, int itemCount, Object payload) { + mPendingUpdates.add(obtainUpdateOp(UpdateOp.UPDATE, positionStart, itemCount, payload)); + mExistingUpdateTypes |= UpdateOp.UPDATE; + return mPendingUpdates.size() == 1; + } + + /** + * @return True if updates should be processed. + */ + boolean onItemRangeInserted(int positionStart, int itemCount) { + mPendingUpdates.add(obtainUpdateOp(UpdateOp.ADD, positionStart, itemCount, null)); + mExistingUpdateTypes |= UpdateOp.ADD; + return mPendingUpdates.size() == 1; + } + + /** + * @return True if updates should be processed. + */ + boolean onItemRangeRemoved(int positionStart, int itemCount) { + mPendingUpdates.add(obtainUpdateOp(UpdateOp.REMOVE, positionStart, itemCount, null)); + mExistingUpdateTypes |= UpdateOp.REMOVE; + return mPendingUpdates.size() == 1; + } + + /** + * @return True if updates should be processed. + */ + boolean onItemRangeMoved(int from, int to, int itemCount) { + if (from == to) { + return false; // no-op + } + if (itemCount != 1) { + throw new IllegalArgumentException("Moving more than 1 item is not supported yet"); + } + mPendingUpdates.add(obtainUpdateOp(UpdateOp.MOVE, from, to, null)); + mExistingUpdateTypes |= UpdateOp.MOVE; + return mPendingUpdates.size() == 1; + } + + /** + * Skips pre-processing and applies all updates in one pass. + */ + void consumeUpdatesInOnePass() { + // we still consume postponed updates (if there is) in case there was a pre-process call + // w/o a matching consumePostponedUpdates. + consumePostponedUpdates(); + final int count = mPendingUpdates.size(); + for (int i = 0; i < count; i++) { + UpdateOp op = mPendingUpdates.get(i); + switch (op.cmd) { + case UpdateOp.ADD: + mCallback.onDispatchSecondPass(op); + mCallback.offsetPositionsForAdd(op.positionStart, op.itemCount); + break; + case UpdateOp.REMOVE: + mCallback.onDispatchSecondPass(op); + mCallback.offsetPositionsForRemovingInvisible(op.positionStart, op.itemCount); + break; + case UpdateOp.UPDATE: + mCallback.onDispatchSecondPass(op); + mCallback.markViewHoldersUpdated(op.positionStart, op.itemCount, op.payload); + break; + case UpdateOp.MOVE: + mCallback.onDispatchSecondPass(op); + mCallback.offsetPositionsForMove(op.positionStart, op.itemCount); + break; + } + if (mOnItemProcessedCallback != null) { + mOnItemProcessedCallback.run(); + } + } + recycleUpdateOpsAndClearList(mPendingUpdates); + mExistingUpdateTypes = 0; + } + + public int applyPendingUpdatesToPosition(int position) { + final int size = mPendingUpdates.size(); + for (int i = 0; i < size; i ++) { + UpdateOp op = mPendingUpdates.get(i); + switch (op.cmd) { + case UpdateOp.ADD: + if (op.positionStart <= position) { + position += op.itemCount; + } + break; + case UpdateOp.REMOVE: + if (op.positionStart <= position) { + final int end = op.positionStart + op.itemCount; + if (end > position) { + return RecyclerView.NO_POSITION; + } + position -= op.itemCount; + } + break; + case UpdateOp.MOVE: + if (op.positionStart == position) { + position = op.itemCount;//position end + } else { + if (op.positionStart < position) { + position -= 1; + } + if (op.itemCount <= position) { + position += 1; + } + } + break; + } + } + return position; + } + + boolean hasUpdates() { + return !mPostponedList.isEmpty() && !mPendingUpdates.isEmpty(); + } + + /** + * Queued operation to happen when child views are updated. + */ + static class UpdateOp { + + static final int ADD = 1; + + static final int REMOVE = 1 << 1; + + static final int UPDATE = 1 << 2; + + static final int MOVE = 1 << 3; + + static final int POOL_SIZE = 30; + + int cmd; + + int positionStart; + + Object payload; + + // holds the target position if this is a MOVE + int itemCount; + + UpdateOp(int cmd, int positionStart, int itemCount, Object payload) { + this.cmd = cmd; + this.positionStart = positionStart; + this.itemCount = itemCount; + this.payload = payload; + } + + String cmdToString() { + switch (cmd) { + case ADD: + return "add"; + case REMOVE: + return "rm"; + case UPDATE: + return "up"; + case MOVE: + return "mv"; + } + return "??"; + } + + @Override + public String toString() { + return Integer.toHexString(System.identityHashCode(this)) + + "[" + cmdToString() + ",s:" + positionStart + "c:" + itemCount + +",p:"+payload + "]"; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + UpdateOp op = (UpdateOp) o; + + if (cmd != op.cmd) { + return false; + } + if (cmd == MOVE && Math.abs(itemCount - positionStart) == 1) { + // reverse of this is also true + if (itemCount == op.positionStart && positionStart == op.itemCount) { + return true; + } + } + if (itemCount != op.itemCount) { + return false; + } + if (positionStart != op.positionStart) { + return false; + } + if (payload != null) { + if (!payload.equals(op.payload)) { + return false; + } + } else if (op.payload != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = cmd; + result = 31 * result + positionStart; + result = 31 * result + itemCount; + return result; + } + } + + @Override + public UpdateOp obtainUpdateOp(int cmd, int positionStart, int itemCount, Object payload) { + UpdateOp op = mUpdateOpPool.acquire(); + if (op == null) { + op = new UpdateOp(cmd, positionStart, itemCount, payload); + } else { + op.cmd = cmd; + op.positionStart = positionStart; + op.itemCount = itemCount; + op.payload = payload; + } + return op; + } + + @Override + public void recycleUpdateOp(UpdateOp op) { + if (!mDisableRecycler) { + op.payload = null; + mUpdateOpPool.release(op); + } + } + + void recycleUpdateOpsAndClearList(List ops) { + final int count = ops.size(); + for (int i = 0; i < count; i++) { + recycleUpdateOp(ops.get(i)); + } + ops.clear(); + } + + /** + * Contract between AdapterHelper and RecyclerView. + */ + static interface Callback { + + ViewHolder findViewHolder(int position); + + void offsetPositionsForRemovingInvisible(int positionStart, int itemCount); + + void offsetPositionsForRemovingLaidOutOrNewView(int positionStart, int itemCount); + + void markViewHoldersUpdated(int positionStart, int itemCount, Object payloads); + + void onDispatchFirstPass(UpdateOp updateOp); + + void onDispatchSecondPass(UpdateOp updateOp); + + void offsetPositionsForAdd(int positionStart, int itemCount); + + void offsetPositionsForMove(int from, int to); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/ChildHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/ChildHelper.java new file mode 100644 index 00000000..582b8f24 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/ChildHelper.java @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.widget; + +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; +import java.util.List; + +/** + * Helper class to manage children. + *

+ * It wraps a RecyclerView and adds ability to hide some children. There are two sets of methods + * provided by this class. Regular methods are the ones that replicate ViewGroup methods + * like getChildAt, getChildCount etc. These methods ignore hidden children. + *

+ * When RecyclerView needs direct access to the view group children, it can call unfiltered + * methods like get getUnfilteredChildCount or getUnfilteredChildAt. + */ +class ChildHelper { + + private static final boolean DEBUG = false; + + private static final String TAG = "ChildrenHelper"; + + final Callback mCallback; + + final Bucket mBucket; + + final List mHiddenViews; + + ChildHelper(Callback callback) { + mCallback = callback; + mBucket = new Bucket(); + mHiddenViews = new ArrayList(); + } + + /** + * Marks a child view as hidden + * + * @param child View to hide. + */ + private void hideViewInternal(View child) { + mHiddenViews.add(child); + mCallback.onEnteredHiddenState(child); + } + + /** + * Unmarks a child view as hidden. + * + * @param child View to hide. + */ + private boolean unhideViewInternal(View child) { + if (mHiddenViews.remove(child)) { + mCallback.onLeftHiddenState(child); + return true; + } else { + return false; + } + } + + /** + * Adds a view to the ViewGroup + * + * @param child View to add. + * @param hidden If set to true, this item will be invisible from regular methods. + */ + void addView(View child, boolean hidden) { + addView(child, -1, hidden); + } + + /** + * Add a view to the ViewGroup at an index + * + * @param child View to add. + * @param index Index of the child from the regular perspective (excluding hidden views). + * ChildHelper offsets this index to actual ViewGroup index. + * @param hidden If set to true, this item will be invisible from regular methods. + */ + void addView(View child, int index, boolean hidden) { + final int offset; + if (index < 0) { + offset = mCallback.getChildCount(); + } else { + offset = getOffset(index); + } + mBucket.insert(offset, hidden); + if (hidden) { + hideViewInternal(child); + } + mCallback.addView(child, offset); + if (DEBUG) { + Log.d(TAG, "addViewAt " + index + ",h:" + hidden + ", " + this); + } + } + + private int getOffset(int index) { + if (index < 0) { + return -1; //anything below 0 won't work as diff will be undefined. + } + final int limit = mCallback.getChildCount(); + int offset = index; + while (offset < limit) { + final int removedBefore = mBucket.countOnesBefore(offset); + final int diff = index - (offset - removedBefore); + if (diff == 0) { + while (mBucket.get(offset)) { // ensure this offset is not hidden + offset ++; + } + return offset; + } else { + offset += diff; + } + } + return -1; + } + + /** + * Removes the provided View from underlying RecyclerView. + * + * @param view The view to remove. + */ + void removeView(View view) { + int index = mCallback.indexOfChild(view); + if (index < 0) { + return; + } + if (mBucket.remove(index)) { + unhideViewInternal(view); + } + mCallback.removeViewAt(index); + if (DEBUG) { + Log.d(TAG, "remove View off:" + index + "," + this); + } + } + + /** + * Removes the view at the provided index from RecyclerView. + * + * @param index Index of the child from the regular perspective (excluding hidden views). + * ChildHelper offsets this index to actual ViewGroup index. + */ + void removeViewAt(int index) { + final int offset = getOffset(index); + final View view = mCallback.getChildAt(offset); + if (view == null) { + return; + } + if (mBucket.remove(offset)) { + unhideViewInternal(view); + } + mCallback.removeViewAt(offset); + if (DEBUG) { + Log.d(TAG, "removeViewAt " + index + ", off:" + offset + ", " + this); + } + } + + /** + * Returns the child at provided index. + * + * @param index Index of the child to return in regular perspective. + */ + View getChildAt(int index) { + final int offset = getOffset(index); + return mCallback.getChildAt(offset); + } + + /** + * Removes all views from the ViewGroup including the hidden ones. + */ + void removeAllViewsUnfiltered() { + mBucket.reset(); + for (int i = mHiddenViews.size() - 1; i >= 0; i--) { + mCallback.onLeftHiddenState(mHiddenViews.get(i)); + mHiddenViews.remove(i); + } + mCallback.removeAllViews(); + if (DEBUG) { + Log.d(TAG, "removeAllViewsUnfiltered"); + } + } + + /** + * This can be used to find a disappearing view by position. + * + * @param position The adapter position of the item. + * @param type View type, can be {@link RecyclerView#INVALID_TYPE}. + * @return A hidden view with a valid ViewHolder that matches the position and type. + */ + View findHiddenNonRemovedView(int position, int type) { + final int count = mHiddenViews.size(); + for (int i = 0; i < count; i++) { + final View view = mHiddenViews.get(i); + RecyclerView.ViewHolder holder = mCallback.getChildViewHolder(view); + if (holder.getLayoutPosition() == position && !holder.isInvalid() && !holder.isRemoved() + && (type == RecyclerView.INVALID_TYPE || holder.getItemViewType() == type)) { + return view; + } + } + return null; + } + + /** + * Attaches the provided view to the underlying ViewGroup. + * + * @param child Child to attach. + * @param index Index of the child to attach in regular perspective. + * @param layoutParams LayoutParams for the child. + * @param hidden If set to true, this item will be invisible to the regular methods. + */ + void attachViewToParent(View child, int index, ViewGroup.LayoutParams layoutParams, + boolean hidden) { + final int offset; + if (index < 0) { + offset = mCallback.getChildCount(); + } else { + offset = getOffset(index); + } + mBucket.insert(offset, hidden); + if (hidden) { + hideViewInternal(child); + } + mCallback.attachViewToParent(child, offset, layoutParams); + if (DEBUG) { + Log.d(TAG, "attach view to parent index:" + index + ",off:" + offset + "," + + "h:" + hidden + ", " + this); + } + } + + /** + * Returns the number of children that are not hidden. + * + * @return Number of children that are not hidden. + * @see #getChildAt(int) + */ + int getChildCount() { + return mCallback.getChildCount() - mHiddenViews.size(); + } + + /** + * Returns the total number of children. + * + * @return The total number of children including the hidden views. + * @see #getUnfilteredChildAt(int) + */ + int getUnfilteredChildCount() { + return mCallback.getChildCount(); + } + + /** + * Returns a child by ViewGroup offset. ChildHelper won't offset this index. + * + * @param index ViewGroup index of the child to return. + * @return The view in the provided index. + */ + View getUnfilteredChildAt(int index) { + return mCallback.getChildAt(index); + } + + /** + * Detaches the view at the provided index. + * + * @param index Index of the child to return in regular perspective. + */ + void detachViewFromParent(int index) { + final int offset = getOffset(index); + mBucket.remove(offset); + mCallback.detachViewFromParent(offset); + if (DEBUG) { + Log.d(TAG, "detach view from parent " + index + ", off:" + offset); + } + } + + /** + * Returns the index of the child in regular perspective. + * + * @param child The child whose index will be returned. + * @return The regular perspective index of the child or -1 if it does not exists. + */ + int indexOfChild(View child) { + final int index = mCallback.indexOfChild(child); + if (index == -1) { + return -1; + } + if (mBucket.get(index)) { + if (DEBUG) { + throw new IllegalArgumentException("cannot get index of a hidden child"); + } else { + return -1; + } + } + // reverse the index + return index - mBucket.countOnesBefore(index); + } + + /** + * Returns whether a View is visible to LayoutManager or not. + * + * @param view The child view to check. Should be a child of the Callback. + * @return True if the View is not visible to LayoutManager + */ + boolean isHidden(View view) { + return mHiddenViews.contains(view); + } + + /** + * Marks a child view as hidden. + * + * @param view The view to hide. + */ + void hide(View view) { + final int offset = mCallback.indexOfChild(view); + if (offset < 0) { + throw new IllegalArgumentException("view is not a child, cannot hide " + view); + } + if (DEBUG && mBucket.get(offset)) { + throw new RuntimeException("trying to hide same view twice, how come ? " + view); + } + mBucket.set(offset); + hideViewInternal(view); + if (DEBUG) { + Log.d(TAG, "hiding child " + view + " at offset " + offset+ ", " + this); + } + } + + /** + * Moves a child view from hidden list to regular list. + * Calling this method should probably be followed by a detach, otherwise, it will suddenly + * show up in LayoutManager's children list. + * + * @param view The hidden View to unhide + */ + void unhide(View view) { + final int offset = mCallback.indexOfChild(view); + if (offset < 0) { + throw new IllegalArgumentException("view is not a child, cannot hide " + view); + } + if (!mBucket.get(offset)) { + throw new RuntimeException("trying to unhide a view that was not hidden" + view); + } + mBucket.clear(offset); + unhideViewInternal(view); + } + + @Override + public String toString() { + return mBucket.toString() + ", hidden list:" + mHiddenViews.size(); + } + + /** + * Removes a view from the ViewGroup if it is hidden. + * + * @param view The view to remove. + * @return True if the View is found and it is hidden. False otherwise. + */ + boolean removeViewIfHidden(View view) { + final int index = mCallback.indexOfChild(view); + if (index == -1) { + if (unhideViewInternal(view) && DEBUG) { + throw new IllegalStateException("view is in hidden list but not in view group"); + } + return true; + } + if (mBucket.get(index)) { + mBucket.remove(index); + if (!unhideViewInternal(view) && DEBUG) { + throw new IllegalStateException( + "removed a hidden view but it is not in hidden views list"); + } + mCallback.removeViewAt(index); + return true; + } + return false; + } + + /** + * Bitset implementation that provides methods to offset indices. + */ + static class Bucket { + + final static int BITS_PER_WORD = Long.SIZE; + + final static long LAST_BIT = 1L << (Long.SIZE - 1); + + long mData = 0; + + Bucket next; + + void set(int index) { + if (index >= BITS_PER_WORD) { + ensureNext(); + next.set(index - BITS_PER_WORD); + } else { + mData |= 1L << index; + } + } + + private void ensureNext() { + if (next == null) { + next = new Bucket(); + } + } + + void clear(int index) { + if (index >= BITS_PER_WORD) { + if (next != null) { + next.clear(index - BITS_PER_WORD); + } + } else { + mData &= ~(1L << index); + } + + } + + boolean get(int index) { + if (index >= BITS_PER_WORD) { + ensureNext(); + return next.get(index - BITS_PER_WORD); + } else { + return (mData & (1L << index)) != 0; + } + } + + void reset() { + mData = 0; + if (next != null) { + next.reset(); + } + } + + void insert(int index, boolean value) { + if (index >= BITS_PER_WORD) { + ensureNext(); + next.insert(index - BITS_PER_WORD, value); + } else { + final boolean lastBit = (mData & LAST_BIT) != 0; + long mask = (1L << index) - 1; + final long before = mData & mask; + final long after = ((mData & ~mask)) << 1; + mData = before | after; + if (value) { + set(index); + } else { + clear(index); + } + if (lastBit || next != null) { + ensureNext(); + next.insert(0, lastBit); + } + } + } + + boolean remove(int index) { + if (index >= BITS_PER_WORD) { + ensureNext(); + return next.remove(index - BITS_PER_WORD); + } else { + long mask = (1L << index); + final boolean value = (mData & mask) != 0; + mData &= ~mask; + mask = mask - 1; + final long before = mData & mask; + // cannot use >> because it adds one. + final long after = Long.rotateRight(mData & ~mask, 1); + mData = before | after; + if (next != null) { + if (next.get(0)) { + set(BITS_PER_WORD - 1); + } + next.remove(0); + } + return value; + } + } + + int countOnesBefore(int index) { + if (next == null) { + if (index >= BITS_PER_WORD) { + return Long.bitCount(mData); + } + return Long.bitCount(mData & ((1L << index) - 1)); + } + if (index < BITS_PER_WORD) { + return Long.bitCount(mData & ((1L << index) - 1)); + } else { + return next.countOnesBefore(index - BITS_PER_WORD) + Long.bitCount(mData); + } + } + + @Override + public String toString() { + return next == null ? Long.toBinaryString(mData) + : next.toString() + "xx" + Long.toBinaryString(mData); + } + } + + static interface Callback { + + int getChildCount(); + + void addView(View child, int index); + + int indexOfChild(View view); + + void removeViewAt(int index); + + View getChildAt(int offset); + + void removeAllViews(); + + RecyclerView.ViewHolder getChildViewHolder(View view); + + void attachViewToParent(View child, int index, ViewGroup.LayoutParams layoutParams); + + void detachViewFromParent(int offset); + + void onEnteredHiddenState(View child); + + void onLeftHiddenState(View child); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/DefaultItemAnimator.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/DefaultItemAnimator.java new file mode 100644 index 00000000..546f93f0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/DefaultItemAnimator.java @@ -0,0 +1,668 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.support.widget; + +import android.support.annotation.NonNull; +import android.support.v4.animation.AnimatorCompatHelper; +import android.support.v4.view.ViewCompat; +import android.support.v4.view.ViewPropertyAnimatorCompat; +import android.support.v4.view.ViewPropertyAnimatorListener; +import org.telegram.messenger.support.widget.RecyclerView.ViewHolder; +import android.view.View; + +import java.util.ArrayList; +import java.util.List; + +/** + * This implementation of {@link RecyclerView.ItemAnimator} provides basic + * animations on remove, add, and move events that happen to the items in + * a RecyclerView. RecyclerView uses a DefaultItemAnimator by default. + * + * @see RecyclerView#setItemAnimator(RecyclerView.ItemAnimator) + */ +public class DefaultItemAnimator extends SimpleItemAnimator { + private static final boolean DEBUG = false; + + private ArrayList mPendingRemovals = new ArrayList<>(); + private ArrayList mPendingAdditions = new ArrayList<>(); + private ArrayList mPendingMoves = new ArrayList<>(); + private ArrayList mPendingChanges = new ArrayList<>(); + + private ArrayList> mAdditionsList = new ArrayList<>(); + private ArrayList> mMovesList = new ArrayList<>(); + private ArrayList> mChangesList = new ArrayList<>(); + + private ArrayList mAddAnimations = new ArrayList<>(); + private ArrayList mMoveAnimations = new ArrayList<>(); + private ArrayList mRemoveAnimations = new ArrayList<>(); + private ArrayList mChangeAnimations = new ArrayList<>(); + + private static class MoveInfo { + public ViewHolder holder; + public int fromX, fromY, toX, toY; + + private MoveInfo(ViewHolder holder, int fromX, int fromY, int toX, int toY) { + this.holder = holder; + this.fromX = fromX; + this.fromY = fromY; + this.toX = toX; + this.toY = toY; + } + } + + private static class ChangeInfo { + public ViewHolder oldHolder, newHolder; + public int fromX, fromY, toX, toY; + private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder) { + this.oldHolder = oldHolder; + this.newHolder = newHolder; + } + + private ChangeInfo(ViewHolder oldHolder, ViewHolder newHolder, + int fromX, int fromY, int toX, int toY) { + this(oldHolder, newHolder); + this.fromX = fromX; + this.fromY = fromY; + this.toX = toX; + this.toY = toY; + } + + @Override + public String toString() { + return "ChangeInfo{" + + "oldHolder=" + oldHolder + + ", newHolder=" + newHolder + + ", fromX=" + fromX + + ", fromY=" + fromY + + ", toX=" + toX + + ", toY=" + toY + + '}'; + } + } + + @Override + public void runPendingAnimations() { + boolean removalsPending = !mPendingRemovals.isEmpty(); + boolean movesPending = !mPendingMoves.isEmpty(); + boolean changesPending = !mPendingChanges.isEmpty(); + boolean additionsPending = !mPendingAdditions.isEmpty(); + if (!removalsPending && !movesPending && !additionsPending && !changesPending) { + // nothing to animate + return; + } + // First, remove stuff + for (ViewHolder holder : mPendingRemovals) { + animateRemoveImpl(holder); + } + mPendingRemovals.clear(); + // Next, move stuff + if (movesPending) { + final ArrayList moves = new ArrayList<>(); + moves.addAll(mPendingMoves); + mMovesList.add(moves); + mPendingMoves.clear(); + Runnable mover = new Runnable() { + @Override + public void run() { + for (MoveInfo moveInfo : moves) { + animateMoveImpl(moveInfo.holder, moveInfo.fromX, moveInfo.fromY, + moveInfo.toX, moveInfo.toY); + } + moves.clear(); + mMovesList.remove(moves); + } + }; + if (removalsPending) { + View view = moves.get(0).holder.itemView; + ViewCompat.postOnAnimationDelayed(view, mover, getRemoveDuration()); + } else { + mover.run(); + } + } + // Next, change stuff, to run in parallel with move animations + if (changesPending) { + final ArrayList changes = new ArrayList<>(); + changes.addAll(mPendingChanges); + mChangesList.add(changes); + mPendingChanges.clear(); + Runnable changer = new Runnable() { + @Override + public void run() { + for (ChangeInfo change : changes) { + animateChangeImpl(change); + } + changes.clear(); + mChangesList.remove(changes); + } + }; + if (removalsPending) { + ViewHolder holder = changes.get(0).oldHolder; + ViewCompat.postOnAnimationDelayed(holder.itemView, changer, getRemoveDuration()); + } else { + changer.run(); + } + } + // Next, add stuff + if (additionsPending) { + final ArrayList additions = new ArrayList<>(); + additions.addAll(mPendingAdditions); + mAdditionsList.add(additions); + mPendingAdditions.clear(); + Runnable adder = new Runnable() { + public void run() { + for (ViewHolder holder : additions) { + animateAddImpl(holder); + } + additions.clear(); + mAdditionsList.remove(additions); + } + }; + if (removalsPending || movesPending || changesPending) { + long removeDuration = removalsPending ? getRemoveDuration() : 0; + long moveDuration = movesPending ? getMoveDuration() : 0; + long changeDuration = changesPending ? getChangeDuration() : 0; + long totalDelay = removeDuration + Math.max(moveDuration, changeDuration); + View view = additions.get(0).itemView; + ViewCompat.postOnAnimationDelayed(view, adder, totalDelay); + } else { + adder.run(); + } + } + } + + @Override + public boolean animateRemove(final ViewHolder holder) { + resetAnimation(holder); + mPendingRemovals.add(holder); + return true; + } + + private void animateRemoveImpl(final ViewHolder holder) { + final View view = holder.itemView; + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); + mRemoveAnimations.add(holder); + animation.setDuration(getRemoveDuration()) + .alpha(0).setListener(new VpaListenerAdapter() { + @Override + public void onAnimationStart(View view) { + dispatchRemoveStarting(holder); + } + + @Override + public void onAnimationEnd(View view) { + animation.setListener(null); + ViewCompat.setAlpha(view, 1); + dispatchRemoveFinished(holder); + mRemoveAnimations.remove(holder); + dispatchFinishedWhenDone(); + } + }).start(); + } + + @Override + public boolean animateAdd(final ViewHolder holder) { + resetAnimation(holder); + ViewCompat.setAlpha(holder.itemView, 0); + mPendingAdditions.add(holder); + return true; + } + + private void animateAddImpl(final ViewHolder holder) { + final View view = holder.itemView; + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); + mAddAnimations.add(holder); + animation.alpha(1).setDuration(getAddDuration()). + setListener(new VpaListenerAdapter() { + @Override + public void onAnimationStart(View view) { + dispatchAddStarting(holder); + } + @Override + public void onAnimationCancel(View view) { + ViewCompat.setAlpha(view, 1); + } + + @Override + public void onAnimationEnd(View view) { + animation.setListener(null); + dispatchAddFinished(holder); + mAddAnimations.remove(holder); + dispatchFinishedWhenDone(); + } + }).start(); + } + + @Override + public boolean animateMove(final ViewHolder holder, int fromX, int fromY, + int toX, int toY) { + final View view = holder.itemView; + fromX += ViewCompat.getTranslationX(holder.itemView); + fromY += ViewCompat.getTranslationY(holder.itemView); + resetAnimation(holder); + int deltaX = toX - fromX; + int deltaY = toY - fromY; + if (deltaX == 0 && deltaY == 0) { + dispatchMoveFinished(holder); + return false; + } + if (deltaX != 0) { + ViewCompat.setTranslationX(view, -deltaX); + } + if (deltaY != 0) { + ViewCompat.setTranslationY(view, -deltaY); + } + mPendingMoves.add(new MoveInfo(holder, fromX, fromY, toX, toY)); + return true; + } + + private void animateMoveImpl(final ViewHolder holder, int fromX, int fromY, int toX, int toY) { + final View view = holder.itemView; + final int deltaX = toX - fromX; + final int deltaY = toY - fromY; + if (deltaX != 0) { + ViewCompat.animate(view).translationX(0); + } + if (deltaY != 0) { + ViewCompat.animate(view).translationY(0); + } + // TODO: make EndActions end listeners instead, since end actions aren't called when + // vpas are canceled (and can't end them. why?) + // need listener functionality in VPACompat for this. Ick. + final ViewPropertyAnimatorCompat animation = ViewCompat.animate(view); + mMoveAnimations.add(holder); + animation.setDuration(getMoveDuration()).setListener(new VpaListenerAdapter() { + @Override + public void onAnimationStart(View view) { + dispatchMoveStarting(holder); + } + @Override + public void onAnimationCancel(View view) { + if (deltaX != 0) { + ViewCompat.setTranslationX(view, 0); + } + if (deltaY != 0) { + ViewCompat.setTranslationY(view, 0); + } + } + @Override + public void onAnimationEnd(View view) { + animation.setListener(null); + dispatchMoveFinished(holder); + mMoveAnimations.remove(holder); + dispatchFinishedWhenDone(); + } + }).start(); + } + + @Override + public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder, + int fromX, int fromY, int toX, int toY) { + if (oldHolder == newHolder) { + // Don't know how to run change animations when the same view holder is re-used. + // run a move animation to handle position changes. + return animateMove(oldHolder, fromX, fromY, toX, toY); + } + final float prevTranslationX = ViewCompat.getTranslationX(oldHolder.itemView); + final float prevTranslationY = ViewCompat.getTranslationY(oldHolder.itemView); + final float prevAlpha = ViewCompat.getAlpha(oldHolder.itemView); + resetAnimation(oldHolder); + int deltaX = (int) (toX - fromX - prevTranslationX); + int deltaY = (int) (toY - fromY - prevTranslationY); + // recover prev translation state after ending animation + ViewCompat.setTranslationX(oldHolder.itemView, prevTranslationX); + ViewCompat.setTranslationY(oldHolder.itemView, prevTranslationY); + ViewCompat.setAlpha(oldHolder.itemView, prevAlpha); + if (newHolder != null) { + // carry over translation values + resetAnimation(newHolder); + ViewCompat.setTranslationX(newHolder.itemView, -deltaX); + ViewCompat.setTranslationY(newHolder.itemView, -deltaY); + ViewCompat.setAlpha(newHolder.itemView, 0); + } + mPendingChanges.add(new ChangeInfo(oldHolder, newHolder, fromX, fromY, toX, toY)); + return true; + } + + private void animateChangeImpl(final ChangeInfo changeInfo) { + final ViewHolder holder = changeInfo.oldHolder; + final View view = holder == null ? null : holder.itemView; + final ViewHolder newHolder = changeInfo.newHolder; + final View newView = newHolder != null ? newHolder.itemView : null; + if (view != null) { + final ViewPropertyAnimatorCompat oldViewAnim = ViewCompat.animate(view).setDuration( + getChangeDuration()); + mChangeAnimations.add(changeInfo.oldHolder); + oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX); + oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY); + oldViewAnim.alpha(0).setListener(new VpaListenerAdapter() { + @Override + public void onAnimationStart(View view) { + dispatchChangeStarting(changeInfo.oldHolder, true); + } + + @Override + public void onAnimationEnd(View view) { + oldViewAnim.setListener(null); + ViewCompat.setAlpha(view, 1); + ViewCompat.setTranslationX(view, 0); + ViewCompat.setTranslationY(view, 0); + dispatchChangeFinished(changeInfo.oldHolder, true); + mChangeAnimations.remove(changeInfo.oldHolder); + dispatchFinishedWhenDone(); + } + }).start(); + } + if (newView != null) { + final ViewPropertyAnimatorCompat newViewAnimation = ViewCompat.animate(newView); + mChangeAnimations.add(changeInfo.newHolder); + newViewAnimation.translationX(0).translationY(0).setDuration(getChangeDuration()). + alpha(1).setListener(new VpaListenerAdapter() { + @Override + public void onAnimationStart(View view) { + dispatchChangeStarting(changeInfo.newHolder, false); + } + @Override + public void onAnimationEnd(View view) { + newViewAnimation.setListener(null); + ViewCompat.setAlpha(newView, 1); + ViewCompat.setTranslationX(newView, 0); + ViewCompat.setTranslationY(newView, 0); + dispatchChangeFinished(changeInfo.newHolder, false); + mChangeAnimations.remove(changeInfo.newHolder); + dispatchFinishedWhenDone(); + } + }).start(); + } + } + + private void endChangeAnimation(List infoList, ViewHolder item) { + for (int i = infoList.size() - 1; i >= 0; i--) { + ChangeInfo changeInfo = infoList.get(i); + if (endChangeAnimationIfNecessary(changeInfo, item)) { + if (changeInfo.oldHolder == null && changeInfo.newHolder == null) { + infoList.remove(changeInfo); + } + } + } + } + + private void endChangeAnimationIfNecessary(ChangeInfo changeInfo) { + if (changeInfo.oldHolder != null) { + endChangeAnimationIfNecessary(changeInfo, changeInfo.oldHolder); + } + if (changeInfo.newHolder != null) { + endChangeAnimationIfNecessary(changeInfo, changeInfo.newHolder); + } + } + private boolean endChangeAnimationIfNecessary(ChangeInfo changeInfo, ViewHolder item) { + boolean oldItem = false; + if (changeInfo.newHolder == item) { + changeInfo.newHolder = null; + } else if (changeInfo.oldHolder == item) { + changeInfo.oldHolder = null; + oldItem = true; + } else { + return false; + } + ViewCompat.setAlpha(item.itemView, 1); + ViewCompat.setTranslationX(item.itemView, 0); + ViewCompat.setTranslationY(item.itemView, 0); + dispatchChangeFinished(item, oldItem); + return true; + } + + @Override + public void endAnimation(ViewHolder item) { + final View view = item.itemView; + // this will trigger end callback which should set properties to their target values. + ViewCompat.animate(view).cancel(); + // TODO if some other animations are chained to end, how do we cancel them as well? + for (int i = mPendingMoves.size() - 1; i >= 0; i--) { + MoveInfo moveInfo = mPendingMoves.get(i); + if (moveInfo.holder == item) { + ViewCompat.setTranslationY(view, 0); + ViewCompat.setTranslationX(view, 0); + dispatchMoveFinished(item); + mPendingMoves.remove(i); + } + } + endChangeAnimation(mPendingChanges, item); + if (mPendingRemovals.remove(item)) { + ViewCompat.setAlpha(view, 1); + dispatchRemoveFinished(item); + } + if (mPendingAdditions.remove(item)) { + ViewCompat.setAlpha(view, 1); + dispatchAddFinished(item); + } + + for (int i = mChangesList.size() - 1; i >= 0; i--) { + ArrayList changes = mChangesList.get(i); + endChangeAnimation(changes, item); + if (changes.isEmpty()) { + mChangesList.remove(i); + } + } + for (int i = mMovesList.size() - 1; i >= 0; i--) { + ArrayList moves = mMovesList.get(i); + for (int j = moves.size() - 1; j >= 0; j--) { + MoveInfo moveInfo = moves.get(j); + if (moveInfo.holder == item) { + ViewCompat.setTranslationY(view, 0); + ViewCompat.setTranslationX(view, 0); + dispatchMoveFinished(item); + moves.remove(j); + if (moves.isEmpty()) { + mMovesList.remove(i); + } + break; + } + } + } + for (int i = mAdditionsList.size() - 1; i >= 0; i--) { + ArrayList additions = mAdditionsList.get(i); + if (additions.remove(item)) { + ViewCompat.setAlpha(view, 1); + dispatchAddFinished(item); + if (additions.isEmpty()) { + mAdditionsList.remove(i); + } + } + } + + // animations should be ended by the cancel above. + //noinspection PointlessBooleanExpression,ConstantConditions + if (mRemoveAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mRemoveAnimations list"); + } + + //noinspection PointlessBooleanExpression,ConstantConditions + if (mAddAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mAddAnimations list"); + } + + //noinspection PointlessBooleanExpression,ConstantConditions + if (mChangeAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mChangeAnimations list"); + } + + //noinspection PointlessBooleanExpression,ConstantConditions + if (mMoveAnimations.remove(item) && DEBUG) { + throw new IllegalStateException("after animation is cancelled, item should not be in " + + "mMoveAnimations list"); + } + dispatchFinishedWhenDone(); + } + + private void resetAnimation(ViewHolder holder) { + AnimatorCompatHelper.clearInterpolator(holder.itemView); + endAnimation(holder); + } + + @Override + public boolean isRunning() { + return (!mPendingAdditions.isEmpty() || + !mPendingChanges.isEmpty() || + !mPendingMoves.isEmpty() || + !mPendingRemovals.isEmpty() || + !mMoveAnimations.isEmpty() || + !mRemoveAnimations.isEmpty() || + !mAddAnimations.isEmpty() || + !mChangeAnimations.isEmpty() || + !mMovesList.isEmpty() || + !mAdditionsList.isEmpty() || + !mChangesList.isEmpty()); + } + + /** + * Check the state of currently pending and running animations. If there are none + * pending/running, call {@link #dispatchAnimationsFinished()} to notify any + * listeners. + */ + private void dispatchFinishedWhenDone() { + if (!isRunning()) { + dispatchAnimationsFinished(); + } + } + + @Override + public void endAnimations() { + int count = mPendingMoves.size(); + for (int i = count - 1; i >= 0; i--) { + MoveInfo item = mPendingMoves.get(i); + View view = item.holder.itemView; + ViewCompat.setTranslationY(view, 0); + ViewCompat.setTranslationX(view, 0); + dispatchMoveFinished(item.holder); + mPendingMoves.remove(i); + } + count = mPendingRemovals.size(); + for (int i = count - 1; i >= 0; i--) { + ViewHolder item = mPendingRemovals.get(i); + dispatchRemoveFinished(item); + mPendingRemovals.remove(i); + } + count = mPendingAdditions.size(); + for (int i = count - 1; i >= 0; i--) { + ViewHolder item = mPendingAdditions.get(i); + View view = item.itemView; + ViewCompat.setAlpha(view, 1); + dispatchAddFinished(item); + mPendingAdditions.remove(i); + } + count = mPendingChanges.size(); + for (int i = count - 1; i >= 0; i--) { + endChangeAnimationIfNecessary(mPendingChanges.get(i)); + } + mPendingChanges.clear(); + if (!isRunning()) { + return; + } + + int listCount = mMovesList.size(); + for (int i = listCount - 1; i >= 0; i--) { + ArrayList moves = mMovesList.get(i); + count = moves.size(); + for (int j = count - 1; j >= 0; j--) { + MoveInfo moveInfo = moves.get(j); + ViewHolder item = moveInfo.holder; + View view = item.itemView; + ViewCompat.setTranslationY(view, 0); + ViewCompat.setTranslationX(view, 0); + dispatchMoveFinished(moveInfo.holder); + moves.remove(j); + if (moves.isEmpty()) { + mMovesList.remove(moves); + } + } + } + listCount = mAdditionsList.size(); + for (int i = listCount - 1; i >= 0; i--) { + ArrayList additions = mAdditionsList.get(i); + count = additions.size(); + for (int j = count - 1; j >= 0; j--) { + ViewHolder item = additions.get(j); + View view = item.itemView; + ViewCompat.setAlpha(view, 1); + dispatchAddFinished(item); + additions.remove(j); + if (additions.isEmpty()) { + mAdditionsList.remove(additions); + } + } + } + listCount = mChangesList.size(); + for (int i = listCount - 1; i >= 0; i--) { + ArrayList changes = mChangesList.get(i); + count = changes.size(); + for (int j = count - 1; j >= 0; j--) { + endChangeAnimationIfNecessary(changes.get(j)); + if (changes.isEmpty()) { + mChangesList.remove(changes); + } + } + } + + cancelAll(mRemoveAnimations); + cancelAll(mMoveAnimations); + cancelAll(mAddAnimations); + cancelAll(mChangeAnimations); + + dispatchAnimationsFinished(); + } + + void cancelAll(List viewHolders) { + for (int i = viewHolders.size() - 1; i >= 0; i--) { + ViewCompat.animate(viewHolders.get(i).itemView).cancel(); + } + } + + /** + * {@inheritDoc} + *

+ * If the payload list is not empty, DefaultItemAnimator returns true. + * When this is the case: + *

    + *
  • If you override {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}, both + * ViewHolder arguments will be the same instance. + *
  • + *
  • + * If you are not overriding {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}, + * then DefaultItemAnimator will call {@link #animateMove(ViewHolder, int, int, int, int)} and + * run a move animation instead. + *
  • + *
+ */ + @Override + public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder, + @NonNull List payloads) { + return !payloads.isEmpty() || super.canReuseUpdatedViewHolder(viewHolder, payloads); + } + + private static class VpaListenerAdapter implements ViewPropertyAnimatorListener { + @Override + public void onAnimationStart(View view) {} + + @Override + public void onAnimationEnd(View view) {} + + @Override + public void onAnimationCancel(View view) {} + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/GridLayoutManager.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/GridLayoutManager.java new file mode 100644 index 00000000..84c3cb49 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/GridLayoutManager.java @@ -0,0 +1,1134 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific languag`e governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.support.widget; + +import android.content.Context; +import android.graphics.Rect; +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; +import android.util.AttributeSet; +import android.util.Log; +import android.util.SparseIntArray; +import android.view.View; +import android.view.ViewGroup; + +import java.util.Arrays; + +/** + * A {@link RecyclerView.LayoutManager} implementations that lays out items in a grid. + *

+ * By default, each item occupies 1 span. You can change it by providing a custom + * {@link SpanSizeLookup} instance via {@link #setSpanSizeLookup(SpanSizeLookup)}. + */ +public class GridLayoutManager extends LinearLayoutManager { + + private static final boolean DEBUG = false; + private static final String TAG = "GridLayoutManager"; + public static final int DEFAULT_SPAN_COUNT = -1; + /** + * Span size have been changed but we've not done a new layout calculation. + */ + boolean mPendingSpanCountChange = false; + int mSpanCount = DEFAULT_SPAN_COUNT; + /** + * Right borders for each span. + *

For i-th item start is {@link #mCachedBorders}[i-1] + 1 + * and end is {@link #mCachedBorders}[i]. + */ + int [] mCachedBorders; + /** + * Temporary array to keep views in layoutChunk method + */ + View[] mSet; + final SparseIntArray mPreLayoutSpanSizeCache = new SparseIntArray(); + final SparseIntArray mPreLayoutSpanIndexCache = new SparseIntArray(); + SpanSizeLookup mSpanSizeLookup = new DefaultSpanSizeLookup(); + // re-used variable to acquire decor insets from RecyclerView + final Rect mDecorInsets = new Rect(); + + + /** + * Constructor used when layout manager is set in XML by RecyclerView attribute + * "layoutManager". If spanCount is not specified in the XML, it defaults to a + * single column. + * + * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_spanCount + */ + public GridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + Properties properties = getProperties(context, attrs, defStyleAttr, defStyleRes); + setSpanCount(properties.spanCount); + } + + /** + * Creates a vertical GridLayoutManager + * + * @param context Current context, will be used to access resources. + * @param spanCount The number of columns in the grid + */ + public GridLayoutManager(Context context, int spanCount) { + super(context); + setSpanCount(spanCount); + } + + /** + * @param context Current context, will be used to access resources. + * @param spanCount The number of columns or rows in the grid + * @param orientation Layout orientation. Should be {@link #HORIZONTAL} or {@link + * #VERTICAL}. + * @param reverseLayout When set to true, layouts from end to start. + */ + public GridLayoutManager(Context context, int spanCount, int orientation, + boolean reverseLayout) { + super(context, orientation, reverseLayout); + setSpanCount(spanCount); + } + + /** + * stackFromEnd is not supported by GridLayoutManager. Consider using + * {@link #setReverseLayout(boolean)}. + */ + @Override + public void setStackFromEnd(boolean stackFromEnd) { + if (stackFromEnd) { + throw new UnsupportedOperationException( + "GridLayoutManager does not support stack from end." + + " Consider using reverse layout"); + } + super.setStackFromEnd(false); + } + + @Override + public int getRowCountForAccessibility(RecyclerView.Recycler recycler, + RecyclerView.State state) { + if (mOrientation == HORIZONTAL) { + return mSpanCount; + } + if (state.getItemCount() < 1) { + return 0; + } + + // Row count is one more than the last item's row index. + return getSpanGroupIndex(recycler, state, state.getItemCount() - 1) + 1; + } + + @Override + public int getColumnCountForAccessibility(RecyclerView.Recycler recycler, + RecyclerView.State state) { + if (mOrientation == VERTICAL) { + return mSpanCount; + } + if (state.getItemCount() < 1) { + return 0; + } + + // Column count is one more than the last item's column index. + return getSpanGroupIndex(recycler, state, state.getItemCount() - 1) + 1; + } + + @Override + public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler, + RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) { + ViewGroup.LayoutParams lp = host.getLayoutParams(); + if (!(lp instanceof LayoutParams)) { + super.onInitializeAccessibilityNodeInfoForItem(host, info); + return; + } + LayoutParams glp = (LayoutParams) lp; + int spanGroupIndex = getSpanGroupIndex(recycler, state, glp.getViewLayoutPosition()); + if (mOrientation == HORIZONTAL) { + info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain( + glp.getSpanIndex(), glp.getSpanSize(), + spanGroupIndex, 1, + mSpanCount > 1 && glp.getSpanSize() == mSpanCount, false)); + } else { // VERTICAL + info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain( + spanGroupIndex , 1, + glp.getSpanIndex(), glp.getSpanSize(), + mSpanCount > 1 && glp.getSpanSize() == mSpanCount, false)); + } + } + + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + if (state.isPreLayout()) { + cachePreLayoutSpanMapping(); + } + super.onLayoutChildren(recycler, state); + if (DEBUG) { + validateChildOrder(); + } + clearPreLayoutSpanMappingCache(); + if (!state.isPreLayout()) { + mPendingSpanCountChange = false; + } + } + + private void clearPreLayoutSpanMappingCache() { + mPreLayoutSpanSizeCache.clear(); + mPreLayoutSpanIndexCache.clear(); + } + + private void cachePreLayoutSpanMapping() { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams(); + final int viewPosition = lp.getViewLayoutPosition(); + mPreLayoutSpanSizeCache.put(viewPosition, lp.getSpanSize()); + mPreLayoutSpanIndexCache.put(viewPosition, lp.getSpanIndex()); + } + } + + @Override + public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) { + mSpanSizeLookup.invalidateSpanIndexCache(); + } + + @Override + public void onItemsChanged(RecyclerView recyclerView) { + mSpanSizeLookup.invalidateSpanIndexCache(); + } + + @Override + public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) { + mSpanSizeLookup.invalidateSpanIndexCache(); + } + + @Override + public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount, + Object payload) { + mSpanSizeLookup.invalidateSpanIndexCache(); + } + + @Override + public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) { + mSpanSizeLookup.invalidateSpanIndexCache(); + } + + @Override + public RecyclerView.LayoutParams generateDefaultLayoutParams() { + if (mOrientation == HORIZONTAL) { + return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.FILL_PARENT); + } else { + return new LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + } + } + + @Override + public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) { + return new LayoutParams(c, attrs); + } + + @Override + public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { + if (lp instanceof ViewGroup.MarginLayoutParams) { + return new LayoutParams((ViewGroup.MarginLayoutParams) lp); + } else { + return new LayoutParams(lp); + } + } + + @Override + public boolean checkLayoutParams(RecyclerView.LayoutParams lp) { + return lp instanceof LayoutParams; + } + + /** + * Sets the source to get the number of spans occupied by each item in the adapter. + * + * @param spanSizeLookup {@link SpanSizeLookup} instance to be used to query number of spans + * occupied by each item + */ + public void setSpanSizeLookup(SpanSizeLookup spanSizeLookup) { + mSpanSizeLookup = spanSizeLookup; + } + + /** + * Returns the current {@link SpanSizeLookup} used by the GridLayoutManager. + * + * @return The current {@link SpanSizeLookup} used by the GridLayoutManager. + */ + public SpanSizeLookup getSpanSizeLookup() { + return mSpanSizeLookup; + } + + private void updateMeasurements() { + int totalSpace; + if (getOrientation() == VERTICAL) { + totalSpace = getWidth() - getPaddingRight() - getPaddingLeft(); + } else { + totalSpace = getHeight() - getPaddingBottom() - getPaddingTop(); + } + calculateItemBorders(totalSpace); + } + + @Override + public void setMeasuredDimension(Rect childrenBounds, int wSpec, int hSpec) { + if (mCachedBorders == null) { + super.setMeasuredDimension(childrenBounds, wSpec, hSpec); + } + final int width, height; + final int horizontalPadding = getPaddingLeft() + getPaddingRight(); + final int verticalPadding = getPaddingTop() + getPaddingBottom(); + if (mOrientation == VERTICAL) { + final int usedHeight = childrenBounds.height() + verticalPadding; + height = chooseSize(hSpec, usedHeight, getMinimumHeight()); + width = chooseSize(wSpec, mCachedBorders[mCachedBorders.length - 1] + horizontalPadding, + getMinimumWidth()); + } else { + final int usedWidth = childrenBounds.width() + horizontalPadding; + width = chooseSize(wSpec, usedWidth, getMinimumWidth()); + height = chooseSize(hSpec, mCachedBorders[mCachedBorders.length - 1] + verticalPadding, + getMinimumHeight()); + } + setMeasuredDimension(width, height); + } + + /** + * @param totalSpace Total available space after padding is removed + */ + private void calculateItemBorders(int totalSpace) { + mCachedBorders = calculateItemBorders(mCachedBorders, mSpanCount, totalSpace); + } + + /** + * @param cachedBorders The out array + * @param spanCount number of spans + * @param totalSpace total available space after padding is removed + * @return The updated array. Might be the same instance as the provided array if its size + * has not changed. + */ + static int[] calculateItemBorders(int[] cachedBorders, int spanCount, int totalSpace) { + if (cachedBorders == null || cachedBorders.length != spanCount + 1 + || cachedBorders[cachedBorders.length - 1] != totalSpace) { + cachedBorders = new int[spanCount + 1]; + } + cachedBorders[0] = 0; + int sizePerSpan = totalSpace / spanCount; + int sizePerSpanRemainder = totalSpace % spanCount; + int consumedPixels = 0; + int additionalSize = 0; + for (int i = 1; i <= spanCount; i++) { + int itemSize = sizePerSpan; + additionalSize += sizePerSpanRemainder; + if (additionalSize > 0 && (spanCount - additionalSize) < sizePerSpanRemainder) { + itemSize += 1; + additionalSize -= spanCount; + } + consumedPixels += itemSize; + cachedBorders[i] = consumedPixels; + } + return cachedBorders; + } + + @Override + void onAnchorReady(RecyclerView.Recycler recycler, RecyclerView.State state, + AnchorInfo anchorInfo, int itemDirection) { + super.onAnchorReady(recycler, state, anchorInfo, itemDirection); + updateMeasurements(); + if (state.getItemCount() > 0 && !state.isPreLayout()) { + ensureAnchorIsInCorrectSpan(recycler, state, anchorInfo, itemDirection); + } + ensureViewSet(); + } + + private void ensureViewSet() { + if (mSet == null || mSet.length != mSpanCount) { + mSet = new View[mSpanCount]; + } + } + + @Override + public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, + RecyclerView.State state) { + updateMeasurements(); + ensureViewSet(); + return super.scrollHorizontallyBy(dx, recycler, state); + } + + @Override + public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, + RecyclerView.State state) { + updateMeasurements(); + ensureViewSet(); + return super.scrollVerticallyBy(dy, recycler, state); + } + + private void ensureAnchorIsInCorrectSpan(RecyclerView.Recycler recycler, + RecyclerView.State state, AnchorInfo anchorInfo, int itemDirection) { + final boolean layingOutInPrimaryDirection = + itemDirection == LayoutState.ITEM_DIRECTION_TAIL; + int span = getSpanIndex(recycler, state, anchorInfo.mPosition); + if (layingOutInPrimaryDirection) { + // choose span 0 + while (span > 0 && anchorInfo.mPosition > 0) { + anchorInfo.mPosition--; + span = getSpanIndex(recycler, state, anchorInfo.mPosition); + } + } else { + // choose the max span we can get. hopefully last one + final int indexLimit = state.getItemCount() - 1; + int pos = anchorInfo.mPosition; + int bestSpan = span; + while (pos < indexLimit) { + int next = getSpanIndex(recycler, state, pos + 1); + if (next > bestSpan) { + pos += 1; + bestSpan = next; + } else { + break; + } + } + anchorInfo.mPosition = pos; + } + } + + @Override + View findReferenceChild(RecyclerView.Recycler recycler, RecyclerView.State state, + int start, int end, int itemCount) { + ensureLayoutState(); + View invalidMatch = null; + View outOfBoundsMatch = null; + final int boundsStart = mOrientationHelper.getStartAfterPadding(); + final int boundsEnd = mOrientationHelper.getEndAfterPadding(); + final int diff = end > start ? 1 : -1; + for (int i = start; i != end; i += diff) { + final View view = getChildAt(i); + final int position = getPosition(view); + if (position >= 0 && position < itemCount) { + final int span = getSpanIndex(recycler, state, position); + if (span != 0) { + continue; + } + if (((RecyclerView.LayoutParams) view.getLayoutParams()).isItemRemoved()) { + if (invalidMatch == null) { + invalidMatch = view; // removed item, least preferred + } + } else if (mOrientationHelper.getDecoratedStart(view) >= boundsEnd || + mOrientationHelper.getDecoratedEnd(view) < boundsStart) { + if (outOfBoundsMatch == null) { + outOfBoundsMatch = view; // item is not visible, less preferred + } + } else { + return view; + } + } + } + return outOfBoundsMatch != null ? outOfBoundsMatch : invalidMatch; + } + + private int getSpanGroupIndex(RecyclerView.Recycler recycler, RecyclerView.State state, + int viewPosition) { + if (!state.isPreLayout()) { + return mSpanSizeLookup.getSpanGroupIndex(viewPosition, mSpanCount); + } + final int adapterPosition = recycler.convertPreLayoutPositionToPostLayout(viewPosition); + if (adapterPosition == -1) { + if (DEBUG) { + throw new RuntimeException("Cannot find span group index for position " + + viewPosition); + } + Log.w(TAG, "Cannot find span size for pre layout position. " + viewPosition); + return 0; + } + return mSpanSizeLookup.getSpanGroupIndex(adapterPosition, mSpanCount); + } + + private int getSpanIndex(RecyclerView.Recycler recycler, RecyclerView.State state, int pos) { + if (!state.isPreLayout()) { + return mSpanSizeLookup.getCachedSpanIndex(pos, mSpanCount); + } + final int cached = mPreLayoutSpanIndexCache.get(pos, -1); + if (cached != -1) { + return cached; + } + final int adapterPosition = recycler.convertPreLayoutPositionToPostLayout(pos); + if (adapterPosition == -1) { + if (DEBUG) { + throw new RuntimeException("Cannot find span index for pre layout position. It is" + + " not cached, not in the adapter. Pos:" + pos); + } + Log.w(TAG, "Cannot find span size for pre layout position. It is" + + " not cached, not in the adapter. Pos:" + pos); + return 0; + } + return mSpanSizeLookup.getCachedSpanIndex(adapterPosition, mSpanCount); + } + + private int getSpanSize(RecyclerView.Recycler recycler, RecyclerView.State state, int pos) { + if (!state.isPreLayout()) { + return mSpanSizeLookup.getSpanSize(pos); + } + final int cached = mPreLayoutSpanSizeCache.get(pos, -1); + if (cached != -1) { + return cached; + } + final int adapterPosition = recycler.convertPreLayoutPositionToPostLayout(pos); + if (adapterPosition == -1) { + if (DEBUG) { + throw new RuntimeException("Cannot find span size for pre layout position. It is" + + " not cached, not in the adapter. Pos:" + pos); + } + Log.w(TAG, "Cannot find span size for pre layout position. It is" + + " not cached, not in the adapter. Pos:" + pos); + return 1; + } + return mSpanSizeLookup.getSpanSize(adapterPosition); + } + + @Override + void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state, + LayoutState layoutState, LayoutChunkResult result) { + final int otherDirSpecMode = mOrientationHelper.getModeInOther(); + final boolean flexibleInOtherDir = otherDirSpecMode != View.MeasureSpec.EXACTLY; + final int currentOtherDirSize = getChildCount() > 0 ? mCachedBorders[mSpanCount] : 0; + // if grid layout's dimensions are not specified, let the new row change the measurements + // This is not perfect since we not covering all rows but still solves an important case + // where they may have a header row which should be laid out according to children. + if (flexibleInOtherDir) { + updateMeasurements(); // reset measurements + } + final boolean layingOutInPrimaryDirection = + layoutState.mItemDirection == LayoutState.ITEM_DIRECTION_TAIL; + int count = 0; + int consumedSpanCount = 0; + int remainingSpan = mSpanCount; + if (!layingOutInPrimaryDirection) { + int itemSpanIndex = getSpanIndex(recycler, state, layoutState.mCurrentPosition); + int itemSpanSize = getSpanSize(recycler, state, layoutState.mCurrentPosition); + remainingSpan = itemSpanIndex + itemSpanSize; + } + while (count < mSpanCount && layoutState.hasMore(state) && remainingSpan > 0) { + int pos = layoutState.mCurrentPosition; + final int spanSize = getSpanSize(recycler, state, pos); + if (spanSize > mSpanCount) { + throw new IllegalArgumentException("Item at position " + pos + " requires " + + spanSize + " spans but GridLayoutManager has only " + mSpanCount + + " spans."); + } + remainingSpan -= spanSize; + if (remainingSpan < 0) { + break; // item did not fit into this row or column + } + View view = layoutState.next(recycler); + if (view == null) { + break; + } + consumedSpanCount += spanSize; + mSet[count] = view; + count++; + } + + if (count == 0) { + result.mFinished = true; + return; + } + + int maxSize = 0; + float maxSizeInOther = 0; // use a float to get size per span + + // we should assign spans before item decor offsets are calculated + assignSpans(recycler, state, count, consumedSpanCount, layingOutInPrimaryDirection); + for (int i = 0; i < count; i++) { + View view = mSet[i]; + if (layoutState.mScrapList == null) { + if (layingOutInPrimaryDirection) { + addView(view); + } else { + addView(view, 0); + } + } else { + if (layingOutInPrimaryDirection) { + addDisappearingView(view); + } else { + addDisappearingView(view, 0); + } + } + + final LayoutParams lp = (LayoutParams) view.getLayoutParams(); + final int spec = getChildMeasureSpec(mCachedBorders[lp.mSpanIndex + lp.mSpanSize] - + mCachedBorders[lp.mSpanIndex], otherDirSpecMode, 0, + mOrientation == HORIZONTAL ? lp.height : lp.width, + false); + final int mainSpec = getChildMeasureSpec(mOrientationHelper.getTotalSpace(), + mOrientationHelper.getMode(), 0, + mOrientation == VERTICAL ? lp.height : lp.width, true); + // Unless the child has MATCH_PARENT, measure it from its specs before adding insets. + if (mOrientation == VERTICAL) { + @SuppressWarnings("deprecation") + final boolean applyInsets = lp.height == ViewGroup.LayoutParams.FILL_PARENT; + measureChildWithDecorationsAndMargin(view, spec, mainSpec, applyInsets, false); + } else { + //noinspection deprecation + final boolean applyInsets = lp.width == ViewGroup.LayoutParams.FILL_PARENT; + measureChildWithDecorationsAndMargin(view, mainSpec, spec, applyInsets, false); + } + final int size = mOrientationHelper.getDecoratedMeasurement(view); + if (size > maxSize) { + maxSize = size; + } + final float otherSize = 1f * mOrientationHelper.getDecoratedMeasurementInOther(view) / + lp.mSpanSize; + if (otherSize > maxSizeInOther) { + maxSizeInOther = otherSize; + } + } + if (flexibleInOtherDir) { + // re-distribute columns + guessMeasurement(maxSizeInOther, currentOtherDirSize); + // now we should re-measure any item that was match parent. + maxSize = 0; + for (int i = 0; i < count; i++) { + View view = mSet[i]; + final LayoutParams lp = (LayoutParams) view.getLayoutParams(); + final int spec = getChildMeasureSpec(mCachedBorders[lp.mSpanIndex + lp.mSpanSize] - + mCachedBorders[lp.mSpanIndex], View.MeasureSpec.EXACTLY, 0, + mOrientation == HORIZONTAL ? lp.height : lp.width, false); + final int mainSpec = getChildMeasureSpec(mOrientationHelper.getTotalSpace(), + mOrientationHelper.getMode(), 0, + mOrientation == VERTICAL ? lp.height : lp.width, true); + if (mOrientation == VERTICAL) { + measureChildWithDecorationsAndMargin(view, spec, mainSpec, false, true); + } else { + measureChildWithDecorationsAndMargin(view, mainSpec, spec, false, true); + } + final int size = mOrientationHelper.getDecoratedMeasurement(view); + if (size > maxSize) { + maxSize = size; + } + } + } + // Views that did not measure the maxSize has to be re-measured + // We will stop doing this once we introduce Gravity in the GLM layout params + final int maxMeasureSpec = View.MeasureSpec.makeMeasureSpec(maxSize, + View.MeasureSpec.EXACTLY); + for (int i = 0; i < count; i ++) { + final View view = mSet[i]; + if (mOrientationHelper.getDecoratedMeasurement(view) != maxSize) { + final LayoutParams lp = (LayoutParams) view.getLayoutParams(); + final int spec = getChildMeasureSpec(mCachedBorders[lp.mSpanIndex + lp.mSpanSize] + - mCachedBorders[lp.mSpanIndex], View.MeasureSpec.EXACTLY, 0, + mOrientation == HORIZONTAL ? lp.height : lp.width, false); + if (mOrientation == VERTICAL) { + measureChildWithDecorationsAndMargin(view, spec, maxMeasureSpec, true, true); + } else { + measureChildWithDecorationsAndMargin(view, maxMeasureSpec, spec, true, true); + } + } + } + + result.mConsumed = maxSize; + + int left = 0, right = 0, top = 0, bottom = 0; + if (mOrientation == VERTICAL) { + if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) { + bottom = layoutState.mOffset; + top = bottom - maxSize; + } else { + top = layoutState.mOffset; + bottom = top + maxSize; + } + } else { + if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) { + right = layoutState.mOffset; + left = right - maxSize; + } else { + left = layoutState.mOffset; + right = left + maxSize; + } + } + for (int i = 0; i < count; i++) { + View view = mSet[i]; + LayoutParams params = (LayoutParams) view.getLayoutParams(); + if (mOrientation == VERTICAL) { + if (isLayoutRTL()) { + right = getPaddingLeft() + mCachedBorders[params.mSpanIndex + params.mSpanSize]; + left = right - mOrientationHelper.getDecoratedMeasurementInOther(view); + } else { + left = getPaddingLeft() + mCachedBorders[params.mSpanIndex]; + right = left + mOrientationHelper.getDecoratedMeasurementInOther(view); + } + } else { + top = getPaddingTop() + mCachedBorders[params.mSpanIndex]; + bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view); + } + // We calculate everything with View's bounding box (which includes decor and margins) + // To calculate correct layout position, we subtract margins. + layoutDecorated(view, left + params.leftMargin, top + params.topMargin, + right - params.rightMargin, bottom - params.bottomMargin); + if (DEBUG) { + Log.d(TAG, "laid out child at position " + getPosition(view) + ", with l:" + + (left + params.leftMargin) + ", t:" + (top + params.topMargin) + ", r:" + + (right - params.rightMargin) + ", b:" + (bottom - params.bottomMargin) + + ", span:" + params.mSpanIndex + ", spanSize:" + params.mSpanSize); + } + // Consume the available space if the view is not removed OR changed + if (params.isItemRemoved() || params.isItemChanged()) { + result.mIgnoreConsumed = true; + } + result.mFocusable |= view.isFocusable(); + } + Arrays.fill(mSet, null); + } + + /** + * This is called after laying out a row (if vertical) or a column (if horizontal) when the + * RecyclerView does not have exact measurement specs. + *

+ * Here we try to assign a best guess width or height and re-do the layout to update other + * views that wanted to FILL_PARENT in the non-scroll orientation. + * + * @param maxSizeInOther The maximum size per span ratio from the measurement of the children. + * @param currentOtherDirSize The size before this layout chunk. There is no reason to go below. + */ + private void guessMeasurement(float maxSizeInOther, int currentOtherDirSize) { + final int contentSize = Math.round(maxSizeInOther * mSpanCount); + // always re-calculate because borders were stretched during the fill + calculateItemBorders(Math.max(contentSize, currentOtherDirSize)); + } + + private void measureChildWithDecorationsAndMargin(View child, int widthSpec, int heightSpec, + boolean capBothSpecs, boolean alreadyMeasured) { + calculateItemDecorationsForChild(child, mDecorInsets); + RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams(); + if (capBothSpecs || mOrientation == VERTICAL) { + widthSpec = updateSpecWithExtra(widthSpec, lp.leftMargin + mDecorInsets.left, + lp.rightMargin + mDecorInsets.right); + } + if (capBothSpecs || mOrientation == HORIZONTAL) { + heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + mDecorInsets.top, + lp.bottomMargin + mDecorInsets.bottom); + } + final boolean measure; + if (alreadyMeasured) { + measure = shouldReMeasureChild(child, widthSpec, heightSpec, lp); + } else { + measure = shouldMeasureChild(child, widthSpec, heightSpec, lp); + } + if (measure) { + child.measure(widthSpec, heightSpec); + } + + } + + private int updateSpecWithExtra(int spec, int startInset, int endInset) { + if (startInset == 0 && endInset == 0) { + return spec; + } + final int mode = View.MeasureSpec.getMode(spec); + if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) { + return View.MeasureSpec.makeMeasureSpec( + Math.max(0, View.MeasureSpec.getSize(spec) - startInset - endInset), mode); + } + return spec; + } + + private void assignSpans(RecyclerView.Recycler recycler, RecyclerView.State state, int count, + int consumedSpanCount, boolean layingOutInPrimaryDirection) { + int span, spanDiff, start, end, diff; + // make sure we traverse from min position to max position + if (layingOutInPrimaryDirection) { + start = 0; + end = count; + diff = 1; + } else { + start = count - 1; + end = -1; + diff = -1; + } + if (mOrientation == VERTICAL && isLayoutRTL()) { // start from last span + span = mSpanCount - 1; + spanDiff = -1; + } else { + span = 0; + spanDiff = 1; + } + for (int i = start; i != end; i += diff) { + View view = mSet[i]; + LayoutParams params = (LayoutParams) view.getLayoutParams(); + params.mSpanSize = getSpanSize(recycler, state, getPosition(view)); + if (spanDiff == -1 && params.mSpanSize > 1) { + params.mSpanIndex = span - (params.mSpanSize - 1); + } else { + params.mSpanIndex = span; + } + span += spanDiff * params.mSpanSize; + } + } + + /** + * Returns the number of spans laid out by this grid. + * + * @return The number of spans + * @see #setSpanCount(int) + */ + public int getSpanCount() { + return mSpanCount; + } + + /** + * Sets the number of spans to be laid out. + *

+ * If {@link #getOrientation()} is {@link #VERTICAL}, this is the number of columns. + * If {@link #getOrientation()} is {@link #HORIZONTAL}, this is the number of rows. + * + * @param spanCount The total number of spans in the grid + * @see #getSpanCount() + */ + public void setSpanCount(int spanCount) { + if (spanCount == mSpanCount) { + return; + } + mPendingSpanCountChange = true; + if (spanCount < 1) { + throw new IllegalArgumentException("Span count should be at least 1. Provided " + + spanCount); + } + mSpanCount = spanCount; + mSpanSizeLookup.invalidateSpanIndexCache(); + } + + /** + * A helper class to provide the number of spans each item occupies. + *

+ * Default implementation sets each item to occupy exactly 1 span. + * + * @see GridLayoutManager#setSpanSizeLookup(SpanSizeLookup) + */ + public static abstract class SpanSizeLookup { + + final SparseIntArray mSpanIndexCache = new SparseIntArray(); + + private boolean mCacheSpanIndices = false; + + /** + * Returns the number of span occupied by the item at position. + * + * @param position The adapter position of the item + * @return The number of spans occupied by the item at the provided position + */ + abstract public int getSpanSize(int position); + + /** + * Sets whether the results of {@link #getSpanIndex(int, int)} method should be cached or + * not. By default these values are not cached. If you are not overriding + * {@link #getSpanIndex(int, int)}, you should set this to true for better performance. + * + * @param cacheSpanIndices Whether results of getSpanIndex should be cached or not. + */ + public void setSpanIndexCacheEnabled(boolean cacheSpanIndices) { + mCacheSpanIndices = cacheSpanIndices; + } + + /** + * Clears the span index cache. GridLayoutManager automatically calls this method when + * adapter changes occur. + */ + public void invalidateSpanIndexCache() { + mSpanIndexCache.clear(); + } + + /** + * Returns whether results of {@link #getSpanIndex(int, int)} method are cached or not. + * + * @return True if results of {@link #getSpanIndex(int, int)} are cached. + */ + public boolean isSpanIndexCacheEnabled() { + return mCacheSpanIndices; + } + + int getCachedSpanIndex(int position, int spanCount) { + if (!mCacheSpanIndices) { + return getSpanIndex(position, spanCount); + } + final int existing = mSpanIndexCache.get(position, -1); + if (existing != -1) { + return existing; + } + final int value = getSpanIndex(position, spanCount); + mSpanIndexCache.put(position, value); + return value; + } + + /** + * Returns the final span index of the provided position. + *

+ * If you have a faster way to calculate span index for your items, you should override + * this method. Otherwise, you should enable span index cache + * ({@link #setSpanIndexCacheEnabled(boolean)}) for better performance. When caching is + * disabled, default implementation traverses all items from 0 to + * position. When caching is enabled, it calculates from the closest cached + * value before the position. + *

+ * If you override this method, you need to make sure it is consistent with + * {@link #getSpanSize(int)}. GridLayoutManager does not call this method for + * each item. It is called only for the reference item and rest of the items + * are assigned to spans based on the reference item. For example, you cannot assign a + * position to span 2 while span 1 is empty. + *

+ * Note that span offsets always start with 0 and are not affected by RTL. + * + * @param position The position of the item + * @param spanCount The total number of spans in the grid + * @return The final span position of the item. Should be between 0 (inclusive) and + * spanCount(exclusive) + */ + public int getSpanIndex(int position, int spanCount) { + int positionSpanSize = getSpanSize(position); + if (positionSpanSize == spanCount) { + return 0; // quick return for full-span items + } + int span = 0; + int startPos = 0; + // If caching is enabled, try to jump + if (mCacheSpanIndices && mSpanIndexCache.size() > 0) { + int prevKey = findReferenceIndexFromCache(position); + if (prevKey >= 0) { + span = mSpanIndexCache.get(prevKey) + getSpanSize(prevKey); + startPos = prevKey + 1; + } + } + for (int i = startPos; i < position; i++) { + int size = getSpanSize(i); + span += size; + if (span == spanCount) { + span = 0; + } else if (span > spanCount) { + // did not fit, moving to next row / column + span = size; + } + } + if (span + positionSpanSize <= spanCount) { + return span; + } + return 0; + } + + int findReferenceIndexFromCache(int position) { + int lo = 0; + int hi = mSpanIndexCache.size() - 1; + + while (lo <= hi) { + final int mid = (lo + hi) >>> 1; + final int midVal = mSpanIndexCache.keyAt(mid); + if (midVal < position) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + int index = lo - 1; + if (index >= 0 && index < mSpanIndexCache.size()) { + return mSpanIndexCache.keyAt(index); + } + return -1; + } + + /** + * Returns the index of the group this position belongs. + *

+ * For example, if grid has 3 columns and each item occupies 1 span, span group index + * for item 1 will be 0, item 5 will be 1. + * + * @param adapterPosition The position in adapter + * @param spanCount The total number of spans in the grid + * @return The index of the span group including the item at the given adapter position + */ + public int getSpanGroupIndex(int adapterPosition, int spanCount) { + int span = 0; + int group = 0; + int positionSpanSize = getSpanSize(adapterPosition); + for (int i = 0; i < adapterPosition; i++) { + int size = getSpanSize(i); + span += size; + if (span == spanCount) { + span = 0; + group++; + } else if (span > spanCount) { + // did not fit, moving to next row / column + span = size; + group++; + } + } + if (span + positionSpanSize > spanCount) { + group++; + } + return group; + } + } + + @Override + public View onFocusSearchFailed(View focused, int focusDirection, + RecyclerView.Recycler recycler, RecyclerView.State state) { + View prevFocusedChild = findContainingItemView(focused); + if (prevFocusedChild == null) { + return null; + } + LayoutParams lp = (LayoutParams) prevFocusedChild.getLayoutParams(); + final int prevSpanStart = lp.mSpanIndex; + final int prevSpanEnd = lp.mSpanIndex + lp.mSpanSize; + View view = super.onFocusSearchFailed(focused, focusDirection, recycler, state); + if (view == null) { + return null; + } + // LinearLayoutManager finds the last child. What we want is the child which has the same + // spanIndex. + final int layoutDir = convertFocusDirectionToLayoutDirection(focusDirection); + final boolean ascend = (layoutDir == LayoutState.LAYOUT_END) != mShouldReverseLayout; + final int start, inc, limit; + if (ascend) { + start = getChildCount() - 1; + inc = -1; + limit = -1; + } else { + start = 0; + inc = 1; + limit = getChildCount(); + } + final boolean preferLastSpan = mOrientation == VERTICAL && isLayoutRTL(); + View weakCandidate = null; // somewhat matches but not strong + int weakCandidateSpanIndex = -1; + int weakCandidateOverlap = 0; // how many spans overlap + + for (int i = start; i != limit; i += inc) { + View candidate = getChildAt(i); + if (candidate == prevFocusedChild) { + break; + } + if (!candidate.isFocusable()) { + continue; + } + final LayoutParams candidateLp = (LayoutParams) candidate.getLayoutParams(); + final int candidateStart = candidateLp.mSpanIndex; + final int candidateEnd = candidateLp.mSpanIndex + candidateLp.mSpanSize; + if (candidateStart == prevSpanStart && candidateEnd == prevSpanEnd) { + return candidate; // perfect match + } + boolean assignAsWeek = false; + if (weakCandidate == null) { + assignAsWeek = true; + } else { + int maxStart = Math.max(candidateStart, prevSpanStart); + int minEnd = Math.min(candidateEnd, prevSpanEnd); + int overlap = minEnd - maxStart; + if (overlap > weakCandidateOverlap) { + assignAsWeek = true; + } else if (overlap == weakCandidateOverlap && + preferLastSpan == (candidateStart > weakCandidateSpanIndex)) { + assignAsWeek = true; + } + } + + if (assignAsWeek) { + weakCandidate = candidate; + weakCandidateSpanIndex = candidateLp.mSpanIndex; + weakCandidateOverlap = Math.min(candidateEnd, prevSpanEnd) - + Math.max(candidateStart, prevSpanStart); + } + } + return weakCandidate; + } + + @Override + public boolean supportsPredictiveItemAnimations() { + return mPendingSavedState == null && !mPendingSpanCountChange; + } + + /** + * Default implementation for {@link SpanSizeLookup}. Each item occupies 1 span. + */ + public static final class DefaultSpanSizeLookup extends SpanSizeLookup { + + @Override + public int getSpanSize(int position) { + return 1; + } + + @Override + public int getSpanIndex(int position, int spanCount) { + return position % spanCount; + } + } + + /** + * LayoutParams used by GridLayoutManager. + *

+ * Note that if the orientation is {@link #VERTICAL}, the width parameter is ignored and if the + * orientation is {@link #HORIZONTAL} the height parameter is ignored because child view is + * expected to fill all of the space given to it. + */ + public static class LayoutParams extends RecyclerView.LayoutParams { + + /** + * Span Id for Views that are not laid out yet. + */ + public static final int INVALID_SPAN_ID = -1; + + private int mSpanIndex = INVALID_SPAN_ID; + + private int mSpanSize = 0; + + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + } + + public LayoutParams(int width, int height) { + super(width, height); + } + + public LayoutParams(ViewGroup.MarginLayoutParams source) { + super(source); + } + + public LayoutParams(ViewGroup.LayoutParams source) { + super(source); + } + + public LayoutParams(RecyclerView.LayoutParams source) { + super(source); + } + + /** + * Returns the current span index of this View. If the View is not laid out yet, the return + * value is undefined. + *

+ * Note that span index may change by whether the RecyclerView is RTL or not. For + * example, if the number of spans is 3 and layout is RTL, the rightmost item will have + * span index of 2. If the layout changes back to LTR, span index for this view will be 0. + * If the item was occupying 2 spans, span indices would be 1 and 0 respectively. + *

+ * If the View occupies multiple spans, span with the minimum index is returned. + * + * @return The span index of the View. + */ + public int getSpanIndex() { + return mSpanIndex; + } + + /** + * Returns the number of spans occupied by this View. If the View not laid out yet, the + * return value is undefined. + * + * @return The number of spans occupied by this View. + */ + public int getSpanSize() { + return mSpanSize; + } + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/LayoutState.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/LayoutState.java new file mode 100644 index 00000000..9ee6745e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/LayoutState.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific languag`e governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.widget; + +import android.view.View; + +/** + * Helper class that keeps temporary state while {LayoutManager} is filling out the empty + * space. + */ +class LayoutState { + + final static String TAG = "LayoutState"; + + final static int LAYOUT_START = -1; + + final static int LAYOUT_END = 1; + + final static int INVALID_LAYOUT = Integer.MIN_VALUE; + + final static int ITEM_DIRECTION_HEAD = -1; + + final static int ITEM_DIRECTION_TAIL = 1; + + /** + * We may not want to recycle children in some cases (e.g. layout) + */ + boolean mRecycle = true; + + /** + * Number of pixels that we should fill, in the layout direction. + */ + int mAvailable; + + /** + * Current position on the adapter to get the next item. + */ + int mCurrentPosition; + + /** + * Defines the direction in which the data adapter is traversed. + * Should be {@link #ITEM_DIRECTION_HEAD} or {@link #ITEM_DIRECTION_TAIL} + */ + int mItemDirection; + + /** + * Defines the direction in which the layout is filled. + * Should be {@link #LAYOUT_START} or {@link #LAYOUT_END} + */ + int mLayoutDirection; + + /** + * This is the target pixel closest to the start of the layout that we are trying to fill + */ + int mStartLine = 0; + + /** + * This is the target pixel closest to the end of the layout that we are trying to fill + */ + int mEndLine = 0; + + /** + * If true, layout should stop if a focusable view is added + */ + boolean mStopInFocusable; + + /** + * If the content is not wrapped with any value + */ + boolean mInfinite; + + /** + * @return true if there are more items in the data adapter + */ + boolean hasMore(RecyclerView.State state) { + return mCurrentPosition >= 0 && mCurrentPosition < state.getItemCount(); + } + + /** + * Gets the view for the next element that we should render. + * Also updates current item index to the next item, based on {@link #mItemDirection} + * + * @return The next element that we should render. + */ + View next(RecyclerView.Recycler recycler) { + final View view = recycler.getViewForPosition(mCurrentPosition); + mCurrentPosition += mItemDirection; + return view; + } + + @Override + public String toString() { + return "LayoutState{" + + "mAvailable=" + mAvailable + + ", mCurrentPosition=" + mCurrentPosition + + ", mItemDirection=" + mItemDirection + + ", mLayoutDirection=" + mLayoutDirection + + ", mStartLine=" + mStartLine + + ", mEndLine=" + mEndLine + + '}'; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/LinearLayoutManager.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/LinearLayoutManager.java new file mode 100644 index 00000000..b1211068 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/LinearLayoutManager.java @@ -0,0 +1,2242 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific languag`e governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.widget; + +import static org.telegram.messenger.support.widget.RecyclerView.NO_POSITION; + +import android.content.Context; +import android.graphics.PointF; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.v4.view.ViewCompat; +import android.support.v4.view.accessibility.AccessibilityEventCompat; +import android.support.v4.view.accessibility.AccessibilityRecordCompat; +import org.telegram.messenger.support.widget.RecyclerView.LayoutParams; +import org.telegram.messenger.support.widget.helper.ItemTouchHelper; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; + +import java.util.List; + +/** + * A {@link android.support.v7.widget.RecyclerView.LayoutManager} implementation which provides + * similar functionality to {@link android.widget.ListView}. + */ +public class LinearLayoutManager extends RecyclerView.LayoutManager implements + ItemTouchHelper.ViewDropHandler { + + private static final String TAG = "LinearLayoutManager"; + + private static final boolean DEBUG = false; + + public static final int HORIZONTAL = OrientationHelper.HORIZONTAL; + + public static final int VERTICAL = OrientationHelper.VERTICAL; + + public static final int INVALID_OFFSET = Integer.MIN_VALUE; + + + /** + * While trying to find next view to focus, LayoutManager will not try to scroll more + * than this factor times the total space of the list. If layout is vertical, total space is the + * height minus padding, if layout is horizontal, total space is the width minus padding. + */ + private static final float MAX_SCROLL_FACTOR = 1 / 3f; + + + /** + * Current orientation. Either {@link #HORIZONTAL} or {@link #VERTICAL} + */ + int mOrientation; + + /** + * Helper class that keeps temporary layout state. + * It does not keep state after layout is complete but we still keep a reference to re-use + * the same object. + */ + private LayoutState mLayoutState; + + /** + * Many calculations are made depending on orientation. To keep it clean, this interface + * helps {@link LinearLayoutManager} make those decisions. + * Based on {@link #mOrientation}, an implementation is lazily created in + * {@link #ensureLayoutState} method. + */ + OrientationHelper mOrientationHelper; + + /** + * We need to track this so that we can ignore current position when it changes. + */ + private boolean mLastStackFromEnd; + + + /** + * Defines if layout should be calculated from end to start. + * + * @see #mShouldReverseLayout + */ + private boolean mReverseLayout = false; + + /** + * This keeps the final value for how LayoutManager should start laying out views. + * It is calculated by checking {@link #getReverseLayout()} and View's layout direction. + * {@link #onLayoutChildren(RecyclerView.Recycler, RecyclerView.State)} is run. + */ + boolean mShouldReverseLayout = false; + + /** + * Works the same way as {@link android.widget.AbsListView#setStackFromBottom(boolean)} and + * it supports both orientations. + * see {@link android.widget.AbsListView#setStackFromBottom(boolean)} + */ + private boolean mStackFromEnd = false; + + /** + * Works the same way as {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}. + * see {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)} + */ + private boolean mSmoothScrollbarEnabled = true; + + /** + * When LayoutManager needs to scroll to a position, it sets this variable and requests a + * layout which will check this variable and re-layout accordingly. + */ + int mPendingScrollPosition = NO_POSITION; + + /** + * Used to keep the offset value when {@link #scrollToPositionWithOffset(int, int)} is + * called. + */ + int mPendingScrollPositionOffset = INVALID_OFFSET; + + private boolean mRecycleChildrenOnDetach; + + SavedState mPendingSavedState = null; + + /** + * Re-used variable to keep anchor information on re-layout. + * Anchor position and coordinate defines the reference point for LLM while doing a layout. + * */ + final AnchorInfo mAnchorInfo = new AnchorInfo(); + + /** + * Creates a vertical LinearLayoutManager + * + * @param context Current context, will be used to access resources. + */ + public LinearLayoutManager(Context context) { + this(context, VERTICAL, false); + } + + /** + * @param context Current context, will be used to access resources. + * @param orientation Layout orientation. Should be {@link #HORIZONTAL} or {@link + * #VERTICAL}. + * @param reverseLayout When set to true, layouts from end to start. + */ + public LinearLayoutManager(Context context, int orientation, boolean reverseLayout) { + setOrientation(orientation); + setReverseLayout(reverseLayout); + setAutoMeasureEnabled(true); + } + + /** + * Constructor used when layout manager is set in XML by RecyclerView attribute + * "layoutManager". Defaults to vertical orientation. + * + * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_android_orientation + * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_reverseLayout + * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_stackFromEnd + */ + public LinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + Properties properties = getProperties(context, attrs, defStyleAttr, defStyleRes); + setOrientation(properties.orientation); + setReverseLayout(properties.reverseLayout); + setStackFromEnd(properties.stackFromEnd); + setAutoMeasureEnabled(true); + } + + /** + * {@inheritDoc} + */ + @Override + public LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + } + + /** + * Returns whether LayoutManager will recycle its children when it is detached from + * RecyclerView. + * + * @return true if LayoutManager will recycle its children when it is detached from + * RecyclerView. + */ + public boolean getRecycleChildrenOnDetach() { + return mRecycleChildrenOnDetach; + } + + /** + * Set whether LayoutManager will recycle its children when it is detached from + * RecyclerView. + *

+ * If you are using a {@link RecyclerView.RecycledViewPool}, it might be a good idea to set + * this flag to true so that views will be avilable to other RecyclerViews + * immediately. + *

+ * Note that, setting this flag will result in a performance drop if RecyclerView + * is restored. + * + * @param recycleChildrenOnDetach Whether children should be recycled in detach or not. + */ + public void setRecycleChildrenOnDetach(boolean recycleChildrenOnDetach) { + mRecycleChildrenOnDetach = recycleChildrenOnDetach; + } + + @Override + public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) { + super.onDetachedFromWindow(view, recycler); + if (mRecycleChildrenOnDetach) { + removeAndRecycleAllViews(recycler); + recycler.clear(); + } + } + + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + if (getChildCount() > 0) { + final AccessibilityRecordCompat record = AccessibilityEventCompat + .asRecord(event); + record.setFromIndex(findFirstVisibleItemPosition()); + record.setToIndex(findLastVisibleItemPosition()); + } + } + + @Override + public Parcelable onSaveInstanceState() { + if (mPendingSavedState != null) { + return new SavedState(mPendingSavedState); + } + SavedState state = new SavedState(); + if (getChildCount() > 0) { + ensureLayoutState(); + boolean didLayoutFromEnd = mLastStackFromEnd ^ mShouldReverseLayout; + state.mAnchorLayoutFromEnd = didLayoutFromEnd; + if (didLayoutFromEnd) { + final View refChild = getChildClosestToEnd(); + state.mAnchorOffset = mOrientationHelper.getEndAfterPadding() - + mOrientationHelper.getDecoratedEnd(refChild); + state.mAnchorPosition = getPosition(refChild); + } else { + final View refChild = getChildClosestToStart(); + state.mAnchorPosition = getPosition(refChild); + state.mAnchorOffset = mOrientationHelper.getDecoratedStart(refChild) - + mOrientationHelper.getStartAfterPadding(); + } + } else { + state.invalidateAnchor(); + } + return state; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (state instanceof SavedState) { + mPendingSavedState = (SavedState) state; + requestLayout(); + if (DEBUG) { + Log.d(TAG, "loaded saved state"); + } + } else if (DEBUG) { + Log.d(TAG, "invalid saved state class"); + } + } + + /** + * @return true if {@link #getOrientation()} is {@link #HORIZONTAL} + */ + @Override + public boolean canScrollHorizontally() { + return mOrientation == HORIZONTAL; + } + + /** + * @return true if {@link #getOrientation()} is {@link #VERTICAL} + */ + @Override + public boolean canScrollVertically() { + return mOrientation == VERTICAL; + } + + /** + * Compatibility support for {@link android.widget.AbsListView#setStackFromBottom(boolean)} + */ + public void setStackFromEnd(boolean stackFromEnd) { + assertNotInLayoutOrScroll(null); + if (mStackFromEnd == stackFromEnd) { + return; + } + mStackFromEnd = stackFromEnd; + requestLayout(); + } + + public boolean getStackFromEnd() { + return mStackFromEnd; + } + + /** + * Returns the current orientaion of the layout. + * + * @return Current orientation, either {@link #HORIZONTAL} or {@link #VERTICAL} + * @see #setOrientation(int) + */ + public int getOrientation() { + return mOrientation; + } + + /** + * Sets the orientation of the layout. {@link android.support.v7.widget.LinearLayoutManager} + * will do its best to keep scroll position. + * + * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL} + */ + public void setOrientation(int orientation) { + if (orientation != HORIZONTAL && orientation != VERTICAL) { + throw new IllegalArgumentException("invalid orientation:" + orientation); + } + assertNotInLayoutOrScroll(null); + if (orientation == mOrientation) { + return; + } + mOrientation = orientation; + mOrientationHelper = null; + requestLayout(); + } + + /** + * Calculates the view layout order. (e.g. from end to start or start to end) + * RTL layout support is applied automatically. So if layout is RTL and + * {@link #getReverseLayout()} is {@code true}, elements will be laid out starting from left. + */ + private void resolveShouldLayoutReverse() { + // A == B is the same result, but we rather keep it readable + if (mOrientation == VERTICAL || !isLayoutRTL()) { + mShouldReverseLayout = mReverseLayout; + } else { + mShouldReverseLayout = !mReverseLayout; + } + } + + /** + * Returns if views are laid out from the opposite direction of the layout. + * + * @return If layout is reversed or not. + * @see #setReverseLayout(boolean) + */ + public boolean getReverseLayout() { + return mReverseLayout; + } + + /** + * Used to reverse item traversal and layout order. + * This behaves similar to the layout change for RTL views. When set to true, first item is + * laid out at the end of the UI, second item is laid out before it etc. + * + * For horizontal layouts, it depends on the layout direction. + * When set to true, If {@link android.support.v7.widget.RecyclerView} is LTR, than it will + * layout from RTL, if {@link android.support.v7.widget.RecyclerView}} is RTL, it will layout + * from LTR. + * + * If you are looking for the exact same behavior of + * {@link android.widget.AbsListView#setStackFromBottom(boolean)}, use + * {@link #setStackFromEnd(boolean)} + */ + public void setReverseLayout(boolean reverseLayout) { + assertNotInLayoutOrScroll(null); + if (reverseLayout == mReverseLayout) { + return; + } + mReverseLayout = reverseLayout; + requestLayout(); + } + + /** + * {@inheritDoc} + */ + @Override + public View findViewByPosition(int position) { + final int childCount = getChildCount(); + if (childCount == 0) { + return null; + } + final int firstChild = getPosition(getChildAt(0)); + final int viewPosition = position - firstChild; + if (viewPosition >= 0 && viewPosition < childCount) { + final View child = getChildAt(viewPosition); + if (getPosition(child) == position) { + return child; // in pre-layout, this may not match + } + } + // fallback to traversal. This might be necessary in pre-layout. + return super.findViewByPosition(position); + } + + /** + *

Returns the amount of extra space that should be laid out by LayoutManager. + * By default, {@link android.support.v7.widget.LinearLayoutManager} lays out 1 extra page of + * items while smooth scrolling and 0 otherwise. You can override this method to implement your + * custom layout pre-cache logic.

+ *

Laying out invisible elements will eventually come with performance cost. On the other + * hand, in places like smooth scrolling to an unknown location, this extra content helps + * LayoutManager to calculate a much smoother scrolling; which improves user experience.

+ *

You can also use this if you are trying to pre-layout your upcoming views.

+ * + * @return The extra space that should be laid out (in pixels). + */ + protected int getExtraLayoutSpace(RecyclerView.State state) { + if (state.hasTargetScrollPosition()) { + return mOrientationHelper.getTotalSpace(); + } else { + return 0; + } + } + + @Override + public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, + int position) { + LinearSmoothScroller linearSmoothScroller = + new LinearSmoothScroller(recyclerView.getContext()) { + @Override + public PointF computeScrollVectorForPosition(int targetPosition) { + return LinearLayoutManager.this + .computeScrollVectorForPosition(targetPosition); + } + }; + linearSmoothScroller.setTargetPosition(position); + startSmoothScroll(linearSmoothScroller); + } + + public PointF computeScrollVectorForPosition(int targetPosition) { + if (getChildCount() == 0) { + return null; + } + final int firstChildPos = getPosition(getChildAt(0)); + final int direction = targetPosition < firstChildPos != mShouldReverseLayout ? -1 : 1; + if (mOrientation == HORIZONTAL) { + return new PointF(direction, 0); + } else { + return new PointF(0, direction); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + // layout algorithm: + // 1) by checking children and other variables, find an anchor coordinate and an anchor + // item position. + // 2) fill towards start, stacking from bottom + // 3) fill towards end, stacking from top + // 4) scroll to fulfill requirements like stack from bottom. + // create layout state + if (DEBUG) { + Log.d(TAG, "is pre layout:" + state.isPreLayout()); + } + if (mPendingSavedState != null || mPendingScrollPosition != NO_POSITION) { + if (state.getItemCount() == 0) { + removeAndRecycleAllViews(recycler); + return; + } + } + if (mPendingSavedState != null && mPendingSavedState.hasValidAnchor()) { + mPendingScrollPosition = mPendingSavedState.mAnchorPosition; + } + + ensureLayoutState(); + mLayoutState.mRecycle = false; + // resolve layout direction + resolveShouldLayoutReverse(); + + mAnchorInfo.reset(); + mAnchorInfo.mLayoutFromEnd = mShouldReverseLayout ^ mStackFromEnd; + // calculate anchor position and coordinate + updateAnchorInfoForLayout(recycler, state, mAnchorInfo); + if (DEBUG) { + Log.d(TAG, "Anchor info:" + mAnchorInfo); + } + + // LLM may decide to layout items for "extra" pixels to account for scrolling target, + // caching or predictive animations. + int extraForStart; + int extraForEnd; + final int extra = getExtraLayoutSpace(state); + // If the previous scroll delta was less than zero, the extra space should be laid out + // at the start. Otherwise, it should be at the end. + if (mLayoutState.mLastScrollDelta >= 0) { + extraForEnd = extra; + extraForStart = 0; + } else { + extraForStart = extra; + extraForEnd = 0; + } + extraForStart += mOrientationHelper.getStartAfterPadding(); + extraForEnd += mOrientationHelper.getEndPadding(); + if (state.isPreLayout() && mPendingScrollPosition != NO_POSITION && + mPendingScrollPositionOffset != INVALID_OFFSET) { + // if the child is visible and we are going to move it around, we should layout + // extra items in the opposite direction to make sure new items animate nicely + // instead of just fading in + final View existing = findViewByPosition(mPendingScrollPosition); + if (existing != null) { + final int current; + final int upcomingOffset; + if (mShouldReverseLayout) { + current = mOrientationHelper.getEndAfterPadding() - + mOrientationHelper.getDecoratedEnd(existing); + upcomingOffset = current - mPendingScrollPositionOffset; + } else { + current = mOrientationHelper.getDecoratedStart(existing) + - mOrientationHelper.getStartAfterPadding(); + upcomingOffset = mPendingScrollPositionOffset - current; + } + if (upcomingOffset > 0) { + extraForStart += upcomingOffset; + } else { + extraForEnd -= upcomingOffset; + } + } + } + int startOffset; + int endOffset; + final int firstLayoutDirection; + if (mAnchorInfo.mLayoutFromEnd) { + firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL : + LayoutState.ITEM_DIRECTION_HEAD; + } else { + firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD : + LayoutState.ITEM_DIRECTION_TAIL; + } + + onAnchorReady(recycler, state, mAnchorInfo, firstLayoutDirection); + detachAndScrapAttachedViews(recycler); + mLayoutState.mInfinite = resolveIsInfinite(); + mLayoutState.mIsPreLayout = state.isPreLayout(); + if (mAnchorInfo.mLayoutFromEnd) { + // fill towards start + updateLayoutStateToFillStart(mAnchorInfo); + mLayoutState.mExtra = extraForStart; + fill(recycler, mLayoutState, state, false); + startOffset = mLayoutState.mOffset; + final int firstElement = mLayoutState.mCurrentPosition; + if (mLayoutState.mAvailable > 0) { + extraForEnd += mLayoutState.mAvailable; + } + // fill towards end + updateLayoutStateToFillEnd(mAnchorInfo); + mLayoutState.mExtra = extraForEnd; + mLayoutState.mCurrentPosition += mLayoutState.mItemDirection; + fill(recycler, mLayoutState, state, false); + endOffset = mLayoutState.mOffset; + + if (mLayoutState.mAvailable > 0) { + // end could not consume all. add more items towards start + extraForStart = mLayoutState.mAvailable; + updateLayoutStateToFillStart(firstElement, startOffset); + mLayoutState.mExtra = extraForStart; + fill(recycler, mLayoutState, state, false); + startOffset = mLayoutState.mOffset; + } + } else { + // fill towards end + updateLayoutStateToFillEnd(mAnchorInfo); + mLayoutState.mExtra = extraForEnd; + fill(recycler, mLayoutState, state, false); + endOffset = mLayoutState.mOffset; + final int lastElement = mLayoutState.mCurrentPosition; + if (mLayoutState.mAvailable > 0) { + extraForStart += mLayoutState.mAvailable; + } + // fill towards start + updateLayoutStateToFillStart(mAnchorInfo); + mLayoutState.mExtra = extraForStart; + mLayoutState.mCurrentPosition += mLayoutState.mItemDirection; + fill(recycler, mLayoutState, state, false); + startOffset = mLayoutState.mOffset; + + if (mLayoutState.mAvailable > 0) { + extraForEnd = mLayoutState.mAvailable; + // start could not consume all it should. add more items towards end + updateLayoutStateToFillEnd(lastElement, endOffset); + mLayoutState.mExtra = extraForEnd; + fill(recycler, mLayoutState, state, false); + endOffset = mLayoutState.mOffset; + } + } + + // changes may cause gaps on the UI, try to fix them. + // TODO we can probably avoid this if neither stackFromEnd/reverseLayout/RTL values have + // changed + if (getChildCount() > 0) { + // because layout from end may be changed by scroll to position + // we re-calculate it. + // find which side we should check for gaps. + if (mShouldReverseLayout ^ mStackFromEnd) { + int fixOffset = fixLayoutEndGap(endOffset, recycler, state, true); + startOffset += fixOffset; + endOffset += fixOffset; + fixOffset = fixLayoutStartGap(startOffset, recycler, state, false); + startOffset += fixOffset; + endOffset += fixOffset; + } else { + int fixOffset = fixLayoutStartGap(startOffset, recycler, state, true); + startOffset += fixOffset; + endOffset += fixOffset; + fixOffset = fixLayoutEndGap(endOffset, recycler, state, false); + startOffset += fixOffset; + endOffset += fixOffset; + } + } + layoutForPredictiveAnimations(recycler, state, startOffset, endOffset); + if (!state.isPreLayout()) { + mPendingScrollPosition = NO_POSITION; + mPendingScrollPositionOffset = INVALID_OFFSET; + mOrientationHelper.onLayoutComplete(); + } + mLastStackFromEnd = mStackFromEnd; + mPendingSavedState = null; // we don't need this anymore + if (DEBUG) { + validateChildOrder(); + } + } + + /** + * Method called when Anchor position is decided. Extending class can setup accordingly or + * even update anchor info if necessary. + * @param recycler The recycler for the layout + * @param state The layout state + * @param anchorInfo The mutable POJO that keeps the position and offset. + * @param firstLayoutItemDirection The direction of the first layout filling in terms of adapter + * indices. + */ + void onAnchorReady(RecyclerView.Recycler recycler, RecyclerView.State state, + AnchorInfo anchorInfo, int firstLayoutItemDirection) { + } + + /** + * If necessary, layouts new items for predictive animations + */ + private void layoutForPredictiveAnimations(RecyclerView.Recycler recycler, + RecyclerView.State state, int startOffset, int endOffset) { + // If there are scrap children that we did not layout, we need to find where they did go + // and layout them accordingly so that animations can work as expected. + // This case may happen if new views are added or an existing view expands and pushes + // another view out of bounds. + if (!state.willRunPredictiveAnimations() || getChildCount() == 0 || state.isPreLayout() + || !supportsPredictiveItemAnimations()) { + return; + } + // to make the logic simpler, we calculate the size of children and call fill. + int scrapExtraStart = 0, scrapExtraEnd = 0; + final List scrapList = recycler.getScrapList(); + final int scrapSize = scrapList.size(); + final int firstChildPos = getPosition(getChildAt(0)); + for (int i = 0; i < scrapSize; i++) { + RecyclerView.ViewHolder scrap = scrapList.get(i); + if (scrap.isRemoved()) { + continue; + } + final int position = scrap.getLayoutPosition(); + final int direction = position < firstChildPos != mShouldReverseLayout + ? LayoutState.LAYOUT_START : LayoutState.LAYOUT_END; + if (direction == LayoutState.LAYOUT_START) { + scrapExtraStart += mOrientationHelper.getDecoratedMeasurement(scrap.itemView); + } else { + scrapExtraEnd += mOrientationHelper.getDecoratedMeasurement(scrap.itemView); + } + } + + if (DEBUG) { + Log.d(TAG, "for unused scrap, decided to add " + scrapExtraStart + + " towards start and " + scrapExtraEnd + " towards end"); + } + mLayoutState.mScrapList = scrapList; + if (scrapExtraStart > 0) { + View anchor = getChildClosestToStart(); + updateLayoutStateToFillStart(getPosition(anchor), startOffset); + mLayoutState.mExtra = scrapExtraStart; + mLayoutState.mAvailable = 0; + mLayoutState.assignPositionFromScrapList(); + fill(recycler, mLayoutState, state, false); + } + + if (scrapExtraEnd > 0) { + View anchor = getChildClosestToEnd(); + updateLayoutStateToFillEnd(getPosition(anchor), endOffset); + mLayoutState.mExtra = scrapExtraEnd; + mLayoutState.mAvailable = 0; + mLayoutState.assignPositionFromScrapList(); + fill(recycler, mLayoutState, state, false); + } + mLayoutState.mScrapList = null; + } + + private void updateAnchorInfoForLayout(RecyclerView.Recycler recycler, RecyclerView.State state, + AnchorInfo anchorInfo) { + if (updateAnchorFromPendingData(state, anchorInfo)) { + if (DEBUG) { + Log.d(TAG, "updated anchor info from pending information"); + } + return; + } + + if (updateAnchorFromChildren(recycler, state, anchorInfo)) { + if (DEBUG) { + Log.d(TAG, "updated anchor info from existing children"); + } + return; + } + if (DEBUG) { + Log.d(TAG, "deciding anchor info for fresh state"); + } + anchorInfo.assignCoordinateFromPadding(); + anchorInfo.mPosition = mStackFromEnd ? state.getItemCount() - 1 : 0; + } + + /** + * Finds an anchor child from existing Views. Most of the time, this is the view closest to + * start or end that has a valid position (e.g. not removed). + *

+ * If a child has focus, it is given priority. + */ + private boolean updateAnchorFromChildren(RecyclerView.Recycler recycler, + RecyclerView.State state, AnchorInfo anchorInfo) { + if (getChildCount() == 0) { + return false; + } + final View focused = getFocusedChild(); + if (focused != null && anchorInfo.isViewValidAsAnchor(focused, state)) { + anchorInfo.assignFromViewAndKeepVisibleRect(focused); + return true; + } + if (mLastStackFromEnd != mStackFromEnd) { + return false; + } + View referenceChild = anchorInfo.mLayoutFromEnd + ? findReferenceChildClosestToEnd(recycler, state) + : findReferenceChildClosestToStart(recycler, state); + if (referenceChild != null) { + anchorInfo.assignFromView(referenceChild); + // If all visible views are removed in 1 pass, reference child might be out of bounds. + // If that is the case, offset it back to 0 so that we use these pre-layout children. + if (!state.isPreLayout() && supportsPredictiveItemAnimations()) { + // validate this child is at least partially visible. if not, offset it to start + final boolean notVisible = + mOrientationHelper.getDecoratedStart(referenceChild) >= mOrientationHelper + .getEndAfterPadding() + || mOrientationHelper.getDecoratedEnd(referenceChild) + < mOrientationHelper.getStartAfterPadding(); + if (notVisible) { + anchorInfo.mCoordinate = anchorInfo.mLayoutFromEnd + ? mOrientationHelper.getEndAfterPadding() + : mOrientationHelper.getStartAfterPadding(); + } + } + return true; + } + return false; + } + + /** + * If there is a pending scroll position or saved states, updates the anchor info from that + * data and returns true + */ + private boolean updateAnchorFromPendingData(RecyclerView.State state, AnchorInfo anchorInfo) { + if (state.isPreLayout() || mPendingScrollPosition == NO_POSITION) { + return false; + } + // validate scroll position + if (mPendingScrollPosition < 0 || mPendingScrollPosition >= state.getItemCount()) { + mPendingScrollPosition = NO_POSITION; + mPendingScrollPositionOffset = INVALID_OFFSET; + if (DEBUG) { + Log.e(TAG, "ignoring invalid scroll position " + mPendingScrollPosition); + } + return false; + } + + // if child is visible, try to make it a reference child and ensure it is fully visible. + // if child is not visible, align it depending on its virtual position. + anchorInfo.mPosition = mPendingScrollPosition; + if (mPendingSavedState != null && mPendingSavedState.hasValidAnchor()) { + // Anchor offset depends on how that child was laid out. Here, we update it + // according to our current view bounds + anchorInfo.mLayoutFromEnd = mPendingSavedState.mAnchorLayoutFromEnd; + if (anchorInfo.mLayoutFromEnd) { + anchorInfo.mCoordinate = mOrientationHelper.getEndAfterPadding() - + mPendingSavedState.mAnchorOffset; + } else { + anchorInfo.mCoordinate = mOrientationHelper.getStartAfterPadding() + + mPendingSavedState.mAnchorOffset; + } + return true; + } + + if (mPendingScrollPositionOffset == INVALID_OFFSET) { + View child = findViewByPosition(mPendingScrollPosition); + if (child != null) { + final int childSize = mOrientationHelper.getDecoratedMeasurement(child); + if (childSize > mOrientationHelper.getTotalSpace()) { + // item does not fit. fix depending on layout direction + anchorInfo.assignCoordinateFromPadding(); + return true; + } + final int startGap = mOrientationHelper.getDecoratedStart(child) + - mOrientationHelper.getStartAfterPadding(); + if (startGap < 0) { + anchorInfo.mCoordinate = mOrientationHelper.getStartAfterPadding(); + anchorInfo.mLayoutFromEnd = false; + return true; + } + final int endGap = mOrientationHelper.getEndAfterPadding() - + mOrientationHelper.getDecoratedEnd(child); + if (endGap < 0) { + anchorInfo.mCoordinate = mOrientationHelper.getEndAfterPadding(); + anchorInfo.mLayoutFromEnd = true; + return true; + } + anchorInfo.mCoordinate = anchorInfo.mLayoutFromEnd + ? (mOrientationHelper.getDecoratedEnd(child) + mOrientationHelper + .getTotalSpaceChange()) + : mOrientationHelper.getDecoratedStart(child); + } else { // item is not visible. + if (getChildCount() > 0) { + // get position of any child, does not matter + int pos = getPosition(getChildAt(0)); + anchorInfo.mLayoutFromEnd = mPendingScrollPosition < pos + == mShouldReverseLayout; + } + anchorInfo.assignCoordinateFromPadding(); + } + return true; + } + // override layout from end values for consistency + anchorInfo.mLayoutFromEnd = mShouldReverseLayout; + // if this changes, we should update prepareForDrop as well + if (mShouldReverseLayout) { + anchorInfo.mCoordinate = mOrientationHelper.getEndAfterPadding() - + mPendingScrollPositionOffset; + } else { + anchorInfo.mCoordinate = mOrientationHelper.getStartAfterPadding() + + mPendingScrollPositionOffset; + } + return true; + } + + /** + * @return The final offset amount for children + */ + private int fixLayoutEndGap(int endOffset, RecyclerView.Recycler recycler, + RecyclerView.State state, boolean canOffsetChildren) { + int gap = mOrientationHelper.getEndAfterPadding() - endOffset; + int fixOffset = 0; + if (gap > 0) { + fixOffset = -scrollBy(-gap, recycler, state); + } else { + return 0; // nothing to fix + } + // move offset according to scroll amount + endOffset += fixOffset; + if (canOffsetChildren) { + // re-calculate gap, see if we could fix it + gap = mOrientationHelper.getEndAfterPadding() - endOffset; + if (gap > 0) { + mOrientationHelper.offsetChildren(gap); + return gap + fixOffset; + } + } + return fixOffset; + } + + /** + * @return The final offset amount for children + */ + private int fixLayoutStartGap(int startOffset, RecyclerView.Recycler recycler, + RecyclerView.State state, boolean canOffsetChildren) { + int gap = startOffset - mOrientationHelper.getStartAfterPadding(); + int fixOffset = 0; + if (gap > 0) { + // check if we should fix this gap. + fixOffset = -scrollBy(gap, recycler, state); + } else { + return 0; // nothing to fix + } + startOffset += fixOffset; + if (canOffsetChildren) { + // re-calculate gap, see if we could fix it + gap = startOffset - mOrientationHelper.getStartAfterPadding(); + if (gap > 0) { + mOrientationHelper.offsetChildren(-gap); + return fixOffset - gap; + } + } + return fixOffset; + } + + private void updateLayoutStateToFillEnd(AnchorInfo anchorInfo) { + updateLayoutStateToFillEnd(anchorInfo.mPosition, anchorInfo.mCoordinate); + } + + private void updateLayoutStateToFillEnd(int itemPosition, int offset) { + mLayoutState.mAvailable = mOrientationHelper.getEndAfterPadding() - offset; + mLayoutState.mItemDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD : + LayoutState.ITEM_DIRECTION_TAIL; + mLayoutState.mCurrentPosition = itemPosition; + mLayoutState.mLayoutDirection = LayoutState.LAYOUT_END; + mLayoutState.mOffset = offset; + mLayoutState.mScrollingOffset = LayoutState.SCOLLING_OFFSET_NaN; + } + + private void updateLayoutStateToFillStart(AnchorInfo anchorInfo) { + updateLayoutStateToFillStart(anchorInfo.mPosition, anchorInfo.mCoordinate); + } + + private void updateLayoutStateToFillStart(int itemPosition, int offset) { + mLayoutState.mAvailable = offset - mOrientationHelper.getStartAfterPadding(); + mLayoutState.mCurrentPosition = itemPosition; + mLayoutState.mItemDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL : + LayoutState.ITEM_DIRECTION_HEAD; + mLayoutState.mLayoutDirection = LayoutState.LAYOUT_START; + mLayoutState.mOffset = offset; + mLayoutState.mScrollingOffset = LayoutState.SCOLLING_OFFSET_NaN; + + } + + protected boolean isLayoutRTL() { + return getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL; + } + + void ensureLayoutState() { + if (mLayoutState == null) { + mLayoutState = createLayoutState(); + } + if (mOrientationHelper == null) { + mOrientationHelper = OrientationHelper.createOrientationHelper(this, mOrientation); + } + } + + /** + * Test overrides this to plug some tracking and verification. + * + * @return A new LayoutState + */ + LayoutState createLayoutState() { + return new LayoutState(); + } + + /** + *

Scroll the RecyclerView to make the position visible.

+ * + *

RecyclerView will scroll the minimum amount that is necessary to make the + * target position visible. If you are looking for a similar behavior to + * {@link android.widget.ListView#setSelection(int)} or + * {@link android.widget.ListView#setSelectionFromTop(int, int)}, use + * {@link #scrollToPositionWithOffset(int, int)}.

+ * + *

Note that scroll position change will not be reflected until the next layout call.

+ * + * @param position Scroll to this adapter position + * @see #scrollToPositionWithOffset(int, int) + */ + @Override + public void scrollToPosition(int position) { + mPendingScrollPosition = position; + mPendingScrollPositionOffset = INVALID_OFFSET; + if (mPendingSavedState != null) { + mPendingSavedState.invalidateAnchor(); + } + requestLayout(); + } + + /** + * Scroll to the specified adapter position with the given offset from resolved layout + * start. Resolved layout start depends on {@link #getReverseLayout()}, + * {@link ViewCompat#getLayoutDirection(android.view.View)} and {@link #getStackFromEnd()}. + *

+ * For example, if layout is {@link #VERTICAL} and {@link #getStackFromEnd()} is true, calling + * scrollToPositionWithOffset(10, 20) will layout such that + * item[10]'s bottom is 20 pixels above the RecyclerView's bottom. + *

+ * Note that scroll position change will not be reflected until the next layout call. + *

+ * If you are just trying to make a position visible, use {@link #scrollToPosition(int)}. + * + * @param position Index (starting at 0) of the reference item. + * @param offset The distance (in pixels) between the start edge of the item view and + * start edge of the RecyclerView. + * @see #setReverseLayout(boolean) + * @see #scrollToPosition(int) + */ + public void scrollToPositionWithOffset(int position, int offset) { + mPendingScrollPosition = position; + mPendingScrollPositionOffset = offset; + if (mPendingSavedState != null) { + mPendingSavedState.invalidateAnchor(); + } + requestLayout(); + } + + + /** + * {@inheritDoc} + */ + @Override + public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, + RecyclerView.State state) { + if (mOrientation == VERTICAL) { + return 0; + } + return scrollBy(dx, recycler, state); + } + + /** + * {@inheritDoc} + */ + @Override + public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, + RecyclerView.State state) { + if (mOrientation == HORIZONTAL) { + return 0; + } + return scrollBy(dy, recycler, state); + } + + @Override + public int computeHorizontalScrollOffset(RecyclerView.State state) { + return computeScrollOffset(state); + } + + @Override + public int computeVerticalScrollOffset(RecyclerView.State state) { + return computeScrollOffset(state); + } + + @Override + public int computeHorizontalScrollExtent(RecyclerView.State state) { + return computeScrollExtent(state); + } + + @Override + public int computeVerticalScrollExtent(RecyclerView.State state) { + return computeScrollExtent(state); + } + + @Override + public int computeHorizontalScrollRange(RecyclerView.State state) { + return computeScrollRange(state); + } + + @Override + public int computeVerticalScrollRange(RecyclerView.State state) { + return computeScrollRange(state); + } + + private int computeScrollOffset(RecyclerView.State state) { + if (getChildCount() == 0) { + return 0; + } + ensureLayoutState(); + return ScrollbarHelper.computeScrollOffset(state, mOrientationHelper, + findFirstVisibleChildClosestToStart(!mSmoothScrollbarEnabled, true), + findFirstVisibleChildClosestToEnd(!mSmoothScrollbarEnabled, true), + this, mSmoothScrollbarEnabled, mShouldReverseLayout); + } + + private int computeScrollExtent(RecyclerView.State state) { + if (getChildCount() == 0) { + return 0; + } + ensureLayoutState(); + return ScrollbarHelper.computeScrollExtent(state, mOrientationHelper, + findFirstVisibleChildClosestToStart(!mSmoothScrollbarEnabled, true), + findFirstVisibleChildClosestToEnd(!mSmoothScrollbarEnabled, true), + this, mSmoothScrollbarEnabled); + } + + private int computeScrollRange(RecyclerView.State state) { + if (getChildCount() == 0) { + return 0; + } + ensureLayoutState(); + return ScrollbarHelper.computeScrollRange(state, mOrientationHelper, + findFirstVisibleChildClosestToStart(!mSmoothScrollbarEnabled, true), + findFirstVisibleChildClosestToEnd(!mSmoothScrollbarEnabled, true), + this, mSmoothScrollbarEnabled); + } + + /** + * When smooth scrollbar is enabled, the position and size of the scrollbar thumb is computed + * based on the number of visible pixels in the visible items. This however assumes that all + * list items have similar or equal widths or heights (depending on list orientation). + * If you use a list in which items have different dimensions, the scrollbar will change + * appearance as the user scrolls through the list. To avoid this issue, you need to disable + * this property. + * + * When smooth scrollbar is disabled, the position and size of the scrollbar thumb is based + * solely on the number of items in the adapter and the position of the visible items inside + * the adapter. This provides a stable scrollbar as the user navigates through a list of items + * with varying widths / heights. + * + * @param enabled Whether or not to enable smooth scrollbar. + * + * @see #setSmoothScrollbarEnabled(boolean) + */ + public void setSmoothScrollbarEnabled(boolean enabled) { + mSmoothScrollbarEnabled = enabled; + } + + /** + * Returns the current state of the smooth scrollbar feature. It is enabled by default. + * + * @return True if smooth scrollbar is enabled, false otherwise. + * + * @see #setSmoothScrollbarEnabled(boolean) + */ + public boolean isSmoothScrollbarEnabled() { + return mSmoothScrollbarEnabled; + } + + private void updateLayoutState(int layoutDirection, int requiredSpace, + boolean canUseExistingSpace, RecyclerView.State state) { + // If parent provides a hint, don't measure unlimited. + mLayoutState.mInfinite = resolveIsInfinite(); + mLayoutState.mExtra = getExtraLayoutSpace(state); + mLayoutState.mLayoutDirection = layoutDirection; + int scrollingOffset; + if (layoutDirection == LayoutState.LAYOUT_END) { + mLayoutState.mExtra += mOrientationHelper.getEndPadding(); + // get the first child in the direction we are going + final View child = getChildClosestToEnd(); + // the direction in which we are traversing children + mLayoutState.mItemDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD + : LayoutState.ITEM_DIRECTION_TAIL; + mLayoutState.mCurrentPosition = getPosition(child) + mLayoutState.mItemDirection; + mLayoutState.mOffset = mOrientationHelper.getDecoratedEnd(child); + // calculate how much we can scroll without adding new children (independent of layout) + scrollingOffset = mOrientationHelper.getDecoratedEnd(child) + - mOrientationHelper.getEndAfterPadding(); + + } else { + final View child = getChildClosestToStart(); + mLayoutState.mExtra += mOrientationHelper.getStartAfterPadding(); + mLayoutState.mItemDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL + : LayoutState.ITEM_DIRECTION_HEAD; + mLayoutState.mCurrentPosition = getPosition(child) + mLayoutState.mItemDirection; + mLayoutState.mOffset = mOrientationHelper.getDecoratedStart(child); + scrollingOffset = -mOrientationHelper.getDecoratedStart(child) + + mOrientationHelper.getStartAfterPadding(); + } + mLayoutState.mAvailable = requiredSpace; + if (canUseExistingSpace) { + mLayoutState.mAvailable -= scrollingOffset; + } + mLayoutState.mScrollingOffset = scrollingOffset; + } + + boolean resolveIsInfinite() { + return mOrientationHelper.getMode() == View.MeasureSpec.UNSPECIFIED + && mOrientationHelper.getEnd() == 0; + } + + int scrollBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { + if (getChildCount() == 0 || dy == 0) { + return 0; + } + mLayoutState.mRecycle = true; + ensureLayoutState(); + final int layoutDirection = dy > 0 ? LayoutState.LAYOUT_END : LayoutState.LAYOUT_START; + final int absDy = Math.abs(dy); + updateLayoutState(layoutDirection, absDy, true, state); + final int consumed = mLayoutState.mScrollingOffset + + fill(recycler, mLayoutState, state, false); + if (consumed < 0) { + if (DEBUG) { + Log.d(TAG, "Don't have any more elements to scroll"); + } + return 0; + } + final int scrolled = absDy > consumed ? layoutDirection * consumed : dy; + mOrientationHelper.offsetChildren(-scrolled); + if (DEBUG) { + Log.d(TAG, "scroll req: " + dy + " scrolled: " + scrolled); + } + mLayoutState.mLastScrollDelta = scrolled; + return scrolled; + } + + @Override + public void assertNotInLayoutOrScroll(String message) { + if (mPendingSavedState == null) { + super.assertNotInLayoutOrScroll(message); + } + } + + /** + * Recycles children between given indices. + * + * @param startIndex inclusive + * @param endIndex exclusive + */ + private void recycleChildren(RecyclerView.Recycler recycler, int startIndex, int endIndex) { + if (startIndex == endIndex) { + return; + } + if (DEBUG) { + Log.d(TAG, "Recycling " + Math.abs(startIndex - endIndex) + " items"); + } + if (endIndex > startIndex) { + for (int i = endIndex - 1; i >= startIndex; i--) { + removeAndRecycleViewAt(i, recycler); + } + } else { + for (int i = startIndex; i > endIndex; i--) { + removeAndRecycleViewAt(i, recycler); + } + } + } + + /** + * Recycles views that went out of bounds after scrolling towards the end of the layout. + * + * @param recycler Recycler instance of {@link android.support.v7.widget.RecyclerView} + * @param dt This can be used to add additional padding to the visible area. This is used + * to detect children that will go out of bounds after scrolling, without + * actually moving them. + */ + private void recycleViewsFromStart(RecyclerView.Recycler recycler, int dt) { + if (dt < 0) { + if (DEBUG) { + Log.d(TAG, "Called recycle from start with a negative value. This might happen" + + " during layout changes but may be sign of a bug"); + } + return; + } + // ignore padding, ViewGroup may not clip children. + final int limit = dt; + final int childCount = getChildCount(); + if (mShouldReverseLayout) { + for (int i = childCount - 1; i >= 0; i--) { + View child = getChildAt(i); + if (mOrientationHelper.getDecoratedEnd(child) > limit) {// stop here + recycleChildren(recycler, childCount - 1, i); + return; + } + } + } else { + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + if (mOrientationHelper.getDecoratedEnd(child) > limit) {// stop here + recycleChildren(recycler, 0, i); + return; + } + } + } + } + + + /** + * Recycles views that went out of bounds after scrolling towards the start of the layout. + * + * @param recycler Recycler instance of {@link android.support.v7.widget.RecyclerView} + * @param dt This can be used to add additional padding to the visible area. This is used + * to detect children that will go out of bounds after scrolling, without + * actually moving them. + */ + private void recycleViewsFromEnd(RecyclerView.Recycler recycler, int dt) { + final int childCount = getChildCount(); + if (dt < 0) { + if (DEBUG) { + Log.d(TAG, "Called recycle from end with a negative value. This might happen" + + " during layout changes but may be sign of a bug"); + } + return; + } + final int limit = mOrientationHelper.getEnd() - dt; + if (mShouldReverseLayout) { + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + if (mOrientationHelper.getDecoratedStart(child) < limit) {// stop here + recycleChildren(recycler, 0, i); + return; + } + } + } else { + for (int i = childCount - 1; i >= 0; i--) { + View child = getChildAt(i); + if (mOrientationHelper.getDecoratedStart(child) < limit) {// stop here + recycleChildren(recycler, childCount - 1, i); + return; + } + } + } + + } + + /** + * Helper method to call appropriate recycle method depending on current layout direction + * + * @param recycler Current recycler that is attached to RecyclerView + * @param layoutState Current layout state. Right now, this object does not change but + * we may consider moving it out of this view so passing around as a + * parameter for now, rather than accessing {@link #mLayoutState} + * @see #recycleViewsFromStart(android.support.v7.widget.RecyclerView.Recycler, int) + * @see #recycleViewsFromEnd(android.support.v7.widget.RecyclerView.Recycler, int) + * @see android.support.v7.widget.LinearLayoutManager.LayoutState#mLayoutDirection + */ + private void recycleByLayoutState(RecyclerView.Recycler recycler, LayoutState layoutState) { + if (!layoutState.mRecycle || layoutState.mInfinite) { + return; + } + if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) { + recycleViewsFromEnd(recycler, layoutState.mScrollingOffset); + } else { + recycleViewsFromStart(recycler, layoutState.mScrollingOffset); + } + } + + /** + * The magic functions :). Fills the given layout, defined by the layoutState. This is fairly + * independent from the rest of the {@link android.support.v7.widget.LinearLayoutManager} + * and with little change, can be made publicly available as a helper class. + * + * @param recycler Current recycler that is attached to RecyclerView + * @param layoutState Configuration on how we should fill out the available space. + * @param state Context passed by the RecyclerView to control scroll steps. + * @param stopOnFocusable If true, filling stops in the first focusable new child + * @return Number of pixels that it added. Useful for scoll functions. + */ + int fill(RecyclerView.Recycler recycler, LayoutState layoutState, + RecyclerView.State state, boolean stopOnFocusable) { + // max offset we should set is mFastScroll + available + final int start = layoutState.mAvailable; + if (layoutState.mScrollingOffset != LayoutState.SCOLLING_OFFSET_NaN) { + // TODO ugly bug fix. should not happen + if (layoutState.mAvailable < 0) { + layoutState.mScrollingOffset += layoutState.mAvailable; + } + recycleByLayoutState(recycler, layoutState); + } + int remainingSpace = layoutState.mAvailable + layoutState.mExtra; + LayoutChunkResult layoutChunkResult = new LayoutChunkResult(); + while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) { + layoutChunkResult.resetInternal(); + layoutChunk(recycler, state, layoutState, layoutChunkResult); + if (layoutChunkResult.mFinished) { + break; + } + layoutState.mOffset += layoutChunkResult.mConsumed * layoutState.mLayoutDirection; + /** + * Consume the available space if: + * * layoutChunk did not request to be ignored + * * OR we are laying out scrap children + * * OR we are not doing pre-layout + */ + if (!layoutChunkResult.mIgnoreConsumed || mLayoutState.mScrapList != null + || !state.isPreLayout()) { + layoutState.mAvailable -= layoutChunkResult.mConsumed; + // we keep a separate remaining space because mAvailable is important for recycling + remainingSpace -= layoutChunkResult.mConsumed; + } + + if (layoutState.mScrollingOffset != LayoutState.SCOLLING_OFFSET_NaN) { + layoutState.mScrollingOffset += layoutChunkResult.mConsumed; + if (layoutState.mAvailable < 0) { + layoutState.mScrollingOffset += layoutState.mAvailable; + } + recycleByLayoutState(recycler, layoutState); + } + if (stopOnFocusable && layoutChunkResult.mFocusable) { + break; + } + } + if (DEBUG) { + validateChildOrder(); + } + return start - layoutState.mAvailable; + } + + void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state, + LayoutState layoutState, LayoutChunkResult result) { + View view = layoutState.next(recycler); + if (view == null) { + if (DEBUG && layoutState.mScrapList == null) { + throw new RuntimeException("received null view when unexpected"); + } + // if we are laying out views in scrap, this may return null which means there is + // no more items to layout. + result.mFinished = true; + return; + } + LayoutParams params = (LayoutParams) view.getLayoutParams(); + if (layoutState.mScrapList == null) { + if (mShouldReverseLayout == (layoutState.mLayoutDirection + == LayoutState.LAYOUT_START)) { + addView(view); + } else { + addView(view, 0); + } + } else { + if (mShouldReverseLayout == (layoutState.mLayoutDirection + == LayoutState.LAYOUT_START)) { + addDisappearingView(view); + } else { + addDisappearingView(view, 0); + } + } + measureChildWithMargins(view, 0, 0); + result.mConsumed = mOrientationHelper.getDecoratedMeasurement(view); + int left, top, right, bottom; + if (mOrientation == VERTICAL) { + if (isLayoutRTL()) { + right = getWidth() - getPaddingRight(); + left = right - mOrientationHelper.getDecoratedMeasurementInOther(view); + } else { + left = getPaddingLeft(); + right = left + mOrientationHelper.getDecoratedMeasurementInOther(view); + } + if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) { + bottom = layoutState.mOffset; + top = layoutState.mOffset - result.mConsumed; + } else { + top = layoutState.mOffset; + bottom = layoutState.mOffset + result.mConsumed; + } + } else { + top = getPaddingTop(); + bottom = top + mOrientationHelper.getDecoratedMeasurementInOther(view); + + if (layoutState.mLayoutDirection == LayoutState.LAYOUT_START) { + right = layoutState.mOffset; + left = layoutState.mOffset - result.mConsumed; + } else { + left = layoutState.mOffset; + right = layoutState.mOffset + result.mConsumed; + } + } + // We calculate everything with View's bounding box (which includes decor and margins) + // To calculate correct layout position, we subtract margins. + layoutDecorated(view, left + params.leftMargin, top + params.topMargin, + right - params.rightMargin, bottom - params.bottomMargin); + if (DEBUG) { + Log.d(TAG, "laid out child at position " + getPosition(view) + ", with l:" + + (left + params.leftMargin) + ", t:" + (top + params.topMargin) + ", r:" + + (right - params.rightMargin) + ", b:" + (bottom - params.bottomMargin)); + } + // Consume the available space if the view is not removed OR changed + if (params.isItemRemoved() || params.isItemChanged()) { + result.mIgnoreConsumed = true; + } + result.mFocusable = view.isFocusable(); + } + + @Override + boolean shouldMeasureTwice() { + return getHeightMode() != View.MeasureSpec.EXACTLY + && getWidthMode() != View.MeasureSpec.EXACTLY + && hasFlexibleChildInBothOrientations(); + } + + /** + * Converts a focusDirection to orientation. + * + * @param focusDirection One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, + * {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT}, + * {@link View#FOCUS_BACKWARD}, {@link View#FOCUS_FORWARD} + * or 0 for not applicable + * @return {@link LayoutState#LAYOUT_START} or {@link LayoutState#LAYOUT_END} if focus direction + * is applicable to current state, {@link LayoutState#INVALID_LAYOUT} otherwise. + */ + int convertFocusDirectionToLayoutDirection(int focusDirection) { + switch (focusDirection) { + case View.FOCUS_BACKWARD: + return LayoutState.LAYOUT_START; + case View.FOCUS_FORWARD: + return LayoutState.LAYOUT_END; + case View.FOCUS_UP: + return mOrientation == VERTICAL ? LayoutState.LAYOUT_START + : LayoutState.INVALID_LAYOUT; + case View.FOCUS_DOWN: + return mOrientation == VERTICAL ? LayoutState.LAYOUT_END + : LayoutState.INVALID_LAYOUT; + case View.FOCUS_LEFT: + return mOrientation == HORIZONTAL ? LayoutState.LAYOUT_START + : LayoutState.INVALID_LAYOUT; + case View.FOCUS_RIGHT: + return mOrientation == HORIZONTAL ? LayoutState.LAYOUT_END + : LayoutState.INVALID_LAYOUT; + default: + if (DEBUG) { + Log.d(TAG, "Unknown focus request:" + focusDirection); + } + return LayoutState.INVALID_LAYOUT; + } + + } + + /** + * Convenience method to find the child closes to start. Caller should check it has enough + * children. + * + * @return The child closes to start of the layout from user's perspective. + */ + private View getChildClosestToStart() { + return getChildAt(mShouldReverseLayout ? getChildCount() - 1 : 0); + } + + /** + * Convenience method to find the child closes to end. Caller should check it has enough + * children. + * + * @return The child closes to end of the layout from user's perspective. + */ + private View getChildClosestToEnd() { + return getChildAt(mShouldReverseLayout ? 0 : getChildCount() - 1); + } + + /** + * Convenience method to find the visible child closes to start. Caller should check if it has + * enough children. + * + * @param completelyVisible Whether child should be completely visible or not + * @return The first visible child closest to start of the layout from user's perspective. + */ + private View findFirstVisibleChildClosestToStart(boolean completelyVisible, + boolean acceptPartiallyVisible) { + if (mShouldReverseLayout) { + return findOneVisibleChild(getChildCount() - 1, -1, completelyVisible, + acceptPartiallyVisible); + } else { + return findOneVisibleChild(0, getChildCount(), completelyVisible, + acceptPartiallyVisible); + } + } + + /** + * Convenience method to find the visible child closes to end. Caller should check if it has + * enough children. + * + * @param completelyVisible Whether child should be completely visible or not + * @return The first visible child closest to end of the layout from user's perspective. + */ + private View findFirstVisibleChildClosestToEnd(boolean completelyVisible, + boolean acceptPartiallyVisible) { + if (mShouldReverseLayout) { + return findOneVisibleChild(0, getChildCount(), completelyVisible, + acceptPartiallyVisible); + } else { + return findOneVisibleChild(getChildCount() - 1, -1, completelyVisible, + acceptPartiallyVisible); + } + } + + + /** + * Among the children that are suitable to be considered as an anchor child, returns the one + * closest to the end of the layout. + *

+ * Due to ambiguous adapter updates or children being removed, some children's positions may be + * invalid. This method is a best effort to find a position within adapter bounds if possible. + *

+ * It also prioritizes children that are within the visible bounds. + * @return A View that can be used an an anchor View. + */ + private View findReferenceChildClosestToEnd(RecyclerView.Recycler recycler, + RecyclerView.State state) { + return mShouldReverseLayout ? findFirstReferenceChild(recycler, state) : + findLastReferenceChild(recycler, state); + } + + /** + * Among the children that are suitable to be considered as an anchor child, returns the one + * closest to the start of the layout. + *

+ * Due to ambiguous adapter updates or children being removed, some children's positions may be + * invalid. This method is a best effort to find a position within adapter bounds if possible. + *

+ * It also prioritizes children that are within the visible bounds. + * + * @return A View that can be used an an anchor View. + */ + private View findReferenceChildClosestToStart(RecyclerView.Recycler recycler, + RecyclerView.State state) { + return mShouldReverseLayout ? findLastReferenceChild(recycler, state) : + findFirstReferenceChild(recycler, state); + } + + private View findFirstReferenceChild(RecyclerView.Recycler recycler, RecyclerView.State state) { + return findReferenceChild(recycler, state, 0, getChildCount(), state.getItemCount()); + } + + private View findLastReferenceChild(RecyclerView.Recycler recycler, RecyclerView.State state) { + return findReferenceChild(recycler, state, getChildCount() - 1, -1, state.getItemCount()); + } + + // overridden by GridLayoutManager + View findReferenceChild(RecyclerView.Recycler recycler, RecyclerView.State state, + int start, int end, int itemCount) { + ensureLayoutState(); + View invalidMatch = null; + View outOfBoundsMatch = null; + final int boundsStart = mOrientationHelper.getStartAfterPadding(); + final int boundsEnd = mOrientationHelper.getEndAfterPadding(); + final int diff = end > start ? 1 : -1; + for (int i = start; i != end; i += diff) { + final View view = getChildAt(i); + final int position = getPosition(view); + if (position >= 0 && position < itemCount) { + if (((LayoutParams) view.getLayoutParams()).isItemRemoved()) { + if (invalidMatch == null) { + invalidMatch = view; // removed item, least preferred + } + } else if (mOrientationHelper.getDecoratedStart(view) >= boundsEnd || + mOrientationHelper.getDecoratedEnd(view) < boundsStart) { + if (outOfBoundsMatch == null) { + outOfBoundsMatch = view; // item is not visible, less preferred + } + } else { + return view; + } + } + } + return outOfBoundsMatch != null ? outOfBoundsMatch : invalidMatch; + } + + /** + * Returns the adapter position of the first visible view. This position does not include + * adapter changes that were dispatched after the last layout pass. + *

+ * Note that, this value is not affected by layout orientation or item order traversal. + * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, + * not in the layout. + *

+ * If RecyclerView has item decorators, they will be considered in calculations as well. + *

+ * LayoutManager may pre-cache some views that are not necessarily visible. Those views + * are ignored in this method. + * + * @return The adapter position of the first visible item or {@link RecyclerView#NO_POSITION} if + * there aren't any visible items. + * @see #findFirstCompletelyVisibleItemPosition() + * @see #findLastVisibleItemPosition() + */ + public int findFirstVisibleItemPosition() { + final View child = findOneVisibleChild(0, getChildCount(), false, true); + return child == null ? NO_POSITION : getPosition(child); + } + + /** + * Returns the adapter position of the first fully visible view. This position does not include + * adapter changes that were dispatched after the last layout pass. + *

+ * Note that bounds check is only performed in the current orientation. That means, if + * LayoutManager is horizontal, it will only check the view's left and right edges. + * + * @return The adapter position of the first fully visible item or + * {@link RecyclerView#NO_POSITION} if there aren't any visible items. + * @see #findFirstVisibleItemPosition() + * @see #findLastCompletelyVisibleItemPosition() + */ + public int findFirstCompletelyVisibleItemPosition() { + final View child = findOneVisibleChild(0, getChildCount(), true, false); + return child == null ? NO_POSITION : getPosition(child); + } + + /** + * Returns the adapter position of the last visible view. This position does not include + * adapter changes that were dispatched after the last layout pass. + *

+ * Note that, this value is not affected by layout orientation or item order traversal. + * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, + * not in the layout. + *

+ * If RecyclerView has item decorators, they will be considered in calculations as well. + *

+ * LayoutManager may pre-cache some views that are not necessarily visible. Those views + * are ignored in this method. + * + * @return The adapter position of the last visible view or {@link RecyclerView#NO_POSITION} if + * there aren't any visible items. + * @see #findLastCompletelyVisibleItemPosition() + * @see #findFirstVisibleItemPosition() + */ + public int findLastVisibleItemPosition() { + final View child = findOneVisibleChild(getChildCount() - 1, -1, false, true); + return child == null ? NO_POSITION : getPosition(child); + } + + /** + * Returns the adapter position of the last fully visible view. This position does not include + * adapter changes that were dispatched after the last layout pass. + *

+ * Note that bounds check is only performed in the current orientation. That means, if + * LayoutManager is horizontal, it will only check the view's left and right edges. + * + * @return The adapter position of the last fully visible view or + * {@link RecyclerView#NO_POSITION} if there aren't any visible items. + * @see #findLastVisibleItemPosition() + * @see #findFirstCompletelyVisibleItemPosition() + */ + public int findLastCompletelyVisibleItemPosition() { + final View child = findOneVisibleChild(getChildCount() - 1, -1, true, false); + return child == null ? NO_POSITION : getPosition(child); + } + + View findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible, + boolean acceptPartiallyVisible) { + ensureLayoutState(); + final int start = mOrientationHelper.getStartAfterPadding(); + final int end = mOrientationHelper.getEndAfterPadding(); + final int next = toIndex > fromIndex ? 1 : -1; + View partiallyVisible = null; + for (int i = fromIndex; i != toIndex; i+=next) { + final View child = getChildAt(i); + final int childStart = mOrientationHelper.getDecoratedStart(child); + final int childEnd = mOrientationHelper.getDecoratedEnd(child); + if (childStart < end && childEnd > start) { + if (completelyVisible) { + if (childStart >= start && childEnd <= end) { + return child; + } else if (acceptPartiallyVisible && partiallyVisible == null) { + partiallyVisible = child; + } + } else { + return child; + } + } + } + return partiallyVisible; + } + + @Override + public View onFocusSearchFailed(View focused, int focusDirection, + RecyclerView.Recycler recycler, RecyclerView.State state) { + resolveShouldLayoutReverse(); + if (getChildCount() == 0) { + return null; + } + + final int layoutDir = convertFocusDirectionToLayoutDirection(focusDirection); + if (layoutDir == LayoutState.INVALID_LAYOUT) { + return null; + } + ensureLayoutState(); + final View referenceChild; + if (layoutDir == LayoutState.LAYOUT_START) { + referenceChild = findReferenceChildClosestToStart(recycler, state); + } else { + referenceChild = findReferenceChildClosestToEnd(recycler, state); + } + if (referenceChild == null) { + if (DEBUG) { + Log.d(TAG, + "Cannot find a child with a valid position to be used for focus search."); + } + return null; + } + ensureLayoutState(); + final int maxScroll = (int) (MAX_SCROLL_FACTOR * mOrientationHelper.getTotalSpace()); + updateLayoutState(layoutDir, maxScroll, false, state); + mLayoutState.mScrollingOffset = LayoutState.SCOLLING_OFFSET_NaN; + mLayoutState.mRecycle = false; + fill(recycler, mLayoutState, state, true); + final View nextFocus; + if (layoutDir == LayoutState.LAYOUT_START) { + nextFocus = getChildClosestToStart(); + } else { + nextFocus = getChildClosestToEnd(); + } + if (nextFocus == referenceChild || !nextFocus.isFocusable()) { + return null; + } + return nextFocus; + } + + /** + * Used for debugging. + * Logs the internal representation of children to default logger. + */ + private void logChildren() { + Log.d(TAG, "internal representation of views on the screen"); + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + Log.d(TAG, "item " + getPosition(child) + ", coord:" + + mOrientationHelper.getDecoratedStart(child)); + } + Log.d(TAG, "=============="); + } + + /** + * Used for debugging. + * Validates that child views are laid out in correct order. This is important because rest of + * the algorithm relies on this constraint. + * + * In default layout, child 0 should be closest to screen position 0 and last child should be + * closest to position WIDTH or HEIGHT. + * In reverse layout, last child should be closes to screen position 0 and first child should + * be closest to position WIDTH or HEIGHT + */ + void validateChildOrder() { + Log.d(TAG, "validating child count " + getChildCount()); + if (getChildCount() < 1) { + return; + } + int lastPos = getPosition(getChildAt(0)); + int lastScreenLoc = mOrientationHelper.getDecoratedStart(getChildAt(0)); + if (mShouldReverseLayout) { + for (int i = 1; i < getChildCount(); i++) { + View child = getChildAt(i); + int pos = getPosition(child); + int screenLoc = mOrientationHelper.getDecoratedStart(child); + if (pos < lastPos) { + logChildren(); + throw new RuntimeException("detected invalid position. loc invalid? " + + (screenLoc < lastScreenLoc)); + } + if (screenLoc > lastScreenLoc) { + logChildren(); + throw new RuntimeException("detected invalid location"); + } + } + } else { + for (int i = 1; i < getChildCount(); i++) { + View child = getChildAt(i); + int pos = getPosition(child); + int screenLoc = mOrientationHelper.getDecoratedStart(child); + if (pos < lastPos) { + logChildren(); + throw new RuntimeException("detected invalid position. loc invalid? " + + (screenLoc < lastScreenLoc)); + } + if (screenLoc < lastScreenLoc) { + logChildren(); + throw new RuntimeException("detected invalid location"); + } + } + } + } + + @Override + public boolean supportsPredictiveItemAnimations() { + return mPendingSavedState == null && mLastStackFromEnd == mStackFromEnd; + } + + /** + * @hide This method should be called by ItemTouchHelper only. + */ + @Override + public void prepareForDrop(View view, View target, int x, int y) { + assertNotInLayoutOrScroll("Cannot drop a view during a scroll or layout calculation"); + ensureLayoutState(); + resolveShouldLayoutReverse(); + final int myPos = getPosition(view); + final int targetPos = getPosition(target); + final int dropDirection = myPos < targetPos ? LayoutState.ITEM_DIRECTION_TAIL : + LayoutState.ITEM_DIRECTION_HEAD; + if (mShouldReverseLayout) { + if (dropDirection == LayoutState.ITEM_DIRECTION_TAIL) { + scrollToPositionWithOffset(targetPos, + mOrientationHelper.getEndAfterPadding() - + (mOrientationHelper.getDecoratedStart(target) + + mOrientationHelper.getDecoratedMeasurement(view))); + } else { + scrollToPositionWithOffset(targetPos, + mOrientationHelper.getEndAfterPadding() - + mOrientationHelper.getDecoratedEnd(target)); + } + } else { + if (dropDirection == LayoutState.ITEM_DIRECTION_HEAD) { + scrollToPositionWithOffset(targetPos, mOrientationHelper.getDecoratedStart(target)); + } else { + scrollToPositionWithOffset(targetPos, + mOrientationHelper.getDecoratedEnd(target) - + mOrientationHelper.getDecoratedMeasurement(view)); + } + } + } + + /** + * Helper class that keeps temporary state while {LayoutManager} is filling out the empty + * space. + */ + static class LayoutState { + + final static String TAG = "LinearLayoutManager#LayoutState"; + + final static int LAYOUT_START = -1; + + final static int LAYOUT_END = 1; + + final static int INVALID_LAYOUT = Integer.MIN_VALUE; + + final static int ITEM_DIRECTION_HEAD = -1; + + final static int ITEM_DIRECTION_TAIL = 1; + + final static int SCOLLING_OFFSET_NaN = Integer.MIN_VALUE; + + /** + * We may not want to recycle children in some cases (e.g. layout) + */ + boolean mRecycle = true; + + /** + * Pixel offset where layout should start + */ + int mOffset; + + /** + * Number of pixels that we should fill, in the layout direction. + */ + int mAvailable; + + /** + * Current position on the adapter to get the next item. + */ + int mCurrentPosition; + + /** + * Defines the direction in which the data adapter is traversed. + * Should be {@link #ITEM_DIRECTION_HEAD} or {@link #ITEM_DIRECTION_TAIL} + */ + int mItemDirection; + + /** + * Defines the direction in which the layout is filled. + * Should be {@link #LAYOUT_START} or {@link #LAYOUT_END} + */ + int mLayoutDirection; + + /** + * Used when LayoutState is constructed in a scrolling state. + * It should be set the amount of scrolling we can make without creating a new view. + * Settings this is required for efficient view recycling. + */ + int mScrollingOffset; + + /** + * Used if you want to pre-layout items that are not yet visible. + * The difference with {@link #mAvailable} is that, when recycling, distance laid out for + * {@link #mExtra} is not considered to avoid recycling visible children. + */ + int mExtra = 0; + + /** + * Equal to {@link RecyclerView.State#isPreLayout()}. When consuming scrap, if this value + * is set to true, we skip removed views since they should not be laid out in post layout + * step. + */ + boolean mIsPreLayout = false; + + /** + * The most recent {@link #scrollBy(int, RecyclerView.Recycler, RecyclerView.State)} + * amount. + */ + int mLastScrollDelta; + + /** + * When LLM needs to layout particular views, it sets this list in which case, LayoutState + * will only return views from this list and return null if it cannot find an item. + */ + List mScrapList = null; + + /** + * Used when there is no limit in how many views can be laid out. + */ + boolean mInfinite; + + /** + * @return true if there are more items in the data adapter + */ + boolean hasMore(RecyclerView.State state) { + return mCurrentPosition >= 0 && mCurrentPosition < state.getItemCount(); + } + + /** + * Gets the view for the next element that we should layout. + * Also updates current item index to the next item, based on {@link #mItemDirection} + * + * @return The next element that we should layout. + */ + View next(RecyclerView.Recycler recycler) { + if (mScrapList != null) { + return nextViewFromScrapList(); + } + final View view = recycler.getViewForPosition(mCurrentPosition); + mCurrentPosition += mItemDirection; + return view; + } + + /** + * Returns the next item from the scrap list. + *

+ * Upon finding a valid VH, sets current item position to VH.itemPosition + mItemDirection + * + * @return View if an item in the current position or direction exists if not null. + */ + private View nextViewFromScrapList() { + final int size = mScrapList.size(); + for (int i = 0; i < size; i++) { + final View view = mScrapList.get(i).itemView; + final LayoutParams lp = (LayoutParams) view.getLayoutParams(); + if (lp.isItemRemoved()) { + continue; + } + if (mCurrentPosition == lp.getViewLayoutPosition()) { + assignPositionFromScrapList(view); + return view; + } + } + return null; + } + + public void assignPositionFromScrapList() { + assignPositionFromScrapList(null); + } + + public void assignPositionFromScrapList(View ignore) { + final View closest = nextViewInLimitedList(ignore); + if (closest == null) { + mCurrentPosition = NO_POSITION; + } else { + mCurrentPosition = ((LayoutParams) closest.getLayoutParams()) + .getViewLayoutPosition(); + } + } + + public View nextViewInLimitedList(View ignore) { + int size = mScrapList.size(); + View closest = null; + int closestDistance = Integer.MAX_VALUE; + if (DEBUG && mIsPreLayout) { + throw new IllegalStateException("Scrap list cannot be used in pre layout"); + } + for (int i = 0; i < size; i++) { + View view = mScrapList.get(i).itemView; + final LayoutParams lp = (LayoutParams) view.getLayoutParams(); + if (view == ignore || lp.isItemRemoved()) { + continue; + } + final int distance = (lp.getViewLayoutPosition() - mCurrentPosition) * + mItemDirection; + if (distance < 0) { + continue; // item is not in current direction + } + if (distance < closestDistance) { + closest = view; + closestDistance = distance; + if (distance == 0) { + break; + } + } + } + return closest; + } + + void log() { + Log.d(TAG, "avail:" + mAvailable + ", ind:" + mCurrentPosition + ", dir:" + + mItemDirection + ", offset:" + mOffset + ", layoutDir:" + mLayoutDirection); + } + } + + /** + * @hide + */ + public static class SavedState implements Parcelable { + + int mAnchorPosition; + + int mAnchorOffset; + + boolean mAnchorLayoutFromEnd; + + public SavedState() { + + } + + SavedState(Parcel in) { + mAnchorPosition = in.readInt(); + mAnchorOffset = in.readInt(); + mAnchorLayoutFromEnd = in.readInt() == 1; + } + + public SavedState(SavedState other) { + mAnchorPosition = other.mAnchorPosition; + mAnchorOffset = other.mAnchorOffset; + mAnchorLayoutFromEnd = other.mAnchorLayoutFromEnd; + } + + boolean hasValidAnchor() { + return mAnchorPosition >= 0; + } + + void invalidateAnchor() { + mAnchorPosition = NO_POSITION; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mAnchorPosition); + dest.writeInt(mAnchorOffset); + dest.writeInt(mAnchorLayoutFromEnd ? 1 : 0); + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + /** + * Simple data class to keep Anchor information + */ + class AnchorInfo { + int mPosition; + int mCoordinate; + boolean mLayoutFromEnd; + void reset() { + mPosition = NO_POSITION; + mCoordinate = INVALID_OFFSET; + mLayoutFromEnd = false; + } + + /** + * assigns anchor coordinate from the RecyclerView's padding depending on current + * layoutFromEnd value + */ + void assignCoordinateFromPadding() { + mCoordinate = mLayoutFromEnd + ? mOrientationHelper.getEndAfterPadding() + : mOrientationHelper.getStartAfterPadding(); + } + + @Override + public String toString() { + return "AnchorInfo{" + + "mPosition=" + mPosition + + ", mCoordinate=" + mCoordinate + + ", mLayoutFromEnd=" + mLayoutFromEnd + + '}'; + } + + private boolean isViewValidAsAnchor(View child, RecyclerView.State state) { + LayoutParams lp = (LayoutParams) child.getLayoutParams(); + return !lp.isItemRemoved() && lp.getViewLayoutPosition() >= 0 + && lp.getViewLayoutPosition() < state.getItemCount(); + } + + public void assignFromViewAndKeepVisibleRect(View child) { + final int spaceChange = mOrientationHelper.getTotalSpaceChange(); + if (spaceChange >= 0) { + assignFromView(child); + return; + } + mPosition = getPosition(child); + if (mLayoutFromEnd) { + final int prevLayoutEnd = mOrientationHelper.getEndAfterPadding() - spaceChange; + final int childEnd = mOrientationHelper.getDecoratedEnd(child); + final int previousEndMargin = prevLayoutEnd - childEnd; + mCoordinate = mOrientationHelper.getEndAfterPadding() - previousEndMargin; + // ensure we did not push child's top out of bounds because of this + if (previousEndMargin > 0) {// we have room to shift bottom if necessary + final int childSize = mOrientationHelper.getDecoratedMeasurement(child); + final int estimatedChildStart = mCoordinate - childSize; + final int layoutStart = mOrientationHelper.getStartAfterPadding(); + final int previousStartMargin = mOrientationHelper.getDecoratedStart(child) - + layoutStart; + final int startReference = layoutStart + Math.min(previousStartMargin, 0); + final int startMargin = estimatedChildStart - startReference; + if (startMargin < 0) { + // offset to make top visible but not too much + mCoordinate += Math.min(previousEndMargin, -startMargin); + } + } + } else { + final int childStart = mOrientationHelper.getDecoratedStart(child); + final int startMargin = childStart - mOrientationHelper.getStartAfterPadding(); + mCoordinate = childStart; + if (startMargin > 0) { // we have room to fix end as well + final int estimatedEnd = childStart + + mOrientationHelper.getDecoratedMeasurement(child); + final int previousLayoutEnd = mOrientationHelper.getEndAfterPadding() - + spaceChange; + final int previousEndMargin = previousLayoutEnd - + mOrientationHelper.getDecoratedEnd(child); + final int endReference = mOrientationHelper.getEndAfterPadding() - + Math.min(0, previousEndMargin); + final int endMargin = endReference - estimatedEnd; + if (endMargin < 0) { + mCoordinate -= Math.min(startMargin, -endMargin); + } + } + } + } + + public void assignFromView(View child) { + if (mLayoutFromEnd) { + mCoordinate = mOrientationHelper.getDecoratedEnd(child) + + mOrientationHelper.getTotalSpaceChange(); + } else { + mCoordinate = mOrientationHelper.getDecoratedStart(child); + } + + mPosition = getPosition(child); + } + } + + protected static class LayoutChunkResult { + public int mConsumed; + public boolean mFinished; + public boolean mIgnoreConsumed; + public boolean mFocusable; + + void resetInternal() { + mConsumed = 0; + mFinished = false; + mIgnoreConsumed = false; + mFocusable = false; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/LinearSmoothScroller.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/LinearSmoothScroller.java new file mode 100644 index 00000000..e5a61118 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/LinearSmoothScroller.java @@ -0,0 +1,339 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.widget; + +import android.content.Context; +import android.graphics.PointF; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.View; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.LinearInterpolator; + +/** + * {@link RecyclerView.SmoothScroller} implementation which uses + * {@link android.view.animation.LinearInterpolator} until the target position becames a child of + * the RecyclerView and then uses + * {@link android.view.animation.DecelerateInterpolator} to slowly approach to target position. + */ +abstract public class LinearSmoothScroller extends RecyclerView.SmoothScroller { + + private static final String TAG = "LinearSmoothScroller"; + + private static final boolean DEBUG = false; + + private static final float MILLISECONDS_PER_INCH = 25f; + + private static final int TARGET_SEEK_SCROLL_DISTANCE_PX = 10000; + + /** + * Align child view's left or top with parent view's left or top + * + * @see #calculateDtToFit(int, int, int, int, int) + * @see #calculateDxToMakeVisible(android.view.View, int) + * @see #calculateDyToMakeVisible(android.view.View, int) + */ + public static final int SNAP_TO_START = -1; + + /** + * Align child view's right or bottom with parent view's right or bottom + * + * @see #calculateDtToFit(int, int, int, int, int) + * @see #calculateDxToMakeVisible(android.view.View, int) + * @see #calculateDyToMakeVisible(android.view.View, int) + */ + public static final int SNAP_TO_END = 1; + + /** + *

Decides if the child should be snapped from start or end, depending on where it + * currently is in relation to its parent.

+ *

For instance, if the view is virtually on the left of RecyclerView, using + * {@code SNAP_TO_ANY} is the same as using {@code SNAP_TO_START}

+ * + * @see #calculateDtToFit(int, int, int, int, int) + * @see #calculateDxToMakeVisible(android.view.View, int) + * @see #calculateDyToMakeVisible(android.view.View, int) + */ + public static final int SNAP_TO_ANY = 0; + + // Trigger a scroll to a further distance than TARGET_SEEK_SCROLL_DISTANCE_PX so that if target + // view is not laid out until interim target position is reached, we can detect the case before + // scrolling slows down and reschedule another interim target scroll + private static final float TARGET_SEEK_EXTRA_SCROLL_RATIO = 1.2f; + + protected final LinearInterpolator mLinearInterpolator = new LinearInterpolator(); + + protected final DecelerateInterpolator mDecelerateInterpolator = new DecelerateInterpolator(); + + protected PointF mTargetVector; + + private final float MILLISECONDS_PER_PX; + + // Temporary variables to keep track of the interim scroll target. These values do not + // point to a real item position, rather point to an estimated location pixels. + protected int mInterimTargetDx = 0, mInterimTargetDy = 0; + + public LinearSmoothScroller(Context context) { + MILLISECONDS_PER_PX = calculateSpeedPerPixel(context.getResources().getDisplayMetrics()); + } + + /** + * {@inheritDoc} + */ + @Override + protected void onStart() { + + } + + /** + * {@inheritDoc} + */ + @Override + protected void onTargetFound(View targetView, RecyclerView.State state, Action action) { + final int dx = calculateDxToMakeVisible(targetView, getHorizontalSnapPreference()); + final int dy = calculateDyToMakeVisible(targetView, getVerticalSnapPreference()); + final int distance = (int) Math.sqrt(dx * dx + dy * dy); + final int time = calculateTimeForDeceleration(distance); + if (time > 0) { + action.update(-dx, -dy, time, mDecelerateInterpolator); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void onSeekTargetStep(int dx, int dy, RecyclerView.State state, Action action) { + if (getChildCount() == 0) { + stop(); + return; + } + //noinspection PointlessBooleanExpression + if (DEBUG && mTargetVector != null + && ((mTargetVector.x * dx < 0 || mTargetVector.y * dy < 0))) { + throw new IllegalStateException("Scroll happened in the opposite direction" + + " of the target. Some calculations are wrong"); + } + mInterimTargetDx = clampApplyScroll(mInterimTargetDx, dx); + mInterimTargetDy = clampApplyScroll(mInterimTargetDy, dy); + + if (mInterimTargetDx == 0 && mInterimTargetDy == 0) { + updateActionForInterimTarget(action); + } // everything is valid, keep going + + } + + /** + * {@inheritDoc} + */ + @Override + protected void onStop() { + mInterimTargetDx = mInterimTargetDy = 0; + mTargetVector = null; + } + + /** + * Calculates the scroll speed. + * + * @param displayMetrics DisplayMetrics to be used for real dimension calculations + * @return The time (in ms) it should take for each pixel. For instance, if returned value is + * 2 ms, it means scrolling 1000 pixels with LinearInterpolation should take 2 seconds. + */ + protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { + return MILLISECONDS_PER_INCH / displayMetrics.densityDpi; + } + + /** + *

Calculates the time for deceleration so that transition from LinearInterpolator to + * DecelerateInterpolator looks smooth.

+ * + * @param dx Distance to scroll + * @return Time for DecelerateInterpolator to smoothly traverse the distance when transitioning + * from LinearInterpolation + */ + protected int calculateTimeForDeceleration(int dx) { + // we want to cover same area with the linear interpolator for the first 10% of the + // interpolation. After that, deceleration will take control. + // area under curve (1-(1-x)^2) can be calculated as (1 - x/3) * x * x + // which gives 0.100028 when x = .3356 + // this is why we divide linear scrolling time with .3356 + return (int) Math.ceil(calculateTimeForScrolling(dx) / .3356); + } + + /** + * Calculates the time it should take to scroll the given distance (in pixels) + * + * @param dx Distance in pixels that we want to scroll + * @return Time in milliseconds + * @see #calculateSpeedPerPixel(android.util.DisplayMetrics) + */ + protected int calculateTimeForScrolling(int dx) { + // In a case where dx is very small, rounding may return 0 although dx > 0. + // To avoid that issue, ceil the result so that if dx > 0, we'll always return positive + // time. + return (int) Math.ceil(Math.abs(dx) * MILLISECONDS_PER_PX); + } + + /** + * When scrolling towards a child view, this method defines whether we should align the left + * or the right edge of the child with the parent RecyclerView. + * + * @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY; depending on the current target vector + * @see #SNAP_TO_START + * @see #SNAP_TO_END + * @see #SNAP_TO_ANY + */ + protected int getHorizontalSnapPreference() { + return mTargetVector == null || mTargetVector.x == 0 ? SNAP_TO_ANY : + mTargetVector.x > 0 ? SNAP_TO_END : SNAP_TO_START; + } + + /** + * When scrolling towards a child view, this method defines whether we should align the top + * or the bottom edge of the child with the parent RecyclerView. + * + * @return SNAP_TO_START, SNAP_TO_END or SNAP_TO_ANY; depending on the current target vector + * @see #SNAP_TO_START + * @see #SNAP_TO_END + * @see #SNAP_TO_ANY + */ + protected int getVerticalSnapPreference() { + return mTargetVector == null || mTargetVector.y == 0 ? SNAP_TO_ANY : + mTargetVector.y > 0 ? SNAP_TO_END : SNAP_TO_START; + } + + /** + * When the target scroll position is not a child of the RecyclerView, this method calculates + * a direction vector towards that child and triggers a smooth scroll. + * + * @see #computeScrollVectorForPosition(int) + */ + protected void updateActionForInterimTarget(Action action) { + // find an interim target position + PointF scrollVector = computeScrollVectorForPosition(getTargetPosition()); + if (scrollVector == null || (scrollVector.x == 0 && scrollVector.y == 0)) { + Log.e(TAG, "To support smooth scrolling, you should override \n" + + "LayoutManager#computeScrollVectorForPosition.\n" + + "Falling back to instant scroll"); + final int target = getTargetPosition(); + action.jumpTo(target); + stop(); + return; + } + normalize(scrollVector); + mTargetVector = scrollVector; + + mInterimTargetDx = (int) (TARGET_SEEK_SCROLL_DISTANCE_PX * scrollVector.x); + mInterimTargetDy = (int) (TARGET_SEEK_SCROLL_DISTANCE_PX * scrollVector.y); + final int time = calculateTimeForScrolling(TARGET_SEEK_SCROLL_DISTANCE_PX); + // To avoid UI hiccups, trigger a smooth scroll to a distance little further than the + // interim target. Since we track the distance travelled in onSeekTargetStep callback, it + // won't actually scroll more than what we need. + action.update((int) (mInterimTargetDx * TARGET_SEEK_EXTRA_SCROLL_RATIO) + , (int) (mInterimTargetDy * TARGET_SEEK_EXTRA_SCROLL_RATIO) + , (int) (time * TARGET_SEEK_EXTRA_SCROLL_RATIO), mLinearInterpolator); + } + + private int clampApplyScroll(int tmpDt, int dt) { + final int before = tmpDt; + tmpDt -= dt; + if (before * tmpDt <= 0) { // changed sign, reached 0 or was 0, reset + return 0; + } + return tmpDt; + } + + /** + * Helper method for {@link #calculateDxToMakeVisible(android.view.View, int)} and + * {@link #calculateDyToMakeVisible(android.view.View, int)} + */ + public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int + snapPreference) { + switch (snapPreference) { + case SNAP_TO_START: + return boxStart - viewStart; + case SNAP_TO_END: + return boxEnd - viewEnd; + case SNAP_TO_ANY: + final int dtStart = boxStart - viewStart; + if (dtStart > 0) { + return dtStart; + } + final int dtEnd = boxEnd - viewEnd; + if (dtEnd < 0) { + return dtEnd; + } + break; + default: + throw new IllegalArgumentException("snap preference should be one of the" + + " constants defined in SmoothScroller, starting with SNAP_"); + } + return 0; + } + + /** + * Calculates the vertical scroll amount necessary to make the given view fully visible + * inside the RecyclerView. + * + * @param view The view which we want to make fully visible + * @param snapPreference The edge which the view should snap to when entering the visible + * area. One of {@link #SNAP_TO_START}, {@link #SNAP_TO_END} or + * {@link #SNAP_TO_ANY}. + * @return The vertical scroll amount necessary to make the view visible with the given + * snap preference. + */ + public int calculateDyToMakeVisible(View view, int snapPreference) { + final RecyclerView.LayoutManager layoutManager = getLayoutManager(); + if (layoutManager == null || !layoutManager.canScrollVertically()) { + return 0; + } + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + final int top = layoutManager.getDecoratedTop(view) - params.topMargin; + final int bottom = layoutManager.getDecoratedBottom(view) + params.bottomMargin; + final int start = layoutManager.getPaddingTop(); + final int end = layoutManager.getHeight() - layoutManager.getPaddingBottom(); + return calculateDtToFit(top, bottom, start, end, snapPreference); + } + + /** + * Calculates the horizontal scroll amount necessary to make the given view fully visible + * inside the RecyclerView. + * + * @param view The view which we want to make fully visible + * @param snapPreference The edge which the view should snap to when entering the visible + * area. One of {@link #SNAP_TO_START}, {@link #SNAP_TO_END} or + * {@link #SNAP_TO_END} + * @return The vertical scroll amount necessary to make the view visible with the given + * snap preference. + */ + public int calculateDxToMakeVisible(View view, int snapPreference) { + final RecyclerView.LayoutManager layoutManager = getLayoutManager(); + if (layoutManager == null || !layoutManager.canScrollHorizontally()) { + return 0; + } + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + final int left = layoutManager.getDecoratedLeft(view) - params.leftMargin; + final int right = layoutManager.getDecoratedRight(view) + params.rightMargin; + final int start = layoutManager.getPaddingLeft(); + final int end = layoutManager.getWidth() - layoutManager.getPaddingRight(); + return calculateDtToFit(left, right, start, end, snapPreference); + } + + abstract public PointF computeScrollVectorForPosition(int targetPosition); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/OpReorderer.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/OpReorderer.java new file mode 100644 index 00000000..b2e508a2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/OpReorderer.java @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.widget; + +import java.util.List; + +import org.telegram.messenger.support.widget.AdapterHelper.UpdateOp; +import static org.telegram.messenger.support.widget.AdapterHelper.UpdateOp.ADD; +import static org.telegram.messenger.support.widget.AdapterHelper.UpdateOp.MOVE; +import static org.telegram.messenger.support.widget.AdapterHelper.UpdateOp.REMOVE; +import static org.telegram.messenger.support.widget.AdapterHelper.UpdateOp.UPDATE; + +class OpReorderer { + + final Callback mCallback; + + public OpReorderer(Callback callback) { + mCallback = callback; + } + + void reorderOps(List ops) { + // since move operations breaks continuity, their effects on ADD/RM are hard to handle. + // we push them to the end of the list so that they can be handled easily. + int badMove; + while ((badMove = getLastMoveOutOfOrder(ops)) != -1) { + swapMoveOp(ops, badMove, badMove + 1); + } + } + + private void swapMoveOp(List list, int badMove, int next) { + final UpdateOp moveOp = list.get(badMove); + final UpdateOp nextOp = list.get(next); + switch (nextOp.cmd) { + case REMOVE: + swapMoveRemove(list, badMove, moveOp, next, nextOp); + break; + case ADD: + swapMoveAdd(list, badMove, moveOp, next, nextOp); + break; + case UPDATE: + swapMoveUpdate(list, badMove, moveOp, next, nextOp); + break; + } + } + + void swapMoveRemove(List list, int movePos, UpdateOp moveOp, + int removePos, UpdateOp removeOp) { + UpdateOp extraRm = null; + // check if move is nulled out by remove + boolean revertedMove = false; + final boolean moveIsBackwards; + + if (moveOp.positionStart < moveOp.itemCount) { + moveIsBackwards = false; + if (removeOp.positionStart == moveOp.positionStart + && removeOp.itemCount == moveOp.itemCount - moveOp.positionStart) { + revertedMove = true; + } + } else { + moveIsBackwards = true; + if (removeOp.positionStart == moveOp.itemCount + 1 && + removeOp.itemCount == moveOp.positionStart - moveOp.itemCount) { + revertedMove = true; + } + } + + // going in reverse, first revert the effect of add + if (moveOp.itemCount < removeOp.positionStart) { + removeOp.positionStart--; + } else if (moveOp.itemCount < removeOp.positionStart + removeOp.itemCount) { + // move is removed. + removeOp.itemCount --; + moveOp.cmd = REMOVE; + moveOp.itemCount = 1; + if (removeOp.itemCount == 0) { + list.remove(removePos); + mCallback.recycleUpdateOp(removeOp); + } + // no need to swap, it is already a remove + return; + } + + // now affect of add is consumed. now apply effect of first remove + if (moveOp.positionStart <= removeOp.positionStart) { + removeOp.positionStart++; + } else if (moveOp.positionStart < removeOp.positionStart + removeOp.itemCount) { + final int remaining = removeOp.positionStart + removeOp.itemCount + - moveOp.positionStart; + extraRm = mCallback.obtainUpdateOp(REMOVE, moveOp.positionStart + 1, remaining, null); + removeOp.itemCount = moveOp.positionStart - removeOp.positionStart; + } + + // if effects of move is reverted by remove, we are done. + if (revertedMove) { + list.set(movePos, removeOp); + list.remove(removePos); + mCallback.recycleUpdateOp(moveOp); + return; + } + + // now find out the new locations for move actions + if (moveIsBackwards) { + if (extraRm != null) { + if (moveOp.positionStart > extraRm.positionStart) { + moveOp.positionStart -= extraRm.itemCount; + } + if (moveOp.itemCount > extraRm.positionStart) { + moveOp.itemCount -= extraRm.itemCount; + } + } + if (moveOp.positionStart > removeOp.positionStart) { + moveOp.positionStart -= removeOp.itemCount; + } + if (moveOp.itemCount > removeOp.positionStart) { + moveOp.itemCount -= removeOp.itemCount; + } + } else { + if (extraRm != null) { + if (moveOp.positionStart >= extraRm.positionStart) { + moveOp.positionStart -= extraRm.itemCount; + } + if (moveOp.itemCount >= extraRm.positionStart) { + moveOp.itemCount -= extraRm.itemCount; + } + } + if (moveOp.positionStart >= removeOp.positionStart) { + moveOp.positionStart -= removeOp.itemCount; + } + if (moveOp.itemCount >= removeOp.positionStart) { + moveOp.itemCount -= removeOp.itemCount; + } + } + + list.set(movePos, removeOp); + if (moveOp.positionStart != moveOp.itemCount) { + list.set(removePos, moveOp); + } else { + list.remove(removePos); + } + if (extraRm != null) { + list.add(movePos, extraRm); + } + } + + private void swapMoveAdd(List list, int move, UpdateOp moveOp, int add, + UpdateOp addOp) { + int offset = 0; + // going in reverse, first revert the effect of add + if (moveOp.itemCount < addOp.positionStart) { + offset--; + } + if (moveOp.positionStart < addOp.positionStart) { + offset++; + } + if (addOp.positionStart <= moveOp.positionStart) { + moveOp.positionStart += addOp.itemCount; + } + if (addOp.positionStart <= moveOp.itemCount) { + moveOp.itemCount += addOp.itemCount; + } + addOp.positionStart += offset; + list.set(move, addOp); + list.set(add, moveOp); + } + + void swapMoveUpdate(List list, int move, UpdateOp moveOp, int update, + UpdateOp updateOp) { + UpdateOp extraUp1 = null; + UpdateOp extraUp2 = null; + // going in reverse, first revert the effect of add + if (moveOp.itemCount < updateOp.positionStart) { + updateOp.positionStart--; + } else if (moveOp.itemCount < updateOp.positionStart + updateOp.itemCount) { + // moved item is updated. add an update for it + updateOp.itemCount--; + extraUp1 = mCallback.obtainUpdateOp(UPDATE, moveOp.positionStart, 1, updateOp.payload); + } + // now affect of add is consumed. now apply effect of first remove + if (moveOp.positionStart <= updateOp.positionStart) { + updateOp.positionStart++; + } else if (moveOp.positionStart < updateOp.positionStart + updateOp.itemCount) { + final int remaining = updateOp.positionStart + updateOp.itemCount + - moveOp.positionStart; + extraUp2 = mCallback.obtainUpdateOp(UPDATE, moveOp.positionStart + 1, remaining, + updateOp.payload); + updateOp.itemCount -= remaining; + } + list.set(update, moveOp); + if (updateOp.itemCount > 0) { + list.set(move, updateOp); + } else { + list.remove(move); + mCallback.recycleUpdateOp(updateOp); + } + if (extraUp1 != null) { + list.add(move, extraUp1); + } + if (extraUp2 != null) { + list.add(move, extraUp2); + } + } + + private int getLastMoveOutOfOrder(List list) { + boolean foundNonMove = false; + for (int i = list.size() - 1; i >= 0; i--) { + final UpdateOp op1 = list.get(i); + if (op1.cmd == MOVE) { + if (foundNonMove) { + return i; + } + } else { + foundNonMove = true; + } + } + return -1; + } + + static interface Callback { + + UpdateOp obtainUpdateOp(int cmd, int startPosition, int itemCount, Object payload); + + void recycleUpdateOp(UpdateOp op); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/OrientationHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/OrientationHelper.java new file mode 100644 index 00000000..1c8aa4a9 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/OrientationHelper.java @@ -0,0 +1,380 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.widget; + +import android.view.View; +import android.widget.LinearLayout; + +/** + * Helper class for LayoutManagers to abstract measurements depending on the View's orientation. + *

+ * It is developed to easily support vertical and horizontal orientations in a LayoutManager but + * can also be used to abstract calls around view bounds and child measurements with margins and + * decorations. + * + * @see #createHorizontalHelper(RecyclerView.LayoutManager) + * @see #createVerticalHelper(RecyclerView.LayoutManager) + */ +public abstract class OrientationHelper { + + private static final int INVALID_SIZE = Integer.MIN_VALUE; + + protected final RecyclerView.LayoutManager mLayoutManager; + + public static final int HORIZONTAL = LinearLayout.HORIZONTAL; + + public static final int VERTICAL = LinearLayout.VERTICAL; + + private int mLastTotalSpace = INVALID_SIZE; + + private OrientationHelper(RecyclerView.LayoutManager layoutManager) { + mLayoutManager = layoutManager; + } + + /** + * Call this method after onLayout method is complete if state is NOT pre-layout. + * This method records information like layout bounds that might be useful in the next layout + * calculations. + */ + public void onLayoutComplete() { + mLastTotalSpace = getTotalSpace(); + } + + /** + * Returns the layout space change between the previous layout pass and current layout pass. + *

+ * Make sure you call {@link #onLayoutComplete()} at the end of your LayoutManager's + * {@link RecyclerView.LayoutManager#onLayoutChildren(RecyclerView.Recycler, + * RecyclerView.State)} method. + * + * @return The difference between the current total space and previous layout's total space. + * @see #onLayoutComplete() + */ + public int getTotalSpaceChange() { + return INVALID_SIZE == mLastTotalSpace ? 0 : getTotalSpace() - mLastTotalSpace; + } + + /** + * Returns the start of the view including its decoration and margin. + *

+ * For example, for the horizontal helper, if a View's left is at pixel 20, has 2px left + * decoration and 3px left margin, returned value will be 15px. + * + * @param view The view element to check + * @return The first pixel of the element + * @see #getDecoratedEnd(android.view.View) + */ + public abstract int getDecoratedStart(View view); + + /** + * Returns the end of the view including its decoration and margin. + *

+ * For example, for the horizontal helper, if a View's right is at pixel 200, has 2px right + * decoration and 3px right margin, returned value will be 205. + * + * @param view The view element to check + * @return The last pixel of the element + * @see #getDecoratedStart(android.view.View) + */ + public abstract int getDecoratedEnd(View view); + + /** + * Returns the space occupied by this View in the current orientation including decorations and + * margins. + * + * @param view The view element to check + * @return Total space occupied by this view + * @see #getDecoratedMeasurementInOther(View) + */ + public abstract int getDecoratedMeasurement(View view); + + /** + * Returns the space occupied by this View in the perpendicular orientation including + * decorations and margins. + * + * @param view The view element to check + * @return Total space occupied by this view in the perpendicular orientation to current one + * @see #getDecoratedMeasurement(View) + */ + public abstract int getDecoratedMeasurementInOther(View view); + + /** + * Returns the start position of the layout after the start padding is added. + * + * @return The very first pixel we can draw. + */ + public abstract int getStartAfterPadding(); + + /** + * Returns the end position of the layout after the end padding is removed. + * + * @return The end boundary for this layout. + */ + public abstract int getEndAfterPadding(); + + /** + * Returns the end position of the layout without taking padding into account. + * + * @return The end boundary for this layout without considering padding. + */ + public abstract int getEnd(); + + /** + * Offsets all children's positions by the given amount. + * + * @param amount Value to add to each child's layout parameters + */ + public abstract void offsetChildren(int amount); + + /** + * Returns the total space to layout. This number is the difference between + * {@link #getEndAfterPadding()} and {@link #getStartAfterPadding()}. + * + * @return Total space to layout children + */ + public abstract int getTotalSpace(); + + /** + * Offsets the child in this orientation. + * + * @param view View to offset + * @param offset offset amount + */ + public abstract void offsetChild(View view, int offset); + + /** + * Returns the padding at the end of the layout. For horizontal helper, this is the right + * padding and for vertical helper, this is the bottom padding. This method does not check + * whether the layout is RTL or not. + * + * @return The padding at the end of the layout. + */ + public abstract int getEndPadding(); + + /** + * Returns the MeasureSpec mode for the current orientation from the LayoutManager. + * + * @return The current measure spec mode. + * + * @see View.MeasureSpec + * @see RecyclerView.LayoutManager#getWidthMode() + * @see RecyclerView.LayoutManager#getHeightMode() + */ + public abstract int getMode(); + + /** + * Returns the MeasureSpec mode for the perpendicular orientation from the LayoutManager. + * + * @return The current measure spec mode. + * + * @see View.MeasureSpec + * @see RecyclerView.LayoutManager#getWidthMode() + * @see RecyclerView.LayoutManager#getHeightMode() + */ + public abstract int getModeInOther(); + + /** + * Creates an OrientationHelper for the given LayoutManager and orientation. + * + * @param layoutManager LayoutManager to attach to + * @param orientation Desired orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL} + * @return A new OrientationHelper + */ + public static OrientationHelper createOrientationHelper( + RecyclerView.LayoutManager layoutManager, int orientation) { + switch (orientation) { + case HORIZONTAL: + return createHorizontalHelper(layoutManager); + case VERTICAL: + return createVerticalHelper(layoutManager); + } + throw new IllegalArgumentException("invalid orientation"); + } + + /** + * Creates a horizontal OrientationHelper for the given LayoutManager. + * + * @param layoutManager The LayoutManager to attach to. + * @return A new OrientationHelper + */ + public static OrientationHelper createHorizontalHelper( + RecyclerView.LayoutManager layoutManager) { + return new OrientationHelper(layoutManager) { + @Override + public int getEndAfterPadding() { + return mLayoutManager.getWidth() - mLayoutManager.getPaddingRight(); + } + + @Override + public int getEnd() { + return mLayoutManager.getWidth(); + } + + @Override + public void offsetChildren(int amount) { + mLayoutManager.offsetChildrenHorizontal(amount); + } + + @Override + public int getStartAfterPadding() { + return mLayoutManager.getPaddingLeft(); + } + + @Override + public int getDecoratedMeasurement(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedMeasuredWidth(view) + params.leftMargin + + params.rightMargin; + } + + @Override + public int getDecoratedMeasurementInOther(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedMeasuredHeight(view) + params.topMargin + + params.bottomMargin; + } + + @Override + public int getDecoratedEnd(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedRight(view) + params.rightMargin; + } + + @Override + public int getDecoratedStart(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedLeft(view) - params.leftMargin; + } + + @Override + public int getTotalSpace() { + return mLayoutManager.getWidth() - mLayoutManager.getPaddingLeft() + - mLayoutManager.getPaddingRight(); + } + + @Override + public void offsetChild(View view, int offset) { + view.offsetLeftAndRight(offset); + } + + @Override + public int getEndPadding() { + return mLayoutManager.getPaddingRight(); + } + + @Override + public int getMode() { + return mLayoutManager.getWidthMode(); + } + + @Override + public int getModeInOther() { + return mLayoutManager.getHeightMode(); + } + }; + } + + /** + * Creates a vertical OrientationHelper for the given LayoutManager. + * + * @param layoutManager The LayoutManager to attach to. + * @return A new OrientationHelper + */ + public static OrientationHelper createVerticalHelper(RecyclerView.LayoutManager layoutManager) { + return new OrientationHelper(layoutManager) { + @Override + public int getEndAfterPadding() { + return mLayoutManager.getHeight() - mLayoutManager.getPaddingBottom(); + } + + @Override + public int getEnd() { + return mLayoutManager.getHeight(); + } + + @Override + public void offsetChildren(int amount) { + mLayoutManager.offsetChildrenVertical(amount); + } + + @Override + public int getStartAfterPadding() { + return mLayoutManager.getPaddingTop(); + } + + @Override + public int getDecoratedMeasurement(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedMeasuredHeight(view) + params.topMargin + + params.bottomMargin; + } + + @Override + public int getDecoratedMeasurementInOther(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedMeasuredWidth(view) + params.leftMargin + + params.rightMargin; + } + + @Override + public int getDecoratedEnd(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedBottom(view) + params.bottomMargin; + } + + @Override + public int getDecoratedStart(View view) { + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) + view.getLayoutParams(); + return mLayoutManager.getDecoratedTop(view) - params.topMargin; + } + + @Override + public int getTotalSpace() { + return mLayoutManager.getHeight() - mLayoutManager.getPaddingTop() + - mLayoutManager.getPaddingBottom(); + } + + @Override + public void offsetChild(View view, int offset) { + view.offsetTopAndBottom(offset); + } + + @Override + public int getEndPadding() { + return mLayoutManager.getPaddingBottom(); + } + + @Override + public int getMode() { + return mLayoutManager.getHeightMode(); + } + + @Override + public int getModeInOther() { + return mLayoutManager.getWidthMode(); + } + }; + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/PositionMap.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/PositionMap.java new file mode 100644 index 00000000..fc98b3f8 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/PositionMap.java @@ -0,0 +1,460 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.telegram.messenger.support.widget; + +import java.util.ArrayList; + +/** + * Like a SparseArray, but with the ability to offset key ranges for bulk insertions/deletions. + */ +class PositionMap implements Cloneable { + private static final Object DELETED = new Object(); + private boolean mGarbage = false; + + private int[] mKeys; + private Object[] mValues; + private int mSize; + + /** + * Creates a new SparseArray containing no mappings. + */ + public PositionMap() { + this(10); + } + + /** + * Creates a new PositionMap containing no mappings that will not + * require any additional memory allocation to store the specified + * number of mappings. If you supply an initial capacity of 0, the + * sparse array will be initialized with a light-weight representation + * not requiring any additional array allocations. + */ + public PositionMap(int initialCapacity) { + if (initialCapacity == 0) { + mKeys = ContainerHelpers.EMPTY_INTS; + mValues = ContainerHelpers.EMPTY_OBJECTS; + } else { + initialCapacity = idealIntArraySize(initialCapacity); + mKeys = new int[initialCapacity]; + mValues = new Object[initialCapacity]; + } + mSize = 0; + } + + @Override + @SuppressWarnings("unchecked") + public PositionMap clone() { + PositionMap clone = null; + try { + clone = (PositionMap) super.clone(); + clone.mKeys = mKeys.clone(); + clone.mValues = mValues.clone(); + } catch (CloneNotSupportedException cnse) { + /* ignore */ + } + return clone; + } + + /** + * Gets the Object mapped from the specified key, or null + * if no such mapping has been made. + */ + public E get(int key) { + return get(key, null); + } + + /** + * Gets the Object mapped from the specified key, or the specified Object + * if no such mapping has been made. + */ + @SuppressWarnings("unchecked") + public E get(int key, E valueIfKeyNotFound) { + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); + + if (i < 0 || mValues[i] == DELETED) { + return valueIfKeyNotFound; + } else { + return (E) mValues[i]; + } + } + + /** + * Removes the mapping from the specified key, if there was any. + */ + public void delete(int key) { + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); + + if (i >= 0) { + if (mValues[i] != DELETED) { + mValues[i] = DELETED; + mGarbage = true; + } + } + } + + /** + * Alias for {@link #delete(int)}. + */ + public void remove(int key) { + delete(key); + } + + /** + * Removes the mapping at the specified index. + */ + public void removeAt(int index) { + if (mValues[index] != DELETED) { + mValues[index] = DELETED; + mGarbage = true; + } + } + + /** + * Remove a range of mappings as a batch. + * + * @param index Index to begin at + * @param size Number of mappings to remove + */ + public void removeAtRange(int index, int size) { + final int end = Math.min(mSize, index + size); + for (int i = index; i < end; i++) { + removeAt(i); + } + } + + public void insertKeyRange(int keyStart, int count) { + + } + + public void removeKeyRange(ArrayList removedItems, int keyStart, int count) { + + } + + private void gc() { + // Log.e("SparseArray", "gc start with " + mSize); + + int n = mSize; + int o = 0; + int[] keys = mKeys; + Object[] values = mValues; + + for (int i = 0; i < n; i++) { + Object val = values[i]; + + if (val != DELETED) { + if (i != o) { + keys[o] = keys[i]; + values[o] = val; + values[i] = null; + } + + o++; + } + } + + mGarbage = false; + mSize = o; + + // Log.e("SparseArray", "gc end with " + mSize); + } + + /** + * Adds a mapping from the specified key to the specified value, + * replacing the previous mapping from the specified key if there + * was one. + */ + public void put(int key, E value) { + int i = ContainerHelpers.binarySearch(mKeys, mSize, key); + + if (i >= 0) { + mValues[i] = value; + } else { + i = ~i; + + if (i < mSize && mValues[i] == DELETED) { + mKeys[i] = key; + mValues[i] = value; + return; + } + + if (mGarbage && mSize >= mKeys.length) { + gc(); + + // Search again because indices may have changed. + i = ~ContainerHelpers.binarySearch(mKeys, mSize, key); + } + + if (mSize >= mKeys.length) { + int n = idealIntArraySize(mSize + 1); + + int[] nkeys = new int[n]; + Object[] nvalues = new Object[n]; + + // Log.e("SparseArray", "grow " + mKeys.length + " to " + n); + System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length); + System.arraycopy(mValues, 0, nvalues, 0, mValues.length); + + mKeys = nkeys; + mValues = nvalues; + } + + if (mSize - i != 0) { + // Log.e("SparseArray", "move " + (mSize - i)); + System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i); + System.arraycopy(mValues, i, mValues, i + 1, mSize - i); + } + + mKeys[i] = key; + mValues[i] = value; + mSize++; + } + } + + /** + * Returns the number of key-value mappings that this SparseArray + * currently stores. + */ + public int size() { + if (mGarbage) { + gc(); + } + + return mSize; + } + + /** + * Given an index in the range 0...size()-1, returns + * the key from the indexth key-value mapping that this + * SparseArray stores. + */ + public int keyAt(int index) { + if (mGarbage) { + gc(); + } + + return mKeys[index]; + } + + /** + * Given an index in the range 0...size()-1, returns + * the value from the indexth key-value mapping that this + * SparseArray stores. + */ + @SuppressWarnings("unchecked") + public E valueAt(int index) { + if (mGarbage) { + gc(); + } + + return (E) mValues[index]; + } + + /** + * Given an index in the range 0...size()-1, sets a new + * value for the indexth key-value mapping that this + * SparseArray stores. + */ + public void setValueAt(int index, E value) { + if (mGarbage) { + gc(); + } + + mValues[index] = value; + } + + /** + * Returns the index for which {@link #keyAt} would return the + * specified key, or a negative number if the specified + * key is not mapped. + */ + public int indexOfKey(int key) { + if (mGarbage) { + gc(); + } + + return ContainerHelpers.binarySearch(mKeys, mSize, key); + } + + /** + * Returns an index for which {@link #valueAt} would return the + * specified key, or a negative number if no keys map to the + * specified value. + *

Beware that this is a linear search, unlike lookups by key, + * and that multiple keys can map to the same value and this will + * find only one of them. + *

Note also that unlike most collections' {@code indexOf} methods, + * this method compares values using {@code ==} rather than {@code equals}. + */ + public int indexOfValue(E value) { + if (mGarbage) { + gc(); + } + + for (int i = 0; i < mSize; i++) + if (mValues[i] == value) + return i; + + return -1; + } + + /** + * Removes all key-value mappings from this SparseArray. + */ + public void clear() { + int n = mSize; + Object[] values = mValues; + + for (int i = 0; i < n; i++) { + values[i] = null; + } + + mSize = 0; + mGarbage = false; + } + + /** + * Puts a key/value pair into the array, optimizing for the case where + * the key is greater than all existing keys in the array. + */ + public void append(int key, E value) { + if (mSize != 0 && key <= mKeys[mSize - 1]) { + put(key, value); + return; + } + + if (mGarbage && mSize >= mKeys.length) { + gc(); + } + + int pos = mSize; + if (pos >= mKeys.length) { + int n = idealIntArraySize(pos + 1); + + int[] nkeys = new int[n]; + Object[] nvalues = new Object[n]; + + // Log.e("SparseArray", "grow " + mKeys.length + " to " + n); + System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length); + System.arraycopy(mValues, 0, nvalues, 0, mValues.length); + + mKeys = nkeys; + mValues = nvalues; + } + + mKeys[pos] = key; + mValues[pos] = value; + mSize = pos + 1; + } + + /** + * {@inheritDoc} + * + *

This implementation composes a string by iterating over its mappings. If + * this map contains itself as a value, the string "(this Map)" + * will appear in its place. + */ + @Override + public String toString() { + if (size() <= 0) { + return "{}"; + } + + StringBuilder buffer = new StringBuilder(mSize * 28); + buffer.append('{'); + for (int i=0; i 0) { + buffer.append(", "); + } + int key = keyAt(i); + buffer.append(key); + buffer.append('='); + Object value = valueAt(i); + if (value != this) { + buffer.append(value); + } else { + buffer.append("(this Map)"); + } + } + buffer.append('}'); + return buffer.toString(); + } + + static int idealByteArraySize(int need) { + for (int i = 4; i < 32; i++) + if (need <= (1 << i) - 12) + return (1 << i) - 12; + + return need; + } + + static int idealBooleanArraySize(int need) { + return idealByteArraySize(need); + } + + static int idealShortArraySize(int need) { + return idealByteArraySize(need * 2) / 2; + } + + static int idealCharArraySize(int need) { + return idealByteArraySize(need * 2) / 2; + } + + static int idealIntArraySize(int need) { + return idealByteArraySize(need * 4) / 4; + } + + static int idealFloatArraySize(int need) { + return idealByteArraySize(need * 4) / 4; + } + + static int idealObjectArraySize(int need) { + return idealByteArraySize(need * 4) / 4; + } + + static int idealLongArraySize(int need) { + return idealByteArraySize(need * 8) / 8; + } + + static class ContainerHelpers { + static final boolean[] EMPTY_BOOLEANS = new boolean[0]; + static final int[] EMPTY_INTS = new int[0]; + static final long[] EMPTY_LONGS = new long[0]; + static final Object[] EMPTY_OBJECTS = new Object[0]; + + // This is Arrays.binarySearch(), but doesn't do any argument validation. + static int binarySearch(int[] array, int size, int value) { + int lo = 0; + int hi = size - 1; + + while (lo <= hi) { + final int mid = (lo + hi) >>> 1; + final int midVal = array[mid]; + + if (midVal < value) { + lo = mid + 1; + } else if (midVal > value) { + hi = mid - 1; + } else { + return mid; // value found + } + } + return ~lo; // value not present + } + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/RecyclerView.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/RecyclerView.java new file mode 100644 index 00000000..5db54056 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/RecyclerView.java @@ -0,0 +1,11099 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.telegram.messenger.support.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.database.Observable; +import android.graphics.Canvas; +import android.graphics.PointF; +import android.graphics.Rect; +import android.os.Build; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.SystemClock; +import android.support.annotation.CallSuper; +import android.support.annotation.IntDef; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; +import android.support.v4.os.TraceCompat; +import android.support.v4.view.InputDeviceCompat; +import android.support.v4.view.MotionEventCompat; +import android.support.v4.view.NestedScrollingChild; +import android.support.v4.view.NestedScrollingChildHelper; +import android.support.v4.view.ScrollingView; +import android.support.v4.view.VelocityTrackerCompat; +import android.support.v4.view.ViewCompat; +import android.support.v4.view.ViewConfigurationCompat; +import android.support.v4.view.accessibility.AccessibilityEventCompat; +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; +import android.support.v4.view.accessibility.AccessibilityRecordCompat; +import android.support.v4.widget.EdgeEffectCompat; +import android.support.v4.widget.ScrollerCompat; + +import org.telegram.messenger.FileLog; +import org.telegram.messenger.support.widget.RecyclerView.ItemAnimator.ItemHolderInfo; +import android.util.AttributeSet; +import android.util.Log; +import android.util.SparseArray; +import android.util.SparseIntArray; +import android.util.TypedValue; +import android.view.FocusFinder; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.View.MeasureSpec; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; +import android.view.animation.Interpolator; +import android.widget.EdgeEffect; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.telegram.messenger.support.widget.AdapterHelper.Callback; +import static org.telegram.messenger.support.widget.AdapterHelper.UpdateOp; + +/** + * A flexible view for providing a limited window into a large data set. + * + *

Glossary of terms:

+ * + *
    + *
  • Adapter: A subclass of {@link Adapter} responsible for providing views + * that represent items in a data set.
  • + *
  • Position: The position of a data item within an Adapter.
  • + *
  • Index: The index of an attached child view as used in a call to + * {@link ViewGroup#getChildAt}. Contrast with Position.
  • + *
  • Binding: The process of preparing a child view to display data corresponding + * to a position within the adapter.
  • + *
  • Recycle (view): A view previously used to display data for a specific adapter + * position may be placed in a cache for later reuse to display the same type of data again + * later. This can drastically improve performance by skipping initial layout inflation + * or construction.
  • + *
  • Scrap (view): A child view that has entered into a temporarily detached + * state during layout. Scrap views may be reused without becoming fully detached + * from the parent RecyclerView, either unmodified if no rebinding is required or modified + * by the adapter if the view was considered dirty.
  • + *
  • Dirty (view): A child view that must be rebound by the adapter before + * being displayed.
  • + *
+ * + *

Positions in RecyclerView:

+ *

+ * RecyclerView introduces an additional level of abstraction between the {@link Adapter} and + * {@link LayoutManager} to be able to detect data set changes in batches during a layout + * calculation. This saves LayoutManager from tracking adapter changes to calculate animations. + * It also helps with performance because all view bindings happen at the same time and unnecessary + * bindings are avoided. + *

+ * For this reason, there are two types of position related methods in RecyclerView: + *

    + *
  • layout position: Position of an item in the latest layout calculation. This is the + * position from the LayoutManager's perspective.
  • + *
  • adapter position: Position of an item in the adapter. This is the position from + * the Adapter's perspective.
  • + *
+ *

+ * These two positions are the same except the time between dispatching adapter.notify* + * events and calculating the updated layout. + *

+ * Methods that return or receive *LayoutPosition* use position as of the latest + * layout calculation (e.g. {@link ViewHolder#getLayoutPosition()}, + * {@link #findViewHolderForLayoutPosition(int)}). These positions include all changes until the + * last layout calculation. You can rely on these positions to be consistent with what user is + * currently seeing on the screen. For example, if you have a list of items on the screen and user + * asks for the 5th element, you should use these methods as they'll match what user + * is seeing. + *

+ * The other set of position related methods are in the form of + * *AdapterPosition*. (e.g. {@link ViewHolder#getAdapterPosition()}, + * {@link #findViewHolderForAdapterPosition(int)}) You should use these methods when you need to + * work with up-to-date adapter positions even if they may not have been reflected to layout yet. + * For example, if you want to access the item in the adapter on a ViewHolder click, you should use + * {@link ViewHolder#getAdapterPosition()}. Beware that these methods may not be able to calculate + * adapter positions if {@link Adapter#notifyDataSetChanged()} has been called and new layout has + * not yet been calculated. For this reasons, you should carefully handle {@link #NO_POSITION} or + * null results from these methods. + *

+ * When writing a {@link LayoutManager} you almost always want to use layout positions whereas when + * writing an {@link Adapter}, you probably want to use adapter positions. + * + * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_layoutManager + */ +public class RecyclerView extends ViewGroup implements ScrollingView, NestedScrollingChild { + + private static final String TAG = "RecyclerView"; + + private static final boolean DEBUG = false; + + private static final int[] NESTED_SCROLLING_ATTRS + = {16843830 /* android.R.attr.nestedScrollingEnabled */}; + + /** + * On Kitkat and JB MR2, there is a bug which prevents DisplayList from being invalidated if + * a View is two levels deep(wrt to ViewHolder.itemView). DisplayList can be invalidated by + * setting View's visibility to INVISIBLE when View is detached. On Kitkat and JB MR2, Recycler + * recursively traverses itemView and invalidates display list for each ViewGroup that matches + * this criteria. + */ + private static final boolean FORCE_INVALIDATE_DISPLAY_LIST = Build.VERSION.SDK_INT == 18 + || Build.VERSION.SDK_INT == 19 || Build.VERSION.SDK_INT == 20; + /** + * On M+, an unspecified measure spec may include a hint which we can use. On older platforms, + * this value might be garbage. To save LayoutManagers from it, RecyclerView sets the size to + * 0 when mode is unspecified. + */ + static final boolean ALLOW_SIZE_IN_UNSPECIFIED_SPEC = Build.VERSION.SDK_INT >= 23; + + static final boolean DISPATCH_TEMP_DETACH = false; + public static final int HORIZONTAL = 0; + public static final int VERTICAL = 1; + + public static final int NO_POSITION = -1; + public static final long NO_ID = -1; + public static final int INVALID_TYPE = -1; + + /** + * Constant for use with {@link #setScrollingTouchSlop(int)}. Indicates + * that the RecyclerView should use the standard touch slop for smooth, + * continuous scrolling. + */ + public static final int TOUCH_SLOP_DEFAULT = 0; + + /** + * Constant for use with {@link #setScrollingTouchSlop(int)}. Indicates + * that the RecyclerView should use the standard touch slop for scrolling + * widgets that snap to a page or other coarse-grained barrier. + */ + public static final int TOUCH_SLOP_PAGING = 1; + + private static final int MAX_SCROLL_DURATION = 2000; + + /** + * RecyclerView is calculating a scroll. + * If there are too many of these in Systrace, some Views inside RecyclerView might be causing + * it. Try to avoid using EditText, focusable views or handle them with care. + */ + private static final String TRACE_SCROLL_TAG = "RV Scroll"; + + /** + * OnLayout has been called by the View system. + * If this shows up too many times in Systrace, make sure the children of RecyclerView do not + * update themselves directly. This will cause a full re-layout but when it happens via the + * Adapter notifyItemChanged, RecyclerView can avoid full layout calculation. + */ + private static final String TRACE_ON_LAYOUT_TAG = "RV OnLayout"; + + /** + * NotifyDataSetChanged or equal has been called. + * If this is taking a long time, try sending granular notify adapter changes instead of just + * calling notifyDataSetChanged or setAdapter / swapAdapter. Adding stable ids to your adapter + * might help. + */ + private static final String TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG = "RV FullInvalidate"; + + /** + * RecyclerView is doing a layout for partial adapter updates (we know what has changed) + * If this is taking a long time, you may have dispatched too many Adapter updates causing too + * many Views being rebind. Make sure all are necessary and also prefer using notify*Range + * methods. + */ + private static final String TRACE_HANDLE_ADAPTER_UPDATES_TAG = "RV PartialInvalidate"; + + /** + * RecyclerView is rebinding a View. + * If this is taking a lot of time, consider optimizing your layout or make sure you are not + * doing extra operations in onBindViewHolder call. + */ + private static final String TRACE_BIND_VIEW_TAG = "RV OnBindView"; + + /** + * RecyclerView is creating a new View. + * If too many of these present in Systrace: + * - There might be a problem in Recycling (e.g. custom Animations that set transient state and + * prevent recycling or ItemAnimator not implementing the contract properly. ({@link + * > Adapter#onFailedToRecycleView(ViewHolder)}) + * + * - There might be too many item view types. + * > Try merging them + * + * - There might be too many itemChange animations and not enough space in RecyclerPool. + * >Try increasing your pool size and item cache size. + */ + private static final String TRACE_CREATE_VIEW_TAG = "RV CreateView"; + private static final Class[] LAYOUT_MANAGER_CONSTRUCTOR_SIGNATURE = + new Class[]{Context.class, AttributeSet.class, int.class, int.class}; + + private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver(); + + final Recycler mRecycler = new Recycler(); + + private SavedState mPendingSavedState; + + /** + * Handles adapter updates + */ + AdapterHelper mAdapterHelper; + + /** + * Handles abstraction between LayoutManager children and RecyclerView children + */ + ChildHelper mChildHelper; + + /** + * Keeps data about views to be used for animations + */ + final ViewInfoStore mViewInfoStore = new ViewInfoStore(); + + /** + * Prior to L, there is no way to query this variable which is why we override the setter and + * track it here. + */ + private boolean mClipToPadding; + + /** + * Note: this Runnable is only ever posted if: + * 1) We've been through first layout + * 2) We know we have a fixed size (mHasFixedSize) + * 3) We're attached + */ + private final Runnable mUpdateChildViewsRunnable = new Runnable() { + public void run() { + if (!mFirstLayoutComplete || isLayoutRequested()) { + // a layout request will happen, we should not do layout here. + return; + } + if (mLayoutFrozen) { + mLayoutRequestEaten = true; + return; //we'll process updates when ice age ends. + } + consumePendingUpdateOperations(); + } + }; + + private final Rect mTempRect = new Rect(); + private Adapter mAdapter; + @VisibleForTesting LayoutManager mLayout; + private RecyclerListener mRecyclerListener; + private final ArrayList mItemDecorations = new ArrayList<>(); + private final ArrayList mOnItemTouchListeners = + new ArrayList<>(); + private OnItemTouchListener mActiveOnItemTouchListener; + private boolean mIsAttached; + private boolean mHasFixedSize; + private boolean mFirstLayoutComplete; + + // Counting lock to control whether we should ignore requestLayout calls from children or not. + private int mEatRequestLayout = 0; + + private boolean mLayoutRequestEaten; + private boolean mLayoutFrozen; + private boolean mIgnoreMotionEventTillDown; + + // binary OR of change events that were eaten during a layout or scroll. + private int mEatenAccessibilityChangeFlags; + private boolean mAdapterUpdateDuringMeasure; + private final boolean mPostUpdatesOnAnimation; + private final AccessibilityManager mAccessibilityManager; + private List mOnChildAttachStateListeners; + + /** + * Set to true when an adapter data set changed notification is received. + * In that case, we cannot run any animations since we don't know what happened. + */ + private boolean mDataSetHasChangedAfterLayout = false; + + /** + * This variable is incremented during a dispatchLayout and/or scroll. + * Some methods should not be called during these periods (e.g. adapter data change). + * Doing so will create hard to find bugs so we better check it and throw an exception. + * + * @see #assertInLayoutOrScroll(String) + * @see #assertNotInLayoutOrScroll(String) + */ + private int mLayoutOrScrollCounter = 0; + + private int topGlowOffset = 0; + private int glowColor = 0; + private EdgeEffectCompat mLeftGlow, mTopGlow, mRightGlow, mBottomGlow; + + ItemAnimator mItemAnimator = new DefaultItemAnimator(); + + private static final int INVALID_POINTER = -1; + + /** + * The RecyclerView is not currently scrolling. + * @see #getScrollState() + */ + public static final int SCROLL_STATE_IDLE = 0; + + /** + * The RecyclerView is currently being dragged by outside input such as user touch input. + * @see #getScrollState() + */ + public static final int SCROLL_STATE_DRAGGING = 1; + + /** + * The RecyclerView is currently animating to a final position while not under + * outside control. + * @see #getScrollState() + */ + public static final int SCROLL_STATE_SETTLING = 2; + + // Touch/scrolling handling + + private int mScrollState = SCROLL_STATE_IDLE; + private int mScrollPointerId = INVALID_POINTER; + private VelocityTracker mVelocityTracker; + private int mInitialTouchX; + private int mInitialTouchY; + private int mLastTouchX; + private int mLastTouchY; + private int mTouchSlop; + private final int mMinFlingVelocity; + private final int mMaxFlingVelocity; + // This value is used when handling generic motion events. + private float mScrollFactor = Float.MIN_VALUE; + + private final ViewFlinger mViewFlinger = new ViewFlinger(); + + final State mState = new State(); + + private OnScrollListener mScrollListener; + private List mScrollListeners; + + // For use in item animations + boolean mItemsAddedOrRemoved = false; + boolean mItemsChanged = false; + private ItemAnimator.ItemAnimatorListener mItemAnimatorListener = + new ItemAnimatorRestoreListener(); + private boolean mPostedAnimatorRunner = false; + private RecyclerViewAccessibilityDelegate mAccessibilityDelegate; + private ChildDrawingOrderCallback mChildDrawingOrderCallback; + + // simple array to keep min and max child position during a layout calculation + // preserved not to create a new one in each layout pass + private final int[] mMinMaxLayoutPositions = new int[2]; + + private NestedScrollingChildHelper mScrollingChildHelper; + private final int[] mScrollOffset = new int[2]; + private final int[] mScrollConsumed = new int[2]; + private final int[] mNestedOffsets = new int[2]; + + private Runnable mItemAnimatorRunner = new Runnable() { + @Override + public void run() { + if (mItemAnimator != null) { + mItemAnimator.runPendingAnimations(); + } + mPostedAnimatorRunner = false; + } + }; + + private static final Interpolator sQuinticInterpolator = new Interpolator() { + public float getInterpolation(float t) { + t -= 1.0f; + return t * t * t * t * t + 1.0f; + } + }; + + /** + * The callback to convert view info diffs into animations. + */ + private final ViewInfoStore.ProcessCallback mViewInfoProcessCallback = + new ViewInfoStore.ProcessCallback() { + @Override + public void processDisappeared(ViewHolder viewHolder, @NonNull ItemHolderInfo info, + @Nullable ItemHolderInfo postInfo) { + mRecycler.unscrapView(viewHolder); + animateDisappearance(viewHolder, info, postInfo); + } + @Override + public void processAppeared(ViewHolder viewHolder, + ItemHolderInfo preInfo, ItemHolderInfo info) { + animateAppearance(viewHolder, preInfo, info); + } + + @Override + public void processPersistent(ViewHolder viewHolder, + @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) { + viewHolder.setIsRecyclable(false); + if (mDataSetHasChangedAfterLayout) { + // since it was rebound, use change instead as we'll be mapping them from + // stable ids. If stable ids were false, we would not be running any + // animations + if (mItemAnimator.animateChange(viewHolder, viewHolder, preInfo, postInfo)) { + postAnimationRunner(); + } + } else if (mItemAnimator.animatePersistence(viewHolder, preInfo, postInfo)) { + postAnimationRunner(); + } + } + @Override + public void unused(ViewHolder viewHolder) { + mLayout.removeAndRecycleView(viewHolder.itemView, mRecycler); + } + }; + + public RecyclerView(Context context) { + this(context, null); + } + + public RecyclerView(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public RecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + setScrollContainer(true); + setFocusableInTouchMode(true); + final int version = Build.VERSION.SDK_INT; + mPostUpdatesOnAnimation = version >= 16; + + final ViewConfiguration vc = ViewConfiguration.get(context); + mTouchSlop = vc.getScaledTouchSlop(); + mMinFlingVelocity = vc.getScaledMinimumFlingVelocity(); + mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); + setWillNotDraw(ViewCompat.getOverScrollMode(this) == ViewCompat.OVER_SCROLL_NEVER); + + mItemAnimator.setListener(mItemAnimatorListener); + initAdapterManager(); + initChildrenHelper(); + // If not explicitly specified this view is important for accessibility. + if (ViewCompat.getImportantForAccessibility(this) + == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + ViewCompat.setImportantForAccessibility(this, + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); + } + mAccessibilityManager = (AccessibilityManager) getContext() + .getSystemService(Context.ACCESSIBILITY_SERVICE); + setAccessibilityDelegateCompat(new RecyclerViewAccessibilityDelegate(this)); + // Create the layoutManager if specified. + + // Re-set whether nested scrolling is enabled so that it is set on all API levels + setNestedScrollingEnabled(true); + } + + /** + * Returns the accessibility delegate compatibility implementation used by the RecyclerView. + * @return An instance of AccessibilityDelegateCompat used by RecyclerView + */ + public RecyclerViewAccessibilityDelegate getCompatAccessibilityDelegate() { + return mAccessibilityDelegate; + } + + /** + * Sets the accessibility delegate compatibility implementation used by RecyclerView. + * @param accessibilityDelegate The accessibility delegate to be used by RecyclerView. + */ + public void setAccessibilityDelegateCompat( + RecyclerViewAccessibilityDelegate accessibilityDelegate) { + mAccessibilityDelegate = accessibilityDelegate; + ViewCompat.setAccessibilityDelegate(this, mAccessibilityDelegate); + } + + /** + * Instantiate and set a LayoutManager, if specified in the attributes. + */ + private void createLayoutManager(Context context, String className, AttributeSet attrs, + int defStyleAttr, int defStyleRes) { + if (className != null) { + className = className.trim(); + if (className.length() != 0) { // Can't use isEmpty since it was added in API 9. + className = getFullClassName(context, className); + try { + ClassLoader classLoader; + if (isInEditMode()) { + // Stupid layoutlib cannot handle simple class loaders. + classLoader = this.getClass().getClassLoader(); + } else { + classLoader = context.getClassLoader(); + } + Class layoutManagerClass = + classLoader.loadClass(className).asSubclass(LayoutManager.class); + Constructor constructor; + Object[] constructorArgs = null; + try { + constructor = layoutManagerClass + .getConstructor(LAYOUT_MANAGER_CONSTRUCTOR_SIGNATURE); + constructorArgs = new Object[]{context, attrs, defStyleAttr, defStyleRes}; + } catch (NoSuchMethodException e) { + try { + constructor = layoutManagerClass.getConstructor(); + } catch (NoSuchMethodException e1) { + e1.initCause(e); + throw new IllegalStateException(attrs.getPositionDescription() + + ": Error creating LayoutManager " + className, e1); + } + } + constructor.setAccessible(true); + setLayoutManager(constructor.newInstance(constructorArgs)); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(attrs.getPositionDescription() + + ": Unable to find LayoutManager " + className, e); + } catch (InvocationTargetException e) { + throw new IllegalStateException(attrs.getPositionDescription() + + ": Could not instantiate the LayoutManager: " + className, e); + } catch (InstantiationException e) { + throw new IllegalStateException(attrs.getPositionDescription() + + ": Could not instantiate the LayoutManager: " + className, e); + } catch (IllegalAccessException e) { + throw new IllegalStateException(attrs.getPositionDescription() + + ": Cannot access non-public constructor " + className, e); + } catch (ClassCastException e) { + throw new IllegalStateException(attrs.getPositionDescription() + + ": Class is not a LayoutManager " + className, e); + } + } + } + } + + private String getFullClassName(Context context, String className) { + if (className.charAt(0) == '.') { + return context.getPackageName() + className; + } + if (className.indexOf('.') != -1) { + return className; + } + return RecyclerView.class.getPackage().getName() + '.' + className; + } + + private void initChildrenHelper() { + mChildHelper = new ChildHelper(new ChildHelper.Callback() { + @Override + public int getChildCount() { + return RecyclerView.this.getChildCount(); + } + + @Override + public void addView(View child, int index) { + RecyclerView.this.addView(child, index); + dispatchChildAttached(child); + } + + @Override + public int indexOfChild(View view) { + return RecyclerView.this.indexOfChild(view); + } + + @Override + public void removeViewAt(int index) { + final View child = RecyclerView.this.getChildAt(index); + if (child != null) { + dispatchChildDetached(child); + } + RecyclerView.this.removeViewAt(index); + } + + @Override + public View getChildAt(int offset) { + return RecyclerView.this.getChildAt(offset); + } + + @Override + public void removeAllViews() { + final int count = getChildCount(); + for (int i = 0; i < count; i ++) { + dispatchChildDetached(getChildAt(i)); + } + RecyclerView.this.removeAllViews(); + } + + @Override + public ViewHolder getChildViewHolder(View view) { + return getChildViewHolderInt(view); + } + + @Override + public void attachViewToParent(View child, int index, + ViewGroup.LayoutParams layoutParams) { + final ViewHolder vh = getChildViewHolderInt(child); + if (vh != null) { + if (!vh.isTmpDetached() && !vh.shouldIgnore()) { + throw new IllegalArgumentException("Called attach on a child which is not" + + " detached: " + vh); + } + if (DEBUG) { + Log.d(TAG, "reAttach " + vh); + } + vh.clearTmpDetachFlag(); + } + RecyclerView.this.attachViewToParent(child, index, layoutParams); + } + + @Override + public void detachViewFromParent(int offset) { + final View view = getChildAt(offset); + if (view != null) { + final ViewHolder vh = getChildViewHolderInt(view); + if (vh != null) { + if (vh.isTmpDetached() && !vh.shouldIgnore()) { + throw new IllegalArgumentException("called detach on an already" + + " detached child " + vh); + } + if (DEBUG) { + Log.d(TAG, "tmpDetach " + vh); + } + vh.addFlags(ViewHolder.FLAG_TMP_DETACHED); + } + } + RecyclerView.this.detachViewFromParent(offset); + } + + @Override + public void onEnteredHiddenState(View child) { + final ViewHolder vh = getChildViewHolderInt(child); + if (vh != null) { + vh.onEnteredHiddenState(); + } + } + + @Override + public void onLeftHiddenState(View child) { + final ViewHolder vh = getChildViewHolderInt(child); + if (vh != null) { + vh.onLeftHiddenState(); + } + } + }); + } + + void initAdapterManager() { + mAdapterHelper = new AdapterHelper(new Callback() { + @Override + public ViewHolder findViewHolder(int position) { + final ViewHolder vh = findViewHolderForPosition(position, true); + if (vh == null) { + return null; + } + // ensure it is not hidden because for adapter helper, the only thing matter is that + // LM thinks view is a child. + if (mChildHelper.isHidden(vh.itemView)) { + if (DEBUG) { + Log.d(TAG, "assuming view holder cannot be find because it is hidden"); + } + return null; + } + return vh; + } + + @Override + public void offsetPositionsForRemovingInvisible(int start, int count) { + offsetPositionRecordsForRemove(start, count, true); + mItemsAddedOrRemoved = true; + mState.mDeletedInvisibleItemCountSincePreviousLayout += count; + } + + @Override + public void offsetPositionsForRemovingLaidOutOrNewView(int positionStart, int itemCount) { + offsetPositionRecordsForRemove(positionStart, itemCount, false); + mItemsAddedOrRemoved = true; + } + + @Override + public void markViewHoldersUpdated(int positionStart, int itemCount, Object payload) { + viewRangeUpdate(positionStart, itemCount, payload); + mItemsChanged = true; + } + + @Override + public void onDispatchFirstPass(UpdateOp op) { + dispatchUpdate(op); + } + + void dispatchUpdate(UpdateOp op) { + switch (op.cmd) { + case UpdateOp.ADD: + mLayout.onItemsAdded(RecyclerView.this, op.positionStart, op.itemCount); + break; + case UpdateOp.REMOVE: + mLayout.onItemsRemoved(RecyclerView.this, op.positionStart, op.itemCount); + break; + case UpdateOp.UPDATE: + mLayout.onItemsUpdated(RecyclerView.this, op.positionStart, op.itemCount, + op.payload); + break; + case UpdateOp.MOVE: + mLayout.onItemsMoved(RecyclerView.this, op.positionStart, op.itemCount, 1); + break; + } + } + + @Override + public void onDispatchSecondPass(UpdateOp op) { + dispatchUpdate(op); + } + + @Override + public void offsetPositionsForAdd(int positionStart, int itemCount) { + offsetPositionRecordsForInsert(positionStart, itemCount); + mItemsAddedOrRemoved = true; + } + + @Override + public void offsetPositionsForMove(int from, int to) { + offsetPositionRecordsForMove(from, to); + // should we create mItemsMoved ? + mItemsAddedOrRemoved = true; + } + }); + } + + /** + * RecyclerView can perform several optimizations if it can know in advance that RecyclerView's + * size is not affected by the adapter contents. RecyclerView can still change its size based + * on other factors (e.g. its parent's size) but this size calculation cannot depend on the + * size of its children or contents of its adapter (except the number of items in the adapter). + *

+ * If your use of RecyclerView falls into this category, set this to {@code true}. It will allow + * RecyclerView to avoid invalidating the whole layout when its adapter contents change. + * + * @param hasFixedSize true if adapter changes cannot affect the size of the RecyclerView. + */ + public void setHasFixedSize(boolean hasFixedSize) { + mHasFixedSize = hasFixedSize; + } + + /** + * @return true if the app has specified that changes in adapter content cannot change + * the size of the RecyclerView itself. + */ + public boolean hasFixedSize() { + return mHasFixedSize; + } + + @Override + public void setClipToPadding(boolean clipToPadding) { + if (clipToPadding != mClipToPadding) { + invalidateGlows(); + } + mClipToPadding = clipToPadding; + super.setClipToPadding(clipToPadding); + if (mFirstLayoutComplete) { + requestLayout(); + } + } + + /** + * Configure the scrolling touch slop for a specific use case. + * + * Set up the RecyclerView's scrolling motion threshold based on common usages. + * Valid arguments are {@link #TOUCH_SLOP_DEFAULT} and {@link #TOUCH_SLOP_PAGING}. + * + * @param slopConstant One of the TOUCH_SLOP_ constants representing + * the intended usage of this RecyclerView + */ + public void setScrollingTouchSlop(int slopConstant) { + final ViewConfiguration vc = ViewConfiguration.get(getContext()); + switch (slopConstant) { + default: + Log.w(TAG, "setScrollingTouchSlop(): bad argument constant " + + slopConstant + "; using default value"); + // fall-through + case TOUCH_SLOP_DEFAULT: + mTouchSlop = vc.getScaledTouchSlop(); + break; + + case TOUCH_SLOP_PAGING: + mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(vc); + break; + } + } + + /** + * Swaps the current adapter with the provided one. It is similar to + * {@link #setAdapter(Adapter)} but assumes existing adapter and the new adapter uses the same + * {@link ViewHolder} and does not clear the RecycledViewPool. + *

+ * Note that it still calls onAdapterChanged callbacks. + * + * @param adapter The new adapter to set, or null to set no adapter. + * @param removeAndRecycleExistingViews If set to true, RecyclerView will recycle all existing + * Views. If adapters have stable ids and/or you want to + * animate the disappearing views, you may prefer to set + * this to false. + * @see #setAdapter(Adapter) + */ + public void swapAdapter(Adapter adapter, boolean removeAndRecycleExistingViews) { + // bail out if layout is frozen + setLayoutFrozen(false); + setAdapterInternal(adapter, true, removeAndRecycleExistingViews); + setDataSetChangedAfterLayout(); + requestLayout(); + } + /** + * Set a new adapter to provide child views on demand. + *

+ * When adapter is changed, all existing views are recycled back to the pool. If the pool has + * only one adapter, it will be cleared. + * + * @param adapter The new adapter to set, or null to set no adapter. + * @see #swapAdapter(Adapter, boolean) + */ + public void setAdapter(Adapter adapter) { + // bail out if layout is frozen + setLayoutFrozen(false); + setAdapterInternal(adapter, false, true); + requestLayout(); + } + + /** + * Replaces the current adapter with the new one and triggers listeners. + * @param adapter The new adapter + * @param compatibleWithPrevious If true, the new adapter is using the same View Holders and + * item types with the current adapter (helps us avoid cache + * invalidation). + * @param removeAndRecycleViews If true, we'll remove and recycle all existing views. If + * compatibleWithPrevious is false, this parameter is ignored. + */ + private void setAdapterInternal(Adapter adapter, boolean compatibleWithPrevious, + boolean removeAndRecycleViews) { + if (mAdapter != null) { + mAdapter.unregisterAdapterDataObserver(mObserver); + mAdapter.onDetachedFromRecyclerView(this); + } + if (!compatibleWithPrevious || removeAndRecycleViews) { + // end all running animations + if (mItemAnimator != null) { + mItemAnimator.endAnimations(); + } + // Since animations are ended, mLayout.children should be equal to + // recyclerView.children. This may not be true if item animator's end does not work as + // expected. (e.g. not release children instantly). It is safer to use mLayout's child + // count. + if (mLayout != null) { + mLayout.removeAndRecycleAllViews(mRecycler); + mLayout.removeAndRecycleScrapInt(mRecycler); + } + // we should clear it here before adapters are swapped to ensure correct callbacks. + mRecycler.clear(); + } + mAdapterHelper.reset(); + final Adapter oldAdapter = mAdapter; + mAdapter = adapter; + if (adapter != null) { + adapter.registerAdapterDataObserver(mObserver); + adapter.onAttachedToRecyclerView(this); + } + if (mLayout != null) { + mLayout.onAdapterChanged(oldAdapter, mAdapter); + } + mRecycler.onAdapterChanged(oldAdapter, mAdapter, compatibleWithPrevious); + mState.mStructureChanged = true; + markKnownViewsInvalid(); + } + + /** + * Retrieves the previously set adapter or null if no adapter is set. + * + * @return The previously set adapter + * @see #setAdapter(Adapter) + */ + public Adapter getAdapter() { + return mAdapter; + } + + /** + * Register a listener that will be notified whenever a child view is recycled. + * + *

This listener will be called when a LayoutManager or the RecyclerView decides + * that a child view is no longer needed. If an application associates expensive + * or heavyweight data with item views, this may be a good place to release + * or free those resources.

+ * + * @param listener Listener to register, or null to clear + */ + public void setRecyclerListener(RecyclerListener listener) { + mRecyclerListener = listener; + } + + /** + *

Return the offset of the RecyclerView's text baseline from the its top + * boundary. If the LayoutManager of this RecyclerView does not support baseline alignment, + * this method returns -1.

+ * + * @return the offset of the baseline within the RecyclerView's bounds or -1 + * if baseline alignment is not supported + */ + @Override + public int getBaseline() { + if (mLayout != null) { + return mLayout.getBaseline(); + } else { + return super.getBaseline(); + } + } + + /** + * Register a listener that will be notified whenever a child view is attached to or detached + * from RecyclerView. + * + *

This listener will be called when a LayoutManager or the RecyclerView decides + * that a child view is no longer needed. If an application associates expensive + * or heavyweight data with item views, this may be a good place to release + * or free those resources.

+ * + * @param listener Listener to register + */ + public void addOnChildAttachStateChangeListener(OnChildAttachStateChangeListener listener) { + if (mOnChildAttachStateListeners == null) { + mOnChildAttachStateListeners = new ArrayList<>(); + } + mOnChildAttachStateListeners.add(listener); + } + + /** + * Removes the provided listener from child attached state listeners list. + * + * @param listener Listener to unregister + */ + public void removeOnChildAttachStateChangeListener(OnChildAttachStateChangeListener listener) { + if (mOnChildAttachStateListeners == null) { + return; + } + mOnChildAttachStateListeners.remove(listener); + } + + /** + * Removes all listeners that were added via + * {@link #addOnChildAttachStateChangeListener(OnChildAttachStateChangeListener)}. + */ + public void clearOnChildAttachStateChangeListeners() { + if (mOnChildAttachStateListeners != null) { + mOnChildAttachStateListeners.clear(); + } + } + + /** + * Set the {@link LayoutManager} that this RecyclerView will use. + * + *

In contrast to other adapter-backed views such as {@link android.widget.ListView} + * or {@link android.widget.GridView}, RecyclerView allows client code to provide custom + * layout arrangements for child views. These arrangements are controlled by the + * {@link LayoutManager}. A LayoutManager must be provided for RecyclerView to function.

+ * + *

Several default strategies are provided for common uses such as lists and grids.

+ * + * @param layout LayoutManager to use + */ + public void setLayoutManager(LayoutManager layout) { + if (layout == mLayout) { + return; + } + stopScroll(); + // TODO We should do this switch a dispachLayout pass and animate children. There is a good + // chance that LayoutManagers will re-use views. + if (mLayout != null) { + if (mIsAttached) { + mLayout.dispatchDetachedFromWindow(this, mRecycler); + } + mLayout.setRecyclerView(null); + } + mRecycler.clear(); + mChildHelper.removeAllViewsUnfiltered(); + mLayout = layout; + if (layout != null) { + if (layout.mRecyclerView != null) { + throw new IllegalArgumentException("LayoutManager " + layout + + " is already attached to a RecyclerView: " + layout.mRecyclerView); + } + mLayout.setRecyclerView(this); + if (mIsAttached) { + mLayout.dispatchAttachedToWindow(this); + } + } + requestLayout(); + } + + @Override + protected Parcelable onSaveInstanceState() { + SavedState state = new SavedState(super.onSaveInstanceState()); + if (mPendingSavedState != null) { + state.copyFrom(mPendingSavedState); + } else if (mLayout != null) { + state.mLayoutState = mLayout.onSaveInstanceState(); + } else { + state.mLayoutState = null; + } + + return state; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (!(state instanceof SavedState)) { + super.onRestoreInstanceState(state); + return; + } + + mPendingSavedState = (SavedState) state; + super.onRestoreInstanceState(mPendingSavedState.getSuperState()); + if (mLayout != null && mPendingSavedState.mLayoutState != null) { + mLayout.onRestoreInstanceState(mPendingSavedState.mLayoutState); + } + } + + /** + * Override to prevent freezing of any views created by the adapter. + */ + @Override + protected void dispatchSaveInstanceState(SparseArray container) { + dispatchFreezeSelfOnly(container); + } + + /** + * Override to prevent thawing of any views created by the adapter. + */ + @Override + protected void dispatchRestoreInstanceState(SparseArray container) { + dispatchThawSelfOnly(container); + } + + /** + * Adds a view to the animatingViews list. + * mAnimatingViews holds the child views that are currently being kept around + * purely for the purpose of being animated out of view. They are drawn as a regular + * part of the child list of the RecyclerView, but they are invisible to the LayoutManager + * as they are managed separately from the regular child views. + * @param viewHolder The ViewHolder to be removed + */ + private void addAnimatingView(ViewHolder viewHolder) { + final View view = viewHolder.itemView; + final boolean alreadyParented = view.getParent() == this; + mRecycler.unscrapView(getChildViewHolder(view)); + if (viewHolder.isTmpDetached()) { + // re-attach + mChildHelper.attachViewToParent(view, -1, view.getLayoutParams(), true); + } else if(!alreadyParented) { + mChildHelper.addView(view, true); + } else { + mChildHelper.hide(view); + } + } + + /** + * Removes a view from the animatingViews list. + * @param view The view to be removed + * @see #addAnimatingView(RecyclerView.ViewHolder) + * @return true if an animating view is removed + */ + private boolean removeAnimatingView(View view) { + eatRequestLayout(); + final boolean removed = mChildHelper.removeViewIfHidden(view); + if (removed) { + final ViewHolder viewHolder = getChildViewHolderInt(view); + mRecycler.unscrapView(viewHolder); + mRecycler.recycleViewHolderInternal(viewHolder); + if (DEBUG) { + Log.d(TAG, "after removing animated view: " + view + ", " + this); + } + } + // only clear request eaten flag if we removed the view. + resumeRequestLayout(!removed); + return removed; + } + + /** + * Return the {@link LayoutManager} currently responsible for + * layout policy for this RecyclerView. + * + * @return The currently bound LayoutManager + */ + public LayoutManager getLayoutManager() { + return mLayout; + } + + /** + * Retrieve this RecyclerView's {@link RecycledViewPool}. This method will never return null; + * if no pool is set for this view a new one will be created. See + * {@link #setRecycledViewPool(RecycledViewPool) setRecycledViewPool} for more information. + * + * @return The pool used to store recycled item views for reuse. + * @see #setRecycledViewPool(RecycledViewPool) + */ + public RecycledViewPool getRecycledViewPool() { + return mRecycler.getRecycledViewPool(); + } + + /** + * Recycled view pools allow multiple RecyclerViews to share a common pool of scrap views. + * This can be useful if you have multiple RecyclerViews with adapters that use the same + * view types, for example if you have several data sets with the same kinds of item views + * displayed by a {@link android.support.v4.view.ViewPager ViewPager}. + * + * @param pool Pool to set. If this parameter is null a new pool will be created and used. + */ + public void setRecycledViewPool(RecycledViewPool pool) { + mRecycler.setRecycledViewPool(pool); + } + + /** + * Sets a new {@link ViewCacheExtension} to be used by the Recycler. + * + * @param extension ViewCacheExtension to be used or null if you want to clear the existing one. + * + * @see {@link ViewCacheExtension#getViewForPositionAndType(Recycler, int, int)} + */ + public void setViewCacheExtension(ViewCacheExtension extension) { + mRecycler.setViewCacheExtension(extension); + } + + /** + * Set the number of offscreen views to retain before adding them to the potentially shared + * {@link #getRecycledViewPool() recycled view pool}. + * + *

The offscreen view cache stays aware of changes in the attached adapter, allowing + * a LayoutManager to reuse those views unmodified without needing to return to the adapter + * to rebind them.

+ * + * @param size Number of views to cache offscreen before returning them to the general + * recycled view pool + */ + public void setItemViewCacheSize(int size) { + mRecycler.setViewCacheSize(size); + } + + /** + * Return the current scrolling state of the RecyclerView. + * + * @return {@link #SCROLL_STATE_IDLE}, {@link #SCROLL_STATE_DRAGGING} or + * {@link #SCROLL_STATE_SETTLING} + */ + public int getScrollState() { + return mScrollState; + } + + private void setScrollState(int state) { + if (state == mScrollState) { + return; + } + if (DEBUG) { + Log.d(TAG, "setting scroll state to " + state + " from " + mScrollState, + new Exception()); + } + mScrollState = state; + if (state != SCROLL_STATE_SETTLING) { + stopScrollersInternal(); + } + dispatchOnScrollStateChanged(state); + } + + /** + * Add an {@link ItemDecoration} to this RecyclerView. Item decorations can + * affect both measurement and drawing of individual item views. + * + *

Item decorations are ordered. Decorations placed earlier in the list will + * be run/queried/drawn first for their effects on item views. Padding added to views + * will be nested; a padding added by an earlier decoration will mean further + * item decorations in the list will be asked to draw/pad within the previous decoration's + * given area.

+ * + * @param decor Decoration to add + * @param index Position in the decoration chain to insert this decoration at. If this value + * is negative the decoration will be added at the end. + */ + public void addItemDecoration(ItemDecoration decor, int index) { + if (mLayout != null) { + mLayout.assertNotInLayoutOrScroll("Cannot add item decoration during a scroll or" + + " layout"); + } + if (mItemDecorations.isEmpty()) { + setWillNotDraw(false); + } + if (index < 0) { + mItemDecorations.add(decor); + } else { + mItemDecorations.add(index, decor); + } + markItemDecorInsetsDirty(); + requestLayout(); + } + + /** + * Add an {@link ItemDecoration} to this RecyclerView. Item decorations can + * affect both measurement and drawing of individual item views. + * + *

Item decorations are ordered. Decorations placed earlier in the list will + * be run/queried/drawn first for their effects on item views. Padding added to views + * will be nested; a padding added by an earlier decoration will mean further + * item decorations in the list will be asked to draw/pad within the previous decoration's + * given area.

+ * + * @param decor Decoration to add + */ + public void addItemDecoration(ItemDecoration decor) { + addItemDecoration(decor, -1); + } + + /** + * Remove an {@link ItemDecoration} from this RecyclerView. + * + *

The given decoration will no longer impact the measurement and drawing of + * item views.

+ * + * @param decor Decoration to remove + * @see #addItemDecoration(ItemDecoration) + */ + public void removeItemDecoration(ItemDecoration decor) { + if (mLayout != null) { + mLayout.assertNotInLayoutOrScroll("Cannot remove item decoration during a scroll or" + + " layout"); + } + mItemDecorations.remove(decor); + if (mItemDecorations.isEmpty()) { + setWillNotDraw(ViewCompat.getOverScrollMode(this) == ViewCompat.OVER_SCROLL_NEVER); + } + markItemDecorInsetsDirty(); + requestLayout(); + } + + /** + * Sets the {@link ChildDrawingOrderCallback} to be used for drawing children. + *

+ * See {@link ViewGroup#getChildDrawingOrder(int, int)} for details. Calling this method will + * always call {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean)}. The parameter will be + * true if childDrawingOrderCallback is not null, false otherwise. + *

+ * Note that child drawing order may be overridden by View's elevation. + * + * @param childDrawingOrderCallback The ChildDrawingOrderCallback to be used by the drawing + * system. + */ + public void setChildDrawingOrderCallback(ChildDrawingOrderCallback childDrawingOrderCallback) { + if (childDrawingOrderCallback == mChildDrawingOrderCallback) { + return; + } + mChildDrawingOrderCallback = childDrawingOrderCallback; + setChildrenDrawingOrderEnabled(mChildDrawingOrderCallback != null); + } + + /** + * Set a listener that will be notified of any changes in scroll state or position. + * + * @param listener Listener to set or null to clear + * + * @deprecated Use {@link #addOnScrollListener(OnScrollListener)} and + * {@link #removeOnScrollListener(OnScrollListener)} + */ + @Deprecated + public void setOnScrollListener(OnScrollListener listener) { + mScrollListener = listener; + } + + /** + * Add a listener that will be notified of any changes in scroll state or position. + * + *

Components that add a listener should take care to remove it when finished. + * Other components that take ownership of a view may call {@link #clearOnScrollListeners()} + * to remove all attached listeners.

+ * + * @param listener listener to set or null to clear + */ + public void addOnScrollListener(OnScrollListener listener) { + if (mScrollListeners == null) { + mScrollListeners = new ArrayList<>(); + } + mScrollListeners.add(listener); + } + + /** + * Remove a listener that was notified of any changes in scroll state or position. + * + * @param listener listener to set or null to clear + */ + public void removeOnScrollListener(OnScrollListener listener) { + if (mScrollListeners != null) { + mScrollListeners.remove(listener); + } + } + + /** + * Remove all secondary listener that were notified of any changes in scroll state or position. + */ + public void clearOnScrollListeners() { + if (mScrollListeners != null) { + mScrollListeners.clear(); + } + } + + /** + * Convenience method to scroll to a certain position. + * + * RecyclerView does not implement scrolling logic, rather forwards the call to + * {@link android.support.v7.widget.RecyclerView.LayoutManager#scrollToPosition(int)} + * @param position Scroll to this adapter position + * @see android.support.v7.widget.RecyclerView.LayoutManager#scrollToPosition(int) + */ + public void scrollToPosition(int position) { + if (mLayoutFrozen) { + return; + } + stopScroll(); + if (mLayout == null) { + Log.e(TAG, "Cannot scroll to position a LayoutManager set. " + + "Call setLayoutManager with a non-null argument."); + return; + } + mLayout.scrollToPosition(position); + awakenScrollBars(); + } + + private void jumpToPositionForSmoothScroller(int position) { + if (mLayout == null) { + return; + } + mLayout.scrollToPosition(position); + awakenScrollBars(); + } + + /** + * Starts a smooth scroll to an adapter position. + *

+ * To support smooth scrolling, you must override + * {@link LayoutManager#smoothScrollToPosition(RecyclerView, State, int)} and create a + * {@link SmoothScroller}. + *

+ * {@link LayoutManager} is responsible for creating the actual scroll action. If you want to + * provide a custom smooth scroll logic, override + * {@link LayoutManager#smoothScrollToPosition(RecyclerView, State, int)} in your + * LayoutManager. + * + * @param position The adapter position to scroll to + * @see LayoutManager#smoothScrollToPosition(RecyclerView, State, int) + */ + public void smoothScrollToPosition(int position) { + if (mLayoutFrozen) { + return; + } + if (mLayout == null) { + Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. " + + "Call setLayoutManager with a non-null argument."); + return; + } + mLayout.smoothScrollToPosition(this, mState, position); + } + + @Override + public void scrollTo(int x, int y) { + Log.w(TAG, "RecyclerView does not support scrolling to an absolute position. " + + "Use scrollToPosition instead"); + } + + @Override + public void scrollBy(int x, int y) { + if (mLayout == null) { + Log.e(TAG, "Cannot scroll without a LayoutManager set. " + + "Call setLayoutManager with a non-null argument."); + return; + } + if (mLayoutFrozen) { + return; + } + final boolean canScrollHorizontal = mLayout.canScrollHorizontally(); + final boolean canScrollVertical = mLayout.canScrollVertically(); + if (canScrollHorizontal || canScrollVertical) { + scrollByInternal(canScrollHorizontal ? x : 0, canScrollVertical ? y : 0, null); + } + } + + /** + * Helper method reflect data changes to the state. + *

+ * Adapter changes during a scroll may trigger a crash because scroll assumes no data change + * but data actually changed. + *

+ * This method consumes all deferred changes to avoid that case. + */ + private void consumePendingUpdateOperations() { + if (!mFirstLayoutComplete) { + // a layout request will happen, we should not do layout here. + return; + } + if (mDataSetHasChangedAfterLayout) { + TraceCompat.beginSection(TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG); + dispatchLayout(); + TraceCompat.endSection(); + return; + } + if (!mAdapterHelper.hasPendingUpdates()) { + return; + } + + // if it is only an item change (no add-remove-notifyDataSetChanged) we can check if any + // of the visible items is affected and if not, just ignore the change. + if (mAdapterHelper.hasAnyUpdateTypes(UpdateOp.UPDATE) && !mAdapterHelper + .hasAnyUpdateTypes(UpdateOp.ADD | UpdateOp.REMOVE | UpdateOp.MOVE)) { + TraceCompat.beginSection(TRACE_HANDLE_ADAPTER_UPDATES_TAG); + eatRequestLayout(); + mAdapterHelper.preProcess(); + if (!mLayoutRequestEaten) { + if (hasUpdatedView()) { + dispatchLayout(); + } else { + // no need to layout, clean state + mAdapterHelper.consumePostponedUpdates(); + } + } + resumeRequestLayout(true); + TraceCompat.endSection(); + } else if (mAdapterHelper.hasPendingUpdates()) { + TraceCompat.beginSection(TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG); + dispatchLayout(); + TraceCompat.endSection(); + } + } + + /** + * @return True if an existing view holder needs to be updated + */ + private boolean hasUpdatedView() { + final int childCount = mChildHelper.getChildCount(); + for (int i = 0; i < childCount; i++) { + final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i)); + if (holder == null || holder.shouldIgnore()) { + continue; + } + if (holder.isUpdated()) { + return true; + } + } + return false; + } + + /** + * Does not perform bounds checking. Used by internal methods that have already validated input. + *

+ * It also reports any unused scroll request to the related EdgeEffect. + * + * @param x The amount of horizontal scroll request + * @param y The amount of vertical scroll request + * @param ev The originating MotionEvent, or null if not from a touch event. + * + * @return Whether any scroll was consumed in either direction. + */ + boolean scrollByInternal(int x, int y, MotionEvent ev) { + int unconsumedX = 0, unconsumedY = 0; + int consumedX = 0, consumedY = 0; + + consumePendingUpdateOperations(); + if (mAdapter != null) { + eatRequestLayout(); + onEnterLayoutOrScroll(); + TraceCompat.beginSection(TRACE_SCROLL_TAG); + if (x != 0) { + consumedX = mLayout.scrollHorizontallyBy(x, mRecycler, mState); + unconsumedX = x - consumedX; + } + if (y != 0) { + consumedY = mLayout.scrollVerticallyBy(y, mRecycler, mState); + unconsumedY = y - consumedY; + } + TraceCompat.endSection(); + repositionShadowingViews(); + onExitLayoutOrScroll(); + resumeRequestLayout(false); + } + if (!mItemDecorations.isEmpty()) { + invalidate(); + } + + if (dispatchNestedScroll(consumedX, consumedY, unconsumedX, unconsumedY, mScrollOffset)) { + // Update the last touch co-ords, taking any scroll offset into account + mLastTouchX -= mScrollOffset[0]; + mLastTouchY -= mScrollOffset[1]; + if (ev != null) { + ev.offsetLocation(mScrollOffset[0], mScrollOffset[1]); + } + mNestedOffsets[0] += mScrollOffset[0]; + mNestedOffsets[1] += mScrollOffset[1]; + } else if (ViewCompat.getOverScrollMode(this) != ViewCompat.OVER_SCROLL_NEVER) { + if (ev != null) { + pullGlows(ev.getX(), unconsumedX, ev.getY(), unconsumedY); + } + considerReleasingGlowsOnScroll(x, y); + } + if (consumedX != 0 || consumedY != 0) { + dispatchOnScrolled(consumedX, consumedY); + } + if (!awakenScrollBars()) { + invalidate(); + } + return consumedX != 0 || consumedY != 0; + } + + /** + *

Compute the horizontal offset of the horizontal scrollbar's thumb within the horizontal + * range. This value is used to compute the length of the thumb within the scrollbar's track. + *

+ * + *

The range is expressed in arbitrary units that must be the same as the units used by + * {@link #computeHorizontalScrollRange()} and {@link #computeHorizontalScrollExtent()}.

+ * + *

Default implementation returns 0.

+ * + *

If you want to support scroll bars, override + * {@link RecyclerView.LayoutManager#computeHorizontalScrollOffset(RecyclerView.State)} in your + * LayoutManager.

+ * + * @return The horizontal offset of the scrollbar's thumb + * @see android.support.v7.widget.RecyclerView.LayoutManager#computeHorizontalScrollOffset + * (RecyclerView.Adapter) + */ + @Override + public int computeHorizontalScrollOffset() { + if (mLayout == null) { + return 0; + } + return mLayout.canScrollHorizontally() ? mLayout.computeHorizontalScrollOffset(mState) : 0; + } + + /** + *

Compute the horizontal extent of the horizontal scrollbar's thumb within the + * horizontal range. This value is used to compute the length of the thumb within the + * scrollbar's track.

+ * + *

The range is expressed in arbitrary units that must be the same as the units used by + * {@link #computeHorizontalScrollRange()} and {@link #computeHorizontalScrollOffset()}.

+ * + *

Default implementation returns 0.

+ * + *

If you want to support scroll bars, override + * {@link RecyclerView.LayoutManager#computeHorizontalScrollExtent(RecyclerView.State)} in your + * LayoutManager.

+ * + * @return The horizontal extent of the scrollbar's thumb + * @see RecyclerView.LayoutManager#computeHorizontalScrollExtent(RecyclerView.State) + */ + @Override + public int computeHorizontalScrollExtent() { + if (mLayout == null) { + return 0; + } + return mLayout.canScrollHorizontally() ? mLayout.computeHorizontalScrollExtent(mState) : 0; + } + + /** + *

Compute the horizontal range that the horizontal scrollbar represents.

+ * + *

The range is expressed in arbitrary units that must be the same as the units used by + * {@link #computeHorizontalScrollExtent()} and {@link #computeHorizontalScrollOffset()}.

+ * + *

Default implementation returns 0.

+ * + *

If you want to support scroll bars, override + * {@link RecyclerView.LayoutManager#computeHorizontalScrollRange(RecyclerView.State)} in your + * LayoutManager.

+ * + * @return The total horizontal range represented by the vertical scrollbar + * @see RecyclerView.LayoutManager#computeHorizontalScrollRange(RecyclerView.State) + */ + @Override + public int computeHorizontalScrollRange() { + if (mLayout == null) { + return 0; + } + return mLayout.canScrollHorizontally() ? mLayout.computeHorizontalScrollRange(mState) : 0; + } + + /** + *

Compute the vertical offset of the vertical scrollbar's thumb within the vertical range. + * This value is used to compute the length of the thumb within the scrollbar's track.

+ * + *

The range is expressed in arbitrary units that must be the same as the units used by + * {@link #computeVerticalScrollRange()} and {@link #computeVerticalScrollExtent()}.

+ * + *

Default implementation returns 0.

+ * + *

If you want to support scroll bars, override + * {@link RecyclerView.LayoutManager#computeVerticalScrollOffset(RecyclerView.State)} in your + * LayoutManager.

+ * + * @return The vertical offset of the scrollbar's thumb + * @see android.support.v7.widget.RecyclerView.LayoutManager#computeVerticalScrollOffset + * (RecyclerView.Adapter) + */ + @Override + public int computeVerticalScrollOffset() { + if (mLayout == null) { + return 0; + } + return mLayout.canScrollVertically() ? mLayout.computeVerticalScrollOffset(mState) : 0; + } + + /** + *

Compute the vertical extent of the vertical scrollbar's thumb within the vertical range. + * This value is used to compute the length of the thumb within the scrollbar's track.

+ * + *

The range is expressed in arbitrary units that must be the same as the units used by + * {@link #computeVerticalScrollRange()} and {@link #computeVerticalScrollOffset()}.

+ * + *

Default implementation returns 0.

+ * + *

If you want to support scroll bars, override + * {@link RecyclerView.LayoutManager#computeVerticalScrollExtent(RecyclerView.State)} in your + * LayoutManager.

+ * + * @return The vertical extent of the scrollbar's thumb + * @see RecyclerView.LayoutManager#computeVerticalScrollExtent(RecyclerView.State) + */ + @Override + public int computeVerticalScrollExtent() { + if (mLayout == null) { + return 0; + } + return mLayout.canScrollVertically() ? mLayout.computeVerticalScrollExtent(mState) : 0; + } + + /** + *

Compute the vertical range that the vertical scrollbar represents.

+ * + *

The range is expressed in arbitrary units that must be the same as the units used by + * {@link #computeVerticalScrollExtent()} and {@link #computeVerticalScrollOffset()}.

+ * + *

Default implementation returns 0.

+ * + *

If you want to support scroll bars, override + * {@link RecyclerView.LayoutManager#computeVerticalScrollRange(RecyclerView.State)} in your + * LayoutManager.

+ * + * @return The total vertical range represented by the vertical scrollbar + * @see RecyclerView.LayoutManager#computeVerticalScrollRange(RecyclerView.State) + */ + @Override + public int computeVerticalScrollRange() { + if (mLayout == null) { + return 0; + } + return mLayout.canScrollVertically() ? mLayout.computeVerticalScrollRange(mState) : 0; + } + + + void eatRequestLayout() { + mEatRequestLayout++; + if (mEatRequestLayout == 1 && !mLayoutFrozen) { + mLayoutRequestEaten = false; + } + } + + void resumeRequestLayout(boolean performLayoutChildren) { + if (mEatRequestLayout < 1) { + //noinspection PointlessBooleanExpression + if (DEBUG) { + throw new IllegalStateException("invalid eat request layout count"); + } + mEatRequestLayout = 1; + } + if (!performLayoutChildren) { + // Reset the layout request eaten counter. + // This is necessary since eatRequest calls can be nested in which case the outher + // call will override the inner one. + // for instance: + // eat layout for process adapter updates + // eat layout for dispatchLayout + // a bunch of req layout calls arrive + + mLayoutRequestEaten = false; + } + if (mEatRequestLayout == 1) { + // when layout is frozen we should delay dispatchLayout() + if (performLayoutChildren && mLayoutRequestEaten && !mLayoutFrozen && + mLayout != null && mAdapter != null) { + dispatchLayout(); + } + if (!mLayoutFrozen) { + mLayoutRequestEaten = false; + } + } + mEatRequestLayout--; + } + + /** + * Enable or disable layout and scroll. After setLayoutFrozen(true) is called, + * Layout requests will be postponed until setLayoutFrozen(false) is called; + * child views are not updated when RecyclerView is frozen, {@link #smoothScrollBy(int, int)}, + * {@link #scrollBy(int, int)}, {@link #scrollToPosition(int)} and + * {@link #smoothScrollToPosition(int)} are dropped; TouchEvents and GenericMotionEvents are + * dropped; {@link LayoutManager#onFocusSearchFailed(View, int, Recycler, State)} will not be + * called. + * + *

+ * setLayoutFrozen(true) does not prevent app from directly calling {@link + * LayoutManager#scrollToPosition(int)}, {@link LayoutManager#smoothScrollToPosition( + * RecyclerView, State, int)}. + *

+ * {@link #setAdapter(Adapter)} and {@link #swapAdapter(Adapter, boolean)} will automatically + * stop frozen. + *

+ * Note: Running ItemAnimator is not stopped automatically, it's caller's + * responsibility to call ItemAnimator.end(). + * + * @param frozen true to freeze layout and scroll, false to re-enable. + */ + public void setLayoutFrozen(boolean frozen) { + if (frozen != mLayoutFrozen) { + assertNotInLayoutOrScroll("Do not setLayoutFrozen in layout or scroll"); + if (!frozen) { + mLayoutFrozen = false; + if (mLayoutRequestEaten && mLayout != null && mAdapter != null) { + requestLayout(); + } + mLayoutRequestEaten = false; + } else { + final long now = SystemClock.uptimeMillis(); + MotionEvent cancelEvent = MotionEvent.obtain(now, now, + MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); + onTouchEvent(cancelEvent); + mLayoutFrozen = true; + mIgnoreMotionEventTillDown = true; + stopScroll(); + } + } + } + + /** + * Returns true if layout and scroll are frozen. + * + * @return true if layout and scroll are frozen + * @see #setLayoutFrozen(boolean) + */ + public boolean isLayoutFrozen() { + return mLayoutFrozen; + } + + /** + * Animate a scroll by the given amount of pixels along either axis. + * + * @param dx Pixels to scroll horizontally + * @param dy Pixels to scroll vertically + */ + public void smoothScrollBy(int dx, int dy) { + if (mLayout == null) { + Log.e(TAG, "Cannot smooth scroll without a LayoutManager set. " + + "Call setLayoutManager with a non-null argument."); + return; + } + if (mLayoutFrozen) { + return; + } + if (!mLayout.canScrollHorizontally()) { + dx = 0; + } + if (!mLayout.canScrollVertically()) { + dy = 0; + } + if (dx != 0 || dy != 0) { + mViewFlinger.smoothScrollBy(dx, dy); + } + } + + /** + * Begin a standard fling with an initial velocity along each axis in pixels per second. + * If the velocity given is below the system-defined minimum this method will return false + * and no fling will occur. + * + * @param velocityX Initial horizontal velocity in pixels per second + * @param velocityY Initial vertical velocity in pixels per second + * @return true if the fling was started, false if the velocity was too low to fling or + * LayoutManager does not support scrolling in the axis fling is issued. + * + * @see LayoutManager#canScrollVertically() + * @see LayoutManager#canScrollHorizontally() + */ + public boolean fling(int velocityX, int velocityY) { + if (mLayout == null) { + Log.e(TAG, "Cannot fling without a LayoutManager set. " + + "Call setLayoutManager with a non-null argument."); + return false; + } + if (mLayoutFrozen) { + return false; + } + + final boolean canScrollHorizontal = mLayout.canScrollHorizontally(); + final boolean canScrollVertical = mLayout.canScrollVertically(); + + if (!canScrollHorizontal || Math.abs(velocityX) < mMinFlingVelocity) { + velocityX = 0; + } + if (!canScrollVertical || Math.abs(velocityY) < mMinFlingVelocity) { + velocityY = 0; + } + if (velocityX == 0 && velocityY == 0) { + // If we don't have any velocity, return false + return false; + } + + if (!dispatchNestedPreFling(velocityX, velocityY)) { + final boolean canScroll = canScrollHorizontal || canScrollVertical; + dispatchNestedFling(velocityX, velocityY, canScroll); + + if (canScroll) { + velocityX = Math.max(-mMaxFlingVelocity, Math.min(velocityX, mMaxFlingVelocity)); + velocityY = Math.max(-mMaxFlingVelocity, Math.min(velocityY, mMaxFlingVelocity)); + mViewFlinger.fling(velocityX, velocityY); + return true; + } + } + return false; + } + + /** + * Stop any current scroll in progress, such as one started by + * {@link #smoothScrollBy(int, int)}, {@link #fling(int, int)} or a touch-initiated fling. + */ + public void stopScroll() { + setScrollState(SCROLL_STATE_IDLE); + stopScrollersInternal(); + } + + /** + * Similar to {@link #stopScroll()} but does not set the state. + */ + private void stopScrollersInternal() { + mViewFlinger.stop(); + if (mLayout != null) { + mLayout.stopSmoothScroller(); + } + } + + /** + * Returns the minimum velocity to start a fling. + * + * @return The minimum velocity to start a fling + */ + public int getMinFlingVelocity() { + return mMinFlingVelocity; + } + + + /** + * Returns the maximum fling velocity used by this RecyclerView. + * + * @return The maximum fling velocity used by this RecyclerView. + */ + public int getMaxFlingVelocity() { + return mMaxFlingVelocity; + } + + /** + * Apply a pull to relevant overscroll glow effects + */ + private void pullGlows(float x, float overscrollX, float y, float overscrollY) { + boolean invalidate = false; + if (overscrollX < 0) { + ensureLeftGlow(); + if (mLeftGlow.onPull(-overscrollX / getWidth(), 1f - y / getHeight())) { + invalidate = true; + } + } else if (overscrollX > 0) { + ensureRightGlow(); + if (mRightGlow.onPull(overscrollX / getWidth(), y / getHeight())) { + invalidate = true; + } + } + + if (overscrollY < 0) { + ensureTopGlow(); + if (mTopGlow.onPull(-overscrollY / getHeight(), x / getWidth())) { + invalidate = true; + } + } else if (overscrollY > 0) { + ensureBottomGlow(); + if (mBottomGlow.onPull(overscrollY / getHeight(), 1f - x / getWidth())) { + invalidate = true; + } + } + + if (invalidate || overscrollX != 0 || overscrollY != 0) { + ViewCompat.postInvalidateOnAnimation(this); + } + } + + private void releaseGlows() { + boolean needsInvalidate = false; + if (mLeftGlow != null) needsInvalidate = mLeftGlow.onRelease(); + if (mTopGlow != null) needsInvalidate |= mTopGlow.onRelease(); + if (mRightGlow != null) needsInvalidate |= mRightGlow.onRelease(); + if (mBottomGlow != null) needsInvalidate |= mBottomGlow.onRelease(); + if (needsInvalidate) { + ViewCompat.postInvalidateOnAnimation(this); + } + } + + private void considerReleasingGlowsOnScroll(int dx, int dy) { + boolean needsInvalidate = false; + if (mLeftGlow != null && !mLeftGlow.isFinished() && dx > 0) { + needsInvalidate = mLeftGlow.onRelease(); + } + if (mRightGlow != null && !mRightGlow.isFinished() && dx < 0) { + needsInvalidate |= mRightGlow.onRelease(); + } + if (mTopGlow != null && !mTopGlow.isFinished() && dy > 0) { + needsInvalidate |= mTopGlow.onRelease(); + } + if (mBottomGlow != null && !mBottomGlow.isFinished() && dy < 0) { + needsInvalidate |= mBottomGlow.onRelease(); + } + if (needsInvalidate) { + ViewCompat.postInvalidateOnAnimation(this); + } + } + + void absorbGlows(int velocityX, int velocityY) { + if (velocityX < 0) { + ensureLeftGlow(); + mLeftGlow.onAbsorb(-velocityX); + } else if (velocityX > 0) { + ensureRightGlow(); + mRightGlow.onAbsorb(velocityX); + } + + if (velocityY < 0) { + ensureTopGlow(); + mTopGlow.onAbsorb(-velocityY); + } else if (velocityY > 0) { + ensureBottomGlow(); + mBottomGlow.onAbsorb(velocityY); + } + + if (velocityX != 0 || velocityY != 0) { + ViewCompat.postInvalidateOnAnimation(this); + } + } + + void ensureLeftGlow() { + if (mLeftGlow != null) { + return; + } + mLeftGlow = new EdgeEffectCompat(getContext()); + if (mClipToPadding) { + mLeftGlow.setSize(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), + getMeasuredWidth() - getPaddingLeft() - getPaddingRight()); + } else { + mLeftGlow.setSize(getMeasuredHeight(), getMeasuredWidth()); + } + applyEdgeEffectColor(mLeftGlow); + } + + void ensureRightGlow() { + if (mRightGlow != null) { + return; + } + mRightGlow = new EdgeEffectCompat(getContext()); + if (mClipToPadding) { + mRightGlow.setSize(getMeasuredHeight() - getPaddingTop() - getPaddingBottom(), + getMeasuredWidth() - getPaddingLeft() - getPaddingRight()); + } else { + mRightGlow.setSize(getMeasuredHeight(), getMeasuredWidth()); + } + applyEdgeEffectColor(mRightGlow); + } + + void ensureTopGlow() { + if (mTopGlow != null) { + return; + } + mTopGlow = new EdgeEffectCompat(getContext()); + if (mClipToPadding) { + mTopGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), + getMeasuredHeight() - getPaddingTop() - getPaddingBottom()); + } else { + mTopGlow.setSize(getMeasuredWidth(), getMeasuredHeight()); + } + applyEdgeEffectColor(mTopGlow); + } + + void ensureBottomGlow() { + if (mBottomGlow != null) { + return; + } + mBottomGlow = new EdgeEffectCompat(getContext()); + if (mClipToPadding) { + mBottomGlow.setSize(getMeasuredWidth() - getPaddingLeft() - getPaddingRight(), + getMeasuredHeight() - getPaddingTop() - getPaddingBottom()); + } else { + mBottomGlow.setSize(getMeasuredWidth(), getMeasuredHeight()); + } + applyEdgeEffectColor(mBottomGlow); + } + + void applyEdgeEffectColor(EdgeEffectCompat edgeEffectCompat) { + if (Build.VERSION.SDK_INT >= 21 && glowColor != 0) { + try { + Field field = EdgeEffectCompat.class.getDeclaredField("mEdgeEffect"); + field.setAccessible(true); + EdgeEffect edgeEffect = (EdgeEffect) field.get(edgeEffectCompat); + if (edgeEffect != null) { + edgeEffect.setColor(glowColor); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + void invalidateGlows() { + mLeftGlow = mRightGlow = mTopGlow = mBottomGlow = null; + } + + // Focus handling + + @Override + public View focusSearch(View focused, int direction) { + View result = mLayout.onInterceptFocusSearch(focused, direction); + if (result != null) { + return result; + } + final FocusFinder ff = FocusFinder.getInstance(); + result = ff.findNextFocus(this, focused, direction); + if (result == null && mAdapter != null && mLayout != null && !isComputingLayout() + && !mLayoutFrozen) { + eatRequestLayout(); + result = mLayout.onFocusSearchFailed(focused, direction, mRecycler, mState); + resumeRequestLayout(false); + } + return result != null ? result : super.focusSearch(focused, direction); + } + + @Override + public void requestChildFocus(View child, View focused) { + if (!mLayout.onRequestChildFocus(this, mState, child, focused) && focused != null) { + mTempRect.set(0, 0, focused.getWidth(), focused.getHeight()); + + // get item decor offsets w/o refreshing. If they are invalid, there will be another + // layout pass to fix them, then it is LayoutManager's responsibility to keep focused + // View in viewport. + final ViewGroup.LayoutParams focusedLayoutParams = focused.getLayoutParams(); + if (focusedLayoutParams instanceof LayoutParams) { + // if focused child has item decors, use them. Otherwise, ignore. + final LayoutParams lp = (LayoutParams) focusedLayoutParams; + if (!lp.mInsetsDirty) { + final Rect insets = lp.mDecorInsets; + mTempRect.left -= insets.left; + mTempRect.right += insets.right; + mTempRect.top -= insets.top; + mTempRect.bottom += insets.bottom; + } + } + + offsetDescendantRectToMyCoords(focused, mTempRect); + offsetRectIntoDescendantCoords(child, mTempRect); + requestChildRectangleOnScreen(child, mTempRect, !mFirstLayoutComplete); + } + super.requestChildFocus(child, focused); + } + + @Override + public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) { + return mLayout.requestChildRectangleOnScreen(this, child, rect, immediate); + } + + @Override + public void addFocusables(ArrayList views, int direction, int focusableMode) { + if (mLayout == null || !mLayout.onAddFocusables(this, views, direction, focusableMode)) { + super.addFocusables(views, direction, focusableMode); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + mLayoutOrScrollCounter = 0; + mIsAttached = true; + mFirstLayoutComplete = false; + if (mLayout != null) { + mLayout.dispatchAttachedToWindow(this); + } + mPostedAnimatorRunner = false; + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (mItemAnimator != null) { + mItemAnimator.endAnimations(); + } + mFirstLayoutComplete = false; + + stopScroll(); + mIsAttached = false; + if (mLayout != null) { + mLayout.dispatchDetachedFromWindow(this, mRecycler); + } + removeCallbacks(mItemAnimatorRunner); + mViewInfoStore.onDetach(); + } + + /** + * Returns true if RecyclerView is attached to window. + */ + // @override + public boolean isAttachedToWindow() { + return mIsAttached; + } + + /** + * Checks if RecyclerView is in the middle of a layout or scroll and throws an + * {@link IllegalStateException} if it is not. + * + * @param message The message for the exception. Can be null. + * @see #assertNotInLayoutOrScroll(String) + */ + void assertInLayoutOrScroll(String message) { + if (!isComputingLayout()) { + if (message == null) { + throw new IllegalStateException("Cannot call this method unless RecyclerView is " + + "computing a layout or scrolling"); + } + throw new IllegalStateException(message); + + } + } + + /** + * Checks if RecyclerView is in the middle of a layout or scroll and throws an + * {@link IllegalStateException} if it is. + * + * @param message The message for the exception. Can be null. + * @see #assertInLayoutOrScroll(String) + */ + void assertNotInLayoutOrScroll(String message) { + if (isComputingLayout()) { + if (message == null) { + throw new IllegalStateException("Cannot call this method while RecyclerView is " + + "computing a layout or scrolling"); + } + throw new IllegalStateException(message); + } + } + + /** + * Add an {@link OnItemTouchListener} to intercept touch events before they are dispatched + * to child views or this view's standard scrolling behavior. + * + *

Client code may use listeners to implement item manipulation behavior. Once a listener + * returns true from + * {@link OnItemTouchListener#onInterceptTouchEvent(RecyclerView, MotionEvent)} its + * {@link OnItemTouchListener#onTouchEvent(RecyclerView, MotionEvent)} method will be called + * for each incoming MotionEvent until the end of the gesture.

+ * + * @param listener Listener to add + * @see SimpleOnItemTouchListener + */ + public void addOnItemTouchListener(OnItemTouchListener listener) { + mOnItemTouchListeners.add(listener); + } + + /** + * Remove an {@link OnItemTouchListener}. It will no longer be able to intercept touch events. + * + * @param listener Listener to remove + */ + public void removeOnItemTouchListener(OnItemTouchListener listener) { + mOnItemTouchListeners.remove(listener); + if (mActiveOnItemTouchListener == listener) { + mActiveOnItemTouchListener = null; + } + } + + private boolean dispatchOnItemTouchIntercept(MotionEvent e) { + final int action = e.getAction(); + if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_DOWN) { + mActiveOnItemTouchListener = null; + } + + final int listenerCount = mOnItemTouchListeners.size(); + for (int i = 0; i < listenerCount; i++) { + final OnItemTouchListener listener = mOnItemTouchListeners.get(i); + if (listener.onInterceptTouchEvent(this, e) && action != MotionEvent.ACTION_CANCEL) { + mActiveOnItemTouchListener = listener; + return true; + } + } + return false; + } + + private boolean dispatchOnItemTouch(MotionEvent e) { + final int action = e.getAction(); + if (mActiveOnItemTouchListener != null) { + if (action == MotionEvent.ACTION_DOWN) { + // Stale state from a previous gesture, we're starting a new one. Clear it. + mActiveOnItemTouchListener = null; + } else { + mActiveOnItemTouchListener.onTouchEvent(this, e); + if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { + // Clean up for the next gesture. + mActiveOnItemTouchListener = null; + } + return true; + } + } + + // Listeners will have already received the ACTION_DOWN via dispatchOnItemTouchIntercept + // as called from onInterceptTouchEvent; skip it. + if (action != MotionEvent.ACTION_DOWN) { + final int listenerCount = mOnItemTouchListeners.size(); + for (int i = 0; i < listenerCount; i++) { + final OnItemTouchListener listener = mOnItemTouchListeners.get(i); + if (listener.onInterceptTouchEvent(this, e)) { + mActiveOnItemTouchListener = listener; + return true; + } + } + } + return false; + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent e) { + if (mLayoutFrozen) { + // When layout is frozen, RV does not intercept the motion event. + // A child view e.g. a button may still get the click. + return false; + } + if (dispatchOnItemTouchIntercept(e)) { + cancelTouch(); + return true; + } + + if (mLayout == null) { + return false; + } + + final boolean canScrollHorizontally = mLayout.canScrollHorizontally(); + final boolean canScrollVertically = mLayout.canScrollVertically(); + + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(e); + + final int action = MotionEventCompat.getActionMasked(e); + final int actionIndex = MotionEventCompat.getActionIndex(e); + + switch (action) { + case MotionEvent.ACTION_DOWN: + if (mIgnoreMotionEventTillDown) { + mIgnoreMotionEventTillDown = false; + } + mScrollPointerId = MotionEventCompat.getPointerId(e, 0); + mInitialTouchX = mLastTouchX = (int) (e.getX() + 0.5f); + mInitialTouchY = mLastTouchY = (int) (e.getY() + 0.5f); + + if (mScrollState == SCROLL_STATE_SETTLING) { + getParent().requestDisallowInterceptTouchEvent(true); + setScrollState(SCROLL_STATE_DRAGGING); + } + + // Clear the nested offsets + mNestedOffsets[0] = mNestedOffsets[1] = 0; + + int nestedScrollAxis = ViewCompat.SCROLL_AXIS_NONE; + if (canScrollHorizontally) { + nestedScrollAxis |= ViewCompat.SCROLL_AXIS_HORIZONTAL; + } + if (canScrollVertically) { + nestedScrollAxis |= ViewCompat.SCROLL_AXIS_VERTICAL; + } + startNestedScroll(nestedScrollAxis); + break; + + case MotionEventCompat.ACTION_POINTER_DOWN: + mScrollPointerId = MotionEventCompat.getPointerId(e, actionIndex); + mInitialTouchX = mLastTouchX = (int) (MotionEventCompat.getX(e, actionIndex) + 0.5f); + mInitialTouchY = mLastTouchY = (int) (MotionEventCompat.getY(e, actionIndex) + 0.5f); + break; + + case MotionEvent.ACTION_MOVE: { + final int index = MotionEventCompat.findPointerIndex(e, mScrollPointerId); + if (index < 0) { + Log.e(TAG, "Error processing scroll; pointer index for id " + + mScrollPointerId + " not found. Did any MotionEvents get skipped?"); + return false; + } + + final int x = (int) (MotionEventCompat.getX(e, index) + 0.5f); + final int y = (int) (MotionEventCompat.getY(e, index) + 0.5f); + if (mScrollState != SCROLL_STATE_DRAGGING) { + final int dx = x - mInitialTouchX; + final int dy = y - mInitialTouchY; + boolean startScroll = false; + if (canScrollHorizontally && Math.abs(dx) > mTouchSlop) { + mLastTouchX = mInitialTouchX + mTouchSlop * (dx < 0 ? -1 : 1); + startScroll = true; + } + if (canScrollVertically && Math.abs(dy) > mTouchSlop) { + mLastTouchY = mInitialTouchY + mTouchSlop * (dy < 0 ? -1 : 1); + startScroll = true; + } + if (startScroll) { + setScrollState(SCROLL_STATE_DRAGGING); + } + } + } break; + + case MotionEventCompat.ACTION_POINTER_UP: { + onPointerUp(e); + } break; + + case MotionEvent.ACTION_UP: { + mVelocityTracker.clear(); + stopNestedScroll(); + } break; + + case MotionEvent.ACTION_CANCEL: { + cancelTouch(); + } + } + return mScrollState == SCROLL_STATE_DRAGGING; + } + + @Override + public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) { + final int listenerCount = mOnItemTouchListeners.size(); + for (int i = 0; i < listenerCount; i++) { + final OnItemTouchListener listener = mOnItemTouchListeners.get(i); + listener.onRequestDisallowInterceptTouchEvent(disallowIntercept); + } + super.requestDisallowInterceptTouchEvent(disallowIntercept); + } + + @Override + public boolean onTouchEvent(MotionEvent e) { + if (mLayoutFrozen || mIgnoreMotionEventTillDown) { + return false; + } + if (dispatchOnItemTouch(e)) { + cancelTouch(); + return true; + } + + if (mLayout == null) { + return false; + } + + final boolean canScrollHorizontally = mLayout.canScrollHorizontally(); + final boolean canScrollVertically = mLayout.canScrollVertically(); + + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + boolean eventAddedToVelocityTracker = false; + + final MotionEvent vtev = MotionEvent.obtain(e); + final int action = MotionEventCompat.getActionMasked(e); + final int actionIndex = MotionEventCompat.getActionIndex(e); + + if (action == MotionEvent.ACTION_DOWN) { + mNestedOffsets[0] = mNestedOffsets[1] = 0; + } + vtev.offsetLocation(mNestedOffsets[0], mNestedOffsets[1]); + + switch (action) { + case MotionEvent.ACTION_DOWN: { + mScrollPointerId = MotionEventCompat.getPointerId(e, 0); + mInitialTouchX = mLastTouchX = (int) (e.getX() + 0.5f); + mInitialTouchY = mLastTouchY = (int) (e.getY() + 0.5f); + + int nestedScrollAxis = ViewCompat.SCROLL_AXIS_NONE; + if (canScrollHorizontally) { + nestedScrollAxis |= ViewCompat.SCROLL_AXIS_HORIZONTAL; + } + if (canScrollVertically) { + nestedScrollAxis |= ViewCompat.SCROLL_AXIS_VERTICAL; + } + startNestedScroll(nestedScrollAxis); + } break; + + case MotionEventCompat.ACTION_POINTER_DOWN: { + mScrollPointerId = MotionEventCompat.getPointerId(e, actionIndex); + mInitialTouchX = mLastTouchX = (int) (MotionEventCompat.getX(e, actionIndex) + 0.5f); + mInitialTouchY = mLastTouchY = (int) (MotionEventCompat.getY(e, actionIndex) + 0.5f); + } break; + + case MotionEvent.ACTION_MOVE: { + final int index = MotionEventCompat.findPointerIndex(e, mScrollPointerId); + if (index < 0) { + Log.e(TAG, "Error processing scroll; pointer index for id " + + mScrollPointerId + " not found. Did any MotionEvents get skipped?"); + return false; + } + + final int x = (int) (MotionEventCompat.getX(e, index) + 0.5f); + final int y = (int) (MotionEventCompat.getY(e, index) + 0.5f); + int dx = mLastTouchX - x; + int dy = mLastTouchY - y; + + if (dispatchNestedPreScroll(dx, dy, mScrollConsumed, mScrollOffset)) { + dx -= mScrollConsumed[0]; + dy -= mScrollConsumed[1]; + vtev.offsetLocation(mScrollOffset[0], mScrollOffset[1]); + // Updated the nested offsets + mNestedOffsets[0] += mScrollOffset[0]; + mNestedOffsets[1] += mScrollOffset[1]; + } + + if (mScrollState != SCROLL_STATE_DRAGGING) { + boolean startScroll = false; + if (canScrollHorizontally && Math.abs(dx) > mTouchSlop) { + if (dx > 0) { + dx -= mTouchSlop; + } else { + dx += mTouchSlop; + } + startScroll = true; + } + if (canScrollVertically && Math.abs(dy) > mTouchSlop) { + if (dy > 0) { + dy -= mTouchSlop; + } else { + dy += mTouchSlop; + } + startScroll = true; + } + if (startScroll) { + setScrollState(SCROLL_STATE_DRAGGING); + } + } + + if (mScrollState == SCROLL_STATE_DRAGGING) { + mLastTouchX = x - mScrollOffset[0]; + mLastTouchY = y - mScrollOffset[1]; + + if (scrollByInternal( + canScrollHorizontally ? dx : 0, + canScrollVertically ? dy : 0, + vtev)) { + getParent().requestDisallowInterceptTouchEvent(true); + } + } + } break; + + case MotionEventCompat.ACTION_POINTER_UP: { + onPointerUp(e); + } break; + + case MotionEvent.ACTION_UP: { + mVelocityTracker.addMovement(vtev); + eventAddedToVelocityTracker = true; + mVelocityTracker.computeCurrentVelocity(1000, mMaxFlingVelocity); + final float xvel = canScrollHorizontally ? + -VelocityTrackerCompat.getXVelocity(mVelocityTracker, mScrollPointerId) : 0; + final float yvel = canScrollVertically ? + -VelocityTrackerCompat.getYVelocity(mVelocityTracker, mScrollPointerId) : 0; + if (!((xvel != 0 || yvel != 0) && fling((int) xvel, (int) yvel))) { + setScrollState(SCROLL_STATE_IDLE); + } + resetTouch(); + } break; + + case MotionEvent.ACTION_CANCEL: { + cancelTouch(); + } break; + } + + if (!eventAddedToVelocityTracker) { + mVelocityTracker.addMovement(vtev); + } + vtev.recycle(); + + return true; + } + + private void resetTouch() { + if (mVelocityTracker != null) { + mVelocityTracker.clear(); + } + stopNestedScroll(); + releaseGlows(); + } + + private void cancelTouch() { + resetTouch(); + setScrollState(SCROLL_STATE_IDLE); + } + + private void onPointerUp(MotionEvent e) { + final int actionIndex = MotionEventCompat.getActionIndex(e); + if (MotionEventCompat.getPointerId(e, actionIndex) == mScrollPointerId) { + // Pick a new pointer to pick up the slack. + final int newIndex = actionIndex == 0 ? 1 : 0; + mScrollPointerId = MotionEventCompat.getPointerId(e, newIndex); + mInitialTouchX = mLastTouchX = (int) (MotionEventCompat.getX(e, newIndex) + 0.5f); + mInitialTouchY = mLastTouchY = (int) (MotionEventCompat.getY(e, newIndex) + 0.5f); + } + } + + // @Override + public boolean onGenericMotionEvent(MotionEvent event) { + if (mLayout == null) { + return false; + } + if (mLayoutFrozen) { + return false; + } + if ((MotionEventCompat.getSource(event) & InputDeviceCompat.SOURCE_CLASS_POINTER) != 0) { + if (event.getAction() == MotionEventCompat.ACTION_SCROLL) { + final float vScroll, hScroll; + if (mLayout.canScrollVertically()) { + // Inverse the sign of the vertical scroll to align the scroll orientation + // with AbsListView. + vScroll = -MotionEventCompat + .getAxisValue(event, MotionEventCompat.AXIS_VSCROLL); + } else { + vScroll = 0f; + } + if (mLayout.canScrollHorizontally()) { + hScroll = MotionEventCompat + .getAxisValue(event, MotionEventCompat.AXIS_HSCROLL); + } else { + hScroll = 0f; + } + + if (vScroll != 0 || hScroll != 0) { + final float scrollFactor = getScrollFactor(); + scrollByInternal((int) (hScroll * scrollFactor), + (int) (vScroll * scrollFactor), event); + } + } + } + return false; + } + + /** + * Ported from View.getVerticalScrollFactor. + */ + private float getScrollFactor() { + if (mScrollFactor == Float.MIN_VALUE) { + TypedValue outValue = new TypedValue(); + if (getContext().getTheme().resolveAttribute( + android.R.attr.listPreferredItemHeight, outValue, true)) { + mScrollFactor = outValue.getDimension( + getContext().getResources().getDisplayMetrics()); + } else { + return 0; //listPreferredItemHeight is not defined, no generic scrolling + } + } + return mScrollFactor; + } + + @Override + protected void onMeasure(int widthSpec, int heightSpec) { + if (mLayout == null) { + defaultOnMeasure(widthSpec, heightSpec); + return; + } + if (mLayout.mAutoMeasure) { + final int widthMode = MeasureSpec.getMode(widthSpec); + final int heightMode = MeasureSpec.getMode(heightSpec); + final boolean skipMeasure = widthMode == MeasureSpec.EXACTLY + && heightMode == MeasureSpec.EXACTLY; + mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec); + if (skipMeasure || mAdapter == null) { + return; + } + if (mState.mLayoutStep == State.STEP_START) { + dispatchLayoutStep1(); + } + // set dimensions in 2nd step. Pre-layout should happen with old dimensions for + // consistency + mLayout.setMeasureSpecs(widthSpec, heightSpec); + mState.mIsMeasuring = true; + dispatchLayoutStep2(); + + // now we can get the width and height from the children. + mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec); + + // if RecyclerView has non-exact width and height and if there is at least one child + // which also has non-exact width & height, we have to re-measure. + if (mLayout.shouldMeasureTwice()) { + mLayout.setMeasureSpecs( + MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY)); + mState.mIsMeasuring = true; + dispatchLayoutStep2(); + // now we can get the width and height from the children. + mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec); + } + } else { + if (mHasFixedSize) { + mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec); + return; + } + // custom onMeasure + if (mAdapterUpdateDuringMeasure) { + eatRequestLayout(); + processAdapterUpdatesAndSetAnimationFlags(); + + if (mState.mRunPredictiveAnimations) { + mState.mInPreLayout = true; + } else { + // consume remaining updates to provide a consistent state with the layout pass. + mAdapterHelper.consumeUpdatesInOnePass(); + mState.mInPreLayout = false; + } + mAdapterUpdateDuringMeasure = false; + resumeRequestLayout(false); + } + + if (mAdapter != null) { + mState.mItemCount = mAdapter.getItemCount(); + } else { + mState.mItemCount = 0; + } + eatRequestLayout(); + mLayout.onMeasure(mRecycler, mState, widthSpec, heightSpec); + resumeRequestLayout(false); + mState.mInPreLayout = false; // clear + } + } + + /** + * Used when onMeasure is called before layout manager is set + */ + void defaultOnMeasure(int widthSpec, int heightSpec) { + // calling LayoutManager here is not pretty but that API is already public and it is better + // than creating another method since this is internal. + final int width = LayoutManager.chooseSize(widthSpec, + getPaddingLeft() + getPaddingRight(), + ViewCompat.getMinimumWidth(this)); + final int height = LayoutManager.chooseSize(heightSpec, + getPaddingTop() + getPaddingBottom(), + ViewCompat.getMinimumHeight(this)); + + setMeasuredDimension(width, height); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + if (w != oldw || h != oldh) { + invalidateGlows(); + // layout's w/h are updated during measure/layout steps. + } + } + + /** + * Sets the {@link ItemAnimator} that will handle animations involving changes + * to the items in this RecyclerView. By default, RecyclerView instantiates and + * uses an instance of {@link DefaultItemAnimator}. Whether item animations are + * enabled for the RecyclerView depends on the ItemAnimator and whether + * the LayoutManager {@link LayoutManager#supportsPredictiveItemAnimations() + * supports item animations}. + * + * @param animator The ItemAnimator being set. If null, no animations will occur + * when changes occur to the items in this RecyclerView. + */ + public void setItemAnimator(ItemAnimator animator) { + if (mItemAnimator != null) { + mItemAnimator.endAnimations(); + mItemAnimator.setListener(null); + } + mItemAnimator = animator; + if (mItemAnimator != null) { + mItemAnimator.setListener(mItemAnimatorListener); + } + } + + private void onEnterLayoutOrScroll() { + mLayoutOrScrollCounter ++; + } + + private void onExitLayoutOrScroll() { + mLayoutOrScrollCounter --; + if (mLayoutOrScrollCounter < 1) { + if (DEBUG && mLayoutOrScrollCounter < 0) { + throw new IllegalStateException("layout or scroll counter cannot go below zero." + + "Some calls are not matching"); + } + mLayoutOrScrollCounter = 0; + dispatchContentChangedIfNecessary(); + } + } + + boolean isAccessibilityEnabled() { + return mAccessibilityManager != null && mAccessibilityManager.isEnabled(); + } + + private void dispatchContentChangedIfNecessary() { + final int flags = mEatenAccessibilityChangeFlags; + mEatenAccessibilityChangeFlags = 0; + if (flags != 0 && isAccessibilityEnabled()) { + final AccessibilityEvent event = AccessibilityEvent.obtain(); + event.setEventType(AccessibilityEventCompat.TYPE_WINDOW_CONTENT_CHANGED); + AccessibilityEventCompat.setContentChangeTypes(event, flags); + sendAccessibilityEventUnchecked(event); + } + } + + /** + * Returns whether RecyclerView is currently computing a layout. + *

+ * If this method returns true, it means that RecyclerView is in a lockdown state and any + * attempt to update adapter contents will result in an exception because adapter contents + * cannot be changed while RecyclerView is trying to compute the layout. + *

+ * It is very unlikely that your code will be running during this state as it is + * called by the framework when a layout traversal happens or RecyclerView starts to scroll + * in response to system events (touch, accessibility etc). + *

+ * This case may happen if you have some custom logic to change adapter contents in + * response to a View callback (e.g. focus change callback) which might be triggered during a + * layout calculation. In these cases, you should just postpone the change using a Handler or a + * similar mechanism. + * + * @return true if RecyclerView is currently computing a layout, false + * otherwise + */ + public boolean isComputingLayout() { + return mLayoutOrScrollCounter > 0; + } + + /** + * Returns true if an accessibility event should not be dispatched now. This happens when an + * accessibility request arrives while RecyclerView does not have a stable state which is very + * hard to handle for a LayoutManager. Instead, this method records necessary information about + * the event and dispatches a window change event after the critical section is finished. + * + * @return True if the accessibility event should be postponed. + */ + boolean shouldDeferAccessibilityEvent(AccessibilityEvent event) { + if (isComputingLayout()) { + int type = 0; + if (event != null) { + type = AccessibilityEventCompat.getContentChangeTypes(event); + } + if (type == 0) { + type = AccessibilityEventCompat.CONTENT_CHANGE_TYPE_UNDEFINED; + } + mEatenAccessibilityChangeFlags |= type; + return true; + } + return false; + } + + @Override + public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { + if (shouldDeferAccessibilityEvent(event)) { + return; + } + super.sendAccessibilityEventUnchecked(event); + } + + /** + * Gets the current ItemAnimator for this RecyclerView. A null return value + * indicates that there is no animator and that item changes will happen without + * any animations. By default, RecyclerView instantiates and + * uses an instance of {@link DefaultItemAnimator}. + * + * @return ItemAnimator The current ItemAnimator. If null, no animations will occur + * when changes occur to the items in this RecyclerView. + */ + public ItemAnimator getItemAnimator() { + return mItemAnimator; + } + + /** + * Post a runnable to the next frame to run pending item animations. Only the first such + * request will be posted, governed by the mPostedAnimatorRunner flag. + */ + private void postAnimationRunner() { + if (!mPostedAnimatorRunner && mIsAttached) { + ViewCompat.postOnAnimation(this, mItemAnimatorRunner); + mPostedAnimatorRunner = true; + } + } + + private boolean predictiveItemAnimationsEnabled() { + return (mItemAnimator != null && mLayout.supportsPredictiveItemAnimations()); + } + + /** + * Consumes adapter updates and calculates which type of animations we want to run. + * Called in onMeasure and dispatchLayout. + *

+ * This method may process only the pre-layout state of updates or all of them. + */ + private void processAdapterUpdatesAndSetAnimationFlags() { + if (mDataSetHasChangedAfterLayout) { + // Processing these items have no value since data set changed unexpectedly. + // Instead, we just reset it. + mAdapterHelper.reset(); + markKnownViewsInvalid(); + mLayout.onItemsChanged(this); + } + // simple animations are a subset of advanced animations (which will cause a + // pre-layout step) + // If layout supports predictive animations, pre-process to decide if we want to run them + if (predictiveItemAnimationsEnabled()) { + mAdapterHelper.preProcess(); + } else { + mAdapterHelper.consumeUpdatesInOnePass(); + } + boolean animationTypeSupported = mItemsAddedOrRemoved || mItemsChanged; + mState.mRunSimpleAnimations = mFirstLayoutComplete && mItemAnimator != null && + (mDataSetHasChangedAfterLayout || animationTypeSupported || + mLayout.mRequestedSimpleAnimations) && + (!mDataSetHasChangedAfterLayout || mAdapter.hasStableIds()); + mState.mRunPredictiveAnimations = mState.mRunSimpleAnimations && + animationTypeSupported && !mDataSetHasChangedAfterLayout && + predictiveItemAnimationsEnabled(); + } + + /** + * Wrapper around layoutChildren() that handles animating changes caused by layout. + * Animations work on the assumption that there are five different kinds of items + * in play: + * PERSISTENT: items are visible before and after layout + * REMOVED: items were visible before layout and were removed by the app + * ADDED: items did not exist before layout and were added by the app + * DISAPPEARING: items exist in the data set before/after, but changed from + * visible to non-visible in the process of layout (they were moved off + * screen as a side-effect of other changes) + * APPEARING: items exist in the data set before/after, but changed from + * non-visible to visible in the process of layout (they were moved on + * screen as a side-effect of other changes) + * The overall approach figures out what items exist before/after layout and + * infers one of the five above states for each of the items. Then the animations + * are set up accordingly: + * PERSISTENT views are animated via + * {@link ItemAnimator#animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo)} + * DISAPPEARING views are animated via + * {@link ItemAnimator#animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)} + * APPEARING views are animated via + * {@link ItemAnimator#animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)} + * and changed views are animated via + * {@link ItemAnimator#animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)}. + */ + void dispatchLayout() { + if (mAdapter == null) { + Log.e(TAG, "No adapter attached; skipping layout"); + // leave the state in START + return; + } + if (mLayout == null) { + Log.e(TAG, "No layout manager attached; skipping layout"); + // leave the state in START + return; + } + mState.mIsMeasuring = false; + if (mState.mLayoutStep == State.STEP_START) { + dispatchLayoutStep1(); + mLayout.setExactMeasureSpecsFrom(this); + dispatchLayoutStep2(); + } else if (mAdapterHelper.hasUpdates() || mLayout.getWidth() != getWidth() || + mLayout.getHeight() != getHeight()) { + // First 2 steps are done in onMeasure but looks like we have to run again due to + // changed size. + mLayout.setExactMeasureSpecsFrom(this); + dispatchLayoutStep2(); + } else { + // always make sure we sync them (to ensure mode is exact) + mLayout.setExactMeasureSpecsFrom(this); + } + dispatchLayoutStep3(); + } + + /** + * The first step of a layout where we; + * - process adapter updates + * - decide which animation should run + * - save information about current views + * - If necessary, run predictive layout and save its information + */ + private void dispatchLayoutStep1() { + mState.assertLayoutStep(State.STEP_START); + mState.mIsMeasuring = false; + eatRequestLayout(); + mViewInfoStore.clear(); + onEnterLayoutOrScroll(); + + processAdapterUpdatesAndSetAnimationFlags(); + mState.mTrackOldChangeHolders = mState.mRunSimpleAnimations && mItemsChanged; + mItemsAddedOrRemoved = mItemsChanged = false; + mState.mInPreLayout = mState.mRunPredictiveAnimations; + mState.mItemCount = mAdapter.getItemCount(); + findMinMaxChildLayoutPositions(mMinMaxLayoutPositions); + + if (mState.mRunSimpleAnimations) { + // Step 0: Find out where all non-removed items are, pre-layout + int count = mChildHelper.getChildCount(); + for (int i = 0; i < count; ++i) { + final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i)); + if (holder.shouldIgnore() || (holder.isInvalid() && !mAdapter.hasStableIds())) { + continue; + } + final ItemHolderInfo animationInfo = mItemAnimator + .recordPreLayoutInformation(mState, holder, + ItemAnimator.buildAdapterChangeFlagsForAnimations(holder), + holder.getUnmodifiedPayloads()); + mViewInfoStore.addToPreLayout(holder, animationInfo); + if (mState.mTrackOldChangeHolders && holder.isUpdated() && !holder.isRemoved() + && !holder.shouldIgnore() && !holder.isInvalid()) { + long key = getChangedHolderKey(holder); + // This is NOT the only place where a ViewHolder is added to old change holders + // list. There is another case where: + // * A VH is currently hidden but not deleted + // * The hidden item is changed in the adapter + // * Layout manager decides to layout the item in the pre-Layout pass (step1) + // When this case is detected, RV will un-hide that view and add to the old + // change holders list. + mViewInfoStore.addToOldChangeHolders(key, holder); + } + } + } + if (mState.mRunPredictiveAnimations) { + // Step 1: run prelayout: This will use the old positions of items. The layout manager + // is expected to layout everything, even removed items (though not to add removed + // items back to the container). This gives the pre-layout position of APPEARING views + // which come into existence as part of the real layout. + + // Save old positions so that LayoutManager can run its mapping logic. + saveOldPositions(); + final boolean didStructureChange = mState.mStructureChanged; + mState.mStructureChanged = false; + // temporarily disable flag because we are asking for previous layout + mLayout.onLayoutChildren(mRecycler, mState); + mState.mStructureChanged = didStructureChange; + + for (int i = 0; i < mChildHelper.getChildCount(); ++i) { + final View child = mChildHelper.getChildAt(i); + final ViewHolder viewHolder = getChildViewHolderInt(child); + if (viewHolder.shouldIgnore()) { + continue; + } + if (!mViewInfoStore.isInPreLayout(viewHolder)) { + int flags = ItemAnimator.buildAdapterChangeFlagsForAnimations(viewHolder); + boolean wasHidden = viewHolder + .hasAnyOfTheFlags(ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST); + if (!wasHidden) { + flags |= ItemAnimator.FLAG_APPEARED_IN_PRE_LAYOUT; + } + final ItemHolderInfo animationInfo = mItemAnimator.recordPreLayoutInformation( + mState, viewHolder, flags, viewHolder.getUnmodifiedPayloads()); + if (wasHidden) { + recordAnimationInfoIfBouncedHiddenView(viewHolder, animationInfo); + } else { + mViewInfoStore.addToAppearedInPreLayoutHolders(viewHolder, animationInfo); + } + } + } + // we don't process disappearing list because they may re-appear in post layout pass. + clearOldPositions(); + } else { + clearOldPositions(); + } + onExitLayoutOrScroll(); + resumeRequestLayout(false); + mState.mLayoutStep = State.STEP_LAYOUT; + } + + /** + * The second layout step where we do the actual layout of the views for the final state. + * This step might be run multiple times if necessary (e.g. measure). + */ + private void dispatchLayoutStep2() { + eatRequestLayout(); + onEnterLayoutOrScroll(); + mState.assertLayoutStep(State.STEP_LAYOUT | State.STEP_ANIMATIONS); + mAdapterHelper.consumeUpdatesInOnePass(); + mState.mItemCount = mAdapter.getItemCount(); + mState.mDeletedInvisibleItemCountSincePreviousLayout = 0; + + // Step 2: Run layout + mState.mInPreLayout = false; + mLayout.onLayoutChildren(mRecycler, mState); + + mState.mStructureChanged = false; + mPendingSavedState = null; + + // onLayoutChildren may have caused client code to disable item animations; re-check + mState.mRunSimpleAnimations = mState.mRunSimpleAnimations && mItemAnimator != null; + mState.mLayoutStep = State.STEP_ANIMATIONS; + onExitLayoutOrScroll(); + resumeRequestLayout(false); + } + + /** + * The final step of the layout where we save the information about views for animations, + * trigger animations and do any necessary cleanup. + */ + private void dispatchLayoutStep3() { + mState.assertLayoutStep(State.STEP_ANIMATIONS); + eatRequestLayout(); + onEnterLayoutOrScroll(); + mState.mLayoutStep = State.STEP_START; + if (mState.mRunSimpleAnimations) { + // Step 3: Find out where things are now, and process change animations. + // traverse list in reverse because we may call animateChange in the loop which may + // remove the target view holder. + for (int i = mChildHelper.getChildCount() - 1; i >= 0; i--) { + ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i)); + if (holder.shouldIgnore()) { + continue; + } + long key = getChangedHolderKey(holder); + final ItemHolderInfo animationInfo = mItemAnimator + .recordPostLayoutInformation(mState, holder); + ViewHolder oldChangeViewHolder = mViewInfoStore.getFromOldChangeHolders(key); + if (oldChangeViewHolder != null && !oldChangeViewHolder.shouldIgnore()) { + // run a change animation + + // If an Item is CHANGED but the updated version is disappearing, it creates + // a conflicting case. + // Since a view that is marked as disappearing is likely to be going out of + // bounds, we run a change animation. Both views will be cleaned automatically + // once their animations finish. + // On the other hand, if it is the same view holder instance, we run a + // disappearing animation instead because we are not going to rebind the updated + // VH unless it is enforced by the layout manager. + final boolean oldDisappearing = mViewInfoStore.isDisappearing( + oldChangeViewHolder); + final boolean newDisappearing = mViewInfoStore.isDisappearing(holder); + if (oldDisappearing && oldChangeViewHolder == holder) { + // run disappear animation instead of change + mViewInfoStore.addToPostLayout(holder, animationInfo); + } else { + final ItemHolderInfo preInfo = mViewInfoStore.popFromPreLayout( + oldChangeViewHolder); + // we add and remove so that any post info is merged. + mViewInfoStore.addToPostLayout(holder, animationInfo); + ItemHolderInfo postInfo = mViewInfoStore.popFromPostLayout(holder); + if (preInfo == null) { + handleMissingPreInfoForChangeError(key, holder, oldChangeViewHolder); + } else { + animateChange(oldChangeViewHolder, holder, preInfo, postInfo, + oldDisappearing, newDisappearing); + } + } + } else { + mViewInfoStore.addToPostLayout(holder, animationInfo); + } + } + + // Step 4: Process view info lists and trigger animations + mViewInfoStore.process(mViewInfoProcessCallback); + } + + mLayout.removeAndRecycleScrapInt(mRecycler); + mState.mPreviousLayoutItemCount = mState.mItemCount; + mDataSetHasChangedAfterLayout = false; + mState.mRunSimpleAnimations = false; + + mState.mRunPredictiveAnimations = false; + mLayout.mRequestedSimpleAnimations = false; + if (mRecycler.mChangedScrap != null) { + mRecycler.mChangedScrap.clear(); + } + onExitLayoutOrScroll(); + resumeRequestLayout(false); + mViewInfoStore.clear(); + if (didChildRangeChange(mMinMaxLayoutPositions[0], mMinMaxLayoutPositions[1])) { + dispatchOnScrolled(0, 0); + } + } + + /** + * This handles the case where there is an unexpected VH missing in the pre-layout map. + *

+ * We might be able to detect the error in the application which will help the developer to + * resolve the issue. + *

+ * If it is not an expected error, we at least print an error to notify the developer and ignore + * the animation. + * + * https://code.google.com/p/android/issues/detail?id=193958 + * + * @param key The change key + * @param holder Current ViewHolder + * @param oldChangeViewHolder Changed ViewHolder + */ + private void handleMissingPreInfoForChangeError(long key, + ViewHolder holder, ViewHolder oldChangeViewHolder) { + // check if two VH have the same key, if so, print that as an error + final int childCount = mChildHelper.getChildCount(); + for (int i = 0; i < childCount; i++) { + View view = mChildHelper.getChildAt(i); + ViewHolder other = getChildViewHolderInt(view); + if (other == holder) { + continue; + } + final long otherKey = getChangedHolderKey(other); + if (otherKey == key) { + if (mAdapter != null && mAdapter.hasStableIds()) { + throw new IllegalStateException("Two different ViewHolders have the same stable" + + " ID. Stable IDs in your adapter MUST BE unique and SHOULD NOT" + + " change.\n ViewHolder 1:" + other + " \n View Holder 2:" + holder); + } else { + throw new IllegalStateException("Two different ViewHolders have the same change" + + " ID. This might happen due to inconsistent Adapter update events or" + + " if the LayoutManager lays out the same View multiple times." + + "\n ViewHolder 1:" + other + " \n View Holder 2:" + holder); + } + } + } + // Very unlikely to happen but if it does, notify the developer. + Log.e(TAG, "Problem while matching changed view holders with the new" + + "ones. The pre-layout information for the change holder " + oldChangeViewHolder + + " cannot be found but it is necessary for " + holder); + } + + /** + * Records the animation information for a view holder that was bounced from hidden list. It + * also clears the bounce back flag. + */ + private void recordAnimationInfoIfBouncedHiddenView(ViewHolder viewHolder, + ItemHolderInfo animationInfo) { + // looks like this view bounced back from hidden list! + viewHolder.setFlags(0, ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST); + if (mState.mTrackOldChangeHolders && viewHolder.isUpdated() + && !viewHolder.isRemoved() && !viewHolder.shouldIgnore()) { + long key = getChangedHolderKey(viewHolder); + mViewInfoStore.addToOldChangeHolders(key, viewHolder); + } + mViewInfoStore.addToPreLayout(viewHolder, animationInfo); + } + + private void findMinMaxChildLayoutPositions(int[] into) { + final int count = mChildHelper.getChildCount(); + if (count == 0) { + into[0] = 0; + into[1] = 0; + return; + } + int minPositionPreLayout = Integer.MAX_VALUE; + int maxPositionPreLayout = Integer.MIN_VALUE; + for (int i = 0; i < count; ++i) { + final ViewHolder holder = getChildViewHolderInt(mChildHelper.getChildAt(i)); + if (holder.shouldIgnore()) { + continue; + } + final int pos = holder.getLayoutPosition(); + if (pos < minPositionPreLayout) { + minPositionPreLayout = pos; + } + if (pos > maxPositionPreLayout) { + maxPositionPreLayout = pos; + } + } + into[0] = minPositionPreLayout; + into[1] = maxPositionPreLayout; + } + + private boolean didChildRangeChange(int minPositionPreLayout, int maxPositionPreLayout) { + int count = mChildHelper.getChildCount(); + if (count == 0) { + return minPositionPreLayout != 0 || maxPositionPreLayout != 0; + } + // get the new min max + findMinMaxChildLayoutPositions(mMinMaxLayoutPositions); + return mMinMaxLayoutPositions[0] != minPositionPreLayout || + mMinMaxLayoutPositions[1] != maxPositionPreLayout; + } + + @Override + protected void removeDetachedView(View child, boolean animate) { + ViewHolder vh = getChildViewHolderInt(child); + if (vh != null) { + if (vh.isTmpDetached()) { + vh.clearTmpDetachFlag(); + } else if (!vh.shouldIgnore()) { + throw new IllegalArgumentException("Called removeDetachedView with a view which" + + " is not flagged as tmp detached." + vh); + } + } + dispatchChildDetached(child); + super.removeDetachedView(child, animate); + } + + /** + * Returns a unique key to be used while handling change animations. + * It might be child's position or stable id depending on the adapter type. + */ + long getChangedHolderKey(ViewHolder holder) { + return mAdapter.hasStableIds() ? holder.getItemId() : holder.mPosition; + } + + private void animateAppearance(@NonNull ViewHolder itemHolder, + @Nullable ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo) { + itemHolder.setIsRecyclable(false); + if (mItemAnimator.animateAppearance(itemHolder, preLayoutInfo, postLayoutInfo)) { + postAnimationRunner(); + } + } + + private void animateDisappearance(@NonNull ViewHolder holder, + @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo) { + addAnimatingView(holder); + holder.setIsRecyclable(false); + if (mItemAnimator.animateDisappearance(holder, preLayoutInfo, postLayoutInfo)) { + postAnimationRunner(); + } + } + + private void animateChange(@NonNull ViewHolder oldHolder, @NonNull ViewHolder newHolder, + @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo, + boolean oldHolderDisappearing, boolean newHolderDisappearing) { + oldHolder.setIsRecyclable(false); + if (oldHolderDisappearing) { + addAnimatingView(oldHolder); + } + if (oldHolder != newHolder) { + if (newHolderDisappearing) { + addAnimatingView(newHolder); + } + oldHolder.mShadowedHolder = newHolder; + // old holder should disappear after animation ends + addAnimatingView(oldHolder); + mRecycler.unscrapView(oldHolder); + newHolder.setIsRecyclable(false); + newHolder.mShadowingHolder = oldHolder; + } + if (mItemAnimator.animateChange(oldHolder, newHolder, preInfo, postInfo)) { + postAnimationRunner(); + } + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + TraceCompat.beginSection(TRACE_ON_LAYOUT_TAG); + dispatchLayout(); + TraceCompat.endSection(); + mFirstLayoutComplete = true; + } + + @Override + public void requestLayout() { + if (mEatRequestLayout == 0 && !mLayoutFrozen) { + super.requestLayout(); + } else { + mLayoutRequestEaten = true; + } + } + + public void setTopGlowOffset(int offset) { + topGlowOffset = offset; + } + + public void setGlowColor(int color) { + glowColor = color; + } + + void markItemDecorInsetsDirty() { + final int childCount = mChildHelper.getUnfilteredChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = mChildHelper.getUnfilteredChildAt(i); + ((LayoutParams) child.getLayoutParams()).mInsetsDirty = true; + } + mRecycler.markItemDecorInsetsDirty(); + } + + @Override + public void draw(Canvas c) { + super.draw(c); + + final int count = mItemDecorations.size(); + for (int i = 0; i < count; i++) { + mItemDecorations.get(i).onDrawOver(c, this, mState); + } + // TODO If padding is not 0 and chilChildrenToPadding is false, to draw glows properly, we + // need find children closest to edges. Not sure if it is worth the effort. + boolean needsInvalidate = false; + if (mLeftGlow != null && !mLeftGlow.isFinished()) { + final int restore = c.save(); + final int padding = mClipToPadding ? getPaddingBottom() : 0; + c.rotate(270); + c.translate(-getHeight() + padding, 0); + needsInvalidate = mLeftGlow != null && mLeftGlow.draw(c); + c.restoreToCount(restore); + } + if (mTopGlow != null && !mTopGlow.isFinished()) { + final int restore = c.save(); + if (mClipToPadding) { + c.translate(getPaddingLeft(), getPaddingTop()); + } + c.translate(0, topGlowOffset); + needsInvalidate |= mTopGlow != null && mTopGlow.draw(c); + c.restoreToCount(restore); + } + if (mRightGlow != null && !mRightGlow.isFinished()) { + final int restore = c.save(); + final int width = getWidth(); + final int padding = mClipToPadding ? getPaddingTop() : 0; + c.rotate(90); + c.translate(-padding, -width); + needsInvalidate |= mRightGlow != null && mRightGlow.draw(c); + c.restoreToCount(restore); + } + if (mBottomGlow != null && !mBottomGlow.isFinished()) { + final int restore = c.save(); + c.rotate(180); + if (mClipToPadding) { + c.translate(-getWidth() + getPaddingRight(), -getHeight() + getPaddingBottom()); + } else { + c.translate(-getWidth(), -getHeight()); + } + needsInvalidate |= mBottomGlow != null && mBottomGlow.draw(c); + c.restoreToCount(restore); + } + + // If some views are animating, ItemDecorators are likely to move/change with them. + // Invalidate RecyclerView to re-draw decorators. This is still efficient because children's + // display lists are not invalidated. + if (!needsInvalidate && mItemAnimator != null && mItemDecorations.size() > 0 && + mItemAnimator.isRunning()) { + needsInvalidate = true; + } + + if (needsInvalidate) { + ViewCompat.postInvalidateOnAnimation(this); + } + } + + @Override + public void onDraw(Canvas c) { + super.onDraw(c); + + final int count = mItemDecorations.size(); + for (int i = 0; i < count; i++) { + mItemDecorations.get(i).onDraw(c, this, mState); + } + } + + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams && mLayout.checkLayoutParams((LayoutParams) p); + } + + @Override + protected ViewGroup.LayoutParams generateDefaultLayoutParams() { + if (mLayout == null) { + throw new IllegalStateException("RecyclerView has no LayoutManager"); + } + return mLayout.generateDefaultLayoutParams(); + } + + @Override + public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { + if (mLayout == null) { + throw new IllegalStateException("RecyclerView has no LayoutManager"); + } + return mLayout.generateLayoutParams(getContext(), attrs); + } + + @Override + protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + if (mLayout == null) { + throw new IllegalStateException("RecyclerView has no LayoutManager"); + } + return mLayout.generateLayoutParams(p); + } + + /** + * Returns true if RecyclerView is currently running some animations. + *

+ * If you want to be notified when animations are finished, use + * {@link ItemAnimator#isRunning(ItemAnimator.ItemAnimatorFinishedListener)}. + * + * @return True if there are some item animations currently running or waiting to be started. + */ + public boolean isAnimating() { + return mItemAnimator != null && mItemAnimator.isRunning(); + } + + void saveOldPositions() { + final int childCount = mChildHelper.getUnfilteredChildCount(); + for (int i = 0; i < childCount; i++) { + final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i)); + if (DEBUG && holder.mPosition == -1 && !holder.isRemoved()) { + throw new IllegalStateException("view holder cannot have position -1 unless it" + + " is removed"); + } + if (!holder.shouldIgnore()) { + holder.saveOldPosition(); + } + } + } + + void clearOldPositions() { + final int childCount = mChildHelper.getUnfilteredChildCount(); + for (int i = 0; i < childCount; i++) { + final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i)); + if (!holder.shouldIgnore()) { + holder.clearOldPosition(); + } + } + mRecycler.clearOldPositions(); + } + + void offsetPositionRecordsForMove(int from, int to) { + final int childCount = mChildHelper.getUnfilteredChildCount(); + final int start, end, inBetweenOffset; + if (from < to) { + start = from; + end = to; + inBetweenOffset = -1; + } else { + start = to; + end = from; + inBetweenOffset = 1; + } + + for (int i = 0; i < childCount; i++) { + final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i)); + if (holder == null || holder.mPosition < start || holder.mPosition > end) { + continue; + } + if (DEBUG) { + Log.d(TAG, "offsetPositionRecordsForMove attached child " + i + " holder " + + holder); + } + if (holder.mPosition == from) { + holder.offsetPosition(to - from, false); + } else { + holder.offsetPosition(inBetweenOffset, false); + } + + mState.mStructureChanged = true; + } + mRecycler.offsetPositionRecordsForMove(from, to); + requestLayout(); + } + + void offsetPositionRecordsForInsert(int positionStart, int itemCount) { + final int childCount = mChildHelper.getUnfilteredChildCount(); + for (int i = 0; i < childCount; i++) { + final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i)); + if (holder != null && !holder.shouldIgnore() && holder.mPosition >= positionStart) { + if (DEBUG) { + Log.d(TAG, "offsetPositionRecordsForInsert attached child " + i + " holder " + + holder + " now at position " + (holder.mPosition + itemCount)); + } + holder.offsetPosition(itemCount, false); + mState.mStructureChanged = true; + } + } + mRecycler.offsetPositionRecordsForInsert(positionStart, itemCount); + requestLayout(); + } + + void offsetPositionRecordsForRemove(int positionStart, int itemCount, + boolean applyToPreLayout) { + final int positionEnd = positionStart + itemCount; + final int childCount = mChildHelper.getUnfilteredChildCount(); + for (int i = 0; i < childCount; i++) { + final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i)); + if (holder != null && !holder.shouldIgnore()) { + if (holder.mPosition >= positionEnd) { + if (DEBUG) { + Log.d(TAG, "offsetPositionRecordsForRemove attached child " + i + + " holder " + holder + " now at position " + + (holder.mPosition - itemCount)); + } + holder.offsetPosition(-itemCount, applyToPreLayout); + mState.mStructureChanged = true; + } else if (holder.mPosition >= positionStart) { + if (DEBUG) { + Log.d(TAG, "offsetPositionRecordsForRemove attached child " + i + + " holder " + holder + " now REMOVED"); + } + holder.flagRemovedAndOffsetPosition(positionStart - 1, -itemCount, + applyToPreLayout); + mState.mStructureChanged = true; + } + } + } + mRecycler.offsetPositionRecordsForRemove(positionStart, itemCount, applyToPreLayout); + requestLayout(); + } + + /** + * Rebind existing views for the given range, or create as needed. + * + * @param positionStart Adapter position to start at + * @param itemCount Number of views that must explicitly be rebound + */ + void viewRangeUpdate(int positionStart, int itemCount, Object payload) { + final int childCount = mChildHelper.getUnfilteredChildCount(); + final int positionEnd = positionStart + itemCount; + + for (int i = 0; i < childCount; i++) { + final View child = mChildHelper.getUnfilteredChildAt(i); + final ViewHolder holder = getChildViewHolderInt(child); + if (holder == null || holder.shouldIgnore()) { + continue; + } + if (holder.mPosition >= positionStart && holder.mPosition < positionEnd) { + // We re-bind these view holders after pre-processing is complete so that + // ViewHolders have their final positions assigned. + holder.addFlags(ViewHolder.FLAG_UPDATE); + holder.addChangePayload(payload); + // lp cannot be null since we get ViewHolder from it. + ((LayoutParams) child.getLayoutParams()).mInsetsDirty = true; + } + } + mRecycler.viewRangeUpdate(positionStart, itemCount); + } + + private boolean canReuseUpdatedViewHolder(ViewHolder viewHolder) { + return mItemAnimator == null || mItemAnimator.canReuseUpdatedViewHolder(viewHolder, + viewHolder.getUnmodifiedPayloads()); + } + + private void setDataSetChangedAfterLayout() { + if (mDataSetHasChangedAfterLayout) { + return; + } + mDataSetHasChangedAfterLayout = true; + final int childCount = mChildHelper.getUnfilteredChildCount(); + for (int i = 0; i < childCount; i++) { + final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i)); + if (holder != null && !holder.shouldIgnore()) { + holder.addFlags(ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN); + } + } + mRecycler.setAdapterPositionsAsUnknown(); + } + + /** + * Mark all known views as invalid. Used in response to a, "the whole world might have changed" + * data change event. + */ + void markKnownViewsInvalid() { + final int childCount = mChildHelper.getUnfilteredChildCount(); + for (int i = 0; i < childCount; i++) { + final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i)); + if (holder != null && !holder.shouldIgnore()) { + holder.addFlags(ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID); + } + } + markItemDecorInsetsDirty(); + mRecycler.markKnownViewsInvalid(); + } + + /** + * Invalidates all ItemDecorations. If RecyclerView has item decorations, calling this method + * will trigger a {@link #requestLayout()} call. + */ + public void invalidateItemDecorations() { + if (mItemDecorations.size() == 0) { + return; + } + if (mLayout != null) { + mLayout.assertNotInLayoutOrScroll("Cannot invalidate item decorations during a scroll" + + " or layout"); + } + markItemDecorInsetsDirty(); + requestLayout(); + } + + /** + * Retrieve the {@link ViewHolder} for the given child view. + * + * @param child Child of this RecyclerView to query for its ViewHolder + * @return The child view's ViewHolder + */ + public ViewHolder getChildViewHolder(View child) { + final ViewParent parent = child.getParent(); + if (parent != null && parent != this) { + throw new IllegalArgumentException("View " + child + " is not a direct child of " + + this); + } + return getChildViewHolderInt(child); + } + + /** + * Traverses the ancestors of the given view and returns the item view that contains it and + * also a direct child of the RecyclerView. This returned view can be used to get the + * ViewHolder by calling {@link #getChildViewHolder(View)}. + * + * @param view The view that is a descendant of the RecyclerView. + * + * @return The direct child of the RecyclerView which contains the given view or null if the + * provided view is not a descendant of this RecyclerView. + * + * @see #getChildViewHolder(View) + * @see #findContainingViewHolder(View) + */ + @Nullable + public View findContainingItemView(View view) { + ViewParent parent = view.getParent(); + while (parent != null && parent != this && parent instanceof View) { + view = (View) parent; + parent = view.getParent(); + } + return parent == this ? view : null; + } + + /** + * Returns the ViewHolder that contains the given view. + * + * @param view The view that is a descendant of the RecyclerView. + * + * @return The ViewHolder that contains the given view or null if the provided view is not a + * descendant of this RecyclerView. + */ + @Nullable + public ViewHolder findContainingViewHolder(View view) { + View itemView = findContainingItemView(view); + return itemView == null ? null : getChildViewHolder(itemView); + } + + + static ViewHolder getChildViewHolderInt(View child) { + if (child == null) { + return null; + } + return ((LayoutParams) child.getLayoutParams()).mViewHolder; + } + + /** + * @deprecated use {@link #getChildAdapterPosition(View)} or + * {@link #getChildLayoutPosition(View)}. + */ + @Deprecated + public int getChildPosition(View child) { + return getChildAdapterPosition(child); + } + + /** + * Return the adapter position that the given child view corresponds to. + * + * @param child Child View to query + * @return Adapter position corresponding to the given view or {@link #NO_POSITION} + */ + public int getChildAdapterPosition(View child) { + final ViewHolder holder = getChildViewHolderInt(child); + return holder != null ? holder.getAdapterPosition() : NO_POSITION; + } + + /** + * Return the adapter position of the given child view as of the latest completed layout pass. + *

+ * This position may not be equal to Item's adapter position if there are pending changes + * in the adapter which have not been reflected to the layout yet. + * + * @param child Child View to query + * @return Adapter position of the given View as of last layout pass or {@link #NO_POSITION} if + * the View is representing a removed item. + */ + public int getChildLayoutPosition(View child) { + final ViewHolder holder = getChildViewHolderInt(child); + return holder != null ? holder.getLayoutPosition() : NO_POSITION; + } + + /** + * Return the stable item id that the given child view corresponds to. + * + * @param child Child View to query + * @return Item id corresponding to the given view or {@link #NO_ID} + */ + public long getChildItemId(View child) { + if (mAdapter == null || !mAdapter.hasStableIds()) { + return NO_ID; + } + final ViewHolder holder = getChildViewHolderInt(child); + return holder != null ? holder.getItemId() : NO_ID; + } + + /** + * @deprecated use {@link #findViewHolderForLayoutPosition(int)} or + * {@link #findViewHolderForAdapterPosition(int)} + */ + @Deprecated + public ViewHolder findViewHolderForPosition(int position) { + return findViewHolderForPosition(position, false); + } + + /** + * Return the ViewHolder for the item in the given position of the data set as of the latest + * layout pass. + *

+ * This method checks only the children of RecyclerView. If the item at the given + * position is not laid out, it will not create a new one. + *

+ * Note that when Adapter contents change, ViewHolder positions are not updated until the + * next layout calculation. If there are pending adapter updates, the return value of this + * method may not match your adapter contents. You can use + * #{@link ViewHolder#getAdapterPosition()} to get the current adapter position of a ViewHolder. + * + * @param position The position of the item in the data set of the adapter + * @return The ViewHolder at position or null if there is no such item + */ + public ViewHolder findViewHolderForLayoutPosition(int position) { + return findViewHolderForPosition(position, false); + } + + /** + * Return the ViewHolder for the item in the given position of the data set. Unlike + * {@link #findViewHolderForLayoutPosition(int)} this method takes into account any pending + * adapter changes that may not be reflected to the layout yet. On the other hand, if + * {@link Adapter#notifyDataSetChanged()} has been called but the new layout has not been + * calculated yet, this method will return null since the new positions of views + * are unknown until the layout is calculated. + *

+ * This method checks only the children of RecyclerView. If the item at the given + * position is not laid out, it will not create a new one. + * + * @param position The position of the item in the data set of the adapter + * @return The ViewHolder at position or null if there is no such item + */ + public ViewHolder findViewHolderForAdapterPosition(int position) { + if (mDataSetHasChangedAfterLayout) { + return null; + } + final int childCount = mChildHelper.getUnfilteredChildCount(); + for (int i = 0; i < childCount; i++) { + final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i)); + if (holder != null && !holder.isRemoved() && getAdapterPositionFor(holder) == position) { + return holder; + } + } + return null; + } + + ViewHolder findViewHolderForPosition(int position, boolean checkNewPosition) { + final int childCount = mChildHelper.getUnfilteredChildCount(); + for (int i = 0; i < childCount; i++) { + final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i)); + if (holder != null && !holder.isRemoved()) { + if (checkNewPosition) { + if (holder.mPosition == position) { + return holder; + } + } else if (holder.getLayoutPosition() == position) { + return holder; + } + } + } + // This method should not query cached views. It creates a problem during adapter updates + // when we are dealing with already laid out views. Also, for the public method, it is more + // reasonable to return null if position is not laid out. + return null; + } + + /** + * Return the ViewHolder for the item with the given id. The RecyclerView must + * use an Adapter with {@link Adapter#setHasStableIds(boolean) stableIds} to + * return a non-null value. + *

+ * This method checks only the children of RecyclerView. If the item with the given + * id is not laid out, it will not create a new one. + * + * @param id The id for the requested item + * @return The ViewHolder with the given id or null if there is no such item + */ + public ViewHolder findViewHolderForItemId(long id) { + final int childCount = mChildHelper.getUnfilteredChildCount(); + for (int i = 0; i < childCount; i++) { + final ViewHolder holder = getChildViewHolderInt(mChildHelper.getUnfilteredChildAt(i)); + if (holder != null && holder.getItemId() == id) { + return holder; + } + } + // this method should not query cached views. They are not children so they + // should not be returned in this public method + return null; + } + + /** + * Find the topmost view under the given point. + * + * @param x Horizontal position in pixels to search + * @param y Vertical position in pixels to search + * @return The child view under (x, y) or null if no matching child is found + */ + public View findChildViewUnder(float x, float y) { + final int count = mChildHelper.getChildCount(); + for (int i = count - 1; i >= 0; i--) { + final View child = mChildHelper.getChildAt(i); + final float translationX = ViewCompat.getTranslationX(child); + final float translationY = ViewCompat.getTranslationY(child); + if (x >= child.getLeft() + translationX && + x <= child.getRight() + translationX && + y >= child.getTop() + translationY && + y <= child.getBottom() + translationY) { + return child; + } + } + return null; + } + + @Override + public boolean drawChild(Canvas canvas, View child, long drawingTime) { + return super.drawChild(canvas, child, drawingTime); + } + + /** + * Offset the bounds of all child views by dy pixels. + * Useful for implementing simple scrolling in {@link LayoutManager LayoutManagers}. + * + * @param dy Vertical pixel offset to apply to the bounds of all child views + */ + public void offsetChildrenVertical(int dy) { + final int childCount = mChildHelper.getChildCount(); + for (int i = 0; i < childCount; i++) { + mChildHelper.getChildAt(i).offsetTopAndBottom(dy); + } + } + + /** + * Called when an item view is attached to this RecyclerView. + * + *

Subclasses of RecyclerView may want to perform extra bookkeeping or modifications + * of child views as they become attached. This will be called before a + * {@link LayoutManager} measures or lays out the view and is a good time to perform these + * changes.

+ * + * @param child Child view that is now attached to this RecyclerView and its associated window + */ + public void onChildAttachedToWindow(View child) { + } + + /** + * Called when an item view is detached from this RecyclerView. + * + *

Subclasses of RecyclerView may want to perform extra bookkeeping or modifications + * of child views as they become detached. This will be called as a + * {@link LayoutManager} fully detaches the child view from the parent and its window.

+ * + * @param child Child view that is now detached from this RecyclerView and its associated window + */ + public void onChildDetachedFromWindow(View child) { + } + + /** + * Offset the bounds of all child views by dx pixels. + * Useful for implementing simple scrolling in {@link LayoutManager LayoutManagers}. + * + * @param dx Horizontal pixel offset to apply to the bounds of all child views + */ + public void offsetChildrenHorizontal(int dx) { + final int childCount = mChildHelper.getChildCount(); + for (int i = 0; i < childCount; i++) { + mChildHelper.getChildAt(i).offsetLeftAndRight(dx); + } + } + + Rect getItemDecorInsetsForChild(View child) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (!lp.mInsetsDirty) { + return lp.mDecorInsets; + } + + final Rect insets = lp.mDecorInsets; + insets.set(0, 0, 0, 0); + final int decorCount = mItemDecorations.size(); + for (int i = 0; i < decorCount; i++) { + mTempRect.set(0, 0, 0, 0); + mItemDecorations.get(i).getItemOffsets(mTempRect, child, this, mState); + insets.left += mTempRect.left; + insets.top += mTempRect.top; + insets.right += mTempRect.right; + insets.bottom += mTempRect.bottom; + } + lp.mInsetsDirty = false; + return insets; + } + + /** + * Called when the scroll position of this RecyclerView changes. Subclasses should use + * this method to respond to scrolling within the adapter's data set instead of an explicit + * listener. + * + *

This method will always be invoked before listeners. If a subclass needs to perform + * any additional upkeep or bookkeeping after scrolling but before listeners run, + * this is a good place to do so.

+ * + *

This differs from {@link View#onScrollChanged(int, int, int, int)} in that it receives + * the distance scrolled in either direction within the adapter's data set instead of absolute + * scroll coordinates. Since RecyclerView cannot compute the absolute scroll position from + * any arbitrary point in the data set, onScrollChanged will always receive + * the current {@link View#getScrollX()} and {@link View#getScrollY()} values which + * do not correspond to the data set scroll position. However, some subclasses may choose + * to use these fields as special offsets.

+ * + * @param dx horizontal distance scrolled in pixels + * @param dy vertical distance scrolled in pixels + */ + public void onScrolled(int dx, int dy) { + // Do nothing + } + + void dispatchOnScrolled(int hresult, int vresult) { + // Pass the current scrollX/scrollY values; no actual change in these properties occurred + // but some general-purpose code may choose to respond to changes this way. + final int scrollX = getScrollX(); + final int scrollY = getScrollY(); + onScrollChanged(scrollX, scrollY, scrollX, scrollY); + + // Pass the real deltas to onScrolled, the RecyclerView-specific method. + onScrolled(hresult, vresult); + + // Invoke listeners last. Subclassed view methods always handle the event first. + // All internal state is consistent by the time listeners are invoked. + if (mScrollListener != null) { + mScrollListener.onScrolled(this, hresult, vresult); + } + if (mScrollListeners != null) { + for (int i = mScrollListeners.size() - 1; i >= 0; i--) { + mScrollListeners.get(i).onScrolled(this, hresult, vresult); + } + } + } + + /** + * Called when the scroll state of this RecyclerView changes. Subclasses should use this + * method to respond to state changes instead of an explicit listener. + * + *

This method will always be invoked before listeners, but after the LayoutManager + * responds to the scroll state change.

+ * + * @param state the new scroll state, one of {@link #SCROLL_STATE_IDLE}, + * {@link #SCROLL_STATE_DRAGGING} or {@link #SCROLL_STATE_SETTLING} + */ + public void onScrollStateChanged(int state) { + // Do nothing + } + + void dispatchOnScrollStateChanged(int state) { + // Let the LayoutManager go first; this allows it to bring any properties into + // a consistent state before the RecyclerView subclass responds. + if (mLayout != null) { + mLayout.onScrollStateChanged(state); + } + + // Let the RecyclerView subclass handle this event next; any LayoutManager property + // changes will be reflected by this time. + onScrollStateChanged(state); + + // Listeners go last. All other internal state is consistent by this point. + if (mScrollListener != null) { + mScrollListener.onScrollStateChanged(this, state); + } + if (mScrollListeners != null) { + for (int i = mScrollListeners.size() - 1; i >= 0; i--) { + mScrollListeners.get(i).onScrollStateChanged(this, state); + } + } + } + + /** + * Returns whether there are pending adapter updates which are not yet applied to the layout. + *

+ * If this method returns true, it means that what user is currently seeing may not + * reflect them adapter contents (depending on what has changed). + * You may use this information to defer or cancel some operations. + *

+ * This method returns true if RecyclerView has not yet calculated the first layout after it is + * attached to the Window or the Adapter has been replaced. + * + * @return True if there are some adapter updates which are not yet reflected to layout or false + * if layout is up to date. + */ + public boolean hasPendingAdapterUpdates() { + return !mFirstLayoutComplete || mDataSetHasChangedAfterLayout + || mAdapterHelper.hasPendingUpdates(); + } + + private class ViewFlinger implements Runnable { + private int mLastFlingX; + private int mLastFlingY; + private ScrollerCompat mScroller; + private Interpolator mInterpolator = sQuinticInterpolator; + + + // When set to true, postOnAnimation callbacks are delayed until the run method completes + private boolean mEatRunOnAnimationRequest = false; + + // Tracks if postAnimationCallback should be re-attached when it is done + private boolean mReSchedulePostAnimationCallback = false; + + public ViewFlinger() { + mScroller = ScrollerCompat.create(getContext(), sQuinticInterpolator); + } + + @Override + public void run() { + if (mLayout == null) { + stop(); + return; // no layout, cannot scroll. + } + disableRunOnAnimationRequests(); + consumePendingUpdateOperations(); + // keep a local reference so that if it is changed during onAnimation method, it won't + // cause unexpected behaviors + final ScrollerCompat scroller = mScroller; + final SmoothScroller smoothScroller = mLayout.mSmoothScroller; + if (scroller.computeScrollOffset()) { + final int x = scroller.getCurrX(); + final int y = scroller.getCurrY(); + final int dx = x - mLastFlingX; + final int dy = y - mLastFlingY; + int hresult = 0; + int vresult = 0; + mLastFlingX = x; + mLastFlingY = y; + int overscrollX = 0, overscrollY = 0; + if (mAdapter != null) { + eatRequestLayout(); + onEnterLayoutOrScroll(); + TraceCompat.beginSection(TRACE_SCROLL_TAG); + if (dx != 0) { + hresult = mLayout.scrollHorizontallyBy(dx, mRecycler, mState); + overscrollX = dx - hresult; + } + if (dy != 0) { + vresult = mLayout.scrollVerticallyBy(dy, mRecycler, mState); + overscrollY = dy - vresult; + } + TraceCompat.endSection(); + repositionShadowingViews(); + + onExitLayoutOrScroll(); + resumeRequestLayout(false); + + if (smoothScroller != null && !smoothScroller.isPendingInitialRun() && + smoothScroller.isRunning()) { + final int adapterSize = mState.getItemCount(); + if (adapterSize == 0) { + smoothScroller.stop(); + } else if (smoothScroller.getTargetPosition() >= adapterSize) { + smoothScroller.setTargetPosition(adapterSize - 1); + smoothScroller.onAnimation(dx - overscrollX, dy - overscrollY); + } else { + smoothScroller.onAnimation(dx - overscrollX, dy - overscrollY); + } + } + } + if (!mItemDecorations.isEmpty()) { + invalidate(); + } + if (ViewCompat.getOverScrollMode(RecyclerView.this) != + ViewCompat.OVER_SCROLL_NEVER) { + considerReleasingGlowsOnScroll(dx, dy); + } + if (overscrollX != 0 || overscrollY != 0) { + final int vel = (int) scroller.getCurrVelocity(); + + int velX = 0; + if (overscrollX != x) { + velX = overscrollX < 0 ? -vel : overscrollX > 0 ? vel : 0; + } + + int velY = 0; + if (overscrollY != y) { + velY = overscrollY < 0 ? -vel : overscrollY > 0 ? vel : 0; + } + + if (ViewCompat.getOverScrollMode(RecyclerView.this) != + ViewCompat.OVER_SCROLL_NEVER) { + absorbGlows(velX, velY); + } + if ((velX != 0 || overscrollX == x || scroller.getFinalX() == 0) && + (velY != 0 || overscrollY == y || scroller.getFinalY() == 0)) { + scroller.abortAnimation(); + } + } + if (hresult != 0 || vresult != 0) { + dispatchOnScrolled(hresult, vresult); + } + + if (!awakenScrollBars()) { + invalidate(); + } + + final boolean fullyConsumedVertical = dy != 0 && mLayout.canScrollVertically() + && vresult == dy; + final boolean fullyConsumedHorizontal = dx != 0 && mLayout.canScrollHorizontally() + && hresult == dx; + final boolean fullyConsumedAny = (dx == 0 && dy == 0) || fullyConsumedHorizontal + || fullyConsumedVertical; + + if (scroller.isFinished() || !fullyConsumedAny) { + setScrollState(SCROLL_STATE_IDLE); // setting state to idle will stop this. + } else { + postOnAnimation(); + } + } + // call this after the onAnimation is complete not to have inconsistent callbacks etc. + if (smoothScroller != null) { + if (smoothScroller.isPendingInitialRun()) { + smoothScroller.onAnimation(0, 0); + } + if (!mReSchedulePostAnimationCallback) { + smoothScroller.stop(); //stop if it does not trigger any scroll + } + } + enableRunOnAnimationRequests(); + } + + private void disableRunOnAnimationRequests() { + mReSchedulePostAnimationCallback = false; + mEatRunOnAnimationRequest = true; + } + + private void enableRunOnAnimationRequests() { + mEatRunOnAnimationRequest = false; + if (mReSchedulePostAnimationCallback) { + postOnAnimation(); + } + } + + void postOnAnimation() { + if (mEatRunOnAnimationRequest) { + mReSchedulePostAnimationCallback = true; + } else { + removeCallbacks(this); + ViewCompat.postOnAnimation(RecyclerView.this, this); + } + } + + public void fling(int velocityX, int velocityY) { + setScrollState(SCROLL_STATE_SETTLING); + mLastFlingX = mLastFlingY = 0; + mScroller.fling(0, 0, velocityX, velocityY, + Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE); + postOnAnimation(); + } + + public void smoothScrollBy(int dx, int dy) { + smoothScrollBy(dx, dy, 0, 0); + } + + public void smoothScrollBy(int dx, int dy, int vx, int vy) { + smoothScrollBy(dx, dy, computeScrollDuration(dx, dy, vx, vy)); + } + + private float distanceInfluenceForSnapDuration(float f) { + f -= 0.5f; // center the values about 0. + f *= 0.3f * Math.PI / 2.0f; + return (float) Math.sin(f); + } + + private int computeScrollDuration(int dx, int dy, int vx, int vy) { + final int absDx = Math.abs(dx); + final int absDy = Math.abs(dy); + final boolean horizontal = absDx > absDy; + final int velocity = (int) Math.sqrt(vx * vx + vy * vy); + final int delta = (int) Math.sqrt(dx * dx + dy * dy); + final int containerSize = horizontal ? getWidth() : getHeight(); + final int halfContainerSize = containerSize / 2; + final float distanceRatio = Math.min(1.f, 1.f * delta / containerSize); + final float distance = halfContainerSize + halfContainerSize * + distanceInfluenceForSnapDuration(distanceRatio); + + final int duration; + if (velocity > 0) { + duration = 4 * Math.round(1000 * Math.abs(distance / velocity)); + } else { + float absDelta = (float) (horizontal ? absDx : absDy); + duration = (int) (((absDelta / containerSize) + 1) * 300); + } + return Math.min(duration, MAX_SCROLL_DURATION); + } + + public void smoothScrollBy(int dx, int dy, int duration) { + smoothScrollBy(dx, dy, duration, sQuinticInterpolator); + } + + public void smoothScrollBy(int dx, int dy, int duration, Interpolator interpolator) { + if (mInterpolator != interpolator) { + mInterpolator = interpolator; + mScroller = ScrollerCompat.create(getContext(), interpolator); + } + setScrollState(SCROLL_STATE_SETTLING); + mLastFlingX = mLastFlingY = 0; + mScroller.startScroll(0, 0, dx, dy, duration); + postOnAnimation(); + } + + public void stop() { + removeCallbacks(this); + mScroller.abortAnimation(); + } + + } + + private void repositionShadowingViews() { + // Fix up shadow views used by change animations + int count = mChildHelper.getChildCount(); + for (int i = 0; i < count; i++) { + View view = mChildHelper.getChildAt(i); + ViewHolder holder = getChildViewHolder(view); + if (holder != null && holder.mShadowingHolder != null) { + View shadowingView = holder.mShadowingHolder.itemView; + int left = view.getLeft(); + int top = view.getTop(); + if (left != shadowingView.getLeft() || + top != shadowingView.getTop()) { + shadowingView.layout(left, top, + left + shadowingView.getWidth(), + top + shadowingView.getHeight()); + } + } + } + } + + private class RecyclerViewDataObserver extends AdapterDataObserver { + @Override + public void onChanged() { + assertNotInLayoutOrScroll(null); + if (mAdapter.hasStableIds()) { + // TODO Determine what actually changed. + // This is more important to implement now since this callback will disable all + // animations because we cannot rely on positions. + mState.mStructureChanged = true; + setDataSetChangedAfterLayout(); + } else { + mState.mStructureChanged = true; + setDataSetChangedAfterLayout(); + } + if (!mAdapterHelper.hasPendingUpdates()) { + requestLayout(); + } + } + + @Override + public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { + assertNotInLayoutOrScroll(null); + if (mAdapterHelper.onItemRangeChanged(positionStart, itemCount, payload)) { + triggerUpdateProcessor(); + } + } + + @Override + public void onItemRangeInserted(int positionStart, int itemCount) { + assertNotInLayoutOrScroll(null); + if (mAdapterHelper.onItemRangeInserted(positionStart, itemCount)) { + triggerUpdateProcessor(); + } + } + + @Override + public void onItemRangeRemoved(int positionStart, int itemCount) { + assertNotInLayoutOrScroll(null); + if (mAdapterHelper.onItemRangeRemoved(positionStart, itemCount)) { + triggerUpdateProcessor(); + } + } + + @Override + public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { + assertNotInLayoutOrScroll(null); + if (mAdapterHelper.onItemRangeMoved(fromPosition, toPosition, itemCount)) { + triggerUpdateProcessor(); + } + } + + void triggerUpdateProcessor() { + if (mPostUpdatesOnAnimation && mHasFixedSize && mIsAttached) { + ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable); + } else { + mAdapterUpdateDuringMeasure = true; + requestLayout(); + } + } + } + + /** + * RecycledViewPool lets you share Views between multiple RecyclerViews. + *

+ * If you want to recycle views across RecyclerViews, create an instance of RecycledViewPool + * and use {@link RecyclerView#setRecycledViewPool(RecycledViewPool)}. + *

+ * RecyclerView automatically creates a pool for itself if you don't provide one. + * + */ + public static class RecycledViewPool { + private SparseArray> mScrap = + new SparseArray>(); + private SparseIntArray mMaxScrap = new SparseIntArray(); + private int mAttachCount = 0; + + private static final int DEFAULT_MAX_SCRAP = 5; + + public void clear() { + mScrap.clear(); + } + + public void setMaxRecycledViews(int viewType, int max) { + mMaxScrap.put(viewType, max); + final ArrayList scrapHeap = mScrap.get(viewType); + if (scrapHeap != null) { + while (scrapHeap.size() > max) { + scrapHeap.remove(scrapHeap.size() - 1); + } + } + } + + public ViewHolder getRecycledView(int viewType) { + final ArrayList scrapHeap = mScrap.get(viewType); + if (scrapHeap != null && !scrapHeap.isEmpty()) { + final int index = scrapHeap.size() - 1; + final ViewHolder scrap = scrapHeap.get(index); + scrapHeap.remove(index); + return scrap; + } + return null; + } + + int size() { + int count = 0; + for (int i = 0; i < mScrap.size(); i ++) { + ArrayList viewHolders = mScrap.valueAt(i); + if (viewHolders != null) { + count += viewHolders.size(); + } + } + return count; + } + + public void putRecycledView(ViewHolder scrap) { + final int viewType = scrap.getItemViewType(); + final ArrayList scrapHeap = getScrapHeapForType(viewType); + if (mMaxScrap.get(viewType) <= scrapHeap.size()) { + return; + } + if (DEBUG && scrapHeap.contains(scrap)) { + throw new IllegalArgumentException("this scrap item already exists"); + } + scrap.resetInternal(); + scrapHeap.add(scrap); + } + + void attach(Adapter adapter) { + mAttachCount++; + } + + void detach() { + mAttachCount--; + } + + + /** + * Detaches the old adapter and attaches the new one. + *

+ * RecycledViewPool will clear its cache if it has only one adapter attached and the new + * adapter uses a different ViewHolder than the oldAdapter. + * + * @param oldAdapter The previous adapter instance. Will be detached. + * @param newAdapter The new adapter instance. Will be attached. + * @param compatibleWithPrevious True if both oldAdapter and newAdapter are using the same + * ViewHolder and view types. + */ + void onAdapterChanged(Adapter oldAdapter, Adapter newAdapter, + boolean compatibleWithPrevious) { + if (oldAdapter != null) { + detach(); + } + if (!compatibleWithPrevious && mAttachCount == 0) { + clear(); + } + if (newAdapter != null) { + attach(newAdapter); + } + } + + private ArrayList getScrapHeapForType(int viewType) { + ArrayList scrap = mScrap.get(viewType); + if (scrap == null) { + scrap = new ArrayList<>(); + mScrap.put(viewType, scrap); + if (mMaxScrap.indexOfKey(viewType) < 0) { + mMaxScrap.put(viewType, DEFAULT_MAX_SCRAP); + } + } + return scrap; + } + } + + /** + * A Recycler is responsible for managing scrapped or detached item views for reuse. + * + *

A "scrapped" view is a view that is still attached to its parent RecyclerView but + * that has been marked for removal or reuse.

+ * + *

Typical use of a Recycler by a {@link LayoutManager} will be to obtain views for + * an adapter's data set representing the data at a given position or item ID. + * If the view to be reused is considered "dirty" the adapter will be asked to rebind it. + * If not, the view can be quickly reused by the LayoutManager with no further work. + * Clean views that have not {@link android.view.View#isLayoutRequested() requested layout} + * may be repositioned by a LayoutManager without remeasurement.

+ */ + public final class Recycler { + final ArrayList mAttachedScrap = new ArrayList<>(); + private ArrayList mChangedScrap = null; + + final ArrayList mCachedViews = new ArrayList(); + + private final List + mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap); + + private int mViewCacheMax = DEFAULT_CACHE_SIZE; + + private RecycledViewPool mRecyclerPool; + + private ViewCacheExtension mViewCacheExtension; + + private static final int DEFAULT_CACHE_SIZE = 2; + + /** + * Clear scrap views out of this recycler. Detached views contained within a + * recycled view pool will remain. + */ + public void clear() { + mAttachedScrap.clear(); + recycleAndClearCachedViews(); + } + + /** + * Set the maximum number of detached, valid views we should retain for later use. + * + * @param viewCount Number of views to keep before sending views to the shared pool + */ + public void setViewCacheSize(int viewCount) { + mViewCacheMax = viewCount; + // first, try the views that can be recycled + for (int i = mCachedViews.size() - 1; i >= 0 && mCachedViews.size() > viewCount; i--) { + recycleCachedViewAt(i); + } + } + + /** + * Returns an unmodifiable list of ViewHolders that are currently in the scrap list. + * + * @return List of ViewHolders in the scrap list. + */ + public List getScrapList() { + return mUnmodifiableAttachedScrap; + } + + /** + * Helper method for getViewForPosition. + *

+ * Checks whether a given view holder can be used for the provided position. + * + * @param holder ViewHolder + * @return true if ViewHolder matches the provided position, false otherwise + */ + boolean validateViewHolderForOffsetPosition(ViewHolder holder) { + // if it is a removed holder, nothing to verify since we cannot ask adapter anymore + // if it is not removed, verify the type and id. + if (holder.isRemoved()) { + if (DEBUG && !mState.isPreLayout()) { + throw new IllegalStateException("should not receive a removed view unelss it" + + " is pre layout"); + } + return mState.isPreLayout(); + } + if (holder.mPosition < 0 || holder.mPosition >= mAdapter.getItemCount()) { + throw new IndexOutOfBoundsException("Inconsistency detected. Invalid view holder " + + "adapter position" + holder); + } + if (!mState.isPreLayout()) { + // don't check type if it is pre-layout. + final int type = mAdapter.getItemViewType(holder.mPosition); + if (type != holder.getItemViewType()) { + return false; + } + } + if (mAdapter.hasStableIds()) { + return holder.getItemId() == mAdapter.getItemId(holder.mPosition); + } + return true; + } + + /** + * Binds the given View to the position. The View can be a View previously retrieved via + * {@link #getViewForPosition(int)} or created by + * {@link Adapter#onCreateViewHolder(ViewGroup, int)}. + *

+ * Generally, a LayoutManager should acquire its views via {@link #getViewForPosition(int)} + * and let the RecyclerView handle caching. This is a helper method for LayoutManager who + * wants to handle its own recycling logic. + *

+ * Note that, {@link #getViewForPosition(int)} already binds the View to the position so + * you don't need to call this method unless you want to bind this View to another position. + * + * @param view The view to update. + * @param position The position of the item to bind to this View. + */ + public void bindViewToPosition(View view, int position) { + ViewHolder holder = getChildViewHolderInt(view); + if (holder == null) { + throw new IllegalArgumentException("The view does not have a ViewHolder. You cannot" + + " pass arbitrary views to this method, they should be created by the " + + "Adapter"); + } + final int offsetPosition = mAdapterHelper.findPositionOffset(position); + if (offsetPosition < 0 || offsetPosition >= mAdapter.getItemCount()) { + throw new IndexOutOfBoundsException("Inconsistency detected. Invalid item " + + "position " + position + "(offset:" + offsetPosition + ")." + + "state:" + mState.getItemCount()); + } + holder.mOwnerRecyclerView = RecyclerView.this; + mAdapter.bindViewHolder(holder, offsetPosition); + attachAccessibilityDelegate(view); + if (mState.isPreLayout()) { + holder.mPreLayoutPosition = position; + } + + final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); + final LayoutParams rvLayoutParams; + if (lp == null) { + rvLayoutParams = (LayoutParams) generateDefaultLayoutParams(); + holder.itemView.setLayoutParams(rvLayoutParams); + } else if (!checkLayoutParams(lp)) { + rvLayoutParams = (LayoutParams) generateLayoutParams(lp); + holder.itemView.setLayoutParams(rvLayoutParams); + } else { + rvLayoutParams = (LayoutParams) lp; + } + + rvLayoutParams.mInsetsDirty = true; + rvLayoutParams.mViewHolder = holder; + rvLayoutParams.mPendingInvalidate = holder.itemView.getParent() == null; + } + + /** + * RecyclerView provides artificial position range (item count) in pre-layout state and + * automatically maps these positions to {@link Adapter} positions when + * {@link #getViewForPosition(int)} or {@link #bindViewToPosition(View, int)} is called. + *

+ * Usually, LayoutManager does not need to worry about this. However, in some cases, your + * LayoutManager may need to call some custom component with item positions in which + * case you need the actual adapter position instead of the pre layout position. You + * can use this method to convert a pre-layout position to adapter (post layout) position. + *

+ * Note that if the provided position belongs to a deleted ViewHolder, this method will + * return -1. + *

+ * Calling this method in post-layout state returns the same value back. + * + * @param position The pre-layout position to convert. Must be greater or equal to 0 and + * less than {@link State#getItemCount()}. + */ + public int convertPreLayoutPositionToPostLayout(int position) { + if (position < 0 || position >= mState.getItemCount()) { + throw new IndexOutOfBoundsException("invalid position " + position + ". State " + + "item count is " + mState.getItemCount()); + } + if (!mState.isPreLayout()) { + return position; + } + return mAdapterHelper.findPositionOffset(position); + } + + /** + * Obtain a view initialized for the given position. + * + * This method should be used by {@link LayoutManager} implementations to obtain + * views to represent data from an {@link Adapter}. + *

+ * The Recycler may reuse a scrap or detached view from a shared pool if one is + * available for the correct view type. If the adapter has not indicated that the + * data at the given position has changed, the Recycler will attempt to hand back + * a scrap view that was previously initialized for that data without rebinding. + * + * @param position Position to obtain a view for + * @return A view representing the data at position from adapter + */ + public View getViewForPosition(int position) { + return getViewForPosition(position, false); + } + + View getViewForPosition(int position, boolean dryRun) { + if (position < 0 || position >= mState.getItemCount()) { + throw new IndexOutOfBoundsException("Invalid item position " + position + + "(" + position + "). Item count:" + mState.getItemCount()); + } + boolean fromScrap = false; + ViewHolder holder = null; + // 0) If there is a changed scrap, try to find from there + if (mState.isPreLayout()) { + holder = getChangedScrapViewForPosition(position); + fromScrap = holder != null; + } + // 1) Find from scrap by position + if (holder == null) { + holder = getScrapViewForPosition(position, INVALID_TYPE, dryRun); + if (holder != null) { + if (!validateViewHolderForOffsetPosition(holder)) { + // recycle this scrap + if (!dryRun) { + // we would like to recycle this but need to make sure it is not used by + // animation logic etc. + holder.addFlags(ViewHolder.FLAG_INVALID); + if (holder.isScrap()) { + removeDetachedView(holder.itemView, false); + holder.unScrap(); + } else if (holder.wasReturnedFromScrap()) { + holder.clearReturnedFromScrapFlag(); + } + recycleViewHolderInternal(holder); + } + holder = null; + } else { + fromScrap = true; + } + } + } + if (holder == null) { + final int offsetPosition = mAdapterHelper.findPositionOffset(position); + if (offsetPosition < 0 || offsetPosition >= mAdapter.getItemCount()) { + throw new IndexOutOfBoundsException("Inconsistency detected. Invalid item " + + "position " + position + "(offset:" + offsetPosition + ")." + + "state:" + mState.getItemCount()); + } + + final int type = mAdapter.getItemViewType(offsetPosition); + // 2) Find from scrap via stable ids, if exists + if (mAdapter.hasStableIds()) { + holder = getScrapViewForId(mAdapter.getItemId(offsetPosition), type, dryRun); + if (holder != null) { + // update position + holder.mPosition = offsetPosition; + fromScrap = true; + } + } + if (holder == null && mViewCacheExtension != null) { + // We are NOT sending the offsetPosition because LayoutManager does not + // know it. + final View view = mViewCacheExtension + .getViewForPositionAndType(this, position, type); + if (view != null) { + holder = getChildViewHolder(view); + if (holder == null) { + throw new IllegalArgumentException("getViewForPositionAndType returned" + + " a view which does not have a ViewHolder"); + } else if (holder.shouldIgnore()) { + throw new IllegalArgumentException("getViewForPositionAndType returned" + + " a view that is ignored. You must call stopIgnoring before" + + " returning this view."); + } + } + } + if (holder == null) { // fallback to recycler + // try recycler. + // Head to the shared pool. + if (DEBUG) { + Log.d(TAG, "getViewForPosition(" + position + ") fetching from shared " + + "pool"); + } + holder = getRecycledViewPool().getRecycledView(type); + if (holder != null) { + holder.resetInternal(); + if (FORCE_INVALIDATE_DISPLAY_LIST) { + invalidateDisplayListInt(holder); + } + } + } + if (holder == null) { + holder = mAdapter.createViewHolder(RecyclerView.this, type); + if (DEBUG) { + Log.d(TAG, "getViewForPosition created new ViewHolder"); + } + } + } + + // This is very ugly but the only place we can grab this information + // before the View is rebound and returned to the LayoutManager for post layout ops. + // We don't need this in pre-layout since the VH is not updated by the LM. + if (fromScrap && !mState.isPreLayout() && holder + .hasAnyOfTheFlags(ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST)) { + holder.setFlags(0, ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST); + if (mState.mRunSimpleAnimations) { + int changeFlags = ItemAnimator + .buildAdapterChangeFlagsForAnimations(holder); + changeFlags |= ItemAnimator.FLAG_APPEARED_IN_PRE_LAYOUT; + final ItemHolderInfo info = mItemAnimator.recordPreLayoutInformation(mState, + holder, changeFlags, holder.getUnmodifiedPayloads()); + recordAnimationInfoIfBouncedHiddenView(holder, info); + } + } + + boolean bound = false; + if (mState.isPreLayout() && holder.isBound()) { + // do not update unless we absolutely have to. + holder.mPreLayoutPosition = position; + } else if (!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) { + if (DEBUG && holder.isRemoved()) { + throw new IllegalStateException("Removed holder should be bound and it should" + + " come here only in pre-layout. Holder: " + holder); + } + final int offsetPosition = mAdapterHelper.findPositionOffset(position); + holder.mOwnerRecyclerView = RecyclerView.this; + mAdapter.bindViewHolder(holder, offsetPosition); + attachAccessibilityDelegate(holder.itemView); + bound = true; + if (mState.isPreLayout()) { + holder.mPreLayoutPosition = position; + } + } + + final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams(); + final LayoutParams rvLayoutParams; + if (lp == null) { + rvLayoutParams = (LayoutParams) generateDefaultLayoutParams(); + holder.itemView.setLayoutParams(rvLayoutParams); + } else if (!checkLayoutParams(lp)) { + rvLayoutParams = (LayoutParams) generateLayoutParams(lp); + holder.itemView.setLayoutParams(rvLayoutParams); + } else { + rvLayoutParams = (LayoutParams) lp; + } + rvLayoutParams.mViewHolder = holder; + rvLayoutParams.mPendingInvalidate = fromScrap && bound; + return holder.itemView; + } + + private void attachAccessibilityDelegate(View itemView) { + if (isAccessibilityEnabled()) { + if (ViewCompat.getImportantForAccessibility(itemView) == + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + ViewCompat.setImportantForAccessibility(itemView, + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES); + } + if (!ViewCompat.hasAccessibilityDelegate(itemView)) { + ViewCompat.setAccessibilityDelegate(itemView, + mAccessibilityDelegate.getItemDelegate()); + } + } + } + + private void invalidateDisplayListInt(ViewHolder holder) { + if (holder.itemView instanceof ViewGroup) { + invalidateDisplayListInt((ViewGroup) holder.itemView, false); + } + } + + private void invalidateDisplayListInt(ViewGroup viewGroup, boolean invalidateThis) { + for (int i = viewGroup.getChildCount() - 1; i >= 0; i--) { + final View view = viewGroup.getChildAt(i); + if (view instanceof ViewGroup) { + invalidateDisplayListInt((ViewGroup) view, true); + } + } + if (!invalidateThis) { + return; + } + // we need to force it to become invisible + if (viewGroup.getVisibility() == View.INVISIBLE) { + viewGroup.setVisibility(View.VISIBLE); + viewGroup.setVisibility(View.INVISIBLE); + } else { + final int visibility = viewGroup.getVisibility(); + viewGroup.setVisibility(View.INVISIBLE); + viewGroup.setVisibility(visibility); + } + } + + /** + * Recycle a detached view. The specified view will be added to a pool of views + * for later rebinding and reuse. + * + *

A view must be fully detached (removed from parent) before it may be recycled. If the + * View is scrapped, it will be removed from scrap list.

+ * + * @param view Removed view for recycling + * @see LayoutManager#removeAndRecycleView(View, Recycler) + */ + public void recycleView(View view) { + // This public recycle method tries to make view recycle-able since layout manager + // intended to recycle this view (e.g. even if it is in scrap or change cache) + ViewHolder holder = getChildViewHolderInt(view); + if (holder.isTmpDetached()) { + removeDetachedView(view, false); + } + if (holder.isScrap()) { + holder.unScrap(); + } else if (holder.wasReturnedFromScrap()){ + holder.clearReturnedFromScrapFlag(); + } + recycleViewHolderInternal(holder); + } + + /** + * Internally, use this method instead of {@link #recycleView(android.view.View)} to + * catch potential bugs. + * @param view + */ + void recycleViewInternal(View view) { + recycleViewHolderInternal(getChildViewHolderInt(view)); + } + + void recycleAndClearCachedViews() { + final int count = mCachedViews.size(); + for (int i = count - 1; i >= 0; i--) { + recycleCachedViewAt(i); + } + mCachedViews.clear(); + } + + /** + * Recycles a cached view and removes the view from the list. Views are added to cache + * if and only if they are recyclable, so this method does not check it again. + *

+ * A small exception to this rule is when the view does not have an animator reference + * but transient state is true (due to animations created outside ItemAnimator). In that + * case, adapter may choose to recycle it. From RecyclerView's perspective, the view is + * still recyclable since Adapter wants to do so. + * + * @param cachedViewIndex The index of the view in cached views list + */ + void recycleCachedViewAt(int cachedViewIndex) { + if (DEBUG) { + Log.d(TAG, "Recycling cached view at index " + cachedViewIndex); + } + ViewHolder viewHolder = mCachedViews.get(cachedViewIndex); + if (DEBUG) { + Log.d(TAG, "CachedViewHolder to be recycled: " + viewHolder); + } + addViewHolderToRecycledViewPool(viewHolder); + mCachedViews.remove(cachedViewIndex); + } + + /** + * internal implementation checks if view is scrapped or attached and throws an exception + * if so. + * Public version un-scraps before calling recycle. + */ + void recycleViewHolderInternal(ViewHolder holder) { + if (holder.isScrap() || holder.itemView.getParent() != null) { + throw new IllegalArgumentException( + "Scrapped or attached views may not be recycled. isScrap:" + + holder.isScrap() + " isAttached:" + + (holder.itemView.getParent() != null)); + } + + if (holder.isTmpDetached()) { + throw new IllegalArgumentException("Tmp detached view should be removed " + + "from RecyclerView before it can be recycled: " + holder); + } + + if (holder.shouldIgnore()) { + throw new IllegalArgumentException("Trying to recycle an ignored view holder. You" + + " should first call stopIgnoringView(view) before calling recycle."); + } + //noinspection unchecked + final boolean transientStatePreventsRecycling = holder + .doesTransientStatePreventRecycling(); + final boolean forceRecycle = mAdapter != null + && transientStatePreventsRecycling + && mAdapter.onFailedToRecycleView(holder); + boolean cached = false; + boolean recycled = false; + if (DEBUG && mCachedViews.contains(holder)) { + throw new IllegalArgumentException("cached view received recycle internal? " + + holder); + } + if (forceRecycle || holder.isRecyclable()) { + if (!holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID | ViewHolder.FLAG_REMOVED + | ViewHolder.FLAG_UPDATE)) { + // Retire oldest cached view + final int cachedViewSize = mCachedViews.size(); + if (cachedViewSize == mViewCacheMax && cachedViewSize > 0) { + recycleCachedViewAt(0); + } + if (cachedViewSize < mViewCacheMax) { + mCachedViews.add(holder); + cached = true; + } + } + if (!cached) { + addViewHolderToRecycledViewPool(holder); + recycled = true; + } + } else if (DEBUG) { + Log.d(TAG, "trying to recycle a non-recycleable holder. Hopefully, it will " + + "re-visit here. We are still removing it from animation lists"); + } + // even if the holder is not removed, we still call this method so that it is removed + // from view holder lists. + mViewInfoStore.removeViewHolder(holder); + if (!cached && !recycled && transientStatePreventsRecycling) { + holder.mOwnerRecyclerView = null; + } + } + + void addViewHolderToRecycledViewPool(ViewHolder holder) { + ViewCompat.setAccessibilityDelegate(holder.itemView, null); + dispatchViewRecycled(holder); + holder.mOwnerRecyclerView = null; + getRecycledViewPool().putRecycledView(holder); + } + + /** + * Used as a fast path for unscrapping and recycling a view during a bulk operation. + * The caller must call {@link #clearScrap()} when it's done to update the recycler's + * internal bookkeeping. + */ + void quickRecycleScrapView(View view) { + final ViewHolder holder = getChildViewHolderInt(view); + holder.mScrapContainer = null; + holder.mInChangeScrap = false; + holder.clearReturnedFromScrapFlag(); + recycleViewHolderInternal(holder); + } + + /** + * Mark an attached view as scrap. + * + *

"Scrap" views are still attached to their parent RecyclerView but are eligible + * for rebinding and reuse. Requests for a view for a given position may return a + * reused or rebound scrap view instance.

+ * + * @param view View to scrap + */ + void scrapView(View view) { + final ViewHolder holder = getChildViewHolderInt(view); + if (holder.hasAnyOfTheFlags(ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_INVALID) + || !holder.isUpdated() || canReuseUpdatedViewHolder(holder)) { + if (holder.isInvalid() && !holder.isRemoved() && !mAdapter.hasStableIds()) { + throw new IllegalArgumentException("Called scrap view with an invalid view." + + " Invalid views cannot be reused from scrap, they should rebound from" + + " recycler pool."); + } + holder.setScrapContainer(this, false); + mAttachedScrap.add(holder); + } else { + if (mChangedScrap == null) { + mChangedScrap = new ArrayList(); + } + holder.setScrapContainer(this, true); + mChangedScrap.add(holder); + } + } + + /** + * Remove a previously scrapped view from the pool of eligible scrap. + * + *

This view will no longer be eligible for reuse until re-scrapped or + * until it is explicitly removed and recycled.

+ */ + void unscrapView(ViewHolder holder) { + if (holder.mInChangeScrap) { + mChangedScrap.remove(holder); + } else { + mAttachedScrap.remove(holder); + } + holder.mScrapContainer = null; + holder.mInChangeScrap = false; + holder.clearReturnedFromScrapFlag(); + } + + int getScrapCount() { + return mAttachedScrap.size(); + } + + View getScrapViewAt(int index) { + return mAttachedScrap.get(index).itemView; + } + + void clearScrap() { + mAttachedScrap.clear(); + if (mChangedScrap != null) { + mChangedScrap.clear(); + } + } + + ViewHolder getChangedScrapViewForPosition(int position) { + // If pre-layout, check the changed scrap for an exact match. + final int changedScrapSize; + if (mChangedScrap == null || (changedScrapSize = mChangedScrap.size()) == 0) { + return null; + } + // find by position + for (int i = 0; i < changedScrapSize; i++) { + final ViewHolder holder = mChangedScrap.get(i); + if (!holder.wasReturnedFromScrap() && holder.getLayoutPosition() == position) { + holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP); + return holder; + } + } + // find by id + if (mAdapter.hasStableIds()) { + final int offsetPosition = mAdapterHelper.findPositionOffset(position); + if (offsetPosition > 0 && offsetPosition < mAdapter.getItemCount()) { + final long id = mAdapter.getItemId(offsetPosition); + for (int i = 0; i < changedScrapSize; i++) { + final ViewHolder holder = mChangedScrap.get(i); + if (!holder.wasReturnedFromScrap() && holder.getItemId() == id) { + holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP); + return holder; + } + } + } + } + return null; + } + + /** + * Returns a scrap view for the position. If type is not INVALID_TYPE, it also checks if + * ViewHolder's type matches the provided type. + * + * @param position Item position + * @param type View type + * @param dryRun Does a dry run, finds the ViewHolder but does not remove + * @return a ViewHolder that can be re-used for this position. + */ + ViewHolder getScrapViewForPosition(int position, int type, boolean dryRun) { + final int scrapCount = mAttachedScrap.size(); + + // Try first for an exact, non-invalid match from scrap. + for (int i = 0; i < scrapCount; i++) { + final ViewHolder holder = mAttachedScrap.get(i); + if (!holder.wasReturnedFromScrap() && holder.getLayoutPosition() == position + && !holder.isInvalid() && (mState.mInPreLayout || !holder.isRemoved())) { + if (type != INVALID_TYPE && holder.getItemViewType() != type) { + Log.e(TAG, "Scrap view for position " + position + " isn't dirty but has" + + " wrong view type! (found " + holder.getItemViewType() + + " but expected " + type + ")"); + break; + } + holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP); + return holder; + } + } + + if (!dryRun) { + View view = mChildHelper.findHiddenNonRemovedView(position, type); + if (view != null) { + // This View is good to be used. We just need to unhide, detach and move to the + // scrap list. + final ViewHolder vh = getChildViewHolderInt(view); + mChildHelper.unhide(view); + int layoutIndex = mChildHelper.indexOfChild(view); + if (layoutIndex == RecyclerView.NO_POSITION) { + throw new IllegalStateException("layout index should not be -1 after " + + "unhiding a view:" + vh); + } + mChildHelper.detachViewFromParent(layoutIndex); + scrapView(view); + vh.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP + | ViewHolder.FLAG_BOUNCED_FROM_HIDDEN_LIST); + return vh; + } + } + + // Search in our first-level recycled view cache. + final int cacheSize = mCachedViews.size(); + for (int i = 0; i < cacheSize; i++) { + final ViewHolder holder = mCachedViews.get(i); + // invalid view holders may be in cache if adapter has stable ids as they can be + // retrieved via getScrapViewForId + if (!holder.isInvalid() && holder.getLayoutPosition() == position) { + if (!dryRun) { + mCachedViews.remove(i); + } + if (DEBUG) { + Log.d(TAG, "getScrapViewForPosition(" + position + ", " + type + + ") found match in cache: " + holder); + } + return holder; + } + } + return null; + } + + ViewHolder getScrapViewForId(long id, int type, boolean dryRun) { + // Look in our attached views first + final int count = mAttachedScrap.size(); + for (int i = count - 1; i >= 0; i--) { + final ViewHolder holder = mAttachedScrap.get(i); + if (holder.getItemId() == id && !holder.wasReturnedFromScrap()) { + if (type == holder.getItemViewType()) { + holder.addFlags(ViewHolder.FLAG_RETURNED_FROM_SCRAP); + if (holder.isRemoved()) { + // this might be valid in two cases: + // > item is removed but we are in pre-layout pass + // >> do nothing. return as is. make sure we don't rebind + // > item is removed then added to another position and we are in + // post layout. + // >> remove removed and invalid flags, add update flag to rebind + // because item was invisible to us and we don't know what happened in + // between. + if (!mState.isPreLayout()) { + holder.setFlags(ViewHolder.FLAG_UPDATE, ViewHolder.FLAG_UPDATE | + ViewHolder.FLAG_INVALID | ViewHolder.FLAG_REMOVED); + } + } + return holder; + } else if (!dryRun) { + // if we are running animations, it is actually better to keep it in scrap + // but this would force layout manager to lay it out which would be bad. + // Recycle this scrap. Type mismatch. + mAttachedScrap.remove(i); + removeDetachedView(holder.itemView, false); + quickRecycleScrapView(holder.itemView); + } + } + } + + // Search the first-level cache + final int cacheSize = mCachedViews.size(); + for (int i = cacheSize - 1; i >= 0; i--) { + final ViewHolder holder = mCachedViews.get(i); + if (holder.getItemId() == id) { + if (type == holder.getItemViewType()) { + if (!dryRun) { + mCachedViews.remove(i); + } + return holder; + } else if (!dryRun) { + recycleCachedViewAt(i); + } + } + } + return null; + } + + void dispatchViewRecycled(ViewHolder holder) { + if (mRecyclerListener != null) { + mRecyclerListener.onViewRecycled(holder); + } + if (mAdapter != null) { + mAdapter.onViewRecycled(holder); + } + if (mState != null) { + mViewInfoStore.removeViewHolder(holder); + } + if (DEBUG) Log.d(TAG, "dispatchViewRecycled: " + holder); + } + + void onAdapterChanged(Adapter oldAdapter, Adapter newAdapter, + boolean compatibleWithPrevious) { + clear(); + getRecycledViewPool().onAdapterChanged(oldAdapter, newAdapter, compatibleWithPrevious); + } + + void offsetPositionRecordsForMove(int from, int to) { + final int start, end, inBetweenOffset; + if (from < to) { + start = from; + end = to; + inBetweenOffset = -1; + } else { + start = to; + end = from; + inBetweenOffset = 1; + } + final int cachedCount = mCachedViews.size(); + for (int i = 0; i < cachedCount; i++) { + final ViewHolder holder = mCachedViews.get(i); + if (holder == null || holder.mPosition < start || holder.mPosition > end) { + continue; + } + if (holder.mPosition == from) { + holder.offsetPosition(to - from, false); + } else { + holder.offsetPosition(inBetweenOffset, false); + } + if (DEBUG) { + Log.d(TAG, "offsetPositionRecordsForMove cached child " + i + " holder " + + holder); + } + } + } + + void offsetPositionRecordsForInsert(int insertedAt, int count) { + final int cachedCount = mCachedViews.size(); + for (int i = 0; i < cachedCount; i++) { + final ViewHolder holder = mCachedViews.get(i); + if (holder != null && holder.mPosition >= insertedAt) { + if (DEBUG) { + Log.d(TAG, "offsetPositionRecordsForInsert cached " + i + " holder " + + holder + " now at position " + (holder.mPosition + count)); + } + holder.offsetPosition(count, true); + } + } + } + + /** + * @param removedFrom Remove start index + * @param count Remove count + * @param applyToPreLayout If true, changes will affect ViewHolder's pre-layout position, if + * false, they'll be applied before the second layout pass + */ + void offsetPositionRecordsForRemove(int removedFrom, int count, boolean applyToPreLayout) { + final int removedEnd = removedFrom + count; + final int cachedCount = mCachedViews.size(); + for (int i = cachedCount - 1; i >= 0; i--) { + final ViewHolder holder = mCachedViews.get(i); + if (holder != null) { + if (holder.mPosition >= removedEnd) { + if (DEBUG) { + Log.d(TAG, "offsetPositionRecordsForRemove cached " + i + + " holder " + holder + " now at position " + + (holder.mPosition - count)); + } + holder.offsetPosition(-count, applyToPreLayout); + } else if (holder.mPosition >= removedFrom) { + // Item for this view was removed. Dump it from the cache. + holder.addFlags(ViewHolder.FLAG_REMOVED); + recycleCachedViewAt(i); + } + } + } + } + + void setViewCacheExtension(ViewCacheExtension extension) { + mViewCacheExtension = extension; + } + + void setRecycledViewPool(RecycledViewPool pool) { + if (mRecyclerPool != null) { + mRecyclerPool.detach(); + } + mRecyclerPool = pool; + if (pool != null) { + mRecyclerPool.attach(getAdapter()); + } + } + + RecycledViewPool getRecycledViewPool() { + if (mRecyclerPool == null) { + mRecyclerPool = new RecycledViewPool(); + } + return mRecyclerPool; + } + + void viewRangeUpdate(int positionStart, int itemCount) { + final int positionEnd = positionStart + itemCount; + final int cachedCount = mCachedViews.size(); + for (int i = cachedCount - 1; i >= 0; i--) { + final ViewHolder holder = mCachedViews.get(i); + if (holder == null) { + continue; + } + + final int pos = holder.getLayoutPosition(); + if (pos >= positionStart && pos < positionEnd) { + holder.addFlags(ViewHolder.FLAG_UPDATE); + recycleCachedViewAt(i); + // cached views should not be flagged as changed because this will cause them + // to animate when they are returned from cache. + } + } + } + + void setAdapterPositionsAsUnknown() { + final int cachedCount = mCachedViews.size(); + for (int i = 0; i < cachedCount; i++) { + final ViewHolder holder = mCachedViews.get(i); + if (holder != null) { + holder.addFlags(ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN); + } + } + } + + void markKnownViewsInvalid() { + if (mAdapter != null && mAdapter.hasStableIds()) { + final int cachedCount = mCachedViews.size(); + for (int i = 0; i < cachedCount; i++) { + final ViewHolder holder = mCachedViews.get(i); + if (holder != null) { + holder.addFlags(ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID); + holder.addChangePayload(null); + } + } + } else { + // we cannot re-use cached views in this case. Recycle them all + recycleAndClearCachedViews(); + } + } + + void clearOldPositions() { + final int cachedCount = mCachedViews.size(); + for (int i = 0; i < cachedCount; i++) { + final ViewHolder holder = mCachedViews.get(i); + holder.clearOldPosition(); + } + final int scrapCount = mAttachedScrap.size(); + for (int i = 0; i < scrapCount; i++) { + mAttachedScrap.get(i).clearOldPosition(); + } + if (mChangedScrap != null) { + final int changedScrapCount = mChangedScrap.size(); + for (int i = 0; i < changedScrapCount; i++) { + mChangedScrap.get(i).clearOldPosition(); + } + } + } + + void markItemDecorInsetsDirty() { + final int cachedCount = mCachedViews.size(); + for (int i = 0; i < cachedCount; i++) { + final ViewHolder holder = mCachedViews.get(i); + LayoutParams layoutParams = (LayoutParams) holder.itemView.getLayoutParams(); + if (layoutParams != null) { + layoutParams.mInsetsDirty = true; + } + } + } + } + + /** + * ViewCacheExtension is a helper class to provide an additional layer of view caching that can + * ben controlled by the developer. + *

+ * When {@link Recycler#getViewForPosition(int)} is called, Recycler checks attached scrap and + * first level cache to find a matching View. If it cannot find a suitable View, Recycler will + * call the {@link #getViewForPositionAndType(Recycler, int, int)} before checking + * {@link RecycledViewPool}. + *

+ * Note that, Recycler never sends Views to this method to be cached. It is developers + * responsibility to decide whether they want to keep their Views in this custom cache or let + * the default recycling policy handle it. + */ + public abstract static class ViewCacheExtension { + + /** + * Returns a View that can be binded to the given Adapter position. + *

+ * This method should not create a new View. Instead, it is expected to return + * an already created View that can be re-used for the given type and position. + * If the View is marked as ignored, it should first call + * {@link LayoutManager#stopIgnoringView(View)} before returning the View. + *

+ * RecyclerView will re-bind the returned View to the position if necessary. + * + * @param recycler The Recycler that can be used to bind the View + * @param position The adapter position + * @param type The type of the View, defined by adapter + * @return A View that is bound to the given position or NULL if there is no View to re-use + * @see LayoutManager#ignoreView(View) + */ + abstract public View getViewForPositionAndType(Recycler recycler, int position, int type); + } + + /** + * Base class for an Adapter + * + *

Adapters provide a binding from an app-specific data set to views that are displayed + * within a {@link RecyclerView}.

+ */ + public static abstract class Adapter { + private final AdapterDataObservable mObservable = new AdapterDataObservable(); + private boolean mHasStableIds = false; + + /** + * Called when RecyclerView needs a new {@link ViewHolder} of the given type to represent + * an item. + *

+ * This new ViewHolder should be constructed with a new View that can represent the items + * of the given type. You can either create a new View manually or inflate it from an XML + * layout file. + *

+ * The new ViewHolder will be used to display items of the adapter using + * {@link #onBindViewHolder(ViewHolder, int, List)}. Since it will be re-used to display + * different items in the data set, it is a good idea to cache references to sub views of + * the View to avoid unnecessary {@link View#findViewById(int)} calls. + * + * @param parent The ViewGroup into which the new View will be added after it is bound to + * an adapter position. + * @param viewType The view type of the new View. + * + * @return A new ViewHolder that holds a View of the given view type. + * @see #getItemViewType(int) + * @see #onBindViewHolder(ViewHolder, int) + */ + public abstract VH onCreateViewHolder(ViewGroup parent, int viewType); + + /** + * Called by RecyclerView to display the data at the specified position. This method should + * update the contents of the {@link ViewHolder#itemView} to reflect the item at the given + * position. + *

+ * Note that unlike {@link android.widget.ListView}, RecyclerView will not call this method + * again if the position of the item changes in the data set unless the item itself is + * invalidated or the new position cannot be determined. For this reason, you should only + * use the position parameter while acquiring the related data item inside + * this method and should not keep a copy of it. If you need the position of an item later + * on (e.g. in a click listener), use {@link ViewHolder#getAdapterPosition()} which will + * have the updated adapter position. + * + * Override {@link #onBindViewHolder(ViewHolder, int, List)} instead if Adapter can + * handle effcient partial bind. + * + * @param holder The ViewHolder which should be updated to represent the contents of the + * item at the given position in the data set. + * @param position The position of the item within the adapter's data set. + */ + public abstract void onBindViewHolder(VH holder, int position); + + /** + * Called by RecyclerView to display the data at the specified position. This method + * should update the contents of the {@link ViewHolder#itemView} to reflect the item at + * the given position. + *

+ * Note that unlike {@link android.widget.ListView}, RecyclerView will not call this method + * again if the position of the item changes in the data set unless the item itself is + * invalidated or the new position cannot be determined. For this reason, you should only + * use the position parameter while acquiring the related data item inside + * this method and should not keep a copy of it. If you need the position of an item later + * on (e.g. in a click listener), use {@link ViewHolder#getAdapterPosition()} which will + * have the updated adapter position. + *

+ * Partial bind vs full bind: + *

+ * The payloads parameter is a merge list from {@link #notifyItemChanged(int, Object)} or + * {@link #notifyItemRangeChanged(int, int, Object)}. If the payloads list is not empty, + * the ViewHolder is currently bound to old data and Adapter may run an efficient partial + * update using the payload info. If the payload is empty, Adapter must run a full bind. + * Adapter should not assume that the payload passed in notify methods will be received by + * onBindViewHolder(). For example when the view is not attached to the screen, the + * payload in notifyItemChange() will be simply dropped. + * + * @param holder The ViewHolder which should be updated to represent the contents of the + * item at the given position in the data set. + * @param position The position of the item within the adapter's data set. + * @param payloads A non-null list of merged payloads. Can be empty list if requires full + * update. + */ + public void onBindViewHolder(VH holder, int position, List payloads) { + onBindViewHolder(holder, position); + } + + /** + * This method calls {@link #onCreateViewHolder(ViewGroup, int)} to create a new + * {@link ViewHolder} and initializes some private fields to be used by RecyclerView. + * + * @see #onCreateViewHolder(ViewGroup, int) + */ + public final VH createViewHolder(ViewGroup parent, int viewType) { + TraceCompat.beginSection(TRACE_CREATE_VIEW_TAG); + final VH holder = onCreateViewHolder(parent, viewType); + holder.mItemViewType = viewType; + TraceCompat.endSection(); + return holder; + } + + /** + * This method internally calls {@link #onBindViewHolder(ViewHolder, int)} to update the + * {@link ViewHolder} contents with the item at the given position and also sets up some + * private fields to be used by RecyclerView. + * + * @see #onBindViewHolder(ViewHolder, int) + */ + public final void bindViewHolder(VH holder, int position) { + holder.mPosition = position; + if (hasStableIds()) { + holder.mItemId = getItemId(position); + } + holder.setFlags(ViewHolder.FLAG_BOUND, + ViewHolder.FLAG_BOUND | ViewHolder.FLAG_UPDATE | ViewHolder.FLAG_INVALID + | ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN); + TraceCompat.beginSection(TRACE_BIND_VIEW_TAG); + onBindViewHolder(holder, position, holder.getUnmodifiedPayloads()); + holder.clearPayload(); + TraceCompat.endSection(); + } + + /** + * Return the view type of the item at position for the purposes + * of view recycling. + * + *

The default implementation of this method returns 0, making the assumption of + * a single view type for the adapter. Unlike ListView adapters, types need not + * be contiguous. Consider using id resources to uniquely identify item view types. + * + * @param position position to query + * @return integer value identifying the type of the view needed to represent the item at + * position. Type codes need not be contiguous. + */ + public int getItemViewType(int position) { + return 0; + } + + /** + * Indicates whether each item in the data set can be represented with a unique identifier + * of type {@link java.lang.Long}. + * + * @param hasStableIds Whether items in data set have unique identifiers or not. + * @see #hasStableIds() + * @see #getItemId(int) + */ + public void setHasStableIds(boolean hasStableIds) { + if (hasObservers()) { + throw new IllegalStateException("Cannot change whether this adapter has " + + "stable IDs while the adapter has registered observers."); + } + mHasStableIds = hasStableIds; + } + + /** + * Return the stable ID for the item at position. If {@link #hasStableIds()} + * would return false this method should return {@link #NO_ID}. The default implementation + * of this method returns {@link #NO_ID}. + * + * @param position Adapter position to query + * @return the stable ID of the item at position + */ + public long getItemId(int position) { + return NO_ID; + } + + /** + * Returns the total number of items in the data set hold by the adapter. + * + * @return The total number of items in this adapter. + */ + public abstract int getItemCount(); + + /** + * Returns true if this adapter publishes a unique long value that can + * act as a key for the item at a given position in the data set. If that item is relocated + * in the data set, the ID returned for that item should be the same. + * + * @return true if this adapter's items have stable IDs + */ + public final boolean hasStableIds() { + return mHasStableIds; + } + + /** + * Called when a view created by this adapter has been recycled. + * + *

A view is recycled when a {@link LayoutManager} decides that it no longer + * needs to be attached to its parent {@link RecyclerView}. This can be because it has + * fallen out of visibility or a set of cached views represented by views still + * attached to the parent RecyclerView. If an item view has large or expensive data + * bound to it such as large bitmaps, this may be a good place to release those + * resources.

+ *

+ * RecyclerView calls this method right before clearing ViewHolder's internal data and + * sending it to RecycledViewPool. This way, if ViewHolder was holding valid information + * before being recycled, you can call {@link ViewHolder#getAdapterPosition()} to get + * its adapter position. + * + * @param holder The ViewHolder for the view being recycled + */ + public void onViewRecycled(VH holder) { + } + + /** + * Called by the RecyclerView if a ViewHolder created by this Adapter cannot be recycled + * due to its transient state. Upon receiving this callback, Adapter can clear the + * animation(s) that effect the View's transient state and return true so that + * the View can be recycled. Keep in mind that the View in question is already removed from + * the RecyclerView. + *

+ * In some cases, it is acceptable to recycle a View although it has transient state. Most + * of the time, this is a case where the transient state will be cleared in + * {@link #onBindViewHolder(ViewHolder, int)} call when View is rebound to a new position. + * For this reason, RecyclerView leaves the decision to the Adapter and uses the return + * value of this method to decide whether the View should be recycled or not. + *

+ * Note that when all animations are created by {@link RecyclerView.ItemAnimator}, you + * should never receive this callback because RecyclerView keeps those Views as children + * until their animations are complete. This callback is useful when children of the item + * views create animations which may not be easy to implement using an {@link ItemAnimator}. + *

+ * You should never fix this issue by calling + * holder.itemView.setHasTransientState(false); unless you've previously called + * holder.itemView.setHasTransientState(true);. Each + * View.setHasTransientState(true) call must be matched by a + * View.setHasTransientState(false) call, otherwise, the state of the View + * may become inconsistent. You should always prefer to end or cancel animations that are + * triggering the transient state instead of handling it manually. + * + * @param holder The ViewHolder containing the View that could not be recycled due to its + * transient state. + * @return True if the View should be recycled, false otherwise. Note that if this method + * returns true, RecyclerView will ignore the transient state of + * the View and recycle it regardless. If this method returns false, + * RecyclerView will check the View's transient state again before giving a final decision. + * Default implementation returns false. + */ + public boolean onFailedToRecycleView(VH holder) { + return false; + } + + /** + * Called when a view created by this adapter has been attached to a window. + * + *

This can be used as a reasonable signal that the view is about to be seen + * by the user. If the adapter previously freed any resources in + * {@link #onViewDetachedFromWindow(RecyclerView.ViewHolder) onViewDetachedFromWindow} + * those resources should be restored here.

+ * + * @param holder Holder of the view being attached + */ + public void onViewAttachedToWindow(VH holder) { + } + + /** + * Called when a view created by this adapter has been detached from its window. + * + *

Becoming detached from the window is not necessarily a permanent condition; + * the consumer of an Adapter's views may choose to cache views offscreen while they + * are not visible, attaching an detaching them as appropriate.

+ * + * @param holder Holder of the view being detached + */ + public void onViewDetachedFromWindow(VH holder) { + } + + /** + * Returns true if one or more observers are attached to this adapter. + * + * @return true if this adapter has observers + */ + public final boolean hasObservers() { + return mObservable.hasObservers(); + } + + /** + * Register a new observer to listen for data changes. + * + *

The adapter may publish a variety of events describing specific changes. + * Not all adapters may support all change types and some may fall back to a generic + * {@link android.support.v7.widget.RecyclerView.AdapterDataObserver#onChanged() + * "something changed"} event if more specific data is not available.

+ * + *

Components registering observers with an adapter are responsible for + * {@link #unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver) + * unregistering} those observers when finished.

+ * + * @param observer Observer to register + * + * @see #unregisterAdapterDataObserver(RecyclerView.AdapterDataObserver) + */ + public void registerAdapterDataObserver(AdapterDataObserver observer) { + mObservable.registerObserver(observer); + } + + /** + * Unregister an observer currently listening for data changes. + * + *

The unregistered observer will no longer receive events about changes + * to the adapter.

+ * + * @param observer Observer to unregister + * + * @see #registerAdapterDataObserver(RecyclerView.AdapterDataObserver) + */ + public void unregisterAdapterDataObserver(AdapterDataObserver observer) { + mObservable.unregisterObserver(observer); + } + + /** + * Called by RecyclerView when it starts observing this Adapter. + *

+ * Keep in mind that same adapter may be observed by multiple RecyclerViews. + * + * @param recyclerView The RecyclerView instance which started observing this adapter. + * @see #onDetachedFromRecyclerView(RecyclerView) + */ + public void onAttachedToRecyclerView(RecyclerView recyclerView) { + } + + /** + * Called by RecyclerView when it stops observing this Adapter. + * + * @param recyclerView The RecyclerView instance which stopped observing this adapter. + * @see #onAttachedToRecyclerView(RecyclerView) + */ + public void onDetachedFromRecyclerView(RecyclerView recyclerView) { + } + + /** + * Notify any registered observers that the data set has changed. + * + *

There are two different classes of data change events, item changes and structural + * changes. Item changes are when a single item has its data updated but no positional + * changes have occurred. Structural changes are when items are inserted, removed or moved + * within the data set.

+ * + *

This event does not specify what about the data set has changed, forcing + * any observers to assume that all existing items and structure may no longer be valid. + * LayoutManagers will be forced to fully rebind and relayout all visible views.

+ * + *

RecyclerView will attempt to synthesize visible structural change events + * for adapters that report that they have {@link #hasStableIds() stable IDs} when + * this method is used. This can help for the purposes of animation and visual + * object persistence but individual item views will still need to be rebound + * and relaid out.

+ * + *

If you are writing an adapter it will always be more efficient to use the more + * specific change events if you can. Rely on notifyDataSetChanged() + * as a last resort.

+ * + * @see #notifyItemChanged(int) + * @see #notifyItemInserted(int) + * @see #notifyItemRemoved(int) + * @see #notifyItemRangeChanged(int, int) + * @see #notifyItemRangeInserted(int, int) + * @see #notifyItemRangeRemoved(int, int) + */ + public void notifyDataSetChanged() { + mObservable.notifyChanged(); + } + + /** + * Notify any registered observers that the item at position has changed. + * Equivalent to calling notifyItemChanged(position, null);. + * + *

This is an item change event, not a structural change event. It indicates that any + * reflection of the data at position is out of date and should be updated. + * The item at position retains the same identity.

+ * + * @param position Position of the item that has changed + * + * @see #notifyItemRangeChanged(int, int) + */ + public void notifyItemChanged(int position) { + mObservable.notifyItemRangeChanged(position, 1); + } + + /** + * Notify any registered observers that the item at position has changed with an + * optional payload object. + * + *

This is an item change event, not a structural change event. It indicates that any + * reflection of the data at position is out of date and should be updated. + * The item at position retains the same identity. + *

+ * + *

+ * Client can optionally pass a payload for partial change. These payloads will be merged + * and may be passed to adapter's {@link #onBindViewHolder(ViewHolder, int, List)} if the + * item is already represented by a ViewHolder and it will be rebound to the same + * ViewHolder. A notifyItemRangeChanged() with null payload will clear all existing + * payloads on that item and prevent future payload until + * {@link #onBindViewHolder(ViewHolder, int, List)} is called. Adapter should not assume + * that the payload will always be passed to onBindViewHolder(), e.g. when the view is not + * attached, the payload will be simply dropped. + * + * @param position Position of the item that has changed + * @param payload Optional parameter, use null to identify a "full" update + * + * @see #notifyItemRangeChanged(int, int) + */ + public void notifyItemChanged(int position, Object payload) { + mObservable.notifyItemRangeChanged(position, 1, payload); + } + + /** + * Notify any registered observers that the itemCount items starting at + * position positionStart have changed. + * Equivalent to calling notifyItemRangeChanged(position, itemCount, null);. + * + *

This is an item change event, not a structural change event. It indicates that + * any reflection of the data in the given position range is out of date and should + * be updated. The items in the given range retain the same identity.

+ * + * @param positionStart Position of the first item that has changed + * @param itemCount Number of items that have changed + * + * @see #notifyItemChanged(int) + */ + public void notifyItemRangeChanged(int positionStart, int itemCount) { + mObservable.notifyItemRangeChanged(positionStart, itemCount); + } + + /** + * Notify any registered observers that the itemCount items starting at + * positionpositionStart have changed. An optional payload can be + * passed to each changed item. + * + *

This is an item change event, not a structural change event. It indicates that any + * reflection of the data in the given position range is out of date and should be updated. + * The items in the given range retain the same identity. + *

+ * + *

+ * Client can optionally pass a payload for partial change. These payloads will be merged + * and may be passed to adapter's {@link #onBindViewHolder(ViewHolder, int, List)} if the + * item is already represented by a ViewHolder and it will be rebound to the same + * ViewHolder. A notifyItemRangeChanged() with null payload will clear all existing + * payloads on that item and prevent future payload until + * {@link #onBindViewHolder(ViewHolder, int, List)} is called. Adapter should not assume + * that the payload will always be passed to onBindViewHolder(), e.g. when the view is not + * attached, the payload will be simply dropped. + * + * @param positionStart Position of the first item that has changed + * @param itemCount Number of items that have changed + * @param payload Optional parameter, use null to identify a "full" update + * + * @see #notifyItemChanged(int) + */ + public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) { + mObservable.notifyItemRangeChanged(positionStart, itemCount, payload); + } + + /** + * Notify any registered observers that the item reflected at position + * has been newly inserted. The item previously at position is now at + * position position + 1. + * + *

This is a structural change event. Representations of other existing items in the + * data set are still considered up to date and will not be rebound, though their + * positions may be altered.

+ * + * @param position Position of the newly inserted item in the data set + * + * @see #notifyItemRangeInserted(int, int) + */ + public void notifyItemInserted(int position) { + mObservable.notifyItemRangeInserted(position, 1); + } + + /** + * Notify any registered observers that the item reflected at fromPosition + * has been moved to toPosition. + * + *

This is a structural change event. Representations of other existing items in the + * data set are still considered up to date and will not be rebound, though their + * positions may be altered.

+ * + * @param fromPosition Previous position of the item. + * @param toPosition New position of the item. + */ + public void notifyItemMoved(int fromPosition, int toPosition) { + mObservable.notifyItemMoved(fromPosition, toPosition); + } + + /** + * Notify any registered observers that the currently reflected itemCount + * items starting at positionStart have been newly inserted. The items + * previously located at positionStart and beyond can now be found starting + * at position positionStart + itemCount. + * + *

This is a structural change event. Representations of other existing items in the + * data set are still considered up to date and will not be rebound, though their positions + * may be altered.

+ * + * @param positionStart Position of the first item that was inserted + * @param itemCount Number of items inserted + * + * @see #notifyItemInserted(int) + */ + public void notifyItemRangeInserted(int positionStart, int itemCount) { + mObservable.notifyItemRangeInserted(positionStart, itemCount); + } + + /** + * Notify any registered observers that the item previously located at position + * has been removed from the data set. The items previously located at and after + * position may now be found at oldPosition - 1. + * + *

This is a structural change event. Representations of other existing items in the + * data set are still considered up to date and will not be rebound, though their positions + * may be altered.

+ * + * @param position Position of the item that has now been removed + * + * @see #notifyItemRangeRemoved(int, int) + */ + public void notifyItemRemoved(int position) { + mObservable.notifyItemRangeRemoved(position, 1); + } + + /** + * Notify any registered observers that the itemCount items previously + * located at positionStart have been removed from the data set. The items + * previously located at and after positionStart + itemCount may now be found + * at oldPosition - itemCount. + * + *

This is a structural change event. Representations of other existing items in the data + * set are still considered up to date and will not be rebound, though their positions + * may be altered.

+ * + * @param positionStart Previous position of the first item that was removed + * @param itemCount Number of items removed from the data set + */ + public void notifyItemRangeRemoved(int positionStart, int itemCount) { + mObservable.notifyItemRangeRemoved(positionStart, itemCount); + } + } + + private void dispatchChildDetached(View child) { + final ViewHolder viewHolder = getChildViewHolderInt(child); + onChildDetachedFromWindow(child); + if (mAdapter != null && viewHolder != null) { + mAdapter.onViewDetachedFromWindow(viewHolder); + } + if (mOnChildAttachStateListeners != null) { + final int cnt = mOnChildAttachStateListeners.size(); + for (int i = cnt - 1; i >= 0; i--) { + mOnChildAttachStateListeners.get(i).onChildViewDetachedFromWindow(child); + } + } + } + + private void dispatchChildAttached(View child) { + final ViewHolder viewHolder = getChildViewHolderInt(child); + onChildAttachedToWindow(child); + if (mAdapter != null && viewHolder != null) { + mAdapter.onViewAttachedToWindow(viewHolder); + } + if (mOnChildAttachStateListeners != null) { + final int cnt = mOnChildAttachStateListeners.size(); + for (int i = cnt - 1; i >= 0; i--) { + mOnChildAttachStateListeners.get(i).onChildViewAttachedToWindow(child); + } + } + } + + /** + * A LayoutManager is responsible for measuring and positioning item views + * within a RecyclerView as well as determining the policy for when to recycle + * item views that are no longer visible to the user. By changing the LayoutManager + * a RecyclerView can be used to implement a standard vertically scrolling list, + * a uniform grid, staggered grids, horizontally scrolling collections and more. Several stock + * layout managers are provided for general use. + *

+ * If the LayoutManager specifies a default constructor or one with the signature + * ({@link Context}, {@link AttributeSet}, {@code int}, {@code int}), RecyclerView will + * instantiate and set the LayoutManager when being inflated. Most used properties can + * be then obtained from {@link #getProperties(Context, AttributeSet, int, int)}. In case + * a LayoutManager specifies both constructors, the non-default constructor will take + * precedence. + * + */ + public static abstract class LayoutManager { + ChildHelper mChildHelper; + RecyclerView mRecyclerView; + + @Nullable + SmoothScroller mSmoothScroller; + + private boolean mRequestedSimpleAnimations = false; + + boolean mIsAttachedToWindow = false; + + private boolean mAutoMeasure = false; + + /** + * LayoutManager has its own more strict measurement cache to avoid re-measuring a child + * if the space that will be given to it is already larger than what it has measured before. + */ + private boolean mMeasurementCacheEnabled = true; + + + /** + * These measure specs might be the measure specs that were passed into RecyclerView's + * onMeasure method OR fake measure specs created by the RecyclerView. + * For example, when a layout is run, RecyclerView always sets these specs to be + * EXACTLY because a LayoutManager cannot resize RecyclerView during a layout pass. + *

+ * Also, to be able to use the hint in unspecified measure specs, RecyclerView checks the + * API level and sets the size to 0 pre-M to avoid any issue that might be caused by + * corrupt values. Older platforms have no responsibility to provide a size if they set + * mode to unspecified. + */ + private int mWidthMode, mHeightMode; + private int mWidth, mHeight; + + void setRecyclerView(RecyclerView recyclerView) { + if (recyclerView == null) { + mRecyclerView = null; + mChildHelper = null; + mWidth = 0; + mHeight = 0; + } else { + mRecyclerView = recyclerView; + mChildHelper = recyclerView.mChildHelper; + mWidth = recyclerView.getWidth(); + mHeight = recyclerView.getHeight(); + } + mWidthMode = MeasureSpec.EXACTLY; + mHeightMode = MeasureSpec.EXACTLY; + } + + void setMeasureSpecs(int wSpec, int hSpec) { + mWidth = MeasureSpec.getSize(wSpec); + mWidthMode = MeasureSpec.getMode(wSpec); + if (mWidthMode == MeasureSpec.UNSPECIFIED && !ALLOW_SIZE_IN_UNSPECIFIED_SPEC) { + mWidth = 0; + } + + mHeight = MeasureSpec.getSize(hSpec); + mHeightMode = MeasureSpec.getMode(hSpec); + if (mHeightMode == MeasureSpec.UNSPECIFIED && !ALLOW_SIZE_IN_UNSPECIFIED_SPEC) { + mHeight = 0; + } + } + + /** + * Called after a layout is calculated during a measure pass when using auto-measure. + *

+ * It simply traverses all children to calculate a bounding box then calls + * {@link #setMeasuredDimension(Rect, int, int)}. LayoutManagers can override that method + * if they need to handle the bounding box differently. + *

+ * For example, GridLayoutManager override that method to ensure that even if a column is + * empty, the GridLayoutManager still measures wide enough to include it. + * + * @param widthSpec The widthSpec that was passing into RecyclerView's onMeasure + * @param heightSpec The heightSpec that was passing into RecyclerView's onMeasure + */ + void setMeasuredDimensionFromChildren(int widthSpec, int heightSpec) { + final int count = getChildCount(); + if (count == 0) { + mRecyclerView.defaultOnMeasure(widthSpec, heightSpec); + return; + } + int minX = Integer.MAX_VALUE; + int minY = Integer.MAX_VALUE; + int maxX = Integer.MIN_VALUE; + int maxY = Integer.MIN_VALUE; + + for (int i = 0; i < count; i++) { + View child = getChildAt(i); + LayoutParams lp = (LayoutParams) child.getLayoutParams(); + int left = getDecoratedLeft(child) - lp.leftMargin; + int right = getDecoratedRight(child) + lp.rightMargin; + int top = getDecoratedTop(child) - lp.topMargin; + int bottom = getDecoratedBottom(child) + lp.bottomMargin; + if (left < minX) { + minX = left; + } + if (right > maxX) { + maxX = right; + } + if (top < minY) { + minY = top; + } + if (bottom > maxY) { + maxY = bottom; + } + } + mRecyclerView.mTempRect.set(minX, minY, maxX, maxY); + setMeasuredDimension(mRecyclerView.mTempRect, widthSpec, heightSpec); + } + + /** + * Sets the measured dimensions from the given bounding box of the children and the + * measurement specs that were passed into {@link RecyclerView#onMeasure(int, int)}. It is + * called after the RecyclerView calls + * {@link LayoutManager#onLayoutChildren(Recycler, State)} during a measurement pass. + *

+ * This method should call {@link #setMeasuredDimension(int, int)}. + *

+ * The default implementation adds the RecyclerView's padding to the given bounding box + * then caps the value to be within the given measurement specs. + *

+ * This method is only called if the LayoutManager opted into the auto measurement API. + * + * @param childrenBounds The bounding box of all children + * @param wSpec The widthMeasureSpec that was passed into the RecyclerView. + * @param hSpec The heightMeasureSpec that was passed into the RecyclerView. + * + * @see #setAutoMeasureEnabled(boolean) + */ + public void setMeasuredDimension(Rect childrenBounds, int wSpec, int hSpec) { + int usedWidth = childrenBounds.width() + getPaddingLeft() + getPaddingRight(); + int usedHeight = childrenBounds.height() + getPaddingTop() + getPaddingBottom(); + int width = chooseSize(wSpec, usedWidth, getMinimumWidth()); + int height = chooseSize(hSpec, usedHeight, getMinimumHeight()); + setMeasuredDimension(width, height); + } + + /** + * Calls {@code RecyclerView#requestLayout} on the underlying RecyclerView + */ + public void requestLayout() { + if(mRecyclerView != null) { + mRecyclerView.requestLayout(); + } + } + + /** + * Checks if RecyclerView is in the middle of a layout or scroll and throws an + * {@link IllegalStateException} if it is not. + * + * @param message The message for the exception. Can be null. + * @see #assertNotInLayoutOrScroll(String) + */ + public void assertInLayoutOrScroll(String message) { + if (mRecyclerView != null) { + mRecyclerView.assertInLayoutOrScroll(message); + } + } + + /** + * Chooses a size from the given specs and parameters that is closest to the desired size + * and also complies with the spec. + * + * @param spec The measureSpec + * @param desired The preferred measurement + * @param min The minimum value + * + * @return A size that fits to the given specs + */ + public static int chooseSize(int spec, int desired, int min) { + final int mode = View.MeasureSpec.getMode(spec); + final int size = View.MeasureSpec.getSize(spec); + switch (mode) { + case View.MeasureSpec.EXACTLY: + return size; + case View.MeasureSpec.AT_MOST: + return Math.min(size, Math.max(desired, min)); + case View.MeasureSpec.UNSPECIFIED: + default: + return Math.max(desired, min); + } + } + + /** + * Checks if RecyclerView is in the middle of a layout or scroll and throws an + * {@link IllegalStateException} if it is. + * + * @param message The message for the exception. Can be null. + * @see #assertInLayoutOrScroll(String) + */ + public void assertNotInLayoutOrScroll(String message) { + if (mRecyclerView != null) { + mRecyclerView.assertNotInLayoutOrScroll(message); + } + } + + /** + * Defines whether the layout should be measured by the RecyclerView or the LayoutManager + * wants to handle the layout measurements itself. + *

+ * This method is usually called by the LayoutManager with value {@code true} if it wants + * to support WRAP_CONTENT. If you are using a public LayoutManager but want to customize + * the measurement logic, you can call this method with {@code false} and override + * {@link LayoutManager#onMeasure(int, int)} to implement your custom measurement logic. + *

+ * AutoMeasure is a convenience mechanism for LayoutManagers to easily wrap their content or + * handle various specs provided by the RecyclerView's parent. + * It works by calling {@link LayoutManager#onLayoutChildren(Recycler, State)} during an + * {@link RecyclerView#onMeasure(int, int)} call, then calculating desired dimensions based + * on children's positions. It does this while supporting all existing animation + * capabilities of the RecyclerView. + *

+ * AutoMeasure works as follows: + *

    + *
  1. LayoutManager should call {@code setAutoMeasureEnabled(true)} to enable it. All of + * the framework LayoutManagers use {@code auto-measure}.
  2. + *
  3. When {@link RecyclerView#onMeasure(int, int)} is called, if the provided specs are + * exact, RecyclerView will only call LayoutManager's {@code onMeasure} and return without + * doing any layout calculation.
  4. + *
  5. If one of the layout specs is not {@code EXACT}, the RecyclerView will start the + * layout process in {@code onMeasure} call. It will process all pending Adapter updates and + * decide whether to run a predictive layout or not. If it decides to do so, it will first + * call {@link #onLayoutChildren(Recycler, State)} with {@link State#isPreLayout()} set to + * {@code true}. At this stage, {@link #getWidth()} and {@link #getHeight()} will still + * return the width and height of the RecyclerView as of the last layout calculation. + *

    + * After handling the predictive case, RecyclerView will call + * {@link #onLayoutChildren(Recycler, State)} with {@link State#isMeasuring()} set to + * {@code true} and {@link State#isPreLayout()} set to {@code false}. The LayoutManager can + * access the measurement specs via {@link #getHeight()}, {@link #getHeightMode()}, + * {@link #getWidth()} and {@link #getWidthMode()}.

  6. + *
  7. After the layout calculation, RecyclerView sets the measured width & height by + * calculating the bounding box for the children (+ RecyclerView's padding). The + * LayoutManagers can override {@link #setMeasuredDimension(Rect, int, int)} to choose + * different values. For instance, GridLayoutManager overrides this value to handle the case + * where if it is vertical and has 3 columns but only 2 items, it should still measure its + * width to fit 3 items, not 2.
  8. + *
  9. Any following on measure call to the RecyclerView will run + * {@link #onLayoutChildren(Recycler, State)} with {@link State#isMeasuring()} set to + * {@code true} and {@link State#isPreLayout()} set to {@code false}. RecyclerView will + * take care of which views are actually added / removed / moved / changed for animations so + * that the LayoutManager should not worry about them and handle each + * {@link #onLayoutChildren(Recycler, State)} call as if it is the last one. + *
  10. + *
  11. When measure is complete and RecyclerView's + * {@link #onLayout(boolean, int, int, int, int)} method is called, RecyclerView checks + * whether it already did layout calculations during the measure pass and if so, it re-uses + * that information. It may still decide to call {@link #onLayoutChildren(Recycler, State)} + * if the last measure spec was different from the final dimensions or adapter contents + * have changed between the measure call and the layout call.
  12. + *
  13. Finally, animations are calculated and run as usual.
  14. + *
+ * + * @param enabled True if the Layout should be measured by the + * RecyclerView, false if the LayoutManager wants + * to measure itself. + * + * @see #setMeasuredDimension(Rect, int, int) + * @see #isAutoMeasureEnabled() + */ + public void setAutoMeasureEnabled(boolean enabled) { + mAutoMeasure = enabled; + } + + /** + * Returns whether the LayoutManager uses the automatic measurement API or not. + * + * @return True if the LayoutManager is measured by the RecyclerView or + * false if it measures itself. + * + * @see #setAutoMeasureEnabled(boolean) + */ + public boolean isAutoMeasureEnabled() { + return mAutoMeasure; + } + + /** + * Returns whether this LayoutManager supports automatic item animations. + * A LayoutManager wishing to support item animations should obey certain + * rules as outlined in {@link #onLayoutChildren(Recycler, State)}. + * The default return value is false, so subclasses of LayoutManager + * will not get predictive item animations by default. + * + *

Whether item animations are enabled in a RecyclerView is determined both + * by the return value from this method and the + * {@link RecyclerView#setItemAnimator(ItemAnimator) ItemAnimator} set on the + * RecyclerView itself. If the RecyclerView has a non-null ItemAnimator but this + * method returns false, then simple item animations will be enabled, in which + * views that are moving onto or off of the screen are simply faded in/out. If + * the RecyclerView has a non-null ItemAnimator and this method returns true, + * then there will be two calls to {@link #onLayoutChildren(Recycler, State)} to + * setup up the information needed to more intelligently predict where appearing + * and disappearing views should be animated from/to.

+ * + * @return true if predictive item animations should be enabled, false otherwise + */ + public boolean supportsPredictiveItemAnimations() { + return false; + } + + void dispatchAttachedToWindow(RecyclerView view) { + mIsAttachedToWindow = true; + onAttachedToWindow(view); + } + + void dispatchDetachedFromWindow(RecyclerView view, Recycler recycler) { + mIsAttachedToWindow = false; + onDetachedFromWindow(view, recycler); + } + + /** + * Returns whether LayoutManager is currently attached to a RecyclerView which is attached + * to a window. + * + * @return True if this LayoutManager is controlling a RecyclerView and the RecyclerView + * is attached to window. + */ + public boolean isAttachedToWindow() { + return mIsAttachedToWindow; + } + + /** + * Causes the Runnable to execute on the next animation time step. + * The runnable will be run on the user interface thread. + *

+ * Calling this method when LayoutManager is not attached to a RecyclerView has no effect. + * + * @param action The Runnable that will be executed. + * + * @see #removeCallbacks + */ + public void postOnAnimation(Runnable action) { + if (mRecyclerView != null) { + ViewCompat.postOnAnimation(mRecyclerView, action); + } + } + + /** + * Removes the specified Runnable from the message queue. + *

+ * Calling this method when LayoutManager is not attached to a RecyclerView has no effect. + * + * @param action The Runnable to remove from the message handling queue + * + * @return true if RecyclerView could ask the Handler to remove the Runnable, + * false otherwise. When the returned value is true, the Runnable + * may or may not have been actually removed from the message queue + * (for instance, if the Runnable was not in the queue already.) + * + * @see #postOnAnimation + */ + public boolean removeCallbacks(Runnable action) { + if (mRecyclerView != null) { + return mRecyclerView.removeCallbacks(action); + } + return false; + } + /** + * Called when this LayoutManager is both attached to a RecyclerView and that RecyclerView + * is attached to a window. + * + *

Subclass implementations should always call through to the superclass implementation. + *

+ * + * @param view The RecyclerView this LayoutManager is bound to + */ + @CallSuper + public void onAttachedToWindow(RecyclerView view) { + } + + /** + * @deprecated + * override {@link #onDetachedFromWindow(RecyclerView, Recycler)} + */ + @Deprecated + public void onDetachedFromWindow(RecyclerView view) { + + } + + /** + * Called when this LayoutManager is detached from its parent RecyclerView or when + * its parent RecyclerView is detached from its window. + * + *

Subclass implementations should always call through to the superclass implementation. + *

+ * + * @param view The RecyclerView this LayoutManager is bound to + * @param recycler The recycler to use if you prefer to recycle your children instead of + * keeping them around. + */ + @CallSuper + public void onDetachedFromWindow(RecyclerView view, Recycler recycler) { + onDetachedFromWindow(view); + } + + /** + * Check if the RecyclerView is configured to clip child views to its padding. + * + * @return true if this RecyclerView clips children to its padding, false otherwise + */ + public boolean getClipToPadding() { + return mRecyclerView != null && mRecyclerView.mClipToPadding; + } + + /** + * Lay out all relevant child views from the given adapter. + * + * The LayoutManager is in charge of the behavior of item animations. By default, + * RecyclerView has a non-null {@link #getItemAnimator() ItemAnimator}, and simple + * item animations are enabled. This means that add/remove operations on the + * adapter will result in animations to add new or appearing items, removed or + * disappearing items, and moved items. If a LayoutManager returns false from + * {@link #supportsPredictiveItemAnimations()}, which is the default, and runs a + * normal layout operation during {@link #onLayoutChildren(Recycler, State)}, the + * RecyclerView will have enough information to run those animations in a simple + * way. For example, the default ItemAnimator, {@link DefaultItemAnimator}, will + * simply fade views in and out, whether they are actually added/removed or whether + * they are moved on or off the screen due to other add/remove operations. + * + *

A LayoutManager wanting a better item animation experience, where items can be + * animated onto and off of the screen according to where the items exist when they + * are not on screen, then the LayoutManager should return true from + * {@link #supportsPredictiveItemAnimations()} and add additional logic to + * {@link #onLayoutChildren(Recycler, State)}. Supporting predictive animations + * means that {@link #onLayoutChildren(Recycler, State)} will be called twice; + * once as a "pre" layout step to determine where items would have been prior to + * a real layout, and again to do the "real" layout. In the pre-layout phase, + * items will remember their pre-layout positions to allow them to be laid out + * appropriately. Also, {@link LayoutParams#isItemRemoved() removed} items will + * be returned from the scrap to help determine correct placement of other items. + * These removed items should not be added to the child list, but should be used + * to help calculate correct positioning of other views, including views that + * were not previously onscreen (referred to as APPEARING views), but whose + * pre-layout offscreen position can be determined given the extra + * information about the pre-layout removed views.

+ * + *

The second layout pass is the real layout in which only non-removed views + * will be used. The only additional requirement during this pass is, if + * {@link #supportsPredictiveItemAnimations()} returns true, to note which + * views exist in the child list prior to layout and which are not there after + * layout (referred to as DISAPPEARING views), and to position/layout those views + * appropriately, without regard to the actual bounds of the RecyclerView. This allows + * the animation system to know the location to which to animate these disappearing + * views.

+ * + *

The default LayoutManager implementations for RecyclerView handle all of these + * requirements for animations already. Clients of RecyclerView can either use one + * of these layout managers directly or look at their implementations of + * onLayoutChildren() to see how they account for the APPEARING and + * DISAPPEARING views.

+ * + * @param recycler Recycler to use for fetching potentially cached views for a + * position + * @param state Transient state of RecyclerView + */ + public void onLayoutChildren(Recycler recycler, State state) { + Log.e(TAG, "You must override onLayoutChildren(Recycler recycler, State state) "); + } + + /** + * Create a default LayoutParams object for a child of the RecyclerView. + * + *

LayoutManagers will often want to use a custom LayoutParams type + * to store extra information specific to the layout. Client code should subclass + * {@link RecyclerView.LayoutParams} for this purpose.

+ * + *

Important: if you use your own custom LayoutParams type + * you must also override + * {@link #checkLayoutParams(LayoutParams)}, + * {@link #generateLayoutParams(android.view.ViewGroup.LayoutParams)} and + * {@link #generateLayoutParams(android.content.Context, android.util.AttributeSet)}.

+ * + * @return A new LayoutParams for a child view + */ + public abstract LayoutParams generateDefaultLayoutParams(); + + /** + * Determines the validity of the supplied LayoutParams object. + * + *

This should check to make sure that the object is of the correct type + * and all values are within acceptable ranges. The default implementation + * returns true for non-null params.

+ * + * @param lp LayoutParams object to check + * @return true if this LayoutParams object is valid, false otherwise + */ + public boolean checkLayoutParams(LayoutParams lp) { + return lp != null; + } + + /** + * Create a LayoutParams object suitable for this LayoutManager, copying relevant + * values from the supplied LayoutParams object if possible. + * + *

Important: if you use your own custom LayoutParams type + * you must also override + * {@link #checkLayoutParams(LayoutParams)}, + * {@link #generateLayoutParams(android.view.ViewGroup.LayoutParams)} and + * {@link #generateLayoutParams(android.content.Context, android.util.AttributeSet)}.

+ * + * @param lp Source LayoutParams object to copy values from + * @return a new LayoutParams object + */ + public LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { + if (lp instanceof LayoutParams) { + return new LayoutParams((LayoutParams) lp); + } else if (lp instanceof MarginLayoutParams) { + return new LayoutParams((MarginLayoutParams) lp); + } else { + return new LayoutParams(lp); + } + } + + /** + * Create a LayoutParams object suitable for this LayoutManager from + * an inflated layout resource. + * + *

Important: if you use your own custom LayoutParams type + * you must also override + * {@link #checkLayoutParams(LayoutParams)}, + * {@link #generateLayoutParams(android.view.ViewGroup.LayoutParams)} and + * {@link #generateLayoutParams(android.content.Context, android.util.AttributeSet)}.

+ * + * @param c Context for obtaining styled attributes + * @param attrs AttributeSet describing the supplied arguments + * @return a new LayoutParams object + */ + public LayoutParams generateLayoutParams(Context c, AttributeSet attrs) { + return new LayoutParams(c, attrs); + } + + /** + * Scroll horizontally by dx pixels in screen coordinates and return the distance traveled. + * The default implementation does nothing and returns 0. + * + * @param dx distance to scroll by in pixels. X increases as scroll position + * approaches the right. + * @param recycler Recycler to use for fetching potentially cached views for a + * position + * @param state Transient state of RecyclerView + * @return The actual distance scrolled. The return value will be negative if dx was + * negative and scrolling proceeeded in that direction. + * Math.abs(result) may be less than dx if a boundary was reached. + */ + public int scrollHorizontallyBy(int dx, Recycler recycler, State state) { + return 0; + } + + /** + * Scroll vertically by dy pixels in screen coordinates and return the distance traveled. + * The default implementation does nothing and returns 0. + * + * @param dy distance to scroll in pixels. Y increases as scroll position + * approaches the bottom. + * @param recycler Recycler to use for fetching potentially cached views for a + * position + * @param state Transient state of RecyclerView + * @return The actual distance scrolled. The return value will be negative if dy was + * negative and scrolling proceeeded in that direction. + * Math.abs(result) may be less than dy if a boundary was reached. + */ + public int scrollVerticallyBy(int dy, Recycler recycler, State state) { + return 0; + } + + /** + * Query if horizontal scrolling is currently supported. The default implementation + * returns false. + * + * @return True if this LayoutManager can scroll the current contents horizontally + */ + public boolean canScrollHorizontally() { + return false; + } + + /** + * Query if vertical scrolling is currently supported. The default implementation + * returns false. + * + * @return True if this LayoutManager can scroll the current contents vertically + */ + public boolean canScrollVertically() { + return false; + } + + /** + * Scroll to the specified adapter position. + * + * Actual position of the item on the screen depends on the LayoutManager implementation. + * @param position Scroll to this adapter position. + */ + public void scrollToPosition(int position) { + if (DEBUG) { + Log.e(TAG, "You MUST implement scrollToPosition. It will soon become abstract"); + } + } + + /** + *

Smooth scroll to the specified adapter position.

+ *

To support smooth scrolling, override this method, create your {@link SmoothScroller} + * instance and call {@link #startSmoothScroll(SmoothScroller)}. + *

+ * @param recyclerView The RecyclerView to which this layout manager is attached + * @param state Current State of RecyclerView + * @param position Scroll to this adapter position. + */ + public void smoothScrollToPosition(RecyclerView recyclerView, State state, + int position) { + Log.e(TAG, "You must override smoothScrollToPosition to support smooth scrolling"); + } + + /** + *

Starts a smooth scroll using the provided SmoothScroller.

+ *

Calling this method will cancel any previous smooth scroll request.

+ * @param smoothScroller Unstance which defines how smooth scroll should be animated + */ + public void startSmoothScroll(SmoothScroller smoothScroller) { + if (mSmoothScroller != null && smoothScroller != mSmoothScroller + && mSmoothScroller.isRunning()) { + mSmoothScroller.stop(); + } + mSmoothScroller = smoothScroller; + mSmoothScroller.start(mRecyclerView, this); + } + + /** + * @return true if RecycylerView is currently in the state of smooth scrolling. + */ + public boolean isSmoothScrolling() { + return mSmoothScroller != null && mSmoothScroller.isRunning(); + } + + + /** + * Returns the resolved layout direction for this RecyclerView. + * + * @return {@link android.support.v4.view.ViewCompat#LAYOUT_DIRECTION_RTL} if the layout + * direction is RTL or returns + * {@link android.support.v4.view.ViewCompat#LAYOUT_DIRECTION_LTR} if the layout direction + * is not RTL. + */ + public int getLayoutDirection() { + return ViewCompat.getLayoutDirection(mRecyclerView); + } + + /** + * Ends all animations on the view created by the {@link ItemAnimator}. + * + * @param view The View for which the animations should be ended. + * @see RecyclerView.ItemAnimator#endAnimations() + */ + public void endAnimation(View view) { + if (mRecyclerView.mItemAnimator != null) { + mRecyclerView.mItemAnimator.endAnimation(getChildViewHolderInt(view)); + } + } + + /** + * To be called only during {@link #onLayoutChildren(Recycler, State)} to add a view + * to the layout that is known to be going away, either because it has been + * {@link Adapter#notifyItemRemoved(int) removed} or because it is actually not in the + * visible portion of the container but is being laid out in order to inform RecyclerView + * in how to animate the item out of view. + *

+ * Views added via this method are going to be invisible to LayoutManager after the + * dispatchLayout pass is complete. They cannot be retrieved via {@link #getChildAt(int)} + * or won't be included in {@link #getChildCount()} method. + * + * @param child View to add and then remove with animation. + */ + public void addDisappearingView(View child) { + addDisappearingView(child, -1); + } + + /** + * To be called only during {@link #onLayoutChildren(Recycler, State)} to add a view + * to the layout that is known to be going away, either because it has been + * {@link Adapter#notifyItemRemoved(int) removed} or because it is actually not in the + * visible portion of the container but is being laid out in order to inform RecyclerView + * in how to animate the item out of view. + *

+ * Views added via this method are going to be invisible to LayoutManager after the + * dispatchLayout pass is complete. They cannot be retrieved via {@link #getChildAt(int)} + * or won't be included in {@link #getChildCount()} method. + * + * @param child View to add and then remove with animation. + * @param index Index of the view. + */ + public void addDisappearingView(View child, int index) { + addViewInt(child, index, true); + } + + /** + * Add a view to the currently attached RecyclerView if needed. LayoutManagers should + * use this method to add views obtained from a {@link Recycler} using + * {@link Recycler#getViewForPosition(int)}. + * + * @param child View to add + */ + public void addView(View child) { + addView(child, -1); + } + + /** + * Add a view to the currently attached RecyclerView if needed. LayoutManagers should + * use this method to add views obtained from a {@link Recycler} using + * {@link Recycler#getViewForPosition(int)}. + * + * @param child View to add + * @param index Index to add child at + */ + public void addView(View child, int index) { + addViewInt(child, index, false); + } + + private void addViewInt(View child, int index, boolean disappearing) { + final ViewHolder holder = getChildViewHolderInt(child); + if (disappearing || holder.isRemoved()) { + // these views will be hidden at the end of the layout pass. + mRecyclerView.mViewInfoStore.addToDisappearedInLayout(holder); + } else { + // This may look like unnecessary but may happen if layout manager supports + // predictive layouts and adapter removed then re-added the same item. + // In this case, added version will be visible in the post layout (because add is + // deferred) but RV will still bind it to the same View. + // So if a View re-appears in post layout pass, remove it from disappearing list. + mRecyclerView.mViewInfoStore.removeFromDisappearedInLayout(holder); + } + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (holder.wasReturnedFromScrap() || holder.isScrap()) { + if (holder.isScrap()) { + holder.unScrap(); + } else { + holder.clearReturnedFromScrapFlag(); + } + mChildHelper.attachViewToParent(child, index, child.getLayoutParams(), false); + if (DISPATCH_TEMP_DETACH) { + ViewCompat.dispatchFinishTemporaryDetach(child); + } + } else if (child.getParent() == mRecyclerView) { // it was not a scrap but a valid child + // ensure in correct position + int currentIndex = mChildHelper.indexOfChild(child); + if (index == -1) { + index = mChildHelper.getChildCount(); + } + if (currentIndex == -1) { + throw new IllegalStateException("Added View has RecyclerView as parent but" + + " view is not a real child. Unfiltered index:" + + mRecyclerView.indexOfChild(child)); + } + if (currentIndex != index) { + mRecyclerView.mLayout.moveView(currentIndex, index); + } + } else { + mChildHelper.addView(child, index, false); + lp.mInsetsDirty = true; + if (mSmoothScroller != null && mSmoothScroller.isRunning()) { + mSmoothScroller.onChildAttachedToWindow(child); + } + } + if (lp.mPendingInvalidate) { + if (DEBUG) { + Log.d(TAG, "consuming pending invalidate on child " + lp.mViewHolder); + } + holder.itemView.invalidate(); + lp.mPendingInvalidate = false; + } + } + + /** + * Remove a view from the currently attached RecyclerView if needed. LayoutManagers should + * use this method to completely remove a child view that is no longer needed. + * LayoutManagers should strongly consider recycling removed views using + * {@link Recycler#recycleView(android.view.View)}. + * + * @param child View to remove + */ + public void removeView(View child) { + mChildHelper.removeView(child); + } + + /** + * Remove a view from the currently attached RecyclerView if needed. LayoutManagers should + * use this method to completely remove a child view that is no longer needed. + * LayoutManagers should strongly consider recycling removed views using + * {@link Recycler#recycleView(android.view.View)}. + * + * @param index Index of the child view to remove + */ + public void removeViewAt(int index) { + final View child = getChildAt(index); + if (child != null) { + mChildHelper.removeViewAt(index); + } + } + + /** + * Remove all views from the currently attached RecyclerView. This will not recycle + * any of the affected views; the LayoutManager is responsible for doing so if desired. + */ + public void removeAllViews() { + // Only remove non-animating views + final int childCount = getChildCount(); + for (int i = childCount - 1; i >= 0; i--) { + mChildHelper.removeViewAt(i); + } + } + + /** + * Returns offset of the RecyclerView's text baseline from the its top boundary. + * + * @return The offset of the RecyclerView's text baseline from the its top boundary; -1 if + * there is no baseline. + */ + public int getBaseline() { + return -1; + } + + /** + * Returns the adapter position of the item represented by the given View. This does not + * contain any adapter changes that might have happened after the last layout. + * + * @param view The view to query + * @return The adapter position of the item which is rendered by this View. + */ + public int getPosition(View view) { + return ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewLayoutPosition(); + } + + /** + * Returns the View type defined by the adapter. + * + * @param view The view to query + * @return The type of the view assigned by the adapter. + */ + public int getItemViewType(View view) { + return getChildViewHolderInt(view).getItemViewType(); + } + + /** + * Traverses the ancestors of the given view and returns the item view that contains it + * and also a direct child of the LayoutManager. + *

+ * Note that this method may return null if the view is a child of the RecyclerView but + * not a child of the LayoutManager (e.g. running a disappear animation). + * + * @param view The view that is a descendant of the LayoutManager. + * + * @return The direct child of the LayoutManager which contains the given view or null if + * the provided view is not a descendant of this LayoutManager. + * + * @see RecyclerView#getChildViewHolder(View) + * @see RecyclerView#findContainingViewHolder(View) + */ + @Nullable + public View findContainingItemView(View view) { + if (mRecyclerView == null) { + return null; + } + View found = mRecyclerView.findContainingItemView(view); + if (found == null) { + return null; + } + if (mChildHelper.isHidden(found)) { + return null; + } + return found; + } + + /** + * Finds the view which represents the given adapter position. + *

+ * This method traverses each child since it has no information about child order. + * Override this method to improve performance if your LayoutManager keeps data about + * child views. + *

+ * If a view is ignored via {@link #ignoreView(View)}, it is also ignored by this method. + * + * @param position Position of the item in adapter + * @return The child view that represents the given position or null if the position is not + * laid out + */ + public View findViewByPosition(int position) { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + ViewHolder vh = getChildViewHolderInt(child); + if (vh == null) { + continue; + } + if (vh.getLayoutPosition() == position && !vh.shouldIgnore() && + (mRecyclerView.mState.isPreLayout() || !vh.isRemoved())) { + return child; + } + } + return null; + } + + /** + * Temporarily detach a child view. + * + *

LayoutManagers may want to perform a lightweight detach operation to rearrange + * views currently attached to the RecyclerView. Generally LayoutManager implementations + * will want to use {@link #detachAndScrapView(android.view.View, RecyclerView.Recycler)} + * so that the detached view may be rebound and reused.

+ * + *

If a LayoutManager uses this method to detach a view, it must + * {@link #attachView(android.view.View, int, RecyclerView.LayoutParams) reattach} + * or {@link #removeDetachedView(android.view.View) fully remove} the detached view + * before the LayoutManager entry point method called by RecyclerView returns.

+ * + * @param child Child to detach + */ + public void detachView(View child) { + final int ind = mChildHelper.indexOfChild(child); + if (ind >= 0) { + detachViewInternal(ind, child); + } + } + + /** + * Temporarily detach a child view. + * + *

LayoutManagers may want to perform a lightweight detach operation to rearrange + * views currently attached to the RecyclerView. Generally LayoutManager implementations + * will want to use {@link #detachAndScrapView(android.view.View, RecyclerView.Recycler)} + * so that the detached view may be rebound and reused.

+ * + *

If a LayoutManager uses this method to detach a view, it must + * {@link #attachView(android.view.View, int, RecyclerView.LayoutParams) reattach} + * or {@link #removeDetachedView(android.view.View) fully remove} the detached view + * before the LayoutManager entry point method called by RecyclerView returns.

+ * + * @param index Index of the child to detach + */ + public void detachViewAt(int index) { + detachViewInternal(index, getChildAt(index)); + } + + private void detachViewInternal(int index, View view) { + if (DISPATCH_TEMP_DETACH) { + ViewCompat.dispatchStartTemporaryDetach(view); + } + mChildHelper.detachViewFromParent(index); + } + + /** + * Reattach a previously {@link #detachView(android.view.View) detached} view. + * This method should not be used to reattach views that were previously + * {@link #detachAndScrapView(android.view.View, RecyclerView.Recycler)} scrapped}. + * + * @param child Child to reattach + * @param index Intended child index for child + * @param lp LayoutParams for child + */ + public void attachView(View child, int index, LayoutParams lp) { + ViewHolder vh = getChildViewHolderInt(child); + if (vh.isRemoved()) { + mRecyclerView.mViewInfoStore.addToDisappearedInLayout(vh); + } else { + mRecyclerView.mViewInfoStore.removeFromDisappearedInLayout(vh); + } + mChildHelper.attachViewToParent(child, index, lp, vh.isRemoved()); + if (DISPATCH_TEMP_DETACH) { + ViewCompat.dispatchFinishTemporaryDetach(child); + } + } + + /** + * Reattach a previously {@link #detachView(android.view.View) detached} view. + * This method should not be used to reattach views that were previously + * {@link #detachAndScrapView(android.view.View, RecyclerView.Recycler)} scrapped}. + * + * @param child Child to reattach + * @param index Intended child index for child + */ + public void attachView(View child, int index) { + attachView(child, index, (LayoutParams) child.getLayoutParams()); + } + + /** + * Reattach a previously {@link #detachView(android.view.View) detached} view. + * This method should not be used to reattach views that were previously + * {@link #detachAndScrapView(android.view.View, RecyclerView.Recycler)} scrapped}. + * + * @param child Child to reattach + */ + public void attachView(View child) { + attachView(child, -1); + } + + /** + * Finish removing a view that was previously temporarily + * {@link #detachView(android.view.View) detached}. + * + * @param child Detached child to remove + */ + public void removeDetachedView(View child) { + mRecyclerView.removeDetachedView(child, false); + } + + /** + * Moves a View from one position to another. + * + * @param fromIndex The View's initial index + * @param toIndex The View's target index + */ + public void moveView(int fromIndex, int toIndex) { + View view = getChildAt(fromIndex); + if (view == null) { + throw new IllegalArgumentException("Cannot move a child from non-existing index:" + + fromIndex); + } + detachViewAt(fromIndex); + attachView(view, toIndex); + } + + /** + * Detach a child view and add it to a {@link Recycler Recycler's} scrap heap. + * + *

Scrapping a view allows it to be rebound and reused to show updated or + * different data.

+ * + * @param child Child to detach and scrap + * @param recycler Recycler to deposit the new scrap view into + */ + public void detachAndScrapView(View child, Recycler recycler) { + int index = mChildHelper.indexOfChild(child); + scrapOrRecycleView(recycler, index, child); + } + + /** + * Detach a child view and add it to a {@link Recycler Recycler's} scrap heap. + * + *

Scrapping a view allows it to be rebound and reused to show updated or + * different data.

+ * + * @param index Index of child to detach and scrap + * @param recycler Recycler to deposit the new scrap view into + */ + public void detachAndScrapViewAt(int index, Recycler recycler) { + final View child = getChildAt(index); + scrapOrRecycleView(recycler, index, child); + } + + /** + * Remove a child view and recycle it using the given Recycler. + * + * @param child Child to remove and recycle + * @param recycler Recycler to use to recycle child + */ + public void removeAndRecycleView(View child, Recycler recycler) { + removeView(child); + recycler.recycleView(child); + } + + /** + * Remove a child view and recycle it using the given Recycler. + * + * @param index Index of child to remove and recycle + * @param recycler Recycler to use to recycle child + */ + public void removeAndRecycleViewAt(int index, Recycler recycler) { + final View view = getChildAt(index); + removeViewAt(index); + recycler.recycleView(view); + } + + /** + * Return the current number of child views attached to the parent RecyclerView. + * This does not include child views that were temporarily detached and/or scrapped. + * + * @return Number of attached children + */ + public int getChildCount() { + return mChildHelper != null ? mChildHelper.getChildCount() : 0; + } + + /** + * Return the child view at the given index + * @param index Index of child to return + * @return Child view at index + */ + public View getChildAt(int index) { + return mChildHelper != null ? mChildHelper.getChildAt(index) : null; + } + + /** + * Return the width measurement spec mode of the RecyclerView. + *

+ * This value is set only if the LayoutManager opts into the auto measure api via + * {@link #setAutoMeasureEnabled(boolean)}. + *

+ * When RecyclerView is running a layout, this value is always set to + * {@link MeasureSpec#EXACTLY} even if it was measured with a different spec mode. + * + * @return Width measure spec mode. + * + * @see MeasureSpec#getMode(int) + * @see View#onMeasure(int, int) + */ + public int getWidthMode() { + return mWidthMode; + } + + /** + * Return the height measurement spec mode of the RecyclerView. + *

+ * This value is set only if the LayoutManager opts into the auto measure api via + * {@link #setAutoMeasureEnabled(boolean)}. + *

+ * When RecyclerView is running a layout, this value is always set to + * {@link MeasureSpec#EXACTLY} even if it was measured with a different spec mode. + * + * @return Height measure spec mode. + * + * @see MeasureSpec#getMode(int) + * @see View#onMeasure(int, int) + */ + public int getHeightMode() { + return mHeightMode; + } + + /** + * Return the width of the parent RecyclerView + * + * @return Width in pixels + */ + public int getWidth() { + return mWidth; + } + + /** + * Return the height of the parent RecyclerView + * + * @return Height in pixels + */ + public int getHeight() { + return mHeight; + } + + /** + * Return the left padding of the parent RecyclerView + * + * @return Padding in pixels + */ + public int getPaddingLeft() { + return mRecyclerView != null ? mRecyclerView.getPaddingLeft() : 0; + } + + /** + * Return the top padding of the parent RecyclerView + * + * @return Padding in pixels + */ + public int getPaddingTop() { + return mRecyclerView != null ? mRecyclerView.getPaddingTop() : 0; + } + + /** + * Return the right padding of the parent RecyclerView + * + * @return Padding in pixels + */ + public int getPaddingRight() { + return mRecyclerView != null ? mRecyclerView.getPaddingRight() : 0; + } + + /** + * Return the bottom padding of the parent RecyclerView + * + * @return Padding in pixels + */ + public int getPaddingBottom() { + return mRecyclerView != null ? mRecyclerView.getPaddingBottom() : 0; + } + + /** + * Return the start padding of the parent RecyclerView + * + * @return Padding in pixels + */ + public int getPaddingStart() { + return mRecyclerView != null ? ViewCompat.getPaddingStart(mRecyclerView) : 0; + } + + /** + * Return the end padding of the parent RecyclerView + * + * @return Padding in pixels + */ + public int getPaddingEnd() { + return mRecyclerView != null ? ViewCompat.getPaddingEnd(mRecyclerView) : 0; + } + + /** + * Returns true if the RecyclerView this LayoutManager is bound to has focus. + * + * @return True if the RecyclerView has focus, false otherwise. + * @see View#isFocused() + */ + public boolean isFocused() { + return mRecyclerView != null && mRecyclerView.isFocused(); + } + + /** + * Returns true if the RecyclerView this LayoutManager is bound to has or contains focus. + * + * @return true if the RecyclerView has or contains focus + * @see View#hasFocus() + */ + public boolean hasFocus() { + return mRecyclerView != null && mRecyclerView.hasFocus(); + } + + /** + * Returns the item View which has or contains focus. + * + * @return A direct child of RecyclerView which has focus or contains the focused child. + */ + public View getFocusedChild() { + if (mRecyclerView == null) { + return null; + } + final View focused = mRecyclerView.getFocusedChild(); + if (focused == null || mChildHelper.isHidden(focused)) { + return null; + } + return focused; + } + + /** + * Returns the number of items in the adapter bound to the parent RecyclerView. + *

+ * Note that this number is not necessarily equal to {@link State#getItemCount()}. In + * methods where State is available, you should use {@link State#getItemCount()} instead. + * For more details, check the documentation for {@link State#getItemCount()}. + * + * @return The number of items in the bound adapter + * @see State#getItemCount() + */ + public int getItemCount() { + final Adapter a = mRecyclerView != null ? mRecyclerView.getAdapter() : null; + return a != null ? a.getItemCount() : 0; + } + + /** + * Offset all child views attached to the parent RecyclerView by dx pixels along + * the horizontal axis. + * + * @param dx Pixels to offset by + */ + public void offsetChildrenHorizontal(int dx) { + if (mRecyclerView != null) { + mRecyclerView.offsetChildrenHorizontal(dx); + } + } + + /** + * Offset all child views attached to the parent RecyclerView by dy pixels along + * the vertical axis. + * + * @param dy Pixels to offset by + */ + public void offsetChildrenVertical(int dy) { + if (mRecyclerView != null) { + mRecyclerView.offsetChildrenVertical(dy); + } + } + + /** + * Flags a view so that it will not be scrapped or recycled. + *

+ * Scope of ignoring a child is strictly restricted to position tracking, scrapping and + * recyling. Methods like {@link #removeAndRecycleAllViews(Recycler)} will ignore the child + * whereas {@link #removeAllViews()} or {@link #offsetChildrenHorizontal(int)} will not + * ignore the child. + *

+ * Before this child can be recycled again, you have to call + * {@link #stopIgnoringView(View)}. + *

+ * You can call this method only if your LayoutManger is in onLayout or onScroll callback. + * + * @param view View to ignore. + * @see #stopIgnoringView(View) + */ + public void ignoreView(View view) { + if (view.getParent() != mRecyclerView || mRecyclerView.indexOfChild(view) == -1) { + // checking this because calling this method on a recycled or detached view may + // cause loss of state. + throw new IllegalArgumentException("View should be fully attached to be ignored"); + } + final ViewHolder vh = getChildViewHolderInt(view); + vh.addFlags(ViewHolder.FLAG_IGNORE); + mRecyclerView.mViewInfoStore.removeViewHolder(vh); + } + + /** + * View can be scrapped and recycled again. + *

+ * Note that calling this method removes all information in the view holder. + *

+ * You can call this method only if your LayoutManger is in onLayout or onScroll callback. + * + * @param view View to ignore. + */ + public void stopIgnoringView(View view) { + final ViewHolder vh = getChildViewHolderInt(view); + vh.stopIgnoring(); + vh.resetInternal(); + vh.addFlags(ViewHolder.FLAG_INVALID); + } + + /** + * Temporarily detach and scrap all currently attached child views. Views will be scrapped + * into the given Recycler. The Recycler may prefer to reuse scrap views before + * other views that were previously recycled. + * + * @param recycler Recycler to scrap views into + */ + public void detachAndScrapAttachedViews(Recycler recycler) { + final int childCount = getChildCount(); + for (int i = childCount - 1; i >= 0; i--) { + final View v = getChildAt(i); + scrapOrRecycleView(recycler, i, v); + } + } + + private void scrapOrRecycleView(Recycler recycler, int index, View view) { + final ViewHolder viewHolder = getChildViewHolderInt(view); + if (viewHolder.shouldIgnore()) { + if (DEBUG) { + Log.d(TAG, "ignoring view " + viewHolder); + } + return; + } + if (viewHolder.isInvalid() && !viewHolder.isRemoved() && + !mRecyclerView.mAdapter.hasStableIds()) { + removeViewAt(index); + recycler.recycleViewHolderInternal(viewHolder); + } else { + detachViewAt(index); + recycler.scrapView(view); + mRecyclerView.mViewInfoStore.onViewDetached(viewHolder); + } + } + + /** + * Recycles the scrapped views. + *

+ * When a view is detached and removed, it does not trigger a ViewGroup invalidate. This is + * the expected behavior if scrapped views are used for animations. Otherwise, we need to + * call remove and invalidate RecyclerView to ensure UI update. + * + * @param recycler Recycler + */ + void removeAndRecycleScrapInt(Recycler recycler) { + final int scrapCount = recycler.getScrapCount(); + // Loop backward, recycler might be changed by removeDetachedView() + for (int i = scrapCount - 1; i >= 0; i--) { + final View scrap = recycler.getScrapViewAt(i); + final ViewHolder vh = getChildViewHolderInt(scrap); + if (vh.shouldIgnore()) { + continue; + } + // If the scrap view is animating, we need to cancel them first. If we cancel it + // here, ItemAnimator callback may recycle it which will cause double recycling. + // To avoid this, we mark it as not recycleable before calling the item animator. + // Since removeDetachedView calls a user API, a common mistake (ending animations on + // the view) may recycle it too, so we guard it before we call user APIs. + vh.setIsRecyclable(false); + if (vh.isTmpDetached()) { + mRecyclerView.removeDetachedView(scrap, false); + } + if (mRecyclerView.mItemAnimator != null) { + mRecyclerView.mItemAnimator.endAnimation(vh); + } + vh.setIsRecyclable(true); + recycler.quickRecycleScrapView(scrap); + } + recycler.clearScrap(); + if (scrapCount > 0) { + mRecyclerView.invalidate(); + } + } + + + /** + * Measure a child view using standard measurement policy, taking the padding + * of the parent RecyclerView and any added item decorations into account. + * + *

If the RecyclerView can be scrolled in either dimension the caller may + * pass 0 as the widthUsed or heightUsed parameters as they will be irrelevant.

+ * + * @param child Child view to measure + * @param widthUsed Width in pixels currently consumed by other views, if relevant + * @param heightUsed Height in pixels currently consumed by other views, if relevant + */ + public void measureChild(View child, int widthUsed, int heightUsed) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child); + widthUsed += insets.left + insets.right; + heightUsed += insets.top + insets.bottom; + final int widthSpec = getChildMeasureSpec(getWidth(), getWidthMode(), + getPaddingLeft() + getPaddingRight() + widthUsed, lp.width, + canScrollHorizontally()); + final int heightSpec = getChildMeasureSpec(getHeight(), getHeightMode(), + getPaddingTop() + getPaddingBottom() + heightUsed, lp.height, + canScrollVertically()); + if (shouldMeasureChild(child, widthSpec, heightSpec, lp)) { + child.measure(widthSpec, heightSpec); + } + } + + /** + * RecyclerView internally does its own View measurement caching which should help with + * WRAP_CONTENT. + *

+ * Use this method if the View is already measured once in this layout pass. + */ + boolean shouldReMeasureChild(View child, int widthSpec, int heightSpec, LayoutParams lp) { + return !mMeasurementCacheEnabled + || !isMeasurementUpToDate(child.getMeasuredWidth(), widthSpec, lp.width) + || !isMeasurementUpToDate(child.getMeasuredHeight(), heightSpec, lp.height); + } + + // we may consider making this public + /** + * RecyclerView internally does its own View measurement caching which should help with + * WRAP_CONTENT. + *

+ * Use this method if the View is not yet measured and you need to decide whether to + * measure this View or not. + */ + boolean shouldMeasureChild(View child, int widthSpec, int heightSpec, LayoutParams lp) { + return child.isLayoutRequested() + || !mMeasurementCacheEnabled + || !isMeasurementUpToDate(child.getWidth(), widthSpec, lp.width) + || !isMeasurementUpToDate(child.getHeight(), heightSpec, lp.height); + } + + /** + * In addition to the View Framework's measurement cache, RecyclerView uses its own + * additional measurement cache for its children to avoid re-measuring them when not + * necessary. It is on by default but it can be turned off via + * {@link #setMeasurementCacheEnabled(boolean)}. + * + * @return True if measurement cache is enabled, false otherwise. + * + * @see #setMeasurementCacheEnabled(boolean) + */ + public boolean isMeasurementCacheEnabled() { + return mMeasurementCacheEnabled; + } + + /** + * Sets whether RecyclerView should use its own measurement cache for the children. This is + * a more aggressive cache than the framework uses. + * + * @param measurementCacheEnabled True to enable the measurement cache, false otherwise. + * + * @see #isMeasurementCacheEnabled() + */ + public void setMeasurementCacheEnabled(boolean measurementCacheEnabled) { + mMeasurementCacheEnabled = measurementCacheEnabled; + } + + private static boolean isMeasurementUpToDate(int childSize, int spec, int dimension) { + final int specMode = MeasureSpec.getMode(spec); + final int specSize = MeasureSpec.getSize(spec); + if (dimension > 0 && childSize != dimension) { + return false; + } + switch (specMode) { + case MeasureSpec.UNSPECIFIED: + return true; + case MeasureSpec.AT_MOST: + return specSize >= childSize; + case MeasureSpec.EXACTLY: + return specSize == childSize; + } + return false; + } + + /** + * Measure a child view using standard measurement policy, taking the padding + * of the parent RecyclerView, any added item decorations and the child margins + * into account. + * + *

If the RecyclerView can be scrolled in either dimension the caller may + * pass 0 as the widthUsed or heightUsed parameters as they will be irrelevant.

+ * + * @param child Child view to measure + * @param widthUsed Width in pixels currently consumed by other views, if relevant + * @param heightUsed Height in pixels currently consumed by other views, if relevant + */ + public void measureChildWithMargins(View child, int widthUsed, int heightUsed) { + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + + final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child); + widthUsed += insets.left + insets.right; + heightUsed += insets.top + insets.bottom; + + final int widthSpec = getChildMeasureSpec(getWidth(), getWidthMode(), + getPaddingLeft() + getPaddingRight() + + lp.leftMargin + lp.rightMargin + widthUsed, lp.width, + canScrollHorizontally()); + final int heightSpec = getChildMeasureSpec(getHeight(), getHeightMode(), + getPaddingTop() + getPaddingBottom() + + lp.topMargin + lp.bottomMargin + heightUsed, lp.height, + canScrollVertically()); + if (shouldMeasureChild(child, widthSpec, heightSpec, lp)) { + child.measure(widthSpec, heightSpec); + } + } + + /** + * Calculate a MeasureSpec value for measuring a child view in one dimension. + * + * @param parentSize Size of the parent view where the child will be placed + * @param padding Total space currently consumed by other elements of the parent + * @param childDimension Desired size of the child view, or FILL_PARENT/WRAP_CONTENT. + * Generally obtained from the child view's LayoutParams + * @param canScroll true if the parent RecyclerView can scroll in this dimension + * + * @return a MeasureSpec value for the child view + * @deprecated use {@link #getChildMeasureSpec(int, int, int, int, boolean)} + */ + @Deprecated + public static int getChildMeasureSpec(int parentSize, int padding, int childDimension, + boolean canScroll) { + int size = Math.max(0, parentSize - padding); + int resultSize = 0; + int resultMode = 0; + if (canScroll) { + if (childDimension >= 0) { + resultSize = childDimension; + resultMode = MeasureSpec.EXACTLY; + } else { + // FILL_PARENT can't be applied since we can scroll in this dimension, wrap + // instead using UNSPECIFIED. + resultSize = 0; + resultMode = MeasureSpec.UNSPECIFIED; + } + } else { + if (childDimension >= 0) { + resultSize = childDimension; + resultMode = MeasureSpec.EXACTLY; + } else if (childDimension == LayoutParams.FILL_PARENT) { + resultSize = size; + // TODO this should be my spec. + resultMode = MeasureSpec.EXACTLY; + } else if (childDimension == LayoutParams.WRAP_CONTENT) { + resultSize = size; + resultMode = MeasureSpec.AT_MOST; + } + } + return MeasureSpec.makeMeasureSpec(resultSize, resultMode); + } + + /** + * Calculate a MeasureSpec value for measuring a child view in one dimension. + * + * @param parentSize Size of the parent view where the child will be placed + * @param parentMode The measurement spec mode of the parent + * @param padding Total space currently consumed by other elements of parent + * @param childDimension Desired size of the child view, or FILL_PARENT/WRAP_CONTENT. + * Generally obtained from the child view's LayoutParams + * @param canScroll true if the parent RecyclerView can scroll in this dimension + * + * @return a MeasureSpec value for the child view + */ + public static int getChildMeasureSpec(int parentSize, int parentMode, int padding, + int childDimension, boolean canScroll) { + int size = Math.max(0, parentSize - padding); + int resultSize = 0; + int resultMode = 0; + if (canScroll) { + if (childDimension >= 0) { + resultSize = childDimension; + resultMode = MeasureSpec.EXACTLY; + } else if (childDimension == LayoutParams.FILL_PARENT){ + switch (parentMode) { + case MeasureSpec.AT_MOST: + case MeasureSpec.EXACTLY: + resultSize = size; + resultMode = parentMode; + break; + case MeasureSpec.UNSPECIFIED: + resultSize = 0; + resultMode = MeasureSpec.UNSPECIFIED; + break; + } + } else if (childDimension == LayoutParams.WRAP_CONTENT) { + resultSize = 0; + resultMode = MeasureSpec.UNSPECIFIED; + } + } else { + if (childDimension >= 0) { + resultSize = childDimension; + resultMode = MeasureSpec.EXACTLY; + } else if (childDimension == LayoutParams.FILL_PARENT) { + resultSize = size; + resultMode = parentMode; + } else if (childDimension == LayoutParams.WRAP_CONTENT) { + resultSize = size; + if (parentMode == MeasureSpec.AT_MOST || parentMode == MeasureSpec.EXACTLY) { + resultMode = MeasureSpec.AT_MOST; + } else { + resultMode = MeasureSpec.UNSPECIFIED; + } + + } + } + //noinspection WrongConstant + return MeasureSpec.makeMeasureSpec(resultSize, resultMode); + } + + /** + * Returns the measured width of the given child, plus the additional size of + * any insets applied by {@link ItemDecoration ItemDecorations}. + * + * @param child Child view to query + * @return child's measured width plus ItemDecoration insets + * + * @see View#getMeasuredWidth() + */ + public int getDecoratedMeasuredWidth(View child) { + final Rect insets = ((LayoutParams) child.getLayoutParams()).mDecorInsets; + return child.getMeasuredWidth() + insets.left + insets.right; + } + + /** + * Returns the measured height of the given child, plus the additional size of + * any insets applied by {@link ItemDecoration ItemDecorations}. + * + * @param child Child view to query + * @return child's measured height plus ItemDecoration insets + * + * @see View#getMeasuredHeight() + */ + public int getDecoratedMeasuredHeight(View child) { + final Rect insets = ((LayoutParams) child.getLayoutParams()).mDecorInsets; + return child.getMeasuredHeight() + insets.top + insets.bottom; + } + + /** + * Lay out the given child view within the RecyclerView using coordinates that + * include any current {@link ItemDecoration ItemDecorations}. + * + *

LayoutManagers should prefer working in sizes and coordinates that include + * item decoration insets whenever possible. This allows the LayoutManager to effectively + * ignore decoration insets within measurement and layout code. See the following + * methods:

+ *
    + *
  • {@link #measureChild(View, int, int)}
  • + *
  • {@link #measureChildWithMargins(View, int, int)}
  • + *
  • {@link #getDecoratedLeft(View)}
  • + *
  • {@link #getDecoratedTop(View)}
  • + *
  • {@link #getDecoratedRight(View)}
  • + *
  • {@link #getDecoratedBottom(View)}
  • + *
  • {@link #getDecoratedMeasuredWidth(View)}
  • + *
  • {@link #getDecoratedMeasuredHeight(View)}
  • + *
+ * + * @param child Child to lay out + * @param left Left edge, with item decoration insets included + * @param top Top edge, with item decoration insets included + * @param right Right edge, with item decoration insets included + * @param bottom Bottom edge, with item decoration insets included + * + * @see View#layout(int, int, int, int) + */ + public void layoutDecorated(View child, int left, int top, int right, int bottom) { + final Rect insets = ((LayoutParams) child.getLayoutParams()).mDecorInsets; + child.layout(left + insets.left, top + insets.top, right - insets.right, + bottom - insets.bottom); + } + + /** + * Returns the left edge of the given child view within its parent, offset by any applied + * {@link ItemDecoration ItemDecorations}. + * + * @param child Child to query + * @return Child left edge with offsets applied + * @see #getLeftDecorationWidth(View) + */ + public int getDecoratedLeft(View child) { + return child.getLeft() - getLeftDecorationWidth(child); + } + + /** + * Returns the top edge of the given child view within its parent, offset by any applied + * {@link ItemDecoration ItemDecorations}. + * + * @param child Child to query + * @return Child top edge with offsets applied + * @see #getTopDecorationHeight(View) + */ + public int getDecoratedTop(View child) { + return child.getTop() - getTopDecorationHeight(child); + } + + /** + * Returns the right edge of the given child view within its parent, offset by any applied + * {@link ItemDecoration ItemDecorations}. + * + * @param child Child to query + * @return Child right edge with offsets applied + * @see #getRightDecorationWidth(View) + */ + public int getDecoratedRight(View child) { + return child.getRight() + getRightDecorationWidth(child); + } + + /** + * Returns the bottom edge of the given child view within its parent, offset by any applied + * {@link ItemDecoration ItemDecorations}. + * + * @param child Child to query + * @return Child bottom edge with offsets applied + * @see #getBottomDecorationHeight(View) + */ + public int getDecoratedBottom(View child) { + return child.getBottom() + getBottomDecorationHeight(child); + } + + /** + * Calculates the item decor insets applied to the given child and updates the provided + * Rect instance with the inset values. + *
    + *
  • The Rect's left is set to the total width of left decorations.
  • + *
  • The Rect's top is set to the total height of top decorations.
  • + *
  • The Rect's right is set to the total width of right decorations.
  • + *
  • The Rect's bottom is set to total height of bottom decorations.
  • + *
+ *

+ * Note that item decorations are automatically calculated when one of the LayoutManager's + * measure child methods is called. If you need to measure the child with custom specs via + * {@link View#measure(int, int)}, you can use this method to get decorations. + * + * @param child The child view whose decorations should be calculated + * @param outRect The Rect to hold result values + */ + public void calculateItemDecorationsForChild(View child, Rect outRect) { + if (mRecyclerView == null) { + outRect.set(0, 0, 0, 0); + return; + } + Rect insets = mRecyclerView.getItemDecorInsetsForChild(child); + outRect.set(insets); + } + + /** + * Returns the total height of item decorations applied to child's top. + *

+ * Note that this value is not updated until the View is measured or + * {@link #calculateItemDecorationsForChild(View, Rect)} is called. + * + * @param child Child to query + * @return The total height of item decorations applied to the child's top. + * @see #getDecoratedTop(View) + * @see #calculateItemDecorationsForChild(View, Rect) + */ + public int getTopDecorationHeight(View child) { + return ((LayoutParams) child.getLayoutParams()).mDecorInsets.top; + } + + /** + * Returns the total height of item decorations applied to child's bottom. + *

+ * Note that this value is not updated until the View is measured or + * {@link #calculateItemDecorationsForChild(View, Rect)} is called. + * + * @param child Child to query + * @return The total height of item decorations applied to the child's bottom. + * @see #getDecoratedBottom(View) + * @see #calculateItemDecorationsForChild(View, Rect) + */ + public int getBottomDecorationHeight(View child) { + return ((LayoutParams) child.getLayoutParams()).mDecorInsets.bottom; + } + + /** + * Returns the total width of item decorations applied to child's left. + *

+ * Note that this value is not updated until the View is measured or + * {@link #calculateItemDecorationsForChild(View, Rect)} is called. + * + * @param child Child to query + * @return The total width of item decorations applied to the child's left. + * @see #getDecoratedLeft(View) + * @see #calculateItemDecorationsForChild(View, Rect) + */ + public int getLeftDecorationWidth(View child) { + return ((LayoutParams) child.getLayoutParams()).mDecorInsets.left; + } + + /** + * Returns the total width of item decorations applied to child's right. + *

+ * Note that this value is not updated until the View is measured or + * {@link #calculateItemDecorationsForChild(View, Rect)} is called. + * + * @param child Child to query + * @return The total width of item decorations applied to the child's right. + * @see #getDecoratedRight(View) + * @see #calculateItemDecorationsForChild(View, Rect) + */ + public int getRightDecorationWidth(View child) { + return ((LayoutParams) child.getLayoutParams()).mDecorInsets.right; + } + + /** + * Called when searching for a focusable view in the given direction has failed + * for the current content of the RecyclerView. + * + *

This is the LayoutManager's opportunity to populate views in the given direction + * to fulfill the request if it can. The LayoutManager should attach and return + * the view to be focused. The default implementation returns null.

+ * + * @param focused The currently focused view + * @param direction One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, + * {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT}, + * {@link View#FOCUS_BACKWARD}, {@link View#FOCUS_FORWARD} + * or 0 for not applicable + * @param recycler The recycler to use for obtaining views for currently offscreen items + * @param state Transient state of RecyclerView + * @return The chosen view to be focused + */ + @Nullable + public View onFocusSearchFailed(View focused, int direction, Recycler recycler, + State state) { + return null; + } + + /** + * This method gives a LayoutManager an opportunity to intercept the initial focus search + * before the default behavior of {@link FocusFinder} is used. If this method returns + * null FocusFinder will attempt to find a focusable child view. If it fails + * then {@link #onFocusSearchFailed(View, int, RecyclerView.Recycler, RecyclerView.State)} + * will be called to give the LayoutManager an opportunity to add new views for items + * that did not have attached views representing them. The LayoutManager should not add + * or remove views from this method. + * + * @param focused The currently focused view + * @param direction One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, + * {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT}, + * {@link View#FOCUS_BACKWARD}, {@link View#FOCUS_FORWARD} + * @return A descendant view to focus or null to fall back to default behavior. + * The default implementation returns null. + */ + public View onInterceptFocusSearch(View focused, int direction) { + return null; + } + + /** + * Called when a child of the RecyclerView wants a particular rectangle to be positioned + * onto the screen. See {@link ViewParent#requestChildRectangleOnScreen(android.view.View, + * android.graphics.Rect, boolean)} for more details. + * + *

The base implementation will attempt to perform a standard programmatic scroll + * to bring the given rect into view, within the padded area of the RecyclerView.

+ * + * @param child The direct child making the request. + * @param rect The rectangle in the child's coordinates the child + * wishes to be on the screen. + * @param immediate True to forbid animated or delayed scrolling, + * false otherwise + * @return Whether the group scrolled to handle the operation + */ + public boolean requestChildRectangleOnScreen(RecyclerView parent, View child, Rect rect, + boolean immediate) { + final int parentLeft = getPaddingLeft(); + final int parentTop = getPaddingTop(); + final int parentRight = getWidth() - getPaddingRight(); + final int parentBottom = getHeight() - getPaddingBottom(); + final int childLeft = child.getLeft() + rect.left - child.getScrollX(); + final int childTop = child.getTop() + rect.top - child.getScrollY(); + final int childRight = childLeft + rect.width(); + final int childBottom = childTop + rect.height(); + + final int offScreenLeft = Math.min(0, childLeft - parentLeft); + final int offScreenTop = Math.min(0, childTop - parentTop); + final int offScreenRight = Math.max(0, childRight - parentRight); + final int offScreenBottom = Math.max(0, childBottom - parentBottom); + + // Favor the "start" layout direction over the end when bringing one side or the other + // of a large rect into view. If we decide to bring in end because start is already + // visible, limit the scroll such that start won't go out of bounds. + final int dx; + if (getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL) { + dx = offScreenRight != 0 ? offScreenRight + : Math.max(offScreenLeft, childRight - parentRight); + } else { + dx = offScreenLeft != 0 ? offScreenLeft + : Math.min(childLeft - parentLeft, offScreenRight); + } + + // Favor bringing the top into view over the bottom. If top is already visible and + // we should scroll to make bottom visible, make sure top does not go out of bounds. + final int dy = offScreenTop != 0 ? offScreenTop + : Math.min(childTop - parentTop, offScreenBottom); + + if (dx != 0 || dy != 0) { + if (immediate) { + parent.scrollBy(dx, dy); + } else { + parent.smoothScrollBy(dx, dy); + } + return true; + } + return false; + } + + /** + * @deprecated Use {@link #onRequestChildFocus(RecyclerView, State, View, View)} + */ + @Deprecated + public boolean onRequestChildFocus(RecyclerView parent, View child, View focused) { + // eat the request if we are in the middle of a scroll or layout + return isSmoothScrolling() || parent.isComputingLayout(); + } + + /** + * Called when a descendant view of the RecyclerView requests focus. + * + *

A LayoutManager wishing to keep focused views aligned in a specific + * portion of the view may implement that behavior in an override of this method.

+ * + *

If the LayoutManager executes different behavior that should override the default + * behavior of scrolling the focused child on screen instead of running alongside it, + * this method should return true.

+ * + * @param parent The RecyclerView hosting this LayoutManager + * @param state Current state of RecyclerView + * @param child Direct child of the RecyclerView containing the newly focused view + * @param focused The newly focused view. This may be the same view as child or it may be + * null + * @return true if the default scroll behavior should be suppressed + */ + public boolean onRequestChildFocus(RecyclerView parent, State state, View child, + View focused) { + return onRequestChildFocus(parent, child, focused); + } + + /** + * Called if the RecyclerView this LayoutManager is bound to has a different adapter set. + * The LayoutManager may use this opportunity to clear caches and configure state such + * that it can relayout appropriately with the new data and potentially new view types. + * + *

The default implementation removes all currently attached views.

+ * + * @param oldAdapter The previous adapter instance. Will be null if there was previously no + * adapter. + * @param newAdapter The new adapter instance. Might be null if + * {@link #setAdapter(RecyclerView.Adapter)} is called with {@code null}. + */ + public void onAdapterChanged(Adapter oldAdapter, Adapter newAdapter) { + } + + /** + * Called to populate focusable views within the RecyclerView. + * + *

The LayoutManager implementation should return true if the default + * behavior of {@link ViewGroup#addFocusables(java.util.ArrayList, int)} should be + * suppressed.

+ * + *

The default implementation returns false to trigger RecyclerView + * to fall back to the default ViewGroup behavior.

+ * + * @param recyclerView The RecyclerView hosting this LayoutManager + * @param views List of output views. This method should add valid focusable views + * to this list. + * @param direction One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, + * {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT}, + * {@link View#FOCUS_BACKWARD}, {@link View#FOCUS_FORWARD} + * @param focusableMode The type of focusables to be added. + * + * @return true to suppress the default behavior, false to add default focusables after + * this method returns. + * + * @see #FOCUSABLES_ALL + * @see #FOCUSABLES_TOUCH_MODE + */ + public boolean onAddFocusables(RecyclerView recyclerView, ArrayList views, + int direction, int focusableMode) { + return false; + } + + /** + * Called when {@link Adapter#notifyDataSetChanged()} is triggered instead of giving + * detailed information on what has actually changed. + * + * @param recyclerView + */ + public void onItemsChanged(RecyclerView recyclerView) { + } + + /** + * Called when items have been added to the adapter. The LayoutManager may choose to + * requestLayout if the inserted items would require refreshing the currently visible set + * of child views. (e.g. currently empty space would be filled by appended items, etc.) + * + * @param recyclerView + * @param positionStart + * @param itemCount + */ + public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) { + } + + /** + * Called when items have been removed from the adapter. + * + * @param recyclerView + * @param positionStart + * @param itemCount + */ + public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) { + } + + /** + * Called when items have been changed in the adapter. + * To receive payload, override {@link #onItemsUpdated(RecyclerView, int, int, Object)} + * instead, then this callback will not be invoked. + * + * @param recyclerView + * @param positionStart + * @param itemCount + */ + public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount) { + } + + /** + * Called when items have been changed in the adapter and with optional payload. + * Default implementation calls {@link #onItemsUpdated(RecyclerView, int, int)}. + * + * @param recyclerView + * @param positionStart + * @param itemCount + * @param payload + */ + public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount, + Object payload) { + onItemsUpdated(recyclerView, positionStart, itemCount); + } + + /** + * Called when an item is moved withing the adapter. + *

+ * Note that, an item may also change position in response to another ADD/REMOVE/MOVE + * operation. This callback is only called if and only if {@link Adapter#notifyItemMoved} + * is called. + * + * @param recyclerView + * @param from + * @param to + * @param itemCount + */ + public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) { + + } + + + /** + *

Override this method if you want to support scroll bars.

+ * + *

Read {@link RecyclerView#computeHorizontalScrollExtent()} for details.

+ * + *

Default implementation returns 0.

+ * + * @param state Current state of RecyclerView + * @return The horizontal extent of the scrollbar's thumb + * @see RecyclerView#computeHorizontalScrollExtent() + */ + public int computeHorizontalScrollExtent(State state) { + return 0; + } + + /** + *

Override this method if you want to support scroll bars.

+ * + *

Read {@link RecyclerView#computeHorizontalScrollOffset()} for details.

+ * + *

Default implementation returns 0.

+ * + * @param state Current State of RecyclerView where you can find total item count + * @return The horizontal offset of the scrollbar's thumb + * @see RecyclerView#computeHorizontalScrollOffset() + */ + public int computeHorizontalScrollOffset(State state) { + return 0; + } + + /** + *

Override this method if you want to support scroll bars.

+ * + *

Read {@link RecyclerView#computeHorizontalScrollRange()} for details.

+ * + *

Default implementation returns 0.

+ * + * @param state Current State of RecyclerView where you can find total item count + * @return The total horizontal range represented by the vertical scrollbar + * @see RecyclerView#computeHorizontalScrollRange() + */ + public int computeHorizontalScrollRange(State state) { + return 0; + } + + /** + *

Override this method if you want to support scroll bars.

+ * + *

Read {@link RecyclerView#computeVerticalScrollExtent()} for details.

+ * + *

Default implementation returns 0.

+ * + * @param state Current state of RecyclerView + * @return The vertical extent of the scrollbar's thumb + * @see RecyclerView#computeVerticalScrollExtent() + */ + public int computeVerticalScrollExtent(State state) { + return 0; + } + + /** + *

Override this method if you want to support scroll bars.

+ * + *

Read {@link RecyclerView#computeVerticalScrollOffset()} for details.

+ * + *

Default implementation returns 0.

+ * + * @param state Current State of RecyclerView where you can find total item count + * @return The vertical offset of the scrollbar's thumb + * @see RecyclerView#computeVerticalScrollOffset() + */ + public int computeVerticalScrollOffset(State state) { + return 0; + } + + /** + *

Override this method if you want to support scroll bars.

+ * + *

Read {@link RecyclerView#computeVerticalScrollRange()} for details.

+ * + *

Default implementation returns 0.

+ * + * @param state Current State of RecyclerView where you can find total item count + * @return The total vertical range represented by the vertical scrollbar + * @see RecyclerView#computeVerticalScrollRange() + */ + public int computeVerticalScrollRange(State state) { + return 0; + } + + /** + * Measure the attached RecyclerView. Implementations must call + * {@link #setMeasuredDimension(int, int)} before returning. + * + *

The default implementation will handle EXACTLY measurements and respect + * the minimum width and height properties of the host RecyclerView if measured + * as UNSPECIFIED. AT_MOST measurements will be treated as EXACTLY and the RecyclerView + * will consume all available space.

+ * + * @param recycler Recycler + * @param state Transient state of RecyclerView + * @param widthSpec Width {@link android.view.View.MeasureSpec} + * @param heightSpec Height {@link android.view.View.MeasureSpec} + */ + public void onMeasure(Recycler recycler, State state, int widthSpec, int heightSpec) { + mRecyclerView.defaultOnMeasure(widthSpec, heightSpec); + } + + /** + * {@link View#setMeasuredDimension(int, int) Set the measured dimensions} of the + * host RecyclerView. + * + * @param widthSize Measured width + * @param heightSize Measured height + */ + public void setMeasuredDimension(int widthSize, int heightSize) { + mRecyclerView.setMeasuredDimension(widthSize, heightSize); + } + + /** + * @return The host RecyclerView's {@link View#getMinimumWidth()} + */ + public int getMinimumWidth() { + return ViewCompat.getMinimumWidth(mRecyclerView); + } + + /** + * @return The host RecyclerView's {@link View#getMinimumHeight()} + */ + public int getMinimumHeight() { + return ViewCompat.getMinimumHeight(mRecyclerView); + } + /** + *

Called when the LayoutManager should save its state. This is a good time to save your + * scroll position, configuration and anything else that may be required to restore the same + * layout state if the LayoutManager is recreated.

+ *

RecyclerView does NOT verify if the LayoutManager has changed between state save and + * restore. This will let you share information between your LayoutManagers but it is also + * your responsibility to make sure they use the same parcelable class.

+ * + * @return Necessary information for LayoutManager to be able to restore its state + */ + public Parcelable onSaveInstanceState() { + return null; + } + + + public void onRestoreInstanceState(Parcelable state) { + + } + + void stopSmoothScroller() { + if (mSmoothScroller != null) { + mSmoothScroller.stop(); + } + } + + private void onSmoothScrollerStopped(SmoothScroller smoothScroller) { + if (mSmoothScroller == smoothScroller) { + mSmoothScroller = null; + } + } + + /** + * RecyclerView calls this method to notify LayoutManager that scroll state has changed. + * + * @param state The new scroll state for RecyclerView + */ + public void onScrollStateChanged(int state) { + } + + /** + * Removes all views and recycles them using the given recycler. + *

+ * If you want to clean cached views as well, you should call {@link Recycler#clear()} too. + *

+ * If a View is marked as "ignored", it is not removed nor recycled. + * + * @param recycler Recycler to use to recycle children + * @see #removeAndRecycleView(View, Recycler) + * @see #removeAndRecycleViewAt(int, Recycler) + * @see #ignoreView(View) + */ + public void removeAndRecycleAllViews(Recycler recycler) { + for (int i = getChildCount() - 1; i >= 0; i--) { + final View view = getChildAt(i); + if (!getChildViewHolderInt(view).shouldIgnore()) { + removeAndRecycleViewAt(i, recycler); + } + } + } + + // called by accessibility delegate + void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfoCompat info) { + onInitializeAccessibilityNodeInfo(mRecyclerView.mRecycler, mRecyclerView.mState, info); + } + + /** + * Called by the AccessibilityDelegate when the information about the current layout should + * be populated. + *

+ * Default implementation adds a {@link + * android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionInfoCompat}. + *

+ * You should override + * {@link #getRowCountForAccessibility(RecyclerView.Recycler, RecyclerView.State)}, + * {@link #getColumnCountForAccessibility(RecyclerView.Recycler, RecyclerView.State)}, + * {@link #isLayoutHierarchical(RecyclerView.Recycler, RecyclerView.State)} and + * {@link #getSelectionModeForAccessibility(RecyclerView.Recycler, RecyclerView.State)} for + * more accurate accessibility information. + * + * @param recycler The Recycler that can be used to convert view positions into adapter + * positions + * @param state The current state of RecyclerView + * @param info The info that should be filled by the LayoutManager + * @see View#onInitializeAccessibilityNodeInfo( + *android.view.accessibility.AccessibilityNodeInfo) + * @see #getRowCountForAccessibility(RecyclerView.Recycler, RecyclerView.State) + * @see #getColumnCountForAccessibility(RecyclerView.Recycler, RecyclerView.State) + * @see #isLayoutHierarchical(RecyclerView.Recycler, RecyclerView.State) + * @see #getSelectionModeForAccessibility(RecyclerView.Recycler, RecyclerView.State) + */ + public void onInitializeAccessibilityNodeInfo(Recycler recycler, State state, + AccessibilityNodeInfoCompat info) { + if (ViewCompat.canScrollVertically(mRecyclerView, -1) || + ViewCompat.canScrollHorizontally(mRecyclerView, -1)) { + info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD); + info.setScrollable(true); + } + if (ViewCompat.canScrollVertically(mRecyclerView, 1) || + ViewCompat.canScrollHorizontally(mRecyclerView, 1)) { + info.addAction(AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD); + info.setScrollable(true); + } + final AccessibilityNodeInfoCompat.CollectionInfoCompat collectionInfo + = AccessibilityNodeInfoCompat.CollectionInfoCompat + .obtain(getRowCountForAccessibility(recycler, state), + getColumnCountForAccessibility(recycler, state), + isLayoutHierarchical(recycler, state), + getSelectionModeForAccessibility(recycler, state)); + info.setCollectionInfo(collectionInfo); + } + + // called by accessibility delegate + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + onInitializeAccessibilityEvent(mRecyclerView.mRecycler, mRecyclerView.mState, event); + } + + /** + * Called by the accessibility delegate to initialize an accessibility event. + *

+ * Default implementation adds item count and scroll information to the event. + * + * @param recycler The Recycler that can be used to convert view positions into adapter + * positions + * @param state The current state of RecyclerView + * @param event The event instance to initialize + * @see View#onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent) + */ + public void onInitializeAccessibilityEvent(Recycler recycler, State state, + AccessibilityEvent event) { + final AccessibilityRecordCompat record = AccessibilityEventCompat + .asRecord(event); + if (mRecyclerView == null || record == null) { + return; + } + record.setScrollable(ViewCompat.canScrollVertically(mRecyclerView, 1) + || ViewCompat.canScrollVertically(mRecyclerView, -1) + || ViewCompat.canScrollHorizontally(mRecyclerView, -1) + || ViewCompat.canScrollHorizontally(mRecyclerView, 1)); + + if (mRecyclerView.mAdapter != null) { + record.setItemCount(mRecyclerView.mAdapter.getItemCount()); + } + } + + // called by accessibility delegate + void onInitializeAccessibilityNodeInfoForItem(View host, AccessibilityNodeInfoCompat info) { + final ViewHolder vh = getChildViewHolderInt(host); + // avoid trying to create accessibility node info for removed children + if (vh != null && !vh.isRemoved() && !mChildHelper.isHidden(vh.itemView)) { + onInitializeAccessibilityNodeInfoForItem(mRecyclerView.mRecycler, + mRecyclerView.mState, host, info); + } + } + + /** + * Called by the AccessibilityDelegate when the accessibility information for a specific + * item should be populated. + *

+ * Default implementation adds basic positioning information about the item. + * + * @param recycler The Recycler that can be used to convert view positions into adapter + * positions + * @param state The current state of RecyclerView + * @param host The child for which accessibility node info should be populated + * @param info The info to fill out about the item + * @see android.widget.AbsListView#onInitializeAccessibilityNodeInfoForItem(View, int, + * android.view.accessibility.AccessibilityNodeInfo) + */ + public void onInitializeAccessibilityNodeInfoForItem(Recycler recycler, State state, + View host, AccessibilityNodeInfoCompat info) { + int rowIndexGuess = canScrollVertically() ? getPosition(host) : 0; + int columnIndexGuess = canScrollHorizontally() ? getPosition(host) : 0; + final AccessibilityNodeInfoCompat.CollectionItemInfoCompat itemInfo + = AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(rowIndexGuess, 1, + columnIndexGuess, 1, false, false); + info.setCollectionItemInfo(itemInfo); + } + + /** + * A LayoutManager can call this method to force RecyclerView to run simple animations in + * the next layout pass, even if there is not any trigger to do so. (e.g. adapter data + * change). + *

+ * Note that, calling this method will not guarantee that RecyclerView will run animations + * at all. For example, if there is not any {@link ItemAnimator} set, RecyclerView will + * not run any animations but will still clear this flag after the layout is complete. + * + */ + public void requestSimpleAnimationsInNextLayout() { + mRequestedSimpleAnimations = true; + } + + /** + * Returns the selection mode for accessibility. Should be + * {@link AccessibilityNodeInfoCompat.CollectionInfoCompat#SELECTION_MODE_NONE}, + * {@link AccessibilityNodeInfoCompat.CollectionInfoCompat#SELECTION_MODE_SINGLE} or + * {@link AccessibilityNodeInfoCompat.CollectionInfoCompat#SELECTION_MODE_MULTIPLE}. + *

+ * Default implementation returns + * {@link AccessibilityNodeInfoCompat.CollectionInfoCompat#SELECTION_MODE_NONE}. + * + * @param recycler The Recycler that can be used to convert view positions into adapter + * positions + * @param state The current state of RecyclerView + * @return Selection mode for accessibility. Default implementation returns + * {@link AccessibilityNodeInfoCompat.CollectionInfoCompat#SELECTION_MODE_NONE}. + */ + public int getSelectionModeForAccessibility(Recycler recycler, State state) { + return AccessibilityNodeInfoCompat.CollectionInfoCompat.SELECTION_MODE_NONE; + } + + /** + * Returns the number of rows for accessibility. + *

+ * Default implementation returns the number of items in the adapter if LayoutManager + * supports vertical scrolling or 1 if LayoutManager does not support vertical + * scrolling. + * + * @param recycler The Recycler that can be used to convert view positions into adapter + * positions + * @param state The current state of RecyclerView + * @return The number of rows in LayoutManager for accessibility. + */ + public int getRowCountForAccessibility(Recycler recycler, State state) { + if (mRecyclerView == null || mRecyclerView.mAdapter == null) { + return 1; + } + return canScrollVertically() ? mRecyclerView.mAdapter.getItemCount() : 1; + } + + /** + * Returns the number of columns for accessibility. + *

+ * Default implementation returns the number of items in the adapter if LayoutManager + * supports horizontal scrolling or 1 if LayoutManager does not support horizontal + * scrolling. + * + * @param recycler The Recycler that can be used to convert view positions into adapter + * positions + * @param state The current state of RecyclerView + * @return The number of rows in LayoutManager for accessibility. + */ + public int getColumnCountForAccessibility(Recycler recycler, State state) { + if (mRecyclerView == null || mRecyclerView.mAdapter == null) { + return 1; + } + return canScrollHorizontally() ? mRecyclerView.mAdapter.getItemCount() : 1; + } + + /** + * Returns whether layout is hierarchical or not to be used for accessibility. + *

+ * Default implementation returns false. + * + * @param recycler The Recycler that can be used to convert view positions into adapter + * positions + * @param state The current state of RecyclerView + * @return True if layout is hierarchical. + */ + public boolean isLayoutHierarchical(Recycler recycler, State state) { + return false; + } + + // called by accessibility delegate + boolean performAccessibilityAction(int action, Bundle args) { + return performAccessibilityAction(mRecyclerView.mRecycler, mRecyclerView.mState, + action, args); + } + + /** + * Called by AccessibilityDelegate when an action is requested from the RecyclerView. + * + * @param recycler The Recycler that can be used to convert view positions into adapter + * positions + * @param state The current state of RecyclerView + * @param action The action to perform + * @param args Optional action arguments + * @see View#performAccessibilityAction(int, android.os.Bundle) + */ + public boolean performAccessibilityAction(Recycler recycler, State state, int action, + Bundle args) { + if (mRecyclerView == null) { + return false; + } + int vScroll = 0, hScroll = 0; + switch (action) { + case AccessibilityNodeInfoCompat.ACTION_SCROLL_BACKWARD: + if (ViewCompat.canScrollVertically(mRecyclerView, -1)) { + vScroll = -(getHeight() - getPaddingTop() - getPaddingBottom()); + } + if (ViewCompat.canScrollHorizontally(mRecyclerView, -1)) { + hScroll = -(getWidth() - getPaddingLeft() - getPaddingRight()); + } + break; + case AccessibilityNodeInfoCompat.ACTION_SCROLL_FORWARD: + if (ViewCompat.canScrollVertically(mRecyclerView, 1)) { + vScroll = getHeight() - getPaddingTop() - getPaddingBottom(); + } + if (ViewCompat.canScrollHorizontally(mRecyclerView, 1)) { + hScroll = getWidth() - getPaddingLeft() - getPaddingRight(); + } + break; + } + if (vScroll == 0 && hScroll == 0) { + return false; + } + mRecyclerView.scrollBy(hScroll, vScroll); + return true; + } + + // called by accessibility delegate + boolean performAccessibilityActionForItem(View view, int action, Bundle args) { + return performAccessibilityActionForItem(mRecyclerView.mRecycler, mRecyclerView.mState, + view, action, args); + } + + /** + * Called by AccessibilityDelegate when an accessibility action is requested on one of the + * children of LayoutManager. + *

+ * Default implementation does not do anything. + * + * @param recycler The Recycler that can be used to convert view positions into adapter + * positions + * @param state The current state of RecyclerView + * @param view The child view on which the action is performed + * @param action The action to perform + * @param args Optional action arguments + * @return true if action is handled + * @see View#performAccessibilityAction(int, android.os.Bundle) + */ + public boolean performAccessibilityActionForItem(Recycler recycler, State state, View view, + int action, Bundle args) { + return false; + } + + /** + * Parse the xml attributes to get the most common properties used by layout managers. + * + * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_android_orientation + * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_spanCount + * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_reverseLayout + * @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_stackFromEnd + * + * @return an object containing the properties as specified in the attrs. + */ + public static Properties getProperties(Context context, AttributeSet attrs, + int defStyleAttr, int defStyleRes) { + Properties properties = new Properties(); + properties.orientation = VERTICAL; + properties.spanCount = 1; + properties.reverseLayout = false; + properties.stackFromEnd = false; + return properties; + } + + void setExactMeasureSpecsFrom(RecyclerView recyclerView) { + setMeasureSpecs( + MeasureSpec.makeMeasureSpec(recyclerView.getWidth(), MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(recyclerView.getHeight(), MeasureSpec.EXACTLY) + ); + } + + /** + * Internal API to allow LayoutManagers to be measured twice. + *

+ * This is not public because LayoutManagers should be able to handle their layouts in one + * pass but it is very convenient to make existing LayoutManagers support wrapping content + * when both orientations are undefined. + *

+ * This API will be removed after default LayoutManagers properly implement wrap content in + * non-scroll orientation. + */ + boolean shouldMeasureTwice() { + return false; + } + + boolean hasFlexibleChildInBothOrientations() { + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getChildAt(i); + final ViewGroup.LayoutParams lp = child.getLayoutParams(); + if (lp.width < 0 && lp.height < 0) { + return true; + } + } + return false; + } + + /** + * Some general properties that a LayoutManager may want to use. + */ + public static class Properties { + /** @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_android_orientation */ + public int orientation; + /** @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_spanCount */ + public int spanCount; + /** @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_reverseLayout */ + public boolean reverseLayout; + /** @attr ref android.support.v7.recyclerview.R.styleable#RecyclerView_stackFromEnd */ + public boolean stackFromEnd; + } + } + + /** + * An ItemDecoration allows the application to add a special drawing and layout offset + * to specific item views from the adapter's data set. This can be useful for drawing dividers + * between items, highlights, visual grouping boundaries and more. + * + *

All ItemDecorations are drawn in the order they were added, before the item + * views (in {@link ItemDecoration#onDraw(Canvas, RecyclerView, RecyclerView.State) onDraw()} + * and after the items (in {@link ItemDecoration#onDrawOver(Canvas, RecyclerView, + * RecyclerView.State)}.

+ */ + public static abstract class ItemDecoration { + /** + * Draw any appropriate decorations into the Canvas supplied to the RecyclerView. + * Any content drawn by this method will be drawn before the item views are drawn, + * and will thus appear underneath the views. + * + * @param c Canvas to draw into + * @param parent RecyclerView this ItemDecoration is drawing into + * @param state The current state of RecyclerView + */ + public void onDraw(Canvas c, RecyclerView parent, State state) { + onDraw(c, parent); + } + + /** + * @deprecated + * Override {@link #onDraw(Canvas, RecyclerView, RecyclerView.State)} + */ + @Deprecated + public void onDraw(Canvas c, RecyclerView parent) { + } + + /** + * Draw any appropriate decorations into the Canvas supplied to the RecyclerView. + * Any content drawn by this method will be drawn after the item views are drawn + * and will thus appear over the views. + * + * @param c Canvas to draw into + * @param parent RecyclerView this ItemDecoration is drawing into + * @param state The current state of RecyclerView. + */ + public void onDrawOver(Canvas c, RecyclerView parent, State state) { + onDrawOver(c, parent); + } + + /** + * @deprecated + * Override {@link #onDrawOver(Canvas, RecyclerView, RecyclerView.State)} + */ + @Deprecated + public void onDrawOver(Canvas c, RecyclerView parent) { + } + + + /** + * @deprecated + * Use {@link #getItemOffsets(Rect, View, RecyclerView, State)} + */ + @Deprecated + public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { + outRect.set(0, 0, 0, 0); + } + + /** + * Retrieve any offsets for the given item. Each field of outRect specifies + * the number of pixels that the item view should be inset by, similar to padding or margin. + * The default implementation sets the bounds of outRect to 0 and returns. + * + *

+ * If this ItemDecoration does not affect the positioning of item views, it should set + * all four fields of outRect (left, top, right, bottom) to zero + * before returning. + * + *

+ * If you need to access Adapter for additional data, you can call + * {@link RecyclerView#getChildAdapterPosition(View)} to get the adapter position of the + * View. + * + * @param outRect Rect to receive the output. + * @param view The child view to decorate + * @param parent RecyclerView this ItemDecoration is decorating + * @param state The current state of RecyclerView. + */ + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) { + getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(), + parent); + } + } + + /** + * An OnItemTouchListener allows the application to intercept touch events in progress at the + * view hierarchy level of the RecyclerView before those touch events are considered for + * RecyclerView's own scrolling behavior. + * + *

This can be useful for applications that wish to implement various forms of gestural + * manipulation of item views within the RecyclerView. OnItemTouchListeners may intercept + * a touch interaction already in progress even if the RecyclerView is already handling that + * gesture stream itself for the purposes of scrolling.

+ * + * @see SimpleOnItemTouchListener + */ + public static interface OnItemTouchListener { + /** + * Silently observe and/or take over touch events sent to the RecyclerView + * before they are handled by either the RecyclerView itself or its child views. + * + *

The onInterceptTouchEvent methods of each attached OnItemTouchListener will be run + * in the order in which each listener was added, before any other touch processing + * by the RecyclerView itself or child views occurs.

+ * + * @param e MotionEvent describing the touch event. All coordinates are in + * the RecyclerView's coordinate system. + * @return true if this OnItemTouchListener wishes to begin intercepting touch events, false + * to continue with the current behavior and continue observing future events in + * the gesture. + */ + public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e); + + /** + * Process a touch event as part of a gesture that was claimed by returning true from + * a previous call to {@link #onInterceptTouchEvent}. + * + * @param e MotionEvent describing the touch event. All coordinates are in + * the RecyclerView's coordinate system. + */ + public void onTouchEvent(RecyclerView rv, MotionEvent e); + + /** + * Called when a child of RecyclerView does not want RecyclerView and its ancestors to + * intercept touch events with + * {@link ViewGroup#onInterceptTouchEvent(MotionEvent)}. + * + * @param disallowIntercept True if the child does not want the parent to + * intercept touch events. + * @see ViewParent#requestDisallowInterceptTouchEvent(boolean) + */ + public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept); + } + + /** + * An implementation of {@link RecyclerView.OnItemTouchListener} that has empty method bodies and + * default return values. + *

+ * You may prefer to extend this class if you don't need to override all methods. Another + * benefit of using this class is future compatibility. As the interface may change, we'll + * always provide a default implementation on this class so that your code won't break when + * you update to a new version of the support library. + */ + public static class SimpleOnItemTouchListener implements RecyclerView.OnItemTouchListener { + @Override + public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { + return false; + } + + @Override + public void onTouchEvent(RecyclerView rv, MotionEvent e) { + } + + @Override + public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { + } + } + + + /** + * An OnScrollListener can be added to a RecyclerView to receive messages when a scrolling event + * has occurred on that RecyclerView. + *

+ * @see RecyclerView#addOnScrollListener(OnScrollListener) + * @see RecyclerView#clearOnChildAttachStateChangeListeners() + * + */ + public abstract static class OnScrollListener { + /** + * Callback method to be invoked when RecyclerView's scroll state changes. + * + * @param recyclerView The RecyclerView whose scroll state has changed. + * @param newState The updated scroll state. One of {@link #SCROLL_STATE_IDLE}, + * {@link #SCROLL_STATE_DRAGGING} or {@link #SCROLL_STATE_SETTLING}. + */ + public void onScrollStateChanged(RecyclerView recyclerView, int newState){} + + /** + * Callback method to be invoked when the RecyclerView has been scrolled. This will be + * called after the scroll has completed. + *

+ * This callback will also be called if visible item range changes after a layout + * calculation. In that case, dx and dy will be 0. + * + * @param recyclerView The RecyclerView which scrolled. + * @param dx The amount of horizontal scroll. + * @param dy The amount of vertical scroll. + */ + public void onScrolled(RecyclerView recyclerView, int dx, int dy){} + } + + /** + * A RecyclerListener can be set on a RecyclerView to receive messages whenever + * a view is recycled. + * + * @see RecyclerView#setRecyclerListener(RecyclerListener) + */ + public interface RecyclerListener { + + /** + * This method is called whenever the view in the ViewHolder is recycled. + * + * RecyclerView calls this method right before clearing ViewHolder's internal data and + * sending it to RecycledViewPool. This way, if ViewHolder was holding valid information + * before being recycled, you can call {@link ViewHolder#getAdapterPosition()} to get + * its adapter position. + * + * @param holder The ViewHolder containing the view that was recycled + */ + public void onViewRecycled(ViewHolder holder); + } + + /** + * A Listener interface that can be attached to a RecylcerView to get notified + * whenever a ViewHolder is attached to or detached from RecyclerView. + */ + public interface OnChildAttachStateChangeListener { + + /** + * Called when a view is attached to the RecyclerView. + * + * @param view The View which is attached to the RecyclerView + */ + public void onChildViewAttachedToWindow(View view); + + /** + * Called when a view is detached from RecyclerView. + * + * @param view The View which is being detached from the RecyclerView + */ + public void onChildViewDetachedFromWindow(View view); + } + + /** + * A ViewHolder describes an item view and metadata about its place within the RecyclerView. + * + *

{@link Adapter} implementations should subclass ViewHolder and add fields for caching + * potentially expensive {@link View#findViewById(int)} results.

+ * + *

While {@link LayoutParams} belong to the {@link LayoutManager}, + * {@link ViewHolder ViewHolders} belong to the adapter. Adapters should feel free to use + * their own custom ViewHolder implementations to store data that makes binding view contents + * easier. Implementations should assume that individual item views will hold strong references + * to ViewHolder objects and that RecyclerView instances may hold + * strong references to extra off-screen item views for caching purposes

+ */ + public static abstract class ViewHolder { + public final View itemView; + int mPosition = NO_POSITION; + int mOldPosition = NO_POSITION; + long mItemId = NO_ID; + int mItemViewType = INVALID_TYPE; + int mPreLayoutPosition = NO_POSITION; + + // The item that this holder is shadowing during an item change event/animation + ViewHolder mShadowedHolder = null; + // The item that is shadowing this holder during an item change event/animation + ViewHolder mShadowingHolder = null; + + /** + * This ViewHolder has been bound to a position; mPosition, mItemId and mItemViewType + * are all valid. + */ + static final int FLAG_BOUND = 1 << 0; + + /** + * The data this ViewHolder's view reflects is stale and needs to be rebound + * by the adapter. mPosition and mItemId are consistent. + */ + static final int FLAG_UPDATE = 1 << 1; + + /** + * This ViewHolder's data is invalid. The identity implied by mPosition and mItemId + * are not to be trusted and may no longer match the item view type. + * This ViewHolder must be fully rebound to different data. + */ + static final int FLAG_INVALID = 1 << 2; + + /** + * This ViewHolder points at data that represents an item previously removed from the + * data set. Its view may still be used for things like outgoing animations. + */ + static final int FLAG_REMOVED = 1 << 3; + + /** + * This ViewHolder should not be recycled. This flag is set via setIsRecyclable() + * and is intended to keep views around during animations. + */ + static final int FLAG_NOT_RECYCLABLE = 1 << 4; + + /** + * This ViewHolder is returned from scrap which means we are expecting an addView call + * for this itemView. When returned from scrap, ViewHolder stays in the scrap list until + * the end of the layout pass and then recycled by RecyclerView if it is not added back to + * the RecyclerView. + */ + static final int FLAG_RETURNED_FROM_SCRAP = 1 << 5; + + /** + * This ViewHolder is fully managed by the LayoutManager. We do not scrap, recycle or remove + * it unless LayoutManager is replaced. + * It is still fully visible to the LayoutManager. + */ + static final int FLAG_IGNORE = 1 << 7; + + /** + * When the View is detached form the parent, we set this flag so that we can take correct + * action when we need to remove it or add it back. + */ + static final int FLAG_TMP_DETACHED = 1 << 8; + + /** + * Set when we can no longer determine the adapter position of this ViewHolder until it is + * rebound to a new position. It is different than FLAG_INVALID because FLAG_INVALID is + * set even when the type does not match. Also, FLAG_ADAPTER_POSITION_UNKNOWN is set as soon + * as adapter notification arrives vs FLAG_INVALID is set lazily before layout is + * re-calculated. + */ + static final int FLAG_ADAPTER_POSITION_UNKNOWN = 1 << 9; + + /** + * Set when a addChangePayload(null) is called + */ + static final int FLAG_ADAPTER_FULLUPDATE = 1 << 10; + + /** + * Used by ItemAnimator when a ViewHolder's position changes + */ + static final int FLAG_MOVED = 1 << 11; + + /** + * Used by ItemAnimator when a ViewHolder appears in pre-layout + */ + static final int FLAG_APPEARED_IN_PRE_LAYOUT = 1 << 12; + + /** + * Used when a ViewHolder starts the layout pass as a hidden ViewHolder but is re-used from + * hidden list (as if it was scrap) without being recycled in between. + * + * When a ViewHolder is hidden, there are 2 paths it can be re-used: + * a) Animation ends, view is recycled and used from the recycle pool. + * b) LayoutManager asks for the View for that position while the ViewHolder is hidden. + * + * This flag is used to represent "case b" where the ViewHolder is reused without being + * recycled (thus "bounced" from the hidden list). This state requires special handling + * because the ViewHolder must be added to pre layout maps for animations as if it was + * already there. + */ + static final int FLAG_BOUNCED_FROM_HIDDEN_LIST = 1 << 13; + + private int mFlags; + + private static final List FULLUPDATE_PAYLOADS = Collections.EMPTY_LIST; + + List mPayloads = null; + List mUnmodifiedPayloads = null; + + private int mIsRecyclableCount = 0; + + // If non-null, view is currently considered scrap and may be reused for other data by the + // scrap container. + private Recycler mScrapContainer = null; + // Keeps whether this ViewHolder lives in Change scrap or Attached scrap + private boolean mInChangeScrap = false; + + // Saves isImportantForAccessibility value for the view item while it's in hidden state and + // marked as unimportant for accessibility. + private int mWasImportantForAccessibilityBeforeHidden = + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO; + + /** + * Is set when VH is bound from the adapter and cleaned right before it is sent to + * {@link RecycledViewPool}. + */ + RecyclerView mOwnerRecyclerView; + + public ViewHolder(View itemView) { + if (itemView == null) { + throw new IllegalArgumentException("itemView may not be null"); + } + this.itemView = itemView; + } + + void flagRemovedAndOffsetPosition(int mNewPosition, int offset, boolean applyToPreLayout) { + addFlags(ViewHolder.FLAG_REMOVED); + offsetPosition(offset, applyToPreLayout); + mPosition = mNewPosition; + } + + void offsetPosition(int offset, boolean applyToPreLayout) { + if (mOldPosition == NO_POSITION) { + mOldPosition = mPosition; + } + if (mPreLayoutPosition == NO_POSITION) { + mPreLayoutPosition = mPosition; + } + if (applyToPreLayout) { + mPreLayoutPosition += offset; + } + mPosition += offset; + if (itemView.getLayoutParams() != null) { + ((LayoutParams) itemView.getLayoutParams()).mInsetsDirty = true; + } + } + + void clearOldPosition() { + mOldPosition = NO_POSITION; + mPreLayoutPosition = NO_POSITION; + } + + void saveOldPosition() { + if (mOldPosition == NO_POSITION) { + mOldPosition = mPosition; + } + } + + boolean shouldIgnore() { + return (mFlags & FLAG_IGNORE) != 0; + } + + /** + * @deprecated This method is deprecated because its meaning is ambiguous due to the async + * handling of adapter updates. Please use {@link #getLayoutPosition()} or + * {@link #getAdapterPosition()} depending on your use case. + * + * @see #getLayoutPosition() + * @see #getAdapterPosition() + */ + @Deprecated + public final int getPosition() { + return mPreLayoutPosition == NO_POSITION ? mPosition : mPreLayoutPosition; + } + + /** + * Returns the position of the ViewHolder in terms of the latest layout pass. + *

+ * This position is mostly used by RecyclerView components to be consistent while + * RecyclerView lazily processes adapter updates. + *

+ * For performance and animation reasons, RecyclerView batches all adapter updates until the + * next layout pass. This may cause mismatches between the Adapter position of the item and + * the position it had in the latest layout calculations. + *

+ * LayoutManagers should always call this method while doing calculations based on item + * positions. All methods in {@link RecyclerView.LayoutManager}, {@link RecyclerView.State}, + * {@link RecyclerView.Recycler} that receive a position expect it to be the layout position + * of the item. + *

+ * If LayoutManager needs to call an external method that requires the adapter position of + * the item, it can use {@link #getAdapterPosition()} or + * {@link RecyclerView.Recycler#convertPreLayoutPositionToPostLayout(int)}. + * + * @return Returns the adapter position of the ViewHolder in the latest layout pass. + * @see #getAdapterPosition() + */ + public final int getLayoutPosition() { + return mPreLayoutPosition == NO_POSITION ? mPosition : mPreLayoutPosition; + } + + /** + * Returns the Adapter position of the item represented by this ViewHolder. + *

+ * Note that this might be different than the {@link #getLayoutPosition()} if there are + * pending adapter updates but a new layout pass has not happened yet. + *

+ * RecyclerView does not handle any adapter updates until the next layout traversal. This + * may create temporary inconsistencies between what user sees on the screen and what + * adapter contents have. This inconsistency is not important since it will be less than + * 16ms but it might be a problem if you want to use ViewHolder position to access the + * adapter. Sometimes, you may need to get the exact adapter position to do + * some actions in response to user events. In that case, you should use this method which + * will calculate the Adapter position of the ViewHolder. + *

+ * Note that if you've called {@link RecyclerView.Adapter#notifyDataSetChanged()}, until the + * next layout pass, the return value of this method will be {@link #NO_POSITION}. + * + * @return The adapter position of the item if it still exists in the adapter. + * {@link RecyclerView#NO_POSITION} if item has been removed from the adapter, + * {@link RecyclerView.Adapter#notifyDataSetChanged()} has been called after the last + * layout pass or the ViewHolder has already been recycled. + */ + public final int getAdapterPosition() { + if (mOwnerRecyclerView == null) { + return NO_POSITION; + } + return mOwnerRecyclerView.getAdapterPositionFor(this); + } + + /** + * When LayoutManager supports animations, RecyclerView tracks 3 positions for ViewHolders + * to perform animations. + *

+ * If a ViewHolder was laid out in the previous onLayout call, old position will keep its + * adapter index in the previous layout. + * + * @return The previous adapter index of the Item represented by this ViewHolder or + * {@link #NO_POSITION} if old position does not exists or cleared (pre-layout is + * complete). + */ + public final int getOldPosition() { + return mOldPosition; + } + + /** + * Returns The itemId represented by this ViewHolder. + * + * @return The the item's id if adapter has stable ids, {@link RecyclerView#NO_ID} + * otherwise + */ + public final long getItemId() { + return mItemId; + } + + /** + * @return The view type of this ViewHolder. + */ + public final int getItemViewType() { + return mItemViewType; + } + + boolean isScrap() { + return mScrapContainer != null; + } + + void unScrap() { + mScrapContainer.unscrapView(this); + } + + boolean wasReturnedFromScrap() { + return (mFlags & FLAG_RETURNED_FROM_SCRAP) != 0; + } + + void clearReturnedFromScrapFlag() { + mFlags = mFlags & ~FLAG_RETURNED_FROM_SCRAP; + } + + void clearTmpDetachFlag() { + mFlags = mFlags & ~FLAG_TMP_DETACHED; + } + + void stopIgnoring() { + mFlags = mFlags & ~FLAG_IGNORE; + } + + void setScrapContainer(Recycler recycler, boolean isChangeScrap) { + mScrapContainer = recycler; + mInChangeScrap = isChangeScrap; + } + + boolean isInvalid() { + return (mFlags & FLAG_INVALID) != 0; + } + + boolean needsUpdate() { + return (mFlags & FLAG_UPDATE) != 0; + } + + boolean isBound() { + return (mFlags & FLAG_BOUND) != 0; + } + + boolean isRemoved() { + return (mFlags & FLAG_REMOVED) != 0; + } + + boolean hasAnyOfTheFlags(int flags) { + return (mFlags & flags) != 0; + } + + boolean isTmpDetached() { + return (mFlags & FLAG_TMP_DETACHED) != 0; + } + + boolean isAdapterPositionUnknown() { + return (mFlags & FLAG_ADAPTER_POSITION_UNKNOWN) != 0 || isInvalid(); + } + + void setFlags(int flags, int mask) { + mFlags = (mFlags & ~mask) | (flags & mask); + } + + void addFlags(int flags) { + mFlags |= flags; + } + + void addChangePayload(Object payload) { + if (payload == null) { + addFlags(FLAG_ADAPTER_FULLUPDATE); + } else if ((mFlags & FLAG_ADAPTER_FULLUPDATE) == 0) { + createPayloadsIfNeeded(); + mPayloads.add(payload); + } + } + + private void createPayloadsIfNeeded() { + if (mPayloads == null) { + mPayloads = new ArrayList(); + mUnmodifiedPayloads = Collections.unmodifiableList(mPayloads); + } + } + + void clearPayload() { + if (mPayloads != null) { + mPayloads.clear(); + } + mFlags = mFlags & ~FLAG_ADAPTER_FULLUPDATE; + } + + List getUnmodifiedPayloads() { + if ((mFlags & FLAG_ADAPTER_FULLUPDATE) == 0) { + if (mPayloads == null || mPayloads.size() == 0) { + // Initial state, no update being called. + return FULLUPDATE_PAYLOADS; + } + // there are none-null payloads + return mUnmodifiedPayloads; + } else { + // a full update has been called. + return FULLUPDATE_PAYLOADS; + } + } + + void resetInternal() { + mFlags = 0; + mPosition = NO_POSITION; + mOldPosition = NO_POSITION; + mItemId = NO_ID; + mPreLayoutPosition = NO_POSITION; + mIsRecyclableCount = 0; + mShadowedHolder = null; + mShadowingHolder = null; + clearPayload(); + mWasImportantForAccessibilityBeforeHidden = ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO; + } + + /** + * Called when the child view enters the hidden state + */ + private void onEnteredHiddenState() { + // While the view item is in hidden state, make it invisible for the accessibility. + mWasImportantForAccessibilityBeforeHidden = + ViewCompat.getImportantForAccessibility(itemView); + ViewCompat.setImportantForAccessibility(itemView, + ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + } + + /** + * Called when the child view leaves the hidden state + */ + private void onLeftHiddenState() { + ViewCompat.setImportantForAccessibility( + itemView, mWasImportantForAccessibilityBeforeHidden); + mWasImportantForAccessibilityBeforeHidden = ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("ViewHolder{" + + Integer.toHexString(hashCode()) + " position=" + mPosition + " id=" + mItemId + + ", oldPos=" + mOldPosition + ", pLpos:" + mPreLayoutPosition); + if (isScrap()) { + sb.append(" scrap ") + .append(mInChangeScrap ? "[changeScrap]" : "[attachedScrap]"); + } + if (isInvalid()) sb.append(" invalid"); + if (!isBound()) sb.append(" unbound"); + if (needsUpdate()) sb.append(" update"); + if (isRemoved()) sb.append(" removed"); + if (shouldIgnore()) sb.append(" ignored"); + if (isTmpDetached()) sb.append(" tmpDetached"); + if (!isRecyclable()) sb.append(" not recyclable(" + mIsRecyclableCount + ")"); + if (isAdapterPositionUnknown()) sb.append(" undefined adapter position"); + + if (itemView.getParent() == null) sb.append(" no parent"); + sb.append("}"); + return sb.toString(); + } + + /** + * Informs the recycler whether this item can be recycled. Views which are not + * recyclable will not be reused for other items until setIsRecyclable() is + * later set to true. Calls to setIsRecyclable() should always be paired (one + * call to setIsRecyclabe(false) should always be matched with a later call to + * setIsRecyclable(true)). Pairs of calls may be nested, as the state is internally + * reference-counted. + * + * @param recyclable Whether this item is available to be recycled. Default value + * is true. + */ + public final void setIsRecyclable(boolean recyclable) { + mIsRecyclableCount = recyclable ? mIsRecyclableCount - 1 : mIsRecyclableCount + 1; + if (mIsRecyclableCount < 0) { + mIsRecyclableCount = 0; + if (DEBUG) { + throw new RuntimeException("isRecyclable decremented below 0: " + + "unmatched pair of setIsRecyable() calls for " + this); + } + Log.e(VIEW_LOG_TAG, "isRecyclable decremented below 0: " + + "unmatched pair of setIsRecyable() calls for " + this); + } else if (!recyclable && mIsRecyclableCount == 1) { + mFlags |= FLAG_NOT_RECYCLABLE; + } else if (recyclable && mIsRecyclableCount == 0) { + mFlags &= ~FLAG_NOT_RECYCLABLE; + } + if (DEBUG) { + Log.d(TAG, "setIsRecyclable val:" + recyclable + ":" + this); + } + } + + /** + * @see {@link #setIsRecyclable(boolean)} + * + * @return true if this item is available to be recycled, false otherwise. + */ + public final boolean isRecyclable() { + return (mFlags & FLAG_NOT_RECYCLABLE) == 0 && + !ViewCompat.hasTransientState(itemView); + } + + /** + * Returns whether we have animations referring to this view holder or not. + * This is similar to isRecyclable flag but does not check transient state. + */ + private boolean shouldBeKeptAsChild() { + return (mFlags & FLAG_NOT_RECYCLABLE) != 0; + } + + /** + * @return True if ViewHolder is not refenrenced by RecyclerView animations but has + * transient state which will prevent it from being recycled. + */ + private boolean doesTransientStatePreventRecycling() { + return (mFlags & FLAG_NOT_RECYCLABLE) == 0 && ViewCompat.hasTransientState(itemView); + } + + boolean isUpdated() { + return (mFlags & FLAG_UPDATE) != 0; + } + } + + private int getAdapterPositionFor(ViewHolder viewHolder) { + if (viewHolder.hasAnyOfTheFlags( ViewHolder.FLAG_INVALID | + ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN) + || !viewHolder.isBound()) { + return RecyclerView.NO_POSITION; + } + return mAdapterHelper.applyPendingUpdatesToPosition(viewHolder.mPosition); + } + + // NestedScrollingChild + + @Override + public void setNestedScrollingEnabled(boolean enabled) { + getScrollingChildHelper().setNestedScrollingEnabled(enabled); + } + + @Override + public boolean isNestedScrollingEnabled() { + return getScrollingChildHelper().isNestedScrollingEnabled(); + } + + @Override + public boolean startNestedScroll(int axes) { + return getScrollingChildHelper().startNestedScroll(axes); + } + + @Override + public void stopNestedScroll() { + getScrollingChildHelper().stopNestedScroll(); + } + + @Override + public boolean hasNestedScrollingParent() { + return getScrollingChildHelper().hasNestedScrollingParent(); + } + + @Override + public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, + int dyUnconsumed, int[] offsetInWindow) { + return getScrollingChildHelper().dispatchNestedScroll(dxConsumed, dyConsumed, + dxUnconsumed, dyUnconsumed, offsetInWindow); + } + + @Override + public boolean dispatchNestedPreScroll(int dx, int dy, int[] consumed, int[] offsetInWindow) { + return getScrollingChildHelper().dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow); + } + + @Override + public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { + return getScrollingChildHelper().dispatchNestedFling(velocityX, velocityY, consumed); + } + + @Override + public boolean dispatchNestedPreFling(float velocityX, float velocityY) { + return getScrollingChildHelper().dispatchNestedPreFling(velocityX, velocityY); + } + + /** + * {@link android.view.ViewGroup.MarginLayoutParams LayoutParams} subclass for children of + * {@link RecyclerView}. Custom {@link LayoutManager layout managers} are encouraged + * to create their own subclass of this LayoutParams class + * to store any additional required per-child view metadata about the layout. + */ + public static class LayoutParams extends android.view.ViewGroup.MarginLayoutParams { + ViewHolder mViewHolder; + final Rect mDecorInsets = new Rect(); + boolean mInsetsDirty = true; + // Flag is set to true if the view is bound while it is detached from RV. + // In this case, we need to manually call invalidate after view is added to guarantee that + // invalidation is populated through the View hierarchy + boolean mPendingInvalidate = false; + + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + } + + public LayoutParams(int width, int height) { + super(width, height); + } + + public LayoutParams(MarginLayoutParams source) { + super(source); + } + + public LayoutParams(ViewGroup.LayoutParams source) { + super(source); + } + + public LayoutParams(LayoutParams source) { + super((ViewGroup.LayoutParams) source); + } + + /** + * Returns true if the view this LayoutParams is attached to needs to have its content + * updated from the corresponding adapter. + * + * @return true if the view should have its content updated + */ + public boolean viewNeedsUpdate() { + return mViewHolder.needsUpdate(); + } + + /** + * Returns true if the view this LayoutParams is attached to is now representing + * potentially invalid data. A LayoutManager should scrap/recycle it. + * + * @return true if the view is invalid + */ + public boolean isViewInvalid() { + return mViewHolder.isInvalid(); + } + + /** + * Returns true if the adapter data item corresponding to the view this LayoutParams + * is attached to has been removed from the data set. A LayoutManager may choose to + * treat it differently in order to animate its outgoing or disappearing state. + * + * @return true if the item the view corresponds to was removed from the data set + */ + public boolean isItemRemoved() { + return mViewHolder.isRemoved(); + } + + /** + * Returns true if the adapter data item corresponding to the view this LayoutParams + * is attached to has been changed in the data set. A LayoutManager may choose to + * treat it differently in order to animate its changing state. + * + * @return true if the item the view corresponds to was changed in the data set + */ + public boolean isItemChanged() { + return mViewHolder.isUpdated(); + } + + /** + * @deprecated use {@link #getViewLayoutPosition()} or {@link #getViewAdapterPosition()} + */ + public int getViewPosition() { + return mViewHolder.getPosition(); + } + + /** + * Returns the adapter position that the view this LayoutParams is attached to corresponds + * to as of latest layout calculation. + * + * @return the adapter position this view as of latest layout pass + */ + public int getViewLayoutPosition() { + return mViewHolder.getLayoutPosition(); + } + + /** + * Returns the up-to-date adapter position that the view this LayoutParams is attached to + * corresponds to. + * + * @return the up-to-date adapter position this view. It may return + * {@link RecyclerView#NO_POSITION} if item represented by this View has been removed or + * its up-to-date position cannot be calculated. + */ + public int getViewAdapterPosition() { + return mViewHolder.getAdapterPosition(); + } + } + + /** + * Observer base class for watching changes to an {@link Adapter}. + * See {@link Adapter#registerAdapterDataObserver(AdapterDataObserver)}. + */ + public static abstract class AdapterDataObserver { + public void onChanged() { + // Do nothing + } + + public void onItemRangeChanged(int positionStart, int itemCount) { + // do nothing + } + + public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { + // fallback to onItemRangeChanged(positionStart, itemCount) if app + // does not override this method. + onItemRangeChanged(positionStart, itemCount); + } + + public void onItemRangeInserted(int positionStart, int itemCount) { + // do nothing + } + + public void onItemRangeRemoved(int positionStart, int itemCount) { + // do nothing + } + + public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { + // do nothing + } + } + + /** + *

Base class for smooth scrolling. Handles basic tracking of the target view position and + * provides methods to trigger a programmatic scroll.

+ * + * @see LinearSmoothScroller + */ + public static abstract class SmoothScroller { + + private int mTargetPosition = RecyclerView.NO_POSITION; + + private RecyclerView mRecyclerView; + + private LayoutManager mLayoutManager; + + private boolean mPendingInitialRun; + + private boolean mRunning; + + private View mTargetView; + + private final Action mRecyclingAction; + + public SmoothScroller() { + mRecyclingAction = new Action(0, 0); + } + + /** + * Starts a smooth scroll for the given target position. + *

In each animation step, {@link RecyclerView} will check + * for the target view and call either + * {@link #onTargetFound(android.view.View, RecyclerView.State, SmoothScroller.Action)} or + * {@link #onSeekTargetStep(int, int, RecyclerView.State, SmoothScroller.Action)} until + * SmoothScroller is stopped.

+ * + *

Note that if RecyclerView finds the target view, it will automatically stop the + * SmoothScroller. This does not mean that scroll will stop, it only means it will + * stop calling SmoothScroller in each animation step.

+ */ + void start(RecyclerView recyclerView, LayoutManager layoutManager) { + mRecyclerView = recyclerView; + mLayoutManager = layoutManager; + if (mTargetPosition == RecyclerView.NO_POSITION) { + throw new IllegalArgumentException("Invalid target position"); + } + mRecyclerView.mState.mTargetPosition = mTargetPosition; + mRunning = true; + mPendingInitialRun = true; + mTargetView = findViewByPosition(getTargetPosition()); + onStart(); + mRecyclerView.mViewFlinger.postOnAnimation(); + } + + public void setTargetPosition(int targetPosition) { + mTargetPosition = targetPosition; + } + + /** + * @return The LayoutManager to which this SmoothScroller is attached. Will return + * null after the SmoothScroller is stopped. + */ + @Nullable + public LayoutManager getLayoutManager() { + return mLayoutManager; + } + + /** + * Stops running the SmoothScroller in each animation callback. Note that this does not + * cancel any existing {@link Action} updated by + * {@link #onTargetFound(android.view.View, RecyclerView.State, SmoothScroller.Action)} or + * {@link #onSeekTargetStep(int, int, RecyclerView.State, SmoothScroller.Action)}. + */ + final protected void stop() { + if (!mRunning) { + return; + } + onStop(); + mRecyclerView.mState.mTargetPosition = RecyclerView.NO_POSITION; + mTargetView = null; + mTargetPosition = RecyclerView.NO_POSITION; + mPendingInitialRun = false; + mRunning = false; + // trigger a cleanup + mLayoutManager.onSmoothScrollerStopped(this); + // clear references to avoid any potential leak by a custom smooth scroller + mLayoutManager = null; + mRecyclerView = null; + } + + /** + * Returns true if SmoothScroller has been started but has not received the first + * animation + * callback yet. + * + * @return True if this SmoothScroller is waiting to start + */ + public boolean isPendingInitialRun() { + return mPendingInitialRun; + } + + + /** + * @return True if SmoothScroller is currently active + */ + public boolean isRunning() { + return mRunning; + } + + /** + * Returns the adapter position of the target item + * + * @return Adapter position of the target item or + * {@link RecyclerView#NO_POSITION} if no target view is set. + */ + public int getTargetPosition() { + return mTargetPosition; + } + + private void onAnimation(int dx, int dy) { + final RecyclerView recyclerView = mRecyclerView; + if (!mRunning || mTargetPosition == RecyclerView.NO_POSITION || recyclerView == null) { + stop(); + } + mPendingInitialRun = false; + if (mTargetView != null) { + // verify target position + if (getChildPosition(mTargetView) == mTargetPosition) { + onTargetFound(mTargetView, recyclerView.mState, mRecyclingAction); + mRecyclingAction.runIfNecessary(recyclerView); + stop(); + } else { + Log.e(TAG, "Passed over target position while smooth scrolling."); + mTargetView = null; + } + } + if (mRunning) { + onSeekTargetStep(dx, dy, recyclerView.mState, mRecyclingAction); + boolean hadJumpTarget = mRecyclingAction.hasJumpTarget(); + mRecyclingAction.runIfNecessary(recyclerView); + if (hadJumpTarget) { + // It is not stopped so needs to be restarted + if (mRunning) { + mPendingInitialRun = true; + recyclerView.mViewFlinger.postOnAnimation(); + } else { + stop(); // done + } + } + } + } + + /** + * @see RecyclerView#getChildLayoutPosition(android.view.View) + */ + public int getChildPosition(View view) { + return mRecyclerView.getChildLayoutPosition(view); + } + + /** + * @see RecyclerView.LayoutManager#getChildCount() + */ + public int getChildCount() { + return mRecyclerView.mLayout.getChildCount(); + } + + /** + * @see RecyclerView.LayoutManager#findViewByPosition(int) + */ + public View findViewByPosition(int position) { + return mRecyclerView.mLayout.findViewByPosition(position); + } + + /** + * @see RecyclerView#scrollToPosition(int) + * @deprecated Use {@link Action#jumpTo(int)}. + */ + @Deprecated + public void instantScrollToPosition(int position) { + mRecyclerView.scrollToPosition(position); + } + + protected void onChildAttachedToWindow(View child) { + if (getChildPosition(child) == getTargetPosition()) { + mTargetView = child; + if (DEBUG) { + Log.d(TAG, "smooth scroll target view has been attached"); + } + } + } + + /** + * Normalizes the vector. + * @param scrollVector The vector that points to the target scroll position + */ + protected void normalize(PointF scrollVector) { + final double magnitute = Math.sqrt(scrollVector.x * scrollVector.x + scrollVector.y * + scrollVector.y); + scrollVector.x /= magnitute; + scrollVector.y /= magnitute; + } + + /** + * Called when smooth scroll is started. This might be a good time to do setup. + */ + abstract protected void onStart(); + + /** + * Called when smooth scroller is stopped. This is a good place to cleanup your state etc. + * @see #stop() + */ + abstract protected void onStop(); + + /** + *

RecyclerView will call this method each time it scrolls until it can find the target + * position in the layout.

+ *

SmoothScroller should check dx, dy and if scroll should be changed, update the + * provided {@link Action} to define the next scroll.

+ * + * @param dx Last scroll amount horizontally + * @param dy Last scroll amount verticaully + * @param state Transient state of RecyclerView + * @param action If you want to trigger a new smooth scroll and cancel the previous one, + * update this object. + */ + abstract protected void onSeekTargetStep(int dx, int dy, State state, Action action); + + /** + * Called when the target position is laid out. This is the last callback SmoothScroller + * will receive and it should update the provided {@link Action} to define the scroll + * details towards the target view. + * @param targetView The view element which render the target position. + * @param state Transient state of RecyclerView + * @param action Action instance that you should update to define final scroll action + * towards the targetView + */ + abstract protected void onTargetFound(View targetView, State state, Action action); + + /** + * Holds information about a smooth scroll request by a {@link SmoothScroller}. + */ + public static class Action { + + public static final int UNDEFINED_DURATION = Integer.MIN_VALUE; + + private int mDx; + + private int mDy; + + private int mDuration; + + private int mJumpToPosition = NO_POSITION; + + private Interpolator mInterpolator; + + private boolean changed = false; + + // we track this variable to inform custom implementer if they are updating the action + // in every animation callback + private int consecutiveUpdates = 0; + + /** + * @param dx Pixels to scroll horizontally + * @param dy Pixels to scroll vertically + */ + public Action(int dx, int dy) { + this(dx, dy, UNDEFINED_DURATION, null); + } + + /** + * @param dx Pixels to scroll horizontally + * @param dy Pixels to scroll vertically + * @param duration Duration of the animation in milliseconds + */ + public Action(int dx, int dy, int duration) { + this(dx, dy, duration, null); + } + + /** + * @param dx Pixels to scroll horizontally + * @param dy Pixels to scroll vertically + * @param duration Duration of the animation in milliseconds + * @param interpolator Interpolator to be used when calculating scroll position in each + * animation step + */ + public Action(int dx, int dy, int duration, Interpolator interpolator) { + mDx = dx; + mDy = dy; + mDuration = duration; + mInterpolator = interpolator; + } + + /** + * Instead of specifying pixels to scroll, use the target position to jump using + * {@link RecyclerView#scrollToPosition(int)}. + *

+ * You may prefer using this method if scroll target is really far away and you prefer + * to jump to a location and smooth scroll afterwards. + *

+ * Note that calling this method takes priority over other update methods such as + * {@link #update(int, int, int, Interpolator)}, {@link #setX(float)}, + * {@link #setY(float)} and #{@link #setInterpolator(Interpolator)}. If you call + * {@link #jumpTo(int)}, the other changes will not be considered for this animation + * frame. + * + * @param targetPosition The target item position to scroll to using instant scrolling. + */ + public void jumpTo(int targetPosition) { + mJumpToPosition = targetPosition; + } + + boolean hasJumpTarget() { + return mJumpToPosition >= 0; + } + + private void runIfNecessary(RecyclerView recyclerView) { + if (mJumpToPosition >= 0) { + final int position = mJumpToPosition; + mJumpToPosition = NO_POSITION; + recyclerView.jumpToPositionForSmoothScroller(position); + changed = false; + return; + } + if (changed) { + validate(); + if (mInterpolator == null) { + if (mDuration == UNDEFINED_DURATION) { + recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy); + } else { + recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy, mDuration); + } + } else { + recyclerView.mViewFlinger.smoothScrollBy(mDx, mDy, mDuration, mInterpolator); + } + consecutiveUpdates ++; + if (consecutiveUpdates > 10) { + // A new action is being set in every animation step. This looks like a bad + // implementation. Inform developer. + Log.e(TAG, "Smooth Scroll action is being updated too frequently. Make sure" + + " you are not changing it unless necessary"); + } + changed = false; + } else { + consecutiveUpdates = 0; + } + } + + private void validate() { + if (mInterpolator != null && mDuration < 1) { + throw new IllegalStateException("If you provide an interpolator, you must" + + " set a positive duration"); + } else if (mDuration < 1) { + throw new IllegalStateException("Scroll duration must be a positive number"); + } + } + + public int getDx() { + return mDx; + } + + public void setDx(int dx) { + changed = true; + mDx = dx; + } + + public int getDy() { + return mDy; + } + + public void setDy(int dy) { + changed = true; + mDy = dy; + } + + public int getDuration() { + return mDuration; + } + + public void setDuration(int duration) { + changed = true; + mDuration = duration; + } + + public Interpolator getInterpolator() { + return mInterpolator; + } + + /** + * Sets the interpolator to calculate scroll steps + * @param interpolator The interpolator to use. If you specify an interpolator, you must + * also set the duration. + * @see #setDuration(int) + */ + public void setInterpolator(Interpolator interpolator) { + changed = true; + mInterpolator = interpolator; + } + + /** + * Updates the action with given parameters. + * @param dx Pixels to scroll horizontally + * @param dy Pixels to scroll vertically + * @param duration Duration of the animation in milliseconds + * @param interpolator Interpolator to be used when calculating scroll position in each + * animation step + */ + public void update(int dx, int dy, int duration, Interpolator interpolator) { + mDx = dx; + mDy = dy; + mDuration = duration; + mInterpolator = interpolator; + changed = true; + } + } + } + + static class AdapterDataObservable extends Observable { + public boolean hasObservers() { + return !mObservers.isEmpty(); + } + + public void notifyChanged() { + // since onChanged() is implemented by the app, it could do anything, including + // removing itself from {@link mObservers} - and that could cause problems if + // an iterator is used on the ArrayList {@link mObservers}. + // to avoid such problems, just march thru the list in the reverse order. + for (int i = mObservers.size() - 1; i >= 0; i--) { + mObservers.get(i).onChanged(); + } + } + + public void notifyItemRangeChanged(int positionStart, int itemCount) { + notifyItemRangeChanged(positionStart, itemCount, null); + } + + public void notifyItemRangeChanged(int positionStart, int itemCount, Object payload) { + // since onItemRangeChanged() is implemented by the app, it could do anything, including + // removing itself from {@link mObservers} - and that could cause problems if + // an iterator is used on the ArrayList {@link mObservers}. + // to avoid such problems, just march thru the list in the reverse order. + for (int i = mObservers.size() - 1; i >= 0; i--) { + mObservers.get(i).onItemRangeChanged(positionStart, itemCount, payload); + } + } + + public void notifyItemRangeInserted(int positionStart, int itemCount) { + // since onItemRangeInserted() is implemented by the app, it could do anything, + // including removing itself from {@link mObservers} - and that could cause problems if + // an iterator is used on the ArrayList {@link mObservers}. + // to avoid such problems, just march thru the list in the reverse order. + for (int i = mObservers.size() - 1; i >= 0; i--) { + mObservers.get(i).onItemRangeInserted(positionStart, itemCount); + } + } + + public void notifyItemRangeRemoved(int positionStart, int itemCount) { + // since onItemRangeRemoved() is implemented by the app, it could do anything, including + // removing itself from {@link mObservers} - and that could cause problems if + // an iterator is used on the ArrayList {@link mObservers}. + // to avoid such problems, just march thru the list in the reverse order. + for (int i = mObservers.size() - 1; i >= 0; i--) { + mObservers.get(i).onItemRangeRemoved(positionStart, itemCount); + } + } + + public void notifyItemMoved(int fromPosition, int toPosition) { + for (int i = mObservers.size() - 1; i >= 0; i--) { + mObservers.get(i).onItemRangeMoved(fromPosition, toPosition, 1); + } + } + } + + /** + * This is public so that the CREATOR can be access on cold launch. + * @hide + */ + public static class SavedState extends android.view.View.BaseSavedState { + + Parcelable mLayoutState; + + /** + * called by CREATOR + */ + SavedState(Parcel in) { + super(in); + mLayoutState = in.readParcelable(LayoutManager.class.getClassLoader()); + } + + /** + * Called by onSaveInstanceState + */ + SavedState(Parcelable superState) { + super(superState); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeParcelable(mLayoutState, 0); + } + + private void copyFrom(SavedState other) { + mLayoutState = other.mLayoutState; + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + /** + *

Contains useful information about the current RecyclerView state like target scroll + * position or view focus. State object can also keep arbitrary data, identified by resource + * ids.

+ *

Often times, RecyclerView components will need to pass information between each other. + * To provide a well defined data bus between components, RecyclerView passes the same State + * object to component callbacks and these components can use it to exchange data.

+ *

If you implement custom components, you can use State's put/get/remove methods to pass + * data between your components without needing to manage their lifecycles.

+ */ + public static class State { + static final int STEP_START = 1; + static final int STEP_LAYOUT = 1 << 1; + static final int STEP_ANIMATIONS = 1 << 2; + + void assertLayoutStep(int accepted) { + if ((accepted & mLayoutStep) == 0) { + throw new IllegalStateException("Layout state should be one of " + + Integer.toBinaryString(accepted) + " but it is " + + Integer.toBinaryString(mLayoutStep)); + } + } + + @IntDef(flag = true, value = { + STEP_START, STEP_LAYOUT, STEP_ANIMATIONS + }) + @Retention(RetentionPolicy.SOURCE) + @interface LayoutState {} + + private int mTargetPosition = RecyclerView.NO_POSITION; + + @LayoutState + private int mLayoutStep = STEP_START; + + private SparseArray mData; + + /** + * Number of items adapter has. + */ + int mItemCount = 0; + + /** + * Number of items adapter had in the previous layout. + */ + private int mPreviousLayoutItemCount = 0; + + /** + * Number of items that were NOT laid out but has been deleted from the adapter after the + * previous layout. + */ + private int mDeletedInvisibleItemCountSincePreviousLayout = 0; + + private boolean mStructureChanged = false; + + private boolean mInPreLayout = false; + + private boolean mRunSimpleAnimations = false; + + private boolean mRunPredictiveAnimations = false; + + private boolean mTrackOldChangeHolders = false; + + private boolean mIsMeasuring = false; + + State reset() { + mTargetPosition = RecyclerView.NO_POSITION; + if (mData != null) { + mData.clear(); + } + mItemCount = 0; + mStructureChanged = false; + mIsMeasuring = false; + return this; + } + + /** + * Returns true if the RecyclerView is currently measuring the layout. This value is + * {@code true} only if the LayoutManager opted into the auto measure API and RecyclerView + * has non-exact measurement specs. + *

+ * Note that if the LayoutManager supports predictive animations and it is calculating the + * pre-layout step, this value will be {@code false} even if the RecyclerView is in + * {@code onMeasure} call. This is because pre-layout means the previous state of the + * RecyclerView and measurements made for that state cannot change the RecyclerView's size. + * LayoutManager is always guaranteed to receive another call to + * {@link LayoutManager#onLayoutChildren(Recycler, State)} when this happens. + * + * @return True if the RecyclerView is currently calculating its bounds, false otherwise. + */ + public boolean isMeasuring() { + return mIsMeasuring; + } + + /** + * Returns true if + * @return + */ + public boolean isPreLayout() { + return mInPreLayout; + } + + /** + * Returns whether RecyclerView will run predictive animations in this layout pass + * or not. + * + * @return true if RecyclerView is calculating predictive animations to be run at the end + * of the layout pass. + */ + public boolean willRunPredictiveAnimations() { + return mRunPredictiveAnimations; + } + + /** + * Returns whether RecyclerView will run simple animations in this layout pass + * or not. + * + * @return true if RecyclerView is calculating simple animations to be run at the end of + * the layout pass. + */ + public boolean willRunSimpleAnimations() { + return mRunSimpleAnimations; + } + + /** + * Removes the mapping from the specified id, if there was any. + * @param resourceId Id of the resource you want to remove. It is suggested to use R.id.* to + * preserve cross functionality and avoid conflicts. + */ + public void remove(int resourceId) { + if (mData == null) { + return; + } + mData.remove(resourceId); + } + + /** + * Gets the Object mapped from the specified id, or null + * if no such data exists. + * + * @param resourceId Id of the resource you want to remove. It is suggested to use R.id.* + * to + * preserve cross functionality and avoid conflicts. + */ + public T get(int resourceId) { + if (mData == null) { + return null; + } + return (T) mData.get(resourceId); + } + + /** + * Adds a mapping from the specified id to the specified value, replacing the previous + * mapping from the specified key if there was one. + * + * @param resourceId Id of the resource you want to add. It is suggested to use R.id.* to + * preserve cross functionality and avoid conflicts. + * @param data The data you want to associate with the resourceId. + */ + public void put(int resourceId, Object data) { + if (mData == null) { + mData = new SparseArray(); + } + mData.put(resourceId, data); + } + + /** + * If scroll is triggered to make a certain item visible, this value will return the + * adapter index of that item. + * @return Adapter index of the target item or + * {@link RecyclerView#NO_POSITION} if there is no target + * position. + */ + public int getTargetScrollPosition() { + return mTargetPosition; + } + + /** + * Returns if current scroll has a target position. + * @return true if scroll is being triggered to make a certain position visible + * @see #getTargetScrollPosition() + */ + public boolean hasTargetScrollPosition() { + return mTargetPosition != RecyclerView.NO_POSITION; + } + + /** + * @return true if the structure of the data set has changed since the last call to + * onLayoutChildren, false otherwise + */ + public boolean didStructureChange() { + return mStructureChanged; + } + + /** + * Returns the total number of items that can be laid out. Note that this number is not + * necessarily equal to the number of items in the adapter, so you should always use this + * number for your position calculations and never access the adapter directly. + *

+ * RecyclerView listens for Adapter's notify events and calculates the effects of adapter + * data changes on existing Views. These calculations are used to decide which animations + * should be run. + *

+ * To support predictive animations, RecyclerView may rewrite or reorder Adapter changes to + * present the correct state to LayoutManager in pre-layout pass. + *

+ * For example, a newly added item is not included in pre-layout item count because + * pre-layout reflects the contents of the adapter before the item is added. Behind the + * scenes, RecyclerView offsets {@link Recycler#getViewForPosition(int)} calls such that + * LayoutManager does not know about the new item's existence in pre-layout. The item will + * be available in second layout pass and will be included in the item count. Similar + * adjustments are made for moved and removed items as well. + *

+ * You can get the adapter's item count via {@link LayoutManager#getItemCount()} method. + * + * @return The number of items currently available + * @see LayoutManager#getItemCount() + */ + public int getItemCount() { + return mInPreLayout ? + (mPreviousLayoutItemCount - mDeletedInvisibleItemCountSincePreviousLayout) : + mItemCount; + } + + @Override + public String toString() { + return "State{" + + "mTargetPosition=" + mTargetPosition + + ", mData=" + mData + + ", mItemCount=" + mItemCount + + ", mPreviousLayoutItemCount=" + mPreviousLayoutItemCount + + ", mDeletedInvisibleItemCountSincePreviousLayout=" + + mDeletedInvisibleItemCountSincePreviousLayout + + ", mStructureChanged=" + mStructureChanged + + ", mInPreLayout=" + mInPreLayout + + ", mRunSimpleAnimations=" + mRunSimpleAnimations + + ", mRunPredictiveAnimations=" + mRunPredictiveAnimations + + '}'; + } + } + + /** + * Internal listener that manages items after animations finish. This is how items are + * retained (not recycled) during animations, but allowed to be recycled afterwards. + * It depends on the contract with the ItemAnimator to call the appropriate dispatch*Finished() + * method on the animator's listener when it is done animating any item. + */ + private class ItemAnimatorRestoreListener implements ItemAnimator.ItemAnimatorListener { + + @Override + public void onAnimationFinished(ViewHolder item) { + item.setIsRecyclable(true); + if (item.mShadowedHolder != null && item.mShadowingHolder == null) { // old vh + item.mShadowedHolder = null; + } + // always null this because an OldViewHolder can never become NewViewHolder w/o being + // recycled. + item.mShadowingHolder = null; + if (!item.shouldBeKeptAsChild()) { + if (!removeAnimatingView(item.itemView) && item.isTmpDetached()) { + removeDetachedView(item.itemView, false); + } + } + } + } + + /** + * This class defines the animations that take place on items as changes are made + * to the adapter. + * + * Subclasses of ItemAnimator can be used to implement custom animations for actions on + * ViewHolder items. The RecyclerView will manage retaining these items while they + * are being animated, but implementors must call {@link #dispatchAnimationFinished(ViewHolder)} + * when a ViewHolder's animation is finished. In other words, there must be a matching + * {@link #dispatchAnimationFinished(ViewHolder)} call for each + * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) animateAppearance()}, + * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animateChange()} + * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo) animatePersistence()}, + * and + * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animateDisappearance()} call. + * + *

By default, RecyclerView uses {@link DefaultItemAnimator}.

+ * + * @see #setItemAnimator(ItemAnimator) + */ + @SuppressWarnings("UnusedParameters") + public static abstract class ItemAnimator { + + /** + * The Item represented by this ViewHolder is updated. + *

+ * @see #recordPreLayoutInformation(State, ViewHolder, int, List) + */ + public static final int FLAG_CHANGED = ViewHolder.FLAG_UPDATE; + + /** + * The Item represented by this ViewHolder is removed from the adapter. + *

+ * @see #recordPreLayoutInformation(State, ViewHolder, int, List) + */ + public static final int FLAG_REMOVED = ViewHolder.FLAG_REMOVED; + + /** + * Adapter {@link Adapter#notifyDataSetChanged()} has been called and the content + * represented by this ViewHolder is invalid. + *

+ * @see #recordPreLayoutInformation(State, ViewHolder, int, List) + */ + public static final int FLAG_INVALIDATED = ViewHolder.FLAG_INVALID; + + /** + * The position of the Item represented by this ViewHolder has been changed. This flag is + * not bound to {@link Adapter#notifyItemMoved(int, int)}. It might be set in response to + * any adapter change that may have a side effect on this item. (e.g. The item before this + * one has been removed from the Adapter). + *

+ * @see #recordPreLayoutInformation(State, ViewHolder, int, List) + */ + public static final int FLAG_MOVED = ViewHolder.FLAG_MOVED; + + /** + * This ViewHolder was not laid out but has been added to the layout in pre-layout state + * by the {@link LayoutManager}. This means that the item was already in the Adapter but + * invisible and it may become visible in the post layout phase. LayoutManagers may prefer + * to add new items in pre-layout to specify their virtual location when they are invisible + * (e.g. to specify the item should animate in from below the visible area). + *

+ * @see #recordPreLayoutInformation(State, ViewHolder, int, List) + */ + public static final int FLAG_APPEARED_IN_PRE_LAYOUT + = ViewHolder.FLAG_APPEARED_IN_PRE_LAYOUT; + + /** + * The set of flags that might be passed to + * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}. + */ + @IntDef(flag=true, value={ + FLAG_CHANGED, FLAG_REMOVED, FLAG_MOVED, FLAG_INVALIDATED, + FLAG_APPEARED_IN_PRE_LAYOUT + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AdapterChanges {} + private ItemAnimatorListener mListener = null; + private ArrayList mFinishedListeners = + new ArrayList(); + + private long mAddDuration = 120; + private long mRemoveDuration = 120; + private long mMoveDuration = 250; + private long mChangeDuration = 250; + + /** + * Gets the current duration for which all move animations will run. + * + * @return The current move duration + */ + public long getMoveDuration() { + return mMoveDuration; + } + + /** + * Sets the duration for which all move animations will run. + * + * @param moveDuration The move duration + */ + public void setMoveDuration(long moveDuration) { + mMoveDuration = moveDuration; + } + + /** + * Gets the current duration for which all add animations will run. + * + * @return The current add duration + */ + public long getAddDuration() { + return mAddDuration; + } + + /** + * Sets the duration for which all add animations will run. + * + * @param addDuration The add duration + */ + public void setAddDuration(long addDuration) { + mAddDuration = addDuration; + } + + /** + * Gets the current duration for which all remove animations will run. + * + * @return The current remove duration + */ + public long getRemoveDuration() { + return mRemoveDuration; + } + + /** + * Sets the duration for which all remove animations will run. + * + * @param removeDuration The remove duration + */ + public void setRemoveDuration(long removeDuration) { + mRemoveDuration = removeDuration; + } + + /** + * Gets the current duration for which all change animations will run. + * + * @return The current change duration + */ + public long getChangeDuration() { + return mChangeDuration; + } + + /** + * Sets the duration for which all change animations will run. + * + * @param changeDuration The change duration + */ + public void setChangeDuration(long changeDuration) { + mChangeDuration = changeDuration; + } + + /** + * Internal only: + * Sets the listener that must be called when the animator is finished + * animating the item (or immediately if no animation happens). This is set + * internally and is not intended to be set by external code. + * + * @param listener The listener that must be called. + */ + void setListener(ItemAnimatorListener listener) { + mListener = listener; + } + + /** + * Called by the RecyclerView before the layout begins. Item animator should record + * necessary information about the View before it is potentially rebound, moved or removed. + *

+ * The data returned from this method will be passed to the related animate** + * methods. + *

+ * Note that this method may be called after pre-layout phase if LayoutManager adds new + * Views to the layout in pre-layout pass. + *

+ * The default implementation returns an {@link ItemHolderInfo} which holds the bounds of + * the View and the adapter change flags. + * + * @param state The current State of RecyclerView which includes some useful data + * about the layout that will be calculated. + * @param viewHolder The ViewHolder whose information should be recorded. + * @param changeFlags Additional information about what changes happened in the Adapter + * about the Item represented by this ViewHolder. For instance, if + * item is deleted from the adapter, {@link #FLAG_REMOVED} will be set. + * @param payloads The payload list that was previously passed to + * {@link Adapter#notifyItemChanged(int, Object)} or + * {@link Adapter#notifyItemRangeChanged(int, int, Object)}. + * + * @return An ItemHolderInfo instance that preserves necessary information about the + * ViewHolder. This object will be passed back to related animate** methods + * after layout is complete. + * + * @see #recordPostLayoutInformation(State, ViewHolder) + * @see #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * @see #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * @see #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo) + * @see #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo) + */ + public @NonNull ItemHolderInfo recordPreLayoutInformation(@NonNull State state, + @NonNull ViewHolder viewHolder, @AdapterChanges int changeFlags, + @NonNull List payloads) { + return obtainHolderInfo().setFrom(viewHolder); + } + + /** + * Called by the RecyclerView after the layout is complete. Item animator should record + * necessary information about the View's final state. + *

+ * The data returned from this method will be passed to the related animate** + * methods. + *

+ * The default implementation returns an {@link ItemHolderInfo} which holds the bounds of + * the View. + * + * @param state The current State of RecyclerView which includes some useful data about + * the layout that will be calculated. + * @param viewHolder The ViewHolder whose information should be recorded. + * + * @return An ItemHolderInfo that preserves necessary information about the ViewHolder. + * This object will be passed back to related animate** methods when + * RecyclerView decides how items should be animated. + * + * @see #recordPreLayoutInformation(State, ViewHolder, int, List) + * @see #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * @see #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * @see #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo) + * @see #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo) + */ + public @NonNull ItemHolderInfo recordPostLayoutInformation(@NonNull State state, + @NonNull ViewHolder viewHolder) { + return obtainHolderInfo().setFrom(viewHolder); + } + + /** + * Called by the RecyclerView when a ViewHolder has disappeared from the layout. + *

+ * This means that the View was a child of the LayoutManager when layout started but has + * been removed by the LayoutManager. It might have been removed from the adapter or simply + * become invisible due to other factors. You can distinguish these two cases by checking + * the change flags that were passed to + * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}. + *

+ * Note that when a ViewHolder both changes and disappears in the same layout pass, the + * animation callback method which will be called by the RecyclerView depends on the + * ItemAnimator's decision whether to re-use the same ViewHolder or not, and also the + * LayoutManager's decision whether to layout the changed version of a disappearing + * ViewHolder or not. RecyclerView will call + * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animateChange} instead of {@code animateDisappearance} if and only if the ItemAnimator + * returns {@code false} from + * {@link #canReuseUpdatedViewHolder(ViewHolder) canReuseUpdatedViewHolder} and the + * LayoutManager lays out a new disappearing view that holds the updated information. + * Built-in LayoutManagers try to avoid laying out updated versions of disappearing views. + *

+ * If LayoutManager supports predictive animations, it might provide a target disappear + * location for the View by laying it out in that location. When that happens, + * RecyclerView will call {@link #recordPostLayoutInformation(State, ViewHolder)} and the + * response of that call will be passed to this method as the postLayoutInfo. + *

+ * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} when the animation + * is complete (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it + * decides not to animate the view). + * + * @param viewHolder The ViewHolder which should be animated + * @param preLayoutInfo The information that was returned from + * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}. + * @param postLayoutInfo The information that was returned from + * {@link #recordPostLayoutInformation(State, ViewHolder)}. Might be + * null if the LayoutManager did not layout the item. + * + * @return true if a later call to {@link #runPendingAnimations()} is requested, + * false otherwise. + */ + public abstract boolean animateDisappearance(@NonNull ViewHolder viewHolder, + @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo); + + /** + * Called by the RecyclerView when a ViewHolder is added to the layout. + *

+ * In detail, this means that the ViewHolder was not a child when the layout started + * but has been added by the LayoutManager. It might be newly added to the adapter or + * simply become visible due to other factors. + *

+ * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} when the animation + * is complete (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it + * decides not to animate the view). + * + * @param viewHolder The ViewHolder which should be animated + * @param preLayoutInfo The information that was returned from + * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}. + * Might be null if Item was just added to the adapter or + * LayoutManager does not support predictive animations or it could + * not predict that this ViewHolder will become visible. + * @param postLayoutInfo The information that was returned from {@link + * #recordPreLayoutInformation(State, ViewHolder, int, List)}. + * + * @return true if a later call to {@link #runPendingAnimations()} is requested, + * false otherwise. + */ + public abstract boolean animateAppearance(@NonNull ViewHolder viewHolder, + @Nullable ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo); + + /** + * Called by the RecyclerView when a ViewHolder is present in both before and after the + * layout and RecyclerView has not received a {@link Adapter#notifyItemChanged(int)} call + * for it or a {@link Adapter#notifyDataSetChanged()} call. + *

+ * This ViewHolder still represents the same data that it was representing when the layout + * started but its position / size may be changed by the LayoutManager. + *

+ * If the Item's layout position didn't change, RecyclerView still calls this method because + * it does not track this information (or does not necessarily know that an animation is + * not required). Your ItemAnimator should handle this case and if there is nothing to + * animate, it should call {@link #dispatchAnimationFinished(ViewHolder)} and return + * false. + *

+ * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} when the animation + * is complete (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it + * decides not to animate the view). + * + * @param viewHolder The ViewHolder which should be animated + * @param preLayoutInfo The information that was returned from + * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}. + * @param postLayoutInfo The information that was returned from {@link + * #recordPreLayoutInformation(State, ViewHolder, int, List)}. + * + * @return true if a later call to {@link #runPendingAnimations()} is requested, + * false otherwise. + */ + public abstract boolean animatePersistence(@NonNull ViewHolder viewHolder, + @NonNull ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo); + + /** + * Called by the RecyclerView when an adapter item is present both before and after the + * layout and RecyclerView has received a {@link Adapter#notifyItemChanged(int)} call + * for it. This method may also be called when + * {@link Adapter#notifyDataSetChanged()} is called and adapter has stable ids so that + * RecyclerView could still rebind views to the same ViewHolders. If viewType changes when + * {@link Adapter#notifyDataSetChanged()} is called, this method will not be called, + * instead, {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo)} will be + * called for the new ViewHolder and the old one will be recycled. + *

+ * If this method is called due to a {@link Adapter#notifyDataSetChanged()} call, there is + * a good possibility that item contents didn't really change but it is rebound from the + * adapter. {@link DefaultItemAnimator} will skip animating the View if its location on the + * screen didn't change and your animator should handle this case as well and avoid creating + * unnecessary animations. + *

+ * When an item is updated, ItemAnimator has a chance to ask RecyclerView to keep the + * previous presentation of the item as-is and supply a new ViewHolder for the updated + * presentation (see: {@link #canReuseUpdatedViewHolder(ViewHolder, List)}. + * This is useful if you don't know the contents of the Item and would like + * to cross-fade the old and the new one ({@link DefaultItemAnimator} uses this technique). + *

+ * When you are writing a custom item animator for your layout, it might be more performant + * and elegant to re-use the same ViewHolder and animate the content changes manually. + *

+ * When {@link Adapter#notifyItemChanged(int)} is called, the Item's view type may change. + * If the Item's view type has changed or ItemAnimator returned false for + * this ViewHolder when {@link #canReuseUpdatedViewHolder(ViewHolder, List)} was called, the + * oldHolder and newHolder will be different ViewHolder instances + * which represent the same Item. In that case, only the new ViewHolder is visible + * to the LayoutManager but RecyclerView keeps old ViewHolder attached for animations. + *

+ * ItemAnimator must call {@link #dispatchAnimationFinished(ViewHolder)} for each distinct + * ViewHolder when their animation is complete + * (or instantly call {@link #dispatchAnimationFinished(ViewHolder)} if it decides not to + * animate the view). + *

+ * If oldHolder and newHolder are the same instance, you should call + * {@link #dispatchAnimationFinished(ViewHolder)} only once. + *

+ * Note that when a ViewHolder both changes and disappears in the same layout pass, the + * animation callback method which will be called by the RecyclerView depends on the + * ItemAnimator's decision whether to re-use the same ViewHolder or not, and also the + * LayoutManager's decision whether to layout the changed version of a disappearing + * ViewHolder or not. RecyclerView will call + * {@code animateChange} instead of + * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animateDisappearance} if and only if the ItemAnimator returns {@code false} from + * {@link #canReuseUpdatedViewHolder(ViewHolder) canReuseUpdatedViewHolder} and the + * LayoutManager lays out a new disappearing view that holds the updated information. + * Built-in LayoutManagers try to avoid laying out updated versions of disappearing views. + * + * @param oldHolder The ViewHolder before the layout is started, might be the same + * instance with newHolder. + * @param newHolder The ViewHolder after the layout is finished, might be the same + * instance with oldHolder. + * @param preLayoutInfo The information that was returned from + * {@link #recordPreLayoutInformation(State, ViewHolder, int, List)}. + * @param postLayoutInfo The information that was returned from {@link + * #recordPreLayoutInformation(State, ViewHolder, int, List)}. + * + * @return true if a later call to {@link #runPendingAnimations()} is requested, + * false otherwise. + */ + public abstract boolean animateChange(@NonNull ViewHolder oldHolder, + @NonNull ViewHolder newHolder, + @NonNull ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo); + + @AdapterChanges static int buildAdapterChangeFlagsForAnimations(ViewHolder viewHolder) { + int flags = viewHolder.mFlags & (FLAG_INVALIDATED | FLAG_REMOVED | FLAG_CHANGED); + if (viewHolder.isInvalid()) { + return FLAG_INVALIDATED; + } + if ((flags & FLAG_INVALIDATED) == 0) { + final int oldPos = viewHolder.getOldPosition(); + final int pos = viewHolder.getAdapterPosition(); + if (oldPos != NO_POSITION && pos != NO_POSITION && oldPos != pos){ + flags |= FLAG_MOVED; + } + } + return flags; + } + + /** + * Called when there are pending animations waiting to be started. This state + * is governed by the return values from + * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animateAppearance()}, + * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animateChange()} + * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animatePersistence()}, and + * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animateDisappearance()}, which inform the RecyclerView that the ItemAnimator wants to be + * called later to start the associated animations. runPendingAnimations() will be scheduled + * to be run on the next frame. + */ + abstract public void runPendingAnimations(); + + /** + * Method called when an animation on a view should be ended immediately. + * This could happen when other events, like scrolling, occur, so that + * animating views can be quickly put into their proper end locations. + * Implementations should ensure that any animations running on the item + * are canceled and affected properties are set to their end values. + * Also, {@link #dispatchAnimationFinished(ViewHolder)} should be called for each finished + * animation since the animations are effectively done when this method is called. + * + * @param item The item for which an animation should be stopped. + */ + abstract public void endAnimation(ViewHolder item); + + /** + * Method called when all item animations should be ended immediately. + * This could happen when other events, like scrolling, occur, so that + * animating views can be quickly put into their proper end locations. + * Implementations should ensure that any animations running on any items + * are canceled and affected properties are set to their end values. + * Also, {@link #dispatchAnimationFinished(ViewHolder)} should be called for each finished + * animation since the animations are effectively done when this method is called. + */ + abstract public void endAnimations(); + + /** + * Method which returns whether there are any item animations currently running. + * This method can be used to determine whether to delay other actions until + * animations end. + * + * @return true if there are any item animations currently running, false otherwise. + */ + abstract public boolean isRunning(); + + /** + * Method to be called by subclasses when an animation is finished. + *

+ * For each call RecyclerView makes to + * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animateAppearance()}, + * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animatePersistence()}, or + * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animateDisappearance()}, there + * should + * be a matching {@link #dispatchAnimationFinished(ViewHolder)} call by the subclass. + *

+ * For {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animateChange()}, sublcass should call this method for both the oldHolder + * and newHolder (if they are not the same instance). + * + * @param viewHolder The ViewHolder whose animation is finished. + * @see #onAnimationFinished(ViewHolder) + */ + public final void dispatchAnimationFinished(ViewHolder viewHolder) { + onAnimationFinished(viewHolder); + if (mListener != null) { + mListener.onAnimationFinished(viewHolder); + } + } + + /** + * Called after {@link #dispatchAnimationFinished(ViewHolder)} is called by the + * ItemAniamtor. + * + * @param viewHolder The ViewHolder whose animation is finished. There might still be other + * animations running on this ViewHolder. + * @see #dispatchAnimationFinished(ViewHolder) + */ + public void onAnimationFinished(ViewHolder viewHolder) { + } + + /** + * Method to be called by subclasses when an animation is started. + *

+ * For each call RecyclerView makes to + * {@link #animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animateAppearance()}, + * {@link #animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animatePersistence()}, or + * {@link #animateDisappearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animateDisappearance()}, there should be a matching + * {@link #dispatchAnimationStarted(ViewHolder)} call by the subclass. + *

+ * For {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo) + * animateChange()}, sublcass should call this method for both the oldHolder + * and newHolder (if they are not the same instance). + *

+ * If your ItemAnimator decides not to animate a ViewHolder, it should call + * {@link #dispatchAnimationFinished(ViewHolder)} without calling + * {@link #dispatchAnimationStarted(ViewHolder)}. + * + * @param viewHolder The ViewHolder whose animation is starting. + * @see #onAnimationStarted(ViewHolder) + */ + public final void dispatchAnimationStarted(ViewHolder viewHolder) { + onAnimationStarted(viewHolder); + } + + /** + * Called when a new animation is started on the given ViewHolder. + * + * @param viewHolder The ViewHolder which started animating. Note that the ViewHolder + * might already be animating and this might be another animation. + * @see #dispatchAnimationStarted(ViewHolder) + */ + public void onAnimationStarted(ViewHolder viewHolder) { + + } + + /** + * Like {@link #isRunning()}, this method returns whether there are any item + * animations currently running. Addtionally, the listener passed in will be called + * when there are no item animations running, either immediately (before the method + * returns) if no animations are currently running, or when the currently running + * animations are {@link #dispatchAnimationsFinished() finished}. + * + *

Note that the listener is transient - it is either called immediately and not + * stored at all, or stored only until it is called when running animations + * are finished sometime later.

+ * + * @param listener A listener to be called immediately if no animations are running + * or later when currently-running animations have finished. A null listener is + * equivalent to calling {@link #isRunning()}. + * @return true if there are any item animations currently running, false otherwise. + */ + public final boolean isRunning(ItemAnimatorFinishedListener listener) { + boolean running = isRunning(); + if (listener != null) { + if (!running) { + listener.onAnimationsFinished(); + } else { + mFinishedListeners.add(listener); + } + } + return running; + } + + /** + * When an item is changed, ItemAnimator can decide whether it wants to re-use + * the same ViewHolder for animations or RecyclerView should create a copy of the + * item and ItemAnimator will use both to run the animation (e.g. cross-fade). + *

+ * Note that this method will only be called if the {@link ViewHolder} still has the same + * type ({@link Adapter#getItemViewType(int)}). Otherwise, ItemAnimator will always receive + * both {@link ViewHolder}s in the + * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)} method. + *

+ * If your application is using change payloads, you can override + * {@link #canReuseUpdatedViewHolder(ViewHolder, List)} to decide based on payloads. + * + * @param viewHolder The ViewHolder which represents the changed item's old content. + * + * @return True if RecyclerView should just rebind to the same ViewHolder or false if + * RecyclerView should create a new ViewHolder and pass this ViewHolder to the + * ItemAnimator to animate. Default implementation returns true. + * + * @see #canReuseUpdatedViewHolder(ViewHolder, List) + */ + public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder) { + return true; + } + + /** + * When an item is changed, ItemAnimator can decide whether it wants to re-use + * the same ViewHolder for animations or RecyclerView should create a copy of the + * item and ItemAnimator will use both to run the animation (e.g. cross-fade). + *

+ * Note that this method will only be called if the {@link ViewHolder} still has the same + * type ({@link Adapter#getItemViewType(int)}). Otherwise, ItemAnimator will always receive + * both {@link ViewHolder}s in the + * {@link #animateChange(ViewHolder, ViewHolder, ItemHolderInfo, ItemHolderInfo)} method. + * + * @param viewHolder The ViewHolder which represents the changed item's old content. + * @param payloads A non-null list of merged payloads that were sent with change + * notifications. Can be empty if the adapter is invalidated via + * {@link RecyclerView.Adapter#notifyDataSetChanged()}. The same list of + * payloads will be passed into + * {@link RecyclerView.Adapter#onBindViewHolder(ViewHolder, int, List)} + * method if this method returns true. + * + * @return True if RecyclerView should just rebind to the same ViewHolder or false if + * RecyclerView should create a new ViewHolder and pass this ViewHolder to the + * ItemAnimator to animate. Default implementation calls + * {@link #canReuseUpdatedViewHolder(ViewHolder)}. + * + * @see #canReuseUpdatedViewHolder(ViewHolder) + */ + public boolean canReuseUpdatedViewHolder(@NonNull ViewHolder viewHolder, + @NonNull List payloads) { + return canReuseUpdatedViewHolder(viewHolder); + } + + /** + * This method should be called by ItemAnimator implementations to notify + * any listeners that all pending and active item animations are finished. + */ + public final void dispatchAnimationsFinished() { + final int count = mFinishedListeners.size(); + for (int i = 0; i < count; ++i) { + mFinishedListeners.get(i).onAnimationsFinished(); + } + mFinishedListeners.clear(); + } + + /** + * Returns a new {@link ItemHolderInfo} which will be used to store information about the + * ViewHolder. This information will later be passed into animate** methods. + *

+ * You can override this method if you want to extend {@link ItemHolderInfo} and provide + * your own instances. + * + * @return A new {@link ItemHolderInfo}. + */ + public ItemHolderInfo obtainHolderInfo() { + return new ItemHolderInfo(); + } + + /** + * The interface to be implemented by listeners to animation events from this + * ItemAnimator. This is used internally and is not intended for developers to + * create directly. + */ + interface ItemAnimatorListener { + void onAnimationFinished(ViewHolder item); + } + + /** + * This interface is used to inform listeners when all pending or running animations + * in an ItemAnimator are finished. This can be used, for example, to delay an action + * in a data set until currently-running animations are complete. + * + * @see #isRunning(ItemAnimatorFinishedListener) + */ + public interface ItemAnimatorFinishedListener { + void onAnimationsFinished(); + } + + /** + * A simple data structure that holds information about an item's bounds. + * This information is used in calculating item animations. Default implementation of + * {@link #recordPreLayoutInformation(RecyclerView.State, ViewHolder, int, List)} and + * {@link #recordPostLayoutInformation(RecyclerView.State, ViewHolder)} returns this data + * structure. You can extend this class if you would like to keep more information about + * the Views. + *

+ * If you want to provide your own implementation butstill use `super` methods to record + * basic information, you can override {@link #obtainHolderInfo()} to provide your own + * instances. + */ + public static class ItemHolderInfo { + + /** + * The left edge of the View (excluding decorations) + */ + public int left; + + /** + * The top edge of the View (excluding decorations) + */ + public int top; + + /** + * The right edge of the View (excluding decorations) + */ + public int right; + + /** + * The bottom edge of the View (excluding decorations) + */ + public int bottom; + + /** + * The change flags that were passed to + * {@link #recordPreLayoutInformation(RecyclerView.State, ViewHolder, int, List)}. + */ + @AdapterChanges + public int changeFlags; + + public ItemHolderInfo() { + } + + /** + * Sets the {@link #left}, {@link #top}, {@link #right} and {@link #bottom} values from + * the given ViewHolder. Clears all {@link #changeFlags}. + * + * @param holder The ViewHolder whose bounds should be copied. + * @return This {@link ItemHolderInfo} + */ + public ItemHolderInfo setFrom(RecyclerView.ViewHolder holder) { + return setFrom(holder, 0); + } + + /** + * Sets the {@link #left}, {@link #top}, {@link #right} and {@link #bottom} values from + * the given ViewHolder and sets the {@link #changeFlags} to the given flags parameter. + * + * @param holder The ViewHolder whose bounds should be copied. + * @param flags The adapter change flags that were passed into + * {@link #recordPreLayoutInformation(RecyclerView.State, ViewHolder, int, + * List)}. + * @return This {@link ItemHolderInfo} + */ + public ItemHolderInfo setFrom(RecyclerView.ViewHolder holder, + @AdapterChanges int flags) { + final View view = holder.itemView; + this.left = view.getLeft(); + this.top = view.getTop(); + this.right = view.getRight(); + this.bottom = view.getBottom(); + return this; + } + } + } + + @Override + protected int getChildDrawingOrder(int childCount, int i) { + if (mChildDrawingOrderCallback == null) { + return super.getChildDrawingOrder(childCount, i); + } else { + return mChildDrawingOrderCallback.onGetChildDrawingOrder(childCount, i); + } + } + + /** + * A callback interface that can be used to alter the drawing order of RecyclerView children. + *

+ * It works using the {@link ViewGroup#getChildDrawingOrder(int, int)} method, so any case + * that applies to that method also applies to this callback. For example, changing the drawing + * order of two views will not have any effect if their elevation values are different since + * elevation overrides the result of this callback. + */ + public interface ChildDrawingOrderCallback { + /** + * Returns the index of the child to draw for this iteration. Override this + * if you want to change the drawing order of children. By default, it + * returns i. + * + * @param i The current iteration. + * @return The index of the child to draw this iteration. + * + * @see RecyclerView#setChildDrawingOrderCallback(RecyclerView.ChildDrawingOrderCallback) + */ + int onGetChildDrawingOrder(int childCount, int i); + } + + private NestedScrollingChildHelper getScrollingChildHelper() { + if (mScrollingChildHelper == null) { + mScrollingChildHelper = new NestedScrollingChildHelper(this); + } + return mScrollingChildHelper; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/RecyclerViewAccessibilityDelegate.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/RecyclerViewAccessibilityDelegate.java new file mode 100644 index 00000000..dc3b9019 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/RecyclerViewAccessibilityDelegate.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.widget; + +import android.os.Bundle; +import android.support.v4.view.AccessibilityDelegateCompat; +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; +import android.view.View; +import android.view.accessibility.AccessibilityEvent; + +/** + * The AccessibilityDelegate used by RecyclerView. + *

+ * This class handles basic accessibility actions and delegates them to LayoutManager. + */ +public class RecyclerViewAccessibilityDelegate extends AccessibilityDelegateCompat { + final RecyclerView mRecyclerView; + + + public RecyclerViewAccessibilityDelegate(RecyclerView recyclerView) { + mRecyclerView = recyclerView; + } + + private boolean shouldIgnore() { + return mRecyclerView.hasPendingAdapterUpdates(); + } + + @Override + public boolean performAccessibilityAction(View host, int action, Bundle args) { + if (super.performAccessibilityAction(host, action, args)) { + return true; + } + if (!shouldIgnore() && mRecyclerView.getLayoutManager() != null) { + return mRecyclerView.getLayoutManager().performAccessibilityAction(action, args); + } + + return false; + } + + @Override + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { + super.onInitializeAccessibilityNodeInfo(host, info); + info.setClassName(RecyclerView.class.getName()); + if (!shouldIgnore() && mRecyclerView.getLayoutManager() != null) { + mRecyclerView.getLayoutManager().onInitializeAccessibilityNodeInfo(info); + } + } + + @Override + public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(host, event); + event.setClassName(RecyclerView.class.getName()); + if (host instanceof RecyclerView && !shouldIgnore()) { + RecyclerView rv = (RecyclerView) host; + if (rv.getLayoutManager() != null) { + rv.getLayoutManager().onInitializeAccessibilityEvent(event); + } + } + } + + AccessibilityDelegateCompat getItemDelegate() { + return mItemDelegate; + } + + final AccessibilityDelegateCompat mItemDelegate = new AccessibilityDelegateCompat() { + @Override + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) { + super.onInitializeAccessibilityNodeInfo(host, info); + if (!shouldIgnore() && mRecyclerView.getLayoutManager() != null) { + mRecyclerView.getLayoutManager(). + onInitializeAccessibilityNodeInfoForItem(host, info); + } + } + + @Override + public boolean performAccessibilityAction(View host, int action, Bundle args) { + if (super.performAccessibilityAction(host, action, args)) { + return true; + } + if (!shouldIgnore() && mRecyclerView.getLayoutManager() != null) { + return mRecyclerView.getLayoutManager(). + performAccessibilityActionForItem(host, action, args); + } + return false; + } + }; +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/ScrollbarHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/ScrollbarHelper.java new file mode 100644 index 00000000..4dd6308d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/ScrollbarHelper.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.support.widget; + +import android.view.View; + +/** + * A helper class to do scroll offset calculations. + */ +class ScrollbarHelper { + + /** + * @param startChild View closest to start of the list. (top or left) + * @param endChild View closest to end of the list (bottom or right) + */ + static int computeScrollOffset(RecyclerView.State state, OrientationHelper orientation, + View startChild, View endChild, RecyclerView.LayoutManager lm, + boolean smoothScrollbarEnabled, boolean reverseLayout) { + if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null || + endChild == null) { + return 0; + } + final int minPosition = Math.min(lm.getPosition(startChild), + lm.getPosition(endChild)); + final int maxPosition = Math.max(lm.getPosition(startChild), + lm.getPosition(endChild)); + final int itemsBefore = reverseLayout + ? Math.max(0, state.getItemCount() - maxPosition - 1) + : Math.max(0, minPosition); + if (!smoothScrollbarEnabled) { + return itemsBefore; + } + final int laidOutArea = Math.abs(orientation.getDecoratedEnd(endChild) - + orientation.getDecoratedStart(startChild)); + final int itemRange = Math.abs(lm.getPosition(startChild) - + lm.getPosition(endChild)) + 1; + final float avgSizePerRow = (float) laidOutArea / itemRange; + + return Math.round(itemsBefore * avgSizePerRow + (orientation.getStartAfterPadding() + - orientation.getDecoratedStart(startChild))); + } + + /** + * @param startChild View closest to start of the list. (top or left) + * @param endChild View closest to end of the list (bottom or right) + */ + static int computeScrollExtent(RecyclerView.State state, OrientationHelper orientation, + View startChild, View endChild, RecyclerView.LayoutManager lm, + boolean smoothScrollbarEnabled) { + if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null || + endChild == null) { + return 0; + } + if (!smoothScrollbarEnabled) { + return Math.abs(lm.getPosition(startChild) - lm.getPosition(endChild)) + 1; + } + final int extend = orientation.getDecoratedEnd(endChild) + - orientation.getDecoratedStart(startChild); + return Math.min(orientation.getTotalSpace(), extend); + } + + /** + * @param startChild View closest to start of the list. (top or left) + * @param endChild View closest to end of the list (bottom or right) + */ + static int computeScrollRange(RecyclerView.State state, OrientationHelper orientation, + View startChild, View endChild, RecyclerView.LayoutManager lm, + boolean smoothScrollbarEnabled) { + if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null || + endChild == null) { + return 0; + } + if (!smoothScrollbarEnabled) { + return state.getItemCount(); + } + // smooth scrollbar enabled. try to estimate better. + final int laidOutArea = orientation.getDecoratedEnd(endChild) - + orientation.getDecoratedStart(startChild); + final int laidOutRange = Math.abs(lm.getPosition(startChild) - + lm.getPosition(endChild)) + + 1; + // estimate a size for full list. + return (int) ((float) laidOutArea / laidOutRange * state.getItemCount()); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/SimpleItemAnimator.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/SimpleItemAnimator.java new file mode 100644 index 00000000..2eb4cce5 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/SimpleItemAnimator.java @@ -0,0 +1,442 @@ +package org.telegram.messenger.support.widget; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import org.telegram.messenger.support.widget.RecyclerView.Adapter; +import org.telegram.messenger.support.widget.RecyclerView.ViewHolder; +import org.telegram.messenger.support.widget.RecyclerView.ItemAnimator.ItemHolderInfo; +import android.util.Log; +import android.view.View; + +import java.util.List; + +/** + * A wrapper class for ItemAnimator that records View bounds and decides whether it should run + * move, change, add or remove animations. This class also replicates the original ItemAnimator + * API. + *

+ * It uses {@link ItemHolderInfo} to track the bounds information of the Views. If you would like + * to + * extend this class, you can override {@link #obtainHolderInfo()} method to provide your own info + * class that extends {@link ItemHolderInfo}. + */ +abstract public class SimpleItemAnimator extends RecyclerView.ItemAnimator { + + private static final boolean DEBUG = false; + + private static final String TAG = "SimpleItemAnimator"; + + boolean mSupportsChangeAnimations = true; + + /** + * Returns whether this ItemAnimator supports animations of change events. + * + * @return true if change animations are supported, false otherwise + */ + @SuppressWarnings("unused") + public boolean getSupportsChangeAnimations() { + return mSupportsChangeAnimations; + } + + /** + * Sets whether this ItemAnimator supports animations of item change events. + * If you set this property to false, actions on the data set which change the + * contents of items will not be animated. What those animations do is left + * up to the discretion of the ItemAnimator subclass, in its + * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} implementation. + * The value of this property is true by default. + * + * @param supportsChangeAnimations true if change animations are supported by + * this ItemAnimator, false otherwise. If the property is false, + * the ItemAnimator + * will not receive a call to + * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, + * int)} when changes occur. + * @see Adapter#notifyItemChanged(int) + * @see Adapter#notifyItemRangeChanged(int, int) + */ + public void setSupportsChangeAnimations(boolean supportsChangeAnimations) { + mSupportsChangeAnimations = supportsChangeAnimations; + } + + /** + * {@inheritDoc} + * + * @return True if change animations are not supported or the ViewHolder is invalid, + * false otherwise. + * + * @see #setSupportsChangeAnimations(boolean) + */ + @Override + public boolean canReuseUpdatedViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) { + return !mSupportsChangeAnimations || viewHolder.isInvalid(); + } + + @Override + public boolean animateDisappearance(@NonNull ViewHolder viewHolder, + @NonNull ItemHolderInfo preLayoutInfo, @Nullable ItemHolderInfo postLayoutInfo) { + int oldLeft = preLayoutInfo.left; + int oldTop = preLayoutInfo.top; + View disappearingItemView = viewHolder.itemView; + int newLeft = postLayoutInfo == null ? disappearingItemView.getLeft() : postLayoutInfo.left; + int newTop = postLayoutInfo == null ? disappearingItemView.getTop() : postLayoutInfo.top; + if (!viewHolder.isRemoved() && (oldLeft != newLeft || oldTop != newTop)) { + disappearingItemView.layout(newLeft, newTop, + newLeft + disappearingItemView.getWidth(), + newTop + disappearingItemView.getHeight()); + if (DEBUG) { + Log.d(TAG, "DISAPPEARING: " + viewHolder + " with view " + disappearingItemView); + } + return animateMove(viewHolder, oldLeft, oldTop, newLeft, newTop); + } else { + if (DEBUG) { + Log.d(TAG, "REMOVED: " + viewHolder + " with view " + disappearingItemView); + } + return animateRemove(viewHolder); + } + } + + @Override + public boolean animateAppearance(@NonNull ViewHolder viewHolder, + @Nullable ItemHolderInfo preLayoutInfo, @NonNull ItemHolderInfo postLayoutInfo) { + if (preLayoutInfo != null && (preLayoutInfo.left != postLayoutInfo.left + || preLayoutInfo.top != postLayoutInfo.top)) { + // slide items in if before/after locations differ + if (DEBUG) { + Log.d(TAG, "APPEARING: " + viewHolder + " with view " + viewHolder); + } + return animateMove(viewHolder, preLayoutInfo.left, preLayoutInfo.top, + postLayoutInfo.left, postLayoutInfo.top); + } else { + if (DEBUG) { + Log.d(TAG, "ADDED: " + viewHolder + " with view " + viewHolder); + } + return animateAdd(viewHolder); + } + } + + @Override + public boolean animatePersistence(@NonNull ViewHolder viewHolder, + @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) { + if (preInfo.left != postInfo.left || preInfo.top != postInfo.top) { + if (DEBUG) { + Log.d(TAG, "PERSISTENT: " + viewHolder + + " with view " + viewHolder.itemView); + } + return animateMove(viewHolder, + preInfo.left, preInfo.top, postInfo.left, postInfo.top); + } + dispatchMoveFinished(viewHolder); + return false; + } + + @Override + public boolean animateChange(@NonNull ViewHolder oldHolder, @NonNull ViewHolder newHolder, + @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) { + if (DEBUG) { + Log.d(TAG, "CHANGED: " + oldHolder + " with view " + oldHolder.itemView); + } + final int fromLeft = preInfo.left; + final int fromTop = preInfo.top; + final int toLeft, toTop; + if (newHolder.shouldIgnore()) { + toLeft = preInfo.left; + toTop = preInfo.top; + } else { + toLeft = postInfo.left; + toTop = postInfo.top; + } + return animateChange(oldHolder, newHolder, fromLeft, fromTop, toLeft, toTop); + } + + /** + * Called when an item is removed from the RecyclerView. Implementors can choose + * whether and how to animate that change, but must always call + * {@link #dispatchRemoveFinished(ViewHolder)} when done, either + * immediately (if no animation will occur) or after the animation actually finishes. + * The return value indicates whether an animation has been set up and whether the + * ItemAnimator's {@link #runPendingAnimations()} method should be called at the + * next opportunity. This mechanism allows ItemAnimator to set up individual animations + * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()}, + * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()}, + * {@link #animateRemove(ViewHolder) animateRemove()}, and + * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one, + * then start the animations together in the later call to {@link #runPendingAnimations()}. + * + *

This method may also be called for disappearing items which continue to exist in the + * RecyclerView, but for which the system does not have enough information to animate + * them out of view. In that case, the default animation for removing items is run + * on those items as well.

+ * + * @param holder The item that is being removed. + * @return true if a later call to {@link #runPendingAnimations()} is requested, + * false otherwise. + */ + abstract public boolean animateRemove(ViewHolder holder); + + /** + * Called when an item is added to the RecyclerView. Implementors can choose + * whether and how to animate that change, but must always call + * {@link #dispatchAddFinished(ViewHolder)} when done, either + * immediately (if no animation will occur) or after the animation actually finishes. + * The return value indicates whether an animation has been set up and whether the + * ItemAnimator's {@link #runPendingAnimations()} method should be called at the + * next opportunity. This mechanism allows ItemAnimator to set up individual animations + * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()}, + * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()}, + * {@link #animateRemove(ViewHolder) animateRemove()}, and + * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one, + * then start the animations together in the later call to {@link #runPendingAnimations()}. + * + *

This method may also be called for appearing items which were already in the + * RecyclerView, but for which the system does not have enough information to animate + * them into view. In that case, the default animation for adding items is run + * on those items as well.

+ * + * @param holder The item that is being added. + * @return true if a later call to {@link #runPendingAnimations()} is requested, + * false otherwise. + */ + abstract public boolean animateAdd(ViewHolder holder); + + /** + * Called when an item is moved in the RecyclerView. Implementors can choose + * whether and how to animate that change, but must always call + * {@link #dispatchMoveFinished(ViewHolder)} when done, either + * immediately (if no animation will occur) or after the animation actually finishes. + * The return value indicates whether an animation has been set up and whether the + * ItemAnimator's {@link #runPendingAnimations()} method should be called at the + * next opportunity. This mechanism allows ItemAnimator to set up individual animations + * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()}, + * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()}, + * {@link #animateRemove(ViewHolder) animateRemove()}, and + * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one, + * then start the animations together in the later call to {@link #runPendingAnimations()}. + * + * @param holder The item that is being moved. + * @return true if a later call to {@link #runPendingAnimations()} is requested, + * false otherwise. + */ + abstract public boolean animateMove(ViewHolder holder, int fromX, int fromY, + int toX, int toY); + + /** + * Called when an item is changed in the RecyclerView, as indicated by a call to + * {@link Adapter#notifyItemChanged(int)} or + * {@link Adapter#notifyItemRangeChanged(int, int)}. + *

+ * Implementers can choose whether and how to animate changes, but must always call + * {@link #dispatchChangeFinished(ViewHolder, boolean)} for each non-null distinct ViewHolder, + * either immediately (if no animation will occur) or after the animation actually finishes. + * If the {@code oldHolder} is the same ViewHolder as the {@code newHolder}, you must call + * {@link #dispatchChangeFinished(ViewHolder, boolean)} once and only once. In that case, the + * second parameter of {@code dispatchChangeFinished} is ignored. + *

+ * The return value indicates whether an animation has been set up and whether the + * ItemAnimator's {@link #runPendingAnimations()} method should be called at the + * next opportunity. This mechanism allows ItemAnimator to set up individual animations + * as separate calls to {@link #animateAdd(ViewHolder) animateAdd()}, + * {@link #animateMove(ViewHolder, int, int, int, int) animateMove()}, + * {@link #animateRemove(ViewHolder) animateRemove()}, and + * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)} come in one by one, + * then start the animations together in the later call to {@link #runPendingAnimations()}. + * + * @param oldHolder The original item that changed. + * @param newHolder The new item that was created with the changed content. Might be null + * @param fromLeft Left of the old view holder + * @param fromTop Top of the old view holder + * @param toLeft Left of the new view holder + * @param toTop Top of the new view holder + * @return true if a later call to {@link #runPendingAnimations()} is requested, + * false otherwise. + */ + abstract public boolean animateChange(ViewHolder oldHolder, + ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop); + + /** + * Method to be called by subclasses when a remove animation is done. + * + * @param item The item which has been removed + * @see RecyclerView.ItemAnimator#animateDisappearance(ViewHolder, ItemHolderInfo, + * ItemHolderInfo) + */ + public final void dispatchRemoveFinished(ViewHolder item) { + onRemoveFinished(item); + dispatchAnimationFinished(item); + } + + /** + * Method to be called by subclasses when a move animation is done. + * + * @param item The item which has been moved + * @see RecyclerView.ItemAnimator#animateDisappearance(ViewHolder, ItemHolderInfo, + * ItemHolderInfo) + * @see RecyclerView.ItemAnimator#animatePersistence(ViewHolder, ItemHolderInfo, ItemHolderInfo) + * @see RecyclerView.ItemAnimator#animateAppearance(ViewHolder, ItemHolderInfo, ItemHolderInfo) + */ + public final void dispatchMoveFinished(ViewHolder item) { + onMoveFinished(item); + dispatchAnimationFinished(item); + } + + /** + * Method to be called by subclasses when an add animation is done. + * + * @param item The item which has been added + */ + public final void dispatchAddFinished(ViewHolder item) { + onAddFinished(item); + dispatchAnimationFinished(item); + } + + /** + * Method to be called by subclasses when a change animation is done. + * + * @param item The item which has been changed (this method must be called for + * each non-null ViewHolder passed into + * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}). + * @param oldItem true if this is the old item that was changed, false if + * it is the new item that replaced the old item. + * @see #animateChange(ViewHolder, ViewHolder, int, int, int, int) + */ + public final void dispatchChangeFinished(ViewHolder item, boolean oldItem) { + onChangeFinished(item, oldItem); + dispatchAnimationFinished(item); + } + + /** + * Method to be called by subclasses when a remove animation is being started. + * + * @param item The item being removed + */ + public final void dispatchRemoveStarting(ViewHolder item) { + onRemoveStarting(item); + } + + /** + * Method to be called by subclasses when a move animation is being started. + * + * @param item The item being moved + */ + public final void dispatchMoveStarting(ViewHolder item) { + onMoveStarting(item); + } + + /** + * Method to be called by subclasses when an add animation is being started. + * + * @param item The item being added + */ + public final void dispatchAddStarting(ViewHolder item) { + onAddStarting(item); + } + + /** + * Method to be called by subclasses when a change animation is being started. + * + * @param item The item which has been changed (this method must be called for + * each non-null ViewHolder passed into + * {@link #animateChange(ViewHolder, ViewHolder, int, int, int, int)}). + * @param oldItem true if this is the old item that was changed, false if + * it is the new item that replaced the old item. + */ + public final void dispatchChangeStarting(ViewHolder item, boolean oldItem) { + onChangeStarting(item, oldItem); + } + + /** + * Called when a remove animation is being started on the given ViewHolder. + * The default implementation does nothing. Subclasses may wish to override + * this method to handle any ViewHolder-specific operations linked to animation + * lifecycles. + * + * @param item The ViewHolder being animated. + */ + @SuppressWarnings("UnusedParameters") + public void onRemoveStarting(ViewHolder item) { + } + + /** + * Called when a remove animation has ended on the given ViewHolder. + * The default implementation does nothing. Subclasses may wish to override + * this method to handle any ViewHolder-specific operations linked to animation + * lifecycles. + * + * @param item The ViewHolder being animated. + */ + public void onRemoveFinished(ViewHolder item) { + } + + /** + * Called when an add animation is being started on the given ViewHolder. + * The default implementation does nothing. Subclasses may wish to override + * this method to handle any ViewHolder-specific operations linked to animation + * lifecycles. + * + * @param item The ViewHolder being animated. + */ + @SuppressWarnings("UnusedParameters") + public void onAddStarting(ViewHolder item) { + } + + /** + * Called when an add animation has ended on the given ViewHolder. + * The default implementation does nothing. Subclasses may wish to override + * this method to handle any ViewHolder-specific operations linked to animation + * lifecycles. + * + * @param item The ViewHolder being animated. + */ + public void onAddFinished(ViewHolder item) { + } + + /** + * Called when a move animation is being started on the given ViewHolder. + * The default implementation does nothing. Subclasses may wish to override + * this method to handle any ViewHolder-specific operations linked to animation + * lifecycles. + * + * @param item The ViewHolder being animated. + */ + @SuppressWarnings("UnusedParameters") + public void onMoveStarting(ViewHolder item) { + } + + /** + * Called when a move animation has ended on the given ViewHolder. + * The default implementation does nothing. Subclasses may wish to override + * this method to handle any ViewHolder-specific operations linked to animation + * lifecycles. + * + * @param item The ViewHolder being animated. + */ + public void onMoveFinished(ViewHolder item) { + } + + /** + * Called when a change animation is being started on the given ViewHolder. + * The default implementation does nothing. Subclasses may wish to override + * this method to handle any ViewHolder-specific operations linked to animation + * lifecycles. + * + * @param item The ViewHolder being animated. + * @param oldItem true if this is the old item that was changed, false if + * it is the new item that replaced the old item. + */ + @SuppressWarnings("UnusedParameters") + public void onChangeStarting(ViewHolder item, boolean oldItem) { + } + + /** + * Called when a change animation has ended on the given ViewHolder. + * The default implementation does nothing. Subclasses may wish to override + * this method to handle any ViewHolder-specific operations linked to animation + * lifecycles. + * + * @param item The ViewHolder being animated. + * @param oldItem true if this is the old item that was changed, false if + * it is the new item that replaced the old item. + */ + public void onChangeFinished(ViewHolder item, boolean oldItem) { + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/StaggeredGridLayoutManager.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/StaggeredGridLayoutManager.java new file mode 100644 index 00000000..f93af4fd --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/StaggeredGridLayoutManager.java @@ -0,0 +1,3040 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.widget; + +import static org.telegram.messenger.support.widget.LayoutState.ITEM_DIRECTION_HEAD; +import static org.telegram.messenger.support.widget.LayoutState.ITEM_DIRECTION_TAIL; +import static org.telegram.messenger.support.widget.LayoutState.LAYOUT_END; +import static org.telegram.messenger.support.widget.LayoutState.LAYOUT_START; +import static org.telegram.messenger.support.widget.RecyclerView.NO_POSITION; + +import android.content.Context; +import android.graphics.PointF; +import android.graphics.Rect; +import android.os.Parcel; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.view.ViewCompat; +import android.support.v4.view.accessibility.AccessibilityEventCompat; +import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; +import android.support.v4.view.accessibility.AccessibilityRecordCompat; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.List; + +/** + * A LayoutManager that lays out children in a staggered grid formation. + * It supports horizontal & vertical layout as well as an ability to layout children in reverse. + *

+ * Staggered grids are likely to have gaps at the edges of the layout. To avoid these gaps, + * StaggeredGridLayoutManager can offset spans independently or move items between spans. You can + * control this behavior via {@link #setGapStrategy(int)}. + */ +public class StaggeredGridLayoutManager extends RecyclerView.LayoutManager { + + public static final String TAG = "StaggeredGridLayoutManager"; + + private static final boolean DEBUG = false; + + public static final int HORIZONTAL = OrientationHelper.HORIZONTAL; + + public static final int VERTICAL = OrientationHelper.VERTICAL; + + /** + * Does not do anything to hide gaps. + */ + public static final int GAP_HANDLING_NONE = 0; + + @SuppressWarnings("unused") + @Deprecated + public static final int GAP_HANDLING_LAZY = 1; + + /** + * When scroll state is changed to {@link RecyclerView#SCROLL_STATE_IDLE}, StaggeredGrid will + * check if there are gaps in the because of full span items. If it finds, it will re-layout + * and move items to correct positions with animations. + *

+ * For example, if LayoutManager ends up with the following layout due to adapter changes: + *

+     * AAA
+     * _BC
+     * DDD
+     * 
+ *

+ * It will animate to the following state: + *

+     * AAA
+     * BC_
+     * DDD
+     * 
+ */ + public static final int GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS = 2; + + private static final int INVALID_OFFSET = Integer.MIN_VALUE; + /** + * While trying to find next view to focus, LayoutManager will not try to scroll more + * than this factor times the total space of the list. If layout is vertical, total space is the + * height minus padding, if layout is horizontal, total space is the width minus padding. + */ + private static final float MAX_SCROLL_FACTOR = 1 / 3f; + + /** + * Number of spans + */ + private int mSpanCount = -1; + + private Span[] mSpans; + + /** + * Primary orientation is the layout's orientation, secondary orientation is the orientation + * for spans. Having both makes code much cleaner for calculations. + */ + @NonNull + OrientationHelper mPrimaryOrientation; + @NonNull + OrientationHelper mSecondaryOrientation; + + private int mOrientation; + + /** + * The width or height per span, depending on the orientation. + */ + private int mSizePerSpan; + + @NonNull + private final LayoutState mLayoutState; + + private boolean mReverseLayout = false; + + /** + * Aggregated reverse layout value that takes RTL into account. + */ + boolean mShouldReverseLayout = false; + + /** + * Temporary variable used during fill method to check which spans needs to be filled. + */ + private BitSet mRemainingSpans; + + /** + * When LayoutManager needs to scroll to a position, it sets this variable and requests a + * layout which will check this variable and re-layout accordingly. + */ + int mPendingScrollPosition = NO_POSITION; + + /** + * Used to keep the offset value when {@link #scrollToPositionWithOffset(int, int)} is + * called. + */ + int mPendingScrollPositionOffset = INVALID_OFFSET; + + /** + * Keeps the mapping between the adapter positions and spans. This is necessary to provide + * a consistent experience when user scrolls the list. + */ + LazySpanLookup mLazySpanLookup = new LazySpanLookup(); + + /** + * how we handle gaps in UI. + */ + private int mGapStrategy = GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS; + + /** + * Saved state needs this information to properly layout on restore. + */ + private boolean mLastLayoutFromEnd; + + /** + * Saved state and onLayout needs this information to re-layout properly + */ + private boolean mLastLayoutRTL; + + /** + * SavedState is not handled until a layout happens. This is where we keep it until next + * layout. + */ + private SavedState mPendingSavedState; + + /** + * Re-used measurement specs. updated by onLayout. + */ + private int mFullSizeSpec; + + /** + * Re-used rectangle to get child decor offsets. + */ + private final Rect mTmpRect = new Rect(); + + /** + * Re-used anchor info. + */ + private final AnchorInfo mAnchorInfo = new AnchorInfo(); + + /** + * If a full span item is invalid / or created in reverse direction; it may create gaps in + * the UI. While laying out, if such case is detected, we set this flag. + *

+ * After scrolling stops, we check this flag and if it is set, re-layout. + */ + private boolean mLaidOutInvalidFullSpan = false; + + /** + * Works the same way as {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)}. + * see {@link android.widget.AbsListView#setSmoothScrollbarEnabled(boolean)} + */ + private boolean mSmoothScrollbarEnabled = true; + + private final Runnable mCheckForGapsRunnable = new Runnable() { + @Override + public void run() { + checkForGaps(); + } + }; + + /** + * Constructor used when layout manager is set in XML by RecyclerView attribute + * "layoutManager". Defaults to single column and vertical. + */ + @SuppressWarnings("unused") + public StaggeredGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + Properties properties = getProperties(context, attrs, defStyleAttr, defStyleRes); + setOrientation(properties.orientation); + setSpanCount(properties.spanCount); + setReverseLayout(properties.reverseLayout); + setAutoMeasureEnabled(mGapStrategy != GAP_HANDLING_NONE); + mLayoutState = new LayoutState(); + createOrientationHelpers(); + } + + /** + * Creates a StaggeredGridLayoutManager with given parameters. + * + * @param spanCount If orientation is vertical, spanCount is number of columns. If + * orientation is horizontal, spanCount is number of rows. + * @param orientation {@link #VERTICAL} or {@link #HORIZONTAL} + */ + public StaggeredGridLayoutManager(int spanCount, int orientation) { + mOrientation = orientation; + setSpanCount(spanCount); + setAutoMeasureEnabled(mGapStrategy != GAP_HANDLING_NONE); + mLayoutState = new LayoutState(); + createOrientationHelpers(); + } + + private void createOrientationHelpers() { + mPrimaryOrientation = OrientationHelper.createOrientationHelper(this, mOrientation); + mSecondaryOrientation = OrientationHelper + .createOrientationHelper(this, 1 - mOrientation); + } + + /** + * Checks for gaps in the UI that may be caused by adapter changes. + *

+ * When a full span item is laid out in reverse direction, it sets a flag which we check when + * scroll is stopped (or re-layout happens) and re-layout after first valid item. + */ + private boolean checkForGaps() { + if (getChildCount() == 0 || mGapStrategy == GAP_HANDLING_NONE || !isAttachedToWindow()) { + return false; + } + final int minPos, maxPos; + if (mShouldReverseLayout) { + minPos = getLastChildPosition(); + maxPos = getFirstChildPosition(); + } else { + minPos = getFirstChildPosition(); + maxPos = getLastChildPosition(); + } + if (minPos == 0) { + View gapView = hasGapsToFix(); + if (gapView != null) { + mLazySpanLookup.clear(); + requestSimpleAnimationsInNextLayout(); + requestLayout(); + return true; + } + } + if (!mLaidOutInvalidFullSpan) { + return false; + } + int invalidGapDir = mShouldReverseLayout ? LAYOUT_START : LAYOUT_END; + final LazySpanLookup.FullSpanItem invalidFsi = mLazySpanLookup + .getFirstFullSpanItemInRange(minPos, maxPos + 1, invalidGapDir, true); + if (invalidFsi == null) { + mLaidOutInvalidFullSpan = false; + mLazySpanLookup.forceInvalidateAfter(maxPos + 1); + return false; + } + final LazySpanLookup.FullSpanItem validFsi = mLazySpanLookup + .getFirstFullSpanItemInRange(minPos, invalidFsi.mPosition, + invalidGapDir * -1, true); + if (validFsi == null) { + mLazySpanLookup.forceInvalidateAfter(invalidFsi.mPosition); + } else { + mLazySpanLookup.forceInvalidateAfter(validFsi.mPosition + 1); + } + requestSimpleAnimationsInNextLayout(); + requestLayout(); + return true; + } + + @Override + public void onScrollStateChanged(int state) { + if (state == RecyclerView.SCROLL_STATE_IDLE) { + checkForGaps(); + } + } + + @Override + public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) { + removeCallbacks(mCheckForGapsRunnable); + for (int i = 0; i < mSpanCount; i++) { + mSpans[i].clear(); + } + } + + /** + * Checks for gaps if we've reached to the top of the list. + *

+ * Intermediate gaps created by full span items are tracked via mLaidOutInvalidFullSpan field. + */ + View hasGapsToFix() { + int startChildIndex = 0; + int endChildIndex = getChildCount() - 1; + BitSet mSpansToCheck = new BitSet(mSpanCount); + mSpansToCheck.set(0, mSpanCount, true); + + final int firstChildIndex, childLimit; + final int preferredSpanDir = mOrientation == VERTICAL && isLayoutRTL() ? 1 : -1; + + if (mShouldReverseLayout) { + firstChildIndex = endChildIndex; + childLimit = startChildIndex - 1; + } else { + firstChildIndex = startChildIndex; + childLimit = endChildIndex + 1; + } + final int nextChildDiff = firstChildIndex < childLimit ? 1 : -1; + for (int i = firstChildIndex; i != childLimit; i += nextChildDiff) { + View child = getChildAt(i); + LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (mSpansToCheck.get(lp.mSpan.mIndex)) { + if (checkSpanForGap(lp.mSpan)) { + return child; + } + mSpansToCheck.clear(lp.mSpan.mIndex); + } + if (lp.mFullSpan) { + continue; // quick reject + } + + if (i + nextChildDiff != childLimit) { + View nextChild = getChildAt(i + nextChildDiff); + boolean compareSpans = false; + if (mShouldReverseLayout) { + // ensure child's end is below nextChild's end + int myEnd = mPrimaryOrientation.getDecoratedEnd(child); + int nextEnd = mPrimaryOrientation.getDecoratedEnd(nextChild); + if (myEnd < nextEnd) { + return child;//i should have a better position + } else if (myEnd == nextEnd) { + compareSpans = true; + } + } else { + int myStart = mPrimaryOrientation.getDecoratedStart(child); + int nextStart = mPrimaryOrientation.getDecoratedStart(nextChild); + if (myStart > nextStart) { + return child;//i should have a better position + } else if (myStart == nextStart) { + compareSpans = true; + } + } + if (compareSpans) { + // equal, check span indices. + LayoutParams nextLp = (LayoutParams) nextChild.getLayoutParams(); + if (lp.mSpan.mIndex - nextLp.mSpan.mIndex < 0 != preferredSpanDir < 0) { + return child; + } + } + } + } + // everything looks good + return null; + } + + private boolean checkSpanForGap(Span span) { + if (mShouldReverseLayout) { + if (span.getEndLine() < mPrimaryOrientation.getEndAfterPadding()) { + // if it is full span, it is OK + final View endView = span.mViews.get(span.mViews.size() - 1); + final LayoutParams lp = span.getLayoutParams(endView); + return !lp.mFullSpan; + } + } else if (span.getStartLine() > mPrimaryOrientation.getStartAfterPadding()) { + // if it is full span, it is OK + final View startView = span.mViews.get(0); + final LayoutParams lp = span.getLayoutParams(startView); + return !lp.mFullSpan; + } + return false; + } + + /** + * Sets the number of spans for the layout. This will invalidate all of the span assignments + * for Views. + *

+ * Calling this method will automatically result in a new layout request unless the spanCount + * parameter is equal to current span count. + * + * @param spanCount Number of spans to layout + */ + public void setSpanCount(int spanCount) { + assertNotInLayoutOrScroll(null); + if (spanCount != mSpanCount) { + invalidateSpanAssignments(); + mSpanCount = spanCount; + mRemainingSpans = new BitSet(mSpanCount); + mSpans = new Span[mSpanCount]; + for (int i = 0; i < mSpanCount; i++) { + mSpans[i] = new Span(i); + } + requestLayout(); + } + } + + /** + * Sets the orientation of the layout. StaggeredGridLayoutManager will do its best to keep + * scroll position if this method is called after views are laid out. + * + * @param orientation {@link #HORIZONTAL} or {@link #VERTICAL} + */ + public void setOrientation(int orientation) { + if (orientation != HORIZONTAL && orientation != VERTICAL) { + throw new IllegalArgumentException("invalid orientation."); + } + assertNotInLayoutOrScroll(null); + if (orientation == mOrientation) { + return; + } + mOrientation = orientation; + OrientationHelper tmp = mPrimaryOrientation; + mPrimaryOrientation = mSecondaryOrientation; + mSecondaryOrientation = tmp; + requestLayout(); + } + + /** + * Sets whether LayoutManager should start laying out items from the end of the UI. The order + * items are traversed is not affected by this call. + *

+ * For vertical layout, if it is set to true, first item will be at the bottom of + * the list. + *

+ * For horizontal layouts, it depends on the layout direction. + * When set to true, If {@link RecyclerView} is LTR, than it will layout from RTL, if + * {@link RecyclerView}} is RTL, it will layout from LTR. + * + * @param reverseLayout Whether layout should be in reverse or not + */ + public void setReverseLayout(boolean reverseLayout) { + assertNotInLayoutOrScroll(null); + if (mPendingSavedState != null && mPendingSavedState.mReverseLayout != reverseLayout) { + mPendingSavedState.mReverseLayout = reverseLayout; + } + mReverseLayout = reverseLayout; + requestLayout(); + } + + /** + * Returns the current gap handling strategy for StaggeredGridLayoutManager. + *

+ * Staggered grid may have gaps in the layout due to changes in the adapter. To avoid gaps, + * StaggeredGridLayoutManager provides 2 options. Check {@link #GAP_HANDLING_NONE} and + * {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS} for details. + *

+ * By default, StaggeredGridLayoutManager uses {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS}. + * + * @return Current gap handling strategy. + * @see #setGapStrategy(int) + * @see #GAP_HANDLING_NONE + * @see #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS + */ + public int getGapStrategy() { + return mGapStrategy; + } + + /** + * Sets the gap handling strategy for StaggeredGridLayoutManager. If the gapStrategy parameter + * is different than the current strategy, calling this method will trigger a layout request. + * + * @param gapStrategy The new gap handling strategy. Should be + * {@link #GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS} or {@link + * #GAP_HANDLING_NONE}. + * @see #getGapStrategy() + */ + public void setGapStrategy(int gapStrategy) { + assertNotInLayoutOrScroll(null); + if (gapStrategy == mGapStrategy) { + return; + } + if (gapStrategy != GAP_HANDLING_NONE && + gapStrategy != GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS) { + throw new IllegalArgumentException("invalid gap strategy. Must be GAP_HANDLING_NONE " + + "or GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS"); + } + mGapStrategy = gapStrategy; + setAutoMeasureEnabled(mGapStrategy != GAP_HANDLING_NONE); + requestLayout(); + } + + @Override + public void assertNotInLayoutOrScroll(String message) { + if (mPendingSavedState == null) { + super.assertNotInLayoutOrScroll(message); + } + } + + /** + * Returns the number of spans laid out by StaggeredGridLayoutManager. + * + * @return Number of spans in the layout + */ + public int getSpanCount() { + return mSpanCount; + } + + /** + * For consistency, StaggeredGridLayoutManager keeps a mapping between spans and items. + *

+ * If you need to cancel current assignments, you can call this method which will clear all + * assignments and request a new layout. + */ + public void invalidateSpanAssignments() { + mLazySpanLookup.clear(); + requestLayout(); + } + + /** + * Calculates the views' layout order. (e.g. from end to start or start to end) + * RTL layout support is applied automatically. So if layout is RTL and + * {@link #getReverseLayout()} is {@code true}, elements will be laid out starting from left. + */ + private void resolveShouldLayoutReverse() { + // A == B is the same result, but we rather keep it readable + if (mOrientation == VERTICAL || !isLayoutRTL()) { + mShouldReverseLayout = mReverseLayout; + } else { + mShouldReverseLayout = !mReverseLayout; + } + } + + boolean isLayoutRTL() { + return getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL; + } + + /** + * Returns whether views are laid out in reverse order or not. + *

+ * Not that this value is not affected by RecyclerView's layout direction. + * + * @return True if layout is reversed, false otherwise + * @see #setReverseLayout(boolean) + */ + public boolean getReverseLayout() { + return mReverseLayout; + } + + @Override + public void setMeasuredDimension(Rect childrenBounds, int wSpec, int hSpec) { + // we don't like it to wrap content in our non-scroll direction. + final int width, height; + final int horizontalPadding = getPaddingLeft() + getPaddingRight(); + final int verticalPadding = getPaddingTop() + getPaddingBottom(); + if (mOrientation == VERTICAL) { + final int usedHeight = childrenBounds.height() + verticalPadding; + height = chooseSize(hSpec, usedHeight, getMinimumHeight()); + width = chooseSize(wSpec, mSizePerSpan * mSpanCount + horizontalPadding, + getMinimumWidth()); + } else { + final int usedWidth = childrenBounds.width() + horizontalPadding; + width = chooseSize(wSpec, usedWidth, getMinimumWidth()); + height = chooseSize(hSpec, mSizePerSpan * mSpanCount + verticalPadding, + getMinimumHeight()); + } + setMeasuredDimension(width, height); + } + + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + onLayoutChildren(recycler, state, true); + } + + + private void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state, + boolean shouldCheckForGaps) { + final AnchorInfo anchorInfo = mAnchorInfo; + anchorInfo.reset(); + + if (mPendingSavedState != null || mPendingScrollPosition != NO_POSITION) { + if (state.getItemCount() == 0) { + removeAndRecycleAllViews(recycler); + return; + } + } + + if (mPendingSavedState != null) { + applyPendingSavedState(anchorInfo); + } else { + resolveShouldLayoutReverse(); + anchorInfo.mLayoutFromEnd = mShouldReverseLayout; + } + + updateAnchorInfoForLayout(state, anchorInfo); + + if (mPendingSavedState == null) { + if (anchorInfo.mLayoutFromEnd != mLastLayoutFromEnd || + isLayoutRTL() != mLastLayoutRTL) { + mLazySpanLookup.clear(); + anchorInfo.mInvalidateOffsets = true; + } + } + + if (getChildCount() > 0 && (mPendingSavedState == null || + mPendingSavedState.mSpanOffsetsSize < 1)) { + if (anchorInfo.mInvalidateOffsets) { + for (int i = 0; i < mSpanCount; i++) { + // Scroll to position is set, clear. + mSpans[i].clear(); + if (anchorInfo.mOffset != INVALID_OFFSET) { + mSpans[i].setLine(anchorInfo.mOffset); + } + } + } else { + for (int i = 0; i < mSpanCount; i++) { + mSpans[i].cacheReferenceLineAndClear(mShouldReverseLayout, anchorInfo.mOffset); + } + } + } + detachAndScrapAttachedViews(recycler); + mLayoutState.mRecycle = false; + mLaidOutInvalidFullSpan = false; + updateMeasureSpecs(mSecondaryOrientation.getTotalSpace()); + updateLayoutState(anchorInfo.mPosition, state); + if (anchorInfo.mLayoutFromEnd) { + // Layout start. + setLayoutStateDirection(LAYOUT_START); + fill(recycler, mLayoutState, state); + // Layout end. + setLayoutStateDirection(LAYOUT_END); + mLayoutState.mCurrentPosition = anchorInfo.mPosition + mLayoutState.mItemDirection; + fill(recycler, mLayoutState, state); + } else { + // Layout end. + setLayoutStateDirection(LAYOUT_END); + fill(recycler, mLayoutState, state); + // Layout start. + setLayoutStateDirection(LAYOUT_START); + mLayoutState.mCurrentPosition = anchorInfo.mPosition + mLayoutState.mItemDirection; + fill(recycler, mLayoutState, state); + } + + repositionToWrapContentIfNecessary(); + + if (getChildCount() > 0) { + if (mShouldReverseLayout) { + fixEndGap(recycler, state, true); + fixStartGap(recycler, state, false); + } else { + fixStartGap(recycler, state, true); + fixEndGap(recycler, state, false); + } + } + boolean hasGaps = false; + if (shouldCheckForGaps && !state.isPreLayout()) { + final boolean needToCheckForGaps = mGapStrategy != GAP_HANDLING_NONE + && getChildCount() > 0 + && (mLaidOutInvalidFullSpan || hasGapsToFix() != null); + if (needToCheckForGaps) { + removeCallbacks(mCheckForGapsRunnable); + if (checkForGaps()) { + hasGaps = true; + } + } + mPendingScrollPosition = NO_POSITION; + mPendingScrollPositionOffset = INVALID_OFFSET; + } + mLastLayoutFromEnd = anchorInfo.mLayoutFromEnd; + mLastLayoutRTL = isLayoutRTL(); + mPendingSavedState = null; // we don't need this anymore + if (hasGaps) { + onLayoutChildren(recycler, state, false); + } + } + + private void repositionToWrapContentIfNecessary() { + if (mSecondaryOrientation.getMode() == View.MeasureSpec.EXACTLY) { + return; // nothing to do + } + float maxSize = 0; + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i ++) { + View child = getChildAt(i); + float size = mSecondaryOrientation.getDecoratedMeasurement(child); + if (size < maxSize) { + continue; + } + LayoutParams layoutParams = (LayoutParams) child.getLayoutParams(); + if (layoutParams.isFullSpan()) { + size = 1f * size / mSpanCount; + } + maxSize = Math.max(maxSize, size); + } + int before = mSizePerSpan; + int desired = Math.round(maxSize * mSpanCount); + if (mSecondaryOrientation.getMode() == View.MeasureSpec.AT_MOST) { + desired = Math.min(desired, mSecondaryOrientation.getTotalSpace()); + } + updateMeasureSpecs(desired); + if (mSizePerSpan == before) { + return; // nothing has changed + } + for (int i = 0; i < childCount; i ++) { + View child = getChildAt(i); + final LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (lp.mFullSpan) { + continue; + } + if (isLayoutRTL() && mOrientation == VERTICAL) { + int newOffset = -(mSpanCount - 1 - lp.mSpan.mIndex) * mSizePerSpan; + int prevOffset = -(mSpanCount - 1 - lp.mSpan.mIndex) * before; + child.offsetLeftAndRight(newOffset - prevOffset); + } else { + int newOffset = lp.mSpan.mIndex * mSizePerSpan; + int prevOffset = lp.mSpan.mIndex * before; + if (mOrientation == VERTICAL) { + child.offsetLeftAndRight(newOffset - prevOffset); + } else { + child.offsetTopAndBottom(newOffset - prevOffset); + } + } + } + } + + private void applyPendingSavedState(AnchorInfo anchorInfo) { + if (DEBUG) { + Log.d(TAG, "found saved state: " + mPendingSavedState); + } + if (mPendingSavedState.mSpanOffsetsSize > 0) { + if (mPendingSavedState.mSpanOffsetsSize == mSpanCount) { + for (int i = 0; i < mSpanCount; i++) { + mSpans[i].clear(); + int line = mPendingSavedState.mSpanOffsets[i]; + if (line != Span.INVALID_LINE) { + if (mPendingSavedState.mAnchorLayoutFromEnd) { + line += mPrimaryOrientation.getEndAfterPadding(); + } else { + line += mPrimaryOrientation.getStartAfterPadding(); + } + } + mSpans[i].setLine(line); + } + } else { + mPendingSavedState.invalidateSpanInfo(); + mPendingSavedState.mAnchorPosition = mPendingSavedState.mVisibleAnchorPosition; + } + } + mLastLayoutRTL = mPendingSavedState.mLastLayoutRTL; + setReverseLayout(mPendingSavedState.mReverseLayout); + resolveShouldLayoutReverse(); + + if (mPendingSavedState.mAnchorPosition != NO_POSITION) { + mPendingScrollPosition = mPendingSavedState.mAnchorPosition; + anchorInfo.mLayoutFromEnd = mPendingSavedState.mAnchorLayoutFromEnd; + } else { + anchorInfo.mLayoutFromEnd = mShouldReverseLayout; + } + if (mPendingSavedState.mSpanLookupSize > 1) { + mLazySpanLookup.mData = mPendingSavedState.mSpanLookup; + mLazySpanLookup.mFullSpanItems = mPendingSavedState.mFullSpanItems; + } + } + + void updateAnchorInfoForLayout(RecyclerView.State state, AnchorInfo anchorInfo) { + if (updateAnchorFromPendingData(state, anchorInfo)) { + return; + } + if (updateAnchorFromChildren(state, anchorInfo)) { + return; + } + if (DEBUG) { + Log.d(TAG, "Deciding anchor info from fresh state"); + } + anchorInfo.assignCoordinateFromPadding(); + anchorInfo.mPosition = 0; + } + + private boolean updateAnchorFromChildren(RecyclerView.State state, AnchorInfo anchorInfo) { + // We don't recycle views out of adapter order. This way, we can rely on the first or + // last child as the anchor position. + // Layout direction may change but we should select the child depending on the latest + // layout direction. Otherwise, we'll choose the wrong child. + anchorInfo.mPosition = mLastLayoutFromEnd + ? findLastReferenceChildPosition(state.getItemCount()) + : findFirstReferenceChildPosition(state.getItemCount()); + anchorInfo.mOffset = INVALID_OFFSET; + return true; + } + + boolean updateAnchorFromPendingData(RecyclerView.State state, AnchorInfo anchorInfo) { + // Validate scroll position if exists. + if (state.isPreLayout() || mPendingScrollPosition == NO_POSITION) { + return false; + } + // Validate it. + if (mPendingScrollPosition < 0 || mPendingScrollPosition >= state.getItemCount()) { + mPendingScrollPosition = NO_POSITION; + mPendingScrollPositionOffset = INVALID_OFFSET; + return false; + } + + if (mPendingSavedState == null || mPendingSavedState.mAnchorPosition == NO_POSITION + || mPendingSavedState.mSpanOffsetsSize < 1) { + // If item is visible, make it fully visible. + final View child = findViewByPosition(mPendingScrollPosition); + if (child != null) { + // Use regular anchor position, offset according to pending offset and target + // child + anchorInfo.mPosition = mShouldReverseLayout ? getLastChildPosition() + : getFirstChildPosition(); + + if (mPendingScrollPositionOffset != INVALID_OFFSET) { + if (anchorInfo.mLayoutFromEnd) { + final int target = mPrimaryOrientation.getEndAfterPadding() - + mPendingScrollPositionOffset; + anchorInfo.mOffset = target - mPrimaryOrientation.getDecoratedEnd(child); + } else { + final int target = mPrimaryOrientation.getStartAfterPadding() + + mPendingScrollPositionOffset; + anchorInfo.mOffset = target - mPrimaryOrientation.getDecoratedStart(child); + } + return true; + } + + // no offset provided. Decide according to the child location + final int childSize = mPrimaryOrientation.getDecoratedMeasurement(child); + if (childSize > mPrimaryOrientation.getTotalSpace()) { + // Item does not fit. Fix depending on layout direction. + anchorInfo.mOffset = anchorInfo.mLayoutFromEnd + ? mPrimaryOrientation.getEndAfterPadding() + : mPrimaryOrientation.getStartAfterPadding(); + return true; + } + + final int startGap = mPrimaryOrientation.getDecoratedStart(child) + - mPrimaryOrientation.getStartAfterPadding(); + if (startGap < 0) { + anchorInfo.mOffset = -startGap; + return true; + } + final int endGap = mPrimaryOrientation.getEndAfterPadding() - + mPrimaryOrientation.getDecoratedEnd(child); + if (endGap < 0) { + anchorInfo.mOffset = endGap; + return true; + } + // child already visible. just layout as usual + anchorInfo.mOffset = INVALID_OFFSET; + } else { + // Child is not visible. Set anchor coordinate depending on in which direction + // child will be visible. + anchorInfo.mPosition = mPendingScrollPosition; + if (mPendingScrollPositionOffset == INVALID_OFFSET) { + final int position = calculateScrollDirectionForPosition( + anchorInfo.mPosition); + anchorInfo.mLayoutFromEnd = position == LAYOUT_END; + anchorInfo.assignCoordinateFromPadding(); + } else { + anchorInfo.assignCoordinateFromPadding(mPendingScrollPositionOffset); + } + anchorInfo.mInvalidateOffsets = true; + } + } else { + anchorInfo.mOffset = INVALID_OFFSET; + anchorInfo.mPosition = mPendingScrollPosition; + } + return true; + } + + void updateMeasureSpecs(int totalSpace) { + mSizePerSpan = totalSpace / mSpanCount; + //noinspection ResourceType + mFullSizeSpec = View.MeasureSpec.makeMeasureSpec( + totalSpace, mSecondaryOrientation.getMode()); + } + + @Override + public boolean supportsPredictiveItemAnimations() { + return mPendingSavedState == null; + } + + /** + * Returns the adapter position of the first visible view for each span. + *

+ * Note that, this value is not affected by layout orientation or item order traversal. + * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, + * not in the layout. + *

+ * If RecyclerView has item decorators, they will be considered in calculations as well. + *

+ * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those + * views are ignored in this method. + * + * @param into An array to put the results into. If you don't provide any, LayoutManager will + * create a new one. + * @return The adapter position of the first visible item in each span. If a span does not have + * any items, {@link RecyclerView#NO_POSITION} is returned for that span. + * @see #findFirstCompletelyVisibleItemPositions(int[]) + * @see #findLastVisibleItemPositions(int[]) + */ + public int[] findFirstVisibleItemPositions(int[] into) { + if (into == null) { + into = new int[mSpanCount]; + } else if (into.length < mSpanCount) { + throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" + + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); + } + for (int i = 0; i < mSpanCount; i++) { + into[i] = mSpans[i].findFirstVisibleItemPosition(); + } + return into; + } + + /** + * Returns the adapter position of the first completely visible view for each span. + *

+ * Note that, this value is not affected by layout orientation or item order traversal. + * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, + * not in the layout. + *

+ * If RecyclerView has item decorators, they will be considered in calculations as well. + *

+ * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those + * views are ignored in this method. + * + * @param into An array to put the results into. If you don't provide any, LayoutManager will + * create a new one. + * @return The adapter position of the first fully visible item in each span. If a span does + * not have any items, {@link RecyclerView#NO_POSITION} is returned for that span. + * @see #findFirstVisibleItemPositions(int[]) + * @see #findLastCompletelyVisibleItemPositions(int[]) + */ + public int[] findFirstCompletelyVisibleItemPositions(int[] into) { + if (into == null) { + into = new int[mSpanCount]; + } else if (into.length < mSpanCount) { + throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" + + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); + } + for (int i = 0; i < mSpanCount; i++) { + into[i] = mSpans[i].findFirstCompletelyVisibleItemPosition(); + } + return into; + } + + /** + * Returns the adapter position of the last visible view for each span. + *

+ * Note that, this value is not affected by layout orientation or item order traversal. + * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, + * not in the layout. + *

+ * If RecyclerView has item decorators, they will be considered in calculations as well. + *

+ * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those + * views are ignored in this method. + * + * @param into An array to put the results into. If you don't provide any, LayoutManager will + * create a new one. + * @return The adapter position of the last visible item in each span. If a span does not have + * any items, {@link RecyclerView#NO_POSITION} is returned for that span. + * @see #findLastCompletelyVisibleItemPositions(int[]) + * @see #findFirstVisibleItemPositions(int[]) + */ + public int[] findLastVisibleItemPositions(int[] into) { + if (into == null) { + into = new int[mSpanCount]; + } else if (into.length < mSpanCount) { + throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" + + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); + } + for (int i = 0; i < mSpanCount; i++) { + into[i] = mSpans[i].findLastVisibleItemPosition(); + } + return into; + } + + /** + * Returns the adapter position of the last completely visible view for each span. + *

+ * Note that, this value is not affected by layout orientation or item order traversal. + * ({@link #setReverseLayout(boolean)}). Views are sorted by their positions in the adapter, + * not in the layout. + *

+ * If RecyclerView has item decorators, they will be considered in calculations as well. + *

+ * StaggeredGridLayoutManager may pre-cache some views that are not necessarily visible. Those + * views are ignored in this method. + * + * @param into An array to put the results into. If you don't provide any, LayoutManager will + * create a new one. + * @return The adapter position of the last fully visible item in each span. If a span does not + * have any items, {@link RecyclerView#NO_POSITION} is returned for that span. + * @see #findFirstCompletelyVisibleItemPositions(int[]) + * @see #findLastVisibleItemPositions(int[]) + */ + public int[] findLastCompletelyVisibleItemPositions(int[] into) { + if (into == null) { + into = new int[mSpanCount]; + } else if (into.length < mSpanCount) { + throw new IllegalArgumentException("Provided int[]'s size must be more than or equal" + + " to span count. Expected:" + mSpanCount + ", array size:" + into.length); + } + for (int i = 0; i < mSpanCount; i++) { + into[i] = mSpans[i].findLastCompletelyVisibleItemPosition(); + } + return into; + } + + @Override + public int computeHorizontalScrollOffset(RecyclerView.State state) { + return computeScrollOffset(state); + } + + private int computeScrollOffset(RecyclerView.State state) { + if (getChildCount() == 0) { + return 0; + } + return ScrollbarHelper.computeScrollOffset(state, mPrimaryOrientation, + findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true) + , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true), + this, mSmoothScrollbarEnabled, mShouldReverseLayout); + } + + @Override + public int computeVerticalScrollOffset(RecyclerView.State state) { + return computeScrollOffset(state); + } + + @Override + public int computeHorizontalScrollExtent(RecyclerView.State state) { + return computeScrollExtent(state); + } + + private int computeScrollExtent(RecyclerView.State state) { + if (getChildCount() == 0) { + return 0; + } + return ScrollbarHelper.computeScrollExtent(state, mPrimaryOrientation, + findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true) + , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true), + this, mSmoothScrollbarEnabled); + } + + @Override + public int computeVerticalScrollExtent(RecyclerView.State state) { + return computeScrollExtent(state); + } + + @Override + public int computeHorizontalScrollRange(RecyclerView.State state) { + return computeScrollRange(state); + } + + private int computeScrollRange(RecyclerView.State state) { + if (getChildCount() == 0) { + return 0; + } + return ScrollbarHelper.computeScrollRange(state, mPrimaryOrientation, + findFirstVisibleItemClosestToStart(!mSmoothScrollbarEnabled, true) + , findFirstVisibleItemClosestToEnd(!mSmoothScrollbarEnabled, true), + this, mSmoothScrollbarEnabled); + } + + @Override + public int computeVerticalScrollRange(RecyclerView.State state) { + return computeScrollRange(state); + } + + private void measureChildWithDecorationsAndMargin(View child, LayoutParams lp, + boolean alreadyMeasured) { + if (lp.mFullSpan) { + if (mOrientation == VERTICAL) { + measureChildWithDecorationsAndMargin(child, mFullSizeSpec, + getChildMeasureSpec(getHeight(), getHeightMode(), 0, lp.height, true), + alreadyMeasured); + } else { + measureChildWithDecorationsAndMargin(child, + getChildMeasureSpec(getWidth(), getWidthMode(), 0, lp.width, true), + mFullSizeSpec, alreadyMeasured); + } + } else { + if (mOrientation == VERTICAL) { + measureChildWithDecorationsAndMargin(child, + getChildMeasureSpec(mSizePerSpan, getWidthMode(), 0, lp.width, false), + getChildMeasureSpec(getHeight(), getHeightMode(), 0, lp.height, true), + alreadyMeasured); + } else { + measureChildWithDecorationsAndMargin(child, + getChildMeasureSpec(getWidth(), getWidthMode(), 0, lp.width, true), + getChildMeasureSpec(mSizePerSpan, getHeightMode(), 0, lp.height, false), + alreadyMeasured); + } + } + } + + private void measureChildWithDecorationsAndMargin(View child, int widthSpec, + int heightSpec, boolean alreadyMeasured) { + calculateItemDecorationsForChild(child, mTmpRect); + LayoutParams lp = (LayoutParams) child.getLayoutParams(); + widthSpec = updateSpecWithExtra(widthSpec, lp.leftMargin + mTmpRect.left, + lp.rightMargin + mTmpRect.right); + heightSpec = updateSpecWithExtra(heightSpec, lp.topMargin + mTmpRect.top, + lp.bottomMargin + mTmpRect.bottom); + final boolean measure = alreadyMeasured + ? shouldReMeasureChild(child, widthSpec, heightSpec, lp) + : shouldMeasureChild(child, widthSpec, heightSpec, lp); + if (measure) { + child.measure(widthSpec, heightSpec); + } + + } + + private int updateSpecWithExtra(int spec, int startInset, int endInset) { + if (startInset == 0 && endInset == 0) { + return spec; + } + final int mode = View.MeasureSpec.getMode(spec); + if (mode == View.MeasureSpec.AT_MOST || mode == View.MeasureSpec.EXACTLY) { + return View.MeasureSpec.makeMeasureSpec( + Math.max(0, View.MeasureSpec.getSize(spec) - startInset - endInset), mode); + } + return spec; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + if (state instanceof SavedState) { + mPendingSavedState = (SavedState) state; + requestLayout(); + } else if (DEBUG) { + Log.d(TAG, "invalid saved state class"); + } + } + + @Override + public Parcelable onSaveInstanceState() { + if (mPendingSavedState != null) { + return new SavedState(mPendingSavedState); + } + SavedState state = new SavedState(); + state.mReverseLayout = mReverseLayout; + state.mAnchorLayoutFromEnd = mLastLayoutFromEnd; + state.mLastLayoutRTL = mLastLayoutRTL; + + if (mLazySpanLookup != null && mLazySpanLookup.mData != null) { + state.mSpanLookup = mLazySpanLookup.mData; + state.mSpanLookupSize = state.mSpanLookup.length; + state.mFullSpanItems = mLazySpanLookup.mFullSpanItems; + } else { + state.mSpanLookupSize = 0; + } + + if (getChildCount() > 0) { + state.mAnchorPosition = mLastLayoutFromEnd ? getLastChildPosition() + : getFirstChildPosition(); + state.mVisibleAnchorPosition = findFirstVisibleItemPositionInt(); + state.mSpanOffsetsSize = mSpanCount; + state.mSpanOffsets = new int[mSpanCount]; + for (int i = 0; i < mSpanCount; i++) { + int line; + if (mLastLayoutFromEnd) { + line = mSpans[i].getEndLine(Span.INVALID_LINE); + if (line != Span.INVALID_LINE) { + line -= mPrimaryOrientation.getEndAfterPadding(); + } + } else { + line = mSpans[i].getStartLine(Span.INVALID_LINE); + if (line != Span.INVALID_LINE) { + line -= mPrimaryOrientation.getStartAfterPadding(); + } + } + state.mSpanOffsets[i] = line; + } + } else { + state.mAnchorPosition = NO_POSITION; + state.mVisibleAnchorPosition = NO_POSITION; + state.mSpanOffsetsSize = 0; + } + if (DEBUG) { + Log.d(TAG, "saved state:\n" + state); + } + return state; + } + + @Override + public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler, + RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) { + ViewGroup.LayoutParams lp = host.getLayoutParams(); + if (!(lp instanceof LayoutParams)) { + super.onInitializeAccessibilityNodeInfoForItem(host, info); + return; + } + LayoutParams sglp = (LayoutParams) lp; + if (mOrientation == HORIZONTAL) { + info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain( + sglp.getSpanIndex(), sglp.mFullSpan ? mSpanCount : 1, + -1, -1, + sglp.mFullSpan, false)); + } else { // VERTICAL + info.setCollectionItemInfo(AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain( + -1, -1, + sglp.getSpanIndex(), sglp.mFullSpan ? mSpanCount : 1, + sglp.mFullSpan, false)); + } + } + + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + if (getChildCount() > 0) { + final AccessibilityRecordCompat record = AccessibilityEventCompat + .asRecord(event); + final View start = findFirstVisibleItemClosestToStart(false, true); + final View end = findFirstVisibleItemClosestToEnd(false, true); + if (start == null || end == null) { + return; + } + final int startPos = getPosition(start); + final int endPos = getPosition(end); + if (startPos < endPos) { + record.setFromIndex(startPos); + record.setToIndex(endPos); + } else { + record.setFromIndex(endPos); + record.setToIndex(startPos); + } + } + } + + /** + * Finds the first fully visible child to be used as an anchor child if span count changes when + * state is restored. If no children is fully visible, returns a partially visible child instead + * of returning null. + */ + int findFirstVisibleItemPositionInt() { + final View first = mShouldReverseLayout ? findFirstVisibleItemClosestToEnd(true, true) : + findFirstVisibleItemClosestToStart(true, true); + return first == null ? NO_POSITION : getPosition(first); + } + + @Override + public int getRowCountForAccessibility(RecyclerView.Recycler recycler, + RecyclerView.State state) { + if (mOrientation == HORIZONTAL) { + return mSpanCount; + } + return super.getRowCountForAccessibility(recycler, state); + } + + @Override + public int getColumnCountForAccessibility(RecyclerView.Recycler recycler, + RecyclerView.State state) { + if (mOrientation == VERTICAL) { + return mSpanCount; + } + return super.getColumnCountForAccessibility(recycler, state); + } + + /** + * This is for internal use. Not necessarily the child closest to start but the first child + * we find that matches the criteria. + * This method does not do any sorting based on child's start coordinate, instead, it uses + * children order. + */ + View findFirstVisibleItemClosestToStart(boolean fullyVisible, boolean acceptPartiallyVisible) { + final int boundsStart = mPrimaryOrientation.getStartAfterPadding(); + final int boundsEnd = mPrimaryOrientation.getEndAfterPadding(); + final int limit = getChildCount(); + View partiallyVisible = null; + for (int i = 0; i < limit; i++) { + final View child = getChildAt(i); + final int childStart = mPrimaryOrientation.getDecoratedStart(child); + final int childEnd = mPrimaryOrientation.getDecoratedEnd(child); + if(childEnd <= boundsStart || childStart >= boundsEnd) { + continue; // not visible at all + } + if (childStart >= boundsStart || !fullyVisible) { + // when checking for start, it is enough even if part of the child's top is visible + // as long as fully visible is not requested. + return child; + } + if (acceptPartiallyVisible && partiallyVisible == null) { + partiallyVisible = child; + } + } + return partiallyVisible; + } + + /** + * This is for internal use. Not necessarily the child closest to bottom but the first child + * we find that matches the criteria. + * This method does not do any sorting based on child's end coordinate, instead, it uses + * children order. + */ + View findFirstVisibleItemClosestToEnd(boolean fullyVisible, boolean acceptPartiallyVisible) { + final int boundsStart = mPrimaryOrientation.getStartAfterPadding(); + final int boundsEnd = mPrimaryOrientation.getEndAfterPadding(); + View partiallyVisible = null; + for (int i = getChildCount() - 1; i >= 0; i--) { + final View child = getChildAt(i); + final int childStart = mPrimaryOrientation.getDecoratedStart(child); + final int childEnd = mPrimaryOrientation.getDecoratedEnd(child); + if(childEnd <= boundsStart || childStart >= boundsEnd) { + continue; // not visible at all + } + if (childEnd <= boundsEnd || !fullyVisible) { + // when checking for end, it is enough even if part of the child's bottom is visible + // as long as fully visible is not requested. + return child; + } + if (acceptPartiallyVisible && partiallyVisible == null) { + partiallyVisible = child; + } + } + return partiallyVisible; + } + + private void fixEndGap(RecyclerView.Recycler recycler, RecyclerView.State state, + boolean canOffsetChildren) { + final int maxEndLine = getMaxEnd(Integer.MIN_VALUE); + if (maxEndLine == Integer.MIN_VALUE) { + return; + } + int gap = mPrimaryOrientation.getEndAfterPadding() - maxEndLine; + int fixOffset; + if (gap > 0) { + fixOffset = -scrollBy(-gap, recycler, state); + } else { + return; // nothing to fix + } + gap -= fixOffset; + if (canOffsetChildren && gap > 0) { + mPrimaryOrientation.offsetChildren(gap); + } + } + + private void fixStartGap(RecyclerView.Recycler recycler, RecyclerView.State state, + boolean canOffsetChildren) { + final int minStartLine = getMinStart(Integer.MAX_VALUE); + if (minStartLine == Integer.MAX_VALUE) { + return; + } + int gap = minStartLine - mPrimaryOrientation.getStartAfterPadding(); + int fixOffset; + if (gap > 0) { + fixOffset = scrollBy(gap, recycler, state); + } else { + return; // nothing to fix + } + gap -= fixOffset; + if (canOffsetChildren && gap > 0) { + mPrimaryOrientation.offsetChildren(-gap); + } + } + + private void updateLayoutState(int anchorPosition, RecyclerView.State state) { + mLayoutState.mAvailable = 0; + mLayoutState.mCurrentPosition = anchorPosition; + int startExtra = 0; + int endExtra = 0; + if (isSmoothScrolling()) { + final int targetPos = state.getTargetScrollPosition(); + if (targetPos != NO_POSITION) { + if (mShouldReverseLayout == targetPos < anchorPosition) { + endExtra = mPrimaryOrientation.getTotalSpace(); + } else { + startExtra = mPrimaryOrientation.getTotalSpace(); + } + } + } + + // Line of the furthest row. + final boolean clipToPadding = getClipToPadding(); + if (clipToPadding) { + mLayoutState.mStartLine = mPrimaryOrientation.getStartAfterPadding() - startExtra; + mLayoutState.mEndLine = mPrimaryOrientation.getEndAfterPadding() + endExtra; + } else { + mLayoutState.mEndLine = mPrimaryOrientation.getEnd() + endExtra; + mLayoutState.mStartLine = -startExtra; + } + mLayoutState.mStopInFocusable = false; + mLayoutState.mRecycle = true; + mLayoutState.mInfinite = mPrimaryOrientation.getMode() == View.MeasureSpec.UNSPECIFIED && + mPrimaryOrientation.getEnd() == 0; + } + + private void setLayoutStateDirection(int direction) { + mLayoutState.mLayoutDirection = direction; + mLayoutState.mItemDirection = (mShouldReverseLayout == (direction == LAYOUT_START)) ? + ITEM_DIRECTION_TAIL : ITEM_DIRECTION_HEAD; + } + + @Override + public void offsetChildrenHorizontal(int dx) { + super.offsetChildrenHorizontal(dx); + for (int i = 0; i < mSpanCount; i++) { + mSpans[i].onOffset(dx); + } + } + + @Override + public void offsetChildrenVertical(int dy) { + super.offsetChildrenVertical(dy); + for (int i = 0; i < mSpanCount; i++) { + mSpans[i].onOffset(dy); + } + } + + @Override + public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) { + handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.REMOVE); + } + + @Override + public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) { + handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.ADD); + } + + @Override + public void onItemsChanged(RecyclerView recyclerView) { + mLazySpanLookup.clear(); + requestLayout(); + } + + @Override + public void onItemsMoved(RecyclerView recyclerView, int from, int to, int itemCount) { + handleUpdate(from, to, AdapterHelper.UpdateOp.MOVE); + } + + @Override + public void onItemsUpdated(RecyclerView recyclerView, int positionStart, int itemCount, + Object payload) { + handleUpdate(positionStart, itemCount, AdapterHelper.UpdateOp.UPDATE); + } + + /** + * Checks whether it should invalidate span assignments in response to an adapter change. + */ + private void handleUpdate(int positionStart, int itemCountOrToPosition, int cmd) { + int minPosition = mShouldReverseLayout ? getLastChildPosition() : getFirstChildPosition(); + final int affectedRangeEnd;// exclusive + final int affectedRangeStart;// inclusive + + if (cmd == AdapterHelper.UpdateOp.MOVE) { + if (positionStart < itemCountOrToPosition) { + affectedRangeEnd = itemCountOrToPosition + 1; + affectedRangeStart = positionStart; + } else { + affectedRangeEnd = positionStart + 1; + affectedRangeStart = itemCountOrToPosition; + } + } else { + affectedRangeStart = positionStart; + affectedRangeEnd = positionStart + itemCountOrToPosition; + } + + mLazySpanLookup.invalidateAfter(affectedRangeStart); + switch (cmd) { + case AdapterHelper.UpdateOp.ADD: + mLazySpanLookup.offsetForAddition(positionStart, itemCountOrToPosition); + break; + case AdapterHelper.UpdateOp.REMOVE: + mLazySpanLookup.offsetForRemoval(positionStart, itemCountOrToPosition); + break; + case AdapterHelper.UpdateOp.MOVE: + // TODO optimize + mLazySpanLookup.offsetForRemoval(positionStart, 1); + mLazySpanLookup.offsetForAddition(itemCountOrToPosition, 1); + break; + } + + if (affectedRangeEnd <= minPosition) { + return; + } + + int maxPosition = mShouldReverseLayout ? getFirstChildPosition() : getLastChildPosition(); + if (affectedRangeStart <= maxPosition) { + requestLayout(); + } + } + + private int fill(RecyclerView.Recycler recycler, LayoutState layoutState, + RecyclerView.State state) { + mRemainingSpans.set(0, mSpanCount, true); + // The target position we are trying to reach. + final int targetLine; + + // Line of the furthest row. + if (mLayoutState.mInfinite) { + if (layoutState.mLayoutDirection == LAYOUT_END) { + targetLine = Integer.MAX_VALUE; + } else { // LAYOUT_START + targetLine = Integer.MIN_VALUE; + } + } else { + if (layoutState.mLayoutDirection == LAYOUT_END) { + targetLine = layoutState.mEndLine + layoutState.mAvailable; + } else { // LAYOUT_START + targetLine = layoutState.mStartLine - layoutState.mAvailable; + } + } + + updateAllRemainingSpans(layoutState.mLayoutDirection, targetLine); + if (DEBUG) { + Log.d(TAG, "FILLING targetLine: " + targetLine + "," + + "remaining spans:" + mRemainingSpans + ", state: " + layoutState); + } + + // the default coordinate to add new view. + final int defaultNewViewLine = mShouldReverseLayout + ? mPrimaryOrientation.getEndAfterPadding() + : mPrimaryOrientation.getStartAfterPadding(); + boolean added = false; + while (layoutState.hasMore(state) + && (mLayoutState.mInfinite || !mRemainingSpans.isEmpty())) { + View view = layoutState.next(recycler); + LayoutParams lp = ((LayoutParams) view.getLayoutParams()); + final int position = lp.getViewLayoutPosition(); + final int spanIndex = mLazySpanLookup.getSpan(position); + Span currentSpan; + final boolean assignSpan = spanIndex == LayoutParams.INVALID_SPAN_ID; + if (assignSpan) { + currentSpan = lp.mFullSpan ? mSpans[0] : getNextSpan(layoutState); + mLazySpanLookup.setSpan(position, currentSpan); + if (DEBUG) { + Log.d(TAG, "assigned " + currentSpan.mIndex + " for " + position); + } + } else { + if (DEBUG) { + Log.d(TAG, "using " + spanIndex + " for pos " + position); + } + currentSpan = mSpans[spanIndex]; + } + // assign span before measuring so that item decorators can get updated span index + lp.mSpan = currentSpan; + if (layoutState.mLayoutDirection == LAYOUT_END) { + addView(view); + } else { + addView(view, 0); + } + measureChildWithDecorationsAndMargin(view, lp, false); + + final int start; + final int end; + if (layoutState.mLayoutDirection == LAYOUT_END) { + start = lp.mFullSpan ? getMaxEnd(defaultNewViewLine) + : currentSpan.getEndLine(defaultNewViewLine); + end = start + mPrimaryOrientation.getDecoratedMeasurement(view); + if (assignSpan && lp.mFullSpan) { + LazySpanLookup.FullSpanItem fullSpanItem; + fullSpanItem = createFullSpanItemFromEnd(start); + fullSpanItem.mGapDir = LAYOUT_START; + fullSpanItem.mPosition = position; + mLazySpanLookup.addFullSpanItem(fullSpanItem); + } + } else { + end = lp.mFullSpan ? getMinStart(defaultNewViewLine) + : currentSpan.getStartLine(defaultNewViewLine); + start = end - mPrimaryOrientation.getDecoratedMeasurement(view); + if (assignSpan && lp.mFullSpan) { + LazySpanLookup.FullSpanItem fullSpanItem; + fullSpanItem = createFullSpanItemFromStart(end); + fullSpanItem.mGapDir = LAYOUT_END; + fullSpanItem.mPosition = position; + mLazySpanLookup.addFullSpanItem(fullSpanItem); + } + } + + // check if this item may create gaps in the future + if (lp.mFullSpan && layoutState.mItemDirection == ITEM_DIRECTION_HEAD) { + if (assignSpan) { + mLaidOutInvalidFullSpan = true; + } else { + final boolean hasInvalidGap; + if (layoutState.mLayoutDirection == LAYOUT_END) { + hasInvalidGap = !areAllEndsEqual(); + } else { // layoutState.mLayoutDirection == LAYOUT_START + hasInvalidGap = !areAllStartsEqual(); + } + if (hasInvalidGap) { + final LazySpanLookup.FullSpanItem fullSpanItem = mLazySpanLookup + .getFullSpanItem(position); + if (fullSpanItem != null) { + fullSpanItem.mHasUnwantedGapAfter = true; + } + mLaidOutInvalidFullSpan = true; + } + } + } + attachViewToSpans(view, lp, layoutState); + final int otherStart; + final int otherEnd; + if (isLayoutRTL() && mOrientation == VERTICAL) { + otherEnd = lp.mFullSpan ? mSecondaryOrientation.getEndAfterPadding() : + mSecondaryOrientation.getEndAfterPadding() + - (mSpanCount - 1 - currentSpan.mIndex) * mSizePerSpan; + otherStart = otherEnd - mSecondaryOrientation.getDecoratedMeasurement(view); + } else { + otherStart = lp.mFullSpan ? mSecondaryOrientation.getStartAfterPadding() + : currentSpan.mIndex * mSizePerSpan + + mSecondaryOrientation.getStartAfterPadding(); + otherEnd = otherStart + mSecondaryOrientation.getDecoratedMeasurement(view); + } + + if (mOrientation == VERTICAL) { + layoutDecoratedWithMargins(view, otherStart, start, otherEnd, end); + } else { + layoutDecoratedWithMargins(view, start, otherStart, end, otherEnd); + } + + if (lp.mFullSpan) { + updateAllRemainingSpans(mLayoutState.mLayoutDirection, targetLine); + } else { + updateRemainingSpans(currentSpan, mLayoutState.mLayoutDirection, targetLine); + } + recycle(recycler, mLayoutState); + if (mLayoutState.mStopInFocusable && view.isFocusable()) { + if (lp.mFullSpan) { + mRemainingSpans.clear(); + } else { + mRemainingSpans.set(currentSpan.mIndex, false); + } + } + added = true; + } + if (!added) { + recycle(recycler, mLayoutState); + } + final int diff; + if (mLayoutState.mLayoutDirection == LAYOUT_START) { + final int minStart = getMinStart(mPrimaryOrientation.getStartAfterPadding()); + diff = mPrimaryOrientation.getStartAfterPadding() - minStart; + } else { + final int maxEnd = getMaxEnd(mPrimaryOrientation.getEndAfterPadding()); + diff = maxEnd - mPrimaryOrientation.getEndAfterPadding(); + } + return diff > 0 ? Math.min(layoutState.mAvailable, diff) : 0; + } + + private LazySpanLookup.FullSpanItem createFullSpanItemFromEnd(int newItemTop) { + LazySpanLookup.FullSpanItem fsi = new LazySpanLookup.FullSpanItem(); + fsi.mGapPerSpan = new int[mSpanCount]; + for (int i = 0; i < mSpanCount; i++) { + fsi.mGapPerSpan[i] = newItemTop - mSpans[i].getEndLine(newItemTop); + } + return fsi; + } + + private LazySpanLookup.FullSpanItem createFullSpanItemFromStart(int newItemBottom) { + LazySpanLookup.FullSpanItem fsi = new LazySpanLookup.FullSpanItem(); + fsi.mGapPerSpan = new int[mSpanCount]; + for (int i = 0; i < mSpanCount; i++) { + fsi.mGapPerSpan[i] = mSpans[i].getStartLine(newItemBottom) - newItemBottom; + } + return fsi; + } + + private void attachViewToSpans(View view, LayoutParams lp, LayoutState layoutState) { + if (layoutState.mLayoutDirection == LayoutState.LAYOUT_END) { + if (lp.mFullSpan) { + appendViewToAllSpans(view); + } else { + lp.mSpan.appendToSpan(view); + } + } else { + if (lp.mFullSpan) { + prependViewToAllSpans(view); + } else { + lp.mSpan.prependToSpan(view); + } + } + } + + private void recycle(RecyclerView.Recycler recycler, LayoutState layoutState) { + if (!layoutState.mRecycle || layoutState.mInfinite) { + return; + } + if (layoutState.mAvailable == 0) { + // easy, recycle line is still valid + if (layoutState.mLayoutDirection == LAYOUT_START) { + recycleFromEnd(recycler, layoutState.mEndLine); + } else { + recycleFromStart(recycler, layoutState.mStartLine); + } + } else { + // scrolling case, recycle line can be shifted by how much space we could cover + // by adding new views + if (layoutState.mLayoutDirection == LAYOUT_START) { + // calculate recycle line + int scrolled = layoutState.mStartLine - getMaxStart(layoutState.mStartLine); + final int line; + if (scrolled < 0) { + line = layoutState.mEndLine; + } else { + line = layoutState.mEndLine - Math.min(scrolled, layoutState.mAvailable); + } + recycleFromEnd(recycler, line); + } else { + // calculate recycle line + int scrolled = getMinEnd(layoutState.mEndLine) - layoutState.mEndLine; + final int line; + if (scrolled < 0) { + line = layoutState.mStartLine; + } else { + line = layoutState.mStartLine + Math.min(scrolled, layoutState.mAvailable); + } + recycleFromStart(recycler, line); + } + } + + } + + private void appendViewToAllSpans(View view) { + // traverse in reverse so that we end up assigning full span items to 0 + for (int i = mSpanCount - 1; i >= 0; i--) { + mSpans[i].appendToSpan(view); + } + } + + private void prependViewToAllSpans(View view) { + // traverse in reverse so that we end up assigning full span items to 0 + for (int i = mSpanCount - 1; i >= 0; i--) { + mSpans[i].prependToSpan(view); + } + } + + private void layoutDecoratedWithMargins(View child, int left, int top, int right, int bottom) { + LayoutParams lp = (LayoutParams) child.getLayoutParams(); + if (DEBUG) { + Log.d(TAG, "layout decorated pos: " + lp.getViewLayoutPosition() + ", span:" + + lp.getSpanIndex() + ", fullspan:" + lp.mFullSpan + + ". l:" + left + ",t:" + top + + ", r:" + right + ", b:" + bottom); + } + layoutDecorated(child, left + lp.leftMargin, top + lp.topMargin, right - lp.rightMargin + , bottom - lp.bottomMargin); + } + + private void updateAllRemainingSpans(int layoutDir, int targetLine) { + for (int i = 0; i < mSpanCount; i++) { + if (mSpans[i].mViews.isEmpty()) { + continue; + } + updateRemainingSpans(mSpans[i], layoutDir, targetLine); + } + } + + private void updateRemainingSpans(Span span, int layoutDir, int targetLine) { + final int deletedSize = span.getDeletedSize(); + if (layoutDir == LAYOUT_START) { + final int line = span.getStartLine(); + if (line + deletedSize <= targetLine) { + mRemainingSpans.set(span.mIndex, false); + } + } else { + final int line = span.getEndLine(); + if (line - deletedSize >= targetLine) { + mRemainingSpans.set(span.mIndex, false); + } + } + } + + private int getMaxStart(int def) { + int maxStart = mSpans[0].getStartLine(def); + for (int i = 1; i < mSpanCount; i++) { + final int spanStart = mSpans[i].getStartLine(def); + if (spanStart > maxStart) { + maxStart = spanStart; + } + } + return maxStart; + } + + private int getMinStart(int def) { + int minStart = mSpans[0].getStartLine(def); + for (int i = 1; i < mSpanCount; i++) { + final int spanStart = mSpans[i].getStartLine(def); + if (spanStart < minStart) { + minStart = spanStart; + } + } + return minStart; + } + + boolean areAllEndsEqual() { + int end = mSpans[0].getEndLine(Span.INVALID_LINE); + for (int i = 1; i < mSpanCount; i++) { + if (mSpans[i].getEndLine(Span.INVALID_LINE) != end) { + return false; + } + } + return true; + } + + boolean areAllStartsEqual() { + int start = mSpans[0].getStartLine(Span.INVALID_LINE); + for (int i = 1; i < mSpanCount; i++) { + if (mSpans[i].getStartLine(Span.INVALID_LINE) != start) { + return false; + } + } + return true; + } + + private int getMaxEnd(int def) { + int maxEnd = mSpans[0].getEndLine(def); + for (int i = 1; i < mSpanCount; i++) { + final int spanEnd = mSpans[i].getEndLine(def); + if (spanEnd > maxEnd) { + maxEnd = spanEnd; + } + } + return maxEnd; + } + + private int getMinEnd(int def) { + int minEnd = mSpans[0].getEndLine(def); + for (int i = 1; i < mSpanCount; i++) { + final int spanEnd = mSpans[i].getEndLine(def); + if (spanEnd < minEnd) { + minEnd = spanEnd; + } + } + return minEnd; + } + + private void recycleFromStart(RecyclerView.Recycler recycler, int line) { + while (getChildCount() > 0) { + View child = getChildAt(0); + if (mPrimaryOrientation.getDecoratedEnd(child) <= line) { + LayoutParams lp = (LayoutParams) child.getLayoutParams(); + // Don't recycle the last View in a span not to lose span's start/end lines + if (lp.mFullSpan) { + for (int j = 0; j < mSpanCount; j++) { + if (mSpans[j].mViews.size() == 1) { + return; + } + } + for (int j = 0; j < mSpanCount; j++) { + mSpans[j].popStart(); + } + } else { + if (lp.mSpan.mViews.size() == 1) { + return; + } + lp.mSpan.popStart(); + } + removeAndRecycleView(child, recycler); + } else { + return;// done + } + } + } + + private void recycleFromEnd(RecyclerView.Recycler recycler, int line) { + final int childCount = getChildCount(); + int i; + for (i = childCount - 1; i >= 0; i--) { + View child = getChildAt(i); + if (mPrimaryOrientation.getDecoratedStart(child) >= line) { + LayoutParams lp = (LayoutParams) child.getLayoutParams(); + // Don't recycle the last View in a span not to lose span's start/end lines + if (lp.mFullSpan) { + for (int j = 0; j < mSpanCount; j++) { + if (mSpans[j].mViews.size() == 1) { + return; + } + } + for (int j = 0; j < mSpanCount; j++) { + mSpans[j].popEnd(); + } + } else { + if (lp.mSpan.mViews.size() == 1) { + return; + } + lp.mSpan.popEnd(); + } + removeAndRecycleView(child, recycler); + } else { + return;// done + } + } + } + + /** + * @return True if last span is the first one we want to fill + */ + private boolean preferLastSpan(int layoutDir) { + if (mOrientation == HORIZONTAL) { + return (layoutDir == LAYOUT_START) != mShouldReverseLayout; + } + return ((layoutDir == LAYOUT_START) == mShouldReverseLayout) == isLayoutRTL(); + } + + /** + * Finds the span for the next view. + */ + private Span getNextSpan(LayoutState layoutState) { + final boolean preferLastSpan = preferLastSpan(layoutState.mLayoutDirection); + final int startIndex, endIndex, diff; + if (preferLastSpan) { + startIndex = mSpanCount - 1; + endIndex = -1; + diff = -1; + } else { + startIndex = 0; + endIndex = mSpanCount; + diff = 1; + } + if (layoutState.mLayoutDirection == LAYOUT_END) { + Span min = null; + int minLine = Integer.MAX_VALUE; + final int defaultLine = mPrimaryOrientation.getStartAfterPadding(); + for (int i = startIndex; i != endIndex; i += diff) { + final Span other = mSpans[i]; + int otherLine = other.getEndLine(defaultLine); + if (otherLine < minLine) { + min = other; + minLine = otherLine; + } + } + return min; + } else { + Span max = null; + int maxLine = Integer.MIN_VALUE; + final int defaultLine = mPrimaryOrientation.getEndAfterPadding(); + for (int i = startIndex; i != endIndex; i += diff) { + final Span other = mSpans[i]; + int otherLine = other.getStartLine(defaultLine); + if (otherLine > maxLine) { + max = other; + maxLine = otherLine; + } + } + return max; + } + } + + @Override + public boolean canScrollVertically() { + return mOrientation == VERTICAL; + } + + @Override + public boolean canScrollHorizontally() { + return mOrientation == HORIZONTAL; + } + + @Override + public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, + RecyclerView.State state) { + return scrollBy(dx, recycler, state); + } + + @Override + public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, + RecyclerView.State state) { + return scrollBy(dy, recycler, state); + } + + private int calculateScrollDirectionForPosition(int position) { + if (getChildCount() == 0) { + return mShouldReverseLayout ? LAYOUT_END : LAYOUT_START; + } + final int firstChildPos = getFirstChildPosition(); + return position < firstChildPos != mShouldReverseLayout ? LAYOUT_START : LAYOUT_END; + } + + @Override + public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, + int position) { + LinearSmoothScroller scroller = new LinearSmoothScroller(recyclerView.getContext()) { + @Override + public PointF computeScrollVectorForPosition(int targetPosition) { + final int direction = calculateScrollDirectionForPosition(targetPosition); + if (direction == 0) { + return null; + } + if (mOrientation == HORIZONTAL) { + return new PointF(direction, 0); + } else { + return new PointF(0, direction); + } + } + }; + scroller.setTargetPosition(position); + startSmoothScroll(scroller); + } + + @Override + public void scrollToPosition(int position) { + if (mPendingSavedState != null && mPendingSavedState.mAnchorPosition != position) { + mPendingSavedState.invalidateAnchorPositionInfo(); + } + mPendingScrollPosition = position; + mPendingScrollPositionOffset = INVALID_OFFSET; + requestLayout(); + } + + /** + * Scroll to the specified adapter position with the given offset from layout start. + *

+ * Note that scroll position change will not be reflected until the next layout call. + *

+ * If you are just trying to make a position visible, use {@link #scrollToPosition(int)}. + * + * @param position Index (starting at 0) of the reference item. + * @param offset The distance (in pixels) between the start edge of the item view and + * start edge of the RecyclerView. + * @see #setReverseLayout(boolean) + * @see #scrollToPosition(int) + */ + public void scrollToPositionWithOffset(int position, int offset) { + if (mPendingSavedState != null) { + mPendingSavedState.invalidateAnchorPositionInfo(); + } + mPendingScrollPosition = position; + mPendingScrollPositionOffset = offset; + requestLayout(); + } + + int scrollBy(int dt, RecyclerView.Recycler recycler, RecyclerView.State state) { + final int referenceChildPosition; + final int layoutDir; + if (dt > 0) { // layout towards end + layoutDir = LAYOUT_END; + referenceChildPosition = getLastChildPosition(); + } else { + layoutDir = LAYOUT_START; + referenceChildPosition = getFirstChildPosition(); + } + mLayoutState.mRecycle = true; + updateLayoutState(referenceChildPosition, state); + setLayoutStateDirection(layoutDir); + mLayoutState.mCurrentPosition = referenceChildPosition + mLayoutState.mItemDirection; + final int absDt = Math.abs(dt); + mLayoutState.mAvailable = absDt; + int consumed = fill(recycler, mLayoutState, state); + final int totalScroll; + if (absDt < consumed) { + totalScroll = dt; + } else if (dt < 0) { + totalScroll = -consumed; + } else { // dt > 0 + totalScroll = consumed; + } + if (DEBUG) { + Log.d(TAG, "asked " + dt + " scrolled" + totalScroll); + } + + mPrimaryOrientation.offsetChildren(-totalScroll); + // always reset this if we scroll for a proper save instance state + mLastLayoutFromEnd = mShouldReverseLayout; + return totalScroll; + } + + private int getLastChildPosition() { + final int childCount = getChildCount(); + return childCount == 0 ? 0 : getPosition(getChildAt(childCount - 1)); + } + + private int getFirstChildPosition() { + final int childCount = getChildCount(); + return childCount == 0 ? 0 : getPosition(getChildAt(0)); + } + + /** + * Finds the first View that can be used as an anchor View. + * + * @return Position of the View or 0 if it cannot find any such View. + */ + private int findFirstReferenceChildPosition(int itemCount) { + final int limit = getChildCount(); + for (int i = 0; i < limit; i++) { + final View view = getChildAt(i); + final int position = getPosition(view); + if (position >= 0 && position < itemCount) { + return position; + } + } + return 0; + } + + /** + * Finds the last View that can be used as an anchor View. + * + * @return Position of the View or 0 if it cannot find any such View. + */ + private int findLastReferenceChildPosition(int itemCount) { + for (int i = getChildCount() - 1; i >= 0; i--) { + final View view = getChildAt(i); + final int position = getPosition(view); + if (position >= 0 && position < itemCount) { + return position; + } + } + return 0; + } + + @SuppressWarnings("deprecation") + @Override + public RecyclerView.LayoutParams generateDefaultLayoutParams() { + if (mOrientation == HORIZONTAL) { + return new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.FILL_PARENT); + } else { + return new LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + } + } + + @Override + public RecyclerView.LayoutParams generateLayoutParams(Context c, AttributeSet attrs) { + return new LayoutParams(c, attrs); + } + + @Override + public RecyclerView.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) { + if (lp instanceof ViewGroup.MarginLayoutParams) { + return new LayoutParams((ViewGroup.MarginLayoutParams) lp); + } else { + return new LayoutParams(lp); + } + } + + @Override + public boolean checkLayoutParams(RecyclerView.LayoutParams lp) { + return lp instanceof LayoutParams; + } + + public int getOrientation() { + return mOrientation; + } + + @Nullable + @Override + public View onFocusSearchFailed(View focused, int direction, RecyclerView.Recycler recycler, + RecyclerView.State state) { + if (getChildCount() == 0) { + return null; + } + + final View directChild = findContainingItemView(focused); + if (directChild == null) { + return null; + } + + resolveShouldLayoutReverse(); + final int layoutDir = convertFocusDirectionToLayoutDirection(direction); + if (layoutDir == LayoutState.INVALID_LAYOUT) { + return null; + } + LayoutParams prevFocusLayoutParams = (LayoutParams) directChild.getLayoutParams(); + boolean prevFocusFullSpan = prevFocusLayoutParams.mFullSpan; + final Span prevFocusSpan = prevFocusLayoutParams.mSpan; + final int referenceChildPosition; + if (layoutDir == LAYOUT_END) { // layout towards end + referenceChildPosition = getLastChildPosition(); + } else { + referenceChildPosition = getFirstChildPosition(); + } + updateLayoutState(referenceChildPosition, state); + setLayoutStateDirection(layoutDir); + + mLayoutState.mCurrentPosition = referenceChildPosition + mLayoutState.mItemDirection; + mLayoutState.mAvailable = (int) (MAX_SCROLL_FACTOR * mPrimaryOrientation.getTotalSpace()); + mLayoutState.mStopInFocusable = true; + mLayoutState.mRecycle = false; + fill(recycler, mLayoutState, state); + mLastLayoutFromEnd = mShouldReverseLayout; + if (!prevFocusFullSpan) { + View view = prevFocusSpan.getFocusableViewAfter(referenceChildPosition, layoutDir); + if (view != null && view != directChild) { + return view; + } + } + // either could not find from the desired span or prev view is full span. + // traverse all spans + if (preferLastSpan(layoutDir)) { + for (int i = mSpanCount - 1; i >= 0; i --) { + View view = mSpans[i].getFocusableViewAfter(referenceChildPosition, layoutDir); + if (view != null && view != directChild) { + return view; + } + } + } else { + for (int i = 0; i < mSpanCount; i ++) { + View view = mSpans[i].getFocusableViewAfter(referenceChildPosition, layoutDir); + if (view != null && view != directChild) { + return view; + } + } + } + return null; + } + + /** + * Converts a focusDirection to orientation. + * + * @param focusDirection One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, + * {@link View#FOCUS_LEFT}, {@link View#FOCUS_RIGHT}, + * {@link View#FOCUS_BACKWARD}, {@link View#FOCUS_FORWARD} + * or 0 for not applicable + * @return {@link LayoutState#LAYOUT_START} or {@link LayoutState#LAYOUT_END} if focus direction + * is applicable to current state, {@link LayoutState#INVALID_LAYOUT} otherwise. + */ + private int convertFocusDirectionToLayoutDirection(int focusDirection) { + switch (focusDirection) { + case View.FOCUS_BACKWARD: + return LayoutState.LAYOUT_START; + case View.FOCUS_FORWARD: + return LayoutState.LAYOUT_END; + case View.FOCUS_UP: + return mOrientation == VERTICAL ? LayoutState.LAYOUT_START + : LayoutState.INVALID_LAYOUT; + case View.FOCUS_DOWN: + return mOrientation == VERTICAL ? LayoutState.LAYOUT_END + : LayoutState.INVALID_LAYOUT; + case View.FOCUS_LEFT: + return mOrientation == HORIZONTAL ? LayoutState.LAYOUT_START + : LayoutState.INVALID_LAYOUT; + case View.FOCUS_RIGHT: + return mOrientation == HORIZONTAL ? LayoutState.LAYOUT_END + : LayoutState.INVALID_LAYOUT; + default: + if (DEBUG) { + Log.d(TAG, "Unknown focus request:" + focusDirection); + } + return LayoutState.INVALID_LAYOUT; + } + + } + + /** + * LayoutParams used by StaggeredGridLayoutManager. + *

+ * Note that if the orientation is {@link #VERTICAL}, the width parameter is ignored and if the + * orientation is {@link #HORIZONTAL} the height parameter is ignored because child view is + * expected to fill all of the space given to it. + */ + public static class LayoutParams extends RecyclerView.LayoutParams { + + /** + * Span Id for Views that are not laid out yet. + */ + public static final int INVALID_SPAN_ID = -1; + + // Package scope to be able to access from tests. + Span mSpan; + + boolean mFullSpan; + + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + } + + public LayoutParams(int width, int height) { + super(width, height); + } + + public LayoutParams(ViewGroup.MarginLayoutParams source) { + super(source); + } + + public LayoutParams(ViewGroup.LayoutParams source) { + super(source); + } + + public LayoutParams(RecyclerView.LayoutParams source) { + super(source); + } + + /** + * When set to true, the item will layout using all span area. That means, if orientation + * is vertical, the view will have full width; if orientation is horizontal, the view will + * have full height. + * + * @param fullSpan True if this item should traverse all spans. + * @see #isFullSpan() + */ + public void setFullSpan(boolean fullSpan) { + mFullSpan = fullSpan; + } + + /** + * Returns whether this View occupies all available spans or just one. + * + * @return True if the View occupies all spans or false otherwise. + * @see #setFullSpan(boolean) + */ + public boolean isFullSpan() { + return mFullSpan; + } + + /** + * Returns the Span index to which this View is assigned. + * + * @return The Span index of the View. If View is not yet assigned to any span, returns + * {@link #INVALID_SPAN_ID}. + */ + public final int getSpanIndex() { + if (mSpan == null) { + return INVALID_SPAN_ID; + } + return mSpan.mIndex; + } + } + + // Package scoped to access from tests. + class Span { + + static final int INVALID_LINE = Integer.MIN_VALUE; + private ArrayList mViews = new ArrayList<>(); + int mCachedStart = INVALID_LINE; + int mCachedEnd = INVALID_LINE; + int mDeletedSize = 0; + final int mIndex; + + private Span(int index) { + mIndex = index; + } + + int getStartLine(int def) { + if (mCachedStart != INVALID_LINE) { + return mCachedStart; + } + if (mViews.size() == 0) { + return def; + } + calculateCachedStart(); + return mCachedStart; + } + + void calculateCachedStart() { + final View startView = mViews.get(0); + final LayoutParams lp = getLayoutParams(startView); + mCachedStart = mPrimaryOrientation.getDecoratedStart(startView); + if (lp.mFullSpan) { + LazySpanLookup.FullSpanItem fsi = mLazySpanLookup + .getFullSpanItem(lp.getViewLayoutPosition()); + if (fsi != null && fsi.mGapDir == LAYOUT_START) { + mCachedStart -= fsi.getGapForSpan(mIndex); + } + } + } + + // Use this one when default value does not make sense and not having a value means a bug. + int getStartLine() { + if (mCachedStart != INVALID_LINE) { + return mCachedStart; + } + calculateCachedStart(); + return mCachedStart; + } + + int getEndLine(int def) { + if (mCachedEnd != INVALID_LINE) { + return mCachedEnd; + } + final int size = mViews.size(); + if (size == 0) { + return def; + } + calculateCachedEnd(); + return mCachedEnd; + } + + void calculateCachedEnd() { + final View endView = mViews.get(mViews.size() - 1); + final LayoutParams lp = getLayoutParams(endView); + mCachedEnd = mPrimaryOrientation.getDecoratedEnd(endView); + if (lp.mFullSpan) { + LazySpanLookup.FullSpanItem fsi = mLazySpanLookup + .getFullSpanItem(lp.getViewLayoutPosition()); + if (fsi != null && fsi.mGapDir == LAYOUT_END) { + mCachedEnd += fsi.getGapForSpan(mIndex); + } + } + } + + // Use this one when default value does not make sense and not having a value means a bug. + int getEndLine() { + if (mCachedEnd != INVALID_LINE) { + return mCachedEnd; + } + calculateCachedEnd(); + return mCachedEnd; + } + + void prependToSpan(View view) { + LayoutParams lp = getLayoutParams(view); + lp.mSpan = this; + mViews.add(0, view); + mCachedStart = INVALID_LINE; + if (mViews.size() == 1) { + mCachedEnd = INVALID_LINE; + } + if (lp.isItemRemoved() || lp.isItemChanged()) { + mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view); + } + } + + void appendToSpan(View view) { + LayoutParams lp = getLayoutParams(view); + lp.mSpan = this; + mViews.add(view); + mCachedEnd = INVALID_LINE; + if (mViews.size() == 1) { + mCachedStart = INVALID_LINE; + } + if (lp.isItemRemoved() || lp.isItemChanged()) { + mDeletedSize += mPrimaryOrientation.getDecoratedMeasurement(view); + } + } + + // Useful method to preserve positions on a re-layout. + void cacheReferenceLineAndClear(boolean reverseLayout, int offset) { + int reference; + if (reverseLayout) { + reference = getEndLine(INVALID_LINE); + } else { + reference = getStartLine(INVALID_LINE); + } + clear(); + if (reference == INVALID_LINE) { + return; + } + if ((reverseLayout && reference < mPrimaryOrientation.getEndAfterPadding()) || + (!reverseLayout && reference > mPrimaryOrientation.getStartAfterPadding())) { + return; + } + if (offset != INVALID_OFFSET) { + reference += offset; + } + mCachedStart = mCachedEnd = reference; + } + + void clear() { + mViews.clear(); + invalidateCache(); + mDeletedSize = 0; + } + + void invalidateCache() { + mCachedStart = INVALID_LINE; + mCachedEnd = INVALID_LINE; + } + + void setLine(int line) { + mCachedEnd = mCachedStart = line; + } + + void popEnd() { + final int size = mViews.size(); + View end = mViews.remove(size - 1); + final LayoutParams lp = getLayoutParams(end); + lp.mSpan = null; + if (lp.isItemRemoved() || lp.isItemChanged()) { + mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(end); + } + if (size == 1) { + mCachedStart = INVALID_LINE; + } + mCachedEnd = INVALID_LINE; + } + + void popStart() { + View start = mViews.remove(0); + final LayoutParams lp = getLayoutParams(start); + lp.mSpan = null; + if (mViews.size() == 0) { + mCachedEnd = INVALID_LINE; + } + if (lp.isItemRemoved() || lp.isItemChanged()) { + mDeletedSize -= mPrimaryOrientation.getDecoratedMeasurement(start); + } + mCachedStart = INVALID_LINE; + } + + public int getDeletedSize() { + return mDeletedSize; + } + + LayoutParams getLayoutParams(View view) { + return (LayoutParams) view.getLayoutParams(); + } + + void onOffset(int dt) { + if (mCachedStart != INVALID_LINE) { + mCachedStart += dt; + } + if (mCachedEnd != INVALID_LINE) { + mCachedEnd += dt; + } + } + + public int findFirstVisibleItemPosition() { + return mReverseLayout + ? findOneVisibleChild(mViews.size() - 1, -1, false) + : findOneVisibleChild(0, mViews.size(), false); + } + + public int findFirstCompletelyVisibleItemPosition() { + return mReverseLayout + ? findOneVisibleChild(mViews.size() - 1, -1, true) + : findOneVisibleChild(0, mViews.size(), true); + } + + public int findLastVisibleItemPosition() { + return mReverseLayout + ? findOneVisibleChild(0, mViews.size(), false) + : findOneVisibleChild(mViews.size() - 1, -1, false); + } + + public int findLastCompletelyVisibleItemPosition() { + return mReverseLayout + ? findOneVisibleChild(0, mViews.size(), true) + : findOneVisibleChild(mViews.size() - 1, -1, true); + } + + int findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible) { + final int start = mPrimaryOrientation.getStartAfterPadding(); + final int end = mPrimaryOrientation.getEndAfterPadding(); + final int next = toIndex > fromIndex ? 1 : -1; + for (int i = fromIndex; i != toIndex; i += next) { + final View child = mViews.get(i); + final int childStart = mPrimaryOrientation.getDecoratedStart(child); + final int childEnd = mPrimaryOrientation.getDecoratedEnd(child); + if (childStart < end && childEnd > start) { + if (completelyVisible) { + if (childStart >= start && childEnd <= end) { + return getPosition(child); + } + } else { + return getPosition(child); + } + } + } + return NO_POSITION; + } + + /** + * Depending on the layout direction, returns the View that is after the given position. + */ + public View getFocusableViewAfter(int referenceChildPosition, int layoutDir) { + View candidate = null; + if (layoutDir == LAYOUT_START) { + final int limit = mViews.size(); + for (int i = 0; i < limit; i++) { + final View view = mViews.get(i); + if (view.isFocusable() && + (getPosition(view) > referenceChildPosition == mReverseLayout) ) { + candidate = view; + } else { + break; + } + } + } else { + for (int i = mViews.size() - 1; i >= 0; i--) { + final View view = mViews.get(i); + if (view.isFocusable() && + (getPosition(view) > referenceChildPosition == !mReverseLayout)) { + candidate = view; + } else { + break; + } + } + } + return candidate; + } + } + + /** + * An array of mappings from adapter position to span. + * This only grows when a write happens and it grows up to the size of the adapter. + */ + static class LazySpanLookup { + + private static final int MIN_SIZE = 10; + int[] mData; + List mFullSpanItems; + + + /** + * Invalidates everything after this position, including full span information + */ + int forceInvalidateAfter(int position) { + if (mFullSpanItems != null) { + for (int i = mFullSpanItems.size() - 1; i >= 0; i--) { + FullSpanItem fsi = mFullSpanItems.get(i); + if (fsi.mPosition >= position) { + mFullSpanItems.remove(i); + } + } + } + return invalidateAfter(position); + } + + /** + * returns end position for invalidation. + */ + int invalidateAfter(int position) { + if (mData == null) { + return RecyclerView.NO_POSITION; + } + if (position >= mData.length) { + return RecyclerView.NO_POSITION; + } + int endPosition = invalidateFullSpansAfter(position); + if (endPosition == RecyclerView.NO_POSITION) { + Arrays.fill(mData, position, mData.length, LayoutParams.INVALID_SPAN_ID); + return mData.length; + } else { + // just invalidate items in between + Arrays.fill(mData, position, endPosition + 1, LayoutParams.INVALID_SPAN_ID); + return endPosition + 1; + } + } + + int getSpan(int position) { + if (mData == null || position >= mData.length) { + return LayoutParams.INVALID_SPAN_ID; + } else { + return mData[position]; + } + } + + void setSpan(int position, Span span) { + ensureSize(position); + mData[position] = span.mIndex; + } + + int sizeForPosition(int position) { + int len = mData.length; + while (len <= position) { + len *= 2; + } + return len; + } + + void ensureSize(int position) { + if (mData == null) { + mData = new int[Math.max(position, MIN_SIZE) + 1]; + Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID); + } else if (position >= mData.length) { + int[] old = mData; + mData = new int[sizeForPosition(position)]; + System.arraycopy(old, 0, mData, 0, old.length); + Arrays.fill(mData, old.length, mData.length, LayoutParams.INVALID_SPAN_ID); + } + } + + void clear() { + if (mData != null) { + Arrays.fill(mData, LayoutParams.INVALID_SPAN_ID); + } + mFullSpanItems = null; + } + + void offsetForRemoval(int positionStart, int itemCount) { + if (mData == null || positionStart >= mData.length) { + return; + } + ensureSize(positionStart + itemCount); + System.arraycopy(mData, positionStart + itemCount, mData, positionStart, + mData.length - positionStart - itemCount); + Arrays.fill(mData, mData.length - itemCount, mData.length, + LayoutParams.INVALID_SPAN_ID); + offsetFullSpansForRemoval(positionStart, itemCount); + } + + private void offsetFullSpansForRemoval(int positionStart, int itemCount) { + if (mFullSpanItems == null) { + return; + } + final int end = positionStart + itemCount; + for (int i = mFullSpanItems.size() - 1; i >= 0; i--) { + FullSpanItem fsi = mFullSpanItems.get(i); + if (fsi.mPosition < positionStart) { + continue; + } + if (fsi.mPosition < end) { + mFullSpanItems.remove(i); + } else { + fsi.mPosition -= itemCount; + } + } + } + + void offsetForAddition(int positionStart, int itemCount) { + if (mData == null || positionStart >= mData.length) { + return; + } + ensureSize(positionStart + itemCount); + System.arraycopy(mData, positionStart, mData, positionStart + itemCount, + mData.length - positionStart - itemCount); + Arrays.fill(mData, positionStart, positionStart + itemCount, + LayoutParams.INVALID_SPAN_ID); + offsetFullSpansForAddition(positionStart, itemCount); + } + + private void offsetFullSpansForAddition(int positionStart, int itemCount) { + if (mFullSpanItems == null) { + return; + } + for (int i = mFullSpanItems.size() - 1; i >= 0; i--) { + FullSpanItem fsi = mFullSpanItems.get(i); + if (fsi.mPosition < positionStart) { + continue; + } + fsi.mPosition += itemCount; + } + } + + /** + * Returns when invalidation should end. e.g. hitting a full span position. + * Returned position SHOULD BE invalidated. + */ + private int invalidateFullSpansAfter(int position) { + if (mFullSpanItems == null) { + return RecyclerView.NO_POSITION; + } + final FullSpanItem item = getFullSpanItem(position); + // if there is an fsi at this position, get rid of it. + if (item != null) { + mFullSpanItems.remove(item); + } + int nextFsiIndex = -1; + final int count = mFullSpanItems.size(); + for (int i = 0; i < count; i++) { + FullSpanItem fsi = mFullSpanItems.get(i); + if (fsi.mPosition >= position) { + nextFsiIndex = i; + break; + } + } + if (nextFsiIndex != -1) { + FullSpanItem fsi = mFullSpanItems.get(nextFsiIndex); + mFullSpanItems.remove(nextFsiIndex); + return fsi.mPosition; + } + return RecyclerView.NO_POSITION; + } + + public void addFullSpanItem(FullSpanItem fullSpanItem) { + if (mFullSpanItems == null) { + mFullSpanItems = new ArrayList<>(); + } + final int size = mFullSpanItems.size(); + for (int i = 0; i < size; i++) { + FullSpanItem other = mFullSpanItems.get(i); + if (other.mPosition == fullSpanItem.mPosition) { + if (DEBUG) { + throw new IllegalStateException("two fsis for same position"); + } else { + mFullSpanItems.remove(i); + } + } + if (other.mPosition >= fullSpanItem.mPosition) { + mFullSpanItems.add(i, fullSpanItem); + return; + } + } + // if it is not added to a position. + mFullSpanItems.add(fullSpanItem); + } + + public FullSpanItem getFullSpanItem(int position) { + if (mFullSpanItems == null) { + return null; + } + for (int i = mFullSpanItems.size() - 1; i >= 0; i--) { + final FullSpanItem fsi = mFullSpanItems.get(i); + if (fsi.mPosition == position) { + return fsi; + } + } + return null; + } + + /** + * @param minPos inclusive + * @param maxPos exclusive + * @param gapDir if not 0, returns FSIs on in that direction + * @param hasUnwantedGapAfter If true, when full span item has unwanted gaps, it will be + * returned even if its gap direction does not match. + */ + public FullSpanItem getFirstFullSpanItemInRange(int minPos, int maxPos, int gapDir, + boolean hasUnwantedGapAfter) { + if (mFullSpanItems == null) { + return null; + } + final int limit = mFullSpanItems.size(); + for (int i = 0; i < limit; i++) { + FullSpanItem fsi = mFullSpanItems.get(i); + if (fsi.mPosition >= maxPos) { + return null; + } + if (fsi.mPosition >= minPos + && (gapDir == 0 || fsi.mGapDir == gapDir || + (hasUnwantedGapAfter && fsi.mHasUnwantedGapAfter))) { + return fsi; + } + } + return null; + } + + /** + * We keep information about full span items because they may create gaps in the UI. + */ + static class FullSpanItem implements Parcelable { + + int mPosition; + int mGapDir; + int[] mGapPerSpan; + // A full span may be laid out in primary direction but may have gaps due to + // invalidation of views after it. This is recorded during a reverse scroll and if + // view is still on the screen after scroll stops, we have to recalculate layout + boolean mHasUnwantedGapAfter; + + public FullSpanItem(Parcel in) { + mPosition = in.readInt(); + mGapDir = in.readInt(); + mHasUnwantedGapAfter = in.readInt() == 1; + int spanCount = in.readInt(); + if (spanCount > 0) { + mGapPerSpan = new int[spanCount]; + in.readIntArray(mGapPerSpan); + } + } + + public FullSpanItem() { + } + + int getGapForSpan(int spanIndex) { + return mGapPerSpan == null ? 0 : mGapPerSpan[spanIndex]; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mPosition); + dest.writeInt(mGapDir); + dest.writeInt(mHasUnwantedGapAfter ? 1 : 0); + if (mGapPerSpan != null && mGapPerSpan.length > 0) { + dest.writeInt(mGapPerSpan.length); + dest.writeIntArray(mGapPerSpan); + } else { + dest.writeInt(0); + } + } + + @Override + public String toString() { + return "FullSpanItem{" + + "mPosition=" + mPosition + + ", mGapDir=" + mGapDir + + ", mHasUnwantedGapAfter=" + mHasUnwantedGapAfter + + ", mGapPerSpan=" + Arrays.toString(mGapPerSpan) + + '}'; + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public FullSpanItem createFromParcel(Parcel in) { + return new FullSpanItem(in); + } + + @Override + public FullSpanItem[] newArray(int size) { + return new FullSpanItem[size]; + } + }; + } + } + + /** + * @hide + */ + public static class SavedState implements Parcelable { + + int mAnchorPosition; + int mVisibleAnchorPosition; // Replacement for span info when spans are invalidated + int mSpanOffsetsSize; + int[] mSpanOffsets; + int mSpanLookupSize; + int[] mSpanLookup; + List mFullSpanItems; + boolean mReverseLayout; + boolean mAnchorLayoutFromEnd; + boolean mLastLayoutRTL; + + public SavedState() { + } + + SavedState(Parcel in) { + mAnchorPosition = in.readInt(); + mVisibleAnchorPosition = in.readInt(); + mSpanOffsetsSize = in.readInt(); + if (mSpanOffsetsSize > 0) { + mSpanOffsets = new int[mSpanOffsetsSize]; + in.readIntArray(mSpanOffsets); + } + + mSpanLookupSize = in.readInt(); + if (mSpanLookupSize > 0) { + mSpanLookup = new int[mSpanLookupSize]; + in.readIntArray(mSpanLookup); + } + mReverseLayout = in.readInt() == 1; + mAnchorLayoutFromEnd = in.readInt() == 1; + mLastLayoutRTL = in.readInt() == 1; + //noinspection unchecked + mFullSpanItems = in.readArrayList( + LazySpanLookup.FullSpanItem.class.getClassLoader()); + } + + public SavedState(SavedState other) { + mSpanOffsetsSize = other.mSpanOffsetsSize; + mAnchorPosition = other.mAnchorPosition; + mVisibleAnchorPosition = other.mVisibleAnchorPosition; + mSpanOffsets = other.mSpanOffsets; + mSpanLookupSize = other.mSpanLookupSize; + mSpanLookup = other.mSpanLookup; + mReverseLayout = other.mReverseLayout; + mAnchorLayoutFromEnd = other.mAnchorLayoutFromEnd; + mLastLayoutRTL = other.mLastLayoutRTL; + mFullSpanItems = other.mFullSpanItems; + } + + void invalidateSpanInfo() { + mSpanOffsets = null; + mSpanOffsetsSize = 0; + mSpanLookupSize = 0; + mSpanLookup = null; + mFullSpanItems = null; + } + + void invalidateAnchorPositionInfo() { + mSpanOffsets = null; + mSpanOffsetsSize = 0; + mAnchorPosition = NO_POSITION; + mVisibleAnchorPosition = NO_POSITION; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mAnchorPosition); + dest.writeInt(mVisibleAnchorPosition); + dest.writeInt(mSpanOffsetsSize); + if (mSpanOffsetsSize > 0) { + dest.writeIntArray(mSpanOffsets); + } + dest.writeInt(mSpanLookupSize); + if (mSpanLookupSize > 0) { + dest.writeIntArray(mSpanLookup); + } + dest.writeInt(mReverseLayout ? 1 : 0); + dest.writeInt(mAnchorLayoutFromEnd ? 1 : 0); + dest.writeInt(mLastLayoutRTL ? 1 : 0); + dest.writeList(mFullSpanItems); + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @Override + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } + + /** + * Data class to hold the information about an anchor position which is used in onLayout call. + */ + private class AnchorInfo { + + int mPosition; + int mOffset; + boolean mLayoutFromEnd; + boolean mInvalidateOffsets; + + void reset() { + mPosition = NO_POSITION; + mOffset = INVALID_OFFSET; + mLayoutFromEnd = false; + mInvalidateOffsets = false; + } + + void assignCoordinateFromPadding() { + mOffset = mLayoutFromEnd ? mPrimaryOrientation.getEndAfterPadding() + : mPrimaryOrientation.getStartAfterPadding(); + } + + void assignCoordinateFromPadding(int addedDistance) { + if (mLayoutFromEnd) { + mOffset = mPrimaryOrientation.getEndAfterPadding() - addedDistance; + } else { + mOffset = mPrimaryOrientation.getStartAfterPadding() + addedDistance; + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/ViewInfoStore.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/ViewInfoStore.java new file mode 100644 index 00000000..938fe42f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/ViewInfoStore.java @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.support.widget; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; +import android.support.v4.util.ArrayMap; +import android.support.v4.util.LongSparseArray; +import android.support.v4.util.Pools; + +import static org.telegram.messenger.support.widget.RecyclerView.ViewHolder; +import static org.telegram.messenger.support.widget.RecyclerView.ItemAnimator.ItemHolderInfo; + +import static org.telegram.messenger.support.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_PRE_AND_POST; +import static org.telegram.messenger.support.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR_AND_DISAPPEAR; +import static org.telegram.messenger.support.widget.ViewInfoStore.InfoRecord.FLAG_PRE_AND_POST; +import static org.telegram.messenger.support.widget.ViewInfoStore.InfoRecord.FLAG_DISAPPEARED; +import static org.telegram.messenger.support.widget.ViewInfoStore.InfoRecord.FLAG_APPEAR; +import static org.telegram.messenger.support.widget.ViewInfoStore.InfoRecord.FLAG_PRE; +import static org.telegram.messenger.support.widget.ViewInfoStore.InfoRecord.FLAG_POST; +/** + * This class abstracts all tracking for Views to run animations + * + * @hide + */ +class ViewInfoStore { + + private static final boolean DEBUG = false; + + /** + * View data records for pre-layout + */ + @VisibleForTesting + final ArrayMap mLayoutHolderMap = new ArrayMap<>(); + + @VisibleForTesting + final LongSparseArray mOldChangedHolders = new LongSparseArray<>(); + + /** + * Clears the state and all existing tracking data + */ + void clear() { + mLayoutHolderMap.clear(); + mOldChangedHolders.clear(); + } + + /** + * Adds the item information to the prelayout tracking + * @param holder The ViewHolder whose information is being saved + * @param info The information to save + */ + void addToPreLayout(ViewHolder holder, ItemHolderInfo info) { + InfoRecord record = mLayoutHolderMap.get(holder); + if (record == null) { + record = InfoRecord.obtain(); + mLayoutHolderMap.put(holder, record); + } + record.preInfo = info; + record.flags |= FLAG_PRE; + } + + boolean isDisappearing(ViewHolder holder) { + final InfoRecord record = mLayoutHolderMap.get(holder); + return record != null && ((record.flags & FLAG_DISAPPEARED) != 0); + } + + /** + * Finds the ItemHolderInfo for the given ViewHolder in preLayout list and removes it. + * + * @param vh The ViewHolder whose information is being queried + * @return The ItemHolderInfo for the given ViewHolder or null if it does not exist + */ + @Nullable + ItemHolderInfo popFromPreLayout(ViewHolder vh) { + return popFromLayoutStep(vh, FLAG_PRE); + } + + /** + * Finds the ItemHolderInfo for the given ViewHolder in postLayout list and removes it. + * + * @param vh The ViewHolder whose information is being queried + * @return The ItemHolderInfo for the given ViewHolder or null if it does not exist + */ + @Nullable + ItemHolderInfo popFromPostLayout(ViewHolder vh) { + return popFromLayoutStep(vh, FLAG_POST); + } + + private ItemHolderInfo popFromLayoutStep(ViewHolder vh, int flag) { + int index = mLayoutHolderMap.indexOfKey(vh); + if (index < 0) { + return null; + } + final InfoRecord record = mLayoutHolderMap.valueAt(index); + if (record != null && (record.flags & flag) != 0) { + record.flags &= ~flag; + final ItemHolderInfo info; + if (flag == FLAG_PRE) { + info = record.preInfo; + } else if (flag == FLAG_POST) { + info = record.postInfo; + } else { + throw new IllegalArgumentException("Must provide flag PRE or POST"); + } + // if not pre-post flag is left, clear. + if ((record.flags & (FLAG_PRE | FLAG_POST)) == 0) { + mLayoutHolderMap.removeAt(index); + InfoRecord.recycle(record); + } + return info; + } + return null; + } + + /** + * Adds the given ViewHolder to the oldChangeHolders list + * @param key The key to identify the ViewHolder. + * @param holder The ViewHolder to store + */ + void addToOldChangeHolders(long key, ViewHolder holder) { + mOldChangedHolders.put(key, holder); + } + + /** + * Adds the given ViewHolder to the appeared in pre layout list. These are Views added by the + * LayoutManager during a pre-layout pass. We distinguish them from other views that were + * already in the pre-layout so that ItemAnimator can choose to run a different animation for + * them. + * + * @param holder The ViewHolder to store + * @param info The information to save + */ + void addToAppearedInPreLayoutHolders(ViewHolder holder, ItemHolderInfo info) { + InfoRecord record = mLayoutHolderMap.get(holder); + if (record == null) { + record = InfoRecord.obtain(); + mLayoutHolderMap.put(holder, record); + } + record.flags |= FLAG_APPEAR; + record.preInfo = info; + } + + /** + * Checks whether the given ViewHolder is in preLayout list + * @param viewHolder The ViewHolder to query + * + * @return True if the ViewHolder is present in preLayout, false otherwise + */ + boolean isInPreLayout(ViewHolder viewHolder) { + final InfoRecord record = mLayoutHolderMap.get(viewHolder); + return record != null && (record.flags & FLAG_PRE) != 0; + } + + /** + * Queries the oldChangeHolder list for the given key. If they are not tracked, simply returns + * null. + * @param key The key to be used to find the ViewHolder. + * + * @return A ViewHolder if exists or null if it does not exist. + */ + ViewHolder getFromOldChangeHolders(long key) { + return mOldChangedHolders.get(key); + } + + /** + * Adds the item information to the post layout list + * @param holder The ViewHolder whose information is being saved + * @param info The information to save + */ + void addToPostLayout(ViewHolder holder, ItemHolderInfo info) { + InfoRecord record = mLayoutHolderMap.get(holder); + if (record == null) { + record = InfoRecord.obtain(); + mLayoutHolderMap.put(holder, record); + } + record.postInfo = info; + record.flags |= FLAG_POST; + } + + /** + * A ViewHolder might be added by the LayoutManager just to animate its disappearance. + * This list holds such items so that we can animate / recycle these ViewHolders properly. + * + * @param holder The ViewHolder which disappeared during a layout. + */ + void addToDisappearedInLayout(ViewHolder holder) { + InfoRecord record = mLayoutHolderMap.get(holder); + if (record == null) { + record = InfoRecord.obtain(); + mLayoutHolderMap.put(holder, record); + } + record.flags |= FLAG_DISAPPEARED; + } + + /** + * Removes a ViewHolder from disappearing list. + * @param holder The ViewHolder to be removed from the disappearing list. + */ + void removeFromDisappearedInLayout(ViewHolder holder) { + InfoRecord record = mLayoutHolderMap.get(holder); + if (record == null) { + return; + } + record.flags &= ~FLAG_DISAPPEARED; + } + + void process(ProcessCallback callback) { + for (int index = mLayoutHolderMap.size() - 1; index >= 0; index --) { + final ViewHolder viewHolder = mLayoutHolderMap.keyAt(index); + final InfoRecord record = mLayoutHolderMap.removeAt(index); + if ((record.flags & FLAG_APPEAR_AND_DISAPPEAR) == FLAG_APPEAR_AND_DISAPPEAR) { + // Appeared then disappeared. Not useful for animations. + callback.unused(viewHolder); + } else if ((record.flags & FLAG_DISAPPEARED) != 0) { + // Set as "disappeared" by the LayoutManager (addDisappearingView) + if (record.preInfo == null) { + // similar to appear disappear but happened between different layout passes. + // this can happen when the layout manager is using auto-measure + callback.unused(viewHolder); + } else { + callback.processDisappeared(viewHolder, record.preInfo, record.postInfo); + } + } else if ((record.flags & FLAG_APPEAR_PRE_AND_POST) == FLAG_APPEAR_PRE_AND_POST) { + // Appeared in the layout but not in the adapter (e.g. entered the viewport) + callback.processAppeared(viewHolder, record.preInfo, record.postInfo); + } else if ((record.flags & FLAG_PRE_AND_POST) == FLAG_PRE_AND_POST) { + // Persistent in both passes. Animate persistence + callback.processPersistent(viewHolder, record.preInfo, record.postInfo); + } else if ((record.flags & FLAG_PRE) != 0) { + // Was in pre-layout, never been added to post layout + callback.processDisappeared(viewHolder, record.preInfo, null); + } else if ((record.flags & FLAG_POST) != 0) { + // Was not in pre-layout, been added to post layout + callback.processAppeared(viewHolder, record.preInfo, record.postInfo); + } else if ((record.flags & FLAG_APPEAR) != 0) { + // Scrap view. RecyclerView will handle removing/recycling this. + } else if (DEBUG) { + throw new IllegalStateException("record without any reasonable flag combination:/"); + } + InfoRecord.recycle(record); + } + } + + /** + * Removes the ViewHolder from all list + * @param holder The ViewHolder which we should stop tracking + */ + void removeViewHolder(ViewHolder holder) { + for (int i = mOldChangedHolders.size() - 1; i >= 0; i--) { + if (holder == mOldChangedHolders.valueAt(i)) { + mOldChangedHolders.removeAt(i); + break; + } + } + final InfoRecord info = mLayoutHolderMap.remove(holder); + if (info != null) { + InfoRecord.recycle(info); + } + } + + void onDetach() { + InfoRecord.drainCache(); + } + + public void onViewDetached(ViewHolder viewHolder) { + removeFromDisappearedInLayout(viewHolder); + } + + interface ProcessCallback { + void processDisappeared(ViewHolder viewHolder, @NonNull ItemHolderInfo preInfo, + @Nullable ItemHolderInfo postInfo); + void processAppeared(ViewHolder viewHolder, @Nullable ItemHolderInfo preInfo, + ItemHolderInfo postInfo); + void processPersistent(ViewHolder viewHolder, @NonNull ItemHolderInfo preInfo, + @NonNull ItemHolderInfo postInfo); + void unused(ViewHolder holder); + } + + static class InfoRecord { + // disappearing list + static final int FLAG_DISAPPEARED = 1; + // appear in pre layout list + static final int FLAG_APPEAR = 1 << 1; + // pre layout, this is necessary to distinguish null item info + static final int FLAG_PRE = 1 << 2; + // post layout, this is necessary to distinguish null item info + static final int FLAG_POST = 1 << 3; + static final int FLAG_APPEAR_AND_DISAPPEAR = FLAG_APPEAR | FLAG_DISAPPEARED; + static final int FLAG_PRE_AND_POST = FLAG_PRE | FLAG_POST; + static final int FLAG_APPEAR_PRE_AND_POST = FLAG_APPEAR | FLAG_PRE | FLAG_POST; + int flags; + @Nullable ItemHolderInfo preInfo; + @Nullable ItemHolderInfo postInfo; + static Pools.Pool sPool = new Pools.SimplePool<>(20); + + private InfoRecord() { + } + + static InfoRecord obtain() { + InfoRecord record = sPool.acquire(); + return record == null ? new InfoRecord() : record; + } + + static void recycle(InfoRecord record) { + record.flags = 0; + record.preInfo = null; + record.postInfo = null; + sPool.release(record); + } + + static void drainCache() { + //noinspection StatementWithEmptyBody + while (sPool.acquire() != null); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/helper/ItemTouchHelper.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/helper/ItemTouchHelper.java new file mode 100644 index 00000000..46b6f9d2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/helper/ItemTouchHelper.java @@ -0,0 +1,2406 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.widget.helper; + +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.os.Build; +import android.support.annotation.Nullable; +import android.support.v4.animation.AnimatorCompatHelper; +import android.support.v4.animation.AnimatorListenerCompat; +import android.support.v4.animation.AnimatorUpdateListenerCompat; +import android.support.v4.animation.ValueAnimatorCompat; +import android.support.v4.view.GestureDetectorCompat; +import android.support.v4.view.MotionEventCompat; +import android.support.v4.view.VelocityTrackerCompat; +import android.support.v4.view.ViewCompat; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.support.widget.LinearLayoutManager; +import org.telegram.messenger.support.widget.RecyclerView; +import org.telegram.messenger.support.widget.RecyclerView.OnItemTouchListener; +import org.telegram.messenger.support.widget.RecyclerView.ViewHolder; +import android.util.Log; +import android.view.GestureDetector; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewParent; +import android.view.animation.Interpolator; + +import java.util.ArrayList; +import java.util.List; + +/** + * This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView. + *

+ * It works with a RecyclerView and a Callback class, which configures what type of interactions + * are enabled and also receives events when user performs these actions. + *

+ * Depending on which functionality you support, you should override + * {@link Callback#onMove(RecyclerView, ViewHolder, ViewHolder)} and / or + * {@link Callback#onSwiped(ViewHolder, int)}. + *

+ * This class is designed to work with any LayoutManager but for certain situations, it can be + * optimized for your custom LayoutManager by extending methods in the + * {@link ItemTouchHelper.Callback} class or implementing {@link ItemTouchHelper.ViewDropHandler} + * interface in your LayoutManager. + *

+ * By default, ItemTouchHelper moves the items' translateX/Y properties to reposition them. On + * platforms older than Honeycomb, ItemTouchHelper uses canvas translations and View's visibility + * property to move items in response to touch events. You can customize these behaviors by + * overriding {@link Callback#onChildDraw(Canvas, RecyclerView, ViewHolder, float, float, int, + * boolean)} + * or {@link Callback#onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int, + * boolean)}. + *

+ * Most of the time, you only need to override onChildDraw but due to limitations of + * platform prior to Honeycomb, you may need to implement onChildDrawOver as well. + */ +public class ItemTouchHelper extends RecyclerView.ItemDecoration + implements RecyclerView.OnChildAttachStateChangeListener { + + /** + * Up direction, used for swipe & drag control. + */ + public static final int UP = 1; + + /** + * Down direction, used for swipe & drag control. + */ + public static final int DOWN = 1 << 1; + + /** + * Left direction, used for swipe & drag control. + */ + public static final int LEFT = 1 << 2; + + /** + * Right direction, used for swipe & drag control. + */ + public static final int RIGHT = 1 << 3; + + // If you change these relative direction values, update Callback#convertToAbsoluteDirection, + // Callback#convertToRelativeDirection. + /** + * Horizontal start direction. Resolved to LEFT or RIGHT depending on RecyclerView's layout + * direction. Used for swipe & drag control. + */ + public static final int START = LEFT << 2; + + /** + * Horizontal end direction. Resolved to LEFT or RIGHT depending on RecyclerView's layout + * direction. Used for swipe & drag control. + */ + public static final int END = RIGHT << 2; + + /** + * ItemTouchHelper is in idle state. At this state, either there is no related motion event by + * the user or latest motion events have not yet triggered a swipe or drag. + */ + public static final int ACTION_STATE_IDLE = 0; + + /** + * A View is currently being swiped. + */ + public static final int ACTION_STATE_SWIPE = 1; + + /** + * A View is currently being dragged. + */ + public static final int ACTION_STATE_DRAG = 2; + + /** + * Animation type for views which are swiped successfully. + */ + public static final int ANIMATION_TYPE_SWIPE_SUCCESS = 1 << 1; + + /** + * Animation type for views which are not completely swiped thus will animate back to their + * original position. + */ + public static final int ANIMATION_TYPE_SWIPE_CANCEL = 1 << 2; + + /** + * Animation type for views that were dragged and now will animate to their final position. + */ + public static final int ANIMATION_TYPE_DRAG = 1 << 3; + + private static final String TAG = "ItemTouchHelper"; + + private static final boolean DEBUG = false; + + private static final int ACTIVE_POINTER_ID_NONE = -1; + + private static final int DIRECTION_FLAG_COUNT = 8; + + private static final int ACTION_MODE_IDLE_MASK = (1 << DIRECTION_FLAG_COUNT) - 1; + + private static final int ACTION_MODE_SWIPE_MASK = ACTION_MODE_IDLE_MASK << DIRECTION_FLAG_COUNT; + + private static final int ACTION_MODE_DRAG_MASK = ACTION_MODE_SWIPE_MASK << DIRECTION_FLAG_COUNT; + + /** + * The unit we are using to track velocity + */ + private static final int PIXELS_PER_SECOND = 1000; + + /** + * Views, whose state should be cleared after they are detached from RecyclerView. + * This is necessary after swipe dismissing an item. We wait until animator finishes its job + * to clean these views. + */ + final List mPendingCleanup = new ArrayList(); + + /** + * Re-use array to calculate dx dy for a ViewHolder + */ + private final float[] mTmpPosition = new float[2]; + + /** + * Currently selected view holder + */ + ViewHolder mSelected = null; + + /** + * The reference coordinates for the action start. For drag & drop, this is the time long + * press is completed vs for swipe, this is the initial touch point. + */ + float mInitialTouchX; + + float mInitialTouchY; + + /** + * Set when ItemTouchHelper is assigned to a RecyclerView. + */ + float mSwipeEscapeVelocity; + + /** + * Set when ItemTouchHelper is assigned to a RecyclerView. + */ + float mMaxSwipeVelocity; + + /** + * The diff between the last event and initial touch. + */ + float mDx; + + float mDy; + + /** + * The coordinates of the selected view at the time it is selected. We record these values + * when action starts so that we can consistently position it even if LayoutManager moves the + * View. + */ + float mSelectedStartX; + + float mSelectedStartY; + + /** + * The pointer we are tracking. + */ + int mActivePointerId = ACTIVE_POINTER_ID_NONE; + + /** + * Developer callback which controls the behavior of ItemTouchHelper. + */ + Callback mCallback; + + /** + * Current mode. + */ + int mActionState = ACTION_STATE_IDLE; + + /** + * The direction flags obtained from unmasking + * {@link Callback#getAbsoluteMovementFlags(RecyclerView, ViewHolder)} for the current + * action state. + */ + int mSelectedFlags; + + /** + * When a View is dragged or swiped and needs to go back to where it was, we create a Recover + * Animation and animate it to its location using this custom Animator, instead of using + * framework Animators. + * Using framework animators has the side effect of clashing with ItemAnimator, creating + * jumpy UIs. + */ + List mRecoverAnimations = new ArrayList(); + + private int mSlop; + + private RecyclerView mRecyclerView; + + /** + * When user drags a view to the edge, we start scrolling the LayoutManager as long as View + * is partially out of bounds. + */ + private final Runnable mScrollRunnable = new Runnable() { + @Override + public void run() { + if (mSelected != null && scrollIfNecessary()) { + if (mSelected != null) { //it might be lost during scrolling + moveIfNecessary(mSelected); + } + mRecyclerView.removeCallbacks(mScrollRunnable); + ViewCompat.postOnAnimation(mRecyclerView, this); + } + } + }; + + /** + * Used for detecting fling swipe + */ + private VelocityTracker mVelocityTracker; + + //re-used list for selecting a swap target + private List mSwapTargets; + + //re used for for sorting swap targets + private List mDistances; + + /** + * If drag & drop is supported, we use child drawing order to bring them to front. + */ + private RecyclerView.ChildDrawingOrderCallback mChildDrawingOrderCallback = null; + + /** + * This keeps a reference to the child dragged by the user. Even after user stops dragging, + * until view reaches its final position (end of recover animation), we keep a reference so + * that it can be drawn above other children. + */ + private View mOverdrawChild = null; + + /** + * We cache the position of the overdraw child to avoid recalculating it each time child + * position callback is called. This value is invalidated whenever a child is attached or + * detached. + */ + private int mOverdrawChildPosition = -1; + + /** + * Used to detect long press. + */ + private GestureDetectorCompat mGestureDetector; + + private final OnItemTouchListener mOnItemTouchListener + = new OnItemTouchListener() { + @Override + public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent event) { + mGestureDetector.onTouchEvent(event); + if (DEBUG) { + Log.d(TAG, "intercept: x:" + event.getX() + ",y:" + event.getY() + ", " + event); + } + final int action = MotionEventCompat.getActionMasked(event); + if (action == MotionEvent.ACTION_DOWN) { + mActivePointerId = MotionEventCompat.getPointerId(event, 0); + mInitialTouchX = event.getX(); + mInitialTouchY = event.getY(); + obtainVelocityTracker(); + if (mSelected == null) { + final RecoverAnimation animation = findAnimation(event); + if (animation != null) { + mInitialTouchX -= animation.mX; + mInitialTouchY -= animation.mY; + endRecoverAnimation(animation.mViewHolder, true); + if (mPendingCleanup.remove(animation.mViewHolder.itemView)) { + mCallback.clearView(mRecyclerView, animation.mViewHolder); + } + select(animation.mViewHolder, animation.mActionState); + updateDxDy(event, mSelectedFlags, 0); + } + } + } else if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { + mActivePointerId = ACTIVE_POINTER_ID_NONE; + select(null, ACTION_STATE_IDLE); + } else if (mActivePointerId != ACTIVE_POINTER_ID_NONE) { + // in a non scroll orientation, if distance change is above threshold, we + // can select the item + final int index = MotionEventCompat.findPointerIndex(event, mActivePointerId); + if (DEBUG) { + Log.d(TAG, "pointer index " + index); + } + if (index >= 0) { + checkSelectForSwipe(action, event, index); + } + } + if (mVelocityTracker != null) { + mVelocityTracker.addMovement(event); + } + return mSelected != null; + } + + @Override + public void onTouchEvent(RecyclerView recyclerView, MotionEvent event) { + mGestureDetector.onTouchEvent(event); + if (DEBUG) { + Log.d(TAG, + "on touch: x:" + mInitialTouchX + ",y:" + mInitialTouchY + ", :" + event); + } + if (mVelocityTracker != null) { + mVelocityTracker.addMovement(event); + } + if (mActivePointerId == ACTIVE_POINTER_ID_NONE) { + return; + } + final int action = MotionEventCompat.getActionMasked(event); + final int activePointerIndex = MotionEventCompat + .findPointerIndex(event, mActivePointerId); + if (activePointerIndex >= 0) { + checkSelectForSwipe(action, event, activePointerIndex); + } + ViewHolder viewHolder = mSelected; + if (viewHolder == null) { + return; + } + switch (action) { + case MotionEvent.ACTION_MOVE: { + // Find the index of the active pointer and fetch its position + if (activePointerIndex >= 0) { + updateDxDy(event, mSelectedFlags, activePointerIndex); + moveIfNecessary(viewHolder); + mRecyclerView.removeCallbacks(mScrollRunnable); + mScrollRunnable.run(); + mRecyclerView.invalidate(); + } + break; + } + case MotionEvent.ACTION_CANCEL: + if (mVelocityTracker != null) { + mVelocityTracker.clear(); + } + // fall through + case MotionEvent.ACTION_UP: + select(null, ACTION_STATE_IDLE); + mActivePointerId = ACTIVE_POINTER_ID_NONE; + break; + case MotionEvent.ACTION_POINTER_UP: { + final int pointerIndex = MotionEventCompat.getActionIndex(event); + final int pointerId = MotionEventCompat.getPointerId(event, pointerIndex); + if (pointerId == mActivePointerId) { + // This was our active pointer going up. Choose a new + // active pointer and adjust accordingly. + final int newPointerIndex = pointerIndex == 0 ? 1 : 0; + mActivePointerId = MotionEventCompat.getPointerId(event, newPointerIndex); + updateDxDy(event, mSelectedFlags, pointerIndex); + } + break; + } + } + } + + @Override + public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { + if (!disallowIntercept) { + return; + } + select(null, ACTION_STATE_IDLE); + } + }; + + /** + * Temporary rect instance that is used when we need to lookup Item decorations. + */ + private Rect mTmpRect; + + /** + * When user started to drag scroll. Reset when we don't scroll + */ + private long mDragScrollStartTimeInMs; + + /** + * Creates an ItemTouchHelper that will work with the given Callback. + *

+ * You can attach ItemTouchHelper to a RecyclerView via + * {@link #attachToRecyclerView(RecyclerView)}. Upon attaching, it will add an item decoration, + * an onItemTouchListener and a Child attach / detach listener to the RecyclerView. + * + * @param callback The Callback which controls the behavior of this touch helper. + */ + public ItemTouchHelper(Callback callback) { + mCallback = callback; + } + + private static boolean hitTest(View child, float x, float y, float left, float top) { + return x >= left && + x <= left + child.getWidth() && + y >= top && + y <= top + child.getHeight(); + } + + /** + * Attaches the ItemTouchHelper to the provided RecyclerView. If TouchHelper is already + * attached to a RecyclerView, it will first detach from the previous one. You can call this + * method with {@code null} to detach it from the current RecyclerView. + * + * @param recyclerView The RecyclerView instance to which you want to add this helper or + * {@code null} if you want to remove ItemTouchHelper from the current + * RecyclerView. + */ + public void attachToRecyclerView(@Nullable RecyclerView recyclerView) { + if (mRecyclerView == recyclerView) { + return; // nothing to do + } + if (mRecyclerView != null) { + destroyCallbacks(); + } + mRecyclerView = recyclerView; + if (mRecyclerView != null) { + final Resources resources = recyclerView.getResources(); + mSwipeEscapeVelocity = AndroidUtilities.dp(120); + mMaxSwipeVelocity = AndroidUtilities.dp(800); + setupCallbacks(); + } + } + + private void setupCallbacks() { + ViewConfiguration vc = ViewConfiguration.get(mRecyclerView.getContext()); + mSlop = vc.getScaledTouchSlop(); + mRecyclerView.addItemDecoration(this); + mRecyclerView.addOnItemTouchListener(mOnItemTouchListener); + mRecyclerView.addOnChildAttachStateChangeListener(this); + initGestureDetector(); + } + + private void destroyCallbacks() { + mRecyclerView.removeItemDecoration(this); + mRecyclerView.removeOnItemTouchListener(mOnItemTouchListener); + mRecyclerView.removeOnChildAttachStateChangeListener(this); + // clean all attached + final int recoverAnimSize = mRecoverAnimations.size(); + for (int i = recoverAnimSize - 1; i >= 0; i--) { + final RecoverAnimation recoverAnimation = mRecoverAnimations.get(0); + mCallback.clearView(mRecyclerView, recoverAnimation.mViewHolder); + } + mRecoverAnimations.clear(); + mOverdrawChild = null; + mOverdrawChildPosition = -1; + releaseVelocityTracker(); + } + + private void initGestureDetector() { + if (mGestureDetector != null) { + return; + } + mGestureDetector = new GestureDetectorCompat(mRecyclerView.getContext(), + new ItemTouchHelperGestureListener()); + } + + private void getSelectedDxDy(float[] outPosition) { + if ((mSelectedFlags & (LEFT | RIGHT)) != 0) { + outPosition[0] = mSelectedStartX + mDx - mSelected.itemView.getLeft(); + } else { + outPosition[0] = ViewCompat.getTranslationX(mSelected.itemView); + } + if ((mSelectedFlags & (UP | DOWN)) != 0) { + outPosition[1] = mSelectedStartY + mDy - mSelected.itemView.getTop(); + } else { + outPosition[1] = ViewCompat.getTranslationY(mSelected.itemView); + } + } + + @Override + public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { + float dx = 0, dy = 0; + if (mSelected != null) { + getSelectedDxDy(mTmpPosition); + dx = mTmpPosition[0]; + dy = mTmpPosition[1]; + } + mCallback.onDrawOver(c, parent, mSelected, + mRecoverAnimations, mActionState, dx, dy); + } + + @Override + public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { + // we don't know if RV changed something so we should invalidate this index. + mOverdrawChildPosition = -1; + float dx = 0, dy = 0; + if (mSelected != null) { + getSelectedDxDy(mTmpPosition); + dx = mTmpPosition[0]; + dy = mTmpPosition[1]; + } + mCallback.onDraw(c, parent, mSelected, + mRecoverAnimations, mActionState, dx, dy); + } + + /** + * Starts dragging or swiping the given View. Call with null if you want to clear it. + * + * @param selected The ViewHolder to drag or swipe. Can be null if you want to cancel the + * current action + * @param actionState The type of action + */ + private void select(ViewHolder selected, int actionState) { + if (selected == mSelected && actionState == mActionState) { + return; + } + mDragScrollStartTimeInMs = Long.MIN_VALUE; + final int prevActionState = mActionState; + // prevent duplicate animations + endRecoverAnimation(selected, true); + mActionState = actionState; + if (actionState == ACTION_STATE_DRAG) { + // we remove after animation is complete. this means we only elevate the last drag + // child but that should perform good enough as it is very hard to start dragging a + // new child before the previous one settles. + mOverdrawChild = selected.itemView; + addChildDrawingOrderCallback(); + } + int actionStateMask = (1 << (DIRECTION_FLAG_COUNT + DIRECTION_FLAG_COUNT * actionState)) + - 1; + boolean preventLayout = false; + + if (mSelected != null) { + final ViewHolder prevSelected = mSelected; + if (prevSelected.itemView.getParent() != null) { + final int swipeDir = prevActionState == ACTION_STATE_DRAG ? 0 + : swipeIfNecessary(prevSelected); + releaseVelocityTracker(); + // find where we should animate to + final float targetTranslateX, targetTranslateY; + int animationType; + switch (swipeDir) { + case LEFT: + case RIGHT: + case START: + case END: + targetTranslateY = 0; + targetTranslateX = Math.signum(mDx) * mRecyclerView.getWidth(); + break; + case UP: + case DOWN: + targetTranslateX = 0; + targetTranslateY = Math.signum(mDy) * mRecyclerView.getHeight(); + break; + default: + targetTranslateX = 0; + targetTranslateY = 0; + } + if (prevActionState == ACTION_STATE_DRAG) { + animationType = ANIMATION_TYPE_DRAG; + } else if (swipeDir > 0) { + animationType = ANIMATION_TYPE_SWIPE_SUCCESS; + } else { + animationType = ANIMATION_TYPE_SWIPE_CANCEL; + } + getSelectedDxDy(mTmpPosition); + final float currentTranslateX = mTmpPosition[0]; + final float currentTranslateY = mTmpPosition[1]; + final RecoverAnimation rv = new RecoverAnimation(prevSelected, animationType, + prevActionState, currentTranslateX, currentTranslateY, + targetTranslateX, targetTranslateY) { + @Override + public void onAnimationEnd(ValueAnimatorCompat animation) { + super.onAnimationEnd(animation); + if (this.mOverridden) { + return; + } + if (swipeDir <= 0) { + // this is a drag or failed swipe. recover immediately + mCallback.clearView(mRecyclerView, prevSelected); + // full cleanup will happen on onDrawOver + } else { + // wait until remove animation is complete. + mPendingCleanup.add(prevSelected.itemView); + mIsPendingCleanup = true; + if (swipeDir > 0) { + // Animation might be ended by other animators during a layout. + // We defer callback to avoid editing adapter during a layout. + postDispatchSwipe(this, swipeDir); + } + } + // removed from the list after it is drawn for the last time + if (mOverdrawChild == prevSelected.itemView) { + removeChildDrawingOrderCallbackIfNecessary(prevSelected.itemView); + } + } + }; + final long duration = mCallback.getAnimationDuration(mRecyclerView, animationType, + targetTranslateX - currentTranslateX, targetTranslateY - currentTranslateY); + rv.setDuration(duration); + mRecoverAnimations.add(rv); + rv.start(); + preventLayout = true; + } else { + removeChildDrawingOrderCallbackIfNecessary(prevSelected.itemView); + mCallback.clearView(mRecyclerView, prevSelected); + } + mSelected = null; + } + if (selected != null) { + mSelectedFlags = + (mCallback.getAbsoluteMovementFlags(mRecyclerView, selected) & actionStateMask) + >> (mActionState * DIRECTION_FLAG_COUNT); + mSelectedStartX = selected.itemView.getLeft(); + mSelectedStartY = selected.itemView.getTop(); + mSelected = selected; + + if (actionState == ACTION_STATE_DRAG) { + mSelected.itemView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + } + } + final ViewParent rvParent = mRecyclerView.getParent(); + if (rvParent != null) { + rvParent.requestDisallowInterceptTouchEvent(mSelected != null); + } + if (!preventLayout) { + mRecyclerView.getLayoutManager().requestSimpleAnimationsInNextLayout(); + } + mCallback.onSelectedChanged(mSelected, mActionState); + mRecyclerView.invalidate(); + } + + private void postDispatchSwipe(final RecoverAnimation anim, final int swipeDir) { + // wait until animations are complete. + mRecyclerView.post(new Runnable() { + @Override + public void run() { + if (mRecyclerView != null && mRecyclerView.isAttachedToWindow() && + !anim.mOverridden && + anim.mViewHolder.getAdapterPosition() != RecyclerView.NO_POSITION) { + final RecyclerView.ItemAnimator animator = mRecyclerView.getItemAnimator(); + // if animator is running or we have other active recover animations, we try + // not to call onSwiped because DefaultItemAnimator is not good at merging + // animations. Instead, we wait and batch. + if ((animator == null || !animator.isRunning(null)) + && !hasRunningRecoverAnim()) { + mCallback.onSwiped(anim.mViewHolder, swipeDir); + } else { + mRecyclerView.post(this); + } + } + } + }); + } + + private boolean hasRunningRecoverAnim() { + final int size = mRecoverAnimations.size(); + for (int i = 0; i < size; i++) { + if (!mRecoverAnimations.get(i).mEnded) { + return true; + } + } + return false; + } + + /** + * If user drags the view to the edge, trigger a scroll if necessary. + */ + private boolean scrollIfNecessary() { + if (mSelected == null) { + mDragScrollStartTimeInMs = Long.MIN_VALUE; + return false; + } + final long now = System.currentTimeMillis(); + final long scrollDuration = mDragScrollStartTimeInMs + == Long.MIN_VALUE ? 0 : now - mDragScrollStartTimeInMs; + RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager(); + if (mTmpRect == null) { + mTmpRect = new Rect(); + } + int scrollX = 0; + int scrollY = 0; + lm.calculateItemDecorationsForChild(mSelected.itemView, mTmpRect); + if (lm.canScrollHorizontally()) { + int curX = (int) (mSelectedStartX + mDx); + final int leftDiff = curX - mTmpRect.left - mRecyclerView.getPaddingLeft(); + if (mDx < 0 && leftDiff < 0) { + scrollX = leftDiff; + } else if (mDx > 0) { + final int rightDiff = + curX + mSelected.itemView.getWidth() + mTmpRect.right + - (mRecyclerView.getWidth() - mRecyclerView.getPaddingRight()); + if (rightDiff > 0) { + scrollX = rightDiff; + } + } + } + if (lm.canScrollVertically()) { + int curY = (int) (mSelectedStartY + mDy); + final int topDiff = curY - mTmpRect.top - mRecyclerView.getPaddingTop(); + if (mDy < 0 && topDiff < 0) { + scrollY = topDiff; + } else if (mDy > 0) { + final int bottomDiff = curY + mSelected.itemView.getHeight() + mTmpRect.bottom - + (mRecyclerView.getHeight() - mRecyclerView.getPaddingBottom()); + if (bottomDiff > 0) { + scrollY = bottomDiff; + } + } + } + if (scrollX != 0) { + scrollX = mCallback.interpolateOutOfBoundsScroll(mRecyclerView, + mSelected.itemView.getWidth(), scrollX, + mRecyclerView.getWidth(), scrollDuration); + } + if (scrollY != 0) { + scrollY = mCallback.interpolateOutOfBoundsScroll(mRecyclerView, + mSelected.itemView.getHeight(), scrollY, + mRecyclerView.getHeight(), scrollDuration); + } + if (scrollX != 0 || scrollY != 0) { + if (mDragScrollStartTimeInMs == Long.MIN_VALUE) { + mDragScrollStartTimeInMs = now; + } + mRecyclerView.scrollBy(scrollX, scrollY); + return true; + } + mDragScrollStartTimeInMs = Long.MIN_VALUE; + return false; + } + + private List findSwapTargets(ViewHolder viewHolder) { + if (mSwapTargets == null) { + mSwapTargets = new ArrayList(); + mDistances = new ArrayList(); + } else { + mSwapTargets.clear(); + mDistances.clear(); + } + final int margin = mCallback.getBoundingBoxMargin(); + final int left = Math.round(mSelectedStartX + mDx) - margin; + final int top = Math.round(mSelectedStartY + mDy) - margin; + final int right = left + viewHolder.itemView.getWidth() + 2 * margin; + final int bottom = top + viewHolder.itemView.getHeight() + 2 * margin; + final int centerX = (left + right) / 2; + final int centerY = (top + bottom) / 2; + final RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager(); + final int childCount = lm.getChildCount(); + for (int i = 0; i < childCount; i++) { + View other = lm.getChildAt(i); + if (other == viewHolder.itemView) { + continue;//myself! + } + if (other.getBottom() < top || other.getTop() > bottom + || other.getRight() < left || other.getLeft() > right) { + continue; + } + final ViewHolder otherVh = mRecyclerView.getChildViewHolder(other); + if (mCallback.canDropOver(mRecyclerView, mSelected, otherVh)) { + // find the index to add + final int dx = Math.abs(centerX - (other.getLeft() + other.getRight()) / 2); + final int dy = Math.abs(centerY - (other.getTop() + other.getBottom()) / 2); + final int dist = dx * dx + dy * dy; + + int pos = 0; + final int cnt = mSwapTargets.size(); + for (int j = 0; j < cnt; j++) { + if (dist > mDistances.get(j)) { + pos++; + } else { + break; + } + } + mSwapTargets.add(pos, otherVh); + mDistances.add(pos, dist); + } + } + return mSwapTargets; + } + + /** + * Checks if we should swap w/ another view holder. + */ + private void moveIfNecessary(ViewHolder viewHolder) { + if (mRecyclerView.isLayoutRequested()) { + return; + } + if (mActionState != ACTION_STATE_DRAG) { + return; + } + + final float threshold = mCallback.getMoveThreshold(viewHolder); + final int x = (int) (mSelectedStartX + mDx); + final int y = (int) (mSelectedStartY + mDy); + if (Math.abs(y - viewHolder.itemView.getTop()) < viewHolder.itemView.getHeight() * threshold + && Math.abs(x - viewHolder.itemView.getLeft()) + < viewHolder.itemView.getWidth() * threshold) { + return; + } + List swapTargets = findSwapTargets(viewHolder); + if (swapTargets.size() == 0) { + return; + } + // may swap. + ViewHolder target = mCallback.chooseDropTarget(viewHolder, swapTargets, x, y); + if (target == null) { + mSwapTargets.clear(); + mDistances.clear(); + return; + } + final int toPosition = target.getAdapterPosition(); + final int fromPosition = viewHolder.getAdapterPosition(); + if (mCallback.onMove(mRecyclerView, viewHolder, target)) { + // keep target visible + mCallback.onMoved(mRecyclerView, viewHolder, fromPosition, + target, toPosition, x, y); + } + } + + @Override + public void onChildViewAttachedToWindow(View view) { + } + + @Override + public void onChildViewDetachedFromWindow(View view) { + removeChildDrawingOrderCallbackIfNecessary(view); + final ViewHolder holder = mRecyclerView.getChildViewHolder(view); + if (holder == null) { + return; + } + if (mSelected != null && holder == mSelected) { + select(null, ACTION_STATE_IDLE); + } else { + endRecoverAnimation(holder, false); // this may push it into pending cleanup list. + if (mPendingCleanup.remove(holder.itemView)) { + mCallback.clearView(mRecyclerView, holder); + } + } + } + + /** + * Returns the animation type or 0 if cannot be found. + */ + private int endRecoverAnimation(ViewHolder viewHolder, boolean override) { + final int recoverAnimSize = mRecoverAnimations.size(); + for (int i = recoverAnimSize - 1; i >= 0; i--) { + final RecoverAnimation anim = mRecoverAnimations.get(i); + if (anim.mViewHolder == viewHolder) { + anim.mOverridden |= override; + if (!anim.mEnded) { + anim.cancel(); + } + mRecoverAnimations.remove(i); + return anim.mAnimationType; + } + } + return 0; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, + RecyclerView.State state) { + outRect.setEmpty(); + } + + private void obtainVelocityTracker() { + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + } + mVelocityTracker = VelocityTracker.obtain(); + } + + private void releaseVelocityTracker() { + if (mVelocityTracker != null) { + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + } + + private ViewHolder findSwipedView(MotionEvent motionEvent) { + final RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager(); + if (mActivePointerId == ACTIVE_POINTER_ID_NONE) { + return null; + } + final int pointerIndex = MotionEventCompat.findPointerIndex(motionEvent, mActivePointerId); + final float dx = MotionEventCompat.getX(motionEvent, pointerIndex) - mInitialTouchX; + final float dy = MotionEventCompat.getY(motionEvent, pointerIndex) - mInitialTouchY; + final float absDx = Math.abs(dx); + final float absDy = Math.abs(dy); + + if (absDx < mSlop && absDy < mSlop) { + return null; + } + if (absDx > absDy && lm.canScrollHorizontally()) { + return null; + } else if (absDy > absDx && lm.canScrollVertically()) { + return null; + } + View child = findChildView(motionEvent); + if (child == null) { + return null; + } + return mRecyclerView.getChildViewHolder(child); + } + + /** + * Checks whether we should select a View for swiping. + */ + private boolean checkSelectForSwipe(int action, MotionEvent motionEvent, int pointerIndex) { + if (mSelected != null || action != MotionEvent.ACTION_MOVE + || mActionState == ACTION_STATE_DRAG || !mCallback.isItemViewSwipeEnabled()) { + return false; + } + if (mRecyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) { + return false; + } + final ViewHolder vh = findSwipedView(motionEvent); + if (vh == null) { + return false; + } + final int movementFlags = mCallback.getAbsoluteMovementFlags(mRecyclerView, vh); + + final int swipeFlags = (movementFlags & ACTION_MODE_SWIPE_MASK) + >> (DIRECTION_FLAG_COUNT * ACTION_STATE_SWIPE); + + if (swipeFlags == 0) { + return false; + } + + // mDx and mDy are only set in allowed directions. We use custom x/y here instead of + // updateDxDy to avoid swiping if user moves more in the other direction + final float x = MotionEventCompat.getX(motionEvent, pointerIndex); + final float y = MotionEventCompat.getY(motionEvent, pointerIndex); + + // Calculate the distance moved + final float dx = x - mInitialTouchX; + final float dy = y - mInitialTouchY; + // swipe target is chose w/o applying flags so it does not really check if swiping in that + // direction is allowed. This why here, we use mDx mDy to check slope value again. + final float absDx = Math.abs(dx); + final float absDy = Math.abs(dy); + + if (absDx < mSlop && absDy < mSlop) { + return false; + } + if (absDx > absDy) { + if (dx < 0 && (swipeFlags & LEFT) == 0) { + return false; + } + if (dx > 0 && (swipeFlags & RIGHT) == 0) { + return false; + } + } else { + if (dy < 0 && (swipeFlags & UP) == 0) { + return false; + } + if (dy > 0 && (swipeFlags & DOWN) == 0) { + return false; + } + } + mDx = mDy = 0f; + mActivePointerId = MotionEventCompat.getPointerId(motionEvent, 0); + select(vh, ACTION_STATE_SWIPE); + return true; + } + + private View findChildView(MotionEvent event) { + // first check elevated views, if none, then call RV + final float x = event.getX(); + final float y = event.getY(); + if (mSelected != null) { + final View selectedView = mSelected.itemView; + if (hitTest(selectedView, x, y, mSelectedStartX + mDx, mSelectedStartY + mDy)) { + return selectedView; + } + } + for (int i = mRecoverAnimations.size() - 1; i >= 0; i--) { + final RecoverAnimation anim = mRecoverAnimations.get(i); + final View view = anim.mViewHolder.itemView; + if (hitTest(view, x, y, anim.mX, anim.mY)) { + return view; + } + } + return mRecyclerView.findChildViewUnder(x, y); + } + + /** + * Starts dragging the provided ViewHolder. By default, ItemTouchHelper starts a drag when a + * View is long pressed. You can disable that behavior by overriding + * {@link ItemTouchHelper.Callback#isLongPressDragEnabled()}. + *

+ * For this method to work: + *

    + *
  • The provided ViewHolder must be a child of the RecyclerView to which this + * ItemTouchHelper + * is attached.
  • + *
  • {@link ItemTouchHelper.Callback} must have dragging enabled.
  • + *
  • There must be a previous touch event that was reported to the ItemTouchHelper + * through RecyclerView's ItemTouchListener mechanism. As long as no other ItemTouchListener + * grabs previous events, this should work as expected.
  • + *
+ * + * For example, if you would like to let your user to be able to drag an Item by touching one + * of its descendants, you may implement it as follows: + *
+     *     viewHolder.dragButton.setOnTouchListener(new View.OnTouchListener() {
+     *         public boolean onTouch(View v, MotionEvent event) {
+     *             if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
+     *                 mItemTouchHelper.startDrag(viewHolder);
+     *             }
+     *             return false;
+     *         }
+     *     });
+     * 
+ *

+ * + * @param viewHolder The ViewHolder to start dragging. It must be a direct child of + * RecyclerView. + * @see ItemTouchHelper.Callback#isItemViewSwipeEnabled() + */ + public void startDrag(ViewHolder viewHolder) { + if (!mCallback.hasDragFlag(mRecyclerView, viewHolder)) { + Log.e(TAG, "Start drag has been called but swiping is not enabled"); + return; + } + if (viewHolder.itemView.getParent() != mRecyclerView) { + Log.e(TAG, "Start drag has been called with a view holder which is not a child of " + + "the RecyclerView which is controlled by this ItemTouchHelper."); + return; + } + obtainVelocityTracker(); + mDx = mDy = 0f; + select(viewHolder, ACTION_STATE_DRAG); + } + + /** + * Starts swiping the provided ViewHolder. By default, ItemTouchHelper starts swiping a View + * when user swipes their finger (or mouse pointer) over the View. You can disable this + * behavior + * by overriding {@link ItemTouchHelper.Callback} + *

+ * For this method to work: + *

    + *
  • The provided ViewHolder must be a child of the RecyclerView to which this + * ItemTouchHelper is attached.
  • + *
  • {@link ItemTouchHelper.Callback} must have swiping enabled.
  • + *
  • There must be a previous touch event that was reported to the ItemTouchHelper + * through RecyclerView's ItemTouchListener mechanism. As long as no other ItemTouchListener + * grabs previous events, this should work as expected.
  • + *
+ * + * For example, if you would like to let your user to be able to swipe an Item by touching one + * of its descendants, you may implement it as follows: + *
+     *     viewHolder.dragButton.setOnTouchListener(new View.OnTouchListener() {
+     *         public boolean onTouch(View v, MotionEvent event) {
+     *             if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
+     *                 mItemTouchHelper.startSwipe(viewHolder);
+     *             }
+     *             return false;
+     *         }
+     *     });
+     * 
+ * + * @param viewHolder The ViewHolder to start swiping. It must be a direct child of + * RecyclerView. + */ + public void startSwipe(ViewHolder viewHolder) { + if (!mCallback.hasSwipeFlag(mRecyclerView, viewHolder)) { + Log.e(TAG, "Start swipe has been called but dragging is not enabled"); + return; + } + if (viewHolder.itemView.getParent() != mRecyclerView) { + Log.e(TAG, "Start swipe has been called with a view holder which is not a child of " + + "the RecyclerView controlled by this ItemTouchHelper."); + return; + } + obtainVelocityTracker(); + mDx = mDy = 0f; + select(viewHolder, ACTION_STATE_SWIPE); + } + + private RecoverAnimation findAnimation(MotionEvent event) { + if (mRecoverAnimations.isEmpty()) { + return null; + } + View target = findChildView(event); + for (int i = mRecoverAnimations.size() - 1; i >= 0; i--) { + final RecoverAnimation anim = mRecoverAnimations.get(i); + if (anim.mViewHolder.itemView == target) { + return anim; + } + } + return null; + } + + private void updateDxDy(MotionEvent ev, int directionFlags, int pointerIndex) { + final float x = MotionEventCompat.getX(ev, pointerIndex); + final float y = MotionEventCompat.getY(ev, pointerIndex); + + // Calculate the distance moved + mDx = x - mInitialTouchX; + mDy = y - mInitialTouchY; + if ((directionFlags & LEFT) == 0) { + mDx = Math.max(0, mDx); + } + if ((directionFlags & RIGHT) == 0) { + mDx = Math.min(0, mDx); + } + if ((directionFlags & UP) == 0) { + mDy = Math.max(0, mDy); + } + if ((directionFlags & DOWN) == 0) { + mDy = Math.min(0, mDy); + } + } + + private int swipeIfNecessary(ViewHolder viewHolder) { + if (mActionState == ACTION_STATE_DRAG) { + return 0; + } + final int originalMovementFlags = mCallback.getMovementFlags(mRecyclerView, viewHolder); + final int absoluteMovementFlags = mCallback.convertToAbsoluteDirection( + originalMovementFlags, + ViewCompat.getLayoutDirection(mRecyclerView)); + final int flags = (absoluteMovementFlags + & ACTION_MODE_SWIPE_MASK) >> (ACTION_STATE_SWIPE * DIRECTION_FLAG_COUNT); + if (flags == 0) { + return 0; + } + final int originalFlags = (originalMovementFlags + & ACTION_MODE_SWIPE_MASK) >> (ACTION_STATE_SWIPE * DIRECTION_FLAG_COUNT); + int swipeDir; + if (Math.abs(mDx) > Math.abs(mDy)) { + if ((swipeDir = checkHorizontalSwipe(viewHolder, flags)) > 0) { + // if swipe dir is not in original flags, it should be the relative direction + if ((originalFlags & swipeDir) == 0) { + // convert to relative + return Callback.convertToRelativeDirection(swipeDir, + ViewCompat.getLayoutDirection(mRecyclerView)); + } + return swipeDir; + } + if ((swipeDir = checkVerticalSwipe(viewHolder, flags)) > 0) { + return swipeDir; + } + } else { + if ((swipeDir = checkVerticalSwipe(viewHolder, flags)) > 0) { + return swipeDir; + } + if ((swipeDir = checkHorizontalSwipe(viewHolder, flags)) > 0) { + // if swipe dir is not in original flags, it should be the relative direction + if ((originalFlags & swipeDir) == 0) { + // convert to relative + return Callback.convertToRelativeDirection(swipeDir, + ViewCompat.getLayoutDirection(mRecyclerView)); + } + return swipeDir; + } + } + return 0; + } + + private int checkHorizontalSwipe(ViewHolder viewHolder, int flags) { + if ((flags & (LEFT | RIGHT)) != 0) { + final int dirFlag = mDx > 0 ? RIGHT : LEFT; + if (mVelocityTracker != null && mActivePointerId > -1) { + mVelocityTracker.computeCurrentVelocity(PIXELS_PER_SECOND, + mCallback.getSwipeVelocityThreshold(mMaxSwipeVelocity)); + final float xVelocity = VelocityTrackerCompat + .getXVelocity(mVelocityTracker, mActivePointerId); + final float yVelocity = VelocityTrackerCompat + .getYVelocity(mVelocityTracker, mActivePointerId); + final int velDirFlag = xVelocity > 0f ? RIGHT : LEFT; + final float absXVelocity = Math.abs(xVelocity); + if ((velDirFlag & flags) != 0 && dirFlag == velDirFlag && + absXVelocity >= mCallback.getSwipeEscapeVelocity(mSwipeEscapeVelocity) && + absXVelocity > Math.abs(yVelocity)) { + return velDirFlag; + } + } + + final float threshold = mRecyclerView.getWidth() * mCallback + .getSwipeThreshold(viewHolder); + + if ((flags & dirFlag) != 0 && Math.abs(mDx) > threshold) { + return dirFlag; + } + } + return 0; + } + + private int checkVerticalSwipe(ViewHolder viewHolder, int flags) { + if ((flags & (UP | DOWN)) != 0) { + final int dirFlag = mDy > 0 ? DOWN : UP; + if (mVelocityTracker != null && mActivePointerId > -1) { + mVelocityTracker.computeCurrentVelocity(PIXELS_PER_SECOND, + mCallback.getSwipeVelocityThreshold(mMaxSwipeVelocity)); + final float xVelocity = VelocityTrackerCompat + .getXVelocity(mVelocityTracker, mActivePointerId); + final float yVelocity = VelocityTrackerCompat + .getYVelocity(mVelocityTracker, mActivePointerId); + final int velDirFlag = yVelocity > 0f ? DOWN : UP; + final float absYVelocity = Math.abs(yVelocity); + if ((velDirFlag & flags) != 0 && velDirFlag == dirFlag && + absYVelocity >= mCallback.getSwipeEscapeVelocity(mSwipeEscapeVelocity) && + absYVelocity > Math.abs(xVelocity)) { + return velDirFlag; + } + } + + final float threshold = mRecyclerView.getHeight() * mCallback + .getSwipeThreshold(viewHolder); + if ((flags & dirFlag) != 0 && Math.abs(mDy) > threshold) { + return dirFlag; + } + } + return 0; + } + + private void addChildDrawingOrderCallback() { + if (Build.VERSION.SDK_INT >= 21) { + return;// we use elevation on Lollipop + } + if (mChildDrawingOrderCallback == null) { + mChildDrawingOrderCallback = new RecyclerView.ChildDrawingOrderCallback() { + @Override + public int onGetChildDrawingOrder(int childCount, int i) { + if (mOverdrawChild == null) { + return i; + } + int childPosition = mOverdrawChildPosition; + if (childPosition == -1) { + childPosition = mRecyclerView.indexOfChild(mOverdrawChild); + mOverdrawChildPosition = childPosition; + } + if (i == childCount - 1) { + return childPosition; + } + return i < childPosition ? i : i + 1; + } + }; + } + mRecyclerView.setChildDrawingOrderCallback(mChildDrawingOrderCallback); + } + + private void removeChildDrawingOrderCallbackIfNecessary(View view) { + if (view == mOverdrawChild) { + mOverdrawChild = null; + // only remove if we've added + if (mChildDrawingOrderCallback != null) { + mRecyclerView.setChildDrawingOrderCallback(null); + } + } + } + + /** + * An interface which can be implemented by LayoutManager for better integration with + * {@link ItemTouchHelper}. + */ + public static interface ViewDropHandler { + + /** + * Called by the {@link ItemTouchHelper} after a View is dropped over another View. + *

+ * A LayoutManager should implement this interface to get ready for the upcoming move + * operation. + *

+ * For example, LinearLayoutManager sets up a "scrollToPositionWithOffset" calls so that + * the View under drag will be used as an anchor View while calculating the next layout, + * making layout stay consistent. + * + * @param view The View which is being dragged. It is very likely that user is still + * dragging this View so there might be other + * {@link #prepareForDrop(View, View, int, int)} after this one. + * @param target The target view which is being dropped on. + * @param x The left offset of the View that is being dragged. This value + * includes the movement caused by the user. + * @param y The top offset of the View that is being dragged. This value + * includes the movement caused by the user. + */ + public void prepareForDrop(View view, View target, int x, int y); + } + + /** + * This class is the contract between ItemTouchHelper and your application. It lets you control + * which touch behaviors are enabled per each ViewHolder and also receive callbacks when user + * performs these actions. + *

+ * To control which actions user can take on each view, you should override + * {@link #getMovementFlags(RecyclerView, ViewHolder)} and return appropriate set + * of direction flags. ({@link #LEFT}, {@link #RIGHT}, {@link #START}, {@link #END}, + * {@link #UP}, {@link #DOWN}). You can use + * {@link #makeMovementFlags(int, int)} to easily construct it. Alternatively, you can use + * {@link SimpleCallback}. + *

+ * If user drags an item, ItemTouchHelper will call + * {@link Callback#onMove(RecyclerView, ViewHolder, ViewHolder) + * onMove(recyclerView, dragged, target)}. + * Upon receiving this callback, you should move the item from the old position + * ({@code dragged.getAdapterPosition()}) to new position ({@code target.getAdapterPosition()}) + * in your adapter and also call {@link RecyclerView.Adapter#notifyItemMoved(int, int)}. + * To control where a View can be dropped, you can override + * {@link #canDropOver(RecyclerView, ViewHolder, ViewHolder)}. When a + * dragging View overlaps multiple other views, Callback chooses the closest View with which + * dragged View might have changed positions. Although this approach works for many use cases, + * if you have a custom LayoutManager, you can override + * {@link #chooseDropTarget(ViewHolder, java.util.List, int, int)} to select a + * custom drop target. + *

+ * When a View is swiped, ItemTouchHelper animates it until it goes out of bounds, then calls + * {@link #onSwiped(ViewHolder, int)}. At this point, you should update your + * adapter (e.g. remove the item) and call related Adapter#notify event. + */ + @SuppressWarnings("UnusedParameters") + public abstract static class Callback { + + public static final int DEFAULT_DRAG_ANIMATION_DURATION = 200; + + public static final int DEFAULT_SWIPE_ANIMATION_DURATION = 250; + + static final int RELATIVE_DIR_FLAGS = START | END | + ((START | END) << DIRECTION_FLAG_COUNT) | + ((START | END) << (2 * DIRECTION_FLAG_COUNT)); + + private static final ItemTouchUIUtil sUICallback; + + private static final int ABS_HORIZONTAL_DIR_FLAGS = LEFT | RIGHT | + ((LEFT | RIGHT) << DIRECTION_FLAG_COUNT) | + ((LEFT | RIGHT) << (2 * DIRECTION_FLAG_COUNT)); + + private static final Interpolator sDragScrollInterpolator = new Interpolator() { + public float getInterpolation(float t) { + return t * t * t * t * t; + } + }; + + private static final Interpolator sDragViewScrollCapInterpolator = new Interpolator() { + public float getInterpolation(float t) { + t -= 1.0f; + return t * t * t * t * t + 1.0f; + } + }; + + /** + * Drag scroll speed keeps accelerating until this many milliseconds before being capped. + */ + private static final long DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS = 500; + + private int mCachedMaxScrollSpeed = -1; + + static { + if (Build.VERSION.SDK_INT >= 21) { + sUICallback = new ItemTouchUIUtilImpl.Lollipop(); + } else if (Build.VERSION.SDK_INT >= 11) { + sUICallback = new ItemTouchUIUtilImpl.Honeycomb(); + } else { + sUICallback = new ItemTouchUIUtilImpl.Gingerbread(); + } + } + + /** + * Returns the {@link ItemTouchUIUtil} that is used by the {@link Callback} class for + * visual + * changes on Views in response to user interactions. {@link ItemTouchUIUtil} has different + * implementations for different platform versions. + *

+ * By default, {@link Callback} applies these changes on + * {@link RecyclerView.ViewHolder#itemView}. + *

+ * For example, if you have a use case where you only want the text to move when user + * swipes over the view, you can do the following: + *

+         *     public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder){
+         *         getDefaultUIUtil().clearView(((ItemTouchViewHolder) viewHolder).textView);
+         *     }
+         *     public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
+         *         if (viewHolder != null){
+         *             getDefaultUIUtil().onSelected(((ItemTouchViewHolder) viewHolder).textView);
+         *         }
+         *     }
+         *     public void onChildDraw(Canvas c, RecyclerView recyclerView,
+         *             RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState,
+         *             boolean isCurrentlyActive) {
+         *         getDefaultUIUtil().onDraw(c, recyclerView,
+         *                 ((ItemTouchViewHolder) viewHolder).textView, dX, dY,
+         *                 actionState, isCurrentlyActive);
+         *         return true;
+         *     }
+         *     public void onChildDrawOver(Canvas c, RecyclerView recyclerView,
+         *             RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState,
+         *             boolean isCurrentlyActive) {
+         *         getDefaultUIUtil().onDrawOver(c, recyclerView,
+         *                 ((ItemTouchViewHolder) viewHolder).textView, dX, dY,
+         *                 actionState, isCurrentlyActive);
+         *         return true;
+         *     }
+         * 
+ * + * @return The {@link ItemTouchUIUtil} instance that is used by the {@link Callback} + */ + public static ItemTouchUIUtil getDefaultUIUtil() { + return sUICallback; + } + + /** + * Replaces a movement direction with its relative version by taking layout direction into + * account. + * + * @param flags The flag value that include any number of movement flags. + * @param layoutDirection The layout direction of the View. Can be obtained from + * {@link ViewCompat#getLayoutDirection(android.view.View)}. + * @return Updated flags which uses relative flags ({@link #START}, {@link #END}) instead + * of {@link #LEFT}, {@link #RIGHT}. + * @see #convertToAbsoluteDirection(int, int) + */ + public static int convertToRelativeDirection(int flags, int layoutDirection) { + int masked = flags & ABS_HORIZONTAL_DIR_FLAGS; + if (masked == 0) { + return flags;// does not have any abs flags, good. + } + flags &= ~masked; //remove left / right. + if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) { + // no change. just OR with 2 bits shifted mask and return + flags |= masked << 2; // START is 2 bits after LEFT, END is 2 bits after RIGHT. + return flags; + } else { + // add RIGHT flag as START + flags |= ((masked << 1) & ~ABS_HORIZONTAL_DIR_FLAGS); + // first clean RIGHT bit then add LEFT flag as END + flags |= ((masked << 1) & ABS_HORIZONTAL_DIR_FLAGS) << 2; + } + return flags; + } + + /** + * Convenience method to create movement flags. + *

+ * For instance, if you want to let your items be drag & dropped vertically and swiped + * left to be dismissed, you can call this method with: + * makeMovementFlags(UP | DOWN, LEFT); + * + * @param dragFlags The directions in which the item can be dragged. + * @param swipeFlags The directions in which the item can be swiped. + * @return Returns an integer composed of the given drag and swipe flags. + */ + public static int makeMovementFlags(int dragFlags, int swipeFlags) { + return makeFlag(ACTION_STATE_IDLE, swipeFlags | dragFlags) | + makeFlag(ACTION_STATE_SWIPE, swipeFlags) | makeFlag(ACTION_STATE_DRAG, + dragFlags); + } + + /** + * Shifts the given direction flags to the offset of the given action state. + * + * @param actionState The action state you want to get flags in. Should be one of + * {@link #ACTION_STATE_IDLE}, {@link #ACTION_STATE_SWIPE} or + * {@link #ACTION_STATE_DRAG}. + * @param directions The direction flags. Can be composed from {@link #UP}, {@link #DOWN}, + * {@link #RIGHT}, {@link #LEFT} {@link #START} and {@link #END}. + * @return And integer that represents the given directions in the provided actionState. + */ + public static int makeFlag(int actionState, int directions) { + return directions << (actionState * DIRECTION_FLAG_COUNT); + } + + /** + * Should return a composite flag which defines the enabled move directions in each state + * (idle, swiping, dragging). + *

+ * Instead of composing this flag manually, you can use {@link #makeMovementFlags(int, + * int)} + * or {@link #makeFlag(int, int)}. + *

+ * This flag is composed of 3 sets of 8 bits, where first 8 bits are for IDLE state, next + * 8 bits are for SWIPE state and third 8 bits are for DRAG state. + * Each 8 bit sections can be constructed by simply OR'ing direction flags defined in + * {@link ItemTouchHelper}. + *

+ * For example, if you want it to allow swiping LEFT and RIGHT but only allow starting to + * swipe by swiping RIGHT, you can return: + *

+         *      makeFlag(ACTION_STATE_IDLE, RIGHT) | makeFlag(ACTION_STATE_SWIPE, LEFT | RIGHT);
+         * 
+ * This means, allow right movement while IDLE and allow right and left movement while + * swiping. + * + * @param recyclerView The RecyclerView to which ItemTouchHelper is attached. + * @param viewHolder The ViewHolder for which the movement information is necessary. + * @return flags specifying which movements are allowed on this ViewHolder. + * @see #makeMovementFlags(int, int) + * @see #makeFlag(int, int) + */ + public abstract int getMovementFlags(RecyclerView recyclerView, + ViewHolder viewHolder); + + /** + * Converts a given set of flags to absolution direction which means {@link #START} and + * {@link #END} are replaced with {@link #LEFT} and {@link #RIGHT} depending on the layout + * direction. + * + * @param flags The flag value that include any number of movement flags. + * @param layoutDirection The layout direction of the RecyclerView. + * @return Updated flags which includes only absolute direction values. + */ + public int convertToAbsoluteDirection(int flags, int layoutDirection) { + int masked = flags & RELATIVE_DIR_FLAGS; + if (masked == 0) { + return flags;// does not have any relative flags, good. + } + flags &= ~masked; //remove start / end + if (layoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) { + // no change. just OR with 2 bits shifted mask and return + flags |= masked >> 2; // START is 2 bits after LEFT, END is 2 bits after RIGHT. + return flags; + } else { + // add START flag as RIGHT + flags |= ((masked >> 1) & ~RELATIVE_DIR_FLAGS); + // first clean start bit then add END flag as LEFT + flags |= ((masked >> 1) & RELATIVE_DIR_FLAGS) >> 2; + } + return flags; + } + + final int getAbsoluteMovementFlags(RecyclerView recyclerView, + ViewHolder viewHolder) { + final int flags = getMovementFlags(recyclerView, viewHolder); + return convertToAbsoluteDirection(flags, ViewCompat.getLayoutDirection(recyclerView)); + } + + private boolean hasDragFlag(RecyclerView recyclerView, ViewHolder viewHolder) { + final int flags = getAbsoluteMovementFlags(recyclerView, viewHolder); + return (flags & ACTION_MODE_DRAG_MASK) != 0; + } + + private boolean hasSwipeFlag(RecyclerView recyclerView, + ViewHolder viewHolder) { + final int flags = getAbsoluteMovementFlags(recyclerView, viewHolder); + return (flags & ACTION_MODE_SWIPE_MASK) != 0; + } + + /** + * Return true if the current ViewHolder can be dropped over the the target ViewHolder. + *

+ * This method is used when selecting drop target for the dragged View. After Views are + * eliminated either via bounds check or via this method, resulting set of views will be + * passed to {@link #chooseDropTarget(ViewHolder, java.util.List, int, int)}. + *

+ * Default implementation returns true. + * + * @param recyclerView The RecyclerView to which ItemTouchHelper is attached to. + * @param current The ViewHolder that user is dragging. + * @param target The ViewHolder which is below the dragged ViewHolder. + * @return True if the dragged ViewHolder can be replaced with the target ViewHolder, false + * otherwise. + */ + public boolean canDropOver(RecyclerView recyclerView, ViewHolder current, + ViewHolder target) { + return true; + } + + /** + * Called when ItemTouchHelper wants to move the dragged item from its old position to + * the new position. + *

+ * If this method returns true, ItemTouchHelper assumes {@code viewHolder} has been moved + * to the adapter position of {@code target} ViewHolder + * ({@link ViewHolder#getAdapterPosition() + * ViewHolder#getAdapterPosition()}). + *

+ * If you don't support drag & drop, this method will never be called. + * + * @param recyclerView The RecyclerView to which ItemTouchHelper is attached to. + * @param viewHolder The ViewHolder which is being dragged by the user. + * @param target The ViewHolder over which the currently active item is being + * dragged. + * @return True if the {@code viewHolder} has been moved to the adapter position of + * {@code target}. + * @see #onMoved(RecyclerView, ViewHolder, int, ViewHolder, int, int, int) + */ + public abstract boolean onMove(RecyclerView recyclerView, + ViewHolder viewHolder, ViewHolder target); + + /** + * Returns whether ItemTouchHelper should start a drag and drop operation if an item is + * long pressed. + *

+ * Default value returns true but you may want to disable this if you want to start + * dragging on a custom view touch using {@link #startDrag(ViewHolder)}. + * + * @return True if ItemTouchHelper should start dragging an item when it is long pressed, + * false otherwise. Default value is true. + * @see #startDrag(ViewHolder) + */ + public boolean isLongPressDragEnabled() { + return true; + } + + /** + * Returns whether ItemTouchHelper should start a swipe operation if a pointer is swiped + * over the View. + *

+ * Default value returns true but you may want to disable this if you want to start + * swiping on a custom view touch using {@link #startSwipe(ViewHolder)}. + * + * @return True if ItemTouchHelper should start swiping an item when user swipes a pointer + * over the View, false otherwise. Default value is true. + * @see #startSwipe(ViewHolder) + */ + public boolean isItemViewSwipeEnabled() { + return true; + } + + /** + * When finding views under a dragged view, by default, ItemTouchHelper searches for views + * that overlap with the dragged View. By overriding this method, you can extend or shrink + * the search box. + * + * @return The extra margin to be added to the hit box of the dragged View. + */ + public int getBoundingBoxMargin() { + return 0; + } + + /** + * Returns the fraction that the user should move the View to be considered as swiped. + * The fraction is calculated with respect to RecyclerView's bounds. + *

+ * Default value is .5f, which means, to swipe a View, user must move the View at least + * half of RecyclerView's width or height, depending on the swipe direction. + * + * @param viewHolder The ViewHolder that is being dragged. + * @return A float value that denotes the fraction of the View size. Default value + * is .5f . + */ + public float getSwipeThreshold(ViewHolder viewHolder) { + return .5f; + } + + /** + * Returns the fraction that the user should move the View to be considered as it is + * dragged. After a view is moved this amount, ItemTouchHelper starts checking for Views + * below it for a possible drop. + * + * @param viewHolder The ViewHolder that is being dragged. + * @return A float value that denotes the fraction of the View size. Default value is + * .5f . + */ + public float getMoveThreshold(ViewHolder viewHolder) { + return .5f; + } + + /** + * Defines the minimum velocity which will be considered as a swipe action by the user. + *

+ * You can increase this value to make it harder to swipe or decrease it to make it easier. + * Keep in mind that ItemTouchHelper also checks the perpendicular velocity and makes sure + * current direction velocity is larger then the perpendicular one. Otherwise, user's + * movement is ambiguous. You can change the threshold by overriding + * {@link #getSwipeVelocityThreshold(float)}. + *

+ * The velocity is calculated in pixels per second. + *

+ * The default framework value is passed as a parameter so that you can modify it with a + * multiplier. + * + * @param defaultValue The default value (in pixels per second) used by the + * ItemTouchHelper. + * @return The minimum swipe velocity. The default implementation returns the + * defaultValue parameter. + * @see #getSwipeVelocityThreshold(float) + * @see #getSwipeThreshold(ViewHolder) + */ + public float getSwipeEscapeVelocity(float defaultValue) { + return defaultValue; + } + + /** + * Defines the maximum velocity ItemTouchHelper will ever calculate for pointer movements. + *

+ * To consider a movement as swipe, ItemTouchHelper requires it to be larger than the + * perpendicular movement. If both directions reach to the max threshold, none of them will + * be considered as a swipe because it is usually an indication that user rather tried to + * scroll then swipe. + *

+ * The velocity is calculated in pixels per second. + *

+ * You can customize this behavior by changing this method. If you increase the value, it + * will be easier for the user to swipe diagonally and if you decrease the value, user will + * need to make a rather straight finger movement to trigger a swipe. + * + * @param defaultValue The default value(in pixels per second) used by the ItemTouchHelper. + * @return The velocity cap for pointer movements. The default implementation returns the + * defaultValue parameter. + * @see #getSwipeEscapeVelocity(float) + */ + public float getSwipeVelocityThreshold(float defaultValue) { + return defaultValue; + } + + /** + * Called by ItemTouchHelper to select a drop target from the list of ViewHolders that + * are under the dragged View. + *

+ * Default implementation filters the View with which dragged item have changed position + * in the drag direction. For instance, if the view is dragged UP, it compares the + * view.getTop() of the two views before and after drag started. If that value + * is different, the target view passes the filter. + *

+ * Among these Views which pass the test, the one closest to the dragged view is chosen. + *

+ * This method is called on the main thread every time user moves the View. If you want to + * override it, make sure it does not do any expensive operations. + * + * @param selected The ViewHolder being dragged by the user. + * @param dropTargets The list of ViewHolder that are under the dragged View and + * candidate as a drop. + * @param curX The updated left value of the dragged View after drag translations + * are applied. This value does not include margins added by + * {@link RecyclerView.ItemDecoration}s. + * @param curY The updated top value of the dragged View after drag translations + * are applied. This value does not include margins added by + * {@link RecyclerView.ItemDecoration}s. + * @return A ViewHolder to whose position the dragged ViewHolder should be + * moved to. + */ + public ViewHolder chooseDropTarget(ViewHolder selected, + List dropTargets, int curX, int curY) { + int right = curX + selected.itemView.getWidth(); + int bottom = curY + selected.itemView.getHeight(); + ViewHolder winner = null; + int winnerScore = -1; + final int dx = curX - selected.itemView.getLeft(); + final int dy = curY - selected.itemView.getTop(); + final int targetsSize = dropTargets.size(); + for (int i = 0; i < targetsSize; i++) { + final ViewHolder target = dropTargets.get(i); + if (dx > 0) { + int diff = target.itemView.getRight() - right; + if (diff < 0 && target.itemView.getRight() > selected.itemView.getRight()) { + final int score = Math.abs(diff); + if (score > winnerScore) { + winnerScore = score; + winner = target; + } + } + } + if (dx < 0) { + int diff = target.itemView.getLeft() - curX; + if (diff > 0 && target.itemView.getLeft() < selected.itemView.getLeft()) { + final int score = Math.abs(diff); + if (score > winnerScore) { + winnerScore = score; + winner = target; + } + } + } + if (dy < 0) { + int diff = target.itemView.getTop() - curY; + if (diff > 0 && target.itemView.getTop() < selected.itemView.getTop()) { + final int score = Math.abs(diff); + if (score > winnerScore) { + winnerScore = score; + winner = target; + } + } + } + + if (dy > 0) { + int diff = target.itemView.getBottom() - bottom; + if (diff < 0 && target.itemView.getBottom() > selected.itemView.getBottom()) { + final int score = Math.abs(diff); + if (score > winnerScore) { + winnerScore = score; + winner = target; + } + } + } + } + return winner; + } + + /** + * Called when a ViewHolder is swiped by the user. + *

+ * If you are returning relative directions ({@link #START} , {@link #END}) from the + * {@link #getMovementFlags(RecyclerView, ViewHolder)} method, this method + * will also use relative directions. Otherwise, it will use absolute directions. + *

+ * If you don't support swiping, this method will never be called. + *

+ * ItemTouchHelper will keep a reference to the View until it is detached from + * RecyclerView. + * As soon as it is detached, ItemTouchHelper will call + * {@link #clearView(RecyclerView, ViewHolder)}. + * + * @param viewHolder The ViewHolder which has been swiped by the user. + * @param direction The direction to which the ViewHolder is swiped. It is one of + * {@link #UP}, {@link #DOWN}, + * {@link #LEFT} or {@link #RIGHT}. If your + * {@link #getMovementFlags(RecyclerView, ViewHolder)} + * method + * returned relative flags instead of {@link #LEFT} / {@link #RIGHT}; + * `direction` will be relative as well. ({@link #START} or {@link + * #END}). + */ + public abstract void onSwiped(ViewHolder viewHolder, int direction); + + /** + * Called when the ViewHolder swiped or dragged by the ItemTouchHelper is changed. + *

+ * If you override this method, you should call super. + * + * @param viewHolder The new ViewHolder that is being swiped or dragged. Might be null if + * it is cleared. + * @param actionState One of {@link ItemTouchHelper#ACTION_STATE_IDLE}, + * {@link ItemTouchHelper#ACTION_STATE_SWIPE} or + * {@link ItemTouchHelper#ACTION_STATE_DRAG}. + * @see #clearView(RecyclerView, RecyclerView.ViewHolder) + */ + public void onSelectedChanged(ViewHolder viewHolder, int actionState) { + if (viewHolder != null) { + sUICallback.onSelected(viewHolder.itemView); + } + } + + private int getMaxDragScroll(RecyclerView recyclerView) { + if (mCachedMaxScrollSpeed == -1) { + mCachedMaxScrollSpeed = AndroidUtilities.dp(20); + } + return mCachedMaxScrollSpeed; + } + + /** + * Called when {@link #onMove(RecyclerView, ViewHolder, ViewHolder)} returns true. + *

+ * ItemTouchHelper does not create an extra Bitmap or View while dragging, instead, it + * modifies the existing View. Because of this reason, it is important that the View is + * still part of the layout after it is moved. This may not work as intended when swapped + * Views are close to RecyclerView bounds or there are gaps between them (e.g. other Views + * which were not eligible for dropping over). + *

+ * This method is responsible to give necessary hint to the LayoutManager so that it will + * keep the View in visible area. For example, for LinearLayoutManager, this is as simple + * as calling {@link LinearLayoutManager#scrollToPositionWithOffset(int, int)}. + * + * Default implementation calls {@link RecyclerView#scrollToPosition(int)} if the View's + * new position is likely to be out of bounds. + *

+ * It is important to ensure the ViewHolder will stay visible as otherwise, it might be + * removed by the LayoutManager if the move causes the View to go out of bounds. In that + * case, drag will end prematurely. + * + * @param recyclerView The RecyclerView controlled by the ItemTouchHelper. + * @param viewHolder The ViewHolder under user's control. + * @param fromPos The previous adapter position of the dragged item (before it was + * moved). + * @param target The ViewHolder on which the currently active item has been dropped. + * @param toPos The new adapter position of the dragged item. + * @param x The updated left value of the dragged View after drag translations + * are applied. This value does not include margins added by + * {@link RecyclerView.ItemDecoration}s. + * @param y The updated top value of the dragged View after drag translations + * are applied. This value does not include margins added by + * {@link RecyclerView.ItemDecoration}s. + */ + public void onMoved(final RecyclerView recyclerView, + final ViewHolder viewHolder, int fromPos, final ViewHolder target, int toPos, int x, + int y) { + final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); + if (layoutManager instanceof ViewDropHandler) { + ((ViewDropHandler) layoutManager).prepareForDrop(viewHolder.itemView, + target.itemView, x, y); + return; + } + + // if layout manager cannot handle it, do some guesswork + if (layoutManager.canScrollHorizontally()) { + final int minLeft = layoutManager.getDecoratedLeft(target.itemView); + if (minLeft <= recyclerView.getPaddingLeft()) { + recyclerView.scrollToPosition(toPos); + } + final int maxRight = layoutManager.getDecoratedRight(target.itemView); + if (maxRight >= recyclerView.getWidth() - recyclerView.getPaddingRight()) { + recyclerView.scrollToPosition(toPos); + } + } + + if (layoutManager.canScrollVertically()) { + final int minTop = layoutManager.getDecoratedTop(target.itemView); + if (minTop <= recyclerView.getPaddingTop()) { + recyclerView.scrollToPosition(toPos); + } + final int maxBottom = layoutManager.getDecoratedBottom(target.itemView); + if (maxBottom >= recyclerView.getHeight() - recyclerView.getPaddingBottom()) { + recyclerView.scrollToPosition(toPos); + } + } + } + + private void onDraw(Canvas c, RecyclerView parent, ViewHolder selected, + List recoverAnimationList, + int actionState, float dX, float dY) { + final int recoverAnimSize = recoverAnimationList.size(); + for (int i = 0; i < recoverAnimSize; i++) { + final ItemTouchHelper.RecoverAnimation anim = recoverAnimationList.get(i); + anim.update(); + final int count = c.save(); + onChildDraw(c, parent, anim.mViewHolder, anim.mX, anim.mY, anim.mActionState, + false); + c.restoreToCount(count); + } + if (selected != null) { + final int count = c.save(); + onChildDraw(c, parent, selected, dX, dY, actionState, true); + c.restoreToCount(count); + } + } + + private void onDrawOver(Canvas c, RecyclerView parent, ViewHolder selected, + List recoverAnimationList, + int actionState, float dX, float dY) { + final int recoverAnimSize = recoverAnimationList.size(); + for (int i = 0; i < recoverAnimSize; i++) { + final ItemTouchHelper.RecoverAnimation anim = recoverAnimationList.get(i); + final int count = c.save(); + onChildDrawOver(c, parent, anim.mViewHolder, anim.mX, anim.mY, anim.mActionState, + false); + c.restoreToCount(count); + } + if (selected != null) { + final int count = c.save(); + onChildDrawOver(c, parent, selected, dX, dY, actionState, true); + c.restoreToCount(count); + } + boolean hasRunningAnimation = false; + for (int i = recoverAnimSize - 1; i >= 0; i--) { + final RecoverAnimation anim = recoverAnimationList.get(i); + if (anim.mEnded && !anim.mIsPendingCleanup) { + recoverAnimationList.remove(i); + } else if (!anim.mEnded) { + hasRunningAnimation = true; + } + } + if (hasRunningAnimation) { + parent.invalidate(); + } + } + + /** + * Called by the ItemTouchHelper when the user interaction with an element is over and it + * also completed its animation. + *

+ * This is a good place to clear all changes on the View that was done in + * {@link #onSelectedChanged(RecyclerView.ViewHolder, int)}, + * {@link #onChildDraw(Canvas, RecyclerView, ViewHolder, float, float, int, + * boolean)} or + * {@link #onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int, boolean)}. + * + * @param recyclerView The RecyclerView which is controlled by the ItemTouchHelper. + * @param viewHolder The View that was interacted by the user. + */ + public void clearView(RecyclerView recyclerView, ViewHolder viewHolder) { + sUICallback.clearView(viewHolder.itemView); + } + + /** + * Called by ItemTouchHelper on RecyclerView's onDraw callback. + *

+ * If you would like to customize how your View's respond to user interactions, this is + * a good place to override. + *

+ * Default implementation translates the child by the given dX, + * dY. + * ItemTouchHelper also takes care of drawing the child after other children if it is being + * dragged. This is done using child re-ordering mechanism. On platforms prior to L, this + * is + * achieved via {@link android.view.ViewGroup#getChildDrawingOrder(int, int)} and on L + * and after, it changes View's elevation value to be greater than all other children.) + * + * @param c The canvas which RecyclerView is drawing its children + * @param recyclerView The RecyclerView to which ItemTouchHelper is attached to + * @param viewHolder The ViewHolder which is being interacted by the User or it was + * interacted and simply animating to its original position + * @param dX The amount of horizontal displacement caused by user's action + * @param dY The amount of vertical displacement caused by user's action + * @param actionState The type of interaction on the View. Is either {@link + * #ACTION_STATE_DRAG} or {@link #ACTION_STATE_SWIPE}. + * @param isCurrentlyActive True if this view is currently being controlled by the user or + * false it is simply animating back to its original state. + * @see #onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int, + * boolean) + */ + public void onChildDraw(Canvas c, RecyclerView recyclerView, + ViewHolder viewHolder, + float dX, float dY, int actionState, boolean isCurrentlyActive) { + sUICallback.onDraw(c, recyclerView, viewHolder.itemView, dX, dY, actionState, + isCurrentlyActive); + } + + /** + * Called by ItemTouchHelper on RecyclerView's onDraw callback. + *

+ * If you would like to customize how your View's respond to user interactions, this is + * a good place to override. + *

+ * Default implementation translates the child by the given dX, + * dY. + * ItemTouchHelper also takes care of drawing the child after other children if it is being + * dragged. This is done using child re-ordering mechanism. On platforms prior to L, this + * is + * achieved via {@link android.view.ViewGroup#getChildDrawingOrder(int, int)} and on L + * and after, it changes View's elevation value to be greater than all other children.) + * + * @param c The canvas which RecyclerView is drawing its children + * @param recyclerView The RecyclerView to which ItemTouchHelper is attached to + * @param viewHolder The ViewHolder which is being interacted by the User or it was + * interacted and simply animating to its original position + * @param dX The amount of horizontal displacement caused by user's action + * @param dY The amount of vertical displacement caused by user's action + * @param actionState The type of interaction on the View. Is either {@link + * #ACTION_STATE_DRAG} or {@link #ACTION_STATE_SWIPE}. + * @param isCurrentlyActive True if this view is currently being controlled by the user or + * false it is simply animating back to its original state. + * @see #onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int, + * boolean) + */ + public void onChildDrawOver(Canvas c, RecyclerView recyclerView, + ViewHolder viewHolder, + float dX, float dY, int actionState, boolean isCurrentlyActive) { + sUICallback.onDrawOver(c, recyclerView, viewHolder.itemView, dX, dY, actionState, + isCurrentlyActive); + } + + /** + * Called by the ItemTouchHelper when user action finished on a ViewHolder and now the View + * will be animated to its final position. + *

+ * Default implementation uses ItemAnimator's duration values. If + * animationType is {@link #ANIMATION_TYPE_DRAG}, it returns + * {@link RecyclerView.ItemAnimator#getMoveDuration()}, otherwise, it returns + * {@link RecyclerView.ItemAnimator#getRemoveDuration()}. If RecyclerView does not have + * any {@link RecyclerView.ItemAnimator} attached, this method returns + * {@code DEFAULT_DRAG_ANIMATION_DURATION} or {@code DEFAULT_SWIPE_ANIMATION_DURATION} + * depending on the animation type. + * + * @param recyclerView The RecyclerView to which the ItemTouchHelper is attached to. + * @param animationType The type of animation. Is one of {@link #ANIMATION_TYPE_DRAG}, + * {@link #ANIMATION_TYPE_SWIPE_CANCEL} or + * {@link #ANIMATION_TYPE_SWIPE_SUCCESS}. + * @param animateDx The horizontal distance that the animation will offset + * @param animateDy The vertical distance that the animation will offset + * @return The duration for the animation + */ + public long getAnimationDuration(RecyclerView recyclerView, int animationType, + float animateDx, float animateDy) { + final RecyclerView.ItemAnimator itemAnimator = recyclerView.getItemAnimator(); + if (itemAnimator == null) { + return animationType == ANIMATION_TYPE_DRAG ? DEFAULT_DRAG_ANIMATION_DURATION + : DEFAULT_SWIPE_ANIMATION_DURATION; + } else { + return animationType == ANIMATION_TYPE_DRAG ? itemAnimator.getMoveDuration() + : itemAnimator.getRemoveDuration(); + } + } + + /** + * Called by the ItemTouchHelper when user is dragging a view out of bounds. + *

+ * You can override this method to decide how much RecyclerView should scroll in response + * to this action. Default implementation calculates a value based on the amount of View + * out of bounds and the time it spent there. The longer user keeps the View out of bounds, + * the faster the list will scroll. Similarly, the larger portion of the View is out of + * bounds, the faster the RecyclerView will scroll. + * + * @param recyclerView The RecyclerView instance to which ItemTouchHelper is + * attached to. + * @param viewSize The total size of the View in scroll direction, excluding + * item decorations. + * @param viewSizeOutOfBounds The total size of the View that is out of bounds. This value + * is negative if the View is dragged towards left or top edge. + * @param totalSize The total size of RecyclerView in the scroll direction. + * @param msSinceStartScroll The time passed since View is kept out of bounds. + * @return The amount that RecyclerView should scroll. Keep in mind that this value will + * be passed to {@link RecyclerView#scrollBy(int, int)} method. + */ + public int interpolateOutOfBoundsScroll(RecyclerView recyclerView, + int viewSize, int viewSizeOutOfBounds, + int totalSize, long msSinceStartScroll) { + final int maxScroll = getMaxDragScroll(recyclerView); + final int absOutOfBounds = Math.abs(viewSizeOutOfBounds); + final int direction = (int) Math.signum(viewSizeOutOfBounds); + // might be negative if other direction + float outOfBoundsRatio = Math.min(1f, 1f * absOutOfBounds / viewSize); + final int cappedScroll = (int) (direction * maxScroll * + sDragViewScrollCapInterpolator.getInterpolation(outOfBoundsRatio)); + final float timeRatio; + if (msSinceStartScroll > DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS) { + timeRatio = 1f; + } else { + timeRatio = (float) msSinceStartScroll / DRAG_SCROLL_ACCELERATION_LIMIT_TIME_MS; + } + final int value = (int) (cappedScroll * sDragScrollInterpolator + .getInterpolation(timeRatio)); + if (value == 0) { + return viewSizeOutOfBounds > 0 ? 1 : -1; + } + return value; + } + } + + /** + * A simple wrapper to the default Callback which you can construct with drag and swipe + * directions and this class will handle the flag callbacks. You should still override onMove + * or + * onSwiped depending on your use case. + * + *

+     * ItemTouchHelper mIth = new ItemTouchHelper(
+     *     new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN,
+     *         ItemTouchHelper.LEFT) {
+     *         public abstract boolean onMove(RecyclerView recyclerView,
+     *             ViewHolder viewHolder, ViewHolder target) {
+     *             final int fromPos = viewHolder.getAdapterPosition();
+     *             final int toPos = viewHolder.getAdapterPosition();
+     *             // move item in `fromPos` to `toPos` in adapter.
+     *             return true;// true if moved, false otherwise
+     *         }
+     *         public void onSwiped(ViewHolder viewHolder, int direction) {
+     *             // remove from adapter
+     *         }
+     * });
+     * 
+ */ + public abstract static class SimpleCallback extends Callback { + + private int mDefaultSwipeDirs; + + private int mDefaultDragDirs; + + /** + * Creates a Callback for the given drag and swipe allowance. These values serve as + * defaults + * and if you want to customize behavior per ViewHolder, you can override + * {@link #getSwipeDirs(RecyclerView, ViewHolder)} + * and / or {@link #getDragDirs(RecyclerView, ViewHolder)}. + * + * @param dragDirs Binary OR of direction flags in which the Views can be dragged. Must be + * composed of {@link #LEFT}, {@link #RIGHT}, {@link #START}, {@link + * #END}, + * {@link #UP} and {@link #DOWN}. + * @param swipeDirs Binary OR of direction flags in which the Views can be swiped. Must be + * composed of {@link #LEFT}, {@link #RIGHT}, {@link #START}, {@link + * #END}, + * {@link #UP} and {@link #DOWN}. + */ + public SimpleCallback(int dragDirs, int swipeDirs) { + mDefaultSwipeDirs = swipeDirs; + mDefaultDragDirs = dragDirs; + } + + /** + * Updates the default swipe directions. For example, you can use this method to toggle + * certain directions depending on your use case. + * + * @param defaultSwipeDirs Binary OR of directions in which the ViewHolders can be swiped. + */ + public void setDefaultSwipeDirs(int defaultSwipeDirs) { + mDefaultSwipeDirs = defaultSwipeDirs; + } + + /** + * Updates the default drag directions. For example, you can use this method to toggle + * certain directions depending on your use case. + * + * @param defaultDragDirs Binary OR of directions in which the ViewHolders can be dragged. + */ + public void setDefaultDragDirs(int defaultDragDirs) { + mDefaultDragDirs = defaultDragDirs; + } + + /** + * Returns the swipe directions for the provided ViewHolder. + * Default implementation returns the swipe directions that was set via constructor or + * {@link #setDefaultSwipeDirs(int)}. + * + * @param recyclerView The RecyclerView to which the ItemTouchHelper is attached to. + * @param viewHolder The RecyclerView for which the swipe drection is queried. + * @return A binary OR of direction flags. + */ + public int getSwipeDirs(RecyclerView recyclerView, ViewHolder viewHolder) { + return mDefaultSwipeDirs; + } + + /** + * Returns the drag directions for the provided ViewHolder. + * Default implementation returns the drag directions that was set via constructor or + * {@link #setDefaultDragDirs(int)}. + * + * @param recyclerView The RecyclerView to which the ItemTouchHelper is attached to. + * @param viewHolder The RecyclerView for which the swipe drection is queried. + * @return A binary OR of direction flags. + */ + public int getDragDirs(RecyclerView recyclerView, ViewHolder viewHolder) { + return mDefaultDragDirs; + } + + @Override + public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) { + return makeMovementFlags(getDragDirs(recyclerView, viewHolder), + getSwipeDirs(recyclerView, viewHolder)); + } + } + + private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener { + + @Override + public boolean onDown(MotionEvent e) { + return true; + } + + @Override + public void onLongPress(MotionEvent e) { + View child = findChildView(e); + if (child != null) { + ViewHolder vh = mRecyclerView.getChildViewHolder(child); + if (vh != null) { + if (!mCallback.hasDragFlag(mRecyclerView, vh)) { + return; + } + int pointerId = MotionEventCompat.getPointerId(e, 0); + // Long press is deferred. + // Check w/ active pointer id to avoid selecting after motion + // event is canceled. + if (pointerId == mActivePointerId) { + final int index = MotionEventCompat + .findPointerIndex(e, mActivePointerId); + final float x = MotionEventCompat.getX(e, index); + final float y = MotionEventCompat.getY(e, index); + mInitialTouchX = x; + mInitialTouchY = y; + mDx = mDy = 0f; + if (DEBUG) { + Log.d(TAG, + "onlong press: x:" + mInitialTouchX + ",y:" + mInitialTouchY); + } + if (mCallback.isLongPressDragEnabled()) { + select(vh, ACTION_STATE_DRAG); + } + } + } + } + } + } + + private class RecoverAnimation implements AnimatorListenerCompat { + + final float mStartDx; + + final float mStartDy; + + final float mTargetX; + + final float mTargetY; + + final ViewHolder mViewHolder; + + final int mActionState; + + private final ValueAnimatorCompat mValueAnimator; + + private final int mAnimationType; + + public boolean mIsPendingCleanup; + + float mX; + + float mY; + + // if user starts touching a recovering view, we put it into interaction mode again, + // instantly. + boolean mOverridden = false; + + private boolean mEnded = false; + + private float mFraction; + + public RecoverAnimation(ViewHolder viewHolder, int animationType, + int actionState, float startDx, float startDy, float targetX, float targetY) { + mActionState = actionState; + mAnimationType = animationType; + mViewHolder = viewHolder; + mStartDx = startDx; + mStartDy = startDy; + mTargetX = targetX; + mTargetY = targetY; + mValueAnimator = AnimatorCompatHelper.emptyValueAnimator(); + mValueAnimator.addUpdateListener( + new AnimatorUpdateListenerCompat() { + @Override + public void onAnimationUpdate(ValueAnimatorCompat animation) { + setFraction(animation.getAnimatedFraction()); + } + }); + mValueAnimator.setTarget(viewHolder.itemView); + mValueAnimator.addListener(this); + setFraction(0f); + } + + public void setDuration(long duration) { + mValueAnimator.setDuration(duration); + } + + public void start() { + mViewHolder.setIsRecyclable(false); + mValueAnimator.start(); + } + + public void cancel() { + mValueAnimator.cancel(); + } + + public void setFraction(float fraction) { + mFraction = fraction; + } + + /** + * We run updates on onDraw method but use the fraction from animator callback. + * This way, we can sync translate x/y values w/ the animators to avoid one-off frames. + */ + public void update() { + if (mStartDx == mTargetX) { + mX = ViewCompat.getTranslationX(mViewHolder.itemView); + } else { + mX = mStartDx + mFraction * (mTargetX - mStartDx); + } + if (mStartDy == mTargetY) { + mY = ViewCompat.getTranslationY(mViewHolder.itemView); + } else { + mY = mStartDy + mFraction * (mTargetY - mStartDy); + } + } + + @Override + public void onAnimationStart(ValueAnimatorCompat animation) { + + } + + @Override + public void onAnimationEnd(ValueAnimatorCompat animation) { + if (!mEnded) { + mViewHolder.setIsRecyclable(true); + } + mEnded = true; + } + + @Override + public void onAnimationCancel(ValueAnimatorCompat animation) { + setFraction(1f); //make sure we recover the view's state. + } + + @Override + public void onAnimationRepeat(ValueAnimatorCompat animation) { + + } + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/helper/ItemTouchUIUtil.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/helper/ItemTouchUIUtil.java new file mode 100644 index 00000000..eeb69da1 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/helper/ItemTouchUIUtil.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.widget.helper; + +import android.graphics.Canvas; +import org.telegram.messenger.support.widget.RecyclerView; +import android.view.View; + +/** + * Utility class for {@link ItemTouchHelper} which handles item transformations for different + * API versions. + *

+ * This class has methods that map to {@link ItemTouchHelper.Callback}'s drawing methods. Default + * implementations in {@link ItemTouchHelper.Callback} call these methods with + * {@link RecyclerView.ViewHolder#itemView} and {@link ItemTouchUIUtil} makes necessary changes + * on the View depending on the API level. You can access the instance of {@link ItemTouchUIUtil} + * via {@link ItemTouchHelper.Callback#getDefaultUIUtil()} and call its methods with the children + * of ViewHolder that you want to apply default effects. + * + * @see ItemTouchHelper.Callback#getDefaultUIUtil() + */ +public interface ItemTouchUIUtil { + + /** + * The default implementation for {@link ItemTouchHelper.Callback#onChildDraw(Canvas, + * RecyclerView, RecyclerView.ViewHolder, float, float, int, boolean)} + */ + void onDraw(Canvas c, RecyclerView recyclerView, View view, + float dX, float dY, int actionState, boolean isCurrentlyActive); + + /** + * The default implementation for {@link ItemTouchHelper.Callback#onChildDrawOver(Canvas, + * RecyclerView, RecyclerView.ViewHolder, float, float, int, boolean)} + */ + void onDrawOver(Canvas c, RecyclerView recyclerView, View view, + float dX, float dY, int actionState, boolean isCurrentlyActive); + + /** + * The default implementation for {@link ItemTouchHelper.Callback#clearView(RecyclerView, + * RecyclerView.ViewHolder)} + */ + void clearView(View view); + + /** + * The default implementation for {@link ItemTouchHelper.Callback#onSelectedChanged( + * RecyclerView.ViewHolder, int)} + */ + void onSelected(View view); +} + diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/helper/ItemTouchUIUtilImpl.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/helper/ItemTouchUIUtilImpl.java new file mode 100644 index 00000000..c0e89159 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/helper/ItemTouchUIUtilImpl.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.widget.helper; + +import android.graphics.Canvas; +import android.support.v4.view.ViewCompat; +import org.telegram.messenger.support.widget.RecyclerView; +import android.view.View; + + +/** + * Package private class to keep implementations. Putting them inside ItemTouchUIUtil makes them + * public API, which is not desired in this case. + */ +class ItemTouchUIUtilImpl { + static class Lollipop extends Honeycomb { + @Override + public void onDraw(Canvas c, RecyclerView recyclerView, View view, + float dX, float dY, int actionState, boolean isCurrentlyActive) { + if (isCurrentlyActive) { + Object originalElevation = view.getTag(); + if (originalElevation == null) { + originalElevation = ViewCompat.getElevation(view); + float newElevation = 1f + findMaxElevation(recyclerView, view); + ViewCompat.setElevation(view, newElevation); + view.setTag(originalElevation); + } + } + super.onDraw(c, recyclerView, view, dX, dY, actionState, isCurrentlyActive); + } + + private float findMaxElevation(RecyclerView recyclerView, View itemView) { + final int childCount = recyclerView.getChildCount(); + float max = 0; + for (int i = 0; i < childCount; i++) { + final View child = recyclerView.getChildAt(i); + if (child == itemView) { + continue; + } + final float elevation = ViewCompat.getElevation(child); + if (elevation > max) { + max = elevation; + } + } + return max; + } + + @Override + public void clearView(View view) { + final Object tag = view.getTag(); + if (tag != null && tag instanceof Float) { + ViewCompat.setElevation(view, (Float) tag); + } + view.setTag(null); + super.clearView(view); + } + } + + static class Honeycomb implements ItemTouchUIUtil { + + @Override + public void clearView(View view) { + ViewCompat.setTranslationX(view, 0f); + ViewCompat.setTranslationY(view, 0f); + } + + @Override + public void onSelected(View view) { + + } + + @Override + public void onDraw(Canvas c, RecyclerView recyclerView, View view, + float dX, float dY, int actionState, boolean isCurrentlyActive) { + ViewCompat.setTranslationX(view, dX); + ViewCompat.setTranslationY(view, dY); + } + + @Override + public void onDrawOver(Canvas c, RecyclerView recyclerView, + View view, float dX, float dY, int actionState, boolean isCurrentlyActive) { + + } + } + + static class Gingerbread implements ItemTouchUIUtil { + + private void draw(Canvas c, RecyclerView parent, View view, + float dX, float dY) { + c.save(); + c.translate(dX, dY); + parent.drawChild(c, view, 0); + c.restore(); + } + + @Override + public void clearView(View view) { + view.setVisibility(View.VISIBLE); + } + + @Override + public void onSelected(View view) { + view.setVisibility(View.INVISIBLE); + } + + @Override + public void onDraw(Canvas c, RecyclerView recyclerView, View view, + float dX, float dY, int actionState, boolean isCurrentlyActive) { + if (actionState != ItemTouchHelper.ACTION_STATE_DRAG) { + draw(c, recyclerView, view, dX, dY); + } + } + + @Override + public void onDrawOver(Canvas c, RecyclerView recyclerView, + View view, float dX, float dY, + int actionState, boolean isCurrentlyActive) { + if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) { + draw(c, recyclerView, view, dX, dY); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/util/SortedListAdapterCallback.java b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/util/SortedListAdapterCallback.java new file mode 100644 index 00000000..86567d5e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/support/widget/util/SortedListAdapterCallback.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.support.widget.util; + +import org.telegram.messenger.support.util.SortedList; +import org.telegram.messenger.support.widget.RecyclerView; + +/** + * A {@link SortedList.Callback} implementation that can bind a {@link SortedList} to a + * {@link RecyclerView.Adapter}. + */ +public abstract class SortedListAdapterCallback extends SortedList.Callback { + + final RecyclerView.Adapter mAdapter; + + /** + * Creates a {@link SortedList.Callback} that will forward data change events to the provided + * Adapter. + * + * @param adapter The Adapter instance which should receive events from the SortedList. + */ + public SortedListAdapterCallback(RecyclerView.Adapter adapter) { + mAdapter = adapter; + } + + @Override + public void onInserted(int position, int count) { + mAdapter.notifyItemRangeInserted(position, count); + } + + @Override + public void onRemoved(int position, int count) { + mAdapter.notifyItemRangeRemoved(position, count); + } + + @Override + public void onMoved(int fromPosition, int toPosition) { + mAdapter.notifyItemMoved(fromPosition, toPosition); + } + + @Override + public void onChanged(int position, int count) { + mAdapter.notifyItemRangeChanged(position, count); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/time/DateParser.java b/TMessagesProj/src/main/java/org/telegram/messenger/time/DateParser.java new file mode 100644 index 00000000..0302103f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/time/DateParser.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.time; + +import java.text.ParseException; +import java.text.ParsePosition; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +/** + *

DateParser is the "missing" interface for the parsing methods of + * {@link java.text.DateFormat}.

+ * + * @since 3.2 + */ +public interface DateParser { + + /** + * Equivalent to DateFormat.parse(String). + *

+ * See {@link java.text.DateFormat#parse(String)} for more information. + * + * @param source A String whose beginning should be parsed. + * @return A Date parsed from the string + * @throws ParseException if the beginning of the specified string cannot be parsed. + */ + Date parse(String source) throws ParseException; + + /** + * Equivalent to DateFormat.parse(String, ParsePosition). + *

+ * See {@link java.text.DateFormat#parse(String, ParsePosition)} for more information. + * + * @param source A String, part of which should be parsed. + * @param pos A ParsePosition object with index and error index information + * as described above. + * @return A Date parsed from the string. In case of error, returns null. + * @throws NullPointerException if text or pos is null. + */ + Date parse(String source, ParsePosition pos); + + // Accessors + //----------------------------------------------------------------------- + + /** + *

Get the pattern used by this parser.

+ * + * @return the pattern, {@link java.text.SimpleDateFormat} compatible + */ + String getPattern(); + + /** + *

+ * Get the time zone used by this parser. + *

+ *

+ *

+ * The default {@link TimeZone} used to create a {@link Date} when the {@link TimeZone} is not specified by + * the format pattern. + *

+ * + * @return the time zone + */ + TimeZone getTimeZone(); + + /** + *

Get the locale used by this parser.

+ * + * @return the locale + */ + Locale getLocale(); + + /** + * Parses text from a string to produce a Date. + * + * @param source A String whose beginning should be parsed. + * @return a java.util.Date object + * @throws ParseException if the beginning of the specified string cannot be parsed. + * @see java.text.DateFormat#parseObject(String) + */ + Object parseObject(String source) throws ParseException; + + /** + * Parse a date/time string according to the given parse position. + * + * @param source A String whose beginning should be parsed. + * @param pos the parse position + * @return a java.util.Date object + * @see java.text.DateFormat#parseObject(String, ParsePosition) + */ + Object parseObject(String source, ParsePosition pos); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/time/DatePrinter.java b/TMessagesProj/src/main/java/org/telegram/messenger/time/DatePrinter.java new file mode 100644 index 00000000..8712820a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/time/DatePrinter.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.time; + +import java.text.FieldPosition; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +/** + *

DatePrinter is the "missing" interface for the format methods of + * {@link java.text.DateFormat}.

+ * + * @since 3.2 + */ +public interface DatePrinter { + + /** + *

Formats a millisecond {@code long} value.

+ * + * @param millis the millisecond value to format + * @return the formatted string + * @since 2.1 + */ + String format(long millis); + + /** + *

Formats a {@code Date} object using a {@code GregorianCalendar}.

+ * + * @param date the date to format + * @return the formatted string + */ + String format(Date date); + + /** + *

Formats a {@code Calendar} object.

+ * + * @param calendar the calendar to format + * @return the formatted string + */ + String format(Calendar calendar); + + /** + *

Formats a milliseond {@code long} value into the + * supplied {@code StringBuffer}.

+ * + * @param millis the millisecond value to format + * @param buf the buffer to format into + * @return the specified string buffer + */ + StringBuffer format(long millis, StringBuffer buf); + + /** + *

Formats a {@code Date} object into the + * supplied {@code StringBuffer} using a {@code GregorianCalendar}.

+ * + * @param date the date to format + * @param buf the buffer to format into + * @return the specified string buffer + */ + StringBuffer format(Date date, StringBuffer buf); + + /** + *

Formats a {@code Calendar} object into the + * supplied {@code StringBuffer}.

+ * + * @param calendar the calendar to format + * @param buf the buffer to format into + * @return the specified string buffer + */ + StringBuffer format(Calendar calendar, StringBuffer buf); + + // Accessors + //----------------------------------------------------------------------- + + /** + *

Gets the pattern used by this printer.

+ * + * @return the pattern, {@link java.text.SimpleDateFormat} compatible + */ + String getPattern(); + + /** + *

Gets the time zone used by this printer.

+ *

+ *

This zone is always used for {@code Date} printing.

+ * + * @return the time zone + */ + TimeZone getTimeZone(); + + /** + *

Gets the locale used by this printer.

+ * + * @return the locale + */ + Locale getLocale(); + + /** + *

Formats a {@code Date}, {@code Calendar} or + * {@code Long} (milliseconds) object.

+ *

+ * See {@link java.text.DateFormat#format(Object, StringBuffer, FieldPosition)} + * + * @param obj the object to format + * @param toAppendTo the buffer to append to + * @param pos the position - ignored + * @return the buffer passed in + */ + StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/time/FastDateFormat.java b/TMessagesProj/src/main/java/org/telegram/messenger/time/FastDateFormat.java new file mode 100644 index 00000000..497edca0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/time/FastDateFormat.java @@ -0,0 +1,613 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.time; + +import java.text.DateFormat; +import java.text.FieldPosition; +import java.text.Format; +import java.text.ParseException; +import java.text.ParsePosition; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +/** + *

FastDateFormat is a fast and thread-safe version of + * {@link java.text.SimpleDateFormat}.

+ * + *

This class can be used as a direct replacement to + * {@code SimpleDateFormat} in most formatting and parsing situations. + * This class is especially useful in multi-threaded server environments. + * {@code SimpleDateFormat} is not thread-safe in any JDK version, + * nor will it be as Sun have closed the bug/RFE. + *

+ * + *

All patterns are compatible with + * SimpleDateFormat (except time zones and some year patterns - see below).

+ * + *

Since 3.2, FastDateFormat supports parsing as well as printing.

+ * + *

Java 1.4 introduced a new pattern letter, {@code 'Z'}, to represent + * time zones in RFC822 format (eg. {@code +0800} or {@code -1100}). + * This pattern letter can be used here (on all JDK versions).

+ * + *

In addition, the pattern {@code 'ZZ'} has been made to represent + * ISO8601 full format time zones (eg. {@code +08:00} or {@code -11:00}). + * This introduces a minor incompatibility with Java 1.4, but at a gain of + * useful functionality.

+ * + *

Javadoc cites for the year pattern: For formatting, if the number of + * pattern letters is 2, the year is truncated to 2 digits; otherwise it is + * interpreted as a number. Starting with Java 1.7 a pattern of 'Y' or + * 'YYY' will be formatted as '2003', while it was '03' in former Java + * versions. FastDateFormat implements the behavior of Java 7.

+ * + * @since 2.0 + * @version $Id: FastDateFormat.java 1572877 2014-02-28 08:42:25Z britter $ + */ +public class FastDateFormat extends Format implements DateParser, DatePrinter { + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 2L; + + /** + * FULL locale dependent date or time style. + */ + public static final int FULL = DateFormat.FULL; + /** + * LONG locale dependent date or time style. + */ + public static final int LONG = DateFormat.LONG; + /** + * MEDIUM locale dependent date or time style. + */ + public static final int MEDIUM = DateFormat.MEDIUM; + /** + * SHORT locale dependent date or time style. + */ + public static final int SHORT = DateFormat.SHORT; + + private static final FormatCache cache = new FormatCache() { + @Override + protected FastDateFormat createInstance(final String pattern, final TimeZone timeZone, final Locale locale) { + return new FastDateFormat(pattern, timeZone, locale); + } + }; + + private final FastDatePrinter printer; + private final FastDateParser parser; + + //----------------------------------------------------------------------- + + /** + *

Gets a formatter instance using the default pattern in the + * default locale.

+ * + * @return a date/time formatter + */ + public static FastDateFormat getInstance() { + return cache.getInstance(); + } + + /** + *

Gets a formatter instance using the specified pattern in the + * default locale.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible + * pattern + * @return a pattern based date/time formatter + * @throws IllegalArgumentException if pattern is invalid + */ + public static FastDateFormat getInstance(final String pattern) { + return cache.getInstance(pattern, null, null); + } + + /** + *

Gets a formatter instance using the specified pattern and + * time zone.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible + * pattern + * @param timeZone optional time zone, overrides time zone of + * formatted date + * @return a pattern based date/time formatter + * @throws IllegalArgumentException if pattern is invalid + */ + public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone) { + return cache.getInstance(pattern, timeZone, null); + } + + /** + *

Gets a formatter instance using the specified pattern and + * locale.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible + * pattern + * @param locale optional locale, overrides system locale + * @return a pattern based date/time formatter + * @throws IllegalArgumentException if pattern is invalid + */ + public static FastDateFormat getInstance(final String pattern, final Locale locale) { + return cache.getInstance(pattern, null, locale); + } + + /** + *

Gets a formatter instance using the specified pattern, time zone + * and locale.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible + * pattern + * @param timeZone optional time zone, overrides time zone of + * formatted date + * @param locale optional locale, overrides system locale + * @return a pattern based date/time formatter + * @throws IllegalArgumentException if pattern is invalid + * or {@code null} + */ + public static FastDateFormat getInstance(final String pattern, final TimeZone timeZone, final Locale locale) { + return cache.getInstance(pattern, timeZone, locale); + } + + //----------------------------------------------------------------------- + + /** + *

Gets a date formatter instance using the specified style in the + * default time zone and locale.

+ * + * @param style date style: FULL, LONG, MEDIUM, or SHORT + * @return a localized standard date formatter + * @throws IllegalArgumentException if the Locale has no date + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getDateInstance(final int style) { + return cache.getDateInstance(style, null, null); + } + + /** + *

Gets a date formatter instance using the specified style and + * locale in the default time zone.

+ * + * @param style date style: FULL, LONG, MEDIUM, or SHORT + * @param locale optional locale, overrides system locale + * @return a localized standard date formatter + * @throws IllegalArgumentException if the Locale has no date + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getDateInstance(final int style, final Locale locale) { + return cache.getDateInstance(style, null, locale); + } + + /** + *

Gets a date formatter instance using the specified style and + * time zone in the default locale.

+ * + * @param style date style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted date + * @return a localized standard date formatter + * @throws IllegalArgumentException if the Locale has no date + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone) { + return cache.getDateInstance(style, timeZone, null); + } + + /** + *

Gets a date formatter instance using the specified style, time + * zone and locale.

+ * + * @param style date style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted date + * @param locale optional locale, overrides system locale + * @return a localized standard date formatter + * @throws IllegalArgumentException if the Locale has no date + * pattern defined + */ + public static FastDateFormat getDateInstance(final int style, final TimeZone timeZone, final Locale locale) { + return cache.getDateInstance(style, timeZone, locale); + } + + //----------------------------------------------------------------------- + + /** + *

Gets a time formatter instance using the specified style in the + * default time zone and locale.

+ * + * @param style time style: FULL, LONG, MEDIUM, or SHORT + * @return a localized standard time formatter + * @throws IllegalArgumentException if the Locale has no time + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getTimeInstance(final int style) { + return cache.getTimeInstance(style, null, null); + } + + /** + *

Gets a time formatter instance using the specified style and + * locale in the default time zone.

+ * + * @param style time style: FULL, LONG, MEDIUM, or SHORT + * @param locale optional locale, overrides system locale + * @return a localized standard time formatter + * @throws IllegalArgumentException if the Locale has no time + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getTimeInstance(final int style, final Locale locale) { + return cache.getTimeInstance(style, null, locale); + } + + /** + *

Gets a time formatter instance using the specified style and + * time zone in the default locale.

+ * + * @param style time style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted time + * @return a localized standard time formatter + * @throws IllegalArgumentException if the Locale has no time + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone) { + return cache.getTimeInstance(style, timeZone, null); + } + + /** + *

Gets a time formatter instance using the specified style, time + * zone and locale.

+ * + * @param style time style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted time + * @param locale optional locale, overrides system locale + * @return a localized standard time formatter + * @throws IllegalArgumentException if the Locale has no time + * pattern defined + */ + public static FastDateFormat getTimeInstance(final int style, final TimeZone timeZone, final Locale locale) { + return cache.getTimeInstance(style, timeZone, locale); + } + + //----------------------------------------------------------------------- + + /** + *

Gets a date/time formatter instance using the specified style + * in the default time zone and locale.

+ * + * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT + * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT + * @return a localized standard date/time formatter + * @throws IllegalArgumentException if the Locale has no date/time + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle) { + return cache.getDateTimeInstance(dateStyle, timeStyle, null, null); + } + + /** + *

Gets a date/time formatter instance using the specified style and + * locale in the default time zone.

+ * + * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT + * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT + * @param locale optional locale, overrides system locale + * @return a localized standard date/time formatter + * @throws IllegalArgumentException if the Locale has no date/time + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final Locale locale) { + return cache.getDateTimeInstance(dateStyle, timeStyle, null, locale); + } + + /** + *

Gets a date/time formatter instance using the specified style and + * time zone in the default locale.

+ * + * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT + * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted date + * @return a localized standard date/time formatter + * @throws IllegalArgumentException if the Locale has no date/time + * pattern defined + * @since 2.1 + */ + public static FastDateFormat getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone) { + return getDateTimeInstance(dateStyle, timeStyle, timeZone, null); + } + + /** + *

Gets a date/time formatter instance using the specified style, + * time zone and locale.

+ * + * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT + * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted date + * @param locale optional locale, overrides system locale + * @return a localized standard date/time formatter + * @throws IllegalArgumentException if the Locale has no date/time + * pattern defined + */ + public static FastDateFormat getDateTimeInstance( + final int dateStyle, final int timeStyle, final TimeZone timeZone, final Locale locale) { + return cache.getDateTimeInstance(dateStyle, timeStyle, timeZone, locale); + } + + // Constructor + //----------------------------------------------------------------------- + + /** + *

Constructs a new FastDateFormat.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible pattern + * @param timeZone non-null time zone to use + * @param locale non-null locale to use + * @throws NullPointerException if pattern, timeZone, or locale is null. + */ + protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale) { + this(pattern, timeZone, locale, null); + } + + // Constructor + //----------------------------------------------------------------------- + + /** + *

Constructs a new FastDateFormat.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible pattern + * @param timeZone non-null time zone to use + * @param locale non-null locale to use + * @param centuryStart The start of the 100 year period to use as the "default century" for 2 digit year parsing. If centuryStart is null, defaults to now - 80 years + * @throws NullPointerException if pattern, timeZone, or locale is null. + */ + protected FastDateFormat(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) { + printer = new FastDatePrinter(pattern, timeZone, locale); + parser = new FastDateParser(pattern, timeZone, locale, centuryStart); + } + + // Format methods + //----------------------------------------------------------------------- + + /** + *

Formats a {@code Date}, {@code Calendar} or + * {@code Long} (milliseconds) object.

+ * + * @param obj the object to format + * @param toAppendTo the buffer to append to + * @param pos the position - ignored + * @return the buffer passed in + */ + @Override + public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) { + return printer.format(obj, toAppendTo, pos); + } + + /** + *

Formats a millisecond {@code long} value.

+ * + * @param millis the millisecond value to format + * @return the formatted string + * @since 2.1 + */ + @Override + public String format(final long millis) { + return printer.format(millis); + } + + /** + *

Formats a {@code Date} object using a {@code GregorianCalendar}.

+ * + * @param date the date to format + * @return the formatted string + */ + @Override + public String format(final Date date) { + return printer.format(date); + } + + /** + *

Formats a {@code Calendar} object.

+ * + * @param calendar the calendar to format + * @return the formatted string + */ + @Override + public String format(final Calendar calendar) { + return printer.format(calendar); + } + + /** + *

Formats a millisecond {@code long} value into the + * supplied {@code StringBuffer}.

+ * + * @param millis the millisecond value to format + * @param buf the buffer to format into + * @return the specified string buffer + * @since 2.1 + */ + @Override + public StringBuffer format(final long millis, final StringBuffer buf) { + return printer.format(millis, buf); + } + + /** + *

Formats a {@code Date} object into the + * supplied {@code StringBuffer} using a {@code GregorianCalendar}.

+ * + * @param date the date to format + * @param buf the buffer to format into + * @return the specified string buffer + */ + @Override + public StringBuffer format(final Date date, final StringBuffer buf) { + return printer.format(date, buf); + } + + /** + *

Formats a {@code Calendar} object into the + * supplied {@code StringBuffer}.

+ * + * @param calendar the calendar to format + * @param buf the buffer to format into + * @return the specified string buffer + */ + @Override + public StringBuffer format(final Calendar calendar, final StringBuffer buf) { + return printer.format(calendar, buf); + } + + // Parsing + //----------------------------------------------------------------------- + + + /* (non-Javadoc) + * @see DateParser#parse(java.lang.String) + */ + @Override + public Date parse(final String source) throws ParseException { + return parser.parse(source); + } + + /* (non-Javadoc) + * @see DateParser#parse(java.lang.String, java.text.ParsePosition) + */ + @Override + public Date parse(final String source, final ParsePosition pos) { + return parser.parse(source, pos); + } + + /* (non-Javadoc) + * @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition) + */ + @Override + public Object parseObject(final String source, final ParsePosition pos) { + return parser.parseObject(source, pos); + } + + // Accessors + //----------------------------------------------------------------------- + + /** + *

Gets the pattern used by this formatter.

+ * + * @return the pattern, {@link java.text.SimpleDateFormat} compatible + */ + @Override + public String getPattern() { + return printer.getPattern(); + } + + /** + *

Gets the time zone used by this formatter.

+ *

+ *

This zone is always used for {@code Date} formatting.

+ * + * @return the time zone + */ + @Override + public TimeZone getTimeZone() { + return printer.getTimeZone(); + } + + /** + *

Gets the locale used by this formatter.

+ * + * @return the locale + */ + @Override + public Locale getLocale() { + return printer.getLocale(); + } + + /** + *

Gets an estimate for the maximum string length that the + * formatter will produce.

+ *

+ *

The actual formatted length will almost always be less than or + * equal to this amount.

+ * + * @return the maximum formatted length + */ + public int getMaxLengthEstimate() { + return printer.getMaxLengthEstimate(); + } + + // Basics + //----------------------------------------------------------------------- + + /** + *

Compares two objects for equality.

+ * + * @param obj the object to compare to + * @return {@code true} if equal + */ + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof FastDateFormat)) { + return false; + } + final FastDateFormat other = (FastDateFormat) obj; + // no need to check parser, as it has same invariants as printer + return printer.equals(other.printer); + } + + /** + *

Returns a hashcode compatible with equals.

+ * + * @return a hashcode compatible with equals + */ + @Override + public int hashCode() { + return printer.hashCode(); + } + + /** + *

Gets a debugging string version of this formatter.

+ * + * @return a debugging string + */ + @Override + public String toString() { + return "FastDateFormat[" + printer.getPattern() + "," + printer.getLocale() + "," + printer.getTimeZone().getID() + "]"; + } + + + /** + *

Performs the formatting by applying the rules to the + * specified calendar.

+ * + * @param calendar the calendar to format + * @param buf the buffer to format into + * @return the specified string buffer + */ + protected StringBuffer applyRules(final Calendar calendar, final StringBuffer buf) { + return printer.applyRules(calendar, buf); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/time/FastDateParser.java b/TMessagesProj/src/main/java/org/telegram/messenger/time/FastDateParser.java new file mode 100644 index 00000000..1af5b0df --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/time/FastDateParser.java @@ -0,0 +1,873 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.time; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.text.DateFormatSymbols; +import java.text.ParseException; +import java.text.ParsePosition; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.SortedMap; +import java.util.TimeZone; +import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + *

FastDateParser is a fast and thread-safe version of + * {@link java.text.SimpleDateFormat}.

+ * + *

This class can be used as a direct replacement for + * SimpleDateFormat in most parsing situations. + * This class is especially useful in multi-threaded server environments. + * SimpleDateFormat is not thread-safe in any JDK version, + * nor will it be as Sun has closed the + * bug/RFE. + *

+ * + *

Only parsing is supported, but all patterns are compatible with + * SimpleDateFormat.

+ * + *

Timing tests indicate this class is as about as fast as SimpleDateFormat + * in single thread applications and about 25% faster in multi-thread applications.

+ * + * @version $Id: FastDateParser.java 1572877 2014-02-28 08:42:25Z britter $ + * @since 3.2 + */ +public class FastDateParser implements DateParser, Serializable { + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 2L; + + static final Locale JAPANESE_IMPERIAL = new Locale("ja", "JP", "JP"); + + // defining fields + private final String pattern; + private final TimeZone timeZone; + private final Locale locale; + private final int century; + private final int startYear; + + // derived fields + private transient Pattern parsePattern; + private transient Strategy[] strategies; + + // dynamic fields to communicate with Strategy + private transient String currentFormatField; + private transient Strategy nextStrategy; + + /** + *

Constructs a new FastDateParser.

+ * + * @param pattern non-null {@link java.text.SimpleDateFormat} compatible + * pattern + * @param timeZone non-null time zone to use + * @param locale non-null locale + */ + protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale) { + this(pattern, timeZone, locale, null); + } + + /** + *

Constructs a new FastDateParser.

+ * + * @param pattern non-null {@link java.text.SimpleDateFormat} compatible + * pattern + * @param timeZone non-null time zone to use + * @param locale non-null locale + * @param centuryStart The start of the century for 2 digit year parsing + * @since 3.3 + */ + protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) { + this.pattern = pattern; + this.timeZone = timeZone; + this.locale = locale; + + final Calendar definingCalendar = Calendar.getInstance(timeZone, locale); + int centuryStartYear; + if (centuryStart != null) { + definingCalendar.setTime(centuryStart); + centuryStartYear = definingCalendar.get(Calendar.YEAR); + } else if (locale.equals(JAPANESE_IMPERIAL)) { + centuryStartYear = 0; + } else { + // from 80 years ago to 20 years from now + definingCalendar.setTime(new Date()); + centuryStartYear = definingCalendar.get(Calendar.YEAR) - 80; + } + century = centuryStartYear / 100 * 100; + startYear = centuryStartYear - century; + + init(definingCalendar); + } + + /** + * Initialize derived fields from defining fields. + * This is called from constructor and from readObject (de-serialization) + * + * @param definingCalendar the {@link java.util.Calendar} instance used to initialize this FastDateParser + */ + private void init(Calendar definingCalendar) { + + final StringBuilder regex = new StringBuilder(); + final List collector = new ArrayList(); + + final Matcher patternMatcher = formatPattern.matcher(pattern); + if (!patternMatcher.lookingAt()) { + throw new IllegalArgumentException( + "Illegal pattern character '" + pattern.charAt(patternMatcher.regionStart()) + "'"); + } + + currentFormatField = patternMatcher.group(); + Strategy currentStrategy = getStrategy(currentFormatField, definingCalendar); + for (; ; ) { + patternMatcher.region(patternMatcher.end(), patternMatcher.regionEnd()); + if (!patternMatcher.lookingAt()) { + nextStrategy = null; + break; + } + final String nextFormatField = patternMatcher.group(); + nextStrategy = getStrategy(nextFormatField, definingCalendar); + if (currentStrategy.addRegex(this, regex)) { + collector.add(currentStrategy); + } + currentFormatField = nextFormatField; + currentStrategy = nextStrategy; + } + if (patternMatcher.regionStart() != patternMatcher.regionEnd()) { + throw new IllegalArgumentException("Failed to parse \"" + pattern + "\" ; gave up at index " + patternMatcher.regionStart()); + } + if (currentStrategy.addRegex(this, regex)) { + collector.add(currentStrategy); + } + currentFormatField = null; + strategies = collector.toArray(new Strategy[collector.size()]); + parsePattern = Pattern.compile(regex.toString()); + } + + // Accessors + //----------------------------------------------------------------------- + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DateParser#getPattern() + */ + @Override + public String getPattern() { + return pattern; + } + + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DateParser#getTimeZone() + */ + @Override + public TimeZone getTimeZone() { + return timeZone; + } + + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DateParser#getLocale() + */ + @Override + public Locale getLocale() { + return locale; + } + + /** + * Returns the generated pattern (for testing purposes). + * + * @return the generated pattern + */ + Pattern getParsePattern() { + return parsePattern; + } + + // Basics + //----------------------------------------------------------------------- + + /** + *

Compare another object for equality with this object.

+ * + * @param obj the object to compare to + * @return trueif equal to this instance + */ + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof FastDateParser)) { + return false; + } + final FastDateParser other = (FastDateParser) obj; + return pattern.equals(other.pattern) + && timeZone.equals(other.timeZone) + && locale.equals(other.locale); + } + + /** + *

Return a hashcode compatible with equals.

+ * + * @return a hashcode compatible with equals + */ + @Override + public int hashCode() { + return pattern.hashCode() + 13 * (timeZone.hashCode() + 13 * locale.hashCode()); + } + + /** + *

Get a string version of this formatter.

+ * + * @return a debugging string + */ + @Override + public String toString() { + return "FastDateParser[" + pattern + "," + locale + "," + timeZone.getID() + "]"; + } + + // Serializing + //----------------------------------------------------------------------- + + /** + * Create the object after serialization. This implementation reinitializes the + * transient properties. + * + * @param in ObjectInputStream from which the object is being deserialized. + * @throws IOException if there is an IO issue. + * @throws ClassNotFoundException if a class cannot be found. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + + final Calendar definingCalendar = Calendar.getInstance(timeZone, locale); + init(definingCalendar); + } + + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DateParser#parseObject(java.lang.String) + */ + @Override + public Object parseObject(final String source) throws ParseException { + return parse(source); + } + + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DateParser#parse(java.lang.String) + */ + @Override + public Date parse(final String source) throws ParseException { + final Date date = parse(source, new ParsePosition(0)); + if (date == null) { + // Add a note re supported date range + if (locale.equals(JAPANESE_IMPERIAL)) { + throw new ParseException( + "(The " + locale + " locale does not support dates before 1868 AD)\n" + + "Unparseable date: \"" + source + "\" does not match " + parsePattern.pattern(), 0); + } + throw new ParseException("Unparseable date: \"" + source + "\" does not match " + parsePattern.pattern(), 0); + } + return date; + } + + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DateParser#parseObject(java.lang.String, java.text.ParsePosition) + */ + @Override + public Object parseObject(final String source, final ParsePosition pos) { + return parse(source, pos); + } + + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DateParser#parse(java.lang.String, java.text.ParsePosition) + */ + @Override + public Date parse(final String source, final ParsePosition pos) { + final int offset = pos.getIndex(); + final Matcher matcher = parsePattern.matcher(source.substring(offset)); + if (!matcher.lookingAt()) { + return null; + } + // timing tests indicate getting new instance is 19% faster than cloning + final Calendar cal = Calendar.getInstance(timeZone, locale); + cal.clear(); + + for (int i = 0; i < strategies.length; ) { + final Strategy strategy = strategies[i++]; + strategy.setCalendar(this, cal, matcher.group(i)); + } + pos.setIndex(offset + matcher.end()); + return cal.getTime(); + } + + // Support for strategies + //----------------------------------------------------------------------- + + /** + * Escape constant fields into regular expression + * + * @param regex The destination regex + * @param value The source field + * @param unquote If true, replace two success quotes ('') with single quote (') + * @return The StringBuilder + */ + private static StringBuilder escapeRegex(final StringBuilder regex, final String value, final boolean unquote) { + regex.append("\\Q"); + for (int i = 0; i < value.length(); ++i) { + char c = value.charAt(i); + switch (c) { + case '\'': + if (unquote) { + if (++i == value.length()) { + return regex; + } + c = value.charAt(i); + } + break; + case '\\': + if (++i == value.length()) { + break; + } + /* + * If we have found \E, we replace it with \E\\E\Q, i.e. we stop the quoting, + * quote the \ in \E, then restart the quoting. + * + * Otherwise we just output the two characters. + * In each case the initial \ needs to be output and the final char is done at the end + */ + regex.append(c); // we always want the original \ + c = value.charAt(i); // Is it followed by E ? + if (c == 'E') { // \E detected + regex.append("E\\\\E\\"); // see comment above + c = 'Q'; // appended below + } + break; + default: + break; + } + regex.append(c); + } + regex.append("\\E"); + return regex; + } + + private static String[] getDisplayNameArray(int field, boolean isLong, Locale locale) { + DateFormatSymbols dfs = new DateFormatSymbols(locale); + switch (field) { + case Calendar.AM_PM: + return dfs.getAmPmStrings(); + case Calendar.DAY_OF_WEEK: + return isLong ? dfs.getWeekdays() : dfs.getShortWeekdays(); + case Calendar.ERA: + return dfs.getEras(); + case Calendar.MONTH: + return isLong ? dfs.getMonths() : dfs.getShortMonths(); + } + return null; + } + + private static void insertValuesInMap(Map map, String[] values) { + if (values == null) { + return; + } + for (int i = 0; i < values.length; ++i) { + if (values[i] != null && values[i].length() > 0) { + map.put(values[i], i); + } + } + } + + private static Map getDisplayNames(int field, Locale locale) { + Map result = new HashMap(); + insertValuesInMap(result, getDisplayNameArray(field, false, locale)); + insertValuesInMap(result, getDisplayNameArray(field, true, locale)); + return result.isEmpty() ? null : result; + } + + /** + * Get the short and long values displayed for a field + * + * @param field The field of interest + * @param definingCalendar The calendar to obtain the short and long values + * @param locale The locale of display names + * @return A Map of the field key / value pairs + */ + private static Map getDisplayNames(final int field, final Calendar definingCalendar, final Locale locale) { + return getDisplayNames(field, locale); + } + + /** + * Adjust dates to be within appropriate century + * + * @param twoDigitYear The year to adjust + * @return A value between centuryStart(inclusive) to centuryStart+100(exclusive) + */ + private int adjustYear(final int twoDigitYear) { + int trial = century + twoDigitYear; + return twoDigitYear >= startYear ? trial : trial + 100; + } + + /** + * Is the next field a number? + * + * @return true, if next field will be a number + */ + boolean isNextNumber() { + return nextStrategy != null && nextStrategy.isNumber(); + } + + /** + * What is the width of the current field? + * + * @return The number of characters in the current format field + */ + int getFieldWidth() { + return currentFormatField.length(); + } + + /** + * A strategy to parse a single field from the parsing pattern + */ + private static abstract class Strategy { + /** + * Is this field a number? + * The default implementation returns false. + * + * @return true, if field is a number + */ + boolean isNumber() { + return false; + } + + /** + * Set the Calendar with the parsed field. + *

+ * The default implementation does nothing. + * + * @param parser The parser calling this strategy + * @param cal The Calendar to set + * @param value The parsed field to translate and set in cal + */ + void setCalendar(final FastDateParser parser, final Calendar cal, final String value) { + + } + + /** + * Generate a Pattern regular expression to the StringBuilder + * which will accept this field + * + * @param parser The parser calling this strategy + * @param regex The StringBuilder to append to + * @return true, if this field will set the calendar; + * false, if this field is a constant value + */ + abstract boolean addRegex(FastDateParser parser, StringBuilder regex); + } + + /** + * A Pattern to parse the user supplied SimpleDateFormat pattern + */ + private static final Pattern formatPattern = Pattern.compile( + "D+|E+|F+|G+|H+|K+|M+|S+|W+|Z+|a+|d+|h+|k+|m+|s+|w+|y+|z+|''|'[^']++(''[^']*+)*+'|[^'A-Za-z]++"); + + /** + * Obtain a Strategy given a field from a SimpleDateFormat pattern + * + * @param formatField A sub-sequence of the SimpleDateFormat pattern + * @param definingCalendar The calendar to obtain the short and long values + * @return The Strategy that will handle parsing for the field + */ + private Strategy getStrategy(final String formatField, final Calendar definingCalendar) { + switch (formatField.charAt(0)) { + case '\'': + if (formatField.length() > 2) { + return new CopyQuotedStrategy(formatField.substring(1, formatField.length() - 1)); + } + //$FALL-THROUGH$ + default: + return new CopyQuotedStrategy(formatField); + case 'D': + return DAY_OF_YEAR_STRATEGY; + case 'E': + return getLocaleSpecificStrategy(Calendar.DAY_OF_WEEK, definingCalendar); + case 'F': + return DAY_OF_WEEK_IN_MONTH_STRATEGY; + case 'G': + return getLocaleSpecificStrategy(Calendar.ERA, definingCalendar); + case 'H': + return MODULO_HOUR_OF_DAY_STRATEGY; + case 'K': + return HOUR_STRATEGY; + case 'M': + return formatField.length() >= 3 ? getLocaleSpecificStrategy(Calendar.MONTH, definingCalendar) : NUMBER_MONTH_STRATEGY; + case 'S': + return MILLISECOND_STRATEGY; + case 'W': + return WEEK_OF_MONTH_STRATEGY; + case 'a': + return getLocaleSpecificStrategy(Calendar.AM_PM, definingCalendar); + case 'd': + return DAY_OF_MONTH_STRATEGY; + case 'h': + return MODULO_HOUR_STRATEGY; + case 'k': + return HOUR_OF_DAY_STRATEGY; + case 'm': + return MINUTE_STRATEGY; + case 's': + return SECOND_STRATEGY; + case 'w': + return WEEK_OF_YEAR_STRATEGY; + case 'y': + return formatField.length() > 2 ? LITERAL_YEAR_STRATEGY : ABBREVIATED_YEAR_STRATEGY; + case 'Z': + case 'z': + return getLocaleSpecificStrategy(Calendar.ZONE_OFFSET, definingCalendar); + } + } + + @SuppressWarnings("unchecked") // OK because we are creating an array with no entries + private static final ConcurrentMap[] caches = new ConcurrentMap[Calendar.FIELD_COUNT]; + + /** + * Get a cache of Strategies for a particular field + * + * @param field The Calendar field + * @return a cache of Locale to Strategy + */ + private static ConcurrentMap getCache(final int field) { + synchronized (caches) { + if (caches[field] == null) { + caches[field] = new ConcurrentHashMap(3); + } + return caches[field]; + } + } + + /** + * Construct a Strategy that parses a Text field + * + * @param field The Calendar field + * @param definingCalendar The calendar to obtain the short and long values + * @return a TextStrategy for the field and Locale + */ + private Strategy getLocaleSpecificStrategy(final int field, final Calendar definingCalendar) { + final ConcurrentMap cache = getCache(field); + Strategy strategy = cache.get(locale); + if (strategy == null) { + strategy = field == Calendar.ZONE_OFFSET + ? new TimeZoneStrategy(locale) + : new TextStrategy(field, definingCalendar, locale); + final Strategy inCache = cache.putIfAbsent(locale, strategy); + if (inCache != null) { + return inCache; + } + } + return strategy; + } + + /** + * A strategy that copies the static or quoted field in the parsing pattern + */ + private static class CopyQuotedStrategy extends Strategy { + private final String formatField; + + /** + * Construct a Strategy that ensures the formatField has literal text + * + * @param formatField The literal text to match + */ + CopyQuotedStrategy(final String formatField) { + this.formatField = formatField; + } + + /** + * {@inheritDoc} + */ + @Override + boolean isNumber() { + char c = formatField.charAt(0); + if (c == '\'') { + c = formatField.charAt(1); + } + return Character.isDigit(c); + } + + /** + * {@inheritDoc} + */ + @Override + boolean addRegex(final FastDateParser parser, final StringBuilder regex) { + escapeRegex(regex, formatField, true); + return false; + } + } + + /** + * A strategy that handles a text field in the parsing pattern + */ + private static class TextStrategy extends Strategy { + private final int field; + private final Map keyValues; + + /** + * Construct a Strategy that parses a Text field + * + * @param field The Calendar field + * @param definingCalendar The Calendar to use + * @param locale The Locale to use + */ + TextStrategy(final int field, final Calendar definingCalendar, final Locale locale) { + this.field = field; + this.keyValues = getDisplayNames(field, definingCalendar, locale); + } + + /** + * {@inheritDoc} + */ + @Override + boolean addRegex(final FastDateParser parser, final StringBuilder regex) { + regex.append('('); + for (final String textKeyValue : keyValues.keySet()) { + escapeRegex(regex, textKeyValue, false).append('|'); + } + regex.setCharAt(regex.length() - 1, ')'); + return true; + } + + /** + * {@inheritDoc} + */ + @Override + void setCalendar(final FastDateParser parser, final Calendar cal, final String value) { + final Integer iVal = keyValues.get(value); + if (iVal == null) { + final StringBuilder sb = new StringBuilder(value); + sb.append(" not in ("); + for (final String textKeyValue : keyValues.keySet()) { + sb.append(textKeyValue).append(' '); + } + sb.setCharAt(sb.length() - 1, ')'); + throw new IllegalArgumentException(sb.toString()); + } + cal.set(field, iVal.intValue()); + } + } + + + /** + * A strategy that handles a number field in the parsing pattern + */ + private static class NumberStrategy extends Strategy { + private final int field; + + /** + * Construct a Strategy that parses a Number field + * + * @param field The Calendar field + */ + NumberStrategy(final int field) { + this.field = field; + } + + /** + * {@inheritDoc} + */ + @Override + boolean isNumber() { + return true; + } + + /** + * {@inheritDoc} + */ + @Override + boolean addRegex(final FastDateParser parser, final StringBuilder regex) { + // See LANG-954: We use {Nd} rather than {IsNd} because Android does not support the Is prefix + if (parser.isNextNumber()) { + regex.append("(\\p{Nd}{").append(parser.getFieldWidth()).append("}+)"); + } else { + regex.append("(\\p{Nd}++)"); + } + return true; + } + + /** + * {@inheritDoc} + */ + @Override + void setCalendar(final FastDateParser parser, final Calendar cal, final String value) { + cal.set(field, modify(Integer.parseInt(value))); + } + + /** + * Make any modifications to parsed integer + * + * @param iValue The parsed integer + * @return The modified value + */ + int modify(final int iValue) { + return iValue; + } + } + + private static final Strategy ABBREVIATED_YEAR_STRATEGY = new NumberStrategy(Calendar.YEAR) { + /** + * {@inheritDoc} + */ + @Override + void setCalendar(final FastDateParser parser, final Calendar cal, final String value) { + int iValue = Integer.parseInt(value); + if (iValue < 100) { + iValue = parser.adjustYear(iValue); + } + cal.set(Calendar.YEAR, iValue); + } + }; + + /** + * A strategy that handles a timezone field in the parsing pattern + */ + private static class TimeZoneStrategy extends Strategy { + + private final String validTimeZoneChars; + private final SortedMap tzNames = new TreeMap(String.CASE_INSENSITIVE_ORDER); + + /** + * Index of zone id + */ + private static final int ID = 0; + /** + * Index of the long name of zone in standard time + */ + private static final int LONG_STD = 1; + /** + * Index of the short name of zone in standard time + */ + private static final int SHORT_STD = 2; + /** + * Index of the long name of zone in daylight saving time + */ + private static final int LONG_DST = 3; + /** + * Index of the short name of zone in daylight saving time + */ + private static final int SHORT_DST = 4; + + /** + * Construct a Strategy that parses a TimeZone + * + * @param locale The Locale + */ + TimeZoneStrategy(final Locale locale) { + final String[][] zones = DateFormatSymbols.getInstance(locale).getZoneStrings(); + for (String[] zone : zones) { + if (zone[ID].startsWith("GMT")) { + continue; + } + final TimeZone tz = TimeZone.getTimeZone(zone[ID]); + if (!tzNames.containsKey(zone[LONG_STD])) { + tzNames.put(zone[LONG_STD], tz); + } + if (!tzNames.containsKey(zone[SHORT_STD])) { + tzNames.put(zone[SHORT_STD], tz); + } + if (tz.useDaylightTime()) { + if (!tzNames.containsKey(zone[LONG_DST])) { + tzNames.put(zone[LONG_DST], tz); + } + if (!tzNames.containsKey(zone[SHORT_DST])) { + tzNames.put(zone[SHORT_DST], tz); + } + } + } + + final StringBuilder sb = new StringBuilder(); + sb.append("(GMT[+\\-]\\d{0,1}\\d{2}|[+\\-]\\d{2}:?\\d{2}|"); + for (final String id : tzNames.keySet()) { + escapeRegex(sb, id, false).append('|'); + } + sb.setCharAt(sb.length() - 1, ')'); + validTimeZoneChars = sb.toString(); + } + + /** + * {@inheritDoc} + */ + @Override + boolean addRegex(final FastDateParser parser, final StringBuilder regex) { + regex.append(validTimeZoneChars); + return true; + } + + /** + * {@inheritDoc} + */ + @Override + void setCalendar(final FastDateParser parser, final Calendar cal, final String value) { + TimeZone tz; + if (value.charAt(0) == '+' || value.charAt(0) == '-') { + tz = TimeZone.getTimeZone("GMT" + value); + } else if (value.startsWith("GMT")) { + tz = TimeZone.getTimeZone(value); + } else { + tz = tzNames.get(value); + if (tz == null) { + throw new IllegalArgumentException(value + " is not a supported timezone name"); + } + } + cal.setTimeZone(tz); + } + } + + private static final Strategy NUMBER_MONTH_STRATEGY = new NumberStrategy(Calendar.MONTH) { + @Override + int modify(final int iValue) { + return iValue - 1; + } + }; + private static final Strategy LITERAL_YEAR_STRATEGY = new NumberStrategy(Calendar.YEAR); + private static final Strategy WEEK_OF_YEAR_STRATEGY = new NumberStrategy(Calendar.WEEK_OF_YEAR); + private static final Strategy WEEK_OF_MONTH_STRATEGY = new NumberStrategy(Calendar.WEEK_OF_MONTH); + private static final Strategy DAY_OF_YEAR_STRATEGY = new NumberStrategy(Calendar.DAY_OF_YEAR); + private static final Strategy DAY_OF_MONTH_STRATEGY = new NumberStrategy(Calendar.DAY_OF_MONTH); + private static final Strategy DAY_OF_WEEK_IN_MONTH_STRATEGY = new NumberStrategy(Calendar.DAY_OF_WEEK_IN_MONTH); + private static final Strategy HOUR_OF_DAY_STRATEGY = new NumberStrategy(Calendar.HOUR_OF_DAY); + private static final Strategy MODULO_HOUR_OF_DAY_STRATEGY = new NumberStrategy(Calendar.HOUR_OF_DAY) { + @Override + int modify(final int iValue) { + return iValue % 24; + } + }; + private static final Strategy MODULO_HOUR_STRATEGY = new NumberStrategy(Calendar.HOUR) { + @Override + int modify(final int iValue) { + return iValue % 12; + } + }; + private static final Strategy HOUR_STRATEGY = new NumberStrategy(Calendar.HOUR); + private static final Strategy MINUTE_STRATEGY = new NumberStrategy(Calendar.MINUTE); + private static final Strategy SECOND_STRATEGY = new NumberStrategy(Calendar.SECOND); + private static final Strategy MILLISECOND_STRATEGY = new NumberStrategy(Calendar.MILLISECOND); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/time/FastDatePrinter.java b/TMessagesProj/src/main/java/org/telegram/messenger/time/FastDatePrinter.java new file mode 100644 index 00000000..58704309 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/time/FastDatePrinter.java @@ -0,0 +1,1278 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.time; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.text.DateFormat; +import java.text.DateFormatSymbols; +import java.text.FieldPosition; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.Locale; +import java.util.TimeZone; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + *

FastDatePrinter is a fast and thread-safe version of + * {@link java.text.SimpleDateFormat}.

+ * + *

This class can be used as a direct replacement to + * {@code SimpleDateFormat} in most formatting situations. + * This class is especially useful in multi-threaded server environments. + * {@code SimpleDateFormat} is not thread-safe in any JDK version, + * nor will it be as Sun have closed the bug/RFE. + *

+ * + *

Only formatting is supported, but all patterns are compatible with + * SimpleDateFormat (except time zones and some year patterns - see below).

+ * + *

Java 1.4 introduced a new pattern letter, {@code 'Z'}, to represent + * time zones in RFC822 format (eg. {@code +0800} or {@code -1100}). + * This pattern letter can be used here (on all JDK versions).

+ * + *

In addition, the pattern {@code 'ZZ'} has been made to represent + * ISO8601 full format time zones (eg. {@code +08:00} or {@code -11:00}). + * This introduces a minor incompatibility with Java 1.4, but at a gain of + * useful functionality.

+ * + *

Javadoc cites for the year pattern: For formatting, if the number of + * pattern letters is 2, the year is truncated to 2 digits; otherwise it is + * interpreted as a number. Starting with Java 1.7 a pattern of 'Y' or + * 'YYY' will be formatted as '2003', while it was '03' in former Java + * versions. FastDatePrinter implements the behavior of Java 7.

+ * + * @version $Id: FastDatePrinter.java 1567799 2014-02-12 23:25:58Z sebb $ + * @since 3.2 + */ +public class FastDatePrinter implements DatePrinter, Serializable { + // A lot of the speed in this class comes from caching, but some comes + // from the special int to StringBuffer conversion. + // + // The following produces a padded 2 digit number: + // buffer.append((char)(value / 10 + '0')); + // buffer.append((char)(value % 10 + '0')); + // + // Note that the fastest append to StringBuffer is a single char (used here). + // Note that Integer.toString() is not called, the conversion is simply + // taking the value and adding (mathematically) the ASCII value for '0'. + // So, don't change this code! It works and is very fast. + + /** + * Required for serialization support. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 1L; + + /** + * FULL locale dependent date or time style. + */ + public static final int FULL = DateFormat.FULL; + /** + * LONG locale dependent date or time style. + */ + public static final int LONG = DateFormat.LONG; + /** + * MEDIUM locale dependent date or time style. + */ + public static final int MEDIUM = DateFormat.MEDIUM; + /** + * SHORT locale dependent date or time style. + */ + public static final int SHORT = DateFormat.SHORT; + + /** + * The pattern. + */ + private final String mPattern; + /** + * The time zone. + */ + private final TimeZone mTimeZone; + /** + * The locale. + */ + private final Locale mLocale; + /** + * The parsed rules. + */ + private transient Rule[] mRules; + /** + * The estimated maximum length. + */ + private transient int mMaxLengthEstimate; + + // Constructor + //----------------------------------------------------------------------- + + /** + *

Constructs a new FastDatePrinter.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible pattern + * @param timeZone non-null time zone to use + * @param locale non-null locale to use + * @throws NullPointerException if pattern, timeZone, or locale is null. + */ + protected FastDatePrinter(final String pattern, final TimeZone timeZone, final Locale locale) { + mPattern = pattern; + mTimeZone = timeZone; + mLocale = locale; + + init(); + } + + /** + *

Initializes the instance for first use.

+ */ + private void init() { + final List rulesList = parsePattern(); + mRules = rulesList.toArray(new Rule[rulesList.size()]); + + int len = 0; + for (int i = mRules.length; --i >= 0; ) { + len += mRules[i].estimateLength(); + } + + mMaxLengthEstimate = len; + } + + // Parse the pattern + //----------------------------------------------------------------------- + + /** + *

Returns a list of Rules given a pattern.

+ * + * @return a {@code List} of Rule objects + * @throws IllegalArgumentException if pattern is invalid + */ + protected List parsePattern() { + final DateFormatSymbols symbols = new DateFormatSymbols(mLocale); + final List rules = new ArrayList(); + + final String[] ERAs = symbols.getEras(); + final String[] months = symbols.getMonths(); + final String[] shortMonths = symbols.getShortMonths(); + final String[] weekdays = symbols.getWeekdays(); + final String[] shortWeekdays = symbols.getShortWeekdays(); + final String[] AmPmStrings = symbols.getAmPmStrings(); + + final int length = mPattern.length(); + final int[] indexRef = new int[1]; + + for (int i = 0; i < length; i++) { + indexRef[0] = i; + final String token = parseToken(mPattern, indexRef); + i = indexRef[0]; + + final int tokenLen = token.length(); + if (tokenLen == 0) { + break; + } + + Rule rule; + final char c = token.charAt(0); + + switch (c) { + case 'G': // era designator (text) + rule = new TextField(Calendar.ERA, ERAs); + break; + case 'y': // year (number) + if (tokenLen == 2) { + rule = TwoDigitYearField.INSTANCE; + } else { + rule = selectNumberRule(Calendar.YEAR, tokenLen < 4 ? 4 : tokenLen); + } + break; + case 'M': // month in year (text and number) + if (tokenLen >= 4) { + rule = new TextField(Calendar.MONTH, months); + } else if (tokenLen == 3) { + rule = new TextField(Calendar.MONTH, shortMonths); + } else if (tokenLen == 2) { + rule = TwoDigitMonthField.INSTANCE; + } else { + rule = UnpaddedMonthField.INSTANCE; + } + break; + case 'd': // day in month (number) + rule = selectNumberRule(Calendar.DAY_OF_MONTH, tokenLen); + break; + case 'h': // hour in am/pm (number, 1..12) + rule = new TwelveHourField(selectNumberRule(Calendar.HOUR, tokenLen)); + break; + case 'H': // hour in day (number, 0..23) + rule = selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen); + break; + case 'm': // minute in hour (number) + rule = selectNumberRule(Calendar.MINUTE, tokenLen); + break; + case 's': // second in minute (number) + rule = selectNumberRule(Calendar.SECOND, tokenLen); + break; + case 'S': // millisecond (number) + rule = selectNumberRule(Calendar.MILLISECOND, tokenLen); + break; + case 'E': // day in week (text) + rule = new TextField(Calendar.DAY_OF_WEEK, tokenLen < 4 ? shortWeekdays : weekdays); + break; + case 'D': // day in year (number) + rule = selectNumberRule(Calendar.DAY_OF_YEAR, tokenLen); + break; + case 'F': // day of week in month (number) + rule = selectNumberRule(Calendar.DAY_OF_WEEK_IN_MONTH, tokenLen); + break; + case 'w': // week in year (number) + rule = selectNumberRule(Calendar.WEEK_OF_YEAR, tokenLen); + break; + case 'W': // week in month (number) + rule = selectNumberRule(Calendar.WEEK_OF_MONTH, tokenLen); + break; + case 'a': // am/pm marker (text) + rule = new TextField(Calendar.AM_PM, AmPmStrings); + break; + case 'k': // hour in day (1..24) + rule = new TwentyFourHourField(selectNumberRule(Calendar.HOUR_OF_DAY, tokenLen)); + break; + case 'K': // hour in am/pm (0..11) + rule = selectNumberRule(Calendar.HOUR, tokenLen); + break; + case 'z': // time zone (text) + if (tokenLen >= 4) { + rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.LONG); + } else { + rule = new TimeZoneNameRule(mTimeZone, mLocale, TimeZone.SHORT); + } + break; + case 'Z': // time zone (value) + if (tokenLen == 1) { + rule = TimeZoneNumberRule.INSTANCE_NO_COLON; + } else { + rule = TimeZoneNumberRule.INSTANCE_COLON; + } + break; + case '\'': // literal text + final String sub = token.substring(1); + if (sub.length() == 1) { + rule = new CharacterLiteral(sub.charAt(0)); + } else { + rule = new StringLiteral(sub); + } + break; + default: + throw new IllegalArgumentException("Illegal pattern component: " + token); + } + + rules.add(rule); + } + + return rules; + } + + /** + *

Performs the parsing of tokens.

+ * + * @param pattern the pattern + * @param indexRef index references + * @return parsed token + */ + protected String parseToken(final String pattern, final int[] indexRef) { + final StringBuilder buf = new StringBuilder(); + + int i = indexRef[0]; + final int length = pattern.length(); + + char c = pattern.charAt(i); + if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z') { + // Scan a run of the same character, which indicates a time + // pattern. + buf.append(c); + + while (i + 1 < length) { + final char peek = pattern.charAt(i + 1); + if (peek == c) { + buf.append(c); + i++; + } else { + break; + } + } + } else { + // This will identify token as text. + buf.append('\''); + + boolean inLiteral = false; + + for (; i < length; i++) { + c = pattern.charAt(i); + + if (c == '\'') { + if (i + 1 < length && pattern.charAt(i + 1) == '\'') { + // '' is treated as escaped ' + i++; + buf.append(c); + } else { + inLiteral = !inLiteral; + } + } else if (!inLiteral && + (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z')) { + i--; + break; + } else { + buf.append(c); + } + } + } + + indexRef[0] = i; + return buf.toString(); + } + + /** + *

Gets an appropriate rule for the padding required.

+ * + * @param field the field to get a rule for + * @param padding the padding required + * @return a new rule with the correct padding + */ + protected NumberRule selectNumberRule(final int field, final int padding) { + switch (padding) { + case 1: + return new UnpaddedNumberField(field); + case 2: + return new TwoDigitNumberField(field); + default: + return new PaddedNumberField(field, padding); + } + } + + // Format methods + //----------------------------------------------------------------------- + + /** + *

Formats a {@code Date}, {@code Calendar} or + * {@code Long} (milliseconds) object.

+ * + * @param obj the object to format + * @param toAppendTo the buffer to append to + * @param pos the position - ignored + * @return the buffer passed in + */ + @Override + public StringBuffer format(final Object obj, final StringBuffer toAppendTo, final FieldPosition pos) { + if (obj instanceof Date) { + return format((Date) obj, toAppendTo); + } else if (obj instanceof Calendar) { + return format((Calendar) obj, toAppendTo); + } else if (obj instanceof Long) { + return format(((Long) obj).longValue(), toAppendTo); + } else { + throw new IllegalArgumentException("Unknown class: " + + (obj == null ? "" : obj.getClass().getName())); + } + } + + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DatePrinter#format(long) + */ + @Override + public String format(final long millis) { + final Calendar c = newCalendar(); // hard code GregorianCalendar + c.setTimeInMillis(millis); + return applyRulesToString(c); + } + + /** + * Creates a String representation of the given Calendar by applying the rules of this printer to it. + * + * @param c the Calender to apply the rules to. + * @return a String representation of the given Calendar. + */ + private String applyRulesToString(final Calendar c) { + return applyRules(c, new StringBuffer(mMaxLengthEstimate)).toString(); + } + + /** + * Creation method for ne calender instances. + * + * @return a new Calendar instance. + */ + private GregorianCalendar newCalendar() { + // hard code GregorianCalendar + return new GregorianCalendar(mTimeZone, mLocale); + } + + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Date) + */ + @Override + public String format(final Date date) { + final Calendar c = newCalendar(); // hard code GregorianCalendar + c.setTime(date); + return applyRulesToString(c); + } + + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Calendar) + */ + @Override + public String format(final Calendar calendar) { + return format(calendar, new StringBuffer(mMaxLengthEstimate)).toString(); + } + + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DatePrinter#format(long, java.lang.StringBuffer) + */ + @Override + public StringBuffer format(final long millis, final StringBuffer buf) { + return format(new Date(millis), buf); + } + + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Date, java.lang.StringBuffer) + */ + @Override + public StringBuffer format(final Date date, final StringBuffer buf) { + final Calendar c = newCalendar(); // hard code GregorianCalendar + c.setTime(date); + return applyRules(c, buf); + } + + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DatePrinter#format(java.util.Calendar, java.lang.StringBuffer) + */ + @Override + public StringBuffer format(final Calendar calendar, final StringBuffer buf) { + return applyRules(calendar, buf); + } + + /** + *

Performs the formatting by applying the rules to the + * specified calendar.

+ * + * @param calendar the calendar to format + * @param buf the buffer to format into + * @return the specified string buffer + */ + protected StringBuffer applyRules(final Calendar calendar, final StringBuffer buf) { + for (final Rule rule : mRules) { + rule.appendTo(buf, calendar); + } + return buf; + } + + // Accessors + //----------------------------------------------------------------------- + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DatePrinter#getPattern() + */ + @Override + public String getPattern() { + return mPattern; + } + + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DatePrinter#getTimeZone() + */ + @Override + public TimeZone getTimeZone() { + return mTimeZone; + } + + /* (non-Javadoc) + * @see org.apache.commons.lang3.time.DatePrinter#getLocale() + */ + @Override + public Locale getLocale() { + return mLocale; + } + + /** + *

Gets an estimate for the maximum string length that the + * formatter will produce.

+ *

+ *

The actual formatted length will almost always be less than or + * equal to this amount.

+ * + * @return the maximum formatted length + */ + public int getMaxLengthEstimate() { + return mMaxLengthEstimate; + } + + // Basics + //----------------------------------------------------------------------- + + /** + *

Compares two objects for equality.

+ * + * @param obj the object to compare to + * @return {@code true} if equal + */ + @Override + public boolean equals(final Object obj) { + if (!(obj instanceof FastDatePrinter)) { + return false; + } + final FastDatePrinter other = (FastDatePrinter) obj; + return mPattern.equals(other.mPattern) + && mTimeZone.equals(other.mTimeZone) + && mLocale.equals(other.mLocale); + } + + /** + *

Returns a hashcode compatible with equals.

+ * + * @return a hashcode compatible with equals + */ + @Override + public int hashCode() { + return mPattern.hashCode() + 13 * (mTimeZone.hashCode() + 13 * mLocale.hashCode()); + } + + /** + *

Gets a debugging string version of this formatter.

+ * + * @return a debugging string + */ + @Override + public String toString() { + return "FastDatePrinter[" + mPattern + "," + mLocale + "," + mTimeZone.getID() + "]"; + } + + // Serializing + //----------------------------------------------------------------------- + + /** + * Create the object after serialization. This implementation reinitializes the + * transient properties. + * + * @param in ObjectInputStream from which the object is being deserialized. + * @throws IOException if there is an IO issue. + * @throws ClassNotFoundException if a class cannot be found. + */ + private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + init(); + } + + // Rules + //----------------------------------------------------------------------- + + /** + *

Inner class defining a rule.

+ */ + private interface Rule { + /** + * Returns the estimated lentgh of the result. + * + * @return the estimated length + */ + int estimateLength(); + + /** + * Appends the value of the specified calendar to the output buffer based on the rule implementation. + * + * @param buffer the output buffer + * @param calendar calendar to be appended + */ + void appendTo(StringBuffer buffer, Calendar calendar); + } + + /** + *

Inner class defining a numeric rule.

+ */ + private interface NumberRule extends Rule { + /** + * Appends the specified value to the output buffer based on the rule implementation. + * + * @param buffer the output buffer + * @param value the value to be appended + */ + void appendTo(StringBuffer buffer, int value); + } + + /** + *

Inner class to output a constant single character.

+ */ + private static class CharacterLiteral implements Rule { + private final char mValue; + + /** + * Constructs a new instance of {@code CharacterLiteral} + * to hold the specified value. + * + * @param value the character literal + */ + CharacterLiteral(final char value) { + mValue = value; + } + + /** + * {@inheritDoc} + */ + @Override + public int estimateLength() { + return 1; + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final Calendar calendar) { + buffer.append(mValue); + } + } + + /** + *

Inner class to output a constant string.

+ */ + private static class StringLiteral implements Rule { + private final String mValue; + + /** + * Constructs a new instance of {@code StringLiteral} + * to hold the specified value. + * + * @param value the string literal + */ + StringLiteral(final String value) { + mValue = value; + } + + /** + * {@inheritDoc} + */ + @Override + public int estimateLength() { + return mValue.length(); + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final Calendar calendar) { + buffer.append(mValue); + } + } + + /** + *

Inner class to output one of a set of values.

+ */ + private static class TextField implements Rule { + private final int mField; + private final String[] mValues; + + /** + * Constructs an instance of {@code TextField} + * with the specified field and values. + * + * @param field the field + * @param values the field values + */ + TextField(final int field, final String[] values) { + mField = field; + mValues = values; + } + + /** + * {@inheritDoc} + */ + @Override + public int estimateLength() { + int max = 0; + for (int i = mValues.length; --i >= 0; ) { + final int len = mValues[i].length(); + if (len > max) { + max = len; + } + } + return max; + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final Calendar calendar) { + buffer.append(mValues[calendar.get(mField)]); + } + } + + /** + *

Inner class to output an unpadded number.

+ */ + private static class UnpaddedNumberField implements NumberRule { + private final int mField; + + /** + * Constructs an instance of {@code UnpadedNumberField} with the specified field. + * + * @param field the field + */ + UnpaddedNumberField(final int field) { + mField = field; + } + + /** + * {@inheritDoc} + */ + @Override + public int estimateLength() { + return 4; + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final Calendar calendar) { + appendTo(buffer, calendar.get(mField)); + } + + /** + * {@inheritDoc} + */ + @Override + public final void appendTo(final StringBuffer buffer, final int value) { + if (value < 10) { + buffer.append((char) (value + '0')); + } else if (value < 100) { + buffer.append((char) (value / 10 + '0')); + buffer.append((char) (value % 10 + '0')); + } else { + buffer.append(Integer.toString(value)); + } + } + } + + /** + *

Inner class to output an unpadded month.

+ */ + private static class UnpaddedMonthField implements NumberRule { + static final UnpaddedMonthField INSTANCE = new UnpaddedMonthField(); + + /** + * Constructs an instance of {@code UnpaddedMonthField}. + */ + UnpaddedMonthField() { + super(); + } + + /** + * {@inheritDoc} + */ + @Override + public int estimateLength() { + return 2; + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final Calendar calendar) { + appendTo(buffer, calendar.get(Calendar.MONTH) + 1); + } + + /** + * {@inheritDoc} + */ + @Override + public final void appendTo(final StringBuffer buffer, final int value) { + if (value < 10) { + buffer.append((char) (value + '0')); + } else { + buffer.append((char) (value / 10 + '0')); + buffer.append((char) (value % 10 + '0')); + } + } + } + + /** + *

Inner class to output a padded number.

+ */ + private static class PaddedNumberField implements NumberRule { + private final int mField; + private final int mSize; + + /** + * Constructs an instance of {@code PaddedNumberField}. + * + * @param field the field + * @param size size of the output field + */ + PaddedNumberField(final int field, final int size) { + if (size < 3) { + // Should use UnpaddedNumberField or TwoDigitNumberField. + throw new IllegalArgumentException(); + } + mField = field; + mSize = size; + } + + /** + * {@inheritDoc} + */ + @Override + public int estimateLength() { + return 4; + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final Calendar calendar) { + appendTo(buffer, calendar.get(mField)); + } + + /** + * {@inheritDoc} + */ + @Override + public final void appendTo(final StringBuffer buffer, final int value) { + if (value < 100) { + for (int i = mSize; --i >= 2; ) { + buffer.append('0'); + } + buffer.append((char) (value / 10 + '0')); + buffer.append((char) (value % 10 + '0')); + } else { + int digits; + if (value < 1000) { + digits = 3; + } else { + digits = Integer.toString(value).length(); + } + for (int i = mSize; --i >= digits; ) { + buffer.append('0'); + } + buffer.append(Integer.toString(value)); + } + } + } + + /** + *

Inner class to output a two digit number.

+ */ + private static class TwoDigitNumberField implements NumberRule { + private final int mField; + + /** + * Constructs an instance of {@code TwoDigitNumberField} with the specified field. + * + * @param field the field + */ + TwoDigitNumberField(final int field) { + mField = field; + } + + /** + * {@inheritDoc} + */ + @Override + public int estimateLength() { + return 2; + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final Calendar calendar) { + appendTo(buffer, calendar.get(mField)); + } + + /** + * {@inheritDoc} + */ + @Override + public final void appendTo(final StringBuffer buffer, final int value) { + if (value < 100) { + buffer.append((char) (value / 10 + '0')); + buffer.append((char) (value % 10 + '0')); + } else { + buffer.append(Integer.toString(value)); + } + } + } + + /** + *

Inner class to output a two digit year.

+ */ + private static class TwoDigitYearField implements NumberRule { + static final TwoDigitYearField INSTANCE = new TwoDigitYearField(); + + /** + * Constructs an instance of {@code TwoDigitYearField}. + */ + TwoDigitYearField() { + super(); + } + + /** + * {@inheritDoc} + */ + @Override + public int estimateLength() { + return 2; + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final Calendar calendar) { + appendTo(buffer, calendar.get(Calendar.YEAR) % 100); + } + + /** + * {@inheritDoc} + */ + @Override + public final void appendTo(final StringBuffer buffer, final int value) { + buffer.append((char) (value / 10 + '0')); + buffer.append((char) (value % 10 + '0')); + } + } + + /** + *

Inner class to output a two digit month.

+ */ + private static class TwoDigitMonthField implements NumberRule { + static final TwoDigitMonthField INSTANCE = new TwoDigitMonthField(); + + /** + * Constructs an instance of {@code TwoDigitMonthField}. + */ + TwoDigitMonthField() { + super(); + } + + /** + * {@inheritDoc} + */ + @Override + public int estimateLength() { + return 2; + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final Calendar calendar) { + appendTo(buffer, calendar.get(Calendar.MONTH) + 1); + } + + /** + * {@inheritDoc} + */ + @Override + public final void appendTo(final StringBuffer buffer, final int value) { + buffer.append((char) (value / 10 + '0')); + buffer.append((char) (value % 10 + '0')); + } + } + + /** + *

Inner class to output the twelve hour field.

+ */ + private static class TwelveHourField implements NumberRule { + private final NumberRule mRule; + + /** + * Constructs an instance of {@code TwelveHourField} with the specified + * {@code NumberRule}. + * + * @param rule the rule + */ + TwelveHourField(final NumberRule rule) { + mRule = rule; + } + + /** + * {@inheritDoc} + */ + @Override + public int estimateLength() { + return mRule.estimateLength(); + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final Calendar calendar) { + int value = calendar.get(Calendar.HOUR); + if (value == 0) { + value = calendar.getLeastMaximum(Calendar.HOUR) + 1; + } + mRule.appendTo(buffer, value); + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final int value) { + mRule.appendTo(buffer, value); + } + } + + /** + *

Inner class to output the twenty four hour field.

+ */ + private static class TwentyFourHourField implements NumberRule { + private final NumberRule mRule; + + /** + * Constructs an instance of {@code TwentyFourHourField} with the specified + * {@code NumberRule}. + * + * @param rule the rule + */ + TwentyFourHourField(final NumberRule rule) { + mRule = rule; + } + + /** + * {@inheritDoc} + */ + @Override + public int estimateLength() { + return mRule.estimateLength(); + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final Calendar calendar) { + int value = calendar.get(Calendar.HOUR_OF_DAY); + if (value == 0) { + value = calendar.getMaximum(Calendar.HOUR_OF_DAY) + 1; + } + mRule.appendTo(buffer, value); + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final int value) { + mRule.appendTo(buffer, value); + } + } + + //----------------------------------------------------------------------- + + private static final ConcurrentMap cTimeZoneDisplayCache = + new ConcurrentHashMap(7); + + /** + *

Gets the time zone display name, using a cache for performance.

+ * + * @param tz the zone to query + * @param daylight true if daylight savings + * @param style the style to use {@code TimeZone.LONG} or {@code TimeZone.SHORT} + * @param locale the locale to use + * @return the textual name of the time zone + */ + static String getTimeZoneDisplay(final TimeZone tz, final boolean daylight, final int style, final Locale locale) { + final TimeZoneDisplayKey key = new TimeZoneDisplayKey(tz, daylight, style, locale); + String value = cTimeZoneDisplayCache.get(key); + if (value == null) { + // This is a very slow call, so cache the results. + value = tz.getDisplayName(daylight, style, locale); + final String prior = cTimeZoneDisplayCache.putIfAbsent(key, value); + if (prior != null) { + value = prior; + } + } + return value; + } + + /** + *

Inner class to output a time zone name.

+ */ + private static class TimeZoneNameRule implements Rule { + private final Locale mLocale; + private final int mStyle; + private final String mStandard; + private final String mDaylight; + + /** + * Constructs an instance of {@code TimeZoneNameRule} with the specified properties. + * + * @param timeZone the time zone + * @param locale the locale + * @param style the style + */ + TimeZoneNameRule(final TimeZone timeZone, final Locale locale, final int style) { + mLocale = locale; + mStyle = style; + + mStandard = getTimeZoneDisplay(timeZone, false, style, locale); + mDaylight = getTimeZoneDisplay(timeZone, true, style, locale); + } + + /** + * {@inheritDoc} + */ + @Override + public int estimateLength() { + // We have no access to the Calendar object that will be passed to + // appendTo so base estimate on the TimeZone passed to the + // constructor + return Math.max(mStandard.length(), mDaylight.length()); + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final Calendar calendar) { + final TimeZone zone = calendar.getTimeZone(); + if (zone.useDaylightTime() + && calendar.get(Calendar.DST_OFFSET) != 0) { + buffer.append(getTimeZoneDisplay(zone, true, mStyle, mLocale)); + } else { + buffer.append(getTimeZoneDisplay(zone, false, mStyle, mLocale)); + } + } + } + + /** + *

Inner class to output a time zone as a number {@code +/-HHMM} + * or {@code +/-HH:MM}.

+ */ + private static class TimeZoneNumberRule implements Rule { + static final TimeZoneNumberRule INSTANCE_COLON = new TimeZoneNumberRule(true); + static final TimeZoneNumberRule INSTANCE_NO_COLON = new TimeZoneNumberRule(false); + + final boolean mColon; + + /** + * Constructs an instance of {@code TimeZoneNumberRule} with the specified properties. + * + * @param colon add colon between HH and MM in the output if {@code true} + */ + TimeZoneNumberRule(final boolean colon) { + mColon = colon; + } + + /** + * {@inheritDoc} + */ + @Override + public int estimateLength() { + return 5; + } + + /** + * {@inheritDoc} + */ + @Override + public void appendTo(final StringBuffer buffer, final Calendar calendar) { + int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET); + + if (offset < 0) { + buffer.append('-'); + offset = -offset; + } else { + buffer.append('+'); + } + + final int hours = offset / (60 * 60 * 1000); + buffer.append((char) (hours / 10 + '0')); + buffer.append((char) (hours % 10 + '0')); + + if (mColon) { + buffer.append(':'); + } + + final int minutes = offset / (60 * 1000) - 60 * hours; + buffer.append((char) (minutes / 10 + '0')); + buffer.append((char) (minutes % 10 + '0')); + } + } + + // ---------------------------------------------------------------------- + + /** + *

Inner class that acts as a compound key for time zone names.

+ */ + private static class TimeZoneDisplayKey { + private final TimeZone mTimeZone; + private final int mStyle; + private final Locale mLocale; + + /** + * Constructs an instance of {@code TimeZoneDisplayKey} with the specified properties. + * + * @param timeZone the time zone + * @param daylight adjust the style for daylight saving time if {@code true} + * @param style the timezone style + * @param locale the timezone locale + */ + TimeZoneDisplayKey(final TimeZone timeZone, + final boolean daylight, final int style, final Locale locale) { + mTimeZone = timeZone; + if (daylight) { + mStyle = style | 0x80000000; + } else { + mStyle = style; + } + mLocale = locale; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + return (mStyle * 31 + mLocale.hashCode()) * 31 + mTimeZone.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj instanceof TimeZoneDisplayKey) { + final TimeZoneDisplayKey other = (TimeZoneDisplayKey) obj; + return + mTimeZone.equals(other.mTimeZone) && + mStyle == other.mStyle && + mLocale.equals(other.mLocale); + } + return false; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/time/FormatCache.java b/TMessagesProj/src/main/java/org/telegram/messenger/time/FormatCache.java new file mode 100644 index 00000000..8caab2cc --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/time/FormatCache.java @@ -0,0 +1,265 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.telegram.messenger.time; + +import java.text.DateFormat; +import java.text.Format; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Locale; +import java.util.TimeZone; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + *

FormatCache is a cache and factory for {@link Format}s.

+ * + * @since 3.0 + * @version $Id: FormatCache 892161 2009-12-18 07:21:10Z $ + */ +// TODO: Before making public move from getDateTimeInstance(Integer,...) to int; or some other approach. +abstract class FormatCache { + /** + * No date or no time. Used in same parameters as DateFormat.SHORT or DateFormat.LONG + */ + static final int NONE = -1; + + private final ConcurrentMap cInstanceCache + = new ConcurrentHashMap(7); + + private static final ConcurrentMap cDateTimeInstanceCache + = new ConcurrentHashMap(7); + + /** + *

Gets a formatter instance using the default pattern in the + * default timezone and locale.

+ * + * @return a date/time formatter + */ + public F getInstance() { + return getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, TimeZone.getDefault(), Locale.getDefault()); + } + + /** + *

Gets a formatter instance using the specified pattern, time zone + * and locale.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible + * pattern, non-null + * @param timeZone the time zone, null means use the default TimeZone + * @param locale the locale, null means use the default Locale + * @return a pattern based date/time formatter + * @throws IllegalArgumentException if pattern is invalid + * or null + */ + public F getInstance(final String pattern, TimeZone timeZone, Locale locale) { + if (pattern == null) { + throw new NullPointerException("pattern must not be null"); + } + if (timeZone == null) { + timeZone = TimeZone.getDefault(); + } + if (locale == null) { + locale = Locale.getDefault(); + } + final MultipartKey key = new MultipartKey(pattern, timeZone, locale); + F format = cInstanceCache.get(key); + if (format == null) { + format = createInstance(pattern, timeZone, locale); + final F previousValue = cInstanceCache.putIfAbsent(key, format); + if (previousValue != null) { + // another thread snuck in and did the same work + // we should return the instance that is in ConcurrentMap + format = previousValue; + } + } + return format; + } + + /** + *

Create a format instance using the specified pattern, time zone + * and locale.

+ * + * @param pattern {@link java.text.SimpleDateFormat} compatible pattern, this will not be null. + * @param timeZone time zone, this will not be null. + * @param locale locale, this will not be null. + * @return a pattern based date/time formatter + * @throws IllegalArgumentException if pattern is invalid + * or null + */ + abstract protected F createInstance(String pattern, TimeZone timeZone, Locale locale); + + /** + *

Gets a date/time formatter instance using the specified style, + * time zone and locale.

+ * + * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no date in format + * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no time in format + * @param timeZone optional time zone, overrides time zone of + * formatted date, null means use default Locale + * @param locale optional locale, overrides system locale + * @return a localized standard date/time formatter + * @throws IllegalArgumentException if the Locale has no date/time + * pattern defined + */ + // This must remain private, see LANG-884 + private F getDateTimeInstance(final Integer dateStyle, final Integer timeStyle, final TimeZone timeZone, Locale locale) { + if (locale == null) { + locale = Locale.getDefault(); + } + final String pattern = getPatternForStyle(dateStyle, timeStyle, locale); + return getInstance(pattern, timeZone, locale); + } + + /** + *

Gets a date/time formatter instance using the specified style, + * time zone and locale.

+ * + * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT + * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted date, null means use default Locale + * @param locale optional locale, overrides system locale + * @return a localized standard date/time formatter + * @throws IllegalArgumentException if the Locale has no date/time + * pattern defined + */ + // package protected, for access from FastDateFormat; do not make public or protected + F getDateTimeInstance(final int dateStyle, final int timeStyle, final TimeZone timeZone, Locale locale) { + return getDateTimeInstance(Integer.valueOf(dateStyle), Integer.valueOf(timeStyle), timeZone, locale); + } + + /** + *

Gets a date formatter instance using the specified style, + * time zone and locale.

+ * + * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted date, null means use default Locale + * @param locale optional locale, overrides system locale + * @return a localized standard date/time formatter + * @throws IllegalArgumentException if the Locale has no date/time + * pattern defined + */ + // package protected, for access from FastDateFormat; do not make public or protected + F getDateInstance(final int dateStyle, final TimeZone timeZone, Locale locale) { + return getDateTimeInstance(Integer.valueOf(dateStyle), null, timeZone, locale); + } + + /** + *

Gets a time formatter instance using the specified style, + * time zone and locale.

+ * + * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT + * @param timeZone optional time zone, overrides time zone of + * formatted date, null means use default Locale + * @param locale optional locale, overrides system locale + * @return a localized standard date/time formatter + * @throws IllegalArgumentException if the Locale has no date/time + * pattern defined + */ + // package protected, for access from FastDateFormat; do not make public or protected + F getTimeInstance(final int timeStyle, final TimeZone timeZone, Locale locale) { + return getDateTimeInstance(null, Integer.valueOf(timeStyle), timeZone, locale); + } + + /** + *

Gets a date/time format for the specified styles and locale.

+ * + * @param dateStyle date style: FULL, LONG, MEDIUM, or SHORT, null indicates no date in format + * @param timeStyle time style: FULL, LONG, MEDIUM, or SHORT, null indicates no time in format + * @param locale The non-null locale of the desired format + * @return a localized standard date/time format + * @throws IllegalArgumentException if the Locale has no date/time pattern defined + */ + // package protected, for access from test code; do not make public or protected + static String getPatternForStyle(final Integer dateStyle, final Integer timeStyle, final Locale locale) { + final MultipartKey key = new MultipartKey(dateStyle, timeStyle, locale); + + String pattern = cDateTimeInstanceCache.get(key); + if (pattern == null) { + try { + DateFormat formatter; + if (dateStyle == null) { + formatter = DateFormat.getTimeInstance(timeStyle.intValue(), locale); + } else if (timeStyle == null) { + formatter = DateFormat.getDateInstance(dateStyle.intValue(), locale); + } else { + formatter = DateFormat.getDateTimeInstance(dateStyle.intValue(), timeStyle.intValue(), locale); + } + pattern = ((SimpleDateFormat) formatter).toPattern(); + final String previous = cDateTimeInstanceCache.putIfAbsent(key, pattern); + if (previous != null) { + // even though it doesn't matter if another thread put the pattern + // it's still good practice to return the String instance that is + // actually in the ConcurrentMap + pattern = previous; + } + } catch (final ClassCastException ex) { + throw new IllegalArgumentException("No date time pattern for locale: " + locale); + } + } + return pattern; + } + + // ---------------------------------------------------------------------- + + /** + *

Helper class to hold multi-part Map keys

+ */ + private static class MultipartKey { + private final Object[] keys; + private int hashCode; + + /** + * Constructs an instance of MultipartKey to hold the specified objects. + * + * @param keys the set of objects that make up the key. Each key may be null. + */ + public MultipartKey(final Object... keys) { + this.keys = keys; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(final Object obj) { + // Eliminate the usual boilerplate because + // this inner static class is only used in a generic ConcurrentHashMap + // which will not compare against other Object types + return Arrays.equals(keys, ((MultipartKey) obj).keys); + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + if (hashCode == 0) { + int rc = 0; + for (final Object key : keys) { + if (key != null) { + rc = rc * 7 + key.hashCode(); + } + } + hashCode = rc; + } + return hashCode; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/InputSurface.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/InputSurface.java new file mode 100644 index 00000000..a1d72a53 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/InputSurface.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.video; + +import android.annotation.TargetApi; +import android.opengl.EGL14; +import android.opengl.EGLExt; +import android.opengl.EGLConfig; +import android.opengl.EGLContext; +import android.opengl.EGLDisplay; +import android.opengl.EGLSurface; +import android.view.Surface; + +@TargetApi(17) +public class InputSurface { + + private static final int EGL_RECORDABLE_ANDROID = 0x3142; + private static final int EGL_OPENGL_ES2_BIT = 4; + private EGLDisplay mEGLDisplay; + private EGLContext mEGLContext; + private EGLSurface mEGLSurface; + private Surface mSurface; + + public InputSurface(Surface surface) { + if (surface == null) { + throw new NullPointerException(); + } + mSurface = surface; + eglSetup(); + } + + private void eglSetup() { + mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); + if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) { + throw new RuntimeException("unable to get EGL14 display"); + } + int[] version = new int[2]; + if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) { + mEGLDisplay = null; + throw new RuntimeException("unable to initialize EGL14"); + } + + int[] attribList = { + EGL14.EGL_RED_SIZE, 8, + EGL14.EGL_GREEN_SIZE, 8, + EGL14.EGL_BLUE_SIZE, 8, + EGL14.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RECORDABLE_ANDROID, 1, + EGL14.EGL_NONE + }; + EGLConfig[] configs = new EGLConfig[1]; + int[] numConfigs = new int[1]; + if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length, + numConfigs, 0)) { + throw new RuntimeException("unable to find RGB888+recordable ES2 EGL config"); + } + + int[] attrib_list = { + EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, + EGL14.EGL_NONE + }; + + mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT, attrib_list, 0); + checkEglError("eglCreateContext"); + if (mEGLContext == null) { + throw new RuntimeException("null context"); + } + + int[] surfaceAttribs = { + EGL14.EGL_NONE + }; + mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, configs[0], mSurface, + surfaceAttribs, 0); + checkEglError("eglCreateWindowSurface"); + if (mEGLSurface == null) { + throw new RuntimeException("surface was null"); + } + } + + public void release() { + if (EGL14.eglGetCurrentContext().equals(mEGLContext)) { + EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); + } + EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface); + EGL14.eglDestroyContext(mEGLDisplay, mEGLContext); + mSurface.release(); + mEGLDisplay = null; + mEGLContext = null; + mEGLSurface = null; + mSurface = null; + } + + public void makeCurrent() { + if (!EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext)) { + throw new RuntimeException("eglMakeCurrent failed"); + } + } + + public boolean swapBuffers() { + return EGL14.eglSwapBuffers(mEGLDisplay, mEGLSurface); + } + + public Surface getSurface() { + return mSurface; + } + + public void setPresentationTime(long nsecs) { + EGLExt.eglPresentationTimeANDROID(mEGLDisplay, mEGLSurface, nsecs); + } + + private void checkEglError(String msg) { + boolean failed = false; + while (EGL14.eglGetError() != EGL14.EGL_SUCCESS) { + failed = true; + } + if (failed) { + throw new RuntimeException("EGL error encountered (see log)"); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/MP4Builder.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/MP4Builder.java new file mode 100644 index 00000000..943b5883 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/MP4Builder.java @@ -0,0 +1,445 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger.video; + +import android.annotation.TargetApi; +import android.media.MediaCodec; +import android.media.MediaFormat; + +import com.coremedia.iso.BoxParser; +import com.coremedia.iso.IsoFile; +import com.coremedia.iso.IsoTypeWriter; +import com.coremedia.iso.boxes.Box; +import com.coremedia.iso.boxes.Container; +import com.coremedia.iso.boxes.DataEntryUrlBox; +import com.coremedia.iso.boxes.DataInformationBox; +import com.coremedia.iso.boxes.DataReferenceBox; +import com.coremedia.iso.boxes.FileTypeBox; +import com.coremedia.iso.boxes.HandlerBox; +import com.coremedia.iso.boxes.MediaBox; +import com.coremedia.iso.boxes.MediaHeaderBox; +import com.coremedia.iso.boxes.MediaInformationBox; +import com.coremedia.iso.boxes.MovieBox; +import com.coremedia.iso.boxes.MovieHeaderBox; +import com.coremedia.iso.boxes.SampleSizeBox; +import com.coremedia.iso.boxes.SampleTableBox; +import com.coremedia.iso.boxes.SampleToChunkBox; +import com.coremedia.iso.boxes.StaticChunkOffsetBox; +import com.coremedia.iso.boxes.SyncSampleBox; +import com.coremedia.iso.boxes.TimeToSampleBox; +import com.coremedia.iso.boxes.TrackBox; +import com.coremedia.iso.boxes.TrackHeaderBox; +import com.googlecode.mp4parser.DataSource; +import com.googlecode.mp4parser.util.Matrix; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.WritableByteChannel; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +@TargetApi(16) +public class MP4Builder { + + private InterleaveChunkMdat mdat = null; + private Mp4Movie currentMp4Movie = null; + private FileOutputStream fos = null; + private FileChannel fc = null; + private long dataOffset = 0; + private long writedSinceLastMdat = 0; + private boolean writeNewMdat = true; + private HashMap track2SampleSizes = new HashMap<>(); + private ByteBuffer sizeBuffer = null; + + public MP4Builder createMovie(Mp4Movie mp4Movie) throws Exception { + currentMp4Movie = mp4Movie; + + fos = new FileOutputStream(mp4Movie.getCacheFile()); + fc = fos.getChannel(); + + FileTypeBox fileTypeBox = createFileTypeBox(); + fileTypeBox.getBox(fc); + dataOffset += fileTypeBox.getSize(); + writedSinceLastMdat += dataOffset; + + mdat = new InterleaveChunkMdat(); + + sizeBuffer = ByteBuffer.allocateDirect(4); + + return this; + } + + private void flushCurrentMdat() throws Exception { + long oldPosition = fc.position(); + fc.position(mdat.getOffset()); + mdat.getBox(fc); + fc.position(oldPosition); + mdat.setDataOffset(0); + mdat.setContentSize(0); + fos.flush(); + } + + public boolean writeSampleData(int trackIndex, ByteBuffer byteBuf, MediaCodec.BufferInfo bufferInfo, boolean isAudio) throws Exception { + if (writeNewMdat) { + mdat.setContentSize(0); + mdat.getBox(fc); + mdat.setDataOffset(dataOffset); + dataOffset += 16; + writedSinceLastMdat += 16; + writeNewMdat = false; + } + + mdat.setContentSize(mdat.getContentSize() + bufferInfo.size); + writedSinceLastMdat += bufferInfo.size; + + boolean flush = false; + if (writedSinceLastMdat >= 32 * 1024) { + flushCurrentMdat(); + writeNewMdat = true; + flush = true; + writedSinceLastMdat -= 32 * 1024; + } + + currentMp4Movie.addSample(trackIndex, dataOffset, bufferInfo); + byteBuf.position(bufferInfo.offset + (isAudio ? 0 : 4)); + byteBuf.limit(bufferInfo.offset + bufferInfo.size); + + if (!isAudio) { + sizeBuffer.position(0); + sizeBuffer.putInt(bufferInfo.size - 4); + sizeBuffer.position(0); + fc.write(sizeBuffer); + } + + fc.write(byteBuf); + dataOffset += bufferInfo.size; + + if (flush) { + fos.flush(); + } + return flush; + } + + public int addTrack(MediaFormat mediaFormat, boolean isAudio) throws Exception { + return currentMp4Movie.addTrack(mediaFormat, isAudio); + } + + public void finishMovie(boolean error) throws Exception { + if (mdat.getContentSize() != 0) { + flushCurrentMdat(); + } + + for (Track track : currentMp4Movie.getTracks()) { + List samples = track.getSamples(); + long[] sizes = new long[samples.size()]; + for (int i = 0; i < sizes.length; i++) { + sizes[i] = samples.get(i).getSize(); + } + track2SampleSizes.put(track, sizes); + } + + Box moov = createMovieBox(currentMp4Movie); + moov.getBox(fc); + fos.flush(); + + fc.close(); + fos.close(); + } + + protected FileTypeBox createFileTypeBox() { + LinkedList minorBrands = new LinkedList<>(); + minorBrands.add("isom"); + minorBrands.add("3gp4"); + return new FileTypeBox("isom", 0, minorBrands); + } + + private class InterleaveChunkMdat implements Box { + private Container parent; + private long contentSize = 1024 * 1024 * 1024; + private long dataOffset = 0; + + public Container getParent() { + return parent; + } + + public long getOffset() { + return dataOffset; + } + + public void setDataOffset(long offset) { + dataOffset = offset; + } + + public void setParent(Container parent) { + this.parent = parent; + } + + public void setContentSize(long contentSize) { + this.contentSize = contentSize; + } + + public long getContentSize() { + return contentSize; + } + + public String getType() { + return "mdat"; + } + + public long getSize() { + return 16 + contentSize; + } + + private boolean isSmallBox(long contentSize) { + return (contentSize + 8) < 4294967296L; + } + + @Override + public void parse(DataSource dataSource, ByteBuffer header, long contentSize, BoxParser boxParser) throws IOException { + + } + + public void getBox(WritableByteChannel writableByteChannel) throws IOException { + ByteBuffer bb = ByteBuffer.allocate(16); + long size = getSize(); + if (isSmallBox(size)) { + IsoTypeWriter.writeUInt32(bb, size); + } else { + IsoTypeWriter.writeUInt32(bb, 1); + } + bb.put(IsoFile.fourCCtoBytes("mdat")); + if (isSmallBox(size)) { + bb.put(new byte[8]); + } else { + IsoTypeWriter.writeUInt64(bb, size); + } + bb.rewind(); + writableByteChannel.write(bb); + } + } + + public static long gcd(long a, long b) { + if (b == 0) { + return a; + } + return gcd(b, a % b); + } + + public long getTimescale(Mp4Movie mp4Movie) { + long timescale = 0; + if (!mp4Movie.getTracks().isEmpty()) { + timescale = mp4Movie.getTracks().iterator().next().getTimeScale(); + } + for (Track track : mp4Movie.getTracks()) { + timescale = gcd(track.getTimeScale(), timescale); + } + return timescale; + } + + protected MovieBox createMovieBox(Mp4Movie movie) { + MovieBox movieBox = new MovieBox(); + MovieHeaderBox mvhd = new MovieHeaderBox(); + + mvhd.setCreationTime(new Date()); + mvhd.setModificationTime(new Date()); + mvhd.setMatrix(Matrix.ROTATE_0); + long movieTimeScale = getTimescale(movie); + long duration = 0; + + for (Track track : movie.getTracks()) { + long tracksDuration = track.getDuration() * movieTimeScale / track.getTimeScale(); + if (tracksDuration > duration) { + duration = tracksDuration; + } + } + + mvhd.setDuration(duration); + mvhd.setTimescale(movieTimeScale); + mvhd.setNextTrackId(movie.getTracks().size() + 1); + + movieBox.addBox(mvhd); + for (Track track : movie.getTracks()) { + movieBox.addBox(createTrackBox(track, movie)); + } + return movieBox; + } + + protected TrackBox createTrackBox(Track track, Mp4Movie movie) { + TrackBox trackBox = new TrackBox(); + TrackHeaderBox tkhd = new TrackHeaderBox(); + + tkhd.setEnabled(true); + tkhd.setInMovie(true); + tkhd.setInPreview(true); + if (track.isAudio()) { + tkhd.setMatrix(Matrix.ROTATE_0); + } else { + tkhd.setMatrix(movie.getMatrix()); + } + tkhd.setAlternateGroup(0); + tkhd.setCreationTime(track.getCreationTime()); + tkhd.setDuration(track.getDuration() * getTimescale(movie) / track.getTimeScale()); + tkhd.setHeight(track.getHeight()); + tkhd.setWidth(track.getWidth()); + tkhd.setLayer(0); + tkhd.setModificationTime(new Date()); + tkhd.setTrackId(track.getTrackId() + 1); + tkhd.setVolume(track.getVolume()); + + trackBox.addBox(tkhd); + + MediaBox mdia = new MediaBox(); + trackBox.addBox(mdia); + MediaHeaderBox mdhd = new MediaHeaderBox(); + mdhd.setCreationTime(track.getCreationTime()); + mdhd.setDuration(track.getDuration()); + mdhd.setTimescale(track.getTimeScale()); + mdhd.setLanguage("eng"); + mdia.addBox(mdhd); + HandlerBox hdlr = new HandlerBox(); + hdlr.setName(track.isAudio() ? "SoundHandle" : "VideoHandle"); + hdlr.setHandlerType(track.getHandler()); + + mdia.addBox(hdlr); + + MediaInformationBox minf = new MediaInformationBox(); + minf.addBox(track.getMediaHeaderBox()); + + DataInformationBox dinf = new DataInformationBox(); + DataReferenceBox dref = new DataReferenceBox(); + dinf.addBox(dref); + DataEntryUrlBox url = new DataEntryUrlBox(); + url.setFlags(1); + dref.addBox(url); + minf.addBox(dinf); + + Box stbl = createStbl(track); + minf.addBox(stbl); + mdia.addBox(minf); + + return trackBox; + } + + protected Box createStbl(Track track) { + SampleTableBox stbl = new SampleTableBox(); + + createStsd(track, stbl); + createStts(track, stbl); + createStss(track, stbl); + createStsc(track, stbl); + createStsz(track, stbl); + createStco(track, stbl); + + return stbl; + } + + protected void createStsd(Track track, SampleTableBox stbl) { + stbl.addBox(track.getSampleDescriptionBox()); + } + + protected void createStts(Track track, SampleTableBox stbl) { + TimeToSampleBox.Entry lastEntry = null; + List entries = new ArrayList<>(); + + for (long delta : track.getSampleDurations()) { + if (lastEntry != null && lastEntry.getDelta() == delta) { + lastEntry.setCount(lastEntry.getCount() + 1); + } else { + lastEntry = new TimeToSampleBox.Entry(1, delta); + entries.add(lastEntry); + } + } + TimeToSampleBox stts = new TimeToSampleBox(); + stts.setEntries(entries); + stbl.addBox(stts); + } + + protected void createStss(Track track, SampleTableBox stbl) { + long[] syncSamples = track.getSyncSamples(); + if (syncSamples != null && syncSamples.length > 0) { + SyncSampleBox stss = new SyncSampleBox(); + stss.setSampleNumber(syncSamples); + stbl.addBox(stss); + } + } + + protected void createStsc(Track track, SampleTableBox stbl) { + SampleToChunkBox stsc = new SampleToChunkBox(); + stsc.setEntries(new LinkedList()); + + long lastOffset; + int lastChunkNumber = 1; + int lastSampleCount = 0; + + int previousWritedChunkCount = -1; + + int samplesCount = track.getSamples().size(); + for (int a = 0; a < samplesCount; a++) { + Sample sample = track.getSamples().get(a); + long offset = sample.getOffset(); + long size = sample.getSize(); + + lastOffset = offset + size; + lastSampleCount++; + + boolean write = false; + if (a != samplesCount - 1) { + Sample nextSample = track.getSamples().get(a + 1); + if (lastOffset != nextSample.getOffset()) { + write = true; + } + } else { + write = true; + } + if (write) { + if (previousWritedChunkCount != lastSampleCount) { + stsc.getEntries().add(new SampleToChunkBox.Entry(lastChunkNumber, lastSampleCount, 1)); + previousWritedChunkCount = lastSampleCount; + } + lastSampleCount = 0; + lastChunkNumber++; + } + } + stbl.addBox(stsc); + } + + protected void createStsz(Track track, SampleTableBox stbl) { + SampleSizeBox stsz = new SampleSizeBox(); + stsz.setSampleSizes(track2SampleSizes.get(track)); + stbl.addBox(stsz); + } + + protected void createStco(Track track, SampleTableBox stbl) { + ArrayList chunksOffsets = new ArrayList<>(); + long lastOffset = -1; + for (Sample sample : track.getSamples()) { + long offset = sample.getOffset(); + if (lastOffset != -1 && lastOffset != offset) { + lastOffset = -1; + } + if (lastOffset == -1) { + chunksOffsets.add(offset); + } + lastOffset = offset + sample.getSize(); + } + long[] chunkOffsetsLong = new long[chunksOffsets.size()]; + for (int a = 0; a < chunksOffsets.size(); a++) { + chunkOffsetsLong[a] = chunksOffsets.get(a); + } + + StaticChunkOffsetBox stco = new StaticChunkOffsetBox(); + stco.setChunkOffsets(chunkOffsetsLong); + stbl.addBox(stco); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/Mp4Movie.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/Mp4Movie.java new file mode 100644 index 00000000..81dc67d9 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/Mp4Movie.java @@ -0,0 +1,81 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger.video; + +import android.annotation.TargetApi; +import android.media.MediaCodec; +import android.media.MediaFormat; + +import com.googlecode.mp4parser.util.Matrix; + +import java.io.File; +import java.util.ArrayList; + +@TargetApi(16) +public class Mp4Movie { + private Matrix matrix = Matrix.ROTATE_0; + private ArrayList tracks = new ArrayList<>(); + private File cacheFile; + private int width; + private int height; + + public Matrix getMatrix() { + return matrix; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public void setCacheFile(File file) { + cacheFile = file; + } + + public void setRotation(int angle) { + if (angle == 0) { + matrix = Matrix.ROTATE_0; + } else if (angle == 90) { + matrix = Matrix.ROTATE_90; + } else if (angle == 180) { + matrix = Matrix.ROTATE_180; + } else if (angle == 270) { + matrix = Matrix.ROTATE_270; + } + } + + public void setSize(int w, int h) { + width = w; + height = h; + } + + public ArrayList getTracks() { + return tracks; + } + + public File getCacheFile() { + return cacheFile; + } + + public void addSample(int trackIndex, long offset, MediaCodec.BufferInfo bufferInfo) throws Exception { + if (trackIndex < 0 || trackIndex >= tracks.size()) { + return; + } + Track track = tracks.get(trackIndex); + track.addSample(offset, bufferInfo); + } + + public int addTrack(MediaFormat mediaFormat, boolean isAudio) throws Exception { + tracks.add(new Track(tracks.size(), mediaFormat, isAudio)); + return tracks.size() - 1; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/OutputSurface.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/OutputSurface.java new file mode 100644 index 00000000..7ec7079f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/OutputSurface.java @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.video; + +import android.annotation.TargetApi; +import android.graphics.SurfaceTexture; +import android.opengl.GLES20; +import android.view.Surface; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.egl.EGLContext; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; + +@TargetApi(16) +public class OutputSurface implements SurfaceTexture.OnFrameAvailableListener { + + private static final int EGL_OPENGL_ES2_BIT = 4; + private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + private EGL10 mEGL; + private EGLDisplay mEGLDisplay = null; + private EGLContext mEGLContext = null; + private EGLSurface mEGLSurface = null; + private SurfaceTexture mSurfaceTexture; + private Surface mSurface; + private final Object mFrameSyncObject = new Object(); + private boolean mFrameAvailable; + private TextureRenderer mTextureRender; + private int mWidth; + private int mHeight; + private int rotateRender = 0; + private ByteBuffer mPixelBuf; + + public OutputSurface(int width, int height, int rotate) { + if (width <= 0 || height <= 0) { + throw new IllegalArgumentException(); + } + mWidth = width; + mHeight = height; + rotateRender = rotate; + mPixelBuf = ByteBuffer.allocateDirect(mWidth * mHeight * 4); + mPixelBuf.order(ByteOrder.LITTLE_ENDIAN); + eglSetup(width, height); + makeCurrent(); + setup(); + } + + public OutputSurface() { + setup(); + } + + private void setup() { + mTextureRender = new TextureRenderer(rotateRender); + mTextureRender.surfaceCreated(); + mSurfaceTexture = new SurfaceTexture(mTextureRender.getTextureId()); + mSurfaceTexture.setOnFrameAvailableListener(this); + mSurface = new Surface(mSurfaceTexture); + } + + private void eglSetup(int width, int height) { + mEGL = (EGL10) EGLContext.getEGL(); + mEGLDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + + if (mEGLDisplay == EGL10.EGL_NO_DISPLAY) { + throw new RuntimeException("unable to get EGL10 display"); + } + + if (!mEGL.eglInitialize(mEGLDisplay, null)) { + mEGLDisplay = null; + throw new RuntimeException("unable to initialize EGL10"); + } + + int[] attribList = { + EGL10.EGL_RED_SIZE, 8, + EGL10.EGL_GREEN_SIZE, 8, + EGL10.EGL_BLUE_SIZE, 8, + EGL10.EGL_ALPHA_SIZE, 8, + EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT, + EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL10.EGL_NONE + }; + EGLConfig[] configs = new EGLConfig[1]; + int[] numConfigs = new int[1]; + if (!mEGL.eglChooseConfig(mEGLDisplay, attribList, configs, configs.length, numConfigs)) { + throw new RuntimeException("unable to find RGB888+pbuffer EGL config"); + } + int[] attrib_list = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL10.EGL_NONE + }; + mEGLContext = mEGL.eglCreateContext(mEGLDisplay, configs[0], EGL10.EGL_NO_CONTEXT, attrib_list); + checkEglError("eglCreateContext"); + if (mEGLContext == null) { + throw new RuntimeException("null context"); + } + int[] surfaceAttribs = { + EGL10.EGL_WIDTH, width, + EGL10.EGL_HEIGHT, height, + EGL10.EGL_NONE + }; + mEGLSurface = mEGL.eglCreatePbufferSurface(mEGLDisplay, configs[0], surfaceAttribs); + checkEglError("eglCreatePbufferSurface"); + if (mEGLSurface == null) { + throw new RuntimeException("surface was null"); + } + } + + public void release() { + if (mEGL != null) { + if (mEGL.eglGetCurrentContext().equals(mEGLContext)) { + mEGL.eglMakeCurrent(mEGLDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + } + mEGL.eglDestroySurface(mEGLDisplay, mEGLSurface); + mEGL.eglDestroyContext(mEGLDisplay, mEGLContext); + } + mSurface.release(); + mEGLDisplay = null; + mEGLContext = null; + mEGLSurface = null; + mEGL = null; + mTextureRender = null; + mSurface = null; + mSurfaceTexture = null; + } + + public void makeCurrent() { + if (mEGL == null) { + throw new RuntimeException("not configured for makeCurrent"); + } + checkEglError("before makeCurrent"); + if (!mEGL.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext)) { + throw new RuntimeException("eglMakeCurrent failed"); + } + } + + public Surface getSurface() { + return mSurface; + } + + public void changeFragmentShader(String fragmentShader) { + mTextureRender.changeFragmentShader(fragmentShader); + } + + public void awaitNewImage() { + final int TIMEOUT_MS = 2500; + synchronized (mFrameSyncObject) { + while (!mFrameAvailable) { + try { + mFrameSyncObject.wait(TIMEOUT_MS); + if (!mFrameAvailable) { + throw new RuntimeException("Surface frame wait timed out"); + } + } catch (InterruptedException ie) { + throw new RuntimeException(ie); + } + } + mFrameAvailable = false; + } + mTextureRender.checkGlError("before updateTexImage"); + mSurfaceTexture.updateTexImage(); + } + + public void drawImage(boolean invert) { + mTextureRender.drawFrame(mSurfaceTexture, invert); + } + + @Override + public void onFrameAvailable(SurfaceTexture st) { + synchronized (mFrameSyncObject) { + if (mFrameAvailable) { + throw new RuntimeException("mFrameAvailable already set, frame could be dropped"); + } + mFrameAvailable = true; + mFrameSyncObject.notifyAll(); + } + } + + public ByteBuffer getFrame() { + mPixelBuf.rewind(); + GLES20.glReadPixels(0, 0, mWidth, mHeight, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, mPixelBuf); + return mPixelBuf; + } + + private void checkEglError(String msg) { + if (mEGL.eglGetError() != EGL10.EGL_SUCCESS) { + throw new RuntimeException("EGL error encountered (see log)"); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/Sample.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/Sample.java new file mode 100644 index 00000000..d73c5b29 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/Sample.java @@ -0,0 +1,27 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger.video; + +public class Sample { + private long offset = 0; + private long size = 0; + + public Sample(long offset, long size) { + this.offset = offset; + this.size = size; + } + + public long getOffset() { + return offset; + } + + public long getSize() { + return size; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java new file mode 100644 index 00000000..6379ef99 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/TextureRenderer.java @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.video; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; + +import android.annotation.TargetApi; +import android.graphics.SurfaceTexture; +import android.opengl.GLES11Ext; +import android.opengl.GLES20; +import android.opengl.Matrix; + +@TargetApi(16) +public class TextureRenderer { + + private static final int FLOAT_SIZE_BYTES = 4; + private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES; + private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0; + private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3; + private static final float[] mTriangleVerticesData = { + -1.0f, -1.0f, 0, 0.f, 0.f, + 1.0f, -1.0f, 0, 1.f, 0.f, + -1.0f, 1.0f, 0, 0.f, 1.f, + 1.0f, 1.0f, 0, 1.f, 1.f, + }; + private FloatBuffer mTriangleVertices; + + private static final String VERTEX_SHADER = + "uniform mat4 uMVPMatrix;\n" + + "uniform mat4 uSTMatrix;\n" + + "attribute vec4 aPosition;\n" + + "attribute vec4 aTextureCoord;\n" + + "varying vec2 vTextureCoord;\n" + + "void main() {\n" + + " gl_Position = uMVPMatrix * aPosition;\n" + + " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" + + "}\n"; + + private static final String FRAGMENT_SHADER = + "#extension GL_OES_EGL_image_external : require\n" + + "precision mediump float;\n" + + "varying vec2 vTextureCoord;\n" + + "uniform samplerExternalOES sTexture;\n" + + "void main() {\n" + + " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" + + "}\n"; + + private float[] mMVPMatrix = new float[16]; + private float[] mSTMatrix = new float[16]; + private int mProgram; + private int mTextureID = -12345; + private int muMVPMatrixHandle; + private int muSTMatrixHandle; + private int maPositionHandle; + private int maTextureHandle; + private int rotationAngle = 0; + + public TextureRenderer(int rotation) { + rotationAngle = rotation; + mTriangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer(); + mTriangleVertices.put(mTriangleVerticesData).position(0); + Matrix.setIdentityM(mSTMatrix, 0); + } + + public int getTextureId() { + return mTextureID; + } + + public void drawFrame(SurfaceTexture st, boolean invert) { + checkGlError("onDrawFrame start"); + st.getTransformMatrix(mSTMatrix); + + if (invert) { + mSTMatrix[5] = -mSTMatrix[5]; + mSTMatrix[13] = 1.0f - mSTMatrix[13]; + } + + GLES20.glUseProgram(mProgram); + checkGlError("glUseProgram"); + GLES20.glActiveTexture(GLES20.GL_TEXTURE0); + GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID); + mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET); + GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices); + checkGlError("glVertexAttribPointer maPosition"); + GLES20.glEnableVertexAttribArray(maPositionHandle); + checkGlError("glEnableVertexAttribArray maPositionHandle"); + mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET); + GLES20.glVertexAttribPointer(maTextureHandle, 2, GLES20.GL_FLOAT, false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices); + checkGlError("glVertexAttribPointer maTextureHandle"); + GLES20.glEnableVertexAttribArray(maTextureHandle); + checkGlError("glEnableVertexAttribArray maTextureHandle"); + GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0); + GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0); + GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); + checkGlError("glDrawArrays"); + GLES20.glFinish(); + } + + public void surfaceCreated() { + mProgram = createProgram(VERTEX_SHADER, FRAGMENT_SHADER); + if (mProgram == 0) { + throw new RuntimeException("failed creating program"); + } + maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition"); + checkGlError("glGetAttribLocation aPosition"); + if (maPositionHandle == -1) { + throw new RuntimeException("Could not get attrib location for aPosition"); + } + maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord"); + checkGlError("glGetAttribLocation aTextureCoord"); + if (maTextureHandle == -1) { + throw new RuntimeException("Could not get attrib location for aTextureCoord"); + } + muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix"); + checkGlError("glGetUniformLocation uMVPMatrix"); + if (muMVPMatrixHandle == -1) { + throw new RuntimeException("Could not get attrib location for uMVPMatrix"); + } + muSTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix"); + checkGlError("glGetUniformLocation uSTMatrix"); + if (muSTMatrixHandle == -1) { + throw new RuntimeException("Could not get attrib location for uSTMatrix"); + } + int[] textures = new int[1]; + GLES20.glGenTextures(1, textures, 0); + mTextureID = textures[0]; + GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTextureID); + checkGlError("glBindTexture mTextureID"); + GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); + GLES20.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); + GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE); + GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE); + checkGlError("glTexParameter"); + + Matrix.setIdentityM(mMVPMatrix, 0); + if (rotationAngle != 0) { + Matrix.rotateM(mMVPMatrix, 0, rotationAngle, 0, 0, 1); + } + } + + public void changeFragmentShader(String fragmentShader) { + GLES20.glDeleteProgram(mProgram); + mProgram = createProgram(VERTEX_SHADER, fragmentShader); + if (mProgram == 0) { + throw new RuntimeException("failed creating program"); + } + } + + private int loadShader(int shaderType, String source) { + int shader = GLES20.glCreateShader(shaderType); + checkGlError("glCreateShader type=" + shaderType); + GLES20.glShaderSource(shader, source); + GLES20.glCompileShader(shader); + int[] compiled = new int[1]; + GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0); + if (compiled[0] == 0) { + GLES20.glDeleteShader(shader); + shader = 0; + } + return shader; + } + + private int createProgram(String vertexSource, String fragmentSource) { + int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource); + if (vertexShader == 0) { + return 0; + } + int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource); + if (pixelShader == 0) { + return 0; + } + int program = GLES20.glCreateProgram(); + checkGlError("glCreateProgram"); + if (program == 0) { + return 0; + } + GLES20.glAttachShader(program, vertexShader); + checkGlError("glAttachShader"); + GLES20.glAttachShader(program, pixelShader); + checkGlError("glAttachShader"); + GLES20.glLinkProgram(program); + int[] linkStatus = new int[1]; + GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0); + if (linkStatus[0] != GLES20.GL_TRUE) { + GLES20.glDeleteProgram(program); + program = 0; + } + return program; + } + + public void checkGlError(String op) { + int error; + if ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { + throw new RuntimeException(op + ": glError " + error); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/video/Track.java b/TMessagesProj/src/main/java/org/telegram/messenger/video/Track.java new file mode 100644 index 00000000..22762d7d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/video/Track.java @@ -0,0 +1,264 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.messenger.video; + +import android.annotation.TargetApi; +import android.media.MediaCodec; +import android.media.MediaFormat; + +import com.coremedia.iso.boxes.AbstractMediaHeaderBox; +import com.coremedia.iso.boxes.SampleDescriptionBox; +import com.coremedia.iso.boxes.SoundMediaHeaderBox; +import com.coremedia.iso.boxes.VideoMediaHeaderBox; +import com.mp4parser.iso14496.part15.AvcConfigurationBox; +import com.coremedia.iso.boxes.sampleentry.AudioSampleEntry; +import com.coremedia.iso.boxes.sampleentry.VisualSampleEntry; +import com.googlecode.mp4parser.boxes.mp4.ESDescriptorBox; +import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.AudioSpecificConfig; +import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.DecoderConfigDescriptor; +import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.ESDescriptor; +import com.googlecode.mp4parser.boxes.mp4.objectdescriptors.SLConfigDescriptor; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +@TargetApi(16) +public class Track { + private long trackId = 0; + private ArrayList samples = new ArrayList<>(); + private long duration = 0; + private String handler; + private AbstractMediaHeaderBox headerBox = null; + private SampleDescriptionBox sampleDescriptionBox = null; + private LinkedList syncSamples = null; + private int timeScale; + private Date creationTime = new Date(); + private int height; + private int width; + private float volume = 0; + private ArrayList sampleDurations = new ArrayList<>(); + private boolean isAudio = false; + private static Map samplingFrequencyIndexMap = new HashMap<>(); + private long lastPresentationTimeUs = 0; + private boolean first = true; + + static { + samplingFrequencyIndexMap.put(96000, 0x0); + samplingFrequencyIndexMap.put(88200, 0x1); + samplingFrequencyIndexMap.put(64000, 0x2); + samplingFrequencyIndexMap.put(48000, 0x3); + samplingFrequencyIndexMap.put(44100, 0x4); + samplingFrequencyIndexMap.put(32000, 0x5); + samplingFrequencyIndexMap.put(24000, 0x6); + samplingFrequencyIndexMap.put(22050, 0x7); + samplingFrequencyIndexMap.put(16000, 0x8); + samplingFrequencyIndexMap.put(12000, 0x9); + samplingFrequencyIndexMap.put(11025, 0xa); + samplingFrequencyIndexMap.put(8000, 0xb); + } + + public Track(int id, MediaFormat format, boolean audio) throws Exception { + trackId = id; + isAudio = audio; + if (!isAudio) { + sampleDurations.add((long) 3015); + duration = 3015; + width = format.getInteger(MediaFormat.KEY_WIDTH); + height = format.getInteger(MediaFormat.KEY_HEIGHT); + timeScale = 90000; + syncSamples = new LinkedList<>(); + handler = "vide"; + headerBox = new VideoMediaHeaderBox(); + sampleDescriptionBox = new SampleDescriptionBox(); + String mime = format.getString(MediaFormat.KEY_MIME); + if (mime.equals("video/avc")) { + VisualSampleEntry visualSampleEntry = new VisualSampleEntry("avc1"); + visualSampleEntry.setDataReferenceIndex(1); + visualSampleEntry.setDepth(24); + visualSampleEntry.setFrameCount(1); + visualSampleEntry.setHorizresolution(72); + visualSampleEntry.setVertresolution(72); + visualSampleEntry.setWidth(width); + visualSampleEntry.setHeight(height); + + AvcConfigurationBox avcConfigurationBox = new AvcConfigurationBox(); + + if (format.getByteBuffer("csd-0") != null) { + ArrayList spsArray = new ArrayList<>(); + ByteBuffer spsBuff = format.getByteBuffer("csd-0"); + spsBuff.position(4); + byte[] spsBytes = new byte[spsBuff.remaining()]; + spsBuff.get(spsBytes); + spsArray.add(spsBytes); + + ArrayList ppsArray = new ArrayList<>(); + ByteBuffer ppsBuff = format.getByteBuffer("csd-1"); + ppsBuff.position(4); + byte[] ppsBytes = new byte[ppsBuff.remaining()]; + ppsBuff.get(ppsBytes); + ppsArray.add(ppsBytes); + avcConfigurationBox.setSequenceParameterSets(spsArray); + avcConfigurationBox.setPictureParameterSets(ppsArray); + } + + avcConfigurationBox.setAvcLevelIndication(13); + avcConfigurationBox.setAvcProfileIndication(100); + avcConfigurationBox.setBitDepthLumaMinus8(-1); + avcConfigurationBox.setBitDepthChromaMinus8(-1); + avcConfigurationBox.setChromaFormat(-1); + avcConfigurationBox.setConfigurationVersion(1); + avcConfigurationBox.setLengthSizeMinusOne(3); + avcConfigurationBox.setProfileCompatibility(0); + + visualSampleEntry.addBox(avcConfigurationBox); + sampleDescriptionBox.addBox(visualSampleEntry); + } else if (mime.equals("video/mp4v")) { + VisualSampleEntry visualSampleEntry = new VisualSampleEntry("mp4v"); + visualSampleEntry.setDataReferenceIndex(1); + visualSampleEntry.setDepth(24); + visualSampleEntry.setFrameCount(1); + visualSampleEntry.setHorizresolution(72); + visualSampleEntry.setVertresolution(72); + visualSampleEntry.setWidth(width); + visualSampleEntry.setHeight(height); + + sampleDescriptionBox.addBox(visualSampleEntry); + } + } else { + sampleDurations.add((long) 1024); + duration = 1024; + volume = 1; + timeScale = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); + handler = "soun"; + headerBox = new SoundMediaHeaderBox(); + sampleDescriptionBox = new SampleDescriptionBox(); + AudioSampleEntry audioSampleEntry = new AudioSampleEntry("mp4a"); + audioSampleEntry.setChannelCount(format.getInteger(MediaFormat.KEY_CHANNEL_COUNT)); + audioSampleEntry.setSampleRate(format.getInteger(MediaFormat.KEY_SAMPLE_RATE)); + audioSampleEntry.setDataReferenceIndex(1); + audioSampleEntry.setSampleSize(16); + + ESDescriptorBox esds = new ESDescriptorBox(); + ESDescriptor descriptor = new ESDescriptor(); + descriptor.setEsId(0); + + SLConfigDescriptor slConfigDescriptor = new SLConfigDescriptor(); + slConfigDescriptor.setPredefined(2); + descriptor.setSlConfigDescriptor(slConfigDescriptor); + + DecoderConfigDescriptor decoderConfigDescriptor = new DecoderConfigDescriptor(); + decoderConfigDescriptor.setObjectTypeIndication(0x40); + decoderConfigDescriptor.setStreamType(5); + decoderConfigDescriptor.setBufferSizeDB(1536); + decoderConfigDescriptor.setMaxBitRate(96000); + decoderConfigDescriptor.setAvgBitRate(96000); + + AudioSpecificConfig audioSpecificConfig = new AudioSpecificConfig(); + audioSpecificConfig.setAudioObjectType(2); + audioSpecificConfig.setSamplingFrequencyIndex(samplingFrequencyIndexMap.get((int) audioSampleEntry.getSampleRate())); + audioSpecificConfig.setChannelConfiguration(audioSampleEntry.getChannelCount()); + decoderConfigDescriptor.setAudioSpecificInfo(audioSpecificConfig); + + descriptor.setDecoderConfigDescriptor(decoderConfigDescriptor); + + ByteBuffer data = descriptor.serialize(); + esds.setEsDescriptor(descriptor); + esds.setData(data); + audioSampleEntry.addBox(esds); + sampleDescriptionBox.addBox(audioSampleEntry); + } + } + + public long getTrackId() { + return trackId; + } + + public void addSample(long offset, MediaCodec.BufferInfo bufferInfo) { + long delta = bufferInfo.presentationTimeUs - lastPresentationTimeUs; + if (delta < 0) { + return; + } + boolean isSyncFrame = !isAudio && (bufferInfo.flags & MediaCodec.BUFFER_FLAG_SYNC_FRAME) != 0; + samples.add(new Sample(offset, bufferInfo.size)); + if (syncSamples != null && isSyncFrame) { + syncSamples.add(samples.size()); + } + + delta = (delta * timeScale + 500000L) / 1000000L; + lastPresentationTimeUs = bufferInfo.presentationTimeUs; + if (!first) { + sampleDurations.add(sampleDurations.size() - 1, delta); + duration += delta; + } + first = false; + } + + public ArrayList getSamples() { + return samples; + } + + public long getDuration() { + return duration; + } + + public String getHandler() { + return handler; + } + + public AbstractMediaHeaderBox getMediaHeaderBox() { + return headerBox; + } + + public SampleDescriptionBox getSampleDescriptionBox() { + return sampleDescriptionBox; + } + + public long[] getSyncSamples() { + if (syncSamples == null || syncSamples.isEmpty()) { + return null; + } + long[] returns = new long[syncSamples.size()]; + for (int i = 0; i < syncSamples.size(); i++) { + returns[i] = syncSamples.get(i); + } + return returns; + } + + public int getTimeScale() { + return timeScale; + } + + public Date getCreationTime() { + return creationTime; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public float getVolume() { + return volume; + } + + public ArrayList getSampleDurations() { + return sampleDurations; + } + + public boolean isAudio() { + return isAudio; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/AuthFailureError.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/AuthFailureError.java new file mode 100644 index 00000000..30d2ec1a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/AuthFailureError.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +import android.content.Intent; + +/** + * Error indicating that there was an authentication failure when performing a Request. + */ +@SuppressWarnings("serial") +public class AuthFailureError extends VolleyError { + /** An intent that can be used to resolve this exception. (Brings up the password dialog.) */ + private Intent mResolutionIntent; + + public AuthFailureError() { } + + public AuthFailureError(Intent intent) { + mResolutionIntent = intent; + } + + public AuthFailureError(NetworkResponse response) { + super(response); + } + + public AuthFailureError(String message) { + super(message); + } + + public AuthFailureError(String message, Exception reason) { + super(message, reason); + } + + public Intent getResolutionIntent() { + return mResolutionIntent; + } + + @Override + public String getMessage() { + if (mResolutionIntent != null) { + return "User needs to (re)enter credentials."; + } + return super.getMessage(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/Cache.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/Cache.java new file mode 100644 index 00000000..619f69b2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/Cache.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +import java.util.Collections; +import java.util.Map; + +/** + * An interface for a cache keyed by a String with a byte array as data. + */ +public interface Cache { + /** + * Retrieves an entry from the cache. + * @param key Cache key + * @return An {@link Entry} or null in the event of a cache miss + */ + public Entry get(String key); + + /** + * Adds or replaces an entry to the cache. + * @param key Cache key + * @param entry Data to store and metadata for cache coherency, TTL, etc. + */ + public void put(String key, Entry entry); + + /** + * Performs any potentially long-running actions needed to initialize the cache; + * will be called from a worker thread. + */ + public void initialize(); + + /** + * Invalidates an entry in the cache. + * @param key Cache key + * @param fullExpire True to fully expire the entry, false to soft expire + */ + public void invalidate(String key, boolean fullExpire); + + /** + * Removes an entry from the cache. + * @param key Cache key + */ + public void remove(String key); + + /** + * Empties the cache. + */ + public void clear(); + + /** + * Data and metadata for an entry returned by the cache. + */ + public static class Entry { + /** The data returned from cache. */ + public byte[] data; + + /** ETag for cache coherency. */ + public String etag; + + /** Date of this response as reported by the server. */ + public long serverDate; + + /** The last modified date for the requested object. */ + public long lastModified; + + /** TTL for this record. */ + public long ttl; + + /** Soft TTL for this record. */ + public long softTtl; + + /** Immutable response headers as received from server; must be non-null. */ + public Map responseHeaders = Collections.emptyMap(); + + /** True if the entry is expired. */ + public boolean isExpired() { + return this.ttl < System.currentTimeMillis(); + } + + /** True if a refresh is needed from the original data source. */ + public boolean refreshNeeded() { + return this.softTtl < System.currentTimeMillis(); + } + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/CacheDispatcher.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/CacheDispatcher.java new file mode 100644 index 00000000..5809df81 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/CacheDispatcher.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +import android.os.Process; + +import java.util.concurrent.BlockingQueue; + +/** + * Provides a thread for performing cache triage on a queue of requests. + * + * Requests added to the specified cache queue are resolved from cache. + * Any deliverable response is posted back to the caller via a + * {@link ResponseDelivery}. Cache misses and responses that require + * refresh are enqueued on the specified network queue for processing + * by a {@link NetworkDispatcher}. + */ +public class CacheDispatcher extends Thread { + + private static final boolean DEBUG = VolleyLog.DEBUG; + + /** The queue of requests coming in for triage. */ + private final BlockingQueue> mCacheQueue; + + /** The queue of requests going out to the network. */ + private final BlockingQueue> mNetworkQueue; + + /** The cache to read from. */ + private final Cache mCache; + + /** For posting responses. */ + private final ResponseDelivery mDelivery; + + /** Used for telling us to die. */ + private volatile boolean mQuit = false; + + /** + * Creates a new cache triage dispatcher thread. You must call {@link #start()} + * in order to begin processing. + * + * @param cacheQueue Queue of incoming requests for triage + * @param networkQueue Queue to post requests that require network to + * @param cache Cache interface to use for resolution + * @param delivery Delivery interface to use for posting responses + */ + public CacheDispatcher( + BlockingQueue> cacheQueue, BlockingQueue> networkQueue, + Cache cache, ResponseDelivery delivery) { + mCacheQueue = cacheQueue; + mNetworkQueue = networkQueue; + mCache = cache; + mDelivery = delivery; + } + + /** + * Forces this dispatcher to quit immediately. If any requests are still in + * the queue, they are not guaranteed to be processed. + */ + public void quit() { + mQuit = true; + interrupt(); + } + + @Override + public void run() { + if (DEBUG) VolleyLog.v("start new dispatcher"); + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + + // Make a blocking call to initialize the cache. + mCache.initialize(); + + while (true) { + try { + // Get a request from the cache triage queue, blocking until + // at least one is available. + final Request request = mCacheQueue.take(); + request.addMarker("cache-queue-take"); + + // If the request has been canceled, don't bother dispatching it. + if (request.isCanceled()) { + request.finish("cache-discard-canceled"); + continue; + } + + // Attempt to retrieve this item from cache. + Cache.Entry entry = mCache.get(request.getCacheKey()); + if (entry == null) { + request.addMarker("cache-miss"); + // Cache miss; send off to the network dispatcher. + mNetworkQueue.put(request); + continue; + } + + // If it is completely expired, just send it to the network. + if (entry.isExpired()) { + request.addMarker("cache-hit-expired"); + request.setCacheEntry(entry); + mNetworkQueue.put(request); + continue; + } + + // We have a cache hit; parse its data for delivery back to the request. + request.addMarker("cache-hit"); + Response response = request.parseNetworkResponse( + new NetworkResponse(entry.data, entry.responseHeaders)); + request.addMarker("cache-hit-parsed"); + + if (!entry.refreshNeeded()) { + // Completely unexpired cache hit. Just deliver the response. + mDelivery.postResponse(request, response); + } else { + // Soft-expired cache hit. We can deliver the cached response, + // but we need to also send the request to the network for + // refreshing. + request.addMarker("cache-hit-refresh-needed"); + request.setCacheEntry(entry); + + // Mark the response as intermediate. + response.intermediate = true; + + // Post the intermediate response back to the user and have + // the delivery then forward the request along to the network. + mDelivery.postResponse(request, response, new Runnable() { + @Override + public void run() { + try { + mNetworkQueue.put(request); + } catch (InterruptedException e) { + // Not much we can do about this. + } + } + }); + } + + } catch (InterruptedException e) { + // We may have been interrupted because it was time to quit. + if (mQuit) { + return; + } + continue; + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/DefaultRetryPolicy.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/DefaultRetryPolicy.java new file mode 100644 index 00000000..28e0059f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/DefaultRetryPolicy.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +/** + * Default retry policy for requests. + */ +public class DefaultRetryPolicy implements RetryPolicy { + /** The current timeout in milliseconds. */ + private int mCurrentTimeoutMs; + + /** The current retry count. */ + private int mCurrentRetryCount; + + /** The maximum number of attempts. */ + private final int mMaxNumRetries; + + /** The backoff multiplier for the policy. */ + private final float mBackoffMultiplier; + + /** The default socket timeout in milliseconds */ + public static final int DEFAULT_TIMEOUT_MS = 2500; + + /** The default number of retries */ + public static final int DEFAULT_MAX_RETRIES = 1; + + /** The default backoff multiplier */ + public static final float DEFAULT_BACKOFF_MULT = 1f; + + /** + * Constructs a new retry policy using the default timeouts. + */ + public DefaultRetryPolicy() { + this(DEFAULT_TIMEOUT_MS, DEFAULT_MAX_RETRIES, DEFAULT_BACKOFF_MULT); + } + + /** + * Constructs a new retry policy. + * @param initialTimeoutMs The initial timeout for the policy. + * @param maxNumRetries The maximum number of retries. + * @param backoffMultiplier Backoff multiplier for the policy. + */ + public DefaultRetryPolicy(int initialTimeoutMs, int maxNumRetries, float backoffMultiplier) { + mCurrentTimeoutMs = initialTimeoutMs; + mMaxNumRetries = maxNumRetries; + mBackoffMultiplier = backoffMultiplier; + } + + /** + * Returns the current timeout. + */ + @Override + public int getCurrentTimeout() { + return mCurrentTimeoutMs; + } + + /** + * Returns the current retry count. + */ + @Override + public int getCurrentRetryCount() { + return mCurrentRetryCount; + } + + /** + * Returns the backoff multiplier for the policy. + */ + public float getBackoffMultiplier() { + return mBackoffMultiplier; + } + + /** + * Prepares for the next retry by applying a backoff to the timeout. + * @param error The error code of the last attempt. + */ + @Override + public void retry(VolleyError error) throws VolleyError { + mCurrentRetryCount++; + mCurrentTimeoutMs += (mCurrentTimeoutMs * mBackoffMultiplier); + if (!hasAttemptRemaining()) { + throw error; + } + } + + /** + * Returns true if this policy has attempts remaining, false otherwise. + */ + protected boolean hasAttemptRemaining() { + return mCurrentRetryCount <= mMaxNumRetries; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/ExecutorDelivery.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/ExecutorDelivery.java new file mode 100644 index 00000000..790d190c --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/ExecutorDelivery.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +import android.os.Handler; + +import java.util.concurrent.Executor; + +/** + * Delivers responses and errors. + */ +public class ExecutorDelivery implements ResponseDelivery { + /** Used for posting responses, typically to the main thread. */ + private final Executor mResponsePoster; + + /** + * Creates a new response delivery interface. + * @param handler {@link Handler} to post responses on + */ + public ExecutorDelivery(final Handler handler) { + // Make an Executor that just wraps the handler. + mResponsePoster = new Executor() { + @Override + public void execute(Runnable command) { + handler.post(command); + } + }; + } + + /** + * Creates a new response delivery interface, mockable version + * for testing. + * @param executor For running delivery tasks + */ + public ExecutorDelivery(Executor executor) { + mResponsePoster = executor; + } + + @Override + public void postResponse(Request request, Response response) { + postResponse(request, response, null); + } + + @Override + public void postResponse(Request request, Response response, Runnable runnable) { + request.markDelivered(); + request.addMarker("post-response"); + mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable)); + } + + @Override + public void postError(Request request, VolleyError error) { + request.addMarker("post-error"); + Response response = Response.error(error); + mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, null)); + } + + /** + * A Runnable used for delivering network responses to a listener on the + * main thread. + */ + @SuppressWarnings("rawtypes") + private class ResponseDeliveryRunnable implements Runnable { + private final Request mRequest; + private final Response mResponse; + private final Runnable mRunnable; + + public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) { + mRequest = request; + mResponse = response; + mRunnable = runnable; + } + + @SuppressWarnings("unchecked") + @Override + public void run() { + // If this request has canceled, finish it and don't deliver. + if (mRequest.isCanceled()) { + mRequest.finish("canceled-at-delivery"); + return; + } + + // Deliver a normal response or error, depending. + if (mResponse.isSuccess()) { + mRequest.deliverResponse(mResponse.result); + } else { + mRequest.deliverError(mResponse.error); + } + + // If this is an intermediate response, add a marker, otherwise we're done + // and the request can be finished. + if (mResponse.intermediate) { + mRequest.addMarker("intermediate-response"); + } else { + mRequest.finish("done"); + } + + // If we have been provided a post-delivery runnable, run it. + if (mRunnable != null) { + mRunnable.run(); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/Network.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/Network.java new file mode 100644 index 00000000..561c0414 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/Network.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +/** + * An interface for performing requests. + */ +public interface Network { + /** + * Performs the specified request. + * @param request Request to process + * @return A {@link NetworkResponse} with data and caching metadata; will never be null + * @throws VolleyError on errors + */ + public NetworkResponse performRequest(Request request) throws VolleyError; +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/NetworkDispatcher.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/NetworkDispatcher.java new file mode 100644 index 00000000..b16c3aaa --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/NetworkDispatcher.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +import android.annotation.TargetApi; +import android.net.TrafficStats; +import android.os.Build; +import android.os.Process; +import android.os.SystemClock; + +import java.util.concurrent.BlockingQueue; + +/** + * Provides a thread for performing network dispatch from a queue of requests. + * + * Requests added to the specified queue are processed from the network via a + * specified {@link Network} interface. Responses are committed to cache, if + * eligible, using a specified {@link Cache} interface. Valid responses and + * errors are posted back to the caller via a {@link ResponseDelivery}. + */ +public class NetworkDispatcher extends Thread { + /** The queue of requests to service. */ + private final BlockingQueue> mQueue; + /** The network interface for processing requests. */ + private final Network mNetwork; + /** The cache to write to. */ + private final Cache mCache; + /** For posting responses and errors. */ + private final ResponseDelivery mDelivery; + /** Used for telling us to die. */ + private volatile boolean mQuit = false; + + /** + * Creates a new network dispatcher thread. You must call {@link #start()} + * in order to begin processing. + * + * @param queue Queue of incoming requests for triage + * @param network Network interface to use for performing requests + * @param cache Cache interface to use for writing responses to cache + * @param delivery Delivery interface to use for posting responses + */ + public NetworkDispatcher(BlockingQueue> queue, + Network network, Cache cache, + ResponseDelivery delivery) { + mQueue = queue; + mNetwork = network; + mCache = cache; + mDelivery = delivery; + } + + /** + * Forces this dispatcher to quit immediately. If any requests are still in + * the queue, they are not guaranteed to be processed. + */ + public void quit() { + mQuit = true; + interrupt(); + } + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + private void addTrafficStatsTag(Request request) { + // Tag the request (if API >= 14) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + TrafficStats.setThreadStatsTag(request.getTrafficStatsTag()); + } + } + + @Override + public void run() { + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + while (true) { + long startTimeMs = SystemClock.elapsedRealtime(); + Request request; + try { + // Take a request from the queue. + request = mQueue.take(); + } catch (InterruptedException e) { + // We may have been interrupted because it was time to quit. + if (mQuit) { + return; + } + continue; + } + + try { + request.addMarker("network-queue-take"); + + // If the request was cancelled already, do not perform the + // network request. + if (request.isCanceled()) { + request.finish("network-discard-cancelled"); + continue; + } + + addTrafficStatsTag(request); + + // Perform the network request. + NetworkResponse networkResponse = mNetwork.performRequest(request); + request.addMarker("network-http-complete"); + + // If the server returned 304 AND we delivered a response already, + // we're done -- don't deliver a second identical response. + if (networkResponse.notModified && request.hasHadResponseDelivered()) { + request.finish("not-modified"); + continue; + } + + // Parse the response here on the worker thread. + Response response = request.parseNetworkResponse(networkResponse); + request.addMarker("network-parse-complete"); + + // Write to cache if applicable. + // TODO: Only update cache metadata instead of entire record for 304s. + if (request.shouldCache() && response.cacheEntry != null) { + mCache.put(request.getCacheKey(), response.cacheEntry); + request.addMarker("network-cache-written"); + } + + // Post the response back. + request.markDelivered(); + mDelivery.postResponse(request, response); + } catch (VolleyError volleyError) { + volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); + parseAndDeliverNetworkError(request, volleyError); + } catch (Exception e) { + VolleyLog.e(e, "Unhandled exception %s", e.toString()); + VolleyError volleyError = new VolleyError(e); + volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); + mDelivery.postError(request, volleyError); + } + } + } + + private void parseAndDeliverNetworkError(Request request, VolleyError error) { + error = request.parseNetworkError(error); + mDelivery.postError(request, error); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/NetworkError.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/NetworkError.java new file mode 100644 index 00000000..3c4e2d4f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/NetworkError.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +/** + * Indicates that there was a network error when performing a Volley request. + */ +@SuppressWarnings("serial") +public class NetworkError extends VolleyError { + public NetworkError() { + super(); + } + + public NetworkError(Throwable cause) { + super(cause); + } + + public NetworkError(NetworkResponse networkResponse) { + super(networkResponse); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/NetworkResponse.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/NetworkResponse.java new file mode 100644 index 00000000..a216694b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/NetworkResponse.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +import org.apache.http.HttpStatus; + +import java.util.Collections; +import java.util.Map; + +/** + * Data and headers returned from {@link Network#performRequest(Request)}. + */ +public class NetworkResponse { + /** + * Creates a new network response. + * @param statusCode the HTTP status code + * @param data Response body + * @param headers Headers returned with this response, or null for none + * @param notModified True if the server returned a 304 and the data was already in cache + * @param networkTimeMs Round-trip network time to receive network response + */ + public NetworkResponse(int statusCode, byte[] data, Map headers, + boolean notModified, long networkTimeMs) { + this.statusCode = statusCode; + this.data = data; + this.headers = headers; + this.notModified = notModified; + this.networkTimeMs = networkTimeMs; + } + + public NetworkResponse(int statusCode, byte[] data, Map headers, + boolean notModified) { + this(statusCode, data, headers, notModified, 0); + } + + public NetworkResponse(byte[] data) { + this(HttpStatus.SC_OK, data, Collections.emptyMap(), false, 0); + } + + public NetworkResponse(byte[] data, Map headers) { + this(HttpStatus.SC_OK, data, headers, false, 0); + } + + /** The HTTP status code. */ + public final int statusCode; + + /** Raw data from this response. */ + public final byte[] data; + + /** Response headers. */ + public final Map headers; + + /** True if the server returned a 304 (Not Modified). */ + public final boolean notModified; + + /** Network roundtrip time in milliseconds. */ + public final long networkTimeMs; +} + diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/NoConnectionError.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/NoConnectionError.java new file mode 100644 index 00000000..48bb3965 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/NoConnectionError.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +/** + * Error indicating that no connection could be established when performing a Volley request. + */ +@SuppressWarnings("serial") +public class NoConnectionError extends NetworkError { + public NoConnectionError() { + super(); + } + + public NoConnectionError(Throwable reason) { + super(reason); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/ParseError.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/ParseError.java new file mode 100644 index 00000000..d70d1caa --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/ParseError.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +/** + * Indicates that the server's response could not be parsed. + */ +@SuppressWarnings("serial") +public class ParseError extends VolleyError { + public ParseError() { } + + public ParseError(NetworkResponse networkResponse) { + super(networkResponse); + } + + public ParseError(Throwable cause) { + super(cause); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/Request.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/Request.java new file mode 100644 index 00000000..472ac03d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/Request.java @@ -0,0 +1,589 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +import android.net.TrafficStats; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.text.TextUtils; + +import org.telegram.messenger.volley.VolleyLog.MarkerLog; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.Collections; +import java.util.Map; + +/** + * Base class for all network requests. + * + * @param The type of parsed response this request expects. + */ +public abstract class Request implements Comparable> { + + /** + * Default encoding for POST or PUT parameters. See {@link #getParamsEncoding()}. + */ + private static final String DEFAULT_PARAMS_ENCODING = "UTF-8"; + + /** + * Supported request methods. + */ + public interface Method { + int DEPRECATED_GET_OR_POST = -1; + int GET = 0; + int POST = 1; + int PUT = 2; + int DELETE = 3; + int HEAD = 4; + int OPTIONS = 5; + int TRACE = 6; + int PATCH = 7; + } + + /** An event log tracing the lifetime of this request; for debugging. */ + private final MarkerLog mEventLog = MarkerLog.ENABLED ? new MarkerLog() : null; + + /** + * Request method of this request. Currently supports GET, POST, PUT, DELETE, HEAD, OPTIONS, + * TRACE, and PATCH. + */ + private final int mMethod; + + /** URL of this request. */ + private final String mUrl; + + /** Default tag for {@link TrafficStats}. */ + private final int mDefaultTrafficStatsTag; + + /** Listener interface for errors. */ + private final Response.ErrorListener mErrorListener; + + /** Sequence number of this request, used to enforce FIFO ordering. */ + private Integer mSequence; + + /** The request queue this request is associated with. */ + private RequestQueue mRequestQueue; + + /** Whether or not responses to this request should be cached. */ + private boolean mShouldCache = true; + + /** Whether or not this request has been canceled. */ + private boolean mCanceled = false; + + /** Whether or not a response has been delivered for this request yet. */ + private boolean mResponseDelivered = false; + + /** The retry policy for this request. */ + private RetryPolicy mRetryPolicy; + + /** + * When a request can be retrieved from cache but must be refreshed from + * the network, the cache entry will be stored here so that in the event of + * a "Not Modified" response, we can be sure it hasn't been evicted from cache. + */ + private Cache.Entry mCacheEntry = null; + + /** An opaque token tagging this request; used for bulk cancellation. */ + private Object mTag; + + /** + * Creates a new request with the given URL and error listener. Note that + * the normal response listener is not provided here as delivery of responses + * is provided by subclasses, who have a better idea of how to deliver an + * already-parsed response. + * + * @deprecated Use {@link #Request(int, String, com.android.volley.Response.ErrorListener)}. + */ + @Deprecated + public Request(String url, Response.ErrorListener listener) { + this(Method.DEPRECATED_GET_OR_POST, url, listener); + } + + /** + * Creates a new request with the given method (one of the values from {@link Method}), + * URL, and error listener. Note that the normal response listener is not provided here as + * delivery of responses is provided by subclasses, who have a better idea of how to deliver + * an already-parsed response. + */ + public Request(int method, String url, Response.ErrorListener listener) { + mMethod = method; + mUrl = url; + mErrorListener = listener; + setRetryPolicy(new DefaultRetryPolicy()); + + mDefaultTrafficStatsTag = findDefaultTrafficStatsTag(url); + } + + /** + * Return the method for this request. Can be one of the values in {@link Method}. + */ + public int getMethod() { + return mMethod; + } + + /** + * Set a tag on this request. Can be used to cancel all requests with this + * tag by {@link RequestQueue#cancelAll(Object)}. + * + * @return This Request object to allow for chaining. + */ + public Request setTag(Object tag) { + mTag = tag; + return this; + } + + /** + * Returns this request's tag. + * @see Request#setTag(Object) + */ + public Object getTag() { + return mTag; + } + + /** + * @return this request's {@link com.android.volley.Response.ErrorListener}. + */ + public Response.ErrorListener getErrorListener() { + return mErrorListener; + } + + /** + * @return A tag for use with {@link TrafficStats#setThreadStatsTag(int)} + */ + public int getTrafficStatsTag() { + return mDefaultTrafficStatsTag; + } + + /** + * @return The hashcode of the URL's host component, or 0 if there is none. + */ + private static int findDefaultTrafficStatsTag(String url) { + if (!TextUtils.isEmpty(url)) { + Uri uri = Uri.parse(url); + if (uri != null) { + String host = uri.getHost(); + if (host != null) { + return host.hashCode(); + } + } + } + return 0; + } + + /** + * Sets the retry policy for this request. + * + * @return This Request object to allow for chaining. + */ + public Request setRetryPolicy(RetryPolicy retryPolicy) { + mRetryPolicy = retryPolicy; + return this; + } + + /** + * Adds an event to this request's event log; for debugging. + */ + public void addMarker(String tag) { + if (MarkerLog.ENABLED) { + mEventLog.add(tag, Thread.currentThread().getId()); + } + } + + /** + * Notifies the request queue that this request has finished (successfully or with error). + * + *

Also dumps all events from this request's event log; for debugging.

+ */ + void finish(final String tag) { + if (mRequestQueue != null) { + mRequestQueue.finish(this); + } + if (MarkerLog.ENABLED) { + final long threadId = Thread.currentThread().getId(); + if (Looper.myLooper() != Looper.getMainLooper()) { + // If we finish marking off of the main thread, we need to + // actually do it on the main thread to ensure correct ordering. + Handler mainThread = new Handler(Looper.getMainLooper()); + mainThread.post(new Runnable() { + @Override + public void run() { + mEventLog.add(tag, threadId); + mEventLog.finish(this.toString()); + } + }); + return; + } + + mEventLog.add(tag, threadId); + mEventLog.finish(this.toString()); + } + } + + /** + * Associates this request with the given queue. The request queue will be notified when this + * request has finished. + * + * @return This Request object to allow for chaining. + */ + public Request setRequestQueue(RequestQueue requestQueue) { + mRequestQueue = requestQueue; + return this; + } + + /** + * Sets the sequence number of this request. Used by {@link RequestQueue}. + * + * @return This Request object to allow for chaining. + */ + public final Request setSequence(int sequence) { + mSequence = sequence; + return this; + } + + /** + * Returns the sequence number of this request. + */ + public final int getSequence() { + if (mSequence == null) { + throw new IllegalStateException("getSequence called before setSequence"); + } + return mSequence; + } + + /** + * Returns the URL of this request. + */ + public String getUrl() { + return mUrl; + } + + /** + * Returns the cache key for this request. By default, this is the URL. + */ + public String getCacheKey() { + return getUrl(); + } + + /** + * Annotates this request with an entry retrieved for it from cache. + * Used for cache coherency support. + * + * @return This Request object to allow for chaining. + */ + public Request setCacheEntry(Cache.Entry entry) { + mCacheEntry = entry; + return this; + } + + /** + * Returns the annotated cache entry, or null if there isn't one. + */ + public Cache.Entry getCacheEntry() { + return mCacheEntry; + } + + /** + * Mark this request as canceled. No callback will be delivered. + */ + public void cancel() { + mCanceled = true; + } + + /** + * Returns true if this request has been canceled. + */ + public boolean isCanceled() { + return mCanceled; + } + + /** + * Returns a list of extra HTTP headers to go along with this request. Can + * throw {@link AuthFailureError} as authentication may be required to + * provide these values. + * @throws AuthFailureError In the event of auth failure + */ + public Map getHeaders() throws AuthFailureError { + return Collections.emptyMap(); + } + + /** + * Returns a Map of POST parameters to be used for this request, or null if + * a simple GET should be used. Can throw {@link AuthFailureError} as + * authentication may be required to provide these values. + * + *

Note that only one of getPostParams() and getPostBody() can return a non-null + * value.

+ * @throws AuthFailureError In the event of auth failure + * + * @deprecated Use {@link #getParams()} instead. + */ + @Deprecated + protected Map getPostParams() throws AuthFailureError { + return getParams(); + } + + /** + * Returns which encoding should be used when converting POST parameters returned by + * {@link #getPostParams()} into a raw POST body. + * + *

This controls both encodings: + *

    + *
  1. The string encoding used when converting parameter names and values into bytes prior + * to URL encoding them.
  2. + *
  3. The string encoding used when converting the URL encoded parameters into a raw + * byte array.
  4. + *
+ * + * @deprecated Use {@link #getParamsEncoding()} instead. + */ + @Deprecated + protected String getPostParamsEncoding() { + return getParamsEncoding(); + } + + /** + * @deprecated Use {@link #getBodyContentType()} instead. + */ + @Deprecated + public String getPostBodyContentType() { + return getBodyContentType(); + } + + /** + * Returns the raw POST body to be sent. + * + * @throws AuthFailureError In the event of auth failure + * + * @deprecated Use {@link #getBody()} instead. + */ + @Deprecated + public byte[] getPostBody() throws AuthFailureError { + // Note: For compatibility with legacy clients of volley, this implementation must remain + // here instead of simply calling the getBody() function because this function must + // call getPostParams() and getPostParamsEncoding() since legacy clients would have + // overridden these two member functions for POST requests. + Map postParams = getPostParams(); + if (postParams != null && postParams.size() > 0) { + return encodeParameters(postParams, getPostParamsEncoding()); + } + return null; + } + + /** + * Returns a Map of parameters to be used for a POST or PUT request. Can throw + * {@link AuthFailureError} as authentication may be required to provide these values. + * + *

Note that you can directly override {@link #getBody()} for custom data.

+ * + * @throws AuthFailureError in the event of auth failure + */ + protected Map getParams() throws AuthFailureError { + return null; + } + + /** + * Returns which encoding should be used when converting POST or PUT parameters returned by + * {@link #getParams()} into a raw POST or PUT body. + * + *

This controls both encodings: + *

    + *
  1. The string encoding used when converting parameter names and values into bytes prior + * to URL encoding them.
  2. + *
  3. The string encoding used when converting the URL encoded parameters into a raw + * byte array.
  4. + *
+ */ + protected String getParamsEncoding() { + return DEFAULT_PARAMS_ENCODING; + } + + /** + * Returns the content type of the POST or PUT body. + */ + public String getBodyContentType() { + return "application/x-www-form-urlencoded; charset=" + getParamsEncoding(); + } + + /** + * Returns the raw POST or PUT body to be sent. + * + *

By default, the body consists of the request parameters in + * application/x-www-form-urlencoded format. When overriding this method, consider overriding + * {@link #getBodyContentType()} as well to match the new body format. + * + * @throws AuthFailureError in the event of auth failure + */ + public byte[] getBody() throws AuthFailureError { + Map params = getParams(); + if (params != null && params.size() > 0) { + return encodeParameters(params, getParamsEncoding()); + } + return null; + } + + /** + * Converts params into an application/x-www-form-urlencoded encoded string. + */ + private byte[] encodeParameters(Map params, String paramsEncoding) { + StringBuilder encodedParams = new StringBuilder(); + try { + for (Map.Entry entry : params.entrySet()) { + encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding)); + encodedParams.append('='); + encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding)); + encodedParams.append('&'); + } + return encodedParams.toString().getBytes(paramsEncoding); + } catch (UnsupportedEncodingException uee) { + throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee); + } + } + + /** + * Set whether or not responses to this request should be cached. + * + * @return This Request object to allow for chaining. + */ + public final Request setShouldCache(boolean shouldCache) { + mShouldCache = shouldCache; + return this; + } + + /** + * Returns true if responses to this request should be cached. + */ + public final boolean shouldCache() { + return mShouldCache; + } + + /** + * Priority values. Requests will be processed from higher priorities to + * lower priorities, in FIFO order. + */ + public enum Priority { + LOW, + NORMAL, + HIGH, + IMMEDIATE + } + + /** + * Returns the {@link Priority} of this request; {@link Priority#NORMAL} by default. + */ + public Priority getPriority() { + return Priority.NORMAL; + } + + /** + * Returns the socket timeout in milliseconds per retry attempt. (This value can be changed + * per retry attempt if a backoff is specified via backoffTimeout()). If there are no retry + * attempts remaining, this will cause delivery of a {@link TimeoutError} error. + */ + public final int getTimeoutMs() { + return mRetryPolicy.getCurrentTimeout(); + } + + /** + * Returns the retry policy that should be used for this request. + */ + public RetryPolicy getRetryPolicy() { + return mRetryPolicy; + } + + /** + * Mark this request as having a response delivered on it. This can be used + * later in the request's lifetime for suppressing identical responses. + */ + public void markDelivered() { + mResponseDelivered = true; + } + + /** + * Returns true if this request has had a response delivered for it. + */ + public boolean hasHadResponseDelivered() { + return mResponseDelivered; + } + + /** + * Subclasses must implement this to parse the raw network response + * and return an appropriate response type. This method will be + * called from a worker thread. The response will not be delivered + * if you return null. + * @param response Response from the network + * @return The parsed response, or null in the case of an error + */ + abstract protected Response parseNetworkResponse(NetworkResponse response); + + /** + * Subclasses can override this method to parse 'networkError' and return a more specific error. + * + *

The default implementation just returns the passed 'networkError'.

+ * + * @param volleyError the error retrieved from the network + * @return an NetworkError augmented with additional information + */ + protected VolleyError parseNetworkError(VolleyError volleyError) { + return volleyError; + } + + /** + * Subclasses must implement this to perform delivery of the parsed + * response to their listeners. The given response is guaranteed to + * be non-null; responses that fail to parse are not delivered. + * @param response The parsed response returned by + * {@link #parseNetworkResponse(NetworkResponse)} + */ + abstract protected void deliverResponse(T response); + + /** + * Delivers error message to the ErrorListener that the Request was + * initialized with. + * + * @param error Error details + */ + public void deliverError(VolleyError error) { + if (mErrorListener != null) { + mErrorListener.onErrorResponse(error); + } + } + + /** + * Our comparator sorts from high to low priority, and secondarily by + * sequence number to provide FIFO ordering. + */ + @Override + public int compareTo(Request other) { + Priority left = this.getPriority(); + Priority right = other.getPriority(); + + // High-priority requests are "lesser" so they are sorted to the front. + // Equal priorities are sorted by sequence number to provide FIFO ordering. + return left == right ? + this.mSequence - other.mSequence : + right.ordinal() - left.ordinal(); + } + + @Override + public String toString() { + String trafficStatsTag = "0x" + Integer.toHexString(getTrafficStatsTag()); + return (mCanceled ? "[X] " : "[ ] ") + getUrl() + " " + trafficStatsTag + " " + + getPriority() + " " + mSequence; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/RequestQueue.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/RequestQueue.java new file mode 100644 index 00000000..b694dbc9 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/RequestQueue.java @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +import android.os.Handler; +import android.os.Looper; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * A request dispatch queue with a thread pool of dispatchers. + * + * Calling {@link #add(Request)} will enqueue the given Request for dispatch, + * resolving from either cache or network on a worker thread, and then delivering + * a parsed response on the main thread. + */ +public class RequestQueue { + + /** Callback interface for completed requests. */ + public static interface RequestFinishedListener { + /** Called when a request has finished processing. */ + public void onRequestFinished(Request request); + } + + /** Used for generating monotonically-increasing sequence numbers for requests. */ + private AtomicInteger mSequenceGenerator = new AtomicInteger(); + + /** + * Staging area for requests that already have a duplicate request in flight. + * + *
    + *
  • containsKey(cacheKey) indicates that there is a request in flight for the given cache + * key.
  • + *
  • get(cacheKey) returns waiting requests for the given cache key. The in flight request + * is not contained in that list. Is null if no requests are staged.
  • + *
+ */ + private final Map>> mWaitingRequests = + new HashMap>>(); + + /** + * The set of all requests currently being processed by this RequestQueue. A Request + * will be in this set if it is waiting in any queue or currently being processed by + * any dispatcher. + */ + private final Set> mCurrentRequests = new HashSet>(); + + /** The cache triage queue. */ + private final PriorityBlockingQueue> mCacheQueue = + new PriorityBlockingQueue>(); + + /** The queue of requests that are actually going out to the network. */ + private final PriorityBlockingQueue> mNetworkQueue = + new PriorityBlockingQueue>(); + + /** Number of network request dispatcher threads to start. */ + private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4; + + /** Cache interface for retrieving and storing responses. */ + private final Cache mCache; + + /** Network interface for performing requests. */ + private final Network mNetwork; + + /** Response delivery mechanism. */ + private final ResponseDelivery mDelivery; + + /** The network dispatchers. */ + private NetworkDispatcher[] mDispatchers; + + /** The cache dispatcher. */ + private CacheDispatcher mCacheDispatcher; + + private List mFinishedListeners = + new ArrayList(); + + /** + * Creates the worker pool. Processing will not begin until {@link #start()} is called. + * + * @param cache A Cache to use for persisting responses to disk + * @param network A Network interface for performing HTTP requests + * @param threadPoolSize Number of network dispatcher threads to create + * @param delivery A ResponseDelivery interface for posting responses and errors + */ + public RequestQueue(Cache cache, Network network, int threadPoolSize, + ResponseDelivery delivery) { + mCache = cache; + mNetwork = network; + mDispatchers = new NetworkDispatcher[threadPoolSize]; + mDelivery = delivery; + } + + /** + * Creates the worker pool. Processing will not begin until {@link #start()} is called. + * + * @param cache A Cache to use for persisting responses to disk + * @param network A Network interface for performing HTTP requests + * @param threadPoolSize Number of network dispatcher threads to create + */ + public RequestQueue(Cache cache, Network network, int threadPoolSize) { + this(cache, network, threadPoolSize, + new ExecutorDelivery(new Handler(Looper.getMainLooper()))); + } + + /** + * Creates the worker pool. Processing will not begin until {@link #start()} is called. + * + * @param cache A Cache to use for persisting responses to disk + * @param network A Network interface for performing HTTP requests + */ + public RequestQueue(Cache cache, Network network) { + this(cache, network, DEFAULT_NETWORK_THREAD_POOL_SIZE); + } + + /** + * Starts the dispatchers in this queue. + */ + public void start() { + stop(); // Make sure any currently running dispatchers are stopped. + // Create the cache dispatcher and start it. + mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery); + mCacheDispatcher.start(); + + // Create network dispatchers (and corresponding threads) up to the pool size. + for (int i = 0; i < mDispatchers.length; i++) { + NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork, + mCache, mDelivery); + mDispatchers[i] = networkDispatcher; + networkDispatcher.start(); + } + } + + /** + * Stops the cache and network dispatchers. + */ + public void stop() { + if (mCacheDispatcher != null) { + mCacheDispatcher.quit(); + } + for (int i = 0; i < mDispatchers.length; i++) { + if (mDispatchers[i] != null) { + mDispatchers[i].quit(); + } + } + } + + /** + * Gets a sequence number. + */ + public int getSequenceNumber() { + return mSequenceGenerator.incrementAndGet(); + } + + /** + * Gets the {@link Cache} instance being used. + */ + public Cache getCache() { + return mCache; + } + + /** + * A simple predicate or filter interface for Requests, for use by + * {@link RequestQueue#cancelAll(RequestFilter)}. + */ + public interface RequestFilter { + public boolean apply(Request request); + } + + /** + * Cancels all requests in this queue for which the given filter applies. + * @param filter The filtering function to use + */ + public void cancelAll(RequestFilter filter) { + synchronized (mCurrentRequests) { + for (Request request : mCurrentRequests) { + if (filter.apply(request)) { + request.cancel(); + } + } + } + } + + /** + * Cancels all requests in this queue with the given tag. Tag must be non-null + * and equality is by identity. + */ + public void cancelAll(final Object tag) { + if (tag == null) { + throw new IllegalArgumentException("Cannot cancelAll with a null tag"); + } + cancelAll(new RequestFilter() { + @Override + public boolean apply(Request request) { + return request.getTag() == tag; + } + }); + } + + /** + * Adds a Request to the dispatch queue. + * @param request The request to service + * @return The passed-in request + */ + public Request add(Request request) { + // Tag the request as belonging to this queue and add it to the set of current requests. + request.setRequestQueue(this); + synchronized (mCurrentRequests) { + mCurrentRequests.add(request); + } + + // Process requests in the order they are added. + request.setSequence(getSequenceNumber()); + request.addMarker("add-to-queue"); + + // If the request is uncacheable, skip the cache queue and go straight to the network. + if (!request.shouldCache()) { + mNetworkQueue.add(request); + return request; + } + + // Insert request into stage if there's already a request with the same cache key in flight. + synchronized (mWaitingRequests) { + String cacheKey = request.getCacheKey(); + if (mWaitingRequests.containsKey(cacheKey)) { + // There is already a request in flight. Queue up. + Queue> stagedRequests = mWaitingRequests.get(cacheKey); + if (stagedRequests == null) { + stagedRequests = new LinkedList>(); + } + stagedRequests.add(request); + mWaitingRequests.put(cacheKey, stagedRequests); + if (VolleyLog.DEBUG) { + VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey); + } + } else { + // Insert 'null' queue for this cacheKey, indicating there is now a request in + // flight. + mWaitingRequests.put(cacheKey, null); + mCacheQueue.add(request); + } + return request; + } + } + + /** + * Called from {@link Request#finish(String)}, indicating that processing of the given request + * has finished. + * + *

Releases waiting requests for request.getCacheKey() if + * request.shouldCache().

+ */ + void finish(Request request) { + // Remove from the set of requests currently being processed. + synchronized (mCurrentRequests) { + mCurrentRequests.remove(request); + } + synchronized (mFinishedListeners) { + for (RequestFinishedListener listener : mFinishedListeners) { + listener.onRequestFinished(request); + } + } + + if (request.shouldCache()) { + synchronized (mWaitingRequests) { + String cacheKey = request.getCacheKey(); + Queue> waitingRequests = mWaitingRequests.remove(cacheKey); + if (waitingRequests != null) { + if (VolleyLog.DEBUG) { + VolleyLog.v("Releasing %d waiting requests for cacheKey=%s.", + waitingRequests.size(), cacheKey); + } + // Process all queued up requests. They won't be considered as in flight, but + // that's not a problem as the cache has been primed by 'request'. + mCacheQueue.addAll(waitingRequests); + } + } + } + } + + public void addRequestFinishedListener(RequestFinishedListener listener) { + synchronized (mFinishedListeners) { + mFinishedListeners.add(listener); + } + } + + /** + * Remove a RequestFinishedListener. Has no effect if listener was not previously added. + */ + public void removeRequestFinishedListener(RequestFinishedListener listener) { + synchronized (mFinishedListeners) { + mFinishedListeners.remove(listener); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/Response.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/Response.java new file mode 100644 index 00000000..aadf2d78 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/Response.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +/** + * Encapsulates a parsed response for delivery. + * + * @param Parsed type of this response + */ +public class Response { + + /** Callback interface for delivering parsed responses. */ + public interface Listener { + /** Called when a response is received. */ + public void onResponse(T response); + } + + /** Callback interface for delivering error responses. */ + public interface ErrorListener { + /** + * Callback method that an error has been occurred with the + * provided error code and optional user-readable message. + */ + public void onErrorResponse(VolleyError error); + } + + /** Returns a successful response containing the parsed result. */ + public static Response success(T result, Cache.Entry cacheEntry) { + return new Response(result, cacheEntry); + } + + /** + * Returns a failed response containing the given error code and an optional + * localized message displayed to the user. + */ + public static Response error(VolleyError error) { + return new Response(error); + } + + /** Parsed response, or null in the case of error. */ + public final T result; + + /** Cache metadata for this response, or null in the case of error. */ + public final Cache.Entry cacheEntry; + + /** Detailed error information if errorCode != OK. */ + public final VolleyError error; + + /** True if this response was a soft-expired one and a second one MAY be coming. */ + public boolean intermediate = false; + + /** + * Returns whether this response is considered successful. + */ + public boolean isSuccess() { + return error == null; + } + + + private Response(T result, Cache.Entry cacheEntry) { + this.result = result; + this.cacheEntry = cacheEntry; + this.error = null; + } + + private Response(VolleyError error) { + this.result = null; + this.cacheEntry = null; + this.error = error; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/ResponseDelivery.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/ResponseDelivery.java new file mode 100644 index 00000000..38e67cf5 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/ResponseDelivery.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +public interface ResponseDelivery { + /** + * Parses a response from the network or cache and delivers it. + */ + public void postResponse(Request request, Response response); + + /** + * Parses a response from the network or cache and delivers it. The provided + * Runnable will be executed after delivery. + */ + public void postResponse(Request request, Response response, Runnable runnable); + + /** + * Posts an error for the given request. + */ + public void postError(Request request, VolleyError error); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/RetryPolicy.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/RetryPolicy.java new file mode 100644 index 00000000..02f279a7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/RetryPolicy.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +/** + * Retry policy for a request. + */ +public interface RetryPolicy { + + /** + * Returns the current timeout (used for logging). + */ + public int getCurrentTimeout(); + + /** + * Returns the current retry count (used for logging). + */ + public int getCurrentRetryCount(); + + /** + * Prepares for the next retry by applying a backoff to the timeout. + * @param error The error code of the last attempt. + * @throws VolleyError In the event that the retry could not be performed (for example if we + * ran out of attempts), the passed in error is thrown. + */ + public void retry(VolleyError error) throws VolleyError; +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/ServerError.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/ServerError.java new file mode 100644 index 00000000..bff6a4cc --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/ServerError.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +/** + * Indicates that the server responded with an error response. + */ +@SuppressWarnings("serial") +public class ServerError extends VolleyError { + public ServerError(NetworkResponse networkResponse) { + super(networkResponse); + } + + public ServerError() { + super(); + } +} + diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/TimeoutError.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/TimeoutError.java new file mode 100644 index 00000000..ca3b185b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/TimeoutError.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +/** + * Indicates that the connection or the socket timed out. + */ +@SuppressWarnings("serial") +public class TimeoutError extends VolleyError { } diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/VolleyError.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/VolleyError.java new file mode 100644 index 00000000..78b5c71b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/VolleyError.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +/** + * Exception style class encapsulating Volley errors + */ +@SuppressWarnings("serial") +public class VolleyError extends Exception { + public final NetworkResponse networkResponse; + private long networkTimeMs; + + public VolleyError() { + networkResponse = null; + } + + public VolleyError(NetworkResponse response) { + networkResponse = response; + } + + public VolleyError(String exceptionMessage) { + super(exceptionMessage); + networkResponse = null; + } + + public VolleyError(String exceptionMessage, Throwable reason) { + super(exceptionMessage, reason); + networkResponse = null; + } + + public VolleyError(Throwable cause) { + super(cause); + networkResponse = null; + } + + /* package */ void setNetworkTimeMs(long networkTimeMs) { + this.networkTimeMs = networkTimeMs; + } + + public long getNetworkTimeMs() { + return networkTimeMs; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/VolleyLog.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/VolleyLog.java new file mode 100644 index 00000000..1834358a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/VolleyLog.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley; + +import android.os.SystemClock; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +/** + * Logging helper class. + *

+ * to see Volley logs call:
+ * {@code /platform-tools/adb shell setprop log.tag.Volley VERBOSE} + */ +public class VolleyLog { + public static String TAG = "Volley"; + + public static boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE); + + /** + * Customize the log tag for your application, so that other apps + * using Volley don't mix their logs with yours. + *
+ * Enable the log property for your tag before starting your app: + *
+ * {@code adb shell setprop log.tag.<tag>} + */ + public static void setTag(String tag) { + d("Changing log tag to %s", tag); + TAG = tag; + + // Reinitialize the DEBUG "constant" + DEBUG = Log.isLoggable(TAG, Log.VERBOSE); + } + + public static void v(String format, Object... args) { + if (DEBUG) { + Log.v(TAG, buildMessage(format, args)); + } + } + + public static void d(String format, Object... args) { + Log.d(TAG, buildMessage(format, args)); + } + + public static void e(String format, Object... args) { + Log.e(TAG, buildMessage(format, args)); + } + + public static void e(Throwable tr, String format, Object... args) { + Log.e(TAG, buildMessage(format, args), tr); + } + + public static void wtf(String format, Object... args) { + Log.wtf(TAG, buildMessage(format, args)); + } + + public static void wtf(Throwable tr, String format, Object... args) { + Log.wtf(TAG, buildMessage(format, args), tr); + } + + /** + * Formats the caller's provided message and prepends useful info like + * calling thread ID and method name. + */ + private static String buildMessage(String format, Object... args) { + String msg = (args == null) ? format : String.format(Locale.US, format, args); + StackTraceElement[] trace = new Throwable().fillInStackTrace().getStackTrace(); + + String caller = ""; + // Walk up the stack looking for the first caller outside of VolleyLog. + // It will be at least two frames up, so start there. + for (int i = 2; i < trace.length; i++) { + Class clazz = trace[i].getClass(); + if (!clazz.equals(VolleyLog.class)) { + String callingClass = trace[i].getClassName(); + callingClass = callingClass.substring(callingClass.lastIndexOf('.') + 1); + callingClass = callingClass.substring(callingClass.lastIndexOf('$') + 1); + + caller = callingClass + "." + trace[i].getMethodName(); + break; + } + } + return String.format(Locale.US, "[%d] %s: %s", + Thread.currentThread().getId(), caller, msg); + } + + /** + * A simple event log with records containing a name, thread ID, and timestamp. + */ + static class MarkerLog { + public static final boolean ENABLED = VolleyLog.DEBUG; + + /** Minimum duration from first marker to last in an marker log to warrant logging. */ + private static final long MIN_DURATION_FOR_LOGGING_MS = 0; + + private static class Marker { + public final String name; + public final long thread; + public final long time; + + public Marker(String name, long thread, long time) { + this.name = name; + this.thread = thread; + this.time = time; + } + } + + private final List mMarkers = new ArrayList(); + private boolean mFinished = false; + + /** Adds a marker to this log with the specified name. */ + public synchronized void add(String name, long threadId) { + if (mFinished) { + throw new IllegalStateException("Marker added to finished log"); + } + + mMarkers.add(new Marker(name, threadId, SystemClock.elapsedRealtime())); + } + + /** + * Closes the log, dumping it to logcat if the time difference between + * the first and last markers is greater than {@link #MIN_DURATION_FOR_LOGGING_MS}. + * @param header Header string to print above the marker log. + */ + public synchronized void finish(String header) { + mFinished = true; + + long duration = getTotalDuration(); + if (duration <= MIN_DURATION_FOR_LOGGING_MS) { + return; + } + + long prevTime = mMarkers.get(0).time; + d("(%-4d ms) %s", duration, header); + for (Marker marker : mMarkers) { + long thisTime = marker.time; + d("(+%-4d) [%2d] %s", (thisTime - prevTime), marker.thread, marker.name); + prevTime = thisTime; + } + } + + @Override + protected void finalize() throws Throwable { + // Catch requests that have been collected (and hence end-of-lifed) + // but had no debugging output printed for them. + if (!mFinished) { + finish("Request on the loose"); + e("Marker log finalized without finish() - uncaught exit point for request"); + } + } + + /** Returns the time difference between the first and last events in this log. */ + private long getTotalDuration() { + if (mMarkers.size() == 0) { + return 0; + } + + long first = mMarkers.get(0).time; + long last = mMarkers.get(mMarkers.size() - 1).time; + return last - first; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/AndroidAuthenticator.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/AndroidAuthenticator.java new file mode 100644 index 00000000..780c643d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/AndroidAuthenticator.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import org.telegram.messenger.volley.AuthFailureError; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.accounts.AccountManagerFuture; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +/** + * An Authenticator that uses {@link AccountManager} to get auth + * tokens of a specified type for a specified account. + */ +public class AndroidAuthenticator implements Authenticator { + private final AccountManager mAccountManager; + private final Account mAccount; + private final String mAuthTokenType; + private final boolean mNotifyAuthFailure; + + /** + * Creates a new authenticator. + * @param context Context for accessing AccountManager + * @param account Account to authenticate as + * @param authTokenType Auth token type passed to AccountManager + */ + public AndroidAuthenticator(Context context, Account account, String authTokenType) { + this(context, account, authTokenType, false); + } + + /** + * Creates a new authenticator. + * @param context Context for accessing AccountManager + * @param account Account to authenticate as + * @param authTokenType Auth token type passed to AccountManager + * @param notifyAuthFailure Whether to raise a notification upon auth failure + */ + public AndroidAuthenticator(Context context, Account account, String authTokenType, + boolean notifyAuthFailure) { + this(AccountManager.get(context), account, authTokenType, notifyAuthFailure); + } + + // Visible for testing. Allows injection of a mock AccountManager. + AndroidAuthenticator(AccountManager accountManager, Account account, + String authTokenType, boolean notifyAuthFailure) { + mAccountManager = accountManager; + mAccount = account; + mAuthTokenType = authTokenType; + mNotifyAuthFailure = notifyAuthFailure; + } + + /** + * Returns the Account being used by this authenticator. + */ + public Account getAccount() { + return mAccount; + } + + // TODO: Figure out what to do about notifyAuthFailure + @SuppressWarnings("deprecation") + @Override + public String getAuthToken() throws AuthFailureError { + AccountManagerFuture future = mAccountManager.getAuthToken(mAccount, + mAuthTokenType, mNotifyAuthFailure, null, null); + Bundle result; + try { + result = future.getResult(); + } catch (Exception e) { + throw new AuthFailureError("Error while retrieving auth token", e); + } + String authToken = null; + if (future.isDone() && !future.isCancelled()) { + if (result.containsKey(AccountManager.KEY_INTENT)) { + Intent intent = result.getParcelable(AccountManager.KEY_INTENT); + throw new AuthFailureError(intent); + } + authToken = result.getString(AccountManager.KEY_AUTHTOKEN); + } + if (authToken == null) { + throw new AuthFailureError("Got null auth token for type: " + mAuthTokenType); + } + + return authToken; + } + + @Override + public void invalidateAuthToken(String authToken) { + mAccountManager.invalidateAuthToken(mAccount.type, authToken); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/Authenticator.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/Authenticator.java new file mode 100644 index 00000000..9118a3bf --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/Authenticator.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import org.telegram.messenger.volley.AuthFailureError; + +/** + * An interface for interacting with auth tokens. + */ +public interface Authenticator { + /** + * Synchronously retrieves an auth token. + * + * @throws AuthFailureError If authentication did not succeed + */ + public String getAuthToken() throws AuthFailureError; + + /** + * Invalidates the provided auth token. + */ + public void invalidateAuthToken(String authToken); +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/BasicNetwork.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/BasicNetwork.java new file mode 100644 index 00000000..0ca76037 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/BasicNetwork.java @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import android.os.SystemClock; + +import org.telegram.messenger.volley.AuthFailureError; +import org.telegram.messenger.volley.Cache; +import org.telegram.messenger.volley.Cache.Entry; +import org.telegram.messenger.volley.Network; +import org.telegram.messenger.volley.NetworkError; +import org.telegram.messenger.volley.NetworkResponse; +import org.telegram.messenger.volley.NoConnectionError; +import org.telegram.messenger.volley.Request; +import org.telegram.messenger.volley.RetryPolicy; +import org.telegram.messenger.volley.ServerError; +import org.telegram.messenger.volley.TimeoutError; +import org.telegram.messenger.volley.VolleyError; +import org.telegram.messenger.volley.VolleyLog; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.StatusLine; +import org.apache.http.conn.ConnectTimeoutException; +import org.apache.http.impl.cookie.DateUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.SocketTimeoutException; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +/** + * A network performing Volley requests over an {@link HttpStack}. + */ +public class BasicNetwork implements Network { + protected static final boolean DEBUG = VolleyLog.DEBUG; + + private static int SLOW_REQUEST_THRESHOLD_MS = 3000; + + private static int DEFAULT_POOL_SIZE = 4096; + + protected final HttpStack mHttpStack; + + protected final ByteArrayPool mPool; + + /** + * @param httpStack HTTP stack to be used + */ + public BasicNetwork(HttpStack httpStack) { + // If a pool isn't passed in, then build a small default pool that will give us a lot of + // benefit and not use too much memory. + this(httpStack, new ByteArrayPool(DEFAULT_POOL_SIZE)); + } + + /** + * @param httpStack HTTP stack to be used + * @param pool a buffer pool that improves GC performance in copy operations + */ + public BasicNetwork(HttpStack httpStack, ByteArrayPool pool) { + mHttpStack = httpStack; + mPool = pool; + } + + @Override + public NetworkResponse performRequest(Request request) throws VolleyError { + long requestStart = SystemClock.elapsedRealtime(); + while (true) { + HttpResponse httpResponse = null; + byte[] responseContents = null; + Map responseHeaders = Collections.emptyMap(); + try { + // Gather headers. + Map headers = new HashMap(); + addCacheHeaders(headers, request.getCacheEntry()); + httpResponse = mHttpStack.performRequest(request, headers); + StatusLine statusLine = httpResponse.getStatusLine(); + int statusCode = statusLine.getStatusCode(); + + responseHeaders = convertHeaders(httpResponse.getAllHeaders()); + // Handle cache validation. + if (statusCode == HttpStatus.SC_NOT_MODIFIED) { + + Entry entry = request.getCacheEntry(); + if (entry == null) { + return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null, + responseHeaders, true, + SystemClock.elapsedRealtime() - requestStart); + } + + // A HTTP 304 response does not have all header fields. We + // have to use the header fields from the cache entry plus + // the new ones from the response. + // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 + entry.responseHeaders.putAll(responseHeaders); + return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data, + entry.responseHeaders, true, + SystemClock.elapsedRealtime() - requestStart); + } + + // Some responses such as 204s do not have content. We must check. + if (httpResponse.getEntity() != null) { + responseContents = entityToBytes(httpResponse.getEntity()); + } else { + // Add 0 byte response as a way of honestly representing a + // no-content request. + responseContents = new byte[0]; + } + + // if the request is slow, log it. + long requestLifetime = SystemClock.elapsedRealtime() - requestStart; + logSlowRequests(requestLifetime, request, responseContents, statusLine); + + if (statusCode < 200 || statusCode > 299) { + throw new IOException(); + } + return new NetworkResponse(statusCode, responseContents, responseHeaders, false, + SystemClock.elapsedRealtime() - requestStart); + } catch (SocketTimeoutException e) { + attemptRetryOnException("socket", request, new TimeoutError()); + } catch (ConnectTimeoutException e) { + attemptRetryOnException("connection", request, new TimeoutError()); + } catch (MalformedURLException e) { + throw new RuntimeException("Bad URL " + request.getUrl(), e); + } catch (IOException e) { + int statusCode = 0; + NetworkResponse networkResponse = null; + if (httpResponse != null) { + statusCode = httpResponse.getStatusLine().getStatusCode(); + } else { + throw new NoConnectionError(e); + } + VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl()); + if (responseContents != null) { + networkResponse = new NetworkResponse(statusCode, responseContents, + responseHeaders, false, SystemClock.elapsedRealtime() - requestStart); + if (statusCode == HttpStatus.SC_UNAUTHORIZED || + statusCode == HttpStatus.SC_FORBIDDEN) { + attemptRetryOnException("auth", + request, new AuthFailureError(networkResponse)); + } else { + // TODO: Only throw ServerError for 5xx status codes. + throw new ServerError(networkResponse); + } + } else { + throw new NetworkError(networkResponse); + } + } + } + } + + /** + * Logs requests that took over SLOW_REQUEST_THRESHOLD_MS to complete. + */ + private void logSlowRequests(long requestLifetime, Request request, + byte[] responseContents, StatusLine statusLine) { + if (DEBUG || requestLifetime > SLOW_REQUEST_THRESHOLD_MS) { + VolleyLog.d("HTTP response for request=<%s> [lifetime=%d], [size=%s], " + + "[rc=%d], [retryCount=%s]", request, requestLifetime, + responseContents != null ? responseContents.length : "null", + statusLine.getStatusCode(), request.getRetryPolicy().getCurrentRetryCount()); + } + } + + /** + * Attempts to prepare the request for a retry. If there are no more attempts remaining in the + * request's retry policy, a timeout exception is thrown. + * @param request The request to use. + */ + private static void attemptRetryOnException(String logPrefix, Request request, + VolleyError exception) throws VolleyError { + RetryPolicy retryPolicy = request.getRetryPolicy(); + int oldTimeout = request.getTimeoutMs(); + + try { + retryPolicy.retry(exception); + } catch (VolleyError e) { + request.addMarker( + String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout)); + throw e; + } + request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout)); + } + + private void addCacheHeaders(Map headers, Cache.Entry entry) { + // If there's no cache entry, we're done. + if (entry == null) { + return; + } + + if (entry.etag != null) { + headers.put("If-None-Match", entry.etag); + } + + if (entry.lastModified > 0) { + Date refTime = new Date(entry.lastModified); + headers.put("If-Modified-Since", DateUtils.formatDate(refTime)); + } + } + + protected void logError(String what, String url, long start) { + long now = SystemClock.elapsedRealtime(); + VolleyLog.v("HTTP ERROR(%s) %d ms to fetch %s", what, (now - start), url); + } + + /** Reads the contents of HttpEntity into a byte[]. */ + private byte[] entityToBytes(HttpEntity entity) throws IOException, ServerError { + PoolingByteArrayOutputStream bytes = + new PoolingByteArrayOutputStream(mPool, (int) entity.getContentLength()); + byte[] buffer = null; + try { + InputStream in = entity.getContent(); + if (in == null) { + throw new ServerError(); + } + buffer = mPool.getBuf(1024); + int count; + while ((count = in.read(buffer)) != -1) { + bytes.write(buffer, 0, count); + } + return bytes.toByteArray(); + } finally { + try { + // Close the InputStream and release the resources by "consuming the content". + entity.consumeContent(); + } catch (IOException e) { + // This can happen if there was an exception above that left the entity in + // an invalid state. + VolleyLog.v("Error occured when calling consumingContent"); + } + mPool.returnBuf(buffer); + bytes.close(); + } + } + + /** + * Converts Headers[] to Map. + */ + protected static Map convertHeaders(Header[] headers) { + Map result = new TreeMap(String.CASE_INSENSITIVE_ORDER); + for (int i = 0; i < headers.length; i++) { + result.put(headers[i].getName(), headers[i].getValue()); + } + return result; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/ByteArrayPool.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/ByteArrayPool.java new file mode 100644 index 00000000..047a9181 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/ByteArrayPool.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +/** + * ByteArrayPool is a source and repository of byte[] objects. Its purpose is to + * supply those buffers to consumers who need to use them for a short period of time and then + * dispose of them. Simply creating and disposing such buffers in the conventional manner can + * considerable heap churn and garbage collection delays on Android, which lacks good management of + * short-lived heap objects. It may be advantageous to trade off some memory in the form of a + * permanently allocated pool of buffers in order to gain heap performance improvements; that is + * what this class does. + *

+ * A good candidate user for this class is something like an I/O system that uses large temporary + * byte[] buffers to copy data around. In these use cases, often the consumer wants + * the buffer to be a certain minimum size to ensure good performance (e.g. when copying data chunks + * off of a stream), but doesn't mind if the buffer is larger than the minimum. Taking this into + * account and also to maximize the odds of being able to reuse a recycled buffer, this class is + * free to return buffers larger than the requested size. The caller needs to be able to gracefully + * deal with getting buffers any size over the minimum. + *

+ * If there is not a suitably-sized buffer in its recycling pool when a buffer is requested, this + * class will allocate a new buffer and return it. + *

+ * This class has no special ownership of buffers it creates; the caller is free to take a buffer + * it receives from this pool, use it permanently, and never return it to the pool; additionally, + * it is not harmful to return to this pool a buffer that was allocated elsewhere, provided there + * are no other lingering references to it. + *

+ * This class ensures that the total size of the buffers in its recycling pool never exceeds a + * certain byte limit. When a buffer is returned that would cause the pool to exceed the limit, + * least-recently-used buffers are disposed. + */ +public class ByteArrayPool { + /** The buffer pool, arranged both by last use and by buffer size */ + private List mBuffersByLastUse = new LinkedList(); + private List mBuffersBySize = new ArrayList(64); + + /** The total size of the buffers in the pool */ + private int mCurrentSize = 0; + + /** + * The maximum aggregate size of the buffers in the pool. Old buffers are discarded to stay + * under this limit. + */ + private final int mSizeLimit; + + /** Compares buffers by size */ + protected static final Comparator BUF_COMPARATOR = new Comparator() { + @Override + public int compare(byte[] lhs, byte[] rhs) { + return lhs.length - rhs.length; + } + }; + + /** + * @param sizeLimit the maximum size of the pool, in bytes + */ + public ByteArrayPool(int sizeLimit) { + mSizeLimit = sizeLimit; + } + + /** + * Returns a buffer from the pool if one is available in the requested size, or allocates a new + * one if a pooled one is not available. + * + * @param len the minimum size, in bytes, of the requested buffer. The returned buffer may be + * larger. + * @return a byte[] buffer is always returned. + */ + public synchronized byte[] getBuf(int len) { + for (int i = 0; i < mBuffersBySize.size(); i++) { + byte[] buf = mBuffersBySize.get(i); + if (buf.length >= len) { + mCurrentSize -= buf.length; + mBuffersBySize.remove(i); + mBuffersByLastUse.remove(buf); + return buf; + } + } + return new byte[len]; + } + + /** + * Returns a buffer to the pool, throwing away old buffers if the pool would exceed its allotted + * size. + * + * @param buf the buffer to return to the pool. + */ + public synchronized void returnBuf(byte[] buf) { + if (buf == null || buf.length > mSizeLimit) { + return; + } + mBuffersByLastUse.add(buf); + int pos = Collections.binarySearch(mBuffersBySize, buf, BUF_COMPARATOR); + if (pos < 0) { + pos = -pos - 1; + } + mBuffersBySize.add(pos, buf); + mCurrentSize += buf.length; + trim(); + } + + /** + * Removes buffers from the pool until it is under its size limit. + */ + private synchronized void trim() { + while (mCurrentSize > mSizeLimit) { + byte[] buf = mBuffersByLastUse.remove(0); + mBuffersBySize.remove(buf); + mCurrentSize -= buf.length; + } + } + +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/ClearCacheRequest.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/ClearCacheRequest.java new file mode 100644 index 00000000..22999cf4 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/ClearCacheRequest.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import org.telegram.messenger.volley.Cache; +import org.telegram.messenger.volley.NetworkResponse; +import org.telegram.messenger.volley.Request; +import org.telegram.messenger.volley.Response; + +import android.os.Handler; +import android.os.Looper; + +/** + * A synthetic request used for clearing the cache. + */ +public class ClearCacheRequest extends Request { + private final Cache mCache; + private final Runnable mCallback; + + /** + * Creates a synthetic request for clearing the cache. + * @param cache Cache to clear + * @param callback Callback to make on the main thread once the cache is clear, + * or null for none + */ + public ClearCacheRequest(Cache cache, Runnable callback) { + super(Method.GET, null, null); + mCache = cache; + mCallback = callback; + } + + @Override + public boolean isCanceled() { + // This is a little bit of a hack, but hey, why not. + mCache.clear(); + if (mCallback != null) { + Handler handler = new Handler(Looper.getMainLooper()); + handler.postAtFrontOfQueue(mCallback); + } + return true; + } + + @Override + public Priority getPriority() { + return Priority.IMMEDIATE; + } + + @Override + protected Response parseNetworkResponse(NetworkResponse response) { + return null; + } + + @Override + protected void deliverResponse(Object response) { + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/DiskBasedCache.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/DiskBasedCache.java new file mode 100644 index 00000000..3ecfaf30 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/DiskBasedCache.java @@ -0,0 +1,571 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import android.os.SystemClock; + +import org.telegram.messenger.volley.Cache; +import org.telegram.messenger.volley.VolleyLog; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Cache implementation that caches files directly onto the hard disk in the specified + * directory. The default disk usage size is 5MB, but is configurable. + */ +public class DiskBasedCache implements Cache { + + /** Map of the Key, CacheHeader pairs */ + private final Map mEntries = + new LinkedHashMap(16, .75f, true); + + /** Total amount of space currently used by the cache in bytes. */ + private long mTotalSize = 0; + + /** The root directory to use for the cache. */ + private final File mRootDirectory; + + /** The maximum size of the cache in bytes. */ + private final int mMaxCacheSizeInBytes; + + /** Default maximum disk usage in bytes. */ + private static final int DEFAULT_DISK_USAGE_BYTES = 5 * 1024 * 1024; + + /** High water mark percentage for the cache */ + private static final float HYSTERESIS_FACTOR = 0.9f; + + /** Magic number for current version of cache file format. */ + private static final int CACHE_MAGIC = 0x20150306; + + /** + * Constructs an instance of the DiskBasedCache at the specified directory. + * @param rootDirectory The root directory of the cache. + * @param maxCacheSizeInBytes The maximum size of the cache in bytes. + */ + public DiskBasedCache(File rootDirectory, int maxCacheSizeInBytes) { + mRootDirectory = rootDirectory; + mMaxCacheSizeInBytes = maxCacheSizeInBytes; + } + + /** + * Constructs an instance of the DiskBasedCache at the specified directory using + * the default maximum cache size of 5MB. + * @param rootDirectory The root directory of the cache. + */ + public DiskBasedCache(File rootDirectory) { + this(rootDirectory, DEFAULT_DISK_USAGE_BYTES); + } + + /** + * Clears the cache. Deletes all cached files from disk. + */ + @Override + public synchronized void clear() { + File[] files = mRootDirectory.listFiles(); + if (files != null) { + for (File file : files) { + file.delete(); + } + } + mEntries.clear(); + mTotalSize = 0; + VolleyLog.d("Cache cleared."); + } + + /** + * Returns the cache entry with the specified key if it exists, null otherwise. + */ + @Override + public synchronized Entry get(String key) { + CacheHeader entry = mEntries.get(key); + // if the entry does not exist, return. + if (entry == null) { + return null; + } + + File file = getFileForKey(key); + CountingInputStream cis = null; + try { + cis = new CountingInputStream(new BufferedInputStream(new FileInputStream(file))); + CacheHeader.readHeader(cis); // eat header + byte[] data = streamToBytes(cis, (int) (file.length() - cis.bytesRead)); + return entry.toCacheEntry(data); + } catch (IOException e) { + VolleyLog.d("%s: %s", file.getAbsolutePath(), e.toString()); + remove(key); + return null; + } finally { + if (cis != null) { + try { + cis.close(); + } catch (IOException ioe) { + return null; + } + } + } + } + + /** + * Initializes the DiskBasedCache by scanning for all files currently in the + * specified root directory. Creates the root directory if necessary. + */ + @Override + public synchronized void initialize() { + if (!mRootDirectory.exists()) { + if (!mRootDirectory.mkdirs()) { + VolleyLog.e("Unable to create cache dir %s", mRootDirectory.getAbsolutePath()); + } + return; + } + + File[] files = mRootDirectory.listFiles(); + if (files == null) { + return; + } + for (File file : files) { + BufferedInputStream fis = null; + try { + fis = new BufferedInputStream(new FileInputStream(file)); + CacheHeader entry = CacheHeader.readHeader(fis); + entry.size = file.length(); + putEntry(entry.key, entry); + } catch (IOException e) { + if (file != null) { + file.delete(); + } + } finally { + try { + if (fis != null) { + fis.close(); + } + } catch (IOException ignored) { } + } + } + } + + /** + * Invalidates an entry in the cache. + * @param key Cache key + * @param fullExpire True to fully expire the entry, false to soft expire + */ + @Override + public synchronized void invalidate(String key, boolean fullExpire) { + Entry entry = get(key); + if (entry != null) { + entry.softTtl = 0; + if (fullExpire) { + entry.ttl = 0; + } + put(key, entry); + } + + } + + /** + * Puts the entry with the specified key into the cache. + */ + @Override + public synchronized void put(String key, Entry entry) { + pruneIfNeeded(entry.data.length); + File file = getFileForKey(key); + try { + BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream(file)); + CacheHeader e = new CacheHeader(key, entry); + boolean success = e.writeHeader(fos); + if (!success) { + fos.close(); + VolleyLog.d("Failed to write header for %s", file.getAbsolutePath()); + throw new IOException(); + } + fos.write(entry.data); + fos.close(); + putEntry(key, e); + return; + } catch (IOException e) { + } + boolean deleted = file.delete(); + if (!deleted) { + VolleyLog.d("Could not clean up file %s", file.getAbsolutePath()); + } + } + + /** + * Removes the specified key from the cache if it exists. + */ + @Override + public synchronized void remove(String key) { + boolean deleted = getFileForKey(key).delete(); + removeEntry(key); + if (!deleted) { + VolleyLog.d("Could not delete cache entry for key=%s, filename=%s", + key, getFilenameForKey(key)); + } + } + + /** + * Creates a pseudo-unique filename for the specified cache key. + * @param key The key to generate a file name for. + * @return A pseudo-unique filename. + */ + private String getFilenameForKey(String key) { + int firstHalfLength = key.length() / 2; + String localFilename = String.valueOf(key.substring(0, firstHalfLength).hashCode()); + localFilename += String.valueOf(key.substring(firstHalfLength).hashCode()); + return localFilename; + } + + /** + * Returns a file object for the given cache key. + */ + public File getFileForKey(String key) { + return new File(mRootDirectory, getFilenameForKey(key)); + } + + /** + * Prunes the cache to fit the amount of bytes specified. + * @param neededSpace The amount of bytes we are trying to fit into the cache. + */ + private void pruneIfNeeded(int neededSpace) { + if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes) { + return; + } + if (VolleyLog.DEBUG) { + VolleyLog.v("Pruning old cache entries."); + } + + long before = mTotalSize; + int prunedFiles = 0; + long startTime = SystemClock.elapsedRealtime(); + + Iterator> iterator = mEntries.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + CacheHeader e = entry.getValue(); + boolean deleted = getFileForKey(e.key).delete(); + if (deleted) { + mTotalSize -= e.size; + } else { + VolleyLog.d("Could not delete cache entry for key=%s, filename=%s", + e.key, getFilenameForKey(e.key)); + } + iterator.remove(); + prunedFiles++; + + if ((mTotalSize + neededSpace) < mMaxCacheSizeInBytes * HYSTERESIS_FACTOR) { + break; + } + } + + if (VolleyLog.DEBUG) { + VolleyLog.v("pruned %d files, %d bytes, %d ms", + prunedFiles, (mTotalSize - before), SystemClock.elapsedRealtime() - startTime); + } + } + + /** + * Puts the entry with the specified key into the cache. + * @param key The key to identify the entry by. + * @param entry The entry to cache. + */ + private void putEntry(String key, CacheHeader entry) { + if (!mEntries.containsKey(key)) { + mTotalSize += entry.size; + } else { + CacheHeader oldEntry = mEntries.get(key); + mTotalSize += (entry.size - oldEntry.size); + } + mEntries.put(key, entry); + } + + /** + * Removes the entry identified by 'key' from the cache. + */ + private void removeEntry(String key) { + CacheHeader entry = mEntries.get(key); + if (entry != null) { + mTotalSize -= entry.size; + mEntries.remove(key); + } + } + + /** + * Reads the contents of an InputStream into a byte[]. + * */ + private static byte[] streamToBytes(InputStream in, int length) throws IOException { + byte[] bytes = new byte[length]; + int count; + int pos = 0; + while (pos < length && ((count = in.read(bytes, pos, length - pos)) != -1)) { + pos += count; + } + if (pos != length) { + throw new IOException("Expected " + length + " bytes, read " + pos + " bytes"); + } + return bytes; + } + + /** + * Handles holding onto the cache headers for an entry. + */ + // Visible for testing. + static class CacheHeader { + /** The size of the data identified by this CacheHeader. (This is not + * serialized to disk. */ + public long size; + + /** The key that identifies the cache entry. */ + public String key; + + /** ETag for cache coherence. */ + public String etag; + + /** Date of this response as reported by the server. */ + public long serverDate; + + /** The last modified date for the requested object. */ + public long lastModified; + + /** TTL for this record. */ + public long ttl; + + /** Soft TTL for this record. */ + public long softTtl; + + /** Headers from the response resulting in this cache entry. */ + public Map responseHeaders; + + private CacheHeader() { } + + /** + * Instantiates a new CacheHeader object + * @param key The key that identifies the cache entry + * @param entry The cache entry. + */ + public CacheHeader(String key, Entry entry) { + this.key = key; + this.size = entry.data.length; + this.etag = entry.etag; + this.serverDate = entry.serverDate; + this.lastModified = entry.lastModified; + this.ttl = entry.ttl; + this.softTtl = entry.softTtl; + this.responseHeaders = entry.responseHeaders; + } + + /** + * Reads the header off of an InputStream and returns a CacheHeader object. + * @param is The InputStream to read from. + * @throws IOException + */ + public static CacheHeader readHeader(InputStream is) throws IOException { + CacheHeader entry = new CacheHeader(); + int magic = readInt(is); + if (magic != CACHE_MAGIC) { + // don't bother deleting, it'll get pruned eventually + throw new IOException(); + } + entry.key = readString(is); + entry.etag = readString(is); + if (entry.etag.equals("")) { + entry.etag = null; + } + entry.serverDate = readLong(is); + entry.lastModified = readLong(is); + entry.ttl = readLong(is); + entry.softTtl = readLong(is); + entry.responseHeaders = readStringStringMap(is); + + return entry; + } + + /** + * Creates a cache entry for the specified data. + */ + public Entry toCacheEntry(byte[] data) { + Entry e = new Entry(); + e.data = data; + e.etag = etag; + e.serverDate = serverDate; + e.lastModified = lastModified; + e.ttl = ttl; + e.softTtl = softTtl; + e.responseHeaders = responseHeaders; + return e; + } + + + /** + * Writes the contents of this CacheHeader to the specified OutputStream. + */ + public boolean writeHeader(OutputStream os) { + try { + writeInt(os, CACHE_MAGIC); + writeString(os, key); + writeString(os, etag == null ? "" : etag); + writeLong(os, serverDate); + writeLong(os, lastModified); + writeLong(os, ttl); + writeLong(os, softTtl); + writeStringStringMap(responseHeaders, os); + os.flush(); + return true; + } catch (IOException e) { + VolleyLog.d("%s", e.toString()); + return false; + } + } + + } + + private static class CountingInputStream extends FilterInputStream { + private int bytesRead = 0; + + private CountingInputStream(InputStream in) { + super(in); + } + + @Override + public int read() throws IOException { + int result = super.read(); + if (result != -1) { + bytesRead++; + } + return result; + } + + @Override + public int read(byte[] buffer, int offset, int count) throws IOException { + int result = super.read(buffer, offset, count); + if (result != -1) { + bytesRead += result; + } + return result; + } + } + + /* + * Homebrewed simple serialization system used for reading and writing cache + * headers on disk. Once upon a time, this used the standard Java + * Object{Input,Output}Stream, but the default implementation relies heavily + * on reflection (even for standard types) and generates a ton of garbage. + */ + + /** + * Simple wrapper around {@link InputStream#read()} that throws EOFException + * instead of returning -1. + */ + private static int read(InputStream is) throws IOException { + int b = is.read(); + if (b == -1) { + throw new EOFException(); + } + return b; + } + + static void writeInt(OutputStream os, int n) throws IOException { + os.write((n >> 0) & 0xff); + os.write((n >> 8) & 0xff); + os.write((n >> 16) & 0xff); + os.write((n >> 24) & 0xff); + } + + static int readInt(InputStream is) throws IOException { + int n = 0; + n |= (read(is) << 0); + n |= (read(is) << 8); + n |= (read(is) << 16); + n |= (read(is) << 24); + return n; + } + + static void writeLong(OutputStream os, long n) throws IOException { + os.write((byte)(n >>> 0)); + os.write((byte)(n >>> 8)); + os.write((byte)(n >>> 16)); + os.write((byte)(n >>> 24)); + os.write((byte)(n >>> 32)); + os.write((byte)(n >>> 40)); + os.write((byte)(n >>> 48)); + os.write((byte)(n >>> 56)); + } + + static long readLong(InputStream is) throws IOException { + long n = 0; + n |= ((read(is) & 0xFFL) << 0); + n |= ((read(is) & 0xFFL) << 8); + n |= ((read(is) & 0xFFL) << 16); + n |= ((read(is) & 0xFFL) << 24); + n |= ((read(is) & 0xFFL) << 32); + n |= ((read(is) & 0xFFL) << 40); + n |= ((read(is) & 0xFFL) << 48); + n |= ((read(is) & 0xFFL) << 56); + return n; + } + + static void writeString(OutputStream os, String s) throws IOException { + byte[] b = s.getBytes("UTF-8"); + writeLong(os, b.length); + os.write(b, 0, b.length); + } + + static String readString(InputStream is) throws IOException { + int n = (int) readLong(is); + byte[] b = streamToBytes(is, n); + return new String(b, "UTF-8"); + } + + static void writeStringStringMap(Map map, OutputStream os) throws IOException { + if (map != null) { + writeInt(os, map.size()); + for (Map.Entry entry : map.entrySet()) { + writeString(os, entry.getKey()); + writeString(os, entry.getValue()); + } + } else { + writeInt(os, 0); + } + } + + static Map readStringStringMap(InputStream is) throws IOException { + int size = readInt(is); + Map result = (size == 0) + ? Collections.emptyMap() + : new HashMap(size); + for (int i = 0; i < size; i++) { + String key = readString(is).intern(); + String value = readString(is).intern(); + result.put(key, value); + } + return result; + } + + +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HttpClientStack.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HttpClientStack.java new file mode 100644 index 00000000..4827ada7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HttpClientStack.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import org.telegram.messenger.volley.AuthFailureError; +import org.telegram.messenger.volley.Request; +import org.telegram.messenger.volley.Request.Method; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpHead; +import org.apache.http.client.methods.HttpOptions; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpTrace; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.params.HttpConnectionParams; +import org.apache.http.params.HttpParams; + +import java.io.IOException; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * An HttpStack that performs request over an {@link HttpClient}. + */ +public class HttpClientStack implements HttpStack { + protected final HttpClient mClient; + + private final static String HEADER_CONTENT_TYPE = "Content-Type"; + + public HttpClientStack(HttpClient client) { + mClient = client; + } + + private static void addHeaders(HttpUriRequest httpRequest, Map headers) { + for (String key : headers.keySet()) { + httpRequest.setHeader(key, headers.get(key)); + } + } + + @SuppressWarnings("unused") + private static List getPostParameterPairs(Map postParams) { + List result = new ArrayList(postParams.size()); + for (String key : postParams.keySet()) { + result.add(new BasicNameValuePair(key, postParams.get(key))); + } + return result; + } + + @Override + public HttpResponse performRequest(Request request, Map additionalHeaders) + throws IOException, AuthFailureError { + HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders); + addHeaders(httpRequest, additionalHeaders); + addHeaders(httpRequest, request.getHeaders()); + onPrepareRequest(httpRequest); + HttpParams httpParams = httpRequest.getParams(); + int timeoutMs = request.getTimeoutMs(); + // TODO: Reevaluate this connection timeout based on more wide-scale + // data collection and possibly different for wifi vs. 3G. + HttpConnectionParams.setConnectionTimeout(httpParams, 5000); + HttpConnectionParams.setSoTimeout(httpParams, timeoutMs); + return mClient.execute(httpRequest); + } + + /** + * Creates the appropriate subclass of HttpUriRequest for passed in request. + */ + @SuppressWarnings("deprecation") + /* protected */ static HttpUriRequest createHttpRequest(Request request, + Map additionalHeaders) throws AuthFailureError { + switch (request.getMethod()) { + case Method.DEPRECATED_GET_OR_POST: { + // This is the deprecated way that needs to be handled for backwards compatibility. + // If the request's post body is null, then the assumption is that the request is + // GET. Otherwise, it is assumed that the request is a POST. + byte[] postBody = request.getPostBody(); + if (postBody != null) { + HttpPost postRequest = new HttpPost(request.getUrl()); + postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType()); + HttpEntity entity; + entity = new ByteArrayEntity(postBody); + postRequest.setEntity(entity); + return postRequest; + } else { + return new HttpGet(request.getUrl()); + } + } + case Method.GET: + return new HttpGet(request.getUrl()); + case Method.DELETE: + return new HttpDelete(request.getUrl()); + case Method.POST: { + HttpPost postRequest = new HttpPost(request.getUrl()); + postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); + setEntityIfNonEmptyBody(postRequest, request); + return postRequest; + } + case Method.PUT: { + HttpPut putRequest = new HttpPut(request.getUrl()); + putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); + setEntityIfNonEmptyBody(putRequest, request); + return putRequest; + } + case Method.HEAD: + return new HttpHead(request.getUrl()); + case Method.OPTIONS: + return new HttpOptions(request.getUrl()); + case Method.TRACE: + return new HttpTrace(request.getUrl()); + case Method.PATCH: { + HttpPatch patchRequest = new HttpPatch(request.getUrl()); + patchRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType()); + setEntityIfNonEmptyBody(patchRequest, request); + return patchRequest; + } + default: + throw new IllegalStateException("Unknown request method."); + } + } + + private static void setEntityIfNonEmptyBody(HttpEntityEnclosingRequestBase httpRequest, + Request request) throws AuthFailureError { + byte[] body = request.getBody(); + if (body != null) { + HttpEntity entity = new ByteArrayEntity(body); + httpRequest.setEntity(entity); + } + } + + /** + * Called before the request is executed using the underlying HttpClient. + * + *

Overwrite in subclasses to augment the request.

+ */ + protected void onPrepareRequest(HttpUriRequest request) throws IOException { + // Nothing. + } + + /** + * The HttpPatch class does not exist in the Android framework, so this has been defined here. + */ + public static final class HttpPatch extends HttpEntityEnclosingRequestBase { + + public final static String METHOD_NAME = "PATCH"; + + public HttpPatch() { + super(); + } + + public HttpPatch(final URI uri) { + super(); + setURI(uri); + } + + /** + * @throws IllegalArgumentException if the uri is invalid. + */ + public HttpPatch(final String uri) { + super(); + setURI(URI.create(uri)); + } + + @Override + public String getMethod() { + return METHOD_NAME; + } + + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HttpHeaderParser.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HttpHeaderParser.java new file mode 100644 index 00000000..9aefea93 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HttpHeaderParser.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import org.telegram.messenger.volley.Cache; +import org.telegram.messenger.volley.NetworkResponse; + +import org.apache.http.impl.cookie.DateParseException; +import org.apache.http.impl.cookie.DateUtils; +import org.apache.http.protocol.HTTP; + +import java.util.Map; + +/** + * Utility methods for parsing HTTP headers. + */ +public class HttpHeaderParser { + + /** + * Extracts a {@link Cache.Entry} from a {@link NetworkResponse}. + * + * @param response The network response to parse headers from + * @return a cache entry for the given response, or null if the response is not cacheable. + */ + public static Cache.Entry parseCacheHeaders(NetworkResponse response) { + long now = System.currentTimeMillis(); + + Map headers = response.headers; + + long serverDate = 0; + long lastModified = 0; + long serverExpires = 0; + long softExpire = 0; + long finalExpire = 0; + long maxAge = 0; + long staleWhileRevalidate = 0; + boolean hasCacheControl = false; + boolean mustRevalidate = false; + + String serverEtag = null; + String headerValue; + + headerValue = headers.get("Date"); + if (headerValue != null) { + serverDate = parseDateAsEpoch(headerValue); + } + + headerValue = headers.get("Cache-Control"); + if (headerValue != null) { + hasCacheControl = true; + String[] tokens = headerValue.split(","); + for (int i = 0; i < tokens.length; i++) { + String token = tokens[i].trim(); + if (token.equals("no-cache") || token.equals("no-store")) { + return null; + } else if (token.startsWith("max-age=")) { + try { + maxAge = Long.parseLong(token.substring(8)); + } catch (Exception e) { + } + } else if (token.startsWith("stale-while-revalidate=")) { + try { + staleWhileRevalidate = Long.parseLong(token.substring(23)); + } catch (Exception e) { + } + } else if (token.equals("must-revalidate") || token.equals("proxy-revalidate")) { + mustRevalidate = true; + } + } + } + + headerValue = headers.get("Expires"); + if (headerValue != null) { + serverExpires = parseDateAsEpoch(headerValue); + } + + headerValue = headers.get("Last-Modified"); + if (headerValue != null) { + lastModified = parseDateAsEpoch(headerValue); + } + + serverEtag = headers.get("ETag"); + + // Cache-Control takes precedence over an Expires header, even if both exist and Expires + // is more restrictive. + if (hasCacheControl) { + softExpire = now + maxAge * 1000; + finalExpire = mustRevalidate + ? softExpire + : softExpire + staleWhileRevalidate * 1000; + } else if (serverDate > 0 && serverExpires >= serverDate) { + // Default semantic for Expire header in HTTP specification is softExpire. + softExpire = now + (serverExpires - serverDate); + finalExpire = softExpire; + } + + Cache.Entry entry = new Cache.Entry(); + entry.data = response.data; + entry.etag = serverEtag; + entry.softTtl = softExpire; + entry.ttl = finalExpire; + entry.serverDate = serverDate; + entry.lastModified = lastModified; + entry.responseHeaders = headers; + + return entry; + } + + /** + * Parse date in RFC1123 format, and return its value as epoch + */ + public static long parseDateAsEpoch(String dateStr) { + try { + // Parse date in RFC1123 format if this header contains one + return DateUtils.parseDate(dateStr).getTime(); + } catch (DateParseException e) { + // Date in invalid format, fallback to 0 + return 0; + } + } + + /** + * Retrieve a charset from headers + * + * @param headers An {@link java.util.Map} of headers + * @param defaultCharset Charset to return if none can be found + * @return Returns the charset specified in the Content-Type of this header, + * or the defaultCharset if none can be found. + */ + public static String parseCharset(Map headers, String defaultCharset) { + String contentType = headers.get(HTTP.CONTENT_TYPE); + if (contentType != null) { + String[] params = contentType.split(";"); + for (int i = 1; i < params.length; i++) { + String[] pair = params[i].trim().split("="); + if (pair.length == 2) { + if (pair[0].equals("charset")) { + return pair[1]; + } + } + } + } + + return defaultCharset; + } + + /** + * Returns the charset specified in the Content-Type of this header, + * or the HTTP default (ISO-8859-1) if none can be found. + */ + public static String parseCharset(Map headers) { + return parseCharset(headers, HTTP.DEFAULT_CONTENT_CHARSET); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HttpStack.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HttpStack.java new file mode 100644 index 00000000..253c1a70 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HttpStack.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import org.telegram.messenger.volley.AuthFailureError; +import org.telegram.messenger.volley.Request; + +import org.apache.http.HttpResponse; + +import java.io.IOException; +import java.util.Map; + +/** + * An HTTP stack abstraction. + */ +public interface HttpStack { + /** + * Performs an HTTP request with the given parameters. + * + *

A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise, + * and the Content-Type header is set to request.getPostBodyContentType().

+ * + * @param request the request to perform + * @param additionalHeaders additional headers to be sent together with + * {@link Request#getHeaders()} + * @return the HTTP response + */ + public HttpResponse performRequest(Request request, Map additionalHeaders) + throws IOException, AuthFailureError; + +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HurlStack.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HurlStack.java new file mode 100644 index 00000000..83b1d338 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/HurlStack.java @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import org.telegram.messenger.volley.AuthFailureError; +import org.telegram.messenger.volley.Request; +import org.telegram.messenger.volley.Request.Method; + +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.ProtocolVersion; +import org.apache.http.StatusLine; +import org.apache.http.entity.BasicHttpEntity; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicHttpResponse; +import org.apache.http.message.BasicStatusLine; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSocketFactory; + +/** + * An {@link HttpStack} based on {@link HttpURLConnection}. + */ +public class HurlStack implements HttpStack { + + private static final String HEADER_CONTENT_TYPE = "Content-Type"; + + /** + * An interface for transforming URLs before use. + */ + public interface UrlRewriter { + /** + * Returns a URL to use instead of the provided one, or null to indicate + * this URL should not be used at all. + */ + public String rewriteUrl(String originalUrl); + } + + private final UrlRewriter mUrlRewriter; + private final SSLSocketFactory mSslSocketFactory; + + public HurlStack() { + this(null); + } + + /** + * @param urlRewriter Rewriter to use for request URLs + */ + public HurlStack(UrlRewriter urlRewriter) { + this(urlRewriter, null); + } + + /** + * @param urlRewriter Rewriter to use for request URLs + * @param sslSocketFactory SSL factory to use for HTTPS connections + */ + public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) { + mUrlRewriter = urlRewriter; + mSslSocketFactory = sslSocketFactory; + } + + @Override + public HttpResponse performRequest(Request request, Map additionalHeaders) + throws IOException, AuthFailureError { + String url = request.getUrl(); + HashMap map = new HashMap(); + map.putAll(request.getHeaders()); + map.putAll(additionalHeaders); + if (mUrlRewriter != null) { + String rewritten = mUrlRewriter.rewriteUrl(url); + if (rewritten == null) { + throw new IOException("URL blocked by rewriter: " + url); + } + url = rewritten; + } + URL parsedUrl = new URL(url); + HttpURLConnection connection = openConnection(parsedUrl, request); + for (String headerName : map.keySet()) { + connection.addRequestProperty(headerName, map.get(headerName)); + } + setConnectionParametersForRequest(connection, request); + // Initialize HttpResponse with data from the HttpURLConnection. + ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1); + int responseCode = connection.getResponseCode(); + if (responseCode == -1) { + // -1 is returned by getResponseCode() if the response code could not be retrieved. + // Signal to the caller that something was wrong with the connection. + throw new IOException("Could not retrieve response code from HttpUrlConnection."); + } + StatusLine responseStatus = new BasicStatusLine(protocolVersion, + connection.getResponseCode(), connection.getResponseMessage()); + BasicHttpResponse response = new BasicHttpResponse(responseStatus); + if (hasResponseBody(request.getMethod(), responseStatus.getStatusCode())) { + response.setEntity(entityFromConnection(connection)); + } + for (Entry> header : connection.getHeaderFields().entrySet()) { + if (header.getKey() != null) { + Header h = new BasicHeader(header.getKey(), header.getValue().get(0)); + response.addHeader(h); + } + } + return response; + } + + /** + * Checks if a response message contains a body. + * @see RFC 7230 section 3.3 + * @param requestMethod request method + * @param responseCode response status code + * @return whether the response has a body + */ + private static boolean hasResponseBody(int requestMethod, int responseCode) { + return requestMethod != Request.Method.HEAD + && !(HttpStatus.SC_CONTINUE <= responseCode && responseCode < HttpStatus.SC_OK) + && responseCode != HttpStatus.SC_NO_CONTENT + && responseCode != HttpStatus.SC_NOT_MODIFIED; + } + + /** + * Initializes an {@link HttpEntity} from the given {@link HttpURLConnection}. + * @param connection + * @return an HttpEntity populated with data from connection. + */ + private static HttpEntity entityFromConnection(HttpURLConnection connection) { + BasicHttpEntity entity = new BasicHttpEntity(); + InputStream inputStream; + try { + inputStream = connection.getInputStream(); + } catch (IOException ioe) { + inputStream = connection.getErrorStream(); + } + entity.setContent(inputStream); + entity.setContentLength(connection.getContentLength()); + entity.setContentEncoding(connection.getContentEncoding()); + entity.setContentType(connection.getContentType()); + return entity; + } + + /** + * Create an {@link HttpURLConnection} for the specified {@code url}. + */ + protected HttpURLConnection createConnection(URL url) throws IOException { + return (HttpURLConnection) url.openConnection(); + } + + /** + * Opens an {@link HttpURLConnection} with parameters. + * @param url + * @return an open connection + * @throws IOException + */ + private HttpURLConnection openConnection(URL url, Request request) throws IOException { + HttpURLConnection connection = createConnection(url); + + int timeoutMs = request.getTimeoutMs(); + connection.setConnectTimeout(timeoutMs); + connection.setReadTimeout(timeoutMs); + connection.setUseCaches(false); + connection.setDoInput(true); + + // use caller-provided custom SslSocketFactory, if any, for HTTPS + if ("https".equals(url.getProtocol()) && mSslSocketFactory != null) { + ((HttpsURLConnection)connection).setSSLSocketFactory(mSslSocketFactory); + } + + return connection; + } + + @SuppressWarnings("deprecation") + /* package */ static void setConnectionParametersForRequest(HttpURLConnection connection, + Request request) throws IOException, AuthFailureError { + switch (request.getMethod()) { + case Method.DEPRECATED_GET_OR_POST: + // This is the deprecated way that needs to be handled for backwards compatibility. + // If the request's post body is null, then the assumption is that the request is + // GET. Otherwise, it is assumed that the request is a POST. + byte[] postBody = request.getPostBody(); + if (postBody != null) { + // Prepare output. There is no need to set Content-Length explicitly, + // since this is handled by HttpURLConnection using the size of the prepared + // output stream. + connection.setDoOutput(true); + connection.setRequestMethod("POST"); + connection.addRequestProperty(HEADER_CONTENT_TYPE, + request.getPostBodyContentType()); + DataOutputStream out = new DataOutputStream(connection.getOutputStream()); + out.write(postBody); + out.close(); + } + break; + case Method.GET: + // Not necessary to set the request method because connection defaults to GET but + // being explicit here. + connection.setRequestMethod("GET"); + break; + case Method.DELETE: + connection.setRequestMethod("DELETE"); + break; + case Method.POST: + connection.setRequestMethod("POST"); + addBodyIfExists(connection, request); + break; + case Method.PUT: + connection.setRequestMethod("PUT"); + addBodyIfExists(connection, request); + break; + case Method.HEAD: + connection.setRequestMethod("HEAD"); + break; + case Method.OPTIONS: + connection.setRequestMethod("OPTIONS"); + break; + case Method.TRACE: + connection.setRequestMethod("TRACE"); + break; + case Method.PATCH: + connection.setRequestMethod("PATCH"); + addBodyIfExists(connection, request); + break; + default: + throw new IllegalStateException("Unknown method type."); + } + } + + private static void addBodyIfExists(HttpURLConnection connection, Request request) + throws IOException, AuthFailureError { + byte[] body = request.getBody(); + if (body != null) { + connection.setDoOutput(true); + connection.addRequestProperty(HEADER_CONTENT_TYPE, request.getBodyContentType()); + DataOutputStream out = new DataOutputStream(connection.getOutputStream()); + out.write(body); + out.close(); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/JsonArrayRequest.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/JsonArrayRequest.java new file mode 100644 index 00000000..7206d7f2 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/JsonArrayRequest.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import org.telegram.messenger.volley.NetworkResponse; +import org.telegram.messenger.volley.ParseError; +import org.telegram.messenger.volley.Response; +import org.telegram.messenger.volley.Response.ErrorListener; +import org.telegram.messenger.volley.Response.Listener; + +import org.json.JSONArray; +import org.json.JSONException; + +import java.io.UnsupportedEncodingException; + +/** + * A request for retrieving a {@link JSONArray} response body at a given URL. + */ +public class JsonArrayRequest extends JsonRequest { + + /** + * Creates a new request. + * @param url URL to fetch the JSON from + * @param listener Listener to receive the JSON response + * @param errorListener Error listener, or null to ignore errors. + */ + public JsonArrayRequest(String url, Listener listener, ErrorListener errorListener) { + super(Method.GET, url, null, listener, errorListener); + } + + /** + * Creates a new request. + * @param method the HTTP method to use + * @param url URL to fetch the JSON from + * @param jsonRequest A {@link JSONArray} to post with the request. Null is allowed and + * indicates no parameters will be posted along with request. + * @param listener Listener to receive the JSON response + * @param errorListener Error listener, or null to ignore errors. + */ + public JsonArrayRequest(int method, String url, JSONArray jsonRequest, + Listener listener, ErrorListener errorListener) { + super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener, + errorListener); + } + + @Override + protected Response parseNetworkResponse(NetworkResponse response) { + try { + String jsonString = new String(response.data, + HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET)); + return Response.success(new JSONArray(jsonString), + HttpHeaderParser.parseCacheHeaders(response)); + } catch (UnsupportedEncodingException e) { + return Response.error(new ParseError(e)); + } catch (JSONException je) { + return Response.error(new ParseError(je)); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/JsonObjectRequest.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/JsonObjectRequest.java new file mode 100644 index 00000000..e6ba9808 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/JsonObjectRequest.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import org.telegram.messenger.volley.NetworkResponse; +import org.telegram.messenger.volley.ParseError; +import org.telegram.messenger.volley.Response; +import org.telegram.messenger.volley.Response.ErrorListener; +import org.telegram.messenger.volley.Response.Listener; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.UnsupportedEncodingException; + +/** + * A request for retrieving a {@link JSONObject} response body at a given URL, allowing for an + * optional {@link JSONObject} to be passed in as part of the request body. + */ +public class JsonObjectRequest extends JsonRequest { + + /** + * Creates a new request. + * @param method the HTTP method to use + * @param url URL to fetch the JSON from + * @param jsonRequest A {@link JSONObject} to post with the request. Null is allowed and + * indicates no parameters will be posted along with request. + * @param listener Listener to receive the JSON response + * @param errorListener Error listener, or null to ignore errors. + */ + public JsonObjectRequest(int method, String url, JSONObject jsonRequest, + Listener listener, ErrorListener errorListener) { + super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener, + errorListener); + } + + /** + * Constructor which defaults to GET if jsonRequest is + * null, POST otherwise. + * + * @see #JsonObjectRequest(int, String, JSONObject, Listener, ErrorListener) + */ + public JsonObjectRequest(String url, JSONObject jsonRequest, Listener listener, + ErrorListener errorListener) { + this(jsonRequest == null ? Method.GET : Method.POST, url, jsonRequest, + listener, errorListener); + } + + @Override + protected Response parseNetworkResponse(NetworkResponse response) { + try { + String jsonString = new String(response.data, + HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET)); + return Response.success(new JSONObject(jsonString), + HttpHeaderParser.parseCacheHeaders(response)); + } catch (UnsupportedEncodingException e) { + return Response.error(new ParseError(e)); + } catch (JSONException je) { + return Response.error(new ParseError(je)); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/JsonRequest.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/JsonRequest.java new file mode 100644 index 00000000..8233d35f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/JsonRequest.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import org.telegram.messenger.volley.NetworkResponse; +import org.telegram.messenger.volley.Request; +import org.telegram.messenger.volley.Response; +import org.telegram.messenger.volley.Response.ErrorListener; +import org.telegram.messenger.volley.Response.Listener; +import org.telegram.messenger.volley.VolleyLog; + +import java.io.UnsupportedEncodingException; + +/** + * A request for retrieving a T type response body at a given URL that also + * optionally sends along a JSON body in the request specified. + * + * @param JSON type of response expected + */ +public abstract class JsonRequest extends Request { + /** Default charset for JSON request. */ + protected static final String PROTOCOL_CHARSET = "utf-8"; + + /** Content type for request. */ + private static final String PROTOCOL_CONTENT_TYPE = + String.format("application/json; charset=%s", PROTOCOL_CHARSET); + + private final Listener mListener; + private final String mRequestBody; + + /** + * Deprecated constructor for a JsonRequest which defaults to GET unless {@link #getPostBody()} + * or {@link #getPostParams()} is overridden (which defaults to POST). + * + * @deprecated Use {@link #JsonRequest(int, String, String, Listener, ErrorListener)}. + */ + public JsonRequest(String url, String requestBody, Listener listener, + ErrorListener errorListener) { + this(Method.DEPRECATED_GET_OR_POST, url, requestBody, listener, errorListener); + } + + public JsonRequest(int method, String url, String requestBody, Listener listener, + ErrorListener errorListener) { + super(method, url, errorListener); + mListener = listener; + mRequestBody = requestBody; + } + + @Override + protected void deliverResponse(T response) { + mListener.onResponse(response); + } + + @Override + abstract protected Response parseNetworkResponse(NetworkResponse response); + + /** + * @deprecated Use {@link #getBodyContentType()}. + */ + @Override + public String getPostBodyContentType() { + return getBodyContentType(); + } + + /** + * @deprecated Use {@link #getBody()}. + */ + @Override + public byte[] getPostBody() { + return getBody(); + } + + @Override + public String getBodyContentType() { + return PROTOCOL_CONTENT_TYPE; + } + + @Override + public byte[] getBody() { + try { + return mRequestBody == null ? null : mRequestBody.getBytes(PROTOCOL_CHARSET); + } catch (UnsupportedEncodingException uee) { + VolleyLog.wtf("Unsupported Encoding while trying to get the bytes of %s using %s", + mRequestBody, PROTOCOL_CHARSET); + return null; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/NoCache.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/NoCache.java new file mode 100644 index 00000000..8db5f2e7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/NoCache.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import org.telegram.messenger.volley.Cache; + +/** + * A cache that doesn't. + */ +public class NoCache implements Cache { + @Override + public void clear() { + } + + @Override + public Entry get(String key) { + return null; + } + + @Override + public void put(String key, Entry entry) { + } + + @Override + public void invalidate(String key, boolean fullExpire) { + } + + @Override + public void remove(String key) { + } + + @Override + public void initialize() { + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/PoolingByteArrayOutputStream.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/PoolingByteArrayOutputStream.java new file mode 100644 index 00000000..b2f66709 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/PoolingByteArrayOutputStream.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * A variation of {@link java.io.ByteArrayOutputStream} that uses a pool of byte[] buffers instead + * of always allocating them fresh, saving on heap churn. + */ +public class PoolingByteArrayOutputStream extends ByteArrayOutputStream { + /** + * If the {@link #PoolingByteArrayOutputStream(ByteArrayPool)} constructor is called, this is + * the default size to which the underlying byte array is initialized. + */ + private static final int DEFAULT_SIZE = 256; + + private final ByteArrayPool mPool; + + /** + * Constructs a new PoolingByteArrayOutputStream with a default size. If more bytes are written + * to this instance, the underlying byte array will expand. + */ + public PoolingByteArrayOutputStream(ByteArrayPool pool) { + this(pool, DEFAULT_SIZE); + } + + /** + * Constructs a new {@code ByteArrayOutputStream} with a default size of {@code size} bytes. If + * more than {@code size} bytes are written to this instance, the underlying byte array will + * expand. + * + * @param size initial size for the underlying byte array. The value will be pinned to a default + * minimum size. + */ + public PoolingByteArrayOutputStream(ByteArrayPool pool, int size) { + mPool = pool; + buf = mPool.getBuf(Math.max(size, DEFAULT_SIZE)); + } + + @Override + public void close() throws IOException { + mPool.returnBuf(buf); + buf = null; + super.close(); + } + + @Override + public void finalize() { + mPool.returnBuf(buf); + } + + /** + * Ensures there is enough space in the buffer for the given number of additional bytes. + */ + private void expand(int i) { + /* Can the buffer handle @i more bytes, if not expand it */ + if (count + i <= buf.length) { + return; + } + byte[] newbuf = mPool.getBuf((count + i) * 2); + System.arraycopy(buf, 0, newbuf, 0, count); + mPool.returnBuf(buf); + buf = newbuf; + } + + @Override + public synchronized void write(byte[] buffer, int offset, int len) { + expand(len); + super.write(buffer, offset, len); + } + + @Override + public synchronized void write(int oneByte) { + expand(1); + super.write(oneByte); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/RequestFuture.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/RequestFuture.java new file mode 100644 index 00000000..2badb860 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/RequestFuture.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import org.telegram.messenger.volley.Request; +import org.telegram.messenger.volley.Response; +import org.telegram.messenger.volley.VolleyError; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +/** + * A Future that represents a Volley request. + * + * Used by providing as your response and error listeners. For example: + *
+ * RequestFuture<JSONObject> future = RequestFuture.newFuture();
+ * MyRequest request = new MyRequest(URL, future, future);
+ *
+ * // If you want to be able to cancel the request:
+ * future.setRequest(requestQueue.add(request));
+ *
+ * // Otherwise:
+ * requestQueue.add(request);
+ *
+ * try {
+ *   JSONObject response = future.get();
+ *   // do something with response
+ * } catch (InterruptedException e) {
+ *   // handle the error
+ * } catch (ExecutionException e) {
+ *   // handle the error
+ * }
+ * 
+ * + * @param The type of parsed response this future expects. + */ +public class RequestFuture implements Future, Response.Listener, + Response.ErrorListener { + private Request mRequest; + private boolean mResultReceived = false; + private T mResult; + private VolleyError mException; + + public static RequestFuture newFuture() { + return new RequestFuture(); + } + + private RequestFuture() {} + + public void setRequest(Request request) { + mRequest = request; + } + + @Override + public synchronized boolean cancel(boolean mayInterruptIfRunning) { + if (mRequest == null) { + return false; + } + + if (!isDone()) { + mRequest.cancel(); + return true; + } else { + return false; + } + } + + @Override + public T get() throws InterruptedException, ExecutionException { + try { + return doGet(null); + } catch (TimeoutException e) { + throw new AssertionError(e); + } + } + + @Override + public T get(long timeout, TimeUnit unit) + throws InterruptedException, ExecutionException, TimeoutException { + return doGet(TimeUnit.MILLISECONDS.convert(timeout, unit)); + } + + private synchronized T doGet(Long timeoutMs) + throws InterruptedException, ExecutionException, TimeoutException { + if (mException != null) { + throw new ExecutionException(mException); + } + + if (mResultReceived) { + return mResult; + } + + if (timeoutMs == null) { + wait(0); + } else if (timeoutMs > 0) { + wait(timeoutMs); + } + + if (mException != null) { + throw new ExecutionException(mException); + } + + if (!mResultReceived) { + throw new TimeoutException(); + } + + return mResult; + } + + @Override + public boolean isCancelled() { + if (mRequest == null) { + return false; + } + return mRequest.isCanceled(); + } + + @Override + public synchronized boolean isDone() { + return mResultReceived || mException != null || isCancelled(); + } + + @Override + public synchronized void onResponse(T response) { + mResultReceived = true; + mResult = response; + notifyAll(); + } + + @Override + public synchronized void onErrorResponse(VolleyError error) { + mException = error; + notifyAll(); + } +} + diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/StringRequest.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/StringRequest.java new file mode 100644 index 00000000..3a7f9150 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/StringRequest.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import org.telegram.messenger.volley.NetworkResponse; +import org.telegram.messenger.volley.Request; +import org.telegram.messenger.volley.Response; +import org.telegram.messenger.volley.Response.ErrorListener; +import org.telegram.messenger.volley.Response.Listener; + +import java.io.UnsupportedEncodingException; + +/** + * A canned request for retrieving the response body at a given URL as a String. + */ +public class StringRequest extends Request { + private final Listener mListener; + + /** + * Creates a new request with the given method. + * + * @param method the request {@link Method} to use + * @param url URL to fetch the string at + * @param listener Listener to receive the String response + * @param errorListener Error listener, or null to ignore errors + */ + public StringRequest(int method, String url, Listener listener, + ErrorListener errorListener) { + super(method, url, errorListener); + mListener = listener; + } + + /** + * Creates a new GET request. + * + * @param url URL to fetch the string at + * @param listener Listener to receive the String response + * @param errorListener Error listener, or null to ignore errors + */ + public StringRequest(String url, Listener listener, ErrorListener errorListener) { + this(Method.GET, url, listener, errorListener); + } + + @Override + protected void deliverResponse(String response) { + mListener.onResponse(response); + } + + @Override + protected Response parseNetworkResponse(NetworkResponse response) { + String parsed; + try { + parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); + } catch (UnsupportedEncodingException e) { + parsed = new String(response.data); + } + return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response)); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/Volley.java b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/Volley.java new file mode 100644 index 00000000..9038d507 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/messenger/volley/toolbox/Volley.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.telegram.messenger.volley.toolbox; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.net.http.AndroidHttpClient; +import android.os.Build; + +import org.telegram.messenger.volley.Network; +import org.telegram.messenger.volley.RequestQueue; + +import java.io.File; + +public class Volley { + + /** Default on-disk cache directory. */ + private static final String DEFAULT_CACHE_DIR = "volley"; + + /** + * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it. + * + * @param context A {@link Context} to use for creating the cache dir. + * @param stack An {@link HttpStack} to use for the network, or null for default. + * @return A started {@link RequestQueue} instance. + */ + public static RequestQueue newRequestQueue(Context context, HttpStack stack) { + File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR); + + String userAgent = "volley/0"; + try { + String packageName = context.getPackageName(); + PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); + userAgent = packageName + "/" + info.versionCode; + } catch (NameNotFoundException e) { + } + + if (stack == null) { + if (Build.VERSION.SDK_INT >= 9) { + stack = new HurlStack(); + } else { + // Prior to Gingerbread, HttpUrlConnection was unreliable. + // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html + stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); + } + } + + Network network = new BasicNetwork(stack); + + RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network); + queue.start(); + + return queue; + } + + /** + * Creates a default instance of the worker pool and calls {@link RequestQueue#start()} on it. + * + * @param context A {@link Context} to use for creating the cache dir. + * @return A started {@link RequestQueue} instance. + */ + public static RequestQueue newRequestQueue(Context context) { + return newRequestQueue(context, null); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/AbstractSerializedData.java b/TMessagesProj/src/main/java/org/telegram/tgnet/AbstractSerializedData.java new file mode 100644 index 00000000..19409cac --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/AbstractSerializedData.java @@ -0,0 +1,52 @@ +package org.telegram.tgnet; + +public abstract class AbstractSerializedData { + + public abstract void writeInt32(int x); + + public abstract void writeInt64(long x); + + public abstract void writeBool(boolean value); + + public abstract void writeBytes(byte[] b); + + public abstract void writeBytes(byte[] b, int offset, int count); + + public abstract void writeByte(int i); + + public abstract void writeByte(byte b); + + public abstract void writeString(String s); + + public abstract void writeByteArray(byte[] b, int offset, int count); + + public abstract void writeByteArray(byte[] b); + + public abstract void writeDouble(double d); + + public abstract void writeByteBuffer(NativeByteBuffer buffer); + + public abstract int readInt32(boolean exception); + + public abstract boolean readBool(boolean exception); + + public abstract long readInt64(boolean exception); + + public abstract void readBytes(byte[] b, boolean exception); + + public abstract byte[] readData(int count, boolean exception); + + public abstract String readString(boolean exception); + + public abstract byte[] readByteArray(boolean exception); + + public abstract NativeByteBuffer readByteBuffer(boolean exception); + + public abstract double readDouble(boolean exception); + + public abstract int length(); + + public abstract void skip(int count); + + public abstract int getPosition(); +} diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java new file mode 100644 index 00000000..e6a5f08b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/ConnectionsManager.java @@ -0,0 +1,525 @@ +package org.telegram.tgnet; + +import android.annotation.SuppressLint; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Build; +import android.os.PowerManager; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; + +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.NetworkInterface; +import java.util.Enumeration; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +public class ConnectionsManager { + + public final static int ConnectionTypeGeneric = 1; + public final static int ConnectionTypeDownload = 2; + public final static int ConnectionTypeUpload = 4; + public final static int ConnectionTypePush = 8; + public final static int ConnectionTypeDownload2 = ConnectionTypeDownload | (1 << 16); + + public final static int RequestFlagEnableUnauthorized = 1; + public final static int RequestFlagFailOnServerErrors = 2; + public final static int RequestFlagCanCompress = 4; + public final static int RequestFlagWithoutLogin = 8; + public final static int RequestFlagTryDifferentDc = 16; + public final static int RequestFlagForceDownload = 32; + public final static int RequestFlagInvokeAfter = 64; + public final static int RequestFlagNeedQuickAck = 128; + + public final static int ConnectionStateConnecting = 1; + public final static int ConnectionStateWaitingForNetwork = 2; + public final static int ConnectionStateConnected = 3; + public final static int ConnectionStateUpdating = 4; + + public final static int DEFAULT_DATACENTER_ID = Integer.MAX_VALUE; + + private long lastPauseTime = System.currentTimeMillis(); + private boolean appPaused = true; + private int lastClassGuid = 1; + private boolean isUpdating = false; + private int connectionState = native_getConnectionState(); + private AtomicInteger lastRequestToken = new AtomicInteger(1); + private PowerManager.WakeLock wakeLock = null; + + private static volatile ConnectionsManager Instance = null; + + public static ConnectionsManager getInstance() { + ConnectionsManager localInstance = Instance; + if (localInstance == null) { + synchronized (ConnectionsManager.class) { + localInstance = Instance; + if (localInstance == null) { + Instance = localInstance = new ConnectionsManager(); + } + } + } + return localInstance; + } + + public ConnectionsManager() { + try { + PowerManager pm = (PowerManager) ApplicationLoader.applicationContext.getSystemService(Context.POWER_SERVICE); + wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "lock"); + wakeLock.setReferenceCounted(false); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public long getCurrentTimeMillis() { + return native_getCurrentTimeMillis(); + } + + public int getCurrentTime() { + return native_getCurrentTime(); + } + + public int getTimeDifference() { + return native_getTimeDifference(); + } + + public int sendRequest(TLObject object, RequestDelegate completionBlock) { + return sendRequest(object, completionBlock, null, 0); + } + + public int sendRequest(TLObject object, RequestDelegate completionBlock, int flags) { + return sendRequest(object, completionBlock, null, flags, DEFAULT_DATACENTER_ID, ConnectionTypeGeneric, true); + } + + public int sendRequest(TLObject object, RequestDelegate completionBlock, int flags, int connetionType) { + return sendRequest(object, completionBlock, null, flags, DEFAULT_DATACENTER_ID, connetionType, true); + } + + public int sendRequest(TLObject object, RequestDelegate completionBlock, QuickAckDelegate quickAckBlock, int flags) { + return sendRequest(object, completionBlock, quickAckBlock, flags, DEFAULT_DATACENTER_ID, ConnectionTypeGeneric, true); + } + + public int sendRequest(final TLObject object, final RequestDelegate onComplete, final QuickAckDelegate onQuickAck, final int flags, final int datacenterId, final int connetionType, final boolean immediate) { + final int requestToken = lastRequestToken.getAndIncrement(); + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + FileLog.d("tmessages", "send request " + object + " with token = " + requestToken); + try { + NativeByteBuffer buffer = new NativeByteBuffer(object.getObjectSize()); + object.serializeToStream(buffer); + object.freeResources(); + + native_sendRequest(buffer.address, new RequestDelegateInternal() { + @Override + public void run(int response, int errorCode, String errorText) { + try { + TLObject resp = null; + TLRPC.TL_error error = null; + if (response != 0) { + NativeByteBuffer buff = NativeByteBuffer.wrap(response); + resp = object.deserializeResponse(buff, buff.readInt32(true), true); + } else if (errorText != null) { + error = new TLRPC.TL_error(); + error.code = errorCode; + error.text = errorText; + FileLog.e("tmessages", object + " got error " + error.code + " " + error.text); + } + FileLog.d("tmessages", "java received " + resp + " error = " + error); + final TLObject finalResponse = resp; + final TLRPC.TL_error finalError = error; + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + onComplete.run(finalResponse, finalError); + if (finalResponse != null) { + finalResponse.freeResources(); + } + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }, onQuickAck, flags, datacenterId, connetionType, immediate, requestToken); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + return requestToken; + } + + public void cancelRequest(int token, boolean notifyServer) { + native_cancelRequest(token, notifyServer); + } + + public void cleanUp() { + native_cleanUp(); + } + + public void cancelRequestsForGuid(int guid) { + native_cancelRequestsForGuid(guid); + } + + public void bindRequestToGuid(int requestToken, int guid) { + native_bindRequestToGuid(requestToken, guid); + } + + public void applyDatacenterAddress(int datacenterId, String ipAddress, int port) { + native_applyDatacenterAddress(datacenterId, ipAddress, port); + } + + public int getConnectionState() { + if (connectionState == ConnectionStateConnected && isUpdating) { + return ConnectionStateUpdating; + } + return connectionState; + } + + public void setUserId(int id) { + native_setUserId(id); + } + + private void checkConnection() { + native_setUseIpv6(useIpv6Address()); + native_setNetworkAvailable(isNetworkOnline()); + } + + public void setPushConnectionEnabled(boolean value) { + native_setPushConnectionEnabled(value); + } + + public void init(int version, int layer, int apiId, String deviceModel, String systemVersion, String appVersion, String langCode, String configPath, String logPath, int userId, boolean enablePushConnection) { + native_init(version, layer, apiId, deviceModel, systemVersion, appVersion, langCode, configPath, logPath, userId, enablePushConnection); + checkConnection(); + BroadcastReceiver networkStateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + checkConnection(); + } + }; + IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); + ApplicationLoader.applicationContext.registerReceiver(networkStateReceiver, filter); + } + + public void switchBackend() { + native_switchBackend(); + } + + public void resumeNetworkMaybe() { + native_resumeNetwork(true); + } + + public void updateDcSettings() { + native_updateDcSettings(); + } + + public long getPauseTime() { + return lastPauseTime; + } + + public void setAppPaused(final boolean value, final boolean byScreenState) { + if (!byScreenState) { + appPaused = value; + FileLog.d("tmessages", "app paused = " + value); + } + if (value) { + if (lastPauseTime == 0) { + lastPauseTime = System.currentTimeMillis(); + } + native_pauseNetwork(); + } else { + if (appPaused) { + return; + } + FileLog.e("tmessages", "reset app pause time"); + if (lastPauseTime != 0 && System.currentTimeMillis() - lastPauseTime > 5000) { + ContactsController.getInstance().checkContacts(); + } + lastPauseTime = 0; + native_resumeNetwork(false); + } + } + + public static void onUnparsedMessageReceived(int address) { + try { + NativeByteBuffer buff = NativeByteBuffer.wrap(address); + final TLObject message = TLClassStore.Instance().TLdeserialize(buff, buff.readInt32(true), true); + if (message instanceof TLRPC.Updates) { + FileLog.d("tmessages", "java received " + message); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (getInstance().wakeLock.isHeld()) { + FileLog.d("tmessages", "release wakelock"); + getInstance().wakeLock.release(); + } + } + }); + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().processUpdates((TLRPC.Updates) message, false); + } + }); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public static void onUpdate() { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().updateTimerProc(); + } + }); + } + + public static void onSessionCreated() { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().getDifference(); + } + }); + } + + public static void onConnectionStateChanged(final int state) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + getInstance().connectionState = state; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didUpdatedConnectionState); + } + }); + } + + public static void onLogout() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (UserConfig.getClientUserId() != 0) { + UserConfig.clearConfig(); + MessagesController.getInstance().performLogout(false); + } + } + }); + } + + public static void onUpdateConfig(int address) { + try { + NativeByteBuffer buff = NativeByteBuffer.wrap(address); + final TLRPC.TL_config message = TLRPC.TL_config.TLdeserialize(buff, buff.readInt32(true), true); + if (message != null) { + Utilities.stageQueue.postRunnable(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().updateConfig(message); + } + }); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public static void onInternalPushReceived() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + if (!getInstance().wakeLock.isHeld()) { + getInstance().wakeLock.acquire(10000); + FileLog.d("tmessages", "acquire wakelock"); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public static native void native_switchBackend(); + public static native void native_pauseNetwork(); + public static native void native_setUseIpv6(boolean value); + public static native void native_updateDcSettings(); + public static native void native_setNetworkAvailable(boolean value); + public static native void native_resumeNetwork(boolean partial); + public static native long native_getCurrentTimeMillis(); + public static native int native_getCurrentTime(); + public static native int native_getTimeDifference(); + public static native void native_sendRequest(int object, RequestDelegateInternal onComplete, QuickAckDelegate onQuickAck, int flags, int datacenterId, int connetionType, boolean immediate, int requestToken); + public static native void native_cancelRequest(int token, boolean notifyServer); + public static native void native_cleanUp(); + public static native void native_cancelRequestsForGuid(int guid); + public static native void native_bindRequestToGuid(int requestToken, int guid); + public static native void native_applyDatacenterAddress(int datacenterId, String ipAddress, int port); + public static native int native_getConnectionState(); + public static native void native_setUserId(int id); + public static native void native_init(int version, int layer, int apiId, String deviceModel, String systemVersion, String appVersion, String langCode, String configPath, String logPath, int userId, boolean enablePushConnection); + public static native void native_setJava(boolean useJavaByteBuffers); + public static native void native_setPushConnectionEnabled(boolean value); + + public int generateClassGuid() { + return lastClassGuid++; + } + + public static boolean isRoaming() { + try { + ConnectivityManager cm = (ConnectivityManager) ApplicationLoader.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo netInfo = cm.getActiveNetworkInfo(); + if (netInfo != null) { + return netInfo.isRoaming(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return false; + } + + public static boolean isConnectedToWiFi() { + try { + ConnectivityManager cm = (ConnectivityManager) ApplicationLoader.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo netInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + if (netInfo != null && netInfo.getState() == NetworkInfo.State.CONNECTED) { + return true; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return false; + } + + public void applyCountryPortNumber(String number) { + + } + + public void setIsUpdating(final boolean value) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (isUpdating == value) { + return; + } + isUpdating = value; + if (connectionState == ConnectionStateConnected) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.didUpdatedConnectionState); + } + } + }); + } + + @SuppressLint("NewApi") + protected static boolean useIpv6Address() { + if (Build.VERSION.SDK_INT < 19) { + return false; + } + if (BuildVars.DEBUG_VERSION) { + try { + NetworkInterface networkInterface; + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); + while (networkInterfaces.hasMoreElements()) { + networkInterface = networkInterfaces.nextElement(); + if (!networkInterface.isUp() || networkInterface.isLoopback() || networkInterface.getInterfaceAddresses().isEmpty()) { + continue; + } + FileLog.e("tmessages", "valid interface: " + networkInterface); + List interfaceAddresses = networkInterface.getInterfaceAddresses(); + for (int a = 0; a < interfaceAddresses.size(); a++) { + InterfaceAddress address = interfaceAddresses.get(a); + InetAddress inetAddress = address.getAddress(); + if (BuildVars.DEBUG_VERSION) { + FileLog.e("tmessages", "address: " + inetAddress.getHostAddress()); + } + if (inetAddress.isLinkLocalAddress() || inetAddress.isLoopbackAddress() || inetAddress.isMulticastAddress()) { + continue; + } + if (BuildVars.DEBUG_VERSION) { + FileLog.e("tmessages", "address is good"); + } + } + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + try { + NetworkInterface networkInterface; + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); + boolean hasIpv4 = false; + boolean hasIpv6 = false; + while (networkInterfaces.hasMoreElements()) { + networkInterface = networkInterfaces.nextElement(); + if (!networkInterface.isUp() || networkInterface.isLoopback()) { + continue; + } + List interfaceAddresses = networkInterface.getInterfaceAddresses(); + for (int a = 0; a < interfaceAddresses.size(); a++) { + InterfaceAddress address = interfaceAddresses.get(a); + InetAddress inetAddress = address.getAddress(); + if (inetAddress.isLinkLocalAddress() || inetAddress.isLoopbackAddress() || inetAddress.isMulticastAddress()) { + continue; + } + if (inetAddress instanceof Inet6Address) { + hasIpv6 = true; + } else if (inetAddress instanceof Inet4Address) { + String addrr = inetAddress.getHostAddress(); + if (!addrr.startsWith("192.0.0.")) { + hasIpv4 = true; + } + } + } + } + if (!hasIpv4 && hasIpv6) { + return true; + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + + return false; + } + + public static boolean isNetworkOnline() { + try { + ConnectivityManager cm = (ConnectivityManager) ApplicationLoader.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo netInfo = cm.getActiveNetworkInfo(); + if (netInfo != null && (netInfo.isConnectedOrConnecting() || netInfo.isAvailable())) { + return true; + } + + netInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); + + if (netInfo != null && netInfo.isConnectedOrConnecting()) { + return true; + } else { + netInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + if (netInfo != null && netInfo.isConnectedOrConnecting()) { + return true; + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + return true; + } + return false; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/NativeByteBuffer.java b/TMessagesProj/src/main/java/org/telegram/tgnet/NativeByteBuffer.java new file mode 100644 index 00000000..eddea361 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/NativeByteBuffer.java @@ -0,0 +1,506 @@ +package org.telegram.tgnet; + +import org.telegram.messenger.FileLog; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class NativeByteBuffer extends AbstractSerializedData { + + protected int address; + public ByteBuffer buffer; + private boolean justCalc = false; + private int len = 0; + + private static final ThreadLocal addressWrapper = new ThreadLocal() { + @Override + protected NativeByteBuffer initialValue() { + return new NativeByteBuffer(0, true); + } + }; + + public static NativeByteBuffer wrap(int address) { + NativeByteBuffer result = addressWrapper.get(); + if (address != 0) { + result.address = address; + result.buffer = native_getJavaByteBuffer(address); + result.buffer.limit(native_limit(address)); + int position = native_position(address); + if (position <= result.buffer.limit()) { + result.buffer.position(position); + } else { + FileLog.e("tmessages", "what with position " + position); + } + result.buffer.order(ByteOrder.LITTLE_ENDIAN); + } + return result; + } + + private NativeByteBuffer(int address, boolean wrap) { + + } + + public NativeByteBuffer(int size) throws Exception { + if (size >= 0) { + address = native_getFreeBuffer(size); + if (address != 0) { + buffer = native_getJavaByteBuffer(address); + buffer.position(0); + buffer.limit(size); + buffer.order(ByteOrder.LITTLE_ENDIAN); + } + } else { + throw new Exception("invalid NativeByteBuffer size"); + } + } + + public NativeByteBuffer(boolean calculate) { + justCalc = calculate; + } + + public int position() { + return buffer.position(); + } + + public void position(int position) { + buffer.position(position); + } + + public int capacity() { + return buffer.capacity(); + } + + public int limit() { + return buffer.limit(); + } + + public void limit(int limit) { + buffer.limit(limit); + } + + public void put(ByteBuffer buff) { + buffer.put(buff); + } + + public void rewind() { + if (justCalc) { + len = 0; + } else { + buffer.rewind(); + } + } + + public void compact() { + buffer.compact(); + } + + public boolean hasRemaining() { + return buffer.hasRemaining(); + } + + public void writeInt32(int x) { + try { + if (!justCalc) { + buffer.putInt(x); + } else { + len += 4; + } + } catch(Exception e) { + FileLog.e("tmessages", "write int32 error"); + } + } + + public void writeInt64(long x) { + try { + if (!justCalc) { + buffer.putLong(x); + } else { + len += 8; + } + } catch(Exception e) { + FileLog.e("tmessages", "write int64 error"); + } + } + + public void writeBool(boolean value) { + if (!justCalc) { + if (value) { + writeInt32(0x997275b5); + } else { + writeInt32(0xbc799737); + } + } else { + len += 4; + } + } + + public void writeBytes(byte[] b) { + try { + if (!justCalc) { + buffer.put(b); + } else { + len += b.length; + } + } catch (Exception e) { + FileLog.e("tmessages", "write raw error"); + } + } + + public void writeBytes(byte[] b, int offset, int count) { + try { + if (!justCalc) { + buffer.put(b, offset, count); + } else { + len += count; + } + } catch (Exception e) { + FileLog.e("tmessages", "write raw error"); + } + } + + public void writeByte(int i) { + writeByte((byte) i); + } + + public void writeByte(byte b) { + try { + if (!justCalc) { + buffer.put(b); + } else { + len += 1; + } + } catch (Exception e) { + FileLog.e("tmessages", "write byte error"); + } + } + + public void writeString(String s) { + try { + writeByteArray(s.getBytes("UTF-8")); + } catch(Exception e) { + FileLog.e("tmessages", "write string error"); + } + } + + public void writeByteArray(byte[] b, int offset, int count) { + try { + if(count <= 253) { + if (!justCalc) { + buffer.put((byte)count); + } else { + len += 1; + } + } else { + if (!justCalc) { + buffer.put((byte)254); + buffer.put((byte)count); + buffer.put((byte)(count >> 8)); + buffer.put((byte)(count >> 16)); + } else { + len += 4; + } + } + if (!justCalc) { + buffer.put(b, offset, count); + } else { + len += count; + } + int i = count <= 253 ? 1 : 4; + while ((count + i) % 4 != 0) { + if (!justCalc) { + buffer.put((byte)0); + } else { + len += 1; + } + i++; + } + } catch (Exception e) { + FileLog.e("tmessages", "write byte array error"); + } + } + + public void writeByteArray(byte[] b) { + try { + if (b.length <= 253) { + if (!justCalc) { + buffer.put((byte) b.length); + } else { + len += 1; + } + } else { + if (!justCalc) { + buffer.put((byte) 254); + buffer.put((byte) b.length); + buffer.put((byte) (b.length >> 8)); + buffer.put((byte) (b.length >> 16)); + } else { + len += 4; + } + } + if (!justCalc) { + buffer.put(b); + } else { + len += b.length; + } + int i = b.length <= 253 ? 1 : 4; + while((b.length + i) % 4 != 0) { + if (!justCalc) { + buffer.put((byte) 0); + } else { + len += 1; + } + i++; + } + } catch (Exception e) { + FileLog.e("tmessages", "write byte array error"); + } + } + + public void writeDouble(double d) { + try { + writeInt64(Double.doubleToRawLongBits(d)); + } catch(Exception e) { + FileLog.e("tmessages", "write double error"); + } + } + + public void writeByteBuffer(NativeByteBuffer b) { + try { + int l = b.limit(); + if (l <= 253) { + if (!justCalc) { + buffer.put((byte) l); + } else { + len += 1; + } + } else { + if (!justCalc) { + buffer.put((byte) 254); + buffer.put((byte) l); + buffer.put((byte) (l >> 8)); + buffer.put((byte) (l >> 16)); + } else { + len += 4; + } + } + if (!justCalc) { + b.rewind(); + buffer.put(b.buffer); + } else { + len += l; + } + int i = l <= 253 ? 1 : 4; + while((l + i) % 4 != 0) { + if (!justCalc) { + buffer.put((byte) 0); + } else { + len += 1; + } + i++; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void writeBytes(NativeByteBuffer b) { + if (justCalc) { + len += b.limit(); + } else { + b.rewind(); + buffer.put(b.buffer); + } + } + + public int getIntFromByte(byte b) { + return b >= 0 ? b : ((int)b) + 256; + } + + public int length() { + if (!justCalc) { + return buffer.position(); + } + return len; + } + + public void skip(int count) { + if (count == 0) { + return; + } + if (!justCalc) { + buffer.position(buffer.position() + count); + } else { + len += count; + } + } + + public int getPosition() { + return buffer.position(); + } + + public int readInt32(boolean exception) { + try { + return buffer.getInt(); + } catch (Exception e) { + if (exception) { + throw new RuntimeException("read int32 error", e); + } else { + FileLog.e("tmessages", "read int32 error"); + } + } + return 0; + } + + public boolean readBool(boolean exception) { + int consructor = readInt32(exception); + if (consructor == 0x997275b5) { + return true; + } else if (consructor == 0xbc799737) { + return false; + } + if (exception) { + throw new RuntimeException("Not bool value!"); + } else { + FileLog.e("tmessages", "Not bool value!"); + } + return false; + } + + public long readInt64(boolean exception) { + try { + return buffer.getLong(); + } catch (Exception e) { + if (exception) { + throw new RuntimeException("read int64 error", e); + } else { + FileLog.e("tmessages", "read int64 error"); + } + } + return 0; + } + + public void readBytes(byte[] b, boolean exception) { + try { + buffer.get(b); + } catch (Exception e) { + if (exception) { + throw new RuntimeException("read raw error", e); + } else { + FileLog.e("tmessages", "read raw error"); + } + } + } + + public byte[] readData(int count, boolean exception) { + byte[] arr = new byte[count]; + readBytes(arr, exception); + return arr; + } + + public String readString(boolean exception) { + try { + int sl = 1; + int l = getIntFromByte(buffer.get()); + if(l >= 254) { + l = getIntFromByte(buffer.get()) | (getIntFromByte(buffer.get()) << 8) | (getIntFromByte(buffer.get()) << 16); + sl = 4; + } + byte[] b = new byte[l]; + buffer.get(b); + int i = sl; + while((l + i) % 4 != 0) { + buffer.get(); + i++; + } + return new String(b, "UTF-8"); + } catch (Exception e) { + if (exception) { + throw new RuntimeException("read string error", e); + } else { + FileLog.e("tmessages", "read string error"); + } + } + return null; + } + + public byte[] readByteArray(boolean exception) { + try { + int sl = 1; + int l = getIntFromByte(buffer.get()); + if (l >= 254) { + l = getIntFromByte(buffer.get()) | (getIntFromByte(buffer.get()) << 8) | (getIntFromByte(buffer.get()) << 16); + sl = 4; + } + byte[] b = new byte[l]; + buffer.get(b); + int i = sl; + while((l + i) % 4 != 0) { + buffer.get(); + i++; + } + return b; + } catch (Exception e) { + if (exception) { + throw new RuntimeException("read byte array error", e); + } else { + FileLog.e("tmessages", "read byte array error"); + } + } + return null; + } + + public NativeByteBuffer readByteBuffer(boolean exception) { + try { + int sl = 1; + int l = getIntFromByte(buffer.get()); + if (l >= 254) { + l = getIntFromByte(buffer.get()) | (getIntFromByte(buffer.get()) << 8) | (getIntFromByte(buffer.get()) << 16); + sl = 4; + } + NativeByteBuffer b = new NativeByteBuffer(l); + int old = buffer.limit(); + buffer.limit(buffer.position() + l); + b.buffer.put(buffer); + buffer.limit(old); + b.buffer.position(0); + int i = sl; + while((l + i) % 4 != 0) { + buffer.get(); + i++; + } + return b; + } catch (Exception e) { + if (exception) { + throw new RuntimeException("read byte array error", e); + } else { + FileLog.e("tmessages", "read byte array error"); + } + } + return null; + } + + public double readDouble(boolean exception) { + try { + return Double.longBitsToDouble(readInt64(exception)); + } catch(Exception e) { + if (exception) { + throw new RuntimeException("read double error", e); + } else { + FileLog.e("tmessages", "read double error"); + } + } + return 0; + } + + public void reuse() { + if (address != 0) { + native_reuse(address); + } + } + + public static native int native_getFreeBuffer(int length); + public static native ByteBuffer native_getJavaByteBuffer(int address); + public static native int native_limit(int address); + public static native int native_position(int address); + public static native void native_reuse(int address); +} diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/QuickAckDelegate.java b/TMessagesProj/src/main/java/org/telegram/tgnet/QuickAckDelegate.java new file mode 100644 index 00000000..e9b1dd39 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/QuickAckDelegate.java @@ -0,0 +1,5 @@ +package org.telegram.tgnet; + +public interface QuickAckDelegate { + void run(); +} diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/RequestDelegate.java b/TMessagesProj/src/main/java/org/telegram/tgnet/RequestDelegate.java new file mode 100644 index 00000000..ad19e523 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/RequestDelegate.java @@ -0,0 +1,5 @@ +package org.telegram.tgnet; + +public interface RequestDelegate { + void run(TLObject response, TLRPC.TL_error error); +} diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/RequestDelegateInternal.java b/TMessagesProj/src/main/java/org/telegram/tgnet/RequestDelegateInternal.java new file mode 100644 index 00000000..1f2133f0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/RequestDelegateInternal.java @@ -0,0 +1,5 @@ +package org.telegram.tgnet; + +public interface RequestDelegateInternal { + void run(int response, int errorCode, String errorText); +} diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/SerializedData.java b/TMessagesProj/src/main/java/org/telegram/tgnet/SerializedData.java new file mode 100644 index 00000000..13f1ff2d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/SerializedData.java @@ -0,0 +1,477 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.tgnet; + +import org.telegram.messenger.FileLog; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; + +public class SerializedData extends AbstractSerializedData { + protected boolean isOut = true; + private ByteArrayOutputStream outbuf; + private DataOutputStream out; + private ByteArrayInputStream inbuf; + private DataInputStream in; + private boolean justCalc = false; + private int len; + + public SerializedData() { + outbuf = new ByteArrayOutputStream(); + out = new DataOutputStream(outbuf); + } + + public SerializedData(boolean calculate) { + if (!calculate) { + outbuf = new ByteArrayOutputStream(); + out = new DataOutputStream(outbuf); + } + justCalc = calculate; + len = 0; + } + + public SerializedData(int size) { + outbuf = new ByteArrayOutputStream(size); + out = new DataOutputStream(outbuf); + } + + public SerializedData(byte[] data) { + isOut = false; + inbuf = new ByteArrayInputStream(data); + in = new DataInputStream(inbuf); + len = 0; + } + + public void cleanup() { + try { + if (inbuf != null) { + inbuf.close(); + inbuf = null; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + if (in != null) { + in.close(); + in = null; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + if (outbuf != null) { + outbuf.close(); + outbuf = null; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + try { + if (out != null) { + out.close(); + out = null; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public SerializedData(File file) throws Exception { + FileInputStream is = new FileInputStream(file); + byte[] data = new byte[(int)file.length()]; + new DataInputStream(is).readFully(data); + is.close(); + + isOut = false; + inbuf = new ByteArrayInputStream(data); + in = new DataInputStream(inbuf); + } + + public void writeInt32(int x) { + if (!justCalc) { + writeInt32(x, out); + } else { + len += 4; + } + } + + private void writeInt32(int x, DataOutputStream out) { + try { + for(int i = 0; i < 4; i++) { + out.write(x >> (i * 8)); + } + } catch(Exception e) { + FileLog.e("tmessages", "write int32 error"); + } + } + + public void writeInt64(long i) { + if (!justCalc) { + writeInt64(i, out); + } else { + len += 8; + } + } + + private void writeInt64(long x, DataOutputStream out) { + try { + for(int i = 0; i < 8; i++) { + out.write((int)(x >> (i * 8))); + } + } catch(Exception e) { + FileLog.e("tmessages", "write int64 error"); + } + } + + public void writeBool(boolean value) { + if (!justCalc) { + if (value) { + writeInt32(0x997275b5); + } else { + writeInt32(0xbc799737); + } + } else { + len += 4; + } + } + + public void writeBytes(byte[] b) { + try { + if (!justCalc) { + out.write(b); + } else { + len += b.length; + } + } catch (Exception e) { + FileLog.e("tmessages", "write raw error"); + } + } + + public void writeBytes(byte[] b, int offset, int count) { + try { + if (!justCalc) { + out.write(b, offset, count); + } else { + len += count; + } + } catch (Exception e) { + FileLog.e("tmessages", "write bytes error"); + } + } + + public void writeByte(int i) { + try { + if (!justCalc) { + out.writeByte((byte) i); + } else { + len += 1; + } + } catch (Exception e) { + FileLog.e("tmessages", "write byte error"); + } + } + + public void writeByte(byte b) { + try { + if (!justCalc) { + out.writeByte(b); + } else { + len += 1; + } + } catch (Exception e) { + FileLog.e("tmessages", "write byte error"); + } + } + + public void writeByteArray(byte[] b) { + try { + if (b.length <= 253) { + if (!justCalc) { + out.write(b.length); + } else { + len += 1; + } + } else { + if (!justCalc) { + out.write(254); + out.write(b.length); + out.write(b.length >> 8); + out.write(b.length >> 16); + } else { + len += 4; + } + } + if (!justCalc) { + out.write(b); + } else { + len += b.length; + } + int i = b.length <= 253 ? 1 : 4; + while((b.length + i) % 4 != 0) { + if (!justCalc) { + out.write(0); + } else { + len += 1; + } + i++; + } + } catch (Exception e) { + FileLog.e("tmessages", "write byte array error"); + } + } + + public void writeString(String s) { + try { + writeByteArray(s.getBytes("UTF-8")); + } catch(Exception e) { + FileLog.e("tmessages", "write string error"); + } + } + + public void writeByteArray(byte[] b, int offset, int count) { + try { + if(count <= 253) { + if (!justCalc) { + out.write(count); + } else { + len += 1; + } + } else { + if (!justCalc) { + out.write(254); + out.write(count); + out.write(count >> 8); + out.write(count >> 16); + } else { + len += 4; + } + } + if (!justCalc) { + out.write(b, offset, count); + } else { + len += count; + } + int i = count <= 253 ? 1 : 4; + while ((count + i) % 4 != 0) { + if (!justCalc) { + out.write(0); + } else { + len += 1; + } + i++; + } + } catch (Exception e) { + FileLog.e("tmessages", "write byte array error"); + } + } + + public void writeDouble(double d) { + try { + writeInt64(Double.doubleToRawLongBits(d)); + } catch(Exception e) { + FileLog.e("tmessages", "write double error"); + } + } + + public int length() { + if (!justCalc) { + return isOut ? outbuf.size() : inbuf.available(); + } + return len; + } + + protected void set(byte[] newData) { + isOut = false; + inbuf = new ByteArrayInputStream(newData); + in = new DataInputStream(inbuf); + } + + public byte[] toByteArray() { + return outbuf.toByteArray(); + } + + public void skip(int count) { + if (count == 0) { + return; + } + if (!justCalc) { + if (in != null) { + try { + in.skipBytes(count); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } else { + len += count; + } + } + + public int getPosition() { + return len; + } + + public boolean readBool(boolean exception) { + int consructor = readInt32(exception); + if (consructor == 0x997275b5) { + return true; + } else if (consructor == 0xbc799737) { + return false; + } + if (exception) { + throw new RuntimeException("Not bool value!"); + } else { + FileLog.e("tmessages", "Not bool value!"); + } + return false; + } + + public void readBytes(byte[] b, boolean exception) { + try { + in.read(b); + len += b.length; + } catch (Exception e) { + if (exception) { + throw new RuntimeException("read bytes error", e); + } else { + FileLog.e("tmessages", "read bytes error"); + } + } + } + + public byte[] readData(int count, boolean exception) { + byte[] arr = new byte[count]; + readBytes(arr, exception); + return arr; + } + + public String readString(boolean exception) { + try { + int sl = 1; + int l = in.read(); + len++; + if(l >= 254) { + l = in.read() | (in.read() << 8) | (in.read() << 16); + len += 3; + sl = 4; + } + byte[] b = new byte[l]; + in.read(b); + len++; + int i=sl; + while((l + i) % 4 != 0) { + in.read(); + len++; + i++; + } + return new String(b, "UTF-8"); + } catch (Exception e) { + if (exception) { + throw new RuntimeException("read string error", e); + } else { + FileLog.e("tmessages", "read string error"); + } + } + return null; + } + + public byte[] readByteArray(boolean exception) { + try { + int sl = 1; + int l = in.read(); + len++; + if (l >= 254) { + l = in.read() | (in.read() << 8) | (in.read() << 16); + len += 3; + sl = 4; + } + byte[] b = new byte[l]; + in.read(b); + len++; + int i = sl; + while((l + i) % 4 != 0) { + in.read(); + len++; + i++; + } + return b; + } catch (Exception e) { + if (exception) { + throw new RuntimeException("read byte array error", e); + } else { + FileLog.e("tmessages", "read byte array error"); + } + } + return null; + } + + public double readDouble(boolean exception) { + try { + return Double.longBitsToDouble(readInt64(exception)); + } catch(Exception e) { + if (exception) { + throw new RuntimeException("read double error", e); + } else { + FileLog.e("tmessages", "read double error"); + } + } + return 0; + } + + public int readInt32(boolean exception) { + try { + int i = 0; + for(int j = 0; j < 4; j++) { + i |= (in.read() << (j * 8)); + len++; + } + return i; + } catch(Exception e) { + if (exception) { + throw new RuntimeException("read int32 error", e); + } else { + FileLog.e("tmessages", "read int32 error"); + } + } + return 0; + } + + public long readInt64(boolean exception) { + try { + long i = 0; + for(int j = 0; j < 8; j++) { + i |= ((long)in.read() << (j * 8)); + len++; + } + return i; + } catch (Exception e) { + if (exception) { + throw new RuntimeException("read int64 error", e); + } else { + FileLog.e("tmessages", "read int64 error"); + } + } + return 0; + } + + @Override + public void writeByteBuffer(NativeByteBuffer buffer) { + + } + + @Override + public NativeByteBuffer readByteBuffer(boolean exception) { + return null; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLClassStore.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLClassStore.java new file mode 100644 index 00000000..11e79f95 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLClassStore.java @@ -0,0 +1,67 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.tgnet; + +import org.telegram.messenger.FileLog; + +import java.util.HashMap; + +public class TLClassStore { + private HashMap classStore; + + public TLClassStore() { + classStore = new HashMap<>(); + + classStore.put(TLRPC.TL_error.constructor, TLRPC.TL_error.class); + classStore.put(TLRPC.TL_decryptedMessageService.constructor, TLRPC.TL_decryptedMessageService.class); + classStore.put(TLRPC.TL_decryptedMessage.constructor, TLRPC.TL_decryptedMessage.class); + classStore.put(TLRPC.TL_config.constructor, TLRPC.TL_config.class); + classStore.put(TLRPC.TL_decryptedMessageLayer.constructor, TLRPC.TL_decryptedMessageLayer.class); + classStore.put(TLRPC.TL_decryptedMessage_layer17.constructor, TLRPC.TL_decryptedMessage.class); + classStore.put(TLRPC.TL_decryptedMessageService_layer8.constructor, TLRPC.TL_decryptedMessageService_layer8.class); + classStore.put(TLRPC.TL_decryptedMessage_layer8.constructor, TLRPC.TL_decryptedMessage_layer8.class); + classStore.put(TLRPC.TL_message_secret.constructor, TLRPC.TL_message_secret.class); + classStore.put(TLRPC.TL_message_secret_old.constructor, TLRPC.TL_message_secret_old.class); + classStore.put(TLRPC.TL_messageEncryptedAction.constructor, TLRPC.TL_messageEncryptedAction.class); + classStore.put(TLRPC.TL_null.constructor, TLRPC.TL_null.class); + + classStore.put(TLRPC.TL_updateShortChatMessage.constructor, TLRPC.TL_updateShortChatMessage.class); + classStore.put(TLRPC.TL_updates.constructor, TLRPC.TL_updates.class); + classStore.put(TLRPC.TL_updateShortMessage.constructor, TLRPC.TL_updateShortMessage.class); + classStore.put(TLRPC.TL_updateShort.constructor, TLRPC.TL_updateShort.class); + classStore.put(TLRPC.TL_updatesCombined.constructor, TLRPC.TL_updatesCombined.class); + classStore.put(TLRPC.TL_updateShortSentMessage.constructor, TLRPC.TL_updateShortSentMessage.class); + classStore.put(TLRPC.TL_updatesTooLong.constructor, TLRPC.TL_updatesTooLong.class); + } + + static TLClassStore store = null; + + public static TLClassStore Instance() { + if (store == null) { + store = new TLClassStore(); + } + return store; + } + + public TLObject TLdeserialize(NativeByteBuffer stream, int constructor, boolean exception) { + Class objClass = classStore.get(constructor); + if (objClass != null) { + TLObject response; + try { + response = (TLObject) objClass.newInstance(); + } catch (Throwable e) { + FileLog.e("tmessages", e); + return null; + } + response.readParams(stream, exception); + return response; + } + return null; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLObject.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLObject.java new file mode 100644 index 00000000..1f781b6d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLObject.java @@ -0,0 +1,47 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.tgnet; + +public class TLObject { + + public boolean disableFree = false; + private static final ThreadLocal sizeCalculator = new ThreadLocal() { + @Override + protected NativeByteBuffer initialValue() { + return new NativeByteBuffer(true); + } + }; + + public TLObject() { + + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + + } + + public void serializeToStream(AbstractSerializedData stream) { + + } + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return null; + } + + public void freeResources() { + + } + + public int getObjectSize() { + NativeByteBuffer byteBuffer = sizeCalculator.get(); + byteBuffer.rewind(); + serializeToStream(sizeCalculator.get()); + return byteBuffer.length(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java new file mode 100644 index 00000000..4418191a --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/tgnet/TLRPC.java @@ -0,0 +1,20993 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.tgnet; + +import java.util.ArrayList; +import java.util.HashMap; + +@SuppressWarnings("unchecked") +public class TLRPC { + + public static final int USER_FLAG_ACCESS_HASH = 0x00000001; + public static final int USER_FLAG_FIRST_NAME = 0x00000002; + public static final int USER_FLAG_LAST_NAME = 0x00000004; + public static final int USER_FLAG_USERNAME = 0x00000008; + public static final int USER_FLAG_PHONE = 0x00000010; + public static final int USER_FLAG_PHOTO = 0x00000020; + public static final int USER_FLAG_STATUS = 0x00000040; + public static final int USER_FLAG_UNUSED = 0x00000080; + public static final int USER_FLAG_UNUSED2 = 0x00000100; + public static final int USER_FLAG_UNUSED3 = 0x00000200; + //public static final int USER_FLAG_SELF = 0x00000400; + //public static final int USER_FLAG_CONTACT = 0x00000800; + //public static final int USER_FLAG_MUTUAL_CONTACT = 0x00001000; + //public static final int USER_FLAG_DELETED = 0x00002000; + //public static final int USER_FLAG_BOT = 0x00004000; + //public static final int USER_FLAG_BOT_READING_HISTORY = 0x00008000; + //public static final int USER_FLAG_BOT_CANT_JOIN_GROUP = 0x00010000; + //public static final int USER_FLAG_VERIFIED = 0x00020000; + + //public static final int CHAT_FLAG_CREATOR = 0x00000001; + //public static final int CHAT_FLAG_USER_KICKED = 0x00000002; + //public static final int CHAT_FLAG_USER_LEFT = 0x00000004; + //public static final int CHAT_FLAG_USER_IS_EDITOR = 0x00000008; + //public static final int CHAT_FLAG_USER_IS_MODERATOR = 0x00000010; + //public static final int CHAT_FLAG_IS_BROADCAST = 0x00000020; + public static final int CHAT_FLAG_IS_PUBLIC = 0x00000040; + //public static final int CHAT_FLAG_IS_VERIFIED = 0x00000080; + + //public static final int MESSAGE_FLAG_UNREAD = 0x00000001; + //public static final int MESSAGE_FLAG_OUT = 0x00000002; + public static final int MESSAGE_FLAG_FWD = 0x00000004; + public static final int MESSAGE_FLAG_REPLY = 0x00000008; + //public static final int MESSAGE_FLAG_MENTION = 0x00000010; + //public static final int MESSAGE_FLAG_CONTENT_UNREAD = 0x00000020; + public static final int MESSAGE_FLAG_HAS_MARKUP = 0x00000040; + public static final int MESSAGE_FLAG_HAS_ENTITIES = 0x00000080; + public static final int MESSAGE_FLAG_HAS_FROM_ID = 0x00000100; + public static final int MESSAGE_FLAG_HAS_MEDIA = 0x00000200; + public static final int MESSAGE_FLAG_HAS_VIEWS = 0x00000400; + public static final int MESSAGE_FLAG_HAS_BOT_ID = 0x00000800; + public static final int MESSAGE_FLAG_MEGAGROUP = 0x80000000; + + public static final int LAYER = 51; + + public static class ChatPhoto extends TLObject { + public FileLocation photo_small; + public FileLocation photo_big; + + public static ChatPhoto TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + ChatPhoto result = null; + switch(constructor) { + case 0x37c1011c: + result = new TL_chatPhotoEmpty(); + break; + case 0x6153276a: + result = new TL_chatPhoto(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in ChatPhoto", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_chatPhotoEmpty extends ChatPhoto { + public static int constructor = 0x37c1011c; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_chatPhoto extends ChatPhoto { + public static int constructor = 0x6153276a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + photo_small = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + photo_big = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + photo_small.serializeToStream(stream); + photo_big.serializeToStream(stream); + } + } + + public static class TL_help_termsOfService extends TLObject { + public static int constructor = 0xf1ee3e90; + + public String text; + + public static TL_help_termsOfService TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_help_termsOfService.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_help_termsOfService", constructor)); + } else { + return null; + } + } + TL_help_termsOfService result = new TL_help_termsOfService(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + } + } + + public static class NotifyPeer extends TLObject { + public Peer peer; + + public static NotifyPeer TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + NotifyPeer result = null; + switch(constructor) { + case 0x74d07c60: + result = new TL_notifyAll(); + break; + case 0xc007cec3: + result = new TL_notifyChats(); + break; + case 0xb4c83b4c: + result = new TL_notifyUsers(); + break; + case 0x9fd40bd8: + result = new TL_notifyPeer(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in NotifyPeer", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_notifyAll extends NotifyPeer { + public static int constructor = 0x74d07c60; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_notifyChats extends NotifyPeer { + public static int constructor = 0xc007cec3; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_notifyUsers extends NotifyPeer { + public static int constructor = 0xb4c83b4c; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_notifyPeer extends NotifyPeer { + public static int constructor = 0x9fd40bd8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + } + } + + public static class messages_SentEncryptedMessage extends TLObject { + public int date; + public EncryptedFile file; + + public static messages_SentEncryptedMessage TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + messages_SentEncryptedMessage result = null; + switch(constructor) { + case 0x560f8935: + result = new TL_messages_sentEncryptedMessage(); + break; + case 0x9493ff32: + result = new TL_messages_sentEncryptedFile(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in messages_SentEncryptedMessage", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messages_sentEncryptedMessage extends messages_SentEncryptedMessage { + public static int constructor = 0x560f8935; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(date); + } + } + + public static class TL_messages_sentEncryptedFile extends messages_SentEncryptedMessage { + public static int constructor = 0x9493ff32; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + date = stream.readInt32(exception); + file = EncryptedFile.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(date); + file.serializeToStream(stream); + } + } + + public static class TL_error extends TLObject { + public static int constructor = 0xc4b9f9bb; + + public int code; + public String text; + + public static TL_error TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_error.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_error", constructor)); + } else { + return null; + } + } + TL_error result = new TL_error(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + code = stream.readInt32(exception); + text = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(code); + stream.writeString(text); + } + } + + public static class TL_auth_checkedPhone extends TLObject { + public static int constructor = 0x811ea28e; + + public boolean phone_registered; + + public static TL_auth_checkedPhone TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_auth_checkedPhone.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_auth_checkedPhone", constructor)); + } else { + return null; + } + } + TL_auth_checkedPhone result = new TL_auth_checkedPhone(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + phone_registered = stream.readBool(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeBool(phone_registered); + } + } + + public static class TL_messages_chatFull extends TLObject { + public static int constructor = 0xe5d7d19c; + + public ChatFull full_chat; + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + public static TL_messages_chatFull TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_chatFull.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_chatFull", constructor)); + } else { + return null; + } + } + TL_messages_chatFull result = new TL_messages_chatFull(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + full_chat = ChatFull.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + full_chat.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_account_passwordSettings extends TLObject { + public static int constructor = 0xb7b72ab3; + + public String email; + + public static TL_account_passwordSettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_account_passwordSettings.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_account_passwordSettings", constructor)); + } else { + return null; + } + } + TL_account_passwordSettings result = new TL_account_passwordSettings(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + email = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(email); + } + } + + public static class DocumentAttribute extends TLObject { + public int w; + public int h; + public int duration; + public String alt; + public InputStickerSet stickerset; + public int flags; + public boolean voice; + public String title; + public String performer; + public byte[] waveform; + public String file_name; + + public static DocumentAttribute TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + DocumentAttribute result = null; + switch(constructor) { + case 0x11b58939: + result = new TL_documentAttributeAnimated(); + break; + case 0xfb0a5727: + result = new TL_documentAttributeSticker_old(); + break; + case 0x6c37c15c: + result = new TL_documentAttributeImageSize(); + break; + case 0x51448e5: + result = new TL_documentAttributeAudio_old(); + break; + case 0x3a556302: + result = new TL_documentAttributeSticker(); + break; + case 0x5910cccb: + result = new TL_documentAttributeVideo(); + break; + case 0x9852f9c6: + result = new TL_documentAttributeAudio(); + break; + case 0x994c9882: + result = new TL_documentAttributeSticker_old2(); + break; + case 0x15590068: + result = new TL_documentAttributeFilename(); + break; + case 0xded218e0: + result = new TL_documentAttributeAudio_layer45(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in DocumentAttribute", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_documentAttributeAnimated extends DocumentAttribute { + public static int constructor = 0x11b58939; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_documentAttributeSticker_old extends TL_documentAttributeSticker { + public static int constructor = 0xfb0a5727; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_documentAttributeImageSize extends DocumentAttribute { + public static int constructor = 0x6c37c15c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + w = stream.readInt32(exception); + h = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(w); + stream.writeInt32(h); + } + } + + public static class TL_documentAttributeAudio_old extends TL_documentAttributeAudio { + public static int constructor = 0x51448e5; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + duration = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(duration); + } + } + + public static class TL_documentAttributeSticker extends DocumentAttribute { + public static int constructor = 0x3a556302; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + alt = stream.readString(exception); + stickerset = InputStickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(alt); + stickerset.serializeToStream(stream); + } + } + + public static class TL_documentAttributeVideo extends DocumentAttribute { + public static int constructor = 0x5910cccb; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + duration = stream.readInt32(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(duration); + stream.writeInt32(w); + stream.writeInt32(h); + } + } + + public static class TL_documentAttributeAudio extends DocumentAttribute { + public static int constructor = 0x9852f9c6; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + voice = (flags & 1024) != 0; + duration = stream.readInt32(exception); + if ((flags & 1) != 0) { + title = stream.readString(exception); + } + if ((flags & 2) != 0) { + performer = stream.readString(exception); + } + if ((flags & 4) != 0) { + waveform = stream.readByteArray(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = voice ? (flags | 1024) : (flags &~ 1024); + stream.writeInt32(flags); + stream.writeInt32(duration); + if ((flags & 1) != 0) { + stream.writeString(title); + } + if ((flags & 2) != 0) { + stream.writeString(performer); + } + if ((flags & 4) != 0) { + stream.writeByteArray(waveform); + } + } + } + + public static class TL_documentAttributeSticker_old2 extends TL_documentAttributeSticker { + public static int constructor = 0x994c9882; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + alt = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(alt); + } + } + + public static class TL_documentAttributeFilename extends DocumentAttribute { + public static int constructor = 0x15590068; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + file_name = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(file_name); + } + } + + public static class TL_documentAttributeAudio_layer45 extends TL_documentAttributeAudio { + public static int constructor = 0xded218e0; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + duration = stream.readInt32(exception); + title = stream.readString(exception); + performer = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(duration); + stream.writeString(title); + stream.writeString(performer); + } + } + + public static class TL_messages_botCallbackAnswer extends TLObject { + public static int constructor = 0x1264f1c6; + + public int flags; + public boolean alert; + public String message; + + public static TL_messages_botCallbackAnswer TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_botCallbackAnswer.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_botCallbackAnswer", constructor)); + } else { + return null; + } + } + TL_messages_botCallbackAnswer result = new TL_messages_botCallbackAnswer(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + alert = (flags & 2) != 0; + if ((flags & 1) != 0) { + message = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = alert ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeString(message); + } + } + } + + public static class TL_contactStatus extends TLObject { + public static int constructor = 0xd3680c61; + + public int user_id; + public UserStatus status; + + public static TL_contactStatus TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_contactStatus.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_contactStatus", constructor)); + } else { + return null; + } + } + TL_contactStatus result = new TL_contactStatus(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + status.serializeToStream(stream); + } + } + + public static class TL_auth_authorization extends TLObject { + public static int constructor = 0xff036af1; + + public User user; + + public static TL_auth_authorization TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_auth_authorization.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_auth_authorization", constructor)); + } else { + return null; + } + } + TL_auth_authorization result = new TL_auth_authorization(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + user = User.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + user.serializeToStream(stream); + } + } + + public static class messages_Messages extends TLObject { + public ArrayList messages = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + public int flags; + public int pts; + public int count; + public ArrayList collapsed = new ArrayList<>(); + + public static messages_Messages TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + messages_Messages result = null; + switch(constructor) { + case 0x8c718e87: + result = new TL_messages_messages(); + break; + case 0xbc0f17bc: + result = new TL_messages_channelMessages(); + break; + case 0xb446ae3: + result = new TL_messages_messagesSlice(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in messages_Messages", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messages_messages extends messages_Messages { + public static int constructor = 0x8c718e87; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Message object = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + messages.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + messages.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_messages_channelMessages extends messages_Messages { + public static int constructor = 0xbc0f17bc; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + pts = stream.readInt32(exception); + count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Message object = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + messages.add(object); + } + if ((flags & 1) != 0) { + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_messageGroup object = TL_messageGroup.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + collapsed.add(object); + } + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(pts); + stream.writeInt32(count); + stream.writeInt32(0x1cb5c415); + int count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + messages.get(a).serializeToStream(stream); + } + if ((flags & 1) != 0) { + stream.writeInt32(0x1cb5c415); + count = collapsed.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + collapsed.get(a).serializeToStream(stream); + } + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_messages_messagesSlice extends messages_Messages { + public static int constructor = 0xb446ae3; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Message object = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + messages.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(count); + stream.writeInt32(0x1cb5c415); + int count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + messages.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class help_AppChangelog extends TLObject { + public String text; + + public static help_AppChangelog TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + help_AppChangelog result = null; + switch(constructor) { + case 0xaf7e0394: + result = new TL_help_appChangelogEmpty(); + break; + case 0x4668e6bd: + result = new TL_help_appChangelog(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in help_AppChangelog", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_help_appChangelogEmpty extends help_AppChangelog { + public static int constructor = 0xaf7e0394; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_help_appChangelog extends help_AppChangelog { + public static int constructor = 0x4668e6bd; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + } + } + + public static class TL_contacts_link extends TLObject { + public static int constructor = 0x3ace484c; + + public ContactLink my_link; + public ContactLink foreign_link; + public User user; + + public static TL_contacts_link TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_contacts_link.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_contacts_link", constructor)); + } else { + return null; + } + } + TL_contacts_link result = new TL_contacts_link(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + my_link = ContactLink.TLdeserialize(stream, stream.readInt32(exception), exception); + foreign_link = ContactLink.TLdeserialize(stream, stream.readInt32(exception), exception); + user = User.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + my_link.serializeToStream(stream); + foreign_link.serializeToStream(stream); + user.serializeToStream(stream); + } + } + + public static class EncryptedFile extends TLObject { + public long id; + public long access_hash; + public int size; + public int dc_id; + public int key_fingerprint; + + public static EncryptedFile TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + EncryptedFile result = null; + switch(constructor) { + case 0x4a70994c: + result = new TL_encryptedFile(); + break; + case 0xc21f497e: + result = new TL_encryptedFileEmpty(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in EncryptedFile", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_encryptedFile extends EncryptedFile { + public static int constructor = 0x4a70994c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + size = stream.readInt32(exception); + dc_id = stream.readInt32(exception); + key_fingerprint = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(size); + stream.writeInt32(dc_id); + stream.writeInt32(key_fingerprint); + } + } + + public static class TL_encryptedFileEmpty extends EncryptedFile { + public static int constructor = 0xc21f497e; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class Peer extends TLObject { + public int channel_id; + public int user_id; + public int chat_id; + + public static Peer TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + Peer result = null; + switch(constructor) { + case 0xbddde532: + result = new TL_peerChannel(); + break; + case 0x9db1bc6d: + result = new TL_peerUser(); + break; + case 0xbad0e5bb: + result = new TL_peerChat(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in Peer", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_peerChannel extends Peer { + public static int constructor = 0xbddde532; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + channel_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(channel_id); + } + } + + public static class TL_peerUser extends Peer { + public static int constructor = 0x9db1bc6d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + } + } + + public static class TL_peerChat extends Peer { + public static int constructor = 0xbad0e5bb; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + } + } + + public static class TL_messages_affectedMessages extends TLObject { + public static int constructor = 0x84d19185; + + public int pts; + public int pts_count; + + public static TL_messages_affectedMessages TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_affectedMessages.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_affectedMessages", constructor)); + } else { + return null; + } + } + TL_messages_affectedMessages result = new TL_messages_affectedMessages(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(pts); + stream.writeInt32(pts_count); + } + } + + public static class TL_channels_channelParticipant extends TLObject { + public static int constructor = 0xd0d9b163; + + public ChannelParticipant participant; + public ArrayList users = new ArrayList<>(); + + public static TL_channels_channelParticipant TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_channels_channelParticipant.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_channels_channelParticipant", constructor)); + } else { + return null; + } + } + TL_channels_channelParticipant result = new TL_channels_channelParticipant(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + participant = ChannelParticipant.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + participant.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_authorization extends TLObject { + public static int constructor = 0x7bf2e6f6; + + public long hash; + public int flags; + public String device_model; + public String platform; + public String system_version; + public int api_id; + public String app_name; + public String app_version; + public int date_created; + public int date_active; + public String ip; + public String country; + public String region; + + public static TL_authorization TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_authorization.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_authorization", constructor)); + } else { + return null; + } + } + TL_authorization result = new TL_authorization(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readInt64(exception); + flags = stream.readInt32(exception); + device_model = stream.readString(exception); + platform = stream.readString(exception); + system_version = stream.readString(exception); + api_id = stream.readInt32(exception); + app_name = stream.readString(exception); + app_version = stream.readString(exception); + date_created = stream.readInt32(exception); + date_active = stream.readInt32(exception); + ip = stream.readString(exception); + country = stream.readString(exception); + region = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + stream.writeInt32(flags); + stream.writeString(device_model); + stream.writeString(platform); + stream.writeString(system_version); + stream.writeInt32(api_id); + stream.writeString(app_name); + stream.writeString(app_version); + stream.writeInt32(date_created); + stream.writeInt32(date_active); + stream.writeString(ip); + stream.writeString(country); + stream.writeString(region); + } + } + + public static class updates_Difference extends TLObject { + public int date; + public int seq; + public ArrayList new_messages = new ArrayList<>(); + public ArrayList new_encrypted_messages = new ArrayList<>(); + public ArrayList other_updates = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + public TL_updates_state intermediate_state; + public TL_updates_state state; + + public static updates_Difference TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + updates_Difference result = null; + switch(constructor) { + case 0x5d75a138: + result = new TL_updates_differenceEmpty(); + break; + case 0xa8fb1981: + result = new TL_updates_differenceSlice(); + break; + case 0xf49ca0: + result = new TL_updates_difference(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in updates_Difference", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_updates_differenceEmpty extends updates_Difference { + public static int constructor = 0x5d75a138; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + date = stream.readInt32(exception); + seq = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(date); + stream.writeInt32(seq); + } + } + + public static class TL_updates_differenceSlice extends updates_Difference { + public static int constructor = 0xa8fb1981; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Message object = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + new_messages.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + EncryptedMessage object = EncryptedMessage.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + new_encrypted_messages.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Update object = Update.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + other_updates.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + intermediate_state = TL_updates_state.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = new_messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + new_messages.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = new_encrypted_messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + new_encrypted_messages.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = other_updates.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + other_updates.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + intermediate_state.serializeToStream(stream); + } + } + + public static class TL_updates_difference extends updates_Difference { + public static int constructor = 0xf49ca0; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Message object = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + new_messages.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + EncryptedMessage object = EncryptedMessage.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + new_encrypted_messages.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Update object = Update.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + other_updates.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + state = TL_updates_state.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = new_messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + new_messages.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = new_encrypted_messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + new_encrypted_messages.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = other_updates.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + other_updates.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + state.serializeToStream(stream); + } + } + + public static class PrivacyKey extends TLObject { + + public static PrivacyKey TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + PrivacyKey result = null; + switch(constructor) { + case 0xbc2eab30: + result = new TL_privacyKeyStatusTimestamp(); + break; + case 0x500e6dfa: + result = new TL_privacyKeyChatInvite(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in PrivacyKey", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_privacyKeyStatusTimestamp extends PrivacyKey { + public static int constructor = 0xbc2eab30; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_privacyKeyChatInvite extends PrivacyKey { + public static int constructor = 0x500e6dfa; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class GeoPoint extends TLObject { + public double _long; + public double lat; + + public static GeoPoint TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + GeoPoint result = null; + switch(constructor) { + case 0x1117dd5f: + result = new TL_geoPointEmpty(); + break; + case 0x2049d70c: + result = new TL_geoPoint(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in GeoPoint", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_geoPointEmpty extends GeoPoint { + public static int constructor = 0x1117dd5f; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_geoPoint extends GeoPoint { + public static int constructor = 0x2049d70c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + _long = stream.readDouble(exception); + lat = stream.readDouble(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeDouble(_long); + stream.writeDouble(lat); + } + } + + public static class TL_account_privacyRules extends TLObject { + public static int constructor = 0x554abb6f; + + public ArrayList rules = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + public static TL_account_privacyRules TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_account_privacyRules.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_account_privacyRules", constructor)); + } else { + return null; + } + } + TL_account_privacyRules result = new TL_account_privacyRules(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + PrivacyRule object = PrivacyRule.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + rules.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = rules.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + rules.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class ChatInvite extends TLObject { + public int flags; + public boolean channel; + public boolean broadcast; + public boolean isPublic; + public boolean megagroup; + public String title; + public Chat chat; + + public static ChatInvite TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + ChatInvite result = null; + switch(constructor) { + case 0x93e99b60: + result = new TL_chatInvite(); + break; + case 0x5a686d7c: + result = new TL_chatInviteAlready(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in ChatInvite", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_chatInvite extends ChatInvite { + public static int constructor = 0x93e99b60; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + channel = (flags & 1) != 0; + broadcast = (flags & 2) != 0; + isPublic = (flags & 4) != 0; + megagroup = (flags & 8) != 0; + title = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = channel ? (flags | 1) : (flags &~ 1); + flags = broadcast ? (flags | 2) : (flags &~ 2); + flags = isPublic ? (flags | 4) : (flags &~ 4); + flags = megagroup ? (flags | 8) : (flags &~ 8); + stream.writeInt32(flags); + stream.writeString(title); + } + } + + public static class TL_chatInviteAlready extends ChatInvite { + public static int constructor = 0x5a686d7c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + chat.serializeToStream(stream); + } + } + + public static class help_AppUpdate extends TLObject { + public int id; + public boolean critical; + public String url; + public String text; + + public static help_AppUpdate TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + help_AppUpdate result = null; + switch(constructor) { + case 0x8987f311: + result = new TL_help_appUpdate(); + break; + case 0xc45a6536: + result = new TL_help_noAppUpdate(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in help_AppUpdate", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_help_appUpdate extends help_AppUpdate { + public static int constructor = 0x8987f311; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + critical = stream.readBool(exception); + url = stream.readString(exception); + text = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeBool(critical); + stream.writeString(url); + stream.writeString(text); + } + } + + public static class TL_help_noAppUpdate extends help_AppUpdate { + public static int constructor = 0xc45a6536; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class SendMessageAction extends TLObject { + public int progress; + + public static SendMessageAction TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + SendMessageAction result = null; + switch(constructor) { + case 0xd52f73f7: + result = new TL_sendMessageRecordAudioAction(); + break; + case 0x92042ff7: + result = new TL_sendMessageUploadVideoAction_old(); + break; + case 0xe6ac8a6f: + result = new TL_sendMessageUploadAudioAction_old(); + break; + case 0xf351d7ab: + result = new TL_sendMessageUploadAudioAction(); + break; + case 0xd1d34a26: + result = new TL_sendMessageUploadPhotoAction(); + break; + case 0x8faee98e: + result = new TL_sendMessageUploadDocumentAction_old(); + break; + case 0xe9763aec: + result = new TL_sendMessageUploadVideoAction(); + break; + case 0xfd5ec8f5: + result = new TL_sendMessageCancelAction(); + break; + case 0x176f8ba1: + result = new TL_sendMessageGeoLocationAction(); + break; + case 0x628cbc6f: + result = new TL_sendMessageChooseContactAction(); + break; + case 0x16bf744e: + result = new TL_sendMessageTypingAction(); + break; + case 0x990a3c1a: + result = new TL_sendMessageUploadPhotoAction_old(); + break; + case 0xaa0cd9e4: + result = new TL_sendMessageUploadDocumentAction(); + break; + case 0xa187d66f: + result = new TL_sendMessageRecordVideoAction(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in SendMessageAction", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_sendMessageRecordAudioAction extends SendMessageAction { + public static int constructor = 0xd52f73f7; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_sendMessageUploadVideoAction_old extends TL_sendMessageUploadVideoAction { + public static int constructor = 0x92042ff7; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_sendMessageUploadAudioAction_old extends TL_sendMessageUploadAudioAction { + public static int constructor = 0xe6ac8a6f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_sendMessageUploadAudioAction extends SendMessageAction { + public static int constructor = 0xf351d7ab; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + progress = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(progress); + } + } + + public static class TL_sendMessageUploadPhotoAction extends SendMessageAction { + public static int constructor = 0xd1d34a26; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + progress = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(progress); + } + } + + public static class TL_sendMessageUploadDocumentAction_old extends TL_sendMessageUploadDocumentAction { + public static int constructor = 0x8faee98e; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_sendMessageUploadVideoAction extends SendMessageAction { + public static int constructor = 0xe9763aec; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + progress = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(progress); + } + } + + public static class TL_sendMessageCancelAction extends SendMessageAction { + public static int constructor = 0xfd5ec8f5; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_sendMessageGeoLocationAction extends SendMessageAction { + public static int constructor = 0x176f8ba1; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_sendMessageChooseContactAction extends SendMessageAction { + public static int constructor = 0x628cbc6f; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_sendMessageTypingAction extends SendMessageAction { + public static int constructor = 0x16bf744e; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_sendMessageUploadPhotoAction_old extends TL_sendMessageUploadPhotoAction { + public static int constructor = 0x990a3c1a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_sendMessageUploadDocumentAction extends SendMessageAction { + public static int constructor = 0xaa0cd9e4; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + progress = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(progress); + } + } + + public static class TL_sendMessageRecordVideoAction extends SendMessageAction { + public static int constructor = 0xa187d66f; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class auth_SentCodeType extends TLObject { + public int length; + public String pattern; + + public static auth_SentCodeType TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + auth_SentCodeType result = null; + switch(constructor) { + case 0x3dbb5986: + result = new TL_auth_sentCodeTypeApp(); + break; + case 0x5353e5a7: + result = new TL_auth_sentCodeTypeCall(); + break; + case 0xab03c6d9: + result = new TL_auth_sentCodeTypeFlashCall(); + break; + case 0xc000bba2: + result = new TL_auth_sentCodeTypeSms(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in auth_SentCodeType", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_auth_sentCodeTypeApp extends auth_SentCodeType { + public static int constructor = 0x3dbb5986; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + length = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(length); + } + } + + public static class TL_auth_sentCodeTypeCall extends auth_SentCodeType { + public static int constructor = 0x5353e5a7; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + length = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(length); + } + } + + public static class TL_auth_sentCodeTypeFlashCall extends auth_SentCodeType { + public static int constructor = 0xab03c6d9; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + pattern = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(pattern); + } + } + + public static class TL_auth_sentCodeTypeSms extends auth_SentCodeType { + public static int constructor = 0xc000bba2; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + length = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(length); + } + } + + public static class TL_peerSettings extends TLObject { + public static int constructor = 0x818426cd; + + public int flags; + public boolean report_spam; + + public static TL_peerSettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_peerSettings.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_peerSettings", constructor)); + } else { + return null; + } + } + TL_peerSettings result = new TL_peerSettings(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + report_spam = (flags & 1) != 0; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = report_spam ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + } + } + + public static class FoundGif extends TLObject { + public String url; + public Photo photo; + public Document document; + public String thumb_url; + public String content_url; + public String content_type; + public int w; + public int h; + + public static FoundGif TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + FoundGif result = null; + switch(constructor) { + case 0x9c750409: + result = new TL_foundGifCached(); + break; + case 0x162ecc1f: + result = new TL_foundGif(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in FoundGif", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_foundGifCached extends FoundGif { + public static int constructor = 0x9c750409; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + url = stream.readString(exception); + photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + document = Document.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(url); + photo.serializeToStream(stream); + document.serializeToStream(stream); + } + } + + public static class TL_foundGif extends FoundGif { + public static int constructor = 0x162ecc1f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + url = stream.readString(exception); + thumb_url = stream.readString(exception); + content_url = stream.readString(exception); + content_type = stream.readString(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(url); + stream.writeString(thumb_url); + stream.writeString(content_url); + stream.writeString(content_type); + stream.writeInt32(w); + stream.writeInt32(h); + } + } + + public static class TL_inputPhoneContact extends TLObject { + public static int constructor = 0xf392b7f4; + + public long client_id; + public String phone; + public String first_name; + public String last_name; + + public static TL_inputPhoneContact TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_inputPhoneContact.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_inputPhoneContact", constructor)); + } else { + return null; + } + } + TL_inputPhoneContact result = new TL_inputPhoneContact(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + client_id = stream.readInt64(exception); + phone = stream.readString(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(client_id); + stream.writeString(phone); + stream.writeString(first_name); + stream.writeString(last_name); + } + } + + public static class PrivacyRule extends TLObject { + public ArrayList users = new ArrayList<>(); + + public static PrivacyRule TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + PrivacyRule result = null; + switch(constructor) { + case 0x4d5bbe0c: + result = new TL_privacyValueAllowUsers(); + break; + case 0x8b73e763: + result = new TL_privacyValueDisallowAll(); + break; + case 0xfffe1bac: + result = new TL_privacyValueAllowContacts(); + break; + case 0xf888fa1a: + result = new TL_privacyValueDisallowContacts(); + break; + case 0x65427b82: + result = new TL_privacyValueAllowAll(); + break; + case 0xc7f49b7: + result = new TL_privacyValueDisallowUsers(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in PrivacyRule", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_privacyValueAllowUsers extends PrivacyRule { + public static int constructor = 0x4d5bbe0c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + users.add(stream.readInt32(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(users.get(a)); + } + } + } + + public static class TL_privacyValueDisallowAll extends PrivacyRule { + public static int constructor = 0x8b73e763; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_privacyValueAllowContacts extends PrivacyRule { + public static int constructor = 0xfffe1bac; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_privacyValueDisallowContacts extends PrivacyRule { + public static int constructor = 0xf888fa1a; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_privacyValueAllowAll extends PrivacyRule { + public static int constructor = 0x65427b82; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_privacyValueDisallowUsers extends PrivacyRule { + public static int constructor = 0xc7f49b7; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + users.add(stream.readInt32(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(users.get(a)); + } + } + } + + public static class TL_messageMediaUnsupported_old extends TL_messageMediaUnsupported { + public static int constructor = 0x29632a36; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + bytes = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(bytes); + } + } + + public static class TL_messageMediaAudio_layer45 extends MessageMedia { + public static int constructor = 0xc6b68300; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + audio_unused = Audio.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + audio_unused.serializeToStream(stream); + } + } + + public static class TL_messageMediaPhoto_old extends TL_messageMediaPhoto { + public static int constructor = 0xc8c45a2a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + photo.serializeToStream(stream); + } + } + + public static class TL_messageMediaUnsupported extends MessageMedia { + public static int constructor = 0x9f84f49e; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messageMediaEmpty extends MessageMedia { + public static int constructor = 0x3ded6320; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messageMediaVenue extends MessageMedia { + public static int constructor = 0x7912b71f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + title = stream.readString(exception); + address = stream.readString(exception); + provider = stream.readString(exception); + venue_id = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + geo.serializeToStream(stream); + stream.writeString(title); + stream.writeString(address); + stream.writeString(provider); + stream.writeString(venue_id); + } + } + + public static class TL_messageMediaVideo_old extends TL_messageMediaVideo_layer45 { + public static int constructor = 0xa2d24290; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + video_unused = Video.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + video_unused.serializeToStream(stream); + } + } + + public static class TL_messageMediaDocument_old extends TL_messageMediaDocument { + public static int constructor = 0x2fda2204; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + document = Document.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + document.serializeToStream(stream); + } + } + + public static class TL_messageMediaDocument extends MessageMedia { + public static int constructor = 0xf3e02ea8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + document = Document.TLdeserialize(stream, stream.readInt32(exception), exception); + caption = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + document.serializeToStream(stream); + stream.writeString(caption); + } + } + + public static class TL_messageMediaContact extends MessageMedia { + public static int constructor = 0x5e7d2f39; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + phone_number = stream.readString(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + user_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(phone_number); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeInt32(user_id); + } + } + + public static class TL_messageMediaPhoto extends MessageMedia { + public static int constructor = 0x3d8ce53d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + caption = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + photo.serializeToStream(stream); + stream.writeString(caption); + } + } + + public static class TL_messageMediaVideo_layer45 extends MessageMedia { + public static int constructor = 0x5bcf1675; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + video_unused = Video.TLdeserialize(stream, stream.readInt32(exception), exception); + caption = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + video_unused.serializeToStream(stream); + stream.writeString(caption); + } + } + + public static class TL_messageMediaGeo extends MessageMedia { + public static int constructor = 0x56e0d474; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + geo.serializeToStream(stream); + } + } + + public static class TL_messageMediaWebPage extends MessageMedia { + public static int constructor = 0xa32dd600; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + webpage = WebPage.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + webpage.serializeToStream(stream); + } + } + + public static class TL_auth_sentCode extends TLObject { + public static int constructor = 0x5e002502; + + public int flags; + public boolean phone_registered; + public auth_SentCodeType type; + public String phone_code_hash; + public auth_CodeType next_type; + public int timeout; + + public static TL_auth_sentCode TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_auth_sentCode.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_auth_sentCode", constructor)); + } else { + return null; + } + } + TL_auth_sentCode result = new TL_auth_sentCode(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + phone_registered = (flags & 1) != 0; + type = auth_SentCodeType.TLdeserialize(stream, stream.readInt32(exception), exception); + phone_code_hash = stream.readString(exception); + if ((flags & 2) != 0) { + next_type = auth_CodeType.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4) != 0) { + timeout = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + flags = phone_registered ? (flags | 1) : (flags &~ 1); + type.serializeToStream(stream); + stream.writeString(phone_code_hash); + if ((flags & 2) != 0) { + next_type.serializeToStream(stream); + } + if ((flags & 4) != 0) { + stream.writeInt32(timeout); + } + } + } + + public static class BotInlineResult extends TLObject { + public int flags; + public String id; + public String type; + public String title; + public String description; + public String url; + public String thumb_url; + public String content_url; + public String content_type; + public int w; + public int h; + public int duration; + public BotInlineMessage send_message; + public Photo photo; + public Document document; + public long query_id; + + public static BotInlineResult TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + BotInlineResult result = null; + switch(constructor) { + case 0x9bebaeb9: + result = new TL_botInlineResult(); + break; + case 0x17db940b: + result = new TL_botInlineMediaResult(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in BotInlineResult", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_botInlineResult extends BotInlineResult { + public static int constructor = 0x9bebaeb9; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + id = stream.readString(exception); + type = stream.readString(exception); + if ((flags & 2) != 0) { + title = stream.readString(exception); + } + if ((flags & 4) != 0) { + description = stream.readString(exception); + } + if ((flags & 8) != 0) { + url = stream.readString(exception); + } + if ((flags & 16) != 0) { + thumb_url = stream.readString(exception); + } + if ((flags & 32) != 0) { + content_url = stream.readString(exception); + } + if ((flags & 32) != 0) { + content_type = stream.readString(exception); + } + if ((flags & 64) != 0) { + w = stream.readInt32(exception); + } + if ((flags & 64) != 0) { + h = stream.readInt32(exception); + } + if ((flags & 128) != 0) { + duration = stream.readInt32(exception); + } + send_message = BotInlineMessage.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeString(id); + stream.writeString(type); + if ((flags & 2) != 0) { + stream.writeString(title); + } + if ((flags & 4) != 0) { + stream.writeString(description); + } + if ((flags & 8) != 0) { + stream.writeString(url); + } + if ((flags & 16) != 0) { + stream.writeString(thumb_url); + } + if ((flags & 32) != 0) { + stream.writeString(content_url); + } + if ((flags & 32) != 0) { + stream.writeString(content_type); + } + if ((flags & 64) != 0) { + stream.writeInt32(w); + } + if ((flags & 64) != 0) { + stream.writeInt32(h); + } + if ((flags & 128) != 0) { + stream.writeInt32(duration); + } + send_message.serializeToStream(stream); + } + } + + public static class TL_botInlineMediaResult extends BotInlineResult { + public static int constructor = 0x17db940b; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + id = stream.readString(exception); + type = stream.readString(exception); + if ((flags & 1) != 0) { + photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 2) != 0) { + document = Document.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 4) != 0) { + title = stream.readString(exception); + } + if ((flags & 8) != 0) { + description = stream.readString(exception); + } + send_message = BotInlineMessage.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeString(id); + stream.writeString(type); + if ((flags & 1) != 0) { + photo.serializeToStream(stream); + } + if ((flags & 2) != 0) { + document.serializeToStream(stream); + } + if ((flags & 4) != 0) { + stream.writeString(title); + } + if ((flags & 8) != 0) { + stream.writeString(description); + } + send_message.serializeToStream(stream); + } + } + + public static class PeerNotifySettings extends TLObject { + public int flags; + public boolean silent; + public int mute_until; + public String sound; + public int events_mask; + + public static PeerNotifySettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + PeerNotifySettings result = null; + switch(constructor) { + case 0x9acda4c0: + result = new TL_peerNotifySettings(); + break; + case 0x8d5e11ee: + result = new TL_peerNotifySettings_layer47(); + break; + case 0x70a68512: + result = new TL_peerNotifySettingsEmpty(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in PeerNotifySettings", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_peerNotifySettings extends PeerNotifySettings { + public static int constructor = 0x9acda4c0; + + public boolean show_previews; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + show_previews = (flags & 1) != 0; + silent = (flags & 2) != 0; + mute_until = stream.readInt32(exception); + sound = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = show_previews ? (flags | 1) : (flags &~ 1); + flags = silent ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + stream.writeInt32(mute_until); + stream.writeString(sound); + } + } + + public static class TL_peerNotifySettings_layer47 extends TL_peerNotifySettings { + public static int constructor = 0x8d5e11ee; + + public boolean show_previews; + + public void readParams(AbstractSerializedData stream, boolean exception) { + mute_until = stream.readInt32(exception); + sound = stream.readString(exception); + show_previews = stream.readBool(exception); + events_mask = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(mute_until); + stream.writeString(sound); + stream.writeBool(show_previews); + stream.writeInt32(events_mask); + } + } + + public static class TL_peerNotifySettingsEmpty extends PeerNotifySettings { + public static int constructor = 0x70a68512; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class contacts_Blocked extends TLObject { + public ArrayList blocked = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + public int count; + + public static contacts_Blocked TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + contacts_Blocked result = null; + switch(constructor) { + case 0x1c138d15: + result = new TL_contacts_blocked(); + break; + case 0x900802a1: + result = new TL_contacts_blockedSlice(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in contacts_Blocked", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_contacts_blocked extends contacts_Blocked { + public static int constructor = 0x1c138d15; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_contactBlocked object = TL_contactBlocked.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + blocked.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = blocked.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + blocked.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_contacts_blockedSlice extends contacts_Blocked { + public static int constructor = 0x900802a1; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_contactBlocked object = TL_contactBlocked.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + blocked.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(count); + stream.writeInt32(0x1cb5c415); + int count = blocked.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + blocked.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class messages_DhConfig extends TLObject { + public byte[] random; + public int g; + public byte[] p; + public int version; + + public static messages_DhConfig TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + messages_DhConfig result = null; + switch(constructor) { + case 0xc0e24635: + result = new TL_messages_dhConfigNotModified(); + break; + case 0x2c221edd: + result = new TL_messages_dhConfig(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in messages_DhConfig", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messages_dhConfigNotModified extends messages_DhConfig { + public static int constructor = 0xc0e24635; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + random = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(random); + } + } + + public static class TL_messages_dhConfig extends messages_DhConfig { + public static int constructor = 0x2c221edd; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + g = stream.readInt32(exception); + p = stream.readByteArray(exception); + version = stream.readInt32(exception); + random = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(g); + stream.writeByteArray(p); + stream.writeInt32(version); + stream.writeByteArray(random); + } + } + + public static class TL_messages_stickerSet extends TLObject { + public static int constructor = 0xb60a24a6; + + public StickerSet set; + public ArrayList packs = new ArrayList<>(); + public ArrayList documents = new ArrayList<>(); + + public static TL_messages_stickerSet TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_stickerSet.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_stickerSet", constructor)); + } else { + return null; + } + } + TL_messages_stickerSet result = new TL_messages_stickerSet(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + set = StickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_stickerPack object = TL_stickerPack.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + packs.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Document object = Document.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + documents.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + set.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = packs.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + packs.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = documents.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + documents.get(a).serializeToStream(stream); + } + } + } + + public static class InputGeoPoint extends TLObject { + public double lat; + public double _long; + + public static InputGeoPoint TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputGeoPoint result = null; + switch(constructor) { + case 0xf3b7acc9: + result = new TL_inputGeoPoint(); + break; + case 0xe4c123d6: + result = new TL_inputGeoPointEmpty(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputGeoPoint", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputGeoPoint extends InputGeoPoint { + public static int constructor = 0xf3b7acc9; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + lat = stream.readDouble(exception); + _long = stream.readDouble(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeDouble(lat); + stream.writeDouble(_long); + } + } + + public static class TL_inputGeoPointEmpty extends InputGeoPoint { + public static int constructor = 0xe4c123d6; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_help_inviteText extends TLObject { + public static int constructor = 0x18cb9f78; + + public String message; + + public static TL_help_inviteText TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_help_inviteText.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_help_inviteText", constructor)); + } else { + return null; + } + } + TL_help_inviteText result = new TL_help_inviteText(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + message = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(message); + } + } + + public static class Audio extends TLObject { + public long id; + public long access_hash; + public int date; + public int duration; + public String mime_type; + public int size; + public int dc_id; + public int user_id; + public byte[] key; + public byte[] iv; + + public static Audio TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + Audio result = null; + switch(constructor) { + case 0x586988d8: + result = new TL_audioEmpty_layer45(); + break; + case 0xf9e35055: + result = new TL_audio_layer45(); + break; + case 0x427425e7: + result = new TL_audio_old(); + break; + case 0x555555F6: + result = new TL_audioEncrypted(); + break; + case 0xc7ac6496: + result = new TL_audio_old2(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in Audio", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_audioEmpty_layer45 extends Audio { + public static int constructor = 0x586988d8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + } + } + + public static class TL_audio_layer45 extends Audio { + public static int constructor = 0xf9e35055; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + date = stream.readInt32(exception); + duration = stream.readInt32(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); + dc_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(date); + stream.writeInt32(duration); + stream.writeString(mime_type); + stream.writeInt32(size); + stream.writeInt32(dc_id); + } + } + + public static class TL_audio_old extends TL_audio_layer45 { + public static int constructor = 0x427425e7; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + duration = stream.readInt32(exception); + size = stream.readInt32(exception); + dc_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + stream.writeInt32(duration); + stream.writeInt32(size); + stream.writeInt32(dc_id); + } + } + + public static class TL_audioEncrypted extends TL_audio_layer45 { + public static int constructor = 0x555555F6; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + duration = stream.readInt32(exception); + size = stream.readInt32(exception); + dc_id = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + stream.writeInt32(duration); + stream.writeInt32(size); + stream.writeInt32(dc_id); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_audio_old2 extends TL_audio_layer45 { + public static int constructor = 0xc7ac6496; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + duration = stream.readInt32(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); + dc_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + stream.writeInt32(duration); + stream.writeString(mime_type); + stream.writeInt32(size); + stream.writeInt32(dc_id); + } + } + + public static class BotInfo extends TLObject { + public int user_id; + public String description; + public ArrayList commands = new ArrayList<>(); + public int version; + + public static BotInfo TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + BotInfo result = null; + switch(constructor) { + case 0xbb2e37ce: + result = new TL_botInfoEmpty_layer48(); + break; + case 0x98e81d3a: + result = new TL_botInfo(); + break; + case 0x9cf585d: + result = new TL_botInfo_layer48(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in BotInfo", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_botInfoEmpty_layer48 extends TL_botInfo { + public static int constructor = 0xbb2e37ce; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_botInfo extends BotInfo { + public static int constructor = 0x98e81d3a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + description = stream.readString(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_botCommand object = TL_botCommand.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + commands.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeString(description); + stream.writeInt32(0x1cb5c415); + int count = commands.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + commands.get(a).serializeToStream(stream); + } + } + } + + public static class TL_botInfo_layer48 extends TL_botInfo { + public static int constructor = 0x9cf585d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + version = stream.readInt32(exception); + stream.readString(exception); + description = stream.readString(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_botCommand object = TL_botCommand.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + commands.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeInt32(version); + stream.writeString(""); + stream.writeString(description); + stream.writeInt32(0x1cb5c415); + int count = commands.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + commands.get(a).serializeToStream(stream); + } + } + } + + public static class ReplyMarkup extends TLObject { + public ArrayList rows = new ArrayList<>(); + public int flags; + public boolean selective; + public boolean single_use; + public boolean resize; + + public static ReplyMarkup TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + ReplyMarkup result = null; + switch(constructor) { + case 0x48a30254: + result = new TL_replyInlineMarkup(); + break; + case 0xa03e5b85: + result = new TL_replyKeyboardHide(); + break; + case 0xf4108aa0: + result = new TL_replyKeyboardForceReply(); + break; + case 0x3502758c: + result = new TL_replyKeyboardMarkup(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in ReplyMarkup", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_replyInlineMarkup extends ReplyMarkup { + public static int constructor = 0x48a30254; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_keyboardButtonRow object = TL_keyboardButtonRow.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + rows.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = rows.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + rows.get(a).serializeToStream(stream); + } + } + } + + public static class TL_replyKeyboardHide extends ReplyMarkup { + public static int constructor = 0xa03e5b85; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + selective = (flags & 4) != 0; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = selective ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + } + } + + public static class TL_replyKeyboardForceReply extends ReplyMarkup { + public static int constructor = 0xf4108aa0; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + single_use = (flags & 2) != 0; + selective = (flags & 4) != 0; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = single_use ? (flags | 2) : (flags &~ 2); + flags = selective ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + } + } + + public static class TL_replyKeyboardMarkup extends ReplyMarkup { + public static int constructor = 0x3502758c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + resize = (flags & 1) != 0; + single_use = (flags & 2) != 0; + selective = (flags & 4) != 0; + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_keyboardButtonRow object = TL_keyboardButtonRow.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + rows.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = resize ? (flags | 1) : (flags &~ 1); + flags = single_use ? (flags | 2) : (flags &~ 2); + flags = selective ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + stream.writeInt32(0x1cb5c415); + int count = rows.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + rows.get(a).serializeToStream(stream); + } + } + } + + public static class contacts_Contacts extends TLObject { + public ArrayList contacts = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + public static contacts_Contacts TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + contacts_Contacts result = null; + switch(constructor) { + case 0xb74ba9d2: + result = new TL_contacts_contactsNotModified(); + break; + case 0x6f8b8cb2: + result = new TL_contacts_contacts(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in contacts_Contacts", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_contacts_contactsNotModified extends contacts_Contacts { + public static int constructor = 0xb74ba9d2; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_contacts_contacts extends contacts_Contacts { + public static int constructor = 0x6f8b8cb2; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_contact object = TL_contact.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + contacts.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = contacts.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + contacts.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class InputPrivacyKey extends TLObject { + + public static InputPrivacyKey TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputPrivacyKey result = null; + switch(constructor) { + case 0xbdfb0426: + result = new TL_inputPrivacyKeyChatInvite(); + break; + case 0x4f96cb18: + result = new TL_inputPrivacyKeyStatusTimestamp(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputPrivacyKey", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputPrivacyKeyChatInvite extends InputPrivacyKey { + public static int constructor = 0xbdfb0426; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputPrivacyKeyStatusTimestamp extends InputPrivacyKey { + public static int constructor = 0x4f96cb18; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class photos_Photos extends TLObject { + public ArrayList photos = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + public int count; + + public static photos_Photos TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + photos_Photos result = null; + switch(constructor) { + case 0x8dca6aa5: + result = new TL_photos_photos(); + break; + case 0x15051f54: + result = new TL_photos_photosSlice(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in photos_Photos", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_photos_photos extends photos_Photos { + public static int constructor = 0x8dca6aa5; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Photo object = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + photos.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = photos.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + photos.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_photos_photosSlice extends photos_Photos { + public static int constructor = 0x15051f54; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Photo object = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + photos.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(count); + stream.writeInt32(0x1cb5c415); + int count = photos.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + photos.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class ChatFull extends TLObject { + public int flags; + public boolean can_view_participants; + public boolean can_set_username; + public int id; + public String about; + public int participants_count; + public int admins_count; + public int kicked_count; + public int read_inbox_max_id; + public int unread_count; + public int unread_important_count; + public Photo chat_photo; + public PeerNotifySettings notify_settings; + public ExportedChatInvite exported_invite; + public ArrayList bot_info = new ArrayList<>(); + public int migrated_from_chat_id; + public int migrated_from_max_id; + public int pinned_msg_id; + public ChatParticipants participants; + + public static ChatFull TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + ChatFull result = null; + switch(constructor) { + case 0x97bee562: + result = new TL_channelFull(); + break; + case 0x2e02a614: + result = new TL_chatFull(); + break; + case 0x9e341ddf: + result = new TL_channelFull_layer48(); + break; + case 0xfab31aa3: + result = new TL_channelFull_old(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in ChatFull", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_channelFull extends ChatFull { + public static int constructor = 0x97bee562; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + can_view_participants = (flags & 8) != 0; + can_set_username = (flags & 64) != 0; + id = stream.readInt32(exception); + about = stream.readString(exception); + if ((flags & 1) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags & 2) != 0) { + admins_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + kicked_count = stream.readInt32(exception); + } + read_inbox_max_id = stream.readInt32(exception); + unread_count = stream.readInt32(exception); + unread_important_count = stream.readInt32(exception); + chat_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + exported_invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + BotInfo object = BotInfo.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + bot_info.add(object); + } + if ((flags & 16) != 0) { + migrated_from_chat_id = stream.readInt32(exception); + } + if ((flags & 16) != 0) { + migrated_from_max_id = stream.readInt32(exception); + } + if ((flags & 32) != 0) { + pinned_msg_id = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = can_view_participants ? (flags | 8) : (flags &~ 8); + flags = can_set_username ? (flags | 64) : (flags &~ 64); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeString(about); + if ((flags & 1) != 0) { + stream.writeInt32(participants_count); + } + if ((flags & 2) != 0) { + stream.writeInt32(admins_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(kicked_count); + } + stream.writeInt32(read_inbox_max_id); + stream.writeInt32(unread_count); + stream.writeInt32(unread_important_count); + chat_photo.serializeToStream(stream); + notify_settings.serializeToStream(stream); + exported_invite.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = bot_info.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + bot_info.get(a).serializeToStream(stream); + } + if ((flags & 16) != 0) { + stream.writeInt32(migrated_from_chat_id); + } + if ((flags & 16) != 0) { + stream.writeInt32(migrated_from_max_id); + } + if ((flags & 32) != 0) { + stream.writeInt32(pinned_msg_id); + } + } + } + + public static class TL_chatFull extends ChatFull { + public static int constructor = 0x2e02a614; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + participants = ChatParticipants.TLdeserialize(stream, stream.readInt32(exception), exception); + chat_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + exported_invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + BotInfo object = BotInfo.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + bot_info.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + participants.serializeToStream(stream); + chat_photo.serializeToStream(stream); + notify_settings.serializeToStream(stream); + exported_invite.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = bot_info.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + bot_info.get(a).serializeToStream(stream); + } + } + } + + public static class TL_channelFull_layer48 extends TL_channelFull { + public static int constructor = 0x9e341ddf; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + can_view_participants = (flags & 8) != 0; + id = stream.readInt32(exception); + about = stream.readString(exception); + if ((flags & 1) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags & 2) != 0) { + admins_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + kicked_count = stream.readInt32(exception); + } + read_inbox_max_id = stream.readInt32(exception); + unread_count = stream.readInt32(exception); + unread_important_count = stream.readInt32(exception); + chat_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + exported_invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + BotInfo object = BotInfo.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + bot_info.add(object); + } + if ((flags & 16) != 0) { + migrated_from_chat_id = stream.readInt32(exception); + } + if ((flags & 16) != 0) { + migrated_from_max_id = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = can_view_participants ? (flags | 8) : (flags &~ 8); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeString(about); + if ((flags & 1) != 0) { + stream.writeInt32(participants_count); + } + if ((flags & 2) != 0) { + stream.writeInt32(admins_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(kicked_count); + } + stream.writeInt32(read_inbox_max_id); + stream.writeInt32(unread_count); + stream.writeInt32(unread_important_count); + chat_photo.serializeToStream(stream); + notify_settings.serializeToStream(stream); + exported_invite.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = bot_info.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + bot_info.get(a).serializeToStream(stream); + } + if ((flags & 16) != 0) { + stream.writeInt32(migrated_from_chat_id); + } + if ((flags & 16) != 0) { + stream.writeInt32(migrated_from_max_id); + } + } + } + + public static class TL_channelFull_old extends TL_channelFull { + public static int constructor = 0xfab31aa3; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + can_view_participants = (flags & 8) != 0; + id = stream.readInt32(exception); + about = stream.readString(exception); + if ((flags & 1) != 0) { + participants_count = stream.readInt32(exception); + } + if ((flags & 2) != 0) { + admins_count = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + kicked_count = stream.readInt32(exception); + } + read_inbox_max_id = stream.readInt32(exception); + unread_count = stream.readInt32(exception); + unread_important_count = stream.readInt32(exception); + chat_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + exported_invite = ExportedChatInvite.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = can_view_participants ? (flags | 8) : (flags &~ 8); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeString(about); + if ((flags & 1) != 0) { + stream.writeInt32(participants_count); + } + if ((flags & 2) != 0) { + stream.writeInt32(admins_count); + } + if ((flags & 4) != 0) { + stream.writeInt32(kicked_count); + } + stream.writeInt32(read_inbox_max_id); + stream.writeInt32(unread_count); + stream.writeInt32(unread_important_count); + chat_photo.serializeToStream(stream); + notify_settings.serializeToStream(stream); + exported_invite.serializeToStream(stream); + } + } + + public static class TL_inputPeerNotifySettings extends TLObject { + public static int constructor = 0x38935eb2; + + public int flags; + public boolean show_previews; + public boolean silent; + public int mute_until; + public String sound; + + public static TL_inputPeerNotifySettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_inputPeerNotifySettings.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_inputPeerNotifySettings", constructor)); + } else { + return null; + } + } + TL_inputPeerNotifySettings result = new TL_inputPeerNotifySettings(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + show_previews = (flags & 1) != 0; + silent = (flags & 2) != 0; + mute_until = stream.readInt32(exception); + sound = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = show_previews ? (flags | 1) : (flags &~ 1); + flags = silent ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + stream.writeInt32(mute_until); + stream.writeString(sound); + } + } + + public static class TL_null extends TLObject { + public static int constructor = 0x56730bcc; + + + public static TL_null TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_null.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_null", constructor)); + } else { + return null; + } + } + TL_null result = new TL_null(); + result.readParams(stream, exception); + return result; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class InputUser extends TLObject { + public int user_id; + public long access_hash; + + public static InputUser TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputUser result = null; + switch(constructor) { + case 0xb98886cf: + result = new TL_inputUserEmpty(); + break; + case 0xf7c1b13f: + result = new TL_inputUserSelf(); + break; + case 0xd8292816: + result = new TL_inputUser(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputUser", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputUserEmpty extends InputUser { + public static int constructor = 0xb98886cf; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputUserSelf extends InputUser { + public static int constructor = 0xf7c1b13f; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputUser extends InputUser { + public static int constructor = 0xd8292816; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeInt64(access_hash); + } + } + + public static class KeyboardButton extends TLObject { + public String text; + public String query; + public byte[] data; + public String url; + + public static KeyboardButton TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + KeyboardButton result = null; + switch(constructor) { + case 0xa2fa4880: + result = new TL_keyboardButton(); + break; + case 0xea1b7a14: + result = new TL_keyboardButtonSwitchInline(); + break; + case 0xb16a6c29: + result = new TL_keyboardButtonRequestPhone(); + break; + case 0x683a5e46: + result = new TL_keyboardButtonCallback(); + break; + case 0x258aff05: + result = new TL_keyboardButtonUrl(); + break; + case 0xfc796b3f: + result = new TL_keyboardButtonRequestGeoLocation(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in KeyboardButton", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_keyboardButton extends KeyboardButton { + public static int constructor = 0xa2fa4880; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + } + } + + public static class TL_keyboardButtonSwitchInline extends KeyboardButton { + public static int constructor = 0xea1b7a14; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + query = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeString(query); + } + } + + public static class TL_keyboardButtonRequestPhone extends KeyboardButton { + public static int constructor = 0xb16a6c29; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + } + } + + public static class TL_keyboardButtonCallback extends KeyboardButton { + public static int constructor = 0x683a5e46; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + data = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeByteArray(data); + } + } + + public static class TL_keyboardButtonUrl extends KeyboardButton { + public static int constructor = 0x258aff05; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeString(url); + } + } + + public static class TL_keyboardButtonRequestGeoLocation extends KeyboardButton { + public static int constructor = 0xfc796b3f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + } + } + + public static class BotInlineMessage extends TLObject { + public int flags; + public GeoPoint geo; + public ReplyMarkup reply_markup; + public String caption; + public boolean no_webpage; + public String message; + public ArrayList entities = new ArrayList<>(); + public String phone_number; + public String first_name; + public String last_name; + public String title; + public String address; + public String provider; + public String venue_id; + + public static BotInlineMessage TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + BotInlineMessage result = null; + switch(constructor) { + case 0x3a8fd8b8: + result = new TL_botInlineMessageMediaGeo(); + break; + case 0xa74b15b: + result = new TL_botInlineMessageMediaAuto(); + break; + case 0x8c7f65e2: + result = new TL_botInlineMessageText(); + break; + case 0x35edb4d4: + result = new TL_botInlineMessageMediaContact(); + break; + case 0x4366232e: + result = new TL_botInlineMessageMediaVenue(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in BotInlineMessage", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_botInlineMessageMediaGeo extends BotInlineMessage { + public static int constructor = 0x3a8fd8b8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + geo.serializeToStream(stream); + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } + + public static class TL_botInlineMessageMediaAuto extends BotInlineMessage { + public static int constructor = 0xa74b15b; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + caption = stream.readString(exception); + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeString(caption); + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } + + public static class TL_botInlineMessageText extends BotInlineMessage { + public static int constructor = 0x8c7f65e2; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + no_webpage = (flags & 1) != 0; + message = stream.readString(exception); + if ((flags & 2) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = no_webpage ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeString(message); + if ((flags & 2) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } + + public static class TL_botInlineMessageMediaContact extends BotInlineMessage { + public static int constructor = 0x35edb4d4; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + phone_number = stream.readString(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeString(phone_number); + stream.writeString(first_name); + stream.writeString(last_name); + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } + + public static class TL_botInlineMessageMediaVenue extends BotInlineMessage { + public static int constructor = 0x4366232e; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + title = stream.readString(exception); + address = stream.readString(exception); + provider = stream.readString(exception); + venue_id = stream.readString(exception); + if ((flags & 4) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + geo.serializeToStream(stream); + stream.writeString(title); + stream.writeString(address); + stream.writeString(provider); + stream.writeString(venue_id); + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } + + public static class TL_keyboardButtonRow extends TLObject { + public static int constructor = 0x77608b83; + + public ArrayList buttons = new ArrayList<>(); + + public static TL_keyboardButtonRow TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_keyboardButtonRow.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_keyboardButtonRow", constructor)); + } else { + return null; + } + } + TL_keyboardButtonRow result = new TL_keyboardButtonRow(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + KeyboardButton object = KeyboardButton.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + buttons.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = buttons.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + buttons.get(a).serializeToStream(stream); + } + } + } + + public static class Bool extends TLObject { + + public static Bool TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + Bool result = null; + switch(constructor) { + case 0x997275b5: + result = new TL_boolTrue(); + break; + case 0xbc799737: + result = new TL_boolFalse(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in Bool", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_boolTrue extends Bool { + public static int constructor = 0x997275b5; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_boolFalse extends Bool { + public static int constructor = 0xbc799737; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_auth_exportedAuthorization extends TLObject { + public static int constructor = 0xdf969c2d; + + public int id; + public byte[] bytes; + + public static TL_auth_exportedAuthorization TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_auth_exportedAuthorization.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_auth_exportedAuthorization", constructor)); + } else { + return null; + } + } + TL_auth_exportedAuthorization result = new TL_auth_exportedAuthorization(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + bytes = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeByteArray(bytes); + } + } + + public static class WebPage extends TLObject { + public int flags; + public long id; + public String url; + public String display_url; + public String type; + public String site_name; + public String title; + public String description; + public Photo photo; + public String embed_url; + public String embed_type; + public int embed_width; + public int embed_height; + public int duration; + public String author; + public int date; + public Document document; + + public static WebPage TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + WebPage result = null; + switch(constructor) { + case 0xa31ea0b5: + result = new TL_webPage_old(); + break; + case 0xd41a5167: + result = new TL_webPageUrlPending(); + break; + case 0xc586da1c: + result = new TL_webPagePending(); + break; + case 0xeb1477e8: + result = new TL_webPageEmpty(); + break; + case 0xca820ed7: + result = new TL_webPage(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in WebPage", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_webPagePending extends WebPage { + public static int constructor = 0xc586da1c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt32(date); + } + } + + public static class TL_webPageEmpty extends WebPage { + public static int constructor = 0xeb1477e8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + } + } + + public static class TL_webPageUrlPending extends WebPage { + public static int constructor = 0xd41a5167; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(url); + } + } + + public static class TL_webPage_old extends WebPage { + public static int constructor = 0xa31ea0b5; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + id = stream.readInt64(exception); + url = stream.readString(exception); + display_url = stream.readString(exception); + if ((flags & 1) != 0) { + type = stream.readString(exception); + } + if ((flags & 2) != 0) { + site_name = stream.readString(exception); + } + if ((flags & 4) != 0) { + title = stream.readString(exception); + } + if ((flags & 8) != 0) { + description = stream.readString(exception); + } + if ((flags & 16) != 0) { + photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32) != 0) { + embed_url = stream.readString(exception); + } + if ((flags & 32) != 0) { + embed_type = stream.readString(exception); + } + if ((flags & 64) != 0) { + embed_width = stream.readInt32(exception); + } + if ((flags & 64) != 0) { + embed_height = stream.readInt32(exception); + } + if ((flags & 128) != 0) { + duration = stream.readInt32(exception); + } + if ((flags & 256) != 0) { + author = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt64(id); + stream.writeString(url); + stream.writeString(display_url); + if ((flags & 1) != 0) { + stream.writeString(type); + } + if ((flags & 2) != 0) { + stream.writeString(site_name); + } + if ((flags & 4) != 0) { + stream.writeString(title); + } + if ((flags & 8) != 0) { + stream.writeString(description); + } + if ((flags & 16) != 0) { + photo.serializeToStream(stream); + } + if ((flags & 32) != 0) { + stream.writeString(embed_url); + } + if ((flags & 32) != 0) { + stream.writeString(embed_type); + } + if ((flags & 64) != 0) { + stream.writeInt32(embed_width); + } + if ((flags & 64) != 0) { + stream.writeInt32(embed_height); + } + if ((flags & 128) != 0) { + stream.writeInt32(duration); + } + if ((flags & 256) != 0) { + stream.writeString(author); + } + } + } + + public static class TL_webPage extends WebPage { + public static int constructor = 0xca820ed7; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + id = stream.readInt64(exception); + url = stream.readString(exception); + display_url = stream.readString(exception); + if ((flags & 1) != 0) { + type = stream.readString(exception); + } + if ((flags & 2) != 0) { + site_name = stream.readString(exception); + } + if ((flags & 4) != 0) { + title = stream.readString(exception); + } + if ((flags & 8) != 0) { + description = stream.readString(exception); + } + if ((flags & 16) != 0) { + photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 32) != 0) { + embed_url = stream.readString(exception); + } + if ((flags & 32) != 0) { + embed_type = stream.readString(exception); + } + if ((flags & 64) != 0) { + embed_width = stream.readInt32(exception); + } + if ((flags & 64) != 0) { + embed_height = stream.readInt32(exception); + } + if ((flags & 128) != 0) { + duration = stream.readInt32(exception); + } + if ((flags & 256) != 0) { + author = stream.readString(exception); + } + if ((flags & 512) != 0) { + document = Document.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt64(id); + stream.writeString(url); + stream.writeString(display_url); + if ((flags & 1) != 0) { + stream.writeString(type); + } + if ((flags & 2) != 0) { + stream.writeString(site_name); + } + if ((flags & 4) != 0) { + stream.writeString(title); + } + if ((flags & 8) != 0) { + stream.writeString(description); + } + if ((flags & 16) != 0) { + photo.serializeToStream(stream); + } + if ((flags & 32) != 0) { + stream.writeString(embed_url); + } + if ((flags & 32) != 0) { + stream.writeString(embed_type); + } + if ((flags & 64) != 0) { + stream.writeInt32(embed_width); + } + if ((flags & 64) != 0) { + stream.writeInt32(embed_height); + } + if ((flags & 128) != 0) { + stream.writeInt32(duration); + } + if ((flags & 256) != 0) { + stream.writeString(author); + } + if ((flags & 512) != 0) { + document.serializeToStream(stream); + } + } + } + + public static class TL_auth_passwordRecovery extends TLObject { + public static int constructor = 0x137948a5; + + public String email_pattern; + + public static TL_auth_passwordRecovery TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_auth_passwordRecovery.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_auth_passwordRecovery", constructor)); + } else { + return null; + } + } + TL_auth_passwordRecovery result = new TL_auth_passwordRecovery(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + email_pattern = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(email_pattern); + } + } + + public static class TL_botCommand extends TLObject { + public static int constructor = 0xc27ac8c7; + + public String command; + public String description; + + public static TL_botCommand TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_botCommand.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_botCommand", constructor)); + } else { + return null; + } + } + TL_botCommand result = new TL_botCommand(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + command = stream.readString(exception); + description = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(command); + stream.writeString(description); + } + } + + public static class InputNotifyPeer extends TLObject { + + public static InputNotifyPeer TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputNotifyPeer result = null; + switch(constructor) { + case 0x4a95e84e: + result = new TL_inputNotifyChats(); + break; + case 0xb8bc5b0c: + result = new TL_inputNotifyPeer(); + break; + case 0x193b4417: + result = new TL_inputNotifyUsers(); + break; + case 0x4d8ddec8: + result = new TL_inputNotifyGeoChatPeer(); + break; + case 0xa429b886: + result = new TL_inputNotifyAll(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputNotifyPeer", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputNotifyChats extends InputNotifyPeer { + public static int constructor = 0x4a95e84e; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputNotifyPeer extends InputNotifyPeer { + public static int constructor = 0xb8bc5b0c; + + public InputPeer peer; + + public void readParams(AbstractSerializedData stream, boolean exception) { + peer = InputPeer.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + } + } + + public static class TL_inputNotifyUsers extends InputNotifyPeer { + public static int constructor = 0x193b4417; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputNotifyGeoChatPeer extends InputNotifyPeer { + public static int constructor = 0x4d8ddec8; + + public TL_inputGeoChat peer; + + public void readParams(AbstractSerializedData stream, boolean exception) { + peer = TL_inputGeoChat.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + } + } + + public static class TL_inputNotifyAll extends InputNotifyPeer { + public static int constructor = 0xa429b886; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class InputFileLocation extends TLObject { + public long id; + public long access_hash; + public long volume_id; + public int local_id; + public long secret; + + public static InputFileLocation TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputFileLocation result = null; + switch(constructor) { + case 0xf5235d55: + result = new TL_inputEncryptedFileLocation(); + break; + case 0x4e45abe9: + result = new TL_inputDocumentFileLocation(); + break; + case 0x14637196: + result = new TL_inputFileLocation(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputFileLocation", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputEncryptedFileLocation extends InputFileLocation { + public static int constructor = 0xf5235d55; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + } + } + + public static class TL_inputDocumentFileLocation extends InputFileLocation { + public static int constructor = 0x4e45abe9; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + } + } + + public static class TL_inputFileLocation extends InputFileLocation { + public static int constructor = 0x14637196; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + volume_id = stream.readInt64(exception); + local_id = stream.readInt32(exception); + secret = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(volume_id); + stream.writeInt32(local_id); + stream.writeInt64(secret); + } + } + + public static class TL_photos_photo extends TLObject { + public static int constructor = 0x20212ca8; + + public Photo photo; + public ArrayList users = new ArrayList<>(); + + public static TL_photos_photo TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_photos_photo.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_photos_photo", constructor)); + } else { + return null; + } + } + TL_photos_photo result = new TL_photos_photo(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + photo.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class User extends TLObject { + public int id; + public String first_name; + public String last_name; + public String username; + public long access_hash; + public String phone; + public UserProfilePhoto photo; + public UserStatus status; + public boolean inactive; + public int flags; + public boolean self; + public boolean contact; + public boolean mutual_contact; + public boolean deleted; + public boolean bot; + public boolean bot_chat_history; + public boolean bot_nochats; + public boolean verified; + public boolean explicit_content; + public int bot_info_version; + public boolean restricted; + public boolean min; + public boolean bot_inline_geo; + public String restriction_reason; + public String bot_inline_placeholder; + + public static User TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + User result = null; + switch(constructor) { + case 0xcab35e18: + result = new TL_userContact_old2(); + break; + case 0xf2fb8319: + result = new TL_userContact_old(); + break; + case 0x720535ec: + result = new TL_userSelf_old(); + break; + case 0x1c60e608: + result = new TL_userSelf_old3(); + break; + case 0xd6016d7a: + result = new TL_userDeleted_old2(); + break; + case 0x200250ba: + result = new TL_userEmpty(); + break; + case 0x22e8ceb0: + result = new TL_userRequest_old(); + break; + case 0x5214c89d: + result = new TL_userForeign_old(); + break; + case 0x75cf7a8: + result = new TL_userForeign_old2(); + break; + case 0xd9ccc4ef: + result = new TL_userRequest_old2(); + break; + case 0xb29ad7cc: + result = new TL_userDeleted_old(); + break; + case 0x7007b451: + result = new TL_userSelf_old2(); + break; + case 0x22e49072: + result = new TL_user_old(); + break; + case 0xd10d979a: + result = new TL_user(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in User", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_userContact_old2 extends User { + public static int constructor = 0xcab35e18; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + username = stream.readString(exception); + access_hash = stream.readInt64(exception); + phone = stream.readString(exception); + photo = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeString(username); + stream.writeInt64(access_hash); + stream.writeString(phone); + photo.serializeToStream(stream); + status.serializeToStream(stream); + } + } + + public static class TL_userContact_old extends TL_userContact_old2 { + public static int constructor = 0xf2fb8319; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + access_hash = stream.readInt64(exception); + phone = stream.readString(exception); + photo = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeInt64(access_hash); + stream.writeString(phone); + photo.serializeToStream(stream); + status.serializeToStream(stream); + } + } + + public static class TL_userSelf_old extends TL_userSelf_old3 { + public static int constructor = 0x720535ec; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + phone = stream.readString(exception); + photo = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + inactive = stream.readBool(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeString(phone); + photo.serializeToStream(stream); + status.serializeToStream(stream); + stream.writeBool(inactive); + } + } + + public static class TL_userSelf_old3 extends User { + public static int constructor = 0x1c60e608; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + username = stream.readString(exception); + phone = stream.readString(exception); + photo = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeString(username); + stream.writeString(phone); + photo.serializeToStream(stream); + status.serializeToStream(stream); + } + } + + public static class TL_userDeleted_old2 extends User { + public static int constructor = 0xd6016d7a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + username = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeString(username); + } + } + + public static class TL_userEmpty extends User { + public static int constructor = 0x200250ba; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + } + } + + public static class TL_userRequest_old extends TL_userRequest_old2 { + public static int constructor = 0x22e8ceb0; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + access_hash = stream.readInt64(exception); + phone = stream.readString(exception); + photo = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeInt64(access_hash); + stream.writeString(phone); + photo.serializeToStream(stream); + status.serializeToStream(stream); + } + } + + public static class TL_userForeign_old extends TL_userForeign_old2 { + public static int constructor = 0x5214c89d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + access_hash = stream.readInt64(exception); + photo = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeInt64(access_hash); + photo.serializeToStream(stream); + status.serializeToStream(stream); + } + } + + public static class TL_userForeign_old2 extends User { + public static int constructor = 0x75cf7a8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + username = stream.readString(exception); + access_hash = stream.readInt64(exception); + photo = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeString(username); + stream.writeInt64(access_hash); + photo.serializeToStream(stream); + status.serializeToStream(stream); + } + } + + public static class TL_userRequest_old2 extends User { + public static int constructor = 0xd9ccc4ef; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + username = stream.readString(exception); + access_hash = stream.readInt64(exception); + phone = stream.readString(exception); + photo = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeString(username); + stream.writeInt64(access_hash); + stream.writeString(phone); + photo.serializeToStream(stream); + status.serializeToStream(stream); + } + } + + public static class TL_userDeleted_old extends TL_userDeleted_old2 { + public static int constructor = 0xb29ad7cc; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + } + } + + public static class TL_userSelf_old2 extends TL_userSelf_old3 { + public static int constructor = 0x7007b451; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + username = stream.readString(exception); + phone = stream.readString(exception); + photo = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + inactive = stream.readBool(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeString(username); + stream.writeString(phone); + photo.serializeToStream(stream); + status.serializeToStream(stream); + stream.writeBool(inactive); + } + } + + public static class TL_user_old extends TL_user { + public static int constructor = 0x22e49072; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + self = (flags & 1024) != 0; + contact = (flags & 2048) != 0; + mutual_contact = (flags & 4096) != 0; + deleted = (flags & 8192) != 0; + bot = (flags & 16384) != 0; + bot_chat_history = (flags & 32768) != 0; + bot_nochats = (flags & 65536) != 0; + verified = (flags & 131072) != 0; + explicit_content = (flags & 262144) != 0; + id = stream.readInt32(exception); + if ((flags & 1) != 0) { + access_hash = stream.readInt64(exception); + } + if ((flags & 2) != 0) { + first_name = stream.readString(exception); + } + if ((flags & 4) != 0) { + last_name = stream.readString(exception); + } + if ((flags & 8) != 0) { + username = stream.readString(exception); + } + if ((flags & 16) != 0) { + phone = stream.readString(exception); + } + if ((flags & 32) != 0) { + photo = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 64) != 0) { + status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 16384) != 0) { + bot_info_version = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = self ? (flags | 1024) : (flags &~ 1024); + flags = contact ? (flags | 2048) : (flags &~ 2048); + flags = mutual_contact ? (flags | 4096) : (flags &~ 4096); + flags = deleted ? (flags | 8192) : (flags &~ 8192); + flags = bot ? (flags | 16384) : (flags &~ 16384); + flags = bot_chat_history ? (flags | 32768) : (flags &~ 32768); + flags = bot_nochats ? (flags | 65536) : (flags &~ 65536); + flags = verified ? (flags | 131072) : (flags &~ 131072); + flags = explicit_content ? (flags | 262144) : (flags &~ 262144); + stream.writeInt32(flags); + stream.writeInt32(id); + if ((flags & 1) != 0) { + stream.writeInt64(access_hash); + } + if ((flags & 2) != 0) { + stream.writeString(first_name); + } + if ((flags & 4) != 0) { + stream.writeString(last_name); + } + if ((flags & 8) != 0) { + stream.writeString(username); + } + if ((flags & 16) != 0) { + stream.writeString(phone); + } + if ((flags & 32) != 0) { + photo.serializeToStream(stream); + } + if ((flags & 64) != 0) { + status.serializeToStream(stream); + } + if ((flags & 16384) != 0) { + stream.writeInt32(bot_info_version); + } + } + } + + public static class TL_user extends User { + public static int constructor = 0xd10d979a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + self = (flags & 1024) != 0; + contact = (flags & 2048) != 0; + mutual_contact = (flags & 4096) != 0; + deleted = (flags & 8192) != 0; + bot = (flags & 16384) != 0; + bot_chat_history = (flags & 32768) != 0; + bot_nochats = (flags & 65536) != 0; + verified = (flags & 131072) != 0; + restricted = (flags & 262144) != 0; + min = (flags & 1048576) != 0; + bot_inline_geo = (flags & 2097152) != 0; + id = stream.readInt32(exception); + if ((flags & 1) != 0) { + access_hash = stream.readInt64(exception); + } + if ((flags & 2) != 0) { + first_name = stream.readString(exception); + } + if ((flags & 4) != 0) { + last_name = stream.readString(exception); + } + if ((flags & 8) != 0) { + username = stream.readString(exception); + } + if ((flags & 16) != 0) { + phone = stream.readString(exception); + } + if ((flags & 32) != 0) { + photo = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 64) != 0) { + status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 16384) != 0) { + bot_info_version = stream.readInt32(exception); + } + if ((flags & 262144) != 0) { + restriction_reason = stream.readString(exception); + } + if ((flags & 524288) != 0) { + bot_inline_placeholder = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = self ? (flags | 1024) : (flags &~ 1024); + flags = contact ? (flags | 2048) : (flags &~ 2048); + flags = mutual_contact ? (flags | 4096) : (flags &~ 4096); + flags = deleted ? (flags | 8192) : (flags &~ 8192); + flags = bot ? (flags | 16384) : (flags &~ 16384); + flags = bot_chat_history ? (flags | 32768) : (flags &~ 32768); + flags = bot_nochats ? (flags | 65536) : (flags &~ 65536); + flags = verified ? (flags | 131072) : (flags &~ 131072); + flags = restricted ? (flags | 262144) : (flags &~ 262144); + flags = min ? (flags | 1048576) : (flags &~ 1048576); + flags = bot_inline_geo ? (flags | 2097152) : (flags &~ 2097152); + stream.writeInt32(flags); + stream.writeInt32(id); + if ((flags & 1) != 0) { + stream.writeInt64(access_hash); + } + if ((flags & 2) != 0) { + stream.writeString(first_name); + } + if ((flags & 4) != 0) { + stream.writeString(last_name); + } + if ((flags & 8) != 0) { + stream.writeString(username); + } + if ((flags & 16) != 0) { + stream.writeString(phone); + } + if ((flags & 32) != 0) { + photo.serializeToStream(stream); + } + if ((flags & 64) != 0) { + status.serializeToStream(stream); + } + if ((flags & 16384) != 0) { + stream.writeInt32(bot_info_version); + } + if ((flags & 262144) != 0) { + stream.writeString(restriction_reason); + } + if ((flags & 524288) != 0) { + stream.writeString(bot_inline_placeholder); + } + } + } + + public static class ChannelParticipantRole extends TLObject { + + public static ChannelParticipantRole TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + ChannelParticipantRole result = null; + switch(constructor) { + case 0x820bfe8c: + result = new TL_channelRoleEditor(); + break; + case 0xb285a0c6: + result = new TL_channelRoleEmpty(); + break; + case 0x9618d975: + result = new TL_channelRoleModerator(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in ChannelParticipantRole", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_channelRoleEditor extends ChannelParticipantRole { + public static int constructor = 0x820bfe8c; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_channelRoleEmpty extends ChannelParticipantRole { + public static int constructor = 0xb285a0c6; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_channelRoleModerator extends ChannelParticipantRole { + public static int constructor = 0x9618d975; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class ChannelParticipantsFilter extends TLObject { + + public static ChannelParticipantsFilter TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + ChannelParticipantsFilter result = null; + switch(constructor) { + case 0xb4608969: + result = new TL_channelParticipantsAdmins(); + break; + case 0xde3f3c79: + result = new TL_channelParticipantsRecent(); + break; + case 0x3c37bb7a: + result = new TL_channelParticipantsKicked(); + break; + case 0xb0d1865b: + result = new TL_channelParticipantsBots(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in ChannelParticipantsFilter", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_channelParticipantsAdmins extends ChannelParticipantsFilter { + public static int constructor = 0xb4608969; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_channelParticipantsRecent extends ChannelParticipantsFilter { + public static int constructor = 0xde3f3c79; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_channelParticipantsKicked extends ChannelParticipantsFilter { + public static int constructor = 0x3c37bb7a; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_channelParticipantsBots extends ChannelParticipantsFilter { + public static int constructor = 0xb0d1865b; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class GeoChatMessage extends TLObject { + public int chat_id; + public int id; + public int from_id; + public int date; + public String message; + public MessageMedia media; + public MessageAction action; + + public static GeoChatMessage TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + GeoChatMessage result = null; + switch(constructor) { + case 0x4505f8e1: + result = new TL_geoChatMessage(); + break; + case 0xd34fa24e: + result = new TL_geoChatMessageService(); + break; + case 0x60311a9b: + result = new TL_geoChatMessageEmpty(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in GeoChatMessage", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_geoChatMessage extends GeoChatMessage { + public static int constructor = 0x4505f8e1; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + id = stream.readInt32(exception); + from_id = stream.readInt32(exception); + date = stream.readInt32(exception); + message = stream.readString(exception); + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeInt32(id); + stream.writeInt32(from_id); + stream.writeInt32(date); + stream.writeString(message); + media.serializeToStream(stream); + } + } + + public static class TL_geoChatMessageService extends GeoChatMessage { + public static int constructor = 0xd34fa24e; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + id = stream.readInt32(exception); + from_id = stream.readInt32(exception); + date = stream.readInt32(exception); + action = MessageAction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeInt32(id); + stream.writeInt32(from_id); + stream.writeInt32(date); + action.serializeToStream(stream); + } + } + + public static class TL_geoChatMessageEmpty extends GeoChatMessage { + public static int constructor = 0x60311a9b; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeInt32(id); + } + } + + public static class MessageAction extends TLObject { + public String title; + public String address; + public DecryptedMessageAction encryptedAction; + public ArrayList users = new ArrayList<>(); + public int channel_id; + public Photo photo; + public int chat_id; + public int user_id; + public UserProfilePhoto newUserPhoto; + public int inviter_id; + public int ttl; + + public static MessageAction TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + MessageAction result = null; + switch(constructor) { + case 0x555555F5: + result = new TL_messageActionLoginUnknownLocation(); + break; + case 0x555555F7: + result = new TL_messageEncryptedAction(); + break; + case 0xa6638b9a: + result = new TL_messageActionChatCreate(); + break; + case 0x51bdb021: + result = new TL_messageActionChatMigrateTo(); + break; + case 0x7fcb13a8: + result = new TL_messageActionChatEditPhoto(); + break; + case 0xb055eaee: + result = new TL_messageActionChannelMigrateFrom(); + break; + case 0x488a7337: + result = new TL_messageActionChatAddUser(); + break; + case 0xb2ae9b0c: + result = new TL_messageActionChatDeleteUser(); + break; + case 0x55555557: + result = new TL_messageActionCreatedBroadcastList(); + break; + case 0x55555550: + result = new TL_messageActionUserJoined(); + break; + case 0x55555551: + result = new TL_messageActionUserUpdatedPhoto(); + break; + case 0xc7d53de: + result = new TL_messageActionGeoChatCheckin(); + break; + case 0xf89cf5e8: + result = new TL_messageActionChatJoinedByLink(); + break; + case 0x5e3cfc4b: + result = new TL_messageActionChatAddUser_old(); + break; + case 0x55555552: + result = new TL_messageActionTTLChange(); + break; + case 0x95d2ac92: + result = new TL_messageActionChannelCreate(); + break; + case 0x94bd38ed: + result = new TL_messageActionPinMessage(); + break; + case 0x95e3fbef: + result = new TL_messageActionChatDeletePhoto(); + break; + case 0xb5a1ce5a: + result = new TL_messageActionChatEditTitle(); + break; + case 0xb6aef7b0: + result = new TL_messageActionEmpty(); + break; + case 0x6f038ebc: + result = new TL_messageActionGeoChatCreate(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in MessageAction", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messageActionLoginUnknownLocation extends MessageAction { + public static int constructor = 0x555555F5; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + title = stream.readString(exception); + address = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(title); + stream.writeString(address); + } + } + + public static class TL_messageEncryptedAction extends MessageAction { + public static int constructor = 0x555555F7; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + encryptedAction = DecryptedMessageAction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + encryptedAction.serializeToStream(stream); + } + } + + public static class TL_messageActionChatCreate extends MessageAction { + public static int constructor = 0xa6638b9a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + title = stream.readString(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + users.add(stream.readInt32(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(title); + stream.writeInt32(0x1cb5c415); + int count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(users.get(a)); + } + } + } + + public static class TL_messageActionChatMigrateTo extends MessageAction { + public static int constructor = 0x51bdb021; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + channel_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(channel_id); + } + } + + public static class TL_messageActionChatEditPhoto extends MessageAction { + public static int constructor = 0x7fcb13a8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + photo.serializeToStream(stream); + } + } + + public static class TL_messageActionChannelMigrateFrom extends MessageAction { + public static int constructor = 0xb055eaee; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + title = stream.readString(exception); + chat_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(title); + stream.writeInt32(chat_id); + } + } + + public static class TL_messageActionChatAddUser extends MessageAction { + public static int constructor = 0x488a7337; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + users.add(stream.readInt32(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(users.get(a)); + } + } + } + + public static class TL_messageActionChatDeleteUser extends MessageAction { + public static int constructor = 0xb2ae9b0c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + } + } + + public static class TL_messageActionCreatedBroadcastList extends MessageAction { + public static int constructor = 0x55555557; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messageActionUserJoined extends MessageAction { + public static int constructor = 0x55555550; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messageActionUserUpdatedPhoto extends MessageAction { + public static int constructor = 0x55555551; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + newUserPhoto = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + newUserPhoto.serializeToStream(stream); + } + } + + public static class TL_messageActionGeoChatCheckin extends MessageAction { + public static int constructor = 0xc7d53de; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messageActionChatJoinedByLink extends MessageAction { + public static int constructor = 0xf89cf5e8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + inviter_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(inviter_id); + } + } + + public static class TL_messageActionChatAddUser_old extends TL_messageActionChatAddUser { + public static int constructor = 0x5e3cfc4b; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + } + } + + public static class TL_messageActionTTLChange extends MessageAction { + public static int constructor = 0x55555552; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + ttl = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(ttl); + } + } + + public static class TL_messageActionChannelCreate extends MessageAction { + public static int constructor = 0x95d2ac92; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + title = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(title); + } + } + + public static class TL_messageActionPinMessage extends MessageAction { + public static int constructor = 0x94bd38ed; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messageActionChatDeletePhoto extends MessageAction { + public static int constructor = 0x95e3fbef; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messageActionChatEditTitle extends MessageAction { + public static int constructor = 0xb5a1ce5a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + title = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(title); + } + } + + public static class TL_messageActionEmpty extends MessageAction { + public static int constructor = 0xb6aef7b0; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messageActionGeoChatCreate extends MessageAction { + public static int constructor = 0x6f038ebc; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + title = stream.readString(exception); + address = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(title); + stream.writeString(address); + } + } + + public static class ReportReason extends TLObject { + public String text; + + public static ReportReason TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + ReportReason result = null; + switch(constructor) { + case 0x58dbcab8: + result = new TL_inputReportReasonSpam(); + break; + case 0x1e22c78d: + result = new TL_inputReportReasonViolence(); + break; + case 0xe1746d0a: + result = new TL_inputReportReasonOther(); + break; + case 0x2e59d922: + result = new TL_inputReportReasonPornography(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in ReportReason", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputReportReasonSpam extends ReportReason { + public static int constructor = 0x58dbcab8; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputReportReasonViolence extends ReportReason { + public static int constructor = 0x1e22c78d; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputReportReasonOther extends ReportReason { + public static int constructor = 0xe1746d0a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + } + } + + public static class TL_inputReportReasonPornography extends ReportReason { + public static int constructor = 0x2e59d922; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class PeerNotifyEvents extends TLObject { + + public static PeerNotifyEvents TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + PeerNotifyEvents result = null; + switch(constructor) { + case 0xadd53cb3: + result = new TL_peerNotifyEventsEmpty(); + break; + case 0x6d1ded88: + result = new TL_peerNotifyEventsAll(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in PeerNotifyEvents", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_peerNotifyEventsEmpty extends PeerNotifyEvents { + public static int constructor = 0xadd53cb3; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_peerNotifyEventsAll extends PeerNotifyEvents { + public static int constructor = 0x6d1ded88; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_chatLocated extends TLObject { + public static int constructor = 0x3631cf4c; + + public int chat_id; + public int distance; + + public static TL_chatLocated TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_chatLocated.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_chatLocated", constructor)); + } else { + return null; + } + } + TL_chatLocated result = new TL_chatLocated(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + distance = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeInt32(distance); + } + } + + public static class DecryptedMessage extends TLObject { + public long random_id; + public int ttl; + public String message; + public DecryptedMessageMedia media; + public DecryptedMessageAction action; + public byte[] random_bytes; + public int flags; + public ArrayList entities = new ArrayList<>(); + public String via_bot_name; + public long reply_to_random_id; + + public static DecryptedMessage TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + DecryptedMessage result = null; + switch(constructor) { + case 0x204d3878: + result = new TL_decryptedMessage_layer17(); + break; + case 0x73164160: + result = new TL_decryptedMessageService(); + break; + case 0xaa48327d: + result = new TL_decryptedMessageService_layer8(); + break; + case 0x1f814f1f: + result = new TL_decryptedMessage_layer8(); + break; + case 0x36b091de: + result = new TL_decryptedMessage(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in DecryptedMessage", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_decryptedMessage_layer17 extends TL_decryptedMessage { + public static int constructor = 0x204d3878; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + random_id = stream.readInt64(exception); + ttl = stream.readInt32(exception); + message = stream.readString(exception); + media = DecryptedMessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(random_id); + stream.writeInt32(ttl); + stream.writeString(message); + media.serializeToStream(stream); + } + } + + public static class TL_decryptedMessageService extends DecryptedMessage { + public static int constructor = 0x73164160; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + random_id = stream.readInt64(exception); + action = DecryptedMessageAction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(random_id); + action.serializeToStream(stream); + } + } + + public static class TL_decryptedMessageService_layer8 extends TL_decryptedMessageService { + public static int constructor = 0xaa48327d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + random_id = stream.readInt64(exception); + random_bytes = stream.readByteArray(exception); + action = DecryptedMessageAction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(random_id); + stream.writeByteArray(random_bytes); + action.serializeToStream(stream); + } + } + + public static class TL_decryptedMessage_layer8 extends TL_decryptedMessage { + public static int constructor = 0x1f814f1f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + random_id = stream.readInt64(exception); + random_bytes = stream.readByteArray(exception); + message = stream.readString(exception); + media = DecryptedMessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(random_id); + stream.writeByteArray(random_bytes); + stream.writeString(message); + media.serializeToStream(stream); + } + } + + public static class TL_decryptedMessage extends DecryptedMessage { + public static int constructor = 0x36b091de; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + random_id = stream.readInt64(exception); + ttl = stream.readInt32(exception); + message = stream.readString(exception); + if ((flags & 512) != 0) { + media = DecryptedMessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 128) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + if ((flags & 2048) != 0) { + via_bot_name = stream.readString(exception); + } + if ((flags & 8) != 0) { + reply_to_random_id = stream.readInt64(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt64(random_id); + stream.writeInt32(ttl); + stream.writeString(message); + if ((flags & 512) != 0) { + media.serializeToStream(stream); + } + if ((flags & 128) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + if ((flags & 2048) != 0) { + stream.writeString(via_bot_name); + } + if ((flags & 8) != 0) { + stream.writeInt64(reply_to_random_id); + } + } + } + + public static class InputPeerNotifyEvents extends TLObject { + + public static InputPeerNotifyEvents TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputPeerNotifyEvents result = null; + switch(constructor) { + case 0xe86a2c74: + result = new TL_inputPeerNotifyEventsAll(); + break; + case 0xf03064d8: + result = new TL_inputPeerNotifyEventsEmpty(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputPeerNotifyEvents", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputPeerNotifyEventsAll extends InputPeerNotifyEvents { + public static int constructor = 0xe86a2c74; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputPeerNotifyEventsEmpty extends InputPeerNotifyEvents { + public static int constructor = 0xf03064d8; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class Video extends TLObject { + public long id; + public long access_hash; + public int user_id; + public int date; + public int duration; + public int size; + public PhotoSize thumb; + public int dc_id; + public int w; + public int h; + public String mime_type; + public String caption; + public byte[] key; + public byte[] iv; + + public static Video TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + Video result = null; + switch(constructor) { + case 0xee9f4a4d: + result = new TL_video_old3(); + break; + case 0xf72887d3: + result = new TL_video_layer45(); + break; + case 0x55555553: + result = new TL_videoEncrypted(); + break; + case 0x5a04a49f: + result = new TL_video_old(); + break; + case 0x388fa391: + result = new TL_video_old2(); + break; + case 0xc10658a8: + result = new TL_videoEmpty_layer45(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in Video", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_video_old3 extends TL_video_layer45 { + public static int constructor = 0xee9f4a4d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + duration = stream.readInt32(exception); + size = stream.readInt32(exception); + thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + dc_id = stream.readInt32(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + stream.writeInt32(duration); + stream.writeInt32(size); + thumb.serializeToStream(stream); + stream.writeInt32(dc_id); + stream.writeInt32(w); + stream.writeInt32(h); + } + } + + public static class TL_video_layer45 extends Video { + public static int constructor = 0xf72887d3; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + date = stream.readInt32(exception); + duration = stream.readInt32(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); + thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + dc_id = stream.readInt32(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(date); + stream.writeInt32(duration); + stream.writeString(mime_type); + stream.writeInt32(size); + thumb.serializeToStream(stream); + stream.writeInt32(dc_id); + stream.writeInt32(w); + stream.writeInt32(h); + } + } + + public static class TL_videoEncrypted extends TL_video_layer45 { + public static int constructor = 0x55555553; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + caption = stream.readString(exception); + duration = stream.readInt32(exception); + size = stream.readInt32(exception); + thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + dc_id = stream.readInt32(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + stream.writeString(caption); + stream.writeInt32(duration); + stream.writeInt32(size); + thumb.serializeToStream(stream); + stream.writeInt32(dc_id); + stream.writeInt32(w); + stream.writeInt32(h); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_video_old extends TL_video_layer45 { + public static int constructor = 0x5a04a49f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + caption = stream.readString(exception); + duration = stream.readInt32(exception); + size = stream.readInt32(exception); + thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + dc_id = stream.readInt32(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + stream.writeString(caption); + stream.writeInt32(duration); + stream.writeInt32(size); + thumb.serializeToStream(stream); + stream.writeInt32(dc_id); + stream.writeInt32(w); + stream.writeInt32(h); + } + } + + public static class TL_video_old2 extends TL_video_layer45 { + public static int constructor = 0x388fa391; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + caption = stream.readString(exception); + duration = stream.readInt32(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); + thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + dc_id = stream.readInt32(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + stream.writeString(caption); + stream.writeInt32(duration); + stream.writeString(mime_type); + stream.writeInt32(size); + thumb.serializeToStream(stream); + stream.writeInt32(dc_id); + stream.writeInt32(w); + stream.writeInt32(h); + } + } + + public static class TL_videoEmpty_layer45 extends Video { + public static int constructor = 0xc10658a8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + } + } + + public static class TL_exportedMessageLink extends TLObject { + public static int constructor = 0x1f486803; + + public String link; + + public static TL_exportedMessageLink TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_exportedMessageLink.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_exportedMessageLink", constructor)); + } else { + return null; + } + } + TL_exportedMessageLink result = new TL_exportedMessageLink(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + link = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(link); + } + } + + public static class TL_contactBlocked extends TLObject { + public static int constructor = 0x561bc879; + + public int user_id; + public int date; + + public static TL_contactBlocked TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_contactBlocked.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_contactBlocked", constructor)); + } else { + return null; + } + } + TL_contactBlocked result = new TL_contactBlocked(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeInt32(date); + } + } + + public static class InputDocument extends TLObject { + public long id; + public long access_hash; + + public static InputDocument TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputDocument result = null; + switch(constructor) { + case 0x72f0eaae: + result = new TL_inputDocumentEmpty(); + break; + case 0x18798952: + result = new TL_inputDocument(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputDocument", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputDocumentEmpty extends InputDocument { + public static int constructor = 0x72f0eaae; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputDocument extends InputDocument { + public static int constructor = 0x18798952; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + } + } + + public static class TL_inputAppEvent extends TLObject { + public static int constructor = 0x770656a8; + + public double time; + public String type; + public long peer; + public String data; + + public static TL_inputAppEvent TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_inputAppEvent.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_inputAppEvent", constructor)); + } else { + return null; + } + } + TL_inputAppEvent result = new TL_inputAppEvent(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + time = stream.readDouble(exception); + type = stream.readString(exception); + peer = stream.readInt64(exception); + data = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeDouble(time); + stream.writeString(type); + stream.writeInt64(peer); + stream.writeString(data); + } + } + + public static class TL_messages_affectedHistory extends TLObject { + public static int constructor = 0xb45c69d1; + + public int pts; + public int pts_count; + public int offset; + + public static TL_messages_affectedHistory TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_affectedHistory.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_affectedHistory", constructor)); + } else { + return null; + } + } + TL_messages_affectedHistory result = new TL_messages_affectedHistory(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + offset = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(pts); + stream.writeInt32(pts_count); + stream.writeInt32(offset); + } + } + + public static class Document extends TLObject { + public long id; + public long access_hash; + public int user_id; + public int date; + public String file_name; + public String mime_type; + public int size; + public PhotoSize thumb; + public int dc_id; + public byte[] key; + public byte[] iv; + public String caption; + public ArrayList attributes = new ArrayList<>(); + + public static Document TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + Document result = null; + switch(constructor) { + case 0x55555556: + result = new TL_documentEncrypted_old(); + break; + case 0x9efc6326: + result = new TL_document_old(); + break; + case 0x36f8c871: + result = new TL_documentEmpty(); + break; + case 0x55555558: + result = new TL_documentEncrypted(); + break; + case 0xf9a39f4f: + result = new TL_document(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in Document", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_documentEncrypted_old extends TL_document { + public static int constructor = 0x55555556; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + file_name = stream.readString(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); + thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + dc_id = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + stream.writeString(file_name); + stream.writeString(mime_type); + stream.writeInt32(size); + thumb.serializeToStream(stream); + stream.writeInt32(dc_id); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_document_old extends TL_document { + public static int constructor = 0x9efc6326; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + file_name = stream.readString(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); + thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + dc_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + stream.writeString(file_name); + stream.writeString(mime_type); + stream.writeInt32(size); + thumb.serializeToStream(stream); + stream.writeInt32(dc_id); + } + } + + public static class TL_documentEmpty extends Document { + public static int constructor = 0x36f8c871; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + } + } + + public static class TL_documentEncrypted extends Document { + public static int constructor = 0x55555558; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + date = stream.readInt32(exception); + int startReadPosiition = stream.getPosition(); //TODO remove this hack after some time + try { + mime_type = stream.readString(true); + } catch (Exception e) { + mime_type = "audio/ogg"; + if (stream instanceof NativeByteBuffer) { + ((NativeByteBuffer) stream).position(startReadPosiition); + } + } + size = stream.readInt32(exception); + thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + dc_id = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + DocumentAttribute object = DocumentAttribute.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + attributes.add(object); + } + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(date); + stream.writeString(mime_type); + stream.writeInt32(size); + thumb.serializeToStream(stream); + stream.writeInt32(dc_id); + stream.writeInt32(0x1cb5c415); + int count = attributes.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + attributes.get(a).serializeToStream(stream); + } + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_document extends Document { + public static int constructor = 0xf9a39f4f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + date = stream.readInt32(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); + thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + dc_id = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + DocumentAttribute object = DocumentAttribute.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + attributes.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(date); + stream.writeString(mime_type); + stream.writeInt32(size); + thumb.serializeToStream(stream); + stream.writeInt32(dc_id); + stream.writeInt32(0x1cb5c415); + int count = attributes.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + attributes.get(a).serializeToStream(stream); + } + } + } + + public static class ContactLink extends TLObject { + + public static ContactLink TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + ContactLink result = null; + switch(constructor) { + case 0xfeedd3ad: + result = new TL_contactLinkNone(); + break; + case 0xd502c2d0: + result = new TL_contactLinkContact(); + break; + case 0x268f3f59: + result = new TL_contactLinkHasPhone(); + break; + case 0x5f4f9247: + result = new TL_contactLinkUnknown(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in ContactLink", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_contactLinkNone extends ContactLink { + public static int constructor = 0xfeedd3ad; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_contactLinkContact extends ContactLink { + public static int constructor = 0xd502c2d0; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_contactLinkHasPhone extends ContactLink { + public static int constructor = 0x268f3f59; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_contactLinkUnknown extends ContactLink { + public static int constructor = 0x5f4f9247; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class InputPrivacyRule extends TLObject { + public ArrayList users = new ArrayList<>(); + + public static InputPrivacyRule TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputPrivacyRule result = null; + switch(constructor) { + case 0x90110467: + result = new TL_inputPrivacyValueDisallowUsers(); + break; + case 0xd66b66c9: + result = new TL_inputPrivacyValueDisallowAll(); + break; + case 0xba52007: + result = new TL_inputPrivacyValueDisallowContacts(); + break; + case 0x184b35ce: + result = new TL_inputPrivacyValueAllowAll(); + break; + case 0xd09e07b: + result = new TL_inputPrivacyValueAllowContacts(); + break; + case 0x131cc67f: + result = new TL_inputPrivacyValueAllowUsers(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputPrivacyRule", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputPrivacyValueDisallowUsers extends InputPrivacyRule { + public static int constructor = 0x90110467; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + InputUser object = InputUser.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_inputPrivacyValueDisallowAll extends InputPrivacyRule { + public static int constructor = 0xd66b66c9; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputPrivacyValueDisallowContacts extends InputPrivacyRule { + public static int constructor = 0xba52007; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputPrivacyValueAllowAll extends InputPrivacyRule { + public static int constructor = 0x184b35ce; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputPrivacyValueAllowContacts extends InputPrivacyRule { + public static int constructor = 0xd09e07b; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputPrivacyValueAllowUsers extends InputPrivacyRule { + public static int constructor = 0x131cc67f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + InputUser object = InputUser.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class InputMedia extends TLObject { + public InputFile file; + public InputFile thumb; + public String mime_type; + public ArrayList attributes = new ArrayList<>(); + public String caption; + public InputGeoPoint geo_point; + public String title; + public String address; + public String provider; + public String venue_id; + public String phone_number; + public String first_name; + public String last_name; + public String url; + public String q; + + public static InputMedia TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputMedia result = null; + switch(constructor) { + case 0xad613491: + result = new TL_inputMediaUploadedThumbDocument(); + break; + case 0xf7aff1c0: + result = new TL_inputMediaUploadedPhoto(); + break; + case 0xf9c44144: + result = new TL_inputMediaGeoPoint(); + break; + case 0x2827a81a: + result = new TL_inputMediaVenue(); + break; + case 0xa6e45987: + result = new TL_inputMediaContact(); + break; + case 0x1a77f29c: + result = new TL_inputMediaDocument(); + break; + case 0x4843b0fd: + result = new TL_inputMediaGifExternal(); + break; + case 0x1d89306d: + result = new TL_inputMediaUploadedDocument(); + break; + case 0xe9bfb4f3: + result = new TL_inputMediaPhoto(); + break; + case 0x9664f57f: + result = new TL_inputMediaEmpty(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputMedia", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputMediaContact extends InputMedia { + public static int constructor = 0xa6e45987; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + phone_number = stream.readString(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(phone_number); + stream.writeString(first_name); + stream.writeString(last_name); + } + } + + public static class TL_inputMediaUploadedThumbDocument extends InputMedia { + public static int constructor = 0xad613491; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + file = InputFile.TLdeserialize(stream, stream.readInt32(exception), exception); + thumb = InputFile.TLdeserialize(stream, stream.readInt32(exception), exception); + mime_type = stream.readString(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + DocumentAttribute object = DocumentAttribute.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + attributes.add(object); + } + caption = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + file.serializeToStream(stream); + thumb.serializeToStream(stream); + stream.writeString(mime_type); + stream.writeInt32(0x1cb5c415); + int count = attributes.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + attributes.get(a).serializeToStream(stream); + } + stream.writeString(caption); + } + } + + public static class TL_inputMediaDocument extends InputMedia { + public static int constructor = 0x1a77f29c; + + public InputDocument id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = InputDocument.TLdeserialize(stream, stream.readInt32(exception), exception); + caption = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + id.serializeToStream(stream); + stream.writeString(caption); + } + } + + public static class TL_inputMediaGifExternal extends InputMedia { + public static int constructor = 0x4843b0fd; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + url = stream.readString(exception); + q = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(url); + stream.writeString(q); + } + } + + public static class TL_inputMediaGeoPoint extends InputMedia { + public static int constructor = 0xf9c44144; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + geo_point = InputGeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + geo_point.serializeToStream(stream); + } + } + + public static class TL_inputMediaEmpty extends InputMedia { + public static int constructor = 0x9664f57f; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputMediaUploadedPhoto extends InputMedia { + public static int constructor = 0xf7aff1c0; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + file = InputFile.TLdeserialize(stream, stream.readInt32(exception), exception); + caption = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + file.serializeToStream(stream); + stream.writeString(caption); + } + } + + public static class TL_inputMediaVenue extends InputMedia { + public static int constructor = 0x2827a81a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + geo_point = InputGeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + title = stream.readString(exception); + address = stream.readString(exception); + provider = stream.readString(exception); + venue_id = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + geo_point.serializeToStream(stream); + stream.writeString(title); + stream.writeString(address); + stream.writeString(provider); + stream.writeString(venue_id); + } + } + + public static class TL_inputMediaUploadedDocument extends InputMedia { + public static int constructor = 0x1d89306d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + file = InputFile.TLdeserialize(stream, stream.readInt32(exception), exception); + mime_type = stream.readString(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + DocumentAttribute object = DocumentAttribute.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + attributes.add(object); + } + caption = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + file.serializeToStream(stream); + stream.writeString(mime_type); + stream.writeInt32(0x1cb5c415); + int count = attributes.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + attributes.get(a).serializeToStream(stream); + } + stream.writeString(caption); + } + } + + public static class TL_inputMediaPhoto extends InputMedia { + public static int constructor = 0xe9bfb4f3; + + public InputPhoto id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = InputPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + caption = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + id.serializeToStream(stream); + stream.writeString(caption); + } + } + + public static class geochats_Messages extends TLObject { + public int count; + public ArrayList messages = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + public static geochats_Messages TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + geochats_Messages result = null; + switch(constructor) { + case 0xbc5863e8: + result = new TL_geochats_messagesSlice(); + break; + case 0xd1526db1: + result = new TL_geochats_messages(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in geochats_Messages", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_geochats_messagesSlice extends geochats_Messages { + public static int constructor = 0xbc5863e8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + GeoChatMessage object = GeoChatMessage.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + messages.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(count); + stream.writeInt32(0x1cb5c415); + int count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + messages.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_geochats_messages extends geochats_Messages { + public static int constructor = 0xd1526db1; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + GeoChatMessage object = GeoChatMessage.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + messages.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + messages.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class EncryptedMessage extends TLObject { + public long random_id; + public int chat_id; + public int date; + public byte[] bytes; + public EncryptedFile file; + + public static EncryptedMessage TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + EncryptedMessage result = null; + switch(constructor) { + case 0x23734b06: + result = new TL_encryptedMessageService(); + break; + case 0xed18c118: + result = new TL_encryptedMessage(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in EncryptedMessage", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_encryptedMessageService extends EncryptedMessage { + public static int constructor = 0x23734b06; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + random_id = stream.readInt64(exception); + chat_id = stream.readInt32(exception); + date = stream.readInt32(exception); + bytes = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(random_id); + stream.writeInt32(chat_id); + stream.writeInt32(date); + stream.writeByteArray(bytes); + } + } + + public static class TL_encryptedMessage extends EncryptedMessage { + public static int constructor = 0xed18c118; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + random_id = stream.readInt64(exception); + chat_id = stream.readInt32(exception); + date = stream.readInt32(exception); + bytes = stream.readByteArray(exception); + file = EncryptedFile.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(random_id); + stream.writeInt32(chat_id); + stream.writeInt32(date); + stream.writeByteArray(bytes); + file.serializeToStream(stream); + } + } + + public static class InputStickerSet extends TLObject { + public long id; + public long access_hash; + public String short_name; + + public static InputStickerSet TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputStickerSet result = null; + switch(constructor) { + case 0xffb62b95: + result = new TL_inputStickerSetEmpty(); + break; + case 0x9de7a269: + result = new TL_inputStickerSetID(); + break; + case 0x861cc8a0: + result = new TL_inputStickerSetShortName(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputStickerSet", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputStickerSetEmpty extends InputStickerSet { + public static int constructor = 0xffb62b95; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputStickerSetID extends InputStickerSet { + public static int constructor = 0x9de7a269; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + } + } + + public static class TL_inputStickerSetShortName extends InputStickerSet { + public static int constructor = 0x861cc8a0; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + short_name = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(short_name); + } + } + + public static class UserStatus extends TLObject { + public int expires; + + public static UserStatus TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + UserStatus result = null; + switch(constructor) { + case 0x8c703f: + result = new TL_userStatusOffline(); + break; + case 0x7bf09fc: + result = new TL_userStatusLastWeek(); + break; + case 0x9d05049: + result = new TL_userStatusEmpty(); + break; + case 0x77ebc742: + result = new TL_userStatusLastMonth(); + break; + case 0xedb93949: + result = new TL_userStatusOnline(); + break; + case 0xe26f42f1: + result = new TL_userStatusRecently(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in UserStatus", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_userStatusOffline extends UserStatus { + public static int constructor = 0x8c703f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + expires = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(expires); + } + } + + public static class TL_userStatusLastWeek extends UserStatus { + public static int constructor = 0x7bf09fc; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_userStatusEmpty extends UserStatus { + public static int constructor = 0x9d05049; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_userStatusLastMonth extends UserStatus { + public static int constructor = 0x77ebc742; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_userStatusOnline extends UserStatus { + public static int constructor = 0xedb93949; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + expires = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(expires); + } + } + + public static class TL_userStatusRecently extends UserStatus { + public static int constructor = 0xe26f42f1; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messages_messageEditData extends TLObject { + public static int constructor = 0x26b5dde6; + + public int flags; + public boolean caption; + + public static TL_messages_messageEditData TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_messageEditData.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_messageEditData", constructor)); + } else { + return null; + } + } + TL_messages_messageEditData result = new TL_messages_messageEditData(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + caption = (flags & 1) != 0; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = caption ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + } + } + + public static class TL_contacts_importedContacts extends TLObject { + public static int constructor = 0xad524315; + + public ArrayList imported = new ArrayList<>(); + public ArrayList retry_contacts = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + public static TL_contacts_importedContacts TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_contacts_importedContacts.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_contacts_importedContacts", constructor)); + } else { + return null; + } + } + TL_contacts_importedContacts result = new TL_contacts_importedContacts(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_importedContact object = TL_importedContact.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + imported.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + retry_contacts.add(stream.readInt64(exception)); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = imported.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + imported.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = retry_contacts.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(retry_contacts.get(a)); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_disabledFeature extends TLObject { + public static int constructor = 0xae636f24; + + public String feature; + public String description; + + public static TL_disabledFeature TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_disabledFeature.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_disabledFeature", constructor)); + } else { + return null; + } + } + TL_disabledFeature result = new TL_disabledFeature(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + feature = stream.readString(exception); + description = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(feature); + stream.writeString(description); + } + } + + public static class TL_inlineBotSwitchPM extends TLObject { + public static int constructor = 0x3c20629f; + + public String text; + public String start_param; + + public static TL_inlineBotSwitchPM TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_inlineBotSwitchPM.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_inlineBotSwitchPM", constructor)); + } else { + return null; + } + } + TL_inlineBotSwitchPM result = new TL_inlineBotSwitchPM(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + text = stream.readString(exception); + start_param = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(text); + stream.writeString(start_param); + } + } + + public static class Update extends TLObject { + public int chat_id; + public int user_id; + public int inviter_id; + public int date; + public int version; + public int pts; + public int pts_count; + public long query_id; + public byte[] data; + public int flags; + public String query; + public GeoPoint geo; + public String offset; + public PeerNotifySettings notify_settings; + public int channel_id; + public SendMessageAction action; + public boolean blocked; + public long auth_key_id; + public String device; + public String location; + public int max_id; + public int qts; + public boolean enabled; + public long random_id; + public ArrayList dc_options = new ArrayList<>(); + public ChatParticipants participants; + public PrivacyKey key; + public ArrayList rules = new ArrayList<>(); + public UserStatus status; + public int views; + public String type; + public MessageMedia media; + public boolean popup; + public boolean is_admin; + public TL_messages_stickerSet stickerset; + public ContactLink my_link; + public ContactLink foreign_link; + public TL_messageGroup group; + public String first_name; + public String last_name; + public String username; + public ArrayList messages = new ArrayList<>(); + public String phone; + public WebPage webpage; + public EncryptedChat chat; + public ArrayList order = new ArrayList<>(); + public int max_date; + public UserProfilePhoto photo; + public boolean previous; + + public static Update TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + Update result = null; + switch(constructor) { + case 0xea4b0e5c: + result = new TL_updateChatParticipantAdd(); + break; + case 0x43ae3dec: + result = new TL_updateStickerSets(); + break; + case 0x1b3f4df7: + result = new TL_updateEditChannelMessage(); + break; + case 0xa68c688c: + result = new TL_updateBotCallbackQuery(); + break; + case 0x54826690: + result = new TL_updateBotInlineQuery(); + break; + case 0xbec268ef: + result = new TL_updateNotifySettings(); + break; + case 0xb6d45656: + result = new TL_updateChannel(); + break; + case 0x6e5f8c22: + result = new TL_updateChatParticipantDelete(); + break; + case 0x5c486927: + result = new TL_updateUserTyping(); + break; + case 0x80ece81a: + result = new TL_updateUserBlocked(); + break; + case 0x8f06529a: + result = new TL_updateNewAuthorization(); + break; + case 0x2575bbb9: + result = new TL_updateContactRegistered(); + break; + case 0x4214f37f: + result = new TL_updateReadChannelInbox(); + break; + case 0x12bcbd9a: + result = new TL_updateNewEncryptedMessage(); + break; + case 0x6e947941: + result = new TL_updateChatAdmins(); + break; + case 0x9375341e: + result = new TL_updateSavedGifs(); + break; + case 0x62ba04d9: + result = new TL_updateNewChannelMessage(); + break; + case 0x4e90bfd6: + result = new TL_updateMessageID(); + break; + case 0x8e5e9873: + result = new TL_updateDcOptions(); + break; + case 0x7761198: + result = new TL_updateChatParticipants(); + break; + case 0xee3b272a: + result = new TL_updatePrivacy(); + break; + case 0x2cbd95af: + result = new TL_updateInlineBotCallbackQuery(); + break; + case 0x1710f156: + result = new TL_updateEncryptedChatTyping(); + break; + case 0x5a68e3f7: + result = new TL_updateNewGeoChatMessage(); + break; + case 0x1bfbd823: + result = new TL_updateUserStatus(); + break; + case 0x98a12b4b: + result = new TL_updateChannelMessageViews(); + break; + case 0xeb0467fb: + result = new TL_updateChannelTooLong(); + break; + case 0x382dd3e4: + result = new TL_updateServiceNotification(); + break; + case 0xb6901959: + result = new TL_updateChatParticipantAdmin(); + break; + case 0x688a30aa: + result = new TL_updateNewStickerSet(); + break; + case 0x9d2e67c5: + result = new TL_updateContactLink(); + break; + case 0x9961fd5c: + result = new TL_updateReadHistoryInbox(); + break; + case 0xc36c1e3c: + result = new TL_updateChannelGroup(); + break; + case 0xa7332b73: + result = new TL_updateUserName(); + break; + case 0xe48f964: + result = new TL_updateBotInlineSend(); + break; + case 0xe40370a3: + result = new TL_updateEditMessage(); + break; + case 0x98592475: + result = new TL_updateChannelPinnedMessage(); + break; + case 0xc37521c9: + result = new TL_updateDeleteChannelMessages(); + break; + case 0x12b9417b: + result = new TL_updateUserPhone(); + break; + case 0x7f891213: + result = new TL_updateWebPage(); + break; + case 0xb4a2e88d: + result = new TL_updateEncryption(); + break; + case 0x1f2b0afd: + result = new TL_updateNewMessage(); + break; + case 0xf0dfb451: + result = new TL_updateStickerSetsOrder(); + break; + case 0x38fe25b7: + result = new TL_updateEncryptedMessagesRead(); + break; + case 0x68c13933: + result = new TL_updateReadMessagesContents(); + break; + case 0xa20db0e5: + result = new TL_updateDeleteMessages(); + break; + case 0x9a65ea1f: + result = new TL_updateChatUserTyping(); + break; + case 0x95313b0c: + result = new TL_updateUserPhoto(); + break; + case 0x2f2f21bf: + result = new TL_updateReadHistoryOutbox(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in Update", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_updateChatParticipantAdd extends Update { + public static int constructor = 0xea4b0e5c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + user_id = stream.readInt32(exception); + inviter_id = stream.readInt32(exception); + date = stream.readInt32(exception); + version = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeInt32(user_id); + stream.writeInt32(inviter_id); + stream.writeInt32(date); + stream.writeInt32(version); + } + } + + public static class TL_updateStickerSets extends Update { + public static int constructor = 0x43ae3dec; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_updateEditChannelMessage extends Update { + public static int constructor = 0x1b3f4df7; + + public Message message; + + public void readParams(AbstractSerializedData stream, boolean exception) { + message = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + message.serializeToStream(stream); + stream.writeInt32(pts); + stream.writeInt32(pts_count); + } + } + + public static class TL_updateBotCallbackQuery extends Update { + public static int constructor = 0xa68c688c; + + public Peer peer; + public int msg_id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + query_id = stream.readInt64(exception); + user_id = stream.readInt32(exception); + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + msg_id = stream.readInt32(exception); + data = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(query_id); + stream.writeInt32(user_id); + peer.serializeToStream(stream); + stream.writeInt32(msg_id); + stream.writeByteArray(data); + } + } + + public static class TL_updateBotInlineQuery extends Update { + public static int constructor = 0x54826690; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + query_id = stream.readInt64(exception); + user_id = stream.readInt32(exception); + query = stream.readString(exception); + if ((flags & 1) != 0) { + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + } + offset = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt64(query_id); + stream.writeInt32(user_id); + stream.writeString(query); + if ((flags & 1) != 0) { + geo.serializeToStream(stream); + } + stream.writeString(offset); + } + } + + public static class TL_updateNotifySettings extends Update { + public static int constructor = 0xbec268ef; + + public NotifyPeer peer; + + public void readParams(AbstractSerializedData stream, boolean exception) { + peer = NotifyPeer.TLdeserialize(stream, stream.readInt32(exception), exception); + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + notify_settings.serializeToStream(stream); + } + } + + public static class TL_updateChannel extends Update { + public static int constructor = 0xb6d45656; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + channel_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(channel_id); + } + } + + public static class TL_updateChatParticipantDelete extends Update { + public static int constructor = 0x6e5f8c22; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + user_id = stream.readInt32(exception); + version = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeInt32(user_id); + stream.writeInt32(version); + } + } + + public static class TL_updateUserTyping extends Update { + public static int constructor = 0x5c486927; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + action = SendMessageAction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + action.serializeToStream(stream); + } + } + + public static class TL_updateUserBlocked extends Update { + public static int constructor = 0x80ece81a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + blocked = stream.readBool(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeBool(blocked); + } + } + + public static class TL_updateNewAuthorization extends Update { + public static int constructor = 0x8f06529a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + auth_key_id = stream.readInt64(exception); + date = stream.readInt32(exception); + device = stream.readString(exception); + location = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(auth_key_id); + stream.writeInt32(date); + stream.writeString(device); + stream.writeString(location); + } + } + + public static class TL_updateContactRegistered extends Update { + public static int constructor = 0x2575bbb9; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeInt32(date); + } + } + + public static class TL_updateReadChannelInbox extends Update { + public static int constructor = 0x4214f37f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + channel_id = stream.readInt32(exception); + max_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(channel_id); + stream.writeInt32(max_id); + } + } + + public static class TL_updateNewEncryptedMessage extends Update { + public static int constructor = 0x12bcbd9a; + + public EncryptedMessage message; + + public void readParams(AbstractSerializedData stream, boolean exception) { + message = EncryptedMessage.TLdeserialize(stream, stream.readInt32(exception), exception); + qts = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + message.serializeToStream(stream); + stream.writeInt32(qts); + } + } + + public static class TL_updateChatAdmins extends Update { + public static int constructor = 0x6e947941; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + enabled = stream.readBool(exception); + version = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeBool(enabled); + stream.writeInt32(version); + } + } + + public static class TL_updateSavedGifs extends Update { + public static int constructor = 0x9375341e; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_updateNewChannelMessage extends Update { + public static int constructor = 0x62ba04d9; + + public Message message; + + public void readParams(AbstractSerializedData stream, boolean exception) { + message = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + message.serializeToStream(stream); + stream.writeInt32(pts); + stream.writeInt32(pts_count); + } + } + + public static class TL_updateMessageID extends Update { + public static int constructor = 0x4e90bfd6; + + public int id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + random_id = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeInt64(random_id); + } + } + + public static class TL_updateDcOptions extends Update { + public static int constructor = 0x8e5e9873; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_dcOption object = TL_dcOption.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + dc_options.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = dc_options.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + dc_options.get(a).serializeToStream(stream); + } + } + } + + public static class TL_updateChatParticipants extends Update { + public static int constructor = 0x7761198; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + participants = ChatParticipants.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + participants.serializeToStream(stream); + } + } + + public static class TL_updatePrivacy extends Update { + public static int constructor = 0xee3b272a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + key = PrivacyKey.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + PrivacyRule object = PrivacyRule.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + rules.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + key.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = rules.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + rules.get(a).serializeToStream(stream); + } + } + } + + public static class TL_updateInlineBotCallbackQuery extends Update { + public static int constructor = 0x2cbd95af; + + public TL_inputBotInlineMessageID msg_id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + query_id = stream.readInt64(exception); + user_id = stream.readInt32(exception); + msg_id = TL_inputBotInlineMessageID.TLdeserialize(stream, stream.readInt32(exception), exception); + data = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(query_id); + stream.writeInt32(user_id); + msg_id.serializeToStream(stream); + stream.writeByteArray(data); + } + } + + public static class TL_updateEncryptedChatTyping extends Update { + public static int constructor = 0x1710f156; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + } + } + + public static class TL_updateNewGeoChatMessage extends Update { + public static int constructor = 0x5a68e3f7; + + public GeoChatMessage message; + + public void readParams(AbstractSerializedData stream, boolean exception) { + message = GeoChatMessage.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + message.serializeToStream(stream); + } + } + + public static class TL_updateUserStatus extends Update { + public static int constructor = 0x1bfbd823; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + status = UserStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + status.serializeToStream(stream); + } + } + + public static class TL_updateChannelMessageViews extends Update { + public static int constructor = 0x98a12b4b; + + public int id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + channel_id = stream.readInt32(exception); + id = stream.readInt32(exception); + views = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(channel_id); + stream.writeInt32(id); + stream.writeInt32(views); + } + } + + public static class TL_updateChannelTooLong extends Update { + public static int constructor = 0xeb0467fb; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + channel_id = stream.readInt32(exception); + if ((flags & 1) != 0) { + pts = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(channel_id); + if ((flags & 1) != 0) { + stream.writeInt32(pts); + } + } + } + + public static class TL_updateServiceNotification extends Update { + public static int constructor = 0x382dd3e4; + + public String message; + + public void readParams(AbstractSerializedData stream, boolean exception) { + type = stream.readString(exception); + message = stream.readString(exception); + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + popup = stream.readBool(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(type); + stream.writeString(message); + media.serializeToStream(stream); + stream.writeBool(popup); + } + } + + public static class TL_updateChatParticipantAdmin extends Update { + public static int constructor = 0xb6901959; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + user_id = stream.readInt32(exception); + is_admin = stream.readBool(exception); + version = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeInt32(user_id); + stream.writeBool(is_admin); + stream.writeInt32(version); + } + } + + public static class TL_updateNewStickerSet extends Update { + public static int constructor = 0x688a30aa; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + stickerset = TL_messages_stickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stickerset.serializeToStream(stream); + } + } + + public static class TL_updateContactLink extends Update { + public static int constructor = 0x9d2e67c5; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + my_link = ContactLink.TLdeserialize(stream, stream.readInt32(exception), exception); + foreign_link = ContactLink.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + my_link.serializeToStream(stream); + foreign_link.serializeToStream(stream); + } + } + + public static class TL_updateReadHistoryInbox extends Update { + public static int constructor = 0x9961fd5c; + + public Peer peer; + + public void readParams(AbstractSerializedData stream, boolean exception) { + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + max_id = stream.readInt32(exception); + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(max_id); + stream.writeInt32(pts); + stream.writeInt32(pts_count); + } + } + + public static class TL_updateChannelGroup extends Update { + public static int constructor = 0xc36c1e3c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + channel_id = stream.readInt32(exception); + group = TL_messageGroup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(channel_id); + group.serializeToStream(stream); + } + } + + public static class TL_updateUserName extends Update { + public static int constructor = 0xa7332b73; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + username = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeString(username); + } + } + + public static class TL_updateBotInlineSend extends Update { + public static int constructor = 0xe48f964; + + public String id; + public TL_inputBotInlineMessageID msg_id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + user_id = stream.readInt32(exception); + query = stream.readString(exception); + if ((flags & 1) != 0) { + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + } + id = stream.readString(exception); + if ((flags & 2) != 0) { + msg_id = TL_inputBotInlineMessageID.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(user_id); + stream.writeString(query); + if ((flags & 1) != 0) { + geo.serializeToStream(stream); + } + stream.writeString(id); + if ((flags & 2) != 0) { + msg_id.serializeToStream(stream); + } + } + } + + public static class TL_updateEditMessage extends Update { + public static int constructor = 0xe40370a3; + + public Message message; + + public void readParams(AbstractSerializedData stream, boolean exception) { + message = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + message.serializeToStream(stream); + stream.writeInt32(pts); + stream.writeInt32(pts_count); + } + } + + public static class TL_updateChannelPinnedMessage extends Update { + public static int constructor = 0x98592475; + + public int id; + + public void readParams(AbstractSerializedData stream, boolean exception) { + channel_id = stream.readInt32(exception); + id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(channel_id); + stream.writeInt32(id); + } + } + + public static class TL_updateDeleteChannelMessages extends Update { + public static int constructor = 0xc37521c9; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + channel_id = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + messages.add(stream.readInt32(exception)); + } + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(channel_id); + stream.writeInt32(0x1cb5c415); + int count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(messages.get(a)); + } + stream.writeInt32(pts); + stream.writeInt32(pts_count); + } + } + + public static class TL_updateUserPhone extends Update { + public static int constructor = 0x12b9417b; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + phone = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeString(phone); + } + } + + public static class TL_updateWebPage extends Update { + public static int constructor = 0x7f891213; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + webpage = WebPage.TLdeserialize(stream, stream.readInt32(exception), exception); + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + webpage.serializeToStream(stream); + stream.writeInt32(pts); + stream.writeInt32(pts_count); + } + } + + public static class TL_updateEncryption extends Update { + public static int constructor = 0xb4a2e88d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat = EncryptedChat.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + chat.serializeToStream(stream); + stream.writeInt32(date); + } + } + + public static class TL_updateNewMessage extends Update { + public static int constructor = 0x1f2b0afd; + + public Message message; + + public void readParams(AbstractSerializedData stream, boolean exception) { + message = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + message.serializeToStream(stream); + stream.writeInt32(pts); + stream.writeInt32(pts_count); + } + } + + public static class TL_updateStickerSetsOrder extends Update { + public static int constructor = 0xf0dfb451; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + order.add(stream.readInt64(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = order.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(order.get(a)); + } + } + } + + public static class TL_updateEncryptedMessagesRead extends Update { + public static int constructor = 0x38fe25b7; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + max_date = stream.readInt32(exception); + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeInt32(max_date); + stream.writeInt32(date); + } + } + + public static class TL_updateReadMessagesContents extends Update { + public static int constructor = 0x68c13933; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + messages.add(stream.readInt32(exception)); + } + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(messages.get(a)); + } + stream.writeInt32(pts); + stream.writeInt32(pts_count); + } + } + + public static class TL_updateDeleteMessages extends Update { + public static int constructor = 0xa20db0e5; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + messages.add(stream.readInt32(exception)); + } + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(messages.get(a)); + } + stream.writeInt32(pts); + stream.writeInt32(pts_count); + } + } + + public static class TL_updateChatUserTyping extends Update { + public static int constructor = 0x9a65ea1f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + user_id = stream.readInt32(exception); + action = SendMessageAction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeInt32(user_id); + action.serializeToStream(stream); + } + } + + public static class TL_updateUserPhoto extends Update { + public static int constructor = 0x95313b0c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + photo = UserProfilePhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + previous = stream.readBool(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeInt32(date); + photo.serializeToStream(stream); + stream.writeBool(previous); + } + } + + public static class TL_updateReadHistoryOutbox extends Update { + public static int constructor = 0x2f2f21bf; + + public Peer peer; + + public void readParams(AbstractSerializedData stream, boolean exception) { + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + max_id = stream.readInt32(exception); + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(max_id); + stream.writeInt32(pts); + stream.writeInt32(pts_count); + } + } + + public static class TL_receivedNotifyMessage extends TLObject { + public static int constructor = 0xa384b779; + + public int id; + public int flags; + + public static TL_receivedNotifyMessage TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_receivedNotifyMessage.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_receivedNotifyMessage", constructor)); + } else { + return null; + } + } + TL_receivedNotifyMessage result = new TL_receivedNotifyMessage(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + flags = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeInt32(flags); + } + } + + public static class InputEncryptedFile extends TLObject { + public long id; + public long access_hash; + public int parts; + public int key_fingerprint; + public String md5_checksum; + + public static InputEncryptedFile TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputEncryptedFile result = null; + switch(constructor) { + case 0x5a17b5e5: + result = new TL_inputEncryptedFile(); + break; + case 0x2dc173c8: + result = new TL_inputEncryptedFileBigUploaded(); + break; + case 0x1837c364: + result = new TL_inputEncryptedFileEmpty(); + break; + case 0x64bd0306: + result = new TL_inputEncryptedFileUploaded(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputEncryptedFile", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputEncryptedFile extends InputEncryptedFile { + public static int constructor = 0x5a17b5e5; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + } + } + + public static class TL_inputEncryptedFileBigUploaded extends InputEncryptedFile { + public static int constructor = 0x2dc173c8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + parts = stream.readInt32(exception); + key_fingerprint = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt32(parts); + stream.writeInt32(key_fingerprint); + } + } + + public static class TL_inputEncryptedFileEmpty extends InputEncryptedFile { + public static int constructor = 0x1837c364; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputEncryptedFileUploaded extends InputEncryptedFile { + public static int constructor = 0x64bd0306; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + parts = stream.readInt32(exception); + md5_checksum = stream.readString(exception); + key_fingerprint = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt32(parts); + stream.writeString(md5_checksum); + stream.writeInt32(key_fingerprint); + } + } + + public static class messages_AllStickers extends TLObject { + public String hash; + public ArrayList sets = new ArrayList<>(); + public ArrayList packs = new ArrayList<>(); + public ArrayList documents = new ArrayList<>(); + + public static messages_AllStickers TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + messages_AllStickers result = null; + switch(constructor) { + case 0xedfd405f: + result = new TL_messages_allStickers(); + break; + case 0xe86602c3: + result = new TL_messages_allStickersNotModified(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in messages_AllStickers", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messages_allStickers extends messages_AllStickers { + public static int constructor = 0xedfd405f; + + public int hash; + + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + StickerSet object = StickerSet.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + sets.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + stream.writeInt32(0x1cb5c415); + int count = sets.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + sets.get(a).serializeToStream(stream); + } + } + } + + public static class TL_messages_allStickersNotModified extends messages_AllStickers { + public static int constructor = 0xe86602c3; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class DecryptedMessageAction extends TLObject { + public int ttl_seconds; + public int layer; + public ArrayList random_ids = new ArrayList<>(); + public long exchange_id; + public long key_fingerprint; + public SendMessageAction action; + public byte[] g_b; + public int start_seq_no; + public int end_seq_no; + public byte[] g_a; + + public static DecryptedMessageAction TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + DecryptedMessageAction result = null; + switch(constructor) { + case 0xa1733aec: + result = new TL_decryptedMessageActionSetMessageTTL(); + break; + case 0xf3048883: + result = new TL_decryptedMessageActionNotifyLayer(); + break; + case 0x65614304: + result = new TL_decryptedMessageActionDeleteMessages(); + break; + case 0xec2e0b9b: + result = new TL_decryptedMessageActionCommitKey(); + break; + case 0xdd05ec6b: + result = new TL_decryptedMessageActionAbortKey(); + break; + case 0x6719e45c: + result = new TL_decryptedMessageActionFlushHistory(); + break; + case 0xccb27641: + result = new TL_decryptedMessageActionTyping(); + break; + case 0x6fe1735b: + result = new TL_decryptedMessageActionAcceptKey(); + break; + case 0xc4f40be: + result = new TL_decryptedMessageActionReadMessages(); + break; + case 0x511110b0: + result = new TL_decryptedMessageActionResend(); + break; + case 0xf3c9611b: + result = new TL_decryptedMessageActionRequestKey(); + break; + case 0x8ac1f475: + result = new TL_decryptedMessageActionScreenshotMessages(); + break; + case 0xa82fdd63: + result = new TL_decryptedMessageActionNoop(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in DecryptedMessageAction", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_decryptedMessageActionSetMessageTTL extends DecryptedMessageAction { + public static int constructor = 0xa1733aec; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + ttl_seconds = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(ttl_seconds); + } + } + + public static class TL_decryptedMessageActionNotifyLayer extends DecryptedMessageAction { + public static int constructor = 0xf3048883; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + layer = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(layer); + } + } + + public static class TL_decryptedMessageActionDeleteMessages extends DecryptedMessageAction { + public static int constructor = 0x65614304; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + random_ids.add(stream.readInt64(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = random_ids.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(random_ids.get(a)); + } + } + } + + public static class TL_decryptedMessageActionCommitKey extends DecryptedMessageAction { + public static int constructor = 0xec2e0b9b; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + exchange_id = stream.readInt64(exception); + key_fingerprint = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(exchange_id); + stream.writeInt64(key_fingerprint); + } + } + + public static class TL_decryptedMessageActionAbortKey extends DecryptedMessageAction { + public static int constructor = 0xdd05ec6b; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + exchange_id = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(exchange_id); + } + } + + public static class TL_decryptedMessageActionFlushHistory extends DecryptedMessageAction { + public static int constructor = 0x6719e45c; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_decryptedMessageActionTyping extends DecryptedMessageAction { + public static int constructor = 0xccb27641; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + action = SendMessageAction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + action.serializeToStream(stream); + } + } + + public static class TL_decryptedMessageActionAcceptKey extends DecryptedMessageAction { + public static int constructor = 0x6fe1735b; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + exchange_id = stream.readInt64(exception); + g_b = stream.readByteArray(exception); + key_fingerprint = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(exchange_id); + stream.writeByteArray(g_b); + stream.writeInt64(key_fingerprint); + } + } + + public static class TL_decryptedMessageActionReadMessages extends DecryptedMessageAction { + public static int constructor = 0xc4f40be; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + random_ids.add(stream.readInt64(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = random_ids.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(random_ids.get(a)); + } + } + } + + public static class TL_decryptedMessageActionResend extends DecryptedMessageAction { + public static int constructor = 0x511110b0; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + start_seq_no = stream.readInt32(exception); + end_seq_no = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(start_seq_no); + stream.writeInt32(end_seq_no); + } + } + + public static class TL_decryptedMessageActionRequestKey extends DecryptedMessageAction { + public static int constructor = 0xf3c9611b; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + exchange_id = stream.readInt64(exception); + g_a = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(exchange_id); + stream.writeByteArray(g_a); + } + } + + public static class TL_decryptedMessageActionScreenshotMessages extends DecryptedMessageAction { + public static int constructor = 0x8ac1f475; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + random_ids.add(stream.readInt64(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = random_ids.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(random_ids.get(a)); + } + } + } + + public static class TL_decryptedMessageActionNoop extends DecryptedMessageAction { + public static int constructor = 0xa82fdd63; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class account_Password extends TLObject { + public byte[] current_salt; + public byte[] new_salt; + public String hint; + public boolean has_recovery; + public String email_unconfirmed_pattern; + + public static account_Password TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + account_Password result = null; + switch(constructor) { + case 0x7c18141c: + result = new TL_account_password(); + break; + case 0x96dabc18: + result = new TL_account_noPassword(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in account_Password", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_account_password extends account_Password { + public static int constructor = 0x7c18141c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + current_salt = stream.readByteArray(exception); + new_salt = stream.readByteArray(exception); + hint = stream.readString(exception); + has_recovery = stream.readBool(exception); + email_unconfirmed_pattern = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(current_salt); + stream.writeByteArray(new_salt); + stream.writeString(hint); + stream.writeBool(has_recovery); + stream.writeString(email_unconfirmed_pattern); + } + } + + public static class TL_account_noPassword extends account_Password { + public static int constructor = 0x96dabc18; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + new_salt = stream.readByteArray(exception); + email_unconfirmed_pattern = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(new_salt); + stream.writeString(email_unconfirmed_pattern); + } + } + + public static class UserProfilePhoto extends TLObject { + public long photo_id; + public FileLocation photo_small; + public FileLocation photo_big; + + public static UserProfilePhoto TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + UserProfilePhoto result = null; + switch(constructor) { + case 0x4f11bae1: + result = new TL_userProfilePhotoEmpty(); + break; + case 0xd559d8c8: + result = new TL_userProfilePhoto(); + break; + case 0x990d1493: + result = new TL_userProfilePhoto_old(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in UserProfilePhoto", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_userProfilePhotoEmpty extends UserProfilePhoto { + public static int constructor = 0x4f11bae1; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_userProfilePhoto extends UserProfilePhoto { + public static int constructor = 0xd559d8c8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + photo_id = stream.readInt64(exception); + photo_small = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + photo_big = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(photo_id); + photo_small.serializeToStream(stream); + photo_big.serializeToStream(stream); + } + } + + public static class TL_userProfilePhoto_old extends TL_userProfilePhoto { + public static int constructor = 0x990d1493; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + photo_small = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + photo_big = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + photo_small.serializeToStream(stream); + photo_big.serializeToStream(stream); + } + } + + public static class MessageEntity extends TLObject { + public int offset; + public int length; + public String language; + public String url; + + public static MessageEntity TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + MessageEntity result = null; + switch(constructor) { + case 0x6ed02538: + result = new TL_messageEntityUrl(); + break; + case 0xbd610bc9: + result = new TL_messageEntityBold(); + break; + case 0x826f8b60: + result = new TL_messageEntityItalic(); + break; + case 0x64e475c2: + result = new TL_messageEntityEmail(); + break; + case 0x73924be0: + result = new TL_messageEntityPre(); + break; + case 0x76a6d327: + result = new TL_messageEntityTextUrl(); + break; + case 0xbb92ba95: + result = new TL_messageEntityUnknown(); + break; + case 0x6f635b0d: + result = new TL_messageEntityHashtag(); + break; + case 0x6cef8ac7: + result = new TL_messageEntityBotCommand(); + break; + case 0x28a20571: + result = new TL_messageEntityCode(); + break; + case 0xfa04579d: + result = new TL_messageEntityMention(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in MessageEntity", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messageEntityUrl extends MessageEntity { + public static int constructor = 0x6ed02538; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + offset = stream.readInt32(exception); + length = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset); + stream.writeInt32(length); + } + } + + public static class TL_messageEntityBold extends MessageEntity { + public static int constructor = 0xbd610bc9; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + offset = stream.readInt32(exception); + length = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset); + stream.writeInt32(length); + } + } + + public static class TL_messageEntityItalic extends MessageEntity { + public static int constructor = 0x826f8b60; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + offset = stream.readInt32(exception); + length = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset); + stream.writeInt32(length); + } + } + + public static class TL_messageEntityEmail extends MessageEntity { + public static int constructor = 0x64e475c2; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + offset = stream.readInt32(exception); + length = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset); + stream.writeInt32(length); + } + } + + public static class TL_messageEntityPre extends MessageEntity { + public static int constructor = 0x73924be0; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + offset = stream.readInt32(exception); + length = stream.readInt32(exception); + language = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset); + stream.writeInt32(length); + stream.writeString(language); + } + } + + public static class TL_messageEntityTextUrl extends MessageEntity { + public static int constructor = 0x76a6d327; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + offset = stream.readInt32(exception); + length = stream.readInt32(exception); + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset); + stream.writeInt32(length); + stream.writeString(url); + } + } + + public static class TL_messageEntityUnknown extends MessageEntity { + public static int constructor = 0xbb92ba95; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + offset = stream.readInt32(exception); + length = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset); + stream.writeInt32(length); + } + } + + public static class TL_messageEntityHashtag extends MessageEntity { + public static int constructor = 0x6f635b0d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + offset = stream.readInt32(exception); + length = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset); + stream.writeInt32(length); + } + } + + public static class TL_messageEntityBotCommand extends MessageEntity { + public static int constructor = 0x6cef8ac7; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + offset = stream.readInt32(exception); + length = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset); + stream.writeInt32(length); + } + } + + public static class TL_messageEntityCode extends MessageEntity { + public static int constructor = 0x28a20571; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + offset = stream.readInt32(exception); + length = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset); + stream.writeInt32(length); + } + } + + public static class TL_messageEntityMention extends MessageEntity { + public static int constructor = 0xfa04579d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + offset = stream.readInt32(exception); + length = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset); + stream.writeInt32(length); + } + } + + public static class Photo extends TLObject { + public long id; + public long access_hash; + public int user_id; + public int date; + public String caption; + public GeoPoint geo; + public ArrayList sizes = new ArrayList<>(); + + public static Photo TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + Photo result = null; + switch(constructor) { + case 0x22b56751: + result = new TL_photo_old(); + break; + case 0xcded42fe: + result = new TL_photo(); + break; + case 0xc3838076: + result = new TL_photo_old2(); + break; + case 0x2331b22d: + result = new TL_photoEmpty(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in Photo", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_photo_old extends TL_photo { + public static int constructor = 0x22b56751; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + caption = stream.readString(exception); + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + PhotoSize object = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + sizes.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + stream.writeString(caption); + geo.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = sizes.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + sizes.get(a).serializeToStream(stream); + } + } + } + + public static class TL_photo extends Photo { + public static int constructor = 0xcded42fe; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + date = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + PhotoSize object = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + sizes.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(date); + stream.writeInt32(0x1cb5c415); + int count = sizes.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + sizes.get(a).serializeToStream(stream); + } + } + } + + public static class TL_photo_old2 extends TL_photo { + public static int constructor = 0xc3838076; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + PhotoSize object = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + sizes.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(user_id); + stream.writeInt32(date); + geo.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = sizes.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + sizes.get(a).serializeToStream(stream); + } + } + } + + public static class TL_photoEmpty extends Photo { + public static int constructor = 0x2331b22d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + } + } + + public static class TL_encryptedChatRequested_old extends TL_encryptedChatRequested { + public static int constructor = 0xfda9a7b7; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + date = stream.readInt32(exception); + admin_id = stream.readInt32(exception); + participant_id = stream.readInt32(exception); + g_a = stream.readByteArray(exception); + nonce = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeInt64(access_hash); + stream.writeInt32(date); + stream.writeInt32(admin_id); + stream.writeInt32(participant_id); + stream.writeByteArray(g_a); + stream.writeByteArray(nonce); + } + } + + public static class TL_encryptedChatRequested extends EncryptedChat { + public static int constructor = 0xc878527e; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + date = stream.readInt32(exception); + admin_id = stream.readInt32(exception); + participant_id = stream.readInt32(exception); + g_a = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeInt64(access_hash); + stream.writeInt32(date); + stream.writeInt32(admin_id); + stream.writeInt32(participant_id); + stream.writeByteArray(g_a); + } + } + + public static class TL_encryptedChat extends EncryptedChat { + public static int constructor = 0xfa56ce36; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + date = stream.readInt32(exception); + admin_id = stream.readInt32(exception); + participant_id = stream.readInt32(exception); + g_a_or_b = stream.readByteArray(exception); + key_fingerprint = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeInt64(access_hash); + stream.writeInt32(date); + stream.writeInt32(admin_id); + stream.writeInt32(participant_id); + stream.writeByteArray(g_a_or_b); + stream.writeInt64(key_fingerprint); + } + } + + public static class TL_encryptedChat_old extends TL_encryptedChat { + public static int constructor = 0x6601d14f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + date = stream.readInt32(exception); + admin_id = stream.readInt32(exception); + participant_id = stream.readInt32(exception); + g_a_or_b = stream.readByteArray(exception); + nonce = stream.readByteArray(exception); + key_fingerprint = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeInt64(access_hash); + stream.writeInt32(date); + stream.writeInt32(admin_id); + stream.writeInt32(participant_id); + stream.writeByteArray(g_a_or_b); + stream.writeByteArray(nonce); + stream.writeInt64(key_fingerprint); + } + } + + public static class TL_encryptedChatEmpty extends EncryptedChat { + public static int constructor = 0xab7ec0a0; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + } + } + + public static class TL_encryptedChatWaiting extends EncryptedChat { + public static int constructor = 0x3bf703dc; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + date = stream.readInt32(exception); + admin_id = stream.readInt32(exception); + participant_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeInt64(access_hash); + stream.writeInt32(date); + stream.writeInt32(admin_id); + stream.writeInt32(participant_id); + } + } + + public static class TL_encryptedChatDiscarded extends EncryptedChat { + public static int constructor = 0x13d6dd27; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + } + } + + public static class TL_geochats_statedMessage extends TLObject { + public static int constructor = 0x17b1578b; + + public GeoChatMessage message; + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + public int seq; + + public static TL_geochats_statedMessage TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_geochats_statedMessage.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_geochats_statedMessage", constructor)); + } else { + return null; + } + } + TL_geochats_statedMessage result = new TL_geochats_statedMessage(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + message = GeoChatMessage.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + seq = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + message.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + stream.writeInt32(seq); + } + } + + public static class TL_contact extends TLObject { + public static int constructor = 0xf911c994; + + public int user_id; + public boolean mutual; + + public static TL_contact TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_contact.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_contact", constructor)); + } else { + return null; + } + } + TL_contact result = new TL_contact(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + mutual = stream.readBool(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeBool(mutual); + } + } + + public static class TL_config extends TLObject { + public static int constructor = 0x317ceef4; + + public int date; + public int expires; + public boolean test_mode; + public int this_dc; + public ArrayList dc_options = new ArrayList<>(); + public int chat_size_max; + public int megagroup_size_max; + public int forwarded_count_max; + public int online_update_period_ms; + public int offline_blur_timeout_ms; + public int offline_idle_timeout_ms; + public int online_cloud_timeout_ms; + public int notify_cloud_delay_ms; + public int notify_default_delay_ms; + public int chat_big_size; + public int push_chat_period_ms; + public int push_chat_limit; + public int saved_gifs_limit; + public int edit_time_limit; + public ArrayList disabled_features = new ArrayList<>(); + + public static TL_config TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_config.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_config", constructor)); + } else { + return null; + } + } + TL_config result = new TL_config(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + date = stream.readInt32(exception); + expires = stream.readInt32(exception); + test_mode = stream.readBool(exception); + this_dc = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_dcOption object = TL_dcOption.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + dc_options.add(object); + } + chat_size_max = stream.readInt32(exception); + megagroup_size_max = stream.readInt32(exception); + forwarded_count_max = stream.readInt32(exception); + online_update_period_ms = stream.readInt32(exception); + offline_blur_timeout_ms = stream.readInt32(exception); + offline_idle_timeout_ms = stream.readInt32(exception); + online_cloud_timeout_ms = stream.readInt32(exception); + notify_cloud_delay_ms = stream.readInt32(exception); + notify_default_delay_ms = stream.readInt32(exception); + chat_big_size = stream.readInt32(exception); + push_chat_period_ms = stream.readInt32(exception); + push_chat_limit = stream.readInt32(exception); + saved_gifs_limit = stream.readInt32(exception); + edit_time_limit = stream.readInt32(exception); + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_disabledFeature object = TL_disabledFeature.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + disabled_features.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(date); + stream.writeInt32(expires); + stream.writeBool(test_mode); + stream.writeInt32(this_dc); + stream.writeInt32(0x1cb5c415); + int count = dc_options.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + dc_options.get(a).serializeToStream(stream); + } + stream.writeInt32(chat_size_max); + stream.writeInt32(megagroup_size_max); + stream.writeInt32(forwarded_count_max); + stream.writeInt32(online_update_period_ms); + stream.writeInt32(offline_blur_timeout_ms); + stream.writeInt32(offline_idle_timeout_ms); + stream.writeInt32(online_cloud_timeout_ms); + stream.writeInt32(notify_cloud_delay_ms); + stream.writeInt32(notify_default_delay_ms); + stream.writeInt32(chat_big_size); + stream.writeInt32(push_chat_period_ms); + stream.writeInt32(push_chat_limit); + stream.writeInt32(saved_gifs_limit); + stream.writeInt32(edit_time_limit); + stream.writeInt32(0x1cb5c415); + count = disabled_features.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + disabled_features.get(a).serializeToStream(stream); + } + } + } + + public static class TL_help_support extends TLObject { + public static int constructor = 0x17c6b5f6; + + public String phone_number; + public User user; + + public static TL_help_support TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_help_support.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_help_support", constructor)); + } else { + return null; + } + } + TL_help_support result = new TL_help_support(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + phone_number = stream.readString(exception); + user = User.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(phone_number); + user.serializeToStream(stream); + } + } + + public static class TL_messages_chats extends TLObject { + public static int constructor = 0x64ff9fd5; + + public ArrayList chats = new ArrayList<>(); + + public static TL_messages_chats TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_chats.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_chats", constructor)); + } else { + return null; + } + } + TL_messages_chats result = new TL_messages_chats(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + } + } + + public static class InputChannel extends TLObject { + public int channel_id; + public long access_hash; + + public static InputChannel TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputChannel result = null; + switch(constructor) { + case 0xee8c1e86: + result = new TL_inputChannelEmpty(); + break; + case 0xafeb712e: + result = new TL_inputChannel(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputChannel", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputChannelEmpty extends InputChannel { + public static int constructor = 0xee8c1e86; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputChannel extends InputChannel { + public static int constructor = 0xafeb712e; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + channel_id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(channel_id); + stream.writeInt64(access_hash); + } + } + + public static class TL_messageRange extends TLObject { + public static int constructor = 0xae30253; + + public int min_id; + public int max_id; + + public static TL_messageRange TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messageRange.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messageRange", constructor)); + } else { + return null; + } + } + TL_messageRange result = new TL_messageRange(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + min_id = stream.readInt32(exception); + max_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(min_id); + stream.writeInt32(max_id); + } + } + + public static class TL_messageGroup extends TLObject { + public static int constructor = 0xe8346f53; + + public int min_id; + public int max_id; + public int count; + public int date; + + public static TL_messageGroup TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messageGroup.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messageGroup", constructor)); + } else { + return null; + } + } + TL_messageGroup result = new TL_messageGroup(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + min_id = stream.readInt32(exception); + max_id = stream.readInt32(exception); + count = stream.readInt32(exception); + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(min_id); + stream.writeInt32(max_id); + stream.writeInt32(count); + stream.writeInt32(date); + } + } + + public static class TL_messages_botResults extends TLObject { + public static int constructor = 0x256709a6; + + public int flags; + public boolean gallery; + public long query_id; + public String next_offset; + public TL_inlineBotSwitchPM switch_pm; + public ArrayList results = new ArrayList<>(); + + public static TL_messages_botResults TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_botResults.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_botResults", constructor)); + } else { + return null; + } + } + TL_messages_botResults result = new TL_messages_botResults(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + gallery = (flags & 1) != 0; + query_id = stream.readInt64(exception); + if ((flags & 2) != 0) { + next_offset = stream.readString(exception); + } + if ((flags & 4) != 0) { + switch_pm = TL_inlineBotSwitchPM.TLdeserialize(stream, stream.readInt32(exception), exception); + } + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + BotInlineResult object = BotInlineResult.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + results.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = gallery ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt64(query_id); + if ((flags & 2) != 0) { + stream.writeString(next_offset); + } + if ((flags & 4) != 0) { + switch_pm.serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + int count = results.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + results.get(a).serializeToStream(stream); + } + } + } + + public static class TL_inputBotInlineMessageID extends TLObject { + public static int constructor = 0x890c3d89; + + public int dc_id; + public long id; + public long access_hash; + + public static TL_inputBotInlineMessageID TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_inputBotInlineMessageID.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_inputBotInlineMessageID", constructor)); + } else { + return null; + } + } + TL_inputBotInlineMessageID result = new TL_inputBotInlineMessageID(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + dc_id = stream.readInt32(exception); + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(dc_id); + stream.writeInt64(id); + stream.writeInt64(access_hash); + } + } + + public static class TL_messages_foundGifs extends TLObject { + public static int constructor = 0x450a1c0a; + + public int next_offset; + public ArrayList results = new ArrayList<>(); + + public static TL_messages_foundGifs TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_foundGifs.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_foundGifs", constructor)); + } else { + return null; + } + } + TL_messages_foundGifs result = new TL_messages_foundGifs(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + next_offset = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + FoundGif object = FoundGif.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + results.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(next_offset); + stream.writeInt32(0x1cb5c415); + int count = results.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + results.get(a).serializeToStream(stream); + } + } + } + + public static class updates_ChannelDifference extends TLObject { + public int flags; + public boolean isFinal; + public int pts; + public int timeout; + public ArrayList new_messages = new ArrayList<>(); + public ArrayList other_updates = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + public int top_message; + public int top_important_message; + public int read_inbox_max_id; + public int unread_count; + public int unread_important_count; + public ArrayList messages = new ArrayList<>(); + + public static updates_ChannelDifference TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + updates_ChannelDifference result = null; + switch(constructor) { + case 0x3e11affb: + result = new TL_updates_channelDifferenceEmpty(); + break; + case 0x2064674e: + result = new TL_updates_channelDifference(); + break; + case 0x5e167646: + result = new TL_updates_channelDifferenceTooLong(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in updates_ChannelDifference", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_updates_channelDifferenceEmpty extends updates_ChannelDifference { + public static int constructor = 0x3e11affb; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + isFinal = (flags & 1) != 0; + pts = stream.readInt32(exception); + if ((flags & 2) != 0) { + timeout = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = isFinal ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt32(pts); + if ((flags & 2) != 0) { + stream.writeInt32(timeout); + } + } + } + + public static class TL_updates_channelDifference extends updates_ChannelDifference { + public static int constructor = 0x2064674e; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + isFinal = (flags & 1) != 0; + pts = stream.readInt32(exception); + if ((flags & 2) != 0) { + timeout = stream.readInt32(exception); + } + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Message object = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + new_messages.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Update object = Update.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + other_updates.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = isFinal ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt32(pts); + if ((flags & 2) != 0) { + stream.writeInt32(timeout); + } + stream.writeInt32(0x1cb5c415); + int count = new_messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + new_messages.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = other_updates.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + other_updates.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_updates_channelDifferenceTooLong extends updates_ChannelDifference { + public static int constructor = 0x5e167646; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + isFinal = (flags & 1) != 0; + pts = stream.readInt32(exception); + if ((flags & 2) != 0) { + timeout = stream.readInt32(exception); + } + top_message = stream.readInt32(exception); + top_important_message = stream.readInt32(exception); + read_inbox_max_id = stream.readInt32(exception); + unread_count = stream.readInt32(exception); + unread_important_count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Message object = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + messages.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = isFinal ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeInt32(pts); + if ((flags & 2) != 0) { + stream.writeInt32(timeout); + } + stream.writeInt32(top_message); + stream.writeInt32(top_important_message); + stream.writeInt32(read_inbox_max_id); + stream.writeInt32(unread_count); + stream.writeInt32(unread_important_count); + stream.writeInt32(0x1cb5c415); + int count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + messages.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class ChannelMessagesFilter extends TLObject { + public int flags; + public boolean important_only; + public boolean exclude_new_messages; + public ArrayList ranges = new ArrayList<>(); + + public static ChannelMessagesFilter TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + ChannelMessagesFilter result = null; + switch(constructor) { + case 0x94d42ee7: + result = new TL_channelMessagesFilterEmpty(); + break; + case 0xcd77d957: + result = new TL_channelMessagesFilter(); + break; + case 0xfa01232e: + result = new TL_channelMessagesFilterCollapsed(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in ChannelMessagesFilter", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_channelMessagesFilterEmpty extends ChannelMessagesFilter { + public static int constructor = 0x94d42ee7; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_channelMessagesFilter extends ChannelMessagesFilter { + public static int constructor = 0xcd77d957; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + important_only = (flags & 1) != 0; + exclude_new_messages = (flags & 2) != 0; + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_messageRange object = TL_messageRange.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + ranges.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = important_only ? (flags | 1) : (flags &~ 1); + flags = exclude_new_messages ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + stream.writeInt32(0x1cb5c415); + int count = ranges.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + ranges.get(a).serializeToStream(stream); + } + } + } + + public static class TL_channelMessagesFilterCollapsed extends ChannelMessagesFilter { + public static int constructor = 0xfa01232e; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_contacts_resolvedPeer extends TLObject { + public static int constructor = 0x7f077ad9; + + public Peer peer; + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + public static TL_contacts_resolvedPeer TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_contacts_resolvedPeer.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_contacts_resolvedPeer", constructor)); + } else { + return null; + } + } + TL_contacts_resolvedPeer result = new TL_contacts_resolvedPeer(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class ChannelParticipant extends TLObject { + public int user_id; + public int date; + public int inviter_id; + public int kicked_by; + + public static ChannelParticipant TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + ChannelParticipant result = null; + switch(constructor) { + case 0x15ebac1d: + result = new TL_channelParticipant(); + break; + case 0xa3289a6d: + result = new TL_channelParticipantSelf(); + break; + case 0x98192d61: + result = new TL_channelParticipantEditor(); + break; + case 0x8cc5e69a: + result = new TL_channelParticipantKicked(); + break; + case 0x91057fef: + result = new TL_channelParticipantModerator(); + break; + case 0xe3e2e1f9: + result = new TL_channelParticipantCreator(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in ChannelParticipant", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_channelParticipant extends ChannelParticipant { + public static int constructor = 0x15ebac1d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeInt32(date); + } + } + + public static class TL_channelParticipantSelf extends ChannelParticipant { + public static int constructor = 0xa3289a6d; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + inviter_id = stream.readInt32(exception); + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeInt32(inviter_id); + stream.writeInt32(date); + } + } + + public static class TL_channelParticipantEditor extends ChannelParticipant { + public static int constructor = 0x98192d61; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + inviter_id = stream.readInt32(exception); + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeInt32(inviter_id); + stream.writeInt32(date); + } + } + + public static class TL_channelParticipantKicked extends ChannelParticipant { + public static int constructor = 0x8cc5e69a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + kicked_by = stream.readInt32(exception); + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeInt32(kicked_by); + stream.writeInt32(date); + } + } + + public static class TL_channelParticipantModerator extends ChannelParticipant { + public static int constructor = 0x91057fef; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + inviter_id = stream.readInt32(exception); + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeInt32(inviter_id); + stream.writeInt32(date); + } + } + + public static class TL_channelParticipantCreator extends ChannelParticipant { + public static int constructor = 0xe3e2e1f9; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + } + } + + public static class TL_channels_channelParticipants extends TLObject { + public static int constructor = 0xf56ee2a8; + + public int count; + public ArrayList participants = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + public static TL_channels_channelParticipants TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_channels_channelParticipants.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_channels_channelParticipants", constructor)); + } else { + return null; + } + } + TL_channels_channelParticipants result = new TL_channels_channelParticipants(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + ChannelParticipant object = ChannelParticipant.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + participants.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(count); + stream.writeInt32(0x1cb5c415); + int count = participants.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + participants.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_contacts_found extends TLObject { + public static int constructor = 0x1aa1f784; + + public ArrayList results = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + public static TL_contacts_found TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_contacts_found.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_contacts_found", constructor)); + } else { + return null; + } + } + TL_contacts_found result = new TL_contacts_found(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Peer object = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + results.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = results.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + results.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class ChatParticipants extends TLObject { + public int flags; + public int chat_id; + public ChatParticipant self_participant; + public ArrayList participants = new ArrayList<>(); + public int version; + public int admin_id; + + public static ChatParticipants TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + ChatParticipants result = null; + switch(constructor) { + case 0xfc900c2b: + result = new TL_chatParticipantsForbidden(); + break; + case 0x3f460fed: + result = new TL_chatParticipants(); + break; + case 0x7841b415: + result = new TL_chatParticipants_old(); + break; + case 0xfd2bb8a: + result = new TL_chatParticipantsForbidden_old(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in ChatParticipants", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_chatParticipantsForbidden extends ChatParticipants { + public static int constructor = 0xfc900c2b; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + chat_id = stream.readInt32(exception); + if ((flags & 1) != 0) { + self_participant = ChatParticipant.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + stream.writeInt32(chat_id); + if ((flags & 1) != 0) { + self_participant.serializeToStream(stream); + } + } + } + + public static class TL_chatParticipants extends ChatParticipants { + public static int constructor = 0x3f460fed; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + ChatParticipant object = ChatParticipant.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + participants.add(object); + } + version = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeInt32(0x1cb5c415); + int count = participants.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + participants.get(a).serializeToStream(stream); + } + stream.writeInt32(version); + } + } + + public static class TL_chatParticipants_old extends TL_chatParticipants { + public static int constructor = 0x7841b415; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + admin_id = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + ChatParticipant object = ChatParticipant.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + participants.add(object); + } + version = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeInt32(admin_id); + stream.writeInt32(0x1cb5c415); + int count = participants.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + participants.get(a).serializeToStream(stream); + } + stream.writeInt32(version); + } + } + + public static class TL_chatParticipantsForbidden_old extends TL_chatParticipantsForbidden { + public static int constructor = 0xfd2bb8a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + } + } + + public static class DecryptedMessageMedia extends TLObject { + public int duration; + public String mime_type; + public int size; + public byte[] key; + public byte[] iv; + public double lat; + public double _long; + public String phone_number; + public String first_name; + public String last_name; + public int user_id; + public int thumb_w; + public int thumb_h; + public ArrayList attributes = new ArrayList<>(); + public String caption; + public String url; + public int w; + public int h; + public String file_name; + public String title; + public String address; + public String provider; + public String venue_id; + public long id; + public long access_hash; + public int date; + public int dc_id; + + public static DecryptedMessageMedia TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + DecryptedMessageMedia result = null; + switch(constructor) { + case 0x57e0a9cb: + result = new TL_decryptedMessageMediaAudio(); + break; + case 0x35480a59: + result = new TL_decryptedMessageMediaGeoPoint(); + break; + case 0x588a0a97: + result = new TL_decryptedMessageMediaContact(); + break; + case 0x89f5c4a: + result = new TL_decryptedMessageMediaEmpty(); + break; + case 0x7afe8ae2: + result = new TL_decryptedMessageMediaDocument(); + break; + case 0xe50511d8: + result = new TL_decryptedMessageMediaWebPage(); + break; + case 0xf1fa8d78: + result = new TL_decryptedMessageMediaPhoto(); + break; + case 0x970c8c0e: + result = new TL_decryptedMessageMediaVideo(); + break; + case 0xb095434b: + result = new TL_decryptedMessageMediaDocument_layer8(); + break; + case 0x4cee6ef3: + result = new TL_decryptedMessageMediaVideo_layer8(); + break; + case 0x8a0df56f: + result = new TL_decryptedMessageMediaVenue(); + break; + case 0xfa95b0dd: + result = new TL_decryptedMessageMediaExternalDocument(); + break; + case 0x524a415d: + result = new TL_decryptedMessageMediaVideo_layer17(); + break; + case 0x6080758f: + result = new TL_decryptedMessageMediaAudio_layer8(); + break; + case 0x32798a8c: + result = new TL_decryptedMessageMediaPhoto_layer8(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in DecryptedMessageMedia", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_decryptedMessageMediaAudio extends DecryptedMessageMedia { + public static int constructor = 0x57e0a9cb; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + duration = stream.readInt32(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(duration); + stream.writeString(mime_type); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_decryptedMessageMediaGeoPoint extends DecryptedMessageMedia { + public static int constructor = 0x35480a59; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + lat = stream.readDouble(exception); + _long = stream.readDouble(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeDouble(lat); + stream.writeDouble(_long); + } + } + + public static class TL_decryptedMessageMediaContact extends DecryptedMessageMedia { + public static int constructor = 0x588a0a97; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + phone_number = stream.readString(exception); + first_name = stream.readString(exception); + last_name = stream.readString(exception); + user_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(phone_number); + stream.writeString(first_name); + stream.writeString(last_name); + stream.writeInt32(user_id); + } + } + + public static class TL_decryptedMessageMediaEmpty extends DecryptedMessageMedia { + public static int constructor = 0x89f5c4a; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_decryptedMessageMediaDocument extends DecryptedMessageMedia { + public static int constructor = 0x7afe8ae2; + + public byte[] thumb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + thumb = stream.readByteArray(exception); + thumb_w = stream.readInt32(exception); + thumb_h = stream.readInt32(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + DocumentAttribute object = DocumentAttribute.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + attributes.add(object); + } + caption = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(thumb); + stream.writeInt32(thumb_w); + stream.writeInt32(thumb_h); + stream.writeString(mime_type); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + stream.writeInt32(0x1cb5c415); + int count = attributes.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + attributes.get(a).serializeToStream(stream); + } + stream.writeString(caption); + } + } + + public static class TL_decryptedMessageMediaWebPage extends DecryptedMessageMedia { + public static int constructor = 0xe50511d8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + url = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(url); + } + } + + public static class TL_decryptedMessageMediaPhoto extends DecryptedMessageMedia { + public static int constructor = 0xf1fa8d78; + + public byte[] thumb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + thumb = stream.readByteArray(exception); + thumb_w = stream.readInt32(exception); + thumb_h = stream.readInt32(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + caption = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(thumb); + stream.writeInt32(thumb_w); + stream.writeInt32(thumb_h); + stream.writeInt32(w); + stream.writeInt32(h); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + stream.writeString(caption); + } + } + + public static class TL_decryptedMessageMediaVideo extends DecryptedMessageMedia { + public static int constructor = 0x970c8c0e; + + public byte[] thumb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + thumb = stream.readByteArray(exception); + thumb_w = stream.readInt32(exception); + thumb_h = stream.readInt32(exception); + duration = stream.readInt32(exception); + mime_type = stream.readString(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + caption = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(thumb); + stream.writeInt32(thumb_w); + stream.writeInt32(thumb_h); + stream.writeInt32(duration); + stream.writeString(mime_type); + stream.writeInt32(w); + stream.writeInt32(h); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + stream.writeString(caption); + } + } + + public static class TL_decryptedMessageMediaDocument_layer8 extends TL_decryptedMessageMediaDocument { + public static int constructor = 0xb095434b; + + public byte[] thumb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + thumb = stream.readByteArray(exception); + thumb_w = stream.readInt32(exception); + thumb_h = stream.readInt32(exception); + file_name = stream.readString(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(thumb); + stream.writeInt32(thumb_w); + stream.writeInt32(thumb_h); + stream.writeString(file_name); + stream.writeString(mime_type); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_decryptedMessageMediaVideo_layer8 extends TL_decryptedMessageMediaVideo { + public static int constructor = 0x4cee6ef3; + + public byte[] thumb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + thumb = stream.readByteArray(exception); + thumb_w = stream.readInt32(exception); + thumb_h = stream.readInt32(exception); + duration = stream.readInt32(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(thumb); + stream.writeInt32(thumb_w); + stream.writeInt32(thumb_h); + stream.writeInt32(duration); + stream.writeInt32(w); + stream.writeInt32(h); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_decryptedMessageMediaVenue extends DecryptedMessageMedia { + public static int constructor = 0x8a0df56f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + lat = stream.readDouble(exception); + _long = stream.readDouble(exception); + title = stream.readString(exception); + address = stream.readString(exception); + provider = stream.readString(exception); + venue_id = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeDouble(lat); + stream.writeDouble(_long); + stream.writeString(title); + stream.writeString(address); + stream.writeString(provider); + stream.writeString(venue_id); + } + } + + public static class TL_decryptedMessageMediaExternalDocument extends DecryptedMessageMedia { + public static int constructor = 0xfa95b0dd; + + public PhotoSize thumb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + date = stream.readInt32(exception); + mime_type = stream.readString(exception); + size = stream.readInt32(exception); + thumb = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + dc_id = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + DocumentAttribute object = DocumentAttribute.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + attributes.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeInt32(date); + stream.writeString(mime_type); + stream.writeInt32(size); + thumb.serializeToStream(stream); + stream.writeInt32(dc_id); + stream.writeInt32(0x1cb5c415); + int count = attributes.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + attributes.get(a).serializeToStream(stream); + } + } + } + + public static class TL_decryptedMessageMediaVideo_layer17 extends TL_decryptedMessageMediaVideo { + public static int constructor = 0x524a415d; + + public byte[] thumb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + thumb = stream.readByteArray(exception); + thumb_w = stream.readInt32(exception); + thumb_h = stream.readInt32(exception); + duration = stream.readInt32(exception); + mime_type = stream.readString(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(thumb); + stream.writeInt32(thumb_w); + stream.writeInt32(thumb_h); + stream.writeInt32(duration); + stream.writeString(mime_type); + stream.writeInt32(w); + stream.writeInt32(h); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_decryptedMessageMediaAudio_layer8 extends TL_decryptedMessageMediaAudio { + public static int constructor = 0x6080758f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + duration = stream.readInt32(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(duration); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_decryptedMessageMediaPhoto_layer8 extends TL_decryptedMessageMediaPhoto { + public static int constructor = 0x32798a8c; + + public byte[] thumb; + + public void readParams(AbstractSerializedData stream, boolean exception) { + thumb = stream.readByteArray(exception); + thumb_w = stream.readInt32(exception); + thumb_h = stream.readInt32(exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + size = stream.readInt32(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(thumb); + stream.writeInt32(thumb_w); + stream.writeInt32(thumb_h); + stream.writeInt32(w); + stream.writeInt32(h); + stream.writeInt32(size); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class ChatParticipant extends TLObject { + public int user_id; + public int inviter_id; + public int date; + + public static ChatParticipant TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + ChatParticipant result = null; + switch(constructor) { + case 0xc8d7493e: + result = new TL_chatParticipant(); + break; + case 0xda13538a: + result = new TL_chatParticipantCreator(); + break; + case 0xe2d6e436: + result = new TL_chatParticipantAdmin(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in ChatParticipant", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_chatParticipant extends ChatParticipant { + public static int constructor = 0xc8d7493e; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + inviter_id = stream.readInt32(exception); + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeInt32(inviter_id); + stream.writeInt32(date); + } + } + + public static class TL_chatParticipantCreator extends ChatParticipant { + public static int constructor = 0xda13538a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + } + } + + public static class TL_chatParticipantAdmin extends ChatParticipant { + public static int constructor = 0xe2d6e436; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + inviter_id = stream.readInt32(exception); + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeInt32(inviter_id); + stream.writeInt32(date); + } + } + + public static class Chat extends TLObject { + public int flags; + public boolean creator; + public boolean kicked; + public boolean admins_enabled; + public boolean admin; + public boolean deactivated; + public int id; + public String title; + public ChatPhoto photo; + public int participants_count; + public int date; + public int version; + public boolean editor; + public boolean moderator; + public boolean broadcast; + public boolean verified; + public boolean megagroup; + public boolean explicit_content; + public boolean left; + public long access_hash; + public String username; + public boolean restricted; + public boolean democracy; + public boolean signatures; + public String restriction_reason; + public boolean min; + public InputChannel migrated_to; + public String address; + public String venue; + public GeoPoint geo; + public boolean checked_in; + + public static Chat TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + Chat result = null; + switch(constructor) { + case 0x7312bc48: + result = new TL_chat_old2(); + break; + case 0x7328bdb: + result = new TL_chatForbidden(); + break; + case 0x678e9587: + result = new TL_channel_old(); + break; + case 0xfb0ccc41: + result = new TL_chatForbidden_old(); + break; + case 0xd91cdd54: + result = new TL_chat(); + break; + case 0x9ba2d800: + result = new TL_chatEmpty(); + break; + case 0x4b1b7506: + result = new TL_channel_layer48(); + break; + case 0x75eaea5a: + result = new TL_geoChat(); + break; + case 0x2d85832c: + result = new TL_channelForbidden(); + break; + case 0xa14dca52: + result = new TL_channel(); + break; + case 0x6e9c9bc7: + result = new TL_chat_old(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in Chat", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_chat_old2 extends TL_chat { + public static int constructor = 0x7312bc48; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + creator = (flags & 1) != 0; + kicked = (flags & 2) != 0; + left = (flags & 4) != 0; + admins_enabled = (flags & 8) != 0; + admin = (flags & 16) != 0; + deactivated = (flags & 32) != 0; + id = stream.readInt32(exception); + title = stream.readString(exception); + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + participants_count = stream.readInt32(exception); + date = stream.readInt32(exception); + version = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator ? (flags | 1) : (flags &~ 1); + flags = kicked ? (flags | 2) : (flags &~ 2); + flags = left ? (flags | 4) : (flags &~ 4); + flags = admins_enabled ? (flags | 8) : (flags &~ 8); + flags = admin ? (flags | 16) : (flags &~ 16); + flags = deactivated ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeString(title); + photo.serializeToStream(stream); + stream.writeInt32(participants_count); + stream.writeInt32(date); + stream.writeInt32(version); + } + } + + public static class TL_chatForbidden extends Chat { + public static int constructor = 0x7328bdb; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + title = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(title); + } + } + + public static class TL_channel extends Chat { + public static int constructor = 0xa14dca52; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + creator = (flags & 1) != 0; + kicked = (flags & 2) != 0; + left = (flags & 4) != 0; + editor = (flags & 8) != 0; + moderator = (flags & 16) != 0; + broadcast = (flags & 32) != 0; + verified = (flags & 128) != 0; + megagroup = (flags & 256) != 0; + restricted = (flags & 512) != 0; + democracy = (flags & 1024) != 0; + signatures = (flags & 2048) != 0; + min = (flags & 4096) != 0; + id = stream.readInt32(exception); + if ((flags & 8192) != 0) { + access_hash = stream.readInt64(exception); + } + title = stream.readString(exception); + if ((flags & 64) != 0) { + username = stream.readString(exception); + } + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + version = stream.readInt32(exception); + if ((flags & 512) != 0) { + restriction_reason = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator ? (flags | 1) : (flags &~ 1); + flags = kicked ? (flags | 2) : (flags &~ 2); + flags = left ? (flags | 4) : (flags &~ 4); + flags = editor ? (flags | 8) : (flags &~ 8); + flags = moderator ? (flags | 16) : (flags &~ 16); + flags = broadcast ? (flags | 32) : (flags &~ 32); + flags = verified ? (flags | 128) : (flags &~ 128); + flags = megagroup ? (flags | 256) : (flags &~ 256); + flags = restricted ? (flags | 512) : (flags &~ 512); + flags = democracy ? (flags | 1024) : (flags &~ 1024); + flags = signatures ? (flags | 2048) : (flags &~ 2048); + flags = min ? (flags | 4096) : (flags &~ 4096); + stream.writeInt32(flags); + stream.writeInt32(id); + if ((flags & 8192) != 0) { + stream.writeInt64(access_hash); + } + stream.writeString(title); + if ((flags & 64) != 0) { + stream.writeString(username); + } + photo.serializeToStream(stream); + stream.writeInt32(date); + stream.writeInt32(version); + if ((flags & 512) != 0) { + stream.writeString(restriction_reason); + } + } + } + + public static class TL_channel_old extends TL_channel { + public static int constructor = 0x678e9587; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + creator = (flags & 1) != 0; + kicked = (flags & 2) != 0; + left = (flags & 4) != 0; + editor = (flags & 8) != 0; + moderator = (flags & 16) != 0; + broadcast = (flags & 32) != 0; + verified = (flags & 128) != 0; + megagroup = (flags & 256) != 0; + explicit_content = (flags & 512) != 0; + id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + title = stream.readString(exception); + if ((flags & 64) != 0) { + username = stream.readString(exception); + } + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + version = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator ? (flags | 1) : (flags &~ 1); + flags = kicked ? (flags | 2) : (flags &~ 2); + flags = left ? (flags | 4) : (flags &~ 4); + flags = editor ? (flags | 8) : (flags &~ 8); + flags = moderator ? (flags | 16) : (flags &~ 16); + flags = broadcast ? (flags | 32) : (flags &~ 32); + flags = verified ? (flags | 128) : (flags &~ 128); + flags = megagroup ? (flags | 256) : (flags &~ 256); + flags = explicit_content ? (flags | 512) : (flags &~ 512); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt64(access_hash); + stream.writeString(title); + if ((flags & 64) != 0) { + stream.writeString(username); + } + photo.serializeToStream(stream); + stream.writeInt32(date); + stream.writeInt32(version); + } + } + + public static class TL_chatForbidden_old extends TL_chatForbidden { + public static int constructor = 0xfb0ccc41; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + title = stream.readString(exception); + date = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(title); + stream.writeInt32(date); + } + } + + public static class TL_chat extends Chat { + public static int constructor = 0xd91cdd54; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + creator = (flags & 1) != 0; + kicked = (flags & 2) != 0; + left = (flags & 4) != 0; + admins_enabled = (flags & 8) != 0; + admin = (flags & 16) != 0; + deactivated = (flags & 32) != 0; + id = stream.readInt32(exception); + title = stream.readString(exception); + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + participants_count = stream.readInt32(exception); + date = stream.readInt32(exception); + version = stream.readInt32(exception); + if ((flags & 64) != 0) { + migrated_to = InputChannel.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator ? (flags | 1) : (flags &~ 1); + flags = kicked ? (flags | 2) : (flags &~ 2); + flags = left ? (flags | 4) : (flags &~ 4); + flags = admins_enabled ? (flags | 8) : (flags &~ 8); + flags = admin ? (flags | 16) : (flags &~ 16); + flags = deactivated ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeString(title); + photo.serializeToStream(stream); + stream.writeInt32(participants_count); + stream.writeInt32(date); + stream.writeInt32(version); + if ((flags & 64) != 0) { + migrated_to.serializeToStream(stream); + } + } + } + + public static class TL_geoChat extends Chat { + public static int constructor = 0x75eaea5a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + title = stream.readString(exception); + address = stream.readString(exception); + venue = stream.readString(exception); + geo = GeoPoint.TLdeserialize(stream, stream.readInt32(exception), exception); + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + participants_count = stream.readInt32(exception); + date = stream.readInt32(exception); + checked_in = stream.readBool(exception); + version = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeInt64(access_hash); + stream.writeString(title); + stream.writeString(address); + stream.writeString(venue); + geo.serializeToStream(stream); + photo.serializeToStream(stream); + stream.writeInt32(participants_count); + stream.writeInt32(date); + stream.writeBool(checked_in); + stream.writeInt32(version); + } + } + + public static class TL_channelForbidden extends Chat { + public static int constructor = 0x2d85832c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + title = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeInt64(access_hash); + stream.writeString(title); + } + } + + public static class TL_chat_old extends TL_chat { + public static int constructor = 0x6e9c9bc7; + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + title = stream.readString(exception); + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + participants_count = stream.readInt32(exception); + date = stream.readInt32(exception); + left = stream.readBool(exception); + version = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(title); + photo.serializeToStream(stream); + stream.writeInt32(participants_count); + stream.writeInt32(date); + stream.writeBool(left); + stream.writeInt32(version); + } + } + + public static class TL_channel_layer48 extends TL_channel { + public static int constructor = 0x4b1b7506; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + creator = (flags & 1) != 0; + kicked = (flags & 2) != 0; + left = (flags & 4) != 0; + editor = (flags & 8) != 0; + moderator = (flags & 16) != 0; + broadcast = (flags & 32) != 0; + verified = (flags & 128) != 0; + megagroup = (flags & 256) != 0; + restricted = (flags & 512) != 0; + democracy = (flags & 1024) != 0; + signatures = (flags & 2048) != 0; + id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + title = stream.readString(exception); + if ((flags & 64) != 0) { + username = stream.readString(exception); + } + photo = ChatPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + version = stream.readInt32(exception); + if ((flags & 512) != 0) { + restriction_reason = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = creator ? (flags | 1) : (flags &~ 1); + flags = kicked ? (flags | 2) : (flags &~ 2); + flags = left ? (flags | 4) : (flags &~ 4); + flags = editor ? (flags | 8) : (flags &~ 8); + flags = moderator ? (flags | 16) : (flags &~ 16); + flags = broadcast ? (flags | 32) : (flags &~ 32); + flags = verified ? (flags | 128) : (flags &~ 128); + flags = megagroup ? (flags | 256) : (flags &~ 256); + flags = restricted ? (flags | 512) : (flags &~ 512); + flags = democracy ? (flags | 1024) : (flags &~ 1024); + flags = signatures ? (flags | 2048) : (flags &~ 2048); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt64(access_hash); + stream.writeString(title); + if ((flags & 64) != 0) { + stream.writeString(username); + } + photo.serializeToStream(stream); + stream.writeInt32(date); + stream.writeInt32(version); + if ((flags & 512) != 0) { + stream.writeString(restriction_reason); + } + } + } + + public static class StickerSet extends TLObject { + public long id; + public long access_hash; + public String title; + public String short_name; + public int flags; + public boolean installed; + public boolean disabled; + public boolean official; + public int count; + public int hash; + + public static StickerSet TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + StickerSet result = null; + switch(constructor) { + case 0xa7a43b17: + result = new TL_stickerSet_old(); + break; + case 0xcd303b41: + result = new TL_stickerSet(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in StickerSet", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_stickerSet_old extends TL_stickerSet { + public static int constructor = 0xa7a43b17; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + title = stream.readString(exception); + short_name = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeString(title); + stream.writeString(short_name); + } + } + + public static class TL_stickerSet extends StickerSet { + public static int constructor = 0xcd303b41; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + installed = (flags & 1) != 0; + disabled = (flags & 2) != 0; + official = (flags & 4) != 0; + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + title = stream.readString(exception); + short_name = stream.readString(exception); + count = stream.readInt32(exception); + hash = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = installed ? (flags | 1) : (flags &~ 1); + flags = disabled ? (flags | 2) : (flags &~ 2); + flags = official ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + stream.writeInt64(id); + stream.writeInt64(access_hash); + stream.writeString(title); + stream.writeString(short_name); + stream.writeInt32(count); + stream.writeInt32(hash); + } + } + + public static class storage_FileType extends TLObject { + + public static storage_FileType TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + storage_FileType result = null; + switch(constructor) { + case 0xaa963b05: + result = new TL_storage_fileUnknown(); + break; + case 0xb3cea0e4: + result = new TL_storage_fileMp4(); + break; + case 0x1081464c: + result = new TL_storage_fileWebp(); + break; + case 0xa4f63c0: + result = new TL_storage_filePng(); + break; + case 0xcae1aadf: + result = new TL_storage_fileGif(); + break; + case 0xae1e508d: + result = new TL_storage_filePdf(); + break; + case 0x528a0677: + result = new TL_storage_fileMp3(); + break; + case 0x7efe0e: + result = new TL_storage_fileJpeg(); + break; + case 0x4b09ebbc: + result = new TL_storage_fileMov(); + break; + case 0x40bc6f52: + result = new TL_storage_filePartial(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in storage_FileType", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_storage_fileUnknown extends storage_FileType { + public static int constructor = 0xaa963b05; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_storage_fileMp4 extends storage_FileType { + public static int constructor = 0xb3cea0e4; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_storage_fileWebp extends storage_FileType { + public static int constructor = 0x1081464c; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_storage_filePng extends storage_FileType { + public static int constructor = 0xa4f63c0; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_storage_fileGif extends storage_FileType { + public static int constructor = 0xcae1aadf; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_storage_filePdf extends storage_FileType { + public static int constructor = 0xae1e508d; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_storage_fileMp3 extends storage_FileType { + public static int constructor = 0x528a0677; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_storage_fileJpeg extends storage_FileType { + public static int constructor = 0x7efe0e; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_storage_fileMov extends storage_FileType { + public static int constructor = 0x4b09ebbc; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_storage_filePartial extends storage_FileType { + public static int constructor = 0x40bc6f52; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class auth_CodeType extends TLObject { + + public static auth_CodeType TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + auth_CodeType result = null; + switch(constructor) { + case 0x72a3158c: + result = new TL_auth_codeTypeSms(); + break; + case 0x741cd3e3: + result = new TL_auth_codeTypeCall(); + break; + case 0x226ccefb: + result = new TL_auth_codeTypeFlashCall(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in auth_CodeType", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_auth_codeTypeSms extends auth_CodeType { + public static int constructor = 0x72a3158c; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_auth_codeTypeCall extends auth_CodeType { + public static int constructor = 0x741cd3e3; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_auth_codeTypeFlashCall extends auth_CodeType { + public static int constructor = 0x226ccefb; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class MessagesFilter extends TLObject { + + public static MessagesFilter TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + MessagesFilter result = null; + switch(constructor) { + case 0x9eddf188: + result = new TL_inputMessagesFilterDocument(); + break; + case 0x3751b49e: + result = new TL_inputMessagesFilterMusic(); + break; + case 0x9fc00e65: + result = new TL_inputMessagesFilterVideo(); + break; + case 0x9609a51c: + result = new TL_inputMessagesFilterPhotos(); + break; + case 0xd95e73bb: + result = new TL_inputMessagesFilterPhotoVideoDocuments(); + break; + case 0x7ef0dd87: + result = new TL_inputMessagesFilterUrl(); + break; + case 0xffc86587: + result = new TL_inputMessagesFilterGif(); + break; + case 0x50f5c392: + result = new TL_inputMessagesFilterVoice(); + break; + case 0x57e2f66c: + result = new TL_inputMessagesFilterEmpty(); + break; + case 0x56e9f0e4: + result = new TL_inputMessagesFilterPhotoVideo(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in MessagesFilter", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputMessagesFilterDocument extends MessagesFilter { + public static int constructor = 0x9eddf188; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputMessagesFilterMusic extends MessagesFilter { + public static int constructor = 0x3751b49e; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputMessagesFilterVideo extends MessagesFilter { + public static int constructor = 0x9fc00e65; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputMessagesFilterPhotos extends MessagesFilter { + public static int constructor = 0x9609a51c; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputMessagesFilterPhotoVideoDocuments extends MessagesFilter { + public static int constructor = 0xd95e73bb; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputMessagesFilterUrl extends MessagesFilter { + public static int constructor = 0x7ef0dd87; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputMessagesFilterGif extends MessagesFilter { + public static int constructor = 0xffc86587; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputMessagesFilterVoice extends MessagesFilter { + public static int constructor = 0x50f5c392; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputMessagesFilterEmpty extends MessagesFilter { + public static int constructor = 0x57e2f66c; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputMessagesFilterPhotoVideo extends MessagesFilter { + public static int constructor = 0x56e9f0e4; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_geochats_located extends TLObject { + public static int constructor = 0x48feb267; + + public ArrayList results = new ArrayList<>(); + public ArrayList messages = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + + public static TL_geochats_located TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_geochats_located.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_geochats_located", constructor)); + } else { + return null; + } + } + TL_geochats_located result = new TL_geochats_located(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_chatLocated object = TL_chatLocated.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + results.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + GeoChatMessage object = GeoChatMessage.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + messages.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = results.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + results.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + messages.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_messages_messageEmpty extends TLObject { + public static int constructor = 0x3f4e0648; + + + public static TL_messages_messageEmpty TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messages_messageEmpty.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messages_messageEmpty", constructor)); + } else { + return null; + } + } + TL_messages_messageEmpty result = new TL_messages_messageEmpty(); + result.readParams(stream, exception); + return result; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messageFwdHeader extends TLObject { + public static int constructor = 0xc786ddcb; + + public int flags; + public int from_id; + public int date; + public int channel_id; + public int channel_post; + + public static TL_messageFwdHeader TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_messageFwdHeader.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_messageFwdHeader", constructor)); + } else { + return null; + } + } + TL_messageFwdHeader result = new TL_messageFwdHeader(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + from_id = stream.readInt32(exception); + } + date = stream.readInt32(exception); + if ((flags & 2) != 0) { + channel_id = stream.readInt32(exception); + } + if ((flags & 4) != 0) { + channel_post = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeInt32(from_id); + } + stream.writeInt32(date); + if ((flags & 2) != 0) { + stream.writeInt32(channel_id); + } + if ((flags & 4) != 0) { + stream.writeInt32(channel_post); + } + } + } + + public static class FileLocation extends TLObject { + public int dc_id; + public long volume_id; + public int local_id; + public long secret; + public byte[] key; + public byte[] iv; + + public static FileLocation TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + FileLocation result = null; + switch (constructor) { + case 0x53d69076: + result = new TL_fileLocation(); + break; + case 0x55555554: + result = new TL_fileEncryptedLocation(); + break; + case 0x7c596b46: + result = new TL_fileLocationUnavailable(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in FileLocation", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_fileLocation extends FileLocation { + public static int constructor = 0x53d69076; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + dc_id = stream.readInt32(exception); + volume_id = stream.readInt64(exception); + local_id = stream.readInt32(exception); + secret = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(dc_id); + stream.writeInt64(volume_id); + stream.writeInt32(local_id); + stream.writeInt64(secret); + } + } + + public static class TL_fileEncryptedLocation extends FileLocation { + public static int constructor = 0x55555554; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + dc_id = stream.readInt32(exception); + volume_id = stream.readInt64(exception); + local_id = stream.readInt32(exception); + secret = stream.readInt64(exception); + key = stream.readByteArray(exception); + iv = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(dc_id); + stream.writeInt64(volume_id); + stream.writeInt32(local_id); + stream.writeInt64(secret); + stream.writeByteArray(key); + stream.writeByteArray(iv); + } + } + + public static class TL_fileLocationUnavailable extends FileLocation { + public static int constructor = 0x7c596b46; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + volume_id = stream.readInt64(exception); + local_id = stream.readInt32(exception); + secret = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(volume_id); + stream.writeInt32(local_id); + stream.writeInt64(secret); + } + } + + public static class TL_inputGeoChat extends TLObject { + public static int constructor = 0x74d456fa; + + public int chat_id; + public long access_hash; + + public static TL_inputGeoChat TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_inputGeoChat.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_inputGeoChat", constructor)); + } else { + return null; + } + } + TL_inputGeoChat result = new TL_inputGeoChat(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeInt64(access_hash); + } + } + + public static class messages_SavedGifs extends TLObject { + public int hash; + public ArrayList gifs = new ArrayList<>(); + + public static messages_SavedGifs TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + messages_SavedGifs result = null; + switch(constructor) { + case 0xe8025ca2: + result = new TL_messages_savedGifsNotModified(); + break; + case 0x2e0709a5: + result = new TL_messages_savedGifs(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in messages_SavedGifs", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messages_savedGifsNotModified extends messages_SavedGifs { + public static int constructor = 0xe8025ca2; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messages_savedGifs extends messages_SavedGifs { + public static int constructor = 0x2e0709a5; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Document object = Document.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + gifs.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + stream.writeInt32(0x1cb5c415); + int count = gifs.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + gifs.get(a).serializeToStream(stream); + } + } + } + + public static class PhotoSize extends TLObject { + public String type; + public FileLocation location; + public int w; + public int h; + public int size; + public byte[] bytes; + + public static PhotoSize TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + PhotoSize result = null; + switch(constructor) { + case 0x77bfb61b: + result = new TL_photoSize(); + break; + case 0xe17e23c: + result = new TL_photoSizeEmpty(); + break; + case 0xe9a734fa: + result = new TL_photoCachedSize(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in PhotoSize", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_photoSize extends PhotoSize { + public static int constructor = 0x77bfb61b; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + type = stream.readString(exception); + location = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + size = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(type); + location.serializeToStream(stream); + stream.writeInt32(w); + stream.writeInt32(h); + stream.writeInt32(size); + } + } + + public static class TL_photoSizeEmpty extends PhotoSize { + public static int constructor = 0xe17e23c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int startReadPosiition = stream.getPosition(); //TODO remove this hack after some time + try { + type = stream.readString(true); + if (type.length() > 1 || !type.equals("") && !type.equals("s") && !type.equals("x") && !type.equals("m") && !type.equals("y") && !type.equals("w")) { + type = "s"; + if (stream instanceof NativeByteBuffer) { + ((NativeByteBuffer) stream).position(startReadPosiition); + } + } + } catch (Exception e) { + type = "s"; + if (stream instanceof NativeByteBuffer) { + ((NativeByteBuffer) stream).position(startReadPosiition); + } + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(type); + } + } + + public static class TL_photoCachedSize extends PhotoSize { + public static int constructor = 0xe9a734fa; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + type = stream.readString(exception); + location = FileLocation.TLdeserialize(stream, stream.readInt32(exception), exception); + w = stream.readInt32(exception); + h = stream.readInt32(exception); + bytes = stream.readByteArray(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(type); + location.serializeToStream(stream); + stream.writeInt32(w); + stream.writeInt32(h); + stream.writeByteArray(bytes); + } + } + + public static class TL_contactFound extends TLObject { + public static int constructor = 0xea879f95; + + public int user_id; + + public static TL_contactFound TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_contactFound.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_contactFound", constructor)); + } else { + return null; + } + } + TL_contactFound result = new TL_contactFound(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + } + } + + public static class ExportedChatInvite extends TLObject { + public String link; + + public static ExportedChatInvite TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + ExportedChatInvite result = null; + switch(constructor) { + case 0xfc2e05bc: + result = new TL_chatInviteExported(); + break; + case 0x69df3769: + result = new TL_chatInviteEmpty(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in ExportedChatInvite", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_chatInviteExported extends ExportedChatInvite { + public static int constructor = 0xfc2e05bc; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + link = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(link); + } + } + + public static class TL_chatInviteEmpty extends ExportedChatInvite { + public static int constructor = 0x69df3769; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class InputFile extends TLObject { + public long id; + public int parts; + public String name; + public String md5_checksum; + + public static InputFile TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputFile result = null; + switch(constructor) { + case 0xfa4f0bb5: + result = new TL_inputFileBig(); + break; + case 0xf52ff27f: + result = new TL_inputFile(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputFile", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputFileBig extends InputFile { + public static int constructor = 0xfa4f0bb5; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + parts = stream.readInt32(exception); + name = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt32(parts); + stream.writeString(name); + } + } + + public static class TL_inputFile extends InputFile { + public static int constructor = 0xf52ff27f; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + parts = stream.readInt32(exception); + name = stream.readString(exception); + md5_checksum = stream.readString(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt32(parts); + stream.writeString(name); + stream.writeString(md5_checksum); + } + } + + public static class TL_updates_state extends TLObject { + public static int constructor = 0xa56c2a3e; + + public int pts; + public int qts; + public int date; + public int seq; + public int unread_count; + + public static TL_updates_state TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_updates_state.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_updates_state", constructor)); + } else { + return null; + } + } + TL_updates_state result = new TL_updates_state(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + pts = stream.readInt32(exception); + qts = stream.readInt32(exception); + date = stream.readInt32(exception); + seq = stream.readInt32(exception); + unread_count = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(pts); + stream.writeInt32(qts); + stream.writeInt32(date); + stream.writeInt32(seq); + stream.writeInt32(unread_count); + } + } + + public static class TL_userFull extends TLObject { + public static int constructor = 0x5932fc03; + + public int flags; + public boolean blocked; + public User user; + public String about; + public TL_contacts_link link; + public Photo profile_photo; + public PeerNotifySettings notify_settings; + public BotInfo bot_info; + + public static TL_userFull TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_userFull.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_userFull", constructor)); + } else { + return null; + } + } + TL_userFull result = new TL_userFull(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + blocked = (flags & 1) != 0; + user = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 2) != 0) { + about = stream.readString(exception); + } + link = TL_contacts_link.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 4) != 0) { + profile_photo = Photo.TLdeserialize(stream, stream.readInt32(exception), exception); + } + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 8) != 0) { + bot_info = BotInfo.TLdeserialize(stream, stream.readInt32(exception), exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = blocked ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + user.serializeToStream(stream); + if ((flags & 2) != 0) { + stream.writeString(about); + } + link.serializeToStream(stream); + if ((flags & 4) != 0) { + profile_photo.serializeToStream(stream); + } + notify_settings.serializeToStream(stream); + if ((flags & 8) != 0) { + bot_info.serializeToStream(stream); + } + } + } + + public static class Updates extends TLObject { + public ArrayList updates = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); + public int date; + public int seq; + public int flags; + public boolean unread; + public boolean out; + public boolean mentioned; + public boolean media_unread; + public boolean silent; + public int id; + public int user_id; + public String message; + public int pts; + public int pts_count; + public TL_messageFwdHeader fwd_from; + public int via_bot_id; + public int reply_to_msg_id; + public ArrayList entities = new ArrayList<>(); + public MessageMedia media; + public Update update; + public int from_id; + public int chat_id; + public int seq_start; + + public static Updates TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + Updates result = null; + switch(constructor) { + case 0x74ae4240: + result = new TL_updates(); + break; + case 0x914fbf11: + result = new TL_updateShortMessage(); + break; + case 0x11f1331c: + result = new TL_updateShortSentMessage(); + break; + case 0x78d4dec1: + result = new TL_updateShort(); + break; + case 0x16812688: + result = new TL_updateShortChatMessage(); + break; + case 0x725b04c3: + result = new TL_updatesCombined(); + break; + case 0xe317af7e: + result = new TL_updatesTooLong(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in Updates", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_updates extends Updates { + public static int constructor = 0x74ae4240; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Update object = Update.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + updates.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + date = stream.readInt32(exception); + seq = stream.readInt32(exception); + } + } + + public static class TL_updateShortMessage extends Updates { + public static int constructor = 0x914fbf11; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + silent = (flags & 8192) != 0; + id = stream.readInt32(exception); + user_id = stream.readInt32(exception); + message = stream.readString(exception); + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + date = stream.readInt32(exception); + if ((flags & 4) != 0) { + fwd_from = TL_messageFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 2048) != 0) { + via_bot_id = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + reply_to_msg_id = stream.readInt32(exception); + } + if ((flags & 128) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + } + } + + public static class TL_updateShortSentMessage extends Updates { + public static int constructor = 0x11f1331c; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + id = stream.readInt32(exception); + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + date = stream.readInt32(exception); + if ((flags & 512) != 0) { + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 128) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + } + } + + public static class TL_updateShort extends Updates { + public static int constructor = 0x78d4dec1; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + update = Update.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + } + } + + public static class TL_updateShortChatMessage extends Updates { + public static int constructor = 0x16812688; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + silent = (flags & 8192) != 0; + id = stream.readInt32(exception); + from_id = stream.readInt32(exception); + chat_id = stream.readInt32(exception); + message = stream.readString(exception); + pts = stream.readInt32(exception); + pts_count = stream.readInt32(exception); + date = stream.readInt32(exception); + if ((flags & 4) != 0) { + fwd_from = TL_messageFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 2048) != 0) { + via_bot_id = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + reply_to_msg_id = stream.readInt32(exception); + } + if ((flags & 128) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + } + } + + public static class TL_updatesCombined extends Updates { + public static int constructor = 0x725b04c3; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Update object = Update.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + updates.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + date = stream.readInt32(exception); + seq_start = stream.readInt32(exception); + seq = stream.readInt32(exception); + } + } + + public static class TL_updatesTooLong extends Updates { + public static int constructor = 0xe317af7e; + } + + public static class WallPaper extends TLObject { + public int id; + public String title; + public ArrayList sizes = new ArrayList<>(); + public int color; + public int bg_color; + + public static WallPaper TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + WallPaper result = null; + switch(constructor) { + case 0xccb03657: + result = new TL_wallPaper(); + break; + case 0x63117f24: + result = new TL_wallPaperSolid(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in WallPaper", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_wallPaper extends WallPaper { + public static int constructor = 0xccb03657; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + title = stream.readString(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + PhotoSize object = PhotoSize.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + sizes.add(object); + } + color = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(title); + stream.writeInt32(0x1cb5c415); + int count = sizes.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + sizes.get(a).serializeToStream(stream); + } + stream.writeInt32(color); + } + } + + public static class TL_wallPaperSolid extends WallPaper { + public static int constructor = 0x63117f24; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + title = stream.readString(exception); + bg_color = stream.readInt32(exception); + color = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeString(title); + stream.writeInt32(bg_color); + stream.writeInt32(color); + } + } + + public static class TL_stickerPack extends TLObject { + public static int constructor = 0x12b299d4; + + public String emoticon; + public ArrayList documents = new ArrayList<>(); + + public static TL_stickerPack TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_stickerPack.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_stickerPack", constructor)); + } else { + return null; + } + } + TL_stickerPack result = new TL_stickerPack(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + emoticon = stream.readString(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + documents.add(stream.readInt64(exception)); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(emoticon); + stream.writeInt32(0x1cb5c415); + int count = documents.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(documents.get(a)); + } + } + } + + public static class TL_inputEncryptedChat extends TLObject { + public static int constructor = 0xf141b5e1; + + public int chat_id; + public long access_hash; + + public static TL_inputEncryptedChat TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_inputEncryptedChat.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_inputEncryptedChat", constructor)); + } else { + return null; + } + } + TL_inputEncryptedChat result = new TL_inputEncryptedChat(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeInt64(access_hash); + } + } + + public static class InputChatPhoto extends TLObject { + public InputPhoto id; + public InputPhotoCrop crop; + public InputFile file; + + public static InputChatPhoto TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputChatPhoto result = null; + switch(constructor) { + case 0xb2e1bf08: + result = new TL_inputChatPhoto(); + break; + case 0x1ca48f57: + result = new TL_inputChatPhotoEmpty(); + break; + case 0x94254732: + result = new TL_inputChatUploadedPhoto(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputChatPhoto", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputChatPhoto extends InputChatPhoto { + public static int constructor = 0xb2e1bf08; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = InputPhoto.TLdeserialize(stream, stream.readInt32(exception), exception); + crop = InputPhotoCrop.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + id.serializeToStream(stream); + crop.serializeToStream(stream); + } + } + + public static class TL_inputChatPhotoEmpty extends InputChatPhoto { + public static int constructor = 0x1ca48f57; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputChatUploadedPhoto extends InputChatPhoto { + public static int constructor = 0x94254732; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + file = InputFile.TLdeserialize(stream, stream.readInt32(exception), exception); + crop = InputPhotoCrop.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + file.serializeToStream(stream); + crop.serializeToStream(stream); + } + } + + public static class TL_nearestDc extends TLObject { + public static int constructor = 0x8e1a1775; + + public String country; + public int this_dc; + public int nearest_dc; + + public static TL_nearestDc TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_nearestDc.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_nearestDc", constructor)); + } else { + return null; + } + } + TL_nearestDc result = new TL_nearestDc(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + country = stream.readString(exception); + this_dc = stream.readInt32(exception); + nearest_dc = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(country); + stream.writeInt32(this_dc); + stream.writeInt32(nearest_dc); + } + } + + public static class InputPhoto extends TLObject { + public long id; + public long access_hash; + + public static InputPhoto TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputPhoto result = null; + switch(constructor) { + case 0x1cd7bf0d: + result = new TL_inputPhotoEmpty(); + break; + case 0xfb95c6c4: + result = new TL_inputPhoto(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputPhoto", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputPhotoEmpty extends InputPhoto { + public static int constructor = 0x1cd7bf0d; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputPhoto extends InputPhoto { + public static int constructor = 0xfb95c6c4; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt64(exception); + access_hash = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(id); + stream.writeInt64(access_hash); + } + } + + public static class TL_importedContact extends TLObject { + public static int constructor = 0xd0028438; + + public int user_id; + public long client_id; + + public static TL_importedContact TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_importedContact.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_importedContact", constructor)); + } else { + return null; + } + } + TL_importedContact result = new TL_importedContact(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + client_id = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeInt64(client_id); + } + } + + public static class TL_accountDaysTTL extends TLObject { + public static int constructor = 0xb8d0afdf; + + public int days; + + public static TL_accountDaysTTL TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_accountDaysTTL.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_accountDaysTTL", constructor)); + } else { + return null; + } + } + TL_accountDaysTTL result = new TL_accountDaysTTL(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + days = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(days); + } + } + + public static class messages_Stickers extends TLObject { + public String hash; + public ArrayList stickers = new ArrayList<>(); + + public static messages_Stickers TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + messages_Stickers result = null; + switch(constructor) { + case 0xf1749a22: + result = new TL_messages_stickersNotModified(); + break; + case 0x8a8ecd32: + result = new TL_messages_stickers(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in messages_Stickers", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messages_stickersNotModified extends messages_Stickers { + public static int constructor = 0xf1749a22; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messages_stickers extends messages_Stickers { + public static int constructor = 0x8a8ecd32; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + hash = stream.readString(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Document object = Document.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + stickers.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(hash); + stream.writeInt32(0x1cb5c415); + int count = stickers.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stickers.get(a).serializeToStream(stream); + } + } + } + + public static class InputPeer extends TLObject { + public int user_id; + public long access_hash; + public int chat_id; + public int channel_id; + + public static InputPeer TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputPeer result = null; + switch(constructor) { + case 0x7b8e7de6: + result = new TL_inputPeerUser(); + break; + case 0x179be863: + result = new TL_inputPeerChat(); + break; + case 0x7f3b18ea: + result = new TL_inputPeerEmpty(); + break; + case 0x7da07ec9: + result = new TL_inputPeerSelf(); + break; + case 0x20adaef8: + result = new TL_inputPeerChannel(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputPeer", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputPeerUser extends InputPeer { + public static int constructor = 0x7b8e7de6; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + user_id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(user_id); + stream.writeInt64(access_hash); + } + } + + public static class TL_inputPeerChat extends InputPeer { + public static int constructor = 0x179be863; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + chat_id = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + } + } + + public static class TL_inputPeerEmpty extends InputPeer { + public static int constructor = 0x7f3b18ea; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputPeerSelf extends InputPeer { + public static int constructor = 0x7da07ec9; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputPeerChannel extends InputPeer { + public static int constructor = 0x20adaef8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + channel_id = stream.readInt32(exception); + access_hash = stream.readInt64(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(channel_id); + stream.writeInt64(access_hash); + } + } + + public static class TL_account_passwordInputSettings extends TLObject { + public static int constructor = 0x86916deb; + + public int flags; + public byte[] new_salt; + public byte[] new_password_hash; + public String hint; + public String email; + + public static TL_account_passwordInputSettings TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_account_passwordInputSettings.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_account_passwordInputSettings", constructor)); + } else { + return null; + } + } + TL_account_passwordInputSettings result = new TL_account_passwordInputSettings(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + if ((flags & 1) != 0) { + new_salt = stream.readByteArray(exception); + } + if ((flags & 1) != 0) { + new_password_hash = stream.readByteArray(exception); + } + if ((flags & 1) != 0) { + hint = stream.readString(exception); + } + if ((flags & 2) != 0) { + email = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeByteArray(new_salt); + } + if ((flags & 1) != 0) { + stream.writeByteArray(new_password_hash); + } + if ((flags & 1) != 0) { + stream.writeString(hint); + } + if ((flags & 2) != 0) { + stream.writeString(email); + } + } + } + + public static class TL_dcOption extends TLObject { + public static int constructor = 0x5d8c6cc; + + public int flags; + public boolean ipv6; + public boolean media_only; + public boolean tcpo_only; + public int id; + public String ip_address; + public int port; + + public static TL_dcOption TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_dcOption.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_dcOption", constructor)); + } else { + return null; + } + } + TL_dcOption result = new TL_dcOption(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + ipv6 = (flags & 1) != 0; + media_only = (flags & 2) != 0; + tcpo_only = (flags & 4) != 0; + id = stream.readInt32(exception); + ip_address = stream.readString(exception); + port = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = ipv6 ? (flags | 1) : (flags &~ 1); + flags = media_only ? (flags | 2) : (flags &~ 2); + flags = tcpo_only ? (flags | 4) : (flags &~ 4); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeString(ip_address); + stream.writeInt32(port); + } + } + + public static class TL_decryptedMessageLayer extends TLObject { + public static int constructor = 0x1be31789; + + public byte[] random_bytes; + public int layer; + public int in_seq_no; + public int out_seq_no; + public DecryptedMessage message; + + public static TL_decryptedMessageLayer TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_decryptedMessageLayer.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_decryptedMessageLayer", constructor)); + } else { + return null; + } + } + TL_decryptedMessageLayer result = new TL_decryptedMessageLayer(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + random_bytes = stream.readByteArray(exception); + layer = stream.readInt32(exception); + in_seq_no = stream.readInt32(exception); + out_seq_no = stream.readInt32(exception); + message = DecryptedMessage.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(random_bytes); + stream.writeInt32(layer); + stream.writeInt32(in_seq_no); + stream.writeInt32(out_seq_no); + message.serializeToStream(stream); + } + } + + public static class InputPhotoCrop extends TLObject { + public double crop_left; + public double crop_top; + public double crop_width; + + public static InputPhotoCrop TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + InputPhotoCrop result = null; + switch(constructor) { + case 0xade6b004: + result = new TL_inputPhotoCropAuto(); + break; + case 0xd9915325: + result = new TL_inputPhotoCrop(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in InputPhotoCrop", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_inputPhotoCropAuto extends InputPhotoCrop { + public static int constructor = 0xade6b004; + + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_inputPhotoCrop extends InputPhotoCrop { + public static int constructor = 0xd9915325; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + crop_left = stream.readDouble(exception); + crop_top = stream.readDouble(exception); + crop_width = stream.readDouble(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeDouble(crop_left); + stream.writeDouble(crop_top); + stream.writeDouble(crop_width); + } + } + + public static class messages_Dialogs extends TLObject { + public ArrayList dialogs = new ArrayList<>(); + public ArrayList messages = new ArrayList<>(); + public ArrayList chats = new ArrayList<>(); + public ArrayList users = new ArrayList<>(); + public int count; + + public static messages_Dialogs TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + messages_Dialogs result = null; + switch(constructor) { + case 0x15ba6c40: + result = new TL_messages_dialogs(); + break; + case 0x71e094f3: + result = new TL_messages_dialogsSlice(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in messages_Dialogs", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messages_dialogs extends messages_Dialogs { + public static int constructor = 0x15ba6c40; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Dialog object = Dialog.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + dialogs.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Message object = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + messages.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = dialogs.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + dialogs.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + messages.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_messages_dialogsSlice extends messages_Dialogs { + public static int constructor = 0x71e094f3; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + count = stream.readInt32(exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Dialog object = Dialog.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + dialogs.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Message object = Message.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + messages.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + Chat object = Chat.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + chats.add(object); + } + magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + users.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(count); + stream.writeInt32(0x1cb5c415); + int count = dialogs.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + dialogs.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = messages.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + messages.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = chats.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + chats.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_account_authorizations extends TLObject { + public static int constructor = 0x1250abde; + + public ArrayList authorizations = new ArrayList<>(); + + public static TL_account_authorizations TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_account_authorizations.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_account_authorizations", constructor)); + } else { + return null; + } + } + TL_account_authorizations result = new TL_account_authorizations(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + TL_authorization object = TL_authorization.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + authorizations.add(object); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = authorizations.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + authorizations.get(a).serializeToStream(stream); + } + } + } + + public static class TL_auth_checkPhone extends TLObject { + public static int constructor = 0x6fe51dfb; + + public String phone_number; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_auth_checkedPhone.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(phone_number); + } + } + + public static class TL_auth_sendCode extends TLObject { + public static int constructor = 0xccfd70cf; + + public int flags; + public boolean allow_flashcall; + public String phone_number; + public boolean current_number; + public int api_id; + public String api_hash; + public String lang_code; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_auth_sentCode.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = allow_flashcall ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeString(phone_number); + if ((flags & 1) != 0) { + stream.writeBool(current_number); + } + stream.writeInt32(api_id); + stream.writeString(api_hash); + stream.writeString(lang_code); + } + } + + public static class TL_auth_signUp extends TLObject { + public static int constructor = 0x1b067634; + + public String phone_number; + public String phone_code_hash; + public String phone_code; + public String first_name; + public String last_name; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_auth_authorization.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(phone_number); + stream.writeString(phone_code_hash); + stream.writeString(phone_code); + stream.writeString(first_name); + stream.writeString(last_name); + } + } + + public static class TL_auth_signIn extends TLObject { + public static int constructor = 0xbcd51581; + + public String phone_number; + public String phone_code_hash; + public String phone_code; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_auth_authorization.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(phone_number); + stream.writeString(phone_code_hash); + stream.writeString(phone_code); + } + } + + public static class TL_auth_logOut extends TLObject { + public static int constructor = 0x5717da40; + + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_auth_resetAuthorizations extends TLObject { + public static int constructor = 0x9fab0d1a; + + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_auth_sendInvites extends TLObject { + public static int constructor = 0x771c1d97; + + public ArrayList phone_numbers = new ArrayList<>(); + public String message; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = phone_numbers.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeString(phone_numbers.get(a)); + } + stream.writeString(message); + } + } + + public static class TL_auth_exportAuthorization extends TLObject { + public static int constructor = 0xe5bfffcd; + + public int dc_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_auth_exportedAuthorization.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(dc_id); + } + } + + public static class TL_auth_importAuthorization extends TLObject { + public static int constructor = 0xe3ef9613; + + public int id; + public byte[] bytes; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_auth_authorization.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeByteArray(bytes); + } + } + + public static class TL_auth_bindTempAuthKey extends TLObject { + public static int constructor = 0xcdd42a05; + + public long perm_auth_key_id; + public long nonce; + public int expires_at; + public byte[] encrypted_message; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(perm_auth_key_id); + stream.writeInt64(nonce); + stream.writeInt32(expires_at); + stream.writeByteArray(encrypted_message); + } + } + + public static class TL_account_registerDevice extends TLObject { + public static int constructor = 0x446c712c; + + public int token_type; + public String token; + public String device_model; + public String system_version; + public String app_version; + public boolean app_sandbox; + public String lang_code; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(token_type); + stream.writeString(token); + stream.writeString(device_model); + stream.writeString(system_version); + stream.writeString(app_version); + stream.writeBool(app_sandbox); + stream.writeString(lang_code); + } + } + + public static class TL_account_unregisterDevice extends TLObject { + public static int constructor = 0x65c55b40; + + public int token_type; + public String token; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(token_type); + stream.writeString(token); + } + } + + public static class TL_account_updateNotifySettings extends TLObject { + public static int constructor = 0x84be5b93; + + public InputNotifyPeer peer; + public TL_inputPeerNotifySettings settings; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + settings.serializeToStream(stream); + } + } + + public static class TL_account_getNotifySettings extends TLObject { + public static int constructor = 0x12b3ad31; + + public InputNotifyPeer peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return PeerNotifySettings.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + } + } + + public static class TL_account_resetNotifySettings extends TLObject { + public static int constructor = 0xdb7e1747; + + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_account_updateProfile extends TLObject { + public static int constructor = 0x78515775; + + public int flags; + public String first_name; + public String last_name; + public String about; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return User.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + if ((flags & 1) != 0) { + stream.writeString(first_name); + } + if ((flags & 2) != 0) { + stream.writeString(last_name); + } + if ((flags & 4) != 0) { + stream.writeString(about); + } + } + } + + public static class TL_account_updateStatus extends TLObject { + public static int constructor = 0x6628562c; + + public boolean offline; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeBool(offline); + } + } + + public static class TL_account_getWallPapers extends TLObject { + public static int constructor = 0xc04cfac2; + + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + Vector vector = new Vector(); + int size = stream.readInt32(exception); + for (int a = 0; a < size; a++) { + WallPaper object = WallPaper.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return vector; + } + vector.objects.add(object); + } + return vector; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_users_getUsers extends TLObject { + public static int constructor = 0xd91a548; + + public ArrayList id = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + Vector vector = new Vector(); + int size = stream.readInt32(exception); + for (int a = 0; a < size; a++) { + User object = User.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return vector; + } + vector.objects.add(object); + } + return vector; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + id.get(a).serializeToStream(stream); + } + } + } + + public static class TL_account_reportPeer extends TLObject { + public static int constructor = 0xae189d5f; + + public InputPeer peer; + public ReportReason reason; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + reason.serializeToStream(stream); + } + } + + public static class TL_users_getFullUser extends TLObject { + public static int constructor = 0xca30a5b1; + + public InputUser id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_userFull.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + id.serializeToStream(stream); + } + } + + public static class TL_contacts_getStatuses extends TLObject { + public static int constructor = 0xc4a353ee; + + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + Vector vector = new Vector(); + int size = stream.readInt32(exception); + for (int a = 0; a < size; a++) { + TL_contactStatus object = TL_contactStatus.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return vector; + } + vector.objects.add(object); + } + return vector; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_contacts_getContacts extends TLObject { + public static int constructor = 0x22c6aa08; + + public String hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return contacts_Contacts.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(hash); + } + } + + public static class TL_contacts_importContacts extends TLObject { + public static int constructor = 0xda30b32d; + + public ArrayList contacts = new ArrayList<>(); + public boolean replace; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_contacts_importedContacts.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = contacts.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + contacts.get(a).serializeToStream(stream); + } + stream.writeBool(replace); + } + } + + public static class TL_contacts_deleteContact extends TLObject { + public static int constructor = 0x8e953744; + + public InputUser id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_contacts_link.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + id.serializeToStream(stream); + } + } + + public static class TL_contacts_deleteContacts extends TLObject { + public static int constructor = 0x59ab389e; + + public ArrayList id = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + id.get(a).serializeToStream(stream); + } + } + } + + public static class TL_contacts_block extends TLObject { + public static int constructor = 0x332b49fc; + + public InputUser id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + id.serializeToStream(stream); + } + } + + public static class TL_contacts_unblock extends TLObject { + public static int constructor = 0xe54100bd; + + public InputUser id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + id.serializeToStream(stream); + } + } + + public static class TL_contacts_getBlocked extends TLObject { + public static int constructor = 0xf57c350f; + + public int offset; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return contacts_Blocked.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset); + stream.writeInt32(limit); + } + } + + public static class TL_contacts_exportCard extends TLObject { + public static int constructor = 0x84e53737; + + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + Vector vector = new Vector(); + int size = stream.readInt32(exception); + for (int a = 0; a < size; a++) { + vector.objects.add(stream.readInt32(exception)); + } + return vector; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_contacts_importCard extends TLObject { + public static int constructor = 0x4fe196fe; + + public ArrayList export_card = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return User.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = export_card.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(export_card.get(a)); + } + } + } + + public static class TL_messages_getMessages extends TLObject { + public static int constructor = 0x4222fa74; + + public ArrayList id = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Messages.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(id.get(a)); + } + } + } + + public static class TL_messages_getDialogs extends TLObject { + public static int constructor = 0x6b47f94d; + + public int offset_date; + public int offset_id; + public InputPeer offset_peer; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Dialogs.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset_date); + stream.writeInt32(offset_id); + offset_peer.serializeToStream(stream); + stream.writeInt32(limit); + } + } + + public static class TL_messages_getHistory extends TLObject { + public static int constructor = 0xafa92846; + + public InputPeer peer; + public int offset_id; + public int offset_date; + public int add_offset; + public int limit; + public int max_id; + public int min_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Messages.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(offset_id); + stream.writeInt32(offset_date); + stream.writeInt32(add_offset); + stream.writeInt32(limit); + stream.writeInt32(max_id); + stream.writeInt32(min_id); + } + } + + public static class TL_messages_search extends TLObject { + public static int constructor = 0xd4569248; + + public int flags; + public boolean important_only; + public InputPeer peer; + public String q; + public MessagesFilter filter; + public int min_date; + public int max_date; + public int offset; + public int max_id; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Messages.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = important_only ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + peer.serializeToStream(stream); + stream.writeString(q); + filter.serializeToStream(stream); + stream.writeInt32(min_date); + stream.writeInt32(max_date); + stream.writeInt32(offset); + stream.writeInt32(max_id); + stream.writeInt32(limit); + } + } + + public static class TL_messages_readHistory extends TLObject { + public static int constructor = 0xe306d3a; + + public InputPeer peer; + public int max_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_affectedMessages.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(max_id); + } + } + + public static class TL_messages_deleteHistory extends TLObject { + public static int constructor = 0xb7c13bd9; + + public InputPeer peer; + public int max_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_affectedHistory.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(max_id); + } + } + + public static class TL_messages_toggleChatAdmins extends TLObject { + public static int constructor = 0xec8bd9e1; + + public int chat_id; + public boolean enabled; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeBool(enabled); + } + } + + public static class TL_messages_editChatAdmin extends TLObject { + public static int constructor = 0xa9e69f2e; + + public int chat_id; + public InputUser user_id; + public boolean is_admin; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + user_id.serializeToStream(stream); + stream.writeBool(is_admin); + } + } + + public static class TL_messages_migrateChat extends TLObject { + public static int constructor = 0x15a3b8e3; + + public int chat_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + } + } + + public static class TL_messages_searchGlobal extends TLObject { + public static int constructor = 0x9e3cacb0; + + public String q; + public int offset_date; + public InputPeer offset_peer; + public int offset_id; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Messages.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(q); + stream.writeInt32(offset_date); + offset_peer.serializeToStream(stream); + stream.writeInt32(offset_id); + stream.writeInt32(limit); + } + } + + public static class TL_messages_deleteMessages extends TLObject { + public static int constructor = 0xa5f18925; + + public ArrayList id = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_affectedMessages.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(id.get(a)); + } + } + } + + public static class TL_messages_receivedMessages extends TLObject { + public static int constructor = 0x5a954c0; + + public int max_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + Vector vector = new Vector(); + int size = stream.readInt32(exception); + for (int a = 0; a < size; a++) { + TL_receivedNotifyMessage object = TL_receivedNotifyMessage.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return vector; + } + vector.objects.add(object); + } + return vector; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(max_id); + } + } + + public static class TL_messages_setTyping extends TLObject { + public static int constructor = 0xa3825e50; + + public InputPeer peer; + public SendMessageAction action; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + action.serializeToStream(stream); + } + } + + public static class TL_messages_sendMessage extends TLObject { + public static int constructor = 0xfa88427a; + + public int flags; + public boolean no_webpage; + public boolean broadcast; + public boolean silent; + public boolean background; + public InputPeer peer; + public int reply_to_msg_id; + public String message; + public long random_id; + public ReplyMarkup reply_markup; + public ArrayList entities = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = no_webpage ? (flags | 2) : (flags &~ 2); + flags = broadcast ? (flags | 16) : (flags &~ 16); + flags = silent ? (flags | 32) : (flags &~ 32); + flags = background ? (flags | 64) : (flags &~ 64); + stream.writeInt32(flags); + peer.serializeToStream(stream); + if ((flags & 1) != 0) { + stream.writeInt32(reply_to_msg_id); + } + stream.writeString(message); + stream.writeInt64(random_id); + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + if ((flags & 8) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + } + } + + public static class TL_messages_sendMedia extends TLObject { + public static int constructor = 0xc8f16791; + + public int flags; + public boolean broadcast; + public boolean silent; + public boolean background; + public InputPeer peer; + public int reply_to_msg_id; + public InputMedia media; + public long random_id; + public ReplyMarkup reply_markup; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = broadcast ? (flags | 16) : (flags &~ 16); + flags = silent ? (flags | 32) : (flags &~ 32); + flags = background ? (flags | 64) : (flags &~ 64); + stream.writeInt32(flags); + peer.serializeToStream(stream); + if ((flags & 1) != 0) { + stream.writeInt32(reply_to_msg_id); + } + media.serializeToStream(stream); + stream.writeInt64(random_id); + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + } + } + + public static class TL_messages_forwardMessages extends TLObject { + public static int constructor = 0x708e0195; + + public int flags; + public boolean broadcast; + public boolean silent; + public boolean background; + public InputPeer from_peer; + public ArrayList id = new ArrayList<>(); + public ArrayList random_id = new ArrayList<>(); + public InputPeer to_peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = broadcast ? (flags | 16) : (flags &~ 16); + flags = silent ? (flags | 32) : (flags &~ 32); + flags = background ? (flags | 64) : (flags &~ 64); + stream.writeInt32(flags); + from_peer.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(id.get(a)); + } + stream.writeInt32(0x1cb5c415); + count = random_id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(random_id.get(a)); + } + to_peer.serializeToStream(stream); + } + } + + public static class TL_messages_reportSpam extends TLObject { + public static int constructor = 0xcf1592db; + + public InputPeer peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + } + } + + public static class TL_messages_hideReportSpam extends TLObject { + public static int constructor = 0xa8f1709b; + + public InputPeer peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + } + } + + public static class TL_messages_getPeerSettings extends TLObject { + public static int constructor = 0x3672e09c; + + public InputPeer peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_peerSettings.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + } + } + + public static class TL_messages_getChats extends TLObject { + public static int constructor = 0x3c6aa187; + + public ArrayList id = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_chats.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(id.get(a)); + } + } + } + + public static class TL_messages_getFullChat extends TLObject { + public static int constructor = 0x3b831c66; + + public int chat_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_chatFull.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + } + } + + public static class TL_messages_editChatTitle extends TLObject { + public static int constructor = 0xdc452855; + + public int chat_id; + public String title; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + stream.writeString(title); + } + } + + public static class TL_messages_editChatPhoto extends TLObject { + public static int constructor = 0xca4c79d8; + + public int chat_id; + public InputChatPhoto photo; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + photo.serializeToStream(stream); + } + } + + public static class TL_messages_addChatUser extends TLObject { + public static int constructor = 0xf9a0aa09; + + public int chat_id; + public InputUser user_id; + public int fwd_limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + user_id.serializeToStream(stream); + stream.writeInt32(fwd_limit); + } + } + + public static class TL_messages_deleteChatUser extends TLObject { + public static int constructor = 0xe0611f16; + + public int chat_id; + public InputUser user_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + user_id.serializeToStream(stream); + } + } + + public static class TL_messages_createChat extends TLObject { + public static int constructor = 0x9cb126e; + + public ArrayList users = new ArrayList<>(); + public String title; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + stream.writeString(title); + } + } + + public static class TL_updates_getState extends TLObject { + public static int constructor = 0xedd4882a; + + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_updates_state.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_updates_getDifference extends TLObject { + public static int constructor = 0xa041495; + + public int pts; + public int date; + public int qts; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return updates_Difference.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(pts); + stream.writeInt32(date); + stream.writeInt32(qts); + } + } + + public static class TL_updates_getChannelDifference extends TLObject { + public static int constructor = 0xbb32d7c0; + + public InputChannel channel; + public ChannelMessagesFilter filter; + public int pts; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return updates_ChannelDifference.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + filter.serializeToStream(stream); + stream.writeInt32(pts); + stream.writeInt32(limit); + } + } + + public static class TL_photos_updateProfilePhoto extends TLObject { + public static int constructor = 0xeef579a0; + + public InputPhoto id; + public InputPhotoCrop crop; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return UserProfilePhoto.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + id.serializeToStream(stream); + crop.serializeToStream(stream); + } + } + + public static class TL_photos_uploadProfilePhoto extends TLObject { + public static int constructor = 0xd50f9c88; + + public InputFile file; + public String caption; + public InputGeoPoint geo_point; + public InputPhotoCrop crop; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_photos_photo.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + file.serializeToStream(stream); + stream.writeString(caption); + geo_point.serializeToStream(stream); + crop.serializeToStream(stream); + } + } + + public static class TL_photos_deletePhotos extends TLObject { + public static int constructor = 0x87cf7f2f; + + public ArrayList id = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + Vector vector = new Vector(); + int size = stream.readInt32(exception); + for (int a = 0; a < size; a++) { + vector.objects.add(stream.readInt64(exception)); + } + return vector; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + id.get(a).serializeToStream(stream); + } + } + } + + public static class TL_upload_getFile extends TLObject { + public static int constructor = 0xe3a6cfb5; + + public InputFileLocation location; + public int offset; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_upload_file.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + location.serializeToStream(stream); + stream.writeInt32(offset); + stream.writeInt32(limit); + } + } + + public static class TL_help_getConfig extends TLObject { + public static int constructor = 0xc4f9186b; + + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_config.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_help_getNearestDc extends TLObject { + public static int constructor = 0x1fb33026; + + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_nearestDc.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_help_getAppUpdate extends TLObject { + public static int constructor = 0xc812ac7e; + + public String device_model; + public String system_version; + public String app_version; + public String lang_code; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return help_AppUpdate.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(device_model); + stream.writeString(system_version); + stream.writeString(app_version); + stream.writeString(lang_code); + } + } + + public static class TL_help_saveAppLog extends TLObject { + public static int constructor = 0x6f02f748; + + public ArrayList events = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = events.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + events.get(a).serializeToStream(stream); + } + } + } + + public static class TL_help_getInviteText extends TLObject { + public static int constructor = 0xa4a95186; + + public String lang_code; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_help_inviteText.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(lang_code); + } + } + + public static class TL_photos_getUserPhotos extends TLObject { + public static int constructor = 0x91cd32a8; + + public InputUser user_id; + public int offset; + public long max_id; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return photos_Photos.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + user_id.serializeToStream(stream); + stream.writeInt32(offset); + stream.writeInt64(max_id); + stream.writeInt32(limit); + } + } + + public static class TL_messages_forwardMessage extends TLObject { + public static int constructor = 0x33963bf9; + + public InputPeer peer; + public int id; + public long random_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(id); + stream.writeInt64(random_id); + } + } + + public static class TL_messages_sendBroadcast extends TLObject { + public static int constructor = 0xbf73f4da; + + public ArrayList contacts = new ArrayList<>(); + public ArrayList random_id = new ArrayList<>(); + public String message; + public InputMedia media; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = contacts.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + contacts.get(a).serializeToStream(stream); + } + stream.writeInt32(0x1cb5c415); + count = random_id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(random_id.get(a)); + } + stream.writeString(message); + media.serializeToStream(stream); + } + } + + public static class TL_geochats_getLocated extends TLObject { + public static int constructor = 0x7f192d8f; + + public InputGeoPoint geo_point; + public int radius; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_geochats_located.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + geo_point.serializeToStream(stream); + stream.writeInt32(radius); + stream.writeInt32(limit); + } + } + + public static class TL_geochats_getRecents extends TLObject { + public static int constructor = 0xe1427e6f; + + public int offset; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return geochats_Messages.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset); + stream.writeInt32(limit); + } + } + + public static class TL_geochats_checkin extends TLObject { + public static int constructor = 0x55b3e8fb; + + public TL_inputGeoChat peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_geochats_statedMessage.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + } + } + + public static class TL_geochats_getFullChat extends TLObject { + public static int constructor = 0x6722dd6f; + + public TL_inputGeoChat peer; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_chatFull.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + } + } + + public static class TL_geochats_editChatTitle extends TLObject { + public static int constructor = 0x4c8e2273; + + public TL_inputGeoChat peer; + public String title; + public String address; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_geochats_statedMessage.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeString(title); + stream.writeString(address); + } + } + + public static class TL_geochats_editChatPhoto extends TLObject { + public static int constructor = 0x35d81a95; + + public TL_inputGeoChat peer; + public InputChatPhoto photo; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_geochats_statedMessage.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + photo.serializeToStream(stream); + } + } + + public static class TL_geochats_search extends TLObject { + public static int constructor = 0xcfcdc44d; + + public TL_inputGeoChat peer; + public String q; + public MessagesFilter filter; + public int min_date; + public int max_date; + public int offset; + public int max_id; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return geochats_Messages.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeString(q); + filter.serializeToStream(stream); + stream.writeInt32(min_date); + stream.writeInt32(max_date); + stream.writeInt32(offset); + stream.writeInt32(max_id); + stream.writeInt32(limit); + } + } + + public static class TL_geochats_getHistory extends TLObject { + public static int constructor = 0xb53f7a68; + + public TL_inputGeoChat peer; + public int offset; + public int max_id; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return geochats_Messages.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(offset); + stream.writeInt32(max_id); + stream.writeInt32(limit); + } + } + + public static class TL_geochats_setTyping extends TLObject { + public static int constructor = 0x8b8a729; + + public TL_inputGeoChat peer; + public boolean typing; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeBool(typing); + } + } + + public static class TL_geochats_sendMessage extends TLObject { + public static int constructor = 0x61b0044; + + public TL_inputGeoChat peer; + public String message; + public long random_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_geochats_statedMessage.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeString(message); + stream.writeInt64(random_id); + } + } + + public static class TL_geochats_sendMedia extends TLObject { + public static int constructor = 0xb8f0deff; + + public TL_inputGeoChat peer; + public InputMedia media; + public long random_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_geochats_statedMessage.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + media.serializeToStream(stream); + stream.writeInt64(random_id); + } + } + + public static class TL_geochats_createGeoChat extends TLObject { + public static int constructor = 0xe092e16; + + public String title; + public InputGeoPoint geo_point; + public String address; + public String venue; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_geochats_statedMessage.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(title); + geo_point.serializeToStream(stream); + stream.writeString(address); + stream.writeString(venue); + } + } + + public static class TL_messages_getDhConfig extends TLObject { + public static int constructor = 0x26cf8950; + + public int version; + public int random_length; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_DhConfig.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(version); + stream.writeInt32(random_length); + } + } + + public static class TL_messages_requestEncryption extends TLObject { + public static int constructor = 0xf64daf43; + + public InputUser user_id; + public int random_id; + public byte[] g_a; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return EncryptedChat.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + user_id.serializeToStream(stream); + stream.writeInt32(random_id); + stream.writeByteArray(g_a); + } + } + + public static class TL_messages_acceptEncryption extends TLObject { + public static int constructor = 0x3dbc0415; + + public TL_inputEncryptedChat peer; + public byte[] g_b; + public long key_fingerprint; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return EncryptedChat.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeByteArray(g_b); + stream.writeInt64(key_fingerprint); + } + } + + public static class TL_messages_discardEncryption extends TLObject { + public static int constructor = 0xedd923c5; + + public int chat_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + } + } + + public static class TL_messages_setEncryptedTyping extends TLObject { + public static int constructor = 0x791451ed; + + public TL_inputEncryptedChat peer; + public boolean typing; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeBool(typing); + } + } + + public static class TL_messages_readEncryptedHistory extends TLObject { + public static int constructor = 0x7f4b690a; + + public TL_inputEncryptedChat peer; + public int max_date; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(max_date); + } + } + + public static class TL_messages_receivedQueue extends TLObject { + public static int constructor = 0x55a5bb66; + + public int max_qts; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + Vector vector = new Vector(); + int size = stream.readInt32(exception); + for (int a = 0; a < size; a++) { + vector.objects.add(stream.readInt64(exception)); + } + return vector; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(max_qts); + } + } + + public static class TL_help_getSupport extends TLObject { + public static int constructor = 0x9cdf08cd; + + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_help_support.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_messages_readMessageContents extends TLObject { + public static int constructor = 0x36a73f77; + + public ArrayList id = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_affectedMessages.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(id.get(a)); + } + } + } + + public static class TL_account_checkUsername extends TLObject { + public static int constructor = 0x2714d86c; + + public String username; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(username); + } + } + + public static class TL_account_updateUsername extends TLObject { + public static int constructor = 0x3e0bdd7c; + + public String username; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return User.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(username); + } + } + + public static class TL_contacts_search extends TLObject { + public static int constructor = 0x11f812d8; + + public String q; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_contacts_found.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(q); + stream.writeInt32(limit); + } + } + + public static class TL_account_getPrivacy extends TLObject { + public static int constructor = 0xdadbc950; + + public InputPrivacyKey key; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_account_privacyRules.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + key.serializeToStream(stream); + } + } + + public static class TL_account_setPrivacy extends TLObject { + public static int constructor = 0xc9f81ce8; + + public InputPrivacyKey key; + public ArrayList rules = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_account_privacyRules.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + key.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = rules.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + rules.get(a).serializeToStream(stream); + } + } + } + + public static class TL_account_deleteAccount extends TLObject { + public static int constructor = 0x418d4e0b; + + public String reason; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(reason); + } + } + + public static class TL_account_getAccountTTL extends TLObject { + public static int constructor = 0x8fc711d; + + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_accountDaysTTL.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_account_setAccountTTL extends TLObject { + public static int constructor = 0x2442485e; + + public TL_accountDaysTTL ttl; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + ttl.serializeToStream(stream); + } + } + + public static class TL_contacts_resolveUsername extends TLObject { + public static int constructor = 0xf93ccba3; + + public String username; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_contacts_resolvedPeer.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(username); + } + } + + public static class TL_account_sendChangePhoneCode extends TLObject { + public static int constructor = 0x8e57deb; + + public int flags; + public boolean allow_flashcall; + public String phone_number; + public boolean current_number; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_auth_sentCode.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = allow_flashcall ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + stream.writeString(phone_number); + if ((flags & 1) != 0) { + stream.writeBool(current_number); + } + } + } + + public static class TL_account_changePhone extends TLObject { + public static int constructor = 0x70c32edb; + + public String phone_number; + public String phone_code_hash; + public String phone_code; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return User.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(phone_number); + stream.writeString(phone_code_hash); + stream.writeString(phone_code); + } + } + + public static class TL_messages_getStickers extends TLObject { + public static int constructor = 0xae22e045; + + public String emoticon; + public String hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Stickers.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(emoticon); + stream.writeString(hash); + } + } + + public static class TL_messages_getAllStickers extends TLObject { + public static int constructor = 0x1c9618b1; + + public int hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_AllStickers.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + } + } + + public static class TL_account_updateDeviceLocked extends TLObject { + public static int constructor = 0x38df3532; + + public int period; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(period); + } + } + + public static class TL_messages_getWebPagePreview extends TLObject { + public static int constructor = 0x25223e24; + + public String message; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return MessageMedia.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(message); + } + } + + public static class TL_account_getAuthorizations extends TLObject { + public static int constructor = 0xe320c158; + + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_account_authorizations.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_account_resetAuthorization extends TLObject { + public static int constructor = 0xdf77f3bc; + + public long hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(hash); + } + } + + public static class TL_account_getPassword extends TLObject { + public static int constructor = 0x548a30f5; + + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return account_Password.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_account_getPasswordSettings extends TLObject { + public static int constructor = 0xbc8d11bb; + + public byte[] current_password_hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_account_passwordSettings.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(current_password_hash); + } + } + + public static class TL_account_updatePasswordSettings extends TLObject { + public static int constructor = 0xfa7c4b86; + + public byte[] current_password_hash; + public TL_account_passwordInputSettings new_settings; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(current_password_hash); + new_settings.serializeToStream(stream); + } + } + + public static class TL_auth_checkPassword extends TLObject { + public static int constructor = 0xa63011e; + + public byte[] password_hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_auth_authorization.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(password_hash); + } + } + + public static class TL_auth_requestPasswordRecovery extends TLObject { + public static int constructor = 0xd897bc66; + + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_auth_passwordRecovery.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + } + } + + public static class TL_auth_recoverPassword extends TLObject { + public static int constructor = 0x4ea56e92; + + public String code; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_auth_authorization.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(code); + } + } + + public static class TL_auth_resendCode extends TLObject { + public static int constructor = 0x3ef1a9bf; + + public String phone_number; + public String phone_code_hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_auth_sentCode.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(phone_number); + stream.writeString(phone_code_hash); + } + } + + public static class TL_auth_cancelCode extends TLObject { + public static int constructor = 0x1f040578; + + public String phone_number; + public String phone_code_hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(phone_number); + stream.writeString(phone_code_hash); + } + } + + public static class TL_messages_exportChatInvite extends TLObject { + public static int constructor = 0x7d885289; + + public int chat_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return ExportedChatInvite.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(chat_id); + } + } + + public static class TL_messages_checkChatInvite extends TLObject { + public static int constructor = 0x3eadb1bb; + + public String hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return ChatInvite.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(hash); + } + } + + public static class TL_messages_importChatInvite extends TLObject { + public static int constructor = 0x6c50051c; + + public String hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(hash); + } + } + + public static class TL_messages_getStickerSet extends TLObject { + public static int constructor = 0x2619a90e; + + public InputStickerSet stickerset; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_stickerSet.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stickerset.serializeToStream(stream); + } + } + + public static class TL_messages_installStickerSet extends TLObject { + public static int constructor = 0x7b30c3a6; + + public InputStickerSet stickerset; + public boolean disabled; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stickerset.serializeToStream(stream); + stream.writeBool(disabled); + } + } + + public static class TL_messages_uninstallStickerSet extends TLObject { + public static int constructor = 0xf96e55de; + + public InputStickerSet stickerset; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stickerset.serializeToStream(stream); + } + } + + public static class TL_messages_startBot extends TLObject { + public static int constructor = 0xe6df7378; + + public InputUser bot; + public InputPeer peer; + public long random_id; + public String start_param; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + bot.serializeToStream(stream); + peer.serializeToStream(stream); + stream.writeInt64(random_id); + stream.writeString(start_param); + } + } + + public static class TL_messages_getMessagesViews extends TLObject { + public static int constructor = 0xc4c8a55d; + + public InputPeer peer; + public ArrayList id = new ArrayList<>(); + public boolean increment; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + Vector vector = new Vector(); + int size = stream.readInt32(exception); + for (int a = 0; a < size; a++) { + vector.objects.add(stream.readInt32(exception)); + } + return vector; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(id.get(a)); + } + stream.writeBool(increment); + } + } + + public static class TL_messages_searchGifs extends TLObject { + public static int constructor = 0xbf9a776b; + + public String q; + public int offset; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_foundGifs.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(q); + stream.writeInt32(offset); + } + } + + public static class TL_messages_getSavedGifs extends TLObject { + public static int constructor = 0x83bf3d52; + + public int hash; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_SavedGifs.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(hash); + } + } + + public static class TL_messages_saveGif extends TLObject { + public static int constructor = 0x327a30cb; + + public InputDocument id; + public boolean unsave; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + id.serializeToStream(stream); + stream.writeBool(unsave); + } + } + + public static class TL_messages_getInlineBotResults extends TLObject { + public static int constructor = 0x514e999d; + + public int flags; + public InputUser bot; + public InputPeer peer; + public InputGeoPoint geo_point; + public String query; + public String offset; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_botResults.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(flags); + bot.serializeToStream(stream); + peer.serializeToStream(stream); + if ((flags & 1) != 0) { + geo_point.serializeToStream(stream); + } + stream.writeString(query); + stream.writeString(offset); + } + } + + public static class TL_messages_sendInlineBotResult extends TLObject { + public static int constructor = 0xb16e06fe; + + public int flags; + public boolean broadcast; + public boolean silent; + public boolean background; + public InputPeer peer; + public int reply_to_msg_id; + public long random_id; + public long query_id; + public String id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = broadcast ? (flags | 16) : (flags &~ 16); + flags = silent ? (flags | 32) : (flags &~ 32); + flags = background ? (flags | 64) : (flags &~ 64); + stream.writeInt32(flags); + peer.serializeToStream(stream); + if ((flags & 1) != 0) { + stream.writeInt32(reply_to_msg_id); + } + stream.writeInt64(random_id); + stream.writeInt64(query_id); + stream.writeString(id); + } + } + + public static class TL_messages_getMessageEditData extends TLObject { + public static int constructor = 0xfda68d36; + + public InputPeer peer; + public int id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_messageEditData.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(id); + } + } + + public static class TL_messages_editMessage extends TLObject { + public static int constructor = 0xce91e4ca; + + public int flags; + public boolean no_webpage; + public InputPeer peer; + public int id; + public String message; + public ReplyMarkup reply_markup; + public ArrayList entities = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = no_webpage ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + peer.serializeToStream(stream); + stream.writeInt32(id); + if ((flags & 2048) != 0) { + stream.writeString(message); + } + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + if ((flags & 8) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + } + } + + public static class TL_messages_getBotCallbackAnswer extends TLObject { + public static int constructor = 0xa6e94f04; + + public InputPeer peer; + public int msg_id; + public byte[] data; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_botCallbackAnswer.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(msg_id); + stream.writeByteArray(data); + } + } + + public static class TL_messages_setBotCallbackAnswer extends TLObject { + public static int constructor = 0x481c591a; + + public int flags; + public boolean alert; + public long query_id; + public String message; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = alert ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + stream.writeInt64(query_id); + if ((flags & 1) != 0) { + stream.writeString(message); + } + } + } + + public static class TL_messages_editInlineBotMessage extends TLObject { + public static int constructor = 0x130c2c85; + + public int flags; + public boolean no_webpage; + public TL_inputBotInlineMessageID id; + public String message; + public ReplyMarkup reply_markup; + public ArrayList entities = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = no_webpage ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + id.serializeToStream(stream); + if ((flags & 2048) != 0) { + stream.writeString(message); + } + if ((flags & 4) != 0) { + reply_markup.serializeToStream(stream); + } + if ((flags & 8) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + } + } + + public static class TL_help_getAppChangelog extends TLObject { + public static int constructor = 0x5bab7fb2; + + public String device_model; + public String system_version; + public String app_version; + public String lang_code; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return help_AppChangelog.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(device_model); + stream.writeString(system_version); + stream.writeString(app_version); + stream.writeString(lang_code); + } + } + + public static class TL_help_getTermsOfService extends TLObject { + public static int constructor = 0x37d78f83; + + public String lang_code; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_help_termsOfService.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeString(lang_code); + } + } + + public static class TL_messages_reorderStickerSets extends TLObject { + public static int constructor = 0x9fcfbc30; + + public ArrayList order = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = order.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt64(order.get(a)); + } + } + } + + public static class TL_messages_getDocumentByHash extends TLObject { + public static int constructor = 0x338e2464; + + public byte[] sha256; + public int size; + public String mime_type; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Document.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeByteArray(sha256); + stream.writeInt32(size); + stream.writeString(mime_type); + } + } + + public static class TL_channels_getDialogs extends TLObject { + public static int constructor = 0xa9d3d249; + + public int offset; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Dialogs.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(offset); + stream.writeInt32(limit); + } + } + + public static class TL_channels_getImportantHistory extends TLObject { + public static int constructor = 0x8f494bb2; + + public InputChannel channel; + public int offset_id; + public int offset_date; + public int add_offset; + public int limit; + public int max_id; + public int min_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Messages.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeInt32(offset_id); + stream.writeInt32(offset_date); + stream.writeInt32(add_offset); + stream.writeInt32(limit); + stream.writeInt32(max_id); + stream.writeInt32(min_id); + } + } + + public static class TL_channels_readHistory extends TLObject { + public static int constructor = 0xcc104937; + + public InputChannel channel; + public int max_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeInt32(max_id); + } + } + + public static class TL_channels_deleteMessages extends TLObject { + public static int constructor = 0x84c1fd4e; + + public InputChannel channel; + public ArrayList id = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_affectedMessages.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(id.get(a)); + } + } + } + + public static class TL_channels_deleteUserHistory extends TLObject { + public static int constructor = 0xd10dd71b; + + public InputChannel channel; + public InputUser user_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_affectedHistory.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + user_id.serializeToStream(stream); + } + } + + public static class TL_channels_reportSpam extends TLObject { + public static int constructor = 0xfe087810; + + public InputChannel channel; + public InputUser user_id; + public ArrayList id = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + user_id.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(id.get(a)); + } + } + } + + public static class TL_channels_getMessages extends TLObject { + public static int constructor = 0x93d7b347; + + public InputChannel channel; + public ArrayList id = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_Messages.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + stream.writeInt32(id.get(a)); + } + } + } + + public static class TL_channels_getParticipants extends TLObject { + public static int constructor = 0x24d98f92; + + public InputChannel channel; + public ChannelParticipantsFilter filter; + public int offset; + public int limit; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_channels_channelParticipants.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + filter.serializeToStream(stream); + stream.writeInt32(offset); + stream.writeInt32(limit); + } + } + + public static class TL_channels_getParticipant extends TLObject { + public static int constructor = 0x546dd7a6; + + public InputChannel channel; + public InputUser user_id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_channels_channelParticipant.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + user_id.serializeToStream(stream); + } + } + + public static class TL_channels_getChannels extends TLObject { + public static int constructor = 0xa7f6bbb; + + public ArrayList id = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_chats.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(0x1cb5c415); + int count = id.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + id.get(a).serializeToStream(stream); + } + } + } + + public static class TL_channels_getFullChannel extends TLObject { + public static int constructor = 0x8736a09; + + public InputChannel channel; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_messages_chatFull.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + } + } + + public static class TL_channels_createChannel extends TLObject { + public static int constructor = 0xf4893d7f; + + public int flags; + public boolean broadcast; + public boolean megagroup; + public String title; + public String about; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = broadcast ? (flags | 1) : (flags &~ 1); + flags = megagroup ? (flags | 2) : (flags &~ 2); + stream.writeInt32(flags); + stream.writeString(title); + stream.writeString(about); + } + } + + public static class TL_channels_editAbout extends TLObject { + public static int constructor = 0x13e27f1e; + + public InputChannel channel; + public String about; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeString(about); + } + } + + public static class TL_channels_editAdmin extends TLObject { + public static int constructor = 0xeb7611d0; + + public InputChannel channel; + public InputUser user_id; + public ChannelParticipantRole role; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + user_id.serializeToStream(stream); + role.serializeToStream(stream); + } + } + + public static class TL_channels_editTitle extends TLObject { + public static int constructor = 0x566decd0; + + public InputChannel channel; + public String title; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeString(title); + } + } + + public static class TL_channels_editPhoto extends TLObject { + public static int constructor = 0xf12e57c9; + + public InputChannel channel; + public InputChatPhoto photo; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + photo.serializeToStream(stream); + } + } + + public static class TL_channels_toggleComments extends TLObject { + public static int constructor = 0xaaa29e88; + + public InputChannel channel; + public boolean enabled; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeBool(enabled); + } + } + + public static class TL_channels_checkUsername extends TLObject { + public static int constructor = 0x10e6bd2c; + + public InputChannel channel; + public String username; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeString(username); + } + } + + public static class TL_channels_updateUsername extends TLObject { + public static int constructor = 0x3514b3de; + + public InputChannel channel; + public String username; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeString(username); + } + } + + public static class TL_channels_joinChannel extends TLObject { + public static int constructor = 0x24b524c5; + + public InputChannel channel; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + } + } + + public static class TL_channels_leaveChannel extends TLObject { + public static int constructor = 0xf836aa95; + + public InputChannel channel; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + } + } + + public static class TL_channels_inviteToChannel extends TLObject { + public static int constructor = 0x199f3a6c; + + public InputChannel channel; + public ArrayList users = new ArrayList<>(); + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = users.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + users.get(a).serializeToStream(stream); + } + } + } + + public static class TL_channels_kickFromChannel extends TLObject { + public static int constructor = 0xa672de14; + + public InputChannel channel; + public InputUser user_id; + public boolean kicked; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + user_id.serializeToStream(stream); + stream.writeBool(kicked); + } + } + + public static class TL_channels_exportInvite extends TLObject { + public static int constructor = 0xc7560885; + + public InputChannel channel; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return ExportedChatInvite.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + } + } + + public static class TL_channels_deleteChannel extends TLObject { + public static int constructor = 0xc0111fe3; + + public InputChannel channel; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + } + } + + public static class TL_channels_toggleInvites extends TLObject { + public static int constructor = 0x49609307; + + public InputChannel channel; + public boolean enabled; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeBool(enabled); + } + } + + public static class TL_channels_exportMessageLink extends TLObject { + public static int constructor = 0xc846d22d; + + public InputChannel channel; + public int id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return TL_exportedMessageLink.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeInt32(id); + } + } + + public static class TL_channels_toggleSignatures extends TLObject { + public static int constructor = 0x1f69b606; + + public InputChannel channel; + public boolean enabled; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + channel.serializeToStream(stream); + stream.writeBool(enabled); + } + } + + public static class TL_channels_updatePinnedMessage extends TLObject { + public static int constructor = 0xa72ded52; + + public int flags; + public boolean silent; + public InputChannel channel; + public int id; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Updates.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = silent ? (flags | 1) : (flags &~ 1); + stream.writeInt32(flags); + channel.serializeToStream(stream); + stream.writeInt32(id); + } + } + + //manually created + + //MessageMedia start + public static class MessageMedia extends TLObject { + public byte[] bytes; + public Audio audio_unused; + public Photo photo; + public GeoPoint geo; + public String title; + public String address; + public String provider; + public String venue_id; + public Video video_unused; + public Document document; + public String caption; + public String phone_number; + public String first_name; + public String last_name; + public int user_id; + public WebPage webpage; + + public static MessageMedia TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + MessageMedia result = null; + switch(constructor) { + case 0x29632a36: + result = new TL_messageMediaUnsupported_old(); + break; + case 0xc6b68300: + result = new TL_messageMediaAudio_layer45(); + break; + case 0xc8c45a2a: + result = new TL_messageMediaPhoto_old(); + break; + case 0x9f84f49e: + result = new TL_messageMediaUnsupported(); + break; + case 0x3ded6320: + result = new TL_messageMediaEmpty(); + break; + case 0x7912b71f: + result = new TL_messageMediaVenue(); + break; + case 0xa2d24290: + result = new TL_messageMediaVideo_old(); + break; + case 0x2fda2204: + result = new TL_messageMediaDocument_old(); + break; + case 0xf3e02ea8: + result = new TL_messageMediaDocument(); + break; + case 0x5e7d2f39: + result = new TL_messageMediaContact(); + break; + case 0x3d8ce53d: + result = new TL_messageMediaPhoto(); + break; + case 0x5bcf1675: + result = new TL_messageMediaVideo_layer45(); + break; + case 0x56e0d474: + result = new TL_messageMediaGeo(); + break; + case 0xa32dd600: + result = new TL_messageMediaWebPage(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in MessageMedia", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + if (result.video_unused != null) { + TL_messageMediaDocument mediaDocument = new TL_messageMediaDocument(); + if (result.video_unused instanceof TLRPC.TL_videoEncrypted) { + mediaDocument.document = new TLRPC.TL_documentEncrypted(); + mediaDocument.document.key = result.video_unused.key; + mediaDocument.document.iv = result.video_unused.iv; + } else { + mediaDocument.document = new TLRPC.TL_document(); + } + mediaDocument.document.id = result.video_unused.id; + mediaDocument.document.access_hash = result.video_unused.access_hash; + mediaDocument.document.date = result.video_unused.date; + if (result.video_unused.mime_type != null) { + mediaDocument.document.mime_type = result.video_unused.mime_type; + } else { + mediaDocument.document.mime_type = "video/mp4"; + } + mediaDocument.document.size = result.video_unused.size; + mediaDocument.document.thumb = result.video_unused.thumb; + mediaDocument.document.dc_id = result.video_unused.dc_id; + mediaDocument.caption = result.caption; + TLRPC.TL_documentAttributeVideo attributeVideo = new TLRPC.TL_documentAttributeVideo(); + attributeVideo.w = result.video_unused.w; + attributeVideo.h = result.video_unused.h; + attributeVideo.duration = result.video_unused.duration; + mediaDocument.document.attributes.add(attributeVideo); + result = mediaDocument; + if (mediaDocument.caption == null) { + mediaDocument.caption = ""; + } + } else if (result.audio_unused != null) { + TL_messageMediaDocument mediaDocument = new TL_messageMediaDocument(); + if (result.audio_unused instanceof TLRPC.TL_audioEncrypted) { + mediaDocument.document = new TLRPC.TL_documentEncrypted(); + mediaDocument.document.key = result.audio_unused.key; + mediaDocument.document.iv = result.audio_unused.iv; + } else { + mediaDocument.document = new TLRPC.TL_document(); + } + mediaDocument.document.id = result.audio_unused.id; + mediaDocument.document.access_hash = result.audio_unused.access_hash; + mediaDocument.document.date = result.audio_unused.date; + if (result.audio_unused.mime_type != null) { + mediaDocument.document.mime_type = result.audio_unused.mime_type; + } else { + mediaDocument.document.mime_type = "audio/ogg"; + } + mediaDocument.document.size = result.audio_unused.size; + mediaDocument.document.thumb = new TL_photoSizeEmpty(); + mediaDocument.document.thumb.type = "s"; + mediaDocument.document.dc_id = result.audio_unused.dc_id; + mediaDocument.caption = result.caption; + TLRPC.TL_documentAttributeAudio attributeAudio = new TLRPC.TL_documentAttributeAudio(); + attributeAudio.duration = result.audio_unused.duration; + attributeAudio.voice = true; + mediaDocument.document.attributes.add(attributeAudio); + result = mediaDocument; + if (mediaDocument.caption == null) { + mediaDocument.caption = ""; + } + } + } + return result; + } + } + //MessageMedia end + + //EncryptedChat start + public static class EncryptedChat extends TLObject { + public int id; + public long access_hash; + public int date; + public int admin_id; + public int participant_id; + public byte[] g_a; + public byte[] nonce; + public byte[] g_a_or_b; + public long key_fingerprint; + public byte[] a_or_b; //custom + public byte[] auth_key; //custom + public int user_id; //custom + public int ttl; //custom + public int layer; //custom + public int seq_in; //custom + public int seq_out; //custom + public byte[] key_hash; //custom + public short key_use_count_in; //custom + public short key_use_count_out; //custom + public long exchange_id; //custom + public int key_create_date; //custom + public long future_key_fingerprint; //custom + public byte[] future_auth_key; //custom + + public static EncryptedChat TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + EncryptedChat result = null; + switch(constructor) { + case 0xfda9a7b7: + result = new TL_encryptedChatRequested_old(); + break; + case 0xc878527e: + result = new TL_encryptedChatRequested(); + break; + case 0xfa56ce36: + result = new TL_encryptedChat(); + break; + case 0x6601d14f: + result = new TL_encryptedChat_old(); + break; + case 0xab7ec0a0: + result = new TL_encryptedChatEmpty(); + break; + case 0x3bf703dc: + result = new TL_encryptedChatWaiting(); + break; + case 0x13d6dd27: + result = new TL_encryptedChatDiscarded(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in EncryptedChat", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + //EncryptedChat end + + //Message start + public static class Message extends TLObject { + public int id; + public int from_id; + public Peer to_id; + public int date; + public MessageAction action; + public int reply_to_msg_id; + public long reply_to_random_id; + public String message; + public MessageMedia media; + public int flags; + public boolean mentioned; + public boolean media_unread; + public boolean out; + public boolean unread; + public ArrayList entities = new ArrayList<>(); + public String via_bot_name; + public ReplyMarkup reply_markup; + public int views; + public int edit_date; + public boolean silent; + public boolean post; + public TL_messageFwdHeader fwd_from; + public int via_bot_id; + public int send_state = 0; //custom + public int fwd_msg_id = 0; //custom + public String attachPath = ""; //custom + public HashMap params; //custom + public long random_id; //custom + public int local_id = 0; //custom + public long dialog_id; //custom + public int ttl; //custom + public int destroyTime; //custom + public int layer; //custom + public int seq_in; //custom + public int seq_out; //custom + public TLRPC.Message replyMessage; //custom + + public static Message TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + Message result = null; + switch(constructor) { + case 0x1d86f70e: + result = new TL_messageService_old2(); + break; + case 0xa7ab1991: + result = new TL_message_old3(); + break; + case 0xc3060325: + result = new TL_message_old4(); + break; + case 0x555555f9: + result = new TL_message_secret(); + break; + case 0xc09be45f: + result = new TL_message(); + break; + case 0xc992e15c: + result = new TL_message_layer47(); + break; + case 0x5ba66c13: + result = new TL_message_old7(); + break; + case 0xc06b9607: + result = new TL_messageService_layer48(); + break; + case 0x83e5de54: + result = new TL_messageEmpty(); + break; + case 0x2bebfa86: + result = new TL_message_old6(); + break; + case 0xa367e716: + result = new TL_messageForwarded_old2(); //custom + break; + case 0x5f46804: + result = new TL_messageForwarded_old(); //custom + break; + case 0x567699b3: + result = new TL_message_old2(); //custom + break; + case 0x9f8d60bb: + result = new TL_messageService_old(); //custom + break; + case 0x22eb6aba: + result = new TL_message_old(); //custom + break; + case 0x555555F8: + result = new TL_message_secret_old(); //custom + break; + case 0x9e19a1f6: + result = new TL_messageService(); + break; + case 0xf07814c8: + result = new TL_message_old5(); //custom + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in Message", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_messageEmpty extends Message { + public static int constructor = 0x83e5de54; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + to_id = new TL_peerUser(); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + } + } + + public static class TL_messageService_old2 extends TL_messageService { + public static int constructor = 0x1d86f70e; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + id = stream.readInt32(exception); + from_id = stream.readInt32(exception); + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + action = MessageAction.TLdeserialize(stream, stream.readInt32(exception), exception); + flags |= MESSAGE_FLAG_HAS_FROM_ID; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt32(from_id); + to_id.serializeToStream(stream); + stream.writeInt32(date); + action.serializeToStream(stream); + } + } + + public static class TL_message extends Message { + public static int constructor = 0xc09be45f; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + silent = (flags & 8192) != 0; + post = (flags & 16384) != 0; + id = stream.readInt32(exception); + if ((flags & 256) != 0) { + from_id = stream.readInt32(exception); + } + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (from_id == 0) { + if (to_id.user_id != 0) { + from_id = to_id.user_id; + } else { + from_id = -to_id.channel_id; + } + } + if ((flags & 4) != 0) { + fwd_from = TL_messageFwdHeader.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 2048) != 0) { + via_bot_id = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + reply_to_msg_id = stream.readInt32(exception); + } + date = stream.readInt32(exception); + message = stream.readString(exception); + if ((flags & 512) != 0) { + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + } else { + media = new TL_messageMediaEmpty(); + } + if ((flags & 64) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 128) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + if ((flags & 1024) != 0) { + views = stream.readInt32(exception); + } + if ((flags & 32768) != 0) { + edit_date = stream.readInt32(exception); + } + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && !(media instanceof TL_messageMediaWebPage) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + if (id < 0 && attachPath.startsWith("||")) { + String args[] = attachPath.split("\\|\\|"); + if (args.length > 0) { + params = new HashMap<>(); + for (int a = 1; a < args.length - 1; a++) { + String args2[] = args[a].split("\\|=\\|"); + if (args2.length == 2) { + params.put(args2[0], args2[1]); + } + } + attachPath = args[args.length - 1]; + } + } + } + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + fwd_msg_id = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + flags = silent ? (flags | 8192) : (flags &~ 8192); + flags = post ? (flags | 16384) : (flags &~ 16384); + stream.writeInt32(flags); + stream.writeInt32(id); + if ((flags & 256) != 0) { + stream.writeInt32(from_id); + } + to_id.serializeToStream(stream); + if ((flags & 4) != 0) { + fwd_from.serializeToStream(stream); + } + if ((flags & 2048) != 0) { + stream.writeInt32(via_bot_id); + } + if ((flags & 8) != 0) { + stream.writeInt32(reply_to_msg_id); + } + stream.writeInt32(date); + stream.writeString(message); + if ((flags & 512) != 0) { + media.serializeToStream(stream); + } + if ((flags & 64) != 0) { + reply_markup.serializeToStream(stream); + } + if ((flags & 128) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + if ((flags & 1024) != 0) { + stream.writeInt32(views); + } + if ((flags & 32768) != 0) { + stream.writeInt32(edit_date); + } + String path = attachPath; + if (id < 0 && params != null && params.size() > 0) { + for (HashMap.Entry entry : params.entrySet()) { + path = entry.getKey() + "|=|" + entry.getValue() + "||" + path; + } + path = "||" + path; + } + stream.writeString(path); + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + stream.writeInt32(fwd_msg_id); + } + } + } + + public static class TL_message_layer47 extends TL_message { + public static int constructor = 0xc992e15c; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + id = stream.readInt32(exception); + if ((flags & 256) != 0) { + from_id = stream.readInt32(exception); + } + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (from_id == 0) { + if (to_id.user_id != 0) { + from_id = to_id.user_id; + } else { + from_id = -to_id.channel_id; + } + } + if ((flags & 4) != 0) { + fwd_from = new TL_messageFwdHeader(); + Peer peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (peer instanceof TLRPC.TL_peerChannel) { + fwd_from.channel_id = peer.channel_id; + fwd_from.flags |= 2; + } else if (peer instanceof TLRPC.TL_peerUser) { + fwd_from.from_id = peer.user_id; + fwd_from.flags |= 1; + } + fwd_from.date = stream.readInt32(exception); + } + if ((flags & 2048) != 0) { + via_bot_id = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + reply_to_msg_id = stream.readInt32(exception); + } + date = stream.readInt32(exception); + message = stream.readString(exception); + if ((flags & 512) != 0) { + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + } else { + media = new TL_messageMediaEmpty(); + } + if ((flags & 64) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 128) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + if ((flags & 1024) != 0) { + views = stream.readInt32(exception); + } + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && !(media instanceof TL_messageMediaWebPage) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + if (id < 0 && attachPath.startsWith("||")) { + String args[] = attachPath.split("\\|\\|"); + if (args.length > 0) { + params = new HashMap<>(); + for (int a = 1; a < args.length - 1; a++) { + String args2[] = args[a].split("\\|=\\|"); + if (args2.length == 2) { + params.put(args2[0], args2[1]); + } + } + attachPath = args[args.length - 1]; + } + } + } + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + fwd_msg_id = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + stream.writeInt32(id); + if ((flags & 256) != 0) { + stream.writeInt32(from_id); + } + to_id.serializeToStream(stream); + if ((flags & 4) != 0) { + if (fwd_from.from_id != 0) { + TLRPC.TL_peerUser peer = new TL_peerUser(); + peer.user_id = fwd_from.from_id; + peer.serializeToStream(stream); + } else { + TLRPC.TL_peerChannel peer = new TL_peerChannel(); + peer.channel_id = fwd_from.channel_id; + peer.serializeToStream(stream); + } + stream.writeInt32(fwd_from.date); + } + if ((flags & 2048) != 0) { + stream.writeInt32(via_bot_id); + } + if ((flags & 8) != 0) { + stream.writeInt32(reply_to_msg_id); + } + stream.writeInt32(date); + stream.writeString(message); + if ((flags & 512) != 0) { + media.serializeToStream(stream); + } + if ((flags & 64) != 0) { + reply_markup.serializeToStream(stream); + } + if ((flags & 128) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + if ((flags & 1024) != 0) { + stream.writeInt32(views); + } + String path = attachPath; + if (id < 0 && params != null && params.size() > 0) { + for (HashMap.Entry entry : params.entrySet()) { + path = entry.getKey() + "|=|" + entry.getValue() + "||" + path; + } + path = "||" + path; + } + stream.writeString(path); + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + stream.writeInt32(fwd_msg_id); + } + } + } + + public static class TL_message_old7 extends TL_message { + public static int constructor = 0x5ba66c13; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + id = stream.readInt32(exception); + if ((flags & 256) != 0) { + from_id = stream.readInt32(exception); + } + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (from_id == 0) { + if (to_id.user_id != 0) { + from_id = to_id.user_id; + } else { + from_id = -to_id.channel_id; + } + } + if ((flags & 4) != 0) { + fwd_from = new TL_messageFwdHeader(); + Peer peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (peer instanceof TLRPC.TL_peerChannel) { + fwd_from.channel_id = peer.channel_id; + fwd_from.flags |= 2; + } else if (peer instanceof TLRPC.TL_peerUser) { + fwd_from.from_id = peer.user_id; + fwd_from.flags |= 1; + } + fwd_from.date = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + reply_to_msg_id = stream.readInt32(exception); + } + date = stream.readInt32(exception); + message = stream.readString(exception); + if ((flags & 512) != 0) { + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + } else { + media = new TL_messageMediaEmpty(); + } + if ((flags & 64) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 128) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + if ((flags & 1024) != 0) { + views = stream.readInt32(exception); + } + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && !(media instanceof TL_messageMediaWebPage) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + } + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + fwd_msg_id = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + stream.writeInt32(id); + if ((flags & 256) != 0) { + stream.writeInt32(from_id); + } + to_id.serializeToStream(stream); + if ((flags & 4) != 0) { + if (fwd_from.from_id != 0) { + TLRPC.TL_peerUser peer = new TL_peerUser(); + peer.user_id = fwd_from.from_id; + peer.serializeToStream(stream); + } else { + TLRPC.TL_peerChannel peer = new TL_peerChannel(); + peer.channel_id = fwd_from.channel_id; + peer.serializeToStream(stream); + } + stream.writeInt32(fwd_from.date); + } + if ((flags & 8) != 0) { + stream.writeInt32(reply_to_msg_id); + } + stream.writeInt32(date); + stream.writeString(message); + if ((flags & 512) != 0) { + media.serializeToStream(stream); + } + if ((flags & 64) != 0) { + reply_markup.serializeToStream(stream); + } + if ((flags & 128) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + if ((flags & 1024) != 0) { + stream.writeInt32(views); + } + stream.writeString(attachPath); + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + stream.writeInt32(fwd_msg_id); + } + } + } + + public static class TL_messageForwarded_old2 extends Message { + public static int constructor = 0xa367e716; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + id = stream.readInt32(exception); + fwd_from = new TL_messageFwdHeader(); + fwd_from.from_id = stream.readInt32(exception); + fwd_from.flags |= 1; + fwd_from.date = stream.readInt32(exception); + from_id = stream.readInt32(exception); + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + message = stream.readString(exception); + flags |= MESSAGE_FLAG_FWD | MESSAGE_FLAG_HAS_FROM_ID | MESSAGE_FLAG_HAS_MEDIA; + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if (id < 0) { + fwd_msg_id = stream.readInt32(exception); + } + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt32(fwd_from.from_id); + stream.writeInt32(fwd_from.date); + stream.writeInt32(from_id); + to_id.serializeToStream(stream); + stream.writeInt32(date); + stream.writeString(message); + media.serializeToStream(stream); + if (id < 0) { + stream.writeInt32(fwd_msg_id); + } + stream.writeString(attachPath); + } + } + + public static class TL_message_old6 extends TL_message { + public static int constructor = 0x2bebfa86; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception) | MESSAGE_FLAG_HAS_FROM_ID; + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + id = stream.readInt32(exception); + from_id = stream.readInt32(exception); + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 4) != 0) { + fwd_from = new TL_messageFwdHeader(); + fwd_from.from_id = stream.readInt32(exception); + fwd_from.flags |= 1; + fwd_from.date = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + reply_to_msg_id = stream.readInt32(exception); + } + date = stream.readInt32(exception); + message = stream.readString(exception); + if ((flags & 512) != 0) { + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + } else { + media = new TL_messageMediaEmpty(); + } + if ((flags & 64) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 128) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && !(media instanceof TL_messageMediaWebPage) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + } + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + fwd_msg_id = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt32(from_id); + to_id.serializeToStream(stream); + if ((flags & 4) != 0) { + stream.writeInt32(fwd_from.from_id); + stream.writeInt32(fwd_from.date); + } + if ((flags & 8) != 0) { + stream.writeInt32(reply_to_msg_id); + } + stream.writeInt32(date); + stream.writeString(message); + if ((flags & 512) != 0) { + media.serializeToStream(stream); + } + if ((flags & 64) != 0) { + reply_markup.serializeToStream(stream); + } + if ((flags & 128) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + stream.writeString(attachPath); + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + stream.writeInt32(fwd_msg_id); + } + } + } + + public static class TL_message_old5 extends TL_message { + public static int constructor = 0xf07814c8; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception) | MESSAGE_FLAG_HAS_FROM_ID | MESSAGE_FLAG_HAS_MEDIA; + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + id = stream.readInt32(exception); + from_id = stream.readInt32(exception); + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 4) != 0) { + fwd_from = new TL_messageFwdHeader(); + fwd_from.from_id = stream.readInt32(exception); + fwd_from.flags |= 1; + fwd_from.date = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + reply_to_msg_id = stream.readInt32(exception); + } + date = stream.readInt32(exception); + message = stream.readString(exception); + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 64) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if ((flags & 128) != 0) { + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + } + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && !(media instanceof TL_messageMediaWebPage) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + } + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + fwd_msg_id = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt32(from_id); + to_id.serializeToStream(stream); + if ((flags & 4) != 0) { + stream.writeInt32(fwd_from.from_id); + stream.writeInt32(fwd_from.date); + } + if ((flags & 8) != 0) { + stream.writeInt32(reply_to_msg_id); + } + stream.writeInt32(date); + stream.writeString(message); + media.serializeToStream(stream); + if ((flags & 64) != 0) { + reply_markup.serializeToStream(stream); + } + if ((flags & 128) != 0) { + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + } + stream.writeString(attachPath); + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + stream.writeInt32(fwd_msg_id); + } + } + } + + public static class TL_messageService_layer48 extends TL_messageService { + public static int constructor = 0xc06b9607; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + silent = (flags & 8192) != 0; + post = (flags & 16384) != 0; + id = stream.readInt32(exception); + if ((flags & 256) != 0) { + from_id = stream.readInt32(exception); + } + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if (from_id == 0) { + if (to_id.user_id != 0) { + from_id = to_id.user_id; + } else { + from_id = -to_id.channel_id; + } + } + date = stream.readInt32(exception); + action = MessageAction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + flags = silent ? (flags | 8192) : (flags &~ 8192); + flags = post ? (flags | 16384) : (flags &~ 16384); + stream.writeInt32(flags); + stream.writeInt32(id); + if ((flags & 256) != 0) { + stream.writeInt32(from_id); + } + to_id.serializeToStream(stream); + stream.writeInt32(date); + action.serializeToStream(stream); + } + } + + public static class TL_message_old4 extends TL_message { + public static int constructor = 0xc3060325; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception) | MESSAGE_FLAG_HAS_FROM_ID | MESSAGE_FLAG_HAS_MEDIA; + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + id = stream.readInt32(exception); + from_id = stream.readInt32(exception); + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 4) != 0) { + fwd_from = new TL_messageFwdHeader(); + fwd_from.from_id = stream.readInt32(exception); + fwd_from.flags |= 1; + fwd_from.date = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + reply_to_msg_id = stream.readInt32(exception); + } + date = stream.readInt32(exception); + message = stream.readString(exception); + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 64) != 0) { + reply_markup = ReplyMarkup.TLdeserialize(stream, stream.readInt32(exception), exception); + } + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && !(media instanceof TL_messageMediaWebPage) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + } + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + fwd_msg_id = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt32(from_id); + to_id.serializeToStream(stream); + if ((flags & 4) != 0) { + stream.writeInt32(fwd_from.from_id); + stream.writeInt32(fwd_from.date); + } + if ((flags & 8) != 0) { + stream.writeInt32(reply_to_msg_id); + } + stream.writeInt32(date); + stream.writeString(message); + media.serializeToStream(stream); + if ((flags & 64) != 0) { + reply_markup.serializeToStream(stream); + } + stream.writeString(attachPath); + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + stream.writeInt32(fwd_msg_id); + } + } + } + + public static class TL_message_old3 extends TL_message { + public static int constructor = 0xa7ab1991; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception) | MESSAGE_FLAG_HAS_FROM_ID | MESSAGE_FLAG_HAS_MEDIA; + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + id = stream.readInt32(exception); + from_id = stream.readInt32(exception); + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 4) != 0) { + fwd_from = new TL_messageFwdHeader(); + fwd_from.from_id = stream.readInt32(exception); + fwd_from.flags |= 1; + fwd_from.date = stream.readInt32(exception); + } + if ((flags & 8) != 0) { + reply_to_msg_id = stream.readInt32(exception); + } + date = stream.readInt32(exception); + message = stream.readString(exception); + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && !(media instanceof TL_messageMediaWebPage) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + } + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + fwd_msg_id = stream.readInt32(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt32(from_id); + to_id.serializeToStream(stream); + if ((flags & 4) != 0) { + stream.writeInt32(fwd_from.from_id); + stream.writeInt32(fwd_from.date); + } + if ((flags & 8) != 0) { + stream.writeInt32(reply_to_msg_id); + } + stream.writeInt32(date); + stream.writeString(message); + media.serializeToStream(stream); + stream.writeString(attachPath); + if ((flags & MESSAGE_FLAG_FWD) != 0 && id < 0) { + stream.writeInt32(fwd_msg_id); + } + } + } + + public static class TL_message_old2 extends TL_message { + public static int constructor = 0x567699b3; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception) | MESSAGE_FLAG_HAS_FROM_ID | MESSAGE_FLAG_HAS_MEDIA; + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + id = stream.readInt32(exception); + from_id = stream.readInt32(exception); + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + message = stream.readString(exception); + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && !(media instanceof TL_messageMediaWebPage) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt32(from_id); + to_id.serializeToStream(stream); + stream.writeInt32(date); + stream.writeString(message); + media.serializeToStream(stream); + stream.writeString(attachPath); + } + } + + public static class TL_messageService_old extends TL_messageService { + public static int constructor = 0x9f8d60bb; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + from_id = stream.readInt32(exception); + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + out = stream.readBool(exception); + unread = stream.readBool(exception); + flags |= MESSAGE_FLAG_HAS_FROM_ID; + date = stream.readInt32(exception); + action = MessageAction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeInt32(from_id); + to_id.serializeToStream(stream); + stream.writeBool(out); + stream.writeBool(unread); + stream.writeInt32(date); + action.serializeToStream(stream); + } + } + + public static class TL_messageForwarded_old extends TL_messageForwarded_old2 { + public static int constructor = 0x5f46804; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + fwd_from = new TL_messageFwdHeader(); + fwd_from.from_id = stream.readInt32(exception); + fwd_from.flags |= 1; + fwd_from.date = stream.readInt32(exception); + from_id = stream.readInt32(exception); + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + out = stream.readBool(exception); + unread = stream.readBool(exception); + flags |= MESSAGE_FLAG_FWD | MESSAGE_FLAG_HAS_FROM_ID | MESSAGE_FLAG_HAS_MEDIA; + date = stream.readInt32(exception); + message = stream.readString(exception); + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if (id < 0) { + fwd_msg_id = stream.readInt32(exception); + } + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && !(media instanceof TL_messageMediaWebPage) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeInt32(fwd_from.from_id); + stream.writeInt32(fwd_from.date); + stream.writeInt32(from_id); + to_id.serializeToStream(stream); + stream.writeBool(out); + stream.writeBool(unread); + stream.writeInt32(date); + stream.writeString(message); + media.serializeToStream(stream); + if (id < 0) { + stream.writeInt32(fwd_msg_id); + } + stream.writeString(attachPath); + } + } + + public static class TL_message_old extends TL_message { + public static int constructor = 0x22eb6aba; + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + from_id = stream.readInt32(exception); + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + out = stream.readBool(exception); + unread = stream.readBool(exception); + flags |= MESSAGE_FLAG_HAS_FROM_ID | MESSAGE_FLAG_HAS_MEDIA; + date = stream.readInt32(exception); + message = stream.readString(exception); + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && !(media instanceof TL_messageMediaWebPage) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + stream.writeInt32(from_id); + to_id.serializeToStream(stream); + stream.writeBool(out); + stream.writeBool(unread); + stream.writeInt32(date); + stream.writeString(message); + media.serializeToStream(stream); + stream.writeString(attachPath); + } + } + + public static class TL_message_secret extends TL_message { + public static int constructor = 0x555555f9; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + id = stream.readInt32(exception); + ttl = stream.readInt32(exception); + from_id = stream.readInt32(exception); + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + message = stream.readString(exception); + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + int magic = stream.readInt32(exception); + if (magic != 0x1cb5c415) { + if (exception) { + throw new RuntimeException(String.format("wrong Vector magic, got %x", magic)); + } + return; + } + int count = stream.readInt32(exception); + for (int a = 0; a < count; a++) { + MessageEntity object = MessageEntity.TLdeserialize(stream, stream.readInt32(exception), exception); + if (object == null) { + return; + } + entities.add(object); + } + if ((flags & 2048) != 0) { + via_bot_name = stream.readString(exception); + } + if ((flags & 8) != 0) { + reply_to_random_id = stream.readInt64(exception); + } + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && !(media instanceof TL_messageMediaWebPage) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt32(ttl); + stream.writeInt32(from_id); + to_id.serializeToStream(stream); + stream.writeInt32(date); + stream.writeString(message); + media.serializeToStream(stream); + stream.writeInt32(0x1cb5c415); + int count = entities.size(); + stream.writeInt32(count); + for (int a = 0; a < count; a++) { + entities.get(a).serializeToStream(stream); + } + if ((flags & 2048) != 0) { + stream.writeString(via_bot_name); + } + if ((flags & 8) != 0) { + stream.writeInt64(reply_to_random_id); + } + stream.writeString(attachPath); + } + } + + public static class TL_message_secret_old extends TL_message_secret { + public static int constructor = 0x555555F8; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception) | MESSAGE_FLAG_HAS_FROM_ID | MESSAGE_FLAG_HAS_MEDIA; + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + id = stream.readInt32(exception); + ttl = stream.readInt32(exception); + from_id = stream.readInt32(exception); + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + date = stream.readInt32(exception); + message = stream.readString(exception); + media = MessageMedia.TLdeserialize(stream, stream.readInt32(exception), exception); + if (id < 0 || (media != null && !(media instanceof TL_messageMediaEmpty) && !(media instanceof TL_messageMediaWebPage) && message != null && message.length() != 0 && message.startsWith("-1"))) { + attachPath = stream.readString(exception); + } + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + stream.writeInt32(flags); + stream.writeInt32(id); + stream.writeInt32(ttl); + stream.writeInt32(from_id); + to_id.serializeToStream(stream); + stream.writeInt32(date); + stream.writeString(message); + media.serializeToStream(stream); + stream.writeString(attachPath); + } + } + + public static class TL_messageService extends Message { + public static int constructor = 0x9e19a1f6; + + public void readParams(AbstractSerializedData stream, boolean exception) { + flags = stream.readInt32(exception); + unread = (flags & 1) != 0; + out = (flags & 2) != 0; + mentioned = (flags & 16) != 0; + media_unread = (flags & 32) != 0; + silent = (flags & 8192) != 0; + post = (flags & 16384) != 0; + id = stream.readInt32(exception); + if ((flags & 256) != 0) { + from_id = stream.readInt32(exception); + } + to_id = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + if ((flags & 8) != 0) { + reply_to_msg_id = stream.readInt32(exception); + } + date = stream.readInt32(exception); + action = MessageAction.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + flags = unread ? (flags | 1) : (flags &~ 1); + flags = out ? (flags | 2) : (flags &~ 2); + flags = mentioned ? (flags | 16) : (flags &~ 16); + flags = media_unread ? (flags | 32) : (flags &~ 32); + flags = silent ? (flags | 8192) : (flags &~ 8192); + flags = post ? (flags | 16384) : (flags &~ 16384); + stream.writeInt32(flags); + stream.writeInt32(id); + if ((flags & 256) != 0) { + stream.writeInt32(from_id); + } + to_id.serializeToStream(stream); + if ((flags & 8) != 0) { + stream.writeInt32(reply_to_msg_id); + } + stream.writeInt32(date); + action.serializeToStream(stream); + } + } + //Message end + + //TL_dialog start + public static class Dialog extends TLObject { + public Peer peer; + public int top_message; + public int top_not_important_message; + public int read_inbox_max_id; + public int unread_count; + public int unread_not_important_count; + public PeerNotifySettings notify_settings; + public int pts; + public int last_message_date; //custom + public int last_message_date_i; //custom + public long id; //custom + public int last_read; //custom + + public static Dialog TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + Dialog result = null; + switch(constructor) { + case 0x5b8496b2: + result = new TL_dialogChannel(); + break; + case 0xc1dd804a: + result = new TL_dialog(); + break; + } + if (result == null && exception) { + throw new RuntimeException(String.format("can't parse magic %x in Dialog", constructor)); + } + if (result != null) { + result.readParams(stream, exception); + } + return result; + } + } + + public static class TL_dialogChannel extends Dialog { + public static int constructor = 0x5b8496b2; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + top_not_important_message = stream.readInt32(exception); + top_message = stream.readInt32(exception); + read_inbox_max_id = stream.readInt32(exception); + unread_not_important_count = stream.readInt32(exception); + unread_count = stream.readInt32(exception); + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + pts = stream.readInt32(exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(top_not_important_message); + stream.writeInt32(top_message); + stream.writeInt32(read_inbox_max_id); + stream.writeInt32(unread_not_important_count); + stream.writeInt32(unread_count); + notify_settings.serializeToStream(stream); + stream.writeInt32(pts); + } + } + + public static class TL_dialog extends Dialog { + public static int constructor = 0xc1dd804a; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + peer = Peer.TLdeserialize(stream, stream.readInt32(exception), exception); + top_message = stream.readInt32(exception); + read_inbox_max_id = stream.readInt32(exception); + unread_count = stream.readInt32(exception); + notify_settings = PeerNotifySettings.TLdeserialize(stream, stream.readInt32(exception), exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt32(top_message); + stream.writeInt32(read_inbox_max_id); + stream.writeInt32(unread_count); + notify_settings.serializeToStream(stream); + } + } + //TL_dialog end + + //ChatParticipant start + public static class TL_chatChannelParticipant extends ChatParticipant { + public static int constructor = 0xc8d7493e; + + public TLRPC.ChannelParticipant channelParticipant; + } + //ChatParticipant end + + //Chat start + public static class TL_chatEmpty extends Chat { + public static int constructor = 0x9ba2d800; + + + public void readParams(AbstractSerializedData stream, boolean exception) { + id = stream.readInt32(exception); + + title = "DELETED"; + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt32(id); + } + } + //Chat end + + //functions memory optimize + public static class TL_upload_saveFilePart extends TLObject { + public static int constructor = 0xb304a621; + + public long file_id; + public int file_part; + public NativeByteBuffer bytes; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(file_id); + stream.writeInt32(file_part); + stream.writeByteBuffer(bytes); + } + + @Override + public void freeResources() { + if (disableFree) { + return; + } + if (bytes != null) { + bytes.reuse(); + bytes = null; + } + } + } + + public static class TL_upload_saveBigFilePart extends TLObject { + public static int constructor = 0xde7b673d; + + public long file_id; + public int file_part; + public int file_total_parts; + public NativeByteBuffer bytes; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return Bool.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + stream.writeInt64(file_id); + stream.writeInt32(file_part); + stream.writeInt32(file_total_parts); + stream.writeByteBuffer(bytes); + } + + @Override + public void freeResources() { + if (disableFree) { + return; + } + if (bytes != null) { + bytes.reuse(); + bytes = null; + } + } + } + + public static class TL_upload_file extends TLObject { + public static int constructor = 0x96a18d5; + + public storage_FileType type; + public int mtime; + public NativeByteBuffer bytes; + + public static TL_upload_file TLdeserialize(AbstractSerializedData stream, int constructor, boolean exception) { + if (TL_upload_file.constructor != constructor) { + if (exception) { + throw new RuntimeException(String.format("can't parse magic %x in TL_upload_file", constructor)); + } else { + return null; + } + } + TL_upload_file result = new TL_upload_file(); + result.readParams(stream, exception); + return result; + } + + public void readParams(AbstractSerializedData stream, boolean exception) { + type = storage_FileType.TLdeserialize(stream, stream.readInt32(exception), exception); + mtime = stream.readInt32(exception); + bytes = stream.readByteBuffer(exception); + } + + @Override + public void freeResources() { + if (disableFree) { + return; + } + if (bytes != null) { + bytes.reuse(); + bytes = null; + } + } + } + + public static class TL_messages_sendEncryptedFile extends TLObject { + public static int constructor = 0x9a901b66; + + public TL_inputEncryptedChat peer; + public long random_id; + public NativeByteBuffer data; + public InputEncryptedFile file; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_SentEncryptedMessage.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt64(random_id); + stream.writeByteBuffer(data); + file.serializeToStream(stream); + } + + @Override + public void freeResources() { + if (data != null) { + data.reuse(); + data = null; + } + } + } + + public static class TL_messages_sendEncrypted extends TLObject { + public static int constructor = 0xa9776773; + + public TL_inputEncryptedChat peer; + public long random_id; + public NativeByteBuffer data; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_SentEncryptedMessage.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt64(random_id); + stream.writeByteBuffer(data); + } + + @Override + public void freeResources() { + if (data != null) { + data.reuse(); + data = null; + } + } + } + + public static class TL_messages_sendEncryptedService extends TLObject { + public static int constructor = 0x32d439a4; + + public TL_inputEncryptedChat peer; + public long random_id; + public NativeByteBuffer data; + + public TLObject deserializeResponse(AbstractSerializedData stream, int constructor, boolean exception) { + return messages_SentEncryptedMessage.TLdeserialize(stream, constructor, exception); + } + + public void serializeToStream(AbstractSerializedData stream) { + stream.writeInt32(constructor); + peer.serializeToStream(stream); + stream.writeInt64(random_id); + stream.writeByteBuffer(data); + } + + @Override + public void freeResources() { + if (data != null) { + data.reuse(); + data = null; + } + } + } + + //functions + + public static class Vector extends TLObject { + public static int constructor = 0x1cb5c415; + public ArrayList objects = new ArrayList<>(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java index 263f9423..b71fa578 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBar.java @@ -12,21 +12,17 @@ import android.content.Context; import android.content.res.Configuration; import android.graphics.drawable.Drawable; import android.os.Build; -import android.text.TextUtils; -import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; -import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.AnimationCompat.AnimatorListenerAdapterProxy; import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.R; import org.telegram.ui.Components.LayoutHelper; import java.util.ArrayList; @@ -44,21 +40,23 @@ public class ActionBar extends FrameLayout { } private ImageView backButtonImageView; - private TextView titleTextView; - private TextView subTitleTextView; + private SimpleTextView titleTextView; + private SimpleTextView subtitleTextView; private View actionModeTop; private ActionBarMenu menu; private ActionBarMenu actionMode; private boolean occupyStatusBar = Build.VERSION.SDK_INT >= 21; private boolean actionModeVisible; private boolean addToContainer = true; + private boolean interceptTouches = true; + private int extraHeight; private boolean allowOverlayTitle; private CharSequence lastTitle; private boolean castShadows = true; protected boolean isSearchFieldVisible; - protected int itemsBackgroundResourceId; + protected int itemsBackgroundColor; private boolean isBackOverlayVisible; protected BaseFragment parentFragment; public ActionBarMenuOnItemClick actionBarMenuOnItemClick; @@ -73,7 +71,7 @@ public class ActionBar extends FrameLayout { } backButtonImageView = new ImageView(getContext()); backButtonImageView.setScaleType(ImageView.ScaleType.CENTER); - backButtonImageView.setBackgroundResource(itemsBackgroundResourceId); + backButtonImageView.setBackgroundDrawable(Theme.createBarSelectorDrawable(itemsBackgroundColor)); backButtonImageView.setPadding(AndroidUtilities.dp(1), 0, 0, 0); addView(backButtonImageView, LayoutHelper.createFrame(54, 54, Gravity.LEFT | Gravity.TOP)); @@ -111,17 +109,13 @@ public class ActionBar extends FrameLayout { } private void createSubtitleTextView() { - if (subTitleTextView != null) { + if (subtitleTextView != null) { return; } - subTitleTextView = new TextView(getContext()); - subTitleTextView.setGravity(Gravity.LEFT); - subTitleTextView.setTextColor(0xffd7e8f7); - subTitleTextView.setSingleLine(true); - subTitleTextView.setLines(1); - subTitleTextView.setMaxLines(1); - subTitleTextView.setEllipsize(TextUtils.TruncateAt.END); - addView(subTitleTextView, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP)); + subtitleTextView = new SimpleTextView(getContext()); + subtitleTextView.setGravity(Gravity.LEFT); + subtitleTextView.setTextColor(Theme.ACTION_BAR_SUBTITLE_COLOR); + addView(subtitleTextView, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP)); } public void setAddToContainer(boolean value) { @@ -133,12 +127,12 @@ public class ActionBar extends FrameLayout { } public void setSubtitle(CharSequence value) { - if (value != null && subTitleTextView == null) { + if (value != null && subtitleTextView == null) { createSubtitleTextView(); } - if (subTitleTextView != null) { - subTitleTextView.setVisibility(value != null && !isSearchFieldVisible ? VISIBLE : INVISIBLE); - subTitleTextView.setText(value); + if (subtitleTextView != null) { + subtitleTextView.setVisibility(value != null && !isSearchFieldVisible ? VISIBLE : INVISIBLE); + subtitleTextView.setText(value); } } @@ -146,12 +140,8 @@ public class ActionBar extends FrameLayout { if (titleTextView != null) { return; } - titleTextView = new TextView(getContext()); + titleTextView = new SimpleTextView(getContext()); titleTextView.setGravity(Gravity.LEFT); - titleTextView.setLines(1); - titleTextView.setMaxLines(1); - titleTextView.setSingleLine(true); - titleTextView.setEllipsize(TextUtils.TruncateAt.END); titleTextView.setTextColor(0xffffffff); titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); addView(titleTextView, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP)); @@ -168,17 +158,17 @@ public class ActionBar extends FrameLayout { } } - public TextView getSubTitleTextView() { - return subTitleTextView; + public SimpleTextView getSubtitleTextView() { + return subtitleTextView; } - public TextView getTitleTextView() { + public SimpleTextView getTitleTextView() { return titleTextView; } - +/* public Drawable getSubTitleIcon() { - return subTitleTextView.getCompoundDrawables()[0]; - } + return subtitleTextView.getCompoundDrawables()[0]; + }*/ public String getTitle() { if (titleTextView == null) { @@ -267,8 +257,8 @@ public class ActionBar extends FrameLayout { if (titleTextView != null) { titleTextView.setVisibility(INVISIBLE); } - if (subTitleTextView != null) { - subTitleTextView.setVisibility(INVISIBLE); + if (subtitleTextView != null) { + subtitleTextView.setVisibility(INVISIBLE); } if (menu != null) { menu.setVisibility(INVISIBLE); @@ -284,8 +274,8 @@ public class ActionBar extends FrameLayout { if (titleTextView != null) { titleTextView.setVisibility(INVISIBLE); } - if (subTitleTextView != null) { - subTitleTextView.setVisibility(INVISIBLE); + if (subtitleTextView != null) { + subtitleTextView.setVisibility(INVISIBLE); } if (menu != null) { menu.setVisibility(INVISIBLE); @@ -296,7 +286,7 @@ public class ActionBar extends FrameLayout { if (drawable instanceof BackDrawable) { ((BackDrawable) drawable).setRotation(1, true); } - backButtonImageView.setBackgroundResource(R.drawable.bar_selector_mode); + backButtonImageView.setBackgroundDrawable(Theme.createBarSelectorDrawable(itemsBackgroundColor)); } } @@ -333,8 +323,8 @@ public class ActionBar extends FrameLayout { if (titleTextView != null) { titleTextView.setVisibility(VISIBLE); } - if (subTitleTextView != null) { - subTitleTextView.setVisibility(VISIBLE); + if (subtitleTextView != null) { + subtitleTextView.setVisibility(VISIBLE); } if (menu != null) { menu.setVisibility(VISIBLE); @@ -344,7 +334,7 @@ public class ActionBar extends FrameLayout { if (drawable instanceof BackDrawable) { ((BackDrawable) drawable).setRotation(0, true); } - backButtonImageView.setBackgroundResource(itemsBackgroundResourceId); + backButtonImageView.setBackgroundDrawable(Theme.createBarSelectorDrawable(itemsBackgroundColor)); } } @@ -370,8 +360,8 @@ public class ActionBar extends FrameLayout { if (titleTextView != null) { titleTextView.setVisibility(visible ? INVISIBLE : VISIBLE); } - if (subTitleTextView != null) { - subTitleTextView.setVisibility(visible ? INVISIBLE : VISIBLE); + if (subtitleTextView != null) { + subtitleTextView.setVisibility(visible ? INVISIBLE : VISIBLE); } Drawable drawable = backButtonImageView.getDrawable(); if (drawable != null && drawable instanceof MenuDrawable) { @@ -379,6 +369,14 @@ public class ActionBar extends FrameLayout { } } + public void setInterceptTouches(boolean value) { + interceptTouches = value; + } + + public void setExtraHeight(int value) { + extraHeight = value; + } + public void closeSearchField() { if (!isSearchFieldVisible || menu == null) { return; @@ -400,7 +398,7 @@ public class ActionBar extends FrameLayout { int actionBarHeight = getCurrentActionBarHeight(); int actionBarHeightSpec = MeasureSpec.makeMeasureSpec(actionBarHeight, MeasureSpec.EXACTLY); - setMeasuredDimension(width, actionBarHeight + (occupyStatusBar ? AndroidUtilities.statusBarHeight : 0)); + setMeasuredDimension(width, actionBarHeight + (occupyStatusBar ? AndroidUtilities.statusBarHeight : 0) + extraHeight); int textLeft; if (backButtonImageView != null && backButtonImageView.getVisibility() != GONE) { @@ -420,24 +418,24 @@ public class ActionBar extends FrameLayout { menu.measure(menuWidth, actionBarHeightSpec); } - if (titleTextView != null && titleTextView.getVisibility() != GONE || subTitleTextView != null && subTitleTextView.getVisibility() != GONE) { + if (titleTextView != null && titleTextView.getVisibility() != GONE || subtitleTextView != null && subtitleTextView.getVisibility() != GONE) { int availableWidth = width - (menu != null ? menu.getMeasuredWidth() : 0) - AndroidUtilities.dp(16) - textLeft; if (titleTextView != null && titleTextView.getVisibility() != GONE) { - titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, !AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 18 : 20); - titleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(actionBarHeight, MeasureSpec.AT_MOST)); + titleTextView.setTextSize(!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 18 : 20); + titleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24), MeasureSpec.AT_MOST)); } - if (subTitleTextView != null && subTitleTextView.getVisibility() != GONE) { - subTitleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, !AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 14 : 16); - subTitleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(actionBarHeight, MeasureSpec.AT_MOST)); + if (subtitleTextView != null && subtitleTextView.getVisibility() != GONE) { + subtitleTextView.setTextSize(!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 14 : 16); + subtitleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.AT_MOST)); } } int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); - if (child.getVisibility() == GONE || child == titleTextView || child == subTitleTextView || child == menu || child == backButtonImageView) { + if (child.getVisibility() == GONE || child == titleTextView || child == subtitleTextView || child == menu || child == backButtonImageView) { continue; } measureChildWithMargins(child, widthMeasureSpec, 0, MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY), 0); @@ -461,25 +459,24 @@ public class ActionBar extends FrameLayout { menu.layout(menuLeft, additionalTop, menuLeft + menu.getMeasuredWidth(), additionalTop + menu.getMeasuredHeight()); } - int offset = AndroidUtilities.dp(!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 1 : 2); if (titleTextView != null && titleTextView.getVisibility() != GONE) { int textTop; - if (subTitleTextView != null && subTitleTextView.getVisibility() != GONE) { - textTop = (getCurrentActionBarHeight() / 2 - titleTextView.getMeasuredHeight()) / 2 + offset; + if (subtitleTextView != null && subtitleTextView.getVisibility() != GONE) { + textTop = (getCurrentActionBarHeight() / 2 - titleTextView.getTextHeight()) / 2 + AndroidUtilities.dp(!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 2 : 3); } else { - textTop = (getCurrentActionBarHeight() - titleTextView.getMeasuredHeight()) / 2 - AndroidUtilities.dp(1); + textTop = (getCurrentActionBarHeight() - titleTextView.getTextHeight()) / 2; } - titleTextView.layout(textLeft, additionalTop + textTop, textLeft + titleTextView.getMeasuredWidth(), additionalTop + textTop + titleTextView.getMeasuredHeight()); + titleTextView.layout(textLeft, additionalTop + textTop, textLeft + titleTextView.getMeasuredWidth(), additionalTop + textTop + titleTextView.getTextHeight()); } - if (subTitleTextView != null && subTitleTextView.getVisibility() != GONE) { - int textTop = getCurrentActionBarHeight() / 2 + (getCurrentActionBarHeight() / 2 - subTitleTextView.getMeasuredHeight()) / 2 - offset; - subTitleTextView.layout(textLeft, additionalTop + textTop, textLeft + subTitleTextView.getMeasuredWidth(), additionalTop + textTop + subTitleTextView.getMeasuredHeight()); + if (subtitleTextView != null && subtitleTextView.getVisibility() != GONE) { + int textTop = getCurrentActionBarHeight() / 2 + (getCurrentActionBarHeight() / 2 - subtitleTextView.getTextHeight()) / 2 - AndroidUtilities.dp(!AndroidUtilities.isTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 1 : 1); + subtitleTextView.layout(textLeft, additionalTop + textTop, textLeft + subtitleTextView.getMeasuredWidth(), additionalTop + textTop + subtitleTextView.getTextHeight()); } int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); - if (child.getVisibility() == GONE || child == titleTextView || child == subTitleTextView || child == menu || child == backButtonImageView) { + if (child.getVisibility() == GONE || child == titleTextView || child == subtitleTextView || child == menu || child == backButtonImageView) { continue; } @@ -572,10 +569,10 @@ public class ActionBar extends FrameLayout { return occupyStatusBar; } - public void setItemsBackground(int resourceId) { - itemsBackgroundResourceId = resourceId; + public void setItemsBackgroundColor(int color) { + itemsBackgroundColor = color; if (backButtonImageView != null) { - backButtonImageView.setBackgroundResource(itemsBackgroundResourceId); + backButtonImageView.setBackgroundDrawable(Theme.createBarSelectorDrawable(itemsBackgroundColor)); } setBackgroundColor(AndroidUtilities.getIntColor("themeColor")); //Plus } @@ -590,8 +587,7 @@ public class ActionBar extends FrameLayout { @Override public boolean onTouchEvent(MotionEvent event) { - super.onTouchEvent(event); - return true; + return super.onTouchEvent(event) || interceptTouches; } public static int getCurrentActionBarHeight() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java index a3aa8f87..fbba0c37 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarLayout.java @@ -13,6 +13,7 @@ import android.content.Context; import android.content.Intent; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Handler; @@ -28,11 +29,13 @@ import android.widget.FrameLayout; import android.widget.LinearLayout; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.R; import org.telegram.messenger.AnimationCompat.AnimatorListenerAdapterProxy; import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; import org.telegram.messenger.AnimationCompat.ViewProxy; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.R; import org.telegram.ui.Components.LayoutHelper; import java.util.ArrayList; @@ -49,6 +52,9 @@ public class ActionBarLayout extends FrameLayout { public class LinearLayoutContainer extends LinearLayout { + private Rect rect = new Rect(); + private boolean isKeyboardVisible; + public LinearLayoutContainer(Context context) { super(context); setOrientation(VERTICAL); @@ -86,12 +92,30 @@ public class ActionBarLayout extends FrameLayout { public boolean hasOverlappingRendering() { return false; } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + + View rootView = getRootView(); + getWindowVisibleDisplayFrame(rect); + int usableViewHeight = rootView.getHeight() - (rect.top != 0 ? AndroidUtilities.statusBarHeight : 0) - AndroidUtilities.getViewInset(rootView); + isKeyboardVisible = usableViewHeight - (rect.bottom - rect.top) > 0; + if (BuildVars.DEBUG_VERSION) { + FileLog.e("tmessages", "keyboard visible = " + isKeyboardVisible + " for " + this); + } + if (waitingForKeyboardCloseRunnable != null && !containerView.isKeyboardVisible && !containerViewBack.isKeyboardVisible) { + AndroidUtilities.cancelRunOnUIThread(waitingForKeyboardCloseRunnable); + waitingForKeyboardCloseRunnable.run(); + waitingForKeyboardCloseRunnable = null; + } + } } private static Drawable headerShadowDrawable; private static Drawable layerShadowDrawable; private static Paint scrimPaint; - + private Runnable waitingForKeyboardCloseRunnable; private LinearLayoutContainer containerView; private LinearLayoutContainer containerViewBack; private DrawerLayoutContainer drawerLayoutContainer; @@ -248,7 +272,7 @@ public class ActionBarLayout extends FrameLayout { } final int restoreCount = canvas.save(); - if (!transitionAnimationInProgress && clipLeft != 0 && clipRight != 0) { + if (!transitionAnimationInProgress) { canvas.clipRect(clipLeft, 0, clipRight, getHeight()); } final boolean result = super.drawChild(canvas, child, drawingTime); @@ -427,7 +451,7 @@ public class ActionBarLayout extends FrameLayout { distToMove = containerView.getMeasuredWidth() - x; animatorSet.playTogether( ObjectAnimatorProxy.ofFloat(containerView, "translationX", containerView.getMeasuredWidth()), - ObjectAnimatorProxy.ofFloat(this, "innerTranslationX", (float)containerView.getMeasuredWidth()) + ObjectAnimatorProxy.ofFloat(this, "innerTranslationX", (float) containerView.getMeasuredWidth()) ); } else { distToMove = x; @@ -443,11 +467,6 @@ public class ActionBarLayout extends FrameLayout { public void onAnimationEnd(Object animator) { onSlideAnimationEnd(backAnimation); } - - @Override - public void onAnimationCancel(Object animator) { - onSlideAnimationEnd(backAnimation); - } }); animatorSet.start(); animationInProgress = true; @@ -498,6 +517,10 @@ public class ActionBarLayout extends FrameLayout { private void onAnimationEndCheck(boolean byCheck) { onCloseAnimationEnd(false); onOpenAnimationEnd(false); + if (waitingForKeyboardCloseRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(waitingForKeyboardCloseRunnable); + waitingForKeyboardCloseRunnable = null; + } if (currentAnimation != null) { if (byCheck) { currentAnimation.cancel(); @@ -518,7 +541,7 @@ public class ActionBarLayout extends FrameLayout { } public boolean checkTransitionAnimation() { - if (transitionAnimationInProgress && transitionAnimationStartTime < System.currentTimeMillis() - 1000) { + if (transitionAnimationInProgress && transitionAnimationStartTime < System.currentTimeMillis() - 1500) { onAnimationEndCheck(true); } return transitionAnimationInProgress; @@ -693,11 +716,6 @@ public class ActionBarLayout extends FrameLayout { public void onAnimationEnd(Object animation) { onAnimationEndCheck(false); } - - @Override - public void onAnimationCancel(Object animation) { - onAnimationEndCheck(false); - } }); currentAnimation.start(); } else { @@ -716,6 +734,7 @@ public class ActionBarLayout extends FrameLayout { ViewProxy.setTranslationX(containerView, 0); } }; + FileLog.e("tmessages", "onOpenAnimationsStart"); fragment.onTransitionAnimationStart(true, false); AnimatorSetProxy animation = fragment.onCustomTransitionAnimation(true, new Runnable() { @Override @@ -726,7 +745,21 @@ public class ActionBarLayout extends FrameLayout { if (animation == null) { ViewProxy.setAlpha(containerView, 0.0f); ViewProxy.setTranslationX(containerView, 48.0f); - startLayoutAnimation(true, true); + if (containerView.isKeyboardVisible || containerViewBack.isKeyboardVisible) { + waitingForKeyboardCloseRunnable = new Runnable() { + @Override + public void run() { + FileLog.e("tmessages", "start delayed by keyboard open animation"); + if (waitingForKeyboardCloseRunnable != this) { + return; + } + startLayoutAnimation(true, true); + } + }; + AndroidUtilities.runOnUIThread(waitingForKeyboardCloseRunnable, 200); + } else { + startLayoutAnimation(true, true); + } } else { if (Build.VERSION.SDK_INT > 15) { //containerView.setLayerType(LAYER_TYPE_HARDWARE, null); @@ -838,6 +871,7 @@ public class ActionBarLayout extends FrameLayout { layoutParams.width = LayoutHelper.MATCH_PARENT; layoutParams.height = LayoutHelper.MATCH_PARENT; fragmentView.setLayoutParams(layoutParams); + FileLog.e("tmessages", "onCloseAnimationStart"); previousFragment.onTransitionAnimationStart(true, true); currentFragment.onTransitionAnimationStart(false, false); previousFragment.onResume(); @@ -875,7 +909,21 @@ public class ActionBarLayout extends FrameLayout { } }); if (animation == null) { - startLayoutAnimation(false, true); + if (containerView.isKeyboardVisible || containerViewBack.isKeyboardVisible) { + waitingForKeyboardCloseRunnable = new Runnable() { + @Override + public void run() { + if (waitingForKeyboardCloseRunnable != this) { + return; + } + FileLog.e("tmessages", "start delayed by keyboard close animation"); + startLayoutAnimation(false, true); + } + }; + AndroidUtilities.runOnUIThread(waitingForKeyboardCloseRunnable, 200); + } else { + startLayoutAnimation(false, true); + } } else { if (Build.VERSION.SDK_INT > 15) { //containerView.setLayerType(LAYER_TYPE_HARDWARE, null); @@ -927,12 +975,8 @@ public class ActionBarLayout extends FrameLayout { public void onAnimationEnd(Object animation) { onAnimationEndCheck(false); } - - @Override - public void onAnimationCancel(Object animation) { - onAnimationEndCheck(false); - } }); + FileLog.e("tmessages", "onCloseAnimationsStart"); currentAnimation.start(); } else { removeFragmentFromStackInternal(currentFragment); @@ -1058,11 +1102,13 @@ public class ActionBarLayout extends FrameLayout { if (post) { new Handler().post(new Runnable() { public void run() { + FileLog.e("tmessages", "onCloseAnimationEnd"); onCloseAnimationEndRunnable.run(); onCloseAnimationEndRunnable = null; } }); } else { + FileLog.e("tmessages", "onCloseAnimationEnd"); onCloseAnimationEndRunnable.run(); onCloseAnimationEndRunnable = null; } @@ -1076,11 +1122,13 @@ public class ActionBarLayout extends FrameLayout { if (post) { new Handler().post(new Runnable() { public void run() { + FileLog.e("tmessages", "onOpenAnimationEnd"); onOpenAnimationEndRunnable.run(); onOpenAnimationEndRunnable = null; } }); } else { + FileLog.e("tmessages", "onOpenAnimationEnd"); onOpenAnimationEndRunnable.run(); onOpenAnimationEndRunnable = null; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java index 7a4ab56a..0c021251 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenu.java @@ -38,7 +38,7 @@ public class ActionBarMenu extends LinearLayout { addView(view); LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) view.getLayoutParams(); layoutParams.height = LayoutHelper.MATCH_PARENT; - view.setBackgroundResource(parentActionBar.itemsBackgroundResourceId); + view.setBackgroundDrawable(Theme.createBarSelectorDrawable(parentActionBar.itemsBackgroundColor)); view.setLayoutParams(layoutParams); view.setOnClickListener(new OnClickListener() { @Override @@ -50,27 +50,27 @@ public class ActionBarMenu extends LinearLayout { } public ActionBarMenuItem addItem(int id, Drawable drawable) { - return addItem(id, 0, parentActionBar.itemsBackgroundResourceId, drawable, AndroidUtilities.dp(48)); + return addItem(id, 0, parentActionBar.itemsBackgroundColor, drawable, AndroidUtilities.dp(48)); } public ActionBarMenuItem addItem(int id, int icon) { - return addItem(id, icon, parentActionBar.itemsBackgroundResourceId); + return addItem(id, icon, parentActionBar.itemsBackgroundColor); } - public ActionBarMenuItem addItem(int id, int icon, int backgroundResource) { - return addItem(id, icon, backgroundResource, null, AndroidUtilities.dp(48)); + public ActionBarMenuItem addItem(int id, int icon, int backgroundColor) { + return addItem(id, icon, backgroundColor, null, AndroidUtilities.dp(48)); } public ActionBarMenuItem addItemWithWidth(int id, int icon, int width) { - return addItem(id, icon, parentActionBar.itemsBackgroundResourceId, null, width); + return addItem(id, icon, parentActionBar.itemsBackgroundColor, null, width); } public ActionBarMenuItem addItemWithWidth(int id, Drawable icon, int width) { - return addItem(id, 0, parentActionBar.itemsBackgroundResourceId, icon, width); + return addItem(id, 0, parentActionBar.itemsBackgroundColor, icon, width); } - public ActionBarMenuItem addItem(int id, int icon, int backgroundResource, Drawable drawable, int width) { - ActionBarMenuItem menuItem = new ActionBarMenuItem(getContext(), this, backgroundResource); + public ActionBarMenuItem addItem(int id, int icon, int backgroundColor, Drawable drawable, int width) { + ActionBarMenuItem menuItem = new ActionBarMenuItem(getContext(), this, backgroundColor); menuItem.setTag(id); if (drawable != null) { menuItem.iconView.setImageDrawable(drawable); @@ -116,10 +116,7 @@ public class ActionBarMenu extends LinearLayout { } public void clearItems() { - for (int a = 0; a < getChildCount(); a++) { - View view = getChildAt(a); - removeView(view); - } + removeAllViews(); } public void onMenuButtonPressed() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java index 10d81a05..9b93092e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/ActionBarMenuItem.java @@ -9,6 +9,7 @@ package org.telegram.ui.ActionBar; import android.content.Context; +import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; @@ -86,9 +87,11 @@ public class ActionBarMenuItem extends FrameLayoutFixed { protected boolean overrideMenuClick; private boolean processedPopupClick; - public ActionBarMenuItem(Context context, ActionBarMenu menu, int background) { + public ActionBarMenuItem(Context context, ActionBarMenu menu, int backgroundColor) { super(context); - setBackgroundResource(background); + if (backgroundColor != 0) { + setBackgroundDrawable(Theme.createBarSelectorDrawable(backgroundColor)); + } parentMenu = menu; iconView = new ImageView(context); @@ -371,6 +374,10 @@ public class ActionBarMenuItem extends FrameLayoutFixed { iconView.setImageDrawable(drawable); } + public void setIconColor(int color){ + iconView.setColorFilter(color, PorterDuff.Mode.SRC_IN); + } +// public EditText getSearchField() { return searchField; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BackDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BackDrawable.java new file mode 100644 index 00000000..7ff727f9 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BackDrawable.java @@ -0,0 +1,136 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.ActionBar; + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; +import android.view.animation.DecelerateInterpolator; + +import org.telegram.messenger.AndroidUtilities; + +public class BackDrawable extends Drawable { + + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint paintB = new Paint(Paint.ANTI_ALIAS_FLAG); + private boolean reverseAngle = false; + private long lastFrameTime; + private boolean animationInProgress; + private float finalRotation; + private float currentRotation; + private int currentAnimationTime; + private boolean alwaysClose; + private DecelerateInterpolator interpolator = new DecelerateInterpolator(); + + public BackDrawable(boolean close) { + super(); + paint.setColor(0xffffffff); + paint.setStrokeWidth(AndroidUtilities.dp(2)); + alwaysClose = close; + } + + public void setRotation(float rotation, boolean animated) { + lastFrameTime = 0; + if (currentRotation == 1) { + reverseAngle = true; + } else if (currentRotation == 0) { + reverseAngle = false; + } + lastFrameTime = 0; + if (animated) { + if (currentRotation < rotation) { + currentAnimationTime = (int) (currentRotation * 300); + } else { + currentAnimationTime = (int) ((1.0f - currentRotation) * 300); + } + lastFrameTime = System.currentTimeMillis(); + finalRotation = rotation; + } else { + finalRotation = currentRotation = rotation; + } + invalidateSelf(); + } + + @Override + public void draw(Canvas canvas) { + if (currentRotation != finalRotation) { + if (lastFrameTime != 0) { + long dt = System.currentTimeMillis() - lastFrameTime; + + currentAnimationTime += dt; + if (currentAnimationTime >= 300) { + currentRotation = finalRotation; + } else { + if (currentRotation < finalRotation) { + currentRotation = interpolator.getInterpolation(currentAnimationTime / 300.0f) * finalRotation; + } else { + currentRotation = 1.0f - interpolator.getInterpolation(currentAnimationTime / 300.0f); + } + } + } + lastFrameTime = System.currentTimeMillis(); + invalidateSelf(); + } + + int rD = (int) ((117 - 255) * currentRotation); + int c = Color.rgb(255 + rD, 255 + rD, 255 + rD); + paint.setColor(c); + if(currentRotation < 1)paint.setColor(paintB.getColor()); + canvas.save(); + canvas.translate(getIntrinsicWidth() / 2, getIntrinsicHeight() / 2); + float rotation = currentRotation; + if (!alwaysClose) { + canvas.rotate(currentRotation * (reverseAngle ? -225 : 135)); + } else { + canvas.rotate(135 + currentRotation * (reverseAngle ? -180 : 180)); + rotation = 1.0f; + } + canvas.drawLine(-AndroidUtilities.dp(7) - AndroidUtilities.dp(1) * rotation, 0, AndroidUtilities.dp(8), 0, paint); + float startYDiff = -AndroidUtilities.dp(0.5f); + float endYDiff = AndroidUtilities.dp(7) + AndroidUtilities.dp(1) * rotation; + float startXDiff = -AndroidUtilities.dp(7.0f) + AndroidUtilities.dp(7.0f) * rotation; + float endXDiff = AndroidUtilities.dp(0.5f) - AndroidUtilities.dp(0.5f) * rotation; + canvas.drawLine(startXDiff, -startYDiff, endXDiff, -endYDiff, paint); + canvas.drawLine(startXDiff, startYDiff, endXDiff, endYDiff, paint); + canvas.restore(); + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(ColorFilter cf) { + + } + //Plus + public void setColor(int color) { + paint.setColor(color); + paintB.setColor(color); + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + + @Override + public int getIntrinsicWidth() { + return AndroidUtilities.dp(24); + } + + @Override + public int getIntrinsicHeight() { + return AndroidUtilities.dp(24); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java index 18de8364..2d17e26d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BaseFragment.java @@ -122,15 +122,21 @@ public class BaseFragment { } } if (parentLayout != null && actionBar == null) { - actionBar = new ActionBar(parentLayout.getContext()); + actionBar = createActionBar(parentLayout.getContext()); actionBar.parentFragment = this; - //actionBar.setBackgroundColor(0xff54759e); - actionBar.setBackgroundResource(R.color.header); //Plus - actionBar.setItemsBackground(R.drawable.bar_selector); } } } + protected ActionBar createActionBar(Context context) { + ActionBar actionBar = new ActionBar(context); + actionBar.setBackgroundColor(Theme.ACTION_BAR_COLOR); + actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_SELECTOR_COLOR); + actionBar.setBackgroundResource(R.color.header); //Plus + //actionBar.setItemsBackground(R.drawable.bar_selector); + return actionBar; + } + public void finishFragment() { finishFragment(true); } @@ -296,6 +302,7 @@ public class BaseFragment { } }); visibleDialog.show(); + //Log.e("BaseFragment","showDialog " + allowInTransition); //Always after .show() SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); int color = preferences.getInt("dialogColor", preferences.getInt("themeColor", AndroidUtilities.defColor)); @@ -312,6 +319,19 @@ public class BaseFragment { if(btn != null)btn.setTextColor(color); btn = (Button) visibleDialog.findViewById(android.R.id.button3); if(btn != null)btn.setTextColor(color); + int bgColor = preferences.getInt("prefBGColor", 0xffffffff); + //dialog.getWindow().setBackgroundDrawableResource(android.R.color.background_dark); + /*visibleDialog.getWindow().setBackgroundDrawable(new ColorDrawable(bgColor)); + int tColor = preferences.getInt("prefTitleColor", 0xff212121); + tColor = 0xffff0000; + tv = (TextView) visibleDialog.findViewById(android.R.id.text1); + if(tv != null)tv.setTextColor(tColor); + tv = (TextView) visibleDialog.findViewById(android.R.id.text2); + if(tv != null)tv.setTextColor(tColor); + id = visibleDialog.getContext().getResources().getIdentifier("android:id/message", null, null); + tv = (TextView) visibleDialog.findViewById(id); + if(tv != null)tv.setTextColor(tColor);*/ + // return visibleDialog; } catch (Exception e) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java new file mode 100644 index 00000000..056bf7ff --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/BottomSheet.java @@ -0,0 +1,867 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.ActionBar; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewAnimationUtils; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowInsets; +import android.view.WindowManager; +import android.view.animation.AccelerateInterpolator; +import android.view.animation.DecelerateInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.AnimationCompat.AnimatorListenerAdapterProxy; +import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; +import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; +import org.telegram.messenger.AnimationCompat.ViewProxy; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.R; +import org.telegram.ui.Components.LayoutHelper; + +import java.util.ArrayList; + +public class BottomSheet extends Dialog { + + private LinearLayout containerView; + private FrameLayout container; + private WindowInsets lastInsets; + + private boolean dismissed; + private int tag; + + private boolean disableBackground; + + private DialogInterface.OnClickListener onClickListener; + + private CharSequence[] items; + private int[] itemIcons; + private View customView; + private CharSequence title; + private boolean fullWidth; + private boolean isGrid; + private ColorDrawable backgroundDrawable = new ColorDrawable(0xff000000); + + private boolean focusable; + + private Paint ciclePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + private Drawable shadowDrawable; + protected static int backgroundPaddingTop; + protected static int backgroundPaddingLeft; + + private boolean useRevealAnimation; + private float revealRadius; + private int revealX; + private int revealY; + private boolean applyTopPadding = true; + private boolean applyBottomPadding = true; + + private DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(); + private AccelerateInterpolator accelerateInterpolator = new AccelerateInterpolator(); + + private ArrayList itemViews = new ArrayList<>(); + + private BottomSheetDelegateInterface delegate; + + public interface BottomSheetDelegateInterface { + void onOpenAnimationStart(); + + void onOpenAnimationEnd(); + + void onRevealAnimationStart(boolean open); + + void onRevealAnimationEnd(boolean open); + + void onRevealAnimationProgress(boolean open, float radius, int x, int y); + + View getRevealView(); + } + + public static class BottomSheetDelegate implements BottomSheetDelegateInterface { + @Override + public void onOpenAnimationStart() { + + } + + @Override + public void onOpenAnimationEnd() { + + } + + @Override + public void onRevealAnimationStart(boolean open) { + + } + + @Override + public void onRevealAnimationEnd(boolean open) { + + } + + @Override + public void onRevealAnimationProgress(boolean open, float radius, int x, int y) { + + } + + @Override + public View getRevealView() { + return null; + } + } + + public static class BottomSheetCell extends FrameLayout { + + private TextView textView; + private ImageView imageView; + private boolean isGrid; + + public BottomSheetCell(Context context, int type) { + super(context); + isGrid = type == 1; + + setBackgroundResource(R.drawable.list_selector); + if (type != 1) { + setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), 0); + } + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + if (type == 1) { + addView(imageView, LayoutHelper.createFrame(48, 48, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 0, 8, 0, 0)); + } else { + addView(imageView, LayoutHelper.createFrame(24, 24, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT))); + } + + textView = new TextView(context); + textView.setLines(1); + textView.setSingleLine(true); + textView.setGravity(Gravity.CENTER_HORIZONTAL); + textView.setEllipsize(TextUtils.TruncateAt.END); + if (type == 1) { + textView.setTextColor(0xff757575); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 0, 60, 0, 0)); + } else if (type == 0) { + textView.setTextColor(0xff212121); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL)); + } else if (type == 2) { + textView.setGravity(Gravity.CENTER); + textView.setTextColor(0xff212121); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(isGrid ? MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(96), MeasureSpec.EXACTLY) : widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(isGrid ? 80 : 48), MeasureSpec.EXACTLY)); + } + + public void setTextColor(int color) { + textView.setTextColor(color); + } + + public void setGravity(int gravity) { + textView.setGravity(gravity); + } + + public void setTextAndIcon(CharSequence text, int icon) { + textView.setText(text); + if (icon != 0) { + imageView.setImageResource(icon); + imageView.setVisibility(VISIBLE); + if (!isGrid) { + textView.setPadding(LocaleController.isRTL ? 0 : AndroidUtilities.dp(56), 0, LocaleController.isRTL ? AndroidUtilities.dp(56) : 0, 0); + } + } else { + imageView.setVisibility(INVISIBLE); + textView.setPadding(0, 0, 0, 0); + } + } + } + + public BottomSheet(Context context, boolean needFocus) { + super(context, R.style.TransparentDialog); + + if (Build.VERSION.SDK_INT >= 21 && !"N".equals(Build.VERSION.CODENAME)) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + } + + Rect padding = new Rect(); + shadowDrawable = context.getResources().getDrawable(R.drawable.sheet_shadow); + shadowDrawable.getPadding(padding); + backgroundPaddingLeft = padding.left; + backgroundPaddingTop = padding.top; + + container = new FrameLayout(getContext()) { + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = MeasureSpec.getSize(widthMeasureSpec); + int height = MeasureSpec.getSize(heightMeasureSpec); + if (lastInsets != null && Build.VERSION.SDK_INT >= 21) { + width -= lastInsets.getSystemWindowInsetRight() + lastInsets.getSystemWindowInsetLeft(); + } + setMeasuredDimension(width, height); + boolean isPortrait = width < height; + + if (containerView != null) { + int left = useRevealAnimation && Build.VERSION.SDK_INT <= 19 ? 0 : backgroundPaddingLeft; + if (!fullWidth) { + int widthSpec; + if (AndroidUtilities.isTablet()) { + widthSpec = MeasureSpec.makeMeasureSpec((int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.8f) + left * 2, MeasureSpec.EXACTLY); + } else { + widthSpec = MeasureSpec.makeMeasureSpec(isPortrait ? width + left * 2 : (int) Math.max(width * 0.8f, Math.min(AndroidUtilities.dp(480), width)) + left * 2, MeasureSpec.EXACTLY); + } + if (lastInsets != null && Build.VERSION.SDK_INT >= 21 && focusable) { + containerView.getLayoutParams(); + containerView.measure(widthSpec, MeasureSpec.makeMeasureSpec(height - lastInsets.getSystemWindowInsetBottom(), MeasureSpec.AT_MOST)); + } else { + containerView.measure(widthSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); + } + } else { + containerView.measure(MeasureSpec.makeMeasureSpec(width + left * 2, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); + } + } + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + if (child.getVisibility() == GONE || child == containerView) { + continue; + } + + measureChildWithMargins(child, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), 0, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY), 0); + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + if (containerView != null) { + + int t = (bottom - top) - containerView.getMeasuredHeight(); + if (lastInsets != null && Build.VERSION.SDK_INT >= 21) { + left += lastInsets.getSystemWindowInsetLeft(); + right += lastInsets.getSystemWindowInsetLeft(); + if (focusable) { + t -= lastInsets.getSystemWindowInsetBottom(); + } + } + int l = ((right - left) - containerView.getMeasuredWidth()) / 2; + containerView.layout(l, t, l + containerView.getMeasuredWidth(), t + getMeasuredHeight()); + } + + final int count = getChildCount(); + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (child.getVisibility() == GONE || child == containerView) { + continue; + } + final FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) child.getLayoutParams(); + + final int width = child.getMeasuredWidth(); + final int height = child.getMeasuredHeight(); + + int childLeft; + int childTop; + + int gravity = lp.gravity; + if (gravity == -1) { + gravity = Gravity.TOP | Gravity.LEFT; + } + + final int absoluteGravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK; + final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK; + + switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) { + case Gravity.CENTER_HORIZONTAL: + childLeft = (right - left - width) / 2 + lp.leftMargin - lp.rightMargin; + break; + case Gravity.RIGHT: + childLeft = right - width - lp.rightMargin; + break; + case Gravity.LEFT: + default: + childLeft = lp.leftMargin; + } + + switch (verticalGravity) { + case Gravity.TOP: + childTop = lp.topMargin; + break; + case Gravity.CENTER_VERTICAL: + childTop = (bottom - top - height) / 2 + lp.topMargin - lp.bottomMargin; + break; + case Gravity.BOTTOM: + childTop = (bottom - top) - height - lp.bottomMargin; + break; + default: + childTop = lp.topMargin; + } + child.layout(childLeft, childTop, childLeft + width, childTop + height); + } + } + }; + container.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + dismiss(); + return false; + } + }); + container.setBackgroundDrawable(backgroundDrawable); + focusable = needFocus; + if (Build.VERSION.SDK_INT >= 21 && !"N".equals(Build.VERSION.CODENAME)) { + container.setFitsSystemWindows(true); + container.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() { + @SuppressLint("NewApi") + @Override + public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { + lastInsets = insets; + v.requestLayout(); + return insets.consumeSystemWindowInsets(); + } + }); + container.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Window window = getWindow(); + window.setWindowAnimations(R.style.DialogNoAnimation); + setContentView(container, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + + ciclePaint.setColor(0xffffffff); + + containerView = new LinearLayout(getContext()) { + + @Override + protected void onDraw(Canvas canvas) { + if (useRevealAnimation && Build.VERSION.SDK_INT <= 19) { + canvas.drawCircle(revealX, revealY, revealRadius, ciclePaint); + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + return super.drawChild(canvas, child, drawingTime); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + FileLog.e("tmessages", "container on layout"); + } + }; + if (Build.VERSION.SDK_INT >= 21) { + containerView.setFitsSystemWindows(true); + } + containerView.setVisibility(View.INVISIBLE); + backgroundDrawable.setAlpha(0); + containerView.setWillNotDraw(false); + containerView.setOrientation(LinearLayout.VERTICAL); + container.addView(containerView, 0, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM)); + + if (title != null) { + TextView titleView = new TextView(getContext()); + titleView.setLines(1); + titleView.setSingleLine(true); + titleView.setText(title); + titleView.setTextColor(0xff757575); + titleView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + titleView.setEllipsize(TextUtils.TruncateAt.MIDDLE); + titleView.setPadding(AndroidUtilities.dp(16), 0, AndroidUtilities.dp(16), AndroidUtilities.dp(8)); + titleView.setGravity(Gravity.CENTER_VERTICAL); + containerView.addView(titleView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + titleView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + } + + if (customView != null) { + if (customView.getParent() != null) { + ViewGroup viewGroup = (ViewGroup) customView.getParent(); + viewGroup.removeView(customView); + } + containerView.addView(customView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + + if (items != null) { + if (customView != null) { + FrameLayout frameLayout = new FrameLayout(getContext()); + frameLayout.setPadding(0, AndroidUtilities.dp(8), 0, 0); + containerView.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 16)); + + View lineView = new View(getContext()); + lineView.setBackgroundColor(0xffd2d2d2); + frameLayout.addView(lineView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1)); + } + FrameLayout rowLayout = null; + int lastRowLayoutNum = 0; + for (int a = 0; a < items.length; a++) { + BottomSheetCell cell = new BottomSheetCell(getContext(), isGrid ? 1 : 0); + cell.setTextAndIcon(items[a], itemIcons != null ? itemIcons[a] : 0); + if (isGrid) { + int row = a / 3; + if (rowLayout == null || lastRowLayoutNum != row) { + rowLayout = new FrameLayout(getContext()); + lastRowLayoutNum = row; + containerView.addView(rowLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 80, 0, lastRowLayoutNum != 0 ? 8 : 0, 0, 0)); + rowLayout.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + } + int col = a % 3; + int gravity; + if (col == 0) { + gravity = Gravity.LEFT | Gravity.TOP; + } else if (col == 1) { + gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; + } else { + gravity = Gravity.RIGHT | Gravity.TOP; + } + rowLayout.addView(cell, LayoutHelper.createFrame(96, 80, gravity)); + } else { + containerView.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + } + cell.setTag(a); + cell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismissWithButtonClick((Integer) v.getTag()); + } + }); + itemViews.add(cell); + } + } + + WindowManager.LayoutParams params = window.getAttributes(); + params.width = ViewGroup.LayoutParams.MATCH_PARENT; + params.gravity = Gravity.TOP | Gravity.LEFT; + params.dimAmount = 0; + params.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND; + if (!focusable) { + params.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM; + } + if (Build.VERSION.SDK_INT < 21) { + params.height = ViewGroup.LayoutParams.MATCH_PARENT; + } + window.setAttributes(params); + } + + @Override + public void show() { + super.show(); + if (focusable) { + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + } + dismissed = false; + if ((Build.VERSION.SDK_INT >= 21 || !useRevealAnimation) && !disableBackground) { + containerView.setBackgroundDrawable(shadowDrawable); + } else { + containerView.setBackgroundDrawable(null); + } + int left = useRevealAnimation && Build.VERSION.SDK_INT <= 19 || disableBackground ? 0 : backgroundPaddingLeft; + int top = useRevealAnimation && Build.VERSION.SDK_INT <= 19 || disableBackground ? 0 : backgroundPaddingTop; + containerView.setPadding(left, (applyTopPadding ? AndroidUtilities.dp(8) : 0) + top, left, (applyBottomPadding ? AndroidUtilities.dp(isGrid ? 16 : 8) : 0)); + if (Build.VERSION.SDK_INT >= 21) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + startOpenAnimation(); + } + }); + } else { + startOpenAnimation(); + } + } + + public void setCustomView(View view) { + customView = view; + } + + public void setTitle(CharSequence value) { + title = value; + } + + public void setApplyTopPadding(boolean value) { + applyTopPadding = value; + } + + public void setApplyBottomPadding(boolean value) { + applyBottomPadding = value; + } + + public void setDisableBackground(boolean value) { + disableBackground = value; + } + + protected void setRevealRadius(float radius) { + revealRadius = radius; + delegate.onRevealAnimationProgress(!dismissed, radius, revealX, revealY); + if (Build.VERSION.SDK_INT <= 19) { + containerView.invalidate(); + } + } + + protected float getRevealRadius() { + return revealRadius; + } + + @SuppressLint("NewApi") + private void startRevealAnimation(final boolean open) { + ViewProxy.setTranslationY(containerView, 0); + + final AnimatorSet animatorSet = new AnimatorSet(); + + View view = delegate.getRevealView(); + if (view.getVisibility() == View.VISIBLE && ((ViewGroup) view.getParent()).getVisibility() == View.VISIBLE) { + final int coords[] = new int[2]; + view.getLocationInWindow(coords); + float top; + if (Build.VERSION.SDK_INT <= 19) { + top = AndroidUtilities.displaySize.y - containerView.getMeasuredHeight() - AndroidUtilities.statusBarHeight; + } else { + top = containerView.getY(); + } + revealX = coords[0] + view.getMeasuredWidth() / 2; + revealY = (int) (coords[1] + view.getMeasuredHeight() / 2 - top); + if (Build.VERSION.SDK_INT <= 19) { + revealY -= AndroidUtilities.statusBarHeight; + } + } else { + revealX = AndroidUtilities.displaySize.x / 2 + backgroundPaddingLeft; + revealY = (int) (AndroidUtilities.displaySize.y - containerView.getY()); + } + + int corners[][] = new int[][]{ + {0, 0}, + {0, containerView.getMeasuredHeight()}, + {containerView.getMeasuredWidth(), 0}, + {containerView.getMeasuredWidth(), containerView.getMeasuredHeight()} + }; + int finalRevealRadius = 0; + for (int a = 0; a < 4; a++) { + finalRevealRadius = Math.max(finalRevealRadius, (int) Math.ceil(Math.sqrt((revealX - corners[a][0]) * (revealX - corners[a][0]) + (revealY - corners[a][1]) * (revealY - corners[a][1])))); + } + + int finalRevealX = revealX <= containerView.getMeasuredWidth() ? revealX : containerView.getMeasuredWidth(); + + ArrayList animators = new ArrayList<>(3); + animators.add(ObjectAnimator.ofFloat(this, "revealRadius", open ? 0 : finalRevealRadius, open ? finalRevealRadius : 0)); + animators.add(ObjectAnimator.ofInt(backgroundDrawable, "alpha", open ? 51 : 0)); + if (Build.VERSION.SDK_INT >= 21) { + containerView.setElevation(AndroidUtilities.dp(10)); + try { + animators.add(ViewAnimationUtils.createCircularReveal(containerView, finalRevealX, revealY, open ? 0 : finalRevealRadius, open ? finalRevealRadius : 0)); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + animatorSet.setDuration(300); + } else { + if (!open) { + animatorSet.setDuration(200); + containerView.setPivotX(revealX <= containerView.getMeasuredWidth() ? revealX : containerView.getMeasuredWidth()); + containerView.setPivotY(revealY); + animators.add(ObjectAnimator.ofFloat(containerView, "scaleX", 0.0f)); + animators.add(ObjectAnimator.ofFloat(containerView, "scaleY", 0.0f)); + animators.add(ObjectAnimator.ofFloat(containerView, "alpha", 0.0f)); + } else { + animatorSet.setDuration(250); + containerView.setScaleX(1); + containerView.setScaleY(1); + containerView.setAlpha(1); + if (Build.VERSION.SDK_INT <= 19) { + animatorSet.setStartDelay(20); + } + } + } + animatorSet.playTogether(animators); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + if (delegate != null) { + delegate.onRevealAnimationStart(open); + } + } + + @Override + public void onAnimationEnd(Animator animation) { + if (delegate != null) { + delegate.onRevealAnimationEnd(open); + } + containerView.invalidate(); + if (Build.VERSION.SDK_INT >= 11) { + containerView.setLayerType(View.LAYER_TYPE_NONE, null); + } + if (!open) { + containerView.setVisibility(View.INVISIBLE); + try { + BottomSheet.super.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + }); + animatorSet.start(); + } + + private void startOpenAnimation() { + + if (containerView.getMeasuredHeight() == 0) { + containerView.measure(View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.x, View.MeasureSpec.AT_MOST), View.MeasureSpec.makeMeasureSpec(AndroidUtilities.displaySize.y, View.MeasureSpec.AT_MOST)); + } + backgroundDrawable.setAlpha(0); + containerView.setVisibility(View.VISIBLE); + if (useRevealAnimation) { + if (Build.VERSION.SDK_INT >= 20) { + containerView.setLayerType(View.LAYER_TYPE_HARDWARE, null); + } + startRevealAnimation(true); + } else { + if (Build.VERSION.SDK_INT >= 20) { + container.setLayerType(View.LAYER_TYPE_HARDWARE, null); + } + ViewProxy.setTranslationY(containerView, containerView.getMeasuredHeight()); + backgroundDrawable.setAlpha(0); + AnimatorSetProxy animatorSetProxy = new AnimatorSetProxy(); + animatorSetProxy.playTogether( + ObjectAnimatorProxy.ofFloat(containerView, "translationY", 0), + ObjectAnimatorProxy.ofInt(backgroundDrawable, "alpha", 51)); + animatorSetProxy.setDuration(200); + animatorSetProxy.setStartDelay(20); + animatorSetProxy.setInterpolator(new DecelerateInterpolator()); + animatorSetProxy.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if (delegate != null) { + delegate.onOpenAnimationEnd(); + } + if (Build.VERSION.SDK_INT >= 11) { + container.setLayerType(View.LAYER_TYPE_NONE, null); + } + } + }); + animatorSetProxy.start(); + } + } + + public void setDelegate(BottomSheetDelegate delegate) { + this.delegate = delegate; + } + + public FrameLayout getContainer() { + return container; + } + + public LinearLayout getSheetContainer() { + return containerView; + } + + public int getTag() { + return tag; + } + + public void setItemText(int item, CharSequence text) { + if (item < 0 || item >= itemViews.size()) { + return; + } + BottomSheetCell cell = itemViews.get(item); + cell.textView.setText(text); + } + + public void dismissWithButtonClick(final int item) { + if (dismissed) { + return; + } + dismissed = true; + AnimatorSetProxy animatorSetProxy = new AnimatorSetProxy(); + animatorSetProxy.playTogether( + ObjectAnimatorProxy.ofFloat(containerView, "translationY", containerView.getMeasuredHeight() + AndroidUtilities.dp(10)), + ObjectAnimatorProxy.ofInt(backgroundDrawable, "alpha", 0) + ); + animatorSetProxy.setDuration(180); + animatorSetProxy.setInterpolator(new AccelerateInterpolator()); + animatorSetProxy.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if (onClickListener != null) { + onClickListener.onClick(BottomSheet.this, item); + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + BottomSheet.super.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + }); + animatorSetProxy.start(); + } + + @Override + public void dismiss() { + if (dismissed) { + return; + } + dismissed = true; + if (useRevealAnimation) { + backgroundDrawable.setAlpha(51); + startRevealAnimation(false); + } else { + AnimatorSetProxy animatorSetProxy = new AnimatorSetProxy(); + animatorSetProxy.playTogether( + ObjectAnimatorProxy.ofFloat(containerView, "translationY", containerView.getMeasuredHeight() + AndroidUtilities.dp(10)), + ObjectAnimatorProxy.ofInt(backgroundDrawable, "alpha", 0) + ); + animatorSetProxy.setDuration(180); + animatorSetProxy.setInterpolator(new AccelerateInterpolator()); + animatorSetProxy.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + BottomSheet.super.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + }); + animatorSetProxy.start(); + } + } + + public static class Builder { + + private BottomSheet bottomSheet; + + public Builder(Context context) { + bottomSheet = new BottomSheet(context, false); + } + + public Builder(Context context, boolean needFocus) { + bottomSheet = new BottomSheet(context, needFocus); + } + + public Builder setItems(CharSequence[] items, final OnClickListener onClickListener) { + bottomSheet.items = items; + bottomSheet.onClickListener = onClickListener; + return this; + } + + public Builder setItems(CharSequence[] items, int[] icons, final OnClickListener onClickListener) { + bottomSheet.items = items; + bottomSheet.itemIcons = icons; + bottomSheet.onClickListener = onClickListener; + return this; + } + + public Builder setCustomView(View view) { + bottomSheet.customView = view; + return this; + } + + public Builder setTitle(CharSequence title) { + bottomSheet.title = title; + return this; + } + + public BottomSheet create() { + return bottomSheet; + } + + public BottomSheet show() { + bottomSheet.show(); + return bottomSheet; + } + + public Builder setTag(int tag) { + bottomSheet.tag = tag; + return this; + } + + public Builder setUseRevealAnimation() { + if (Build.VERSION.SDK_INT >= 18 && !AndroidUtilities.isTablet()) { + bottomSheet.useRevealAnimation = true; + } + return this; + } + + public Builder setDelegate(BottomSheetDelegate delegate) { + bottomSheet.setDelegate(delegate); + return this; + } + + public Builder setIsGrid(boolean value) { + bottomSheet.isGrid = value; + return this; + } + + public Builder setApplyTopPadding(boolean value) { + bottomSheet.applyTopPadding = value; + return this; + } + + public Builder setApplyBottomPadding(boolean value) { + bottomSheet.applyBottomPadding = value; + return this; + } + + public BottomSheet setUseFullWidth(boolean value) { + bottomSheet.fullWidth = value; + return bottomSheet; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java index 47a41063..06b56e03 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/DrawerLayoutContainer.java @@ -17,6 +17,7 @@ import android.graphics.Paint; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.os.Build; +import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.VelocityTracker; @@ -28,12 +29,12 @@ import android.widget.FrameLayout; import android.widget.ListView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.R; import org.telegram.messenger.AnimationCompat.AnimatorListenerAdapterProxy; import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.R; public class DrawerLayoutContainer extends FrameLayout { @@ -73,23 +74,23 @@ public class DrawerLayoutContainer extends FrameLayout { if (Build.VERSION.SDK_INT >= 21) { setFitsSystemWindows(true); - setOnApplyWindowInsetsListener(new InsetsListener()); + setOnApplyWindowInsetsListener(new OnApplyWindowInsetsListener() { + @SuppressLint("NewApi") + @Override + public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { + final DrawerLayoutContainer drawerLayout = (DrawerLayoutContainer) v; + lastInsets = insets; + drawerLayout.setWillNotDraw(insets.getSystemWindowInsetTop() <= 0 && getBackground() == null); + drawerLayout.requestLayout(); + return insets.consumeSystemWindowInsets(); + } + }); setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); } shadowLeft = getResources().getDrawable(R.drawable.menu_shadow); } - @SuppressLint("NewApi") - private class InsetsListener implements View.OnApplyWindowInsetsListener { - @Override - public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) { - final DrawerLayoutContainer drawerLayout = (DrawerLayoutContainer) v; - drawerLayout.setChildInsets(insets, insets.getSystemWindowInsetTop() > 0); - return insets.consumeSystemWindowInsets(); - } - } - @SuppressLint("NewApi") private void dispatchChildInsets(View child, Object insets, int drawerGravity) { WindowInsets wi = (WindowInsets) insets; @@ -122,12 +123,6 @@ public class DrawerLayoutContainer extends FrameLayout { return 0; } - private void setChildInsets(Object insets, boolean draw) { - lastInsets = insets; - setWillNotDraw(!draw && getBackground() == null); - requestLayout(); - } - public void setDrawerLayout(ViewGroup layout) { drawerLayout = layout; addView(drawerLayout); @@ -168,6 +163,7 @@ public class DrawerLayoutContainer extends FrameLayout { } public void openDrawer(boolean fast) { + Log.e("DrawerLAyout","openDrawer allowOpenDrawer " + allowOpenDrawer); if (!allowOpenDrawer) { return; } @@ -190,11 +186,6 @@ public class DrawerLayoutContainer extends FrameLayout { public void onAnimationEnd(Object animator) { onDrawerAnimationEnd(true); } - - @Override - public void onAnimationCancel(Object animator) { - onDrawerAnimationEnd(true); - } }); animatorSet.start(); currentAnimation = animatorSet; @@ -217,11 +208,6 @@ public class DrawerLayoutContainer extends FrameLayout { public void onAnimationEnd(Object animator) { onDrawerAnimationEnd(false); } - - @Override - public void onAnimationCancel(Object animator) { - onDrawerAnimationEnd(false); - } }); animatorSet.start(); } @@ -258,8 +244,8 @@ public class DrawerLayoutContainer extends FrameLayout { allowOpenDrawer = value; if (!allowOpenDrawer && drawerPosition != 0) { if (!animated) { - setDrawerPosition(0); - onDrawerAnimationEnd(false); + setDrawerPosition(0); + onDrawerAnimationEnd(false); } else { closeDrawer(true); } @@ -384,6 +370,7 @@ public class DrawerLayoutContainer extends FrameLayout { @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { inLayout = true; + //FileLog.w("tmessages", "onLayout"); final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); @@ -410,6 +397,10 @@ public class DrawerLayoutContainer extends FrameLayout { @Override public void requestLayout() { if (!inLayout) { + /*StackTraceElement[] elements = Thread.currentThread().getStackTrace(); + for (int a = 0; a < elements.length; a++) { + FileLog.d("tmessages", "on " + elements[a]); + }*/ super.requestLayout(); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java new file mode 100644 index 00000000..cdda2c80 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/SimpleTextView.java @@ -0,0 +1,281 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.ActionBar; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.text.Layout; +import android.text.SpannableStringBuilder; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; + +public class SimpleTextView extends View implements Drawable.Callback { + + private Layout layout; + private TextPaint textPaint; + private int gravity = Gravity.LEFT | Gravity.TOP; + private CharSequence text; + private SpannableStringBuilder spannableStringBuilder; + private Drawable leftDrawable; + private Drawable rightDrawable; + private int drawablePadding = AndroidUtilities.dp(4); + private int leftDrawableTopPadding; + private int rightDrawableTopPadding; + + private int offsetX; + private int textWidth; + private int textHeight; + private boolean wasLayout; + + public enum Alignment { + ALIGN_NORMAL, + ALIGN_OPPOSITE, + ALIGN_CENTER, + ALIGN_LEFT, + ALIGN_RIGHT + } + + public SimpleTextView(Context context) { + super(context); + textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + } + + public void setTextColor(int color) { + textPaint.setColor(color); + invalidate(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + wasLayout = false; + } + + public void setTextSize(int size) { + int newSize = AndroidUtilities.dp(size); + if (newSize == textPaint.getTextSize()) { + return; + } + textPaint.setTextSize(newSize); + recreateLayoutMaybe(); + } + + public void setGravity(int value) { + gravity = value; + } + + public void setTypeface(Typeface typeface) { + textPaint.setTypeface(typeface); + } + + public int getSideDrawablesSize() { + int size = 0; + if (leftDrawable != null) { + size += leftDrawable.getIntrinsicWidth() + drawablePadding; + } + if (rightDrawable != null) { + size += rightDrawable.getIntrinsicWidth() + drawablePadding; + } + return size; + } + + public Paint getPaint() { + return textPaint; + } + + private void createLayout(int width) { + if (text != null) { + try { + if (leftDrawable != null) { + width -= leftDrawable.getIntrinsicWidth(); + width -= drawablePadding; + } + if (rightDrawable != null) { + width -= rightDrawable.getIntrinsicWidth(); + width -= drawablePadding; + } + width -= getPaddingLeft() + getPaddingRight(); + CharSequence string = TextUtils.ellipsize(text, textPaint, width, TextUtils.TruncateAt.END); + if (layout != null && TextUtils.equals(layout.getText(), string)) { + return; + } + layout = new StaticLayout(string, 0, string.length(), textPaint, width + AndroidUtilities.dp(8), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + + if (layout.getLineCount() > 0) { + textWidth = (int) Math.ceil(layout.getLineWidth(0)); + textHeight = layout.getLineBottom(0); + if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT) { + offsetX = -(int) layout.getLineLeft(0); + } else if (layout.getLineLeft(0) == 0) { + offsetX = width - textWidth; + } else { + offsetX = 0; + } + } + } catch (Exception e) { + //ignore + } + } else { + layout = null; + textWidth = 0; + textHeight = 0; + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = MeasureSpec.getSize(widthMeasureSpec); + int height = MeasureSpec.getSize(heightMeasureSpec); + createLayout(width - getPaddingLeft() - getPaddingRight()); + + int finalHeight; + if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) { + finalHeight = height; + } else { + finalHeight = textHeight; + } + setMeasuredDimension(width, finalHeight); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + if (changed) { + wasLayout = true; + } + } + + public int getTextWidth() { + return textWidth; + } + + public int getTextHeight() { + return textHeight; + } + + public void setLeftDrawableTopPadding(int value) { + leftDrawableTopPadding = value; + } + + public void setRightDrawableTopPadding(int value) { + rightDrawableTopPadding = value; + } + + public void setLeftDrawable(int resId) { + setLeftDrawable(resId == 0 ? null : getContext().getResources().getDrawable(resId)); + } + + public void setRightDrawable(int resId) { + setRightDrawable(resId == 0 ? null : getContext().getResources().getDrawable(resId)); + } + + public void setLeftDrawable(Drawable drawable) { + if (leftDrawable == drawable) { + return; + } + if (leftDrawable != null) { + leftDrawable.setCallback(null); + } + leftDrawable = drawable; + if (drawable != null) { + drawable.setCallback(this); + } + recreateLayoutMaybe(); + } + + public void setRightDrawable(Drawable drawable) { + if (rightDrawable == drawable) { + return; + } + if (rightDrawable != null) { + rightDrawable.setCallback(null); + } + rightDrawable = drawable; + if (drawable != null) { + drawable.setCallback(this); + } + recreateLayoutMaybe(); + } + + public void setText(CharSequence value) { + if (text == null && value == null || text != null && value != null && text.equals(value)) { + return; + } + text = value; + recreateLayoutMaybe(); + } + + public void setDrawablePadding(int value) { + if (drawablePadding == value) { + return; + } + drawablePadding = value; + recreateLayoutMaybe(); + } + + private void recreateLayoutMaybe() { + if (wasLayout) { + createLayout(getMeasuredWidth()); + invalidate(); + } else { + requestLayout(); + } + } + + public CharSequence getText() { + if (text == null) { + return ""; + } + return text; + } + + @Override + protected void onDraw(Canvas canvas) { + int textOffsetX = 0; + if (leftDrawable != null) { + int y = (textHeight - leftDrawable.getIntrinsicHeight()) / 2 + leftDrawableTopPadding; + leftDrawable.setBounds(0, y, leftDrawable.getIntrinsicWidth(), y + leftDrawable.getIntrinsicHeight()); + leftDrawable.draw(canvas); + if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT) { + textOffsetX += drawablePadding + leftDrawable.getIntrinsicWidth(); + } + } + if (rightDrawable != null) { + int x = textOffsetX + textWidth + drawablePadding; + if (leftDrawable != null) { + x += drawablePadding + leftDrawable.getIntrinsicWidth(); + } + int y = (textHeight - rightDrawable.getIntrinsicHeight()) / 2 + rightDrawableTopPadding; + rightDrawable.setBounds(x, y, x + rightDrawable.getIntrinsicWidth(), y + rightDrawable.getIntrinsicHeight()); + rightDrawable.draw(canvas); + } + if (layout != null) { + if (offsetX + textOffsetX != 0) { + canvas.save(); + canvas.translate(offsetX + textOffsetX, 0); + } + layout.draw(canvas); + if (offsetX + textOffsetX != 0) { + canvas.restore(); + } + } + } + + @Override + public void invalidateDrawable(Drawable who) { + invalidate(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java new file mode 100644 index 00000000..217ec62c --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ActionBar/Theme.java @@ -0,0 +1,579 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.ActionBar; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.ColorStateList; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.RippleDrawable; +import android.graphics.drawable.StateListDrawable; +import android.os.Build; +import android.util.Log; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.R; +import org.telegram.ui.ImageListActivity; + +public class Theme { + + public static final int ACTION_BAR_COLOR = 0xff527da3; + public static final int ACTION_BAR_PHOTO_VIEWER_COLOR = 0x7f000000; + public static final int ACTION_BAR_MEDIA_PICKER_COLOR = 0xff333333; + public static final int ACTION_BAR_CHANNEL_INTRO_COLOR = 0xffffffff; + public static final int ACTION_BAR_PLAYER_COLOR = 0xffffffff; + public static final int ACTION_BAR_TITLE_COLOR = 0xffffffff; + public static final int ACTION_BAR_SUBTITLE_COLOR = 0xffd5e8f7; + public static final int ACTION_BAR_PROFILE_COLOR = 0xff598fba; + public static final int ACTION_BAR_PROFILE_SUBTITLE_COLOR = 0xffd7eafa; + public static final int ACTION_BAR_MAIN_AVATAR_COLOR = 0xff5085b1; + public static final int ACTION_BAR_ACTION_MODE_TEXT_COLOR = 0xff737373; + public static final int ACTION_BAR_SELECTOR_COLOR = 0xff406d94; + + public static final int INPUT_FIELD_SELECTOR_COLOR = 0xffd6d6d6; + public static final int ACTION_BAR_PICKER_SELECTOR_COLOR = 0xff3d3d3d; + public static final int ACTION_BAR_WHITE_SELECTOR_COLOR = 0x40ffffff; + public static final int ACTION_BAR_AUDIO_SELECTOR_COLOR = 0x2f000000; + public static final int ACTION_BAR_CHANNEL_INTRO_SELECTOR_COLOR = 0x2f000000; + public static final int ACTION_BAR_MODE_SELECTOR_COLOR = 0xfff0f0f0; + public static final int ACTION_BAR_BLUE_SELECTOR_COLOR = 0xff4981ad; + public static final int ACTION_BAR_CYAN_SELECTOR_COLOR = 0xff39849d; + public static final int ACTION_BAR_GREEN_SELECTOR_COLOR = 0xff48953d; + public static final int ACTION_BAR_ORANGE_SELECTOR_COLOR = 0xffe67429; + public static final int ACTION_BAR_PINK_SELECTOR_COLOR = 0xffd44e7b; + public static final int ACTION_BAR_RED_SELECTOR_COLOR = 0xffbc4b41; + public static final int ACTION_BAR_VIOLET_SELECTOR_COLOR = 0xff735fbe; + public static final int ACTION_BAR_YELLOW_SELECTOR_COLOR = 0xffef9f09; + + + + public static final int CHAT_UNREAD_TEXT_COLOR = 0xff5695cc; + public static final int CHAT_ADD_CONTACT_TEXT_COLOR = 0xff4a82b5; + public static final int CHAT_REPORT_SPAM_TEXT_COLOR = 0xffcf5957; + public static final int CHAT_BOTTOM_OVERLAY_TEXT_COLOR = 0xff7f7f7f; + public static final int CHAT_BOTTOM_CHAT_OVERLAY_TEXT_COLOR = 0xff3a8ccf; + public static final int CHAT_GIF_HINT_TEXT_COLOR = 0xffffffff; + public static final int CHAT_EMPTY_VIEW_TEXT_COLOR = 0xffffffff; + + public static final int INAPP_PLAYER_PERFORMER_TEXT_COLOR = 0xff2f3438; + public static final int INAPP_PLAYER_TITLE_TEXT_COLOR = 0xff2f3438; + public static final int INAPP_PLAYER_BACKGROUND_COLOR = 0xffffffff; + + public static final int REPLY_PANEL_NAME_TEXT_COLOR = 0xff3a8ccf; + public static final int REPLY_PANEL_MESSAGE_TEXT_COLOR = 0xff222222; + + public static final int ALERT_PANEL_NAME_TEXT_COLOR = 0xff3a8ccf; + public static final int ALERT_PANEL_MESSAGE_TEXT_COLOR = 0xff999999; + + public static final int AUTODOWNLOAD_SHEET_SAVE_TEXT_COLOR = 0xff3a8ccf; + + public static final int SHARE_SHEET_COPY_TEXT_COLOR = 0xff3a8ccf; + public static final int SHARE_SHEET_SEND_TEXT_COLOR = 0xff3ec1f9; + public static final int SHARE_SHEET_SEND_DISABLED_TEXT_COLOR = 0xffb3b3b3; + public static final int SHARE_SHEET_EDIT_TEXT_COLOR = 0xff212121; + public static final int SHARE_SHEET_EDIT_PLACEHOLDER_TEXT_COLOR = 0xff979797; + public static final int SHARE_SHEET_BADGE_TEXT_COLOR = 0xffffffff; + + public static final int STICKERS_SHEET_TITLE_TEXT_COLOR = 0xff212121; + public static final int STICKERS_SHEET_SEND_TEXT_COLOR = 0xff3a8ccf; + public static final int STICKERS_SHEET_ADD_TEXT_COLOR = 0xff3a8ccf; + public static final int STICKERS_SHEET_CLOSE_TEXT_COLOR = 0xff3a8ccf; + public static final int STICKERS_SHEET_REMOVE_TEXT_COLOR = 0xffcd5a5a; + + public static final int PINNED_PANEL_NAME_TEXT_COLOR = 0xff3a8ccf; + public static final int PINNED_PANEL_MESSAGE_TEXT_COLOR = 0xff999999; + + public static final int SECRET_CHAT_INFO_TEXT_COLOR = 0xffffffff; + + public static final int MSG_WEB_PREVIEW_DURATION_TEXT_COLOR = 0xffffffff; + public static final int MSG_SECRET_TIME_TEXT_COLOR = 0xffe4e2e0; + public static final int MSG_STICKER_NAME_TEXT_COLOR = 0xffffffff; + public static final int MSG_BOT_BUTTON_TEXT_COLOR = 0xffffffff; + public static final int MSG_BOT_PROGRESS_COLOR = 0xffffffff; + public static final int MSG_IN_FORDWARDED_NAME_TEXT_COLOR = 0xff3886c7; + public static final int MSG_OUT_FORDWARDED_NAME_TEXT_COLOR = 0xff55ab4f; + public static final int MSG_IN_VIA_BOT_NAME_TEXT_COLOR = 0xff3a8ccf; + public static final int MSG_OUT_VIA_BOT_NAME_TEXT_COLOR = 0xff55ab4f; + public static final int MSG_STICKER_VIA_BOT_NAME_TEXT_COLOR = 0xffffffff; + public static final int MSG_IN_REPLY_LINE_COLOR = 0xff70b4e8; + public static final int MSG_OUT_REPLY_LINE_COLOR = 0xff88c97b; + public static final int MSG_STICKER_REPLY_LINE_COLOR = 0xffffffff; + public static final int MSG_IN_REPLY_NAME_TEXT_COLOR = 0xff3a8ccf; + public static final int MSG_OUT_REPLY_NAME_TEXT_COLOR = 0xff55ab4f; + public static final int MSG_STICKER_REPLY_NAME_TEXT_COLOR = 0xffffffff; + public static final int MSG_IN_REPLY_MESSAGE_TEXT_COLOR = 0xff000000; + public static final int MSG_OUT_REPLY_MESSAGE_TEXT_COLOR = 0xff000000; + public static final int MSG_IN_REPLY_MEDIA_MESSAGE_TEXT_COLOR = 0xffa1aab3; + public static final int MSG_OUT_REPLY_MEDIA_MESSAGE_TEXT_COLOR = 0xff65b05b; + public static final int MSG_IN_REPLY_MEDIA_MESSAGE_SELETED_TEXT_COLOR = 0xff89b4c1; + public static final int MSG_OUT_REPLY_MEDIA_MESSAGE_SELETED_TEXT_COLOR = 0xff65b05b; + public static final int MSG_STICKER_REPLY_MESSAGE_TEXT_COLOR = 0xffffffff; + public static final int MSG_IN_WEB_PREVIEW_LINE_COLOR = 0xff70b4e8; + public static final int MSG_OUT_WEB_PREVIEW_LINE_COLOR = 0xff88c97b; + public static final int MSG_IN_SITE_NAME_TEXT_COLOR = 0xff3a8ccf; + public static final int MSG_OUT_SITE_NAME_TEXT_COLOR = 0xff55ab4f; + public static final int MSG_IN_CONTACT_NAME_TEXT_COLOR = 0xff4e9ad4; + public static final int MSG_OUT_CONTACT_NAME_TEXT_COLOR = 0xff55ab4f; + public static final int MSG_IN_CONTACT_PHONE_TEXT_COLOR = 0xff2f3438; + public static final int MSG_OUT_CONTACT_PHONE_TEXT_COLOR = 0xff354234; + public static final int MSG_MEDIA_PROGRESS_COLOR = 0xffffffff; + public static final int MSG_IN_AUDIO_PROGRESS_COLOR = 0xffffffff; + public static final int MSG_OUT_AUDIO_PROGRESS_COLOR = 0xffefffde; + public static final int MSG_IN_AUDIO_SELECTED_PROGRESS_COLOR = 0xffe2f8ff; + public static final int MSG_OUT_AUDIO_SELECTED_PROGRESS_COLOR = 0xffd4f5bc; + public static final int MSG_MEDIA_TIME_TEXT_COLOR = 0xffffffff; + public static final int MSG_IN_TIME_TEXT_COLOR = 0xffa1aab3; + public static final int MSG_OUT_TIME_TEXT_COLOR = 0xff70b15c; + public static final int MSG_IN_TIME_SELECTED_TEXT_COLOR = 0xff89b4c1; + public static final int MSG_OUT_TIME_SELECTED_TEXT_COLOR = 0xff70b15c; + public static final int MSG_IN_AUDIO_PERFORMER_TEXT_COLOR = 0xff2f3438; + public static final int MSG_OUT_AUDIO_PERFORMER_TEXT_COLOR = 0xff354234; + public static final int MSG_IN_AUDIO_TITLE_TEXT_COLOR = 0xff4e9ad4; + public static final int MSG_OUT_AUDIO_TITLE_TEXT_COLOR = 0xff55ab4f; + public static final int MSG_IN_AUDIO_DURATION_TEXT_COLOR = 0xffa1aab3; + public static final int MSG_OUT_AUDIO_DURATION_TEXT_COLOR = 0xff65b05b; + public static final int MSG_IN_AUDIO_DURATION_SELECTED_TEXT_COLOR = 0xff89b4c1; + public static final int MSG_OUT_AUDIO_DURATION_SELECTED_TEXT_COLOR = 0xff65b05b; + public static final int MSG_IN_AUDIO_SEEKBAR_COLOR = 0xffe4eaf0; + public static final int MSG_OUT_AUDIO_SEEKBAR_COLOR = 0xffbbe3ac; + public static final int MSG_IN_AUDIO_SEEKBAR_SELECTED_COLOR = 0xffbcdee8; + public static final int MSG_OUT_AUDIO_SEEKBAR_SELECTED_COLOR = 0xffa9dd96; + public static final int MSG_IN_AUDIO_SEEKBAR_FILL_COLOR = 0xff72b5e8; + public static final int MSG_OUT_AUDIO_SEEKBAR_FILL_COLOR = 0xff78c272; + public static final int MSG_IN_VOICE_SEEKBAR_COLOR = 0xffdee5eb; + public static final int MSG_OUT_VOICE_SEEKBAR_COLOR = 0xffbbe3ac; + public static final int MSG_IN_VOICE_SEEKBAR_SELECTED_COLOR = 0xffbcdee8; + public static final int MSG_OUT_VOICE_SEEKBAR_SELECTED_COLOR = 0xffa9dd96; + public static final int MSG_IN_VOICE_SEEKBAR_FILL_COLOR = 0xff72b5e8; + public static final int MSG_OUT_VOICE_SEEKBAR_FILL_COLOR = 0xff78c272; + public static final int MSG_IN_FILE_PROGRESS_COLOR = 0xffebf0f5; + public static final int MSG_OUT_FILE_PROGRESS_COLOR = 0xffdaf5c3; + public static final int MSG_IN_FILE_PROGRESS_SELECTED_COLOR = 0xffcbeaf6; + public static final int MSG_OUT_FILE_PROGRESS_SELECTED_COLOR = 0xffc5eca7; + public static final int MSG_IN_FILE_NAME_TEXT_COLOR = 0xff4e9ad4; + public static final int MSG_OUT_FILE_NAME_TEXT_COLOR = 0xff55ab4f; + public static final int MSG_IN_FILE_INFO_TEXT_COLOR = 0xffa1aab3; + public static final int MSG_OUT_FILE_INFO_TEXT_COLOR = 0xff65b05b; + public static final int MSG_IN_FILE_INFO_SELECTED_TEXT_COLOR = 0xff89b4c1; + public static final int MSG_OUT_FILE_INFO_SELECTED_TEXT_COLOR = 0xff65b05b; + public static final int MSG_IN_FILE_BACKGROUND_COLOR = 0xffebf0f5; + public static final int MSG_OUT_FILE_BACKGROUND_COLOR = 0xffdaf5c3; + public static final int MSG_IN_FILE_BACKGROUND_SELECTED_COLOR = 0xffcbeaf6; + public static final int MSG_OUT_FILE_BACKGROUND_SELECTED_COLOR = 0xffc5eca7; + public static final int MSG_IN_VENUE_NAME_TEXT_COLOR = 0xff4e9ad4; + public static final int MSG_OUT_VENUE_NAME_TEXT_COLOR = 0xff55ab4f; + public static final int MSG_IN_VENUE_INFO_TEXT_COLOR = 0xffa1aab3; + public static final int MSG_OUT_VENUE_INFO_TEXT_COLOR = 0xff65b05b; + public static final int MSG_IN_VENUE_INFO_SELECTED_TEXT_COLOR = 0xff89b4c1; + public static final int MSG_OUT_VENUE_INFO_SELECTED_TEXT_COLOR = 0xff65b05b; + public static final int MSG_MEDIA_INFO_TEXT_COLOR = 0xffffffff; + public static final int MSG_TEXT_COLOR = 0xff000000; + public static final int MSG_LINK_TEXT_COLOR = 0xff2678b6; + public static final int MSG_LINK_SELECT_BACKGROUND_COLOR = 0x3362a9e3; + + + public static Drawable backgroundDrawableIn; + public static Drawable backgroundDrawableInSelected; + public static Drawable backgroundDrawableOut; + public static Drawable backgroundDrawableOutSelected; + public static Drawable backgroundMediaDrawableIn; + public static Drawable backgroundMediaDrawableInSelected; + public static Drawable backgroundMediaDrawableOut; + public static Drawable backgroundMediaDrawableOutSelected; + public static Drawable checkDrawable; + public static Drawable halfCheckDrawable; + public static Drawable clockDrawable; + public static Drawable broadcastDrawable; + public static Drawable checkMediaDrawable; + public static Drawable halfCheckMediaDrawable; + public static Drawable clockMediaDrawable; + public static Drawable broadcastMediaDrawable; + public static Drawable errorDrawable; + public static Drawable systemDrawable; + public static Drawable backgroundBluePressed; + public static Drawable timeBackgroundDrawable; + public static Drawable timeStickerBackgroundDrawable; + public static Drawable botLink; + public static Drawable botInline; + public static Drawable[] clockChannelDrawable = new Drawable[2]; + + public static Drawable[] cornerOuter = new Drawable[4]; + public static Drawable[] cornerInner = new Drawable[4]; + + public static Drawable shareDrawable; + public static Drawable shareIconDrawable; + + public static Drawable[] viewsCountDrawable = new Drawable[2]; + public static Drawable viewsOutCountDrawable; + public static Drawable viewsMediaCountDrawable; + + public static Drawable geoInDrawable; + public static Drawable geoOutDrawable; + + public static Drawable inlineDocDrawable; + public static Drawable inlineAudioDrawable; + public static Drawable inlineLocationDrawable; + + public static Drawable[] contactDrawable = new Drawable[2]; + public static Drawable[][] fileStatesDrawable = new Drawable[10][2]; + public static Drawable[][] photoStatesDrawables = new Drawable[13][2]; + public static Drawable[] docMenuDrawable = new Drawable[4]; + + public static PorterDuffColorFilter colorFilter; + public static PorterDuffColorFilter colorPressedFilter; + private static int currentColor; + + public static Drawable attachButtonDrawables[] = new Drawable[8]; + + private static Paint maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public static void loadResources(Context context) { + if (backgroundDrawableIn == null) { + //backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in); + //backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_selected); + //backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out); + //backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_selected); + //backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_photo); + //backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_photo_selected); + //backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_photo); + //backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_photo_selected); + setBubbles(context); + setChecks(context); + //checkDrawable = context.getResources().getDrawable(R.drawable.msg_check); + //halfCheckDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck); + clockDrawable = context.getResources().getDrawable(R.drawable.msg_clock); + //checkMediaDrawable = context.getResources().getDrawable(R.drawable.msg_check_w); + //halfCheckMediaDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_w); + clockMediaDrawable = context.getResources().getDrawable(R.drawable.msg_clock_photo); + clockChannelDrawable[0] = context.getResources().getDrawable(R.drawable.msg_clock2); + clockChannelDrawable[1] = context.getResources().getDrawable(R.drawable.msg_clock2_s); + errorDrawable = context.getResources().getDrawable(R.drawable.msg_warning); + timeBackgroundDrawable = context.getResources().getDrawable(R.drawable.phototime2_b); + timeStickerBackgroundDrawable = context.getResources().getDrawable(R.drawable.phototime2); + broadcastDrawable = context.getResources().getDrawable(R.drawable.broadcast3); + broadcastMediaDrawable = context.getResources().getDrawable(R.drawable.broadcast4); + systemDrawable = context.getResources().getDrawable(R.drawable.system); + botLink = context.getResources().getDrawable(R.drawable.bot_link); + botInline = context.getResources().getDrawable(R.drawable.bot_lines); + + viewsCountDrawable[0] = context.getResources().getDrawable(R.drawable.post_views); + viewsCountDrawable[1] = context.getResources().getDrawable(R.drawable.post_views_s); + viewsOutCountDrawable = context.getResources().getDrawable(R.drawable.post_viewsg); + viewsMediaCountDrawable = context.getResources().getDrawable(R.drawable.post_views_w); + + fileStatesDrawable[0][0] = context.getResources().getDrawable(R.drawable.play_g); + fileStatesDrawable[0][1] = context.getResources().getDrawable(R.drawable.play_g_s); + fileStatesDrawable[1][0] = context.getResources().getDrawable(R.drawable.pause_g); + fileStatesDrawable[1][1] = context.getResources().getDrawable(R.drawable.pause_g_s); + fileStatesDrawable[2][0] = context.getResources().getDrawable(R.drawable.file_g_load); + fileStatesDrawable[2][1] = context.getResources().getDrawable(R.drawable.file_g_load_s); + fileStatesDrawable[3][0] = context.getResources().getDrawable(R.drawable.file_g); + fileStatesDrawable[3][1] = context.getResources().getDrawable(R.drawable.file_g_s); + fileStatesDrawable[4][0] = context.getResources().getDrawable(R.drawable.file_g_cancel); + fileStatesDrawable[4][1] = context.getResources().getDrawable(R.drawable.file_g_cancel_s); + fileStatesDrawable[5][0] = context.getResources().getDrawable(R.drawable.play_b); + fileStatesDrawable[5][1] = context.getResources().getDrawable(R.drawable.play_b_s); + fileStatesDrawable[6][0] = context.getResources().getDrawable(R.drawable.pause_b); + fileStatesDrawable[6][1] = context.getResources().getDrawable(R.drawable.pause_b_s); + fileStatesDrawable[7][0] = context.getResources().getDrawable(R.drawable.file_b_load); + fileStatesDrawable[7][1] = context.getResources().getDrawable(R.drawable.file_b_load_s); + fileStatesDrawable[8][0] = context.getResources().getDrawable(R.drawable.file_b); + fileStatesDrawable[8][1] = context.getResources().getDrawable(R.drawable.file_b_s); + fileStatesDrawable[9][0] = context.getResources().getDrawable(R.drawable.file_b_cancel); + fileStatesDrawable[9][1] = context.getResources().getDrawable(R.drawable.file_b_cancel_s); + + photoStatesDrawables[0][0] = context.getResources().getDrawable(R.drawable.photoload); + photoStatesDrawables[0][1] = context.getResources().getDrawable(R.drawable.photoload_pressed); + photoStatesDrawables[1][0] = context.getResources().getDrawable(R.drawable.photocancel); + photoStatesDrawables[1][1] = context.getResources().getDrawable(R.drawable.photocancel_pressed); + photoStatesDrawables[2][0] = context.getResources().getDrawable(R.drawable.photogif); + photoStatesDrawables[2][1] = context.getResources().getDrawable(R.drawable.photogif_pressed); + photoStatesDrawables[3][0] = context.getResources().getDrawable(R.drawable.playvideo); + photoStatesDrawables[3][1] = context.getResources().getDrawable(R.drawable.playvideo_pressed); + //photoStatesDrawables[4] = context.getResources().getDrawable(R.drawable.photopause); + photoStatesDrawables[4][0] = photoStatesDrawables[4][1] = context.getResources().getDrawable(R.drawable.burn); + photoStatesDrawables[5][0] = photoStatesDrawables[5][1] = context.getResources().getDrawable(R.drawable.circle); + photoStatesDrawables[6][0] = photoStatesDrawables[6][1] = context.getResources().getDrawable(R.drawable.photocheck); + + photoStatesDrawables[7][0] = context.getResources().getDrawable(R.drawable.photoload_g); + photoStatesDrawables[7][1] = context.getResources().getDrawable(R.drawable.photoload_g_s); + photoStatesDrawables[8][0] = context.getResources().getDrawable(R.drawable.photocancel_g); + photoStatesDrawables[8][1] = context.getResources().getDrawable(R.drawable.photocancel_g_s); + photoStatesDrawables[9][0] = context.getResources().getDrawable(R.drawable.doc_green); + photoStatesDrawables[9][1] = context.getResources().getDrawable(R.drawable.doc_green); + + photoStatesDrawables[10][0] = context.getResources().getDrawable(R.drawable.photoload_b); + photoStatesDrawables[10][1] = context.getResources().getDrawable(R.drawable.photoload_b_s); + photoStatesDrawables[11][0] = context.getResources().getDrawable(R.drawable.photocancel_b); + photoStatesDrawables[11][1] = context.getResources().getDrawable(R.drawable.photocancel_b_s); + photoStatesDrawables[12][0] = context.getResources().getDrawable(R.drawable.doc_blue); + photoStatesDrawables[12][1] = context.getResources().getDrawable(R.drawable.doc_blue_s); + + docMenuDrawable[0] = context.getResources().getDrawable(R.drawable.doc_actions_b); + docMenuDrawable[1] = context.getResources().getDrawable(R.drawable.doc_actions_g); + docMenuDrawable[2] = context.getResources().getDrawable(R.drawable.doc_actions_b_s); + docMenuDrawable[3] = context.getResources().getDrawable(R.drawable.video_actions); + + contactDrawable[0] = context.getResources().getDrawable(R.drawable.contact_blue); + contactDrawable[1] = context.getResources().getDrawable(R.drawable.contact_green); + + shareDrawable = context.getResources().getDrawable(R.drawable.share_round); + shareIconDrawable = context.getResources().getDrawable(R.drawable.share_arrow); + + geoInDrawable = context.getResources().getDrawable(R.drawable.location_b); + geoOutDrawable = context.getResources().getDrawable(R.drawable.location_g); + + attachButtonDrawables[0] = context.getResources().getDrawable(R.drawable.attach_camera_states); + attachButtonDrawables[1] = context.getResources().getDrawable(R.drawable.attach_gallery_states); + attachButtonDrawables[2] = context.getResources().getDrawable(R.drawable.attach_video_states); + attachButtonDrawables[3] = context.getResources().getDrawable(R.drawable.attach_audio_states); + attachButtonDrawables[4] = context.getResources().getDrawable(R.drawable.attach_file_states); + attachButtonDrawables[5] = context.getResources().getDrawable(R.drawable.attach_contact_states); + attachButtonDrawables[6] = context.getResources().getDrawable(R.drawable.attach_location_states); + attachButtonDrawables[7] = context.getResources().getDrawable(R.drawable.attach_hide_states); + + cornerOuter[0] = context.getResources().getDrawable(R.drawable.corner_out_tl); + cornerOuter[1] = context.getResources().getDrawable(R.drawable.corner_out_tr); + cornerOuter[2] = context.getResources().getDrawable(R.drawable.corner_out_br); + cornerOuter[3] = context.getResources().getDrawable(R.drawable.corner_out_bl); + + cornerInner[0] = context.getResources().getDrawable(R.drawable.corner_in_tr); + cornerInner[1] = context.getResources().getDrawable(R.drawable.corner_in_tl); + cornerInner[2] = context.getResources().getDrawable(R.drawable.corner_in_br); + cornerInner[3] = context.getResources().getDrawable(R.drawable.corner_in_bl); + + inlineDocDrawable = context.getResources().getDrawable(R.drawable.bot_file); + inlineAudioDrawable = context.getResources().getDrawable(R.drawable.bot_music); + inlineLocationDrawable = context.getResources().getDrawable(R.drawable.bot_location); + } + + int color = ApplicationLoader.getServiceMessageColor(); + if (currentColor != color) { + colorFilter = new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY); + colorPressedFilter = new PorterDuffColorFilter(ApplicationLoader.getServiceSelectedMessageColor(), PorterDuff.Mode.MULTIPLY); + currentColor = color; + for (int a = 0; a < 4; a++) { + cornerOuter[a].setColorFilter(colorFilter); + cornerInner[a].setColorFilter(colorFilter); + } + timeStickerBackgroundDrawable.setColorFilter(colorFilter); + } + } + + public static Drawable createBarSelectorDrawable(int color) { + return createBarSelectorDrawable(color, true); + } + + public static Drawable createBarSelectorDrawable(int color, boolean masked) { + Drawable drawable; + if (Build.VERSION.SDK_INT >= 21) { + Drawable maskDrawable = null; + if (masked) { + maskPaint.setColor(0xffffffff); + maskDrawable = new Drawable() { + @Override + public void draw(Canvas canvas) { + android.graphics.Rect bounds = getBounds(); + canvas.drawCircle(bounds.centerX(), bounds.centerY(), AndroidUtilities.dp(18), maskPaint); + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(ColorFilter colorFilter) { + + } + + @Override + public int getOpacity() { + return 0; + } + }; + } + ColorStateList colorStateList = new ColorStateList( + new int[][]{new int[]{}}, + new int[]{color} + ); + return new RippleDrawable(colorStateList, null, maskDrawable); + } else { + StateListDrawable stateListDrawable = new StateListDrawable(); + stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, new ColorDrawable(color)); + stateListDrawable.addState(new int[]{android.R.attr.state_focused}, new ColorDrawable(color)); + stateListDrawable.addState(new int[]{android.R.attr.state_selected}, new ColorDrawable(color)); + if (Build.VERSION.SDK_INT >= 11) { + stateListDrawable.addState(new int[]{android.R.attr.state_activated}, new ColorDrawable(color)); + } + stateListDrawable.addState(new int[]{}, new ColorDrawable(0x00000000)); + return stateListDrawable; + } + } + + public static void setBubbles(Context context){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + String bubble = themePrefs.getString("chatBubbleStyle", ImageListActivity.getBubbleName(0)); + if(bubble.equals(ImageListActivity.getBubbleName(0))){ + backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in); + backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_selected); + backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out); + backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_selected); + backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_photo); + backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_photo_selected); + backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_photo); + backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_photo_selected); + } else if(bubble.equals(ImageListActivity.getBubbleName(1))){ + backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_2); + backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_2_selected); + backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_2); + backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_2_selected); + backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_2_photo); + backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_2_photo_selected); + backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_2_photo); + backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_2_photo_selected); + } else if(bubble.equals(ImageListActivity.getBubbleName(2))){ + backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_3); + backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_3_selected); + backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_3); + backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_3_selected); + backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_3_photo); + backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_3_photo_selected); + backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_3_photo); + backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_3_photo_selected); + } else if(bubble.equals(ImageListActivity.getBubbleName(3))){ + backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_4); + backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_4_selected); + backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_4); + backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_4_selected); + backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_4_photo); + backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_4_photo_selected); + backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_4_photo); + backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_4_photo_selected); + } else if(bubble.equals(ImageListActivity.getBubbleName(4))){ + backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_5); + backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_5_selected); + backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_5); + backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_5_selected); + backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_5_photo); + backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_5_photo_selected); + backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_5_photo); + backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_5_photo_selected); + } else if(bubble.equals(ImageListActivity.getBubbleName(5))){ + backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_6); + backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_6_selected); + backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_6); + backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_6_selected); + backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_6_photo); + backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_6_photo_selected); + backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_6_photo); + backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_6_photo_selected); + } else if(bubble.equals(ImageListActivity.getBubbleName(6))){ + backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_7); + backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_7_selected); + backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_7); + backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_7_selected); + backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_7_photo); + backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_7_photo_selected); + backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_7_photo); + backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_7_photo_selected); + } else if(bubble.equals(ImageListActivity.getBubbleName(7))){ + backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_8); + backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_8_selected); + backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_8); + backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_8_selected); + backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_8_photo); + backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_8_photo_selected); + backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_8_photo); + backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_8_photo_selected); + } else{ + backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in); + backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_selected); + backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out); + backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_selected); + backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_photo); + backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_photo_selected); + backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_photo); + backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_photo_selected); + } + } + + public static void setChecks(Context context) { + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + String check = themePrefs.getString("chatCheckStyle", ImageListActivity.getCheckName(0)); + if (check.equals(ImageListActivity.getCheckName(1))) { + checkDrawable = context.getResources().getDrawable(R.drawable.msg_check_2); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_2); + checkMediaDrawable = context.getResources().getDrawable(R.drawable.msg_check_w_2); + halfCheckMediaDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_w_2); + } else if (check.equals(ImageListActivity.getCheckName(2))) { + checkDrawable = context.getResources().getDrawable(R.drawable.msg_check_3); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_3); + checkMediaDrawable = context.getResources().getDrawable(R.drawable.msg_check_w_3); + halfCheckMediaDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_w_3); + } else if (check.equals(ImageListActivity.getCheckName(3))) { + checkDrawable = context.getResources().getDrawable(R.drawable.msg_check_4); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_4); + checkMediaDrawable = context.getResources().getDrawable(R.drawable.msg_check_w_4); + halfCheckMediaDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_w_4); + } else if (check.equals(ImageListActivity.getCheckName(4))) { + checkDrawable = context.getResources().getDrawable(R.drawable.msg_check_5); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_5); + checkMediaDrawable = context.getResources().getDrawable(R.drawable.msg_check_w_5); + halfCheckMediaDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_w_5); + } else if (check.equals(ImageListActivity.getCheckName(5))) { + checkDrawable = context.getResources().getDrawable(R.drawable.msg_check_6); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_6); + checkMediaDrawable = context.getResources().getDrawable(R.drawable.msg_check_w_6); + halfCheckMediaDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_w_6); + } else if (check.equals(ImageListActivity.getCheckName(6))) { + checkDrawable = context.getResources().getDrawable(R.drawable.msg_check_7); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_7); + checkMediaDrawable = context.getResources().getDrawable(R.drawable.msg_check_w_7); + halfCheckMediaDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_w_7); + } else if (check.equals(ImageListActivity.getCheckName(7))) { + checkDrawable = context.getResources().getDrawable(R.drawable.msg_check_8); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_8); + checkMediaDrawable = context.getResources().getDrawable(R.drawable.msg_check_w_8); + halfCheckMediaDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_w_8); + } else if (check.equals(ImageListActivity.getCheckName(8))) { + checkDrawable = context.getResources().getDrawable(R.drawable.msg_check_9); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_9); + checkMediaDrawable = context.getResources().getDrawable(R.drawable.msg_check_w_9); + halfCheckMediaDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_w_9); + } else if (check.equals(ImageListActivity.getCheckName(9))) { + checkDrawable = context.getResources().getDrawable(R.drawable.msg_check_10); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_10); + checkMediaDrawable = context.getResources().getDrawable(R.drawable.msg_check_w_10); + halfCheckMediaDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_w_10); + } else if (check.equals(ImageListActivity.getCheckName(10))) { + checkDrawable = context.getResources().getDrawable(R.drawable.msg_check_11); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_11); + checkMediaDrawable = context.getResources().getDrawable(R.drawable.msg_check_w_11); + halfCheckMediaDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_w_11); + } else if (check.equals(ImageListActivity.getCheckName(11))) { + checkDrawable = context.getResources().getDrawable(R.drawable.msg_check_12); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_12); + checkMediaDrawable = context.getResources().getDrawable(R.drawable.msg_check_w_12); + halfCheckMediaDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_w_12); + } else { + checkDrawable = context.getResources().getDrawable(R.drawable.msg_check); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck); + checkMediaDrawable = context.getResources().getDrawable(R.drawable.msg_check_w); + halfCheckMediaDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_w); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseSearchAdapterRecycler.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseSearchAdapterRecycler.java new file mode 100644 index 00000000..c5c0912e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/BaseSearchAdapterRecycler.java @@ -0,0 +1,218 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Adapters; + +import org.telegram.SQLite.SQLiteCursor; +import org.telegram.SQLite.SQLitePreparedStatement; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.support.widget.RecyclerView; +import org.telegram.messenger.FileLog; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class BaseSearchAdapterRecycler extends RecyclerView.Adapter { + + protected static class HashtagObject { + String hashtag; + int date; + } + + protected ArrayList globalSearch = new ArrayList<>(); + private int reqId = 0; + private int lastReqId; + protected String lastFoundUsername = null; + + protected ArrayList hashtags; + protected HashMap hashtagsByText; + protected boolean hashtagsLoadedFromDb = false; + + public void queryServerSearch(final String query, final boolean allowChats) { + if (reqId != 0) { + ConnectionsManager.getInstance().cancelRequest(reqId, true); + reqId = 0; + } + if (query == null || query.length() < 5) { + globalSearch.clear(); + lastReqId = 0; + notifyDataSetChanged(); + return; + } + TLRPC.TL_contacts_search req = new TLRPC.TL_contacts_search(); + req.q = query; + req.limit = 50; + final int currentReqId = ++lastReqId; + reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (currentReqId == lastReqId) { + if (error == null) { + TLRPC.TL_contacts_found res = (TLRPC.TL_contacts_found) response; + globalSearch.clear(); + if (allowChats) { + for (int a = 0; a < res.chats.size(); a++) { + globalSearch.add(res.chats.get(a)); + } + } + for (int a = 0; a < res.users.size(); a++) { + globalSearch.add(res.users.get(a)); + } + lastFoundUsername = query; + notifyDataSetChanged(); + } + } + reqId = 0; + } + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + } + + public void loadRecentHashtags() { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized("SELECT id, date FROM hashtag_recent_v2 WHERE 1"); + final ArrayList arrayList = new ArrayList<>(); + final HashMap hashMap = new HashMap<>(); + while (cursor.next()) { + HashtagObject hashtagObject = new HashtagObject(); + hashtagObject.hashtag = cursor.stringValue(0); + hashtagObject.date = cursor.intValue(1); + arrayList.add(hashtagObject); + hashMap.put(hashtagObject.hashtag, hashtagObject); + } + cursor.dispose(); + Collections.sort(arrayList, new Comparator() { + @Override + public int compare(HashtagObject lhs, HashtagObject rhs) { + if (lhs.date < rhs.date) { + return 1; + } else if (lhs.date > rhs.date) { + return -1; + } else { + return 0; + } + } + }); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + setHashtags(arrayList, hashMap); + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void addHashtagsFromMessage(String message) { + if (message == null) { + return; + } + boolean changed = false; + Pattern pattern = Pattern.compile("(^|\\s)#[\\w@\\.]+"); + Matcher matcher = pattern.matcher(message); + while (matcher.find()) { + int start = matcher.start(); + int end = matcher.end(); + if (message.charAt(start) != '@' && message.charAt(start) != '#') { + start++; + } + String hashtag = message.substring(start, end); + if (hashtagsByText == null) { + hashtagsByText = new HashMap<>(); + hashtags = new ArrayList<>(); + } + HashtagObject hashtagObject = hashtagsByText.get(hashtag); + if (hashtagObject == null) { + hashtagObject = new HashtagObject(); + hashtagObject.hashtag = hashtag; + hashtagsByText.put(hashtagObject.hashtag, hashtagObject); + } else { + hashtags.remove(hashtagObject); + } + hashtagObject.date = (int) (System.currentTimeMillis() / 1000); + hashtags.add(0, hashtagObject); + changed = true; + } + if (changed) { + putRecentHashtags(hashtags); + } + } + + private void putRecentHashtags(final ArrayList arrayList) { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + MessagesStorage.getInstance().getDatabase().beginTransaction(); + SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("REPLACE INTO hashtag_recent_v2 VALUES(?, ?)"); + for (int a = 0; a < arrayList.size(); a++) { + if (a == 100) { + break; + } + HashtagObject hashtagObject = arrayList.get(a); + state.requery(); + state.bindString(1, hashtagObject.hashtag); + state.bindInteger(2, hashtagObject.date); + state.step(); + } + state.dispose(); + MessagesStorage.getInstance().getDatabase().commitTransaction(); + if (arrayList.size() >= 100) { + MessagesStorage.getInstance().getDatabase().beginTransaction(); + for (int a = 100; a < arrayList.size(); a++) { + MessagesStorage.getInstance().getDatabase().executeFast("DELETE FROM hashtag_recent_v2 WHERE id = '" + arrayList.get(a).hashtag + "'").stepThis().dispose(); + } + MessagesStorage.getInstance().getDatabase().commitTransaction(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + public void clearRecentHashtags() { + hashtags = new ArrayList<>(); + hashtagsByText = new HashMap<>(); + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + MessagesStorage.getInstance().getDatabase().executeFast("DELETE FROM hashtag_recent_v2 WHERE 1").stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + protected void setHashtags(ArrayList arrayList, HashMap hashMap) { + hashtags = arrayList; + hashtagsByText = hashMap; + hashtagsLoadedFromDb = true; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ChatActivityAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ChatActivityAdapter.java index 183076a7..f01a9184 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ChatActivityAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ChatActivityAdapter.java @@ -202,7 +202,7 @@ public class ChatActivityAdapter { Intent intent = new Intent(Intent.ACTION_VIEW); if (message.type == 8 || message.type == 9) { MimeTypeMap myMime = MimeTypeMap.getSingleton(); - int idx = fileName.lastIndexOf("."); + int idx = fileName.lastIndexOf('.'); if (idx != -1) { String ext = fileName.substring(idx + 1); realMimeType = myMime.getMimeTypeFromExtension(ext.toLowerCase()); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsAdapter.java index c7ff8a43..869fc05e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/ContactsAdapter.java @@ -259,7 +259,7 @@ public class ContactsAdapter extends BaseSectionsAdapter { } } else if (type == 0) { if (convertView == null) { - convertView = new UserCell(mContext, 58, 1); + convertView = new UserCell(mContext, 58, 1, false); ((UserCell) convertView).setStatusColors(0xffa8a8a8, 0xff3b84c0); convertView.setTag("Contacts"); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java index e3631429..ad060006 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsAdapter.java @@ -58,7 +58,6 @@ public class DialogsAdapter extends RecyclerView.Adapter { } private ArrayList getDialogsArray() { - //SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); if (dialogsType == 0) { boolean hideTabs = plusPreferences.getBoolean("hideTabs", false); @@ -136,6 +135,11 @@ public class DialogsAdapter extends RecyclerView.Adapter { return null; } //plus + public void sort(){ + getDialogsArray(); + notifyDataSetChanged(); + } + private void sortUsersByStatus(){ Collections.sort(MessagesController.getInstance().dialogsUsers, new Comparator() { @Override @@ -227,35 +231,6 @@ public class DialogsAdapter extends RecyclerView.Adapter { }); } - /*private void sortAllDefault(ArrayList dialogs){ - Collections.sort(dialogs, new Comparator() { - @Override - public int compare(TLRPC.Dialog dialog, TLRPC.Dialog dialog2) { - if (dialog.last_message_date == dialog2.last_message_date) { - return 0; - } else if (dialog.last_message_date < dialog2.last_message_date) { - return 1; - } else { - return -1; - } - } - }); - } - - private void sortAllUnread(ArrayList dialogs){ - Collections.sort(dialogs, new Comparator() { - @Override - public int compare(TLRPC.Dialog dialog, TLRPC.Dialog dialog2) { - if (dialog.unread_count == dialog2.unread_count) { - return 0; - } else if (dialog.unread_count < dialog2.unread_count) { - return 1; - } else { - return -1; - } - } - }); - }*/ // @Override public int getItemCount() { @@ -278,6 +253,13 @@ public class DialogsAdapter extends RecyclerView.Adapter { return arrayList.get(i); } + @Override + public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { + if (holder.itemView instanceof DialogCell) { + ((DialogCell) holder.itemView).checkCurrentDialogIndex(); + } + } + @Override public long getItemId(int i) { return i; @@ -291,6 +273,7 @@ public class DialogsAdapter extends RecyclerView.Adapter { } else if (viewType == 1) { view = new LoadingCell(mContext); } + view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)); if(dialogsType > 2 && viewType == 1)view.setVisibility(View.GONE); SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); int mainColor = themePrefs.getInt("chatsRowColor", 0xffffffff); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java index 725d779a..de9f5d9e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DialogsSearchAdapter.java @@ -333,7 +333,7 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler { recentSearchObjects.add(0, recentSearchObject); recentSearchObject.did = did; recentSearchObject.object = object; - recentSearchObject.date = (int) System.currentTimeMillis() / 1000; + recentSearchObject.date = (int) (System.currentTimeMillis() / 1000); notifyDataSetChanged(); MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { @Override @@ -342,7 +342,7 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler { SQLitePreparedStatement state = MessagesStorage.getInstance().getDatabase().executeFast("REPLACE INTO search_recent VALUES(?, ?)"); state.requery(); state.bindLong(1, did); - state.bindInteger(2, (int) System.currentTimeMillis() / 1000); + state.bindInteger(2, (int) (System.currentTimeMillis() / 1000)); state.step(); state.dispose(); } catch (Exception e) { @@ -887,6 +887,7 @@ public class DialogsSearchAdapter extends BaseSearchAdapterRecycler { view = new HashtagSearchCell(mContext); break; } + view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)); return new Holder(view); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java index 7a6742ba..e363d557 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/DrawerLayoutAdapter.java @@ -157,7 +157,23 @@ public class DrawerLayoutAdapter extends BaseAdapter { if (i == versionRow) { try { PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); - ((TextInfoCell) view).setText(String.format(Locale.US, LocaleController.getString("TelegramForAndroid", R.string.TelegramForAndroid)+" v%s (%d)", pInfo.versionName, pInfo.versionCode)); + int code = pInfo.versionCode / 10; + String abi = ""; + switch (pInfo.versionCode % 10) { + case 0: + abi = "arm"; + break; + case 1: + abi = "arm-v7a"; + break; + case 2: + abi = "x86"; + break; + case 3: + abi = "universal"; + break; + } + ((TextInfoCell) view).setText(String.format(Locale.US, LocaleController.getString("TelegramForAndroid", R.string.TelegramForAndroid)+ "\nv%s (%d) %s", pInfo.versionName, code, abi)); ((TextInfoCell) view).setTextColor(themePrefs.getInt("drawerVersionColor", 0xffa3a3a3)); ((TextInfoCell) view).setTextSize(themePrefs.getInt("drawerVersionSize", 13)); } catch (Exception e) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java index d528b6d9..dc0e10b6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/MentionsAdapter.java @@ -8,17 +8,29 @@ package org.telegram.ui.Adapters; +import android.Manifest; +import android.app.Activity; +import android.app.AlertDialog; import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.location.Location; +import android.os.Build; import android.view.View; import android.view.ViewGroup; import org.telegram.SQLite.SQLiteCursor; import org.telegram.SQLite.SQLitePreparedStatement; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.R; +import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.UserObject; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.messenger.support.widget.RecyclerView; @@ -26,6 +38,8 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Cells.BotSwitchCell; import org.telegram.ui.Cells.ContextLinkCell; import org.telegram.ui.Cells.MentionCell; @@ -42,7 +56,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { void onContextClick(TLRPC.BotInlineResult result); } - private class Holder extends RecyclerView.ViewHolder { + public class Holder extends RecyclerView.ViewHolder { public Holder(View itemView) { super(itemView); @@ -50,6 +64,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { } private Context mContext; + private long dialog_id; private TLRPC.ChatFull info; private ArrayList botRecent; private ArrayList searchResultUsernames; @@ -58,6 +73,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { private ArrayList searchResultCommandsHelp; private ArrayList searchResultCommandsUsers; private ArrayList searchResultBotContext; + private TLRPC.TL_inlineBotSwitchPM searchResultBotContextSwitch; private HashMap searchResultBotContextById; private MentionsAdapterDelegate delegate; private HashMap botInfo; @@ -71,6 +87,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { private boolean isDarkTheme; private int botsCount; private boolean loadingBotRecent; + private boolean botRecentLoaded; private String searchingContextUsername; private String searchingContextQuery; @@ -81,11 +98,62 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { private TLRPC.User foundContextBot; private boolean contextMedia; private Runnable contextQueryRunnable; + private Location lastKnownLocation; - public MentionsAdapter(Context context, boolean isDarkTheme, MentionsAdapterDelegate delegate) { + private BaseFragment parentFragment; + + private SendMessagesHelper.LocationProvider locationProvider = new SendMessagesHelper.LocationProvider(new SendMessagesHelper.LocationProvider.LocationProviderDelegate() { + @Override + public void onLocationAcquired(Location location) { + if (foundContextBot != null && foundContextBot.bot_inline_geo) { + lastKnownLocation = location; + searchForContextBotResults(foundContextBot, searchingContextQuery, ""); + } + } + + @Override + public void onUnableLocationAcquire() { + onLocationUnavailable(); + } + }) { + @Override + public void stop() { + super.stop(); + lastKnownLocation = null; + } + }; + + public MentionsAdapter(Context context, boolean isDarkTheme, long did, MentionsAdapterDelegate delegate) { mContext = context; this.delegate = delegate; this.isDarkTheme = isDarkTheme; + dialog_id = did; + } + + public void onDestroy() { + if (locationProvider != null) { + locationProvider.stop(); + } + if (contextQueryRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(contextQueryRunnable); + contextQueryRunnable = null; + } + if (contextUsernameReqid != 0) { + ConnectionsManager.getInstance().cancelRequest(contextUsernameReqid, true); + contextUsernameReqid = 0; + } + if (contextQueryReqid != 0) { + ConnectionsManager.getInstance().cancelRequest(contextQueryReqid, true); + contextQueryReqid = 0; + } + foundContextBot = null; + searchingContextUsername = null; + searchingContextQuery = null; + noUserName = false; + } + + public void setParentFragment(BaseFragment fragment) { + parentFragment = fragment; } public void setChatInfo(TLRPC.ChatFull chatParticipants) { @@ -96,7 +164,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { } private void loadBotRecent() { - if (loadingBotRecent) { + if (loadingBotRecent || botRecentLoaded) { return; } loadingBotRecent = true; @@ -114,12 +182,27 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { } cursor.dispose(); if (uids != null) { + final ArrayList uidsFinal = uids; final ArrayList users = MessagesStorage.getInstance().getUsers(uids); + Collections.sort(users, new Comparator() { + @Override + public int compare(TLRPC.User lhs, TLRPC.User rhs) { + int idx1 = uidsFinal.indexOf(lhs.id); + int idx2 = uidsFinal.indexOf(rhs.id); + if (idx1 > idx2) { + return 1; + } else if (idx1 < idx2) { + return -1; + } + return 0; + } + }); AndroidUtilities.runOnUIThread(new Runnable() { @Override public void run() { botRecent = users; loadingBotRecent = false; + botRecentLoaded = true; if (lastText != null) { searchUsernameOrHashtag(lastText, lastPosition, messages); } @@ -130,6 +213,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { @Override public void run() { loadingBotRecent = false; + botRecentLoaded = true; } }); } @@ -237,13 +321,26 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { } } + public TLRPC.TL_inlineBotSwitchPM getBotContextSwitch() { + return searchResultBotContextSwitch; + } + public int getContextBotId() { return foundContextBot != null ? foundContextBot.id : 0; } + public TLRPC.User getContextBotUser() { + return foundContextBot != null ? foundContextBot : null; + } + + public String getContextBotName() { + return foundContextBot != null ? foundContextBot.username : ""; + } + private void searchForContextBot(final String username, final String query) { searchResultBotContext = null; searchResultBotContextById = null; + searchResultBotContextSwitch = null; notifyDataSetChanged(); if (foundContextBot != null) { delegate.needChangePanelVisibility(false); @@ -264,6 +361,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { foundContextBot = null; searchingContextUsername = null; searchingContextQuery = null; + locationProvider.stop(); noUserName = false; if (delegate != null) { delegate.onContextSearch(false); @@ -318,6 +416,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { } contextUsernameReqid = 0; foundContextBot = null; + locationProvider.stop(); if (error == null) { TLRPC.TL_contacts_resolvedPeer res = (TLRPC.TL_contacts_resolvedPeer) response; if (!res.users.isEmpty()) { @@ -326,6 +425,35 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { MessagesController.getInstance().putUser(user, false); MessagesStorage.getInstance().putUsersAndChats(res.users, null, true, true); foundContextBot = user; + if (foundContextBot.bot_inline_geo) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + boolean allowGeo = preferences.getBoolean("inlinegeo_" + foundContextBot.id, false); + if (!allowGeo && parentFragment != null && parentFragment.getParentActivity() != null) { + final TLRPC.User foundContextBotFinal = foundContextBot; + AlertDialog.Builder builder = new AlertDialog.Builder(parentFragment.getParentActivity()); + builder.setTitle(LocaleController.getString("ShareYouLocationTitle", R.string.ShareYouLocationTitle)); + builder.setMessage(LocaleController.getString("ShareYouLocationInline", R.string.ShareYouLocationInline)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (foundContextBotFinal != null) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + preferences.edit().putBoolean("inlinegeo_" + foundContextBotFinal.id, true).commit(); + checkLocationPermissionsOrStart(); + } + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + onLocationUnavailable(); + } + }); + parentFragment.showDialog(builder.create()); + } else { + checkLocationPermissionsOrStart(); + } + } } } } @@ -348,6 +476,28 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { AndroidUtilities.runOnUIThread(contextQueryRunnable, 400); } + private void onLocationUnavailable() { + if (foundContextBot != null && foundContextBot.bot_inline_geo) { + lastKnownLocation = new Location("network"); + lastKnownLocation.setLatitude(-1000); + lastKnownLocation.setLongitude(-1000); + searchForContextBotResults(foundContextBot, searchingContextQuery, ""); + } + } + + private void checkLocationPermissionsOrStart() { + if (parentFragment == null || parentFragment.getParentActivity() == null) { + return; + } + if (Build.VERSION.SDK_INT >= 23 && parentFragment.getParentActivity().checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + parentFragment.getParentActivity().requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 2); + return; + } + if (foundContextBot != null && foundContextBot.bot_inline_geo) { + locationProvider.start(); + } + } + public int getOrientation() { return searchResultBotContext != null && !searchResultBotContext.isEmpty() && contextMedia ? LinearLayoutManager.HORIZONTAL : LinearLayoutManager.VERTICAL; } @@ -377,10 +527,26 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { searchingContextQuery = null; return; } + if (user.bot_inline_geo && lastKnownLocation == null) { + return; + } TLRPC.TL_messages_getInlineBotResults req = new TLRPC.TL_messages_getInlineBotResults(); req.bot = MessagesController.getInputUser(user); req.query = query; req.offset = offset; + if (user.bot_inline_geo && lastKnownLocation != null && lastKnownLocation.getLatitude() != -1000) { + req.flags |= 1; + req.geo_point = new TLRPC.TL_inputGeoPoint(); + req.geo_point.lat = lastKnownLocation.getLatitude(); + req.geo_point._long = lastKnownLocation.getLongitude(); + } + int lower_id = (int) dialog_id; + int high_id = (int) (dialog_id >> 32); + if (lower_id != 0) { + req.peer = MessagesController.getInputPeer(lower_id); + } else { + req.peer = new TLRPC.TL_inputPeerEmpty(); + } contextQueryReqid = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { @Override public void run(final TLObject response, final TLRPC.TL_error error) { @@ -399,6 +565,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { nextQueryOffset = res.next_offset; if (searchResultBotContextById == null) { searchResultBotContextById = new HashMap<>(); + searchResultBotContextSwitch = res.switch_pm; } for (int a = 0; a < res.results.size(); a++) { TLRPC.BotInlineResult result = res.results.get(a); @@ -412,6 +579,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { boolean added = false; if (searchResultBotContext == null || offset.length() == 0) { searchResultBotContext = res.results; + contextMedia = res.gallery; } else { added = true; searchResultBotContext.addAll(res.results); @@ -419,18 +587,19 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { nextQueryOffset = ""; } } - contextMedia = res.gallery; searchResultHashtags = null; searchResultUsernames = null; searchResultCommands = null; searchResultCommandsHelp = null; searchResultCommandsUsers = null; if (added) { - notifyItemRangeInserted(searchResultBotContext.size() - res.results.size(), res.results.size()); + boolean hasTop = getOrientation() == LinearLayoutManager.VERTICAL && searchResultBotContextSwitch != null; + notifyItemChanged(searchResultBotContext.size() - res.results.size() + (hasTop ? 1 : 0) - 1); + notifyItemRangeInserted(searchResultBotContext.size() - res.results.size() + (hasTop ? 1 : 0), res.results.size()); } else { notifyDataSetChanged(); } - delegate.needChangePanelVisibility(!searchResultBotContext.isEmpty()); + delegate.needChangePanelVisibility(!searchResultBotContext.isEmpty() || searchResultBotContextSwitch != null); } } }); @@ -457,7 +626,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { int index = text.indexOf(' '); if (index > 0) { String username = text.substring(1, index); - if (username.length() >= 3) { + if (username.length() >= 1) { for (int a = 1; a < username.length(); a++) { char ch = username.charAt(a); if (!(ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch == '_')) { @@ -488,7 +657,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { char ch = text.charAt(a); if (a == 0 || text.charAt(a - 1) == ' ' || text.charAt(a - 1) == '\n') { if (ch == '@') { - if (needUsernames || botRecent != null && a == 0) { + if (needUsernames || needBotContext && botRecent != null && a == 0) { if (hasIllegalUsernameCharacters) { delegate.needChangePanelVisibility(false); return; @@ -556,7 +725,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { String usernameString = result.toString().toLowerCase(); ArrayList newResult = new ArrayList<>(); final HashMap newResultsHashMap = new HashMap<>(); - if (dogPostion == 0 && botRecent != null) { + if (needBotContext && dogPostion == 0 && botRecent != null) { for (int a = 0; a < botRecent.size(); a++) { TLRPC.User user = botRecent.get(a); if (user.username != null && user.username.length() > 0 && (usernameString.length() > 0 && user.username.toLowerCase().startsWith(usernameString) || usernameString.length() == 0)) { @@ -609,7 +778,8 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { } else if (foundType == 1) { ArrayList newResult = new ArrayList<>(); String hashtagString = result.toString().toLowerCase(); - for (HashtagObject hashtagObject : hashtags) { + for (int a = 0; a < hashtags.size(); a++) { + HashtagObject hashtagObject = hashtags.get(a); if (hashtagObject != null && hashtagObject.hashtag != null && hashtagObject.hashtag.startsWith(hashtagString)) { newResult.add(hashtagObject.hashtag); } @@ -658,7 +828,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { @Override public int getItemCount() { if (searchResultBotContext != null) { - return searchResultBotContext.size(); + return searchResultBotContext.size() + (getOrientation() == LinearLayoutManager.VERTICAL && searchResultBotContextSwitch != null ? 1 : 0); } else if (searchResultUsernames != null) { return searchResultUsernames.size(); } else if (searchResultHashtags != null) { @@ -672,6 +842,9 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { @Override public int getItemViewType(int position) { if (searchResultBotContext != null) { + if (position == 0 && getOrientation() == LinearLayoutManager.VERTICAL && searchResultBotContextSwitch != null) { + return 2; + } return 1; } else { return 0; @@ -680,6 +853,14 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { public Object getItem(int i) { if (searchResultBotContext != null) { + boolean hasTop = getOrientation() == LinearLayoutManager.VERTICAL && searchResultBotContextSwitch != null; + if (hasTop) { + if (i == 0) { + return searchResultBotContextSwitch; + } else { + i--; + } + } if (i < 0 || i >= searchResultBotContext.size()) { return null; } @@ -711,7 +892,7 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { } public boolean isLongClickEnabled() { - return searchResultHashtags != null; + return searchResultHashtags != null || searchResultCommands != null; } public boolean isBotCommands() { @@ -733,6 +914,8 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { delegate.onContextClick(cell.getResult()); } }); + } else if (viewType == 2) { + view = new BotSwitchCell(mContext); } else { view = new MentionCell(mContext); ((MentionCell) view).setIsDarkTheme(isDarkTheme); @@ -743,7 +926,17 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { if (searchResultBotContext != null) { - ((ContextLinkCell) holder.itemView).setLink(searchResultBotContext.get(position), contextMedia, position != searchResultBotContext.size() - 1); + boolean hasTop = getOrientation() == LinearLayoutManager.VERTICAL && searchResultBotContextSwitch != null; + if (holder.getItemViewType() == 2) { + if (hasTop) { + ((BotSwitchCell) holder.itemView).setText(searchResultBotContextSwitch.text); + } + } else { + if (hasTop) { + position--; + } + ((ContextLinkCell) holder.itemView).setLink(searchResultBotContext.get(position), contextMedia, position != searchResultBotContext.size() - 1, hasTop && position == 0); + } } else { if (searchResultUsernames != null) { ((MentionCell) holder.itemView).setUser(searchResultUsernames.get(position)); @@ -754,4 +947,16 @@ public class MentionsAdapter extends BaseSearchAdapterRecycler { } } } + + public void onRequestPermissionsResultFragment(int requestCode, String[] permissions, int[] grantResults) { + if (requestCode == 2) { + if (foundContextBot != null && foundContextBot.bot_inline_geo) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + locationProvider.start(); + } else { + onLocationUnavailable(); + } + } + } + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java index 08ae3a64..11a5651b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Adapters/SearchAdapter.java @@ -238,7 +238,7 @@ public class SearchAdapter extends BaseSearchAdapter { } else { if (view == null) { if (useUserCell) { - view = new UserCell(mContext, 1, 1); + view = new UserCell(mContext, 1, 1, false); if (checkedMap != null) { ((UserCell) view).setChecked(false, false); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/AudioPlayerActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/AudioPlayerActivity.java new file mode 100644 index 00000000..364008f6 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/AudioPlayerActivity.java @@ -0,0 +1,484 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ImageLoader; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.audioinfo.AudioInfo; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LineProgressView; + +import java.io.File; + +public class AudioPlayerActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, MediaController.FileDownloadProgressListener { + + private MessageObject lastMessageObject; + private ImageView placeholder; + private ImageView playButton; + private ImageView nextButton; + private ImageView prevButton; + private ImageView shuffleButton; + private LineProgressView progressView; + private ImageView repeatButton; + private ImageView[] buttons = new ImageView[5]; + private TextView durationTextView; + private TextView timeTextView; + private SeekBarView seekBarView; + + private int TAG; + + private String lastTimeString; + + private class SeekBarView extends FrameLayout { + + private Paint innerPaint1; + private Paint outerPaint1; + private int thumbWidth; + private int thumbHeight; + public int thumbX = 0; + public int thumbDX = 0; + private boolean pressed = false; + + public SeekBarView(Context context) { + super(context); + setWillNotDraw(false); + innerPaint1 = new Paint(Paint.ANTI_ALIAS_FLAG); + innerPaint1.setColor(0x19000000); + + outerPaint1 = new Paint(Paint.ANTI_ALIAS_FLAG); + outerPaint1.setColor(0xff23afef); + + thumbWidth = AndroidUtilities.dp(24); + thumbHeight = AndroidUtilities.dp(24); + } + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return onTouch(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + return onTouch(event); + } + + boolean onTouch(MotionEvent ev) { + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + getParent().requestDisallowInterceptTouchEvent(true); + int additionWidth = (getMeasuredHeight() - thumbWidth) / 2; + if (thumbX - additionWidth <= ev.getX() && ev.getX() <= thumbX + thumbWidth + additionWidth && ev.getY() >= 0 && ev.getY() <= getMeasuredHeight()) { + pressed = true; + thumbDX = (int)(ev.getX() - thumbX); + invalidate(); + return true; + } + } else if (ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL) { + if (pressed) { + if (ev.getAction() == MotionEvent.ACTION_UP) { + onSeekBarDrag((float) thumbX / (float) (getMeasuredWidth() - thumbWidth)); + } + pressed = false; + invalidate(); + return true; + } + } else if (ev.getAction() == MotionEvent.ACTION_MOVE) { + if (pressed) { + thumbX = (int)(ev.getX() - thumbDX); + if (thumbX < 0) { + thumbX = 0; + } else if (thumbX > getMeasuredWidth() - thumbWidth) { + thumbX = getMeasuredWidth() - thumbWidth; + } + invalidate(); + return true; + } + } + return false; + } + + public void setProgress(float progress) { + int newThumbX = (int)Math.ceil((getMeasuredWidth() - thumbWidth) * progress); + if (thumbX != newThumbX) { + thumbX = newThumbX; + if (thumbX < 0) { + thumbX = 0; + } else if (thumbX > getMeasuredWidth() - thumbWidth) { + thumbX = getMeasuredWidth() - thumbWidth; + } + invalidate(); + } + } + + public boolean isDragging() { + return pressed; + } + + @Override + protected void onDraw(Canvas canvas) { + int y = (getMeasuredHeight() - thumbHeight) / 2; + canvas.drawRect(thumbWidth / 2, getMeasuredHeight() / 2 - AndroidUtilities.dp(1), getMeasuredWidth() - thumbWidth / 2, getMeasuredHeight() / 2 + AndroidUtilities.dp(1), innerPaint1); + canvas.drawRect(thumbWidth / 2, getMeasuredHeight() / 2 - AndroidUtilities.dp(1), thumbWidth / 2 + thumbX, getMeasuredHeight() / 2 + AndroidUtilities.dp(1), outerPaint1); + canvas.drawCircle(thumbX + thumbWidth / 2, y + thumbHeight / 2, AndroidUtilities.dp(pressed ? 8 : 6), outerPaint1); + } + } + + @Override + public boolean onFragmentCreate() { + TAG = MediaController.getInstance().generateObserverTag(); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioDidReset); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioPlayStateChanged); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioDidStarted); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioProgressDidChanged); + return super.onFragmentCreate(); + } + + @Override + public void onFragmentDestroy() { + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioDidReset); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioPlayStateChanged); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioDidStarted); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioProgressDidChanged); + MediaController.getInstance().removeLoadingFileObserver(this); + super.onFragmentDestroy(); + } + + @Override + public View createView(Context context) { + FrameLayout frameLayout = new FrameLayout(context); + frameLayout.setBackgroundColor(0xfff0f0f0); + frameLayout.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + fragmentView = frameLayout; + + actionBar.setBackgroundColor(Theme.ACTION_BAR_PLAYER_COLOR); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int hColor = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + int tColor = hColor != 0xffffffff ? 0xffffffff : 0xff212121; + Drawable back = context.getResources().getDrawable(R.drawable.pl_back); + back.setColorFilter(tColor, PorterDuff.Mode.SRC_IN); + actionBar.setBackButtonDrawable(back); + //actionBar.setBackButtonImage(R.drawable.pl_back); + actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_AUDIO_SELECTOR_COLOR); + if (!AndroidUtilities.isTablet()) { + actionBar.showActionModeTop(); + } + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + + placeholder = new ImageView(context); + frameLayout.addView(placeholder, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 66)); + + View shadow = new View(context); + shadow.setBackgroundResource(R.drawable.header_shadow_reverse); + frameLayout.addView(shadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 3, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 96)); + + FrameLayout seekBarContainer = new FrameLayout(context); + seekBarContainer.setBackgroundColor(0xe5ffffff); + frameLayout.addView(seekBarContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 30, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 66)); + + timeTextView = new TextView(context); + timeTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); + timeTextView.setTextColor(0xff19a7e8); + timeTextView.setGravity(Gravity.CENTER); + timeTextView.setText("0:00"); + seekBarContainer.addView(timeTextView, LayoutHelper.createFrame(44, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); + + durationTextView = new TextView(context); + durationTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); + durationTextView.setTextColor(0xff8a8a8a); + durationTextView.setGravity(Gravity.CENTER); + durationTextView.setText("3:00"); + seekBarContainer.addView(durationTextView, LayoutHelper.createFrame(44, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); + + seekBarView = new SeekBarView(context); + seekBarContainer.addView(seekBarView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 32, 0, 32, 0)); + + progressView = new LineProgressView(context); + progressView.setVisibility(View.INVISIBLE); + progressView.setBackgroundColor(0x19000000); + progressView.setProgressColor(0xff23afef); + seekBarContainer.addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 2, Gravity.CENTER_VERTICAL | Gravity.LEFT, 44, 0, 44, 0)); + + FrameLayout bottomView = new FrameLayout(context) { + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + int dist = ((right - left) - AndroidUtilities.dp(30 + 48 * 5)) / 4; + for (int a = 0; a < 5; a++) { + int l = AndroidUtilities.dp(15 + 48 * a) + dist * a; + int t = AndroidUtilities.dp(9); + buttons[a].layout(l, t, l + buttons[a].getMeasuredWidth(), t + buttons[a].getMeasuredHeight()); + } + } + }; + bottomView.setBackgroundColor(0xffffffff); + frameLayout.addView(bottomView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 66, Gravity.BOTTOM | Gravity.LEFT)); + + buttons[0] = repeatButton = new ImageView(context); + repeatButton.setScaleType(ImageView.ScaleType.CENTER); + bottomView.addView(repeatButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); + repeatButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MediaController.getInstance().toggleRepeatMode(); + updateRepeatButton(); + } + }); + + buttons[1] = prevButton = new ImageView(context); + prevButton.setScaleType(ImageView.ScaleType.CENTER); + prevButton.setImageResource(R.drawable.player_prev_states); + bottomView.addView(prevButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); + prevButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MediaController.getInstance().playPreviousMessage(); + } + }); + + buttons[2] = playButton = new ImageView(context); + playButton.setScaleType(ImageView.ScaleType.CENTER); + playButton.setImageResource(R.drawable.player_play_states); + bottomView.addView(playButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); + playButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (MediaController.getInstance().isDownloadingCurrentMessage()) { + return; + } + if (MediaController.getInstance().isAudioPaused()) { + MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject()); + } else { + MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject()); + } + } + }); + + buttons[3] = nextButton = new ImageView(context); + nextButton.setScaleType(ImageView.ScaleType.CENTER); + nextButton.setImageResource(R.drawable.player_next_states); + bottomView.addView(nextButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); + nextButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MediaController.getInstance().playNextMessage(); + } + }); + + buttons[4] = shuffleButton = new ImageView(context); + shuffleButton.setScaleType(ImageView.ScaleType.CENTER); + bottomView.addView(shuffleButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.TOP)); + shuffleButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MediaController.getInstance().toggleShuffleMusic(); + updateShuffleButton(); + } + }); + + updateTitle(false); + updateRepeatButton(); + updateShuffleButton(); + + return frameLayout; + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.audioDidStarted || id == NotificationCenter.audioPlayStateChanged || id == NotificationCenter.audioDidReset) { + updateTitle(id == NotificationCenter.audioDidReset && (Boolean) args[1]); + } else if (id == NotificationCenter.audioProgressDidChanged) { + MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); + + if (messageObject.isMusic()) { + updateProgress(messageObject); + } + } + } + + @Override + public void onFailedDownload(String fileName) { + + } + + @Override + public void onSuccessDownload(String fileName) { + + } + + @Override + public void onProgressDownload(String fileName, float progress) { + progressView.setProgress(progress, true); + } + + @Override + public void onProgressUpload(String fileName, float progress, boolean isEncrypted) { + + } + + @Override + public int getObserverTag() { + return TAG; + } + + private void onSeekBarDrag(float progress) { + MediaController.getInstance().seekToProgress(MediaController.getInstance().getPlayingMessageObject(), progress); + } + + private void updateShuffleButton() { + if (MediaController.getInstance().isShuffleMusic()) { + shuffleButton.setImageResource(R.drawable.pl_shuffle_active); + } else { + shuffleButton.setImageResource(R.drawable.pl_shuffle); + } + } + + private void updateRepeatButton() { + int mode = MediaController.getInstance().getRepeatMode(); + if (mode == 0) { + repeatButton.setImageResource(R.drawable.pl_repeat); + } else if (mode == 1) { + repeatButton.setImageResource(R.drawable.pl_repeat_active); + } else if (mode == 2) { + repeatButton.setImageResource(R.drawable.pl_repeat1_active); + } + } + + private void updateProgress(MessageObject messageObject) { + if (seekBarView != null) { + if (!seekBarView.isDragging()) { + seekBarView.setProgress(messageObject.audioProgress); + } + String timeString = String.format("%d:%02d", messageObject.audioProgressSec / 60, messageObject.audioProgressSec % 60); + if (lastTimeString == null || lastTimeString != null && !lastTimeString.equals(timeString)) { + lastTimeString = timeString; + timeTextView.setText(timeString); + } + } + } + + private void checkIfMusicDownloaded(MessageObject messageObject) { + File cacheFile = null; + if (messageObject.messageOwner.attachPath != null && messageObject.messageOwner.attachPath.length() > 0) { + cacheFile = new File(messageObject.messageOwner.attachPath); + if(!cacheFile.exists()) { + cacheFile = null; + } + } + if (cacheFile == null) { + cacheFile = FileLoader.getPathToMessage(messageObject.messageOwner); + } + if (!cacheFile.exists()) { + String fileName = messageObject.getFileName(); + MediaController.getInstance().addLoadingFileObserver(fileName, this); + Float progress = ImageLoader.getInstance().getFileProgress(fileName); + progressView.setProgress(progress != null ? progress : 0, false); + progressView.setVisibility(View.VISIBLE); + seekBarView.setVisibility(View.INVISIBLE); + playButton.setEnabled(false); + } else { + MediaController.getInstance().removeLoadingFileObserver(this); + progressView.setVisibility(View.INVISIBLE); + seekBarView.setVisibility(View.VISIBLE); + playButton.setEnabled(true); + } + } + + private void updateTitle(boolean shutdown) { + MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); + if (messageObject == null && shutdown || messageObject != null && !messageObject.isMusic()) { + if (parentLayout != null && !parentLayout.fragmentsStack.isEmpty() && parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 1) == this) { + finishFragment(); + } else { + removeSelfFromStack(); + } + } else { + if (messageObject == null) { + return; + } + checkIfMusicDownloaded(messageObject); + updateProgress(messageObject); + + if (MediaController.getInstance().isAudioPaused()) { + playButton.setImageResource(R.drawable.player_play_states); + } else { + playButton.setImageResource(R.drawable.player_pause_states); + } + if (actionBar != null) { + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int hColor = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + int tColor = hColor != 0xffffffff ? 0xffffffff : 0xff212121; + actionBar.setTitle(messageObject.getMusicTitle()); + //actionBar.getTitleTextView().setTextColor(0xff212121); + actionBar.getTitleTextView().setTextColor(tColor); + actionBar.setSubtitle(messageObject.getMusicAuthor()); + //actionBar.getSubTitleTextView().setTextColor(0xff8a8a8a); + //actionBar.getSubTitleTextView().setTextColor(tColor); + } + AudioInfo audioInfo = MediaController.getInstance().getAudioInfo(); + if (audioInfo != null && audioInfo.getCover() != null) { + placeholder.setImageBitmap(audioInfo.getCover()); + placeholder.setPadding(0, 0, 0, 0); + placeholder.setScaleType(ImageView.ScaleType.CENTER_CROP); + } else { + placeholder.setImageResource(R.drawable.nocover); + placeholder.setPadding(0, 0, 0, AndroidUtilities.dp(30)); + placeholder.setScaleType(ImageView.ScaleType.CENTER); + } + + if (durationTextView != null) { + int duration = 0; + TLRPC.Document document = messageObject.getDocument(); + if (document != null) { + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + duration = attribute.duration; + break; + } + } + } + durationTextView.setText(duration != 0 ? String.format("%d:%02d", duration / 60, duration % 60) : "-:--"); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/AudioSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/AudioSelectActivity.java new file mode 100644 index 00000000..ae365bbe --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/AudioSelectActivity.java @@ -0,0 +1,346 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.content.Context; +import android.database.Cursor; +import android.os.Build; +import android.provider.MediaStore; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.FrameLayout; +import android.widget.ListView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Adapters.BaseFragmentAdapter; +import org.telegram.ui.Cells.AudioCell; +import org.telegram.ui.Components.EmptyTextProgressView; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.PickerBottomLayout; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; + +public class AudioSelectActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + private ListAdapter listViewAdapter; + private EmptyTextProgressView progressView; + private PickerBottomLayout bottomLayout; + + private boolean loadingAudio; + + private ArrayList audioEntries = new ArrayList<>(); + private HashMap selectedAudios = new HashMap<>(); + + private AudioSelectActivityDelegate delegate; + + private MessageObject playingAudio; + + public interface AudioSelectActivityDelegate { + void didSelectAudio(ArrayList audios); + } + + @Override + public boolean onFragmentCreate() { + super.onFragmentCreate(); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.closeChats); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioDidReset); + loadAudio(); + return true; + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.closeChats); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioDidReset); + if (playingAudio != null && MediaController.getInstance().isPlayingAudio(playingAudio)) { + MediaController.getInstance().cleanupPlayer(true, true); + } + } + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(LocaleController.getString("AttachMusic", R.string.AttachMusic)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + + fragmentView = new FrameLayout(context); + FrameLayout frameLayout = (FrameLayout) fragmentView; + + progressView = new EmptyTextProgressView(context); + progressView.setText(LocaleController.getString("NoAudio", R.string.NoAudio)); + frameLayout.addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + ListView listView = new ListView(context); + listView.setEmptyView(progressView); + listView.setVerticalScrollBarEnabled(false); + listView.setDivider(null); + listView.setDividerHeight(0); + listView.setAdapter(listViewAdapter = new ListAdapter(context)); + if (Build.VERSION.SDK_INT >= 11) { + listView.setVerticalScrollbarPosition(LocaleController.isRTL ? ListView.SCROLLBAR_POSITION_LEFT : ListView.SCROLLBAR_POSITION_RIGHT); + } + frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP, 0, 0, 0, 48)); + + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + AudioCell audioCell = (AudioCell) view; + MediaController.AudioEntry audioEntry = audioCell.getAudioEntry(); + if (selectedAudios.containsKey(audioEntry.id)) { + selectedAudios.remove(audioEntry.id); + audioCell.setChecked(false); + } else { + selectedAudios.put(audioEntry.id, audioEntry); + audioCell.setChecked(true); + } + updateBottomLayoutCount(); + } + }); + + bottomLayout = new PickerBottomLayout(context, false); + frameLayout.addView(bottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM)); + bottomLayout.cancelButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + finishFragment(); + } + }); + bottomLayout.doneButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (delegate != null) { + ArrayList audios = new ArrayList<>(); + for (HashMap.Entry entry : selectedAudios.entrySet()) { + audios.add(entry.getValue().messageObject); + } + delegate.didSelectAudio(audios); + } + finishFragment(); + } + }); + + View shadow = new View(context); + shadow.setBackgroundResource(R.drawable.header_shadow_reverse); + frameLayout.addView(shadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 3, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 48)); + + if (loadingAudio) { + progressView.showProgress(); + } else { + progressView.showTextView(); + } + updateBottomLayoutCount(); + return fragmentView; + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.closeChats) { + removeSelfFromStack(); + } else if (id == NotificationCenter.audioDidReset) { + if (listViewAdapter != null) { + listViewAdapter.notifyDataSetChanged(); + } + } + } + + private void updateBottomLayoutCount() { + bottomLayout.updateSelectedCount(selectedAudios.size(), true); + } + + public void setDelegate(AudioSelectActivityDelegate audioSelectActivityDelegate) { + delegate = audioSelectActivityDelegate; + } + + private void loadAudio() { + loadingAudio = true; + if (progressView != null) { + progressView.showProgress(); + } + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + String[] projection = { + MediaStore.Audio.Media._ID, + MediaStore.Audio.Media.ARTIST, + MediaStore.Audio.Media.TITLE, + MediaStore.Audio.Media.DATA, + MediaStore.Audio.Media.DURATION, + MediaStore.Audio.Media.ALBUM + }; + + final ArrayList newAudioEntries = new ArrayList<>(); + Cursor cursor = null; + try { + cursor = ApplicationLoader.applicationContext.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, projection, MediaStore.Audio.Media.IS_MUSIC + " != 0", null, MediaStore.Audio.Media.TITLE); + int id = -2000000000; + while (cursor.moveToNext()) { + MediaController.AudioEntry audioEntry = new MediaController.AudioEntry(); + audioEntry.id = cursor.getInt(0); + audioEntry.author = cursor.getString(1); + audioEntry.title = cursor.getString(2); + audioEntry.path = cursor.getString(3); + audioEntry.duration = (int) (cursor.getLong(4) / 1000); + audioEntry.genre = cursor.getString(5); + + File file = new File(audioEntry.path); + + TLRPC.TL_message message = new TLRPC.TL_message(); + message.out = true; + message.id = id; + message.to_id = new TLRPC.TL_peerUser(); + message.to_id.user_id = message.from_id = UserConfig.getClientUserId(); + message.date = (int) (System.currentTimeMillis() / 1000); + message.message = "-1"; + message.attachPath = audioEntry.path; + message.media = new TLRPC.TL_messageMediaDocument(); + message.media.document = new TLRPC.TL_document(); + message.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA | TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + + String ext = FileLoader.getFileExtension(file); + + message.media.document.id = 0; + message.media.document.access_hash = 0; + message.media.document.date = message.date; + message.media.document.mime_type = "audio/" + (ext.length() > 0 ? ext : "mp3"); + message.media.document.size = (int) file.length(); + message.media.document.thumb = new TLRPC.TL_photoSizeEmpty(); + message.media.document.thumb.type = "s"; + message.media.document.dc_id = 0; + + TLRPC.TL_documentAttributeAudio attributeAudio = new TLRPC.TL_documentAttributeAudio(); + attributeAudio.duration = audioEntry.duration; + attributeAudio.title = audioEntry.title; + attributeAudio.performer = audioEntry.author; + attributeAudio.flags |= 3; + message.media.document.attributes.add(attributeAudio); + + TLRPC.TL_documentAttributeFilename fileName = new TLRPC.TL_documentAttributeFilename(); + fileName.file_name = file.getName(); + message.media.document.attributes.add(fileName); + + audioEntry.messageObject = new MessageObject(message, null, false); + + newAudioEntries.add(audioEntry); + id--; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + if (cursor != null) { + cursor.close(); + } + } + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + audioEntries = newAudioEntries; + progressView.showTextView(); + listViewAdapter.notifyDataSetChanged(); + } + }); + } + }); + } + + private class ListAdapter extends BaseFragmentAdapter { + private Context mContext; + + public ListAdapter(Context context) { + mContext = context; + } + + @Override + public boolean areAllItemsEnabled() { + return true; + } + + @Override + public boolean isEnabled(int i) { + return true; + } + + @Override + public int getCount() { + return audioEntries.size(); + } + + @Override + public Object getItem(int i) { + return audioEntries.get(i); + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public boolean hasStableIds() { + return false; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + int type = getItemViewType(i); + if (view == null) { + view = new AudioCell(mContext); + ((AudioCell) view).setDelegate(new AudioCell.AudioCellDelegate() { + @Override + public void startedPlayingAudio(MessageObject messageObject) { + playingAudio = messageObject; + } + }); + } + MediaController.AudioEntry audioEntry = audioEntries.get(i); + ((AudioCell) view).setAudio(audioEntries.get(i), i != audioEntries.size() - 1, selectedAudios.containsKey(audioEntry.id)); + return view; + } + + @Override + public int getItemViewType(int i) { + return 0; + } + + @Override + public int getViewTypeCount() { + return 1; + } + + @Override + public boolean isEmpty() { + return audioEntries.isEmpty(); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/BlockedUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/BlockedUsersActivity.java index 7ed17b2d..173173c7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/BlockedUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/BlockedUsersActivity.java @@ -288,14 +288,22 @@ public class BlockedUsersActivity extends BaseFragment implements NotificationCe SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); if (type == 0) { if (view == null) { - view = new UserCell(mContext, 1, 0); + view = new UserCell(mContext, 1, 0, false); view.setTag("Pref"); } ((UserCell) view).setNameColor(preferences.getInt("prefTitleColor", 0xff212121)); ((UserCell) view).setStatusColor(preferences.getInt("prefSummaryColor", 0xff8a8a8a)); TLRPC.User user = MessagesController.getInstance().getUser(MessagesController.getInstance().blockedUsers.get(i)); if (user != null) { - ((UserCell) view).setData(user, null, user.phone != null && user.phone.length() != 0 ? PhoneFormat.getInstance().format("+" + user.phone) : LocaleController.getString("NumberUnknown", R.string.NumberUnknown), 0); + String number; + if (user.bot) { + number = LocaleController.getString("Bot", R.string.Bot).substring(0, 1).toUpperCase() + LocaleController.getString("Bot", R.string.Bot).substring(1); + } else if (user.phone != null && user.phone.length() != 0) { + number = PhoneFormat.getInstance().format("+" + user.phone); + } else { + number = LocaleController.getString("NumberUnknown", R.string.NumberUnknown); + } + ((UserCell) view).setData(user, null, number, 0); } } else if (type == 1) { if (view == null) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java new file mode 100644 index 00000000..81eb9220 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/CacheControlActivity.java @@ -0,0 +1,681 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.app.Activity; +import android.app.AlarmManager; +import android.app.AlertDialog; +import android.app.PendingIntent; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.ListView; + +import org.telegram.SQLite.SQLiteCursor; +import org.telegram.SQLite.SQLiteDatabase; +import org.telegram.SQLite.SQLitePreparedStatement; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ClearCacheService; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageLoader; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.messenger.query.BotQuery; +import org.telegram.tgnet.NativeByteBuffer; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.Adapters.BaseFragmentAdapter; +import org.telegram.ui.Cells.CheckBoxCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Cells.TextSettingsCell; +import org.telegram.ui.Components.LayoutHelper; + +import java.io.File; +import java.util.ArrayList; + +public class CacheControlActivity extends BaseFragment { + + private ListAdapter listAdapter; + + private int databaseRow; + private int databaseInfoRow; + private int keepMediaRow; + private int keepMediaInfoRow; + private int cacheRow; + private int cacheInfoRow; + private int rowCount; + + private long databaseSize = -1; + private long cacheSize = -1; + private long documentsSize = -1; + private long audioSize = -1; + private long musicSize = -1; + private long photoSize = -1; + private long videoSize = -1; + private long totalSize = -1; + private boolean clear[] = new boolean[6]; + private boolean calculating = true; + + private volatile boolean canceled = false; + + @Override + public boolean onFragmentCreate() { + super.onFragmentCreate(); + + rowCount = 0; + keepMediaRow = rowCount++; + keepMediaInfoRow = rowCount++; + cacheRow = rowCount++; + cacheInfoRow = rowCount++; + + databaseRow = rowCount++; + databaseInfoRow = rowCount++; + + File file = new File(ApplicationLoader.getFilesDirFixed(), "cache4.db"); + databaseSize = file.length(); + + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + cacheSize = getDirectorySize(FileLoader.getInstance().checkDirectory(FileLoader.MEDIA_DIR_CACHE), 0); + if (canceled) { + return; + } + photoSize = getDirectorySize(FileLoader.getInstance().checkDirectory(FileLoader.MEDIA_DIR_IMAGE), 0); + if (canceled) { + return; + } + videoSize = getDirectorySize(FileLoader.getInstance().checkDirectory(FileLoader.MEDIA_DIR_VIDEO), 0); + if (canceled) { + return; + } + documentsSize = getDirectorySize(FileLoader.getInstance().checkDirectory(FileLoader.MEDIA_DIR_DOCUMENT), 1); + if (canceled) { + return; + } + musicSize = getDirectorySize(FileLoader.getInstance().checkDirectory(FileLoader.MEDIA_DIR_DOCUMENT), 2); + if (canceled) { + return; + } + audioSize = getDirectorySize(FileLoader.getInstance().checkDirectory(FileLoader.MEDIA_DIR_AUDIO), 0); + totalSize = cacheSize + videoSize + audioSize + photoSize + documentsSize + musicSize; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + calculating = false; + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + } + }); + } + }); + + return true; + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + canceled = true; + } + + /*private long getDirectorySize2(File dir) { + long size = 0; + if (dir.isDirectory()) { + File[] array = dir.listFiles(); + if (array != null) { + for (int a = 0; a < array.length; a++) { + File file = array[a]; + if (file.isDirectory()) { + size += getDirectorySize2(file); + } else { + size += file.length(); + FileLog.e("tmessages", "" + file + " size = " + file.length()); + } + } + } + } else if (dir.isFile()) { + FileLog.e("tmessages", "" + dir + " size = " + dir.length()); + size += dir.length(); + } + return size; + }*/ + + private long getDirectorySize(File dir, int documentsMusicType) { + if (dir == null || canceled) { + return 0; + } + long size = 0; + if (dir.isDirectory()) { + try { + File[] array = dir.listFiles(); + if (array != null) { + for (int a = 0; a < array.length; a++) { + if (canceled) { + return 0; + } + File file = array[a]; + if (documentsMusicType == 1 || documentsMusicType == 2) { + String name = file.getName().toLowerCase(); + if (name.endsWith(".mp3") || name.endsWith(".m4a")) { + if (documentsMusicType == 1) { + continue; + } + } else if (documentsMusicType == 2) { + continue; + } + } + if (file.isDirectory()) { + size += getDirectorySize(file, documentsMusicType); + } else { + size += file.length(); + } + } + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } else if (dir.isFile()) { + size += dir.length(); + } + return size; + } + + private void cleanupFolders() { + final ProgressDialog progressDialog = new ProgressDialog(getParentActivity()); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + progressDialog.show(); + Utilities.globalQueue.postRunnable(new Runnable() { + @Override + public void run() { + boolean imagesCleared = false; + for (int a = 0; a < 6; a++) { + if (!clear[a]) { + continue; + } + int type = -1; + int documentsMusicType = 0; + if (a == 0) { + type = FileLoader.MEDIA_DIR_IMAGE; + } else if (a == 1) { + type = FileLoader.MEDIA_DIR_VIDEO; + } else if (a == 2) { + type = FileLoader.MEDIA_DIR_DOCUMENT; + documentsMusicType = 1; + } else if (a == 3) { + type = FileLoader.MEDIA_DIR_DOCUMENT; + documentsMusicType = 2; + } else if (a == 4) { + type = FileLoader.MEDIA_DIR_AUDIO; + } else if (a == 5) { + type = FileLoader.MEDIA_DIR_CACHE; + } + if (type == -1) { + continue; + } + File file = FileLoader.getInstance().checkDirectory(type); + if (file != null) { + try { + File[] array = file.listFiles(); + if (array != null) { + for (int b = 0; b < array.length; b++) { + String name = array[b].getName().toLowerCase(); + if (documentsMusicType == 1 || documentsMusicType == 2) { + if (name.endsWith(".mp3") || name.endsWith(".m4a")) { + if (documentsMusicType == 1) { + continue; + } + } else if (documentsMusicType == 2) { + continue; + } + } + if (name.equals(".nomedia")) { + continue; + } + if (array[b].isFile()) { + array[b].delete(); + } + } + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + if (type == FileLoader.MEDIA_DIR_CACHE) { + cacheSize = getDirectorySize(FileLoader.getInstance().checkDirectory(FileLoader.MEDIA_DIR_CACHE), documentsMusicType); + imagesCleared = true; + } else if (type == FileLoader.MEDIA_DIR_AUDIO) { + audioSize = getDirectorySize(FileLoader.getInstance().checkDirectory(FileLoader.MEDIA_DIR_AUDIO), documentsMusicType); + } else if (type == FileLoader.MEDIA_DIR_DOCUMENT) { + if (documentsMusicType == 1) { + documentsSize = getDirectorySize(FileLoader.getInstance().checkDirectory(FileLoader.MEDIA_DIR_DOCUMENT), documentsMusicType); + } else { + musicSize = getDirectorySize(FileLoader.getInstance().checkDirectory(FileLoader.MEDIA_DIR_DOCUMENT), documentsMusicType); + } + } else if (type == FileLoader.MEDIA_DIR_IMAGE) { + imagesCleared = true; + photoSize = getDirectorySize(FileLoader.getInstance().checkDirectory(FileLoader.MEDIA_DIR_IMAGE), documentsMusicType); + } else if (type == FileLoader.MEDIA_DIR_VIDEO) { + videoSize = getDirectorySize(FileLoader.getInstance().checkDirectory(FileLoader.MEDIA_DIR_VIDEO), documentsMusicType); + } + } + final boolean imagesClearedFinal = imagesCleared; + totalSize = cacheSize + videoSize + audioSize + photoSize + documentsSize + musicSize; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (imagesClearedFinal) { + ImageLoader.getInstance().clearMemory(); + } + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + }); + } + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(LocaleController.getString("CacheSettings", R.string.CacheSettings)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + + listAdapter = new ListAdapter(context); + + fragmentView = new FrameLayout(context); + FrameLayout frameLayout = (FrameLayout) fragmentView; + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int sColor = themePrefs.getInt("prefBGColor", themePrefs.getInt("themeColor", AndroidUtilities.defColor)); + frameLayout.setBackgroundColor(sColor); + //frameLayout.setBackgroundColor(0xfff0f0f0); + + ListView listView = new ListView(context); + listView.setDivider(null); + listView.setDividerHeight(0); + listView.setVerticalScrollBarEnabled(false); + listView.setDrawSelectorOnTop(true); + frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + listView.setAdapter(listAdapter); + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(final AdapterView adapterView, View view, final int i, long l) { + if (i == keepMediaRow) { + BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); + builder.setItems(new CharSequence[]{LocaleController.formatPluralString("Weeks", 1), LocaleController.formatPluralString("Months", 1), LocaleController.getString("KeepMediaForever", R.string.KeepMediaForever)}, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, final int which) { + SharedPreferences.Editor editor = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).edit(); + editor.putInt("keep_media", which).commit(); + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + PendingIntent pintent = PendingIntent.getService(ApplicationLoader.applicationContext, 0, new Intent(ApplicationLoader.applicationContext, ClearCacheService.class), 0); + AlarmManager alarmManager = (AlarmManager) ApplicationLoader.applicationContext.getSystemService(Context.ALARM_SERVICE); + if (which == 2) { + alarmManager.cancel(pintent); + } else { + alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, AlarmManager.INTERVAL_DAY, AlarmManager.INTERVAL_DAY, pintent); + } + } + }); + showDialog(builder.create()); + } else if (i == databaseRow) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setMessage(LocaleController.getString("LocalDatabaseClear", R.string.LocalDatabaseClear)); + builder.setPositiveButton(LocaleController.getString("CacheClear", R.string.CacheClear), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + final ProgressDialog progressDialog = new ProgressDialog(getParentActivity()); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + progressDialog.show(); + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + SQLiteDatabase database = MessagesStorage.getInstance().getDatabase(); + ArrayList dialogsToCleanup = new ArrayList<>(); + SQLiteCursor cursor = database.queryFinalized("SELECT did FROM dialogs WHERE 1"); + StringBuilder ids = new StringBuilder(); + while (cursor.next()) { + long did = cursor.longValue(0); + int lower_id = (int) did; + int high_id = (int) (did >> 32); + if (lower_id != 0 && high_id != 1) { + dialogsToCleanup.add(did); + } + } + cursor.dispose(); + + SQLitePreparedStatement state5 = database.executeFast("REPLACE INTO messages_holes VALUES(?, ?, ?)"); + SQLitePreparedStatement state6 = database.executeFast("REPLACE INTO media_holes_v2 VALUES(?, ?, ?, ?)"); + SQLitePreparedStatement state7 = database.executeFast("REPLACE INTO messages_imp_holes VALUES(?, ?, ?)"); + SQLitePreparedStatement state8 = database.executeFast("REPLACE INTO channel_group VALUES(?, ?, ?, ?)"); + + database.beginTransaction(); + for (int a = 0; a < dialogsToCleanup.size(); a++) { + Long did = dialogsToCleanup.get(a); + int messagesCount = 0; + cursor = database.queryFinalized("SELECT COUNT(mid) FROM messages WHERE uid = " + did); + if (cursor.next()) { + messagesCount = cursor.intValue(0); + } + cursor.dispose(); + if (messagesCount <= 2) { + continue; + } + + cursor = database.queryFinalized("SELECT last_mid_i, last_mid FROM dialogs WHERE did = " + did); + ArrayList arrayList = new ArrayList<>(); + if (cursor.next()) { + long last_mid_i = cursor.longValue(0); + long last_mid = cursor.longValue(1); + SQLiteCursor cursor2 = database.queryFinalized("SELECT data FROM messages WHERE uid = " + did + " AND mid IN (" + last_mid_i + "," + last_mid + ")"); + try { + while (cursor2.next()) { + NativeByteBuffer data = new NativeByteBuffer(cursor2.byteArrayLength(0)); + if (data != null && cursor2.byteBufferValue(0, data) != 0) { + TLRPC.Message message = TLRPC.Message.TLdeserialize(data, data.readInt32(false), false); + if (message != null) { + arrayList.add(message); + } + } + data.reuse(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + cursor2.dispose(); + + database.executeFast("DELETE FROM messages WHERE uid = " + did + " AND mid != " + last_mid_i + " AND mid != " + last_mid).stepThis().dispose(); + database.executeFast("DELETE FROM channel_group WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM messages_holes WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM messages_imp_holes WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM bot_keyboard WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_counts_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_v2 WHERE uid = " + did).stepThis().dispose(); + database.executeFast("DELETE FROM media_holes_v2 WHERE uid = " + did).stepThis().dispose(); + BotQuery.clearBotKeyboard(did, null); + MessagesStorage.createFirstHoles(did, state5, state6, state7, state8, arrayList); + } + cursor.dispose(); + } + state5.dispose(); + state6.dispose(); + state7.dispose(); + state8.dispose(); + database.commitTransaction(); + database.executeFast("VACUUM").stepThis().dispose(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } finally { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (listAdapter != null) { + File file = new File(ApplicationLoader.getFilesDirFixed(), "cache4.db"); + databaseSize = file.length(); + listAdapter.notifyDataSetChanged(); + } + } + }); + } + } + }); + } + }); + showDialog(builder.create()); + } else if (i == cacheRow) { + if (totalSize <= 0 || getParentActivity() == null) { + return; + } + BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); + builder.setApplyTopPadding(false); + builder.setApplyBottomPadding(false); + LinearLayout linearLayout = new LinearLayout(getParentActivity()); + linearLayout.setOrientation(LinearLayout.VERTICAL); + for (int a = 0; a < 6; a++) { + long size = 0; + String name = null; + if (a == 0) { + size = photoSize; + name = LocaleController.getString("LocalPhotoCache", R.string.LocalPhotoCache); + } else if (a == 1) { + size = videoSize; + name = LocaleController.getString("LocalVideoCache", R.string.LocalVideoCache); + } else if (a == 2) { + size = documentsSize; + name = LocaleController.getString("LocalDocumentCache", R.string.LocalDocumentCache); + } else if (a == 3) { + size = musicSize; + name = LocaleController.getString("LocalMusicCache", R.string.LocalMusicCache); + } else if (a == 4) { + size = audioSize; + name = LocaleController.getString("LocalAudioCache", R.string.LocalAudioCache); + } else if (a == 5) { + size = cacheSize; + name = LocaleController.getString("LocalCache", R.string.LocalCache); + } + if (size > 0) { + clear[a] = true; + CheckBoxCell checkBoxCell = new CheckBoxCell(getParentActivity()); + checkBoxCell.setTag(a); + checkBoxCell.setBackgroundResource(R.drawable.list_selector); + linearLayout.addView(checkBoxCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + checkBoxCell.setText(name, AndroidUtilities.formatFileSize(size), true, true); + checkBoxCell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + CheckBoxCell cell = (CheckBoxCell) v; + int num = (Integer) cell.getTag(); + clear[num] = !clear[num]; + cell.setChecked(clear[num], true); + } + }); + } else { + clear[a] = false; + } + } + BottomSheet.BottomSheetCell cell = new BottomSheet.BottomSheetCell(getParentActivity(), 2); + cell.setBackgroundResource(R.drawable.list_selector); + cell.setTextAndIcon(LocaleController.getString("ClearMediaCache", R.string.ClearMediaCache).toUpperCase(), 0); + cell.setTextColor(0xffcd5a5a); + cell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + if (visibleDialog != null) { + visibleDialog.dismiss(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + cleanupFolders(); + } + }); + linearLayout.addView(cell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + builder.setCustomView(linearLayout); + showDialog(builder.create()); + } + } + }); + + return fragmentView; + } + + @Override + public void onResume() { + super.onResume(); + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + updateTheme(); + } + + private void updateTheme(){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + actionBar.setBackgroundColor(themePrefs.getInt("prefHeaderColor", def)); + actionBar.setTitleColor(themePrefs.getInt("prefHeaderTitleColor", 0xffffffff)); + + Drawable back = getParentActivity().getResources().getDrawable(R.drawable.ic_ab_back); + back.setColorFilter(themePrefs.getInt("prefHeaderIconsColor", 0xffffffff), PorterDuff.Mode.MULTIPLY); + actionBar.setBackButtonDrawable(back); + + Drawable other = getParentActivity().getResources().getDrawable(R.drawable.ic_ab_other); + other.setColorFilter(themePrefs.getInt("prefHeaderIconsColor", 0xffffffff), PorterDuff.Mode.MULTIPLY); + } + + private class ListAdapter extends BaseFragmentAdapter { + private Context mContext; + + public ListAdapter(Context context) { + mContext = context; + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public boolean isEnabled(int i) { + return i == databaseRow || i == cacheRow && totalSize > 0 || i == keepMediaRow; + } + + @Override + public int getCount() { + return rowCount; + } + + @Override + public Object getItem(int i) { + return null; + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public boolean hasStableIds() { + return false; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + int type = getItemViewType(i); + if (type == 0) { + if (view == null) { + view = new TextSettingsCell(mContext); + view.setBackgroundColor(0xffffffff); + } + TextSettingsCell textCell = (TextSettingsCell) view; + if (i == databaseRow) { + textCell.setTextAndValue(LocaleController.getString("LocalDatabase", R.string.LocalDatabase), AndroidUtilities.formatFileSize(databaseSize), false); + } else if (i == cacheRow) { + if (calculating) { + textCell.setTextAndValue(LocaleController.getString("ClearMediaCache", R.string.ClearMediaCache), LocaleController.getString("CalculatingSize", R.string.CalculatingSize), false); + } else { + textCell.setTextAndValue(LocaleController.getString("ClearMediaCache", R.string.ClearMediaCache), totalSize == 0 ? LocaleController.getString("CacheEmpty", R.string.CacheEmpty) : AndroidUtilities.formatFileSize(totalSize), false); + } + } else if (i == keepMediaRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + int keepMedia = preferences.getInt("keep_media", 2); + String value; + if (keepMedia == 0) { + value = LocaleController.formatPluralString("Weeks", 1); + } else if (keepMedia == 1) { + value = LocaleController.formatPluralString("Months", 1); + } else { + value = LocaleController.getString("KeepMediaForever", R.string.KeepMediaForever); + } + textCell.setTextAndValue(LocaleController.getString("KeepMedia", R.string.KeepMedia), value, false); + } + } else if (type == 1) { + if (view == null) { + view = new TextInfoPrivacyCell(mContext); + } + if (i == databaseInfoRow) { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("LocalDatabaseInfo", R.string.LocalDatabaseInfo)); + view.setBackgroundResource(R.drawable.greydivider_bottom); + } else if (i == cacheInfoRow) { + ((TextInfoPrivacyCell) view).setText(""); + view.setBackgroundResource(R.drawable.greydivider); + } else if (i == keepMediaInfoRow) { + ((TextInfoPrivacyCell) view).setText(AndroidUtilities.replaceTags(LocaleController.getString("KeepMediaInfo", R.string.KeepMediaInfo))); + view.setBackgroundResource(R.drawable.greydivider); + } + } + return view; + } + + @Override + public int getItemViewType(int i) { + if (i == databaseRow || i == cacheRow || i == keepMediaRow) { + return 0; + } else if (i == databaseInfoRow || i == cacheInfoRow || i == keepMediaInfoRow) { + return 1; + } + return 0; + } + + @Override + public int getViewTypeCount() { + return 2; + } + + @Override + public boolean isEmpty() { + return false; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java new file mode 100644 index 00000000..6f58c550 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AboutLinkCell.java @@ -0,0 +1,216 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.os.Build; +import android.text.Layout; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.style.ClickableSpan; +import android.text.style.URLSpan; +import android.view.Gravity; +import android.view.MotionEvent; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.browser.Browser; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.URLSpanNoUnderline; + +public class AboutLinkCell extends FrameLayout { + + private StaticLayout textLayout; + private TextPaint textPaint; + private Paint urlPaint; + private String oldText; + private int textX; + private int textY; + private SpannableStringBuilder stringBuilder; + + private ImageView imageView; + + private ClickableSpan pressedLink; + private LinkPath urlPath = new LinkPath(); + + private AboutLinkCellDelegate delegate; + + public interface AboutLinkCellDelegate { + void didPressUrl(String url); + } + + public AboutLinkCell(Context context) { + super(context); + + textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + textPaint.setTextSize(AndroidUtilities.dp(16)); + textPaint.setColor(0xff000000); + textPaint.linkColor = Theme.MSG_LINK_TEXT_COLOR; + + urlPaint = new Paint(); + urlPaint.setColor(Theme.MSG_LINK_SELECT_BACKGROUND_COLOR); + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 16, 5, LocaleController.isRTL ? 16 : 0, 0)); + setWillNotDraw(false); + } + + public void setDelegate(AboutLinkCellDelegate botHelpCellDelegate) { + delegate = botHelpCellDelegate; + } + + private void resetPressedLink() { + if (pressedLink != null) { + pressedLink = null; + } + invalidate(); + } + + public void setTextAndIcon(String text, int resId) { + if (text == null || text.length() == 0) { + setVisibility(GONE); + return; + } + if (text != null && oldText != null && text.equals(oldText)) { + return; + } + oldText = text; + stringBuilder = new SpannableStringBuilder(oldText); + MessageObject.addLinks(stringBuilder, false); + Emoji.replaceEmoji(stringBuilder, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); + requestLayout(); + if (resId == 0) { + imageView.setImageDrawable(null); + } else { + imageView.setImageResource(resId); + } + } + + public void setIconColor(int color) { + imageView.setColorFilter(color, PorterDuff.Mode.SRC_IN); + } + + public void setTextColor(int color) { + textPaint.setColor(color); + } + + public void setLinkColor(int color) { + textPaint.linkColor = color; + urlPaint.setColor(Color.argb(Math.round(Color.alpha(color) * 0.13f), Color.red(color), Color.green(color), Color.blue(color))); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + float x = event.getX(); + float y = event.getY(); + + if (Build.VERSION.SDK_INT >= 21 && getBackground() != null) { + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + getBackground().setHotspot(x, y); + } + } + + boolean result = false; + if (textLayout != null) { + if (event.getAction() == MotionEvent.ACTION_DOWN || pressedLink != null && event.getAction() == MotionEvent.ACTION_UP) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + resetPressedLink(); + try { + int x2 = (int) (x - textX); + int y2 = (int) (y - textY); + final int line = textLayout.getLineForVertical(y2); + final int off = textLayout.getOffsetForHorizontal(line, x2); + + final float left = textLayout.getLineLeft(line); + if (left <= x2 && left + textLayout.getLineWidth(line) >= x2) { + Spannable buffer = (Spannable) textLayout.getText(); + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + if (link.length != 0) { + resetPressedLink(); + pressedLink = link[0]; + result = true; + try { + int start = buffer.getSpanStart(pressedLink); + urlPath.setCurrentLayout(textLayout, start, 0); + textLayout.getSelectionPath(start, buffer.getSpanEnd(pressedLink), urlPath); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else { + resetPressedLink(); + } + } else { + resetPressedLink(); + } + } catch (Exception e) { + resetPressedLink(); + FileLog.e("tmessages", e); + } + } else if (pressedLink != null) { + try { + if (pressedLink instanceof URLSpanNoUnderline) { + String url = ((URLSpanNoUnderline) pressedLink).getURL(); + if (url.startsWith("@") || url.startsWith("#") || url.startsWith("/")) { + if (delegate != null) { + delegate.didPressUrl(url); + } + } + } else { + if (pressedLink instanceof URLSpan) { + Browser.openUrl(getContext(), ((URLSpan) pressedLink).getURL()); + } else { + pressedLink.onClick(this); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + resetPressedLink(); + result = true; + } + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + resetPressedLink(); + } + } + return result || super.onTouchEvent(event); + } + + @SuppressLint("DrawAllocation") + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + textLayout = new StaticLayout(stringBuilder, textPaint, MeasureSpec.getSize(widthMeasureSpec) - AndroidUtilities.dp(71 + 16), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(textLayout.getHeight() + AndroidUtilities.dp(16), MeasureSpec.EXACTLY)); + } + + @Override + protected void onDraw(Canvas canvas) { + canvas.save(); + canvas.translate(textX = AndroidUtilities.dp(LocaleController.isRTL ? 16 : 71), textY = AndroidUtilities.dp(8)); + if (pressedLink != null) { + canvas.drawPath(urlPath, urlPaint); + } + textLayout.draw(canvas); + canvas.restore(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/AudioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AudioCell.java new file mode 100644 index 00000000..5b44689d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/AudioCell.java @@ -0,0 +1,169 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.R; +import org.telegram.ui.Components.CheckBox; +import org.telegram.ui.Components.LayoutHelper; + +import java.util.ArrayList; + +public class AudioCell extends FrameLayout { + + private ImageView playButton; + private TextView titleTextView; + private TextView authorTextView; + private TextView genreTextView; + private TextView timeTextView; + private CheckBox checkBox; + + private MediaController.AudioEntry audioEntry; + private boolean needDivider; + private static Paint paint; + + private AudioCellDelegate delegate; + + public interface AudioCellDelegate { + void startedPlayingAudio(MessageObject messageObject); + } + + public AudioCell(Context context) { + super(context); + + if (paint == null) { + paint = new Paint(); + paint.setColor(0xffd9d9d9); + paint.setStrokeWidth(1); + } + + playButton = new ImageView(context); + playButton.setScaleType(ImageView.ScaleType.CENTER); + addView(playButton, LayoutHelper.createFrame(46, 46, ((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP), LocaleController.isRTL ? 0 : 13, 13, LocaleController.isRTL ? 13 : 0, 0)); + playButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (audioEntry != null) { + if (MediaController.getInstance().isPlayingAudio(audioEntry.messageObject) && !MediaController.getInstance().isAudioPaused()) { + MediaController.getInstance().pauseAudio(audioEntry.messageObject); + playButton.setImageResource(R.drawable.audiosend_play); + } else { + ArrayList arrayList = new ArrayList<>(); + arrayList.add(audioEntry.messageObject); + if (MediaController.getInstance().setPlaylist(arrayList, audioEntry.messageObject)) { + playButton.setImageResource(R.drawable.audiosend_pause); + if (delegate != null) { + delegate.startedPlayingAudio(audioEntry.messageObject); + } + } + } + } + } + }); + + titleTextView = new TextView(context); + titleTextView.setTextColor(0xff212121); + titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleTextView.setLines(1); + titleTextView.setMaxLines(1); + titleTextView.setSingleLine(true); + titleTextView.setEllipsize(TextUtils.TruncateAt.END); + titleTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); + addView(titleTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 50 : 72, 7, LocaleController.isRTL ? 72 : 50, 0)); + + genreTextView = new TextView(context); + genreTextView.setTextColor(0xff8a8a8a); + genreTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + genreTextView.setLines(1); + genreTextView.setMaxLines(1); + genreTextView.setSingleLine(true); + genreTextView.setEllipsize(TextUtils.TruncateAt.END); + genreTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); + addView(genreTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 50 : 72, 28, LocaleController.isRTL ? 72 : 50, 0)); + + authorTextView = new TextView(context); + authorTextView.setTextColor(0xff8a8a8a); + authorTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + authorTextView.setLines(1); + authorTextView.setMaxLines(1); + authorTextView.setSingleLine(true); + authorTextView.setEllipsize(TextUtils.TruncateAt.END); + authorTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); + addView(authorTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 50 : 72, 44, LocaleController.isRTL ? 72 : 50, 0)); + + timeTextView = new TextView(context); + timeTextView.setTextColor(0xff999999); + timeTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + timeTextView.setLines(1); + timeTextView.setMaxLines(1); + timeTextView.setSingleLine(true); + timeTextView.setEllipsize(TextUtils.TruncateAt.END); + timeTextView.setGravity((LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP); + addView(timeTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, LocaleController.isRTL ? 18 : 0, 11, LocaleController.isRTL ? 0 : 18, 0)); + + checkBox = new CheckBox(context, R.drawable.round_check2); + checkBox.setVisibility(VISIBLE); + checkBox.setColor(0xff29b6f7); + addView(checkBox, LayoutHelper.createFrame(22, 22, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, LocaleController.isRTL ? 18 : 0, 39, LocaleController.isRTL ? 0 : 18, 0)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(72) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY)); + } + + public void setAudio(MediaController.AudioEntry entry, boolean divider, boolean checked) { + audioEntry = entry; + + titleTextView.setText(audioEntry.title); + genreTextView.setText(audioEntry.genre); + authorTextView.setText(audioEntry.author); + timeTextView.setText(String.format("%d:%02d", audioEntry.duration / 60, audioEntry.duration % 60)); + playButton.setImageResource(MediaController.getInstance().isPlayingAudio(audioEntry.messageObject) && !MediaController.getInstance().isAudioPaused() ? R.drawable.audiosend_pause : R.drawable.audiosend_play); + + needDivider = divider; + setWillNotDraw(!divider); + + checkBox.setChecked(checked, false); + } + + public void setChecked(boolean value) { + checkBox.setChecked(value, true); + } + + public void setDelegate(AudioCellDelegate audioCellDelegate) { + delegate = audioCellDelegate; + } + + public MediaController.AudioEntry getAudioEntry() { + return audioEntry; + } + + @Override + protected void onDraw(Canvas canvas) { + if (needDivider) { + canvas.drawLine(AndroidUtilities.dp(72), getHeight() - 1, getWidth(), getHeight() - 1, paint); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java index 3f108795..71d87bdb 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BaseCell.java @@ -52,9 +52,11 @@ public class BaseCell extends View { } protected void setDrawableBounds(Drawable drawable, int x, int y) { - if (drawable != null) { - setDrawableBounds(drawable, x, y, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); - } + setDrawableBounds(drawable, x, y, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + } + + protected void setDrawableBounds(Drawable drawable, float x, float y) { + setDrawableBounds(drawable, (int) x, (int) y, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); } protected void setDrawableBounds(Drawable drawable, int x, int y, int w, int h) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java new file mode 100644 index 00000000..3dd8f6c0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotHelpCell.java @@ -0,0 +1,222 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.text.Layout; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.style.ClickableSpan; +import android.text.style.URLSpan; +import android.view.MotionEvent; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.R; +import org.telegram.messenger.browser.Browser; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.LinkPath; +import org.telegram.ui.Components.TypefaceSpan; +import org.telegram.ui.Components.URLSpanNoUnderline; + +public class BotHelpCell extends View { + + private StaticLayout textLayout; + private TextPaint textPaint; + private Paint urlPaint; + private String oldText; + + private int width; + private int height; + private int textX; + private int textY; + + private ClickableSpan pressedLink; + private LinkPath urlPath = new LinkPath(); + + private BotHelpCellDelegate delegate; + + public interface BotHelpCellDelegate { + void didPressUrl(String url); + } + + public BotHelpCell(Context context) { + super(context); + + textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + textPaint.setTextSize(AndroidUtilities.dp(16)); + //textPaint.setColor(0xff000000); + //textPaint.linkColor = Theme.MSG_LINK_TEXT_COLOR; + + urlPaint = new Paint(); + //urlPaint.setColor(Theme.MSG_LINK_SELECT_BACKGROUND_COLOR); + //plus + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int inColor = themePrefs.getInt("chatLTextColor", 0xff000000); + int defColor = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + int linkColor = themePrefs.getInt("chatLLinkColor", defColor); + textPaint.setColor(inColor); + textPaint.linkColor = linkColor; + urlPaint.setColor(AndroidUtilities.getIntAlphaColor("chatLLinkColor", 0x33316f9f, 0.3f)); + } + + public void setDelegate(BotHelpCellDelegate botHelpCellDelegate) { + delegate = botHelpCellDelegate; + } + + private void resetPressedLink() { + if (pressedLink != null) { + pressedLink = null; + } + invalidate(); + } + + public void setText(String text) { + if (text == null || text.length() == 0) { + setVisibility(GONE); + return; + } + if (text != null && oldText != null && text.equals(oldText)) { + return; + } + oldText = text; + setVisibility(VISIBLE); + if (AndroidUtilities.isTablet()) { + width = (int) (AndroidUtilities.getMinTabletSide() * 0.7f); + } else { + width = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.7f); + } + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); + String help = LocaleController.getString("BotInfoTitle", R.string.BotInfoTitle); + stringBuilder.append(help); + stringBuilder.append("\n\n"); + stringBuilder.append(text); + MessageObject.addLinks(stringBuilder); + stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")), 0, help.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + Emoji.replaceEmoji(stringBuilder, textPaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); + try { + textLayout = new StaticLayout(stringBuilder, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + width = 0; + height = textLayout.getHeight() + AndroidUtilities.dp(4 + 18); + int count = textLayout.getLineCount(); + for (int a = 0; a < count; a++) { + width = (int) Math.ceil(Math.max(width, textLayout.getLineWidth(a) + textLayout.getLineLeft(a))); + } + } catch (Exception e) { + FileLog.e("tmessage", e); + } + width += AndroidUtilities.dp(4 + 18); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + float x = event.getX(); + float y = event.getY(); + + boolean result = false; + if (textLayout != null) { + if (event.getAction() == MotionEvent.ACTION_DOWN || pressedLink != null && event.getAction() == MotionEvent.ACTION_UP) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + resetPressedLink(); + try { + int x2 = (int) (x - textX); + int y2 = (int) (y - textY); + final int line = textLayout.getLineForVertical(y2); + final int off = textLayout.getOffsetForHorizontal(line, x2); + + final float left = textLayout.getLineLeft(line); + if (left <= x2 && left + textLayout.getLineWidth(line) >= x2) { + Spannable buffer = (Spannable) textLayout.getText(); + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + if (link.length != 0) { + resetPressedLink(); + pressedLink = link[0]; + result = true; + try { + int start = buffer.getSpanStart(pressedLink); + urlPath.setCurrentLayout(textLayout, start, 0); + textLayout.getSelectionPath(start, buffer.getSpanEnd(pressedLink), urlPath); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else { + resetPressedLink(); + } + } else { + resetPressedLink(); + } + } catch (Exception e) { + resetPressedLink(); + FileLog.e("tmessages", e); + } + } else if (pressedLink != null) { + try { + if (pressedLink instanceof URLSpanNoUnderline) { + String url = ((URLSpanNoUnderline) pressedLink).getURL(); + if (url.startsWith("@") || url.startsWith("#") || url.startsWith("/")) { + if (delegate != null) { + delegate.didPressUrl(url); + } + } + } else { + if (pressedLink instanceof URLSpan) { + Browser.openUrl(getContext(), ((URLSpan) pressedLink).getURL()); + } else { + pressedLink.onClick(this); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + resetPressedLink(); + result = true; + } + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + resetPressedLink(); + } + } + return result || super.onTouchEvent(event); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), height + AndroidUtilities.dp(8)); + } + + @Override + protected void onDraw(Canvas canvas) { + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + Theme.backgroundMediaDrawableIn.setColorFilter(themePrefs.getInt("chatLBubbleColor", 0xffffffff), PorterDuff.Mode.SRC_IN); + int x = (canvas.getWidth() - width) / 2; + int y = AndroidUtilities.dp(4); + Theme.backgroundMediaDrawableIn.setBounds(x, y, width + x, height + y); + Theme.backgroundMediaDrawableIn.draw(canvas); + canvas.save(); + canvas.translate(textX = AndroidUtilities.dp(2 + 9) + x, textY = AndroidUtilities.dp(2 + 9) + y); + if (pressedLink != null) { + canvas.drawPath(urlPath, urlPaint); + } + if (textLayout != null) { + textLayout.draw(canvas); + } + canvas.restore(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotSwitchCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotSwitchCell.java new file mode 100644 index 00000000..dbe52d88 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/BotSwitchCell.java @@ -0,0 +1,62 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.os.Build; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.Components.LayoutHelper; + +public class BotSwitchCell extends FrameLayout { + + private TextView textView; + + public BotSwitchCell(Context context) { + super(context); + setBackgroundResource(R.drawable.list_selector); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + textView.setTextColor(0xff4391cc); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setSingleLine(true); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setMaxLines(1); + textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 14, 0, 14, 0)); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (Build.VERSION.SDK_INT >= 21 && getBackground() != null) { + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + getBackground().setHotspot(event.getX(), event.getY()); + } + } + return super.onTouchEvent(event); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(36), MeasureSpec.EXACTLY)); + } + + public void setText(String text) { + textView.setText(text); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java index 22246bee..8f3aa086 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatActionCell.java @@ -14,7 +14,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; +import android.graphics.RectF; import android.text.Layout; import android.text.Spannable; import android.text.StaticLayout; @@ -24,19 +24,17 @@ import android.view.MotionEvent; import android.view.SoundEffectConstants; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ImageReceiver; -import org.telegram.messenger.MessageObject; -import org.telegram.messenger.MessagesController; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; -import org.telegram.tgnet.TLRPC; -import org.telegram.messenger.R; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.UserConfig; -import org.telegram.ui.Components.ResourceLoader; -import org.telegram.ui.ImageListActivity; -import org.telegram.ui.PhotoViewer; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.PhotoViewer; public class ChatActionCell extends BaseCell { @@ -47,6 +45,8 @@ public class ChatActionCell extends BaseCell { } private static TextPaint textPaint; + private static Paint backPaint; + private static RectF rect; private URLSpan pressedLink; @@ -61,17 +61,29 @@ public class ChatActionCell extends BaseCell { private int previousWidth = 0; private boolean imagePressed = false; + private boolean hasReplyMessage; + private MessageObject currentMessageObject; private ChatActionCellDelegate delegate; + private int dateBubbleColor; + public ChatActionCell(Context context) { super(context); if (textPaint == null) { textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); textPaint.setColor(0xffffffff); textPaint.linkColor = 0xffffffff; + textPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + + backPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + rect = new RectF(); } + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + dateBubbleColor = themePrefs.getInt("chatDateBubbleColor", ApplicationLoader.getServiceMessageColor()); + //backPaint.setColor(ApplicationLoader.getServiceMessageColor()); + backPaint.setColor(dateBubbleColor); imageReceiver = new ImageReceiver(this); imageReceiver.setRoundRadius(AndroidUtilities.dp(32)); avatarDrawable = new AvatarDrawable(); @@ -80,7 +92,7 @@ public class ChatActionCell extends BaseCell { imageReceiver.setRoundRadius(radius); avatarDrawable.setRadius(radius); // - textPaint.setTextSize(AndroidUtilities.dp(MessagesController.getInstance().fontSize)); + textPaint.setTextSize(AndroidUtilities.dp(MessagesController.getInstance().fontSize - 2)); } public void setDelegate(ChatActionCellDelegate delegate) { @@ -88,10 +100,11 @@ public class ChatActionCell extends BaseCell { } public void setMessageObject(MessageObject messageObject) { - if (currentMessageObject == messageObject) { + if (currentMessageObject == messageObject && (hasReplyMessage || messageObject.replyMessageObject == null)) { return; } currentMessageObject = messageObject; + hasReplyMessage = messageObject.replyMessageObject != null; previousWidth = 0; if (currentMessageObject.type == 11) { int id = 0; @@ -222,7 +235,7 @@ public class ChatActionCell extends BaseCell { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - updateTheme(); + //updateTheme(); if (currentMessageObject == null) { setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), textHeight + AndroidUtilities.dp(14)); return; @@ -230,8 +243,8 @@ public class ChatActionCell extends BaseCell { int width = Math.max(AndroidUtilities.dp(30), MeasureSpec.getSize(widthMeasureSpec)); if (width != previousWidth) { previousWidth = width; - - textLayout = new StaticLayout(currentMessageObject.messageText, textPaint, width - AndroidUtilities.dp(30), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + int maxWidth = width - AndroidUtilities.dp(30); + textLayout = new StaticLayout(currentMessageObject.messageText, textPaint, maxWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); textHeight = 0; textWidth = 0; try { @@ -240,6 +253,9 @@ public class ChatActionCell extends BaseCell { float lineWidth; try { lineWidth = textLayout.getLineWidth(a); + if (lineWidth > maxWidth) { + lineWidth = maxWidth; + } textHeight = (int)Math.max(textHeight, Math.ceil(textLayout.getLineBottom(a))); } catch (Exception e) { FileLog.e("tmessages", e); @@ -262,49 +278,167 @@ public class ChatActionCell extends BaseCell { setMeasuredDimension(width, textHeight + AndroidUtilities.dp(14 + (currentMessageObject.type == 11 ? 70 : 0))); } + private int findMaxWidthAroundLine(int line) { + int width = (int) Math.ceil(textLayout.getLineWidth(line)); + int count = textLayout.getLineCount(); + for (int a = line + 1; a < count; a++) { + int w = (int) Math.ceil(textLayout.getLineWidth(a)); + if (Math.abs(w - width) < AndroidUtilities.dp(12)) { + width = Math.max(w, width); + } else { + break; + } + } + for (int a = line - 1; a >= 0; a--) { + int w = (int) Math.ceil(textLayout.getLineWidth(a)); + if (Math.abs(w - width) < AndroidUtilities.dp(12)) { + width = Math.max(w, width); + } else { + break; + } + } + return width; + } + private void updateTheme(){ SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); int color = themePrefs.getInt("chatDateColor", 0xffffffff); + //int dBColor = themePrefs.getInt("chatDateBubbleColor", 0x59000000); textPaint.setColor(color); if(color != 0xffffffff){ textPaint.linkColor = AndroidUtilities.getIntDarkerColor("chatDateColor", -0x50); } - textPaint.setTextSize(AndroidUtilities.dp(themePrefs.getInt("chatDateSize", 16)));//16 - setBubbles(themePrefs.getString("chatBubbleStyle", ImageListActivity.getBubbleName(0))); - ResourceLoader.backgroundWhite.setColorFilter(themePrefs.getInt("chatDateBubbleColor", 0x59000000), PorterDuff.Mode.MULTIPLY); + textPaint.setTextSize(AndroidUtilities.dp(themePrefs.getInt("chatDateSize", MessagesController.getInstance().fontSize - 2)));//16 + //backPaint.setColor(dBColor); + //setBubbles(themePrefs.getString("chatBubbleStyle", ImageListActivity.getBubbleName(0))); + //Theme.backgroundWhite.setColorFilter(themePrefs.getInt("chatDateBubbleColor", 0x59000000), PorterDuff.Mode.MULTIPLY); } - private void setBubbles(String bubble){ - if(bubble.equals(ImageListActivity.getBubbleName(0))){ - ResourceLoader.backgroundWhite = getResources().getDrawable(R.drawable.system_white); - } else if(bubble.equals(ImageListActivity.getBubbleName(1))){ - ResourceLoader.backgroundWhite = getResources().getDrawable(R.drawable.system_white); - } else if(bubble.equals(ImageListActivity.getBubbleName(2))){ - ResourceLoader.backgroundWhite = getResources().getDrawable(R.drawable.system_white_3); - } else if(bubble.equals(ImageListActivity.getBubbleName(3))){ - ResourceLoader.backgroundWhite = getResources().getDrawable(R.drawable.system_white_4); - } - } @Override protected void onDraw(Canvas canvas) { if (currentMessageObject == null) { return; } - Drawable backgroundDrawable; - if (ApplicationLoader.isCustomTheme()) { - backgroundDrawable = ResourceLoader.backgroundWhite;//backgroundBlack; - } else { - backgroundDrawable = ResourceLoader.backgroundWhite;//backgroundBlue; - } - backgroundDrawable.setBounds(textX - AndroidUtilities.dp(5), AndroidUtilities.dp(5), textX + textWidth + AndroidUtilities.dp(5), AndroidUtilities.dp(9) + textHeight); - backgroundDrawable.draw(canvas); - if (currentMessageObject.type == 11) { imageReceiver.draw(canvas); } - + updateTheme(); if (textLayout != null) { + final int count = textLayout.getLineCount(); + final int corner = AndroidUtilities.dp(6); + int y = AndroidUtilities.dp(7); + int previousLineBottom = 0; + int dx; + int dy; + for (int a = 0; a < count; a++) { + int width = findMaxWidthAroundLine(a); + int x = (getMeasuredWidth() - width) / 2 - AndroidUtilities.dp(3); + width += AndroidUtilities.dp(6); + int lineBottom = textLayout.getLineBottom(a); + int height = lineBottom - previousLineBottom; + int additionalHeight = 0; + previousLineBottom = lineBottom; + + boolean drawBottomCorners = a == count - 1; + boolean drawTopCorners = a == 0; + + if (drawTopCorners) { + y -= AndroidUtilities.dp(3); + height += AndroidUtilities.dp(3); + } + if (drawBottomCorners) { + height += AndroidUtilities.dp(3); + } + canvas.drawRect(x, y, x + width, y + height, backPaint); + + if (!drawBottomCorners && a + 1 < count) { + int nextLineWidth = findMaxWidthAroundLine(a + 1) + AndroidUtilities.dp(6); + if (nextLineWidth + corner * 2 < width) { + int nextX = (getMeasuredWidth() - nextLineWidth) / 2; + drawBottomCorners = true; + additionalHeight = AndroidUtilities.dp(3); + + canvas.drawRect(x, y + height, nextX, y + height + AndroidUtilities.dp(3), backPaint); + canvas.drawRect(nextX + nextLineWidth, y + height, x + width, y + height + AndroidUtilities.dp(3), backPaint); + } else if (width + corner * 2 < nextLineWidth) { + additionalHeight = AndroidUtilities.dp(3); + + dy = y + height - AndroidUtilities.dp(9); + Theme.cornerInner[2].setColorFilter(dateBubbleColor, PorterDuff.Mode.SRC_IN); + Theme.cornerInner[3].setColorFilter(dateBubbleColor, PorterDuff.Mode.SRC_IN); + dx = x - corner * 2; + Theme.cornerInner[2].setBounds(dx, dy, dx + corner, dy + corner); + Theme.cornerInner[2].draw(canvas); + + dx = x + width + corner; + Theme.cornerInner[3].setBounds(dx, dy, dx + corner, dy + corner); + Theme.cornerInner[3].draw(canvas); + } else { + additionalHeight = AndroidUtilities.dp(6); + } + } + if (!drawTopCorners && a > 0) { + int prevLineWidth = findMaxWidthAroundLine(a - 1) + AndroidUtilities.dp(6); + if (prevLineWidth + corner * 2 < width) { + int prevX = (getMeasuredWidth() - prevLineWidth) / 2; + drawTopCorners = true; + y -= AndroidUtilities.dp(3); + height += AndroidUtilities.dp(3); + + canvas.drawRect(x, y, prevX, y + AndroidUtilities.dp(3), backPaint); + canvas.drawRect(prevX + prevLineWidth, y, x + width, y + AndroidUtilities.dp(3), backPaint); + } else if (width + corner * 2 < prevLineWidth) { + y -= AndroidUtilities.dp(3); + height += AndroidUtilities.dp(3); + + dy = y + corner; + Theme.cornerInner[0].setColorFilter(dateBubbleColor, PorterDuff.Mode.SRC_IN); + Theme.cornerInner[1].setColorFilter(dateBubbleColor, PorterDuff.Mode.SRC_IN); + dx = x - corner * 2; + Theme.cornerInner[0].setBounds(dx, dy, dx + corner, dy + corner); + Theme.cornerInner[0].draw(canvas); + + dx = x + width + corner; + Theme.cornerInner[1].setBounds(dx, dy, dx + corner, dy + corner); + Theme.cornerInner[1].draw(canvas); + } else { + y -= AndroidUtilities.dp(6); + height += AndroidUtilities.dp(6); + } + } + + canvas.drawRect(x - corner, y + corner, x, y + height + additionalHeight - corner, backPaint); + canvas.drawRect(x + width, y + corner, x + width + corner, y + height + additionalHeight - corner, backPaint); + + if (drawTopCorners) { + Theme.cornerOuter[0].setColorFilter(dateBubbleColor, PorterDuff.Mode.SRC_IN); + Theme.cornerOuter[1].setColorFilter(dateBubbleColor, PorterDuff.Mode.SRC_IN); + dx = x - corner; + Theme.cornerOuter[0].setBounds(dx, y, dx + corner, y + corner); + Theme.cornerOuter[0].draw(canvas); + + dx = x + width; + Theme.cornerOuter[1].setBounds(dx, y, dx + corner, y + corner); + Theme.cornerOuter[1].draw(canvas); + } + + if (drawBottomCorners) { + dy = y + height + additionalHeight - corner; + Theme.cornerOuter[2].setColorFilter(dateBubbleColor, PorterDuff.Mode.SRC_IN); + Theme.cornerOuter[3].setColorFilter(dateBubbleColor, PorterDuff.Mode.SRC_IN); + dx = x + width; + Theme.cornerOuter[2].setBounds(dx, dy, dx + corner, dy + corner); + Theme.cornerOuter[2].draw(canvas); + + dx = x - corner; + Theme.cornerOuter[3].setBounds(dx, dy, dx + corner, dy + corner); + Theme.cornerOuter[3].draw(canvas); + } + + y += height; + } + canvas.save(); canvas.translate(textXLeft, textY); textLayout.draw(canvas); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java deleted file mode 100644 index e7bbcb76..00000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatAudioCell.java +++ /dev/null @@ -1,422 +0,0 @@ -/* - * This is the source code of Telegram for Android v. 1.3.x. - * It is licensed under GNU GPL v. 2 or later. - * You should have received a copy of the license in this archive (see LICENSE). - * - * Copyright Nikolai Kudashov, 2013-2016. - */ - -package org.telegram.ui.Cells; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.drawable.Drawable; -import android.text.Layout; -import android.text.StaticLayout; -import android.text.TextPaint; -import android.util.Log; -import android.view.MotionEvent; -import android.view.SoundEffectConstants; - -import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.BuildConfig; - -import org.telegram.messenger.ImageLoader; - -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.SendMessagesHelper; -import org.telegram.messenger.BuildVars; -import org.telegram.messenger.FileLoader; -import org.telegram.messenger.MediaController; -import org.telegram.messenger.MessageObject; -import org.telegram.messenger.FileLog; -import org.telegram.ui.Components.RadialProgress; -import org.telegram.ui.Components.ResourceLoader; -import org.telegram.ui.Components.SeekBar; - -import java.io.File; - -public class ChatAudioCell extends ChatBaseCell implements SeekBar.SeekBarDelegate { - - private static TextPaint timePaint; - private static Paint circlePaint; - - private SeekBar seekBar; - private int seekBarX; - private int seekBarY; - - private RadialProgress radialProgress; - private int buttonState = 0; - private int buttonX; - private int buttonY; - private boolean buttonPressed = false; - - private StaticLayout timeLayout; - private int timeX; - private int timeWidth; - private String lastTimeString = null; - - public ChatAudioCell(Context context) { - super(context); - - seekBar = new SeekBar(context); - seekBar.delegate = this; - radialProgress = new RadialProgress(this); - drawForwardedName = true; - /*avatarDrawable = new AvatarDrawable(); - //Chat Audio Photo - int radius = AndroidUtilities.dp(AndroidUtilities.getIntDef("chatAvatarRadius", 32)); - avatarImage.setRoundRadius(radius); - avatarDrawable.setRadius(radius);*/ - // - if (timePaint == null) { - timePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - timePaint.setTextSize(AndroidUtilities.dp(12)); - - circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG); - } - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - MediaController.getInstance().removeLoadingFileObserver(this); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - updateButtonState(false); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - float x = event.getX(); - float y = event.getY(); - boolean result = seekBar.onTouch(event.getAction(), event.getX() - seekBarX, event.getY() - seekBarY); - if (result) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - getParent().requestDisallowInterceptTouchEvent(true); - } - invalidate(); - } else { - int side = AndroidUtilities.dp(36); - if (event.getAction() == MotionEvent.ACTION_DOWN) { - if (x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side) { - buttonPressed = true; - invalidate(); - result = true; - radialProgress.swapBackground(getDrawableForCurrentState()); - } - } else if (buttonPressed) { - if (event.getAction() == MotionEvent.ACTION_UP) { - buttonPressed = false; - playSoundEffect(SoundEffectConstants.CLICK); - didPressedButton(); - invalidate(); - } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { - buttonPressed = false; - invalidate(); - } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (!(x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side)) { - buttonPressed = false; - invalidate(); - } - } - radialProgress.swapBackground(getDrawableForCurrentState()); - } - if (!result) { - result = super.onTouchEvent(event); - } - } - - return result; - } - - private void didPressedButton() { - if (buttonState == 0) { - boolean result = MediaController.getInstance().playAudio(currentMessageObject); - if (!currentMessageObject.isOut() && currentMessageObject.isContentUnread()) { - if (currentMessageObject.messageOwner.to_id.channel_id == 0) { - MessagesController.getInstance().markMessageContentAsRead(currentMessageObject.messageOwner); - } - } - if (result) { - buttonState = 1; - radialProgress.setBackground(getDrawableForCurrentState(), false, false); - invalidate(); - } - } else if (buttonState == 1) { - boolean result = MediaController.getInstance().pauseAudio(currentMessageObject); - if (result) { - buttonState = 0; - radialProgress.setBackground(getDrawableForCurrentState(), false, false); - invalidate(); - } - } else if (buttonState == 2) { - radialProgress.setProgress(0, false); - FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.audio, true); - buttonState = 3; - radialProgress.setBackground(getDrawableForCurrentState(), true, false); - invalidate(); - } else if (buttonState == 3) { - FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.audio); - buttonState = 2; - radialProgress.setBackground(getDrawableForCurrentState(), false, false); - invalidate(); - } else if (buttonState == 4) { - if (currentMessageObject.isOut() && currentMessageObject.isSending()) { - if (delegate != null) { - delegate.didPressedCancelSendButton(this); - } - } - } - } - - public void updateProgress() { - if (currentMessageObject == null) { - return; - } - - if (!seekBar.isDragging()) { - seekBar.setProgress(currentMessageObject.audioProgress); - } - - int duration; - if (!MediaController.getInstance().isPlayingAudio(currentMessageObject)) { - duration = currentMessageObject.messageOwner.media.audio.duration; - } else { - duration = currentMessageObject.audioProgressSec; - } - String timeString = String.format("%02d:%02d", duration / 60, duration % 60); - if (lastTimeString == null || lastTimeString != null && !lastTimeString.equals(timeString)) { - lastTimeString = timeString; - timeWidth = (int)Math.ceil(timePaint.measureText(timeString)); - timeLayout = new StaticLayout(timeString, timePaint, timeWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - } - invalidate(); - } - - public void downloadAudioIfNeed() { - if (buttonState == 2) { - FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.audio, true); - buttonState = 3; - radialProgress.setBackground(getDrawableForCurrentState(), false, false); - } - } - - public void updateButtonState(boolean animated) { - if (currentMessageObject == null) { - return; - } - if (currentMessageObject.isOut() && currentMessageObject.isSending()) { - MediaController.getInstance().addLoadingFileObserver(currentMessageObject.messageOwner.attachPath, this); - buttonState = 4; - radialProgress.setBackground(getDrawableForCurrentState(), true, animated); - Float progress = ImageLoader.getInstance().getFileProgress(currentMessageObject.messageOwner.attachPath); - if (progress == null && SendMessagesHelper.getInstance().isSendingMessage(currentMessageObject.getId())) { - progress = 1.0f; - } - radialProgress.setProgress(progress != null ? progress : 0, false); - } else { - File cacheFile = null; - if (currentMessageObject.messageOwner.attachPath != null && currentMessageObject.messageOwner.attachPath.length() > 0) { - cacheFile = new File(currentMessageObject.messageOwner.attachPath); - if(!cacheFile.exists()) { - cacheFile = null; - } - } - if (cacheFile == null) { - cacheFile = FileLoader.getPathToMessage(currentMessageObject.messageOwner); - } - if (BuildVars.DEBUG_VERSION) { - FileLog.d("tmessages", "looking for audio in " + cacheFile); - } - if (cacheFile.exists()) { - MediaController.getInstance().removeLoadingFileObserver(this); - boolean playing = MediaController.getInstance().isPlayingAudio(currentMessageObject); - if (!playing || playing && MediaController.getInstance().isAudioPaused()) { - buttonState = 0; - } else { - buttonState = 1; - } - radialProgress.setProgress(0, animated); - radialProgress.setBackground(getDrawableForCurrentState(), false, animated); - } else { - String fileName = currentMessageObject.getFileName(); - MediaController.getInstance().addLoadingFileObserver(fileName, this); - if (!FileLoader.getInstance().isLoadingFile(fileName)) { - buttonState = 2; - radialProgress.setProgress(0, animated); - radialProgress.setBackground(getDrawableForCurrentState(), false, animated); - } else { - buttonState = 3; - Float progress = ImageLoader.getInstance().getFileProgress(fileName); - if (progress != null) { - radialProgress.setProgress(progress, animated); - } else { - radialProgress.setProgress(0, animated); - } - radialProgress.setBackground(getDrawableForCurrentState(), true, animated); - } - } - } - updateProgress(); - } - - @Override - public void onFailedDownload(String fileName) { - updateButtonState(true); - } - - @Override - public void onSuccessDownload(String fileName) { - updateButtonState(true); - } - - @Override - public void onProgressDownload(String fileName, float progress) { - radialProgress.setProgress(progress, true); - if (buttonState != 3) { - updateButtonState(false); - } - } - - @Override - public void onProgressUpload(String fileName, float progress, boolean isEncrypted) { - radialProgress.setProgress(progress, true); - } - - @Override - public void onSeekBarDrag(float progress) { - if (currentMessageObject == null) { - return; - } - currentMessageObject.audioProgress = progress; - MediaController.getInstance().seekToProgress(currentMessageObject, progress); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int width = MeasureSpec.getSize(widthMeasureSpec); - setMeasuredDimension(width, AndroidUtilities.dp(66) + namesOffset); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - - if (currentMessageObject.isOutOwner()) { - //seekBarX = layoutWidth - backgroundWidth + AndroidUtilities.dp(55); - //buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(13); - //timeX = layoutWidth - backgroundWidth + AndroidUtilities.dp(66); - seekBarX = layoutWidth - backgroundWidth + AndroidUtilities.dp(55) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); - buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(13) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); - timeX = layoutWidth - backgroundWidth + AndroidUtilities.dp(66) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); - } else { - //if (isChat && currentMessageObject.messageOwner.from_id > 0) { - if ((isChat || showAvatar) && currentMessageObject.messageOwner.from_id > 0) { - //seekBarX = AndroidUtilities.dp(116); - //buttonX = AndroidUtilities.dp(74); - //timeX = AndroidUtilities.dp(127); - seekBarX = AndroidUtilities.dp(leftBound + 64); - buttonX = AndroidUtilities.dp(leftBound + 22); - timeX = AndroidUtilities.dp(leftBound + 75); - } else { - seekBarX = AndroidUtilities.dp(64); - buttonX = AndroidUtilities.dp(22); - timeX = AndroidUtilities.dp(75); - } - } - - seekBar.width = backgroundWidth - AndroidUtilities.dp(70); - seekBar.height = AndroidUtilities.dp(30); - seekBarY = AndroidUtilities.dp(11) + namesOffset; - buttonY = AndroidUtilities.dp(13) + namesOffset; - radialProgress.setProgressRect(buttonX, buttonY, buttonX + AndroidUtilities.dp(40), buttonY + AndroidUtilities.dp(40)); - - updateProgress(); - } - - @Override - public void setMessageObject(MessageObject messageObject) { - boolean dataChanged = currentMessageObject == messageObject && isUserDataChanged(); - if (currentMessageObject != messageObject || dataChanged) { - if (AndroidUtilities.isTablet()) { - //backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(isChat && messageObject.messageOwner.from_id > 0 ? 102 : 50), AndroidUtilities.dp(300)); - backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp( ((isChat || showAvatar) && messageObject.messageOwner.from_id > 0) || (messageObject.isOutOwner() && ((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat))) ? leftBound + 50 : 50), AndroidUtilities.dp(300)); - } else { - //backgroundWidth = Math.min(AndroidUtilities.displaySize.x - AndroidUtilities.dp(isChat && messageObject.messageOwner.from_id > 0 ? 102 : 50), AndroidUtilities.dp(300)); - backgroundWidth = Math.min(AndroidUtilities.displaySize.x - AndroidUtilities.dp((isChat || showAvatar) || (messageObject.isOut() && ((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat))) ? leftBound + 50 : 50), AndroidUtilities.dp(300)); - } - - if (messageObject.isOutOwner()) { - seekBar.type = 0; - //radialProgress.setProgressColor(0xff87bf78); - } else { - seekBar.type = 1; - //radialProgress.setProgressColor(0xffa2b5c7); - } - - super.setMessageObject(messageObject); - } - updateButtonState(dataChanged); - } - - @Override - public void setCheckPressed(boolean value, boolean pressed) { - super.setCheckPressed(value, pressed); - if (radialProgress.swapBackground(getDrawableForCurrentState())) { - invalidate(); - } - } - - @Override - public void setHighlighted(boolean value) { - super.setHighlighted(value); - if (radialProgress.swapBackground(getDrawableForCurrentState())) { - invalidate(); - } - } - - @Override - public void setPressed(boolean pressed) { - super.setPressed(pressed); - if (radialProgress.swapBackground(getDrawableForCurrentState())) { - invalidate(); - } - } - - private Drawable getDrawableForCurrentState() { - return ResourceLoader.audioStatesDrawable[currentMessageObject.isOutOwner() ? buttonState : buttonState + 5][isDrawSelectedBackground() ? 2 : (buttonPressed ? 1 : 0)]; - } - - @Override - protected void onDraw(Canvas canvas) { - if (currentMessageObject == null) { - return; - } - - super.onDraw(canvas); - - canvas.save(); - canvas.translate(seekBarX, seekBarY); - seekBar.draw(canvas); - canvas.restore(); - - radialProgress.setProgressColor(currentMessageObject.isOutOwner() ? 0xff87bf78 : (isDrawSelectedBackground() ? 0xff83b2c2 : 0xffa2b5c7)); - timePaint.setColor(currentMessageObject.isOutOwner() ? 0xff70b15c : (isDrawSelectedBackground() ? 0xff89b4c1 : 0xffa1aab3)); - circlePaint.setColor(currentMessageObject.isOutOwner() ? 0xff87bf78 : 0xff4195e5); - radialProgress.draw(canvas); - - canvas.save(); - canvas.translate(timeX, AndroidUtilities.dp(42) + namesOffset); - timeLayout.draw(canvas); - canvas.restore(); - - if (currentMessageObject.messageOwner.to_id.channel_id == 0 && currentMessageObject.isContentUnread()) { - canvas.drawCircle(timeX + timeWidth + AndroidUtilities.dp(8), AndroidUtilities.dp(49.5f) + namesOffset, AndroidUtilities.dp(3), circlePaint); - } - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java index 4aceb766..f906986b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatBaseCell.java @@ -1,5 +1,5 @@ /* - * This is the source code of Telegram for Android v. 1.3.x. + * This is the source code of Telegram for Android v. 3.x.x. * It is licensed under GNU GPL v. 2 or later. * You should have received a copy of the license in this archive (see LICENSE). * @@ -12,11 +12,11 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.SharedPreferences; -import android.content.res.Configuration; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; +import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.text.Layout; @@ -32,61 +32,62 @@ import android.view.SoundEffectConstants; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ContactsController; import org.telegram.messenger.Emoji; -import org.telegram.messenger.FileLoader; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.ImageReceiver; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; -import org.telegram.messenger.MessageObject; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.R; import org.telegram.messenger.UserObject; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.ImageReceiver; import org.telegram.ui.Components.AvatarDrawable; -import org.telegram.ui.Components.LinkPath; -import org.telegram.ui.Components.ResourceLoader; -import org.telegram.ui.Components.StaticLayoutEx; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.TypefaceSpan; public class ChatBaseCell extends BaseCell implements MediaController.FileDownloadProgressListener { public interface ChatBaseCellDelegate { void didPressedUserAvatar(ChatBaseCell cell, TLRPC.User user); - void didPressedViaBot(ChatBaseCell cell, TLRPC.User user); - void didPressedChannelAvatar(ChatBaseCell cell, TLRPC.Chat chat); + void didPressedViaBot(ChatBaseCell cell, String username); + void didPressedChannelAvatar(ChatBaseCell cell, TLRPC.Chat chat, int postId); void didPressedCancelSendButton(ChatBaseCell cell); void didLongPressed(ChatBaseCell cell); - void didPressReplyMessage(ChatBaseCell cell, int id); - void didPressUrl(MessageObject messageObject, ClickableSpan url, boolean longPress); - void needOpenWebView(String url, String title, String originalUrl, int w, int h); - void didClickedImage(ChatBaseCell cell); - void didPressShare(ChatBaseCell cell); + void didPressedReplyMessage(ChatBaseCell cell, int id); + void didPressedUrl(MessageObject messageObject, ClickableSpan url, boolean longPress); + void needOpenWebView(String url, String title, String description, String originalUrl, int w, int h); + void didPressedImage(ChatBaseCell cell); + void didPressedShare(ChatBaseCell cell); + void didPressedOther(ChatBaseCell cell); + void didPressedBotButton(ChatBaseCell cell, TLRPC.KeyboardButton button); + boolean needPlayAudio(MessageObject messageObject); boolean canPerformActions(); } - protected ClickableSpan pressedLink; - protected boolean linkPreviewPressed; - protected LinkPath urlPath = new LinkPath(); - protected static Paint urlPaint; private int TAG; public boolean isChat; protected boolean isPressed; protected boolean forwardName; protected boolean isHighlighted; - protected boolean media; + protected boolean mediaBackground; protected boolean isCheckPressed = true; private boolean wasLayout; protected boolean isAvatarVisible; protected boolean drawBackground = true; + protected int substractBackgroundHeight; protected boolean allowAssistant; + protected Drawable currentBackgroundDrawable; protected MessageObject currentMessageObject; private int viaWidth; private int viaNameWidth; + protected int availableTimeWidth; - private static TextPaint timePaint; + protected static TextPaint timePaint; private static TextPaint namePaint; private static TextPaint forwardNamePaint; protected static TextPaint replyNamePaint; @@ -117,7 +118,6 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo private boolean replyPressed; private TLRPC.FileLocation currentReplyPhoto; - //private boolean drawShareButton; protected boolean drawShareButton; private boolean sharePressed; private int shareStartX; @@ -127,14 +127,16 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo protected int nameWidth; private float nameOffsetX; private float nameX; + private float nameY; protected boolean drawName; + protected boolean drawNameLayout; - private StaticLayout forwardedNameLayout; + private StaticLayout[] forwardedNameLayout = new StaticLayout[2]; protected int forwardedNameWidth; protected boolean drawForwardedName; private int forwardNameX; private int forwardNameY; - private float forwardNameOffsetX; + private float forwardNameOffsetX[] = new float[2]; private StaticLayout timeLayout; protected int timeWidth; @@ -164,7 +166,8 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo private int lastSendState; private int lastDeleteDate; private int lastViewsCount; - protected int leftBound = 52;//52 + //plus + protected int leftBound = 48;//52 //private int avatarSize = AndroidUtilities.dp(42); protected int avatarSize = AndroidUtilities.dp(42); protected boolean avatarAlignTop = false; @@ -173,11 +176,12 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo boolean showAvatar = false; boolean showMyAvatar = false; - boolean showMyAvatarGroup = true; + boolean showMyAvatarGroup = false; private int checkX = 0; private GradientDrawable statusBG; private boolean drawStatus; + private boolean showEditedMark; public ChatBaseCell(Context context) { super(context); @@ -186,7 +190,8 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo timePaint.setTextSize(AndroidUtilities.dp(12)); namePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - namePaint.setTextSize(AndroidUtilities.dp(15)); + namePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + namePaint.setTextSize(AndroidUtilities.dp(14)); forwardNamePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); forwardNamePaint.setTextSize(AndroidUtilities.dp(14)); @@ -197,18 +202,16 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo replyTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); replyTextPaint.setTextSize(AndroidUtilities.dp(14)); - replyTextPaint.linkColor = 0xff316f9f; + replyTextPaint.linkColor = Theme.MSG_LINK_TEXT_COLOR; replyLinePaint = new Paint(); - - urlPaint = new Paint(); - urlPaint.setColor(0x33316f9f); } avatarImage = new ImageReceiver(this); avatarImage.setRoundRadius(AndroidUtilities.dp(21)); avatarDrawable = new AvatarDrawable(); replyImageReceiver = new ImageReceiver(this); TAG = MediaController.getInstance().generateObserverTag(); + //plus SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); int radius = AndroidUtilities.dp(themePrefs.getInt("chatAvatarRadius", 32)); avatarImage.setRoundRadius(radius); @@ -222,8 +225,8 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo showMyAvatar = themePrefs.getBoolean("chatShowOwnAvatar", false); showMyAvatarGroup = themePrefs.getBoolean("chatShowOwnAvatarGroup", false); showAvatar = themePrefs.getBoolean("chatShowContactAvatar", false); - leftBound = aSize + AndroidUtilities.dp(3); - + //leftBound = aSize + AndroidUtilities.dp(3); + leftBound = aSize + 6; statusBG = new GradientDrawable(); statusBG.setColor(Color.GRAY); statusBG.setCornerRadius(AndroidUtilities.dp(13)); @@ -273,27 +276,27 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } replyTextPaint.linkColor = linkColor; - if(ResourceLoader.mediaBackgroundDrawable != null)ResourceLoader.mediaBackgroundDrawable.setColorFilter(bColor, PorterDuff.Mode.SRC_IN); + //if(Theme.mediaBackgroundDrawable != null)Theme.mediaBackgroundDrawable.setColorFilter(bColor, PorterDuff.Mode.SRC_IN); - ResourceLoader.backgroundDrawableOut.setColorFilter(rBubbleColor, PorterDuff.Mode.SRC_IN); - ResourceLoader.backgroundMediaDrawableOut.setColorFilter(rBubbleColor, PorterDuff.Mode.SRC_IN); - ResourceLoader.backgroundDrawableOutSelected.setColorFilter(rBubbleSColor, PorterDuff.Mode.SRC_IN); - ResourceLoader.backgroundMediaDrawableOutSelected.setColorFilter(rBubbleSColor, PorterDuff.Mode.SRC_IN); + Theme.backgroundDrawableOut.setColorFilter(rBubbleColor, PorterDuff.Mode.SRC_IN); + Theme.backgroundMediaDrawableOut.setColorFilter(rBubbleColor, PorterDuff.Mode.SRC_IN); + Theme.backgroundDrawableOutSelected.setColorFilter(rBubbleSColor, PorterDuff.Mode.SRC_IN); + Theme.backgroundMediaDrawableOutSelected.setColorFilter(rBubbleSColor, PorterDuff.Mode.SRC_IN); - ResourceLoader.backgroundDrawableIn.setColorFilter(lBubbleColor, PorterDuff.Mode.SRC_IN); - ResourceLoader.backgroundMediaDrawableIn.setColorFilter(lBubbleColor, PorterDuff.Mode.SRC_IN); - ResourceLoader.backgroundDrawableInSelected.setColorFilter(lBubbleSColor, PorterDuff.Mode.SRC_IN); - ResourceLoader.backgroundMediaDrawableInSelected.setColorFilter(lBubbleSColor, PorterDuff.Mode.SRC_IN); + Theme.backgroundDrawableIn.setColorFilter(lBubbleColor, PorterDuff.Mode.SRC_IN); + Theme.backgroundMediaDrawableIn.setColorFilter(lBubbleColor, PorterDuff.Mode.SRC_IN); + Theme.backgroundDrawableInSelected.setColorFilter(lBubbleSColor, PorterDuff.Mode.SRC_IN); + Theme.backgroundMediaDrawableInSelected.setColorFilter(lBubbleSColor, PorterDuff.Mode.SRC_IN); int checksColor = themePrefs.getInt("chatChecksColor", defColor); - ResourceLoader.checkDrawable.setColorFilter(checksColor, PorterDuff.Mode.SRC_IN); - ResourceLoader.halfCheckDrawable.setColorFilter(checksColor, PorterDuff.Mode.SRC_IN); - ResourceLoader.clockDrawable.setColorFilter(checksColor, PorterDuff.Mode.SRC_IN); - ResourceLoader.checkMediaDrawable.setColorFilter(checksColor, PorterDuff.Mode.MULTIPLY); - ResourceLoader.halfCheckMediaDrawable.setColorFilter(checksColor, PorterDuff.Mode.MULTIPLY); - ResourceLoader.halfCheckMediaDrawable.setColorFilter(checksColor, PorterDuff.Mode.MULTIPLY); + Theme.checkDrawable.setColorFilter(checksColor, PorterDuff.Mode.SRC_IN); + Theme.halfCheckDrawable.setColorFilter(checksColor, PorterDuff.Mode.SRC_IN); + Theme.clockDrawable.setColorFilter(checksColor, PorterDuff.Mode.SRC_IN); + Theme.checkMediaDrawable.setColorFilter(checksColor, PorterDuff.Mode.MULTIPLY); + Theme.halfCheckMediaDrawable.setColorFilter(checksColor, PorterDuff.Mode.MULTIPLY); + Theme.halfCheckMediaDrawable.setColorFilter(checksColor, PorterDuff.Mode.MULTIPLY); - ResourceLoader.viewsCountDrawable.setColorFilter(vColor, PorterDuff.Mode.SRC_IN); + //Theme.viewsCountDrawable.setColorFilter(vColor, PorterDuff.Mode.SRC_IN); } catch (NullPointerException e) { FileLog.e("tmessages", e); } @@ -319,14 +322,6 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo invalidate(); } - protected void resetPressedLink() { - if (pressedLink != null) { - pressedLink = null; - } - linkPreviewPressed = false; - invalidate(); - } - public void setDelegate(ChatBaseCellDelegate delegate) { this.delegate = delegate; } @@ -365,10 +360,12 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo TLRPC.User newUser = null; TLRPC.Chat newChat = null; - if (currentMessageObject.messageOwner.from_id > 0) { + if (currentMessageObject.isFromUser()) { newUser = MessagesController.getInstance().getUser(currentMessageObject.messageOwner.from_id); } else if (currentMessageObject.messageOwner.from_id < 0) { newChat = MessagesController.getInstance().getChat(-currentMessageObject.messageOwner.from_id); + } else if (currentMessageObject.messageOwner.post) { + newChat = MessagesController.getInstance().getChat(currentMessageObject.messageOwner.to_id.channel_id); } TLRPC.FileLocation newPhoto = null; //plus @@ -417,19 +414,60 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } if (drawForwardedName) { - newNameString = currentMessageObject.getForwardedName(); - return currentForwardNameString == null && newNameString != null || currentForwardNameString != null && newNameString == null || currentForwardNameString != null && newNameString != null && !currentForwardNameString.equals(newNameString); - } + newNameString = currentMessageObject.getForwardedName(); + return currentForwardNameString == null && newNameString != null || currentForwardNameString != null && newNameString == null || currentForwardNameString != null && newNameString != null && !currentForwardNameString.equals(newNameString); + } return false; } protected void measureTime(MessageObject messageObject) { - currentTimeString = LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000); + boolean hasSign = !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0 && messageObject.messageOwner.post; + TLRPC.User signUser = MessagesController.getInstance().getUser(messageObject.messageOwner.from_id); + if (hasSign && signUser == null) { + hasSign = false; + } + if (hasSign) { + currentTimeString = ", " + LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000); + } else { + currentTimeString = LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000); + } + if(showEditedMark && messageObject.messageOwner.edit_date > 0)currentTimeString = currentTimeString + " E"; timeTextWidth = timeWidth = (int) Math.ceil(timePaint.measureText(currentTimeString)); if ((messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { currentViewsString = String.format("%s", LocaleController.formatShortNumber(Math.max(1, messageObject.messageOwner.views), null)); - timeWidth += (int) Math.ceil(timePaint.measureText(currentViewsString)) + ResourceLoader.viewsCountDrawable.getIntrinsicWidth() + AndroidUtilities.dp(10); + viewsTextWidth = (int) Math.ceil(timePaint.measureText(currentViewsString)); + timeWidth += viewsTextWidth + Theme.viewsCountDrawable[0].getIntrinsicWidth() + AndroidUtilities.dp(10); } + if (hasSign) { + if (availableTimeWidth == 0) { + availableTimeWidth = AndroidUtilities.dp(1000); + } + CharSequence name = ContactsController.formatName(signUser.first_name, signUser.last_name).replace('\n', ' '); + int widthForSign = availableTimeWidth - timeWidth; + int width = (int) Math.ceil(timePaint.measureText(name, 0, name.length())); + if (width > widthForSign) { + name = TextUtils.ellipsize(name, timePaint, widthForSign, TextUtils.TruncateAt.END); + width = widthForSign; + } + currentTimeString = name + currentTimeString; + timeTextWidth += width; + timeWidth += width; + } + } + + protected boolean checkNeedDrawShareButton(MessageObject messageObject) { + if (messageObject.isFromUser()) { + TLRPC.User user = MessagesController.getInstance().getUser(messageObject.messageOwner.from_id); + if (user != null && user.bot && messageObject.type != 13 && !(messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaEmpty || messageObject.messageOwner.media == null + || messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && !(messageObject.messageOwner.media.webpage instanceof TLRPC.TL_webPage))) { + return true; + } + } else if (messageObject.messageOwner.from_id < 0 || messageObject.messageOwner.post) { + if (messageObject.messageOwner.to_id.channel_id != 0 && (messageObject.messageOwner.via_bot_id == 0 && messageObject.messageOwner.reply_to_msg_id == 0 || messageObject.type != 13)) { + return true; + } + } + return false; } public void setMessageObject(MessageObject messageObject) { @@ -441,7 +479,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo isCheckPressed = true; isAvatarVisible = false; wasLayout = false; - drawShareButton = false; + drawShareButton = checkNeedDrawShareButton(messageObject); replyNameLayout = null; replyTextLayout = null; replyNameWidth = 0; @@ -452,6 +490,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo currentUser = null; currentChat = null; currentViaBotUser = null; + drawNameLayout = false; if ((messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { if (currentMessageObject.isContentUnread() && !currentMessageObject.isOut()) { @@ -464,10 +503,10 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + showEditedMark = preferences.getBoolean("showEditedMark", true); - //Log.e("chatBaseCell","messageObject.messageOwner.from_id " + messageObject.messageOwner.from_id); - if (messageObject.messageOwner.from_id > 0) { - currentUser = MessagesController.getInstance().getUser(messageObject.messageOwner.from_id); + if (currentMessageObject.isFromUser()) { + currentUser = MessagesController.getInstance().getUser(currentMessageObject.messageOwner.from_id); if(currentUser != null && !currentMessageObject.isOut() && messageObject.type != 13){ //Log.e("chatBaseCell"," chat_id " + messageObject.messageOwner.to_id.chat_id); boolean showDSBtnUsers = preferences.getBoolean("showDSBtnUsers", false); @@ -476,8 +515,8 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo boolean showDSBtnBots = preferences.getBoolean("showDSBtnBots", true); if(showDSBtnBots && currentUser.bot || !isChat && !currentUser.bot && showDSBtnUsers || showDSBtnSGroups && messageObject.isMegagroup() || messageObject.messageOwner.to_id.chat_id != 0 && showDSBtnGroups)drawShareButton = true; // Users Bots Supergroups } - } else if (messageObject.messageOwner.from_id < 0) { - currentChat = MessagesController.getInstance().getChat(-messageObject.messageOwner.from_id); + } else if (currentMessageObject.messageOwner.from_id < 0) { + currentChat = MessagesController.getInstance().getChat(-currentMessageObject.messageOwner.from_id); if (messageObject.messageOwner.to_id.channel_id != 0 && (messageObject.messageOwner.reply_to_msg_id == 0 || messageObject.type != 13)) { drawShareButton = true; } @@ -485,11 +524,12 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo boolean showDSBtnChannels = preferences.getBoolean("showDSBtnChannels", true); drawShareButton = messageObject.messageOwner.to_id.channel_id != 0 && showDSBtnChannels; // Groups Channels } + } else if (currentMessageObject.messageOwner.post) { + currentChat = MessagesController.getInstance().getChat(currentMessageObject.messageOwner.to_id.channel_id); } - setStatusColor(currentUser); - //if (isChat && !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0) { - if ( ((isChat || showAvatar) && !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0) + //if (isChat && !messageObject.isOutOwner() && messageObject.isFromUser()) { + if ( ((isChat || showAvatar) && !messageObject.isOutOwner() && messageObject.isFromUser()) || ( (showMyAvatar && !isChat) || (showMyAvatarGroup && isChat) ) && messageObject.isOutOwner()) { isAvatarVisible = true; if (currentUser != null) { @@ -515,166 +555,171 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo avatarImage.setImage(currentPhoto, "50_50", avatarDrawable, null, false); } - /*if (!media) { - if (currentMessageObject.isOutOwner()) { - //currentTimePaint = timePaintOut; - } else { - //currentTimePaint = timePaintIn; - } - } else { - //currentTimePaint = timeMediaPaint; - }*/ - currentTimeString = LocaleController.getInstance().formatterDay.format((long) (messageObject.messageOwner.date) * 1000); - timeTextWidth = timeWidth = (int)Math.ceil(timePaint.measureText(currentTimeString)); - if ((messageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { - currentViewsString = String.format("%s", LocaleController.formatShortNumber(Math.max(1, messageObject.messageOwner.views), null)); - viewsTextWidth = (int) Math.ceil(timePaint.measureText(currentViewsString)); - timeWidth += viewsTextWidth + ResourceLoader.viewsCountDrawable.getIntrinsicWidth() + AndroidUtilities.dp(10); - } + measureTime(messageObject); namesOffset = 0; String viaUsername = null; - String viaString = null; + CharSequence viaString = null; if (messageObject.messageOwner.via_bot_id != 0) { TLRPC.User botUser = MessagesController.getInstance().getUser(messageObject.messageOwner.via_bot_id); if (botUser != null && botUser.username != null && botUser.username.length() > 0) { viaUsername = "@" + botUser.username; - viaString = " via " + viaUsername; - viaWidth = (int) Math.ceil(forwardNamePaint.measureText(viaString)); + viaString = AndroidUtilities.replaceTags(String.format(" via %s", viaUsername)); + viaWidth = (int) Math.ceil(replyNamePaint.measureText(viaString, 0, viaString.length())); currentViaBotUser = botUser; } + } else if (messageObject.messageOwner.via_bot_name != null && messageObject.messageOwner.via_bot_name.length() > 0) { + viaUsername = "@" + messageObject.messageOwner.via_bot_name; + viaString = AndroidUtilities.replaceTags(String.format(" via %s", viaUsername)); + viaWidth = (int) Math.ceil(replyNamePaint.measureText(viaString, 0, viaString.length())); } + boolean authorName = drawName && isChat && !currentMessageObject.isOutOwner(); - boolean viaBot = messageObject.messageOwner.fwd_from_id == null && currentViaBotUser != null; + boolean viaBot = (messageObject.messageOwner.fwd_from == null || messageObject.type == 14) && viaUsername != null; if (authorName || viaBot) { - drawName = true; + drawNameLayout = true; nameWidth = getMaxNameWidth(); if (nameWidth < 0) { nameWidth = AndroidUtilities.dp(100); } - if (authorName || !currentMessageObject.isOutOwner()) { - if (currentUser != null) { - currentNameString = UserObject.getUserName(currentUser); - String currentUsernameString = currentUser.username; - if(currentUsernameString != null && AndroidUtilities.getBoolPref("chatShowUsernameCheck")){ - currentNameString = currentNameString.replaceAll("\\p{C}", " "); - currentNameString = currentNameString.trim().replaceAll(" +", " ") + " [@"+currentUsernameString+"]"; + + if (authorName) { + if (currentUser != null) { + currentNameString = UserObject.getUserName(currentUser); + String currentUsernameString = currentUser.username; + if(currentUsernameString != null && AndroidUtilities.getBoolPref("chatShowUsernameCheck")){ + currentNameString = currentNameString.replaceAll("\\p{C}", " "); + currentNameString = currentNameString.trim().replaceAll(" +", " ") + " [@"+currentUsernameString+"]"; + } + } else if (currentChat != null) { + currentNameString = currentChat.title; + } else { + currentNameString = "DELETED"; } - } else if (currentChat != null) { - currentNameString = currentChat.title; - } else { - currentNameString = "DELETED"; - } } else { currentNameString = ""; } - - CharSequence nameStringFinal = TextUtils.ellipsize(currentNameString.replace("\n", " "), namePaint, nameWidth - AndroidUtilities.dp(12) - (viaBot ? viaWidth : 0), TextUtils.TruncateAt.END); + CharSequence nameStringFinal = TextUtils.ellipsize(currentNameString.replace('\n', ' '), namePaint, nameWidth - (viaBot ? viaWidth : 0), TextUtils.TruncateAt.END); if (viaBot) { viaNameWidth = (int) Math.ceil(namePaint.measureText(nameStringFinal, 0, nameStringFinal.length())); if (viaNameWidth != 0) { viaNameWidth += AndroidUtilities.dp(4); } + int color; + if (currentMessageObject.type == 13) { + color = Theme.MSG_STICKER_VIA_BOT_NAME_TEXT_COLOR; + } else { + color = currentMessageObject.isOutOwner() ? Theme.MSG_OUT_VIA_BOT_NAME_TEXT_COLOR : Theme.MSG_IN_VIA_BOT_NAME_TEXT_COLOR; + } SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); int defColor = themePrefs.getInt("themeColor", AndroidUtilities.defColor); - int rColor = 0xff4a923c; - int lColor = 0xff006fc8; + int rColor = Theme.MSG_OUT_VIA_BOT_NAME_TEXT_COLOR; + int lColor = Theme.MSG_IN_VIA_BOT_NAME_TEXT_COLOR; if (currentMessageObject.isOutOwner()) { rColor = themePrefs.getInt("chatForwardRColor", AndroidUtilities.setDarkColor(defColor, 0x15)); + color = rColor; }else{ lColor = themePrefs.getInt("chatForwardLColor", defColor); + color = lColor; } if (currentNameString.length() > 0) { - SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.format("%s via @%s", nameStringFinal, currentViaBotUser.username)); - //stringBuilder.setSpan(new TypefaceSpan(null, 0, currentMessageObject.isOutOwner() ? 0xff4a923c : 0xff006fc8), nameStringFinal.length() + 1, nameStringFinal.length() + 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - stringBuilder.setSpan(new TypefaceSpan(null, 0, currentMessageObject.isOutOwner() ? rColor : lColor), nameStringFinal.length() + 1, nameStringFinal.length() + 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - //stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, currentMessageObject.isOutOwner() ? 0xff4a923c : 0xff006fc8), nameStringFinal.length() + 5, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, currentMessageObject.isOutOwner() ? rColor : lColor), nameStringFinal.length() + 5, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.format("%s via %s", nameStringFinal, viaUsername)); + stringBuilder.setSpan(new TypefaceSpan(Typeface.DEFAULT, 0, color), nameStringFinal.length() + 1, nameStringFinal.length() + 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, color), nameStringFinal.length() + 5, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); nameStringFinal = stringBuilder; } else { - SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.format("via @%s", currentViaBotUser.username)); - //stringBuilder.setSpan(new TypefaceSpan(null, 0, currentMessageObject.isOutOwner() ? 0xff4a923c : 0xff006fc8), 0, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - stringBuilder.setSpan(new TypefaceSpan(null, 0, currentMessageObject.isOutOwner() ? rColor : lColor), 0, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - //stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, currentMessageObject.isOutOwner() ? 0xff4a923c : 0xff006fc8), 4, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, currentMessageObject.isOutOwner() ? rColor : lColor), 4, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(String.format("via %s", viaUsername)); + stringBuilder.setSpan(new TypefaceSpan(Typeface.DEFAULT, 0, color), 0, 4, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + stringBuilder.setSpan(new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, color), 4, stringBuilder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); nameStringFinal = stringBuilder; } + nameStringFinal = TextUtils.ellipsize(nameStringFinal, namePaint, nameWidth, TextUtils.TruncateAt.END); } try { - nameLayout = new StaticLayout(nameStringFinal, namePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + nameLayout = new StaticLayout(nameStringFinal, namePaint, nameWidth + AndroidUtilities.dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (nameLayout != null && nameLayout.getLineCount() > 0) { - nameWidth = (int)Math.ceil(nameLayout.getLineWidth(0)); - namesOffset += AndroidUtilities.dp(19); - nameOffsetX = nameLayout.getLineLeft(0); - } else { - nameWidth = 0; - } + nameWidth = (int) Math.ceil(nameLayout.getLineWidth(0)); + if (messageObject.type != 13) { + namesOffset += AndroidUtilities.dp(19); + } + nameOffsetX = nameLayout.getLineLeft(0); + } else { + nameWidth = 0; + } } catch (Exception e) { FileLog.e("tmessages", e); } + if (currentNameString.length() == 0) { + currentNameString = null; + } } else { currentNameString = null; nameLayout = null; nameWidth = 0; } + currentForwardUser = null; + currentForwardNameString = null; + forwardedNameLayout[0] = null; + forwardedNameLayout[1] = null; + forwardedNameWidth = 0; if (drawForwardedName && messageObject.isForwarded()) { - if (messageObject.messageOwner.fwd_from_id instanceof TLRPC.TL_peerChannel) { - currentForwardChannel = MessagesController.getInstance().getChat(messageObject.messageOwner.fwd_from_id.channel_id); - currentForwardUser = null; - } else if (messageObject.messageOwner.fwd_from_id instanceof TLRPC.TL_peerUser) { - currentForwardChannel = null; - currentForwardUser = MessagesController.getInstance().getUser(messageObject.messageOwner.fwd_from_id.user_id); + currentForwardChannel = null; + if (messageObject.messageOwner.fwd_from.channel_id != 0) { + currentForwardChannel = MessagesController.getInstance().getChat(messageObject.messageOwner.fwd_from.channel_id); + } + if (messageObject.messageOwner.fwd_from.from_id != 0) { + currentForwardUser = MessagesController.getInstance().getUser(messageObject.messageOwner.fwd_from.from_id); } if (currentForwardUser != null || currentForwardChannel != null) { - if (currentForwardUser != null) { + if (currentForwardChannel != null) { + if (currentForwardUser != null) { + currentForwardNameString = String.format("%s (%s)", currentForwardChannel.title, UserObject.getUserName(currentForwardUser)); + } else { + currentForwardNameString = currentForwardChannel.title; + } + } else if (currentForwardUser != null) { currentForwardNameString = UserObject.getUserName(currentForwardUser); - } else { - currentForwardNameString = currentForwardChannel.title; } forwardedNameWidth = getMaxNameWidth(); - /*SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); int defColor = themePrefs.getInt("themeColor", AndroidUtilities.defColor); if (currentMessageObject.isOutOwner()) { forwardNamePaint.setColor(themePrefs.getInt("chatForwardRColor", AndroidUtilities.setDarkColor(defColor, 0x15))); }else{ forwardNamePaint.setColor(themePrefs.getInt("chatForwardLColor", defColor)); - }*/ - CharSequence str = TextUtils.ellipsize(currentForwardNameString.replace("\n", " "), forwardNamePaint, forwardedNameWidth - AndroidUtilities.dp(40) - viaWidth, TextUtils.TruncateAt.END); + } + int fromWidth = (int) Math.ceil(forwardNamePaint.measureText(LocaleController.getString("From", R.string.From) + " ")); + CharSequence name = TextUtils.ellipsize(currentForwardNameString.replace('\n', ' '), replyNamePaint, forwardedNameWidth - fromWidth - viaWidth, TextUtils.TruncateAt.END); + CharSequence lastLine; if (viaString != null) { - viaNameWidth = (int) Math.ceil(forwardNamePaint.measureText(LocaleController.getString("From", R.string.From) + " " + str)); - str = AndroidUtilities.replaceTags(String.format("%s\n%s %s via %s", LocaleController.getString("ForwardedMessage", R.string.ForwardedMessage), LocaleController.getString("From", R.string.From), str, viaUsername)); + viaNameWidth = (int) Math.ceil(forwardNamePaint.measureText(LocaleController.getString("From", R.string.From) + " " + name)); + lastLine = AndroidUtilities.replaceTags(String.format("%s %s via %s", LocaleController.getString("From", R.string.From), name, viaUsername)); } else { - str = AndroidUtilities.replaceTags(String.format("%s\n%s %s", LocaleController.getString("ForwardedMessage", R.string.ForwardedMessage), LocaleController.getString("From", R.string.From), str)); + lastLine = AndroidUtilities.replaceTags(String.format("%s %s", LocaleController.getString("From", R.string.From), name)); } - forwardedNameLayout = StaticLayoutEx.createStaticLayout(str, forwardNamePaint, forwardedNameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, forwardedNameWidth, 2); - if (forwardedNameLayout.getLineCount() > 1) { - forwardedNameWidth = Math.max((int) Math.ceil(forwardedNameLayout.getLineWidth(0)), (int) Math.ceil(forwardedNameLayout.getLineWidth(1))); + lastLine = TextUtils.ellipsize(lastLine, forwardNamePaint, forwardedNameWidth, TextUtils.TruncateAt.END); + try { + forwardedNameLayout[1] = new StaticLayout(lastLine, forwardNamePaint, forwardedNameWidth + AndroidUtilities.dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + lastLine = TextUtils.ellipsize(AndroidUtilities.replaceTags(LocaleController.getString("ForwardedMessage", R.string.ForwardedMessage)), forwardNamePaint, forwardedNameWidth, TextUtils.TruncateAt.END); + forwardedNameLayout[0] = new StaticLayout(lastLine, forwardNamePaint, forwardedNameWidth + AndroidUtilities.dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + forwardedNameWidth = Math.max((int) Math.ceil(forwardedNameLayout[0].getLineWidth(0)), (int) Math.ceil(forwardedNameLayout[1].getLineWidth(0))); + forwardNameOffsetX[0] = forwardedNameLayout[0].getLineLeft(0); + forwardNameOffsetX[1] = forwardedNameLayout[1].getLineLeft(0); namesOffset += AndroidUtilities.dp(36); - forwardNameOffsetX = Math.min(forwardedNameLayout.getLineLeft(0), forwardedNameLayout.getLineLeft(1)); - } else { - forwardedNameWidth = 0; + } catch (Exception e) { + FileLog.e("tmessages", e); } - } else { - currentForwardNameString = null; - forwardedNameLayout = null; - forwardedNameWidth = 0; } - } else { - currentForwardNameString = null; - forwardedNameLayout = null; - forwardedNameWidth = 0; } if (messageObject.isReply()) { namesOffset += AndroidUtilities.dp(42); - if (messageObject.contentType == 2 || messageObject.contentType == 3) { - namesOffset += AndroidUtilities.dp(4); - } else if (messageObject.contentType == 1) { + if (messageObject.type != 0) { if (messageObject.type == 13) { namesOffset -= AndroidUtilities.dp(42); } else { @@ -682,42 +727,16 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } } - int maxWidth; - if (messageObject.type == 13) { - int width; - if (AndroidUtilities.isTablet()) { - if (AndroidUtilities.isSmallTablet() && getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - width = AndroidUtilities.displaySize.x; - } else { - int leftWidth = AndroidUtilities.displaySize.x / 100 * 35; - if (leftWidth < AndroidUtilities.dp(320)) { - leftWidth = AndroidUtilities.dp(320); - } - width = AndroidUtilities.displaySize.x - leftWidth; - } - } else { - width = AndroidUtilities.displaySize.x; - } - - if (messageObject.isOutOwner()) { - //maxWidth = width - backgroundWidth - AndroidUtilities.dp(60); - maxWidth = width - backgroundWidth - AndroidUtilities.dp(60 + ((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat) ? (leftBound + 10) : 0)); - } else { - //maxWidth = width - backgroundWidth - AndroidUtilities.dp(56 + (isChat && messageObject.messageOwner.from_id > 0 ? 61 : 0)); - maxWidth = width - backgroundWidth - AndroidUtilities.dp(56 + (isChat || showAvatar ? (leftBound + 10) : 0)); - } - } else { - maxWidth = getMaxNameWidth() - AndroidUtilities.dp(22); - } - if (!media && messageObject.contentType != 0) { - maxWidth -= AndroidUtilities.dp(8); + int maxWidth = getMaxNameWidth(); + if (messageObject.type != 13) { + maxWidth -= AndroidUtilities.dp(10); } CharSequence stringFinalName = null; CharSequence stringFinalText = null; if (messageObject.replyMessageObject != null) { TLRPC.PhotoSize photoSize = FileLoader.getClosestPhotoSizeWithSize(messageObject.replyMessageObject.photoThumbs, 80); - if (photoSize == null || messageObject.replyMessageObject.type == 13 || messageObject.type == 13 && !AndroidUtilities.isTablet()) { + if (photoSize == null || messageObject.replyMessageObject.type == 13 || messageObject.type == 13 && !AndroidUtilities.isTablet() || messageObject.replyMessageObject.isSecretMedia()) { replyImageReceiver.setImageBitmap((Drawable) null); needReplyImage = false; } else { @@ -728,36 +747,41 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } String name = null; - if (messageObject.replyMessageObject.messageOwner.from_id > 0) { + if (messageObject.replyMessageObject.isFromUser()) { TLRPC.User user = MessagesController.getInstance().getUser(messageObject.replyMessageObject.messageOwner.from_id); if (user != null) { name = UserObject.getUserName(user); } - } else { + } else if (messageObject.replyMessageObject.messageOwner.from_id < 0) { TLRPC.Chat chat = MessagesController.getInstance().getChat(-messageObject.replyMessageObject.messageOwner.from_id); if (chat != null) { name = chat.title; } + } else { + TLRPC.Chat chat = MessagesController.getInstance().getChat(messageObject.replyMessageObject.messageOwner.to_id.channel_id); + if (chat != null) { + name = chat.title; + } } if (name != null) { - stringFinalName = TextUtils.ellipsize(name.replace("\n", " "), replyNamePaint, maxWidth - AndroidUtilities.dp(8), TextUtils.TruncateAt.END); + stringFinalName = TextUtils.ellipsize(name.replace('\n', ' '), replyNamePaint, maxWidth, TextUtils.TruncateAt.END); } if (messageObject.replyMessageObject.messageText != null && messageObject.replyMessageObject.messageText.length() > 0) { String mess = messageObject.replyMessageObject.messageText.toString(); if (mess.length() > 150) { mess = mess.substring(0, 150); } - mess = mess.replace("\n", " "); + mess = mess.replace('\n', ' '); stringFinalText = Emoji.replaceEmoji(mess, replyTextPaint.getFontMetricsInt(), AndroidUtilities.dp(14), false); - stringFinalText = TextUtils.ellipsize(stringFinalText, replyTextPaint, maxWidth - AndroidUtilities.dp(8), TextUtils.TruncateAt.END); + stringFinalText = TextUtils.ellipsize(stringFinalText, replyTextPaint, maxWidth, TextUtils.TruncateAt.END); } } if (stringFinalName == null) { stringFinalName = LocaleController.getString("Loading", R.string.Loading); } try { - replyNameLayout = new StaticLayout(stringFinalName, replyNamePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + replyNameLayout = new StaticLayout(stringFinalName, replyNamePaint, maxWidth + AndroidUtilities.dp(6), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (replyNameLayout.getLineCount() > 0) { replyNameWidth = (int)Math.ceil(replyNameLayout.getLineWidth(0)) + AndroidUtilities.dp(12 + (needReplyImage ? 44 : 0)); replyNameOffset = replyNameLayout.getLineLeft(0); @@ -767,7 +791,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } try { if (stringFinalText != null) { - replyTextLayout = new StaticLayout(stringFinalText, replyTextPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + replyTextLayout = new StaticLayout(stringFinalText, replyTextPaint, maxWidth + AndroidUtilities.dp(6), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); if (replyTextLayout.getLineCount() > 0) { replyTextWidth = (int) Math.ceil(replyTextLayout.getLineWidth(0)) + AndroidUtilities.dp(12 + (needReplyImage ? 44 : 0)); replyTextOffset = replyTextLayout.getLineLeft(0); @@ -786,7 +810,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } protected int getMaxNameWidth() { - return backgroundWidth - AndroidUtilities.dp(8); + return backgroundWidth - AndroidUtilities.dp(mediaBackground ? 22 : 31); } @Override @@ -799,19 +823,19 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo if (isAvatarVisible && avatarImage.isInsideImage(x, y)) { avatarPressed = true; result = true; - } else if (drawForwardedName && forwardedNameLayout != null && x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + AndroidUtilities.dp(32)) { + } else if (drawForwardedName && forwardedNameLayout[0] != null && x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + AndroidUtilities.dp(32)) { if (viaWidth != 0 && x >= forwardNameX + viaNameWidth + AndroidUtilities.dp(4)) { forwardBotPressed = true; } else { forwardNamePressed = true; } result = true; - } else if (drawName && nameLayout != null && viaWidth != 0 && x >= nameX + viaNameWidth && x <= nameX + viaNameWidth + viaWidth && y >= AndroidUtilities.dp(6) && y <= AndroidUtilities.dp(30)) { + } else if (drawNameLayout && nameLayout != null && viaWidth != 0 && x >= nameX + viaNameWidth && x <= nameX + viaNameWidth + viaWidth && y >= nameY - AndroidUtilities.dp(4) && y <= nameY + AndroidUtilities.dp(20)) { forwardBotPressed = true; - result = true; + result = true; } else if (currentMessageObject.isReply() && x >= replyStartX && x <= replyStartX + Math.max(replyNameWidth, replyTextWidth) && y >= replyStartY && y <= replyStartY + AndroidUtilities.dp(35)) { - replyPressed = true; - result = true; + replyPressed = true; + result = true; } else if (drawShareButton && x >= shareStartX && x <= shareStartX + AndroidUtilities.dp(40) && y >= shareStartY && y <= shareStartY + AndroidUtilities.dp(32)) { sharePressed = true; result = true; @@ -833,7 +857,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo if (currentUser != null) { delegate.didPressedUserAvatar(this, currentUser); } else if (currentChat != null) { - delegate.didPressedChannelAvatar(this, currentChat); + delegate.didPressedChannelAvatar(this, currentChat, 0); } } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { @@ -848,10 +872,10 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo forwardNamePressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { - if (currentForwardUser != null) { + if (currentForwardChannel != null) { + delegate.didPressedChannelAvatar(this, currentForwardChannel, currentMessageObject.messageOwner.fwd_from.channel_post); + } else if (currentForwardUser != null) { delegate.didPressedUserAvatar(this, currentForwardUser); - } else { - delegate.didPressedChannelAvatar(this, currentForwardChannel); } } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { @@ -866,17 +890,17 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo forwardBotPressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { - delegate.didPressedViaBot(this, currentViaBotUser); + delegate.didPressedViaBot(this, currentViaBotUser != null ? currentViaBotUser.username : currentMessageObject.messageOwner.via_bot_name); } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { forwardBotPressed = false; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (drawForwardedName && forwardedNameLayout != null) { + if (drawForwardedName && forwardedNameLayout[0] != null) { if (!(x >= forwardNameX && x <= forwardNameX + forwardedNameWidth && y >= forwardNameY && y <= forwardNameY + AndroidUtilities.dp(32))) { forwardBotPressed = false; } } else { - if (!(x >= nameX + viaNameWidth && x <= nameX + viaNameWidth + viaWidth && y >= AndroidUtilities.dp(6) && y <= AndroidUtilities.dp(30))) { + if (!(x >= nameX + viaNameWidth && x <= nameX + viaNameWidth + viaWidth && y >= nameY - AndroidUtilities.dp(4) && y <= nameY + AndroidUtilities.dp(20))) { forwardBotPressed = false; } } @@ -886,7 +910,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo replyPressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { - delegate.didPressReplyMessage(this, currentMessageObject.messageOwner.reply_to_msg_id); + delegate.didPressedReplyMessage(this, currentMessageObject.messageOwner.reply_to_msg_id); } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { replyPressed = false; @@ -900,7 +924,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo sharePressed = false; playSoundEffect(SoundEffectConstants.CLICK); if (delegate != null) { - delegate.didPressShare(this); + delegate.didPressedShare(this); } } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { sharePressed = false; @@ -925,25 +949,35 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo if (changed || !wasLayout) { layoutWidth = getMeasuredWidth(); - layoutHeight = getMeasuredHeight(); - - timeLayout = new StaticLayout(currentTimeString, timePaint, timeTextWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - if (!media) { + layoutHeight = getMeasuredHeight() - substractBackgroundHeight; + if (timeTextWidth < 0) { + timeTextWidth = AndroidUtilities.dp(10); + } + timeLayout = new StaticLayout(currentTimeString, timePaint, timeTextWidth + AndroidUtilities.dp(6), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + if (!mediaBackground) { if (!currentMessageObject.isOutOwner()) { - //timeX = backgroundWidth - AndroidUtilities.dp(9) - timeWidth + (isChat && currentMessageObject.messageOwner.from_id > 0 ? AndroidUtilities.dp(52) : 0); - timeX = backgroundWidth - AndroidUtilities.dp(9) - timeWidth + ( (isChat || showAvatar) && currentMessageObject.messageOwner.from_id > 0 ? AndroidUtilities.dp(leftBound) : 0); + //timeX = backgroundWidth - AndroidUtilities.dp(9) - timeWidth + (isChat && currentMessageObject.isFromUser() ? AndroidUtilities.dp(48) : 0); + timeX = backgroundWidth - AndroidUtilities.dp(9) - timeWidth + ( (isChat || showAvatar) && currentMessageObject.isFromUser() ? AndroidUtilities.dp(leftBound) : 0); + //Log.e("ChatBaseCell", "NO MEDIA 0 - timeX " + timeX); } else { timeX = layoutWidth - timeWidth - AndroidUtilities.dp(38.5f); - if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat))timeX = layoutWidth - timeWidth - AndroidUtilities.dp(38.5f) - AndroidUtilities.dp(leftBound); + if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)){ + timeX = layoutWidth - timeWidth - AndroidUtilities.dp(38.5f) - AndroidUtilities.dp(leftBound); + } + //Log.e("ChatBaseCell", "NO MEDIA 1 - timeX " + timeX); checkX = timeX + timeWidth; } } else { if (!currentMessageObject.isOutOwner()) { - //timeX = backgroundWidth - AndroidUtilities.dp(4) - timeWidth + (isChat && currentMessageObject.messageOwner.from_id > 0 ? AndroidUtilities.dp(52) : 0); - timeX = backgroundWidth - AndroidUtilities.dp(4) - timeWidth + ((isChat || showAvatar) && currentMessageObject.messageOwner.from_id > 0 ? AndroidUtilities.dp(leftBound) : 0); + //timeX = backgroundWidth - AndroidUtilities.dp(4) - timeWidth + (isChat && currentMessageObject.isFromUser() ? AndroidUtilities.dp(48) : 0); + timeX = backgroundWidth - AndroidUtilities.dp(4) - timeWidth + ((isChat || showAvatar) && currentMessageObject.isFromUser() ? AndroidUtilities.dp(leftBound) : 0); + //Log.e("ChatBaseCell", "MEDIA 2 - timeX " + timeX); } else { timeX = layoutWidth - timeWidth - AndroidUtilities.dp(42.0f); - if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat))timeX = layoutWidth - timeWidth - AndroidUtilities.dp(42.0f) - AndroidUtilities.dp(leftBound); + if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)){ + timeX = layoutWidth - timeWidth - AndroidUtilities.dp(42.0f) - AndroidUtilities.dp(leftBound); + } + //Log.e("ChatBaseCell", "MEDIA 3 - timeX " + timeX); checkX = timeX + timeWidth; } } @@ -955,7 +989,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } if (isAvatarVisible) { - //avatarImage.setImageCoords(AndroidUtilities.dp(6), layoutHeight - AndroidUtilities.dp(45), AndroidUtilities.dp(42), AndroidUtilities.dp(42)); + //avatarImage.setImageCoords(AndroidUtilities.dp(6), layoutHeight - AndroidUtilities.dp(44), AndroidUtilities.dp(42), AndroidUtilities.dp(42)); if(((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) && currentMessageObject.isOutOwner()){ avatarImage.setImageCoords(layoutWidth - avatarSize - avatarLeft, ownAvatarAlignTop ? AndroidUtilities.dp(3) : layoutHeight - AndroidUtilities.dp(3) - avatarSize, avatarSize, avatarSize); drawStatus = false; @@ -968,7 +1002,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } } - protected void onAfterBackgroundDraw(Canvas canvas) { + protected void drawContent(Canvas canvas) { } @@ -1005,142 +1039,152 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo statusBG.draw(canvas); } } - - //if (media) { - // timePaint.setColor(0xffffffff); + int tColor; + //if (mediaBackground) { + // timePaint.setColor(Theme.MSG_MEDIA_TIME_TEXT_COLOR); //} else { if (currentMessageObject.isOutOwner()) { - //timePaint.setColor(0xff70b15c); - timePaint.setColor(themePrefs.getInt("chatRTimeColor", AndroidUtilities.setDarkColor(themePrefs.getInt("themeColor", AndroidUtilities.defColor), 0x15))); + //timePaint.setColor(isDrawSelectedBackground() ? Theme.MSG_OUT_TIME_SELECTED_TEXT_COLOR : Theme.MSG_OUT_TIME_TEXT_COLOR); + tColor = themePrefs.getInt("chatRTimeColor", AndroidUtilities.setDarkColor(themePrefs.getInt("themeColor", AndroidUtilities.defColor), 0x15)); } else { - //timePaint.setColor(isDrawSelectedBackground() ? 0xff89b4c1 : 0xffa1aab3); - timePaint.setColor(isDrawSelectedBackground() ? 0xff89b4c1 : themePrefs.getInt("chatLTimeColor", 0xffa1aab3)); + //timePaint.setColor(isDrawSelectedBackground() ? Theme.MSG_IN_TIME_SELECTED_TEXT_COLOR : Theme.MSG_IN_TIME_TEXT_COLOR); + tColor = isDrawSelectedBackground() ? Theme.MSG_IN_TIME_SELECTED_TEXT_COLOR : themePrefs.getInt("chatLTimeColor", Theme.MSG_IN_TIME_TEXT_COLOR); } //} - + timePaint.setColor(tColor); updateTheme(); - Drawable currentBackgroundDrawable; if (currentMessageObject.isOutOwner()) { if (isDrawSelectedBackground()) { - if (!media) { - currentBackgroundDrawable = ResourceLoader.backgroundDrawableOutSelected; + if (!mediaBackground) { + currentBackgroundDrawable = Theme.backgroundDrawableOutSelected; } else { - currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableOutSelected; + currentBackgroundDrawable = Theme.backgroundMediaDrawableOutSelected; } } else { - if (!media) { - currentBackgroundDrawable = ResourceLoader.backgroundDrawableOut; + if (!mediaBackground) { + currentBackgroundDrawable = Theme.backgroundDrawableOut; } else { - currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableOut; + currentBackgroundDrawable = Theme.backgroundMediaDrawableOut; } } - + //setDrawableBounds(currentBackgroundDrawable, layoutWidth - backgroundWidth - (!mediaBackground ? 0 : AndroidUtilities.dp(9)), AndroidUtilities.dp(1), backgroundWidth - (mediaBackground ? 0 : AndroidUtilities.dp(3)), layoutHeight - AndroidUtilities.dp(2)); if ((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) { - setDrawableBounds(currentBackgroundDrawable, layoutWidth - backgroundWidth - (!media ? 0 : AndroidUtilities.dp(9)) - AndroidUtilities.dp(leftBound), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2)); + setDrawableBounds(currentBackgroundDrawable, layoutWidth - backgroundWidth - (!mediaBackground ? 0 : AndroidUtilities.dp(9)) - AndroidUtilities.dp(leftBound), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2)); }else{ - setDrawableBounds(currentBackgroundDrawable, layoutWidth - backgroundWidth - (!media ? 0 : AndroidUtilities.dp(9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2)); + setDrawableBounds(currentBackgroundDrawable, layoutWidth - backgroundWidth - (!mediaBackground ? 0 : AndroidUtilities.dp(9)), AndroidUtilities.dp(1), backgroundWidth - (mediaBackground ? 0 : AndroidUtilities.dp(3)), layoutHeight - AndroidUtilities.dp(2)); } - } else { if (isDrawSelectedBackground()) { - if (!media) { - currentBackgroundDrawable = ResourceLoader.backgroundDrawableInSelected; + if (!mediaBackground) { + currentBackgroundDrawable = Theme.backgroundDrawableInSelected; } else { - currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableInSelected; + currentBackgroundDrawable = Theme.backgroundMediaDrawableInSelected; } } else { - if (!media) { - currentBackgroundDrawable = ResourceLoader.backgroundDrawableIn; + if (!mediaBackground) { + currentBackgroundDrawable = Theme.backgroundDrawableIn; } else { - currentBackgroundDrawable = ResourceLoader.backgroundMediaDrawableIn; + currentBackgroundDrawable = Theme.backgroundMediaDrawableIn; } } - if ((isChat || showAvatar) && currentMessageObject.messageOwner.from_id > 0) { - //Log.e("chatBaseCell","1 backgroundWidth: " + backgroundWidth); - setDrawableBounds(currentBackgroundDrawable, AndroidUtilities.dp(leftBound + (!media ? 0 : 9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2)); + //if (isChat && currentMessageObject.isFromUser()) { + // setDrawableBounds(currentBackgroundDrawable, AndroidUtilities.dp(48 + (!mediaBackground ? 3 : 9)), AndroidUtilities.dp(1), backgroundWidth - (mediaBackground ? 0 : AndroidUtilities.dp(3)), layoutHeight - AndroidUtilities.dp(2)); + //} else { + // setDrawableBounds(currentBackgroundDrawable, (!mediaBackground ? AndroidUtilities.dp(3) : AndroidUtilities.dp(9)), AndroidUtilities.dp(1), backgroundWidth - (mediaBackground ? 0 : AndroidUtilities.dp(3)), layoutHeight - AndroidUtilities.dp(2)); + //} + if ((isChat || showAvatar) && currentMessageObject.isFromUser()) { + setDrawableBounds(currentBackgroundDrawable, AndroidUtilities.dp(leftBound + (!mediaBackground ? 3 : 9)), AndroidUtilities.dp(1), backgroundWidth - (mediaBackground ? 0 : AndroidUtilities.dp(3)), layoutHeight - AndroidUtilities.dp(2)); } else { - //Log.e("chatBaseCell","2 backgroundWidth: " + backgroundWidth); - setDrawableBounds(currentBackgroundDrawable, (!media ? 0 : AndroidUtilities.dp(9)), AndroidUtilities.dp(1), backgroundWidth, layoutHeight - AndroidUtilities.dp(2)); + setDrawableBounds(currentBackgroundDrawable, (!mediaBackground ? AndroidUtilities.dp(3) : AndroidUtilities.dp(9)), AndroidUtilities.dp(1), backgroundWidth - (mediaBackground ? 0 : AndroidUtilities.dp(3)), layoutHeight - AndroidUtilities.dp(2)); } } if (drawBackground && currentBackgroundDrawable != null) { currentBackgroundDrawable.draw(canvas); } - onAfterBackgroundDraw(canvas); + drawContent(canvas); if (drawShareButton) { - //ResourceLoader.shareDrawable[ApplicationLoader.isCustomTheme() ? 1 : 0][sharePressed ? 1 : 0].setBounds(shareStartX = currentBackgroundDrawable.getBounds().right + AndroidUtilities.dp(8), shareStartY = layoutHeight - AndroidUtilities.dp(41), currentBackgroundDrawable.getBounds().right + AndroidUtilities.dp(40), layoutHeight - AndroidUtilities.dp(9)); - //boolean b = currentMessageObject.messageOwner.from_id < 0 && (currentMessageObject.messageOwner.to_id.channel_id != 0 && (currentMessageObject.messageOwner.reply_to_msg_id == 0 || currentMessageObject.type != 13)); - ResourceLoader.shareDrawable[ApplicationLoader.isCustomTheme() ? 1 : 0][sharePressed ? 1 : 0].setBounds(shareStartX = currentBackgroundDrawable.getBounds().right + AndroidUtilities.dp(1), shareStartY = layoutHeight - AndroidUtilities.dp(35), currentBackgroundDrawable.getBounds().right + AndroidUtilities.dp(33), layoutHeight - AndroidUtilities.dp(3)); - ResourceLoader.shareDrawable[ApplicationLoader.isCustomTheme() ? 1 : 0][sharePressed ? 1 : 0].draw(canvas); + Theme.shareDrawable.setColorFilter(sharePressed ? Theme.colorPressedFilter : Theme.colorFilter); + //setDrawableBounds(Theme.shareDrawable, shareStartX = currentBackgroundDrawable.getBounds().right + AndroidUtilities.dp(8), shareStartY = layoutHeight - AndroidUtilities.dp(41)); + setDrawableBounds(Theme.shareDrawable, shareStartX = currentBackgroundDrawable.getBounds().right + AndroidUtilities.dp(1), shareStartY = layoutHeight - AndroidUtilities.dp(35)); + Theme.shareDrawable.draw(canvas); + setDrawableBounds(Theme.shareIconDrawable, shareStartX + AndroidUtilities.dp(9), shareStartY + AndroidUtilities.dp(9)); + Theme.shareIconDrawable.draw(canvas); } - - boolean mCheck = AndroidUtilities.getBoolPref("chatMemberColorCheck"); int mColor = themePrefs.getInt("chatMemberColor", AndroidUtilities.getIntDarkerColor("themeColor", 0x15)); - if (drawName && nameLayout != null) { + if (drawNameLayout && nameLayout != null) { canvas.save(); - if (media || currentMessageObject.isOutOwner()) { - canvas.translate(nameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(10) - nameOffsetX, AndroidUtilities.dp(10)); + + if (currentMessageObject.type == 13) { + namePaint.setColor(Theme.MSG_STICKER_NAME_TEXT_COLOR); + int backWidth; + if (currentMessageObject.isOutOwner()) { + nameX = AndroidUtilities.dp(28); + } else { + nameX = currentBackgroundDrawable.getBounds().right + AndroidUtilities.dp(22); + } + nameY = layoutHeight - AndroidUtilities.dp(38); + Theme.systemDrawable.setColorFilter(Theme.colorFilter); + Theme.systemDrawable.setBounds((int) nameX - AndroidUtilities.dp(12), (int) nameY - AndroidUtilities.dp(5), (int) nameX + AndroidUtilities.dp(12) + nameWidth, (int) nameY + AndroidUtilities.dp(22)); + Theme.systemDrawable.draw(canvas); } else { - canvas.translate(nameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(19) - nameOffsetX, AndroidUtilities.dp(10)); - } - if (currentUser != null) { - if(mCheck){ - namePaint.setColor(mColor); - }else { - namePaint.setColor(AvatarDrawable.getNameColorForId(currentUser.id)); - } - } else if (currentChat != null) { - if(mCheck){ - namePaint.setColor(mColor); - }else { - namePaint.setColor(AvatarDrawable.getNameColorForId(currentChat.id)); - } - } else { - if(mCheck){ - namePaint.setColor(mColor); - }else { - namePaint.setColor(AvatarDrawable.getNameColorForId(0)); - } + if (mediaBackground || currentMessageObject.isOutOwner()) { + nameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(11) - nameOffsetX; + } else { + nameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(17) - nameOffsetX; + } + if (currentUser != null) { + if(mCheck){ + namePaint.setColor(mColor); + }else { + namePaint.setColor(AvatarDrawable.getNameColorForId(currentUser.id)); + } + } else if (currentChat != null) { + if(mCheck){ + namePaint.setColor(mColor); + }else { + namePaint.setColor(AvatarDrawable.getNameColorForId(currentChat.id)); + } + } else { + if(mCheck){ + namePaint.setColor(mColor); + }else { + namePaint.setColor(AvatarDrawable.getNameColorForId(0)); + } + } + nameY = AndroidUtilities.dp(10); } + canvas.translate(nameX, nameY); nameLayout.draw(canvas); canvas.restore(); - - /*if (forwardedNameLayout == null && viaWidth != 0) { - canvas.drawRect(nameX + viaNameWidth, AndroidUtilities.dp(6), nameX + viaNameWidth + viaWidth, AndroidUtilities.dp(30), namePaint); - }*/ } - if (drawForwardedName && forwardedNameLayout != null) { - forwardNameY = AndroidUtilities.dp(10 + (drawName ? 19 : 0)); + if (drawForwardedName && forwardedNameLayout[0] != null && forwardedNameLayout[1] != null) { + forwardNameY = AndroidUtilities.dp(10 + (drawNameLayout ? 19 : 0)); int defColor = themePrefs.getInt("themeColor",AndroidUtilities.defColor); if (currentMessageObject.isOutOwner()) { - //forwardNamePaint.setColor(0xff4a923c); + //forwardNamePaint.setColor(Theme.MSG_OUT_FORDWARDED_NAME_TEXT_COLOR); forwardNamePaint.setColor(themePrefs.getInt("chatForwardRColor", AndroidUtilities.setDarkColor(defColor, 0x15))); - forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(10); - if(showMyAvatarGroup && isChat)forwardNameY = AndroidUtilities.dp(10); - //if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat))forwardNameY = AndroidUtilities.dp((drawName ? 10 : 0)); - if(!isChat && showMyAvatar)forwardNameY = AndroidUtilities.dp(10); + forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(11); + if(!isChat && showMyAvatar || showMyAvatarGroup && isChat)forwardNameY = AndroidUtilities.dp(11); } else { - //forwardNamePaint.setColor(0xff006fc8); + //forwardNamePaint.setColor(Theme.MSG_IN_FORDWARDED_NAME_TEXT_COLOR); forwardNamePaint.setColor(themePrefs.getInt("chatForwardLColor", defColor)); - if (media) { - forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(10); + if (mediaBackground) { + forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(11); } else { - forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(19); + forwardNameX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(17); } - if(!isChat && showAvatar)forwardNameY = AndroidUtilities.dp(10); + if(!isChat && showAvatar)forwardNameY = AndroidUtilities.dp(11); + } + for (int a = 0; a < 2; a++) { + canvas.save(); + canvas.translate(forwardNameX - forwardNameOffsetX[a], forwardNameY + AndroidUtilities.dp(16) * a); + forwardedNameLayout[a].draw(canvas); + canvas.restore(); } - canvas.save(); - canvas.translate(forwardNameX - forwardNameOffsetX, forwardNameY); - forwardedNameLayout.draw(canvas); - canvas.restore(); - - /*if (viaWidth != 0) { - canvas.drawRect(forwardNameX + viaNameWidth, forwardNameY, forwardNameX + viaNameWidth + viaWidth, forwardNameY + AndroidUtilities.dp(32), namePaint); - }*/ } if (currentMessageObject.isReply()) { @@ -1149,62 +1193,62 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo int lColor = themePrefs.getInt("chatForwardLColor", defColor); int outColor = themePrefs.getInt("chatRTextColor", 0xff000000); int inColor = themePrefs.getInt("chatLTextColor", 0xff000000); - //int bColor = themePrefs.getInt("chatRBubbleColor", AndroidUtilities.getDefBubbleColor()); - if (currentMessageObject.type == 13) { - replyLinePaint.setColor(0xffffffff); - replyNamePaint.setColor(0xffffffff); - replyTextPaint.setColor(0xffffffff); - int backWidth; + replyLinePaint.setColor(Theme.MSG_STICKER_REPLY_LINE_COLOR); + replyNamePaint.setColor(Theme.MSG_STICKER_REPLY_NAME_TEXT_COLOR); + replyTextPaint.setColor(Theme.MSG_STICKER_REPLY_MESSAGE_TEXT_COLOR); if (currentMessageObject.isOutOwner()) { - //bColor = themePrefs.getInt("chatLBubbleColor", 0xffffffff);// replyLinePaint.setColor(rColor); replyNamePaint.setColor(rColor); replyTextPaint.setColor(outColor); - backWidth = currentBackgroundDrawable.getBounds().left - AndroidUtilities.dp(32); - replyStartX = currentBackgroundDrawable.getBounds().left - AndroidUtilities.dp(9) - backWidth; + replyStartX = AndroidUtilities.dp(23); } else { replyLinePaint.setColor(lColor); replyNamePaint.setColor(lColor); replyTextPaint.setColor(inColor); - backWidth = getWidth() - currentBackgroundDrawable.getBounds().right - AndroidUtilities.dp(32); - replyStartX = currentBackgroundDrawable.getBounds().right + AndroidUtilities.dp(23); + replyStartX = currentBackgroundDrawable.getBounds().right + AndroidUtilities.dp(17); } - //Drawable back; - Drawable back = ResourceLoader.mediaBackgroundDrawable; - //if (ApplicationLoader.isCustomTheme()) { - // back = ResourceLoader.backgroundBlack; - //} else { - // back = ResourceLoader.backgroundBlue; - //} replyStartY = layoutHeight - AndroidUtilities.dp(58); - back.setBounds(replyStartX - AndroidUtilities.dp(7), replyStartY - AndroidUtilities.dp(6), replyStartX - AndroidUtilities.dp(7) + backWidth, replyStartY + AndroidUtilities.dp(41)); - back.draw(canvas); + if (nameLayout != null) { + replyStartY -= AndroidUtilities.dp(25 + 6); + } + int backWidth = Math.max(replyNameWidth, replyTextWidth) + AndroidUtilities.dp(14 + (needReplyImage ? 44 : 0)); + Theme.systemDrawable.setColorFilter(Theme.colorFilter); + Theme.systemDrawable.setBounds(replyStartX - AndroidUtilities.dp(7), replyStartY - AndroidUtilities.dp(6), replyStartX - AndroidUtilities.dp(7) + backWidth, replyStartY + AndroidUtilities.dp(41)); + Theme.systemDrawable.draw(canvas); } else { if (currentMessageObject.isOutOwner()) { - replyLinePaint.setColor(rColor);//0xff8dc97a); - replyNamePaint.setColor(rColor);//0xff61a349); + //replyLinePaint.setColor(Theme.MSG_OUT_REPLY_LINE_COLOR); + //replyNamePaint.setColor(Theme.MSG_OUT_REPLY_NAME_TEXT_COLOR); + replyLinePaint.setColor(rColor); + replyNamePaint.setColor(rColor); if (currentMessageObject.replyMessageObject != null && currentMessageObject.replyMessageObject.type == 0) { + //replyTextPaint.setColor(Theme.MSG_OUT_REPLY_MESSAGE_TEXT_COLOR); replyTextPaint.setColor(outColor);//0xff000000); } else { + //replyTextPaint.setColor(isDrawSelectedBackground() ? Theme.MSG_OUT_REPLY_MEDIA_MESSAGE_SELETED_TEXT_COLOR : Theme.MSG_OUT_REPLY_MEDIA_MESSAGE_TEXT_COLOR); replyTextPaint.setColor(rColor);//0xff70b15c); } - replyStartX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(11); + replyStartX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(12); } else { + //replyLinePaint.setColor(Theme.MSG_IN_REPLY_LINE_COLOR); + //replyNamePaint.setColor(Theme.MSG_IN_REPLY_NAME_TEXT_COLOR); replyLinePaint.setColor(lColor);//0xff6c9fd2); replyNamePaint.setColor(lColor);//0xff377aae); if (currentMessageObject.replyMessageObject != null && currentMessageObject.replyMessageObject.type == 0) { - replyTextPaint.setColor(inColor);//0xff000000); + //replyTextPaint.setColor(Theme.MSG_IN_REPLY_MESSAGE_TEXT_COLOR); + replyTextPaint.setColor(inColor); } else { - replyTextPaint.setColor(lColor);//0xff999999); + //replyTextPaint.setColor(isDrawSelectedBackground() ? Theme.MSG_IN_REPLY_MEDIA_MESSAGE_SELETED_TEXT_COLOR : Theme.MSG_IN_REPLY_MEDIA_MESSAGE_TEXT_COLOR); + replyTextPaint.setColor(lColor); } - if (currentMessageObject.contentType == 1 && media) { - replyStartX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(11); + if (mediaBackground) { + replyStartX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(12); } else { - replyStartX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(20); + replyStartX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(18); } } - replyStartY = AndroidUtilities.dp(12 + (drawForwardedName && forwardedNameLayout != null ? 36 : 0) + (drawName && nameLayout != null ? 20 : 0)); + replyStartY = AndroidUtilities.dp(12 + (drawForwardedName && forwardedNameLayout[0] != null ? 36 : 0) + (drawNameLayout && nameLayout != null ? 20 : 0)); } canvas.drawRect(replyStartX, replyStartY, replyStartX + AndroidUtilities.dp(2), replyStartY + AndroidUtilities.dp(35), replyLinePaint); if (needReplyImage) { @@ -1225,10 +1269,16 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } } - if (drawTime || !media) { - if (media) { - setDrawableBounds(ResourceLoader.mediaBackgroundDrawable, timeX - AndroidUtilities.dp(3), layoutHeight - AndroidUtilities.dp(27.5f), timeWidth + AndroidUtilities.dp(6 + (currentMessageObject.isOutOwner() ? 20 : 0)), AndroidUtilities.dp(16.5f)); - ResourceLoader.mediaBackgroundDrawable.draw(canvas); + if (drawTime || !mediaBackground) { + if (mediaBackground) { + Drawable drawable; + if (currentMessageObject.type == 13) { + drawable = Theme.timeStickerBackgroundDrawable; + } else { + drawable = Theme.timeBackgroundDrawable; + } + setDrawableBounds(drawable, timeX - AndroidUtilities.dp(4), layoutHeight - AndroidUtilities.dp(27), timeWidth + AndroidUtilities.dp(8 + (currentMessageObject.isOutOwner() ? 20 : 0)), AndroidUtilities.dp(17)); + drawable.draw(canvas); int additionalX = 0; if ((currentMessageObject.messageOwner.flags & TLRPC.MESSAGE_FLAG_HAS_VIEWS) != 0) { @@ -1236,22 +1286,22 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo if (currentMessageObject.isSending()) { if (!currentMessageObject.isOutOwner()) { - setDrawableBounds(ResourceLoader.clockMediaDrawable, timeX + AndroidUtilities.dp(11), layoutHeight - AndroidUtilities.dp(13.0f) - ResourceLoader.clockMediaDrawable.getIntrinsicHeight()); - ResourceLoader.clockMediaDrawable.draw(canvas); + setDrawableBounds(Theme.clockMediaDrawable, timeX + AndroidUtilities.dp(11), layoutHeight - AndroidUtilities.dp(13.0f) - Theme.clockMediaDrawable.getIntrinsicHeight()); + Theme.clockMediaDrawable.draw(canvas); } } else if (currentMessageObject.isSendError()) { if (!currentMessageObject.isOutOwner()) { - setDrawableBounds(ResourceLoader.errorDrawable, timeX + AndroidUtilities.dp(11), layoutHeight - AndroidUtilities.dp(12.5f) - ResourceLoader.errorDrawable.getIntrinsicHeight()); - ResourceLoader.errorDrawable.draw(canvas); + setDrawableBounds(Theme.errorDrawable, timeX + AndroidUtilities.dp(11), layoutHeight - AndroidUtilities.dp(12.5f) - Theme.errorDrawable.getIntrinsicHeight()); + Theme.errorDrawable.draw(canvas); } } else { - Drawable countDrawable = ResourceLoader.viewsMediaCountDrawable[isDrawSelectedBackground() ? 1 : 0]; - setDrawableBounds(countDrawable, timeX, layoutHeight - AndroidUtilities.dp(10) - timeLayout.getHeight()); + Drawable countDrawable = Theme.viewsMediaCountDrawable; + setDrawableBounds(countDrawable, timeX, layoutHeight - AndroidUtilities.dp(9.5f) - timeLayout.getHeight()); countDrawable.draw(canvas); if (viewsLayout != null) { canvas.save(); - canvas.translate(timeX + countDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3), layoutHeight - AndroidUtilities.dp(12.0f) - timeLayout.getHeight()); + canvas.translate(timeX + countDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3), layoutHeight - AndroidUtilities.dp(11.3f) - timeLayout.getHeight()); viewsLayout.draw(canvas); canvas.restore(); } @@ -1259,7 +1309,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } canvas.save(); - canvas.translate(timeX + additionalX, layoutHeight - AndroidUtilities.dp(12.0f) - timeLayout.getHeight()); + canvas.translate(timeX + additionalX, layoutHeight - AndroidUtilities.dp(11.3f) - timeLayout.getHeight()); timeLayout.draw(canvas); canvas.restore(); } else { @@ -1269,27 +1319,27 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo if (currentMessageObject.isSending()) { if (!currentMessageObject.isOutOwner()) { - Drawable clockDrawable = ResourceLoader.clockChannelDrawable[isDrawSelectedBackground() ? 1 : 0]; + Drawable clockDrawable = Theme.clockChannelDrawable[isDrawSelectedBackground() ? 1 : 0]; setDrawableBounds(clockDrawable, timeX + AndroidUtilities.dp(11), layoutHeight - AndroidUtilities.dp(8.5f) - clockDrawable.getIntrinsicHeight()); clockDrawable.draw(canvas); } } else if (currentMessageObject.isSendError()) { if (!currentMessageObject.isOutOwner()) { - setDrawableBounds(ResourceLoader.errorDrawable, timeX + AndroidUtilities.dp(11), layoutHeight - AndroidUtilities.dp(6.5f) - ResourceLoader.errorDrawable.getIntrinsicHeight()); - ResourceLoader.errorDrawable.draw(canvas); + setDrawableBounds(Theme.errorDrawable, timeX + AndroidUtilities.dp(11), layoutHeight - AndroidUtilities.dp(6.5f) - Theme.errorDrawable.getIntrinsicHeight()); + Theme.errorDrawable.draw(canvas); } } else { if (!currentMessageObject.isOutOwner()) { - setDrawableBounds(ResourceLoader.viewsCountDrawable, timeX, layoutHeight - AndroidUtilities.dp(4.5f) - timeLayout.getHeight()); - ResourceLoader.viewsCountDrawable.draw(canvas); + setDrawableBounds(Theme.viewsCountDrawable[isDrawSelectedBackground() ? 1 : 0], timeX, layoutHeight - AndroidUtilities.dp(4.5f) - timeLayout.getHeight()); + Theme.viewsCountDrawable[isDrawSelectedBackground() ? 1 : 0].draw(canvas); } else { - setDrawableBounds(ResourceLoader.viewsOutCountDrawable, timeX, layoutHeight - AndroidUtilities.dp(4.5f) - timeLayout.getHeight()); - ResourceLoader.viewsOutCountDrawable.draw(canvas); + setDrawableBounds(Theme.viewsOutCountDrawable, timeX, layoutHeight - AndroidUtilities.dp(4.5f) - timeLayout.getHeight()); + Theme.viewsOutCountDrawable.draw(canvas); } if (viewsLayout != null) { canvas.save(); - canvas.translate(timeX + ResourceLoader.viewsOutCountDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3), layoutHeight - AndroidUtilities.dp(6.5f) - timeLayout.getHeight()); + canvas.translate(timeX + Theme.viewsOutCountDrawable.getIntrinsicWidth() + AndroidUtilities.dp(3), layoutHeight - AndroidUtilities.dp(6.5f) - timeLayout.getHeight()); viewsLayout.draw(canvas); canvas.restore(); } @@ -1300,6 +1350,7 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo canvas.translate(timeX + additionalX, layoutHeight - AndroidUtilities.dp(6.5f) - timeLayout.getHeight()); timeLayout.draw(canvas); canvas.restore(); + //canvas.drawRect(timeX, layoutHeight - AndroidUtilities.dp(6.5f) - timeLayout.getHeight(), timeX + availableTimeWidth, layoutHeight - AndroidUtilities.dp(4.5f) - timeLayout.getHeight(), timePaint); } if (currentMessageObject.isOutOwner()) { @@ -1332,107 +1383,119 @@ public class ChatBaseCell extends BaseCell implements MediaController.FileDownlo } if (drawClock) { - if (!media) { + if (!mediaBackground) { + //setDrawableBounds(Theme.clockDrawable, layoutWidth - AndroidUtilities.dp(18.5f) - Theme.clockDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.5f) - Theme.clockDrawable.getIntrinsicHeight()); if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)){ - setDrawableBounds(ResourceLoader.clockDrawable, checkX - AndroidUtilities.dp(3.5f) + ResourceLoader.clockDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.5f) - ResourceLoader.clockDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.clockDrawable, checkX - AndroidUtilities.dp(3.5f) + Theme.clockDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.5f) - Theme.clockDrawable.getIntrinsicHeight()); }else{ - setDrawableBounds(ResourceLoader.clockDrawable, layoutWidth - AndroidUtilities.dp(18.5f) - ResourceLoader.clockDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.5f) - ResourceLoader.clockDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.clockDrawable, layoutWidth - AndroidUtilities.dp(18.5f) - Theme.clockDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.5f) - Theme.clockDrawable.getIntrinsicHeight()); } - ResourceLoader.clockDrawable.draw(canvas); + Theme.clockDrawable.draw(canvas); } else { + //setDrawableBounds(Theme.clockMediaDrawable, layoutWidth - AndroidUtilities.dp(22.0f) - Theme.clockMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(12.5f) - Theme.clockMediaDrawable.getIntrinsicHeight()); if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)){ - setDrawableBounds(ResourceLoader.clockMediaDrawable, checkX - AndroidUtilities.dp(7.0f) + ResourceLoader.clockMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.0f) - ResourceLoader.clockMediaDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.clockMediaDrawable, checkX - AndroidUtilities.dp(7.0f) + Theme.clockMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(12.5f) - Theme.clockMediaDrawable.getIntrinsicHeight()); }else{ - setDrawableBounds(ResourceLoader.clockMediaDrawable, layoutWidth - AndroidUtilities.dp(22.0f) - ResourceLoader.clockMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.0f) - ResourceLoader.clockMediaDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.clockMediaDrawable, layoutWidth - AndroidUtilities.dp(22.0f) - Theme.clockMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(12.5f) - Theme.clockMediaDrawable.getIntrinsicHeight()); } - ResourceLoader.clockMediaDrawable.draw(canvas); + Theme.clockMediaDrawable.draw(canvas); } } if (isBroadcast) { if (drawCheck1 || drawCheck2) { - if (!media) { + if (!mediaBackground) { + //setDrawableBounds(Theme.broadcastDrawable, layoutWidth - AndroidUtilities.dp(20.5f) - Theme.broadcastDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - Theme.broadcastDrawable.getIntrinsicHeight()); if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)){ - setDrawableBounds(ResourceLoader.broadcastDrawable, checkX - AndroidUtilities.dp(5.5f) + ResourceLoader.broadcastDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.broadcastDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.broadcastDrawable, checkX - AndroidUtilities.dp(5.5f) + Theme.broadcastDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - Theme.broadcastDrawable.getIntrinsicHeight()); }else{ - setDrawableBounds(ResourceLoader.broadcastDrawable, layoutWidth - AndroidUtilities.dp(20.5f) - ResourceLoader.broadcastDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.broadcastDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.broadcastDrawable, layoutWidth - AndroidUtilities.dp(20.5f) - Theme.broadcastDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - Theme.broadcastDrawable.getIntrinsicHeight()); } - ResourceLoader.broadcastDrawable.draw(canvas); + Theme.broadcastDrawable.draw(canvas); } else { + //setDrawableBounds(Theme.broadcastMediaDrawable, layoutWidth - AndroidUtilities.dp(24.0f) - Theme.broadcastMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.0f) - Theme.broadcastMediaDrawable.getIntrinsicHeight()); if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)){ - setDrawableBounds(ResourceLoader.broadcastMediaDrawable, checkX - AndroidUtilities.dp(9.0f) + ResourceLoader.broadcastMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.0f) - ResourceLoader.broadcastMediaDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.broadcastMediaDrawable, checkX - AndroidUtilities.dp(9.0f) + Theme.broadcastMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.0f) - Theme.broadcastMediaDrawable.getIntrinsicHeight()); }else{ - setDrawableBounds(ResourceLoader.broadcastMediaDrawable, layoutWidth - AndroidUtilities.dp(24.0f) - ResourceLoader.broadcastMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.0f) - ResourceLoader.broadcastMediaDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.broadcastMediaDrawable, layoutWidth - AndroidUtilities.dp(24.0f) - Theme.broadcastMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.0f) - Theme.broadcastMediaDrawable.getIntrinsicHeight()); } - ResourceLoader.broadcastMediaDrawable.draw(canvas); + Theme.broadcastMediaDrawable.draw(canvas); } } } else { if (drawCheck2) { - if (!media) { + if (!mediaBackground) { if (drawCheck1) { + //setDrawableBounds(Theme.checkDrawable, layoutWidth - AndroidUtilities.dp(22.5f) - Theme.checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - Theme.checkDrawable.getIntrinsicHeight()); if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)){ - setDrawableBounds(ResourceLoader.checkDrawable, checkX - AndroidUtilities.dp(7.5f) + ResourceLoader.checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.checkDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.checkDrawable, checkX - AndroidUtilities.dp(7.5f) + Theme.checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - Theme.checkDrawable.getIntrinsicHeight()); }else{ - setDrawableBounds(ResourceLoader.checkDrawable, layoutWidth - AndroidUtilities.dp(22.5f) - ResourceLoader.checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.checkDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.checkDrawable, layoutWidth - AndroidUtilities.dp(22.5f) - Theme.checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - Theme.checkDrawable.getIntrinsicHeight()); } } else { + //setDrawableBounds(Theme.checkDrawable, layoutWidth - AndroidUtilities.dp(18.5f) - Theme.checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - Theme.checkDrawable.getIntrinsicHeight()); if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)){ - setDrawableBounds(ResourceLoader.checkDrawable, checkX - AndroidUtilities.dp(3.5f) + ResourceLoader.checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.checkDrawable.getIntrinsicHeight()); - }else{ - setDrawableBounds(ResourceLoader.checkDrawable, layoutWidth - AndroidUtilities.dp(18.5f) - ResourceLoader.checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.checkDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.checkDrawable, checkX - AndroidUtilities.dp(3.5f) + Theme.checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - Theme.checkDrawable.getIntrinsicHeight()); + }else { + setDrawableBounds(Theme.checkDrawable, layoutWidth - AndroidUtilities.dp(18.5f) - Theme.checkDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - Theme.checkDrawable.getIntrinsicHeight()); + } } - } - ResourceLoader.checkDrawable.draw(canvas); + Theme.checkDrawable.draw(canvas); } else { if (drawCheck1) { + //setDrawableBounds(Theme.checkMediaDrawable, layoutWidth - AndroidUtilities.dp(26.3f) - Theme.checkMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(12.5f) - Theme.checkMediaDrawable.getIntrinsicHeight()); if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)){ - setDrawableBounds(ResourceLoader.checkMediaDrawable, checkX - AndroidUtilities.dp(8.0f) + ResourceLoader.checkMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.0f) - ResourceLoader.checkMediaDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.checkMediaDrawable, checkX - AndroidUtilities.dp(8.0f) + Theme.checkMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(12.5f) - Theme.checkMediaDrawable.getIntrinsicHeight()); }else{ - setDrawableBounds(ResourceLoader.checkMediaDrawable, layoutWidth - AndroidUtilities.dp(26.0f) - ResourceLoader.checkMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.0f) - ResourceLoader.checkMediaDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.checkMediaDrawable, layoutWidth - AndroidUtilities.dp(26.3f) - Theme.checkMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(12.5f) - Theme.checkMediaDrawable.getIntrinsicHeight()); } } else { + //setDrawableBounds(Theme.checkMediaDrawable, layoutWidth - AndroidUtilities.dp(21.5f) - Theme.checkMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(12.5f) - Theme.checkMediaDrawable.getIntrinsicHeight()); if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)){ - setDrawableBounds(ResourceLoader.checkMediaDrawable, checkX - AndroidUtilities.dp(7.0f) + ResourceLoader.checkMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.0f) - ResourceLoader.checkMediaDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.checkMediaDrawable, checkX - AndroidUtilities.dp(7.0f) + Theme.checkMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(12.5f) - Theme.checkMediaDrawable.getIntrinsicHeight()); }else{ - setDrawableBounds(ResourceLoader.checkMediaDrawable, layoutWidth - AndroidUtilities.dp(22.0f) - ResourceLoader.checkMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.0f) - ResourceLoader.checkMediaDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.checkMediaDrawable, layoutWidth - AndroidUtilities.dp(21.5f) - Theme.checkMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(12.5f) - Theme.checkMediaDrawable.getIntrinsicHeight()); + } } - } - ResourceLoader.checkMediaDrawable.draw(canvas); + Theme.checkMediaDrawable.draw(canvas); } } if (drawCheck1) { - if (!media) { + if (!mediaBackground) { + //setDrawableBounds(Theme.halfCheckDrawable, layoutWidth - AndroidUtilities.dp(18) - Theme.halfCheckDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - Theme.halfCheckDrawable.getIntrinsicHeight()); if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)){ - setDrawableBounds(ResourceLoader.halfCheckDrawable, checkX - AndroidUtilities.dp(3) + ResourceLoader.halfCheckDrawable.getIntrinsicWidth() , layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.halfCheckDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.halfCheckDrawable, checkX - AndroidUtilities.dp(3) + Theme.halfCheckDrawable.getIntrinsicWidth() , layoutHeight - AndroidUtilities.dp(8.0f) - Theme.halfCheckDrawable.getIntrinsicHeight()); }else{ - setDrawableBounds(ResourceLoader.halfCheckDrawable, layoutWidth - AndroidUtilities.dp(18) - ResourceLoader.halfCheckDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - ResourceLoader.halfCheckDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.halfCheckDrawable, layoutWidth - AndroidUtilities.dp(18) - Theme.halfCheckDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(8.0f) - Theme.halfCheckDrawable.getIntrinsicHeight()); } - ResourceLoader.halfCheckDrawable.draw(canvas); + Theme.halfCheckDrawable.draw(canvas); } else { + //setDrawableBounds(Theme.halfCheckMediaDrawable, layoutWidth - AndroidUtilities.dp(21.5f) - Theme.halfCheckMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(12.5f) - Theme.halfCheckMediaDrawable.getIntrinsicHeight()); if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)){ - setDrawableBounds(ResourceLoader.halfCheckMediaDrawable, checkX - AndroidUtilities.dp(3.0f) + ResourceLoader.halfCheckMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.0f) - ResourceLoader.halfCheckMediaDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.halfCheckMediaDrawable, checkX - AndroidUtilities.dp(3.0f) + Theme.halfCheckMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(12.5f) - Theme.halfCheckMediaDrawable.getIntrinsicHeight()); }else{ - setDrawableBounds(ResourceLoader.halfCheckMediaDrawable, layoutWidth - AndroidUtilities.dp(20.5f) - ResourceLoader.halfCheckMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(13.0f) - ResourceLoader.halfCheckMediaDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.halfCheckMediaDrawable, layoutWidth - AndroidUtilities.dp(21.5f) - Theme.halfCheckMediaDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(12.5f) - Theme.halfCheckMediaDrawable.getIntrinsicHeight()); } - ResourceLoader.halfCheckMediaDrawable.draw(canvas); + Theme.halfCheckMediaDrawable.draw(canvas); } } } if (drawError) { - if (!media) { + if (!mediaBackground) { + //setDrawableBounds(Theme.errorDrawable, layoutWidth - AndroidUtilities.dp(18) - Theme.errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(7) - Theme.errorDrawable.getIntrinsicHeight()); if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)){ - setDrawableBounds(ResourceLoader.errorDrawable, checkX - AndroidUtilities.dp(3) + ResourceLoader.errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(6.5f) - ResourceLoader.errorDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.errorDrawable, checkX - AndroidUtilities.dp(3) + Theme.errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(7f) - Theme.errorDrawable.getIntrinsicHeight()); }else{ - setDrawableBounds(ResourceLoader.errorDrawable, layoutWidth - AndroidUtilities.dp(18) - ResourceLoader.errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(6.5f) - ResourceLoader.errorDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.errorDrawable, layoutWidth - AndroidUtilities.dp(18) - Theme.errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(7f) - Theme.errorDrawable.getIntrinsicHeight()); } - ResourceLoader.errorDrawable.draw(canvas); + Theme.errorDrawable.draw(canvas); } else { + //setDrawableBounds(Theme.errorDrawable, layoutWidth - AndroidUtilities.dp(20.5f) - Theme.errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(11.5f) - Theme.errorDrawable.getIntrinsicHeight()); if((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)){ - setDrawableBounds(ResourceLoader.errorDrawable, checkX - AndroidUtilities.dp(5.5f) + ResourceLoader.errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(12.5f) - ResourceLoader.errorDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.errorDrawable, checkX - AndroidUtilities.dp(5.5f) + Theme.errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(11.5f) - Theme.errorDrawable.getIntrinsicHeight()); }else{ - setDrawableBounds(ResourceLoader.errorDrawable, layoutWidth - AndroidUtilities.dp(20.5f) - ResourceLoader.errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(12.5f) - ResourceLoader.errorDrawable.getIntrinsicHeight()); + setDrawableBounds(Theme.errorDrawable, layoutWidth - AndroidUtilities.dp(20.5f) - Theme.errorDrawable.getIntrinsicWidth(), layoutHeight - AndroidUtilities.dp(11.5f) - Theme.errorDrawable.getIntrinsicHeight()); } - ResourceLoader.errorDrawable.draw(canvas); + Theme.errorDrawable.draw(canvas); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java deleted file mode 100644 index ba243273..00000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatContactCell.java +++ /dev/null @@ -1,335 +0,0 @@ -/* - * This is the source code of Telegram for Android v. 3.x.x. - * It is licensed under GNU GPL v. 2 or later. - * You should have received a copy of the license in this archive (see LICENSE). - * - * Copyright Nikolai Kudashov, 2013-2016. - */ - -package org.telegram.ui.Cells; - -import android.content.Context; -import android.content.SharedPreferences; -import android.graphics.Canvas; -import android.graphics.drawable.Drawable; -import android.text.Layout; -import android.text.StaticLayout; -import android.text.TextPaint; -import android.text.TextUtils; -import android.view.MotionEvent; -import android.view.SoundEffectConstants; - -import org.telegram.PhoneFormat.PhoneFormat; -import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.ContactsController; -import org.telegram.messenger.ImageReceiver; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MessageObject; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.R; -import org.telegram.tgnet.TLRPC; -import org.telegram.messenger.UserConfig; -import org.telegram.ui.Components.AvatarDrawable; - -public class ChatContactCell extends ChatBaseCell { - - public interface ChatContactCellDelegate { - void didClickAddButton(ChatContactCell cell, TLRPC.User user); - void didClickPhone(ChatContactCell cell); - } - - private static TextPaint namePaint; - private static TextPaint phonePaint; - private static Drawable addContactDrawableIn; - private static Drawable addContactDrawableOut; - - private ImageReceiver avatarImage; - private AvatarDrawable avatarDrawable; - - private StaticLayout nameLayout; - private StaticLayout phoneLayout; - - private TLRPC.User contactUser; - private TLRPC.FileLocation currentPhoto; - - private boolean avatarPressed = false; - private boolean buttonPressed = false; - private boolean drawAddButton = false; - private int namesWidth = 0; - - private ChatContactCellDelegate contactDelegate = null; - - public ChatContactCell(Context context) { - super(context); - if (namePaint == null) { - namePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - namePaint.setTextSize(AndroidUtilities.dp(15)); - - phonePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); - phonePaint.setTextSize(AndroidUtilities.dp(15)); - phonePaint.setColor(0xff212121); - - addContactDrawableIn = getResources().getDrawable(R.drawable.addcontact_blue); - addContactDrawableOut = getResources().getDrawable(R.drawable.addcontact_green); - } - avatarImage = new ImageReceiver(this); - avatarImage.setRoundRadius(AndroidUtilities.dp(21)); - avatarDrawable = new AvatarDrawable(); - //Chat Contact Photo - int radius = AndroidUtilities.dp(AndroidUtilities.getIntDef("chatAvatarRadius", 32)); - avatarImage.setRoundRadius(radius); - avatarDrawable.setRadius(radius); - // - } - - public void setContactDelegate(ChatContactCellDelegate delegate) { - this.contactDelegate = delegate; - } - - @Override - protected boolean isUserDataChanged() { - if (currentMessageObject == null) { - return false; - } - - int uid = currentMessageObject.messageOwner.media.user_id; - boolean newDrawAdd = contactUser != null && uid != UserConfig.getClientUserId() && ContactsController.getInstance().contactsDict.get(uid) == null; - if (newDrawAdd != drawAddButton) { - return true; - } - - contactUser = MessagesController.getInstance().getUser(currentMessageObject.messageOwner.media.user_id); - - TLRPC.FileLocation newPhoto = null; - if (contactUser != null && contactUser.photo != null) { - newPhoto = contactUser.photo.photo_small; - } - - return currentPhoto == null && newPhoto != null || currentPhoto != null && newPhoto == null || currentPhoto != null && newPhoto != null && (currentPhoto.local_id != newPhoto.local_id || currentPhoto.volume_id != newPhoto.volume_id) || super.isUserDataChanged(); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - float x = event.getX(); - float y = event.getY(); - - boolean result = false; - if (event.getAction() == MotionEvent.ACTION_DOWN) { - if (x >= avatarImage.getImageX() && x <= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(42) && y >= avatarImage.getImageY() && y <= avatarImage.getImageY() + avatarImage.getImageHeight()) { - avatarPressed = true; - result = true; - } else if (x >= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(52) && y >= AndroidUtilities.dp(13) + namesOffset && x <= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(92) && y <= AndroidUtilities.dp(52) + namesOffset) { - buttonPressed = true; - result = true; - } - if (result) { - startCheckLongPress(); - } - } else { - if (event.getAction() != MotionEvent.ACTION_MOVE) { - cancelCheckLongPress(); - } - if (avatarPressed) { - if (event.getAction() == MotionEvent.ACTION_UP) { - avatarPressed = false; - playSoundEffect(SoundEffectConstants.CLICK); - if (contactUser != null) { - if (delegate != null) { - delegate.didPressedUserAvatar(this, contactUser); - } - } else { - if (contactDelegate != null) { - contactDelegate.didClickPhone(this); - } - } - } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { - avatarPressed = false; - } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (!(x >= avatarImage.getImageX() && x <= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(42) && y >= avatarImage.getImageY() && y <= avatarImage.getImageY() + avatarImage.getImageHeight())) { - avatarPressed = false; - } - } - } else if (buttonPressed) { - if (event.getAction() == MotionEvent.ACTION_UP) { - buttonPressed = false; - playSoundEffect(SoundEffectConstants.CLICK); - if (contactUser != null && contactDelegate != null) { - contactDelegate.didClickAddButton(this, contactUser); - } - } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { - buttonPressed = false; - } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (!(x >= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(52) && y >= AndroidUtilities.dp(13) + namesOffset && x <= avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(92) && y <= AndroidUtilities.dp(52) + namesOffset)) { - buttonPressed = false; - } - } - } - } - if (!result) { - result = super.onTouchEvent(event); - } - - return result; - } - - @Override - public void setMessageObject(MessageObject messageObject) { - if (currentMessageObject != messageObject || isUserDataChanged()) { - - int uid = messageObject.messageOwner.media.user_id; - contactUser = MessagesController.getInstance().getUser(uid); - - drawAddButton = contactUser != null && uid != UserConfig.getClientUserId() && ContactsController.getInstance().contactsDict.get(uid) == null; - - int maxWidth; - if (AndroidUtilities.isTablet()) { - maxWidth = (int) (AndroidUtilities.getMinTabletSide() * 0.7f); - } else { - maxWidth = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.7f); - } - maxWidth -= AndroidUtilities.dp(58 + (drawAddButton ? 42 : 0)); - - if (contactUser != null) { - if (contactUser.photo != null) { - currentPhoto = contactUser.photo.photo_small; - } else { - currentPhoto = null; - } - avatarDrawable.setInfo(contactUser); - } else { - currentPhoto = null; - avatarDrawable.setInfo(uid, null, null, false); - } - if(uid == 0) { - SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - int color = themePrefs.getInt("chatContactNameColor", themePrefs.getInt("themeColor", AndroidUtilities.defColor)); - avatarDrawable.setColor(color); - } - avatarImage.setImage(currentPhoto, "50_50", avatarDrawable, null, false); - - String currentNameString = ContactsController.formatName(messageObject.messageOwner.media.first_name, messageObject.messageOwner.media.last_name); - int nameWidth = Math.min((int) Math.ceil(namePaint.measureText(currentNameString)), maxWidth); - if (maxWidth < 0) { - maxWidth = AndroidUtilities.dp(100); - } - - CharSequence stringFinal = TextUtils.ellipsize(currentNameString.replace("\n", " "), namePaint, nameWidth, TextUtils.TruncateAt.END); - nameLayout = new StaticLayout(stringFinal, namePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - if (nameLayout.getLineCount() > 0) { - nameWidth = (int)Math.ceil(nameLayout.getLineWidth(0)); - } else { - nameWidth = 0; - } - - String phone = messageObject.messageOwner.media.phone_number; - if (phone != null && phone.length() != 0) { - if (!phone.startsWith("+")) { - phone = "+" + phone; - } - phone = PhoneFormat.getInstance().format(phone); - } else { - phone = LocaleController.getString("NumberUnknown", R.string.NumberUnknown); - } - int phoneWidth = Math.min((int) Math.ceil(phonePaint.measureText(phone)), maxWidth); - stringFinal = TextUtils.ellipsize(phone.replace("\n", " "), phonePaint, phoneWidth, TextUtils.TruncateAt.END); - phoneLayout = new StaticLayout(stringFinal, phonePaint, phoneWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - if (phoneLayout.getLineCount() > 0) { - phoneWidth = (int)Math.ceil(phoneLayout.getLineWidth(0)); - } else { - phoneWidth = 0; - } - - namesWidth = Math.max(nameWidth, phoneWidth); - backgroundWidth = AndroidUtilities.dp(77 + (drawAddButton ? 42 : 0)) + namesWidth; - - super.setMessageObject(messageObject); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(71) + namesOffset); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - - if (currentMessageObject == null) { - return; - } - - int x; - - if (currentMessageObject.isOutOwner()) { - //x = layoutWidth - backgroundWidth + AndroidUtilities.dp(8); - x = layoutWidth - backgroundWidth + AndroidUtilities.dp(8) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); - } else { - if ((isChat || showAvatar) && currentMessageObject.messageOwner.from_id > 0) { - //x = AndroidUtilities.dp(69); - x = AndroidUtilities.dp(leftBound + 17); - } else { - x = AndroidUtilities.dp(16); - } - } - avatarImage.setImageCoords(x, AndroidUtilities.dp(9) + namesOffset, AndroidUtilities.dp(42), AndroidUtilities.dp(42)); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - if (currentMessageObject == null) { - return; - } - - avatarImage.draw(canvas); - SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - if (nameLayout != null) { - canvas.save(); - canvas.translate(avatarImage.getImageX() + avatarImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(10) + namesOffset); - //namePaint.setColor(AvatarDrawable.getColorForId(currentMessageObject.messageOwner.media.user_id)); - namePaint.setColor(AvatarDrawable.getNameColorForId(currentMessageObject.messageOwner.media.user_id)); - int id = currentMessageObject.messageOwner.media.user_id; - int defColor = themePrefs.getInt("themeColor", AndroidUtilities.defColor); - int color = themePrefs.getInt("chatContactNameColor", defColor); - if(id == 0 || color != defColor){ - namePaint.setColor(color); - //avatarDrawable.setColor(color); - }/*else{ - //if(color == defColor){ - namePaint.setColor(AvatarDrawable.getNameColorForId(currentMessageObject.messageOwner.media.user_id)); - //}else{ - // namePaint.setColor(color); - //} - }*/ - - nameLayout.draw(canvas); - canvas.restore(); - } - if (phoneLayout != null) { - - int color = themePrefs.getInt("chatLTextColor", 0xff000000); - if (currentMessageObject.isOut()) { - color = themePrefs.getInt("chatRTextColor", 0xff000000); - } - phonePaint.setColor(color); - canvas.save(); - canvas.translate(avatarImage.getImageX() + avatarImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(31) + namesOffset); - phoneLayout.draw(canvas); - canvas.restore(); - } - - if (drawAddButton) { - Drawable addContactDrawable; - if (currentMessageObject.isOutOwner()) { - addContactDrawable = addContactDrawableOut; - } else { - addContactDrawable = addContactDrawableIn; - } - setDrawableBounds(addContactDrawable, avatarImage.getImageX() + namesWidth + AndroidUtilities.dp(78), AndroidUtilities.dp(13) + namesOffset); - addContactDrawable.draw(canvas); - } - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatLoadingCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatLoadingCell.java new file mode 100644 index 00000000..a0f48780 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatLoadingCell.java @@ -0,0 +1,52 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.ProgressBar; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.R; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.ActionBar.Theme; + +public class ChatLoadingCell extends FrameLayout { + + private FrameLayout frameLayout; + + public ChatLoadingCell(Context context) { + super(context); + + frameLayout = new FrameLayout(context); + frameLayout.setBackgroundResource(R.drawable.system_loader); + frameLayout.getBackground().setColorFilter(Theme.colorFilter); + addView(frameLayout, LayoutHelper.createFrame(36, 36, Gravity.CENTER)); + + ProgressBar progressBar = new ProgressBar(context); + try { + progressBar.setIndeterminateDrawable(getResources().getDrawable(R.drawable.loading_animation)); + } catch (Exception e) { + //don't promt + } + progressBar.setIndeterminate(true); + AndroidUtilities.setProgressBarAnimationDuration(progressBar, 1500); + frameLayout.addView(progressBar, LayoutHelper.createFrame(32, 32, Gravity.CENTER)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(44), MeasureSpec.EXACTLY)); + } + + public void setProgressVisible(boolean value) { + frameLayout.setVisibility(value ? VISIBLE : INVISIBLE); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java deleted file mode 100644 index b7cec741..00000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMediaCell.java +++ /dev/null @@ -1,1429 +0,0 @@ -/* - * This is the source code of Telegram for Android v. 3.x.x. - * It is licensed under GNU GPL v. 2 or later. - * You should have received a copy of the license in this archive (see LICENSE). - * - * Copyright Nikolai Kudashov, 2013-2016. - */ - -package org.telegram.ui.Cells; - -import android.content.Context; -import android.content.SharedPreferences; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.RectF; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.text.Layout; -import android.text.Spannable; -import android.text.StaticLayout; -import android.text.TextPaint; -import android.text.TextUtils; -import android.text.style.ClickableSpan; -import android.util.Log; -import android.view.MotionEvent; -import android.view.SoundEffectConstants; - -import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.FileLoader; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.ImageLoader; -import org.telegram.messenger.ImageReceiver; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MediaController; -import org.telegram.messenger.MessageObject; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.R; -import org.telegram.messenger.SendMessagesHelper; -import org.telegram.messenger.UserObject; -import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.TLRPC; -import org.telegram.ui.Components.AvatarDrawable; -import org.telegram.ui.Components.RadialProgress; -import org.telegram.ui.Components.ResourceLoader; -import org.telegram.ui.Components.StaticLayoutEx; -import org.telegram.ui.Components.URLSpanBotCommand; -import org.telegram.ui.PhotoViewer; - -import java.io.File; -import java.util.HashMap; -import java.util.Locale; - -public class ChatMediaCell extends ChatBaseCell { - - public interface ChatMediaCellDelegate { - void didPressedOther(ChatMediaCell cell); - } - - private static TextPaint infoPaint; - private static TextPaint namePaint; - private static Paint docBackPaint; - private static Paint deleteProgressPaint; - private static TextPaint locationTitlePaint; - private static TextPaint locationAddressPaint; - - private RadialProgress radialProgress; - - private int photoWidth; - private int photoHeight; - private TLRPC.PhotoSize currentPhotoObject; - private TLRPC.PhotoSize currentPhotoObjectThumb; - private String currentUrl; - private String currentPhotoFilter; - private ImageReceiver photoImage; - private boolean photoNotSet = false; - private boolean cancelLoading = false; - private int additionHeight; - - private boolean allowedToSetPhoto = true; - - private int buttonState = 0; - private int buttonPressed = 0; - private boolean imagePressed = false; - private boolean otherPressed = false; - private int buttonX; - private int buttonY; - - private StaticLayout infoLayout; - private int infoWidth; - private int infoOffset = 0; - private String currentInfoString; - //Plus - private StaticLayout infoLayout2; - private int infoWidth2; - private static TextPaint senderPaint; - private int infoOffset2 = 0; - // - private StaticLayout nameLayout; - private int nameWidth = 0; - private int nameOffsetX = 0; - private String currentNameString; - - private ChatMediaCellDelegate mediaDelegate = null; - private RectF deleteProgressRect = new RectF(); - - private int captionX; - private int captionY; - private int captionHeight; - - private long docSize; - - public ChatMediaCell(Context context) { - super(context); - - if (infoPaint == null) { - infoPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - infoPaint.setTextSize(AndroidUtilities.dp(12)); - - namePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - namePaint.setColor(0xff212121); - namePaint.setTextSize(AndroidUtilities.dp(16)); - - //namePaint.setColor(AndroidUtilities.getIntDef("chatFileInfoColor", 0xff212121)); - senderPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - senderPaint.setColor(0xffffffff); - senderPaint.setTextSize(AndroidUtilities.dp(15)); - - docBackPaint = new Paint(); - - deleteProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - deleteProgressPaint.setColor(0xffe4e2e0); - - locationTitlePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - locationTitlePaint.setTextSize(AndroidUtilities.dp(14)); - locationTitlePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - - locationAddressPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - locationAddressPaint.setTextSize(AndroidUtilities.dp(14)); - } - - photoImage = new ImageReceiver(this); - radialProgress = new RadialProgress(this); - } - - public void setMediaDelegate(ChatMediaCellDelegate delegate) { - this.mediaDelegate = delegate; - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - photoImage.onDetachedFromWindow(); - MediaController.getInstance().removeLoadingFileObserver(this); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if (photoImage.onAttachedToWindow()) { - updateButtonState(false); - } - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - float x = event.getX(); - float y = event.getY(); - - boolean result = false; - int side = AndroidUtilities.dp(48); - if (currentMessageObject.caption instanceof Spannable && delegate.canPerformActions()) { - if (event.getAction() == MotionEvent.ACTION_DOWN || (linkPreviewPressed || pressedLink != null) && event.getAction() == MotionEvent.ACTION_UP) { - if (nameLayout != null && x >= captionX && x <= captionX + backgroundWidth && y >= captionY && y <= captionY + captionHeight) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - resetPressedLink(); - try { - int x2 = (int) (x - captionX); - int y2 = (int) (y - captionY); - final int line = nameLayout.getLineForVertical(y2); - final int off = nameLayout.getOffsetForHorizontal(line, x2); - - final float left = nameLayout.getLineLeft(line); - if (left <= x2 && left + nameLayout.getLineWidth(line) >= x2) { - Spannable buffer = (Spannable) currentMessageObject.caption; - ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); - boolean ignore = false; - if (link.length == 0 || link.length != 0 && link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { - ignore = true; - } - if (!ignore) { - resetPressedLink(); - pressedLink = link[0]; - linkPreviewPressed = true; - result = true; - try { - int start = buffer.getSpanStart(pressedLink); - urlPath.setCurrentLayout(nameLayout, start); - nameLayout.getSelectionPath(start, buffer.getSpanEnd(pressedLink), urlPath); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } else { - resetPressedLink(); - } - } else { - resetPressedLink(); - } - } catch (Exception e) { - resetPressedLink(); - FileLog.e("tmessages", e); - } - } else if (linkPreviewPressed) { - try { - delegate.didPressUrl(currentMessageObject, pressedLink, false); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - resetPressedLink(); - result = true; - } - } else { - resetPressedLink(); - } - } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { - resetPressedLink(); - } - - if (result && event.getAction() == MotionEvent.ACTION_DOWN) { - startCheckLongPress(); - } - if (event.getAction() != MotionEvent.ACTION_DOWN && event.getAction() != MotionEvent.ACTION_MOVE) { - cancelCheckLongPress(); - } - if (result) { - return true; - } - } - if (event.getAction() == MotionEvent.ACTION_DOWN) { - if (delegate == null || delegate.canPerformActions()) { - if (buttonState != -1 && x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side) { - buttonPressed = 1; - invalidate(); - result = true; - } else { - if (currentMessageObject.type == 9) { - if (x >= photoImage.getImageX() && x <= photoImage.getImageX() + backgroundWidth - AndroidUtilities.dp(50) && y >= photoImage.getImageY() && y <= photoImage.getImageY() + photoImage.getImageHeight()) { - imagePressed = true; - result = true; - } else if (x >= photoImage.getImageX() + backgroundWidth - AndroidUtilities.dp(50) && x <= photoImage.getImageX() + backgroundWidth && y >= photoImage.getImageY() && y <= photoImage.getImageY() + photoImage.getImageHeight()) { - otherPressed = true; - result = true; - } - } else if (currentMessageObject.type != 13) { - if (x >= photoImage.getImageX() && x <= photoImage.getImageX() + backgroundWidth && y >= photoImage.getImageY() && y <= photoImage.getImageY() + photoImage.getImageHeight()) { - imagePressed = true; - result = true; - } - } - } - if (imagePressed && currentMessageObject.isSecretPhoto()) { - imagePressed = false; - } else if (imagePressed && currentMessageObject.isSendError()) { - imagePressed = false; - result = false; - } else if (imagePressed && currentMessageObject.type == 8 && buttonState == -1 && MediaController.getInstance().canAutoplayGifs()) { - imagePressed = false; - result = false; - } else if (result) { - startCheckLongPress(); - } - } - } else { - if (event.getAction() != MotionEvent.ACTION_MOVE) { - cancelCheckLongPress(); - } - if (buttonPressed == 1) { - if (event.getAction() == MotionEvent.ACTION_UP) { - buttonPressed = 0; - playSoundEffect(SoundEffectConstants.CLICK); - didPressedButton(false); - invalidate(); - } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { - buttonPressed = 0; - invalidate(); - } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (!(x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side)) { - buttonPressed = 0; - invalidate(); - } - } - } else if (imagePressed) { - if (event.getAction() == MotionEvent.ACTION_UP) { - imagePressed = false; - if (buttonState == -1 || buttonState == 2 || buttonState == 3) { - playSoundEffect(SoundEffectConstants.CLICK); - didClickedImage(); - } - invalidate(); - } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { - imagePressed = false; - invalidate(); - } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (currentMessageObject.type == 9) { - if (!(x >= photoImage.getImageX() && x <= photoImage.getImageX() + backgroundWidth - AndroidUtilities.dp(50) && y >= photoImage.getImageY() && y <= photoImage.getImageY() + photoImage.getImageHeight())) { - imagePressed = false; - invalidate(); - } - } else { - if (!photoImage.isInsideImage(x, y)) { - imagePressed = false; - invalidate(); - } - } - } - } else if (otherPressed) { - if (event.getAction() == MotionEvent.ACTION_UP) { - otherPressed = false; - playSoundEffect(SoundEffectConstants.CLICK); - if (mediaDelegate != null) { - mediaDelegate.didPressedOther(this); - } - } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { - otherPressed = false; - } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (currentMessageObject.type == 9) { - if (!(x >= photoImage.getImageX() + backgroundWidth - AndroidUtilities.dp(50) && x <= photoImage.getImageX() + backgroundWidth && y >= photoImage.getImageY() && y <= photoImage.getImageY() + photoImage.getImageHeight())) { - otherPressed = false; - } - } - } - } - } - if (!result) { - result = super.onTouchEvent(event); - } - - return result; - } - - private void didClickedImage() { - if (currentMessageObject.type == 1) { - if (buttonState == -1) { - if (delegate != null) { - delegate.didClickedImage(this); - } - } else if (buttonState == 0) { - didPressedButton(false); - } - } else if (currentMessageObject.type == 8) { - if (buttonState == -1) { - buttonState = 2; - currentMessageObject.audioProgress = 1; - photoImage.setAllowStartAnimation(false); - photoImage.stopAnimation(); - radialProgress.setBackground(getDrawableForCurrentState(), false, false); - invalidate(); - } else if (buttonState == 2 || buttonState == 0) { - didPressedButton(false); - } - } else if (currentMessageObject.type == 3) { - if (buttonState == 0 || buttonState == 3) { - didPressedButton(false); - } - } else if (currentMessageObject.type == 4) { - if (delegate != null) { - delegate.didClickedImage(this); - } - } else if (currentMessageObject.type == 9) { - if (buttonState == -1) { - if (delegate != null) { - delegate.didClickedImage(this); - } - } - } - } - - @Override - public void setCheckPressed(boolean value, boolean pressed) { - super.setCheckPressed(value, pressed); - if (radialProgress.swapBackground(getDrawableForCurrentState())) { - invalidate(); - } - } - - @Override - public void setHighlighted(boolean value) { - super.setHighlighted(value); - if (radialProgress.swapBackground(getDrawableForCurrentState())) { - invalidate(); - } - } - - @Override - public void setPressed(boolean pressed) { - super.setPressed(pressed); - if (radialProgress.swapBackground(getDrawableForCurrentState())) { - invalidate(); - } - } - - private Drawable getDrawableForCurrentState() { - if (buttonState >= 0 && buttonState < 4) { - if (currentMessageObject.type == 9) { - if (buttonState == 1 && !currentMessageObject.isSending()) { - return ResourceLoader.buttonStatesDrawablesDoc[2][currentMessageObject.isOutOwner() ? 1 : (isDrawSelectedBackground() ? 2 : 0)]; - } else { - return ResourceLoader.buttonStatesDrawablesDoc[buttonState][currentMessageObject.isOutOwner() ? 1 : (isDrawSelectedBackground() ? 2 : 0)]; - } - } else { - if (buttonState == 1 && !currentMessageObject.isSending()) { - return ResourceLoader.buttonStatesDrawables[4]; - } else { - return ResourceLoader.buttonStatesDrawables[buttonState]; - } - } - } else if (buttonState == -1) { - if (currentMessageObject.type == 9) { - return ResourceLoader.placeholderDocDrawable[currentMessageObject.isOutOwner() ? 1 : (isDrawSelectedBackground() ? 2 : 0)]; - } - } - return null; - } - - private void didPressedButton(boolean animated) { - if (buttonState == 0) { - cancelLoading = false; - radialProgress.setProgress(0, false); - if (currentMessageObject.type == 1) { - photoImage.setImage(currentPhotoObject.location, currentPhotoFilter, currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, currentPhotoFilter, currentPhotoObject.size, null, false); - } else if (currentMessageObject.type == 8) { - currentMessageObject.audioProgress = 2; - photoImage.setImage(currentMessageObject.messageOwner.media.document, null, currentPhotoObject != null ? currentPhotoObject.location : null, currentPhotoFilter, currentMessageObject.messageOwner.media.document.size, null, false); - } else if (currentMessageObject.type == 9) { - FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.document, false, false); - } else if (currentMessageObject.type == 3) { - FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.video, true); - } - buttonState = 1; - radialProgress.setBackground(getDrawableForCurrentState(), true, animated); - invalidate(); - } else if (buttonState == 1) { - if (currentMessageObject.isOut() && currentMessageObject.isSending()) { - if (delegate != null) { - delegate.didPressedCancelSendButton(this); - } - } else { - cancelLoading = true; - if (currentMessageObject.type == 1 || currentMessageObject.type == 8) { - photoImage.cancelLoadImage(); - } else if (currentMessageObject.type == 9) { - FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.document); - } else if (currentMessageObject.type == 3) { - FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.video); - } - buttonState = 0; - radialProgress.setBackground(getDrawableForCurrentState(), false, animated); - invalidate(); - } - } else if (buttonState == 2) { - photoImage.setAllowStartAnimation(true); - photoImage.startAnimation(); - currentMessageObject.audioProgress = 0; - buttonState = -1; - radialProgress.setBackground(getDrawableForCurrentState(), false, animated); - } else if (buttonState == 3) { - if (delegate != null) { - delegate.didClickedImage(this); - } - } - } - - private boolean isPhotoDataChanged(MessageObject object) { - if (object.type == 4) { - if (currentUrl == null) { - return true; - } - double lat = object.messageOwner.media.geo.lat; - double lon = object.messageOwner.media.geo._long; - String url = String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%f,%f&zoom=15&size=100x100&maptype=roadmap&scale=%d&markers=color:red|size:big|%f,%f&sensor=false", lat, lon, Math.min(2, (int) Math.ceil(AndroidUtilities.density)), lat, lon); - if (!url.equals(currentUrl)) { - return true; - } - } else if (currentPhotoObject == null || currentPhotoObject.location instanceof TLRPC.TL_fileLocationUnavailable) { - return true; - } else if (currentMessageObject != null && photoNotSet) { - File cacheFile = FileLoader.getPathToMessage(currentMessageObject.messageOwner); - if (cacheFile.exists()) { - return true; - } - } - return false; - } - - private String getCurrentNameString(MessageObject messageObject){ - TLRPC.User currentUser = null; - TLRPC.Chat currentChat = null; - String s; - if (messageObject.messageOwner.from_id > 0) { - currentUser = MessagesController.getInstance().getUser(messageObject.messageOwner.from_id); - } else if (messageObject.messageOwner.from_id < 0) { - currentChat = MessagesController.getInstance().getChat(-messageObject.messageOwner.from_id); - } - - if (currentUser != null) { - s = UserObject.getUserName(currentUser); - String currentUsernameString = currentUser.username; - /*if(currentUsernameString != null && AndroidUtilities.getBoolPref("chatShowUsernameCheck")){ - currentNameString = currentNameString.replaceAll("\\p{C}", " "); - currentNameString = currentNameString.trim().replaceAll(" +", " ") + " [@"+currentUsernameString+"]"; - }*/ - } else if (currentChat != null) { - s = currentChat.title; - } else { - s = "DELETED"; - } - return s; - } - - @Override - public void setMessageObject(MessageObject messageObject) { - boolean messageChanged = currentMessageObject != messageObject; - boolean dataChanged = currentMessageObject == messageObject && (isUserDataChanged() || photoNotSet); - if (currentMessageObject != messageObject || isPhotoDataChanged(messageObject) || dataChanged) { - drawForwardedName = messageObject.messageOwner.fwd_from_id != null && messageObject.type != 13; - media = messageObject.type != 9; - cancelLoading = false; - additionHeight = 0; - resetPressedLink(); - if (messageObject.audioProgress != 2 && !MediaController.getInstance().canAutoplayGifs() && messageObject.type == 8) { - messageObject.audioProgress = 1; - } - - buttonState = -1; - currentPhotoObject = null; - currentPhotoObjectThumb = null; - currentUrl = null; - photoNotSet = false; - drawBackground = true; - drawName = false; - photoImage.setAllowStartAnimation(messageObject.audioProgress == 0); - - photoImage.setForcePreview(messageObject.isSecretPhoto()); - if (messageObject.type == 9) { - String name = messageObject.getDocumentName(); - if (name == null || name.length() == 0) { - name = LocaleController.getString("AttachDocument", R.string.AttachDocument); - } - int maxWidth; - if (AndroidUtilities.isTablet()) { - maxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(122 + 86 + 24); - } else { - //maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(122 + 86 + 24); - maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp((isChat && messageObject.messageOwner.from_id < 0 ? 15 : leftBound) + 70 + 86 + 24); - if(!messageObject.isOutOwner() && (!isChat && showAvatar || isChat && messageObject.messageOwner.from_id > 0))maxWidth = maxWidth - AndroidUtilities.dp(15); - } - if (currentNameString == null || !currentNameString.equals(name)) { - currentNameString = name; - maxWidth = maxWidth + AndroidUtilities.dp(1); //to fix 2 lines bug - nameLayout = StaticLayoutEx.createStaticLayout(currentNameString, namePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, maxWidth, 1); - if (nameLayout != null && nameLayout.getLineCount() > 0) { - nameWidth = Math.min(maxWidth, (int) Math.ceil(nameLayout.getLineWidth(0))); - nameOffsetX = (int) Math.ceil(-nameLayout.getLineLeft(0)); - } else { - nameWidth = maxWidth; - } - } - - String str = AndroidUtilities.formatFileSize(messageObject.messageOwner.media.document.size) + " " + messageObject.getExtension(); - - radialProgress.setSizeAndType(messageObject.messageOwner.media.document.size, messageObject.type); //plus - if (currentInfoString == null || !currentInfoString.equals(str)) { - currentInfoString = str; - infoOffset = 0; - infoWidth = Math.min(maxWidth, (int) Math.ceil(infoPaint.measureText(currentInfoString))); - infoLayout2 = null; - - if(isChat){ - - String senderName = getCurrentNameString(messageObject); - - infoWidth2 = Math.min(maxWidth, (int) Math.ceil(senderPaint.measureText(senderName))); - CharSequence str2 = TextUtils.ellipsize(senderName, senderPaint, infoWidth2, TextUtils.TruncateAt.END); - infoLayout2 = new StaticLayout(str2, senderPaint, infoWidth2, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - infoWidth = Math.max(infoWidth2, (int) Math.ceil(infoPaint.measureText(currentInfoString))); - } - CharSequence str2 = TextUtils.ellipsize(currentInfoString, infoPaint, infoWidth, TextUtils.TruncateAt.END); - infoLayout = new StaticLayout(str2, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - } - } else if (messageObject.type == 8) { - String str = AndroidUtilities.formatFileSize(messageObject.messageOwner.media.document.size); - radialProgress.setSizeAndType(messageObject.messageOwner.media.document.size, messageObject.type); //plus - if (currentInfoString == null || !currentInfoString.equals(str)) { - currentInfoString = str; - infoOffset = 0; - infoWidth = (int) Math.ceil(infoPaint.measureText(currentInfoString)); - infoLayout = new StaticLayout(currentInfoString, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - } - nameLayout = null; - currentNameString = null; - } else if (messageObject.type == 3) { //VIDEO - int duration = messageObject.messageOwner.media.video.duration; - int minutes = duration / 60; - int seconds = duration - minutes * 60; - String str = String.format("%d:%02d, %s", minutes, seconds, AndroidUtilities.formatFileSize(messageObject.messageOwner.media.video.size)); - radialProgress.setSizeAndType(messageObject.messageOwner.media.video.size, messageObject.type); //plus - if (currentInfoString == null || !currentInfoString.equals(str)) { - currentInfoString = str; - infoOffset = ResourceLoader.videoIconDrawable.getIntrinsicWidth() + AndroidUtilities.dp(4); - infoWidth = (int) Math.ceil(infoPaint.measureText(currentInfoString)); - infoLayout = new StaticLayout(currentInfoString, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - //Plus - //infoLayout = null; - infoLayout2 = null; - if(isChat){ - infoOffset2 = ResourceLoader.videoIconDrawable.getIntrinsicWidth() + AndroidUtilities.dp(5); - infoOffset = 0; - String senderName = getCurrentNameString(messageObject); - infoWidth2 = (int) Math.ceil(infoPaint.measureText(currentInfoString)); - //infoWidth = (int) Math.ceil(senderPaint.measureText(senderName)); - infoWidth = Math.max(infoWidth2, (int) Math.ceil(senderPaint.measureText(senderName))); - infoLayout = new StaticLayout(senderName, senderPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - infoLayout2 = new StaticLayout(currentInfoString, infoPaint, infoWidth2, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - - }// - } - nameLayout = null; - currentNameString = null; - }//Plus: member name in photos - else if (messageObject.type == 1) { //PHOTO - radialProgress.setSizeAndType(0, messageObject.type); - currentNameString = getCurrentNameString(messageObject); - - String senderName = currentNameString; - - if (currentInfoString == null || !currentInfoString.equals(senderName)) { - currentInfoString = senderName; - infoOffset = 0; - infoLayout = null; - //Log.e("chatMediaCell"," chat_id " + messageObject.messageOwner.to_id.chat_id + " channel_id " + messageObject.messageOwner.to_id.channel_id + " from_id " + messageObject.messageOwner.from_id); - try{ - if(isChat && messageObject.messageOwner.from_id > 0){ - infoWidth = (int) Math.min(Math.ceil(namePaint.measureText(currentNameString)), Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.5f); - CharSequence str = TextUtils.ellipsize(currentNameString, senderPaint, infoWidth, TextUtils.TruncateAt.END); - infoLayout = new StaticLayout(str, senderPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - nameLayout = null; - currentNameString = null; - infoLayout2 = null; - }// - else { - currentInfoString = null; - currentNameString = null; - infoLayout = null; - nameLayout = null; - updateSecretTimeText(messageObject); - infoLayout2 = null; //Plus - } - if (messageObject.type == 9) { //doc - photoWidth = AndroidUtilities.dp(86); - photoHeight = AndroidUtilities.dp(86); - backgroundWidth = photoWidth + Math.max(nameWidth, infoWidth) + AndroidUtilities.dp(68); - //Log.e("ChatMediaCell","backgroundWidth " + backgroundWidth + " nameWidth " + nameWidth + " infoWidth " + infoWidth + " drawShareButton " + drawShareButton); - //backgroundWidth = backgroundWidth - AndroidUtilities.dp(5); - currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); - photoImage.setNeedsQualityThumb(true); - photoImage.setShouldGenerateQualityThumb(true); - photoImage.setParentMessageObject(messageObject); - if (currentPhotoObject != null) { - currentPhotoFilter = String.format(Locale.US, "%d_%d_b", photoWidth, photoHeight); - photoImage.setImage(null, null, null, null, currentPhotoObject.location, currentPhotoFilter, 0, null, true); - } else { - photoImage.setImageBitmap((BitmapDrawable) null); - } - } else if (messageObject.type == 4) { //geo - double lat = messageObject.messageOwner.media.geo.lat; - double lon = messageObject.messageOwner.media.geo._long; - - if (messageObject.messageOwner.media.title != null && messageObject.messageOwner.media.title.length() > 0) { - //int maxWidth = (AndroidUtilities.isTablet() ? AndroidUtilities.getMinTabletSide() : Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y)) - AndroidUtilities.dp((isChat && !messageObject.isOutOwner() ? 102 : 40) + 86 + 24); - int maxWidth = (AndroidUtilities.isTablet() ? AndroidUtilities.getMinTabletSide() : Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y)) - AndroidUtilities.dp(((isChat || showAvatar) && !messageObject.isOutOwner() ? leftBound + 50 : 40) + 86 + 24); - nameLayout = StaticLayoutEx.createStaticLayout(messageObject.messageOwner.media.title, locationTitlePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, maxWidth - AndroidUtilities.dp(4), 3); - int lineCount = nameLayout.getLineCount(); - if (messageObject.messageOwner.media.address != null && messageObject.messageOwner.media.address.length() > 0) { - infoLayout = StaticLayoutEx.createStaticLayout(messageObject.messageOwner.media.address, locationAddressPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, maxWidth - AndroidUtilities.dp(4), Math.min(3, 4 - lineCount)); - } else { - infoLayout = null; - } - - media = false; - measureTime(messageObject); - photoWidth = AndroidUtilities.dp(86); - photoHeight = AndroidUtilities.dp(86); - maxWidth = timeWidth + AndroidUtilities.dp(messageObject.isOutOwner() ? 29 : 9); - for (int a = 0; a < lineCount; a++) { - maxWidth = (int) Math.max(maxWidth, nameLayout.getLineWidth(a) + AndroidUtilities.dp(16)); - } - if (infoLayout != null) { - for (int a = 0; a < infoLayout.getLineCount(); a++) { - maxWidth = (int) Math.max(maxWidth, infoLayout.getLineWidth(a) + AndroidUtilities.dp(16)); - } - } - backgroundWidth = photoWidth + AndroidUtilities.dp(21) + maxWidth; - currentUrl = String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%f,%f&zoom=15&size=72x72&maptype=roadmap&scale=%d&markers=color:red|size:big|%f,%f&sensor=false", lat, lon, Math.min(2, (int) Math.ceil(AndroidUtilities.density)), lat, lon); - } else { - photoWidth = AndroidUtilities.dp(200); - photoHeight = AndroidUtilities.dp(100); - backgroundWidth = photoWidth + AndroidUtilities.dp(12); - currentUrl = String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%f,%f&zoom=15&size=200x100&maptype=roadmap&scale=%d&markers=color:red|size:big|%f,%f&sensor=false", lat, lon, Math.min(2, (int) Math.ceil(AndroidUtilities.density)), lat, lon); - } - - photoImage.setNeedsQualityThumb(false); - photoImage.setShouldGenerateQualityThumb(false); - photoImage.setParentMessageObject(null); - photoImage.setImage(currentUrl, null, messageObject.isOutOwner() ? ResourceLoader.geoOutDrawable : ResourceLoader.geoInDrawable, null, 0); - } else if (messageObject.type == 13) { //webp - drawBackground = false; - for (int a = 0; a < messageObject.messageOwner.media.document.attributes.size(); a++) { - TLRPC.DocumentAttribute attribute = messageObject.messageOwner.media.document.attributes.get(a); - if (attribute instanceof TLRPC.TL_documentAttributeImageSize) { - photoWidth = attribute.w; - photoHeight = attribute.h; - break; - } - } - float maxHeight = AndroidUtilities.displaySize.y * 0.4f; - float maxWidth; - if (AndroidUtilities.isTablet()) { - maxWidth = AndroidUtilities.getMinTabletSide() * 0.5f; - } else { - maxWidth = AndroidUtilities.displaySize.x * 0.5f; - } - if (photoWidth == 0) { - photoHeight = (int) maxHeight; - photoWidth = photoHeight + AndroidUtilities.dp(100); - } - if (photoHeight > maxHeight) { - photoWidth *= maxHeight / photoHeight; - photoHeight = (int) maxHeight; - } - if (photoWidth > maxWidth) { - photoHeight *= maxWidth / photoWidth; - photoWidth = (int) maxWidth; - } - backgroundWidth = photoWidth + AndroidUtilities.dp(12); - currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 80); - photoImage.setNeedsQualityThumb(false); - photoImage.setShouldGenerateQualityThumb(false); - photoImage.setParentMessageObject(null); - if (messageObject.messageOwner.attachPath != null && messageObject.messageOwner.attachPath.length() > 0) { - File f = new File(messageObject.messageOwner.attachPath); - if (f.exists()) { - photoImage.setImage(null, messageObject.messageOwner.attachPath, - String.format(Locale.US, "%d_%d", photoWidth, photoHeight), - null, - currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, - "b1", - messageObject.messageOwner.media.document.size, "webp", true); - } - } else if (messageObject.messageOwner.media.document.id != 0) { - photoImage.setImage(messageObject.messageOwner.media.document, null, - String.format(Locale.US, "%d_%d", photoWidth, photoHeight), - null, - currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, - "b1", - messageObject.messageOwner.media.document.size, "webp", true); - } - radialProgress.setSizeAndType(messageObject.messageOwner.media.document.size, messageObject.type); //plus - } else { - if (AndroidUtilities.isTablet()) { - photoWidth = (int) (AndroidUtilities.getMinTabletSide() * 0.7f); - } else { - //photoWidth = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.7f); - photoWidth = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.68f); - } - //Log.e("ChatMediaCell","photoWidth 1 "+photoWidth + " drawShareButton " + drawShareButton); - photoHeight = photoWidth + AndroidUtilities.dp(100); - - if (photoWidth > AndroidUtilities.getPhotoSize()) { - photoWidth = AndroidUtilities.getPhotoSize(); - } - if (photoHeight > AndroidUtilities.getPhotoSize()) { - photoHeight = AndroidUtilities.getPhotoSize(); - } - //Log.e("ChatMediaCell","photoWidth 2 "+photoWidth); - if (messageObject.type == 1) { - photoImage.setNeedsQualityThumb(false); - photoImage.setShouldGenerateQualityThumb(false); - photoImage.setParentMessageObject(null); - currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 80); - } else if (messageObject.type == 3) { - photoImage.setNeedsQualityThumb(true); - photoImage.setShouldGenerateQualityThumb(true); - photoImage.setParentMessageObject(messageObject); - } else if (messageObject.type == 8) { - photoImage.setNeedsQualityThumb(true); - photoImage.setShouldGenerateQualityThumb(true); - photoImage.setParentMessageObject(messageObject); - } - //8 - gif, 1 - photo, 3 - video - - if (messageObject.caption != null) { - media = false; - } - - currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); - - int w = 0; - int h = 0; - - if (currentPhotoObject != null && currentPhotoObject == currentPhotoObjectThumb) { - currentPhotoObjectThumb = null; - } - - if (currentPhotoObject != null) { - float scale = (float) currentPhotoObject.w / (float) photoWidth; - w = (int) (currentPhotoObject.w / scale); - h = (int) (currentPhotoObject.h / scale); - if (w == 0) { - if (messageObject.type == 3) { - w = infoWidth + infoOffset + AndroidUtilities.dp(16); - } else { - w = AndroidUtilities.dp(100); - } - } - if (h == 0) { - h = AndroidUtilities.dp(100); - } - if (h > photoHeight) { - float scale2 = h; - h = photoHeight; - scale2 /= h; - w = (int) (w / scale2); - } else if (h < AndroidUtilities.dp(120)) { - h = AndroidUtilities.dp(120); - float hScale = (float) currentPhotoObject.h / h; - if (currentPhotoObject.w / hScale < photoWidth) { - w = (int) (currentPhotoObject.w / hScale); - } - } - } - - if ((w == 0 || h == 0) && messageObject.type == 8) { - for (int a = 0; a < messageObject.messageOwner.media.document.attributes.size(); a++) { - TLRPC.DocumentAttribute attribute = messageObject.messageOwner.media.document.attributes.get(a); - if (attribute instanceof TLRPC.TL_documentAttributeImageSize || attribute instanceof TLRPC.TL_documentAttributeVideo) { - float scale = (float) attribute.w / (float) photoWidth; - w = (int) (attribute.w / scale); - h = (int) (attribute.h / scale); - if (h > photoHeight) { - float scale2 = h; - h = photoHeight; - scale2 /= h; - w = (int) (w / scale2); - } else if (h < AndroidUtilities.dp(120)) { - h = AndroidUtilities.dp(120); - float hScale = (float) attribute.h / h; - if (attribute.w / hScale < photoWidth) { - w = (int) (attribute.w / hScale); - } - } - break; - } - } - } - - - if (w == 0 || h == 0) { - w = h = AndroidUtilities.dp(100); - } - - measureTime(messageObject); - int timeWidthTotal = timeWidth + AndroidUtilities.dp(14 + (messageObject.isOutOwner() ? 20 : 0)); - if (w < timeWidthTotal) { - w = timeWidthTotal; - } - - if (messageObject.isSecretPhoto()) { - if (AndroidUtilities.isTablet()) { - w = h = (int) (AndroidUtilities.getMinTabletSide() * 0.5f); - } else { - w = h = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.5f); - } - } - - photoWidth = w; - photoHeight = h; - backgroundWidth = w + AndroidUtilities.dp(12); - if (!media) { - backgroundWidth += AndroidUtilities.dp(9); - } - if (messageObject.caption != null) { - try { - if(messageObject.isOutOwner()){ //fix caption color bug - MessageObject.textPaint = MessageObject.textPaintRight; - }else{ - MessageObject.textPaint = MessageObject.textPaintLeft; - } - nameLayout = new StaticLayout(messageObject.caption, MessageObject.textPaint, photoWidth - AndroidUtilities.dp(10), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - if (nameLayout != null && nameLayout.getLineCount() > 0) { - captionHeight = nameLayout.getHeight(); - additionHeight += captionHeight + AndroidUtilities.dp(9); - float lastLineWidth = nameLayout.getLineWidth(nameLayout.getLineCount() - 1) + nameLayout.getLineLeft(nameLayout.getLineCount() - 1); - if (photoWidth - AndroidUtilities.dp(8) - lastLineWidth < timeWidthTotal) { - additionHeight += AndroidUtilities.dp(14); - } - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - //Log.e("ChatMediaCell","backgroundWidth: " + backgroundWidth); - currentPhotoFilter = String.format(Locale.US, "%d_%d", (int) (w / AndroidUtilities.density), (int) (h / AndroidUtilities.density)); - if (messageObject.photoThumbs != null && messageObject.photoThumbs.size() > 1 || messageObject.type == 3 || messageObject.type == 8) { - if (messageObject.isSecretPhoto()) { - currentPhotoFilter += "_b2"; - } else { - currentPhotoFilter += "_b"; - } - } - - boolean noSize = false; - if (messageObject.type == 3 || messageObject.type == 8) { - noSize = true; - } - if (currentPhotoObject != null && !noSize && currentPhotoObject.size == 0) { - currentPhotoObject.size = -1; - } - - if (messageObject.type == 1) { - if (currentPhotoObject != null) { - String fileName = FileLoader.getAttachFileName(currentPhotoObject); - boolean photoExist = true; - File cacheFile = FileLoader.getPathToMessage(messageObject.messageOwner); - if (!cacheFile.exists()) { - photoExist = false; - } else { - MediaController.getInstance().removeLoadingFileObserver(this); - } - - if (photoExist || MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_PHOTO) || FileLoader.getInstance().isLoadingFile(fileName)) { - if (allowedToSetPhoto || ImageLoader.getInstance().getImageFromMemory(currentPhotoObject.location, null, currentPhotoFilter) != null) { - allowedToSetPhoto = true; - photoImage.setImage(currentPhotoObject.location, currentPhotoFilter, currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, currentPhotoFilter, noSize ? 0 : currentPhotoObject.size, null, false); - } else if (currentPhotoObjectThumb != null) { - photoImage.setImage(null, null, currentPhotoObjectThumb.location, currentPhotoFilter, 0, null, false); - } else { - photoImage.setImageBitmap((Drawable) null); - } - } else { - photoNotSet = true; - if (currentPhotoObjectThumb != null) { - photoImage.setImage(null, null, currentPhotoObjectThumb.location, currentPhotoFilter, 0, null, false); - } else { - photoImage.setImageBitmap((Drawable) null); - } - } - } else { - photoImage.setImageBitmap((Bitmap) null); - } - } else if (messageObject.type == 8) { - String fileName = FileLoader.getAttachFileName(messageObject.messageOwner.media.document); - File cacheFile = null; - boolean localFile = false; - if (messageObject.messageOwner.attachPath != null && messageObject.messageOwner.attachPath.length() != 0) { - cacheFile = new File(messageObject.messageOwner.attachPath); - if (!cacheFile.exists()) { - cacheFile = null; - } else { - MediaController.getInstance().removeLoadingFileObserver(this); - localFile = true; - } - } - if (cacheFile == null) { - cacheFile = FileLoader.getPathToMessage(messageObject.messageOwner); - if (!cacheFile.exists()) { - cacheFile = null; - } - } - if (!messageObject.isSending() && (cacheFile != null || MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_GIF) && MessageObject.isNewGifDocument(messageObject.messageOwner.media.document) || FileLoader.getInstance().isLoadingFile(fileName))) { - if (localFile) { - photoImage.setImage(null, messageObject.isSendError() ? null : cacheFile.getAbsolutePath(), null, null, currentPhotoObject != null ? currentPhotoObject.location : null, currentPhotoFilter, 0, null, false); - } else { - photoImage.setImage(messageObject.messageOwner.media.document, null, currentPhotoObject != null ? currentPhotoObject.location : null, currentPhotoFilter, messageObject.messageOwner.media.document.size, null, false); - } - } else { - photoNotSet = true; - photoImage.setImage(null, null, currentPhotoObject != null ? currentPhotoObject.location : null, currentPhotoFilter, 0, null, false); - } - } else { - photoImage.setImage(null, null, currentPhotoObject != null ? currentPhotoObject.location : null, currentPhotoFilter, 0, null, false); - } - } - - super.setMessageObject(messageObject); - - if (drawForwardedName) { - namesOffset += AndroidUtilities.dp(5); - } else if (drawName && messageObject.messageOwner.reply_to_msg_id == 0) { - namesOffset += AndroidUtilities.dp(7); - } - - invalidate(); - } - updateButtonState(dataChanged); - } - - @Override - protected int getMaxNameWidth() { - return backgroundWidth - AndroidUtilities.dp(14); - } - - @Override - public ImageReceiver getPhotoImage() { - return photoImage; - } - - public void updateButtonState(boolean animated) { - String fileName = null; - File cacheFile = null; - if (currentMessageObject.type == 1) { - if (currentPhotoObject == null) { - return; - } - //fileName = FileLoader.getAttachFileName(currentPhotoObject); - fileName = FileLoader.getAttachFileName(currentPhotoObject, null, currentMessageObject.isOutOwner()); - cacheFile = FileLoader.getPathToMessage(currentMessageObject.messageOwner); - } else if (currentMessageObject.type == 8 || currentMessageObject.type == 3 || currentMessageObject.type == 9) { - if (currentMessageObject.messageOwner.attachPath != null && currentMessageObject.messageOwner.attachPath.length() != 0) { - File f = new File(currentMessageObject.messageOwner.attachPath); - if (f.exists()) { - fileName = currentMessageObject.messageOwner.attachPath; - cacheFile = f; - } - } - if (fileName == null) { - if (!currentMessageObject.isSendError()) { - fileName = currentMessageObject.getFileName(); - cacheFile = FileLoader.getPathToMessage(currentMessageObject.messageOwner); - } - } - } - if (fileName == null || fileName.length() == 0) { - radialProgress.setBackground(null, false, false); - return; - } - if (currentMessageObject.isOut() && currentMessageObject.isSending()) { - if (currentMessageObject.messageOwner.attachPath != null && currentMessageObject.messageOwner.attachPath.length() > 0) { - MediaController.getInstance().addLoadingFileObserver(currentMessageObject.messageOwner.attachPath, this); - boolean needProgress = currentMessageObject.messageOwner.attachPath == null || !currentMessageObject.messageOwner.attachPath.startsWith("http"); - HashMap params = currentMessageObject.messageOwner.params; - if (currentMessageObject.messageOwner.message != null && params != null && (params.containsKey("url") || params.containsKey("bot"))) { - needProgress = false; - buttonState = -1; - } else { - buttonState = 1; - } - radialProgress.setBackground(getDrawableForCurrentState(), needProgress, animated); - if (needProgress) { - Float progress = ImageLoader.getInstance().getFileProgress(currentMessageObject.messageOwner.attachPath); - if (progress == null && SendMessagesHelper.getInstance().isSendingMessage(currentMessageObject.getId())) { - progress = 1.0f; - } - radialProgress.setProgress(progress != null ? progress : 0, false); - } else { - radialProgress.setProgress(0, false); - } - invalidate(); - } - } else { - if (currentMessageObject.messageOwner.attachPath != null && currentMessageObject.messageOwner.attachPath.length() != 0) { - MediaController.getInstance().removeLoadingFileObserver(this); - } - if (cacheFile.exists() && cacheFile.length() == 0) { - cacheFile.delete(); - } - if (!cacheFile.exists()) { - MediaController.getInstance().addLoadingFileObserver(fileName, this); - float setProgress = 0; - boolean progressVisible = false; - if (!FileLoader.getInstance().isLoadingFile(fileName)) { - if (!cancelLoading && - (currentMessageObject.type == 1 && MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_PHOTO) || - currentMessageObject.type == 8 && MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_GIF) && MessageObject.isNewGifDocument(currentMessageObject.messageOwner.media.document)) ) { - progressVisible = true; - buttonState = 1; - } else { - buttonState = 0; - } - } else { - progressVisible = true; - buttonState = 1; - Float progress = ImageLoader.getInstance().getFileProgress(fileName); - setProgress = progress != null ? progress : 0; - } - radialProgress.setProgress(setProgress, false); - radialProgress.setBackground(getDrawableForCurrentState(), progressVisible, animated); - invalidate(); - } else { - MediaController.getInstance().removeLoadingFileObserver(this); - if (currentMessageObject.type == 8 && !photoImage.isAllowStartAnimation()) { - buttonState = 2; - } else if (currentMessageObject.type == 3) { - buttonState = 3; - } else { - buttonState = -1; - } - radialProgress.setBackground(getDrawableForCurrentState(), false, animated); - if (photoNotSet) { - setMessageObject(currentMessageObject); - } - invalidate(); - } - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), photoHeight + AndroidUtilities.dp(14) + namesOffset + additionHeight); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - - int x; - if (currentMessageObject.isOutOwner()) { - if (media) { - //x = layoutWidth - backgroundWidth - AndroidUtilities.dp(3); - x = layoutWidth - backgroundWidth - AndroidUtilities.dp(3) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); - } else { - //x = layoutWidth - backgroundWidth + AndroidUtilities.dp(6); - x = layoutWidth - backgroundWidth + AndroidUtilities.dp(6) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); - } - } else { - if ((isChat || showAvatar) && currentMessageObject.messageOwner.from_id > 0) { - //x = AndroidUtilities.dp(67); - x = AndroidUtilities.dp(leftBound + 15); - } else { - x = AndroidUtilities.dp(15); - } - } - photoImage.setImageCoords(x, AndroidUtilities.dp(7) + namesOffset, photoWidth, photoHeight); - int size = AndroidUtilities.dp(48); - buttonX = (int) (x + (photoWidth - size) / 2.0f); - buttonY = (int) (AndroidUtilities.dp(7) + (photoHeight - size) / 2.0f) + namesOffset; - - radialProgress.setProgressRect(buttonX, buttonY, buttonX + AndroidUtilities.dp(48), buttonY + AndroidUtilities.dp(48)); - deleteProgressRect.set(buttonX + AndroidUtilities.dp(3), buttonY + AndroidUtilities.dp(3), buttonX + AndroidUtilities.dp(45), buttonY + AndroidUtilities.dp(45)); - } - - private void updateSecretTimeText(MessageObject messageObject) { - if (messageObject == null || messageObject.isOut()) { - return; - } - String str = messageObject.getSecretTimeString(); - if (str == null) { - infoLayout = null; - return; - } - if (currentInfoString == null || !currentInfoString.equals(str)) { - currentInfoString = str; - infoOffset = 0; - infoWidth = (int) Math.ceil(infoPaint.measureText(currentInfoString)); - CharSequence str2 = TextUtils.ellipsize(currentInfoString, infoPaint, infoWidth, TextUtils.TruncateAt.END); - infoLayout = new StaticLayout(str2, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - invalidate(); - } - } - - public void setAllowedToSetPhoto(boolean value) { - if (allowedToSetPhoto == value) { - return; - } - if (currentMessageObject != null && currentMessageObject.type == 1) { - allowedToSetPhoto = value; - if (value) { - MessageObject temp = currentMessageObject; - currentMessageObject = null; - setMessageObject(temp); - } - } - } - - @Override - protected void onAfterBackgroundDraw(Canvas canvas) { - photoImage.setPressed(isDrawSelectedBackground()); - photoImage.setVisible(!PhotoViewer.getInstance().isShowingImage(currentMessageObject), false); - boolean imageDrawn = photoImage.draw(canvas); - drawTime = photoImage.getVisible(); - - radialProgress.setHideCurrentDrawable(false); - SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - if (currentMessageObject.type == 9) { - Drawable menuDrawable; - int color = themePrefs.getInt("chatRTextColor", 0xff000000); - if (currentMessageObject.isOutOwner()) { - //infoPaint.setColor(0xff70b15c); - infoPaint.setColor(color); - docBackPaint.setColor(0xffdaf5c3); - ResourceLoader.docMenuDrawable[0].setColorFilter(themePrefs.getInt("chatRTimeColor", AndroidUtilities.getIntDarkerColor("themeColor", 0x15)), PorterDuff.Mode.SRC_IN); - menuDrawable = ResourceLoader.docMenuDrawable[0]; - namePaint.setColor(color); - } else { - //infoPaint.setColor(0xffa1adbb); - color = themePrefs.getInt("chatLTextColor", 0xff000000); - infoPaint.setColor(color); - docBackPaint.setColor(0xffebf0f5); - ResourceLoader.docMenuDrawable[1].setColorFilter(themePrefs.getInt("chatLTimeColor", 0xffa1adbb), PorterDuff.Mode.SRC_IN); - menuDrawable = ResourceLoader.docMenuDrawable[1]; - namePaint.setColor(color); - } - - setDrawableBounds(menuDrawable, photoImage.getImageX() + backgroundWidth - AndroidUtilities.dp(44), AndroidUtilities.dp(10) + namesOffset); - menuDrawable.draw(canvas); - - if (buttonState >= 0 && buttonState < 4) { - if (!imageDrawn) { - if (buttonState == 1 && !currentMessageObject.isSending()) { - radialProgress.swapBackground(ResourceLoader.buttonStatesDrawablesDoc[2][currentMessageObject.isOutOwner() ? 1 : (isDrawSelectedBackground() ? 2 : 0)]); - } else { - radialProgress.swapBackground(ResourceLoader.buttonStatesDrawablesDoc[buttonState][currentMessageObject.isOutOwner() ? 1 : (isDrawSelectedBackground() ? 2 : 0)]); - } - } else { - if (buttonState == 1 && !currentMessageObject.isSending()) { - radialProgress.swapBackground(ResourceLoader.buttonStatesDrawables[4]); - } else { - radialProgress.swapBackground(ResourceLoader.buttonStatesDrawables[buttonState]); - } - } - } - - if (!imageDrawn) { - canvas.drawRect(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX() + photoImage.getImageWidth(), photoImage.getImageY() + photoImage.getImageHeight(), docBackPaint); - if (currentMessageObject.isOutOwner()) { - radialProgress.setProgressColor(0xff81bd72); - } else { - radialProgress.setProgressColor(isDrawSelectedBackground() ? 0xff83b2c2 : 0xffadbdcc); - } - } else { - if (buttonState == -1) { - radialProgress.setHideCurrentDrawable(true); - } - radialProgress.setProgressColor(0xffffffff); - } - } else { - radialProgress.setProgressColor(0xffffffff); - } - - if (buttonState == -1 && currentMessageObject.isSecretPhoto()) { - int drawable = 5; - if (currentMessageObject.messageOwner.destroyTime != 0) { - if (currentMessageObject.isOutOwner()) { - drawable = 7; - } else { - drawable = 6; - } - } - setDrawableBounds(ResourceLoader.buttonStatesDrawables[drawable], buttonX, buttonY); - ResourceLoader.buttonStatesDrawables[drawable].setAlpha((int) (255 * (1.0f - radialProgress.getAlpha()))); - ResourceLoader.buttonStatesDrawables[drawable].draw(canvas); - if (!currentMessageObject.isOutOwner() && currentMessageObject.messageOwner.destroyTime != 0) { - long msTime = System.currentTimeMillis() + ConnectionsManager.getInstance().getTimeDifference() * 1000; - float progress = Math.max(0, (long) currentMessageObject.messageOwner.destroyTime * 1000 - msTime) / (currentMessageObject.messageOwner.ttl * 1000.0f); - canvas.drawArc(deleteProgressRect, -90, -360 * progress, true, deleteProgressPaint); - if (progress != 0) { - int offset = AndroidUtilities.dp(2); - invalidate((int) deleteProgressRect.left - offset, (int) deleteProgressRect.top - offset, (int) deleteProgressRect.right + offset * 2, (int) deleteProgressRect.bottom + offset * 2); - } - updateSecretTimeText(currentMessageObject); - } - } - - radialProgress.draw(canvas); - try{ - if(themePrefs.getBoolean("chatMemberColorCheck", false)){ - senderPaint.setColor(themePrefs.getInt("chatMemberColor", AndroidUtilities.getIntDarkerColor("themeColor", 0x15))); - }else{ - if (currentMessageObject != null && currentMessageObject.messageOwner.from_id > 0) { - senderPaint.setColor(AvatarDrawable.getNameColorForId(MessagesController.getInstance().getUser(currentMessageObject.messageOwner.from_id).id)); - } - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - if (currentMessageObject.type == 1 || currentMessageObject.type == 3) {//1: photo 3: video - if (nameLayout != null) { - canvas.save(); - canvas.translate(captionX = photoImage.getImageX() + AndroidUtilities.dp(5), captionY = photoImage.getImageY() + photoHeight + AndroidUtilities.dp(6)); - if (pressedLink != null) { - canvas.drawPath(urlPath, urlPaint); - } - try { - nameLayout.draw(canvas); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - canvas.restore(); - } - //if (infoLayout != null && (buttonState == 1 || buttonState == 0 || buttonState == 3 || currentMessageObject.isSecretPhoto())) { - if (infoLayout != null && (buttonState == 1 || buttonState == 0 || buttonState == 3 || currentMessageObject.isSecretPhoto() || currentMessageObject.type == 1)) { - infoPaint.setColor(0xffffffff); - if (currentMessageObject.type == 1){ - setDrawableBounds(ResourceLoader.mediaBackgroundDrawable, photoImage.getImageX() + AndroidUtilities.dp(4), photoImage.getImageY() + AndroidUtilities.dp(4), infoWidth + AndroidUtilities.dp(8) + infoOffset, AndroidUtilities.dp(20)); - } else if (currentMessageObject.type == 3){ - setDrawableBounds(ResourceLoader.mediaBackgroundDrawable, photoImage.getImageX() + AndroidUtilities.dp(4), photoImage.getImageY() + AndroidUtilities.dp(4), infoWidth + AndroidUtilities.dp(8) + (isChat ? infoOffset2 : infoOffset), AndroidUtilities.dp(isChat ? 35 : 16.5f)); - } else{ - setDrawableBounds(ResourceLoader.mediaBackgroundDrawable, photoImage.getImageX() + AndroidUtilities.dp(4), photoImage.getImageY() + AndroidUtilities.dp(4), infoWidth + AndroidUtilities.dp(8) + infoOffset, AndroidUtilities.dp(16.5f)); - } - ResourceLoader.mediaBackgroundDrawable.draw(canvas); - - if (currentMessageObject.type == 3) { - //setDrawableBounds(ResourceLoader.videoIconDrawable, photoImage.getImageX() + AndroidUtilities.dp(8), photoImage.getImageY() + AndroidUtilities.dp(7.5f)); - if (infoLayout2 != null) { - setDrawableBounds(ResourceLoader.videoIconDrawable, photoImage.getImageX() + AndroidUtilities.dp(8), 2*(photoImage.getImageY() + AndroidUtilities.dp(10))); - }else{ - setDrawableBounds(ResourceLoader.videoIconDrawable, photoImage.getImageX() + AndroidUtilities.dp(8), photoImage.getImageY() + AndroidUtilities.dp(8)); - } - ResourceLoader.videoIconDrawable.draw(canvas); - } - - canvas.save(); - canvas.translate(photoImage.getImageX() + AndroidUtilities.dp(8) + infoOffset, photoImage.getImageY() + AndroidUtilities.dp(5.5f)); - infoLayout.draw(canvas); - if (infoLayout2 != null) { - canvas.translate(infoOffset2, photoImage.getImageY() + AndroidUtilities.dp(12)); - infoLayout2.draw(canvas); - } - canvas.restore(); - } - } else if (currentMessageObject.type == 4) { - if (nameLayout != null) { - locationAddressPaint.setColor(currentMessageObject.isOutOwner() ? 0xff70b15c : (isDrawSelectedBackground() ? 0xff89b4c1 : 0xff999999)); - - canvas.save(); - canvas.translate(nameOffsetX + photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(10), photoImage.getImageY() + AndroidUtilities.dp(3)); - nameLayout.draw(canvas); - canvas.restore(); - - if (infoLayout != null) { - canvas.save(); - canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(10), photoImage.getImageY() + AndroidUtilities.dp(nameLayout.getLineCount() * 16 + 5)); - infoLayout.draw(canvas); - canvas.restore(); - } - } - } else if (currentMessageObject.type == 8) { - if (nameLayout != null) { - if (infoLayout2 != null) { - canvas.save(); - canvas.translate(captionX = photoImage.getImageX() + AndroidUtilities.dp(5), captionY = photoImage.getImageY() + photoHeight + AndroidUtilities.dp(6)); - infoLayout2.draw(canvas); - canvas.restore(); - } - if (pressedLink != null) { - canvas.drawPath(urlPath, urlPaint); - } - - canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(10), photoImage.getImageY() + AndroidUtilities.dp(30));//8 - try { - nameLayout.draw(canvas); - canvas.restore(); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - - if (infoLayout != null) { - canvas.save(); - canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(10), photoImage.getImageY() + AndroidUtilities.dp(50));//30 - infoLayout.draw(canvas); - canvas.restore(); - } - } - } else if (nameLayout != null) { - canvas.save(); - canvas.translate(nameOffsetX + photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(10), photoImage.getImageY() + AndroidUtilities.dp(8)); - nameLayout.draw(canvas); - canvas.restore(); - - if (infoLayout != null) { - canvas.save(); - canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(10), photoImage.getImageY() + AndroidUtilities.dp(30)); - infoLayout.draw(canvas); - canvas.restore(); - } - } - } - - @Override - public void onFailedDownload(String fileName) { - updateButtonState(false); - } - - @Override - public void onSuccessDownload(String fileName) { - radialProgress.setProgress(1, true); - if (!photoNotSet || currentMessageObject.type == 8 && currentMessageObject.audioProgress != 1) { - if (currentMessageObject.type == 8 && currentMessageObject.audioProgress != 1) { - photoNotSet = false; - buttonState = 2; - didPressedButton(true); - } else { - updateButtonState(true); - } - } - if (photoNotSet) { - setMessageObject(currentMessageObject); - } - } - - @Override - public void onProgressDownload(String fileName, float progress) { - radialProgress.setProgress(progress, true); - if (buttonState != 1) { - updateButtonState(false); - } - } - - @Override - public void onProgressUpload(String fileName, float progress, boolean isEncrypted) { - radialProgress.setProgress(progress, true); - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java index 03f683d5..2ed1bc85 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatMessageCell.java @@ -1,5 +1,5 @@ /* - * This is the source code of Telegram for Android v. 1.3.x. + * This is the source code of Telegram for Android v. 3.x.x. * It is licensed under GNU GPL v. 2 or later. * You should have received a copy of the license in this archive (see LICENSE). * @@ -9,14 +9,15 @@ package org.telegram.ui.Cells; import android.content.Context; -import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.net.Uri; import android.os.Build; -import android.provider.Browser; import android.text.Layout; import android.text.Spannable; import android.text.SpannableStringBuilder; @@ -24,284 +25,907 @@ import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; import android.text.style.ClickableSpan; +import android.text.style.URLSpan; import android.util.Log; +import android.view.Gravity; import android.view.MotionEvent; import android.view.SoundEffectConstants; import android.view.ViewStructure; +import android.widget.Toast; +import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.ImageLoader; -import org.telegram.messenger.ImageReceiver; -import org.telegram.messenger.MediaController; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageLoader; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaController; import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; +import org.telegram.messenger.SendMessagesHelper; +import org.telegram.messenger.UserObject; +import org.telegram.messenger.Utilities; +import org.telegram.messenger.browser.Browser; +import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.LinkPath; import org.telegram.ui.Components.RadialProgress; -import org.telegram.ui.Components.ResourceLoader; +import org.telegram.ui.Components.SeekBar; +import org.telegram.ui.Components.SeekBarWaveform; import org.telegram.ui.Components.StaticLayoutEx; import org.telegram.ui.Components.URLSpanBotCommand; import org.telegram.ui.Components.URLSpanNoUnderline; +import org.telegram.ui.PhotoViewer; import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; import java.util.Locale; -public class ChatMessageCell extends ChatBaseCell { +public class ChatMessageCell extends ChatBaseCell implements SeekBar.SeekBarDelegate, ImageReceiver.ImageReceiverDelegate{ - private int textX, textY; - private int totalHeight = 0; + private final static int DOCUMENT_ATTACH_TYPE_NONE = 0; + private final static int DOCUMENT_ATTACH_TYPE_DOCUMENT = 1; + private final static int DOCUMENT_ATTACH_TYPE_GIF = 2; + private final static int DOCUMENT_ATTACH_TYPE_AUDIO = 3; + private final static int DOCUMENT_ATTACH_TYPE_VIDEO = 4; + private final static int DOCUMENT_ATTACH_TYPE_MUSIC = 5; + private final static int DOCUMENT_ATTACH_TYPE_STICKER = 6; + + private class BotButton { + private int x; + private int y; + private int width; + private int height; + private StaticLayout caption; + private TLRPC.KeyboardButton button; + private int angle; + private float progressAlpha; + private long lastUpdateTime; + } + + private int textX; + private int textY; + private int totalHeight; + private int keyboardHeight; private int linkBlockNum; - private int lastVisibleBlockNum = 0; - private int firstVisibleBlockNum = 0; - private int totalVisibleBlocksCount = 0; + private Rect scrollRect = new Rect(); + + private int lastVisibleBlockNum; + private int firstVisibleBlockNum; + private int totalVisibleBlocksCount; + private boolean needNewVisiblePart; private RadialProgress radialProgress; - private ImageReceiver linkImageView; + private ImageReceiver photoImage; + private AvatarDrawable avatarDrawable; + + private boolean disallowLongPress; + private boolean isSmallImage; private boolean drawImageButton; - private boolean isGifDocument; - private boolean drawLinkImageView; + private int documentAttachType; + private TLRPC.Document documentAttach; + private boolean drawPhotoImage; private boolean hasLinkPreview; private int linkPreviewHeight; - private boolean isInstagram; + private int mediaOffsetY; private int descriptionY; private int durationWidth; private int descriptionX; private int titleX; private int authorX; - private StaticLayout siteNameLayout; + private StaticLayout siteCaptionLayout; private StaticLayout titleLayout; private StaticLayout descriptionLayout; private StaticLayout durationLayout; private StaticLayout authorLayout; - private static TextPaint durationPaint; + //Plus + private StaticLayout infoLayout2; + private int infoWidth2; + private static TextPaint senderPaint; + private int infoOffset2 = 0; + // + private StaticLayout captionLayout; + private int captionX; + private int captionY; + private int captionHeight; + private int nameOffsetX; + + private StaticLayout infoLayout; + private int infoWidth; + + private String currentUrl; + + private boolean allowedToSetPhoto = true; private int buttonX; private int buttonY; private int buttonState; - private boolean buttonPressed; + private int buttonPressed; + private int otherX; + private int otherY; + private boolean imagePressed; + private boolean otherPressed; private boolean photoNotSet; + private RectF deleteProgressRect = new RectF(); + private RectF rect = new RectF(); private TLRPC.PhotoSize currentPhotoObject; private TLRPC.PhotoSize currentPhotoObjectThumb; private String currentPhotoFilter; private String currentPhotoFilterThumb; private boolean cancelLoading; - private static Drawable igvideoDrawable; + private static TextPaint infoPaint; + private static TextPaint docNamePaint; + private static Paint docBackPaint; + private static Paint deleteProgressPaint; + private static Paint botProgressPaint; + private static TextPaint locationTitlePaint; + private static TextPaint locationAddressPaint; + private static Paint urlPaint; + private static TextPaint durationPaint; + + private ClickableSpan pressedLink; + private int pressedLinkType; + private boolean linkPreviewPressed; + private ArrayList urlPathCache = new ArrayList<>(); + private ArrayList urlPath = new ArrayList<>(); + //private LinkPath urlPath = new LinkPath(); + + private boolean useSeekBarWaweform; + private SeekBar seekBar; + private SeekBarWaveform seekBarWaveform; + private int seekBarX; + private int seekBarY; + + private StaticLayout timeLayout; + private String lastTimeString; + private int timeWidthAudio; + private int timeAudioX; + + private static TextPaint audioTimePaint; + private static TextPaint audioTitlePaint; + private static TextPaint audioPerformerPaint; + private static TextPaint botButtonPaint; + private static TextPaint contactNamePaint; + private static TextPaint contactPhonePaint; + + private StaticLayout songLayout; + private int songX; + + private StaticLayout performerLayout; + private int performerX; + + private ArrayList botButtons = new ArrayList<>(); + private HashMap botButtonsByData = new HashMap<>(); + private int widthForButtons; + private int pressedBotButton; public ChatMessageCell(Context context) { super(context); - drawForwardedName = true; - linkImageView = new ImageReceiver(this); + avatarDrawable = new AvatarDrawable(); + photoImage = new ImageReceiver(this); + photoImage.setDelegate(this); + radialProgress = new RadialProgress(this); + seekBar = new SeekBar(context); + seekBar.setDelegate(this); + seekBarWaveform = new SeekBarWaveform(context); + seekBarWaveform.setDelegate(this); + seekBarWaveform.setParentView(this); + + if (infoPaint == null) { + infoPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + infoPaint.setTextSize(AndroidUtilities.dp(12)); + + docNamePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + docNamePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + docNamePaint.setTextSize(AndroidUtilities.dp(15)); + + docBackPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + deleteProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + deleteProgressPaint.setColor(Theme.MSG_SECRET_TIME_TEXT_COLOR); + + botProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + botProgressPaint.setColor(Theme.MSG_BOT_PROGRESS_COLOR); + botProgressPaint.setStrokeCap(Paint.Cap.ROUND); + botProgressPaint.setStyle(Paint.Style.STROKE); + botProgressPaint.setStrokeWidth(AndroidUtilities.dp(2)); + + locationTitlePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + locationTitlePaint.setTextSize(AndroidUtilities.dp(15)); + locationTitlePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + + locationAddressPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + locationAddressPaint.setTextSize(AndroidUtilities.dp(13)); + + urlPaint = new Paint(); + urlPaint.setColor(Theme.MSG_LINK_SELECT_BACKGROUND_COLOR); + + audioTimePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); + audioTimePaint.setTextSize(AndroidUtilities.dp(12)); + + audioTitlePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + audioTitlePaint.setTextSize(AndroidUtilities.dp(16)); + audioTitlePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + + audioPerformerPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + audioPerformerPaint.setTextSize(AndroidUtilities.dp(15)); + + botButtonPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + botButtonPaint.setTextSize(AndroidUtilities.dp(15)); + botButtonPaint.setColor(Theme.MSG_BOT_BUTTON_TEXT_COLOR); + botButtonPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + + contactNamePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + contactNamePaint.setTextSize(AndroidUtilities.dp(15)); + contactNamePaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + + contactPhonePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + contactPhonePaint.setTextSize(AndroidUtilities.dp(13)); + + durationPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + durationPaint.setTextSize(AndroidUtilities.dp(12)); + durationPaint.setColor(Theme.MSG_WEB_PREVIEW_DURATION_TEXT_COLOR); + + senderPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + senderPaint.setColor(0xffffffff); + senderPaint.setTextSize(AndroidUtilities.dp(15)); + } + radialProgress = new RadialProgress(this); } - @Override - public boolean onTouchEvent(MotionEvent event) { - boolean result = false; - if (currentMessageObject != null && currentMessageObject.textLayoutBlocks != null && !currentMessageObject.textLayoutBlocks.isEmpty() && currentMessageObject.messageText instanceof Spannable && delegate.canPerformActions()) { - if (event.getAction() == MotionEvent.ACTION_DOWN || (linkPreviewPressed || pressedLink != null || buttonPressed) && event.getAction() == MotionEvent.ACTION_UP) { - int x = (int) event.getX(); - int y = (int) event.getY(); - if (x >= textX && y >= textY && x <= textX + currentMessageObject.textWidth && y <= textY + currentMessageObject.textHeight) { - y -= textY; - int blockNum = Math.max(0, y / currentMessageObject.blockHeight); - if (blockNum < currentMessageObject.textLayoutBlocks.size()) { - try { - MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(blockNum); - x -= textX - (int) Math.ceil(block.textXOffset); - y -= block.textYOffset; - final int line = block.textLayout.getLineForVertical(y); - final int off = block.textLayout.getOffsetForHorizontal(line, x) + block.charactersOffset; + private void resetPressedLink(int type) { + if (pressedLink == null || pressedLinkType != type && type != -1) { + return; + } + resetUrlPaths(); + pressedLink = null; + pressedLinkType = -1; + invalidate(); + } - final float left = block.textLayout.getLineLeft(line); - if (left <= x && left + block.textLayout.getLineWidth(line) >= x) { - Spannable buffer = (Spannable) currentMessageObject.messageText; - ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); - boolean ignore = false; - if (link.length == 0 || link.length != 0 && link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { - ignore = true; - } - if (!ignore) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - resetPressedLink(); - pressedLink = link[0]; - linkBlockNum = blockNum; - try { - int start = buffer.getSpanStart(pressedLink) - block.charactersOffset; - urlPath.setCurrentLayout(block.textLayout, start); - block.textLayout.getSelectionPath(start, buffer.getSpanEnd(pressedLink) - block.charactersOffset, urlPath); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - result = true; - } else { - if (link[0] == pressedLink) { - try { - delegate.didPressUrl(currentMessageObject, pressedLink, false); - } catch (Exception e) { - FileLog.e("tmessages", e); + private void resetUrlPaths() { + if (urlPath.isEmpty()) { + return; + } + urlPathCache.addAll(urlPath); + urlPath.clear(); + } + + private LinkPath obtainNewUrlPath() { + LinkPath linkPath; + if (!urlPathCache.isEmpty()) { + linkPath = urlPathCache.get(0); + urlPathCache.remove(0); + } else { + linkPath = new LinkPath(); + } + urlPath.add(linkPath); + return linkPath; + } + + private boolean checkTextBlockMotionEvent(MotionEvent event) { + if (currentMessageObject.type != 0 || currentMessageObject.textLayoutBlocks == null || currentMessageObject.textLayoutBlocks.isEmpty() || !(currentMessageObject.messageText instanceof Spannable)) { + return false; + } + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP && pressedLinkType == 1) { + int x = (int) event.getX(); + int y = (int) event.getY(); + if (x >= textX && y >= textY && x <= textX + currentMessageObject.textWidth && y <= textY + currentMessageObject.textHeight) { + y -= textY; + int blockNum = 0; + for (int a = 0; a < currentMessageObject.textLayoutBlocks.size(); a++) { + if (currentMessageObject.textLayoutBlocks.get(a).textYOffset > y) { + break; + } + blockNum = a; + } + try { + MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(blockNum); + x -= textX - (int) Math.ceil(block.textXOffset); + y -= block.textYOffset; + final int line = block.textLayout.getLineForVertical(y); + final int off = block.textLayout.getOffsetForHorizontal(line, x) + block.charactersOffset; + + final float left = block.textLayout.getLineLeft(line); + if (left <= x && left + block.textLayout.getLineWidth(line) >= x) { + Spannable buffer = (Spannable) currentMessageObject.messageText; + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + boolean ignore = false; + if (link.length == 0 || link.length != 0 && link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { + ignore = true; + } + if (!ignore) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + pressedLink = link[0]; + linkBlockNum = blockNum; + pressedLinkType = 1; + resetUrlPaths(); + try { + LinkPath path = obtainNewUrlPath(); + int start = buffer.getSpanStart(pressedLink) - block.charactersOffset; + int end = buffer.getSpanEnd(pressedLink); + int length = block.textLayout.getText().length(); + path.setCurrentLayout(block.textLayout, start, 0); + block.textLayout.getSelectionPath(start, end - block.charactersOffset, path); + if (end >= block.charactersOffset + length) { + for (int a = blockNum + 1; a < currentMessageObject.textLayoutBlocks.size(); a++) { + MessageObject.TextLayoutBlock nextBlock = currentMessageObject.textLayoutBlocks.get(a); + length = nextBlock.textLayout.getText().length(); + ClickableSpan[] nextLink = buffer.getSpans(nextBlock.charactersOffset, nextBlock.charactersOffset, ClickableSpan.class); + if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink) { + break; + } + path = obtainNewUrlPath(); + path.setCurrentLayout(nextBlock.textLayout, 0, nextBlock.height); + nextBlock.textLayout.getSelectionPath(0, end - nextBlock.charactersOffset, path); + if (end < block.charactersOffset + length - 1) { + break; } - resetPressedLink(); - result = true; } } - } else { - resetPressedLink(); - } - } else { - resetPressedLink(); - } - } catch (Exception e) { - resetPressedLink(); - FileLog.e("tmessages", e); - } - } else { - resetPressedLink(); - } - } else if (hasLinkPreview && x >= textX && x <= textX + backgroundWidth && y >= textY + currentMessageObject.textHeight && y <= textY + currentMessageObject.textHeight + linkPreviewHeight + AndroidUtilities.dp(8)) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - resetPressedLink(); - if (drawLinkImageView && linkImageView.isInsideImage(x, y)) { - if (drawImageButton && buttonState != -1 && x >= buttonX && x <= buttonX + AndroidUtilities.dp(48) && y >= buttonY && y <= buttonY + AndroidUtilities.dp(48)) { - buttonPressed = true; - result = true; - } else { - linkPreviewPressed = true; - result = true; - } - if (linkPreviewPressed && isGifDocument && buttonState == -1 && MediaController.getInstance().canAutoplayGifs()) { - linkPreviewPressed = false; - result = false; - } - } else { - if (descriptionLayout != null && y >= descriptionY) { - try { - x -= textX + AndroidUtilities.dp(10) + descriptionX; - y -= descriptionY; - final int line = descriptionLayout.getLineForVertical(y); - final int off = descriptionLayout.getOffsetForHorizontal(line, x); - - final float left = descriptionLayout.getLineLeft(line); - if (left <= x && left + descriptionLayout.getLineWidth(line) >= x) { - Spannable buffer = (Spannable) currentMessageObject.linkDescription; - ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); - boolean ignore = false; - if (link.length == 0 || link.length != 0 && link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { - ignore = true; - } - if (!ignore) { - resetPressedLink(); - pressedLink = link[0]; - linkPreviewPressed = true; - linkBlockNum = -10; - result = true; - try { - int start = buffer.getSpanStart(pressedLink); - urlPath.setCurrentLayout(descriptionLayout, start); - descriptionLayout.getSelectionPath(start, buffer.getSpanEnd(pressedLink), urlPath); - } catch (Exception e) { - FileLog.e("tmessages", e); + if (start < 0) { + for (int a = blockNum - 1; a >= 0; a--) { + MessageObject.TextLayoutBlock nextBlock = currentMessageObject.textLayoutBlocks.get(a); + length = nextBlock.textLayout.getText().length(); + ClickableSpan[] nextLink = buffer.getSpans(nextBlock.charactersOffset + length - 1, nextBlock.charactersOffset + length - 1, ClickableSpan.class); + if (nextLink == null || nextLink.length == 0 || nextLink[0] != pressedLink) { + break; + } + path = obtainNewUrlPath(); + start = buffer.getSpanStart(pressedLink) - nextBlock.charactersOffset; + path.setCurrentLayout(nextBlock.textLayout, start, -nextBlock.height); + nextBlock.textLayout.getSelectionPath(start, buffer.getSpanEnd(pressedLink) - nextBlock.charactersOffset, path); + if (start >= 0) { + break; } - } else { - resetPressedLink(); } - } else { - resetPressedLink(); } } catch (Exception e) { - resetPressedLink(); FileLog.e("tmessages", e); } - } - } - } else if (linkPreviewPressed) { - try { - if (pressedLink != null) { - pressedLink.onClick(this); + invalidate(); + return true; } else { - if (drawImageButton && delegate != null) { - if (isGifDocument) { - if (buttonState == -1) { - buttonState = 2; - currentMessageObject.audioProgress = 1; - linkImageView.setAllowStartAnimation(false); - linkImageView.stopAnimation(); - radialProgress.setBackground(getDrawableForCurrentState(), false, false); - invalidate(); - playSoundEffect(SoundEffectConstants.CLICK); - } else if (buttonState == 2 || buttonState == 0) { - didPressedButton(false); - playSoundEffect(SoundEffectConstants.CLICK); - } - } else if (buttonState == -1) { - delegate.didClickedImage(this); - playSoundEffect(SoundEffectConstants.CLICK); - } - } else { - TLRPC.WebPage webPage = currentMessageObject.messageOwner.media.webpage; - if (Build.VERSION.SDK_INT >= 16 && webPage.embed_url != null && webPage.embed_url.length() != 0) { - delegate.needOpenWebView(webPage.embed_url, webPage.site_name, webPage.url, webPage.embed_width, webPage.embed_height); - } else { - Uri uri = Uri.parse(webPage.url); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, getContext().getPackageName()); - getContext().startActivity(intent); - } + if (link[0] == pressedLink) { + delegate.didPressedUrl(currentMessageObject, pressedLink, false); + resetPressedLink(1); + return true; } } - } catch (Exception e) { - FileLog.e("tmessages", e); } - resetPressedLink(); - result = true; - } else if (buttonPressed) { + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else { + resetPressedLink(1); + } + } + return false; + } + + private boolean checkCaptionMotionEvent(MotionEvent event) { + if (!(currentMessageObject.caption instanceof Spannable) || captionLayout == null) { + return false; + } + if (event.getAction() == MotionEvent.ACTION_DOWN || (linkPreviewPressed || pressedLink != null) && event.getAction() == MotionEvent.ACTION_UP) { + int x = (int) event.getX(); + int y = (int) event.getY(); + if (x >= captionX && x <= captionX + backgroundWidth && y >= captionY && y <= captionY + captionHeight) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + try { + x -= captionX; + y -= captionY; + final int line = captionLayout.getLineForVertical(y); + final int off = captionLayout.getOffsetForHorizontal(line, x); + + final float left = captionLayout.getLineLeft(line); + if (left <= x && left + captionLayout.getLineWidth(line) >= x) { + Spannable buffer = (Spannable) currentMessageObject.caption; + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + boolean ignore = false; + if (link.length == 0 || link.length != 0 && link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { + ignore = true; + } + if (!ignore) { + pressedLink = link[0]; + pressedLinkType = 3; + resetUrlPaths(); + try { + LinkPath path = obtainNewUrlPath(); + int start = buffer.getSpanStart(pressedLink); + path.setCurrentLayout(captionLayout, start, 0); + captionLayout.getSelectionPath(start, buffer.getSpanEnd(pressedLink), path); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + invalidate(); + return true; + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else if (pressedLinkType == 3) { + delegate.didPressedUrl(currentMessageObject, pressedLink, false); + resetPressedLink(3); + return true; + } + } else { + resetPressedLink(3); + } + } + return false; + } + + private boolean checkLinkPreviewMotionEvent(MotionEvent event) { + if (currentMessageObject.type != 0 || !hasLinkPreview) { + return false; + } + int x = (int) event.getX(); + int y = (int) event.getY(); + + if (x >= textX && x <= textX + backgroundWidth && y >= textY + currentMessageObject.textHeight && y <= textY + currentMessageObject.textHeight + linkPreviewHeight + AndroidUtilities.dp(8)) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT && drawPhotoImage && photoImage.isInsideImage(x, y)) { + if (drawImageButton && buttonState != -1 && x >= buttonX && x <= buttonX + AndroidUtilities.dp(48) && y >= buttonY && y <= buttonY + AndroidUtilities.dp(48)) { + buttonPressed = 1; + return true; + } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && buttonState == -1 && MediaController.getInstance().canAutoplayGifs()) { + linkPreviewPressed = false; + return false; + } else { + linkPreviewPressed = true; + return true; + } + } else if (descriptionLayout != null && y >= descriptionY) { + try { + x -= textX + AndroidUtilities.dp(10) + descriptionX; + y -= descriptionY; + final int line = descriptionLayout.getLineForVertical(y); + final int off = descriptionLayout.getOffsetForHorizontal(line, x); + + final float left = descriptionLayout.getLineLeft(line); + if (left <= x && left + descriptionLayout.getLineWidth(line) >= x) { + Spannable buffer = (Spannable) currentMessageObject.linkDescription; + ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); + boolean ignore = false; + if (link.length == 0 || link.length != 0 && link[0] instanceof URLSpanBotCommand && !URLSpanBotCommand.enabled) { + ignore = true; + } + if (!ignore) { + pressedLink = link[0]; + linkBlockNum = -10; + pressedLinkType = 2; + resetUrlPaths(); + try { + LinkPath path = obtainNewUrlPath(); + int start = buffer.getSpanStart(pressedLink); + path.setCurrentLayout(descriptionLayout, start, 0); + descriptionLayout.getSelectionPath(start, buffer.getSpanEnd(pressedLink), path); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + invalidate(); + return true; + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } else if (event.getAction() == MotionEvent.ACTION_UP) { + if (pressedLinkType == 2 || buttonPressed != 0 || linkPreviewPressed) { + if (buttonPressed != 0) { if (event.getAction() == MotionEvent.ACTION_UP) { - buttonPressed = false; + buttonPressed = 0; playSoundEffect(SoundEffectConstants.CLICK); didPressedButton(false); invalidate(); } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { - buttonPressed = false; + buttonPressed = 0; invalidate(); - } else if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (!(x >= buttonX && x <= buttonX + AndroidUtilities.dp(48) && y >= buttonY && y <= buttonY + AndroidUtilities.dp(48))) { - buttonPressed = false; - invalidate(); + } + } else if (pressedLink != null) { + if (pressedLink instanceof URLSpan) { + Browser.openUrl(getContext(), ((URLSpan) pressedLink).getURL()); + } else { + pressedLink.onClick(this); + } + resetPressedLink(2); + } else { + if (drawImageButton) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { + if (buttonState == -1) { + buttonState = 2; + currentMessageObject.audioProgress = 1; + photoImage.setAllowStartAnimation(false); + photoImage.stopAnimation(); + radialProgress.setBackground(getDrawableForCurrentState(), false, false); + invalidate(); + playSoundEffect(SoundEffectConstants.CLICK); + } else if (buttonState == 2 || buttonState == 0) { + didPressedButton(false); + playSoundEffect(SoundEffectConstants.CLICK); + } + } else if (buttonState == -1) { + delegate.didPressedImage(this); + playSoundEffect(SoundEffectConstants.CLICK); + } + } else { + TLRPC.WebPage webPage = currentMessageObject.messageOwner.media.webpage; + if (webPage != null) { + if (Build.VERSION.SDK_INT >= 16 && webPage.embed_url != null && webPage.embed_url.length() != 0) { + delegate.needOpenWebView(webPage.embed_url, webPage.site_name, webPage.description, webPage.url, webPage.embed_width, webPage.embed_height); + } else { + Browser.openUrl(getContext(), webPage.url); + } } } + resetPressedLink(2); + return true; } } else { - resetPressedLink(); + resetPressedLink(2); } - } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { - resetPressedLink(); + } + } + return false; + } + + private boolean checkOtherButtonMotionEvent(MotionEvent event) { + if (documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT && currentMessageObject.type != 12 && documentAttachType != DOCUMENT_ATTACH_TYPE_MUSIC && documentAttachType != DOCUMENT_ATTACH_TYPE_VIDEO) { + return false; + } + + int x = (int) event.getX(); + int y = (int) event.getY(); + + boolean result = false; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (x >= otherX - AndroidUtilities.dp(20) && x <= otherX + AndroidUtilities.dp(20) && y >= otherY - AndroidUtilities.dp(4) && y <= otherY + AndroidUtilities.dp(30)) { + otherPressed = true; + result = true; } } else { - resetPressedLink(); + if (event.getAction() == MotionEvent.ACTION_UP) { + if (otherPressed) { + otherPressed = false; + playSoundEffect(SoundEffectConstants.CLICK); + delegate.didPressedOther(this); + } + } } - if (result && event.getAction() == MotionEvent.ACTION_DOWN) { + return result; + } + + private boolean checkPhotoImageMotionEvent(MotionEvent event) { + if (!drawPhotoImage && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT) { + return false; + } + + int x = (int) event.getX(); + int y = (int) event.getY(); + + boolean result = false; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (buttonState != -1 && x >= buttonX && x <= buttonX + AndroidUtilities.dp(48) && y >= buttonY && y <= buttonY + AndroidUtilities.dp(48)) { + buttonPressed = 1; + invalidate(); + result = true; + } else { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { + if (x >= photoImage.getImageX() && x <= photoImage.getImageX() + backgroundWidth - AndroidUtilities.dp(50) && y >= photoImage.getImageY() && y <= photoImage.getImageY() + photoImage.getImageHeight()) { + imagePressed = true; + result = true; + } + } else if (currentMessageObject.type != 13 || currentMessageObject.getInputStickerSet() != null) { + if (x >= photoImage.getImageX() && x <= photoImage.getImageX() + backgroundWidth && y >= photoImage.getImageY() && y <= photoImage.getImageY() + photoImage.getImageHeight()) { + imagePressed = true; + result = true; + } + if (currentMessageObject.type == 12) { + TLRPC.User user = MessagesController.getInstance().getUser(currentMessageObject.messageOwner.media.user_id); + if (user == null) { + imagePressed = false; + result = false; + } + } + } + } + if (imagePressed && currentMessageObject.isSecretPhoto()) { + imagePressed = false; + } else if (imagePressed && currentMessageObject.isSendError()) { + imagePressed = false; + result = false; + } else if (imagePressed && currentMessageObject.type == 8 && buttonState == -1 && MediaController.getInstance().canAutoplayGifs()) { + imagePressed = false; + result = false; + } + } else { + if (event.getAction() == MotionEvent.ACTION_UP) { + if (buttonPressed == 1) { + buttonPressed = 0; + playSoundEffect(SoundEffectConstants.CLICK); + didPressedButton(false); + invalidate(); + } else if (imagePressed) { + imagePressed = false; + if (buttonState == -1 || buttonState == 2 || buttonState == 3) { + playSoundEffect(SoundEffectConstants.CLICK); + didClickedImage(); + } else if (buttonState == 0 && documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { + playSoundEffect(SoundEffectConstants.CLICK); + didPressedButton(false); + } + invalidate(); + //plus + if(currentMessageObject.type == 9) { + final String name = FileLoader.getDocumentFileName(currentMessageObject.messageOwner.media.document); + if(name.length() > 0) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (getContext() != null) { + Toast toast = Toast.makeText(getContext(), name, Toast.LENGTH_SHORT); + toast.setGravity(Gravity.TOP, 0, AndroidUtilities.dp(90)); + toast.show(); + } + } + }); + } + } + } + } + } + return result; + } + + private boolean checkAudioMotionEvent(MotionEvent event) { + if (documentAttachType != DOCUMENT_ATTACH_TYPE_AUDIO && documentAttachType != DOCUMENT_ATTACH_TYPE_MUSIC) { + return false; + } + + int x = (int) event.getX(); + int y = (int) event.getY(); + boolean result; + if (useSeekBarWaweform) { + result = seekBarWaveform.onTouch(event.getAction(), event.getX() - seekBarX - AndroidUtilities.dp(13), event.getY() - seekBarY); + } else { + result = seekBar.onTouch(event.getAction(), event.getX() - seekBarX, event.getY() - seekBarY); + } + if (result) { + if (!useSeekBarWaweform && event.getAction() == MotionEvent.ACTION_DOWN) { + getParent().requestDisallowInterceptTouchEvent(true); + } else if (useSeekBarWaweform && !seekBarWaveform.isStartDraging() && event.getAction() == MotionEvent.ACTION_UP) { + didPressedButton(true); + } + disallowLongPress = true; + invalidate(); + } else { + int side = AndroidUtilities.dp(36); + boolean area; + if (buttonState == 0 || buttonState == 1 || buttonState == 2) { + area = x >= buttonX - AndroidUtilities.dp(12) && x <= buttonX - AndroidUtilities.dp(12) + backgroundWidth && y >= namesOffset + mediaOffsetY && y <= layoutHeight; + } else { + area = x >= buttonX && x <= buttonX + side && y >= buttonY && y <= buttonY + side; + } + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (area) { + buttonPressed = 1; + invalidate(); + result = true; + radialProgress.swapBackground(getDrawableForCurrentState()); + } + } else if (buttonPressed != 0) { + if (event.getAction() == MotionEvent.ACTION_UP) { + buttonPressed = 0; + playSoundEffect(SoundEffectConstants.CLICK); + didPressedButton(true); + invalidate(); + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + buttonPressed = 0; + invalidate(); + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (!area) { + buttonPressed = 0; + invalidate(); + } + } + radialProgress.swapBackground(getDrawableForCurrentState()); + } + } + return result; + } + + private boolean checkBotButtonMotionEvent(MotionEvent event) { + if (botButtons.isEmpty()) { + return false; + } + + int x = (int) event.getX(); + int y = (int) event.getY(); + + boolean result = false; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + int addX; + if (currentMessageObject.isOutOwner()) { + addX = getMeasuredWidth() - widthForButtons - AndroidUtilities.dp(10); + } else { + addX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(mediaBackground ? 1 : 7); + } + for (int a = 0; a < botButtons.size(); a++) { + BotButton button = botButtons.get(a); + int y2 = button.y + layoutHeight - AndroidUtilities.dp(2); + if (x >= button.x + addX && x <= button.x + addX + button.width && y >= y2 && y <= y2 + button.height) { + pressedBotButton = a; + invalidate(); + result = true; + break; + } + } + } else { + if (event.getAction() == MotionEvent.ACTION_UP) { + if (pressedBotButton != -1) { + playSoundEffect(SoundEffectConstants.CLICK); + delegate.didPressedBotButton(this, botButtons.get(pressedBotButton).button); + pressedBotButton = -1; + invalidate(); + } + } + } + return result; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (currentMessageObject == null || !delegate.canPerformActions()) { + return super.onTouchEvent(event); + } + + disallowLongPress = false; + + boolean result = checkTextBlockMotionEvent(event); + if (!result) { + result = checkOtherButtonMotionEvent(event); + } + if (!result) { + result = checkLinkPreviewMotionEvent(event); + } + if (!result) { + result = checkCaptionMotionEvent(event); + } + if (!result) { + result = checkAudioMotionEvent(event); + } + if (!result) { + result = checkPhotoImageMotionEvent(event); + } + if (!result) { + result = checkBotButtonMotionEvent(event); + } + + if (event.getAction() == MotionEvent.ACTION_CANCEL) { + buttonPressed = 0; + pressedBotButton = -1; + linkPreviewPressed = false; + otherPressed = false; + imagePressed = false; + result = false; + resetPressedLink(-1); + } + if (!disallowLongPress && result && event.getAction() == MotionEvent.ACTION_DOWN) { startCheckLongPress(); } if (event.getAction() != MotionEvent.ACTION_DOWN && event.getAction() != MotionEvent.ACTION_MOVE) { cancelCheckLongPress(); } + return result || super.onTouchEvent(event); } + public void updateAudioProgress() { + if (currentMessageObject == null || documentAttach == null) { + return; + } + + if (useSeekBarWaweform) { + if (!seekBarWaveform.isDragging()) { + seekBarWaveform.setProgress(currentMessageObject.audioProgress); + } + } else { + if (!seekBar.isDragging()) { + seekBar.setProgress(currentMessageObject.audioProgress); + } + } + + int duration = 0; + if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO) { + if (!MediaController.getInstance().isPlayingAudio(currentMessageObject)) { + for (int a = 0; a < documentAttach.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = documentAttach.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + duration = attribute.duration; + break; + } + } + } else { + duration = currentMessageObject.audioProgressSec; + } + String timeString = String.format("%02d:%02d", duration / 60, duration % 60); + if (lastTimeString == null || lastTimeString != null && !lastTimeString.equals(timeString)) { + lastTimeString = timeString; + timeWidthAudio = (int) Math.ceil(audioTimePaint.measureText(timeString)); + timeLayout = new StaticLayout(timeString, audioTimePaint, timeWidthAudio, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + } + } else { + int currentProgress = 0; + for (int a = 0; a < documentAttach.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = documentAttach.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + duration = attribute.duration; + break; + } + } + if (MediaController.getInstance().isPlayingAudio(currentMessageObject)) { + currentProgress = currentMessageObject.audioProgressSec; + } + String timeString = String.format("%d:%02d / %d:%02d", currentProgress / 60, currentProgress % 60, duration / 60, duration % 60); + //if(currentMessageObject.messageOwner.to_id.channel_id == 0){ + if(currentMessageObject.messageOwner.media.document != null)timeString += " " + AndroidUtilities.formatFileSize(currentMessageObject.messageOwner.media.document.size); + //} + if (lastTimeString == null || lastTimeString != null && !lastTimeString.equals(timeString)) { + lastTimeString = timeString; + int timeWidth = (int) Math.ceil(audioTimePaint.measureText(timeString)); + timeLayout = new StaticLayout(timeString, audioTimePaint, timeWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + } + } + invalidate(); + } + + public void downloadAudioIfNeed() { + if (documentAttachType != DOCUMENT_ATTACH_TYPE_AUDIO || documentAttach.size >= 1024 * 1024 * 5) { + return; + } + if (buttonState == 2) { + FileLoader.getInstance().loadFile(documentAttach, true, false); + buttonState = 4; + radialProgress.setBackground(getDrawableForCurrentState(), false, false); + } + } + public void setVisiblePart(int position, int height) { if (currentMessageObject == null || currentMessageObject.textLayoutBlocks == null) { return; } + position -= textY; + int newFirst = -1, newLast = -1, newCount = 0; - for (int a = Math.max(0, (position - textY) / currentMessageObject.blockHeight); a < currentMessageObject.textLayoutBlocks.size(); a++) { + int startBlock = 0; + for (int a = 0; a < currentMessageObject.textLayoutBlocks.size(); a++) { + if (currentMessageObject.textLayoutBlocks.get(a).textYOffset > position) { + break; + } + startBlock = a; + } + + for (int a = startBlock; a < currentMessageObject.textLayoutBlocks.size(); a++) { MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(a); - float y = textY + block.textYOffset; - if (intersect(y, y + currentMessageObject.blockHeight, position, position + height)) { + float y = block.textYOffset; + if (intersect(y, y + block.height, position, position + height)) { if (newFirst == -1) { newFirst = a; } @@ -354,31 +978,138 @@ public class ChatMessageCell extends ChatBaseCell { return StaticLayoutEx.createStaticLayout(stringBuilder, paint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, maxWidth, maxLines); } + private void didClickedImage() { + if (currentMessageObject.type == 1 || currentMessageObject.type == 13) { + if (buttonState == -1) { + delegate.didPressedImage(this); + } else if (buttonState == 0) { + didPressedButton(false); + } + } else if (currentMessageObject.type == 12) { + TLRPC.User user = MessagesController.getInstance().getUser(currentMessageObject.messageOwner.media.user_id); + delegate.didPressedUserAvatar(this, user); + } else if (currentMessageObject.type == 8) { + if (buttonState == -1) { + buttonState = 2; + currentMessageObject.audioProgress = 1; + photoImage.setAllowStartAnimation(false); + photoImage.stopAnimation(); + radialProgress.setBackground(getDrawableForCurrentState(), false, false); + invalidate(); + } else if (buttonState == 2 || buttonState == 0) { + didPressedButton(false); + } + } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { + if (buttonState == 0 || buttonState == 3) { + didPressedButton(false); + } + } else if (currentMessageObject.type == 4) { + delegate.didPressedImage(this); + } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { + if (buttonState == -1) { + delegate.didPressedImage(this); + } + } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { + if (buttonState == -1) { + TLRPC.WebPage webPage = currentMessageObject.messageOwner.media.webpage; + if (Build.VERSION.SDK_INT >= 16 && webPage.embed_url != null && webPage.embed_url.length() != 0) { + delegate.needOpenWebView(webPage.embed_url, webPage.site_name, webPage.description, webPage.url, webPage.embed_width, webPage.embed_height); + } else { + Browser.openUrl(getContext(), webPage.url); + } + } + } + } + + private void updateSecretTimeText(MessageObject messageObject) { + if (messageObject == null || messageObject.isOut()) { + return; + } + String str = messageObject.getSecretTimeString(); + if (str == null) { + return; + } + infoWidth = (int) Math.ceil(infoPaint.measureText(str)); + CharSequence str2 = TextUtils.ellipsize(str, infoPaint, infoWidth, TextUtils.TruncateAt.END); + infoLayout = new StaticLayout(str2, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + invalidate(); + } + + private boolean isPhotoDataChanged(MessageObject object) { + if (object.type == 0 || object.type == 14) { + return false; + } + if (object.type == 4) { + if (currentUrl == null) { + return true; + } + double lat = object.messageOwner.media.geo.lat; + double lon = object.messageOwner.media.geo._long; + String url = String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%f,%f&zoom=15&size=100x100&maptype=roadmap&scale=%d&markers=color:red|size:mid|%f,%f&sensor=false", lat, lon, Math.min(2, (int) Math.ceil(AndroidUtilities.density)), lat, lon); + if (!url.equals(currentUrl)) { + return true; + } + } else if (currentPhotoObject == null || currentPhotoObject.location instanceof TLRPC.TL_fileLocationUnavailable) { + return true; + } else if (currentMessageObject != null && photoNotSet) { + File cacheFile = FileLoader.getPathToMessage(currentMessageObject.messageOwner); + if (cacheFile.exists()) { //TODO + return true; + } + } + return false; + } + //Plus + private String getCurrentNameString(MessageObject messageObject){ + TLRPC.User currentUser = null; + TLRPC.Chat currentChat = null; + String s; + if (messageObject.isFromUser()) { + currentUser = MessagesController.getInstance().getUser(messageObject.messageOwner.from_id); + } else if (messageObject.messageOwner.from_id < 0) { + currentChat = MessagesController.getInstance().getChat(-messageObject.messageOwner.from_id); + } + + if (currentUser != null) { + s = UserObject.getUserName(currentUser); + String currentUsernameString = currentUser.username; + /*if(currentUsernameString != null && AndroidUtilities.getBoolPref("chatShowUsernameCheck")){ + currentNameString = currentNameString.replaceAll("\\p{C}", " "); + currentNameString = currentNameString.trim().replaceAll(" +", " ") + " [@"+currentUsernameString+"]"; + }*/ + } else if (currentChat != null) { + s = currentChat.title; + } else { + s = "DELETED"; + } + return s; + } + // @Override protected boolean isUserDataChanged() { - if (!hasLinkPreview && currentMessageObject.messageOwner.media != null && currentMessageObject.messageOwner.media.webpage instanceof TLRPC.TL_webPage) { - return true; - } - //suppress warning - return super.isUserDataChanged(); + return currentMessageObject != null && (!hasLinkPreview && currentMessageObject.messageOwner.media != null && currentMessageObject.messageOwner.media.webpage instanceof TLRPC.TL_webPage || super.isUserDataChanged()); } @Override public ImageReceiver getPhotoImage() { - return linkImageView; + return photoImage; } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - linkImageView.onDetachedFromWindow(); + photoImage.onDetachedFromWindow(); MediaController.getInstance().removeLoadingFileObserver(this); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - if (linkImageView.onAttachedToWindow()) { + if (drawPhotoImage) { + if (photoImage.onAttachedToWindow()) { + updateButtonState(false); + } + } else { updateButtonState(false); } } @@ -388,287 +1119,564 @@ public class ChatMessageCell extends ChatBaseCell { if (pressedLink instanceof URLSpanNoUnderline) { URLSpanNoUnderline url = (URLSpanNoUnderline) pressedLink; if (url.getURL().startsWith("/")) { - delegate.didPressUrl(currentMessageObject, pressedLink, true); + delegate.didPressedUrl(currentMessageObject, pressedLink, true); return; } + } else if (pressedLink instanceof URLSpan) { + delegate.didPressedUrl(currentMessageObject, pressedLink, true); + return; + } + resetPressedLink(-1); + if (buttonPressed != 0 || pressedBotButton != -1) { + buttonPressed = 0; + pressedBotButton = -1; + invalidate(); } super.onLongPress(); } @Override - public void setMessageObject(MessageObject messageObject) { - boolean dataChanged = currentMessageObject == messageObject && (isUserDataChanged() || photoNotSet); - if (currentMessageObject != messageObject || dataChanged) { - if (currentMessageObject != messageObject) { - firstVisibleBlockNum = 0; - lastVisibleBlockNum = 0; + public void setCheckPressed(boolean value, boolean pressed) { + super.setCheckPressed(value, pressed); + if (radialProgress.swapBackground(getDrawableForCurrentState())) { + invalidate(); + } + if (useSeekBarWaweform) { + seekBarWaveform.setSelected(isDrawSelectedBackground()); + } else { + seekBar.setSelected(isDrawSelectedBackground()); + } + } + + @Override + public void setHighlighted(boolean value) { + super.setHighlighted(value); + if (radialProgress.swapBackground(getDrawableForCurrentState())) { + invalidate(); + } + if (useSeekBarWaweform) { + seekBarWaveform.setSelected(isDrawSelectedBackground()); + } else { + seekBar.setSelected(isDrawSelectedBackground()); + } + } + + @Override + public void setPressed(boolean pressed) { + super.setPressed(pressed); + if (radialProgress.swapBackground(getDrawableForCurrentState())) { + invalidate(); + } + if (useSeekBarWaweform) { + seekBarWaveform.setSelected(isDrawSelectedBackground()); + } else { + seekBar.setSelected(isDrawSelectedBackground()); + } + } + + @Override + public void onSeekBarDrag(float progress) { + if (currentMessageObject == null) { + return; + } + currentMessageObject.audioProgress = progress; + MediaController.getInstance().seekToProgress(currentMessageObject, progress); + } + + private void updateWaveform() { + if (currentMessageObject == null || documentAttachType != DOCUMENT_ATTACH_TYPE_AUDIO) { + return; + } + for (int a = 0; a < documentAttach.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = documentAttach.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.waveform == null || attribute.waveform.length == 0) { + MediaController.getInstance().generateWaveform(currentMessageObject); + } + useSeekBarWaweform = attribute.waveform != null; + seekBarWaveform.setWaveform(attribute.waveform); + break; } - drawLinkImageView = false; + } + } + + private int createDocumentLayout(int maxWidth, MessageObject messageObject) { + if (messageObject.type == 0) { + documentAttach = messageObject.messageOwner.media.webpage.document; + } else { + documentAttach = messageObject.messageOwner.media.document; + } + if (documentAttach == null) { + return 0; + } + if (MessageObject.isVoiceDocument(documentAttach)) { + documentAttachType = DOCUMENT_ATTACH_TYPE_AUDIO; + int duration = 0; + for (int a = 0; a < documentAttach.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = documentAttach.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + duration = attribute.duration; + break; + } + } + availableTimeWidth = maxWidth - AndroidUtilities.dp(76 + 18) - (int) Math.ceil(audioTimePaint.measureText("00:00")); + measureTime(messageObject); + int minSize = AndroidUtilities.dp(40 + 14 + 20 + 90 + 10) + timeWidth; + if (!hasLinkPreview) { + backgroundWidth = Math.min(maxWidth, minSize + duration * AndroidUtilities.dp(10)); + } + + if (messageObject.isOutOwner()) { + seekBarWaveform.setColors(Theme.MSG_OUT_VOICE_SEEKBAR_COLOR, Theme.MSG_OUT_VOICE_SEEKBAR_FILL_COLOR, Theme.MSG_OUT_VOICE_SEEKBAR_SELECTED_COLOR); + seekBar.setColors(Theme.MSG_OUT_AUDIO_SEEKBAR_COLOR, Theme.MSG_OUT_AUDIO_SEEKBAR_FILL_COLOR, Theme.MSG_OUT_AUDIO_SEEKBAR_SELECTED_COLOR); + } else { + seekBarWaveform.setColors(Theme.MSG_IN_VOICE_SEEKBAR_COLOR, Theme.MSG_IN_VOICE_SEEKBAR_FILL_COLOR, Theme.MSG_IN_VOICE_SEEKBAR_SELECTED_COLOR); + seekBar.setColors(Theme.MSG_IN_AUDIO_SEEKBAR_COLOR, Theme.MSG_IN_AUDIO_SEEKBAR_FILL_COLOR, Theme.MSG_IN_AUDIO_SEEKBAR_SELECTED_COLOR); + } + seekBarWaveform.setMessageObject(messageObject); + return 0; + } else if (MessageObject.isMusicDocument(documentAttach)) { + documentAttachType = DOCUMENT_ATTACH_TYPE_MUSIC; + if (messageObject.isOutOwner()) { + seekBar.setColors(Theme.MSG_OUT_AUDIO_SEEKBAR_COLOR, Theme.MSG_OUT_AUDIO_SEEKBAR_FILL_COLOR, Theme.MSG_OUT_AUDIO_SEEKBAR_SELECTED_COLOR); + } else { + seekBar.setColors(Theme.MSG_IN_AUDIO_SEEKBAR_COLOR, Theme.MSG_IN_AUDIO_SEEKBAR_FILL_COLOR, Theme.MSG_IN_AUDIO_SEEKBAR_SELECTED_COLOR); + } + + maxWidth = maxWidth - AndroidUtilities.dp(86); + + CharSequence stringFinal = TextUtils.ellipsize(messageObject.getMusicTitle().replace('\n', ' '), audioTitlePaint, maxWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); + songLayout = new StaticLayout(stringFinal, audioTitlePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + if (songLayout.getLineCount() > 0) { + songX = -(int) Math.ceil(songLayout.getLineLeft(0)); + } + + stringFinal = TextUtils.ellipsize(messageObject.getMusicAuthor().replace('\n', ' '), audioPerformerPaint, maxWidth, TextUtils.TruncateAt.END); + performerLayout = new StaticLayout(stringFinal, audioPerformerPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + if (performerLayout.getLineCount() > 0) { + performerX = -(int) Math.ceil(performerLayout.getLineLeft(0)); + } + radialProgress.setSizeAndType(documentAttach.size, messageObject.type); //plus MUSIC type=14 + int duration = 0; + for (int a = 0; a < documentAttach.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = documentAttach.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + duration = attribute.duration; + break; + } + } + int durationWidth = (int) Math.ceil(audioTimePaint.measureText(String.format("%d:%02d / %d:%02d", duration / 60, duration % 60, duration / 60, duration % 60))); + availableTimeWidth = backgroundWidth - AndroidUtilities.dp(76 + 18) - durationWidth; + return durationWidth; + } else if (MessageObject.isVideoDocument(documentAttach)) { + documentAttachType = DOCUMENT_ATTACH_TYPE_VIDEO; + int duration = 0; + for (int a = 0; a < documentAttach.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = documentAttach.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeVideo) { + duration = attribute.duration; + break; + } + } + int minutes = duration / 60; + int seconds = duration - minutes * 60; + String str = String.format("%d:%02d, %s", minutes, seconds, AndroidUtilities.formatFileSize(documentAttach.size)); + infoWidth = (int) Math.ceil(infoPaint.measureText(str)); + infoLayout = new StaticLayout(str, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + //radialProgress.setSizeAndType(documentAttach.size, messageObject.type); //plus VIDEO type=3 + return 0; + } else { + drawPhotoImage = documentAttach.mime_type != null && documentAttach.mime_type.toLowerCase().startsWith("image/") || documentAttach.thumb instanceof TLRPC.TL_photoSize && !(documentAttach.thumb.location instanceof TLRPC.TL_fileLocationUnavailable); + if (!drawPhotoImage) { + maxWidth += AndroidUtilities.dp(30); + } + documentAttachType = DOCUMENT_ATTACH_TYPE_DOCUMENT; + String name = FileLoader.getDocumentFileName(documentAttach); + if (name == null || name.length() == 0) { + name = LocaleController.getString("AttachDocument", R.string.AttachDocument); + } + captionLayout = StaticLayoutEx.createStaticLayout(name, docNamePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.MIDDLE, maxWidth, drawPhotoImage ? 2 : 1); + // boolean hasSign = !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0 && messageObject.messageOwner.post; + //maxWidth = maxWidth + AndroidUtilities.dp(1); //to fix 2 lines bug + //captionLayout = StaticLayoutEx.createStaticLayout(name, docNamePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.MIDDLE, maxWidth, /*hasSign ? 2 : drawPhotoImage ? 3 : 2*/3); + nameOffsetX = Integer.MIN_VALUE; + int captionWidth; + if (captionLayout != null && captionLayout.getLineCount() > 0) { + int maxLineWidth = 0; + for (int a = 0; a < captionLayout.getLineCount(); a++) { + maxLineWidth = Math.max(maxLineWidth, (int) Math.ceil(captionLayout.getLineWidth(a))); + nameOffsetX = Math.max(nameOffsetX, (int) Math.ceil(-captionLayout.getLineLeft(a))); + } + captionWidth = Math.min(maxWidth, maxLineWidth); + } else { + captionWidth = maxWidth; + nameOffsetX = 0; + } + //radialProgress.setSizeAndType(documentAttach.size, messageObject.type); //plus FILE type=9 + String str = AndroidUtilities.formatFileSize(documentAttach.size) + " " + FileLoader.getDocumentExtension(documentAttach); + infoWidth = Math.min(maxWidth, (int) Math.ceil(infoPaint.measureText(str))); + //Plus + infoLayout2 = null; + if(isChat){ + String senderName = getCurrentNameString(messageObject); + infoWidth2 = Math.min(maxWidth, (int) Math.ceil(senderPaint.measureText(senderName))); + CharSequence str2 = TextUtils.ellipsize(senderName, senderPaint, infoWidth2, TextUtils.TruncateAt.END); + infoLayout2 = new StaticLayout(str2, senderPaint, infoWidth2, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + infoWidth = Math.max(infoWidth2, (int) Math.ceil(infoPaint.measureText(str))); + } + // + CharSequence str2 = TextUtils.ellipsize(str, infoPaint, infoWidth, TextUtils.TruncateAt.END); + try { + if (infoWidth < 0) { + infoWidth = AndroidUtilities.dp(10); + } + infoLayout = new StaticLayout(str2, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + if (drawPhotoImage) { + currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); + photoImage.setNeedsQualityThumb(true); + photoImage.setShouldGenerateQualityThumb(true); + photoImage.setParentMessageObject(messageObject); + if (currentPhotoObject != null) { + currentPhotoFilter = "86_86_b"; + photoImage.setImage(null, null, null, null, currentPhotoObject.location, currentPhotoFilter, 0, null, true); + } else { + photoImage.setImageBitmap((BitmapDrawable) null); + } + } + return captionWidth; + } + } + + private void calcBackgroundWidth(int maxWidth, int timeMore, int maxChildWidth) { + if (hasLinkPreview || maxWidth - currentMessageObject.lastLineWidth < timeMore) { + totalHeight += AndroidUtilities.dp(14); + backgroundWidth = Math.max(maxChildWidth, currentMessageObject.lastLineWidth) + AndroidUtilities.dp(31); + backgroundWidth = Math.max(backgroundWidth, timeWidth + AndroidUtilities.dp(31)); + } else { + int diff = maxChildWidth - currentMessageObject.lastLineWidth; + if (diff >= 0 && diff <= timeMore) { + backgroundWidth = maxChildWidth + timeMore - diff + AndroidUtilities.dp(31); + } else { + backgroundWidth = Math.max(maxChildWidth, currentMessageObject.lastLineWidth + timeMore) + AndroidUtilities.dp(31); + } + } + } + + @Override + public void setMessageObject(MessageObject messageObject) { + boolean messageIdChanged = currentMessageObject == null || currentMessageObject.getId() != messageObject.getId(); + boolean messageChanged = currentMessageObject != messageObject || messageObject.forceUpdate; + boolean dataChanged = currentMessageObject == messageObject && (isUserDataChanged() || photoNotSet); + if (messageChanged || dataChanged || isPhotoDataChanged(messageObject)) { + resetPressedLink(-1); + messageObject.forceUpdate = false; + drawPhotoImage = false; hasLinkPreview = false; - resetPressedLink(); linkPreviewPressed = false; - buttonPressed = false; + buttonPressed = 0; + pressedBotButton = -1; linkPreviewHeight = 0; - isInstagram = false; + mediaOffsetY = 0; durationLayout = null; - isGifDocument = false; + documentAttachType = DOCUMENT_ATTACH_TYPE_NONE; + documentAttach = null; descriptionLayout = null; titleLayout = null; - siteNameLayout = null; + siteCaptionLayout = null; authorLayout = null; + captionLayout = null; drawImageButton = false; currentPhotoObject = null; currentPhotoObjectThumb = null; currentPhotoFilter = null; - int maxWidth; + infoLayout = null; + cancelLoading = false; + buttonState = -1; + currentUrl = null; + photoNotSet = false; + drawBackground = true; + drawName = false; + useSeekBarWaweform = false; + drawForwardedName = false; + mediaBackground = false; + availableTimeWidth = 0; + photoImage.setNeedsQualityThumb(false); + photoImage.setShouldGenerateQualityThumb(false); + photoImage.setParentMessageObject(null); + photoImage.setRoundRadius(AndroidUtilities.dp(3)); - if (AndroidUtilities.isTablet()) { - //if (isChat && !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0) { - if ((isChat || showAvatar) && !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0 - || ( (showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) && messageObject.isOutOwner()) { - //maxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(122); - maxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(leftBound + 70); - drawName = true; - } else { - drawName = messageObject.messageOwner.to_id.channel_id != 0 && !messageObject.isOutOwner(); - maxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(80); - } - } else { - //if (isChat && !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0) { - if ((isChat || showAvatar) && !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0 - || ( (showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) && messageObject.isOutOwner()) { - maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(122); - //Log.e("ChatMessageCell","1 DRAWNAME true maxWidth: " + maxWidth); - drawName = true; - } else { - maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(80); - drawName = messageObject.messageOwner.to_id.channel_id != 0 && !messageObject.isOutOwner(); - //Log.e("ChatMessageCell","2 DRAWNAME x maxWidth: " + maxWidth); - } + if (messageChanged) { + firstVisibleBlockNum = 0; + lastVisibleBlockNum = 0; + needNewVisiblePart = true; } - backgroundWidth = maxWidth; + if (messageObject.type == 0) { + drawForwardedName = true; - super.setMessageObject(messageObject); - - backgroundWidth = messageObject.textWidth; - //Log.e("ChatMessageCell","3 textWidth: " + backgroundWidth); - totalHeight = messageObject.textHeight + AndroidUtilities.dp(19.5f) + namesOffset; - - int maxChildWidth = Math.max(backgroundWidth, nameWidth); - maxChildWidth = Math.max(maxChildWidth, forwardedNameWidth); - maxChildWidth = Math.max(maxChildWidth, replyNameWidth); - maxChildWidth = Math.max(maxChildWidth, replyTextWidth); - int maxWebWidth = 0; - - int timeMore = timeWidth + AndroidUtilities.dp(6); - if (messageObject.isOutOwner()) { - timeMore += AndroidUtilities.dp(20.5f); - } - - if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && messageObject.messageOwner.media.webpage instanceof TLRPC.TL_webPage) { - int linkPreviewMaxWidth; + int maxWidth; if (AndroidUtilities.isTablet()) { - if (messageObject.messageOwner.from_id > 0 && (currentMessageObject.messageOwner.to_id.channel_id != 0 || currentMessageObject.messageOwner.to_id.chat_id != 0) && !currentMessageObject.isOut()) { - //linkPreviewMaxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(122); - linkPreviewMaxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(leftBound + 70); + //if (isChat && !messageObject.isOutOwner() && messageObject.isFromUser()) { + if ( (isChat || showAvatar) && !messageObject.isOutOwner() && messageObject.isFromUser() + || ( (showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) && messageObject.isOutOwner()) { + //maxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(122); + maxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(leftBound + 74); + drawName = true; } else { - linkPreviewMaxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(80); + drawName = messageObject.messageOwner.to_id.channel_id != 0 && !messageObject.isOutOwner(); + maxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(80); } } else { - //if (messageObject.messageOwner.from_id > 0 && (currentMessageObject.messageOwner.to_id.channel_id != 0 || currentMessageObject.messageOwner.to_id.chat_id != 0) && !currentMessageObject.isOutOwner()) { - if (messageObject.messageOwner.from_id > 0 && (currentMessageObject.messageOwner.to_id.channel_id != 0 || currentMessageObject.messageOwner.to_id.chat_id != 0 || showAvatar) && !currentMessageObject.isOutOwner() || (showMyAvatar && currentMessageObject.isOutOwner())) { - //linkPreviewMaxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(122); - linkPreviewMaxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(leftBound + 70); + //if (isChat && !messageObject.isOutOwner() && messageObject.isFromUser()) { + if ((isChat || showAvatar) && !messageObject.isOutOwner() && messageObject.isFromUser() + || ( (showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) && messageObject.isOutOwner()) { + maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(122); + drawName = true; } else { - linkPreviewMaxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(80); + maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(80); + drawName = messageObject.messageOwner.to_id.channel_id != 0 && !messageObject.isOutOwner(); } } - - TLRPC.TL_webPage webPage = (TLRPC.TL_webPage) messageObject.messageOwner.media.webpage; - - if (webPage.site_name != null && webPage.photo != null && webPage.site_name.toLowerCase().equals("instagram")) { - linkPreviewMaxWidth = Math.max(AndroidUtilities.displaySize.y / 3, currentMessageObject.textWidth); + measureTime(messageObject); + int timeMore = timeWidth + AndroidUtilities.dp(6); + if (messageObject.isOutOwner()) { + timeMore += AndroidUtilities.dp(20.5f); } - int additinalWidth = AndroidUtilities.dp(10); - int restLinesCount = 3; - int additionalHeight = 0; - linkPreviewMaxWidth -= additinalWidth; - - hasLinkPreview = true; - - if (currentMessageObject.photoThumbs == null && webPage.photo != null) { - currentMessageObject.generateThumbs(true); - } - - isSmallImage = webPage.description != null && webPage.type != null && (webPage.type.equals("app") || webPage.type.equals("profile") || webPage.type.equals("article")) && currentMessageObject.photoThumbs != null; - - if (webPage.site_name != null) { - try { - int width = (int) Math.ceil(replyNamePaint.measureText(webPage.site_name)); - siteNameLayout = new StaticLayout(webPage.site_name, replyNamePaint, Math.min(width, linkPreviewMaxWidth), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - int height = siteNameLayout.getLineBottom(siteNameLayout.getLineCount() - 1); - linkPreviewHeight += height; - totalHeight += height; - additionalHeight += height; - width = siteNameLayout.getWidth(); - maxChildWidth = Math.max(maxChildWidth, width + additinalWidth); - maxWebWidth = Math.max(maxWebWidth, width + additinalWidth); - } catch (Exception e) { - FileLog.e("tmessages", e); + hasLinkPreview = messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && messageObject.messageOwner.media.webpage instanceof TLRPC.TL_webPage; + backgroundWidth = maxWidth; + if (hasLinkPreview || maxWidth - messageObject.lastLineWidth < timeMore) { + backgroundWidth = Math.max(backgroundWidth, messageObject.lastLineWidth) + AndroidUtilities.dp(31); + backgroundWidth = Math.max(backgroundWidth, timeWidth + AndroidUtilities.dp(31)); + } else { + int diff = backgroundWidth - messageObject.lastLineWidth; + if (diff >= 0 && diff <= timeMore) { + backgroundWidth = backgroundWidth + timeMore - diff + AndroidUtilities.dp(31); + } else { + backgroundWidth = Math.max(backgroundWidth, messageObject.lastLineWidth + timeMore) + AndroidUtilities.dp(31); } } + availableTimeWidth = backgroundWidth - AndroidUtilities.dp(31); - boolean titleIsRTL = false; - if (webPage.title != null) { - try { - titleX = 0; - if (linkPreviewHeight != 0) { - linkPreviewHeight += AndroidUtilities.dp(2); - totalHeight += AndroidUtilities.dp(2); - } - int restLines = 0; - if (!isSmallImage || webPage.description == null) { - titleLayout = StaticLayoutEx.createStaticLayout(webPage.title, replyNamePaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, 4); + super.setMessageObject(messageObject); + + backgroundWidth = messageObject.textWidth; + totalHeight = messageObject.textHeight + AndroidUtilities.dp(19.5f) + namesOffset; + + int maxChildWidth = Math.max(backgroundWidth, nameWidth); + maxChildWidth = Math.max(maxChildWidth, forwardedNameWidth); + maxChildWidth = Math.max(maxChildWidth, replyNameWidth); + maxChildWidth = Math.max(maxChildWidth, replyTextWidth); + int maxWebWidth = 0; + + if (hasLinkPreview) { + int linkPreviewMaxWidth; + if (AndroidUtilities.isTablet()) { + if (messageObject.isFromUser() && (currentMessageObject.messageOwner.to_id.channel_id != 0 || currentMessageObject.messageOwner.to_id.chat_id != 0) && !currentMessageObject.isOut()) { + //linkPreviewMaxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(122); + linkPreviewMaxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(leftBound + 70); } else { - restLines = restLinesCount; - titleLayout = generateStaticLayout(webPage.title, replyNamePaint, linkPreviewMaxWidth, linkPreviewMaxWidth - AndroidUtilities.dp(48 + 2), restLinesCount, 4); - restLinesCount -= titleLayout.getLineCount(); + linkPreviewMaxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(80); } - int height = titleLayout.getLineBottom(titleLayout.getLineCount() - 1); - linkPreviewHeight += height; - totalHeight += height; - for (int a = 0; a < titleLayout.getLineCount(); a++) { - int lineLeft = (int) titleLayout.getLineLeft(a); - if (lineLeft != 0) { - titleIsRTL = true; - if (titleX == 0) { - titleX = -lineLeft; - } else { - titleX = Math.max(titleX, -lineLeft); - } + } else { + //if (messageObject.isFromUser() && (currentMessageObject.messageOwner.to_id.channel_id != 0 || currentMessageObject.messageOwner.to_id.chat_id != 0) && !currentMessageObject.isOutOwner()) { + if (messageObject.isFromUser() && (currentMessageObject.messageOwner.to_id.channel_id != 0 || currentMessageObject.messageOwner.to_id.chat_id != 0 || showAvatar) && !currentMessageObject.isOutOwner() || (showMyAvatar && currentMessageObject.isOutOwner())) { + //linkPreviewMaxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(122); + linkPreviewMaxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(leftBound + 70); + } else { + linkPreviewMaxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(80); + } + } + if (drawShareButton) { + linkPreviewMaxWidth -= AndroidUtilities.dp(20); + } + + TLRPC.TL_webPage webPage = (TLRPC.TL_webPage) messageObject.messageOwner.media.webpage; + + if (webPage.site_name != null && webPage.photo != null && webPage.site_name.toLowerCase().equals("instagram")) { + linkPreviewMaxWidth = Math.max(AndroidUtilities.displaySize.y / 3, currentMessageObject.textWidth); + } + + int additinalWidth = AndroidUtilities.dp(10); + int restLinesCount = 3; + int additionalHeight = 0; + linkPreviewMaxWidth -= additinalWidth; + + if (currentMessageObject.photoThumbs == null && webPage.photo != null) { + currentMessageObject.generateThumbs(true); + } + + isSmallImage = webPage.description != null && webPage.type != null && (webPage.type.equals("app") || webPage.type.equals("profile") || webPage.type.equals("article")) && currentMessageObject.photoThumbs != null; + + if (webPage.site_name != null) { + try { + int width = (int) Math.ceil(replyNamePaint.measureText(webPage.site_name)); + siteCaptionLayout = new StaticLayout(webPage.site_name, replyNamePaint, Math.min(width, linkPreviewMaxWidth), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + int height = siteCaptionLayout.getLineBottom(siteCaptionLayout.getLineCount() - 1); + linkPreviewHeight += height; + totalHeight += height; + additionalHeight += height; + width = siteCaptionLayout.getWidth(); + maxChildWidth = Math.max(maxChildWidth, width + additinalWidth); + maxWebWidth = Math.max(maxWebWidth, width + additinalWidth); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + boolean titleIsRTL = false; + if (webPage.title != null) { + try { + titleX = 0; + if (linkPreviewHeight != 0) { + linkPreviewHeight += AndroidUtilities.dp(2); + totalHeight += AndroidUtilities.dp(2); } + int restLines = 0; + if (!isSmallImage || webPage.description == null) { + titleLayout = StaticLayoutEx.createStaticLayout(webPage.title, replyNamePaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, 4); + } else { + restLines = restLinesCount; + titleLayout = generateStaticLayout(webPage.title, replyNamePaint, linkPreviewMaxWidth, linkPreviewMaxWidth - AndroidUtilities.dp(48 + 4), restLinesCount, 4); + restLinesCount -= titleLayout.getLineCount(); + } + int height = titleLayout.getLineBottom(titleLayout.getLineCount() - 1); + linkPreviewHeight += height; + totalHeight += height; + for (int a = 0; a < titleLayout.getLineCount(); a++) { + int lineLeft = (int) titleLayout.getLineLeft(a); + if (lineLeft != 0) { + titleIsRTL = true; + if (titleX == 0) { + titleX = -lineLeft; + } else { + titleX = Math.max(titleX, -lineLeft); + } + } + int width; + if (lineLeft != 0) { + width = titleLayout.getWidth() - lineLeft; + } else { + width = (int) Math.ceil(titleLayout.getLineWidth(a)); + } + if (a < restLines || lineLeft != 0 && isSmallImage) { + width += AndroidUtilities.dp(48 + 4); + } + maxChildWidth = Math.max(maxChildWidth, width + additinalWidth); + maxWebWidth = Math.max(maxWebWidth, width + additinalWidth); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + boolean authorIsRTL = false; + if (webPage.author != null) { + try { + if (linkPreviewHeight != 0) { + linkPreviewHeight += AndroidUtilities.dp(2); + totalHeight += AndroidUtilities.dp(2); + } + //int width = Math.min((int) Math.ceil(replyNamePaint.measureText(webPage.author)), linkPreviewMaxWidth); + if (restLinesCount == 3 && (!isSmallImage || webPage.description == null)) { + authorLayout = new StaticLayout(webPage.author, replyNamePaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + } else { + authorLayout = generateStaticLayout(webPage.author, replyNamePaint, linkPreviewMaxWidth, linkPreviewMaxWidth - AndroidUtilities.dp(48 + 4), restLinesCount, 1); + restLinesCount -= authorLayout.getLineCount(); + } + int height = authorLayout.getLineBottom(authorLayout.getLineCount() - 1); + linkPreviewHeight += height; + totalHeight += height; + int lineLeft = (int) authorLayout.getLineLeft(0); + authorX = -lineLeft; int width; if (lineLeft != 0) { - width = titleLayout.getWidth() - lineLeft; + width = authorLayout.getWidth() - lineLeft; + authorIsRTL = true; } else { - width = (int) Math.ceil(titleLayout.getLineWidth(a)); - } - if (a < restLines || lineLeft != 0 && isSmallImage) { - width += AndroidUtilities.dp(48 + 2); + width = (int) Math.ceil(authorLayout.getLineWidth(0)); } maxChildWidth = Math.max(maxChildWidth, width + additinalWidth); maxWebWidth = Math.max(maxWebWidth, width + additinalWidth); + } catch (Exception e) { + FileLog.e("tmessages", e); } - } catch (Exception e) { - FileLog.e("tmessages", e); } - } - boolean authorIsRTL = false; - if (webPage.author != null) { - try { - if (linkPreviewHeight != 0) { - linkPreviewHeight += AndroidUtilities.dp(2); - totalHeight += AndroidUtilities.dp(2); - } - //int width = Math.min((int) Math.ceil(replyNamePaint.measureText(webPage.author)), linkPreviewMaxWidth); - if (restLinesCount == 3 && (!isSmallImage || webPage.description == null)) { - authorLayout = new StaticLayout(webPage.author, replyNamePaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - } else { - authorLayout = generateStaticLayout(webPage.author, replyNamePaint, linkPreviewMaxWidth, linkPreviewMaxWidth - AndroidUtilities.dp(48 + 2), restLinesCount, 1); - restLinesCount -= authorLayout.getLineCount(); - } - int height = authorLayout.getLineBottom(authorLayout.getLineCount() - 1); - linkPreviewHeight += height; - totalHeight += height; - int lineLeft = (int) authorLayout.getLineLeft(0); - authorX = -lineLeft; - int width; - if (lineLeft != 0) { - width = authorLayout.getWidth() - lineLeft; - authorIsRTL = true; - } else { - width = (int) Math.ceil(authorLayout.getLineWidth(0)); - } - maxChildWidth = Math.max(maxChildWidth, width + additinalWidth); - maxWebWidth = Math.max(maxWebWidth, width + additinalWidth); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - - if (webPage.description != null) { - try { - descriptionX = 0; - currentMessageObject.generateLinkDescription(); - if (linkPreviewHeight != 0) { - linkPreviewHeight += AndroidUtilities.dp(2); - totalHeight += AndroidUtilities.dp(2); - } - int restLines = 0; - if (restLinesCount == 3 && !isSmallImage) { - descriptionLayout = StaticLayoutEx.createStaticLayout(messageObject.linkDescription, replyTextPaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, 6); - } else { - restLines = restLinesCount; - descriptionLayout = generateStaticLayout(messageObject.linkDescription, replyTextPaint, linkPreviewMaxWidth, linkPreviewMaxWidth - AndroidUtilities.dp(48 + 2), restLinesCount, 6); - } - int height = descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); - linkPreviewHeight += height; - totalHeight += height; - - boolean hasRTL = false; - for (int a = 0; a < descriptionLayout.getLineCount(); a++) { - int lineLeft = (int) Math.ceil(descriptionLayout.getLineLeft(a)); - if (lineLeft != 0) { - hasRTL = true; - if (descriptionX == 0) { - descriptionX = -lineLeft; + if (webPage.description != null) { + try { + descriptionX = 0; + currentMessageObject.generateLinkDescription(); + if (linkPreviewHeight != 0) { + linkPreviewHeight += AndroidUtilities.dp(2); + totalHeight += AndroidUtilities.dp(2); + } + int restLines = 0; + if (restLinesCount == 3 && !isSmallImage) { + descriptionLayout = StaticLayoutEx.createStaticLayout(messageObject.linkDescription, replyTextPaint, linkPreviewMaxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, AndroidUtilities.dp(1), false, TextUtils.TruncateAt.END, linkPreviewMaxWidth, 6); } else { - descriptionX = Math.max(descriptionX, -lineLeft); + restLines = restLinesCount; + descriptionLayout = generateStaticLayout(messageObject.linkDescription, replyTextPaint, linkPreviewMaxWidth, linkPreviewMaxWidth - AndroidUtilities.dp(48 + 4), restLinesCount, 6); } - } - } + int height = descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); + linkPreviewHeight += height; + totalHeight += height; - for (int a = 0; a < descriptionLayout.getLineCount(); a++) { - int lineLeft = (int) Math.ceil(descriptionLayout.getLineLeft(a)); - if (lineLeft == 0 && descriptionX != 0) { - descriptionX = 0; + boolean hasRTL = false; + for (int a = 0; a < descriptionLayout.getLineCount(); a++) { + int lineLeft = (int) Math.ceil(descriptionLayout.getLineLeft(a)); + if (lineLeft != 0) { + hasRTL = true; + if (descriptionX == 0) { + descriptionX = -lineLeft; + } else { + descriptionX = Math.max(descriptionX, -lineLeft); + } + } } - int width; - if (lineLeft != 0) { - width = descriptionLayout.getWidth() - lineLeft; - } else { - width = hasRTL ? descriptionLayout.getWidth() : (int) Math.ceil(descriptionLayout.getLineWidth(a)); - } - if (a < restLines || restLines != 0 && lineLeft != 0 && isSmallImage) { - width += AndroidUtilities.dp(48 + 2); - } - if (maxWebWidth < width + additinalWidth) { - if (titleIsRTL) { - titleX += (width + additinalWidth - maxWebWidth); + for (int a = 0; a < descriptionLayout.getLineCount(); a++) { + int lineLeft = (int) Math.ceil(descriptionLayout.getLineLeft(a)); + if (lineLeft == 0 && descriptionX != 0) { + descriptionX = 0; } - if (authorIsRTL) { - authorX += (width + additinalWidth - maxWebWidth); + + int width; + if (lineLeft != 0) { + width = descriptionLayout.getWidth() - lineLeft; + } else { + width = hasRTL ? descriptionLayout.getWidth() : (int) Math.ceil(descriptionLayout.getLineWidth(a)); } - maxWebWidth = width + additinalWidth; + if (a < restLines || restLines != 0 && lineLeft != 0 && isSmallImage) { + width += AndroidUtilities.dp(48 + 4); + } + if (maxWebWidth < width + additinalWidth) { + if (titleIsRTL) { + titleX += (width + additinalWidth - maxWebWidth); + } + if (authorIsRTL) { + authorX += (width + additinalWidth - maxWebWidth); + } + maxWebWidth = width + additinalWidth; + } + if (restLines == 0 || !isSmallImage) { + if (titleIsRTL) { + titleX = -AndroidUtilities.dp(4); + } + if (authorIsRTL) { + authorX = -AndroidUtilities.dp(4); + } + } + maxChildWidth = Math.max(maxChildWidth, width + additinalWidth); } - if (restLines == 0 || !isSmallImage) { - if (titleIsRTL) { - titleX = -AndroidUtilities.dp(4); - } - if (authorIsRTL) { - authorX = -AndroidUtilities.dp(4); - } - } - maxChildWidth = Math.max(maxChildWidth, width + additinalWidth); + } catch (Exception e) { + FileLog.e("tmessages", e); } - } catch (Exception e) { - FileLog.e("tmessages", e); } - } boolean smallImage = webPage.type != null && (webPage.type.equals("app") || webPage.type.equals("profile") || webPage.type.equals("article")); if (smallImage && (descriptionLayout == null || descriptionLayout != null && descriptionLayout.getLineCount() == 1)) { @@ -677,461 +1685,1916 @@ public class ChatMessageCell extends ChatBaseCell { } int maxPhotoWidth = smallImage ? AndroidUtilities.dp(48) : linkPreviewMaxWidth; - if (webPage.document != null && MessageObject.isGifDocument(webPage.document)) { - if (!MediaController.getInstance().canAutoplayGifs()) { - messageObject.audioProgress = 1; + if (webPage.document != null) { + TLRPC.Document document = webPage.document; + if (MessageObject.isGifDocument(document)){ + if (!MediaController.getInstance().canAutoplayGifs()) { + messageObject.audioProgress = 1; + } + photoImage.setAllowStartAnimation(messageObject.audioProgress != 1); + currentPhotoObject = document.thumb; + if (currentPhotoObject != null && (currentPhotoObject.w == 0 || currentPhotoObject.h == 0)) { + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeImageSize || attribute instanceof TLRPC.TL_documentAttributeVideo) { + currentPhotoObject.w = attribute.w; + currentPhotoObject.h = attribute.h; + break; + } + } + if (currentPhotoObject.w == 0 || currentPhotoObject.h == 0) { + currentPhotoObject.w = currentPhotoObject.h = AndroidUtilities.dp(150); + } + } + documentAttachType = DOCUMENT_ATTACH_TYPE_GIF; + } else if (MessageObject.isVideoDocument(document)) { + currentPhotoObject = document.thumb; + if (currentPhotoObject != null && (currentPhotoObject.w == 0 || currentPhotoObject.h == 0)) { + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeVideo) { + currentPhotoObject.w = attribute.w; + currentPhotoObject.h = attribute.h; + break; + } + } + if (currentPhotoObject.w == 0 || currentPhotoObject.h == 0) { + currentPhotoObject.w = currentPhotoObject.h = AndroidUtilities.dp(150); + } + } + createDocumentLayout(0, messageObject); + } else if (MessageObject.isStickerDocument(document)) { + currentPhotoObject = document.thumb; + if (currentPhotoObject != null && (currentPhotoObject.w == 0 || currentPhotoObject.h == 0)) { + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeImageSize) { + currentPhotoObject.w = attribute.w; + currentPhotoObject.h = attribute.h; + break; + } + } + if (currentPhotoObject.w == 0 || currentPhotoObject.h == 0) { + currentPhotoObject.w = currentPhotoObject.h = AndroidUtilities.dp(150); + } + } + documentAttach = document; + documentAttachType = DOCUMENT_ATTACH_TYPE_STICKER; + } else { + calcBackgroundWidth(maxWidth, timeMore, maxChildWidth); + if (!MessageObject.isStickerDocument(document)) { + if (backgroundWidth < maxWidth + AndroidUtilities.dp(20)) { + backgroundWidth = maxWidth + AndroidUtilities.dp(20); + } + if (MessageObject.isVoiceDocument(document)) { + createDocumentLayout(backgroundWidth - AndroidUtilities.dp(10), messageObject); + mediaOffsetY = currentMessageObject.textHeight + AndroidUtilities.dp(8) + linkPreviewHeight; + totalHeight += AndroidUtilities.dp(30 + 14); + linkPreviewHeight += AndroidUtilities.dp(44); + calcBackgroundWidth(maxWidth, timeMore, maxChildWidth); + } else if (MessageObject.isMusicDocument(document)) { + int durationWidth = createDocumentLayout(backgroundWidth - AndroidUtilities.dp(10), messageObject); + mediaOffsetY = currentMessageObject.textHeight + AndroidUtilities.dp(8) + linkPreviewHeight; + totalHeight += AndroidUtilities.dp(42 + 14); + linkPreviewHeight += AndroidUtilities.dp(56); + + maxWidth = maxWidth - AndroidUtilities.dp(86); + maxChildWidth = Math.max(maxChildWidth, durationWidth + additinalWidth + AndroidUtilities.dp(86 + 8)); + if (songLayout != null && songLayout.getLineCount() > 0) { + maxChildWidth = (int) Math.max(maxChildWidth, songLayout.getLineWidth(0) + additinalWidth + AndroidUtilities.dp(86)); + } + if (performerLayout != null && performerLayout.getLineCount() > 0) { + maxChildWidth = (int) Math.max(maxChildWidth, performerLayout.getLineWidth(0) + additinalWidth + AndroidUtilities.dp(86)); + } + + calcBackgroundWidth(maxWidth, timeMore, maxChildWidth); + } else { + createDocumentLayout(backgroundWidth - AndroidUtilities.dp(86 + 24 + 58), messageObject); + drawImageButton = true; + if (drawPhotoImage) { + totalHeight += AndroidUtilities.dp(86 + 14); + linkPreviewHeight += AndroidUtilities.dp(86); + photoImage.setImageCoords(0, totalHeight + namesOffset, AndroidUtilities.dp(86), AndroidUtilities.dp(86)); + } else { + mediaOffsetY = currentMessageObject.textHeight + AndroidUtilities.dp(8) + linkPreviewHeight; + photoImage.setImageCoords(0, totalHeight + namesOffset - AndroidUtilities.dp(14), AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + totalHeight += AndroidUtilities.dp(50 + 14); + linkPreviewHeight += AndroidUtilities.dp(50); + } + } + } + } + } else if (webPage.photo != null) { + drawImageButton = webPage.type != null && webPage.type.equals("photo"); + currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, drawImageButton ? AndroidUtilities.getPhotoSize() : maxPhotoWidth, !drawImageButton); + currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 80); + if (currentPhotoObjectThumb == currentPhotoObject) { + currentPhotoObjectThumb = null; + } } - linkImageView.setAllowStartAnimation(messageObject.audioProgress != 1); - currentPhotoObject = webPage.document.thumb; - isGifDocument = true; - } else if (webPage.photo != null) { - currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, drawImageButton ? AndroidUtilities.getPhotoSize() : maxPhotoWidth, !drawImageButton); + + if (documentAttachType != DOCUMENT_ATTACH_TYPE_MUSIC && documentAttachType != DOCUMENT_ATTACH_TYPE_AUDIO && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT) { + if (currentPhotoObject != null) { + drawImageButton = webPage.type != null && (webPage.type.equals("photo") || webPage.type.equals("document") && documentAttachType != DOCUMENT_ATTACH_TYPE_STICKER || webPage.type.equals("gif") || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO); + if (linkPreviewHeight != 0) { + linkPreviewHeight += AndroidUtilities.dp(2); + totalHeight += AndroidUtilities.dp(2); + } + + if (documentAttachType == DOCUMENT_ATTACH_TYPE_STICKER) { + if (AndroidUtilities.isTablet()) { + maxPhotoWidth = (int) (AndroidUtilities.getMinTabletSide() * 0.5f); + } else { + maxPhotoWidth = (int) (AndroidUtilities.displaySize.x * 0.5f); + } + } + + maxChildWidth = Math.max(maxChildWidth, maxPhotoWidth + additinalWidth); + currentPhotoObject.size = -1; + if (currentPhotoObjectThumb != null) { + currentPhotoObjectThumb.size = -1; + } + + int width; + int height; + if (smallImage) { + width = height = maxPhotoWidth; + } else { + width = currentPhotoObject.w; + height = currentPhotoObject.h; + float scale = width / (float) (maxPhotoWidth - AndroidUtilities.dp(2)); + width /= scale; + height /= scale; + if (webPage.site_name == null || webPage.site_name != null && !webPage.site_name.toLowerCase().equals("instagram") && documentAttachType == 0) { + if (height > AndroidUtilities.displaySize.y / 3) { + height = AndroidUtilities.displaySize.y / 3; + } + } + } + if (isSmallImage) { + if (AndroidUtilities.dp(50) + additionalHeight > linkPreviewHeight) { + totalHeight += AndroidUtilities.dp(50) + additionalHeight - linkPreviewHeight + AndroidUtilities.dp(8); + linkPreviewHeight = AndroidUtilities.dp(50) + additionalHeight; + } + linkPreviewHeight -= AndroidUtilities.dp(8); + } else { + totalHeight += height + AndroidUtilities.dp(12); + linkPreviewHeight += height; + } + + photoImage.setImageCoords(0, 0, width, height); + + currentPhotoFilter = String.format(Locale.US, "%d_%d", width, height); + currentPhotoFilterThumb = String.format(Locale.US, "%d_%d_b", width, height); + + if (documentAttachType == DOCUMENT_ATTACH_TYPE_STICKER) { + photoImage.setImage(documentAttach, null, currentPhotoFilter, null, currentPhotoObject != null ? currentPhotoObject.location : null, "b1", documentAttach.size, "webp", true); + } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { + photoImage.setImage(null, null, currentPhotoObject.location, currentPhotoFilter, 0, null, false); + } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { + boolean photoExist = messageObject.mediaExists; + String fileName = FileLoader.getAttachFileName(webPage.document); + if (photoExist || MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_GIF) || FileLoader.getInstance().isLoadingFile(fileName)) { + photoNotSet = false; + photoImage.setImage(webPage.document, null, currentPhotoObject.location, currentPhotoFilter, webPage.document.size, null, false); + } else { + photoNotSet = true; + photoImage.setImage(null, null, currentPhotoObject.location, currentPhotoFilter, 0, null, false); + } + } else { + boolean photoExist = messageObject.mediaExists; + String fileName = FileLoader.getAttachFileName(currentPhotoObject); + if (photoExist || MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_PHOTO) || FileLoader.getInstance().isLoadingFile(fileName)) { + photoNotSet = false; + photoImage.setImage(currentPhotoObject.location, currentPhotoFilter, currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, currentPhotoFilterThumb, 0, null, false); + } else { + photoNotSet = true; + if (currentPhotoObjectThumb != null) { + photoImage.setImage(null, null, currentPhotoObjectThumb.location, String.format(Locale.US, "%d_%d_b", width, height), 0, null, false); + } else { + photoImage.setImageBitmap((Drawable) null); + } + } + } + drawPhotoImage = true; + + if (webPage.type != null && webPage.type.equals("video") && webPage.duration != 0) { + int minutes = webPage.duration / 60; + int seconds = webPage.duration - minutes * 60; + String str = String.format("%d:%02d", minutes, seconds); + durationWidth = (int) Math.ceil(durationPaint.measureText(str)); + durationLayout = new StaticLayout(str, durationPaint, durationWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + } + } else { + photoImage.setImageBitmap((Drawable) null); + linkPreviewHeight -= AndroidUtilities.dp(6); + totalHeight += AndroidUtilities.dp(4); + } + calcBackgroundWidth(maxWidth, timeMore, maxChildWidth); + } + } else { + photoImage.setImageBitmap((Drawable) null); + calcBackgroundWidth(maxWidth, timeMore, maxChildWidth); + } + } else if (messageObject.type == 12) { + drawName = false; + drawForwardedName = true; + drawPhotoImage = true; + photoImage.setRoundRadius(AndroidUtilities.dp(22)); + if (AndroidUtilities.isTablet()) { + backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(270)); + } else { + backgroundWidth = Math.min(AndroidUtilities.displaySize.x - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(270)); + } + availableTimeWidth = backgroundWidth - AndroidUtilities.dp(31); + + int uid = messageObject.messageOwner.media.user_id; + TLRPC.User user = MessagesController.getInstance().getUser(uid); + + int maxWidth = getMaxNameWidth() - AndroidUtilities.dp(110); + if (maxWidth < 0) { + maxWidth = AndroidUtilities.dp(10); + } + + TLRPC.FileLocation currentPhoto = null; + if (user != null) { + if (user.photo != null) { + currentPhoto = user.photo.photo_small; + } + avatarDrawable.setInfo(user); + } + if(uid == 0) { + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int color = themePrefs.getInt("chatContactNameColor", themePrefs.getInt("themeColor", AndroidUtilities.defColor)); + avatarDrawable.setColor(color); + } + photoImage.setImage(currentPhoto, "50_50", user != null ? avatarDrawable : Theme.contactDrawable[messageObject.isOutOwner() ? 1 : 0], null, false); + + String phone = messageObject.messageOwner.media.phone_number; + if (phone != null && phone.length() != 0) { + if (!phone.startsWith("+")) { + phone = "+" + phone; + } + phone = PhoneFormat.getInstance().format(phone); + } else { + phone = LocaleController.getString("NumberUnknown", R.string.NumberUnknown); + } + + CharSequence currentNameString = ContactsController.formatName(messageObject.messageOwner.media.first_name, messageObject.messageOwner.media.last_name).replace('\n', ' '); + if (currentNameString.length() == 0) { + currentNameString = phone; + } + titleLayout = new StaticLayout(TextUtils.ellipsize(currentNameString, contactNamePaint, maxWidth, TextUtils.TruncateAt.END), contactNamePaint, maxWidth + AndroidUtilities.dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + captionLayout = new StaticLayout(TextUtils.ellipsize(phone.replace('\n', ' '), contactPhonePaint, maxWidth, TextUtils.TruncateAt.END), contactPhonePaint, maxWidth + AndroidUtilities.dp(2), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + + super.setMessageObject(messageObject); + + if (drawForwardedName && messageObject.isForwarded()) { + namesOffset += AndroidUtilities.dp(5); + } else if (drawNameLayout && messageObject.messageOwner.reply_to_msg_id == 0) { + namesOffset += AndroidUtilities.dp(7); + } + + totalHeight = AndroidUtilities.dp(70) + namesOffset; + } else if (messageObject.type == 2) { + drawForwardedName = true; + if (AndroidUtilities.isTablet()) { + backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(270)); + } else { + backgroundWidth = Math.min(AndroidUtilities.displaySize.x - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(270)); + } + createDocumentLayout(backgroundWidth, messageObject); + + super.setMessageObject(messageObject); + + totalHeight = AndroidUtilities.dp(70) + namesOffset; + } else if (messageObject.type == 14) { + if (AndroidUtilities.isTablet()) { + backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(270)); + } else { + backgroundWidth = Math.min(AndroidUtilities.displaySize.x - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(270)); + } + + createDocumentLayout(backgroundWidth, messageObject); + + super.setMessageObject(messageObject); + + //totalHeight = AndroidUtilities.dp(82) + namesOffset; + totalHeight = AndroidUtilities.dp(100) + namesOffset; //archivo de audio + } else { + drawForwardedName = messageObject.messageOwner.fwd_from != null && messageObject.type != 13; + mediaBackground = messageObject.type != 9; + drawImageButton = true; + drawPhotoImage = true; + + int photoWidth = 0; + int photoHeight = 0; + int additionHeight = 0; + + if (messageObject.audioProgress != 2 && !MediaController.getInstance().canAutoplayGifs() && messageObject.type == 8) { + messageObject.audioProgress = 1; + } + + photoImage.setAllowStartAnimation(messageObject.audioProgress == 0); + + photoImage.setForcePreview(messageObject.isSecretPhoto()); + if (messageObject.type == 9) { + radialProgress.setSizeAndType(messageObject.messageOwner.media.document.size, messageObject.type); // plus FILE + boolean hasSign = !messageObject.isOutOwner() && messageObject.messageOwner.from_id > 0 && messageObject.messageOwner.post; + if (AndroidUtilities.isTablet()) { + backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(270)); + } else { + backgroundWidth = Math.min(AndroidUtilities.displaySize.x - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(270)); + //backgroundWidth = Math.min(AndroidUtilities.displaySize.x - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(( (isChat && messageObject.messageOwner.from_id < 0) || hasSign ? 15 : leftBound) + 70 + 86 + 24)); + //if(!messageObject.isOutOwner() && (!isChat && showAvatar || isChat && messageObject.isFromUser()))backgroundWidth = backgroundWidth - AndroidUtilities.dp(15); + } + //if (checkNeedDrawShareButton(messageObject)) { + if (checkNeedDrawShareButton(messageObject) && messageObject.messageOwner.to_id.channel_id <= 0) { + backgroundWidth -= AndroidUtilities.dp(20); + } + int maxWidth = backgroundWidth - AndroidUtilities.dp(86 + 52); + + createDocumentLayout(maxWidth, messageObject); + if (drawPhotoImage) { + photoWidth = AndroidUtilities.dp(86); + photoHeight = AndroidUtilities.dp(86); + } else { + photoWidth = AndroidUtilities.dp(56); + photoHeight = AndroidUtilities.dp(56); + } + availableTimeWidth = maxWidth; + } else if (messageObject.type == 4) { //geo + double lat = messageObject.messageOwner.media.geo.lat; + double lon = messageObject.messageOwner.media.geo._long; + + if (messageObject.messageOwner.media.title != null && messageObject.messageOwner.media.title.length() > 0) { + if (AndroidUtilities.isTablet()) { + backgroundWidth = Math.min(AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(270)); + } else { + backgroundWidth = Math.min(AndroidUtilities.displaySize.x - AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 102 : 50), AndroidUtilities.dp(270)); + } + if (checkNeedDrawShareButton(messageObject)) { + backgroundWidth -= AndroidUtilities.dp(20); + } + int maxWidth = backgroundWidth - AndroidUtilities.dp(86 + 37); + + captionLayout = StaticLayoutEx.createStaticLayout(messageObject.messageOwner.media.title, locationTitlePaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, maxWidth, 2); + int lineCount = captionLayout.getLineCount(); + if (messageObject.messageOwner.media.address != null && messageObject.messageOwner.media.address.length() > 0) { + infoLayout = StaticLayoutEx.createStaticLayout(messageObject.messageOwner.media.address, locationAddressPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, maxWidth, Math.min(3, 3 - lineCount)); + } else { + infoLayout = null; + } + + mediaBackground = false; + availableTimeWidth = maxWidth; + photoWidth = AndroidUtilities.dp(86); + photoHeight = AndroidUtilities.dp(86); + currentUrl = String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%f,%f&zoom=15&size=72x72&maptype=roadmap&scale=%d&markers=color:red|size:mid|%f,%f&sensor=false", lat, lon, Math.min(2, (int) Math.ceil(AndroidUtilities.density)), lat, lon); + } else { + availableTimeWidth = AndroidUtilities.dp(200 - 14); + photoWidth = AndroidUtilities.dp(200); + photoHeight = AndroidUtilities.dp(100); + backgroundWidth = photoWidth + AndroidUtilities.dp(12); + currentUrl = String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%f,%f&zoom=15&size=200x100&maptype=roadmap&scale=%d&markers=color:red|size:mid|%f,%f&sensor=false", lat, lon, Math.min(2, (int) Math.ceil(AndroidUtilities.density)), lat, lon); + } + photoImage.setImage(currentUrl, null, messageObject.isOutOwner() ? Theme.geoOutDrawable : Theme.geoInDrawable, null, 0); + } else if (messageObject.type == 13) { //webp + drawBackground = false; + for (int a = 0; a < messageObject.messageOwner.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = messageObject.messageOwner.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeImageSize) { + photoWidth = attribute.w; + photoHeight = attribute.h; + break; + } + } + float maxHeight = AndroidUtilities.displaySize.y * 0.4f; + float maxWidth; + if (AndroidUtilities.isTablet()) { + maxWidth = AndroidUtilities.getMinTabletSide() * 0.5f; + } else { + maxWidth = AndroidUtilities.displaySize.x * 0.5f; + } + if (photoWidth == 0) { + photoHeight = (int) maxHeight; + photoWidth = photoHeight + AndroidUtilities.dp(100); + } + if (photoHeight > maxHeight) { + photoWidth *= maxHeight / photoHeight; + photoHeight = (int) maxHeight; + } + //else { + if (photoWidth > maxWidth) { // 3.7.0 + photoHeight *= maxWidth / photoWidth; + photoWidth = (int) maxWidth; + } + documentAttachType = DOCUMENT_ATTACH_TYPE_STICKER; + availableTimeWidth = photoWidth - AndroidUtilities.dp(14); + backgroundWidth = photoWidth + AndroidUtilities.dp(12); currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 80); - if (currentPhotoObjectThumb == currentPhotoObject) { + if (messageObject.attachPathExists) { + photoImage.setImage(null, messageObject.messageOwner.attachPath, + String.format(Locale.US, "%d_%d", photoWidth, photoHeight), + null, + currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, + "b1", + messageObject.messageOwner.media.document.size, "webp", true); + } else if (messageObject.messageOwner.media.document.id != 0) { + photoImage.setImage(messageObject.messageOwner.media.document, null, + String.format(Locale.US, "%d_%d", photoWidth, photoHeight), + null, + currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, + "b1", + messageObject.messageOwner.media.document.size, "webp", true); + } + radialProgress.setSizeAndType(messageObject.messageOwner.media.document.size, messageObject.type); //plus STICKER WEBP type=13 + } else { + int maxPhotoWidth; + if (AndroidUtilities.isTablet()) { + maxPhotoWidth = photoWidth = (int) (AndroidUtilities.getMinTabletSide() * 0.7f); + } else { + //maxPhotoWidth = photoWidth = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.7f); + maxPhotoWidth = photoWidth = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.68f); + } + photoHeight = photoWidth + AndroidUtilities.dp(100); + if (checkNeedDrawShareButton(messageObject)) { + maxPhotoWidth -= AndroidUtilities.dp(20); + photoWidth -= AndroidUtilities.dp(20); + } + + if (photoWidth > AndroidUtilities.getPhotoSize()) { + photoWidth = AndroidUtilities.getPhotoSize(); + } + if (photoHeight > AndroidUtilities.getPhotoSize()) { + photoHeight = AndroidUtilities.getPhotoSize(); + } + + if (messageObject.type == 1) { //photo + updateSecretTimeText(messageObject); + currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 80); + } else if (messageObject.type == 3) { //video + createDocumentLayout(0, messageObject); + //Plus + radialProgress.setSizeAndType(messageObject.messageOwner.media.document.size, messageObject.type); + infoLayout2 = null; + /*String senderName = getCurrentNameString(messageObject); + if(isChat && !senderName.equals("DELETED")){ + infoOffset2 = Theme.videoIconDrawable.getIntrinsicWidth() + AndroidUtilities.dp(5); + infoOffset = 0; + infoWidth2 = (int) Math.ceil(infoPaint.measureText(str)); + infoWidth = Math.max(infoWidth2, (int) Math.ceil(senderPaint.measureText(senderName))); + infoLayout = new StaticLayout(senderName, senderPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + infoLayout2 = new StaticLayout(str, infoPaint, infoWidth2, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + }*/ + // + photoImage.setNeedsQualityThumb(true); + photoImage.setShouldGenerateQualityThumb(true); + photoImage.setParentMessageObject(messageObject); + } else if (messageObject.type == 8) { //gif + String str = AndroidUtilities.formatFileSize(messageObject.messageOwner.media.document.size); + radialProgress.setSizeAndType(messageObject.messageOwner.media.document.size, messageObject.type); //plus GIF + infoWidth = (int) Math.ceil(infoPaint.measureText(str)); + infoLayout = new StaticLayout(str, infoPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + + photoImage.setNeedsQualityThumb(true); + photoImage.setShouldGenerateQualityThumb(true); + photoImage.setParentMessageObject(messageObject); + infoLayout2 = null; + } + //Plus + else { + infoLayout2 = null; //Plus + } + // + + if (messageObject.caption != null) { + mediaBackground = false; + } + + currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, AndroidUtilities.getPhotoSize()); + + int w = 0; + int h = 0; + + if (currentPhotoObject != null && currentPhotoObject == currentPhotoObjectThumb) { currentPhotoObjectThumb = null; } - } if (currentPhotoObject != null) { - drawImageButton = webPage.type != null && (webPage.type.equals("photo") || webPage.type.equals("document") || webPage.type.equals("gif")); - if (linkPreviewHeight != 0) { - linkPreviewHeight += AndroidUtilities.dp(2); - totalHeight += AndroidUtilities.dp(2); + float scale = (float) currentPhotoObject.w / (float) photoWidth; + w = (int) (currentPhotoObject.w / scale); + h = (int) (currentPhotoObject.h / scale); + if (w == 0) { + w = AndroidUtilities.dp(150); } - - maxChildWidth = Math.max(maxChildWidth, maxPhotoWidth + additinalWidth); - currentPhotoObject.size = -1; - if (currentPhotoObjectThumb != null) { - currentPhotoObjectThumb.size = -1; + if (h == 0) { + h = AndroidUtilities.dp(150); } + if (h > photoHeight) { + float scale2 = h; + h = photoHeight; + scale2 /= h; + w = (int) (w / scale2); + } else if (h < AndroidUtilities.dp(120)) { + h = AndroidUtilities.dp(120); + float hScale = (float) currentPhotoObject.h / h; + if (currentPhotoObject.w / hScale < photoWidth) { + w = (int) (currentPhotoObject.w / hScale); + } + } + } - int width; - int height; - if (smallImage) { - width = height = maxPhotoWidth; + if ((w == 0 || h == 0) && messageObject.type == 8) { + for (int a = 0; a < messageObject.messageOwner.media.document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = messageObject.messageOwner.media.document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeImageSize || attribute instanceof TLRPC.TL_documentAttributeVideo) { + float scale = (float) attribute.w / (float) photoWidth; + w = (int) (attribute.w / scale); + h = (int) (attribute.h / scale); + if (h > photoHeight) { + float scale2 = h; + h = photoHeight; + scale2 /= h; + w = (int) (w / scale2); + } else if (h < AndroidUtilities.dp(120)) { + h = AndroidUtilities.dp(120); + float hScale = (float) attribute.h / h; + if (attribute.w / hScale < photoWidth) { + w = (int) (attribute.w / hScale); + } + } + break; + } + } + } + + + if (w == 0 || h == 0) { + w = h = AndroidUtilities.dp(150); + } + if (messageObject.type == 3) { + if (w < infoWidth + AndroidUtilities.dp(16 + 24)) { + w = infoWidth + AndroidUtilities.dp(16 + 24); + } + } + + availableTimeWidth = maxPhotoWidth - AndroidUtilities.dp(14); + measureTime(messageObject); + int timeWidthTotal = timeWidth + AndroidUtilities.dp(14 + (messageObject.isOutOwner() ? 20 : 0)); + if (w < timeWidthTotal) { + w = timeWidthTotal; + } + + if (messageObject.isSecretPhoto()) { + if (AndroidUtilities.isTablet()) { + w = h = (int) (AndroidUtilities.getMinTabletSide() * 0.5f); } else { - width = currentPhotoObject.w; - height = currentPhotoObject.h; - float scale = width / (float) maxPhotoWidth; - width /= scale; - height /= scale; - if (webPage.site_name == null || webPage.site_name != null && !webPage.site_name.toLowerCase().equals("instagram") && !isGifDocument) { - if (height > AndroidUtilities.displaySize.y / 3) { - height = AndroidUtilities.displaySize.y / 3; + w = h = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.5f); + } + } + + photoWidth = w; + photoHeight = h; + backgroundWidth = w + AndroidUtilities.dp(12); + if (!mediaBackground) { + backgroundWidth += AndroidUtilities.dp(9); + } + if (messageObject.caption != null) { + try { + + if(messageObject.isOutOwner()){ //fix caption color bug + MessageObject.textPaint = MessageObject.textPaintRight; + }else{ + MessageObject.textPaint = MessageObject.textPaintLeft; + } + //captionLayout = new StaticLayout(messageObject.caption, MessageObject.getTextPaint(), photoWidth - AndroidUtilities.dp(10), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + captionLayout = new StaticLayout(messageObject.caption, MessageObject.textPaint, photoWidth - AndroidUtilities.dp(10), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + if (captionLayout != null && captionLayout.getLineCount() > 0) { + captionHeight = captionLayout.getHeight(); + additionHeight += captionHeight + AndroidUtilities.dp(9); + float lastLineWidth = captionLayout.getLineWidth(captionLayout.getLineCount() - 1) + captionLayout.getLineLeft(captionLayout.getLineCount() - 1); + if (photoWidth - AndroidUtilities.dp(8) - lastLineWidth < timeWidthTotal) { + additionHeight += AndroidUtilities.dp(14); } } + } catch (Exception e) { + FileLog.e("tmessages", e); } - if (isSmallImage) { - if (AndroidUtilities.dp(50) + additionalHeight > linkPreviewHeight) { - totalHeight += AndroidUtilities.dp(50) + additionalHeight - linkPreviewHeight + AndroidUtilities.dp(8); - linkPreviewHeight = AndroidUtilities.dp(50) + additionalHeight; - } - linkPreviewHeight -= AndroidUtilities.dp(8); + } + + currentPhotoFilter = String.format(Locale.US, "%d_%d", (int) (w / AndroidUtilities.density), (int) (h / AndroidUtilities.density)); + if (messageObject.photoThumbs != null && messageObject.photoThumbs.size() > 1 || messageObject.type == 3 || messageObject.type == 8) { + if (messageObject.isSecretPhoto()) { + currentPhotoFilter += "_b2"; } else { - totalHeight += height + AndroidUtilities.dp(12); - linkPreviewHeight += height; + currentPhotoFilter += "_b"; } + } - linkImageView.setImageCoords(0, 0, width, height); + boolean noSize = false; + if (messageObject.type == 3 || messageObject.type == 8) { + noSize = true; + } + if (currentPhotoObject != null && !noSize && currentPhotoObject.size == 0) { + currentPhotoObject.size = -1; + } - currentPhotoFilter = String.format(Locale.US, "%d_%d", width, height); - currentPhotoFilterThumb = String.format(Locale.US, "%d_%d_b", width, height); - - if (isGifDocument) { - boolean photoExist = true; - File cacheFile = FileLoader.getPathToAttach(webPage.document); - if (!cacheFile.exists()) { - photoExist = false; + if (messageObject.type == 1) { + if (currentPhotoObject != null) { + boolean photoExist = true; + String fileName = FileLoader.getAttachFileName(currentPhotoObject); + if (messageObject.mediaExists) { + MediaController.getInstance().removeLoadingFileObserver(this); + } else { + photoExist = false; + } + if (photoExist || MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_PHOTO) || FileLoader.getInstance().isLoadingFile(fileName)) { + if (allowedToSetPhoto || ImageLoader.getInstance().getImageFromMemory(currentPhotoObject.location, null, currentPhotoFilter) != null) { + allowedToSetPhoto = true; + photoImage.setImage(currentPhotoObject.location, currentPhotoFilter, currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, currentPhotoFilter, noSize ? 0 : currentPhotoObject.size, null, false); + } else if (currentPhotoObjectThumb != null) { + photoImage.setImage(null, null, currentPhotoObjectThumb.location, currentPhotoFilter, 0, null, false); + } else { + photoImage.setImageBitmap((Drawable) null); + } + } else { + photoNotSet = true; + if (currentPhotoObjectThumb != null) { + photoImage.setImage(null, null, currentPhotoObjectThumb.location, currentPhotoFilter, 0, null, false); + } else { + photoImage.setImageBitmap((Drawable) null); + } + } + } else { + photoImage.setImageBitmap((BitmapDrawable) null); } - String fileName = FileLoader.getAttachFileName(webPage.document); - if (photoExist || MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_GIF) || FileLoader.getInstance().isLoadingFile(fileName)) { - photoNotSet = false; - linkImageView.setImage(webPage.document, null, currentPhotoObject.location, currentPhotoFilter, webPage.document.size, null, false); + } else if (messageObject.type == 8) { + String fileName = FileLoader.getAttachFileName(messageObject.messageOwner.media.document); + int localFile = 0; + if (messageObject.attachPathExists) { + MediaController.getInstance().removeLoadingFileObserver(this); + localFile = 1; + } else if (messageObject.mediaExists) { + localFile = 2; + } + if (!messageObject.isSending() && (localFile != 0 || MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_GIF) && MessageObject.isNewGifDocument(messageObject.messageOwner.media.document) || FileLoader.getInstance().isLoadingFile(fileName))) { + if (localFile == 1) { + photoImage.setImage(null, messageObject.isSendError() ? null : messageObject.messageOwner.attachPath, null, null, currentPhotoObject != null ? currentPhotoObject.location : null, currentPhotoFilter, 0, null, false); + } else { + photoImage.setImage(messageObject.messageOwner.media.document, null, currentPhotoObject != null ? currentPhotoObject.location : null, currentPhotoFilter, messageObject.messageOwner.media.document.size, null, false); + } } else { photoNotSet = true; - linkImageView.setImage(null, null, currentPhotoObject.location, currentPhotoFilter, 0, null, false); + photoImage.setImage(null, null, currentPhotoObject != null ? currentPhotoObject.location : null, currentPhotoFilter, 0, null, false); } } else { - boolean photoExist = true; - File cacheFile = FileLoader.getPathToAttach(currentPhotoObject, true); - if (!cacheFile.exists()) { - photoExist = false; - } - String fileName = FileLoader.getAttachFileName(currentPhotoObject); - if (photoExist || MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_PHOTO) || FileLoader.getInstance().isLoadingFile(fileName)) { - photoNotSet = false; - linkImageView.setImage(currentPhotoObject.location, currentPhotoFilter, currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, currentPhotoFilterThumb, 0, null, false); - } else { - photoNotSet = true; - if (currentPhotoObjectThumb != null) { - linkImageView.setImage(null, null, currentPhotoObjectThumb.location, String.format(Locale.US, "%d_%d_b", width, height), 0, null, false); - } else { - linkImageView.setImageBitmap((Drawable) null); - } - } + photoImage.setImage(null, null, currentPhotoObject != null ? currentPhotoObject.location : null, currentPhotoFilter, 0, null, false); } - drawLinkImageView = true; - - if (webPage.site_name != null) { - if (webPage.site_name.toLowerCase().equals("instagram") && webPage.type != null && webPage.type.equals("video")) { - isInstagram = true; - if (igvideoDrawable == null) { - igvideoDrawable = getResources().getDrawable(R.drawable.igvideo); - } - } - } - - if (webPage.type != null && webPage.type.equals("video") && webPage.duration != 0) { - if (durationPaint == null) { - durationPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - durationPaint.setTextSize(AndroidUtilities.dp(12)); - durationPaint.setColor(0xffffffff); - } - int minutes = webPage.duration / 60; - int seconds = webPage.duration - minutes * 60; - String str = String.format("%d:%02d", minutes, seconds); - durationWidth = (int) Math.ceil(durationPaint.measureText(str)); - durationLayout = new StaticLayout(str, durationPaint, durationWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - } - } else { - linkImageView.setImageBitmap((Drawable) null); - linkPreviewHeight -= AndroidUtilities.dp(6); - totalHeight += AndroidUtilities.dp(4); } - } else { - linkImageView.setImageBitmap((Drawable) null); + super.setMessageObject(messageObject); + + if (drawForwardedName) { + namesOffset += AndroidUtilities.dp(5); + } else if (drawNameLayout && messageObject.messageOwner.reply_to_msg_id == 0) { + namesOffset += AndroidUtilities.dp(7); + } + + invalidate(); + + photoImage.setImageCoords(0, AndroidUtilities.dp(7) + namesOffset, photoWidth, photoHeight); + totalHeight = photoHeight + AndroidUtilities.dp(14) + namesOffset + additionHeight; + //plus + if(messageObject.type == DOCUMENT_ATTACH_TYPE_DOCUMENT && !drawPhotoImage){ // file bubble height + totalHeight = totalHeight + AndroidUtilities.dp(10); + } } + botButtons.clear(); + if (messageIdChanged) { + botButtonsByData.clear(); + } + if (messageObject.messageOwner.reply_markup instanceof TLRPC.TL_replyInlineMarkup) { + int rows = messageObject.messageOwner.reply_markup.rows.size(); + substractBackgroundHeight = keyboardHeight = AndroidUtilities.dp(44 + 4) * rows + AndroidUtilities.dp(1); - if (hasLinkPreview || maxWidth - messageObject.lastLineWidth < timeMore) { - totalHeight += AndroidUtilities.dp(14); - backgroundWidth = Math.max(maxChildWidth, messageObject.lastLineWidth) + AndroidUtilities.dp(29); - //Log.e("ChatMessageCell","4 backgroundWidth: " + backgroundWidth + " hasLinkPreview: " + hasLinkPreview + " maxChildWidth: " + maxChildWidth + " lastLineWidth: " + messageObject.lastLineWidth); - } else { - int diff = maxChildWidth - messageObject.lastLineWidth; - if (diff >= 0 && diff <= timeMore) { - backgroundWidth = maxChildWidth + timeMore - diff + AndroidUtilities.dp(29); - //Log.e("ChatMessageCell","5 backgroundWidth: " + backgroundWidth); - } else { - backgroundWidth = Math.max(maxChildWidth, messageObject.lastLineWidth + timeMore) + AndroidUtilities.dp(29); - //Log.e("ChatMessageCell","6 backgroundWidth: " + backgroundWidth); + widthForButtons = backgroundWidth; + boolean fullWidth = false; + if (messageObject.wantedBotKeyboardWidth > widthForButtons) { + int maxButtonWidth = -AndroidUtilities.dp(isChat && messageObject.isFromUser() && !messageObject.isOutOwner() ? 62 : 10); + if (AndroidUtilities.isTablet()) { + maxButtonWidth += AndroidUtilities.getMinTabletSide(); + } else { + maxButtonWidth += Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y); + } + widthForButtons = Math.max(backgroundWidth, Math.min(messageObject.wantedBotKeyboardWidth, maxButtonWidth)); + fullWidth = true; } + + int maxButtonsWidth = 0; + for (int a = 0; a < rows; a++) { + TLRPC.TL_keyboardButtonRow row = messageObject.messageOwner.reply_markup.rows.get(a); + int buttonsCount = row.buttons.size(); + int buttonWidth = (widthForButtons - (AndroidUtilities.dp(5) * (buttonsCount - 1)) - AndroidUtilities.dp(!fullWidth && mediaBackground ? 0 : 9) - AndroidUtilities.dp(2)) / buttonsCount; + for (int b = 0; b < row.buttons.size(); b++) { + BotButton botButton = new BotButton(); + botButton.button = row.buttons.get(b); + String key = Utilities.bytesToHex(botButton.button.data); + BotButton oldButton = botButtonsByData.get(key); + if (oldButton != null) { + botButton.progressAlpha = oldButton.progressAlpha; + botButton.angle = oldButton.angle; + botButton.lastUpdateTime = oldButton.lastUpdateTime; + } else { + botButton.lastUpdateTime = System.currentTimeMillis(); + } + botButtonsByData.put(key, botButton); + botButton.x = b * (buttonWidth + AndroidUtilities.dp(5)); + botButton.y = a * AndroidUtilities.dp(44 + 4) + AndroidUtilities.dp(5); + botButton.width = buttonWidth; + botButton.height = AndroidUtilities.dp(44); + CharSequence caption = Emoji.replaceEmoji(botButton.button.text, botButtonPaint.getFontMetricsInt(), AndroidUtilities.dp(15), false); + caption = TextUtils.ellipsize(caption, botButtonPaint, buttonWidth - AndroidUtilities.dp(10), TextUtils.TruncateAt.END); + botButton.caption = new StaticLayout(caption, botButtonPaint, buttonWidth - AndroidUtilities.dp(10), Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false); + botButtons.add(botButton); + if (b == row.buttons.size() - 1) { + maxButtonsWidth = Math.max(maxButtonsWidth, botButton.x + botButton.width); + } + } + } + widthForButtons = maxButtonsWidth; + } else { + substractBackgroundHeight = 0; + keyboardHeight = 0; } //Plus if( ( showAvatar && !isChat && !messageObject.isOutOwner() ) || ((( (showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) && messageObject.isOutOwner()))){ if ((totalHeight < avatarSize)) { totalHeight = avatarSize + AndroidUtilities.dp(10); } - //Log.e("ChatMessageCell","7 " + backgroundWidth); - if(backgroundWidth > Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(leftBound + 70) && hasLinkPreview){ - //Log.e("ChatMessageCell","8 YES"); - } } } + updateWaveform(); updateButtonState(dataChanged); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), totalHeight); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), totalHeight + keyboardHeight); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); - if (currentMessageObject.isOutOwner()) { - //textX = layoutWidth - backgroundWidth + AndroidUtilities.dp(10); - textX = layoutWidth - backgroundWidth + AndroidUtilities.dp(10) - ((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat) ? AndroidUtilities.dp(leftBound) : 0); + if (currentMessageObject.type == 0) { + //plus + if (currentMessageObject.isOutOwner()) { + //textX = layoutWidth - backgroundWidth + AndroidUtilities.dp(10) - ((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat) ? AndroidUtilities.dp(leftBound) : 0); + } else { + //textX = AndroidUtilities.dp(19) + ((isChat || showAvatar) && currentMessageObject.isFromUser() ? AndroidUtilities.dp(leftBound) : 0); + } + // textY = AndroidUtilities.dp(10) + namesOffset; + } + if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO) { + if (currentMessageObject.isOutOwner()) { + //seekBarX = layoutWidth - backgroundWidth + AndroidUtilities.dp(57); + //buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(14); + //timeAudioX = layoutWidth - backgroundWidth + AndroidUtilities.dp(67); + seekBarX = layoutWidth - backgroundWidth + AndroidUtilities.dp(57) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); + buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(14) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); + timeAudioX = layoutWidth - backgroundWidth + AndroidUtilities.dp(67) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); + } else { + //if (isChat && currentMessageObject.isFromUser()) { + if ((isChat || showAvatar) && currentMessageObject.isFromUser()) { + //seekBarX = AndroidUtilities.dp(114); + //buttonX = AndroidUtilities.dp(71); + //timeAudioX = AndroidUtilities.dp(124); + seekBarX = AndroidUtilities.dp(leftBound + 66); + buttonX = AndroidUtilities.dp(leftBound + 23); + timeAudioX = AndroidUtilities.dp(leftBound + 76); + } else { + seekBarX = AndroidUtilities.dp(66); + buttonX = AndroidUtilities.dp(23); + timeAudioX = AndroidUtilities.dp(76); + } + } + if (hasLinkPreview) { + seekBarX += AndroidUtilities.dp(10); + buttonX += AndroidUtilities.dp(10); + timeAudioX += AndroidUtilities.dp(10); + } + seekBarWaveform.setSize(backgroundWidth - AndroidUtilities.dp(92 + (hasLinkPreview ? 10 : 0)), AndroidUtilities.dp(30)); + seekBar.setSize(backgroundWidth - AndroidUtilities.dp(72 + (hasLinkPreview ? 10 : 0)), AndroidUtilities.dp(30)); + seekBarY = AndroidUtilities.dp(13) + namesOffset + mediaOffsetY; + buttonY = AndroidUtilities.dp(13) + namesOffset + mediaOffsetY; + radialProgress.setProgressRect(buttonX, buttonY, buttonX + AndroidUtilities.dp(44), buttonY + AndroidUtilities.dp(44)); + + updateAudioProgress(); + } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { + if (currentMessageObject.isOutOwner()) { + //seekBarX = layoutWidth - backgroundWidth + AndroidUtilities.dp(56); + //buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(14); + //timeAudioX = layoutWidth - backgroundWidth + AndroidUtilities.dp(67); + seekBarX = layoutWidth - backgroundWidth + AndroidUtilities.dp(56) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); + buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(14) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); + timeAudioX = layoutWidth - backgroundWidth + AndroidUtilities.dp(67) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); + } else { + //if (isChat && currentMessageObject.isFromUser()) { + if ((isChat || showAvatar) && currentMessageObject.isFromUser()) { + //seekBarX = AndroidUtilities.dp(113); + //buttonX = AndroidUtilities.dp(71); + //timeAudioX = AndroidUtilities.dp(124); + seekBarX = AndroidUtilities.dp(leftBound + 65); + buttonX = AndroidUtilities.dp(leftBound + 23); + timeAudioX = AndroidUtilities.dp(leftBound + 76); + } else { + seekBarX = AndroidUtilities.dp(65); + buttonX = AndroidUtilities.dp(23); + timeAudioX = AndroidUtilities.dp(76); + } + } + if (hasLinkPreview) { + seekBarX += AndroidUtilities.dp(10); + buttonX += AndroidUtilities.dp(10); + timeAudioX += AndroidUtilities.dp(10); + } + seekBar.setSize(backgroundWidth - AndroidUtilities.dp(65 + (hasLinkPreview ? 10 : 0)), AndroidUtilities.dp(30)); + seekBarY = AndroidUtilities.dp(29) + namesOffset + mediaOffsetY; + buttonY = AndroidUtilities.dp(13) + namesOffset + mediaOffsetY; + radialProgress.setProgressRect(buttonX, buttonY, buttonX + AndroidUtilities.dp(44), buttonY + AndroidUtilities.dp(44)); + + updateAudioProgress(); + } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT && !drawPhotoImage) { + if (currentMessageObject.isOutOwner()) { + //buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(14); + buttonX = layoutWidth - backgroundWidth + AndroidUtilities.dp(14) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); + } else { + //if (isChat && currentMessageObject.isFromUser()) { + if ((isChat || showAvatar) && currentMessageObject.isFromUser()) { + //buttonX = AndroidUtilities.dp(71); + buttonX = AndroidUtilities.dp(leftBound + 23); + } else { + buttonX = AndroidUtilities.dp(23); + } + } + if (hasLinkPreview) { + buttonX += AndroidUtilities.dp(10); + } + buttonY = AndroidUtilities.dp(13) + namesOffset + mediaOffsetY; + radialProgress.setProgressRect(buttonX, buttonY, buttonX + AndroidUtilities.dp(44), buttonY + AndroidUtilities.dp(44)); + photoImage.setImageCoords(buttonX - AndroidUtilities.dp(10), buttonY - AndroidUtilities.dp(10), photoImage.getImageWidth(), photoImage.getImageHeight()); + } else if (currentMessageObject.type == 12) { + int x; + + if (currentMessageObject.isOutOwner()) { + //x = layoutWidth - backgroundWidth + AndroidUtilities.dp(14); + x = layoutWidth - backgroundWidth + AndroidUtilities.dp(14) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); + } else { + //if (isChat && currentMessageObject.isFromUser()) { + if ((isChat || showAvatar) && currentMessageObject.isFromUser()) { + //x = AndroidUtilities.dp(72); + x = AndroidUtilities.dp(leftBound + 23); + } else { + x = AndroidUtilities.dp(23); + } + } + photoImage.setImageCoords(x, AndroidUtilities.dp(13) + namesOffset, AndroidUtilities.dp(44), AndroidUtilities.dp(44)); } else { - //textX = AndroidUtilities.dp(19) + (isChat && currentMessageObject.messageOwner.from_id > 0 ? AndroidUtilities.dp(52) : 0); - textX = AndroidUtilities.dp(19) + ((isChat || showAvatar) && currentMessageObject.messageOwner.from_id > 0 ? AndroidUtilities.dp(leftBound) : 0); - textY = AndroidUtilities.dp(10) + namesOffset; + int x; + if (currentMessageObject.isOutOwner()) { + if (mediaBackground) { + //x = layoutWidth - backgroundWidth - AndroidUtilities.dp(3); + x = layoutWidth - backgroundWidth - AndroidUtilities.dp(3) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); + } else { + //x = layoutWidth - backgroundWidth + AndroidUtilities.dp(6); + x = layoutWidth - backgroundWidth + AndroidUtilities.dp(6) - (((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat)) ? AndroidUtilities.dp(leftBound) : 0); + } + } else { + //if (isChat && currentMessageObject.isFromUser()) { + if ((isChat || showAvatar) && currentMessageObject.isFromUser()) { + //x = AndroidUtilities.dp(63); + x = AndroidUtilities.dp(leftBound + 15); + } else { + x = AndroidUtilities.dp(15); + } + } + photoImage.setImageCoords(x, photoImage.getImageY(), photoImage.getImageWidth(), photoImage.getImageHeight()); + buttonX = (int) (x + (photoImage.getImageWidth() - AndroidUtilities.dp(48)) / 2.0f); + buttonY = (int) (AndroidUtilities.dp(7) + (photoImage.getImageHeight() - AndroidUtilities.dp(48)) / 2.0f) + namesOffset; + radialProgress.setProgressRect(buttonX, buttonY, buttonX + AndroidUtilities.dp(48), buttonY + AndroidUtilities.dp(48)); + deleteProgressRect.set(buttonX + AndroidUtilities.dp(3), buttonY + AndroidUtilities.dp(3), buttonX + AndroidUtilities.dp(45), buttonY + AndroidUtilities.dp(45)); } } @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - if (currentMessageObject == null || currentMessageObject.textLayoutBlocks == null || currentMessageObject.textLayoutBlocks.isEmpty()) { - return; + protected void drawContent(Canvas canvas) { + + if (needNewVisiblePart && currentMessageObject.type == 0) { + getLocalVisibleRect(scrollRect); + setVisiblePart(scrollRect.top, scrollRect.bottom - scrollRect.top); + needNewVisiblePart = false; } - if (currentMessageObject.isOutOwner()) { - //textX = layoutWidth - backgroundWidth + AndroidUtilities.dp(10); - textX = layoutWidth - backgroundWidth + AndroidUtilities.dp(10) - ( (showMyAvatar && !isChat) || (showMyAvatarGroup && isChat) ? AndroidUtilities.dp(leftBound) : 0); - textY = AndroidUtilities.dp(10) + namesOffset; - } else { - //textX = AndroidUtilities.dp(19) + (isChat && currentMessageObject.messageOwner.from_id > 0 ? AndroidUtilities.dp(52) : 0); - textX = AndroidUtilities.dp(19) + ((isChat || showAvatar) && currentMessageObject.messageOwner.from_id > 0 ? AndroidUtilities.dp(leftBound) : 0); - textY = AndroidUtilities.dp(10) + namesOffset; - } + photoImage.setPressed(isDrawSelectedBackground()); + photoImage.setVisible(!PhotoViewer.getInstance().isShowingImage(currentMessageObject), false); + radialProgress.setHideCurrentDrawable(false); + radialProgress.setProgressColor(Theme.MSG_MEDIA_PROGRESS_COLOR); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - if (firstVisibleBlockNum >= 0) { - for (int a = firstVisibleBlockNum; a <= lastVisibleBlockNum; a++) { - if (a >= currentMessageObject.textLayoutBlocks.size()) { - break; + boolean imageDrawn = false; + if (currentMessageObject.type == 0 && currentMessageObject.textLayoutBlocks != null && !currentMessageObject.textLayoutBlocks.isEmpty()) { + if (currentMessageObject.isOutOwner()) { + textX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(11); + //textX = layoutWidth - backgroundWidth + AndroidUtilities.dp(10); + //textX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(11) - ((showMyAvatar && !isChat) || (showMyAvatarGroup && isChat) ? AndroidUtilities.dp(leftBound) : 0); + } else { + textX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(17); + //textX = AndroidUtilities.dp(17) + (isChat && currentMessageObject.isFromUser() ? AndroidUtilities.dp(52) : 0); + //textX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(17) + ((isChat || showAvatar) && currentMessageObject.isFromUser() ? AndroidUtilities.dp(leftBound) : 0); + } + + textY = AndroidUtilities.dp(10) + namesOffset; + + if (firstVisibleBlockNum >= 0) { + for (int a = firstVisibleBlockNum; a <= lastVisibleBlockNum; a++) { + if (a >= currentMessageObject.textLayoutBlocks.size()) { + break; + } + MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(a); + canvas.save(); + canvas.translate(textX - (int) Math.ceil(block.textXOffset), textY + block.textYOffset); + if (pressedLink != null && a == linkBlockNum) { + for (int b = 0; b < urlPath.size(); b++) { + canvas.drawPath(urlPath.get(b), urlPaint); + } + } + try { + block.textLayout.draw(canvas); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + canvas.restore(); } - MessageObject.TextLayoutBlock block = currentMessageObject.textLayoutBlocks.get(a); + } + + if (hasLinkPreview) { + int startY = textY + currentMessageObject.textHeight + AndroidUtilities.dp(8); + int linkX = textX + AndroidUtilities.dp(1); + int linkPreviewY = startY; + int smallImageStartY = 0; + //replyLinePaint.setColor(currentMessageObject.isOutOwner() ? Theme.MSG_OUT_WEB_PREVIEW_LINE_COLOR : Theme.MSG_IN_WEB_PREVIEW_LINE_COLOR); + int defColor = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + int rColor = themePrefs.getInt("chatRLinkColor", defColor); + int lColor = themePrefs.getInt("chatLLinkColor", defColor); + int rtColor = themePrefs.getInt("chatRTextColor", 0xff000000); + int ltColor = themePrefs.getInt("chatLTextColor", 0xff000000); + replyLinePaint.setColor(currentMessageObject.isOutOwner() ? rColor : lColor); + canvas.drawRect(linkX, linkPreviewY - AndroidUtilities.dp(3), linkX + AndroidUtilities.dp(2), linkPreviewY + linkPreviewHeight + AndroidUtilities.dp(3), replyLinePaint); + + if (siteCaptionLayout != null) { + //replyNamePaint.setColor(currentMessageObject.isOutOwner() ? Theme.MSG_OUT_SITE_NAME_TEXT_COLOR : Theme.MSG_IN_SITE_NAME_TEXT_COLOR); + replyNamePaint.setColor(currentMessageObject.isOutOwner() ? rColor : lColor); + canvas.save(); + canvas.translate(linkX + AndroidUtilities.dp(10), linkPreviewY - AndroidUtilities.dp(3)); + siteCaptionLayout.draw(canvas); + canvas.restore(); + linkPreviewY += siteCaptionLayout.getLineBottom(siteCaptionLayout.getLineCount() - 1); + } + + replyNamePaint.setColor(Theme.MSG_TEXT_COLOR); + replyTextPaint.setColor(Theme.MSG_TEXT_COLOR); + if (titleLayout != null) { + if (linkPreviewY != startY) { + linkPreviewY += AndroidUtilities.dp(2); + } + replyNamePaint.setColor(currentMessageObject.isOutOwner() ? rtColor : ltColor); + smallImageStartY = linkPreviewY - AndroidUtilities.dp(1); + canvas.save(); + canvas.translate(linkX + AndroidUtilities.dp(10) + titleX, linkPreviewY - AndroidUtilities.dp(3)); + titleLayout.draw(canvas); + canvas.restore(); + linkPreviewY += titleLayout.getLineBottom(titleLayout.getLineCount() - 1); + } + + if (authorLayout != null) { + if (linkPreviewY != startY) { + linkPreviewY += AndroidUtilities.dp(2); + } + if (smallImageStartY == 0) { + smallImageStartY = linkPreviewY - AndroidUtilities.dp(1); + } + replyNamePaint.setColor(currentMessageObject.isOutOwner() ? rtColor : ltColor); + canvas.save(); + canvas.translate(linkX + AndroidUtilities.dp(10) + authorX, linkPreviewY - AndroidUtilities.dp(3)); + authorLayout.draw(canvas); + canvas.restore(); + linkPreviewY += authorLayout.getLineBottom(authorLayout.getLineCount() - 1); + } + + if (descriptionLayout != null) { + if (linkPreviewY != startY) { + linkPreviewY += AndroidUtilities.dp(2); + } + if (smallImageStartY == 0) { + smallImageStartY = linkPreviewY - AndroidUtilities.dp(1); + } + replyTextPaint.setColor(currentMessageObject.isOutOwner() ? rtColor : ltColor); + descriptionY = linkPreviewY - AndroidUtilities.dp(3); + canvas.save(); + canvas.translate(linkX + AndroidUtilities.dp(10) + descriptionX, descriptionY); + if (pressedLink != null && linkBlockNum == -10) { + for (int b = 0; b < urlPath.size(); b++) { + canvas.drawPath(urlPath.get(b), urlPaint); + } + } + descriptionLayout.draw(canvas); + canvas.restore(); + linkPreviewY += descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); + } + + if (drawPhotoImage) { + if (linkPreviewY != startY) { + linkPreviewY += AndroidUtilities.dp(2); + } + + if (isSmallImage) { + photoImage.setImageCoords(linkX + backgroundWidth - AndroidUtilities.dp(81), smallImageStartY, photoImage.getImageWidth(), photoImage.getImageHeight()); + } else { + photoImage.setImageCoords(linkX + AndroidUtilities.dp(10), linkPreviewY, photoImage.getImageWidth(), photoImage.getImageHeight()); + if (drawImageButton) { + int size = AndroidUtilities.dp(48); + buttonX = (int) (photoImage.getImageX() + (photoImage.getImageWidth() - size) / 2.0f); + buttonY = (int) (photoImage.getImageY() + (photoImage.getImageHeight() - size) / 2.0f); + radialProgress.setProgressRect(buttonX, buttonY, buttonX + AndroidUtilities.dp(48), buttonY + AndroidUtilities.dp(48)); + } + } + imageDrawn = photoImage.draw(canvas); + + if (durationLayout != null) { + int x = photoImage.getImageX() + photoImage.getImageWidth() - AndroidUtilities.dp(8) - durationWidth; + int y = photoImage.getImageY() + photoImage.getImageHeight() - AndroidUtilities.dp(19); + Theme.timeBackgroundDrawable.setBounds(x - AndroidUtilities.dp(4), y - AndroidUtilities.dp(1.5f), x + durationWidth + AndroidUtilities.dp(4), y + AndroidUtilities.dp(14.5f)); + Theme.timeBackgroundDrawable.draw(canvas); + + canvas.save(); + canvas.translate(x, y); + durationLayout.draw(canvas); + canvas.restore(); + } + } + } + drawTime = true; + } else if (drawPhotoImage) { + imageDrawn = photoImage.draw(canvas); + drawTime = photoImage.getVisible(); + } + + if (buttonState == -1 && currentMessageObject.isSecretPhoto()) { + int drawable = 4; + if (currentMessageObject.messageOwner.destroyTime != 0) { + if (currentMessageObject.isOutOwner()) { + drawable = 6; + } else { + drawable = 5; + } + } + setDrawableBounds(Theme.photoStatesDrawables[drawable][buttonPressed], buttonX, buttonY); + Theme.photoStatesDrawables[drawable][buttonPressed].setAlpha((int) (255 * (1.0f - radialProgress.getAlpha()))); + Theme.photoStatesDrawables[drawable][buttonPressed].draw(canvas); + if (!currentMessageObject.isOutOwner() && currentMessageObject.messageOwner.destroyTime != 0) { + long msTime = System.currentTimeMillis() + ConnectionsManager.getInstance().getTimeDifference() * 1000; + float progress = Math.max(0, (long) currentMessageObject.messageOwner.destroyTime * 1000 - msTime) / (currentMessageObject.messageOwner.ttl * 1000.0f); + canvas.drawArc(deleteProgressRect, -90, -360 * progress, true, deleteProgressPaint); + if (progress != 0) { + int offset = AndroidUtilities.dp(2); + invalidate((int) deleteProgressRect.left - offset, (int) deleteProgressRect.top - offset, (int) deleteProgressRect.right + offset * 2, (int) deleteProgressRect.bottom + offset * 2); + } + updateSecretTimeText(currentMessageObject); + } + } + try{ + if(themePrefs.getBoolean("chatMemberColorCheck", false)){ + senderPaint.setColor(themePrefs.getInt("chatMemberColor", AndroidUtilities.getIntDarkerColor("themeColor", 0x15))); + }else{ + if (currentMessageObject != null && currentMessageObject.isFromUser()) { + senderPaint.setColor(AvatarDrawable.getNameColorForId(MessagesController.getInstance().getUser(currentMessageObject.messageOwner.from_id).id)); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { + int color = themePrefs.getInt("chatRTextColor", 0xff212121); + int darkColor = AndroidUtilities.getIntDarkerColor("themeColor", 0x15); + int tColor = themePrefs.getInt("chatRTimeColor", darkColor); + if (currentMessageObject.isOutOwner()) { + //audioTitlePaint.setColor(Theme.MSG_OUT_AUDIO_TITLE_TEXT_COLOR); + //audioPerformerPaint.setColor(Theme.MSG_OUT_AUDIO_PERFORMER_TEXT_COLOR); + //audioTimePaint.setColor(Theme.MSG_OUT_AUDIO_DURATION_TEXT_COLOR); + audioTitlePaint.setColor(color); + audioPerformerPaint.setColor(color); + audioTimePaint.setColor(tColor); + radialProgress.setProgressColor(isDrawSelectedBackground() || buttonPressed != 0 ? Theme.MSG_OUT_AUDIO_SELECTED_PROGRESS_COLOR : Theme.MSG_OUT_AUDIO_PROGRESS_COLOR); + } else { + //audioTitlePaint.setColor(Theme.MSG_IN_AUDIO_TITLE_TEXT_COLOR); + //audioPerformerPaint.setColor(Theme.MSG_IN_AUDIO_PERFORMER_TEXT_COLOR); + //audioTimePaint.setColor(Theme.MSG_IN_AUDIO_DURATION_TEXT_COLOR); + color = themePrefs.getInt("chatLTextColor", 0xff212121); + tColor = themePrefs.getInt("chatLTimeColor", 0xffa1aab3); + audioTitlePaint.setColor(color); + audioPerformerPaint.setColor(color); + audioTimePaint.setColor(tColor); + radialProgress.setProgressColor(isDrawSelectedBackground() || buttonPressed != 0 ? Theme.MSG_IN_AUDIO_SELECTED_PROGRESS_COLOR : Theme.MSG_IN_AUDIO_PROGRESS_COLOR); + } + radialProgress.draw(canvas); + + canvas.save(); + canvas.translate(timeAudioX + songX, AndroidUtilities.dp(13) + namesOffset + mediaOffsetY); + songLayout.draw(canvas); + canvas.restore(); + + canvas.save(); + if (MediaController.getInstance().isPlayingAudio(currentMessageObject)) { + canvas.translate(seekBarX, seekBarY); + seekBar.draw(canvas); + } else { + canvas.translate(timeAudioX + performerX, AndroidUtilities.dp(35) + namesOffset + mediaOffsetY); + performerLayout.draw(canvas); + } + canvas.restore(); + + canvas.save(); + canvas.translate(timeAudioX, AndroidUtilities.dp(57) + namesOffset + mediaOffsetY); + timeLayout.draw(canvas); + canvas.restore(); + + Drawable menuDrawable; + if (currentMessageObject.isOutOwner()) { + menuDrawable = Theme.docMenuDrawable[1]; + } else { + menuDrawable = Theme.docMenuDrawable[isDrawSelectedBackground() ? 2 : 0]; + } + setDrawableBounds(menuDrawable, otherX = buttonX + backgroundWidth - AndroidUtilities.dp(currentMessageObject.type == 0 ? 58 : 48), otherY = buttonY - AndroidUtilities.dp(5)); + menuDrawable.draw(canvas); + } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO) { + if (currentMessageObject.isOutOwner()) { + audioTimePaint.setColor(isDrawSelectedBackground() ? Theme.MSG_OUT_AUDIO_DURATION_SELECTED_TEXT_COLOR : Theme.MSG_OUT_AUDIO_DURATION_TEXT_COLOR); + radialProgress.setProgressColor(isDrawSelectedBackground() || buttonPressed != 0 ? Theme.MSG_OUT_AUDIO_SELECTED_PROGRESS_COLOR : Theme.MSG_OUT_AUDIO_PROGRESS_COLOR); + } else { + audioTimePaint.setColor(isDrawSelectedBackground() ? Theme.MSG_IN_AUDIO_DURATION_SELECTED_TEXT_COLOR : Theme.MSG_IN_AUDIO_DURATION_TEXT_COLOR); + radialProgress.setProgressColor(isDrawSelectedBackground() || buttonPressed != 0 ? Theme.MSG_IN_AUDIO_SELECTED_PROGRESS_COLOR : Theme.MSG_IN_AUDIO_PROGRESS_COLOR); + } + radialProgress.draw(canvas); + + canvas.save(); + if (useSeekBarWaweform) { + canvas.translate(seekBarX + AndroidUtilities.dp(13), seekBarY); + seekBarWaveform.draw(canvas); + } else { + canvas.translate(seekBarX, seekBarY); + seekBar.draw(canvas); + } + canvas.restore(); + + canvas.save(); + canvas.translate(timeAudioX, AndroidUtilities.dp(44) + namesOffset + mediaOffsetY); + timeLayout.draw(canvas); + canvas.restore(); + + if (currentMessageObject.type != 0 && currentMessageObject.messageOwner.to_id.channel_id == 0 && currentMessageObject.isContentUnread()) { + docBackPaint.setColor(currentMessageObject.isOutOwner() ? Theme.MSG_OUT_VOICE_SEEKBAR_FILL_COLOR : Theme.MSG_IN_VOICE_SEEKBAR_FILL_COLOR); + canvas.drawCircle(timeAudioX + timeWidthAudio + AndroidUtilities.dp(6), AndroidUtilities.dp(51) + namesOffset + mediaOffsetY, AndroidUtilities.dp(3), docBackPaint); + } + } + if (currentMessageObject.type == 1 || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { + setDrawableBounds(Theme.docMenuDrawable[3], otherX = photoImage.getImageX() + photoImage.getImageWidth() - AndroidUtilities.dp(14), otherY = photoImage.getImageY() + AndroidUtilities.dp(8.1f)); + Theme.docMenuDrawable[3].draw(canvas); + } + + if (captionLayout != null) { canvas.save(); - canvas.translate(textX - (int) Math.ceil(block.textXOffset), textY + block.textYOffset); - if (pressedLink != null && a == linkBlockNum) { - canvas.drawPath(urlPath, urlPaint); + canvas.translate(captionX = photoImage.getImageX() + AndroidUtilities.dp(5), captionY = photoImage.getImageY() + photoImage.getImageHeight() + AndroidUtilities.dp(6)); + if (pressedLink != null) { + for (int b = 0; b < urlPath.size(); b++) { + canvas.drawPath(urlPath.get(b), urlPaint); + } } try { - block.textLayout.draw(canvas); + captionLayout.draw(canvas); } catch (Exception e) { FileLog.e("tmessages", e); } canvas.restore(); } - } - - if (hasLinkPreview) { - int startY = textY + currentMessageObject.textHeight + AndroidUtilities.dp(8); - int linkPreviewY = startY; - int smallImageStartY = 0; - //replyLinePaint.setColor(currentMessageObject.isOutOwner() ? 0xff8dc97a : 0xff6c9fd2); - SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - int defColor = themePrefs.getInt("themeColor", AndroidUtilities.defColor); - int rColor = themePrefs.getInt("chatRLinkColor", defColor); - int lColor = themePrefs.getInt("chatLLinkColor", defColor); - int rtColor = themePrefs.getInt("chatRTextColor", 0xff000000); - int ltColor = themePrefs.getInt("chatLTextColor", 0xff000000); - replyLinePaint.setColor(currentMessageObject.isOutOwner() ? rColor : lColor); - canvas.drawRect(textX, linkPreviewY - AndroidUtilities.dp(3), textX + AndroidUtilities.dp(2), linkPreviewY + linkPreviewHeight + AndroidUtilities.dp(3), replyLinePaint); - - if (siteNameLayout != null) { - //replyNamePaint.setColor(currentMessageObject.isOutOwner() ? 0xff70b15c : 0xff4b91cf); - replyNamePaint.setColor(currentMessageObject.isOutOwner() ? rColor : lColor); - canvas.save(); - canvas.translate(textX + AndroidUtilities.dp(10), linkPreviewY - AndroidUtilities.dp(3)); - siteNameLayout.draw(canvas); - canvas.restore(); - linkPreviewY += siteNameLayout.getLineBottom(siteNameLayout.getLineCount() - 1); + // plus show sender name on images + boolean showSenderName = currentMessageObject.type == 1; + if(showSenderName){ + String senderName = getCurrentNameString(currentMessageObject); + try{ + if(isChat && currentMessageObject.isFromUser()){ + infoWidth = (int) Math.min(Math.ceil(senderPaint.measureText(senderName)), Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) * 0.5f); + CharSequence str = TextUtils.ellipsize(senderName, senderPaint, infoWidth, TextUtils.TruncateAt.END); + infoLayout = new StaticLayout(str, senderPaint, infoWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } } - if (titleLayout != null) { - if (linkPreviewY != startY) { - linkPreviewY += AndroidUtilities.dp(2); - } - //replyNamePaint.setColor(0xff000000); - replyNamePaint.setColor(currentMessageObject.isOutOwner() ? rtColor : ltColor); - smallImageStartY = linkPreviewY - AndroidUtilities.dp(1); + //if (infoLayout != null && (buttonState == 1 || buttonState == 0 || buttonState == 3 || currentMessageObject.isSecretPhoto())) { + if (infoLayout != null && (buttonState == 1 || buttonState == 0 || buttonState == 3 || currentMessageObject.isSecretPhoto() || showSenderName)) { + infoPaint.setColor(Theme.MSG_MEDIA_INFO_TEXT_COLOR); + setDrawableBounds(Theme.timeBackgroundDrawable, photoImage.getImageX() + AndroidUtilities.dp(4), photoImage.getImageY() + AndroidUtilities.dp(4), infoWidth + AndroidUtilities.dp(8), AndroidUtilities.dp(showSenderName ? 20f : 16.5f)); + Theme.timeBackgroundDrawable.draw(canvas); + canvas.save(); - canvas.translate(textX + AndroidUtilities.dp(10) + titleX, linkPreviewY - AndroidUtilities.dp(3)); - titleLayout.draw(canvas); + canvas.translate(photoImage.getImageX() + AndroidUtilities.dp(8), photoImage.getImageY() + AndroidUtilities.dp(5.5f)); + infoLayout.draw(canvas); canvas.restore(); - linkPreviewY += titleLayout.getLineBottom(titleLayout.getLineCount() - 1); } - - if (authorLayout != null) { - if (linkPreviewY != startY) { - linkPreviewY += AndroidUtilities.dp(2); - } - if (smallImageStartY == 0) { - smallImageStartY = linkPreviewY - AndroidUtilities.dp(1); - } - //replyNamePaint.setColor(0xff000000); - replyNamePaint.setColor(currentMessageObject.isOutOwner() ? rtColor : ltColor); - canvas.save(); - canvas.translate(textX + AndroidUtilities.dp(10) + authorX, linkPreviewY - AndroidUtilities.dp(3)); - authorLayout.draw(canvas); - canvas.restore(); - linkPreviewY += authorLayout.getLineBottom(authorLayout.getLineCount() - 1); - } - - if (descriptionLayout != null) { - if (linkPreviewY != startY) { - linkPreviewY += AndroidUtilities.dp(2); - } - if (smallImageStartY == 0) { - smallImageStartY = linkPreviewY - AndroidUtilities.dp(1); - } - //replyTextPaint.setColor(0xff000000); - replyTextPaint.setColor(currentMessageObject.isOutOwner() ? rtColor : ltColor); - descriptionY = linkPreviewY - AndroidUtilities.dp(3); - canvas.save(); - canvas.translate(textX + AndroidUtilities.dp(10) + descriptionX, descriptionY); - if (pressedLink != null && linkBlockNum == -10) { - canvas.drawPath(urlPath, urlPaint); - } - descriptionLayout.draw(canvas); - canvas.restore(); - linkPreviewY += descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); - } - - if (drawLinkImageView) { - if (linkPreviewY != startY) { - linkPreviewY += AndroidUtilities.dp(2); - } - - if (isSmallImage) { - linkImageView.setImageCoords(textX + backgroundWidth - AndroidUtilities.dp(77), smallImageStartY, linkImageView.getImageWidth(), linkImageView.getImageHeight()); + } else if (currentMessageObject.type == 4) { + if (captionLayout != null) { + int color = themePrefs.getInt("chatRTextColor", 0xff212121); + int darkColor = AndroidUtilities.getIntDarkerColor("themeColor", 0x15); + int tColor = themePrefs.getInt("chatRTimeColor", darkColor); + if (currentMessageObject.isOutOwner()) { + //locationTitlePaint.setColor(Theme.MSG_OUT_VENUE_NAME_TEXT_COLOR); + //locationAddressPaint.setColor(isDrawSelectedBackground() ? Theme.MSG_OUT_VENUE_INFO_SELECTED_TEXT_COLOR : Theme.MSG_OUT_VENUE_INFO_TEXT_COLOR); + locationTitlePaint.setColor(color); + locationAddressPaint.setColor(tColor); } else { - linkImageView.setImageCoords(textX + AndroidUtilities.dp(10), linkPreviewY, linkImageView.getImageWidth(), linkImageView.getImageHeight()); - if (drawImageButton) { - int size = AndroidUtilities.dp(48); - buttonX = (int) (linkImageView.getImageX() + (linkImageView.getImageWidth() - size) / 2.0f); - buttonY = (int) (linkImageView.getImageY() + (linkImageView.getImageHeight() - size) / 2.0f); - radialProgress.setProgressRect(buttonX, buttonY, buttonX + AndroidUtilities.dp(48), buttonY + AndroidUtilities.dp(48)); + //locationTitlePaint.setColor(Theme.MSG_IN_VENUE_NAME_TEXT_COLOR); + //locationAddressPaint.setColor(isDrawSelectedBackground() ? Theme.MSG_IN_VENUE_INFO_SELECTED_TEXT_COLOR : Theme.MSG_IN_VENUE_INFO_TEXT_COLOR); + color = themePrefs.getInt("chatLTextColor", 0xff212121); + tColor = themePrefs.getInt("chatLTimeColor", 0xffa1aab3); + locationTitlePaint.setColor(color); + locationAddressPaint.setColor(tColor); + } + + canvas.save(); + canvas.translate(nameOffsetX + photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(10), photoImage.getImageY() + AndroidUtilities.dp(8)); + captionLayout.draw(canvas); + canvas.restore(); + + if (infoLayout != null) { + canvas.save(); + canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(10), photoImage.getImageY() + captionLayout.getLineBottom(captionLayout.getLineCount() - 1) + AndroidUtilities.dp(13)); + infoLayout.draw(canvas); + canvas.restore(); + } + } + } else if (currentMessageObject.type == 8) { + if (captionLayout != null) { + canvas.save(); + canvas.translate(captionX = photoImage.getImageX() + AndroidUtilities.dp(5), captionY = photoImage.getImageY() + photoImage.getImageHeight() + AndroidUtilities.dp(6)); + if (pressedLink != null) { + for (int b = 0; b < urlPath.size(); b++) { + canvas.drawPath(urlPath.get(b), urlPaint); } } - linkImageView.draw(canvas); - if (drawImageButton) { - radialProgress.draw(canvas); + try { + captionLayout.draw(canvas); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + canvas.restore(); + } + } else if (currentMessageObject.type == 12) { + contactNamePaint.setColor(currentMessageObject.isOutOwner() ? Theme.MSG_OUT_CONTACT_NAME_TEXT_COLOR : Theme.MSG_IN_CONTACT_NAME_TEXT_COLOR); + int id = currentMessageObject.messageOwner.media.user_id; + int defColor = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + int color = themePrefs.getInt("chatContactNameColor", defColor); + if(id == 0 || color != defColor){ + contactNamePaint.setColor(color); + } + //contactPhonePaint.setColor(currentMessageObject.isOutOwner() ? Theme.MSG_OUT_CONTACT_PHONE_TEXT_COLOR : Theme.MSG_IN_CONTACT_PHONE_TEXT_COLOR); + color = themePrefs.getInt("chatLTextColor", Theme.MSG_IN_CONTACT_PHONE_TEXT_COLOR); + if (currentMessageObject.isOutOwner()) { + color = themePrefs.getInt("chatRTextColor", Theme.MSG_OUT_CONTACT_PHONE_TEXT_COLOR); + } + contactPhonePaint.setColor(color); + if (titleLayout != null) { + canvas.save(); + canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(16) + namesOffset); + titleLayout.draw(canvas); + canvas.restore(); + } + if (captionLayout != null) { + canvas.save(); + canvas.translate(photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(9), AndroidUtilities.dp(39) + namesOffset); + captionLayout.draw(canvas); + canvas.restore(); + } + + Drawable menuDrawable; + if (currentMessageObject.isOutOwner()) { + menuDrawable = Theme.docMenuDrawable[1]; + } else { + menuDrawable = Theme.docMenuDrawable[isDrawSelectedBackground() ? 2 : 0]; + } + setDrawableBounds(menuDrawable, otherX = photoImage.getImageX() + backgroundWidth - AndroidUtilities.dp(48), otherY = photoImage.getImageY() - AndroidUtilities.dp(5)); + menuDrawable.draw(canvas); + } + if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { + Drawable menuDrawable; + int color = themePrefs.getInt("chatRTextColor", 0xff000000); + if (currentMessageObject.isOutOwner()) { + //docNamePaint.setColor(Theme.MSG_OUT_FILE_NAME_TEXT_COLOR); + //infoPaint.setColor(isDrawSelectedBackground() ? Theme.MSG_OUT_FILE_INFO_SELECTED_TEXT_COLOR : Theme.MSG_OUT_FILE_INFO_TEXT_COLOR); + docBackPaint.setColor(isDrawSelectedBackground() ? Theme.MSG_OUT_FILE_BACKGROUND_SELECTED_COLOR : Theme.MSG_OUT_FILE_BACKGROUND_COLOR); + docNamePaint.setColor(color); + infoPaint.setColor(color); + //docBackPaint.setColor(0xffdaf5c3); + menuDrawable = Theme.docMenuDrawable[1]; + menuDrawable.setColorFilter(themePrefs.getInt("chatRTimeColor", AndroidUtilities.getIntDarkerColor("themeColor", 0x15)), PorterDuff.Mode.SRC_IN); + } else { + //docNamePaint.setColor(Theme.MSG_IN_FILE_NAME_TEXT_COLOR); + //infoPaint.setColor(isDrawSelectedBackground() ? Theme.MSG_IN_FILE_INFO_SELECTED_TEXT_COLOR : Theme.MSG_IN_FILE_INFO_TEXT_COLOR); + docBackPaint.setColor(isDrawSelectedBackground() ? Theme.MSG_IN_FILE_BACKGROUND_SELECTED_COLOR : Theme.MSG_IN_FILE_BACKGROUND_COLOR); + color = themePrefs.getInt("chatLTextColor", 0xff000000); + docNamePaint.setColor(color); + infoPaint.setColor(color); + //docBackPaint.setColor(0xffebf0f5); + menuDrawable = Theme.docMenuDrawable[isDrawSelectedBackground() ? 2 : 0]; + menuDrawable.setColorFilter(themePrefs.getInt("chatLTimeColor", 0xffa1adbb), PorterDuff.Mode.SRC_IN); + } + + int x; + int titleY; + int subtitleY; + if (drawPhotoImage) { + if (currentMessageObject.type == 0) { + setDrawableBounds(menuDrawable, otherX = photoImage.getImageX() + backgroundWidth - AndroidUtilities.dp(56), otherY = photoImage.getImageY() + AndroidUtilities.dp(1)); + } else { + setDrawableBounds(menuDrawable, otherX = photoImage.getImageX() + backgroundWidth - AndroidUtilities.dp(40), otherY = photoImage.getImageY() + AndroidUtilities.dp(1)); } - if (isInstagram && igvideoDrawable != null) { - int x = linkImageView.getImageX() + linkImageView.getImageWidth() - igvideoDrawable.getIntrinsicWidth() - AndroidUtilities.dp(4); - int y = linkImageView.getImageY() + AndroidUtilities.dp(4); - igvideoDrawable.setBounds(x, y, x + igvideoDrawable.getIntrinsicWidth(), y + igvideoDrawable.getIntrinsicHeight()); - igvideoDrawable.draw(canvas); + x = photoImage.getImageX() + photoImage.getImageWidth() + AndroidUtilities.dp(10); + titleY = photoImage.getImageY() + AndroidUtilities.dp(8); + subtitleY = photoImage.getImageY() + captionLayout.getLineBottom(captionLayout.getLineCount() - 1) + AndroidUtilities.dp(13); + if (buttonState >= 0 && buttonState < 4) { + if (!imageDrawn) { + int image = buttonState; + if (buttonState == 0) { + image = currentMessageObject.isOutOwner() ? 7 : 10; + } else if (buttonState == 1) { + image = currentMessageObject.isOutOwner() ? 8 : 11; + } + radialProgress.swapBackground(Theme.photoStatesDrawables[image][isDrawSelectedBackground() || buttonPressed != 0 ? 1 : 0]); + } else { + radialProgress.swapBackground(Theme.photoStatesDrawables[buttonState][buttonPressed]); + } } - if (durationLayout != null) { - int x = linkImageView.getImageX() + linkImageView.getImageWidth() - AndroidUtilities.dp(8) - durationWidth; - int y = linkImageView.getImageY() + linkImageView.getImageHeight() - AndroidUtilities.dp(19); - ResourceLoader.mediaBackgroundDrawable.setBounds(x - AndroidUtilities.dp(4), y - AndroidUtilities.dp(1.5f), x + durationWidth + AndroidUtilities.dp(4), y + AndroidUtilities.dp(14.5f)); - ResourceLoader.mediaBackgroundDrawable.draw(canvas); + if (!imageDrawn) { + rect.set(photoImage.getImageX(), photoImage.getImageY(), photoImage.getImageX() + photoImage.getImageWidth(), photoImage.getImageY() + photoImage.getImageHeight()); + canvas.drawRoundRect(rect, AndroidUtilities.dp(3), AndroidUtilities.dp(3), docBackPaint); + if (currentMessageObject.isOutOwner()) { + radialProgress.setProgressColor(isDrawSelectedBackground() ? Theme.MSG_OUT_FILE_PROGRESS_SELECTED_COLOR : Theme.MSG_OUT_FILE_PROGRESS_COLOR); + } else { + radialProgress.setProgressColor(isDrawSelectedBackground() ? Theme.MSG_IN_FILE_PROGRESS_SELECTED_COLOR : Theme.MSG_IN_FILE_PROGRESS_COLOR); + } + } else { + if (buttonState == -1) { + radialProgress.setHideCurrentDrawable(true); + } + radialProgress.setProgressColor(Theme.MSG_MEDIA_PROGRESS_COLOR); + } + } else { + setDrawableBounds(menuDrawable, otherX = buttonX + backgroundWidth - AndroidUtilities.dp(currentMessageObject.type == 0 ? 58 : 48), otherY = buttonY - AndroidUtilities.dp(5)); + x = buttonX + AndroidUtilities.dp(53); + titleY = buttonY + AndroidUtilities.dp(4); + subtitleY = buttonY + AndroidUtilities.dp(27); + if (currentMessageObject.isOutOwner()) { + radialProgress.setProgressColor(isDrawSelectedBackground() || buttonPressed != 0 ? Theme.MSG_OUT_AUDIO_SELECTED_PROGRESS_COLOR : Theme.MSG_OUT_AUDIO_PROGRESS_COLOR); + } else { + radialProgress.setProgressColor(isDrawSelectedBackground() || buttonPressed != 0 ? Theme.MSG_IN_AUDIO_SELECTED_PROGRESS_COLOR : Theme.MSG_IN_AUDIO_PROGRESS_COLOR); + } + } + menuDrawable.draw(canvas); + try { + if (captionLayout != null) { canvas.save(); - canvas.translate(x, y); - durationLayout.draw(canvas); + canvas.translate(x + nameOffsetX, titleY); + captionLayout.draw(canvas); canvas.restore(); } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + try { + if (infoLayout != null) { + canvas.save(); + canvas.translate(x, subtitleY); + infoLayout.draw(canvas); + canvas.restore(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + if (drawImageButton) { + radialProgress.draw(canvas); + } + + if (!botButtons.isEmpty()) { + int addX; + if (currentMessageObject.isOutOwner()) { + addX = getMeasuredWidth() - widthForButtons - AndroidUtilities.dp(10); + } else { + addX = currentBackgroundDrawable.getBounds().left + AndroidUtilities.dp(mediaBackground ? 1 : 7); + } + for (int a = 0; a < botButtons.size(); a++) { + BotButton button = botButtons.get(a); + int y = button.y + layoutHeight - AndroidUtilities.dp(2); + Theme.systemDrawable.setColorFilter(a == pressedBotButton ? Theme.colorPressedFilter : Theme.colorFilter); + Theme.systemDrawable.setBounds(button.x + addX, y, button.x + addX + button.width, y + button.height); + Theme.systemDrawable.draw(canvas); + canvas.save(); + canvas.translate(button.x + addX + AndroidUtilities.dp(5), y + (AndroidUtilities.dp(44) - button.caption.getLineBottom(button.caption.getLineCount() - 1)) / 2); + button.caption.draw(canvas); + canvas.restore(); + if (button.button instanceof TLRPC.TL_keyboardButtonUrl) { + int x = button.x + button.width - AndroidUtilities.dp(3) - Theme.botLink.getIntrinsicWidth() + addX; + setDrawableBounds(Theme.botLink, x, y + AndroidUtilities.dp(3)); + Theme.botLink.draw(canvas); + } else if (button.button instanceof TLRPC.TL_keyboardButtonSwitchInline) { + int x = button.x + button.width - AndroidUtilities.dp(3) - Theme.botInline.getIntrinsicWidth() + addX; + setDrawableBounds(Theme.botInline, x, y + AndroidUtilities.dp(3)); + Theme.botInline.draw(canvas); + } else if (button.button instanceof TLRPC.TL_keyboardButtonCallback || button.button instanceof TLRPC.TL_keyboardButtonRequestGeoLocation) { + boolean drawProgress = button.button instanceof TLRPC.TL_keyboardButtonCallback && SendMessagesHelper.getInstance().isSendingCallback(currentMessageObject, button.button) || + button.button instanceof TLRPC.TL_keyboardButtonRequestGeoLocation && SendMessagesHelper.getInstance().isSendingCurrentLocation(currentMessageObject, button.button); + if (drawProgress || !drawProgress && button.progressAlpha != 0) { + botProgressPaint.setAlpha(Math.min(255, (int) (button.progressAlpha * 255))); + int x = button.x + button.width - AndroidUtilities.dp(9 + 3) + addX; + rect.set(x, y + AndroidUtilities.dp(4), x + AndroidUtilities.dp(8), y + AndroidUtilities.dp(8 + 4)); + canvas.drawArc(rect, button.angle, 220, false, botProgressPaint); + invalidate((int) rect.left - AndroidUtilities.dp(2), (int) rect.top - AndroidUtilities.dp(2), (int) rect.right + AndroidUtilities.dp(2), (int) rect.bottom + AndroidUtilities.dp(2)); + long newTime = System.currentTimeMillis(); + if (Math.abs(button.lastUpdateTime - System.currentTimeMillis()) < 1000) { + long delta = (newTime - button.lastUpdateTime); + float dt = 360 * delta / 2000.0f; + button.angle += dt; + button.angle -= 360 * (button.angle / 360); + if (drawProgress) { + if (button.progressAlpha < 1.0f) { + button.progressAlpha += delta / 200.0f; + if (button.progressAlpha > 1.0f) { + button.progressAlpha = 1.0f; + } + } + } else { + if (button.progressAlpha > 0.0f) { + button.progressAlpha -= delta / 200.0f; + if (button.progressAlpha < 0.0f) { + button.progressAlpha = 0.0f; + } + } + } + } + button.lastUpdateTime = newTime; + } + } } } } private Drawable getDrawableForCurrentState() { - if (buttonState >= 0 && buttonState < 4) { - if (buttonState == 1) { - return ResourceLoader.buttonStatesDrawables[4]; + if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { + if (buttonState == -1) { + return null; + } + radialProgress.setAlphaForPrevious(false); + return Theme.fileStatesDrawable[currentMessageObject.isOutOwner() ? buttonState : buttonState + 5][isDrawSelectedBackground() || buttonPressed != 0 ? 1 : 0]; + } else { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT && !drawPhotoImage) { + radialProgress.setAlphaForPrevious(false); + if (buttonState == -1) { + return Theme.fileStatesDrawable[currentMessageObject.isOutOwner() ? 3 : 8][isDrawSelectedBackground() ? 1 : 0]; + } else if (buttonState == 0) { + return Theme.fileStatesDrawable[currentMessageObject.isOutOwner() ? 2 : 7][isDrawSelectedBackground() ? 1 : 0]; + } else if (buttonState == 1) { + return Theme.fileStatesDrawable[currentMessageObject.isOutOwner() ? 4 : 9][isDrawSelectedBackground() ? 1 : 0]; + } } else { - return ResourceLoader.buttonStatesDrawables[buttonState]; + radialProgress.setAlphaForPrevious(true); + if (buttonState >= 0 && buttonState < 4) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { + int image = buttonState; + if (buttonState == 0) { + image = currentMessageObject.isOutOwner() ? 7 : 10; + } else if (buttonState == 1) { + image = currentMessageObject.isOutOwner() ? 8 : 11; + } + return Theme.photoStatesDrawables[image][isDrawSelectedBackground() || buttonPressed != 0 ? 1 : 0]; + } else { + return Theme.photoStatesDrawables[buttonState][buttonPressed]; + } + } else if (buttonState == -1 && documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { + return Theme.photoStatesDrawables[currentMessageObject.isOutOwner() ? 9 : 12][isDrawSelectedBackground() ? 1 : 0]; + } } } return null; } - public void updateButtonState(boolean animated) { - if (currentPhotoObject == null || !drawImageButton) { - return; - } - String fileName; - File cacheFile; - - if (isGifDocument) { - fileName = FileLoader.getAttachFileName(currentMessageObject.messageOwner.media.webpage.document); - cacheFile = FileLoader.getPathToAttach(currentMessageObject.messageOwner.media.webpage.document); - } else { - fileName = FileLoader.getAttachFileName(currentPhotoObject); - cacheFile = FileLoader.getPathToAttach(currentPhotoObject, true); - } - if (fileName == null) { - radialProgress.setBackground(null, false, false); - return; - } - if (!cacheFile.exists()) { - MediaController.getInstance().addLoadingFileObserver(fileName, this); - float setProgress = 0; - boolean progressVisible = false; - if (!FileLoader.getInstance().isLoadingFile(fileName)) { - if (!cancelLoading && - (!isGifDocument && MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_PHOTO) || - isGifDocument && MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_GIF)) ) { - progressVisible = true; - buttonState = 1; + @Override + protected int getMaxNameWidth() { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_STICKER) { + int maxWidth; + if (AndroidUtilities.isTablet()) { + if (isChat && !currentMessageObject.isOutOwner() && currentMessageObject.isFromUser()) { + maxWidth = AndroidUtilities.getMinTabletSide() - AndroidUtilities.dp(42); } else { - buttonState = 0; + maxWidth = AndroidUtilities.getMinTabletSide(); } } else { - progressVisible = true; - buttonState = 1; - Float progress = ImageLoader.getInstance().getFileProgress(fileName); - setProgress = progress != null ? progress : 0; + if (isChat && !currentMessageObject.isOutOwner() && currentMessageObject.isFromUser()) { + maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) - AndroidUtilities.dp(42); + } else { + maxWidth = Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y); + } } - radialProgress.setProgress(setProgress, false); - radialProgress.setBackground(getDrawableForCurrentState(), progressVisible, animated); - invalidate(); - } else { - MediaController.getInstance().removeLoadingFileObserver(this); - if (isGifDocument && !linkImageView.isAllowStartAnimation()) { - buttonState = 2; + return maxWidth - backgroundWidth - AndroidUtilities.dp(57); + } + return super.getMaxNameWidth(); + } + + public void updateButtonState(boolean animated) { + String fileName = null; + boolean fileExists = false; + if (currentMessageObject.type == 1) { + if (currentPhotoObject == null) { + return; + } + fileName = FileLoader.getAttachFileName(currentPhotoObject); + fileName = FileLoader.getAttachFileName(currentPhotoObject, null, currentMessageObject.isOutOwner());//KEEP_ORIGINAL_FILENAME + fileExists = currentMessageObject.mediaExists; + } else if (currentMessageObject.type == 8 || documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || currentMessageObject.type == 9 || documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { + if (currentMessageObject.attachPathExists) { + fileName = currentMessageObject.messageOwner.attachPath; + fileExists = true; + } else if (!currentMessageObject.isSendError() || documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { + fileName = currentMessageObject.getFileName(); + fileExists = currentMessageObject.mediaExists; + } + } else if (documentAttachType != DOCUMENT_ATTACH_TYPE_NONE) { + fileName = FileLoader.getAttachFileName(documentAttach); + fileExists = currentMessageObject.mediaExists; + } else if (currentPhotoObject != null) { + fileName = FileLoader.getAttachFileName(currentPhotoObject); + fileExists = currentMessageObject.mediaExists; + } + if (fileName == null || fileName.length() == 0) { + //radialProgress.setBackground(null, false, false); + //return; + //Plus temporary fix + if(documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO ) { + File cacheFile = FileLoader.getPathToMessage(currentMessageObject.messageOwner); + if (cacheFile == null || cacheFile.length() == 0) { + radialProgress.setBackground(null, false, false); + return; + } + } else{ + radialProgress.setBackground(null, false, false); + return; + } + } + boolean fromBot = currentMessageObject.messageOwner.params != null && currentMessageObject.messageOwner.params.containsKey("query_id"); + + if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { + if (currentMessageObject.isOut() && currentMessageObject.isSending() || currentMessageObject.isSendError() && fromBot) { + MediaController.getInstance().addLoadingFileObserver(currentMessageObject.messageOwner.attachPath, currentMessageObject, this); + buttonState = 4; + radialProgress.setBackground(getDrawableForCurrentState(), !fromBot, animated); + if (!fromBot) { + Float progress = ImageLoader.getInstance().getFileProgress(currentMessageObject.messageOwner.attachPath); + if (progress == null && SendMessagesHelper.getInstance().isSendingMessage(currentMessageObject.getId())) { + progress = 1.0f; + } + radialProgress.setProgress(progress != null ? progress : 0, false); + } else { + radialProgress.setProgress(0, false); + } } else { - buttonState = -1; + if (fileExists) { + MediaController.getInstance().removeLoadingFileObserver(this); + boolean playing = MediaController.getInstance().isPlayingAudio(currentMessageObject); + if (!playing || playing && MediaController.getInstance().isAudioPaused()) { + buttonState = 0; + } else { + buttonState = 1; + } + radialProgress.setBackground(getDrawableForCurrentState(), false, animated); + } else { + MediaController.getInstance().addLoadingFileObserver(fileName, currentMessageObject, this); + if (!FileLoader.getInstance().isLoadingFile(fileName)) { + buttonState = 2; + radialProgress.setProgress(0, animated); + radialProgress.setBackground(getDrawableForCurrentState(), false, animated); + } else { + buttonState = 4; + Float progress = ImageLoader.getInstance().getFileProgress(fileName); + if (progress != null) { + radialProgress.setProgress(progress, animated); + } else { + radialProgress.setProgress(0, animated); + } + radialProgress.setBackground(getDrawableForCurrentState(), true, animated); + } + } + } + updateAudioProgress(); + } else if (currentMessageObject.type == 0 && documentAttachType != DOCUMENT_ATTACH_TYPE_DOCUMENT && documentAttachType != DOCUMENT_ATTACH_TYPE_VIDEO) { + if (currentPhotoObject == null || !drawImageButton) { + return; + } + if (!fileExists) { + MediaController.getInstance().addLoadingFileObserver(fileName, currentMessageObject, this); + float setProgress = 0; + boolean progressVisible = false; + if (!FileLoader.getInstance().isLoadingFile(fileName)) { + if (!cancelLoading && + (documentAttachType == 0 && MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_PHOTO) || + documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_GIF))) { + progressVisible = true; + buttonState = 1; + } else { + buttonState = 0; + } + } else { + progressVisible = true; + buttonState = 1; + Float progress = ImageLoader.getInstance().getFileProgress(fileName); + setProgress = progress != null ? progress : 0; + } + radialProgress.setProgress(setProgress, false); + radialProgress.setBackground(getDrawableForCurrentState(), progressVisible, animated); + invalidate(); + } else { + MediaController.getInstance().removeLoadingFileObserver(this); + if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && !photoImage.isAllowStartAnimation()) { + buttonState = 2; + } else { + buttonState = -1; + } + radialProgress.setBackground(getDrawableForCurrentState(), false, animated); + invalidate(); + } + } else { + if (currentMessageObject.isOut() && currentMessageObject.isSending()) { + if (currentMessageObject.messageOwner.attachPath != null && currentMessageObject.messageOwner.attachPath.length() > 0) { + MediaController.getInstance().addLoadingFileObserver(currentMessageObject.messageOwner.attachPath, currentMessageObject, this); + boolean needProgress = currentMessageObject.messageOwner.attachPath == null || !currentMessageObject.messageOwner.attachPath.startsWith("http"); + HashMap params = currentMessageObject.messageOwner.params; + if (currentMessageObject.messageOwner.message != null && params != null && (params.containsKey("url") || params.containsKey("bot"))) { + needProgress = false; + buttonState = -1; + } else { + buttonState = 1; + } + radialProgress.setBackground(getDrawableForCurrentState(), needProgress, animated); + if (needProgress) { + Float progress = ImageLoader.getInstance().getFileProgress(currentMessageObject.messageOwner.attachPath); + if (progress == null && SendMessagesHelper.getInstance().isSendingMessage(currentMessageObject.getId())) { + progress = 1.0f; + } + radialProgress.setProgress(progress != null ? progress : 0, false); + } else { + radialProgress.setProgress(0, false); + } + invalidate(); + } + } else { + if (currentMessageObject.messageOwner.attachPath != null && currentMessageObject.messageOwner.attachPath.length() != 0) { + MediaController.getInstance().removeLoadingFileObserver(this); + } + if (!fileExists) { + MediaController.getInstance().addLoadingFileObserver(fileName, currentMessageObject, this); + float setProgress = 0; + boolean progressVisible = false; + if (!FileLoader.getInstance().isLoadingFile(fileName)) { + if (!cancelLoading && + (currentMessageObject.type == 1 && MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_PHOTO) || + currentMessageObject.type == 8 && MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_GIF) && MessageObject.isNewGifDocument(currentMessageObject.messageOwner.media.document)) ) { + progressVisible = true; + buttonState = 1; + } else { + buttonState = 0; + } + } else { + progressVisible = true; + buttonState = 1; + Float progress = ImageLoader.getInstance().getFileProgress(fileName); + setProgress = progress != null ? progress : 0; + } + radialProgress.setBackground(getDrawableForCurrentState(), progressVisible, animated); + radialProgress.setProgress(setProgress, false); + invalidate(); + } else { + MediaController.getInstance().removeLoadingFileObserver(this); + if (currentMessageObject.type == 8 && !photoImage.isAllowStartAnimation()) { + buttonState = 2; + } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { + buttonState = 3; + } else { + buttonState = -1; + } + radialProgress.setBackground(getDrawableForCurrentState(), false, animated); + if (photoNotSet) { + setMessageObject(currentMessageObject); + } + invalidate(); + } + } + } + } + + public void setAllowedToSetPhoto(boolean value) { + if (allowedToSetPhoto == value) { + return; + } + if (currentMessageObject != null && currentMessageObject.type == 1) { + allowedToSetPhoto = value; + if (value) { + MessageObject temp = currentMessageObject; + currentMessageObject = null; + setMessageObject(temp); } - radialProgress.setBackground(getDrawableForCurrentState(), false, animated); - invalidate(); } } private void didPressedButton(boolean animated) { if (buttonState == 0) { - cancelLoading = false; - radialProgress.setProgress(0, false); - if (isGifDocument) { - linkImageView.setImage(currentMessageObject.messageOwner.media.webpage.document, null, currentPhotoObject.location, currentPhotoFilter, currentMessageObject.messageOwner.media.webpage.document.size, null, false); - currentMessageObject.audioProgress = 2; - } else { - linkImageView.setImage(currentPhotoObject.location, currentPhotoFilter, currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, currentPhotoFilterThumb, 0, null, false); - } - buttonState = 1; - radialProgress.setBackground(getDrawableForCurrentState(), true, animated); - invalidate(); - } else if (buttonState == 1) { - if (currentMessageObject.isOut() && currentMessageObject.isSending()) { - if (delegate != null) { - delegate.didPressedCancelSendButton(this); + if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { + if (delegate.needPlayAudio(currentMessageObject)) { + buttonState = 1; + radialProgress.setBackground(getDrawableForCurrentState(), false, false); + invalidate(); } } else { - cancelLoading = true; - linkImageView.cancelLoadImage(); - buttonState = 0; - radialProgress.setBackground(getDrawableForCurrentState(), false, animated); + cancelLoading = false; + radialProgress.setProgress(0, false); + if (currentMessageObject.type == 1) { + photoImage.setImage(currentPhotoObject.location, currentPhotoFilter, currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, currentPhotoFilter, currentPhotoObject.size, null, false); + radialProgress.setSizeAndType(currentPhotoObject.size, currentMessageObject.type); // plus IMAGE + } else if (currentMessageObject.type == 8) { + currentMessageObject.audioProgress = 2; + photoImage.setImage(currentMessageObject.messageOwner.media.document, null, currentPhotoObject != null ? currentPhotoObject.location : null, currentPhotoFilter, currentMessageObject.messageOwner.media.document.size, null, false); + } else if (currentMessageObject.type == 9) { + FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.document, false, false); + } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO) { + FileLoader.getInstance().loadFile(documentAttach, true, false); + } else if (currentMessageObject.type == 0 && documentAttachType != DOCUMENT_ATTACH_TYPE_NONE) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { + photoImage.setImage(currentMessageObject.messageOwner.media.webpage.document, null, currentPhotoObject.location, currentPhotoFilter, currentMessageObject.messageOwner.media.webpage.document.size, null, false); + currentMessageObject.audioProgress = 2; + } else if (documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { + FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.webpage.document, false, false); + } + } else { + photoImage.setImage(currentPhotoObject.location, currentPhotoFilter, currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, currentPhotoFilterThumb, 0, null, false); + } + buttonState = 1; + radialProgress.setBackground(getDrawableForCurrentState(), true, animated); invalidate(); } + } else if (buttonState == 1) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { + boolean result = MediaController.getInstance().pauseAudio(currentMessageObject); + if (result) { + buttonState = 0; + radialProgress.setBackground(getDrawableForCurrentState(), false, false); + invalidate(); + } + } else { + if (currentMessageObject.isOut() && currentMessageObject.isSending()) { + delegate.didPressedCancelSendButton(this); + } else { + cancelLoading = true; + if (documentAttachType == DOCUMENT_ATTACH_TYPE_VIDEO || documentAttachType == DOCUMENT_ATTACH_TYPE_DOCUMENT) { + FileLoader.getInstance().cancelLoadFile(documentAttach); + } else if (currentMessageObject.type == 0 || currentMessageObject.type == 1 || currentMessageObject.type == 8) { + photoImage.cancelLoadImage(); + } else if (currentMessageObject.type == 9) { + FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.document); + } + buttonState = 0; + radialProgress.setBackground(getDrawableForCurrentState(), false, animated); + invalidate(); + } + } } else if (buttonState == 2) { - linkImageView.setAllowStartAnimation(true); - linkImageView.startAnimation(); - currentMessageObject.audioProgress = 0; - buttonState = -1; - radialProgress.setBackground(getDrawableForCurrentState(), false, animated); + if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { + radialProgress.setProgress(0, false); + FileLoader.getInstance().loadFile(documentAttach, true, false); + buttonState = 4; + radialProgress.setBackground(getDrawableForCurrentState(), true, false); + invalidate(); + } else { + photoImage.setAllowStartAnimation(true); + photoImage.startAnimation(); + currentMessageObject.audioProgress = 0; + buttonState = -1; + radialProgress.setBackground(getDrawableForCurrentState(), false, animated); + } + } else if (buttonState == 3) { + delegate.didPressedImage(this); + } else if (buttonState == 4) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { + if (currentMessageObject.isOut() && currentMessageObject.isSending() || currentMessageObject.isSendError()) { + if (delegate != null) { + delegate.didPressedCancelSendButton(this); + } + } else { + FileLoader.getInstance().cancelLoadFile(documentAttach); + buttonState = 2; + radialProgress.setBackground(getDrawableForCurrentState(), false, false); + invalidate(); + } + } } } @Override public void onFailedDownload(String fileName) { - updateButtonState(false); + updateButtonState(documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC); } @Override public void onSuccessDownload(String fileName) { - radialProgress.setProgress(1, true); - if (isGifDocument && currentMessageObject.audioProgress != 1) { - buttonState = 2; - didPressedButton(true); - } else if (!photoNotSet) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { updateButtonState(true); + updateWaveform(); } else { - setMessageObject(currentMessageObject); + radialProgress.setProgress(1, true); + if (currentMessageObject.type == 0) { + if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF && currentMessageObject.audioProgress != 1) { + buttonState = 2; + didPressedButton(true); + } else if (!photoNotSet) { + updateButtonState(true); + } else { + setMessageObject(currentMessageObject); + } + } else { + if (!photoNotSet || currentMessageObject.type == 8 && currentMessageObject.audioProgress != 1) { + if (currentMessageObject.type == 8 && currentMessageObject.audioProgress != 1) { + photoNotSet = false; + buttonState = 2; + didPressedButton(true); + } else { + updateButtonState(true); + } + } + if (photoNotSet) { + setMessageObject(currentMessageObject); + } + } + } + } + + @Override + public void didSetImage(ImageReceiver imageReceiver, boolean set, boolean thumb) { + if (currentMessageObject != null && set && !thumb && !currentMessageObject.mediaExists && !currentMessageObject.attachPathExists) { + currentMessageObject.mediaExists = true; + updateButtonState(true); } } @Override public void onProgressDownload(String fileName, float progress) { radialProgress.setProgress(progress, true); - if (buttonState != 1) { - updateButtonState(false); + if (documentAttachType == DOCUMENT_ATTACH_TYPE_AUDIO || documentAttachType == DOCUMENT_ATTACH_TYPE_MUSIC) { + if (buttonState != 4) { + updateButtonState(false); + } + } else { + if (buttonState != 1) { + updateButtonState(false); + } } } + @Override + public void onProgressUpload(String fileName, float progress, boolean isEncrypted) { + radialProgress.setProgress(progress, true); + } + @Override public void onProvideStructure(ViewStructure structure) { super.onProvideStructure(structure); if (allowAssistant && Build.VERSION.SDK_INT >= 23) { - structure.setText(currentMessageObject.messageText); + if (currentMessageObject.messageText != null && currentMessageObject.messageText.length() > 0) { + structure.setText(currentMessageObject.messageText); + } else if (currentMessageObject.caption != null && currentMessageObject.caption.length() > 0) { + structure.setText(currentMessageObject.caption); + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatUnreadCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatUnreadCell.java new file mode 100644 index 00000000..658fb2e0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ChatUnreadCell.java @@ -0,0 +1,68 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.R; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.ActionBar.Theme; + +public class ChatUnreadCell extends FrameLayout { + + private TextView textView; + + public ChatUnreadCell(Context context) { + super(context); + + FrameLayout frameLayout = new FrameLayout(context); + frameLayout.setBackgroundResource(R.drawable.newmsg_divider); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int bgColor = themePrefs.getInt("chatDateBubbleColor", 0xccffffff); + if(bgColor != 0xccffffff)frameLayout.setBackgroundColor(bgColor); + addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 27, Gravity.LEFT | Gravity.TOP, 0, 7, 0, 0)); + + ImageView imageView = new ImageView(context); + //imageView.setImageResource(R.drawable.ic_ab_new); + int color = themePrefs.getInt("chatDateColor", 0xffA2B5C7); + Drawable abNew = getResources().getDrawable(R.drawable.ic_ab_new); + abNew.setColorFilter(color, PorterDuff.Mode.SRC_IN); + imageView.setImageDrawable(abNew); + imageView.setPadding(0, AndroidUtilities.dp(2), 0, 0); + frameLayout.addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 0, 0, 10, 0)); + + textView = new TextView(context); + textView.setPadding(0, 0, 0, AndroidUtilities.dp(1)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + //textView.setTextColor(Theme.CHAT_UNREAD_TEXT_COLOR); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + int textColor = themePrefs.getInt("chatDateColor", 0xff4a7297); + textView.setTextColor(textColor); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + } + + public void setText(String text) { + textView.setText(text); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(40), MeasureSpec.EXACTLY)); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxCell.java new file mode 100644 index 00000000..f32a6553 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/CheckBoxCell.java @@ -0,0 +1,103 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.ui.Components.CheckBoxSquare; +import org.telegram.ui.Components.LayoutHelper; + +public class CheckBoxCell extends FrameLayout { + + private TextView textView; + private TextView valueTextView; + private CheckBoxSquare checkBox; + private static Paint paint; + private boolean needDivider; + + public CheckBoxCell(Context context) { + super(context); + + if (paint == null) { + paint = new Paint(); + paint.setColor(0xffd9d9d9); + paint.setStrokeWidth(1); + } + + textView = new TextView(context); + textView.setTextColor(0xff212121); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setLines(1); + textView.setMaxLines(1); + textView.setSingleLine(true); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, (LocaleController.isRTL ? 17 : 46), 0, (LocaleController.isRTL ? 46 : 17), 0)); + + valueTextView = new TextView(context); + valueTextView.setTextColor(0xff2f8cc9); + valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + valueTextView.setLines(1); + valueTextView.setMaxLines(1); + valueTextView.setSingleLine(true); + valueTextView.setEllipsize(TextUtils.TruncateAt.END); + valueTextView.setGravity((LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL); + addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, 17, 0, 17, 0)); + + checkBox = new CheckBoxSquare(context); + addView(checkBox, LayoutHelper.createFrame(18, 18, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, (LocaleController.isRTL ? 0 : 17), 15, (LocaleController.isRTL ? 17 : 0), 0)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(48) + (needDivider ? 1 : 0)); + + int availableWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - AndroidUtilities.dp(34); + + valueTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth / 2, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY)); + textView.measure(MeasureSpec.makeMeasureSpec(availableWidth - valueTextView.getMeasuredWidth() - AndroidUtilities.dp(8), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY)); + checkBox.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(18), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(18), MeasureSpec.EXACTLY)); + } + + public void setTextColor(int color) { + textView.setTextColor(color); + } + + public void setText(String text, String value, boolean checked, boolean divider) { + textView.setText(text); + checkBox.setChecked(checked, false); + valueTextView.setText(value); + needDivider = divider; + setWillNotDraw(!divider); + } + + public void setChecked(boolean checked, boolean animated) { + checkBox.setChecked(checked, animated); + } + + public boolean isChecked() { + return checkBox.isChecked(); + } + + @Override + protected void onDraw(Canvas canvas) { + if (needDivider) { + canvas.drawLine(getPaddingLeft(), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, paint); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java new file mode 100644 index 00000000..5c789c3d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ContextLinkCell.java @@ -0,0 +1,641 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.view.MotionEvent; +import android.view.SoundEffectConstants; +import android.view.View; +import android.view.animation.AccelerateInterpolator; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageLoader; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.LetterDrawable; +import org.telegram.ui.Components.RadialProgress; +import org.telegram.ui.ActionBar.Theme; + +import java.io.File; +import java.util.ArrayList; +import java.util.Locale; + +public class ContextLinkCell extends View implements MediaController.FileDownloadProgressListener { + + private final static int DOCUMENT_ATTACH_TYPE_NONE = 0; + private final static int DOCUMENT_ATTACH_TYPE_DOCUMENT = 1; + private final static int DOCUMENT_ATTACH_TYPE_GIF = 2; + private final static int DOCUMENT_ATTACH_TYPE_AUDIO = 3; + private final static int DOCUMENT_ATTACH_TYPE_VIDEO = 4; + private final static int DOCUMENT_ATTACH_TYPE_MUSIC = 5; + private final static int DOCUMENT_ATTACH_TYPE_STICKER = 6; + private final static int DOCUMENT_ATTACH_TYPE_PHOTO = 7; + private final static int DOCUMENT_ATTACH_TYPE_GEO = 8; + + public interface ContextLinkCellDelegate { + void didPressedImage(ContextLinkCell cell); + } + + private ImageReceiver linkImageView; + private boolean drawLinkImageView; + private LetterDrawable letterDrawable; + + private boolean needDivider; + private boolean buttonPressed; + private boolean needShadow; + + private int linkY; + private StaticLayout linkLayout; + + private int titleY = AndroidUtilities.dp(7); + private StaticLayout titleLayout; + + private int descriptionY = AndroidUtilities.dp(27); + private StaticLayout descriptionLayout; + + private TLRPC.BotInlineResult inlineResult; + private TLRPC.Document documentAttach; + private int documentAttachType; + private boolean mediaWebpage; + + private static TextPaint titleTextPaint; + private static TextPaint descriptionTextPaint; + private static Paint paint; + private static Drawable shadowDrawable; + + private int TAG; + private int buttonState; + private RadialProgress radialProgress; + + private long lastUpdateTime; + private boolean scaled; + private float scale; + private long time = 0; + private static AccelerateInterpolator interpolator = new AccelerateInterpolator(0.5f); + + private ContextLinkCellDelegate delegate; + + public ContextLinkCell(Context context) { + super(context); + + if (titleTextPaint == null) { + titleTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + titleTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleTextPaint.setColor(0xff212121); + titleTextPaint.setTextSize(AndroidUtilities.dp(15)); + + descriptionTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + descriptionTextPaint.setTextSize(AndroidUtilities.dp(13)); + + paint = new Paint(); + paint.setColor(0xffd9d9d9); + paint.setStrokeWidth(1); + } + + linkImageView = new ImageReceiver(this); + letterDrawable = new LetterDrawable(); + radialProgress = new RadialProgress(this); + TAG = MediaController.getInstance().generateObserverTag(); + } + + @SuppressLint("DrawAllocation") + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + drawLinkImageView = false; + descriptionLayout = null; + titleLayout = null; + linkLayout = null; + linkY = AndroidUtilities.dp(27); + + if (inlineResult == null && documentAttach == null) { + setMeasuredDimension(AndroidUtilities.dp(100), AndroidUtilities.dp(100)); + return; + } + + int viewWidth = MeasureSpec.getSize(widthMeasureSpec); + int maxWidth = viewWidth - AndroidUtilities.dp(AndroidUtilities.leftBaseline) - AndroidUtilities.dp(8); + + TLRPC.PhotoSize currentPhotoObject = null; + TLRPC.PhotoSize currentPhotoObjectThumb = null; + ArrayList photoThumbs = null; + String url = null; + + if (documentAttach != null) { + photoThumbs = new ArrayList<>(); + photoThumbs.add(documentAttach.thumb); + } else if (inlineResult != null && inlineResult.photo != null) { + photoThumbs = new ArrayList<>(inlineResult.photo.sizes); + } + + if (!mediaWebpage && inlineResult != null) { + if (inlineResult.title != null) { + try { + int width = (int) Math.ceil(titleTextPaint.measureText(inlineResult.title)); + CharSequence titleFinal = TextUtils.ellipsize(Emoji.replaceEmoji(inlineResult.title.replace('\n', ' '), titleTextPaint.getFontMetricsInt(), AndroidUtilities.dp(15), false), titleTextPaint, Math.min(width, maxWidth), TextUtils.TruncateAt.END); + titleLayout = new StaticLayout(titleFinal, titleTextPaint, maxWidth + AndroidUtilities.dp(4), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + letterDrawable.setTitle(inlineResult.title); + } + + if (inlineResult.description != null) { + try { + descriptionLayout = ChatMessageCell.generateStaticLayout(Emoji.replaceEmoji(inlineResult.description, descriptionTextPaint.getFontMetricsInt(), AndroidUtilities.dp(13), false), descriptionTextPaint, maxWidth, maxWidth, 0, 3); + if (descriptionLayout.getLineCount() > 0) { + linkY = descriptionY + descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1) + AndroidUtilities.dp(1); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + if (inlineResult.url != null) { + try { + int width = (int) Math.ceil(descriptionTextPaint.measureText(inlineResult.url)); + CharSequence linkFinal = TextUtils.ellipsize(inlineResult.url.replace('\n', ' '), descriptionTextPaint, Math.min(width, maxWidth), TextUtils.TruncateAt.MIDDLE); + linkLayout = new StaticLayout(linkFinal, descriptionTextPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + documentAttachType = DOCUMENT_ATTACH_TYPE_NONE; + String ext = null; + if (documentAttach != null) { + if (MessageObject.isGifDocument(documentAttach)) { + documentAttachType = DOCUMENT_ATTACH_TYPE_GIF; + currentPhotoObject = documentAttach.thumb; + } else if (MessageObject.isStickerDocument(documentAttach)) { + documentAttachType = DOCUMENT_ATTACH_TYPE_STICKER; + currentPhotoObject = documentAttach.thumb; + ext = "webp"; + } else { + currentPhotoObject = documentAttach.thumb; + } + } else if (inlineResult != null && inlineResult.photo != null) { + documentAttachType = DOCUMENT_ATTACH_TYPE_PHOTO; + currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(photoThumbs, AndroidUtilities.getPhotoSize(), true); + currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(photoThumbs, 80); + if (currentPhotoObjectThumb == currentPhotoObject) { + currentPhotoObjectThumb = null; + } + } + if (inlineResult != null) { + if (inlineResult.content_url != null) { + if (inlineResult.type != null) { + if (inlineResult.type.startsWith("gif")) { + if (documentAttachType != DOCUMENT_ATTACH_TYPE_GIF) { + url = inlineResult.content_url; + documentAttachType = DOCUMENT_ATTACH_TYPE_GIF; + } + } else if (inlineResult.type.equals("photo")) { + url = inlineResult.thumb_url; + if (url == null) { + url = inlineResult.content_url; + } + } + } + } + if (url == null && inlineResult.thumb_url != null) { + url = inlineResult.thumb_url; + } + } + if (url == null && currentPhotoObject == null && currentPhotoObjectThumb == null) { + if (inlineResult.send_message instanceof TLRPC.TL_botInlineMessageMediaVenue || inlineResult.send_message instanceof TLRPC.TL_botInlineMessageMediaGeo) { + double lat = inlineResult.send_message.geo.lat; + double lon = inlineResult.send_message.geo._long; + url = String.format(Locale.US, "https://maps.googleapis.com/maps/api/staticmap?center=%f,%f&zoom=15&size=72x72&maptype=roadmap&scale=%d&markers=color:red|size:small|%f,%f&sensor=false", lat, lon, Math.min(2, (int) Math.ceil(AndroidUtilities.density)), lat, lon); + } + } + + int width = 1; + int w = 0; + int h = 0; + + if (documentAttach != null) { + for (int b = 0; b < documentAttach.attributes.size(); b++) { + TLRPC.DocumentAttribute attribute = documentAttach.attributes.get(b); + if (attribute instanceof TLRPC.TL_documentAttributeImageSize || attribute instanceof TLRPC.TL_documentAttributeVideo) { + w = attribute.w; + h = attribute.h; + break; + } + } + } + if (w == 0 || h == 0) { + if (currentPhotoObject != null) { + if (currentPhotoObjectThumb != null) { + currentPhotoObjectThumb.size = -1; + } + w = currentPhotoObject.w; + h = currentPhotoObject.h; + } else if (inlineResult != null) { + w = inlineResult.w; + h = inlineResult.h; + } + } + if (w == 0 || h == 0) { + w = h = AndroidUtilities.dp(80); + } + if (documentAttach != null || currentPhotoObject != null || url != null) { + String currentPhotoFilter; + String currentPhotoFilterThumb = "52_52_b"; + + if (mediaWebpage) { + width = (int) (w / (h / (float) AndroidUtilities.dp(80))); + if (Build.VERSION.SDK_INT >= 11 && documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { + currentPhotoFilterThumb = currentPhotoFilter = String.format(Locale.US, "%d_%d_b", (int) (width / AndroidUtilities.density), 80); + } else { + currentPhotoFilter = String.format(Locale.US, "%d_%d", (int) (width / AndroidUtilities.density), 80); + currentPhotoFilterThumb = currentPhotoFilter + "_b"; + } + } else { + currentPhotoFilter = "52_52"; + } + + if (documentAttachType == DOCUMENT_ATTACH_TYPE_GIF) { + if (documentAttach != null && Build.VERSION.SDK_INT >= 11) { + linkImageView.setImage(documentAttach, null, currentPhotoObject != null ? currentPhotoObject.location : null, currentPhotoFilter, documentAttach.size, ext, false); + } else { + linkImageView.setImage(null, url, null, null, currentPhotoObject != null ? currentPhotoObject.location : null, currentPhotoFilter, -1, ext, true); + } + } else { + if (currentPhotoObject != null) { + linkImageView.setImage(currentPhotoObject.location, currentPhotoFilter, currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, currentPhotoFilterThumb, 0, ext, false); + } else { + linkImageView.setImage(null, url, currentPhotoFilter, null, currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, currentPhotoFilterThumb, -1, ext, true); + } + } + drawLinkImageView = true; + } + + if (mediaWebpage) { + setBackgroundDrawable(null); + if (inlineResult == null) { + width = viewWidth; + int height = MeasureSpec.getSize(heightMeasureSpec); + setMeasuredDimension(width, height); + if (needDivider) { + height -= AndroidUtilities.dp(2); + } + int x = (width - AndroidUtilities.dp(24)) / 2; + int y = (height - AndroidUtilities.dp(24)) / 2; + radialProgress.setProgressRect(x, y, x + AndroidUtilities.dp(24), y + AndroidUtilities.dp(24)); + linkImageView.setImageCoords(0, 0, width, height); + } else { + setMeasuredDimension(width + AndroidUtilities.dp(5), AndroidUtilities.dp(90)); + int x = AndroidUtilities.dp(5) + (width - AndroidUtilities.dp(24)) / 2; + int y = (AndroidUtilities.dp(90) - AndroidUtilities.dp(24)) / 2; + radialProgress.setProgressRect(x, y, x + AndroidUtilities.dp(24), y + AndroidUtilities.dp(24)); + linkImageView.setImageCoords(AndroidUtilities.dp(5), AndroidUtilities.dp(5), width, AndroidUtilities.dp(80)); + } + } else { + setBackgroundResource(R.drawable.list_selector); + int height = 0; + if (titleLayout != null && titleLayout.getLineCount() != 0) { + height += titleLayout.getLineBottom(titleLayout.getLineCount() - 1); + } + if (descriptionLayout != null && descriptionLayout.getLineCount() != 0) { + height += descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); + } + if (linkLayout != null && linkLayout.getLineCount() > 0) { + height += linkLayout.getLineBottom(linkLayout.getLineCount() - 1); + } + height = Math.max(AndroidUtilities.dp(52), height); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), Math.max(AndroidUtilities.dp(68), height + AndroidUtilities.dp(16)) + (needDivider ? 1 : 0)); + + int maxPhotoWidth = AndroidUtilities.dp(52); + int x = LocaleController.isRTL ? MeasureSpec.getSize(widthMeasureSpec) - AndroidUtilities.dp(8) - maxPhotoWidth : AndroidUtilities.dp(8); + letterDrawable.setBounds(x, AndroidUtilities.dp(8), x + maxPhotoWidth, AndroidUtilities.dp(60)); + linkImageView.setImageCoords(x, AndroidUtilities.dp(8), maxPhotoWidth, maxPhotoWidth); + } + } + + public void setLink(TLRPC.BotInlineResult contextResult, boolean media, boolean divider, boolean shadow) { + needDivider = divider; + needShadow = shadow; + if (needShadow && shadowDrawable == null) { + shadowDrawable = getContext().getResources().getDrawable(R.drawable.header_shadow); + } + inlineResult = contextResult; + if (inlineResult != null && inlineResult.document != null) { + documentAttach = inlineResult.document; + } else { + documentAttach = null; + } + mediaWebpage = media; + requestLayout(); + updateButtonState(false); + } + + public void setGif(TLRPC.Document document, boolean divider) { + needDivider = divider; + needShadow = false; + inlineResult = null; + documentAttach = document; + mediaWebpage = true; + requestLayout(); + updateButtonState(false); + } + + public boolean isSticker() { + return documentAttachType == DOCUMENT_ATTACH_TYPE_STICKER; + } + + public boolean showingBitmap() { + return linkImageView.getBitmap() != null; + } + + public TLRPC.Document getDocument() { + return documentAttach; + } + + public void setScaled(boolean value) { + scaled = value; + lastUpdateTime = System.currentTimeMillis(); + invalidate(); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (drawLinkImageView) { + linkImageView.onDetachedFromWindow(); + } + MediaController.getInstance().removeLoadingFileObserver(this); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (drawLinkImageView) { + if (linkImageView.onAttachedToWindow()) { + updateButtonState(false); + } + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (Build.VERSION.SDK_INT >= 21 && getBackground() != null) { + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + getBackground().setHotspot(event.getX(), event.getY()); + } + } + + if (mediaWebpage || delegate == null || inlineResult == null) { + return super.onTouchEvent(event); + } + int x = (int) event.getX(); + int y = (int) event.getY(); + + boolean result = false; + int side = AndroidUtilities.dp(48); + if (inlineResult != null && inlineResult.content_url != null && inlineResult.content_url.length() > 0) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (letterDrawable.getBounds().contains(x, y)) { + buttonPressed = true; + result = true; + } + } else { + if (buttonPressed) { + if (event.getAction() == MotionEvent.ACTION_UP) { + buttonPressed = false; + playSoundEffect(SoundEffectConstants.CLICK); + delegate.didPressedImage(this); + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + buttonPressed = false; + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (!letterDrawable.getBounds().contains(x, y)) { + buttonPressed = false; + } + } + } + } + } + if (!result) { + result = super.onTouchEvent(event); + } + + return result; + } + + @Override + protected void onDraw(Canvas canvas) { + if (titleLayout != null) { + canvas.save(); + canvas.translate(AndroidUtilities.dp(LocaleController.isRTL ? 8 : AndroidUtilities.leftBaseline), titleY); + titleLayout.draw(canvas); + canvas.restore(); + } + + if (descriptionLayout != null) { + descriptionTextPaint.setColor(0xff8a8a8a); + canvas.save(); + canvas.translate(AndroidUtilities.dp(LocaleController.isRTL ? 8 : AndroidUtilities.leftBaseline), descriptionY); + descriptionLayout.draw(canvas); + canvas.restore(); + } + + if (linkLayout != null) { + descriptionTextPaint.setColor(Theme.MSG_LINK_TEXT_COLOR); + canvas.save(); + canvas.translate(AndroidUtilities.dp(LocaleController.isRTL ? 8 : AndroidUtilities.leftBaseline), linkY); + linkLayout.draw(canvas); + canvas.restore(); + } + + if (!mediaWebpage) { + if (inlineResult != null && inlineResult.type.equals("file")) { + int w = Theme.inlineDocDrawable.getIntrinsicWidth(); + int h = Theme.inlineDocDrawable.getIntrinsicHeight(); + int x = linkImageView.getImageX() + (AndroidUtilities.dp(52) - w) / 2; + int y = linkImageView.getImageY() + (AndroidUtilities.dp(52) - h) / 2; + canvas.drawRect(linkImageView.getImageX(), linkImageView.getImageY(), linkImageView.getImageX() + AndroidUtilities.dp(52), linkImageView.getImageY() + AndroidUtilities.dp(52), LetterDrawable.paint); + Theme.inlineDocDrawable.setBounds(x, y, x + w, y + h); + Theme.inlineDocDrawable.draw(canvas); + } else if (inlineResult != null && (inlineResult.type.equals("audio") || inlineResult.type.equals("voice"))) { + int w = Theme.inlineAudioDrawable.getIntrinsicWidth(); + int h = Theme.inlineAudioDrawable.getIntrinsicHeight(); + int x = linkImageView.getImageX() + (AndroidUtilities.dp(52) - w) / 2; + int y = linkImageView.getImageY() + (AndroidUtilities.dp(52) - h) / 2; + canvas.drawRect(linkImageView.getImageX(), linkImageView.getImageY(), linkImageView.getImageX() + AndroidUtilities.dp(52), linkImageView.getImageY() + AndroidUtilities.dp(52), LetterDrawable.paint); + Theme.inlineAudioDrawable.setBounds(x, y, x + w, y + h); + Theme.inlineAudioDrawable.draw(canvas); + } else if (inlineResult != null && (inlineResult.type.equals("venue") || inlineResult.type.equals("geo"))) { + int w = Theme.inlineLocationDrawable.getIntrinsicWidth(); + int h = Theme.inlineLocationDrawable.getIntrinsicHeight(); + int x = linkImageView.getImageX() + (AndroidUtilities.dp(52) - w) / 2; + int y = linkImageView.getImageY() + (AndroidUtilities.dp(52) - h) / 2; + canvas.drawRect(linkImageView.getImageX(), linkImageView.getImageY(), linkImageView.getImageX() + AndroidUtilities.dp(52), linkImageView.getImageY() + AndroidUtilities.dp(52), LetterDrawable.paint); + Theme.inlineLocationDrawable.setBounds(x, y, x + w, y + h); + Theme.inlineLocationDrawable.draw(canvas); + } else { + letterDrawable.draw(canvas); + } + } else { + if (inlineResult != null && (inlineResult.send_message instanceof TLRPC.TL_botInlineMessageMediaGeo || inlineResult.send_message instanceof TLRPC.TL_botInlineMessageMediaVenue)) { + int w = Theme.inlineLocationDrawable.getIntrinsicWidth(); + int h = Theme.inlineLocationDrawable.getIntrinsicHeight(); + int x = linkImageView.getImageX() + (linkImageView.getImageWidth() - w) / 2; + int y = linkImageView.getImageY() + (linkImageView.getImageHeight() - h) / 2; + canvas.drawRect(linkImageView.getImageX(), linkImageView.getImageY(), linkImageView.getImageX() + linkImageView.getImageWidth(), linkImageView.getImageY() + linkImageView.getImageHeight(), LetterDrawable.paint); + Theme.inlineLocationDrawable.setBounds(x, y, x + w, y + h); + Theme.inlineLocationDrawable.draw(canvas); + } + } + if (drawLinkImageView) { + canvas.save(); + if (scaled && scale != 0.8f || !scaled && scale != 1.0f) { + long newTime = System.currentTimeMillis(); + long dt = (newTime - lastUpdateTime); + lastUpdateTime = newTime; + if (scaled && scale != 0.8f) { + scale -= dt / 400.0f; + if (scale < 0.8f) { + scale = 0.8f; + } + } else { + scale += dt / 400.0f; + if (scale > 1.0f) { + scale = 1.0f; + } + } + invalidate(); + } + canvas.scale(scale, scale, getMeasuredWidth() / 2, getMeasuredHeight() / 2); + linkImageView.draw(canvas); + canvas.restore(); + } + if (mediaWebpage && (documentAttachType == DOCUMENT_ATTACH_TYPE_PHOTO || documentAttachType == DOCUMENT_ATTACH_TYPE_GIF)) { + radialProgress.draw(canvas); + } + + if (needDivider && !mediaWebpage) { + if (LocaleController.isRTL) { + canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth() - AndroidUtilities.dp(AndroidUtilities.leftBaseline), getMeasuredHeight() - 1, paint); + } else { + canvas.drawLine(AndroidUtilities.dp(AndroidUtilities.leftBaseline), getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, paint); + } + } + if (needShadow && shadowDrawable != null) { + shadowDrawable.setBounds(0, 0, getMeasuredWidth(), AndroidUtilities.dp(3)); + shadowDrawable.draw(canvas); + } + } + + private Drawable getDrawableForCurrentState() { + return buttonState == 1 ? Theme.photoStatesDrawables[5][0] : null; + } + + public void updateButtonState(boolean animated) { + if (!mediaWebpage || Build.VERSION.SDK_INT < 11) { + return; + } + String fileName = null; + File cacheFile = null; + if (inlineResult != null) { + if (inlineResult.document instanceof TLRPC.TL_document) { + fileName = FileLoader.getAttachFileName(inlineResult.document); + cacheFile = FileLoader.getPathToAttach(inlineResult.document); + } else if (inlineResult.photo instanceof TLRPC.TL_photo) { + TLRPC.PhotoSize currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(inlineResult.photo.sizes, AndroidUtilities.getPhotoSize(), true); + fileName = FileLoader.getAttachFileName(currentPhotoObject); + cacheFile = FileLoader.getPathToAttach(currentPhotoObject); + } else if (inlineResult.content_url != null) { + fileName = Utilities.MD5(inlineResult.content_url) + "." + ImageLoader.getHttpUrlExtension(inlineResult.content_url, "jpg"); + cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); + } else if (inlineResult.thumb_url != null) { + fileName = Utilities.MD5(inlineResult.thumb_url) + "." + ImageLoader.getHttpUrlExtension(inlineResult.thumb_url, "jpg"); + cacheFile = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); + } + } else if (documentAttach != null) { + fileName = FileLoader.getAttachFileName(documentAttach); + cacheFile = FileLoader.getPathToAttach(documentAttach); + } + if (fileName == null) { + radialProgress.setBackground(null, false, false); + return; + } + if (cacheFile.exists() && cacheFile.length() == 0) { + cacheFile.delete(); + } + if (!cacheFile.exists()) { + MediaController.getInstance().addLoadingFileObserver(fileName, this); + boolean progressVisible = true; + buttonState = 1; + Float progress = ImageLoader.getInstance().getFileProgress(fileName); + float setProgress = progress != null ? progress : 0; + radialProgress.setProgress(setProgress, false); + radialProgress.setBackground(getDrawableForCurrentState(), progressVisible, animated); + invalidate(); + } else { + MediaController.getInstance().removeLoadingFileObserver(this); + buttonState = -1; + radialProgress.setBackground(getDrawableForCurrentState(), false, animated); + invalidate(); + } + } + + public void setDelegate(ContextLinkCellDelegate contextLinkCellDelegate) { + delegate = contextLinkCellDelegate; + } + + public TLRPC.BotInlineResult getResult() { + return inlineResult; + } + + @Override + public void onFailedDownload(String fileName) { + updateButtonState(false); + } + + @Override + public void onSuccessDownload(String fileName) { + radialProgress.setProgress(1, true); + updateButtonState(true); + } + + @Override + public void onProgressDownload(String fileName, float progress) { + radialProgress.setProgress(progress, true); + if (buttonState != 1) { + updateButtonState(false); + } + } + + @Override + public void onProgressUpload(String fileName, float progress, boolean isEncrypted) { + + } + + @Override + public int getObserverTag() { + return TAG; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java index 6c060940..d2f37a43 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DialogCell.java @@ -21,6 +21,7 @@ import android.text.Layout; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; +import android.util.Log; import android.view.MotionEvent; import org.telegram.PhoneFormat.PhoneFormat; @@ -40,6 +41,7 @@ import org.telegram.messenger.UserObject; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.ImageListActivity; import java.util.ArrayList; @@ -203,8 +205,9 @@ public class DialogCell extends BaseCell { countPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); lockDrawable = getResources().getDrawable(R.drawable.list_secret); - checkDrawable = getResources().getDrawable(R.drawable.dialogs_check); - halfCheckDrawable = getResources().getDrawable(R.drawable.dialogs_halfcheck); + setChecks(context); + //checkDrawable = getResources().getDrawable(R.drawable.dialogs_check); + //halfCheckDrawable = getResources().getDrawable(R.drawable.dialogs_halfcheck); clockDrawable = getResources().getDrawable(R.drawable.msg_clock); errorDrawable = getResources().getDrawable(R.drawable.dialogs_warning); countDrawable = getResources().getDrawable(R.drawable.dialogs_badge); @@ -229,6 +232,48 @@ public class DialogCell extends BaseCell { statusBG.setStroke(AndroidUtilities.dp(2), Color.WHITE); } + private static void setChecks(Context context) { + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + String check = themePrefs.getString("chatCheckStyle", ImageListActivity.getCheckName(0)); + if (check.equals(ImageListActivity.getCheckName(1))) { + checkDrawable = context.getResources().getDrawable(R.drawable.dialogs_check_2); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.dialogs_halfcheck_2); + } else if (check.equals(ImageListActivity.getCheckName(2))) { + checkDrawable = context.getResources().getDrawable(R.drawable.dialogs_check_3); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.dialogs_halfcheck_3); + } else if (check.equals(ImageListActivity.getCheckName(3))) { + checkDrawable = context.getResources().getDrawable(R.drawable.dialogs_check_4); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.dialogs_halfcheck_4); + } else if (check.equals(ImageListActivity.getCheckName(4))) { + checkDrawable = context.getResources().getDrawable(R.drawable.dialogs_check_5); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.dialogs_halfcheck_5); + } else if (check.equals(ImageListActivity.getCheckName(5))) { + checkDrawable = context.getResources().getDrawable(R.drawable.dialogs_check_6); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.dialogs_halfcheck_6); + } else if (check.equals(ImageListActivity.getCheckName(6))) { + checkDrawable = context.getResources().getDrawable(R.drawable.dialogs_check_7); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.dialogs_halfcheck_7); + } else if (check.equals(ImageListActivity.getCheckName(7))) { + checkDrawable = context.getResources().getDrawable(R.drawable.dialogs_check_8); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.dialogs_halfcheck_8); + } else if (check.equals(ImageListActivity.getCheckName(8))) { + checkDrawable = context.getResources().getDrawable(R.drawable.dialogs_check_9); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.dialogs_halfcheck_9); + } else if (check.equals(ImageListActivity.getCheckName(9))) { + checkDrawable = context.getResources().getDrawable(R.drawable.dialogs_check_10); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.dialogs_halfcheck_10); + } else if (check.equals(ImageListActivity.getCheckName(10))) { + checkDrawable = context.getResources().getDrawable(R.drawable.dialogs_check_11); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.dialogs_halfcheck_11); + } else if (check.equals(ImageListActivity.getCheckName(11))) { + checkDrawable = context.getResources().getDrawable(R.drawable.dialogs_check_12); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.dialogs_halfcheck_12); + } else { + checkDrawable = context.getResources().getDrawable(R.drawable.dialogs_check); + halfCheckDrawable = context.getResources().getDrawable(R.drawable.dialogs_halfcheck); + } + } + public void setDialog(TLRPC.Dialog dialog, int i, int type) { currentDialogId = dialog.id; isDialogCell = true; @@ -409,10 +454,10 @@ public class DialogCell extends BaseCell { } else { TLRPC.User fromUser = null; TLRPC.Chat fromChat = null; - if (message.messageOwner.from_id > 0) { + if (message.isFromUser()) { fromUser = MessagesController.getInstance().getUser(message.messageOwner.from_id); - } else if (message.messageOwner.from_id < 0) { - fromChat = MessagesController.getInstance().getChat(-message.messageOwner.from_id); + } else { + fromChat = MessagesController.getInstance().getChat(message.messageOwner.to_id.channel_id); } if (lastMessageDate != 0) { @@ -453,7 +498,7 @@ public class DialogCell extends BaseCell { if (mess.length() > 150) { mess = mess.substring(0, 150); } - mess = mess.replace("\n", " "); + mess = mess.replace('\n', ' '); //messageString = Emoji.replaceEmoji(AndroidUtilities.replaceTags(String.format("%s: %s", name.replace("\n", ""), mess), AndroidUtilities.FLAG_TAG_COLOR), messagePaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); messageString = Emoji.replaceEmoji(AndroidUtilities.replaceTags(String.format("%s: %s", name.replace("\n", ""), mess), AndroidUtilities.FLAG_TAG_COLOR), messagePaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); } else { @@ -467,7 +512,7 @@ public class DialogCell extends BaseCell { if (mess.length() > 150) { mess = mess.substring(0, 150); } - mess = mess.replace("\n", " "); + mess = mess.replace('\n', ' '); //messageString = Emoji.replaceEmoji(AndroidUtilities.replaceTags(String.format("%s: %s", name.replace("\n", ""), mess)), AndroidUtilities.FLAG_TAG_COLOR), messagePaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); messageString = Emoji.replaceEmoji(AndroidUtilities.replaceTags(String.format("%s: %s", name.replace("\n", ""), mess), AndroidUtilities.FLAG_TAG_COLOR), messagePaint.getFontMetricsInt(), AndroidUtilities.dp(20), false); } @@ -625,7 +670,7 @@ public class DialogCell extends BaseCell { } nameWidth = Math.max(AndroidUtilities.dp(12), nameWidth); - CharSequence nameStringFinal = TextUtils.ellipsize(nameString.replace("\n", " "), currentNamePaint, nameWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); + CharSequence nameStringFinal = TextUtils.ellipsize(nameString.replace('\n', ' '), currentNamePaint, nameWidth - AndroidUtilities.dp(12), TextUtils.TruncateAt.END); try { nameLayout = new StaticLayout(nameStringFinal, currentNamePaint, nameWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); } catch (Exception e) { @@ -679,7 +724,7 @@ public class DialogCell extends BaseCell { if (mess.length() > 150) { mess = mess.substring(0, 150); } - mess = mess.replace("\n", " "); + mess = mess.replace('\n', ' '); messageString = Emoji.replaceEmoji(mess, messagePaint.getFontMetricsInt(), AndroidUtilities.dp(17), false); } messageWidth = Math.max(AndroidUtilities.dp(12), messageWidth); @@ -1006,6 +1051,7 @@ public class DialogCell extends BaseCell { avatarLeftMargin = AndroidUtilities.dp(themePrefs.getInt("chatsAvatarMarginLeft", AndroidUtilities.isTablet() ? 13 : 9)); statusBG.setStroke(AndroidUtilities.dp(2), themePrefs.getInt("chatsRowColor", 0xffffffff)); + setChecks(this.getContext()); } @Override @@ -1055,7 +1101,11 @@ public class DialogCell extends BaseCell { if (messageLayout != null) { canvas.save(); canvas.translate(messageLeft, messageTop); + try { messageLayout.draw(canvas); + } catch (Exception e) { + FileLog.e("tmessages", e); + } canvas.restore(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java index 914b3066..e3c73628 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/DrawerProfileCell.java @@ -14,12 +14,15 @@ import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.os.Build; +import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; import android.view.View; @@ -38,6 +41,7 @@ import org.telegram.messenger.FileLog; import org.telegram.messenger.R; import org.telegram.tgnet.TLRPC; import org.telegram.messenger.UserConfig; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.LayoutHelper; @@ -52,10 +56,11 @@ public class DrawerProfileCell extends FrameLayout implements PhotoViewer.PhotoV private Rect srcRect = new Rect(); private Rect destRect = new Rect(); private Paint paint = new Paint(); + private int currentColor; public DrawerProfileCell(Context context) { super(context); - setBackgroundColor(0xff4c84b5); + setBackgroundColor(Theme.ACTION_BAR_PROFILE_COLOR); shadowView = new ImageView(context); shadowView.setVisibility(INVISIBLE); @@ -98,6 +103,7 @@ public class DrawerProfileCell extends FrameLayout implements PhotoViewer.PhotoV nameTextView.setSingleLine(true); if(!centerAvatar){ nameTextView.setGravity(Gravity.LEFT); + nameTextView.setEllipsize(TextUtils.TruncateAt.END); addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 16, 0, 16, 28)); }else{ nameTextView.setGravity(Gravity.CENTER); @@ -165,6 +171,11 @@ public class DrawerProfileCell extends FrameLayout implements PhotoViewer.PhotoV @Override protected void onDraw(Canvas canvas) { Drawable backgroundDrawable = ApplicationLoader.getCachedWallpaper(); + int color = ApplicationLoader.getServiceMessageColor(); + if (currentColor != color) { + currentColor = color; + shadowView.getDrawable().setColorFilter(new PorterDuffColorFilter(color | 0xff000000, PorterDuff.Mode.MULTIPLY)); + } SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); if (ApplicationLoader.isCustomTheme() && backgroundDrawable != null && !themePrefs.getBoolean("drawerHeaderBGCheck", false)) { phoneTextView.setTextColor(0xffffffff); @@ -220,7 +231,7 @@ public class DrawerProfileCell extends FrameLayout implements PhotoViewer.PhotoV } phoneTextView.setText(value); AvatarDrawable avatarDrawable = new AvatarDrawable(user); - avatarDrawable.setColor(0xff5c98cd); + avatarDrawable.setColor(Theme.ACTION_BAR_MAIN_AVATAR_COLOR); avatarImageView.setImage(photo, "50_50", avatarDrawable); updateTheme(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java index aa0c9bff..94ffcd3c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/MentionCell.java @@ -9,13 +9,16 @@ package org.telegram.ui.Cells; import android.content.Context; +import android.os.Build; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; +import android.view.MotionEvent; import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.R; import org.telegram.messenger.UserObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.Components.AvatarDrawable; @@ -34,6 +37,8 @@ public class MentionCell extends LinearLayout { setOrientation(HORIZONTAL); + setBackgroundResource(R.drawable.list_selector); + avatarDrawable = new AvatarDrawable(); avatarDrawable.setSmallStyle(true); @@ -63,6 +68,16 @@ public class MentionCell extends LinearLayout { super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(36), MeasureSpec.EXACTLY)); } + @Override + public boolean onTouchEvent(MotionEvent event) { + if (Build.VERSION.SDK_INT >= 21 && getBackground() != null) { + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + getBackground().setHotspot(event.getX(), event.getY()); + } + } + return super.onTouchEvent(event); + } + public void setUser(TLRPC.User user) { if (user == null) { nameTextView.setText(""); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachCameraCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachCameraCell.java new file mode 100644 index 00000000..4d2fc2e6 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachCameraCell.java @@ -0,0 +1,34 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.ui.Components.LayoutHelper; + +public class PhotoAttachCameraCell extends FrameLayout { + + public PhotoAttachCameraCell(Context context) { + super(context); + + ImageView imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + //imageView.setImageResource(R.drawable.ic_attach_photobig); + imageView.setBackgroundColor(0xff777777); + addView(imageView, LayoutHelper.createFrame(80, 80)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(86), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(80), MeasureSpec.EXACTLY)); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachPhotoCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachPhotoCell.java new file mode 100644 index 00000000..1f87cfff --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoAttachPhotoCell.java @@ -0,0 +1,145 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Rect; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.SoundEffectConstants; +import android.view.View; +import android.widget.FrameLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.R; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.CheckBox; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.PhotoViewer; + +public class PhotoAttachPhotoCell extends FrameLayout { + + private BackupImageView imageView; + private FrameLayout checkFrame; + private CheckBox checkBox; + private boolean isLast; + private boolean pressed; + private static Rect rect = new Rect(); + private PhotoAttachPhotoCellDelegate delegate; + + public interface PhotoAttachPhotoCellDelegate { + void onCheckClick(PhotoAttachPhotoCell v); + } + + private MediaController.PhotoEntry photoEntry; + + public PhotoAttachPhotoCell(Context context) { + super(context); + + imageView = new BackupImageView(context); + addView(imageView, LayoutHelper.createFrame(80, 80)); + checkFrame = new FrameLayout(context); + addView(checkFrame, LayoutHelper.createFrame(42, 42, Gravity.LEFT | Gravity.TOP, 38, 0, 0, 0)); + + checkBox = new CheckBox(context, R.drawable.checkbig); + checkBox.setSize(30); + checkBox.setCheckOffset(AndroidUtilities.dp(1)); + checkBox.setDrawBackground(true); + //checkBox.setColor(0xff3ccaef); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + checkBox.setColor(themePrefs.getInt("themeColor", AndroidUtilities.defColor)); + addView(checkBox, LayoutHelper.createFrame(30, 30, Gravity.LEFT | Gravity.TOP, 46, 4, 0, 0)); + checkBox.setVisibility(VISIBLE); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(80 + (isLast ? 0 : 6)), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(80), MeasureSpec.EXACTLY)); + } + + public MediaController.PhotoEntry getPhotoEntry() { + return photoEntry; + } + + public BackupImageView getImageView() { + return imageView; + } + + public CheckBox getCheckBox() { + return checkBox; + } + + public void setPhotoEntry(MediaController.PhotoEntry entry, boolean last) { + pressed = false; + photoEntry = entry; + isLast = last; + if (photoEntry.thumbPath != null) { + imageView.setImage(photoEntry.thumbPath, null, getResources().getDrawable(R.drawable.nophotos)); + } else if (photoEntry.path != null) { + imageView.setOrientation(photoEntry.orientation, true); + imageView.setImage("thumb://" + photoEntry.imageId + ":" + photoEntry.path, null, getResources().getDrawable(R.drawable.nophotos)); + } else { + imageView.setImageResource(R.drawable.nophotos); + } + boolean showing = PhotoViewer.getInstance().isShowingImage(photoEntry.path); + imageView.getImageReceiver().setVisible(!showing, true); + checkBox.setVisibility(showing ? View.INVISIBLE : View.VISIBLE); + requestLayout(); + } + + public void setChecked(boolean value, boolean animated) { + checkBox.setChecked(value, animated); + } + + public void setOnCheckClickLisnener(OnClickListener onCheckClickLisnener) { + checkFrame.setOnClickListener(onCheckClickLisnener); + } + + public void setDelegate(PhotoAttachPhotoCellDelegate delegate) { + this.delegate = delegate; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean result = false; + + checkFrame.getHitRect(rect); + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (rect.contains((int) event.getX(), (int) event.getY())) { + pressed = true; + invalidate(); + result = true; + } + } else if (pressed) { + if (event.getAction() == MotionEvent.ACTION_UP) { + getParent().requestDisallowInterceptTouchEvent(true); + pressed = false; + playSoundEffect(SoundEffectConstants.CLICK); + delegate.onCheckClick(this); + invalidate(); + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + pressed = false; + invalidate(); + } else if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (!(rect.contains((int) event.getX(), (int) event.getY()))) { + pressed = false; + invalidate(); + } + } + } + if (!result) { + result = super.onTouchEvent(event); + } + + return result; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerPhotoCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerPhotoCell.java index e39fb48a..c4d28b1d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerPhotoCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerPhotoCell.java @@ -52,7 +52,7 @@ public class PhotoPickerPhotoCell extends FrameLayout { super.onMeasure(MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(itemWidth, MeasureSpec.EXACTLY)); } - public void setChecked(final boolean checked, boolean animated) { + public void setChecked(final boolean checked, final boolean animated) { checkBox.setChecked(checked, animated); if (animator != null) { animator.cancel(); @@ -69,13 +69,20 @@ public class PhotoPickerPhotoCell extends FrameLayout { animator.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Object animation) { - if (animator.equals(animation)) { + if (animator != null && animator.equals(animation)) { animator = null; if (!checked) { setBackgroundColor(0); } } } + + @Override + public void onAnimationCancel(Object animation) { + if (animator != null && animator.equals(animation)) { + animator = null; + } + } }); animator.start(); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerSearchCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerSearchCell.java index cfeb5a5c..bcb61072 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerSearchCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/PhotoPickerSearchCell.java @@ -127,14 +127,14 @@ public class PhotoPickerSearchCell extends LinearLayout { layoutParams.width = 0; searchButton.setLayoutParams(layoutParams); if (allowGifs) { - searchButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (delegate != null) { - delegate.didPressedSearchButton(1); + searchButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (delegate != null) { + delegate.didPressedSearchButton(1); + } } - } - }); + }); } else { ViewProxy.setAlpha(searchButton, 0.5f); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java index beb03cf5..fd59cb48 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ProfileSearchCell.java @@ -35,6 +35,7 @@ import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.ActionBar.Theme; public class ProfileSearchCell extends BaseCell { @@ -110,7 +111,7 @@ public class ProfileSearchCell extends BaseCell { onlinePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); onlinePaint.setTextSize(AndroidUtilities.dp(16)); - onlinePaint.setColor(0xff316f9f); + onlinePaint.setColor(Theme.MSG_LINK_TEXT_COLOR); offlinePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); offlinePaint.setTextSize(AndroidUtilities.dp(16)); @@ -281,7 +282,7 @@ public class ProfileSearchCell extends BaseCell { } else if (user != null) { nameString2 = UserObject.getUserName(user); } - nameString = nameString2.replace("\n", " "); + nameString = nameString2.replace('\n', ' '); } if (nameString.length() == 0) { if (user != null && user.phone != null && user.phone.length() != 0) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioButtonCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioButtonCell.java new file mode 100644 index 00000000..6a6199f0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioButtonCell.java @@ -0,0 +1,90 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.ui.Components.FrameLayoutFixed; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RadioButton; + +public class RadioButtonCell extends FrameLayoutFixed { + + private TextView textView; + private TextView valueTextView; + private RadioButton radioButton; + private static Paint paint; + private boolean needDivider; + + public RadioButtonCell(Context context) { + super(context); + + if (paint == null) { + paint = new Paint(); + paint.setColor(0xffd9d9d9); + paint.setStrokeWidth(1); + } + + radioButton = new RadioButton(context); + radioButton.setSize(AndroidUtilities.dp(20)); + radioButton.setColor(0xffb3b3b3, 0xff37a9f0); + addView(radioButton, LayoutHelper.createFrame(22, 22, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, (LocaleController.isRTL ? 0 : 18), 10, (LocaleController.isRTL ? 18 : 0), 0)); + + textView = new TextView(context); + textView.setTextColor(0xff212121); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setLines(1); + textView.setMaxLines(1); + textView.setSingleLine(true); + textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, (LocaleController.isRTL ? 17 : 51), 10, (LocaleController.isRTL ? 51 : 17), 0)); + + valueTextView = new TextView(context); + valueTextView.setTextColor(0xff8a8a8a); + valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + valueTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + valueTextView.setLines(0); + valueTextView.setMaxLines(0); + valueTextView.setSingleLine(false); + valueTextView.setPadding(0, 0, 0, AndroidUtilities.dp(12)); + addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, (LocaleController.isRTL ? 17 : 51), 35, (LocaleController.isRTL ? 51 : 17), 0)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)); + } + + public void setTextAndValue(String text, String value, boolean checked, boolean divider) { + textView.setText(text); + valueTextView.setText(value); + needDivider = divider; + radioButton.setChecked(checked, false); + setWillNotDraw(!divider); + } + + public void setChecked(boolean checked, boolean animated) { + radioButton.setChecked(checked, animated); + } + + @Override + protected void onDraw(Canvas canvas) { + if (needDivider) { + canvas.drawLine(getPaddingLeft(), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, paint); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java new file mode 100644 index 00000000..fa879a4b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/RadioCell.java @@ -0,0 +1,103 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.LocaleController; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RadioButton; + +public class RadioCell extends FrameLayout { + + private TextView textView; + private RadioButton radioButton; + private static Paint paint; + private boolean needDivider; + + public RadioCell(Context context) { + super(context); + + if (paint == null) { + paint = new Paint(); + paint.setColor(0xffd9d9d9); + paint.setStrokeWidth(1); + } + + textView = new TextView(context); + textView.setTextColor(0xff212121); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setLines(1); + textView.setMaxLines(1); + textView.setSingleLine(true); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 0, 17, 0)); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + radioButton = new RadioButton(context); + radioButton.setSize(AndroidUtilities.dp(20)); + radioButton.setColor(0xffb3b3b3, /*0xff37a9f0*/ def); + addView(radioButton, LayoutHelper.createFrame(22, 22, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, (LocaleController.isRTL ? 18 : 0), 13, (LocaleController.isRTL ? 0 : 18), 0)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), AndroidUtilities.dp(48) + (needDivider ? 1 : 0)); + + int availableWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - AndroidUtilities.dp(34); + radioButton.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(22), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(22), MeasureSpec.EXACTLY)); + textView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(getMeasuredHeight(), MeasureSpec.EXACTLY)); + } + + public void setTextColor(int color) { + textView.setTextColor(color); + } + + public void setText(String text, boolean checked, boolean divider) { + textView.setText(text); + radioButton.setChecked(checked, false); + needDivider = divider; + setWillNotDraw(!divider); + } + + public void setChecked(boolean checked, boolean animated) { + radioButton.setChecked(checked, animated); + } + + @Override + protected void onDraw(Canvas canvas) { + if (needDivider) { + canvas.drawLine(getPaddingLeft(), getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, paint); + } + setTheme(); + } + + private void setTheme(){ + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + //int summaryColor = preferences.getInt("profileSummaryColor", 0xff212121); + int summaryColor = preferences.getInt("prefSummaryColor", 0xff212121); + //int shadowColor = preferences.getInt("prefShadowColor", 0xfff0f0f0); + String tag = getTag() != null ? getTag().toString() : ""; + if(tag.contains("Pref")){ + textView.setTextColor(summaryColor); + } + + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SendLocationCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SendLocationCell.java index e78a8c39..e7d11b6f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SendLocationCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SendLocationCell.java @@ -17,7 +17,7 @@ import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.ui.Components.LayoutHelper; -import org.telegram.ui.Components.SimpleTextView; +import org.telegram.ui.ActionBar.SimpleTextView; public class SendLocationCell extends FrameLayout { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShadowSectionCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShadowSectionCell.java index ca9494ed..44860f51 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShadowSectionCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShadowSectionCell.java @@ -18,6 +18,8 @@ import org.telegram.messenger.R; public class ShadowSectionCell extends View { + private int size = 12; + boolean bTheme; public ShadowSectionCell(Context context) { super(context); @@ -25,6 +27,13 @@ public class ShadowSectionCell extends View { bTheme = true; } + public void setSize(int value) { + size = value; + + + + } + public ShadowSectionCell(Context context, boolean theme) { super(context); setBackgroundResource(R.drawable.greydivider); @@ -33,7 +42,7 @@ public class ShadowSectionCell extends View { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(12), MeasureSpec.EXACTLY)); + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(size), MeasureSpec.EXACTLY)); if(bTheme)setTheme(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java new file mode 100644 index 00000000..9310bf4b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/ShareDialogCell.java @@ -0,0 +1,118 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Build; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.widget.FrameLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.CheckBox; +import org.telegram.ui.Components.LayoutHelper; + +public class ShareDialogCell extends FrameLayout { + + private BackupImageView imageView; + private TextView nameTextView; + private CheckBox checkBox; + private AvatarDrawable avatarDrawable = new AvatarDrawable(); + + public ShareDialogCell(Context context) { + super(context); + setBackgroundResource(R.drawable.list_selector); + + imageView = new BackupImageView(context); + imageView.setRoundRadius(AndroidUtilities.dp(27)); + addView(imageView, LayoutHelper.createFrame(54, 54, Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, 7, 0, 0)); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int nColor = themePrefs.getInt("chatAttachTextColor", 0xff757575); + nameTextView = new TextView(context); + //nameTextView.setTextColor(0xff212121); + nameTextView.setTextColor(nColor != 0xff757575 ? nColor : 0xff212121); + nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); + nameTextView.setMaxLines(2); + nameTextView.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL); + nameTextView.setLines(2); + nameTextView.setEllipsize(TextUtils.TruncateAt.END); + addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 6, 64, 6, 0)); + + checkBox = new CheckBox(context, R.drawable.round_check2); + checkBox.setSize(24); + checkBox.setCheckOffset(AndroidUtilities.dp(1)); + checkBox.setVisibility(VISIBLE); + checkBox.setColor(0xff3ec1f9); + addView(checkBox, LayoutHelper.createFrame(24, 24, Gravity.CENTER_HORIZONTAL | Gravity.TOP, 17, 39, 0, 0)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(100), MeasureSpec.EXACTLY)); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (Build.VERSION.SDK_INT >= 21 && getBackground() != null) { + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + getBackground().setHotspot(event.getX(), event.getY()); + } + } + return super.onTouchEvent(event); + } + + public void setDialog(TLRPC.Dialog dialog, boolean checked, CharSequence name) { + int lower_id = (int) dialog.id; + TLRPC.FileLocation photo = null; + if (lower_id > 0) { + TLRPC.User user = MessagesController.getInstance().getUser(lower_id); + if (name != null) { + nameTextView.setText(name); + } else if (user != null) { + nameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); + } else { + nameTextView.setText(""); + } + avatarDrawable.setInfo(user); + if (user != null && user.photo != null) { + photo = user.photo.photo_small; + } + } else { + TLRPC.Chat chat = MessagesController.getInstance().getChat(-lower_id); + if (name != null) { + nameTextView.setText(name); + } else if (chat != null) { + nameTextView.setText(chat.title); + } else { + nameTextView.setText(""); + } + avatarDrawable.setInfo(chat); + if (chat != null && chat.photo != null) { + photo = chat.photo.photo_small; + } + } + imageView.setImage(photo, "50_50", avatarDrawable); + checkBox.setChecked(checked, false); + } + + public void setChecked(boolean checked, boolean animated) { + checkBox.setChecked(checked, animated); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedDocumentCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedDocumentCell.java index a5b6cca6..63475c9b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedDocumentCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedDocumentCell.java @@ -146,7 +146,7 @@ public class SharedDocumentCell extends FrameLayout implements MediaController.F } if (color == -1) { int idx; - String ext = (idx = name.lastIndexOf(".")) == -1 ? "" : name.substring(idx + 1); + String ext = (idx = name.lastIndexOf('.')) == -1 ? "" : name.substring(idx + 1); if (ext.length() != 0) { color = ext.charAt(0) % icons.length; } else { @@ -198,29 +198,49 @@ public class SharedDocumentCell extends FrameLayout implements MediaController.F checkBox.setChecked(checked, animated); } - public void setDocument(MessageObject document, boolean divider) { + public void setDocument(MessageObject messageObject, boolean divider) { needDivider = divider; - message = document; + message = messageObject; loaded = false; loading = false; - if (document != null && document.messageOwner.media != null && document.messageOwner.media.document != null) { + if (messageObject != null && messageObject.getDocument() != null) { int idx; - String name = FileLoader.getDocumentFileName(document.messageOwner.media.document); + String name = null; + if (messageObject.isMusic()) { + TLRPC.Document document; + if (messageObject.type == 0) { + document = messageObject.messageOwner.media.webpage.document; + } else { + document = messageObject.messageOwner.media.document; + } + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.performer != null && attribute.performer.length() != 0 || attribute.title != null && attribute.title.length() != 0) { + name = messageObject.getMusicAuthor() + " - " + messageObject.getMusicTitle(); + } + } + } + } + String fileName = FileLoader.getDocumentFileName(messageObject.getDocument()); + if (name == null) { + name = fileName; + } + nameTextView.setText(name); placeholderImabeView.setVisibility(VISIBLE); extTextView.setVisibility(VISIBLE); - placeholderImabeView.setImageResource(getThumbForNameOrMime(name, document.messageOwner.media.document.mime_type)); - nameTextView.setText(name); - extTextView.setText((idx = name.lastIndexOf(".")) == -1 ? "" : name.substring(idx + 1).toLowerCase()); - if (document.messageOwner.media.document.thumb instanceof TLRPC.TL_photoSizeEmpty || document.messageOwner.media.document.thumb == null) { + placeholderImabeView.setImageResource(getThumbForNameOrMime(fileName, messageObject.getDocument().mime_type)); + extTextView.setText((idx = fileName.lastIndexOf('.')) == -1 ? "" : fileName.substring(idx + 1).toLowerCase()); + if (messageObject.getDocument().thumb instanceof TLRPC.TL_photoSizeEmpty || messageObject.getDocument().thumb == null) { thumbImageView.setVisibility(INVISIBLE); thumbImageView.setImageBitmap(null); } else { thumbImageView.setVisibility(VISIBLE); - thumbImageView.setImage(document.messageOwner.media.document.thumb.location, "40_40", (Drawable) null); + thumbImageView.setImage(messageObject.getDocument().thumb.location, "40_40", (Drawable) null); } - long date = (long) document.messageOwner.date * 1000; - dateTextView.setText(String.format("%s, %s", AndroidUtilities.formatFileSize(document.messageOwner.media.document.size), LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.getInstance().formatterYear.format(new Date(date)), LocaleController.getInstance().formatterDay.format(new Date(date))))); + long date = (long) messageObject.messageOwner.date * 1000; + dateTextView.setText(String.format("%s, %s", AndroidUtilities.formatFileSize(messageObject.getDocument().size), LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.getInstance().formatterYear.format(new Date(date)), LocaleController.getInstance().formatterDay.format(new Date(date))))); } else { nameTextView.setText(""); extTextView.setText(""); @@ -243,7 +263,7 @@ public class SharedDocumentCell extends FrameLayout implements MediaController.F if (message.messageOwner.attachPath == null || message.messageOwner.attachPath.length() == 0 || !(new File(message.messageOwner.attachPath).exists())) { cacheFile = FileLoader.getPathToMessage(message.messageOwner); if (!cacheFile.exists()) { - fileName = FileLoader.getAttachFileName(message.messageOwner.media.document); + fileName = FileLoader.getAttachFileName(message.getDocument()); } } loaded = false; @@ -281,7 +301,7 @@ public class SharedDocumentCell extends FrameLayout implements MediaController.F } } - public MessageObject getDocument() { + public MessageObject getMessage() { return message; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedLinkCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedLinkCell.java new file mode 100644 index 00000000..fe3906bc --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedLinkCell.java @@ -0,0 +1,494 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.MotionEvent; +import android.widget.FrameLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.R; +import org.telegram.messenger.browser.Browser; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.CheckBox; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LetterDrawable; +import org.telegram.ui.Components.LinkPath; + +import java.io.File; +import java.util.ArrayList; +import java.util.Locale; + +public class SharedLinkCell extends FrameLayout { + + public interface SharedLinkCellDelegate { + void needOpenWebView(TLRPC.WebPage webPage); + boolean canPerformActions(); + } + + private boolean linkPreviewPressed; + private LinkPath urlPath = new LinkPath(); + private static Paint urlPaint; + private int pressedLink; + + private ImageReceiver linkImageView; + private boolean drawLinkImageView; + private LetterDrawable letterDrawable; + private CheckBox checkBox; + + private SharedLinkCellDelegate delegate; + + private boolean needDivider; + + ArrayList links = new ArrayList<>(); + private int linkY; + private ArrayList linkLayout = new ArrayList<>(); + + private int titleY = AndroidUtilities.dp(7); + private StaticLayout titleLayout; + + private int descriptionY = AndroidUtilities.dp(27); + private StaticLayout descriptionLayout; + + private int description2Y = AndroidUtilities.dp(27); + private StaticLayout descriptionLayout2; + + private MessageObject message; + + private static TextPaint titleTextPaint; + private static TextPaint descriptionTextPaint; + private static Paint paint; + + public SharedLinkCell(Context context) { + super(context); + + if (titleTextPaint == null) { + titleTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + titleTextPaint.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleTextPaint.setColor(0xff212121); + titleTextPaint.setTextSize(AndroidUtilities.dp(16)); + + descriptionTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + descriptionTextPaint.setTextSize(AndroidUtilities.dp(16)); + + paint = new Paint(); + paint.setColor(0xffd9d9d9); + paint.setStrokeWidth(1); + + urlPaint = new Paint(); + urlPaint.setColor(Theme.MSG_LINK_SELECT_BACKGROUND_COLOR); + } + + setWillNotDraw(false); + linkImageView = new ImageReceiver(this); + letterDrawable = new LetterDrawable(); + + checkBox = new CheckBox(context, R.drawable.round_check2); + checkBox.setVisibility(INVISIBLE); + addView(checkBox, LayoutHelper.createFrame(22, 22, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 44, 44, LocaleController.isRTL ? 44 : 0, 0)); + } + + @SuppressLint("DrawAllocation") + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + drawLinkImageView = false; + descriptionLayout = null; + titleLayout = null; + descriptionLayout2 = null; + description2Y = descriptionY; + linkLayout.clear(); + links.clear(); + + int maxWidth = MeasureSpec.getSize(widthMeasureSpec) - AndroidUtilities.dp(AndroidUtilities.leftBaseline) - AndroidUtilities.dp(8); + + String title = null; + String description = null; + String description2 = null; + String webPageLink = null; + boolean hasPhoto = false; + + if (message.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && message.messageOwner.media.webpage instanceof TLRPC.TL_webPage) { + TLRPC.WebPage webPage = message.messageOwner.media.webpage; + if (message.photoThumbs == null && webPage.photo != null) { + message.generateThumbs(true); + } + hasPhoto = webPage.photo != null && message.photoThumbs != null; + title = webPage.title; + if (title == null) { + title = webPage.site_name; + } + description = webPage.description; + webPageLink = webPage.url; + } + if (message != null && !message.messageOwner.entities.isEmpty()) { + for (int a = 0; a < message.messageOwner.entities.size(); a++) { + TLRPC.MessageEntity entity = message.messageOwner.entities.get(a); + if (entity.length <= 0 || entity.offset < 0 || entity.offset >= message.messageOwner.message.length()) { + continue; + } else if (entity.offset + entity.length > message.messageOwner.message.length()) { + entity.length = message.messageOwner.message.length() - entity.offset; + } + if (a == 0 && webPageLink != null && !(entity.offset == 0 && entity.length == message.messageOwner.message.length())) { + if (message.messageOwner.entities.size() == 1) { + if (description == null) { + description2 = message.messageOwner.message; + } + } else { + description2 = message.messageOwner.message; + } + } + try { + String link = null; + if (entity instanceof TLRPC.TL_messageEntityTextUrl || entity instanceof TLRPC.TL_messageEntityUrl) { + if (entity instanceof TLRPC.TL_messageEntityUrl) { + link = message.messageOwner.message.substring(entity.offset, entity.offset + entity.length); + } else { + link = entity.url; + } + if (title == null || title.length() == 0) { + title = link; + Uri uri = Uri.parse(title); + title = uri.getHost(); + if (title == null) { + title = link; + } + int index; + if (title != null && (index = title.lastIndexOf('.')) >= 0) { + title = title.substring(0, index); + if ((index = title.lastIndexOf('.')) >= 0) { + title = title.substring(index + 1); + } + title = title.substring(0, 1).toUpperCase() + title.substring(1); + } + if (entity.offset != 0 || entity.length != message.messageOwner.message.length()) { + description = message.messageOwner.message; + } + } + } else if (entity instanceof TLRPC.TL_messageEntityEmail) { + if (title == null || title.length() == 0) { + link = "mailto:" + message.messageOwner.message.substring(entity.offset, entity.offset + entity.length); + title = message.messageOwner.message.substring(entity.offset, entity.offset + entity.length); + if (entity.offset != 0 || entity.length != message.messageOwner.message.length()) { + description = message.messageOwner.message; + } + } + } + if (link != null) { + if (link.toLowerCase().indexOf("http") != 0 && link.toLowerCase().indexOf("mailto") != 0) { + links.add("http://" + link); + } else { + links.add(link); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + if (webPageLink != null && links.isEmpty()) { + links.add(webPageLink); + } + + if (title != null) { + try { + int width = (int) Math.ceil(titleTextPaint.measureText(title)); + CharSequence titleFinal = TextUtils.ellipsize(title.replace('\n', ' '), titleTextPaint, Math.min(width, maxWidth), TextUtils.TruncateAt.END); + titleLayout = new StaticLayout(titleFinal, titleTextPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + letterDrawable.setTitle(title); + } + + if (description != null) { + try { + descriptionLayout = ChatMessageCell.generateStaticLayout(description, descriptionTextPaint, maxWidth, maxWidth, 0, 3); + if (descriptionLayout.getLineCount() > 0) { + description2Y = descriptionY + descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1) + AndroidUtilities.dp(1); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + if (description2 != null) { + try { + descriptionLayout2 = ChatMessageCell.generateStaticLayout(description2, descriptionTextPaint, maxWidth, maxWidth, 0, 3); + int height = descriptionLayout2.getLineBottom(descriptionLayout2.getLineCount() - 1); + if (descriptionLayout != null) { + description2Y += AndroidUtilities.dp(10); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + if (!links.isEmpty()) { + for (int a = 0; a < links.size(); a++) { + try { + String link = links.get(a); + int width = (int) Math.ceil(descriptionTextPaint.measureText(link)); + CharSequence linkFinal = TextUtils.ellipsize(link.replace('\n', ' '), descriptionTextPaint, Math.min(width, maxWidth), TextUtils.TruncateAt.MIDDLE); + StaticLayout layout = new StaticLayout(linkFinal, descriptionTextPaint, maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + linkY = description2Y; + if (descriptionLayout2 != null && descriptionLayout2.getLineCount() != 0) { + linkY += descriptionLayout2.getLineBottom(descriptionLayout2.getLineCount() - 1) + AndroidUtilities.dp(1); + } + linkLayout.add(layout); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + int maxPhotoWidth = AndroidUtilities.dp(52); + int x = LocaleController.isRTL ? MeasureSpec.getSize(widthMeasureSpec) - AndroidUtilities.dp(10) - maxPhotoWidth : AndroidUtilities.dp(10); + letterDrawable.setBounds(x, AndroidUtilities.dp(10), x + maxPhotoWidth, AndroidUtilities.dp(62)); + + if (hasPhoto) { + TLRPC.PhotoSize currentPhotoObject = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, maxPhotoWidth, true); + TLRPC.PhotoSize currentPhotoObjectThumb = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, 80); + if (currentPhotoObjectThumb == currentPhotoObject) { + currentPhotoObjectThumb = null; + } + currentPhotoObject.size = -1; + if (currentPhotoObjectThumb != null) { + currentPhotoObjectThumb.size = -1; + } + linkImageView.setImageCoords(x, AndroidUtilities.dp(10), maxPhotoWidth, maxPhotoWidth); + String fileName = FileLoader.getAttachFileName(currentPhotoObject); + boolean photoExist = true; + File cacheFile = FileLoader.getPathToAttach(currentPhotoObject, true); + if (!cacheFile.exists()) { + photoExist = false; + } + String filter = String.format(Locale.US, "%d_%d", maxPhotoWidth, maxPhotoWidth); + if (photoExist || MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_PHOTO) || FileLoader.getInstance().isLoadingFile(fileName)) { + linkImageView.setImage(currentPhotoObject.location, filter, currentPhotoObjectThumb != null ? currentPhotoObjectThumb.location : null, String.format(Locale.US, "%d_%d_b", maxPhotoWidth, maxPhotoWidth), 0, null, false); + } else { + if (currentPhotoObjectThumb != null) { + linkImageView.setImage(null, null, currentPhotoObjectThumb.location, String.format(Locale.US, "%d_%d_b", maxPhotoWidth, maxPhotoWidth), 0, null, false); + } else { + linkImageView.setImageBitmap((Drawable) null); + } + } + drawLinkImageView = true; + } + + int height = 0; + if (titleLayout != null && titleLayout.getLineCount() != 0) { + height += titleLayout.getLineBottom(titleLayout.getLineCount() - 1); + } + if (descriptionLayout != null && descriptionLayout.getLineCount() != 0) { + height += descriptionLayout.getLineBottom(descriptionLayout.getLineCount() - 1); + } + if (descriptionLayout2 != null && descriptionLayout2.getLineCount() != 0) { + height += descriptionLayout2.getLineBottom(descriptionLayout2.getLineCount() - 1); + if (descriptionLayout != null) { + height += AndroidUtilities.dp(10); + } + } + for (int a = 0; a < linkLayout.size(); a++) { + StaticLayout layout = linkLayout.get(a); + if (layout.getLineCount() > 0) { + height += layout.getLineBottom(layout.getLineCount() - 1); + } + } + if (hasPhoto) { + height = Math.max(AndroidUtilities.dp(48), height); + } + checkBox.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(22), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(22), MeasureSpec.EXACTLY)); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), Math.max(AndroidUtilities.dp(72), height + AndroidUtilities.dp(16)) + (needDivider ? 1 : 0)); + } + + public void setLink(MessageObject messageObject, boolean divider) { + needDivider = divider; + resetPressedLink(); + message = messageObject; + + requestLayout(); + } + + public void setDelegate(SharedLinkCellDelegate sharedLinkCellDelegate) { + delegate = sharedLinkCellDelegate; + } + + public MessageObject getMessage() { + return message; + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (drawLinkImageView) { + linkImageView.onDetachedFromWindow(); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (drawLinkImageView) { + linkImageView.onAttachedToWindow(); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean result = false; + if (message != null && !linkLayout.isEmpty() && delegate != null && delegate.canPerformActions()) { + if (event.getAction() == MotionEvent.ACTION_DOWN || linkPreviewPressed && event.getAction() == MotionEvent.ACTION_UP) { + int x = (int) event.getX(); + int y = (int) event.getY(); + int offset = 0; + boolean ok = false; + for (int a = 0; a < linkLayout.size(); a++) { + StaticLayout layout = linkLayout.get(a); + if (layout.getLineCount() > 0) { + int height = layout.getLineBottom(layout.getLineCount() - 1); + int linkPosX = AndroidUtilities.dp(LocaleController.isRTL ? 8 : AndroidUtilities.leftBaseline); + if (x >= linkPosX + layout.getLineLeft(0) && x <= linkPosX + layout.getLineWidth(0) && y >= linkY + offset && y <= linkY + offset + height) { + ok = true; + if (event.getAction() == MotionEvent.ACTION_DOWN) { + resetPressedLink(); + pressedLink = a; + linkPreviewPressed = true; + try { + urlPath.setCurrentLayout(layout, 0, 0); + layout.getSelectionPath(0, layout.getText().length(), urlPath); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + result = true; + } else if (linkPreviewPressed) { + try { + TLRPC.WebPage webPage = pressedLink == 0 && message.messageOwner.media != null ? message.messageOwner.media.webpage : null; + if (webPage != null && Build.VERSION.SDK_INT >= 16 && webPage.embed_url != null && webPage.embed_url.length() != 0) { + delegate.needOpenWebView(webPage); + } else { + Browser.openUrl(getContext(), links.get(pressedLink)); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + resetPressedLink(); + result = true; + } + break; + } + offset += height; + } + } + if (!ok) { + resetPressedLink(); + } + } else if (event.getAction() == MotionEvent.ACTION_CANCEL) { + resetPressedLink(); + } + } else { + resetPressedLink(); + } + return result || super.onTouchEvent(event); + } + + public String getLink(int num) { + if (num < 0 || num >= links.size()) { + return null; + } + return links.get(num); + } + + protected void resetPressedLink() { + pressedLink = -1; + linkPreviewPressed = false; + invalidate(); + } + + public void setChecked(boolean checked, boolean animated) { + if (checkBox.getVisibility() != VISIBLE) { + checkBox.setVisibility(VISIBLE); + } + checkBox.setChecked(checked, animated); + } + + @Override + protected void onDraw(Canvas canvas) { + if (titleLayout != null) { + canvas.save(); + canvas.translate(AndroidUtilities.dp(LocaleController.isRTL ? 8 : AndroidUtilities.leftBaseline), titleY); + titleLayout.draw(canvas); + canvas.restore(); + } + + if (descriptionLayout != null) { + descriptionTextPaint.setColor(0xff212121); + canvas.save(); + canvas.translate(AndroidUtilities.dp(LocaleController.isRTL ? 8 : AndroidUtilities.leftBaseline), descriptionY); + descriptionLayout.draw(canvas); + canvas.restore(); + } + + if (descriptionLayout2 != null) { + descriptionTextPaint.setColor(0xff212121); + canvas.save(); + canvas.translate(AndroidUtilities.dp(LocaleController.isRTL ? 8 : AndroidUtilities.leftBaseline), description2Y); + descriptionLayout2.draw(canvas); + canvas.restore(); + } + + if (!linkLayout.isEmpty()) { + descriptionTextPaint.setColor(Theme.MSG_LINK_TEXT_COLOR); + int offset = 0; + for (int a = 0; a < linkLayout.size(); a++) { + StaticLayout layout = linkLayout.get(a); + if (layout.getLineCount() > 0) { + canvas.save(); + canvas.translate(AndroidUtilities.dp(LocaleController.isRTL ? 8 : AndroidUtilities.leftBaseline), linkY + offset); + if (pressedLink == a) { + canvas.drawPath(urlPath, urlPaint); + } + layout.draw(canvas); + canvas.restore(); + offset += layout.getLineBottom(layout.getLineCount() - 1); + } + } + } + + letterDrawable.draw(canvas); + if (drawLinkImageView) { + linkImageView.draw(canvas); + } + + if (needDivider) { + if (LocaleController.isRTL) { + canvas.drawLine(0, getMeasuredHeight() - 1, getMeasuredWidth() - AndroidUtilities.dp(AndroidUtilities.leftBaseline), getMeasuredHeight() - 1, paint); + } else { + canvas.drawLine(AndroidUtilities.dp(AndroidUtilities.leftBaseline), getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight() - 1, paint); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell.java index 36214478..333a8687 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/SharedPhotoVideoCell.java @@ -123,13 +123,20 @@ public class SharedPhotoVideoCell extends FrameLayoutFixed { animator.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Object animation) { - if (animator.equals(animation)) { + if (animator != null && animator.equals(animation)) { animator = null; if (!checked) { setBackgroundColor(0); } } } + + @Override + public void onAnimationCancel(Object animation) { + if (animator != null && animator.equals(animation)) { + animator = null; + } + } }); animator.start(); } else { @@ -226,14 +233,21 @@ public class SharedPhotoVideoCell extends FrameLayoutFixed { PhotoVideoView photoVideoView = photoVideoViews[a]; photoVideoView.imageView.getImageReceiver().setParentMessageObject(messageObject); photoVideoView.imageView.getImageReceiver().setVisible(!PhotoViewer.getInstance().isShowingImage(messageObject), false); - if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo && messageObject.messageOwner.media.video != null) { + if (messageObject.isVideo()) { photoVideoView.videoInfoContainer.setVisibility(VISIBLE); - int duration = messageObject.messageOwner.media.video.duration; + int duration = 0; + for (int b = 0; b < messageObject.getDocument().attributes.size(); b++) { + TLRPC.DocumentAttribute attribute = messageObject.getDocument().attributes.get(b); + if (attribute instanceof TLRPC.TL_documentAttributeVideo) { + duration = attribute.duration; + break; + } + } int minutes = duration / 60; int seconds = duration - minutes * 60; photoVideoView.videoTextView.setText(String.format("%d:%02d", minutes, seconds)); - if (messageObject.messageOwner.media.video.thumb != null) { - TLRPC.FileLocation location = messageObject.messageOwner.media.video.thumb.location; + if (messageObject.getDocument().thumb != null) { + TLRPC.FileLocation location = messageObject.getDocument().thumb.location; photoVideoView.imageView.setImage(null, null, null, ApplicationLoader.applicationContext.getResources().getDrawable(R.drawable.photo_placeholder_in), null, location, "b", null, 0); } else { photoVideoView.imageView.setImageResource(R.drawable.photo_placeholder_in); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerCell.java index 5f51556e..6116b06a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerCell.java @@ -9,7 +9,12 @@ package org.telegram.ui.Cells; import android.content.Context; +import android.graphics.Canvas; +import android.os.Build; +import android.util.Log; import android.view.Gravity; +import android.view.View; +import android.view.animation.AccelerateInterpolator; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.R; @@ -21,10 +26,16 @@ import org.telegram.ui.Components.LayoutHelper; public class StickerCell extends FrameLayoutFixed { private BackupImageView imageView; + private TLRPC.Document sticker; + private long lastUpdateTime; + private boolean scaled; + private float scale; + private long time = 0; + private static AccelerateInterpolator interpolator = new AccelerateInterpolator(0.5f); public StickerCell(Context context) { super(context); - + Log.e("StickerCell", "scaled " + scaled + " scale " + scale); imageView = new BackupImageView(context); imageView.setAspectFit(true); addView(imageView, LayoutHelper.createFrame(66, 66, Gravity.CENTER_HORIZONTAL, 0, 5, 0, 0)); @@ -48,6 +59,7 @@ public class StickerCell extends FrameLayoutFixed { if (document != null && document.thumb != null) { imageView.setImage(document.thumb.location, null, "webp", null); } + sticker = document; if (side == -1) { setBackgroundResource(R.drawable.stickers_back_left); setPadding(AndroidUtilities.dp(7), 0, 0, 0); @@ -65,4 +77,46 @@ public class StickerCell extends FrameLayoutFixed { getBackground().setAlpha(230); } } + + public TLRPC.Document getSticker() { + return sticker; + } + + public void setScaled(boolean value) { + scaled = value; + lastUpdateTime = System.currentTimeMillis(); + invalidate(); + } + + public boolean showingBitmap() { + return imageView.getImageReceiver().getBitmap() != null; + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + boolean result = super.drawChild(canvas, child, drawingTime); + if (child == imageView && (scaled && scale != 0.8f || !scaled && scale != 1.0f)) { + long newTime = System.currentTimeMillis(); + long dt = (newTime - lastUpdateTime); + lastUpdateTime = newTime; + if (scaled && scale != 0.8f) { + scale -= dt / 400.0f; + if (scale < 0.8f) { + scale = 0.8f; + } + } else { + scale += dt / 400.0f; + if (scale > 1.0f) { + scale = 1.0f; + } + } + if (Build.VERSION.SDK_INT >= 11) { + imageView.setScaleX(scale); + imageView.setScaleY(scale); + } + imageView.invalidate(); + invalidate(); + } + return result; + } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerEmojiCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerEmojiCell.java index ebbdb4da..af2825e4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerEmojiCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerEmojiCell.java @@ -36,7 +36,7 @@ public class StickerEmojiCell extends FrameLayout { private boolean scaled; private float scale; private long time = 0; - private AccelerateInterpolator interpolator = new AccelerateInterpolator(0.5f); + private static AccelerateInterpolator interpolator = new AccelerateInterpolator(0.5f); public StickerEmojiCell(Context context) { super(context); @@ -63,7 +63,8 @@ public class StickerEmojiCell extends FrameLayout { if (showEmoji) { boolean set = false; - for (TLRPC.DocumentAttribute attribute : document.attributes) { + for (int a = 0; a < document.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(a); if (attribute instanceof TLRPC.TL_documentAttributeSticker) { if (attribute.alt != null && attribute.alt.length() > 0) { emojiTextView.setText(Emoji.replaceEmoji(attribute.alt, emojiTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(16), false)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetCell.java new file mode 100644 index 00000000..9c1e2784 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/StickerSetCell.java @@ -0,0 +1,160 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.os.Build; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.AnimationCompat.ViewProxy; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.LayoutHelper; + +import java.util.ArrayList; + +public class StickerSetCell extends FrameLayout { + + private TextView textView; + private TextView valueTextView; + private BackupImageView imageView; + private boolean needDivider; + private ImageView optionsButton; + private TLRPC.TL_messages_stickerSet stickersSet; + private Rect rect = new Rect(); + + private static Paint paint; + + public StickerSetCell(Context context) { + super(context); + + if (paint == null) { + paint = new Paint(); + paint.setColor(0xffd9d9d9); + } + + textView = new TextView(context); + textView.setTextColor(0xff212121); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setLines(1); + textView.setMaxLines(1); + textView.setSingleLine(true); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, LocaleController.isRTL ? 40 : 71, 10, LocaleController.isRTL ? 71 : 40, 0)); + + valueTextView = new TextView(context); + valueTextView.setTextColor(0xff8a8a8a); + valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + valueTextView.setLines(1); + valueTextView.setMaxLines(1); + valueTextView.setSingleLine(true); + valueTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, LocaleController.isRTL ? 40 : 71, 35, LocaleController.isRTL ? 71 : 40, 0)); + + imageView = new BackupImageView(context); + imageView.setAspectFit(true); + addView(imageView, LayoutHelper.createFrame(48, 48, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 12, 8, LocaleController.isRTL ? 12 : 0, 0)); + + optionsButton = new ImageView(context); + optionsButton.setFocusable(false); + optionsButton.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_AUDIO_SELECTOR_COLOR)); + optionsButton.setImageResource(R.drawable.doc_actions_b); + optionsButton.setScaleType(ImageView.ScaleType.CENTER); + addView(optionsButton, LayoutHelper.createFrame(40, 40, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(64) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY)); + setTheme(); + } + + public void setStickersSet(TLRPC.TL_messages_stickerSet set, boolean divider) { + needDivider = divider; + stickersSet = set; + + textView.setText(stickersSet.set.title); + if (stickersSet.set.disabled) { + ViewProxy.setAlpha(textView, 0.5f); + ViewProxy.setAlpha(valueTextView, 0.5f); + ViewProxy.setAlpha(imageView, 0.5f); + } else { + ViewProxy.setAlpha(textView, 1.0f); + ViewProxy.setAlpha(valueTextView, 1.0f); + ViewProxy.setAlpha(imageView, 1.0f); + } + ArrayList documents = set.documents; + if (documents != null && !documents.isEmpty()) { + valueTextView.setText(LocaleController.formatPluralString("Stickers", documents.size())); + TLRPC.Document document = documents.get(0); + if (document.thumb != null && document.thumb.location != null) { + imageView.setImage(document.thumb.location, null, "webp", null); + } + } else { + valueTextView.setText(LocaleController.formatPluralString("Stickers", 0)); + } + } + + public void setOnOptionsClick(OnClickListener listener) { + optionsButton.setOnClickListener(listener); + } + + public TLRPC.TL_messages_stickerSet getStickersSet() { + return stickersSet; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (Build.VERSION.SDK_INT >= 21 && getBackground() != null) { + optionsButton.getHitRect(rect); + if (rect.contains((int) event.getX(), (int) event.getY())) { + return true; + } + if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) { + getBackground().setHotspot(event.getX(), event.getY()); + } + } + return super.onTouchEvent(event); + } + + @Override + protected void onDraw(Canvas canvas) { + if (needDivider) { + canvas.drawLine(0, getHeight() - 1, getWidth() - getPaddingRight(), getHeight() - 1, paint); + } + } + + private void setTheme(){ + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int bgColor = preferences.getInt("prefBGColor", 0xffffffff); + setBackgroundColor(bgColor); + int divColor = preferences.getInt("prefDividerColor", 0xffd9d9d9); + int titleColor = preferences.getInt("prefTitleColor", 0xff212121); + int summaryColor = preferences.getInt("prefSummaryColor", 0xff8a8a8a); + textView.setTextColor(titleColor); + valueTextView.setTextColor(summaryColor); + paint.setColor(divColor); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextBlockCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextBlockCell.java index c9a9fee6..37b6f197 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextBlockCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextBlockCell.java @@ -38,7 +38,7 @@ public class TextBlockCell extends FrameLayoutFixed { textView.setTextColor(0xff212121); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); - addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 8, 17, 8)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 10, 17, 10)); } public void setTextColor(int color) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java index b8573343..26bd1507 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCell.java @@ -20,35 +20,36 @@ import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.LocaleController; +import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.Components.LayoutHelper; public class TextCell extends FrameLayout { - private TextView textView; - private TextView valueTextView; + private SimpleTextView textView; + private SimpleTextView valueTextView; private ImageView imageView; private ImageView valueImageView; public TextCell(Context context) { super(context); - textView = new TextView(context); + textView = new SimpleTextView(context); textView.setTextColor(0xff212121); - textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - textView.setLines(1); - textView.setMaxLines(1); - textView.setSingleLine(true); - textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setTextSize(16); + //textView.setLines(1); + //textView.setMaxLines(1); + //textView.setSingleLine(true); + //textView.setEllipsize(TextUtils.TruncateAt.END); textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 16 : 71, 0, LocaleController.isRTL ? 71 : 16, 0)); - valueTextView = new TextView(context); + valueTextView = new SimpleTextView(context); //valueTextView.setTextColor(0xff2f8cc9); valueTextView.setTextColor(AndroidUtilities.getIntColor("themeColor")); - valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - valueTextView.setLines(1); - valueTextView.setMaxLines(1); - valueTextView.setSingleLine(true); + valueTextView.setTextSize(16); + //valueTextView.setLines(1); + //valueTextView.setMaxLines(1); + //valueTextView.setSingleLine(true); valueTextView.setGravity((LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.CENTER_VERTICAL); addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, LocaleController.isRTL ? 24 : 0, 0, LocaleController.isRTL ? 0 : 24, 0)); @@ -63,7 +64,37 @@ public class TextCell extends FrameLayout { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(48), MeasureSpec.EXACTLY)); + int width = MeasureSpec.getSize(widthMeasureSpec); + int height = AndroidUtilities.dp(48); + + valueTextView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(24), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + textView.measure(MeasureSpec.makeMeasureSpec(width - AndroidUtilities.dp(71 + 24), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.EXACTLY)); + imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); + valueImageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST)); + + setMeasuredDimension(width, AndroidUtilities.dp(48)); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + int height = bottom - top; + int width = right - left; + + int viewTop = (height - valueTextView.getTextHeight()) / 2; + int viewLeft = LocaleController.isRTL ? AndroidUtilities.dp(24) : 0; + valueTextView.layout(viewLeft, viewTop, viewLeft + valueTextView.getMeasuredWidth(), viewTop + valueTextView.getMeasuredHeight()); + + viewTop = (height - textView.getTextHeight()) / 2; + viewLeft = !LocaleController.isRTL ? AndroidUtilities.dp(71) : AndroidUtilities.dp(24); + textView.layout(viewLeft, viewTop, viewLeft + textView.getMeasuredWidth(), viewTop + textView.getMeasuredHeight()); + + viewTop = AndroidUtilities.dp(5); + viewLeft = !LocaleController.isRTL ? AndroidUtilities.dp(16) : width - imageView.getMeasuredWidth() - AndroidUtilities.dp(16); + imageView.layout(viewLeft, viewTop, viewLeft + imageView.getMeasuredWidth(), viewTop + imageView.getMeasuredHeight()); + + viewTop = (height - valueImageView.getMeasuredHeight()) / 2; + viewLeft = LocaleController.isRTL ? AndroidUtilities.dp(24) : width - valueImageView.getMeasuredWidth() - AndroidUtilities.dp(24); + valueImageView.layout(viewLeft, viewTop, viewLeft + valueImageView.getMeasuredWidth(), viewTop + valueImageView.getMeasuredHeight()); } public void setTextColor(int color) { @@ -72,6 +103,7 @@ public class TextCell extends FrameLayout { public void setText(String text) { textView.setText(text); + valueTextView.setText(null); imageView.setVisibility(INVISIBLE); valueTextView.setVisibility(INVISIBLE); valueImageView.setVisibility(INVISIBLE); @@ -79,6 +111,7 @@ public class TextCell extends FrameLayout { public void setTextAndIcon(String text, int resId) { textView.setText(text); + valueTextView.setText(null); imageView.setImageResource(resId); imageView.setVisibility(VISIBLE); valueTextView.setVisibility(INVISIBLE); @@ -108,6 +141,7 @@ public class TextCell extends FrameLayout { public void setTextAndValueDrawable(String text, Drawable drawable) { textView.setText(text); + valueTextView.setText(null); valueImageView.setVisibility(VISIBLE); valueImageView.setImageDrawable(drawable); valueTextView.setVisibility(INVISIBLE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java index 0c93c243..d4161f12 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextCheckCell.java @@ -28,9 +28,11 @@ import org.telegram.ui.Components.Switch; public class TextCheckCell extends FrameLayoutFixed { private TextView textView; + private TextView valueTextView; private Switch checkBox; private static Paint paint; private boolean needDivider; + private boolean isMultiline; public TextCheckCell(Context context) { super(context); @@ -47,9 +49,20 @@ public class TextCheckCell extends FrameLayoutFixed { textView.setLines(1); textView.setMaxLines(1); textView.setSingleLine(true); - textView.setEllipsize(TextUtils.TruncateAt.END); textView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); - addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, 17, 0, 60, 0)); + textView.setEllipsize(TextUtils.TruncateAt.END); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 64 : 17, 0, LocaleController.isRTL ? 17 : 64, 0)); + + valueTextView = new TextView(context); + valueTextView.setTextColor(0xff8a8a8a); + valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + valueTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + valueTextView.setLines(1); + valueTextView.setMaxLines(1); + valueTextView.setSingleLine(true); + valueTextView.setPadding(0, 0, 0, 0); + valueTextView.setEllipsize(TextUtils.TruncateAt.END); + addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 64 : 17, 35, LocaleController.isRTL ? 17 : 64, 0)); checkBox = new Switch(context); checkBox.setDuplicateParentStateEnabled(false); @@ -61,7 +74,11 @@ public class TextCheckCell extends FrameLayoutFixed { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(48) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY)); + if (isMultiline) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + } else { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(valueTextView.getVisibility() == VISIBLE ? 64 : 48) + (needDivider ? 1 : 0), MeasureSpec.EXACTLY)); + } setTheme(); } @@ -71,8 +88,45 @@ public class TextCheckCell extends FrameLayoutFixed { checkBox.resetLayout(); checkBox.requestLayout(); } + isMultiline = false; checkBox.setChecked(checked); needDivider = divider; + valueTextView.setVisibility(GONE); + LayoutParams layoutParams = (LayoutParams) textView.getLayoutParams(); + layoutParams.height = LayoutParams.MATCH_PARENT; + layoutParams.topMargin = 0; + textView.setLayoutParams(layoutParams); + setWillNotDraw(!divider); + } + + public void setTextAndValueAndCheck(String text, String value, boolean checked, boolean multiline, boolean divider) { + textView.setText(text); + valueTextView.setText(value); + if (Build.VERSION.SDK_INT < 11) { + checkBox.resetLayout(); + checkBox.requestLayout(); + } + checkBox.setChecked(checked); + needDivider = divider; + valueTextView.setVisibility(VISIBLE); + isMultiline = multiline; + if (multiline) { + valueTextView.setLines(0); + valueTextView.setMaxLines(0); + valueTextView.setSingleLine(false); + valueTextView.setEllipsize(null); + valueTextView.setPadding(0, 0, 0, AndroidUtilities.dp(11)); + } else { + valueTextView.setLines(1); + valueTextView.setMaxLines(1); + valueTextView.setSingleLine(true); + valueTextView.setEllipsize(TextUtils.TruncateAt.END); + valueTextView.setPadding(0, 0, 0, 0); + } + LayoutParams layoutParams = (LayoutParams) textView.getLayoutParams(); + layoutParams.height = LayoutParams.WRAP_CONTENT; + layoutParams.topMargin = AndroidUtilities.dp(10); + textView.setLayoutParams(layoutParams); setWillNotDraw(!divider); } @@ -93,7 +147,9 @@ public class TextCheckCell extends FrameLayoutFixed { setBackgroundColor(bgColor); int divColor = preferences.getInt("prefDividerColor", 0xffd9d9d9); int titleColor = preferences.getInt("prefTitleColor", 0xff212121); + int sumColor = preferences.getInt("prefSummaryColor", 0xff8a8a8a); textView.setTextColor(titleColor); + valueTextView.setTextColor(sumColor); paint.setColor(divColor); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextDetailSettingsCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextDetailSettingsCell.java index 32398e9b..2cd78d04 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextDetailSettingsCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextDetailSettingsCell.java @@ -12,6 +12,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.graphics.Canvas; import android.graphics.Paint; +import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.widget.TextView; @@ -84,6 +85,23 @@ public class TextDetailSettingsCell extends FrameLayoutFixed { } } + public void setMultilineText(boolean value) { + multiline = value; + if (value) { + textView.setLines(0); + textView.setMaxLines(0); + textView.setSingleLine(false); + textView.setPadding(0, 0, 0, AndroidUtilities.dp(35)); + removeView(valueTextView); + addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.BOTTOM, 17, 0, 17, 12)); + } else { + textView.setLines(1); + textView.setMaxLines(1); + textView.setSingleLine(true); + textView.setPadding(0, 0, 0, 0); + } + } + public void setTextAndValue(String text, String value, boolean divider) { textView.setText(text); valueTextView.setText(value); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSettingsCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSettingsCell.java index c2d64afb..d93db7bc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSettingsCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/TextSettingsCell.java @@ -92,6 +92,10 @@ public class TextSettingsCell extends FrameLayout { textView.setTextColor(color); } + public void setTextValueColor(int color) { + valueTextView.setTextColor(color); + } + public void setDividerColor(int color) { paint.setColor(color); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java index 23c38fd0..036aa161 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/UserCell.java @@ -26,13 +26,12 @@ import org.telegram.messenger.UserObject; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.SimpleTextView; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.CheckBox; import org.telegram.ui.Components.CheckBoxSquare; import org.telegram.ui.Components.LayoutHelper; -import org.telegram.ui.Components.SimpleTextView; - public class UserCell extends FrameLayout { private BackupImageView avatarImageView; @@ -41,6 +40,7 @@ public class UserCell extends FrameLayout { private ImageView imageView; private CheckBox checkBox; private CheckBoxSquare checkBoxBig; + private ImageView adminImage; private AvatarDrawable avatarDrawable; private TLObject currentObject = null; @@ -62,7 +62,7 @@ public class UserCell extends FrameLayout { private int radius = 32; - public UserCell(Context context, int padding, int checkbox) { + public UserCell(Context context, int padding, int checkbox, boolean admin) { super(context); avatarDrawable = new AvatarDrawable(); @@ -75,7 +75,7 @@ public class UserCell extends FrameLayout { nameTextView.setTextColor(0xff212121); nameTextView.setTextSize(17); nameTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP); - addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 28 : (68 + padding), 11.5f, LocaleController.isRTL ? (68 + padding) : 28, 0)); + addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 20, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 28 + (checkbox == 2 ? 18 : 0) : (68 + padding), 11.5f, LocaleController.isRTL ? (68 + padding) : 28 + (checkbox == 2 ? 18 : 0), 0)); statusTextView = new SimpleTextView(context); statusTextView.setTextSize(14); @@ -95,6 +95,25 @@ public class UserCell extends FrameLayout { checkBox.setVisibility(INVISIBLE); addView(checkBox, LayoutHelper.createFrame(22, 22, (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.TOP, LocaleController.isRTL ? 0 : 37 + padding, 38, LocaleController.isRTL ? 37 + padding : 0, 0)); } + + if (admin) { + adminImage = new ImageView(context); + adminImage.setImageResource(R.drawable.admin_star); + addView(adminImage, LayoutHelper.createFrame(16, 16, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.TOP, LocaleController.isRTL ? 24 : 0, 13.5f, LocaleController.isRTL ? 0 : 24, 0)); + } + } + + public void setIsAdmin(int value) { + if (adminImage == null) { + return; + } + adminImage.setVisibility(value != 0 ? VISIBLE : GONE); + nameTextView.setPadding(LocaleController.isRTL && value != 0 ? AndroidUtilities.dp(16) : 0, 0, !LocaleController.isRTL && value != 0 ? AndroidUtilities.dp(16) : 0, 0); + if (value == 1) { + adminImage.setImageResource(R.drawable.admin_star); + } else if (value == 2) { + adminImage.setImageResource(R.drawable.admin_star2); + } } public void setData(TLObject user, CharSequence name, CharSequence status, int resId) { @@ -132,12 +151,13 @@ public class UserCell extends FrameLayout { setStatusSize(14); //setAvatarRadius(32); setAvatarRadius(themePrefs.getInt("profileRowAvatarRadius", 32)); + int dColor = themePrefs.getInt("profileIconsColor", 0xff737373); if(currentDrawable != 0) { - int dColor = themePrefs.getInt("profileIconsColor", 0xff737373); Drawable d = getResources().getDrawable(currentDrawable); d.setColorFilter(dColor, PorterDuff.Mode.SRC_IN); } - }else if(tag.contains("Pref")){ + if(adminImage != null)adminImage.setColorFilter(dColor, PorterDuff.Mode.SRC_IN); + } else if(tag.contains("Pref")){ setStatusColors(themePrefs.getInt("prefSummaryColor", 0xff8a8a8a), AndroidUtilities.getIntDarkerColor("themeColor", -0x40)); nameColor = themePrefs.getInt("prefTitleColor", 0xff212121); nameTextView.setTextColor(nameColor); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Cells/WallpaperCell.java b/TMessagesProj/src/main/java/org/telegram/ui/Cells/WallpaperCell.java new file mode 100644 index 00000000..a37de6fe --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Cells/WallpaperCell.java @@ -0,0 +1,85 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Cells; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.LayoutHelper; + +public class WallpaperCell extends FrameLayout { + + private BackupImageView imageView; + private View selectionView; + private ImageView imageView2; + + public WallpaperCell(Context context) { + super(context); + + imageView = new BackupImageView(context); + addView(imageView, LayoutHelper.createFrame(100, 100, Gravity.LEFT | Gravity.BOTTOM)); + + imageView2 = new ImageView(context); + imageView2.setImageResource(R.drawable.ic_gallery_background); + imageView2.setScaleType(ImageView.ScaleType.CENTER); + addView(imageView2, LayoutHelper.createFrame(100, 100, Gravity.LEFT | Gravity.BOTTOM)); + + selectionView = new View(context); + selectionView.setBackgroundResource(R.drawable.wall_selection); + addView(selectionView, LayoutHelper.createFrame(100, 102)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(100), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(102), MeasureSpec.EXACTLY)); + } + + public void setWallpaper(TLRPC.WallPaper wallpaper, int selectedBackground) { + if (wallpaper == null) { + imageView.setVisibility(INVISIBLE); + imageView2.setVisibility(VISIBLE); + selectionView.setVisibility(selectedBackground == -1 ? View.VISIBLE : INVISIBLE); + imageView2.setBackgroundColor(selectedBackground == -1 || selectedBackground == 1000001 ? 0x5a475866 : 0x5a000000); + } else { + imageView.setVisibility(VISIBLE); + imageView2.setVisibility(INVISIBLE); + selectionView.setVisibility(selectedBackground == wallpaper.id ? View.VISIBLE : INVISIBLE); + + if (wallpaper instanceof TLRPC.TL_wallPaperSolid) { + imageView.setImageBitmap(null); + imageView.setBackgroundColor(0xff000000 | wallpaper.bg_color); + } else { + int side = AndroidUtilities.dp(100); + TLRPC.PhotoSize size = null; + for (int a = 0; a < wallpaper.sizes.size(); a++) { + TLRPC.PhotoSize obj = wallpaper.sizes.get(a); + if (obj == null) { + continue; + } + int currentSide = obj.w >= obj.h ? obj.w : obj.h; + if (size == null || side > 100 && size.location != null && size.location.dc_id == Integer.MIN_VALUE || obj instanceof TLRPC.TL_photoCachedSize || currentSide <= side) { + size = obj; + } + } + if (size != null && size.location != null) { + imageView.setImage(size.location, "100_100", (Drawable) null); + } + imageView.setBackgroundColor(0x5a475866); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChangeAboutActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChangeAboutActivity.java new file mode 100644 index 00000000..043c297d --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChangeAboutActivity.java @@ -0,0 +1,206 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.text.InputFilter; +import android.text.InputType; +import android.util.Log; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Components.LayoutHelper; + +public class ChangeAboutActivity extends BaseFragment { + + private EditText aboutField; + private View doneButton; + + private final static int done_button = 1; + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(LocaleController.getString("EditBio", R.string.EditBio)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } else if (id == done_button) { + if (aboutField.getText().length() != 0) { + saveAbout(); + finishFragment(); + } + } + } + }); + + ActionBarMenu menu = actionBar.createMenu(); + //doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + Drawable done = getParentActivity().getResources().getDrawable(R.drawable.ic_done); + done.setColorFilter(themePrefs.getInt("prefHeaderIconsColor", 0xffffffff), PorterDuff.Mode.SRC_IN); + doneButton = menu.addItemWithWidth(done_button, done, AndroidUtilities.dp(56)); + + TLRPC.User user = MessagesController.getInstance().getUser(UserConfig.getClientUserId()); + if (user == null) { + user = UserConfig.getCurrentUser(); + } + + LinearLayout linearLayout = new LinearLayout(context); + fragmentView = linearLayout; + fragmentView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + ((LinearLayout) fragmentView).setOrientation(LinearLayout.VERTICAL); + fragmentView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + + aboutField = new EditText(context); + aboutField.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); + aboutField.setHintTextColor(0xff979797); + aboutField.setTextColor(0xff212121); + aboutField.setPadding(0, 0, 0, 10); + aboutField.getBackground().setColorFilter(AndroidUtilities.getIntColor("themeColor"), PorterDuff.Mode.SRC_IN); + aboutField.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean showEmojiBtn = preferences.getBoolean("showEmojiKbBtn", false); + aboutField.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + if(showEmojiBtn){ + aboutField.setInputType(aboutField.getInputType() | InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE); + } + //aboutField.setImeOptions(EditorInfo.TYPE_TEXT_FLAG_IME_MULTI_LINE); + InputFilter[] inputFilters = new InputFilter[1]; + inputFilters[0] = new InputFilter.LengthFilter(250); + aboutField.setFilters(inputFilters); + aboutField.setHint(LocaleController.getString("Info", R.string.Info)); + AndroidUtilities.clearCursorDrawable(aboutField); + linearLayout.addView(aboutField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 24, 24, 24, 0)); + aboutField.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { + if (i == EditorInfo.IME_ACTION_DONE) { + doneButton.performClick(); + return true; + } + return false; + } + }); + + if (user != null) { + aboutField.setText(MessagesController.getInstance().getUserAbout(user.id)); + } + + return fragmentView; + } + + @Override + public void onResume() { + super.onResume(); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + boolean animations = preferences.getBoolean("view_animations", true); + if (!animations) { + aboutField.requestFocus(); + AndroidUtilities.showKeyboard(aboutField); + } + updateTheme(); + } + + private void updateTheme(){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + actionBar.setBackgroundColor(themePrefs.getInt("prefHeaderColor", def)); + actionBar.setTitleColor(themePrefs.getInt("prefHeaderTitleColor", 0xffffffff)); + + Drawable back = getParentActivity().getResources().getDrawable(R.drawable.ic_ab_back); + back.setColorFilter(themePrefs.getInt("prefHeaderIconsColor", 0xffffffff), PorterDuff.Mode.MULTIPLY); + actionBar.setBackButtonDrawable(back); + } + + private void saveAbout() { + TLRPC.User currentUser = UserConfig.getCurrentUser(); + String about = MessagesController.getInstance().getUserAbout(currentUser.id); + if (aboutField.getText() == null) { + return; + } + String newAbout = aboutField.getText().toString(); + if (about != null && about.equals(newAbout)) { + return; + } + TLRPC.TL_account_updateProfile req = new TLRPC.TL_account_updateProfile(); + req.flags |= 4; + req.about = newAbout; + + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if(error != null){ + Log.e("ChangeNameAbout","error " + error.toString()); + } + if(response != null){ + Log.e("ChangeNameAbout","response " + response.toString()); + MessagesController.getInstance().loadFullUser(UserConfig.getCurrentUser(), classGuid, true); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.userInfoDidLoaded, UserConfig.getCurrentUser().id); + UserConfig.saveConfig(true); + } + }); + } + } + }); + } + + @Override + public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { + if (isOpen) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (aboutField != null) { + aboutField.requestFocus(); + AndroidUtilities.showKeyboard(aboutField); + } +} + }, 100); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChangeNameActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChangeNameActivity.java index 1c4575d4..256a26f6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChangeNameActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChangeNameActivity.java @@ -13,7 +13,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; -import android.text.InputFilter; import android.text.InputType; import android.util.Log; import android.util.TypedValue; @@ -28,26 +27,21 @@ import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.LocaleController; import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.UserObject; -import org.telegram.messenger.query.BotQuery; -import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.RequestDelegate; -import org.telegram.tgnet.TLObject; -import org.telegram.tgnet.TLRPC; +import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Components.LayoutHelper; -import java.util.ArrayList; - public class ChangeNameActivity extends BaseFragment { private EditText firstNameField; @@ -195,8 +189,11 @@ public class ChangeNameActivity extends BaseFragment { return; } TLRPC.TL_account_updateProfile req = new TLRPC.TL_account_updateProfile(); + req.flags = 7;//3; currentUser.first_name = req.first_name = newFirst; currentUser.last_name = req.last_name = newLast; + //req.about = "Esto es un test desde Plus Messenger"; + req.about = "This is a test from Plus Messenger"; TLRPC.User user = MessagesController.getInstance().getUser(UserConfig.getClientUserId()); if (user != null) { user.first_name = req.first_name; @@ -208,7 +205,8 @@ public class ChangeNameActivity extends BaseFragment { ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { @Override public void run(TLObject response, TLRPC.TL_error error) { - + if(response != null) Log.e("saveName","response " + response.toString()); + if(error != null)Log.e("saveName","error " + error.text); } }); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java index c687be34..f4e5d343 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChangePhoneActivity.java @@ -1,5 +1,5 @@ /* - * This is the source code of Telegram for Android v. 2.0.x. + * This is the source code of Telegram for Android v. 3.x.x. * It is licensed under GNU GPL v. 2 or later. * You should have received a copy of the license in this archive (see LICENSE). * @@ -8,13 +8,22 @@ package org.telegram.ui; +import android.Manifest; import android.annotation.SuppressLint; +import android.app.Activity; import android.app.AlertDialog; +import android.app.Dialog; import android.app.ProgressDialog; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Bundle; import android.telephony.TelephonyManager; import android.text.Editable; @@ -33,6 +42,7 @@ import android.view.inputmethod.EditorInfo; import android.widget.AdapterView; import android.widget.EditText; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; @@ -59,6 +69,10 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.messenger.AnimationCompat.AnimatorListenerAdapterProxy; +import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; +import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; +import org.telegram.messenger.AnimationCompat.ViewProxy; import org.telegram.ui.Components.HintEditText; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.SlideView; @@ -77,17 +91,21 @@ import java.util.TimerTask; public class ChangePhoneActivity extends BaseFragment { private int currentViewNum = 0; - private SlideView[] views = new SlideView[2]; + private SlideView[] views = new SlideView[5]; private ProgressDialog progressDialog; + private Dialog permissionsDialog; + private ArrayList permissionsItems = new ArrayList<>(); + private boolean checkPermissions = true; + private View doneButton; private final static int done_button = 1; @Override public void onFragmentDestroy() { super.onFragmentDestroy(); - for (SlideView v : views) { - if (v != null) { - v.onDestroyActivity(); + for (int a = 0; a < views.length; a++) { + if (views[a] != null) { + views[a].onDestroyActivity(); } } if (progressDialog != null) { @@ -117,44 +135,29 @@ public class ChangePhoneActivity extends BaseFragment { }); ActionBarMenu menu = actionBar.createMenu(); - //menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); - + //doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); Drawable done = getParentActivity().getResources().getDrawable(R.drawable.ic_done); done.setColorFilter(themePrefs.getInt("prefHeaderIconsColor", 0xffffffff), PorterDuff.Mode.SRC_IN); - menu.addItemWithWidth(done_button, done, AndroidUtilities.dp(56)); + doneButton = menu.addItemWithWidth(done_button, done, AndroidUtilities.dp(56)); fragmentView = new ScrollView(context); ScrollView scrollView = (ScrollView) fragmentView; scrollView.setFillViewport(true); FrameLayout frameLayout = new FrameLayout(context); - scrollView.addView(frameLayout); - ScrollView.LayoutParams layoutParams = (ScrollView.LayoutParams) frameLayout.getLayoutParams(); - layoutParams.width = ScrollView.LayoutParams.MATCH_PARENT; - layoutParams.height = ScrollView.LayoutParams.WRAP_CONTENT; - layoutParams.gravity = Gravity.TOP | Gravity.LEFT; - frameLayout.setLayoutParams(layoutParams); + scrollView.addView(frameLayout, LayoutHelper.createScroll(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT)); views[0] = new PhoneView(context); - views[0].setVisibility(View.VISIBLE); - frameLayout.addView(views[0], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 16, 30, 16, 0)); + views[1] = new LoginActivitySmsView(context, 1); + views[2] = new LoginActivitySmsView(context, 2); + views[3] = new LoginActivitySmsView(context, 3); + views[4] = new LoginActivitySmsView(context, 4); - views[1] = new LoginActivitySmsView(context); - views[1].setVisibility(View.GONE); - frameLayout.addView(views[1], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 16, 30, 16, 0)); - - try { - if (views[0] == null || views[1] == null) { - FrameLayout parent = (FrameLayout) ((ScrollView) fragmentView).getChildAt(0); for (int a = 0; a < views.length; a++) { - if (views[a] == null) { - views[a] = (SlideView) parent.getChildAt(a); - } - } - } - } catch (Exception e) { - FileLog.e("tmessages", e); + views[a].setVisibility(a == 0 ? View.VISIBLE : View.GONE); + frameLayout.addView(views[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, a == 0 ? LayoutHelper.WRAP_CONTENT : LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, AndroidUtilities.isTablet() ? 26 : 18, 30, AndroidUtilities.isTablet() ? 26 : 18, 0)); + //LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 16, 30, 16, 0) } actionBar.setTitle(views[0].getHeaderName()); @@ -180,16 +183,34 @@ public class ChangePhoneActivity extends BaseFragment { actionBar.setBackButtonDrawable(back); } + @Override + public void onRequestPermissionsResultFragment(int requestCode, String[] permissions, int[] grantResults) { + if (requestCode == 6) { + checkPermissions = false; + if (currentViewNum == 0) { + views[currentViewNum].onNextPressed(); + } + } + } + + @Override + protected void onDialogDismiss(Dialog dialog) { + if (Build.VERSION.SDK_INT >= 23 && dialog == permissionsDialog && !permissionsItems.isEmpty()) { + getParentActivity().requestPermissions(permissionsItems.toArray(new String[permissionsItems.size()]), 6); + } + } + @Override public boolean onBackPressed() { if (currentViewNum == 0) { - for (SlideView v : views) { - if (v != null) { - v.onDestroyActivity(); + for (int a = 0; a < views.length; a++) { + if (views[a] != null) { + views[a].onDestroyActivity(); } } return true; - } else if (currentViewNum == 1) { + } else { + views[currentViewNum].onBackPressed(); setPage(0, true, null, true); } return false; @@ -237,6 +258,14 @@ public class ChangePhoneActivity extends BaseFragment { } public void setPage(int page, boolean animated, Bundle params, boolean back) { + if (page == 3) { + doneButton.setVisibility(View.GONE); + } else { + if (page == 0) { + checkPermissions = true; + } + doneButton.setVisibility(View.VISIBLE); + } if(android.os.Build.VERSION.SDK_INT > 10) { final SlideView outView = views[currentViewNum]; final SlideView newView = views[page]; @@ -277,6 +306,40 @@ public class ChangePhoneActivity extends BaseFragment { } } + private void fillNextCodeParams(Bundle params, TLRPC.TL_auth_sentCode res) { + params.putString("phoneHash", res.phone_code_hash); + if (res.next_type instanceof TLRPC.TL_auth_codeTypeCall) { + params.putInt("nextType", 4); + } else if (res.next_type instanceof TLRPC.TL_auth_codeTypeFlashCall) { + params.putInt("nextType", 3); + } else if (res.next_type instanceof TLRPC.TL_auth_codeTypeSms) { + params.putInt("nextType", 2); + } + if (res.type instanceof TLRPC.TL_auth_sentCodeTypeApp) { + params.putInt("type", 1); + params.putInt("length", res.type.length); + setPage(1, true, params, false); + } else { + if (res.timeout == 0) { + res.timeout = 60; + } + params.putInt("timeout", res.timeout * 1000); + if (res.type instanceof TLRPC.TL_auth_sentCodeTypeCall) { + params.putInt("type", 4); + params.putInt("length", res.type.length); + setPage(4, true, params, false); + } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeFlashCall) { + params.putInt("type", 3); + params.putString("pattern", res.type.pattern); + setPage(3, true, params, false); + } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeSms) { + params.putInt("type", 2); + params.putInt("length", res.type.length); + setPage(2, true, params, false); + } + } + } + public class PhoneView extends SlideView implements AdapterView.OnItemSelectedListener { private EditText codeField; @@ -307,9 +370,9 @@ public class ChangePhoneActivity extends BaseFragment { countryButton.setMaxLines(1); countryButton.setSingleLine(true); countryButton.setEllipsize(TextUtils.TruncateAt.END); - countryButton.setGravity(Gravity.LEFT | Gravity.CENTER_HORIZONTAL); + countryButton.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_HORIZONTAL); countryButton.setBackgroundResource(R.drawable.spinner_states); - addView(countryButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 20, 0, 20, 14)); + addView(countryButton, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 0, 0, 0, 14)); countryButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { @@ -335,7 +398,7 @@ public class ChangePhoneActivity extends BaseFragment { View view = new View(context); view.setPadding(AndroidUtilities.dp(12), 0, AndroidUtilities.dp(12), 0); view.setBackgroundColor(0xffdbdbdb); - addView(view, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 1, 24, -17.5f, 24, 0)); + addView(view, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 1, 4, -17.5f, 4, 0)); LinearLayout linearLayout = new LinearLayout(context); linearLayout.setOrientation(HORIZONTAL); @@ -345,7 +408,7 @@ public class ChangePhoneActivity extends BaseFragment { textView.setText("+"); textView.setTextColor(0xff212121); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); - linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 24, 0, 0, 0)); + linearLayout.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); codeField = new EditText(context); codeField.setInputType(InputType.TYPE_CLASS_PHONE); @@ -374,7 +437,6 @@ public class ChangePhoneActivity extends BaseFragment { @Override public void afterTextChanged(Editable editable) { if (ignoreOnTextChange) { - ignoreOnTextChange = false; return; } ignoreOnTextChange = true; @@ -434,6 +496,7 @@ public class ChangePhoneActivity extends BaseFragment { phoneField.setSelection(phoneField.length()); } } + ignoreOnTextChange = false; } }); codeField.setOnEditorActionListener(new TextView.OnEditorActionListener() { @@ -459,7 +522,7 @@ public class ChangePhoneActivity extends BaseFragment { phoneField.setMaxLines(1); phoneField.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL); phoneField.setImeOptions(EditorInfo.IME_ACTION_NEXT | EditorInfo.IME_FLAG_NO_EXTRACT_UI); - linearLayout.addView(phoneField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 0, 0, 24, 0)); + linearLayout.addView(phoneField, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36)); phoneField.addTextChangedListener(new TextWatcher() { private int characterAction = -1; @@ -549,9 +612,9 @@ public class ChangePhoneActivity extends BaseFragment { textView.setText(LocaleController.getString("ChangePhoneHelp", R.string.ChangePhoneHelp)); textView.setTextColor(0xff757575); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - textView.setGravity(Gravity.LEFT); + textView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); textView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); - addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT, 24, 28, 24, 10)); + addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 28, 0, 10)); HashMap languageMap = new HashMap<>(); try { @@ -582,7 +645,7 @@ public class ChangePhoneActivity extends BaseFragment { String country = null; try { - TelephonyManager telephonyManager = (TelephonyManager)ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); + TelephonyManager telephonyManager = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); if (telephonyManager != null) { country = telephonyManager.getSimCountryIso().toUpperCase(); } @@ -626,6 +689,7 @@ public class ChangePhoneActivity extends BaseFragment { String hint = phoneFormatMap.get(code); phoneField.setHintText(hint != null ? hint.replace('X', '–') : null); countryState = 0; + ignoreOnTextChange = false; } } @@ -638,6 +702,7 @@ public class ChangePhoneActivity extends BaseFragment { ignoreOnTextChange = true; String str = countriesArray.get(i); codeField.setText(countriesMap.get(str)); + ignoreOnTextChange = false; } @Override @@ -647,9 +712,46 @@ public class ChangePhoneActivity extends BaseFragment { @Override public void onNextPressed() { - if (nextPressed) { + if (getParentActivity() == null || nextPressed) { return; } + TelephonyManager tm = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); + boolean simcardAvailable = tm.getSimState() != TelephonyManager.SIM_STATE_ABSENT && tm.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE; + boolean allowCall = true; + if (Build.VERSION.SDK_INT >= 23 && simcardAvailable) { + allowCall = getParentActivity().checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; + boolean allowSms = getParentActivity().checkSelfPermission(Manifest.permission.RECEIVE_SMS) == PackageManager.PERMISSION_GRANTED; + if (checkPermissions) { + permissionsItems.clear(); + if (!allowCall) { + permissionsItems.add(Manifest.permission.READ_PHONE_STATE); + } + if (!allowSms) { + permissionsItems.add(Manifest.permission.RECEIVE_SMS); + } + if (!permissionsItems.isEmpty()) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + if (preferences.getBoolean("firstlogin", true) || getParentActivity().shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE) || getParentActivity().shouldShowRequestPermissionRationale(Manifest.permission.RECEIVE_SMS)) { + preferences.edit().putBoolean("firstlogin", false).commit(); + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + if (permissionsItems.size() == 2) { + builder.setMessage(LocaleController.getString("AllowReadCallAndSms", R.string.AllowReadCallAndSms)); + } else if (!allowSms) { + builder.setMessage(LocaleController.getString("AllowReadSms", R.string.AllowReadSms)); + } else { + builder.setMessage(LocaleController.getString("AllowReadCall", R.string.AllowReadCall)); + } + permissionsDialog = showDialog(builder.create()); + } else { + getParentActivity().requestPermissions(permissionsItems.toArray(new String[permissionsItems.size()]), 6); + } + return; + } + } + } + if (countryState == 1) { needShowAlert(LocaleController.getString("ChooseCountry", R.string.ChooseCountry)); return; @@ -664,10 +766,20 @@ public class ChangePhoneActivity extends BaseFragment { TLRPC.TL_account_sendChangePhoneCode req = new TLRPC.TL_account_sendChangePhoneCode(); String phone = PhoneFormat.stripExceptNumbers("" + codeField.getText() + phoneField.getText()); req.phone_number = phone; - final String phone2 = "+" + codeField.getText() + " " + phoneField.getText(); + req.allow_flashcall = simcardAvailable && allowCall; + if (req.allow_flashcall) { + String number = tm.getLine1Number(); + req.current_number = number != null && number.length() != 0 && (phone.contains(number) || number.contains(phone)); + } final Bundle params = new Bundle(); - params.putString("phone", phone2); + params.putString("phone", "+" + codeField.getText() + phoneField.getText()); + try { + params.putString("ephone", "+" + PhoneFormat.stripExceptNumbers(codeField.getText().toString()) + " " + PhoneFormat.stripExceptNumbers(phoneField.getText().toString())); + } catch (Exception e) { + FileLog.e("tmessages", e); + params.putString("ephone", "+" + phone); + } params.putString("phoneFormated", phone); nextPressed = true; needShowProgress(); @@ -679,10 +791,7 @@ public class ChangePhoneActivity extends BaseFragment { public void run() { nextPressed = false; if (error == null) { - TLRPC.TL_account_sentChangePhoneCode res = (TLRPC.TL_account_sentChangePhoneCode)response; - params.putString("phoneHash", res.phone_code_hash); - params.putInt("calltime", res.send_call_timeout * 1000); - setPage(1, true, params, false); + fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response); } else { if (error.text != null) { if (error.text.contains("PHONE_NUMBER_INVALID")) { @@ -694,7 +803,7 @@ public class ChangePhoneActivity extends BaseFragment { } else if (error.text.startsWith("FLOOD_WAIT")) { needShowAlert(LocaleController.getString("FloodWait", R.string.FloodWait)); } else if (error.text.startsWith("PHONE_NUMBER_OCCUPIED")) { - needShowAlert(LocaleController.formatString("ChangePhoneNumberOccupied", R.string.ChangePhoneNumberOccupied, phone2)); + needShowAlert(LocaleController.formatString("ChangePhoneNumberOccupied", R.string.ChangePhoneNumberOccupied, params.getString("phone"))); } else { needShowAlert(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred)); } @@ -730,43 +839,88 @@ public class ChangePhoneActivity extends BaseFragment { public class LoginActivitySmsView extends SlideView implements NotificationCenter.NotificationCenterDelegate { + private class ProgressView extends View { + + private Paint paint = new Paint(); + private Paint paint2 = new Paint(); + private float progress; + + public ProgressView(Context context) { + super(context); + paint.setColor(0xffe1eaf2); + paint2.setColor(0xff62a0d0); + } + + public void setProgress(float value) { + progress = value; + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + int start = (int) (getMeasuredWidth() * progress); + canvas.drawRect(0, 0, start, getMeasuredHeight(), paint2); + canvas.drawRect(start, 0, getMeasuredWidth(), getMeasuredHeight(), paint); + } + } + + private String phone; private String phoneHash; private String requestPhone; + private String emailPhone; private EditText codeField; private TextView confirmTextView; private TextView timeText; + private TextView problemText; private Bundle currentParams; + private ProgressView progressView; private Timer timeTimer; private Timer codeTimer; + private int openTime; private final Object timerSync = new Object(); private volatile int time = 60000; private volatile int codeTime = 15000; private double lastCurrentTime; private double lastCodeTime; private boolean ignoreOnTextChange; - private boolean waitingForSms = false; - private boolean nextPressed = false; + private boolean waitingForEvent; + private boolean nextPressed; private String lastError = ""; + private int currentType; + private int nextType; + private String pattern = "*"; + private int length; + private int timeout; - public LoginActivitySmsView(Context context) { + public LoginActivitySmsView(Context context, final int type) { super(context); + currentType = type; setOrientation(VERTICAL); confirmTextView = new TextView(context); confirmTextView.setTextColor(0xff757575); confirmTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - confirmTextView.setGravity(Gravity.LEFT); + confirmTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); confirmTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); - addView(confirmTextView); - LayoutParams layoutParams = (LayoutParams) confirmTextView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.WRAP_CONTENT; - layoutParams.gravity = Gravity.LEFT; - layoutParams.leftMargin = AndroidUtilities.dp(24); - layoutParams.rightMargin = AndroidUtilities.dp(24); - confirmTextView.setLayoutParams(layoutParams); + + if (currentType == 3) { + FrameLayout frameLayout = new FrameLayout(context); + + ImageView imageView = new ImageView(context); + imageView.setImageResource(R.drawable.phone_activate); + if (LocaleController.isRTL) { + frameLayout.addView(imageView, LayoutHelper.createFrame(64, 76, Gravity.LEFT | Gravity.CENTER_VERTICAL, 2, 2, 0, 0)); + frameLayout.addView(confirmTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 64 + 18, 0, 0, 0)); + } else { + frameLayout.addView(confirmTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 0, 64 + 18, 0)); + frameLayout.addView(imageView, LayoutHelper.createFrame(64, 76, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 0, 2, 0, 2)); + } + addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)); + } else { + addView(confirmTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)); + } codeField = new EditText(context); codeField.setTextColor(0xff212121); @@ -778,15 +932,7 @@ public class ChangePhoneActivity extends BaseFragment { codeField.setInputType(InputType.TYPE_CLASS_PHONE); codeField.setMaxLines(1); codeField.setPadding(0, 0, 0, 0); - addView(codeField); - layoutParams = (LayoutParams) codeField.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = AndroidUtilities.dp(36); - layoutParams.gravity = Gravity.CENTER_HORIZONTAL; - layoutParams.topMargin = AndroidUtilities.dp(20); - layoutParams.leftMargin = AndroidUtilities.dp(24); - layoutParams.rightMargin = AndroidUtilities.dp(24); - codeField.setLayoutParams(layoutParams); + addView(codeField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.CENTER_HORIZONTAL, 0, 20, 0, 0)); codeField.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -803,7 +949,7 @@ public class ChangePhoneActivity extends BaseFragment { if (ignoreOnTextChange) { return; } - if (codeField.length() == 5) { + if (length != 0 && codeField.length() == length) { onNextPressed(); } } @@ -818,56 +964,134 @@ public class ChangePhoneActivity extends BaseFragment { return false; } }); + if (currentType == 3) { + codeField.setEnabled(false); + codeField.setInputType(InputType.TYPE_NULL); + codeField.setVisibility(GONE); + } timeText = new TextView(context); timeText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); timeText.setTextColor(0xff757575); timeText.setLineSpacing(AndroidUtilities.dp(2), 1.0f); - timeText.setGravity(Gravity.LEFT); - addView(timeText); - layoutParams = (LayoutParams) timeText.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.WRAP_CONTENT; - layoutParams.gravity = Gravity.LEFT; - layoutParams.topMargin = AndroidUtilities.dp(30); - layoutParams.leftMargin = AndroidUtilities.dp(24); - layoutParams.rightMargin = AndroidUtilities.dp(24); - timeText.setLayoutParams(layoutParams); + timeText.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + addView(timeText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 30, 0, 0)); + + if (currentType == 3) { + progressView = new ProgressView(context); + addView(progressView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 3, 0, 12, 0, 0)); + } + + problemText = new TextView(context); + problemText.setText(LocaleController.getString("DidNotGetTheCode", R.string.DidNotGetTheCode)); + problemText.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + problemText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + problemText.setTextColor(0xff4d83b3); + problemText.setLineSpacing(AndroidUtilities.dp(2), 1.0f); + problemText.setPadding(0, AndroidUtilities.dp(2), 0, AndroidUtilities.dp(12)); + addView(problemText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 20, 0, 0)); + problemText.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (nextPressed) { + return; + } + if (nextType != 0 && nextType != 4) { + resendCode(); + } else { + try { + PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); + String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); + + Intent mailer = new Intent(Intent.ACTION_SEND); + mailer.setType("message/rfc822"); + mailer.putExtra(Intent.EXTRA_EMAIL, new String[]{"sms@stel.com"}); + mailer.putExtra(Intent.EXTRA_SUBJECT, "Android registration/login issue " + version + " " + emailPhone); + mailer.putExtra(Intent.EXTRA_TEXT, "Phone: " + requestPhone + "\nApp version: " + version + "\nOS version: SDK " + Build.VERSION.SDK_INT + "\nDevice Name: " + Build.MANUFACTURER + Build.MODEL + "\nLocale: " + Locale.getDefault() + "\nError: " + lastError); + getContext().startActivity(Intent.createChooser(mailer, "Send email...")); + } catch (Exception e) { + needShowAlert(LocaleController.getString("NoMailInstalled", R.string.NoMailInstalled)); + } + } + } + }); LinearLayout linearLayout = new LinearLayout(context); - linearLayout.setGravity(Gravity.BOTTOM | Gravity.CENTER_VERTICAL); - addView(linearLayout); - layoutParams = (LayoutParams) linearLayout.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - linearLayout.setLayoutParams(layoutParams); + linearLayout.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); + addView(linearLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)); TextView wrongNumber = new TextView(context); - wrongNumber.setGravity(Gravity.LEFT | Gravity.CENTER_HORIZONTAL); + wrongNumber.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_HORIZONTAL); //wrongNumber.setTextColor(0xff4d83b3); wrongNumber.setTextColor(AndroidUtilities.getIntColor("themeColor")); wrongNumber.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); wrongNumber.setLineSpacing(AndroidUtilities.dp(2), 1.0f); wrongNumber.setPadding(0, AndroidUtilities.dp(24), 0, 0); - linearLayout.addView(wrongNumber); - layoutParams = (LayoutParams) wrongNumber.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.WRAP_CONTENT; - layoutParams.gravity = Gravity.BOTTOM | Gravity.LEFT; - layoutParams.bottomMargin = AndroidUtilities.dp(10); - layoutParams.leftMargin = AndroidUtilities.dp(24); - layoutParams.rightMargin = AndroidUtilities.dp(24); - wrongNumber.setLayoutParams(layoutParams); + linearLayout.addView(wrongNumber, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), 0, 0, 0, 10)); wrongNumber.setText(LocaleController.getString("WrongNumber", R.string.WrongNumber)); wrongNumber.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { + TLRPC.TL_auth_cancelCode req = new TLRPC.TL_auth_cancelCode(); + req.phone_number = requestPhone; + req.phone_code_hash = phoneHash; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); onBackPressed(); setPage(0, true, null, true); } }); } + private void resendCode() { + final Bundle params = new Bundle(); + params.putString("phone", phone); + params.putString("ephone", emailPhone); + params.putString("phoneFormated", requestPhone); + + nextPressed = true; + needShowProgress(); + + TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); + req.phone_number = requestPhone; + req.phone_code_hash = phoneHash; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + nextPressed = false; + if (error == null) { + fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response); + } else { + if (error.text != null) { + if (error.text.contains("PHONE_NUMBER_INVALID")) { + needShowAlert(LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); + } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { + needShowAlert(LocaleController.getString("InvalidCode", R.string.InvalidCode)); + } else if (error.text.contains("PHONE_CODE_EXPIRED")) { + onBackPressed(); + setPage(0, true, null, true); + needShowAlert(LocaleController.getString("CodeExpired", R.string.CodeExpired)); + } else if (error.text.startsWith("FLOOD_WAIT")) { + needShowAlert(LocaleController.getString("FloodWait", R.string.FloodWait)); + } else if (error.code != -1000) { + needShowAlert(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text); + } + } + } + needHideProgress(); + } + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + } + @Override public String getHeaderName() { return LocaleController.getString("YourCode", R.string.YourCode); @@ -879,41 +1103,87 @@ public class ChangePhoneActivity extends BaseFragment { return; } codeField.setText(""); + waitingForEvent = true; + if (currentType == 2) { AndroidUtilities.setWaitingForSms(true); NotificationCenter.getInstance().addObserver(this, NotificationCenter.didReceiveSmsCode); + } else if (currentType == 3) { + AndroidUtilities.setWaitingForCall(true); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.didReceiveCall); + } + currentParams = params; - waitingForSms = true; - String phone = params.getString("phone"); + phone = params.getString("phone"); + emailPhone = params.getString("ephone"); requestPhone = params.getString("phoneFormated"); phoneHash = params.getString("phoneHash"); - time = params.getInt("calltime"); + timeout = time = params.getInt("timeout"); + openTime = (int) (System.currentTimeMillis() / 1000); + nextType = params.getInt("nextType"); + pattern = params.getString("pattern"); + length = params.getInt("length"); + + if (length != 0) { + InputFilter[] inputFilters = new InputFilter[1]; + inputFilters[0] = new InputFilter.LengthFilter(length); + codeField.setFilters(inputFilters); + } else { + codeField.setFilters(new InputFilter[0]); + } + if (progressView != null) { + progressView.setVisibility(nextType != 0 ? VISIBLE : GONE); + } if (phone == null) { return; } String number = PhoneFormat.getInstance().format(phone); - String str = String.format(Locale.US, LocaleController.getString("SentSmsCode", R.string.SentSmsCode) + " %s", number); - try { - SpannableStringBuilder stringBuilder = new SpannableStringBuilder(str); - TypefaceSpan span = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - int idx = str.indexOf(number); - stringBuilder.setSpan(span, idx, idx + number.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); - confirmTextView.setText(stringBuilder); - } catch (Exception e) { - FileLog.e("tmessages", e); - confirmTextView.setText(str); + CharSequence str = ""; + if (currentType == 1) { + str = AndroidUtilities.replaceTags(LocaleController.getString("SentAppCode", R.string.SentAppCode)); + } else if (currentType == 2) { + str = AndroidUtilities.replaceTags(LocaleController.formatString("SentSmsCode", R.string.SentSmsCode, number)); + } else if (currentType == 3) { + str = AndroidUtilities.replaceTags(LocaleController.formatString("SentCallCode", R.string.SentCallCode, number)); + } else if (currentType == 4) { + str = AndroidUtilities.replaceTags(LocaleController.formatString("SentCallOnly", R.string.SentCallOnly, number)); } + confirmTextView.setText(str); + if (currentType != 3) { AndroidUtilities.showKeyboard(codeField); codeField.requestFocus(); + } else { + AndroidUtilities.hideKeyboard(codeField); + } destroyTimer(); destroyCodeTimer(); - timeText.setText(LocaleController.formatString("CallText", R.string.CallText, 1, 0)); - lastCurrentTime = System.currentTimeMillis(); - createTimer(); + lastCurrentTime = System.currentTimeMillis(); + if (currentType == 1) { + problemText.setVisibility(VISIBLE); + timeText.setVisibility(GONE); + } else if (currentType == 3 && (nextType == 4 || nextType == 2)) { + problemText.setVisibility(GONE); + timeText.setVisibility(VISIBLE); + if (nextType == 4) { + timeText.setText(LocaleController.formatString("CallText", R.string.CallText, 1, 0)); + } else if (nextType == 2) { + timeText.setText(LocaleController.formatString("SmsText", R.string.SmsText, 1, 0)); + } + createTimer(); + } else if (currentType == 2 && (nextType == 4 || nextType == 3)) { + timeText.setVisibility(VISIBLE); + timeText.setText(LocaleController.formatString("CallText", R.string.CallText, 2, 0)); + problemText.setVisibility(time < 1000 ? VISIBLE : GONE); + createTimer(); + } else { + timeText.setVisibility(GONE); + problemText.setVisibility(GONE); + createCodeTimer(); + } } private void createCodeTimer() { @@ -934,6 +1204,7 @@ public class ChangePhoneActivity extends BaseFragment { @Override public void run() { if (codeTime <= 1000) { + problemText.setVisibility(VISIBLE); destroyCodeTimer(); } } @@ -944,7 +1215,7 @@ public class ChangePhoneActivity extends BaseFragment { private void destroyCodeTimer() { try { - synchronized(timerSync) { + synchronized (timerSync) { if (codeTimer != null) { codeTimer.cancel(); codeTimer = null; @@ -963,7 +1234,10 @@ public class ChangePhoneActivity extends BaseFragment { timeTimer.schedule(new TimerTask() { @Override public void run() { - double currentTime = System.currentTimeMillis(); + if (timeTimer == null) { + return; + } + final double currentTime = System.currentTimeMillis(); double diff = currentTime - lastCurrentTime; time -= diff; lastCurrentTime = currentTime; @@ -973,12 +1247,30 @@ public class ChangePhoneActivity extends BaseFragment { if (time >= 1000) { int minutes = time / 1000 / 60; int seconds = time / 1000 - minutes * 60; + if (nextType == 4 || nextType == 3) { timeText.setText(LocaleController.formatString("CallText", R.string.CallText, minutes, seconds)); + } else if (nextType == 2) { + timeText.setText(LocaleController.formatString("SmsText", R.string.SmsText, minutes, seconds)); + } + if (progressView != null) { + progressView.setProgress(1.0f - (float) time / (float) timeout); + } } else { - timeText.setText(LocaleController.getString("Calling", R.string.Calling)); + if (progressView != null) { + progressView.setProgress(1.0f); + } destroyTimer(); + if (currentType == 3) { + AndroidUtilities.setWaitingForCall(false); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall); + waitingForEvent = false; + destroyCodeTimer(); + resendCode(); + } else if (currentType == 2) { + if (nextType == 4) { + timeText.setText(LocaleController.getString("Calling", R.string.Calling)); createCodeTimer(); - TLRPC.TL_auth_sendCall req = new TLRPC.TL_auth_sendCall(); + TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); req.phone_number = requestPhone; req.phone_code_hash = phoneHash; ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { @@ -994,8 +1286,16 @@ public class ChangePhoneActivity extends BaseFragment { } } }, ConnectionsManager.RequestFlagFailOnServerErrors); + } else if (nextType == 3) { + AndroidUtilities.setWaitingForSms(false); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); + waitingForEvent = false; + destroyCodeTimer(); + resendCode(); + } } } + } }); } }, 0, 1000); @@ -1003,7 +1303,7 @@ public class ChangePhoneActivity extends BaseFragment { private void destroyTimer() { try { - synchronized(timerSync) { + synchronized (timerSync) { if (timeTimer != null) { timeTimer.cancel(); timeTimer = null; @@ -1020,9 +1320,14 @@ public class ChangePhoneActivity extends BaseFragment { return; } nextPressed = true; - waitingForSms = false; + if (currentType == 2) { AndroidUtilities.setWaitingForSms(false); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); + } else if (currentType == 3) { + AndroidUtilities.setWaitingForCall(false); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall); + } + waitingForEvent = false; final TLRPC.TL_account_changePhone req = new TLRPC.TL_account_changePhone(); req.phone_number = requestPhone; req.phone_code = codeField.getText().toString(); @@ -1050,7 +1355,18 @@ public class ChangePhoneActivity extends BaseFragment { finishFragment(); } else { lastError = error.text; - createTimer(); + if (currentType == 3 && (nextType == 4 || nextType == 2) || currentType == 2 && (nextType == 4 || nextType == 3)) { + createTimer(); + } + if (currentType == 2) { + AndroidUtilities.setWaitingForSms(true); + NotificationCenter.getInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveSmsCode); + } else if (currentType == 3) { + AndroidUtilities.setWaitingForCall(true); + NotificationCenter.getInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveCall); + } + waitingForEvent = true; + if (currentType != 3) { if (error.text.contains("PHONE_NUMBER_INVALID")) { needShowAlert(LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { @@ -1064,6 +1380,7 @@ public class ChangePhoneActivity extends BaseFragment { } } } + } }); } }, ConnectionsManager.RequestFlagFailOnServerErrors); @@ -1074,19 +1391,29 @@ public class ChangePhoneActivity extends BaseFragment { destroyTimer(); destroyCodeTimer(); currentParams = null; - AndroidUtilities.setWaitingForSms(false); - NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); - waitingForSms = false; + if (currentType == 2) { + AndroidUtilities.setWaitingForSms(false); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); + } else if (currentType == 3) { + AndroidUtilities.setWaitingForCall(false); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall); + } + waitingForEvent = false; } @Override public void onDestroyActivity() { super.onDestroyActivity(); - AndroidUtilities.setWaitingForSms(false); - NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); + if (currentType == 2) { + AndroidUtilities.setWaitingForSms(false); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); + } else if (currentType == 3) { + AndroidUtilities.setWaitingForCall(false); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall); + } + waitingForEvent = false; destroyTimer(); destroyCodeTimer(); - waitingForSms = false; } @Override @@ -1100,16 +1427,27 @@ public class ChangePhoneActivity extends BaseFragment { @Override public void didReceivedNotification(int id, final Object... args) { + if (!waitingForEvent || codeField == null) { + return; + } if (id == NotificationCenter.didReceiveSmsCode) { - if (!waitingForSms) { - return; - } - if (codeField != null) { ignoreOnTextChange = true; codeField.setText("" + args[0]); - onNextPressed(); - } + ignoreOnTextChange = false; + onNextPressed(); + } else if (id == NotificationCenter.didReceiveCall) { + String num = "" + args[0]; + if (!pattern.equals("*")) { + String patternNumbers = pattern.replace("*", ""); + if (!num.contains(patternNumbers)) { + return; } - } + } + ignoreOnTextChange = true; + codeField.setText(num); + ignoreOnTextChange = false; + onNextPressed(); } } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java new file mode 100644 index 00000000..13b2b705 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelCreateActivity.java @@ -0,0 +1,1235 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.drawable.BitmapDrawable; +import android.os.Build; +import android.os.Bundle; +import android.os.Vibrator; +import android.text.Editable; +import android.text.InputFilter; +import android.text.InputType; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.SpannableStringBuilder; +import android.text.TextWatcher; +import android.text.style.ImageSpan; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import android.widget.AbsListView; +import android.widget.AdapterView; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.ScrollView; +import android.widget.TextView; +import android.widget.Toast; + +import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserObject; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Adapters.ContactsAdapter; +import org.telegram.ui.Adapters.SearchAdapter; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.RadioButtonCell; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextBlockCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Cells.UserCell; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.AvatarUpdater; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.ChipSpan; +import org.telegram.ui.Components.FrameLayoutFixed; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.LetterSectionsListView; + +import java.util.ArrayList; +import java.util.HashMap; + +public class ChannelCreateActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, AvatarUpdater.AvatarUpdaterDelegate { + + private View doneButton; + private EditText nameTextView; + private ProgressDialog progressDialog = null; + + private BackupImageView avatarImage; + private AvatarDrawable avatarDrawable; + private AvatarUpdater avatarUpdater; + private EditText descriptionTextView; + private TLRPC.FileLocation avatar; + private String nameToSet = null; + + private LinearLayout linkContainer; + private LinearLayout publicContainer; + private TextBlockCell privateContainer; + private RadioButtonCell radioButtonCell1; + private RadioButtonCell radioButtonCell2; + private TextInfoPrivacyCell typeInfoCell; + private TextView checkTextView; + private HeaderCell headerCell; + private int checkReqId = 0; + private String lastCheckName = null; + private Runnable checkRunnable = null; + private boolean lastNameAvailable = false; + private boolean isPrivate = false; + private boolean loadingInvite; + private TLRPC.ExportedChatInvite invite; + + private ContactsAdapter listViewAdapter; + private TextView emptyTextView; + private LetterSectionsListView listView; + private SearchAdapter searchListViewAdapter; + private boolean searchWas; + private boolean searching; + private HashMap selectedContacts = new HashMap<>(); + private ArrayList allSpans = new ArrayList<>(); + private int beforeChangeIndex; + private boolean ignoreChange; + private CharSequence changeString; + + private int currentStep; + private int chatId; + private boolean allowComments = false; + private boolean canCreatePublic = true; + private TLRPC.InputFile uploadedAvatar; + + private boolean createAfterUpload; + private boolean donePressed; + + private final static int done_button = 1; + + public ChannelCreateActivity(Bundle args) { + super(args); + currentStep = args.getInt("step", 0); + if (currentStep == 0) { + avatarDrawable = new AvatarDrawable(); + avatarUpdater = new AvatarUpdater(); + + TLRPC.TL_channels_checkUsername req = new TLRPC.TL_channels_checkUsername(); + req.username = "1"; + req.channel = new TLRPC.TL_inputChannelEmpty(); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + canCreatePublic = error == null || !error.text.equals("CHANNELS_ADMIN_PUBLIC_TOO_MUCH"); + } + }); + } + }); + } else { + if (currentStep == 1) { + canCreatePublic = args.getBoolean("canCreatePublic", true); + isPrivate = !canCreatePublic; + } + chatId = args.getInt("chat_id", 0); + } + } + + @SuppressWarnings("unchecked") + @Override + public boolean onFragmentCreate() { + NotificationCenter.getInstance().addObserver(this, NotificationCenter.updateInterfaces); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.chatDidCreated); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.chatDidFailCreate); + if (currentStep == 2) { + NotificationCenter.getInstance().addObserver(this, NotificationCenter.contactsDidLoaded); + } else if (currentStep == 1) { + generateLink(); + } + if (avatarUpdater != null) { + avatarUpdater.parentFragment = this; + avatarUpdater.delegate = this; + } + return super.onFragmentCreate(); + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.updateInterfaces); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.chatDidCreated); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.chatDidFailCreate); + if (currentStep == 2) { + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.contactsDidLoaded); + } + if (avatarUpdater != null) { + avatarUpdater.clear(); + } + AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid); + } + + @Override + public void onResume() { + super.onResume(); + AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); + } + + @Override + public View createView(Context context) { + searching = false; + searchWas = false; + + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } else if (id == done_button) { + if (currentStep == 0) { + if (donePressed) { + return; + } + if (nameTextView.length() == 0) { + Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE); + if (v != null) { + v.vibrate(200); + } + AndroidUtilities.shakeView(nameTextView, 2, 0); + return; + } + donePressed = true; + if (avatarUpdater.uploadingAvatar != null) { + createAfterUpload = true; + progressDialog = new ProgressDialog(getParentActivity()); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + createAfterUpload = false; + progressDialog = null; + donePressed = false; + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + progressDialog.show(); + return; + } + final int reqId = MessagesController.getInstance().createChat(nameTextView.getText().toString(), new ArrayList(), descriptionTextView.getText().toString(), ChatObject.CHAT_TYPE_CHANNEL, ChannelCreateActivity.this); + progressDialog = new ProgressDialog(getParentActivity()); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + ConnectionsManager.getInstance().cancelRequest(reqId, true); + donePressed = false; + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + progressDialog.show(); + } else if (currentStep == 1) { + if (!isPrivate) { + if (nameTextView.length() == 0) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("ChannelPublicEmptyUsername", R.string.ChannelPublicEmptyUsername)); + builder.setPositiveButton(LocaleController.getString("Close", R.string.Close), null); + showDialog(builder.create()); + return; + } else { + if (!lastNameAvailable) { + Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE); + if (v != null) { + v.vibrate(200); + } + AndroidUtilities.shakeView(checkTextView, 2, 0); + return; + } else { + MessagesController.getInstance().updateChannelUserName(chatId, lastCheckName); + } + } + } + if (allowComments) { + MessagesController.getInstance().toogleChannelComments(chatId, allowComments); + } + Bundle args = new Bundle(); + args.putInt("step", 2); + args.putInt("chat_id", chatId); + presentFragment(new ChannelCreateActivity(args), true); + } else { + ArrayList result = new ArrayList<>(); + for (Integer uid : selectedContacts.keySet()) { + TLRPC.InputUser user = MessagesController.getInputUser(MessagesController.getInstance().getUser(uid)); + if (user != null) { + result.add(user); + } + } + MessagesController.getInstance().addUsersToChannel(chatId, result, null); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); + Bundle args2 = new Bundle(); + args2.putInt("chat_id", chatId); + presentFragment(new ChatActivity(args2), true); + } + } + } + }); + + ActionBarMenu menu = actionBar.createMenu(); + doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + + LinearLayout linearLayout; + if (currentStep != 2) { + fragmentView = new ScrollView(context); + ScrollView scrollView = (ScrollView) fragmentView; + scrollView.setFillViewport(true); + linearLayout = new LinearLayout(context); + scrollView.addView(linearLayout, new ScrollView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + } else { + fragmentView = new LinearLayout(context); + fragmentView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + linearLayout = (LinearLayout) fragmentView; + } + linearLayout.setOrientation(LinearLayout.VERTICAL); + + if (currentStep == 0) { + actionBar.setTitle(LocaleController.getString("NewChannel", R.string.NewChannel)); + fragmentView.setBackgroundColor(0xffffffff); + FrameLayout frameLayout = new FrameLayoutFixed(context); + linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + avatarImage = new BackupImageView(context); + avatarImage.setRoundRadius(AndroidUtilities.dp(32)); + avatarDrawable.setInfo(5, null, null, false); + avatarDrawable.setDrawPhoto(true); + avatarImage.setImageDrawable(avatarDrawable); + frameLayout.addView(avatarImage, LayoutHelper.createFrame(64, 64, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 0 : 16, 12, LocaleController.isRTL ? 16 : 0, 12)); + avatarImage.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + + CharSequence[] items; + + if (avatar != null) { + items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley), LocaleController.getString("DeletePhoto", R.string.DeletePhoto)}; + } else { + items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley)}; + } + + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (i == 0) { + avatarUpdater.openCamera(); + } else if (i == 1) { + avatarUpdater.openGallery(); + } else if (i == 2) { + avatar = null; + uploadedAvatar = null; + avatarImage.setImage(avatar, "50_50", avatarDrawable); + } + } + }); + showDialog(builder.create()); + } + }); + + nameTextView = new EditText(context); + nameTextView.setHint(LocaleController.getString("EnterChannelName", R.string.EnterChannelName)); + if (nameToSet != null) { + nameTextView.setText(nameToSet); + nameToSet = null; + } + nameTextView.setMaxLines(4); + nameTextView.setGravity(Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)); + nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + nameTextView.setHintTextColor(0xff979797); + nameTextView.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); + nameTextView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES); + InputFilter[] inputFilters = new InputFilter[1]; + inputFilters[0] = new InputFilter.LengthFilter(100); + nameTextView.setFilters(inputFilters); + nameTextView.setPadding(0, 0, 0, AndroidUtilities.dp(8)); + AndroidUtilities.clearCursorDrawable(nameTextView); + nameTextView.setTextColor(0xff212121); + frameLayout.addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, LocaleController.isRTL ? 16 : 96, 0, LocaleController.isRTL ? 96 : 16, 0)); + nameTextView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + avatarDrawable.setInfo(5, nameTextView.length() > 0 ? nameTextView.getText().toString() : null, null, false); + avatarImage.invalidate(); + } + }); + + descriptionTextView = new EditText(context); + descriptionTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); + descriptionTextView.setHintTextColor(0xff979797); + descriptionTextView.setTextColor(0xff212121); + descriptionTextView.setPadding(0, 0, 0, AndroidUtilities.dp(6)); + descriptionTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + descriptionTextView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + descriptionTextView.setImeOptions(EditorInfo.IME_ACTION_DONE); + inputFilters = new InputFilter[1]; + inputFilters[0] = new InputFilter.LengthFilter(120); + descriptionTextView.setFilters(inputFilters); + descriptionTextView.setHint(LocaleController.getString("DescriptionPlaceholder", R.string.DescriptionPlaceholder)); + AndroidUtilities.clearCursorDrawable(descriptionTextView); + linearLayout.addView(descriptionTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 24, 18, 24, 0)); + descriptionTextView.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { + if (i == EditorInfo.IME_ACTION_DONE && doneButton != null) { + doneButton.performClick(); + return true; + } + return false; + } + }); + descriptionTextView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void afterTextChanged(Editable editable) { + + } + }); + + TextView helpTextView = new TextView(context); + helpTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + helpTextView.setTextColor(0xff6d6d72); + helpTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + helpTextView.setText(LocaleController.getString("DescriptionInfo", R.string.DescriptionInfo)); + linearLayout.addView(helpTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 24, 10, 24, 20)); + + /*helpTextView = new TextView(context); + helpTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + helpTextView.setTextColor(0xff3d93d5); + helpTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + helpTextView.setText(LocaleController.getString("ChannelAlertTitle", R.string.ChannelAlertTitle)); + linearLayout.addView(helpTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 24, 14, 24, 20)); + helpTextView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("ChannelAlertTitle", R.string.ChannelAlertTitle)); + builder.setMessage(LocaleController.getString("ChannelAlertText", R.string.ChannelAlertText)); + builder.setPositiveButton(LocaleController.getString("Close", R.string.Close), null); + showDialog(builder.create()); + } + });*/ + } else if (currentStep == 1) { + actionBar.setTitle(LocaleController.getString("ChannelSettings", R.string.ChannelSettings)); + fragmentView.setBackgroundColor(0xfff0f0f0); + + LinearLayout linearLayout2 = new LinearLayout(context); + linearLayout2.setOrientation(LinearLayout.VERTICAL); + linearLayout2.setBackgroundColor(0xffffffff); + linearLayout.addView(linearLayout2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + radioButtonCell1 = new RadioButtonCell(context); + radioButtonCell1.setBackgroundResource(R.drawable.list_selector); + radioButtonCell1.setTextAndValue(LocaleController.getString("ChannelPublic", R.string.ChannelPublic), LocaleController.getString("ChannelPublicInfo", R.string.ChannelPublicInfo), !isPrivate, false); + linearLayout2.addView(radioButtonCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + radioButtonCell1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!canCreatePublic) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("ChannelPublicLimitReached", R.string.ChannelPublicLimitReached)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); + return; + } + if (!isPrivate) { + return; + } + isPrivate = false; + updatePrivatePublic(); + } + }); + + radioButtonCell2 = new RadioButtonCell(context); + radioButtonCell2.setBackgroundResource(R.drawable.list_selector); + radioButtonCell2.setTextAndValue(LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate), LocaleController.getString("ChannelPrivateInfo", R.string.ChannelPrivateInfo), isPrivate, false); + linearLayout2.addView(radioButtonCell2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + radioButtonCell2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isPrivate) { + return; + } + isPrivate = true; + updatePrivatePublic(); + } + }); + + ShadowSectionCell sectionCell = new ShadowSectionCell(context); + linearLayout.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + linkContainer = new LinearLayout(context); + linkContainer.setOrientation(LinearLayout.VERTICAL); + linkContainer.setBackgroundColor(0xffffffff); + linearLayout.addView(linkContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + headerCell = new HeaderCell(context); + linkContainer.addView(headerCell); + + publicContainer = new LinearLayout(context); + publicContainer.setOrientation(LinearLayout.HORIZONTAL); + linkContainer.addView(publicContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 17, 7, 17, 0)); + + EditText editText = new EditText(context); + editText.setText("telegram.me/"); + editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); + editText.setHintTextColor(0xff979797); + editText.setTextColor(0xff212121); + editText.setMaxLines(1); + editText.setLines(1); + editText.setEnabled(false); + editText.setBackgroundDrawable(null); + editText.setPadding(0, 0, 0, 0); + editText.setSingleLine(true); + editText.setInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + editText.setImeOptions(EditorInfo.IME_ACTION_DONE); + publicContainer.addView(editText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 36)); + + nameTextView = new EditText(context); + nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); + nameTextView.setHintTextColor(0xff979797); + nameTextView.setTextColor(0xff212121); + nameTextView.setMaxLines(1); + nameTextView.setLines(1); + nameTextView.setBackgroundDrawable(null); + nameTextView.setPadding(0, 0, 0, 0); + nameTextView.setSingleLine(true); + nameTextView.setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + nameTextView.setImeOptions(EditorInfo.IME_ACTION_DONE); + nameTextView.setHint(LocaleController.getString("ChannelUsernamePlaceholder", R.string.ChannelUsernamePlaceholder)); + AndroidUtilities.clearCursorDrawable(nameTextView); + publicContainer.addView(nameTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36)); + nameTextView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { + checkUserName(nameTextView.getText().toString(), false); + } + + @Override + public void afterTextChanged(Editable editable) { + + } + }); + + privateContainer = new TextBlockCell(context); + privateContainer.setBackgroundResource(R.drawable.list_selector); + linkContainer.addView(privateContainer); + privateContainer.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (invite == null) { + return; + } + try { + if (Build.VERSION.SDK_INT < 11) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(invite.link); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", invite.link); + clipboard.setPrimaryClip(clip); + } + Toast.makeText(getParentActivity(), LocaleController.getString("LinkCopied", R.string.LinkCopied), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + + checkTextView = new TextView(context); + checkTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + checkTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + checkTextView.setVisibility(View.GONE); + linkContainer.addView(checkTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 17, 3, 17, 7)); + + typeInfoCell = new TextInfoPrivacyCell(context); + //typeInfoCell.setBackgroundResource(R.drawable.greydivider); + typeInfoCell.setBackgroundResource(R.drawable.greydivider_bottom); + linearLayout.addView(typeInfoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + /*FrameLayout frameLayout = new FrameLayoutFixed(context); + frameLayout.setBackgroundColor(0xffffffff); + linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + TextCheckCell commentsCell = new TextCheckCell(context); + commentsCell.setTextAndCheck(LocaleController.getString("Comments", R.string.Comments), allowComments, false); + commentsCell.setBackgroundResource(R.drawable.list_selector); + frameLayout.addView(commentsCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + commentsCell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + allowComments = !allowComments; + ((TextCheckCell) v).setChecked(allowComments); + } + }); + + TextInfoPrivacyCell infoCell = new TextInfoPrivacyCell(context); + infoCell.setText(LocaleController.getString("CommentsInfo", R.string.CommentsInfo)); + infoCell.setBackgroundResource(R.drawable.greydivider_bottom); + linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));*/ + updatePrivatePublic(); + } else if (currentStep == 2) { + actionBar.setTitle(LocaleController.getString("ChannelAddMembers", R.string.ChannelAddMembers)); + actionBar.setSubtitle(LocaleController.formatPluralString("Members", selectedContacts.size())); + + searchListViewAdapter = new SearchAdapter(context, null, false, false, false, false); + searchListViewAdapter.setCheckedMap(selectedContacts); + searchListViewAdapter.setUseUserCell(true); + listViewAdapter = new ContactsAdapter(context, 1, false, null, false); + listViewAdapter.setCheckedMap(selectedContacts); + + FrameLayout frameLayout = new FrameLayout(context); + linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + nameTextView = new EditText(context); + nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + nameTextView.setHintTextColor(0xff979797); + nameTextView.setTextColor(0xff212121); + nameTextView.setInputType(InputType.TYPE_TEXT_VARIATION_FILTER | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_MULTI_LINE); + nameTextView.setMinimumHeight(AndroidUtilities.dp(54)); + nameTextView.setSingleLine(false); + nameTextView.setLines(2); + nameTextView.setMaxLines(2); + nameTextView.setVerticalScrollBarEnabled(true); + nameTextView.setHorizontalScrollBarEnabled(false); + nameTextView.setPadding(0, 0, 0, 0); + nameTextView.setHint(LocaleController.getString("AddMutual", R.string.AddMutual)); + if (Build.VERSION.SDK_INT >= 11) { + nameTextView.setTextIsSelectable(false); + } + nameTextView.setImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfo.IME_FLAG_NO_EXTRACT_UI); + nameTextView.setGravity((LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT) | Gravity.CENTER_VERTICAL); + AndroidUtilities.clearCursorDrawable(nameTextView); + frameLayout.addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 10, 0, 10, 0)); + + nameTextView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int start, int count, int after) { + if (!ignoreChange) { + beforeChangeIndex = nameTextView.getSelectionStart(); + changeString = new SpannableString(charSequence); + } + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void afterTextChanged(Editable editable) { + if (!ignoreChange) { + boolean search = false; + int afterChangeIndex = nameTextView.getSelectionEnd(); + if (editable.toString().length() < changeString.toString().length()) { + String deletedString = ""; + try { + deletedString = changeString.toString().substring(afterChangeIndex, beforeChangeIndex); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (deletedString.length() > 0) { + if (searching && searchWas) { + search = true; + } + Spannable span = nameTextView.getText(); + for (int a = 0; a < allSpans.size(); a++) { + ChipSpan sp = allSpans.get(a); + if (span.getSpanStart(sp) == -1) { + allSpans.remove(sp); + selectedContacts.remove(sp.uid); + } + } + actionBar.setSubtitle(LocaleController.formatPluralString("Members", selectedContacts.size())); + listView.invalidateViews(); + } else { + search = true; + } + } else { + search = true; + } + if (search) { + String text = nameTextView.getText().toString().replace("<", ""); + if (text.length() != 0) { + searching = true; + searchWas = true; + if (listView != null) { + listView.setAdapter(searchListViewAdapter); + searchListViewAdapter.notifyDataSetChanged(); + if (android.os.Build.VERSION.SDK_INT >= 11) { + listView.setFastScrollAlwaysVisible(false); + } + listView.setFastScrollEnabled(false); + listView.setVerticalScrollBarEnabled(true); + } + if (emptyTextView != null) { + emptyTextView.setText(LocaleController.getString("NoResult", R.string.NoResult)); + } + searchListViewAdapter.searchDialogs(text); + } else { + searchListViewAdapter.searchDialogs(null); + searching = false; + searchWas = false; + listView.setAdapter(listViewAdapter); + listViewAdapter.notifyDataSetChanged(); + if (android.os.Build.VERSION.SDK_INT >= 11) { + listView.setFastScrollAlwaysVisible(true); + } + listView.setFastScrollEnabled(true); + listView.setVerticalScrollBarEnabled(false); + emptyTextView.setText(LocaleController.getString("NoContacts", R.string.NoContacts)); + } + } + } + } + }); + + LinearLayout emptyTextLayout = new LinearLayout(context); + emptyTextLayout.setVisibility(View.INVISIBLE); + emptyTextLayout.setOrientation(LinearLayout.VERTICAL); + linearLayout.addView(emptyTextLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + emptyTextLayout.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + + emptyTextView = new TextView(context); + emptyTextView.setTextColor(0xff808080); + emptyTextView.setTextSize(20); + emptyTextView.setGravity(Gravity.CENTER); + emptyTextView.setText(LocaleController.getString("NoContacts", R.string.NoContacts)); + emptyTextLayout.addView(emptyTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0.5f)); + + FrameLayout frameLayout2 = new FrameLayout(context); + emptyTextLayout.addView(frameLayout2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0.5f)); + + listView = new LetterSectionsListView(context); + listView.setEmptyView(emptyTextLayout); + listView.setVerticalScrollBarEnabled(false); + listView.setDivider(null); + listView.setDividerHeight(0); + listView.setFastScrollEnabled(true); + listView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY); + listView.setAdapter(listViewAdapter); + if (Build.VERSION.SDK_INT >= 11) { + listView.setFastScrollAlwaysVisible(true); + listView.setVerticalScrollbarPosition(LocaleController.isRTL ? ListView.SCROLLBAR_POSITION_LEFT : ListView.SCROLLBAR_POSITION_RIGHT); + } + linearLayout.addView(listView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + TLRPC.User user; + if (searching && searchWas) { + user = (TLRPC.User) searchListViewAdapter.getItem(i); + } else { + int section = listViewAdapter.getSectionForPosition(i); + int row = listViewAdapter.getPositionInSectionForPosition(i); + if (row < 0 || section < 0) { + return; + } + user = (TLRPC.User) listViewAdapter.getItem(section, row); + } + if (user == null) { + return; + } + + boolean check = true; + if (selectedContacts.containsKey(user.id)) { + check = false; + try { + ChipSpan span = selectedContacts.get(user.id); + selectedContacts.remove(user.id); + SpannableStringBuilder text = new SpannableStringBuilder(nameTextView.getText()); + text.delete(text.getSpanStart(span), text.getSpanEnd(span)); + allSpans.remove(span); + ignoreChange = true; + nameTextView.setText(text); + nameTextView.setSelection(text.length()); + ignoreChange = false; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else { + ignoreChange = true; + ChipSpan span = createAndPutChipForUser(user); + if (span != null) { + span.uid = user.id; + } + ignoreChange = false; + if (span == null) { + return; + } + } + actionBar.setSubtitle(LocaleController.formatPluralString("Members", selectedContacts.size())); + if (searching || searchWas) { + ignoreChange = true; + SpannableStringBuilder ssb = new SpannableStringBuilder(""); + for (ImageSpan sp : allSpans) { + ssb.append("<<"); + ssb.setSpan(sp, ssb.length() - 2, ssb.length(), SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE); + } + nameTextView.setText(ssb); + nameTextView.setSelection(ssb.length()); + ignoreChange = false; + + searchListViewAdapter.searchDialogs(null); + searching = false; + searchWas = false; + listView.setAdapter(listViewAdapter); + listViewAdapter.notifyDataSetChanged(); + if (android.os.Build.VERSION.SDK_INT >= 11) { + listView.setFastScrollAlwaysVisible(true); + } + listView.setFastScrollEnabled(true); + listView.setVerticalScrollBarEnabled(false); + emptyTextView.setText(LocaleController.getString("NoContacts", R.string.NoContacts)); + } else { + if (view instanceof UserCell) { + ((UserCell) view).setChecked(check, true); + } + } + } + }); + listView.setOnScrollListener(new AbsListView.OnScrollListener() { + @Override + public void onScrollStateChanged(AbsListView absListView, int i) { + if (i == SCROLL_STATE_TOUCH_SCROLL) { + AndroidUtilities.hideKeyboard(nameTextView); + } + if (listViewAdapter != null) { + listViewAdapter.setIsScrolling(i != SCROLL_STATE_IDLE); + } + } + + @Override + public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + if (absListView.isFastScrollEnabled()) { + AndroidUtilities.clearDrawableAnimation(absListView); + } + } + }); + } + + return fragmentView; + } + + private void generateLink() { + if (loadingInvite || invite != null) { + return; + } + loadingInvite = true; + TLRPC.TL_channels_exportInvite req = new TLRPC.TL_channels_exportInvite(); + req.channel = MessagesController.getInputChannel(chatId); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (error == null) { + invite = (TLRPC.ExportedChatInvite) response; + } + loadingInvite = false; + privateContainer.setText(invite != null ? invite.link : LocaleController.getString("Loading", R.string.Loading), false); + } + }); + } + }); + } + + private void updatePrivatePublic() { + radioButtonCell1.setChecked(!isPrivate, true); + radioButtonCell2.setChecked(isPrivate, true); + typeInfoCell.setText(isPrivate ? LocaleController.getString("ChannelPrivateLinkHelp", R.string.ChannelPrivateLinkHelp) : LocaleController.getString("ChannelUsernameHelp", R.string.ChannelUsernameHelp)); + headerCell.setText(isPrivate ? LocaleController.getString("ChannelInviteLinkTitle", R.string.ChannelInviteLinkTitle) : LocaleController.getString("ChannelLinkTitle", R.string.ChannelLinkTitle)); + publicContainer.setVisibility(isPrivate ? View.GONE : View.VISIBLE); + privateContainer.setVisibility(isPrivate ? View.VISIBLE : View.GONE); + linkContainer.setPadding(0, 0, 0, isPrivate ? 0 : AndroidUtilities.dp(7)); + privateContainer.setText(invite != null ? invite.link : LocaleController.getString("Loading", R.string.Loading), false); + nameTextView.clearFocus(); + checkTextView.setVisibility(!isPrivate && checkTextView.length() != 0 ? View.VISIBLE : View.GONE); + AndroidUtilities.hideKeyboard(nameTextView); + } + + @Override + public void didUploadedPhoto(final TLRPC.InputFile file, final TLRPC.PhotoSize small, final TLRPC.PhotoSize big) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + uploadedAvatar = file; + avatar = small.location; + avatarImage.setImage(avatar, "50_50", avatarDrawable); + if (createAfterUpload) { + try { + if (progressDialog != null && progressDialog.isShowing()) { + progressDialog.dismiss(); + progressDialog = null; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + doneButton.performClick(); + } + } + }); + } + + @Override + public void onActivityResultFragment(int requestCode, int resultCode, Intent data) { + avatarUpdater.onActivityResult(requestCode, resultCode, data); + } + + @Override + public void saveSelfArgs(Bundle args) { + if (currentStep == 0) { + if (avatarUpdater != null && avatarUpdater.currentPicturePath != null) { + args.putString("path", avatarUpdater.currentPicturePath); + } + if (nameTextView != null) { + String text = nameTextView.getText().toString(); + if (text != null && text.length() != 0) { + args.putString("nameTextView", text); + } + } + } + } + + @Override + public void restoreSelfArgs(Bundle args) { + if (currentStep == 0) { + if (avatarUpdater != null) { + avatarUpdater.currentPicturePath = args.getString("path"); + } + String text = args.getString("nameTextView"); + if (text != null) { + if (nameTextView != null) { + nameTextView.setText(text); + } else { + nameToSet = text; + } + } + } + } + + @Override + public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { + if (isOpen && currentStep != 1) { + nameTextView.requestFocus(); + AndroidUtilities.showKeyboard(nameTextView); + } + } + + @Override + public void didReceivedNotification(int id, final Object... args) { + if (id == NotificationCenter.updateInterfaces) { + int mask = (Integer)args[0]; + if ((mask & MessagesController.UPDATE_MASK_AVATAR) != 0 || (mask & MessagesController.UPDATE_MASK_NAME) != 0 || (mask & MessagesController.UPDATE_MASK_STATUS) != 0) { + updateVisibleRows(mask); + } + } else if (id == NotificationCenter.chatDidFailCreate) { + if (progressDialog != null) { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + donePressed = false; + } else if (id == NotificationCenter.chatDidCreated) { + if (progressDialog != null) { + try { + progressDialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + int chat_id = (Integer) args[0]; + Bundle bundle = new Bundle(); + bundle.putInt("step", 1); + bundle.putInt("chat_id", chat_id); + bundle.putBoolean("canCreatePublic", canCreatePublic); + if (uploadedAvatar != null) { + MessagesController.getInstance().changeChatAvatar(chat_id, uploadedAvatar); + } + presentFragment(new ChannelCreateActivity(bundle), true); + } else if (id == NotificationCenter.contactsDidLoaded) { + if (listViewAdapter != null) { + listViewAdapter.notifyDataSetChanged(); + } + } + } + + private boolean checkUserName(final String name, boolean alert) { + if (name != null && name.length() > 0) { + checkTextView.setVisibility(View.VISIBLE); + } else { + checkTextView.setVisibility(View.GONE); + } + if (alert && name.length() == 0) { + return true; + } + if (checkRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(checkRunnable); + checkRunnable = null; + lastCheckName = null; + if (checkReqId != 0) { + ConnectionsManager.getInstance().cancelRequest(checkReqId, true); + } + } + lastNameAvailable = false; + if (name != null) { + if (name.startsWith("_") || name.endsWith("_")) { + checkTextView.setText(LocaleController.getString("LinkInvalid", R.string.LinkInvalid)); + checkTextView.setTextColor(0xffcf3030); + return false; + } + for (int a = 0; a < name.length(); a++) { + char ch = name.charAt(a); + if (a == 0 && ch >= '0' && ch <= '9') { + if (alert) { + showErrorAlert(LocaleController.getString("LinkInvalidStartNumber", R.string.LinkInvalidStartNumber)); + } else { + checkTextView.setText(LocaleController.getString("LinkInvalidStartNumber", R.string.LinkInvalidStartNumber)); + checkTextView.setTextColor(0xffcf3030); + } + return false; + } + if (!(ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch == '_')) { + if (alert) { + showErrorAlert(LocaleController.getString("LinkInvalid", R.string.LinkInvalid)); + } else { + checkTextView.setText(LocaleController.getString("LinkInvalid", R.string.LinkInvalid)); + checkTextView.setTextColor(0xffcf3030); + } + return false; + } + } + } + if (name == null || name.length() < 5) { + if (alert) { + showErrorAlert(LocaleController.getString("LinkInvalidShort", R.string.LinkInvalidShort)); + } else { + checkTextView.setText(LocaleController.getString("LinkInvalidShort", R.string.LinkInvalidShort)); + checkTextView.setTextColor(0xffcf3030); + } + return false; + } + if (name.length() > 32) { + if (alert) { + showErrorAlert(LocaleController.getString("LinkInvalidLong", R.string.LinkInvalidLong)); + } else { + checkTextView.setText(LocaleController.getString("LinkInvalidLong", R.string.LinkInvalidLong)); + checkTextView.setTextColor(0xffcf3030); + } + return false; + } + + if (!alert) { + checkTextView.setText(LocaleController.getString("LinkChecking", R.string.LinkChecking)); + checkTextView.setTextColor(0xff6d6d72); + lastCheckName = name; + checkRunnable = new Runnable() { + @Override + public void run() { + TLRPC.TL_channels_checkUsername req = new TLRPC.TL_channels_checkUsername(); + req.username = name; + req.channel = MessagesController.getInputChannel(chatId); + checkReqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + checkReqId = 0; + if (lastCheckName != null && lastCheckName.equals(name)) { + if (error == null && response instanceof TLRPC.TL_boolTrue) { + checkTextView.setText(LocaleController.formatString("LinkAvailable", R.string.LinkAvailable, name)); + checkTextView.setTextColor(0xff26972c); + lastNameAvailable = true; + } else { + if (error != null && error.text.equals("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) { + checkTextView.setText(LocaleController.getString("ChannelPublicLimitReached", R.string.ChannelPublicLimitReached)); + } else { + checkTextView.setText(LocaleController.getString("LinkInUse", R.string.LinkInUse)); + } + checkTextView.setTextColor(0xffcf3030); + lastNameAvailable = false; + } + } + } + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + } + }; + AndroidUtilities.runOnUIThread(checkRunnable, 300); + } + return true; + } + + private void showErrorAlert(String error) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + switch (error) { + case "USERNAME_INVALID": + builder.setMessage(LocaleController.getString("LinkInvalid", R.string.LinkInvalid)); + break; + case "USERNAME_OCCUPIED": + builder.setMessage(LocaleController.getString("LinkInUse", R.string.LinkInUse)); + break; + case "USERNAMES_UNAVAILABLE": + builder.setMessage(LocaleController.getString("FeatureUnavailable", R.string.FeatureUnavailable)); + break; + default: + builder.setMessage(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred)); + break; + } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); + } + + private void updateVisibleRows(int mask) { + if (listView == null) { + return; + } + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + if (child instanceof UserCell) { + ((UserCell) child).update(mask); + } + } + } + + private ChipSpan createAndPutChipForUser(TLRPC.User user) { + try { + LayoutInflater lf = (LayoutInflater) ApplicationLoader.applicationContext.getSystemService(Activity.LAYOUT_INFLATER_SERVICE); + View textView = lf.inflate(R.layout.group_create_bubble, null); + TextView text = (TextView)textView.findViewById(R.id.bubble_text_view); + String name = UserObject.getUserName(user); + if (name.length() == 0 && user.phone != null && user.phone.length() != 0) { + name = PhoneFormat.getInstance().format("+" + user.phone); + } + text.setText(name + ", "); + + int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + textView.measure(spec, spec); + textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight()); + Bitmap b = Bitmap.createBitmap(textView.getWidth(), textView.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(b); + canvas.translate(-textView.getScrollX(), -textView.getScrollY()); + textView.draw(canvas); + textView.setDrawingCacheEnabled(true); + Bitmap cacheBmp = textView.getDrawingCache(); + Bitmap viewBmp = cacheBmp.copy(Bitmap.Config.ARGB_8888, true); + textView.destroyDrawingCache(); + + final BitmapDrawable bmpDrawable = new BitmapDrawable(b); + bmpDrawable.setBounds(0, 0, b.getWidth(), b.getHeight()); + + SpannableStringBuilder ssb = new SpannableStringBuilder(""); + ChipSpan span = new ChipSpan(bmpDrawable, ImageSpan.ALIGN_BASELINE); + allSpans.add(span); + selectedContacts.put(user.id, span); + for (ImageSpan sp : allSpans) { + ssb.append("<<"); + ssb.setSpan(sp, ssb.length() - 2, ssb.length(), SpannableStringBuilder.SPAN_EXCLUSIVE_EXCLUSIVE); + } + nameTextView.setText(ssb); + nameTextView.setSelection(ssb.length()); + return span; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return null; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditActivity.java new file mode 100644 index 00000000..38a4caa6 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditActivity.java @@ -0,0 +1,656 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Vibrator; +import android.text.Editable; +import android.text.InputFilter; +import android.text.InputType; +import android.text.TextWatcher; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextCheckCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Cells.TextSettingsCell; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.AvatarUpdater; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.FrameLayoutFixed; +import org.telegram.ui.Components.LayoutHelper; + +import java.util.concurrent.Semaphore; + +public class ChannelEditActivity extends BaseFragment implements AvatarUpdater.AvatarUpdaterDelegate, NotificationCenter.NotificationCenterDelegate { + + private View doneButton; + private EditText nameTextView; + private EditText descriptionTextView; + private EditText userNameTextView; + private BackupImageView avatarImage; + private AvatarDrawable avatarDrawable; + private AvatarUpdater avatarUpdater; + private ProgressDialog progressDialog; + private TextSettingsCell typeCell; + private TextSettingsCell adminCell; + + private TextView checkTextView; + + private TLRPC.FileLocation avatar; + private int checkReqId = 0; + private String lastCheckName = null; + private Runnable checkRunnable = null; + private boolean lastNameAvailable = false; + private TLRPC.Chat currentChat; + private TLRPC.ChatFull info; + private int chatId; + private boolean allowComments = true; + private TLRPC.InputFile uploadedAvatar; + private boolean wasPrivate; + private boolean privateAlertShown; + private boolean signMessages; + + private boolean createAfterUpload; + private boolean donePressed; + + private final static int done_button = 1; + + public ChannelEditActivity(Bundle args) { + super(args); + avatarDrawable = new AvatarDrawable(); + avatarUpdater = new AvatarUpdater(); + chatId = args.getInt("chat_id", 0); + } + + @SuppressWarnings("unchecked") + @Override + public boolean onFragmentCreate() { + currentChat = MessagesController.getInstance().getChat(chatId); + if (currentChat == null) { + final Semaphore semaphore = new Semaphore(0); + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + currentChat = MessagesStorage.getInstance().getChat(chatId); + semaphore.release(); + } + }); + try { + semaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (currentChat != null) { + MessagesController.getInstance().putChat(currentChat, true); + } else { + return false; + } + if (info == null) { + MessagesStorage.getInstance().loadChatInfo(chatId, semaphore, false, false); + try { + semaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (info == null) { + return false; + } + } + } + avatarUpdater.parentFragment = this; + avatarUpdater.delegate = this; + allowComments = !currentChat.broadcast; + signMessages = currentChat.signatures; + NotificationCenter.getInstance().addObserver(this, NotificationCenter.chatInfoDidLoaded); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.updateInterfaces); + return super.onFragmentCreate(); + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + if (avatarUpdater != null) { + avatarUpdater.clear(); + } + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.chatInfoDidLoaded); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.updateInterfaces); + AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid); + } + + @Override + public void onResume() { + super.onResume(); + AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); + } + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } else if (id == done_button) { + if (donePressed) { + return; + } + if (nameTextView.length() == 0) { + Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE); + if (v != null) { + v.vibrate(200); + } + AndroidUtilities.shakeView(nameTextView, 2, 0); + return; + } + donePressed = true; + + if (avatarUpdater.uploadingAvatar != null) { + createAfterUpload = true; + progressDialog = new ProgressDialog(getParentActivity()); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + createAfterUpload = false; + progressDialog = null; + donePressed = false; + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + progressDialog.show(); + return; + } + boolean currentAllowComments = !currentChat.broadcast; + if (allowComments != currentAllowComments) { + MessagesController.getInstance().toogleChannelComments(chatId, allowComments); + } + if (!currentChat.title.equals(nameTextView.getText().toString())) { + MessagesController.getInstance().changeChatTitle(chatId, nameTextView.getText().toString()); + } + if (info != null && !info.about.equals(descriptionTextView.getText().toString())) { + MessagesController.getInstance().updateChannelAbout(chatId, descriptionTextView.getText().toString(), info); + } + if (signMessages != currentChat.signatures) { + currentChat.signatures = true; + MessagesController.getInstance().toogleChannelSignatures(chatId, signMessages); + } + if (uploadedAvatar != null) { + MessagesController.getInstance().changeChatAvatar(chatId, uploadedAvatar); + } else if (avatar == null && currentChat.photo instanceof TLRPC.TL_chatPhoto) { + MessagesController.getInstance().changeChatAvatar(chatId, null); + } + finishFragment(); + } + } + }); + + ActionBarMenu menu = actionBar.createMenu(); + doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + + LinearLayout linearLayout; + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int rowColor = themePrefs.getInt("profileRowColor", 0xffffffff); + int tColor = themePrefs.getInt("profileTitleColor", 0xff212121); + int sColor = themePrefs.getInt("profileSummaryColor", 0xff8a8a8a); + fragmentView = new ScrollView(context); + //fragmentView.setBackgroundColor(0xfff0f0f0); + fragmentView.setBackgroundColor(rowColor != 0xffffffff ? rowColor : 0xfff0f0f0); + ScrollView scrollView = (ScrollView) fragmentView; + scrollView.setFillViewport(true); + linearLayout = new LinearLayout(context); + scrollView.addView(linearLayout, new ScrollView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + + linearLayout.setOrientation(LinearLayout.VERTICAL); + + actionBar.setTitle(LocaleController.getString("ChannelEdit", R.string.ChannelEdit)); + + LinearLayout linearLayout2 = new LinearLayout(context); + linearLayout2.setOrientation(LinearLayout.VERTICAL); + //linearLayout2.setBackgroundColor(0xffffffff); + linearLayout2.setBackgroundColor(rowColor); + linearLayout.addView(linearLayout2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + FrameLayout frameLayout = new FrameLayoutFixed(context); + linearLayout2.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + avatarImage = new BackupImageView(context); + avatarImage.setRoundRadius(AndroidUtilities.dp(32)); + avatarDrawable.setInfo(5, null, null, false); + avatarDrawable.setDrawPhoto(true); + frameLayout.addView(avatarImage, LayoutHelper.createFrame(64, 64, Gravity.TOP | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT), LocaleController.isRTL ? 0 : 16, 12, LocaleController.isRTL ? 16 : 0, 12)); + avatarImage.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + + CharSequence[] items; + + if (avatar != null) { + items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley), LocaleController.getString("DeletePhoto", R.string.DeletePhoto)}; + } else { + items = new CharSequence[]{LocaleController.getString("FromCamera", R.string.FromCamera), LocaleController.getString("FromGalley", R.string.FromGalley)}; + } + + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (i == 0) { + avatarUpdater.openCamera(); + } else if (i == 1) { + avatarUpdater.openGallery(); + } else if (i == 2) { + avatar = null; + uploadedAvatar = null; + avatarImage.setImage(avatar, "50_50", avatarDrawable); + } + } + }); + showDialog(builder.create()); + } + }); + + nameTextView = new EditText(context); + if (currentChat.megagroup) { + nameTextView.setHint(LocaleController.getString("GroupName", R.string.GroupName)); + } else { + nameTextView.setHint(LocaleController.getString("EnterChannelName", R.string.EnterChannelName)); + } + nameTextView.setMaxLines(4); + nameTextView.setGravity(Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)); + nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + nameTextView.setHintTextColor(0xff979797); + nameTextView.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); + nameTextView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES); + nameTextView.setPadding(0, 0, 0, AndroidUtilities.dp(8)); + InputFilter[] inputFilters = new InputFilter[1]; + inputFilters[0] = new InputFilter.LengthFilter(100); + nameTextView.setFilters(inputFilters); + AndroidUtilities.clearCursorDrawable(nameTextView); + //nameTextView.setTextColor(0xff212121); + nameTextView.setTextColor(tColor); + frameLayout.addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, LocaleController.isRTL ? 16 : 96, 0, LocaleController.isRTL ? 96 : 16, 0)); + nameTextView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + avatarDrawable.setInfo(5, nameTextView.length() > 0 ? nameTextView.getText().toString() : null, null, false); + avatarImage.invalidate(); + } + }); + + View lineView = new View(context); + lineView.setBackgroundColor(0xffcfcfcf); + linearLayout.addView(lineView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1)); + + linearLayout2 = new LinearLayout(context); + linearLayout2.setOrientation(LinearLayout.VERTICAL); + //linearLayout2.setBackgroundColor(0xffffffff); + linearLayout2.setBackgroundColor(rowColor); + linearLayout.addView(linearLayout2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + descriptionTextView = new EditText(context); + descriptionTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + descriptionTextView.setHintTextColor(0xff979797); + //descriptionTextView.setTextColor(0xff212121); + descriptionTextView.setTextColor(rowColor != 0xffffffff ? tColor : 0xff212121); + descriptionTextView.setPadding(0, 0, 0, AndroidUtilities.dp(6)); + descriptionTextView.setBackgroundDrawable(null); + descriptionTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + descriptionTextView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + descriptionTextView.setImeOptions(EditorInfo.IME_ACTION_DONE); + inputFilters = new InputFilter[1]; + inputFilters[0] = new InputFilter.LengthFilter(255); + descriptionTextView.setFilters(inputFilters); + descriptionTextView.setHint(LocaleController.getString("DescriptionOptionalPlaceholder", R.string.DescriptionOptionalPlaceholder)); + AndroidUtilities.clearCursorDrawable(descriptionTextView); + linearLayout2.addView(descriptionTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, 17, 12, 17, 6)); + descriptionTextView.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { + if (i == EditorInfo.IME_ACTION_DONE && doneButton != null) { + doneButton.performClick(); + return true; + } + return false; + } + }); + descriptionTextView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void afterTextChanged(Editable editable) { + + } + }); + + ShadowSectionCell sectionCell = new ShadowSectionCell(context); + sectionCell.setSize(20); + linearLayout.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + if (currentChat.megagroup || !currentChat.megagroup) { + frameLayout = new FrameLayoutFixed(context); + frameLayout.setBackgroundColor(0xffffffff); + linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + typeCell = new TextSettingsCell(context); + updateTypeCell(); + typeCell.setBackgroundResource(R.drawable.list_selector); + frameLayout.addView(typeCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + //TODO + + lineView = new View(context); + lineView.setBackgroundColor(0xffcfcfcf); + linearLayout.addView(lineView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1)); + + frameLayout = new FrameLayoutFixed(context); + frameLayout.setBackgroundColor(0xffffffff); + linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + if (!currentChat.megagroup) { + TextCheckCell textCheckCell = new TextCheckCell(context); + textCheckCell.setBackgroundResource(R.drawable.list_selector); + textCheckCell.setTextAndCheck(LocaleController.getString("ChannelSignMessages", R.string.ChannelSignMessages), signMessages, false); + frameLayout.addView(textCheckCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + textCheckCell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + signMessages = !signMessages; + ((TextCheckCell) v).setChecked(signMessages); + } + }); + + TextInfoPrivacyCell infoCell = new TextInfoPrivacyCell(context); + infoCell.setBackgroundResource(R.drawable.greydivider); + infoCell.setText(LocaleController.getString("ChannelSignMessagesInfo", R.string.ChannelSignMessagesInfo)); + linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } else { + adminCell = new TextSettingsCell(context); + updateAdminCell(); + adminCell.setBackgroundResource(R.drawable.list_selector); + frameLayout.addView(adminCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + adminCell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Bundle args = new Bundle(); + args.putInt("chat_id", chatId); + args.putInt("type", 1); + presentFragment(new ChannelUsersActivity(args)); + } + }); + + sectionCell = new ShadowSectionCell(context); + sectionCell.setSize(20); + linearLayout.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + if (!currentChat.creator) { + sectionCell.setBackgroundResource(R.drawable.greydivider_bottom); + } + } + } + + if (currentChat.creator) { + frameLayout = new FrameLayoutFixed(context); + frameLayout.setBackgroundColor(0xffffffff); + linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + TextSettingsCell textCell = new TextSettingsCell(context); + textCell.setTextColor(0xffed3d39); + textCell.setBackgroundResource(R.drawable.list_selector); + if (currentChat.megagroup) { + textCell.setText(LocaleController.getString("DeleteMega", R.string.DeleteMega), false); + } else { + textCell.setText(LocaleController.getString("ChannelDelete", R.string.ChannelDelete), false); + } + frameLayout.addView(textCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + textCell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + if (currentChat.megagroup) { + builder.setMessage(LocaleController.getString("MegaDeleteAlert", R.string.MegaDeleteAlert)); + } else { + builder.setMessage(LocaleController.getString("ChannelDeleteAlert", R.string.ChannelDeleteAlert)); + } + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.closeChats); + if (AndroidUtilities.isTablet()) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats, -(long) chatId); + } else { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); + } + MessagesController.getInstance().deleteUserFromChat(chatId, MessagesController.getInstance().getUser(UserConfig.getClientUserId()), info); + finishFragment(); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } + }); + + TextInfoPrivacyCell infoCell = new TextInfoPrivacyCell(context); + infoCell.setBackgroundResource(R.drawable.greydivider_bottom); + if (currentChat.megagroup) { + infoCell.setText(LocaleController.getString("MegaDeleteInfo", R.string.MegaDeleteInfo)); + } else { + infoCell.setText(LocaleController.getString("ChannelDeleteInfo", R.string.ChannelDeleteInfo)); + } + linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + } + + /*frameLayout = new FrameLayoutFixed(context); + frameLayout.setBackgroundColor(0xffffffff); + linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + TextCheckCell commentsCell = new TextCheckCell(context); + commentsCell.setTextAndCheck(LocaleController.getString("Comments", R.string.Comments), allowComments, false); + commentsCell.setBackgroundResource(R.drawable.list_selector); + frameLayout.addView(commentsCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + commentsCell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + allowComments = !allowComments; + ((TextCheckCell) v).setChecked(allowComments); + } + }); + + infoCell = new TextInfoPrivacyCell(context); + infoCell.setText(LocaleController.getString("CommentsInfo", R.string.CommentsInfo)); + infoCell.setBackgroundResource(R.drawable.greydivider); + linearLayout.addView(infoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT));*/ + + nameTextView.setText(currentChat.title); + nameTextView.setSelection(nameTextView.length()); + if (info != null) { + descriptionTextView.setText(info.about); + } + if (currentChat.photo != null) { + avatar = currentChat.photo.photo_small; + avatarImage.setImage(avatar, "50_50", avatarDrawable); + } else { + avatarImage.setImageDrawable(avatarDrawable); + } + + return fragmentView; + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.chatInfoDidLoaded) { + TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; + if (chatFull.id == chatId) { + if (info == null) { + descriptionTextView.setText(chatFull.about); + } + info = chatFull; + updateAdminCell(); + updateTypeCell(); + } + } else if (id == NotificationCenter.updateInterfaces) { + int updateMask = (Integer) args[0]; + if ((updateMask & MessagesController.UPDATE_MASK_CHANNEL) != 0) { + updateTypeCell(); + } + } + } + + @Override + public void didUploadedPhoto(final TLRPC.InputFile file, final TLRPC.PhotoSize small, final TLRPC.PhotoSize big) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + uploadedAvatar = file; + avatar = small.location; + avatarImage.setImage(avatar, "50_50", avatarDrawable); + if (createAfterUpload) { + try { + if (progressDialog != null && progressDialog.isShowing()) { + progressDialog.dismiss(); + progressDialog = null; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + doneButton.performClick(); + } + } + }); + } + + @Override + public void onActivityResultFragment(int requestCode, int resultCode, Intent data) { + avatarUpdater.onActivityResult(requestCode, resultCode, data); + } + + @Override + public void saveSelfArgs(Bundle args) { + if (avatarUpdater != null && avatarUpdater.currentPicturePath != null) { + args.putString("path", avatarUpdater.currentPicturePath); + } + if (nameTextView != null) { + String text = nameTextView.getText().toString(); + if (text != null && text.length() != 0) { + args.putString("nameTextView", text); + } + } + } + + @Override + public void restoreSelfArgs(Bundle args) { + if (avatarUpdater != null) { + avatarUpdater.currentPicturePath = args.getString("path"); + } + } + + public void setInfo(TLRPC.ChatFull chatFull) { + info = chatFull; + } + + private void updateTypeCell() { + String type = currentChat.username == null || currentChat.username.length() == 0 ? LocaleController.getString("ChannelTypePrivate", R.string.ChannelTypePrivate) : LocaleController.getString("ChannelTypePublic", R.string.ChannelTypePublic); + if (currentChat.megagroup) { + typeCell.setTextAndValue(LocaleController.getString("GroupType", R.string.GroupType), type, false); + } else { + typeCell.setTextAndValue(LocaleController.getString("ChannelType", R.string.ChannelType), type, false); + } + + if (currentChat.creator && (info == null || info.can_set_username)) { + typeCell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Bundle args = new Bundle(); + args.putInt("chat_id", chatId); + ChannelEditTypeActivity fragment = new ChannelEditTypeActivity(args); + fragment.setInfo(info); + presentFragment(fragment); + } + }); + typeCell.setTextColor(0xff212121); + typeCell.setTextValueColor(0xff2f8cc9); + } else { + typeCell.setOnClickListener(null); + typeCell.setTextColor(0xffa8a8a8); + typeCell.setTextValueColor(0xffa8a8a8); + } + } + + private void updateAdminCell() { + if (adminCell == null) { + return; + } + if (info != null) { + adminCell.setTextAndValue(LocaleController.getString("ChannelAdministrators", R.string.ChannelAdministrators), String.format("%d", info.admins_count), false); + } else { + adminCell.setText(LocaleController.getString("ChannelAdministrators", R.string.ChannelAdministrators), false); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditTypeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditTypeActivity.java new file mode 100644 index 00000000..a389ec5c --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelEditTypeActivity.java @@ -0,0 +1,544 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.app.AlertDialog; +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.os.Vibrator; +import android.text.Editable; +import android.text.InputType; +import android.text.TextWatcher; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; +import android.widget.Toast; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.RadioButtonCell; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextBlockCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Components.LayoutHelper; + +import java.util.concurrent.Semaphore; + +public class ChannelEditTypeActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + private LinearLayout linkContainer; + private LinearLayout publicContainer; + private TextBlockCell privateContainer; + private RadioButtonCell radioButtonCell1; + private RadioButtonCell radioButtonCell2; + private TextInfoPrivacyCell typeInfoCell; + private TextView checkTextView; + private HeaderCell headerCell; + private EditText nameTextView; + private boolean isPrivate = false; + private boolean loadingInvite; + private TLRPC.ExportedChatInvite invite; + + private int checkReqId = 0; + private String lastCheckName = null; + private Runnable checkRunnable = null; + private boolean lastNameAvailable = false; + private TLRPC.Chat currentChat; + private int chatId; + + private boolean donePressed; + + private final static int done_button = 1; + + public ChannelEditTypeActivity(Bundle args) { + super(args); + chatId = args.getInt("chat_id", 0); + } + + @SuppressWarnings("unchecked") + @Override + public boolean onFragmentCreate() { + currentChat = MessagesController.getInstance().getChat(chatId); + if (currentChat == null) { + final Semaphore semaphore = new Semaphore(0); + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + currentChat = MessagesStorage.getInstance().getChat(chatId); + semaphore.release(); + } + }); + try { + semaphore.acquire(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (currentChat != null) { + MessagesController.getInstance().putChat(currentChat, true); + } else { + return false; + } + } + isPrivate = currentChat.username == null || currentChat.username.length() == 0; + NotificationCenter.getInstance().addObserver(this, NotificationCenter.chatInfoDidLoaded); + return super.onFragmentCreate(); + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.chatInfoDidLoaded); + AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid); + } + + @Override + public void onResume() { + super.onResume(); + AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); + } + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } else if (id == done_button) { + if (donePressed) { + return; + } + + if (!isPrivate && ((currentChat.username == null && nameTextView.length() != 0) || (currentChat.username != null && !currentChat.username.equalsIgnoreCase(nameTextView.getText().toString())))) { + if (nameTextView.length() != 0 && !lastNameAvailable) { + Vibrator v = (Vibrator) getParentActivity().getSystemService(Context.VIBRATOR_SERVICE); + if (v != null) { + v.vibrate(200); + } + AndroidUtilities.shakeView(checkTextView, 2, 0); + return; + } + } + donePressed = true; + + String oldUserName = currentChat.username != null ? currentChat.username : ""; + String newUserName = isPrivate ? "" : nameTextView.getText().toString(); + if (!oldUserName.equals(newUserName)) { + MessagesController.getInstance().updateChannelUserName(chatId, newUserName); + } + finishFragment(); + } + } + }); + + ActionBarMenu menu = actionBar.createMenu(); + menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + + LinearLayout linearLayout; + + fragmentView = new ScrollView(context); + fragmentView.setBackgroundColor(0xfff0f0f0); + ScrollView scrollView = (ScrollView) fragmentView; + scrollView.setFillViewport(true); + linearLayout = new LinearLayout(context); + scrollView.addView(linearLayout, new ScrollView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); + + linearLayout.setOrientation(LinearLayout.VERTICAL); + + if (currentChat.megagroup) { + actionBar.setTitle(LocaleController.getString("GroupType", R.string.GroupType)); + } else { + actionBar.setTitle(LocaleController.getString("ChannelType", R.string.ChannelType)); + } + + LinearLayout linearLayout2 = new LinearLayout(context); + linearLayout2.setOrientation(LinearLayout.VERTICAL); + linearLayout2.setBackgroundColor(0xffffffff); + linearLayout.addView(linearLayout2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + radioButtonCell1 = new RadioButtonCell(context); + radioButtonCell1.setBackgroundResource(R.drawable.list_selector); + if (currentChat.megagroup) { + radioButtonCell1.setTextAndValue(LocaleController.getString("MegaPublic", R.string.MegaPublic), LocaleController.getString("MegaPublicInfo", R.string.MegaPublicInfo), !isPrivate, false); + } else { + radioButtonCell1.setTextAndValue(LocaleController.getString("ChannelPublic", R.string.ChannelPublic), LocaleController.getString("ChannelPublicInfo", R.string.ChannelPublicInfo), !isPrivate, false); + } + linearLayout2.addView(radioButtonCell1, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + radioButtonCell1.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!isPrivate) { + return; + } + isPrivate = false; + updatePrivatePublic(); + } + }); + + radioButtonCell2 = new RadioButtonCell(context); + radioButtonCell2.setBackgroundResource(R.drawable.list_selector); + if (currentChat.megagroup) { + radioButtonCell2.setTextAndValue(LocaleController.getString("MegaPrivate", R.string.MegaPrivate), LocaleController.getString("MegaPrivateInfo", R.string.MegaPrivateInfo), isPrivate, false); + } else { + radioButtonCell2.setTextAndValue(LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate), LocaleController.getString("ChannelPrivateInfo", R.string.ChannelPrivateInfo), isPrivate, false); + } + linearLayout2.addView(radioButtonCell2, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + radioButtonCell2.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isPrivate) { + return; + } + isPrivate = true; + updatePrivatePublic(); + } + }); + + ShadowSectionCell sectionCell = new ShadowSectionCell(context); + linearLayout.addView(sectionCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + linkContainer = new LinearLayout(context); + linkContainer.setOrientation(LinearLayout.VERTICAL); + linkContainer.setBackgroundColor(0xffffffff); + linearLayout.addView(linkContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + headerCell = new HeaderCell(context); + linkContainer.addView(headerCell); + + publicContainer = new LinearLayout(context); + publicContainer.setOrientation(LinearLayout.HORIZONTAL); + linkContainer.addView(publicContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 17, 7, 17, 0)); + + EditText editText = new EditText(context); + editText.setText("telegram.me/"); + editText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); + editText.setHintTextColor(0xff979797); + editText.setTextColor(0xff212121); + editText.setMaxLines(1); + editText.setLines(1); + editText.setEnabled(false); + editText.setBackgroundDrawable(null); + editText.setPadding(0, 0, 0, 0); + editText.setSingleLine(true); + editText.setInputType(InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + editText.setImeOptions(EditorInfo.IME_ACTION_DONE); + publicContainer.addView(editText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 36)); + + nameTextView = new EditText(context); + nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); + if (!isPrivate) { + nameTextView.setText(currentChat.username); + } + nameTextView.setHintTextColor(0xff979797); + nameTextView.setTextColor(0xff212121); + nameTextView.setMaxLines(1); + nameTextView.setLines(1); + nameTextView.setBackgroundDrawable(null); + nameTextView.setPadding(0, 0, 0, 0); + nameTextView.setSingleLine(true); + nameTextView.setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + nameTextView.setImeOptions(EditorInfo.IME_ACTION_DONE); + nameTextView.setHint(LocaleController.getString("ChannelUsernamePlaceholder", R.string.ChannelUsernamePlaceholder)); + AndroidUtilities.clearCursorDrawable(nameTextView); + publicContainer.addView(nameTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36)); + nameTextView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { + checkUserName(nameTextView.getText().toString(), false); + } + + @Override + public void afterTextChanged(Editable editable) { + + } + }); + + privateContainer = new TextBlockCell(context); + privateContainer.setBackgroundResource(R.drawable.list_selector); + linkContainer.addView(privateContainer); + privateContainer.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (invite == null) { + return; + } + try { + if (Build.VERSION.SDK_INT < 11) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(invite.link); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", invite.link); + clipboard.setPrimaryClip(clip); + } + Toast.makeText(getParentActivity(), LocaleController.getString("LinkCopied", R.string.LinkCopied), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + + checkTextView = new TextView(context); + checkTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + checkTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + checkTextView.setVisibility(View.GONE); + linkContainer.addView(checkTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 17, 3, 17, 7)); + + typeInfoCell = new TextInfoPrivacyCell(context); + typeInfoCell.setBackgroundResource(R.drawable.greydivider_bottom); + linearLayout.addView(typeInfoCell, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT)); + + updatePrivatePublic(); + + return fragmentView; + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.chatInfoDidLoaded) { + TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; + if (chatFull.id == chatId) { + invite = chatFull.exported_invite; + updatePrivatePublic(); + } + } + } + + public void setInfo(TLRPC.ChatFull chatFull) { + if (chatFull != null) { + if (chatFull.exported_invite instanceof TLRPC.TL_chatInviteExported) { + invite = chatFull.exported_invite; + } else { + generateLink(); + } + } + } + + private void updatePrivatePublic() { + radioButtonCell1.setChecked(!isPrivate, true); + radioButtonCell2.setChecked(isPrivate, true); + if (currentChat.megagroup) { + typeInfoCell.setText(isPrivate ? LocaleController.getString("MegaPrivateLinkHelp", R.string.MegaPrivateLinkHelp) : LocaleController.getString("MegaUsernameHelp", R.string.MegaUsernameHelp)); + headerCell.setText(isPrivate ? LocaleController.getString("ChannelInviteLinkTitle", R.string.ChannelInviteLinkTitle) : LocaleController.getString("ChannelLinkTitle", R.string.ChannelLinkTitle)); + } else { + typeInfoCell.setText(isPrivate ? LocaleController.getString("ChannelPrivateLinkHelp", R.string.ChannelPrivateLinkHelp) : LocaleController.getString("ChannelUsernameHelp", R.string.ChannelUsernameHelp)); + headerCell.setText(isPrivate ? LocaleController.getString("ChannelInviteLinkTitle", R.string.ChannelInviteLinkTitle) : LocaleController.getString("ChannelLinkTitle", R.string.ChannelLinkTitle)); + } + publicContainer.setVisibility(isPrivate ? View.GONE : View.VISIBLE); + privateContainer.setVisibility(isPrivate ? View.VISIBLE : View.GONE); + linkContainer.setPadding(0, 0, 0, isPrivate ? 0 : AndroidUtilities.dp(7)); + privateContainer.setText(invite != null ? invite.link : LocaleController.getString("Loading", R.string.Loading), false); + nameTextView.clearFocus(); + checkTextView.setVisibility(!isPrivate && checkTextView.length() != 0 ? View.VISIBLE : View.GONE); + AndroidUtilities.hideKeyboard(nameTextView); + } + + private boolean checkUserName(final String name, boolean alert) { + if (name != null && name.length() > 0) { + checkTextView.setVisibility(View.VISIBLE); + } else { + checkTextView.setVisibility(View.GONE); + } + if (alert && name.length() == 0) { + return true; + } + if (checkRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(checkRunnable); + checkRunnable = null; + lastCheckName = null; + if (checkReqId != 0) { + ConnectionsManager.getInstance().cancelRequest(checkReqId, true); + } + } + lastNameAvailable = false; + if (name != null) { + if (name.startsWith("_") || name.endsWith("_")) { + checkTextView.setText(LocaleController.getString("LinkInvalid", R.string.LinkInvalid)); + checkTextView.setTextColor(0xffcf3030); + return false; + } + for (int a = 0; a < name.length(); a++) { + char ch = name.charAt(a); + if (a == 0 && ch >= '0' && ch <= '9') { + if (currentChat.megagroup) { + if (alert) { + showErrorAlert(LocaleController.getString("LinkInvalidStartNumberMega", R.string.LinkInvalidStartNumberMega)); + } else { + checkTextView.setText(LocaleController.getString("LinkInvalidStartNumberMega", R.string.LinkInvalidStartNumberMega)); + checkTextView.setTextColor(0xffcf3030); + } + } else { + if (alert) { + showErrorAlert(LocaleController.getString("LinkInvalidStartNumber", R.string.LinkInvalidStartNumber)); + } else { + checkTextView.setText(LocaleController.getString("LinkInvalidStartNumber", R.string.LinkInvalidStartNumber)); + checkTextView.setTextColor(0xffcf3030); + } + } + return false; + } + if (!(ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch == '_')) { + if (alert) { + showErrorAlert(LocaleController.getString("LinkInvalid", R.string.LinkInvalid)); + } else { + checkTextView.setText(LocaleController.getString("LinkInvalid", R.string.LinkInvalid)); + checkTextView.setTextColor(0xffcf3030); + } + return false; + } + } + } + if (name == null || name.length() < 5) { + if (currentChat.megagroup) { + if (alert) { + showErrorAlert(LocaleController.getString("LinkInvalidShortMega", R.string.LinkInvalidShortMega)); + } else { + checkTextView.setText(LocaleController.getString("LinkInvalidShortMega", R.string.LinkInvalidShortMega)); + checkTextView.setTextColor(0xffcf3030); + } + } else { + if (alert) { + showErrorAlert(LocaleController.getString("LinkInvalidShort", R.string.LinkInvalidShort)); + } else { + checkTextView.setText(LocaleController.getString("LinkInvalidShort", R.string.LinkInvalidShort)); + checkTextView.setTextColor(0xffcf3030); + } + } + return false; + } + if (name.length() > 32) { + if (alert) { + showErrorAlert(LocaleController.getString("LinkInvalidLong", R.string.LinkInvalidLong)); + } else { + checkTextView.setText(LocaleController.getString("LinkInvalidLong", R.string.LinkInvalidLong)); + checkTextView.setTextColor(0xffcf3030); + } + return false; + } + + if (!alert) { + checkTextView.setText(LocaleController.getString("LinkChecking", R.string.LinkChecking)); + checkTextView.setTextColor(0xff6d6d72); + lastCheckName = name; + checkRunnable = new Runnable() { + @Override + public void run() { + TLRPC.TL_channels_checkUsername req = new TLRPC.TL_channels_checkUsername(); + req.username = name; + req.channel = MessagesController.getInputChannel(chatId); + checkReqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + checkReqId = 0; + if (lastCheckName != null && lastCheckName.equals(name)) { + if (error == null && response instanceof TLRPC.TL_boolTrue) { + checkTextView.setText(LocaleController.formatString("LinkAvailable", R.string.LinkAvailable, name)); + checkTextView.setTextColor(0xff26972c); + lastNameAvailable = true; + } else { + if (error != null && error.text.equals("CHANNELS_ADMIN_PUBLIC_TOO_MUCH")) { + checkTextView.setText(LocaleController.getString("ChangePublicLimitReached", R.string.ChangePublicLimitReached)); + } else { + checkTextView.setText(LocaleController.getString("LinkInUse", R.string.LinkInUse)); + } + checkTextView.setTextColor(0xffcf3030); + lastNameAvailable = false; + } + } + } + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors); + } + }; + AndroidUtilities.runOnUIThread(checkRunnable, 300); + } + return true; + } + + private void generateLink() { + if (loadingInvite || invite != null) { + return; + } + loadingInvite = true; + TLRPC.TL_channels_exportInvite req = new TLRPC.TL_channels_exportInvite(); + req.channel = MessagesController.getInputChannel(chatId); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (error == null) { + invite = (TLRPC.ExportedChatInvite) response; + } + loadingInvite = false; + privateContainer.setText(invite != null ? invite.link : LocaleController.getString("Loading", R.string.Loading), false); + } + }); + } + }); + } + + private void showErrorAlert(String error) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + switch (error) { + case "USERNAME_INVALID": + builder.setMessage(LocaleController.getString("LinkInvalid", R.string.LinkInvalid)); + break; + case "USERNAME_OCCUPIED": + builder.setMessage(LocaleController.getString("LinkInUse", R.string.LinkInUse)); + break; + case "USERNAMES_UNAVAILABLE": + builder.setMessage(LocaleController.getString("FeatureUnavailable", R.string.FeatureUnavailable)); + break; + default: + builder.setMessage(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred)); + break; + } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelIntroActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelIntroActivity.java new file mode 100644 index 00000000..1ad5b77b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelIntroActivity.java @@ -0,0 +1,150 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.content.Context; +import android.os.Bundle; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; + +public class ChannelIntroActivity extends BaseFragment { + + private ImageView imageView; + private TextView createChannelText; + private TextView whatIsChannelText; + private TextView descriptionText; + + @Override + public View createView(Context context) { + actionBar.setBackgroundColor(Theme.ACTION_BAR_CHANNEL_INTRO_COLOR); + actionBar.setBackButtonImage(R.drawable.pl_back); + actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_CHANNEL_INTRO_SELECTOR_COLOR); + actionBar.setCastShadows(false); + if (!AndroidUtilities.isTablet()) { + actionBar.showActionModeTop(); + } + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + + fragmentView = new ViewGroup(context) { + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = MeasureSpec.getSize(widthMeasureSpec); + int height = MeasureSpec.getSize(heightMeasureSpec); + + if (width > height) { + imageView.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.45f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) (height * 0.78f), MeasureSpec.EXACTLY)); + whatIsChannelText.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.6f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); + descriptionText.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.5f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); + createChannelText.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.6f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24), MeasureSpec.EXACTLY)); + } else { + imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec((int) (height * 0.44f), MeasureSpec.EXACTLY)); + whatIsChannelText.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); + descriptionText.measure(MeasureSpec.makeMeasureSpec((int) (width * 0.9f), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED)); + createChannelText.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24), MeasureSpec.EXACTLY)); + } + + setMeasuredDimension(width, height); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + int width = r - l; + int height = b - t; + + if (r > b) { + int y = (int) (height * 0.05f); + imageView.layout(0, y, imageView.getMeasuredWidth(), y + imageView.getMeasuredHeight()); + int x = (int) (width * 0.4f); + y = (int) (height * 0.14f); + whatIsChannelText.layout(x, y, x + whatIsChannelText.getMeasuredWidth(), y + whatIsChannelText.getMeasuredHeight()); + y = (int) (height * 0.61f); + createChannelText.layout(x, y, x + createChannelText.getMeasuredWidth(), y + createChannelText.getMeasuredHeight()); + x = (int) (width * 0.45f); + y = (int) (height * 0.31f); + descriptionText.layout(x, y, x + descriptionText.getMeasuredWidth(), y + descriptionText.getMeasuredHeight()); + } else { + int y = (int) (height * 0.05f); + imageView.layout(0, y, imageView.getMeasuredWidth(), y + imageView.getMeasuredHeight()); + y = (int) (height * 0.59f); + whatIsChannelText.layout(0, y, whatIsChannelText.getMeasuredWidth(), y + whatIsChannelText.getMeasuredHeight()); + y = (int) (height * 0.68f); + int x = (int) (width * 0.05f); + descriptionText.layout(x, y, x + descriptionText.getMeasuredWidth(), y + descriptionText.getMeasuredHeight()); + y = (int) (height * 0.86f); + createChannelText.layout(0, y, createChannelText.getMeasuredWidth(), y + createChannelText.getMeasuredHeight()); + } + } + }; + fragmentView.setBackgroundColor(0xffffffff); + ViewGroup viewGroup = (ViewGroup) fragmentView; + viewGroup.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + + imageView = new ImageView(context); + imageView.setImageResource(R.drawable.channelintro); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + viewGroup.addView(imageView); + + whatIsChannelText = new TextView(context); + whatIsChannelText.setTextColor(0xff212121); + whatIsChannelText.setGravity(Gravity.CENTER_HORIZONTAL); + whatIsChannelText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 24); + whatIsChannelText.setText(LocaleController.getString("ChannelAlertTitle", R.string.ChannelAlertTitle)); + viewGroup.addView(whatIsChannelText); + + descriptionText = new TextView(context); + descriptionText.setTextColor(0xff787878); + descriptionText.setGravity(Gravity.CENTER_HORIZONTAL); + descriptionText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + descriptionText.setText(LocaleController.getString("ChannelAlertText", R.string.ChannelAlertText)); + viewGroup.addView(descriptionText); + + createChannelText = new TextView(context); + createChannelText.setTextColor(0xff4c8eca); + createChannelText.setGravity(Gravity.CENTER); + createChannelText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + createChannelText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + createChannelText.setText(LocaleController.getString("ChannelAlertCreate", R.string.ChannelAlertCreate)); + viewGroup.addView(createChannelText); + createChannelText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Bundle args = new Bundle(); + args.putInt("step", 0); + presentFragment(new ChannelCreateActivity(args), true); + } + }); + + return fragmentView; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChannelUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChannelUsersActivity.java new file mode 100644 index 00000000..50d49b29 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChannelUsersActivity.java @@ -0,0 +1,747 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.os.Build; +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.FrameLayout; +import android.widget.ListView; + +import org.telegram.PhoneFormat.PhoneFormat; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Adapters.BaseFragmentAdapter; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.RadioCell; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Cells.TextSettingsCell; +import org.telegram.ui.Cells.UserCell; +import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.EmptyTextProgressView; +import org.telegram.ui.Components.LayoutHelper; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + +public class ChannelUsersActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + private ListAdapter listViewAdapter; + private EmptyTextProgressView emptyView; + + private ArrayList participants = new ArrayList<>(); + private int chatId; + private int type; + private boolean loadingUsers; + private boolean firstLoaded; + private boolean isAdmin; + private boolean isPublic; + private boolean isMegagroup; + private int participantsStartRow; + + public ChannelUsersActivity(Bundle args) { + super(args); + chatId = arguments.getInt("chat_id"); + type = arguments.getInt("type"); + TLRPC.Chat chat = MessagesController.getInstance().getChat(chatId); + if (chat != null) { + if (chat.creator) { + isAdmin = true; + isPublic = (chat.flags & TLRPC.CHAT_FLAG_IS_PUBLIC) != 0; + } + isMegagroup = chat.megagroup; + } + if (type == 0) { + participantsStartRow = 0; + } else if (type == 1) { + participantsStartRow = isAdmin && isMegagroup ? 4 : 0; + } else if (type == 2) { + participantsStartRow = isAdmin ? (isPublic ? 2 : 3) : 0; + } + } + + @Override + public boolean onFragmentCreate() { + super.onFragmentCreate(); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.chatInfoDidLoaded); + getChannelParticipants(0, 200); + return true; + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.chatInfoDidLoaded); + } + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + if (type == 0) { + actionBar.setTitle(LocaleController.getString("ChannelBlockedUsers", R.string.ChannelBlockedUsers)); + } else if (type == 1) { + actionBar.setTitle(LocaleController.getString("ChannelAdministrators", R.string.ChannelAdministrators)); + } else if (type == 2) { + actionBar.setTitle(LocaleController.getString("ChannelMembers", R.string.ChannelMembers)); + } + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + + ActionBarMenu menu = actionBar.createMenu(); + + fragmentView = new FrameLayout(context); + //fragmentView.setBackgroundColor(0xfff0f0f0); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int rowColor = themePrefs.getInt("profileRowColor", 0xffffffff); + fragmentView.setBackgroundColor(rowColor); + FrameLayout frameLayout = (FrameLayout) fragmentView; + + emptyView = new EmptyTextProgressView(context); + if (type == 0) { + if (isMegagroup) { + emptyView.setText(LocaleController.getString("NoBlockedGroup", R.string.NoBlockedGroup)); + } else { + emptyView.setText(LocaleController.getString("NoBlocked", R.string.NoBlocked)); + } + } + frameLayout.addView(emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + final ListView listView = new ListView(context); + listView.setEmptyView(emptyView); + listView.setDivider(null); + listView.setDividerHeight(0); + listView.setDrawSelectorOnTop(true); + listView.setAdapter(listViewAdapter = new ListAdapter(context)); + if (Build.VERSION.SDK_INT >= 11) { + listView.setVerticalScrollbarPosition(LocaleController.isRTL ? ListView.SCROLLBAR_POSITION_LEFT : ListView.SCROLLBAR_POSITION_RIGHT); + } + frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + if (type == 2) { + if (isAdmin) { + if (i == 0) { + Bundle args = new Bundle(); + args.putBoolean("onlyUsers", true); + args.putBoolean("destroyAfterSelect", true); + args.putBoolean("returnAsResult", true); + args.putBoolean("needForwardCount", false); + args.putBoolean("allowUsernameSearch", false); + args.putString("selectAlertString", LocaleController.getString("ChannelAddTo", R.string.ChannelAddTo)); + ContactsActivity fragment = new ContactsActivity(args); + fragment.setDelegate(new ContactsActivity.ContactsActivityDelegate() { + @Override + public void didSelectContact(TLRPC.User user, String param) { + MessagesController.getInstance().addUserToChat(chatId, user, null, param != null ? Utilities.parseInt(param) : 0, null, ChannelUsersActivity.this); + } + }); + presentFragment(fragment); + } else if (!isPublic && i == 1) { + presentFragment(new GroupInviteActivity(chatId)); + } + } + + } else if (type == 1) { + if (isAdmin) { + if (isMegagroup && (i == 1 || i == 2)) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(chatId); + if (chat == null) { + return; + } + boolean changed = false; + if (i == 1 && !chat.democracy) { + chat.democracy = true; + changed = true; + } else if (i == 2 && chat.democracy) { + chat.democracy = false; + changed = true; + } + if (changed) { + MessagesController.getInstance().toogleChannelInvites(chatId, chat.democracy); + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + if (child instanceof RadioCell) { + int num = (Integer) child.getTag(); + ((RadioCell) child).setChecked(num == 0 && chat.democracy || num == 1 && !chat.democracy, true); + } + } + } + return; + } + if (i == participantsStartRow + participants.size()) { + Bundle args = new Bundle(); + args.putBoolean("onlyUsers", true); + args.putBoolean("destroyAfterSelect", true); + args.putBoolean("returnAsResult", true); + args.putBoolean("needForwardCount", false); + args.putBoolean("allowUsernameSearch", true); + /*if (isMegagroup) { + args.putBoolean("allowBots", false); + }*/ + args.putString("selectAlertString", LocaleController.getString("ChannelAddUserAdminAlert", R.string.ChannelAddUserAdminAlert)); + ContactsActivity fragment = new ContactsActivity(args); + fragment.setDelegate(new ContactsActivity.ContactsActivityDelegate() { + @Override + public void didSelectContact(TLRPC.User user, String param) { + setUserChannelRole(user, new TLRPC.TL_channelRoleEditor()); + } + }); + presentFragment(fragment); + return; + } + } + } + TLRPC.ChannelParticipant participant = null; + if (i >= participantsStartRow && i < participants.size() + participantsStartRow) { + participant = participants.get(i - participantsStartRow); + } + if (participant != null) { + Bundle args = new Bundle(); + args.putInt("user_id", participant.user_id); + presentFragment(new ProfileActivity(args)); + } + } + }); + + if (isAdmin || isMegagroup && type == 0) { + listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { + @Override + public boolean onItemLongClick(AdapterView adapterView, View view, int i, long l) { + if (getParentActivity() == null) { + return false; + } + TLRPC.ChannelParticipant participant = null; + if (i >= participantsStartRow && i < participants.size() + participantsStartRow) { + participant = participants.get(i - participantsStartRow); + } + if (participant != null) { + final TLRPC.ChannelParticipant finalParticipant = participant; + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + CharSequence[] items = null; + if (type == 0) { + items = new CharSequence[]{LocaleController.getString("Unblock", R.string.Unblock)}; + } else if (type == 1) { + items = new CharSequence[]{LocaleController.getString("ChannelRemoveUserAdmin", R.string.ChannelRemoveUserAdmin)}; + } else if (type == 2) { + items = new CharSequence[]{LocaleController.getString("ChannelRemoveUser", R.string.ChannelRemoveUser)}; + } + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (i == 0) { + if (type == 0) { + participants.remove(finalParticipant); + listViewAdapter.notifyDataSetChanged(); + TLRPC.TL_channels_kickFromChannel req = new TLRPC.TL_channels_kickFromChannel(); + req.kicked = false; + req.user_id = MessagesController.getInputUser(finalParticipant.user_id); + req.channel = MessagesController.getInputChannel(chatId); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + if (response != null) { + final TLRPC.Updates updates = (TLRPC.Updates) response; + MessagesController.getInstance().processUpdates(updates, false); + if (!updates.chats.isEmpty()) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + TLRPC.Chat chat = updates.chats.get(0); + MessagesController.getInstance().loadFullChat(chat.id, 0, true); + } + }, 1000); + } + } + } + }); + } else if (type == 1) { + setUserChannelRole(MessagesController.getInstance().getUser(finalParticipant.user_id), new TLRPC.TL_channelRoleEmpty()); + } else if (type == 2) { + MessagesController.getInstance().deleteUserFromChat(chatId, MessagesController.getInstance().getUser(finalParticipant.user_id), null); + } + } + } + }); + showDialog(builder.create()); + return true; + } else { + return false; + } + } + }); + } + + if (loadingUsers) { + emptyView.showProgress(); + } else { + emptyView.showTextView(); + } + return fragmentView; + } + + public void setUserChannelRole(TLRPC.User user, TLRPC.ChannelParticipantRole role) { + if (user == null || role == null) { + return; + } + TLRPC.TL_channels_editAdmin req = new TLRPC.TL_channels_editAdmin(); + req.channel = MessagesController.getInputChannel(chatId); + req.user_id = MessagesController.getInputUser(user); + req.role = role; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, final TLRPC.TL_error error) { + if (error == null) { + MessagesController.getInstance().processUpdates((TLRPC.Updates) response, false); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + MessagesController.getInstance().loadFullChat(chatId, 0, true); + } + }, 1000); + } else { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + AlertsCreator.showAddUserAlert(error.text, ChannelUsersActivity.this, !isMegagroup); + } + }); + } + } + }); + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.chatInfoDidLoaded) { + TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; + if (chatFull.id == chatId) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + getChannelParticipants(0, 200); + } + }); + } + } + } + + private int getChannelAdminParticipantType(TLRPC.ChannelParticipant participant) { + if (participant instanceof TLRPC.TL_channelParticipantCreator || participant instanceof TLRPC.TL_channelParticipantSelf) { + return 0; + } else if (participant instanceof TLRPC.TL_channelParticipantEditor) { + return 1; + } else { + return 2; + } + } + + private void getChannelParticipants(int offset, int count) { + if (loadingUsers) { + return; + } + loadingUsers = true; + if (emptyView != null && !firstLoaded) { + emptyView.showProgress(); + } + if (listViewAdapter != null) { + listViewAdapter.notifyDataSetChanged(); + } + TLRPC.TL_channels_getParticipants req = new TLRPC.TL_channels_getParticipants(); + req.channel = MessagesController.getInputChannel(chatId); + if (type == 0) { + req.filter = new TLRPC.TL_channelParticipantsKicked(); + } else if (type == 1) { + req.filter = new TLRPC.TL_channelParticipantsAdmins(); + } else if (type == 2) { + req.filter = new TLRPC.TL_channelParticipantsRecent(); + } + req.offset = offset; + req.limit = count; + int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (error == null) { + TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; + MessagesController.getInstance().putUsers(res.users, false); + participants = res.participants; + try { + if (type == 0 || type == 2) { + Collections.sort(participants, new Comparator() { + @Override + public int compare(TLRPC.ChannelParticipant lhs, TLRPC.ChannelParticipant rhs) { + TLRPC.User user1 = MessagesController.getInstance().getUser(rhs.user_id); + TLRPC.User user2 = MessagesController.getInstance().getUser(lhs.user_id); + int status1 = 0; + int status2 = 0; + if (user1 != null && user1.status != null) { + if (user1.id == UserConfig.getClientUserId()) { + status1 = ConnectionsManager.getInstance().getCurrentTime() + 50000; + } else { + status1 = user1.status.expires; + } + } + if (user2 != null && user2.status != null) { + if (user2.id == UserConfig.getClientUserId()) { + status2 = ConnectionsManager.getInstance().getCurrentTime() + 50000; + } else { + status2 = user2.status.expires; + } + } + if (status1 > 0 && status2 > 0) { + if (status1 > status2) { + return 1; + } else if (status1 < status2) { + return -1; + } + return 0; + } else if (status1 < 0 && status2 < 0) { + if (status1 > status2) { + return 1; + } else if (status1 < status2) { + return -1; + } + return 0; + } else if (status1 < 0 && status2 > 0 || status1 == 0 && status2 != 0) { + return -1; + } else if (status2 < 0 && status1 > 0 || status2 == 0 && status1 != 0) { + return 1; + } + return 0; + } + }); + } else if (type == 1) { + Collections.sort(res.participants, new Comparator() { + @Override + public int compare(TLRPC.ChannelParticipant lhs, TLRPC.ChannelParticipant rhs) { + int type1 = getChannelAdminParticipantType(lhs); + int type2 = getChannelAdminParticipantType(rhs); + if (type1 > type2) { + return 1; + } else if (type1 < type2) { + return -1; + } + return 0; + } + }); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + loadingUsers = false; + firstLoaded = true; + if (emptyView != null) { + emptyView.showTextView(); + } + if (listViewAdapter != null) { + listViewAdapter.notifyDataSetChanged(); + } + } + }); + } + }); + ConnectionsManager.getInstance().bindRequestToGuid(reqId, classGuid); + } + + @Override + public void onResume() { + super.onResume(); + if (listViewAdapter != null) { + listViewAdapter.notifyDataSetChanged(); + } + } + + private class ListAdapter extends BaseFragmentAdapter { + private Context mContext; + + public ListAdapter(Context context) { + mContext = context; + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public boolean isEnabled(int i) { + if (type == 2) { + if (isAdmin) { + if (!isPublic) { + if (i == 0 || i == 1) { + return true; + } else if (i == 2) { + return false; + } + } else { + if (i == 0) { + return true; + } else if (i == 1) { + return false; + } + } + } + } else if (type == 1) { + if (i == participantsStartRow + participants.size()) { + return isAdmin; + } else if (i == participantsStartRow + participants.size() + 1) { + return false; + } else if (isMegagroup && isAdmin && i < 4) { + return i == 1 || i == 2; + } + } + return i != participants.size() + participantsStartRow && participants.get(i - participantsStartRow).user_id != UserConfig.getClientUserId(); + } + + @Override + public int getCount() { + if (participants.isEmpty() && type == 0 || loadingUsers && !firstLoaded) { + return 0; + } else if (type == 1) { + return participants.size() + (isAdmin ? 2 : 1) + (isAdmin && isMegagroup ? 4 : 0); + } + return participants.size() + participantsStartRow + 1; + } + + @Override + public Object getItem(int i) { + return null; + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public boolean hasStableIds() { + return false; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int rowColor = themePrefs.getInt("profileRowColor", 0xffffffff); + int tColor = themePrefs.getInt("profileTitleColor", 0xff212121); + int sColor = themePrefs.getInt("profileSummaryColor", 0xff8a8a8a); + int viewType = getItemViewType(i); + if (viewType == 0) { + if (view == null) { + view = new UserCell(mContext, 1, 0, false); + //view.setBackgroundColor(0xffffffff); + view.setBackgroundColor(rowColor); + //view.setBackgroundColor(0x00000000); + view.setTag("Profile"); + } + UserCell userCell = (UserCell) view; + userCell.setNameColor(tColor); + userCell.setStatusColor(sColor); + TLRPC.ChannelParticipant participant = participants.get(i - participantsStartRow); + TLRPC.User user = MessagesController.getInstance().getUser(participant.user_id); + if (user != null) { + if (type == 0) { + userCell.setData(user, null, user.phone != null && user.phone.length() != 0 ? PhoneFormat.getInstance().format("+" + user.phone) : LocaleController.getString("NumberUnknown", R.string.NumberUnknown), 0); + } else if (type == 1) { + String role = null; + if (participant instanceof TLRPC.TL_channelParticipantCreator || participant instanceof TLRPC.TL_channelParticipantSelf) { + role = LocaleController.getString("ChannelCreator", R.string.ChannelCreator); + } else if (participant instanceof TLRPC.TL_channelParticipantModerator) { + role = LocaleController.getString("ChannelModerator", R.string.ChannelModerator); + } else if (participant instanceof TLRPC.TL_channelParticipantEditor) { + role = LocaleController.getString("ChannelEditor", R.string.ChannelEditor); + } + userCell.setData(user, null, role, 0); + } else if (type == 2) { + userCell.setData(user, null, null, 0); + } + } + } else if (viewType == 1) { + if (view == null) { + view = new TextInfoPrivacyCell(mContext); + } + if (type == 0) { + ((TextInfoPrivacyCell) view).setText(String.format("%1$s\n\n%2$s", LocaleController.getString("NoBlockedGroup", R.string.NoBlockedGroup), LocaleController.getString("UnblockText", R.string.UnblockText))); + view.setBackgroundResource(R.drawable.greydivider_bottom); + } else if (type == 1) { + if (isAdmin) { + if (isMegagroup) { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("MegaAdminsInfo", R.string.MegaAdminsInfo)); + view.setBackgroundResource(R.drawable.greydivider_bottom); + } else { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("ChannelAdminsInfo", R.string.ChannelAdminsInfo)); + view.setBackgroundResource(R.drawable.greydivider_bottom); + } + } else { + ((TextInfoPrivacyCell) view).setText(""); + view.setBackgroundResource(R.drawable.greydivider_bottom); + } + } else if (type == 2) { + if ((!isPublic && i == 2 || i == 1) && isAdmin) { + if (isMegagroup) { + ((TextInfoPrivacyCell) view).setText(""); + } else { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("ChannelMembersInfo", R.string.ChannelMembersInfo)); + } + view.setBackgroundResource(R.drawable.greydivider); + } else { + ((TextInfoPrivacyCell) view).setText(""); + view.setBackgroundResource(R.drawable.greydivider_bottom); + } + } + view.setTag("Profile"); + ((TextInfoPrivacyCell) view).setTextColor(sColor); + if(rowColor != 0xffffffff)view.setBackgroundColor(rowColor); + } else if (viewType == 2) { + if (view == null) { + view = new TextSettingsCell(mContext); + //view.setBackgroundColor(0xffffffff); + view.setBackgroundColor(rowColor); + } + TextSettingsCell actionCell = (TextSettingsCell) view; + actionCell.setTag("Profile"); + actionCell.setTextColor(tColor); + if (type == 2) { + if (i == 0) { + actionCell.setText(LocaleController.getString("AddMember", R.string.AddMember), true); + } else if (i == 1) { + actionCell.setText(LocaleController.getString("ChannelInviteViaLink", R.string.ChannelInviteViaLink), false); + } + } else if (type == 1) { + actionCell.setTextAndIcon(LocaleController.getString("ChannelAddAdmin", R.string.ChannelAddAdmin), R.drawable.managers, false); + } + } else if (viewType == 3) { + if (view == null) { + //view = new ShadowSectionCell(mContext); + view = new ShadowSectionCell(mContext, false); + view.setBackgroundColor(rowColor); + } + } else if (viewType == 4) { + if (view == null) { + view = new TextCell(mContext); + view.setBackgroundColor(0xffffffff); + if(rowColor != 0xffffffff)view.setBackgroundColor(rowColor); + } + ((TextCell) view).setTextAndIcon(LocaleController.getString("ChannelAddAdmin", R.string.ChannelAddAdmin), R.drawable.managers); + ((TextCell) view).setTextColor(tColor); + } else if (viewType == 5) { + if (view == null) { + view = new HeaderCell(mContext); + view.setBackgroundColor(0xffffffff); + if(rowColor != 0xffffffff)view.setBackgroundColor(rowColor); + } + ((HeaderCell) view).setText(LocaleController.getString("WhoCanAddMembers", R.string.WhoCanAddMembers)); + } else if (viewType == 6) { + if (view == null) { + view = new RadioCell(mContext); + view.setBackgroundColor(0xffffffff); + if(rowColor != 0xffffffff)view.setBackgroundColor(rowColor); + } + RadioCell radioCell = (RadioCell) view; + radioCell.setTextColor(tColor); + TLRPC.Chat chat = MessagesController.getInstance().getChat(chatId); + if (i == 1) { + radioCell.setTag(0); + radioCell.setText(LocaleController.getString("WhoCanAddMembersAllMembers", R.string.WhoCanAddMembersAllMembers), chat != null && chat.democracy, true); + } else if (i == 2) { + radioCell.setTag(1); + radioCell.setText(LocaleController.getString("WhoCanAddMembersAdmins", R.string.WhoCanAddMembersAdmins), chat != null && !chat.democracy, false); + } + } + return view; + } + + @Override + public int getItemViewType(int i) { + if (type == 1) { + if (isAdmin) { + if (isMegagroup) { + if (i == 0) { + return 5; + } else if (i == 1 || i == 2) { + return 6; + } else if (i == 3) { + return 3; + } + } + if (i == participantsStartRow + participants.size()) { + return 4; + } else if (i == participantsStartRow + participants.size() + 1) { + return 1; + } + } + } else if (type == 2) { + if (isAdmin) { + if (!isPublic) { + if (i == 0 || i == 1) { + return 2; + } else if (i == 2) { + return 1; + } + } else { + if (i == 0) { + return 2; + } else if (i == 1) { + return 1; + } + } + } + } + if (i == participants.size() + participantsStartRow) { + return 1; + } + return 0; + } + + @Override + public int getViewTypeCount() { + return 7; + } + + @Override + public boolean isEmpty() { + return getCount() == 0 || participants.isEmpty() && loadingUsers; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java index 0b46adbd..ce9f0f8a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ChatActivity.java @@ -12,6 +12,7 @@ import android.Manifest; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; +import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -20,6 +21,7 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.database.Cursor; import android.graphics.Bitmap; +import android.graphics.Canvas; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; @@ -30,11 +32,11 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.provider.Browser; import android.provider.ContactsContract; import android.provider.MediaStore; import android.text.TextUtils; import android.text.style.ClickableSpan; +import android.text.style.URLSpan; import android.util.Base64; import android.util.Log; import android.util.SparseArray; @@ -45,6 +47,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; +import android.view.WindowManager; import android.webkit.MimeTypeMap; import android.widget.EditText; import android.widget.FrameLayout; @@ -62,6 +65,7 @@ import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; import org.telegram.messenger.AnimationCompat.ViewProxy; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.Emoji; @@ -82,9 +86,10 @@ import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.messenger.VideoEditedInfo; +import org.telegram.messenger.browser.Browser; import org.telegram.messenger.query.BotQuery; +import org.telegram.messenger.query.MessagesQuery; import org.telegram.messenger.query.MessagesSearchQuery; -import org.telegram.messenger.query.ReplyMessageQuery; import org.telegram.messenger.query.StickersQuery; import org.telegram.messenger.support.widget.LinearLayoutManager; import org.telegram.messenger.support.widget.RecyclerView; @@ -100,36 +105,33 @@ import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.BackDrawable; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.SimpleTextView; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.MentionsAdapter; import org.telegram.ui.Adapters.StickersAdapter; import org.telegram.ui.Cells.BotHelpCell; +import org.telegram.ui.Cells.BotSwitchCell; import org.telegram.ui.Cells.ChatActionCell; -import org.telegram.ui.Cells.ChatAudioCell; import org.telegram.ui.Cells.ChatBaseCell; -import org.telegram.ui.Cells.ChatContactCell; import org.telegram.ui.Cells.ChatLoadingCell; -import org.telegram.ui.Cells.ChatMediaCell; import org.telegram.ui.Cells.ChatMessageCell; -import org.telegram.ui.Cells.ChatMusicCell; import org.telegram.ui.Cells.ChatUnreadCell; +import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Components.AlertsCreator; -import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.BackupImageView; import org.telegram.ui.Components.ChatActivityEnterView; import org.telegram.ui.Components.ChatAttachView; +import org.telegram.ui.Components.ChatAvatarContainer; import org.telegram.ui.Components.FrameLayoutFixed; +import org.telegram.ui.Components.Glow; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.NumberTextView; import org.telegram.ui.Components.PlayerView; -import org.telegram.ui.Components.RadioButton; -import org.telegram.ui.Components.RecordStatusDrawable; import org.telegram.ui.Components.RecyclerListView; -import org.telegram.ui.Components.ResourceLoader; -import org.telegram.ui.Components.SendingFileExDrawable; -import org.telegram.ui.Components.ShareFrameLayout; +import org.telegram.ui.Components.ShareAlert; import org.telegram.ui.Components.SizeNotifierFrameLayout; +import org.telegram.ui.Components.StickersAlert; import org.telegram.ui.Components.TimerDrawable; -import org.telegram.ui.Components.TypingDotsDrawable; import org.telegram.ui.Components.URLSpanBotCommand; import org.telegram.ui.Components.URLSpanNoUnderline; import org.telegram.ui.Components.URLSpanReplacement; @@ -144,7 +146,7 @@ import java.util.concurrent.Semaphore; import java.util.regex.Matcher; @SuppressWarnings("unchecked") -public class ChatActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, DialogsActivity.MessagesActivityDelegate, +public class ChatActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, DialogsActivity.DialogsActivityDelegate, PhotoViewer.PhotoViewerProvider { protected TLRPC.Chat currentChat; @@ -153,7 +155,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private boolean userBlocked = false; private ArrayList chatMessageCellsCache = new ArrayList<>(); - private ArrayList chatMediaCellsCache = new ArrayList<>(); private Dialog closeChatDialog; private FrameLayout progressView; @@ -172,22 +173,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private RecyclerListView chatListView; private LinearLayoutManager chatLayoutManager; private ChatActivityAdapter chatAdapter; - private BackupImageView avatarImageView; + //private BackupImageView avatarImageView; private TextView bottomOverlayChatText; private FrameLayout bottomOverlayChat; - private TypingDotsDrawable typingDotsDrawable; - private RecordStatusDrawable recordStatusDrawable; - private SendingFileExDrawable sendingFileDrawable; + //private TypingDotsDrawable typingDotsDrawable; + //private RecordStatusDrawable recordStatusDrawable; + //private SendingFileExDrawable sendingFileDrawable; private FrameLayout emptyViewContainer; private ArrayList actionModeViews = new ArrayList<>(); - private TextView nameTextView; - private TextView onlineTextView; - private RadioButton radioButton; - private FrameLayout avatarContainer; + private ChatAvatarContainer avatarContainer; + //private TextView nameTextView; + //private TextView onlineTextView; + //private RadioButton radioButton; private TextView bottomOverlayText; private TextView secretViewStatusTextView; private NumberTextView selectedMessagesCountTextView; + private TextView actionModeTextView; private RecyclerListView stickersListView; + private RecyclerListView.OnItemClickListener stickersOnItemClickListener; + private RecyclerListView.OnItemClickListener mentionsOnItemClickListener; private StickersAdapter stickersAdapter; private FrameLayout stickersPanel; private TextView muteItem; @@ -197,24 +201,44 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private TextView replyObjectTextView; private ImageView replyIconImageView; private MentionsAdapter mentionsAdapter; + private BotSwitchCell botSwitchCell; + private View botSwitchShadow; + private FrameLayout mentionContainer; private RecyclerListView mentionListView; private LinearLayoutManager mentionLayoutManager; private AnimatorSetProxy mentionListAnimation; private ChatAttachView chatAttachView; private BottomSheet chatAttachViewSheet; private LinearLayout reportSpamView; + private AnimatorSetProxy reportSpamViewAnimator; private TextView addToContactsButton; private TextView reportSpamButton; private FrameLayout reportSpamContainer; private PlayerView playerView; private TextView gifHintTextView; private View emojiButtonRed; + private FrameLayout pinnedMessageView; + private AnimatorSetProxy pinnedMessageViewAnimator; + private SimpleTextView pinnedMessageNameTextView; + private SimpleTextView pinnedMessageTextView; + private FrameLayout alertView; + private Runnable hideAlertViewRunnable; + private TextView alertNameTextView; + private TextView alertTextView; + private AnimatorSetProxy alertViewAnimator; + + private boolean mentionListViewIgnoreLayout; + private int mentionListViewScrollOffsetY; + private int mentionListViewLastViewTop; + private int mentionListViewLastViewPosition; + private boolean mentionListViewIsScrolling; + + private MessageObject pinnedMessageObject; + private int loadingPinnedMessage; private ObjectAnimatorProxy pagedownButtonAnimation; private AnimatorSetProxy replyButtonAnimation; - private TLRPC.User reportSpamUser; - private boolean openSearchKeyboard; private int channelMessagesImportant; @@ -222,6 +246,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private ImageView deleteIconImageView; private View lineView; + + private boolean waitingForReplyMessageLoad; + private boolean allowStickersPanel; private boolean allowContextBotPanel; private boolean allowContextBotPanelSecond = true; @@ -243,6 +270,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private Runnable waitingForCharaterEnterRunnable; private boolean openAnimationEnded; + private boolean attachAttachViewFirstShow = true; private int readWithDate; private int readWithMid; @@ -275,6 +303,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private int startLoadFromMessageId; private boolean needSelectFromMessageId; private int returnToMessageId; + private int returnToLoadIndex; private boolean first = true; private int unread_to_load; @@ -290,10 +319,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private Rect scrollRect = new Rect(); protected TLRPC.ChatFull info = null; - private int onlineCount = -1; private HashMap botInfo = new HashMap<>(); private String botUser; + private long inlineReturn; private MessageObject botButtons; private MessageObject botReplyButtons; private int botsCount; @@ -322,8 +351,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private final static int share_contact = 17;//13; private final static int mute = 18;//14; private final static int reply = 19;//15; - - private final static int add_member = 20; + private final static int edit_done = 20; + private final static int report = 21; + private final static int leave_group = 28;//12; + private final static int add_member = 29; private final static int bot_help = 30; private final static int bot_settings = 31; @@ -353,13 +384,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private static boolean QuoteForward; private final static int quoteforward = 111;//0; + private final static int direct_share = 112; private final static int chat_background = 99; private boolean refreshWallpaper; private boolean quote; + private boolean directShareReplies; + private boolean directShareToMenu; private TextView dateTv; + private boolean showDateTv; RecyclerListView.OnItemLongClickListener onItemLongClickListener = new RecyclerListView.OnItemLongClickListener() { @Override @@ -394,10 +429,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not quote = arguments.getBoolean("quote", false); final int userId = arguments.getInt("user_id", 0); final int encId = arguments.getInt("enc_id", 0); + inlineReturn = arguments.getLong("inline_return", 0); + String inlineQuery = arguments.getString("inline_query"); startLoadFromMessageId = arguments.getInt("message_id", 0); int migrated_to = arguments.getInt("migrated_to", 0); scrollToTopOnResume = arguments.getBoolean("scrollToTopOnResume", false); + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + directShareReplies = plusPreferences.getBoolean("directShareReplies", false); + directShareToMenu = plusPreferences.getBoolean("directShareToMenu", false); + if (chatId != 0) { currentChat = MessagesController.getInstance().getChat(chatId); if (currentChat == null) { @@ -428,8 +469,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (ChatObject.isChannel(currentChat)) { if (!currentChat.megagroup) { - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); - channelMessagesImportant = preferences.getInt("important_" + dialog_id, 2); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + channelMessagesImportant = preferences.getInt("important_" + dialog_id, 2); + directShareReplies = false; //In channels reply doesn't make sense } else { channelMessagesImportant = 1; } @@ -459,6 +501,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } dialog_id = userId; botUser = arguments.getString("botUser"); + if (inlineQuery != null) { + MessagesController.getInstance().sendBotStart(currentUser, inlineQuery); + } } else if (encId != 0) { currentEncryptedChat = MessagesController.getInstance().getEncryptedChat(encId); if (currentEncryptedChat == null) { @@ -545,6 +590,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not NotificationCenter.getInstance().addObserver(this, NotificationCenter.chatSearchResultsAvailable); NotificationCenter.getInstance().addObserver(this, NotificationCenter.didUpdatedMessagesViews); NotificationCenter.getInstance().addObserver(this, NotificationCenter.chatInfoCantLoad); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.didLoadedPinnedMessage); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.peerSettingsDidLoaded); NotificationCenter.getInstance().addObserver(this, NotificationCenter.wallpaperChanged); @@ -555,7 +602,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } loading = true; - + MessagesController.getInstance().loadPeerSettings(dialog_id, currentUser, currentChat); + MessagesController.getInstance().setLastCreatedDialogId(dialog_id, true); if (startLoadFromMessageId != 0) { needSelectFromMessageId = true; waitingForLoad.add(lastLoadIndex); @@ -608,12 +656,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not NotificationCenter.getInstance().postNotificationName(NotificationCenter.openedChatChanged, dialog_id, false); } - typingDotsDrawable = new TypingDotsDrawable(); - typingDotsDrawable.setIsChat(currentChat != null); - recordStatusDrawable = new RecordStatusDrawable(); - recordStatusDrawable.setIsChat(currentChat != null); - sendingFileDrawable = new SendingFileExDrawable(); - sendingFileDrawable.setIsChat(currentChat != null); + //typingDotsDrawable = new TypingDotsDrawable(); + //typingDotsDrawable.setIsChat(currentChat != null); + //recordStatusDrawable = new RecordStatusDrawable(); + //recordStatusDrawable.setIsChat(currentChat != null); + //sendingFileDrawable = new SendingFileExDrawable(); + //sendingFileDrawable.setIsChat(currentChat != null); if (currentEncryptedChat != null && AndroidUtilities.getMyLayerVersion(currentEncryptedChat.layer) != SecretChatHelper.CURRENT_SECRET_CHAT_LAYER) { SecretChatHelper.getInstance().sendNotifyLayerMessage(currentEncryptedChat, null); @@ -628,6 +676,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatActivityEnterView != null) { chatActivityEnterView.onDestroy(); } + if (mentionsAdapter != null) { + mentionsAdapter.onDestroy(); + } + MessagesController.getInstance().setLastCreatedDialogId(dialog_id, false); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messagesDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.emojiDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.updateInterfaces); @@ -663,6 +715,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioPlayStateChanged); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didUpdatedMessagesViews); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.chatInfoCantLoad); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didLoadedPinnedMessage); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.peerSettingsDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.wallpaperChanged); @@ -671,6 +725,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (currentEncryptedChat != null) { MediaController.getInstance().stopMediaObserver(); + try { + if (Build.VERSION.SDK_INT >= 14) { + getParentActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SECURE); + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } } if (currentUser != null) { MessagesController.getInstance().cancelLoadFullUser(currentUser.id); @@ -683,10 +744,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatAttachView.onDestroy(); } AndroidUtilities.unlockOrientation(getParentActivity()); - MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); + /*MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); if (messageObject != null && !messageObject.isMusic()) { MediaController.getInstance().stopAudio(); - } + }*/ if (ChatObject.isChannel(currentChat)) { MessagesController.getInstance().startShortPoll(currentChat.id, true); } @@ -700,32 +761,30 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatMessageCellsCache.add(new ChatMessageCell(context)); } } - if (chatMediaCellsCache.isEmpty()) { - for (int a = 0; a < 4; a++) { - chatMediaCellsCache.add(new ChatMediaCell(context)); - } - } for (int a = 1; a >= 0; a--) { selectedMessagesIds[a].clear(); selectedMessagesCanCopyIds[a].clear(); } cantDeleteMessagesCount = 0; - lastPrintString = null; - lastStatus = null; - hasOwnBackground = true; - chatAttachView = null; + lastPrintString = null; + lastStatus = null; + hasOwnBackground = true; + if (chatAttachView != null){ + chatAttachView.onDestroy(); + chatAttachView = null; + } chatAttachViewSheet = null; - ResourceLoader.loadRecources(context); + Theme.loadResources(context); - //actionBar.setBackButtonDrawable(new BackDrawable(false)); - SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + //actionBar.setBackButtonDrawable(new BackDrawable(false)); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); int tColor = themePrefs.getInt("chatsHeaderTitleColor", 0xffffffff); - Drawable d = new BackDrawable(false); - ((BackDrawable) d).setColor(themePrefs.getInt("chatHeaderIconsColor", 0xffffffff)); - actionBar.setBackButtonDrawable(d); - actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + Drawable d = new BackDrawable(false); + ((BackDrawable) d).setColor(themePrefs.getInt("chatHeaderIconsColor", 0xffffffff)); + actionBar.setBackButtonDrawable(d); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(final int id) { if (id == -1) { @@ -735,7 +794,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not selectedMessagesCanCopyIds[a].clear(); } cantDeleteMessagesCount = 0; + chatActivityEnterView.setEditinigMessageObject(null, false); actionBar.hideActionMode(); + updatePinnedMessageView(true); updateVisibleRows(); } else { finishFragment(); @@ -755,8 +816,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (str.length() != 0) { str += "\n"; } - if (messageObject.messageOwner.message != null) { + if (messageObject.type == 0 && messageObject.messageOwner.message != null) { str += messageObject.messageOwner.message; + } else if (messageObject.messageOwner.media != null && messageObject.messageOwner.media.caption != null) { + str += messageObject.messageOwner.media.caption; } else { str += messageObject.messageText; } @@ -782,43 +845,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } cantDeleteMessagesCount = 0; actionBar.hideActionMode(); + updatePinnedMessageView(true); updateVisibleRows(); + } else if (id == edit_done) { + if (chatActivityEnterView != null && (chatActivityEnterView.isEditingCaption() || chatActivityEnterView.hasText())) { + chatActivityEnterView.doneEditingMessage(); + actionBar.hideActionMode(); + updatePinnedMessageView(true); + } } else if (id == delete) { if (getParentActivity() == null) { return; } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.formatString("AreYouSureDeleteMessages", R.string.AreYouSureDeleteMessages, LocaleController.formatPluralString("messages", selectedMessagesIds[0].size() + selectedMessagesIds[1].size()))); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - for (int a = 1; a >= 0; a--) { - ArrayList ids = new ArrayList<>(selectedMessagesIds[a].keySet()); - ArrayList random_ids = null; - int channelId = 0; - if (!ids.isEmpty()) { - MessageObject msg = selectedMessagesIds[a].get(ids.get(0)); - if (channelId == 0 && msg.messageOwner.to_id.channel_id != 0) { - channelId = msg.messageOwner.to_id.channel_id; - } - } - if (currentEncryptedChat != null) { - random_ids = new ArrayList<>(); - for (HashMap.Entry entry : selectedMessagesIds[a].entrySet()) { - MessageObject msg = entry.getValue(); - if (msg.messageOwner.random_id != 0 && msg.type != 10) { - random_ids.add(msg.messageOwner.random_id); - } - } - } - MessagesController.getInstance().deleteMessages(ids, random_ids, currentEncryptedChat, channelId); - } - actionBar.hideActionMode(); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); + createDeleteMessagesAlert(null); } else if (id == forward || id == quoteforward) { if (id == quoteforward) { QuoteForward = true; @@ -873,7 +912,66 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); - } else if (id == share_contact) { + } //plus + else if (id == leave_group) { + if (getParentActivity() == null) { + return; + } + final boolean isChat = (int) dialog_id < 0 && (int) (dialog_id >> 32) != 1; + if(!isChat){ + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("LeaveWithoutDeleteMsg", R.string.LeaveWithoutDeleteMsg)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + //MessagesController.getInstance().deleteUserFromChat((int) -dialog_id, MessagesController.getInstance().getUser(UserConfig.getClientUserId()), null, false); + TLRPC.User user = MessagesController.getInstance().getUser(UserConfig.getClientUserId()); + //chat_id = (int) -dialog_id; + if (user == null) { + return; + } + if (chat_id > 0) { + TLObject request; + TLRPC.TL_messages_deleteChatUser req = new TLRPC.TL_messages_deleteChatUser(); + req.chat_id = chat_id; + req.user_id = MessagesController.getInputUser(user); + request = req; + ConnectionsManager.getInstance().sendRequest(request, new RequestDelegate() { + @Override + public void run(TLObject response, final TLRPC.TL_error error) { + if(response != null){ + //Log.e("LeaveWithoutDeleteMsg","response "+ response.toString()); + //Toast.makeText(getParentActivity(), response.toString(), Toast.LENGTH_SHORT).show(); + } + if (error != null) { + //Log.e("LeaveWithoutDeleteMsg","error "+ error.text); + //Toast.makeText(getParentActivity(), error.text, Toast.LENGTH_SHORT).show(); + return; + } + final TLRPC.Updates updates = (TLRPC.Updates) response; + MessagesController.getInstance().processUpdates(updates, false); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try{ + finishFragment(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + }, ConnectionsManager.RequestFlagInvokeAfter); + } + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + }// + else if (id == share_contact) { if (currentUser == null || getParentActivity() == null) { return; } @@ -883,22 +981,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not args.putBoolean("addContact", true); presentFragment(new ContactAddActivity(args)); } else { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.getString("AreYouSureShareMyContactInfo", R.string.AreYouSureShareMyContactInfo)); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - SendMessagesHelper.getInstance().sendMessage(UserConfig.getCurrentUser(), dialog_id, replyingMessageObject, chatActivityEnterView == null || chatActivityEnterView.asAdmin()); - moveScrollToLastMessage(); - showReplyPanel(false, null, null, null, false, true); - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); + shareMyContact(replyingMessageObject); } } else if (id == mute) { toggleMute(false); + } else if (id == report) { + showDialog(AlertsCreator.createReportAlert(getParentActivity(), dialog_id, ChatActivity.this)); } else if (id == reply) { MessageObject messageObject = null; for (int a = 1; a >= 0; a--) { @@ -909,104 +997,31 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not selectedMessagesIds[a].clear(); selectedMessagesCanCopyIds[a].clear(); } - if (messageObject != null && messageObject.messageOwner.id > 0) { + if (messageObject != null && (messageObject.messageOwner.id > 0 || messageObject.messageOwner.id < 0 && currentEncryptedChat != null)) { showReplyPanel(true, messageObject, null, null, false, true); } cantDeleteMessagesCount = 0; actionBar.hideActionMode(); + updatePinnedMessageView(true); updateVisibleRows(); } else if (id == chat_menu_attach) { if (getParentActivity() == null) { return; } - if (chatAttachView == null) { - BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); - chatAttachView = new ChatAttachView(getParentActivity()); - chatAttachView.setDelegate(new ChatAttachView.ChatAttachViewDelegate() { - @Override - public void didPressedButton(int button) { - if (button == 7) { - chatAttachViewSheet.dismiss(); - HashMap selectedPhotos = chatAttachView.getSelectedPhotos(); - if (!selectedPhotos.isEmpty()) { - ArrayList photos = new ArrayList<>(); - ArrayList captions = new ArrayList<>(); - for (HashMap.Entry entry : selectedPhotos.entrySet()) { - MediaController.PhotoEntry photoEntry = entry.getValue(); - if (photoEntry.imagePath != null) { - photos.add(photoEntry.imagePath); - captions.add(photoEntry.caption != null ? photoEntry.caption.toString() : null); - } else if (photoEntry.path != null) { - photos.add(photoEntry.path); - captions.add(photoEntry.caption != null ? photoEntry.caption.toString() : null); - } - photoEntry.imagePath = null; - photoEntry.thumbPath = null; - photoEntry.caption = null; - } - SendMessagesHelper.prepareSendingPhotos(photos, null, dialog_id, replyingMessageObject, captions, chatActivityEnterView == null || chatActivityEnterView.asAdmin()); - showReplyPanel(false, null, null, null, false, true); - } - return; - } else { - if (chatAttachViewSheet != null) { - chatAttachViewSheet.dismissWithButtonClick(button); - } - } - processSelectedAttach(button); - } - }); - builder.setDelegate(new BottomSheet.BottomSheetDelegate() { - - @Override - public void onRevealAnimationStart(boolean open) { - if (chatAttachView != null) { - chatAttachView.onRevealAnimationStart(open); - } - } - - @Override - public void onRevealAnimationProgress(boolean open, float radius, int x, int y) { - if (chatAttachView != null) { - chatAttachView.onRevealAnimationProgress(open, radius, x, y); - } - } - - @Override - public void onRevealAnimationEnd(boolean open) { - if (chatAttachView != null) { - chatAttachView.onRevealAnimationEnd(open); - } - } - - @Override - public void onOpenAnimationEnd() { - if (chatAttachView != null) { - chatAttachView.onRevealAnimationEnd(true); - } - } - - @Override - public View getRevealView() { - return menuItem; - } - }); - builder.setApplyTopPaddings(false); - builder.setUseRevealAnimation(); - builder.setCustomView(chatAttachView); - chatAttachViewSheet = builder.create(); - } + createChatAttachView(); + chatAttachView.loadGalleryPhotos(); if (Build.VERSION.SDK_INT == 21 || Build.VERSION.SDK_INT == 22) { chatActivityEnterView.closeKeyboard(); } chatAttachView.init(ChatActivity.this); - showDialog(chatAttachViewSheet); + showDialog(chatAttachViewSheet); + } else if (id == bot_help) { - SendMessagesHelper.getInstance().sendMessage("/help", dialog_id, null, null, false, chatActivityEnterView == null || chatActivityEnterView.asAdmin(), null, null); + SendMessagesHelper.getInstance().sendMessage("/help", dialog_id, null, null, false, chatActivityEnterView == null || chatActivityEnterView.asAdmin(), null, null, null); } else if (id == bot_settings) { - SendMessagesHelper.getInstance().sendMessage("/settings", dialog_id, null, null, false, chatActivityEnterView == null || chatActivityEnterView.asAdmin(), null, null); + SendMessagesHelper.getInstance().sendMessage("/settings", dialog_id, null, null, false, chatActivityEnterView == null || chatActivityEnterView.asAdmin(), null, null, null); } else if (id == search) { openSearchWithText(null); } else if (id == search_up) { @@ -1028,35 +1043,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); - avatarContainer = new FrameLayoutFixed(context); - avatarContainer.setBackgroundResource(R.drawable.bar_selector); - avatarContainer.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + avatarContainer = new ChatAvatarContainer(context, this, ChatObject.isChannel(currentChat) && !currentChat.megagroup && !(currentChat instanceof TLRPC.TL_channelForbidden), currentEncryptedChat != null); + avatarContainer.setRadioChecked(channelMessagesImportant == 1, false); actionBar.addView(avatarContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 56, 0, 40, 0)); - avatarContainer.setOnClickListener(new View.OnClickListener() { + avatarContainer.setDelegate(new ChatAvatarContainer.ChatAvatarContainerDelegate() { @Override - public void onClick(View v) { - if (radioButton == null || radioButton.getVisibility() != View.VISIBLE) { - if (currentUser != null) { - Bundle args = new Bundle(); - args.putInt("user_id", currentUser.id); - if (currentEncryptedChat != null) { - args.putLong("dialog_id", dialog_id); - } - ProfileActivity fragment = new ProfileActivity(args); - fragment.setPlayProfileAnimation(true); - presentFragment(fragment); - } else if (currentChat != null) { - Bundle args = new Bundle(); - args.putInt("chat_id", currentChat.id); - ProfileActivity fragment = new ProfileActivity(args); - fragment.setChatInfo(info); - fragment.setPlayProfileAnimation(true); - presentFragment(fragment); - } - } else { + public void didPressedRadioButton() { switchImportantMode(null); } - } }); if (currentChat != null) { @@ -1071,58 +1065,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - avatarImageView = new BackupImageView(context); - avatarImageView.setRoundRadius(AndroidUtilities.dp(21)); - avatarContainer.addView(avatarImageView, LayoutHelper.createFrame(42, 42, Gravity.TOP | Gravity.LEFT, 0, 3, 0, 0)); - - if (currentEncryptedChat != null) { - timeItem = new ImageView(context); - timeItem.setPadding(AndroidUtilities.dp(10), AndroidUtilities.dp(10), AndroidUtilities.dp(5), AndroidUtilities.dp(5)); - timeItem.setScaleType(ImageView.ScaleType.CENTER); - timeItem.setImageDrawable(timerDrawable = new TimerDrawable(context)); - avatarContainer.addView(timeItem, LayoutHelper.createFrame(34, 34, Gravity.TOP | Gravity.LEFT, 16, 18, 0, 0)); - timeItem.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - if (getParentActivity() == null) { - return; - } - showDialog(AndroidUtilities.buildTTLAlert(getParentActivity(), currentEncryptedChat).create()); - } - }); - } - - nameTextView = new TextView(context); - nameTextView.setTextColor(0xffffffff); - nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); - nameTextView.setLines(1); - nameTextView.setMaxLines(1); - nameTextView.setSingleLine(true); - nameTextView.setEllipsize(TextUtils.TruncateAt.END); - nameTextView.setGravity(Gravity.LEFT); - nameTextView.setCompoundDrawablePadding(AndroidUtilities.dp(4)); - nameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - avatarContainer.addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 54, 0, 0, 22)); - - onlineTextView = new TextView(context); - onlineTextView.setTextColor(0xffd7e8f7); - onlineTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - onlineTextView.setLines(1); - onlineTextView.setMaxLines(1); - onlineTextView.setSingleLine(true); - onlineTextView.setEllipsize(TextUtils.TruncateAt.END); - onlineTextView.setGravity(Gravity.LEFT); - - if (ChatObject.isChannel(currentChat) && !currentChat.megagroup && !(currentChat instanceof TLRPC.TL_channelForbidden)) { - radioButton = new RadioButton(context); - radioButton.setChecked(channelMessagesImportant == 1, false); - radioButton.setVisibility(View.GONE); - avatarContainer.addView(radioButton, LayoutHelper.createFrame(24, 24, Gravity.LEFT | Gravity.BOTTOM, 50, 0, 0, 0)); - avatarContainer.addView(onlineTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 54, 0, 0, 4)); - } else { - avatarContainer.addView(onlineTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 54, 0, 0, 4)); - } - ActionBarMenu menu = actionBar.createMenu(); if (currentEncryptedChat == null && !isBroadcast) { @@ -1168,7 +1110,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not searchItem.getSearchField().requestFocus(); AndroidUtilities.showKeyboard(searchItem.getSearchField()); } - }, 300); //TODO find a better way to open keyboard + }, 300); } @Override @@ -1220,6 +1162,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } catch (Exception e) { FileLog.e("tmessages", e); } + if (ChatObject.isChannel(currentChat) && !currentChat.creator && (!currentChat.megagroup || currentChat.username != null && currentChat.username.length() > 0)) { + headerItem.addSubItem(report, LocaleController.getString("ReportChat", R.string.ReportChat), 0); + } if (currentUser != null) { addContactItem = headerItem.addSubItem(share_contact, "", 0); } @@ -1230,6 +1175,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not headerItem.addSubItem(clear_history, LocaleController.getString("ClearHistory", R.string.ClearHistory), 0); if (currentChat != null && !isBroadcast) { headerItem.addSubItem(delete_chat, LocaleController.getString("DeleteAndExit", R.string.DeleteAndExit), 0); + headerItem.addSubItem(leave_group, LocaleController.getString("LeaveWithoutDelete", R.string.LeaveWithoutDelete), 0); } else { headerItem.addSubItem(delete_chat, LocaleController.getString("DeleteChatUser", R.string.DeleteChatUser), 0); } @@ -1242,7 +1188,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } updateTitle(); - updateSubtitle(); + avatarContainer.updateOnlineCount(); + avatarContainer.updateSubtitle(); updateTitleIcons(); //attachItem = menu.addItem(chat_menu_attach, R.drawable.ic_ab_other).setOverrideMenuClick(true).setAllowCloseAnimation(false); @@ -1262,7 +1209,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not selectedMessagesCountTextView = new NumberTextView(actionMode.getContext()); selectedMessagesCountTextView.setTextSize(18); selectedMessagesCountTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - selectedMessagesCountTextView.setTextColor(0xff737373); + selectedMessagesCountTextView.setTextColor(Theme.ACTION_BAR_ACTION_MODE_TEXT_COLOR); actionMode.addView(selectedMessagesCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 65, 0, 0, 0)); selectedMessagesCountTextView.setOnTouchListener(new View.OnTouchListener() { @Override @@ -1271,18 +1218,36 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); - if (currentEncryptedChat == null) { - if (!isBroadcast) { - actionModeViews.add(actionMode.addItem(reply, R.drawable.ic_ab_reply, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); - } - actionModeViews.add(actionMode.addItem(copy, R.drawable.ic_ab_fwd_copy, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); - actionModeViews.add(actionMode.addItem(quoteforward, R.drawable.ic_ab_fwd_quoteforward, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); - actionModeViews.add(actionMode.addItem(forward, R.drawable.ic_ab_fwd_forward, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); - actionModeViews.add(actionMode.addItem(delete, R.drawable.ic_ab_fwd_delete, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); - } else { - actionModeViews.add(actionMode.addItem(copy, R.drawable.ic_ab_fwd_copy, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); - actionModeViews.add(actionMode.addItem(delete, R.drawable.ic_ab_fwd_delete, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); + actionModeTextView = new TextView(actionMode.getContext()); + actionModeTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); + actionModeTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + actionModeTextView.setTextColor(Theme.ACTION_BAR_ACTION_MODE_TEXT_COLOR); + actionModeTextView.setVisibility(View.GONE); + actionModeTextView.setGravity(Gravity.CENTER_VERTICAL); + actionModeTextView.setText(LocaleController.getString("Edit", R.string.Edit)); + actionMode.addView(actionModeTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 65, 0, 0, 0)); + actionModeTextView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; } + }); + + if (currentEncryptedChat == null) { + if (!isBroadcast) { + actionModeViews.add(actionMode.addItem(reply, R.drawable.ic_ab_reply, Theme.ACTION_BAR_MODE_SELECTOR_COLOR, null, AndroidUtilities.dp(54))); + } + actionModeViews.add(actionMode.addItem(copy, R.drawable.ic_ab_fwd_copy, Theme.ACTION_BAR_MODE_SELECTOR_COLOR, null, AndroidUtilities.dp(54))); + actionModeViews.add(actionMode.addItem(quoteforward, R.drawable.ic_ab_fwd_quoteforward, Theme.ACTION_BAR_MODE_SELECTOR_COLOR, null, AndroidUtilities.dp(54))); + actionModeViews.add(actionMode.addItem(forward, R.drawable.ic_ab_fwd_forward, Theme.ACTION_BAR_MODE_SELECTOR_COLOR, null, AndroidUtilities.dp(54))); + actionModeViews.add(actionMode.addItem(delete, R.drawable.ic_ab_fwd_delete, Theme.ACTION_BAR_MODE_SELECTOR_COLOR, null, AndroidUtilities.dp(54))); + actionModeViews.add(actionMode.addItem(edit_done, R.drawable.check_blue, Theme.ACTION_BAR_MODE_SELECTOR_COLOR, null, AndroidUtilities.dp(54))); + actionMode.getItem(edit_done).setVisibility(View.GONE); + } else { + actionModeViews.add(actionMode.addItem(reply, R.drawable.ic_ab_reply, Theme.ACTION_BAR_MODE_SELECTOR_COLOR, null, AndroidUtilities.dp(54))); + actionModeViews.add(actionMode.addItem(copy, R.drawable.ic_ab_fwd_copy, Theme.ACTION_BAR_MODE_SELECTOR_COLOR, null, AndroidUtilities.dp(54))); + actionModeViews.add(actionMode.addItem(delete, R.drawable.ic_ab_fwd_delete, Theme.ACTION_BAR_MODE_SELECTOR_COLOR, null, AndroidUtilities.dp(54))); + } actionMode.getItem(copy).setVisibility(selectedMessagesCanCopyIds[0].size() + selectedMessagesCanCopyIds[1].size() != 0 ? View.VISIBLE : View.GONE); actionMode.getItem(delete).setVisibility(cantDeleteMessagesCount == 0 ? View.VISIBLE : View.GONE); checkActionBarMenu(); @@ -1326,6 +1291,58 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not child.measure(contentWidthSpec, contentHeightSpec); } else if (chatActivityEnterView.isPopupView(child)) { child.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(child.getLayoutParams().height, MeasureSpec.EXACTLY)); + } else if (child == mentionContainer) { + int orientation = mentionsAdapter.getOrientation(); + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mentionContainer.getLayoutParams(); + int height; + mentionListViewIgnoreLayout = true; + if (mentionsAdapter.isBotContext()) { + if (orientation == LinearLayoutManager.HORIZONTAL) { + height = AndroidUtilities.dp(90); + if (botSwitchCell.getVisibility() == VISIBLE) { + height += AndroidUtilities.dp(36); + mentionListView.setPadding(0, AndroidUtilities.dp(2 + 36), AndroidUtilities.dp(5), 0); + } else { + mentionListView.setPadding(0, AndroidUtilities.dp(2), AndroidUtilities.dp(5), 0); + } + } else { + int size = mentionsAdapter.getItemCount(); + int maxHeight = 0; + if (mentionsAdapter.getBotContextSwitch() != null) { + maxHeight += 36; + size -= 1; + } + maxHeight += size * 68; + + height = heightSize - chatActivityEnterView.getMeasuredHeight() + (maxHeight != 0 ? AndroidUtilities.dp(2) : 0); + mentionListView.setPadding(0, Math.max(0, height - AndroidUtilities.dp(Math.min(maxHeight, 68 * 1.8f))), 0, 0); + } + layoutParams.height = height; + layoutParams.topMargin = 0; + } else { + if (orientation == LinearLayoutManager.HORIZONTAL) { + mentionListView.setPadding(0, AndroidUtilities.dp(2), AndroidUtilities.dp(5), 0); + height = 90; + } else { + mentionListView.setPadding(0, AndroidUtilities.dp(2), 0, 0); + if (mentionsAdapter.isBotContext()) { + height = 36 * 3 + 18; + } else { + height = 36 * Math.min(3, mentionsAdapter.getItemCount()) + (mentionsAdapter.getItemCount() > 3 ? 18 : 0); + //plus + try{ + int y = AndroidUtilities.displaySize.y / heightSize >= 1 ? AndroidUtilities.displaySize.y / heightSize : 1; + height = 36 * Math.min(10/y, mentionsAdapter.getItemCount());//puede haber java.lang.ArithmeticException: divide by zero + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + layoutParams.height = AndroidUtilities.dp(height + (height != 0 ? 2 : 0)); + layoutParams.topMargin = -AndroidUtilities.dp(height); + } + mentionListViewIgnoreLayout = false; + child.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY)); } else { measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); } @@ -1389,7 +1406,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not childTop = lp.topMargin; } - if (child == mentionListView) { + if (child == mentionContainer) { childTop -= chatActivityEnterView.getMeasuredHeight() - AndroidUtilities.dp(2); } else if (child == pagedownButton) { childTop -= chatActivityEnterView.getMeasuredHeight(); @@ -1403,6 +1420,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not child.layout(childLeft, childTop, childLeft + width, childTop + height); } + updateMessagesVisisblePart(); notifyHeightChanged(); } }; @@ -1420,9 +1438,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); - Drawable dSystem = context.getResources().getDrawable(R.drawable.system_white); - dSystem.setColorFilter(themePrefs.getInt("chatDateBubbleColor", 0x59000000), PorterDuff.Mode.SRC_IN); + //Drawable dSystem = context.getResources().getDrawable(R.drawable.system); + //dSystem.setColorFilter(themePrefs.getInt("chatDateBubbleColor", 0x59000000), PorterDuff.Mode.SRC_IN); int dColor = themePrefs.getInt("chatDateColor", 0xffffffff); + int dBColor = themePrefs.getInt("chatDateBubbleColor", 0x59000000); if (currentEncryptedChat == null) { TextView emptyView = new TextView(context); if (currentUser != null && currentUser.id != 777000 && currentUser.id != 429000 && (currentUser.id / 1000 == 333 || currentUser.id % 1000 == 0)) { @@ -1430,25 +1449,29 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { emptyView.setText(LocaleController.getString("NoMessages", R.string.NoMessages)); } - emptyView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + emptyView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); emptyView.setGravity(Gravity.CENTER); - //emptyView.setTextColor(0xffffffff); + //emptyView.setTextColor(Theme.CHAT_EMPTY_VIEW_TEXT_COLOR); emptyView.setTextColor(dColor); - //emptyView.setBackgroundResource(ApplicationLoader.isCustomTheme() ? R.drawable.system_black : R.drawable.system_blue); - emptyView.setBackgroundDrawable(dSystem); - emptyView.setPadding(AndroidUtilities.dp(7), AndroidUtilities.dp(1), AndroidUtilities.dp(7), AndroidUtilities.dp(1)); + emptyView.setBackgroundResource(R.drawable.system); + //emptyView.setBackgroundDrawable(dSystem); + emptyView.getBackground().setColorFilter(dBColor, PorterDuff.Mode.SRC_IN); + emptyView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + emptyView.setPadding(AndroidUtilities.dp(10), AndroidUtilities.dp(2), AndroidUtilities.dp(10), AndroidUtilities.dp(3)); emptyViewContainer.addView(emptyView, new FrameLayout.LayoutParams(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); } else { LinearLayout secretChatPlaceholder = new LinearLayout(context); - //secretChatPlaceholder.setBackgroundResource(ApplicationLoader.isCustomTheme() ? R.drawable.system_black : R.drawable.system_blue); - secretChatPlaceholder.setBackgroundDrawable(dSystem); + secretChatPlaceholder.setBackgroundResource(R.drawable.system); + //secretChatPlaceholder.setBackgroundDrawable(dSystem); + //secretChatPlaceholder.getBackground().setColorFilter(Theme.colorFilter); + secretChatPlaceholder.getBackground().setColorFilter(dBColor, PorterDuff.Mode.SRC_IN); secretChatPlaceholder.setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(12), AndroidUtilities.dp(16), AndroidUtilities.dp(12)); secretChatPlaceholder.setOrientation(LinearLayout.VERTICAL); emptyViewContainer.addView(secretChatPlaceholder, new FrameLayout.LayoutParams(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); secretViewStatusTextView = new TextView(context); secretViewStatusTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - //secretViewStatusTextView.setTextColor(0xffffffff); + //secretViewStatusTextView.setTextColor(Theme.SECRET_CHAT_INFO_TEXT_COLOR); secretViewStatusTextView.setTextColor(dColor); secretViewStatusTextView.setGravity(Gravity.CENTER_HORIZONTAL); secretViewStatusTextView.setMaxWidth(AndroidUtilities.dp(210)); @@ -1462,7 +1485,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not TextView textView = new TextView(context); textView.setText(LocaleController.getString("EncryptedDescriptionTitle", R.string.EncryptedDescriptionTitle)); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - //textView.setTextColor(0xffffffff); + //textView.setTextColor(Theme.SECRET_CHAT_INFO_TEXT_COLOR); textView.setTextColor(dColor); textView.setGravity(Gravity.CENTER_HORIZONTAL); textView.setMaxWidth(AndroidUtilities.dp(260)); @@ -1478,7 +1501,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not textView = new TextView(context); textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); - //textView.setTextColor(0xffffffff); + //textView.setTextColor(Theme.SECRET_CHAT_INFO_TEXT_COLOR); textView.setTextColor(dColor); textView.setGravity(Gravity.CENTER_VERTICAL | (LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)); textView.setMaxWidth(AndroidUtilities.dp(260)); @@ -1511,6 +1534,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatActivityEnterView != null) { chatActivityEnterView.onDestroy(); } + if (mentionsAdapter != null) { + mentionsAdapter.onDestroy(); + } chatListView = new RecyclerListView(context) { @Override @@ -1532,6 +1558,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } }; + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + final int hColor = themePrefs.getInt("chatsHeaderColor", def); chatListView.setVerticalScrollBarEnabled(true); chatListView.setAdapter(chatAdapter = new ChatActivityAdapter(context)); chatListView.setClipToPadding(false); @@ -1558,7 +1586,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not highlightMessageId = Integer.MAX_VALUE; updateVisibleRows(); } - + Glow.setEdgeGlowColor(chatListView, hColor); if(newState == 0){ hideDateTv(); } @@ -1566,7 +1594,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - checkScrollForLoad(); + checkScrollForLoad(true); int firstVisibleItem = chatLayoutManager.findFirstVisibleItemPosition(); int visibleItemCount = firstVisibleItem == RecyclerView.NO_POSITION ? 0 : Math.abs(chatLayoutManager.findLastVisibleItemPosition() - firstVisibleItem) + 1; if (visibleItemCount > 0) { @@ -1635,6 +1663,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatListView.setOnInterceptTouchListener(new RecyclerListView.OnInterceptTouchListener() { @Override public boolean onInterceptTouchEvent(MotionEvent event) { + if (chatActivityEnterView != null && chatActivityEnterView.isEditingMessage()) { + return true; + } if (actionBar.isActionModeShowed()) { return false; } @@ -1649,10 +1680,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (top > y || bottom < y) { continue; } - if (!(view instanceof ChatMediaCell)) { + if (!(view instanceof ChatMessageCell)) { break; } - final ChatMediaCell cell = (ChatMediaCell) view; + final ChatMessageCell cell = (ChatMessageCell) view; final MessageObject messageObject = cell.getMessageObject(); if (messageObject == null || messageObject.isSending() || !messageObject.isSecretPhoto() || !cell.getPhotoImage().isInsideImage(x, y - top)) { break; @@ -1694,7 +1725,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not contentView.addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); View view = new View(context); - view.setBackgroundResource(ApplicationLoader.isCustomTheme() ? R.drawable.system_loader2 : R.drawable.system_loader1); + view.setBackgroundResource(R.drawable.system_loader); + view.getBackground().setColorFilter(Theme.colorFilter); progressView.addView(view, LayoutHelper.createFrame(36, 36, Gravity.CENTER)); ProgressBar progressBar = new ProgressBar(context); @@ -1707,13 +1739,87 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AndroidUtilities.setProgressBarAnimationDuration(progressBar, 1500); progressView.addView(progressBar, LayoutHelper.createFrame(32, 32, Gravity.CENTER)); + if (ChatObject.isChannel(currentChat)) { + int defColor = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + //int hColor = themePrefs.getInt("chatHeaderColor", defColor); + int nameColor = themePrefs.getInt("chatNameColor", 0xffffffff); + int statusColor = themePrefs.getInt("chatStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40)); + pinnedMessageView = new FrameLayoutFixed(context); + pinnedMessageView.setTag(1); + ViewProxy.setTranslationY(pinnedMessageView, -AndroidUtilities.dp(50)); + pinnedMessageView.clearAnimation(); + pinnedMessageView.setVisibility(View.GONE); + //pinnedMessageView.setBackgroundResource(R.drawable.blockpanel); + pinnedMessageView.setBackgroundColor(hColor); + contentView.addView(pinnedMessageView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 50, Gravity.TOP | Gravity.LEFT)); + pinnedMessageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + scrollToMessageId(info.pinned_msg_id, 0, true, 0); + } + }); + + View lineView = new View(context); + //lineView.setBackgroundColor(0xff6c9fd2); + lineView.setBackgroundColor(nameColor); + pinnedMessageView.addView(lineView, LayoutHelper.createFrame(2, 32, Gravity.LEFT | Gravity.TOP, 8, 8, 0, 0)); + + pinnedMessageNameTextView = new SimpleTextView(context); + pinnedMessageNameTextView.setTextSize(14); + //pinnedMessageNameTextView.setTextColor(Theme.PINNED_PANEL_NAME_TEXT_COLOR); + pinnedMessageNameTextView.setTextColor(nameColor); + pinnedMessageNameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + pinnedMessageView.addView(pinnedMessageNameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, AndroidUtilities.dp(18), Gravity.TOP | Gravity.LEFT, 18, 7.3f, 52, 0)); + + pinnedMessageTextView = new SimpleTextView(context); + pinnedMessageTextView.setTextSize(14); + //pinnedMessageTextView.setTextColor(Theme.PINNED_PANEL_MESSAGE_TEXT_COLOR); + pinnedMessageTextView.setTextColor(statusColor); + pinnedMessageView.addView(pinnedMessageTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, AndroidUtilities.dp(18), Gravity.TOP | Gravity.LEFT, 18, 25.3f, 52, 0)); + + ImageView closePinned = new ImageView(context); + closePinned.setImageResource(R.drawable.miniplayer_close); + closePinned.setColorFilter(nameColor, PorterDuff.Mode.SRC_IN); + closePinned.setScaleType(ImageView.ScaleType.CENTER); + pinnedMessageView.addView(closePinned, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.TOP)); + closePinned.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (getParentActivity() == null) { + return; + } + if (currentChat.creator || currentChat.editor) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("UnpinMessageAlert", R.string.UnpinMessageAlert)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + MessagesController.getInstance().pinChannelMessage(currentChat, 0, false); + } + }); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } else { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + preferences.edit().putInt("pin_" + dialog_id, info.pinned_msg_id).commit(); + updatePinnedMessageView(true); + } + } + }); + } + reportSpamView = new LinearLayout(context); + reportSpamView.setTag(1); + ViewProxy.setTranslationY(reportSpamView, -AndroidUtilities.dp(50)); + reportSpamView.clearAnimation(); reportSpamView.setVisibility(View.GONE); reportSpamView.setBackgroundResource(R.drawable.blockpanel); contentView.addView(reportSpamView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 50, Gravity.TOP | Gravity.LEFT)); addToContactsButton = new TextView(context); - addToContactsButton.setTextColor(0xff4a82b5); + addToContactsButton.setTextColor(Theme.CHAT_ADD_CONTACT_TEXT_COLOR); + addToContactsButton.setVisibility(View.GONE); addToContactsButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); addToContactsButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); addToContactsButton.setSingleLine(true); @@ -1733,26 +1839,32 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }); reportSpamContainer = new FrameLayout(context); - reportSpamView.addView(reportSpamContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0.5f, Gravity.LEFT | Gravity.TOP)); + reportSpamView.addView(reportSpamContainer, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 1.0f, Gravity.LEFT | Gravity.TOP, 0, 0, 0, AndroidUtilities.dp(1))); reportSpamButton = new TextView(context); - reportSpamButton.setTextColor(0xffcf5957); + reportSpamButton.setTextColor(Theme.CHAT_REPORT_SPAM_TEXT_COLOR); reportSpamButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); reportSpamButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); reportSpamButton.setSingleLine(true); reportSpamButton.setMaxLines(1); + if (currentChat != null) { + reportSpamButton.setText(LocaleController.getString("ReportSpamAndLeave", R.string.ReportSpamAndLeave)); + } else { reportSpamButton.setText(LocaleController.getString("ReportSpam", R.string.ReportSpam)); + } reportSpamButton.setGravity(Gravity.CENTER); - reportSpamButton.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(50), 0); + reportSpamButton.setPadding(AndroidUtilities.dp(50), 0, AndroidUtilities.dp(50), 0); reportSpamContainer.addView(reportSpamButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); reportSpamButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (reportSpamUser == null || getParentActivity() == null) { + if (getParentActivity() == null) { return; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - if (currentChat != null) { + if (ChatObject.isChannel(currentChat) && !currentChat.megagroup) { + builder.setMessage(LocaleController.getString("ReportSpamAlertChannel", R.string.ReportSpamAlertChannel)); + } else if (currentChat != null) { builder.setMessage(LocaleController.getString("ReportSpamAlertGroup", R.string.ReportSpamAlertGroup)); } else { builder.setMessage(LocaleController.getString("ReportSpamAlert", R.string.ReportSpamAlert)); @@ -1761,29 +1873,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - if (reportSpamUser == null) { - return; + if (currentUser != null) { + MessagesController.getInstance().blockUser(currentUser.id); } - TLRPC.TL_messages_reportSpam req = new TLRPC.TL_messages_reportSpam(); - req.peer = new TLRPC.TL_inputPeerUser(); - req.peer.user_id = reportSpamUser.id; - req.peer.access_hash = reportSpamUser.access_hash; - MessagesController.getInstance().blockUser(reportSpamUser.id); - ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - if (error == null) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); - preferences.edit().putBoolean("spam_" + dialog_id, true).commit(); - updateSpamView(); - } - }); - } + MessagesController.getInstance().reportSpam(dialog_id, currentUser, currentChat); + updateSpamView(); + if (currentChat != null) { + if (ChatObject.isNotInChat(currentChat)) { + MessagesController.getInstance().deleteDialog(dialog_id, 0); + } else { + MessagesController.getInstance().deleteUserFromChat((int) -dialog_id, MessagesController.getInstance().getUser(UserConfig.getClientUserId()), null); } - }, ConnectionsManager.RequestFlagFailOnServerErrors); + } else { + MessagesController.getInstance().deleteDialog(dialog_id, 0); + } + finishFragment(); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -1792,64 +1896,175 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }); ImageView closeReportSpam = new ImageView(context); - closeReportSpam.setImageResource(R.drawable.delete_reply); + closeReportSpam.setImageResource(R.drawable.miniplayer_close); closeReportSpam.setScaleType(ImageView.ScaleType.CENTER); reportSpamContainer.addView(closeReportSpam, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.TOP)); closeReportSpam.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); - preferences.edit().putBoolean("spam_" + dialog_id, true).commit(); + MessagesController.getInstance().hideReportSpam(dialog_id, currentUser, currentChat); updateSpamView(); } }); - if (currentEncryptedChat == null && !isBroadcast) { - mentionListView = new RecyclerListView(context); + alertView = new FrameLayoutFixed(context); + alertView.setTag(1); + ViewProxy.setTranslationY(alertView, -AndroidUtilities.dp(50)); + alertView.clearAnimation(); + alertView.setVisibility(View.GONE); + alertView.setBackgroundResource(R.drawable.blockpanel); + contentView.addView(alertView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 50, Gravity.TOP | Gravity.LEFT)); + + alertNameTextView = new TextView(context); + alertNameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + alertNameTextView.setTextColor(Theme.ALERT_PANEL_NAME_TEXT_COLOR); + alertNameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + alertNameTextView.setSingleLine(true); + alertNameTextView.setEllipsize(TextUtils.TruncateAt.END); + alertNameTextView.setMaxLines(1); + alertView.addView(alertNameTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 8, 5, 8, 0)); + + alertTextView = new TextView(context); + alertTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + alertTextView.setTextColor(Theme.ALERT_PANEL_MESSAGE_TEXT_COLOR); + alertTextView.setSingleLine(true); + alertTextView.setEllipsize(TextUtils.TruncateAt.END); + alertTextView.setMaxLines(1); + alertView.addView(alertTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 8, 23, 8, 0)); + + if (!isBroadcast) { + mentionContainer = new FrameLayoutFixed(context) { + + private Drawable background; + + @Override + public void onDraw(Canvas canvas) { + if (mentionsAdapter.isBotContext() && mentionsAdapter.getOrientation() == LinearLayoutManager.VERTICAL) { + background.setBounds(0, mentionListViewScrollOffsetY - AndroidUtilities.dp(2), getMeasuredWidth(), getMeasuredHeight()); + } else { + background.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); + } + background.draw(canvas); + } + + @Override + public void setBackgroundResource(int resid) { + background = getContext().getResources().getDrawable(resid); + } + + @Override + public void requestLayout() { + if (mentionListViewIgnoreLayout) { + return; + } + super.requestLayout(); + } + }; + mentionContainer.setBackgroundResource(R.drawable.compose_panel); + mentionContainer.setVisibility(View.GONE); + mentionContainer.setWillNotDraw(false); + contentView.addView(mentionContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 110, Gravity.LEFT | Gravity.BOTTOM)); + + mentionListView = new RecyclerListView(context) { + + private int lastWidth; + private int lastHeight; + + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + if (!mentionListViewIsScrolling && mentionListViewScrollOffsetY != 0 && event.getY() < mentionListViewScrollOffsetY && mentionsAdapter.isBotContext() && mentionsAdapter.getOrientation() == LinearLayoutManager.VERTICAL) { + return false; + } + boolean result = StickerPreviewViewer.getInstance().onInterceptTouchEvent(event, mentionListView, 0); + return super.onInterceptTouchEvent(event) || result; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (!mentionListViewIsScrolling && mentionListViewScrollOffsetY != 0 && event.getY() < mentionListViewScrollOffsetY && mentionsAdapter.isBotContext() && mentionsAdapter.getOrientation() == LinearLayoutManager.VERTICAL) { + return false; + } + //supress warning + return super.onTouchEvent(event); + } + + @Override + public void requestLayout() { + if (mentionListViewIgnoreLayout) { + return; + } + super.requestLayout(); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + int width = r - l; + int height = b - t; + + int newPosition = -1; + int newTop = 0; + if (mentionListView != null && mentionListViewLastViewPosition >= 0 && width == lastWidth && height - lastHeight != 0) { + newPosition = mentionListViewLastViewPosition; + newTop = mentionListViewLastViewTop + height - lastHeight - getPaddingTop(); + } + + super.onLayout(changed, l, t, r, b); + + if (newPosition != -1) { + mentionListViewIgnoreLayout = true; + mentionLayoutManager.scrollToPositionWithOffset(newPosition, newTop); + super.onLayout(false, l, t, r, b); + mentionListViewIgnoreLayout = false; + } + + lastHeight = height; + lastWidth = width; + mentionListViewUpdateLayout(); + } + }; + mentionListView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return StickerPreviewViewer.getInstance().onTouch(event, mentionListView, 0, mentionsOnItemClickListener); + } + }); mentionLayoutManager = new LinearLayoutManager(context) { @Override public boolean supportsPredictiveItemAnimations() { return false; } }; + mentionListView.setItemAnimator(null); + mentionListView.setLayoutAnimation(null); mentionLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); mentionListView.setLayoutManager(mentionLayoutManager); - - mentionListView.setBackgroundResource(R.drawable.compose_panel); - mentionListView.setVisibility(View.GONE); - mentionListView.setPadding(0, AndroidUtilities.dp(2), 0, 0); - mentionListView.setClipToPadding(true); - mentionListView.setDisallowInterceptTouchEvents(true); - if (Build.VERSION.SDK_INT > 8) { mentionListView.setOverScrollMode(ListView.OVER_SCROLL_NEVER); - } - contentView.addView(mentionListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 110, Gravity.LEFT | Gravity.BOTTOM)); + mentionContainer.addView(mentionListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); - mentionListView.setAdapter(mentionsAdapter = new MentionsAdapter(context, false, new MentionsAdapter.MentionsAdapterDelegate() { + mentionListView.setAdapter(mentionsAdapter = new MentionsAdapter(context, false, dialog_id, new MentionsAdapter.MentionsAdapterDelegate() { @Override public void needChangePanelVisibility(boolean show) { if (show) { int orientation = mentionsAdapter.getOrientation(); - - FrameLayout.LayoutParams layoutParams3 = (FrameLayout.LayoutParams) mentionListView.getLayoutParams(); - int height; if (orientation == LinearLayoutManager.HORIZONTAL) { - mentionListView.setPadding(0, AndroidUtilities.dp(2), AndroidUtilities.dp(5), 0); mentionListView.setClipToPadding(false); - height = 90; + mentionListView.setDisallowInterceptTouchEvents(true); } else { - mentionListView.setPadding(0, AndroidUtilities.dp(2), 0, 0); - mentionListView.setClipToPadding(true); - if (mentionsAdapter.isBotContext()) { - height = 36 * 3 + 18; - } else { - height = 36 * Math.min(3, mentionsAdapter.getItemCount()) + (mentionsAdapter.getItemCount() > 3 ? 18 : 0); - } + mentionListView.setClipToPadding(!mentionsAdapter.isBotContext()); + mentionListView.setDisallowInterceptTouchEvents(false); + } + if (mentionsAdapter.isBotContext() && orientation == LinearLayoutManager.HORIZONTAL && mentionsAdapter.getBotContextSwitch() != null) { + botSwitchShadow.setVisibility(View.VISIBLE); + botSwitchCell.setVisibility(View.VISIBLE); + botSwitchCell.setText(mentionsAdapter.getBotContextSwitch().text); + } else { + botSwitchShadow.setVisibility(View.GONE); + botSwitchCell.setVisibility(View.GONE); + } + if (!mentionsAdapter.isBotContext() || orientation == LinearLayoutManager.HORIZONTAL) { + mentionListViewScrollOffsetY = 0; + mentionListViewLastViewPosition = -1; } - layoutParams3.height = AndroidUtilities.dp(2 + height); - layoutParams3.topMargin = -AndroidUtilities.dp(height); - mentionListView.setLayoutParams(layoutParams3); - mentionLayoutManager.setOrientation(orientation); if (mentionListAnimation != null) { @@ -1857,56 +2072,42 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentionListAnimation = null; } - if (mentionListView.getVisibility() == View.VISIBLE) { - ViewProxy.setAlpha(mentionListView, 1.0f); + if (mentionContainer.getVisibility() == View.VISIBLE) { + ViewProxy.setAlpha(mentionContainer, 1.0f); return; } else { mentionLayoutManager.scrollToPositionWithOffset(0, 10000); } if (allowStickersPanel && (!mentionsAdapter.isBotContext() || (allowContextBotPanel || allowContextBotPanelSecond))) { - mentionListView.setVisibility(View.VISIBLE); - mentionListView.setTag(null); + if (currentEncryptedChat != null && mentionsAdapter.isBotContext()) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + if (!preferences.getBoolean("secretbot", false)) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("SecretChatContextBotAlert", R.string.SecretChatContextBotAlert)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); + preferences.edit().putBoolean("secretbot", true).commit(); + } + } + mentionContainer.setVisibility(View.VISIBLE); + mentionContainer.setTag(null); mentionListAnimation = new AnimatorSetProxy(); mentionListAnimation.playTogether( - ObjectAnimatorProxy.ofFloat(mentionListView, "alpha", 0.0f, 1.0f) + ObjectAnimatorProxy.ofFloat(mentionContainer, "alpha", 0.0f, 1.0f) ); mentionListAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Object animation) { if (mentionListAnimation != null && mentionListAnimation.equals(animation)) { - mentionListView.clearAnimation(); + mentionContainer.clearAnimation(); mentionListAnimation = null; } } - }); - mentionListAnimation.setDuration(200); - mentionListAnimation.start(); - } else { - ViewProxy.setAlpha(mentionListView, 1.0f); - mentionListView.clearAnimation(); - mentionListView.setVisibility(View.INVISIBLE); - } - } else { - if (mentionListAnimation != null) { - mentionListAnimation.cancel(); - mentionListAnimation = null; - } - if (mentionListView.getVisibility() == View.GONE) { - return; - } - if (allowStickersPanel) { - mentionListAnimation = new AnimatorSetProxy(); - mentionListAnimation.playTogether( - ObjectAnimatorProxy.ofFloat(mentionListView, "alpha", 0.0f) - ); - mentionListAnimation.addListener(new AnimatorListenerAdapterProxy() { - @Override - public void onAnimationEnd(Object animation) { - if (mentionListAnimation != null && mentionListAnimation.equals(animation)) { - mentionListView.clearAnimation(); - mentionListView.setVisibility(View.GONE); - mentionListView.setTag(null); + @Override + public void onAnimationCancel(Object animation) { + if (mentionListAnimation != null && mentionListAnimation.equals(animation)) { mentionListAnimation = null; } } @@ -1914,9 +2115,48 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not mentionListAnimation.setDuration(200); mentionListAnimation.start(); } else { - mentionListView.setTag(null); - mentionListView.clearAnimation(); - mentionListView.setVisibility(View.GONE); + ViewProxy.setAlpha(mentionContainer, 1.0f); + mentionContainer.clearAnimation(); + mentionContainer.setVisibility(View.INVISIBLE); + } + } else { + if (mentionListAnimation != null) { + mentionListAnimation.cancel(); + mentionListAnimation = null; + } + + if (mentionContainer.getVisibility() == View.GONE) { + return; + } + if (allowStickersPanel) { + mentionListAnimation = new AnimatorSetProxy(); + mentionListAnimation.playTogether( + ObjectAnimatorProxy.ofFloat(mentionContainer, "alpha", 0.0f) + ); + mentionListAnimation.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if (mentionListAnimation != null && mentionListAnimation.equals(animation)) { + mentionContainer.clearAnimation(); + mentionContainer.setVisibility(View.GONE); + mentionContainer.setTag(null); + mentionListAnimation = null; + } + } + + @Override + public void onAnimationCancel(Object animation) { + if (mentionListAnimation != null && mentionListAnimation.equals(animation)) { + mentionListAnimation = null; + } + } + }); + mentionListAnimation.setDuration(200); + mentionListAnimation.start(); + } else { + mentionContainer.setTag(null); + mentionContainer.clearAnimation(); + mentionContainer.setVisibility(View.GONE); } } } @@ -1936,27 +2176,23 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (result.type.equals("video") || result.type.equals("web_player_video")) { BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); - builder.setCustomView(new WebFrameLayout(getParentActivity(), builder.create(), result.title != null ? result.title : "", result.content_url, result.content_url, result.w, result.h)); + builder.setCustomView(new WebFrameLayout(getParentActivity(), builder.create(), result.title != null ? result.title : "", result.description, result.content_url, result.content_url, result.w, result.h)); builder.setUseFullWidth(true); showDialog(builder.create()); } else { - try { - Uri uri = Uri.parse(result.content_url); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, getParentActivity().getPackageName()); - getParentActivity().startActivity(intent); - } catch (Exception e) { - FileLog.e("tmessages", e); - } + Browser.openUrl(getParentActivity(), result.content_url); } } })); - mentionsAdapter.setBotInfo(botInfo); - mentionsAdapter.setChatInfo(info); - mentionsAdapter.setNeedUsernames(currentChat != null); - mentionsAdapter.setNeedBotContext(currentEncryptedChat == null); + if (!ChatObject.isChannel(currentChat) || currentChat != null && currentChat.megagroup) { + mentionsAdapter.setBotInfo(botInfo); + } + mentionsAdapter.setParentFragment(this); + mentionsAdapter.setChatInfo(info); + mentionsAdapter.setNeedUsernames(currentChat != null); + mentionsAdapter.setNeedBotContext(currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46); mentionsAdapter.setBotsCount(currentChat != null ? botsCount : 1); - mentionListView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { + mentionListView.setOnItemClickListener(mentionsOnItemClickListener = new RecyclerListView.OnItemClickListener() { @Override public void onItemClick(View view, int position) { Object object = mentionsAdapter.getItem(position); @@ -1969,7 +2205,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (object instanceof String) { if (mentionsAdapter.isBotCommands()) { - SendMessagesHelper.getInstance().sendMessage((String) object, dialog_id, null, null, false, chatActivityEnterView == null || chatActivityEnterView.asAdmin(), null, null); + SendMessagesHelper.getInstance().sendMessage((String) object, dialog_id, null, null, false, chatActivityEnterView == null || chatActivityEnterView.asAdmin(), null, null, null); chatActivityEnterView.setFieldText(""); } else { chatActivityEnterView.replaceWithText(start, len, object + " "); @@ -1984,10 +2220,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not params.put("id", result.id); params.put("query_id", "" + result.query_id); params.put("bot", "" + mentionsAdapter.getContextBotId()); + params.put("bot_name", mentionsAdapter.getContextBotName()); mentionsAdapter.addRecentBot(); SendMessagesHelper.prepareSendingBotContextResult(result, params, dialog_id, replyingMessageObject, chatActivityEnterView == null || chatActivityEnterView.asAdmin()); chatActivityEnterView.setFieldText(""); showReplyPanel(false, null, null, null, false, true); + } else if (object instanceof TLRPC.TL_inlineBotSwitchPM) { + processInlineBotContextPM((TLRPC.TL_inlineBotSwitchPM) object); } } }); @@ -2000,6 +2239,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } Object object = mentionsAdapter.getItem(position); if (object instanceof String) { + if (mentionsAdapter.isBotCommands()) { + if (URLSpanBotCommand.enabled) { + chatActivityEnterView.setFieldText(""); + chatActivityEnterView.setCommand(null, (String) object, true, currentChat != null && currentChat.megagroup); + return true; + } + return false; + } else { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setMessage(LocaleController.getString("ClearSearch", R.string.ClearSearch)); @@ -2013,20 +2260,45 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not showDialog(builder.create()); return true; } + } return false; } }); mentionListView.setOnScrollListener(new RecyclerView.OnScrollListener() { + + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + mentionListViewIsScrolling = newState == RecyclerView.SCROLL_STATE_DRAGGING; + } + @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { - int firstVisibleItem = mentionLayoutManager.findFirstVisibleItemPosition(); - int visibleItemCount = firstVisibleItem == RecyclerView.NO_POSITION ? 0 : firstVisibleItem; - if (visibleItemCount > 0 && firstVisibleItem > mentionsAdapter.getItemCount() - 5) { + int lastVisibleItem = mentionLayoutManager.findLastVisibleItemPosition(); + int visibleItemCount = lastVisibleItem == RecyclerView.NO_POSITION ? 0 : lastVisibleItem; + if (visibleItemCount > 0 && lastVisibleItem > mentionsAdapter.getItemCount() - 5) { mentionsAdapter.searchForContextBotForNextOffset(); } + + mentionListViewUpdateLayout(); } }); + + botSwitchCell = new BotSwitchCell(context); + botSwitchCell.setVisibility(View.GONE); + botSwitchCell.setBackgroundResource(R.drawable.list_selector); + mentionContainer.addView(botSwitchCell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.LEFT | Gravity.TOP, 0, 2, 0, 0)); + botSwitchCell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + processInlineBotContextPM(mentionsAdapter.getBotContextSwitch()); + } + }); + + botSwitchShadow = new View(context); + botSwitchShadow.setBackgroundResource(R.drawable.header_shadow); + botSwitchShadow.setVisibility(View.GONE); + mentionContainer.addView(botSwitchShadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 3, Gravity.LEFT | Gravity.TOP, 0, 38, 0, 0)); } pagedownButton = new ImageView(context); @@ -2037,18 +2309,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onClick(View view) { if (returnToMessageId > 0) { - scrollToMessageId(returnToMessageId, 0, true, 0); + scrollToMessageId(returnToMessageId, 0, true, returnToLoadIndex); } else { scrollToLastMessage(true); } } }); - chatActivityEnterView = new ChatActivityEnterView(getParentActivity(), contentView, this, true); - chatActivityEnterView.setDialogId(dialog_id); - chatActivityEnterView.addToAttachLayout(menuItem); - chatActivityEnterView.setId(id_chat_compose_panel); + chatActivityEnterView = new ChatActivityEnterView(getParentActivity(), contentView, this, true); + chatActivityEnterView.setDialogId(dialog_id); + chatActivityEnterView.addToAttachLayout(menuItem); + chatActivityEnterView.setId(id_chat_compose_panel); chatActivityEnterView.setBotsCount(botsCount, hasBotsCommands); + chatActivityEnterView.setAllowStickersAndGifs(currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 23, currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46); contentView.addView(chatActivityEnterView, contentView.getChildCount() - 1, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM)); chatActivityEnterView.setDelegate(new ChatActivityEnterView.ChatActivityEnterViewDelegate() { @Override @@ -2062,7 +2335,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onTextChanged(final CharSequence text, boolean bigChange) { - if (stickersAdapter != null) { + MediaController.getInstance().setInputFieldHasText(text != null && text.length() != 0 || chatActivityEnterView.isEditingMessage()); + if (stickersAdapter != null && !chatActivityEnterView.isEditingMessage()) { stickersAdapter.loadStikersForEmoji(text); } if (mentionsAdapter != null) { @@ -2072,7 +2346,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not AndroidUtilities.cancelRunOnUIThread(waitingForCharaterEnterRunnable); waitingForCharaterEnterRunnable = null; } - if (chatActivityEnterView.isMessageWebPageSearchEnabled()) { + if (chatActivityEnterView.isMessageWebPageSearchEnabled() && (!chatActivityEnterView.isEditingMessage() || !chatActivityEnterView.isEditingCaption())) { if (bigChange) { searchLinks(text, true); } else { @@ -2122,6 +2396,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } @Override + public void onMessageEditEnd() { + mentionsAdapter.setNeedBotContext(currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46); + chatListView.setOnItemLongClickListener(onItemLongClickListener); + chatListView.setOnItemClickListener(onItemClickListener); + chatListView.setClickable(true); + chatListView.setLongClickable(true); + actionModeTextView.setVisibility(View.GONE); + selectedMessagesCountTextView.setVisibility(View.VISIBLE); + chatActivityEnterView.setAllowStickersAndGifs(currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 23, currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46); + } + + @Override public void onWindowSizeChanged(int size) { if (size < AndroidUtilities.dp(72) + ActionBar.getCurrentActionBarHeight()) { allowStickersPanel = false; @@ -2129,9 +2415,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not stickersPanel.clearAnimation(); stickersPanel.setVisibility(View.INVISIBLE); } - if (mentionListView != null && mentionListView.getVisibility() == View.VISIBLE) { - mentionListView.clearAnimation(); - mentionListView.setVisibility(View.INVISIBLE); + if (mentionContainer != null && mentionContainer.getVisibility() == View.VISIBLE) { + mentionContainer.clearAnimation(); + mentionContainer.setVisibility(View.INVISIBLE); } } else { allowStickersPanel = true; @@ -2139,30 +2425,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not stickersPanel.clearAnimation(); stickersPanel.setVisibility(View.VISIBLE); } - if (mentionListView != null && mentionListView.getVisibility() == View.INVISIBLE && (!mentionsAdapter.isBotContext() || (allowContextBotPanel || allowContextBotPanelSecond))) { - mentionListView.clearAnimation(); - mentionListView.setVisibility(View.VISIBLE); - mentionListView.setTag(null); - } - //plus - if (mentionListView != null && !mentionsAdapter.isBotContext()) { - try{ - int y = AndroidUtilities.displaySize.y / size >= 1 ? AndroidUtilities.displaySize.y / size : 1; - int height = AndroidUtilities.dp(37 * Math.min(10/y, mentionsAdapter.getItemCount()));//puede haber java.lang.ArithmeticException: divide by zero - FrameLayout.LayoutParams layoutParams3 = (FrameLayout.LayoutParams) mentionListView.getLayoutParams(); - if(height != layoutParams3.height) { - layoutParams3.height = height; - layoutParams3.topMargin = -height; - mentionListView.setLayoutParams(layoutParams3); - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } + if (mentionContainer != null && mentionContainer.getVisibility() == View.INVISIBLE && (!mentionsAdapter.isBotContext() || (allowContextBotPanel || allowContextBotPanelSecond))) { + mentionContainer.clearAnimation(); + mentionContainer.setVisibility(View.VISIBLE); + mentionContainer.setTag(null); } } allowContextBotPanel = !chatActivityEnterView.isPopupShowing(); checkContextBotPanel(); - updateMessagesVisisblePart(); } @Override @@ -2186,33 +2456,32 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not replyLayout.addView(lineView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 1, Gravity.BOTTOM | Gravity.LEFT)); replyIconImageView = new ImageView(context); - replyIconImageView.setScaleType(ImageView.ScaleType.CENTER); + replyIconImageView.setScaleType(ImageView.ScaleType.CENTER); replyLayout.addView(replyIconImageView, LayoutHelper.createFrame(52, 46, Gravity.TOP | Gravity.LEFT)); - - deleteIconImageView = new ImageView(context); //ImageView imageView = new ImageView(context); - // imageView.setImageResource(R.drawable.delete_reply); - // imageView.setScaleType(ImageView.ScaleType.CENTER); - //replyLayout.addView(imageView, LayoutHelper.createFrame(52, 46, Gravity.RIGHT | Gravity.TOP, 0, 0.5f, 0, 0)); - //imageView.setOnClickListener(new View.OnClickListener() { + deleteIconImageView = new ImageView(context); + //imageView.setImageResource(R.drawable.delete_reply); deleteIconImageView.setImageResource(R.drawable.delete_reply); + //imageView.setScaleType(ImageView.ScaleType.CENTER); deleteIconImageView.setScaleType(ImageView.ScaleType.CENTER); + //replyLayout.addView(imageView, LayoutHelper.createFrame(52, 46, Gravity.RIGHT | Gravity.TOP, 0, 0.5f, 0, 0)); replyLayout.addView(deleteIconImageView, LayoutHelper.createFrame(52, 46, Gravity.RIGHT | Gravity.TOP, 0, 0.5f, 0, 0)); + //imageView.setOnClickListener(new View.OnClickListener() { deleteIconImageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (forwardingMessages != null) { forwardingMessages.clear(); } - v.setVisibility(View.INVISIBLE); + //v.setVisibility(View.INVISIBLE); showReplyPanel(false, null, null, foundWebPage, true, true); } }); replyNameTextView = new TextView(context); replyNameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - replyNameTextView.setTextColor(0xff377aae); + replyNameTextView.setTextColor(Theme.REPLY_PANEL_NAME_TEXT_COLOR); replyNameTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); replyNameTextView.setSingleLine(true); replyNameTextView.setEllipsize(TextUtils.TruncateAt.END); @@ -2221,7 +2490,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not replyObjectTextView = new TextView(context); replyObjectTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - replyObjectTextView.setTextColor(0xff999999); + replyObjectTextView.setTextColor(Theme.REPLY_PANEL_MESSAGE_TEXT_COLOR); replyObjectTextView.setSingleLine(true); replyObjectTextView.setEllipsize(TextUtils.TruncateAt.END); replyObjectTextView.setMaxLines(1); @@ -2234,7 +2503,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not stickersPanel.setVisibility(View.GONE); contentView.addView(stickersPanel, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 81.5f, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 38)); - stickersListView = new RecyclerListView(context); + stickersListView = new RecyclerListView(context) { + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + boolean result = StickerPreviewViewer.getInstance().onInterceptTouchEvent(event, stickersListView, 0); + return super.onInterceptTouchEvent(event) || result; + } + }; + stickersListView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return StickerPreviewViewer.getInstance().onTouch(event, stickersListView, 0, stickersOnItemClickListener); + } + }); stickersListView.setDisallowInterceptTouchEvents(true); LinearLayoutManager layoutManager = new LinearLayoutManager(context); layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); @@ -2244,86 +2525,31 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not stickersListView.setOverScrollMode(RecyclerListView.OVER_SCROLL_NEVER); } stickersPanel.addView(stickersListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 78)); - if (currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 23) { - chatActivityEnterView.setAllowStickersAndGifs(true, currentEncryptedChat == null); - if (stickersAdapter != null) { - stickersAdapter.onDestroy(); - } - stickersListView.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); - stickersListView.setAdapter(stickersAdapter = new StickersAdapter(context, new StickersAdapter.StickersAdapterDelegate() { - @Override - public void needChangePanelVisibility(final boolean show) { - if (show && stickersPanel.getVisibility() == View.VISIBLE || !show && stickersPanel.getVisibility() == View.GONE) { - return; - } - if (show) { - stickersListView.scrollToPosition(0); - stickersPanel.clearAnimation(); - stickersPanel.setVisibility(allowStickersPanel ? View.VISIBLE : View.INVISIBLE); - } - if (runningAnimation != null) { - runningAnimation.cancel(); - runningAnimation = null; - } - if (stickersPanel.getVisibility() != View.INVISIBLE) { - runningAnimation = new AnimatorSetProxy(); - runningAnimation.playTogether( - ObjectAnimatorProxy.ofFloat(stickersPanel, "alpha", show ? 0.0f : 1.0f, show ? 1.0f : 0.0f) - ); - runningAnimation.setDuration(150); - runningAnimation.addListener(new AnimatorListenerAdapterProxy() { - @Override - public void onAnimationEnd(Object animation) { - if (runningAnimation != null && runningAnimation.equals(animation)) { - if (!show) { - stickersAdapter.clearStickers(); - stickersPanel.clearAnimation(); - stickersPanel.setVisibility(View.GONE); - } - runningAnimation = null; - } - } - }); - runningAnimation.start(); - } else if (!show) { - stickersPanel.setVisibility(View.GONE); - } - } - })); - stickersListView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - TLRPC.Document document = stickersAdapter.getItem(position); - if (document instanceof TLRPC.TL_document) { - SendMessagesHelper.getInstance().sendSticker(document, dialog_id, replyingMessageObject, chatActivityEnterView == null || chatActivityEnterView.asAdmin()); - showReplyPanel(false, null, null, null, false, true); - } - chatActivityEnterView.setFieldText(""); - } - }); - } + initStickers(); ImageView imageView = new ImageView(context);//plus - imageView.setImageResource(R.drawable.stickers_back_arrow); + imageView.setImageResource(R.drawable.stickers_back_arrow); stickersPanel.addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT, 53, 0, 0, 0)); bottomOverlay = new FrameLayout(context); - bottomOverlay.setBackgroundColor(0xffffffff); bottomOverlay.setVisibility(View.INVISIBLE); bottomOverlay.setFocusable(true); bottomOverlay.setFocusableInTouchMode(true); bottomOverlay.setClickable(true); - contentView.addView(bottomOverlay, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM)); + bottomOverlay.setBackgroundResource(R.drawable.compose_panel); + bottomOverlay.setPadding(0, AndroidUtilities.dp(3), 0, 0); + contentView.addView(bottomOverlay, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 51, Gravity.BOTTOM)); bottomOverlayText = new TextView(context); bottomOverlayText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); - bottomOverlayText.setTextColor(0xff7f7f7f); + bottomOverlayText.setTextColor(Theme.CHAT_BOTTOM_OVERLAY_TEXT_COLOR); bottomOverlay.addView(bottomOverlayText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); bottomOverlayChat = new FrameLayout(context); - bottomOverlayChat.setBackgroundColor(0xfffbfcfd); + bottomOverlayChat.setBackgroundResource(R.drawable.compose_panel); + bottomOverlayChat.setPadding(0, AndroidUtilities.dp(3), 0, 0); bottomOverlayChat.setVisibility(View.INVISIBLE); - contentView.addView(bottomOverlayChat, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM)); + contentView.addView(bottomOverlayChat, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 51, Gravity.BOTTOM)); bottomOverlayChat.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -2339,7 +2565,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (botUserLast != null && botUserLast.length() != 0) { MessagesController.getInstance().sendBotStart(currentUser, botUserLast); } else { - SendMessagesHelper.getInstance().sendMessage("/start", dialog_id, null, null, false, chatActivityEnterView == null || chatActivityEnterView.asAdmin(), null, null); + SendMessagesHelper.getInstance().sendMessage("/start", dialog_id, null, null, false, chatActivityEnterView == null || chatActivityEnterView.asAdmin(), null, null, null); } } else { builder = new AlertDialog.Builder(getParentActivity()); @@ -2355,12 +2581,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (botUser.length() != 0) { MessagesController.getInstance().sendBotStart(currentUser, botUser); } else { - SendMessagesHelper.getInstance().sendMessage("/start", dialog_id, null, null, false, chatActivityEnterView == null || chatActivityEnterView.asAdmin(), null, null); + SendMessagesHelper.getInstance().sendMessage("/start", dialog_id, null, null, false, chatActivityEnterView == null || chatActivityEnterView.asAdmin(), null, null, null); } botUser = null; updateBottomOverlay(); } else { - if (ChatObject.isChannel(currentChat) && !currentChat.megagroup && !(currentChat instanceof TLRPC.TL_channelForbidden)) { + if (ChatObject.isChannel(currentChat) && !(currentChat instanceof TLRPC.TL_channelForbidden)) { if (ChatObject.isNotInChat(currentChat)) { MessagesController.getInstance().addUserToChat(currentChat.id, UserConfig.getCurrentUser(), null, 0, null, null); } else { @@ -2368,14 +2594,38 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else { builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.getString("AreYouSureDeleteThisChat", R.string.AreYouSureDeleteThisChat)); + /*builder.setMessage(LocaleController.getString("AreYouSureDeleteThisChat", R.string.AreYouSureDeleteThisChat)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { MessagesController.getInstance().deleteDialog(dialog_id, 0); finishFragment(); } - }); + });*/ + //plus + if (ChatObject.isLeftFromChat(currentChat)){ + builder.setMessage(LocaleController.getString("ReturnToThisGroupMsg", R.string.ReturnToThisGroupMsg)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (currentChat != null) { + MessagesController.getInstance().addUserToChat(currentChat.id, UserConfig.getCurrentUser(), null, 0, null, null); + updateBottomOverlay(); + //finishFragment(); + } + } + }); + } else{ + builder.setMessage(LocaleController.getString("AreYouSureDeleteThisChat", R.string.AreYouSureDeleteThisChat)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + MessagesController.getInstance().deleteDialog(dialog_id, 0); + finishFragment(); + } + }); + } + // } } if (builder != null) { @@ -2387,8 +2637,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }); bottomOverlayChatText = new TextView(context); - bottomOverlayChatText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); - bottomOverlayChatText.setTextColor(0xff3e6fa1); + bottomOverlayChatText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + bottomOverlayChatText.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + bottomOverlayChatText.setTextColor(Theme.CHAT_BOTTOM_CHAT_OVERLAY_TEXT_COLOR); bottomOverlayChat.addView(bottomOverlayChatText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); chatAdapter.updateRows(); @@ -2406,6 +2657,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not contentView.addView(playerView = new PlayerView(context, this), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 39, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); } + updateContactStatus(); + updateBottomOverlay(); + updateSecretStatus(); + updateSpamView(); + updatePinnedMessageView(true); + + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + showDateTv = plusPreferences.getBoolean("showDateToast", true); + dateTv = new TextView(context); dateTv.setVisibility(View.GONE); dateTv.setPadding(AndroidUtilities.dp(5), 0, AndroidUtilities.dp(5), 0); @@ -2417,16 +2677,252 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not dateTv.setTextColor(themePrefs.getInt("chatDateColor", 0xffffffff)); contentView.addView(dateTv, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER, 0, 2, 0, 0)); - updateContactStatus(); - updateBottomOverlay(); - updateSecretStatus(); - updateSpamView(); + try { + if (currentEncryptedChat != null && Build.VERSION.SDK_INT >= 23) { + getParentActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + fixLayoutInternal(); return fragmentView; } + private void mentionListViewUpdateLayout() { + if (mentionListView.getChildCount() <= 0 || !mentionsAdapter.isBotContext() || mentionsAdapter.getOrientation() != LinearLayoutManager.VERTICAL) { + mentionListViewScrollOffsetY = 0; + mentionListViewLastViewPosition = -1; + return; + } + View child = mentionListView.getChildAt(mentionListView.getChildCount() - 1); + MentionsAdapter.Holder holder = (MentionsAdapter.Holder) mentionListView.findContainingViewHolder(child); + if (holder != null) { + mentionListViewLastViewPosition = holder.getAdapterPosition(); + mentionListViewLastViewTop = child.getTop(); + } else { + mentionListViewLastViewPosition = -1; + } + + child = mentionListView.getChildAt(0); + holder = (MentionsAdapter.Holder) mentionListView.findContainingViewHolder(child); + int newOffset = child.getTop() > 0 && holder != null && holder.getAdapterPosition() == 0 ? child.getTop() : 0; + if (mentionListViewScrollOffsetY != newOffset) { + mentionListView.setTopGlowOffset(mentionListViewScrollOffsetY = newOffset); + mentionListView.invalidate(); + mentionContainer.invalidate(); + } + } + + public void processInlineBotContextPM(TLRPC.TL_inlineBotSwitchPM object) { + if (object == null) { + return; + } + TLRPC.User user = mentionsAdapter.getContextBotUser(); + if (user == null) { + return; + } + chatActivityEnterView.setFieldText(""); + if (dialog_id == user.id) { + inlineReturn = dialog_id; + MessagesController.getInstance().sendBotStart(currentUser, object.start_param); + } else { + Bundle args = new Bundle(); + args.putInt("user_id", user.id); + args.putString("inline_query", object.start_param); + args.putLong("inline_return", dialog_id); + if (!MessagesController.checkCanOpenChat(args, ChatActivity.this)) { + return; + } + presentFragment(new ChatActivity(args)); + } + } + + private void createChatAttachView() { + if (chatAttachView == null) { + BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); + chatAttachView = new ChatAttachView(getParentActivity()); + chatAttachView.setDelegate(new ChatAttachView.ChatAttachViewDelegate() { + @Override + public void didPressedButton(int button) { + if (button == 7) { + chatAttachViewSheet.dismiss(); + HashMap selectedPhotos = chatAttachView.getSelectedPhotos(); + if (!selectedPhotos.isEmpty()) { + ArrayList photos = new ArrayList<>(); + ArrayList captions = new ArrayList<>(); + for (HashMap.Entry entry : selectedPhotos.entrySet()) { + MediaController.PhotoEntry photoEntry = entry.getValue(); + if (photoEntry.imagePath != null) { + photos.add(photoEntry.imagePath); + captions.add(photoEntry.caption != null ? photoEntry.caption.toString() : null); + } else if (photoEntry.path != null) { + photos.add(photoEntry.path); + captions.add(photoEntry.caption != null ? photoEntry.caption.toString() : null); + } + photoEntry.imagePath = null; + photoEntry.thumbPath = null; + photoEntry.caption = null; + } + SendMessagesHelper.prepareSendingPhotos(photos, null, dialog_id, replyingMessageObject, captions, chatActivityEnterView == null || chatActivityEnterView.asAdmin()); + showReplyPanel(false, null, null, null, false, true); + } + return; + } else { + if (chatAttachViewSheet != null) { + chatAttachViewSheet.dismissWithButtonClick(button); + } + } + processSelectedAttach(button); + } + }); + builder.setDelegate(new BottomSheet.BottomSheetDelegate() { + + @Override + public void onRevealAnimationStart(boolean open) { + if (chatAttachView != null) { + chatAttachView.onRevealAnimationStart(open); + } + } + + @Override + public void onRevealAnimationProgress(boolean open, float radius, int x, int y) { + if (chatAttachView != null) { + chatAttachView.onRevealAnimationProgress(open, radius, x, y); + } + } + + @Override + public void onRevealAnimationEnd(boolean open) { + if (chatAttachView != null) { + chatAttachView.onRevealAnimationEnd(open); + } + } + + @Override + public void onOpenAnimationEnd() { + if (chatAttachView != null) { + chatAttachView.onRevealAnimationEnd(true); + } + } + + @Override + public View getRevealView() { + return menuItem; + } + }); + builder.setApplyTopPadding(false); + builder.setApplyBottomPadding(false); + builder.setUseRevealAnimation(); + builder.setCustomView(chatAttachView); + chatAttachViewSheet = builder.create(); + } + } + + public long getDialogId() { + return dialog_id; + } + + public void setBotUser(String value) { + if (inlineReturn != 0) { + MessagesController.getInstance().sendBotStart(currentUser, value); + } else { + botUser = value; + updateBottomOverlay(); + } + } + + public boolean playFirstUnreadVoiceMessage() { + for (int a = messages.size() - 1; a >= 0; a--) { + MessageObject messageObject = messages.get(a); + if (messageObject.isVoice() && messageObject.isContentUnread() && !messageObject.isOut() && messageObject.messageOwner.to_id.channel_id == 0) { + MediaController.getInstance().setVoiceMessagesPlaylist(MediaController.getInstance().playAudio(messageObject) ? createVoiceMessagesPlaylist(messageObject, true) : null, true); + return true; + } + } + if (Build.VERSION.SDK_INT >= 23 && getParentActivity() != null) { + if (getParentActivity().checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { + getParentActivity().requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 3); + return true; + } + } + return false; + } + + private void initStickers() { + if (chatActivityEnterView == null || getParentActivity() == null || stickersAdapter != null || currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 23) { + return; + } + if (stickersAdapter != null) { + stickersAdapter.onDestroy(); + } + stickersListView.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); + stickersListView.setAdapter(stickersAdapter = new StickersAdapter(getParentActivity(), new StickersAdapter.StickersAdapterDelegate() { + @Override + public void needChangePanelVisibility(final boolean show) { + if (show && stickersPanel.getVisibility() == View.VISIBLE || !show && stickersPanel.getVisibility() == View.GONE) { + return; + } + if (show) { + stickersListView.scrollToPosition(0); + stickersPanel.clearAnimation(); + stickersPanel.setVisibility(allowStickersPanel ? View.VISIBLE : View.INVISIBLE); + } + if (runningAnimation != null) { + runningAnimation.cancel(); + runningAnimation = null; + } + if (stickersPanel.getVisibility() != View.INVISIBLE) { + runningAnimation = new AnimatorSetProxy(); + runningAnimation.playTogether( + ObjectAnimatorProxy.ofFloat(stickersPanel, "alpha", show ? 0.0f : 1.0f, show ? 1.0f : 0.0f) + ); + runningAnimation.setDuration(150); + runningAnimation.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if (runningAnimation != null && runningAnimation.equals(animation)) { + if (!show) { + stickersAdapter.clearStickers(); + stickersPanel.clearAnimation(); + stickersPanel.setVisibility(View.GONE); + if (StickerPreviewViewer.getInstance().isVisible()) { + StickerPreviewViewer.getInstance().close(); + } + StickerPreviewViewer.getInstance().reset(); + } + runningAnimation = null; + } + } + + @Override + public void onAnimationCancel(Object animation) { + if (runningAnimation != null && runningAnimation.equals(animation)) { + runningAnimation = null; + } + } + }); + runningAnimation.start(); + } else if (!show) { + stickersPanel.setVisibility(View.GONE); + } + } + })); + stickersListView.setOnItemClickListener(stickersOnItemClickListener = new RecyclerListView.OnItemClickListener() { + @Override + public void onItemClick(View view, int position) { + TLRPC.Document document = stickersAdapter.getItem(position); + if (document instanceof TLRPC.TL_document) { + SendMessagesHelper.getInstance().sendSticker(document, dialog_id, replyingMessageObject, chatActivityEnterView == null || chatActivityEnterView.asAdmin()); + showReplyPanel(false, null, null, null, false, true); + } + chatActivityEnterView.setFieldText(""); + } + }); + } + private void updateDateToast(){ - if (chatListView == null) { + if (chatListView == null || !showDateTv) { return; } @@ -2453,6 +2949,30 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }, 1500); } + public void shareMyContact(final MessageObject messageObject) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("ShareYouPhoneNumberTitle", R.string.ShareYouPhoneNumberTitle)); + if (currentUser != null) { + if (currentUser.bot) { + builder.setMessage(LocaleController.getString("AreYouSureShareMyContactInfoBot", R.string.AreYouSureShareMyContactInfoBot)); + } else { + builder.setMessage(AndroidUtilities.replaceTags(LocaleController.formatString("AreYouSureShareMyContactInfoUser", R.string.AreYouSureShareMyContactInfoUser, PhoneFormat.getInstance().format("+" + UserConfig.getCurrentUser().phone), ContactsController.formatName(currentUser.first_name, currentUser.last_name)))); + } + } else { + builder.setMessage(LocaleController.getString("AreYouSureShareMyContactInfo", R.string.AreYouSureShareMyContactInfo)); + } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + SendMessagesHelper.getInstance().sendMessage(UserConfig.getCurrentUser(), dialog_id, messageObject, chatActivityEnterView == null || chatActivityEnterView.asAdmin(), null, null); + moveScrollToLastMessage(); + showReplyPanel(false, null, null, null, false, true); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } + private void showGifHint() { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); if (preferences.getBoolean("gifhint", false)) { @@ -2481,7 +3001,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not gifHintTextView = new TextView(getParentActivity()); gifHintTextView.setBackgroundResource(R.drawable.tooltip); - gifHintTextView.setTextColor(0xffffffff); + gifHintTextView.setTextColor(Theme.CHAT_GIF_HINT_TEXT_COLOR); gifHintTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); gifHintTextView.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0); gifHintTextView.setText(LocaleController.getString("TapHereGifs", R.string.TapHereGifs)); @@ -2528,47 +3048,59 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not private void checkContextBotPanel() { if (allowStickersPanel && mentionsAdapter != null && mentionsAdapter.isBotContext()) { if (!allowContextBotPanel && !allowContextBotPanelSecond) { - if (mentionListView.getVisibility() == View.VISIBLE && mentionListView.getTag() == null) { + if (mentionContainer.getVisibility() == View.VISIBLE && mentionContainer.getTag() == null) { if (mentionListAnimation != null) { mentionListAnimation.cancel(); - mentionListAnimation = null; } - mentionListView.setTag(1); + mentionContainer.setTag(1); mentionListAnimation = new AnimatorSetProxy(); mentionListAnimation.playTogether( - ObjectAnimatorProxy.ofFloat(mentionListView, "alpha", 0.0f) + ObjectAnimatorProxy.ofFloat(mentionContainer, "alpha", 0.0f) ); mentionListAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Object animation) { if (mentionListAnimation != null && mentionListAnimation.equals(animation)) { - mentionListView.clearAnimation(); - mentionListView.setVisibility(View.INVISIBLE); + mentionContainer.clearAnimation(); + mentionContainer.setVisibility(View.INVISIBLE); + mentionListAnimation = null; + } + } + + @Override + public void onAnimationCancel(Object animation) { + if (mentionListAnimation != null && mentionListAnimation.equals(animation)) { mentionListAnimation = null; } } }); mentionListAnimation.setDuration(200); mentionListAnimation.start(); - } + } } else { - if (mentionListView.getVisibility() == View.INVISIBLE || mentionListView.getTag() != null) { + if (mentionContainer.getVisibility() == View.INVISIBLE || mentionContainer.getTag() != null) { if (mentionListAnimation != null) { mentionListAnimation.cancel(); - mentionListAnimation = null; } - mentionListView.setTag(null); - mentionListView.setVisibility(View.VISIBLE); + mentionContainer.setTag(null); + mentionContainer.setVisibility(View.VISIBLE); mentionListAnimation = new AnimatorSetProxy(); mentionListAnimation.playTogether( - ObjectAnimatorProxy.ofFloat(mentionListView, "alpha", 0.0f, 1.0f) + ObjectAnimatorProxy.ofFloat(mentionContainer, "alpha", 0.0f, 1.0f) ); mentionListAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Object animation) { if (mentionListAnimation != null && mentionListAnimation.equals(animation)) { - mentionListView.clearAnimation(); + mentionContainer.clearAnimation(); + mentionListAnimation = null; + } + } + + @Override + public void onAnimationCancel(Object animation) { + if (mentionListAnimation != null && mentionListAnimation.equals(animation)) { mentionListAnimation = null; } } @@ -2578,7 +3110,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } - } + } private void openAddMember() { Bundle args = new Bundle(); @@ -2610,7 +3142,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not presentFragment(fragment); } - private void checkScrollForLoad() { + private void checkScrollForLoad(boolean scroll) { if (chatLayoutManager == null || paused) { return; } @@ -2618,7 +3150,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int visibleItemCount = firstVisibleItem == RecyclerView.NO_POSITION ? 0 : Math.abs(chatLayoutManager.findLastVisibleItemPosition() - firstVisibleItem) + 1; if (visibleItemCount > 0) { int totalItemCount = chatAdapter.getItemCount(); - if (firstVisibleItem <= 25 && !loading) { + int checkLoadCount; + if (scroll) { + checkLoadCount = 25; + } else { + checkLoadCount = 5; + } + if (firstVisibleItem <= checkLoadCount && !loading) { if (!endReached[0]) { loading = true; waitingForLoad.add(lastLoadIndex); @@ -2679,32 +3217,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - private boolean searchForHttpInText(CharSequence string) { - int len = string.length(); - int seqLen = 0; - for (int a = 0; a < len; a++) { - char ch = string.charAt(a); - if (seqLen == 0 && (ch == 'h' || ch == 'H')) { - seqLen++; - } else if ((seqLen == 1 || seqLen == 2) && (ch == 't' || ch == 'T')) { - seqLen++; - } else if (seqLen == 3 && (ch == 'p' || ch == 'P')) { - seqLen++; - } else if (seqLen == 4 && (ch == 's' || ch == 'S')) { - seqLen++; - } else if ((seqLen == 4 || seqLen == 5) && ch == ':') { - seqLen++; - } else if ((seqLen == 5 || seqLen == 6 || seqLen == 7) && ch == '/') { - if (seqLen == 6 || seqLen == 7) { - return true; - } - seqLen++; - } else if (seqLen != 0) { - seqLen = 0; - } - } - return false; - } private void processSelectedAttach(int which) { if (which == attach_photo || which == attach_gallery || which == attach_document || which == attach_video) { @@ -2752,7 +3264,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 4); return; } - PhotoAlbumPickerActivity fragment = new PhotoAlbumPickerActivity(false, currentEncryptedChat == null, ChatActivity.this); + PhotoAlbumPickerActivity fragment = new PhotoAlbumPickerActivity(false, currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46, ChatActivity.this); fragment.setDelegate(new PhotoAlbumPickerActivity.PhotoAlbumPickerActivityDelegate() { @Override public void didSelectPhotos(ArrayList photos, ArrayList captions, ArrayList webPhotos) { @@ -2808,14 +3320,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not FileLog.e("tmessages", e); } } else if (which == attach_location) { - if (!isGoogleMapsInstalled()) { + if (!AndroidUtilities.isGoogleMapsInstalled(ChatActivity.this)) { return; } LocationActivity fragment = new LocationActivity(); fragment.setDelegate(new LocationActivity.LocationActivityDelegate() { @Override public void didSelectLocation(TLRPC.MessageMedia location) { - SendMessagesHelper.getInstance().sendMessage(location, dialog_id, replyingMessageObject, chatActivityEnterView == null || chatActivityEnterView.asAdmin()); + SendMessagesHelper.getInstance().sendMessage(location, dialog_id, replyingMessageObject, chatActivityEnterView == null || chatActivityEnterView.asAdmin(), null, null); moveScrollToLastMessage(); showReplyPanel(false, null, null, null, false, true); if (paused) { @@ -2886,19 +3398,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return !(dialog == chatAttachViewSheet && PhotoViewer.getInstance().isVisible()) && super.dismissDialogOnPause(dialog); } - private void searchLinks(final CharSequence charSequence, boolean force) { - if (currentEncryptedChat != null) { + private void searchLinks(final CharSequence charSequence, final boolean force) { + if (currentEncryptedChat != null && (MessagesController.getInstance().secretWebpagePreview == 0 || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 46)) { return; } if (force && foundWebPage != null) { if (foundWebPage.url != null) { int index = TextUtils.indexOf(charSequence, foundWebPage.url); - char lastChar; - boolean lenEqual; + char lastChar = 0; + boolean lenEqual = false; if (index == -1) { + if (foundWebPage.display_url != null) { index = TextUtils.indexOf(charSequence, foundWebPage.display_url); lenEqual = index != -1 && index + foundWebPage.display_url.length() == charSequence.length(); lastChar = index != -1 && !lenEqual ? charSequence.charAt(index + foundWebPage.display_url.length()) : 0; + } } else { lenEqual = index + foundWebPage.url.length() == charSequence.length(); lastChar = !lenEqual ? charSequence.charAt(index + foundWebPage.url.length()) : 0; @@ -2922,6 +3436,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not try { Matcher m = AndroidUtilities.WEB_URL.matcher(charSequence); while (m.find()) { + if (m.start() > 0) { + if (charSequence.charAt(m.start() - 1) == '@') { + continue; + } + } if (urls == null) { urls = new ArrayList<>(); } @@ -2970,6 +3489,32 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not textToCheck = charSequence; } + if (currentEncryptedChat != null && MessagesController.getInstance().secretWebpagePreview == 2) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + MessagesController.getInstance().secretWebpagePreview = 1; + ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).edit().putInt("secretWebpage2", MessagesController.getInstance().secretWebpagePreview).commit(); + foundUrls = null; + searchLinks(charSequence, force); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + builder.setMessage(LocaleController.getString("SecretLinkPreviewAlert", R.string.SecretLinkPreviewAlert)); + showDialog(builder.create()); + + MessagesController.getInstance().secretWebpagePreview = 0; + ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).edit().putInt("secretWebpage2", MessagesController.getInstance().secretWebpagePreview).commit(); + } + }); + return; + } + final TLRPC.TL_messages_getWebPagePreview req = new TLRPC.TL_messages_getWebPagePreview(); if (textToCheck instanceof String) { req.message = (String) textToCheck; @@ -2990,6 +3535,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (foundWebPage instanceof TLRPC.TL_webPagePending) { pendingLinkSearchString = req.message; } + if (currentEncryptedChat != null && foundWebPage instanceof TLRPC.TL_webPagePending) { + foundWebPage.url = req.message; + } showReplyPanel(true, null, null, foundWebPage, false, true); } else { if (foundWebPage != null) { @@ -3041,12 +3589,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int iColor = themePrefs.getInt("chatEditTextIconsColor", bgColor == 0xffffffff ? defColor : 0xffadadad); int textColor = themePrefs.getInt("chatEditTextColor", 0xff999999); replyObjectTextView.setTextColor(textColor); - //int rColor = themePrefs.getInt("chatForwardRColor", defColor); - if(getParentActivity() != null) { - Drawable delete = getParentActivity().getResources().getDrawable(R.drawable.delete_reply); - delete.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); - deleteIconImageView.setImageDrawable(delete); - } + deleteIconImageView.setImageResource(R.drawable.delete_reply); + deleteIconImageView.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); boolean openKeyboard = false; if (messageObject != null && messageObject.getDialogId() != dialog_id) { messageObjects = new ArrayList<>(); @@ -3056,14 +3600,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (messageObject != null) { String name; - if (messageObject.messageOwner.from_id > 0) { + if (messageObject.isFromUser()) { TLRPC.User user = MessagesController.getInstance().getUser(messageObject.messageOwner.from_id); if (user == null) { return; } name = UserObject.getUserName(user); } else { - TLRPC.Chat chat = MessagesController.getInstance().getChat(-messageObject.messageOwner.from_id); + TLRPC.Chat chat = MessagesController.getInstance().getChat(messageObject.messageOwner.to_id.channel_id); if (chat == null) { return; } @@ -3076,21 +3620,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (foundWebPage != null) { return; } - //replyIconImageView.setImageResource(R.drawable.reply); - Drawable reply = getParentActivity().getResources().getDrawable(R.drawable.reply); - reply.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); - replyIconImageView.setImageDrawable(reply); - + replyIconImageView.setImageResource(R.drawable.reply); + replyIconImageView.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); deleteIconImageView.setVisibility(View.VISIBLE); lineView.setVisibility(View.VISIBLE); - replyNameTextView.setText(name); replyNameTextView.setTextColor(iColor); + replyNameTextView.setText(name); if (messageObject.messageText != null) { String mess = messageObject.messageText.toString(); if (mess.length() > 150) { mess = mess.substring(0, 150); } - mess = mess.replace("\n", " "); + mess = mess.replace('\n', ' '); replyObjectTextView.setText(Emoji.replaceEmoji(mess, replyObjectTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false)); } } else if (messageObjects != null) { @@ -3106,16 +3647,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } chatActivityEnterView.setForceShowSendButton(true, animated); ArrayList uids = new ArrayList<>(); - //replyIconImageView.setImageResource(R.drawable.forward_blue); - Drawable forward = getParentActivity().getResources().getDrawable(R.drawable.forward_blue); - forward.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); - replyIconImageView.setImageDrawable(forward); + replyIconImageView.setImageResource(R.drawable.forward_blue); + MessageObject object = messageObjects.get(0); + if (object.isFromUser()) { + uids.add(object.messageOwner.from_id); + } else { + uids.add(-object.messageOwner.to_id.channel_id); + } + replyIconImageView.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); deleteIconImageView.setVisibility(View.VISIBLE); lineView.setVisibility(View.VISIBLE); - uids.add(messageObjects.get(0).messageOwner.from_id); int type = messageObjects.get(0).type; for (int a = 1; a < messageObjects.size(); a++) { - Integer uid = messageObjects.get(a).messageOwner.from_id; + object = messageObjects.get(a); + Integer uid; + if (object.isFromUser()) { + uid = object.messageOwner.from_id; + } else { + uid = -object.messageOwner.to_id.channel_id; + } if (!uids.contains(uid)) { uids.add(uid); } @@ -3171,7 +3721,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (mess.length() > 150) { mess = mess.substring(0, 150); } - mess = mess.replace("\n", " "); + mess = mess.replace('\n', ' '); replyObjectTextView.setText(Emoji.replaceEmoji(mess, replyObjectTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false)); } else { replyObjectTextView.setText(LocaleController.formatPluralString("ForwardedMessage", messageObjects.size())); @@ -3191,8 +3741,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (type == 12) { replyObjectTextView.setText(LocaleController.formatPluralString("ForwardedContact", messageObjects.size())); - } else if (type == 2 || type == 14) { + } else if (type == 2) { replyObjectTextView.setText(LocaleController.formatPluralString("ForwardedAudio", messageObjects.size())); + } else if (type == 14) { + replyObjectTextView.setText(LocaleController.formatPluralString("ForwardedMusic", messageObjects.size())); } else if (type == 13) { replyObjectTextView.setText(LocaleController.formatPluralString("ForwardedSticker", messageObjects.size())); } else if (type == 8 || type == 9) { @@ -3201,7 +3753,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not replyObjectTextView.setText(LocaleController.getString("AttachGif", R.string.AttachGif)); } else { String name; - if ((name = FileLoader.getDocumentFileName(messageObjects.get(0).messageOwner.media.document)).length() != 0) { + if ((name = FileLoader.getDocumentFileName(messageObjects.get(0).getDocument())).length() != 0) { replyObjectTextView.setText(name); } messageObject = messageObjects.get(0); @@ -3213,11 +3765,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else { replyIconImageView.setImageResource(R.drawable.link); - if(getParentActivity() != null ) { - Drawable link = getParentActivity().getResources().getDrawable(R.drawable.link); - link.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); - replyIconImageView.setImageDrawable(link); - } + replyIconImageView.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); replyNameTextView.setTextColor(iColor);// if (webPage instanceof TLRPC.TL_webPagePending) { replyNameTextView.setText(LocaleController.getString("GettingLinkInfo", R.string.GettingLinkInfo)); @@ -3227,15 +3775,18 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not replyNameTextView.setText(webPage.site_name); } else if (webPage.title != null) { replyNameTextView.setText(webPage.title); + Log.e("ChatActivity","webPage.title " + webPage.title); } else { replyNameTextView.setText(LocaleController.getString("LinkPreview", R.string.LinkPreview)); } if (webPage.description != null) { replyObjectTextView.setText(webPage.description); + Log.e("ChatActivity","webPage.description " + webPage.description); } else if (webPage.title != null && webPage.site_name != null) { replyObjectTextView.setText(webPage.title); } else if (webPage.author != null) { replyObjectTextView.setText(webPage.author); + Log.e("ChatActivity","webPage.author " + webPage.author); } else { replyObjectTextView.setText(webPage.display_url); } @@ -3245,7 +3796,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not FrameLayout.LayoutParams layoutParams1 = (FrameLayout.LayoutParams) replyNameTextView.getLayoutParams(); FrameLayout.LayoutParams layoutParams2 = (FrameLayout.LayoutParams) replyObjectTextView.getLayoutParams(); TLRPC.PhotoSize photoSize = messageObject != null ? FileLoader.getClosestPhotoSizeWithSize(messageObject.photoThumbs, 80) : null; - if (photoSize == null || messageObject.type == 13) { + if (photoSize == null || photoSize instanceof TLRPC.TL_photoSizeEmpty || photoSize.location instanceof TLRPC.TL_fileLocationUnavailable || messageObject.type == 13 || messageObject != null && messageObject.isSecretMedia()) { replyImageView.setImageBitmap(null); replyImageLocation = null; replyImageView.setVisibility(View.INVISIBLE); @@ -3292,7 +3843,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not replyIconImageView.setImageDrawable(null); replyNameTextView.setText(""); replyObjectTextView.setText(""); - //deleteIconImageView.setImageDrawable(null); deleteIconImageView.setVisibility(View.INVISIBLE); lineView.setVisibility(View.INVISIBLE); } @@ -3339,6 +3889,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not firstLoading = true; loading = true; waitingForImportantLoad = false; + waitingForReplyMessageLoad = false; startLoadFromMessageId = 0; last_message_id = 0; needSelectFromMessageId = false; @@ -3458,21 +4009,27 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (query) { - clearChatData(); + if (currentEncryptedChat != null && !MessagesStorage.getInstance().checkMessageId(dialog_id, startLoadFromMessageId)) { + return; + } + /*clearChatData(); loadsCount = 0; unread_to_load = 0; first_unread_id = 0; loadingForward = false; unreadMessageObject = null; - scrollToMessage = null; + scrollToMessage = null;*/ + + waitingForReplyMessageLoad = true; highlightMessageId = Integer.MAX_VALUE; scrollToMessagePosition = -10000; startLoadFromMessageId = id; waitingForLoad.add(lastLoadIndex); MessagesController.getInstance().loadMessages(loadIndex == 0 ? dialog_id : mergeDialogId, AndroidUtilities.isTablet() ? 30 : 20, startLoadFromMessageId, true, 0, classGuid, 3, 0, loadIndex == 0 ? channelMessagesImportant : 0, lastLoadIndex++); - emptyViewContainer.setVisibility(View.INVISIBLE); + //emptyViewContainer.setVisibility(View.INVISIBLE); } returnToMessageId = fromMessageId; + returnToLoadIndex = loadIndex; needSelectFromMessageId = select; } @@ -3548,6 +4105,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (currentEncryptedChat instanceof TLRPC.TL_encryptedChat) { bottomOverlay.setVisibility(View.INVISIBLE); } + checkRaiseSensors(); if (hideKeyboard) { chatActivityEnterView.hidePopup(false); if (getParentActivity() != null) { @@ -3557,53 +4115,44 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not checkActionBarMenu(); } + @Override + public void onRequestPermissionsResultFragment(int requestCode, String[] permissions, int[] grantResults) { + if (chatActivityEnterView != null) { + chatActivityEnterView.onRequestPermissionsResultFragment(requestCode, permissions, grantResults); + } + if (mentionsAdapter != null) { + mentionsAdapter.onRequestPermissionsResultFragment(requestCode, permissions, grantResults); + } + } + private void checkActionBarMenu() { if (currentEncryptedChat != null && !(currentEncryptedChat instanceof TLRPC.TL_encryptedChat) || currentChat != null && ChatObject.isNotInChat(currentChat) || currentUser != null && UserObject.isDeleted(currentUser)) { - if (menuItem != null) { menuItem.setVisibility(View.GONE); } - if (timeItem != null) { - timeItem.setVisibility(View.GONE); - } if (timeItem2 != null) { timeItem2.setVisibility(View.GONE); } + if (avatarContainer != null) { + avatarContainer.hideTimeItem(); + } } else { if (menuItem != null) { menuItem.setVisibility(View.VISIBLE); } - if (timeItem != null) { - timeItem.setVisibility(View.VISIBLE); - } if (timeItem2 != null) { timeItem2.setVisibility(View.VISIBLE); } - } - - if (timerDrawable != null && currentEncryptedChat != null) { - timerDrawable.setTime(currentEncryptedChat.ttl); - } - - checkAndUpdateAvatar(); - } - - private int updateOnlineCount() { - onlineCount = 0; - if (!(info instanceof TLRPC.TL_chatFull)) { - return 0; - } - int currentTime = ConnectionsManager.getInstance().getCurrentTime(); - for (int a = 0; a < info.participants.participants.size(); a++) { - TLRPC.ChatParticipant participant = info.participants.participants.get(a); - TLRPC.User user = MessagesController.getInstance().getUser(participant.user_id); - if (user != null && user.status != null && (user.status.expires > currentTime || user.id == UserConfig.getClientUserId()) && user.status.expires > 10000) { - onlineCount++; + if (avatarContainer != null) { + avatarContainer.showTimeItem(); } } - return onlineCount; + if (avatarContainer != null && currentEncryptedChat != null) { + avatarContainer.setTime(currentEncryptedChat.ttl); + } + checkAndUpdateAvatar(); } private int getMessageType(MessageObject messageObject) { @@ -3631,16 +4180,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } return 1; } else { - if (!messageObject.isMediaEmpty()) { - if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo || - messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || - messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { - if (messageObject.isSticker()) { + if (messageObject.isVoice()) { + return 2; + } else if (messageObject.isSticker()) { TLRPC.InputStickerSet inputStickerSet = messageObject.getInputStickerSet(); - if (inputStickerSet != null && !StickersQuery.isStickerPackInstalled(inputStickerSet.id)) { + if (inputStickerSet instanceof TLRPC.TL_inputStickerSetID) { + if (!StickersQuery.isStickerPackInstalled(inputStickerSet.id)) { + return 7; + } + } else if (inputStickerSet instanceof TLRPC.TL_inputStickerSetShortName) { + if (!StickersQuery.isStickerPackInstalled(inputStickerSet.short_name)) { return 7; } } + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || messageObject.getDocument() != null || messageObject.isMusic() || messageObject.isVideo()) { boolean canSave = false; if (messageObject.messageOwner.attachPath != null && messageObject.messageOwner.attachPath.length() != 0) { File f = new File(messageObject.messageOwner.attachPath); @@ -3655,8 +4208,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } if (canSave) { - if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { - String mime = messageObject.messageOwner.media.document.mime_type; + if (messageObject.getDocument() != null) { + String mime = messageObject.getDocument().mime_type; if (mime != null) { if (mime.endsWith("/xml")) { return 5; @@ -3667,11 +4220,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } return 4; } - } - return 2; - } else { + } else if (messageObject.type == 12) { + return 8; + } else if (messageObject.isMediaEmpty()) { return 3; } + return 2; } } } else { @@ -3693,16 +4247,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return 1; } } else { - if (!messageObject.isMediaEmpty()) { - if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo || - messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || - messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { - if (messageObject.isSticker()) { + if (messageObject.isVoice()) { + return 2; + } else if (messageObject.isSticker()) { TLRPC.InputStickerSet inputStickerSet = messageObject.getInputStickerSet(); - if (inputStickerSet != null && !StickersQuery.isStickerPackInstalled(inputStickerSet.id)) { + if (inputStickerSet instanceof TLRPC.TL_inputStickerSetShortName) { + if (!StickersQuery.isStickerPackInstalled(inputStickerSet.short_name)) { return 7; - } } + } + } else if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || messageObject.getDocument() != null || messageObject.isMusic() || messageObject.isVideo()) { boolean canSave = false; if (messageObject.messageOwner.attachPath != null && messageObject.messageOwner.attachPath.length() != 0) { File f = new File(messageObject.messageOwner.attachPath); @@ -3717,8 +4271,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } if (canSave) { - if (messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { - String mime = messageObject.messageOwner.media.document.mime_type; + if (messageObject.getDocument() != null) { + String mime = messageObject.getDocument().mime_type; if (mime != null && mime.endsWith("text/xml")) { return 5; } @@ -3727,11 +4281,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return 4; } } - } - return 2; - } else { + } else if (messageObject.type == 12) { + return 8; + } else if (messageObject.isMediaEmpty()) { return 3; } + return 2; } } } @@ -3740,7 +4295,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int index = messageObject.getDialogId() == dialog_id ? 0 : 1; if (selectedMessagesIds[index].containsKey(messageObject.getId())) { selectedMessagesIds[index].remove(messageObject.getId()); - if (messageObject.type == 0) { + if (messageObject.type == 0 || messageObject.caption != null) { selectedMessagesCanCopyIds[index].remove(messageObject.getId()); } if (!messageObject.canDeleteMessage(currentChat)) { @@ -3748,7 +4303,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else { selectedMessagesIds[index].put(messageObject.getId(), messageObject); - if (messageObject.type == 0) { + if (messageObject.type == 0 || messageObject.caption != null) { selectedMessagesCanCopyIds[index].put(messageObject.getId(), messageObject); } if (!messageObject.canDeleteMessage(currentChat)) { @@ -3758,12 +4313,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (actionBar.isActionModeShowed()) { if (selectedMessagesIds[0].isEmpty() && selectedMessagesIds[1].isEmpty()) { actionBar.hideActionMode(); + updatePinnedMessageView(true); } else { - try{ - actionBar.createActionMode().getItem(forward).setVisibility(messageObject.messageOwner.media != null && messageObject.messageOwner.media.caption != null && messageObject.messageOwner.media.caption.length() > 0 ? View.GONE : View.VISIBLE ); - } catch (Exception e) { - FileLog.e("tmessages", e); - } int copyVisible = actionBar.createActionMode().getItem(copy).getVisibility(); actionBar.createActionMode().getItem(copy).setVisibility(selectedMessagesCanCopyIds[0].size() + selectedMessagesCanCopyIds[1].size() != 0 ? View.VISIBLE : View.GONE); int newCopyVisible = actionBar.createActionMode().getItem(copy).getVisibility(); @@ -3771,14 +4322,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not final ActionBarMenuItem replyItem = actionBar.createActionMode().getItem(reply); if (replyItem != null) { boolean allowChatActions = true; - if (isBroadcast || currentChat != null && (ChatObject.isNotInChat(currentChat) || ChatObject.isChannel(currentChat) && !currentChat.creator && !currentChat.editor && !currentChat.megagroup)) { + if (currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 46 || isBroadcast || currentChat != null && (ChatObject.isNotInChat(currentChat) || ChatObject.isChannel(currentChat) && !currentChat.creator && !currentChat.editor && !currentChat.megagroup)) { allowChatActions = false; } final int newVisibility = allowChatActions && selectedMessagesIds[0].size() + selectedMessagesIds[1].size() == 1 ? View.VISIBLE : View.GONE; if (replyItem.getVisibility() != newVisibility) { if (replyButtonAnimation != null) { replyButtonAnimation.cancel(); - replyButtonAnimation = null; } if (copyVisible != newCopyVisible) { if (newVisibility == View.VISIBLE) { @@ -3809,13 +4359,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not replyButtonAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Object animation) { - if (replyButtonAnimation.equals(animation)) { + if (replyButtonAnimation != null && replyButtonAnimation.equals(animation)) { replyItem.clearAnimation(); if (newVisibility == View.GONE) { replyItem.setVisibility(View.GONE); } } } + + @Override + public void onAnimationCancel(Object animation) { + if (replyButtonAnimation != null && replyButtonAnimation.equals(animation)) { + replyButtonAnimation = null; + } + } }); replyButtonAnimation.start(); } @@ -3853,20 +4410,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void updateTitle() { - if (nameTextView == null) { + if (avatarContainer == null) { return; } if (currentChat != null) { - nameTextView.setText(currentChat.title); + avatarContainer.setTitle(currentChat.title); } else if (currentUser != null) { if (currentUser.id / 1000 != 777 && currentUser.id / 1000 != 333 && ContactsController.getInstance().contactsDict.get(currentUser.id) == null && (ContactsController.getInstance().contactsDict.size() != 0 || !ContactsController.getInstance().isLoadingContacts())) { if (currentUser.phone != null && currentUser.phone.length() != 0) { - nameTextView.setText(PhoneFormat.getInstance().format("+" + currentUser.phone)); + avatarContainer.setTitle(PhoneFormat.getInstance().format("+" + currentUser.phone)); } else { - nameTextView.setText(UserObject.getUserName(currentUser)); + avatarContainer.setTitle(UserObject.getUserName(currentUser)); } } else { - nameTextView.setText(UserObject.getUserName(currentUser)); + avatarContainer.setTitle(UserObject.getUserName(currentUser)); } } } @@ -3906,13 +4463,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } private void updateTitleIcons() { - if (nameTextView == null) { + if (avatarContainer == null) { return; } //int leftIcon = currentEncryptedChat != null ? R.drawable.ic_lock_header : 0; int rightIcon = MessagesController.getInstance().isDialogMuted(dialog_id) ? R.drawable.mute_fixed : 0; + avatarContainer.setTitleIcons(currentEncryptedChat != null ? R.drawable.ic_lock_header : 0, rightIcon); //nameTextView.setCompoundDrawablesWithIntrinsicBounds(leftIcon, 0, rightIcon, 0); - if(getParentActivity() != null) { + /*if(getParentActivity() != null) { Drawable lock = getParentActivity().getResources().getDrawable(R.drawable.ic_lock_header); SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); int color = themePrefs.getInt("chatHeaderIconsColor", 0xffffffff); @@ -3922,8 +4480,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not Drawable mute = getParentActivity().getResources().getDrawable(R.drawable.mute_blue); mute.setColorFilter(color, PorterDuff.Mode.SRC_IN); mute = MessagesController.getInstance().isDialogMuted(dialog_id) ? mute : null; - nameTextView.setCompoundDrawablesWithIntrinsicBounds(lock, null, mute, null); - } + //nameTextView.setCompoundDrawablesWithIntrinsicBounds(lock, null, mute, null); + }*/ if (rightIcon != 0) { muteItem.setText(LocaleController.getString("UnmuteNotifications", R.string.UnmuteNotifications)); } else { @@ -3931,178 +4489,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - private void updateSubtitle() { - if (onlineTextView == null) { - return; - } - SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - int lightColor = AndroidUtilities.getIntDarkerColor("themeColor", -0x40); - onlineTextView.setTextColor(themePrefs.getInt("chatStatusColor", lightColor)); - CharSequence printString = MessagesController.getInstance().printingStrings.get(dialog_id); - if (printString != null) { - printString = TextUtils.replace(printString, new String[]{"..."}, new String[]{""}); - } - if (printString == null || printString.length() == 0 || ChatObject.isChannel(currentChat) && !currentChat.megagroup) { - setTypingAnimation(false); - if (currentChat != null) { - if (ChatObject.isChannel(currentChat)) { - if (!currentChat.broadcast && !currentChat.megagroup && !(currentChat instanceof TLRPC.TL_channelForbidden)) { - onlineTextView.setText(LocaleController.getString("ShowDiscussion", R.string.ShowDiscussion)); - if (radioButton != null && radioButton.getVisibility() != View.VISIBLE) { - radioButton.setVisibility(View.VISIBLE); - onlineTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 74, 0, 0, 4)); - } - } else { - if (info != null && info.participants_count != 0) { - int result[] = new int[1]; - String shortNumber = LocaleController.formatShortNumber(info.participants_count, result); - String text = LocaleController.formatPluralString("Members", result[0]).replace(String.format("%d", result[0]), shortNumber); - onlineTextView.setText(text); - } else { - if (currentChat.megagroup) { - onlineTextView.setText(LocaleController.getString("Loading", R.string.Loading).toLowerCase()); - } else { - if ((currentChat.flags & TLRPC.CHAT_FLAG_IS_PUBLIC) != 0) { - onlineTextView.setText(LocaleController.getString("ChannelPublic", R.string.ChannelPublic).toLowerCase()); - } else { - onlineTextView.setText(LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate).toLowerCase()); - } - } - } - if (radioButton != null && radioButton.getVisibility() != View.GONE) { - radioButton.setVisibility(View.GONE); - onlineTextView.setLayoutParams(LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 54, 0, 0, 4)); - } - } - } else { - if (ChatObject.isKickedFromChat(currentChat)) { - onlineTextView.setText(LocaleController.getString("YouWereKicked", R.string.YouWereKicked)); - } else if (ChatObject.isLeftFromChat(currentChat)) { - onlineTextView.setText(LocaleController.getString("YouLeft", R.string.YouLeft)); - } else { - int count = currentChat.participants_count; - if (info != null) { - count = info.participants.participants.size(); - } - if (onlineCount > 1 && count != 0) { - onlineTextView.setText(String.format("%s, %s", LocaleController.formatPluralString("Members", count), LocaleController.formatPluralString("Online", onlineCount))); - } else { - onlineTextView.setText(LocaleController.formatPluralString("Members", count)); - } - } - } - } else if (currentUser != null) { - TLRPC.User user = MessagesController.getInstance().getUser(currentUser.id); - if (user != null) { - currentUser = user; - } - String newStatus; - if (currentUser.id == 333000 || currentUser.id == 777000) { - newStatus = LocaleController.getString("ServiceNotifications", R.string.ServiceNotifications); - } else if (currentUser.bot) { - newStatus = LocaleController.getString("Bot", R.string.Bot); - } else { - newStatus = LocaleController.formatUserStatus(currentUser); - } - if (lastStatus == null || lastPrintString != null || !lastStatus.equals(newStatus)) { - lastStatus = newStatus; - onlineTextView.setText(newStatus); - } - //plus - if(newStatus.equals(LocaleController.getString("Online", R.string.Online))){ - onlineTextView.setTextColor(themePrefs.getInt("chatOnlineColor", themePrefs.getInt("chatStatusColor", lightColor))); - } - } - lastPrintString = null; - } else { - lastPrintString = printString; - onlineTextView.setText(printString); - setTypingAnimation(true); - //plus - onlineTextView.setTextColor(themePrefs.getInt("chatTypingColor", themePrefs.getInt("chatStatusColor", lightColor))); - - } - } - - private void setTypingAnimation(boolean start) { - if (actionBar == null) { - return; - } - if (start) { - try { - Integer type = MessagesController.getInstance().printingStringsTypes.get(dialog_id); - if (type == 0) { - if (lastStatusDrawable == 1) { - return; - } - lastStatusDrawable = 1; - if (onlineTextView != null) { - onlineTextView.setCompoundDrawablesWithIntrinsicBounds(typingDotsDrawable, null, null, null); - onlineTextView.setCompoundDrawablePadding(AndroidUtilities.dp(4)); - - typingDotsDrawable.start(); - recordStatusDrawable.stop(); - sendingFileDrawable.stop(); - } - } else if (type == 1) { - if (lastStatusDrawable == 2) { - return; - } - lastStatusDrawable = 2; - if (onlineTextView != null) { - onlineTextView.setCompoundDrawablesWithIntrinsicBounds(recordStatusDrawable, null, null, null); - onlineTextView.setCompoundDrawablePadding(AndroidUtilities.dp(4)); - - recordStatusDrawable.start(); - typingDotsDrawable.stop(); - sendingFileDrawable.stop(); - } - } else if (type == 2) { - if (lastStatusDrawable == 3) { - return; - } - lastStatusDrawable = 3; - if (onlineTextView != null) { - onlineTextView.setCompoundDrawablesWithIntrinsicBounds(sendingFileDrawable, null, null, null); - onlineTextView.setCompoundDrawablePadding(AndroidUtilities.dp(4)); - - sendingFileDrawable.start(); - typingDotsDrawable.stop(); - recordStatusDrawable.stop(); - } - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } else { - if (lastStatusDrawable == 0) { - return; - } - lastStatusDrawable = 0; - if (onlineTextView != null) { - onlineTextView.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); - onlineTextView.setCompoundDrawablePadding(0); - - typingDotsDrawable.stop(); - recordStatusDrawable.stop(); - sendingFileDrawable.stop(); - } - } - } - private void checkAndUpdateAvatar() { - TLRPC.FileLocation newPhoto = null; - AvatarDrawable avatarDrawable = null; if (currentUser != null) { TLRPC.User user = MessagesController.getInstance().getUser(currentUser.id); if (user == null) { return; } currentUser = user; - if (currentUser.photo != null) { - newPhoto = currentUser.photo.photo_small; - } - avatarDrawable = new AvatarDrawable(currentUser); } else if (currentChat != null) { TLRPC.Chat chat = MessagesController.getInstance().getChat(currentChat.id); if (chat == null) { @@ -4110,18 +4503,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } currentChat = chat; if (currentChat.photo != null) { - newPhoto = currentChat.photo.photo_small; + //newPhoto = currentChat.photo.photo_small; } - avatarDrawable = new AvatarDrawable(currentChat); + //avatarDrawable = new AvatarDrawable(currentChat); + } + if (avatarContainer != null) { + avatarContainer.checkAndUpdateAvatar(); } //Chat header photo int radius = AndroidUtilities.dp(AndroidUtilities.getIntDef("chatHeaderAvatarRadius", 32)); - if(avatarImageView != null)avatarImageView.setRoundRadius(radius); - if(avatarDrawable != null)avatarDrawable.setRadius(radius); + //if(avatarImageView != null)avatarImageView.setRoundRadius(radius); + //if(avatarDrawable != null)avatarDrawable.setRadius(radius); // - if (avatarImageView != null) { - avatarImageView.setImage(newPhoto, "50_50", avatarDrawable); - } + //if (avatarImageView != null) { + //avatarImageView.setImage(newPhoto, "50_50", avatarDrawable); + //} } public boolean openVideoEditor(String videoPath, boolean removeLast, boolean animated) { @@ -4236,10 +4632,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not showReplyPanel(false, null, null, null, false, true); } else if (requestCode == 2) { String videoPath = null; + FileLog.d("tmessages", "pic path " + currentPicturePath); + if (data != null && currentPicturePath != null) { + if (new File(currentPicturePath).exists()) { + data = null; + } + } if (data != null) { Uri uri = data.getData(); if (uri != null) { - videoPath = uri.getPath(); + FileLog.d("tmessages", "video record uri " + uri.toString()); + videoPath = AndroidUtilities.getPath(uri); + FileLog.d("tmessages", "resolved path = " + videoPath); + if (!(new File(videoPath).exists())) { + videoPath = currentPicturePath; + } } else { videoPath = currentPicturePath; } @@ -4288,7 +4695,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not String originalPath = tempPath; if (tempPath == null) { originalPath = data.toString(); - tempPath = MediaController.copyDocumentToCache(data.getData(), "file"); + tempPath = MediaController.copyFileToCache(data.getData(), "file"); } if (tempPath == null) { showAttachmentError(); @@ -4315,7 +4722,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not user.first_name = name; user.last_name = ""; user.phone = number; - SendMessagesHelper.getInstance().sendMessage(user, dialog_id, replyingMessageObject, chatActivityEnterView == null || chatActivityEnterView.asAdmin()); + SendMessagesHelper.getInstance().sendMessage(user, dialog_id, replyingMessageObject, chatActivityEnterView == null || chatActivityEnterView.asAdmin(), null, null); } if (sent) { showReplyPanel(false, null, null, null, false, true); @@ -4370,6 +4777,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (id == NotificationCenter.messagesDidLoaded) { int guid = (Integer) args[11]; if (guid == classGuid) { + if (!openAnimationEnded) { + NotificationCenter.getInstance().setAllowedNotificationsDutingAnimation(new int[]{NotificationCenter.chatInfoDidLoaded, NotificationCenter.dialogsNeedReload, + NotificationCenter.closeChats, NotificationCenter.botKeyboardDidLoaded/*, NotificationCenter.botInfoDidLoaded*/}); + } int queryLoadIndex = (Integer) args[12]; int index = waitingForLoad.indexOf(queryLoadIndex); if (index == -1) { @@ -4377,10 +4788,26 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { waitingForLoad.remove(index); } - if (waitingForImportantLoad) { + ArrayList messArr = (ArrayList) args[2]; + if (waitingForImportantLoad || waitingForReplyMessageLoad) { + if (waitingForReplyMessageLoad) { + boolean found = false; + for (int a = 0; a < messArr.size(); a++) { + if (messArr.get(a).getId() == startLoadFromMessageId) { + found = true; + break; + } + } + if (!found) { + startLoadFromMessageId = 0; + return; + } + } int startLoadFrom = startLoadFromMessageId; + boolean needSelect = needSelectFromMessageId; clearChatData(); startLoadFromMessageId = startLoadFrom; + needSelectFromMessageId = needSelect; } loadsCount++; @@ -4399,7 +4826,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (startLoadFromMessageId != 0 && load_type == 3) { last_message_id = (Integer) args[5]; } - ArrayList messArr = (ArrayList) args[2]; ArrayList groups = (ArrayList) args[9]; SparseArray groupsByStart = null; if (groups != null && !groups.isEmpty()) { @@ -4445,9 +4871,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (load_type == 1) { Collections.reverse(messArr); } - ReplyMessageQuery.loadReplyMessagesForMessages(messArr, dialog_id); + if (currentEncryptedChat == null) { + MessagesQuery.loadReplyMessagesForMessages(messArr, dialog_id); + } + int approximateHeightSum = 0; for (int a = 0; a < messArr.size(); a++) { MessageObject obj = messArr.get(a); + approximateHeightSum += obj.getApproximateHeight(); + if (currentUser != null && currentUser.bot && obj.isOut()) { + obj.setIsRead(); + } if (messagesDict[loadIndex].containsKey(obj.getId())) { continue; } @@ -4490,7 +4923,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not dateMsg.id = 0; MessageObject dateObj = new MessageObject(dateMsg, null, false); dateObj.type = 10; - dateObj.contentType = 4; + dateObj.contentType = 1; if (load_type == 1) { messages.add(0, dateObj); } else { @@ -4515,7 +4948,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not dateMsg.from_id = group.max_id; MessageObject dateObj = new MessageObject(dateMsg, null, false); dateObj.type = 10; - dateObj.contentType = 4; + dateObj.contentType = 1; dayArray.add(dateObj); if (load_type == 1) { messages.add(0, dateObj); @@ -4531,22 +4964,24 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not messages.add(messages.size() - 1, obj); } + if (obj.getId() == last_message_id) { + forwardEndReached[loadIndex] = true; + } + if (load_type == 2 && obj.getId() == first_unread_id) { + if (approximateHeightSum > AndroidUtilities.displaySize.y / 2 || !forwardEndReached[0]) { TLRPC.Message dateMsg = new TLRPC.Message(); dateMsg.message = ""; dateMsg.id = 0; MessageObject dateObj = new MessageObject(dateMsg, null, false); - dateObj.contentType = dateObj.type = 6; - //boolean dateAdded = true; - //if (a != messArr.size() - 1) { - // MessageObject next = messArr.get(a + 1); - // dateAdded = !next.dateKey.equals(obj.dateKey); - //} + dateObj.type = 6; + dateObj.contentType = 2; messages.add(messages.size() - 1, dateObj); unreadMessageObject = dateObj; scrollToMessage = unreadMessageObject; scrollToMessagePosition = -10000; newRowsCount++; + } } else if (load_type == 3 && obj.getId() == startLoadFromMessageId) { if (needSelectFromMessageId) { highlightMessageId = obj.getId(); @@ -4559,10 +4994,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not scrollToMessagePosition = -9000; } } - - if (obj.getId() == last_message_id) { - forwardEndReached[loadIndex] = true; - } } if (forwardEndReached[loadIndex] && loadIndex != 1) { @@ -4571,7 +5002,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (loadsCount <= 2) { - if (messages.size() >= 20 || !isCache) { + if (!isCache) { updateSpamView(); } } @@ -4587,13 +5018,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } startLoadFromMessageId = 0; } - if (newRowsCount != 0) { + if (newRowsCount > 0) { int firstVisPos = chatLayoutManager.findLastVisibleItemPosition(); int top = 0; if (firstVisPos != chatLayoutManager.getItemCount() - 1) { firstVisPos = RecyclerView.NO_POSITION; } else { - View firstVisView = chatListView.getChildAt(chatListView.getChildCount() - 1); + View firstVisView = chatLayoutManager.findViewByPosition(firstVisPos); top = ((firstVisView == null) ? 0 : firstVisView.getTop()) - chatListView.getPaddingTop(); } chatAdapter.notifyItemRangeInserted(chatAdapter.getItemCount() - 1, newRowsCount); @@ -4651,7 +5082,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatAdapter.notifyItemRangeChanged(chatAdapter.isBot ? 1 : 0, 2); } int firstVisPos = chatLayoutManager.findLastVisibleItemPosition(); - View firstVisView = chatListView.getChildAt(chatListView.getChildCount() - 1); + View firstVisView = chatLayoutManager.findViewByPosition(firstVisPos); int top = ((firstVisView == null) ? 0 : firstVisView.getTop()) - chatListView.getPaddingTop(); if (newRowsCount - (end ? 1 : 0) > 0) { chatAdapter.notifyItemRangeInserted((chatAdapter.isBot ? 2 : 1) + (end ? 0 : 1), newRowsCount - (end ? 1 : 0)); @@ -4720,7 +5151,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not progressView.setVisibility(View.INVISIBLE); } } - checkScrollForLoad(); + checkScrollForLoad(false); } } else if (id == NotificationCenter.emojiDidLoaded) { if (chatListView != null) { @@ -4729,6 +5160,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (replyObjectTextView != null) { replyObjectTextView.invalidate(); } + if (alertTextView != null) { + alertTextView.invalidate(); + } + if (pinnedMessageTextView != null) { + pinnedMessageTextView.invalidate(); + } + if (mentionListView != null) { + mentionListView.invalidateViews(); + } } else if (id == NotificationCenter.updateInterfaces) { int updateMask = (Integer) args[0]; if ((updateMask & MessagesController.UPDATE_MASK_NAME) != 0 || (updateMask & MessagesController.UPDATE_MASK_CHAT_NAME) != 0) { @@ -4736,24 +5176,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } boolean updateSubtitle = false; if ((updateMask & MessagesController.UPDATE_MASK_CHAT_MEMBERS) != 0 || (updateMask & MessagesController.UPDATE_MASK_STATUS) != 0) { - if (currentChat != null) { - int lastCount = onlineCount; - if (lastCount != updateOnlineCount()) { - updateSubtitle = true; - } - } else { - updateSubtitle = true; + if (currentChat != null && avatarContainer != null) { + avatarContainer.updateOnlineCount(); } + updateSubtitle = true; } if ((updateMask & MessagesController.UPDATE_MASK_AVATAR) != 0 || (updateMask & MessagesController.UPDATE_MASK_CHAT_AVATAR) != 0 || (updateMask & MessagesController.UPDATE_MASK_NAME) != 0) { checkAndUpdateAvatar(); updateVisibleRows(); } if ((updateMask & MessagesController.UPDATE_MASK_USER_PRINT) != 0) { - CharSequence printString = MessagesController.getInstance().printingStrings.get(dialog_id); - if (lastPrintString != null && printString == null || lastPrintString == null && printString != null || lastPrintString != null && printString != null && !lastPrintString.equals(printString)) { - updateSubtitle = true; - } + updateSubtitle = true; } if ((updateMask & MessagesController.UPDATE_MASK_CHANNEL) != 0 && ChatObject.isChannel(currentChat)) { TLRPC.Chat chat = MessagesController.getInstance().getChat(currentChat.id); @@ -4767,12 +5200,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.setDialogId(dialog_id); } } - if (updateSubtitle) { - updateSubtitle(); + if (avatarContainer != null && updateSubtitle) { + avatarContainer.updateSubtitle(); } if ((updateMask & MessagesController.UPDATE_MASK_USER_PHONE) != 0) { updateContactStatus(); - updateSpamView(); } } else if (id == NotificationCenter.didReceivedNewMessages) { long did = (Long) args[0]; @@ -4781,7 +5213,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean updateChat = false; boolean hasFromMe = false; ArrayList arr = (ArrayList) args[1]; - if (currentEncryptedChat != null && arr.size() == 1) { MessageObject obj = arr.get(0); @@ -4796,8 +5227,44 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } + if (currentChat != null || inlineReturn != 0) { + for (int a = 0; a < arr.size(); a++) { + MessageObject messageObject = arr.get(a); + if (currentChat != null) { + if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatDeleteUser && messageObject.messageOwner.action.user_id == UserConfig.getClientUserId() || + messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatAddUser && messageObject.messageOwner.action.users.contains(UserConfig.getClientUserId())) { + TLRPC.Chat newChat = MessagesController.getInstance().getChat(currentChat.id); + if (newChat != null) { + currentChat = newChat; + checkActionBarMenu(); + updateBottomOverlay(); + if (avatarContainer != null) { + avatarContainer.updateSubtitle(); + } + } + } else if (messageObject.messageOwner.reply_to_msg_id != 0 && messageObject.replyMessageObject == null) { + messageObject.replyMessageObject = messagesDict[0].get(messageObject.messageOwner.reply_to_msg_id); + if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) { + messageObject.generatePinMessageText(null, null); + } + } + } else if (inlineReturn != 0) { + if (messageObject.messageOwner.reply_markup != null) { + for (int b = 0; b < messageObject.messageOwner.reply_markup.rows.size(); b++) { + TLRPC.TL_keyboardButtonRow row = messageObject.messageOwner.reply_markup.rows.get(b); + for (int c = 0; c < row.buttons.size(); c++) { + TLRPC.KeyboardButton button = row.buttons.get(c); + if (button instanceof TLRPC.TL_keyboardButtonSwitchInline) { + processSwitchButton((TLRPC.TL_keyboardButtonSwitchInline) button); + break; + } + } + } + } + } + } + } - ReplyMessageQuery.loadReplyMessagesForMessages(arr, dialog_id); boolean reloadMegagroup = false; if (!forwardEndReached[0]) { int currentMaxDate = Integer.MIN_VALUE; @@ -4809,10 +5276,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not for (int a = 0; a < arr.size(); a++) { MessageObject obj = arr.get(a); - if (currentEncryptedChat != null && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction && - obj.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL && timerDrawable != null) { - TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL) obj.messageOwner.action.encryptedAction; - timerDrawable.setTime(action.ttl_seconds); + if (currentUser != null && currentUser.bot && obj.isOut()) { + obj.setIsRead(); + } + if (avatarContainer != null && currentEncryptedChat != null && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction && obj.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { + avatarContainer.setTime(((TLRPC.TL_decryptedMessageActionSetMessageTTL) obj.messageOwner.action.encryptedAction).ttl_seconds); } if (obj.messageOwner.action instanceof TLRPC.TL_messageActionChatMigrateTo) { final Bundle bundle = new Bundle(); @@ -4847,6 +5315,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (messagesDict[0].containsKey(obj.getId())) { continue; } + obj.checkLayout(); currentMaxDate = Math.max(currentMaxDate, obj.messageOwner.date); if (obj.getId() > 0) { currentMinMsgId = Math.max(obj.getId(), currentMinMsgId); @@ -4882,16 +5351,30 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean unreadUpdated = true; int oldCount = messages.size(); int addedCount = 0; + HashMap> webpagesToReload = null; for (int a = 0; a < arr.size(); a++) { MessageObject obj = arr.get(a); - if (currentEncryptedChat != null && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction && - obj.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL && timerDrawable != null) { - TLRPC.TL_decryptedMessageActionSetMessageTTL action = (TLRPC.TL_decryptedMessageActionSetMessageTTL) obj.messageOwner.action.encryptedAction; - timerDrawable.setTime(action.ttl_seconds); + if (currentUser != null && currentUser.bot && obj.isOut()) { + obj.setIsRead(); + } + if (avatarContainer != null && currentEncryptedChat != null && obj.messageOwner.action != null && obj.messageOwner.action instanceof TLRPC.TL_messageEncryptedAction && obj.messageOwner.action.encryptedAction instanceof TLRPC.TL_decryptedMessageActionSetMessageTTL) { + avatarContainer.setTime(((TLRPC.TL_decryptedMessageActionSetMessageTTL) obj.messageOwner.action.encryptedAction).ttl_seconds); } if (messagesDict[0].containsKey(obj.getId())) { continue; } + if (currentEncryptedChat != null && obj.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && obj.messageOwner.media.webpage instanceof TLRPC.TL_webPageUrlPending) { + if (webpagesToReload == null) { + webpagesToReload = new HashMap<>(); + } + ArrayList arrayList = webpagesToReload.get(obj.messageOwner.media.webpage.url); + if (arrayList == null) { + arrayList = new ArrayList<>(); + webpagesToReload.put(obj.messageOwner.media.webpage.url, arrayList); + } + arrayList.add(obj); + } + obj.checkLayout(); if (obj.messageOwner.action instanceof TLRPC.TL_messageActionChatMigrateTo) { final Bundle bundle = new Bundle(); bundle.putInt("chat_id", obj.messageOwner.action.channel_id); @@ -4945,7 +5428,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not dateMsg.id = 0; MessageObject dateObj = new MessageObject(dateMsg, null, false); dateObj.type = 10; - dateObj.contentType = 4; + dateObj.contentType = 1; messages.add(0, dateObj); addedCount++; } @@ -4964,7 +5447,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not dateMsg.message = ""; dateMsg.id = 0; MessageObject dateObj = new MessageObject(dateMsg, null, false); - dateObj.contentType = dateObj.type = 6; + dateObj.type = 6; + dateObj.contentType = 2; messages.add(0, dateObj); unreadMessageObject = dateObj; scrollToMessage = unreadMessageObject; @@ -4994,6 +5478,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updateChat = true; } } + if (webpagesToReload != null) { + MessagesController.getInstance().reloadWebPages(dialog_id, webpagesToReload); + } if (progressView != null) { progressView.setVisibility(View.INVISIBLE); @@ -5128,6 +5615,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not for (int a = 0; a < markAsDeletedMessages.size(); a++) { Integer ids = markAsDeletedMessages.get(a); MessageObject obj = messagesDict[loadIndex].get(ids); + if (loadIndex == 0 && info != null && info.pinned_msg_id == ids) { + pinnedMessageObject = null; + info.pinned_msg_id = 0; + MessagesStorage.getInstance().updateChannelPinnedMessage(channelId, 0); + updatePinnedMessageView(true); + } if (obj != null) { int index = messages.indexOf(obj); if (index != -1) { @@ -5209,21 +5702,25 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not TLRPC.Message newMsgObj = (TLRPC.Message) args[2]; boolean mediaUpdated = false; try { - mediaUpdated = newMsgObj.media != null && obj.messageOwner.media != null && !newMsgObj.media.getClass().equals(obj.messageOwner.media.getClass()); + mediaUpdated = obj.messageOwner.params != null && obj.messageOwner.params.containsKey("query_id") || newMsgObj.media != null && obj.messageOwner.media != null && !newMsgObj.media.getClass().equals(obj.messageOwner.media.getClass()); } catch (Exception e) { //TODO FileLog.e("tmessages", e); } if (newMsgObj != null) { - obj.messageOwner.media = newMsgObj.media; + obj.messageOwner = newMsgObj; obj.generateThumbs(true); + obj.setType(); } messagesDict[0].remove(msgId); messagesDict[0].put(newMsgId, obj); obj.messageOwner.id = newMsgId; obj.messageOwner.send_state = MessageObject.MESSAGE_SEND_STATE_SENT; + obj.forceUpdate = mediaUpdated; ArrayList messArr = new ArrayList<>(); messArr.add(obj); - ReplyMessageQuery.loadReplyMessagesForMessages(messArr, dialog_id); + if (currentEncryptedChat == null) { + MessagesQuery.loadReplyMessagesForMessages(messArr, dialog_id); + } if (chatAdapter != null) { chatAdapter.updateRowWithMessageObject(obj); } @@ -5271,8 +5768,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (mentionsAdapter != null) { mentionsAdapter.setChatInfo(info); } - updateOnlineCount(); - updateSubtitle(); + if (args[3] instanceof MessageObject) { + pinnedMessageObject = (MessageObject) args[3]; + updatePinnedMessageView(false); + } else { + updatePinnedMessageView(true); + } + if (avatarContainer != null) { + avatarContainer.updateOnlineCount(); + avatarContainer.updateSubtitle(); + } if (isBroadcast) { SendMessagesHelper.getInstance().setCurrentChatInfo(info); } @@ -5301,7 +5806,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not botsCount = info.bot_info.size(); for (int a = 0; a < info.bot_info.size(); a++) { TLRPC.BotInfo bot = info.bot_info.get(a); - if (!bot.commands.isEmpty()) { + if (!bot.commands.isEmpty() && (!ChatObject.isChannel(currentChat) || currentChat != null && currentChat.megagroup)) { hasBotsCommands = true; } botInfo.put(bot.user_id, bot); @@ -5309,7 +5814,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chatListView != null) { chatListView.invalidateViews(); } - if (mentionsAdapter != null) { + if (mentionsAdapter != null && (!ChatObject.isChannel(currentChat) || currentChat != null && currentChat.megagroup)) { mentionsAdapter.setBotInfo(botInfo); } } @@ -5330,12 +5835,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (id == NotificationCenter.chatInfoCantLoad) { int chatId = (Integer) args[0]; if (currentChat != null && currentChat.id == chatId) { + int reason = (Integer) args[1]; if (getParentActivity() == null || closeChatDialog != null) { return; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + if (reason == 0) { builder.setMessage(LocaleController.getString("ChannelCantOpenPrivate", R.string.ChannelCantOpenPrivate)); + } else if (reason == 1) { + builder.setMessage(LocaleController.getString("ChannelCantOpenNa", R.string.ChannelCantOpenNa)); + } else if (reason == 2) { + builder.setMessage(LocaleController.getString("ChannelCantOpenBanned", R.string.ChannelCantOpenBanned)); + } builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); showDialog(closeChatDialog = builder.create()); @@ -5349,14 +5861,22 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } else if (id == NotificationCenter.contactsDidLoaded) { updateContactStatus(); - updateSubtitle(); - updateSpamView(); + if (avatarContainer != null) { + avatarContainer.updateSubtitle(); + } } else if (id == NotificationCenter.encryptedChatUpdated) { TLRPC.EncryptedChat chat = (TLRPC.EncryptedChat) args[0]; if (currentEncryptedChat != null && chat.id == currentEncryptedChat.id) { currentEncryptedChat = chat; updateContactStatus(); updateSecretStatus(); + initStickers(); + if (chatActivityEnterView != null) { + chatActivityEnterView.setAllowStickersAndGifs(currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 23, currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46); + } + if (mentionsAdapter != null) { + mentionsAdapter.setNeedBotContext(!chatActivityEnterView.isEditingMessage() && (currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46)); + } } } else if (id == NotificationCenter.messagesReadEncrypted) { int encId = (Integer) args[0]; @@ -5379,14 +5899,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int count = chatListView.getChildCount(); for (int a = 0; a < count; a++) { View view = chatListView.getChildAt(a); - if (view instanceof ChatAudioCell) { - ChatAudioCell cell = (ChatAudioCell) view; - if (cell.getMessageObject() != null) { - cell.updateButtonState(false); - } - } else if (view instanceof ChatMusicCell) { - ChatMusicCell cell = (ChatMusicCell) view; - if (cell.getMessageObject() != null) { + if (view instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) view; + MessageObject messageObject = cell.getMessageObject(); + if (messageObject != null && (messageObject.isVoice() || messageObject.isMusic())) { cell.updateButtonState(false); } } @@ -5398,21 +5914,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int count = chatListView.getChildCount(); for (int a = 0; a < count; a++) { View view = chatListView.getChildAt(a); - if (view instanceof ChatAudioCell) { - ChatAudioCell cell = (ChatAudioCell) view; - if (cell.getMessageObject() != null && cell.getMessageObject().getId() == mid) { - cell.updateProgress(); - break; - } - } else if (view instanceof ChatMusicCell) { - ChatMusicCell cell = (ChatMusicCell) view; + if (view instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) view; if (cell.getMessageObject() != null && cell.getMessageObject().getId() == mid) { MessageObject playing = cell.getMessageObject(); MessageObject player = MediaController.getInstance().getPlayingMessageObject(); if (player != null) { - playing.audioProgress = player.audioProgress; - playing.audioProgressSec = player.audioProgressSec; - cell.updateProgress(); + playing.audioProgress = player.audioProgress; + playing.audioProgressSec = player.audioProgressSec; + cell.updateAudioProgress(); } break; } @@ -5441,6 +5951,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } cantDeleteMessagesCount = 0; actionBar.hideActionMode(); + updatePinnedMessageView(true); if (botButtons != null) { botButtons = null; @@ -5489,7 +6000,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not userBlocked = MessagesController.getInstance().blockedUsers.contains(currentUser.id); if (oldValue != userBlocked) { updateBottomOverlay(); - updateSpamView(); } } } else if (id == NotificationCenter.FileNewChunkAvailable) { @@ -5498,7 +6008,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (finalSize != 0 && dialog_id == messageObject.getDialogId()) { MessageObject currentObject = messagesDict[0].get(messageObject.getId()); if (currentObject != null) { - currentObject.messageOwner.media.video.size = (int) finalSize; + currentObject.messageOwner.media.document.size = (int) finalSize; updateVisibleRows(); } } @@ -5526,14 +6036,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not int count = chatListView.getChildCount(); for (int a = 0; a < count; a++) { View view = chatListView.getChildAt(a); - if (view instanceof ChatAudioCell) { - ChatAudioCell cell = (ChatAudioCell) view; - if (cell.getMessageObject() != null) { - cell.updateButtonState(false); - } - } else if (view instanceof ChatMusicCell) { - ChatMusicCell cell = (ChatMusicCell) view; - if (cell.getMessageObject() != null) { + if (view instanceof ChatMessageCell) { + ChatMessageCell cell = (ChatMessageCell) view; + MessageObject messageObject1 = cell.getMessageObject(); + if (messageObject1 != null && (messageObject1.isVoice() || messageObject1.isMusic())) { cell.updateButtonState(false); } } @@ -5557,12 +6063,20 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean changed = false; boolean mediaUpdated = false; ArrayList messageObjects = (ArrayList) args[1]; - for (MessageObject messageObject : messageObjects) { + for (int a = 0; a < messageObjects.size(); a++) { + MessageObject messageObject = messageObjects.get(a); MessageObject old = messagesDict[loadIndex].get(messageObject.getId()); + if (pinnedMessageObject != null && pinnedMessageObject.getId() == messageObject.getId()) { + pinnedMessageObject = messageObject; + updatePinnedMessageView(true); + } if (old != null) { if (!mediaUpdated && messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { mediaUpdated = true; } + if (old.replyMessageObject != null) { + messageObject.replyMessageObject = old.replyMessageObject; + } messagesDict[loadIndex].put(old.getId(), messageObject); int index = messages.indexOf(old); if (index >= 0) { @@ -5589,6 +6103,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (did == dialog_id) { updateVisibleRows(); } + } else if (id == NotificationCenter.didLoadedPinnedMessage) { + MessageObject message = (MessageObject) args[0]; + if (message.getDialogId() == dialog_id && info != null && info.pinned_msg_id == message.getId()) { + pinnedMessageObject = message; + loadingPinnedMessage = 0; + updatePinnedMessageView(true); + } } else if (id == NotificationCenter.didReceivedWebpages) { ArrayList arrayList = (ArrayList) args[0]; boolean updated = false; @@ -5608,7 +6129,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } if (updated) { updateVisibleRows(); - if (chatLayoutManager.findLastVisibleItemPosition() >= messages.size() - 1) { + if (chatLayoutManager != null && chatLayoutManager.findLastVisibleItemPosition() >= messages.size() - 1) { moveScrollToLastMessage(); } } @@ -5627,7 +6148,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not boolean updated = false; for (int a = 0; a < arrayList.size(); a++) { long mid = arrayList.get(a); - MessageObject currentMessage = messagesDict[0].get((int) mid); + MessageObject currentMessage = messagesDict[mergeDialogId == 0 ? 0 : 1].get((int) mid); if (currentMessage != null) { currentMessage.setContentIsRead(); updated = true; @@ -5641,14 +6162,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (classGuid == guid) { TLRPC.BotInfo info = (TLRPC.BotInfo) args[0]; if (currentEncryptedChat == null) { - if (!info.commands.isEmpty()) { + if (!info.commands.isEmpty() && !ChatObject.isChannel(currentChat)) { hasBotsCommands = true; } botInfo.put(info.user_id, info); if (chatAdapter != null) { chatAdapter.notifyItemChanged(0); } - if (mentionsAdapter != null) { + if (mentionsAdapter != null && (!ChatObject.isChannel(currentChat) || currentChat != null && currentChat.megagroup)) { mentionsAdapter.setBotInfo(botInfo); } if (chatActivityEnterView != null) { @@ -5718,12 +6239,59 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not updateVisibleRows(); } } + } else if (id == NotificationCenter.peerSettingsDidLoaded) { + long did = (Long) args[0]; + if (did == dialog_id) { + updateSpamView(); + } } else if (id == NotificationCenter.wallpaperChanged) { refreshWallpaper = true; } } + public boolean processSwitchButton(TLRPC.TL_keyboardButtonSwitchInline button) { + if (inlineReturn == 0) { + return false; + } + String query = "@" + currentUser.username + " " + button.query; + if (inlineReturn == dialog_id) { + inlineReturn = 0; + chatActivityEnterView.setFieldText(query); + } else { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString("dialog_" + inlineReturn, query); + editor.commit(); + if (parentLayout.fragmentsStack.size() > 1) { + BaseFragment prevFragment = parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 2); + if (prevFragment instanceof ChatActivity && ((ChatActivity) prevFragment).dialog_id == inlineReturn) { + finishFragment(); + } else { + Bundle bundle = new Bundle(); + int lower_part = (int) inlineReturn; + int high_part = (int) (inlineReturn >> 32); + if (lower_part != 0) { + if (lower_part > 0) { + bundle.putInt("user_id", lower_part); + } else if (lower_part < 0) { + bundle.putInt("chat_id", -lower_part); + } + } else { + bundle.putInt("enc_id", high_part); + } + /*ActionBarLayout parentLayout = ChatActivity.this.parentLayout; + if (lastFragment != null) { + NotificationCenter.getInstance().removeObserver(lastFragment, NotificationCenter.closeChats); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats);*/ + presentFragment(new ChatActivity(bundle), true); + } + } + } + return true; + } + private void updateSearchButtons(int mask) { if (searchUpItem != null) { searchUpItem.setEnabled((mask & 1) != 0); @@ -5735,29 +6303,33 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onTransitionAnimationStart(boolean isOpen, boolean backward) { - if (isOpen) { + NotificationCenter.getInstance().setAllowedNotificationsDutingAnimation(new int[]{NotificationCenter.chatInfoDidLoaded, NotificationCenter.dialogsNeedReload, + NotificationCenter.closeChats, NotificationCenter.messagesDidLoaded, NotificationCenter.botKeyboardDidLoaded/*, NotificationCenter.botInfoDidLoaded*/}); NotificationCenter.getInstance().setAnimationInProgress(true); + if (isOpen) { openAnimationEnded = false; } } @Override public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { - if (isOpen) { NotificationCenter.getInstance().setAnimationInProgress(false); + if (isOpen) { openAnimationEnded = true; int count = chatListView.getChildCount(); for (int a = 0; a < count; a++) { View view = chatListView.getChildAt(a); - if (view instanceof ChatMediaCell) { - ChatMediaCell cell = (ChatMediaCell) view; - cell.setAllowedToSetPhoto(true); + if (view instanceof ChatMessageCell) { + ((ChatMessageCell) view).setAllowedToSetPhoto(true); + } } - } - if (currentUser != null) { - MessagesController.getInstance().loadFullUser(currentUser, classGuid); + if (currentUser != null) { + MessagesController.getInstance().loadFullUser(currentUser, classGuid, false); } + if (Build.VERSION.SDK_INT >= 21) { + createChatAttachView(); + } } } @@ -5765,7 +6337,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not protected void onDialogDismiss(Dialog dialog) { if (closeChatDialog != null && dialog == closeChatDialog) { MessagesController.getInstance().deleteDialog(dialog_id, 0); - finishFragment(); + if (parentLayout != null && !parentLayout.fragmentsStack.isEmpty() && parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 1) != this) { + BaseFragment fragment = parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 1); + removeSelfFromStack(); + fragment.finishFragment(); + } else { + finishFragment(); + } } } @@ -5774,7 +6352,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } if (currentChat != null) { - if (ChatObject.isChannel(currentChat) && !currentChat.megagroup && !(currentChat instanceof TLRPC.TL_channelForbidden)) { + if (ChatObject.isChannel(currentChat) && !(currentChat instanceof TLRPC.TL_channelForbidden)) { if (ChatObject.isNotInChat(currentChat)) { bottomOverlayChatText.setText(LocaleController.getString("ChannelJoin", R.string.ChannelJoin)); } else { @@ -5785,7 +6363,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } } else { - bottomOverlayChatText.setText(LocaleController.getString("DeleteThisGroup", R.string.DeleteThisGroup)); + //bottomOverlayChatText.setText(LocaleController.getString("DeleteThisGroup", R.string.DeleteThisGroup)); + //plus + if (ChatObject.isLeftFromChat(currentChat)){ + bottomOverlayChatText.setText(LocaleController.getString("ReturnToThisGroup", R.string.ReturnToThisGroup)); + }else{ + bottomOverlayChatText.setText(LocaleController.getString("DeleteThisGroup", R.string.DeleteThisGroup)); + }// } } else { if (userBlocked) { @@ -5830,81 +6414,291 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } muteItem.setVisibility(View.VISIBLE); } + checkRaiseSensors(); + } + + public void showAlert(TLRPC.User user, String message) { + if (alertView == null || user == null || message == null) { + return; + } + + if (alertView.getTag() != null) { + alertView.setTag(null); + if (alertViewAnimator != null) { + alertViewAnimator.cancel(); + alertViewAnimator = null; + } + if (Build.VERSION.SDK_INT >= 11) { + alertView.setVisibility(View.VISIBLE); + alertViewAnimator = new AnimatorSetProxy(); + alertViewAnimator.playTogether(ObjectAnimatorProxy.ofFloat(alertView, "translationY", 0)); + alertViewAnimator.setDuration(200); + alertViewAnimator.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if (alertViewAnimator != null && alertViewAnimator.equals(animation)) { + alertView.clearAnimation(); + alertViewAnimator = null; + } + } + + @Override + public void onAnimationCancel(Object animation) { + if (alertViewAnimator != null && alertViewAnimator.equals(animation)) { + alertViewAnimator = null; + } + } + }); + alertViewAnimator.start(); + } else { + ViewProxy.setTranslationY(alertView, 0); + alertView.clearAnimation(); + alertView.setVisibility(View.VISIBLE); + } + } + alertNameTextView.setText(ContactsController.formatName(user.first_name, user.last_name)); + alertTextView.setText(Emoji.replaceEmoji(message.replace('\n', ' '), alertTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false)); + if (hideAlertViewRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(hideAlertViewRunnable); + } + AndroidUtilities.runOnUIThread(hideAlertViewRunnable = new Runnable() { + @Override + public void run() { + if (hideAlertViewRunnable != this) { + return; + } + if (alertView.getTag() == null) { + alertView.setTag(1); + if (alertViewAnimator != null) { + alertViewAnimator.cancel(); + alertViewAnimator = null; + } + if (Build.VERSION.SDK_INT >= 11) { + alertViewAnimator = new AnimatorSetProxy(); + alertViewAnimator.playTogether(ObjectAnimatorProxy.ofFloat(alertView, "translationY", -AndroidUtilities.dp(50))); + alertViewAnimator.setDuration(200); + alertViewAnimator.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if (alertViewAnimator != null && alertViewAnimator.equals(animation)) { + alertView.clearAnimation(); + alertView.setVisibility(View.GONE); + alertViewAnimator = null; + } + } + + @Override + public void onAnimationCancel(Object animation) { + if (alertViewAnimator != null && alertViewAnimator.equals(animation)) { + alertViewAnimator = null; + } + } + }); + alertViewAnimator.start(); + } else { + ViewProxy.setTranslationY(alertView, -AndroidUtilities.dp(50)); + alertView.clearAnimation(); + alertView.setVisibility(View.GONE); + } + } + } + }, 3000); + } + + private void hidePinnedMessageView(boolean animated) { + if (pinnedMessageView.getTag() == null) { + pinnedMessageView.setTag(1); + if (pinnedMessageViewAnimator != null) { + pinnedMessageViewAnimator.cancel(); + pinnedMessageViewAnimator = null; + } + if (Build.VERSION.SDK_INT >= 11 && animated) { + pinnedMessageViewAnimator = new AnimatorSetProxy(); + pinnedMessageViewAnimator.playTogether(ObjectAnimatorProxy.ofFloat(pinnedMessageView, "translationY", -AndroidUtilities.dp(50))); + pinnedMessageViewAnimator.setDuration(200); + pinnedMessageViewAnimator.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if (pinnedMessageViewAnimator != null && pinnedMessageViewAnimator.equals(animation)) { + pinnedMessageView.clearAnimation(); + pinnedMessageView.setVisibility(View.GONE); + pinnedMessageViewAnimator = null; + } + } + + @Override + public void onAnimationCancel(Object animation) { + if (pinnedMessageViewAnimator != null && pinnedMessageViewAnimator.equals(animation)) { + pinnedMessageViewAnimator = null; + } + } + }); + pinnedMessageViewAnimator.start(); + } else { + ViewProxy.setTranslationY(pinnedMessageView, -AndroidUtilities.dp(50)); + pinnedMessageView.clearAnimation(); + pinnedMessageView.setVisibility(View.GONE); + } + } + } + + private void updatePinnedMessageView(boolean animated) { + if (pinnedMessageView == null) { + return; + } + if (info != null) { + if (pinnedMessageObject != null && info.pinned_msg_id != pinnedMessageObject.getId()) { + pinnedMessageObject = null; + } + if (info.pinned_msg_id != 0 && pinnedMessageObject == null) { + pinnedMessageObject = messagesDict[0].get(info.pinned_msg_id); + } + } + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + if (info == null || info.pinned_msg_id == 0 || info.pinned_msg_id == preferences.getInt("pin_" + dialog_id, 0) || actionBar != null && actionBar.isActionModeShowed()) { + hidePinnedMessageView(animated); + } else { + if (pinnedMessageObject != null) { + if (pinnedMessageView.getTag() != null) { + pinnedMessageView.setTag(null); + if (pinnedMessageViewAnimator != null) { + pinnedMessageViewAnimator.cancel(); + pinnedMessageViewAnimator = null; + } + if (Build.VERSION.SDK_INT >= 11 && animated) { + pinnedMessageView.setVisibility(View.VISIBLE); + pinnedMessageViewAnimator = new AnimatorSetProxy(); + pinnedMessageViewAnimator.playTogether(ObjectAnimatorProxy.ofFloat(pinnedMessageView, "translationY", 0)); + pinnedMessageViewAnimator.setDuration(200); + pinnedMessageViewAnimator.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if (pinnedMessageViewAnimator != null && pinnedMessageViewAnimator.equals(animation)) { + pinnedMessageView.clearAnimation(); + pinnedMessageViewAnimator = null; + } + } + + @Override + public void onAnimationCancel(Object animation) { + if (pinnedMessageViewAnimator != null && pinnedMessageViewAnimator.equals(animation)) { + pinnedMessageViewAnimator = null; + } + } + }); + pinnedMessageViewAnimator.start(); + } else { + ViewProxy.setTranslationY(pinnedMessageView, 0); + pinnedMessageView.clearAnimation(); + pinnedMessageView.setVisibility(View.VISIBLE); + } + } + pinnedMessageNameTextView.setText(LocaleController.getString("PinnedMessage", R.string.PinnedMessage)); + if (pinnedMessageObject.messageText != null) { + String mess = pinnedMessageObject.messageText.toString(); + if (mess.length() > 150) { + mess = mess.substring(0, 150); + } + mess = mess.replace('\n', ' '); + pinnedMessageTextView.setText(Emoji.replaceEmoji(mess, pinnedMessageTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(14), false)); + } + } else { + hidePinnedMessageView(animated); + if (loadingPinnedMessage != info.pinned_msg_id) { + loadingPinnedMessage = info.pinned_msg_id; + MessagesQuery.loadPinnedMessage(currentChat.id, info.pinned_msg_id, true); + } + } + } + checkListViewPaddings(); } private void updateSpamView() { if (reportSpamView == null) { return; } - reportSpamUser = null; SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); - if (!messages.isEmpty() && !preferences.getBoolean("spam_" + dialog_id, false)) { - if (currentChat != null) { + boolean show = preferences.getInt("spam3_" + dialog_id, 0) == 2; + if (show) { + if (messages.isEmpty()) { + show = false; + } else { int count = messages.size() - 1; for (int a = count; a >= Math.max(count - 50, 0); a--) { MessageObject messageObject = messages.get(a); if (messageObject.isOut()) { - reportSpamUser = null; - } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatCreate) { - reportSpamUser = MessagesController.getInstance().getUser(messageObject.messageOwner.from_id); - } else if (messageObject.messageOwner.action instanceof TLRPC.TL_messageActionChatAddUser) { - if (messageObject.messageOwner.action.user_id == UserConfig.getClientUserId() || messageObject.messageOwner.action.users.contains(UserConfig.getClientUserId())) { - reportSpamUser = MessagesController.getInstance().getUser(messageObject.messageOwner.from_id); - } - } - } - if (reportSpamUser != null && ContactsController.getInstance().contactsDict.get(reportSpamUser.id) != null) { - reportSpamUser = null; - } - if (reportSpamUser != null) { - addToContactsButton.setVisibility(View.GONE); - reportSpamButton.setPadding(AndroidUtilities.dp(50), 0, AndroidUtilities.dp(50), 0); - reportSpamContainer.setLayoutParams(LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 1.0f, Gravity.LEFT | Gravity.TOP, 0, 0, 0, AndroidUtilities.dp(1))); - } - } else if (currentUser != null) { - if (!currentUser.bot && - currentUser.id / 1000 != 333 && currentUser.id / 1000 != 777 - && !UserObject.isDeleted(currentUser) - && !userBlocked - && !ContactsController.getInstance().isLoadingContacts() - && (currentUser.phone == null || currentUser.phone.length() == 0 || ContactsController.getInstance().contactsDict.get(currentUser.id) == null)) { - if (currentUser.phone != null && currentUser.phone.length() != 0) { - reportSpamButton.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(50), 0); - addToContactsButton.setVisibility(View.VISIBLE); - reportSpamContainer.setLayoutParams(LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0.5f, Gravity.LEFT | Gravity.TOP, 0, 0, 0, AndroidUtilities.dp(1))); - } else { - reportSpamButton.setPadding(AndroidUtilities.dp(50), 0, AndroidUtilities.dp(50), 0); - addToContactsButton.setVisibility(View.GONE); - reportSpamContainer.setLayoutParams(LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 1.0f, Gravity.LEFT | Gravity.TOP, 0, 0, 0, AndroidUtilities.dp(1))); - } - reportSpamUser = currentUser; - } - if (reportSpamUser != null) { - int count = messages.size() - 1; - for (int a = count; a >= Math.max(count - 50, 0); a--) { - MessageObject messageObject = messages.get(a); - if (messageObject.isOut()) { - reportSpamUser = null; - break; - } + show = false; + break; } } } } - if (reportSpamUser != null) { - if (reportSpamView.getVisibility() != View.VISIBLE) { - reportSpamView.setVisibility(View.VISIBLE); + if (!show) { + if (reportSpamView.getTag() == null) { reportSpamView.setTag(1); - chatListView.setTopGlowOffset(AndroidUtilities.dp(48)); - chatListView.setPadding(0, AndroidUtilities.dp(52), 0, AndroidUtilities.dp(3)); + if (Build.VERSION.SDK_INT >= 11) { + if (reportSpamViewAnimator != null) { + reportSpamViewAnimator.cancel(); + } + reportSpamViewAnimator = new AnimatorSetProxy(); + reportSpamViewAnimator.playTogether(ObjectAnimatorProxy.ofFloat(reportSpamView, "translationY", -AndroidUtilities.dp(50))); + reportSpamViewAnimator.setDuration(200); + reportSpamViewAnimator.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if (reportSpamViewAnimator != null && reportSpamViewAnimator.equals(animation)) { + reportSpamView.clearAnimation(); + reportSpamView.setVisibility(View.GONE); + reportSpamViewAnimator = null; + } + } + + @Override + public void onAnimationCancel(Object animation) { + if (reportSpamViewAnimator != null && reportSpamViewAnimator.equals(animation)) { + reportSpamViewAnimator = null; + } + } + }); + reportSpamViewAnimator.start(); + } else { + reportSpamView.setVisibility(View.GONE); + } } - } else if (reportSpamView.getVisibility() != View.GONE) { - reportSpamView.setVisibility(View.GONE); + } else { + if (reportSpamView.getTag() != null) { reportSpamView.setTag(null); - chatListView.setPadding(0, AndroidUtilities.dp(4), 0, AndroidUtilities.dp(3)); - chatListView.setTopGlowOffset(0); - chatLayoutManager.scrollToPositionWithOffset(messages.size() - 1, -100000 - chatListView.getPaddingTop()); + if (Build.VERSION.SDK_INT >= 11) { + reportSpamView.setVisibility(View.VISIBLE); + if (reportSpamViewAnimator != null) { + reportSpamViewAnimator.cancel(); + } + reportSpamViewAnimator = new AnimatorSetProxy(); + reportSpamViewAnimator.playTogether(ObjectAnimatorProxy.ofFloat(reportSpamView, "translationY", 0)); + reportSpamViewAnimator.setDuration(200); + reportSpamViewAnimator.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if (reportSpamViewAnimator != null && reportSpamViewAnimator.equals(animation)) { + reportSpamView.clearAnimation(); + reportSpamViewAnimator = null; + } + } + + @Override + public void onAnimationCancel(Object animation) { + if (reportSpamViewAnimator != null && reportSpamViewAnimator.equals(animation)) { + reportSpamViewAnimator = null; + } + } + }); + reportSpamViewAnimator.start(); + } else { + reportSpamView.setVisibility(View.VISIBLE); + } + } } + checkListViewPaddings(); } private void updateContactStatus() { @@ -5924,27 +6718,62 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not || ContactsController.getInstance().isLoadingContacts() || (currentUser.phone != null && currentUser.phone.length() != 0 && ContactsController.getInstance().contactsDict.get(currentUser.id) != null && (ContactsController.getInstance().contactsDict.size() != 0 || !ContactsController.getInstance().isLoadingContacts()))) { addContactItem.setVisibility(View.GONE); - reportSpamView.setVisibility(View.GONE); - chatListView.setTopGlowOffset(0); - chatListView.setPadding(0, AndroidUtilities.dp(4), 0, AndroidUtilities.dp(3)); } else { addContactItem.setVisibility(View.VISIBLE); - if (reportSpamView.getTag() != null) { - reportSpamView.setVisibility(View.VISIBLE); - chatListView.setPadding(0, AndroidUtilities.dp(52), 0, AndroidUtilities.dp(3)); - chatListView.setTopGlowOffset(AndroidUtilities.dp(48)); - } if (currentUser.phone != null && currentUser.phone.length() != 0) { addContactItem.setText(LocaleController.getString("AddToContacts", R.string.AddToContacts)); + reportSpamButton.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(50), 0); addToContactsButton.setVisibility(View.VISIBLE); reportSpamContainer.setLayoutParams(LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 0.5f, Gravity.LEFT | Gravity.TOP, 0, 0, 0, AndroidUtilities.dp(1))); } else { addContactItem.setText(LocaleController.getString("ShareMyContactInfo", R.string.ShareMyContactInfo)); addToContactsButton.setVisibility(View.GONE); + reportSpamButton.setPadding(AndroidUtilities.dp(50), 0, AndroidUtilities.dp(50), 0); reportSpamContainer.setLayoutParams(LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 1.0f, Gravity.LEFT | Gravity.TOP, 0, 0, 0, AndroidUtilities.dp(1))); } } } + checkListViewPaddings(); + } + + private void checkListViewPaddings() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + int firstVisPos = chatLayoutManager.findLastVisibleItemPosition(); + int top = 0; + if (firstVisPos != RecyclerView.NO_POSITION) { + View firstVisView = chatLayoutManager.findViewByPosition(firstVisPos); + top = ((firstVisView == null) ? 0 : firstVisView.getTop()) - chatListView.getPaddingTop(); + } + if (chatListView.getPaddingTop() != AndroidUtilities.dp(52) && (pinnedMessageView != null && pinnedMessageView.getTag() == null || reportSpamView != null && reportSpamView.getTag() == null)) { + chatListView.setPadding(0, AndroidUtilities.dp(52), 0, AndroidUtilities.dp(3)); + chatListView.setTopGlowOffset(AndroidUtilities.dp(48)); + top -= AndroidUtilities.dp(48); + } else if (chatListView.getPaddingTop() != AndroidUtilities.dp(4) && (pinnedMessageView == null || pinnedMessageView.getTag() != null) && (reportSpamView == null || reportSpamView.getTag() != null)) { + chatListView.setPadding(0, AndroidUtilities.dp(4), 0, AndroidUtilities.dp(3)); + chatListView.setTopGlowOffset(0); + top += AndroidUtilities.dp(48); + } else { + firstVisPos = RecyclerView.NO_POSITION; + } + if (firstVisPos != RecyclerView.NO_POSITION) { + chatLayoutManager.scrollToPositionWithOffset(firstVisPos, top); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + private void checkRaiseSensors() { + if (!ApplicationLoader.mainInterfacePaused && (bottomOverlayChat == null || bottomOverlayChat.getVisibility() != View.VISIBLE) && (bottomOverlay == null || bottomOverlay.getVisibility() != View.VISIBLE)) { + MediaController.getInstance().setAllowStartRecord(true); + } else { + MediaController.getInstance().setAllowStartRecord(false); + } } @Override @@ -5952,13 +6781,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not super.onResume(); AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); + MediaController.getInstance().startRaiseToEarSensors(this); + checkRaiseSensors(); checkActionBarMenu(); if (replyImageLocation != null && replyImageView != null) { replyImageView.setImage(replyImageLocation, "50_50", (Drawable) null); } - NotificationsController.getInstance().setOpennedDialogId(dialog_id); + NotificationsController.getInstance().setOpenedDialogId(dialog_id); if (scrollToTopOnResume) { if (scrollToTopUnReadOnResume && scrollToMessage != null) { if (chatListView != null) { @@ -5992,7 +6823,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not readWhenResume = false; MessagesController.getInstance().markDialogAsRead(dialog_id, messages.get(0).getId(), readWithMid, readWithDate, true, false); } - checkScrollForLoad(); + checkScrollForLoad(false); if (wasPaused) { wasPaused = false; if (chatAdapter != null) { @@ -6000,7 +6831,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - fixLayout(true); + fixLayout(); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); if (chatActivityEnterView.getFieldText() == null) { String lastMessageText = preferences.getString("dialog_" + dialog_id, null); @@ -6063,9 +6894,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not }); } - chatListView.setOnItemLongClickListener(onItemLongClickListener); - chatListView.setOnItemClickListener(onItemClickListener); - chatListView.setLongClickable(true); + if (chatActivityEnterView == null || !chatActivityEnterView.isEditingMessage()) { + chatListView.setOnItemLongClickListener(onItemLongClickListener); + chatListView.setOnItemClickListener(onItemClickListener); + chatListView.setLongClickable(true); + } + updateTheme(); } @@ -6099,10 +6933,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not actionBar.setBackgroundDrawable(gd); } int nameColor = themePrefs.getInt("chatNameColor", 0xffffffff); - nameTextView.setTextColor(nameColor); - nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, themePrefs.getInt("chatNameSize", 18)); + avatarContainer.setTitleColor(nameColor); + avatarContainer.setTitleSize(themePrefs.getInt("chatNameSize", 18)); + avatarContainer.setSubtitleColor(themePrefs.getInt("chatStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40))); + avatarContainer.setSubtitleSize(themePrefs.getInt("chatStatusSize", 14)); + //nameTextView.setTextColor(nameColor); + //nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, themePrefs.getInt("chatNameSize", 18)); //onlineTextView.setTextColor(themePrefs.getInt("chatStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40))); - onlineTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, themePrefs.getInt("chatStatusSize", 14)); + //onlineTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, themePrefs.getInt("chatStatusSize", 14)); int iColor = themePrefs.getInt("chatHeaderIconsColor", 0xffffffff); if(getParentActivity() != null) { Drawable mute = getParentActivity().getResources().getDrawable(R.drawable.mute_blue); @@ -6141,14 +6979,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public void onPause() { super.onPause(); + MediaController.getInstance().stopRaiseToEarSensors(this); if (menuItem != null) { menuItem.closeSubMenu(); } paused = true; wasPaused = true; - NotificationsController.getInstance().setOpennedDialogId(0); + NotificationsController.getInstance().setOpenedDialogId(0); if (chatActivityEnterView != null) { chatActivityEnterView.onPause(); + if (!chatActivityEnterView.isEditingMessage()) { String text = chatActivityEnterView.getFieldText(); if (text != null && !text.equals("@gif ")) { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); @@ -6156,6 +6996,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not editor.putString("dialog_" + dialog_id, text); editor.commit(); } + } chatActivityEnterView.setFieldFocused(false); } if (replyingMessageObject != null) { @@ -6205,29 +7046,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not MediaController.getInstance().setLastEncryptedChatParams(chatEnterTime, chatLeaveTime, currentEncryptedChat, visibleMessages); } - private void fixLayout(final boolean resume) { - if (avatarContainer != null) { - avatarContainer.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - if (avatarContainer != null) { - avatarContainer.getViewTreeObserver().removeOnPreDrawListener(this); - } + private boolean fixLayoutInternal() { if (!AndroidUtilities.isTablet() && ApplicationLoader.applicationContext.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { selectedMessagesCountTextView.setTextSize(18); + actionModeTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); } else { selectedMessagesCountTextView.setTextSize(20); + actionModeTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); } - int padding = (ActionBar.getCurrentActionBarHeight() - AndroidUtilities.dp(48)) / 2; - if (avatarContainer.getPaddingTop() != padding) { - avatarContainer.setPadding(avatarContainer.getPaddingLeft(), padding, avatarContainer.getPaddingRight(), padding); - } - FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) avatarContainer.getLayoutParams(); - if (layoutParams.topMargin != (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0)) { - layoutParams.topMargin = (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); - avatarContainer.setLayoutParams(layoutParams); - } if (AndroidUtilities.isTablet()) { SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); int color = themePrefs.getInt("chatHeaderIconsColor", 0xffffffff); @@ -6242,7 +7069,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not ((ViewGroup) fragmentView).addView(playerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 39, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); } } else { - //actionBar.setBackButtonDrawable(new BackDrawable(true)); + actionBar.setBackButtonDrawable(new BackDrawable(parentLayout == null || parentLayout.fragmentsStack.isEmpty() || parentLayout.fragmentsStack.get(0) == ChatActivity.this || parentLayout.fragmentsStack.size() == 1)); Drawable back = new BackDrawable(false); ((BackDrawable) back).setColor(color); @@ -6257,13 +7084,24 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } return true; } + + private void fixLayout() { + if (avatarContainer != null) { + avatarContainer.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + if (avatarContainer != null) { + avatarContainer.getViewTreeObserver().removeOnPreDrawListener(this); + } + return fixLayoutInternal(); + } }); } } @Override public void onConfigurationChanged(android.content.res.Configuration newConfig) { - fixLayout(false); + fixLayout(); } private void switchImportantMode(MessageObject searchBeforeMessage) { @@ -6322,8 +7160,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } - radioButton.setChecked(!radioButton.isChecked(), true); - channelMessagesImportant = radioButton.isChecked() ? 1 : 2; + avatarContainer.setRadioChecked(!avatarContainer.isRadioChecked(), true); + channelMessagesImportant = avatarContainer.isRadioChecked() ? 1 : 2; SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); preferences.edit().putInt("important_" + dialog_id, channelMessagesImportant).commit(); waitingForImportantLoad = true; @@ -6336,6 +7174,141 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + private void createDeleteMessagesAlert(final MessageObject finalSelectedObject) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.formatString("AreYouSureDeleteMessages", R.string.AreYouSureDeleteMessages, LocaleController.formatPluralString("messages", finalSelectedObject != null ? 1 : selectedMessagesIds[0].size() + selectedMessagesIds[1].size()))); + builder.setTitle(LocaleController.getString("Message", R.string.Message)); + + final boolean[] checks = new boolean[3]; + TLRPC.User user = null; + if (currentChat != null && currentChat.megagroup) { + if (finalSelectedObject != null) { + if (finalSelectedObject.messageOwner.action == null || finalSelectedObject.messageOwner.action instanceof TLRPC.TL_messageActionEmpty) { + user = MessagesController.getInstance().getUser(finalSelectedObject.messageOwner.from_id); + } + } else { + int from_id = -1; + for (int a = 1; a >= 0; a--) { + int channelId = 0; + for (HashMap.Entry entry : selectedMessagesIds[a].entrySet()) { + MessageObject msg = entry.getValue(); + if (from_id == -1) { + from_id = msg.messageOwner.from_id; + } + if (from_id < 0 || from_id != msg.messageOwner.from_id) { + from_id = -2; + break; + } + } + if (from_id == -2) { + break; + } + } + if (from_id != -1) { + user = MessagesController.getInstance().getUser(from_id); + } + } + if (user != null && user.id != UserConfig.getClientUserId()) { + FrameLayout frameLayout = new FrameLayout(getParentActivity()); + if (Build.VERSION.SDK_INT >= 21) { + frameLayout.setPadding(0, AndroidUtilities.dp(8), 0, 0); + } + for (int a = 0; a < 3; a++) { + CheckBoxCell cell = new CheckBoxCell(getParentActivity()); + cell.setBackgroundResource(R.drawable.list_selector); + cell.setTag(a); + if (Build.VERSION.SDK_INT < 11) { + cell.setTextColor(0xffffffff); + } + if (a == 0) { + cell.setText(LocaleController.getString("DeleteBanUser", R.string.DeleteBanUser), "", false, false); + } else if (a == 1) { + cell.setText(LocaleController.getString("DeleteReportSpam", R.string.DeleteReportSpam), "", false, false); + } else if (a == 2) { + cell.setText(LocaleController.formatString("DeleteAllFrom", R.string.DeleteAllFrom, ContactsController.formatName(user.first_name, user.last_name)), "", false, false); + } + cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(8) : 0, 0, LocaleController.isRTL ? 0 : AndroidUtilities.dp(8), 0); + frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 8, 48 * a, 8, 0)); + cell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + CheckBoxCell cell = (CheckBoxCell) v; + Integer num = (Integer) cell.getTag(); + checks[num] = !checks[num]; + cell.setChecked(checks[num], true); + } + }); + } + builder.setView(frameLayout); + } else { + user = null; + } + } + final TLRPC.User userFinal = user; + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + ArrayList ids = null; + if (finalSelectedObject != null) { + ids = new ArrayList<>(); + ids.add(finalSelectedObject.getId()); + ArrayList random_ids = null; + if (currentEncryptedChat != null && finalSelectedObject.messageOwner.random_id != 0 && finalSelectedObject.type != 10) { + random_ids = new ArrayList<>(); + random_ids.add(finalSelectedObject.messageOwner.random_id); + } + MessagesController.getInstance().deleteMessages(ids, random_ids, currentEncryptedChat, finalSelectedObject.messageOwner.to_id.channel_id); + } else { + for (int a = 1; a >= 0; a--) { + ids = new ArrayList<>(selectedMessagesIds[a].keySet()); + ArrayList random_ids = null; + int channelId = 0; + if (!ids.isEmpty()) { + MessageObject msg = selectedMessagesIds[a].get(ids.get(0)); + if (channelId == 0 && msg.messageOwner.to_id.channel_id != 0) { + channelId = msg.messageOwner.to_id.channel_id; + } + } + if (currentEncryptedChat != null) { + random_ids = new ArrayList<>(); + for (HashMap.Entry entry : selectedMessagesIds[a].entrySet()) { + MessageObject msg = entry.getValue(); + if (msg.messageOwner.random_id != 0 && msg.type != 10) { + random_ids.add(msg.messageOwner.random_id); + } + } + } + MessagesController.getInstance().deleteMessages(ids, random_ids, currentEncryptedChat, channelId); + } + actionBar.hideActionMode(); + updatePinnedMessageView(true); + } + if (userFinal != null) { + if (checks[0]) { + MessagesController.getInstance().deleteUserFromChat(currentChat.id, userFinal, info); + } + if (checks[1]) { + TLRPC.TL_channels_reportSpam req = new TLRPC.TL_channels_reportSpam(); + req.channel = MessagesController.getInputChannel(currentChat); + req.user_id = MessagesController.getInputUser(userFinal); + req.id = ids; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }); + } + if (checks[2]) { + MessagesController.getInstance().deleteUserChannelHistory(currentChat, userFinal, 0); + } + } + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } + private void createMenu(View v, boolean single) { if (actionBar.isActionModeShowed()) { return; @@ -6351,10 +7324,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } final int type = getMessageType(message); - if (channelMessagesImportant == 2 && message.getId() == 0 && message.contentType == 4 && message.type == 10 && message.messageOwner.from_id != 0) { + if (channelMessagesImportant == 2 && message.getId() == 0 && message.contentType == 1 && message.type == 10 && message.messageOwner.from_id != 0) { switchImportantMode(message); return; } + if (single && message.messageOwner.action instanceof TLRPC.TL_messageActionPinMessage) { + scrollToMessageId(message.messageOwner.reply_to_msg_id, 0, true, 0); + return; + } selectedObject = null; forwaringMessage = null; @@ -6364,12 +7341,24 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } cantDeleteMessagesCount = 0; actionBar.hideActionMode(); + updatePinnedMessageView(true); boolean allowChatActions = true; - if (type == 1 && message.getDialogId() == mergeDialogId || message.getId() < 0 || isBroadcast || currentChat != null && (ChatObject.isNotInChat(currentChat) || ChatObject.isChannel(currentChat) && !currentChat.creator && !currentChat.editor && !currentChat.megagroup)) { + boolean allowPin = message.getDialogId() != mergeDialogId && message.getId() > 0 && ChatObject.isChannel(currentChat) && currentChat.megagroup && (currentChat.creator || currentChat.editor) && (message.messageOwner.action == null || message.messageOwner.action instanceof TLRPC.TL_messageActionEmpty); + boolean allowUnpin = message.getDialogId() != mergeDialogId && info != null && info.pinned_msg_id == message.getId() && (currentChat.creator || currentChat.editor); + boolean allowEdit = message.canEditMessage(currentChat) && !chatActivityEnterView.hasAudioToSend(); + if (currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) < 46 || type == 1 && message.getDialogId() == mergeDialogId || currentEncryptedChat == null && message.getId() < 0 || isBroadcast || currentChat != null && (ChatObject.isNotInChat(currentChat) || ChatObject.isChannel(currentChat) && !currentChat.creator && !currentChat.editor && !currentChat.megagroup)) { allowChatActions = false; } + boolean hasSign = BuildVars.DEBUG_VERSION & !message.isOutOwner() && message.messageOwner.from_id > 0 && message.messageOwner.post; + if(hasSign){ + TLRPC.User signUser = MessagesController.getInstance().getUser(message.messageOwner.from_id); + if(signUser == null || UserObject.isDeleted(signUser) || signUser.username == null) { + hasSign = false; + } + } + if (single || type < 2 || type == 20) { if (type >= 0) { selectedObject = message; @@ -6392,6 +7381,21 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not items.add(LocaleController.getString("Reply", R.string.Reply)); options.add(8); } + if (directShareToMenu) { + items.add(LocaleController.getString("DirectShare", R.string.DirectShare)); + options.add(98); + } + if (allowUnpin) { + items.add(LocaleController.getString("UnpinMessage", R.string.UnpinMessage)); + options.add(14); + } else if (allowPin) { + items.add(LocaleController.getString("PinMessage", R.string.PinMessage)); + options.add(13); + } + if (allowEdit) { + items.add(LocaleController.getString("Edit", R.string.Edit)); + options.add(12); + } if (message.canDeleteMessage(currentChat)) { items.add(LocaleController.getString("Delete", R.string.Delete)); options.add(1); @@ -6415,23 +7419,39 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not items.add(LocaleController.getString("Reply", R.string.Reply)); options.add(8); } - if (type == 3) { + if (directShareToMenu) { + items.add(LocaleController.getString("DirectShare", R.string.DirectShare)); + options.add(98); + } + if (selectedObject.type == 0 || selectedObject.caption != null) { items.add(LocaleController.getString("Copy", R.string.Copy)); options.add(3); + } + if (type == 3) { if (selectedObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage && MessageObject.isNewGifDocument(selectedObject.messageOwner.media.webpage.document)) { items.add(LocaleController.getString("SaveToGIFs", R.string.SaveToGIFs)); options.add(11); } } else if (type == 4) { - if (selectedObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { - if (MessageObject.isNewGifDocument(selectedObject.messageOwner.media.document)) { + if (selectedObject.isVideo()) { + items.add(LocaleController.getString("SaveToGallery", R.string.SaveToGallery)); + options.add(4); + items.add(LocaleController.getString("ShareFile", R.string.ShareFile)); + options.add(6); + } else if (selectedObject.isMusic()) { + items.add(LocaleController.getString("SaveToMusic", R.string.SaveToMusic)); + options.add(10); + items.add(LocaleController.getString("ShareFile", R.string.ShareFile)); + options.add(6); + } else if (selectedObject.getDocument() != null) { + if (MessageObject.isNewGifDocument(selectedObject.getDocument())) { items.add(LocaleController.getString("SaveToGIFs", R.string.SaveToGIFs)); options.add(11); } - items.add(selectedObject.isMusic() ? LocaleController.getString("SaveToMusic", R.string.SaveToMusic) : LocaleController.getString("SaveToDownloads", R.string.SaveToDownloads)); + items.add(LocaleController.getString("SaveToDownloads", R.string.SaveToDownloads)); options.add(10); items.add(LocaleController.getString("ShareFile", R.string.ShareFile)); - options.add(4); + options.add(6); } else { items.add(LocaleController.getString("SaveToGallery", R.string.SaveToGallery)); options.add(4); @@ -6442,45 +7462,90 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not items.add(LocaleController.getString("ApplyTheme", R.string.ApplyTheme)); options.add(55); items.add(LocaleController.getString("ShareFile", R.string.ShareFile)); - options.add(4); + options.add(6); } else if (type == 6) { items.add(LocaleController.getString("SaveToGallery", R.string.SaveToGallery)); options.add(7); - items.add(selectedObject.isMusic() ? LocaleController.getString("SaveToMusic", R.string.SaveToMusic) : LocaleController.getString("SaveToDownloads", R.string.SaveToDownloads)); + items.add(LocaleController.getString("SaveToDownloads", R.string.SaveToDownloads)); options.add(10); items.add(LocaleController.getString("ShareFile", R.string.ShareFile)); options.add(6); } else if (type == 7) { items.add(LocaleController.getString("AddToStickers", R.string.AddToStickers)); options.add(9); + } else if (type == 8) { + TLRPC.User user = MessagesController.getInstance().getUser(selectedObject.messageOwner.media.user_id); + if (user != null && user.id != UserConfig.getClientUserId() && ContactsController.getInstance().contactsDict.get(user.id) == null) { + items.add(LocaleController.getString("AddContactTitle", R.string.AddContactTitle)); + options.add(15); + } + if (selectedObject.messageOwner.media.phone_number != null || selectedObject.messageOwner.media.phone_number.length() != 0) { + items.add(LocaleController.getString("Copy", R.string.Copy)); + options.add(16); + items.add(LocaleController.getString("Call", R.string.Call)); + options.add(17); + } } items.add(LocaleController.getString("Forward", R.string.Forward)); options.add(22); - //items.add(LocaleController.getString("Forward", R.string.Forward)); if(selectedObject.messageOwner.media != null && selectedObject.messageOwner.media.caption != null && selectedObject.messageOwner.media.caption.length() > 0){ }else { items.add(LocaleController.getString("ForwardNoQuote", R.string.ForwardNoQuote)); options.add(2); } + if (allowUnpin) { + items.add(LocaleController.getString("UnpinMessage", R.string.UnpinMessage)); + options.add(14); + } else if (allowPin) { + items.add(LocaleController.getString("PinMessage", R.string.PinMessage)); + options.add(13); + } + if (allowEdit) { + items.add(LocaleController.getString("Edit", R.string.Edit)); + options.add(12); + } if (message.canDeleteMessage(currentChat)) { items.add(LocaleController.getString("Delete", R.string.Delete)); options.add(1); } + if(hasSign) { + //CharSequence name[] = UserObject.getUserName(signUser).split("\\s"); + //CharSequence cs = name.length < 2 ? name[0] : name[0] + " " + name[1]; + //if(cs.length() > 26)cs = cs.subSequence(0, 25) + " ..."; + TLRPC.User signUser = MessagesController.getInstance().getUser(message.messageOwner.from_id); + items.add(signUser.username); + options.add(99); + } } else { - if (type == 3) { + if (allowChatActions) { + items.add(LocaleController.getString("Reply", R.string.Reply)); + options.add(8); + } + if (selectedObject.type == 0 || selectedObject.caption != null) { items.add(LocaleController.getString("Copy", R.string.Copy)); options.add(3); - } else if (type == 4) { - if (selectedObject.messageOwner.media instanceof TLRPC.TL_messageMediaDocument) { - items.add(selectedObject.isMusic() ? LocaleController.getString("SaveToMusic", R.string.SaveToMusic) : LocaleController.getString("SaveToDownloads", R.string.SaveToDownloads)); + } + if (type == 4) { + if (selectedObject.isVideo()) { + items.add(LocaleController.getString("SaveToGallery", R.string.SaveToGallery)); + options.add(4); + items.add(LocaleController.getString("ShareFile", R.string.ShareFile)); + options.add(6); + } else if (selectedObject.isMusic()) { + items.add(LocaleController.getString("SaveToMusic", R.string.SaveToMusic)); options.add(10); items.add(LocaleController.getString("ShareFile", R.string.ShareFile)); - options.add(4); + options.add(6); + } else if (!selectedObject.isVideo() && selectedObject.getDocument() != null) { + items.add(LocaleController.getString("SaveToDownloads", R.string.SaveToDownloads)); + options.add(10); + items.add(LocaleController.getString("ShareFile", R.string.ShareFile)); + options.add(6); } else { items.add(LocaleController.getString("SaveToGallery", R.string.SaveToGallery)); options.add(4); - } + } } else if (type == 5) { items.add(LocaleController.getString("ApplyLocalizationFile", R.string.ApplyLocalizationFile)); options.add(5); @@ -6509,8 +7574,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } }); - builder.setTitle(LocaleController.getString("Message", R.string.Message)); - //SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + //builder.setTitle(LocaleController.getString("Message", R.string.Message)); + int d = selectedObject != null && selectedObject.messageOwner.edit_date > 0 ? selectedObject.messageOwner.edit_date : 0; + builder.setTitle(LocaleController.getString("Message", R.string.Message) + (d > 0 ? " " + LocaleController.getString("Edited", R.string.Edited) + ": " + LocaleController.getInstance().formatterDay.format((long) (d) * 1000) : "")); + if(selectedObject.messageOwner.media != null && selectedObject.type != 13) { + String name = FileLoader.getDocumentFileName(selectedObject.messageOwner.media.document).replace("\n", " "); + if (name.length() > 0) { + if(name.length() > 50)name = name.substring(0, 50) + "..." + name.substring(name.length() - 3, name.length()); + builder.setTitle(name); + } + } SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); if(!plusPreferences.getBoolean("disableMessageClick", false) || type != 3){ showDialog(builder.create()); @@ -6518,7 +7591,22 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } return; } + final ActionBarMenu actionMode = actionBar.createActionMode(); + View item = actionMode.getItem(forward); + if (item != null) { + item.setVisibility(View.VISIBLE); + } + item = actionMode.getItem(delete); + if (item != null) { + item.setVisibility(View.VISIBLE); + } + item = actionMode.getItem(edit_done); + if (item != null) { + item.setVisibility(View.GONE); + } + actionBar.showActionMode(); + updatePinnedMessageView(true); if (Build.VERSION.SDK_INT >= 11) { AnimatorSetProxy animatorSet = new AnimatorSetProxy(); @@ -6542,226 +7630,412 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (selectedObject == null) { return; } - if (option == 0) { - if (SendMessagesHelper.getInstance().retrySendMessage(selectedObject, false)) { - moveScrollToLastMessage(); - } - } else if (option == 1) { - if (getParentActivity() == null) { - return; - } - final MessageObject finalSelectedObject = selectedObject; - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.formatString("AreYouSureDeleteMessages", R.string.AreYouSureDeleteMessages, LocaleController.formatPluralString("messages", 1))); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - ArrayList ids = new ArrayList<>(); - ids.add(finalSelectedObject.getId()); - removeUnreadPlane(); - ArrayList random_ids = null; - if (currentEncryptedChat != null && finalSelectedObject.messageOwner.random_id != 0 && finalSelectedObject.type != 10) { - random_ids = new ArrayList<>(); - random_ids.add(finalSelectedObject.messageOwner.random_id); - } - MessagesController.getInstance().deleteMessages(ids, random_ids, currentEncryptedChat, finalSelectedObject.messageOwner.to_id.channel_id); + switch (option) { + case 0: { + if (SendMessagesHelper.getInstance().retrySendMessage(selectedObject, false)) { + moveScrollToLastMessage(); } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - } else if (option == 2 || option == 22) { - if (option == 22) { - QuoteForward = true; - } else { - QuoteForward = false; - } - forwaringMessage = selectedObject; - Bundle args = new Bundle(); - args.putBoolean("onlySelect", true); - args.putInt("dialogsType", 1); - DialogsActivity fragment = new DialogsActivity(args); - fragment.setDelegate(this); - presentFragment(fragment); - } else if (option == 3) { - try { - if (Build.VERSION.SDK_INT < 11) { - android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - clipboard.setText(selectedObject.messageText); - } else { - android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData.newPlainText("label", selectedObject.messageText); - clipboard.setPrimaryClip(clip); - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } else if (option == 4) { - String path = selectedObject.messageOwner.attachPath; - if (path != null && path.length() > 0) { - File temp = new File(path); - if (!temp.exists()) { - path = null; + break; } - } - if (path == null || path.length() == 0) { - path = FileLoader.getPathToMessage(selectedObject.messageOwner).toString(); - } - if (selectedObject.type == 3 || selectedObject.type == 1) { - if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - getParentActivity().requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 4); + case 1: { + if (getParentActivity() == null) { + selectedObject = null; return; } - MediaController.saveFile(path, getParentActivity(), selectedObject.type == 3 ? 1 : 0, null); - } else if (selectedObject.type == 8 || selectedObject.type == 9 || selectedObject.type == 14) { - Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType(selectedObject.messageOwner.media.document.mime_type); - intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(path))); - getParentActivity().startActivityForResult(Intent.createChooser(intent, LocaleController.getString("ShareFile", R.string.ShareFile)), 500); - } - } else if (option == 5) { - File locFile = null; - if (selectedObject.messageOwner.attachPath != null && selectedObject.messageOwner.attachPath.length() != 0) { - File f = new File(selectedObject.messageOwner.attachPath); - if (f.exists()) { - locFile = f; + createDeleteMessagesAlert(selectedObject); + break; } - } - if (locFile == null) { - File f = FileLoader.getPathToMessage(selectedObject.messageOwner); - if (f.exists()) { - locFile = f; - } - } - if (locFile != null) { - if (LocaleController.getInstance().applyLanguageFile(locFile)) { - presentFragment(new LanguageSelectActivity()); + case 2: + case 22: { + /*if (option == 22) { + QuoteForward = true; } else { - if (getParentActivity() == null) { - return; + QuoteForward = false; + }*/ + QuoteForward = option == 22; + forwaringMessage = selectedObject; + Bundle args = new Bundle(); + args.putBoolean("onlySelect", true); + args.putInt("dialogsType", 1); + DialogsActivity fragment = new DialogsActivity(args); + fragment.setDelegate(this); + presentFragment(fragment); + break; + } + case 3: { + try { + CharSequence str; + if (selectedObject.type == 0 && selectedObject.messageOwner.message != null) { + str = selectedObject.messageOwner.message; + } else if (selectedObject.messageOwner.media != null && selectedObject.messageOwner.media.caption != null) { + str = selectedObject.messageOwner.media.caption; + } else { + str = selectedObject.messageText; } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("IncorrectLocalization", R.string.IncorrectLocalization)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - showDialog(builder.create()); + if (Build.VERSION.SDK_INT < 11) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(str); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", str); + clipboard.setPrimaryClip(clip); } - } - } else if (option == 55) { //Apply theme - File locFile = null; - if (selectedObject.messageOwner.attachPath != null && selectedObject.messageOwner.attachPath.length() != 0) { - File f = new File(selectedObject.messageOwner.attachPath); - if (f.exists()) { - locFile = f; + } catch (Exception e) { + FileLog.e("tmessages", e); } + break; } - if (locFile == null) { - File f = FileLoader.getPathToMessage(selectedObject.messageOwner); - if (f.exists()) { - locFile = f; - } - } - if (locFile != null) { - String theme = Utilities.applyThemeFile(locFile); - if (!theme.equals("")) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(theme); - builder.setMessage(LocaleController.getString("ThemeApplied", R.string.ThemeApplied) + "\n" + LocaleController.getString("ClickOkToRestart", R.string.ClickOkToRestart)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - Utilities.restartApp(); - } - }); - showDialog(builder.create()); - } else { - if (getParentActivity() == null) { - return; + case 4: { + String path = selectedObject.messageOwner.attachPath; + if (path != null && path.length() > 0) { + File temp = new File(path); + if (!temp.exists()) { + path = null; } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred)); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - showDialog(builder.create()); } - } - } else if (option == 6 || option == 7) { - String path = selectedObject.messageOwner.attachPath; - if (path != null && path.length() > 0) { - File temp = new File(path); - if (!temp.exists()) { - path = null; + if (path == null || path.length() == 0) { + path = FileLoader.getPathToMessage(selectedObject.messageOwner).toString(); } - } - if (path == null || path.length() == 0) { - path = FileLoader.getPathToMessage(selectedObject.messageOwner).toString(); - } - if (selectedObject.type == 8 || selectedObject.type == 9 || selectedObject.type == 14) { - if (option == 6) { - Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType(selectedObject.messageOwner.media.document.mime_type); - intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(path))); - getParentActivity().startActivityForResult(Intent.createChooser(intent, LocaleController.getString("ShareFile", R.string.ShareFile)), 500); - } else { + if (selectedObject.type == 3 || selectedObject.type == 1) { if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { getParentActivity().requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 4); + selectedObject = null; return; } - MediaController.saveFile(path, getParentActivity(), 0, null); + MediaController.saveFile(path, getParentActivity(), selectedObject.type == 3 ? 1 : 0, null, null); } + break; } - } else if (option == 8) { - showReplyPanel(true, selectedObject, null, null, false, true); - } else if (option == 9) { - StickersQuery.loadStickers(this, selectedObject.getInputStickerSet()); - } else if (option == 10) { - if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { - getParentActivity().requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 4); - return; - } - String fileName = FileLoader.getDocumentFileName(selectedObject.messageOwner.media.document); - if (fileName == null || fileName.length() == 0) { - fileName = selectedObject.getFileName(); - } - String path = selectedObject.messageOwner.attachPath; - if (path != null && path.length() > 0) { - File temp = new File(path); - if (!temp.exists()) { - path = null; + case 5: { + File locFile = null; + if (selectedObject.messageOwner.attachPath != null && selectedObject.messageOwner.attachPath.length() != 0) { + File f = new File(selectedObject.messageOwner.attachPath); + if (f.exists()) { + locFile = f; + } } - } - if (path == null || path.length() == 0) { - path = FileLoader.getPathToMessage(selectedObject.messageOwner).toString(); - } - MediaController.saveFile(path, getParentActivity(), selectedObject.isMusic() ? 3 : 2, fileName); - } else if (option == 11) { - MediaController.SearchImage searchImage = new MediaController.SearchImage(); - searchImage.type = 2; - if (selectedObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { - searchImage.document = selectedObject.messageOwner.media.webpage.document; - } else { - searchImage.document = selectedObject.messageOwner.media.document; - } - searchImage.date = (int) (System.currentTimeMillis() / 1000); - searchImage.id = "" + searchImage.document.id; - - ArrayList arrayList = new ArrayList<>(); - arrayList.add(searchImage); - MessagesStorage.getInstance().putWebRecent(arrayList); - TLRPC.TL_messages_saveGif req = new TLRPC.TL_messages_saveGif(); - req.id = new TLRPC.TL_inputDocument(); - req.id.id = searchImage.document.id; - req.id.access_hash = searchImage.document.access_hash; - req.unsave = false; - ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { - @Override - public void run(TLObject response, TLRPC.TL_error error) { - + if (locFile == null) { + File f = FileLoader.getPathToMessage(selectedObject.messageOwner); + if (f.exists()) { + locFile = f; + } } - }); - showGifHint(); + if (locFile != null) { + if (LocaleController.getInstance().applyLanguageFile(locFile)) { + presentFragment(new LanguageSelectActivity()); + } else { + if (getParentActivity() == null) { + selectedObject = null; + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("IncorrectLocalization", R.string.IncorrectLocalization)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); + } + } + break; + } + case 55: { //Apply theme + File locFile = null; + if (selectedObject.messageOwner.attachPath != null && selectedObject.messageOwner.attachPath.length() != 0) { + File f = new File(selectedObject.messageOwner.attachPath); + if (f.exists()) { + locFile = f; + } + } + if (locFile == null) { + File f = FileLoader.getPathToMessage(selectedObject.messageOwner); + if (f.exists()) { + locFile = f; + } + } + if (locFile != null) { + String theme = Utilities.applyThemeFile(locFile); + if (!theme.equals("")) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(theme); + builder.setMessage(LocaleController.getString("ThemeApplied", R.string.ThemeApplied) + "\n" + LocaleController.getString("ClickOkToRestart", R.string.ClickOkToRestart)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + Utilities.restartApp(); + } + }); + showDialog(builder.create()); + } else { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); + } + } + break; + } + case 6: { + String path = selectedObject.messageOwner.attachPath; + if (path != null && path.length() > 0) { + File temp = new File(path); + if (!temp.exists()) { + path = null; + } + } + if (path == null || path.length() == 0) { + path = FileLoader.getPathToMessage(selectedObject.messageOwner).toString(); + } + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType(selectedObject.getDocument().mime_type); + intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File(path))); + getParentActivity().startActivityForResult(Intent.createChooser(intent, LocaleController.getString("ShareFile", R.string.ShareFile)), 500); + break; + } + case 7: { + String path = selectedObject.messageOwner.attachPath; + if (path != null && path.length() > 0) { + File temp = new File(path); + if (!temp.exists()) { + path = null; + } + } + if (path == null || path.length() == 0) { + path = FileLoader.getPathToMessage(selectedObject.messageOwner).toString(); + } + if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + getParentActivity().requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 4); + selectedObject = null; + return; + } + MediaController.saveFile(path, getParentActivity(), 0, null, null); + break; + } + case 8: { + showReplyPanel(true, selectedObject, null, null, false, true); + break; + } + case 9: { + showDialog(new StickersAlert(getParentActivity(), selectedObject.getInputStickerSet(), null, bottomOverlayChat.getVisibility() != View.VISIBLE ? chatActivityEnterView : null)); + break; + } + case 10: { + if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + getParentActivity().requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 4); + selectedObject = null; + return; + } + String fileName = FileLoader.getDocumentFileName(selectedObject.getDocument()); + if (fileName == null || fileName.length() == 0) { + fileName = selectedObject.getFileName(); + } + String path = selectedObject.messageOwner.attachPath; + if (path != null && path.length() > 0) { + File temp = new File(path); + if (!temp.exists()) { + path = null; + } + } + if (path == null || path.length() == 0) { + path = FileLoader.getPathToMessage(selectedObject.messageOwner).toString(); + } + MediaController.saveFile(path, getParentActivity(), selectedObject.isMusic() ? 3 : 2, fileName, selectedObject.getDocument() != null ? selectedObject.getDocument().mime_type : ""); + break; + } + case 11: { + MediaController.SearchImage searchImage = MessagesController.getInstance().saveGif(selectedObject.getDocument()); + showGifHint(); + chatActivityEnterView.addRecentGif(searchImage); + break; + } + case 12: { + if (getParentActivity() == null) { + selectedObject = null; + return; + } + final MessageObject editingMessageObject = selectedObject; + final ProgressDialog progressDialog = new ProgressDialog(getParentActivity()); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); - chatActivityEnterView.addRecentGif(searchImage); + TLRPC.TL_messages_getMessageEditData req = new TLRPC.TL_messages_getMessageEditData(); + req.peer = MessagesController.getInputPeer((int) dialog_id); + req.id = selectedObject.getId(); + final int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + if (!getParentActivity().isFinishing()) { + progressDialog.dismiss(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (response != null) { + TLRPC.TL_messages_messageEditData res = (TLRPC.TL_messages_messageEditData) response; + if (mentionsAdapter != null) { + mentionsAdapter.setNeedBotContext(false); + chatListView.setOnItemLongClickListener(null); + chatListView.setOnItemClickListener(null); + chatListView.setClickable(false); + chatListView.setLongClickable(false); + chatActivityEnterView.setEditinigMessageObject(editingMessageObject, res.caption); + actionModeTextView.setVisibility(View.VISIBLE); + selectedMessagesCountTextView.setVisibility(View.GONE); + + chatActivityEnterView.setAllowStickersAndGifs(false, false); + final ActionBarMenu actionMode = actionBar.createActionMode(); + actionMode.getItem(reply).setVisibility(View.GONE); + actionMode.getItem(copy).setVisibility(View.GONE); + actionMode.getItem(forward).setVisibility(View.GONE); + actionMode.getItem(quoteforward).setVisibility(View.GONE); + actionMode.getItem(delete).setVisibility(View.GONE); + actionMode.getItem(edit_done).setVisibility(View.VISIBLE); + actionBar.showActionMode(); + updatePinnedMessageView(true); + } + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("EditMessageError", R.string.EditMessageError)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); + } + } + }); + } + }); + progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + ConnectionsManager.getInstance().cancelRequest(reqId, true); + try { + dialog.dismiss(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + try { + progressDialog.show(); + } catch (Exception e) { + //don't promt + } + break; + } + case 13: { + final int mid = selectedObject.getId(); + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("PinMessageAlert", R.string.PinMessageAlert)); + + final boolean[] checks = new boolean[]{true}; + FrameLayout frameLayout = new FrameLayout(getParentActivity()); + if (Build.VERSION.SDK_INT >= 21) { + frameLayout.setPadding(0, AndroidUtilities.dp(8), 0, 0); + } + CheckBoxCell cell = new CheckBoxCell(getParentActivity()); + cell.setBackgroundResource(R.drawable.list_selector); + if (Build.VERSION.SDK_INT < 11) { + cell.setTextColor(0xffffffff); + } + cell.setText(LocaleController.getString("PinNotify", R.string.PinNotify), "", true, false); + cell.setPadding(LocaleController.isRTL ? AndroidUtilities.dp(8) : 0, 0, LocaleController.isRTL ? 0 : AndroidUtilities.dp(8), 0); + frameLayout.addView(cell, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.TOP | Gravity.LEFT, 8, 0, 8, 0)); + cell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + CheckBoxCell cell = (CheckBoxCell) v; + checks[0] = !checks[0]; + cell.setChecked(checks[0], true); + } + }); + builder.setView(frameLayout); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + MessagesController.getInstance().pinChannelMessage(currentChat, mid, checks[0]); + } + }); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + break; + } + case 14: { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("UnpinMessageAlert", R.string.UnpinMessageAlert)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + MessagesController.getInstance().pinChannelMessage(currentChat, 0, false); + } + }); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + break; + } + case 15: { + Bundle args = new Bundle(); + args.putInt("user_id", selectedObject.messageOwner.media.user_id); + args.putString("phone", selectedObject.messageOwner.media.phone_number); + args.putBoolean("addContact", true); + presentFragment(new ContactAddActivity(args)); + break; + } + case 16: { + try { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(selectedObject.messageOwner.media.phone_number); + + + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", selectedObject.messageOwner.media.phone_number); + clipboard.setPrimaryClip(clip); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + break; + } + case 17: { + try { + Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + selectedObject.messageOwner.media.phone_number)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + getParentActivity().startActivityForResult(intent, 500); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + break; + } + case 98: { //Direct share + if (getParentActivity() == null) { + selectedObject = null; + return; + } + if (chatActivityEnterView != null) { + chatActivityEnterView.closeKeyboard(); + } + showDialog(new ShareAlert(getParentActivity(), selectedObject, ChatObject.isChannel(currentChat) && !currentChat.megagroup && currentChat.username != null && currentChat.username.length() > 0)); + break; + } + case 99: { //Open sign user + if (getParentActivity() == null) { + selectedObject = null; + return; + } + TLRPC.User signUser = MessagesController.getInstance().getUser(selectedObject.messageOwner.from_id); + MessagesController.openByUserName(signUser.username, ChatActivity.this, 0); + break; + } } selectedObject = null; } @@ -6789,6 +8063,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } cantDeleteMessagesCount = 0; actionBar.hideActionMode(); + updatePinnedMessageView(true); } if (did != dialog_id) { @@ -6801,6 +8076,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (lower_part < 0) { args.putInt("chat_id", -lower_part); } + if (!MessagesController.checkCanOpenChat(args, activity)) { + return; + } + ChatActivity chatActivity = new ChatActivity(args); if (presentFragment(chatActivity, true)) { chatActivity.showReplyPanel(true, null, fmessages, null, false, false); @@ -6819,6 +8098,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not showReplyPanel(true, null, fmessages, null, false, AndroidUtilities.isTablet()); if (AndroidUtilities.isTablet()) { actionBar.hideActionMode(); + updatePinnedMessageView(true); } updateVisibleRows(); } @@ -6832,7 +8112,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not selectedMessagesIds[a].clear(); selectedMessagesCanCopyIds[a].clear(); } + chatActivityEnterView.setEditinigMessageObject(null, false); actionBar.hideActionMode(); + updatePinnedMessageView(true); cantDeleteMessagesCount = 0; updateVisibleRows(); return false; @@ -6843,34 +8125,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return true; } - public boolean isGoogleMapsInstalled() { - try { - ApplicationLoader.applicationContext.getPackageManager().getApplicationInfo("com.google.android.apps.maps", 0); - return true; - } catch (PackageManager.NameNotFoundException e) { - if (getParentActivity() == null) { - return false; - } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage("Install Google Maps?"); - builder.setCancelable(true); - builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - try { - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.google.android.apps.maps")); - getParentActivity().startActivityForResult(intent, 500); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - showDialog(builder.create()); - return false; - } - } - private void updateVisibleRows() { if (chatListView == null) { return; @@ -6899,10 +8153,29 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not cell.setMessageObject(cell.getMessageObject()); cell.setCheckPressed(!disableSelection, disableSelection && selected); cell.setHighlighted(highlightMessageId != Integer.MAX_VALUE && cell.getMessageObject() != null && cell.getMessageObject().getId() == highlightMessageId); + } else if (view instanceof ChatActionCell) { + ChatActionCell cell = (ChatActionCell) view; + cell.setMessageObject(cell.getMessageObject()); } } } + private ArrayList createVoiceMessagesPlaylist(MessageObject startMessageObject, boolean playingUnreadMedia) { + ArrayList messageObjects = new ArrayList<>(); + messageObjects.add(startMessageObject); + int messageId = startMessageObject.getId(); + if (messageId != 0) { + boolean started = false; + for (int a = messages.size() - 1; a >= 0; a--) { + MessageObject messageObject = messages.get(a); + if ((currentEncryptedChat == null && messageObject.getId() > messageId || currentEncryptedChat != null && messageObject.getId() < messageId) && messageObject.isVoice() && (!playingUnreadMedia || messageObject.isContentUnread() && !messageObject.isOut())) { + messageObjects.add(messageObject); + } + } + } + return messageObjects; + } + private void alertUserOpenError(MessageObject message) { if (getParentActivity() == null) { return; @@ -6913,7 +8186,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (message.type == 3) { builder.setMessage(LocaleController.getString("NoPlayerInstalled", R.string.NoPlayerInstalled)); } else { - builder.setMessage(LocaleController.formatString("NoHandleAppInstalled", R.string.NoHandleAppInstalled, message.messageOwner.media.document.mime_type)); + builder.setMessage(LocaleController.formatString("NoHandleAppInstalled", R.string.NoHandleAppInstalled, message.getDocument().mime_type)); } showDialog(builder.create()); } @@ -6922,9 +8195,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not avatarContainer.setVisibility(View.GONE); headerItem.setVisibility(View.GONE); attachItem.setVisibility(View.GONE); + if (searchUpItem.getVisibility() != View.VISIBLE) { searchItem.setVisibility(View.VISIBLE); searchUpItem.setVisibility(View.VISIBLE); searchDownItem.setVisibility(View.VISIBLE); + } updateSearchButtons(0); openSearchKeyboard = text == null; searchItem.openSearch(openSearchKeyboard); @@ -6940,6 +8215,26 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } + public boolean isSecretChat() { + return currentEncryptedChat != null; + } + + public TLRPC.User getCurrentUser() { + return currentUser; + } + + public TLRPC.Chat getCurrentChat() { + return currentChat; + } + + public TLRPC.EncryptedChat getCurrentEncryptedChat() { + return currentEncryptedChat; + } + + public TLRPC.ChatFull getCurrentChatInfo() { + return info; + } + @Override public PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index) { if (messageObject == null) { @@ -6977,6 +8272,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not object.imageReceiver = imageReceiver; object.thumb = imageReceiver.getBitmap(); object.radius = imageReceiver.getRoundRadius(); + if (pinnedMessageView != null && pinnedMessageView.getTag() == null || reportSpamView != null && reportSpamView.getTag() == null) { + object.clipTopAddition = AndroidUtilities.dp(48); + } return object; } } @@ -7019,6 +8317,24 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return 0; } + public void showOpenUrlAlert(final String url) { + if (Browser.isInternalUrl(url)) { + Browser.openUrl(getParentActivity(), url, inlineReturn == 0); + } else { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.formatString("OpenUrlAlert", R.string.OpenUrlAlert, url)); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("Open", R.string.Open), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + Browser.openUrl(getParentActivity(), url, inlineReturn == 0); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } + } + public class ChatActivityAdapter extends RecyclerView.Adapter { private Context mContext; @@ -7091,64 +8407,37 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { view = new ChatMessageCell(mContext); } - } else if (viewType == 1) { - if (!chatMediaCellsCache.isEmpty()) { - view = chatMediaCellsCache.get(0); - chatMediaCellsCache.remove(0); - } else { - view = new ChatMediaCell(mContext); - } - } else if (viewType == 2) { - view = new ChatAudioCell(mContext); - } else if (viewType == 3) { - view = new ChatContactCell(mContext); - } else if (viewType == 4) { - view = new ChatActionCell(mContext); - } else if (viewType == 5) { - view = new ChatLoadingCell(mContext); - } else if (viewType == 6) { - view = new ChatUnreadCell(mContext); - } else if (viewType == 7) { - view = new BotHelpCell(mContext); - ((BotHelpCell) view).setDelegate(new BotHelpCell.BotHelpCellDelegate() { + ChatMessageCell chatMessageCell = (ChatMessageCell) view; + chatMessageCell.setDelegate(new ChatBaseCell.ChatBaseCellDelegate() { @Override - public void didPressUrl(String url) { - if (url.startsWith("@")) { - MessagesController.openByUserName(url.substring(1), ChatActivity.this, 0); - } else if (url.startsWith("#")) { - DialogsActivity fragment = new DialogsActivity(null); - fragment.setSearchString(url); - presentFragment(fragment); - } else if (url.startsWith("/")) { - chatActivityEnterView.setCommand(null, url, false, false); - } - } - }); - } else if (viewType == 8) { - view = new ChatMusicCell(mContext); - } - - if (view instanceof ChatBaseCell) { - if (currentEncryptedChat == null) { - ((ChatBaseCell) view).setAllowAssistant(true); - } - ((ChatBaseCell) view).setDelegate(new ChatBaseCell.ChatBaseCellDelegate() { - @Override - public void didPressShare(ChatBaseCell cell) { + public void didPressedShare(ChatBaseCell cell) { if (getParentActivity() == null) { return; } - if (chatActivityEnterView != null) { - chatActivityEnterView.closeKeyboard(); + if(directShareReplies) { + showReplyPanel(true, cell.getMessageObject(), null, null, false, true); + } else{ + if (chatActivityEnterView != null) { + chatActivityEnterView.closeKeyboard(); + } + showDialog(new ShareAlert(mContext, cell.getMessageObject(), ChatObject.isChannel(currentChat) && !currentChat.megagroup && currentChat.username != null && currentChat.username.length() > 0)); } - BottomSheet.Builder builder = new BottomSheet.Builder(mContext, true); - builder.setCustomView(new ShareFrameLayout(mContext, builder.create(), cell.getMessageObject())).setApplyTopPaddings(false); - builder.setUseFullWidth(false); - showDialog(builder.create()); } @Override - public void didPressedChannelAvatar(ChatBaseCell cell, TLRPC.Chat chat) { + public boolean needPlayAudio(MessageObject messageObject) { + if (messageObject.isVoice()) { + boolean result = MediaController.getInstance().playAudio(messageObject); + MediaController.getInstance().setVoiceMessagesPlaylist(result ? createVoiceMessagesPlaylist(messageObject, false) : null, false); + return result; + } else if (messageObject.isMusic()) { + return MediaController.getInstance().setPlaylist(messages, messageObject); + } + return false; + } + + @Override + public void didPressedChannelAvatar(ChatBaseCell cell, TLRPC.Chat chat, int postId) { if (actionBar.isActionModeShowed()) { processRowSelect(cell); return; @@ -7156,9 +8445,19 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (chat != null && chat != currentChat) { Bundle args = new Bundle(); args.putInt("chat_id", chat.id); + if (postId != 0) { + args.putInt("message_id", postId); + } + if (MessagesController.checkCanOpenChat(args, ChatActivity.this)) { presentFragment(new ChatActivity(args), true); } } + } + + @Override + public void didPressedOther(ChatBaseCell cell) { + createMenu(cell, true); + } @Override public void didPressedUserAvatar(ChatBaseCell cell, TLRPC.User user) { @@ -7167,8 +8466,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return; } //if (user != null && user.id != UserConfig.getClientUserId()) { - /*if (user != null) { - Bundle args = new Bundle(); + /* Bundle args = new Bundle(); args.putInt("user_id", user.id); ProfileActivity fragment = new ProfileActivity(args); fragment.setPlayProfileAnimation(currentUser != null && currentUser.id == user.id); @@ -7349,6 +8647,14 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } + @Override + public void didPressedBotButton(ChatBaseCell cell, TLRPC.KeyboardButton button) { + if (getParentActivity() == null || bottomOverlayChat.getVisibility() == View.VISIBLE && !(button instanceof TLRPC.TL_keyboardButtonCallback) && !(button instanceof TLRPC.TL_keyboardButtonUrl)) { + return; + } + chatActivityEnterView.didPressedBotButton(button, cell.getMessageObject(), cell.getMessageObject()); + } + @Override public void didPressedCancelSendButton(ChatBaseCell cell) { MessageObject message = cell.getMessageObject(); @@ -7368,7 +8674,10 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } @Override - public void didPressUrl(MessageObject messageObject, final ClickableSpan url, boolean longPress) { + public void didPressedUrl(MessageObject messageObject, final ClickableSpan url, boolean longPress) { + if (url == null) { + return; + } if (url instanceof URLSpanNoUnderline) { String str = ((URLSpanNoUnderline) url).getURL(); if (str.startsWith("@")) { @@ -7386,55 +8695,77 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not chatActivityEnterView.setCommand(messageObject, str, longPress, currentChat != null && currentChat.megagroup); } } - } else if (url instanceof URLSpanReplacement) { - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.formatString("OpenUrlAlert", R.string.OpenUrlAlert, ((URLSpanReplacement) url).getURL())); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setPositiveButton(LocaleController.getString("Open", R.string.Open), new DialogInterface.OnClickListener() { + } else { + final String urlFinal = ((URLSpan) url).getURL(); + if (longPress) { + BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); + builder.setTitle(urlFinal); + builder.setItems(new CharSequence[]{LocaleController.getString("Open", R.string.Open), LocaleController.getString("Copy", R.string.Copy)}, new DialogInterface.OnClickListener() { @Override - public void onClick(DialogInterface dialogInterface, int i) { - try { - url.onClick(fragmentView); - } catch (Exception e) { - FileLog.e("tmessages", e); + public void onClick(DialogInterface dialog, final int which) { + if (which == 0) { + Browser.openUrl(getParentActivity(), urlFinal, inlineReturn == 0); + } else if (which == 1) { + try { + if (Build.VERSION.SDK_INT < 11) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(urlFinal); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", urlFinal); + clipboard.setPrimaryClip(clip); + } + Toast.makeText(getParentActivity(), LocaleController.getString("LinkCopied", R.string.LinkCopied), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } } } }); - builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } else { - url.onClick(fragmentView); + if (url instanceof URLSpanReplacement) { + showOpenUrlAlert(((URLSpanReplacement) url).getURL()); + } else if (url instanceof URLSpan) { + Browser.openUrl(getParentActivity(), urlFinal, inlineReturn == 0); + } else { + url.onClick(fragmentView); + } + } } } @Override - public void needOpenWebView(String url, String title, String originalUrl, int w, int h) { + public void needOpenWebView(String url, String title, String description, String originalUrl, int w, int h) { BottomSheet.Builder builder = new BottomSheet.Builder(mContext); - builder.setCustomView(new WebFrameLayout(mContext, builder.create(), title, originalUrl, url, w, h)); + builder.setCustomView(new WebFrameLayout(mContext, builder.create(), title, description, originalUrl, url, w, h)); builder.setUseFullWidth(true); showDialog(builder.create()); } @Override - public void didPressReplyMessage(ChatBaseCell cell, int id) { + public void didPressedReplyMessage(ChatBaseCell cell, int id) { MessageObject messageObject = cell.getMessageObject(); if (messageObject.replyMessageObject != null && !messageObject.replyMessageObject.isImportant() && channelMessagesImportant == 2) { channelMessagesImportant = 1; - radioButton.setChecked(channelMessagesImportant == 1, false); + avatarContainer.setRadioChecked(true, false); } scrollToMessageId(id, messageObject.getId(), true, messageObject.getDialogId() == mergeDialogId ? 1 : 0); } @Override - public void didPressedViaBot(ChatBaseCell cell, TLRPC.User user) { - if (chatActivityEnterView != null && user != null && user.username != null && user.username.length() > 0) { - chatActivityEnterView.setFieldText("@" + user.username + " "); + public void didPressedViaBot(ChatBaseCell cell, String username) { + if (bottomOverlayChat != null && bottomOverlayChat.getVisibility() == View.VISIBLE || bottomOverlay != null && bottomOverlay.getVisibility() == View.VISIBLE) { + return; + } + if (chatActivityEnterView != null && username != null && username.length() > 0) { + chatActivityEnterView.setFieldText("@" + username + " "); chatActivityEnterView.openKeyboard(); } } @Override - public void didClickedImage(ChatBaseCell cell) { + public void didPressedImage(ChatBaseCell cell) { MessageObject message = cell.getMessageObject(); if (message.isSendError()) { createMenu(cell, false); @@ -7442,9 +8773,11 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else if (message.isSending()) { return; } - if (message.type == 1 || message.type == 0) { + if (message.type == 13) { + showDialog(new StickersAlert(getParentActivity(), message.getInputStickerSet(), null, bottomOverlayChat.getVisibility() != View.VISIBLE ? chatActivityEnterView : null)); + } else if (message.type == 1 || message.type == 0 && !message.isWebpageDocument()) { PhotoViewer.getInstance().setParentActivity(getParentActivity()); - PhotoViewer.getInstance().openPhoto(message, message.contentType == 1 ? dialog_id : 0, message.contentType == 1 ? mergeDialogId : 0, ChatActivity.this); + PhotoViewer.getInstance().openPhoto(message, message.type != 0 ? dialog_id : 0, message.type != 0 ? mergeDialogId : 0, ChatActivity.this); } else if (message.type == 3) { sendSecretMessageRead(message); try { @@ -7462,13 +8795,13 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not alertUserOpenError(message); } } else if (message.type == 4) { - if (!isGoogleMapsInstalled()) { + if (!AndroidUtilities.isGoogleMapsInstalled(ChatActivity.this)) { return; } LocationActivity fragment = new LocationActivity(); fragment.setMessageObject(message); presentFragment(fragment); - } else if (message.type == 9) { + } else if (message.type == 9 || message.type == 0) { File f = null; String fileName = message.getFileName(); if (message.messageOwner.attachPath != null && message.messageOwner.attachPath.length() != 0) { @@ -7481,14 +8814,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not String realMimeType = null; try { Intent intent = new Intent(Intent.ACTION_VIEW); - if (message.type == 8 || message.type == 9) { MimeTypeMap myMime = MimeTypeMap.getSingleton(); - int idx = fileName.lastIndexOf("."); + int idx = fileName.lastIndexOf('.'); if (idx != -1) { String ext = fileName.substring(idx + 1); realMimeType = myMime.getMimeTypeFromExtension(ext.toLowerCase()); if (realMimeType == null) { - realMimeType = message.messageOwner.media.document.mime_type; + if (message.type == 9 || message.type == 0) { + realMimeType = message.getDocument().mime_type; + } if (realMimeType == null || realMimeType.length() == 0) { realMimeType = null; } @@ -7501,7 +8835,6 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } else { intent.setDataAndType(Uri.fromFile(f), "text/plain"); } - } if (realMimeType != null) { try { getParentActivity().startActivityForResult(intent, 500); @@ -7519,81 +8852,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } }); - if (view instanceof ChatMediaCell) { - ((ChatMediaCell) view).setAllowedToSetPhoto(openAnimationEnded); - ((ChatMediaCell) view).setMediaDelegate(new ChatMediaCell.ChatMediaCellDelegate() { - @Override - public void didPressedOther(ChatMediaCell cell) { - createMenu(cell, true); - } - }); - } else if (view instanceof ChatContactCell) { - ((ChatContactCell) view).setContactDelegate(new ChatContactCell.ChatContactCellDelegate() { - @Override - public void didClickAddButton(ChatContactCell cell, TLRPC.User user) { - if (actionBar.isActionModeShowed()) { - processRowSelect(cell); - return; - } - MessageObject messageObject = cell.getMessageObject(); - Bundle args = new Bundle(); - args.putInt("user_id", messageObject.messageOwner.media.user_id); - args.putString("phone", messageObject.messageOwner.media.phone_number); - args.putBoolean("addContact", true); - presentFragment(new ContactAddActivity(args)); - } - - @Override - public void didClickPhone(ChatContactCell cell) { - if (actionBar.isActionModeShowed()) { - processRowSelect(cell); - return; - } - final MessageObject messageObject = cell.getMessageObject(); - if (getParentActivity() == null || messageObject.messageOwner.media.phone_number == null || messageObject.messageOwner.media.phone_number.length() == 0) { - return; - } - AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setItems(new CharSequence[]{LocaleController.getString("Copy", R.string.Copy), LocaleController.getString("Call", R.string.Call)}, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (i == 1) { - try { - Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + messageObject.messageOwner.media.phone_number)); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - getParentActivity().startActivityForResult(intent, 500); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } else if (i == 0) { - try { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { - android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - clipboard.setText(messageObject.messageOwner.media.phone_number); - } else { - android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); - android.content.ClipData clip = android.content.ClipData.newPlainText("label", messageObject.messageOwner.media.phone_number); - clipboard.setPrimaryClip(clip); - } - } catch (Exception e) { - FileLog.e("tmessages", e); - } - } - } - } - ); - showDialog(builder.create()); - } - }); - } else if (view instanceof ChatMusicCell) { - ((ChatMusicCell) view).setMusicDelegate(new ChatMusicCell.ChatMusicCellDelegate() { - @Override - public boolean needPlayMusic(MessageObject messageObject) { - return MediaController.getInstance().setPlaylist(messages, messageObject); - } - }); - } - } else if (view instanceof ChatActionCell) { + chatMessageCell.setAllowedToSetPhoto(openAnimationEnded); + if (currentEncryptedChat == null) { + chatMessageCell.setAllowAssistant(true); + } + } else if (viewType == 1) { + view = new ChatActionCell(mContext); ((ChatActionCell) view).setDelegate(new ChatActionCell.ChatActionCellDelegate() { @Override public void didClickedImage(ChatActionCell cell) { @@ -7612,7 +8876,9 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not if (uid < 0) { Bundle args = new Bundle(); args.putInt("chat_id", -uid); + if (MessagesController.checkCanOpenChat(args, ChatActivity.this)) { presentFragment(new ChatActivity(args), true); + } } else if (uid != UserConfig.getClientUserId()) { Bundle args = new Bundle(); args.putInt("user_id", uid); @@ -7625,8 +8891,28 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not } } }); + } else if (viewType == 2) { + view = new ChatUnreadCell(mContext); + } else if (viewType == 3) { + view = new BotHelpCell(mContext); + ((BotHelpCell) view).setDelegate(new BotHelpCell.BotHelpCellDelegate() { + @Override + public void didPressUrl(String url) { + if (url.startsWith("@")) { + MessagesController.openByUserName(url.substring(1), ChatActivity.this, 0); + } else if (url.startsWith("#")) { + DialogsActivity fragment = new DialogsActivity(null); + fragment.setSearchString(url); + presentFragment(fragment); + } else if (url.startsWith("/")) { + chatActivityEnterView.setCommand(null, url, false, false); + } + } + }); + } else if (viewType == 4) { + view = new ChatLoadingCell(mContext); } - + view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)); return new Holder(view); } @@ -7718,15 +9004,15 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not view.setBackgroundColor(0); } - if (view instanceof ChatBaseCell) { - ChatBaseCell baseCell = (ChatBaseCell) view; - baseCell.isChat = currentChat != null; - baseCell.setMessageObject(message); - baseCell.setCheckPressed(!disableSelection, disableSelection && selected); - if (view instanceof ChatAudioCell && MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_AUDIO)) { - ((ChatAudioCell) view).downloadAudioIfNeed(); + if (view instanceof ChatMessageCell) { + ChatMessageCell messageCell = (ChatMessageCell) view; + messageCell.isChat = currentChat != null; + messageCell.setMessageObject(message); + messageCell.setCheckPressed(!disableSelection, disableSelection && selected); + if (view instanceof ChatMessageCell && MediaController.getInstance().canDownloadMedia(MediaController.AUTODOWNLOAD_MASK_AUDIO)) { + ((ChatMessageCell) view).downloadAudioIfNeed(); } - baseCell.setHighlighted(highlightMessageId != Integer.MAX_VALUE && message.getId() == highlightMessageId); + messageCell.setHighlighted(highlightMessageId != Integer.MAX_VALUE && message.getId() == highlightMessageId); } else if (view instanceof ChatActionCell) { ChatActionCell actionCell = (ChatActionCell) view; actionCell.setMessageObject(message); @@ -7739,22 +9025,16 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not @Override public int getItemViewType(int position) { - if (position == loadingUpRow || position == loadingDownRow) { - return 5; - } else if (position == botInfoRow) { - return 7; - } else if (position >= messagesStartRow && position < messagesEndRow) { + if (position >= messagesStartRow && position < messagesEndRow) { return messages.get(messages.size() - (position - messagesStartRow) - 1).contentType; + } else if (position == botInfoRow) { + return 3; } - return 5; + return 4; } @Override public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) { - if (holder.itemView instanceof ChatBaseCell) { - ChatBaseCell baseCell = (ChatBaseCell) holder.itemView; - baseCell.setHighlighted(highlightMessageId != Integer.MAX_VALUE && baseCell.getMessageObject().getId() == highlightMessageId); - } if (holder.itemView instanceof ChatMessageCell) { final ChatMessageCell messageCell = (ChatMessageCell) holder.itemView; messageCell.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @@ -7766,6 +9046,7 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not return true; } }); + messageCell.setHighlighted(highlightMessageId != Integer.MAX_VALUE && messageCell.getMessageObject().getId() == highlightMessageId); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java new file mode 100644 index 00000000..c9c17d72 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AlertsCreator.java @@ -0,0 +1,224 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.os.Bundle; + +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationsController; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ReportOtherActivity; + +public class AlertsCreator { + + public static Dialog createMuteAlert(Context context, final long dialog_id) { + if (context == null) { + return null; + } + + BottomSheet.Builder builder = new BottomSheet.Builder(context); + builder.setTitle(LocaleController.getString("Notifications", R.string.Notifications)); + CharSequence[] items = new CharSequence[]{ + LocaleController.formatString("MuteFor", R.string.MuteFor, LocaleController.formatPluralString("Hours", 1)), + LocaleController.formatString("MuteFor", R.string.MuteFor, LocaleController.formatPluralString("Hours", 8)), + LocaleController.formatString("MuteFor", R.string.MuteFor, LocaleController.formatPluralString("Days", 2)), + LocaleController.getString("MuteDisable", R.string.MuteDisable) + }; + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + int untilTime = ConnectionsManager.getInstance().getCurrentTime(); + if (i == 0) { + untilTime += 60 * 60; + } else if (i == 1) { + untilTime += 60 * 60 * 8; + } else if (i == 2) { + untilTime += 60 * 60 * 48; + } else if (i == 3) { + untilTime = Integer.MAX_VALUE; + } + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + long flags; + if (i == 3) { + editor.putInt("notify2_" + dialog_id, 2); + flags = 1; + } else { + editor.putInt("notify2_" + dialog_id, 3); + editor.putInt("notifyuntil_" + dialog_id, untilTime); + flags = ((long) untilTime << 32) | 1; + } + NotificationsController.getInstance().removeNotificationsForDialog(dialog_id); + MessagesStorage.getInstance().setDialogFlags(dialog_id, flags); + editor.commit(); + TLRPC.Dialog dialog = MessagesController.getInstance().dialogs_dict.get(dialog_id); + if (dialog != null) { + dialog.notify_settings = new TLRPC.TL_peerNotifySettings(); + dialog.notify_settings.mute_until = untilTime; + } + NotificationsController.updateServerNotificationsSettings(dialog_id); + } + } + ); + return builder.create(); + } + + public static Dialog createReportAlert(Context context, final long dialog_id, final BaseFragment parentFragment) { + if (context == null || parentFragment == null) { + return null; + } + + BottomSheet.Builder builder = new BottomSheet.Builder(context); + builder.setTitle(LocaleController.getString("ReportChat", R.string.ReportChat)); + CharSequence[] items = new CharSequence[]{ + LocaleController.getString("ReportChatSpam", R.string.ReportChatSpam), + LocaleController.getString("ReportChatViolence", R.string.ReportChatViolence), + LocaleController.getString("ReportChatPornography", R.string.ReportChatPornography), + LocaleController.getString("ReportChatOther", R.string.ReportChatOther) + }; + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (i == 3) { + Bundle args = new Bundle(); + args.putLong("dialog_id", dialog_id); + parentFragment.presentFragment(new ReportOtherActivity(args)); + return; + } + TLRPC.TL_account_reportPeer req = new TLRPC.TL_account_reportPeer(); + req.peer = MessagesController.getInputPeer((int) dialog_id); + if (i == 0) { + req.reason = new TLRPC.TL_inputReportReasonSpam(); + } else if (i == 1) { + req.reason = new TLRPC.TL_inputReportReasonViolence(); + } else if (i == 2) { + req.reason = new TLRPC.TL_inputReportReasonPornography(); + } + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }); + } + } + ); + return builder.create(); + } + + public static void showFloodWaitAlert(String error, final BaseFragment fragment) { + if (error == null || !error.startsWith("FLOOD_WAIT") || fragment == null || fragment.getParentActivity() == null) { + return; + } + int time = Utilities.parseInt(error); + String timeString; + if (time < 60) { + timeString = LocaleController.formatPluralString("Seconds", time); + } else { + timeString = LocaleController.formatPluralString("Minutes", time / 60); + } + + AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.formatString("FloodWaitTime", R.string.FloodWaitTime, timeString)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + fragment.showDialog(builder.create(), true); + } + + public static void showAddUserAlert(String error, final BaseFragment fragment, boolean isChannel) { + if (error == null || fragment == null || fragment.getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(fragment.getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + switch (error) { + case "PEER_FLOOD": + builder.setMessage(LocaleController.getString("NobodyLikesSpam2", R.string.NobodyLikesSpam2)); + builder.setNegativeButton(LocaleController.getString("MoreInfo", R.string.MoreInfo), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + MessagesController.openByUserName("spambot", fragment, 1); + } + }); + break; + case "USER_BLOCKED": + case "USER_BOT": + case "USER_ID_INVALID": + if (isChannel) { + builder.setMessage(LocaleController.getString("ChannelUserCantAdd", R.string.ChannelUserCantAdd)); + } else { + builder.setMessage(LocaleController.getString("GroupUserCantAdd", R.string.GroupUserCantAdd)); + } + break; + case "USERS_TOO_MUCH": + if (isChannel) { + builder.setMessage(LocaleController.getString("ChannelUserAddLimit", R.string.ChannelUserAddLimit)); + } else { + builder.setMessage(LocaleController.getString("GroupUserAddLimit", R.string.GroupUserAddLimit)); + } + break; + case "USER_NOT_MUTUAL_CONTACT": + if (isChannel) { + builder.setMessage(LocaleController.getString("ChannelUserLeftError", R.string.ChannelUserLeftError)); + } else { + builder.setMessage(LocaleController.getString("GroupUserLeftError", R.string.GroupUserLeftError)); + } + break; + case "ADMINS_TOO_MUCH": + if (isChannel) { + builder.setMessage(LocaleController.getString("ChannelUserCantAdmin", R.string.ChannelUserCantAdmin)); + } else { + builder.setMessage(LocaleController.getString("GroupUserCantAdmin", R.string.GroupUserCantAdmin)); + } + break; + case "BOTS_TOO_MUCH": + if (isChannel) { + builder.setMessage(LocaleController.getString("ChannelUserCantBot", R.string.ChannelUserCantBot)); + } else { + builder.setMessage(LocaleController.getString("GroupUserCantBot", R.string.GroupUserCantBot)); + } + break; + case "USER_PRIVACY_RESTRICTED": + if (isChannel) { + builder.setMessage(LocaleController.getString("InviteToChannelError", R.string.InviteToChannelError)); + } else { + builder.setMessage(LocaleController.getString("InviteToGroupError", R.string.InviteToGroupError)); + } + break; + case "USERS_TOO_FEW": + builder.setMessage(LocaleController.getString("CreateGroupError", R.string.CreateGroupError)); + break; + case "USER_RESTRICTED": + builder.setMessage(LocaleController.getString("UserRestricted", R.string.UserRestricted)); + break; + default: + builder.setMessage(error); + break; + } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + fragment.showDialog(builder.create(), true); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java new file mode 100644 index 00000000..649694d7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AnimatedFileDrawable.java @@ -0,0 +1,348 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.RectF; +import android.graphics.Shader; +import android.graphics.drawable.Animatable; +import android.graphics.drawable.BitmapDrawable; +import android.os.Handler; +import android.os.Looper; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; + +import java.io.File; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadPoolExecutor; + +public class AnimatedFileDrawable extends BitmapDrawable implements Animatable { + + private static native int createDecoder(String src, int[] params); + private static native void destroyDecoder(int ptr); + private static native int getVideoFrame(int ptr, Bitmap bitmap, int[] params); + + private long lastFrameTime; + private int lastTimeStamp; + private int invalidateAfter = 50; + private final int[] metaData = new int[3]; + private Runnable loadFrameTask; + private Bitmap renderingBitmap; + private Bitmap nextRenderingBitmap; + private Bitmap backgroundBitmap; + private boolean destroyWhenDone; + private boolean decoderCreated; + private File path; + + private BitmapShader renderingShader; + private BitmapShader nextRenderingShader; + private BitmapShader backgroundShader; + + private int roundRadius; + private RectF roundRect = new RectF(); + private RectF bitmapRect = new RectF(); + private Matrix shaderMatrix = new Matrix(); + + private float scaleX = 1.0f; + private float scaleY = 1.0f; + private boolean applyTransformation; + private final android.graphics.Rect dstRect = new android.graphics.Rect(); + private static final Handler uiHandler = new Handler(Looper.getMainLooper()); + private volatile boolean isRunning; + private volatile boolean isRecycled; + private volatile int nativePtr; + private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(2, new ThreadPoolExecutor.DiscardPolicy()); + + private View parentView = null; + + protected final Runnable mInvalidateTask = new Runnable() { + @Override + public void run() { + if (parentView != null) { + parentView.invalidate(); + } + } + }; + + private Runnable uiRunnable = new Runnable() { + @Override + public void run() { + if (destroyWhenDone && nativePtr != 0) { + destroyDecoder(nativePtr); + nativePtr = 0; + } + if (nativePtr == 0) { + if (backgroundBitmap != null) { + backgroundBitmap.recycle(); + backgroundBitmap = null; + } + return; + } + loadFrameTask = null; + nextRenderingBitmap = backgroundBitmap; + nextRenderingShader = backgroundShader; + if (metaData[2] < lastTimeStamp) { + lastTimeStamp = 0; + } + if (metaData[2] - lastTimeStamp != 0) { + invalidateAfter = metaData[2] - lastTimeStamp; + } + lastTimeStamp = metaData[2]; + if (parentView != null) { + parentView.invalidate(); + } + } + }; + + private Runnable loadFrameRunnable = new Runnable() { + @Override + public void run() { + if (!isRecycled) { + if (!decoderCreated && nativePtr == 0) { + nativePtr = createDecoder(path.getAbsolutePath(), metaData); + decoderCreated = true; + } + try { + if (backgroundBitmap == null) { + try { + backgroundBitmap = Bitmap.createBitmap(metaData[0], metaData[1], Bitmap.Config.ARGB_8888); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + if (backgroundShader == null && backgroundBitmap != null && roundRadius != 0) { + backgroundShader = new BitmapShader(backgroundBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + } + } + if (backgroundBitmap != null) { + getVideoFrame(nativePtr, backgroundBitmap, metaData); + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + AndroidUtilities.runOnUIThread(uiRunnable); + } + }; + + private final Runnable mStartTask = new Runnable() { + @Override + public void run() { + if (parentView != null) { + parentView.invalidate(); + } + } + }; + + public AnimatedFileDrawable(File file, boolean createDecoder) { + path = file; + if (createDecoder) { + nativePtr = createDecoder(file.getAbsolutePath(), metaData); + decoderCreated = true; + } + } + + protected void postToDecodeQueue(Runnable runnable) { + executor.execute(runnable); + } + + public void setParentView(View view) { + parentView = view; + } + + public void recycle() { + isRunning = false; + isRecycled = true; + if (loadFrameTask == null) { + if (nativePtr != 0) { + destroyDecoder(nativePtr); + nativePtr = 0; + } + if (nextRenderingBitmap != null) { + nextRenderingBitmap.recycle(); + nextRenderingBitmap = null; + } + } else { + destroyWhenDone = true; + } + if (renderingBitmap != null) { + renderingBitmap.recycle(); + renderingBitmap = null; + } + } + + protected static void runOnUiThread(Runnable task) { + if (Looper.myLooper() == uiHandler.getLooper()) { + task.run(); + } else { + uiHandler.post(task); + } + } + + @Override + protected void finalize() throws Throwable { + try { + recycle(); + } finally { + super.finalize(); + } + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + + @Override + public void start() { + if (isRunning) { + return; + } + isRunning = true; + if (renderingBitmap == null) { + scheduleNextGetFrame(); + } + runOnUiThread(mStartTask); + } + + private void scheduleNextGetFrame() { + if (loadFrameTask != null || nativePtr == 0 && decoderCreated || destroyWhenDone) { + return; + } + postToDecodeQueue(loadFrameTask = loadFrameRunnable); + } + + @Override + public void stop() { + isRunning = false; + } + + @Override + public boolean isRunning() { + return isRunning; + } + + @Override + public int getIntrinsicHeight() { + return decoderCreated ? metaData[1] : AndroidUtilities.dp(100); + } + + @Override + public int getIntrinsicWidth() { + return decoderCreated ? metaData[0] : AndroidUtilities.dp(100); + } + + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + applyTransformation = true; + } + + @Override + public void draw(Canvas canvas) { + if (nativePtr == 0 && decoderCreated || destroyWhenDone) { + return; + } + if (isRunning) { + if (renderingBitmap == null && nextRenderingBitmap == null) { + scheduleNextGetFrame(); + } else if (Math.abs(System.currentTimeMillis() - lastFrameTime) >= invalidateAfter) { + if (nextRenderingBitmap != null) { + scheduleNextGetFrame(); + renderingBitmap = nextRenderingBitmap; + renderingShader = nextRenderingShader; + nextRenderingBitmap = null; + nextRenderingShader = null; + lastFrameTime = System.currentTimeMillis(); + } + } + } + + if (renderingBitmap != null) { + if (applyTransformation) { + dstRect.set(getBounds()); + scaleX = (float) dstRect.width() / renderingBitmap.getWidth(); + scaleY = (float) dstRect.height() / renderingBitmap.getHeight(); + applyTransformation = false; + } + if (roundRadius != 0) { + int bitmapW = renderingBitmap.getWidth(); + int bitmapH = renderingBitmap.getHeight(); + float scale = Math.max(scaleX, scaleY); + + if (renderingShader == null) { + renderingShader = new BitmapShader(backgroundBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); + } + getPaint().setShader(renderingShader); + roundRect.set(dstRect); + shaderMatrix.reset(); + if (Math.abs(scaleX - scaleY) > 0.00001f) { + int w = (int) Math.floor(dstRect.width() / scale); + int h = (int) Math.floor(dstRect.height() / scale); + bitmapRect.set((bitmapW - w) / 2, (bitmapH - h) / 2, w, h); + shaderMatrix.setRectToRect(bitmapRect, roundRect, Matrix.ScaleToFit.START); + } else { + bitmapRect.set(0, 0, renderingBitmap.getWidth(), renderingBitmap.getHeight()); + shaderMatrix.setRectToRect(bitmapRect, roundRect, Matrix.ScaleToFit.FILL); + } + renderingShader.setLocalMatrix(shaderMatrix); + canvas.drawRoundRect(roundRect, roundRadius, roundRadius, getPaint()); + } else { + canvas.translate(dstRect.left, dstRect.top); + canvas.scale(scaleX, scaleY); + canvas.drawBitmap(renderingBitmap, 0, 0, getPaint()); + } + if (isRunning) { + uiHandler.postDelayed(mInvalidateTask, invalidateAfter); + } + } + } + + @Override + public int getMinimumHeight() { + return decoderCreated ? metaData[1] : AndroidUtilities.dp(100); + } + + @Override + public int getMinimumWidth() { + return decoderCreated ? metaData[0] : AndroidUtilities.dp(100); + } + + public Bitmap getAnimatedBitmap() { + if (renderingBitmap != null) { + return renderingBitmap; + } else if (nextRenderingBitmap != null) { + return nextRenderingBitmap; + } + return null; + } + + public void setRoundRadius(int value) { + roundRadius = value; + getPaint().setFlags(Paint.ANTI_ALIAS_FLAG); + } + + public boolean hasBitmap() { + return nativePtr != 0 && (renderingBitmap != null || nextRenderingBitmap != null); + } + + public AnimatedFileDrawable makeCopy() { + AnimatedFileDrawable drawable = new AnimatedFileDrawable(path, false); + drawable.metaData[0] = metaData[0]; + drawable.metaData[1] = metaData[1]; + return drawable; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java index 489b3158..7ca0ce1f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/AvatarDrawable.java @@ -26,7 +26,7 @@ import org.telegram.messenger.FileLog; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.tgnet.TLRPC; - +import org.telegram.ui.ActionBar.Theme; import java.util.Locale; public class AvatarDrawable extends Drawable { @@ -34,11 +34,13 @@ public class AvatarDrawable extends Drawable { private static Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); private static TextPaint namePaint; private static TextPaint namePaintSmall; - private static int[] arrColors = {0xffe56555, 0xfff28c48, 0xff549cdd, 0xff76c84d, 0xff5fbed5, 0xff549cdd, 0xff8e85ee, 0xfff2749a}; - private static int[] arrColorsProfiles = {0xffd86f65, 0xfff69d61, 0xff8c79d2, 0xff67b35d, 0xff56a2bb, 0xff5c98cd, 0xff8c79d2, 0xfff37fa6}; - private static int[] arrColorsProfilesBack = {0xffca6056, 0xfff18944, 0xff7d6ac4, 0xff56a14c, 0xff4492ac, 0xff4c84b6, 0xff7d6ac4, 0xff4c84b6}; - private static int[] arrColorsProfilesText = {0xfff9cbc5, 0xfffdddc8, 0xffcdc4ed, 0xffc0edba, 0xffb8e2f0, 0xffb3d7f7, 0xffcdc4ed, 0xffb3d7f7}; + private static int[] arrColors = {0xffe56555, 0xfff28c48, 0xff8e85ee, 0xff76c84d, 0xff5fbed5, 0xff549cdd, 0xff8e85ee, 0xfff2749a}; + private static int[] arrColorsProfiles = {0xffd86f65, 0xfff69d61, 0xff8c79d2, 0xff67b35d, 0xff56a2bb, Theme.ACTION_BAR_MAIN_AVATAR_COLOR, 0xff8c79d2, 0xfff37fa6}; + private static int[] arrColorsProfilesBack = {0xffca6056, 0xfff18944, 0xff7d6ac4, 0xff56a14c, 0xff4492ac, Theme.ACTION_BAR_PROFILE_COLOR, 0xff7d6ac4, 0xff4c84b6}; + private static int[] arrColorsProfilesText = {0xfff9cbc5, 0xfffdddc8, 0xffcdc4ed, 0xffc0edba, 0xffb8e2f0, Theme.ACTION_BAR_PROFILE_SUBTITLE_COLOR, 0xffcdc4ed, 0xffb3d7f7}; //private static int[] arrColorsNames = {0xffca5650, 0xffd87b29, 0xff4e92cc, 0xff50b232, 0xff42b1a8, 0xff4e92cc, 0xff4e92cc, 0xff4e92cc}; + private static int[] arrColorsButtons = {Theme.ACTION_BAR_RED_SELECTOR_COLOR, Theme.ACTION_BAR_ORANGE_SELECTOR_COLOR, Theme.ACTION_BAR_VIOLET_SELECTOR_COLOR, + Theme.ACTION_BAR_GREEN_SELECTOR_COLOR, Theme.ACTION_BAR_CYAN_SELECTOR_COLOR, Theme.ACTION_BAR_BLUE_SELECTOR_COLOR, Theme.ACTION_BAR_VIOLET_SELECTOR_COLOR, Theme.ACTION_BAR_BLUE_SELECTOR_COLOR}; private static int[] arrColorsNames = { 0xFFF44336, //RED 0xFFE91E63, //PINK @@ -61,8 +63,8 @@ public class AvatarDrawable extends Drawable { 0xFF607D8B //BLUE GREY }; - private static int[] arrColorsButtons = {R.drawable.bar_selector_red, R.drawable.bar_selector_orange, R.drawable.bar_selector_violet, - R.drawable.bar_selector_green, R.drawable.bar_selector_cyan, R.drawable.bar_selector_blue, R.drawable.bar_selector_violet, R.drawable.bar_selector_blue}; + //private static int[] arrColorsButtons = {R.drawable.bar_selector_red, R.drawable.bar_selector_orange, R.drawable.bar_selector_violet, + // R.drawable.bar_selector_green, R.drawable.bar_selector_cyan, R.drawable.bar_selector_blue, R.drawable.bar_selector_violet, R.drawable.bar_selector_blue}; private static Drawable broadcastDrawable; private static Drawable photoDrawable; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java new file mode 100644 index 00000000..f0bdd471 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/BotKeyboardView.java @@ -0,0 +1,132 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.ScrollView; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.R; +import org.telegram.tgnet.TLRPC; + +import java.util.ArrayList; + +public class BotKeyboardView extends LinearLayout { + + private LinearLayout container; + private TLRPC.TL_replyKeyboardMarkup botButtons; + private BotKeyboardViewDelegate delegate; + private int panelHeight; + private boolean isFullSize; + private int buttonHeight; + private ArrayList buttonViews = new ArrayList<>(); + + public interface BotKeyboardViewDelegate { + void didPressedButton(TLRPC.KeyboardButton button); + } + + public BotKeyboardView(Context context) { + super(context); + + setOrientation(VERTICAL); + + ScrollView scrollView = new ScrollView(context); + addView(scrollView); + container = new LinearLayout(context); + container.setOrientation(VERTICAL); + scrollView.addView(container); + + setBackgroundColor(0xfff5f6f7); + } + + public void setDelegate(BotKeyboardViewDelegate botKeyboardViewDelegate) { + delegate = botKeyboardViewDelegate; + } + + public void setPanelHeight(int height) { + panelHeight = height; + if (isFullSize && botButtons != null && botButtons.rows.size() != 0) { + buttonHeight = !isFullSize ? 42 : (int) Math.max(42, (panelHeight - AndroidUtilities.dp(30) - (botButtons.rows.size() - 1) * AndroidUtilities.dp(10)) / botButtons.rows.size() / AndroidUtilities.density); + int count = container.getChildCount(); + int newHeight = AndroidUtilities.dp(buttonHeight); + for (int a = 0; a < count; a++) { + View v = container.getChildAt(a); + LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) v.getLayoutParams(); + if (layoutParams.height != newHeight) { + layoutParams.height = newHeight; + v.setLayoutParams(layoutParams); + } + } + } + } + + public void invalidateViews() { + for (int a = 0; a < buttonViews.size(); a++) { + buttonViews.get(a).invalidate(); + } + } + + public boolean isFullSize() { + return isFullSize; + } + + public void setButtons(TLRPC.TL_replyKeyboardMarkup buttons) { + botButtons = buttons; + container.removeAllViews(); + buttonViews.clear(); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int bgColor = themePrefs.getInt("chatEmojiViewBGColor", 0xfff5f6f7); + setBackgroundColor(bgColor); + int tabColor = themePrefs.getInt("chatEmojiViewTabColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x15)); + if (buttons != null && botButtons.rows.size() != 0) { + isFullSize = !buttons.resize; + buttonHeight = !isFullSize ? 42 : (int) Math.max(42, (panelHeight - AndroidUtilities.dp(30) - (botButtons.rows.size() - 1) * AndroidUtilities.dp(10)) / botButtons.rows.size() / AndroidUtilities.density); + for (int a = 0; a < buttons.rows.size(); a++) { + TLRPC.TL_keyboardButtonRow row = buttons.rows.get(a); + + LinearLayout layout = new LinearLayout(getContext()); + layout.setOrientation(LinearLayout.HORIZONTAL); + container.addView(layout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, buttonHeight, 15, a == 0 ? 15 : 10, 15, a == buttons.rows.size() - 1 ? 15 : 0)); + + float weight = 1.0f / row.buttons.size(); + for (int b = 0; b < row.buttons.size(); b++) { + TLRPC.KeyboardButton button = row.buttons.get(b); + TextView textView = new TextView(getContext()); + textView.setTag(button); + textView.setTextColor(0xff36474f); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setGravity(Gravity.CENTER); + textView.setBackgroundResource(R.drawable.bot_keyboard_states); + textView.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); + textView.setText(Emoji.replaceEmoji(button.text, textView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(16), false)); + layout.addView(textView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, weight, 0, 0, b != row.buttons.size() - 1 ? 10 : 0, 0)); + textView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + delegate.didPressedButton((TLRPC.KeyboardButton) v.getTag()); + } + }); + buttonViews.add(textView); + } + } + } + } + + public int getKeyboardHeight() { + return isFullSize ? panelHeight : botButtons.rows.size() * AndroidUtilities.dp(buttonHeight) + AndroidUtilities.dp(30) + (botButtons.rows.size() - 1) * AndroidUtilities.dp(10); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java index 77cfe429..32a923a8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatActivityEnterView.java @@ -11,19 +11,26 @@ package org.telegram.ui.Components; import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; +import android.app.AlertDialog; import android.content.Context; +import android.content.DialogInterface; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.media.AudioManager; import android.os.Build; +import android.os.Bundle; import android.os.PowerManager; +import android.os.SystemClock; import android.text.Editable; +import android.text.InputFilter; import android.text.Layout; +import android.text.SpannableStringBuilder; import android.text.StaticLayout; import android.text.TextPaint; import android.text.TextUtils; @@ -44,33 +51,40 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.TextView; +import android.widget.Toast; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ChatObject; -import org.telegram.messenger.Emoji; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MediaController; -import org.telegram.messenger.MessageObject; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.SendMessagesHelper; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.NotificationCenter; -import org.telegram.messenger.R; -import org.telegram.tgnet.ConnectionsManager; -import org.telegram.tgnet.TLRPC; -import org.telegram.messenger.UserConfig; -import org.telegram.ui.ActionBar.ActionBar; -import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.messenger.AnimationCompat.AnimatorListenerAdapterProxy; import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; import org.telegram.messenger.AnimationCompat.ViewProxy; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.NotificationsController; +import org.telegram.messenger.R; +import org.telegram.messenger.SendMessagesHelper; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.DialogsActivity; import org.telegram.ui.StickersActivity; +import java.io.File; +import java.lang.reflect.Field; +import java.util.ArrayList; import java.util.Locale; -public class ChatActivityEnterView extends FrameLayoutFixed implements NotificationCenter.NotificationCenterDelegate, SizeNotifierFrameLayout.SizeNotifierFrameLayoutDelegate { +public class ChatActivityEnterView extends FrameLayoutFixed implements NotificationCenter.NotificationCenterDelegate, SizeNotifierFrameLayout.SizeNotifierFrameLayoutDelegate, StickersAlert.StickersAlertDelegate { public interface ChatActivityEnterViewDelegate { void onMessageSend(String message); @@ -80,6 +94,63 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat void onAttachButtonShow(); void onWindowSizeChanged(int size); void onStickersTab(boolean opened); + void onMessageEditEnd(); + } + + private class SeekBarWaveformView extends View { + + private SeekBarWaveform seekBarWaveform; + + public SeekBarWaveformView(Context context) { + super(context); + seekBarWaveform = new SeekBarWaveform(context); + seekBarWaveform.setColors(0xffa2cef8, 0xffffffff, 0xffa2cef8); + seekBarWaveform.setDelegate(new SeekBar.SeekBarDelegate() { + @Override + public void onSeekBarDrag(float progress) { + audioToSendMessageObject.audioProgress = progress; + MediaController.getInstance().seekToProgress(audioToSendMessageObject, progress); + } + }); + } + + public void setWaveform(byte[] waveform) { + seekBarWaveform.setWaveform(waveform); + invalidate(); + } + + public void setProgress(float progress) { + seekBarWaveform.setProgress(progress); + invalidate(); + } + + public boolean isDragging() { + return seekBarWaveform.isDragging(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + boolean result = seekBarWaveform.onTouch(event.getAction(), event.getX(), event.getY()); + if (result) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + requestDisallowInterceptTouchEvent(true); + } + invalidate(); + } + return result || super.onTouchEvent(event); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + seekBarWaveform.setSize(right - left, bottom - top); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + seekBarWaveform.draw(canvas); + } } private class EditTextCaption extends EditText { @@ -89,9 +160,28 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat private int userNameLength; private int xOffset; private int yOffset; + private Object editor; + private Field editorField; + private Drawable[] mCursorDrawable; + private Field mCursorDrawableField; + private int triesCount = 0; public EditTextCaption(Context context) { super(context); + + try { + Field field = TextView.class.getDeclaredField("mEditor"); + field.setAccessible(true); + editor = field.get(this); + Class editorClass = Class.forName("android.widget.Editor"); + editorField = editorClass.getDeclaredField("mShowCursor"); + editorField.setAccessible(true); + mCursorDrawableField = editorClass.getDeclaredField("mCursorDrawable"); + mCursorDrawableField.setAccessible(true); + mCursorDrawable = (Drawable[]) mCursorDrawableField.get(editor); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } } public void setCaption(String value) { @@ -139,6 +229,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat @Override protected void onDraw(Canvas canvas) { + try { super.onDraw(canvas); if (captionLayout != null && userNameLength == length()) { Paint paint = getPaint(); @@ -150,6 +241,24 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat canvas.restore(); paint.setColor(oldColor); } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + + try { + if (editorField != null && mCursorDrawable != null && mCursorDrawable[0] != null) { + long mShowCursor = editorField.getLong(editor); + boolean showCursor = (SystemClock.uptimeMillis() - mShowCursor) % (2 * 500) < 500; + if (showCursor) { + canvas.save(); + canvas.translate(0, getPaddingTop()); + mCursorDrawable[0].draw(canvas); + canvas.restore(); + } + } + } catch (Throwable e) { + //ignore + } } @Override @@ -164,26 +273,40 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat private EditTextCaption messageEditText; private ImageView sendButton; + private ImageView cancelBotButton; private ImageView emojiButton; private EmojiView emojiView; private TextView recordTimeText; private ImageView audioSendButton; private FrameLayout recordPanel; + private FrameLayout recordedAudioPanel; + private SeekBarWaveformView recordedAudioSeekBar; + private ImageView recordedAudioPlayButton; + private TextView recordedAudioTimeTextView; private LinearLayout slideText; private RecordDot recordDot; private SizeNotifierFrameLayout sizeNotifierLayout; private LinearLayout attachButton; private ImageView botButton; private LinearLayout textFieldContainer; + private FrameLayout sendButtonContainer; private View topView; private PopupWindow botKeyboardPopup; private BotKeyboardView botKeyboardView; private ImageView asAdminButton; + private ImageView notifyButton; private RecordCircle recordCircle; private ContextProgressView contextProgressView; + private CloseProgressDrawable2 progressDrawable; + + private MessageObject editingMessageObject; + private boolean editingCaption; private int currentPopupContentType = -1; + private boolean silent; + private boolean canWriteToChannel; + private boolean isAsAdmin; private boolean adminModeAvailable; @@ -220,7 +343,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat private boolean lastSizeChangeValue2; private Activity parentActivity; - private BaseFragment parentFragment; + private ChatActivity parentFragment; private long dialog_id; private boolean ignoreTextChange; private int innerTextChange; @@ -230,11 +353,19 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat private boolean messageWebPageSearch = true; private ChatActivityEnterViewDelegate delegate; + private TLRPC.TL_document audioToSend; + private String audioToSendPath; + private MessageObject audioToSendMessageObject; + private float topViewAnimation; private boolean topViewShowed; private boolean needShowTopView; private boolean allowShowTopView; private AnimatorSetProxy currentTopViewAnimation; + private MessageObject pendingMessageObject; + private TLRPC.KeyboardButton pendingLocationButton; + + private boolean hideBotKeyboard; private boolean waitingForKeyboardOpen; private Runnable openKeyboardRunnable = new Runnable() { @@ -272,16 +403,16 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat @Override protected void onDraw(Canvas canvas) { dotDrawable.setBounds(0, 0, AndroidUtilities.dp(11), AndroidUtilities.dp(11)); - dotDrawable.setAlpha(185 + (int) (70 * alpha)); + dotDrawable.setAlpha((int) (255 * alpha)); long dt = (System.currentTimeMillis() - lastUpdateTime); if (!isIncr) { - alpha -= dt / 200.0f; + alpha -= dt / 400.0f; if (alpha <= 0) { alpha = 0; isIncr = true; } } else { - alpha += dt / 200.0f; + alpha += dt / 400.0f; if (alpha >= 1) { alpha = 1; isIncr = false; @@ -369,7 +500,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } } - public ChatActivityEnterView(Activity context, SizeNotifierFrameLayout parent, BaseFragment fragment, boolean isChat) { + public ChatActivityEnterView(Activity context, SizeNotifierFrameLayout parent, ChatActivity fragment, boolean isChat) { super(context); setBackgroundResource(R.drawable.compose_panel); setFocusable(true); @@ -383,13 +514,18 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioDidSent); NotificationCenter.getInstance().addObserver(this, NotificationCenter.emojiDidLoaded); NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioRouteChanged); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioDidReset); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioProgressDidChanged); parentActivity = context; parentFragment = fragment; sizeNotifierLayout = parent; sizeNotifierLayout.setDelegate(this); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); sendByEnter = preferences.getBoolean("send_by_enter", false); - + //plus + SharedPreferences plusPrefs = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + hideBotKeyboard = plusPrefs.getBoolean("hideBotKeyboard", false); + // textFieldContainer = new LinearLayout(context); textFieldContainer.setBackgroundColor(0xffffffff); textFieldContainer.setOrientation(LinearLayout.HORIZONTAL); @@ -399,16 +535,21 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat textFieldContainer.addView(frameLayout, LayoutHelper.createLinear(0, LayoutHelper.WRAP_CONTENT, 1.0f)); emojiButton = new ImageView(context); - //emojiButton.setImageResource(R.drawable.ic_msg_panel_smiles); - Drawable emoji = getResources().getDrawable(R.drawable.ic_msg_panel_smiles); + emojiButton.setImageResource(R.drawable.ic_msg_panel_smiles); + //Drawable emoji = getResources().getDrawable(R.drawable.ic_msg_panel_smiles); SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); final int color = themePrefs.getInt("chatEditTextIconsColor", 0xffadadad); - emoji.setColorFilter(color, PorterDuff.Mode.SRC_IN); - emojiButton.setImageDrawable(emoji); + //emoji.setColorFilter(color, PorterDuff.Mode.SRC_IN); + //emojiButton.setImageDrawable(emoji); + emojiButton.setColorFilter(color, PorterDuff.Mode.SRC_IN); emojiButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - emojiButton.setPadding(AndroidUtilities.dp(4), AndroidUtilities.dp(1), 0, 0); - frameLayout.addView(emojiButton, LayoutHelper.createFrame(48, 48, Gravity.BOTTOM)); - emojiButton.setOnClickListener(new View.OnClickListener() { + emojiButton.setPadding(0, AndroidUtilities.dp(1), 0, 0); + if (Build.VERSION.SDK_INT >= 21) { + emojiButton.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.INPUT_FIELD_SELECTOR_COLOR)); + } + frameLayout.addView(emojiButton, LayoutHelper.createFrame(48, 48, Gravity.BOTTOM | Gravity.LEFT, 3, 0, 0, 0)); + emojiButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { if (!isPopupShowing() || currentPopupContentType != 0) { @@ -416,7 +557,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } else { openKeyboardInternal(); removeGifFromInputField(); - } + } } }); @@ -430,11 +571,10 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat messageEditText.setGravity(Gravity.BOTTOM); messageEditText.setPadding(0, AndroidUtilities.dp(11), 0, AndroidUtilities.dp(12)); messageEditText.setBackgroundDrawable(null); - AndroidUtilities.clearCursorDrawable(messageEditText); messageEditText.setTextColor(0xff000000); messageEditText.setHintTextColor(0xffb2b2b2); frameLayout.addView(messageEditText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM, 52, 0, isChat ? 50 : 2, 0)); - messageEditText.setOnKeyListener(new View.OnKeyListener() { + messageEditText.setOnKeyListener(new OnKeyListener() { boolean ctrlPressed = false; @@ -500,12 +640,14 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat if (count > 2 || charSequence == null || charSequence.length() == 0) { messageWebPageSearch = true; } - delegate.onTextChanged(charSequence, before > count + 1 || (count - before) > 2); + if (!ignoreTextChange) { + delegate.onTextChanged(charSequence, before > count + 1 || (count - before) > 2); + } } if (innerTextChange != 2 && before != count && (count - before) > 1) { processChange = true; } - if (!isAsAdmin && message.length() != 0 && lastTypingTimeSend < System.currentTimeMillis() - 5000 && !ignoreTextChange) { + if (editingMessageObject == null && !isAsAdmin && message.length() != 0 && lastTypingTimeSend < System.currentTimeMillis() - 5000 && !ignoreTextChange) { int currentTime = ConnectionsManager.getInstance().getCurrentTime(); TLRPC.User currentUser = null; if ((int) dialog_id > 0) { @@ -539,6 +681,14 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } } }); + try { + //Field mCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes"); + //mCursorDrawableRes.setAccessible(true); + //mCursorDrawableRes.set(messageEditText, R.drawable.field_carret); + AndroidUtilities.clearCursorDrawable(messageEditText); + } catch (Exception e) { + //nothing to do + } if (isChat) { contextProgressView = new ContextProgressView(context); @@ -555,6 +705,9 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat botButton.setImageResource(R.drawable.bot_keyboard2); botButton.setScaleType(ImageView.ScaleType.CENTER); botButton.setVisibility(GONE); + if (Build.VERSION.SDK_INT >= 21) { + botButton.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.INPUT_FIELD_SELECTOR_COLOR)); + } attachButton.addView(botButton, LayoutHelper.createLinear(48, 48)); botButton.setOnClickListener(new OnClickListener() { @Override @@ -582,6 +735,9 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat asAdminButton.setImageResource(isAsAdmin ? R.drawable.publish_active : R.drawable.publish); asAdminButton.setScaleType(ImageView.ScaleType.CENTER); asAdminButton.setVisibility(adminModeAvailable ? VISIBLE : GONE); + if (Build.VERSION.SDK_INT >= 21) { + asAdminButton.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.INPUT_FIELD_SELECTOR_COLOR)); + } attachButton.addView(asAdminButton, LayoutHelper.createLinear(48, 48)); asAdminButton.setOnClickListener(new OnClickListener() { @Override @@ -593,8 +749,99 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat preferences.edit().putBoolean("asadmin_" + dialog_id, isAsAdmin).commit(); } }); + + notifyButton = new ImageView(context); + notifyButton.setImageResource(silent ? R.drawable.notify_members_off : R.drawable.notify_members_on); + notifyButton.setColorFilter(color, PorterDuff.Mode.SRC_IN); + notifyButton.setScaleType(ImageView.ScaleType.CENTER); + notifyButton.setVisibility(canWriteToChannel ? VISIBLE : GONE); + if (Build.VERSION.SDK_INT >= 21) { + notifyButton.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.INPUT_FIELD_SELECTOR_COLOR)); + } + attachButton.addView(notifyButton, LayoutHelper.createLinear(48, 48)); + notifyButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + silent = !silent; + notifyButton.setImageResource(silent ? R.drawable.notify_members_off : R.drawable.notify_members_on); + notifyButton.setColorFilter(color, PorterDuff.Mode.SRC_IN); + ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).edit().putBoolean("silent_" + dialog_id, silent).commit(); + NotificationsController.updateServerNotificationsSettings(dialog_id); + if (silent) { + Toast.makeText(parentActivity, LocaleController.getString("ChannelNotifyMembersInfoOff", R.string.ChannelNotifyMembersInfoOff), Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(parentActivity, LocaleController.getString("ChannelNotifyMembersInfoOn", R.string.ChannelNotifyMembersInfoOn), Toast.LENGTH_SHORT).show(); + } + updateFieldHint(); + } + }); } + recordedAudioPanel = new FrameLayoutFixed(context); + recordedAudioPanel.setVisibility(audioToSend == null ? GONE : VISIBLE); + recordedAudioPanel.setBackgroundColor(0xffffffff); + recordedAudioPanel.setFocusable(true); + recordedAudioPanel.setFocusableInTouchMode(true); + recordedAudioPanel.setClickable(true); + frameLayout.addView(recordedAudioPanel, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM)); + + ImageView imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + imageView.setImageResource(R.drawable.ic_ab_fwd_delete); + int iconColor = themePrefs.getInt("chatEditTextIconsColor", 0xff737373); + imageView.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + recordedAudioPanel.addView(imageView, LayoutHelper.createFrame(48, 48)); + imageView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + MessageObject playing = MediaController.getInstance().getPlayingMessageObject(); + if (playing != null && playing == audioToSendMessageObject) { + MediaController.getInstance().cleanupPlayer(true, true); + } + if (audioToSendPath != null) { + new File(audioToSendPath).delete(); + } + hideRecordedAudioPanel(); + checkSendButton(true); + } + }); + + View view = new View(context); + view.setBackgroundResource(R.drawable.recorded); + int bgColor = themePrefs.getInt("chatEditTextBGColor", 0xffffffff); + bgColor = Color.argb(0xff, Color.red(bgColor), Color.green(bgColor), Color.blue(bgColor)); + view.getBackground().setColorFilter(bgColor == 0xffffffff ? def : AndroidUtilities.setDarkColor(bgColor, 0x25), PorterDuff.Mode.SRC_IN); + recordedAudioPanel.addView(view, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 32, Gravity.CENTER_VERTICAL | Gravity.LEFT, 48, 0, 0, 0)); + + recordedAudioSeekBar = new SeekBarWaveformView(context); + recordedAudioPanel.addView(recordedAudioSeekBar, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 32, Gravity.CENTER_VERTICAL | Gravity.LEFT, 48 + 44, 0, 52, 0)); + + recordedAudioPlayButton = new ImageView(context); + recordedAudioPlayButton.setImageResource(R.drawable.s_player_play_states); + recordedAudioPlayButton.setScaleType(ImageView.ScaleType.CENTER); + recordedAudioPanel.addView(recordedAudioPlayButton, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.BOTTOM, 48, 0, 0, 0)); + recordedAudioPlayButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (audioToSend == null) { + return; + } + if (MediaController.getInstance().isPlayingAudio(audioToSendMessageObject) && !MediaController.getInstance().isAudioPaused()) { + MediaController.getInstance().pauseAudio(audioToSendMessageObject); + recordedAudioPlayButton.setImageResource(R.drawable.s_player_play_states); + } else { + recordedAudioPlayButton.setImageResource(R.drawable.s_player_pause_states); + MediaController.getInstance().playAudio(audioToSendMessageObject); + } + } + }); + + recordedAudioTimeTextView = new TextView(context); + recordedAudioTimeTextView.setTextColor(0xffffffff); + recordedAudioTimeTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + recordedAudioTimeTextView.setText("0:13"); + recordedAudioPanel.addView(recordedAudioTimeTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 0, 0, 13, 0)); + recordPanel = new FrameLayoutFixed(context); recordPanel.setVisibility(GONE); recordPanel.setBackgroundColor(0xffffffff); @@ -604,7 +851,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat slideText.setOrientation(LinearLayout.HORIZONTAL); recordPanel.addView(slideText, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 30, 0, 0, 0)); - ImageView imageView = new ImageView(context); + imageView = new ImageView(context); imageView.setImageResource(R.drawable.slidearrow); slideText.addView(imageView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 0, 1, 0, 0)); @@ -629,34 +876,34 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat recordTimeText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); linearLayout.addView(recordTimeText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL, 6, 0, 0, 0)); - FrameLayout frameLayout1 = new FrameLayout(context); - textFieldContainer.addView(frameLayout1, LayoutHelper.createLinear(48, 48, Gravity.BOTTOM)); + sendButtonContainer = new FrameLayout(context); + textFieldContainer.addView(sendButtonContainer, LayoutHelper.createLinear(48, 48, Gravity.BOTTOM)); audioSendButton = new ImageView(context); audioSendButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - //audioSendButton.setImageResource(R.drawable.mic); + audioSendButton.setImageResource(R.drawable.mic); //audioSendButton.setBackgroundColor(0xffffffff); audioSendButton.setSoundEffectsEnabled(false); - Drawable mic = getResources().getDrawable(R.drawable.mic); - mic.setColorFilter(color, PorterDuff.Mode.SRC_IN); - audioSendButton.setImageDrawable(mic); + //Drawable mic = getResources().getDrawable(R.drawable.mic); + //mic.setColorFilter(color, PorterDuff.Mode.SRC_IN); + //audioSendButton.setImageDrawable(mic); + audioSendButton.setColorFilter(color, PorterDuff.Mode.SRC_IN); audioSendButton.setBackgroundColor(0x00000000); audioSendButton.setPadding(0, 0, AndroidUtilities.dp(4), 0); - frameLayout1.addView(audioSendButton, LayoutHelper.createFrame(48, 48)); - audioSendButton.setOnTouchListener(new View.OnTouchListener() { + sendButtonContainer.addView(audioSendButton, LayoutHelper.createFrame(48, 48)); + audioSendButton.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { - Drawable mic = getResources().getDrawable(R.drawable.mic); + //Drawable mic = getResources().getDrawable(R.drawable.mic); if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) { - mic.setColorFilter(0xffda564d, PorterDuff.Mode.SRC_IN); - audioSendButton.setImageDrawable(mic); + //mic.setColorFilter(0xffda564d, PorterDuff.Mode.SRC_IN); + //audioSendButton.setImageDrawable(mic); + audioSendButton.setColorFilter(0xffda564d, PorterDuff.Mode.SRC_IN); if (parentFragment != null) { - if (Build.VERSION.SDK_INT >= 23) { - if (parentActivity.checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { + if (Build.VERSION.SDK_INT >= 23 && parentActivity.checkSelfPermission(Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) { parentActivity.requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO}, 3); return false; } - } String action; TLRPC.Chat currentChat; @@ -679,16 +926,17 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat updateAudioRecordIntefrace(); audioSendButton.getParent().requestDisallowInterceptTouchEvent(true); } else if (motionEvent.getAction() == MotionEvent.ACTION_UP || motionEvent.getAction() == MotionEvent.ACTION_CANCEL) { - mic.setColorFilter(color, PorterDuff.Mode.SRC_IN); - audioSendButton.setImageDrawable(mic); + //mic.setColorFilter(color, PorterDuff.Mode.SRC_IN); + //audioSendButton.setImageDrawable(mic); + audioSendButton.setColorFilter(color, PorterDuff.Mode.SRC_IN); startedDraggingX = -1; - MediaController.getInstance().stopRecording(true); + MediaController.getInstance().stopRecording(1); recordingAudio = false; updateAudioRecordIntefrace(); } else if (motionEvent.getAction() == MotionEvent.ACTION_MOVE && recordingAudio) { float x = motionEvent.getX(); if (x < -distCanMove) { - MediaController.getInstance().stopRecording(false); + MediaController.getInstance().stopRecording(0); recordingAudio = false; updateAudioRecordIntefrace(); } @@ -736,17 +984,42 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat recordCircle.setVisibility(GONE); sizeNotifierLayout.addView(recordCircle, LayoutHelper.createFrame(124, 124, Gravity.BOTTOM | Gravity.RIGHT, 0, 0, -36, -38)); + cancelBotButton = new ImageView(context); + cancelBotButton.setVisibility(INVISIBLE); + cancelBotButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE); + //cancelBotButton.setImageResource(R.drawable.delete_reply); + cancelBotButton.setImageDrawable(progressDrawable = new CloseProgressDrawable2()); + cancelBotButton.setSoundEffectsEnabled(false); + ViewProxy.setScaleX(cancelBotButton, 0.1f); + ViewProxy.setScaleY(cancelBotButton, 0.1f); + ViewProxy.setAlpha(cancelBotButton, 0.0f); + cancelBotButton.clearAnimation(); + sendButtonContainer.addView(cancelBotButton, LayoutHelper.createFrame(48, 48)); + cancelBotButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + String text = messageEditText.getText().toString(); + int idx = text.indexOf(' '); + if (idx == -1 || idx == text.length() - 1) { + setFieldText(""); + } else { + setFieldText(text.substring(0, idx + 1)); + } + } + }); + sendButton = new ImageView(context); - sendButton.setVisibility(View.INVISIBLE); + sendButton.setVisibility(INVISIBLE); sendButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE); sendButton.setImageResource(R.drawable.ic_send); + sendButton.setColorFilter(themePrefs.getInt("chatSendIconColor", themePrefs.getInt("chatEditTextIconsColor", def)), PorterDuff.Mode.SRC_IN); sendButton.setSoundEffectsEnabled(false); ViewProxy.setScaleX(sendButton, 0.1f); ViewProxy.setScaleY(sendButton, 0.1f); ViewProxy.setAlpha(sendButton, 0.0f); sendButton.clearAnimation(); - frameLayout1.addView(sendButton, LayoutHelper.createFrame(48, 48)); - sendButton.setOnClickListener(new View.OnClickListener() { + sendButtonContainer.addView(sendButton, LayoutHelper.createFrame(48, 48)); + sendButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { sendMessage(); @@ -764,10 +1037,13 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat private void updateTheme() { SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); - Drawable send = getResources().getDrawable(R.drawable.ic_send); - send.setColorFilter(themePrefs.getInt("chatSendIconColor", themePrefs.getInt("chatEditTextIconsColor", def)), PorterDuff.Mode.SRC_IN); - sendButton.setImageDrawable(send); - messageEditText.setTextColor(themePrefs.getInt("chatEditTextColor", 0xff000000)); + //Drawable send = getResources().getDrawable(R.drawable.ic_send); + //send.setColorFilter(themePrefs.getInt("chatSendIconColor", themePrefs.getInt("chatEditTextIconsColor", def)), PorterDuff.Mode.SRC_IN); + //sendButton.setImageDrawable(send); + sendButton.setColorFilter(themePrefs.getInt("chatSendIconColor", themePrefs.getInt("chatEditTextIconsColor", def)), PorterDuff.Mode.SRC_IN); + int editTextColor = themePrefs.getInt("chatEditTextColor", 0xff000000); + messageEditText.setTextColor(editTextColor); + //AndroidUtilities.setCursorDrawableColor(messageEditText, editTextColor); messageEditText.setHintTextColor(AndroidUtilities.getIntAlphaColor("chatEditTextColor", 0xff000000, 0.35f)); messageEditText.setTextSize(themePrefs.getInt("chatEditTextSize", 18)); @@ -796,10 +1072,12 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat setBackgroundDrawable(gd); textFieldContainer.setBackgroundDrawable(gd); } + recordedAudioPanel.setBackgroundColor(Color.argb(0xff, Color.red(color), Color.green(color), Color.blue(color))); + //recordPanel.setBackgroundColor(color); } public void showContextProgress(boolean show) { - if (contextProgressView == null) { + /*if (contextProgressView == null) { return; } contextProgressView.setVisibility(show ? VISIBLE : INVISIBLE); @@ -807,12 +1085,21 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat messageEditText.setPadding(0, AndroidUtilities.dp(11), show ? AndroidUtilities.dp(38) : 0, AndroidUtilities.dp(12)); } catch (Exception e) { FileLog.e("tmessages", e); + }*/ + if (progressDrawable == null) { + return; + } + if (show) { + progressDrawable.startAnimation(); + } else { + progressDrawable.stopAnimation(); } } public void setCaption(String caption) { if (messageEditText != null) { messageEditText.setCaption(caption); + checkSendButton(true); } } @@ -843,6 +1130,13 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } public void setAllowStickersAndGifs(boolean value, boolean value2) { + if ((allowStickers != value || allowGifs != value2) && emojiView != null) { + if (emojiView.getVisibility() == VISIBLE) { + hidePopup(false); + } + sizeNotifierLayout.removeView(emojiView); + emojiView = null; + } allowStickers = value; allowGifs = value2; } @@ -880,18 +1174,25 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat public void onAnimationEnd(Object animation) { if (currentTopViewAnimation != null && currentTopViewAnimation.equals(animation)) { setTopViewAnimation(1.0f); - if (!forceShowSendButton || openKeyboard) { + if (recordedAudioPanel.getVisibility() != VISIBLE && (!forceShowSendButton || openKeyboard)) { openKeyboard(); } currentTopViewAnimation = null; } } + + @Override + public void onAnimationCancel(Object animation) { + if (currentTopViewAnimation != null && currentTopViewAnimation.equals(animation)) { + currentTopViewAnimation = null; + } + } }); currentTopViewAnimation.setDuration(200); currentTopViewAnimation.start(); } else { setTopViewAnimation(1.0f); - if (!forceShowSendButton || openKeyboard) { + if (recordedAudioPanel.getVisibility() != VISIBLE && (!forceShowSendButton || openKeyboard)) { openKeyboard(); } } @@ -929,6 +1230,13 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat currentTopViewAnimation = null; } } + + @Override + public void onAnimationCancel(Object animation) { + if (currentTopViewAnimation != null && currentTopViewAnimation.equals(animation)) { + currentTopViewAnimation = null; + } + } }); currentTopViewAnimation.setDuration(200); currentTopViewAnimation.start(); @@ -956,7 +1264,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat if (allowShowTopView) { allowShowTopView = false; if (needShowTopView) { - topView.setVisibility(View.GONE); + topView.setVisibility(GONE); setTopViewAnimation(0.0f); } } @@ -964,7 +1272,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat if (!allowShowTopView) { allowShowTopView = true; if (needShowTopView) { - topView.setVisibility(View.VISIBLE); + topView.setVisibility(VISIBLE); setTopViewAnimation(1.0f); } } @@ -981,6 +1289,11 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioDidSent); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.emojiDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioRouteChanged); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioDidReset); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioProgressDidChanged); + if (emojiView != null) { + emojiView.onDestroy(); + } if (mWakeLock != null) { try { mWakeLock.release(); @@ -1017,8 +1330,10 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat dialog_id = id; if ((int) dialog_id < 0) { TLRPC.Chat currentChat = MessagesController.getInstance().getChat(-(int) dialog_id); + silent = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE).getBoolean("silent_" + dialog_id, false); isAsAdmin = ChatObject.isChannel(currentChat) && (currentChat.creator || currentChat.editor) && !currentChat.megagroup; adminModeAvailable = isAsAdmin && !currentChat.broadcast; + canWriteToChannel = isAsAdmin; if (adminModeAvailable) { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); isAsAdmin = preferences.getBoolean("asadmin_" + dialog_id, true); @@ -1028,6 +1343,11 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat asAdminButton.setImageResource(isAsAdmin ? R.drawable.publish_active : R.drawable.publish); updateFieldHint(); } + if (notifyButton != null) { + notifyButton.setVisibility(canWriteToChannel ? VISIBLE : GONE); + notifyButton.setImageResource(silent ? R.drawable.notify_members_off : R.drawable.notify_members_on); + ViewProxy.setPivotX(attachButton, AndroidUtilities.dp((botButton == null || botButton.getVisibility() == GONE) && (notifyButton == null || notifyButton.getVisibility() == GONE) ? 48 : 96)); + } } } @@ -1038,7 +1358,19 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat isChannel = ChatObject.isChannel(chat) && !chat.megagroup; } if (isChannel) { - messageEditText.setHint(isAsAdmin ? LocaleController.getString("ChannelBroadcast", R.string.ChannelBroadcast) : LocaleController.getString("ChannelComment", R.string.ChannelComment)); + if (editingMessageObject != null) { + messageEditText.setHint(editingCaption ? LocaleController.getString("Caption", R.string.Caption) : LocaleController.getString("TypeMessage", R.string.TypeMessage)); + } else { + if (isAsAdmin) { + if (silent) { + messageEditText.setHint(LocaleController.getString("ChannelSilentBroadcast", R.string.ChannelSilentBroadcast)); + } else { + messageEditText.setHint(LocaleController.getString("ChannelBroadcast", R.string.ChannelBroadcast)); + } + } else { + messageEditText.setHint(LocaleController.getString("ChannelComment", R.string.ChannelComment)); + } + } } else { messageEditText.setHint(LocaleController.getString("TypeMessage", R.string.TypeMessage)); } @@ -1069,6 +1401,26 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat return messageWebPageSearch; } + private void hideRecordedAudioPanel() { + audioToSendPath = null; + audioToSend = null; + audioToSendMessageObject = null; + AnimatorSetProxy animatorSetProxy = new AnimatorSetProxy(); + animatorSetProxy.playTogether( + ObjectAnimatorProxy.ofFloat(recordedAudioPanel, "alpha", 0.0f) + ); + animatorSetProxy.setDuration(200); + animatorSetProxy.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + recordedAudioPanel.clearAnimation(); + recordedAudioPanel.setVisibility(GONE); + + } + }); + animatorSetProxy.start(); + } + private void sendMessage() { if (parentFragment != null) { String action; @@ -1087,6 +1439,19 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat return; } } + if (audioToSend != null) { + MessageObject playing = MediaController.getInstance().getPlayingMessageObject(); + if (playing != null && playing == audioToSendMessageObject) { + MediaController.getInstance().cleanupPlayer(true, true); + } + SendMessagesHelper.getInstance().sendMessage(audioToSend, null, audioToSendPath, dialog_id, replyingMessageObject, isAsAdmin, null, null); + if (delegate != null) { + delegate.onMessageSend(null); + } + hideRecordedAudioPanel(); + checkSendButton(true); + return; + } String message = messageEditText.getText().toString(); if (processSendingText(message)) { messageEditText.setText(""); @@ -1101,13 +1466,20 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } } + public void doneEditingMessage() { + if (editingMessageObject != null) { + SendMessagesHelper.getInstance().editMessage(editingMessageObject, messageEditText.getText().toString(), messageWebPageSearch, parentFragment); + setEditinigMessageObject(null, false); + } + } + public boolean processSendingText(String text) { text = getTrimmedString(text); if (text.length() != 0) { int count = (int) Math.ceil(text.length() / 4096.0f); for (int a = 0; a < count; a++) { String mess = text.substring(a * 4096, Math.min((a + 1) * 4096, text.length())); - SendMessagesHelper.getInstance().sendMessage(mess, dialog_id, replyingMessageObject, messageWebPage, messageWebPageSearch, asAdmin(), null, null); + SendMessagesHelper.getInstance().sendMessage(mess, dialog_id, replyingMessageObject, messageWebPage, messageWebPageSearch, asAdmin(), null, null, null); } return true; } @@ -1129,11 +1501,16 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } private void checkSendButton(final boolean animated) { + if (editingMessageObject != null) { + return; + } String message = getTrimmedString(messageEditText.getText().toString()); - if (message.length() > 0 || forceShowSendButton) { - if (audioSendButton.getVisibility() == View.VISIBLE) { + if (message.length() > 0 || forceShowSendButton || audioToSend != null) { + boolean showBotButton = messageEditText.caption != null && sendButton.getVisibility() == VISIBLE; + boolean showSendButton = messageEditText.caption == null && cancelBotButton.getVisibility() == VISIBLE; + if (audioSendButton.getVisibility() == VISIBLE || showBotButton || showSendButton) { if (animated) { - if (runningAnimationType == 1) { + if (runningAnimationType == 1 && messageEditText.caption == null || runningAnimationType == 3 && messageEditText.caption != null) { return; } if (runningAnimation != null) { @@ -1155,65 +1532,125 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat runningAnimation2.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Object animation) { - if (runningAnimation2.equals(animation)) { - attachButton.setVisibility(View.GONE); + if (runningAnimation2 != null && runningAnimation2.equals(animation)) { + attachButton.setVisibility(GONE); attachButton.clearAnimation(); } } + + @Override + public void onAnimationCancel(Object animation) { + if (runningAnimation2 != null && runningAnimation2.equals(animation)) { + runningAnimation2 = null; + } + } }); runningAnimation2.start(); - updateFieldRight(0); - + if (delegate != null) { delegate.onAttachButtonHidden(); } + } - sendButton.setVisibility(View.VISIBLE); runningAnimation = new AnimatorSetProxy(); + + ArrayList animators = new ArrayList<>(); + if (audioSendButton.getVisibility() == VISIBLE) { + animators.add(ObjectAnimatorProxy.ofFloat(audioSendButton, "scaleX", 0.1f)); + animators.add(ObjectAnimatorProxy.ofFloat(audioSendButton, "scaleY", 0.1f)); + animators.add(ObjectAnimatorProxy.ofFloat(audioSendButton, "alpha", 0.0f)); + } + if (showBotButton) { + animators.add(ObjectAnimatorProxy.ofFloat(sendButton, "scaleX", 0.1f)); + animators.add(ObjectAnimatorProxy.ofFloat(sendButton, "scaleY", 0.1f)); + animators.add(ObjectAnimatorProxy.ofFloat(sendButton, "alpha", 0.0f)); + } else if (showSendButton) { + animators.add(ObjectAnimatorProxy.ofFloat(cancelBotButton, "scaleX", 0.1f)); + animators.add(ObjectAnimatorProxy.ofFloat(cancelBotButton, "scaleY", 0.1f)); + animators.add(ObjectAnimatorProxy.ofFloat(cancelBotButton, "alpha", 0.0f)); + } + if (messageEditText.caption != null) { + runningAnimationType = 3; + animators.add(ObjectAnimatorProxy.ofFloat(cancelBotButton, "scaleX", 1.0f)); + animators.add(ObjectAnimatorProxy.ofFloat(cancelBotButton, "scaleY", 1.0f)); + animators.add(ObjectAnimatorProxy.ofFloat(cancelBotButton, "alpha", 1.0f)); + cancelBotButton.setVisibility(VISIBLE); + } else { runningAnimationType = 1; + animators.add(ObjectAnimatorProxy.ofFloat(sendButton, "scaleX", 1.0f)); + animators.add(ObjectAnimatorProxy.ofFloat(sendButton, "scaleY", 1.0f)); + animators.add(ObjectAnimatorProxy.ofFloat(sendButton, "alpha", 1.0f)); + sendButton.setVisibility(VISIBLE); + } - runningAnimation.playTogether( - ObjectAnimatorProxy.ofFloat(audioSendButton, "scaleX", 0.1f), - ObjectAnimatorProxy.ofFloat(audioSendButton, "scaleY", 0.1f), - ObjectAnimatorProxy.ofFloat(audioSendButton, "alpha", 0.0f), - ObjectAnimatorProxy.ofFloat(sendButton, "scaleX", 1.0f), - ObjectAnimatorProxy.ofFloat(sendButton, "scaleY", 1.0f), - ObjectAnimatorProxy.ofFloat(sendButton, "alpha", 1.0f) - ); - + runningAnimation.playTogether(animators); runningAnimation.setDuration(150); runningAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Object animation) { if (runningAnimation != null && runningAnimation.equals(animation)) { - sendButton.setVisibility(View.VISIBLE); - audioSendButton.setVisibility(View.GONE); + if (messageEditText.caption != null) { + cancelBotButton.setVisibility(VISIBLE); + sendButton.setVisibility(GONE); + sendButton.clearAnimation(); + } else { + sendButton.setVisibility(VISIBLE); + cancelBotButton.setVisibility(GONE); + cancelBotButton.clearAnimation(); + } + audioSendButton.setVisibility(GONE); audioSendButton.clearAnimation(); runningAnimation = null; runningAnimationType = 0; } } + + @Override + public void onAnimationCancel(Object animation) { + if (runningAnimation != null && runningAnimation.equals(animation)) { + runningAnimation = null; + } + } }); runningAnimation.start(); } else { ViewProxy.setScaleX(audioSendButton, 0.1f); ViewProxy.setScaleY(audioSendButton, 0.1f); ViewProxy.setAlpha(audioSendButton, 0.0f); + if (messageEditText.caption != null) { + ViewProxy.setScaleX(sendButton, 0.1f); + ViewProxy.setScaleY(sendButton, 0.1f); + ViewProxy.setAlpha(sendButton, 0.0f); + ViewProxy.setScaleX(cancelBotButton, 1.0f); + ViewProxy.setScaleY(cancelBotButton, 1.0f); + ViewProxy.setAlpha(cancelBotButton, 1.0f); + cancelBotButton.setVisibility(VISIBLE); + sendButton.setVisibility(GONE); + sendButton.clearAnimation(); + } else { + ViewProxy.setScaleX(cancelBotButton, 0.1f); + ViewProxy.setScaleY(cancelBotButton, 0.1f); + ViewProxy.setAlpha(cancelBotButton, 0.0f); ViewProxy.setScaleX(sendButton, 1.0f); ViewProxy.setScaleY(sendButton, 1.0f); ViewProxy.setAlpha(sendButton, 1.0f); - sendButton.setVisibility(View.VISIBLE); - audioSendButton.setVisibility(View.GONE); + sendButton.setVisibility(VISIBLE); + cancelBotButton.setVisibility(GONE); + cancelBotButton.clearAnimation(); + } + audioSendButton.setVisibility(GONE); audioSendButton.clearAnimation(); if (attachButton != null) { - attachButton.setVisibility(View.GONE); + attachButton.setVisibility(GONE); attachButton.clearAnimation(); + if (delegate != null) { delegate.onAttachButtonHidden(); + } updateFieldRight(0); } } } - } else if (sendButton.getVisibility() == View.VISIBLE) { + } else if (sendButton.getVisibility() == VISIBLE || cancelBotButton.getVisibility() == VISIBLE) { if (animated) { if (runningAnimationType == 2) { return; @@ -1229,7 +1666,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } if (attachButton != null) { - attachButton.setVisibility(View.VISIBLE); + attachButton.setVisibility(VISIBLE); runningAnimation2 = new AnimatorSetProxy(); runningAnimation2.playTogether( ObjectAnimatorProxy.ofFloat(attachButton, "alpha", 1.0f), @@ -1237,52 +1674,70 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat ); runningAnimation2.setDuration(100); runningAnimation2.start(); - updateFieldRight(1); - delegate.onAttachButtonShow(); } - audioSendButton.setVisibility(View.VISIBLE); + audioSendButton.setVisibility(VISIBLE); runningAnimation = new AnimatorSetProxy(); runningAnimationType = 2; - runningAnimation.playTogether( - ObjectAnimatorProxy.ofFloat(sendButton, "scaleX", 0.1f), - ObjectAnimatorProxy.ofFloat(sendButton, "scaleY", 0.1f), - ObjectAnimatorProxy.ofFloat(sendButton, "alpha", 0.0f), - ObjectAnimatorProxy.ofFloat(audioSendButton, "scaleX", 1.0f), - ObjectAnimatorProxy.ofFloat(audioSendButton, "scaleY", 1.0f), - ObjectAnimatorProxy.ofFloat(audioSendButton, "alpha", 1.0f) - ); + ArrayList animators = new ArrayList<>(); + animators.add(ObjectAnimatorProxy.ofFloat(audioSendButton, "scaleX", 1.0f)); + animators.add(ObjectAnimatorProxy.ofFloat(audioSendButton, "scaleY", 1.0f)); + animators.add(ObjectAnimatorProxy.ofFloat(audioSendButton, "alpha", 1.0f)); + if (cancelBotButton.getVisibility() == VISIBLE) { + animators.add(ObjectAnimatorProxy.ofFloat(cancelBotButton, "scaleX", 0.1f)); + animators.add(ObjectAnimatorProxy.ofFloat(cancelBotButton, "scaleY", 0.1f)); + animators.add(ObjectAnimatorProxy.ofFloat(cancelBotButton, "alpha", 0.0f)); + } else { + animators.add(ObjectAnimatorProxy.ofFloat(sendButton, "scaleX", 0.1f)); + animators.add(ObjectAnimatorProxy.ofFloat(sendButton, "scaleY", 0.1f)); + animators.add(ObjectAnimatorProxy.ofFloat(sendButton, "alpha", 0.0f)); + } + runningAnimation.playTogether(animators); runningAnimation.setDuration(150); runningAnimation.addListener(new AnimatorListenerAdapterProxy() { @Override public void onAnimationEnd(Object animation) { if (runningAnimation != null && runningAnimation.equals(animation)) { - sendButton.setVisibility(View.GONE); + sendButton.setVisibility(GONE); sendButton.clearAnimation(); - audioSendButton.setVisibility(View.VISIBLE); + cancelBotButton.setVisibility(GONE); + cancelBotButton.clearAnimation(); + audioSendButton.setVisibility(VISIBLE); runningAnimation = null; runningAnimationType = 0; } } + + @Override + public void onAnimationCancel(Object animation) { + if (runningAnimation != null && runningAnimation.equals(animation)) { + runningAnimation = null; + } + } }); runningAnimation.start(); } else { ViewProxy.setScaleX(sendButton, 0.1f); ViewProxy.setScaleY(sendButton, 0.1f); ViewProxy.setAlpha(sendButton, 0.0f); + ViewProxy.setScaleX(cancelBotButton, 0.1f); + ViewProxy.setScaleY(cancelBotButton, 0.1f); + ViewProxy.setAlpha(cancelBotButton, 0.0f); ViewProxy.setScaleX(audioSendButton, 1.0f); ViewProxy.setScaleY(audioSendButton, 1.0f); ViewProxy.setAlpha(audioSendButton, 1.0f); - sendButton.setVisibility(View.GONE); + cancelBotButton.setVisibility(GONE); + cancelBotButton.clearAnimation(); + sendButton.setVisibility(GONE); sendButton.clearAnimation(); - audioSendButton.setVisibility(View.VISIBLE); + audioSendButton.setVisibility(VISIBLE); if (attachButton != null) { delegate.onAttachButtonShow(); - attachButton.setVisibility(View.VISIBLE); + attachButton.setVisibility(VISIBLE); updateFieldRight(1); } } @@ -1290,19 +1745,19 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } private void updateFieldRight(int attachVisible) { - if (messageEditText == null) { + if (messageEditText == null || editingMessageObject != null) { return; } FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) messageEditText.getLayoutParams(); if (attachVisible == 1) { - if (botButton != null && botButton.getVisibility() == VISIBLE) { + if (botButton != null && botButton.getVisibility() == VISIBLE || notifyButton != null && notifyButton.getVisibility() == VISIBLE) { layoutParams.rightMargin = AndroidUtilities.dp(98); } else { layoutParams.rightMargin = AndroidUtilities.dp(50); } } else if (attachVisible == 2) { if (layoutParams.rightMargin != AndroidUtilities.dp(2)) { - if (botButton != null && botButton.getVisibility() == VISIBLE) { + if (botButton != null && botButton.getVisibility() == VISIBLE || notifyButton != null && notifyButton.getVisibility() == VISIBLE) { layoutParams.rightMargin = AndroidUtilities.dp(98); } else { layoutParams.rightMargin = AndroidUtilities.dp(50); @@ -1394,8 +1849,8 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat params.leftMargin = AndroidUtilities.dp(30); slideText.setLayoutParams(params); ViewProxy.setAlpha(slideText, 1); - recordPanel.setVisibility(View.GONE); - recordCircle.setVisibility(View.GONE); + recordPanel.setVisibility(GONE); + recordCircle.setVisibility(GONE); runningAnimationAudio = null; } } @@ -1425,20 +1880,94 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat messageEditText.setText(text); messageEditText.setSelection(messageEditText.getText().length()); ignoreTextChange = false; + if (delegate != null) { + delegate.onTextChanged(messageEditText.getText(), true); + } if (!keyboardVisible && currentPopupContentType == -1) { openKeyboard(); } } else { TLRPC.User user = messageObject != null && (int) dialog_id < 0 ? MessagesController.getInstance().getUser(messageObject.messageOwner.from_id) : null; if ((botCount != 1 || username) && user != null && user.bot && !command.contains("@")) { - SendMessagesHelper.getInstance().sendMessage(String.format(Locale.US, "%s@%s", command, user.username), dialog_id, null, null, false, asAdmin(), null, null); + SendMessagesHelper.getInstance().sendMessage(String.format(Locale.US, "%s@%s", command, user.username), dialog_id, null, null, false, asAdmin(), null, null, null); } else { - SendMessagesHelper.getInstance().sendMessage(command, dialog_id, null, null, false, asAdmin(), null, null); + SendMessagesHelper.getInstance().sendMessage(command, dialog_id, null, null, false, asAdmin(), null, null, null); } } } - public void setFieldText(String text) { + public void setEditinigMessageObject(MessageObject messageObject, boolean caption) { + if (audioToSend != null || editingMessageObject == messageObject) { + return; + } + //SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + //int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + //messageEditText.setTextColor(themePrefs.getInt("chatRTextColor", 0xff000000)); + + editingMessageObject = messageObject; + editingCaption = caption; + if (editingMessageObject != null) { + //messageEditText.getPaint().set(editingMessageObject.getEditTextPaint()); + InputFilter[] inputFilters = new InputFilter[1]; + if (caption) { + inputFilters[0] = new InputFilter.LengthFilter(200); + if (editingMessageObject.caption != null) { + setFieldText(Emoji.replaceEmoji(new SpannableStringBuilder(editingMessageObject.caption.toString()), messageEditText.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false)); + } else { + setFieldText(""); + } + } else { + inputFilters[0] = new InputFilter.LengthFilter(4096); + if (editingMessageObject.messageText != null) { + setFieldText(Emoji.replaceEmoji(new SpannableStringBuilder(editingMessageObject.messageText.toString()), messageEditText.getPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false)); + } else { + setFieldText(""); + } + } + messageEditText.setFilters(inputFilters); + openKeyboard(); + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) messageEditText.getLayoutParams(); + layoutParams.rightMargin = AndroidUtilities.dp(4); + messageEditText.setLayoutParams(layoutParams); + sendButton.clearAnimation(); + cancelBotButton.clearAnimation(); + audioSendButton.clearAnimation(); + attachButton.clearAnimation(); + sendButtonContainer.clearAnimation(); + sendButton.setVisibility(GONE); + cancelBotButton.setVisibility(GONE); + audioSendButton.setVisibility(GONE); + attachButton.setVisibility(GONE); + sendButtonContainer.setVisibility(GONE); + } else { + messageEditText.setFilters(new InputFilter[0]); + delegate.onMessageEditEnd(); + audioSendButton.setVisibility(VISIBLE); + attachButton.setVisibility(VISIBLE); + sendButtonContainer.setVisibility(VISIBLE); + ViewProxy.setScaleX(attachButton, 1.0f); + ViewProxy.setAlpha(attachButton, 1.0f); + ViewProxy.setScaleX(sendButton, 0.1f); + ViewProxy.setScaleY(sendButton, 0.1f); + ViewProxy.setAlpha(sendButton, 0.0f); + ViewProxy.setScaleX(cancelBotButton, 0.1f); + ViewProxy.setScaleY(cancelBotButton, 0.1f); + ViewProxy.setAlpha(cancelBotButton, 0.0f); + ViewProxy.setScaleX(audioSendButton, 1.0f); + ViewProxy.setScaleY(audioSendButton, 1.0f); + ViewProxy.setAlpha(audioSendButton, 1.0f); + sendButton.setVisibility(GONE); + sendButton.clearAnimation(); + cancelBotButton.setVisibility(GONE); + cancelBotButton.clearAnimation(); + messageEditText.setText(""); + delegate.onAttachButtonShow(); + updateFieldRight(1); + } + updateFieldHint(); + } + + public void setFieldText(CharSequence text) { if (messageEditText == null) { return; } @@ -1521,6 +2050,9 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat ViewGroup viewGroup = (ViewGroup) view.getParent(); viewGroup.removeView(view); } + if (Build.VERSION.SDK_INT >= 21) { + view.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.INPUT_FIELD_SELECTOR_COLOR)); + } attachButton.addView(view, LayoutHelper.createLinear(48, 48)); } @@ -1532,32 +2064,23 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat if (botButton.getVisibility() != VISIBLE) { botButton.setVisibility(VISIBLE); } - Drawable d; SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); int color = themePrefs.getInt("chatEditTextIconsColor", 0xffadadad); if (botReplyMarkup != null) { if (isPopupShowing() && currentPopupContentType == 1) { - d = getResources().getDrawable(R.drawable.ic_msg_panel_kb); - d.setColorFilter(color, PorterDuff.Mode.SRC_IN); - botButton.setImageDrawable(d); - //botButton.setImageResource(R.drawable.ic_msg_panel_kb); + botButton.setImageResource(R.drawable.ic_msg_panel_kb); } else { - d = getResources().getDrawable(R.drawable.bot_keyboard2); - d.setColorFilter(color, PorterDuff.Mode.SRC_IN); - botButton.setImageDrawable(d); - //botButton.setImageResource(R.drawable.bot_keyboard2); + botButton.setImageResource(R.drawable.bot_keyboard2); } } else { - d = getResources().getDrawable(R.drawable.bot_keyboard); - d.setColorFilter(color, PorterDuff.Mode.SRC_IN); - botButton.setImageDrawable(d); - //botButton.setImageResource(R.drawable.bot_keyboard); + botButton.setImageResource(R.drawable.bot_keyboard); } + botButton.setColorFilter(color, PorterDuff.Mode.SRC_IN); } else { botButton.setVisibility(GONE); } updateFieldRight(2); - ViewProxy.setPivotX(attachButton, AndroidUtilities.dp(botButton.getVisibility() == GONE ? 48 : 96)); + ViewProxy.setPivotX(attachButton, AndroidUtilities.dp((botButton == null || botButton.getVisibility() == GONE) && (notifyButton == null || notifyButton.getVisibility() == GONE) ? 48 : 96)); attachButton.clearAnimation(); } @@ -1586,9 +2109,9 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat botKeyboardView.setVisibility(GONE); botKeyboardView.setDelegate(new BotKeyboardView.BotKeyboardViewDelegate() { @Override - public void didPressedButton(CharSequence text) { + public void didPressedButton(TLRPC.KeyboardButton button) { MessageObject object = replyingMessageObject != null ? replyingMessageObject : ((int) dialog_id < 0 ? botButtonsMessageObject : null); - SendMessagesHelper.getInstance().sendMessage(text.toString(), dialog_id, object, null, false, asAdmin(), null, null); + didPressedBotButton(button, object, replyingMessageObject != null ? replyingMessageObject : botButtonsMessageObject); if (replyingMessageObject != null) { openKeyboardInternal(); setButtons(botMessageObject, false); @@ -1618,7 +2141,8 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } } if (!keyboardHidden && messageEditText.length() == 0 && !isPopupShowing()) { - //showPopup(1, 1); //hide botbuttons by default + //showPopup(1, 1); + if(!hideBotKeyboard)showPopup(1, 1); } } else { if (isPopupShowing() && currentPopupContentType == 1) { @@ -1632,6 +2156,92 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat updateBotButton(); } + public void didPressedBotButton(final TLRPC.KeyboardButton button, final MessageObject replyMessageObject, final MessageObject messageObject) { + if (button == null || messageObject == null) { + return; + } + if (button instanceof TLRPC.TL_keyboardButton) { + SendMessagesHelper.getInstance().sendMessage(button.text, dialog_id, replyMessageObject, null, false, asAdmin(), null, null, null); + } else if (button instanceof TLRPC.TL_keyboardButtonUrl) { + parentFragment.showOpenUrlAlert(button.url); + } else if (button instanceof TLRPC.TL_keyboardButtonRequestPhone) { + parentFragment.shareMyContact(messageObject); + } else if (button instanceof TLRPC.TL_keyboardButtonRequestGeoLocation) { + AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); + builder.setTitle(LocaleController.getString("ShareYouLocationTitle", R.string.ShareYouLocationTitle)); + builder.setMessage(LocaleController.getString("ShareYouLocationInfo", R.string.ShareYouLocationInfo)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (Build.VERSION.SDK_INT >= 23 && parentActivity.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + parentActivity.requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 2); + pendingMessageObject = messageObject; + pendingLocationButton = button; + return; + } + SendMessagesHelper.getInstance().sendCurrentLocation(messageObject, button); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + parentFragment.showDialog(builder.create()); + } else if (button instanceof TLRPC.TL_keyboardButtonCallback) { + SendMessagesHelper.getInstance().sendCallback(messageObject, button, parentFragment); + } else if (button instanceof TLRPC.TL_keyboardButtonSwitchInline) { + if (parentFragment.processSwitchButton((TLRPC.TL_keyboardButtonSwitchInline) button)) { + return; + } + Bundle args = new Bundle(); + args.putBoolean("onlySelect", true); + args.putInt("dialogsType", 1); + DialogsActivity fragment = new DialogsActivity(args); + fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { + @Override + public void didSelectDialog(DialogsActivity fragment, long did, boolean param) { + int uid = messageObject.messageOwner.from_id; + if (messageObject.messageOwner.via_bot_id != 0) { + uid = messageObject.messageOwner.via_bot_id; + } + TLRPC.User user = MessagesController.getInstance().getUser(uid); + if (user == null) { + fragment.finishFragment(); + return; + } + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString("dialog_" + did, "@" + user.username + " " + button.query); + editor.commit(); + if (did != dialog_id) { + int lower_part = (int) did; + if (lower_part != 0) { + Bundle args = new Bundle(); + if (lower_part > 0) { + args.putInt("user_id", lower_part); + } else if (lower_part < 0) { + args.putInt("chat_id", -lower_part); + } + if (!MessagesController.checkCanOpenChat(args, fragment)) { + return; + } + ChatActivity chatActivity = new ChatActivity(args); + if (parentFragment.presentFragment(chatActivity, true)) { + if (!AndroidUtilities.isTablet()) { + parentFragment.removeSelfFromStack(); + } + } else { + fragment.finishFragment(); + } + } else { + fragment.finishFragment(); + } + } else { + fragment.finishFragment(); + } + } + }); + parentFragment.presentFragment(fragment); + } + } + public boolean isPopupView(View view) { return view == botKeyboardView || view == emojiView; } @@ -1674,10 +2284,7 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } public void onStickerSelected(TLRPC.Document sticker) { - SendMessagesHelper.getInstance().sendSticker(sticker, dialog_id, replyingMessageObject, asAdmin()); - if (delegate != null) { - delegate.onMessageSend(null); - } + ChatActivityEnterView.this.onStickerSelected(sticker); } @Override @@ -1689,7 +2296,10 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat @Override public void onGifSelected(TLRPC.Document gif) { - SendMessagesHelper.getInstance().sendMessage((TLRPC.TL_document) gif, null, dialog_id, replyingMessageObject, asAdmin(), null); + SendMessagesHelper.getInstance().sendSticker(gif, dialog_id, replyingMessageObject, asAdmin()); + if ((int) dialog_id == 0) { + MessagesController.getInstance().saveGif(gif); + } if (delegate != null) { delegate.onMessageSend(null); } @@ -1713,11 +2323,37 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat public void onStickersTab(boolean opened) { delegate.onStickersTab(opened); } + + @Override + public void onClearEmojiRecent() { + if (parentFragment == null || parentActivity == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("ClearRecentEmoji", R.string.ClearRecentEmoji)); + builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + emojiView.clearRecentEmoji(); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + parentFragment.showDialog(builder.create()); + } }); emojiView.setVisibility(GONE); sizeNotifierLayout.addView(emojiView); } + @Override + public void onStickerSelected(TLRPC.Document sticker) { + SendMessagesHelper.getInstance().sendSticker(sticker, dialog_id, replyingMessageObject, asAdmin()); + if (delegate != null) { + delegate.onMessageSend(null); + } + } + private void showPopup(int show, int contentType) { SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); int color = themePrefs.getInt("chatEditTextIconsColor", 0xffadadad); @@ -1768,17 +2404,12 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat emojiPadding = currentHeight; sizeNotifierLayout.requestLayout(); try{ - if (contentType == 0) { - Drawable d = getResources().getDrawable(R.drawable.ic_msg_panel_kb); - d.setColorFilter(color, PorterDuff.Mode.SRC_IN); - emojiButton.setImageDrawable(d); - //emojiButton.setImageResource(R.drawable.ic_msg_panel_kb); - } else if (contentType == 1) { - Drawable d = getResources().getDrawable(R.drawable.ic_msg_panel_smiles); - d.setColorFilter(color, PorterDuff.Mode.SRC_IN); - emojiButton.setImageDrawable(d); - //emojiButton.setImageResource(R.drawable.ic_msg_panel_smiles); - } + if (contentType == 0) { + emojiButton.setImageResource(R.drawable.ic_msg_panel_kb); + } else if (contentType == 1) { + emojiButton.setImageResource(R.drawable.ic_msg_panel_smiles); + } + emojiButton.setColorFilter(color, PorterDuff.Mode.SRC_IN); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -1787,10 +2418,8 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } } else { if (emojiButton != null) { - Drawable d = getResources().getDrawable(R.drawable.ic_msg_panel_smiles); - d.setColorFilter(color, PorterDuff.Mode.SRC_IN); - emojiButton.setImageDrawable(d); - //emojiButton.setImageResource(R.drawable.ic_msg_panel_smiles); + emojiButton.setImageResource(R.drawable.ic_msg_panel_smiles); + emojiButton.setColorFilter(color, PorterDuff.Mode.SRC_IN); } currentPopupContentType = -1; if (emojiView != null) { @@ -1842,6 +2471,18 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat } } + public boolean isEditingMessage() { + return editingMessageObject != null; + } + + public boolean isEditingCaption() { + return editingCaption; + } + + public boolean hasAudioToSend() { + return audioToSendMessageObject != null; + } + public void openKeyboard() { AndroidUtilities.showKeyboard(messageEditText); } @@ -1879,7 +2520,6 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat if (isPopupShowing()) { int newHeight = isWidthGreater ? keyboardHeightLand : keyboardHeight; - //SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("emoji", Activity.MODE_PRIVATE); SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); int pSize = plusPreferences.getInt("emojiPopupSize", 60); int popupSize = AndroidUtilities.dp((pSize - 40) * 10); @@ -1957,8 +2597,10 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat botKeyboardView.invalidateViews(); } } else if (id == NotificationCenter.recordProgressChanged) { - Long time = (Long) args[0] / 1000; - String str = String.format("%02d:%02d", time / 60, time % 60); + long t = (Long) args[0]; + Long time = t / 1000; + int ms = (int) (t % 1000L) / 10; + String str = String.format("%02d:%02d.%02d", time / 60, time % 60, ms); if (lastTimeString == null || !lastTimeString.equals(str)) { if (time % 5 == 0) { MessagesController.getInstance().sendTyping(dialog_id, 1, 0); @@ -1986,14 +2628,89 @@ public class ChatActivityEnterView extends FrameLayoutFixed implements Notificat updateAudioRecordIntefrace(); } } else if (id == NotificationCenter.audioDidSent) { - if (delegate != null) { - delegate.onMessageSend(null); + audioToSend = (TLRPC.TL_document) args[0]; + audioToSendPath = (String) args[1]; + if (audioToSend != null) { + if (recordedAudioPanel == null) { + return; + } + + TLRPC.TL_message message = new TLRPC.TL_message(); + message.out = true; + message.id = 0; + message.to_id = new TLRPC.TL_peerUser(); + message.to_id.user_id = message.from_id = UserConfig.getClientUserId(); + message.date = (int) (System.currentTimeMillis() / 1000); + message.message = "-1"; + message.attachPath = audioToSendPath; + message.media = new TLRPC.TL_messageMediaDocument(); + message.media.document = audioToSend; + message.flags |= TLRPC.MESSAGE_FLAG_HAS_MEDIA | TLRPC.MESSAGE_FLAG_HAS_FROM_ID; + audioToSendMessageObject = new MessageObject(message, null, false); + + ViewProxy.setAlpha(recordedAudioPanel, 1.0f); + recordedAudioPanel.clearAnimation(); + recordedAudioPanel.setVisibility(VISIBLE); + int duration = 0; + for (int a = 0; a < audioToSend.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = audioToSend.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + duration = attribute.duration; + break; + } + } + + for (int a = 0; a < audioToSend.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = audioToSend.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.waveform == null || attribute.waveform.length == 0) { + attribute.waveform = MediaController.getInstance().getWaveform(audioToSendPath); + } + recordedAudioSeekBar.setWaveform(attribute.waveform); + break; + } + } + recordedAudioTimeTextView.setText(String.format("%d:%02d", duration / 60, duration % 60)); + closeKeyboard(); + hidePopup(false); + checkSendButton(false); + } else { + if (delegate != null) { + delegate.onMessageSend(null); + } } } else if (id == NotificationCenter.audioRouteChanged) { if (parentActivity != null) { boolean frontSpeaker = (Boolean) args[0]; parentActivity.setVolumeControlStream(frontSpeaker ? AudioManager.STREAM_VOICE_CALL : AudioManager.USE_DEFAULT_STREAM_TYPE); } + } else if (id == NotificationCenter.audioDidReset) { + if (audioToSendMessageObject != null && !MediaController.getInstance().isPlayingAudio(audioToSendMessageObject)) { + recordedAudioPlayButton.setImageResource(R.drawable.s_player_play_states); + recordedAudioSeekBar.setProgress(0); + } + } else if (id == NotificationCenter.audioProgressDidChanged) { + Integer mid = (Integer) args[0]; + if (audioToSendMessageObject != null && MediaController.getInstance().isPlayingAudio(audioToSendMessageObject)) { + MessageObject player = MediaController.getInstance().getPlayingMessageObject(); + audioToSendMessageObject.audioProgress = player.audioProgress; + audioToSendMessageObject.audioProgressSec = player.audioProgressSec; + if (!recordedAudioSeekBar.isDragging()) { + recordedAudioSeekBar.setProgress(audioToSendMessageObject.audioProgress); + } + } + } + } + + public void onRequestPermissionsResultFragment(int requestCode, String[] permissions, int[] grantResults) { + if (requestCode == 2) { + if (pendingLocationButton != null) { + if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + SendMessagesHelper.getInstance().sendCurrentLocation(pendingMessageObject, pendingLocationButton); + } + pendingLocationButton = null; + pendingMessageObject = null; + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachView.java new file mode 100644 index 00000000..a56fd006 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAttachView.java @@ -0,0 +1,647 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.Manifest; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.os.Build; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.DecelerateInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.AnimationCompat.ViewProxy; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.support.widget.LinearLayoutManager; +import org.telegram.messenger.support.widget.RecyclerView; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.PhotoAttachPhotoCell; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.PhotoViewer; + +import java.util.ArrayList; +import java.util.HashMap; + +public class ChatAttachView extends FrameLayout implements NotificationCenter.NotificationCenterDelegate, PhotoViewer.PhotoViewerProvider { + + public interface ChatAttachViewDelegate { + void didPressedButton(int button); + } + + private LinearLayoutManager attachPhotoLayoutManager; + private PhotoAttachAdapter photoAttachAdapter; + private ChatActivity baseFragment; + private AttachButton sendPhotosButton; + private View views[] = new View[20]; + private RecyclerListView attachPhotoRecyclerView; + private View lineView; + private EmptyTextProgressView progressView; + private ArrayList viewsCache = new ArrayList<>(8); + + private float[] distCache = new float[20]; + + private DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator(); + + private boolean loading = true; + + private ChatAttachViewDelegate delegate; + + private static class AttachButton extends FrameLayout { + + private TextView textView; + private ImageView imageView; + + public AttachButton(Context context) { + super(context); + + imageView = new ImageView(context); + imageView.setScaleType(ImageView.ScaleType.CENTER); + addView(imageView, LayoutHelper.createFrame(64, 64, Gravity.CENTER_HORIZONTAL | Gravity.TOP)); + + textView = new TextView(context); + textView.setLines(1); + textView.setSingleLine(true); + textView.setGravity(Gravity.CENTER_HORIZONTAL); + textView.setEllipsize(TextUtils.TruncateAt.END); + //textView.setTextColor(0xff757575); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + textView.setTextColor(themePrefs.getInt("chatAttachTextColor", 0xff757575)); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 0, 64, 0, 0)); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(85), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(90), MeasureSpec.EXACTLY)); + } + + public void setTextAndIcon(CharSequence text, Drawable drawable) { + textView.setText(text); + imageView.setBackgroundDrawable(drawable); + } + } + + public ChatAttachView(Context context) { + super(context); + + NotificationCenter.getInstance().addObserver(this, NotificationCenter.albumsDidLoaded); + + views[8] = attachPhotoRecyclerView = new RecyclerListView(context); + attachPhotoRecyclerView.setVerticalScrollBarEnabled(true); + attachPhotoRecyclerView.setAdapter(photoAttachAdapter = new PhotoAttachAdapter(context)); + attachPhotoRecyclerView.setClipToPadding(false); + attachPhotoRecyclerView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), 0); + attachPhotoRecyclerView.setItemAnimator(null); + attachPhotoRecyclerView.setLayoutAnimation(null); + if (Build.VERSION.SDK_INT >= 9) { + attachPhotoRecyclerView.setOverScrollMode(RecyclerListView.OVER_SCROLL_NEVER); + } + addView(attachPhotoRecyclerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 80)); + attachPhotoLayoutManager = new LinearLayoutManager(context) { + @Override + public boolean supportsPredictiveItemAnimations() { + return false; + } + }; + attachPhotoLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); + attachPhotoRecyclerView.setLayoutManager(attachPhotoLayoutManager); + attachPhotoRecyclerView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { + @SuppressWarnings("unchecked") + @Override + public void onItemClick(View view, int position) { + if (baseFragment == null || baseFragment.getParentActivity() == null) { + return; + } + ArrayList arrayList = (ArrayList) MediaController.allPhotosAlbumEntry.photos; + if (position < 0 || position >= arrayList.size()) { + return; + } + PhotoViewer.getInstance().setParentActivity(baseFragment.getParentActivity()); + PhotoViewer.getInstance().openPhotoForSelect(arrayList, position, 0, ChatAttachView.this, baseFragment); + AndroidUtilities.hideKeyboard(baseFragment.getFragmentView().findFocus()); + } + }); + + views[9] = progressView = new EmptyTextProgressView(context); + if (Build.VERSION.SDK_INT >= 23 && getContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + progressView.setText(LocaleController.getString("PermissionStorage", R.string.PermissionStorage)); + progressView.setTextSize(16); + } else { + progressView.setText(LocaleController.getString("NoPhotos", R.string.NoPhotos)); + progressView.setTextSize(20); + } + addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 80)); + attachPhotoRecyclerView.setEmptyView(progressView); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int color = themePrefs.getInt("chatAttachBGColor", 0xffffffff); + setBackgroundColor(color); + int val = themePrefs.getInt("chatAttachBGGradient", 0); + if(val > 0) { + GradientDrawable.Orientation go; + switch(val) { + case 2: + go = GradientDrawable.Orientation.LEFT_RIGHT; + break; + case 3: + go = GradientDrawable.Orientation.TL_BR; + break; + case 4: + go = GradientDrawable.Orientation.BL_TR; + break; + default: + go = GradientDrawable.Orientation.TOP_BOTTOM; + } + int gradColor = themePrefs.getInt("chatAttachBGGradientColor", 0xffffffff); + int[] colors = new int[]{color, gradColor}; + GradientDrawable gd = new GradientDrawable(go, colors); + setBackgroundDrawable(gd); + } + + views[10] = lineView = new View(getContext()); + //lineView.setBackgroundColor(0xffd2d2d2); + lineView.setBackgroundColor(color == 0xffffffff ? 0xffd2d2d2 : color); + addView(lineView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1, Gravity.TOP | Gravity.LEFT)); + CharSequence[] items = new CharSequence[]{ + LocaleController.getString("ChatCamera", R.string.ChatCamera), + LocaleController.getString("ChatGallery", R.string.ChatGallery), + LocaleController.getString("ChatVideo", R.string.ChatVideo), + LocaleController.getString("AttachMusic", R.string.AttachMusic), + LocaleController.getString("ChatDocument", R.string.ChatDocument), + LocaleController.getString("AttachContact", R.string.AttachContact), + LocaleController.getString("ChatLocation", R.string.ChatLocation), + "" + }; + + for (int a = 0; a < 8; a++) { + AttachButton attachButton = new AttachButton(context); + attachButton.setTextAndIcon(items[a], Theme.attachButtonDrawables[a]); + addView(attachButton, LayoutHelper.createFrame(85, 90, Gravity.LEFT | Gravity.TOP)); + attachButton.setTag(a); + views[a] = attachButton; + if (a == 7) { + sendPhotosButton = attachButton; + sendPhotosButton.imageView.setPadding(0, AndroidUtilities.dp(4), 0, 0); + } + attachButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (delegate != null) { + delegate.didPressedButton((Integer) v.getTag()); + } + } + }); + } + setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + + for (int a = 0; a < 8; a++) { + viewsCache.add(photoAttachAdapter.createHolder()); + } + + if (loading) { + progressView.showProgress(); + } else { + progressView.showTextView(); + } + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.albumsDidLoaded) { + if (photoAttachAdapter != null) { + loading = false; + progressView.showTextView(); + photoAttachAdapter.notifyDataSetChanged(); + } + } + } + + @Override + protected void onMeasure(int widthSpec, int heightSpec) { + super.onMeasure(widthSpec, MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(294), MeasureSpec.EXACTLY)); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + int width = right - left; + + int t = AndroidUtilities.dp(8); + attachPhotoRecyclerView.layout(0, t, width, t + attachPhotoRecyclerView.getMeasuredHeight()); + progressView.layout(0, t, width, t + progressView.getMeasuredHeight()); + lineView.layout(0, AndroidUtilities.dp(96), width, AndroidUtilities.dp(96) + lineView.getMeasuredHeight()); + + int diff = (width - AndroidUtilities.dp(85 * 4 + 20)) / 3; + for (int a = 0; a < 8; a++) { + int y = AndroidUtilities.dp(105 + 95 * (a / 4)); + int x = AndroidUtilities.dp(10) + (a % 4) * (AndroidUtilities.dp(85) + diff); + views[a].layout(x, y, x + views[a].getMeasuredWidth(), y + views[a].getMeasuredHeight()); + } + } + + public void updatePhotosButton() { + int count = photoAttachAdapter.getSelectedPhotos().size(); + if (count == 0) { + sendPhotosButton.imageView.setPadding(0, AndroidUtilities.dp(4), 0, 0); + sendPhotosButton.imageView.setBackgroundResource(R.drawable.attach_hide_states); + sendPhotosButton.imageView.setImageResource(R.drawable.attach_hide2); + sendPhotosButton.textView.setText(""); + } else { + sendPhotosButton.imageView.setPadding(AndroidUtilities.dp(2), 0, 0, 0); + //sendPhotosButton.imageView.setBackgroundResource(R.drawable.attach_send_states); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + Drawable send = getResources().getDrawable(R.drawable.attach_send1); + send.setColorFilter(themePrefs.getInt("themeColor", AndroidUtilities.defColor), PorterDuff.Mode.SRC_IN); + sendPhotosButton.imageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.attach_send_states)); + sendPhotosButton.imageView.setImageResource(R.drawable.attach_send2); + sendPhotosButton.textView.setText(LocaleController.formatString("SendItems", R.string.SendItems, String.format("(%d)", count))); + } + + if (Build.VERSION.SDK_INT >= 23 && getContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + progressView.setText(LocaleController.getString("PermissionStorage", R.string.PermissionStorage)); + progressView.setTextSize(16); + } else { + progressView.setText(LocaleController.getString("NoPhotos", R.string.NoPhotos)); + progressView.setTextSize(20); + } + } + + public void setDelegate(ChatAttachViewDelegate chatAttachViewDelegate) { + delegate = chatAttachViewDelegate; + } + + public void onRevealAnimationEnd(boolean open) { + if (open && Build.VERSION.SDK_INT <= 19 && MediaController.allPhotosAlbumEntry == null) { + MediaController.loadGalleryPhotosAlbums(0); + } + } + + public void loadGalleryPhotos() { + if (MediaController.allPhotosAlbumEntry == null && Build.VERSION.SDK_INT >= 21) { + MediaController.loadGalleryPhotosAlbums(0); + } + } + + @SuppressLint("NewApi") + public void onRevealAnimationStart(boolean open) { + if (!open) { + return; + } + int count = Build.VERSION.SDK_INT <= 19 ? 11 : 8; + for (int a = 0; a < count; a++) { + if (Build.VERSION.SDK_INT <= 19) { + if (a < 8) { + views[a].setScaleX(0.1f); + views[a].setScaleY(0.1f); + } + views[a].setAlpha(0.0f); + } else { + views[a].setScaleX(0.7f); + views[a].setScaleY(0.7f); + } + views[a].setTag(R.string.AppName, null); + distCache[a] = 0; + } + } + + @SuppressLint("NewApi") + public void onRevealAnimationProgress(boolean open, float radius, int x, int y) { + if (!open) { + return; + } + int count = Build.VERSION.SDK_INT <= 19 ? 11 : 8; + for (int a = 0; a < count; a++) { + if (views[a].getTag(R.string.AppName) == null) { + if (distCache[a] == 0) { + int buttonX = views[a].getLeft() + views[a].getMeasuredWidth() / 2; + int buttonY = views[a].getTop() + views[a].getMeasuredHeight() / 2; + distCache[a] = (float) Math.sqrt((x - buttonX) * (x - buttonX) + (y - buttonY) * (y - buttonY)); + float vecX = (x - buttonX) / distCache[a]; + float vecY = (y - buttonY) / distCache[a]; + views[a].setPivotX(views[a].getMeasuredWidth() / 2 + vecX * AndroidUtilities.dp(20)); + views[a].setPivotY(views[a].getMeasuredHeight() / 2 + vecY * AndroidUtilities.dp(20)); + } + if (distCache[a] > radius + AndroidUtilities.dp(27)) { + continue; + } + + views[a].setTag(R.string.AppName, 1); + final ArrayList animators = new ArrayList<>(); + final ArrayList animators2 = new ArrayList<>(); + if (a < 8) { + animators.add(ObjectAnimator.ofFloat(views[a], "scaleX", 0.7f, 1.05f)); + animators.add(ObjectAnimator.ofFloat(views[a], "scaleY", 0.7f, 1.05f)); + animators2.add(ObjectAnimator.ofFloat(views[a], "scaleX", 1.0f)); + animators2.add(ObjectAnimator.ofFloat(views[a], "scaleY", 1.0f)); + } + if (Build.VERSION.SDK_INT <= 19) { + animators.add(ObjectAnimator.ofFloat(views[a], "alpha", 1.0f)); + } + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether(animators); + animatorSet.setDuration(150); + animatorSet.setInterpolator(decelerateInterpolator); + animatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + AnimatorSet animatorSet = new AnimatorSet(); + animatorSet.playTogether(animators2); + animatorSet.setDuration(100); + animatorSet.setInterpolator(decelerateInterpolator); + animatorSet.start(); + } + }); + animatorSet.start(); + } + } + } + + public void init(ChatActivity parentFragment) { + if (MediaController.allPhotosAlbumEntry != null) { + for (int a = 0; a < Math.min(100, MediaController.allPhotosAlbumEntry.photos.size()); a++) { + MediaController.PhotoEntry photoEntry = MediaController.allPhotosAlbumEntry.photos.get(a); + photoEntry.caption = null; + photoEntry.imagePath = null; + photoEntry.thumbPath = null; + } + } + attachPhotoLayoutManager.scrollToPositionWithOffset(0, 1000000); + photoAttachAdapter.clearSelectedPhotos(); + baseFragment = parentFragment; + updatePhotosButton(); + } + + public HashMap getSelectedPhotos() { + return photoAttachAdapter.getSelectedPhotos(); + } + + public void onDestroy() { + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.albumsDidLoaded); + baseFragment = null; + } + + private PhotoAttachPhotoCell getCellForIndex(int index) { + int count = attachPhotoRecyclerView.getChildCount(); + for (int a = 0; a < count; a++) { + View view = attachPhotoRecyclerView.getChildAt(a); + if (view instanceof PhotoAttachPhotoCell) { + PhotoAttachPhotoCell cell = (PhotoAttachPhotoCell) view; + int num = (Integer) cell.getImageView().getTag(); + if (num < 0 || num >= MediaController.allPhotosAlbumEntry.photos.size()) { + continue; + } + if (num == index) { + return cell; + } + } + } + return null; + } + + @Override + public PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index) { + PhotoAttachPhotoCell cell = getCellForIndex(index); + if (cell != null) { + int coords[] = new int[2]; + cell.getImageView().getLocationInWindow(coords); + PhotoViewer.PlaceProviderObject object = new PhotoViewer.PlaceProviderObject(); + object.viewX = coords[0]; + object.viewY = coords[1] - (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); + object.parentView = attachPhotoRecyclerView; + object.imageReceiver = cell.getImageView().getImageReceiver(); + object.thumb = object.imageReceiver.getBitmap(); + object.scale = ViewProxy.getScaleX(cell.getImageView()); + object.clipBottomAddition = (Build.VERSION.SDK_INT >= 21 ? 0 : -AndroidUtilities.statusBarHeight); + cell.getCheckBox().setVisibility(View.GONE); + return object; + } + return null; + } + + @Override + public void updatePhotoAtIndex(int index) { + PhotoAttachPhotoCell cell = getCellForIndex(index); + if (cell != null) { + cell.getImageView().setOrientation(0, true); + MediaController.PhotoEntry photoEntry = MediaController.allPhotosAlbumEntry.photos.get(index); + if (photoEntry.thumbPath != null) { + cell.getImageView().setImage(photoEntry.thumbPath, null, cell.getContext().getResources().getDrawable(R.drawable.nophotos)); + } else if (photoEntry.path != null) { + cell.getImageView().setOrientation(photoEntry.orientation, true); + cell.getImageView().setImage("thumb://" + photoEntry.imageId + ":" + photoEntry.path, null, cell.getContext().getResources().getDrawable(R.drawable.nophotos)); + } else { + cell.getImageView().setImageResource(R.drawable.nophotos); + } + } + } + + @Override + public Bitmap getThumbForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index) { + PhotoAttachPhotoCell cell = getCellForIndex(index); + if (cell != null) { + return cell.getImageView().getImageReceiver().getBitmap(); + } + return null; + } + + @Override + public void willSwitchFromPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index) { + PhotoAttachPhotoCell cell = getCellForIndex(index); + if (cell != null) { + cell.getCheckBox().setVisibility(View.VISIBLE); + } + } + + @Override + public void willHidePhotoViewer() { + int count = attachPhotoRecyclerView.getChildCount(); + for (int a = 0; a < count; a++) { + View view = attachPhotoRecyclerView.getChildAt(a); + if (view instanceof PhotoAttachPhotoCell) { + PhotoAttachPhotoCell cell = (PhotoAttachPhotoCell) view; + if (cell.getCheckBox().getVisibility() != VISIBLE) { + cell.getCheckBox().setVisibility(VISIBLE); + } + } + } + } + + @Override + public boolean isPhotoChecked(int index) { + return !(index < 0 || index >= MediaController.allPhotosAlbumEntry.photos.size()) && photoAttachAdapter.getSelectedPhotos().containsKey(MediaController.allPhotosAlbumEntry.photos.get(index).imageId); + } + + @Override + public void setPhotoChecked(int index) { + boolean add = true; + if (index < 0 || index >= MediaController.allPhotosAlbumEntry.photos.size()) { + return; + } + MediaController.PhotoEntry photoEntry = MediaController.allPhotosAlbumEntry.photos.get(index); + if (photoAttachAdapter.getSelectedPhotos().containsKey(photoEntry.imageId)) { + photoAttachAdapter.getSelectedPhotos().remove(photoEntry.imageId); + add = false; + } else { + photoAttachAdapter.getSelectedPhotos().put(photoEntry.imageId, photoEntry); + } + int count = attachPhotoRecyclerView.getChildCount(); + for (int a = 0; a < count; a++) { + View view = attachPhotoRecyclerView.getChildAt(a); + int num = (Integer) view.getTag(); + if (num == index) { + ((PhotoAttachPhotoCell) view).setChecked(add, false); + break; + } + } + updatePhotosButton(); + } + + @Override + public boolean cancelButtonPressed() { + return false; + } + + @Override + public void sendButtonPressed(int index) { + if (photoAttachAdapter.getSelectedPhotos().isEmpty()) { + if (index < 0 || index >= MediaController.allPhotosAlbumEntry.photos.size()) { + return; + } + MediaController.PhotoEntry photoEntry = MediaController.allPhotosAlbumEntry.photos.get(index); + photoAttachAdapter.getSelectedPhotos().put(photoEntry.imageId, photoEntry); + } + delegate.didPressedButton(7); + } + + @Override + public int getSelectedCount() { + return photoAttachAdapter.getSelectedPhotos().size(); + } + + @Override + public boolean hasOverlappingRendering() { + return false; + } + + public class PhotoAttachAdapter extends RecyclerView.Adapter { + + private Context mContext; + private HashMap selectedPhotos = new HashMap<>(); + + private class Holder extends RecyclerView.ViewHolder { + + public Holder(View itemView) { + super(itemView); + } + } + + public PhotoAttachAdapter(Context context) { + mContext = context; + } + + public void clearSelectedPhotos() { + if (!selectedPhotos.isEmpty()) { + for (HashMap.Entry entry : selectedPhotos.entrySet()) { + MediaController.PhotoEntry photoEntry = entry.getValue(); + photoEntry.imagePath = null; + photoEntry.thumbPath = null; + photoEntry.caption = null; + } + selectedPhotos.clear(); + updatePhotosButton(); + notifyDataSetChanged(); + } + } + + public Holder createHolder() { + PhotoAttachPhotoCell cell = new PhotoAttachPhotoCell(mContext); + cell.setDelegate(new PhotoAttachPhotoCell.PhotoAttachPhotoCellDelegate() { + @Override + public void onCheckClick(PhotoAttachPhotoCell v) { + MediaController.PhotoEntry photoEntry = v.getPhotoEntry(); + if (selectedPhotos.containsKey(photoEntry.imageId)) { + selectedPhotos.remove(photoEntry.imageId); + v.setChecked(false, true); + photoEntry.imagePath = null; + photoEntry.thumbPath = null; + v.setPhotoEntry(photoEntry, (Integer) v.getTag() == MediaController.allPhotosAlbumEntry.photos.size() - 1); + } else { + selectedPhotos.put(photoEntry.imageId, photoEntry); + v.setChecked(true, true); + } + updatePhotosButton(); + } + }); + return new Holder(cell); + } + + public HashMap getSelectedPhotos() { + return selectedPhotos; + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + PhotoAttachPhotoCell cell = (PhotoAttachPhotoCell) holder.itemView; + MediaController.PhotoEntry photoEntry = MediaController.allPhotosAlbumEntry.photos.get(position); + cell.setPhotoEntry(photoEntry, position == MediaController.allPhotosAlbumEntry.photos.size() - 1); + cell.setChecked(selectedPhotos.containsKey(photoEntry.imageId), false); + cell.getImageView().setTag(position); + cell.setTag(position); + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + Holder holder; + if (!viewsCache.isEmpty()) { + holder = viewsCache.get(0); + viewsCache.remove(0); + } else { + holder = createHolder(); + } + return holder; + } + + @Override + public int getItemCount() { + return (MediaController.allPhotosAlbumEntry != null ? MediaController.allPhotosAlbumEntry.photos.size() : 0); + } + + @Override + public int getItemViewType(int position) { + return 0; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java new file mode 100644 index 00000000..3a56e5c8 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChatAvatarContainer.java @@ -0,0 +1,386 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.os.Build; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ImageView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.SimpleTextView; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.ProfileActivity; + +public class ChatAvatarContainer extends FrameLayout { + + private BackupImageView avatarImageView; + private SimpleTextView titleTextView; + private SimpleTextView subtitleTextView; + private RadioButton radioButton; + private ImageView timeItem; + private TimerDrawable timerDrawable; + private ChatActivity parentFragment; + private TypingDotsDrawable typingDotsDrawable; + private RecordStatusDrawable recordStatusDrawable; + private SendingFileExDrawable sendingFileDrawable; + private AvatarDrawable avatarDrawable = new AvatarDrawable(); + private ChatAvatarContainerDelegate delegate; + + private int onlineCount = -1; + + public interface ChatAvatarContainerDelegate { + void didPressedRadioButton(); + } + + public ChatAvatarContainer(Context context, ChatActivity chatActivity, boolean needRadio, boolean needTime) { + super(context); + parentFragment = chatActivity; + + avatarImageView = new BackupImageView(context); + avatarImageView.setRoundRadius(AndroidUtilities.dp(21)); + addView(avatarImageView); + + titleTextView = new SimpleTextView(context); + titleTextView.setTextColor(Theme.ACTION_BAR_TITLE_COLOR); + titleTextView.setTextSize(18); + titleTextView.setGravity(Gravity.LEFT); + titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + titleTextView.setLeftDrawableTopPadding(-AndroidUtilities.dp(1.3f)); + titleTextView.setRightDrawableTopPadding(-AndroidUtilities.dp(1.3f)); + addView(titleTextView); + + subtitleTextView = new SimpleTextView(context); + subtitleTextView.setTextColor(Theme.ACTION_BAR_SUBTITLE_COLOR); + subtitleTextView.setTextSize(14); + subtitleTextView.setGravity(Gravity.LEFT); + addView(subtitleTextView); + + if (needTime) { + timeItem = new ImageView(context); + timeItem.setPadding(AndroidUtilities.dp(10), AndroidUtilities.dp(10), AndroidUtilities.dp(5), AndroidUtilities.dp(5)); + timeItem.setScaleType(ImageView.ScaleType.CENTER); + timeItem.setImageDrawable(timerDrawable = new TimerDrawable(context)); + addView(timeItem); + timeItem.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + parentFragment.showDialog(AndroidUtilities.buildTTLAlert(getContext(), parentFragment.getCurrentEncryptedChat()).create()); + } + }); + } + + if (needRadio) { + radioButton = new RadioButton(context); + radioButton.setVisibility(View.GONE); + addView(radioButton); + } + + setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (radioButton == null || radioButton.getVisibility() != View.VISIBLE) { + TLRPC.User user = parentFragment.getCurrentUser(); + TLRPC.Chat chat = parentFragment.getCurrentChat(); + if (user != null) { + Bundle args = new Bundle(); + args.putInt("user_id", user.id); + if (timeItem != null) { + args.putLong("dialog_id", parentFragment.getDialogId()); + } + ProfileActivity fragment = new ProfileActivity(args); + fragment.setPlayProfileAnimation(true); + parentFragment.presentFragment(fragment); + } else if (chat != null) { + Bundle args = new Bundle(); + args.putInt("chat_id", chat.id); + ProfileActivity fragment = new ProfileActivity(args); + fragment.setChatInfo(parentFragment.getCurrentChatInfo()); + fragment.setPlayProfileAnimation(true); + parentFragment.presentFragment(fragment); + } + } else { + delegate.didPressedRadioButton(); + } + } + }); + + TLRPC.Chat chat = parentFragment.getCurrentChat(); + typingDotsDrawable = new TypingDotsDrawable(); + typingDotsDrawable.setIsChat(chat != null); + recordStatusDrawable = new RecordStatusDrawable(); + recordStatusDrawable.setIsChat(chat != null); + sendingFileDrawable = new SendingFileExDrawable(); + sendingFileDrawable.setIsChat(chat != null); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = MeasureSpec.getSize(widthMeasureSpec); + int availableWidth = width - AndroidUtilities.dp(54 + 16); + avatarImageView.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(42), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(42), MeasureSpec.EXACTLY)); + titleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24), MeasureSpec.AT_MOST)); + if (radioButton != null && radioButton.getVisibility() == VISIBLE) { + radioButton.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(24), MeasureSpec.EXACTLY)); + availableWidth -= AndroidUtilities.dp(20); + } + subtitleTextView.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(20), MeasureSpec.AT_MOST)); + if (timeItem != null) { + timeItem.measure(MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(34), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(34), MeasureSpec.EXACTLY)); + } + setMeasuredDimension(width, MeasureSpec.getSize(heightMeasureSpec)); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + int actionBarHeight = ActionBar.getCurrentActionBarHeight(); + int viewTop = (actionBarHeight - AndroidUtilities.dp(42)) / 2 + (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); + avatarImageView.layout(AndroidUtilities.dp(8), viewTop, AndroidUtilities.dp(42 + 8), viewTop + AndroidUtilities.dp(42)); + titleTextView.layout(AndroidUtilities.dp(8 + 54), viewTop + AndroidUtilities.dp(1.3f), AndroidUtilities.dp(8 + 54) + titleTextView.getMeasuredWidth(), viewTop + titleTextView.getTextHeight() + AndroidUtilities.dp(1.3f)); + if (timeItem != null) { + timeItem.layout(AndroidUtilities.dp(8 + 16), viewTop + AndroidUtilities.dp(15), AndroidUtilities.dp(8 + 16 + 34), viewTop + AndroidUtilities.dp(15 + 34)); + } + if (radioButton != null && radioButton.getVisibility() == VISIBLE) { + subtitleTextView.layout(AndroidUtilities.dp(8 + 54 + 20), viewTop + AndroidUtilities.dp(24), AndroidUtilities.dp(8 + 54 + 20) + subtitleTextView.getMeasuredWidth(), viewTop + subtitleTextView.getTextHeight() + AndroidUtilities.dp(24)); + viewTop = viewTop + subtitleTextView.getTextHeight() / 2 + AndroidUtilities.dp(12); + radioButton.layout(AndroidUtilities.dp(8 + 50), viewTop, AndroidUtilities.dp(8 + 50 + 24), viewTop + AndroidUtilities.dp(24)); + } else { + subtitleTextView.layout(AndroidUtilities.dp(8 + 54), viewTop + AndroidUtilities.dp(24), AndroidUtilities.dp(8 + 54) + subtitleTextView.getMeasuredWidth(), viewTop + subtitleTextView.getTextHeight() + AndroidUtilities.dp(24)); + } + } + + public void setRadioChecked(boolean value, boolean animated) { + if (radioButton == null) { + return; + } + radioButton.setChecked(value, animated); + } + + public boolean isRadioChecked() { + return radioButton.isChecked(); + } + + public void showTimeItem() { + if (timeItem == null) { + return; + } + timeItem.setVisibility(VISIBLE); + } + + public void hideTimeItem() { + if (timeItem == null) { + return; + } + timeItem.setVisibility(GONE); + } + + public void setTime(int value) { + if (timerDrawable == null) { + return; + } + timerDrawable.setTime(value); + } + + public void setTitleIcons(int leftIcon, int rightIcon) { + titleTextView.setLeftDrawable(leftIcon); + titleTextView.setRightDrawable(rightIcon); + } + + public void setTitle(CharSequence value) { + titleTextView.setText(value); + } + + public void setTitleColor(int color){ + titleTextView.setTextColor(color); + } + + public void setTitleSize(int size){ + titleTextView.setTextSize(size); + } + + public void setSubtitleColor(int color){ + subtitleTextView.setTextColor(color); + } + + public void setSubtitleSize(int size){ + subtitleTextView.setTextSize(size); + } + + public void setDelegate(ChatAvatarContainerDelegate chatAvatarContainerDelegate) { + delegate = chatAvatarContainerDelegate; + } + + private void setTypingAnimation(boolean start) { + if (start) { + try { + Integer type = MessagesController.getInstance().printingStringsTypes.get(parentFragment.getDialogId()); + if (type == 0) { + subtitleTextView.setLeftDrawable(typingDotsDrawable); + typingDotsDrawable.start(); + recordStatusDrawable.stop(); + sendingFileDrawable.stop(); + } else if (type == 1) { + subtitleTextView.setLeftDrawable(recordStatusDrawable); + recordStatusDrawable.start(); + typingDotsDrawable.stop(); + sendingFileDrawable.stop(); + } else if (type == 2) { + subtitleTextView.setLeftDrawable(sendingFileDrawable); + sendingFileDrawable.start(); + typingDotsDrawable.stop(); + recordStatusDrawable.stop(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else { + subtitleTextView.setLeftDrawable(null); + typingDotsDrawable.stop(); + recordStatusDrawable.stop(); + sendingFileDrawable.stop(); + } + } + + public void updateSubtitle() { + TLRPC.User user = parentFragment.getCurrentUser(); + TLRPC.Chat chat = parentFragment.getCurrentChat(); + CharSequence printString = MessagesController.getInstance().printingStrings.get(parentFragment.getDialogId()); + if (printString != null) { + printString = TextUtils.replace(printString, new String[]{"..."}, new String[]{""}); + } + if (printString == null || printString.length() == 0 || ChatObject.isChannel(chat) && !chat.megagroup) { + setTypingAnimation(false); + if (chat != null) { + TLRPC.ChatFull info = parentFragment.getCurrentChatInfo(); + if (ChatObject.isChannel(chat)) { + if (!chat.broadcast && !chat.megagroup && !(chat instanceof TLRPC.TL_channelForbidden)) { + subtitleTextView.setText(LocaleController.getString("ShowDiscussion", R.string.ShowDiscussion)); + if (radioButton != null && radioButton.getVisibility() != VISIBLE) { + radioButton.setVisibility(View.VISIBLE); + } + } else { + if (info != null && info.participants_count != 0) { + if (chat.megagroup && info.participants_count <= 200) { + if (onlineCount > 1 && info.participants_count != 0) { + subtitleTextView.setText(String.format("%s, %s", LocaleController.formatPluralString("Members", info.participants_count), LocaleController.formatPluralString("Online", onlineCount))); + } else { + subtitleTextView.setText(LocaleController.formatPluralString("Members", info.participants_count)); + } + } else { + int result[] = new int[1]; + String shortNumber = LocaleController.formatShortNumber(info.participants_count, result); + String text = LocaleController.formatPluralString("Members", result[0]).replace(String.format("%d", result[0]), shortNumber); + subtitleTextView.setText(text); + } + } else { + if (chat.megagroup) { + subtitleTextView.setText(LocaleController.getString("Loading", R.string.Loading).toLowerCase()); + } else { + if ((chat.flags & TLRPC.CHAT_FLAG_IS_PUBLIC) != 0) { + subtitleTextView.setText(LocaleController.getString("ChannelPublic", R.string.ChannelPublic).toLowerCase()); + } else { + subtitleTextView.setText(LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate).toLowerCase()); + } + } + } + if (radioButton != null && radioButton.getVisibility() != GONE) { + radioButton.setVisibility(View.GONE); + } + } + } else { + if (ChatObject.isKickedFromChat(chat)) { + subtitleTextView.setText(LocaleController.getString("YouWereKicked", R.string.YouWereKicked)); + } else if (ChatObject.isLeftFromChat(chat)) { + subtitleTextView.setText(LocaleController.getString("YouLeft", R.string.YouLeft)); + } else { + int count = chat.participants_count; + if (info != null) { + count = info.participants.participants.size(); + } + if (onlineCount > 1 && count != 0) { + subtitleTextView.setText(String.format("%s, %s", LocaleController.formatPluralString("Members", count), LocaleController.formatPluralString("Online", onlineCount))); + } else { + subtitleTextView.setText(LocaleController.formatPluralString("Members", count)); + } + } + } + } else if (user != null) { + user = MessagesController.getInstance().getUser(user.id); + String newStatus; + if (user.id == 333000 || user.id == 777000) { + newStatus = LocaleController.getString("ServiceNotifications", R.string.ServiceNotifications); + } else if (user.bot) { + newStatus = LocaleController.getString("Bot", R.string.Bot); + } else { + newStatus = LocaleController.formatUserStatus(user); + } + subtitleTextView.setText(newStatus); + } + } else { + subtitleTextView.setText(printString); + setTypingAnimation(true); + } + } + + public void checkAndUpdateAvatar() { + TLRPC.FileLocation newPhoto = null; + TLRPC.User user = parentFragment.getCurrentUser(); + TLRPC.Chat chat = parentFragment.getCurrentChat(); + if (user != null) { + if (user.photo != null) { + newPhoto = user.photo.photo_small; + } + avatarDrawable.setInfo(user); + } else if (chat != null) { + if (chat.photo != null) { + newPhoto = chat.photo.photo_small; + } + avatarDrawable.setInfo(chat); + } + int radius = AndroidUtilities.dp(AndroidUtilities.getIntDef("chatHeaderAvatarRadius", 32)); + if (avatarImageView != null) { + avatarImageView.setImage(newPhoto, "50_50", avatarDrawable); + avatarImageView.setRoundRadius(radius); + } + //Chat header photo + if(avatarDrawable != null)avatarDrawable.setRadius(radius); + } + + public void updateOnlineCount() { + onlineCount = 0; + TLRPC.ChatFull info = parentFragment.getCurrentChatInfo(); + if (info == null) { + return; + } + int currentTime = ConnectionsManager.getInstance().getCurrentTime(); + if (info instanceof TLRPC.TL_chatFull || info instanceof TLRPC.TL_channelFull && info.participants_count <= 200 && info.participants != null) { + for (int a = 0; a < info.participants.participants.size(); a++) { + TLRPC.ChatParticipant participant = info.participants.participants.get(a); + TLRPC.User user = MessagesController.getInstance().getUser(participant.user_id); + if (user != null && user.status != null && (user.status.expires > currentTime || user.id == UserConfig.getClientUserId()) && user.status.expires > 10000) { + onlineCount++; + } + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxSquare.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxSquare.java new file mode 100644 index 00000000..eea7e161 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CheckBoxSquare.java @@ -0,0 +1,183 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.RectF; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; + +public class CheckBoxSquare extends View { + + private static Paint eraser; + private static Paint checkPaint; + private static Paint backgroundPaint; + private static RectF rectF; + + private Bitmap drawBitmap; + private Canvas drawCanvas; + + private float progress; + private ObjectAnimatorProxy checkAnimator; + + private boolean attachedToWindow; + private boolean isChecked; + private boolean isDisabled; + + private int color = 0xff43a0df; + + private final static float progressBounceDiff = 0.2f; + + public CheckBoxSquare(Context context) { + super(context); + if (checkPaint == null) { + checkPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + checkPaint.setColor(0xffffffff); + checkPaint.setStyle(Paint.Style.STROKE); + checkPaint.setStrokeWidth(AndroidUtilities.dp(2)); + eraser = new Paint(Paint.ANTI_ALIAS_FLAG); + eraser.setColor(0); + eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + backgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + rectF = new RectF(); + } + + drawBitmap = Bitmap.createBitmap(AndroidUtilities.dp(18), AndroidUtilities.dp(18), Bitmap.Config.ARGB_4444); + drawCanvas = new Canvas(drawBitmap); + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + if (visibility == VISIBLE && drawBitmap == null) { + + } + } + + public void setProgress(float value) { + if (progress == value) { + return; + } + progress = value; + invalidate(); + } + + public float getProgress() { + return progress; + } + + public void setColor(int value) { + color = value; + } + + private void cancelCheckAnimator() { + if (checkAnimator != null) { + checkAnimator.cancel(); + } + } + + private void animateToCheckedState(boolean newCheckedState) { + checkAnimator = ObjectAnimatorProxy.ofFloatProxy(this, "progress", newCheckedState ? 1 : 0); + checkAnimator.setDuration(300); + checkAnimator.start(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + attachedToWindow = true; + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + attachedToWindow = false; + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + } + + public void setChecked(boolean checked, boolean animated) { + if (checked == isChecked) { + return; + } + isChecked = checked; + if (attachedToWindow && animated) { + animateToCheckedState(checked); + } else { + cancelCheckAnimator(); + setProgress(checked ? 1.0f : 0.0f); + } + } + + public void setDisabled(boolean disabled) { + isDisabled = disabled; + invalidate(); + } + + public boolean isChecked() { + return isChecked; + } + + @Override + protected void onDraw(Canvas canvas) { + if (getVisibility() != VISIBLE) { + return; + } + + float checkProgress; + float bounceProgress; + if (progress <= 0.5f) { + bounceProgress = checkProgress = progress / 0.5f; + int rD = (int) ((Color.red(color) - 0x73) * checkProgress); + int gD = (int) ((Color.green(color) - 0x73) * checkProgress); + int bD = (int) ((Color.blue(color) - 0x73) * checkProgress); + int c = Color.rgb(0x73 + rD, 0x73 + gD, 0x73 + bD); + backgroundPaint.setColor(c); + } else { + bounceProgress = 2.0f - progress / 0.5f; + checkProgress = 1.0f; + backgroundPaint.setColor(color); + } + if (isDisabled) { + backgroundPaint.setColor(0xffb0b0b0); + } + float bounce = AndroidUtilities.dp(1) * bounceProgress; + rectF.set(bounce, bounce, AndroidUtilities.dp(18) - bounce, AndroidUtilities.dp(18) - bounce); + + drawBitmap.eraseColor(0); + drawCanvas.drawRoundRect(rectF, AndroidUtilities.dp(2), AndroidUtilities.dp(2), backgroundPaint); + + if (checkProgress != 1) { + float rad = Math.min(AndroidUtilities.dp(7), AndroidUtilities.dp(7) * checkProgress + bounce); + rectF.set(AndroidUtilities.dp(2) + rad, AndroidUtilities.dp(2) + rad, AndroidUtilities.dp(16) - rad, AndroidUtilities.dp(16) - rad); + drawCanvas.drawRect(rectF, eraser); + } + + if (progress > 0.5f) { + int endX = (int) (AndroidUtilities.dp(7.5f) - AndroidUtilities.dp(5) * (1.0f - bounceProgress)); + int endY = (int) (AndroidUtilities.dpf2(13.5f) - AndroidUtilities.dp(5) * (1.0f - bounceProgress)); + drawCanvas.drawLine(AndroidUtilities.dp(7.5f), (int) AndroidUtilities.dpf2(13.5f), endX, endY, checkPaint); + endX = (int) (AndroidUtilities.dpf2(6.5f) + AndroidUtilities.dp(9) * (1.0f - bounceProgress)); + endY = (int) (AndroidUtilities.dpf2(13.5f) - AndroidUtilities.dp(9) * (1.0f - bounceProgress)); + drawCanvas.drawLine((int) AndroidUtilities.dpf2(6.5f), (int) AndroidUtilities.dpf2(13.5f), endX, endY, checkPaint); + } + canvas.drawBitmap(drawBitmap, 0, 0, null); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ChipSpan.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChipSpan.java new file mode 100644 index 00000000..6ef95a40 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ChipSpan.java @@ -0,0 +1,41 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.graphics.Paint; +import android.graphics.drawable.Drawable; +import android.text.style.ImageSpan; + +import org.telegram.messenger.AndroidUtilities; + +public class ChipSpan extends ImageSpan { + + public int uid; + + public ChipSpan(Drawable d, int verticalAlignment) { + super(d, verticalAlignment); + } + + @Override + public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { + if (fm == null) { + fm = new Paint.FontMetricsInt(); + } + + int sz = super.getSize(paint, text, start, end, fm); + int offset = AndroidUtilities.dp(6); + int w = (fm.bottom - fm.top) / 2; + fm.top = -w - offset; + fm.bottom = w - offset; + fm.ascent = -w - offset; + fm.leading = 0; + fm.descent = w - offset; + return sz; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ClippingImageView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ClippingImageView.java index 615777ef..64790946 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ClippingImageView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ClippingImageView.java @@ -51,6 +51,9 @@ public class ClippingImageView extends View { matrix = new Matrix(); drawRect = new RectF(); bitmapRect = new RectF(); + roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + roundRect = new RectF(); + shaderMatrix = new Matrix(); } public void setAnimationValues(float[][] values) { @@ -109,10 +112,32 @@ public class ClippingImageView extends View { canvas.save(); if (needRadius) { - roundRect.set(0, 0, getWidth(), getHeight()); shaderMatrix.reset(); - shaderMatrix.setRectToRect(bitmapRect, roundRect, Matrix.ScaleToFit.FILL); + roundRect.set(0, 0, getWidth(), getHeight()); + + int bitmapW; + int bitmapH; + if (orientation % 360 == 90 || orientation % 360 == 270) { + bitmapW = bmp.getHeight(); + bitmapH = bmp.getWidth(); + } else { + bitmapW = bmp.getWidth(); + bitmapH = bmp.getHeight(); + } + float scaleW = getWidth() != 0 ? bitmapW / getWidth() : 1.0f; + float scaleH = getHeight() != 0 ? bitmapH / getHeight() : 1.0f; + float scale = Math.min(scaleW, scaleH); + if (Math.abs(scaleW - scaleH) > 0.00001f) { + int w = (int) Math.floor(getWidth() * scale); + int h = (int) Math.floor(getHeight() * scale); + bitmapRect.set((bitmapW - w) / 2, (bitmapH - h) / 2, w, h); + shaderMatrix.setRectToRect(bitmapRect, roundRect, Matrix.ScaleToFit.START); + } else { + bitmapRect.set(0, 0, bmp.getWidth(), bmp.getHeight()); + shaderMatrix.setRectToRect(bitmapRect, roundRect, Matrix.ScaleToFit.FILL); + } bitmapShader.setLocalMatrix(shaderMatrix); + canvas.clipRect(clipLeft / scaleY, clipTop / scaleY, getWidth() - clipRight / scaleY, getHeight() - clipBottom / scaleY); canvas.drawRoundRect(roundRect, radius, radius, roundPaint); } else { if (orientation == 90 || orientation == 270) { @@ -182,10 +207,7 @@ public class ClippingImageView extends View { if (bitmap != null) { bitmapRect.set(0, 0, bitmap.getWidth(), bitmap.getHeight()); if (needRadius) { - roundRect = new RectF(); - shaderMatrix = new Matrix(); bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); - roundPaint = new Paint(Paint.ANTI_ALIAS_FLAG); roundPaint.setShader(bitmapShader); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CloseProgressDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CloseProgressDrawable.java new file mode 100644 index 00000000..7ddd3586 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CloseProgressDrawable.java @@ -0,0 +1,91 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; +import android.view.animation.DecelerateInterpolator; + +import org.telegram.messenger.AndroidUtilities; + +public class CloseProgressDrawable extends Drawable { + + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private long lastFrameTime; + private int currentAnimationTime; + private DecelerateInterpolator interpolator = new DecelerateInterpolator(); + private int currentSegment; + + public CloseProgressDrawable() { + super(); + paint.setColor(0xff757575); + paint.setStrokeWidth(AndroidUtilities.dp(2)); + paint.setStrokeCap(Paint.Cap.ROUND); + } + + @Override + public void draw(Canvas canvas) { + long newTime = System.currentTimeMillis(); + if (lastFrameTime != 0) { + long dt = (newTime - lastFrameTime); + currentAnimationTime += dt; + if (currentAnimationTime > 200) { + currentAnimationTime = 0; + currentSegment++; + if (currentSegment == 4) { + currentSegment -= 4; + } + } + } + + canvas.save(); + canvas.translate(getIntrinsicWidth() / 2, getIntrinsicHeight() / 2); + canvas.rotate(45); + paint.setAlpha(255 - (currentSegment % 4) * 40); + canvas.drawLine(-AndroidUtilities.dp(8), 0, 0, 0, paint); + paint.setAlpha(255 - ((currentSegment + 1) % 4) * 40); + canvas.drawLine(0, -AndroidUtilities.dp(8), 0, 0, paint); + paint.setAlpha(255 - ((currentSegment + 2) % 4) * 40); + canvas.drawLine(0, 0, AndroidUtilities.dp(8), 0, paint); + paint.setAlpha(255 - ((currentSegment + 3) % 4) * 40); + canvas.drawLine(0, 0, 0, AndroidUtilities.dp(8), paint); + canvas.restore(); + + lastFrameTime = newTime; + invalidateSelf(); + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(ColorFilter cf) { + + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + + @Override + public int getIntrinsicWidth() { + return AndroidUtilities.dp(24); + } + + @Override + public int getIntrinsicHeight() { + return AndroidUtilities.dp(24); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/CloseProgressDrawable2.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/CloseProgressDrawable2.java new file mode 100644 index 00000000..7d93f125 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/CloseProgressDrawable2.java @@ -0,0 +1,143 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; +import android.view.animation.DecelerateInterpolator; + +import org.telegram.messenger.AndroidUtilities; + +public class CloseProgressDrawable2 extends Drawable { + + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private long lastFrameTime; + private DecelerateInterpolator interpolator = new DecelerateInterpolator(); + private RectF rect = new RectF(); + private float angle; + private boolean animating; + + public CloseProgressDrawable2() { + super(); + paint.setColor(0xffadadad); + paint.setStrokeWidth(AndroidUtilities.dp(2)); + paint.setStrokeCap(Paint.Cap.ROUND); + paint.setStyle(Paint.Style.STROKE); + } + + public void startAnimation() { + animating = true; + lastFrameTime = System.currentTimeMillis(); + invalidateSelf(); + } + + public void stopAnimation() { + animating = false; + } + + @Override + public void draw(Canvas canvas) { + long newTime = System.currentTimeMillis(); + boolean invalidate = false; + if (lastFrameTime != 0) { + long dt = (newTime - lastFrameTime); + if (animating || angle != 0) { + angle += 360 * dt / 500.0f; + if (!animating && angle >= 720) { + angle = 0; + } else { + angle -= (int) (angle / 720) * 720; + } + invalidateSelf(); + } + } + + canvas.save(); + canvas.translate(getIntrinsicWidth() / 2, getIntrinsicHeight() / 2); + canvas.rotate(-45); + float progress1 = 1.0f; + float progress2 = 1.0f; + float progress3 = 1.0f; + float progress4 = 0.0f; + if (angle >= 0 && angle < 90) { + progress1 = (1.0f - angle / 90.0f); + } else if (angle >= 90 && angle < 180) { + progress1 = 0.0f; + progress2 = 1.0f - (angle - 90) / 90.0f; + } else if (angle >= 180 && angle < 270) { + progress1 = progress2 = 0; + progress3 = 1.0f - (angle - 180) / 90.0f; + } else if (angle >= 270 && angle < 360) { + progress1 = progress2 = progress3 = 0; + progress4 = (angle - 270) / 90.0f; + } else if (angle >= 360 && angle < 450) { + progress1 = progress2 = progress3 = 0; + progress4 = 1.0f - (angle - 360) / 90.0f; + } else if (angle >= 450 && angle < 540) { + progress2 = progress3 = 0; + progress1 = (angle - 450) / 90.0f; + } else if (angle >= 540 && angle < 630) { + progress3 = 0; + progress2 = (angle - 540) / 90.0f; + } else if (angle >= 630 && angle < 720) { + progress3 = (angle - 630) / 90.0f; + } + + if (progress1 != 0) { + canvas.drawLine(0, 0, 0, AndroidUtilities.dp(8) * progress1, paint); + } + if (progress2 != 0) { + canvas.drawLine(-AndroidUtilities.dp(8) * progress2, 0, 0, 0, paint); + } + if (progress3 != 0) { + canvas.drawLine(0, -AndroidUtilities.dp(8) * progress3, 0, 0, paint); + } + if (progress4 != 1) { + canvas.drawLine(AndroidUtilities.dp(8) * progress4, 0, AndroidUtilities.dp(8), 0, paint); + } + + canvas.restore(); + + int cx = getBounds().centerX(); + int cy = getBounds().centerY(); + rect.set(cx - AndroidUtilities.dp(8), cy - AndroidUtilities.dp(8), cx + AndroidUtilities.dp(8), cy + AndroidUtilities.dp(8)); + canvas.drawArc(rect, (angle < 360 ? 0 : angle - 360) - 45, (angle < 360 ? angle : 720 - angle), false, paint); + + lastFrameTime = newTime; + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(ColorFilter cf) { + + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + + @Override + public int getIntrinsicWidth() { + return AndroidUtilities.dp(24); + } + + @Override + public int getIntrinsicHeight() { + return AndroidUtilities.dp(24); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ContextProgressView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ContextProgressView.java new file mode 100644 index 00000000..156e8356 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ContextProgressView.java @@ -0,0 +1,69 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.RectF; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; + +public class ContextProgressView extends View { + + private Paint innerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint outerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private RectF cicleRect = new RectF(); + private int radOffset = 0; + private long lastUpdateTime; + + public ContextProgressView(Context context) { + super(context); + innerPaint.setColor(0xffbfdff6); + innerPaint.setStyle(Paint.Style.STROKE); + innerPaint.setStrokeWidth(AndroidUtilities.dp(2)); + outerPaint.setColor(0xff2b96e2); + outerPaint.setStyle(Paint.Style.STROKE); + outerPaint.setStrokeWidth(AndroidUtilities.dp(2)); + outerPaint.setStrokeCap(Paint.Cap.ROUND); + } + + @Override + public void setVisibility(int visibility) { + super.setVisibility(visibility); + lastUpdateTime = System.currentTimeMillis(); + invalidate(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + lastUpdateTime = System.currentTimeMillis(); + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + if (getVisibility() != VISIBLE) { + return; + } + long newTime = System.currentTimeMillis(); + long dt = newTime - lastUpdateTime; + lastUpdateTime = newTime; + radOffset += 360 * dt / 1000.0f; + + int x = getMeasuredWidth() / 2 - AndroidUtilities.dp(9); + int y = getMeasuredHeight() / 2 - AndroidUtilities.dp(9); + cicleRect.set(x, y, x + AndroidUtilities.dp(18), y + AndroidUtilities.dp(18)); + canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, AndroidUtilities.dp(9), innerPaint); + canvas.drawArc(cicleRect, -90 + radOffset, 90, false, outerPaint); + invalidate(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java index bd42e85d..da536cdd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmojiView.java @@ -53,6 +53,7 @@ import org.telegram.messenger.MediaController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; import org.telegram.messenger.query.StickersQuery; import org.telegram.messenger.support.widget.RecyclerView; import org.telegram.tgnet.ConnectionsManager; @@ -80,6 +81,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific void onGifSelected(TLRPC.Document gif); void onGifTab(boolean opened); void onStickersTab(boolean opened); + void onClearEmojiRecent(); } private static final Field superListenerField; @@ -163,6 +165,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific pickerViewPopup.showAsDropDown(view, xOffset, -view.getMeasuredHeight() - popupHeight + (view.getMeasuredHeight() - emojiSize) / 2 - yOffset); view.getParent().requestDisallowInterceptTouchEvent(true); return true; + } else if (pager.getCurrentItem() == 0) { + listener.onClearEmojiRecent(); } return false; } @@ -491,7 +495,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private HashMap emojiUseHistory = new HashMap<>(); private static HashMap emojiColor = new HashMap<>(); private ArrayList recentEmoji = new ArrayList<>(); - private HashMap stickersUseHistory = new HashMap<>(); + private ArrayList newRecentStickers = new ArrayList<>(); private ArrayList recentStickers = new ArrayList<>(); private ArrayList stickerSets = new ArrayList<>(); private ArrayList recentImages; @@ -521,8 +525,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private FlowLayoutManager flowLayoutManager; private GifsAdapter gifsAdapter; private AdapterView.OnItemClickListener stickersOnItemClickListener; - private Runnable openStickerPreviewRunnable; - private StickerEmojiCell currentStickerPreviewCell; + private EmojiColorPickerView pickerView; private EmojiPopupWindow pickerViewPopup; private int popupWidth; @@ -534,9 +537,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private int gifTabBum = -2; private boolean switchToGifTab; - private int startX; - private int startY; - private int oldWidth; private int lastNotifyWidth; @@ -580,45 +580,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific stickersGridView = new GridView(context) { @Override public boolean onInterceptTouchEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - int x = (int) event.getX(); - int y = (int) event.getY(); - int count = stickersGridView.getChildCount(); - for (int a = 0; a < count; a++) { - View view = stickersGridView.getChildAt(a); - int top = view.getTop(); - int bottom = view.getBottom(); - int left = view.getLeft(); - int right = view.getRight(); - if (top > y || bottom < y || left > x || right < x) { - continue; - } - if (!(view instanceof StickerEmojiCell) || !((StickerEmojiCell) view).showingBitmap()) { - return super.onInterceptTouchEvent(event); - } - startX = x; - startY = y; - currentStickerPreviewCell = (StickerEmojiCell) view; - openStickerPreviewRunnable = new Runnable() { - @Override - public void run() { - if (openStickerPreviewRunnable == null) { - return; - } - stickersGridView.setOnItemClickListener(null); - stickersGridView.requestDisallowInterceptTouchEvent(true); - openStickerPreviewRunnable = null; - StickerPreviewViewer.getInstance().setParentActivity((Activity) getContext()); - StickerPreviewViewer.getInstance().setKeyboardHeight(EmojiView.this.getMeasuredHeight()); - StickerPreviewViewer.getInstance().open(currentStickerPreviewCell.getSticker()); - currentStickerPreviewCell.setScaled(true); - } - }; - AndroidUtilities.runOnUIThread(openStickerPreviewRunnable, 200); - return true; - } - } - return false; + boolean result = StickerPreviewViewer.getInstance().onInterceptTouchEvent(event, stickersGridView, EmojiView.this.getMeasuredHeight()); + return super.onInterceptTouchEvent(event) || result; } @Override @@ -641,67 +604,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific stickersGridView.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { - if (openStickerPreviewRunnable != null || StickerPreviewViewer.getInstance().isVisible()) { - if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_POINTER_UP) { - AndroidUtilities.runOnUIThread(new Runnable() { - @Override - public void run() { - stickersGridView.setOnItemClickListener(stickersOnItemClickListener); - } - }, 150); - if (openStickerPreviewRunnable != null) { - AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); - openStickerPreviewRunnable = null; - } else if (StickerPreviewViewer.getInstance().isVisible()) { - StickerPreviewViewer.getInstance().close(); - if (currentStickerPreviewCell != null) { - currentStickerPreviewCell.setScaled(false); - currentStickerPreviewCell = null; - } - } - } else if (event.getAction() != MotionEvent.ACTION_DOWN) { - if (StickerPreviewViewer.getInstance().isVisible()) { - if (event.getAction() == MotionEvent.ACTION_MOVE) { - int x = (int) event.getX(); - int y = (int) event.getY(); - int count = stickersGridView.getChildCount(); - for (int a = 0; a < count; a++) { - View view = stickersGridView.getChildAt(a); - int top = view.getTop(); - int bottom = view.getBottom(); - int left = view.getLeft(); - int right = view.getRight(); - if (top > y || bottom < y || left > x || right < x) { - continue; - } - if (!(view instanceof StickerEmojiCell) || view == currentStickerPreviewCell) { - break; - } - if (currentStickerPreviewCell != null) { - currentStickerPreviewCell.setScaled(false); - } - currentStickerPreviewCell = (StickerEmojiCell) view; - StickerPreviewViewer.getInstance().setKeyboardHeight(EmojiView.this.getMeasuredHeight()); - StickerPreviewViewer.getInstance().open(currentStickerPreviewCell.getSticker()); - currentStickerPreviewCell.setScaled(true); - return true; - } - } - return true; - } else if (openStickerPreviewRunnable != null) { - if (event.getAction() == MotionEvent.ACTION_MOVE) { - if (Math.hypot(startX - event.getX(), startY - event.getY()) > AndroidUtilities.dp(10)) { - AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); - openStickerPreviewRunnable = null; - } - } else { - AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); - openStickerPreviewRunnable = null; - } - } - } - } - return false; + return StickerPreviewViewer.getInstance().onTouch(event, stickersGridView, EmojiView.this.getMeasuredHeight(), stickersOnItemClickListener); } }); stickersOnItemClickListener = new AdapterView.OnItemClickListener() { @@ -710,35 +613,23 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (!(view instanceof StickerEmojiCell)) { return; } - if (openStickerPreviewRunnable != null) { - AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); - openStickerPreviewRunnable = null; - } - if (currentStickerPreviewCell != null) { - currentStickerPreviewCell.setScaled(false); - currentStickerPreviewCell = null; - } + StickerPreviewViewer.getInstance().reset(); StickerEmojiCell cell = (StickerEmojiCell) view; if (cell.isDisabled()) { return; } cell.disable(); TLRPC.Document document = cell.getSticker(); - Integer count = stickersUseHistory.get(document.id); - if (count == null) { - count = 0; - } - if (count == 0 && stickersUseHistory.size() > 19) { - for (int a = recentStickers.size() - 1; a >= 0; a--) { - TLRPC.Document sticker = recentStickers.get(a); - stickersUseHistory.remove(sticker.id); - recentStickers.remove(a); - if (stickersUseHistory.size() <= 19) { - break; - } + int index = newRecentStickers.indexOf(document.id); + if (index == -1) { + newRecentStickers.add(0, document.id); + if (newRecentStickers.size() > 20) { + newRecentStickers.remove(newRecentStickers.size() - 1); } + } else if (index != 0) { + newRecentStickers.remove(index); + newRecentStickers.add(0, document.id); } - stickersUseHistory.put(document.id, ++count); saveRecentStickers(); if (listener != null) { @@ -746,7 +637,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } }; - stickersGridView.setOnItemClickListener(stickersOnItemClickListener); + stickersGridView.setOnItemClickListener(stickersOnItemClickListener); AndroidUtilities.setListViewEdgeEffectColor(stickersGridView, 0xfff5f6f7); stickersWrap = new FrameLayout(context); @@ -771,12 +662,6 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific break; } } - if (size.width == 0) { - size.width = 100; - } - if (size.height == 0) { - size.height = 100; - } return size; } }); @@ -791,7 +676,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific return; } TLRPC.Document document = recentImages.get(position).document; - listener.onStickerSelected(document); + listener.onGifSelected(document); } }); gifsGridView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { @@ -829,7 +714,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); - builder.show(); + builder.show().setCanceledOnTouchOutside(true); return true; } }); @@ -1128,6 +1013,15 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific loadRecents(); } + public void clearRecentEmoji() { + SharedPreferences preferences = getContext().getSharedPreferences("emoji", Activity.MODE_PRIVATE); + preferences.edit().putBoolean("filled_default", true).commit(); + emojiUseHistory.clear(); + recentEmoji.clear(); + saveRecentEmoji(); + adapters.get(0).notifyDataSetChanged(); + } + private void showGifTab() { gifsGridView.setVisibility(VISIBLE); stickersGridView.setVisibility(GONE); @@ -1259,16 +1153,13 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific private void saveRecentStickers() { SharedPreferences.Editor editor = getContext().getSharedPreferences("emoji", Activity.MODE_PRIVATE).edit(); StringBuilder stringBuilder = new StringBuilder(); - for (HashMap.Entry entry : stickersUseHistory.entrySet()) { + for (int a = 0; a < newRecentStickers.size(); a++) { if (stringBuilder.length() != 0) { stringBuilder.append(","); } - stringBuilder.append(entry.getKey()); - stringBuilder.append("="); - stringBuilder.append(entry.getValue()); + stringBuilder.append(newRecentStickers.get(a)); } - editor.putString("stickers", stringBuilder.toString()); - + editor.putString("stickers2", stringBuilder.toString()); editor.commit(); } @@ -1316,43 +1207,28 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific return; } recentStickers.clear(); - HashMap hashMap = new HashMap<>(); - for (HashMap.Entry entry : stickersUseHistory.entrySet()) { - TLRPC.Document sticker = StickersQuery.getStickerById(entry.getKey()); + for (int a = 0; a < newRecentStickers.size(); a++) { + TLRPC.Document sticker = StickersQuery.getStickerById(newRecentStickers.get(a)); if (sticker != null) { recentStickers.add(sticker); - hashMap.put(sticker.id, entry.getValue()); } - } - if (stickersUseHistory.size() != hashMap.size()) { - stickersUseHistory = hashMap; - saveRecentStickers(); - } - Collections.sort(recentStickers, new Comparator() { - @Override - public int compare(TLRPC.Document lhs, TLRPC.Document rhs) { - Integer count1 = stickersUseHistory.get(lhs.id); - Integer count2 = stickersUseHistory.get(rhs.id); - if (count1 == null) { - count1 = 0; - } - if (count2 == null) { - count2 = 0; - } - if (count1 > count2) { - return -1; - } else if (count1 < count2) { - return 1; - } - return 0; } - }); while (recentStickers.size() > 20) { recentStickers.remove(recentStickers.size() - 1); } + if (newRecentStickers.size() != recentStickers.size()) { + newRecentStickers.clear(); + for (int a = 0; a < recentStickers.size(); a++) { + newRecentStickers.add(recentStickers.get(a).id); + } + saveRecentStickers(); + } } private void updateStickerTabs() { + if (scrollSlidingTabStrip == null) { + return; + } recentTabBum = -2; gifTabBum = -2; @@ -1448,7 +1324,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific String[] args = str.split(","); for (String arg : args) { String[] args2 = arg.split("="); - long value = Long.parseLong(args2[0]); + long value = Utilities.parseLong(args2[0]); String string = ""; for (int a = 0; a < 4; a++) { char ch = (char) value; @@ -1459,7 +1335,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } if (string.length() > 0) { - emojiUseHistory.put(string, Integer.parseInt(args2[1])); + emojiUseHistory.put(string, Utilities.parseInt(args2[1])); } } } @@ -1471,11 +1347,12 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific String[] args = str.split(","); for (String arg : args) { String[] args2 = arg.split("="); - emojiUseHistory.put(args2[0], Integer.parseInt(args2[1])); + emojiUseHistory.put(args2[0], Utilities.parseInt(args2[1])); } } } if (emojiUseHistory.isEmpty()) { + if (!preferences.getBoolean("filled_default", false)) { String[] newRecent = new String[]{ "\uD83D\uDE02", "\uD83D\uDE18", "\u2764", "\uD83D\uDE0D", "\uD83D\uDE0A", "\uD83D\uDE01", "\uD83D\uDC4D", "\u263A", "\uD83D\uDE14", "\uD83D\uDE04", "\uD83D\uDE2D", "\uD83D\uDC8B", @@ -1486,8 +1363,10 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific for (int i = 0; i < newRecent.length; i++) { emojiUseHistory.put(newRecent[i], newRecent.length - i); } + preferences.edit().putBoolean("filled_default", true).commit(); saveRecentEmoji(); } + } sortEmoji(); adapters.get(0).notifyDataSetChanged(); } catch (Exception e) { @@ -1498,7 +1377,8 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific str = preferences.getString("color", ""); if (str != null && str.length() > 0) { String[] args = str.split(","); - for (String arg : args) { + for (int a = 0; a < args.length; a++) { + String arg = args[a]; String[] args2 = arg.split("="); emojiColor.put(args2[0], args2[1]); } @@ -1509,13 +1389,50 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (showStickers) { try { - stickersUseHistory.clear(); + newRecentStickers.clear(); str = preferences.getString("stickers", ""); if (str != null && str.length() > 0) { String[] args = str.split(","); - for (String arg : args) { + final HashMap stickersUseHistory = new HashMap<>(); + for (int a = 0; a < args.length; a++) { + String arg = args[a]; String[] args2 = arg.split("="); - stickersUseHistory.put(Long.parseLong(args2[0]), Integer.parseInt(args2[1])); + Long key = Utilities.parseLong(args2[0]); + stickersUseHistory.put(key, Utilities.parseInt(args2[1])); + newRecentStickers.add(key); + } + Collections.sort(newRecentStickers, new Comparator() { + @Override + public int compare(Long lhs, Long rhs) { + Integer count1 = stickersUseHistory.get(lhs); + Integer count2 = stickersUseHistory.get(rhs); + if (count1 == null) { + count1 = 0; + } + if (count2 == null) { + count2 = 0; + } + if (count1 > count2) { + return -1; + } else if (count1 < count2) { + return 1; + } + return 0; + } + }); + preferences.edit().remove("stickers").commit(); + saveRecentStickers(); + } else { + str = preferences.getString("stickers2", ""); + String[] args = str.split(","); + for (int a = 0; a < args.length; a++) { + if (args[a].length() == 0) { + continue; + } + long id = Utilities.parseLong(args[a]); + if (id != 0) { + newRecentStickers.add(id); + } } } sortStickers(); @@ -1564,14 +1481,7 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (StickerPreviewViewer.getInstance().isVisible()) { StickerPreviewViewer.getInstance().close(); } - if (openStickerPreviewRunnable != null) { - AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); - openStickerPreviewRunnable = null; - } - if (currentStickerPreviewCell != null) { - currentStickerPreviewCell.setScaled(false); - currentStickerPreviewCell = null; - } + StickerPreviewViewer.getInstance().reset(); } public void setListener(Listener value) { @@ -1592,6 +1502,13 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific if (stickersGridAdapter != null) { NotificationCenter.getInstance().addObserver(this, NotificationCenter.stickersDidLoaded); NotificationCenter.getInstance().addObserver(this, NotificationCenter.recentImagesDidLoaded); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + updateStickerTabs(); + reloadStickersAdapter(); + } + }); } } @@ -1622,13 +1539,16 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific } } - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); + public void onDestroy() { if (stickersGridAdapter != null) { NotificationCenter.getInstance().removeObserver(this, NotificationCenter.stickersDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.recentImagesDidLoaded); } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); if (pickerViewPopup != null && pickerViewPopup.isShowing()) { pickerViewPopup.dismiss(); } @@ -1712,7 +1632,9 @@ public class EmojiView extends FrameLayout implements NotificationCenter.Notific int previousCount = recentImages != null ? recentImages.size() : 0; recentImages = (ArrayList) args[1]; loadingRecent = false; - gifsAdapter.notifyDataSetChanged(); + if (gifsAdapter != null) { + gifsAdapter.notifyDataSetChanged(); + } if (previousCount != recentImages.size()) { updateStickerTabs(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/EmptyTextProgressView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmptyTextProgressView.java new file mode 100644 index 00000000..3eb99cf9 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/EmptyTextProgressView.java @@ -0,0 +1,108 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.ProgressBar; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; + +public class EmptyTextProgressView extends FrameLayout { + + private TextView textView; + private ProgressBar progressBar; + private boolean inLayout; + private boolean showAtCenter; + + public EmptyTextProgressView(Context context) { + super(context); + + progressBar = new ProgressBar(context); + progressBar.setVisibility(INVISIBLE); + addView(progressBar, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + textView.setTextColor(0xff808080); + textView.setGravity(Gravity.CENTER); + textView.setVisibility(INVISIBLE); + textView.setPadding(AndroidUtilities.dp(20), 0, AndroidUtilities.dp(20), 0); + textView.setText(LocaleController.getString("NoResult", R.string.NoResult)); + addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); + + setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + } + + public void showProgress() { + textView.setVisibility(INVISIBLE); + progressBar.setVisibility(VISIBLE); + } + + public void showTextView() { + textView.setVisibility(VISIBLE); + progressBar.setVisibility(INVISIBLE); + } + + public void setText(String text) { + textView.setText(text); + } + + public void setTextSize(int size) { + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, size); + } + + public void setShowAtCenter(boolean value) { + showAtCenter = value; + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + inLayout = true; + int width = r - l; + int height = b - t; + int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = getChildAt(i); + + if (child.getVisibility() == GONE) { + continue; + } + + int x = (width - child.getMeasuredWidth()) / 2; + int y; + if (showAtCenter) { + y = (height / 2 - child.getMeasuredHeight()) / 2; + } else { + y = (height - child.getMeasuredHeight()) / 2; + } + child.layout(x, y, x + child.getMeasuredWidth(), y + child.getMeasuredHeight()); + } + inLayout = false; + } + + @Override + public void requestLayout() { + if (!inLayout) { + super.requestLayout(); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Favourite.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Favourite.java new file mode 100644 index 00000000..a719c9c0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Favourite.java @@ -0,0 +1,63 @@ +package org.telegram.ui.Components; + +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.FileLog; + +public class Favourite { + + long id; + long chat_id; + + public Favourite(){ + + } + + public Favourite(long id, long chat_id){ + this.id = id; + this.chat_id = chat_id; + } + + public Favourite(long chat_id){ + this.chat_id = chat_id; + } + + public long getChatID(){ + return this.chat_id; + } + + public long getID(){ + return this.id; + } + + public void setChatID(long chat_id){ + this.chat_id = chat_id; + } + + public void setID(long id){ + this.id = id; + } + + public static void addFavourite(Long id){ + Favourite favourite = new Favourite(id); + ApplicationLoader.databaseHandler.addFavourite(favourite); + } + + public static void deleteFavourite(Long id){ + ApplicationLoader.databaseHandler.deleteFavourite(id); + } + + public static boolean isFavourite(Long id){ + try{ + Favourite favourite = ApplicationLoader.databaseHandler.getFavouriteByChatId(id); + if(favourite == null){ + return false; + }else{ + return true; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + return false; + } + } +} + diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FlowLayoutManager.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FlowLayoutManager.java new file mode 100644 index 00000000..4d5d6c41 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FlowLayoutManager.java @@ -0,0 +1,529 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.util.SparseArray; +import android.view.View; +import android.view.ViewGroup; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.support.widget.RecyclerView; + +import java.util.ArrayList; + +public class FlowLayoutManager extends RecyclerView.LayoutManager { + + private SparseArray framesPos; + private SparseArray itemsToRow; + private SparseArray rowToItems; + private ArrayList> rows; + private Size actualSize = new Size(); + private int lastCalculatedWidth; + private int lastCalculatedHeight; + private float minimumInteritemSpacing = AndroidUtilities.dp(2); + private float preferredRowSize; + + private static final int DIRECTION_NONE = -1; + private static final int DIRECTION_UP = 0; + private static final int DIRECTION_DOWN = 1; + + private int firstVisiblePosition; + private boolean forceClearOffsets; + + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + if (getItemCount() == 0) { + detachAndScrapAttachedViews(recycler); + return; + } + + int childTop; + if (framesPos == null || framesPos.size() != getItemCount() || lastCalculatedHeight != getHeight() || lastCalculatedWidth != getWidth()) { + prepareLayout(); + firstVisiblePosition = 0; + childTop = 0; + } else if (getChildCount() == 0) { + firstVisiblePosition = 0; + childTop = 0; + } else if (getVisibleChildCount(0) >= state.getItemCount()) { + firstVisiblePosition = 0; + childTop = 0; + } else { + final View topChild = getChildAt(0); + if (forceClearOffsets) { + childTop = 0; + forceClearOffsets = false; + } else { + childTop = getDecoratedTop(topChild); + } + + Rect lastFrame = framesPos.get(getIndexOfRow(rows.size() - 1)); + if (getHeight() > lastFrame.y + lastFrame.height) { + firstVisiblePosition = 0; + childTop = 0; + } + + int maxFirstRow = rows.size() - (getVisibleRowCount(0) - 1); + boolean isOutOfRowBounds = getFirstVisibleRow() > maxFirstRow; + if (isOutOfRowBounds) { + int firstRow; + if (isOutOfRowBounds) { + firstRow = maxFirstRow; + } else { + firstRow = getFirstVisibleRow(); + } + firstVisiblePosition = getIndexOfRow(firstRow); + + childTop = (int) framesPos.get(getIndexOfRow(rows.size() - 1)).y; + + if (getFirstVisibleRow() == 0) { + childTop = Math.min(childTop, 0); + } + } + } + detachAndScrapAttachedViews(recycler); + fillGrid(DIRECTION_NONE, childTop, 0, recycler, state); + } + + @Override + public void onAdapterChanged(RecyclerView.Adapter oldAdapter, RecyclerView.Adapter newAdapter) { + removeAllViews(); + } + + private void fillGrid(int direction, int emptyTop, int directionRowCount, RecyclerView.Recycler recycler, RecyclerView.State state) { + if (firstVisiblePosition < 0) { + firstVisiblePosition = 0; + } + if (firstVisiblePosition >= getItemCount()) { + firstVisiblePosition = (getItemCount() - 1); + } + + SparseArray viewCache = null; + int topOffset = emptyTop; + int childCount = getChildCount(); + if (childCount != 0) { + final View topView = getChildAt(0); + topOffset = getDecoratedTop(topView); + switch (direction) { + case DIRECTION_UP: { + //FileLog.d("tmessages", "up topOffset from " + topOffset); + for (int a = 0; a < directionRowCount; a++) { + topOffset -= preferredRowSize; + } + //FileLog.d("tmessages", "up topOffset to " + topOffset); + /*framesPos.get(firstVisiblePosition - 1).height*/ //TODO support various row height + break; + } + case DIRECTION_DOWN: { + //FileLog.d("tmessages", "down topOffset from " + topOffset); + for (int a = 0; a < directionRowCount; a++) { + topOffset += preferredRowSize; + } + //FileLog.d("tmessages", "down topOffset to " + topOffset); + /*framesPos.get(firstVisiblePosition).height*/ //TODO support various row height + break; + } + } + + viewCache = new SparseArray<>(getChildCount()); + for (int i = 0; i < childCount; i++) { + viewCache.put(firstVisiblePosition + i, getChildAt(i)); + } + for (int i = 0; i < childCount; i++) { + detachView(viewCache.valueAt(i)); + } + } + + int firstRow = getRowOfIndex(firstVisiblePosition); + switch (direction) { + case DIRECTION_UP: + //FileLog.d("tmessages", "up first position from " + firstVisiblePosition + " row from " + getRowOfIndex(firstVisiblePosition)); + for (int a = 0; a < directionRowCount; a++) { + firstVisiblePosition -= getCountForRow(firstRow - (a + 1)); + } + //FileLog.d("tmessages", "up first position to " + firstVisiblePosition + " row to " + getRowOfIndex(firstVisiblePosition)); + break; + case DIRECTION_DOWN: + //FileLog.d("tmessages", "down first position from " + firstVisiblePosition + " row from " + getRowOfIndex(firstVisiblePosition)); + for (int a = 0; a < directionRowCount; a++) { + firstVisiblePosition += getCountForRow(firstRow + a); + } + //FileLog.d("tmessages", "down first position to " + firstVisiblePosition + " row to " + getRowOfIndex(firstVisiblePosition)); + break; + } + + int lastHeight = 0; + int lastRow = -1; + //FileLog.d("tmessages", "fill from " + firstVisiblePosition + " to " + getVisibleChildCount(topOffset)); + for (int i = firstVisiblePosition, v = firstVisiblePosition + getVisibleChildCount(topOffset); i < v; i++) { + if (i < 0 || i >= state.getItemCount()) { + continue; + } + int newRow = getRowOfIndex(i); + if (lastRow != -1 && newRow != lastRow) { + topOffset = lastHeight; + } + + Rect rect = framesPos.get(i); + View view = viewCache != null ? viewCache.get(i) : null; + if (view == null) { + view = recycler.getViewForPosition(i); + addView(view); + RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams(); + layoutParams.width = (int) rect.width; + layoutParams.height = (int) rect.height; + view.setLayoutParams(layoutParams); + measureChildWithMargins(view, 0, 0); + layoutDecorated(view, (int) rect.x, topOffset, (int) (rect.x + rect.width), (int) (topOffset + rect.height)); + } else { + attachView(view); + viewCache.remove(i); + } + lastHeight = (int) (topOffset + rect.height); + lastRow = newRow; + } + if (viewCache != null) { + for (int i = 0; i < viewCache.size(); i++) { + final View removingView = viewCache.valueAt(i); + recycler.recycleView(removingView); + } + } + } + + @Override + public void scrollToPosition(int position) { + if (position >= getItemCount()) { + return; + } + forceClearOffsets = true; + firstVisiblePosition = position; + requestLayout(); + } + + @Override + public boolean canScrollVertically() { + return true; + } + + @Override + public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { + if (getChildCount() == 0) { + return 0; + } + + final View topView = getChildAt(0); + final View bottomView = getChildAt(getChildCount() - 1); + + int viewSpan = getDecoratedBottom(bottomView) - getDecoratedTop(topView); + if (viewSpan < getHeight()) { + return 0; + } + + int delta; + int rowsCount; + int firstVisibleRow = getFirstVisibleRow(); + int lastVisibleRow = firstVisibleRow + getVisibleRowCount(0) - 1; + boolean topBoundReached = firstVisibleRow == 0; + boolean bottomBoundReached = lastVisibleRow >= rows.size() - 1; + //FileLog.d("tmessages", "first = " + firstVisibleRow + " last = " + lastVisibleRow + " rows = " + rows.size() + " height = " + getHeight() + " preferredRowSize = " + preferredRowSize); + if (dy > 0) { + int bottom = getDecoratedBottom(bottomView); + int amount = getHeight() - bottom + dy; + rowsCount = (int) Math.ceil(Math.abs(amount) / preferredRowSize); + //FileLog.d("tmessages", "scroll bottom = " + dy + " decorated bottom = " + bottom + " amount = " + amount + " rowsCount = " + rowsCount); + if (amount < 0 || lastVisibleRow + rowsCount <= rows.size() - 1) { + delta = -dy; + //FileLog.d("tmessages", "delta1 = " + delta); + } else { + rowsCount = rows.size() - 1 - lastVisibleRow; + delta = getHeight() - bottom - (int) (rowsCount * preferredRowSize); + //FileLog.d("tmessages", "delta2 = " + delta + " rowsCount = " + rowsCount); + } + } else { + int top = getDecoratedTop(topView); + int amount = Math.abs(dy) + top; + rowsCount = (int) Math.ceil(Math.abs(amount) / preferredRowSize); + //FileLog.d("tmessages", "scroll top = " + dy + " decorated top = " + top + " amount = " + amount + " rowsCount = " + rowsCount); + if (amount < 0 || firstVisibleRow - rowsCount >= 0) { + delta = -dy; + //FileLog.d("tmessages", "delta1 = " + delta); + } else { + rowsCount = firstVisibleRow; + delta = -top + (int) (firstVisibleRow * preferredRowSize); + //FileLog.d("tmessages", "delta2 = " + delta + " rowsCount = " + rowsCount); + } + } + + offsetChildrenVertical(delta); + + if (dy > 0) { + if (getDecoratedBottom(topView) < 0 && !bottomBoundReached) { + fillGrid(DIRECTION_DOWN, 0, rowsCount, recycler, state); + } else if (!bottomBoundReached) { + fillGrid(DIRECTION_NONE, 0, 0, recycler, state); + } + } else { + if (getDecoratedTop(topView) > 0 && !topBoundReached) { + fillGrid(DIRECTION_UP, 0, rowsCount, recycler, state); + } else if (!topBoundReached) { + fillGrid(DIRECTION_NONE, 0, 0, recycler, state); + } + } + + return -delta; + } + + @Override + public RecyclerView.LayoutParams generateDefaultLayoutParams() { + return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + } + + private int getCountForRow(int row) { + if (row < 0 || row >= rows.size()) { + return 0; + } + return rows.get(row).size(); + } + + private int getIndexOfRow(int row) { + if (rows == null) { + return 0; + } + Integer value = rowToItems.get(row); + return value == null ? 0 : value; + } + + public int getRowCount() { + return rows != null ? rows.size() : 0; + } + + public int getRowOfIndex(int index) { + if (rows == null) { + return 0; + } + Integer value = itemsToRow.get(index); + return value == null ? 0 : value; + } + + private int getFirstVisibleRow() { + return getRowOfIndex(firstVisiblePosition); + } + + private int getVisibleChildCount(int topOffset) { + int startRow = getFirstVisibleRow(); + int count = 0; + for (int a = startRow, e = startRow + getVisibleRowCount(topOffset); a < e; a++) { + if (a < rows.size()) { + count += rows.get(a).size(); + } else { + break; + } + } + return count; + } + + private int getVisibleRowCount(int topOffset) { + int height = getHeight(); + View topChild = getChildAt(0); + int top = topChild != null ? getDecoratedTop(topChild) : topOffset; + int count = 0; + int startRow = getFirstVisibleRow(); + for (int a = startRow; a < rows.size(); a++) { + if (top > height) { + break; + } + top += framesPos.get(getIndexOfRow(a)).height; + count++; + } + return count; + } + + private void prepareLayout() { + if (framesPos == null) { + framesPos = new SparseArray<>(); + itemsToRow = new SparseArray<>(); + rowToItems = new SparseArray<>(); + } else { + framesPos.clear(); + itemsToRow.clear(); + rowToItems.clear(); + } + preferredRowSize = getHeight() / 2.0f; + float viewPortAvailableSize = getWidth(); + if (BuildVars.DEBUG_VERSION) { + FileLog.d("tmessages", "preferredRowSize = " + preferredRowSize + " width = " + viewPortAvailableSize); + } + + float totalItemSize = 0; + int[] weights = new int[getItemCount()]; + for (int a = 0; a < getItemCount(); a++) { + Size size = sizeForItem(a); + totalItemSize += (size.width / size.height) * preferredRowSize; + weights[a] = Math.round(size.width / size.height * 100); + } + + int numberOfRows = Math.max(Math.round(totalItemSize / viewPortAvailableSize), 1); + + rows = getLinearPartitionForSequence(weights, numberOfRows); + + int i = 0, a; + Point offset = new Point(0, 0); + float previousItemSize = 0; + for (a = 0; a < rows.size(); a++) { + ArrayList row = rows.get(a); + + float summedRatios = 0; + for (int j = i, n = i + row.size(); j < n; j++) { + Size preferredSize = sizeForItem(j); + summedRatios += preferredSize.width / preferredSize.height; + } + + float rowSize = viewPortAvailableSize - ((row.size() - 1) * minimumInteritemSpacing); + + if (rows.size() == 1 && a == rows.size() - 1) { + if (row.size() < 2) { + rowSize = (float) Math.floor(viewPortAvailableSize / 3.0f) - ((row.size() - 1) * minimumInteritemSpacing); + } else if (row.size() < 3) { + rowSize = (float) Math.floor(viewPortAvailableSize * 2.0f / 3.0f) - ((row.size() - 1) * minimumInteritemSpacing); + } + } + + for (int j = i, n = i + row.size(); j < n; j++) { + Size preferredSize = sizeForItem(j); + + actualSize.width = Math.round(rowSize / summedRatios * (preferredSize.width / preferredSize.height)); + actualSize.height = preferredRowSize;//Math.round(rowSize / summedRatios); + if (a == row.size() - 1) { + actualSize.height = preferredRowSize; + } + Rect rect = new Rect(offset.x, offset.y, actualSize.width, actualSize.height); + if (rect.x + rect.width >= viewPortAvailableSize - 2.0f) { + rect.width = Math.max(1.0f, viewPortAvailableSize - rect.x); + } + framesPos.put(j, rect); + itemsToRow.put(j, a); + if (j == i) { + rowToItems.put(a, j); + } + offset.x += actualSize.width + minimumInteritemSpacing; + previousItemSize = actualSize.height; + } + + if (row.size() > 0) { + offset.x = 0; + offset.y += previousItemSize; + } + + i += row.size(); + } + } + + private int[] getLinearPartitionTable(int[] sequence, int numPartitions) { + int n = sequence.length; + int i, j, x; + + int tmpTable[] = new int[n * numPartitions]; + int solution[] = new int[(n - 1) * (numPartitions - 1)]; + + for (i = 0; i < n; i++) { + tmpTable[i * numPartitions] = sequence[i] + (i != 0 ? tmpTable[(i - 1) * numPartitions] : 0); + } + + for (j = 0; j < numPartitions; j++) { + tmpTable[j] = sequence[0]; + } + + for (i = 1; i < n; i++) { + for (j = 1; j < numPartitions; j++) { + int currentMin = 0; + int minX = Integer.MAX_VALUE; + + for (x = 0; x < i; x++) { + int cost = Math.max(tmpTable[x * numPartitions + (j - 1)], tmpTable[i * numPartitions] - tmpTable[x * numPartitions]); + if (x == 0 || cost < currentMin) { + currentMin = cost; + minX = x; + } + } + tmpTable[i * numPartitions + j] = currentMin; + solution[(i - 1) * (numPartitions - 1) + (j - 1)] = minX; + } + } + + return solution; + } + + private ArrayList> getLinearPartitionForSequence(int[] sequence, int numberOfPartitions) { + int n = sequence.length; + int k = numberOfPartitions; + + if (k <= 0) { + return new ArrayList<>(); + } + + if (k >= n || n == 1) { + ArrayList> partition = new ArrayList<>(sequence.length); + for (int i = 0; i < sequence.length; i++) { + ArrayList arrayList = new ArrayList<>(1); + arrayList.add(sequence[i]); + partition.add(arrayList); + } + return partition; + } + + int[] solution = getLinearPartitionTable(sequence, numberOfPartitions); + int solutionRowSize = numberOfPartitions - 1; + + k = k - 2; + n = n - 1; + ArrayList> answer = new ArrayList<>(); + + while (k >= 0) { + if (n < 1) { + answer.add(0, new ArrayList()); + } else { + ArrayList currentAnswer = new ArrayList<>(); + for (int i = solution[(n - 1) * solutionRowSize + k] + 1, range = n + 1; i < range; i++) { + currentAnswer.add(sequence[i]); + } + answer.add(0, currentAnswer); + n = solution[(n - 1) * solutionRowSize + k]; + } + k = k - 1; + } + + ArrayList currentAnswer = new ArrayList<>(); + for (int i = 0, range = n + 1; i < range; i++) { + currentAnswer.add(sequence[i]); + } + answer.add(0, currentAnswer); + return answer; + } + + private Size sizeForItem(int i) { + Size size = getSizeForItem(i); + if (size.width == 0) { + size.width = 100; + } + if (size.height == 0) { + size.height = 100; + } + float aspect = size.width / size.height; + if (aspect > 4.0f || aspect < 0.2f) { + size.height = size.width = Math.max(size.width, size.height); + } + return size; + } + + protected Size getSizeForItem(int i) { + return new Size(100, 100); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/FrameLayoutFixed.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/FrameLayoutFixed.java index 930ad191..f558d9d2 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/FrameLayoutFixed.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/FrameLayoutFixed.java @@ -14,6 +14,7 @@ import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; +import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.FileLog; import java.util.ArrayList; @@ -155,6 +156,7 @@ public class FrameLayoutFixed extends FrameLayout { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } catch (Exception e2) { FileLog.e("tmessages", e2); + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.makeMeasureSpec(AndroidUtilities.dp(10), MeasureSpec.EXACTLY)); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Glow.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Glow.java new file mode 100644 index 00000000..165f8580 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Glow.java @@ -0,0 +1,316 @@ +package org.telegram.ui.Components; + +import android.annotation.TargetApi; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.support.annotation.ColorInt; +import android.support.annotation.IntDef; +import android.support.v4.widget.EdgeEffectCompat; +import android.support.v4.widget.NestedScrollView; +import android.widget.AbsListView; +import android.widget.EdgeEffect; +import android.widget.ScrollView; + +import org.telegram.messenger.BuildConfig; +import org.telegram.messenger.support.widget.RecyclerView; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + + +@TargetApi(21) +public class Glow { + protected Glow() {} + + private static final Class CLASS_SCROLL_VIEW = ScrollView.class; + private static final Field SCROLL_VIEW_FIELD_EDGE_GLOW_TOP; + private static final Field SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM; + + private static final Class CLASS_NESTED_SCROLL_VIEW = NestedScrollView.class; + private static final Field NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_TOP; + private static final Field NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM; + + private static final Class CLASS_RECYCLER_VIEW = RecyclerView.class; + private static final Field RECYCLER_VIEW_FIELD_EDGE_GLOW_TOP; + private static final Field RECYCLER_VIEW_FIELD_EDGE_GLOW_LEFT; + private static final Field RECYCLER_VIEW_FIELD_EDGE_GLOW_RIGHT; + private static final Field RECYCLER_VIEW_FIELD_EDGE_GLOW_BOTTOM; + + private static final Class CLASS_LIST_VIEW = AbsListView.class; + private static final Field LIST_VIEW_FIELD_EDGE_GLOW_TOP; + private static final Field LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM; + + private static final Field EDGE_GLOW_FIELD_EDGE; + private static final Field EDGE_GLOW_FIELD_GLOW; + + private static final Field EDGE_EFFECT_COMPAT_FIELD_EDGE_EFFECT; + + static { + Field edgeGlowTop = null, edgeGlowBottom = null, edgeGlowLeft = null, edgeGlowRight = null; + + for (Field f : CLASS_RECYCLER_VIEW.getDeclaredFields()) { + switch (f.getName()) { + case "mTopGlow": + f.setAccessible(true); + edgeGlowTop = f; + break; + case "mBottomGlow": + f.setAccessible(true); + edgeGlowBottom = f; + break; + case "mLeftGlow": + f.setAccessible(true); + edgeGlowLeft = f; + break; + case "mRightGlow": + f.setAccessible(true); + edgeGlowRight = f; + break; + } + } + + RECYCLER_VIEW_FIELD_EDGE_GLOW_TOP = edgeGlowTop; + RECYCLER_VIEW_FIELD_EDGE_GLOW_BOTTOM = edgeGlowBottom; + RECYCLER_VIEW_FIELD_EDGE_GLOW_LEFT = edgeGlowLeft; + RECYCLER_VIEW_FIELD_EDGE_GLOW_RIGHT = edgeGlowRight; + + for (Field f : CLASS_NESTED_SCROLL_VIEW.getDeclaredFields()) { + switch (f.getName()) { + case "mEdgeGlowTop": + f.setAccessible(true); + edgeGlowTop = f; + break; + case "mEdgeGlowBottom": + f.setAccessible(true); + edgeGlowBottom = f; + break; + } + } + + NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_TOP = edgeGlowTop; + NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM = edgeGlowBottom; + + for (Field f : CLASS_SCROLL_VIEW.getDeclaredFields()) { + switch (f.getName()) { + case "mEdgeGlowTop": + f.setAccessible(true); + edgeGlowTop = f; + break; + case "mEdgeGlowBottom": + f.setAccessible(true); + edgeGlowBottom = f; + break; + } + } + + SCROLL_VIEW_FIELD_EDGE_GLOW_TOP = edgeGlowTop; + SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM = edgeGlowBottom; + + for (Field f : CLASS_LIST_VIEW.getDeclaredFields()) { + switch (f.getName()) { + case "mEdgeGlowTop": + f.setAccessible(true); + edgeGlowTop = f; + break; + case "mEdgeGlowBottom": + f.setAccessible(true); + edgeGlowBottom = f; + break; + } + } + + LIST_VIEW_FIELD_EDGE_GLOW_TOP = edgeGlowTop; + LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM = edgeGlowBottom; + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + Field edge = null, glow = null; + + Class cls = null; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + try { + cls = Class.forName("android.widget.EdgeGlow"); + } catch (ClassNotFoundException e) { + if (BuildConfig.DEBUG) e.printStackTrace(); + } + } else { + cls = EdgeEffect.class; + + } + + if (cls != null) { + for (Field f : cls.getDeclaredFields()) { + switch (f.getName()) { + case "mEdge": + f.setAccessible(true); + edge = f; + break; + case "mGlow": + f.setAccessible(true); + glow = f; + break; + } + } + } + + EDGE_GLOW_FIELD_EDGE = edge; + EDGE_GLOW_FIELD_GLOW = glow; + } else { + EDGE_GLOW_FIELD_EDGE = null; + EDGE_GLOW_FIELD_GLOW = null; + } + + Field efc = null; + try { + efc = EdgeEffectCompat.class.getDeclaredField("mEdgeEffect"); + } catch (NoSuchFieldException e) { + if (BuildConfig.DEBUG) e.printStackTrace(); + } + EDGE_EFFECT_COMPAT_FIELD_EDGE_EFFECT = efc; + } + + @IntDef({ALWAYS, PRE_HONEYCOMB, PRE_KITKAT, PRE_LOLLIPOP}) + @Retention(RetentionPolicy.SOURCE) + public @interface EdgeGlowColorApi {} + + public static final int ALWAYS = 0; + /** Replace yellow glow in vanilla, blue glow on Samsung. */ + public static final int PRE_HONEYCOMB = Build.VERSION_CODES.HONEYCOMB; + /** Replace Holo blue glow. */ + public static final int PRE_KITKAT = Build.VERSION_CODES.KITKAT; + /** Replace Holo grey glow. */ + public static final int PRE_LOLLIPOP = Build.VERSION_CODES.LOLLIPOP; + + public static void setEdgeGlowColor(AbsListView listView, @ColorInt int color, @EdgeGlowColorApi int when) { + if (Build.VERSION.SDK_INT < when || when == ALWAYS) { + setEdgeGlowColor(listView, color); + } + } + + public static void setEdgeGlowColor(AbsListView listView, @ColorInt int color) { + try { + Object ee; + ee = LIST_VIEW_FIELD_EDGE_GLOW_TOP.get(listView); + setEdgeGlowColor(ee, color); + ee = LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM.get(listView); + setEdgeGlowColor(ee, color); + } catch (Exception ex) { + if (BuildConfig.DEBUG) ex.printStackTrace(); + } + } + + public static void setEdgeGlowColor(ScrollView scrollView, @ColorInt int color, @EdgeGlowColorApi int when) { + if (Build.VERSION.SDK_INT < when || when == ALWAYS) { + setEdgeGlowColor(scrollView, color); + } + } + + public static void setEdgeGlowColor(ScrollView scrollView, @ColorInt int color) { + try { + Object ee; + ee = SCROLL_VIEW_FIELD_EDGE_GLOW_TOP.get(scrollView); + setEdgeGlowColor(ee, color); + ee = SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM.get(scrollView); + setEdgeGlowColor(ee, color); + } catch (Exception ex) { + if (BuildConfig.DEBUG) ex.printStackTrace(); + } + } + + public static void setEdgeGlowColor(NestedScrollView scrollView, @ColorInt int color, @EdgeGlowColorApi int when) { + if (Build.VERSION.SDK_INT < when || when == ALWAYS) { + setEdgeGlowColor(scrollView, color); + } + } + + public static void setEdgeGlowColor(NestedScrollView scrollView, @ColorInt int color) { + try { + Object ee; + ee = NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_TOP.get(scrollView); + setEdgeGlowColor(ee, color); + ee = NESTED_SCROLL_VIEW_FIELD_EDGE_GLOW_BOTTOM.get(scrollView); + setEdgeGlowColor(ee, color); + } catch (Exception ex) { + if (BuildConfig.DEBUG) ex.printStackTrace(); + } + } + + public static void setEdgeGlowColor(RecyclerView scrollView, @ColorInt int color, @EdgeGlowColorApi int when) { + if (Build.VERSION.SDK_INT < when || when == ALWAYS) { + setEdgeGlowColor(scrollView, color); + } + } + + public static void setEdgeGlowColorOld(RecyclerView scrollView, @ColorInt int color) { + try { + Object ee; + ee = RECYCLER_VIEW_FIELD_EDGE_GLOW_TOP.get(scrollView); + setEdgeGlowColor(ee, color); + ee = RECYCLER_VIEW_FIELD_EDGE_GLOW_BOTTOM.get(scrollView); + setEdgeGlowColor(ee, color); + ee = RECYCLER_VIEW_FIELD_EDGE_GLOW_LEFT.get(scrollView); + setEdgeGlowColor(ee, color); + ee = RECYCLER_VIEW_FIELD_EDGE_GLOW_RIGHT.get(scrollView); + setEdgeGlowColor(ee, color); + } catch (Exception ex) { + if (BuildConfig.DEBUG) ex.printStackTrace(); + } + } + + public static void setEdgeGlowColor(final RecyclerView recyclerView, final int color) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + try { + final Class clazz = RecyclerView.class; + for (final String name : new String[] {"ensureTopGlow", "ensureBottomGlow"}) { + Method method = clazz.getDeclaredMethod(name); + method.setAccessible(true); + method.invoke(recyclerView); + } + for (final String name : new String[] {"mTopGlow", "mBottomGlow"}) { + final Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + final Object edge = field.get(recyclerView); // android.support.v4.widget.EdgeEffectCompat + final Field fEdgeEffect = edge.getClass().getDeclaredField("mEdgeEffect"); + fEdgeEffect.setAccessible(true); + ((EdgeEffect) fEdgeEffect.get(edge)).setColor(color); + } + } catch (final Exception ignored) {} + } else{ + setEdgeGlowColorOld(recyclerView, color); + } + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + private static void setEdgeGlowColor(Object edgeEffect, @ColorInt int color) { + if (edgeEffect instanceof EdgeEffectCompat) { + // EdgeEffectCompat + try { + edgeEffect = EDGE_EFFECT_COMPAT_FIELD_EDGE_EFFECT.get(edgeEffect); + } catch (IllegalAccessException e) { + if (BuildConfig.DEBUG) e.printStackTrace(); + return; + } + } + + if (edgeEffect == null) return; + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + // EdgeGlow below Android 4 then old EdgeEffect + try { + final Drawable mEdge = (Drawable) EDGE_GLOW_FIELD_EDGE.get(edgeEffect); + final Drawable mGlow = (Drawable) EDGE_GLOW_FIELD_GLOW.get(edgeEffect); + mEdge.setColorFilter(color, PorterDuff.Mode.SRC_IN); + mGlow.setColorFilter(color, PorterDuff.Mode.SRC_IN); + mEdge.setCallback(null); // free up any references + mGlow.setCallback(null); // free up any references + } catch (Exception ex) { + if (BuildConfig.DEBUG) ex.printStackTrace(); + } + } else { + // EdgeEffect + ((EdgeEffect) edgeEffect).setColor(color); + } + } +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/HintEditText.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/HintEditText.java new file mode 100644 index 00000000..fc8d7154 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/HintEditText.java @@ -0,0 +1,73 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.widget.EditText; + +import org.telegram.messenger.AndroidUtilities; + +public class HintEditText extends EditText { + + private String hintText; + private float textOffset; + private float spaceSize; + private float numberSize; + private Paint paint = new Paint(); + private Rect rect = new Rect(); + + public HintEditText(Context context) { + super(context); + paint.setColor(0xff979797); + } + + public String getHintText() { + return hintText; + } + + public void setHintText(String value) { + hintText = value; + onTextChange(); + setText(getText()); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + onTextChange(); + } + + public void onTextChange() { + textOffset = (length() > 0 ? getPaint().measureText(getText(), 0, length()) : 0); + spaceSize = getPaint().measureText(" "); + numberSize = getPaint().measureText("1"); + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (hintText != null && length() < hintText.length()) { + int top = getMeasuredHeight() / 2; + float offsetX = textOffset; + for (int a = length(); a < hintText.length(); a++) { + if (hintText.charAt(a) == ' ') { + offsetX += spaceSize; + } else { + rect.set((int) offsetX + AndroidUtilities.dp(1), top, (int) (offsetX + numberSize) - AndroidUtilities.dp(1), top + AndroidUtilities.dp(2)); + canvas.drawRect(rect, paint); + offsetX += numberSize; + } + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/IdenticonDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/IdenticonDrawable.java index 0973d69a..5625ed37 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/IdenticonDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/IdenticonDrawable.java @@ -15,7 +15,6 @@ import android.graphics.drawable.Drawable; import org.telegram.messenger.AndroidUtilities; import org.telegram.tgnet.TLRPC; -import org.telegram.messenger.Utilities; public class IdenticonDrawable extends Drawable { @@ -35,9 +34,7 @@ public class IdenticonDrawable extends Drawable { public void setEncryptedChat(TLRPC.EncryptedChat encryptedChat) { data = encryptedChat.key_hash; if (data == null) { - byte[] sha1 = Utilities.computeSHA1(encryptedChat.auth_key); - encryptedChat.key_hash = data = new byte[16]; - System.arraycopy(sha1, 0, data, 0, data.length); + encryptedChat.key_hash = data = AndroidUtilities.calcAuthKeyHash(encryptedChat.auth_key); } invalidateSelf(); } @@ -48,17 +45,33 @@ public class IdenticonDrawable extends Drawable { return; } - int bitPointer = 0; - float rectSize = (float)Math.floor(Math.min(getBounds().width(), getBounds().height()) / 8.0f); - float xOffset = Math.max(0, (getBounds().width() - rectSize * 8) / 2); - float yOffset = Math.max(0, (getBounds().height() - rectSize * 8) / 2); - for (int iy = 0; iy < 8; iy++) { - for (int ix = 0; ix < 8; ix++) { - int byteValue = getBits(bitPointer); - bitPointer += 2; - int colorIndex = Math.abs(byteValue) % 4; - paint.setColor(colors[colorIndex]); - canvas.drawRect(xOffset + ix * rectSize, iy * rectSize + yOffset, xOffset + ix * rectSize + rectSize, iy * rectSize + rectSize + yOffset, paint); + if (data.length == 16) { + int bitPointer = 0; + float rectSize = (float) Math.floor(Math.min(getBounds().width(), getBounds().height()) / 8.0f); + float xOffset = Math.max(0, (getBounds().width() - rectSize * 8) / 2); + float yOffset = Math.max(0, (getBounds().height() - rectSize * 8) / 2); + for (int iy = 0; iy < 8; iy++) { + for (int ix = 0; ix < 8; ix++) { + int byteValue = getBits(bitPointer); + bitPointer += 2; + int colorIndex = Math.abs(byteValue) % 4; + paint.setColor(colors[colorIndex]); + canvas.drawRect(xOffset + ix * rectSize, iy * rectSize + yOffset, xOffset + ix * rectSize + rectSize, iy * rectSize + rectSize + yOffset, paint); + } + } + } else { + int bitPointer = 0; + float rectSize = (float) Math.floor(Math.min(getBounds().width(), getBounds().height()) / 12.0f); + float xOffset = Math.max(0, (getBounds().width() - rectSize * 12) / 2); + float yOffset = Math.max(0, (getBounds().height() - rectSize * 12) / 2); + for (int iy = 0; iy < 12; iy++) { + for (int ix = 0; ix < 12; ix++) { + int byteValue = getBits(bitPointer); + int colorIndex = Math.abs(byteValue) % 4; + paint.setColor(colors[colorIndex]); + canvas.drawRect(xOffset + ix * rectSize, iy * rectSize + yOffset, xOffset + ix * rectSize + rectSize, iy * rectSize + rectSize + yOffset, paint); + bitPointer += 2; + } } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LetterDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LetterDrawable.java new file mode 100644 index 00000000..91bd7ead --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LetterDrawable.java @@ -0,0 +1,109 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; + +public class LetterDrawable extends Drawable { + + public static Paint paint = new Paint(); + private static TextPaint namePaint; + + private StaticLayout textLayout; + private float textWidth; + private float textHeight; + private float textLeft; + private StringBuilder stringBuilder = new StringBuilder(5); + + public LetterDrawable() { + super(); + + if (namePaint == null) { + paint.setColor(0xfff0f0f0); + namePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + namePaint.setColor(0xffffffff); + namePaint.setTextSize(AndroidUtilities.dp(28)); + } + } + + public void setTitle(String title) { + stringBuilder.setLength(0); + if (title != null && title.length() > 0) { + stringBuilder.append(title.substring(0, 1)); + } + + if (stringBuilder.length() > 0) { + String text = stringBuilder.toString().toUpperCase(); + try { + textLayout = new StaticLayout(text, namePaint, AndroidUtilities.dp(100), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + if (textLayout.getLineCount() > 0) { + textLeft = textLayout.getLineLeft(0); + textWidth = textLayout.getLineWidth(0); + textHeight = textLayout.getLineBottom(0); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else { + textLayout = null; + } + } + + @Override + public void draw(Canvas canvas) { + Rect bounds = getBounds(); + if (bounds == null) { + return; + } + int size = bounds.width(); + canvas.save(); + canvas.drawRect(bounds.left, bounds.top, bounds.right, bounds.bottom, paint); + if (textLayout != null) { + canvas.translate(bounds.left + (size - textWidth) / 2 - textLeft, bounds.top + (size - textHeight) / 2); + textLayout.draw(canvas); + } + canvas.restore(); + } + + @Override + public void setAlpha(int alpha) { + + } + + @Override + public void setColorFilter(ColorFilter cf) { + + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSPARENT; + } + + @Override + public int getIntrinsicWidth() { + return 0; + } + + @Override + public int getIntrinsicHeight() { + return 0; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkPath.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkPath.java new file mode 100644 index 00000000..f7203005 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/LinkPath.java @@ -0,0 +1,51 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.graphics.Path; +import android.text.StaticLayout; + +public class LinkPath extends Path { + + private StaticLayout currentLayout; + private int currentLine; + private float lastTop = -1; + private float heightOffset; + + public void setCurrentLayout(StaticLayout layout, int start, float yOffset) { + currentLayout = layout; + currentLine = layout.getLineForOffset(start); + lastTop = -1; + heightOffset = yOffset; + } + + @Override + public void addRect(float left, float top, float right, float bottom, Direction dir) { + top += heightOffset; + bottom += heightOffset; + if (lastTop == -1) { + lastTop = top; + } else if (lastTop != top) { + lastTop = top; + currentLine++; + } + float lineRight = currentLayout.getLineRight(currentLine); + float lineLeft = currentLayout.getLineLeft(currentLine); + if (left >= lineRight) { + return; + } + if (right > lineRight) { + right = lineRight; + } + if (left < lineLeft) { + left = lineLeft; + } + super.addRect(left, top, right, bottom, dir); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberTextView.java new file mode 100644 index 00000000..dbc1f0f5 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/NumberTextView.java @@ -0,0 +1,167 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.AnimationCompat.AnimatorListenerAdapterProxy; +import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; + +import java.util.ArrayList; +import java.util.Locale; + +public class NumberTextView extends View { + + private ArrayList letters = new ArrayList<>(); + private ArrayList oldLetters = new ArrayList<>(); + private TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + private ObjectAnimatorProxy animator; + private float progress = 0.0f; + private int currentNumber = 1; + + public NumberTextView(Context context) { + super(context); + } + + public void setProgress(float value) { + if (progress == value) { + return; + } + progress = value; + invalidate(); + } + + public float getProgress() { + return progress; + } + + public void setNumber(int number, boolean animated) { + if (currentNumber == number && animated) { + return; + } + if (animator != null) { + animator.cancel(); + animator = null; + } + oldLetters.clear(); + oldLetters.addAll(letters); + letters.clear(); + String oldText = String.format(Locale.US, "%d", currentNumber); + String text = String.format(Locale.US, "%d", number); + boolean forwardAnimation = number > currentNumber; + currentNumber = number; + progress = 0; + for (int a = 0; a < text.length(); a++) { + String ch = text.substring(a, a + 1); + String oldCh = !oldLetters.isEmpty() && a < oldText.length() ? oldText.substring(a, a + 1) : null; + if (oldCh != null && oldCh.equals(ch)) { + letters.add(oldLetters.get(a)); + oldLetters.set(a, null); + } else { + StaticLayout layout = new StaticLayout(ch, textPaint, (int) Math.ceil(textPaint.measureText(ch)), Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); + letters.add(layout); + } + } + if (animated && !oldLetters.isEmpty()) { + animator = ObjectAnimatorProxy.ofFloatProxy(this, "progress", forwardAnimation ? -1 : 1, 0); + animator.setDuration(150); + animator.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + animator = null; + oldLetters.clear(); + } + }); + animator.start(); + } + invalidate(); + } + + public void setTextSize(int size) { + textPaint.setTextSize(AndroidUtilities.dp(size)); + oldLetters.clear(); + letters.clear(); + setNumber(currentNumber, false); + } + + public void setTextColor(int value) { + textPaint.setColor(value); + invalidate(); + } + + public void setTypeface(Typeface typeface) { + textPaint.setTypeface(typeface); + oldLetters.clear(); + letters.clear(); + setNumber(currentNumber, false); + } + + @Override + protected void onDraw(Canvas canvas) { + if (letters.isEmpty()) { + return; + } + float height = letters.get(0).getHeight(); + canvas.save(); + canvas.translate(getPaddingLeft(), (getMeasuredHeight() - height) / 2); + int count = Math.max(letters.size(), oldLetters.size()); + for (int a = 0; a < count; a++) { + canvas.save(); + StaticLayout old = a < oldLetters.size() ? oldLetters.get(a) : null; + StaticLayout layout = a < letters.size() ? letters.get(a) : null; + if (progress > 0) { + if (old != null) { + textPaint.setAlpha((int) (255 * progress)); + canvas.save(); + canvas.translate(0, (progress - 1.0f) * height); + old.draw(canvas); + canvas.restore(); + if (layout != null) { + textPaint.setAlpha((int) (255 * (1.0f - progress))); + canvas.translate(0, progress * height); + } + } else { + textPaint.setAlpha(255); + } + } else if (progress < 0) { + if (old != null) { + textPaint.setAlpha((int) (255 * -progress)); + canvas.save(); + canvas.translate(0, (1.0f + progress) * height); + old.draw(canvas); + canvas.restore(); + } + if (layout != null) { + if (a == count - 1 || old != null) { + textPaint.setAlpha((int) (255 * (1.0f + progress))); + canvas.translate(0, progress * height); + } else { + textPaint.setAlpha(255); + } + } + } else if (layout != null) { + textPaint.setAlpha(255); + } + if (layout != null) { + layout.draw(canvas); + } + canvas.restore(); + canvas.translate(layout != null ? layout.getLineWidth(0) : old.getLineWidth(0) + AndroidUtilities.dp(1), 0); + } + canvas.restore(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoCropView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoCropView.java index eb9b8ed3..be8516ef 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoCropView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoCropView.java @@ -24,6 +24,7 @@ public class PhotoCropView extends FrameLayout { public interface PhotoCropViewDelegate { void needMoveImageTo(float x, float y, float s, boolean animated); + Bitmap getBitmap(); } private boolean freeformCrop = true; @@ -38,11 +39,11 @@ public class PhotoCropView extends FrameLayout { private float oldX = 0, oldY = 0; private int bitmapWidth = 1, bitmapHeight = 1, bitmapX, bitmapY; private float rectX = -1, rectY = -1; - private Bitmap bitmapToEdit; private float bitmapGlobalScale = 1; private float bitmapGlobalX = 0; private float bitmapGlobalY = 0; private PhotoCropViewDelegate delegate; + private Bitmap bitmapToEdit; private RectF animationStartValues; private RectF animationEndValues; @@ -80,6 +81,132 @@ public class PhotoCropView extends FrameLayout { requestLayout(); } + public void setOrientation(int rotation) { + orientation = rotation; + rectX = -1; + rectY = -1; + rectSizeX = 600; + rectSizeY = 600; + delegate.needMoveImageTo(0, 0, 1, false); + requestLayout(); + + /*float bitmapScaledWidth = bitmapWidth * bitmapGlobalScale; + float bitmapScaledHeight = bitmapHeight * bitmapGlobalScale; + float bitmapStartX = (getWidth() - AndroidUtilities.dp(28) - bitmapScaledWidth) / 2 + bitmapGlobalX + AndroidUtilities.dp(14); + float bitmapStartY = (getHeight() - AndroidUtilities.dp(28) - bitmapScaledHeight) / 2 + bitmapGlobalY + AndroidUtilities.dp(14); + + float percSizeX = rectSizeX / bitmapScaledWidth; + float percSizeY = rectSizeY / bitmapScaledHeight; + float percX = (rectX - bitmapStartX) / bitmapScaledWidth + percSizeX; + float percY = (rectY - bitmapStartY) / bitmapScaledHeight; + + int width; + int height; + if (orientation % 360 == 90 || orientation % 360 == 270) { + width = bitmapToEdit.getHeight(); + height = bitmapToEdit.getWidth(); + } else { + width = bitmapToEdit.getWidth(); + height = bitmapToEdit.getHeight(); + } + + int x = (int) (percX * width); + int y = (int) (percY * height); + int sizeX = (int) (percSizeX * width); + int sizeY = (int) (percSizeY * height); + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + if (x + sizeX > width) { + sizeX = width - x; + } + if (y + sizeY > height) { + sizeY = height - y; + } + + double cx = (x + sizeX) - width / 2.0f; + double cy = y - height / 2.0f; + double newX = cx * Math.cos(-Math.PI / 2) - cy * Math.sin(-Math.PI / 2) + height / 2.0f; + double newY = cx * Math.sin(-Math.PI / 2) + cy * Math.cos(-Math.PI / 2) + width / 2.0f; + int temp = sizeX; + sizeY = sizeY; + sizeY = temp;*/ + + + + /*int temp = bitmapWidth; + orientation = rotation; + bitmapWidth = bitmapHeight; + bitmapHeight = temp; + bitmapScaledWidth = bitmapWidth * bitmapGlobalScale; + bitmapScaledHeight = bitmapHeight * bitmapGlobalScale; + + rectX = (float) (newX * bitmapScaledWidth); + rectY = (float) (newX * bitmapScaledHeight); + float temp2 = rectSizeX; + rectSizeX = rectSizeY; + rectSizeY = temp2; + + moveToFill(false); + invalidate();*/ + + /*float temp = rectX; + rectX = rectY; + rectY = temp; + temp = rectSizeX; + rectSizeX = rectSizeY; + rectSizeY = temp; + int temp2 = bitmapWidth;*/ + //requestLayout(); + + /* + bitmapWidth = bitmapHeight; + bitmapHeight = temp2;*/ + + /*float bitmapScaledWidth = bitmapWidth * bitmapGlobalScale; + float bitmapScaledHeight = bitmapHeight * bitmapGlobalScale; + float bitmapStartX = (getWidth() - AndroidUtilities.dp(28) - bitmapScaledWidth) / 2 + bitmapGlobalX + AndroidUtilities.dp(14); + float bitmapStartY = (getHeight() - AndroidUtilities.dp(28) - bitmapScaledHeight) / 2 + bitmapGlobalY + AndroidUtilities.dp(14); + + float percX = (rectX - bitmapStartX) / bitmapScaledWidth; + float percY = (rectY - bitmapStartY) / bitmapScaledHeight; + float percSizeX = rectSizeX / bitmapScaledWidth; + float percSizeY = rectSizeY / bitmapScaledHeight; + + rectX = percY + + int width; + int height; + if (orientation % 360 == 90 || orientation % 360 == 270) { + width = bitmapToEdit.getHeight(); + height = bitmapToEdit.getWidth(); + } else { + width = bitmapToEdit.getWidth(); + height = bitmapToEdit.getHeight(); + } + + int x = (int) (percX * width); + int y = (int) (percY * height); + int sizeX = (int) (percSizeX * width); + int sizeY = (int) (percSizeY * height); + if (x < 0) { + x = 0; + } + if (y < 0) { + y = 0; + } + if (x + sizeX > width) { + sizeX = width - x; + } + if (y + sizeY > height) { + sizeY = height - y; + }*/ + //moveToFill(false); + } + public boolean onTouch(MotionEvent motionEvent) { if (motionEvent == null) { draggingState = 0; @@ -346,6 +473,11 @@ public class PhotoCropView extends FrameLayout { } private Bitmap createBitmap(int x, int y, int w, int h) { + Bitmap newBimap = delegate.getBitmap(); + if (newBimap != null) { + bitmapToEdit = newBimap; + } + Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG); @@ -353,7 +485,7 @@ public class PhotoCropView extends FrameLayout { Matrix matrix = new Matrix(); matrix.setTranslate(-bitmapToEdit.getWidth() / 2, -bitmapToEdit.getHeight() / 2); matrix.postRotate(orientation); - if (orientation == 90 || orientation == 270) { + if (orientation % 360 == 90 || orientation % 360 == 270) { matrix.postTranslate(bitmapToEdit.getHeight() / 2 - x, bitmapToEdit.getWidth() / 2 - y); } else { matrix.postTranslate(bitmapToEdit.getWidth() / 2 - x, bitmapToEdit.getHeight() / 2 - y); @@ -369,6 +501,11 @@ public class PhotoCropView extends FrameLayout { } public Bitmap getBitmap() { + Bitmap newBimap = delegate.getBitmap(); + if (newBimap != null) { + bitmapToEdit = newBimap; + } + float bitmapScaledWidth = bitmapWidth * bitmapGlobalScale; float bitmapScaledHeight = bitmapHeight * bitmapGlobalScale; float bitmapStartX = (getWidth() - AndroidUtilities.dp(28) - bitmapScaledWidth) / 2 + bitmapGlobalX + AndroidUtilities.dp(14); @@ -381,7 +518,7 @@ public class PhotoCropView extends FrameLayout { int width; int height; - if (orientation == 90 || orientation == 270) { + if (orientation % 360 == 90 || orientation % 360 == 270) { width = bitmapToEdit.getHeight(); height = bitmapToEdit.getWidth(); } else { @@ -467,7 +604,7 @@ public class PhotoCropView extends FrameLayout { public void run() { if (animationRunnable == this) { animationRunnable = null; - animateToFill(); + moveToFill(true); } } }; @@ -502,7 +639,7 @@ public class PhotoCropView extends FrameLayout { } } - public void animateToFill() { + public void moveToFill(boolean animated) { float scaleToX = bitmapWidth / rectSizeX; float scaleToY = bitmapHeight / rectSizeY; float scaleTo = scaleToX > scaleToY ? scaleToY : scaleToX; @@ -521,7 +658,7 @@ public class PhotoCropView extends FrameLayout { float newBitmapGlobalX = newX + getWidth() / 2 * (scaleTo - 1) + (bitmapGlobalX - rectX) * scaleTo; float newBitmapGlobalY = newY + getHeight() / 2 * (scaleTo - 1) + (bitmapGlobalY - rectY) * scaleTo; - delegate.needMoveImageTo(newBitmapGlobalX, newBitmapGlobalY, bitmapGlobalScale * scaleTo, true); + delegate.needMoveImageTo(newBitmapGlobalX, newBitmapGlobalY, bitmapGlobalScale * scaleTo, animated); } public void setDelegate(PhotoCropViewDelegate delegate) { @@ -532,6 +669,11 @@ public class PhotoCropView extends FrameLayout { protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); + Bitmap newBimap = delegate.getBitmap(); + if (newBimap != null) { + bitmapToEdit = newBimap; + } + if (bitmapToEdit == null) { return; } @@ -541,7 +683,7 @@ public class PhotoCropView extends FrameLayout { float bitmapW; float bitmapH; - if (orientation == 90 || orientation == 270) { + if (orientation % 360 == 90 || orientation % 360 == 270) { bitmapW = bitmapToEdit.getHeight(); bitmapH = bitmapToEdit.getWidth(); } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterBlurControl.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterBlurControl.java index d7e3d11d..1c81798d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterBlurControl.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterBlurControl.java @@ -61,7 +61,7 @@ public class PhotoFilterBlurControl extends FrameLayout { private float pointerScale = 1; private boolean isMoving; private boolean isZooming; - private boolean checkForMoving; + private boolean checkForMoving = true; private boolean checkForZooming; private int type; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterCurvesControl.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterCurvesControl.java new file mode 100644 index 00000000..8946a24f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterCurvesControl.java @@ -0,0 +1,322 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.text.TextPaint; +import android.view.MotionEvent; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; + +import java.util.Locale; + +public class PhotoFilterCurvesControl extends View { + + public interface PhotoFilterCurvesControlDelegate { + void valueChanged(); + } + + private final static int CurvesSegmentNone = 0; + private final static int CurvesSegmentBlacks = 1; + private final static int CurvesSegmentShadows = 2; + private final static int CurvesSegmentMidtones = 3; + private final static int CurvesSegmentHighlights = 4; + private final static int CurvesSegmentWhites = 5; + + private final static int GestureStateBegan = 1; + private final static int GestureStateChanged = 2; + private final static int GestureStateEnded = 3; + private final static int GestureStateCancelled = 4; + private final static int GestureStateFailed = 5; + + private int activeSegment = CurvesSegmentNone; + + private boolean isMoving; + private boolean checkForMoving = true; + + private float lastX; + private float lastY; + + private Rect actualArea = new Rect(); + + private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint paintDash = new Paint(Paint.ANTI_ALIAS_FLAG); + private Paint paintCurve = new Paint(Paint.ANTI_ALIAS_FLAG); + private TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); + private Path path = new Path(); + + private PhotoFilterCurvesControlDelegate delegate; + + private PhotoFilterView.CurvesToolValue curveValue; + + public PhotoFilterCurvesControl(Context context, PhotoFilterView.CurvesToolValue value) { + super(context); + setWillNotDraw(false); + + curveValue = value; + + paint.setColor(0x99ffffff); + paint.setStrokeWidth(AndroidUtilities.dp(1)); + paint.setStyle(Paint.Style.STROKE); + + paintDash.setColor(0x99ffffff); + paintDash.setStrokeWidth(AndroidUtilities.dp(2)); + paintDash.setStyle(Paint.Style.STROKE); + + paintCurve.setColor(0xffffffff); + paintCurve.setStrokeWidth(AndroidUtilities.dp(2)); + paintCurve.setStyle(Paint.Style.STROKE); + + textPaint.setColor(0xffbfbfbf); + textPaint.setTextSize(AndroidUtilities.dp(13)); + } + + public void setDelegate(PhotoFilterCurvesControlDelegate photoFilterCurvesControlDelegate) { + delegate = photoFilterCurvesControlDelegate; + } + + public void setActualArea(float x, float y, float width, float height) { + actualArea.x = x; + actualArea.y = y; + actualArea.width = width; + actualArea.height = height; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + int action = event.getActionMasked(); + + switch (action) { + case MotionEvent.ACTION_POINTER_DOWN: + case MotionEvent.ACTION_DOWN: { + if (event.getPointerCount() == 1) { + if (checkForMoving && !isMoving) { + float locationX = event.getX(); + float locationY = event.getY(); + lastX = locationX; + lastY = locationY; + if (locationX >= actualArea.x && locationX <= actualArea.x + actualArea.width && locationY >= actualArea.y && locationY <= actualArea.y + actualArea.height) { + isMoving = true; + } + checkForMoving = false; + if (isMoving) { + handlePan(GestureStateBegan, event); + } + } + } else { + if (isMoving) { + handlePan(GestureStateEnded, event); + checkForMoving = true; + isMoving = false; + } + } + break; + } + + case MotionEvent.ACTION_POINTER_UP: + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: { + if (isMoving) { + handlePan(GestureStateEnded, event); + isMoving = false; + } + checkForMoving = true; + break; + } + + case MotionEvent.ACTION_MOVE: { + if (isMoving) { + handlePan(GestureStateChanged, event); + } + } + } + return true; + } + + private void handlePan(int state, MotionEvent event) { + float locationX = event.getX(); + float locationY = event.getY(); + + switch (state) { + case GestureStateBegan: { + selectSegmentWithPoint(locationX); + break; + } + + case GestureStateChanged: { + float delta = Math.min(2, (lastY - locationY) / 8.0f); + + PhotoFilterView.CurvesValue curveValue = null; + switch (this.curveValue.activeType) { + case PhotoFilterView.CurvesToolValue.CurvesTypeLuminance: + curveValue = this.curveValue.luminanceCurve; + break; + + case PhotoFilterView.CurvesToolValue.CurvesTypeRed: + curveValue = this.curveValue.redCurve; + break; + + case PhotoFilterView.CurvesToolValue.CurvesTypeGreen: + curveValue = this.curveValue.greenCurve; + break; + + case PhotoFilterView.CurvesToolValue.CurvesTypeBlue: + curveValue = this.curveValue.blueCurve; + break; + + default: + break; + } + + switch (activeSegment) { + case CurvesSegmentBlacks: + curveValue.blacksLevel = Math.max(0, Math.min(100, curveValue.blacksLevel + delta)); + break; + + case CurvesSegmentShadows: + curveValue.shadowsLevel = Math.max(0, Math.min(100, curveValue.shadowsLevel + delta)); + break; + + case CurvesSegmentMidtones: + curveValue.midtonesLevel = Math.max(0, Math.min(100, curveValue.midtonesLevel + delta)); + break; + + case CurvesSegmentHighlights: + curveValue.highlightsLevel = Math.max(0, Math.min(100, curveValue.highlightsLevel + delta)); + break; + + case CurvesSegmentWhites: + curveValue.whitesLevel = Math.max(0, Math.min(100, curveValue.whitesLevel + delta)); + break; + + default: + break; + } + + invalidate(); + + if (delegate != null) { + delegate.valueChanged(); + } + + lastX = locationX; + lastY = locationY; + } + break; + + case GestureStateEnded: + case GestureStateCancelled: + case GestureStateFailed: { + unselectSegments(); + } + break; + + default: + break; + } + } + + private void selectSegmentWithPoint(float pointx) { + if (activeSegment != CurvesSegmentNone) { + return; + } + float segmentWidth = actualArea.width / 5.0f; + pointx -= actualArea.x; + activeSegment = (int) Math.floor((pointx / segmentWidth) + 1); + } + + private void unselectSegments() { + if (activeSegment == CurvesSegmentNone) { + return; + } + activeSegment = CurvesSegmentNone; + } + + @SuppressLint("DrawAllocation") + @Override + protected void onDraw(Canvas canvas) { + float segmentWidth = actualArea.width / 5.0f; + + for (int i = 0; i < 4; i++) { + canvas.drawLine(actualArea.x + segmentWidth + i * segmentWidth, actualArea.y, actualArea.x + segmentWidth + i * segmentWidth, actualArea.y + actualArea.height, paint); + } + + canvas.drawLine(actualArea.x, actualArea.y + actualArea.height, actualArea.x + actualArea.width, actualArea.y, paintDash); + + PhotoFilterView.CurvesValue curvesValue = null; + switch (curveValue.activeType) { + case PhotoFilterView.CurvesToolValue.CurvesTypeLuminance: + paintCurve.setColor(0xffffffff); + curvesValue = curveValue.luminanceCurve; + break; + + case PhotoFilterView.CurvesToolValue.CurvesTypeRed: + paintCurve.setColor(0xffed3d4c); + curvesValue = curveValue.redCurve; + break; + + case PhotoFilterView.CurvesToolValue.CurvesTypeGreen: + paintCurve.setColor(0xff10ee9d); + curvesValue = curveValue.greenCurve; + break; + + case PhotoFilterView.CurvesToolValue.CurvesTypeBlue: + paintCurve.setColor(0xff3377fb); + curvesValue = curveValue.blueCurve; + break; + + default: + break; + } + + for (int a = 0; a < 5; a++) { + String str; + switch (a) { + case 0: + str = String.format(Locale.US, "%.2f", curvesValue.blacksLevel / 100.0f); + break; + case 1: + str = String.format(Locale.US, "%.2f", curvesValue.shadowsLevel / 100.0f); + break; + case 2: + str = String.format(Locale.US, "%.2f", curvesValue.midtonesLevel / 100.0f); + break; + case 3: + str = String.format(Locale.US, "%.2f", curvesValue.highlightsLevel / 100.0f); + break; + case 4: + str = String.format(Locale.US, "%.2f", curvesValue.whitesLevel / 100.0f); + break; + default: + str = ""; + break; + } + float width = textPaint.measureText(str); + canvas.drawText(str, actualArea.x + (segmentWidth - width) / 2 + segmentWidth * a, actualArea.y + actualArea.height - AndroidUtilities.dp(4), textPaint); + } + + float[] points = curvesValue.interpolateCurve(); + invalidate(); + path.reset(); + for (int a = 0; a < points.length / 2; a++) { + if (a == 0) { + path.moveTo(actualArea.x + points[a * 2] * actualArea.width, actualArea.y + (1.0f - points[a * 2 + 1]) * actualArea.height); + } else { + path.lineTo(actualArea.x + points[a * 2] * actualArea.width, actualArea.y + (1.0f - points[a * 2 + 1]) * actualArea.height); + } + } + + canvas.drawPath(path, paintCurve); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterView.java index 0ecb1b68..c5a16298 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoFilterView.java @@ -25,6 +25,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; @@ -39,11 +40,13 @@ import org.telegram.messenger.AnimationCompat.AnimatorListenerAdapterProxy; import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; import org.telegram.messenger.AnimationCompat.ViewProxy; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.PhotoEditToolCell; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; +import java.util.ArrayList; import java.util.concurrent.Semaphore; import javax.microedition.khronos.egl.EGL10; @@ -57,9 +60,35 @@ import javax.microedition.khronos.opengles.GL10; @SuppressLint("NewApi") public class PhotoFilterView extends FrameLayout { + private final int[] tintShadowColors = new int[] { + 0x00000000, + 0xffff4d4d, + 0xfff48022, + 0xffffcd00, + 0xff81d281, + 0xff71c5d6, + 0xff0072bc, + 0xff662d91 + }; + + private final int[] tintHighlighsColors = new int[] { + 0x00000000, + 0xffef9286, + 0xffeacea2, + 0xfff2e17c, + 0xffa4edae, + 0xff89dce5, + 0xff2e8bc8, + 0xffcd98e5 + }; + private boolean showOriginal; private float previousValue; + private int previousValueInt; + private int previousValueInt2; + + private int selectedTintMode; private int selectedTool = -1; private int enhanceTool = 0; @@ -67,24 +96,35 @@ public class PhotoFilterView extends FrameLayout { private int contrastTool = 2; private int warmthTool = 3; private int saturationTool = 4; - private int highlightsTool = 5; - private int shadowsTool = 6; - private int vignetteTool = 7; - private int grainTool = 8; - private int blurTool = 9; - private int sharpenTool = 10; + private int tintTool = 5; + private int fadeTool = 6; + private int highlightsTool = 7; + private int shadowsTool = 8; + private int vignetteTool = 9; + private int grainTool = 10; + private int blurTool = 11; + private int sharpenTool = 12; + private int curvesTool = 13; - private float highlightsValue = 0; //0 100 - private float contrastValue = 0; //-100 100 - private float shadowsValue = 0; //0 100 - private float exposureValue = 0; //-100 100 private float enhanceValue = 0; //0 100 - private float saturationValue = 0; //-100 100 + private float exposureValue = 0; //-100 100 + private float contrastValue = 0; //-100 100 private float warmthValue = 0; //-100 100 + private float saturationValue = 0; //-100 100 + private float fadeValue = 0; // 0 100 + private int tintShadowsColor = 0; //0 0xffffffff + private int tintHighlightsColor = 0; //0 0xffffffff + private float highlightsValue = 0; //-100 100 + private float shadowsValue = 0; //-100 100 private float vignetteValue = 0; //0 100 private float grainValue = 0; //0 100 - private float sharpenValue = 0; //0 100 private int blurType = 0; //0 none, 1 radial, 2 linear + private float sharpenValue = 0; //0 100 + private CurvesToolValue curvesToolValue = new CurvesToolValue(); + + private final static int curveGranularity = 100; + private final static int curveDataStep = 2; + private float blurExcludeSize = 0.35f; private Point blurExcludePoint = new Point(0.5f, 0.5f); private float blurExcludeBlurSize = 0.15f; @@ -95,7 +135,7 @@ public class PhotoFilterView extends FrameLayout { private FrameLayout toolsView; private FrameLayout editView; private TextView paramTextView; - private TextView blurTextView; + private TextView infoTextView; private TextView valueTextView; private TextView doneTextView; private TextView cancelTextView; @@ -104,13 +144,169 @@ public class PhotoFilterView extends FrameLayout { private RecyclerListView recyclerListView; private FrameLayout blurLayout; private PhotoFilterBlurControl blurControl; + private PhotoFilterCurvesControl curvesControl; private TextView blurOffButton; private TextView blurRadialButton; private TextView blurLinearButton; + private FrameLayout tintLayout; + private TextView tintShadowsButton; + private TextView tintHighlightsButton; + private LinearLayout tintButtonsContainer; + private FrameLayout curveLayout; + private TextView[] curveTextView = new TextView[4]; private Bitmap bitmapToEdit; private int orientation; + public static class CurvesValue { + + public float blacksLevel = 0.0f; + public float shadowsLevel = 25.0f; + public float midtonesLevel = 50.0f; + public float highlightsLevel = 75.0f; + public float whitesLevel = 100.0f; + + public float previousBlacksLevel = 0.0f; + public float previousShadowsLevel = 25.0f; + public float previousMidtonesLevel = 50.0f; + public float previousHighlightsLevel = 75.0f; + public float previousWhitesLevel = 100.0f; + + public float[] cachedDataPoints; + + public float[] getDataPoints() { + if (cachedDataPoints == null) { + interpolateCurve(); + } + return cachedDataPoints; + } + + public void saveValues() { + previousBlacksLevel = blacksLevel; + previousShadowsLevel = shadowsLevel; + previousMidtonesLevel = midtonesLevel; + previousHighlightsLevel = highlightsLevel; + previousWhitesLevel = whitesLevel; + } + + public void restoreValues() { + blacksLevel = previousBlacksLevel; + shadowsLevel = previousShadowsLevel; + midtonesLevel = previousMidtonesLevel; + highlightsLevel = previousHighlightsLevel; + whitesLevel = previousWhitesLevel; + interpolateCurve(); + } + + public float[] interpolateCurve() { + float[] points = new float[] { + -0.001f, blacksLevel / 100.0f, + 0.0f, blacksLevel / 100.0f, + 0.25f, shadowsLevel / 100.0f, + 0.5f, midtonesLevel / 100.0f, + 0.75f, highlightsLevel / 100.0f, + 1f, whitesLevel / 100.0f, + 1.001f, whitesLevel / 100.0f + }; + + ArrayList dataPoints = new ArrayList<>(100); + ArrayList interpolatedPoints = new ArrayList<>(100); + + interpolatedPoints.add(points[0]); + interpolatedPoints.add(points[1]); + + for (int index = 1; index < points.length / 2 - 2; index++) { + float point0x = points[(index - 1) * 2]; + float point0y = points[(index - 1) * 2 + 1]; + float point1x = points[(index) * 2]; + float point1y = points[(index) * 2 + 1]; + float point2x = points[(index + 1) * 2]; + float point2y = points[(index + 1) * 2 + 1]; + float point3x = points[(index + 2) * 2]; + float point3y = points[(index + 2) * 2 + 1]; + + + for (int i = 1; i < curveGranularity; i++) { + float t = (float) i * (1.0f / (float) curveGranularity); + float tt = t * t; + float ttt = tt * t; + + float pix = 0.5f * (2 * point1x + (point2x - point0x) * t + (2 * point0x - 5 * point1x + 4 * point2x - point3x) * tt + (3 * point1x - point0x - 3 * point2x + point3x) * ttt); + float piy = 0.5f * (2 * point1y + (point2y - point0y) * t + (2 * point0y - 5 * point1y + 4 * point2y - point3y) * tt + (3 * point1y - point0y - 3 * point2y + point3y) * ttt); + + piy = Math.max(0, Math.min(1, piy)); + + if (pix > point0x) { + interpolatedPoints.add(pix); + interpolatedPoints.add(piy); + } + + if ((i - 1) % curveDataStep == 0) { + dataPoints.add(piy); + } + } + interpolatedPoints.add(point2x); + interpolatedPoints.add(point2y); + } + interpolatedPoints.add(points[12]); + interpolatedPoints.add(points[13]); + + cachedDataPoints = new float[dataPoints.size()]; + for (int a = 0; a < cachedDataPoints.length; a++) { + cachedDataPoints[a] = dataPoints.get(a); + } + float[] retValue = new float[interpolatedPoints.size()]; + for (int a = 0; a < retValue.length; a++) { + retValue[a] = interpolatedPoints.get(a); + } + return retValue; + } + + public boolean isDefault() { + return Math.abs(blacksLevel - 0) < 0.00001 && Math.abs(shadowsLevel - 25) < 0.00001 && Math.abs(midtonesLevel - 50) < 0.00001 && Math.abs(highlightsLevel - 75) < 0.00001 && Math.abs(whitesLevel - 100) < 0.00001; + } + } + + public static class CurvesToolValue { + + public CurvesValue luminanceCurve = new CurvesValue(); + public CurvesValue redCurve = new CurvesValue(); + public CurvesValue greenCurve = new CurvesValue(); + public CurvesValue blueCurve = new CurvesValue(); + public ByteBuffer curveBuffer = null; + + public int activeType; + + public final static int CurvesTypeLuminance = 0; + public final static int CurvesTypeRed = 1; + public final static int CurvesTypeGreen = 2; + public final static int CurvesTypeBlue = 3; + + public CurvesToolValue() { + curveBuffer = ByteBuffer.allocateDirect(200 * 4); + curveBuffer.order(ByteOrder.LITTLE_ENDIAN); + } + + public void fillBuffer() { + curveBuffer.position(0); + float[] luminanceCurveData = luminanceCurve.getDataPoints(); + float[] redCurveData = redCurve.getDataPoints(); + float[] greenCurveData = greenCurve.getDataPoints(); + float[] blueCurveData = blueCurve.getDataPoints(); + for (int a = 0; a < 200; a++) { + curveBuffer.put((byte) (redCurveData[a] * 255)); + curveBuffer.put((byte) (greenCurveData[a] * 255)); + curveBuffer.put((byte) (blueCurveData[a] * 255)); + curveBuffer.put((byte) (luminanceCurveData[a] * 255)); + } + curveBuffer.position(0); + } + + public boolean shouldBeSkipped() { + return luminanceCurve.isDefault() && redCurve.isDefault() && greenCurve.isDefault() && blueCurve.isDefault(); + } + } + public class EGLThread extends DispatchQueue { private final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; @@ -141,18 +337,26 @@ public class PhotoFilterView extends FrameLayout { private int toolsShaderProgram; private int positionHandle; - private int inputTexCoordHandle; - private int sourceImageHandle; - private int shadowsHandle; - private int highlightsHandle; - private int exposureHandle; - private int contrastHandle; - private int saturationHandle; - private int warmthHandle; - private int vignetteHandle; - private int grainHandle; - private int widthHandle; - private int heightHandle; + private int inputTexCoordHandle; //"varying vec2 texCoord;" + + private int sourceImageHandle; //"uniform sampler2D sourceImage;" + + private int shadowsHandle; //"uniform float shadows;" + + private int highlightsHandle; //"uniform float highlights;" + + private int exposureHandle; //"uniform float exposure;" + + private int contrastHandle; //"uniform float contrast;" + + private int saturationHandle; //"uniform float saturation;" + + private int warmthHandle; //"uniform float warmth;" + + private int vignetteHandle; //"uniform float vignette;" + + private int grainHandle; //"uniform float grain;" + + private int widthHandle; //"uniform float width;" + + private int heightHandle; //"uniform float height;" + + + private int curvesImageHandle; //"uniform sampler2D curvesImage;" + + private int skipToneHandle; //"uniform lowp float skipTone;" + + private int fadeAmountHandle; //"uniform lowp float fadeAmount;" + + private int shadowsTintIntensityHandle; //"uniform lowp float shadowsTintIntensity;" + + private int highlightsTintIntensityHandle; //"uniform lowp float highlightsTintIntensity;" + + private int shadowsTintColorHandle; //"uniform lowp vec3 shadowsTintColor;" + + private int highlightsTintColorHandle; //"uniform lowp vec3 highlightsTintColor;" + private int blurShaderProgram; private int blurPositionHandle; @@ -198,6 +402,7 @@ public class PhotoFilterView extends FrameLayout { private int[] enhanceTextures = new int[2]; private int[] renderTexture = new int[3]; private int[] renderFrameBuffer = new int[3]; + private int[] curveTextures = new int[1]; private boolean hsvGenerated; private int renderBufferWidth; private int renderBufferHeight; @@ -213,6 +418,8 @@ public class PhotoFilterView extends FrameLayout { private final static int PGPhotoEnhanceHistogramBins = 256; private final static int PGPhotoEnhanceSegments = 4; + private long lastRenderCallTime; + private static final String radialBlurFragmentShaderCode = "varying highp vec2 texCoord;" + "uniform sampler2D sourceImage;" + @@ -402,105 +609,285 @@ public class PhotoFilterView extends FrameLayout { "gl_FragColor = result;" + "}"; + /* private static final String toolsFragmentShaderCode = - "precision highp float;" + - "varying vec2 texCoord;" + - "uniform float inputWidth;" + - "uniform float inputHeight;" + + "varying highp vec2 texCoord;" + "uniform sampler2D sourceImage;" + - "uniform float shadows;" + - "uniform float width;" + - "uniform float height;" + - "const vec3 hsLuminanceWeighting = vec3(0.3, 0.3, 0.3);" + - "uniform float highlights;" + - "uniform float exposure;" + - "uniform float contrast;" + - "const vec3 satLuminanceWeighting = vec3(0.2126, 0.7152, 0.0722);" + - "uniform float saturation;" + - "uniform float warmth;" + - "uniform float grain;" + - "const float permTexUnit = 1.0 / 256.0;" + - "const float permTexUnitHalf = 0.5 / 256.0;" + - "const float grainsize = 2.3;" + - "uniform float vignette;" + - "float getLuma(vec3 rgbP) { " + - "return (0.299 * rgbP.r) + (0.587 * rgbP.g) + (0.114 * rgbP.b); " + + "uniform highp float width;" + + "uniform highp float height;" + + "uniform lowp float rgbCurveValues[200];" + + "uniform lowp float redCurveValues[200];" + + "uniform lowp float greenCurveValues[200];" + + "uniform lowp float blueCurveValues[200];" + + "uniform lowp float skipTone;" + + "uniform lowp float shadows;" + + "const mediump vec3 hsLuminanceWeighting = vec3(0.3, 0.3, 0.3);" + + "uniform lowp float highlights;" + + "uniform lowp float contrast;" + + "uniform lowp float fadeAmount;" + + "const mediump vec3 satLuminanceWeighting = vec3(0.2126, 0.7152, 0.0722);" + + "uniform lowp float saturation;" + + "uniform lowp float shadowsTintIntensity;" + + "uniform lowp float highlightsTintIntensity;" + + "uniform lowp vec3 shadowsTintColor;" + + "uniform lowp vec3 highlightsTintColor;" + + "uniform lowp float exposure;" + + "uniform lowp float warmth;" + + "uniform lowp float grain;" + + "const lowp float permTexUnit = 1.0 / 256.0;" + + "const lowp float permTexUnitHalf = 0.5 / 256.0;" + + "const lowp float grainsize = 2.3;" + + "uniform lowp float vignette;" + + "highp float getLuma(highp vec3 rgbP) {" + + "return (0.299 * rgbP.r) + (0.587 * rgbP.g) + (0.114 * rgbP.b);" + "}" + - "vec3 rgbToYuv(vec3 inP) {" + - "vec3 outP;" + + "lowp vec3 rgbToHsv(lowp vec3 c) {" + + "highp vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);" + + "highp vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy);" + + "highp vec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx);" + + "highp float d = q.x - min(q.w, q.y);" + + "highp float e = 1.0e-10;" + + "return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);" + + "}" + + "lowp vec3 hsvToRgb(lowp vec3 c) {" + + "highp vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);" + + "highp vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);" + + "return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);" + + "}" + + "highp vec3 rgbToHsl(highp vec3 color) {" + + "highp vec3 hsl;" + + "highp float fmin = min(min(color.r, color.g), color.b);" + + "highp float fmax = max(max(color.r, color.g), color.b);" + + "highp float delta = fmax - fmin;" + + "hsl.z = (fmax + fmin) / 2.0;" + + "if (delta == 0.0) {" + + "hsl.x = 0.0;" + + "hsl.y = 0.0;" + + "} else {" + + "if (hsl.z < 0.5) {" + + "hsl.y = delta / (fmax + fmin);" + + "} else {" + + "hsl.y = delta / (2.0 - fmax - fmin);" + + "}" + + "highp float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;" + + "highp float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;" + + "highp float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;" + + "if (color.r == fmax) {" + + "hsl.x = deltaB - deltaG;" + + "} else if (color.g == fmax) {" + + "hsl.x = (1.0 / 3.0) + deltaR - deltaB;" + + "} else if (color.b == fmax) {" + + "hsl.x = (2.0 / 3.0) + deltaG - deltaR;" + + "}" + + "if (hsl.x < 0.0) {" + + "hsl.x += 1.0;" + + "} else if (hsl.x > 1.0) {" + + "hsl.x -= 1.0;" + + "}" + + "}" + + "return hsl;" + + "}" + + "highp float hueToRgb(highp float f1, highp float f2, highp float hue) {" + + "if (hue < 0.0) {" + + "hue += 1.0;" + + "} else if (hue > 1.0) {" + + "hue -= 1.0;" + + "}" + + "highp float res;" + + "if ((6.0 * hue) < 1.0) {" + + "res = f1 + (f2 - f1) * 6.0 * hue;" + + "} else if ((2.0 * hue) < 1.0) {" + + "res = f2;" + + "} else if ((3.0 * hue) < 2.0) {" + + "res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;" + + "} else {" + + "res = f1;" + + "} return res;" + + "}" + + "highp vec3 hslToRgb(highp vec3 hsl) {" + + "highp vec3 rgb;" + + "if (hsl.y == 0.0) {" + + "rgb = vec3(hsl.z);" + + "} else {" + + "highp float f2;" + + "if (hsl.z < 0.5) {" + + "f2 = hsl.z * (1.0 + hsl.y);" + + "} else {" + + "f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);" + + "}" + + "highp float f1 = 2.0 * hsl.z - f2;" + + "rgb.r = hueToRgb(f1, f2, hsl.x + (1.0/3.0));" + + "rgb.g = hueToRgb(f1, f2, hsl.x);" + + "rgb.b = hueToRgb(f1, f2, hsl.x - (1.0/3.0));" + + "}" + + "return rgb;" + + "}" + + "highp vec3 rgbToYuv(highp vec3 inP) {" + + "highp vec3 outP;" + "outP.r = getLuma(inP);" + "outP.g = (1.0 / 1.772) * (inP.b - outP.r);" + "outP.b = (1.0 / 1.402) * (inP.r - outP.r);" + - "return outP; " + + "return outP;" + "}" + - "vec3 yuvToRgb(vec3 inP) {" + - "return vec3(1.402 * inP.b + inP.r, (inP.r - (0.299 * 1.402 / 0.587) * inP.b - (0.114 * 1.772 / 0.587) * inP.g), 1.772 * inP.g + inP.r);" + + "lowp vec3 yuvToRgb(highp vec3 inP) {" + + "highp float y = inP.r;" + + "highp float u = inP.g;" + + "highp float v = inP.b;" + + "lowp vec3 outP;" + + "outP.r = 1.402 * v + y;" + + "outP.g = (y - (0.299 * 1.402 / 0.587) * v - (0.114 * 1.772 / 0.587) * u);" + + "outP.b = 1.772 * u + y;" + + "return outP;" + "}" + - "float easeInOutSigmoid(float value, float strength) {" + - "float t = 1.0 / (1.0 - strength);" + + "lowp float easeInOutSigmoid(lowp float value, lowp float strength) {" + + "lowp float t = 1.0 / (1.0 - strength);" + "if (value > 0.5) {" + "return 1.0 - pow(2.0 - 2.0 * value, t) * 0.5;" + "} else {" + - "return pow(2.0 * value, t) * 0.5; " + + "return pow(2.0 * value, t) * 0.5;" + "}" + "}" + - "vec4 rnm(in vec2 tc) {" + - "float noise = sin(dot(tc,vec2(12.9898,78.233))) * 43758.5453;" + - "float noiseR = fract(noise)*2.0-1.0;" + - "float noiseG = fract(noise*1.2154)*2.0-1.0;" + - "float noiseB = fract(noise*1.3453)*2.0-1.0;" + - "float noiseA = fract(noise*1.3647)*2.0-1.0;" + + "lowp vec3 applyLuminanceCurve(lowp vec3 pixel) {" + + "int index = int(clamp(pixel.z / (1.0 / 200.0), 0.0, 199.0));" + + "highp float value = rgbCurveValues[index];" + + "highp float grayscale = (smoothstep(0.0, 0.1, pixel.z) * (1.0 - smoothstep(0.8, 1.0, pixel.z)));" + + "highp float saturation = mix(0.0, pixel.y, grayscale);" + + "pixel.y = saturation;" + + "pixel.z = value;" + + "return pixel;" + + "}" + + "lowp vec3 applyRGBCurve(lowp vec3 pixel) {" + + "int index = int(clamp(pixel.r / (1.0 / 200.0), 0.0, 199.0));" + + "highp float value = redCurveValues[index];" + + "pixel.r = value;" + + "index = int(clamp(pixel.g / (1.0 / 200.0), 0.0, 199.0));" + + "value = greenCurveValues[index];" + + "pixel.g = clamp(value, 0.0, 1.0);" + + "index = int(clamp(pixel.b / (1.0 / 200.0), 0.0, 199.0));" + + "value = blueCurveValues[index];" + + "pixel.b = clamp(value, 0.0, 1.0);" + + "return pixel;" + + "}" + + "highp vec3 fadeAdjust(highp vec3 color, highp float fadeVal) {" + + "highp vec3 co1 = vec3(-0.9772);" + + "highp vec3 co2 = vec3(1.708);" + + "highp vec3 co3 = vec3(-0.1603);" + + "highp vec3 co4 = vec3(0.2878);" + + "highp vec3 comp1 = co1 * pow(vec3(color), vec3(3.0));" + + "highp vec3 comp2 = co2 * pow(vec3(color), vec3(2.0));" + + "highp vec3 comp3 = co3 * vec3(color);" + + "highp vec3 comp4 = co4;" + + "highp vec3 finalComponent = comp1 + comp2 + comp3 + comp4;" + + "highp vec3 difference = finalComponent - color;" + + "highp vec3 scalingValue = vec3(0.9);" + + "highp vec3 faded = color + (difference * scalingValue);" + + "return (color * (1.0 - fadeVal)) + (faded * fadeVal);" + + "}" + + "lowp vec3 tintRaiseShadowsCurve(lowp vec3 color) {" + + "highp vec3 co1 = vec3(-0.003671);" + + "highp vec3 co2 = vec3(0.3842);" + + "highp vec3 co3 = vec3(0.3764);" + + "highp vec3 co4 = vec3(0.2515);" + + "highp vec3 comp1 = co1 * pow(color, vec3(3.0));" + + "highp vec3 comp2 = co2 * pow(color, vec3(2.0));" + + "highp vec3 comp3 = co3 * color;" + + "highp vec3 comp4 = co4;" + + "return comp1 + comp2 + comp3 + comp4;" + + "}" + + "lowp vec3 tintShadows(lowp vec3 texel, lowp vec3 tintColor, lowp float tintAmount) {" + + "highp vec3 raisedShadows = tintRaiseShadowsCurve(texel);" + + "highp vec3 tintedShadows = mix(texel, raisedShadows, tintColor);" + + "highp vec3 tintedShadowsWithAmount = mix(texel, tintedShadows, tintAmount);" + + "return clamp(tintedShadowsWithAmount, 0.0, 1.0);" + + "} " + + "lowp vec3 tintHighlights(lowp vec3 texel, lowp vec3 tintColor, lowp float tintAmount) {" + + "lowp vec3 loweredHighlights = vec3(1.0) - tintRaiseShadowsCurve(vec3(1.0) - texel);" + + "lowp vec3 tintedHighlights = mix(texel, loweredHighlights, (vec3(1.0) - tintColor));" + + "lowp vec3 tintedHighlightsWithAmount = mix(texel, tintedHighlights, tintAmount);" + + "return clamp(tintedHighlightsWithAmount, 0.0, 1.0);" + + "}" + + "highp vec4 rnm(in highp vec2 tc) {" + + "highp float noise = sin(dot(tc,vec2(12.9898,78.233))) * 43758.5453;" + + "highp float noiseR = fract(noise)*2.0-1.0;" + + "highp float noiseG = fract(noise*1.2154)*2.0-1.0;" + + "highp float noiseB = fract(noise*1.3453)*2.0-1.0;" + + "highp float noiseA = fract(noise*1.3647)*2.0-1.0;" + "return vec4(noiseR,noiseG,noiseB,noiseA);" + "}" + - "float fade(in float t) {" + + "highp float fade(in highp float t) {" + "return t*t*t*(t*(t*6.0-15.0)+10.0);" + "}" + - "float pnoise3D(in vec3 p) {" + - "vec3 pi = permTexUnit*floor(p)+permTexUnitHalf;" + - "vec3 pf = fract(p);" + - "float perm00 = rnm(pi.xy).a;" + - "vec3 grad000 = rnm(vec2(perm00, pi.z)).rgb * 4.0 - 1.0;" + - "float n000 = dot(grad000, pf);" + - "vec3 grad001 = rnm(vec2(perm00, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + - "float n001 = dot(grad001, pf - vec3(0.0, 0.0, 1.0));" + - "float perm01 = rnm(pi.xy + vec2(0.0, permTexUnit)).a;" + - "vec3 grad010 = rnm(vec2(perm01, pi.z)).rgb * 4.0 - 1.0;" + - "float n010 = dot(grad010, pf - vec3(0.0, 1.0, 0.0));" + - "vec3 grad011 = rnm(vec2(perm01, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + - "float n011 = dot(grad011, pf - vec3(0.0, 1.0, 1.0));" + - "float perm10 = rnm(pi.xy + vec2(permTexUnit, 0.0)).a;" + - "vec3 grad100 = rnm(vec2(perm10, pi.z)).rgb * 4.0 - 1.0;" + - "float n100 = dot(grad100, pf - vec3(1.0, 0.0, 0.0));" + - "vec3 grad101 = rnm(vec2(perm10, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + - "float n101 = dot(grad101, pf - vec3(1.0, 0.0, 1.0));" + - "float perm11 = rnm(pi.xy + vec2(permTexUnit, permTexUnit)).a;" + - "vec3 grad110 = rnm(vec2(perm11, pi.z)).rgb * 4.0 - 1.0;" + - "float n110 = dot(grad110, pf - vec3(1.0, 1.0, 0.0));" + - "vec3 grad111 = rnm(vec2(perm11, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + - "float n111 = dot(grad111, pf - vec3(1.0, 1.0, 1.0));" + - "vec4 n_x = mix(vec4(n000, n001, n010, n011), vec4(n100, n101, n110, n111), fade(pf.x));" + - "vec2 n_xy = mix(n_x.xy, n_x.zw, fade(pf.y));" + - "float n_xyz = mix(n_xy.x, n_xy.y, fade(pf.z));" + + "highp float pnoise3D(in highp vec3 p) {" + + "highp vec3 pi = permTexUnit*floor(p)+permTexUnitHalf;" + + "highp vec3 pf = fract(p);" + + "highp float perm00 = rnm(pi.xy).a;" + + "highp vec3 grad000 = rnm(vec2(perm00, pi.z)).rgb * 4.0 - 1.0;" + + "highp float n000 = dot(grad000, pf);" + + "highp vec3 grad001 = rnm(vec2(perm00, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + + "highp float n001 = dot(grad001, pf - vec3(0.0, 0.0, 1.0));" + + "highp float perm01 = rnm(pi.xy + vec2(0.0, permTexUnit)).a;" + + "highp vec3 grad010 = rnm(vec2(perm01, pi.z)).rgb * 4.0 - 1.0;" + + "highp float n010 = dot(grad010, pf - vec3(0.0, 1.0, 0.0));" + + "highp vec3 grad011 = rnm(vec2(perm01, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + + "highp float n011 = dot(grad011, pf - vec3(0.0, 1.0, 1.0));" + + "highp float perm10 = rnm(pi.xy + vec2(permTexUnit, 0.0)).a;" + + "highp vec3 grad100 = rnm(vec2(perm10, pi.z)).rgb * 4.0 - 1.0;" + + "highp float n100 = dot(grad100, pf - vec3(1.0, 0.0, 0.0));" + + "highp vec3 grad101 = rnm(vec2(perm10, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + + "highp float n101 = dot(grad101, pf - vec3(1.0, 0.0, 1.0));" + + "highp float perm11 = rnm(pi.xy + vec2(permTexUnit, permTexUnit)).a;" + + "highp vec3 grad110 = rnm(vec2(perm11, pi.z)).rgb * 4.0 - 1.0;" + + "highp float n110 = dot(grad110, pf - vec3(1.0, 1.0, 0.0));" + + "highp vec3 grad111 = rnm(vec2(perm11, pi.z + permTexUnit)).rgb * 4.0 - 1.0;" + + "highp float n111 = dot(grad111, pf - vec3(1.0, 1.0, 1.0));" + + "highp vec4 n_x = mix(vec4(n000, n001, n010, n011), vec4(n100, n101, n110, n111), fade(pf.x));" + + "highp vec2 n_xy = mix(n_x.xy, n_x.zw, fade(pf.y));" + + "highp float n_xyz = mix(n_xy.x, n_xy.y, fade(pf.z));" + "return n_xyz;" + "}" + - "vec2 coordRot(in vec2 tc, in float angle) {" + - "float rotX = ((tc.x * 2.0 - 1.0) * cos(angle)) - ((tc.y * 2.0 - 1.0) * sin(angle));" + - "float rotY = ((tc.y * 2.0 - 1.0) * cos(angle)) + ((tc.x * 2.0 - 1.0) * sin(angle));" + - "return vec2(rotX * 0.5 + 0.5, rotY * 0.5 + 0.5);" + + "lowp vec2 coordRot(in lowp vec2 tc, in lowp float angle) {" + + "lowp float rotX = ((tc.x * 2.0 - 1.0) * cos(angle)) - ((tc.y * 2.0 - 1.0) * sin(angle));" + + "lowp float rotY = ((tc.y * 2.0 - 1.0) * cos(angle)) + ((tc.x * 2.0 - 1.0) * sin(angle));" + + "rotX = rotX * 0.5 + 0.5;" + + "rotY = rotY * 0.5 + 0.5;" + + "return vec2(rotX,rotY);" + "}" + "void main() {" + - "vec4 result = texture2D(sourceImage, texCoord);" + - "const float toolEpsilon = 0.005;" + - - "float hsLuminance = dot(result.rgb, hsLuminanceWeighting);" + - "float shadow = clamp((pow(hsLuminance, 1.0 / (shadows + 1.0)) + (-0.76) * pow(hsLuminance, 2.0 / (shadows + 1.0))) - hsLuminance, 0.0, 1.0);" + - "float highlight = clamp((1.0 - (pow(1.0 - hsLuminance, 1.0 / (2.0 - highlights)) + (-0.8) * pow(1.0 - hsLuminance, 2.0 / (2.0 - highlights)))) - hsLuminance, -1.0, 0.0);" + - "vec3 shresult = (hsLuminance + shadow + highlight) * (result.rgb / hsLuminance);" + - "result = vec4(shresult.rgb, result.a);" + - + "lowp vec4 source = texture2D(sourceImage, texCoord);" + + "lowp vec4 result = source;" + + "const lowp float toolEpsilon = 0.005;" + + "if (skipTone < toolEpsilon) {" + + "result = vec4(applyRGBCurve(hslToRgb(applyLuminanceCurve(rgbToHsl(result.rgb)))), result.a);" + + "}" + + "mediump float hsLuminance = dot(result.rgb, hsLuminanceWeighting);" + + "mediump float shadow = clamp((pow(hsLuminance, 1.0 / shadows) + (-0.76) * pow(hsLuminance, 2.0 / shadows)) - hsLuminance, 0.0, 1.0);" + + "mediump float highlight = clamp((1.0 - (pow(1.0 - hsLuminance, 1.0 / (2.0 - highlights)) + (-0.8) * pow(1.0 - hsLuminance, 2.0 / (2.0 - highlights)))) - hsLuminance, -1.0, 0.0);" + + "lowp vec3 hsresult = vec3(0.0, 0.0, 0.0) + ((hsLuminance + shadow + highlight) - 0.0) * ((result.rgb - vec3(0.0, 0.0, 0.0)) / (hsLuminance - 0.0));" + + "mediump float contrastedLuminance = ((hsLuminance - 0.5) * 1.5) + 0.5;" + + "mediump float whiteInterp = contrastedLuminance * contrastedLuminance * contrastedLuminance;" + + "mediump float whiteTarget = clamp(highlights, 1.0, 2.0) - 1.0;" + + "hsresult = mix(hsresult, vec3(1.0), whiteInterp * whiteTarget);" + + "mediump float invContrastedLuminance = 1.0 - contrastedLuminance;" + + "mediump float blackInterp = invContrastedLuminance * invContrastedLuminance * invContrastedLuminance;" + + "mediump float blackTarget = 1.0 - clamp(shadows, 0.0, 1.0);" + + "hsresult = mix(hsresult, vec3(0.0), blackInterp * blackTarget);" + + "result = vec4(hsresult.rgb, result.a);" + + "result = vec4(clamp(((result.rgb - vec3(0.5)) * contrast + vec3(0.5)), 0.0, 1.0), result.a);" + + "if (abs(fadeAmount) > toolEpsilon) {" + + "result.rgb = fadeAdjust(result.rgb, fadeAmount);" + + "}" + + "lowp float satLuminance = dot(result.rgb, satLuminanceWeighting);" + + "lowp vec3 greyScaleColor = vec3(satLuminance);" + + "result = vec4(clamp(mix(greyScaleColor, result.rgb, saturation), 0.0, 1.0), result.a);" + + "if (abs(shadowsTintIntensity) > toolEpsilon) {" + + "result.rgb = tintShadows(result.rgb, shadowsTintColor, shadowsTintIntensity * 2.0);" + + "}" + + "if (abs(highlightsTintIntensity) > toolEpsilon) {" + + "result.rgb = tintHighlights(result.rgb, highlightsTintColor, highlightsTintIntensity * 2.0);" + + "}" + "if (abs(exposure) > toolEpsilon) {" + - "float mag = exposure * 1.045;" + - "float exppower = 1.0 + abs(mag);" + + "mediump float mag = exposure * 1.045;" + + "mediump float exppower = 1.0 + abs(mag);" + "if (mag < 0.0) {" + "exppower = 1.0 / exppower;" + "}" + @@ -508,41 +895,290 @@ public class PhotoFilterView extends FrameLayout { "result.g = 1.0 - pow((1.0 - result.g), exppower);" + "result.b = 1.0 - pow((1.0 - result.b), exppower);" + "}" + - "result = vec4(((result.rgb - vec3(0.5)) * contrast + vec3(0.5)), result.a);" + - "float satLuminance = dot(result.rgb, satLuminanceWeighting);" + - "vec3 greyScaleColor = vec3(satLuminance);" + - "result = vec4(mix(greyScaleColor, result.rgb, saturation), result.a);" + "if (abs(warmth) > toolEpsilon) {" + - "vec3 yuvVec; if (warmth > 0.0 ) {" + + "highp vec3 yuvVec;" + + "if (warmth > 0.0 ) {" + "yuvVec = vec3(0.1765, -0.1255, 0.0902);" + "} else {" + "yuvVec = -vec3(0.0588, 0.1569, -0.1255);" + "}" + - "vec3 yuvColor = rgbToYuv(result.rgb);" + - "float luma = yuvColor.r;" + - "float curveScale = sin(luma * 3.14159);" + + "highp vec3 yuvColor = rgbToYuv(result.rgb);" + + "highp float luma = yuvColor.r;" + + "highp float curveScale = sin(luma * 3.14159);" + "yuvColor += 0.375 * warmth * curveScale * yuvVec;" + "result.rgb = yuvToRgb(yuvColor);" + "}" + "if (abs(grain) > toolEpsilon) {" + - "vec3 rotOffset = vec3(1.425, 3.892, 5.835);" + - "vec2 rotCoordsR = coordRot(texCoord, rotOffset.x);" + - "vec3 noise = vec3(pnoise3D(vec3(rotCoordsR * vec2(width / grainsize, height / grainsize),0.0)));" + - "vec3 lumcoeff = vec3(0.299,0.587,0.114);" + - "float luminance = dot(result.rgb, lumcoeff);" + - "float lum = smoothstep(0.2, 0.0, luminance);" + + "highp vec3 rotOffset = vec3(1.425, 3.892, 5.835);" + + "highp vec2 rotCoordsR = coordRot(texCoord, rotOffset.x);" + + "highp vec3 noise = vec3(pnoise3D(vec3(rotCoordsR * vec2(width / grainsize, height / grainsize),0.0)));" + + "lowp vec3 lumcoeff = vec3(0.299,0.587,0.114);" + + "lowp float luminance = dot(result.rgb, lumcoeff);" + + "lowp float lum = smoothstep(0.2, 0.0, luminance);" + "lum += luminance;" + "noise = mix(noise,vec3(0.0),pow(lum,4.0));" + "result.rgb = result.rgb + noise * grain;" + "}" + "if (abs(vignette) > toolEpsilon) {" + - "const float midpoint = 0.7;" + - "const float fuzziness = 0.62;" + - "float radDist = length(texCoord - 0.5) / sqrt(0.5);" + - "float mag = easeInOutSigmoid(radDist * midpoint, fuzziness) * vignette * 0.645;" + + "const lowp float midpoint = 0.7;" + + "const lowp float fuzziness = 0.62;" + + "lowp float radDist = length(texCoord - 0.5) / sqrt(0.5);" + + "lowp float mag = easeInOutSigmoid(radDist * midpoint, fuzziness) * vignette * 0.645;" + "result.rgb = mix(pow(result.rgb, vec3(1.0 / (1.0 - mag))), vec3(0.0), mag * mag);" + "}" + + "gl_FragColor = result;" + + "}"; + */ + private static final String toolsFragmentShaderCode = + "varying highp vec2 texCoord;" + + "uniform sampler2D sourceImage;" + + "uniform highp float width;" + + "uniform highp float height;" + + "uniform sampler2D curvesImage;" + + "uniform lowp float skipTone;" + + "uniform lowp float shadows;" + + "const mediump vec3 hsLuminanceWeighting = vec3(0.3, 0.3, 0.3);" + + "uniform lowp float highlights;" + + "uniform lowp float contrast;" + + "uniform lowp float fadeAmount;" + + "const mediump vec3 satLuminanceWeighting = vec3(0.2126, 0.7152, 0.0722);" + + "uniform lowp float saturation;" + + "uniform lowp float shadowsTintIntensity;" + + "uniform lowp float highlightsTintIntensity;" + + "uniform lowp vec3 shadowsTintColor;" + + "uniform lowp vec3 highlightsTintColor;" + + "uniform lowp float exposure;" + + "uniform lowp float warmth;" + + "uniform lowp float grain;" + + "const lowp float permTexUnit = 1.0 / 256.0;" + + "const lowp float permTexUnitHalf = 0.5 / 256.0;" + + "const lowp float grainsize = 2.3;" + + "uniform lowp float vignette;" + + "highp float getLuma(highp vec3 rgbP) {" + + "return (0.299 * rgbP.r) + (0.587 * rgbP.g) + (0.114 * rgbP.b);" + + "}" + + "lowp vec3 rgbToHsv(lowp vec3 c) {" + + "highp vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);" + + "highp vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy);" + + "highp vec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx);" + + "highp float d = q.x - min(q.w, q.y);" + + "highp float e = 1.0e-10;" + + "return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);" + + "}" + + "lowp vec3 hsvToRgb(lowp vec3 c) {" + + "highp vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);" + + "highp vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);" + + "return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);" + + "}" + + "highp vec3 rgbToHsl(highp vec3 color) {" + + "highp vec3 hsl;" + + "highp float fmin = min(min(color.r, color.g), color.b);" + + "highp float fmax = max(max(color.r, color.g), color.b);" + + "highp float delta = fmax - fmin;" + + "hsl.z = (fmax + fmin) / 2.0;" + + "if (delta == 0.0) {" + + "hsl.x = 0.0;" + + "hsl.y = 0.0;" + + "} else {" + + "if (hsl.z < 0.5) {" + + "hsl.y = delta / (fmax + fmin);" + + "} else {" + + "hsl.y = delta / (2.0 - fmax - fmin);" + + "}" + + "highp float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;" + + "highp float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;" + + "highp float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;" + + "if (color.r == fmax) {" + + "hsl.x = deltaB - deltaG;" + + "} else if (color.g == fmax) {" + + "hsl.x = (1.0 / 3.0) + deltaR - deltaB;" + + "} else if (color.b == fmax) {" + + "hsl.x = (2.0 / 3.0) + deltaG - deltaR;" + + "}" + + "if (hsl.x < 0.0) {" + + "hsl.x += 1.0;" + + "} else if (hsl.x > 1.0) {" + + "hsl.x -= 1.0;" + + "}" + + "}" + + "return hsl;" + + "}" + + "highp float hueToRgb(highp float f1, highp float f2, highp float hue) {" + + "if (hue < 0.0) {" + + "hue += 1.0;" + + "} else if (hue > 1.0) {" + + "hue -= 1.0;" + + "}" + + "highp float res;" + + "if ((6.0 * hue) < 1.0) {" + + "res = f1 + (f2 - f1) * 6.0 * hue;" + + "} else if ((2.0 * hue) < 1.0) {" + + "res = f2;" + + "} else if ((3.0 * hue) < 2.0) {" + + "res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;" + + "} else {" + + "res = f1;" + + "} return res;" + + "}" + + "highp vec3 hslToRgb(highp vec3 hsl) {" + + "if (hsl.y == 0.0) {" + + "return vec3(hsl.z);" + + "} else {" + + "highp float f2;" + + "if (hsl.z < 0.5) {" + + "f2 = hsl.z * (1.0 + hsl.y);" + + "} else {" + + "f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);" + + "}" + + "highp float f1 = 2.0 * hsl.z - f2;" + + "return vec3(hueToRgb(f1, f2, hsl.x + (1.0/3.0)), hueToRgb(f1, f2, hsl.x), hueToRgb(f1, f2, hsl.x - (1.0/3.0)));" + + "}" + + "}" + + "highp vec3 rgbToYuv(highp vec3 inP) {" + + "highp float luma = getLuma(inP);" + + "return vec3(luma, (1.0 / 1.772) * (inP.b - luma), (1.0 / 1.402) * (inP.r - luma));" + + "}" + + "lowp vec3 yuvToRgb(highp vec3 inP) {" + + "return vec3(1.402 * inP.b + inP.r, (inP.r - (0.299 * 1.402 / 0.587) * inP.b - (0.114 * 1.772 / 0.587) * inP.g), 1.772 * inP.g + inP.r);" + + "}" + + "lowp float easeInOutSigmoid(lowp float value, lowp float strength) {" + + "if (value > 0.5) {" + + "return 1.0 - pow(2.0 - 2.0 * value, 1.0 / (1.0 - strength)) * 0.5;" + + "} else {" + + "return pow(2.0 * value, 1.0 / (1.0 - strength)) * 0.5;" + + "}" + + "}" + + "lowp vec3 applyLuminanceCurve(lowp vec3 pixel) {" + + "highp float index = floor(clamp(pixel.z / (1.0 / 200.0), 0.0, 199.0));" + + "pixel.y = mix(0.0, pixel.y, smoothstep(0.0, 0.1, pixel.z) * (1.0 - smoothstep(0.8, 1.0, pixel.z)));" + + "pixel.z = texture2D(curvesImage, vec2(1.0 / 200.0 * index, 0)).a;" + + "return pixel;" + + "}" + + "lowp vec3 applyRGBCurve(lowp vec3 pixel) {" + + "highp float index = floor(clamp(pixel.r / (1.0 / 200.0), 0.0, 199.0));" + + "pixel.r = texture2D(curvesImage, vec2(1.0 / 200.0 * index, 0)).r;" + + "index = floor(clamp(pixel.g / (1.0 / 200.0), 0.0, 199.0));" + + "pixel.g = clamp(texture2D(curvesImage, vec2(1.0 / 200.0 * index, 0)).g, 0.0, 1.0);" + + "index = floor(clamp(pixel.b / (1.0 / 200.0), 0.0, 199.0));" + + "pixel.b = clamp(texture2D(curvesImage, vec2(1.0 / 200.0 * index, 0)).b, 0.0, 1.0);" + + "return pixel;" + + "}" + + "highp vec3 fadeAdjust(highp vec3 color, highp float fadeVal) {" + + "return (color * (1.0 - fadeVal)) + ((color + (vec3(-0.9772) * pow(vec3(color), vec3(3.0)) + vec3(1.708) * pow(vec3(color), vec3(2.0)) + vec3(-0.1603) * vec3(color) + vec3(0.2878) - color * vec3(0.9))) * fadeVal);" + + "}" + + "lowp vec3 tintRaiseShadowsCurve(lowp vec3 color) {" + + "return vec3(-0.003671) * pow(color, vec3(3.0)) + vec3(0.3842) * pow(color, vec3(2.0)) + vec3(0.3764) * color + vec3(0.2515);" + + "}" + + "lowp vec3 tintShadows(lowp vec3 texel, lowp vec3 tintColor, lowp float tintAmount) {" + + "return clamp(mix(texel, mix(texel, tintRaiseShadowsCurve(texel), tintColor), tintAmount), 0.0, 1.0);" + + "} " + + "lowp vec3 tintHighlights(lowp vec3 texel, lowp vec3 tintColor, lowp float tintAmount) {" + + "return clamp(mix(texel, mix(texel, vec3(1.0) - tintRaiseShadowsCurve(vec3(1.0) - texel), (vec3(1.0) - tintColor)), tintAmount), 0.0, 1.0);" + + "}" + + "highp vec4 rnm(in highp vec2 tc) {" + + "highp float noise = sin(dot(tc, vec2(12.9898, 78.233))) * 43758.5453;" + + "return vec4(fract(noise), fract(noise * 1.2154), fract(noise * 1.3453), fract(noise * 1.3647)) * 2.0 - 1.0;" + + "}" + + "highp float fade(in highp float t) {" + + "return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);" + + "}" + + "highp float pnoise3D(in highp vec3 p) {" + + "highp vec3 pi = permTexUnit * floor(p) + permTexUnitHalf;" + + "highp vec3 pf = fract(p);" + + "highp float perm = rnm(pi.xy).a;" + + "highp float n000 = dot(rnm(vec2(perm, pi.z)).rgb * 4.0 - 1.0, pf);" + + "highp float n001 = dot(rnm(vec2(perm, pi.z + permTexUnit)).rgb * 4.0 - 1.0, pf - vec3(0.0, 0.0, 1.0));" + + "perm = rnm(pi.xy + vec2(0.0, permTexUnit)).a;" + + "highp float n010 = dot(rnm(vec2(perm, pi.z)).rgb * 4.0 - 1.0, pf - vec3(0.0, 1.0, 0.0));" + + "highp float n011 = dot(rnm(vec2(perm, pi.z + permTexUnit)).rgb * 4.0 - 1.0, pf - vec3(0.0, 1.0, 1.0));" + + "perm = rnm(pi.xy + vec2(permTexUnit, 0.0)).a;" + + "highp float n100 = dot(rnm(vec2(perm, pi.z)).rgb * 4.0 - 1.0, pf - vec3(1.0, 0.0, 0.0));" + + "highp float n101 = dot(rnm(vec2(perm, pi.z + permTexUnit)).rgb * 4.0 - 1.0, pf - vec3(1.0, 0.0, 1.0));" + + "perm = rnm(pi.xy + vec2(permTexUnit, permTexUnit)).a;" + + "highp float n110 = dot(rnm(vec2(perm, pi.z)).rgb * 4.0 - 1.0, pf - vec3(1.0, 1.0, 0.0));" + + "highp float n111 = dot(rnm(vec2(perm, pi.z + permTexUnit)).rgb * 4.0 - 1.0, pf - vec3(1.0, 1.0, 1.0));" + + "highp vec4 n_x = mix(vec4(n000, n001, n010, n011), vec4(n100, n101, n110, n111), fade(pf.x));" + + "highp vec2 n_xy = mix(n_x.xy, n_x.zw, fade(pf.y));" + + "return mix(n_xy.x, n_xy.y, fade(pf.z));" + + "}" + + "lowp vec2 coordRot(in lowp vec2 tc, in lowp float angle) {" + + "return vec2(((tc.x * 2.0 - 1.0) * cos(angle) - (tc.y * 2.0 - 1.0) * sin(angle)) * 0.5 + 0.5, ((tc.y * 2.0 - 1.0) * cos(angle) + (tc.x * 2.0 - 1.0) * sin(angle)) * 0.5 + 0.5);" + + "}" + + "void main() {" + + "lowp vec4 source = texture2D(sourceImage, texCoord);" + + "lowp vec4 result = source;" + + "const lowp float toolEpsilon = 0.005;" + + "if (skipTone < toolEpsilon) {" + + "result = vec4(applyRGBCurve(hslToRgb(applyLuminanceCurve(rgbToHsl(result.rgb)))), result.a);" + + "}" + + "mediump float hsLuminance = dot(result.rgb, hsLuminanceWeighting);" + + "mediump float shadow = clamp((pow(hsLuminance, 1.0 / shadows) + (-0.76) * pow(hsLuminance, 2.0 / shadows)) - hsLuminance, 0.0, 1.0);" + + "mediump float highlight = clamp((1.0 - (pow(1.0 - hsLuminance, 1.0 / (2.0 - highlights)) + (-0.8) * pow(1.0 - hsLuminance, 2.0 / (2.0 - highlights)))) - hsLuminance, -1.0, 0.0);" + + "lowp vec3 hsresult = vec3(0.0, 0.0, 0.0) + ((hsLuminance + shadow + highlight) - 0.0) * ((result.rgb - vec3(0.0, 0.0, 0.0)) / (hsLuminance - 0.0));" + + "mediump float contrastedLuminance = ((hsLuminance - 0.5) * 1.5) + 0.5;" + + "mediump float whiteInterp = contrastedLuminance * contrastedLuminance * contrastedLuminance;" + + "mediump float whiteTarget = clamp(highlights, 1.0, 2.0) - 1.0;" + + "hsresult = mix(hsresult, vec3(1.0), whiteInterp * whiteTarget);" + + "mediump float invContrastedLuminance = 1.0 - contrastedLuminance;" + + "mediump float blackInterp = invContrastedLuminance * invContrastedLuminance * invContrastedLuminance;" + + "mediump float blackTarget = 1.0 - clamp(shadows, 0.0, 1.0);" + + "hsresult = mix(hsresult, vec3(0.0), blackInterp * blackTarget);" + + "result = vec4(hsresult.rgb, result.a);" + + "result = vec4(clamp(((result.rgb - vec3(0.5)) * contrast + vec3(0.5)), 0.0, 1.0), result.a);" + + "if (abs(fadeAmount) > toolEpsilon) {" + + "result.rgb = fadeAdjust(result.rgb, fadeAmount);" + + "}" + + "lowp float satLuminance = dot(result.rgb, satLuminanceWeighting);" + + "lowp vec3 greyScaleColor = vec3(satLuminance);" + + "result = vec4(clamp(mix(greyScaleColor, result.rgb, saturation), 0.0, 1.0), result.a);" + + "if (abs(shadowsTintIntensity) > toolEpsilon) {" + + "result.rgb = tintShadows(result.rgb, shadowsTintColor, shadowsTintIntensity * 2.0);" + + "}" + + "if (abs(highlightsTintIntensity) > toolEpsilon) {" + + "result.rgb = tintHighlights(result.rgb, highlightsTintColor, highlightsTintIntensity * 2.0);" + + "}" + + "if (abs(exposure) > toolEpsilon) {" + + "mediump float mag = exposure * 1.045;" + + "mediump float exppower = 1.0 + abs(mag);" + + "if (mag < 0.0) {" + + "exppower = 1.0 / exppower;" + + "}" + + "result.r = 1.0 - pow((1.0 - result.r), exppower);" + + "result.g = 1.0 - pow((1.0 - result.g), exppower);" + + "result.b = 1.0 - pow((1.0 - result.b), exppower);" + + "}" + + "if (abs(warmth) > toolEpsilon) {" + + "highp vec3 yuvVec;" + + "if (warmth > 0.0 ) {" + + "yuvVec = vec3(0.1765, -0.1255, 0.0902);" + + "} else {" + + "yuvVec = -vec3(0.0588, 0.1569, -0.1255);" + + "}" + + "highp vec3 yuvColor = rgbToYuv(result.rgb);" + + "highp float luma = yuvColor.r;" + + "highp float curveScale = sin(luma * 3.14159);" + + "yuvColor += 0.375 * warmth * curveScale * yuvVec;" + + "result.rgb = yuvToRgb(yuvColor);" + + "}" + + "if (abs(grain) > toolEpsilon) {" + + "highp vec3 rotOffset = vec3(1.425, 3.892, 5.835);" + + "highp vec2 rotCoordsR = coordRot(texCoord, rotOffset.x);" + + "highp vec3 noise = vec3(pnoise3D(vec3(rotCoordsR * vec2(width / grainsize, height / grainsize),0.0)));" + + "lowp vec3 lumcoeff = vec3(0.299,0.587,0.114);" + + "lowp float luminance = dot(result.rgb, lumcoeff);" + + "lowp float lum = smoothstep(0.2, 0.0, luminance);" + + "lum += luminance;" + + "noise = mix(noise,vec3(0.0),pow(lum,4.0));" + + "result.rgb = result.rgb + noise * grain;" + + "}" + + "if (abs(vignette) > toolEpsilon) {" + + "const lowp float midpoint = 0.7;" + + "const lowp float fuzziness = 0.62;" + + "lowp float radDist = length(texCoord - 0.5) / sqrt(0.5);" + + "lowp float mag = easeInOutSigmoid(radDist * midpoint, fuzziness) * vignette * 0.645;" + + "result.rgb = mix(pow(result.rgb, vec3(1.0 / (1.0 - mag))), vec3(0.0), mag * mag);" + + "}" + "gl_FragColor = result;" + "}"; @@ -559,6 +1195,7 @@ public class PhotoFilterView extends FrameLayout { int[] compileStatus = new int[1]; GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0); if (compileStatus[0] == 0) { + FileLog.e("tmessages", GLES20.glGetShaderInfoLog(shader)); GLES20.glDeleteShader(shader); shader = 0; } @@ -671,6 +1308,7 @@ public class PhotoFilterView extends FrameLayout { textureBuffer.put(textureCoordinates); textureBuffer.position(0); + GLES20.glGenTextures(1, curveTextures, 0); GLES20.glGenTextures(2, enhanceTextures, 0); int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, simpleVertexShaderCode); @@ -705,6 +1343,13 @@ public class PhotoFilterView extends FrameLayout { grainHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "grain"); widthHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "width"); heightHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "height"); + curvesImageHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "curvesImage"); + skipToneHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "skipTone"); + fadeAmountHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "fadeAmount"); + shadowsTintIntensityHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "shadowsTintIntensity"); + highlightsTintIntensityHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "highlightsTintIntensity"); + shadowsTintColorHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "shadowsTintColor"); + highlightsTintColorHandle = GLES20.glGetUniformLocation(toolsShaderProgram, "highlightsTintColor"); } } else { finish(); @@ -1032,7 +1677,7 @@ public class PhotoFilterView extends FrameLayout { GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, renderTexture[0]); GLES20.glUniform1i(sourceImageHandle, 0); if (showOriginal) { - GLES20.glUniform1f(shadowsHandle, 0); + GLES20.glUniform1f(shadowsHandle, 1); GLES20.glUniform1f(highlightsHandle, 1); GLES20.glUniform1f(exposureHandle, 0); GLES20.glUniform1f(contrastHandle, 1); @@ -1040,6 +1685,12 @@ public class PhotoFilterView extends FrameLayout { GLES20.glUniform1f(warmthHandle, 0); GLES20.glUniform1f(vignetteHandle, 0); GLES20.glUniform1f(grainHandle, 0); + GLES20.glUniform1f(fadeAmountHandle, 0); + GLES20.glUniform3f(highlightsTintColorHandle, 0, 0, 0); + GLES20.glUniform1f(highlightsTintIntensityHandle, 0); + GLES20.glUniform3f(shadowsTintColorHandle, 0, 0, 0); + GLES20.glUniform1f(shadowsTintIntensityHandle, 0); + GLES20.glUniform1f(skipToneHandle, 1); } else { GLES20.glUniform1f(shadowsHandle, getShadowsValue()); GLES20.glUniform1f(highlightsHandle, getHighlightsValue()); @@ -1049,7 +1700,26 @@ public class PhotoFilterView extends FrameLayout { GLES20.glUniform1f(warmthHandle, getWarmthValue()); GLES20.glUniform1f(vignetteHandle, getVignetteValue()); GLES20.glUniform1f(grainHandle, getGrainValue()); + GLES20.glUniform1f(fadeAmountHandle, getFadeValue()); + GLES20.glUniform3f(highlightsTintColorHandle, (tintHighlightsColor >> 16 & 0xff) / 255.0f, (tintHighlightsColor >> 8 & 0xff) / 255.0f, (tintHighlightsColor & 0xff) / 255.0f); + GLES20.glUniform1f(highlightsTintIntensityHandle, getTintHighlightsIntensityValue()); + GLES20.glUniform3f(shadowsTintColorHandle, (tintShadowsColor >> 16 & 0xff) / 255.0f, (tintShadowsColor >> 8 & 0xff) / 255.0f, (tintShadowsColor & 0xff) / 255.0f); + GLES20.glUniform1f(shadowsTintIntensityHandle, getTintShadowsIntensityValue()); + boolean skipTone = curvesToolValue.shouldBeSkipped(); + GLES20.glUniform1f(skipToneHandle, skipTone ? 1.0f : 0.0f); + if (!skipTone) { + curvesToolValue.fillBuffer(); + GLES20.glActiveTexture(GLES20.GL_TEXTURE1); + GLES20.glBindTexture(GL10.GL_TEXTURE_2D, curveTextures[0]); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); + GLES20.glTexParameteri(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); + GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, 200, 1, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, curvesToolValue.curveBuffer); + GLES20.glUniform1i(curvesImageHandle, 1); + } } + GLES20.glUniform1f(widthHandle, renderBufferWidth); GLES20.glUniform1f(heightHandle, renderBufferHeight); GLES20.glEnableVertexAttribArray(inputTexCoordHandle); @@ -1203,36 +1873,17 @@ public class PhotoFilterView extends FrameLayout { } private Bitmap createBitmap(Bitmap bitmap, int w, int h, float scale) { - //Bitmap result = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - //Canvas canvas = new Canvas(result); - //Paint paint = new Paint(); - //paint.setFilterBitmap(true); - Matrix matrix = new Matrix(); matrix.setScale(scale, scale); - //matrix.postTranslate(-bitmap.getWidth() / 2, -bitmap.getHeight() / 2); matrix.postRotate(orientation); - /*if (orientation == 90 || orientation == 270) { - matrix.postTranslate(bitmap.getHeight() / 2, bitmap.getWidth() / 2); - } else { - matrix.postTranslate(bitmap.getWidth() / 2, bitmap.getHeight() / 2); - }*/ - //canvas.drawBitmap(bitmap, matrix, paint); - //try { - // canvas.setBitmap(null); - //} catch (Exception e) { - //don't promt, this will crash on 2.x - //} return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); - - //return result; } private void loadTexture(Bitmap bitmap) { renderBufferWidth = bitmap.getWidth(); renderBufferHeight = bitmap.getHeight(); float maxSize = AndroidUtilities.getPhotoSize(); - if (renderBufferWidth > maxSize || renderBufferHeight > maxSize || orientation != 0) { + if (renderBufferWidth > maxSize || renderBufferHeight > maxSize || orientation % 360 != 0) { float scale = 1; if (renderBufferWidth > maxSize || renderBufferHeight > maxSize) { float scaleX = maxSize / bitmap.getWidth(); @@ -1248,7 +1899,7 @@ public class PhotoFilterView extends FrameLayout { } } - if (orientation == 90 || orientation == 270) { + if (orientation % 360 == 90 || orientation % 360 == 270) { int temp = renderBufferWidth; renderBufferWidth = renderBufferHeight; renderBufferHeight = temp; @@ -1313,8 +1964,13 @@ public class PhotoFilterView extends FrameLayout { if (!needUpdateBlurTexture) { needUpdateBlurTexture = updateBlur; } - cancelRunnable(drawRunnable); - postRunnable(drawRunnable); + long newTime = System.currentTimeMillis(); + if (Math.abs(lastRenderCallTime - newTime) > 30) { + lastRenderCallTime = newTime; + drawRunnable.run(); + //cancelRunnable(drawRunnable); + //postRunnable(drawRunnable, 30); + } } }); } @@ -1331,13 +1987,8 @@ public class PhotoFilterView extends FrameLayout { //setLayerType(LAYER_TYPE_HARDWARE, null); //textureView.setLayerType(LAYER_TYPE_HARDWARE, null); } - addView(textureView); + addView(textureView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); textureView.setVisibility(INVISIBLE); - LayoutParams layoutParams = (LayoutParams) textureView.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.TOP | Gravity.LEFT; - textureView.setLayoutParams(layoutParams); textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { @@ -1356,7 +2007,9 @@ public class PhotoFilterView extends FrameLayout { eglThread.postRunnable(new Runnable() { @Override public void run() { - eglThread.requestRender(false); + if (eglThread != null) { + eglThread.requestRender(false); + } } }); } @@ -1379,12 +2032,7 @@ public class PhotoFilterView extends FrameLayout { blurControl = new PhotoFilterBlurControl(context); blurControl.setVisibility(INVISIBLE); - addView(blurControl); - layoutParams = (LayoutParams) blurControl.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.LEFT | Gravity.TOP; - blurControl.setLayoutParams(layoutParams); + addView(blurControl, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); blurControl.setDelegate(new PhotoFilterBlurControl.PhotoFilterLinearBlurControlDelegate() { @Override public void valueChanged(Point centerPoint, float falloff, float size, float angle) { @@ -1398,52 +2046,44 @@ public class PhotoFilterView extends FrameLayout { } }); + curvesControl = new PhotoFilterCurvesControl(context, curvesToolValue); + curvesControl.setDelegate(new PhotoFilterCurvesControl.PhotoFilterCurvesControlDelegate() { + @Override + public void valueChanged() { + if (eglThread != null) { + eglThread.requestRender(false); + } + } + }); + curvesControl.setVisibility(INVISIBLE); + addView(curvesControl, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.LEFT | Gravity.TOP)); + toolsView = new FrameLayout(context); - addView(toolsView); - layoutParams = (LayoutParams) toolsView.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = AndroidUtilities.dp(126); - layoutParams.gravity = Gravity.LEFT | Gravity.BOTTOM; - toolsView.setLayoutParams(layoutParams); + addView(toolsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 126, Gravity.LEFT | Gravity.BOTTOM)); FrameLayout frameLayout = new FrameLayout(context); frameLayout.setBackgroundColor(0xff1a1a1a); - toolsView.addView(frameLayout); - layoutParams = (LayoutParams) frameLayout.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = AndroidUtilities.dp(48); - layoutParams.gravity = Gravity.BOTTOM | Gravity.LEFT; - frameLayout.setLayoutParams(layoutParams); + toolsView.addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT)); cancelTextView = new TextView(context); cancelTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); cancelTextView.setTextColor(0xffffffff); cancelTextView.setGravity(Gravity.CENTER); - cancelTextView.setBackgroundResource(R.drawable.bar_selector_picker); + cancelTextView.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_PICKER_SELECTOR_COLOR, false)); cancelTextView.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); cancelTextView.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase()); cancelTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - frameLayout.addView(cancelTextView); - layoutParams = (LayoutParams) cancelTextView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.TOP | Gravity.LEFT; - cancelTextView.setLayoutParams(layoutParams); + frameLayout.addView(cancelTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); doneTextView = new TextView(context); doneTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); doneTextView.setTextColor(0xff51bdf3); doneTextView.setGravity(Gravity.CENTER); - doneTextView.setBackgroundResource(R.drawable.bar_selector_picker); + doneTextView.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_PICKER_SELECTOR_COLOR, false)); doneTextView.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); doneTextView.setText(LocaleController.getString("Done", R.string.Done).toUpperCase()); doneTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - frameLayout.addView(doneTextView); - layoutParams = (LayoutParams) doneTextView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.TOP | Gravity.RIGHT; - doneTextView.setLayoutParams(layoutParams); + frameLayout.addView(doneTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); recyclerListView = new RecyclerListView(context); LinearLayoutManager layoutManager = new LinearLayoutManager(context); @@ -1454,12 +2094,7 @@ public class PhotoFilterView extends FrameLayout { recyclerListView.setOverScrollMode(RecyclerListView.OVER_SCROLL_NEVER); } recyclerListView.setAdapter(toolsAdapter = new ToolsAdapter(context)); - toolsView.addView(recyclerListView); - layoutParams = (FrameLayout.LayoutParams) recyclerListView.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = AndroidUtilities.dp(60); - layoutParams.gravity = Gravity.LEFT | Gravity.TOP; - recyclerListView.setLayoutParams(layoutParams); + toolsView.addView(recyclerListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 60, Gravity.LEFT | Gravity.TOP)); recyclerListView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { @Override public void onItemClick(View view, int position) { @@ -1470,7 +2105,7 @@ public class PhotoFilterView extends FrameLayout { paramTextView.setText(LocaleController.getString("Enhance", R.string.Enhance)); } else if (position == highlightsTool) { previousValue = highlightsValue; - valueSeekBar.setMinMax(0, 100); + valueSeekBar.setMinMax(-100, 100); paramTextView.setText(LocaleController.getString("Highlights", R.string.Highlights)); } else if (position == contrastTool) { previousValue = contrastValue; @@ -1494,18 +2129,30 @@ public class PhotoFilterView extends FrameLayout { paramTextView.setText(LocaleController.getString("Vignette", R.string.Vignette)); } else if (position == shadowsTool) { previousValue = shadowsValue; - valueSeekBar.setMinMax(0, 100); + valueSeekBar.setMinMax(-100, 100); paramTextView.setText(LocaleController.getString("Shadows", R.string.Shadows)); } else if (position == grainTool) { previousValue = grainValue; valueSeekBar.setMinMax(0, 100); paramTextView.setText(LocaleController.getString("Grain", R.string.Grain)); + } else if (position == fadeTool) { + previousValue = fadeValue; + valueSeekBar.setMinMax(0, 100); + paramTextView.setText(LocaleController.getString("Fade", R.string.Fade)); } else if (position == sharpenTool) { previousValue = sharpenValue; valueSeekBar.setMinMax(0, 100); paramTextView.setText(LocaleController.getString("Sharpen", R.string.Sharpen)); } else if (position == blurTool) { - previousValue = blurType; + previousValueInt = blurType; + } else if (position == tintTool) { + previousValueInt = tintShadowsColor; + previousValueInt2 = tintHighlightsColor; + } else if (position == curvesTool) { + curvesToolValue.luminanceCurve.saveValues(); + curvesToolValue.redCurve.saveValues(); + curvesToolValue.greenCurve.saveValues(); + curvesToolValue.blueCurve.saveValues(); } valueSeekBar.setProgress((int) previousValue, false); updateValueTextView(); @@ -1515,32 +2162,17 @@ public class PhotoFilterView extends FrameLayout { editView = new FrameLayout(context); editView.setVisibility(GONE); - addView(editView); - layoutParams = (LayoutParams) editView.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = AndroidUtilities.dp(126); - layoutParams.gravity = Gravity.LEFT | Gravity.BOTTOM; - editView.setLayoutParams(layoutParams); + addView(editView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 126, Gravity.LEFT | Gravity.BOTTOM)); frameLayout = new FrameLayout(context); frameLayout.setBackgroundColor(0xff1a1a1a); - editView.addView(frameLayout); - layoutParams = (LayoutParams) frameLayout.getLayoutParams(); - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.height = AndroidUtilities.dp(48); - layoutParams.gravity = Gravity.BOTTOM | Gravity.LEFT; - frameLayout.setLayoutParams(layoutParams); + editView.addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT)); ImageView imageView = new ImageView(context); imageView.setImageResource(R.drawable.edit_cancel); - imageView.setBackgroundResource(R.drawable.bar_selector_picker); + imageView.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_PICKER_SELECTOR_COLOR, false)); imageView.setPadding(AndroidUtilities.dp(22), 0, AndroidUtilities.dp(22), 0); - frameLayout.addView(imageView); - layoutParams = (LayoutParams) imageView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.TOP | Gravity.LEFT; - imageView.setLayoutParams(layoutParams); + frameLayout.addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -1564,8 +2196,18 @@ public class PhotoFilterView extends FrameLayout { grainValue = previousValue; } else if (selectedTool == sharpenTool) { sharpenValue = previousValue; + } else if (selectedTool == fadeTool) { + fadeValue = previousValue; } else if (selectedTool == blurTool) { - blurType = (int) previousValue; + blurType = previousValueInt; + } else if (selectedTool == tintTool) { + tintShadowsColor = previousValueInt; + tintHighlightsColor = previousValueInt2; + } else if (selectedTool == curvesTool) { + curvesToolValue.luminanceCurve.restoreValues(); + curvesToolValue.redCurve.restoreValues(); + curvesToolValue.greenCurve.restoreValues(); + curvesToolValue.blueCurve.restoreValues(); } if (eglThread != null) { eglThread.requestRender(selectedTool != blurTool); @@ -1576,14 +2218,9 @@ public class PhotoFilterView extends FrameLayout { imageView = new ImageView(context); imageView.setImageResource(R.drawable.edit_doneblue); - imageView.setBackgroundResource(R.drawable.bar_selector_picker); + imageView.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_PICKER_SELECTOR_COLOR, false)); imageView.setPadding(AndroidUtilities.dp(22), AndroidUtilities.dp(1), AndroidUtilities.dp(22), 0); - frameLayout.addView(imageView); - layoutParams = (LayoutParams) imageView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.TOP | Gravity.RIGHT; - imageView.setLayoutParams(layoutParams); + frameLayout.addView(imageView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -1592,39 +2229,20 @@ public class PhotoFilterView extends FrameLayout { } }); - blurTextView = new TextView(context); - blurTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); - blurTextView.setTextColor(0xffffffff); - blurTextView.setText(LocaleController.getString("Blur", R.string.Blur)); - frameLayout.addView(blurTextView); - layoutParams = (LayoutParams) blurTextView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.WRAP_CONTENT; - layoutParams.gravity = Gravity.CENTER_HORIZONTAL; - layoutParams.topMargin = AndroidUtilities.dp(9); - blurTextView.setLayoutParams(layoutParams); + infoTextView = new TextView(context); + infoTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + infoTextView.setTextColor(0xffffffff); + frameLayout.addView(infoTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 9, 0, 0)); paramTextView = new TextView(context); paramTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 12); paramTextView.setTextColor(0xff808080); - frameLayout.addView(paramTextView); - layoutParams = (LayoutParams) paramTextView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.WRAP_CONTENT; - layoutParams.gravity = Gravity.CENTER_HORIZONTAL; - layoutParams.topMargin = AndroidUtilities.dp(26); - paramTextView.setLayoutParams(layoutParams); + frameLayout.addView(paramTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 26, 0, 0)); valueTextView = new TextView(context); valueTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); valueTextView.setTextColor(0xffffffff); - frameLayout.addView(valueTextView); - layoutParams = (LayoutParams) valueTextView.getLayoutParams(); - layoutParams.width = LayoutHelper.WRAP_CONTENT; - layoutParams.height = LayoutHelper.WRAP_CONTENT; - layoutParams.gravity = Gravity.CENTER_HORIZONTAL; - layoutParams.topMargin = AndroidUtilities.dp(3); - valueTextView.setLayoutParams(layoutParams); + frameLayout.addView(valueTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_HORIZONTAL, 0, 3, 0, 0)); valueSeekBar = new PhotoEditorSeekBar(context); valueSeekBar.setDelegate(new PhotoEditorSeekBar.PhotoEditorSeekBarDelegate() { @@ -1651,6 +2269,8 @@ public class PhotoFilterView extends FrameLayout { grainValue = progress; } else if (selectedTool == sharpenTool) { sharpenValue = progress; + } else if (selectedTool == fadeTool) { + fadeValue = progress; } updateValueTextView(); if (eglThread != null) { @@ -1658,41 +2278,116 @@ public class PhotoFilterView extends FrameLayout { } } }); - editView.addView(valueSeekBar); - layoutParams = (LayoutParams) valueSeekBar.getLayoutParams(); - layoutParams.height = AndroidUtilities.dp(60); - layoutParams.leftMargin = AndroidUtilities.dp(14); - layoutParams.rightMargin = AndroidUtilities.dp(14); - layoutParams.topMargin = AndroidUtilities.dp(10); - if (AndroidUtilities.isTablet()) { - layoutParams.width = AndroidUtilities.dp(498); - layoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; - } else { - layoutParams.width = LayoutHelper.MATCH_PARENT; - layoutParams.gravity = Gravity.LEFT | Gravity.TOP; + editView.addView(valueSeekBar, LayoutHelper.createFrame(AndroidUtilities.isTablet() ? 498 : LayoutHelper.MATCH_PARENT, 60, AndroidUtilities.isTablet() ? Gravity.CENTER_HORIZONTAL | Gravity.TOP : Gravity.LEFT | Gravity.TOP, 14, 10, 14, 0)); + + curveLayout = new FrameLayout(context); + editView.addView(curveLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 78, Gravity.CENTER_HORIZONTAL)); + + LinearLayout curveTextViewContainer = new LinearLayout(context); + curveTextViewContainer.setOrientation(LinearLayout.HORIZONTAL); + curveLayout.addView(curveTextViewContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 28, Gravity.CENTER_HORIZONTAL)); + + for (int a = 0; a < 4; a++) { + curveTextView[a] = new TextView(context); + curveTextView[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + curveTextView[a].setGravity(Gravity.CENTER_VERTICAL); + curveTextView[a].setTag(a); + if (a == 0) { + curveTextView[a].setText(LocaleController.getString("CurvesAll", R.string.CurvesAll).toUpperCase()); + } else if (a == 1) { + curveTextView[a].setText(LocaleController.getString("CurvesRed", R.string.CurvesRed).toUpperCase()); + } else if (a == 2) { + curveTextView[a].setText(LocaleController.getString("CurvesGreen", R.string.CurvesGreen).toUpperCase()); + } else if (a == 3) { + curveTextView[a].setText(LocaleController.getString("CurvesBlue", R.string.CurvesBlue).toUpperCase()); + } + curveTextView[a].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + curveTextViewContainer.addView(curveTextView[a], LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 28, a == 0 ? 0 : 30, 0, 0, 0)); + curveTextView[a].setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + int num = (Integer) v.getTag(); + for (int a = 0; a < 4; a++) { + curveTextView[a].setTextColor(a == num ? 0xffffffff : 0xff808080); + } + curvesToolValue.activeType = num; + curvesControl.invalidate(); + } + }); + } + + tintLayout = new FrameLayout(context); + editView.addView(tintLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 78, Gravity.CENTER_HORIZONTAL)); + + LinearLayout tintTextViewContainer = new LinearLayout(context); + tintTextViewContainer.setOrientation(LinearLayout.HORIZONTAL); + tintLayout.addView(tintTextViewContainer, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, 28, Gravity.CENTER_HORIZONTAL)); + + tintShadowsButton = new TextView(context); + tintShadowsButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + tintShadowsButton.setGravity(Gravity.CENTER_VERTICAL); + tintShadowsButton.setText(LocaleController.getString("TintShadows", R.string.TintShadows).toUpperCase()); + tintShadowsButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + tintTextViewContainer.addView(tintShadowsButton, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 28)); + tintShadowsButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + selectedTintMode = 0; + updateSelectedTintButton(true); + } + }); + + tintHighlightsButton = new TextView(context); + tintHighlightsButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + tintHighlightsButton.setGravity(Gravity.CENTER_VERTICAL); + tintHighlightsButton.setText(LocaleController.getString("TintHighlights", R.string.TintHighlights).toUpperCase()); + tintHighlightsButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + tintTextViewContainer.addView(tintHighlightsButton, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 28, 100, 0, 0, 0)); + tintHighlightsButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + selectedTintMode = 1; + updateSelectedTintButton(true); + } + }); + + tintButtonsContainer = new LinearLayout(context); + tintButtonsContainer.setOrientation(LinearLayout.HORIZONTAL); + tintButtonsContainer.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0); + tintLayout.addView(tintButtonsContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 50, Gravity.LEFT | Gravity.TOP, 0, 24, 0, 0)); + for (int a = 0; a < tintShadowColors.length; a++) { + RadioButton radioButton = new RadioButton(context); + radioButton.setSize(AndroidUtilities.dp(20)); + radioButton.setTag(a); + tintButtonsContainer.addView(radioButton, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f / tintShadowColors.length)); + radioButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + RadioButton radioButton = (RadioButton) v; + if (selectedTintMode == 0) { + tintShadowsColor = tintShadowColors[(Integer) radioButton.getTag()]; + } else { + tintHighlightsColor = tintHighlighsColors[(Integer) radioButton.getTag()]; + } + updateSelectedTintButton(true); + if (eglThread != null) { + eglThread.requestRender(false); + } + } + }); } - valueSeekBar.setLayoutParams(layoutParams); blurLayout = new FrameLayout(context); - editView.addView(blurLayout); - layoutParams = (LayoutParams) blurLayout.getLayoutParams(); - layoutParams.width = AndroidUtilities.dp(280); - layoutParams.height = AndroidUtilities.dp(60); - layoutParams.topMargin = AndroidUtilities.dp(10); - layoutParams.gravity = Gravity.CENTER_HORIZONTAL; - blurLayout.setLayoutParams(layoutParams); + editView.addView(blurLayout, LayoutHelper.createFrame(280, 60, Gravity.CENTER_HORIZONTAL, 0, 10, 0, 0)); blurOffButton = new TextView(context); blurOffButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.blur_off_active, 0, 0); + blurOffButton.setCompoundDrawablePadding(AndroidUtilities.dp(2)); blurOffButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); blurOffButton.setTextColor(0xff51bdf3); blurOffButton.setGravity(Gravity.CENTER_HORIZONTAL); blurOffButton.setText(LocaleController.getString("BlurOff", R.string.BlurOff)); - blurLayout.addView(blurOffButton); - layoutParams = (LayoutParams) blurOffButton.getLayoutParams(); - layoutParams.width = AndroidUtilities.dp(80); - layoutParams.height = AndroidUtilities.dp(60); - blurOffButton.setLayoutParams(layoutParams); + blurLayout.addView(blurOffButton, LayoutHelper.createFrame(80, 60)); blurOffButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -1707,16 +2402,12 @@ public class PhotoFilterView extends FrameLayout { blurRadialButton = new TextView(context); blurRadialButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.blur_radial, 0, 0); + blurRadialButton.setCompoundDrawablePadding(AndroidUtilities.dp(2)); blurRadialButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); blurRadialButton.setTextColor(0xffffffff); blurRadialButton.setGravity(Gravity.CENTER_HORIZONTAL); blurRadialButton.setText(LocaleController.getString("BlurRadial", R.string.BlurRadial)); - blurLayout.addView(blurRadialButton); - layoutParams = (LayoutParams) blurRadialButton.getLayoutParams(); - layoutParams.width = AndroidUtilities.dp(80); - layoutParams.height = AndroidUtilities.dp(60); - layoutParams.leftMargin = AndroidUtilities.dp(100); - blurRadialButton.setLayoutParams(layoutParams); + blurLayout.addView(blurRadialButton, LayoutHelper.createFrame(80, 80, Gravity.LEFT | Gravity.TOP, 100, 0, 0, 0)); blurRadialButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -1732,16 +2423,12 @@ public class PhotoFilterView extends FrameLayout { blurLinearButton = new TextView(context); blurLinearButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.blur_linear, 0, 0); + blurLinearButton.setCompoundDrawablePadding(AndroidUtilities.dp(2)); blurLinearButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); blurLinearButton.setTextColor(0xffffffff); blurLinearButton.setGravity(Gravity.CENTER_HORIZONTAL); blurLinearButton.setText(LocaleController.getString("BlurLinear", R.string.BlurLinear)); - blurLayout.addView(blurLinearButton); - layoutParams = (LayoutParams) blurLinearButton.getLayoutParams(); - layoutParams.width = AndroidUtilities.dp(80); - layoutParams.height = AndroidUtilities.dp(60); - layoutParams.leftMargin = AndroidUtilities.dp(200); - blurLinearButton.setLayoutParams(layoutParams); + blurLayout.addView(blurLinearButton, LayoutHelper.createFrame(80, 80, Gravity.LEFT | Gravity.TOP, 200, 0, 0, 0)); blurLinearButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -1781,6 +2468,23 @@ public class PhotoFilterView extends FrameLayout { } } + private void updateSelectedTintButton(boolean animated) { + tintHighlightsButton.setTextColor(selectedTintMode == 1 ? 0xffffffff : 0xff808080); + tintShadowsButton.setTextColor(selectedTintMode == 1 ? 0xff808080 : 0xffffffff); + int childCount = tintButtonsContainer.getChildCount(); + for (int a = 0; a < childCount; a++) { + View child = tintButtonsContainer.getChildAt(a); + if (child instanceof RadioButton) { + RadioButton radioButton = (RadioButton) child; + int num = (Integer) radioButton.getTag(); + int color1 = selectedTintMode == 0 ? tintShadowsColor : tintHighlightsColor; + int color2 = selectedTintMode == 0 ? tintShadowColors[num] : tintHighlighsColors[num]; + radioButton.setChecked(color1 == color2, animated); + radioButton.setColor(num == 0 ? 0xffffffff : (selectedTintMode == 0 ? tintShadowColors[num] : tintHighlighsColors[num]), num == 0 ? 0xffffffff : (selectedTintMode == 0 ? tintShadowColors[num] : tintHighlighsColors[num])); + } + } + } + private void updateValueTextView() { int value = 0; if (selectedTool == enhanceTool) { @@ -1803,6 +2507,8 @@ public class PhotoFilterView extends FrameLayout { value = (int) grainValue; } else if (selectedTool == sharpenTool) { value = (int) sharpenValue; + } else if (selectedTool == fadeTool) { + value = (int) fadeValue; } if (value > 0) { valueTextView.setText("+" + value); @@ -1813,7 +2519,7 @@ public class PhotoFilterView extends FrameLayout { public boolean hasChanges() { return enhanceValue != 0 || contrastValue != 0 || highlightsValue != 0 || exposureValue != 0 || warmthValue != 0 || saturationValue != 0 || vignetteValue != 0 || - shadowsValue != 0 || grainValue != 0 || sharpenValue != 0; + shadowsValue != 0 || grainValue != 0 || sharpenValue != 0 || fadeValue != 0 || tintHighlightsColor != 0 || tintShadowsColor != 0 || !curvesToolValue.shouldBeSkipped(); } public void onTouch(MotionEvent event) { @@ -1844,29 +2550,49 @@ public class PhotoFilterView extends FrameLayout { viewFrom = toolsView; viewTo = editView; - if (selectedTool == blurTool) { - blurLayout.setVisibility(VISIBLE); + if (selectedTool == blurTool || selectedTool == tintTool || selectedTool == curvesTool) { + blurLayout.setVisibility(selectedTool == blurTool ? VISIBLE : INVISIBLE); + tintLayout.setVisibility(selectedTool == tintTool ? VISIBLE : INVISIBLE); + curveLayout.setVisibility(selectedTool == curvesTool ? VISIBLE : INVISIBLE); + if (selectedTool == blurTool) { + infoTextView.setText(LocaleController.getString("Blur", R.string.Blur)); + if (blurType != 0) { + blurControl.setVisibility(VISIBLE); + } + } else if (selectedTool == curvesTool) { + infoTextView.setText(LocaleController.getString("Curves", R.string.Curves)); + curvesControl.setVisibility(VISIBLE); + curvesToolValue.activeType = 0; + for (int a = 0; a < 4; a++) { + curveTextView[a].setTextColor(a == 0 ? 0xffffffff : 0xff808080); + } + } else { + selectedTintMode = 0; + updateSelectedTintButton(false); + infoTextView.setText(LocaleController.getString("Tint", R.string.Tint)); + } + infoTextView.setVisibility(VISIBLE); valueSeekBar.setVisibility(INVISIBLE); - blurTextView.setVisibility(VISIBLE); paramTextView.setVisibility(INVISIBLE); valueTextView.setVisibility(INVISIBLE); - if (blurType != 0) { - blurControl.setVisibility(VISIBLE); - } updateSelectedBlurType(); } else { + tintLayout.setVisibility(INVISIBLE); + curveLayout.setVisibility(INVISIBLE); blurLayout.setVisibility(INVISIBLE); valueSeekBar.setVisibility(VISIBLE); - blurTextView.setVisibility(INVISIBLE); + infoTextView.setVisibility(INVISIBLE); paramTextView.setVisibility(VISIBLE); valueTextView.setVisibility(VISIBLE); blurControl.setVisibility(INVISIBLE); + curvesControl.setVisibility(INVISIBLE); } } else { selectedTool = -1; viewFrom = editView; viewTo = toolsView; blurControl.setVisibility(INVISIBLE); + curvesControl.setVisibility(INVISIBLE); } AnimatorSetProxy animatorSet = new AnimatorSetProxy(); @@ -1928,7 +2654,7 @@ public class PhotoFilterView extends FrameLayout { float bitmapW; float bitmapH; - if (orientation == 90 || orientation == 270) { + if (orientation % 360 == 90 || orientation % 360 == 270) { bitmapW = bitmapToEdit.getHeight(); bitmapH = bitmapToEdit.getWidth(); } else { @@ -1954,12 +2680,17 @@ public class PhotoFilterView extends FrameLayout { layoutParams.width = (int) bitmapW; layoutParams.height = (int) bitmapH; textureView.setLayoutParams(layoutParams); + curvesControl.setActualArea(bitmapX, bitmapY, layoutParams.width, layoutParams.height); blurControl.setActualAreaSize(layoutParams.width, layoutParams.height); layoutParams = (LayoutParams) blurControl.getLayoutParams(); layoutParams.height = viewHeight + AndroidUtilities.dp(28); blurControl.setLayoutParams(layoutParams); + layoutParams = (LayoutParams) curvesControl.getLayoutParams(); + layoutParams.height = viewHeight + AndroidUtilities.dp(28); + curvesControl.setLayoutParams(layoutParams); + if (AndroidUtilities.isTablet()) { int total = AndroidUtilities.dp(86) * 10; layoutParams = (FrameLayout.LayoutParams) recyclerListView.getLayoutParams(); @@ -1981,11 +2712,11 @@ public class PhotoFilterView extends FrameLayout { } private float getShadowsValue() { - return (shadowsValue / 100.0f) * 0.65f; + return (shadowsValue * 0.55f + 100.0f) / 100.0f; } private float getHighlightsValue() { - return 1 - (highlightsValue / 100.0f); + return (highlightsValue * 0.75f + 100.0f) / 100.0f; } private float getEnhanceValue() { @@ -2016,6 +2747,20 @@ public class PhotoFilterView extends FrameLayout { return grainValue / 100.0f * 0.04f; } + private float getFadeValue() { + return fadeValue / 100.0f; + } + + private float getTintHighlightsIntensityValue() { + float tintHighlightsIntensity = 50.0f; + return tintHighlightsColor == 0 ? 0 : tintHighlightsIntensity / 100.0f; + } + + private float getTintShadowsIntensityValue() { + float tintShadowsIntensity = 50.0f; + return tintShadowsColor == 0 ? 0 : tintShadowsIntensity / 100.0f; + } + private float getSaturationValue() { float parameterValue = (saturationValue / 100.0f); if (parameterValue > 0) { @@ -2078,7 +2823,7 @@ public class PhotoFilterView extends FrameLayout { @Override public int getItemCount() { - return 11; + return 14; } @Override @@ -2115,6 +2860,12 @@ public class PhotoFilterView extends FrameLayout { ((PhotoEditToolCell) holder.itemView).setIconAndTextAndValue(R.drawable.tool_grain, LocaleController.getString("Grain", R.string.Grain), grainValue); } else if (i == sharpenTool) { ((PhotoEditToolCell) holder.itemView).setIconAndTextAndValue(R.drawable.tool_details, LocaleController.getString("Sharpen", R.string.Sharpen), sharpenValue); + } else if (i == tintTool) { + ((PhotoEditToolCell) holder.itemView).setIconAndTextAndValue(R.drawable.tool_tint, LocaleController.getString("Tint", R.string.Tint), tintHighlightsColor != 0 || tintShadowsColor != 0 ? "◆" : ""); + } else if (i == fadeTool) { + ((PhotoEditToolCell) holder.itemView).setIconAndTextAndValue(R.drawable.tool_fade, LocaleController.getString("Fade", R.string.Fade), fadeValue); + } else if (i == curvesTool) { + ((PhotoEditToolCell) holder.itemView).setIconAndTextAndValue(R.drawable.tool_curve, LocaleController.getString("Curves", R.string.Curves), curvesToolValue.shouldBeSkipped() ? "" : "◆"); } else if (i == blurTool) { String value = ""; if (blurType == 1) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java index 87532d29..3da5c1ac 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PhotoViewerCaptionEnterView.java @@ -9,20 +9,23 @@ package org.telegram.ui.Components; import android.content.Context; +import android.os.Build; import android.text.Editable; import android.text.InputFilter; import android.text.TextWatcher; import android.text.style.ImageSpan; import android.util.TypedValue; +import android.view.ActionMode; import android.view.Gravity; import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.view.inputmethod.EditorInfo; import android.widget.EditText; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.Emoji; @@ -35,6 +38,9 @@ import org.telegram.tgnet.TLRPC; import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + public class PhotoViewerCaptionEnterView extends FrameLayoutFixed implements NotificationCenter.NotificationCenterDelegate, SizeNotifierFrameLayoutPhoto.SizeNotifierFrameLayoutPhotoDelegate { public interface PhotoViewerCaptionEnterViewDelegate { @@ -48,6 +54,8 @@ public class PhotoViewerCaptionEnterView extends FrameLayoutFixed implements Not private EmojiView emojiView; private SizeNotifierFrameLayoutPhoto sizeNotifierLayout; + private ActionMode currentActionMode; + private AnimatorSetProxy runningAnimation; private AnimatorSetProxy runningAnimation2; private ObjectAnimatorProxy runningAnimationAudio; @@ -66,11 +74,14 @@ public class PhotoViewerCaptionEnterView extends FrameLayoutFixed implements Not private PhotoViewerCaptionEnterViewDelegate delegate; - public PhotoViewerCaptionEnterView(Context context, SizeNotifierFrameLayoutPhoto parent) { + private View windowView; + + public PhotoViewerCaptionEnterView(Context context, SizeNotifierFrameLayoutPhoto parent, final View window) { super(context); setBackgroundColor(0x7f000000); setFocusable(true); setFocusableInTouchMode(true); + windowView = window; sizeNotifierLayout = parent; @@ -98,9 +109,66 @@ public class PhotoViewerCaptionEnterView extends FrameLayoutFixed implements Not }); messageEditText = new EditText(context); + if (Build.VERSION.SDK_INT >= 23) { + messageEditText.setCustomSelectionActionModeCallback(new ActionMode.Callback() { + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + currentActionMode = mode; + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + if (Build.VERSION.SDK_INT >= 23) { + fixActionMode(mode); + } + return true; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + return false; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + if (currentActionMode == mode) { + currentActionMode = null; + } + } + }); + + messageEditText.setCustomInsertionActionModeCallback(new ActionMode.Callback() { + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + currentActionMode = mode; + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + if (Build.VERSION.SDK_INT >= 23) { + fixActionMode(mode); + } + return true; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + return false; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + if (currentActionMode == mode) { + currentActionMode = null; + } + } + }); + } messageEditText.setHint(LocaleController.getString("AddCaption", R.string.AddCaption)); - messageEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI | EditorInfo.IME_ACTION_DONE); - messageEditText.setInputType(EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES | EditorInfo.TYPE_CLASS_TEXT); + messageEditText.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); + messageEditText.setInputType(messageEditText.getInputType() | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES); messageEditText.setMaxLines(4); messageEditText.setHorizontallyScrolling(false); messageEditText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); @@ -111,20 +179,21 @@ public class PhotoViewerCaptionEnterView extends FrameLayoutFixed implements Not messageEditText.setTextColor(0xffffffff); messageEditText.setHintTextColor(0xb2ffffff); InputFilter[] inputFilters = new InputFilter[1]; - inputFilters[0] = new InputFilter.LengthFilter(140); + inputFilters[0] = new InputFilter.LengthFilter(200); messageEditText.setFilters(inputFilters); frameLayout.addView(messageEditText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 52, 0, 6, 0)); messageEditText.setOnKeyListener(new OnKeyListener() { @Override public boolean onKey(View view, int i, KeyEvent keyEvent) { - if (i == KeyEvent.KEYCODE_BACK && !keyboardVisible && isPopupShowing()) { - if (keyEvent.getAction() == 1) { - showPopup(0); + if (i == KeyEvent.KEYCODE_BACK) { + if (hideActionMode()) { + return true; + } else if (!keyboardVisible && isPopupShowing()) { + if (keyEvent.getAction() == 1) { + showPopup(0); + } + return true; } - return true; - } else if (i == KeyEvent.KEYCODE_ENTER && keyEvent.getAction() == KeyEvent.ACTION_DOWN) { - delegate.onCaptionEnter(); - return true; } return false; } @@ -137,19 +206,20 @@ public class PhotoViewerCaptionEnterView extends FrameLayoutFixed implements Not } } }); - messageEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { + /*messageEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { if (i == EditorInfo.IME_ACTION_DONE || i == EditorInfo.IME_ACTION_NEXT) { delegate.onCaptionEnter(); return true; - } else if (keyEvent != null && i == EditorInfo.IME_NULL && keyEvent.getAction() == KeyEvent.ACTION_DOWN) { + } else + if (keyEvent != null && i == EditorInfo.IME_NULL && keyEvent.getAction() == KeyEvent.ACTION_DOWN) { delegate.onCaptionEnter(); return true; } return false; } - }); + });*/ messageEditText.addTextChangedListener(new TextWatcher() { boolean processChange = false; @@ -190,6 +260,47 @@ public class PhotoViewerCaptionEnterView extends FrameLayoutFixed implements Not }); } + public boolean hideActionMode() { + if (Build.VERSION.SDK_INT >= 23 && currentActionMode != null) { + currentActionMode.finish(); + currentActionMode = null; + return true; + } + return false; + } + + @SuppressWarnings("unchecked") + private void fixActionMode(ActionMode mode) { + try { + Class classActionMode = Class.forName("com.android.internal.view.FloatingActionMode"); + Field fieldToolbar = classActionMode.getDeclaredField("mFloatingToolbar"); + fieldToolbar.setAccessible(true); + Object toolbar = fieldToolbar.get(mode); + + Class classToolbar = Class.forName("com.android.internal.widget.FloatingToolbar"); + Field fieldToolbarPopup = classToolbar.getDeclaredField("mPopup"); + Field fieldToolbarWidth = classToolbar.getDeclaredField("mWidthChanged"); + fieldToolbarPopup.setAccessible(true); + fieldToolbarWidth.setAccessible(true); + Object popup = fieldToolbarPopup.get(toolbar); + + Class classToolbarPopup = Class.forName("com.android.internal.widget.FloatingToolbar$FloatingToolbarPopup"); + Field fieldToolbarPopupParent = classToolbarPopup.getDeclaredField("mParent"); + fieldToolbarPopupParent.setAccessible(true); + + View currentView = (View) fieldToolbarPopupParent.get(popup); + if (currentView != windowView) { + fieldToolbarPopupParent.set(popup, windowView); + + Method method = classActionMode.getDeclaredMethod("updateViewLocationInWindow"); + method.setAccessible(true); + method.invoke(mode); + } + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + private void onWindowSizeChanged() { int size = sizeNotifierLayout.getHeight(); if (!keyboardVisible) { @@ -346,6 +457,11 @@ public class PhotoViewerCaptionEnterView extends FrameLayoutFixed implements Not public void onStickersTab(boolean opened) { } + + @Override + public void onClearEmojiRecent() { + + } }); sizeNotifierLayout.addView(emojiView); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PickerBottomLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PickerBottomLayout.java new file mode 100644 index 00000000..8aaf358f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PickerBottomLayout.java @@ -0,0 +1,100 @@ +/* + * This is the source code of Telegram for Android v. 2.0.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; + +public class PickerBottomLayout extends FrameLayout { + + public LinearLayout doneButton; + public TextView cancelButton; + public TextView doneButtonTextView; + public TextView doneButtonBadgeTextView; + + private boolean isDarkTheme; + + public PickerBottomLayout(Context context) { + this(context, true); + } + + public PickerBottomLayout(Context context, boolean darkTheme) { + super(context); + isDarkTheme = darkTheme; + + setBackgroundColor(isDarkTheme ? 0xff1a1a1a : 0xffffffff); + + cancelButton = new TextView(context); + cancelButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + cancelButton.setTextColor(isDarkTheme ? 0xffffffff : 0xff19a7e8); + cancelButton.setGravity(Gravity.CENTER); + cancelButton.setBackgroundDrawable(Theme.createBarSelectorDrawable(isDarkTheme ? Theme.ACTION_BAR_PICKER_SELECTOR_COLOR : Theme.ACTION_BAR_AUDIO_SELECTOR_COLOR, false)); + cancelButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); + cancelButton.setText(LocaleController.getString("Cancel", R.string.Cancel).toUpperCase()); + cancelButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + addView(cancelButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); + + doneButton = new LinearLayout(context); + doneButton.setOrientation(LinearLayout.HORIZONTAL); + doneButton.setBackgroundDrawable(Theme.createBarSelectorDrawable(isDarkTheme ? Theme.ACTION_BAR_PICKER_SELECTOR_COLOR : Theme.ACTION_BAR_AUDIO_SELECTOR_COLOR, false)); + doneButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); + addView(doneButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); + + doneButtonBadgeTextView = new TextView(context); + doneButtonBadgeTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + doneButtonBadgeTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + doneButtonBadgeTextView.setTextColor(0xffffffff); + doneButtonBadgeTextView.setGravity(Gravity.CENTER); + doneButtonBadgeTextView.setBackgroundResource(isDarkTheme ? R.drawable.photobadge : R.drawable.bluecounter); + doneButtonBadgeTextView.setMinWidth(AndroidUtilities.dp(23)); + doneButtonBadgeTextView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), AndroidUtilities.dp(1)); + doneButton.addView(doneButtonBadgeTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 23, Gravity.CENTER_VERTICAL, 0, 0, 10, 0)); + + doneButtonTextView = new TextView(context); + doneButtonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + doneButtonTextView.setTextColor(isDarkTheme ? 0xffffffff : 0xff19a7e8); + doneButtonTextView.setGravity(Gravity.CENTER); + doneButtonTextView.setCompoundDrawablePadding(AndroidUtilities.dp(8)); + doneButtonTextView.setText(LocaleController.getString("Send", R.string.Send).toUpperCase()); + doneButtonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + doneButton.addView(doneButtonTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); + } + + public void updateSelectedCount(int count, boolean disable) { + if (count == 0) { + doneButtonBadgeTextView.setVisibility(View.GONE); + + if (disable) { + doneButtonTextView.setTextColor(0xff999999); + doneButton.setEnabled(false); + } else { + doneButtonTextView.setTextColor(isDarkTheme ? 0xffffffff : 0xff19a7e8); + } + } else { + doneButtonTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + doneButtonBadgeTextView.setVisibility(View.VISIBLE); + doneButtonBadgeTextView.setText(String.format("%d", count)); + + doneButtonTextView.setTextColor(isDarkTheme ? 0xffffffff : 0xff19a7e8); + if (disable) { + doneButton.setEnabled(true); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PlayerView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PlayerView.java new file mode 100644 index 00000000..f390cae0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PlayerView.java @@ -0,0 +1,310 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Canvas; +import android.graphics.PorterDuff; +import android.os.Build; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.AnimationCompat.AnimatorListenerAdapterProxy; +import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; +import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; +import org.telegram.messenger.AnimationCompat.ViewProxy; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.AudioPlayerActivity; +import org.telegram.ui.ChatActivity; +import org.telegram.ui.DialogsActivity; + +public class PlayerView extends FrameLayout implements NotificationCenter.NotificationCenterDelegate { + + private ImageView playButton; + private TextView titleTextView; + private MessageObject lastMessageObject; + private AnimatorSetProxy animatorSet; + private float yPosition; + private BaseFragment fragment; + private float topPadding; + private boolean visible; + + private int titleColor = Theme.INAPP_PLAYER_TITLE_TEXT_COLOR; + + public PlayerView(Context context, BaseFragment parentFragment) { + super(context); + + fragment = parentFragment; + visible = true; + ((ViewGroup) fragment.getFragmentView()).setClipToPadding(false); + + setTag(1); + FrameLayout frameLayout = new FrameLayout(context); + frameLayout.setBackgroundColor(Theme.INAPP_PLAYER_BACKGROUND_COLOR); + addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 0)); + + View shadow = new View(context); + shadow.setBackgroundResource(R.drawable.header_shadow); + addView(shadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 3, Gravity.LEFT | Gravity.TOP, 0, 36, 0, 0)); + + playButton = new ImageView(context); + playButton.setScaleType(ImageView.ScaleType.CENTER); + addView(playButton, LayoutHelper.createFrame(36, 36, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 0)); + playButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (MediaController.getInstance().isAudioPaused()) { + MediaController.getInstance().playAudio(MediaController.getInstance().getPlayingMessageObject()); + } else { + MediaController.getInstance().pauseAudio(MediaController.getInstance().getPlayingMessageObject()); + } + } + }); + paintPlayer(); + titleTextView = new TextView(context); + //titleTextView.setTextColor(Theme.INAPP_PLAYER_TITLE_TEXT_COLOR); + titleTextView.setTextColor(titleColor); + titleTextView.setMaxLines(1); + titleTextView.setLines(1); + titleTextView.setSingleLine(true); + titleTextView.setEllipsize(TextUtils.TruncateAt.END); + titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + titleTextView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); + addView(titleTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 36, Gravity.LEFT | Gravity.TOP, 35, 0, 36, 0)); + + ImageView closeButton = new ImageView(context); + closeButton.setImageResource(R.drawable.miniplayer_close); + closeButton.setScaleType(ImageView.ScaleType.CENTER); + addView(closeButton, LayoutHelper.createFrame(36, 36, Gravity.RIGHT | Gravity.TOP)); + closeButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + MediaController.getInstance().cleanupPlayer(true, true); + } + }); + + setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); + if (messageObject != null && messageObject.isMusic() && fragment != null) { + fragment.presentFragment(new AudioPlayerActivity()); + } + } + }); + } + + public float getTopPadding() { + return topPadding; + } + + public void setTopPadding(float value) { + topPadding = value; + if (fragment != null) { + View view = fragment.getFragmentView(); + if (view != null) { + view.setPadding(0, (int) topPadding, 0, 0); + } + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + topPadding = 0; + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioDidReset); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioPlayStateChanged); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.audioDidStarted); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioDidReset); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioPlayStateChanged); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.audioDidStarted); + checkPlayer(true); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, AndroidUtilities.dp(39)); + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.audioDidStarted || id == NotificationCenter.audioPlayStateChanged || id == NotificationCenter.audioDidReset) { + checkPlayer(false); + } + } + + private void checkPlayer(boolean create) { + MessageObject messageObject = MediaController.getInstance().getPlayingMessageObject(); + View fragmentView = fragment.getFragmentView(); + if (!create && fragmentView != null) { + if (fragmentView.getParent() == null || ((View) fragmentView.getParent()).getVisibility() != VISIBLE) { + create = true; + } + } + if (messageObject == null || messageObject.getId() == 0/* || !messageObject.isMusic()*/) { + lastMessageObject = null; + if (visible) { + visible = false; + if (create) { + clearAnimation(); + if (getVisibility() != GONE) { + setVisibility(GONE); + } + setTopPadding(0); + } else { + if (animatorSet != null) { + animatorSet.cancel(); + animatorSet = null; + } + animatorSet = new AnimatorSetProxy(); + animatorSet.playTogether(ObjectAnimatorProxy.ofFloat(this, "translationY", -AndroidUtilities.dp(36)), + ObjectAnimatorProxy.ofFloat(this, "topPadding", 0)); + animatorSet.setDuration(200); + animatorSet.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if (animatorSet != null && animatorSet.equals(animation)) { + clearAnimation(); + setVisibility(GONE); + animatorSet = null; + } + } + }); + animatorSet.start(); + } + } + } else { + if (create && topPadding == 0) { + setTopPadding(AndroidUtilities.dp(36)); + ViewProxy.setTranslationY(this, 0); + yPosition = 0; + } + if (!visible) { + if (!create) { + if (animatorSet != null) { + animatorSet.cancel(); + animatorSet = null; + } + animatorSet = new AnimatorSetProxy(); + animatorSet.playTogether(ObjectAnimatorProxy.ofFloat(this, "translationY", -AndroidUtilities.dp(36), 0), + ObjectAnimatorProxy.ofFloat(this, "topPadding", AndroidUtilities.dp(36))); + animatorSet.setDuration(200); + animatorSet.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if (animatorSet != null && animatorSet.equals(animation)) { + animatorSet = null; + } + } + }); + animatorSet.start(); + } + visible = true; + setVisibility(VISIBLE); + } + if (MediaController.getInstance().isAudioPaused()) { + playButton.setImageResource(R.drawable.miniplayer_play); + } else { + playButton.setImageResource(R.drawable.miniplayer_pause); + } + if (lastMessageObject != messageObject) { + lastMessageObject = messageObject; + SpannableStringBuilder stringBuilder; + if (lastMessageObject.isVoice()) { + stringBuilder = new SpannableStringBuilder(String.format("%s %s", messageObject.getMusicAuthor(), messageObject.getMusicTitle())); + titleTextView.setEllipsize(TextUtils.TruncateAt.MIDDLE); + } else { + stringBuilder = new SpannableStringBuilder(String.format("%s - %s", messageObject.getMusicAuthor(), messageObject.getMusicTitle())); + titleTextView.setEllipsize(TextUtils.TruncateAt.END); + } + //TypefaceSpan span = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, Theme.INAPP_PLAYER_PERFORMER_TEXT_COLOR); + TypefaceSpan span = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf"), 0, titleColor); + stringBuilder.setSpan(span, 0, messageObject.getMusicAuthor().length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + titleTextView.setText(stringBuilder); + } + } + } + + @Override + public void setTranslationY(float translationY) { + super.setTranslationY(translationY); + yPosition = translationY; + invalidate(); + } + + private void paintPlayer(){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int hColor = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + int iconColor = 0xffffffff; + int tColor = 0xffffffff; + if(fragment instanceof DialogsActivity){ + hColor = themePrefs.getInt("chatsHeaderColor", hColor); + iconColor = themePrefs.getInt("chatsHeaderIconsColor", iconColor); + tColor = themePrefs.getInt("chatsHeaderTitleColor", tColor); + } else if(fragment instanceof ChatActivity){ + hColor = themePrefs.getInt("chatHeaderColor", hColor); + iconColor = themePrefs.getInt("chatHeaderIconsColor", iconColor); + tColor = themePrefs.getInt("chatNameColor", tColor); + } + setBackgroundColor(0x00000000); + if(getChildAt(0) != null){ + getChildAt(0).setBackgroundColor(hColor); + } + + if(titleColor != tColor){ + titleColor = tColor; + if(titleTextView != null){ + titleTextView.setTextColor(tColor); + } + } + + playButton.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + if(getChildAt(4) != null){ + ((ImageView)getChildAt(4)).setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + } + } + + @Override + protected boolean drawChild(Canvas canvas, View child, long drawingTime) { + int restoreToCount = 0; + if (Build.VERSION.SDK_INT >= 11) { + restoreToCount = canvas.save(); + if (yPosition < 0) { + canvas.clipRect(0, (int) -yPosition, child.getMeasuredWidth(), AndroidUtilities.dp(39)); + } + } + final boolean result = super.drawChild(canvas, child, drawingTime); + if (Build.VERSION.SDK_INT >= 11) { + canvas.restoreToCount(restoreToCount); + } + paintPlayer(); + return result; + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupAudioView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupAudioView.java index 7f6be166..a6a40c03 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupAudioView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/PopupAudioView.java @@ -24,6 +24,8 @@ import org.telegram.messenger.MessagesController; import org.telegram.messenger.FileLoader; import org.telegram.messenger.R; import org.telegram.messenger.MessageObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.BaseCell; import java.io.File; @@ -59,23 +61,23 @@ public class PopupAudioView extends BaseCell implements SeekBar.SeekBarDelegate, super(context); if (backgroundMediaDrawableIn == null) { backgroundMediaDrawableIn = getResources().getDrawable(R.drawable.msg_in_photo); - statesDrawable[0][0] = getResources().getDrawable(R.drawable.play_w2); - statesDrawable[0][1] = getResources().getDrawable(R.drawable.play_w2_pressed); - statesDrawable[1][0] = getResources().getDrawable(R.drawable.pause_w2); - statesDrawable[1][1] = getResources().getDrawable(R.drawable.pause_w2_pressed); - statesDrawable[2][0] = getResources().getDrawable(R.drawable.download_g); - statesDrawable[2][1] = getResources().getDrawable(R.drawable.download_g_pressed); - statesDrawable[3][0] = getResources().getDrawable(R.drawable.pause_g); - statesDrawable[3][1] = getResources().getDrawable(R.drawable.pause_g_pressed); + statesDrawable[0][0] = getResources().getDrawable(R.drawable.play_g); + statesDrawable[0][1] = getResources().getDrawable(R.drawable.play_g_s); + statesDrawable[1][0] = getResources().getDrawable(R.drawable.pause_g); + statesDrawable[1][1] = getResources().getDrawable(R.drawable.pause_g_s); + statesDrawable[2][0] = getResources().getDrawable(R.drawable.file_g_load); + statesDrawable[2][1] = getResources().getDrawable(R.drawable.file_g_load_s); + statesDrawable[3][0] = getResources().getDrawable(R.drawable.file_g_cancel); + statesDrawable[3][1] = getResources().getDrawable(R.drawable.file_g_cancel_s); - statesDrawable[4][0] = getResources().getDrawable(R.drawable.play_w); - statesDrawable[4][1] = getResources().getDrawable(R.drawable.play_w_pressed); - statesDrawable[5][0] = getResources().getDrawable(R.drawable.pause_w); - statesDrawable[5][1] = getResources().getDrawable(R.drawable.pause_w_pressed); - statesDrawable[6][0] = getResources().getDrawable(R.drawable.download_b); - statesDrawable[6][1] = getResources().getDrawable(R.drawable.download_b_pressed); - statesDrawable[7][0] = getResources().getDrawable(R.drawable.pause_b); - statesDrawable[7][1] = getResources().getDrawable(R.drawable.pause_b_pressed); + statesDrawable[4][0] = getResources().getDrawable(R.drawable.play_b); + statesDrawable[4][1] = getResources().getDrawable(R.drawable.play_b_s); + statesDrawable[5][0] = getResources().getDrawable(R.drawable.pause_b); + statesDrawable[5][1] = getResources().getDrawable(R.drawable.pause_b_s); + statesDrawable[6][0] = getResources().getDrawable(R.drawable.file_b_load); + statesDrawable[6][1] = getResources().getDrawable(R.drawable.file_b_load_s); + statesDrawable[7][0] = getResources().getDrawable(R.drawable.file_b_cancel); + statesDrawable[7][1] = getResources().getDrawable(R.drawable.file_b_cancel_s); timePaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG); timePaint.setTextSize(AndroidUtilities.dp(16)); @@ -84,13 +86,13 @@ public class PopupAudioView extends BaseCell implements SeekBar.SeekBarDelegate, TAG = MediaController.getInstance().generateObserverTag(); seekBar = new SeekBar(getContext()); - seekBar.delegate = this; + seekBar.setDelegate(this); progressView = new ProgressView(); } public void setMessageObject(MessageObject messageObject) { if (currentMessageObject != messageObject) { - seekBar.type = 1; + seekBar.setColors(Theme.MSG_IN_AUDIO_SEEKBAR_COLOR, Theme.MSG_IN_AUDIO_SEEKBAR_FILL_COLOR, Theme.MSG_IN_AUDIO_SEEKBAR_SELECTED_COLOR); progressView.setProgressColors(0xffd9e2eb, 0xff86c5f8); currentMessageObject = messageObject; @@ -122,8 +124,7 @@ public class PopupAudioView extends BaseCell implements SeekBar.SeekBarDelegate, buttonX = AndroidUtilities.dp(10); timeX = getMeasuredWidth() - timeWidth - AndroidUtilities.dp(16); - seekBar.width = getMeasuredWidth() - AndroidUtilities.dp(70) - timeWidth; - seekBar.height = AndroidUtilities.dp(30); + seekBar.setSize(getMeasuredWidth() - AndroidUtilities.dp(70) - timeWidth, AndroidUtilities.dp(30)); progressView.width = getMeasuredWidth() - AndroidUtilities.dp(94) - timeWidth; progressView.height = AndroidUtilities.dp(30); seekBarY = AndroidUtilities.dp(13); @@ -232,7 +233,7 @@ public class PopupAudioView extends BaseCell implements SeekBar.SeekBarDelegate, boolean result = MediaController.getInstance().playAudio(currentMessageObject); if (!currentMessageObject.isOut() && currentMessageObject.isContentUnread()) { if (currentMessageObject.messageOwner.to_id.channel_id == 0) { - MessagesController.getInstance().markMessageContentAsRead(currentMessageObject.messageOwner); + MessagesController.getInstance().markMessageContentAsRead(currentMessageObject); currentMessageObject.setContentIsRead(); } } @@ -247,11 +248,11 @@ public class PopupAudioView extends BaseCell implements SeekBar.SeekBarDelegate, invalidate(); } } else if (buttonState == 2) { - FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.audio, true); + FileLoader.getInstance().loadFile(currentMessageObject.getDocument(), true, false); buttonState = 3; invalidate(); } else if (buttonState == 3) { - FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.audio); + FileLoader.getInstance().cancelLoadFile(currentMessageObject.getDocument()); buttonState = 2; invalidate(); } @@ -266,9 +267,15 @@ public class PopupAudioView extends BaseCell implements SeekBar.SeekBarDelegate, seekBar.setProgress(currentMessageObject.audioProgress); } - int duration; + int duration = 0; if (!MediaController.getInstance().isPlayingAudio(currentMessageObject)) { - duration = currentMessageObject.messageOwner.media.audio.duration; + for (int a = 0; a < currentMessageObject.getDocument().attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = currentMessageObject.getDocument().attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + duration = attribute.duration; + break; + } + } } else { duration = currentMessageObject.audioProgressSec; } @@ -282,7 +289,7 @@ public class PopupAudioView extends BaseCell implements SeekBar.SeekBarDelegate, public void downloadAudioIfNeed() { if (buttonState == 2) { - FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.audio, true); + FileLoader.getInstance().loadFile(currentMessageObject.getDocument(), true, false); buttonState = 3; invalidate(); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress.java index 4064d443..40a7061f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RadialProgress.java @@ -12,16 +12,14 @@ import android.content.SharedPreferences; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; -import android.graphics.PorterDuff; import android.graphics.RectF; import android.graphics.drawable.Drawable; -import android.util.Log; import android.view.View; import android.view.animation.DecelerateInterpolator; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.FileLog; +import org.telegram.ui.ActionBar.Theme; public class RadialProgress { @@ -33,7 +31,7 @@ public class RadialProgress { private float animatedProgressValue = 0; private RectF progressRect = new RectF(); private RectF cicleRect = new RectF(); - private View parent = null; + private View parent; private float animatedAlphaValue = 1.0f; private boolean currentWithRound; @@ -43,10 +41,11 @@ public class RadialProgress { private boolean hideCurrentDrawable; private int progressColor = 0xffffffff; - private static DecelerateInterpolator decelerateInterpolator = null; - private static Paint progressPaint = null; + private static DecelerateInterpolator decelerateInterpolator; + private static Paint progressPaint; + private boolean alphaForPrevious = true; - private Paint progressText; + private Paint progressTextPaint; private long docSize; private int docType; @@ -56,14 +55,13 @@ public class RadialProgress { progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); progressPaint.setStyle(Paint.Style.STROKE); progressPaint.setStrokeCap(Paint.Cap.ROUND); - progressPaint.setStrokeWidth(AndroidUtilities.dp(2)); + progressPaint.setStrokeWidth(AndroidUtilities.dp(3)); } - progressText = new Paint(Paint.ANTI_ALIAS_FLAG); - progressText.setColor(Color.BLACK); - progressText.setTextSize(AndroidUtilities.dp(11)); - progressText.setFakeBoldText(true); - progressText.setTextAlign(Paint.Align.CENTER); - + progressTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + progressTextPaint.setColor(Color.BLACK); + progressTextPaint.setTextSize(AndroidUtilities.dp(9)); + progressTextPaint.setFakeBoldText(true); + progressTextPaint.setTextAlign(Paint.Align.CENTER); parent = parentView; } @@ -71,6 +69,10 @@ public class RadialProgress { progressRect.set(left, top, right, bottom); } + public void setAlphaForPrevious(boolean value) { + alphaForPrevious = value; + } + private void updateAnimation(boolean progress) { long newTime = System.currentTimeMillis(); long dt = newTime - lastUpdateTime; @@ -115,7 +117,7 @@ public class RadialProgress { public void setProgressColor(int color) { progressColor = color; SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - progressText.setColor(themePrefs.getInt(color == 0xff87bf78 || color == 0xff81bd72 ? "chatRTextColor" : "chatLTextColor", 0xff000000)); + progressTextPaint.setColor(themePrefs.getInt(color == Theme.MSG_OUT_FILE_PROGRESS_SELECTED_COLOR || color == Theme.MSG_OUT_FILE_PROGRESS_COLOR ? "chatRTextColor" : "chatLTextColor", 0xff000000)); } public void setHideCurrentDrawable(boolean value) { @@ -123,10 +125,17 @@ public class RadialProgress { } public void setProgress(float value, boolean animated) { + if (value != 1 && animatedAlphaValue != 0 && previousDrawable != null) { + animatedAlphaValue = 0.0f; + previousDrawable = null; + } if (!animated) { animatedProgressValue = value; animationProgressStart = value; } else { + if (animatedProgressValue > value) { + animatedProgressValue = value; + } animationProgressStart = animatedProgressValue; } currentProgress = value; @@ -137,6 +146,7 @@ public class RadialProgress { public void setSizeAndType(long size, int type) { docSize = size; docType = type; + progressTextPaint.setTextSize(AndroidUtilities.dp(docType == 9 ? 9 : docType == 14 ? 9 : 12)); } // private void invalidateParent() { @@ -147,10 +157,10 @@ public class RadialProgress { public void setBackground(Drawable drawable, boolean withRound, boolean animated) { lastUpdateTime = System.currentTimeMillis(); if (animated && currentDrawable != drawable) { - setProgress(1, animated); previousDrawable = currentDrawable; previousWithRound = currentWithRound; animatedAlphaValue = 1.0f; + setProgress(1, animated); } else { previousDrawable = null; previousWithRound = false; @@ -178,7 +188,11 @@ public class RadialProgress { public void draw(Canvas canvas) { if (previousDrawable != null) { - previousDrawable.setAlpha((int)(255 * animatedAlphaValue)); + if (alphaForPrevious) { + previousDrawable.setAlpha((int) (255 * animatedAlphaValue)); + } else { + previousDrawable.setAlpha(255); + } previousDrawable.setBounds((int)progressRect.left, (int)progressRect.top, (int)progressRect.right, (int)progressRect.bottom); previousDrawable.draw(canvas); } @@ -189,12 +203,12 @@ public class RadialProgress { } else { currentDrawable.setAlpha(255); } - currentDrawable.setBounds((int) progressRect.left, (int) progressRect.top, (int) progressRect.right, (int) progressRect.bottom); + currentDrawable.setBounds((int)progressRect.left, (int)progressRect.top, (int)progressRect.right, (int)progressRect.bottom); currentDrawable.draw(canvas); } if (currentWithRound || previousWithRound) { - int diff = AndroidUtilities.dp(1); + int diff = AndroidUtilities.dp(4); progressPaint.setColor(progressColor); if (previousWithRound) { progressPaint.setAlpha((int)(255 * animatedAlphaValue)); @@ -203,15 +217,19 @@ public class RadialProgress { } cicleRect.set(progressRect.left + diff, progressRect.top + diff, progressRect.right - diff, progressRect.bottom - diff); canvas.drawArc(cicleRect, -90 + radOffset, Math.max(4, 360 * animatedProgressValue), false, progressPaint); - if(currentDrawable != null && progressText != null) { + //plus + if(currentDrawable != null && progressTextPaint != null) { if (currentProgress < 1.0f && docSize > 0) { - if(docType > 0)progressText.setColor(progressColor); + //Log.e("RadialProgress","docType " + docType); + //if(docType > 0)progressTextPaint.setColor(progressColor); if(docType == 1 || docType == 3 || docType == 8){ - ResourceLoader.mediaBackgroundDrawable.setBounds((int) progressRect.left - AndroidUtilities.dp(20), (int) progressRect.bottom + AndroidUtilities.dp(2), (int) progressRect.right + AndroidUtilities.dp(20) , (int) progressRect.bottom + AndroidUtilities.dp(18)); - ResourceLoader.mediaBackgroundDrawable.draw(canvas); + progressTextPaint.setColor(progressColor); + Theme.timeBackgroundDrawable.setBounds((int) progressRect.left - AndroidUtilities.dp(20), (int) progressRect.bottom + AndroidUtilities.dp(2), (int) progressRect.right + AndroidUtilities.dp(20) , (int) progressRect.bottom + AndroidUtilities.dp(18)); + Theme.timeBackgroundDrawable.draw(canvas); } String s = AndroidUtilities.formatFileSize((long) (docSize * currentProgress)) + (docType != 0 ? " | " + String.format(docSize * currentProgress < 104857000 ? "%.1f" : "%.0f", currentProgress * 100) + '%' : ""); //AndroidUtilities.formatFileSize(docSize)*/ //String.format("%.1f", currentProgress * 100) + '%' - canvas.drawText(s, (int) progressRect.left + (currentDrawable.getIntrinsicWidth() / 2) + AndroidUtilities.dp(1), (int) progressRect.bottom + AndroidUtilities.dp(14), progressText); + //canvas.drawText(s, (int) progressRect.left + (currentDrawable.getIntrinsicWidth() / 2) + AndroidUtilities.dp(1), (int) progressRect.bottom + AndroidUtilities.dp(docType == 9 ? 8 : 14), progressTextPaint); + canvas.drawText(s, (int) progressRect.left + (currentDrawable.getIntrinsicWidth() / 2) + AndroidUtilities.dp(docType == 14 ? 1 : 1), (int) progressRect.bottom + AndroidUtilities.dp(docType == 9 ? 8 : docType == 14 ? 24 : 14), progressTextPaint); } } updateAnimation(true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RadioButton.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RadioButton.java new file mode 100644 index 00000000..93bd1eff --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RadioButton.java @@ -0,0 +1,190 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageLoader; +import org.telegram.ui.ActionBar.Theme; + +public class RadioButton extends View { + + private Bitmap bitmap; + private Canvas bitmapCanvas; + private static Paint paint; + private static Paint eraser; + private static Paint checkedPaint; + + private int checkedColor = Theme.ACTION_BAR_SUBTITLE_COLOR; + private int color = Theme.ACTION_BAR_SUBTITLE_COLOR; + + private float progress; + private ObjectAnimatorProxy checkAnimator; + + private boolean attachedToWindow; + private boolean isChecked; + private int size = AndroidUtilities.dp(16); + + public RadioButton(Context context) { + super(context); + if (paint == null) { + paint = new Paint(Paint.ANTI_ALIAS_FLAG); + paint.setStrokeWidth(AndroidUtilities.dp(2)); + paint.setStyle(Paint.Style.STROKE); + checkedPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + eraser = new Paint(Paint.ANTI_ALIAS_FLAG); + eraser.setColor(0); + eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); + } + + try { + bitmap = Bitmap.createBitmap(AndroidUtilities.dp(size), AndroidUtilities.dp(size), Bitmap.Config.ARGB_4444); + if (ImageLoader.getInstance().runtimeHack != null) { + ImageLoader.getInstance().runtimeHack.trackFree(bitmap.getRowBytes() * bitmap.getHeight()); + } + bitmapCanvas = new Canvas(bitmap); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + + public void setProgress(float value) { + if (progress == value) { + return; + } + progress = value; + invalidate(); + } + + public float getProgress() { + return progress; + } + + public void setSize(int value) { + if (size == value) { + return; + } + size = value; + } + + public void setColor(int color1, int color2) { + color = color1; + checkedColor = color2; + invalidate(); + } + + private void cancelCheckAnimator() { + if (checkAnimator != null) { + checkAnimator.cancel(); + } + } + + private void animateToCheckedState(boolean newCheckedState) { + checkAnimator = ObjectAnimatorProxy.ofFloatProxy(this, "progress", newCheckedState ? 1 : 0); + checkAnimator.setDuration(200); + checkAnimator.start(); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + attachedToWindow = true; + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + attachedToWindow = false; + if (bitmap != null && ImageLoader.getInstance().runtimeHack != null) { + ImageLoader.getInstance().runtimeHack.trackAlloc(bitmap.getRowBytes() * bitmap.getHeight()); + bitmap.recycle(); + bitmap = null; + } + } + + public void setChecked(boolean checked, boolean animated) { + if (checked == isChecked) { + return; + } + isChecked = checked; + + if (attachedToWindow && animated) { + animateToCheckedState(checked); + } else { + cancelCheckAnimator(); + setProgress(checked ? 1.0f : 0.0f); + } + } + + public boolean isChecked() { + return isChecked; + } + + @Override + protected void onDraw(Canvas canvas) { + if (bitmap == null || bitmap.getWidth() != getMeasuredWidth()) { + if (bitmap != null) { + if (ImageLoader.getInstance().runtimeHack != null) { + ImageLoader.getInstance().runtimeHack.trackAlloc(bitmap.getRowBytes() * bitmap.getHeight()); + } + bitmap.recycle(); + } + try { + bitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888); + if (ImageLoader.getInstance().runtimeHack != null) { + ImageLoader.getInstance().runtimeHack.trackFree(bitmap.getRowBytes() * bitmap.getHeight()); + } + bitmapCanvas = new Canvas(bitmap); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + float circleProgress; + float innerRad; + if (progress <= 0.5f) { + paint.setColor(color); + checkedPaint.setColor(color); + circleProgress = progress / 0.5f; + } else { + circleProgress = 2.0f - progress / 0.5f; + int r1 = Color.red(color); + int rD = (int) ((Color.red(checkedColor) - r1) * (1.0f - circleProgress)); + int g1 = Color.green(color); + int gD = (int) ((Color.green(checkedColor) - g1) * (1.0f - circleProgress)); + int b1 = Color.blue(color); + int bD = (int) ((Color.blue(checkedColor) - b1) * (1.0f - circleProgress)); + int c = Color.rgb(r1 + rD, g1 + gD, b1 + bD); + paint.setColor(c); + checkedPaint.setColor(c); + } + if (bitmap != null) { + bitmap.eraseColor(0); + float rad = size / 2 - (1 + circleProgress) * AndroidUtilities.density; + bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, rad, paint); + if (progress <= 0.5f) { + bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, (rad - AndroidUtilities.dp(1)), checkedPaint); + bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, (rad - AndroidUtilities.dp(1)) * (1.0f - circleProgress), eraser); + } else { + bitmapCanvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, size / 4 + (rad - AndroidUtilities.dp(1) - size / 4) * circleProgress, checkedPaint); + } + + canvas.drawBitmap(bitmap, 0, 0, null); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecordStatusDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecordStatusDrawable.java index f9f7ea69..0982457e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/RecordStatusDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/RecordStatusDrawable.java @@ -16,6 +16,7 @@ import android.graphics.RectF; import android.graphics.drawable.Drawable; import org.telegram.messenger.AndroidUtilities; +import org.telegram.ui.ActionBar.Theme; import org.telegram.messenger.ApplicationLoader; public class RecordStatusDrawable extends Drawable { @@ -29,7 +30,7 @@ public class RecordStatusDrawable extends Drawable { public RecordStatusDrawable() { super(); - //paint.setColor(0xffd7e8f7); + //paint.setColor(Theme.ACTION_BAR_SUBTITLE_COLOR); SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); paint.setColor(themePrefs.getInt("chatTypingColor",themePrefs.getInt("chatStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40)))); paint.setStyle(Paint.Style.STROKE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Rect.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Rect.java index 60bc7433..9777cdcc 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Rect.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Rect.java @@ -9,11 +9,16 @@ package org.telegram.ui.Components; public class Rect { + public float x; public float y; public float width; public float height; + public Rect() { + + } + public Rect(float x, float y, float width, float height) { this.x = x; this.y = y; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ResourceLoader.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ResourceLoader.java deleted file mode 100644 index 31b3775b..00000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/ResourceLoader.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * This is the source code of Telegram for Android v. 3.x.x - * It is licensed under GNU GPL v. 2 or later. - * You should have received a copy of the license in this archive (see LICENSE). - * - * Copyright Nikolai Kudashov, 2013-2016. - */ - -package org.telegram.ui.Components; - -import android.content.Context; -import android.content.SharedPreferences; -import android.graphics.drawable.Drawable; - -import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.FileLog; -import org.telegram.messenger.R; -import org.telegram.ui.ImageListActivity; - -public class ResourceLoader { - - public static Drawable backgroundDrawableIn; - public static Drawable backgroundDrawableInSelected; - public static Drawable backgroundDrawableOut; - public static Drawable backgroundDrawableOutSelected; - public static Drawable backgroundMediaDrawableIn; - public static Drawable backgroundMediaDrawableInSelected; - public static Drawable backgroundMediaDrawableOut; - public static Drawable backgroundMediaDrawableOutSelected; - public static Drawable checkDrawable; - public static Drawable halfCheckDrawable; - public static Drawable clockDrawable; - public static Drawable broadcastDrawable; - public static Drawable checkMediaDrawable; - public static Drawable halfCheckMediaDrawable; - public static Drawable clockMediaDrawable; - public static Drawable broadcastMediaDrawable; - public static Drawable errorDrawable; - public static Drawable backgroundBlack; - public static Drawable backgroundBlue; - public static Drawable mediaBackgroundDrawable; - public static Drawable[] clockChannelDrawable = new Drawable[2]; - - public static Drawable[][] shareDrawable = new Drawable[2][2]; - - public static Drawable viewsCountDrawable; - public static Drawable viewsOutCountDrawable; - public static Drawable[] viewsMediaCountDrawable = new Drawable[2]; - - public static Drawable backgroundWhite; - - public static Drawable geoInDrawable; - public static Drawable geoOutDrawable; - - public static Drawable[][] audioStatesDrawable = new Drawable[10][3]; - - public static Drawable[] placeholderDocDrawable = new Drawable[3]; - public static Drawable videoIconDrawable; - public static Drawable[] docMenuDrawable = new Drawable[3]; - public static Drawable[] buttonStatesDrawables = new Drawable[8]; - public static Drawable[][] buttonStatesDrawablesDoc = new Drawable[3][3]; - - public static void loadRecources(Context context) { - //if (backgroundDrawableIn == null) { - //backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in); - //backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_selected); - //backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out); - //backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_selected); - //backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_photo); - //backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_photo_selected); - //backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_photo); - //backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_photo_selected); - setBubbles(context); - checkDrawable = context.getResources().getDrawable(R.drawable.msg_check); - halfCheckDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck); - clockDrawable = context.getResources().getDrawable(R.drawable.msg_clock); - checkMediaDrawable = context.getResources().getDrawable(R.drawable.msg_check_w); - halfCheckMediaDrawable = context.getResources().getDrawable(R.drawable.msg_halfcheck_w); - clockMediaDrawable = context.getResources().getDrawable(R.drawable.msg_clock_photo); - clockChannelDrawable[0] = context.getResources().getDrawable(R.drawable.msg_clock2); - clockChannelDrawable[1] = context.getResources().getDrawable(R.drawable.msg_clock2_s); - errorDrawable = context.getResources().getDrawable(R.drawable.msg_warning); - mediaBackgroundDrawable = context.getResources().getDrawable(R.drawable.phototime); - broadcastDrawable = context.getResources().getDrawable(R.drawable.broadcast3); - broadcastMediaDrawable = context.getResources().getDrawable(R.drawable.broadcast4); - backgroundBlack = context.getResources().getDrawable(R.drawable.system_black); - backgroundBlue = context.getResources().getDrawable(R.drawable.system_blue); - - backgroundWhite = context.getResources().getDrawable(R.drawable.system_white); - - viewsCountDrawable = context.getResources().getDrawable(R.drawable.post_views); - viewsOutCountDrawable = context.getResources().getDrawable(R.drawable.post_viewsg); - viewsMediaCountDrawable[0] = context.getResources().getDrawable(R.drawable.post_views_w); - viewsMediaCountDrawable[1] = context.getResources().getDrawable(R.drawable.post_views_s); - - audioStatesDrawable[0][2] = audioStatesDrawable[0][0] = context.getResources().getDrawable(R.drawable.play_w2); - audioStatesDrawable[0][1] = context.getResources().getDrawable(R.drawable.play_w2_pressed); - - audioStatesDrawable[1][2] = audioStatesDrawable[1][0] = context.getResources().getDrawable(R.drawable.pause_w2); - audioStatesDrawable[1][1] = context.getResources().getDrawable(R.drawable.pause_w2_pressed); - - audioStatesDrawable[2][0] = context.getResources().getDrawable(R.drawable.download_g); - audioStatesDrawable[2][1] = context.getResources().getDrawable(R.drawable.download_g_pressed); - audioStatesDrawable[2][2] = context.getResources().getDrawable(R.drawable.download_g_s); - - audioStatesDrawable[3][0] = context.getResources().getDrawable(R.drawable.pause_g); - audioStatesDrawable[3][1] = context.getResources().getDrawable(R.drawable.pause_g_pressed); - audioStatesDrawable[3][2] = context.getResources().getDrawable(R.drawable.pause_g_s); - - audioStatesDrawable[4][0] = context.getResources().getDrawable(R.drawable.cancel_g); - audioStatesDrawable[4][1] = context.getResources().getDrawable(R.drawable.cancel_g_pressed); - audioStatesDrawable[4][2] = context.getResources().getDrawable(R.drawable.cancel_g_s); - - audioStatesDrawable[5][2] = audioStatesDrawable[5][0] = context.getResources().getDrawable(R.drawable.play_w); - audioStatesDrawable[5][1] = context.getResources().getDrawable(R.drawable.play_w_pressed); - - audioStatesDrawable[6][2] = audioStatesDrawable[6][0] = context.getResources().getDrawable(R.drawable.pause_w); - audioStatesDrawable[6][1] = context.getResources().getDrawable(R.drawable.pause_w_pressed); - - audioStatesDrawable[7][0] = context.getResources().getDrawable(R.drawable.download_b); - audioStatesDrawable[7][1] = context.getResources().getDrawable(R.drawable.download_b_pressed); - audioStatesDrawable[7][2] = context.getResources().getDrawable(R.drawable.download_b_s); - - audioStatesDrawable[8][0] = context.getResources().getDrawable(R.drawable.pause_b); - audioStatesDrawable[8][1] = context.getResources().getDrawable(R.drawable.pause_b_pressed); - audioStatesDrawable[8][2] = context.getResources().getDrawable(R.drawable.pause_b_s); - - audioStatesDrawable[9][0] = context.getResources().getDrawable(R.drawable.cancel_b); - audioStatesDrawable[9][1] = context.getResources().getDrawable(R.drawable.cancel_b_pressed); - audioStatesDrawable[9][2] = context.getResources().getDrawable(R.drawable.cancel_b_s); - - placeholderDocDrawable[0] = context.getResources().getDrawable(R.drawable.doc_blue); - placeholderDocDrawable[1] = context.getResources().getDrawable(R.drawable.doc_green); - placeholderDocDrawable[2] = context.getResources().getDrawable(R.drawable.doc_blue_s); - buttonStatesDrawables[0] = context.getResources().getDrawable(R.drawable.photoload); - buttonStatesDrawables[1] = context.getResources().getDrawable(R.drawable.photocancel); - buttonStatesDrawables[2] = context.getResources().getDrawable(R.drawable.photogif); - buttonStatesDrawables[3] = context.getResources().getDrawable(R.drawable.playvideo); - buttonStatesDrawables[4] = context.getResources().getDrawable(R.drawable.photopause); - buttonStatesDrawables[5] = context.getResources().getDrawable(R.drawable.burn); - buttonStatesDrawables[6] = context.getResources().getDrawable(R.drawable.circle); - buttonStatesDrawables[7] = context.getResources().getDrawable(R.drawable.photocheck); - buttonStatesDrawablesDoc[0][0] = context.getResources().getDrawable(R.drawable.docload_b); - buttonStatesDrawablesDoc[0][1] = context.getResources().getDrawable(R.drawable.docload_g); - buttonStatesDrawablesDoc[0][2] = context.getResources().getDrawable(R.drawable.docload_b_s); - buttonStatesDrawablesDoc[1][0] = context.getResources().getDrawable(R.drawable.doccancel_b); - buttonStatesDrawablesDoc[1][1] = context.getResources().getDrawable(R.drawable.doccancel_g); - buttonStatesDrawablesDoc[1][2] = context.getResources().getDrawable(R.drawable.doccancel_b_s); - buttonStatesDrawablesDoc[2][0] = context.getResources().getDrawable(R.drawable.docpause_b); - buttonStatesDrawablesDoc[2][1] = context.getResources().getDrawable(R.drawable.docpause_g); - buttonStatesDrawablesDoc[2][2] = context.getResources().getDrawable(R.drawable.docpause_b_s); - videoIconDrawable = context.getResources().getDrawable(R.drawable.ic_video); - docMenuDrawable[0] = context.getResources().getDrawable(R.drawable.doc_actions_b); - docMenuDrawable[1] = context.getResources().getDrawable(R.drawable.doc_actions_g); - docMenuDrawable[2] = context.getResources().getDrawable(R.drawable.doc_actions_b_s); - - shareDrawable[0][0] = context.getResources().getDrawable(R.drawable.shareblue); - shareDrawable[0][1] = context.getResources().getDrawable(R.drawable.shareblue_pressed); - shareDrawable[1][0] = context.getResources().getDrawable(R.drawable.shareblack); - shareDrawable[1][1] = context.getResources().getDrawable(R.drawable.shareblack_pressed); - - geoInDrawable = context.getResources().getDrawable(R.drawable.location_b); - geoOutDrawable = context.getResources().getDrawable(R.drawable.location_g); - try{ - context.getResources().getDrawable(R.drawable.attach_camera_states); - context.getResources().getDrawable(R.drawable.attach_gallery_states); - context.getResources().getDrawable(R.drawable.attach_video_states); - context.getResources().getDrawable(R.drawable.attach_audio_states); - context.getResources().getDrawable(R.drawable.attach_file_states); - context.getResources().getDrawable(R.drawable.attach_contact_states); - context.getResources().getDrawable(R.drawable.attach_location_states); - context.getResources().getDrawable(R.drawable.attach_hide_states); - } catch (Exception e) { - FileLog.e("tmessages", e); - } - // } - } - - private static void setBubbles(Context context){ - SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - String bubble = themePrefs.getString("chatBubbleStyle", ImageListActivity.getBubbleName(0)); - if(bubble.equals(ImageListActivity.getBubbleName(0))){ - backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in); - backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_selected); - backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out); - backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_selected); - backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_photo); - backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_photo_selected); - backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_photo); - backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_photo_selected); - } else if(bubble.equals(ImageListActivity.getBubbleName(1))){ - backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_2); - backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_2_selected); - backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_2); - backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_2_selected); - backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_2_photo); - backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_2_photo_selected); - backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_2_photo); - backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_2_photo_selected); - } else if(bubble.equals(ImageListActivity.getBubbleName(2))){ - backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_3); - backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_3_selected); - backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_3); - backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_3_selected); - backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_3_photo); - backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_3_photo_selected); - backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_3_photo); - backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_3_photo_selected); - } else if(bubble.equals(ImageListActivity.getBubbleName(3))){ - backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_4); - backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_4_selected); - backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_4); - backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_4_selected); - backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_4_photo); - backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_4_photo_selected); - backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_4_photo); - backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_4_photo_selected); - } else if(bubble.equals(ImageListActivity.getBubbleName(4))){ - backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_5); - backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_5_selected); - backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_5); - backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_5_selected); - backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_5_photo); - backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_5_photo_selected); - backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_5_photo); - backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_5_photo_selected); - } else if(bubble.equals(ImageListActivity.getBubbleName(5))){ - backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_6); - backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_6_selected); - backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_6); - backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_6_selected); - backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_6_photo); - backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_6_photo_selected); - backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_6_photo); - backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_6_photo_selected); - } else if(bubble.equals(ImageListActivity.getBubbleName(6))){ - backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_7); - backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_7_selected); - backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_7); - backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_7_selected); - backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_7_photo); - backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_7_photo_selected); - backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_7_photo); - backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_7_photo_selected); - } else{ - backgroundDrawableIn = context.getResources().getDrawable(R.drawable.msg_in); - backgroundDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_selected); - backgroundDrawableOut = context.getResources().getDrawable(R.drawable.msg_out); - backgroundDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_selected); - backgroundMediaDrawableIn = context.getResources().getDrawable(R.drawable.msg_in_photo); - backgroundMediaDrawableInSelected = context.getResources().getDrawable(R.drawable.msg_in_photo_selected); - backgroundMediaDrawableOut = context.getResources().getDrawable(R.drawable.msg_out_photo); - backgroundMediaDrawableOutSelected = context.getResources().getDrawable(R.drawable.msg_out_photo_selected); - } - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java new file mode 100644 index 00000000..edfef1be --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ScrollSlidingTabStrip.java @@ -0,0 +1,241 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Paint.Style; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; +import android.widget.HorizontalScrollView; +import android.widget.ImageView; +import android.widget.LinearLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.tgnet.TLRPC; + +public class ScrollSlidingTabStrip extends HorizontalScrollView { + + public interface ScrollSlidingTabStripDelegate { + void onPageSelected(int page); + } + + private LinearLayout.LayoutParams defaultTabLayoutParams; + private LinearLayout tabsContainer; + private ScrollSlidingTabStripDelegate delegate; + + private int tabCount; + + private int currentPosition = 0; + + private Paint rectPaint; + + private int indicatorColor = 0xff666666; + private int underlineColor = 0x1a000000; + + private int scrollOffset = AndroidUtilities.dp(52); + private int underlineHeight = AndroidUtilities.dp(2); + private int dividerPadding = AndroidUtilities.dp(12); + private int tabPadding = AndroidUtilities.dp(24); + + private int lastScrollX = 0; + + public ScrollSlidingTabStrip(Context context) { + super(context); + + setFillViewport(true); + setWillNotDraw(false); + + setHorizontalScrollBarEnabled(false); + tabsContainer = new LinearLayout(context); + tabsContainer.setOrientation(LinearLayout.HORIZONTAL); + tabsContainer.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + addView(tabsContainer); + + rectPaint = new Paint(); + rectPaint.setAntiAlias(true); + rectPaint.setStyle(Style.FILL); + + defaultTabLayoutParams = new LinearLayout.LayoutParams(AndroidUtilities.dp(52), LayoutHelper.MATCH_PARENT); + } + + public void setDelegate(ScrollSlidingTabStripDelegate scrollSlidingTabStripDelegate) { + delegate = scrollSlidingTabStripDelegate; + } + + public void removeTabs() { + tabsContainer.removeAllViews(); + tabCount = 0; + currentPosition = 0; + } + + public void selectTab(int num) { + if (num < 0 || num >= tabCount) { + return; + } + View tab = tabsContainer.getChildAt(num); + if (Build.VERSION.SDK_INT >= 15) { + tab.callOnClick(); + } else { + tab.performClick(); + } + } + + public void addIconTab(int resId) { + final int position = tabCount++; + ImageView tab = new ImageView(getContext()); + tab.setFocusable(true); + paintTabIcons(resId); + //tab.setImageResource(resId); + tab.setImageDrawable(getResources().getDrawable(resId)); + tab.setScaleType(ImageView.ScaleType.CENTER); + tab.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + delegate.onPageSelected(position); + } + }); + tabsContainer.addView(tab); + tab.setSelected(position == currentPosition); + } + + private void paintTabIcons(int i){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + Drawable icon = getResources().getDrawable(i); + int iconColor = themePrefs.getInt("chatEmojiViewTabIconColor", 0xffa8a8a8); + icon.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + } + + public void addStickerTab(TLRPC.Document sticker) { + final int position = tabCount++; + FrameLayout tab = new FrameLayout(getContext()); + tab.setFocusable(true); + tab.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + delegate.onPageSelected(position); + } + }); + tabsContainer.addView(tab); + tab.setSelected(position == currentPosition); + BackupImageView imageView = new BackupImageView(getContext()); + if (sticker != null && sticker.thumb != null) { + imageView.setImage(sticker.thumb.location, null, "webp", null); + } + imageView.setAspectFit(true); + tab.addView(imageView, LayoutHelper.createFrame(30, 30, Gravity.CENTER)); + } + + public void updateTabStyles() { + for (int i = 0; i < tabCount; i++) { + View v = tabsContainer.getChildAt(i); + v.setLayoutParams(defaultTabLayoutParams); + } + } + + private void scrollToChild(int position) { + if (tabCount == 0 || tabsContainer.getChildAt(position) == null) { + return; + } + int newScrollX = tabsContainer.getChildAt(position).getLeft(); + if (position > 0) { + newScrollX -= scrollOffset; + } + int currentScrollX = getScrollX(); + if (newScrollX != lastScrollX) { + if (newScrollX < currentScrollX) { + lastScrollX = newScrollX; + smoothScrollTo(lastScrollX, 0); + } else if (newScrollX + scrollOffset > currentScrollX + getWidth() - scrollOffset * 2) { + lastScrollX = newScrollX - getWidth() + scrollOffset * 3; + smoothScrollTo(lastScrollX, 0); + } + } + } + + @Override + protected void onScrollChanged(int l, int t, int oldl, int oldt) { + super.onScrollChanged(l, t, oldl, oldt); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (isInEditMode() || tabCount == 0) { + return; + } + + final int height = getHeight(); + + rectPaint.setColor(underlineColor); + canvas.drawRect(0, height - underlineHeight, tabsContainer.getWidth(), height, rectPaint); + + View currentTab = tabsContainer.getChildAt(currentPosition); + float lineLeft = 0; + float lineRight = 0; + if (currentTab != null) { + lineLeft = currentTab.getLeft(); + lineRight = currentTab.getRight(); + } + + rectPaint.setColor(indicatorColor); + canvas.drawRect(lineLeft, 0, lineRight, height, rectPaint); + } + + public int getCurrentPosition() { + return currentPosition; + } + + public void onPageScrolled(int position, int first) { + if (currentPosition == position) { + return; + } + currentPosition = position; + if (position >= tabsContainer.getChildCount()) { + return; + } + for (int a = 0; a < tabsContainer.getChildCount(); a++) { + tabsContainer.getChildAt(a).setSelected(a == position); + } + if (first == position && position > 1) { + scrollToChild(position - 1); + } else { + scrollToChild(position); + } + invalidate(); + } + + public void setIndicatorColor(int indicatorColor) { + this.indicatorColor = indicatorColor; + invalidate(); + } + + public void setUnderlineColor(int underlineColor) { + this.underlineColor = underlineColor; + invalidate(); + } + + public void setUnderlineColorResource(int resId) { + this.underlineColor = getResources().getColor(resId); + invalidate(); + } + + public void setUnderlineHeight(int underlineHeightPx) { + this.underlineHeight = underlineHeightPx; + invalidate(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java index 7e86e75c..87a77c45 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBar.java @@ -21,39 +21,32 @@ public class SeekBar { void onSeekBarDrag(float progress); } - private static Paint innerPaint1; - private static Paint outerPaint1; - private static Paint innerPaint2; - private static Paint outerPaint2; + private static Paint innerPaint; + private static Paint outerPaint; private static int thumbWidth; - private static int thumbHeight; - public int type; - public int thumbX = 0; - public int thumbDX = 0; + private int thumbX = 0; + private int thumbDX = 0; private boolean pressed = false; - public int width; - public int height; - public SeekBarDelegate delegate; + private int width; + private int height; + private SeekBarDelegate delegate; + private int innerColor; + private int outerColor; + private int selectedColor; + private boolean selected; public SeekBar(Context context) { - if (innerPaint1 == null) { - innerPaint1 = new Paint(Paint.ANTI_ALIAS_FLAG); - innerPaint1.setColor(0xffc3e3ab); - - outerPaint1 = new Paint(Paint.ANTI_ALIAS_FLAG); - outerPaint1.setColor(0xff87bf78); - - innerPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG); - innerPaint2.setColor(0xffe4eaf0); - - outerPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG); - outerPaint2.setColor(0xff4195e5); - + if (innerPaint == null) { + innerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + outerPaint = new Paint(Paint.ANTI_ALIAS_FLAG); thumbWidth = AndroidUtilities.dp(24); - thumbHeight = AndroidUtilities.dp(24); } } + public void setDelegate(SeekBarDelegate seekBarDelegate) { + delegate = seekBarDelegate; + } + public boolean onTouch(int action, float x, float y) { if (action == MotionEvent.ACTION_DOWN) { int additionWidth = (height - thumbWidth) / 2; @@ -84,6 +77,12 @@ public class SeekBar { return false; } + public void setColors(int inner, int outer, int selected) { + innerColor = inner; + outerColor = outer; + selectedColor = selected; + } + public void setProgress(float progress) { thumbX = (int)Math.ceil((width - thumbWidth) * progress); if (thumbX < 0) { @@ -97,19 +96,21 @@ public class SeekBar { return pressed; } + public void setSelected(boolean value) { + selected = value; + } + + public void setSize(int w, int h) { + width = w; + height = h; + } + public void draw(Canvas canvas) { - Paint inner = null; - Paint outer = null; - if (type == 0) { - inner = innerPaint1; - outer = outerPaint1; - } else if (type == 1) { - inner = innerPaint2; - outer = outerPaint2; - } - int y = (height - thumbHeight) / 2; - canvas.drawRect(thumbWidth / 2, height / 2 - AndroidUtilities.dp(1), width - thumbWidth / 2, height / 2 + AndroidUtilities.dp(1), inner); - canvas.drawRect(thumbWidth / 2, height / 2 - AndroidUtilities.dp(1), thumbWidth / 2 + thumbX, height / 2 + AndroidUtilities.dp(1), outer); - canvas.drawCircle(thumbX + thumbWidth / 2, y + thumbHeight / 2, AndroidUtilities.dp(pressed ? 8 : 6), outer); + innerPaint.setColor(selected ? selectedColor : innerColor); + outerPaint.setColor(outerColor); + + canvas.drawRect(thumbWidth / 2, height / 2 - AndroidUtilities.dp(1), width - thumbWidth / 2, height / 2 + AndroidUtilities.dp(1), innerPaint); + canvas.drawRect(thumbWidth / 2, height / 2 - AndroidUtilities.dp(1), thumbWidth / 2 + thumbX, height / 2 + AndroidUtilities.dp(1), outerPaint); + canvas.drawCircle(thumbX + thumbWidth / 2, height / 2, AndroidUtilities.dp(pressed ? 8 : 6), outerPaint); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarPreference.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarPreference.java index 6095bfc9..dbcb7ac8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarPreference.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarPreference.java @@ -261,5 +261,4 @@ public class SeekBarPreference extends Preference implements OnSeekBarChangeList } -} - +} \ No newline at end of file diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarWaveform.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarWaveform.java new file mode 100644 index 00000000..776fbe48 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SeekBarWaveform.java @@ -0,0 +1,195 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.view.MotionEvent; +import android.view.View; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.MessageObject; + +public class SeekBarWaveform { + + private static Paint paintInner; + private static Paint paintOuter; + private int thumbX = 0; + private int thumbDX = 0; + private float startX; + private boolean startDraging = false; + private boolean pressed = false; + private int width; + private int height; + private SeekBar.SeekBarDelegate delegate; + private byte[] waveformBytes; + private MessageObject messageObject; + private View parentView; + private boolean selected; + + private int innerColor; + private int outerColor; + private int selectedColor; + + public SeekBarWaveform(Context context) { + if (paintInner == null) { + paintInner = new Paint(); + paintOuter = new Paint(); + } + } + + public void setDelegate(SeekBar.SeekBarDelegate seekBarDelegate) { + delegate = seekBarDelegate; + } + + public void setColors(int inner, int outer, int selected) { + innerColor = inner; + outerColor = outer; + selectedColor = selected; + } + + public void setWaveform(byte[] waveform) { + waveformBytes = waveform; + } + + public void setSelected(boolean value) { + selected = value; + } + + public void setMessageObject(MessageObject object) { + messageObject = object; + } + + public void setParentView(View view) { + parentView = view; + } + + public boolean isStartDraging() { + return startDraging; + } + + public boolean onTouch(int action, float x, float y) { + if (action == MotionEvent.ACTION_DOWN) { + if (0 <= x && x <= width && y >= 0 && y <= height) { + startX = x; + pressed = true; + thumbDX = (int) (x - thumbX); + startDraging = false; + return true; + } + } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { + if (pressed) { + if (action == MotionEvent.ACTION_UP && delegate != null) { + delegate.onSeekBarDrag((float) thumbX / (float) width); + } + pressed = false; + return true; + } + } else if (action == MotionEvent.ACTION_MOVE) { + if (pressed) { + if (startDraging) { + thumbX = (int) (x - thumbDX); + if (thumbX < 0) { + thumbX = 0; + } else if (thumbX > width) { + thumbX = width; + } + } + if (startX != -1 && Math.abs(x - startX) > AndroidUtilities.getPixelsInCM(0.2f, true)) { + if (parentView != null) { + parentView.getParent().requestDisallowInterceptTouchEvent(true); + } + startDraging = true; + startX = -1; + } + return true; + } + } + return false; + } + + public void setProgress(float progress) { + thumbX = (int)Math.ceil(width * progress); + if (thumbX < 0) { + thumbX = 0; + } else if (thumbX > width) { + thumbX = width; + } + } + + public boolean isDragging() { + return pressed; + } + + public void setSize(int w, int h) { + width = w; + height = h; + } + + public void draw(Canvas canvas) { + if (waveformBytes == null || width == 0) { + return; + } + float totalBarsCount = width / AndroidUtilities.dp(3); + if (totalBarsCount <= 0.1f) { + return; + } + byte value; + int samplesCount = (waveformBytes.length * 8 / 5); + float samplesPerBar = samplesCount / totalBarsCount; + float barCounter = 0; + int nextBarNum = 0; + + paintInner.setColor(messageObject != null && !messageObject.isOutOwner() && messageObject.isContentUnread() && messageObject.messageOwner.to_id.channel_id == 0 ? outerColor : (selected ? selectedColor : innerColor)); + paintOuter.setColor(outerColor); + + int y = (height - AndroidUtilities.dp(14)) / 2; + int barNum = 0; + int lastBarNum; + int drawBarCount; + + for (int a = 0; a < samplesCount; a++) { + if (a != nextBarNum) { + continue; + } + drawBarCount = 0; + lastBarNum = nextBarNum; + while (lastBarNum == nextBarNum) { + barCounter += samplesPerBar; + nextBarNum = (int) barCounter; + drawBarCount++; + } + + int bitPointer = a * 5; + int byteNum = bitPointer / 8; + int byteBitOffset = bitPointer - byteNum * 8; + int currentByteCount = 8 - byteBitOffset; + int nextByteRest = 5 - currentByteCount; + value = (byte) ((waveformBytes[byteNum] >> byteBitOffset) & ((2 << (Math.min(5, currentByteCount) - 1)) - 1)); + if (nextByteRest > 0) { + value <<= nextByteRest; + value |= waveformBytes[byteNum + 1] & ((2 << (nextByteRest - 1)) - 1); + } + + for (int b = 0; b < drawBarCount; b++) { + int x = barNum * AndroidUtilities.dp(3); + if (x < thumbX && x + AndroidUtilities.dp(2) < thumbX) { + canvas.drawRect(x, y + AndroidUtilities.dp(14 - Math.max(1, 14.0f * value / 31.0f)), x + AndroidUtilities.dp(2), y + AndroidUtilities.dp(14), paintOuter); + } else { + canvas.drawRect(x, y + AndroidUtilities.dp(14 - Math.max(1, 14.0f * value / 31.0f)), x + AndroidUtilities.dp(2), y + AndroidUtilities.dp(14), paintInner); + if (x < thumbX) { + canvas.drawRect(x, y + AndroidUtilities.dp(14 - Math.max(1, 14.0f * value / 31.0f)), thumbX, y + AndroidUtilities.dp(14), paintOuter); + } + } + barNum++; + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileDrawable.java index bef8b71c..893468e6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileDrawable.java @@ -18,6 +18,7 @@ import android.view.animation.DecelerateInterpolator; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; +import org.telegram.ui.ActionBar.Theme; public class SendingFileDrawable extends Drawable { @@ -35,7 +36,7 @@ public class SendingFileDrawable extends Drawable { public SendingFileDrawable() { super(); - //paint.setColor(0xffd7e8f7); + //paint.setColor(Theme.ACTION_BAR_SUBTITLE_COLOR); SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); paint.setColor(themePrefs.getInt("chatTypingColor",themePrefs.getInt("chatStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40)))); paint.setStyle(Paint.Style.STROKE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileEx2Drawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileEx2Drawable.java index 110cb386..7f15c7db 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileEx2Drawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileEx2Drawable.java @@ -15,6 +15,7 @@ import android.graphics.Paint; import android.graphics.drawable.Drawable; import org.telegram.messenger.AndroidUtilities; +import org.telegram.ui.ActionBar.Theme; import org.telegram.messenger.ApplicationLoader; public class SendingFileEx2Drawable extends Drawable { @@ -27,7 +28,7 @@ public class SendingFileEx2Drawable extends Drawable { public SendingFileEx2Drawable() { super(); - //paint.setColor(0xffd7e8f7); + //paint.setColor(Theme.ACTION_BAR_SUBTITLE_COLOR); SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); paint.setColor(themePrefs.getInt("chatTypingColor",themePrefs.getInt("chatStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40)))); paint.setStyle(Paint.Style.STROKE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileExDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileExDrawable.java index 54257193..46741db7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileExDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SendingFileExDrawable.java @@ -16,6 +16,7 @@ import android.graphics.drawable.Drawable; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; +import org.telegram.ui.ActionBar.Theme; public class SendingFileExDrawable extends Drawable { @@ -27,7 +28,7 @@ public class SendingFileExDrawable extends Drawable { public SendingFileExDrawable() { super(); - //paint.setColor(0xffd7e8f7); + //paint.setColor(Theme.ACTION_BAR_SUBTITLE_COLOR); SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); paint.setColor(themePrefs.getInt("chatTypingColor",themePrefs.getInt("chatStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40)))); paint.setStyle(Paint.Style.STROKE); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java new file mode 100644 index 00000000..e9098e00 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/ShareAlert.java @@ -0,0 +1,928 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.graphics.*; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.Editable; +import android.text.InputType; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + +import org.telegram.SQLite.SQLiteCursor; +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.R; +import org.telegram.messenger.SendMessagesHelper; +import org.telegram.messenger.support.widget.GridLayoutManager; +import org.telegram.messenger.support.widget.RecyclerView; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.NativeByteBuffer; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.ShareDialogCell; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Locale; +import java.util.Timer; +import java.util.TimerTask; + +public class ShareAlert extends BottomSheet { + + private FrameLayout frameLayout; + private FrameLayout container; + private TextView doneButtonBadgeTextView; + private TextView doneButtonTextView; + private LinearLayout doneButton; + private EditText nameTextView; + private View shadow; + private RecyclerListView gridView; + private GridLayoutManager layoutManager; + private ShareDialogsAdapter listAdapter; + private ShareSearchAdapter searchAdapter; + private MessageObject sendingMessageObject; + private EmptyTextProgressView searchEmptyView; + private Drawable shadowDrawable; + private HashMap selectedDialogs = new HashMap<>(); + + private TLRPC.TL_exportedMessageLink exportedMessageLink; + private boolean loadingLink; + private boolean copyLinkOnEnd; + + private boolean isPublicChannel; + + private int scrollOffsetY; + private int topBeforeSwitch; + + private Switch quoteSwitch; + private boolean favsFirst; + + public ShareAlert(final Context context, final MessageObject messageObject, boolean publicChannel) { + super(context, true); + setApplyTopPadding(false); + setApplyBottomPadding(false); + if (Build.VERSION.SDK_INT >= 11) { + setDisableBackground(true); + } + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + favsFirst = plusPreferences.getBoolean("directShareFavsFirst", false); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int bgColor = themePrefs.getInt("chatAttachBGColor", 0xffffffff); + //setBackgroundColor(bgColor); + int textColor = themePrefs.getInt("chatAttachTextColor", 0xff757575); + shadowDrawable = context.getResources().getDrawable(R.drawable.sheet_shadow); + shadowDrawable.setColorFilter(bgColor, PorterDuff.Mode.SRC_IN); + sendingMessageObject = messageObject; + searchAdapter = new ShareSearchAdapter(context); + isPublicChannel = publicChannel; + + if (publicChannel) { + loadingLink = true; + TLRPC.TL_channels_exportMessageLink req = new TLRPC.TL_channels_exportMessageLink(); + req.id = messageObject.getId(); + req.channel = MessagesController.getInputChannel(messageObject.messageOwner.to_id.channel_id); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (response != null) { + exportedMessageLink = (TLRPC.TL_exportedMessageLink) response; + if (copyLinkOnEnd) { + copyLink(context); + } + } + loadingLink = false; + } + }); + + } + }); + } + + container = new FrameLayout(context) { + + private boolean ignoreLayout = false; + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return scrollOffsetY != 0 && ev.getY() < scrollOffsetY || super.onInterceptTouchEvent(ev); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int height = MeasureSpec.getSize(heightMeasureSpec); + if (Build.VERSION.SDK_INT >= 21) { + height -= AndroidUtilities.statusBarHeight; + } + int size = Math.max(searchAdapter.getItemCount(), listAdapter.getItemCount()); + int contentSize = AndroidUtilities.dp(48) + Math.max(3, (int) Math.ceil(size / 4.0f)) * AndroidUtilities.dp(100) + backgroundPaddingTop; + if (Build.VERSION.SDK_INT < 11) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Math.min(contentSize, AndroidUtilities.displaySize.y / 5 * 3), MeasureSpec.EXACTLY)); + } else { + int padding = contentSize < height ? 0 : height - (height / 5 * 3) + AndroidUtilities.dp(8); + if (gridView.getPaddingTop() != padding) { + ignoreLayout = true; + gridView.setPadding(0, padding, 0, AndroidUtilities.dp(8)); + ignoreLayout = false; + } + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Math.min(contentSize, height), MeasureSpec.EXACTLY)); + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (Build.VERSION.SDK_INT >= 11) { + updateLayout(); + } + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + + @Override + protected void onDraw(Canvas canvas) { + if (Build.VERSION.SDK_INT >= 11) { + shadowDrawable.setBounds(0, scrollOffsetY - backgroundPaddingTop, getMeasuredWidth(), getMeasuredHeight()); + shadowDrawable.draw(canvas); + } + } + }; + if (Build.VERSION.SDK_INT >= 11) { + container.setWillNotDraw(false); + } + container.setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, 0); + setCustomView(container); + + frameLayout = new FrameLayout(context); + //frameLayout.setBackgroundColor(0xffffffff); + frameLayout.setBackgroundColor(bgColor); + frameLayout.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + + doneButton = new LinearLayout(context); + doneButton.setOrientation(LinearLayout.HORIZONTAL); + doneButton.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_AUDIO_SELECTOR_COLOR, false)); + doneButton.setPadding(AndroidUtilities.dp(21), 0, AndroidUtilities.dp(21), 0); + frameLayout.addView(doneButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); + doneButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (selectedDialogs.isEmpty() && isPublicChannel) { + if (loadingLink) { + copyLinkOnEnd = true; + Toast.makeText(ShareAlert.this.getContext(), LocaleController.getString("Loading", R.string.Loading), Toast.LENGTH_SHORT).show(); + } else { + copyLink(ShareAlert.this.getContext()); + } + dismiss(); + } else { + ArrayList arrayList = new ArrayList<>(); + arrayList.add(sendingMessageObject); + for (HashMap.Entry entry : selectedDialogs.entrySet()) { + TLRPC.Dialog dialog = entry.getValue(); + boolean asAdmin = true; + int lower_id = (int) dialog.id; + if (lower_id < 0) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(-lower_id); + if (chat.megagroup) { + asAdmin = false; + } + } + //SendMessagesHelper.getInstance().sendMessage(arrayList, entry.getKey(), asAdmin); + if (quoteSwitch.isChecked()) { + SendMessagesHelper.getInstance().sendMessage(arrayList, entry.getKey(), asAdmin); + } else { + for (MessageObject object : arrayList) { + SendMessagesHelper.getInstance().processForwardFromMyName(object, entry.getKey(), asAdmin); + } + } + } + dismiss(); + } + } + }); + + doneButtonBadgeTextView = new TextView(context); + doneButtonBadgeTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + doneButtonBadgeTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13); + doneButtonBadgeTextView.setTextColor(Theme.SHARE_SHEET_BADGE_TEXT_COLOR); + doneButtonBadgeTextView.setGravity(Gravity.CENTER); + doneButtonBadgeTextView.setBackgroundResource(R.drawable.bluecounter); + doneButtonBadgeTextView.setMinWidth(AndroidUtilities.dp(23)); + doneButtonBadgeTextView.setPadding(AndroidUtilities.dp(8), 0, AndroidUtilities.dp(8), AndroidUtilities.dp(1)); + doneButton.addView(doneButtonBadgeTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, 23, Gravity.CENTER_VERTICAL, 0, 0, 10, 0)); + + doneButtonTextView = new TextView(context); + doneButtonTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + doneButtonTextView.setGravity(Gravity.CENTER); + doneButtonTextView.setCompoundDrawablePadding(AndroidUtilities.dp(8)); + doneButtonTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + doneButton.addView(doneButtonTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER_VERTICAL)); + + //ImageView imageView = new ImageView(context); + //imageView.setImageResource(R.drawable.search_share); + //imageView.setScaleType(ImageView.ScaleType.CENTER); + //imageView.setPadding(0, AndroidUtilities.dp(2), 0, 0); + //frameLayout.addView(imageView, LayoutHelper.createFrame(48, 48, Gravity.LEFT | Gravity.CENTER_VERTICAL)); + //switch + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + quoteSwitch = new Switch(context); + quoteSwitch.setTag("chat"); + quoteSwitch.setDuplicateParentStateEnabled(false); + quoteSwitch.setFocusable(false); + quoteSwitch.setFocusableInTouchMode(false); + quoteSwitch.setClickable(true); + setCheck(preferences.getBoolean("directShareQuote", true)); + setCheckColor(); + frameLayout.addView(quoteSwitch, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.CENTER_VERTICAL, 0, 2, 0, 0)); + quoteSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("directShareQuote", isChecked).apply(); + setCheckColor(); + } + }); + TextView quoteTextView = new TextView(context); + quoteTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 9); + //quoteTextView.setTextColor(0xff979797); + quoteTextView.setTextColor(textColor != 0xff757575 ? textColor : 0xff979797); + quoteTextView.setGravity(Gravity.CENTER); + quoteTextView.setCompoundDrawablePadding(AndroidUtilities.dp(8)); + quoteTextView.setText(LocaleController.getString("Quote", R.string.Quote).toUpperCase()); + quoteTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + frameLayout.addView(quoteTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP , 12, 2, 0, 0)); + + nameTextView = new EditText(context); + nameTextView.setHint(LocaleController.getString("ShareSendTo", R.string.ShareSendTo)); + nameTextView.setMaxLines(1); + nameTextView.setSingleLine(true); + nameTextView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT); + nameTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + nameTextView.setBackgroundDrawable(null); + nameTextView.setHintTextColor(Theme.SHARE_SHEET_EDIT_PLACEHOLDER_TEXT_COLOR); + nameTextView.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); + nameTextView.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES); + AndroidUtilities.clearCursorDrawable(nameTextView); + //nameTextView.setTextColor(Theme.SHARE_SHEET_EDIT_TEXT_COLOR); + nameTextView.setTextColor(textColor != 0xff757575 ? textColor : 0xff212121); + frameLayout.addView(nameTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 48, 2, 96, 0)); + nameTextView.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + String text = nameTextView.getText().toString(); + if (text.length() != 0) { + if (gridView.getAdapter() != searchAdapter) { + topBeforeSwitch = getCurrentTop(); + gridView.setAdapter(searchAdapter); + searchAdapter.notifyDataSetChanged(); + } + if (searchEmptyView != null) { + searchEmptyView.setText(LocaleController.getString("NoResult", R.string.NoResult)); + } + } else { + if (gridView.getAdapter() != listAdapter) { + int top = getCurrentTop(); + searchEmptyView.setText(LocaleController.getString("NoChats", R.string.NoChats)); + gridView.setAdapter(listAdapter); + listAdapter.notifyDataSetChanged(); + if (top > 0) { + layoutManager.scrollToPositionWithOffset(0, -top); + } + } + } + if (searchAdapter != null) { + searchAdapter.searchDialogs(text); + } + } + }); + + gridView = new RecyclerListView(context); + gridView.setPadding(0, 0, 0, AndroidUtilities.dp(8)); + gridView.setClipToPadding(false); + gridView.setLayoutManager(layoutManager = new GridLayoutManager(getContext(), 4)); + gridView.setHorizontalScrollBarEnabled(false); + gridView.setVerticalScrollBarEnabled(false); + gridView.addItemDecoration(new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(android.graphics.Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + Holder holder = (Holder) parent.getChildViewHolder(view); + if (holder != null) { + int pos = holder.getAdapterPosition(); + outRect.left = pos % 4 == 0 ? 0 : AndroidUtilities.dp(4); + outRect.right = pos % 4 == 3 ? 0 : AndroidUtilities.dp(4); + } else { + outRect.left = AndroidUtilities.dp(4); + outRect.right = AndroidUtilities.dp(4); + } + } + }); + container.addView(gridView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 48, 0, 0)); + gridView.setAdapter(listAdapter = new ShareDialogsAdapter(context)); + //gridView.setGlowColor(0xfff5f6f7); + gridView.setGlowColor(bgColor != 0xffffffff ? bgColor : 0xfff5f6f7); + gridView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { + @Override + public void onItemClick(View view, int position) { + TLRPC.Dialog dialog; + if (gridView.getAdapter() == listAdapter) { + dialog = listAdapter.getItem(position); + } else { + dialog = searchAdapter.getItem(position); + } + ShareDialogCell cell = (ShareDialogCell) view; + if (selectedDialogs.containsKey(dialog.id)) { + selectedDialogs.remove(dialog.id); + cell.setChecked(false, true); + } else { + selectedDialogs.put(dialog.id, dialog); + cell.setChecked(true, true); + } + updateSelectedCount(); + } + }); + if (Build.VERSION.SDK_INT >= 11) { + gridView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @SuppressLint("NewApi") + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + updateLayout(); + } + }); + } + + searchEmptyView = new EmptyTextProgressView(context); + searchEmptyView.setShowAtCenter(true); + searchEmptyView.showTextView(); + searchEmptyView.setText(LocaleController.getString("NoChats", R.string.NoChats)); + gridView.setEmptyView(searchEmptyView); + container.addView(searchEmptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 48, 0, 0)); + + container.addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.TOP)); + + shadow = new View(context); + shadow.setBackgroundResource(R.drawable.header_shadow); + container.addView(shadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 3, Gravity.TOP | Gravity.LEFT, 0, 48, 0, 0)); + + updateSelectedCount(); + } + + private int getCurrentTop() { + if (gridView.getChildCount() != 0) { + View child = gridView.getChildAt(0); + Holder holder = (Holder) gridView.findContainingViewHolder(child); + if (holder != null) { + return gridView.getPaddingTop() - (holder.getAdapterPosition() == 0 && child.getTop() >= 0 ? child.getTop() : 0); + } + } + return -1000; + } + + @SuppressLint("NewApi") + private void updateLayout() { + if (gridView.getChildCount() <= 0) { + return; + } + View child = gridView.getChildAt(0); + Holder holder = (Holder) gridView.findContainingViewHolder(child); + int top = child.getTop() - AndroidUtilities.dp(8); + int newOffset = top > 0 && holder != null && holder.getAdapterPosition() == 0 ? top : 0; + if (scrollOffsetY != newOffset) { + gridView.setTopGlowOffset(scrollOffsetY = newOffset); + frameLayout.setTranslationY(scrollOffsetY); + shadow.setTranslationY(scrollOffsetY); + searchEmptyView.setTranslationY(scrollOffsetY); + container.invalidate(); + } + } + + private void copyLink(Context context) { + if (exportedMessageLink == null) { + return; + } + try { + if (Build.VERSION.SDK_INT < 11) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(exportedMessageLink.link); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", exportedMessageLink.link); + clipboard.setPrimaryClip(clip); + } + Toast.makeText(context, LocaleController.getString("LinkCopied", R.string.LinkCopied), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void setCheck(boolean checked) { + if (Build.VERSION.SDK_INT < 11) { + quoteSwitch.resetLayout(); + quoteSwitch.requestLayout(); + } + quoteSwitch.setChecked(checked); + setCheckColor(); + } + + private void setCheckColor(){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + quoteSwitch.setColor(themePrefs.getInt("chatAttachTextColor", 0xff757575)); + } + + public void updateSelectedCount() { + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int textColor = themePrefs.getInt("chatAttachTextColor", 0xff3ec1f9); + if (selectedDialogs.isEmpty()) { + doneButtonBadgeTextView.setVisibility(View.GONE); + if (!isPublicChannel) { + doneButtonTextView.setTextColor(Theme.SHARE_SHEET_SEND_DISABLED_TEXT_COLOR); + doneButton.setEnabled(false); + doneButtonTextView.setText(LocaleController.getString("Send", R.string.Send).toUpperCase()); + } else { + doneButtonTextView.setTextColor(Theme.SHARE_SHEET_COPY_TEXT_COLOR); + doneButton.setEnabled(true); + doneButtonTextView.setText(LocaleController.getString("CopyLink", R.string.CopyLink).toUpperCase()); + } + } else { + doneButtonTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + doneButtonBadgeTextView.setVisibility(View.VISIBLE); + doneButtonBadgeTextView.setText(String.format("%d", selectedDialogs.size())); + doneButtonTextView.setTextColor(Theme.SHARE_SHEET_SEND_TEXT_COLOR); + doneButton.setEnabled(true); + doneButtonTextView.setText(LocaleController.getString("Send", R.string.Send).toUpperCase()); + } + doneButtonTextView.setTextColor(textColor); + } + + private class Holder extends RecyclerView.ViewHolder { + + public Holder(View itemView) { + super(itemView); + } + } + + private class ShareDialogsAdapter extends RecyclerView.Adapter { + + private Context context; + private int currentCount; + private ArrayList dialogs = new ArrayList<>(); + + public ShareDialogsAdapter(Context context) { + this.context = context; + //plus + if(favsFirst) { + for (int a = 0; a < MessagesController.getInstance().dialogsFavs.size(); a++) { + TLRPC.Dialog dialog = MessagesController.getInstance().dialogsFavs.get(a); + int lower_id = (int) dialog.id; + int high_id = (int) (dialog.id >> 32); + if (lower_id != 0 && high_id != 1) { + if (lower_id > 0) { + dialogs.add(dialog); + } else { + TLRPC.Chat chat = MessagesController.getInstance().getChat(-lower_id); + if (!(chat == null || ChatObject.isNotInChat(chat) || ChatObject.isChannel(chat) && !chat.creator && !chat.editor && !chat.megagroup)) { + dialogs.add(dialog); + } + } + } + } + } + for (int a = 0; a < MessagesController.getInstance().dialogsServerOnly.size(); a++) { + TLRPC.Dialog dialog = MessagesController.getInstance().dialogsServerOnly.get(a); + //plus + if(favsFirst && Favourite.isFavourite(dialog.id)){ + continue; + } + // + int lower_id = (int) dialog.id; + int high_id = (int) (dialog.id >> 32); + if (lower_id != 0 && high_id != 1) { + if (lower_id > 0) { + dialogs.add(dialog); + } else { + TLRPC.Chat chat = MessagesController.getInstance().getChat(-lower_id); + if (!(chat == null || ChatObject.isNotInChat(chat) || ChatObject.isChannel(chat) && !chat.creator && !chat.editor && !chat.megagroup)) { + dialogs.add(dialog); + } + } + } + } + } + + @Override + public int getItemCount() { + return dialogs.size(); + } + + public TLRPC.Dialog getItem(int i) { + if (i < 0 || i >= dialogs.size()) { + return null; + } + return dialogs.get(i); + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = new ShareDialogCell(context); + view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, AndroidUtilities.dp(100))); + return new Holder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + ShareDialogCell cell = (ShareDialogCell) holder.itemView; + TLRPC.Dialog dialog = getItem(position); + cell.setDialog(dialog, selectedDialogs.containsKey(dialog.id), null); + } + + @Override + public int getItemViewType(int i) { + return 0; + } + } + + public class ShareSearchAdapter extends RecyclerView.Adapter { + + private Context context; + private Timer searchTimer; + private ArrayList searchResult = new ArrayList<>(); + private String lastSearchText; + private int reqId = 0; + private int lastReqId; + private int lastSearchId = 0; + + private class DialogSearchResult { + public TLRPC.Dialog dialog = new TLRPC.Dialog(); + public TLObject object; + public int date; + public CharSequence name; + } + + public ShareSearchAdapter(Context context) { + this.context = context; + } + + private void searchDialogsInternal(final String query, final int searchId) { + MessagesStorage.getInstance().getStorageQueue().postRunnable(new Runnable() { + @Override + public void run() { + try { + String search1 = query.trim().toLowerCase(); + if (search1.length() == 0) { + lastSearchId = -1; + updateSearchResults(new ArrayList(), lastSearchId); + return; + } + String search2 = LocaleController.getInstance().getTranslitString(search1); + if (search1.equals(search2) || search2.length() == 0) { + search2 = null; + } + String search[] = new String[1 + (search2 != null ? 1 : 0)]; + search[0] = search1; + if (search2 != null) { + search[1] = search2; + } + + ArrayList usersToLoad = new ArrayList<>(); + ArrayList chatsToLoad = new ArrayList<>(); + int resultCount = 0; + + HashMap dialogsResult = new HashMap<>(); + SQLiteCursor cursor = MessagesStorage.getInstance().getDatabase().queryFinalized("SELECT did, date FROM dialogs ORDER BY date DESC LIMIT 400"); + while (cursor.next()) { + long id = cursor.longValue(0); + DialogSearchResult dialogSearchResult = new DialogSearchResult(); + dialogSearchResult.date = cursor.intValue(1); + dialogsResult.put(id, dialogSearchResult); + + int lower_id = (int) id; + int high_id = (int) (id >> 32); + if (lower_id != 0 && high_id != 1) { + if (lower_id > 0) { + if (!usersToLoad.contains(lower_id)) { + usersToLoad.add(lower_id); + } + } else { + if (!chatsToLoad.contains(-lower_id)) { + chatsToLoad.add(-lower_id); + } + } + } + } + cursor.dispose(); + + if (!usersToLoad.isEmpty()) { + cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, status, name FROM users WHERE uid IN(%s)", TextUtils.join(",", usersToLoad))); + while (cursor.next()) { + String name = cursor.stringValue(2); + String tName = LocaleController.getInstance().getTranslitString(name); + if (name.equals(tName)) { + tName = null; + } + String username = null; + int usernamePos = name.lastIndexOf(";;;"); + if (usernamePos != -1) { + username = name.substring(usernamePos + 3); + } + int found = 0; + for (String q : search) { + if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + found = 1; + } else if (username != null && username.startsWith(q)) { + found = 2; + } + if (found != 0) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + TLRPC.User user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); + DialogSearchResult dialogSearchResult = dialogsResult.get((long) user.id); + if (user.status != null) { + user.status.expires = cursor.intValue(1); + } + if (found == 1) { + dialogSearchResult.name = AndroidUtilities.generateSearchName(user.first_name, user.last_name, q); + } else { + dialogSearchResult.name = AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q); + } + dialogSearchResult.object = user; + dialogSearchResult.dialog.id = user.id; + resultCount++; + } + data.reuse(); + break; + } + } + } + cursor.dispose(); + } + + if (!chatsToLoad.isEmpty()) { + cursor = MessagesStorage.getInstance().getDatabase().queryFinalized(String.format(Locale.US, "SELECT data, name FROM chats WHERE uid IN(%s)", TextUtils.join(",", chatsToLoad))); + while (cursor.next()) { + String name = cursor.stringValue(1); + String tName = LocaleController.getInstance().getTranslitString(name); + if (name.equals(tName)) { + tName = null; + } + for (int a = 0; a < search.length; a++) { + String q = search[a]; + if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + TLRPC.Chat chat = TLRPC.Chat.TLdeserialize(data, data.readInt32(false), false); + if (!(chat == null || ChatObject.isNotInChat(chat) || ChatObject.isChannel(chat) && !chat.creator && !chat.editor && !chat.megagroup)) { + DialogSearchResult dialogSearchResult = dialogsResult.get(-(long) chat.id); + dialogSearchResult.name = AndroidUtilities.generateSearchName(chat.title, null, q); + dialogSearchResult.object = chat; + dialogSearchResult.dialog.id = -chat.id; + resultCount++; + } + } + data.reuse(); + break; + } + } + } + cursor.dispose(); + } + + ArrayList searchResults = new ArrayList<>(resultCount); + for (DialogSearchResult dialogSearchResult : dialogsResult.values()) { + if (dialogSearchResult.object != null && dialogSearchResult.name != null) { + searchResults.add(dialogSearchResult); + } + } + + cursor = MessagesStorage.getInstance().getDatabase().queryFinalized("SELECT u.data, u.status, u.name, u.uid FROM users as u INNER JOIN contacts as c ON u.uid = c.uid"); + while (cursor.next()) { + int uid = cursor.intValue(3); + if (dialogsResult.containsKey((long) uid)) { + continue; + } + String name = cursor.stringValue(2); + String tName = LocaleController.getInstance().getTranslitString(name); + if (name.equals(tName)) { + tName = null; + } + String username = null; + int usernamePos = name.lastIndexOf(";;;"); + if (usernamePos != -1) { + username = name.substring(usernamePos + 3); + } + int found = 0; + for (String q : search) { + if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + found = 1; + } else if (username != null && username.startsWith(q)) { + found = 2; + } + if (found != 0) { + NativeByteBuffer data = new NativeByteBuffer(cursor.byteArrayLength(0)); + if (data != null && cursor.byteBufferValue(0, data) != 0) { + TLRPC.User user = TLRPC.User.TLdeserialize(data, data.readInt32(false), false); + DialogSearchResult dialogSearchResult = new DialogSearchResult(); + if (user.status != null) { + user.status.expires = cursor.intValue(1); + } + dialogSearchResult.dialog.id = user.id; + dialogSearchResult.object = user; + if (found == 1) { + dialogSearchResult.name = AndroidUtilities.generateSearchName(user.first_name, user.last_name, q); + } else { + dialogSearchResult.name = AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q); + } + searchResults.add(dialogSearchResult); + } + data.reuse(); + break; + } + } + } + cursor.dispose(); + + Collections.sort(searchResults, new Comparator() { + @Override + public int compare(DialogSearchResult lhs, DialogSearchResult rhs) { + if (lhs.date < rhs.date) { + return 1; + } else if (lhs.date > rhs.date) { + return -1; + } + return 0; + } + }); + + updateSearchResults(searchResults, searchId); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + } + + private void updateSearchResults(final ArrayList result, final int searchId) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (searchId != lastSearchId) { + return; + } + for (int a = 0; a < result.size(); a++) { + DialogSearchResult obj = result.get(a); + if (obj.object instanceof TLRPC.User) { + TLRPC.User user = (TLRPC.User) obj.object; + MessagesController.getInstance().putUser(user, true); + } else if (obj.object instanceof TLRPC.Chat) { + TLRPC.Chat chat = (TLRPC.Chat) obj.object; + MessagesController.getInstance().putChat(chat, true); + } + } + boolean becomeEmpty = !searchResult.isEmpty() && result.isEmpty(); + boolean isEmpty = searchResult.isEmpty() && result.isEmpty(); + if (becomeEmpty) { + topBeforeSwitch = getCurrentTop(); + } + searchResult = result; + notifyDataSetChanged(); + if (!isEmpty && !becomeEmpty && topBeforeSwitch > 0) { + layoutManager.scrollToPositionWithOffset(0, -topBeforeSwitch); + topBeforeSwitch = -1000; + } + } + }); + } + + public void searchDialogs(final String query) { + if (query != null && lastSearchText != null && query.equals(lastSearchText)) { + return; + } + lastSearchText = query; + try { + if (searchTimer != null) { + searchTimer.cancel(); + searchTimer = null; + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (query == null || query.length() == 0) { + searchResult.clear(); + topBeforeSwitch = getCurrentTop(); + notifyDataSetChanged(); + } else { + final int searchId = ++lastSearchId; + searchTimer = new Timer(); + searchTimer.schedule(new TimerTask() { + @Override + public void run() { + try { + cancel(); + searchTimer.cancel(); + searchTimer = null; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + searchDialogsInternal(query, searchId); + } + }, 200, 300); + } + } + + @Override + public int getItemCount() { + return searchResult.size(); + } + + public TLRPC.Dialog getItem(int i) { + return searchResult.get(i).dialog; + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = new ShareDialogCell(context); + view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, AndroidUtilities.dp(100))); + return new Holder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + ShareDialogCell cell = (ShareDialogCell) holder.itemView; + DialogSearchResult result = searchResult.get(position); + cell.setDialog(result.dialog, selectedDialogs.containsKey(result.dialog.id), result.name); + } + + @Override + public int getItemViewType(int i) { + return 0; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleTextView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleTextView.java deleted file mode 100644 index e955b854..00000000 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SimpleTextView.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * This is the source code of Telegram for Android v. 3.x.x - * It is licensed under GNU GPL v. 2 or later. - * You should have received a copy of the license in this archive (see LICENSE). - * - * Copyright Nikolai Kudashov, 2013-2016. - */ - -package org.telegram.ui.Components; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Typeface; -import android.text.Layout; -import android.text.SpannableStringBuilder; -import android.text.StaticLayout; -import android.text.TextPaint; -import android.text.TextUtils; -import android.view.Gravity; -import android.view.View; - -import org.telegram.messenger.AndroidUtilities; - -public class SimpleTextView extends View { - - private Layout layout; - private TextPaint textPaint; - private int gravity; - private CharSequence text; - private SpannableStringBuilder spannableStringBuilder; - - private int offsetX; - private boolean wasLayout = false; - - public SimpleTextView(Context context) { - super(context); - textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG); - } - - public void setTextColor(int color) { - textPaint.setColor(color); - } - - public void setTextSize(int size) { - textPaint.setTextSize(AndroidUtilities.dp(size)); - } - - public void setGravity(int value) { - gravity = value; - } - - public void setTypeface(Typeface typeface) { - textPaint.setTypeface(typeface); - } - - private void createLayout(int width) { - if (text != null) { - try { - CharSequence string = TextUtils.ellipsize(text, textPaint, width, TextUtils.TruncateAt.END); - layout = new StaticLayout(string, 0, string.length(), textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false); - - /*if (metrics == null) { - metrics = BoringLayout.isBoring(text, textPaint); - } - if (layout == null) { - layout = BoringLayout.make(text, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, metrics, false, TextUtils.TruncateAt.END, width); - } else { - layout = ((BoringLayout) layout).replaceOrMake(text, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, metrics, false, TextUtils.TruncateAt.END, width); - }*/ - - /*if (spannableStringBuilder == null) { - spannableStringBuilder = new SpannableStringBuilder(text); - layout = new DynamicLayout(text, text, textPaint, width, Layout.Alignment.ALIGN_NORMAL, 1.0f, 0.0f, false, TextUtils.TruncateAt.END, width); - } else { - spannableStringBuilder.replace(0, text.length(), text); - }*/ - - if (layout.getLineCount() > 0) { - if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.LEFT) { - offsetX = -(int) layout.getLineLeft(0); - } else if (layout.getLineLeft(0) == 0) { - offsetX = (int) (width - layout.getLineWidth(0)); - } else { - offsetX = 0; - } - } - } catch (Exception e) { - //ignore - } - } - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - if (changed) { - createLayout(right - left); - invalidate(); - wasLayout = true; - } - } - - public void setText(CharSequence value) { - text = value; - if (wasLayout) { - createLayout(getMeasuredWidth()); - invalidate(); - } else { - requestLayout(); - } - } - - @Override - protected void onDraw(Canvas canvas) { - if (layout != null) { - if (offsetX != 0) { - canvas.save(); - canvas.translate(offsetX, 0); - } - layout.draw(canvas); - if (offsetX != 0) { - canvas.restore(); - } - } - } -} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java new file mode 100644 index 00000000..cd6b58c4 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayout.java @@ -0,0 +1,126 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.widget.FrameLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; + +public class SizeNotifierFrameLayout extends FrameLayout { + + private Rect rect = new Rect(); + private Drawable backgroundDrawable; + private int keyboardHeight; + private int bottomClip; + private SizeNotifierFrameLayoutDelegate delegate; + + public interface SizeNotifierFrameLayoutDelegate { + void onSizeChanged(int keyboardHeight, boolean isWidthGreater); + } + + public SizeNotifierFrameLayout(Context context) { + super(context); + setWillNotDraw(false); + } + + public void setBackgroundImage(int resourceId) { + try { + backgroundDrawable = getResources().getDrawable(resourceId); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + + public void setBackgroundImage(Drawable bitmap) { + backgroundDrawable = bitmap; + } + + public Drawable getBackgroundImage() { + return backgroundDrawable; + } + + public void setDelegate(SizeNotifierFrameLayoutDelegate delegate) { + this.delegate = delegate; + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + notifyHeightChanged(); + } + + public int getKeyboardHeight() { + View rootView = getRootView(); + getWindowVisibleDisplayFrame(rect); + int usableViewHeight = rootView.getHeight() - (rect.top != 0 ? AndroidUtilities.statusBarHeight : 0) - AndroidUtilities.getViewInset(rootView); + return usableViewHeight - (rect.bottom - rect.top); + } + + public void notifyHeightChanged() { + if (delegate != null) { + keyboardHeight = getKeyboardHeight(); + final boolean isWidthGreater = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y; + post(new Runnable() { + @Override + public void run() { + if (delegate != null) { + delegate.onSizeChanged(keyboardHeight, isWidthGreater); + } + } + }); + } + } + + public void setBottomClip(int value) { + bottomClip = value; + } + + @Override + protected void onDraw(Canvas canvas) { + if (backgroundDrawable != null) { + if (backgroundDrawable instanceof ColorDrawable) { + if (bottomClip != 0) { + canvas.save(); + canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight() - bottomClip); + } + backgroundDrawable.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight()); + backgroundDrawable.draw(canvas); + if (bottomClip != 0) { + canvas.restore(); + } + } else { + float scaleX = (float) getMeasuredWidth() / (float) backgroundDrawable.getIntrinsicWidth(); + float scaleY = (float) (getMeasuredHeight() + keyboardHeight) / (float) backgroundDrawable.getIntrinsicHeight(); + float scale = scaleX < scaleY ? scaleY : scaleX; + int width = (int) Math.ceil(backgroundDrawable.getIntrinsicWidth() * scale); + int height = (int) Math.ceil(backgroundDrawable.getIntrinsicHeight() * scale); + int x = (getMeasuredWidth() - width) / 2; + int y = (getMeasuredHeight() - height + keyboardHeight) / 2; + if (bottomClip != 0) { + canvas.save(); + canvas.clipRect(0, 0, width, getMeasuredHeight() - bottomClip); + } + backgroundDrawable.setBounds(x, y, x + width, y + height); + backgroundDrawable.draw(canvas); + if (bottomClip != 0) { + canvas.restore(); + } + } + } else { + super.onDraw(canvas); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayoutPhoto.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayoutPhoto.java new file mode 100644 index 00000000..79a0c051 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SizeNotifierFrameLayoutPhoto.java @@ -0,0 +1,72 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.Context; +import android.graphics.Rect; +import android.view.View; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import org.telegram.messenger.AndroidUtilities; + +public class SizeNotifierFrameLayoutPhoto extends FrameLayout { + + private Rect rect = new Rect(); + private int keyboardHeight; + private SizeNotifierFrameLayoutPhotoDelegate delegate; + private WindowManager windowManager; + + public interface SizeNotifierFrameLayoutPhotoDelegate { + void onSizeChanged(int keyboardHeight, boolean isWidthGreater); + } + + public SizeNotifierFrameLayoutPhoto(Context context) { + super(context); + } + + public void setDelegate(SizeNotifierFrameLayoutPhotoDelegate delegate) { + this.delegate = delegate; + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + notifyHeightChanged(); + } + + public int getKeyboardHeight() { + View rootView = getRootView(); + int usableViewHeight = rootView.getHeight() - AndroidUtilities.getViewInset(rootView); + getWindowVisibleDisplayFrame(rect); + int top = rect.top; + int size = (rect.bottom - rect.top); + + size = AndroidUtilities.displaySize.y - top - usableViewHeight; + if (size <= AndroidUtilities.dp(10)) { + size = 0; + } + return size; + } + + public void notifyHeightChanged() { + if (delegate != null) { + keyboardHeight = getKeyboardHeight(); + final boolean isWidthGreater = AndroidUtilities.displaySize.x > AndroidUtilities.displaySize.y; + post(new Runnable() { + @Override + public void run() { + if (delegate != null) { + delegate.onSizeChanged(keyboardHeight, isWidthGreater); + } + } + }); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SlidingTabView.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SlidingTabView.java index d81c556f..8cb1adad 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/SlidingTabView.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SlidingTabView.java @@ -20,7 +20,7 @@ import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.Theme; public class SlidingTabView extends LinearLayout { @@ -58,7 +58,7 @@ public class SlidingTabView extends LinearLayout { tab.setTextColor(0xffffffff); tab.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); tab.setTypeface(Typeface.DEFAULT_BOLD); - tab.setBackgroundResource(R.drawable.bar_selector_picker); + tab.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_PICKER_SELECTOR_COLOR, false)); tab.setOnClickListener(new OnClickListener() { @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/SpannableStringLight.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/SpannableStringLight.java new file mode 100644 index 00000000..2bb99850 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/SpannableStringLight.java @@ -0,0 +1,88 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.text.SpannableString; + +import org.telegram.messenger.FileLog; + +import java.lang.reflect.Field; + +public class SpannableStringLight extends SpannableString { + + private static Field mSpansField; + private static Field mSpanDataField; + private static Field mSpanCountField; + private static boolean fieldsAvailable; + + private Object[] mSpansOverride; + private int[] mSpanDataOverride; + private int mSpanCountOverride; + private int num; + + public SpannableStringLight(CharSequence source) { + super(source); + + try { + mSpansOverride = (Object[]) mSpansField.get(this); + mSpanDataOverride = (int[]) mSpanDataField.get(this); + mSpanCountOverride = (int) mSpanCountField.get(this); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + + public void setSpansCount(int count) { + count += mSpanCountOverride; + mSpansOverride = new Object[count]; + mSpanDataOverride = new int[count * 3]; + num = mSpanCountOverride; + mSpanCountOverride = count; + + try { + mSpansField.set(this, mSpansOverride); + mSpanDataField.set(this, mSpanDataOverride); + mSpanCountField.set(this, mSpanCountOverride); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + + public static boolean isFieldsAvailable() { + if (!fieldsAvailable && mSpansField == null) { + try { + mSpansField = SpannableString.class.getSuperclass().getDeclaredField("mSpans"); + mSpansField.setAccessible(true); + + mSpanDataField = SpannableString.class.getSuperclass().getDeclaredField("mSpanData"); + mSpanDataField.setAccessible(true); + + mSpanCountField = SpannableString.class.getSuperclass().getDeclaredField("mSpanCount"); + mSpanCountField.setAccessible(true); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + fieldsAvailable = true; + } + return mSpansField != null; + } + + public void setSpanLight(Object what, int start, int end, int flags) { + mSpansOverride[num] = what; + mSpanDataOverride[num * 3] = start; + mSpanDataOverride[num * 3 + 1] = end; + mSpanDataOverride[num * 3 + 2] = flags; + num++; + } + + @Override + public void removeSpan(Object what) { + super.removeSpan(what); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java new file mode 100644 index 00000000..eae765ee --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/StickersAlert.java @@ -0,0 +1,615 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.graphics.*; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.AnimationCompat.AnimatorListenerAdapterProxy; +import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; +import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; +import org.telegram.messenger.AnimationCompat.ViewProxy; +import org.telegram.messenger.Emoji; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.query.StickersQuery; +import org.telegram.messenger.support.widget.GridLayoutManager; +import org.telegram.messenger.support.widget.RecyclerView; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Cells.StickerEmojiCell; +import org.telegram.ui.StickerPreviewViewer; + +public class StickersAlert extends BottomSheet implements NotificationCenter.NotificationCenterDelegate { + + public interface StickersAlertDelegate { + void onStickerSelected(TLRPC.Document sticker); + } + + private FrameLayout container; + private RecyclerListView gridView; + private GridLayoutManager layoutManager; + private GridAdapter adapter; + private TextView titleTextView; + private PickerBottomLayout pickerBottomLayout; + private FrameLayout stickerPreviewLayout; + private TextView previewSendButton; + private View previewSendButtonShadow; + private BackupImageView stickerImageView; + private TextView stickerEmojiTextView; + private RecyclerListView.OnItemClickListener stickersOnItemClickListener; + private Drawable shadowDrawable; + private AnimatorSetProxy shadowAnimation[] = new AnimatorSetProxy[2]; + private View shadow[] = new View[2]; + private FrameLayout emptyView; + + private TLRPC.TL_messages_stickerSet stickerSet; + private TLRPC.Document selectedSticker; + private TLRPC.InputStickerSet inputStickerSet; + + private StickersAlertDelegate delegate; + + private int scrollOffsetY; + private int reqId; + private boolean ignoreLayout = false; + + public StickersAlert(Context context, TLRPC.InputStickerSet set, TLRPC.TL_messages_stickerSet loadedSet, StickersAlertDelegate stickersAlertDelegate) { + super(context, false); + setApplyTopPadding(false); + setApplyBottomPadding(false); + if (Build.VERSION.SDK_INT >= 11) { + setDisableBackground(true); + } + + delegate = stickersAlertDelegate; + inputStickerSet = set; + stickerSet = loadedSet; + shadowDrawable = context.getResources().getDrawable(R.drawable.sheet_shadow); + + container = new FrameLayout(context) { + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + return scrollOffsetY != 0 && ev.getY() < scrollOffsetY || super.onInterceptTouchEvent(ev); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int height = MeasureSpec.getSize(heightMeasureSpec); + if (Build.VERSION.SDK_INT >= 21) { + height -= AndroidUtilities.statusBarHeight; + } + int contentSize = AndroidUtilities.dp(48 + 48) + Math.max(3, (stickerSet != null ? (int) Math.ceil(stickerSet.documents.size() / 5.0f) : 0)) * AndroidUtilities.dp(82) + backgroundPaddingTop; + if (Build.VERSION.SDK_INT < 11) { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Math.min(contentSize, AndroidUtilities.displaySize.y / 5 * 3), MeasureSpec.EXACTLY)); + } else { + int padding = contentSize < (height / 5 * 3.2) ? 0 : (height / 5 * 2); + if (padding != 0 && contentSize < height) { + padding -= (height - contentSize); + } + if (padding == 0) { + padding = backgroundPaddingTop; + } + if (gridView.getPaddingTop() != padding) { + ignoreLayout = true; + gridView.setPadding(AndroidUtilities.dp(10), padding, AndroidUtilities.dp(10), 0); + emptyView.setPadding(0, padding, 0, 0); + ignoreLayout = false; + } + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Math.min(contentSize, height), MeasureSpec.EXACTLY)); + } + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (Build.VERSION.SDK_INT >= 11) { + updateLayout(); + } + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + + @Override + protected void onDraw(Canvas canvas) { + if (Build.VERSION.SDK_INT >= 11) { + shadowDrawable.setBounds(0, scrollOffsetY - backgroundPaddingTop, getMeasuredWidth(), getMeasuredHeight()); + shadowDrawable.draw(canvas); + } + } + }; + if (Build.VERSION.SDK_INT >= 11) { + container.setWillNotDraw(false); + } + container.setPadding(backgroundPaddingLeft, 0, backgroundPaddingLeft, 0); + setCustomView(container); + + titleTextView = new TextView(context); + + titleTextView = new TextView(getContext()); + titleTextView.setLines(1); + titleTextView.setSingleLine(true); + titleTextView.setTextColor(Theme.STICKERS_SHEET_TITLE_TEXT_COLOR); + titleTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + titleTextView.setEllipsize(TextUtils.TruncateAt.MIDDLE); + titleTextView.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); + titleTextView.setGravity(Gravity.CENTER_VERTICAL); + titleTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + container.addView(titleTextView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 48)); + titleTextView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + + shadow[0] = new View(context); + shadow[0].setBackgroundResource(R.drawable.header_shadow); + ViewProxy.setAlpha(shadow[0], 0.0f); + shadow[0].clearAnimation(); + shadow[0].setVisibility(View.INVISIBLE); + shadow[0].setTag(1); + container.addView(shadow[0], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 3, Gravity.TOP | Gravity.LEFT, 0, 48, 0, 0)); + + gridView = new RecyclerListView(context) { + @Override + public boolean onInterceptTouchEvent(MotionEvent event) { + boolean result = StickerPreviewViewer.getInstance().onInterceptTouchEvent(event, gridView, 0); + return super.onInterceptTouchEvent(event) || result; + } + + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + gridView.setLayoutManager(layoutManager = new GridLayoutManager(getContext(), 5)); + gridView.setAdapter(adapter = new GridAdapter(context)); + gridView.setVerticalScrollBarEnabled(false); + gridView.addItemDecoration(new RecyclerView.ItemDecoration() { + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + outRect.left = 0; + outRect.right = 0; + outRect.bottom = 0; + outRect.top = 0; + } + }); + gridView.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), 0); + gridView.setClipToPadding(false); + gridView.setEnabled(true); + gridView.setGlowColor(0xfff5f6f7); + gridView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return StickerPreviewViewer.getInstance().onTouch(event, gridView, 0, stickersOnItemClickListener); + } + }); + if (Build.VERSION.SDK_INT >= 11) { + gridView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @SuppressLint("NewApi") + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + updateLayout(); + } + }); + } + stickersOnItemClickListener = new RecyclerListView.OnItemClickListener() { + @Override + public void onItemClick(View view, int position) { + if (stickerSet == null || position < 0 || position >= stickerSet.documents.size()) { + return; + } + selectedSticker = stickerSet.documents.get(position); + + boolean set = false; + for (int a = 0; a < selectedSticker.attributes.size(); a++) { + TLRPC.DocumentAttribute attribute = selectedSticker.attributes.get(a); + if (attribute instanceof TLRPC.TL_documentAttributeSticker) { + if (attribute.alt != null && attribute.alt.length() > 0) { + stickerEmojiTextView.setText(Emoji.replaceEmoji(attribute.alt, stickerEmojiTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(30), false)); + set = true; + } + break; + } + } + if (!set) { + stickerEmojiTextView.setText(Emoji.replaceEmoji(StickersQuery.getEmojiForSticker(selectedSticker.id), stickerEmojiTextView.getPaint().getFontMetricsInt(), AndroidUtilities.dp(30), false)); + } + + stickerImageView.getImageReceiver().setImage(selectedSticker, null, selectedSticker.thumb.location, null, "webp", true); + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) stickerPreviewLayout.getLayoutParams(); + layoutParams.topMargin = scrollOffsetY; + stickerPreviewLayout.setLayoutParams(layoutParams); + stickerPreviewLayout.setVisibility(View.VISIBLE); + AnimatorSetProxy animatorSet = new AnimatorSetProxy(); + animatorSet.playTogether(ObjectAnimatorProxy.ofFloat(stickerPreviewLayout, "alpha", 0.0f, 1.0f)); + animatorSet.setDuration(200); + animatorSet.start(); + } + }; + gridView.setOnItemClickListener(stickersOnItemClickListener); + container.addView(gridView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 48, 0, 48)); + + emptyView = new FrameLayout(context) { + @Override + public void requestLayout() { + if (ignoreLayout) { + return; + } + super.requestLayout(); + } + }; + container.addView(emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 48)); + gridView.setEmptyView(emptyView); + emptyView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + + ProgressBar progressView = new ProgressBar(context); + emptyView.addView(progressView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + + shadow[1] = new View(context); + shadow[1].setBackgroundResource(R.drawable.header_shadow_reverse); + container.addView(shadow[1], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 3, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 48)); + + pickerBottomLayout = new PickerBottomLayout(context, false); + container.addView(pickerBottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM)); + pickerBottomLayout.cancelButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); + pickerBottomLayout.cancelButton.setTextColor(Theme.STICKERS_SHEET_CLOSE_TEXT_COLOR); + pickerBottomLayout.cancelButton.setText(LocaleController.getString("Close", R.string.Close).toUpperCase()); + pickerBottomLayout.cancelButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + dismiss(); + } + }); + pickerBottomLayout.doneButton.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); + pickerBottomLayout.doneButtonBadgeTextView.setBackgroundResource(R.drawable.stickercounter); + + stickerPreviewLayout = new FrameLayout(context); + stickerPreviewLayout.setBackgroundColor(0xdfffffff); + stickerPreviewLayout.setVisibility(View.GONE); + stickerPreviewLayout.setSoundEffectsEnabled(false); + container.addView(stickerPreviewLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + stickerPreviewLayout.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + hidePreview(); + } + }); + + ImageView closeButton = new ImageView(context); + closeButton.setImageResource(R.drawable.delete_reply); + closeButton.setScaleType(ImageView.ScaleType.CENTER); + if (Build.VERSION.SDK_INT >= 21) { + closeButton.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.INPUT_FIELD_SELECTOR_COLOR)); + } + stickerPreviewLayout.addView(closeButton, LayoutHelper.createFrame(48, 48, Gravity.RIGHT | Gravity.TOP)); + closeButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + hidePreview(); + } + }); + + stickerImageView = new BackupImageView(context); + stickerImageView.setAspectFit(true); + int size = (int) (Math.min(AndroidUtilities.displaySize.x, AndroidUtilities.displaySize.y) / 2 / AndroidUtilities.density); + stickerPreviewLayout.addView(stickerImageView, LayoutHelper.createFrame(size, size, Gravity.CENTER)); + + stickerEmojiTextView = new TextView(context); + stickerEmojiTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 30); + stickerEmojiTextView.setGravity(Gravity.BOTTOM | Gravity.RIGHT); + stickerPreviewLayout.addView(stickerEmojiTextView, LayoutHelper.createFrame(size, size, Gravity.CENTER)); + + previewSendButton = new TextView(context); + previewSendButton.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + previewSendButton.setTextColor(Theme.STICKERS_SHEET_SEND_TEXT_COLOR); + previewSendButton.setGravity(Gravity.CENTER); + previewSendButton.setBackgroundColor(0xffffffff); + previewSendButton.setPadding(AndroidUtilities.dp(29), 0, AndroidUtilities.dp(29), 0); + previewSendButton.setText(LocaleController.getString("Close", R.string.Close).toUpperCase()); + previewSendButton.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + previewSendButton.setVisibility(View.GONE); + stickerPreviewLayout.addView(previewSendButton, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT)); + previewSendButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + delegate.onStickerSelected(selectedSticker); + dismiss(); + } + }); + + previewSendButtonShadow = new View(context); + previewSendButtonShadow.setBackgroundResource(R.drawable.header_shadow_reverse); + previewSendButtonShadow.setVisibility(View.GONE); + stickerPreviewLayout.addView(previewSendButtonShadow, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 3, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 48)); + + if (delegate != null) { + previewSendButton.setText(LocaleController.getString("SendSticker", R.string.SendSticker).toUpperCase()); + stickerImageView.setLayoutParams(LayoutHelper.createFrame(size, size, Gravity.CENTER, 0, 0, 0, 30)); + stickerEmojiTextView.setLayoutParams(LayoutHelper.createFrame(size, size, Gravity.CENTER, 0, 0, 0, 30)); + previewSendButton.setVisibility(View.VISIBLE); + previewSendButtonShadow.setVisibility(View.VISIBLE); + } + + if (stickerSet == null && inputStickerSet.short_name != null) { + stickerSet = StickersQuery.getStickerSetByName(inputStickerSet.short_name); + } + if (stickerSet == null) { + stickerSet = StickersQuery.getStickerSetById(inputStickerSet.id); + } + if (stickerSet == null) { + TLRPC.TL_messages_getStickerSet req = new TLRPC.TL_messages_getStickerSet(); + req.stickerset = inputStickerSet; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + reqId = 0; + if (error == null) { + stickerSet = (TLRPC.TL_messages_stickerSet) response; + updateFields(); + adapter.notifyDataSetChanged(); + } else { + Toast.makeText(getContext(), LocaleController.getString("AddStickersNotFound", R.string.AddStickersNotFound), Toast.LENGTH_SHORT).show(); + dismiss(); + } + } + }); + } + }); + } + NotificationCenter.getInstance().addObserver(this, NotificationCenter.emojiDidLoaded); + updateFields(); + } + + private void updateFields() { + if (titleTextView == null) { + return; + } + if (stickerSet != null) { + titleTextView.setText(stickerSet.set.title); + + if (stickerSet.set == null || !StickersQuery.isStickerPackInstalled(stickerSet.set.id)) { + setRightButton(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + TLRPC.TL_messages_installStickerSet req = new TLRPC.TL_messages_installStickerSet(); + req.stickerset = inputStickerSet; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + try { + if (error == null) { + Toast.makeText(getContext(), LocaleController.getString("AddStickersInstalled", R.string.AddStickersInstalled), Toast.LENGTH_SHORT).show(); + } else { + if (error.text.equals("STICKERSETS_TOO_MUCH")) { + Toast.makeText(getContext(), LocaleController.getString("TooMuchStickersets", R.string.TooMuchStickersets), Toast.LENGTH_SHORT).show(); + } else { + Toast.makeText(getContext(), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred), Toast.LENGTH_SHORT).show(); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + StickersQuery.loadStickers(false, true); + } + }); + } + }); + } + }, LocaleController.getString("AddStickers", R.string.AddStickers), Theme.STICKERS_SHEET_ADD_TEXT_COLOR, true); + } else { + if (stickerSet.set.official) { + setRightButton(null, null, Theme.STICKERS_SHEET_REMOVE_TEXT_COLOR, false); + } else { + setRightButton(new View.OnClickListener() { + @Override + public void onClick(View v) { + dismiss(); + StickersQuery.removeStickersSet(getContext(), stickerSet.set, 0); + } + }, LocaleController.getString("StickersRemove", R.string.StickersRemove), Theme.STICKERS_SHEET_REMOVE_TEXT_COLOR, false); + } + } + adapter.notifyDataSetChanged(); + } else { + setRightButton(null, null, Theme.STICKERS_SHEET_REMOVE_TEXT_COLOR, false); + } + } + + @SuppressLint("NewApi") + private void updateLayout() { + if (gridView.getChildCount() <= 0) { + gridView.setTopGlowOffset(scrollOffsetY = gridView.getPaddingTop()); + titleTextView.setTranslationY(scrollOffsetY); + shadow[0].setTranslationY(scrollOffsetY); + container.invalidate(); + return; + } + View child = gridView.getChildAt(0); + GridAdapter.Holder holder = (GridAdapter.Holder) gridView.findContainingViewHolder(child); + int top = child.getTop(); + int newOffset = 0; + if (top >= 0 && holder != null && holder.getAdapterPosition() == 0) { + newOffset = top; + runShadowAnimation(0, false); + } else { + runShadowAnimation(0, true); + } + if (scrollOffsetY != newOffset) { + gridView.setTopGlowOffset(scrollOffsetY = newOffset); + titleTextView.setTranslationY(scrollOffsetY); + shadow[0].setTranslationY(scrollOffsetY); + container.invalidate(); + } + } + + private void hidePreview() { + AnimatorSetProxy animatorSet = new AnimatorSetProxy(); + animatorSet.playTogether(ObjectAnimatorProxy.ofFloat(stickerPreviewLayout, "alpha", 0.0f)); + animatorSet.setDuration(200); + animatorSet.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + stickerPreviewLayout.setVisibility(View.GONE); + } + }); + animatorSet.start(); + } + + private void runShadowAnimation(final int num, final boolean show) { + if (show && shadow[num].getTag() != null || !show && shadow[num].getTag() == null) { + shadow[num].setTag(show ? null : 1); + if (show) { + shadow[num].setVisibility(View.VISIBLE); + } + if (shadowAnimation[num] != null) { + shadowAnimation[num].cancel(); + } + shadowAnimation[num] = new AnimatorSetProxy(); + shadowAnimation[num].playTogether(ObjectAnimatorProxy.ofFloat(shadow[num], "alpha", show ? 1.0f : 0.0f)); + shadowAnimation[num].setDuration(150); + shadowAnimation[num].addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if (shadowAnimation[num] != null && shadowAnimation[num].equals(animation)) { + shadow[num].clearAnimation(); + if (!show) { + shadow[num].setVisibility(View.INVISIBLE); + } + shadowAnimation[num] = null; + } + } + + @Override + public void onAnimationCancel(Object animation) { + if (shadowAnimation[num] != null && shadowAnimation[num].equals(animation)) { + shadowAnimation[num] = null; + } + } + }); + shadowAnimation[num].start(); + } + } + + @Override + public void dismiss() { + super.dismiss(); + if (reqId != 0) { + ConnectionsManager.getInstance().cancelRequest(reqId, true); + reqId = 0; + } + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.emojiDidLoaded); + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.emojiDidLoaded) { + if (gridView != null) { + gridView.invalidateViews(); + } + if (StickerPreviewViewer.getInstance().isVisible()) { + StickerPreviewViewer.getInstance().close(); + } + StickerPreviewViewer.getInstance().reset(); + } + } + + private void setRightButton(View.OnClickListener onClickListener, String title, int color, boolean showCircle) { + if (title == null) { + pickerBottomLayout.doneButton.setVisibility(View.GONE); + } else { + pickerBottomLayout.doneButton.setVisibility(View.VISIBLE); + if (showCircle) { + pickerBottomLayout.doneButtonBadgeTextView.setVisibility(View.VISIBLE); + pickerBottomLayout.doneButtonBadgeTextView.setText(String.format("%d", stickerSet.documents.size())); + } else { + pickerBottomLayout.doneButtonBadgeTextView.setVisibility(View.GONE); + } + pickerBottomLayout.doneButtonTextView.setTextColor(color); + pickerBottomLayout.doneButtonTextView.setText(title.toUpperCase()); + pickerBottomLayout.doneButton.setOnClickListener(onClickListener); + } + } + + private class GridAdapter extends RecyclerView.Adapter { + + Context context; + + public GridAdapter(Context context) { + this.context = context; + } + + @Override + public int getItemCount() { + return stickerSet != null ? stickerSet.documents.size() : 0; + } + + private class Holder extends RecyclerView.ViewHolder { + + public Holder(View itemView) { + super(itemView); + } + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = new StickerEmojiCell(context); + view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, AndroidUtilities.dp(82))); + return new Holder(view); + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + ((StickerEmojiCell) holder.itemView).setSticker(stickerSet.documents.get(position), true); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java index e50a0c93..0f1b10a6 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/Switch.java @@ -393,6 +393,7 @@ public class Switch extends CompoundButton { protected void onAttachedToWindow() { super.onAttachedToWindow(); attachedToWindow = true; + requestLayout(); } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/TypingDotsDrawable.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/TypingDotsDrawable.java index 1663d174..c9744e32 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/Components/TypingDotsDrawable.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/TypingDotsDrawable.java @@ -17,6 +17,7 @@ import android.view.animation.DecelerateInterpolator; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; +import org.telegram.ui.ActionBar.Theme; public class TypingDotsDrawable extends Drawable { @@ -31,7 +32,7 @@ public class TypingDotsDrawable extends Drawable { public TypingDotsDrawable() { super(); - //paint.setColor(0xffd7e8f7); + //paint.setColor(Theme.ACTION_BAR_SUBTITLE_COLOR); SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); paint.setColor(themePrefs.getInt("chatTypingColor",themePrefs.getInt("chatStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40)))); } @@ -94,9 +95,9 @@ public class TypingDotsDrawable extends Drawable { public void draw(Canvas canvas) { int y; if (isChat) { - y = AndroidUtilities.dp(6); + y = AndroidUtilities.dp(8.3f) + getBounds().top; } else { - y = AndroidUtilities.dp(7); + y = AndroidUtilities.dp(9) + getBounds().top; } canvas.drawCircle(AndroidUtilities.dp(3), y, scales[0] * AndroidUtilities.density, paint); canvas.drawCircle(AndroidUtilities.dp(9), y, scales[1] * AndroidUtilities.density, paint); @@ -128,6 +129,6 @@ public class TypingDotsDrawable extends Drawable { @Override public int getIntrinsicHeight() { - return AndroidUtilities.dp(10); + return AndroidUtilities.dp(18); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanBotCommand.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanBotCommand.java new file mode 100644 index 00000000..367cdb41 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanBotCommand.java @@ -0,0 +1,37 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.content.SharedPreferences; +import android.text.TextPaint; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.ui.ActionBar.Theme; + + +public class URLSpanBotCommand extends URLSpanNoUnderline { + + public static boolean enabled = true; + + public URLSpanBotCommand(String url) { + super(url); + } + + @Override + public void updateDrawState(TextPaint ds) { + super.updateDrawState(ds); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int def = themePrefs.getInt("chatCommandColor", themePrefs.getInt("themeColor", AndroidUtilities.defColor)); + boolean check = themePrefs.getBoolean("chatCommandColorCheck", false); + //ds.setColor(enabled ? Theme.MSG_LINK_TEXT_COLOR : Theme.MSG_TEXT_COLOR); + if(enabled && check)ds.setColor(def); + ds.setUnderlineText(false); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderlineBold.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderlineBold.java new file mode 100644 index 00000000..5660d187 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanNoUnderlineBold.java @@ -0,0 +1,26 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.text.TextPaint; + +import org.telegram.messenger.AndroidUtilities; + +public class URLSpanNoUnderlineBold extends URLSpanNoUnderline { + public URLSpanNoUnderlineBold(String url) { + super(url); + } + + @Override + public void updateDrawState(TextPaint ds) { + super.updateDrawState(ds); + ds.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + ds.setUnderlineText(false); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanReplacement.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanReplacement.java new file mode 100644 index 00000000..cb0b291b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/URLSpanReplacement.java @@ -0,0 +1,18 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.text.style.URLSpan; + +public class URLSpanReplacement extends URLSpan { + + public URLSpanReplacement(String url) { + super(url); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/Components/WebFrameLayout.java b/TMessagesProj/src/main/java/org/telegram/ui/Components/WebFrameLayout.java new file mode 100644 index 00000000..81cf1346 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/Components/WebFrameLayout.java @@ -0,0 +1,390 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui.Components; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.net.Uri; +import android.os.Build; +import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.CookieManager; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebViewClient; +import android.widget.FrameLayout; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.messenger.browser.Browser; +import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.Theme; + +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class WebFrameLayout extends FrameLayout { + + private WebView webView; + private BottomSheet dialog; + private View customView; + private FrameLayout fullscreenVideoContainer; + private WebChromeClient.CustomViewCallback customViewCallback; + private ProgressBar progressBar; + + private int width; + private int height; + private String openUrl; + private boolean hasDescription; + private String embedUrl; + + final static Pattern youtubeIdRegex = Pattern.compile("(?:youtube(?:-nocookie)?\\.com\\/(?:[^\\/\\n\\s]+\\/\\S+\\/|(?:v|e(?:mbed)?)\\/|\\S*?[?&]v=)|youtu\\.be\\/)([a-zA-Z0-9_-]{11})"); + private final String youtubeFrame = "" + + "
" + + "
" + + "
" + + " " + + " " + + "" + + ""; + @SuppressLint("SetJavaScriptEnabled") + public WebFrameLayout(Context context, final BottomSheet parentDialog, String title, String descripton, String originalUrl, final String url, int w, int h) { + super(context); + embedUrl = url; + if (embedUrl.toLowerCase().contains("youtube")) { + //embedUrl += "&enablejsapi=1"; + } + hasDescription = descripton != null && descripton.length() > 0; + openUrl = originalUrl; + width = w; + height = h; + if (width == 0 || height == 0) { + width = AndroidUtilities.displaySize.x; + height = AndroidUtilities.displaySize.y / 2; + } + dialog = parentDialog; + + fullscreenVideoContainer = new FrameLayout(context); + fullscreenVideoContainer.setBackgroundColor(0xff000000); + if (Build.VERSION.SDK_INT >= 21) { + fullscreenVideoContainer.setFitsSystemWindows(true); + } + parentDialog.setApplyTopPadding(false); + parentDialog.setApplyBottomPadding(false); + dialog.getContainer().addView(fullscreenVideoContainer, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + fullscreenVideoContainer.setVisibility(INVISIBLE); + + /*LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 32, Gravity.LEFT | Gravity.TOP)); + + + + */ + + webView = new WebView(context); + webView.getSettings().setJavaScriptEnabled(true); + webView.getSettings().setDomStorageEnabled(true); + if (Build.VERSION.SDK_INT >= 17) { + webView.getSettings().setMediaPlaybackRequiresUserGesture(false); + } + + String userAgent = webView.getSettings().getUserAgentString(); + if (userAgent != null) { + userAgent = userAgent.replace("Android", ""); + webView.getSettings().setUserAgentString(userAgent); + } + if (Build.VERSION.SDK_INT >= 21) { + webView.getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW); + CookieManager cookieManager = CookieManager.getInstance(); + cookieManager.setAcceptThirdPartyCookies(webView, true); + } + + webView.setWebChromeClient(new WebChromeClient() { + + @Override + public void onShowCustomView(View view, int requestedOrientation, CustomViewCallback callback) { + onShowCustomView(view, callback); + } + + @Override + public void onShowCustomView(View view, CustomViewCallback callback) { + if (customView != null) { + callback.onCustomViewHidden(); + return; + } + customView = view; + if (dialog != null) { + dialog.getSheetContainer().setVisibility(INVISIBLE); + fullscreenVideoContainer.setVisibility(VISIBLE); + fullscreenVideoContainer.addView(view, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + } + customViewCallback = callback; + } + + @Override + public void onHideCustomView() { + super.onHideCustomView(); + if (customView == null) { + return; + } + if (dialog != null) { + dialog.getSheetContainer().setVisibility(VISIBLE); + fullscreenVideoContainer.setVisibility(INVISIBLE); + fullscreenVideoContainer.removeView(customView); + } + if (customViewCallback != null && !customViewCallback.getClass().getName().contains(".chromium.")) { + customViewCallback.onCustomViewHidden(); + } + customView = null; + } + }); + + webView.setWebViewClient(new WebViewClient() { + @Override + public void onLoadResource(WebView view, String url) { + super.onLoadResource(view, url); + } + + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + progressBar.setVisibility(INVISIBLE); + } + }); + + addView(webView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 48 + 36 + (hasDescription ? 22 : 0))); + + progressBar = new ProgressBar(context); + addView(progressBar, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER, 0, 0, 0, (48 + 36 + (hasDescription ? 22 : 0)) / 2)); + + + TextView textView; + + if (hasDescription) { + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setTextColor(0xff222222); + textView.setText(descripton); + textView.setSingleLine(true); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 48 + 9 + 20)); + } + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setTextColor(0xff8a8a8a); + textView.setText(title); + textView.setSingleLine(true); + textView.setEllipsize(TextUtils.TruncateAt.END); + textView.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); + addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.BOTTOM, 0, 0, 0, 48 + 9)); + + View lineView = new View(context); + lineView.setBackgroundColor(0xffdbdbdb); + addView(lineView, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1, Gravity.LEFT | Gravity.BOTTOM)); + ((LayoutParams) lineView.getLayoutParams()).bottomMargin = AndroidUtilities.dp(48); + + FrameLayout frameLayout = new FrameLayout(context); + frameLayout.setBackgroundColor(0xffffffff); + addView(frameLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.LEFT | Gravity.BOTTOM)); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setTextColor(0xff19a7e8); + textView.setGravity(Gravity.CENTER); + textView.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_AUDIO_SELECTOR_COLOR, false)); + textView.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); + textView.setText(LocaleController.getString("Close", R.string.Close).toUpperCase()); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); + textView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (dialog != null) { + dialog.dismiss(); + } + } + }); + + LinearLayout linearLayout = new LinearLayout(context); + linearLayout.setOrientation(LinearLayout.HORIZONTAL); + frameLayout.addView(linearLayout, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setTextColor(0xff19a7e8); + textView.setGravity(Gravity.CENTER); + textView.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_AUDIO_SELECTOR_COLOR, false)); + textView.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); + textView.setText(LocaleController.getString("Copy", R.string.Copy).toUpperCase()); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + linearLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); + textView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + try { + if (Build.VERSION.SDK_INT < 11) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(openUrl); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", openUrl); + clipboard.setPrimaryClip(clip); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + Toast.makeText(getContext(), LocaleController.getString("LinkCopied", R.string.LinkCopied), Toast.LENGTH_SHORT).show(); + if (dialog != null) { + dialog.dismiss(); + } + } + }); + + textView = new TextView(context); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + textView.setTextColor(0xff19a7e8); + textView.setGravity(Gravity.CENTER); + textView.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_AUDIO_SELECTOR_COLOR, false)); + textView.setPadding(AndroidUtilities.dp(18), 0, AndroidUtilities.dp(18), 0); + textView.setText(LocaleController.getString("OpenInBrowser", R.string.OpenInBrowser).toUpperCase()); + textView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); + linearLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); + textView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + Browser.openUrl(getContext(), openUrl); + if (dialog != null) { + dialog.dismiss(); + } + } + }); + + setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + + parentDialog.setDelegate(new BottomSheet.BottomSheetDelegate() { + + @Override + public void onOpenAnimationEnd() { + HashMap args = new HashMap<>(); + args.put("Referer", "http://youtube.com"); + boolean ok = false; + try { + Uri uri = Uri.parse(openUrl); + String host = uri.getHost().toLowerCase(); + if (host != null && host.endsWith("youtube.com") || host.endsWith("youtu.be")) { + Matcher matcher = youtubeIdRegex.matcher(openUrl); + String id = null; + if (matcher.find()) { + id = matcher.group(1); + } + if (id != null) { + ok = true; + webView.loadDataWithBaseURL("http://youtube.com", String.format(youtubeFrame, id), "text/html", "UTF-8", "http://youtube.com"); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (!ok) { + try { + webView.loadUrl(embedUrl, args); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + }); + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + try { + removeView(webView); + webView.stopLoading(); + webView.loadUrl("about:blank"); + webView.destroy(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int parentWidth = MeasureSpec.getSize(widthMeasureSpec); + float scale = width / parentWidth; + int h = (int) Math.min(height / scale, AndroidUtilities.displaySize.y / 2); + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h + AndroidUtilities.dp(48 + 36 + (hasDescription ? 22 : 0)) + 1, MeasureSpec.EXACTLY)); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java index 2719ce94..c4a0da7b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactAddActivity.java @@ -98,6 +98,8 @@ public class ContactAddActivity extends BaseFragment implements NotificationCent user.last_name = lastNameField.getText().toString(); ContactsController.getInstance().addContact(user); finishFragment(); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + preferences.edit().putInt("spam3_" + user_id, 1).commit(); NotificationCenter.getInstance().postNotificationName(NotificationCenter.updateInterfaces, MessagesController.UPDATE_MASK_NAME); } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java index 8cfb3479..191c2e5a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ContactsActivity.java @@ -48,6 +48,7 @@ import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.SecretChatHelper; +import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; import org.telegram.messenger.Utilities; import org.telegram.tgnet.TLRPC; @@ -59,6 +60,7 @@ import org.telegram.ui.Adapters.BaseSectionsAdapter; import org.telegram.ui.Adapters.ContactsAdapter; import org.telegram.ui.Adapters.SearchAdapter; import org.telegram.ui.Cells.UserCell; +import org.telegram.ui.Components.Glow; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.LetterSectionsListView; @@ -266,6 +268,9 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter frameLayout.setLayoutParams(layoutParams1); listView = new LetterSectionsListView(context); + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + int hColor = themePrefs.getInt("contactsHeaderColor", def); + Glow.setEdgeGlowColor(listView, hColor); listView.setEmptyView(emptyTextLayout); listView.setVerticalScrollBarEnabled(false); listView.setDivider(null); @@ -304,14 +309,19 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter didSelectResult(user, true, null); } else { if (createSecretChat) { + if (user.id == UserConfig.getClientUserId()) { + return; + } creatingChat = true; SecretChatHelper.getInstance().startSecretChat(getParentActivity(), user); } else { Bundle args = new Bundle(); args.putInt("user_id", user.id); + if (MessagesController.checkCanOpenChat(args, ContactsActivity.this)) { presentFragment(new ChatActivity(args), true); } } + } } else { int section = listViewAdapter.getSectionForPosition(i); int row = listViewAdapter.getPositionInSectionForPosition(i); @@ -345,6 +355,7 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter args.putBoolean("onlyUsers", true); args.putBoolean("destroyAfterSelect", true); args.putBoolean("createSecretChat", true); + args.putBoolean("allowBots", false); presentFragment(new ContactsActivity(args), false); } else if (row == 2) { if (!MessagesController.isFeatureEnabled("broadcast_create", ContactsActivity.this)) { @@ -378,9 +389,11 @@ public class ContactsActivity extends BaseFragment implements NotificationCenter } else { Bundle args = new Bundle(); args.putInt("user_id", user.id); + if (MessagesController.checkCanOpenChat(args, ContactsActivity.this)) { presentFragment(new ChatActivity(args), true); } } + } } else if (item instanceof ContactsController.Contact) { ContactsController.Contact contact = (ContactsController.Contact) item; String usePhone = null; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ConvertGroupActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ConvertGroupActivity.java new file mode 100644 index 00000000..3af4bb4c --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ConvertGroupActivity.java @@ -0,0 +1,216 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.FrameLayout; +import android.widget.ListView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Adapters.BaseFragmentAdapter; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Cells.TextSettingsCell; +import org.telegram.ui.Components.LayoutHelper; + +public class ConvertGroupActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + private ListAdapter listAdapter; + + private int convertInfoRow; + private int convertRow; + private int convertDetailRow; + private int rowCount; + + private int chat_id; + + public ConvertGroupActivity(Bundle args) { + super(args); + chat_id = args.getInt("chat_id"); + } + + @Override + public boolean onFragmentCreate() { + super.onFragmentCreate(); + + convertInfoRow = rowCount++; + convertRow = rowCount++; + convertDetailRow = rowCount++; + + NotificationCenter.getInstance().addObserver(this, NotificationCenter.closeChats); + + return true; + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.closeChats); + } + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(LocaleController.getString("ConvertGroup", R.string.ConvertGroup)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + + listAdapter = new ListAdapter(context); + + fragmentView = new FrameLayout(context); + FrameLayout frameLayout = (FrameLayout) fragmentView; + frameLayout.setBackgroundColor(0xfff0f0f0); + + ListView listView = new ListView(context); + listView.setDivider(null); + listView.setDividerHeight(0); + listView.setVerticalScrollBarEnabled(false); + listView.setDrawSelectorOnTop(true); + frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + listView.setAdapter(listAdapter); + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(final AdapterView adapterView, View view, final int i, long l) { + if (i == convertRow) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("ConvertGroupAlert", R.string.ConvertGroupAlert)); + builder.setTitle(LocaleController.getString("ConvertGroupAlertWarning", R.string.ConvertGroupAlertWarning)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + MessagesController.getInstance().convertToMegaGroup(getParentActivity(), chat_id); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } + } + }); + + return fragmentView; + } + + @Override + public void onResume() { + super.onResume(); + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.closeChats) { + removeSelfFromStack(); + } + } + + private class ListAdapter extends BaseFragmentAdapter { + private Context mContext; + + public ListAdapter(Context context) { + mContext = context; + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public boolean isEnabled(int i) { + return i == convertRow; + } + + @Override + public int getCount() { + return rowCount; + } + + @Override + public Object getItem(int i) { + return null; + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public boolean hasStableIds() { + return false; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + int type = getItemViewType(i); + if (type == 0) { + if (view == null) { + view = new TextSettingsCell(mContext); + view.setBackgroundColor(0xffffffff); + } + TextSettingsCell textCell = (TextSettingsCell) view; + if (i == convertRow) { + textCell.setText(LocaleController.getString("ConvertGroup", R.string.ConvertGroup), false); + } + } else if (type == 1) { + if (view == null) { + view = new TextInfoPrivacyCell(mContext); + } + if (i == convertInfoRow) { + ((TextInfoPrivacyCell) view).setText(AndroidUtilities.replaceTags(LocaleController.getString("ConvertGroupInfo2", R.string.ConvertGroupInfo2))); + view.setBackgroundResource(R.drawable.greydivider); + } else if (i == convertDetailRow) { + ((TextInfoPrivacyCell) view).setText(AndroidUtilities.replaceTags(LocaleController.getString("ConvertGroupInfo3", R.string.ConvertGroupInfo3))); + view.setBackgroundResource(R.drawable.greydivider_bottom); + } + } + return view; + } + + @Override + public int getItemViewType(int i) { + if (i == convertRow) { + return 0; + } else if (i == convertInfoRow || i == convertDetailRow) { + return 1; + } + return 0; + } + + @Override + public int getViewTypeCount() { + return 2; + } + + @Override + public boolean isEmpty() { + return false; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java new file mode 100644 index 00000000..3609825f --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/DialogsActivity.java @@ -0,0 +1,2964 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.Manifest; +import android.animation.ObjectAnimator; +import android.animation.StateListAnimator; +import android.annotation.SuppressLint; +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.ActivityManager; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Outline; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffXfermode; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.GradientDrawable; +import android.os.Build; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewOutlineProvider; +import android.view.ViewTreeObserver; +import android.view.animation.AccelerateDecelerateInterpolator; +import android.widget.Button; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.ListView; +import android.widget.ProgressBar; +import android.widget.RelativeLayout; +import android.widget.TextView; +import android.widget.Toast; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.AnimationCompat.AnimatorListenerAdapterProxy; +import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; +import org.telegram.messenger.AnimationCompat.ViewProxy; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BuildConfig; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.ChatObject; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.ImageLoader; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.NotificationsController; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.UserObject; +import org.telegram.messenger.support.widget.LinearLayoutManager; +import org.telegram.messenger.support.widget.RecyclerView; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.MenuDrawable; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Adapters.DialogsAdapter; +import org.telegram.ui.Adapters.DialogsSearchAdapter; +import org.telegram.ui.Cells.DialogCell; +import org.telegram.ui.Cells.ProfileSearchCell; +import org.telegram.ui.Cells.UserCell; +import org.telegram.ui.Components.AlertsCreator; +import org.telegram.ui.Components.AvatarDrawable; +import org.telegram.ui.Components.BackupImageView; +import org.telegram.ui.Components.EmptyTextProgressView; +import org.telegram.ui.Components.Favourite; +import org.telegram.ui.Components.Glow; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.PlayerView; +import org.telegram.ui.Components.RecyclerListView; + +import java.util.ArrayList; +import java.util.Timer; +import java.util.TimerTask; + +public class DialogsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate,PhotoViewer.PhotoViewerProvider { + + private RecyclerListView listView; + private LinearLayoutManager layoutManager; + private DialogsAdapter dialogsAdapter; + private DialogsSearchAdapter dialogsSearchAdapter; + private EmptyTextProgressView searchEmptyView; + private ProgressBar progressView; + private LinearLayout emptyView; + private ActionBarMenuItem passcodeItem; + private ImageView floatingButton; + + private AlertDialog permissionDialog; + + private int prevPosition; + private int prevTop; + private boolean scrollUpdated; + private boolean floatingHidden; + private final AccelerateDecelerateInterpolator floatingInterpolator = new AccelerateDecelerateInterpolator(); + + private boolean checkPermission = true; + + private String selectAlertString; + private String selectAlertStringGroup; + private String addToGroupAlertString; + private int dialogsType; + + private static boolean dialogsLoaded; + private boolean searching; + private boolean searchWas; + private boolean onlySelect; + private long selectedDialog; + private String searchString; + private long openedDialogId; + + private DialogsActivityDelegate delegate; + + private float touchPositionDP; + private int user_id = 0; + private int chat_id = 0; + private BackupImageView avatarImage; + + private Button toastBtn; + + private FrameLayout tabsView; + private LinearLayout tabsLayout; + private int tabsHeight; + private ImageView allTab; + private ImageView usersTab; + private ImageView groupsTab; + private ImageView superGroupsTab; + private ImageView channelsTab; + private ImageView botsTab; + private ImageView favsTab; + private TextView allCounter; + private TextView usersCounter; + private TextView groupsCounter; + private TextView sGroupsCounter; + private TextView botsCounter; + private TextView channelsCounter; + private TextView favsCounter; + private boolean countSize; + + private boolean hideTabs; + private int selectedTab; + private DialogsAdapter dialogsBackupAdapter; + private boolean tabsHidden; + private boolean disableAnimation; + + private DialogsOnTouch onTouchListener = null; + //private DisplayMetrics displayMetrics; + + public interface DialogsActivityDelegate { + void didSelectDialog(DialogsActivity fragment, long dialog_id, boolean param); + } + + public DialogsActivity(Bundle args) { + super(args); + } + + @Override + public boolean onFragmentCreate() { + super.onFragmentCreate(); + + if (getArguments() != null) { + onlySelect = arguments.getBoolean("onlySelect", false); + dialogsType = arguments.getInt("dialogsType", 0); + selectAlertString = arguments.getString("selectAlertString"); + selectAlertStringGroup = arguments.getString("selectAlertStringGroup"); + addToGroupAlertString = arguments.getString("addToGroupAlertString"); + } + + if (searchString == null) { + NotificationCenter.getInstance().addObserver(this, NotificationCenter.dialogsNeedReload); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.emojiDidLoaded); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.updateInterfaces); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.encryptedChatUpdated); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.contactsDidLoaded); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.appDidLogout); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.openedChatChanged); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.notificationsSettingsUpdated); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.messageReceivedByAck); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.messageReceivedByServer); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.messageSendError); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.didSetPasscode); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.needReloadRecentDialogsSearch); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.didLoadedReplyMessages); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.refreshTabs); + } + + + if (!dialogsLoaded) { + MessagesController.getInstance().loadDialogs(0, 100, true); + ContactsController.getInstance().checkInviteText(); + dialogsLoaded = true; + } + return true; + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + if (searchString == null) { + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.dialogsNeedReload); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.emojiDidLoaded); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.updateInterfaces); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.encryptedChatUpdated); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.contactsDidLoaded); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.appDidLogout); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.openedChatChanged); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.notificationsSettingsUpdated); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messageReceivedByAck); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messageReceivedByServer); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.messageSendError); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didSetPasscode); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.needReloadRecentDialogsSearch); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didLoadedReplyMessages); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.refreshTabs); + } + delegate = null; + } + + @Override + public View createView(final Context context) { + searching = false; + searchWas = false; + + Theme.loadResources(context); + + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int iconColor = themePrefs.getInt("chatsHeaderIconsColor", 0xffffffff); + int tColor = themePrefs.getInt("chatsHeaderTitleColor", 0xffffffff); + avatarImage = new BackupImageView(context); + avatarImage.setRoundRadius(AndroidUtilities.dp(30)); + ActionBarMenu menu = actionBar.createMenu(); + if (!onlySelect && searchString == null) { + Drawable lock = getParentActivity().getResources().getDrawable(R.drawable.lock_close); + lock.setColorFilter(iconColor, PorterDuff.Mode.MULTIPLY); + passcodeItem = menu.addItem(1, lock); + updatePasscodeButton(); + } + //final ActionBarMenuItem item = menu.addItem(0, R.drawable.ic_ab_search).setIsSearchField(true).setActionBarMenuItemSearchListener(new ActionBarMenuItem.ActionBarMenuItemSearchListener() { + Drawable search = getParentActivity().getResources().getDrawable(R.drawable.ic_ab_search); + final ActionBarMenuItem item = menu.addItem(0, search).setIsSearchField(true).setActionBarMenuItemSearchListener(new ActionBarMenuItem.ActionBarMenuItemSearchListener() { + @Override + public void onSearchExpand() { + //plus + refreshTabAndListViews(true); + // + searching = true; + if (listView != null) { + if (searchString != null) { + listView.setEmptyView(searchEmptyView); + progressView.setVisibility(View.GONE); + emptyView.setVisibility(View.GONE); + } + if (!onlySelect) { + floatingButton.setVisibility(View.GONE); + } + } + updatePasscodeButton(); + } + + @Override + public boolean canCollapseSearch() { + if (searchString != null) { + finishFragment(); + return false; + } + return true; + } + + @Override + public void onSearchCollapse() { + //plus + refreshTabAndListViews(false); + // + searching = false; + searchWas = false; + if (listView != null) { + searchEmptyView.setVisibility(View.GONE); + if (MessagesController.getInstance().loadingDialogs && MessagesController.getInstance().dialogs.isEmpty()) { + emptyView.setVisibility(View.GONE); + listView.setEmptyView(progressView); + } else { + progressView.setVisibility(View.GONE); + listView.setEmptyView(emptyView); + } + if (!onlySelect) { + floatingButton.setVisibility(View.VISIBLE); + floatingHidden = true; + ViewProxy.setTranslationY(floatingButton, AndroidUtilities.dp(100)); + hideFloatingButton(false); + } + if (listView.getAdapter() != dialogsAdapter) { + listView.setAdapter(dialogsAdapter); + dialogsAdapter.notifyDataSetChanged(); + } + } + if (dialogsSearchAdapter != null) { + dialogsSearchAdapter.searchDialogs(null); + } + updatePasscodeButton(); + } + + @Override + public void onTextChanged(EditText editText) { + String text = editText.getText().toString(); + if (text.length() != 0 || dialogsSearchAdapter != null && dialogsSearchAdapter.hasRecentRearch()) { + searchWas = true; + if (dialogsSearchAdapter != null && listView.getAdapter() != dialogsSearchAdapter) { + listView.setAdapter(dialogsSearchAdapter); + dialogsSearchAdapter.notifyDataSetChanged(); + } + if (searchEmptyView != null && listView.getEmptyView() != searchEmptyView) { + emptyView.setVisibility(View.GONE); + progressView.setVisibility(View.GONE); + searchEmptyView.showTextView(); + listView.setEmptyView(searchEmptyView); + } + } + if (dialogsSearchAdapter != null) { + dialogsSearchAdapter.searchDialogs(text); + } + updateListBG(); + } + }); + item.getSearchField().setHint(LocaleController.getString("Search", R.string.Search)); + + if(tColor != 0xffffffff) { + item.getSearchField().setTextColor(tColor); + item.getSearchField().setHintTextColor(AndroidUtilities.getIntAlphaColor("chatsHeaderTitleColor", 0xffffffff, 0.5f)); + } + Drawable clear = getParentActivity().getResources().getDrawable(R.drawable.ic_close_white); + if(clear != null)clear.setColorFilter(iconColor, PorterDuff.Mode.MULTIPLY); + item.getClearButton().setImageDrawable(clear); + if (onlySelect) { + //actionBar.setBackButtonImage(R.drawable.ic_ab_back); + Drawable back = getParentActivity().getResources().getDrawable(R.drawable.ic_ab_back); + if (back != null)back.setColorFilter(iconColor, PorterDuff.Mode.MULTIPLY); + actionBar.setBackButtonDrawable(back); + actionBar.setTitle(LocaleController.getString("SelectChat", R.string.SelectChat)); + } else { + if (searchString != null) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + } else { + actionBar.setBackButtonDrawable(new MenuDrawable()); + } + if (BuildVars.DEBUG_VERSION) { + actionBar.setTitle(LocaleController.getString("AppNameBeta", R.string.AppNameBeta)); + } else { + actionBar.setTitle(LocaleController.getString("AppName", R.string.AppName)); + } + } + actionBar.setAllowOverlayTitle(true); + + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + if (onlySelect) { + finishFragment(); + } else if (parentLayout != null) { + // + //if (!hideTabs) { + // parentLayout.getDrawerLayoutContainer().setAllowOpenDrawer(true, false); + //} + // + parentLayout.getDrawerLayoutContainer().openDrawer(false); + } + } else if (id == 1) { + UserConfig.appLocked = !UserConfig.appLocked; + UserConfig.saveConfig(false); + updatePasscodeButton(); + } + } + }); + + paintHeader(false); + + FrameLayout frameLayout = new FrameLayout(context); + fragmentView = frameLayout; + + listView = new RecyclerListView(context); + listView.setVerticalScrollBarEnabled(true); + listView.setItemAnimator(null); + listView.setInstantClick(true); + listView.setLayoutAnimation(null); + layoutManager = new LinearLayoutManager(context) { + @Override + public boolean supportsPredictiveItemAnimations() { + return false; + } + }; + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + listView.setLayoutManager(layoutManager); + if (Build.VERSION.SDK_INT >= 11) { + listView.setVerticalScrollbarPosition(LocaleController.isRTL ? ListView.SCROLLBAR_POSITION_LEFT : ListView.SCROLLBAR_POSITION_RIGHT); + } + frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + onTouchListener = new DialogsOnTouch(context); + listView.setOnTouchListener(onTouchListener); + + listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { + @Override + public void onItemClick(View view, int position) { + if (listView == null || listView.getAdapter() == null) { + return; + } + long dialog_id = 0; + int message_id = 0; + RecyclerView.Adapter adapter = listView.getAdapter(); + if (adapter == dialogsAdapter) { + TLRPC.Dialog dialog = dialogsAdapter.getItem(position); + if (dialog == null) { + return; + } + dialog_id = dialog.id; + } else if (adapter == dialogsSearchAdapter) { + Object obj = dialogsSearchAdapter.getItem(position); + if (obj instanceof TLRPC.User) { + dialog_id = ((TLRPC.User) obj).id; + if (dialogsSearchAdapter.isGlobalSearch(position)) { + ArrayList users = new ArrayList<>(); + users.add((TLRPC.User) obj); + MessagesController.getInstance().putUsers(users, false); + MessagesStorage.getInstance().putUsersAndChats(users, null, false, true); + } + if (!onlySelect) { + dialogsSearchAdapter.putRecentSearch(dialog_id, (TLRPC.User) obj); + } + } else if (obj instanceof TLRPC.Chat) { + if (dialogsSearchAdapter.isGlobalSearch(position)) { + ArrayList chats = new ArrayList<>(); + chats.add((TLRPC.Chat) obj); + MessagesController.getInstance().putChats(chats, false); + MessagesStorage.getInstance().putUsersAndChats(null, chats, false, true); + } + if (((TLRPC.Chat) obj).id > 0) { + dialog_id = -((TLRPC.Chat) obj).id; + } else { + dialog_id = AndroidUtilities.makeBroadcastId(((TLRPC.Chat) obj).id); + } + if (!onlySelect) { + dialogsSearchAdapter.putRecentSearch(dialog_id, (TLRPC.Chat) obj); + } + } else if (obj instanceof TLRPC.EncryptedChat) { + dialog_id = ((long) ((TLRPC.EncryptedChat) obj).id) << 32; + if (!onlySelect) { + dialogsSearchAdapter.putRecentSearch(dialog_id, (TLRPC.EncryptedChat) obj); + } + } else if (obj instanceof MessageObject) { + MessageObject messageObject = (MessageObject) obj; + dialog_id = messageObject.getDialogId(); + message_id = messageObject.getId(); + dialogsSearchAdapter.addHashtagsFromMessage(dialogsSearchAdapter.getLastSearchString()); + } else if (obj instanceof String) { + actionBar.openSearchField((String) obj); + } + } + + if (dialog_id == 0) { + return; + } + + if (touchPositionDP < 65) { + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + //if(preferences.getInt("dialogsClickOnGroupPic", 0) == 2)MessagesController.getInstance().loadChatInfo(chat_id, null, false); + user_id = 0; + chat_id = 0; + int lower_part = (int) dialog_id; + int high_id = (int) (dialog_id >> 32); + + if (lower_part != 0) { + if (high_id == 1) { + chat_id = lower_part; + } else { + if (lower_part > 0) { + user_id = lower_part; + } else if (lower_part < 0) { + chat_id = -lower_part; + } + } + } else { + TLRPC.EncryptedChat chat = MessagesController.getInstance().getEncryptedChat(high_id); + user_id = chat.user_id; + } + + if (user_id != 0) { + int picClick = plusPreferences.getInt("dialogsClickOnPic", 0); + if (picClick == 2) { + Bundle args = new Bundle(); + args.putInt("user_id", user_id); + presentFragment(new ProfileActivity(args)); + return; + } else if (picClick == 1) { + TLRPC.User user = MessagesController.getInstance().getUser(user_id); + if (user.photo != null && user.photo.photo_big != null) { + PhotoViewer.getInstance().setParentActivity(getParentActivity()); + PhotoViewer.getInstance().openPhoto(user.photo.photo_big, DialogsActivity.this); + } + return; + } + + } else if (chat_id != 0) { + int picClick = plusPreferences.getInt("dialogsClickOnGroupPic", 0); + if (picClick == 2) { + MessagesController.getInstance().loadChatInfo(chat_id, null, false); + Bundle args = new Bundle(); + args.putInt("chat_id", chat_id); + ProfileActivity fragment = new ProfileActivity(args); + presentFragment(fragment); + return; + } else if (picClick == 1) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(chat_id); + if (chat.photo != null && chat.photo.photo_big != null) { + PhotoViewer.getInstance().setParentActivity(getParentActivity()); + PhotoViewer.getInstance().openPhoto(chat.photo.photo_big, DialogsActivity.this); + } + return; + } + } + } + + // + if (onlySelect) { + didSelectResult(dialog_id, true, false); + } else { + Bundle args = new Bundle(); + int lower_part = (int) dialog_id; + int high_id = (int) (dialog_id >> 32); + if (lower_part != 0) { + if (high_id == 1) { + args.putInt("chat_id", lower_part); + } else { + if (lower_part > 0) { + args.putInt("user_id", lower_part); + } else if (lower_part < 0) { + if (message_id != 0) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(-lower_part); + if (chat != null && chat.migrated_to != null) { + args.putInt("migrated_to", lower_part); + lower_part = -chat.migrated_to.channel_id; + } + } + args.putInt("chat_id", -lower_part); + } + } + } else { + args.putInt("enc_id", high_id); + } + if (message_id != 0) { + args.putInt("message_id", message_id); + } else { + if (actionBar != null) { + actionBar.closeSearchField(); + } + } + if (AndroidUtilities.isTablet()) { + if (openedDialogId == dialog_id && adapter != dialogsSearchAdapter) { + return; + } + if (dialogsAdapter != null) { + dialogsAdapter.setOpenedDialogId(openedDialogId = dialog_id); + updateVisibleRows(MessagesController.UPDATE_MASK_SELECT_DIALOG); + } + } + if (searchString != null) { + if (MessagesController.checkCanOpenChat(args, DialogsActivity.this)) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); + presentFragment(new ChatActivity(args)); + } + } else { + if (MessagesController.checkCanOpenChat(args, DialogsActivity.this)) { + presentFragment(new ChatActivity(args)); + } + } + } + } + }); + listView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { + @Override + public boolean onItemClick(View view, int position) { + if (onlySelect || searching && searchWas || getParentActivity() == null) { + if (searchWas && searching || dialogsSearchAdapter.isRecentSearchDisplayed()) { + RecyclerView.Adapter adapter = listView.getAdapter(); + if (adapter == dialogsSearchAdapter) { + Object item = dialogsSearchAdapter.getItem(position); + if (item instanceof String || dialogsSearchAdapter.isRecentSearchDisplayed()) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("ClearSearch", R.string.ClearSearch)); + builder.setPositiveButton(LocaleController.getString("ClearButton", R.string.ClearButton).toUpperCase(), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (dialogsSearchAdapter.isRecentSearchDisplayed()) { + dialogsSearchAdapter.clearRecentSearch(); + } else { + dialogsSearchAdapter.clearRecentHashtags(); + } + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + return true; + } + } + } + return false; + } + TLRPC.Dialog dialog; + ArrayList dialogs = getDialogsArray(); + if (position < 0 || position >= dialogs.size()) { + return false; + } + dialog = dialogs.get(position); + selectedDialog = dialog.id; + + BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); + int lower_id = (int) selectedDialog; + int high_id = (int) (selectedDialog >> 32); + + if (dialog instanceof TLRPC.TL_dialogChannel) { + final TLRPC.Chat chat = MessagesController.getInstance().getChat(-lower_id); + CharSequence items[]; + final boolean isFav = Favourite.isFavourite(dialog.id); + CharSequence cs2 = isFav ? LocaleController.getString("DeleteFromFavorites", R.string.DeleteFromFavorites) : LocaleController.getString("AddToFavorites", R.string.AddToFavorites); + int muted = MessagesController.getInstance().isDialogMuted(selectedDialog) ? R.drawable.mute_fixed : 0; + CharSequence cs = muted != 0 ? LocaleController.getString("UnmuteNotifications", R.string.UnmuteNotifications) : LocaleController.getString("MuteNotifications", R.string.MuteNotifications); + CharSequence csa = LocaleController.getString("AddShortcut", R.string.AddShortcut); + if (chat != null && chat.megagroup) { + items = new CharSequence[]{LocaleController.getString("ClearHistoryCache", R.string.ClearHistoryCache), chat == null || !chat.creator ? LocaleController.getString("LeaveMegaMenu", R.string.LeaveMegaMenu) : LocaleController.getString("DeleteMegaMenu", R.string.DeleteMegaMenu), cs, cs2, LocaleController.getString("MarkAsRead", R.string.MarkAsRead), csa}; + } else { + items = new CharSequence[]{LocaleController.getString("ClearHistoryCache", R.string.ClearHistoryCache), chat == null || !chat.creator ? LocaleController.getString("LeaveChannelMenu", R.string.LeaveChannelMenu) : LocaleController.getString("ChannelDeleteMenu", R.string.ChannelDeleteMenu), cs, cs2, LocaleController.getString("MarkAsRead", R.string.MarkAsRead), csa}; + } + + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, final int which) { + if (which == 3) { + TLRPC.Dialog dialg = MessagesController.getInstance().dialogs_dict.get(selectedDialog); + if (isFav) { + Favourite.deleteFavourite(selectedDialog); + MessagesController.getInstance().dialogsFavs.remove(dialg); + } else { + Favourite.addFavourite(selectedDialog); + MessagesController.getInstance().dialogsFavs.add(dialg); + } + if (dialogsType == 8) { + dialogsAdapter.notifyDataSetChanged(); + if(!hideTabs){ + updateTabs(); + } + } + unreadCount(MessagesController.getInstance().dialogsFavs, favsCounter); + } else if (which == 2) { + boolean muted = MessagesController.getInstance().isDialogMuted(selectedDialog); + if (!muted) { + showDialog(AlertsCreator.createMuteAlert(getParentActivity(), selectedDialog)); + } else { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("notify2_" + selectedDialog, 0); + MessagesStorage.getInstance().setDialogFlags(selectedDialog, 0); + editor.commit(); + TLRPC.Dialog dialg = MessagesController.getInstance().dialogs_dict.get(selectedDialog); + if (dialg != null) { + dialg.notify_settings = new TLRPC.TL_peerNotifySettings(); + } + NotificationsController.updateServerNotificationsSettings(selectedDialog); + } + } + // + else if (which == 4) { + markAsReadDialog(false); + } else if (which == 5) { + addShortcut(); + } + // + else { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + //builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setTitle(chat != null ? chat.title : LocaleController.getString("AppName", R.string.AppName)); + if (which == 0) { + if (chat != null && chat.megagroup) { + builder.setMessage(LocaleController.getString("AreYouSureClearHistorySuper", R.string.AreYouSureClearHistorySuper)); + } else { + builder.setMessage(LocaleController.getString("AreYouSureClearHistoryChannel", R.string.AreYouSureClearHistoryChannel)); + } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + MessagesController.getInstance().deleteDialog(selectedDialog, 2); + } + }); + } else { + if (chat != null && chat.megagroup) { + if (!chat.creator) { + builder.setMessage(LocaleController.getString("MegaLeaveAlert", R.string.MegaLeaveAlert)); + } else { + builder.setMessage(LocaleController.getString("MegaDeleteAlert", R.string.MegaDeleteAlert)); + } + } else { + if (chat == null || !chat.creator) { + builder.setMessage(LocaleController.getString("ChannelLeaveAlert", R.string.ChannelLeaveAlert)); + } else { + builder.setMessage(LocaleController.getString("ChannelDeleteAlert", R.string.ChannelDeleteAlert)); + } + } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + MessagesController.getInstance().deleteUserFromChat((int) -selectedDialog, UserConfig.getCurrentUser(), null); + if (AndroidUtilities.isTablet()) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats, selectedDialog); + } + } + }); + } + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } + } + }); + showDialog(builder.create()); + } else { + final boolean isChat = lower_id < 0 && high_id != 1; + int muted = MessagesController.getInstance().isDialogMuted(selectedDialog) ? R.drawable.mute_fixed : 0; + TLRPC.User user = null; + if (!isChat && lower_id > 0 && high_id != 1) { + user = MessagesController.getInstance().getUser(lower_id); + } + final boolean isBot = user != null && user.bot; + final boolean isFav = Favourite.isFavourite(dialog.id); + CharSequence cs = isFav ? LocaleController.getString("DeleteFavourite", R.string.DeleteFromFavorites) : LocaleController.getString("AddFavourite", R.string.AddToFavorites); + CharSequence csa = LocaleController.getString("AddShortcut", R.string.AddShortcut); + builder.setItems(new CharSequence[]{LocaleController.getString("ClearHistory", R.string.ClearHistory), + isChat ? LocaleController.getString("DeleteChat", R.string.DeleteChat) : + isBot ? LocaleController.getString("DeleteAndStop", R.string.DeleteAndStop) : LocaleController.getString("Delete", R.string.Delete), muted != 0 ? LocaleController.getString("UnmuteNotifications", R.string.UnmuteNotifications) : LocaleController.getString("MuteNotifications", R.string.MuteNotifications), cs, LocaleController.getString("MarkAsRead", R.string.MarkAsRead), csa}, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, final int which) { + if (which == 3) { + TLRPC.Dialog dialg = MessagesController.getInstance().dialogs_dict.get(selectedDialog); + if(isFav){ + Favourite.deleteFavourite(selectedDialog); + MessagesController.getInstance().dialogsFavs.remove(dialg); + }else{ + Favourite.addFavourite(selectedDialog); + MessagesController.getInstance().dialogsFavs.add(dialg); + } + if(dialogsType == 8){ + dialogsAdapter.notifyDataSetChanged(); + if(!hideTabs){ + updateTabs(); + } + } + unreadCount(MessagesController.getInstance().dialogsFavs, favsCounter); + } else if (which == 2) { + boolean muted = MessagesController.getInstance().isDialogMuted(selectedDialog); + if (!muted) { + showDialog(AlertsCreator.createMuteAlert(getParentActivity(), selectedDialog)); + } else { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("notify2_" + selectedDialog, 0); + MessagesStorage.getInstance().setDialogFlags(selectedDialog, 0); + editor.commit(); + TLRPC.Dialog dialg = MessagesController.getInstance().dialogs_dict.get(selectedDialog); + if (dialg != null) { + dialg.notify_settings = new TLRPC.TL_peerNotifySettings(); + } + NotificationsController.updateServerNotificationsSettings(selectedDialog); + } + }// + else if (which == 4) { + markAsReadDialog(false); + } else if (which == 5) { + addShortcut(); + } + // + else { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + //builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + TLRPC.Chat currentChat = MessagesController.getInstance().getChat((int) -selectedDialog); + TLRPC.User user = MessagesController.getInstance().getUser((int) selectedDialog); + String title = currentChat != null ? currentChat.title : user != null ? UserObject.getUserName(user) : LocaleController.getString("AppName", R.string.AppName); + builder.setTitle(title); + if (which == 0) { + builder.setMessage(LocaleController.getString("AreYouSureClearHistory", R.string.AreYouSureClearHistory)); + } else { + if (isChat) { + builder.setMessage(LocaleController.getString("AreYouSureDeleteAndExit", R.string.AreYouSureDeleteAndExit)); + } else { + builder.setMessage(LocaleController.getString("AreYouSureDeleteThisChat", R.string.AreYouSureDeleteThisChat)); + } + } + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (which != 0) { + if (isChat) { + TLRPC.Chat currentChat = MessagesController.getInstance().getChat((int) -selectedDialog); + if (currentChat != null && ChatObject.isNotInChat(currentChat)) { + MessagesController.getInstance().deleteDialog(selectedDialog, 0); + } else { + MessagesController.getInstance().deleteUserFromChat((int) -selectedDialog, MessagesController.getInstance().getUser(UserConfig.getClientUserId()), null); + } + } else { + MessagesController.getInstance().deleteDialog(selectedDialog, 0); + } + if (isBot) { + MessagesController.getInstance().blockUser((int) selectedDialog); + } + if (AndroidUtilities.isTablet()) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats, selectedDialog); + } + } else { + MessagesController.getInstance().deleteDialog(selectedDialog, 1); + } + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } + } + }); + showDialog(builder.create()); + } + return true; + } + }); + + searchEmptyView = new EmptyTextProgressView(context); + searchEmptyView.setVisibility(View.GONE); + searchEmptyView.setShowAtCenter(true); + searchEmptyView.setText(LocaleController.getString("NoResult", R.string.NoResult)); + frameLayout.addView(searchEmptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + emptyView = new LinearLayout(context); + emptyView.setOrientation(LinearLayout.VERTICAL); + emptyView.setVisibility(View.GONE); + emptyView.setGravity(Gravity.CENTER); + frameLayout.addView(emptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + //emptyView.setOnTouchListener(new View.OnTouchListener() { + // + // @Override + // public boolean onTouch(View v, MotionEvent event) { + // return true; + // } + //}); + emptyView.setOnTouchListener(onTouchListener); + TextView textView = new TextView(context); + textView.setText(LocaleController.getString("NoChats", R.string.NoChats)); + textView.setTextColor(0xff959595); + textView.setGravity(Gravity.CENTER); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 20); + emptyView.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); + + textView = new TextView(context); + String help = LocaleController.getString("NoChatsHelp", R.string.NoChatsHelp); + if (AndroidUtilities.isTablet() && !AndroidUtilities.isSmallTablet()) { + help = help.replace('\n', ' '); + } + textView.setText(help); + textView.setTextColor(0xff959595); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 15); + textView.setGravity(Gravity.CENTER); + textView.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(6), AndroidUtilities.dp(8), 0); + textView.setLineSpacing(AndroidUtilities.dp(2), 1); + emptyView.addView(textView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT)); + + progressView = new ProgressBar(context); + progressView.setVisibility(View.GONE); + frameLayout.addView(progressView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.CENTER)); + + floatingButton = new ImageView(context); + floatingButton.setVisibility(onlySelect ? View.GONE : View.VISIBLE); + floatingButton.setScaleType(ImageView.ScaleType.CENTER); + floatingButton.setBackgroundResource(R.drawable.floating_states); + floatingButton.setImageResource(R.drawable.floating_pencil); + if (Build.VERSION.SDK_INT >= 21) { + StateListAnimator animator = new StateListAnimator(); + animator.addState(new int[]{android.R.attr.state_pressed}, ObjectAnimator.ofFloat(floatingButton, "translationZ", AndroidUtilities.dp(2), AndroidUtilities.dp(4)).setDuration(200)); + animator.addState(new int[]{}, ObjectAnimator.ofFloat(floatingButton, "translationZ", AndroidUtilities.dp(4), AndroidUtilities.dp(2)).setDuration(200)); + floatingButton.setStateListAnimator(animator); + floatingButton.setOutlineProvider(new ViewOutlineProvider() { + @SuppressLint("NewApi") + @Override + public void getOutline(View view, Outline outline) { + outline.setOval(0, 0, AndroidUtilities.dp(56), AndroidUtilities.dp(56)); + } + }); + } + frameLayout.addView(floatingButton, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, (LocaleController.isRTL ? Gravity.LEFT : Gravity.RIGHT) | Gravity.BOTTOM, LocaleController.isRTL ? 14 : 0, 0, LocaleController.isRTL ? 0 : 14, 14)); + floatingButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Bundle args = new Bundle(); + args.putBoolean("destroyAfterSelect", true); + presentFragment(new ContactsActivity(args)); + } + }); + + tabsView = new FrameLayout(context); + createTabs(context); + //if(dialogsType == 0 || dialogsType > 2){ + frameLayout.addView(tabsView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, tabsHeight, Gravity.TOP, 0, 0, 0, 0)); + //} + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + final int hColor = themePrefs.getInt("chatsHeaderColor", def); + listView.setOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + if (newState == RecyclerView.SCROLL_STATE_DRAGGING && searching && searchWas) { + AndroidUtilities.hideKeyboard(getParentActivity().getCurrentFocus()); + } + Glow.setEdgeGlowColor(listView, hColor); + } + + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + int firstVisibleItem = layoutManager.findFirstVisibleItemPosition(); + int visibleItemCount = Math.abs(layoutManager.findLastVisibleItemPosition() - firstVisibleItem) + 1; + int totalItemCount = recyclerView.getAdapter().getItemCount(); + + if (searching && searchWas) { + if (visibleItemCount > 0 && layoutManager.findLastVisibleItemPosition() == totalItemCount - 1 && !dialogsSearchAdapter.isMessagesSearchEndReached()) { + dialogsSearchAdapter.loadMoreSearchMessages(); + } + return; + } + if (visibleItemCount > 0) { + if (layoutManager.findLastVisibleItemPosition() >= getDialogsArray().size() - 10) { + MessagesController.getInstance().loadDialogs(-1, 100, !MessagesController.getInstance().dialogsEndReached); + } + } + + if (floatingButton.getVisibility() != View.GONE) { + final View topChild = recyclerView.getChildAt(0); + int firstViewTop = 0; + if (topChild != null) { + firstViewTop = topChild.getTop(); + } + boolean goingDown; + boolean changed = true; + if (prevPosition == firstVisibleItem) { + final int topDelta = prevTop - firstViewTop; + goingDown = firstViewTop < prevTop; + changed = Math.abs(topDelta) > 1; + } else { + goingDown = firstVisibleItem > prevPosition; + } + if (changed && scrollUpdated) { + if(!hideTabs && !disableAnimation || hideTabs)hideFloatingButton(goingDown); + } + prevPosition = firstVisibleItem; + prevTop = firstViewTop; + scrollUpdated = true; + } + + if(!hideTabs) { + //if(!disableAnimation) { + if (dy > 1) { + //Down (HIDE) + if (recyclerView.getChildAt(0).getTop() < 0){ + if(!disableAnimation) { + hideTabsAnimated(true); + } else{ + hideFloatingButton(true); + } + } + + } + if (dy < -1) { + //Up (SHOW) + if(!disableAnimation) { + hideTabsAnimated(false); + if (firstVisibleItem == 0) { + listView.setPadding(0, AndroidUtilities.dp(tabsHeight), 0, 0); + } + } else{ + hideFloatingButton(false); + } + } + //} + } + } + }); + + if (searchString == null) { + dialogsAdapter = new DialogsAdapter(context, dialogsType); + if (AndroidUtilities.isTablet() && openedDialogId != 0) { + dialogsAdapter.setOpenedDialogId(openedDialogId); + } + listView.setAdapter(dialogsAdapter); + dialogsBackupAdapter = dialogsAdapter; + } + int type = 0; + if (searchString != null) { + type = 2; + } else if (!onlySelect) { + type = 1; + } + dialogsSearchAdapter = new DialogsSearchAdapter(context, type, dialogsType); + dialogsSearchAdapter.setDelegate(new DialogsSearchAdapter.MessagesActivitySearchAdapterDelegate() { + @Override + public void searchStateChanged(boolean search) { + if (searching && searchWas && searchEmptyView != null) { + if (search) { + searchEmptyView.showProgress(); + } else { + searchEmptyView.showTextView(); + } + } + } + }); + + if (MessagesController.getInstance().loadingDialogs && MessagesController.getInstance().dialogs.isEmpty()) { + searchEmptyView.setVisibility(View.GONE); + emptyView.setVisibility(View.GONE); + listView.setEmptyView(progressView); + } else { + searchEmptyView.setVisibility(View.GONE); + progressView.setVisibility(View.GONE); + listView.setEmptyView(emptyView); + } + if (searchString != null) { + actionBar.openSearchField(searchString); + } + + //if (!onlySelect && dialogsType == 0) { + if (!onlySelect && (dialogsType == 0 || dialogsType > 2)) { + frameLayout.addView(new PlayerView(context, this), LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 39, Gravity.TOP | Gravity.LEFT, 0, -36, 0, 0)); + } + + toastBtn = new Button(context); + toastBtn.setVisibility(AndroidUtilities.themeUpdated ? View.VISIBLE : View.GONE); + if(AndroidUtilities.themeUpdated) { + AndroidUtilities.themeUpdated = false; + String tName = themePrefs.getString("themeName", ""); + //int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + //int hColor = themePrefs.getInt("chatsHeaderColor", def); + toastBtn.setText(LocaleController.formatString("ThemeUpdated", R.string.ThemeUpdated, tName)); + if(Build.VERSION.SDK_INT >= 14)toastBtn.setAllCaps(false); + GradientDrawable shape = new GradientDrawable(); + shape.setCornerRadius(AndroidUtilities.dp(4)); + shape.setColor(hColor); + toastBtn.setBackgroundDrawable(shape); + toastBtn.setTextColor(tColor); + toastBtn.setTextSize(16); + ViewProxy.setTranslationY(toastBtn, -AndroidUtilities.dp(100)); + ObjectAnimatorProxy animator = ObjectAnimatorProxy.ofFloatProxy(toastBtn, "translationY", 0).setDuration(500); + //animator.setInterpolator(tabsInterpolator); + animator.start(); + + toastBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + String packageName = "es.rafalense.themes"; + if (BuildConfig.DEBUG) packageName = "es.rafalense.themes.beta"; + Intent intent = ApplicationLoader.applicationContext.getPackageManager().getLaunchIntentForPackage(packageName); + if (intent != null) { + ApplicationLoader.applicationContext.startActivity(intent); + } + toastBtn.setVisibility(View.GONE); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + frameLayout.addView(toastBtn, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.CENTER, 0, 10, 0, 0)); + Timer t = new Timer(); + t.schedule(new TimerTask() { + @Override + public void run() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + ObjectAnimatorProxy animator = ObjectAnimatorProxy.ofFloatProxy(toastBtn, "translationY", -AndroidUtilities.dp(100)).setDuration(500); + //animator.setInterpolator(tabsInterpolator); + animator.start(); + } + }); + } + }, 4000); + } + + return fragmentView; + } + + private void markAsReadDialog(final boolean all){ + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + TLRPC.Chat currentChat = MessagesController.getInstance().getChat((int) -selectedDialog); + TLRPC.User user = MessagesController.getInstance().getUser((int) selectedDialog); + String title = currentChat != null ? currentChat.title : user != null ? UserObject.getUserName(user) : LocaleController.getString("AppName", R.string.AppName); + builder.setTitle(all ? getHeaderAllTitles() : title); + builder.setMessage((all ? LocaleController.getString("MarkAllAsRead", R.string.MarkAllAsRead) : LocaleController.getString("MarkAsRead", R.string.MarkAsRead)) + '\n' + LocaleController.getString("AreYouSure", R.string.AreYouSure)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if(all){ + ArrayList dialogs = getDialogsArray(); + if (dialogs != null && !dialogs.isEmpty()) { + for (int a = 0; a < dialogs.size(); a++) { + TLRPC.Dialog dialg = getDialogsArray().get(a); + if(dialg.unread_count > 0){ + MessagesController.getInstance().markDialogAsRead(dialg.id, dialg.last_read, Math.max(0, dialg.top_message), dialg.last_message_date, true, false); + } + } + } + } else { + TLRPC.Dialog dialg = MessagesController.getInstance().dialogs_dict.get(selectedDialog); + if(dialg.unread_count > 0) { + MessagesController.getInstance().markDialogAsRead(dialg.id, dialg.last_read, Math.max(0, dialg.top_message), dialg.last_message_date, true, false); + } + } + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } + + private void addShortcut() { + + Intent shortcutIntent = new Intent(ApplicationLoader.applicationContext, ShortcutActivity.class); + shortcutIntent.setAction("com.tmessages.openchat" + Math.random() + Integer.MAX_VALUE); + shortcutIntent.setFlags(32768); + + TLRPC.Dialog dialg = MessagesController.getInstance().dialogs_dict.get(selectedDialog); + TLRPC.Chat currentChat = MessagesController.getInstance().getChat((int) -selectedDialog); + TLRPC.User user = MessagesController.getInstance().getUser((int) selectedDialog); + TLRPC.EncryptedChat encryptedChat = null; + + AvatarDrawable avatarDrawable = new AvatarDrawable(); + long dialog_id = dialg.id; + + int lower_id = (int)dialog_id; + int high_id = (int)(dialog_id >> 32); + if (lower_id != 0) { + if (high_id == 1) { + currentChat = MessagesController.getInstance().getChat(lower_id); + shortcutIntent.putExtra("chatId", lower_id); + avatarDrawable.setInfo(currentChat); + } else { + if (lower_id < 0) { + currentChat = MessagesController.getInstance().getChat(-lower_id); + if (currentChat != null && currentChat.migrated_to != null) { + TLRPC.Chat chat2 = MessagesController.getInstance().getChat(currentChat.migrated_to.channel_id); + if (chat2 != null) { + currentChat = chat2; + } + } + shortcutIntent.putExtra("chatId", -lower_id); + avatarDrawable.setInfo(currentChat); + } else { + user = MessagesController.getInstance().getUser(lower_id); + shortcutIntent.putExtra("userId", lower_id); + avatarDrawable.setInfo(user); + } + } + } else { + encryptedChat = MessagesController.getInstance().getEncryptedChat(high_id); + if (encryptedChat != null) { + user = MessagesController.getInstance().getUser(encryptedChat.user_id); + shortcutIntent.putExtra("encId", high_id); + avatarDrawable.setInfo(user); + } + } + + final String name = currentChat != null ? currentChat.title : user != null && encryptedChat == null ? UserObject.getUserName(user) : encryptedChat != null ? new String(Character.toChars(0x1F512)) + UserObject.getUserName(user) : null; + //Log.e("DialogsActivity", "addShortcut " + user.id); + if(name == null){ + return; + } + //Log.e("Plus", "addShortcut " + name + " dialog_id " + dialog_id); + + TLRPC.FileLocation photoPath = null; + + if (currentChat != null) { + if (currentChat.photo != null && currentChat.photo.photo_small != null && currentChat.photo.photo_small.volume_id != 0 && currentChat.photo.photo_small.local_id != 0) { + photoPath = currentChat.photo.photo_small; + } + } else if (user != null) { + if (user.photo != null && user.photo.photo_small != null && user.photo.photo_small.volume_id != 0 && user.photo.photo_small.local_id != 0) { + photoPath = user.photo.photo_small; + } + } + BitmapDrawable img = null; + + if (photoPath != null) { + img = ImageLoader.getInstance().getImageFromMemory(photoPath, null, "50_50"); + } + + String action = "com.android.launcher.action.INSTALL_SHORTCUT"; + Intent addIntent = new Intent(); + addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); + addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name); + + if (img != null){ + addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, getRoundBitmap(img.getBitmap())); + } else{ + int w = AndroidUtilities.dp(40); + int h = AndroidUtilities.dp(40); + Bitmap mutableBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(mutableBitmap); + avatarDrawable.setBounds(0, 0, w, h); + avatarDrawable.draw(canvas); + //if(mutableBitmap != null){ + addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, getRoundBitmap(mutableBitmap)); + //} else{ + //addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(ApplicationLoader.applicationContext, R.drawable.intro1)); + //} + } + + addIntent.putExtra("duplicate", false); + addIntent.setAction(action); + //addIntent.setPackage(ApplicationLoader.applicationContext.getPackageName()); + boolean error = false; + if(ApplicationLoader.applicationContext.getPackageManager().queryBroadcastReceivers(new Intent(action), 0).size() > 0) { + ApplicationLoader.applicationContext.sendBroadcast(addIntent); + } else{ + error = true; + } + final String msg = error ? LocaleController.formatString("ShortcutError", R.string.ShortcutError, name) : LocaleController.formatString("ShortcutAdded", R.string.ShortcutAdded, name); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (getParentActivity() != null) { + Toast toast = Toast.makeText(getParentActivity(), msg, Toast.LENGTH_SHORT); + toast.show(); + } + } + }); + } + + private Bitmap getRoundBitmap(Bitmap bitmap){ + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + int radius = Math.min(h / 2, w / 2); + Bitmap output = Bitmap.createBitmap(w + 8, h + 8, Bitmap.Config.ARGB_8888); + Paint p = new Paint(); + p.setAntiAlias(true); + Canvas c = new Canvas(output); + c.drawARGB(0, 0, 0, 0); + p.setStyle(Paint.Style.FILL); + c.drawCircle((w / 2) + 4, (h / 2) + 4, radius, p); + p.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); + c.drawBitmap(bitmap, 4, 4, p); + return output; + } + + public class DialogsOnTouch implements View.OnTouchListener { + + private DisplayMetrics displayMetrics; + //private static final String logTag = "SwipeDetector"; + private static final int MIN_DISTANCE_HIGH = 40; + private static final int MIN_DISTANCE_HIGH_Y = 60; + private float downX, downY, upX, upY; + private float vDPI; + + Context mContext; + + public DialogsOnTouch(Context context) { + this.mContext = context; + displayMetrics = context.getResources().getDisplayMetrics(); + vDPI = displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT; + //Log.e("DialogsActivity","DialogsOnTouch vDPI " + vDPI); + } + + public boolean onTouch(View view, MotionEvent event) { + + touchPositionDP = Math.round(event.getX() / vDPI); + //Log.e("DialogsActivity","onTouch touchPositionDP " + touchPositionDP + " hideTabs " + hideTabs); + if(hideTabs){ + return false; + } + + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: { + downX = Math.round(event.getX() / vDPI); + downY = Math.round(event.getY() / vDPI); + //Log.e("DialogsActivity", "view " + view.toString()); + if(touchPositionDP > 50){ + parentLayout.getDrawerLayoutContainer().setAllowOpenDrawer(false, false); + //Log.e("DialogsActivity", "DOWN setAllowOpenDrawer FALSE"); + } + //Log.e("DialogsActivity", "DOWN downX " + downX); + return view instanceof LinearLayout; // for emptyView + } + case MotionEvent.ACTION_UP: { + upX = Math.round(event.getX() / vDPI); + upY = Math.round(event.getY() / vDPI); + float deltaX = downX - upX; + float deltaY = downY - upY; + //Log.e(logTag, "MOVE X " + deltaX); + //Log.e(logTag, "MOVE Y " + deltaY); + //Log.e("DialogsActivity", "UP downX " + downX); + //Log.e("DialogsActivity", "UP upX " + upX); + //Log.e("DialogsActivity", "UP deltaX " + deltaX); + // horizontal swipe detection + if (Math.abs(deltaX) > MIN_DISTANCE_HIGH && Math.abs(deltaY) < MIN_DISTANCE_HIGH_Y) { + //if (Math.abs(deltaX) > MIN_DISTANCE_HIGH) { + refreshDialogType(deltaX < 0 ? 0 : 1);//0: Left - Right 1: Right - Left + downX = Math.round(event.getX() / vDPI ); + refreshAdapter(mContext); + //dialogsAdapter.notifyDataSetChanged(); + refreshTabAndListViews(false); + //return true; + } + //Log.e("DialogsActivity", "UP2 downX " + downX); + if(touchPositionDP > 50){ + parentLayout.getDrawerLayoutContainer().setAllowOpenDrawer(true, false); + + } + //downX = downY = upX = upY = 0; + return false; + } + } + + return false; + } + } + + + @Override + public void onResume() { + super.onResume(); + if (dialogsAdapter != null) { + dialogsAdapter.notifyDataSetChanged(); + } + if (dialogsSearchAdapter != null) { + dialogsSearchAdapter.notifyDataSetChanged(); + } + if (checkPermission && !onlySelect && Build.VERSION.SDK_INT >= 23) { + Activity activity = getParentActivity(); + if (activity != null) { + checkPermission = false; + if (activity.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED || activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + if (activity.shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS)) { + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("PermissionContacts", R.string.PermissionContacts)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(permissionDialog = builder.create()); + } else if (activity.shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { + AlertDialog.Builder builder = new AlertDialog.Builder(activity); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("PermissionStorage", R.string.PermissionStorage)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(permissionDialog = builder.create()); + } else { + askForPermissons(); + } + } + } + } + updateTheme(); + unreadCount(); + } + + @TargetApi(Build.VERSION_CODES.M) + private void askForPermissons() { + Activity activity = getParentActivity(); + if (activity == null) { + return; + } + ArrayList permissons = new ArrayList<>(); + if (activity.checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) { + permissons.add(Manifest.permission.READ_CONTACTS); + permissons.add(Manifest.permission.WRITE_CONTACTS); + permissons.add(Manifest.permission.GET_ACCOUNTS); + } + if (activity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { + permissons.add(Manifest.permission.READ_EXTERNAL_STORAGE); + permissons.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + } + String[] items = permissons.toArray(new String[permissons.size()]); + activity.requestPermissions(items, 1); + } + + @Override + protected void onDialogDismiss(Dialog dialog) { + super.onDialogDismiss(dialog); + if (permissionDialog != null && dialog == permissionDialog && getParentActivity() != null) { + askForPermissons(); + } + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + if (!onlySelect && floatingButton != null) { + floatingButton.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + ViewProxy.setTranslationY(floatingButton, floatingHidden ? AndroidUtilities.dp(100) : 0); + floatingButton.setClickable(!floatingHidden); + if (floatingButton != null) { + if (Build.VERSION.SDK_INT < 16) { + floatingButton.getViewTreeObserver().removeGlobalOnLayoutListener(this); + } else { + floatingButton.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + } + } + }); + } + } + + @Override + public void onRequestPermissionsResultFragment(int requestCode, String[] permissions, int[] grantResults) { + if (requestCode == 1) { + for (int a = 0; a < permissions.length; a++) { + if (grantResults.length <= a || grantResults[a] != PackageManager.PERMISSION_GRANTED) { + continue; + } + switch (permissions[a]) { + case Manifest.permission.READ_CONTACTS: + ContactsController.getInstance().readContacts(); + break; + case Manifest.permission.WRITE_EXTERNAL_STORAGE: + ImageLoader.getInstance().checkMediaPaths(); + break; + } + } + } + } + + @Override + @SuppressWarnings("unchecked") + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.dialogsNeedReload) { + if (dialogsAdapter != null) { + if (dialogsAdapter.isDataSetChanged()) { + dialogsAdapter.notifyDataSetChanged(); + } else { + updateVisibleRows(MessagesController.UPDATE_MASK_NEW_MESSAGE); + } + } + if (dialogsSearchAdapter != null) { + dialogsSearchAdapter.notifyDataSetChanged(); + } + if (listView != null) { + try { + if (MessagesController.getInstance().loadingDialogs && MessagesController.getInstance().dialogs.isEmpty()) { + searchEmptyView.setVisibility(View.GONE); + emptyView.setVisibility(View.GONE); + listView.setEmptyView(progressView); + } else { + progressView.setVisibility(View.GONE); + if (searching && searchWas) { + emptyView.setVisibility(View.GONE); + listView.setEmptyView(searchEmptyView); + } else { + searchEmptyView.setVisibility(View.GONE); + listView.setEmptyView(emptyView); + } + } + } catch (Exception e) { + FileLog.e("tmessages", e); //TODO fix it in other way? + } + } + } else if (id == NotificationCenter.emojiDidLoaded) { + updateVisibleRows(0); + } else if (id == NotificationCenter.updateInterfaces) { + updateVisibleRows((Integer) args[0]); + } else if (id == NotificationCenter.appDidLogout) { + dialogsLoaded = false; + } else if (id == NotificationCenter.encryptedChatUpdated) { + updateVisibleRows(0); + } else if (id == NotificationCenter.contactsDidLoaded) { + updateVisibleRows(0); + } else if (id == NotificationCenter.openedChatChanged) { + if (dialogsType == 0 && AndroidUtilities.isTablet()) { + boolean close = (Boolean) args[1]; + long dialog_id = (Long) args[0]; + if (close) { + if (dialog_id == openedDialogId) { + openedDialogId = 0; + } + } else { + openedDialogId = dialog_id; + } + if (dialogsAdapter != null) { + dialogsAdapter.setOpenedDialogId(openedDialogId); + } + updateVisibleRows(MessagesController.UPDATE_MASK_SELECT_DIALOG); + } + } else if (id == NotificationCenter.notificationsSettingsUpdated) { + updateVisibleRows(0); + } else if (id == NotificationCenter.messageReceivedByAck || id == NotificationCenter.messageReceivedByServer || id == NotificationCenter.messageSendError) { + updateVisibleRows(MessagesController.UPDATE_MASK_SEND_STATE); + } else if (id == NotificationCenter.didSetPasscode) { + updatePasscodeButton(); + } else if (id == NotificationCenter.refreshTabs) { + updateTabs(); + hideShowTabs((int) args[0]); + } + + if (id == NotificationCenter.needReloadRecentDialogsSearch) { + if (dialogsSearchAdapter != null) { + dialogsSearchAdapter.loadRecentSearch(); + } + } else if (id == NotificationCenter.didLoadedReplyMessages) { + updateVisibleRows(0); + } + } + + private ArrayList getDialogsArray() { + if (dialogsType == 0) { + return MessagesController.getInstance().dialogs; + } else if (dialogsType == 1) { + return MessagesController.getInstance().dialogsServerOnly; + } else if (dialogsType == 2) { + return MessagesController.getInstance().dialogsGroupsOnly; + } + //plus + else if (dialogsType == 3) { + return MessagesController.getInstance().dialogsUsers; + } else if (dialogsType == 4) { + return MessagesController.getInstance().dialogsGroups; + } else if (dialogsType == 5) { + return MessagesController.getInstance().dialogsChannels; + } else if (dialogsType == 6) { + return MessagesController.getInstance().dialogsBots; + } else if (dialogsType == 7) { + return MessagesController.getInstance().dialogsMegaGroups; + } else if (dialogsType == 8) { + return MessagesController.getInstance().dialogsFavs; + } else if (dialogsType == 9) { + return MessagesController.getInstance().dialogsGroupsAll; + } + // + return null; + } + + private void updatePasscodeButton() { + if (passcodeItem == null) { + return; + } + if (UserConfig.passcodeHash.length() != 0 && !searching) { + passcodeItem.setVisibility(View.VISIBLE); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int iconColor = themePrefs.getInt("chatsHeaderIconsColor", 0xffffffff); + if (UserConfig.appLocked) { + //passcodeItem.setIcon(R.drawable.lock_close); + Drawable lockC = getParentActivity().getResources().getDrawable(R.drawable.lock_close); + if(lockC != null)lockC.setColorFilter(iconColor, PorterDuff.Mode.MULTIPLY); + passcodeItem.setIcon(lockC); + } else { + //passcodeItem.setIcon(R.drawable.lock_open); + Drawable lockO = getParentActivity().getResources().getDrawable(R.drawable.lock_open); + if(lockO != null)lockO.setColorFilter(iconColor, PorterDuff.Mode.MULTIPLY); + passcodeItem.setIcon(lockO); + } + } else { + passcodeItem.setVisibility(View.GONE); + } + } + + private void hideFloatingButton(boolean hide) { + if (floatingHidden == hide) { + return; + } + floatingHidden = hide; + ObjectAnimatorProxy animator = ObjectAnimatorProxy.ofFloatProxy(floatingButton, "translationY", floatingHidden ? AndroidUtilities.dp(100) : 0).setDuration(300); + animator.setInterpolator(floatingInterpolator); + floatingButton.setClickable(!hide); + animator.start(); + } + + private void updateVisibleRows(int mask) { + if (listView == null) { + return; + } + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + if (child instanceof DialogCell) { + if (listView.getAdapter() != dialogsSearchAdapter) { + DialogCell cell = (DialogCell) child; + if ((mask & MessagesController.UPDATE_MASK_NEW_MESSAGE) != 0) { + cell.checkCurrentDialogIndex(); + if (dialogsType == 0 && AndroidUtilities.isTablet()) { + cell.setDialogSelected(cell.getDialogId() == openedDialogId); + } + } else if ((mask & MessagesController.UPDATE_MASK_SELECT_DIALOG) != 0) { + if (dialogsType == 0 && AndroidUtilities.isTablet()) { + cell.setDialogSelected(cell.getDialogId() == openedDialogId); + } + } else { + cell.update(mask); + } + } + } else if (child instanceof UserCell) { + ((UserCell) child).update(mask); + } else if (child instanceof ProfileSearchCell) { + ((ProfileSearchCell) child).update(mask); + } + } + updateListBG(); + unreadCount(); + } + + private void unreadCount(){ + unreadCount(MessagesController.getInstance().dialogs, allCounter); + unreadCount(MessagesController.getInstance().dialogsUsers, usersCounter); + unreadCount(MessagesController.getInstance().dialogsBots, botsCounter); + unreadCount(MessagesController.getInstance().dialogsChannels, channelsCounter); + unreadCount(MessagesController.getInstance().dialogsFavs, favsCounter); + unreadCountGroups(); + + } + + private void unreadCountGroups(){ + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean hideSGroups = plusPreferences.getBoolean("hideSGroups", false); + if(hideSGroups){ + unreadCount(MessagesController.getInstance().dialogsGroupsAll, groupsCounter); + } else{ + unreadCount(MessagesController.getInstance().dialogsGroups, groupsCounter); + unreadCount(MessagesController.getInstance().dialogsMegaGroups, sGroupsCounter); + } + } + + private void unreadCount(ArrayList dialogs, TextView tv){ + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean hTabs = plusPreferences.getBoolean("hideTabs", false); + if(hTabs)return; + boolean hideCounters = plusPreferences.getBoolean("hideTabsCounters", false); + if(hideCounters){ + tv.setVisibility(View.GONE); + return; + } + boolean allMuted = true; + boolean countDialogs = plusPreferences.getBoolean("tabsCountersCountChats", false); + boolean countNotMuted = plusPreferences.getBoolean("tabsCountersCountNotMuted", false); + int unreadCount = 0; + + if (dialogs != null && !dialogs.isEmpty()) { + for(int a = 0; a < dialogs.size(); a++) { + TLRPC.Dialog dialg = dialogs.get(a); + boolean isMuted = MessagesController.getInstance().isDialogMuted(dialg.id); + if(!isMuted || !countNotMuted){ + int i = dialg.unread_count; + if(i > 0) { + if (countDialogs) { + if (i > 0) unreadCount = unreadCount + 1; + } else { + unreadCount = unreadCount + i; + } + if (i > 0 && !isMuted) allMuted = false; + } + } + } + } + + if(unreadCount == 0){ + tv.setVisibility(View.GONE); + } else{ + tv.setVisibility(View.VISIBLE); + tv.setText("" + unreadCount); + + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int size = themePrefs.getInt("chatsHeaderTabCounterSize", 11); + tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, size); + tv.setPadding(AndroidUtilities.dp(size > 10 ? size - 7 : 4), 0, AndroidUtilities.dp(size > 10 ? size - 7 : 4), 0); + int cColor = themePrefs.getInt("chatsHeaderTabCounterColor", 0xffffffff); + if(allMuted){ + tv.getBackground().setColorFilter(themePrefs.getInt("chatsHeaderTabCounterSilentBGColor", 0xffb9b9b9), PorterDuff.Mode.SRC_IN); + tv.setTextColor(cColor); + } else{ + tv.getBackground().setColorFilter(themePrefs.getInt("chatsHeaderTabCounterBGColor", 0xffd32f2f), PorterDuff.Mode.SRC_IN); + tv.setTextColor(cColor); + } + } + } + + private void updateListBG(){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int mainColor = themePrefs.getInt("chatsRowColor", 0xffffffff); + int value = themePrefs.getInt("chatsRowGradient", 0); + boolean b = true;//themePrefs.getBoolean("chatsRowGradientListCheck", false); + if(value > 0 && b) { + GradientDrawable.Orientation go; + switch(value) { + case 2: + go = GradientDrawable.Orientation.LEFT_RIGHT; + break; + case 3: + go = GradientDrawable.Orientation.TL_BR; + break; + case 4: + go = GradientDrawable.Orientation.BL_TR; + break; + default: + go = GradientDrawable.Orientation.TOP_BOTTOM; + } + + int gradColor = themePrefs.getInt("chatsRowGradientColor", 0xffffffff); + int[] colors = new int[]{mainColor, gradColor}; + GradientDrawable gd = new GradientDrawable(go, colors); + listView.setBackgroundDrawable(gd); + }else{ + listView.setBackgroundColor(mainColor); + } + } + + public void setDelegate(DialogsActivityDelegate delegate) { + this.delegate = delegate; + } + + public void setSearchString(String string) { + searchString = string; + } + + public boolean isMainDialogList() { + return delegate == null && searchString == null; + } + + private void didSelectResult(final long dialog_id, boolean useAlert, final boolean param) { + if (addToGroupAlertString == null) { + if ((int) dialog_id < 0 && ChatObject.isChannel(-(int) dialog_id) && !ChatObject.isCanWriteToChannel(-(int) dialog_id)) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("ChannelCantSendMessage", R.string.ChannelCantSendMessage)); + builder.setNegativeButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); + return; + } + } + if (useAlert && (selectAlertString != null && selectAlertStringGroup != null || addToGroupAlertString != null)) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + int lower_part = (int) dialog_id; + int high_id = (int) (dialog_id >> 32); + if (lower_part != 0) { + if (high_id == 1) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(lower_part); + if (chat == null) { + return; + } + builder.setMessage(LocaleController.formatStringSimple(selectAlertStringGroup, chat.title)); + } else { + if (lower_part > 0) { + TLRPC.User user = MessagesController.getInstance().getUser(lower_part); + if (user == null) { + return; + } + builder.setMessage(LocaleController.formatStringSimple(selectAlertString, UserObject.getUserName(user))); + } else if (lower_part < 0) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(-lower_part); + if (chat == null) { + return; + } + if (addToGroupAlertString != null) { + builder.setMessage(LocaleController.formatStringSimple(addToGroupAlertString, chat.title)); + } else { + builder.setMessage(LocaleController.formatStringSimple(selectAlertStringGroup, chat.title)); + } + } + } + } else { + TLRPC.EncryptedChat chat = MessagesController.getInstance().getEncryptedChat(high_id); + TLRPC.User user = MessagesController.getInstance().getUser(chat.user_id); + if (user == null) { + return; + } + builder.setMessage(LocaleController.formatStringSimple(selectAlertString, UserObject.getUserName(user))); + } + + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + didSelectResult(dialog_id, false, false); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } else { + if (delegate != null) { + delegate.didSelectDialog(DialogsActivity.this, dialog_id, param); + delegate = null; + } else { + finishFragment(); + } + } + } + + private String getHeaderTitle(){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int value = themePrefs.getInt("chatsHeaderTitle", 0); + String title = LocaleController.getString("AppName", R.string.AppName); + TLRPC.User user = UserConfig.getCurrentUser(); + if( value == 1){ + title = LocaleController.getString("ShortAppName", R.string.ShortAppName); + } else if( value == 2){ + if (user != null && (user.first_name != null || user.last_name != null)) { + title = ContactsController.formatName(user.first_name, user.last_name); + } + } else if(value == 3){ + if (user != null && user.username != null && user.username.length() != 0) { + title = "@" + user.username; + } + } else if(value == 4){ + title = ""; + } + return title; + } + + private String getHeaderAllTitles(){ + switch(dialogsType) { + case 3: + return LocaleController.getString("Users", R.string.Users); + case 4: + case 9: + return LocaleController.getString("Groups", R.string.Groups); + case 5: + return LocaleController.getString("Channels", R.string.Channels); + case 6: + return LocaleController.getString("Bots", R.string.Bots); + case 7: + return LocaleController.getString("SuperGroups", R.string.SuperGroups); + case 8: + return LocaleController.getString("Favorites", R.string.Favorites); + default: + return getHeaderTitle(); + } + } + + /*private void updateHeaderTitle(){ + String s = ""; + switch(dialogsType) { + case 3: + s = LocaleController.getString("Users", R.string.Users); + break; + case 4: + case 9: + s = LocaleController.getString("Groups", R.string.Groups); + break; + case 5: + s = LocaleController.getString("Channels", R.string.Channels); + break; + case 6: + s = LocaleController.getString("Bots", R.string.Bots); + break; + case 7: + s = LocaleController.getString("SuperGroups", R.string.SuperGroups); + break; + case 8: + s = getParentActivity().getString(R.string.Favorites); + break; + default: + s = getHeaderTitle(); + } + actionBar.setTitle(getHeaderAllTitles()); + paintHeader(true); + }*/ + + private void paintHeader(boolean tabs){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + actionBar.setTitleColor(themePrefs.getInt("chatsHeaderTitleColor", 0xffffffff)); + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + int hColor = themePrefs.getInt("chatsHeaderColor", def); + /*if(!tabs){ + actionBar.setBackgroundColor(hColor); + }else{ + tabsView.setBackgroundColor(hColor); + }*/ + if(!tabs)actionBar.setBackgroundColor(hColor); + if(tabs){ + tabsView.setBackgroundColor(hColor); + } + int val = themePrefs.getInt("chatsHeaderGradient", 0); + if(val > 0) { + GradientDrawable.Orientation go; + switch(val) { + case 2: + go = GradientDrawable.Orientation.LEFT_RIGHT; + break; + case 3: + go = GradientDrawable.Orientation.TL_BR; + break; + case 4: + go = GradientDrawable.Orientation.BL_TR; + break; + default: + go = GradientDrawable.Orientation.TOP_BOTTOM; + } + int gradColor = themePrefs.getInt("chatsHeaderGradientColor", def); + int[] colors = new int[]{hColor, gradColor}; + GradientDrawable gd = new GradientDrawable(go, colors); + if(!tabs)actionBar.setBackgroundDrawable(gd); + if(tabs){ + tabsView.setBackgroundDrawable(gd); + } + /*if(!tabs){ + actionBar.setBackgroundDrawable(gd); + }else{ + tabsView.setBackgroundDrawable(gd); + }*/ + } + } + + private void updateTheme(){ + paintHeader(false); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + int iconColor = themePrefs.getInt("chatsHeaderIconsColor", 0xffffffff); + try{ + int hColor = themePrefs.getInt("chatsHeaderColor", def); + //plus + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + Bitmap bm = BitmapFactory.decodeResource(getParentActivity().getResources(), R.drawable.ic_launcher); + ActivityManager.TaskDescription td = new ActivityManager.TaskDescription(getHeaderTitle(), bm, hColor); + getParentActivity().setTaskDescription(td); + bm.recycle(); + } + + Drawable floatingDrawableWhite = getParentActivity().getResources().getDrawable(R.drawable.floating_white); + if(floatingDrawableWhite != null)floatingDrawableWhite.setColorFilter(themePrefs.getInt("chatsFloatingBGColor", def), PorterDuff.Mode.MULTIPLY); + floatingButton.setBackgroundDrawable(floatingDrawableWhite); + Drawable pencilDrawableWhite = getParentActivity().getResources().getDrawable(R.drawable.floating_pencil); + if(pencilDrawableWhite != null)pencilDrawableWhite.setColorFilter(themePrefs.getInt("chatsFloatingPencilColor", 0xffffffff), PorterDuff.Mode.MULTIPLY); + floatingButton.setImageDrawable(pencilDrawableWhite); + } catch (NullPointerException e) { + FileLog.e("tmessages", e); + } + try{ + Drawable search = getParentActivity().getResources().getDrawable(R.drawable.ic_ab_search); + if(search != null)search.setColorFilter(iconColor, PorterDuff.Mode.MULTIPLY); + Drawable lockO = getParentActivity().getResources().getDrawable(R.drawable.lock_close); + if(lockO != null)lockO.setColorFilter(iconColor, PorterDuff.Mode.MULTIPLY); + Drawable lockC = getParentActivity().getResources().getDrawable(R.drawable.lock_open); + if(lockC != null)lockC.setColorFilter(iconColor, PorterDuff.Mode.MULTIPLY); + Drawable clear = getParentActivity().getResources().getDrawable(R.drawable.ic_close_white); + if(clear != null)clear.setColorFilter(iconColor, PorterDuff.Mode.MULTIPLY); + } catch (OutOfMemoryError e) { + FileLog.e("tmessages", e); + } + refreshTabs(); + paintHeader(true); + } + + //plus + private void createTabs(final Context context){ + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = plusPreferences.edit(); + + boolean hideUsers = plusPreferences.getBoolean("hideUsers", false); + boolean hideGroups = plusPreferences.getBoolean("hideGroups", false); + boolean hideSGroups = plusPreferences.getBoolean("hideSGroups", false); + boolean hideChannels = plusPreferences.getBoolean("hideChannels", false); + boolean hideBots = plusPreferences.getBoolean("hideBots", false); + boolean hideFavs = plusPreferences.getBoolean("hideFavs", false); + + hideTabs = plusPreferences.getBoolean("hideTabs", false); + disableAnimation = plusPreferences.getBoolean("disableTabsAnimation", false); + + if(hideUsers && hideGroups && hideSGroups && hideChannels && hideBots && hideFavs){ + if(!hideTabs){ + hideTabs = true; + editor.putBoolean("hideTabs", true).apply(); + } + } + + tabsHeight = plusPreferences.getInt("tabsHeight", 40); + + refreshTabAndListViews(false); + + int t = plusPreferences.getInt("defTab", -1); + selectedTab = t != -1 ? t : plusPreferences.getInt("selTab", 0); + + if(!hideTabs && dialogsType != selectedTab){ + dialogsType = selectedTab == 4 && hideSGroups ? 9 : selectedTab; + dialogsAdapter = new DialogsAdapter(context, dialogsType); + listView.setAdapter(dialogsAdapter); + dialogsAdapter.notifyDataSetChanged(); + } + + dialogsBackupAdapter = new DialogsAdapter(context, 0); + + tabsLayout = new LinearLayout(context); + tabsLayout.setOrientation(LinearLayout.HORIZONTAL); + tabsLayout.setGravity(Gravity.CENTER); + + //1 + allTab = new ImageView(context); + //allTab.setScaleType(ImageView.ScaleType.CENTER); + allTab.setImageResource(R.drawable.tab_all); + + //tabsLayout.addView(allTab, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + + allCounter = new TextView(context); + allCounter.setTag("ALL"); + addTabView(context, allTab, allCounter, true); + + //2 + usersTab = new ImageView(context); + usersTab.setImageResource(R.drawable.tab_user); + /*usersTab.setScaleType(ImageView.ScaleType.CENTER); + if(!hideUsers) { + tabsLayout.addView(usersTab, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + }*/ + usersCounter = new TextView(context); + usersCounter.setTag("USERS"); + addTabView(context, usersTab, usersCounter, !hideUsers); + //3 + groupsTab = new ImageView(context); + groupsTab.setImageResource(R.drawable.tab_group); + /*groupsTab.setScaleType(ImageView.ScaleType.CENTER); + if(!hideGroups) { + tabsLayout.addView(groupsTab, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + }*/ + groupsCounter = new TextView(context); + groupsCounter.setTag("GROUPS"); + addTabView(context, groupsTab, groupsCounter, !hideGroups); + //4 + superGroupsTab = new ImageView(context); + superGroupsTab.setImageResource(R.drawable.tab_supergroup); + /*superGroupsTab.setScaleType(ImageView.ScaleType.CENTER); + if(!hideSGroups){ + tabsLayout.addView(superGroupsTab, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + }*/ + sGroupsCounter = new TextView(context); + sGroupsCounter.setTag("SGROUP"); + addTabView(context, superGroupsTab, sGroupsCounter, !hideSGroups); + //5 + channelsTab = new ImageView(context); + channelsTab.setImageResource(R.drawable.tab_channel); + /*channelsTab.setScaleType(ImageView.ScaleType.CENTER); + if(!hideChannels){ + tabsLayout.addView(channelsTab, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + }*/ + channelsCounter = new TextView(context); + channelsCounter.setTag("CHANNELS"); + addTabView(context, channelsTab, channelsCounter, !hideChannels); + //6 + botsTab = new ImageView(context); + botsTab.setImageResource(R.drawable.tab_bot); + /*botsTab.setScaleType(ImageView.ScaleType.CENTER); + if(!hideBots){ + tabsLayout.addView(botsTab, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + }*/ + botsCounter = new TextView(context); + botsCounter.setTag("BOTS"); + addTabView(context, botsTab, botsCounter, !hideBots); + //7 + favsTab = new ImageView(context); + favsTab.setImageResource(R.drawable.tab_favs); + /*favsTab.setScaleType(ImageView.ScaleType.CENTER); + if(!hideFavs){ + tabsLayout.addView(favsTab, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + }*/ + favsCounter = new TextView(context); + favsCounter.setTag("FAVS"); + addTabView(context, favsTab, favsCounter, !hideFavs); + + tabsView.addView(tabsLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + allTab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (dialogsType != 0) { + dialogsType = 0; + refreshAdapter(context); + } + } + }); + + allTab.setOnLongClickListener(new View.OnLongClickListener() { + public boolean onLongClick(View view) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("All", R.string.All)); + CharSequence items[]; + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + final int tabVal = 0; + final int def = plusPreferences.getInt("defTab", -1); + final int sort = plusPreferences.getInt("sortAll", 0); + + CharSequence cs2 = def == tabVal ? LocaleController.getString("ResetDefaultTab", R.string.ResetDefaultTab) : LocaleController.getString("SetAsDefaultTab", R.string.SetAsDefaultTab); + CharSequence cs1 = sort == 0 ? LocaleController.getString("SortByUnreadCount", R.string.SortByUnreadCount) : LocaleController.getString("SortByLastMessage", R.string.SortByLastMessage); + CharSequence cs0 = LocaleController.getString("HideShowTabs", R.string.HideShowTabs); + items = new CharSequence[]{cs0, cs1, cs2, LocaleController.getString("MarkAllAsRead", R.string.MarkAllAsRead)}; + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, final int which) { + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = plusPreferences.edit(); + if (which == 0) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + createTabsDialog(context, builder); + builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), null); + showDialog(builder.create()); + } else if (which == 1) { + editor.putInt("sortAll", sort == 0 ? 1 : 0).apply(); + if(dialogsAdapter.getItemCount() > 1) { + dialogsAdapter.notifyDataSetChanged(); + } + } else if (which == 2){ + editor.putInt("defTab", def == tabVal ? -1 : tabVal).apply(); + } else if (which == 3){ + markAsReadDialog(true); + } + } + }); + showDialog(builder.create()); + return true; + } + }); + + usersTab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (dialogsType != 3) { + dialogsType = 3; + refreshAdapter(context); + } + } + }); + + usersTab.setOnLongClickListener(new View.OnLongClickListener() { + public boolean onLongClick(View view) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("Users", R.string.Users)); + CharSequence items[]; + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + final int tabVal = 3; + final int sort = plusPreferences.getInt("sortUsers", 0); + final int def = plusPreferences.getInt("defTab", -1); + CharSequence cs = def == tabVal ? LocaleController.getString("ResetDefaultTab", R.string.ResetDefaultTab) : LocaleController.getString("SetAsDefaultTab", R.string.SetAsDefaultTab); + items = new CharSequence[]{sort == 0 ? LocaleController.getString("SortByStatus", R.string.SortByStatus) : LocaleController.getString("SortByLastMessage", R.string.SortByLastMessage), cs, LocaleController.getString("MarkAllAsRead", R.string.MarkAllAsRead)}; + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, final int which) { + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = plusPreferences.edit(); + if (which == 1) { + editor.putInt("defTab", def == tabVal ? -1 : tabVal).apply(); + } else if (which == 0){ + editor.putInt("sortUsers", sort == 0 ? 1 : 0).apply(); + if(dialogsAdapter.getItemCount() > 1) { + dialogsAdapter.notifyDataSetChanged(); + } + } else if (which == 2){ + markAsReadDialog(true); + } + } + }); + showDialog(builder.create()); + return true; + } + }); + + groupsTab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + final boolean hideSGroups = plusPreferences.getBoolean("hideSGroups", false); + int i = hideSGroups ? 9 : 4; + if (dialogsType != i) { + dialogsType = i; + refreshAdapter(context); + } + } + }); + + groupsTab.setOnLongClickListener(new View.OnLongClickListener() { + public boolean onLongClick(View view) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("Groups", R.string.Groups)); + CharSequence items[]; + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + final boolean hideSGroups = plusPreferences.getBoolean("hideSGroups", false); + final int tabVal = 4; + final int sort = plusPreferences.getInt("sortGroups", 0); + final int def = plusPreferences.getInt("defTab", -1); + + CharSequence cs2 = def == tabVal ? LocaleController.getString("ResetDefaultTab", R.string.ResetDefaultTab) : LocaleController.getString("SetAsDefaultTab", R.string.SetAsDefaultTab); + CharSequence cs1 = sort == 0 ? LocaleController.getString("SortByUnreadCount", R.string.SortByUnreadCount) : LocaleController.getString("SortByLastMessage", R.string.SortByLastMessage); + CharSequence cs0 = hideSGroups ? LocaleController.getString("ShowSuperGroupsTab", R.string.ShowSuperGroupsTab) : LocaleController.getString("HideSuperGroupsTab", R.string.HideSuperGroupsTab); + items = new CharSequence[]{cs0, cs1, cs2, LocaleController.getString("MarkAllAsRead", R.string.MarkAllAsRead)}; + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, final int which) { + + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = plusPreferences.edit(); + if (which == 0){ + RelativeLayout rl = (RelativeLayout) superGroupsTab.getParent(); + editor.putBoolean("hideSGroups", !hideSGroups).apply(); + if (!hideSGroups) { + tabsLayout.removeView(rl); + if (dialogsType == 7) { + dialogsType = 9; + refreshAdapter(context); + } + } else { + boolean hideUsers = plusPreferences.getBoolean("hideUsers", false); + tabsLayout.addView(rl, hideUsers ? 2 : 3, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + } + unreadCountGroups(); + } else if (which == 1) { + editor.putInt("sortGroups", sort == 0 ? 1 : 0).apply(); + if(dialogsAdapter.getItemCount() > 1) { + dialogsAdapter.notifyDataSetChanged(); + } + } else if (which == 2){ + editor.putInt("defTab", def == tabVal ? -1 : tabVal).apply(); + } else if (which == 3){ + markAsReadDialog(true); + } + } + }); + showDialog(builder.create()); + return true; + } + }); + + superGroupsTab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (dialogsType != 7) { + dialogsType = 7; + refreshAdapter(context); + } + } + }); + + superGroupsTab.setOnLongClickListener(new View.OnLongClickListener() { + public boolean onLongClick(View view) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("SuperGroups", R.string.SuperGroups)); + CharSequence items[]; + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + final int tabVal = 7; + final int def = plusPreferences.getInt("defTab", -1); + final int sort = plusPreferences.getInt("sortSGroups", 0); + final boolean hideSGroups = plusPreferences.getBoolean("hideSGroups", false); + CharSequence cs2 = def == tabVal ? LocaleController.getString("ResetDefaultTab", R.string.ResetDefaultTab) : LocaleController.getString("SetAsDefaultTab", R.string.SetAsDefaultTab); + CharSequence cs1 = sort == 0 ? LocaleController.getString("SortByUnreadCount", R.string.SortByUnreadCount) : LocaleController.getString("SortByLastMessage", R.string.SortByLastMessage); + CharSequence cs0 = hideSGroups ? LocaleController.getString("ShowSuperGroupsTab", R.string.ShowSuperGroupsTab) : LocaleController.getString("HideSuperGroupsTab", R.string.HideSuperGroupsTab); + items = new CharSequence[]{cs0, cs1, cs2, LocaleController.getString("MarkAllAsRead", R.string.MarkAllAsRead)}; + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, final int which) { + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = plusPreferences.edit(); + + if (which == 0){ + RelativeLayout rl = (RelativeLayout) superGroupsTab.getParent(); + editor.putBoolean("hideSGroups", !hideSGroups).apply(); + if (!hideSGroups) { + tabsLayout.removeView(rl); + if (dialogsType == 7) { + dialogsType = 0; + refreshAdapter(context); + } + } else { + tabsLayout.addView(rl, 3, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + } + unreadCountGroups(); + } else if (which == 1) { + editor.putInt("sortSGroups", sort == 0 ? 1 : 0).apply(); + if(dialogsAdapter.getItemCount() > 1) { + dialogsAdapter.notifyDataSetChanged(); + } + } else if (which == 2){ + editor.putInt("defTab", def == tabVal ? -1 : tabVal).apply(); + } else if (which == 3){ + markAsReadDialog(true); + } + } + }); + showDialog(builder.create()); + return true; + } + }); + + channelsTab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (dialogsType != 5) { + dialogsType = 5; + refreshAdapter(context); + } + } + }); + + channelsTab.setOnLongClickListener(new View.OnLongClickListener() { + public boolean onLongClick(View view) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("Channels", R.string.Channels)); + CharSequence items[]; + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + final int tabVal = 5; + final int sort = plusPreferences.getInt("sortChannels", 0); + final int def = plusPreferences.getInt("defTab", -1); + CharSequence cs = def == tabVal ? LocaleController.getString("ResetDefaultTab", R.string.ResetDefaultTab) : LocaleController.getString("SetAsDefaultTab", R.string.SetAsDefaultTab); + CharSequence cs1 = sort == 0 ? LocaleController.getString("SortByUnreadCount", R.string.SortByUnreadCount) : LocaleController.getString("SortByLastMessage", R.string.SortByLastMessage); + items = new CharSequence[]{cs1, cs, LocaleController.getString("MarkAllAsRead", R.string.MarkAllAsRead)}; + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, final int which) { + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = plusPreferences.edit(); + if (which == 1) { + editor.putInt("defTab", def == tabVal ? -1 : tabVal).apply(); + } else if (which == 0) { + editor.putInt("sortChannels", sort == 0 ? 1 : 0).apply(); + if(dialogsAdapter.getItemCount() > 1) { + dialogsAdapter.notifyDataSetChanged(); + } + } else if (which == 2) { + markAsReadDialog(true); + } + + } + }); + showDialog(builder.create()); + return true; + } + }); + + botsTab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (dialogsType != 6) { + dialogsType = 6; + refreshAdapter(context); + } + } + }); + + botsTab.setOnLongClickListener(new View.OnLongClickListener() { + public boolean onLongClick(View view) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("Bots", R.string.Bots)); + CharSequence items[]; + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + final int tabVal = 6; + final int sort = plusPreferences.getInt("sortBots", 0); + final int def = plusPreferences.getInt("defTab", -1); + CharSequence cs = def == tabVal ? LocaleController.getString("ResetDefaultTab", R.string.ResetDefaultTab) : LocaleController.getString("SetAsDefaultTab", R.string.SetAsDefaultTab); + CharSequence cs1 = sort == 0 ? LocaleController.getString("SortByUnreadCount", R.string.SortByUnreadCount) : LocaleController.getString("SortByLastMessage", R.string.SortByLastMessage); + items = new CharSequence[]{cs1, cs, LocaleController.getString("MarkAllAsRead", R.string.MarkAllAsRead)}; + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, final int which) { + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = plusPreferences.edit(); + if (which == 1) { + editor.putInt("defTab", def == tabVal ? -1 : tabVal).apply(); + } else if (which == 0){ + editor.putInt("sortBots", sort == 0 ? 1 : 0).apply(); + if(dialogsAdapter.getItemCount() > 1) { + dialogsAdapter.notifyDataSetChanged(); + } + } else if (which == 2){ + markAsReadDialog(true); + } + } + }); + showDialog(builder.create()); + return true; + } + }); + + favsTab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (dialogsType != 8) { + dialogsType = 8; + refreshAdapter(context); + } + } + }); + + favsTab.setOnLongClickListener(new View.OnLongClickListener() { + public boolean onLongClick(View view) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("Favorites", R.string.Favorites)); + CharSequence items[]; + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + final int tabVal = 8; + final int sort = plusPreferences.getInt("sortFavs", 0); + final int def = plusPreferences.getInt("defTab", -1); + CharSequence cs = def == tabVal ? LocaleController.getString("ResetDefaultTab", R.string.ResetDefaultTab) : LocaleController.getString("SetAsDefaultTab", R.string.SetAsDefaultTab); + CharSequence cs1 = sort == 0 ? LocaleController.getString("SortByUnreadCount", R.string.SortByUnreadCount) : LocaleController.getString("SortByLastMessage", R.string.SortByLastMessage); + items = new CharSequence[]{cs1, cs, LocaleController.getString("MarkAllAsRead", R.string.MarkAllAsRead)}; + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, final int which) { + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = plusPreferences.edit(); + if (which == 1) { + editor.putInt("defTab", def == tabVal ? -1 : tabVal).apply(); + } else if (which == 0){ + editor.putInt("sortFavs", sort == 0 ? 1 : 0).apply(); + if(dialogsAdapter.getItemCount() > 1) { + dialogsAdapter.notifyDataSetChanged(); + } + } else if (which == 2){ + markAsReadDialog(true); + } + + } + }); + showDialog(builder.create()); + return true; + } + }); + } + + private void addTabView(Context context, ImageView iv, TextView tv, boolean show){ + //SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + //int cColor = themePrefs.getInt("chatsHeaderTabCounterColor", 0xffffffff); + //int bgColor = themePrefs.getInt("chatsHeaderTabCounterBGColor", 0xffff0000); + + iv.setScaleType(ImageView.ScaleType.CENTER); + //int size = themePrefs.getInt("chatsHeaderTabCounterSize", 11); + //tv.setTextSize(TypedValue.COMPLEX_UNIT_DIP, size); + tv.setGravity(Gravity.CENTER); + //tv.setTextColor(cColor); + + GradientDrawable shape = new GradientDrawable(); + shape.setShape(GradientDrawable.RECTANGLE); + shape.setCornerRadius(AndroidUtilities.dp(32)); + //shape.setColor(bgColor); + + tv.setBackgroundDrawable(shape); + //tv.setPadding(AndroidUtilities.dp(size > 10 ? size - 7 : 4), 0, AndroidUtilities.dp(size > 10 ? size - 7 : 4), 0); + RelativeLayout layout = new RelativeLayout(context); + layout.addView(iv, LayoutHelper.createRelative(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + layout.addView(tv, LayoutHelper.createRelative(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, 0, 0, 3, 6, RelativeLayout.ALIGN_PARENT_RIGHT)); + RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) tv.getLayoutParams(); + params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); + tv.setLayoutParams(params); + if(show){ + tabsLayout.addView(layout, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + } + } + + private AlertDialog.Builder createTabsDialog(final Context context, AlertDialog.Builder builder){ + builder.setTitle(LocaleController.getString("HideShowTabs", R.string.HideShowTabs)); + + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean hideUsers = plusPreferences.getBoolean("hideUsers", false); + boolean hideGroups = plusPreferences.getBoolean("hideGroups", false); + boolean hideSGroups = plusPreferences.getBoolean("hideSGroups", false); + boolean hideChannels = plusPreferences.getBoolean("hideChannels", false); + boolean hideBots = plusPreferences.getBoolean("hideBots", false); + boolean hideFavs = plusPreferences.getBoolean("hideFavs", false); + + builder.setMultiChoiceItems( + new CharSequence[]{LocaleController.getString("Users", R.string.Users), LocaleController.getString("Groups", R.string.Groups), LocaleController.getString("SuperGroups", R.string.SuperGroups), LocaleController.getString("Channels", R.string.Channels), LocaleController.getString("Bots", R.string.Bots), LocaleController.getString("Favorites", R.string.Favorites)}, + new boolean[]{!hideUsers, !hideGroups, !hideSGroups, !hideChannels, !hideBots, !hideFavs}, + new DialogInterface.OnMultiChoiceClickListener() { + @Override + public void onClick(DialogInterface dialog, int which, boolean isChecked) { + + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = plusPreferences.edit(); + + boolean hide = plusPreferences.getBoolean("hideTabs", false); + + boolean hideUsers = plusPreferences.getBoolean("hideUsers", false); + boolean hideGroups = plusPreferences.getBoolean("hideGroups", false); + boolean hideSGroups = plusPreferences.getBoolean("hideSGroups", false); + boolean hideChannels = plusPreferences.getBoolean("hideChannels", false); + boolean hideBots = plusPreferences.getBoolean("hideBots", false); + boolean hideFavs = plusPreferences.getBoolean("hideFavs", false); + + if (which == 0) { + RelativeLayout rl = (RelativeLayout) usersTab.getParent(); + editor.putBoolean("hideUsers", !hideUsers).apply(); + if (!hideUsers) { + tabsLayout.removeView(rl); + if (dialogsType == 3) { + dialogsType = 0; + refreshAdapter(context); + } + hideUsers = true; + } else { + tabsLayout.addView(rl, 1, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + } + } else if (which == 1) { + RelativeLayout rl = (RelativeLayout) groupsTab.getParent(); + editor.putBoolean("hideGroups", !hideGroups).apply(); + if (!hideGroups) { + tabsLayout.removeView(rl); + if (dialogsType == 4) { + dialogsType = 0; + refreshAdapter(context); + } + hideGroups = true; + } else { + tabsLayout.addView(rl, hideUsers ? 1 : 2, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + } + } else if (which == 2) { + RelativeLayout rl = (RelativeLayout) superGroupsTab.getParent(); + editor.putBoolean("hideSGroups", !hideSGroups).apply(); + if (!hideSGroups) { + tabsLayout.removeView(rl); + if (dialogsType == 7) { + dialogsType = 4; + refreshAdapter(context); + } + hideSGroups = true; + } else { + int pos = 3; + if (hideUsers) pos = pos - 1; + if (hideGroups) pos = pos - 1; + tabsLayout.addView(rl, pos, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + } + } else if (which == 3) { + RelativeLayout rl = (RelativeLayout) channelsTab.getParent(); + editor.putBoolean("hideChannels", !hideChannels).apply(); + if (!hideChannels) { + tabsLayout.removeView(rl); + if (dialogsType == 5) { + dialogsType = 0; + refreshAdapter(context); + } + hideChannels = true; + } else { + int place = tabsLayout.getChildCount(); + if (!hideFavs) --place; + if (!hideBots) --place; + tabsLayout.addView(rl, place, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + } + } else if (which == 4) { + RelativeLayout rl = (RelativeLayout) botsTab.getParent(); + editor.putBoolean("hideBots", !hideBots).apply(); + if (!hideBots) { + tabsLayout.removeView(rl); + if (dialogsType == 6) { + dialogsType = 0; + refreshAdapter(context); + } + hideBots = true; + } else { + int place = tabsLayout.getChildCount(); + if (!hideFavs) --place; + tabsLayout.addView(rl, place, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, Gravity.TOP, 0, 0, 0, 0)); + } + } else if (which == 5) { + RelativeLayout rl = (RelativeLayout) favsTab.getParent(); + editor.putBoolean("hideFavs", !hideFavs).apply(); + if (!hideFavs) { + tabsLayout.removeView(rl); + if (dialogsType == 8) { + dialogsType = 0; + refreshAdapter(context); + } + hideFavs = true; + } else { + tabsLayout.addView(rl, tabsLayout.getChildCount(), LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + } + } + if (hideUsers && hideGroups && hideSGroups && hideChannels && hideBots && hideFavs) { + hideTabs = true; + editor.putBoolean("hideTabs", true).apply(); + refreshTabAndListViews(true); + } + if (isChecked && hide) { + hideTabs = false; + editor.putBoolean("hideTabs", false).apply(); + refreshTabAndListViews(false); + } + } + }); + return builder; + } + + private void refreshAdapter(Context context){ + refreshAdapterAndTabs(new DialogsAdapter(context, dialogsType)); + } + + private void refreshAdapterAndTabs(DialogsAdapter adapter){ + dialogsAdapter = adapter; + listView.setAdapter(dialogsAdapter); + dialogsAdapter.notifyDataSetChanged(); + if(!onlySelect){ + selectedTab = dialogsType == 9 ? 4 : dialogsType; + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = plusPreferences.edit(); + editor.putInt("selTab", selectedTab).apply(); + } + refreshTabs(); + } + + private void refreshTabs(){ + //resetTabs(); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int defColor = themePrefs.getInt("chatsHeaderIconsColor", 0xffffffff); + int iconColor = themePrefs.getInt("chatsHeaderTabIconColor", defColor); + + int iColor = themePrefs.getInt("chatsHeaderTabUnselectedIconColor", AndroidUtilities.getIntAlphaColor("chatsHeaderTabIconColor", defColor, 0.3f)); + + allTab.setBackgroundResource(0); + usersTab.setBackgroundResource(0); + groupsTab.setBackgroundResource(0); + superGroupsTab.setBackgroundResource(0); + channelsTab.setBackgroundResource(0); + botsTab.setBackgroundResource(0); + favsTab.setBackgroundResource(0); + + allTab.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); + usersTab.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); + groupsTab.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); + superGroupsTab.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); + channelsTab.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); + botsTab.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); + favsTab.setColorFilter(iColor, PorterDuff.Mode.SRC_IN); + + Drawable selected = getParentActivity().getResources().getDrawable(R.drawable.tab_selected); + selected.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + + switch(dialogsType == 9 ? 4 : dialogsType) { + case 3: + usersTab.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + usersTab.setBackgroundDrawable(selected); + break; + case 4: + groupsTab.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + groupsTab.setBackgroundDrawable(selected); + break; + case 5: + channelsTab.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + channelsTab.setBackgroundDrawable(selected); + break; + case 6: + botsTab.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + botsTab.setBackgroundDrawable(selected); + break; + case 7: + superGroupsTab.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + superGroupsTab.setBackgroundDrawable(selected); + break; + case 8: + favsTab.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + favsTab.setBackgroundDrawable(selected); + break; + default: + allTab.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + allTab.setBackgroundDrawable(selected); + } + + String t = getHeaderAllTitles(); + actionBar.setTitle(t); + paintHeader(true); + + if (getDialogsArray() != null && getDialogsArray().isEmpty()) { + searchEmptyView.setVisibility(View.GONE); + progressView.setVisibility(View.GONE); + + if(emptyView.getChildCount() > 0){ + TextView tv = (TextView) emptyView.getChildAt(0); + if(tv != null){ + tv.setText(dialogsType < 3 ? LocaleController.getString("NoChats", R.string.NoChats) : dialogsType == 8 ? LocaleController.getString("NoFavoritesHelp", R.string.NoFavoritesHelp) : t); + tv.setTextColor(themePrefs.getInt("chatsNameColor", 0xff212121)); + } + if(emptyView.getChildAt(1) != null)emptyView.getChildAt(1).setVisibility(View.GONE); + } + + emptyView.setVisibility(View.VISIBLE); + emptyView.setBackgroundColor(themePrefs.getInt("chatsRowColor", 0xffffffff)); + listView.setEmptyView(emptyView); + } + } + + private void hideShowTabs(int i){ + RelativeLayout rl = null; + int pos = 0; + boolean b = false; + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean hideUsers = plusPreferences.getBoolean("hideUsers", false); + boolean hideGroups = plusPreferences.getBoolean("hideGroups", false); + boolean hideSGroups = plusPreferences.getBoolean("hideSGroups", false); + boolean hideBots = plusPreferences.getBoolean("hideBots", false); + boolean hideFavs = plusPreferences.getBoolean("hideFavs", false); + switch(i) { + case 0: // Users + rl = (RelativeLayout) usersTab.getParent(); + pos = 1; + b = hideUsers; + break; + case 1: //Groups + rl = (RelativeLayout) groupsTab.getParent(); + pos = hideUsers ? 1 : 2; + b = hideGroups; + break; + case 2: //Supergroups + rl = (RelativeLayout) superGroupsTab.getParent(); + pos = 3; + if(hideGroups)pos = pos - 1; + if(hideUsers)pos = pos - 1; + b = hideSGroups; + break; + case 3: //Channels + rl = (RelativeLayout) channelsTab.getParent(); + pos = tabsLayout.getChildCount(); + if(!hideBots)pos = pos - 1; + if(!hideFavs)pos = pos - 1; + b = plusPreferences.getBoolean("hideChannels", false); + break; + case 4: //Bots + rl = (RelativeLayout) botsTab.getParent(); + pos = tabsLayout.getChildCount(); + if(!hideFavs)pos = pos - 1; + b = hideBots; + break; + case 5: //Favorites + rl = (RelativeLayout) favsTab.getParent(); + pos = tabsLayout.getChildCount(); + b = hideFavs; + break; + default: + updateTabs(); + } + + if(rl != null) { + if (!b) { + tabsLayout.addView(rl, pos, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f)); + } else { + tabsLayout.removeView(rl); + } + } + + } + + private void updateTabs(){ + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + hideTabs = plusPreferences.getBoolean("hideTabs", false); + disableAnimation = plusPreferences.getBoolean("disableTabsAnimation", false); + + tabsHeight = plusPreferences.getInt("tabsHeight", 40); + + refreshTabAndListViews(false); + + if (hideTabs && dialogsType > 2) { + dialogsType = 0; + refreshAdapterAndTabs(dialogsBackupAdapter); + } + //hideTabsAnimated(false); + } + + private void refreshTabAndListViews(boolean forceHide){ + if(hideTabs || forceHide){ + tabsView.setVisibility(View.GONE); + listView.setPadding(0, 0, 0, 0); + }else{ + tabsView.setVisibility(View.VISIBLE); + int h = AndroidUtilities.dp(tabsHeight); + ViewGroup.LayoutParams params = tabsView.getLayoutParams(); + if(params != null){ + params.height = h; + tabsView.setLayoutParams(params); + } + listView.setPadding(0, h, 0, 0); + hideTabsAnimated(false); + } + listView.scrollToPosition(0); + } + + private void hideTabsAnimated(final boolean hide){ + if (tabsHidden == hide) { + return; + } + tabsHidden = hide; + if(hide)listView.setPadding(0, 0, 0, 0); + ObjectAnimatorProxy animator = ObjectAnimatorProxy.ofFloatProxy(tabsView, "translationY", hide ? -AndroidUtilities.dp(tabsHeight) : 0).setDuration(300); + animator.addListener(new AnimatorListenerAdapterProxy() { + @Override + public void onAnimationEnd(Object animation) { + if(!tabsHidden)listView.setPadding(0, AndroidUtilities.dp(tabsHeight) , 0, 0); + } + }); + animator.start(); + } + + private void refreshDialogType(int d){ + if(hideTabs)return; + SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean hideUsers = plusPreferences.getBoolean("hideUsers", false); + boolean hideGroups = plusPreferences.getBoolean("hideGroups", false); + boolean hideSGroups = plusPreferences.getBoolean("hideSGroups", false); + boolean hideChannels = plusPreferences.getBoolean("hideChannels", false); + boolean hideBots = plusPreferences.getBoolean("hideBots", false); + boolean hideFavs = plusPreferences.getBoolean("hideFavs", false); + boolean loop = plusPreferences.getBoolean("infiniteTabsSwipe", false); + if(d == 1){ + switch(dialogsType) { + case 3: // Users + if(hideGroups){ + dialogsType = !hideSGroups ? 7 : !hideChannels ? 5 : !hideBots ? 6 : !hideFavs ? 8 : loop ? 0 : dialogsType; + }else{ + dialogsType = hideSGroups ? 9 : 4; + } + break; + case 4: //Groups + dialogsType = !hideSGroups ? 7 : !hideChannels ? 5 : !hideBots ? 6 : !hideFavs ? 8 : loop ? 0 : dialogsType; + break; + case 9: //Groups + case 7: //Supergroups + dialogsType = !hideChannels ? 5 : !hideBots ? 6 : !hideFavs ? 8 : loop ? 0 : dialogsType; + break; + case 5: //Channels + dialogsType = !hideBots ? 6 : !hideFavs ? 8 : loop ? 0 : dialogsType; + break; + case 6: //Bots + dialogsType = !hideFavs ? 8 : loop ? 0 : dialogsType; + break; + case 8: //Favorites + if(loop){ + dialogsType = 0; + } + break; + default: //All + dialogsType = !hideUsers ? 3 : !hideGroups && hideSGroups ? 9 : !hideGroups ? 7 : !hideChannels ? 5 : !hideBots ? 6 : !hideFavs ? 8 : loop ? 0 : dialogsType; + } + }else{ + switch(dialogsType) { + case 3: // Users + dialogsType = 0; + break; + case 4: //Groups + case 9: //Groups + dialogsType = !hideUsers ? 3 : 0; + break; + case 7: //Supergroups + dialogsType = !hideGroups ? 4 : !hideUsers ? 3 : 0; + break; + case 5: //Channels + dialogsType = !hideSGroups ? 7 : !hideGroups ? 9 : !hideUsers ? 3 : 0; + break; + case 6: //Bots + dialogsType = !hideChannels ? 5 : !hideSGroups ? 7 : !hideGroups ? 9 : !hideUsers ? 3 : 0; + break; + case 8: //Favorites + dialogsType = !hideBots ? 6 : !hideChannels ? 5 : !hideSGroups ? 7 : !hideGroups ? 9 : !hideUsers ? 3 : 0; + break; + default: //All + if(loop){ + dialogsType = !hideFavs ? 8 : !hideBots ? 6 : !hideChannels ? 5 : !hideSGroups ? 7 : !hideGroups ? 9 : !hideUsers ? 3 : 0; + } + } + } + + } + + @Override + public PhotoViewer.PlaceProviderObject getPlaceForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index) { + if (fileLocation == null) { + return null; + } + + TLRPC.FileLocation photoBig = null; + if (user_id != 0) { + TLRPC.User user = MessagesController.getInstance().getUser(user_id); + if (user != null && user.photo != null && user.photo.photo_big != null) { + photoBig = user.photo.photo_big; + } + } else if (chat_id != 0) { + TLRPC.Chat chat = MessagesController.getInstance().getChat(chat_id); + if (chat != null && chat.photo != null && chat.photo.photo_big != null) { + photoBig = chat.photo.photo_big; + } + } + + if (photoBig != null && photoBig.local_id == fileLocation.local_id && photoBig.volume_id == fileLocation.volume_id && photoBig.dc_id == fileLocation.dc_id) { + int coords[] = new int[2]; + avatarImage.getLocationInWindow(coords); + PhotoViewer.PlaceProviderObject object = new PhotoViewer.PlaceProviderObject(); + object.viewX = coords[0]; + object.viewY = coords[1] - AndroidUtilities.statusBarHeight; + object.parentView = avatarImage; + object.imageReceiver = avatarImage.getImageReceiver(); + object.user_id = user_id; + object.thumb = object.imageReceiver.getBitmap(); + object.size = -1; + object.radius = avatarImage.getImageReceiver().getRoundRadius(); + return object; + } + return null; + } + + @Override + public Bitmap getThumbForPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index) { + return null; + } + + @Override + public void willSwitchFromPhoto(MessageObject messageObject, TLRPC.FileLocation fileLocation, int index) { + + } + + @Override + public void willHidePhotoViewer() { + + } + + @Override + public boolean isPhotoChecked(int index) { + return false; + } + + @Override + public void setPhotoChecked(int index) { + + } + + @Override + public boolean cancelButtonPressed() { + return true; + } + + @Override + public void sendButtonPressed(int index) { + + } + + @Override + public int getSelectedCount() { + return 0; + } + + @Override + public void updatePhotoAtIndex(int index) { + + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/DocumentSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/DocumentSelectActivity.java index 960ac0dd..e3cff7de 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/DocumentSelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/DocumentSelectActivity.java @@ -40,7 +40,13 @@ import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.BackDrawable; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.BaseFragmentAdapter; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; +import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; +import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Cells.SharedDocumentCell; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.NumberTextView; @@ -155,6 +161,8 @@ public class DocumentSelectActivity extends BaseFragment { SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); Drawable d = new BackDrawable(false); ((BackDrawable) d).setColor(themePrefs.getInt("chatHeaderIconsColor", 0xffffffff)); + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + actionBar.setBackgroundColor(def); actionBar.setBackButtonDrawable(d); actionBar.setAllowOverlayTitle(true); actionBar.setTitle(LocaleController.getString("SelectFile", R.string.SelectFile)); @@ -196,7 +204,7 @@ public class DocumentSelectActivity extends BaseFragment { }); actionMode.addView(selectedMessagesCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 65, 0, 0, 0)); - actionModeViews.add(actionMode.addItem(done, R.drawable.ic_ab_done_gray, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); + actionModeViews.add(actionMode.addItem(done, R.drawable.ic_ab_done_gray, Theme.ACTION_BAR_MODE_SELECTOR_COLOR, null, AndroidUtilities.dp(54))); fragmentView = getParentActivity().getLayoutInflater().inflate(R.layout.document_select_layout, null, false); listAdapter = new ListAdapter(context); @@ -463,8 +471,9 @@ public class DocumentSelectActivity extends BaseFragment { }*/ } }); - for (File file : files) { - if (file.getName().startsWith(".")) { + for (int a = 0; a < files.length; a++) { + File file = files[a]; + if (file.getName().indexOf('.') == 0) { continue; } ListItem item = new ListItem(); @@ -527,7 +536,7 @@ public class DocumentSelectActivity extends BaseFragment { String defaultPathState = Environment.getExternalStorageState(); if (defaultPathState.equals(Environment.MEDIA_MOUNTED) || defaultPathState.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) { ListItem ext = new ListItem(); - if (Build.VERSION.SDK_INT < 9 || Environment.isExternalStorageRemovable()) { + if (Environment.isExternalStorageRemovable()) { ext.title = LocaleController.getString("SdCard", R.string.SdCard); ext.icon = R.drawable.ic_external_storage; } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java index 4a3fd98a..469f469f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateActivity.java @@ -9,6 +9,7 @@ package org.telegram.ui; import android.app.Activity; +import android.app.AlertDialog; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -77,12 +78,13 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen private int beforeChangeIndex; private boolean ignoreChange; private CharSequence changeString; - private int maxCount = 199; + private int maxCount = 5000; private int chatType = ChatObject.CHAT_TYPE_CHAT; private boolean isAlwaysShare; private boolean isNeverShare; private boolean searchWas; private boolean searching; + private boolean isGroup; private HashMap selectedContacts = new HashMap<>(); private ArrayList allSpans = new ArrayList<>(); @@ -97,7 +99,8 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen chatType = args.getInt("chatType", ChatObject.CHAT_TYPE_CHAT); isAlwaysShare = args.getBoolean("isAlwaysShare", false); isNeverShare = args.getBoolean("isNeverShare", false); - maxCount = chatType == ChatObject.CHAT_TYPE_CHAT ? (MessagesController.getInstance().maxGroupCount - 1) : MessagesController.getInstance().maxBroadcastCount; + isGroup = args.getBoolean("isGroup", false); + maxCount = chatType == ChatObject.CHAT_TYPE_CHAT ? MessagesController.getInstance().maxMegagroupCount : MessagesController.getInstance().maxBroadcastCount; } @Override @@ -124,9 +127,17 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); if (isAlwaysShare) { - actionBar.setTitle(LocaleController.getString("AlwaysShareWithTitle", R.string.AlwaysShareWithTitle)); + if (isGroup) { + actionBar.setTitle(LocaleController.getString("AlwaysAllow", R.string.AlwaysAllow)); + } else { + actionBar.setTitle(LocaleController.getString("AlwaysShareWithTitle", R.string.AlwaysShareWithTitle)); + } } else if (isNeverShare) { - actionBar.setTitle(LocaleController.getString("NeverShareWithTitle", R.string.NeverShareWithTitle)); + if (isGroup) { + actionBar.setTitle(LocaleController.getString("NeverAllow", R.string.NeverAllow)); + } else { + actionBar.setTitle(LocaleController.getString("NeverShareWithTitle", R.string.NeverShareWithTitle)); + } } else { actionBar.setTitle(chatType == ChatObject.CHAT_TYPE_CHAT ? LocaleController.getString("NewGroup", R.string.NewGroup) : LocaleController.getString("NewBroadcastList", R.string.NewBroadcastList)); actionBar.setSubtitle(LocaleController.formatString("MembersCount", R.string.MembersCount, selectedContacts.size(), maxCount)); @@ -191,9 +202,17 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen frameLayout.addView(userSelectEditText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 10, 0, 10, 0)); if (isAlwaysShare) { - userSelectEditText.setHint(LocaleController.getString("AlwaysShareWithPlaceholder", R.string.AlwaysShareWithPlaceholder)); + if (isGroup) { + userSelectEditText.setHint(LocaleController.getString("AlwaysAllowPlaceholder", R.string.AlwaysAllowPlaceholder)); + } else { + userSelectEditText.setHint(LocaleController.getString("AlwaysShareWithPlaceholder", R.string.AlwaysShareWithPlaceholder)); + } } else if (isNeverShare) { - userSelectEditText.setHint(LocaleController.getString("NeverShareWithPlaceholder", R.string.NeverShareWithPlaceholder)); + if (isGroup) { + userSelectEditText.setHint(LocaleController.getString("NeverAllowPlaceholder", R.string.NeverAllowPlaceholder)); + } else { + userSelectEditText.setHint(LocaleController.getString("NeverShareWithPlaceholder", R.string.NeverShareWithPlaceholder)); + } } else { userSelectEditText.setHint(LocaleController.getString("SendMessageTo", R.string.SendMessageTo)); } @@ -356,6 +375,14 @@ public class GroupCreateActivity extends BaseFragment implements NotificationCen if (maxCount != 0 && selectedContacts.size() == maxCount) { return; } + if (chatType == ChatObject.CHAT_TYPE_CHAT && selectedContacts.size() == MessagesController.getInstance().maxGroupCount - 1) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setMessage(LocaleController.getString("SoftUserLimitAlert", R.string.SoftUserLimitAlert)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + showDialog(builder.create()); + return; + } ignoreChange = true; ChipSpan span = createAndPutChipForUser(user); span.uid = user.id; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java index 3cbe3a9e..4cde07fd 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupCreateFinalActivity.java @@ -164,7 +164,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati donePressed = true; if (chatType == ChatObject.CHAT_TYPE_BROADCAST) { - MessagesController.getInstance().createChat(nameTextView.getText().toString(), selectedContacts, null, chatType); + MessagesController.getInstance().createChat(nameTextView.getText().toString(), selectedContacts, null, chatType, GroupCreateFinalActivity.this); } else { if (avatarUpdater.uploadingAvatar != null) { createAfterUpload = true; @@ -174,7 +174,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati progressDialog.setCanceledOnTouchOutside(false); progressDialog.setCancelable(false); - final int reqId = MessagesController.getInstance().createChat(nameTextView.getText().toString(), selectedContacts, null, chatType); + final int reqId = MessagesController.getInstance().createChat(nameTextView.getText().toString(), selectedContacts, null, chatType, GroupCreateFinalActivity.this); progressDialog.setButton(DialogInterface.BUTTON_NEGATIVE, LocaleController.getString("Cancel", R.string.Cancel), new DialogInterface.OnClickListener() { @Override @@ -335,7 +335,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati avatarImage.setImage(avatar, "50_50", avatarDrawable); if (createAfterUpload) { FileLog.e("tmessages", "avatar did uploaded"); - MessagesController.getInstance().createChat(nameTextView.getText().toString(), selectedContacts, null, chatType); + MessagesController.getInstance().createChat(nameTextView.getText().toString(), selectedContacts, null, chatType, GroupCreateFinalActivity.this); } } }); @@ -450,7 +450,7 @@ public class GroupCreateFinalActivity extends BaseFragment implements Notificati @Override public View getView(int i, View view, ViewGroup viewGroup) { if (view == null) { - view = new UserCell(mContext, 1, 0); + view = new UserCell(mContext, 1, 0, false); } TLRPC.User user = MessagesController.getInstance().getUser(selectedContacts.get(i)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/GroupInviteActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/GroupInviteActivity.java index 09fea806..17b7765b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/GroupInviteActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/GroupInviteActivity.java @@ -12,6 +12,7 @@ import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Build; import android.view.Gravity; import android.view.View; @@ -105,8 +106,9 @@ public class GroupInviteActivity extends BaseFragment implements NotificationCen fragmentView = new FrameLayout(context); FrameLayout frameLayout = (FrameLayout) fragmentView; - frameLayout.setBackgroundColor(0xfff0f0f0); - + //frameLayout.setBackgroundColor(0xfff0f0f0); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + frameLayout.setBackgroundColor(preferences.getInt("prefBGColor", 0xfff0f0f0)); FrameLayout progressView = new FrameLayout(context); frameLayout.addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); @@ -315,11 +317,16 @@ public class GroupInviteActivity extends BaseFragment implements NotificationCen view.setBackgroundResource(R.drawable.greydivider); } } else if (type == 2) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int bgColor = preferences.getInt("prefBGColor", 0xffffffff); + int titleColor = preferences.getInt("prefTitleColor", 0xff212121); if (view == null) { view = new TextBlockCell(mContext); - view.setBackgroundColor(0xffffffff); + //view.setBackgroundColor(0xffffffff); + view.setBackgroundColor(bgColor); } ((TextBlockCell) view).setText(invite != null ? invite.link : "error", false); + ((TextBlockCell) view).setTextColor(titleColor); } return view; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/IdenticonActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/IdenticonActivity.java index 0dcbd1d6..401a1b00 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/IdenticonActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/IdenticonActivity.java @@ -10,28 +10,54 @@ package org.telegram.ui; import android.content.Context; import android.os.Bundle; +import android.support.annotation.NonNull; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.method.LinkMovementMethod; +import android.util.TypedValue; +import android.view.Gravity; import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.ViewTreeObserver; import android.view.WindowManager; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.Utilities; import org.telegram.tgnet.TLRPC; import org.telegram.messenger.MessagesController; import org.telegram.messenger.R; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Components.IdenticonDrawable; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.ActionBar.Theme; +import org.telegram.ui.Components.URLSpanReplacement; public class IdenticonActivity extends BaseFragment { + private int chat_id; + private static class LinkMovementMethodMy extends LinkMovementMethod { + @Override + public boolean onTouchEvent(@NonNull TextView widget, @NonNull Spannable buffer, @NonNull MotionEvent event) { + try { + return super.onTouchEvent(widget, buffer, event); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + return false; + } + } + public IdenticonActivity(Bundle args) { super(args); } @@ -57,18 +83,11 @@ public class IdenticonActivity extends BaseFragment { } }); - fragmentView = getParentActivity().getLayoutInflater().inflate(R.layout.identicon_layout, null, false); - ImageView identiconView = (ImageView) fragmentView.findViewById(R.id.identicon_view); - TextView textView = (TextView) fragmentView.findViewById(R.id.identicon_text); - TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(chat_id); - if (encryptedChat != null) { - IdenticonDrawable drawable = new IdenticonDrawable(); - identiconView.setImageDrawable(drawable); - drawable.setEncryptedChat(encryptedChat); - TLRPC.User user = MessagesController.getInstance().getUser(encryptedChat.user_id); - textView.setText(AndroidUtilities.replaceTags(LocaleController.formatString("EncryptionKeyDescription", R.string.EncryptionKeyDescription, user.first_name, user.first_name))); - } - + fragmentView = new LinearLayout(context); + LinearLayout linearLayout = (LinearLayout) fragmentView; + linearLayout.setOrientation(LinearLayout.VERTICAL); + linearLayout.setWeightSum(100); + linearLayout.setBackgroundColor(0xfff0f0f0); fragmentView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { @@ -76,6 +95,61 @@ public class IdenticonActivity extends BaseFragment { } }); + FrameLayout frameLayout = new FrameLayout(context); + frameLayout.setPadding(AndroidUtilities.dp(20), AndroidUtilities.dp(20), AndroidUtilities.dp(20), AndroidUtilities.dp(20)); + linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 50.0f)); + + ImageView identiconView = new ImageView(context); + identiconView.setScaleType(ImageView.ScaleType.FIT_XY); + frameLayout.addView(identiconView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + frameLayout = new FrameLayout(context); + frameLayout.setBackgroundColor(0xffffffff); + frameLayout.setPadding(AndroidUtilities.dp(10), 0, AndroidUtilities.dp(10), AndroidUtilities.dp(10)); + linearLayout.addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, 50.0f)); + + TextView textView = new TextView(context); + textView.setTextColor(0xff7f7f7f); + textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16); + textView.setLinksClickable(true); + textView.setClickable(true); + textView.setMovementMethod(new LinkMovementMethodMy()); + //textView.setAutoLinkMask(Linkify.WEB_URLS); + textView.setLinkTextColor(Theme.MSG_LINK_TEXT_COLOR); + textView.setGravity(Gravity.CENTER); + frameLayout.addView(textView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + + TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat(chat_id); + if (encryptedChat != null) { + IdenticonDrawable drawable = new IdenticonDrawable(); + identiconView.setImageDrawable(drawable); + drawable.setEncryptedChat(encryptedChat); + TLRPC.User user = MessagesController.getInstance().getUser(encryptedChat.user_id); + SpannableStringBuilder hash = new SpannableStringBuilder(); + if (encryptedChat.key_hash.length > 16) { + String hex = Utilities.bytesToHex(encryptedChat.key_hash); + for (int a = 0; a < 32; a++) { + if (a != 0) { + if (a % 8 == 0) { + hash.append('\n'); + } else if (a % 4 == 0) { + hash.append(' '); + } + } + hash.append(hex.substring(a * 2, a * 2 + 2)); + hash.append(' '); + } + hash.append("\n\n"); + } + hash.append(AndroidUtilities.replaceTags(LocaleController.formatString("EncryptionKeyDescription", R.string.EncryptionKeyDescription, user.first_name, user.first_name))); + final String url = "telegram.org"; + int index = hash.toString().indexOf(url); + if (index != -1) { + hash.setSpan(new URLSpanReplacement(LocaleController.getString("EncryptionKeyLink", R.string.EncryptionKeyLink)), index, index + url.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + textView.setText(hash); + } + return fragmentView; } @@ -100,7 +174,7 @@ public class IdenticonActivity extends BaseFragment { return true; } fragmentView.getViewTreeObserver().removeOnPreDrawListener(this); - LinearLayout layout = (LinearLayout)fragmentView; + LinearLayout layout = (LinearLayout) fragmentView; WindowManager manager = (WindowManager) ApplicationLoader.applicationContext.getSystemService(Context.WINDOW_SERVICE); int rotation = manager.getDefaultDisplay().getRotation(); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ImageListActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ImageListActivity.java index 44801346..709da38a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ImageListActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ImageListActivity.java @@ -2,6 +2,8 @@ package org.telegram.ui; import android.content.Context; import android.content.SharedPreferences; +import android.graphics.PorterDuff; +import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -12,15 +14,33 @@ import android.widget.ListView; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.LocaleController; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; public class ImageListActivity extends BaseFragment { - private ListView list; + private int arrayId; + + public ImageListActivity(Bundle args) { + super(args); + } + + @Override + public boolean onFragmentCreate() { + arrayId = arguments.getInt("array_id", 0); + + if (arrayId != 0) { + + } + //Log.e("ImageListActivity","arrayId " + arrayId); + super.onFragmentCreate(); + return true; + } + //private ListView list; private CustomListAdapter listAdapter; private static String[] bubblesNamesArray ={ @@ -30,7 +50,8 @@ public class ImageListActivity extends BaseFragment { "Notepad", "Ed", "Edge", - "iOS" + "iOS", + "Telegram_old" }; Integer[] imgid ={ @@ -41,24 +62,120 @@ public class ImageListActivity extends BaseFragment { R.drawable.msg_in_5, R.drawable.msg_in_6, R.drawable.msg_in_7, + R.drawable.msg_in_8, R.drawable.msg_out, R.drawable.msg_out_2, R.drawable.msg_out_3, R.drawable.msg_out_4, R.drawable.msg_out_5, R.drawable.msg_out_6, - R.drawable.msg_out_7 + R.drawable.msg_out_7, + R.drawable.msg_out_8 + }; + + private static String[] checksNamesArray ={ + "Stock", + "EdCheck", + "Lex", + "Gladiator", + "MaxChecks", + "ElipLex", + "CubeLex", + "MaxLines", + "RLex", + "MaxLinesPro", + "ReadLex", + "MaxHeart" + }; + + Integer[] checkid ={ + R.drawable.dialogs_check, + R.drawable.dialogs_check_2, + R.drawable.dialogs_check_3, + R.drawable.dialogs_check_4, + R.drawable.dialogs_check_5, + R.drawable.dialogs_check_6, + R.drawable.dialogs_check_7, + R.drawable.dialogs_check_8, + R.drawable.dialogs_check_9, + R.drawable.dialogs_check_10, + R.drawable.dialogs_check_11, + R.drawable.dialogs_check_12, + R.drawable.dialogs_halfcheck, + R.drawable.dialogs_halfcheck_2, + R.drawable.dialogs_halfcheck_3, + R.drawable.dialogs_halfcheck_4, + R.drawable.dialogs_halfcheck_5, + R.drawable.dialogs_halfcheck_6, + R.drawable.dialogs_halfcheck_7, + R.drawable.dialogs_halfcheck_8, + R.drawable.dialogs_halfcheck_9, + R.drawable.dialogs_halfcheck_10, + R.drawable.dialogs_halfcheck_11, + R.drawable.dialogs_halfcheck_12, + R.drawable.msg_check, + R.drawable.msg_check_2, + R.drawable.msg_check_3, + R.drawable.msg_check_4, + R.drawable.msg_check_5, + R.drawable.msg_check_6, + R.drawable.msg_check_7, + R.drawable.msg_check_8, + R.drawable.msg_check_9, + R.drawable.msg_check_10, + R.drawable.msg_check_11, + R.drawable.msg_check_12, + R.drawable.msg_halfcheck, + R.drawable.msg_halfcheck_2, + R.drawable.msg_halfcheck_3, + R.drawable.msg_halfcheck_4, + R.drawable.msg_halfcheck_5, + R.drawable.msg_halfcheck_6, + R.drawable.msg_halfcheck_7, + R.drawable.msg_halfcheck_8, + R.drawable.msg_halfcheck_9, + R.drawable.msg_halfcheck_10, + R.drawable.msg_halfcheck_11, + R.drawable.msg_halfcheck_12, + R.drawable.msg_check_w, + R.drawable.msg_check_w_2, + R.drawable.msg_check_w_3, + R.drawable.msg_check_w_4, + R.drawable.msg_check_w_5, + R.drawable.msg_check_w_6, + R.drawable.msg_check_w_7, + R.drawable.msg_check_w_8, + R.drawable.msg_check_w_9, + R.drawable.msg_check_w_10, + R.drawable.msg_check_w_11, + R.drawable.msg_check_w_12, + R.drawable.msg_halfcheck_w, + R.drawable.msg_halfcheck_w_2, + R.drawable.msg_halfcheck_w_3, + R.drawable.msg_halfcheck_w_4, + R.drawable.msg_halfcheck_w_5, + R.drawable.msg_halfcheck_w_6, + R.drawable.msg_halfcheck_w_7, + R.drawable.msg_halfcheck_w_8, + R.drawable.msg_halfcheck_w_9, + R.drawable.msg_halfcheck_w_10, + R.drawable.msg_halfcheck_w_11, + R.drawable.msg_halfcheck_w_12 }; public static String getBubbleName(int i){ return bubblesNamesArray[i]; } + public static String getCheckName(int i){ + return checksNamesArray[i]; + } + @Override public View createView(Context context){ actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); - actionBar.setTitle(LocaleController.getString("BubbleStyle", R.string.BubbleStyle)); + actionBar.setTitle(arrayId == 0 ? LocaleController.getString("BubbleStyle", R.string.BubbleStyle) : LocaleController.getString("CheckStyle", R.string.CheckStyle)); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -70,8 +187,8 @@ public class ImageListActivity extends BaseFragment { fragmentView = getParentActivity().getLayoutInflater().inflate(R.layout.imagelistlayout, null, false); - listAdapter = new CustomListAdapter(context, bubblesNamesArray, imgid); - list=(ListView) fragmentView.findViewById(R.id.list); + listAdapter = new CustomListAdapter(context, arrayId == 0 ? bubblesNamesArray : checksNamesArray, arrayId == 0 ? imgid : checkid); + ListView list = (ListView) fragmentView.findViewById(R.id.list); list.setAdapter(listAdapter); list.setDivider(null); @@ -80,11 +197,20 @@ public class ImageListActivity extends BaseFragment { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { - String Slecteditem = bubblesNamesArray[+position]; + String selectedItem = arrayId == 0 ? bubblesNamesArray[+position] : checksNamesArray[+position]; SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - SharedPreferences.Editor editor = preferences.edit(); - editor.putString("chatBubbleStyle", Slecteditem); - editor.commit(); + String key = arrayId == 0 ? "chatBubbleStyle" : "chatCheckStyle"; + String oldVal = preferences.getString(key, ""); + if(!oldVal.equals(selectedItem)){ + SharedPreferences.Editor editor = preferences.edit(); + editor.putString(key, selectedItem); + editor.apply(); + if(arrayId == 0) { + Theme.setBubbles(getParentActivity()); + } else{ + Theme.setChecks(getParentActivity()); + } + } listAdapter.notifyDataSetChanged(); finishFragment(); } @@ -110,10 +236,12 @@ public class ImageListActivity extends BaseFragment { public View getView(int position, View view, ViewGroup parent) { LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - String name = themePrefs.getString("chatBubbleStyle", itemname[0]); + String name = themePrefs.getString(arrayId == 0 ? "chatBubbleStyle" : "chatCheckStyle", itemname[0]); view = inflater.inflate(R.layout.imagelist, parent, false); if(name.equals(itemname[position]) ){ - view.setBackgroundColor(0xffe6e6e6); + view.setBackgroundColor(0xffd0d0d0); + } else{ + view.setBackgroundColor(0xfff0f0f0); } TextView txtTitle = (TextView) view.findViewById(R.id.bubble_title); @@ -121,16 +249,19 @@ public class ImageListActivity extends BaseFragment { ImageView outImageView = (ImageView) view.findViewById(R.id.bubble_out); txtTitle.setText(itemname[position]); - //Drawable in = mContext.getResources().getDrawable(imgid[position]); - //in.setColorFilter(themePrefs.getInt("chatLBubbleColor", 0xffffffff), PorterDuff.Mode.SRC_IN); - //inImageView.setImageDrawable(in); inImageView.setImageResource(imgid[position]); - - //Drawable out = mContext.getResources().getDrawable(imgid[position + itemname.length]); - //out.setColorFilter(themePrefs.getInt("chatRBubbleColor", themePrefs.getInt("themeColor", AndroidUtilities.defColor)), PorterDuff.Mode.SRC_IN); - //outImageView.setImageDrawable(out); outImageView.setImageResource(imgid[position + itemname.length]); + if(arrayId == 1){ + view.setPadding(50, 0, 0, 0); + //inImageView.getLayoutParams().height = 70; + inImageView.getLayoutParams().width = 70; + inImageView.setColorFilter(0, PorterDuff.Mode.SRC_ATOP); + //outImageView.getLayoutParams().height = 70; + outImageView.getLayoutParams().width = 70; + outImageView.setColorFilter(0, PorterDuff.Mode.SRC_ATOP); + } + return view; }; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/IntroActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/IntroActivity.java index 954a197b..c677978d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/IntroActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/IntroActivity.java @@ -28,10 +28,11 @@ import android.widget.ImageView; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.BuildConfig; +import org.telegram.messenger.BuildVars; import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.tgnet.ConnectionsManager; +import org.telegram.ui.ActionBar.Theme; public class IntroActivity extends Activity { @@ -50,6 +51,7 @@ public class IntroActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { setTheme(R.style.Theme_TMessages); super.onCreate(savedInstanceState); + Theme.loadResources(this); requestWindowFeature(Window.FEATURE_NO_TITLE); if (AndroidUtilities.isTablet()) { @@ -221,7 +223,7 @@ public class IntroActivity extends Activity { finish(); } }); - if (BuildConfig.DEBUG) { + if (BuildVars.DEBUG_VERSION) { startMessagingButton.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java index 0e76366c..4b85e45c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LanguageSelectActivity.java @@ -176,7 +176,6 @@ public class LanguageSelectActivity extends BaseFragment { localeInfo = LocaleController.getInstance().sortedLanguages.get(i); } } - Log.e("Language","localeInfo " + (localeInfo != null ? localeInfo.shortName : "NULL")); if (localeInfo != null) { LocaleController.getInstance().applyLanguage(localeInfo, true); parentLayout.rebuildAllFragmentViews(false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java index e95f667b..3cadecd4 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java @@ -17,7 +17,6 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; -import android.content.pm.Signature; import android.content.res.Configuration; import android.database.Cursor; import android.graphics.Point; @@ -25,10 +24,9 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Parcelable; -import android.provider.Browser; import android.provider.ContactsContract; +import android.provider.Settings; import android.support.annotation.NonNull; -import android.util.Log; import android.view.ActionMode; import android.view.KeyEvent; import android.view.MotionEvent; @@ -45,15 +43,19 @@ import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.Toast; +import net.hockeyapp.android.LoginManager; + import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AndroidUtilities; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildConfig; +import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLoader; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessageObject; import org.telegram.messenger.MessagesController; import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NativeCrashManager; @@ -62,7 +64,8 @@ import org.telegram.messenger.R; import org.telegram.messenger.SendMessagesHelper; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; -import org.telegram.messenger.query.StickersQuery; +import org.telegram.messenger.Utilities; +import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; @@ -70,18 +73,23 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBarLayout; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.DrawerLayoutContainer; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.DrawerLayoutAdapter; +import org.telegram.ui.Components.Glow; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.PasscodeView; +import org.telegram.ui.Components.StickersAlert; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; import java.util.Locale; import java.util.Map; -public class LaunchActivity extends Activity implements ActionBarLayout.ActionBarLayoutDelegate, NotificationCenter.NotificationCenterDelegate, DialogsActivity.MessagesActivityDelegate { +public class LaunchActivity extends Activity implements ActionBarLayout.ActionBarLayoutDelegate, NotificationCenter.NotificationCenterDelegate, DialogsActivity.DialogsActivityDelegate { private boolean finished; private String videoPath; @@ -127,6 +135,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa private int communityRow = 12; private int versionRow = 13; private int faqRow = 14; + private boolean pass; @Override protected void onCreate(Bundle savedInstanceState) { @@ -141,7 +150,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa return; } if (intent != null && !intent.getBooleanExtra("fromIntro", false)) { - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("logininfo", MODE_PRIVATE); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("logininfo2", MODE_PRIVATE); Map state = preferences.getAll(); if (state.isEmpty()) { Intent intent2 = new Intent(this, IntroActivity.class); @@ -158,6 +167,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa getWindow().setBackgroundDrawableResource(R.drawable.transparent); super.onCreate(savedInstanceState); + Theme.loadResources(this); if (UserConfig.passcodeHash.length() != 0 && UserConfig.appLocked) { UserConfig.lastPauseTime = ConnectionsManager.getInstance().getCurrentTime(); @@ -282,6 +292,10 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa return false; } }; + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + int hColor = themePrefs.getInt("contactsHeaderColor", def); + Glow.setEdgeGlowColor(listView, hColor); listView.setBackgroundColor(0xffffffff); listView.setAdapter(drawerLayoutAdapter = new DrawerLayoutAdapter(this)); listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE); @@ -309,6 +323,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa args.putBoolean("onlyUsers", true); args.putBoolean("destroyAfterSelect", true); args.putBoolean("createSecretChat", true); + args.putBoolean("allowBots", false); presentFragment(new ContactsActivity(args)); drawerLayoutContainer.closeDrawer(false); } else if (position == 4) { @@ -338,12 +353,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa presentFragment(new SettingsActivity()); drawerLayoutContainer.closeDrawer(false); } else if (position == faqRow) { - try { - Intent pickIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl))); - startActivityForResult(pickIntent, 500); - } catch (Exception e) { - FileLog.e("tmessages", e); - } + Browser.openUrl(LaunchActivity.this, LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl)); drawerLayoutContainer.closeDrawer(false); } else if (position == channelRow) { try { @@ -420,6 +430,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa NotificationCenter.getInstance().addObserver(this, NotificationCenter.closeOtherAppActivities); NotificationCenter.getInstance().addObserver(this, NotificationCenter.didUpdatedConnectionState); NotificationCenter.getInstance().addObserver(this, NotificationCenter.needShowAlert); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.wasUnableToFindCurrentLocation); if (Build.VERSION.SDK_INT < 14) { NotificationCenter.getInstance().addObserver(this, NotificationCenter.screenStateChanged); } @@ -525,6 +536,44 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } } }); + + } + + private void verifyLogin(SharedPreferences prefs){ + String id = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID); + //SharedPreferences prefs = ApplicationLoader.applicationContext.getSharedPreferences("net.hockeyapp.android.login", 0); + String did = prefs.getString("did", null); + int currentMode = prefs.getInt("mode", -1); + String auid = prefs.getString("auid", null); + //String iuid = prefs.getString("iuid", null); + //Log.e("verifyLogin 0", "currentMode: " + currentMode + " auid: " + auid + " did: " + did); + if (currentMode == -1 || currentMode >= 1 && auid == null || !id.equals(did)) { + //Log.e("verifyLogin 1","currentMode: " + currentMode + " auid: " + auid + " iuid: " + iuid); + SharedPreferences.Editor editor = prefs.edit(); + editor.remove("auid"); + editor.remove("iuid"); + editor.remove("mode"); + if (!id.equals(did)) { + editor.putString("did", id); + } + editor.apply(); + //Log.e("verifyLogin 2","currentMode: " + currentMode + " auid: " + auid + " iuid: " + iuid); + LoginManager.register(this, BuildVars.HOCKEY_APP_HASH_DEBUG, BuildVars.HOCKEY_APP_HASH_DEBUG_SECRET, LoginManager.LOGIN_MODE_EMAIL_PASSWORD, this.getClass()); + LoginManager.verifyLogin(this, getIntent()); + } + + if (currentMode == 2 && id.equals(did) && auid != null) { + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean("pass", true); + editor.apply(); + pass = true; + } + //SharedPreferences.Editor editor = prefs.edit(); + //editor.remove("auid"); + //editor.remove("iuid"); + //editor.remove("mode"); + //editor.remove("did"); + //editor.apply(); } private void showPasscodeActivity() { @@ -670,10 +719,12 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa error = true; } } else { - if (type != null && (type.equals("text/plain") || type.equals("message/rfc822")) && (intent.getStringExtra(Intent.EXTRA_TEXT) != null || intent.getCharSequenceExtra(Intent.EXTRA_TEXT) != null)) { String text = intent.getStringExtra(Intent.EXTRA_TEXT); if (text == null) { - text = intent.getCharSequenceExtra(Intent.EXTRA_TEXT).toString(); + CharSequence textSequence = intent.getCharSequenceExtra(Intent.EXTRA_TEXT); + if (textSequence != null) { + text = textSequence.toString(); + } } String subject = intent.getStringExtra(Intent.EXTRA_SUBJECT); @@ -682,10 +733,10 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa text = subject + "\n" + text; } sendingText = text; - } else { - error = true; + } else if (subject != null && subject.length() > 0) { + sendingText = subject; } - } + Parcelable parcelable = intent.getParcelableExtra(Intent.EXTRA_STREAM); if (parcelable != null) { String path; @@ -693,6 +744,12 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa parcelable = Uri.parse(parcelable.toString()); } Uri uri = (Uri) parcelable; + if (uri != null) { + if (isInternalUri(uri)) { + error = true; + } + } + if (!error) { if (uri != null && (type != null && type.startsWith("image/") || uri.toString().toLowerCase().endsWith(".jpg"))) { if (photoPathsArray == null) { photoPathsArray = new ArrayList<>(); @@ -727,6 +784,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa sendingText = null; } } + } } else if (sendingText == null) { error = true; } @@ -740,8 +798,27 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa ArrayList uris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); String type = intent.getType(); if (uris != null) { + for (int a = 0; a < uris.size(); a++) { + Parcelable parcelable = uris.get(a); + if (!(parcelable instanceof Uri)) { + parcelable = Uri.parse(parcelable.toString()); + } + Uri uri = (Uri) parcelable; + if (uri != null) { + if (isInternalUri(uri)) { + uris.remove(a); + a--; + } + } + } + if (uris.isEmpty()) { + uris = null; + } + } + if (uris != null) { if (type != null && type.startsWith("image/")) { - for (Parcelable parcelable : uris) { + for (int a = 0; a < uris.size(); a++) { + Parcelable parcelable = uris.get(a); if (!(parcelable instanceof Uri)) { parcelable = Uri.parse(parcelable.toString()); } @@ -752,7 +829,8 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa photoPathsArray.add(uri); } } else { - for (Parcelable parcelable : uris) { + for (int a = 0; a < uris.size(); a++) { + Parcelable parcelable = uris.get(a); if (!(parcelable instanceof Uri)) { parcelable = Uri.parse(parcelable.toString()); } @@ -793,12 +871,13 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa String botUser = null; String botChat = null; String message = null; + Integer messageId = null; boolean hasUrl = false; String scheme = data.getScheme(); if (scheme != null) { if ((scheme.equals("http") || scheme.equals("https"))) { String host = data.getHost().toLowerCase(); - if (host.equals("telegram.me")) { + if (host.equals("telegram.me") || host.equals("telegram.dog")) { String path = data.getPath(); if (path != null && path.length() > 1) { path = path.substring(1); @@ -818,8 +897,17 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } message += data.getQueryParameter("text"); } - } else if (path.length() >= 3) { - username = data.getLastPathSegment(); + } else if (path.length() >= 1) { + List segments = data.getPathSegments(); + if (segments.size() > 0) { + username = segments.get(0); + if (segments.size() > 1) { + messageId = Utilities.parseInt(segments.get(1)); + if (messageId == 0) { + messageId = null; + } + } + } botUser = data.getQueryParameter("start"); botChat = data.getQueryParameter("startgroup"); } @@ -841,8 +929,8 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa url = url.replace("tg:addstickers", "tg://telegram.org").replace("tg://addstickers", "tg://telegram.org"); data = Uri.parse(url); sticker = data.getQueryParameter("set"); - } else if (url.startsWith("tg:msg") || url.startsWith("tg://msg")) { - url = url.replace("tg:msg", "tg://telegram.org").replace("tg://msg", "tg://telegram.org"); + } else if (url.startsWith("tg:msg") || url.startsWith("tg://msg")|| url.startsWith("tg://share") || url.startsWith("tg:share")) { + url = url.replace("tg:msg", "tg://telegram.org").replace("tg://msg", "tg://telegram.org").replace("tg://share", "tg://telegram.org").replace("tg:share", "tg://telegram.org"); data = Uri.parse(url); message = data.getQueryParameter("url"); if (message == null) { @@ -859,7 +947,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } } if (username != null || group != null || sticker != null || message != null) { - runLinkRequest(username, group, sticker, botUser, botChat, message, hasUrl, 0); + runLinkRequest(username, group, sticker, botUser, botChat, message, hasUrl, messageId, 0); } else { try { Cursor cursor = getContentResolver().query(intent.getData(), null, null, null, null); @@ -903,16 +991,20 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa if (push_user_id != 0) { Bundle args = new Bundle(); args.putInt("user_id", push_user_id); - ChatActivity fragment = new ChatActivity(args); - if (actionBarLayout.presentFragment(fragment, false, true, true)) { - pushOpened = true; + if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) { + ChatActivity fragment = new ChatActivity(args); + if (actionBarLayout.presentFragment(fragment, false, true, true)) { + pushOpened = true; + } } } else if (push_chat_id != 0) { Bundle args = new Bundle(); args.putInt("chat_id", push_chat_id); - ChatActivity fragment = new ChatActivity(args); - if (actionBarLayout.presentFragment(fragment, false, true, true)) { - pushOpened = true; + if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) { + ChatActivity fragment = new ChatActivity(args); + if (actionBarLayout.presentFragment(fragment, false, true, true)) { + pushOpened = true; + } } } else if (push_enc_id != 0) { Bundle args = new Bundle(); @@ -1046,7 +1138,22 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa return false; } - private void runLinkRequest(final String username, final String group, final String sticker, final String botUser, final String botChat, final String message, final boolean hasUrl, final int state) { + private boolean isInternalUri(Uri uri) { + String pathString = uri.getPath(); + if (pathString == null) { + return false; + } + while (true) { + String newPath = Utilities.readlink(pathString); + if (newPath == null || newPath.equals(pathString)) { + break; + } + pathString = newPath; + } + return pathString != null && pathString.toLowerCase().contains("/data/data/" + getPackageName() + "/files"); + } + + private void runLinkRequest(final String username, final String group, final String sticker, final String botUser, final String botChat, final String message, final boolean hasUrl, final Integer messageId, final int state) { final ProgressDialog progressDialog = new ProgressDialog(this); progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); progressDialog.setCanceledOnTouchOutside(false); @@ -1089,31 +1196,48 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa args.putInt("dialogsType", 2); args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupTitle", R.string.AddToTheGroupTitle, UserObject.getUserName(user), "%1$s")); DialogsActivity fragment = new DialogsActivity(args); - fragment.setDelegate(new DialogsActivity.MessagesActivityDelegate() { + fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { @Override public void didSelectDialog(DialogsActivity fragment, long did, boolean param) { - NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); - MessagesController.getInstance().addUserToChat(-(int) did, user, null, 0, botChat, null); Bundle args = new Bundle(); args.putBoolean("scrollToTopOnResume", true); args.putInt("chat_id", -(int) did); + if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); + MessagesController.getInstance().addUserToChat(-(int) did, user, null, 0, botChat, null); actionBarLayout.presentFragment(new ChatActivity(args), true, false, true); } + } }); presentFragment(fragment); } else { + long dialog_id; + boolean isBot = false; Bundle args = new Bundle(); if (!res.chats.isEmpty()) { args.putInt("chat_id", res.chats.get(0).id); + dialog_id = -res.chats.get(0).id; } else { args.putInt("user_id", res.users.get(0).id); + dialog_id = res.users.get(0).id; } if (botUser != null && res.users.size() > 0 && res.users.get(0).bot) { args.putString("botUser", botUser); + isBot = true; + } + if (messageId != null) { + args.putInt("message_id", messageId); + } + BaseFragment lastFragment = !mainFragmentsStack.isEmpty() ? mainFragmentsStack.get(mainFragmentsStack.size() - 1) : null; + if (lastFragment == null || MessagesController.checkCanOpenChat(args, lastFragment)) { + if (isBot && lastFragment != null && lastFragment instanceof ChatActivity && ((ChatActivity) lastFragment).getDialogId() == dialog_id) { + ((ChatActivity) lastFragment).setBotUser(botUser); + } else { + ChatActivity fragment = new ChatActivity(args); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); + actionBarLayout.presentFragment(fragment, false, true, true); + } } - ChatActivity fragment = new ChatActivity(args); - NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); - actionBarLayout.presentFragment(fragment, false, true, true); } } else { try { @@ -1152,9 +1276,11 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa MessagesStorage.getInstance().putUsersAndChats(null, chats, false, true); Bundle args = new Bundle(); args.putInt("chat_id", invite.chat.id); - ChatActivity fragment = new ChatActivity(args); - NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); - actionBarLayout.presentFragment(fragment, false, true, true); + if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) { + ChatActivity fragment = new ChatActivity(args); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); + actionBarLayout.presentFragment(fragment, false, true, true); + } } else { AlertDialog.Builder builder = new AlertDialog.Builder(LaunchActivity.this); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); @@ -1166,7 +1292,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - runLinkRequest(username, group, sticker, botUser, botChat, message, hasUrl, 1); + runLinkRequest(username, group, sticker, botUser, botChat, message, hasUrl, messageId, 1); } }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); @@ -1218,9 +1344,11 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa MessagesController.getInstance().putChats(updates.chats, false); Bundle args = new Bundle(); args.putInt("chat_id", chat.id); - ChatActivity fragment = new ChatActivity(args); - NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); - actionBarLayout.presentFragment(fragment, false, true, true); + if (mainFragmentsStack.isEmpty() || MessagesController.checkCanOpenChat(args, mainFragmentsStack.get(mainFragmentsStack.size() - 1))) { + ChatActivity fragment = new ChatActivity(args); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); + actionBarLayout.presentFragment(fragment, false, true, true); + } } } } else { @@ -1246,21 +1374,16 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa if (!mainFragmentsStack.isEmpty()) { TLRPC.TL_inputStickerSetShortName stickerset = new TLRPC.TL_inputStickerSetShortName(); stickerset.short_name = sticker; - StickersQuery.loadStickers(mainFragmentsStack.get(0), stickerset); + mainFragmentsStack.get(mainFragmentsStack.size() - 1).showDialog(new StickersAlert(LaunchActivity.this, stickerset, null, null)); } return; } else if (message != null) { Bundle args = new Bundle(); args.putBoolean("onlySelect", true); DialogsActivity fragment = new DialogsActivity(args); - fragment.setDelegate(new DialogsActivity.MessagesActivityDelegate() { + fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { @Override public void didSelectDialog(DialogsActivity fragment, long did, boolean param) { - NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); - SharedPreferences.Editor editor = preferences.edit(); - editor.putString("dialog_" + did, message); - editor.commit(); Bundle args = new Bundle(); args.putBoolean("scrollToTopOnResume", true); args.putBoolean("hasUrl", hasUrl); @@ -1279,8 +1402,15 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } else { args.putInt("enc_id", high_id); } + if (MessagesController.checkCanOpenChat(args, fragment)) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString("dialog_" + did, message); + editor.commit(); actionBarLayout.presentFragment(new ChatActivity(args), true, false, true); } + } }); presentFragment(fragment, false, true); } @@ -1357,6 +1487,9 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } else { args.putInt("enc_id", high_id); } + if (!MessagesController.checkCanOpenChat(args, dialogsFragment)) { + return; + } ChatActivity fragment = new ChatActivity(args); if (videoPath != null) { @@ -1391,7 +1524,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa } if (contactsToSend != null && !contactsToSend.isEmpty()) { for (TLRPC.User user : contactsToSend) { - SendMessagesHelper.getInstance().sendMessage(user, dialog_id, null, true); + SendMessagesHelper.getInstance().sendMessage(user, dialog_id, null, true, null, null); } } } @@ -1419,6 +1552,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa NotificationCenter.getInstance().removeObserver(this, NotificationCenter.closeOtherAppActivities); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didUpdatedConnectionState); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.needShowAlert); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.wasUnableToFindCurrentLocation); if (Build.VERSION.SDK_INT < 14) { NotificationCenter.getInstance().removeObserver(this, NotificationCenter.screenStateChanged); } @@ -1434,7 +1568,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa public void needLayout() { if (AndroidUtilities.isTablet()) { - RelativeLayout.LayoutParams relativeLayoutParams = (RelativeLayout.LayoutParams)layersActionBarLayout.getLayoutParams(); + RelativeLayout.LayoutParams relativeLayoutParams = (RelativeLayout.LayoutParams) layersActionBarLayout.getLayoutParams(); relativeLayoutParams.leftMargin = (AndroidUtilities.displaySize.x - relativeLayoutParams.width) / 2; int y = (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); relativeLayoutParams.topMargin = y + (AndroidUtilities.displaySize.y - relativeLayoutParams.height - y) / 2; @@ -1463,11 +1597,14 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa relativeLayoutParams.leftMargin = leftWidth; rightActionBarLayout.setLayoutParams(relativeLayoutParams); - if (AndroidUtilities.isSmallTablet() && actionBarLayout.fragmentsStack.size() == 2) { - BaseFragment chatFragment = actionBarLayout.fragmentsStack.get(1); + if (AndroidUtilities.isSmallTablet() && actionBarLayout.fragmentsStack.size() >= 2) { + for (int a = 1; a < actionBarLayout.fragmentsStack.size(); a++) { + BaseFragment chatFragment = actionBarLayout.fragmentsStack.get(a); chatFragment.onPause(); - actionBarLayout.fragmentsStack.remove(1); + actionBarLayout.fragmentsStack.remove(a); rightActionBarLayout.fragmentsStack.add(chatFragment); + a--; + } if (passcodeView.getVisibility() != View.VISIBLE) { actionBarLayout.showLastFragment(); rightActionBarLayout.showLastFragment(); @@ -1489,12 +1626,14 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa rightActionBarLayout.setVisibility(View.GONE); backgroundTablet.setVisibility(!actionBarLayout.fragmentsStack.isEmpty() ? View.GONE : View.VISIBLE); - if (rightActionBarLayout.fragmentsStack.size() == 1) { - BaseFragment chatFragment = rightActionBarLayout.fragmentsStack.get(0); + if (!rightActionBarLayout.fragmentsStack.isEmpty()) { + for (int a = 0; a < rightActionBarLayout.fragmentsStack.size(); a++) { + BaseFragment chatFragment = rightActionBarLayout.fragmentsStack.get(a); chatFragment.onPause(); - rightActionBarLayout.fragmentsStack.remove(0); + rightActionBarLayout.fragmentsStack.remove(a); actionBarLayout.fragmentsStack.add(chatFragment); - //actionBarLayout.addFragmentToStack(chatFragment); + a--; + } if (passcodeView.getVisibility() != View.VISIBLE) { actionBarLayout.showLastFragment(); } @@ -1513,7 +1652,12 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa actionBarLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { needLayout(); + } + }); if (actionBarLayout != null) { if (Build.VERSION.SDK_INT < 16) { actionBarLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this); @@ -1554,7 +1698,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa if (requestCode == 3 || requestCode == 4 || requestCode == 5) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (requestCode == 4) { - ImageLoader.getInstance().createMediaPaths(); + ImageLoader.getInstance().checkMediaPaths(); } else if (requestCode == 5) { ContactsController.getInstance().readContacts(); } @@ -1623,6 +1767,18 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa AndroidUtilities.unregisterUpdates(); } + @Override + protected void onStart() { + super.onStart(); + Browser.bindCustomTabsService(this); + } + + @Override + protected void onStop() { + super.onStop(); + Browser.unbindCustomTabsService(this); + } + @Override protected void onDestroy() { PhotoViewer.getInstance().destroyPhotoViewer(); @@ -1658,11 +1814,11 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa ApplicationLoader.mainInterfacePaused = false; onPasscodeResume(); if (passcodeView.getVisibility() != View.VISIBLE) { - actionBarLayout.onResume(); - if (AndroidUtilities.isTablet()) { - rightActionBarLayout.onResume(); - layersActionBarLayout.onResume(); - } + actionBarLayout.onResume(); + if (AndroidUtilities.isTablet()) { + rightActionBarLayout.onResume(); + layersActionBarLayout.onResume(); + } } else { passcodeView.onResume(); } @@ -1671,7 +1827,14 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa AndroidUtilities.checkForCrashes(this); AndroidUtilities.checkForUpdates(this); } - //AndroidUtilities.checkForThemes(this); + AndroidUtilities.checkForThemes(this); + if(BuildConfig.DEBUG){ + SharedPreferences prefs = ApplicationLoader.applicationContext.getSharedPreferences("net.hockeyapp.android.login", 0); + pass = prefs.getBoolean("pass", false); + if(!pass){ + verifyLogin(prefs); + } + } ConnectionsManager.getInstance().setAppPaused(false, false); updateCurrentConnectionState(); if (PhotoViewer.getInstance().isVisible()) { @@ -1742,13 +1905,9 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa builder.setNegativeButton(LocaleController.getString("MoreInfo", R.string.MoreInfo), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - try { - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(LocaleController.getString("NobodyLikesSpamUrl", R.string.NobodyLikesSpamUrl))); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, getPackageName()); - startActivity(intent); - } catch (Exception e) { - FileLog.e("tmessages", e); - } + if (!mainFragmentsStack.isEmpty()) { + MessagesController.openByUserName("spambot", mainFragmentsStack.get(mainFragmentsStack.size() - 1), 1); + } } }); } @@ -1762,6 +1921,38 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa if (!mainFragmentsStack.isEmpty()) { mainFragmentsStack.get(mainFragmentsStack.size() - 1).showDialog(builder.create()); } + } else if (id == NotificationCenter.wasUnableToFindCurrentLocation) { + final HashMap waitingForLocation = (HashMap) args[0]; + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + builder.setNegativeButton(LocaleController.getString("ShareYouLocationUnableManually", R.string.ShareYouLocationUnableManually), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (mainFragmentsStack.isEmpty()) { + return; + } + BaseFragment lastFragment = mainFragmentsStack.get(mainFragmentsStack.size() - 1); + if (!AndroidUtilities.isGoogleMapsInstalled(lastFragment)) { + return; + } + LocationActivity fragment = new LocationActivity(); + fragment.setDelegate(new LocationActivity.LocationActivityDelegate() { + @Override + public void didSelectLocation(TLRPC.MessageMedia location) { + for (HashMap.Entry entry : waitingForLocation.entrySet()) { + MessageObject messageObject = entry.getValue(); + SendMessagesHelper.getInstance().sendMessage(location, messageObject.getDialogId(), messageObject, false, null, null); + } + } + }); + presentFragment(fragment); + } + }); + builder.setMessage(LocaleController.getString("ShareYouLocationUnable", R.string.ShareYouLocationUnable)); + if (!mainFragmentsStack.isEmpty()) { + mainFragmentsStack.get(mainFragmentsStack.size() - 1).showDialog(builder.create()); + } } } @@ -1946,7 +2137,7 @@ public class LaunchActivity extends Activity implements ActionBarLayout.ActionBa @Override public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU) { + if (keyCode == KeyEvent.KEYCODE_MENU && !UserConfig.isWaitingForPasscodeEnter) { if (AndroidUtilities.isTablet()) { if (layersActionBarLayout.getVisibility() == View.VISIBLE && !layersActionBarLayout.fragmentsStack.isEmpty()) { layersActionBarLayout.onKeyUp(keyCode, event); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java index 5ffc506a..78bc7cb0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LocationActivity.java @@ -363,6 +363,15 @@ public class LocationActivity extends BaseFragment implements NotificationCenter routeButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + if (Build.VERSION.SDK_INT >= 23) { + Activity activity = getParentActivity(); + if (activity != null) { + if (activity.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + showPermissionAlert(true); + return; + } + } + } if (myLocation != null) { try { Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(String.format(Locale.US, "http://maps.google.com/maps?saddr=%f,%f&daddr=%f,%f", myLocation.getLatitude(), myLocation.getLongitude(), messageObject.messageOwner.media.geo.lat, messageObject.messageOwner.media.geo._long))); @@ -382,7 +391,7 @@ public class LocationActivity extends BaseFragment implements NotificationCenter Activity activity = getParentActivity(); if (activity != null) { if (activity.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - showPermissionAlert(); + showPermissionAlert(true); return; } } @@ -505,7 +514,7 @@ public class LocationActivity extends BaseFragment implements NotificationCenter } }; try { - mapView.onCreate(null); + mapView.onCreate(null); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -539,7 +548,7 @@ public class LocationActivity extends BaseFragment implements NotificationCenter Activity activity = getParentActivity(); if (activity != null) { if (activity.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - showPermissionAlert(); + showPermissionAlert(false); return; } } @@ -627,7 +636,7 @@ public class LocationActivity extends BaseFragment implements NotificationCenter if (googleMap != null) { try { - googleMap.setMyLocationEnabled(true); + googleMap.setMyLocationEnabled(true); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -646,13 +655,17 @@ public class LocationActivity extends BaseFragment implements NotificationCenter return fragmentView; } - private void showPermissionAlert() { + private void showPermissionAlert(boolean byButton) { if (getParentActivity() == null) { return; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); - builder.setMessage(LocaleController.getString("PermissionNoLocation", R.string.PermissionNoLocation)); + if (byButton) { + builder.setMessage(LocaleController.getString("PermissionNoLocationPosition", R.string.PermissionNoLocationPosition)); + } else { + builder.setMessage(LocaleController.getString("PermissionNoLocation", R.string.PermissionNoLocation)); + } builder.setNegativeButton(LocaleController.getString("PermissionOpenSettings", R.string.PermissionOpenSettings), new DialogInterface.OnClickListener() { @TargetApi(Build.VERSION_CODES.GINGERBREAD) @Override @@ -817,10 +830,10 @@ public class LocationActivity extends BaseFragment implements NotificationCenter if (messageObject != null && avatarImageView != null) { int fromId = messageObject.messageOwner.from_id; if (messageObject.isForwarded()) { - if (messageObject.messageOwner.fwd_from_id.user_id != 0) { - fromId = messageObject.messageOwner.fwd_from_id.user_id; + if (messageObject.messageOwner.fwd_from.channel_id != 0) { + fromId = -messageObject.messageOwner.fwd_from.channel_id; } else { - fromId = -messageObject.messageOwner.fwd_from_id.channel_id; + fromId = messageObject.messageOwner.fwd_from.from_id; } } String name = ""; @@ -929,7 +942,18 @@ public class LocationActivity extends BaseFragment implements NotificationCenter super.onResume(); AndroidUtilities.removeAdjustResize(getParentActivity(), classGuid); if (mapView != null) { - mapView.onResume(); + try { + mapView.onResume(); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + if (googleMap != null) { + try { + googleMap.setMyLocationEnabled(true); + } catch (Exception e) { + FileLog.e("tmessages", e); + } } updateUserData(); fixLayoutInternal(true); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java index cdad6116..3e88bda8 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/LoginActivity.java @@ -8,8 +8,10 @@ package org.telegram.ui; +import android.Manifest; import android.animation.Animator; import android.annotation.SuppressLint; +import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; @@ -18,6 +20,9 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.graphics.Canvas; +import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.Typeface; import android.os.Build; @@ -41,6 +46,7 @@ import android.view.inputmethod.EditorInfo; import android.widget.AdapterView; import android.widget.EditText; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; @@ -85,17 +91,21 @@ import java.util.TimerTask; public class LoginActivity extends BaseFragment { private int currentViewNum = 0; - private SlideView[] views = new SlideView[5]; + private SlideView[] views = new SlideView[8]; private ProgressDialog progressDialog; + private Dialog permissionsDialog; + private ArrayList permissionsItems = new ArrayList<>(); + private boolean checkPermissions = true; + private View doneButton; private final static int done_button = 1; @Override public void onFragmentDestroy() { super.onFragmentDestroy(); - for (SlideView v : views) { - if (v != null) { - v.onDestroyActivity(); + for (int a = 0; a < views.length; a++) { + if (views[a] != null) { + views[a].onDestroyActivity(); } } if (progressDialog != null) { @@ -124,7 +134,7 @@ public class LoginActivity extends BaseFragment { }); ActionBarMenu menu = actionBar.createMenu(); - menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); fragmentView = new ScrollView(context); ScrollView scrollView = (ScrollView) fragmentView; @@ -134,12 +144,15 @@ public class LoginActivity extends BaseFragment { scrollView.addView(frameLayout, LayoutHelper.createScroll(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT)); views[0] = new PhoneView(context); - views[1] = new LoginActivitySmsView(context); - views[2] = new LoginActivityRegisterView(context); - views[3] = new LoginActivityPasswordView(context); - views[4] = new LoginActivityRecoverView(context); + views[1] = new LoginActivitySmsView(context, 1); + views[2] = new LoginActivitySmsView(context, 2); + views[3] = new LoginActivitySmsView(context, 3); + views[4] = new LoginActivitySmsView(context, 4); + views[5] = new LoginActivityRegisterView(context); + views[6] = new LoginActivityPasswordView(context); + views[7] = new LoginActivityRecoverView(context); - for (int a = 0; a < 5; a++) { + for (int a = 0; a < views.length; a++) { views[a].setVisibility(a == 0 ? View.VISIBLE : View.GONE); frameLayout.addView(views[a], LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, a == 0 ? LayoutHelper.WRAP_CONTENT : LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, AndroidUtilities.isTablet() ? 26 : 18, 30, AndroidUtilities.isTablet() ? 26 : 18, 0)); } @@ -147,7 +160,7 @@ public class LoginActivity extends BaseFragment { Bundle savedInstanceState = loadCurrentState(); if (savedInstanceState != null) { currentViewNum = savedInstanceState.getInt("currentViewNum", 0); - if (currentViewNum == 1) { + if (currentViewNum >= 1 && currentViewNum <= 4) { int time = savedInstanceState.getInt("open"); if (time != 0 && Math.abs(System.currentTimeMillis() / 1000 - time) >= 24 * 60 * 60) { currentViewNum = 0; @@ -159,12 +172,21 @@ public class LoginActivity extends BaseFragment { actionBar.setTitle(views[currentViewNum].getHeaderName()); for (int a = 0; a < views.length; a++) { if (savedInstanceState != null) { + if (a >= 1 && a <= 4) { + if (a == currentViewNum) { views[a].restoreStateParams(savedInstanceState); + } + } else { + views[a].restoreStateParams(savedInstanceState); + } } if (currentViewNum == a) { actionBar.setBackButtonImage(views[a].needBackButton() ? R.drawable.ic_ab_back : 0); views[a].setVisibility(View.VISIBLE); views[a].onShow(); + if (a == 3) { + doneButton.setVisibility(View.GONE); + } } else { views[a].setVisibility(View.GONE); } @@ -184,10 +206,10 @@ public class LoginActivity extends BaseFragment { super.onResume(); AndroidUtilities.requestAdjustResize(getParentActivity(), classGuid); try { - if (currentViewNum == 1 && views[1] instanceof LoginActivitySmsView) { - int time = ((LoginActivitySmsView) views[1]).openTime; + if (currentViewNum >= 1 && currentViewNum <= 4 && views[currentViewNum] instanceof LoginActivitySmsView) { + int time = ((LoginActivitySmsView) views[currentViewNum]).openTime; if (time != 0 && Math.abs(System.currentTimeMillis() / 1000 - time) >= 24 * 60 * 60) { - views[1].onBackPressed(); + views[currentViewNum].onBackPressed(); setPage(0, false, null, true); } } @@ -196,10 +218,20 @@ public class LoginActivity extends BaseFragment { } } + @Override + public void onRequestPermissionsResultFragment(int requestCode, String[] permissions, int[] grantResults) { + if (requestCode == 6) { + checkPermissions = false; + if (currentViewNum == 0) { + views[currentViewNum].onNextPressed(); + } + } + } + private Bundle loadCurrentState() { try { Bundle bundle = new Bundle(); - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("logininfo", Context.MODE_PRIVATE); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("logininfo2", Context.MODE_PRIVATE); Map params = preferences.getAll(); for (Map.Entry entry : params.entrySet()) { String key = entry.getKey(); @@ -232,7 +264,7 @@ public class LoginActivity extends BaseFragment { } private void clearCurrentState() { - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("logininfo", Context.MODE_PRIVATE); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("logininfo2", Context.MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); editor.clear(); editor.commit(); @@ -260,22 +292,29 @@ public class LoginActivity extends BaseFragment { } } + @Override + protected void onDialogDismiss(Dialog dialog) { + if (Build.VERSION.SDK_INT >= 23 && dialog == permissionsDialog && !permissionsItems.isEmpty() && getParentActivity() != null) { + getParentActivity().requestPermissions(permissionsItems.toArray(new String[permissionsItems.size()]), 6); + } + } + @Override public boolean onBackPressed() { if (currentViewNum == 0) { - for (SlideView v : views) { - if (v != null) { - v.onDestroyActivity(); + for (int a = 0; a < views.length; a++) { + if (views[a] != null) { + views[a].onDestroyActivity(); } } clearCurrentState(); return true; - } else if (currentViewNum == 3) { + } else if (currentViewNum == 6) { views[currentViewNum].onBackPressed(); setPage(0, true, null, true); - } else if (currentViewNum == 4) { + } else if (currentViewNum == 7) { views[currentViewNum].onBackPressed(); - setPage(3, true, null, true); + setPage(6, true, null, true); } return false; } @@ -315,6 +354,14 @@ public class LoginActivity extends BaseFragment { } public void setPage(int page, boolean animated, Bundle params, boolean back) { + if (page == 3) { + doneButton.setVisibility(View.GONE); + } else { + if (page == 0) { + checkPermissions = true; + } + doneButton.setVisibility(View.VISIBLE); + } if (android.os.Build.VERSION.SDK_INT > 13 && animated) { final SlideView outView = views[currentViewNum]; final SlideView newView = views[page]; @@ -385,7 +432,7 @@ public class LoginActivity extends BaseFragment { v.saveStateParams(bundle); } } - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("logininfo", Context.MODE_PRIVATE); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("logininfo2", Context.MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); editor.clear(); putBundleToEditor(bundle, editor, null); @@ -395,12 +442,46 @@ public class LoginActivity extends BaseFragment { } } - public void needFinishActivity() { + private void needFinishActivity() { clearCurrentState(); presentFragment(new DialogsActivity(null), true); NotificationCenter.getInstance().postNotificationName(NotificationCenter.mainUserInfoChanged); } + private void fillNextCodeParams(Bundle params, TLRPC.TL_auth_sentCode res) { + params.putString("phoneHash", res.phone_code_hash); + if (res.next_type instanceof TLRPC.TL_auth_codeTypeCall) { + params.putInt("nextType", 4); + } else if (res.next_type instanceof TLRPC.TL_auth_codeTypeFlashCall) { + params.putInt("nextType", 3); + } else if (res.next_type instanceof TLRPC.TL_auth_codeTypeSms) { + params.putInt("nextType", 2); + } + if (res.type instanceof TLRPC.TL_auth_sentCodeTypeApp) { + params.putInt("type", 1); + params.putInt("length", res.type.length); + setPage(1, true, params, false); + } else { + if (res.timeout == 0) { + res.timeout = 60; + } + params.putInt("timeout", res.timeout * 1000); + if (res.type instanceof TLRPC.TL_auth_sentCodeTypeCall) { + params.putInt("type", 4); + params.putInt("length", res.type.length); + setPage(4, true, params, false); + } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeFlashCall) { + params.putInt("type", 3); + params.putString("pattern", res.type.pattern); + setPage(3, true, params, false); + } else if (res.type instanceof TLRPC.TL_auth_sentCodeTypeSms) { + params.putInt("type", 2); + params.putInt("length", res.type.length); + setPage(2, true, params, false); + } + } + } + public class PhoneView extends SlideView implements AdapterView.OnItemSelectedListener { private EditText codeField; @@ -419,7 +500,7 @@ public class LoginActivity extends BaseFragment { private boolean ignoreOnPhoneChange = false; private boolean nextPressed = false; - public PhoneView(final Context context) { + public PhoneView(Context context) { super(context); setOrientation(VERTICAL); @@ -731,11 +812,9 @@ public class LoginActivity extends BaseFragment { } if (codeField.length() != 0) { - AndroidUtilities.showKeyboard(phoneField); phoneField.requestFocus(); phoneField.setSelection(phoneField.length()); } else { - AndroidUtilities.showKeyboard(codeField); codeField.requestFocus(); } } @@ -773,13 +852,50 @@ public class LoginActivity extends BaseFragment { @Override public void onNextPressed() { - if (nextPressed) { + if (getParentActivity() == null || nextPressed) { return; } + TelephonyManager tm = (TelephonyManager) ApplicationLoader.applicationContext.getSystemService(Context.TELEPHONY_SERVICE); + boolean simcardAvailable = tm.getSimState() != TelephonyManager.SIM_STATE_ABSENT && tm.getPhoneType() != TelephonyManager.PHONE_TYPE_NONE; + boolean allowCall = true; + if (Build.VERSION.SDK_INT >= 23 && simcardAvailable) { + allowCall = getParentActivity().checkSelfPermission(Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED; + boolean allowSms = getParentActivity().checkSelfPermission(Manifest.permission.RECEIVE_SMS) == PackageManager.PERMISSION_GRANTED; + if (checkPermissions) { + permissionsItems.clear(); + if (!allowCall) { + permissionsItems.add(Manifest.permission.READ_PHONE_STATE); + } + if (!allowSms) { + permissionsItems.add(Manifest.permission.RECEIVE_SMS); + } + if (!permissionsItems.isEmpty()) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + if (preferences.getBoolean("firstlogin", true) || getParentActivity().shouldShowRequestPermissionRationale(Manifest.permission.READ_PHONE_STATE) || getParentActivity().shouldShowRequestPermissionRationale(Manifest.permission.RECEIVE_SMS)) { + preferences.edit().putBoolean("firstlogin", false).commit(); + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); + if (permissionsItems.size() == 2) { + builder.setMessage(LocaleController.getString("AllowReadCallAndSms", R.string.AllowReadCallAndSms)); + } else if (!allowSms) { + builder.setMessage(LocaleController.getString("AllowReadSms", R.string.AllowReadSms)); + } else { + builder.setMessage(LocaleController.getString("AllowReadCall", R.string.AllowReadCall)); + } + permissionsDialog = showDialog(builder.create()); + } else { + getParentActivity().requestPermissions(permissionsItems.toArray(new String[permissionsItems.size()]), 6); + } + return; + } + } + } + if (countryState == 1) { needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("ChooseCountry", R.string.ChooseCountry)); return; - } else if (countryState == 2 && !BuildVars.DEBUG_VERSION) { + } else if (countryState == 2 && !BuildVars.DEBUG_VERSION && !codeField.getText().toString().equals("999")) { needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("WrongCountry", R.string.WrongCountry)); return; } @@ -794,12 +910,16 @@ public class LoginActivity extends BaseFragment { ConnectionsManager.getInstance().applyCountryPortNumber(phone); req.api_hash = BuildVars.APP_HASH; req.api_id = BuildVars.APP_ID; - req.sms_type = 0; req.phone_number = phone; - req.lang_code = LocaleController.getLocaleString(LocaleController.getInstance().getSystemDefaultLocale()); + req.lang_code = LocaleController.getLocaleStringIso639(); if (req.lang_code.length() == 0) { req.lang_code = "en"; } + req.allow_flashcall = simcardAvailable && allowCall; + if (req.allow_flashcall) { + String number = tm.getLine1Number(); + req.current_number = number != null && number.length() != 0 && (phone.contains(number) || number.contains(phone)); + } final Bundle params = new Bundle(); params.putString("phone", "+" + codeField.getText() + phoneField.getText()); @@ -820,10 +940,7 @@ public class LoginActivity extends BaseFragment { public void run() { nextPressed = false; if (error == null) { - final TLRPC.TL_auth_sentCode res = (TLRPC.TL_auth_sentCode) response; - params.putString("phoneHash", res.phone_code_hash); - params.putInt("calltime", res.send_call_timeout * 1000); - setPage(1, true, params, false); + fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response); } else { if (error.text != null) { if (error.text.contains("PHONE_NUMBER_INVALID")) { @@ -893,6 +1010,32 @@ public class LoginActivity extends BaseFragment { public class LoginActivitySmsView extends SlideView implements NotificationCenter.NotificationCenterDelegate { + private class ProgressView extends View { + + private Paint paint = new Paint(); + private Paint paint2 = new Paint(); + private float progress; + + public ProgressView(Context context) { + super(context); + paint.setColor(0xffe1eaf2); + paint2.setColor(0xff62a0d0); + } + + public void setProgress(float value) { + progress = value; + invalidate(); + } + + @Override + protected void onDraw(Canvas canvas) { + int start = (int) (getMeasuredWidth() * progress); + canvas.drawRect(0, 0, start, getMeasuredHeight(), paint2); + canvas.drawRect(start, 0, getMeasuredWidth(), getMeasuredHeight(), paint); + } + } + + private String phone; private String phoneHash; private String requestPhone; private String emailPhone; @@ -901,6 +1044,7 @@ public class LoginActivity extends BaseFragment { private TextView timeText; private TextView problemText; private Bundle currentParams; + private ProgressView progressView; private Timer timeTimer; private Timer codeTimer; @@ -910,14 +1054,20 @@ public class LoginActivity extends BaseFragment { private volatile int codeTime = 15000; private double lastCurrentTime; private double lastCodeTime; - private boolean ignoreOnTextChange = false; - private boolean waitingForSms = false; - private boolean nextPressed = false; + private boolean ignoreOnTextChange; + private boolean waitingForEvent; + private boolean nextPressed; private String lastError = ""; + private int currentType; + private int nextType; + private String pattern = "*"; + private int length; + private int timeout; - public LoginActivitySmsView(Context context) { + public LoginActivitySmsView(Context context, final int type) { super(context); + currentType = type; setOrientation(VERTICAL); confirmTextView = new TextView(context); @@ -925,7 +1075,23 @@ public class LoginActivity extends BaseFragment { confirmTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); confirmTextView.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); confirmTextView.setLineSpacing(AndroidUtilities.dp(2), 1.0f); + + if (currentType == 3) { + FrameLayout frameLayout = new FrameLayout(context); + + ImageView imageView = new ImageView(context); + imageView.setImageResource(R.drawable.phone_activate); + if (LocaleController.isRTL) { + frameLayout.addView(imageView, LayoutHelper.createFrame(64, 76, Gravity.LEFT | Gravity.CENTER_VERTICAL, 2, 2, 0, 0)); + frameLayout.addView(confirmTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 64 + 18, 0, 0, 0)); + } else { + frameLayout.addView(confirmTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 0, 64 + 18, 0)); + frameLayout.addView(imageView, LayoutHelper.createFrame(64, 76, Gravity.RIGHT | Gravity.CENTER_VERTICAL, 0, 2, 0, 2)); + } + addView(frameLayout, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)); + } else { addView(confirmTextView, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT)); + } codeField = new EditText(context); codeField.setTextColor(0xff212121); @@ -940,9 +1106,6 @@ public class LoginActivity extends BaseFragment { codeField.setInputType(InputType.TYPE_CLASS_PHONE); codeField.setMaxLines(1); codeField.setPadding(0, 0, 0, 0); - InputFilter[] inputFilters = new InputFilter[1]; - inputFilters[0] = new InputFilter.LengthFilter(5); - codeField.setFilters(inputFilters); addView(codeField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, Gravity.CENTER_HORIZONTAL, 0, 20, 0, 0)); codeField.addTextChangedListener(new TextWatcher() { @Override @@ -960,7 +1123,7 @@ public class LoginActivity extends BaseFragment { if (ignoreOnTextChange) { return; } - if (codeField.length() == 5) { + if (length != 0 && codeField.length() == length) { onNextPressed(); } } @@ -975,6 +1138,11 @@ public class LoginActivity extends BaseFragment { return false; } }); + if (currentType == 3) { + codeField.setEnabled(false); + codeField.setInputType(InputType.TYPE_NULL); + codeField.setVisibility(GONE); + } timeText = new TextView(context); timeText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); @@ -983,9 +1151,13 @@ public class LoginActivity extends BaseFragment { timeText.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); addView(timeText, LayoutHelper.createLinear(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT, 0, 30, 0, 0)); + if (currentType == 3) { + progressView = new ProgressView(context); + addView(progressView, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 3, 0, 12, 0, 0)); + } + problemText = new TextView(context); problemText.setText(LocaleController.getString("DidNotGetTheCode", R.string.DidNotGetTheCode)); - problemText.setVisibility(time < 1000 ? VISIBLE : GONE); problemText.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); problemText.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); //problemText.setTextColor(0xff4d83b3); @@ -996,6 +1168,12 @@ public class LoginActivity extends BaseFragment { problemText.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { + if (nextPressed) { + return; + } + if (nextType != 0 && nextType != 4) { + resendCode(); + } else { try { PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); String version = String.format(Locale.US, "%s (%d)", pInfo.versionName, pInfo.versionCode); @@ -1010,6 +1188,7 @@ public class LoginActivity extends BaseFragment { needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("NoMailInstalled", R.string.NoMailInstalled)); } } + } }); LinearLayout linearLayout = new LinearLayout(context); @@ -1028,12 +1207,66 @@ public class LoginActivity extends BaseFragment { wrongNumber.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { + TLRPC.TL_auth_cancelCode req = new TLRPC.TL_auth_cancelCode(); + req.phone_number = requestPhone; + req.phone_code_hash = phoneHash; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); onBackPressed(); setPage(0, true, null, true); } }); } + private void resendCode() { + final Bundle params = new Bundle(); + params.putString("phone", phone); + params.putString("ephone", emailPhone); + params.putString("phoneFormated", requestPhone); + + nextPressed = true; + needShowProgress(); + + TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); + req.phone_number = requestPhone; + req.phone_code_hash = phoneHash; + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + nextPressed = false; + if (error == null) { + fillNextCodeParams(params, (TLRPC.TL_auth_sentCode) response); + } else { + if (error.text != null) { + if (error.text.contains("PHONE_NUMBER_INVALID")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); + } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidCode", R.string.InvalidCode)); + } else if (error.text.contains("PHONE_CODE_EXPIRED")) { + onBackPressed(); + setPage(0, true, null, true); + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("CodeExpired", R.string.CodeExpired)); + } else if (error.text.startsWith("FLOOD_WAIT")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("FloodWait", R.string.FloodWait)); + } else if (error.code != -1000) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text); + } + } + } + needHideProgress(); + } + }); + } + }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + } + @Override public String getHeaderName() { return LocaleController.getString("YourCode", R.string.YourCode); @@ -1045,44 +1278,87 @@ public class LoginActivity extends BaseFragment { return; } codeField.setText(""); + waitingForEvent = true; + if (currentType == 2) { AndroidUtilities.setWaitingForSms(true); NotificationCenter.getInstance().addObserver(this, NotificationCenter.didReceiveSmsCode); + } else if (currentType == 3) { + AndroidUtilities.setWaitingForCall(true); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.didReceiveCall); + } + currentParams = params; - waitingForSms = true; - String phone = params.getString("phone"); + phone = params.getString("phone"); emailPhone = params.getString("ephone"); requestPhone = params.getString("phoneFormated"); phoneHash = params.getString("phoneHash"); - time = params.getInt("calltime"); + timeout = time = params.getInt("timeout"); openTime = (int) (System.currentTimeMillis() / 1000); + nextType = params.getInt("nextType"); + pattern = params.getString("pattern"); + length = params.getInt("length"); + + if (length != 0) { + InputFilter[] inputFilters = new InputFilter[1]; + inputFilters[0] = new InputFilter.LengthFilter(length); + codeField.setFilters(inputFilters); + } else { + codeField.setFilters(new InputFilter[0]); + } + if (progressView != null) { + progressView.setVisibility(nextType != 0 ? VISIBLE : GONE); + } if (phone == null) { return; } String number = PhoneFormat.getInstance().format(phone); - String str = String.format(LocaleController.getString("SentSmsCode", R.string.SentSmsCode) + " %s", number); - try { - SpannableStringBuilder stringBuilder = new SpannableStringBuilder(str); - TypefaceSpan span = new TypefaceSpan(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - int idx = str.indexOf(number); - stringBuilder.setSpan(span, idx, idx + number.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); - confirmTextView.setText(stringBuilder); - } catch (Exception e) { - FileLog.e("tmessages", e); - confirmTextView.setText(str); + CharSequence str = ""; + if (currentType == 1) { + str = AndroidUtilities.replaceTags(LocaleController.getString("SentAppCode", R.string.SentAppCode)); + } else if (currentType == 2) { + str = AndroidUtilities.replaceTags(LocaleController.formatString("SentSmsCode", R.string.SentSmsCode, number)); + } else if (currentType == 3) { + str = AndroidUtilities.replaceTags(LocaleController.formatString("SentCallCode", R.string.SentCallCode, number)); + } else if (currentType == 4) { + str = AndroidUtilities.replaceTags(LocaleController.formatString("SentCallOnly", R.string.SentCallOnly, number)); } + confirmTextView.setText(str); + if (currentType != 3) { AndroidUtilities.showKeyboard(codeField); codeField.requestFocus(); + } else { + AndroidUtilities.hideKeyboard(codeField); + } destroyTimer(); destroyCodeTimer(); - timeText.setText(LocaleController.formatString("CallText", R.string.CallText, 1, 0)); - lastCurrentTime = System.currentTimeMillis(); - problemText.setVisibility(time < 1000 ? VISIBLE : GONE); - createTimer(); + lastCurrentTime = System.currentTimeMillis(); + if (currentType == 1) { + problemText.setVisibility(VISIBLE); + timeText.setVisibility(GONE); + } else if (currentType == 3 && (nextType == 4 || nextType == 2)) { + problemText.setVisibility(GONE); + timeText.setVisibility(VISIBLE); + if (nextType == 4) { + timeText.setText(LocaleController.formatString("CallText", R.string.CallText, 1, 0)); + } else if (nextType == 2) { + timeText.setText(LocaleController.formatString("SmsText", R.string.SmsText, 1, 0)); + } + createTimer(); + } else if (currentType == 2 && (nextType == 4 || nextType == 3)) { + timeText.setVisibility(VISIBLE); + timeText.setText(LocaleController.formatString("CallText", R.string.CallText, 2, 0)); + problemText.setVisibility(time < 1000 ? VISIBLE : GONE); + createTimer(); + } else { + timeText.setVisibility(GONE); + problemText.setVisibility(GONE); + createCodeTimer(); + } } private void createCodeTimer() { @@ -1133,7 +1409,10 @@ public class LoginActivity extends BaseFragment { timeTimer.schedule(new TimerTask() { @Override public void run() { - double currentTime = System.currentTimeMillis(); + if (timeTimer == null) { + return; + } + final double currentTime = System.currentTimeMillis(); double diff = currentTime - lastCurrentTime; time -= diff; lastCurrentTime = currentTime; @@ -1143,12 +1422,30 @@ public class LoginActivity extends BaseFragment { if (time >= 1000) { int minutes = time / 1000 / 60; int seconds = time / 1000 - minutes * 60; + if (nextType == 4 || nextType == 3) { timeText.setText(LocaleController.formatString("CallText", R.string.CallText, minutes, seconds)); + } else if (nextType == 2) { + timeText.setText(LocaleController.formatString("SmsText", R.string.SmsText, minutes, seconds)); + } + if (progressView != null) { + progressView.setProgress(1.0f - (float) time / (float) timeout); + } } else { - timeText.setText(LocaleController.getString("Calling", R.string.Calling)); + if (progressView != null) { + progressView.setProgress(1.0f); + } destroyTimer(); + if (currentType == 3) { + AndroidUtilities.setWaitingForCall(false); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall); + waitingForEvent = false; + destroyCodeTimer(); + resendCode(); + } else if (currentType == 2) { + if (nextType == 4) { + timeText.setText(LocaleController.getString("Calling", R.string.Calling)); createCodeTimer(); - TLRPC.TL_auth_sendCall req = new TLRPC.TL_auth_sendCall(); + TLRPC.TL_auth_resendCode req = new TLRPC.TL_auth_resendCode(); req.phone_number = requestPhone; req.phone_code_hash = phoneHash; ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { @@ -1164,8 +1461,16 @@ public class LoginActivity extends BaseFragment { } } }, ConnectionsManager.RequestFlagFailOnServerErrors | ConnectionsManager.RequestFlagWithoutLogin); + } else if (nextType == 3) { + AndroidUtilities.setWaitingForSms(false); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); + waitingForEvent = false; + destroyCodeTimer(); + resendCode(); + } } } + } }); } }, 0, 1000); @@ -1190,9 +1495,14 @@ public class LoginActivity extends BaseFragment { return; } nextPressed = true; - waitingForSms = false; + if (currentType == 2) { AndroidUtilities.setWaitingForSms(false); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); + } else if (currentType == 3) { + AndroidUtilities.setWaitingForCall(false); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall); + } + waitingForEvent = false; final TLRPC.TL_auth_signIn req = new TLRPC.TL_auth_signIn(); req.phone_number = requestPhone; req.phone_code = codeField.getText().toString(); @@ -1233,7 +1543,7 @@ public class LoginActivity extends BaseFragment { params.putString("phoneFormated", requestPhone); params.putString("phoneHash", phoneHash); params.putString("code", req.phone_code); - setPage(2, true, params, false); + setPage(5, true, params, false); destroyTimer(); destroyCodeTimer(); } else if (error.text.contains("SESSION_PASSWORD_NEEDED")) { @@ -1255,7 +1565,7 @@ public class LoginActivity extends BaseFragment { bundle.putString("phoneHash", phoneHash); bundle.putString("code", req.phone_code); bundle.putInt("has_recovery", password.has_recovery ? 1 : 0); - setPage(3, true, bundle, false); + setPage(6, true, bundle, false); } else { needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); } @@ -1267,19 +1577,31 @@ public class LoginActivity extends BaseFragment { destroyCodeTimer(); } else { needHideProgress(); - createTimer(); - if (error.text.contains("PHONE_NUMBER_INVALID")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); - } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidCode", R.string.InvalidCode)); - } else if (error.text.contains("PHONE_CODE_EXPIRED")) { - onBackPressed(); - setPage(0, true, null, true); - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("CodeExpired", R.string.CodeExpired)); - } else if (error.text.startsWith("FLOOD_WAIT")) { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("FloodWait", R.string.FloodWait)); - } else { - needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); + if (currentType == 3 && (nextType == 4 || nextType == 2) || currentType == 2 && (nextType == 4 || nextType == 3)) { + createTimer(); + } + if (currentType == 2) { + AndroidUtilities.setWaitingForSms(true); + NotificationCenter.getInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveSmsCode); + } else if (currentType == 3) { + AndroidUtilities.setWaitingForCall(true); + NotificationCenter.getInstance().addObserver(LoginActivitySmsView.this, NotificationCenter.didReceiveCall); + } + waitingForEvent = true; + if (currentType != 3) { + if (error.text.contains("PHONE_NUMBER_INVALID")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidPhoneNumber", R.string.InvalidPhoneNumber)); + } else if (error.text.contains("PHONE_CODE_EMPTY") || error.text.contains("PHONE_CODE_INVALID")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("InvalidCode", R.string.InvalidCode)); + } else if (error.text.contains("PHONE_CODE_EXPIRED")) { + onBackPressed(); + setPage(0, true, null, true); + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("CodeExpired", R.string.CodeExpired)); + } else if (error.text.startsWith("FLOOD_WAIT")) { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("FloodWait", R.string.FloodWait)); + } else { + needShowAlert(LocaleController.getString("AppName", R.string.AppName), LocaleController.getString("ErrorOccurred", R.string.ErrorOccurred) + "\n" + error.text); + } } } } @@ -1294,19 +1616,29 @@ public class LoginActivity extends BaseFragment { destroyTimer(); destroyCodeTimer(); currentParams = null; - AndroidUtilities.setWaitingForSms(false); - NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); - waitingForSms = false; + if (currentType == 2) { + AndroidUtilities.setWaitingForSms(false); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); + } else if (currentType == 3) { + AndroidUtilities.setWaitingForCall(false); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall); + } + waitingForEvent = false; } @Override public void onDestroyActivity() { super.onDestroyActivity(); - AndroidUtilities.setWaitingForSms(false); - NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); + if (currentType == 2) { + AndroidUtilities.setWaitingForSms(false); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveSmsCode); + } else if (currentType == 3) { + AndroidUtilities.setWaitingForCall(false); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceiveCall); + } + waitingForEvent = false; destroyTimer(); destroyCodeTimer(); - waitingForSms = false; } @Override @@ -1320,27 +1652,37 @@ public class LoginActivity extends BaseFragment { @Override public void didReceivedNotification(int id, final Object... args) { + if (!waitingForEvent || codeField == null) { + return; + } if (id == NotificationCenter.didReceiveSmsCode) { - if (!waitingForSms) { - return; - } - if (codeField != null) { ignoreOnTextChange = true; codeField.setText("" + args[0]); ignoreOnTextChange = false; onNextPressed(); - } + } else if (id == NotificationCenter.didReceiveCall) { + String num = "" + args[0]; + if (!pattern.equals("*")) { + String patternNumbers = pattern.replace("*", ""); + if (!num.contains(patternNumbers)) { + return; } + } + ignoreOnTextChange = true; + codeField.setText(num); + ignoreOnTextChange = false; + onNextPressed(); + } } @Override public void saveStateParams(Bundle bundle) { String code = codeField.getText().toString(); if (code.length() != 0) { - bundle.putString("smsview_code", code); + bundle.putString("smsview_code_" + currentType, code); } if (currentParams != null) { - bundle.putBundle("smsview_params", currentParams); + bundle.putBundle("smsview_params_" + currentType, currentParams); } if (time != 0) { bundle.putInt("time", time); @@ -1352,11 +1694,11 @@ public class LoginActivity extends BaseFragment { @Override public void restoreStateParams(Bundle bundle) { - currentParams = bundle.getBundle("smsview_params"); + currentParams = bundle.getBundle("smsview_params_" + currentType); if (currentParams != null) { setParams(currentParams); } - String code = bundle.getString("smsview_code"); + String code = bundle.getString("smsview_code_" + currentType); if (code != null) { codeField.setText(code); } @@ -1457,7 +1799,7 @@ public class LoginActivity extends BaseFragment { public void onClick(DialogInterface dialogInterface, int i) { Bundle bundle = new Bundle(); bundle.putString("email_unconfirmed_pattern", res.email_pattern); - setPage(4, true, bundle, false); + setPage(7, true, bundle, false); } }); Dialog dialog = showDialog(builder.create()); @@ -1526,7 +1868,7 @@ public class LoginActivity extends BaseFragment { params.putString("phoneFormated", requestPhone); params.putString("phoneHash", phoneHash); params.putString("code", phoneCode); - setPage(2, true, params, false); + setPage(5, true, params, false); } else { needShowAlert(LocaleController.getString("AppName", R.string.AppName), error.text); } @@ -1783,7 +2125,7 @@ public class LoginActivity extends BaseFragment { builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - setPage(3, true, new Bundle(), true); + setPage(6, true, new Bundle(), true); } }); Dialog dialog = showDialog(builder.create()); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ManageSpaceActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ManageSpaceActivity.java new file mode 100644 index 00000000..e3e6cbb7 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ManageSpaceActivity.java @@ -0,0 +1,382 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Configuration; +import android.os.Build; +import android.os.Bundle; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.RelativeLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.ui.ActionBar.ActionBarLayout; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.DrawerLayoutContainer; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.ActionBar.Theme; + +import java.util.ArrayList; + +public class ManageSpaceActivity extends Activity implements ActionBarLayout.ActionBarLayoutDelegate { + + private boolean finished; + private int currentConnectionState; + private static ArrayList mainFragmentsStack = new ArrayList<>(); + private static ArrayList layerFragmentsStack = new ArrayList<>(); + + private ActionBarLayout actionBarLayout; + private ActionBarLayout layersActionBarLayout; + protected DrawerLayoutContainer drawerLayoutContainer; + + @Override + protected void onCreate(Bundle savedInstanceState) { + ApplicationLoader.postInitApplication(); + + requestWindowFeature(Window.FEATURE_NO_TITLE); + setTheme(R.style.Theme_TMessages); + getWindow().setBackgroundDrawableResource(R.drawable.transparent); + + super.onCreate(savedInstanceState); + Theme.loadResources(this); + + int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resourceId > 0) { + AndroidUtilities.statusBarHeight = getResources().getDimensionPixelSize(resourceId); + } + + actionBarLayout = new ActionBarLayout(this); + + drawerLayoutContainer = new DrawerLayoutContainer(this); + drawerLayoutContainer.setAllowOpenDrawer(false, false); + setContentView(drawerLayoutContainer, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + + if (AndroidUtilities.isTablet()) { + getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); + + RelativeLayout launchLayout = new RelativeLayout(this); + drawerLayoutContainer.addView(launchLayout); + FrameLayout.LayoutParams layoutParams1 = (FrameLayout.LayoutParams) launchLayout.getLayoutParams(); + layoutParams1.width = LayoutHelper.MATCH_PARENT; + layoutParams1.height = LayoutHelper.MATCH_PARENT; + launchLayout.setLayoutParams(layoutParams1); + + ImageView backgroundTablet = new ImageView(this); + backgroundTablet.setScaleType(ImageView.ScaleType.CENTER_CROP); + backgroundTablet.setImageResource(R.drawable.cats); + launchLayout.addView(backgroundTablet); + RelativeLayout.LayoutParams relativeLayoutParams = (RelativeLayout.LayoutParams) backgroundTablet.getLayoutParams(); + relativeLayoutParams.width = LayoutHelper.MATCH_PARENT; + relativeLayoutParams.height = LayoutHelper.MATCH_PARENT; + backgroundTablet.setLayoutParams(relativeLayoutParams); + + launchLayout.addView(actionBarLayout); + relativeLayoutParams = (RelativeLayout.LayoutParams) actionBarLayout.getLayoutParams(); + relativeLayoutParams.width = LayoutHelper.MATCH_PARENT; + relativeLayoutParams.height = LayoutHelper.MATCH_PARENT; + actionBarLayout.setLayoutParams(relativeLayoutParams); + + FrameLayout shadowTablet = new FrameLayout(this); + shadowTablet.setBackgroundColor(0x7F000000); + launchLayout.addView(shadowTablet); + relativeLayoutParams = (RelativeLayout.LayoutParams) shadowTablet.getLayoutParams(); + relativeLayoutParams.width = LayoutHelper.MATCH_PARENT; + relativeLayoutParams.height = LayoutHelper.MATCH_PARENT; + shadowTablet.setLayoutParams(relativeLayoutParams); + shadowTablet.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (!actionBarLayout.fragmentsStack.isEmpty() && event.getAction() == MotionEvent.ACTION_UP) { + float x = event.getX(); + float y = event.getY(); + int location[] = new int[2]; + layersActionBarLayout.getLocationOnScreen(location); + int viewX = location[0]; + int viewY = location[1]; + + if (layersActionBarLayout.checkTransitionAnimation() || x > viewX && x < viewX + layersActionBarLayout.getWidth() && y > viewY && y < viewY + layersActionBarLayout.getHeight()) { + return false; + } else { + if (!layersActionBarLayout.fragmentsStack.isEmpty()) { + for (int a = 0; a < layersActionBarLayout.fragmentsStack.size() - 1; a++) { + layersActionBarLayout.removeFragmentFromStack(layersActionBarLayout.fragmentsStack.get(0)); + a--; + } + layersActionBarLayout.closeLastFragment(true); + } + return true; + } + } + return false; + } + }); + + shadowTablet.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + } + }); + + layersActionBarLayout = new ActionBarLayout(this); + layersActionBarLayout.setRemoveActionBarExtraHeight(true); + layersActionBarLayout.setBackgroundView(shadowTablet); + layersActionBarLayout.setUseAlphaAnimations(true); + layersActionBarLayout.setBackgroundResource(R.drawable.boxshadow); + launchLayout.addView(layersActionBarLayout); + relativeLayoutParams = (RelativeLayout.LayoutParams)layersActionBarLayout.getLayoutParams(); + relativeLayoutParams.width = AndroidUtilities.dp(530); + relativeLayoutParams.height = AndroidUtilities.dp(528); + layersActionBarLayout.setLayoutParams(relativeLayoutParams); + layersActionBarLayout.init(layerFragmentsStack); + layersActionBarLayout.setDelegate(this); + layersActionBarLayout.setDrawerLayoutContainer(drawerLayoutContainer); + } else { + drawerLayoutContainer.addView(actionBarLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + } + + // drawerLayoutContainer.setDrawerLayout(listView); + + drawerLayoutContainer.setParentActionBarLayout(actionBarLayout); + actionBarLayout.setDrawerLayoutContainer(drawerLayoutContainer); + actionBarLayout.init(mainFragmentsStack); + actionBarLayout.setDelegate(this); + + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeOtherAppActivities, this); + currentConnectionState = ConnectionsManager.getInstance().getConnectionState(); + + handleIntent(getIntent(), false, savedInstanceState != null, false); + needLayout(); + } + + private boolean handleIntent(Intent intent, boolean isNew, boolean restore, boolean fromPassword) { + if (AndroidUtilities.isTablet()) { + if (layersActionBarLayout.fragmentsStack.isEmpty()) { + layersActionBarLayout.addFragmentToStack(new CacheControlActivity()); + } + } else { + if (actionBarLayout.fragmentsStack.isEmpty()) { + actionBarLayout.addFragmentToStack(new CacheControlActivity()); + } + } + actionBarLayout.showLastFragment(); + if (AndroidUtilities.isTablet()) { + layersActionBarLayout.showLastFragment(); + } + intent.setAction(null); + return false; + } + + @Override + public boolean onPreIme() { + return false; + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + handleIntent(intent, true, false, false); + } + + private void onFinish() { + if (finished) { + return; + } + finished = true; + } + + public void presentFragment(BaseFragment fragment) { + actionBarLayout.presentFragment(fragment); + } + + public boolean presentFragment(final BaseFragment fragment, final boolean removeLast, boolean forceWithoutAnimation) { + return actionBarLayout.presentFragment(fragment, removeLast, forceWithoutAnimation, true); + } + + public void needLayout() { + if (AndroidUtilities.isTablet()) { + RelativeLayout.LayoutParams relativeLayoutParams = (RelativeLayout.LayoutParams)layersActionBarLayout.getLayoutParams(); + relativeLayoutParams.leftMargin = (AndroidUtilities.displaySize.x - relativeLayoutParams.width) / 2; + int y = (Build.VERSION.SDK_INT >= 21 ? AndroidUtilities.statusBarHeight : 0); + relativeLayoutParams.topMargin = y + (AndroidUtilities.displaySize.y - relativeLayoutParams.height - y) / 2; + layersActionBarLayout.setLayoutParams(relativeLayoutParams); + + + if (!AndroidUtilities.isSmallTablet() || getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + int leftWidth = AndroidUtilities.displaySize.x / 100 * 35; + if (leftWidth < AndroidUtilities.dp(320)) { + leftWidth = AndroidUtilities.dp(320); + } + + relativeLayoutParams = (RelativeLayout.LayoutParams) actionBarLayout.getLayoutParams(); + relativeLayoutParams.width = leftWidth; + relativeLayoutParams.height = LayoutHelper.MATCH_PARENT; + actionBarLayout.setLayoutParams(relativeLayoutParams); + + if (AndroidUtilities.isSmallTablet() && actionBarLayout.fragmentsStack.size() == 2) { + BaseFragment chatFragment = actionBarLayout.fragmentsStack.get(1); + chatFragment.onPause(); + actionBarLayout.fragmentsStack.remove(1); + actionBarLayout.showLastFragment(); + } + } else { + relativeLayoutParams = (RelativeLayout.LayoutParams) actionBarLayout.getLayoutParams(); + relativeLayoutParams.width = LayoutHelper.MATCH_PARENT; + relativeLayoutParams.height = LayoutHelper.MATCH_PARENT; + actionBarLayout.setLayoutParams(relativeLayoutParams); + } + } + } + + public void fixLayout() { + if (!AndroidUtilities.isTablet()) { + return; + } + if (actionBarLayout == null) { + return; + } + actionBarLayout.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + needLayout(); + if (actionBarLayout != null) { + if (Build.VERSION.SDK_INT < 16) { + actionBarLayout.getViewTreeObserver().removeGlobalOnLayoutListener(this); + } else { + actionBarLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + } + } + }); + } + + @Override + protected void onPause() { + super.onPause(); + actionBarLayout.onPause(); + if (AndroidUtilities.isTablet()) { + layersActionBarLayout.onPause(); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + onFinish(); + } + + @Override + protected void onResume() { + super.onResume(); + actionBarLayout.onResume(); + if (AndroidUtilities.isTablet()) { + layersActionBarLayout.onResume(); + } + } + + @Override + public void onConfigurationChanged(android.content.res.Configuration newConfig) { + AndroidUtilities.checkDisplaySize(); + super.onConfigurationChanged(newConfig); + fixLayout(); + } + + private void updateCurrentConnectionState() { + String text = null; + if (currentConnectionState == ConnectionsManager.ConnectionStateWaitingForNetwork) { + text = LocaleController.getString("WaitingForNetwork", R.string.WaitingForNetwork); + } else if (currentConnectionState == ConnectionsManager.ConnectionStateConnecting) { + text = LocaleController.getString("Connecting", R.string.Connecting); + } else if (currentConnectionState == ConnectionsManager.ConnectionStateUpdating) { + text = LocaleController.getString("Updating", R.string.Updating); + } + actionBarLayout.setTitleOverlayText(text); + } + + @Override + public void onBackPressed() { + if (PhotoViewer.getInstance().isVisible()) { + PhotoViewer.getInstance().closePhoto(true, false); + } else if (drawerLayoutContainer.isDrawerOpened()) { + drawerLayoutContainer.closeDrawer(false); + } else if (AndroidUtilities.isTablet()) { + if (layersActionBarLayout.getVisibility() == View.VISIBLE) { + layersActionBarLayout.onBackPressed(); + } else { + actionBarLayout.onBackPressed(); + } + } else { + actionBarLayout.onBackPressed(); + } + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + actionBarLayout.onLowMemory(); + if (AndroidUtilities.isTablet()) { + layersActionBarLayout.onLowMemory(); + } + } + + @Override + public boolean needPresentFragment(BaseFragment fragment, boolean removeLast, boolean forceWithoutAnimation, ActionBarLayout layout) { + return true; + } + + @Override + public boolean needAddFragmentToStack(BaseFragment fragment, ActionBarLayout layout) { + return true; + } + + @Override + public boolean needCloseLastFragment(ActionBarLayout layout) { + if (AndroidUtilities.isTablet()) { + if (layout == actionBarLayout && layout.fragmentsStack.size() <= 1) { + onFinish(); + finish(); + return false; + } else if (layout == layersActionBarLayout && actionBarLayout.fragmentsStack.isEmpty() && layersActionBarLayout.fragmentsStack.size() == 1) { + onFinish(); + finish(); + return false; + } + } else { + if (layout.fragmentsStack.size() <= 1) { + onFinish(); + finish(); + return false; + } + } + return true; + } + + @Override + public void onRebuildAllFragments(ActionBarLayout layout) { + if (AndroidUtilities.isTablet()) { + if (layout == layersActionBarLayout) { + actionBarLayout.rebuildAllFragmentViews(true); + actionBarLayout.showLastFragment(); + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java index d896cea5..b1a6f02d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/MediaActivity.java @@ -20,7 +20,6 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.provider.Browser; import android.text.TextUtils; import android.util.TypedValue; import android.view.Gravity; @@ -41,32 +40,35 @@ import android.widget.ProgressBar; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ChatObject; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.MediaController; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.query.SharedMediaQuery; +import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; +import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ChatObject; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MediaController; +import org.telegram.messenger.MessageObject; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.Utilities; +import org.telegram.messenger.browser.Browser; +import org.telegram.messenger.query.SharedMediaQuery; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; -import org.telegram.messenger.MessageObject; -import org.telegram.messenger.NotificationCenter; -import org.telegram.messenger.R; -import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.ActionBarPopupWindow; -import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.BackDrawable; +import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.BaseFragmentAdapter; import org.telegram.ui.Adapters.BaseSectionsAdapter; -import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; -import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; import org.telegram.ui.Cells.GreySectionCell; import org.telegram.ui.Cells.LoadingCell; import org.telegram.ui.Cells.SharedDocumentCell; @@ -74,7 +76,6 @@ import org.telegram.ui.Cells.SharedLinkCell; import org.telegram.ui.Cells.SharedMediaSectionCell; import org.telegram.ui.Cells.SharedPhotoVideoCell; import org.telegram.ui.Components.BackupImageView; -import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.NumberTextView; import org.telegram.ui.Components.PlayerView; @@ -220,6 +221,13 @@ private final static int quoteforward = 33; NotificationCenter.getInstance().addObserver(this, NotificationCenter.didReceivedNewMessages); NotificationCenter.getInstance().addObserver(this, NotificationCenter.messageReceivedByServer); dialog_id = getArguments().getLong("dialog_id", 0); + selectedMode = getArguments().getInt("selected_mode", 0); + /*SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + int sm = preferences.getInt("mediaSelectedMode", 0); + if(selectedMode == 0 && selectedMode != sm){ + selectedMode = sm; + }*/ + for (int a = 0; a < sharedMediaData.length; a++) { sharedMediaData[a] = new SharedMediaData(); sharedMediaData[a].max_id[0] = ((int)dialog_id) == 0 ? Integer.MIN_VALUE : Integer.MAX_VALUE; @@ -251,6 +259,8 @@ private final static int quoteforward = 33; actionBar.setBackButtonDrawable(d); actionBar.setTitle(""); actionBar.setAllowOverlayTitle(false); + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + actionBar.setBackgroundColor(def); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -346,7 +356,7 @@ private final static int quoteforward = 33; args.putInt("dialogsType", 1); final boolean quoteForward = id == forward ? false : true; DialogsActivity fragment = new DialogsActivity(args); - fragment.setDelegate(new DialogsActivity.MessagesActivityDelegate() { + fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { @Override public void didSelectDialog(DialogsActivity fragment, long did, boolean param) { int lower_part = (int) did; @@ -361,6 +371,9 @@ private final static int quoteforward = 33; } else if (lower_part < 0) { args.putInt("chat_id", -lower_part); } + if (!MessagesController.checkCanOpenChat(args, fragment)) { + return; + } ArrayList fmessages = new ArrayList<>(); for (int a = 1; a >= 0; a--) { @@ -377,6 +390,7 @@ private final static int quoteforward = 33; actionBar.hideActionMode(); NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); + ChatActivity chatActivity = new ChatActivity(args); presentFragment(chatActivity, true); chatActivity.showReplyPanel(true, null, fmessages, null, false, false); @@ -391,6 +405,12 @@ private final static int quoteforward = 33; }); presentFragment(fragment); } + /*SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + int sm = preferences.getInt("mediaSelectedMode",0); + if(selectedMode != sm){ + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("mediaSelectedMode", selectedMode).apply(); + }*/ } }); @@ -451,13 +471,18 @@ private final static int quoteforward = 33; searchItem.getSearchField().setHint(LocaleController.getString("Search", R.string.Search)); searchItem.setVisibility(View.GONE); - dropDownContainer = new ActionBarMenuItem(context, menu, R.drawable.bar_selector); + dropDownContainer = new ActionBarMenuItem(context, menu, 0); dropDownContainer.setSubMenuOpenSide(1); dropDownContainer.addSubItem(shared_media_item, LocaleController.getString("SharedMediaTitle", R.string.SharedMediaTitle), 0); dropDownContainer.addSubItem(files_item, LocaleController.getString("DocumentsTitle", R.string.DocumentsTitle), 0); if ((int) dialog_id != 0) { dropDownContainer.addSubItem(links_item, LocaleController.getString("LinksTitle", R.string.LinksTitle), 0); dropDownContainer.addSubItem(music_item, LocaleController.getString("AudioTitle", R.string.AudioTitle), 0); + } else { + TLRPC.EncryptedChat currentEncryptedChat = MessagesController.getInstance().getEncryptedChat((int) (dialog_id >> 32)); + if (currentEncryptedChat != null && AndroidUtilities.getPeerLayerVersion(currentEncryptedChat.layer) >= 46) { + dropDownContainer.addSubItem(music_item, LocaleController.getString("AudioTitle", R.string.AudioTitle), 0); + } } actionBar.addView(dropDownContainer, 0, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, AndroidUtilities.isTablet() ? 64 : 56, 0, 40, 0)); dropDownContainer.setOnClickListener(new View.OnClickListener() { @@ -495,10 +520,10 @@ private final static int quoteforward = 33; actionMode.addView(selectedMessagesCountTextView, LayoutHelper.createLinear(0, LayoutHelper.MATCH_PARENT, 1.0f, 65, 0, 0, 0)); if ((int) dialog_id != 0) { - actionModeViews.add(actionMode.addItem(quoteforward, R.drawable.ic_ab_fwd_quoteforward, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); - actionModeViews.add(actionMode.addItem(forward, R.drawable.ic_ab_fwd_forward, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); + actionModeViews.add(actionMode.addItem(quoteforward, R.drawable.ic_ab_fwd_quoteforward, Theme.ACTION_BAR_MODE_SELECTOR_COLOR, null, AndroidUtilities.dp(54))); + actionModeViews.add(actionMode.addItem(forward, R.drawable.ic_ab_fwd_forward, Theme.ACTION_BAR_MODE_SELECTOR_COLOR, null, AndroidUtilities.dp(54))); } - actionModeViews.add(actionMode.addItem(delete, R.drawable.ic_ab_fwd_delete, R.drawable.bar_selector_mode, null, AndroidUtilities.dp(54))); + actionModeViews.add(actionMode.addItem(delete, R.drawable.ic_ab_fwd_delete, Theme.ACTION_BAR_MODE_SELECTOR_COLOR, null, AndroidUtilities.dp(54))); photoVideoAdapter = new SharedPhotoVideoAdapter(context); documentsAdapter = new SharedDocumentsAdapter(context, 1); @@ -521,7 +546,7 @@ private final static int quoteforward = 33; @Override public void onItemClick(AdapterView adapterView, View view, final int i, long l) { if ((selectedMode == 1 || selectedMode == 4) && view instanceof SharedDocumentCell) { - MediaActivity.this.onItemClick(i, view, ((SharedDocumentCell) view).getDocument(), 0); + MediaActivity.this.onItemClick(i, view, ((SharedDocumentCell) view).getMessage(), 0); } else if (selectedMode == 3 && view instanceof SharedLinkCell) { MediaActivity.this.onItemClick(i, view, ((SharedLinkCell) view).getMessage(), 0); } @@ -569,7 +594,7 @@ private final static int quoteforward = 33; public boolean onItemLongClick(AdapterView parent, View view, int i, long id) { if ((selectedMode == 1 || selectedMode == 4) && view instanceof SharedDocumentCell) { SharedDocumentCell cell = (SharedDocumentCell) view; - MessageObject message = cell.getDocument(); + MessageObject message = cell.getMessage(); return MediaActivity.this.onItemLongClick(message, view, 0); } else if (selectedMode == 3 && view instanceof SharedLinkCell) { SharedLinkCell cell = (SharedLinkCell) view; @@ -910,7 +935,11 @@ private final static int quoteforward = 33; listView.setAdapter(photoVideoAdapter); dropDown.setText(LocaleController.getString("SharedMediaTitle", R.string.SharedMediaTitle)); emptyImageView.setImageResource(R.drawable.tip1); + if ((int) dialog_id == 0) { + emptyTextView.setText(LocaleController.getString("NoMediaSecret", R.string.NoMediaSecret)); + } else { emptyTextView.setText(LocaleController.getString("NoMedia", R.string.NoMedia)); + } searchItem.setVisibility(View.GONE); if (sharedMediaData[selectedMode].loading && sharedMediaData[selectedMode].messages.isEmpty()) { progressView.setVisibility(View.VISIBLE); @@ -927,13 +956,21 @@ private final static int quoteforward = 33; listView.setAdapter(documentsAdapter); dropDown.setText(LocaleController.getString("DocumentsTitle", R.string.DocumentsTitle)); emptyImageView.setImageResource(R.drawable.tip2); + if ((int) dialog_id == 0) { + emptyTextView.setText(LocaleController.getString("NoSharedFilesSecret", R.string.NoSharedFilesSecret)); + } else { emptyTextView.setText(LocaleController.getString("NoSharedFiles", R.string.NoSharedFiles)); + } } else if (selectedMode == 4) { listView.setAdapter(audioAdapter); dropDown.setText(LocaleController.getString("AudioTitle", R.string.AudioTitle)); emptyImageView.setImageResource(R.drawable.tip4); + if ((int) dialog_id == 0) { + emptyTextView.setText(LocaleController.getString("NoSharedAudioSecret", R.string.NoSharedAudioSecret)); + } else { emptyTextView.setText(LocaleController.getString("NoSharedAudio", R.string.NoSharedAudio)); } + } searchItem.setVisibility(!sharedMediaData[selectedMode].messages.isEmpty() ? View.VISIBLE : View.GONE); if (!sharedMediaData[selectedMode].loading && !sharedMediaData[selectedMode].endReached[0] && sharedMediaData[selectedMode].messages.isEmpty()) { sharedMediaData[selectedMode].loading = true; @@ -953,7 +990,11 @@ private final static int quoteforward = 33; listView.setAdapter(linksAdapter); dropDown.setText(LocaleController.getString("LinksTitle", R.string.LinksTitle)); emptyImageView.setImageResource(R.drawable.tip3); + if ((int) dialog_id == 0) { + emptyTextView.setText(LocaleController.getString("NoSharedLinksSecret", R.string.NoSharedLinksSecret)); + } else { emptyTextView.setText(LocaleController.getString("NoSharedLinks", R.string.NoSharedLinks)); + } searchItem.setVisibility(!sharedMediaData[3].messages.isEmpty() ? View.VISIBLE : View.GONE); if (!sharedMediaData[selectedMode].loading && !sharedMediaData[selectedMode].endReached[0] && sharedMediaData[selectedMode].messages.isEmpty()) { sharedMediaData[selectedMode].loading = true; @@ -1053,7 +1094,7 @@ private final static int quoteforward = 33; } } File f = null; - String fileName = message.messageOwner.media != null ? FileLoader.getAttachFileName(message.messageOwner.media.document) : ""; + String fileName = message.messageOwner.media != null ? FileLoader.getAttachFileName(message.getDocument()) : ""; if (message.messageOwner.attachPath != null && message.messageOwner.attachPath.length() != 0) { f = new File(message.messageOwner.attachPath); } @@ -1065,12 +1106,12 @@ private final static int quoteforward = 33; try { Intent intent = new Intent(Intent.ACTION_VIEW); MimeTypeMap myMime = MimeTypeMap.getSingleton(); - int idx = fileName.lastIndexOf("."); + int idx = fileName.lastIndexOf('.'); if (idx != -1) { String ext = fileName.substring(idx + 1); realMimeType = myMime.getMimeTypeFromExtension(ext.toLowerCase()); if (realMimeType == null) { - realMimeType = message.messageOwner.media.document.mime_type; + realMimeType = message.getDocument().mime_type; if (realMimeType == null || realMimeType.length() == 0) { realMimeType = null; } @@ -1100,15 +1141,15 @@ private final static int quoteforward = 33; AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), null); - builder.setMessage(LocaleController.formatString("NoHandleAppInstalled", R.string.NoHandleAppInstalled, message.messageOwner.media.document.mime_type)); + builder.setMessage(LocaleController.formatString("NoHandleAppInstalled", R.string.NoHandleAppInstalled, message.getDocument().mime_type)); showDialog(builder.create()); } } } else if (!cell.isLoading()) { - FileLoader.getInstance().loadFile(cell.getDocument().messageOwner.media.document, false, false); + FileLoader.getInstance().loadFile(cell.getMessage().getDocument(), false, false); cell.updateFileExistIcon(); } else { - FileLoader.getInstance().cancelLoadFile(cell.getDocument().messageOwner.media.document); + FileLoader.getInstance().cancelLoadFile(cell.getMessage().getDocument()); cell.updateFileExistIcon(); } } @@ -1128,10 +1169,7 @@ private final static int quoteforward = 33; link = ((SharedLinkCell) view).getLink(0); } if (link != null) { - Uri uri = Uri.parse(link); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, getParentActivity().getPackageName()); - getParentActivity().startActivity(intent); + Browser.openUrl(getParentActivity(), link); } } catch (Exception e) { FileLog.e("tmessages", e); @@ -1142,7 +1180,7 @@ private final static int quoteforward = 33; private void openWebView(TLRPC.WebPage webPage) { BottomSheet.Builder builder = new BottomSheet.Builder(getParentActivity()); - builder.setCustomView(new WebFrameLayout(getParentActivity(), builder.create(), webPage.title, webPage.url, webPage.embed_url, webPage.embed_width, webPage.embed_height)); + builder.setCustomView(new WebFrameLayout(getParentActivity(), builder.create(), webPage.site_name, webPage.description, webPage.url, webPage.embed_url, webPage.embed_width, webPage.embed_height)); builder.setUseFullWidth(true); showDialog(builder.create()); } @@ -1554,7 +1592,7 @@ private final static int quoteforward = 33; } else if (currentType == 3) { req.filter = new TLRPC.TL_inputMessagesFilterUrl(); } else if (currentType == 4) { - req.filter = new TLRPC.TL_inputMessagesFilterAudioDocuments(); + req.filter = new TLRPC.TL_inputMessagesFilterMusic(); } req.q = query; req.peer = MessagesController.getInputPeer(uid); @@ -1624,14 +1662,14 @@ private final static int quoteforward = 33; @Override public void run() { if (!sharedMediaData[currentType].messages.isEmpty()) { - if (currentType == 1) { + if (currentType == 1 || currentType == 4) { MessageObject messageObject = sharedMediaData[currentType].messages.get(sharedMediaData[currentType].messages.size() - 1); queryServerSearch(query, messageObject.getId(), messageObject.getDialogId()); - } else if (currentType == 3 || currentType == 4) { + } else if (currentType == 3) { queryServerSearch(query, 0, dialog_id); } } - if (currentType == 1) { + if (currentType == 1 || currentType == 4) { final ArrayList copy = new ArrayList<>(); copy.addAll(sharedMediaData[currentType].messages); Utilities.searchQueue.postRunnable(new Runnable() { @@ -1656,7 +1694,8 @@ private final static int quoteforward = 33; for (int a = 0; a < copy.size(); a++) { MessageObject messageObject = copy.get(a); - for (String q : search) { + for (int b = 0; b < search.length; b++) { + String q = search[b]; String name = messageObject.getDocumentName(); if (name == null || name.length() == 0) { continue; @@ -1666,6 +1705,31 @@ private final static int quoteforward = 33; resultArray.add(messageObject); break; } + if (currentType == 4) { + TLRPC.Document document; + if (messageObject.type == 0) { + document = messageObject.messageOwner.media.webpage.document; + } else { + document = messageObject.messageOwner.media.document; + } + boolean ok = false; + for (int c = 0; c < document.attributes.size(); c++) { + TLRPC.DocumentAttribute attribute = document.attributes.get(c); + if (attribute instanceof TLRPC.TL_documentAttributeAudio) { + if (attribute.performer != null) { + ok = attribute.performer.toLowerCase().contains(q); + } + if (!ok && attribute.title != null) { + ok = attribute.title.toLowerCase().contains(q); + } + break; + } + } + if (ok) { + resultArray.add(messageObject); + break; + } + } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java index 5c6f2eac..d8d73552 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/NotificationsSettingsActivity.java @@ -61,7 +61,7 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif private boolean reseting = false; private int notificationsServiceRow; - private int messageSectionRow2; + private int notificationsServiceConnectionRow; private int messageSectionRow; private int messageAlertRow; private int messagePreviewRow; @@ -89,6 +89,7 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif private int eventsSectionRow2; private int eventsSectionRow; private int contactJoinedRow; + private int pinnedMessageRow; private int otherSectionRow2; private int otherSectionRow; private int badgeNumberRow; @@ -101,8 +102,6 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif @Override public boolean onFragmentCreate() { - notificationsServiceRow = rowCount++; - messageSectionRow2 = rowCount++; messageSectionRow = rowCount++; messageAlertRow = rowCount++; messagePreviewRow = rowCount++; @@ -142,8 +141,11 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif eventsSectionRow2 = rowCount++; eventsSectionRow = rowCount++; contactJoinedRow = rowCount++; + pinnedMessageRow = rowCount++; otherSectionRow2 = rowCount++; otherSectionRow = rowCount++; + notificationsServiceRow = rowCount++; + notificationsServiceConnectionRow = rowCount++; badgeNumberRow = rowCount++; androidAutoAlertRow = -1; repeatRow = rowCount++; @@ -325,6 +327,12 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif MessagesController.getInstance().enableJoined = !enabled; editor.putBoolean("EnableContactJoined", !enabled); editor.commit(); + } else if (i == pinnedMessageRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + enabled = preferences.getBoolean("PinnedMessages", true); + editor.putBoolean("PinnedMessages", !enabled); + editor.commit(); } else if (i == androidAutoAlertRow) { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); @@ -338,14 +346,30 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif editor.putBoolean("badgeNumber", !enabled); editor.commit(); NotificationsController.getInstance().setBadgeEnabled(!enabled); + } else if (i == notificationsServiceConnectionRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); + enabled = preferences.getBoolean("pushConnection", true); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("pushConnection", !enabled); + editor.commit(); + if (!enabled) { + ConnectionsManager.getInstance().setPushConnectionEnabled(true); + } else { + ConnectionsManager.getInstance().setPushConnectionEnabled(false); + } } else if (i == notificationsServiceRow) { final SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("Notifications", Activity.MODE_PRIVATE); enabled = preferences.getBoolean("pushService", true); - if (!enabled) { - final SharedPreferences.Editor editor = preferences.edit(); + SharedPreferences.Editor editor = preferences.edit(); editor.putBoolean("pushService", !enabled); editor.commit(); + if (!enabled) { ApplicationLoader.startPushService(); + } else { + ApplicationLoader.stopPushService(); + } + /*if (!enabled) { + } else { if (getParentActivity() == null) { return; @@ -356,7 +380,7 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - ApplicationLoader.stopPushService(); + final SharedPreferences.Editor editor = preferences.edit(); editor.putBoolean("pushService", false); editor.commit(); @@ -370,7 +394,7 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif } }); showDialog(builder.create()); - } + }*/ } else if (i == messageLedRow || i == groupLedRow) { if (getParentActivity() == null) { return; @@ -664,7 +688,7 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif public boolean isEnabled(int i) { return !(i == messageSectionRow || i == groupSectionRow || i == inappSectionRow || i == eventsSectionRow || i == otherSectionRow || i == resetSectionRow || - i == messageSectionRow2 || i == eventsSectionRow2 || i == groupSectionRow2 || + i == eventsSectionRow2 || i == groupSectionRow2 || i == inappSectionRow2 || i == otherSectionRow2 || i == resetSectionRow2); } @@ -732,11 +756,15 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif } else if (i == inappPriorityRow) { checkCell.setTextAndCheck(LocaleController.getString("NotificationsPriority", R.string.NotificationsPriority), preferences.getBoolean("EnableInAppPriority", false), false); } else if (i == contactJoinedRow) { - checkCell.setTextAndCheck(LocaleController.getString("ContactJoined", R.string.ContactJoined), preferences.getBoolean("EnableContactJoined", true), false); + checkCell.setTextAndCheck(LocaleController.getString("ContactJoined", R.string.ContactJoined), preferences.getBoolean("EnableContactJoined", true), true); + } else if (i == pinnedMessageRow) { + checkCell.setTextAndCheck(LocaleController.getString("PinnedMessages", R.string.PinnedMessages), preferences.getBoolean("PinnedMessages", true), false); } else if (i == androidAutoAlertRow) { checkCell.setTextAndCheck("Android Auto", preferences.getBoolean("EnableAutoNotifications", false), true); } else if (i == notificationsServiceRow) { - checkCell.setTextAndCheck(LocaleController.getString("NotificationsService", R.string.NotificationsService), preferences.getBoolean("pushService", true), false); + checkCell.setTextAndValueAndCheck(LocaleController.getString("NotificationsService", R.string.NotificationsService), LocaleController.getString("NotificationsServiceInfo", R.string.NotificationsServiceInfo), preferences.getBoolean("pushService", true), true, true); + } else if (i == notificationsServiceConnectionRow) { + checkCell.setTextAndValueAndCheck(LocaleController.getString("NotificationsServiceConnection", R.string.NotificationsServiceConnection), LocaleController.getString("NotificationsServiceConnectionInfo", R.string.NotificationsServiceConnectionInfo), preferences.getBoolean("pushConnection", true), true, true); } else if (i == badgeNumberRow) { checkCell.setTextAndCheck(LocaleController.getString("BadgeNumber", R.string.BadgeNumber), preferences.getBoolean("badgeNumber", true), true); } else if (i == inchatSoundRow) { @@ -860,13 +888,13 @@ public class NotificationsSettingsActivity extends BaseFragment implements Notif return 0; } else if (i == messageAlertRow || i == messagePreviewRow || i == groupAlertRow || i == groupPreviewRow || i == inappSoundRow || i == inappVibrateRow || - i == inappPreviewRow || i == contactJoinedRow || + i == inappPreviewRow || i == contactJoinedRow || i == pinnedMessageRow || i == notificationsServiceRow || i == badgeNumberRow || i == inappPriorityRow || - i == inchatSoundRow || i == androidAutoAlertRow) { + i == inchatSoundRow || i == androidAutoAlertRow || i == notificationsServiceConnectionRow) { return 1; } else if (i == messageLedRow || i == groupLedRow) { return 3; - } else if (i == messageSectionRow2 || i == eventsSectionRow2 || i == groupSectionRow2 || + } else if (i == eventsSectionRow2 || i == groupSectionRow2 || i == inappSectionRow2 || i == otherSectionRow2 || i == resetSectionRow2) { return 4; } else { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PasscodeActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PasscodeActivity.java index db15a693..f3e0d32a 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PasscodeActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PasscodeActivity.java @@ -56,6 +56,7 @@ import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.BaseFragmentAdapter; import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; @@ -262,7 +263,7 @@ public class PasscodeActivity extends BaseFragment implements NotificationCenter } if (type == 1) { - dropDownContainer = new ActionBarMenuItem(context, menu, R.drawable.bar_selector); + dropDownContainer = new ActionBarMenuItem(context, menu, 0); dropDownContainer.setSubMenuOpenSide(1); dropDownContainer.addSubItem(pin_item, LocaleController.getString("PasscodePIN", R.string.PasscodePIN), 0); dropDownContainer.addSubItem(password_item, LocaleController.getString("PasscodePassword", R.string.PasscodePassword), 0); @@ -371,7 +372,7 @@ public class PasscodeActivity extends BaseFragment implements NotificationCenter @Override public String format(int value) { if (value == 0) { - return LocaleController.getString("Disabled", R.string.Disabled); + return LocaleController.getString("AutoLockDisabled", R.string.AutoLockDisabled); } else if (value == 1) { return LocaleController.formatString("AutoLockInTime", R.string.AutoLockInTime, LocaleController.formatPluralString("Minutes", 1)); } else if (value == 2) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoAlbumPickerActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoAlbumPickerActivity.java index 8be4e8e4..12310daf 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoAlbumPickerActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoAlbumPickerActivity.java @@ -37,6 +37,7 @@ import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.BaseFragmentAdapter; import org.telegram.ui.Cells.PhotoPickerAlbumsCell; import org.telegram.ui.Cells.PhotoPickerSearchCell; @@ -116,8 +117,8 @@ public class PhotoAlbumPickerActivity extends BaseFragment implements Notificati @SuppressWarnings("unchecked") @Override public View createView(Context context) { - actionBar.setBackgroundColor(0xff333333); - actionBar.setItemsBackground(R.drawable.bar_selector_picker); + actionBar.setBackgroundColor(Theme.ACTION_BAR_MEDIA_PICKER_COLOR); + actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_PICKER_SELECTOR_COLOR); actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override @@ -165,7 +166,7 @@ public class PhotoAlbumPickerActivity extends BaseFragment implements Notificati if (!singlePhoto) { selectedMode = 0; - dropDownContainer = new ActionBarMenuItem(context, menu, R.drawable.bar_selector_picker); + dropDownContainer = new ActionBarMenuItem(context, menu, 0); dropDownContainer.setSubMenuOpenSide(1); dropDownContainer.addSubItem(item_photos, LocaleController.getString("PickerPhotos", R.string.PickerPhotos), 0); dropDownContainer.addSubItem(item_video, LocaleController.getString("PickerVideo", R.string.PickerVideo), 0); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java index f51a2ebb..b3d8d659 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoCropActivity.java @@ -15,7 +15,6 @@ import android.graphics.Paint; import android.graphics.drawable.BitmapDrawable; import android.net.Uri; import android.os.Bundle; -import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; @@ -29,6 +28,7 @@ import org.telegram.messenger.R; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.LayoutHelper; import java.io.File; @@ -58,16 +58,6 @@ public class PhotoCropActivity extends BaseFragment { init(); } - public PhotoCropView(Context context, AttributeSet attrs) { - super(context, attrs); - init(); - } - - public PhotoCropView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(); - } - private void init() { rectPaint = new Paint(); rectPaint.setColor(0x3ffafafa); @@ -428,8 +418,8 @@ public class PhotoCropActivity extends BaseFragment { @Override public View createView(Context context) { - actionBar.setBackgroundColor(0xff333333); - actionBar.setItemsBackground(R.drawable.bar_selector_picker); + actionBar.setBackgroundColor(Theme.ACTION_BAR_MEDIA_PICKER_COLOR); + actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_PICKER_SELECTOR_COLOR); actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); actionBar.setTitle(LocaleController.getString("CropImage", R.string.CropImage)); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java index 2b50cfa6..63fc2d0e 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoPickerActivity.java @@ -62,6 +62,7 @@ import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.BaseFragmentAdapter; import org.telegram.ui.Cells.PhotoPickerPhotoCell; import org.telegram.ui.Components.BackupImageView; @@ -78,7 +79,9 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen public interface PhotoPickerActivityDelegate { void selectedPhotosChanged(); + void actionButtonPressed(boolean canceled); + boolean didSelectVideo(String path); } @@ -159,8 +162,8 @@ public class PhotoPickerActivity extends BaseFragment implements NotificationCen @SuppressWarnings("unchecked") @Override public View createView(Context context) { - actionBar.setBackgroundColor(0xff333333); - actionBar.setItemsBackground(R.drawable.bar_selector_picker); + actionBar.setBackgroundColor(Theme.ACTION_BAR_MEDIA_PICKER_COLOR); + actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_PICKER_SELECTOR_COLOR); actionBar.setBackButtonImage(R.drawable.ic_ab_back); if (selectedAlbum != null) { actionBar.setTitle(selectedAlbum.bucketName); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java index 15313755..ecc5fcba 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PhotoViewer.java @@ -32,8 +32,11 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.Browser; +import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.util.TypedValue; +import android.view.ActionMode; +import android.view.ContextThemeWrapper; import android.view.GestureDetector; import android.view.Gravity; import android.view.KeyEvent; @@ -56,6 +59,7 @@ import org.telegram.messenger.AnimationCompat.AnimatorSetProxy; import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; import org.telegram.messenger.AnimationCompat.ViewProxy; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.Emoji; import org.telegram.messenger.FileLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.ImageLoader; @@ -77,6 +81,7 @@ import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.MentionsAdapter; import org.telegram.ui.Components.CheckBox; import org.telegram.ui.Components.ClippingImageView; @@ -103,6 +108,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private boolean isVisible; private Activity parentActivity; + private Context actvityContext; private ActionBar actionBar; private boolean isActionBarVisible = true; @@ -183,19 +189,20 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private boolean draggingDown = false; private float dragY; - private float translationX = 0; - private float translationY = 0; + private float translationX; + private float translationY; private float scale = 1; private float animateToX; private float animateToY; private float animateToScale; private float animationValue; + private int currentRotation; private long animationStartTime; private AnimatorSetProxy imageMoveAnimation; private AnimatorSetProxy changeModeAnimation; private GestureDetector gestureDetector; private DecelerateInterpolator interpolator = new DecelerateInterpolator(1.5f); - private float pinchStartDistance = 0; + private float pinchStartDistance; private float pinchStartScale = 1; private float pinchCenterX; private float pinchCenterY; @@ -244,6 +251,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat private static DecelerateInterpolator decelerateInterpolator = null; private static Paint progressPaint = null; + private static int iconColor; + private class BackgroundDrawable extends ColorDrawable { private Runnable drawRunnable; @@ -295,7 +304,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG); progressPaint.setStyle(Paint.Style.STROKE); progressPaint.setStrokeCap(Paint.Cap.ROUND); - progressPaint.setStrokeWidth(AndroidUtilities.dp(2)); + progressPaint.setStrokeWidth(AndroidUtilities.dp(3)); progressPaint.setColor(0xffffffff); } parent = parentView; @@ -390,7 +399,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (backgroundState == 0 || backgroundState == 1 || previousBackgroundState == 0 || previousBackgroundState == 1) { - int diff = AndroidUtilities.dp(1); + int diff = AndroidUtilities.dp(4); if (previousBackgroundState != -2) { progressPaint.setAlpha((int) (255 * animatedAlphaValue * alpha)); } else { @@ -887,6 +896,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return; } parentActivity = activity; + actvityContext = new ContextThemeWrapper(parentActivity, R.style.Theme_TMessages); if (progressDrawables == null) { progressDrawables = new Drawable[4]; @@ -912,9 +922,27 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } return super.dispatchKeyEventPreIme(event); } + + @Override + public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback, int type) { + if (Build.VERSION.SDK_INT >= 23) { + View view = parentActivity.findViewById(android.R.id.content); + if (view instanceof ViewGroup) { + try { + return ((ViewGroup) view).startActionModeForChild(originalView, callback, type); + } catch (Throwable e) { + FileLog.e("tmessages", e); + } + } + } + return super.startActionModeForChild(originalView, callback, type); + } }; windowView.setBackgroundDrawable(backgroundDrawable); windowView.setFocusable(false); + if (Build.VERSION.SDK_INT >= 23) { + windowView.setFitsSystemWindows(true); + } animatingImageView = new ClippingImageView(activity); animatingImageView.setAnimationValues(animationValues); @@ -933,7 +961,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; actionBar = new ActionBar(activity); - //actionBar.setBackgroundColor(0x7F000000); + //actionBar.setBackgroundColor(Theme.ACTION_BAR_PHOTO_VIEWER_COLOR); SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); @@ -961,7 +989,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat actionBar.setBackgroundDrawable(gd); } actionBar.setOccupyStatusBar(false); - actionBar.setItemsBackground(R.drawable.bar_selector_white); + actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR); //actionBar.setBackButtonImage(R.drawable.ic_ab_back); Drawable back = parentActivity.getResources().getDrawable(R.drawable.ic_ab_back); int iconsColor = themePrefs.getInt("chatHeaderIconsColor", 0xffffffff); @@ -994,7 +1022,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (f != null && f.exists()) { - MediaController.saveFile(f.toString(), parentActivity, currentFileNames[0].endsWith("mp4") ? 1 : 0, null); + MediaController.saveFile(f.toString(), parentActivity, currentMessageObject != null && currentMessageObject.isVideo() ? 1 : 0, null, null); } else { AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); @@ -1054,7 +1082,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return; } AlertDialog.Builder builder = new AlertDialog.Builder(parentActivity); - if (currentFileNames[0] != null && currentFileNames[0].endsWith("mp4")) { + if (currentMessageObject != null && currentMessageObject.isVideo()) { builder.setMessage(LocaleController.formatString("AreYouSureDeleteVideo", R.string.AreYouSureDeleteVideo)); } else { builder.setMessage(LocaleController.formatString("AreYouSureDeletePhoto", R.string.AreYouSureDeletePhoto)); @@ -1178,10 +1206,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat ActionBarMenu menu = actionBar.createMenu(); - //menuItem = menu.addItem(0, R.drawable.ic_ab_other); - Drawable dots = parentActivity.getResources().getDrawable(R.drawable.ic_ab_other); - dots.setColorFilter(AndroidUtilities.getIntDef("chatHeaderIconsColor", 0xffffffff), PorterDuff.Mode.MULTIPLY); - menuItem = menu.addItem(0, dots); + menuItem = menu.addItem(0, R.drawable.ic_ab_other); + //Drawable dots = parentActivity.getResources().getDrawable(R.drawable.ic_ab_other); + //dots.setColorFilter(iconColor, PorterDuff.Mode.MULTIPLY); + //menuItem = menu.addItem(0, dots); menuItem.addSubItem(gallery_menu_showall, LocaleController.getString("ShowAllMedia", R.string.ShowAllMedia), 0); menuItem.addSubItem(gallery_menu_save, LocaleController.getString("SaveToGallery", R.string.SaveToGallery), 0); menuItem.addSubItem(gallery_menu_delete, LocaleController.getString("Delete", R.string.Delete), 0); @@ -1191,11 +1219,30 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat cropItem = menu.addItemWithWidth(gallery_menu_crop, R.drawable.photo_crop, AndroidUtilities.dp(56)); tuneItem = menu.addItemWithWidth(gallery_menu_tune, R.drawable.photo_tools, AndroidUtilities.dp(56)); - bottomLayout = new FrameLayout(parentActivity); + iconColor = themePrefs.getInt("chatHeaderIconsColor", 0xffffffff); + menuItem.setIconColor(iconColor); + captionDoneItem.setIconColor(iconColor); + captionItem.setIconColor(iconColor); + cropItem.setIconColor(iconColor); + tuneItem.setIconColor(iconColor); + //Drawable done = parentActivity.getResources().getDrawable(R.drawable.ic_done); + //Drawable photoText = parentActivity.getResources().getDrawable(R.drawable.photo_text); + //Drawable photoCrop = parentActivity.getResources().getDrawable(R.drawable.photo_crop); + //Drawable photoTools = parentActivity.getResources().getDrawable(R.drawable.photo_tools); + //done.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + //photoText.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + //photoCrop.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + //photoTools.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN); + //captionDoneItem = menu.addItemWithWidth(gallery_menu_caption_done, done, AndroidUtilities.dp(56)); + //captionItem = menu.addItemWithWidth(gallery_menu_caption, photoText, AndroidUtilities.dp(56)); + //cropItem = menu.addItemWithWidth(gallery_menu_crop, photoCrop, AndroidUtilities.dp(56)); + //tuneItem = menu.addItemWithWidth(gallery_menu_tune, photoTools, AndroidUtilities.dp(56)); + + bottomLayout = new FrameLayout(actvityContext); bottomLayout.setBackgroundColor(0x7f000000); containerView.addView(bottomLayout, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT)); - captionTextViewOld = new TextView(parentActivity); + captionTextViewOld = new TextView(actvityContext); captionTextViewOld.setMaxLines(10); captionTextViewOld.setBackgroundColor(0x7f000000); captionTextViewOld.setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(8), AndroidUtilities.dp(16), AndroidUtilities.dp(8)); @@ -1206,7 +1253,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat captionTextViewOld.setVisibility(View.INVISIBLE); containerView.addView(captionTextViewOld, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, 48)); - captionTextView = captionTextViewNew = new TextView(parentActivity); + captionTextView = captionTextViewNew = new TextView(actvityContext); captionTextViewNew.setMaxLines(10); captionTextViewNew.setBackgroundColor(0x7f000000); captionTextViewNew.setPadding(AndroidUtilities.dp(16), AndroidUtilities.dp(8), AndroidUtilities.dp(16), AndroidUtilities.dp(8)); @@ -1227,7 +1274,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat shareButton = new ImageView(containerView.getContext()); shareButton.setImageResource(R.drawable.share); shareButton.setScaleType(ImageView.ScaleType.CENTER); - shareButton.setBackgroundResource(R.drawable.bar_selector_white); + shareButton.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); bottomLayout.addView(shareButton, LayoutHelper.createFrame(50, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.RIGHT)); shareButton.setOnClickListener(new View.OnClickListener() { @Override @@ -1237,15 +1284,14 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } try { File f = null; + boolean isVideo = false; if (currentMessageObject != null) { - if (currentMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { - Uri uri = Uri.parse(currentMessageObject.messageOwner.media.webpage.url); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, parentActivity.getPackageName()); - parentActivity.startActivity(intent); + isVideo = currentMessageObject.isVideo(); + /*if (currentMessageObject.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { + AndroidUtilities.openUrl(parentActivity, currentMessageObject.messageOwner.media.webpage.url); return; - } + }*/ f = FileLoader.getPathToMessage(currentMessageObject.messageOwner); } else if (currentFileLocation != null) { f = FileLoader.getPathToAttach(currentFileLocation, avatarsUserId != 0); @@ -1253,7 +1299,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (f.exists()) { Intent intent = new Intent(Intent.ACTION_SEND); - if (f.toString().endsWith("mp4")) { + if (isVideo) { intent.setType("video/mp4"); } else { intent.setType("image/jpeg"); @@ -1294,7 +1340,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat dateTextView.setGravity(Gravity.LEFT); bottomLayout.addView(dateTextView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.TOP | Gravity.LEFT, 16, 25, 50, 0)); - pickerView = new PickerBottomLayout(parentActivity); + pickerView = new PickerBottomLayout(actvityContext); pickerView.setBackgroundColor(0x7f000000); containerView.addView(pickerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 48, Gravity.BOTTOM | Gravity.LEFT)); pickerView.cancelButton.setOnClickListener(new View.OnClickListener() { @@ -1315,7 +1361,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } }); - editorDoneLayout = new PickerBottomLayout(parentActivity); + editorDoneLayout = new PickerBottomLayout(actvityContext); editorDoneLayout.setBackgroundColor(0x7f000000); editorDoneLayout.updateSelectedCount(0, false); editorDoneLayout.setVisibility(View.GONE); @@ -1343,6 +1389,20 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } }); + ImageView rotateButton = new ImageView(actvityContext); + rotateButton.setScaleType(ImageView.ScaleType.CENTER); + rotateButton.setImageResource(R.drawable.tool_rotate); + rotateButton.setBackgroundDrawable(Theme.createBarSelectorDrawable(Theme.ACTION_BAR_WHITE_SELECTOR_COLOR)); + editorDoneLayout.addView(rotateButton, LayoutHelper.createFrame(48, 48, Gravity.CENTER)); + rotateButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + centerImage.setOrientation(centerImage.getOrientation() - 90, false); + photoCropView.setOrientation(centerImage.getOrientation()); + containerView.invalidate(); + } + }); + gestureDetector = new GestureDetector(containerView.getContext(), this); gestureDetector.setOnDoubleTapListener(this); @@ -1377,7 +1437,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } }); - captionEditText = new PhotoViewerCaptionEnterView(parentActivity, containerView); + captionEditText = new PhotoViewerCaptionEnterView(actvityContext, containerView, windowView); captionEditText.setDelegate(new PhotoViewerCaptionEnterView.PhotoViewerCaptionEnterViewDelegate() { @Override public void onCaptionEnter() { @@ -1411,8 +1471,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat }); containerView.addView(captionEditText, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.WRAP_CONTENT, Gravity.BOTTOM | Gravity.LEFT, 0, 0, 0, -400)); - mentionListView = new RecyclerListView(parentActivity); - mentionLayoutManager = new LinearLayoutManager(parentActivity) { + mentionListView = new RecyclerListView(actvityContext); + mentionLayoutManager = new LinearLayoutManager(actvityContext) { @Override public boolean supportsPredictiveItemAnimations() { return false; @@ -1423,12 +1483,10 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat mentionListView.setBackgroundColor(0x7f000000); mentionListView.setVisibility(View.GONE); mentionListView.setClipToPadding(true); - if (Build.VERSION.SDK_INT > 8) { mentionListView.setOverScrollMode(ListView.OVER_SCROLL_NEVER); - } containerView.addView(mentionListView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 110, Gravity.LEFT | Gravity.BOTTOM)); - mentionListView.setAdapter(mentionsAdapter = new MentionsAdapter(parentActivity, true, new MentionsAdapter.MentionsAdapterDelegate() { + mentionListView.setAdapter(mentionsAdapter = new MentionsAdapter(actvityContext, true, 0, new MentionsAdapter.MentionsAdapterDelegate() { @Override public void needChangePanelVisibility(boolean show) { if (show) { @@ -1807,7 +1865,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat imageMoveAnimation.start(); } else if (mode == 1) { if (photoCropView == null) { - photoCropView = new PhotoCropView(parentActivity); + photoCropView = new PhotoCropView(actvityContext); photoCropView.setVisibility(View.GONE); containerView.addView(photoCropView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 48)); photoCropView.setDelegate(new PhotoCropView.PhotoCropViewDelegate() { @@ -1822,6 +1880,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat containerView.invalidate(); } } + + @Override + public Bitmap getBitmap() { + return centerImage.getBitmap(); + } }); } @@ -2111,23 +2174,17 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat return null; } if (!imagesArrLocations.isEmpty() || !imagesArr.isEmpty()) { - TLRPC.InputFileLocation file = getInputFileLocation(index); - if (file == null) { + if (!imagesArrLocations.isEmpty()) { + if (index >= imagesArrLocations.size()) { return null; } - if (!imagesArrLocations.isEmpty()) { - return file.volume_id + "_" + file.local_id + ".jpg"; + TLRPC.FileLocation location = imagesArrLocations.get(index); + return location.volume_id + "_" + location.local_id + ".jpg"; } else if (!imagesArr.isEmpty()) { - MessageObject message = imagesArr.get(index); - if (message.messageOwner instanceof TLRPC.TL_messageService) { - return file.volume_id + "_" + file.local_id + ".jpg"; - } else if (message.messageOwner.media != null) { - if (message.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { - return file.volume_id + "_" + file.id + ".mp4"; - } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || message.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { - return file.volume_id + "_" + file.local_id + ".jpg"; - } + if (index >= imagesArr.size()) { + return null; } + return FileLoader.getMessageFileName(imagesArr.get(index).messageOwner); } } else if (!imagesArrLocals.isEmpty()) { if (index >= imagesArrLocals.size()) { @@ -2146,7 +2203,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat searchImage.localUrl = ""; } } - return Utilities.MD5(searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.imageUrl); + return Utilities.MD5(searchImage.imageUrl) + "." + ImageLoader.getHttpUrlExtension(searchImage.imageUrl, "jpg"); } } return null; @@ -2193,72 +2250,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } else { size[0] = -1; } - } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaVideo && message.messageOwner.media.video != null && message.messageOwner.media.video.thumb != null) { - size[0] = message.messageOwner.media.video.thumb.size; + } else if (message.getDocument() != null && message.getDocument().thumb != null) { + size[0] = message.getDocument().thumb.size; if (size[0] == 0) { size[0] = -1; } - return message.messageOwner.media.video.thumb.location; - } - } - return null; - } - - private TLRPC.InputFileLocation getInputFileLocation(int index) { - if (index < 0) { - return null; - } - if (!imagesArrLocations.isEmpty()) { - if (index >= imagesArrLocations.size()) { - return null; - } - TLRPC.FileLocation sizeFull = imagesArrLocations.get(index); - TLRPC.TL_inputFileLocation location = new TLRPC.TL_inputFileLocation(); - location.local_id = sizeFull.local_id; - location.volume_id = sizeFull.volume_id; - location.id = sizeFull.dc_id; - location.secret = sizeFull.secret; - return location; - } else if (!imagesArr.isEmpty()) { - if (index >= imagesArr.size()) { - return null; - } - MessageObject message = imagesArr.get(index); - if (message.messageOwner instanceof TLRPC.TL_messageService) { - if (message.messageOwner.action instanceof TLRPC.TL_messageActionUserUpdatedPhoto) { - TLRPC.FileLocation sizeFull = message.messageOwner.action.newUserPhoto.photo_big; - TLRPC.TL_inputFileLocation location = new TLRPC.TL_inputFileLocation(); - location.local_id = sizeFull.local_id; - location.volume_id = sizeFull.volume_id; - location.id = sizeFull.dc_id; - location.secret = sizeFull.secret; - return location; - } else { - TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize()); - if (sizeFull != null) { - TLRPC.TL_inputFileLocation location = new TLRPC.TL_inputFileLocation(); - location.local_id = sizeFull.location.local_id; - location.volume_id = sizeFull.location.volume_id; - location.id = sizeFull.location.dc_id; - location.secret = sizeFull.location.secret; - return location; - } - } - } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaPhoto || message.messageOwner.media instanceof TLRPC.TL_messageMediaWebPage) { - TLRPC.PhotoSize sizeFull = FileLoader.getClosestPhotoSizeWithSize(message.photoThumbs, AndroidUtilities.getPhotoSize()); - if (sizeFull != null) { - TLRPC.TL_inputFileLocation location = new TLRPC.TL_inputFileLocation(); - location.local_id = sizeFull.location.local_id; - location.volume_id = sizeFull.location.volume_id; - location.id = sizeFull.location.dc_id; - location.secret = sizeFull.location.secret; - return location; - } - } else if (message.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { - TLRPC.TL_inputVideoFileLocation location = new TLRPC.TL_inputVideoFileLocation(); - location.volume_id = message.messageOwner.media.video.dc_id; - location.id = message.messageOwner.media.video.id; - return location; + return message.getDocument().thumb.location; } } return null; @@ -2390,7 +2387,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat canShowBottom = false; Object obj = imagesArrLocals.get(index); cropItem.setVisibility(obj instanceof MediaController.PhotoEntry || obj instanceof MediaController.SearchImage && ((MediaController.SearchImage) obj).type == 0 ? View.VISIBLE : View.GONE); - if (parentChatActivity != null && parentChatActivity.currentEncryptedChat == null) { + if (parentChatActivity != null && (parentChatActivity.currentEncryptedChat == null || AndroidUtilities.getPeerLayerVersion(parentChatActivity.currentEncryptedChat.layer) >= 46)) { mentionsAdapter.setChatInfo(parentChatActivity.info); mentionsAdapter.setNeedUsernames(parentChatActivity.currentChat != null); mentionsAdapter.setNeedBotContext(false); @@ -2438,7 +2435,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat placeProvider.willSwitchFromPhoto(currentMessageObject, currentFileLocation, currentIndex); int prevIndex = currentIndex; currentIndex = index; - + boolean isVideo = false; boolean sameImage = false; if (!imagesArr.isEmpty()) { @@ -2446,13 +2443,16 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat closePhoto(false, false); return; } - currentMessageObject = imagesArr.get(currentIndex); + MessageObject newMessageObject = imagesArr.get(currentIndex); + sameImage = currentMessageObject != null && currentMessageObject.getId() == newMessageObject.getId(); + currentMessageObject = newMessageObject; + isVideo = currentMessageObject.isVideo(); if (currentMessageObject.canDeleteMessage(null)) { menuItem.showSubItem(gallery_menu_delete); } else { menuItem.hideSubItem(gallery_menu_delete); } - if (currentMessageObject.messageOwner.from_id > 0) { + if (currentMessageObject.isFromUser()) { TLRPC.User user = MessagesController.getInstance().getUser(currentMessageObject.messageOwner.from_id); if (user != null) { nameTextView.setText(UserObject.getUserName(user)); @@ -2460,7 +2460,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat nameTextView.setText(""); } } else { - TLRPC.Chat chat = MessagesController.getInstance().getChat(-currentMessageObject.messageOwner.from_id); + TLRPC.Chat chat = MessagesController.getInstance().getChat(currentMessageObject.messageOwner.to_id.channel_id); if (chat != null) { nameTextView.setText(chat.title); } else { @@ -2469,8 +2469,8 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } long date = (long) currentMessageObject.messageOwner.date * 1000; String dateString = LocaleController.formatString("formatDateAtTime", R.string.formatDateAtTime, LocaleController.getInstance().formatterYear.format(new Date(date)), LocaleController.getInstance().formatterDay.format(new Date(date))); - if (currentFileNames[0] != null && currentFileNames[0].endsWith("mp4")) { - dateTextView.setText(String.format("%s (%s)", dateString, AndroidUtilities.formatFileSize(currentMessageObject.messageOwner.media.video.size))); + if (currentFileNames[0] != null && isVideo) { + dateTextView.setText(String.format("%s (%s)", dateString, AndroidUtilities.formatFileSize(currentMessageObject.getDocument().size))); } else { dateTextView.setText(dateString); } @@ -2617,7 +2617,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat canDragDown = true; changingPage = false; switchImageAfterAnimation = 0; - canZoom = !imagesArrLocals.isEmpty() || (currentFileNames[0] != null && !currentFileNames[0].endsWith("mp4") && radialProgressViews[0].backgroundState != 0); + canZoom = !imagesArrLocals.isEmpty() || (currentFileNames[0] != null && !isVideo && radialProgressViews[0].backgroundState != 0); updateMinMax(scale); } @@ -2666,8 +2666,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat captionTextViewNew = captionTextView; captionItem.setIcon(R.drawable.photo_text2); - captionTextView.setTag(caption); - captionTextView.setText(caption); + CharSequence str = Emoji.replaceEmoji(new SpannableStringBuilder(caption.toString()), MessageObject.getTextPaint().getFontMetricsInt(), AndroidUtilities.dp(20), false); + captionTextView.setTag(str); + captionTextView.setText(str); ViewProxy.setAlpha(captionTextView, bottomLayout.getVisibility() == View.VISIBLE || pickerView.getVisibility() == View.VISIBLE ? 1.0f : 0.0f); AndroidUtilities.runOnUIThread(new Runnable() { @Override @@ -2680,6 +2681,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat }); } else { captionItem.setIcon(R.drawable.photo_text); + captionItem.setIconColor(iconColor); captionTextView.setTag(null); captionTextView.clearAnimation(); captionTextView.setVisibility(View.INVISIBLE); @@ -2695,9 +2697,11 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat index -= 1; } File f = null; + boolean isVideo = false; if (currentMessageObject != null) { MessageObject messageObject = imagesArr.get(index); f = FileLoader.getPathToMessage(messageObject.messageOwner); + isVideo = messageObject.isVideo(); } else if (currentFileLocation != null) { TLRPC.FileLocation location = imagesArrLocations.get(index); f = FileLoader.getPathToAttach(location, avatarsUserId != 0); @@ -2708,13 +2712,13 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } } if (f != null && f.exists()) { - if (currentPathObject == null && currentFileNames[a].endsWith("mp4")) { + if (isVideo) { radialProgressViews[a].setBackgroundState(3, animated); } else { radialProgressViews[a].setBackgroundState(-1, animated); } } else { - if (currentPathObject == null && currentFileNames[a].endsWith("mp4")) { + if (isVideo) { if (!FileLoader.getInstance().isLoadingFile(currentFileNames[a])) { radialProgressViews[a].setBackgroundState(2, false); } else { @@ -2730,7 +2734,7 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat radialProgressViews[a].setProgress(progress, false); } if (a == 0) { - canZoom = !imagesArrLocals.isEmpty() || (currentFileNames[0] != null && !currentFileNames[0].endsWith("mp4") && radialProgressViews[0].backgroundState != 0); + canZoom = !imagesArrLocals.isEmpty() || (currentFileNames[0] != null && !isVideo && radialProgressViews[0].backgroundState != 0); } } else { radialProgressViews[a].setBackgroundState(-1, animated); @@ -2799,9 +2803,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat imageReceiver.setShouldGenerateQualityThumb(true); } - if (messageObject != null && messageObject.messageOwner.media instanceof TLRPC.TL_messageMediaVideo) { + if (messageObject != null && messageObject.isVideo()) { imageReceiver.setNeedsQualityThumb(true); - if (messageObject.messageOwner.media.video.thumb != null) { + if (messageObject.photoThumbs != null && !messageObject.photoThumbs.isEmpty()) { Bitmap placeHolder = null; if (currentThumb != null && imageReceiver == centerImage) { placeHolder = currentThumb; @@ -3057,16 +3061,12 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } }); } - - @Override - public void onAnimationCancel(Object animation) { - onAnimationEnd(animation); - } }); transitionAnimationStartTime = System.currentTimeMillis(); AndroidUtilities.runOnUIThread(new Runnable() { @Override public void run() { + NotificationCenter.getInstance().setAllowedNotificationsDutingAnimation(new int[]{NotificationCenter.dialogsNeedReload, NotificationCenter.closeChats, NotificationCenter.mediaCountDidLoaded, NotificationCenter.mediaDidLoaded}); NotificationCenter.getInstance().setAnimationInProgress(true); animatorSet.start(); } @@ -3128,6 +3128,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat if (parentActivity == null || !isVisible || checkAnimation() || placeProvider == null) { return; } + if (captionEditText.hideActionMode() && !fromEditMode) { + return; + } captionEditText.onDestroy(); parentChatActivity = null; @@ -3262,11 +3265,6 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } }); } - - @Override - public void onAnimationCancel(Object animation) { - onAnimationEnd(animation); - } }); transitionAnimationStartTime = System.currentTimeMillis(); if (Build.VERSION.SDK_INT >= 18) { @@ -4000,9 +3998,9 @@ public class PhotoViewer implements NotificationCenter.NotificationCenterDelegat } if (loadFile) { if (!FileLoader.getInstance().isLoadingFile(currentFileNames[0])) { - FileLoader.getInstance().loadFile(currentMessageObject.messageOwner.media.video, true); + FileLoader.getInstance().loadFile(currentMessageObject.getDocument(), true, false); } else { - FileLoader.getInstance().cancelLoadFile(currentMessageObject.messageOwner.media.video); + FileLoader.getInstance().cancelLoadFile(currentMessageObject.getDocument()); } } } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PlusSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PlusSettingsActivity.java new file mode 100644 index 00000000..784b5975 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/PlusSettingsActivity.java @@ -0,0 +1,1356 @@ +package org.telegram.ui; + +/** + * Created by Sergio on 22/01/2016. + */ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.res.Configuration; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.widget.AdapterView; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ListView; +import android.widget.Toast; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.BuildVars; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Adapters.BaseFragmentAdapter; +import org.telegram.ui.Cells.EmptyCell; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextCheckCell; +import org.telegram.ui.Cells.TextDetailSettingsCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Cells.TextSettingsCell; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.NumberPicker; + +import java.io.File; +import java.util.ArrayList; + +public class PlusSettingsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + private ListView listView; + private ListAdapter listAdapter; + + private int overscrollRow; + private int emptyRow; + + private int settingsSectionRow; + private int settingsSectionRow2; + + private int mediaDownloadSection; + private int mediaDownloadSection2; + + private int drawerSectionRow; + private int drawerSectionRow2; + private int showUsernameRow; + + private int messagesSectionRow; + private int messagesSectionRow2; + + private int profileSectionRow; + private int profileSectionRow2; + private int profileSharedOptionsRow; + + private int notificationSectionRow; + private int notificationSection2Row; + private int notificationInvertMessagesOrderRow; + + private int privacySectionRow; + private int privacySectionRow2; + private int hideMobileNumberRow; + + private int rowCount; + private int disableMessageClickRow; + private int showAndroidEmojiRow; + private int useDeviceFontRow; + private int keepOriginalFilenameRow; + private int keepOriginalFilenameDetailRow; + private int emojiPopupSize; + private int disableAudioStopRow; + private int dialogsSectionRow; + private int dialogsSectionRow2; + private int dialogsPicClickRow; + private int dialogsGroupPicClickRow; + private int dialogsHideTabsCheckRow; + private int dialogsTabsHeightRow; + private int dialogsTabsRow; + private int dialogsDisableTabsAnimationCheckRow; + private int dialogsInfiniteTabsSwipe; + private int chatShowDirectShareBtn; + private int dialogsHideTabsCounters; + private int dialogsTabsCountersCountChats; + private int dialogsTabsCountersCountNotMuted; + private int chatDirectShareToMenu; + private int chatDirectShareReplies; + private int chatDirectShareFavsFirst; + private int chatShowEditedMarkRow; + private int chatShowDateToastRow; + private int chatHideLeftGroupRow; + private int chatHideJoinedGroupRow; + private int chatHideBotKeyboardRow; + private int chatSearchUserOnTwitterRow; + + private int plusSettingsSectionRow; + private int plusSettingsSectionRow2; + private int savePlusSettingsRow; + private int restorePlusSettingsRow; + private int resetPlusSettingsRow; + + private boolean reseting = false; + private boolean saving = false; + + @Override + public boolean onFragmentCreate() { + super.onFragmentCreate(); + + NotificationCenter.getInstance().addObserver(this, NotificationCenter.refreshTabs); + + rowCount = 0; + overscrollRow = -1; + emptyRow = -1; + + settingsSectionRow = rowCount++; + settingsSectionRow2 = rowCount++; + + if (android.os.Build.VERSION.SDK_INT >= 19) { // Only enable this option for Kitkat and newer android versions + showAndroidEmojiRow = rowCount++; + } else { + showAndroidEmojiRow = -1; + } + useDeviceFontRow = rowCount++; + + messagesSectionRow = rowCount++; + messagesSectionRow2 = rowCount++; + + emojiPopupSize = rowCount++; + + disableAudioStopRow = rowCount++; + disableMessageClickRow = rowCount++; + chatShowDirectShareBtn = rowCount++; + chatDirectShareReplies = rowCount++; + chatDirectShareToMenu = rowCount++; + chatDirectShareFavsFirst = rowCount++; + chatShowEditedMarkRow = rowCount++; + chatHideLeftGroupRow = rowCount++; + chatHideJoinedGroupRow = -1; + chatHideBotKeyboardRow = rowCount++; + chatShowDateToastRow = rowCount++; + chatSearchUserOnTwitterRow = rowCount++; + + dialogsSectionRow = rowCount++; + dialogsSectionRow2 = rowCount++; + + dialogsHideTabsCheckRow = rowCount++; + dialogsTabsRow = rowCount++; + dialogsTabsHeightRow = rowCount++; + dialogsDisableTabsAnimationCheckRow = rowCount++; + dialogsInfiniteTabsSwipe = rowCount++; + dialogsHideTabsCounters = rowCount++; + dialogsTabsCountersCountNotMuted = rowCount++; + dialogsTabsCountersCountChats = rowCount++; + + dialogsPicClickRow = rowCount++; + dialogsGroupPicClickRow = rowCount++; + + profileSectionRow = rowCount++; + profileSectionRow2 = rowCount++; + + profileSharedOptionsRow = rowCount++; + + drawerSectionRow = rowCount++; + drawerSectionRow2 = rowCount++; + showUsernameRow = rowCount++; + + notificationSectionRow = rowCount++; + notificationSection2Row = rowCount++; + notificationInvertMessagesOrderRow = rowCount++; + + privacySectionRow = rowCount++; + privacySectionRow2 = rowCount++; + hideMobileNumberRow = rowCount++; + + mediaDownloadSection = rowCount++; + mediaDownloadSection2 = rowCount++; + keepOriginalFilenameRow = rowCount++; + keepOriginalFilenameDetailRow = rowCount++; + + plusSettingsSectionRow = rowCount++; + plusSettingsSectionRow2 = rowCount++; + savePlusSettingsRow = rowCount++; + restorePlusSettingsRow = rowCount++; + resetPlusSettingsRow = rowCount++; + + MessagesController.getInstance().loadFullUser(UserConfig.getCurrentUser(), classGuid, true); + + return true; + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.refreshTabs); + } + + @Override + public View createView(Context context) { + //actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + + if (AndroidUtilities.isTablet()) { + actionBar.setOccupyStatusBar(false); + } + actionBar.setTitle(LocaleController.getString("PlusSettings", R.string.PlusSettings)); + + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + + listAdapter = new ListAdapter(context); + + fragmentView = new FrameLayout(context); + FrameLayout frameLayout = (FrameLayout) fragmentView; + + + listView = new ListView(context); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + listView.setBackgroundColor(preferences.getInt("prefBGColor", 0xffffffff)); + listView.setDivider(null); + listView.setDividerHeight(0); + listView.setVerticalScrollBarEnabled(false); + + listView.setAdapter(listAdapter); + + int bgColor = preferences.getInt("prefBGColor", 0xffffffff); + int def = preferences.getInt("themeColor", AndroidUtilities.defColor); + int hColor = preferences.getInt("prefHeaderColor", def); + + AndroidUtilities.setListViewEdgeEffectColor(listView, hColor); + frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); + listView.setAdapter(listAdapter); + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, final int i, long l) { + + if (i == emojiPopupSize) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("EmojiPopupSize", R.string.EmojiPopupSize)); + final NumberPicker numberPicker = new NumberPicker(getParentActivity()); + numberPicker.setMinValue(60); + numberPicker.setMaxValue(100); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + numberPicker.setValue(preferences.getInt("emojiPopupSize", AndroidUtilities.isTablet() ? 65 : 60)); + builder.setView(numberPicker); + builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("emojiPopupSize", numberPicker.getValue()); + editor.apply(); + if (listView != null) { + listView.invalidateViews(); + } + } + }); + showDialog(builder.create()); + } else if (i == showAndroidEmojiRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + boolean enabled = preferences.getBoolean("showAndroidEmoji", false); + editor.putBoolean("showAndroidEmoji", !enabled); + editor.apply(); + ApplicationLoader.SHOW_ANDROID_EMOJI = !enabled; + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!enabled); + } + } else if (i == useDeviceFontRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + boolean enabled = preferences.getBoolean("useDeviceFont", false); + editor.putBoolean("useDeviceFont", !enabled); + editor.apply(); + ApplicationLoader.USE_DEVICE_FONT = !enabled; + AndroidUtilities.needRestart = true; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (getParentActivity() != null) { + Toast toast = Toast.makeText(getParentActivity(), LocaleController.getString("AppWillRestart", R.string.AppWillRestart), Toast.LENGTH_SHORT); + toast.show(); + } + } + }); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!enabled); + } + } else if (i == disableAudioStopRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean send = preferences.getBoolean("disableAudioStop", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("disableAudioStop", !send); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!send); + } + } else if (i == disableMessageClickRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean send = preferences.getBoolean("disableMessageClick", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("disableMessageClick", !send); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!send); + } + } else if (i == chatDirectShareReplies) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean send = preferences.getBoolean("directShareReplies", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("directShareReplies", !send); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!send); + } + } else if (i == chatDirectShareToMenu) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean send = preferences.getBoolean("directShareToMenu", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("directShareToMenu", !send); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!send); + } + } else if (i == chatDirectShareFavsFirst) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean send = preferences.getBoolean("directShareFavsFirst", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("directShareFavsFirst", !send); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!send); + } + } else if (i == chatShowEditedMarkRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean send = preferences.getBoolean("showEditedMark", true); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("showEditedMark", !send); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!send); + } + } else if (i == chatShowDateToastRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean show = preferences.getBoolean("showDateToast", true); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("showDateToast", !show); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!show); + } + } else if (i == chatHideLeftGroupRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean hide = preferences.getBoolean("hideLeftGroup", false); + MessagesController.getInstance().hideLeftGroup = !hide; + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("hideLeftGroup", !hide); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!hide); + } + } else if (i == chatHideJoinedGroupRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean hide = preferences.getBoolean("hideJoinedGroup", false); + MessagesController.getInstance().hideJoinedGroup = !hide; + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("hideJoinedGroup", !hide); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!hide); + } + } else if (i == chatHideBotKeyboardRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean hide = preferences.getBoolean("hideBotKeyboard", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("hideBotKeyboard", !hide); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!hide); + } + } else if (i == dialogsHideTabsCheckRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean hide = preferences.getBoolean("hideTabs", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("hideTabs", !hide); + editor.apply(); + + boolean hideUsers = preferences.getBoolean("hideUsers", false); + boolean hideGroups = preferences.getBoolean("hideGroups", false); + boolean hideSGroups = preferences.getBoolean("hideSGroups", false); + boolean hideChannels = preferences.getBoolean("hideChannels", false); + boolean hideBots = preferences.getBoolean("hideBots", false); + boolean hideFavs = preferences.getBoolean("hideFavs", false); + if(hideUsers && hideGroups && hideSGroups && hideChannels && hideBots && hideFavs){ + //editor.putBoolean("hideUsers", false).apply(); + //editor.putBoolean("hideGroups", false).apply(); + if (listView != null) { + listView.invalidateViews(); + } + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.refreshTabs, 10); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!hide); + } + } else if (i == dialogsDisableTabsAnimationCheckRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean disable = preferences.getBoolean("disableTabsAnimation", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("disableTabsAnimation", !disable); + editor.apply(); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.refreshTabs, 11); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!disable); + } + } else if (i == dialogsInfiniteTabsSwipe) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean disable = preferences.getBoolean("infiniteTabsSwipe", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("infiniteTabsSwipe", !disable); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!disable); + } + } else if (i == dialogsHideTabsCounters) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean disable = preferences.getBoolean("hideTabsCounters", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("hideTabsCounters", !disable); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!disable); + } + } else if (i == dialogsTabsCountersCountChats) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean disable = preferences.getBoolean("tabsCountersCountChats", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("tabsCountersCountChats", !disable); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!disable); + } + } else if (i == dialogsTabsCountersCountNotMuted) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean disable = preferences.getBoolean("tabsCountersCountNotMuted", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("tabsCountersCountNotMuted", !disable); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!disable); + } + } else if (i == showUsernameRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean scr = preferences.getBoolean("showUsername", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("showUsername", !scr); + /*if(!scr){ + editor.putBoolean("hideMobile", true); + if (listView != null) { + listView.invalidateViews(); + } + }*/ + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!scr); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.mainUserInfoChanged); + } else if (i == hideMobileNumberRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean scr = preferences.getBoolean("hideMobile", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("hideMobile", !scr); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!scr); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.mainUserInfoChanged); + } else if (i == keepOriginalFilenameRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean keep = preferences.getBoolean("keepOriginalFilename", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("keepOriginalFilename", !keep); + editor.apply(); + ApplicationLoader.KEEP_ORIGINAL_FILENAME = !keep; + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!keep); + } + } else if (i == dialogsPicClickRow) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("ClickOnContactPic", R.string.ClickOnContactPic)); + builder.setItems(new CharSequence[]{ + LocaleController.getString("RowGradientDisabled", R.string.RowGradientDisabled), + LocaleController.getString("ShowPics", R.string.ShowPics), + LocaleController.getString("ShowProfile", R.string.ShowProfile) + }, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("dialogsClickOnPic", which); + editor.apply(); + if (listView != null) { + listView.invalidateViews(); + } + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } else if (i == dialogsGroupPicClickRow) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("ClickOnGroupPic", R.string.ClickOnGroupPic)); + builder.setItems(new CharSequence[]{ + LocaleController.getString("RowGradientDisabled", R.string.RowGradientDisabled), + LocaleController.getString("ShowPics", R.string.ShowPics), + LocaleController.getString("ShowProfile", R.string.ShowProfile) + }, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("dialogsClickOnGroupPic", which); + editor.apply(); + if (listView != null) { + listView.invalidateViews(); + } + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } else if (i == dialogsTabsHeightRow) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("TabsHeight", R.string.TabsHeight)); + final NumberPicker numberPicker = new NumberPicker(getParentActivity()); + numberPicker.setMinValue(30); + numberPicker.setMaxValue(48); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + numberPicker.setValue(preferences.getInt("tabsHeight", AndroidUtilities.isTablet() ? 42 : 40)); + builder.setView(numberPicker); + builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt("tabsHeight", numberPicker.getValue()); + editor.apply(); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.refreshTabs, 12); + if (listView != null) { + listView.invalidateViews(); + } + } + }); + showDialog(builder.create()); + } else if (i == dialogsTabsRow) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + createTabsDialog(builder); + builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + NotificationCenter.getInstance().postNotificationName(NotificationCenter.refreshTabs, 13); + if (listView != null) { + listView.invalidateViews(); + } + } + }); + showDialog(builder.create()); + } else if (i == profileSharedOptionsRow) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + createSharedOptions(builder); + builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + //NotificationCenter.getInstance().postNotificationName(NotificationCenter.refreshTabs, 13); + if (listView != null) { + listView.invalidateViews(); + } + } + }); + showDialog(builder.create()); + } else if (i == chatShowDirectShareBtn) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + createDialog(builder, chatShowDirectShareBtn); + builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (listView != null) { + listView.invalidateViews(); + } + } + }); + showDialog(builder.create()); + } else if (i == notificationInvertMessagesOrderRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean scr = preferences.getBoolean("invertMessagesOrder", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("invertMessagesOrder", !scr); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!scr); + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.mainUserInfoChanged); + } else if (i == chatSearchUserOnTwitterRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean hide = preferences.getBoolean("searchOnTwitter", true); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("searchOnTwitter", !hide); + editor.apply(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(!hide); + } + } else if(i == savePlusSettingsRow){ + LayoutInflater li = LayoutInflater.from(getParentActivity()); + View promptsView = li.inflate(R.layout.editbox_dialog, null); + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setView(promptsView); + final EditText userInput = (EditText) promptsView.findViewById(R.id.editTextDialogUserInput); + userInput.setHint(LocaleController.getString("EnterName", R.string.EnterName)); + userInput.setHintTextColor(0xff979797); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int defColor = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + userInput.getBackground().setColorFilter(themePrefs.getInt("dialogColor", defColor), PorterDuff.Mode.SRC_IN); + AndroidUtilities.clearCursorDrawable(userInput); + //builder.setMessage(LocaleController.getString("EnterName", R.string.EnterName)); + builder.setTitle(LocaleController.getString("SaveSettings", R.string.SaveSettings)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (saving) { + return; + } + saving = true; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + saving = false; + if (getParentActivity() != null) { + String pName = userInput.getText().toString(); + //AndroidUtilities.setStringPref(getParentActivity(), "themeName", pName); + //try{ + // PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); + // AndroidUtilities.setStringPref(getParentActivity(),"version", pInfo.versionName); + //} catch (Exception e) { + // FileLog.e("tmessages", e); + //} + //AndroidUtilities.setStringPref(getParentActivity(),"model", android.os.Build.MODEL+"/"+android.os.Build.VERSION.RELEASE); + Utilities.savePreferencesToSD(getParentActivity(), "/Telegram/Telegram Documents", "plusconfig.xml", pName+".xml", true); + //Utilities.copyWallpaperToSD(getParentActivity(), pName, true); + //Toast toast = Toast.makeText(getParentActivity(), LocaleController.getString("SaveThemeToastText", R.string.SaveThemeToastText), Toast.LENGTH_SHORT); + //toast.show(); + } + } + }); + } + }); + + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } else if (i == restorePlusSettingsRow) { + DocumentSelectActivity fragment = new DocumentSelectActivity(); + fragment.fileFilter = ".xml"; + fragment.setDelegate(new DocumentSelectActivity.DocumentSelectActivityDelegate() { + @Override + public void didSelectFiles(final DocumentSelectActivity activity, ArrayList files) { + final String xmlFile = files.get(0); + File file = new File(xmlFile); + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("RestoreSettings", R.string.RestoreSettings)); + builder.setMessage(file.getName()); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if(Utilities.loadPrefFromSD(getParentActivity(), xmlFile, "plusconfig") == 4){ + Utilities.restartApp(); + /*activity.finishFragment(); + if (listView != null) { + listView.invalidateViews(); + fixLayout(); + }*/ + } + } + }); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } + + @Override + public void startDocumentSelectActivity() {} + }); + presentFragment(fragment); + } else if(i == resetPlusSettingsRow){ + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setMessage(LocaleController.getString("AreYouSure", R.string.AreYouSure)); + builder.setTitle(LocaleController.getString("ResetSettings", R.string.ResetSettings)); + builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (reseting) { + return; + } + reseting = true; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + reseting = false; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + editor.clear(); + editor.apply(); + if (listView != null) { + listView.invalidateViews(); + fixLayout(); + } + } + }); + AndroidUtilities.needRestart = true; + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (getParentActivity() != null) { + Toast toast = Toast.makeText(getParentActivity(), LocaleController.getString("AppWillRestart", R.string.AppWillRestart), Toast.LENGTH_SHORT); + toast.show(); + } + } + }); + } + }); + builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); + showDialog(builder.create()); + } + } + }); + + frameLayout.addView(actionBar); + + return fragmentView; + } + + private AlertDialog.Builder createTabsDialog(AlertDialog.Builder builder){ + builder.setTitle(LocaleController.getString("HideShowTabs", R.string.HideShowTabs)); + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean hideUsers = preferences.getBoolean("hideUsers", false); + boolean hideGroups = preferences.getBoolean("hideGroups", false); + boolean hideSGroups = preferences.getBoolean("hideSGroups", false); + boolean hideChannels = preferences.getBoolean("hideChannels", false); + boolean hideBots = preferences.getBoolean("hideBots", false); + boolean hideFavs = preferences.getBoolean("hideFavs", false); + + builder.setMultiChoiceItems( + new CharSequence[]{LocaleController.getString("Users", R.string.Users), LocaleController.getString("Groups", R.string.Groups), LocaleController.getString("SuperGroups", R.string.SuperGroups), LocaleController.getString("Channels", R.string.Channels), LocaleController.getString("Bots", R.string.Bots), LocaleController.getString("Favorites", R.string.Favorites)}, + new boolean[]{!hideUsers, !hideGroups, !hideSGroups, !hideChannels, !hideBots, !hideFavs}, + new DialogInterface.OnMultiChoiceClickListener() { + @Override + public void onClick(DialogInterface dialog, int which, boolean isChecked) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + + if (which == 0) { + editor.putBoolean("hideUsers", !isChecked); + } else if (which == 1) { + editor.putBoolean("hideGroups", !isChecked); + } else if (which == 2) { + editor.putBoolean("hideSGroups", !isChecked); + } else if (which == 3) { + editor.putBoolean("hideChannels", !isChecked); + } else if (which == 4) { + editor.putBoolean("hideBots", !isChecked); + } else if (which == 5) { + editor.putBoolean("hideFavs", !isChecked); + } + editor.apply(); + + boolean hideUsers = preferences.getBoolean("hideUsers", false); + boolean hideGroups = preferences.getBoolean("hideGroups", false); + boolean hideSGroups = preferences.getBoolean("hideSGroups", false); + boolean hideChannels = preferences.getBoolean("hideChannels", false); + boolean hideBots = preferences.getBoolean("hideBots", false); + boolean hideFavs = preferences.getBoolean("hideFavs", false); + if(hideUsers && hideGroups && hideSGroups && hideChannels && hideBots && hideFavs){ + editor.putBoolean("hideTabs", true); + editor.apply(); + if (listView != null) { + listView.invalidateViews(); + } + } + NotificationCenter.getInstance().postNotificationName(NotificationCenter.refreshTabs, which); + } + }); + return builder; + } + + private AlertDialog.Builder createSharedOptions(AlertDialog.Builder builder){ + builder.setTitle(LocaleController.getString("SharedMedia", R.string.SharedMedia)); + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean hideMedia = preferences.getBoolean("hideSharedMedia", false); + boolean hideFiles = preferences.getBoolean("hideSharedFiles", false); + boolean hideMusic = preferences.getBoolean("hideSharedMusic", false); + boolean hideLinks = preferences.getBoolean("hideSharedLinks", false); + CharSequence[] cs = BuildVars.DEBUG_VERSION ? new CharSequence[]{LocaleController.getString("SharedMediaTitle", R.string.SharedMediaTitle), LocaleController.getString("DocumentsTitle", R.string.DocumentsTitle), LocaleController.getString("AudioTitle", R.string.AudioTitle), LocaleController.getString("LinksTitle", R.string.LinksTitle)} : + new CharSequence[]{LocaleController.getString("SharedMediaTitle", R.string.SharedMediaTitle), LocaleController.getString("DocumentsTitle", R.string.DocumentsTitle), LocaleController.getString("AudioTitle", R.string.AudioTitle)}; + boolean[] b = BuildVars.DEBUG_VERSION ? new boolean[]{!hideMedia, !hideFiles, !hideMusic, !hideLinks} : + new boolean[]{!hideMedia, !hideFiles, !hideMusic}; + builder.setMultiChoiceItems(cs, b, + new DialogInterface.OnMultiChoiceClickListener() { + @Override + public void onClick(DialogInterface dialog, int which, boolean isChecked) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + + if (which == 0) { + editor.putBoolean("hideSharedMedia", !isChecked); + } else if (which == 1) { + editor.putBoolean("hideSharedFiles", !isChecked); + } else if (which == 2) { + editor.putBoolean("hideSharedMusic", !isChecked); + } else if (which == 3) { + editor.putBoolean("hideSharedLinks", !isChecked); + } + editor.apply(); + } + }); + return builder; + } + + private AlertDialog.Builder createDialog(AlertDialog.Builder builder, int i){ + if (i == chatShowDirectShareBtn) { + builder.setTitle(LocaleController.getString("ShowDirectShareButton", R.string.ShowDirectShareButton)); + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + //SharedPreferences mainPreferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + boolean showDSBtnUsers = preferences.getBoolean("showDSBtnUsers", false); + boolean showDSBtnGroups = preferences.getBoolean("showDSBtnGroups", true); + boolean showDSBtnSGroups = preferences.getBoolean("showDSBtnSGroups", true); + boolean showDSBtnChannels = preferences.getBoolean("showDSBtnChannels", true); + boolean showDSBtnBots = preferences.getBoolean("showDSBtnBots", true); + + builder.setMultiChoiceItems( + new CharSequence[]{LocaleController.getString("Users", R.string.Users), LocaleController.getString("Groups", R.string.Groups), LocaleController.getString("SuperGroups", R.string.SuperGroups), LocaleController.getString("Channels", R.string.Channels), LocaleController.getString("Bots", R.string.Bots)}, + new boolean[]{showDSBtnUsers, showDSBtnGroups, showDSBtnSGroups, showDSBtnChannels, showDSBtnBots}, + new DialogInterface.OnMultiChoiceClickListener() { + @Override + public void onClick(DialogInterface dialog, int which, boolean isChecked) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + //Log.e("createDialog","which " + which + " isChecked " + isChecked); + if (which == 0) { + editor.putBoolean("showDSBtnUsers", isChecked); + } else if (which == 1) { + editor.putBoolean("showDSBtnGroups", isChecked); + } else if (which == 2) { + editor.putBoolean("showDSBtnSGroups", isChecked); + } else if (which == 3) { + editor.putBoolean("showDSBtnChannels", isChecked); + } else if (which == 4) { + editor.putBoolean("showDSBtnBots", isChecked); + } + editor.apply(); + + } + }); + } + + return builder; + } + + @Override + public void onResume() { + super.onResume(); + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + + updateTheme(); + fixLayout(); + } + + private void updateTheme(){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + actionBar.setBackgroundColor(themePrefs.getInt("prefHeaderColor", def)); + actionBar.setTitleColor(themePrefs.getInt("prefHeaderTitleColor", 0xffffffff)); + + Drawable back = getParentActivity().getResources().getDrawable(R.drawable.ic_ab_back); + back.setColorFilter(themePrefs.getInt("prefHeaderIconsColor", 0xffffffff), PorterDuff.Mode.MULTIPLY); + actionBar.setBackButtonDrawable(back); + + Drawable other = getParentActivity().getResources().getDrawable(R.drawable.ic_ab_other); + other.setColorFilter(themePrefs.getInt("prefHeaderIconsColor", 0xffffffff), PorterDuff.Mode.MULTIPLY); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + fixLayout(); + } + + private void fixLayout() { + if (fragmentView == null) { + return; + } + fragmentView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + if (fragmentView != null) { + fragmentView.getViewTreeObserver().removeOnPreDrawListener(this); + } + return true; + } + }); + } + + @Override + public void didReceivedNotification(int id, Object... args) { + + } + + + private class ListAdapter extends BaseFragmentAdapter { + private Context mContext; + + public ListAdapter(Context context) { + mContext = context; + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public boolean isEnabled(int i) { + return i == showAndroidEmojiRow || i == useDeviceFontRow || i == emojiPopupSize || i == dialogsTabsHeightRow || i == dialogsTabsRow || i == chatShowDirectShareBtn || i == profileSharedOptionsRow || + i == disableAudioStopRow || i == disableMessageClickRow || i == chatDirectShareToMenu || i == chatDirectShareReplies || i == chatDirectShareFavsFirst || i == chatShowEditedMarkRow || + i == chatShowDateToastRow || i == chatHideLeftGroupRow || i == chatHideJoinedGroupRow || i == chatHideBotKeyboardRow || i == dialogsHideTabsCheckRow || i == dialogsDisableTabsAnimationCheckRow || + i == dialogsInfiniteTabsSwipe || i == dialogsHideTabsCounters || i == dialogsTabsCountersCountChats || i == dialogsTabsCountersCountNotMuted || i == chatSearchUserOnTwitterRow || + i == keepOriginalFilenameRow || i == dialogsPicClickRow || i == dialogsGroupPicClickRow || i == hideMobileNumberRow || i == showUsernameRow || + i == notificationInvertMessagesOrderRow || i == savePlusSettingsRow || i == restorePlusSettingsRow || i == resetPlusSettingsRow; + } + + @Override + public int getCount() { + return rowCount; + } + + @Override + public Object getItem(int i) { + return null; + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public boolean hasStableIds() { + return false; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + int type = getItemViewType(i); + if (type == 0) { + if (view == null) { + view = new EmptyCell(mContext); + } + if (i == overscrollRow) { + ((EmptyCell) view).setHeight(AndroidUtilities.dp(88)); + } else { + ((EmptyCell) view).setHeight(AndroidUtilities.dp(16)); + } + } else if (type == 1) { + if (view == null) { + view = new ShadowSectionCell(mContext); + } + } else if (type == 2) { + if (view == null) { + view = new TextSettingsCell(mContext); + } + TextSettingsCell textCell = (TextSettingsCell) view; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + //SharedPreferences mainPreferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + if (i == emojiPopupSize) { + //SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + //SharedPreferences mainPreferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + int size = preferences.getInt("emojiPopupSize", AndroidUtilities.isTablet() ? 65 : 60); + textCell.setTextAndValue(LocaleController.getString("EmojiPopupSize", R.string.EmojiPopupSize), String.format("%d", size), true); + } else if (i == dialogsTabsHeightRow) { + //SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + int size = preferences.getInt("tabsHeight", AndroidUtilities.isTablet() ? 42 : 40); + textCell.setTextAndValue(LocaleController.getString("TabsHeight", R.string.TabsHeight), String.format("%d", size), true); + } else if (i == dialogsPicClickRow) { + String value; + //SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + int sort = preferences.getInt("dialogsClickOnPic", 0); + if (sort == 0) { + value = LocaleController.getString("RowGradientDisabled", R.string.RowGradientDisabled); + } else if (sort == 1) { + value = LocaleController.getString("ShowPics", R.string.ShowPics); + } else { + value = LocaleController.getString("ShowProfile", R.string.ShowProfile); + } + textCell.setTextAndValue(LocaleController.getString("ClickOnContactPic", R.string.ClickOnContactPic), value, true); + } else if (i == dialogsGroupPicClickRow) { + String value; + //SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + int sort = preferences.getInt("dialogsClickOnGroupPic", 0); + if (sort == 0) { + value = LocaleController.getString("RowGradientDisabled", R.string.RowGradientDisabled); + } else if (sort == 1) { + value = LocaleController.getString("ShowPics", R.string.ShowPics); + } else { + value = LocaleController.getString("ShowProfile", R.string.ShowProfile); + } + textCell.setTextAndValue(LocaleController.getString("ClickOnGroupPic", R.string.ClickOnGroupPic), value, true); + } + } else if (type == 3) { + if (view == null) { + view = new TextCheckCell(mContext); + } + TextCheckCell textCell = (TextCheckCell) view; + + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + //SharedPreferences mainPreferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + if (i == disableAudioStopRow) { + textCell.setTextAndCheck(LocaleController.getString("DisableAudioStop", R.string.DisableAudioStop), preferences.getBoolean("disableAudioStop", false), true); + } else if (i == disableMessageClickRow) { + textCell.setTextAndCheck(LocaleController.getString("DisableMessageClick", R.string.DisableMessageClick), preferences.getBoolean("disableMessageClick", false), true); + } else if (i == chatDirectShareReplies) { + textCell.setTextAndCheck(LocaleController.getString("DirectShareReplies", R.string.DirectShareReplies), preferences.getBoolean("directShareReplies", false), true); + } else if (i == chatDirectShareToMenu) { + textCell.setTextAndCheck(LocaleController.getString("DirectShareToMenu", R.string.DirectShareToMenu), preferences.getBoolean("directShareToMenu", false), true); + } else if (i == chatDirectShareFavsFirst) { + textCell.setTextAndCheck(LocaleController.getString("DirectShareShowFavsFirst", R.string.DirectShareShowFavsFirst), preferences.getBoolean("directShareFavsFirst", false), true); + } else if (i == chatShowEditedMarkRow) { + textCell.setTextAndCheck(LocaleController.getString("ShowEditedMark", R.string.ShowEditedMark), preferences.getBoolean("showEditedMark", true), true); + } else if (i == chatShowDateToastRow) { + textCell.setTextAndCheck(LocaleController.getString("ShowDateToast", R.string.ShowDateToast), preferences.getBoolean("showDateToast", true), true); + } else if (i == chatHideLeftGroupRow) { + textCell.setTextAndCheck(LocaleController.getString("HideLeftGroup", R.string.HideLeftGroup), preferences.getBoolean("hideLeftGroup", false), true); + } else if (i == chatHideJoinedGroupRow) { + textCell.setTextAndCheck(LocaleController.getString("HideJoinedGroup", R.string.HideJoinedGroup), preferences.getBoolean("hideJoinedGroup", false), true); + } else if (i == chatHideBotKeyboardRow) { + textCell.setTextAndCheck(LocaleController.getString("HideBotKeyboard", R.string.HideBotKeyboard), preferences.getBoolean("hideBotKeyboard", false), true); + } else if (i == keepOriginalFilenameRow) { + textCell.setTextAndCheck(LocaleController.getString("KeepOriginalFilename", R.string.KeepOriginalFilename), preferences.getBoolean("keepOriginalFilename", false), false); + } else if (i == showAndroidEmojiRow) { + textCell.setTextAndCheck(LocaleController.getString("ShowAndroidEmoji", R.string.ShowAndroidEmoji), preferences.getBoolean("showAndroidEmoji", false), true); + } else if (i == useDeviceFontRow) { + textCell.setTextAndCheck(LocaleController.getString("UseDeviceFont", R.string.UseDeviceFont), preferences.getBoolean("useDeviceFont", false), false); + } else if (i == dialogsHideTabsCheckRow) { + textCell.setTextAndCheck(LocaleController.getString("HideTabs", R.string.HideTabs), preferences.getBoolean("hideTabs", false), true); + } else if (i == dialogsDisableTabsAnimationCheckRow) { + textCell.setTextAndCheck(LocaleController.getString("DisableTabsAnimation", R.string.DisableTabsAnimation), preferences.getBoolean("disableTabsAnimation", false), true); + } else if (i == dialogsInfiniteTabsSwipe) { + textCell.setTextAndCheck(LocaleController.getString("InfiniteSwipe", R.string.InfiniteSwipe), preferences.getBoolean("infiniteTabsSwipe", false), true); + } else if (i == dialogsHideTabsCounters) { + textCell.setTextAndCheck(LocaleController.getString("HideTabsCounters", R.string.HideTabsCounters), preferences.getBoolean("hideTabsCounters", false), true); + } else if (i == dialogsTabsCountersCountChats) { + textCell.setTextAndCheck(LocaleController.getString("HeaderTabCounterCountChats", R.string.HeaderTabCounterCountChats), preferences.getBoolean("tabsCountersCountChats", false), true); + } else if (i == dialogsTabsCountersCountNotMuted) { + textCell.setTextAndCheck(LocaleController.getString("HeaderTabCounterCountNotMuted", R.string.HeaderTabCounterCountNotMuted), preferences.getBoolean("tabsCountersCountNotMuted", false), true); + } else if (i == hideMobileNumberRow) { + textCell.setTextAndCheck(LocaleController.getString("HideMobile", R.string.HideMobile), preferences.getBoolean("hideMobile", false), true); + } else if (i == showUsernameRow) { + textCell.setTextAndCheck(LocaleController.getString("ShowUsernameInMenu", R.string.ShowUsernameInMenu), preferences.getBoolean("showUsername", false), true); + } else if (i == notificationInvertMessagesOrderRow) { + textCell.setTextAndCheck(LocaleController.getString("InvertMessageOrder", R.string.InvertMessageOrder), preferences.getBoolean("invertMessagesOrder", false), true); + } else if (i == chatSearchUserOnTwitterRow) { + textCell.setTextAndCheck(LocaleController.getString("SearchUserOnTwitter", R.string.SearchUserOnTwitter), preferences.getBoolean("searchOnTwitter", true), false); + } + } else if (type == 4) { + if (view == null) { + view = new HeaderCell(mContext); + } + if (i == settingsSectionRow2) { + ((HeaderCell) view).setText(LocaleController.getString("General", R.string.General)); + } else if (i == messagesSectionRow2) { + ((HeaderCell) view).setText(LocaleController.getString("MessagesSettings", R.string.MessagesSettings)); + } else if (i == profileSectionRow2) { + ((HeaderCell) view).setText(LocaleController.getString("ProfileScreen", R.string.ProfileScreen)); + } else if (i == drawerSectionRow2) { + ((HeaderCell) view).setText(LocaleController.getString("NavigationDrawer", R.string.NavigationDrawer)); + } else if (i == privacySectionRow2) { + ((HeaderCell) view).setText(LocaleController.getString("PrivacySettings", R.string.PrivacySettings)); + } else if (i == mediaDownloadSection2) { + ((HeaderCell) view).setText(LocaleController.getString("SharedMedia", R.string.SharedMedia)); + } else if (i == dialogsSectionRow2) { + ((HeaderCell) view).setText(LocaleController.getString("DialogsSettings", R.string.DialogsSettings)); + } else if (i == notificationSection2Row) { + ((HeaderCell) view).setText(LocaleController.getString("Notifications", R.string.Notifications)); + } else if (i == plusSettingsSectionRow2) { + ((HeaderCell) view).setText(LocaleController.getString("PlusSettings", R.string.PlusSettings)); + } + } + else if (type == 6) { + if (view == null) { + view = new TextDetailSettingsCell(mContext); + } + TextDetailSettingsCell textCell = (TextDetailSettingsCell) view; + + if (i == dialogsTabsRow) { + String value; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + + boolean hideUsers = preferences.getBoolean("hideUsers", false); + boolean hideGroups = preferences.getBoolean("hideGroups", false); + boolean hideSGroups = preferences.getBoolean("hideSGroups", false); + boolean hideChannels = preferences.getBoolean("hideChannels", false); + boolean hideBots = preferences.getBoolean("hideBots", false); + boolean hideFavs = preferences.getBoolean("hideFavs", false); + + value = LocaleController.getString("HideShowTabs", R.string.HideShowTabs); + + String text = ""; + if (!hideUsers) { + text += LocaleController.getString("Users", R.string.Users); + } + if (!hideGroups) { + if (text.length() != 0) { + text += ", "; + } + text += LocaleController.getString("Groups", R.string.Groups); + } + if (!hideSGroups) { + if (text.length() != 0) { + text += ", "; + } + text += LocaleController.getString("SuperGroups", R.string.SuperGroups); + } + if (!hideChannels) { + if (text.length() != 0) { + text += ", "; + } + text += LocaleController.getString("Channels", R.string.Channels); + } + if (!hideBots) { + if (text.length() != 0) { + text += ", "; + } + text += LocaleController.getString("Bots", R.string.Bots); + } + if (!hideFavs) { + if (text.length() != 0) { + text += ", "; + } + text += LocaleController.getString("Favorites", R.string.Favorites); + } + if (text.length() == 0) { + text = ""; + } + textCell.setTextAndValue(value, text, true); + } else if (i == chatShowDirectShareBtn) { + String value; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + boolean showDSBtnUsers = preferences.getBoolean("showDSBtnUsers", false); + boolean showDSBtnGroups = preferences.getBoolean("showDSBtnGroups", true); + boolean showDSBtnSGroups = preferences.getBoolean("showDSBtnSGroups", true); + boolean showDSBtnChannels = preferences.getBoolean("showDSBtnChannels", true); + boolean showDSBtnBots = preferences.getBoolean("showDSBtnBots", true); + + value = LocaleController.getString("ShowDirectShareButton", R.string.ShowDirectShareButton); + + String text = ""; + if (showDSBtnUsers) { + text += LocaleController.getString("Users", R.string.Users); + } + if (showDSBtnGroups) { + if (text.length() != 0) { + text += ", "; + } + text += LocaleController.getString("Groups", R.string.Groups); + } + if (showDSBtnSGroups) { + if (text.length() != 0) { + text += ", "; + } + text += LocaleController.getString("SuperGroups", R.string.SuperGroups); + } + if (showDSBtnChannels) { + if (text.length() != 0) { + text += ", "; + } + text += LocaleController.getString("Channels", R.string.Channels); + } + if (showDSBtnBots) { + if (text.length() != 0) { + text += ", "; + } + text += LocaleController.getString("Bots", R.string.Bots); + } + + if (text.length() == 0) { + text = LocaleController.getString("Channels", R.string.UsernameEmpty); + } + textCell.setTextAndValue(value, text, true); + } else if (i == profileSharedOptionsRow) { + String value; + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + + boolean hideMedia = preferences.getBoolean("hideSharedMedia", false); + boolean hideFiles = preferences.getBoolean("hideSharedFiles", false); + boolean hideMusic = preferences.getBoolean("hideSharedMusic", false); + boolean hideLinks = preferences.getBoolean("hideSharedLinks", false); + + value = LocaleController.getString("SharedMedia", R.string.SharedMedia); + + String text = ""; + if (!hideMedia) { + text += LocaleController.getString("Users", R.string.SharedMediaTitle); + } + if (!hideFiles) { + if (text.length() != 0) { + text += ", "; + } + text += LocaleController.getString("DocumentsTitle", R.string.DocumentsTitle); + } + if (!hideMusic) { + if (text.length() != 0) { + text += ", "; + } + text += LocaleController.getString("AudioTitle", R.string.AudioTitle); + } + if (!hideLinks && BuildVars.DEBUG_VERSION) { + if (text.length() != 0) { + text += ", "; + } + text += LocaleController.getString("LinksTitle", R.string.LinksTitle); + } + + if (text.length() == 0) { + text = ""; + } + textCell.setTextAndValue(value, text, true); + } else if (i == savePlusSettingsRow) { + textCell.setMultilineDetail(true); + textCell.setTextAndValue(LocaleController.getString("SaveSettings", R.string.SaveSettings), LocaleController.getString("SaveSettingsSum", R.string.SaveSettingsSum), true); + } else if (i == restorePlusSettingsRow) { + textCell.setMultilineDetail(true); + textCell.setTextAndValue(LocaleController.getString("RestoreSettings", R.string.RestoreSettings), LocaleController.getString("RestoreSettingsSum", R.string.RestoreSettingsSum), true); + } else if (i == resetPlusSettingsRow) { + textCell.setMultilineDetail(true); + textCell.setTextAndValue(LocaleController.getString("ResetSettings", R.string.ResetSettings), LocaleController.getString("ResetSettingsSum", R.string.ResetSettingsSum), false); + } + } else if (type == 7) { + if (view == null) { + view = new TextInfoPrivacyCell(mContext); + } + if (i == keepOriginalFilenameDetailRow) { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("KeepOriginalFilenameHelp", R.string.KeepOriginalFilenameHelp)); + view.setBackgroundResource(R.drawable.greydivider); + } + } + return view; + } + + @Override + public int getItemViewType(int i) { + if (i == emptyRow || i == overscrollRow) { + return 0; + } + if (i == settingsSectionRow || i == messagesSectionRow || i == profileSectionRow || i == drawerSectionRow || i == privacySectionRow || + i == mediaDownloadSection || i == dialogsSectionRow || i == notificationSectionRow || i == plusSettingsSectionRow) { + return 1; + } else if (i == disableAudioStopRow || i == disableMessageClickRow || i == dialogsHideTabsCheckRow || i == dialogsDisableTabsAnimationCheckRow || i == dialogsInfiniteTabsSwipe || + i == dialogsHideTabsCounters || i == dialogsTabsCountersCountChats || i == dialogsTabsCountersCountNotMuted || i == showAndroidEmojiRow || i == useDeviceFontRow || + i == keepOriginalFilenameRow || i == hideMobileNumberRow || i == showUsernameRow || i == chatDirectShareToMenu || i == chatDirectShareReplies || i == chatDirectShareFavsFirst || + i == chatShowEditedMarkRow || i == chatShowDateToastRow || i == chatHideLeftGroupRow || i == chatHideJoinedGroupRow || i == chatHideBotKeyboardRow || i == notificationInvertMessagesOrderRow || i == chatSearchUserOnTwitterRow) { + return 3; + } else if (i == emojiPopupSize || i == dialogsTabsHeightRow || i == dialogsPicClickRow || i == dialogsGroupPicClickRow) { + return 2; + } else if (i == dialogsTabsRow || i == chatShowDirectShareBtn || i == profileSharedOptionsRow || i == savePlusSettingsRow || + i == restorePlusSettingsRow || i == resetPlusSettingsRow) { + return 6; + } else if (i == keepOriginalFilenameDetailRow) { + return 7; + } else if (i == settingsSectionRow2 || i == messagesSectionRow2 || i == profileSectionRow2 || i == drawerSectionRow2 || + i == privacySectionRow2 || i == mediaDownloadSection2 || i == dialogsSectionRow2 || i == notificationSection2Row || + i == plusSettingsSectionRow2) { + return 4; + } else { + return 2; + } + } + + @Override + public int getViewTypeCount() { + return 8; + } + + @Override + public boolean isEmpty() { + return false; + } + } +} + diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java index 979c08ad..81425c82 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PopupNotificationActivity.java @@ -63,6 +63,7 @@ import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.PopupAudioView; import org.telegram.ui.Components.RecordStatusDrawable; import org.telegram.ui.Components.SizeNotifierFrameLayout; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.TypingDotsDrawable; import java.io.File; @@ -160,6 +161,7 @@ public class PopupNotificationActivity extends Activity implements NotificationC @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + Theme.loadResources(this); int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android"); if (resourceId > 0) { @@ -308,6 +310,11 @@ public class PopupNotificationActivity extends Activity implements NotificationC } + @Override + public void onMessageEditEnd() { + + } + @Override public void needSendTyping() { if (currentMessageObject != null) { @@ -342,9 +349,9 @@ public class PopupNotificationActivity extends Activity implements NotificationC actionBar = new ActionBar(this); actionBar.setOccupyStatusBar(false); actionBar.setBackButtonImage(R.drawable.ic_ab_back); - //actionBar.setBackgroundColor(0xff54759e); + //actionBar.setBackgroundColor(Theme.ACTION_BAR_COLOR); + actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_SELECTOR_COLOR); actionBar.setBackgroundResource(R.color.header); - actionBar.setItemsBackground(R.drawable.bar_selector); popupContainer.addView(actionBar); ViewGroup.LayoutParams layoutParams = actionBar.getLayoutParams(); layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; @@ -355,7 +362,6 @@ public class PopupNotificationActivity extends Activity implements NotificationC countText = (TextView) view.findViewById(R.id.count_text); avatarContainer = new FrameLayoutFixed(this); - avatarContainer.setBackgroundResource(R.drawable.bar_selector); avatarContainer.setPadding(AndroidUtilities.dp(4), 0, AndroidUtilities.dp(4), 0); actionBar.addView(avatarContainer); FrameLayout.LayoutParams layoutParams2 = (FrameLayout.LayoutParams) avatarContainer.getLayoutParams(); @@ -394,7 +400,7 @@ public class PopupNotificationActivity extends Activity implements NotificationC nameTextView.setLayoutParams(layoutParams2); onlineTextView = new TextView(this); - onlineTextView.setTextColor(0xffd7e8f7); + onlineTextView.setTextColor(Theme.ACTION_BAR_SUBTITLE_COLOR); onlineTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); onlineTextView.setLines(1); onlineTextView.setMaxLines(1); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LastSeenActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java similarity index 73% rename from TMessagesProj/src/main/java/org/telegram/ui/LastSeenActivity.java rename to TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java index 4d66312b..fe19406b 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LastSeenActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyControlActivity.java @@ -8,6 +8,7 @@ package org.telegram.ui; +import android.annotation.TargetApi; import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; @@ -16,6 +17,7 @@ import android.content.DialogInterface; import android.content.SharedPreferences; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; +import android.os.Build; import android.os.Bundle; import android.text.Spannable; import android.text.method.LinkMovementMethod; @@ -23,18 +25,20 @@ import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.widget.AbsListView; import android.widget.AdapterView; +import android.widget.EdgeEffect; import android.widget.FrameLayout; import android.widget.ListView; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.ContactsController; +import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; -import org.telegram.messenger.ApplicationLoader; -import org.telegram.messenger.FileLog; import org.telegram.messenger.R; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.RequestDelegate; @@ -45,14 +49,15 @@ import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Adapters.BaseFragmentAdapter; import org.telegram.ui.Cells.HeaderCell; -import org.telegram.ui.Cells.LastSeenRadioCell; +import org.telegram.ui.Cells.RadioCell; import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.LayoutHelper; +import java.lang.reflect.Field; import java.util.ArrayList; -public class LastSeenActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { +public class PrivacyControlActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { private ListAdapter listAdapter; private View doneButton; @@ -62,17 +67,23 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter private ArrayList currentMinus; private int lastCheckedType = -1; - private int lastSeenSectionRow; + private boolean isGroup; + + private boolean enableAnimation; + + private int sectionRow; private int everybodyRow; private int myContactsRow; private int nobodyRow; - private int lastSeenDetailRow; + private int detailRow; private int shareSectionRow; private int alwaysShareRow; private int neverShareRow; private int shareDetailRow; private int rowCount; + private int bgColor; + private final static int done_button = 1; private static class LinkMovementMethodMy extends LinkMovementMethod { @@ -87,6 +98,11 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter } } + public PrivacyControlActivity(boolean group) { + super(); + isGroup = group; + } + @Override public boolean onFragmentCreate() { super.onFragmentCreate(); @@ -106,7 +122,11 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); - actionBar.setTitle(LocaleController.getString("PrivacyLastSeen", R.string.PrivacyLastSeen)); + if (isGroup) { + actionBar.setTitle(LocaleController.getString("GroupsAndChannels", R.string.GroupsAndChannels)); + } else { + actionBar.setTitle(LocaleController.getString("PrivacyLastSeen", R.string.PrivacyLastSeen)); + } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -117,12 +137,16 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter return; } - if (currentType != 0) { + if (currentType != 0 && !isGroup) { final SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); boolean showed = preferences.getBoolean("privacyAlertShowed", false); if (!showed) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); - builder.setMessage(LocaleController.getString("CustomHelp", R.string.CustomHelp)); + if (isGroup) { + builder.setMessage(LocaleController.getString("WhoCanAddMeInfo", R.string.WhoCanAddMeInfo)); + } else { + builder.setMessage(LocaleController.getString("CustomHelp", R.string.CustomHelp)); + } builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { @Override @@ -142,23 +166,18 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter }); ActionBarMenu menu = actionBar.createMenu(); - //doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); - SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - Drawable done = getParentActivity().getResources().getDrawable(R.drawable.ic_done); - done.setColorFilter(themePrefs.getInt("prefHeaderIconsColor", 0xffffffff), PorterDuff.Mode.SRC_IN); - doneButton = menu.addItemWithWidth(done_button, done, AndroidUtilities.dp(56)); - + doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); doneButton.setVisibility(View.GONE); listAdapter = new ListAdapter(context); - + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + bgColor = themePrefs.getInt("prefBGColor", 0xffffffff); fragmentView = new FrameLayout(context); FrameLayout frameLayout = (FrameLayout) fragmentView; frameLayout.setBackgroundColor(0xfff0f0f0); ListView listView = new ListView(context); - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - listView.setBackgroundColor(preferences.getInt("prefBGColor", 0xffffffff)); + listView.setBackgroundColor(bgColor); listView.setDivider(null); listView.setDividerHeight(0); listView.setVerticalScrollBarEnabled(false); @@ -185,6 +204,7 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter if (newType == currentType) { return; } + enableAnimation = true; doneButton.setVisibility(View.VISIBLE); lastCheckedType = currentType; currentType = newType; @@ -199,19 +219,20 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter if (createFromArray.isEmpty()) { Bundle args = new Bundle(); args.putBoolean(i == neverShareRow ? "isNeverShare" : "isAlwaysShare", true); + args.putBoolean("isGroup", isGroup); GroupCreateActivity fragment = new GroupCreateActivity(args); fragment.setDelegate(new GroupCreateActivity.GroupCreateActivityDelegate() { @Override public void didSelectUsers(ArrayList ids) { if (i == neverShareRow) { currentMinus = ids; - for (Integer id : currentMinus) { - currentPlus.remove(id); + for (int a = 0; a < currentMinus.size(); a++) { + currentPlus.remove(currentMinus.get(a)); } } else { currentPlus = ids; - for (Integer id : currentPlus) { - currentMinus.remove(id); + for (int a = 0; a < currentPlus.size(); a++) { + currentMinus.remove(currentPlus.get(a)); } } doneButton.setVisibility(View.VISIBLE); @@ -221,22 +242,22 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter }); presentFragment(fragment); } else { - LastSeenUsersActivity fragment = new LastSeenUsersActivity(createFromArray, i == alwaysShareRow); - fragment.setDelegate(new LastSeenUsersActivity.LastSeenUsersActivityDelegate() { + PrivacyUsersActivity fragment = new PrivacyUsersActivity(createFromArray, isGroup, i == alwaysShareRow); + fragment.setDelegate(new PrivacyUsersActivity.PrivacyActivityDelegate() { @Override public void didUpdatedUserList(ArrayList ids, boolean added) { if (i == neverShareRow) { currentMinus = ids; if (added) { - for (Integer id : currentMinus) { - currentPlus.remove(id); + for (int a = 0; a < currentMinus.size(); a++) { + currentPlus.remove(currentMinus.get(a)); } } } else { currentPlus = ids; if (added) { - for (Integer id : currentPlus) { - currentMinus.remove(id); + for (int a = 0; a < currentPlus.size(); a++) { + currentMinus.remove(currentPlus.get(a)); } } } @@ -249,10 +270,47 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter } } }); - + updateTheme(); return fragmentView; } + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public static void setEdgeGlowColor(AbsListView listView, int color) { + Class CLASS_LIST_VIEW = AbsListView.class; + Field LIST_VIEW_FIELD_EDGE_GLOW_TOP; + Field LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM; + + Field edgeGlowTop = null, edgeGlowBottom = null; + + for (Field f : CLASS_LIST_VIEW.getDeclaredFields()) { + switch (f.getName()) { + case "mEdgeGlowTop": + f.setAccessible(true); + edgeGlowTop = f; + break; + case "mEdgeGlowBottom": + f.setAccessible(true); + edgeGlowBottom = f; + break; + } + } + + LIST_VIEW_FIELD_EDGE_GLOW_TOP = edgeGlowTop; + LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM = edgeGlowBottom; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + try { + EdgeEffect ee; + ee = (EdgeEffect) LIST_VIEW_FIELD_EDGE_GLOW_TOP.get(listView); + ee.setColor(color); + ee = (EdgeEffect) LIST_VIEW_FIELD_EDGE_GLOW_BOTTOM.get(listView); + ee.setColor(color); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + @Override public void didReceivedNotification(int id, Object... args) { if (id == NotificationCenter.privacyRulesUpdated) { @@ -262,11 +320,15 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter private void applyCurrentPrivacySettings() { TLRPC.TL_account_setPrivacy req = new TLRPC.TL_account_setPrivacy(); - req.key = new TLRPC.TL_inputPrivacyKeyStatusTimestamp(); + if (isGroup) { + req.key = new TLRPC.TL_inputPrivacyKeyChatInvite(); + } else { + req.key = new TLRPC.TL_inputPrivacyKeyStatusTimestamp(); + } if (currentType != 0 && currentPlus.size() > 0) { TLRPC.TL_inputPrivacyValueAllowUsers rule = new TLRPC.TL_inputPrivacyValueAllowUsers(); - for (Integer uid : currentPlus) { - TLRPC.User user = MessagesController.getInstance().getUser(uid); + for (int a = 0; a < currentPlus.size(); a++) { + TLRPC.User user = MessagesController.getInstance().getUser(currentPlus.get(a)); if (user != null) { TLRPC.InputUser inputUser = MessagesController.getInputUser(user); if (inputUser != null) { @@ -278,8 +340,8 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter } if (currentType != 1 && currentMinus.size() > 0) { TLRPC.TL_inputPrivacyValueDisallowUsers rule = new TLRPC.TL_inputPrivacyValueDisallowUsers(); - for (Integer uid : currentMinus) { - TLRPC.User user = MessagesController.getInstance().getUser(uid); + for (int a = 0; a < currentMinus.size(); a++) { + TLRPC.User user = MessagesController.getInstance().getUser(currentMinus.get(a)); if (user != null) { TLRPC.InputUser inputUser = MessagesController.getInputUser(user); if (inputUser != null) { @@ -299,10 +361,10 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter ProgressDialog progressDialog = null; if (getParentActivity() != null) { progressDialog = new ProgressDialog(getParentActivity()); - progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); - progressDialog.setCanceledOnTouchOutside(false); - progressDialog.setCancelable(false); - progressDialog.show(); + progressDialog.setMessage(LocaleController.getString("Loading", R.string.Loading)); + progressDialog.setCanceledOnTouchOutside(false); + progressDialog.setCancelable(false); + progressDialog.show(); } final ProgressDialog progressDialogFinal = progressDialog; ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { @@ -322,7 +384,7 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter finishFragment(); TLRPC.TL_account_privacyRules rules = (TLRPC.TL_account_privacyRules) response; MessagesController.getInstance().putUsers(rules.users, false); - ContactsController.getInstance().setPrivacyRules(rules.rules); + ContactsController.getInstance().setPrivacyRules(rules.rules, isGroup); } else { showErrorAlert(); } @@ -346,13 +408,14 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter private void checkPrivacy() { currentPlus = new ArrayList<>(); currentMinus = new ArrayList<>(); - ArrayList privacyRules = ContactsController.getInstance().getPrivacyRules(); + ArrayList privacyRules = ContactsController.getInstance().getPrivacyRules(isGroup); if (privacyRules.size() == 0) { currentType = 1; return; } int type = -1; - for (TLRPC.PrivacyRule rule : privacyRules) { + for (int a = 0; a < privacyRules.size(); a++) { + TLRPC.PrivacyRule rule = privacyRules.get(a); if (rule instanceof TLRPC.TL_privacyValueAllowUsers) { currentPlus.addAll(rule.users); } else if (rule instanceof TLRPC.TL_privacyValueDisallowUsers) { @@ -380,11 +443,15 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter private void updateRows() { rowCount = 0; - lastSeenSectionRow = rowCount++; + sectionRow = rowCount++; everybodyRow = rowCount++; myContactsRow = rowCount++; - nobodyRow = rowCount++; - lastSeenDetailRow = rowCount++; + if (isGroup) { + nobodyRow = -1; + } else { + nobodyRow = rowCount++; + } + detailRow = rowCount++; shareSectionRow = rowCount++; if (currentType == 1 || currentType == 2) { alwaysShareRow = rowCount++; @@ -406,10 +473,7 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter public void onResume() { super.onResume(); lastCheckedType = -1; - if (listAdapter != null) { - listAdapter.notifyDataSetChanged(); - } - updateTheme(); + enableAnimation = false; } private void updateTheme(){ @@ -417,7 +481,6 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); actionBar.setBackgroundColor(themePrefs.getInt("prefHeaderColor", def)); actionBar.setTitleColor(themePrefs.getInt("prefHeaderTitleColor", 0xffffffff)); - Drawable back = getParentActivity().getResources().getDrawable(R.drawable.ic_ab_back); back.setColorFilter(themePrefs.getInt("prefHeaderIconsColor", 0xffffffff), PorterDuff.Mode.MULTIPLY); actionBar.setBackButtonDrawable(back); @@ -463,10 +526,11 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter @Override public View getView(int i, View view, ViewGroup viewGroup) { int type = getItemViewType(i); + if (type == 0) { if (view == null) { view = new TextSettingsCell(mContext); - view.setBackgroundColor(0xffffffff); + view.setBackgroundColor(/*0xffffffff*/ bgColor); } TextSettingsCell textCell = (TextSettingsCell) view; if (i == alwaysShareRow) { @@ -476,7 +540,11 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter } else { value = LocaleController.getString("EmpryUsersPlaceholder", R.string.EmpryUsersPlaceholder); } - textCell.setTextAndValue(LocaleController.getString("AlwaysShareWith", R.string.AlwaysShareWith), value, neverShareRow != -1); + if (isGroup) { + textCell.setTextAndValue(LocaleController.getString("AlwaysAllow", R.string.AlwaysAllow), value, neverShareRow != -1); + } else { + textCell.setTextAndValue(LocaleController.getString("AlwaysShareWith", R.string.AlwaysShareWith), value, neverShareRow != -1); + } } else if (i == neverShareRow) { String value; if (currentMinus.size() != 0) { @@ -484,51 +552,68 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter } else { value = LocaleController.getString("EmpryUsersPlaceholder", R.string.EmpryUsersPlaceholder); } - textCell.setTextAndValue(LocaleController.getString("NeverShareWith", R.string.NeverShareWith), value, false); + if (isGroup) { + textCell.setTextAndValue(LocaleController.getString("NeverAllow", R.string.NeverAllow), value, false); + } else { + textCell.setTextAndValue(LocaleController.getString("NeverShareWith", R.string.NeverShareWith), value, false); + } } } else if (type == 1) { if (view == null) { view = new TextInfoPrivacyCell(mContext); - //view.setBackgroundColor(0xffffffff); + view.setBackgroundColor(/*0xffffffff*/ bgColor); } - if (i == lastSeenDetailRow) { - ((TextInfoPrivacyCell) view).setText(LocaleController.getString("CustomHelp", R.string.CustomHelp)); + if (i == detailRow) { + if (isGroup) { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("WhoCanAddMeInfo", R.string.WhoCanAddMeInfo)); + } else { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("CustomHelp", R.string.CustomHelp)); + } view.setBackgroundResource(R.drawable.greydivider); } else if (i == shareDetailRow) { - ((TextInfoPrivacyCell) view).setText(LocaleController.getString("CustomShareSettingsHelp", R.string.CustomShareSettingsHelp)); + if (isGroup) { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("CustomShareInfo", R.string.CustomShareInfo)); + } else { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("CustomShareSettingsHelp", R.string.CustomShareSettingsHelp)); + } view.setBackgroundResource(R.drawable.greydivider_bottom); } } else if (type == 2) { if (view == null) { view = new HeaderCell(mContext); - view.setBackgroundColor(0xffffffff); + view.setBackgroundColor(/*0xffffffff*/ bgColor); } - if (i == lastSeenSectionRow) { - ((HeaderCell) view).setText(LocaleController.getString("LastSeenTitle", R.string.LastSeenTitle)); + if (i == sectionRow) { + if (isGroup) { + ((HeaderCell) view).setText(LocaleController.getString("WhoCanAddMe", R.string.WhoCanAddMe)); + } else { + ((HeaderCell) view).setText(LocaleController.getString("LastSeenTitle", R.string.LastSeenTitle)); + } } else if (i == shareSectionRow) { ((HeaderCell) view).setText(LocaleController.getString("AddExceptions", R.string.AddExceptions)); } } else if (type == 3) { if (view == null) { - view = new LastSeenRadioCell(mContext); - view.setBackgroundColor(0xffffffff); + view = new RadioCell(mContext); + view.setBackgroundColor(/*0xffffffff*/ bgColor); } - LastSeenRadioCell textCell = (LastSeenRadioCell) view; + RadioCell textCell = (RadioCell) view; + textCell.setTag("Pref"); int checkedType = 0; if (i == everybodyRow) { textCell.setText(LocaleController.getString("LastSeenEverybody", R.string.LastSeenEverybody), lastCheckedType == 0, true); checkedType = 0; } else if (i == myContactsRow) { - textCell.setText(LocaleController.getString("LastSeenContacts", R.string.LastSeenContacts), lastCheckedType == 2, true); + textCell.setText(LocaleController.getString("LastSeenContacts", R.string.LastSeenContacts), lastCheckedType == 2, nobodyRow != -1); checkedType = 2; } else if (i == nobodyRow) { textCell.setText(LocaleController.getString("LastSeenNobody", R.string.LastSeenNobody), lastCheckedType == 1, false); checkedType = 1; } if (lastCheckedType == checkedType) { - textCell.setChecked(false, true); + textCell.setChecked(false, enableAnimation); } else if (currentType == checkedType) { - textCell.setChecked(true, true); + textCell.setChecked(true, enableAnimation); } } return view; @@ -538,9 +623,9 @@ public class LastSeenActivity extends BaseFragment implements NotificationCenter public int getItemViewType(int i) { if (i == alwaysShareRow || i == neverShareRow) { return 0; - } else if (i == shareDetailRow || i == lastSeenDetailRow) { + } else if (i == shareDetailRow || i == detailRow) { return 1; - } else if (i == lastSeenSectionRow || i == shareSectionRow) { + } else if (i == sectionRow || i == shareSectionRow) { return 2; } else if (i == everybodyRow || i == myContactsRow || i == nobodyRow) { return 3; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java index 038c0359..69be3779 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacySettingsActivity.java @@ -23,18 +23,18 @@ import android.widget.FrameLayout; import android.widget.ListView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.ContactsController; -import org.telegram.messenger.LocaleController; -import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.ApplicationLoader; -import org.telegram.tgnet.ConnectionsManager; +import org.telegram.messenger.ContactsController; import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.TLObject; import org.telegram.tgnet.TLRPC; -import org.telegram.messenger.UserConfig; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Adapters.BaseFragmentAdapter; @@ -46,6 +46,8 @@ import org.telegram.ui.Components.LayoutHelper; import java.util.ArrayList; +import static org.telegram.ui.Components.Glow.setEdgeGlowColor; + public class PrivacySettingsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { private ListAdapter listAdapter; @@ -53,7 +55,8 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio private int privacySectionRow; private int blockedRow; private int lastSeenRow; - private int lastSeenDetailRow; + private int groupsRow; + private int groupsDetailRow; private int securitySectionRow; private int sessionsRow; private int passwordRow; @@ -62,7 +65,9 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio private int deleteAccountSectionRow; private int deleteAccountRow; private int deleteAccountDetailRow; - + private int secretSectionRow; + private int secretWebpageRow; + private int secretDetailRow; private int rowCount; @Override @@ -73,10 +78,10 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio rowCount = 0; privacySectionRow = rowCount++; - blockedRow = rowCount++; lastSeenRow = rowCount++; - lastSeenDetailRow = rowCount++; + groupsRow = rowCount++; + groupsDetailRow = rowCount++; securitySectionRow = rowCount++; passcodeRow = rowCount++; passwordRow = rowCount++; @@ -85,6 +90,15 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio deleteAccountSectionRow = rowCount++; deleteAccountRow = rowCount++; deleteAccountDetailRow = rowCount++; + if (MessagesController.getInstance().secretWebpagePreview != 1) { + secretSectionRow = rowCount++; + secretWebpageRow = rowCount++; + secretDetailRow = rowCount++; + } else { + secretSectionRow = -1; + secretWebpageRow = -1; + secretDetailRow = -1; + } NotificationCenter.getInstance().addObserver(this, NotificationCenter.privacyRulesUpdated); @@ -116,10 +130,13 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio fragmentView = new FrameLayout(context); FrameLayout frameLayout = (FrameLayout) fragmentView; frameLayout.setBackgroundColor(0xfff0f0f0); - - ListView listView = new ListView(context); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - listView.setBackgroundColor(preferences.getInt("prefBGColor", 0xffffffff)); + int def = preferences.getInt("themeColor", AndroidUtilities.defColor); + int hColor = preferences.getInt("prefHeaderColor", def); + int bgColor = preferences.getInt("prefBGColor", 0xffffffff); + ListView listView = new ListView(context); + setEdgeGlowColor(listView, hColor); + listView.setBackgroundColor(bgColor); listView.setDivider(null); listView.setDividerHeight(0); listView.setVerticalScrollBarEnabled(false); @@ -190,7 +207,9 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } else if (i == lastSeenRow) { - presentFragment(new LastSeenActivity()); + presentFragment(new PrivacyControlActivity(false)); + } else if (i == groupsRow) { + presentFragment(new PrivacyControlActivity(true)); } else if (i == passwordRow) { presentFragment(new TwoStepVerificationActivity(0)); } else if (i == passcodeRow) { @@ -199,10 +218,20 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } else { presentFragment(new PasscodeActivity(0)); } + } else if (i == secretWebpageRow) { + if (MessagesController.getInstance().secretWebpagePreview == 1) { + MessagesController.getInstance().secretWebpagePreview = 0; + } else { + MessagesController.getInstance().secretWebpagePreview = 1; + } + ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE).edit().putInt("secretWebpage2", MessagesController.getInstance().secretWebpagePreview).commit(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(MessagesController.getInstance().secretWebpagePreview == 1); + } } } }); - + updateTheme(); return fragmentView; } @@ -215,15 +244,16 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } } - private String formatRulesString() { - ArrayList privacyRules = ContactsController.getInstance().getPrivacyRules(); + private String formatRulesString(boolean isGroup) { + ArrayList privacyRules = ContactsController.getInstance().getPrivacyRules(isGroup); if (privacyRules.size() == 0) { return LocaleController.getString("LastSeenNobody", R.string.LastSeenNobody); } int type = -1; int plus = 0; int minus = 0; - for (TLRPC.PrivacyRule rule : privacyRules) { + for (int a = 0; a < privacyRules.size(); a++) { + TLRPC.PrivacyRule rule = privacyRules.get(a); if (rule instanceof TLRPC.TL_privacyValueAllowUsers) { plus += rule.users.size(); } else if (rule instanceof TLRPC.TL_privacyValueDisallowUsers) { @@ -270,7 +300,6 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio if (listAdapter != null) { listAdapter.notifyDataSetChanged(); } - updateTheme(); } private void updateTheme(){ @@ -298,7 +327,10 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio @Override public boolean isEnabled(int i) { - return i == passcodeRow || i == passwordRow || i == blockedRow || i == sessionsRow || i == lastSeenRow && !ContactsController.getInstance().getLoadingLastSeenInfo() || i == deleteAccountRow && !ContactsController.getInstance().getLoadingDeleteInfo(); + return i == passcodeRow || i == passwordRow || i == blockedRow || i == sessionsRow || i == secretWebpageRow || + i == groupsRow && !ContactsController.getInstance().getLoadingGroupInfo() || + i == lastSeenRow && !ContactsController.getInstance().getLoadingLastSeenInfo() || + i == deleteAccountRow && !ContactsController.getInstance().getLoadingDeleteInfo(); } @Override @@ -343,9 +375,17 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio if (ContactsController.getInstance().getLoadingLastSeenInfo()) { value = LocaleController.getString("Loading", R.string.Loading); } else { - value = formatRulesString(); + value = formatRulesString(false); } - textCell.setTextAndValue(LocaleController.getString("PrivacyLastSeen", R.string.PrivacyLastSeen), value, false); + textCell.setTextAndValue(LocaleController.getString("PrivacyLastSeen", R.string.PrivacyLastSeen), value, true); + } else if (i == groupsRow) { + String value; + if (ContactsController.getInstance().getLoadingGroupInfo()) { + value = LocaleController.getString("Loading", R.string.Loading); + } else { + value = formatRulesString(true); + } + textCell.setTextAndValue(LocaleController.getString("GroupsAndChannels", R.string.GroupsAndChannels), value, false); } else if (i == deleteAccountRow) { String value; if (ContactsController.getInstance().getLoadingDeleteInfo()) { @@ -368,13 +408,16 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio } if (i == deleteAccountDetailRow) { ((TextInfoPrivacyCell) view).setText(LocaleController.getString("DeleteAccountHelp", R.string.DeleteAccountHelp)); - view.setBackgroundResource(R.drawable.greydivider_bottom); - } else if (i == lastSeenDetailRow) { - ((TextInfoPrivacyCell) view).setText(LocaleController.getString("LastSeenHelp", R.string.LastSeenHelp)); + view.setBackgroundResource(secretSectionRow == -1 ? R.drawable.greydivider_bottom : R.drawable.greydivider); + } else if (i == groupsDetailRow) { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("GroupsAndChannelsHelp", R.string.GroupsAndChannelsHelp)); view.setBackgroundResource(R.drawable.greydivider); } else if (i == sessionsDetailRow) { ((TextInfoPrivacyCell) view).setText(LocaleController.getString("SessionsInfo", R.string.SessionsInfo)); view.setBackgroundResource(R.drawable.greydivider); + } else if (i == secretDetailRow) { + ((TextInfoPrivacyCell) view).setText(""); + view.setBackgroundResource(R.drawable.greydivider_bottom); } } else if (type == 2) { if (view == null) { @@ -387,6 +430,17 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio ((HeaderCell) view).setText(LocaleController.getString("SecurityTitle", R.string.SecurityTitle)); } else if (i == deleteAccountSectionRow) { ((HeaderCell) view).setText(LocaleController.getString("DeleteAccountTitle", R.string.DeleteAccountTitle)); + } else if (i == secretSectionRow) { + ((HeaderCell) view).setText(LocaleController.getString("SecretChat", R.string.SecretChat)); + } + } else if (type == 3) { + if (view == null) { + view = new TextCheckCell(mContext); + view.setBackgroundColor(0xffffffff); + } + TextCheckCell textCell = (TextCheckCell) view; + if (i == secretWebpageRow) { + textCell.setTextAndCheck(LocaleController.getString("SecretWebPage", R.string.SecretWebPage), MessagesController.getInstance().secretWebpagePreview == 1, true); } } return view; @@ -394,19 +448,21 @@ public class PrivacySettingsActivity extends BaseFragment implements Notificatio @Override public int getItemViewType(int i) { - if (i == lastSeenRow || i == blockedRow || i == deleteAccountRow || i == sessionsRow || i == passwordRow || i == passcodeRow) { + if (i == lastSeenRow || i == blockedRow || i == deleteAccountRow || i == sessionsRow || i == passwordRow || i == passcodeRow || i == groupsRow) { return 0; - } else if (i == deleteAccountDetailRow || i == lastSeenDetailRow || i == sessionsDetailRow) { + } else if (i == deleteAccountDetailRow || i == groupsDetailRow || i == sessionsDetailRow || i == secretDetailRow) { return 1; - } else if (i == securitySectionRow || i == deleteAccountSectionRow || i == privacySectionRow) { + } else if (i == securitySectionRow || i == deleteAccountSectionRow || i == privacySectionRow || i == secretSectionRow) { return 2; + } else if (i == secretWebpageRow) { + return 3; } return 0; } @Override public int getViewTypeCount() { - return 3; + return 4; } @Override diff --git a/TMessagesProj/src/main/java/org/telegram/ui/LastSeenUsersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyUsersActivity.java similarity index 85% rename from TMessagesProj/src/main/java/org/telegram/ui/LastSeenUsersActivity.java rename to TMessagesProj/src/main/java/org/telegram/ui/PrivacyUsersActivity.java index 3f145820..add07e2f 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/LastSeenUsersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/PrivacyUsersActivity.java @@ -12,8 +12,6 @@ import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; -import android.graphics.PorterDuff; -import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.view.Gravity; @@ -27,10 +25,10 @@ import android.widget.TextView; import org.telegram.PhoneFormat.PhoneFormat; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; -import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.R; import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; @@ -43,9 +41,9 @@ import org.telegram.ui.Components.LayoutHelper; import java.util.ArrayList; -public class LastSeenUsersActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { +public class PrivacyUsersActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { - public interface LastSeenUsersActivityDelegate { + public interface PrivacyActivityDelegate { void didUpdatedUserList(ArrayList ids, boolean added); } @@ -53,17 +51,20 @@ public class LastSeenUsersActivity extends BaseFragment implements NotificationC private ListAdapter listViewAdapter; private int selectedUserId; + private boolean isGroup; + private ArrayList uidArray; private boolean isAlwaysShare; - private LastSeenUsersActivityDelegate delegate; + private PrivacyActivityDelegate delegate; private final static int block_user = 1; - public LastSeenUsersActivity(ArrayList users, boolean always) { + public PrivacyUsersActivity(ArrayList users, boolean group, boolean always) { super(); uidArray = users; isAlwaysShare = always; + isGroup = group; } @Override @@ -83,11 +84,20 @@ public class LastSeenUsersActivity extends BaseFragment implements NotificationC public View createView(Context context) { actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAllowOverlayTitle(true); - if (isAlwaysShare) { - actionBar.setTitle(LocaleController.getString("AlwaysShareWithTitle", R.string.AlwaysShareWithTitle)); + if (isGroup) { + if (isAlwaysShare) { + actionBar.setTitle(LocaleController.getString("AlwaysAllow", R.string.AlwaysAllow)); + } else { + actionBar.setTitle(LocaleController.getString("NeverAllow", R.string.NeverAllow)); + } } else { - actionBar.setTitle(LocaleController.getString("NeverShareWithTitle", R.string.NeverShareWithTitle)); + if (isAlwaysShare) { + actionBar.setTitle(LocaleController.getString("AlwaysShareWithTitle", R.string.AlwaysShareWithTitle)); + } else { + actionBar.setTitle(LocaleController.getString("NeverShareWithTitle", R.string.NeverShareWithTitle)); + } } + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(int id) { @@ -96,6 +106,7 @@ public class LastSeenUsersActivity extends BaseFragment implements NotificationC } else if (id == block_user) { Bundle args = new Bundle(); args.putBoolean(isAlwaysShare ? "isAlwaysShare" : "isNeverShare", true); + args.putBoolean("isGroup", isGroup); GroupCreateActivity fragment = new GroupCreateActivity(args); fragment.setDelegate(new GroupCreateActivity.GroupCreateActivityDelegate() { @Override @@ -143,8 +154,6 @@ public class LastSeenUsersActivity extends BaseFragment implements NotificationC }); listView = new ListView(context); - SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - listView.setBackgroundColor(preferences.getInt("prefBGColor", 0xffffffff)); listView.setEmptyView(emptyTextView); listView.setVerticalScrollBarEnabled(false); listView.setDivider(null); @@ -223,8 +232,8 @@ public class LastSeenUsersActivity extends BaseFragment implements NotificationC } } - public void setDelegate(LastSeenUsersActivityDelegate delegate) { - this.delegate = delegate; + public void setDelegate(PrivacyActivityDelegate privacyActivityDelegate) { + delegate = privacyActivityDelegate; } @Override @@ -233,18 +242,6 @@ public class LastSeenUsersActivity extends BaseFragment implements NotificationC if (listViewAdapter != null) { listViewAdapter.notifyDataSetChanged(); } - updateTheme(); - } - - private void updateTheme(){ - SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); - int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); - actionBar.setBackgroundColor(themePrefs.getInt("prefHeaderColor", def)); - actionBar.setTitleColor(themePrefs.getInt("prefHeaderTitleColor", 0xffffffff)); - - Drawable back = getParentActivity().getResources().getDrawable(R.drawable.ic_ab_back); - back.setColorFilter(themePrefs.getInt("prefHeaderIconsColor", 0xffffffff), PorterDuff.Mode.MULTIPLY); - actionBar.setBackButtonDrawable(back); } private class ListAdapter extends BaseFragmentAdapter { @@ -290,9 +287,10 @@ public class LastSeenUsersActivity extends BaseFragment implements NotificationC @Override public View getView(int i, View view, ViewGroup viewGroup) { int type = getItemViewType(i); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); if (type == 0) { if (view == null) { - view = new UserCell(mContext, 1, 0); + view = new UserCell(mContext, 1, 0, false); } TLRPC.User user = MessagesController.getInstance().getUser(uidArray.get(i)); ((UserCell)view).setData(user, null, user.phone != null && user.phone.length() != 0 ? PhoneFormat.getInstance().format("+" + user.phone) : LocaleController.getString("NumberUnknown", R.string.NumberUnknown), 0); @@ -300,6 +298,7 @@ public class LastSeenUsersActivity extends BaseFragment implements NotificationC if (view == null) { view = new TextInfoCell(mContext); ((TextInfoCell) view).setText(LocaleController.getString("RemoveFromListText", R.string.RemoveFromListText)); + view.setBackgroundColor(themePrefs.getInt("prefBGColor", 0xffffffff)); } } return view; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java index dec804f1..3a807444 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileActivity.java @@ -20,16 +20,17 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.Bitmap; +import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Outline; +import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.text.TextUtils; -import android.util.TypedValue; +import android.os.Handler; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; @@ -40,7 +41,7 @@ import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; -import android.widget.TextView; +import android.widget.ListAdapter; import android.widget.Toast; import org.telegram.PhoneFormat.PhoneFormat; @@ -51,6 +52,7 @@ import org.telegram.messenger.AnimationCompat.ObjectAnimatorProxy; import org.telegram.messenger.AnimationCompat.ViewProxy; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.BuildConfig; +import org.telegram.messenger.BuildVars; import org.telegram.messenger.ChatObject; import org.telegram.messenger.ContactsController; import org.telegram.messenger.FileLog; @@ -78,6 +80,8 @@ import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.BackDrawable; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.SimpleTextView; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Cells.AboutLinkCell; import org.telegram.ui.Cells.DividerCell; import org.telegram.ui.Cells.EmptyCell; @@ -101,20 +105,21 @@ import java.util.Comparator; import java.util.HashMap; import java.util.concurrent.Semaphore; -public class ProfileActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, DialogsActivity.MessagesActivityDelegate, PhotoViewer.PhotoViewerProvider { +public class ProfileActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate, DialogsActivity.DialogsActivityDelegate, PhotoViewer.PhotoViewerProvider { private RecyclerListView listView; private LinearLayoutManager layoutManager; private ListAdapter listAdapter; private BackupImageView avatarImage; - private TextView nameTextView[] = new TextView[2]; - private TextView onlineTextView[] = new TextView[2]; + private SimpleTextView nameTextView[] = new SimpleTextView[2]; + private SimpleTextView onlineTextView[] = new SimpleTextView[2]; private ImageView writeButton; private AnimatorSetProxy writeButtonAnimation; - private View extraHeightView; - private View shadowView; + //private View extraHeightView; + //private View shadowView; private AvatarDrawable avatarDrawable; private ActionBarMenuItem animatingItem; + private TopView topView; private int user_id; private int chat_id; private long dialog_id; @@ -123,8 +128,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private long mergeDialogId; private boolean loadingUsers; - private ArrayList participants = new ArrayList<>(); - private HashMap participantsMap = new HashMap<>(); + private HashMap participantsMap = new HashMap<>(); private boolean usersEndReached; private boolean openAnimationInProgress; @@ -145,21 +149,27 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private int totalMediaCount = -1; private int totalMediaCountMerge = -1; + private int totalFilesCount = -1; + private int totalFilesCountMerge = -1; + private int totalMusicCount = -1; + private int totalMusicCountMerge = -1; + private int totalLinksCount = -1; + private int totalLinksCountMerge = -1; + boolean hideMedia, hideFiles, hideMusic, hideLinks; private final static int add_contact = 1; private final static int block_contact = 2; private final static int share_contact = 3; private final static int edit_contact = 4; private final static int delete_contact = 5; - //private final static int add_member = 6; private final static int leave_group = 7; private final static int edit_name = 8; private final static int invite_to_group = 9; private final static int share = 10; private final static int set_admins = 11; private final static int edit_channel = 12; + private final static int convert_to_supergroup = 13; - private int overscrollRow; private int emptyRow; private int emptyRowChat; private int emptyRowChat2; @@ -173,22 +183,64 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private int convertHelpRow; private int settingsNotificationsRow; private int sharedMediaRow; + private int sharedFilesRow; + private int sharedMusicRow; + private int sharedLinksRow; private int membersRow; private int managementRow; private int blockedUsersRow; private int leaveChannelRow; private int startSecretChatRow; private int sectionRow; - private int botSectionRow; - private int botInfoRow; + private int userSectionRow; + private int userInfoRow; private int membersSectionRow; private int membersEndRow; private int loadMoreMembersRow; private int addMemberRow; private int rowCount = 0; - private TextView adminTextView; + private SimpleTextView adminTextView; private int creatorID; + //private AboutLinkCell aboutLinkCell; + private String userAbout; + private int linkSearchRequestId; + private TLRPC.WebPage foundWebPage; + private int pass; + private int topViewColor; + + private class TopView extends View { + + private int currentColor; + private Paint paint = new Paint(); + + public TopView(Context context) { + super(context); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), ActionBar.getCurrentActionBarHeight() + (!AndroidUtilities.isTablet() ? AndroidUtilities.statusBarHeight : 0) + AndroidUtilities.dp(91)); + } + + @Override + public void setBackgroundColor(int color) { + if (color != currentColor) { + paint.setColor(color); + invalidate(); + } + } + + @Override + protected void onDraw(Canvas canvas) { + int height = getMeasuredHeight() - AndroidUtilities.dp(91); + paint.setColor(topViewColor); //plus + canvas.drawRect(0, 0, getMeasuredWidth(), height + extraHeight, paint); + if (parentLayout != null) { + parentLayout.drawHeaderShadow(canvas, height + extraHeight); + } + } + } public ProfileActivity(Bundle args) { super(args); @@ -213,6 +265,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. NotificationCenter.getInstance().addObserver(this, NotificationCenter.encryptedChatUpdated); NotificationCenter.getInstance().addObserver(this, NotificationCenter.blockedUsersDidLoaded); NotificationCenter.getInstance().addObserver(this, NotificationCenter.botInfoDidLoaded); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.userInfoDidLoaded); if (currentEncryptedChat != null) { NotificationCenter.getInstance().addObserver(this, NotificationCenter.didReceivedNewMessages); } @@ -220,8 +273,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (user.bot) { BotQuery.loadBotInfo(user.id, true, classGuid); } - MessagesController.getInstance().loadFullUser(MessagesController.getInstance().getUser(user_id), classGuid); - participants = null; + MessagesController.getInstance().loadFullUser(MessagesController.getInstance().getUser(user_id), classGuid, true); participantsMap = null; } else if (chat_id != 0) { currentChat = MessagesController.getInstance().getChat(chat_id); @@ -249,7 +301,6 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (currentChat.megagroup) { getChannelParticipants(true); } else { - participants = null; participantsMap = null; } NotificationCenter.getInstance().addObserver(this, NotificationCenter.chatInfoDidLoaded); @@ -267,18 +318,56 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } }; avatarUpdater.parentFragment = this; + + if (ChatObject.isChannel(currentChat)) { + MessagesController.getInstance().loadFullChat(chat_id, classGuid, true); + } } else { return false; } + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + hideMedia = preferences.getBoolean("hideSharedMedia", false); + hideFiles = preferences.getBoolean("hideSharedFiles", false); + hideMusic = preferences.getBoolean("hideSharedMusic", false); + hideLinks = !BuildVars.DEBUG_VERSION || preferences.getBoolean("hideSharedLinks", false); + if (dialog_id != 0) { - SharedMediaQuery.getMediaCount(dialog_id, SharedMediaQuery.MEDIA_PHOTOVIDEO, classGuid, true); + if(!hideMedia) + SharedMediaQuery.getMediaCount(dialog_id, SharedMediaQuery.MEDIA_PHOTOVIDEO, classGuid, true); + if(!hideFiles) + SharedMediaQuery.getMediaCount(dialog_id, SharedMediaQuery.MEDIA_FILE, classGuid, true); + if(!hideMusic) + SharedMediaQuery.getMediaCount(dialog_id, SharedMediaQuery.MEDIA_MUSIC, classGuid, true); + if(!hideLinks) + SharedMediaQuery.getMediaCount(dialog_id, SharedMediaQuery.MEDIA_URL, classGuid, true); } else if (user_id != 0) { - SharedMediaQuery.getMediaCount(user_id, SharedMediaQuery.MEDIA_PHOTOVIDEO, classGuid, true); + if(!hideMedia) + SharedMediaQuery.getMediaCount(user_id, SharedMediaQuery.MEDIA_PHOTOVIDEO, classGuid, true); + if(!hideFiles) + SharedMediaQuery.getMediaCount(user_id, SharedMediaQuery.MEDIA_FILE, classGuid, true); + if(!hideMusic) + SharedMediaQuery.getMediaCount(user_id, SharedMediaQuery.MEDIA_MUSIC, classGuid, true); + if(!hideLinks) + SharedMediaQuery.getMediaCount(user_id, SharedMediaQuery.MEDIA_URL, classGuid, true); } else if (chat_id > 0) { - SharedMediaQuery.getMediaCount(-chat_id, SharedMediaQuery.MEDIA_PHOTOVIDEO, classGuid, true); + if(!hideMedia) + SharedMediaQuery.getMediaCount(-chat_id, SharedMediaQuery.MEDIA_PHOTOVIDEO, classGuid, true); + if(!hideFiles) + SharedMediaQuery.getMediaCount(-chat_id, SharedMediaQuery.MEDIA_FILE, classGuid, true); + if(!hideMusic) + SharedMediaQuery.getMediaCount(-chat_id, SharedMediaQuery.MEDIA_MUSIC, classGuid, true); + if(!hideLinks) + SharedMediaQuery.getMediaCount(-chat_id, SharedMediaQuery.MEDIA_URL, classGuid, true); if (mergeDialogId != 0) { - SharedMediaQuery.getMediaCount(mergeDialogId, SharedMediaQuery.MEDIA_PHOTOVIDEO, classGuid, true); + if(!hideMedia) + SharedMediaQuery.getMediaCount(mergeDialogId, SharedMediaQuery.MEDIA_PHOTOVIDEO, classGuid, true); + if(!hideFiles) + SharedMediaQuery.getMediaCount(mergeDialogId, SharedMediaQuery.MEDIA_FILE, classGuid, true); + if(!hideMusic) + SharedMediaQuery.getMediaCount(mergeDialogId, SharedMediaQuery.MEDIA_MUSIC, classGuid, true); + if(!hideLinks) + SharedMediaQuery.getMediaCount(mergeDialogId, SharedMediaQuery.MEDIA_URL, classGuid, true); } } @@ -286,7 +375,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. NotificationCenter.getInstance().addObserver(this, NotificationCenter.updateInterfaces); NotificationCenter.getInstance().addObserver(this, NotificationCenter.closeChats); updateRowsIds(); - + if(BuildConfig.DEBUG){ + getUserAbout(user_id); + } return true; } @@ -305,6 +396,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. NotificationCenter.getInstance().removeObserver(this, NotificationCenter.encryptedChatUpdated); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.blockedUsersDidLoaded); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.botInfoDidLoaded); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.userInfoDidLoaded); MessagesController.getInstance().cancelLoadFullUser(user_id); if (currentEncryptedChat != null) { NotificationCenter.getInstance().removeObserver(this, NotificationCenter.didReceivedNewMessages); @@ -316,21 +408,31 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } @Override - public View createView(Context context) { + protected ActionBar createActionBar(Context context) { + ActionBar actionBar = new ActionBar(context) { + @Override + public boolean onTouchEvent(MotionEvent event) { + return super.onTouchEvent(event); //TODO + } + }; + actionBar.setItemsBackgroundColor(AvatarDrawable.getButtonColorForId(user_id != 0 || ChatObject.isChannel(chat_id) && !currentChat.megagroup ? 5 : chat_id)); + //actionBar.setBackButtonDrawable(new BackDrawable(false)); SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); actionBar.setBackgroundColor(AvatarDrawable.getProfileBackColorForId(user_id != 0 || ChatObject.isChannel(chat_id) && !currentChat.megagroup ? 5 : chat_id)); - actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(user_id != 0 || ChatObject.isChannel(chat_id) && !currentChat.megagroup ? 5 : chat_id)); - //actionBar.setBackButtonDrawable(new BackDrawable(false)); + //actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(user_id != 0 || ChatObject.isChannel(chat_id) && !currentChat.megagroup ? 5 : chat_id)); Drawable back = new BackDrawable(false); ((BackDrawable) back).setColor(themePrefs.getInt("profileHeaderIconsColor", 0xffffffff)); actionBar.setBackButtonDrawable(back); actionBar.setCastShadows(false); actionBar.setAddToContainer(false); + actionBar.setOccupyStatusBar(!AndroidUtilities.isTablet()); + return actionBar; + } + + @Override + public View createView(Context context) { hasOwnBackground = true; extraHeight = 88; - if (AndroidUtilities.isTablet()) { - actionBar.setOccupyStatusBar(false); - } actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @Override public void onItemClick(final int id) { @@ -369,7 +471,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. MessagesController.getInstance().blockUser(user_id); } else { MessagesController.getInstance().unblockUser(user_id); - SendMessagesHelper.getInstance().sendMessage("/start", user_id, null, null, false, false, null, null); + SendMessagesHelper.getInstance().sendMessage("/start", user_id, null, null, false, false, null, null, null); finishFragment(); } } @@ -432,15 +534,19 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. args.putInt("dialogsType", 2); args.putString("addToGroupAlertString", LocaleController.formatString("AddToTheGroupTitle", R.string.AddToTheGroupTitle, UserObject.getUserName(user), "%1$s")); DialogsActivity fragment = new DialogsActivity(args); - fragment.setDelegate(new DialogsActivity.MessagesActivityDelegate() { + fragment.setDelegate(new DialogsActivity.DialogsActivityDelegate() { @Override public void didSelectDialog(DialogsActivity fragment, long did, boolean param) { - NotificationCenter.getInstance().removeObserver(ProfileActivity.this, NotificationCenter.closeChats); - NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); - MessagesController.getInstance().addUserToChat(-(int) did, user, null, 0, null, ProfileActivity.this); Bundle args = new Bundle(); args.putBoolean("scrollToTopOnResume", true); args.putInt("chat_id", -(int) did); + if (!MessagesController.checkCanOpenChat(args, fragment)) { + return; + } + + NotificationCenter.getInstance().removeObserver(ProfileActivity.this, NotificationCenter.closeChats); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); + MessagesController.getInstance().addUserToChat(-(int) did, user, null, 0, null, ProfileActivity.this); presentFragment(new ChatActivity(args), true); removeSelfFromStack(); } @@ -454,8 +560,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("text/plain"); - if (botInfo != null && botInfo.share_text != null && botInfo.share_text.length() > 0) { - intent.putExtra(Intent.EXTRA_TEXT, String.format("%s https://telegram.me/%s", botInfo.share_text, user.username)); + String about = MessagesController.getInstance().getUserAbout(botInfo.user_id); + if (botInfo != null && about != null) { + intent.putExtra(Intent.EXTRA_TEXT, String.format("%s https://telegram.me/%s", about, user.username)); } else { intent.putExtra(Intent.EXTRA_TEXT, String.format("https://telegram.me/%s", user.username)); } @@ -469,6 +576,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. SetAdminsActivity fragment = new SetAdminsActivity(args); fragment.setChatInfo(info); presentFragment(fragment); + } else if (id == convert_to_supergroup) { + Bundle args = new Bundle(); + args.putInt("chat_id", chat_id); + presentFragment(new ConvertGroupActivity(args)); } } }); @@ -484,6 +595,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. public boolean hasOverlappingRendering() { return false; } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + checkListViewScroll(); + } }; FrameLayout frameLayout = (FrameLayout) fragmentView; @@ -493,10 +610,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. return false; } }; + listView.setPadding(0, AndroidUtilities.dp(88), 0, 0); //listView.setBackgroundColor(0xffffffff); listView.setVerticalScrollBarEnabled(false); listView.setItemAnimator(null); listView.setLayoutAnimation(null); + listView.setClipToPadding(false); layoutManager = new LinearLayoutManager(context) { @Override public boolean supportsPredictiveItemAnimations() { @@ -525,6 +644,39 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. MediaActivity fragment = new MediaActivity(args); fragment.setChatInfo(info); presentFragment(fragment); + } else if (position == sharedMusicRow) { + Bundle args = new Bundle(); + if (user_id != 0) { + args.putLong("dialog_id", dialog_id != 0 ? dialog_id : user_id); + } else { + args.putLong("dialog_id", -chat_id); + } + args.putInt("selected_mode", 4); + MediaActivity fragment = new MediaActivity(args); + fragment.setChatInfo(info); + presentFragment(fragment); + } else if (position == sharedLinksRow) { + Bundle args = new Bundle(); + if (user_id != 0) { + args.putLong("dialog_id", dialog_id != 0 ? dialog_id : user_id); + } else { + args.putLong("dialog_id", -chat_id); + } + args.putInt("selected_mode", 3); + MediaActivity fragment = new MediaActivity(args); + fragment.setChatInfo(info); + presentFragment(fragment); + } else if (position == sharedFilesRow) { + Bundle args = new Bundle(); + if (user_id != 0) { + args.putLong("dialog_id", dialog_id != 0 ? dialog_id : user_id); + } else { + args.putLong("dialog_id", -chat_id); + } + args.putInt("selected_mode", 1); + MediaActivity fragment = new MediaActivity(args); + fragment.setChatInfo(info); + presentFragment(fragment); } else if (position == settingsKeyRow) { Bundle args = new Bundle(); args.putInt("chat_id", (int) (dialog_id >> 32)); @@ -630,10 +782,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. showDialog(builder.create()); } else if (position > emptyRowChat2 && position < membersEndRow) { int user_id; - if (participants != null) { - user_id = participants.get(position - emptyRowChat2 - 1).user_id; - } else { + if (!sortedUsers.isEmpty()) { user_id = info.participants.participants.get(sortedUsers.get(position - emptyRowChat2 - 1)).user_id; + } else { + user_id = info.participants.participants.get(position - emptyRowChat2 - 1).user_id; } if (user_id == UserConfig.getClientUserId()) { return; @@ -724,10 +876,30 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } }); showDialog(builder.create()); + } else if (position == userInfoRow) { + /*AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setItems(new CharSequence[]{LocaleController.getString("Copy", R.string.Copy)}, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + try { + if (Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(botInfo.share_text); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", botInfo.share_text); + clipboard.setPrimaryClip(clip); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + showDialog(builder.create());*/ } else if (position == convertRow) { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setMessage(LocaleController.getString("ConvertGroupAlert", R.string.ConvertGroupAlert)); - builder.setTitle(LocaleController.getString("AppName", R.string.AppName)); + builder.setTitle(LocaleController.getString("ConvertGroupAlertWarning", R.string.ConvertGroupAlertWarning)); builder.setPositiveButton(LocaleController.getString("OK", R.string.OK), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { @@ -736,11 +908,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. }); builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); + } else { + processOnClickOrPress(position); } } }); - if (chat_id != 0) { listView.setOnItemLongClickListener(new RecyclerListView.OnItemLongClickListener() { @Override public boolean onItemClick(View view, int position) { @@ -750,10 +923,18 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } boolean allowKick = false; boolean allowSetAdmin = false; - TLRPC.ChannelParticipant channelParticipant = null; + + final TLRPC.ChatParticipant user; + if (!sortedUsers.isEmpty()) { + user = info.participants.participants.get(sortedUsers.get(position - emptyRowChat2 - 1)); + } else { + user = info.participants.participants.get(position - emptyRowChat2 - 1); + } + selectedUser = user.user_id; + if (ChatObject.isChannel(currentChat)) { - channelParticipant = participants.get(position - emptyRowChat2 - 1); - if (channelParticipant.user_id != UserConfig.getClientUserId()) { + TLRPC.ChannelParticipant channelParticipant = ((TLRPC.TL_chatChannelParticipant) user).channelParticipant; + if (user.user_id != UserConfig.getClientUserId()) { if (currentChat.creator) { allowKick = true; } else if (channelParticipant instanceof TLRPC.TL_channelParticipant) { @@ -762,11 +943,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } } - TLRPC.User u = MessagesController.getInstance().getUser(channelParticipant.user_id); + TLRPC.User u = MessagesController.getInstance().getUser(user.user_id); allowSetAdmin = channelParticipant instanceof TLRPC.TL_channelParticipant && !u.bot; - selectedUser = channelParticipant.user_id; } else { - TLRPC.ChatParticipant user = info.participants.participants.get(sortedUsers.get(position - emptyRowChat2 - 1)); if (user.user_id != UserConfig.getClientUserId()) { if (currentChat.creator) { allowKick = true; @@ -776,27 +955,24 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } } - selectedUser = user.user_id; } if (!allowKick) { return false; } AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); if (currentChat.megagroup && currentChat.creator && allowSetAdmin) { - final TLRPC.ChannelParticipant channelParticipantFinal = channelParticipant; CharSequence[] items = new CharSequence[]{LocaleController.getString("SetAsAdmin", R.string.SetAsAdmin), LocaleController.getString("KickFromGroup", R.string.KickFromGroup)}; builder.setItems(items, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { if (i == 0) { - int index = participants.indexOf(channelParticipantFinal); - if (index != -1) { - TLRPC.TL_channelParticipantEditor editor = new TLRPC.TL_channelParticipantEditor(); - editor.inviter_id = UserConfig.getClientUserId(); - editor.user_id = channelParticipantFinal.user_id; - editor.date = channelParticipantFinal.date; - participants.set(index, editor); - } + TLRPC.TL_chatChannelParticipant channelParticipant = ((TLRPC.TL_chatChannelParticipant) user); + + channelParticipant.channelParticipant = new TLRPC.TL_channelParticipantEditor(); + channelParticipant.channelParticipant.inviter_id = UserConfig.getClientUserId(); + channelParticipant.channelParticipant.user_id = user.user_id; + channelParticipant.channelParticipant.date = user.date; + TLRPC.TL_channels_editAdmin req = new TLRPC.TL_channels_editAdmin(); req.channel = MessagesController.getInputChannel(chat_id); req.user_id = MessagesController.getInputUser(selectedUser); @@ -840,30 +1016,22 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } showDialog(builder.create()); return true; - } - return false; + } else { + return processOnClickOrPress(position); } - }); - } + } + }); + + topView = new TopView(context); + //topView.setBackgroundColor(AvatarDrawable.getProfileBackColorForId(user_id != 0 || ChatObject.isChannel(chat_id) && !currentChat.megagroup ? 5 : chat_id)); + frameLayout.addView(topView); frameLayout.addView(actionBar); - extraHeightView = new View(context); - ViewProxy.setPivotY(extraHeightView, 0); - //extraHeightView.setBackgroundColor(AvatarDrawable.getProfileBackColorForId(user_id != 0 || ChatObject.isChannel(chat_id) && !currentChat.megagroup ? 5 : chat_id)); - frameLayout.addView(extraHeightView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 88)); - - shadowView = new View(context); - try { - shadowView.setBackgroundResource(R.drawable.header_shadow); - } catch (Throwable e) { - FileLog.e("tmessages", e); - } - frameLayout.addView(shadowView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, 3)); - avatarImage = new BackupImageView(context); //avatarImage.setRoundRadius(AndroidUtilities.dp(21)); //Plus: user profile avatar + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); int radius = AndroidUtilities.dp(themePrefs.getInt("profileAvatarRadius", 32)); avatarImage.setRoundRadius(radius); ViewProxy.setPivotX(avatarImage, 0); @@ -895,46 +1063,41 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (!playProfileAnimation && a == 0) { continue; } - nameTextView[a] = new TextView(context); + nameTextView[a] = new SimpleTextView(context); //nameTextView[a].setTextColor(0xffffffff); + //nameTextView[a].setTextSize(18); nameTextView[a].setTextColor(themePrefs.getInt("profileNameColor", 0xffffffff)); - //nameTextView[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); - nameTextView[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, themePrefs.getInt("profileNameSize", 18)); - nameTextView[a].setLines(1); - nameTextView[a].setMaxLines(1); - nameTextView[a].setSingleLine(true); - nameTextView[a].setEllipsize(TextUtils.TruncateAt.END); + nameTextView[a].setTextSize(themePrefs.getInt("profileNameSize", 18)); + //nameTextView[a].setLines(1); + //nameTextView[a].setMaxLines(1); + //nameTextView[a].setSingleLine(true); + //nameTextView[a].setEllipsize(TextUtils.TruncateAt.END); nameTextView[a].setGravity(Gravity.LEFT); nameTextView[a].setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - nameTextView[a].setCompoundDrawablePadding(AndroidUtilities.dp(4)); + nameTextView[a].setLeftDrawableTopPadding(-AndroidUtilities.dp(1.3f)); + nameTextView[a].setRightDrawableTopPadding(-AndroidUtilities.dp(1.3f)); ViewProxy.setPivotX(nameTextView[a], 0); ViewProxy.setPivotY(nameTextView[a], 0); frameLayout.addView(nameTextView[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 118, 0, a == 0 ? 48 : 0, 0)); - onlineTextView[a] = new TextView(context); + onlineTextView[a] = new SimpleTextView(context); //onlineTextView[a].setTextColor(AvatarDrawable.getProfileTextColorForId(user_id != 0 || ChatObject.isChannel(chat_id) && !currentChat.megagroup ? 5 : chat_id)); + //onlineTextView[a].setTextSize(14); onlineTextView[a].setTextColor(dark); - //onlineTextView[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); - onlineTextView[a].setTextSize(TypedValue.COMPLEX_UNIT_DIP, oSize); - onlineTextView[a].setLines(1); - onlineTextView[a].setMaxLines(1); - onlineTextView[a].setSingleLine(true); - onlineTextView[a].setEllipsize(TextUtils.TruncateAt.END); + onlineTextView[a].setTextSize(oSize); + //onlineTextView[a].setLines(1); + //onlineTextView[a].setMaxLines(1); + //onlineTextView[a].setSingleLine(true); + //onlineTextView[a].setEllipsize(TextUtils.TruncateAt.END); onlineTextView[a].setGravity(Gravity.LEFT); frameLayout.addView(onlineTextView[a], LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 118, 0, a == 0 ? 48 : 8, 0)); } - adminTextView = new TextView(context); - adminTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14); + adminTextView = new SimpleTextView(context); adminTextView.setTextColor(dark); - if (oSize < 14)adminTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, oSize); - adminTextView.setLines(1); - adminTextView.setMaxLines(1); - adminTextView.setSingleLine(true); - adminTextView.setEllipsize(TextUtils.TruncateAt.END); + adminTextView.setTextSize(oSize < 14 ? oSize : 14); adminTextView.setGravity(Gravity.LEFT); adminTextView.setTypeface(AndroidUtilities.getTypeface("fonts/rmedium.ttf")); - frameLayout.addView(adminTextView, LayoutHelper.createFrame(LayoutHelper.WRAP_CONTENT, LayoutHelper.WRAP_CONTENT, Gravity.LEFT | Gravity.TOP, 118, 0, 48, 0)); if (user_id != 0 || chat_id >= 0 && !ChatObject.isLeftFromChat(currentChat)) { @@ -988,10 +1151,13 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (user == null || user instanceof TLRPC.TL_userEmpty) { return; } - NotificationCenter.getInstance().removeObserver(ProfileActivity.this, NotificationCenter.closeChats); - NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); - Bundle args = new Bundle(); - args.putInt("user_id", user_id); + Bundle args = new Bundle(); + args.putInt("user_id", user_id); + if (!MessagesController.checkCanOpenChat(args, ProfileActivity.this)) { + return; + } + NotificationCenter.getInstance().removeObserver(ProfileActivity.this, NotificationCenter.closeChats); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); presentFragment(new ChatActivity(args), true); } } else if (chat_id != 0) { @@ -1000,10 +1166,13 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (playProfileAnimation && parentLayout.fragmentsStack.get(parentLayout.fragmentsStack.size() - 2) instanceof ChatActivity) { finishFragment(); } else { - NotificationCenter.getInstance().removeObserver(ProfileActivity.this, NotificationCenter.closeChats); - NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); Bundle args = new Bundle(); args.putInt("chat_id", currentChat.id); + if (!MessagesController.checkCanOpenChat(args, ProfileActivity.this)) { + return; + } + NotificationCenter.getInstance().removeObserver(ProfileActivity.this, NotificationCenter.closeChats); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); presentFragment(new ChatActivity(args), true); } } else { @@ -1034,27 +1203,166 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } }); } + needLayout(); listView.setOnScrollListener(new RecyclerView.OnScrollListener() { - @Override - public void onScrollStateChanged(RecyclerView recyclerView, int newState) { - super.onScrollStateChanged(recyclerView, newState); - } - @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { checkListViewScroll(); - if (participants != null && loadMoreMembersRow != -1 && layoutManager.findLastVisibleItemPosition() > loadMoreMembersRow - 8) { + if (participantsMap != null && loadMoreMembersRow != -1 && layoutManager.findLastVisibleItemPosition() > loadMoreMembersRow - 8) { getChannelParticipants(false); } } }); updateListBG(); - updateActionBarBG(); + //updateActionBarBG(); return fragmentView; } + private boolean processOnClickOrPress(final int position) { + if (position == usernameRow) { + final TLRPC.User user = MessagesController.getInstance().getUser(user_id); + if (user == null || user.username == null) { + return false; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setItems(new CharSequence[]{LocaleController.getString("Copy", R.string.Copy)}, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (i == 0) { + try { + if (Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText("@" + user.username); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", "@" + user.username); + clipboard.setPrimaryClip(clip); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + }); + showDialog(builder.create()); + return true; + } else if (position == phoneRow) { + final TLRPC.User user = MessagesController.getInstance().getUser(user_id); + if (user == null || user.phone == null || user.phone.length() == 0 || getParentActivity() == null) { + return false; + } + + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setItems(new CharSequence[]{LocaleController.getString("Call", R.string.Call), LocaleController.getString("Copy", R.string.Copy)}, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (i == 0) { + try { + Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:+" + user.phone)); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + getParentActivity().startActivityForResult(intent, 500); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else if (i == 1) { + try { + if (Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText("+" + user.phone); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", "+" + user.phone); + clipboard.setPrimaryClip(clip); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + }); + showDialog(builder.create()); + return true; + } else if (position == channelInfoRow || position == userInfoRow) { + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setItems(new CharSequence[]{LocaleController.getString("Copy", R.string.Copy)}, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + try { + String about; + if (position == channelInfoRow) { + about = info.about; + } else { + about = MessagesController.getInstance().getUserAbout(botInfo.user_id); + } + if (about == null) { + return; + } + if (Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(about); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", about); + clipboard.setPrimaryClip(clip); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + }); + showDialog(builder.create()); + return true; + } + return false; + } + + public void getUserAbout(final int uid) { + final TLRPC.User user = MessagesController.getInstance().getUser(uid); + if(user == null || user.username == null){ + return; + } + String link = String.format("https://telegram.me/%s", user.username); + //Log.e("ProfileActivity", "getUserAbout link "+link); + userAbout = null; + final TLRPC.TL_messages_getWebPagePreview req = new TLRPC.TL_messages_getWebPagePreview(); + req.message = link; + + linkSearchRequestId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + linkSearchRequestId = 0; + if (error == null) { + if (response instanceof TLRPC.TL_messageMediaWebPage) { + foundWebPage = ((TLRPC.TL_messageMediaWebPage) response).webpage; + if(foundWebPage.description != null){ + userAbout = foundWebPage.description; + NotificationCenter.getInstance().postNotificationName(NotificationCenter.userInfoDidLoaded, uid); + } else{ + if(pass != 1){ + pass = 1; + final Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + @Override + public void run() { + getUserAbout(uid); + } + }, 500); + } + } + } + } + } + }); + } + }); + ConnectionsManager.getInstance().bindRequestToGuid(linkSearchRequestId, classGuid); + } + private void leaveChatPressed() { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); if (ChatObject.isChannel(chat_id) && !currentChat.megagroup) { @@ -1100,17 +1408,17 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } private void getChannelParticipants(boolean reload) { - if (loadingUsers || participants == null) { + if (loadingUsers || participantsMap == null || info == null) { return; } loadingUsers = true; - final int delay = Build.VERSION.SDK_INT >= 11 && !participants.isEmpty() && reload ? 300 : 0; + final int delay = Build.VERSION.SDK_INT >= 11 && !participantsMap.isEmpty() && reload ? 300 : 0; final TLRPC.TL_channels_getParticipants req = new TLRPC.TL_channels_getParticipants(); req.channel = MessagesController.getInputChannel(chat_id); req.filter = new TLRPC.TL_channelParticipantsRecent(); - req.offset = reload ? 0 : participants.size(); - req.limit = 33; + req.offset = reload ? 0 : participantsMap.size(); + req.limit = 200; int reqId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { @Override public void run(final TLObject response, final TLRPC.TL_error error) { @@ -1120,25 +1428,28 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (error == null) { TLRPC.TL_channels_channelParticipants res = (TLRPC.TL_channels_channelParticipants) response; MessagesController.getInstance().putUsers(res.users, false); - if (res.participants.size() == 33) { - res.participants.remove(32); - } else { + if (res.users.size() != 200) { usersEndReached = true; } if (req.offset == 0) { - participants.clear(); participantsMap.clear(); + info.participants = new TLRPC.TL_chatParticipants(); MessagesStorage.getInstance().putUsersAndChats(res.users, null, true, true); MessagesStorage.getInstance().updateChannelUsers(chat_id, res.participants); } for (int a = 0; a < res.participants.size(); a++) { - TLRPC.ChannelParticipant participant = res.participants.get(a); + TLRPC.TL_chatChannelParticipant participant = new TLRPC.TL_chatChannelParticipant(); + participant.channelParticipant = res.participants.get(a); + participant.inviter_id = participant.channelParticipant.inviter_id; + participant.user_id = participant.channelParticipant.user_id; + participant.date = participant.channelParticipant.date; if (!participantsMap.containsKey(participant.user_id)) { - participants.add(participant); + info.participants.participants.add(participant); participantsMap.put(participant.user_id, participant); } } } + updateOnlineCount(); loadingUsers = false; updateRowsIds(); if (listAdapter != null) { @@ -1171,36 +1482,32 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. MessagesController.getInstance().addUserToChat(chat_id, user, info, param != null ? Utilities.parseInt(param) : 0, null, ProfileActivity.this); } }); - if (info instanceof TLRPC.TL_chatFull) { + if (info != null && info.participants != null) { HashMap users = new HashMap<>(); for (int a = 0; a < info.participants.participants.size(); a++) { users.put(info.participants.participants.get(a).user_id, null); } fragment.setIgnoreUsers(users); - } else if (participants != null) { - HashMap users = new HashMap<>(); - for (int a = 0; a < participants.size(); a++) { - users.put(participants.get(a).user_id, null); - } - fragment.setIgnoreUsers(users); } presentFragment(fragment); } private void checkListViewScroll() { - if (listView.getChildCount() == 0 || openAnimationInProgress) { + if (listView.getChildCount() <= 0 || openAnimationInProgress) { return; } - int height = 0; + View child = listView.getChildAt(0); - if (child != null) { - if (layoutManager.findFirstVisibleItemPosition() == 0) { - height = AndroidUtilities.dp(88) + (child.getTop() < 0 ? child.getTop() : 0); - } - if (extraHeight != height) { - extraHeight = height; - needLayout(); - } + ListAdapter.Holder holder = (ListAdapter.Holder) listView.findContainingViewHolder(child); + int top = child.getTop(); + int newOffset = 0; + if (top >= 0 && holder != null && holder.getAdapterPosition() == 0) { + newOffset = top; + } + if (extraHeight != newOffset) { + extraHeight = newOffset; + topView.invalidate(); + needLayout(); } } @@ -1211,15 +1518,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. layoutParams = (FrameLayout.LayoutParams) listView.getLayoutParams(); if (layoutParams.topMargin != newTop) { layoutParams.topMargin = newTop; - listView.setLayoutParams(layoutParams); - ViewProxy.setTranslationY(extraHeightView, newTop); + listView.setLayoutParams(layoutParams); } } if (avatarImage != null) { float diff = extraHeight / (float) AndroidUtilities.dp(88); - ViewProxy.setScaleY(extraHeightView, diff); - ViewProxy.setTranslationY(shadowView, newTop + extraHeight); listView.setTopGlowOffset(extraHeight); if (writeButton != null) { @@ -1284,11 +1588,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. float avatarY = (actionBar.getOccupyStatusBar() ? AndroidUtilities.statusBarHeight : 0) + ActionBar.getCurrentActionBarHeight() / 2.0f * (1.0f + diff) - 21 * AndroidUtilities.density + 27 * AndroidUtilities.density * diff; if (Build.VERSION.SDK_INT < 11) { - layoutParams = (FrameLayout.LayoutParams) avatarImage.getLayoutParams(); + layoutParams = (FrameLayout.LayoutParams) avatarImage.getLayoutParams(); layoutParams.height = layoutParams.width = (int) Math.ceil(AndroidUtilities.dp(42) * (42 + 18 * diff) / 42.0f); layoutParams.leftMargin = (int) Math.ceil(AndroidUtilities.dp(64) - AndroidUtilities.dp(47) * diff); layoutParams.topMargin = (int) Math.ceil(avatarY); - avatarImage.setLayoutParams(layoutParams); + avatarImage.setLayoutParams(layoutParams); avatarImage.setRoundRadius(layoutParams.height / 2); } else { ViewProxy.setScaleX(avatarImage, (42 + 18 * diff) / 42.0f); @@ -1306,9 +1610,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. int y2 = themePrefs.getInt("profileStatusSize", 14) - 14 + y; ViewProxy.setTranslationX(nameTextView[a], -21 * AndroidUtilities.density * diff); - ViewProxy.setTranslationY(nameTextView[a], (float) Math.floor(avatarY) - (float) Math.ceil(AndroidUtilities.density) + (float) Math.floor(7 * AndroidUtilities.density * diff)); + ViewProxy.setTranslationY(nameTextView[a], (float) Math.floor(avatarY) + AndroidUtilities.dp(1.3f) + AndroidUtilities.dp(7) * diff); ViewProxy.setTranslationX(onlineTextView[a], -21 * AndroidUtilities.density * diff); - ViewProxy.setTranslationY(onlineTextView[a], (float) Math.floor(avatarY) + AndroidUtilities.dp(22) + (float) Math.floor(11 * AndroidUtilities.density) * diff); + ViewProxy.setTranslationY(onlineTextView[a], (float) Math.floor(avatarY) + AndroidUtilities.dp(24) + (float) Math.floor(11 * AndroidUtilities.density) * diff); ViewProxy.setTranslationX(adminTextView, -21 * AndroidUtilities.density * diff); ViewProxy.setTranslationY(adminTextView, (float) Math.floor(avatarY) + AndroidUtilities.dp(32 + y2) + (float )Math.floor(22 * AndroidUtilities.density) * diff); @@ -1323,13 +1627,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. width = AndroidUtilities.displaySize.x; } width = (int) (width - AndroidUtilities.dp(118 + 8 + 40 * (1.0f - diff)) - ViewProxy.getTranslationX(nameTextView[a])); - float width2 = nameTextView[a].getPaint().measureText(nameTextView[a].getText().toString()) * ViewProxy.getScaleX(nameTextView[a]); - Drawable[] drawables = nameTextView[a].getCompoundDrawables(); - for (int b = 0; b < drawables.length; b++) { - if (drawables[b] != null) { - width2 += drawables[b].getIntrinsicWidth() + AndroidUtilities.dp(4); - } - } + float width2 = nameTextView[a].getPaint().measureText(nameTextView[a].getText().toString()) * ViewProxy.getScaleX(nameTextView[a]) + nameTextView[a].getSideDrawablesSize(); layoutParams = (FrameLayout.LayoutParams) nameTextView[a].getLayoutParams(); if (width < width2) { layoutParams.width = (int) Math.ceil(width / ViewProxy.getScaleX(nameTextView[a])); @@ -1341,15 +1639,15 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. layoutParams = (FrameLayout.LayoutParams) onlineTextView[a].getLayoutParams(); layoutParams.rightMargin = (int) Math.ceil(ViewProxy.getTranslationX(onlineTextView[a]) + AndroidUtilities.dp(8) + AndroidUtilities.dp(40) * (1.0f - diff)); onlineTextView[a].setLayoutParams(layoutParams); - - } - if (diff > 0.85) { - adminTextView.setVisibility(View.VISIBLE); - } else { - adminTextView.setVisibility(View.GONE); } } + if (diff > 0.85) { + adminTextView.setVisibility(View.VISIBLE); + } else { + adminTextView.setVisibility(View.GONE); + } } + updateActionBarBG(); } private void fixLayout() { @@ -1429,29 +1727,119 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } else if (id == NotificationCenter.contactsDidLoaded) { createActionBarMenu(); } else if (id == NotificationCenter.mediaCountDidLoaded) { - long uid = (Long) args[0]; - long did = dialog_id; - if (did == 0) { - if (user_id != 0) { - did = user_id; - } else if (chat_id != 0) { - did = -chat_id; + int type = (Integer) args[3]; + if(type == SharedMediaQuery.MEDIA_PHOTOVIDEO){ + long uid = (Long) args[0]; + long did = dialog_id; + if (did == 0) { + if (user_id != 0) { + did = user_id; + } else if (chat_id != 0) { + did = -chat_id; + } } - } - if (uid == did || uid == mergeDialogId) { - if (uid == did) { - totalMediaCount = (Integer) args[1]; - } else { - totalMediaCountMerge = (Integer) args[1]; + if (uid == did || uid == mergeDialogId) { + if (uid == did) { + totalMediaCount = (Integer) args[1]; + } else { + totalMediaCountMerge = (Integer) args[1]; + } + if (listView != null) { + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + ListAdapter.Holder holder = (ListAdapter.Holder) listView.getChildViewHolder(child); + if (holder.getAdapterPosition() == sharedMediaRow) { + listAdapter.onBindViewHolder(holder, sharedMediaRow); + break; + } + } + } } - if (listView != null) { - int count = listView.getChildCount(); - for (int a = 0; a < count; a++) { - View child = listView.getChildAt(a); - ListAdapter.Holder holder = (ListAdapter.Holder) listView.getChildViewHolder(child); - if (holder.getAdapterPosition() == sharedMediaRow) { - listAdapter.onBindViewHolder(holder, sharedMediaRow); - break; + } else if(type == SharedMediaQuery.MEDIA_FILE){ + long uid = (Long) args[0]; + long did = dialog_id; + if (did == 0) { + if (user_id != 0) { + did = user_id; + } else if (chat_id != 0) { + did = -chat_id; + } + } + if (uid == did || uid == mergeDialogId) { + if (uid == did) { + totalFilesCount = (Integer) args[1]; + } else { + totalFilesCountMerge = (Integer) args[1]; + } + + if (listView != null) { + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + ListAdapter.Holder holder = (ListAdapter.Holder) listView.getChildViewHolder(child); + if (holder.getAdapterPosition() == sharedFilesRow) { + listAdapter.onBindViewHolder(holder, sharedFilesRow); + break; + } + } + } + } + } else if(type == SharedMediaQuery.MEDIA_MUSIC){ + long uid = (Long) args[0]; + long did = dialog_id; + if (did == 0) { + if (user_id != 0) { + did = user_id; + } else if (chat_id != 0) { + did = -chat_id; + } + } + if (uid == did || uid == mergeDialogId) { + if (uid == did) { + totalMusicCount = (Integer) args[1]; + } else { + totalMusicCountMerge = (Integer) args[1]; + } + + if (listView != null) { + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + ListAdapter.Holder holder = (ListAdapter.Holder) listView.getChildViewHolder(child); + if (holder.getAdapterPosition() == sharedMusicRow) { + listAdapter.onBindViewHolder(holder, sharedMusicRow); + break; + } + } + } + } + } else if(type == SharedMediaQuery.MEDIA_URL){ + long uid = (Long) args[0]; + long did = dialog_id; + if (did == 0) { + if (user_id != 0) { + did = user_id; + } else if (chat_id != 0) { + did = -chat_id; + } + } + if (uid == did || uid == mergeDialogId) { + if (uid == did) { + totalLinksCount = (Integer) args[1]; + } else { + totalLinksCountMerge = (Integer) args[1]; + } + //Toast.makeText(getParentActivity(), "Total: " + totalLinksCount + '\n' + "Merge: " + totalLinksCountMerge + '\n' + "uid: " + uid + '\n' + "did: " + did, Toast.LENGTH_SHORT).show(); + if (listView != null) { + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + ListAdapter.Holder holder = (ListAdapter.Holder) listView.getChildViewHolder(child); + if (holder.getAdapterPosition() == sharedLinksRow) { + listAdapter.onBindViewHolder(holder, sharedLinksRow); + break; + } } } } @@ -1495,10 +1883,18 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. chatFull.participants = info.participants; } } + boolean loadChannelParticipants = info == null && chatFull instanceof TLRPC.TL_channelFull; info = chatFull; if (mergeDialogId == 0 && info.migrated_from_chat_id != 0) { mergeDialogId = -info.migrated_from_chat_id; - SharedMediaQuery.getMediaCount(mergeDialogId, SharedMediaQuery.MEDIA_PHOTOVIDEO, classGuid, true); + if(!hideMedia) + SharedMediaQuery.getMediaCount(mergeDialogId, SharedMediaQuery.MEDIA_PHOTOVIDEO, classGuid, true); + if(!hideFiles) + SharedMediaQuery.getMediaCount(mergeDialogId, SharedMediaQuery.MEDIA_FILE, classGuid, true); + if(!hideMusic) + SharedMediaQuery.getMediaCount(mergeDialogId, SharedMediaQuery.MEDIA_MUSIC, classGuid, true); + if(!hideLinks) + SharedMediaQuery.getMediaCount(mergeDialogId, SharedMediaQuery.MEDIA_URL, classGuid, true); } fetchUsersFromChannelInfo(); updateOnlineCount(); @@ -1512,7 +1908,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. currentChat = newChat; createActionBarMenu(); } - if (currentChat.megagroup && !byChannelUsers) { + if (currentChat.megagroup && (loadChannelParticipants || !byChannelUsers)) { getChannelParticipants(true); } } @@ -1528,6 +1924,14 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. checkListViewScroll(); } } + } else if (id == NotificationCenter.userInfoDidLoaded) { + int uid = (Integer) args[0]; + if (uid == user_id) { + updateRowsIds(); + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + } } else if (id == NotificationCenter.didReceivedNewMessages) { long did = (Long) args[0]; if (did == dialog_id) { @@ -1568,6 +1972,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (!backward && playProfileAnimation) { openAnimationInProgress = true; } + NotificationCenter.getInstance().setAllowedNotificationsDutingAnimation(new int[]{NotificationCenter.dialogsNeedReload, NotificationCenter.closeChats, NotificationCenter.mediaCountDidLoaded}); NotificationCenter.getInstance().setAnimationInProgress(true); } @@ -1586,22 +1991,32 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. public void setAnimationProgress(float progress) { animationProgress = progress; ViewProxy.setAlpha(listView, progress); - ViewProxy.setTranslationX(listView, AndroidUtilities.dp(48) * (1.0f - progress)); + + //ViewProxy.setTranslationY(listView, -AndroidUtilities.dp(48) + AndroidUtilities.dp(48) * progress); int color = AvatarDrawable.getProfileBackColorForId(user_id != 0 || ChatObject.isChannel(chat_id) && !currentChat.megagroup ? 5 : chat_id); - int rD = (int) ((Color.red(color) - 0x54) * progress); - int gD = (int) ((Color.green(color) - 0x75) * progress); - int bD = (int) ((Color.blue(color) - 0x9e) * progress); - //actionBar.setBackgroundColor(Color.rgb(0x54 + rD, 0x75 + gD, 0x9e + bD)); - //extraHeightView.setBackgroundColor(Color.rgb(0x54 + rD, 0x75 + gD, 0x9e + bD)); + int r = Color.red(Theme.ACTION_BAR_COLOR); + int g = Color.green(Theme.ACTION_BAR_COLOR); + int b = Color.blue(Theme.ACTION_BAR_COLOR); + + int rD = (int) ((Color.red(color) - r) * progress); + int gD = (int) ((Color.green(color) - g) * progress); + int bD = (int) ((Color.blue(color) - b) * progress); + //topView.setBackgroundColor(Color.rgb(r + rD, g + gD, b + bD)); + color = AvatarDrawable.getProfileTextColorForId(user_id != 0 || ChatObject.isChannel(chat_id) && !currentChat.megagroup ? 5 : chat_id); - rD = (int) ((Color.red(color) - 0xd7) * progress); - gD = (int) ((Color.green(color) - 0xe8) * progress); - bD = (int) ((Color.blue(color) - 0xf7) * progress); + + r = Color.red(Theme.ACTION_BAR_SUBTITLE_COLOR); + g = Color.green(Theme.ACTION_BAR_SUBTITLE_COLOR); + b = Color.blue(Theme.ACTION_BAR_SUBTITLE_COLOR); + + rD = (int) ((Color.red(color) - r) * progress); + gD = (int) ((Color.green(color) - g) * progress); + bD = (int) ((Color.blue(color) - b) * progress); for (int a = 0; a < 2; a++) { if (onlineTextView[a] == null) { continue; } - //onlineTextView[a].setTextColor(Color.rgb(0xd7 + rD, 0xe8 + gD, 0xf7 + bD)); + //onlineTextView[a].setTextColor(Color.rgb(r + rD, g + gD, b + bD)); } extraHeight = (int) (initialAnimationExtraHeight * progress); color = AvatarDrawable.getProfileColorForId(user_id != 0 ? user_id : chat_id); @@ -1615,13 +2030,14 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } needLayout(); + updateActionBarBG(); } @Override protected AnimatorSetProxy onCustomTransitionAnimation(final boolean isOpen, final Runnable callback) { if (playProfileAnimation) { final AnimatorSetProxy animatorSet = new AnimatorSetProxy(); - animatorSet.setDuration(150); + animatorSet.setDuration(180); if (Build.VERSION.SDK_INT > 15) { listView.setLayerType(View.LAYER_TYPE_HARDWARE, null); } @@ -1637,14 +2053,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. onlineTextView[1].setLayoutParams(layoutParams); int width = (int) Math.ceil(AndroidUtilities.displaySize.x - AndroidUtilities.dp(118 + 8) + 21 * AndroidUtilities.density); - float width2 = nameTextView[1].getPaint().measureText(nameTextView[1].getText().toString()) * 1.12f; - Drawable[] drawables = nameTextView[1].getCompoundDrawables(); - for (int b = 0; b < drawables.length; b++) { - if (drawables[b] != null) { - width2 += drawables[b].getIntrinsicWidth() + AndroidUtilities.dp(4); - } - } - + float width2 = nameTextView[1].getPaint().measureText(nameTextView[1].getText().toString()) * 1.12f + nameTextView[1].getSideDrawablesSize(); layoutParams = (FrameLayout.LayoutParams) nameTextView[1].getLayoutParams(); if (width < width2) { layoutParams.width = (int) Math.ceil(width / 1.12f); @@ -1709,13 +2118,6 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } callback.run(); } - - @Override - public void onAnimationCancel(Object animation) { - if (Build.VERSION.SDK_INT > 15) { - listView.setLayerType(View.LAYER_TYPE_NONE, null); - } - } }); animatorSet.setInterpolator(new DecelerateInterpolator()); @@ -1803,21 +2205,19 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. private void updateOnlineCount() { onlineCount = 0; - if (!(info instanceof TLRPC.TL_chatFull)) { - return; - } int currentTime = ConnectionsManager.getInstance().getCurrentTime(); sortedUsers.clear(); - int i = 0; - for (TLRPC.ChatParticipant participant : info.participants.participants) { - TLRPC.User user = MessagesController.getInstance().getUser(participant.user_id); - if (user != null && user.status != null && (user.status.expires > currentTime || user.id == UserConfig.getClientUserId()) && user.status.expires > 10000) { - onlineCount++; - } - sortedUsers.add(i); - i++; - if(participant instanceof TLRPC.TL_chatParticipantCreator){ - creatorID = participant.user_id; + if (info instanceof TLRPC.TL_chatFull || info instanceof TLRPC.TL_channelFull && info.participants_count <= 200 && info.participants != null) { + for (int a = 0; a < info.participants.participants.size(); a++) { + TLRPC.ChatParticipant participant = info.participants.participants.get(a); + TLRPC.User user = MessagesController.getInstance().getUser(participant.user_id); + if (user != null && user.status != null && (user.status.expires > currentTime || user.id == UserConfig.getClientUserId()) && user.status.expires > 10000) { + onlineCount++; + } + sortedUsers.add(a); + if (participant instanceof TLRPC.TL_chatParticipantCreator) { + creatorID = participant.user_id; + } } } @@ -1874,7 +2274,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } }); } catch (Exception e) { - FileLog.e("tmessages", e); //TODO find crash + FileLog.e("tmessages", e); } if (listAdapter != null) { @@ -1891,35 +2291,29 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } private void fetchUsersFromChannelInfo() { - if (info != null && info instanceof TLRPC.TL_channelFull && info.participants != null && participants != null && participants.isEmpty()) { + if (info instanceof TLRPC.TL_channelFull && info.participants != null) { for (int a = 0; a < info.participants.participants.size(); a++) { TLRPC.ChatParticipant chatParticipant = info.participants.participants.get(a); - if (chatParticipant instanceof TLRPC.TL_chatChannelParticipant) { - TLRPC.ChannelParticipant channelParticipant = ((TLRPC.TL_chatChannelParticipant) chatParticipant).channelParticipant; - participants.add(channelParticipant); - participantsMap.put(channelParticipant.user_id, channelParticipant); - if(channelParticipant instanceof TLRPC.TL_channelParticipantCreator){ - creatorID = channelParticipant.user_id; - } + participantsMap.put(chatParticipant.user_id, chatParticipant); + if(((TLRPC.TL_chatChannelParticipant) chatParticipant).channelParticipant instanceof TLRPC.TL_channelParticipantCreator){ + creatorID = chatParticipant.user_id; } } } } - - private void kickUser(int uid) { if (uid != 0) { MessagesController.getInstance().deleteUserFromChat(chat_id, MessagesController.getInstance().getUser(uid), info); - if (currentChat.megagroup && participants != null) { + if (currentChat.megagroup && info != null && info.participants != null) { boolean changed = false; - for (int a = 0; a < participants.size(); a++) { - TLRPC.ChannelParticipant p = participants.get(a); + for (int a = 0; a < info.participants.participants.size(); a++) { + TLRPC.ChannelParticipant p = ((TLRPC.TL_chatChannelParticipant) info.participants.participants.get(a)).channelParticipant; if (p.user_id == uid) { if (info != null) { info.participants_count--; } - participants.remove(a); + info.participants.participants.remove(a); changed = true; break; } @@ -1935,6 +2329,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } } if (changed) { + updateOnlineCount(); updateRowsIds(); listAdapter.notifyDataSetChanged(); } @@ -1957,16 +2352,34 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } private void updateRowsIds() { - rowCount = 0; - overscrollRow = rowCount++; - if (user_id != 0) { + emptyRow = -1; phoneRow = -1; + userInfoRow = -1; + userSectionRow = -1; + sectionRow = -1; + sharedMediaRow = -1; + settingsNotificationsRow = -1; usernameRow = -1; settingsTimerRow = -1; settingsKeyRow = -1; startSecretChatRow = -1; + membersEndRow = -1; + emptyRowChat2 = -1; + addMemberRow = -1; + channelInfoRow = -1; + channelNameRow = -1; + convertRow = -1; + convertHelpRow = -1; + emptyRowChat = -1; + membersSectionRow = -1; + membersRow = -1; + managementRow = -1; + leaveChannelRow = -1; + loadMoreMembersRow = -1; blockedUsersRow = -1; + rowCount = 0; + if (user_id != 0) { TLRPC.User user = MessagesController.getInstance().getUser(user_id); emptyRow = rowCount++; if (user == null || !user.bot) { @@ -1975,37 +2388,29 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (user != null && user.username != null && user.username.length() > 0) { usernameRow = rowCount++; } - if (botInfo != null && botInfo.share_text != null && botInfo.share_text.length() > 0) { - botSectionRow = rowCount++; - botInfoRow = rowCount++; + String about = MessagesController.getInstance().getUserAbout(user.id); + //if (about != null) { + if (about != null || userAbout != null) { + userSectionRow = rowCount++; + userInfoRow = rowCount++; + } else { + userSectionRow = -1; + userInfoRow = -1; } sectionRow = rowCount++; settingsNotificationsRow = rowCount++; - sharedMediaRow = rowCount++; + sharedMediaRow = hideMedia ? -1 : rowCount++; + sharedFilesRow = hideFiles ? -1 : rowCount++; + sharedMusicRow = hideMusic ? -1 : rowCount++; + sharedLinksRow = hideLinks ? -1 : rowCount++; if (currentEncryptedChat instanceof TLRPC.TL_encryptedChat) { settingsTimerRow = rowCount++; settingsKeyRow = rowCount++; } - if (user != null && !user.bot && currentEncryptedChat == null) { + if (user != null && !user.bot && currentEncryptedChat == null && user.id != UserConfig.getClientUserId()) { startSecretChatRow = rowCount++; } } else if (chat_id != 0) { - membersEndRow = -1; - membersSectionRow = -1; - emptyRowChat2 = -1; - addMemberRow = -1; - channelInfoRow = -1; - channelNameRow = -1; - convertRow = -1; - convertHelpRow = -1; - emptyRowChat = -1; - membersSectionRow = -1; - membersRow = -1; - managementRow = -1; - leaveChannelRow = -1; - loadMoreMembersRow = -1; - blockedUsersRow = -1; - if (chat_id > 0) { emptyRow = rowCount++; if (ChatObject.isChannel(currentChat) && (info != null && info.about != null && info.about.length() > 0 || currentChat.username != null && currentChat.username.length() > 0)) { @@ -2018,12 +2423,15 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. sectionRow = rowCount++; } settingsNotificationsRow = rowCount++; - sharedMediaRow = rowCount++; + sharedMediaRow = hideMedia ? -1 : rowCount++; + sharedFilesRow = hideFiles ? -1 : rowCount++; + sharedMusicRow = hideMusic ? -1 : rowCount++; + sharedLinksRow = hideLinks ? -1 : rowCount++; if (ChatObject.isChannel(currentChat)) { if (!currentChat.megagroup && info != null && (currentChat.creator || info.can_view_participants)) { membersRow = rowCount++; } - if (!ChatObject.isNotInChat(currentChat) && (currentChat.creator || currentChat.editor || currentChat.moderator)) { + if (!ChatObject.isNotInChat(currentChat) && !currentChat.megagroup && (currentChat.creator || currentChat.editor || currentChat.moderator)) { managementRow = rowCount++; } if (!ChatObject.isNotInChat(currentChat) && currentChat.megagroup && (currentChat.editor || currentChat.creator)) { @@ -2032,16 +2440,16 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (!currentChat.creator && !currentChat.left && !currentChat.kicked && !currentChat.megagroup) { leaveChannelRow = rowCount++; } - if (currentChat.megagroup && (currentChat.editor || currentChat.creator)) { + if (currentChat.megagroup && (currentChat.editor || currentChat.creator || currentChat.democracy)) { if (info == null || info.participants_count < MessagesController.getInstance().maxMegagroupCount) { addMemberRow = rowCount++; } } - if (participants != null && !participants.isEmpty()) { + if (info != null && info.participants != null && !info.participants.participants.isEmpty()) { emptyRowChat = rowCount++; membersSectionRow = rowCount++; emptyRowChat2 = rowCount++; - rowCount += participants.size(); + rowCount += info.participants.participants.size(); membersEndRow = rowCount; if (!usersEndReached) { loadMoreMembersRow = rowCount++; @@ -2055,8 +2463,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. addMemberRow = rowCount++; } - if (currentChat.creator && info.participants.participants.size() >= MessagesController.getInstance().minGroupConvertSize - || currentChat.creator && info.participants.participants.size() >= 4 && currentChat.creator && BuildConfig.DEBUG) { + if (currentChat.creator && info.participants.participants.size() >= MessagesController.getInstance().minGroupConvertSize) { convertRow = rowCount++; } } @@ -2116,15 +2523,11 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (nameTextView[a] == null) { continue; } - if (a == 0) { - if (user.id / 1000 != 777 && user.id / 1000 != 333 && ContactsController.getInstance().contactsDict.get(user.id) == null && (ContactsController.getInstance().contactsDict.size() != 0 || !ContactsController.getInstance().isLoadingContacts())) { - if (user.phone != null && user.phone.length() != 0) { - nameTextView[a].setText(PhoneFormat.getInstance().format("+" + user.phone)); - } else { - nameTextView[a].setText(UserObject.getUserName(user)); - } - } else { - nameTextView[a].setText(UserObject.getUserName(user)); + if (a == 0 && user.phone != null && user.phone.length() != 0 && user.id / 1000 != 777 && user.id / 1000 != 333 && ContactsController.getInstance().contactsDict.get(user.id) == null && + (ContactsController.getInstance().contactsDict.size() != 0 || !ContactsController.getInstance().isLoadingContacts())) { + String phoneString = PhoneFormat.getInstance().format("+" + user.phone); + if (!nameTextView[a].getText().equals(phoneString)) { + nameTextView[a].setText(phoneString); } } else { if (!nameTextView[a].getText().equals(newString)) { @@ -2135,30 +2538,20 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. onlineTextView[a].setText(newString2); } int leftIcon = currentEncryptedChat != null ? R.drawable.ic_lock_header : 0; - if (a != 0) { - if (user.verified) { - if (nameTextView[a].getCompoundDrawables()[2] == null || nameTextView[a].getCompoundDrawables()[0] == null && leftIcon != 0) { - nameTextView[a].setCompoundDrawablesWithIntrinsicBounds(leftIcon, 0, R.drawable.check_profile_fixed, 0); - } - } else { - if (nameTextView[a].getCompoundDrawables()[2] != null || nameTextView[a].getCompoundDrawables()[0] == null && leftIcon != 0) { - nameTextView[a].setCompoundDrawablesWithIntrinsicBounds(leftIcon, 0, 0, 0); - } - } - } else { - nameTextView[a].setCompoundDrawablesWithIntrinsicBounds(leftIcon, 0, MessagesController.getInstance().isDialogMuted(dialog_id != 0 ? dialog_id : (long) user_id) ? R.drawable.mute_fixed : 0, 0); + int rightIcon = 0; + if (a == 0) { + rightIcon = MessagesController.getInstance().isDialogMuted(dialog_id != 0 ? dialog_id : (long) user_id) ? R.drawable.mute_fixed : 0; + } else if (user.verified) { + rightIcon = R.drawable.check_profile_fixed; } + nameTextView[a].setLeftDrawable(leftIcon); + nameTextView[a].setRightDrawable(rightIcon); } - if(BuildConfig.DEBUG){ id = user_id; adminTextView.setText("id: " + user_id); } - //if(!user.bot){ - // if(user.bot_inline_placeholder != null && user.bot_inline_placeholder.length() > 0)adminTextView.setText(user.bot_inline_placeholder); - //} - avatarImage.getImageReceiver().setVisible(!PhotoViewer.getInstance().isShowingImage(photoBig), false); } else if (chat_id != 0) { TLRPC.Chat chat = MessagesController.getInstance().getChat(chat_id); @@ -2171,22 +2564,32 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. String newString; if (ChatObject.isChannel(chat)) { if (info == null || !currentChat.megagroup && (info.participants_count == 0 || (currentChat.admin || info.can_view_participants))) { + if (currentChat.megagroup) { + newString = LocaleController.getString("Loading", R.string.Loading).toLowerCase(); + } else { if ((chat.flags & TLRPC.CHAT_FLAG_IS_PUBLIC) != 0) { newString = LocaleController.getString("ChannelPublic", R.string.ChannelPublic).toLowerCase(); } else { newString = LocaleController.getString("ChannelPrivate", R.string.ChannelPrivate).toLowerCase(); } + } } else { - int result[] = new int[1]; - String shortNumber = LocaleController.formatShortNumber(info.participants_count, result); - newString = LocaleController.formatPluralString("Members", result[0]).replace(String.format("%d", result[0]), shortNumber); + if (currentChat.megagroup && info.participants_count <= 200) { + if (onlineCount > 1 && info.participants_count != 0) { + newString = String.format("%s, %s", LocaleController.formatPluralString("Members", info.participants_count), LocaleController.formatPluralString("Online", onlineCount)); + } else { + newString = LocaleController.formatPluralString("Members", info.participants_count); + } + } else { + int result[] = new int[1]; + String shortNumber = LocaleController.formatShortNumber(info.participants_count, result); + newString = LocaleController.formatPluralString("Members", result[0]).replace(String.format("%d", result[0]), shortNumber); + } } - - if(BuildConfig.DEBUG){ + if (BuildConfig.DEBUG) { id = chat_id; adminTextView.setText("id: " + chat_id); } - } else { int count = chat.participants_count; if (info != null) { @@ -2211,24 +2614,24 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (chat.title != null && !nameTextView[a].getText().equals(chat.title)) { nameTextView[a].setText(chat.title); } + nameTextView[a].setLeftDrawable(null); if (a != 0) { if (chat.verified) { - if (nameTextView[a].getCompoundDrawables()[2] == null) { - nameTextView[a].setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.check_profile_fixed, 0); - } + nameTextView[a].setRightDrawable(R.drawable.check_profile_fixed); } else { - if (nameTextView[a].getCompoundDrawables()[2] != null) { - nameTextView[a].setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); - } + nameTextView[a].setRightDrawable(null); } } else { - nameTextView[a].setCompoundDrawablesWithIntrinsicBounds(0, 0, MessagesController.getInstance().isDialogMuted((long) -chat_id) ? R.drawable.mute_fixed : 0, 0); + nameTextView[a].setRightDrawable(MessagesController.getInstance().isDialogMuted((long) -chat_id) ? R.drawable.mute_fixed : 0); } - if (a == 0 && ChatObject.isChannel(currentChat) && info != null && info.participants_count != 0 && (currentChat.megagroup || currentChat.broadcast)) { + if (currentChat.megagroup && info != null && info.participants_count <= 200 && onlineCount > 0) { + if (!onlineTextView[a].getText().equals(newString)) { + onlineTextView[a].setText(newString); + } + } else if (a == 0 && ChatObject.isChannel(currentChat) && info != null && info.participants_count != 0 && (currentChat.megagroup || currentChat.broadcast)) { int result[] = new int[1]; String shortNumber = LocaleController.formatShortNumber(info.participants_count, result); - String text = LocaleController.formatPluralString("Members", result[0]).replace(String.format("%d", result[0]), shortNumber); - onlineTextView[a].setText(text); + onlineTextView[a].setText(LocaleController.formatPluralString("Members", result[0]).replace(String.format("%d", result[0]), shortNumber)); } else { if (!onlineTextView[a].getText().equals(newString)) { onlineTextView[a].setText(newString); @@ -2313,9 +2716,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. int hColor = themePrefs.getInt("profileHeaderColor", def); actionBar.setBackgroundColor(hColor); listView.setGlowColor(hColor); - extraHeightView.setBackgroundColor(hColor); + topViewColor = hColor; int val = themePrefs.getInt("profileHeaderGradient", 0); if (val > 0) { + topViewColor = 0x00000000; int gradColor = themePrefs.getInt("profileHeaderGradientColor", def); GradientDrawable.Orientation go; switch (val) { @@ -2330,15 +2734,13 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. break; default: go = GradientDrawable.Orientation.TOP_BOTTOM; - extraHeightView.setBackgroundColor(gradColor); + topViewColor = gradColor; } - int[] colors = new int[]{hColor, gradColor}; - GradientDrawable gd = new GradientDrawable(go, colors); - actionBar.setBackgroundDrawable(gd); - if(val > 1)extraHeightView.setBackgroundDrawable(gd); + GradientDrawable actionBarGradient = new GradientDrawable(go, colors); + actionBar.setBackgroundDrawable(actionBarGradient); } - + topView.setBackgroundColor(topViewColor); } private void createActionBarMenu() { @@ -2397,14 +2799,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } if (ChatObject.isChannel(chat)) { ActionBarMenuItem item = null; - if (chat.creator) { + if (chat.creator || chat.megagroup && chat.editor) { //item = menu.addItem(10, R.drawable.ic_ab_other); item = menu.addItem(10, dots); item.addSubItem(edit_channel, LocaleController.getString("ChannelEdit", R.string.ChannelEdit), 0); - } else if (chat.megagroup && chat.editor) { - //item = menu.addItem(10, R.drawable.ic_ab_other); - item = menu.addItem(10, dots); - item.addSubItem(edit_name, LocaleController.getString("EditName", R.string.EditName), 0); } if (!chat.creator && !chat.left && !chat.kicked && chat.megagroup) { if (item == null) { @@ -2422,6 +2820,9 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (!chat.admins_enabled || chat.creator || chat.admin) { item.addSubItem(edit_name, LocaleController.getString("EditName", R.string.EditName), 0); } + if (chat.creator && (info == null || info.participants.participants.size() > 1)) { + item.addSubItem(convert_to_supergroup, LocaleController.getString("ConvertGroupMenu", R.string.ConvertGroupMenu), 0); + } item.addSubItem(leave_group, LocaleController.getString("DeleteAndExit", R.string.DeleteAndExit), 0); } } else { @@ -2440,12 +2841,10 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } @Override - public void didSelectDialog(DialogsActivity messageFragment, long dialog_id, boolean param) { + public void didSelectDialog(DialogsActivity fragment, long dialog_id, boolean param) { if (dialog_id != 0) { Bundle args = new Bundle(); args.putBoolean("scrollToTopOnResume", true); - NotificationCenter.getInstance().removeObserver(this, NotificationCenter.closeChats); - NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); int lower_part = (int) dialog_id; if (lower_part != 0) { if (lower_part > 0) { @@ -2456,10 +2855,16 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } else { args.putInt("enc_id", (int) (dialog_id >> 32)); } + if (!MessagesController.checkCanOpenChat(args, fragment)) { + return; + } + + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.closeChats); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.closeChats); presentFragment(new ChatActivity(args), true); removeSelfFromStack(); TLRPC.User user = MessagesController.getInstance().getUser(user_id); - SendMessagesHelper.getInstance().sendMessage(user, dialog_id, null, true); + SendMessagesHelper.getInstance().sendMessage(user, dialog_id, null, true, null, null); } } @@ -2532,7 +2937,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. ((TextCell) view).setTextColor(tColor); break; case 4: - view = new UserCell(mContext, 61, 0) { + view = new UserCell(mContext, 61, 0, true) { @Override public boolean onTouchEvent(MotionEvent event) { if (Build.VERSION.SDK_INT >= 21 && getBackground() != null) { @@ -2557,12 +2962,14 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. TextInfoPrivacyCell cell = (TextInfoPrivacyCell) view; cell.setBackgroundResource(R.drawable.greydivider); cell.setText(AndroidUtilities.replaceTags(LocaleController.formatString("ConvertGroupInfo", R.string.ConvertGroupInfo, LocaleController.formatPluralString("Members", MessagesController.getInstance().maxMegagroupCount)))); + if(rColor != 0xffffffff || value > 0)view.setBackgroundColor(0x00000000); break; case 7: view = new LoadingCell(mContext); break; case 8: view = new AboutLinkCell(mContext); + if(rColor != 0xffffffff || value > 0)view.setBackgroundColor(0x00000000); ((AboutLinkCell) view).setDelegate(new AboutLinkCell.AboutLinkCellDelegate() { @Override public void didPressUrl(String url) { @@ -2585,6 +2992,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. }); break; } + view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)); return new Holder(view); } @@ -2597,9 +3005,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. int dColor = themePrefs.getInt("profileIconsColor", 0xff737373); switch (holder.getItemViewType()) { case 0: - if (i == overscrollRow) { - ((EmptyCell) holder.itemView).setHeight(AndroidUtilities.dp(88)); - } else if (i == emptyRowChat || i == emptyRowChat2) { + if (i == emptyRowChat || i == emptyRowChat2) { ((EmptyCell) holder.itemView).setHeight(AndroidUtilities.dp(8)); } else { ((EmptyCell) holder.itemView).setHeight(AndroidUtilities.dp(36)); @@ -2654,6 +3060,33 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } textCell.setTextAndValue(LocaleController.getString("SharedMedia", R.string.SharedMedia), value); textCell.setValueColor(vColor); + } else if (i == sharedFilesRow) { + String value; + if (totalFilesCount == -1) { + value = LocaleController.getString("Loading", R.string.Loading); + } else { + value = String.format("%d", totalFilesCount + (totalFilesCountMerge != -1 ? totalFilesCountMerge : 0)); + } + textCell.setTextAndValue(LocaleController.getString("DocumentsTitle", R.string.DocumentsTitle), value); + textCell.setValueColor(vColor); + } else if (i == sharedMusicRow) { + String value; + if (totalMusicCount == -1) { + value = LocaleController.getString("Loading", R.string.Loading); + } else { + value = String.format("%d", totalMusicCount + (totalMusicCountMerge != -1 ? totalMusicCountMerge : 0)); + } + textCell.setTextAndValue(LocaleController.getString("AudioTitle", R.string.AudioTitle), value); + textCell.setValueColor(vColor); + } else if (i == sharedLinksRow) { + String value; + if (totalLinksCount == -1) { + value = LocaleController.getString("Loading", R.string.Loading); + } else { + value = String.format("%d", totalLinksCount + (totalLinksCountMerge != -1 ? totalLinksCountMerge : 0)); + } + textCell.setTextAndValue(LocaleController.getString("LinksTitle", R.string.LinksTitle), value); + textCell.setValueColor(vColor); } else if (i == settingsTimerRow) { TLRPC.EncryptedChat encryptedChat = MessagesController.getInstance().getEncryptedChat((int)(dialog_id >> 32)); String value; @@ -2681,7 +3114,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. textCell.setTextColor(themePrefs.getInt("profileTitleColor", AndroidUtilities.getIntDarkerColor("themeColor", 0x15))); textCell.setText(LocaleController.getString("LeaveChannel", R.string.LeaveChannel)); } else if (i == convertRow) { - textCell.setText(LocaleController.getString("ConvertGroup", R.string.ConvertGroup)); + textCell.setText(LocaleController.getString("UpgradeGroup", R.string.UpgradeGroup)); textCell.setTextColor(0xff37a919); } else if (i == membersRow) { if (info != null) { @@ -2713,33 +3146,44 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. } break; case 4: - if (participants != null) { - TLRPC.ChannelParticipant part = participants.get(i - emptyRowChat2 - 1); - int icon = 0; - if (part instanceof TLRPC.TL_channelParticipantCreator || part instanceof TLRPC.TL_channelParticipantEditor) { - icon = R.drawable.menu_admin; - } - //((UserCell) holder.itemView).setData(MessagesController.getInstance().getUser(part.user_id), null, null, i == emptyRowChat2 + 1 ? R.drawable.menu_newgroup : 0); - ((UserCell) holder.itemView).setData(MessagesController.getInstance().getUser(part.user_id), null, null, icon != 0 ? icon : i == emptyRowChat2 + 1 ? R.drawable.menu_newgroup : 0); + UserCell userCell = ((UserCell) holder.itemView); + TLRPC.ChatParticipant part; + if (!sortedUsers.isEmpty()) { + part = info.participants.participants.get(sortedUsers.get(i - emptyRowChat2 - 1)); } else { - TLRPC.ChatParticipant part = info.participants.participants.get(sortedUsers.get(i - emptyRowChat2 - 1)); - int icon = 0; - if (creatorID == part.user_id || (currentChat != null && currentChat.admins_enabled && part instanceof TLRPC.TL_chatParticipantAdmin)) { - icon = R.drawable.menu_admin; - } else if (part.user_id == UserConfig.getClientUserId()) { - icon = R.drawable.menu_contacts; + part = info.participants.participants.get(i - emptyRowChat2 - 1); + } + if (part != null) { + if (part instanceof TLRPC.TL_chatChannelParticipant) { + TLRPC.ChannelParticipant channelParticipant = ((TLRPC.TL_chatChannelParticipant) part).channelParticipant; + if (channelParticipant instanceof TLRPC.TL_channelParticipantCreator) { + userCell.setIsAdmin(1); + } else if (channelParticipant instanceof TLRPC.TL_channelParticipantEditor || channelParticipant instanceof TLRPC.TL_channelParticipantModerator) { + userCell.setIsAdmin(2); + } else { + userCell.setIsAdmin(0); + } + } else { + if (part instanceof TLRPC.TL_chatParticipantCreator) { + userCell.setIsAdmin(1); + } else if (currentChat.admins_enabled && part instanceof TLRPC.TL_chatParticipantAdmin) { + userCell.setIsAdmin(2); + } else { + userCell.setIsAdmin(0); + } } - //((UserCell) holder.itemView).setData(MessagesController.getInstance().getUser(part.user_id), null, null, i == emptyRowChat2 + 1 ? R.drawable.menu_newgroup : 0); - ((UserCell) holder.itemView).setData(MessagesController.getInstance().getUser(part.user_id), null, null, icon); + userCell.setData(MessagesController.getInstance().getUser(part.user_id), null, null, i == emptyRowChat2 + 1 ? R.drawable.menu_newgroup : 0); } break; case 8: AboutLinkCell aboutLinkCell = (AboutLinkCell) holder.itemView; aboutLinkCell.setTextColor(tColor); aboutLinkCell.setLinkColor(themePrefs.getInt("profileSummaryColor", def)); - if (i == botInfoRow) { - aboutLinkCell.setTextAndIcon(botInfo.share_text, R.drawable.bot_info); - aboutLinkCell.setIconColor(dColor); + if (i == userInfoRow) { + String about = MessagesController.getInstance().getUserAbout(user_id); + //aboutLinkCell.setTextAndIcon(about, R.drawable.bot_info); + //Log.e("ProfileActivity","userInfoRow userAbout: " + userAbout); + aboutLinkCell.setTextAndIcon(about == null ? userAbout : about, R.drawable.bot_info); } else if (i == channelInfoRow) { String text = info.about; while (text.contains("\n\n\n")) { @@ -2755,9 +3199,12 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. if (checkBackground) { boolean enabled = false; if (user_id != 0) { - enabled = i == phoneRow || i == settingsTimerRow || i == settingsKeyRow || i == settingsNotificationsRow || i == sharedMediaRow || i == startSecretChatRow || i == usernameRow; + enabled = i == phoneRow || i == settingsTimerRow || i == settingsKeyRow || i == settingsNotificationsRow || + i == sharedMediaRow || i == sharedFilesRow || i == sharedMusicRow || i == sharedLinksRow || i == startSecretChatRow || i == usernameRow || i == userInfoRow; } else if (chat_id != 0) { - enabled = i == convertRow || i == settingsNotificationsRow || i == sharedMediaRow || i > emptyRowChat2 && i < membersEndRow || i == addMemberRow || i == channelNameRow || i == leaveChannelRow || i == membersRow || i == managementRow || i == blockedUsersRow || i == channelInfoRow; + enabled = i == convertRow || i == settingsNotificationsRow || i == sharedMediaRow || i == sharedFilesRow || i == sharedMusicRow || i == sharedLinksRow || i > emptyRowChat2 && i < membersEndRow || + i == addMemberRow || i == channelNameRow || i == leaveChannelRow || i == membersRow || i == managementRow || + i == blockedUsersRow || i == channelInfoRow; } if (enabled) { if (holder.itemView.getBackground() == null) { @@ -2779,13 +3226,13 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. @Override public int getItemViewType(int i) { - if (i == emptyRow || i == overscrollRow || i == emptyRowChat || i == emptyRowChat2) { + if (i == emptyRow || i == emptyRowChat || i == emptyRowChat2) { return 0; - } else if (i == sectionRow || i == botSectionRow) { + } else if (i == sectionRow || i == userSectionRow) { return 1; } else if (i == phoneRow || i == usernameRow || i == channelNameRow) { return 2; - } else if (i == leaveChannelRow || i == sharedMediaRow || i == settingsTimerRow || i == settingsNotificationsRow || i == startSecretChatRow || i == settingsKeyRow || i == membersRow || i == managementRow || i == blockedUsersRow || i == convertRow || i == addMemberRow) { + } else if (i == leaveChannelRow || i == sharedMediaRow || i == sharedFilesRow || i == sharedMusicRow || i == sharedLinksRow || i == settingsTimerRow || i == settingsNotificationsRow || i == startSecretChatRow || i == settingsKeyRow || i == membersRow || i == managementRow || i == blockedUsersRow || i == convertRow || i == addMemberRow) { return 3; } else if (i > emptyRowChat2 && i < membersEndRow) { return 4; @@ -2795,7 +3242,7 @@ public class ProfileActivity extends BaseFragment implements NotificationCenter. return 6; } else if (i == loadMoreMembersRow) { return 7; - } else if (i == botInfoRow || i == channelInfoRow) { + } else if (i == userInfoRow || i == channelInfoRow) { return 8; } return 0; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java index 786af766..53b34bfe 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ProfileNotificationsActivity.java @@ -31,22 +31,21 @@ import android.widget.ListView; import android.widget.TextView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.MessagesController; -import org.telegram.messenger.MessagesStorage; -import org.telegram.messenger.NotificationsController; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.FileLog; import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.MessagesStorage; import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.NotificationsController; import org.telegram.messenger.R; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Adapters.BaseFragmentAdapter; import org.telegram.ui.Cells.TextColorCell; import org.telegram.ui.Cells.TextDetailSettingsCell; -import org.telegram.ui.ActionBar.ActionBar; -import org.telegram.ui.ActionBar.BaseFragment; -import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.ColorPickerView; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.NumberPicker; @@ -119,7 +118,9 @@ public class ProfileNotificationsActivity extends BaseFragment implements Notifi listView.setDivider(null); listView.setDividerHeight(0); listView.setVerticalScrollBarEnabled(false); - AndroidUtilities.setListViewEdgeEffectColor(listView, AvatarDrawable.getProfileBackColorForId(5)); + int def = preferences.getInt("themeColor", AndroidUtilities.defColor); + int hColor = preferences.getInt("prefHeaderColor", def); + AndroidUtilities.setListViewEdgeEffectColor(listView, /*AvatarDrawable.getProfileBackColorForId(5)*/ hColor); frameLayout.addView(listView); final FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) listView.getLayoutParams(); layoutParams.width = LayoutHelper.MATCH_PARENT; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ReportOtherActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ReportOtherActivity.java new file mode 100644 index 00000000..e1691864 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ReportOtherActivity.java @@ -0,0 +1,151 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.text.InputType; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.TextView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.R; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Components.LayoutHelper; + +public class ReportOtherActivity extends BaseFragment { + + private EditText firstNameField; + private View headerLabelView; + private long dialog_id; + private View doneButton; + + private final static int done_button = 1; + + public ReportOtherActivity(Bundle args) { + super(args); + dialog_id = getArguments().getLong("dialog_id", 0); + } + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(LocaleController.getString("ReportChat", R.string.ReportChat)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } else if (id == done_button) { + if (firstNameField.getText().length() != 0) { + TLRPC.TL_account_reportPeer req = new TLRPC.TL_account_reportPeer(); + req.peer = MessagesController.getInputPeer((int) dialog_id); + req.reason = new TLRPC.TL_inputReportReasonOther(); + req.reason.text = firstNameField.getText().toString(); + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }); + finishFragment(); + } + } + } + }); + + ActionBarMenu menu = actionBar.createMenu(); + doneButton = menu.addItemWithWidth(done_button, R.drawable.ic_done, AndroidUtilities.dp(56)); + + LinearLayout linearLayout = new LinearLayout(context); + fragmentView = linearLayout; + fragmentView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + ((LinearLayout) fragmentView).setOrientation(LinearLayout.VERTICAL); + fragmentView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return true; + } + }); + + firstNameField = new EditText(context); + firstNameField.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 18); + firstNameField.setHintTextColor(0xff979797); + firstNameField.setTextColor(0xff212121); + firstNameField.setMaxLines(3); + firstNameField.setPadding(0, 0, 0, 0); + firstNameField.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + firstNameField.setInputType(InputType.TYPE_TEXT_FLAG_CAP_SENTENCES | InputType.TYPE_TEXT_FLAG_MULTI_LINE | InputType.TYPE_TEXT_FLAG_AUTO_CORRECT); + firstNameField.setImeOptions(EditorInfo.IME_ACTION_DONE); + firstNameField.setGravity(LocaleController.isRTL ? Gravity.RIGHT : Gravity.LEFT); + AndroidUtilities.clearCursorDrawable(firstNameField); + firstNameField.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(TextView textView, int i, KeyEvent keyEvent) { + if (i == EditorInfo.IME_ACTION_DONE && doneButton != null) { + doneButton.performClick(); + return true; + } + return false; + } + }); + + linearLayout.addView(firstNameField, LayoutHelper.createLinear(LayoutHelper.MATCH_PARENT, 36, 24, 24, 24, 0)); + firstNameField.setHint(LocaleController.getString("ReportChatDescription", R.string.ReportChatDescription)); + firstNameField.setSelection(firstNameField.length()); + + return fragmentView; + } + + @Override + public void onResume() { + super.onResume(); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); + boolean animations = preferences.getBoolean("view_animations", true); + if (!animations) { + firstNameField.requestFocus(); + AndroidUtilities.showKeyboard(firstNameField); + } + } + + @Override + public void onTransitionAnimationEnd(boolean isOpen, boolean backward) { + if (isOpen) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (firstNameField != null) { + firstNameField.requestFocus(); + AndroidUtilities.showKeyboard(firstNameField); + } + } + }, 100); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java index edcc97be..b7dbcd7c 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SecretPhotoViewer.java @@ -202,6 +202,9 @@ public class SecretPhotoViewer implements NotificationCenter.NotificationCenterD windowView.setBackgroundColor(0xff000000); windowView.setFocusable(true); windowView.setFocusableInTouchMode(true); + if (Build.VERSION.SDK_INT >= 23) { + windowView.setFitsSystemWindows(true); //TODO ? + } containerView = new FrameLayoutDrawer(activity); containerView.setFocusable(false); diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SetAdminsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SetAdminsActivity.java new file mode 100644 index 00000000..8b4bdb7b --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/SetAdminsActivity.java @@ -0,0 +1,675 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.EditText; +import android.widget.FrameLayout; +import android.widget.ListView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.ContactsController; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.R; +import org.telegram.messenger.UserConfig; +import org.telegram.messenger.Utilities; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.ActionBarMenu; +import org.telegram.ui.ActionBar.ActionBarMenuItem; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Adapters.BaseFragmentAdapter; +import org.telegram.ui.Cells.TextCheckCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Cells.UserCell; +import org.telegram.ui.Components.EmptyTextProgressView; +import org.telegram.ui.Components.LayoutHelper; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Timer; +import java.util.TimerTask; + +public class SetAdminsActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + private ListAdapter listAdapter; + private SearchAdapter searchAdapter; + private EmptyTextProgressView searchEmptyView; + private ListView listView; + private TLRPC.ChatFull info; + private ArrayList participants = new ArrayList<>(); + private int chat_id; + private TLRPC.Chat chat; + private ActionBarMenuItem searchItem; + private boolean searching; + private boolean searchWas; + + private int allAdminsRow; + private int allAdminsInfoRow; + private int usersStartRow; + private int usersEndRow; + private int rowCount; + + public SetAdminsActivity(Bundle args) { + super(args); + chat_id = args.getInt("chat_id"); + } + + @Override + public boolean onFragmentCreate() { + super.onFragmentCreate(); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.chatInfoDidLoaded); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.updateInterfaces); + return true; + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.chatInfoDidLoaded); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.updateInterfaces); + } + + @Override + public View createView(Context context) { + searching = false; + searchWas = false; + + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(LocaleController.getString("SetAdminsTitle", R.string.SetAdminsTitle)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + + ActionBarMenu menu = actionBar.createMenu(); + searchItem = menu.addItem(0, R.drawable.ic_ab_search).setIsSearchField(true).setActionBarMenuItemSearchListener(new ActionBarMenuItem.ActionBarMenuItemSearchListener() { + @Override + public void onSearchExpand() { + searching = true; + listView.setEmptyView(searchEmptyView); + } + + @Override + public void onSearchCollapse() { + searching = false; + searchWas = false; + if (listView != null) { + listView.setEmptyView(null); + searchEmptyView.setVisibility(View.GONE); + if (listView.getAdapter() != listAdapter) { + listView.setAdapter(listAdapter); + fragmentView.setBackgroundColor(0xfff0f0f0); + } + } + if (searchAdapter != null) { + searchAdapter.search(null); + } + } + + @Override + public void onTextChanged(EditText editText) { + String text = editText.getText().toString(); + if (text.length() != 0) { + searchWas = true; + if (searchAdapter != null && listView.getAdapter() != searchAdapter) { + listView.setAdapter(searchAdapter); + fragmentView.setBackgroundColor(0xffffffff); + } + if (searchEmptyView != null && listView.getEmptyView() != searchEmptyView) { + searchEmptyView.showTextView(); + listView.setEmptyView(searchEmptyView); + } + } + if (searchAdapter != null) { + searchAdapter.search(text); + } + } + }); + searchItem.getSearchField().setHint(LocaleController.getString("Search", R.string.Search)); + + listAdapter = new ListAdapter(context); + searchAdapter = new SearchAdapter(context); + + fragmentView = new FrameLayout(context); + FrameLayout frameLayout = (FrameLayout) fragmentView; + fragmentView.setBackgroundColor(0xfff0f0f0); + + listView = new ListView(context); + listView.setDivider(null); + listView.setDividerHeight(0); + listView.setVerticalScrollBarEnabled(false); + listView.setDrawSelectorOnTop(true); + frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + listView.setAdapter(listAdapter); + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, final int i, long l) { + if (listView.getAdapter() == searchAdapter || i >= usersStartRow && i < usersEndRow) { + UserCell userCell = (UserCell) view; + chat = MessagesController.getInstance().getChat(chat_id); + TLRPC.ChatParticipant participant; + int index = -1; + if (listView.getAdapter() == searchAdapter) { + participant = searchAdapter.getItem(i); + for (int a = 0; a < participants.size(); a++) { + TLRPC.ChatParticipant p = participants.get(a); + if (p.user_id == participant.user_id) { + index = a; + break; + } + } + } else { + participant = participants.get(index = i - usersStartRow); + } + if (index != -1 && !(participant instanceof TLRPC.TL_chatParticipantCreator)) { + TLRPC.ChatParticipant newParticipant; + if (participant instanceof TLRPC.TL_chatParticipant) { + newParticipant = new TLRPC.TL_chatParticipantAdmin(); + newParticipant.user_id = participant.user_id; + newParticipant.date = participant.date; + newParticipant.inviter_id = participant.inviter_id; + } else { + newParticipant = new TLRPC.TL_chatParticipant(); + newParticipant.user_id = participant.user_id; + newParticipant.date = participant.date; + newParticipant.inviter_id = participant.inviter_id; + } + participants.set(index, newParticipant); + index = info.participants.participants.indexOf(participant); + if (index != -1) { + info.participants.participants.set(index, newParticipant); + } + if (listView.getAdapter() == searchAdapter) { + searchAdapter.searchResult.set(i, newParticipant); + } + participant = newParticipant; + userCell.setChecked(!(participant instanceof TLRPC.TL_chatParticipant) || chat != null && !chat.admins_enabled, true); + if (chat != null && chat.admins_enabled) { + MessagesController.getInstance().toggleUserAdmin(chat_id, participant.user_id, !(participant instanceof TLRPC.TL_chatParticipant)); + } + } + } else { + if (i == allAdminsRow) { + chat = MessagesController.getInstance().getChat(chat_id); + if (chat != null) { + chat.admins_enabled = !chat.admins_enabled; + ((TextCheckCell) view).setChecked(!chat.admins_enabled); + MessagesController.getInstance().toggleAdminMode(chat_id, chat.admins_enabled); + } + } + } + } + }); + + searchEmptyView = new EmptyTextProgressView(context); + searchEmptyView.setVisibility(View.GONE); + searchEmptyView.setShowAtCenter(true); + searchEmptyView.setText(LocaleController.getString("NoResult", R.string.NoResult)); + frameLayout.addView(searchEmptyView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + searchEmptyView.showTextView(); + + updateRowsIds(); + + return fragmentView; + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.chatInfoDidLoaded) { + TLRPC.ChatFull chatFull = (TLRPC.ChatFull) args[0]; + if (chatFull.id == chat_id) { + info = chatFull; + updateChatParticipants(); + updateRowsIds(); + } + } if (id == NotificationCenter.updateInterfaces) { + int mask = (Integer) args[0]; + if ((mask & MessagesController.UPDATE_MASK_AVATAR) != 0 || (mask & MessagesController.UPDATE_MASK_NAME) != 0 || (mask & MessagesController.UPDATE_MASK_STATUS) != 0) { + if (listView != null) { + int count = listView.getChildCount(); + for (int a = 0; a < count; a++) { + View child = listView.getChildAt(a); + if (child instanceof UserCell) { + ((UserCell) child).update(mask); + } + } + } + } + } + } + + @Override + public void onResume() { + super.onResume(); + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + } + + public void setChatInfo(TLRPC.ChatFull chatParticipants) { + info = chatParticipants; + updateChatParticipants(); + } + + private int getChatAdminParticipantType(TLRPC.ChatParticipant participant) { + if (participant instanceof TLRPC.TL_chatParticipantCreator) { + return 0; + } else if (participant instanceof TLRPC.TL_chatParticipantAdmin) { + return 1; + } else { + return 2; + } + } + + private void updateChatParticipants() { + if (info == null) { + return; + } + if (participants.size() != info.participants.participants.size()) { + participants.clear(); + participants.addAll(info.participants.participants); + try { + Collections.sort(participants, new Comparator() { + @Override + public int compare(TLRPC.ChatParticipant lhs, TLRPC.ChatParticipant rhs) { + int type1 = getChatAdminParticipantType(lhs); + int type2 = getChatAdminParticipantType(rhs); + if (type1 > type2) { + return 1; + } else if (type1 < type2) { + return -1; + } else if (type1 == type2) { + TLRPC.User user1 = MessagesController.getInstance().getUser(rhs.user_id); + TLRPC.User user2 = MessagesController.getInstance().getUser(lhs.user_id); + int status1 = 0; + int status2 = 0; + if (user1 != null && user1.status != null) { + status1 = user1.status.expires; + } + if (user2 != null && user2.status != null) { + status2 = user2.status.expires; + } + if (status1 > 0 && status2 > 0) { + if (status1 > status2) { + return 1; + } else if (status1 < status2) { + return -1; + } + return 0; + } else if (status1 < 0 && status2 < 0) { + if (status1 > status2) { + return 1; + } else if (status1 < status2) { + return -1; + } + return 0; + } else if (status1 < 0 && status2 > 0 || status1 == 0 && status2 != 0) { + return -1; + } else if (status2 < 0 && status1 > 0 || status2 == 0 && status1 != 0) { + return 1; + } + } + return 0; + } + }); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + private void updateRowsIds() { + rowCount = 0; + allAdminsRow = rowCount++; + allAdminsInfoRow = rowCount++; + if (info != null) { + usersStartRow = rowCount; + rowCount += participants.size(); + usersEndRow = rowCount++; + if (searchItem != null && !searchWas) { + searchItem.setVisibility(View.VISIBLE); + } + } else { + usersStartRow = -1; + usersEndRow = -1; + if (searchItem != null) { + searchItem.setVisibility(View.GONE); + } + } + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + } + + private class ListAdapter extends BaseFragmentAdapter { + private Context mContext; + + public ListAdapter(Context context) { + mContext = context; + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public boolean isEnabled(int i) { + if (i == allAdminsRow) { + return true; + } else if (i >= usersStartRow && i < usersEndRow) { + TLRPC.ChatParticipant participant = participants.get(i - usersStartRow); + if (!(participant instanceof TLRPC.TL_chatParticipantCreator)) { + return true; + } + } + return false; + } + + @Override + public int getCount() { + return rowCount; + } + + @Override + public Object getItem(int i) { + return null; + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public boolean hasStableIds() { + return false; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + int type = getItemViewType(i); + if (type == 0) { + if (view == null) { + view = new TextCheckCell(mContext); + view.setBackgroundColor(0xffffffff); + } + TextCheckCell checkCell = (TextCheckCell) view; + chat = MessagesController.getInstance().getChat(chat_id); + checkCell.setTextAndCheck(LocaleController.getString("SetAdminsAll", R.string.SetAdminsAll), chat != null && !chat.admins_enabled, false); + } else if (type == 1) { + if (view == null) { + view = new TextInfoPrivacyCell(mContext); + } + if (i == allAdminsInfoRow) { + if (chat.admins_enabled) { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("SetAdminsNotAllInfo", R.string.SetAdminsNotAllInfo)); + } else { + ((TextInfoPrivacyCell) view).setText(LocaleController.getString("SetAdminsAllInfo", R.string.SetAdminsAllInfo)); + } + if (usersStartRow != -1) { + view.setBackgroundResource(R.drawable.greydivider); + } else { + view.setBackgroundResource(R.drawable.greydivider_bottom); + } + } else if (i == usersEndRow) { + ((TextInfoPrivacyCell) view).setText(""); + view.setBackgroundResource(R.drawable.greydivider_bottom); + } + } else if (type == 2) { + if (view == null) { + view = new UserCell(mContext, 1, 2, false); + view.setBackgroundColor(0xffffffff); + } + UserCell userCell = (UserCell) view; + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int mainColor = themePrefs.getInt("profileRowColor", 0xffffffff); + userCell.setBackgroundColor(mainColor); + userCell.setTag("Profile"); + TLRPC.ChatParticipant part = participants.get(i - usersStartRow); + TLRPC.User user = MessagesController.getInstance().getUser(part.user_id); + userCell.setData(user, null, null, 0); + chat = MessagesController.getInstance().getChat(chat_id); + userCell.setChecked(!(part instanceof TLRPC.TL_chatParticipant) || chat != null && !chat.admins_enabled, false); + userCell.setCheckDisabled(chat == null || !chat.admins_enabled || part.user_id == UserConfig.getClientUserId()); + } + return view; + } + + @Override + public int getItemViewType(int i) { + if (i == allAdminsRow) { + return 0; + } else if (i == allAdminsInfoRow || i == usersEndRow) { + return 1; + } else { + return 2; + } + } + + @Override + public int getViewTypeCount() { + return 3; + } + + @Override + public boolean isEmpty() { + return false; + } + } + + public class SearchAdapter extends BaseFragmentAdapter { + + private Context mContext; + private ArrayList searchResult = new ArrayList<>(); + private ArrayList searchResultNames = new ArrayList<>(); + private Timer searchTimer; + + public SearchAdapter(Context context) { + mContext = context; + } + + public void search(final String query) { + try { + if (searchTimer != null) { + searchTimer.cancel(); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + if (query == null) { + searchResult.clear(); + searchResultNames.clear(); + notifyDataSetChanged(); + } else { + searchTimer = new Timer(); + searchTimer.schedule(new TimerTask() { + @Override + public void run() { + try { + searchTimer.cancel(); + searchTimer = null; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + processSearch(query); + } + }, 200, 300); + } + } + + private void processSearch(final String query) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + final ArrayList contactsCopy = new ArrayList<>(); + contactsCopy.addAll(participants); + Utilities.searchQueue.postRunnable(new Runnable() { + @Override + public void run() { + String search1 = query.trim().toLowerCase(); + if (search1.length() == 0) { + updateSearchResults(new ArrayList(), new ArrayList()); + return; + } + String search2 = LocaleController.getInstance().getTranslitString(search1); + if (search1.equals(search2) || search2.length() == 0) { + search2 = null; + } + String search[] = new String[1 + (search2 != null ? 1 : 0)]; + search[0] = search1; + if (search2 != null) { + search[1] = search2; + } + + ArrayList resultArray = new ArrayList<>(); + ArrayList resultArrayNames = new ArrayList<>(); + + for (int a = 0; a < contactsCopy.size(); a++) { + TLRPC.ChatParticipant participant = contactsCopy.get(a); + TLRPC.User user = MessagesController.getInstance().getUser(participant.user_id); + if (user.id == UserConfig.getClientUserId()) { + continue; + } + + String name = ContactsController.formatName(user.first_name, user.last_name).toLowerCase(); + String tName = LocaleController.getInstance().getTranslitString(name); + if (name.equals(tName)) { + tName = null; + } + + int found = 0; + for (String q : search) { + if (name.startsWith(q) || name.contains(" " + q) || tName != null && (tName.startsWith(q) || tName.contains(" " + q))) { + found = 1; + } else if (user.username != null && user.username.startsWith(q)) { + found = 2; + } + + if (found != 0) { + if (found == 1) { + resultArrayNames.add(AndroidUtilities.generateSearchName(user.first_name, user.last_name, q)); + } else { + resultArrayNames.add(AndroidUtilities.generateSearchName("@" + user.username, null, "@" + q)); + } + resultArray.add(participant); + break; + } + } + } + + updateSearchResults(resultArray, resultArrayNames); + } + }); + } + }); + } + + private void updateSearchResults(final ArrayList users, final ArrayList names) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + searchResult = users; + searchResultNames = names; + notifyDataSetChanged(); + } + }); + } + + @Override + public boolean areAllItemsEnabled() { + return true; + } + + @Override + public boolean isEnabled(int i) { + return true; + } + + @Override + public int getCount() { + return searchResult.size(); + } + + @Override + public TLRPC.ChatParticipant getItem(int i) { + return searchResult.get(i); + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public boolean hasStableIds() { + return true; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + if (view == null) { + view = new UserCell(mContext, 1, 2, false); + } + + TLRPC.ChatParticipant participant = getItem(i); + TLRPC.User user = MessagesController.getInstance().getUser(participant.user_id); + String un = user.username; + + CharSequence username = null; + CharSequence name = null; + if (i < searchResult.size()) { + name = searchResultNames.get(i); + if (name != null && un != null && un.length() > 0) { + if (name.toString().startsWith("@" + un)) { + username = name; + name = null; + } + } + } + UserCell userCell = (UserCell) view; + userCell.setData(user, name, username, 0); + chat = MessagesController.getInstance().getChat(chat_id); + userCell.setChecked(!(participant instanceof TLRPC.TL_chatParticipant) || chat != null && !chat.admins_enabled, false); + userCell.setCheckDisabled(chat == null || !chat.admins_enabled || participant.user_id == UserConfig.getClientUserId()); + return view; + } + + @Override + public int getItemViewType(int i) { + return 0; + } + + @Override + public int getViewTypeCount() { + return 1; + } + + @Override + public boolean isEmpty() { + return searchResult.isEmpty(); + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java index 4d325e5e..03f6d7c3 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/SettingsActivity.java @@ -29,13 +29,13 @@ import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.support.annotation.NonNull; import android.text.Html; import android.text.Spannable; import android.text.TextUtils; import android.text.method.LinkMovementMethod; import android.util.Base64; -import android.util.Log; import android.util.TypedValue; import android.view.Gravity; import android.view.MotionEvent; @@ -50,7 +50,6 @@ import android.widget.AdapterView; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.ListAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; @@ -74,6 +73,7 @@ import org.telegram.messenger.NotificationCenter; import org.telegram.messenger.R; import org.telegram.messenger.UserConfig; import org.telegram.messenger.UserObject; +import org.telegram.messenger.browser.Browser; import org.telegram.tgnet.ConnectionsManager; import org.telegram.tgnet.RequestDelegate; import org.telegram.tgnet.SerializedData; @@ -84,6 +84,7 @@ import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.ActionBarMenuItem; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.ActionBar.BottomSheet; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Adapters.BaseFragmentAdapter; import org.telegram.ui.Cells.CheckBoxCell; import org.telegram.ui.Cells.EmptyCell; @@ -92,7 +93,6 @@ import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextDetailSettingsCell; import org.telegram.ui.Cells.TextInfoCell; -import org.telegram.ui.Cells.TextInfoPrivacyCell; import org.telegram.ui.Cells.TextSettingsCell; import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.AvatarUpdater; @@ -140,14 +140,18 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter private int saveToGalleryRow; private int messagesSectionRow; private int messagesSectionRow2; + private int customTabsRow; + private int directShareRow; private int textSizeRow; private int stickersRow; private int cacheRow; + private int raiseToSpeakRow; private int sendByEnterRow; private int supportSectionRow; private int supportSectionRow2; private int askQuestionRow; private int telegramFaqRow; + private int privacyPolicyRow; private int sendLogsRow; private int clearLogsRow; private int switchBackendButtonRow; @@ -160,6 +164,13 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter private final static int edit_name = 1; private final static int logout = 2; + //plus + private int aboutRow; + private TextDetailSettingsCell aboutLinkCell; + private String userAbout; + private int linkSearchRequestId; + private TLRPC.WebPage foundWebPage; + private int pass; private static class LinkMovementMethodMy extends LinkMovementMethod { @Override @@ -231,6 +242,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter } }; NotificationCenter.getInstance().addObserver(this, NotificationCenter.updateInterfaces); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.userInfoDidLoaded); SharedPreferences plusPreferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); boolean hideMobile = plusPreferences.getBoolean("hideMobile", false); @@ -242,6 +254,11 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter numberRow = rowCount++; } usernameRow = rowCount++; + if (BuildVars.DEBUG_VERSION) { + aboutRow = rowCount++; + }else{ + aboutRow = -1; + } settingsSectionRow = rowCount++; settingsSectionRow2 = rowCount++; notificationRow = rowCount++; @@ -249,7 +266,6 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter backgroundRow = rowCount++; languageRow = rowCount++; enableAnimationsRow = rowCount++; - mediaDownloadSection = rowCount++; mediaDownloadSection2 = rowCount++; mobileDownloadRow = rowCount++; @@ -259,19 +275,22 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter autoplayGifsRow = rowCount++; } saveToGalleryRow = rowCount++; - messagesSectionRow = rowCount++; messagesSectionRow2 = rowCount++; + customTabsRow = rowCount++; + if (Build.VERSION.SDK_INT >= 23) { + directShareRow = rowCount++; + } textSizeRow = rowCount++; stickersRow = rowCount++; cacheRow = rowCount++; - + raiseToSpeakRow = rowCount++; sendByEnterRow = rowCount++; - supportSectionRow = rowCount++; supportSectionRow2 = rowCount++; askQuestionRow = rowCount++; telegramFaqRow = rowCount++; + privacyPolicyRow = rowCount++; if (BuildVars.DEBUG_VERSION) { sendLogsRow = rowCount++; clearLogsRow = rowCount++; @@ -282,8 +301,8 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter //contactsReimportRow = rowCount++; //contactsSortRow = rowCount++; - MessagesController.getInstance().loadFullUser(UserConfig.getCurrentUser(), classGuid); - + MessagesController.getInstance().loadFullUser(UserConfig.getCurrentUser(), classGuid, true); + getUserAbout(UserConfig.getClientUserId()); return true; } @@ -295,13 +314,14 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter } MessagesController.getInstance().cancelLoadFullUser(UserConfig.getClientUserId()); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.updateInterfaces); + NotificationCenter.getInstance().removeObserver(this, NotificationCenter.userInfoDidLoaded); avatarUpdater.clear(); } @Override public View createView(Context context) { //actionBar.setBackgroundColor(AvatarDrawable.getProfileBackColorForId(5)); - //actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); + //actionBar.setItemsBackgroundColor(AvatarDrawable.getButtonColorForId(5)); actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setAddToContainer(false); extraHeight = 88; @@ -384,7 +404,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter listView.setDividerHeight(0); listView.setVerticalScrollBarEnabled(false); //AndroidUtilities.setListViewEdgeEffectColor(listView, AvatarDrawable.getProfileBackColorForId(5)); - AndroidUtilities.setListViewEdgeEffectColor(listView, bgColor); + AndroidUtilities.setListViewEdgeEffectColor(listView, hColor); frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); listView.setAdapter(listAdapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @@ -408,7 +428,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter SharedPreferences.Editor editor = preferences.edit(); editor.putInt("fons_size", numberPicker.getValue()); MessagesController.getInstance().fontSize = numberPicker.getValue(); - editor.apply(); + editor.commit(); // SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); SharedPreferences.Editor edit = themePrefs.edit(); @@ -450,7 +470,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter boolean animations = preferences.getBoolean("view_animations", true); SharedPreferences.Editor editor = preferences.edit(); editor.putBoolean("view_animations", !animations); - editor.apply();; + editor.commit(); if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(!animations); } @@ -465,6 +485,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter final TextView message = new TextView(getParentActivity()); message.setText(Html.fromHtml(LocaleController.getString("AskAQuestionInfo", R.string.AskAQuestionInfo))); message.setTextSize(18); + message.setLinkTextColor(Theme.MSG_LINK_TEXT_COLOR); message.setPadding(AndroidUtilities.dp(8), AndroidUtilities.dp(5), AndroidUtilities.dp(8), AndroidUtilities.dp(6)); message.setMovementMethod(new LinkMovementMethodMy()); @@ -487,10 +508,15 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter boolean send = preferences.getBoolean("send_by_enter", false); SharedPreferences.Editor editor = preferences.edit(); editor.putBoolean("send_by_enter", !send); - editor.apply();; + editor.commit(); if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(!send); } + } else if (i == raiseToSpeakRow) { + MediaController.getInstance().toogleRaiseToSpeak(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(MediaController.getInstance().canRaiseToSpeak()); + } } else if (i == autoplayGifsRow) { MediaController.getInstance().toggleAutoplayGifs(); if (view instanceof TextCheckCell) { @@ -501,6 +527,16 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(MediaController.getInstance().canSaveToGallery()); } + } else if (i == customTabsRow) { + MediaController.getInstance().toggleCustomTabs(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(MediaController.getInstance().canCustomTabs()); + } + } else if(i == directShareRow) { + MediaController.getInstance().toggleDirectShare(); + if (view instanceof TextCheckCell) { + ((TextCheckCell) view).setChecked(MediaController.getInstance().canDirectShare()); + } } else if (i == privacyRow) { presentFragment(new PrivacySettingsActivity()); } else if (i == languageRow) { @@ -521,12 +557,9 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); } else if (i == telegramFaqRow) { - try { - Intent pickIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl))); - getParentActivity().startActivityForResult(pickIntent, 500); - } catch (Exception e) { - FileLog.e("tmessages", e); - } + Browser.openUrl(getParentActivity(), LocaleController.getString("TelegramFaqUrl", R.string.TelegramFaqUrl)); + } else if (i == privacyPolicyRow) { + Browser.openUrl(getParentActivity(), LocaleController.getString("PrivacyPolicyUrl", R.string.PrivacyPolicyUrl)); } else if (i == contactsReimportRow) { //not implemented } else if (i == contactsSortRow) { @@ -545,7 +578,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); editor.putInt("sortContactsBy", which); - editor.apply();; + editor.commit(); if (listView != null) { listView.invalidateViews(); } @@ -569,7 +602,8 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter mask = MediaController.getInstance().roamingDownloadMask; } - builder.setApplyTopPaddings(false); + builder.setApplyTopPadding(false); + builder.setApplyBottomPadding(false); LinearLayout linearLayout = new LinearLayout(getParentActivity()); linearLayout.setOrientation(LinearLayout.VERTICAL); for (int a = 0; a < 6; a++) { @@ -615,7 +649,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter BottomSheet.BottomSheetCell cell = new BottomSheet.BottomSheetCell(getParentActivity(), 2); cell.setBackgroundResource(R.drawable.list_selector); cell.setTextAndIcon(LocaleController.getString("Save", R.string.Save).toUpperCase(), 0); - cell.setTextColor(0xffcd5a5a); + cell.setTextColor(Theme.AUTODOWNLOAD_SHEET_SAVE_TEXT_COLOR); cell.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -655,7 +689,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter editor.putInt("roamingDownloadMask", newMask); MediaController.getInstance().roamingDownloadMask = newMask; } - editor.apply();; + editor.commit(); if (listView != null) { listView.invalidateViews(); } @@ -673,9 +707,39 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter } else if (i == cacheRow) { presentFragment(new CacheControlActivity()); } + //plus + else if (i == aboutRow) { + presentFragment(new ChangeAboutActivity()); + } } }); + listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { + @Override + public boolean onItemLongClick(AdapterView adapterView, View view, int i, long l) { + if (getParentActivity() == null) { + return false; + } + if (i == aboutRow) { + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("plusconfig", Activity.MODE_PRIVATE); + final boolean showEmojiBtn = preferences.getBoolean("showEmojiKbBtn", false); + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean("showEmojiKbBtn", !showEmojiBtn); + editor.apply(); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (getParentActivity() != null) { + Toast toast = Toast.makeText(getParentActivity(), "Show emoji button: " + showEmojiBtn, Toast.LENGTH_SHORT); + toast.show(); + } + } + }); + } + return true; + } + }); + frameLayout.addView(actionBar); extraHeightView = new View(context); @@ -701,7 +765,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter @Override public void onClick(View v) { TLRPC.User user = MessagesController.getInstance().getUser(UserConfig.getClientUserId()); - if (user.photo != null && user.photo.photo_big != null) { + if (user != null && user.photo != null && user.photo.photo_big != null) { PhotoViewer.getInstance().setParentActivity(getParentActivity()); PhotoViewer.getInstance().openPhoto(user.photo.photo_big, SettingsActivity.this); } @@ -968,7 +1032,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter SerializedData data = new SerializedData(); res.user.serializeToStream(data); editor.putString("support_user", Base64.encodeToString(data.toByteArray(), Base64.DEFAULT)); - editor.apply();; + editor.commit(); data.cleanup(); try { progressDialog.dismiss(); @@ -1033,6 +1097,27 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter updateUserData(); } } + else if(id == NotificationCenter.userInfoDidLoaded){ + TLRPC.User user = UserConfig.getCurrentUser(); + if (aboutLinkCell != null && user.id == (Integer) args[0]) { + //Log.e("SettingsActivity","userInfoDidLoaded " + (Integer) args[0]); + String about = MessagesController.getInstance().getUserAbout(user.id); + String value; + if (about != null && about.length() > 0) { + value = about; + } else { + if( userAbout != null && userAbout.length() > 0){ + value = userAbout; + } else{ + value = LocaleController.getString("UsernameEmpty", R.string.UsernameEmpty); + } + //value = LocaleController.getString("UsernameEmpty", R.string.UsernameEmpty); + } + //Log.e("SettingsActivity","userInfoDidLoaded " + args[0] + " " + value); + aboutLinkCell.setTextAndValue(value, LocaleController.getString("Bio", R.string.Bio), false); + aboutLinkCell.setMultilineText(true); + } + } } @Override @@ -1060,6 +1145,52 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter other.setColorFilter(themePrefs.getInt("prefHeaderIconsColor", 0xffffffff), PorterDuff.Mode.MULTIPLY); } + public void getUserAbout(final int uid) { + final TLRPC.User user = MessagesController.getInstance().getUser(uid); + if(user == null || user.username == null){ + return; + } + String link = String.format("https://telegram.me/%s", user.username); + //Log.e("SettingsActivity", "getUserAbout link "+link); + userAbout = null; + final TLRPC.TL_messages_getWebPagePreview req = new TLRPC.TL_messages_getWebPagePreview(); + req.message = link; + + linkSearchRequestId = ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(final TLObject response, final TLRPC.TL_error error) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + linkSearchRequestId = 0; + if (error == null) { + if (response instanceof TLRPC.TL_messageMediaWebPage) { + foundWebPage = ((TLRPC.TL_messageMediaWebPage) response).webpage; + if(foundWebPage.description != null){ + userAbout = foundWebPage.description; + //Log.e("SettingsActivity", "userAbout "+userAbout); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.userInfoDidLoaded, uid); + } else{ + if(pass != 1){ + pass = 1; + final Handler handler = new Handler(); + handler.postDelayed(new Runnable() { + @Override + public void run() { + getUserAbout(uid); + } + }, 500); + } + } + } + } + } + }); + } + }); + ConnectionsManager.getInstance().bindRequestToGuid(linkSearchRequestId, classGuid); + } + @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); @@ -1184,7 +1315,7 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter photoBig = user.photo.photo_big; } AvatarDrawable avatarDrawable = new AvatarDrawable(user, true); - //avatarDrawable.setColor(0xff5c98cd); + //avatarDrawable.setColor(Theme.ACTION_BAR_MAIN_AVATAR_COLOR); avatarDrawable.setColor(AndroidUtilities.getIntDef("prefAvatarColor", AndroidUtilities.getIntDarkerColor("themeColor", 0x10))); int radius = AndroidUtilities.dp(AndroidUtilities.getIntDef("prefAvatarRadius", 32)); avatarImage.getImageReceiver().setRoundRadius(radius); @@ -1258,9 +1389,9 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter public boolean isEnabled(int i) { return i == textSizeRow || i == enableAnimationsRow || i == notificationRow || i == backgroundRow || i == numberRow || i == askQuestionRow || i == sendLogsRow || i == sendByEnterRow || i == autoplayGifsRow || i == privacyRow || i == wifiDownloadRow || - i == mobileDownloadRow || i == clearLogsRow || i == roamingDownloadRow || i == languageRow || i == usernameRow || + i == mobileDownloadRow || i == clearLogsRow || i == roamingDownloadRow || i == languageRow || i == usernameRow || i == aboutRow || i == switchBackendButtonRow || i == telegramFaqRow || i == contactsSortRow || i == contactsReimportRow || i == saveToGalleryRow || - i == stickersRow || i == cacheRow; + i == stickersRow || i == cacheRow || i == raiseToSpeakRow || i == privacyPolicyRow || i == customTabsRow || i == directShareRow; } @Override @@ -1346,6 +1477,8 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter textCell.setText(LocaleController.getString("Stickers", R.string.Stickers), true); } else if (i == cacheRow) { textCell.setText(LocaleController.getString("CacheSettings", R.string.CacheSettings), true); + } else if (i == privacyPolicyRow) { + textCell.setText(LocaleController.getString("PrivacyPolicy", R.string.PrivacyPolicy), true); } } else if (type == 3) { if (view == null) { @@ -1355,13 +1488,19 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); if (i == enableAnimationsRow) { - textCell.setTextAndCheck(LocaleController.getString("EnableAnimations", R.string.EnableAnimations), preferences.getBoolean("view_animations", true), true); + textCell.setTextAndCheck(LocaleController.getString("EnableAnimations", R.string.EnableAnimations), preferences.getBoolean("view_animations", true), false); } else if (i == sendByEnterRow) { - textCell.setTextAndCheck(LocaleController.getString("SendByEnter", R.string.SendByEnter), preferences.getBoolean("send_by_enter", false), true); + textCell.setTextAndCheck(LocaleController.getString("SendByEnter", R.string.SendByEnter), preferences.getBoolean("send_by_enter", false), false); } else if (i == saveToGalleryRow) { - textCell.setTextAndCheck(LocaleController.getString("SaveToGallerySettings", R.string.SaveToGallerySettings), MediaController.getInstance().canSaveToGallery(), true); + textCell.setTextAndCheck(LocaleController.getString("SaveToGallerySettings", R.string.SaveToGallerySettings), MediaController.getInstance().canSaveToGallery(), false); } else if (i == autoplayGifsRow) { textCell.setTextAndCheck(LocaleController.getString("AutoplayGifs", R.string.AutoplayGifs), MediaController.getInstance().canAutoplayGifs(), true); + } else if (i == raiseToSpeakRow) { + textCell.setTextAndCheck(LocaleController.getString("RaiseToSpeak", R.string.RaiseToSpeak), MediaController.getInstance().canRaiseToSpeak(), true); + } else if (i == customTabsRow) { + textCell.setTextAndValueAndCheck(LocaleController.getString("ChromeCustomTabs", R.string.ChromeCustomTabs), LocaleController.getString("ChromeCustomTabsInfo", R.string.ChromeCustomTabsInfo), MediaController.getInstance().canCustomTabs(), false, true); + } else if (i == directShareRow) { + textCell.setTextAndValueAndCheck(LocaleController.getString("DirectShare", R.string.DirectShare), LocaleController.getString("DirectShareInfo", R.string.DirectShareInfo), MediaController.getInstance().canDirectShare(), false, true); } } else if (type == 4) { if (view == null) { @@ -1383,7 +1522,23 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter view = new TextInfoCell(mContext); try { PackageInfo pInfo = ApplicationLoader.applicationContext.getPackageManager().getPackageInfo(ApplicationLoader.applicationContext.getPackageName(), 0); - ((TextInfoCell) view).setText(String.format(Locale.US, "Telegram for Android v%s (%d)", pInfo.versionName, pInfo.versionCode)); + int code = pInfo.versionCode / 10; + String abi = ""; + switch (pInfo.versionCode % 10) { + case 0: + abi = "arm"; + break; + case 1: + abi = "arm-v7a"; + break; + case 2: + abi = "x86"; + break; + case 3: + abi = "universal"; + break; + } + ((TextInfoCell) view).setText(String.format(Locale.US, "Telegram for Android v%s (%d) %s", pInfo.versionName, code, abi)); } catch (Exception e) { FileLog.e("tmessages", e); } @@ -1467,6 +1622,27 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter } textCell.setTextAndValue(value, LocaleController.getString("Username", R.string.Username), false); } + // + else if (i == aboutRow) { + aboutLinkCell = (TextDetailSettingsCell) view; + //aboutLinkCell.setMultilineDetail(true); + + TLRPC.User user = UserConfig.getCurrentUser(); + String about = MessagesController.getInstance().getUserAbout(user.id); + String value; + if (about != null && about.length() > 0) { + value = about; + } else { + if( userAbout != null && userAbout.length() > 0){ + value = userAbout; + } else{ + value = LocaleController.getString("UsernameEmpty", R.string.UsernameEmpty); + } + //value = LocaleController.getString("UsernameEmpty", R.string.UsernameEmpty); + } + aboutLinkCell.setTextAndValue(value, LocaleController.getString("Bio", R.string.Bio), false); + aboutLinkCell.setMultilineText(true); + } } return view; } @@ -1478,15 +1654,16 @@ public class SettingsActivity extends BaseFragment implements NotificationCenter } if (i == settingsSectionRow || i == supportSectionRow || i == messagesSectionRow || i == mediaDownloadSection || i == contactsSectionRow) { return 1; - } else if (i == enableAnimationsRow || i == sendByEnterRow || i == saveToGalleryRow || i == autoplayGifsRow) { + } else if (i == enableAnimationsRow || i == sendByEnterRow || i == saveToGalleryRow || i == autoplayGifsRow || i == raiseToSpeakRow || i == customTabsRow || i == directShareRow) { return 3; - } else if (i == notificationRow || i == backgroundRow || i == askQuestionRow || i == sendLogsRow || i == privacyRow || i == clearLogsRow || i == switchBackendButtonRow || i == telegramFaqRow || i == contactsReimportRow || i == textSizeRow || i == languageRow || i == contactsSortRow || i == stickersRow || i == cacheRow) { + } else if (i == notificationRow || i == backgroundRow || i == askQuestionRow || i == sendLogsRow || i == privacyRow || i == clearLogsRow || i == switchBackendButtonRow || i == telegramFaqRow || i == contactsReimportRow || i == textSizeRow || i == languageRow || i == contactsSortRow || i == stickersRow || i == cacheRow || i == privacyPolicyRow) { return 2; } else if (i == versionRow) { return 5; - } else if (i == wifiDownloadRow || i == mobileDownloadRow || i == roamingDownloadRow || i == numberRow || i == usernameRow) { + } else if (i == wifiDownloadRow || i == mobileDownloadRow || i == roamingDownloadRow || i == numberRow || i == usernameRow || i == aboutRow) { return 6; - } else if (i == settingsSectionRow2 || i == messagesSectionRow2 || i == supportSectionRow2 || i == numberSectionRow || i == mediaDownloadSection2) { + } + else if (i == settingsSectionRow2 || i == messagesSectionRow2 || i == supportSectionRow2 || i == numberSectionRow || i == mediaDownloadSection2) { return 4; } else { return 2; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ShortcutActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ShortcutActivity.java new file mode 100644 index 00000000..875510a0 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ShortcutActivity.java @@ -0,0 +1,33 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.Window; + +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.R; + +public class ShortcutActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + requestWindowFeature(Window.FEATURE_NO_TITLE); + setTheme(R.style.Theme_TMessages); + getWindow().setBackgroundDrawableResource(R.drawable.transparent); + super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + intent.setClassName(ApplicationLoader.applicationContext.getPackageName(), "org.telegram.ui.LaunchActivity"); + startActivity(intent); + finish(); + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StickerPreviewViewer.java b/TMessagesProj/src/main/java/org/telegram/ui/StickerPreviewViewer.java new file mode 100644 index 00000000..9970ed5e --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/StickerPreviewViewer.java @@ -0,0 +1,430 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.PixelFormat; +import android.graphics.drawable.ColorDrawable; +import android.os.Build; +import android.view.Gravity; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; +import android.widget.AbsListView; +import android.widget.AdapterView; +import android.widget.FrameLayout; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ImageReceiver; +import org.telegram.messenger.FileLog; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.Cells.ContextLinkCell; +import org.telegram.ui.Cells.StickerCell; +import org.telegram.ui.Cells.StickerEmojiCell; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RecyclerListView; + +public class StickerPreviewViewer { + + private class FrameLayoutDrawer extends FrameLayout { + public FrameLayoutDrawer(Context context) { + super(context); + setWillNotDraw(false); + } + + @Override + protected void onDraw(Canvas canvas) { + getInstance().onDraw(canvas); + } + } + + private int startX; + private int startY; + private View currentStickerPreviewCell; + private Runnable openStickerPreviewRunnable; + + private ColorDrawable backgroundDrawable = new ColorDrawable(0x71000000); + private Activity parentActivity; + private WindowManager.LayoutParams windowLayoutParams; + private FrameLayout windowView; + private FrameLayoutDrawer containerView; + private ImageReceiver centerImage = new ImageReceiver(); + private boolean isVisible = false; + private float showProgress; + private long lastUpdateTime; + private int keyboardHeight = AndroidUtilities.dp(200); + + private TLRPC.Document currentSticker = null; + + private static volatile StickerPreviewViewer Instance = null; + public static StickerPreviewViewer getInstance() { + StickerPreviewViewer localInstance = Instance; + if (localInstance == null) { + synchronized (PhotoViewer.class) { + localInstance = Instance; + if (localInstance == null) { + Instance = localInstance = new StickerPreviewViewer(); + } + } + } + return localInstance; + } + + public void reset() { + if (openStickerPreviewRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); + openStickerPreviewRunnable = null; + } + if (currentStickerPreviewCell != null) { + if (currentStickerPreviewCell instanceof StickerEmojiCell) { + ((StickerEmojiCell) currentStickerPreviewCell).setScaled(false); + } else if (currentStickerPreviewCell instanceof StickerCell) { + ((StickerCell) currentStickerPreviewCell).setScaled(false); + } else if (currentStickerPreviewCell instanceof ContextLinkCell) { + ((ContextLinkCell) currentStickerPreviewCell).setScaled(false); + } + currentStickerPreviewCell = null; + } + } + + public boolean onTouch(MotionEvent event, final View listView, final int height, final Object listener) { + if (openStickerPreviewRunnable != null || isVisible()) { + if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL || event.getAction() == MotionEvent.ACTION_POINTER_UP) { + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + if (listView instanceof AbsListView) { + ((AbsListView) listView).setOnItemClickListener((AdapterView.OnItemClickListener) listener); + } else if (listView instanceof RecyclerListView) { + ((RecyclerListView) listView).setOnItemClickListener((RecyclerListView.OnItemClickListener) listener); + } + } + }, 150); + if (openStickerPreviewRunnable != null) { + AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); + openStickerPreviewRunnable = null; + } else if (isVisible()) { + close(); + if (currentStickerPreviewCell != null) { + if (currentStickerPreviewCell instanceof StickerEmojiCell) { + ((StickerEmojiCell) currentStickerPreviewCell).setScaled(false); + } else if (currentStickerPreviewCell instanceof StickerCell) { + ((StickerCell) currentStickerPreviewCell).setScaled(false); + } else if (currentStickerPreviewCell instanceof ContextLinkCell) { + ((ContextLinkCell) currentStickerPreviewCell).setScaled(false); + } + currentStickerPreviewCell = null; + } + } + } else if (event.getAction() != MotionEvent.ACTION_DOWN) { + if (isVisible()) { + if (event.getAction() == MotionEvent.ACTION_MOVE) { + int x = (int) event.getX(); + int y = (int) event.getY(); + int count = 0; + if (listView instanceof AbsListView) { + count = ((AbsListView) listView).getChildCount(); + } else if (listView instanceof RecyclerListView) { + count = ((RecyclerListView) listView).getChildCount(); + } + for (int a = 0; a < count; a++) { + View view = null; + if (listView instanceof AbsListView) { + view = ((AbsListView) listView).getChildAt(a); + } else if (listView instanceof RecyclerListView) { + view = ((RecyclerListView) listView).getChildAt(a); + } + if (view == null) { + return false; + } + int top = view.getTop(); + int bottom = view.getBottom(); + int left = view.getLeft(); + int right = view.getRight(); + if (top > y || bottom < y || left > x || right < x) { + continue; + } + boolean ok = false; + if (view instanceof StickerEmojiCell) { + ok = true; + } else if (view instanceof StickerCell) { + ok = true; + } else if (view instanceof ContextLinkCell) { + ok = ((ContextLinkCell) view).isSticker(); + } + if (!ok || view == currentStickerPreviewCell) { + break; + } + if (currentStickerPreviewCell instanceof StickerEmojiCell) { + ((StickerEmojiCell) currentStickerPreviewCell).setScaled(false); + } else if (currentStickerPreviewCell instanceof StickerCell) { + ((StickerCell) currentStickerPreviewCell).setScaled(false); + } else if (currentStickerPreviewCell instanceof ContextLinkCell) { + ((ContextLinkCell) currentStickerPreviewCell).setScaled(false); + } + currentStickerPreviewCell = view; + setKeyboardHeight(height); + if (currentStickerPreviewCell instanceof StickerEmojiCell) { + open(((StickerEmojiCell) currentStickerPreviewCell).getSticker()); + ((StickerEmojiCell) currentStickerPreviewCell).setScaled(true); + } else if (currentStickerPreviewCell instanceof StickerCell) { + open(((StickerCell) currentStickerPreviewCell).getSticker()); + ((StickerCell) currentStickerPreviewCell).setScaled(true); + } else if (currentStickerPreviewCell instanceof ContextLinkCell) { + open(((ContextLinkCell) currentStickerPreviewCell).getDocument()); + ((ContextLinkCell) currentStickerPreviewCell).setScaled(true); + } + return true; + } + } + return true; + } else if (openStickerPreviewRunnable != null) { + if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (Math.hypot(startX - event.getX(), startY - event.getY()) > AndroidUtilities.dp(10)) { + AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); + openStickerPreviewRunnable = null; + } + } else { + AndroidUtilities.cancelRunOnUIThread(openStickerPreviewRunnable); + openStickerPreviewRunnable = null; + } + } + } + } + return false; + } + + public boolean onInterceptTouchEvent(MotionEvent event, final View listView, final int height) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + int x = (int) event.getX(); + int y = (int) event.getY(); + int count = 0; + if (listView instanceof AbsListView) { + count = ((AbsListView) listView).getChildCount(); + } else if (listView instanceof RecyclerListView) { + count = ((RecyclerListView) listView).getChildCount(); + } + for (int a = 0; a < count; a++) { + View view = null; + if (listView instanceof AbsListView) { + view = ((AbsListView) listView).getChildAt(a); + } else if (listView instanceof RecyclerListView) { + view = ((RecyclerListView) listView).getChildAt(a); + } + if (view == null) { + return false; + } + int top = view.getTop(); + int bottom = view.getBottom(); + int left = view.getLeft(); + int right = view.getRight(); + if (top > y || bottom < y || left > x || right < x) { + continue; + } + boolean ok = false; + if (view instanceof StickerEmojiCell) { + ok = ((StickerEmojiCell) view).showingBitmap(); + } else if (view instanceof StickerCell) { + ok = ((StickerCell) view).showingBitmap(); + } else if (view instanceof ContextLinkCell) { + ContextLinkCell cell = (ContextLinkCell) view; + ok = cell.isSticker() && cell.showingBitmap(); + } + if (!ok) { + return false; + } + startX = x; + startY = y; + currentStickerPreviewCell = view; + openStickerPreviewRunnable = new Runnable() { + @Override + public void run() { + if (openStickerPreviewRunnable == null) { + return; + } + if (listView instanceof AbsListView) { + ((AbsListView) listView).setOnItemClickListener(null); + ((AbsListView) listView).requestDisallowInterceptTouchEvent(true); + } else if (listView instanceof RecyclerListView) { + ((RecyclerListView) listView).setOnItemClickListener(null); + ((RecyclerListView) listView).requestDisallowInterceptTouchEvent(true); + } + openStickerPreviewRunnable = null; + setParentActivity((Activity) listView.getContext()); + setKeyboardHeight(height); + if (currentStickerPreviewCell instanceof StickerEmojiCell) { + open(((StickerEmojiCell) currentStickerPreviewCell).getSticker()); + ((StickerEmojiCell) currentStickerPreviewCell).setScaled(true); + } else if (currentStickerPreviewCell instanceof StickerCell) { + open(((StickerCell) currentStickerPreviewCell).getSticker()); + ((StickerCell) currentStickerPreviewCell).setScaled(true); + } else if (currentStickerPreviewCell instanceof ContextLinkCell) { + open(((ContextLinkCell) currentStickerPreviewCell).getDocument()); + ((ContextLinkCell) currentStickerPreviewCell).setScaled(true); + } + } + }; + AndroidUtilities.runOnUIThread(openStickerPreviewRunnable, 200); + return true; + } + } + return false; + } + + public void setParentActivity(Activity activity) { + if (parentActivity == activity) { + return; + } + parentActivity = activity; + + windowView = new FrameLayout(activity); + windowView.setFocusable(true); + windowView.setFocusableInTouchMode(true); + if (Build.VERSION.SDK_INT >= 23) { + windowView.setFitsSystemWindows(true); + } + + containerView = new FrameLayoutDrawer(activity); + containerView.setFocusable(false); + windowView.addView(containerView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT)); + containerView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_POINTER_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { + close(); + } + return true; + } + }); + + windowLayoutParams = new WindowManager.LayoutParams(); + windowLayoutParams.height = WindowManager.LayoutParams.MATCH_PARENT; + windowLayoutParams.format = PixelFormat.TRANSLUCENT; + windowLayoutParams.width = WindowManager.LayoutParams.MATCH_PARENT; + windowLayoutParams.gravity = Gravity.TOP; + windowLayoutParams.type = WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; + if (Build.VERSION.SDK_INT >= 21) { + windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; + } else { + windowLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + } + centerImage.setAspectFit(true); + centerImage.setInvalidateAll(true); + centerImage.setParentView(containerView); + } + + public void setKeyboardHeight(int height) { + keyboardHeight = height; + } + + public void open(TLRPC.Document sticker) { + if (parentActivity == null || sticker == null) { + return; + } + + centerImage.setImage(sticker, null, sticker.thumb.location, null, "webp", true); + currentSticker = sticker; + containerView.invalidate(); + + if (!isVisible) { + AndroidUtilities.lockOrientation(parentActivity); + try { + if (windowView.getParent() != null) { + WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); + wm.removeView(windowView); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); + wm.addView(windowView, windowLayoutParams); + isVisible = true; + showProgress = 0.0f; + lastUpdateTime = System.currentTimeMillis(); + } + } + + public boolean isVisible() { + return isVisible; + } + + public void close() { + if (parentActivity == null) { + return; + } + showProgress = 1.0f; + currentSticker = null; + isVisible = false; + AndroidUtilities.unlockOrientation(parentActivity); + AndroidUtilities.runOnUIThread(new Runnable() { + @Override + public void run() { + centerImage.setImageBitmap((Bitmap)null); + } + }); + try { + if (windowView.getParent() != null) { + WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); + wm.removeView(windowView); + } + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + + public void destroy() { + isVisible = false; + currentSticker = null; + if (parentActivity == null || windowView == null) { + return; + } + try { + if (windowView.getParent() != null) { + WindowManager wm = (WindowManager) parentActivity.getSystemService(Context.WINDOW_SERVICE); + wm.removeViewImmediate(windowView); + } + windowView = null; + } catch (Exception e) { + FileLog.e("tmessages", e); + } + Instance = null; + } + + private void onDraw(Canvas canvas) { + backgroundDrawable.setAlpha((int) (180 * showProgress)); + backgroundDrawable.setBounds(0, 0, containerView.getWidth(), containerView.getHeight()); + backgroundDrawable.draw(canvas); + + canvas.save(); + int size = (int) (Math.min(containerView.getWidth(), containerView.getHeight()) / 1.8f); + canvas.translate(containerView.getWidth() / 2, Math.max(size / 2 + AndroidUtilities.statusBarHeight, (containerView.getHeight() - keyboardHeight) / 2)); + Bitmap bitmap = centerImage.getBitmap(); + if (bitmap != null) { + float scale = 0.8f * showProgress / 0.8f; + size = (int) (size * scale); + centerImage.setAlpha(showProgress); + centerImage.setImageCoords(-size / 2, -size / 2, size, size); + centerImage.draw(canvas); + } + canvas.restore(); + if (showProgress != 1) { + long newTime = System.currentTimeMillis(); + long dt = newTime - lastUpdateTime; + lastUpdateTime = newTime; + showProgress += dt / 150.0f; + containerView.invalidate(); + if (showProgress > 1.0f) { + showProgress = 1.0f; + } + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java new file mode 100644 index 00000000..6cde6e63 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/StickersActivity.java @@ -0,0 +1,410 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.graphics.Canvas; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Message; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.Toast; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.MessagesController; +import org.telegram.messenger.NotificationCenter; +import org.telegram.messenger.query.StickersQuery; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.FileLog; +import org.telegram.messenger.R; +import org.telegram.messenger.support.widget.LinearLayoutManager; +import org.telegram.messenger.support.widget.RecyclerView; +import org.telegram.messenger.support.widget.helper.ItemTouchHelper; +import org.telegram.tgnet.ConnectionsManager; +import org.telegram.tgnet.RequestDelegate; +import org.telegram.tgnet.TLObject; +import org.telegram.tgnet.TLRPC; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Cells.StickerSetCell; +import org.telegram.ui.Cells.TextInfoPrivacyCell; +import org.telegram.ui.Components.LayoutHelper; +import org.telegram.ui.Components.RecyclerListView; +import org.telegram.ui.Components.StickersAlert; +import org.telegram.ui.Components.URLSpanNoUnderline; + +import java.util.ArrayList; +import java.util.Locale; + +public class StickersActivity extends BaseFragment implements NotificationCenter.NotificationCenterDelegate { + + private RecyclerListView listView; + private ListAdapter listAdapter; + + private boolean needReorder; + + private int stickersStartRow; + private int stickersEndRow; + private int stickersInfoRow; + private int rowCount; + + public class TouchHelperCallback extends ItemTouchHelper.Callback { + + public static final float ALPHA_FULL = 1.0f; + + @Override + public boolean isLongPressDragEnabled() { + return true; + } + + @Override + public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + if (viewHolder.getItemViewType() != 0) { + return makeMovementFlags(0, 0); + } + return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, 0); + } + + @Override + public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { + if (source.getItemViewType() != target.getItemViewType()) { + return false; + } + listAdapter.swapElements(source.getAdapterPosition(), target.getAdapterPosition()); + return true; + } + + @Override + public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + } + + @Override + public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { + if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) { + listView.cancelClickRunnables(false); + viewHolder.itemView.setPressed(true); + } + super.onSelectedChanged(viewHolder, actionState); + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { + + } + + @Override + public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + super.clearView(recyclerView, viewHolder); + viewHolder.itemView.setPressed(false); + } + } + + @Override + public boolean onFragmentCreate() { + super.onFragmentCreate(); + StickersQuery.checkStickers(); + NotificationCenter.getInstance().addObserver(this, NotificationCenter.stickersDidLoaded); + updateRows(); + return true; + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + sendReorder(); + } + + @Override + public View createView(Context context) { + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + actionBar.setAllowOverlayTitle(true); + actionBar.setTitle(LocaleController.getString("Stickers", R.string.Stickers)); + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + + listAdapter = new ListAdapter(context); + + fragmentView = new FrameLayout(context); + FrameLayout frameLayout = (FrameLayout) fragmentView; + frameLayout.setBackgroundColor(0xfff0f0f0); + + listView = new RecyclerListView(context); + listView.setFocusable(true); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + listView.setBackgroundColor(preferences.getInt("prefBGColor", 0xffffffff)); + LinearLayoutManager layoutManager = new LinearLayoutManager(context); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + listView.setLayoutManager(layoutManager); + ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new TouchHelperCallback()); + itemTouchHelper.attachToRecyclerView(listView); + + frameLayout.addView(listView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT)); + listView.setAdapter(listAdapter); + listView.setOnItemClickListener(new RecyclerListView.OnItemClickListener() { + @Override + public void onItemClick(View view, int position) { + if (position >= stickersStartRow && position < stickersEndRow && getParentActivity() != null) { + sendReorder(); + final TLRPC.TL_messages_stickerSet stickerSet = StickersQuery.getStickerSets().get(position); + ArrayList stickers = stickerSet.documents; + if (stickers == null || stickers.isEmpty()) { + return; + } + showDialog(new StickersAlert(getParentActivity(), null, stickerSet, null)); + } + } + }); + + return fragmentView; + } + + @Override + public void didReceivedNotification(int id, Object... args) { + if (id == NotificationCenter.stickersDidLoaded) { + updateRows(); + } + } + + private void sendReorder() { + if (!needReorder) { + return; + } + StickersQuery.calcNewHash(); + needReorder = false; + TLRPC.TL_messages_reorderStickerSets req = new TLRPC.TL_messages_reorderStickerSets(); + ArrayList arrayList = StickersQuery.getStickerSets(); + for (int a = 0; a < arrayList.size(); a++) { + req.order.add(arrayList.get(a).set.id); + } + ConnectionsManager.getInstance().sendRequest(req, new RequestDelegate() { + @Override + public void run(TLObject response, TLRPC.TL_error error) { + + } + }); + NotificationCenter.getInstance().postNotificationName(NotificationCenter.stickersDidLoaded); + } + + private void updateRows() { + rowCount = 0; + ArrayList stickerSets = StickersQuery.getStickerSets(); + if (!stickerSets.isEmpty()) { + stickersStartRow = 0; + stickersEndRow = stickerSets.size(); + rowCount += stickerSets.size(); + } else { + stickersStartRow = -1; + stickersEndRow = -1; + } + stickersInfoRow = rowCount++; + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + } + + @Override + public void onResume() { + super.onResume(); + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + updateTheme(); + } + + private void updateTheme(){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + actionBar.setBackgroundColor(themePrefs.getInt("prefHeaderColor", def)); + actionBar.setTitleColor(themePrefs.getInt("prefHeaderTitleColor", 0xffffffff)); + + Drawable back = getParentActivity().getResources().getDrawable(R.drawable.ic_ab_back); + back.setColorFilter(themePrefs.getInt("prefHeaderIconsColor", 0xffffffff), PorterDuff.Mode.MULTIPLY); + actionBar.setBackButtonDrawable(back); + } + + private class ListAdapter extends RecyclerListView.Adapter { + private Context mContext; + + private class Holder extends RecyclerView.ViewHolder { + + public Holder(View itemView) { + super(itemView); + } + } + + public ListAdapter(Context context) { + mContext = context; + } + + @Override + public int getItemCount() { + return rowCount; + } + + @Override + public long getItemId(int i) { + if (i >= stickersStartRow && i < stickersEndRow) { + ArrayList arrayList = StickersQuery.getStickerSets(); + return arrayList.get(i).set.id; + } else if (i == stickersInfoRow) { + return Integer.MIN_VALUE; + } + return i; + } + + private void processSelectionOption(int which, TLRPC.TL_messages_stickerSet stickerSet) { + if (which == 0) { + StickersQuery.removeStickersSet(getParentActivity(), stickerSet.set, !stickerSet.set.disabled ? 1 : 2); + } else if (which == 1) { + StickersQuery.removeStickersSet(getParentActivity(), stickerSet.set, 0); + } else if (which == 2) { + try { + Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_TEXT, String.format(Locale.US, "https://telegram.me/addstickers/%s", stickerSet.set.short_name)); + getParentActivity().startActivityForResult(Intent.createChooser(intent, LocaleController.getString("StickersShare", R.string.StickersShare)), 500); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } else if (which == 3) { + try { + if (Build.VERSION.SDK_INT < 11) { + android.text.ClipboardManager clipboard = (android.text.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText(String.format(Locale.US, "https://telegram.me/addstickers/%s", stickerSet.set.short_name)); + } else { + android.content.ClipboardManager clipboard = (android.content.ClipboardManager) ApplicationLoader.applicationContext.getSystemService(Context.CLIPBOARD_SERVICE); + android.content.ClipData clip = android.content.ClipData.newPlainText("label", String.format(Locale.US, "https://telegram.me/addstickers/%s", stickerSet.set.short_name)); + clipboard.setPrimaryClip(clip); + } + Toast.makeText(getParentActivity(), LocaleController.getString("LinkCopied", R.string.LinkCopied), Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + FileLog.e("tmessages", e); + } + } + } + + @Override + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { + if (holder.getItemViewType() == 0) { + ArrayList arrayList = StickersQuery.getStickerSets(); + ((StickerSetCell) holder.itemView).setStickersSet(arrayList.get(position), position != arrayList.size() - 1); + } + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = null; + switch (viewType) { + case 0: + view = new StickerSetCell(mContext); + view.setBackgroundColor(0xffffffff); + view.setBackgroundResource(R.drawable.list_selector_white); + ((StickerSetCell) view).setOnOptionsClick(new View.OnClickListener() { + @Override + public void onClick(View v) { + sendReorder(); + StickerSetCell cell = (StickerSetCell) v.getParent(); + final TLRPC.TL_messages_stickerSet stickerSet = cell.getStickersSet(); + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(stickerSet.set.title); + CharSequence[] items; + final int[] options; + if (stickerSet.set.official) { + options = new int[]{0}; + items = new CharSequence[]{ + !stickerSet.set.disabled ? LocaleController.getString("StickersHide", R.string.StickersHide) : LocaleController.getString("StickersShow", R.string.StickersShow) + }; + } else { + options = new int[]{0, 1, 2, 3}; + items = new CharSequence[]{ + !stickerSet.set.disabled ? LocaleController.getString("StickersHide", R.string.StickersHide) : LocaleController.getString("StickersShow", R.string.StickersShow), + LocaleController.getString("StickersRemove", R.string.StickersRemove), + LocaleController.getString("StickersShare", R.string.StickersShare), + LocaleController.getString("StickersCopy", R.string.StickersCopy), + }; + } + builder.setItems(items, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + processSelectionOption(options[which], stickerSet); + } + }); + showDialog(builder.create()); + } + }); + break; + case 1: + view = new TextInfoPrivacyCell(mContext); + String text = LocaleController.getString("StickersInfo", R.string.StickersInfo); + String botName = "@stickers"; + int index = text.indexOf(botName); + if (index != -1) { + try { + SpannableStringBuilder stringBuilder = new SpannableStringBuilder(text); + URLSpanNoUnderline spanNoUnderline = new URLSpanNoUnderline("@stickers") { + @Override + public void onClick(View widget) { + MessagesController.openByUserName("stickers", StickersActivity.this, 1); + } + }; + stringBuilder.setSpan(spanNoUnderline, index, index + botName.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); + ((TextInfoPrivacyCell) view).setText(stringBuilder); + } catch (Exception e) { + FileLog.e("tmessages", e); + ((TextInfoPrivacyCell) view).setText(text); + } + } else { + ((TextInfoPrivacyCell) view).setText(text); + } + view.setBackgroundResource(R.drawable.greydivider_bottom); + break; + } + view.setLayoutParams(new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.WRAP_CONTENT)); + return new Holder(view); + } + + @Override + public int getItemViewType(int i) { + if (i >= stickersStartRow && i < stickersEndRow) { + return 0; + } else if (i == stickersInfoRow) { + return 1; + } + return 0; + } + + public void swapElements(int fromIndex, int toIndex) { + if (fromIndex != toIndex) { + needReorder = true; + } + ArrayList arrayList = StickersQuery.getStickerSets(); + TLRPC.TL_messages_stickerSet from = arrayList.get(fromIndex); + arrayList.set(fromIndex, arrayList.get(toIndex)); + arrayList.set(toIndex, from); + notifyItemMoved(fromIndex, toIndex); + } +} +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemingActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemingActivity.java index 38a2ca71..da03266d 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemingActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemingActivity.java @@ -29,9 +29,9 @@ import android.widget.ListView; import android.widget.Toast; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.LocaleController; import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.FileLog; +import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.messenger.Utilities; import org.telegram.ui.ActionBar.ActionBar; @@ -42,7 +42,6 @@ import org.telegram.ui.Cells.ShadowSectionCell; import org.telegram.ui.Cells.TextColorCell; import org.telegram.ui.Cells.TextDetailSettingsCell; import org.telegram.ui.Cells.TextSettingsCell; -import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.ColorSelectorDialog; import java.io.File; @@ -123,7 +122,7 @@ public class ThemingActivity extends BaseFragment { public View createView(Context context) { if (fragmentView == null) { - actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); + //actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); actionBar.setBackButtonImage(R.drawable.ic_ab_back); if (AndroidUtilities.isTablet()) { @@ -152,7 +151,9 @@ public class ThemingActivity extends BaseFragment { listView.setDivider(null); listView.setDividerHeight(0); listView.setVerticalScrollBarEnabled(false); - AndroidUtilities.setListViewEdgeEffectColor(listView, AvatarDrawable.getProfileBackColorForId(5)); + int def = preferences.getInt("themeColor", AndroidUtilities.defColor); + int hColor = preferences.getInt("prefHeaderColor", def); + AndroidUtilities.setListViewEdgeEffectColor(listView, /*AvatarDrawable.getProfileBackColorForId(5)*/ hColor); frameLayout.addView(listView); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) listView.getLayoutParams(); layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; @@ -232,7 +233,7 @@ public class ThemingActivity extends BaseFragment { FileLog.e("tmessages", e); } AndroidUtilities.setStringPref(getParentActivity(),"model", android.os.Build.MODEL+"/"+android.os.Build.VERSION.RELEASE); - Utilities.savePreferencesToSD(getParentActivity(), AndroidUtilities.THEME_PREFS+".xml", pName+".xml", true); + Utilities.savePreferencesToSD(getParentActivity(), "/Telegram/Themes", AndroidUtilities.THEME_PREFS+".xml", pName+".xml", true); Utilities.copyWallpaperToSD(getParentActivity(), pName, true); //Toast toast = Toast.makeText(getParentActivity(), LocaleController.getString("SaveThemeToastText", R.string.SaveThemeToastText), Toast.LENGTH_SHORT); //toast.show(); @@ -245,7 +246,7 @@ public class ThemingActivity extends BaseFragment { builder.setNegativeButton(LocaleController.getString("Cancel", R.string.Cancel), null); showDialog(builder.create()); - } else if (i == applyThemeRow) { + } else if (i == applyThemeRow) { DocumentSelectActivity fragment = new DocumentSelectActivity(); fragment.fileFilter = ".xml"; fragment.setDelegate(new DocumentSelectActivity.DocumentSelectActivityDelegate() { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemingChatActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemingChatActivity.java index f2288058..b4a6d213 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemingChatActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemingChatActivity.java @@ -16,6 +16,7 @@ import android.content.SharedPreferences; import android.content.res.Configuration; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -39,7 +40,6 @@ import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextColorCell; import org.telegram.ui.Cells.TextDetailSettingsCell; import org.telegram.ui.Cells.TextSettingsCell; -import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.ColorSelectorDialog; import org.telegram.ui.Components.NumberPicker; @@ -126,6 +126,8 @@ public class ThemingChatActivity extends BaseFragment { private int hideStatusIndicatorCheckRow; + private int checksRow; + private int rowCount; public final static int CENTER = 0; @@ -187,6 +189,7 @@ public class ThemingChatActivity extends BaseFragment { dateColorRow = rowCount++; bubblesRow = rowCount++; + checksRow = rowCount++; rBubbleColorRow = rowCount++; lBubbleColorRow = rowCount++; dateBubbleColorRow = rowCount++; @@ -231,7 +234,7 @@ public class ThemingChatActivity extends BaseFragment { public View createView(Context context) { if (fragmentView == null) { - actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); + //actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); actionBar.setBackButtonImage(R.drawable.ic_ab_back); if (AndroidUtilities.isTablet()) { @@ -259,7 +262,9 @@ public class ThemingChatActivity extends BaseFragment { listView.setDivider(null); listView.setDividerHeight(0); listView.setVerticalScrollBarEnabled(false); - AndroidUtilities.setListViewEdgeEffectColor(listView, AvatarDrawable.getProfileBackColorForId(5)); + int def = preferences.getInt("themeColor", AndroidUtilities.defColor); + int hColor = preferences.getInt("prefHeaderColor", def); + AndroidUtilities.setListViewEdgeEffectColor(listView, /*AvatarDrawable.getProfileBackColorForId(5)*/ hColor); frameLayout.addView(listView); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) listView.getLayoutParams(); layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; @@ -406,7 +411,7 @@ public class ThemingChatActivity extends BaseFragment { boolean b = themePrefs.getBoolean( key, false); SharedPreferences.Editor editor = themePrefs.edit(); editor.putBoolean(key, !b); - editor.commit(); + editor.apply(); if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(!b); } @@ -418,7 +423,7 @@ public class ThemingChatActivity extends BaseFragment { boolean b = themePrefs.getBoolean( key, false); SharedPreferences.Editor editor = themePrefs.edit(); editor.putBoolean(key, !b); - editor.commit(); + editor.apply(); ApplicationLoader.reloadWallpaper(); if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(!b); @@ -431,7 +436,7 @@ public class ThemingChatActivity extends BaseFragment { boolean b = themePrefs.getBoolean( key, false); SharedPreferences.Editor editor = themePrefs.edit(); editor.putBoolean( key, !b); - editor.commit(); + editor.apply(); if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(!b); } @@ -443,7 +448,7 @@ public class ThemingChatActivity extends BaseFragment { boolean b = themePrefs.getBoolean( key, false); SharedPreferences.Editor editor = themePrefs.edit(); editor.putBoolean( key, !b); - editor.commit(); + editor.apply(); if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(!b); } @@ -455,7 +460,7 @@ public class ThemingChatActivity extends BaseFragment { boolean b = themePrefs.getBoolean( key, false); SharedPreferences.Editor editor = themePrefs.edit(); editor.putBoolean( key, !b); - editor.commit(); + editor.apply(); if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(!b); } @@ -464,7 +469,7 @@ public class ThemingChatActivity extends BaseFragment { boolean b = themePrefs.getBoolean( key, false); SharedPreferences.Editor editor = themePrefs.edit(); editor.putBoolean( key, !b); - editor.commit(); + editor.apply(); if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(!b); } @@ -473,7 +478,7 @@ public class ThemingChatActivity extends BaseFragment { boolean b = themePrefs.getBoolean( key, false); SharedPreferences.Editor editor = themePrefs.edit(); editor.putBoolean( key, !b); - editor.commit(); + editor.apply(); if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(!b); } @@ -482,7 +487,7 @@ public class ThemingChatActivity extends BaseFragment { boolean b = themePrefs.getBoolean( key, false); SharedPreferences.Editor editor = themePrefs.edit(); editor.putBoolean( key, !b); - editor.commit(); + editor.apply(); if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(!b); } @@ -490,7 +495,7 @@ public class ThemingChatActivity extends BaseFragment { boolean b = themePrefs.getBoolean( key, false); SharedPreferences.Editor editor = themePrefs.edit(); editor.putBoolean( key, !b); - editor.commit(); + editor.apply(); if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(!b); } @@ -498,7 +503,7 @@ public class ThemingChatActivity extends BaseFragment { boolean b = themePrefs.getBoolean( key, false); SharedPreferences.Editor editor = themePrefs.edit(); editor.putBoolean( key, !b); - editor.commit(); + editor.apply(); if (view instanceof TextCheckCell) { ((TextCheckCell) view).setChecked(!b); } @@ -1223,7 +1228,7 @@ public class ThemingChatActivity extends BaseFragment { SharedPreferences.Editor editor = preferences.edit(); editor.putInt("fons_size", numberPicker.getValue()); MessagesController.getInstance().fontSize = numberPicker.getValue(); - editor.commit(); + editor.apply(); } } }); @@ -1256,7 +1261,7 @@ public class ThemingChatActivity extends BaseFragment { AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); builder.setTitle(LocaleController.getString("DateSize", R.string.DateSize)); final NumberPicker numberPicker = new NumberPicker(getParentActivity()); - final int currentValue = themePrefs.getInt("chatDateSize", 16); + final int currentValue = themePrefs.getInt("chatDateSize", MessagesController.getInstance().fontSize - 2); numberPicker.setMinValue(8); numberPicker.setMaxValue(20); numberPicker.setValue(currentValue); @@ -1292,7 +1297,13 @@ public class ThemingChatActivity extends BaseFragment { }); showDialog(builder.create()); } else if (i == bubblesRow) { - presentFragment(new ImageListActivity()); + Bundle args = new Bundle(); + args.putInt("array_id", 0); + presentFragment(new ImageListActivity(args)); + } else if (i == checksRow) { + Bundle args = new Bundle(); + args.putInt("array_id", 1); + presentFragment(new ImageListActivity(args)); } } }); @@ -1409,7 +1420,7 @@ public class ThemingChatActivity extends BaseFragment { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); SharedPreferences.Editor editor = preferences.edit(); editor.remove(key); - editor.commit(); + editor.apply(); if (listView != null) { listView.invalidateViews(); } @@ -1422,7 +1433,7 @@ public class ThemingChatActivity extends BaseFragment { SharedPreferences.Editor editor = preferences.edit(); editor.putInt("fons_size", value); MessagesController.getInstance().fontSize = value; - editor.commit(); + editor.apply(); } } @@ -1430,7 +1441,7 @@ public class ThemingChatActivity extends BaseFragment { SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); SharedPreferences.Editor editor = preferences.edit(); editor.putInt(key, value); - editor.commit(); + editor.apply(); if (listView != null) { listView.invalidateViews(); } @@ -1497,7 +1508,7 @@ public class ThemingChatActivity extends BaseFragment { public boolean isEnabled(int i) { boolean b = AndroidUtilities.getBoolPref("chatSolidBGColorCheck"); int g = AndroidUtilities.getIntDef("chatGradientBG", 0); - return i == headerColorRow || i == headerGradientRow || AndroidUtilities.getIntDef("chatHeaderGradient", 0) != 0 && i == headerGradientColorRow || i == muteColorRow || i == headerIconsColorRow || i == headerAvatarRadiusRow || i == rBubbleColorRow || i == lBubbleColorRow || i == bubblesRow || + return i == headerColorRow || i == headerGradientRow || AndroidUtilities.getIntDef("chatHeaderGradient", 0) != 0 && i == headerGradientColorRow || i == muteColorRow || i == headerIconsColorRow || i == headerAvatarRadiusRow || i == rBubbleColorRow || i == lBubbleColorRow || i == bubblesRow || i == checksRow || i == solidBGColorCheckRow || b && i == solidBGColorRow || b && i == gradientBGRow || (g != 0 && i == gradientBGColorRow) || i == avatarRadiusRow || i == avatarSizeRow || i == avatarMarginLeftRow || i == avatarAlignTopRow || i == ownAvatarAlignTopRow || i == showContactAvatar || i == showOwnAvatar || i == showOwnAvatarGroup || i == hideStatusIndicatorCheckRow || i == nameColorRow || i == nameSizeRow || i == statusColorRow || i == onlineColorRow || i == typingColorRow || i == statusSizeRow || i == textSizeRow || i == timeSizeRow || AndroidUtilities.getBoolPref("chatCommandColorCheck") && i == commandColorRow || i == commandColorCheckRow || i == dateColorRow || i == dateSizeRow || i == dateBubbleColorRow || i == rTextColorRow || i == rLinkColorRow || i == lTextColorRow || i == lLinkColorRow || i == rTimeColorRow|| i == lTimeColorRow || i == checksColorRow || i == memberColorCheckRow || AndroidUtilities.getBoolPref("chatMemberColorCheck") && i == memberColorRow || i == contactNameColorRow || i == forwardRightNameColorRow || i == forwardLeftNameColorRow || i == showUsernameCheckRow || @@ -1579,7 +1590,7 @@ public class ThemingChatActivity extends BaseFragment { int size = themePrefs.getInt("chatTimeSize", AndroidUtilities.isTablet() ? 14 : 12); textCell.setTextAndValue(LocaleController.getString("TimeSize", R.string.TimeSize), String.format("%d", size), true); } else if (i == dateSizeRow) { - int size = themePrefs.getInt("chatDateSize", AndroidUtilities.isTablet() ? 18 : 16); + int size = themePrefs.getInt("chatDateSize", AndroidUtilities.isTablet() ? 18 : MessagesController.getInstance().fontSize - 2); textCell.setTextAndValue(LocaleController.getString("DateSize", R.string.DateSize), String.format("%d", size), true); } else if (i == editTextSizeRow) { int size = themePrefs.getInt("chatEditTextSize", AndroidUtilities.isTablet() ? 20 : 18); @@ -1587,6 +1598,9 @@ public class ThemingChatActivity extends BaseFragment { } else if (i == bubblesRow) { String bStyle = themePrefs.getString("chatBubbleStyle", ImageListActivity.getBubbleName(0)); textCell.setTextAndValue(LocaleController.getString("BubbleStyle", R.string.BubbleStyle), bStyle, true); + } else if (i == checksRow) { + String cStyle = themePrefs.getString("chatCheckStyle", ImageListActivity.getCheckName(0)); + textCell.setTextAndValue(LocaleController.getString("CheckStyle", R.string.CheckStyle), cStyle, true); } } else if (type == 4) { if (view == null) { @@ -1810,7 +1824,7 @@ public class ThemingChatActivity extends BaseFragment { else if ( i == headerSection2Row || i == rowsSection2Row ) { return 1; } - else if ( i == headerAvatarRadiusRow || i == avatarRadiusRow || i == avatarSizeRow || i == avatarMarginLeftRow || i == nameSizeRow || i == statusSizeRow || i == textSizeRow || i == timeSizeRow || i == dateSizeRow || i == editTextSizeRow || i == bubblesRow) { + else if ( i == headerAvatarRadiusRow || i == avatarRadiusRow || i == avatarSizeRow || i == avatarMarginLeftRow || i == nameSizeRow || i == statusSizeRow || i == textSizeRow || i == timeSizeRow || i == dateSizeRow || i == editTextSizeRow || i == bubblesRow || i == checksRow) { return 2; } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemingChatsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemingChatsActivity.java index 97c56c78..4eedfc60 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemingChatsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemingChatsActivity.java @@ -25,14 +25,14 @@ import android.widget.FrameLayout; import android.widget.ListView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.ContactsController; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MessagesController; import org.telegram.messenger.NotificationCenter; -import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.R; -import org.telegram.tgnet.TLRPC; import org.telegram.messenger.UserConfig; +import org.telegram.tgnet.TLRPC; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.BaseFragment; import org.telegram.ui.Adapters.BaseFragmentAdapter; @@ -42,7 +42,6 @@ import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextColorCell; import org.telegram.ui.Cells.TextDetailSettingsCell; import org.telegram.ui.Cells.TextSettingsCell; -import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.ColorSelectorDialog; import org.telegram.ui.Components.NumberPicker; @@ -80,7 +79,6 @@ public class ThemingChatsActivity extends BaseFragment { private int countColorRow; private int countSizeRow; private int countBGColorRow; - //private int countSilentColorRow; private int countSilentBGColorRow; private int floatingPencilColorRow; private int floatingBGColorRow; @@ -99,6 +97,12 @@ public class ThemingChatsActivity extends BaseFragment { private int highlightSearchColorRow; private int hideStatusIndicatorCheckRow; + private int headerTabIconColorRow; + private int headerTabUnselectedIconColorRow; + private int headerTabCounterColorRow; + private int headerTabCounterBGColorRow; + private int headerTabCounterSilentBGColorRow; + private int headerTabCounterSizeRow; private int rowCount; @@ -116,6 +120,12 @@ public class ThemingChatsActivity extends BaseFragment { headerTitleColorRow = rowCount++; headerTitleRow = rowCount++; headerIconsColorRow = rowCount++; + headerTabIconColorRow = rowCount++; + headerTabUnselectedIconColorRow = rowCount++; + headerTabCounterColorRow = rowCount++; + headerTabCounterBGColorRow = rowCount++; + headerTabCounterSilentBGColorRow = rowCount++; + headerTabCounterSizeRow = rowCount++; rowsSectionRow = rowCount++; rowsSection2Row = rowCount++; @@ -170,7 +180,7 @@ public class ThemingChatsActivity extends BaseFragment { public View createView(Context context) { if (fragmentView == null) { - actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); + //actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); actionBar.setBackButtonImage(R.drawable.ic_ab_back); if (AndroidUtilities.isTablet()) { @@ -198,7 +208,9 @@ public class ThemingChatsActivity extends BaseFragment { listView.setDivider(null); listView.setDividerHeight(0); listView.setVerticalScrollBarEnabled(false); - AndroidUtilities.setListViewEdgeEffectColor(listView, AvatarDrawable.getProfileBackColorForId(5)); + int def = preferences.getInt("themeColor", AndroidUtilities.defColor); + int hColor = preferences.getInt("prefHeaderColor", def); + AndroidUtilities.setListViewEdgeEffectColor(listView, /*AvatarDrawable.getProfileBackColorForId(5)*/ hColor); frameLayout.addView(listView); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) listView.getLayoutParams(); layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; @@ -255,9 +267,22 @@ public class ThemingChatsActivity extends BaseFragment { public void colorChanged(int color) { commitInt(key, color); } - },themePrefs.getInt( key, 0xffffffff), CENTER, 0, true); + },themePrefs.getInt(key, 0xffffffff), CENTER, 0, true); colorDialog.show(); } else if (i == headerIconsColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt(key, color); + } + },themePrefs.getInt(key, themePrefs.getInt("chatsHeaderIconsColor", 0xffffffff)), CENTER, 0, true); + colorDialog.show(); + } else if (i == headerTabIconColorRow) { if (getParentActivity() == null) { return; } @@ -270,6 +295,58 @@ public class ThemingChatsActivity extends BaseFragment { } },themePrefs.getInt( key, 0xffffffff), CENTER, 0, true); colorDialog.show(); + } else if (i == headerTabUnselectedIconColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt(key, color); + } + },themePrefs.getInt( key, AndroidUtilities.getIntAlphaColor("chatsHeaderTabIconColor", defColor, 0.3f)), CENTER, 0, true); + colorDialog.show(); + } else if (i == headerTabCounterColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt(key, color); + } + },themePrefs.getInt(key, 0xffffffff), CENTER, 0, true); + colorDialog.show(); + } else if (i == headerTabCounterBGColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt(key, color); + } + },themePrefs.getInt(key, 0xffd32f2f), CENTER, 0, true); + colorDialog.show(); + } else if (i == headerTabCounterSilentBGColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt(key, color); + } + },themePrefs.getInt(key, 0xffb9b9b9), CENTER, 0, true); + colorDialog.show(); } else if (i == rowColorRow) { if (getParentActivity() == null) { return; @@ -614,21 +691,7 @@ public class ThemingChatsActivity extends BaseFragment { },themePrefs.getInt( key, defColor), CENTER, 0, true); colorDialog.show(); - } /*else if (i == countSilentColorRow) { - if (getParentActivity() == null) { - return; - } - LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - li.inflate(R.layout.colordialog, null, false); - ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { - @Override - public void colorChanged(int color) { - commitInt( key, color); - } - - },themePrefs.getInt( key, 0xffffffff), CENTER, 0, true); - colorDialog.show(); - }*/ else if (i == countSilentBGColorRow) { + } else if (i == countSilentBGColorRow) { if (getParentActivity() == null) { return; } @@ -664,6 +727,27 @@ public class ThemingChatsActivity extends BaseFragment { } }); + showDialog(builder.create()); + } else if (i == headerTabCounterSizeRow) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("CountSize", R.string.CountSize)); + final NumberPicker numberPicker = new NumberPicker(getParentActivity()); + final int currentValue = themePrefs.getInt( key, 11); + numberPicker.setMinValue(9); + numberPicker.setMaxValue(14); + numberPicker.setValue(currentValue); + builder.setView(numberPicker); + builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (numberPicker.getValue() != currentValue) { + commitInt( key, numberPicker.getValue()); + } + } + }); showDialog(builder.create()); } else if (i == avatarSizeRow) { if (getParentActivity() == null) { @@ -963,7 +1047,7 @@ public class ThemingChatsActivity extends BaseFragment { @Override public boolean isEnabled(int i) { int g = AndroidUtilities.getIntDef("chatsRowGradient",0); - return i == headerColorRow || i == headerGradientRow || (AndroidUtilities.getIntDef("chatsHeaderGradient", 0) != 0 && i == headerGradientColorRow) || i == headerTitleColorRow || i == headerIconsColorRow || i == headerTitleRow || + return i == headerColorRow || i == headerGradientRow || (AndroidUtilities.getIntDef("chatsHeaderGradient", 0) != 0 && i == headerGradientColorRow) || i == headerTitleColorRow || i == headerIconsColorRow || i == headerTabIconColorRow || i == headerTabUnselectedIconColorRow || i == headerTitleRow || i == headerTabCounterColorRow || i == headerTabCounterBGColorRow || i == headerTabCounterSilentBGColorRow || i == headerTabCounterSizeRow || i == rowColorRow || i == rowGradientRow || (g != 0 && i == rowGradientColorRow) || (g != 0 && i == rowGradientListCheckRow) || i == dividerColorRow || i == avatarRadiusRow || i == avatarSizeRow || i == avatarMarginLeftRow || i == hideStatusIndicatorCheckRow || i == nameColorRow || i == groupNameColorRow || i == unknownNameColorRow || i == groupIconColorRow || i == muteColorRow || i == checksColorRow || i == nameSizeRow || i == groupNameSizeRow || i == messageColorRow || i == highlightSearchColorRow || i == memberColorRow || i == mediaColorRow || i == typingColorRow || i == messageSizeRow || i == timeColorRow || i == timeSizeRow || i == countColorRow || i == countSizeRow || i == countBGColorRow /*|| i == countSilentColorRow*/ || i == countSilentBGColorRow || i == floatingPencilColorRow || i == floatingBGColorRow; @@ -1018,6 +1102,10 @@ public class ThemingChatsActivity extends BaseFragment { textCell.setTag("chatsAvatarRadius"); int size = themePrefs.getInt("chatsAvatarRadius", AndroidUtilities.isTablet() ? 35 : 32); textCell.setTextAndValue(LocaleController.getString("AvatarRadius", R.string.AvatarRadius), String.format("%d", size), true); + } else if (i == headerTabCounterSizeRow) { + textCell.setTag("chatsHeaderTabCounterSize"); + int size = themePrefs.getInt("chatsHeaderTabCounterSize", AndroidUtilities.isTablet() ? 13 : 11); + textCell.setTextAndValue(LocaleController.getString("CountSize", R.string.CountSize), String.format("%d", size), true); } else if (i == avatarSizeRow) { textCell.setTag("chatsAvatarSize"); int size = themePrefs.getInt("chatsAvatarSize", AndroidUtilities.isTablet() ? 55 : 52); @@ -1066,7 +1154,22 @@ public class ThemingChatsActivity extends BaseFragment { textCell.setTextAndColor(LocaleController.getString("HeaderTitleColor", R.string.HeaderTitleColor), themePrefs.getInt(textCell.getTag().toString(), 0xffffffff), true); } else if (i == headerIconsColorRow) { textCell.setTag("chatsHeaderIconsColor"); - textCell.setTextAndColor(LocaleController.getString("HeaderIconsColor", R.string.HeaderIconsColor), themePrefs.getInt(textCell.getTag().toString(), 0xffffffff), false); + textCell.setTextAndColor(LocaleController.getString("HeaderIconsColor", R.string.HeaderIconsColor), themePrefs.getInt(textCell.getTag().toString(), 0xffffffff), true); + } else if (i == headerTabIconColorRow) { + textCell.setTag("chatsHeaderTabIconColor"); + textCell.setTextAndColor(LocaleController.getString("HeaderTabIconColor", R.string.HeaderTabIconColor), themePrefs.getInt(textCell.getTag().toString(), themePrefs.getInt("chatsHeaderIconsColor", 0xffffffff)), true); + } else if (i == headerTabUnselectedIconColorRow) { + textCell.setTag("chatsHeaderTabUnselectedIconColor"); + textCell.setTextAndColor(LocaleController.getString("HeaderTabUnselectedIconColor", R.string.HeaderTabUnselectedIconColor), themePrefs.getInt(textCell.getTag().toString(), themePrefs.getInt("chatsHeaderTabUnselectedIconColor", AndroidUtilities.getIntAlphaColor("chatsHeaderTabIconColor", defColor, 0.3f))), true); + } else if (i == headerTabCounterColorRow) { + textCell.setTag("chatsHeaderTabCounterColor"); + textCell.setTextAndColor(LocaleController.getString("HeaderTabCounterColor", R.string.HeaderTabCounterColor), themePrefs.getInt(textCell.getTag().toString(), 0xffffffff), true); + } else if (i == headerTabCounterBGColorRow) { + textCell.setTag("chatsHeaderTabCounterBGColor"); + textCell.setTextAndColor(LocaleController.getString("HeaderTabCounterBGColor", R.string.HeaderTabCounterBGColor), themePrefs.getInt(textCell.getTag().toString(), 0xffD32F2F), false); + } else if (i == headerTabCounterSilentBGColorRow) { + textCell.setTag("chatsHeaderTabCounterSilentBGColor"); + textCell.setTextAndColor(LocaleController.getString("CountSilentBGColor", R.string.CountSilentBGColor), themePrefs.getInt(textCell.getTag().toString(), 0xffb9b9b9), false); } else if (i == rowColorRow) { textCell.setTag("chatsRowColor"); textCell.setTextAndColor(LocaleController.getString("RowColor", R.string.RowColor), themePrefs.getInt("chatsRowColor", 0xffffffff), false); @@ -1214,9 +1317,9 @@ public class ThemingChatsActivity extends BaseFragment { return 0; } else if ( i == headerSection2Row || i == rowsSection2Row ) { return 1; - } else if ( i == avatarRadiusRow || i == avatarSizeRow || i == avatarMarginLeftRow || i == nameSizeRow || i == groupNameSizeRow || i == messageSizeRow || i == timeSizeRow || i == countSizeRow ) { + } else if ( i == avatarRadiusRow || i == avatarSizeRow || i == avatarMarginLeftRow || i == nameSizeRow || i == groupNameSizeRow || i == messageSizeRow || i == timeSizeRow || i == countSizeRow || i == headerTabCounterSizeRow) { return 2; - } else if ( i == headerColorRow || i == headerGradientColorRow || i == headerTitleColorRow || i == headerIconsColorRow || + } else if ( i == headerColorRow || i == headerGradientColorRow || i == headerTitleColorRow || i == headerIconsColorRow || i == headerTabIconColorRow || i == headerTabUnselectedIconColorRow || i == headerTabCounterColorRow || i == headerTabCounterBGColorRow || i == headerTabCounterSilentBGColorRow || i == rowColorRow || i == rowGradientColorRow || i == dividerColorRow || i == nameColorRow || i == groupNameColorRow || i == unknownNameColorRow || i == groupIconColorRow || i == muteColorRow || i == checksColorRow || i == messageColorRow || i == highlightSearchColorRow || i == memberColorRow || i == mediaColorRow || i == typingColorRow || i == timeColorRow || i == countColorRow || i == countBGColorRow /*|| i == countSilentColorRow*/ || i == countSilentBGColorRow || i == floatingPencilColorRow || i == floatingBGColorRow) { return 3; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemingContactsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemingContactsActivity.java index 0ad14751..3f057555 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemingContactsActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemingContactsActivity.java @@ -25,8 +25,8 @@ import android.widget.FrameLayout; import android.widget.ListView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.LocaleController; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.BaseFragment; @@ -37,7 +37,6 @@ import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextColorCell; import org.telegram.ui.Cells.TextDetailSettingsCell; import org.telegram.ui.Cells.TextSettingsCell; -import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.ColorSelectorDialog; import org.telegram.ui.Components.NumberPicker; @@ -117,7 +116,7 @@ public class ThemingContactsActivity extends BaseFragment { public View createView(Context context) { if (fragmentView == null) { - actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); + //actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); actionBar.setBackButtonImage(R.drawable.ic_ab_back); if (AndroidUtilities.isTablet()) { @@ -145,7 +144,9 @@ public class ThemingContactsActivity extends BaseFragment { listView.setDivider(null); listView.setDividerHeight(0); listView.setVerticalScrollBarEnabled(false); - AndroidUtilities.setListViewEdgeEffectColor(listView, AvatarDrawable.getProfileBackColorForId(5)); + int def = preferences.getInt("themeColor", AndroidUtilities.defColor); + int hColor = preferences.getInt("prefHeaderColor", def); + AndroidUtilities.setListViewEdgeEffectColor(listView, /*AvatarDrawable.getProfileBackColorForId(5)*/ hColor); frameLayout.addView(listView); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) listView.getLayoutParams(); layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemingDrawerActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemingDrawerActivity.java index 3ccf1d8a..a6b568d0 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemingDrawerActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemingDrawerActivity.java @@ -25,10 +25,10 @@ import android.widget.FrameLayout; import android.widget.ListView; import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.LocaleController; import org.telegram.messenger.MediaController; import org.telegram.messenger.NotificationCenter; -import org.telegram.messenger.ApplicationLoader; import org.telegram.messenger.R; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.BaseFragment; @@ -39,7 +39,6 @@ import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextColorCell; import org.telegram.ui.Cells.TextDetailSettingsCell; import org.telegram.ui.Cells.TextSettingsCell; -import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.ColorSelectorDialog; import org.telegram.ui.Components.NumberPicker; @@ -139,7 +138,7 @@ public class ThemingDrawerActivity extends BaseFragment { public View createView(Context context) { if (fragmentView == null) { - actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); + //actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); actionBar.setBackButtonImage(R.drawable.ic_ab_back); if (AndroidUtilities.isTablet()) { @@ -167,7 +166,9 @@ public class ThemingDrawerActivity extends BaseFragment { listView.setDivider(null); listView.setDividerHeight(0); listView.setVerticalScrollBarEnabled(false); - AndroidUtilities.setListViewEdgeEffectColor(listView, AvatarDrawable.getProfileBackColorForId(5)); + int def = preferences.getInt("themeColor", AndroidUtilities.defColor); + int hColor = preferences.getInt("prefHeaderColor", def); + AndroidUtilities.setListViewEdgeEffectColor(listView, /*AvatarDrawable.getProfileBackColorForId(5)*/ hColor); frameLayout.addView(listView); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) listView.getLayoutParams(); layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemingProfileActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemingProfileActivity.java index 623fae12..c45e1891 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/ThemingProfileActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemingProfileActivity.java @@ -25,8 +25,8 @@ import android.widget.FrameLayout; import android.widget.ListView; import org.telegram.messenger.AndroidUtilities; -import org.telegram.messenger.LocaleController; import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.LocaleController; import org.telegram.messenger.R; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.BaseFragment; @@ -37,7 +37,6 @@ import org.telegram.ui.Cells.TextCheckCell; import org.telegram.ui.Cells.TextColorCell; import org.telegram.ui.Cells.TextDetailSettingsCell; import org.telegram.ui.Cells.TextSettingsCell; -import org.telegram.ui.Components.AvatarDrawable; import org.telegram.ui.Components.ColorSelectorDialog; import org.telegram.ui.Components.NumberPicker; @@ -123,7 +122,7 @@ public class ThemingProfileActivity extends BaseFragment { public View createView(Context context) { if (fragmentView == null) { - actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); + //actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); actionBar.setBackButtonImage(R.drawable.ic_ab_back); if (AndroidUtilities.isTablet()) { @@ -151,7 +150,9 @@ public class ThemingProfileActivity extends BaseFragment { listView.setDivider(null); listView.setDividerHeight(0); listView.setVerticalScrollBarEnabled(false); - AndroidUtilities.setListViewEdgeEffectColor(listView, AvatarDrawable.getProfileBackColorForId(5)); + int def = preferences.getInt("themeColor", AndroidUtilities.defColor); + int hColor = preferences.getInt("prefHeaderColor", def); + AndroidUtilities.setListViewEdgeEffectColor(listView, /*AvatarDrawable.getProfileBackColorForId(5)*/ hColor); frameLayout.addView(listView); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) listView.getLayoutParams(); layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; diff --git a/TMessagesProj/src/main/java/org/telegram/ui/ThemingSettingsActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/ThemingSettingsActivity.java new file mode 100644 index 00000000..ecfe6f84 --- /dev/null +++ b/TMessagesProj/src/main/java/org/telegram/ui/ThemingSettingsActivity.java @@ -0,0 +1,588 @@ +/* + * This is the source code of Telegram for Android v. 3.x.x. + * It is licensed under GNU GPL v. 2 or later. + * You should have received a copy of the license in this archive (see LICENSE). + * + * Copyright Nikolai Kudashov, 2013-2016. + */ + +package org.telegram.ui; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.widget.AdapterView; +import android.widget.FrameLayout; +import android.widget.ListView; + +import org.telegram.messenger.AndroidUtilities; +import org.telegram.messenger.ApplicationLoader; +import org.telegram.messenger.LocaleController; +import org.telegram.messenger.R; +import org.telegram.ui.ActionBar.ActionBar; +import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.Adapters.BaseFragmentAdapter; +import org.telegram.ui.Cells.HeaderCell; +import org.telegram.ui.Cells.ShadowSectionCell; +import org.telegram.ui.Cells.TextColorCell; +import org.telegram.ui.Cells.TextSettingsCell; +import org.telegram.ui.Components.ColorSelectorDialog; +import org.telegram.ui.Components.NumberPicker; + +import static org.telegram.ui.Components.ColorSelectorDialog.OnColorChangedListener; + +public class ThemingSettingsActivity extends BaseFragment { + + private ListView listView; + private ListAdapter listAdapter; + + private int sectionColorRow; + private int titleColorRow; + private int summaryColorRow; + private int backgroundColorRow; + private int dividerColorRow; + private int shadowColorRow; + + private int headerSection2Row; + private int headerColorRow; + private int headerTitleColorRow; + private int headerIconsColorRow; + + private int rowsSectionRow; + private int rowsSection2Row; + private int avatarColorRow; + private int avatarRadiusRow; + private int avatarSizeRow; + private int headerStatusColorRow; + + private int rowCount; + + public final static int CENTER = 0; + + @Override + public boolean onFragmentCreate() { + super.onFragmentCreate(); + + rowCount = 0; + + headerSection2Row = rowCount++; + headerColorRow = rowCount++; + headerTitleColorRow = rowCount++; + headerStatusColorRow = rowCount++; + headerIconsColorRow = rowCount++; + avatarColorRow = rowCount++; + avatarRadiusRow = rowCount++; + avatarSizeRow = rowCount++; + + rowsSectionRow = rowCount++; + rowsSection2Row = rowCount++; + backgroundColorRow = rowCount++; + shadowColorRow = rowCount++; + sectionColorRow = rowCount++; + titleColorRow = rowCount++; + summaryColorRow = rowCount++; + dividerColorRow = rowCount++; + + return true; + } + + @Override + public void onFragmentDestroy() { + super.onFragmentDestroy(); + + } + + @Override + public View createView(Context context) { + if (fragmentView == null) { + + //actionBar.setItemsBackground(AvatarDrawable.getButtonColorForId(5)); + actionBar.setBackButtonImage(R.drawable.ic_ab_back); + + + if (AndroidUtilities.isTablet()) { + actionBar.setOccupyStatusBar(false); + } + actionBar.setTitle(LocaleController.getString("SettingsScreen", R.string.SettingsScreen)); + + actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { + @Override + public void onItemClick(int id) { + if (id == -1) { + finishFragment(); + } + } + }); + + listAdapter = new ListAdapter(context); + + fragmentView = new FrameLayout(context); + FrameLayout frameLayout = (FrameLayout) fragmentView; + + listView = new ListView(context); + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + listView.setBackgroundColor(preferences.getInt("prefBGColor", 0xffffffff)); + listView.setDivider(null); + listView.setDividerHeight(0); + listView.setVerticalScrollBarEnabled(false); + + int def = preferences.getInt("themeColor", AndroidUtilities.defColor); + int hColor = preferences.getInt("prefHeaderColor", def); + AndroidUtilities.setListViewEdgeEffectColor(listView, /*AvatarDrawable.getProfileBackColorForId(5)*/ hColor); + frameLayout.addView(listView); + FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) listView.getLayoutParams(); + layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; + layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT; + layoutParams.gravity = Gravity.TOP; + listView.setLayoutParams(layoutParams); + listView.setAdapter(listAdapter); + + listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, final int i, long l) { + + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int defColor = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + if (i == headerColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt("prefHeaderColor", color); + } + },themePrefs.getInt("prefHeaderColor", defColor), CENTER, 0, false); + colorDialog.show(); + } else if (i == headerTitleColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt("prefHeaderTitleColor", color); + } + },themePrefs.getInt("prefHeaderTitleColor", 0xffffffff), CENTER, 0, false); + colorDialog.show(); + } else if (i == headerStatusColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt("prefHeaderStatusColor", color); + } + },themePrefs.getInt("prefHeaderStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40)), CENTER, 0, false); + colorDialog.show(); + } else if (i == headerIconsColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt( "prefHeaderIconsColor", color); + } + },themePrefs.getInt( "prefHeaderIconsColor", 0xffffffff), CENTER, 0, true); + colorDialog.show(); + } else if (i == avatarColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt( "prefAvatarColor", color); + } + },themePrefs.getInt( "prefAvatarColor", AndroidUtilities.getIntDarkerColor("themeColor", 0x15)), CENTER, 0, false); + colorDialog.show(); + } else if (i == avatarRadiusRow) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AvatarRadius", R.string.AvatarRadius)); + final NumberPicker numberPicker = new NumberPicker(getParentActivity()); + final int currentValue = themePrefs.getInt("prefAvatarRadius", 32); + numberPicker.setMinValue(1); + numberPicker.setMaxValue(32); + numberPicker.setValue(currentValue); + builder.setView(numberPicker); + builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (numberPicker.getValue() != currentValue) { + commitInt("prefAvatarRadius", numberPicker.getValue()); + } + } + }); + showDialog(builder.create()); + } else if (i == avatarSizeRow) { + if (getParentActivity() == null) { + return; + } + AlertDialog.Builder builder = new AlertDialog.Builder(getParentActivity()); + builder.setTitle(LocaleController.getString("AvatarSize", R.string.AvatarSize)); + final NumberPicker numberPicker = new NumberPicker(getParentActivity()); + final int currentValue = themePrefs.getInt("prefAvatarSize", 42); + numberPicker.setMinValue(0); + numberPicker.setMaxValue(48); + numberPicker.setValue(currentValue); + builder.setView(numberPicker); + builder.setNegativeButton(LocaleController.getString("Done", R.string.Done), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + if (numberPicker.getValue() != currentValue) { + commitInt("prefAvatarSize", numberPicker.getValue()); + } + } + }); + showDialog(builder.create()); + } + else if (i == backgroundColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt( "prefBGColor", color); + } + },themePrefs.getInt( "prefBGColor", 0xffffffff), CENTER, 0, false); + colorDialog.show(); + } else if (i == shadowColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt( "prefShadowColor", color); + } + },themePrefs.getInt( "prefShadowColor", 0xfff0f0f0), CENTER, 0, false); + colorDialog.show(); + } else if (i == sectionColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt("prefSectionColor", color); + } + },themePrefs.getInt("prefSectionColor", defColor), CENTER, 0, false); + colorDialog.show(); + } else if (i == titleColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt("prefTitleColor", color); + } + },themePrefs.getInt("prefTitleColor", 0xff212121), CENTER, 0, false); + colorDialog.show(); + } else if (i == summaryColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt("prefSummaryColor", color); + } + },themePrefs.getInt("prefSummaryColor", 0xff8a8a8a), CENTER, 0, false); + colorDialog.show(); + } else if (i == dividerColorRow) { + if (getParentActivity() == null) { + return; + } + LayoutInflater li = (LayoutInflater)getParentActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + li.inflate(R.layout.colordialog, null, false); + ColorSelectorDialog colorDialog = new ColorSelectorDialog(getParentActivity(), new OnColorChangedListener() { + @Override + public void colorChanged(int color) { + commitInt("prefDividerColor", color); + } + },themePrefs.getInt("prefDividerColor", 0xffd9d9d9), CENTER, 0, false); + colorDialog.show(); + } + } + }); + + listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() { + @Override + public boolean onItemLongClick(AdapterView adapterView, View view, int i, long l) { + if (getParentActivity() == null) { + return false; + } + if (i == headerColorRow) { + resetInt("prefHeaderColor"); + } else if (i == headerTitleColorRow) { + resetInt("prefHeaderTitleColor"); + } else if (i == headerStatusColorRow) { + resetInt("prefHeaderStatusColor"); + } else if (i == headerIconsColorRow) { + resetInt("prefHeaderIconsColor"); + } else if (i == avatarColorRow) { + resetInt("prefAvatarColor"); + } else if (i == avatarRadiusRow) { + resetInt("prefAvatarRadius"); + } else if (i == avatarSizeRow) { + resetInt("prefAvatarSize"); + } else if (i == backgroundColorRow) { + resetInt("prefBGColor"); + } else if (i == shadowColorRow) { + resetInt("prefShadowColor"); + } else if (i == sectionColorRow) { + resetInt("prefSectionColor"); + } else if (i == titleColorRow) { + resetInt("prefTitleColor"); + } else if (i == summaryColorRow) { + resetInt("prefSummaryColor"); + } else if (i == dividerColorRow) { + resetInt("prefDividerColor"); + } + return true; + } + }); + + frameLayout.addView(actionBar); + } else { + ViewGroup parent = (ViewGroup)fragmentView.getParent(); + if (parent != null) { + parent.removeView(fragmentView); + } + } + return fragmentView; + } + + private void resetInt(String key){ + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + SharedPreferences.Editor editor = preferences.edit(); + editor.remove(key); + editor.commit(); + if (listView != null) { + listView.invalidateViews(); + } + } + + private void commitInt(String key, int value){ + SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + SharedPreferences.Editor editor = preferences.edit(); + editor.putInt(key, value); + editor.commit(); + if (listView != null) { + listView.invalidateViews(); + } + } + + @Override + public void onResume() { + super.onResume(); + + if (listAdapter != null) { + listAdapter.notifyDataSetChanged(); + } + fixLayout(); + updateTheme(); + } + + private void updateTheme(){ + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + int def = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + actionBar.setBackgroundColor(themePrefs.getInt("prefHeaderColor", def)); + actionBar.setTitleColor(themePrefs.getInt("prefHeaderTitleColor", 0xffffffff)); + + Drawable back = getParentActivity().getResources().getDrawable(R.drawable.ic_ab_back); + back.setColorFilter(themePrefs.getInt("prefHeaderIconsColor", 0xffffffff), PorterDuff.Mode.MULTIPLY); + actionBar.setBackButtonDrawable(back); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + fixLayout(); + } + + private void fixLayout() { + if (fragmentView == null) { + return; + } + fragmentView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + if (fragmentView != null) { + //needLayout(); + fragmentView.getViewTreeObserver().removeOnPreDrawListener(this); + } + return false; + } + }); + listView.setAdapter(listAdapter); + //actionBar.setBackgroundColor(AndroidUtilities.getIntColor("themeColor")); + } + + private class ListAdapter extends BaseFragmentAdapter { + private Context mContext; + + public ListAdapter(Context context) { + mContext = context; + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public boolean isEnabled(int i) { + return i == headerColorRow || i == headerTitleColorRow || i == headerStatusColorRow || i == headerIconsColorRow || i == avatarColorRow || i == avatarRadiusRow || i == avatarSizeRow || i == backgroundColorRow || i == shadowColorRow || i == sectionColorRow || i == titleColorRow || i == summaryColorRow || i == dividerColorRow; + } + + @Override + public int getCount() { + return rowCount; + } + + @Override + public Object getItem(int i) { + return null; + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public boolean hasStableIds() { + return false; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + int type = getItemViewType(i); + SharedPreferences themePrefs = ApplicationLoader.applicationContext.getSharedPreferences(AndroidUtilities.THEME_PREFS, AndroidUtilities.THEME_PREFS_MODE); + if (type == 0) { + if (view == null) { + view = new ShadowSectionCell(mContext); + } + } + else if (type == 1) { + if (view == null) { + view = new HeaderCell(mContext); + view.setBackgroundColor(0xffffffff); + } + if (i == headerSection2Row) { + ((HeaderCell) view).setText(LocaleController.getString("Header", R.string.Header)); + } else if (i == rowsSection2Row) { + ((HeaderCell) view).setText(LocaleController.getString("OptionsList", R.string.OptionsList)); + } + } + else if (type == 2){ + if (view == null) { + view = new TextColorCell(mContext); + } + + TextColorCell textCell = (TextColorCell) view; + int defColor = themePrefs.getInt("themeColor", AndroidUtilities.defColor); + if (i == headerColorRow) { + textCell.setTextAndColor(LocaleController.getString("HeaderColor", R.string.HeaderColor), themePrefs.getInt("prefHeaderColor", defColor), true); + } else if (i == headerTitleColorRow) { + textCell.setTextAndColor(LocaleController.getString("HeaderTitleColor", R.string.HeaderTitleColor), themePrefs.getInt("prefHeaderTitleColor", 0xffffffff), true); + } else if (i == headerStatusColorRow) { + textCell.setTextAndColor(LocaleController.getString("StatusColor", R.string.StatusColor), themePrefs.getInt("prefHeaderStatusColor", AndroidUtilities.getIntDarkerColor("themeColor", -0x40)), true); + } else if (i == headerIconsColorRow) { + textCell.setTextAndColor(LocaleController.getString("HeaderIconsColor", R.string.HeaderIconsColor), themePrefs.getInt("prefHeaderIconsColor", 0xffffffff), true); + } else if (i == avatarColorRow) { + textCell.setTextAndColor(LocaleController.getString("AvatarColor", R.string.AvatarColor), themePrefs.getInt("prefAvatarColor", AndroidUtilities.getIntDarkerColor("themeColor", 0x15)), true); + } else if (i == backgroundColorRow) { + textCell.setTextAndColor(LocaleController.getString("BackgroundColor", R.string.BackgroundColor), themePrefs.getInt("prefBGColor", 0xffffffff), true); + } else if (i == shadowColorRow) { + textCell.setTextAndColor(LocaleController.getString("ShadowColor", R.string.ShadowColor), themePrefs.getInt("prefShadowColor", 0xfff0f0f0), true); + } else if (i == sectionColorRow) { + textCell.setTextAndColor(LocaleController.getString("SectionColor", R.string.SectionColor), themePrefs.getInt("prefSectionColor", defColor), true); + } else if (i == titleColorRow) { + textCell.setTextAndColor(LocaleController.getString("TitleColor", R.string.TitleColor), themePrefs.getInt("prefTitleColor", 0xff212121), true); + } else if (i == summaryColorRow) { + textCell.setTextAndColor(LocaleController.getString("SummaryColor", R.string.SummaryColor), themePrefs.getInt("prefSummaryColor", 0xff8a8a8a), true); + } else if (i == dividerColorRow) { + textCell.setTextAndColor(LocaleController.getString("DividerColor", R.string.DividerColor), themePrefs.getInt("prefDividerColor", 0xffd9d9d9), true); + } + } else if (type == 3) { + if (view == null) { + view = new TextSettingsCell(mContext); + } + TextSettingsCell textCell = (TextSettingsCell) view; + if (i == avatarRadiusRow) { + int size = themePrefs.getInt("prefAvatarRadius", AndroidUtilities.isTablet() ? 35 : 32); + textCell.setTextAndValue(LocaleController.getString("AvatarRadius", R.string.AvatarRadius), String.format("%d", size), true); + } else if (i == avatarSizeRow) { + int size = themePrefs.getInt("prefAvatarSize", AndroidUtilities.isTablet() ? 45 : 42); + textCell.setTextAndValue(LocaleController.getString("AvatarSize", R.string.AvatarSize), String.format("%d", size), false); + } + + } + return view; + } + + @Override + public int getItemViewType(int i) { + if ( i == avatarRadiusRow || i == avatarSizeRow) { + return 3; + } + if ( i == headerColorRow || i == headerTitleColorRow || i == headerStatusColorRow || i == headerIconsColorRow || i == avatarColorRow || i == backgroundColorRow || i == shadowColorRow || i == sectionColorRow || i == titleColorRow || i == summaryColorRow || i == dividerColorRow) { + return 2; + } + else if ( i == headerSection2Row || i == rowsSection2Row ) { + return 1; + } + else { + return 0; + } + } + + @Override + public int getViewTypeCount() { + return 4; + } + + @Override + public boolean isEmpty() { + return false; + } + } +} diff --git a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java index 58296692..88a930b7 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/TwoStepVerificationActivity.java @@ -685,8 +685,8 @@ public class TwoStepVerificationActivity extends BaseFragment implements Notific if (text == null || text.length() < 3) { return false; } - int dot = text.lastIndexOf("."); - int dog = text.lastIndexOf("@"); + int dot = text.lastIndexOf('.'); + int dog = text.lastIndexOf('@'); return !(dot < 0 || dog < 0 || dot < dog); } diff --git a/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java index b41852d2..c2a9e660 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/VideoEditorActivity.java @@ -51,6 +51,7 @@ import org.telegram.messenger.R; import org.telegram.ui.ActionBar.ActionBar; import org.telegram.ui.ActionBar.ActionBarMenu; import org.telegram.ui.ActionBar.BaseFragment; +import org.telegram.ui.ActionBar.Theme; import org.telegram.ui.Components.LayoutHelper; import org.telegram.ui.Components.VideoSeekBarView; import org.telegram.ui.Components.VideoTimelineView; @@ -231,8 +232,8 @@ public class VideoEditorActivity extends BaseFragment implements TextureView.Sur @Override public View createView(Context context) { - actionBar.setBackgroundColor(0xff333333); - actionBar.setItemsBackground(R.drawable.bar_selector_white); + actionBar.setBackgroundColor(Theme.ACTION_BAR_MEDIA_PICKER_COLOR); + actionBar.setItemsBackgroundColor(Theme.ACTION_BAR_PICKER_SELECTOR_COLOR); actionBar.setBackButtonImage(R.drawable.ic_ab_back); actionBar.setTitle(LocaleController.getString("EditVideo", R.string.EditVideo)); actionBar.setActionBarMenuOnItemClick(new ActionBar.ActionBarMenuOnItemClick() { @@ -256,7 +257,6 @@ public class VideoEditorActivity extends BaseFragment implements TextureView.Sur if (compressVideo.getVisibility() == View.GONE || compressVideo.getVisibility() == View.VISIBLE && !compressVideo.isChecked()) { delegate.didFinishEditVideo(videoPath, startTime, endTime, originalWidth, originalHeight, rotationValue, originalWidth, originalHeight, originalBitrate, estimatedSize, esimatedDuration); } else { - Log.e("VideoEditor","resultWidth "+ resultWidth + " resultHeight " + resultHeight + " bitrate " + bitrate + " estimatedSize " + estimatedSize + " esimatedDuration " + esimatedDuration); delegate.didFinishEditVideo(videoPath, startTime, endTime, resultWidth, resultHeight, rotationValue, originalWidth, originalHeight, bitrate, estimatedSize, esimatedDuration); } } @@ -785,14 +785,12 @@ public class VideoEditorActivity extends BaseFragment implements TextureView.Sur } videoDuration = (float) mediaHeaderBox.getDuration() / (float) mediaHeaderBox.getTimescale(); trackBitrate = (int) (sampleSizes * 8 / videoDuration); - //tBitrate = trackBitrate; } catch (Exception e) { FileLog.e("tmessages", e); } TrackHeaderBox headerBox = trackBox.getTrackHeaderBox(); if (headerBox.getWidth() != 0 && headerBox.getHeight() != 0) { trackHeaderBox = headerBox; - //tBitrate = trackBitrate; originalBitrate = bitrate = (int)(trackBitrate / 100000 * 100000); if (bitrate > 900000) { bitrate = 900000; @@ -844,16 +842,12 @@ public class VideoEditorActivity extends BaseFragment implements TextureView.Sur } private void calculate(){ - //videoDuration /= 1000; - resultWidth = originalWidth; resultHeight = originalHeight; - //bitrate = (int)(tBitrate / 100000 * 100000); bitrate = originalBitrate; bitrate /= barValue; int x = 2; - //int minSize = 640; if(barValue > 4) { if (originalWidth > 640 * x || originalHeight > 640 * x || barValue > 8) { if(barValue > 14 || Math.max(originalWidth, originalHeight) <= 640*2)x = 1; @@ -866,7 +860,6 @@ public class VideoEditorActivity extends BaseFragment implements TextureView.Sur if (bitrate != 0){ videoFramesSize = (long) (bitrate / 8 * (videoDuration/1000)); } - //videoDuration *= 1000; } private int calculateEstimatedSize(float timeDelta) { diff --git a/TMessagesProj/src/main/java/org/telegram/ui/WallpapersActivity.java b/TMessagesProj/src/main/java/org/telegram/ui/WallpapersActivity.java index 5e5e0b97..c4b6c831 100644 --- a/TMessagesProj/src/main/java/org/telegram/ui/WallpapersActivity.java +++ b/TMessagesProj/src/main/java/org/telegram/ui/WallpapersActivity.java @@ -17,6 +17,7 @@ import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Build; @@ -61,7 +62,8 @@ public class WallpapersActivity extends BaseFragment implements NotificationCent private ListAdapter listAdapter; private ImageView backgroundImage; - private ProgressBar progressBar; + private FrameLayout progressView; + private View progressViewBackground; private int selectedBackground; private int selectedColor; private ArrayList wallPapers = new ArrayList<>(); @@ -80,7 +82,6 @@ public class WallpapersActivity extends BaseFragment implements NotificationCent NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidFailedLoad); NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileDidLoaded); - NotificationCenter.getInstance().addObserver(this, NotificationCenter.FileLoadProgressChanged); NotificationCenter.getInstance().addObserver(this, NotificationCenter.wallpapersDidLoaded); SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("mainconfig", Activity.MODE_PRIVATE); @@ -97,7 +98,6 @@ public class WallpapersActivity extends BaseFragment implements NotificationCent super.onFragmentDestroy(); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.FileDidFailedLoad); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.FileDidLoaded); - NotificationCenter.getInstance().removeObserver(this, NotificationCenter.FileLoadProgressChanged); NotificationCenter.getInstance().removeObserver(this, NotificationCenter.wallpapersDidLoaded); } @@ -182,9 +182,23 @@ public class WallpapersActivity extends BaseFragment implements NotificationCent } }); - progressBar = new ProgressBar(context); - progressBar.setPadding(AndroidUtilities.dp(6), AndroidUtilities.dp(6), AndroidUtilities.dp(6), AndroidUtilities.dp(6)); - frameLayout.addView(progressBar, LayoutHelper.createFrame(60, 60, Gravity.CENTER, 0, 0, 0, 52)); + progressView = new FrameLayout(context); + progressView.setVisibility(View.INVISIBLE); + frameLayout.addView(progressView, LayoutHelper.createFrame(LayoutHelper.MATCH_PARENT, LayoutHelper.MATCH_PARENT, Gravity.TOP | Gravity.LEFT, 0, 0, 0, 52)); + + progressViewBackground = new View(context); + progressViewBackground.setBackgroundResource(R.drawable.system_loader); + progressView.addView(progressViewBackground, LayoutHelper.createFrame(36, 36, Gravity.CENTER)); + + ProgressBar progressBar = new ProgressBar(context); + try { + progressBar.setIndeterminateDrawable(context.getResources().getDrawable(R.drawable.loading_animation)); + } catch (Exception e) { + //don't promt + } + progressBar.setIndeterminate(true); + AndroidUtilities.setProgressBarAnimationDuration(progressBar, 1500); + progressView.addView(progressBar, LayoutHelper.createFrame(32, 32, Gravity.CENTER)); RecyclerListView listView = new RecyclerListView(context); listView.setClipToPadding(false); @@ -192,7 +206,6 @@ public class WallpapersActivity extends BaseFragment implements NotificationCent LinearLayoutManager layoutManager = new LinearLayoutManager(context); layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); listView.setLayoutManager(layoutManager); - listView.setClipToPadding(false); listView.setDisallowInterceptTouchEvents(true); if (Build.VERSION.SDK_INT >= 9) { listView.setOverScrollMode(RecyclerListView.OVER_SCROLL_NEVER); @@ -332,11 +345,12 @@ public class WallpapersActivity extends BaseFragment implements NotificationCent String fileName = size.location.volume_id + "_" + size.location.local_id + ".jpg"; File f = new File(FileLoader.getInstance().getDirectory(FileLoader.MEDIA_DIR_CACHE), fileName); if (!f.exists()) { - progressBar.setProgress(0); + int result[] = AndroidUtilities.calcDrawableColor(backgroundImage.getDrawable()); + progressViewBackground.getBackground().setColorFilter(new PorterDuffColorFilter(result[0], PorterDuff.Mode.MULTIPLY)); loadingFile = fileName; loadingFileObject = f; doneButton.setEnabled(false); - progressBar.setVisibility(View.VISIBLE); + progressView.setVisibility(View.VISIBLE); loadingSize = size; selectedColor = 0; FileLoader.getInstance().loadFile(size, null, true); @@ -356,7 +370,7 @@ public class WallpapersActivity extends BaseFragment implements NotificationCent backgroundImage.setBackgroundColor(0); selectedColor = 0; doneButton.setEnabled(true); - progressBar.setVisibility(View.GONE); + progressView.setVisibility(View.GONE); } } else { if (loadingFile != null) { @@ -372,11 +386,7 @@ public class WallpapersActivity extends BaseFragment implements NotificationCent toFile = new File(ApplicationLoader.getFilesDirFixed(), "wallpaper.jpg"); } if (toFile.exists()) { - try{ backgroundImage.setImageURI(Uri.fromFile(toFile)); - } catch (Exception e) { - FileLog.e("tmessages", e); - } } else { selectedBackground = 1000001; processSelectedBackground(); @@ -396,7 +406,7 @@ public class WallpapersActivity extends BaseFragment implements NotificationCent loadingFile = null; loadingSize = null; doneButton.setEnabled(true); - progressBar.setVisibility(View.GONE); + progressView.setVisibility(View.GONE); } } @@ -409,26 +419,20 @@ public class WallpapersActivity extends BaseFragment implements NotificationCent loadingFileObject = null; loadingFile = null; loadingSize = null; - progressBar.setVisibility(View.GONE); + progressView.setVisibility(View.GONE); doneButton.setEnabled(false); } } else if (id == NotificationCenter.FileDidLoaded) { String location = (String) args[0]; if (loadingFile != null && loadingFile.equals(location)) { backgroundImage.setImageURI(Uri.fromFile(loadingFileObject)); - progressBar.setVisibility(View.GONE); + progressView.setVisibility(View.GONE); backgroundImage.setBackgroundColor(0); doneButton.setEnabled(true); loadingFileObject = null; loadingFile = null; loadingSize = null; } - } else if (id == NotificationCenter.FileLoadProgressChanged) { - String location = (String) args[0]; - if (loadingFile != null && loadingFile.equals(location)) { - Float progress = (Float) args[1]; - progressBar.setProgress((int) (progress * 100)); - } } else if (id == NotificationCenter.wallpapersDidLoaded) { wallPapers = (ArrayList) args[0]; wallpappersByIds.clear(); diff --git a/TMessagesProj/src/main/res/anim/no_animation.xml b/TMessagesProj/src/main/res/anim/no_animation.xml new file mode 100644 index 00000000..bfaa5cfb --- /dev/null +++ b/TMessagesProj/src/main/res/anim/no_animation.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable-hdpi/abc_ic_menu_share_mtrl_alpha.png b/TMessagesProj/src/main/res/drawable-hdpi/abc_ic_menu_share_mtrl_alpha.png new file mode 100644 index 00000000..ee408129 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/abc_ic_menu_share_mtrl_alpha.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/addcontact_blue.png b/TMessagesProj/src/main/res/drawable-hdpi/addcontact_blue.png deleted file mode 100644 index a90b6ce9..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/addcontact_blue.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/admin_star.png b/TMessagesProj/src/main/res/drawable-hdpi/admin_star.png new file mode 100644 index 00000000..2f6db99e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/admin_star.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/admin_star2.png b/TMessagesProj/src/main/res/drawable-hdpi/admin_star2.png new file mode 100644 index 00000000..6d9f3a89 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/admin_star2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/assign_manager.png b/TMessagesProj/src/main/res/drawable-hdpi/assign_manager.png new file mode 100644 index 00000000..153a7fb1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/assign_manager.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_audio.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_audio.png new file mode 100644 index 00000000..a5c7a37c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_audio.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_audio_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_audio_pressed.png new file mode 100644 index 00000000..f29f74fa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_audio_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_camera.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_camera.png new file mode 100644 index 00000000..1c38eae4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_camera.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_camera_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_camera_pressed.png new file mode 100644 index 00000000..c44d38bc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_camera_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_contact.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_contact.png new file mode 100644 index 00000000..147f8b75 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_contact.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_contact_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_contact_pressed.png new file mode 100644 index 00000000..8c38efd6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_contact_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_file.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_file.png new file mode 100644 index 00000000..26abdde7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_file.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_file_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_file_pressed.png new file mode 100644 index 00000000..4859f01c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_file_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_gallery.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_gallery.png new file mode 100644 index 00000000..e207259c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_gallery.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_gallery_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_gallery_pressed.png new file mode 100644 index 00000000..354e4617 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_gallery_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_hide1.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_hide1.png new file mode 100644 index 00000000..20940dec Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_hide1.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_hide1_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_hide1_pressed.png new file mode 100644 index 00000000..ac591268 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_hide1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_hide2.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_hide2.png new file mode 100644 index 00000000..e5051523 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_hide2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_location.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_location.png new file mode 100644 index 00000000..8e76cff4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_location_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_location_pressed.png new file mode 100644 index 00000000..bc2f1184 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_location_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_send1.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_send1.png new file mode 100644 index 00000000..b5e89766 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_send1.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_send1_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_send1_pressed.png new file mode 100644 index 00000000..86dafab4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_send1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_send2.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_send2.png new file mode 100644 index 00000000..92f8b2dd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_send2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_video.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_video.png new file mode 100644 index 00000000..2b21de5b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_video.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/attach_video_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/attach_video_pressed.png new file mode 100644 index 00000000..3f23133f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/attach_video_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/audiosend_pause.png b/TMessagesProj/src/main/res/drawable-hdpi/audiosend_pause.png new file mode 100644 index 00000000..3900d815 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/audiosend_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/audiosend_play.png b/TMessagesProj/src/main/res/drawable-hdpi/audiosend_play.png new file mode 100644 index 00000000..4b13c02e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/audiosend_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/blockpanel.png b/TMessagesProj/src/main/res/drawable-hdpi/blockpanel.png new file mode 100644 index 00000000..b9f658a3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/blockpanel.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bluecounter.9.png b/TMessagesProj/src/main/res/drawable-hdpi/bluecounter.9.png new file mode 100644 index 00000000..afafbee3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/bluecounter.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_file.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_file.png new file mode 100644 index 00000000..81a867e9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/bot_file.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_info.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_info.png new file mode 100644 index 00000000..6b5a4a2b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/bot_info.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard.png new file mode 100644 index 00000000..e045972d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard2.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard2.png new file mode 100644 index 00000000..d43df46c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard_button.9.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard_button.9.png new file mode 100644 index 00000000..55777ab3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard_button.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard_button_pressed.9.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard_button_pressed.9.png new file mode 100644 index 00000000..15a03df7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/bot_keyboard_button_pressed.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_lines.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_lines.png new file mode 100644 index 00000000..3d80a3e4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/bot_lines.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_link.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_link.png new file mode 100644 index 00000000..9fbea8cf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/bot_link.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_list.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_list.png new file mode 100644 index 00000000..cbcfa1f2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/bot_list.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_location.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_location.png new file mode 100644 index 00000000..e587748f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/bot_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/bot_music.png b/TMessagesProj/src/main/res/drawable-hdpi/bot_music.png new file mode 100644 index 00000000..03857ec8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/bot_music.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/cancel_b.png b/TMessagesProj/src/main/res/drawable-hdpi/cancel_b.png deleted file mode 100644 index c942d603..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/cancel_b.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/cancel_b_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/cancel_b_pressed.png deleted file mode 100644 index 58add0c1..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/cancel_b_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/cancel_g.png b/TMessagesProj/src/main/res/drawable-hdpi/cancel_g.png deleted file mode 100644 index 7c9c3dec..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/cancel_g.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/cancel_g_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/cancel_g_pressed.png deleted file mode 100644 index 2efb6df0..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/cancel_g_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/channelintro.png b/TMessagesProj/src/main/res/drawable-hdpi/channelintro.png new file mode 100644 index 00000000..7a9b8b49 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/channelintro.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/check_list.png b/TMessagesProj/src/main/res/drawable-hdpi/check_list.png new file mode 100644 index 00000000..e739bea2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/check_list.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/check_profile.png b/TMessagesProj/src/main/res/drawable-hdpi/check_profile.png new file mode 100644 index 00000000..380a8ebf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/check_profile.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/contact_blue.png b/TMessagesProj/src/main/res/drawable-hdpi/contact_blue.png new file mode 100644 index 00000000..0f52e878 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/contact_blue.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/contact_green.png b/TMessagesProj/src/main/res/drawable-hdpi/contact_green.png new file mode 100644 index 00000000..1b3c67d7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/contact_green.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/corner_in_bl.png b/TMessagesProj/src/main/res/drawable-hdpi/corner_in_bl.png new file mode 100644 index 00000000..de269315 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/corner_in_bl.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/corner_in_br.png b/TMessagesProj/src/main/res/drawable-hdpi/corner_in_br.png new file mode 100644 index 00000000..4bdd9632 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/corner_in_br.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/corner_in_tl.png b/TMessagesProj/src/main/res/drawable-hdpi/corner_in_tl.png new file mode 100644 index 00000000..26868c2a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/corner_in_tl.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/corner_in_tr.png b/TMessagesProj/src/main/res/drawable-hdpi/corner_in_tr.png new file mode 100644 index 00000000..7351bcc9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/corner_in_tr.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/corner_out_bl.png b/TMessagesProj/src/main/res/drawable-hdpi/corner_out_bl.png new file mode 100644 index 00000000..6209ba0b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/corner_out_bl.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/corner_out_br.png b/TMessagesProj/src/main/res/drawable-hdpi/corner_out_br.png new file mode 100644 index 00000000..e4783db8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/corner_out_br.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/corner_out_tl.png b/TMessagesProj/src/main/res/drawable-hdpi/corner_out_tl.png new file mode 100644 index 00000000..0c22f84e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/corner_out_tl.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/corner_out_tr.png b/TMessagesProj/src/main/res/drawable-hdpi/corner_out_tr.png new file mode 100644 index 00000000..64cab85f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/corner_out_tr.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_badge2.9.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_badge2.9.png new file mode 100644 index 00000000..3a857ff2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_badge2.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_10.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_10.png new file mode 100644 index 00000000..68aa1dfe Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_11.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_11.png new file mode 100644 index 00000000..152fca1a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_12.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_12.png new file mode 100644 index 00000000..34608104 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_2.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_2.png new file mode 100644 index 00000000..0f3b1c17 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_3.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_3.png new file mode 100644 index 00000000..454d59ac Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_4.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_4.png new file mode 100644 index 00000000..32523935 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_5.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_5.png new file mode 100644 index 00000000..71761362 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_6.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_6.png new file mode 100644 index 00000000..ad37a1d0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_7.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_7.png new file mode 100644 index 00000000..1649119a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_8.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_8.png new file mode 100644 index 00000000..b59bdcd4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_9.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_9.png new file mode 100644 index 00000000..3ae0c5b1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_check_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_10.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_10.png new file mode 100644 index 00000000..b59bdcd4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_11.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_11.png new file mode 100644 index 00000000..850c1174 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_12.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_12.png new file mode 100644 index 00000000..c2abcc0a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_2.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_2.png new file mode 100644 index 00000000..0f3b1c17 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_3.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_3.png new file mode 100644 index 00000000..454d59ac Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_4.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_4.png new file mode 100644 index 00000000..9f8f9c99 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_5.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_5.png new file mode 100644 index 00000000..6eadf894 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_6.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_6.png new file mode 100644 index 00000000..d454b648 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_7.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_7.png new file mode 100644 index 00000000..25053a21 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_8.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_8.png new file mode 100644 index 00000000..b59bdcd4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_9.png b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_9.png new file mode 100644 index 00000000..36d5afcc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/dialogs_halfcheck_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/doc_actions_b_s.png b/TMessagesProj/src/main/res/drawable-hdpi/doc_actions_b_s.png new file mode 100644 index 00000000..f107194d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/doc_actions_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/doc_blue_s.png b/TMessagesProj/src/main/res/drawable-hdpi/doc_blue_s.png new file mode 100644 index 00000000..0484f441 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/doc_blue_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/doccancel_b_s.png b/TMessagesProj/src/main/res/drawable-hdpi/doccancel_b_s.png new file mode 100644 index 00000000..0f607d71 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/doccancel_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/docload_b_s.png b/TMessagesProj/src/main/res/drawable-hdpi/docload_b_s.png new file mode 100644 index 00000000..e5bbd51f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/docload_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/docpause_b_s.png b/TMessagesProj/src/main/res/drawable-hdpi/docpause_b_s.png new file mode 100644 index 00000000..3bc4621e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/docpause_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/download_b.png b/TMessagesProj/src/main/res/drawable-hdpi/download_b.png deleted file mode 100644 index a9f42812..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/download_b.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/download_b_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/download_b_pressed.png deleted file mode 100644 index d3a6eb91..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/download_b_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/download_g.png b/TMessagesProj/src/main/res/drawable-hdpi/download_g.png deleted file mode 100644 index 1c576213..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/download_g.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/download_g_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/download_g_pressed.png deleted file mode 100644 index c4bba83d..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/download_g_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/file_b.png b/TMessagesProj/src/main/res/drawable-hdpi/file_b.png new file mode 100644 index 00000000..b9b9fdbc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/file_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/file_b_cancel.png b/TMessagesProj/src/main/res/drawable-hdpi/file_b_cancel.png new file mode 100644 index 00000000..76fccb3b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/file_b_cancel.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/file_b_cancel_s.png b/TMessagesProj/src/main/res/drawable-hdpi/file_b_cancel_s.png new file mode 100644 index 00000000..212a68f2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/file_b_cancel_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/file_b_load.png b/TMessagesProj/src/main/res/drawable-hdpi/file_b_load.png new file mode 100644 index 00000000..d704af86 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/file_b_load.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/file_b_load_s.png b/TMessagesProj/src/main/res/drawable-hdpi/file_b_load_s.png new file mode 100644 index 00000000..23a413da Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/file_b_load_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/file_b_s.png b/TMessagesProj/src/main/res/drawable-hdpi/file_b_s.png new file mode 100644 index 00000000..b682a368 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/file_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/file_g.png b/TMessagesProj/src/main/res/drawable-hdpi/file_g.png new file mode 100644 index 00000000..6b805748 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/file_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/file_g_cancel.png b/TMessagesProj/src/main/res/drawable-hdpi/file_g_cancel.png new file mode 100644 index 00000000..5fbc87d9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/file_g_cancel.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/file_g_cancel_s.png b/TMessagesProj/src/main/res/drawable-hdpi/file_g_cancel_s.png new file mode 100644 index 00000000..07b8de15 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/file_g_cancel_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/file_g_load.png b/TMessagesProj/src/main/res/drawable-hdpi/file_g_load.png new file mode 100644 index 00000000..741b6986 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/file_g_load.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/file_g_load_s.png b/TMessagesProj/src/main/res/drawable-hdpi/file_g_load_s.png new file mode 100644 index 00000000..24490012 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/file_g_load_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/file_g_s.png b/TMessagesProj/src/main/res/drawable-hdpi/file_g_s.png new file mode 100644 index 00000000..41228655 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/file_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/ic_action_next.png b/TMessagesProj/src/main/res/drawable-hdpi/ic_action_next.png new file mode 100644 index 00000000..4eaf7caa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/ic_action_next.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/ic_action_pause.png b/TMessagesProj/src/main/res/drawable-hdpi/ic_action_pause.png new file mode 100644 index 00000000..da17d12b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/ic_action_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/ic_action_play.png b/TMessagesProj/src/main/res/drawable-hdpi/ic_action_play.png new file mode 100644 index 00000000..0cd5cb61 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/ic_action_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/ic_action_previous.png b/TMessagesProj/src/main/res/drawable-hdpi/ic_action_previous.png new file mode 100644 index 00000000..e59dedb6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/ic_action_previous.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/ic_create.png b/TMessagesProj/src/main/res/drawable-hdpi/ic_create.png new file mode 100644 index 00000000..82966ed2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/ic_create.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/ic_fp_40px.png b/TMessagesProj/src/main/res/drawable-hdpi/ic_fp_40px.png new file mode 100644 index 00000000..48ebd8ad Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/ic_fp_40px.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/ic_launcher_beta.png b/TMessagesProj/src/main/res/drawable-hdpi/ic_launcher_beta.png new file mode 100644 index 00000000..a2c11681 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/ic_launcher_beta.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/ic_settings.png b/TMessagesProj/src/main/res/drawable-hdpi/ic_settings.png new file mode 100644 index 00000000..e999e329 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/ic_settings.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/ic_smiles_gif.png b/TMessagesProj/src/main/res/drawable-hdpi/ic_smiles_gif.png new file mode 100644 index 00000000..a06057c5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/ic_smiles_gif.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/igvideo.png b/TMessagesProj/src/main/res/drawable-hdpi/igvideo.png deleted file mode 100644 index 92c22481..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/igvideo.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/list_circle.png b/TMessagesProj/src/main/res/drawable-hdpi/list_circle.png new file mode 100644 index 00000000..e6c27d1d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/list_circle.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/list_supergroup.png b/TMessagesProj/src/main/res/drawable-hdpi/list_supergroup.png new file mode 100644 index 00000000..1968085a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/list_supergroup.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/location2.png b/TMessagesProj/src/main/res/drawable-hdpi/location2.png new file mode 100644 index 00000000..84e92b27 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/location2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/logo_avatar.png b/TMessagesProj/src/main/res/drawable-hdpi/logo_avatar.png new file mode 100644 index 00000000..8892c08d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/logo_avatar.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/managers.png b/TMessagesProj/src/main/res/drawable-hdpi/managers.png new file mode 100644 index 00000000..0cad1f45 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/managers.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_admin.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_admin.png new file mode 100644 index 00000000..b8418c52 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_admin.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_plus.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_plus.png new file mode 100644 index 00000000..60948cb1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_plus.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/menu_themes.png b/TMessagesProj/src/main/res/drawable-hdpi/menu_themes.png new file mode 100644 index 00000000..0f3f38a1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/menu_themes.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/miniplayer_close.png b/TMessagesProj/src/main/res/drawable-hdpi/miniplayer_close.png new file mode 100644 index 00000000..ee4972c7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/miniplayer_close.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/miniplayer_pause.png b/TMessagesProj/src/main/res/drawable-hdpi/miniplayer_pause.png new file mode 100644 index 00000000..f173ae63 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/miniplayer_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/miniplayer_play.png b/TMessagesProj/src/main/res/drawable-hdpi/miniplayer_play.png new file mode 100644 index 00000000..7dd0d068 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/miniplayer_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_10.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_10.png new file mode 100644 index 00000000..8d63ea2b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_11.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_11.png new file mode 100644 index 00000000..727e3047 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_12.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_12.png new file mode 100644 index 00000000..3a25d80b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_2.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_2.png new file mode 100644 index 00000000..f0296d41 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_3.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_3.png new file mode 100644 index 00000000..5d438f8d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_4.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_4.png new file mode 100644 index 00000000..39c26c52 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_5.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_5.png new file mode 100644 index 00000000..6052c9cd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_6.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_6.png new file mode 100644 index 00000000..7dd4d9b4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_7.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_7.png new file mode 100644 index 00000000..0d98dd32 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_8.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_8.png new file mode 100644 index 00000000..5a52b24c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_9.png new file mode 100644 index 00000000..578adf6a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_10.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_10.png new file mode 100644 index 00000000..f5bd31df Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_11.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_11.png new file mode 100644 index 00000000..c3191aee Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_12.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_12.png new file mode 100644 index 00000000..dba17090 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_2.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_2.png new file mode 100644 index 00000000..a5706f46 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_3.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_3.png new file mode 100644 index 00000000..ba41ad6b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_4.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_4.png new file mode 100644 index 00000000..f8e33cd5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_5.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_5.png new file mode 100644 index 00000000..4c717f51 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_6.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_6.png new file mode 100644 index 00000000..2cdee862 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_7.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_7.png new file mode 100644 index 00000000..de3fddad Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_8.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_8.png new file mode 100644 index 00000000..3b01d65e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_9.png new file mode 100644 index 00000000..c5286f13 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_check_w_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_clock2.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_clock2.png new file mode 100644 index 00000000..68c4f355 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_clock2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_clock2_s.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_clock2_s.png new file mode 100644 index 00000000..74166457 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_clock2_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_10.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_10.png new file mode 100644 index 00000000..5a52b24c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_11.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_11.png new file mode 100644 index 00000000..22c90419 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_12.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_12.png new file mode 100644 index 00000000..ec4ca2b6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_13.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_13.png new file mode 100644 index 00000000..36a47882 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_13.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_2.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_2.png new file mode 100644 index 00000000..f0296d41 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_3.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_3.png new file mode 100644 index 00000000..5d438f8d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_4.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_4.png new file mode 100644 index 00000000..e8935d73 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_5.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_5.png new file mode 100644 index 00000000..d9c9b8cc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_6.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_6.png new file mode 100644 index 00000000..41c21aa6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_7.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_7.png new file mode 100644 index 00000000..4ae46054 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_8.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_8.png new file mode 100644 index 00000000..5a52b24c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_9.png new file mode 100644 index 00000000..0969549d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_10.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_10.png new file mode 100644 index 00000000..6dd74b40 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_11.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_11.png new file mode 100644 index 00000000..c96ab3aa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_12.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_12.png new file mode 100644 index 00000000..3fd76704 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_13.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_13.png new file mode 100644 index 00000000..a455ecb1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_13.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_2.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_2.png new file mode 100644 index 00000000..a5706f46 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_3.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_3.png new file mode 100644 index 00000000..ba41ad6b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_4.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_4.png new file mode 100644 index 00000000..fc2db41a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_5.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_5.png new file mode 100644 index 00000000..22c6acd3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_6.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_6.png new file mode 100644 index 00000000..8a9429b0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_7.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_7.png new file mode 100644 index 00000000..e0b6d671 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_8.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_8.png new file mode 100644 index 00000000..3b01d65e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_9.png new file mode 100644 index 00000000..3d2c1f54 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_halfcheck_w_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_5.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_5.9.png new file mode 100644 index 00000000..3efdfb91 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_5.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_5_photo.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_5_photo.9.png new file mode 100644 index 00000000..e92d7aed Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_5_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_5_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_5_photo_selected.9.png new file mode 100644 index 00000000..f88932d1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_5_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_5_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_5_selected.9.png new file mode 100644 index 00000000..5ca39d4d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_5_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_6.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_6.9.png new file mode 100644 index 00000000..d61099c7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_6.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_6_photo.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_6_photo.9.png new file mode 100644 index 00000000..ed05680b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_6_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_6_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_6_photo_selected.9.png new file mode 100644 index 00000000..d22419bc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_6_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_6_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_6_selected.9.png new file mode 100644 index 00000000..862d97dc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_6_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_7.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_7.9.png new file mode 100644 index 00000000..d7f86250 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_7.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_7_photo.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_7_photo.9.png new file mode 100644 index 00000000..e92d7aed Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_7_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_7_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_7_photo_selected.9.png new file mode 100644 index 00000000..f88932d1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_7_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_7_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_7_selected.9.png new file mode 100644 index 00000000..d1fbda48 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_7_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_8.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_8.9.png new file mode 100644 index 00000000..974d60e2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_8.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_8_photo.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_8_photo.9.png new file mode 100644 index 00000000..e92d7aed Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_8_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_8_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_8_photo_selected.9.png new file mode 100644 index 00000000..f88932d1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_8_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_in_8_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_8_selected.9.png new file mode 100644 index 00000000..a7638c2d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_in_8_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_5.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_5.9.png new file mode 100644 index 00000000..9d6764e8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_5.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_5_photo.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_5_photo.9.png new file mode 100644 index 00000000..f8f07f7f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_5_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_5_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_5_photo_selected.9.png new file mode 100644 index 00000000..3d5b1f9f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_5_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_5_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_5_selected.9.png new file mode 100644 index 00000000..9db6fc55 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_5_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_6.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_6.9.png new file mode 100644 index 00000000..bd4e9a9c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_6.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_6_photo.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_6_photo.9.png new file mode 100644 index 00000000..81150da1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_6_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_6_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_6_photo_selected.9.png new file mode 100644 index 00000000..23e950ea Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_6_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_6_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_6_selected.9.png new file mode 100644 index 00000000..72b6276b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_6_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_7.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_7.9.png new file mode 100644 index 00000000..52ebfa1f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_7.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_7_photo.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_7_photo.9.png new file mode 100644 index 00000000..f8f07f7f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_7_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_7_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_7_photo_selected.9.png new file mode 100644 index 00000000..3d5b1f9f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_7_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_7_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_7_selected.9.png new file mode 100644 index 00000000..e8fb49a7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_7_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_8.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_8.9.png new file mode 100644 index 00000000..08fd35b4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_8.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_8_photo.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_8_photo.9.png new file mode 100644 index 00000000..f8f07f7f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_8_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_8_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_8_photo_selected.9.png new file mode 100644 index 00000000..3d5b1f9f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_8_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/msg_out_8_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_8_selected.9.png new file mode 100644 index 00000000..5e01d8fe Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/msg_out_8_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/nocover.png b/TMessagesProj/src/main/res/drawable-hdpi/nocover.png new file mode 100644 index 00000000..4c0748a9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/nocover.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/nocover_big.9.png b/TMessagesProj/src/main/res/drawable-hdpi/nocover_big.9.png new file mode 100644 index 00000000..7b02d9e1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/nocover_big.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/nocover_small.9.png b/TMessagesProj/src/main/res/drawable-hdpi/nocover_small.9.png new file mode 100644 index 00000000..8e5d60b8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/nocover_small.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/notify_members_off.png b/TMessagesProj/src/main/res/drawable-hdpi/notify_members_off.png new file mode 100644 index 00000000..6f77fbdc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/notify_members_off.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/notify_members_on.png b/TMessagesProj/src/main/res/drawable-hdpi/notify_members_on.png new file mode 100644 index 00000000..cd6f4229 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/notify_members_on.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pause_b_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/pause_b_pressed.png deleted file mode 100644 index 9f4b6e1d..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/pause_b_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pause_b_s.png b/TMessagesProj/src/main/res/drawable-hdpi/pause_b_s.png new file mode 100644 index 00000000..fe250126 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pause_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pause_g_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/pause_g_pressed.png deleted file mode 100644 index 19c76b44..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/pause_g_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pause_g_s.png b/TMessagesProj/src/main/res/drawable-hdpi/pause_g_s.png new file mode 100644 index 00000000..f9b9d428 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pause_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pause_w.png b/TMessagesProj/src/main/res/drawable-hdpi/pause_w.png deleted file mode 100644 index b3ba2dce..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/pause_w.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pause_w2.png b/TMessagesProj/src/main/res/drawable-hdpi/pause_w2.png deleted file mode 100644 index c673dbc1..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/pause_w2.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pause_w2_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/pause_w2_pressed.png deleted file mode 100644 index 7fdae4f8..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/pause_w2_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pause_w_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/pause_w_pressed.png deleted file mode 100644 index ca28d541..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/pause_w_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/phone_activate.png b/TMessagesProj/src/main/res/drawable-hdpi/phone_activate.png new file mode 100644 index 00000000..52b4de8d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/phone_activate.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/photocancel_b.png b/TMessagesProj/src/main/res/drawable-hdpi/photocancel_b.png new file mode 100644 index 00000000..780ecf6a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/photocancel_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/photocancel_b_s.png b/TMessagesProj/src/main/res/drawable-hdpi/photocancel_b_s.png new file mode 100644 index 00000000..6c2bc841 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/photocancel_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/photocancel_g.png b/TMessagesProj/src/main/res/drawable-hdpi/photocancel_g.png new file mode 100644 index 00000000..23200be5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/photocancel_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/photocancel_g_s.png b/TMessagesProj/src/main/res/drawable-hdpi/photocancel_g_s.png new file mode 100644 index 00000000..a8aad3a0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/photocancel_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/photocancel_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/photocancel_pressed.png new file mode 100644 index 00000000..3aa1632d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/photocancel_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/photogif_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/photogif_pressed.png new file mode 100644 index 00000000..ec339890 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/photogif_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/photoload_b.png b/TMessagesProj/src/main/res/drawable-hdpi/photoload_b.png new file mode 100644 index 00000000..f78f534d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/photoload_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/photoload_b_s.png b/TMessagesProj/src/main/res/drawable-hdpi/photoload_b_s.png new file mode 100644 index 00000000..563dd17c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/photoload_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/photoload_g.png b/TMessagesProj/src/main/res/drawable-hdpi/photoload_g.png new file mode 100644 index 00000000..bb7ba472 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/photoload_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/photoload_g_s.png b/TMessagesProj/src/main/res/drawable-hdpi/photoload_g_s.png new file mode 100644 index 00000000..027d0da0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/photoload_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/photoload_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/photoload_pressed.png new file mode 100644 index 00000000..588a4fa7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/photoload_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/photopause.png b/TMessagesProj/src/main/res/drawable-hdpi/photopause.png deleted file mode 100644 index ca0653d4..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/photopause.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/phototime2.9.png b/TMessagesProj/src/main/res/drawable-hdpi/phototime2.9.png new file mode 100644 index 00000000..143a0fbd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/phototime2.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/phototime2_b.9.png b/TMessagesProj/src/main/res/drawable-hdpi/phototime2_b.9.png new file mode 100644 index 00000000..a0e4a272 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/phototime2_b.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pl_back.png b/TMessagesProj/src/main/res/drawable-hdpi/pl_back.png new file mode 100644 index 00000000..8eb567ad Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pl_back.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pl_next.png b/TMessagesProj/src/main/res/drawable-hdpi/pl_next.png new file mode 100644 index 00000000..c6581812 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pl_next.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pl_next_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/pl_next_pressed.png new file mode 100644 index 00000000..5a01fac9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pl_next_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pl_pause.png b/TMessagesProj/src/main/res/drawable-hdpi/pl_pause.png new file mode 100644 index 00000000..c3cbab41 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pl_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pl_pause_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/pl_pause_pressed.png new file mode 100644 index 00000000..4ec1ead1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pl_pause_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pl_play.png b/TMessagesProj/src/main/res/drawable-hdpi/pl_play.png new file mode 100644 index 00000000..434039be Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pl_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pl_play_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/pl_play_pressed.png new file mode 100644 index 00000000..836f92d5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pl_play_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pl_previous.png b/TMessagesProj/src/main/res/drawable-hdpi/pl_previous.png new file mode 100644 index 00000000..b9d67872 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pl_previous.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pl_previous_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/pl_previous_pressed.png new file mode 100644 index 00000000..4ef7d468 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pl_previous_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pl_repeat.png b/TMessagesProj/src/main/res/drawable-hdpi/pl_repeat.png new file mode 100644 index 00000000..492637b7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pl_repeat.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pl_repeat1_active.png b/TMessagesProj/src/main/res/drawable-hdpi/pl_repeat1_active.png new file mode 100644 index 00000000..4379bbd2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pl_repeat1_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pl_repeat_active.png b/TMessagesProj/src/main/res/drawable-hdpi/pl_repeat_active.png new file mode 100644 index 00000000..432f0287 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pl_repeat_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pl_shuffle.png b/TMessagesProj/src/main/res/drawable-hdpi/pl_shuffle.png new file mode 100644 index 00000000..0389f00b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pl_shuffle.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/pl_shuffle_active.png b/TMessagesProj/src/main/res/drawable-hdpi/pl_shuffle_active.png new file mode 100644 index 00000000..c1c5ab85 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/pl_shuffle_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/play_b.png b/TMessagesProj/src/main/res/drawable-hdpi/play_b.png new file mode 100644 index 00000000..702c57a9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/play_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/play_b_s.png b/TMessagesProj/src/main/res/drawable-hdpi/play_b_s.png new file mode 100644 index 00000000..fd1dc122 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/play_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/play_g.png b/TMessagesProj/src/main/res/drawable-hdpi/play_g.png new file mode 100644 index 00000000..6b61de3f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/play_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/play_g_s.png b/TMessagesProj/src/main/res/drawable-hdpi/play_g_s.png new file mode 100644 index 00000000..0cffb436 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/play_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/play_w.png b/TMessagesProj/src/main/res/drawable-hdpi/play_w.png deleted file mode 100644 index 3b9bac66..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/play_w.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/play_w2.png b/TMessagesProj/src/main/res/drawable-hdpi/play_w2.png deleted file mode 100644 index 330da7e1..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/play_w2.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/play_w2_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/play_w2_pressed.png deleted file mode 100644 index 7b7018e2..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/play_w2_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/play_w_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/play_w_pressed.png deleted file mode 100644 index 7261585f..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/play_w_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/player.png b/TMessagesProj/src/main/res/drawable-hdpi/player.png new file mode 100644 index 00000000..a62ef59b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/player.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/playvideo_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/playvideo_pressed.png new file mode 100644 index 00000000..63b03ebb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/playvideo_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/post_views.png b/TMessagesProj/src/main/res/drawable-hdpi/post_views.png new file mode 100644 index 00000000..ec2add86 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/post_views.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/post_views_s.png b/TMessagesProj/src/main/res/drawable-hdpi/post_views_s.png new file mode 100644 index 00000000..ab68d75a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/post_views_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/post_views_w.png b/TMessagesProj/src/main/res/drawable-hdpi/post_views_w.png new file mode 100644 index 00000000..a224f596 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/post_views_w.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/post_viewsg.png b/TMessagesProj/src/main/res/drawable-hdpi/post_viewsg.png new file mode 100644 index 00000000..ff153d19 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/post_viewsg.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/publish.png b/TMessagesProj/src/main/res/drawable-hdpi/publish.png new file mode 100644 index 00000000..97802475 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/publish.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/publish_active.png b/TMessagesProj/src/main/res/drawable-hdpi/publish_active.png new file mode 100644 index 00000000..9354ce65 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/publish_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/recorded.9.png b/TMessagesProj/src/main/res/drawable-hdpi/recorded.9.png new file mode 100644 index 00000000..5709cf57 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/recorded.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/redcircle.png b/TMessagesProj/src/main/res/drawable-hdpi/redcircle.png new file mode 100644 index 00000000..8b93a6c8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/redcircle.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/addcontact_green.png b/TMessagesProj/src/main/res/drawable-hdpi/s_pause.png similarity index 52% rename from TMessagesProj/src/main/res/drawable-xhdpi/addcontact_green.png rename to TMessagesProj/src/main/res/drawable-hdpi/s_pause.png index 5beefa1c..9fac4ed3 100644 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/addcontact_green.png and b/TMessagesProj/src/main/res/drawable-hdpi/s_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/s_pause_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/s_pause_pressed.png new file mode 100644 index 00000000..1965bd3b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/s_pause_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/s_play.png b/TMessagesProj/src/main/res/drawable-hdpi/s_play.png new file mode 100644 index 00000000..678a351a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/s_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/s_play_pressed.png b/TMessagesProj/src/main/res/drawable-hdpi/s_play_pressed.png new file mode 100644 index 00000000..56284c35 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/s_play_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/search_down.png b/TMessagesProj/src/main/res/drawable-hdpi/search_down.png new file mode 100644 index 00000000..f7831fa7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/search_down.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/search_share.png b/TMessagesProj/src/main/res/drawable-hdpi/search_share.png new file mode 100644 index 00000000..e5bf1d95 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/search_share.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/search_up.png b/TMessagesProj/src/main/res/drawable-hdpi/search_up.png new file mode 100644 index 00000000..41839a16 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/search_up.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/share_arrow.png b/TMessagesProj/src/main/res/drawable-hdpi/share_arrow.png new file mode 100644 index 00000000..c30cfa14 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/share_arrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/share_round.png b/TMessagesProj/src/main/res/drawable-hdpi/share_round.png new file mode 100644 index 00000000..d21a328b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/share_round.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/sheet_shadow.9.png b/TMessagesProj/src/main/res/drawable-hdpi/sheet_shadow.9.png new file mode 100644 index 00000000..dccf34fe Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/sheet_shadow.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/stickercounter.9.png b/TMessagesProj/src/main/res/drawable-hdpi/stickercounter.9.png new file mode 100644 index 00000000..e17364d6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/stickercounter.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/system.9.png b/TMessagesProj/src/main/res/drawable-hdpi/system.9.png new file mode 100644 index 00000000..de5d484a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/system.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/system_black.9.png b/TMessagesProj/src/main/res/drawable-hdpi/system_black.9.png deleted file mode 100644 index 14865b7a..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/system_black.9.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/system_blue.9.png b/TMessagesProj/src/main/res/drawable-hdpi/system_blue.9.png deleted file mode 100644 index 65ad2140..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/system_blue.9.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/system_loader.png b/TMessagesProj/src/main/res/drawable-hdpi/system_loader.png new file mode 100644 index 00000000..f6a19f07 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/system_loader.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/system_loader1.png b/TMessagesProj/src/main/res/drawable-hdpi/system_loader1.png deleted file mode 100644 index c7303995..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/system_loader1.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/system_loader2.png b/TMessagesProj/src/main/res/drawable-hdpi/system_loader2.png deleted file mode 100644 index 30432e96..00000000 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/system_loader2.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tab_all.png b/TMessagesProj/src/main/res/drawable-hdpi/tab_all.png new file mode 100644 index 00000000..7ec92239 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tab_all.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tab_bot.png b/TMessagesProj/src/main/res/drawable-hdpi/tab_bot.png new file mode 100644 index 00000000..bc252c77 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tab_bot.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tab_channel.png b/TMessagesProj/src/main/res/drawable-hdpi/tab_channel.png new file mode 100644 index 00000000..439cbb7c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tab_channel.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tab_favs.png b/TMessagesProj/src/main/res/drawable-hdpi/tab_favs.png new file mode 100644 index 00000000..c42f507e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tab_favs.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tab_group.png b/TMessagesProj/src/main/res/drawable-hdpi/tab_group.png new file mode 100644 index 00000000..91f99f88 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tab_group.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tab_selected.9.png b/TMessagesProj/src/main/res/drawable-hdpi/tab_selected.9.png new file mode 100644 index 00000000..181a528e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tab_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tab_supergroup.png b/TMessagesProj/src/main/res/drawable-hdpi/tab_supergroup.png new file mode 100644 index 00000000..b4e7e907 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tab_supergroup.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tab_user.png b/TMessagesProj/src/main/res/drawable-hdpi/tab_user.png new file mode 100644 index 00000000..98d50a26 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tab_user.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tip3.png b/TMessagesProj/src/main/res/drawable-hdpi/tip3.png new file mode 100644 index 00000000..241f3c1e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tip3.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tip4.png b/TMessagesProj/src/main/res/drawable-hdpi/tip4.png new file mode 100644 index 00000000..cdc21ca7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tip4.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tool_cropfix.png b/TMessagesProj/src/main/res/drawable-hdpi/tool_cropfix.png new file mode 100644 index 00000000..8039e1bc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tool_cropfix.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tool_curve.png b/TMessagesProj/src/main/res/drawable-hdpi/tool_curve.png new file mode 100644 index 00000000..6ba63758 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tool_curve.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tool_fade.png b/TMessagesProj/src/main/res/drawable-hdpi/tool_fade.png new file mode 100644 index 00000000..041898e9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tool_fade.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tool_rotate.png b/TMessagesProj/src/main/res/drawable-hdpi/tool_rotate.png new file mode 100644 index 00000000..00475a72 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tool_rotate.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tool_tint.png b/TMessagesProj/src/main/res/drawable-hdpi/tool_tint.png new file mode 100644 index 00000000..5fd37eb5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tool_tint.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/tooltip.9.png b/TMessagesProj/src/main/res/drawable-hdpi/tooltip.9.png new file mode 100644 index 00000000..dba0f159 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/tooltip.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/video_actions.png b/TMessagesProj/src/main/res/drawable-hdpi/video_actions.png new file mode 100644 index 00000000..1a80a8cd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-hdpi/video_actions.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/abc_ic_menu_share_mtrl_alpha.png b/TMessagesProj/src/main/res/drawable-mdpi/abc_ic_menu_share_mtrl_alpha.png new file mode 100644 index 00000000..d05f969e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/abc_ic_menu_share_mtrl_alpha.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/admin_star.png b/TMessagesProj/src/main/res/drawable-mdpi/admin_star.png new file mode 100644 index 00000000..d676d01e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/admin_star.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/admin_star2.png b/TMessagesProj/src/main/res/drawable-mdpi/admin_star2.png new file mode 100644 index 00000000..150fb215 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/admin_star2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/assign_manager.png b/TMessagesProj/src/main/res/drawable-mdpi/assign_manager.png new file mode 100644 index 00000000..40800d94 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/assign_manager.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_audio.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_audio.png new file mode 100644 index 00000000..6c576c5b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_audio.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_audio_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_audio_pressed.png new file mode 100644 index 00000000..1ca2ee2b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_audio_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_camera.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_camera.png new file mode 100644 index 00000000..cf44d89e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_camera.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_camera_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_camera_pressed.png new file mode 100644 index 00000000..0acb5a38 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_camera_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_contact.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_contact.png new file mode 100644 index 00000000..6d32ff13 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_contact.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_contact_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_contact_pressed.png new file mode 100644 index 00000000..0546d8d7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_contact_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_file.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_file.png new file mode 100644 index 00000000..3fad1ceb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_file.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_file_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_file_pressed.png new file mode 100644 index 00000000..4075c3ba Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_file_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_gallery.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_gallery.png new file mode 100644 index 00000000..d70963a2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_gallery.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_gallery_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_gallery_pressed.png new file mode 100644 index 00000000..5dcdcf07 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_gallery_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_hide1.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_hide1.png new file mode 100644 index 00000000..cb21c788 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_hide1.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_hide1_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_hide1_pressed.png new file mode 100644 index 00000000..8439f1f5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_hide1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_hide2.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_hide2.png new file mode 100644 index 00000000..1bc52abd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_hide2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_location.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_location.png new file mode 100644 index 00000000..cc02b320 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_location_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_location_pressed.png new file mode 100644 index 00000000..1c3917fe Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_location_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_send1.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_send1.png new file mode 100644 index 00000000..afcfb0aa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_send1.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_send1_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_send1_pressed.png new file mode 100644 index 00000000..d8f4bed3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_send1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_send2.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_send2.png new file mode 100644 index 00000000..a8e54f40 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_send2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_video.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_video.png new file mode 100644 index 00000000..4a956ce6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_video.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/attach_video_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/attach_video_pressed.png new file mode 100644 index 00000000..aef64ae3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/attach_video_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/audiosend_pause.png b/TMessagesProj/src/main/res/drawable-mdpi/audiosend_pause.png new file mode 100644 index 00000000..df9cc8f1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/audiosend_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/audiosend_play.png b/TMessagesProj/src/main/res/drawable-mdpi/audiosend_play.png new file mode 100644 index 00000000..b2352c30 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/audiosend_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/blockpanel.png b/TMessagesProj/src/main/res/drawable-mdpi/blockpanel.png new file mode 100644 index 00000000..fd46ec9b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/blockpanel.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bluecounter.9.png b/TMessagesProj/src/main/res/drawable-mdpi/bluecounter.9.png new file mode 100644 index 00000000..b683c0ce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/bluecounter.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bot_file.png b/TMessagesProj/src/main/res/drawable-mdpi/bot_file.png new file mode 100644 index 00000000..44b53c44 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/bot_file.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bot_info.png b/TMessagesProj/src/main/res/drawable-mdpi/bot_info.png new file mode 100644 index 00000000..d25ea6e3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/bot_info.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard.png b/TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard.png new file mode 100644 index 00000000..0e9f59a4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard2.png b/TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard2.png new file mode 100644 index 00000000..200acbe0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard_button.9.png b/TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard_button.9.png new file mode 100644 index 00000000..d84e5188 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard_button.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard_button_pressed.9.png b/TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard_button_pressed.9.png new file mode 100644 index 00000000..09472087 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/bot_keyboard_button_pressed.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bot_lines.png b/TMessagesProj/src/main/res/drawable-mdpi/bot_lines.png new file mode 100644 index 00000000..8f7e13f5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/bot_lines.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bot_link.png b/TMessagesProj/src/main/res/drawable-mdpi/bot_link.png new file mode 100644 index 00000000..76d34b50 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/bot_link.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bot_list.png b/TMessagesProj/src/main/res/drawable-mdpi/bot_list.png new file mode 100644 index 00000000..41a7ae2f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/bot_list.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bot_location.png b/TMessagesProj/src/main/res/drawable-mdpi/bot_location.png new file mode 100644 index 00000000..e18474ab Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/bot_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/bot_music.png b/TMessagesProj/src/main/res/drawable-mdpi/bot_music.png new file mode 100644 index 00000000..2a9f2e53 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/bot_music.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/cancel_b.png b/TMessagesProj/src/main/res/drawable-mdpi/cancel_b.png deleted file mode 100644 index b0dd70ea..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/cancel_b.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/cancel_b_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/cancel_b_pressed.png deleted file mode 100644 index 41215327..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/cancel_b_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/cancel_g.png b/TMessagesProj/src/main/res/drawable-mdpi/cancel_g.png deleted file mode 100644 index 43b0a71e..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/cancel_g.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/cancel_g_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/cancel_g_pressed.png deleted file mode 100644 index 4942c02c..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/cancel_g_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/channelintro.png b/TMessagesProj/src/main/res/drawable-mdpi/channelintro.png new file mode 100644 index 00000000..e4a82890 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/channelintro.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/check_list.png b/TMessagesProj/src/main/res/drawable-mdpi/check_list.png new file mode 100644 index 00000000..4061ffae Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/check_list.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/check_profile.png b/TMessagesProj/src/main/res/drawable-mdpi/check_profile.png new file mode 100644 index 00000000..ada9e496 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/check_profile.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/contact_blue.png b/TMessagesProj/src/main/res/drawable-mdpi/contact_blue.png new file mode 100644 index 00000000..1b2beced Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/contact_blue.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/contact_green.png b/TMessagesProj/src/main/res/drawable-mdpi/contact_green.png new file mode 100644 index 00000000..0cb73343 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/contact_green.png differ diff --git a/TMessagesProj/src/main/res/drawable-hdpi/addcontact_green.png b/TMessagesProj/src/main/res/drawable-mdpi/corner_in_bl.png similarity index 53% rename from TMessagesProj/src/main/res/drawable-hdpi/addcontact_green.png rename to TMessagesProj/src/main/res/drawable-mdpi/corner_in_bl.png index a553f495..51b1c281 100644 Binary files a/TMessagesProj/src/main/res/drawable-hdpi/addcontact_green.png and b/TMessagesProj/src/main/res/drawable-mdpi/corner_in_bl.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/corner_in_br.png b/TMessagesProj/src/main/res/drawable-mdpi/corner_in_br.png new file mode 100644 index 00000000..ef954307 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/corner_in_br.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/addcontact_green.png b/TMessagesProj/src/main/res/drawable-mdpi/corner_in_tl.png similarity index 54% rename from TMessagesProj/src/main/res/drawable-mdpi/addcontact_green.png rename to TMessagesProj/src/main/res/drawable-mdpi/corner_in_tl.png index 45d6ac2b..c9d6a398 100644 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/addcontact_green.png and b/TMessagesProj/src/main/res/drawable-mdpi/corner_in_tl.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/corner_in_tr.png b/TMessagesProj/src/main/res/drawable-mdpi/corner_in_tr.png new file mode 100644 index 00000000..1ca70a22 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/corner_in_tr.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/addcontact_blue.png b/TMessagesProj/src/main/res/drawable-mdpi/corner_out_bl.png similarity index 53% rename from TMessagesProj/src/main/res/drawable-mdpi/addcontact_blue.png rename to TMessagesProj/src/main/res/drawable-mdpi/corner_out_bl.png index ec9b9c02..4d5e2d59 100644 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/addcontact_blue.png and b/TMessagesProj/src/main/res/drawable-mdpi/corner_out_bl.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/corner_out_br.png b/TMessagesProj/src/main/res/drawable-mdpi/corner_out_br.png new file mode 100644 index 00000000..93b55ba6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/corner_out_br.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/corner_out_tl.png b/TMessagesProj/src/main/res/drawable-mdpi/corner_out_tl.png new file mode 100644 index 00000000..023cc522 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/corner_out_tl.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/corner_out_tr.png b/TMessagesProj/src/main/res/drawable-mdpi/corner_out_tr.png new file mode 100644 index 00000000..c549ad93 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/corner_out_tr.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_badge2.9.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_badge2.9.png new file mode 100644 index 00000000..26856e0f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_badge2.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_10.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_10.png new file mode 100644 index 00000000..4d77be82 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_11.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_11.png new file mode 100644 index 00000000..edae957b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_12.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_12.png new file mode 100644 index 00000000..3032df91 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_2.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_2.png new file mode 100644 index 00000000..0554f306 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_3.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_3.png new file mode 100644 index 00000000..e559d972 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_4.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_4.png new file mode 100644 index 00000000..37a762c4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_5.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_5.png new file mode 100644 index 00000000..d0829b02 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_6.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_6.png new file mode 100644 index 00000000..afa76a96 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_7.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_7.png new file mode 100644 index 00000000..6bf1adaf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_8.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_8.png new file mode 100644 index 00000000..a647c304 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_9.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_9.png new file mode 100644 index 00000000..2a58571a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_check_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_10.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_10.png new file mode 100644 index 00000000..a647c304 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_11.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_11.png new file mode 100644 index 00000000..b0fc3242 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_12.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_12.png new file mode 100644 index 00000000..0f657069 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_2.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_2.png new file mode 100644 index 00000000..0554f306 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_3.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_3.png new file mode 100644 index 00000000..e559d972 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_4.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_4.png new file mode 100644 index 00000000..826a998b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_5.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_5.png new file mode 100644 index 00000000..4dc83ec8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_6.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_6.png new file mode 100644 index 00000000..92213ed0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_7.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_7.png new file mode 100644 index 00000000..c9c3aa33 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_8.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_8.png new file mode 100644 index 00000000..a647c304 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_9.png b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_9.png new file mode 100644 index 00000000..f71b5290 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/dialogs_halfcheck_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/doc_actions_b_s.png b/TMessagesProj/src/main/res/drawable-mdpi/doc_actions_b_s.png new file mode 100644 index 00000000..0d86fada Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/doc_actions_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/doc_blue_s.png b/TMessagesProj/src/main/res/drawable-mdpi/doc_blue_s.png new file mode 100644 index 00000000..361da2e7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/doc_blue_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/doccancel_b_s.png b/TMessagesProj/src/main/res/drawable-mdpi/doccancel_b_s.png new file mode 100644 index 00000000..fdf95793 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/doccancel_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/docload_b_s.png b/TMessagesProj/src/main/res/drawable-mdpi/docload_b_s.png new file mode 100644 index 00000000..3b7fa820 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/docload_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/docpause_b_s.png b/TMessagesProj/src/main/res/drawable-mdpi/docpause_b_s.png new file mode 100644 index 00000000..dfe863db Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/docpause_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/download_b.png b/TMessagesProj/src/main/res/drawable-mdpi/download_b.png deleted file mode 100644 index 7c3fb80c..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/download_b.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/download_b_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/download_b_pressed.png deleted file mode 100644 index 7e5385dd..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/download_b_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/download_g.png b/TMessagesProj/src/main/res/drawable-mdpi/download_g.png deleted file mode 100644 index 2b6c9b92..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/download_g.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/download_g_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/download_g_pressed.png deleted file mode 100644 index a1270b16..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/download_g_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/file_b.png b/TMessagesProj/src/main/res/drawable-mdpi/file_b.png new file mode 100644 index 00000000..463d6452 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/file_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/file_b_cancel.png b/TMessagesProj/src/main/res/drawable-mdpi/file_b_cancel.png new file mode 100644 index 00000000..d2e69537 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/file_b_cancel.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/file_b_cancel_s.png b/TMessagesProj/src/main/res/drawable-mdpi/file_b_cancel_s.png new file mode 100644 index 00000000..0535435f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/file_b_cancel_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/file_b_load.png b/TMessagesProj/src/main/res/drawable-mdpi/file_b_load.png new file mode 100644 index 00000000..4038ef60 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/file_b_load.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/file_b_load_s.png b/TMessagesProj/src/main/res/drawable-mdpi/file_b_load_s.png new file mode 100644 index 00000000..68251f82 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/file_b_load_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/file_b_s.png b/TMessagesProj/src/main/res/drawable-mdpi/file_b_s.png new file mode 100644 index 00000000..970f88a9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/file_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/file_g.png b/TMessagesProj/src/main/res/drawable-mdpi/file_g.png new file mode 100644 index 00000000..7e3ba259 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/file_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/file_g_cancel.png b/TMessagesProj/src/main/res/drawable-mdpi/file_g_cancel.png new file mode 100644 index 00000000..8697a7ef Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/file_g_cancel.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/file_g_cancel_s.png b/TMessagesProj/src/main/res/drawable-mdpi/file_g_cancel_s.png new file mode 100644 index 00000000..16c52423 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/file_g_cancel_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/file_g_load.png b/TMessagesProj/src/main/res/drawable-mdpi/file_g_load.png new file mode 100644 index 00000000..9a760469 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/file_g_load.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/file_g_load_s.png b/TMessagesProj/src/main/res/drawable-mdpi/file_g_load_s.png new file mode 100644 index 00000000..dd804226 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/file_g_load_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/file_g_s.png b/TMessagesProj/src/main/res/drawable-mdpi/file_g_s.png new file mode 100644 index 00000000..e72c909d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/file_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/ic_action_next.png b/TMessagesProj/src/main/res/drawable-mdpi/ic_action_next.png new file mode 100644 index 00000000..936cdd77 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/ic_action_next.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/ic_action_pause.png b/TMessagesProj/src/main/res/drawable-mdpi/ic_action_pause.png new file mode 100644 index 00000000..b4bdbb55 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/ic_action_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/ic_action_play.png b/TMessagesProj/src/main/res/drawable-mdpi/ic_action_play.png new file mode 100644 index 00000000..164385d0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/ic_action_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/ic_action_previous.png b/TMessagesProj/src/main/res/drawable-mdpi/ic_action_previous.png new file mode 100644 index 00000000..97970e08 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/ic_action_previous.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/ic_create.png b/TMessagesProj/src/main/res/drawable-mdpi/ic_create.png new file mode 100644 index 00000000..289f7933 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/ic_create.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/ic_fp_40px.png b/TMessagesProj/src/main/res/drawable-mdpi/ic_fp_40px.png new file mode 100644 index 00000000..122f4425 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/ic_fp_40px.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/ic_launcher_beta.png b/TMessagesProj/src/main/res/drawable-mdpi/ic_launcher_beta.png new file mode 100644 index 00000000..8a8cbb53 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/ic_launcher_beta.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/ic_settings.png b/TMessagesProj/src/main/res/drawable-mdpi/ic_settings.png new file mode 100644 index 00000000..1d60c823 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/ic_settings.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/ic_smiles_gif.png b/TMessagesProj/src/main/res/drawable-mdpi/ic_smiles_gif.png new file mode 100644 index 00000000..0017818e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/ic_smiles_gif.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/igvideo.png b/TMessagesProj/src/main/res/drawable-mdpi/igvideo.png deleted file mode 100644 index e7b93b3b..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/igvideo.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/list_circle.png b/TMessagesProj/src/main/res/drawable-mdpi/list_circle.png new file mode 100644 index 00000000..b35bee65 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/list_circle.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/list_supergroup.png b/TMessagesProj/src/main/res/drawable-mdpi/list_supergroup.png new file mode 100644 index 00000000..bdbf41af Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/list_supergroup.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/location2.png b/TMessagesProj/src/main/res/drawable-mdpi/location2.png new file mode 100644 index 00000000..3f0abf8b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/location2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/logo_avatar.png b/TMessagesProj/src/main/res/drawable-mdpi/logo_avatar.png new file mode 100644 index 00000000..c2de7747 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/logo_avatar.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/managers.png b/TMessagesProj/src/main/res/drawable-mdpi/managers.png new file mode 100644 index 00000000..71c809f1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/managers.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_admin.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_admin.png new file mode 100644 index 00000000..f2caffcb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_admin.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_plus.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_plus.png new file mode 100644 index 00000000..8427ee2f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_plus.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/menu_themes.png b/TMessagesProj/src/main/res/drawable-mdpi/menu_themes.png new file mode 100644 index 00000000..2ece2e05 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/menu_themes.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/miniplayer_close.png b/TMessagesProj/src/main/res/drawable-mdpi/miniplayer_close.png new file mode 100644 index 00000000..1f5816b6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/miniplayer_close.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/miniplayer_pause.png b/TMessagesProj/src/main/res/drawable-mdpi/miniplayer_pause.png new file mode 100644 index 00000000..295f9add Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/miniplayer_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/miniplayer_play.png b/TMessagesProj/src/main/res/drawable-mdpi/miniplayer_play.png new file mode 100644 index 00000000..10b948e6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/miniplayer_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_10.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_10.png new file mode 100644 index 00000000..0a1d9df1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_11.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_11.png new file mode 100644 index 00000000..f7e7ad33 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_12.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_12.png new file mode 100644 index 00000000..d8607ee3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_2.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_2.png new file mode 100644 index 00000000..14c78681 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_3.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_3.png new file mode 100644 index 00000000..faaf6e5d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_4.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_4.png new file mode 100644 index 00000000..c678560f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_5.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_5.png new file mode 100644 index 00000000..b52a6afe Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_6.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_6.png new file mode 100644 index 00000000..6e53ff1c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_7.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_7.png new file mode 100644 index 00000000..e0c192aa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_8.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_8.png new file mode 100644 index 00000000..cfc778df Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_9.png new file mode 100644 index 00000000..5787d681 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_10.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_10.png new file mode 100644 index 00000000..e0c75de4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_11.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_11.png new file mode 100644 index 00000000..12af3a7c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_12.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_12.png new file mode 100644 index 00000000..f82f04ff Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_2.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_2.png new file mode 100644 index 00000000..19ec6c16 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_3.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_3.png new file mode 100644 index 00000000..5cdca932 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_4.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_4.png new file mode 100644 index 00000000..a7a003ea Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_5.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_5.png new file mode 100644 index 00000000..722ab8b2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_6.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_6.png new file mode 100644 index 00000000..d356f9fa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_7.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_7.png new file mode 100644 index 00000000..9b71c324 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_8.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_8.png new file mode 100644 index 00000000..5471f3d1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_9.png new file mode 100644 index 00000000..c839f307 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_check_w_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_clock2.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_clock2.png new file mode 100644 index 00000000..94a136eb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_clock2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_clock2_s.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_clock2_s.png new file mode 100644 index 00000000..11805a2e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_clock2_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_10.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_10.png new file mode 100644 index 00000000..cfc778df Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_11.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_11.png new file mode 100644 index 00000000..2b7ee657 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_12.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_12.png new file mode 100644 index 00000000..b92c5737 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_2.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_2.png new file mode 100644 index 00000000..14c78681 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_3.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_3.png new file mode 100644 index 00000000..faaf6e5d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_4.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_4.png new file mode 100644 index 00000000..82a1d94b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_5.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_5.png new file mode 100644 index 00000000..630d5b5d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_6.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_6.png new file mode 100644 index 00000000..c9f5ef90 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_7.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_7.png new file mode 100644 index 00000000..49df61b7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_8.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_8.png new file mode 100644 index 00000000..cfc778df Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_9.png new file mode 100644 index 00000000..f263edea Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_10.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_10.png new file mode 100644 index 00000000..4f4e87de Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_11.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_11.png new file mode 100644 index 00000000..44600c99 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_12.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_12.png new file mode 100644 index 00000000..0e289e23 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_2.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_2.png new file mode 100644 index 00000000..19ec6c16 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_3.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_3.png new file mode 100644 index 00000000..5cdca932 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_4.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_4.png new file mode 100644 index 00000000..c45cdcd7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_5.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_5.png new file mode 100644 index 00000000..66e34f65 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_6.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_6.png new file mode 100644 index 00000000..8e0eacc7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_7.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_7.png new file mode 100644 index 00000000..c1f62434 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_8.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_8.png new file mode 100644 index 00000000..5471f3d1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_9.png new file mode 100644 index 00000000..42fc9ac2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_halfcheck_w_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_5.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_5.9.png new file mode 100644 index 00000000..4043d0e2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_5.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_photo_2.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_5_photo.9.png similarity index 100% rename from TMessagesProj/src/main/res/drawable-mdpi/msg_in_photo_2.9.png rename to TMessagesProj/src/main/res/drawable-mdpi/msg_in_5_photo.9.png diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_5_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_5_photo_selected.9.png new file mode 100644 index 00000000..0658e94a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_5_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_5_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_5_selected.9.png new file mode 100644 index 00000000..7a0c9c18 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_5_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_6.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_6.9.png new file mode 100644 index 00000000..70f7ba1b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_6.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_6_photo.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_6_photo.9.png new file mode 100644 index 00000000..8a046746 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_6_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_6_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_6_photo_selected.9.png new file mode 100644 index 00000000..79e045e8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_6_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_6_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_6_selected.9.png new file mode 100644 index 00000000..374c537c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_6_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_7.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_7.9.png new file mode 100644 index 00000000..dbc29f3a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_7.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_7_photo.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_7_photo.9.png new file mode 100644 index 00000000..c5c6aa59 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_7_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_7_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_7_photo_selected.9.png new file mode 100644 index 00000000..0658e94a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_7_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_7_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_7_selected.9.png new file mode 100644 index 00000000..c19f5ad2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_7_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_8.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_8.9.png new file mode 100644 index 00000000..f9a0267b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_8.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_8_photo.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_8_photo.9.png new file mode 100644 index 00000000..c5c6aa59 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_8_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_8_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_8_photo_selected.9.png new file mode 100644 index 00000000..0658e94a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_8_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_in_8_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_8_selected.9.png new file mode 100644 index 00000000..cd111806 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_in_8_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_5.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_5.9.png new file mode 100644 index 00000000..8eae2363 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_5.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_5_photo.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_5_photo.9.png new file mode 100644 index 00000000..ad4ad9ce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_5_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_5_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_5_photo_selected.9.png new file mode 100644 index 00000000..734f9436 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_5_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_5_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_5_selected.9.png new file mode 100644 index 00000000..55e11ffd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_5_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_6.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_6.9.png new file mode 100644 index 00000000..8221c3ef Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_6.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_6_photo.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_6_photo.9.png new file mode 100644 index 00000000..7374f59e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_6_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_6_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_6_photo_selected.9.png new file mode 100644 index 00000000..c8e81cb8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_6_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_6_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_6_selected.9.png new file mode 100644 index 00000000..77d6d021 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_6_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_7.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_7.9.png new file mode 100644 index 00000000..03e0175a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_7.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_7_photo.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_7_photo.9.png new file mode 100644 index 00000000..ad4ad9ce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_7_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_7_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_7_photo_selected.9.png new file mode 100644 index 00000000..734f9436 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_7_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_7_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_7_selected.9.png new file mode 100644 index 00000000..e15fa3d7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_7_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_.9.png new file mode 100644 index 00000000..f22c541f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_photo.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_photo.9.png new file mode 100644 index 00000000..ad4ad9ce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_photo_selected.9.png new file mode 100644 index 00000000..734f9436 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_selected.9.png b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_selected.9.png new file mode 100644 index 00000000..7e29c812 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/msg_out_8_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/nocover.png b/TMessagesProj/src/main/res/drawable-mdpi/nocover.png new file mode 100644 index 00000000..abbedfc2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/nocover.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/nocover_big.9.png b/TMessagesProj/src/main/res/drawable-mdpi/nocover_big.9.png new file mode 100644 index 00000000..017c16f1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/nocover_big.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/nocover_small.9.png b/TMessagesProj/src/main/res/drawable-mdpi/nocover_small.9.png new file mode 100644 index 00000000..6c5b5e65 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/nocover_small.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/notify_members_off.png b/TMessagesProj/src/main/res/drawable-mdpi/notify_members_off.png new file mode 100644 index 00000000..d6bb409e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/notify_members_off.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/notify_members_on.png b/TMessagesProj/src/main/res/drawable-mdpi/notify_members_on.png new file mode 100644 index 00000000..001f109b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/notify_members_on.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pause_b_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/pause_b_pressed.png deleted file mode 100644 index e300fbbc..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/pause_b_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pause_b_s.png b/TMessagesProj/src/main/res/drawable-mdpi/pause_b_s.png new file mode 100644 index 00000000..80fafabb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pause_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pause_g_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/pause_g_pressed.png deleted file mode 100644 index 82e15e54..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/pause_g_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pause_g_s.png b/TMessagesProj/src/main/res/drawable-mdpi/pause_g_s.png new file mode 100644 index 00000000..b711a313 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pause_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pause_w.png b/TMessagesProj/src/main/res/drawable-mdpi/pause_w.png deleted file mode 100644 index a6416a69..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/pause_w.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pause_w2.png b/TMessagesProj/src/main/res/drawable-mdpi/pause_w2.png deleted file mode 100644 index a5d419e7..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/pause_w2.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pause_w2_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/pause_w2_pressed.png deleted file mode 100644 index 03dad746..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/pause_w2_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/phone_activate.png b/TMessagesProj/src/main/res/drawable-mdpi/phone_activate.png new file mode 100644 index 00000000..62dcc7ae Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/phone_activate.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/photocancel_b.png b/TMessagesProj/src/main/res/drawable-mdpi/photocancel_b.png new file mode 100644 index 00000000..be189093 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/photocancel_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/photocancel_b_s.png b/TMessagesProj/src/main/res/drawable-mdpi/photocancel_b_s.png new file mode 100644 index 00000000..2d432869 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/photocancel_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/photocancel_g.png b/TMessagesProj/src/main/res/drawable-mdpi/photocancel_g.png new file mode 100644 index 00000000..9493aa82 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/photocancel_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/photocancel_g_s.png b/TMessagesProj/src/main/res/drawable-mdpi/photocancel_g_s.png new file mode 100644 index 00000000..7d4af043 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/photocancel_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/photocancel_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/photocancel_pressed.png new file mode 100644 index 00000000..491b3d43 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/photocancel_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/photogif_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/photogif_pressed.png new file mode 100644 index 00000000..64af18ac Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/photogif_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/photoload_b.png b/TMessagesProj/src/main/res/drawable-mdpi/photoload_b.png new file mode 100644 index 00000000..fb97fc7c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/photoload_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/photoload_b_s.png b/TMessagesProj/src/main/res/drawable-mdpi/photoload_b_s.png new file mode 100644 index 00000000..be2dfb74 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/photoload_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/photoload_g.png b/TMessagesProj/src/main/res/drawable-mdpi/photoload_g.png new file mode 100644 index 00000000..7321550e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/photoload_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/photoload_g_s.png b/TMessagesProj/src/main/res/drawable-mdpi/photoload_g_s.png new file mode 100644 index 00000000..2411e380 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/photoload_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/photoload_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/photoload_pressed.png new file mode 100644 index 00000000..87810072 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/photoload_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/photopause.png b/TMessagesProj/src/main/res/drawable-mdpi/photopause.png deleted file mode 100644 index e3051be7..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/photopause.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/phototime2.9.png b/TMessagesProj/src/main/res/drawable-mdpi/phototime2.9.png new file mode 100644 index 00000000..584a253b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/phototime2.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/phototime2_b.9.png b/TMessagesProj/src/main/res/drawable-mdpi/phototime2_b.9.png new file mode 100644 index 00000000..59f83e02 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/phototime2_b.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pl_back.png b/TMessagesProj/src/main/res/drawable-mdpi/pl_back.png new file mode 100644 index 00000000..6702c4be Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pl_back.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pl_next.png b/TMessagesProj/src/main/res/drawable-mdpi/pl_next.png new file mode 100644 index 00000000..08df043e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pl_next.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pl_next_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/pl_next_pressed.png new file mode 100644 index 00000000..fc645c14 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pl_next_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pl_pause.png b/TMessagesProj/src/main/res/drawable-mdpi/pl_pause.png new file mode 100644 index 00000000..1bf3d4ab Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pl_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pl_pause_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/pl_pause_pressed.png new file mode 100644 index 00000000..b8e61746 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pl_pause_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pl_play.png b/TMessagesProj/src/main/res/drawable-mdpi/pl_play.png new file mode 100644 index 00000000..31fce9bc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pl_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pl_play_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/pl_play_pressed.png new file mode 100644 index 00000000..d8ca3eb7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pl_play_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pl_previous.png b/TMessagesProj/src/main/res/drawable-mdpi/pl_previous.png new file mode 100644 index 00000000..1b52aca0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pl_previous.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pl_previous_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/pl_previous_pressed.png new file mode 100644 index 00000000..1b34ae6f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pl_previous_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pl_repeat.png b/TMessagesProj/src/main/res/drawable-mdpi/pl_repeat.png new file mode 100644 index 00000000..c62fb6c8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pl_repeat.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pl_repeat1_active.png b/TMessagesProj/src/main/res/drawable-mdpi/pl_repeat1_active.png new file mode 100644 index 00000000..0b1a4743 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pl_repeat1_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pl_repeat_active.png b/TMessagesProj/src/main/res/drawable-mdpi/pl_repeat_active.png new file mode 100644 index 00000000..140c797b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pl_repeat_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pl_shuffle.png b/TMessagesProj/src/main/res/drawable-mdpi/pl_shuffle.png new file mode 100644 index 00000000..c22ab8e3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pl_shuffle.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/pl_shuffle_active.png b/TMessagesProj/src/main/res/drawable-mdpi/pl_shuffle_active.png new file mode 100644 index 00000000..8e3888dd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/pl_shuffle_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/play_b.png b/TMessagesProj/src/main/res/drawable-mdpi/play_b.png new file mode 100644 index 00000000..247246ed Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/play_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/play_b_s.png b/TMessagesProj/src/main/res/drawable-mdpi/play_b_s.png new file mode 100644 index 00000000..c3e88682 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/play_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/play_g.png b/TMessagesProj/src/main/res/drawable-mdpi/play_g.png new file mode 100644 index 00000000..10f5caf0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/play_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/play_g_s.png b/TMessagesProj/src/main/res/drawable-mdpi/play_g_s.png new file mode 100644 index 00000000..761fa518 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/play_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/play_w.png b/TMessagesProj/src/main/res/drawable-mdpi/play_w.png deleted file mode 100644 index ca0df62f..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/play_w.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/play_w2.png b/TMessagesProj/src/main/res/drawable-mdpi/play_w2.png deleted file mode 100644 index 5fba3f1b..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/play_w2.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/play_w2_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/play_w2_pressed.png deleted file mode 100644 index 7b9fc05b..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/play_w2_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/play_w_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/play_w_pressed.png deleted file mode 100644 index b8b601b8..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/play_w_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/player.png b/TMessagesProj/src/main/res/drawable-mdpi/player.png new file mode 100644 index 00000000..1a26651c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/player.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/playvideo_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/playvideo_pressed.png new file mode 100644 index 00000000..5a361fe4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/playvideo_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/post_views.png b/TMessagesProj/src/main/res/drawable-mdpi/post_views.png new file mode 100644 index 00000000..7004aa51 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/post_views.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/post_views_s.png b/TMessagesProj/src/main/res/drawable-mdpi/post_views_s.png new file mode 100644 index 00000000..2ecc4809 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/post_views_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/post_views_w.png b/TMessagesProj/src/main/res/drawable-mdpi/post_views_w.png new file mode 100644 index 00000000..894d8cbb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/post_views_w.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/post_viewsg.png b/TMessagesProj/src/main/res/drawable-mdpi/post_viewsg.png new file mode 100644 index 00000000..f59e64f8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/post_viewsg.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/publish.png b/TMessagesProj/src/main/res/drawable-mdpi/publish.png new file mode 100644 index 00000000..4864c24d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/publish.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/publish_active.png b/TMessagesProj/src/main/res/drawable-mdpi/publish_active.png new file mode 100644 index 00000000..bd5ce853 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/publish_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/recorded.9.png b/TMessagesProj/src/main/res/drawable-mdpi/recorded.9.png new file mode 100644 index 00000000..efe1f2a7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/recorded.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/redcircle.png b/TMessagesProj/src/main/res/drawable-mdpi/redcircle.png new file mode 100644 index 00000000..da49308f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/redcircle.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/s_pause.png b/TMessagesProj/src/main/res/drawable-mdpi/s_pause.png new file mode 100644 index 00000000..6411c801 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/s_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/s_pause_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/s_pause_pressed.png new file mode 100644 index 00000000..40e04fc7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/s_pause_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/s_play.png b/TMessagesProj/src/main/res/drawable-mdpi/s_play.png new file mode 100644 index 00000000..3602a959 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/s_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/s_play_pressed.png b/TMessagesProj/src/main/res/drawable-mdpi/s_play_pressed.png new file mode 100644 index 00000000..f5a73508 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/s_play_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/search_down.png b/TMessagesProj/src/main/res/drawable-mdpi/search_down.png new file mode 100644 index 00000000..143e47d8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/search_down.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/search_share.png b/TMessagesProj/src/main/res/drawable-mdpi/search_share.png new file mode 100644 index 00000000..9e0e2da3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/search_share.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/search_up.png b/TMessagesProj/src/main/res/drawable-mdpi/search_up.png new file mode 100644 index 00000000..9c3d94a2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/search_up.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/share_arrow.png b/TMessagesProj/src/main/res/drawable-mdpi/share_arrow.png new file mode 100644 index 00000000..b42481c8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/share_arrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/share_round.png b/TMessagesProj/src/main/res/drawable-mdpi/share_round.png new file mode 100644 index 00000000..abdb1a8b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/share_round.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/sheet_shadow.9.png b/TMessagesProj/src/main/res/drawable-mdpi/sheet_shadow.9.png new file mode 100644 index 00000000..58be559f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/sheet_shadow.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/stickercounter.9.png b/TMessagesProj/src/main/res/drawable-mdpi/stickercounter.9.png new file mode 100644 index 00000000..217e9f16 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/stickercounter.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/system.9.png b/TMessagesProj/src/main/res/drawable-mdpi/system.9.png new file mode 100644 index 00000000..5ffd21af Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/system.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/system_black.9.png b/TMessagesProj/src/main/res/drawable-mdpi/system_black.9.png deleted file mode 100644 index fcb08a14..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/system_black.9.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/system_blue.9.png b/TMessagesProj/src/main/res/drawable-mdpi/system_blue.9.png deleted file mode 100644 index c1ce3b4f..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/system_blue.9.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/system_loader.png b/TMessagesProj/src/main/res/drawable-mdpi/system_loader.png new file mode 100644 index 00000000..79c6aab9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/system_loader.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/system_loader1.png b/TMessagesProj/src/main/res/drawable-mdpi/system_loader1.png deleted file mode 100644 index 35768859..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/system_loader1.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/system_loader2.png b/TMessagesProj/src/main/res/drawable-mdpi/system_loader2.png deleted file mode 100644 index 6c319058..00000000 Binary files a/TMessagesProj/src/main/res/drawable-mdpi/system_loader2.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tab_all.png b/TMessagesProj/src/main/res/drawable-mdpi/tab_all.png new file mode 100644 index 00000000..6b2d9710 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tab_all.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tab_bot.png b/TMessagesProj/src/main/res/drawable-mdpi/tab_bot.png new file mode 100644 index 00000000..32edca1e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tab_bot.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tab_channel.png b/TMessagesProj/src/main/res/drawable-mdpi/tab_channel.png new file mode 100644 index 00000000..ff619d43 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tab_channel.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tab_favs.png b/TMessagesProj/src/main/res/drawable-mdpi/tab_favs.png new file mode 100644 index 00000000..89b79c49 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tab_favs.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tab_group.png b/TMessagesProj/src/main/res/drawable-mdpi/tab_group.png new file mode 100644 index 00000000..3cc59fbe Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tab_group.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tab_supergroup.png b/TMessagesProj/src/main/res/drawable-mdpi/tab_supergroup.png new file mode 100644 index 00000000..4495cd86 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tab_supergroup.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tab_user.png b/TMessagesProj/src/main/res/drawable-mdpi/tab_user.png new file mode 100644 index 00000000..a78e7e6a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tab_user.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tip3.png b/TMessagesProj/src/main/res/drawable-mdpi/tip3.png new file mode 100644 index 00000000..db501192 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tip3.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tip4.png b/TMessagesProj/src/main/res/drawable-mdpi/tip4.png new file mode 100644 index 00000000..a73985ca Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tip4.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tool_cropfix.png b/TMessagesProj/src/main/res/drawable-mdpi/tool_cropfix.png new file mode 100644 index 00000000..af519d76 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tool_cropfix.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tool_curve.png b/TMessagesProj/src/main/res/drawable-mdpi/tool_curve.png new file mode 100644 index 00000000..58842bff Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tool_curve.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tool_fade.png b/TMessagesProj/src/main/res/drawable-mdpi/tool_fade.png new file mode 100644 index 00000000..ea4c1319 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tool_fade.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tool_rotate.png b/TMessagesProj/src/main/res/drawable-mdpi/tool_rotate.png new file mode 100644 index 00000000..e4ee283e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tool_rotate.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tool_tint.png b/TMessagesProj/src/main/res/drawable-mdpi/tool_tint.png new file mode 100644 index 00000000..d61b1774 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tool_tint.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/tooltip.9.png b/TMessagesProj/src/main/res/drawable-mdpi/tooltip.9.png new file mode 100644 index 00000000..a0d9bd35 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/tooltip.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-mdpi/video_actions.png b/TMessagesProj/src/main/res/drawable-mdpi/video_actions.png new file mode 100644 index 00000000..84aee2f5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-mdpi/video_actions.png differ diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector.xml deleted file mode 100644 index 1d5c6abe..00000000 --- a/TMessagesProj/src/main/res/drawable-v21/bar_selector.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector_blue.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector_blue.xml deleted file mode 100644 index 34512df8..00000000 --- a/TMessagesProj/src/main/res/drawable-v21/bar_selector_blue.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector_cyan.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector_cyan.xml deleted file mode 100644 index 64d8697d..00000000 --- a/TMessagesProj/src/main/res/drawable-v21/bar_selector_cyan.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector_green.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector_green.xml deleted file mode 100644 index 49c5a35e..00000000 --- a/TMessagesProj/src/main/res/drawable-v21/bar_selector_green.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector_mode.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector_mode.xml deleted file mode 100644 index 386d01ce..00000000 --- a/TMessagesProj/src/main/res/drawable-v21/bar_selector_mode.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector_orange.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector_orange.xml deleted file mode 100644 index 2d5c96c8..00000000 --- a/TMessagesProj/src/main/res/drawable-v21/bar_selector_orange.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector_picker.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector_picker.xml deleted file mode 100644 index 8c28f1d3..00000000 --- a/TMessagesProj/src/main/res/drawable-v21/bar_selector_picker.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector_pink.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector_pink.xml deleted file mode 100644 index 72f76405..00000000 --- a/TMessagesProj/src/main/res/drawable-v21/bar_selector_pink.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector_red.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector_red.xml deleted file mode 100644 index 4badd687..00000000 --- a/TMessagesProj/src/main/res/drawable-v21/bar_selector_red.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector_violet.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector_violet.xml deleted file mode 100644 index ee31ab7f..00000000 --- a/TMessagesProj/src/main/res/drawable-v21/bar_selector_violet.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable-v21/bar_selector_yellow.xml b/TMessagesProj/src/main/res/drawable-v21/bar_selector_yellow.xml deleted file mode 100644 index f0ee5a20..00000000 --- a/TMessagesProj/src/main/res/drawable-v21/bar_selector_yellow.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable-v21/list_selector_white.xml b/TMessagesProj/src/main/res/drawable-v21/list_selector_white.xml new file mode 100644 index 00000000..a7802617 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable-v21/list_selector_white.xml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/abc_ic_menu_share_mtrl_alpha.png b/TMessagesProj/src/main/res/drawable-xhdpi/abc_ic_menu_share_mtrl_alpha.png new file mode 100644 index 00000000..b57ee193 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/abc_ic_menu_share_mtrl_alpha.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/addcontact_blue.png b/TMessagesProj/src/main/res/drawable-xhdpi/addcontact_blue.png deleted file mode 100644 index 3ba0c9c3..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/addcontact_blue.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/admin_star.png b/TMessagesProj/src/main/res/drawable-xhdpi/admin_star.png new file mode 100644 index 00000000..370787e2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/admin_star.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/admin_star2.png b/TMessagesProj/src/main/res/drawable-xhdpi/admin_star2.png new file mode 100644 index 00000000..6afc194e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/admin_star2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/assign_manager.png b/TMessagesProj/src/main/res/drawable-xhdpi/assign_manager.png new file mode 100644 index 00000000..114615b1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/assign_manager.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_audio.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_audio.png new file mode 100644 index 00000000..eec77984 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_audio.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_audio_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_audio_pressed.png new file mode 100644 index 00000000..4d058f53 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_audio_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_camera.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_camera.png new file mode 100644 index 00000000..8a2056ec Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_camera.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_camera_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_camera_pressed.png new file mode 100644 index 00000000..ba0d8627 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_camera_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_contact.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_contact.png new file mode 100644 index 00000000..b81f418d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_contact.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_contact_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_contact_pressed.png new file mode 100644 index 00000000..bada4c26 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_contact_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_file.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_file.png new file mode 100644 index 00000000..ef152d00 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_file.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_file_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_file_pressed.png new file mode 100644 index 00000000..491efc19 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_file_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_gallery.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_gallery.png new file mode 100644 index 00000000..8c2fe674 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_gallery.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_gallery_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_gallery_pressed.png new file mode 100644 index 00000000..e9e73521 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_gallery_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_hide1.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_hide1.png new file mode 100644 index 00000000..1c0ab496 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_hide1.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_hide1_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_hide1_pressed.png new file mode 100644 index 00000000..1fabe1da Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_hide1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_hide2.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_hide2.png new file mode 100644 index 00000000..ef92c839 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_hide2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_location.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_location.png new file mode 100644 index 00000000..0294c218 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_location_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_location_pressed.png new file mode 100644 index 00000000..50e92b49 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_location_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_send1.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_send1.png new file mode 100644 index 00000000..69742eb4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_send1.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_send1_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_send1_pressed.png new file mode 100644 index 00000000..4a107c6b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_send1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_send2.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_send2.png new file mode 100644 index 00000000..be41c728 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_send2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_video.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_video.png new file mode 100644 index 00000000..f3182c9d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_video.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/attach_video_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/attach_video_pressed.png new file mode 100644 index 00000000..c932ef09 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/attach_video_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/audiosend_pause.png b/TMessagesProj/src/main/res/drawable-xhdpi/audiosend_pause.png new file mode 100644 index 00000000..8078779d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/audiosend_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/audiosend_play.png b/TMessagesProj/src/main/res/drawable-xhdpi/audiosend_play.png new file mode 100644 index 00000000..bfd90992 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/audiosend_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/blockpanel.png b/TMessagesProj/src/main/res/drawable-xhdpi/blockpanel.png new file mode 100644 index 00000000..0e3bb913 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/blockpanel.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bluecounter.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/bluecounter.9.png new file mode 100644 index 00000000..2087fd18 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/bluecounter.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_file.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_file.png new file mode 100644 index 00000000..2191a418 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/bot_file.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_info.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_info.png new file mode 100644 index 00000000..69c0388e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/bot_info.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard.png new file mode 100644 index 00000000..af078978 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard2.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard2.png new file mode 100644 index 00000000..6a672a79 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard_button.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard_button.9.png new file mode 100644 index 00000000..7f5fd2a7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard_button.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard_button_pressed.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard_button_pressed.9.png new file mode 100644 index 00000000..66fe8b30 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/bot_keyboard_button_pressed.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_lines.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_lines.png new file mode 100644 index 00000000..11980a89 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/bot_lines.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_link.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_link.png new file mode 100644 index 00000000..024405b3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/bot_link.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_list.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_list.png new file mode 100644 index 00000000..f8ed9caa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/bot_list.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_location.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_location.png new file mode 100644 index 00000000..f66cdbd7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/bot_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/bot_music.png b/TMessagesProj/src/main/res/drawable-xhdpi/bot_music.png new file mode 100644 index 00000000..e1aebb69 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/bot_music.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/cancel_b.png b/TMessagesProj/src/main/res/drawable-xhdpi/cancel_b.png deleted file mode 100644 index 36c6390e..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/cancel_b.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/cancel_b_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/cancel_b_pressed.png deleted file mode 100644 index 79f95172..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/cancel_b_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/cancel_g.png b/TMessagesProj/src/main/res/drawable-xhdpi/cancel_g.png deleted file mode 100644 index a77e504f..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/cancel_g.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/cancel_g_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/cancel_g_pressed.png deleted file mode 100644 index dea2364d..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/cancel_g_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/channelintro.png b/TMessagesProj/src/main/res/drawable-xhdpi/channelintro.png new file mode 100644 index 00000000..0d6febb7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/channelintro.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/check_list.png b/TMessagesProj/src/main/res/drawable-xhdpi/check_list.png new file mode 100644 index 00000000..7bc4bc30 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/check_list.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/check_profile.png b/TMessagesProj/src/main/res/drawable-xhdpi/check_profile.png new file mode 100644 index 00000000..36efe548 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/check_profile.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/contact_blue.png b/TMessagesProj/src/main/res/drawable-xhdpi/contact_blue.png new file mode 100644 index 00000000..0691158e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/contact_blue.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/contact_green.png b/TMessagesProj/src/main/res/drawable-xhdpi/contact_green.png new file mode 100644 index 00000000..d50586ac Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/contact_green.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/corner_in_bl.png b/TMessagesProj/src/main/res/drawable-xhdpi/corner_in_bl.png new file mode 100644 index 00000000..0620792f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/corner_in_bl.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/corner_in_br.png b/TMessagesProj/src/main/res/drawable-xhdpi/corner_in_br.png new file mode 100644 index 00000000..40e0bba7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/corner_in_br.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/corner_in_tl.png b/TMessagesProj/src/main/res/drawable-xhdpi/corner_in_tl.png new file mode 100644 index 00000000..7c75fa2c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/corner_in_tl.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/corner_in_tr.png b/TMessagesProj/src/main/res/drawable-xhdpi/corner_in_tr.png new file mode 100644 index 00000000..919358f8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/corner_in_tr.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/corner_out_bl.png b/TMessagesProj/src/main/res/drawable-xhdpi/corner_out_bl.png new file mode 100644 index 00000000..b286218b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/corner_out_bl.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/corner_out_br.png b/TMessagesProj/src/main/res/drawable-xhdpi/corner_out_br.png new file mode 100644 index 00000000..3e859e80 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/corner_out_br.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/corner_out_tl.png b/TMessagesProj/src/main/res/drawable-xhdpi/corner_out_tl.png new file mode 100644 index 00000000..84433cf5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/corner_out_tl.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/corner_out_tr.png b/TMessagesProj/src/main/res/drawable-xhdpi/corner_out_tr.png new file mode 100644 index 00000000..ba5b3c2d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/corner_out_tr.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_badge2.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_badge2.9.png new file mode 100644 index 00000000..6ddebe88 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_badge2.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_10.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_10.png new file mode 100644 index 00000000..7018bc7c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_11.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_11.png new file mode 100644 index 00000000..6a7a25da Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_12.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_12.png new file mode 100644 index 00000000..6738a349 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_2.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_2.png new file mode 100644 index 00000000..730dfecc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_3.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_3.png new file mode 100644 index 00000000..bae528cf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_4.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_4.png new file mode 100644 index 00000000..1974ba48 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_5.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_5.png new file mode 100644 index 00000000..182be455 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_6.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_6.png new file mode 100644 index 00000000..4c3db063 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_7.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_7.png new file mode 100644 index 00000000..3faf39fe Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_8.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_8.png new file mode 100644 index 00000000..1e4d8b94 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_9.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_9.png new file mode 100644 index 00000000..51386128 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_check_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_10.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_10.png new file mode 100644 index 00000000..1e4d8b94 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_11.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_11.png new file mode 100644 index 00000000..fbdf0fdc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_12.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_12.png new file mode 100644 index 00000000..8842f9e7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_2.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_2.png new file mode 100644 index 00000000..730dfecc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_3.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_3.png new file mode 100644 index 00000000..bae528cf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_4.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_4.png new file mode 100644 index 00000000..37be4e47 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_5.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_5.png new file mode 100644 index 00000000..72deaaa5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_6.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_6.png new file mode 100644 index 00000000..f73d9391 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_7.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_7.png new file mode 100644 index 00000000..621291e0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_8.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_8.png new file mode 100644 index 00000000..1e4d8b94 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_9.png b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_9.png new file mode 100644 index 00000000..959f2e02 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/dialogs_halfcheck_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/doc_actions_b_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/doc_actions_b_s.png new file mode 100644 index 00000000..ac076eff Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/doc_actions_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/doc_blue_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/doc_blue_s.png new file mode 100644 index 00000000..ae8dcf51 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/doc_blue_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/doccancel_b_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/doccancel_b_s.png new file mode 100644 index 00000000..c157d854 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/doccancel_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/docload_b_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/docload_b_s.png new file mode 100644 index 00000000..13fbdb3d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/docload_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/docpause_b_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/docpause_b_s.png new file mode 100644 index 00000000..98445c9a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/docpause_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/download_b.png b/TMessagesProj/src/main/res/drawable-xhdpi/download_b.png deleted file mode 100644 index 5d114b08..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/download_b.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/download_b_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/download_b_pressed.png deleted file mode 100644 index 671f591b..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/download_b_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/download_g.png b/TMessagesProj/src/main/res/drawable-xhdpi/download_g.png deleted file mode 100644 index 1eaf6cfc..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/download_g.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/download_g_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/download_g_pressed.png deleted file mode 100644 index 4d785fbb..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/download_g_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/file_b.png b/TMessagesProj/src/main/res/drawable-xhdpi/file_b.png new file mode 100644 index 00000000..85c47ecf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/file_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/file_b_cancel.png b/TMessagesProj/src/main/res/drawable-xhdpi/file_b_cancel.png new file mode 100644 index 00000000..ed4c2381 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/file_b_cancel.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/file_b_cancel_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/file_b_cancel_s.png new file mode 100644 index 00000000..0efa019d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/file_b_cancel_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/file_b_load.png b/TMessagesProj/src/main/res/drawable-xhdpi/file_b_load.png new file mode 100644 index 00000000..f9412a04 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/file_b_load.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/file_b_load_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/file_b_load_s.png new file mode 100644 index 00000000..50cc62b0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/file_b_load_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/file_b_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/file_b_s.png new file mode 100644 index 00000000..da8180c0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/file_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/file_g.png b/TMessagesProj/src/main/res/drawable-xhdpi/file_g.png new file mode 100644 index 00000000..7b1911ab Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/file_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/file_g_cancel.png b/TMessagesProj/src/main/res/drawable-xhdpi/file_g_cancel.png new file mode 100644 index 00000000..376d89f6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/file_g_cancel.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/file_g_cancel_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/file_g_cancel_s.png new file mode 100644 index 00000000..4a8e785f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/file_g_cancel_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/file_g_load.png b/TMessagesProj/src/main/res/drawable-xhdpi/file_g_load.png new file mode 100644 index 00000000..8ef2faff Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/file_g_load.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/file_g_load_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/file_g_load_s.png new file mode 100644 index 00000000..6eb2518e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/file_g_load_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/file_g_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/file_g_s.png new file mode 100644 index 00000000..aaae696a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/file_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/ic_action_next.png b/TMessagesProj/src/main/res/drawable-xhdpi/ic_action_next.png new file mode 100644 index 00000000..f282b924 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/ic_action_next.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/ic_action_pause.png b/TMessagesProj/src/main/res/drawable-xhdpi/ic_action_pause.png new file mode 100644 index 00000000..72dfa9fa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/ic_action_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/ic_action_play.png b/TMessagesProj/src/main/res/drawable-xhdpi/ic_action_play.png new file mode 100644 index 00000000..043acd80 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/ic_action_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/ic_action_previous.png b/TMessagesProj/src/main/res/drawable-xhdpi/ic_action_previous.png new file mode 100644 index 00000000..2522877d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/ic_action_previous.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/ic_create.png b/TMessagesProj/src/main/res/drawable-xhdpi/ic_create.png new file mode 100644 index 00000000..27579452 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/ic_create.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/ic_fp_40px.png b/TMessagesProj/src/main/res/drawable-xhdpi/ic_fp_40px.png new file mode 100644 index 00000000..e1c9590b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/ic_fp_40px.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/ic_launcher_beta.png b/TMessagesProj/src/main/res/drawable-xhdpi/ic_launcher_beta.png new file mode 100644 index 00000000..1be48bf1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/ic_launcher_beta.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/ic_settings.png b/TMessagesProj/src/main/res/drawable-xhdpi/ic_settings.png new file mode 100644 index 00000000..c2d1c30b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/ic_settings.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/ic_smiles_gif.png b/TMessagesProj/src/main/res/drawable-xhdpi/ic_smiles_gif.png new file mode 100644 index 00000000..1feede31 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/ic_smiles_gif.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/igvideo.png b/TMessagesProj/src/main/res/drawable-xhdpi/igvideo.png deleted file mode 100644 index bad39364..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/igvideo.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/list_circle.png b/TMessagesProj/src/main/res/drawable-xhdpi/list_circle.png new file mode 100644 index 00000000..73433f90 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/list_circle.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/list_supergroup.png b/TMessagesProj/src/main/res/drawable-xhdpi/list_supergroup.png new file mode 100644 index 00000000..f0e09776 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/list_supergroup.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/location2.png b/TMessagesProj/src/main/res/drawable-xhdpi/location2.png new file mode 100644 index 00000000..ade7b9ef Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/location2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/logo_avatar.png b/TMessagesProj/src/main/res/drawable-xhdpi/logo_avatar.png new file mode 100644 index 00000000..10c2dc9a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/logo_avatar.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/managers.png b/TMessagesProj/src/main/res/drawable-xhdpi/managers.png new file mode 100644 index 00000000..cdcbc9ba Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/managers.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_admin.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_admin.png new file mode 100644 index 00000000..f4e79ff4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_admin.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_plus.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_plus.png new file mode 100644 index 00000000..27c74af9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_plus.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/menu_themes.png b/TMessagesProj/src/main/res/drawable-xhdpi/menu_themes.png new file mode 100644 index 00000000..ceceef5b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/menu_themes.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/miniplayer_close.png b/TMessagesProj/src/main/res/drawable-xhdpi/miniplayer_close.png new file mode 100644 index 00000000..07d83314 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/miniplayer_close.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/miniplayer_pause.png b/TMessagesProj/src/main/res/drawable-xhdpi/miniplayer_pause.png new file mode 100644 index 00000000..556aec50 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/miniplayer_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/miniplayer_play.png b/TMessagesProj/src/main/res/drawable-xhdpi/miniplayer_play.png new file mode 100644 index 00000000..fd6c00ec Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/miniplayer_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_10.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_10.png new file mode 100644 index 00000000..c6b957de Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_11.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_11.png new file mode 100644 index 00000000..d61620ef Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_12.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_12.png new file mode 100644 index 00000000..a5a294c0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_2.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_2.png new file mode 100644 index 00000000..5731295c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_3.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_3.png new file mode 100644 index 00000000..87ca9c97 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_4.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_4.png new file mode 100644 index 00000000..5593c59a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_5.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_5.png new file mode 100644 index 00000000..8ace0557 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_6.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_6.png new file mode 100644 index 00000000..2da3d8b5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_7.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_7.png new file mode 100644 index 00000000..c8a831f8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_8.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_8.png new file mode 100644 index 00000000..ca5b122b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_9.png new file mode 100644 index 00000000..52cea1dc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_10.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_10.png new file mode 100644 index 00000000..0b4c3774 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_11.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_11.png new file mode 100644 index 00000000..f82c99ce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_12.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_12.png new file mode 100644 index 00000000..cb42bc2b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_2.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_2.png new file mode 100644 index 00000000..3be28fff Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_3.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_3.png new file mode 100644 index 00000000..080f1c28 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_4.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_4.png new file mode 100644 index 00000000..ed74800e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_5.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_5.png new file mode 100644 index 00000000..b921904a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_6.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_6.png new file mode 100644 index 00000000..3e0c12d9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_7.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_7.png new file mode 100644 index 00000000..13478019 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_8.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_8.png new file mode 100644 index 00000000..42a26425 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_9.png new file mode 100644 index 00000000..32a179bb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_check_w_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_clock2.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_clock2.png new file mode 100644 index 00000000..334d7aa0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_clock2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_clock2_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_clock2_s.png new file mode 100644 index 00000000..f2303b7c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_clock2_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_10.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_10.png new file mode 100644 index 00000000..ca5b122b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_11.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_11.png new file mode 100644 index 00000000..bd01dc5a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_12.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_12.png new file mode 100644 index 00000000..1ec4b915 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_2.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_2.png new file mode 100644 index 00000000..5731295c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_3.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_3.png new file mode 100644 index 00000000..87ca9c97 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_4.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_4.png new file mode 100644 index 00000000..d8bebefb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_5.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_5.png new file mode 100644 index 00000000..facd83a6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_6.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_6.png new file mode 100644 index 00000000..9a8d3a5c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_7.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_7.png new file mode 100644 index 00000000..20d5d290 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_8.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_8.png new file mode 100644 index 00000000..ca5b122b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_9.png new file mode 100644 index 00000000..521d3cd7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_10.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_10.png new file mode 100644 index 00000000..7324946d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_11.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_11.png new file mode 100644 index 00000000..05883730 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_12.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_12.png new file mode 100644 index 00000000..b7f9b31b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_2.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_2.png new file mode 100644 index 00000000..3be28fff Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_3.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_3.png new file mode 100644 index 00000000..080f1c28 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_4.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_4.png new file mode 100644 index 00000000..2e53da18 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_5.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_5.png new file mode 100644 index 00000000..ba9ac44a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_6.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_6.png new file mode 100644 index 00000000..fc8b52f3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_7.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_7.png new file mode 100644 index 00000000..c78ccdb5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_8.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_8.png new file mode 100644 index 00000000..42a26425 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_9.png new file mode 100644 index 00000000..803e97fb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_halfcheck_w_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5.9.png new file mode 100644 index 00000000..722bdb11 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5_photo.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5_photo.9.png new file mode 100644 index 00000000..248b9ba2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5_photo_selected.9.png new file mode 100644 index 00000000..91dabc47 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5_selected.9.png new file mode 100644 index 00000000..97109c72 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_5_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6.9.png new file mode 100644 index 00000000..296a1a41 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6_photo.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6_photo.9.png new file mode 100644 index 00000000..6e0374c5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6_photo_selected.9.png new file mode 100644 index 00000000..ddbbf10d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6_selected.9.png new file mode 100644 index 00000000..787e3951 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_6_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7.9.png new file mode 100644 index 00000000..33ad477a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7_photo.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7_photo.9.png new file mode 100644 index 00000000..248b9ba2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7_photo_selected.9.png new file mode 100644 index 00000000..91dabc47 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7_selected.9.png new file mode 100644 index 00000000..24c17aaf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_7_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8.9.png new file mode 100644 index 00000000..f5db8372 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8_photo.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8_photo.9.png new file mode 100644 index 00000000..248b9ba2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8_photo_selected.9.png new file mode 100644 index 00000000..91dabc47 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8_selected.9.png new file mode 100644 index 00000000..e61ca03b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_in_8_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5.9.png new file mode 100644 index 00000000..d65c338c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5_photo.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5_photo.9.png new file mode 100644 index 00000000..c452372f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5_photo_selected.9.png new file mode 100644 index 00000000..faa2daa5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5_selected.9.png new file mode 100644 index 00000000..529406e7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_5_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6.9.png new file mode 100644 index 00000000..98af3bb4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6_photo.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6_photo.9.png new file mode 100644 index 00000000..1a25cd63 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6_photo_selected.9.png new file mode 100644 index 00000000..323fb498 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6_selected.9.png new file mode 100644 index 00000000..8d907d9b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_6_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7.9.png new file mode 100644 index 00000000..828fb7c7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7_photo.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7_photo.9.png new file mode 100644 index 00000000..c452372f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7_photo_selected.9.png new file mode 100644 index 00000000..faa2daa5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7_selected.9.png new file mode 100644 index 00000000..2861ba33 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_7_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8.9.png new file mode 100644 index 00000000..d7c2816f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8_photo.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8_photo.9.png new file mode 100644 index 00000000..c452372f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8_photo_selected.9.png new file mode 100644 index 00000000..faa2daa5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8_selected.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8_selected.9.png new file mode 100644 index 00000000..65e00a86 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/msg_out_8_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/nocover.png b/TMessagesProj/src/main/res/drawable-xhdpi/nocover.png new file mode 100644 index 00000000..0e916f37 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/nocover.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/nocover_big.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/nocover_big.9.png new file mode 100644 index 00000000..7026a671 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/nocover_big.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/nocover_small.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/nocover_small.9.png new file mode 100644 index 00000000..5e135bde Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/nocover_small.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/notify_members_off.png b/TMessagesProj/src/main/res/drawable-xhdpi/notify_members_off.png new file mode 100644 index 00000000..7fcaef92 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/notify_members_off.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/notify_members_on.png b/TMessagesProj/src/main/res/drawable-xhdpi/notify_members_on.png new file mode 100644 index 00000000..74270aae Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/notify_members_on.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pause_b_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/pause_b_pressed.png deleted file mode 100644 index ab048657..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/pause_b_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pause_b_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/pause_b_s.png new file mode 100644 index 00000000..6c796c01 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pause_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pause_g_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/pause_g_pressed.png deleted file mode 100644 index c6d72f73..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/pause_g_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pause_g_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/pause_g_s.png new file mode 100644 index 00000000..a7bb4434 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pause_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pause_w.png b/TMessagesProj/src/main/res/drawable-xhdpi/pause_w.png deleted file mode 100644 index 9228d6e5..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/pause_w.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pause_w2.png b/TMessagesProj/src/main/res/drawable-xhdpi/pause_w2.png deleted file mode 100644 index bcb65abf..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/pause_w2.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pause_w2_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/pause_w2_pressed.png deleted file mode 100644 index 7b7e3907..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/pause_w2_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pause_w_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/pause_w_pressed.png deleted file mode 100644 index 214572b3..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/pause_w_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/phone_activate.png b/TMessagesProj/src/main/res/drawable-xhdpi/phone_activate.png new file mode 100644 index 00000000..f97ecc3b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/phone_activate.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_b.png b/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_b.png new file mode 100644 index 00000000..7fef9dc1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_b_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_b_s.png new file mode 100644 index 00000000..81fcc3a9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_g.png b/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_g.png new file mode 100644 index 00000000..e61452ac Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_g_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_g_s.png new file mode 100644 index 00000000..6600032f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_pressed.png new file mode 100644 index 00000000..99ff3c7e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/photocancel_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/photogif_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/photogif_pressed.png new file mode 100644 index 00000000..4c903256 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/photogif_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/photoload_b.png b/TMessagesProj/src/main/res/drawable-xhdpi/photoload_b.png new file mode 100644 index 00000000..08d8ba1e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/photoload_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/photoload_b_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/photoload_b_s.png new file mode 100644 index 00000000..9b860d1e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/photoload_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/photoload_g.png b/TMessagesProj/src/main/res/drawable-xhdpi/photoload_g.png new file mode 100644 index 00000000..9ffbdfdd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/photoload_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/photoload_g_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/photoload_g_s.png new file mode 100644 index 00000000..c22b11e8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/photoload_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/photoload_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/photoload_pressed.png new file mode 100644 index 00000000..3fc49d39 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/photoload_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/photopause.png b/TMessagesProj/src/main/res/drawable-xhdpi/photopause.png deleted file mode 100644 index 8c6463d6..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/photopause.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/phototime2.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/phototime2.9.png new file mode 100644 index 00000000..8ccee471 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/phototime2.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/phototime2_b.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/phototime2_b.9.png new file mode 100644 index 00000000..504d8397 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/phototime2_b.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pl_back.png b/TMessagesProj/src/main/res/drawable-xhdpi/pl_back.png new file mode 100644 index 00000000..5be0d0c9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pl_back.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pl_next.png b/TMessagesProj/src/main/res/drawable-xhdpi/pl_next.png new file mode 100644 index 00000000..a9b7bb55 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pl_next.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pl_next_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/pl_next_pressed.png new file mode 100644 index 00000000..adfa9150 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pl_next_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pl_pause.png b/TMessagesProj/src/main/res/drawable-xhdpi/pl_pause.png new file mode 100644 index 00000000..88901a49 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pl_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pl_pause_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/pl_pause_pressed.png new file mode 100644 index 00000000..95d5b122 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pl_pause_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pl_play.png b/TMessagesProj/src/main/res/drawable-xhdpi/pl_play.png new file mode 100644 index 00000000..337bf8a3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pl_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pl_play_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/pl_play_pressed.png new file mode 100644 index 00000000..adc3c6fe Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pl_play_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pl_previous.png b/TMessagesProj/src/main/res/drawable-xhdpi/pl_previous.png new file mode 100644 index 00000000..1dbd201b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pl_previous.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pl_previous_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/pl_previous_pressed.png new file mode 100644 index 00000000..6979d0dd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pl_previous_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pl_repeat.png b/TMessagesProj/src/main/res/drawable-xhdpi/pl_repeat.png new file mode 100644 index 00000000..f0ebf498 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pl_repeat.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pl_repeat1_active.png b/TMessagesProj/src/main/res/drawable-xhdpi/pl_repeat1_active.png new file mode 100644 index 00000000..9b37d2dd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pl_repeat1_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pl_repeat_active.png b/TMessagesProj/src/main/res/drawable-xhdpi/pl_repeat_active.png new file mode 100644 index 00000000..da9e63bc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pl_repeat_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pl_shuffle.png b/TMessagesProj/src/main/res/drawable-xhdpi/pl_shuffle.png new file mode 100644 index 00000000..00293fad Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pl_shuffle.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/pl_shuffle_active.png b/TMessagesProj/src/main/res/drawable-xhdpi/pl_shuffle_active.png new file mode 100644 index 00000000..1cba5d2f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/pl_shuffle_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/play_b.png b/TMessagesProj/src/main/res/drawable-xhdpi/play_b.png new file mode 100644 index 00000000..c2f1803c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/play_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/play_b_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/play_b_s.png new file mode 100644 index 00000000..9ab9ba84 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/play_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/play_g.png b/TMessagesProj/src/main/res/drawable-xhdpi/play_g.png new file mode 100644 index 00000000..6c442666 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/play_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/play_g_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/play_g_s.png new file mode 100644 index 00000000..95b40bc0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/play_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/play_w.png b/TMessagesProj/src/main/res/drawable-xhdpi/play_w.png deleted file mode 100644 index 77d1a292..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/play_w.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/play_w2.png b/TMessagesProj/src/main/res/drawable-xhdpi/play_w2.png deleted file mode 100644 index 580da833..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/play_w2.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/play_w2_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/play_w2_pressed.png deleted file mode 100644 index 9bdc7f20..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/play_w2_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/play_w_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/play_w_pressed.png deleted file mode 100644 index 11b12a54..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/play_w_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/player.png b/TMessagesProj/src/main/res/drawable-xhdpi/player.png new file mode 100644 index 00000000..c236f57a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/player.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/playvideo_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/playvideo_pressed.png new file mode 100644 index 00000000..1f3374c2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/playvideo_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/post_views.png b/TMessagesProj/src/main/res/drawable-xhdpi/post_views.png new file mode 100644 index 00000000..9cf0d5bd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/post_views.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/post_views_s.png b/TMessagesProj/src/main/res/drawable-xhdpi/post_views_s.png new file mode 100644 index 00000000..87af7233 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/post_views_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/post_views_w.png b/TMessagesProj/src/main/res/drawable-xhdpi/post_views_w.png new file mode 100644 index 00000000..2de06dd7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/post_views_w.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/post_viewsg.png b/TMessagesProj/src/main/res/drawable-xhdpi/post_viewsg.png new file mode 100644 index 00000000..fc3764cc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/post_viewsg.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/publish.png b/TMessagesProj/src/main/res/drawable-xhdpi/publish.png new file mode 100644 index 00000000..e48445bc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/publish.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/publish_active.png b/TMessagesProj/src/main/res/drawable-xhdpi/publish_active.png new file mode 100644 index 00000000..d2737527 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/publish_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/recorded.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/recorded.9.png new file mode 100644 index 00000000..af215a34 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/recorded.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/redcircle.png b/TMessagesProj/src/main/res/drawable-xhdpi/redcircle.png new file mode 100644 index 00000000..0b972367 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/redcircle.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/s_pause.png b/TMessagesProj/src/main/res/drawable-xhdpi/s_pause.png new file mode 100644 index 00000000..980cb0d4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/s_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/s_pause_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/s_pause_pressed.png new file mode 100644 index 00000000..83e9e820 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/s_pause_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/s_play.png b/TMessagesProj/src/main/res/drawable-xhdpi/s_play.png new file mode 100644 index 00000000..2d98d4cc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/s_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/s_play_pressed.png b/TMessagesProj/src/main/res/drawable-xhdpi/s_play_pressed.png new file mode 100644 index 00000000..f0993b74 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/s_play_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/search_down.png b/TMessagesProj/src/main/res/drawable-xhdpi/search_down.png new file mode 100644 index 00000000..2b8bd80c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/search_down.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/search_share.png b/TMessagesProj/src/main/res/drawable-xhdpi/search_share.png new file mode 100644 index 00000000..c8c15c21 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/search_share.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/search_up.png b/TMessagesProj/src/main/res/drawable-xhdpi/search_up.png new file mode 100644 index 00000000..a212e27c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/search_up.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/share_arrow.png b/TMessagesProj/src/main/res/drawable-xhdpi/share_arrow.png new file mode 100644 index 00000000..f77b129c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/share_arrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/share_round.png b/TMessagesProj/src/main/res/drawable-xhdpi/share_round.png new file mode 100644 index 00000000..78cf5a52 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/share_round.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/sheet_shadow.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/sheet_shadow.9.png new file mode 100644 index 00000000..171a4d54 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/sheet_shadow.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/stickercounter.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/stickercounter.9.png new file mode 100644 index 00000000..7f1f17fb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/stickercounter.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/system.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/system.9.png new file mode 100644 index 00000000..2d50ef79 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/system.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/system_black.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/system_black.9.png deleted file mode 100644 index b9df0b89..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/system_black.9.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/system_blue.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/system_blue.9.png deleted file mode 100644 index 68c39841..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/system_blue.9.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/system_loader.png b/TMessagesProj/src/main/res/drawable-xhdpi/system_loader.png new file mode 100644 index 00000000..fe0a9e49 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/system_loader.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/system_loader1.png b/TMessagesProj/src/main/res/drawable-xhdpi/system_loader1.png deleted file mode 100644 index 37bef2be..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/system_loader1.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/system_loader2.png b/TMessagesProj/src/main/res/drawable-xhdpi/system_loader2.png deleted file mode 100644 index 5bb6c3b1..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xhdpi/system_loader2.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tab_all.png b/TMessagesProj/src/main/res/drawable-xhdpi/tab_all.png new file mode 100644 index 00000000..a8e6b133 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tab_all.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tab_bot.png b/TMessagesProj/src/main/res/drawable-xhdpi/tab_bot.png new file mode 100644 index 00000000..8708650e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tab_bot.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tab_channel.png b/TMessagesProj/src/main/res/drawable-xhdpi/tab_channel.png new file mode 100644 index 00000000..1a2a61a0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tab_channel.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tab_favs.png b/TMessagesProj/src/main/res/drawable-xhdpi/tab_favs.png new file mode 100644 index 00000000..037adfc6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tab_favs.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tab_group.png b/TMessagesProj/src/main/res/drawable-xhdpi/tab_group.png new file mode 100644 index 00000000..4258728f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tab_group.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tab_supergroup.png b/TMessagesProj/src/main/res/drawable-xhdpi/tab_supergroup.png new file mode 100644 index 00000000..2fd5e872 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tab_supergroup.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tab_user.png b/TMessagesProj/src/main/res/drawable-xhdpi/tab_user.png new file mode 100644 index 00000000..738e3490 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tab_user.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tip3.png b/TMessagesProj/src/main/res/drawable-xhdpi/tip3.png new file mode 100644 index 00000000..4f128e89 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tip3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tip4.png b/TMessagesProj/src/main/res/drawable-xhdpi/tip4.png new file mode 100644 index 00000000..e27f791d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tip4.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tool_cropfix.png b/TMessagesProj/src/main/res/drawable-xhdpi/tool_cropfix.png new file mode 100644 index 00000000..6cfea5aa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tool_cropfix.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tool_curve.png b/TMessagesProj/src/main/res/drawable-xhdpi/tool_curve.png new file mode 100644 index 00000000..9113acad Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tool_curve.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tool_fade.png b/TMessagesProj/src/main/res/drawable-xhdpi/tool_fade.png new file mode 100644 index 00000000..56d76ece Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tool_fade.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tool_rotate.png b/TMessagesProj/src/main/res/drawable-xhdpi/tool_rotate.png new file mode 100644 index 00000000..b47bd668 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tool_rotate.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tool_tint.png b/TMessagesProj/src/main/res/drawable-xhdpi/tool_tint.png new file mode 100644 index 00000000..8419721d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tool_tint.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/tooltip.9.png b/TMessagesProj/src/main/res/drawable-xhdpi/tooltip.9.png new file mode 100644 index 00000000..ab5eb807 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/tooltip.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xhdpi/video_actions.png b/TMessagesProj/src/main/res/drawable-xhdpi/video_actions.png new file mode 100644 index 00000000..f692c300 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xhdpi/video_actions.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/Thumbs.db b/TMessagesProj/src/main/res/drawable-xxhdpi/Thumbs.db deleted file mode 100644 index fa5f56fd..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/Thumbs.db and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/abc_ic_menu_share_mtrl_alpha.png b/TMessagesProj/src/main/res/drawable-xxhdpi/abc_ic_menu_share_mtrl_alpha.png new file mode 100644 index 00000000..a1866ba4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/abc_ic_menu_share_mtrl_alpha.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/addcontact_blue.png b/TMessagesProj/src/main/res/drawable-xxhdpi/addcontact_blue.png deleted file mode 100644 index a592549b..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/addcontact_blue.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/addcontact_green.png b/TMessagesProj/src/main/res/drawable-xxhdpi/addcontact_green.png deleted file mode 100644 index fd4bada3..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/addcontact_green.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/admin_star.png b/TMessagesProj/src/main/res/drawable-xxhdpi/admin_star.png new file mode 100644 index 00000000..8724c05b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/admin_star.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/admin_star2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/admin_star2.png new file mode 100644 index 00000000..6dac9318 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/admin_star2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/assign_manager.png b/TMessagesProj/src/main/res/drawable-xxhdpi/assign_manager.png new file mode 100644 index 00000000..fcad7d9e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/assign_manager.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_audio.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_audio.png new file mode 100644 index 00000000..e6383e09 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_audio.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_audio_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_audio_pressed.png new file mode 100644 index 00000000..28f865b7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_audio_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_camera.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_camera.png new file mode 100644 index 00000000..824b9f6e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_camera.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_camera_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_camera_pressed.png new file mode 100644 index 00000000..b9e2a008 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_camera_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_contact.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_contact.png new file mode 100644 index 00000000..71f9be5b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_contact.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_contact_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_contact_pressed.png new file mode 100644 index 00000000..d8824727 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_contact_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_file.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_file.png new file mode 100644 index 00000000..50294ed7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_file.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_file_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_file_pressed.png new file mode 100644 index 00000000..ff36de72 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_file_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_gallery.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_gallery.png new file mode 100644 index 00000000..7aaa8baa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_gallery.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_gallery_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_gallery_pressed.png new file mode 100644 index 00000000..7ae2a56a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_gallery_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_hide1.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_hide1.png new file mode 100644 index 00000000..a00c94db Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_hide1.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_hide1_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_hide1_pressed.png new file mode 100644 index 00000000..4e3cc02a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_hide1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_hide2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_hide2.png new file mode 100644 index 00000000..28b2e4b1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_hide2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_location.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_location.png new file mode 100644 index 00000000..13ba2eaa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_location_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_location_pressed.png new file mode 100644 index 00000000..cfa436dd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_location_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_send1.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_send1.png new file mode 100644 index 00000000..91ebc55d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_send1.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_send1_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_send1_pressed.png new file mode 100644 index 00000000..750e47fc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_send1_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_send2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_send2.png new file mode 100644 index 00000000..d7f0a3d0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_send2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_video.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_video.png new file mode 100644 index 00000000..0572bb47 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_video.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/attach_video_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_video_pressed.png new file mode 100644 index 00000000..edee8cc9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/attach_video_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/audiosend_pause.png b/TMessagesProj/src/main/res/drawable-xxhdpi/audiosend_pause.png new file mode 100644 index 00000000..6a227efc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/audiosend_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/audiosend_play.png b/TMessagesProj/src/main/res/drawable-xxhdpi/audiosend_play.png new file mode 100644 index 00000000..40478b91 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/audiosend_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/blockpanel.png b/TMessagesProj/src/main/res/drawable-xxhdpi/blockpanel.png new file mode 100644 index 00000000..cad6be16 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/blockpanel.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bluecounter.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bluecounter.9.png new file mode 100644 index 00000000..113537b7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/bluecounter.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_file.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_file.png new file mode 100644 index 00000000..3fdbe990 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_file.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_info.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_info.png new file mode 100644 index 00000000..c620bbaf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_info.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard.png new file mode 100644 index 00000000..67b0fa4d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard2.png new file mode 100644 index 00000000..b75abe5c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard_button.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard_button.9.png new file mode 100644 index 00000000..58fccc6e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard_button.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard_button_pressed.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard_button_pressed.9.png new file mode 100644 index 00000000..dba2a36b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_keyboard_button_pressed.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_lines.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_lines.png new file mode 100644 index 00000000..e5d26151 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_lines.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_link.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_link.png new file mode 100644 index 00000000..411dc89d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_link.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_list.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_list.png new file mode 100644 index 00000000..3391bb61 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_list.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_location.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_location.png new file mode 100644 index 00000000..6c75f1de Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_location.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/bot_music.png b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_music.png new file mode 100644 index 00000000..16bf5bc9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/bot_music.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/cancel_b.png b/TMessagesProj/src/main/res/drawable-xxhdpi/cancel_b.png deleted file mode 100644 index 2fa1d0c1..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/cancel_b.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/cancel_b_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/cancel_b_pressed.png deleted file mode 100644 index 8f3b4c08..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/cancel_b_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/cancel_g.png b/TMessagesProj/src/main/res/drawable-xxhdpi/cancel_g.png deleted file mode 100644 index 34c23a83..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/cancel_g.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/cancel_g_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/cancel_g_pressed.png deleted file mode 100644 index a8585f32..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/cancel_g_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/channelintro.png b/TMessagesProj/src/main/res/drawable-xxhdpi/channelintro.png new file mode 100644 index 00000000..22d7c01c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/channelintro.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/check_list.png b/TMessagesProj/src/main/res/drawable-xxhdpi/check_list.png new file mode 100644 index 00000000..fd5a56b4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/check_list.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/check_profile.png b/TMessagesProj/src/main/res/drawable-xxhdpi/check_profile.png new file mode 100644 index 00000000..30bfdb48 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/check_profile.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/contact_blue.png b/TMessagesProj/src/main/res/drawable-xxhdpi/contact_blue.png new file mode 100644 index 00000000..aa2f30e3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/contact_blue.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/contact_green.png b/TMessagesProj/src/main/res/drawable-xxhdpi/contact_green.png new file mode 100644 index 00000000..1fb42bf4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/contact_green.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_bl.png b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_bl.png new file mode 100644 index 00000000..feb15efe Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_bl.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_br.png b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_br.png new file mode 100644 index 00000000..fa742b3b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_br.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_tl.png b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_tl.png new file mode 100644 index 00000000..5db9f5ce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_tl.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_tr.png b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_tr.png new file mode 100644 index 00000000..a2c058a0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_in_tr.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_bl.png b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_bl.png new file mode 100644 index 00000000..64b85cc3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_bl.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_br.png b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_br.png new file mode 100644 index 00000000..50ae092c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_br.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_tl.png b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_tl.png new file mode 100644 index 00000000..1e3f529e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_tl.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_tr.png b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_tr.png new file mode 100644 index 00000000..8b7f95fe Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/corner_out_tr.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_badge2.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_badge2.9.png new file mode 100644 index 00000000..7facfe30 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_badge2.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_10.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_10.png new file mode 100644 index 00000000..29e57eed Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_11.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_11.png new file mode 100644 index 00000000..2a7bd52a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_12.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_12.png new file mode 100644 index 00000000..55b6bbf2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_2.png new file mode 100644 index 00000000..bf63c915 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_3.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_3.png new file mode 100644 index 00000000..00f7237a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_4.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_4.png new file mode 100644 index 00000000..7f239afb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_5.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_5.png new file mode 100644 index 00000000..8c86e128 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_6.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_6.png new file mode 100644 index 00000000..d151dbea Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_7.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_7.png new file mode 100644 index 00000000..42599e90 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_8.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_8.png new file mode 100644 index 00000000..cf6322c6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_9.png new file mode 100644 index 00000000..0cef03b9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_check_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_10.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_10.png new file mode 100644 index 00000000..cf6322c6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_11.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_11.png new file mode 100644 index 00000000..571c6834 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_12.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_12.png new file mode 100644 index 00000000..15d5ee71 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_2.png new file mode 100644 index 00000000..a9482f53 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_3.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_3.png new file mode 100644 index 00000000..2914e3a4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_4.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_4.png new file mode 100644 index 00000000..10ebec6c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_5.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_5.png new file mode 100644 index 00000000..2b21705c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_6.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_6.png new file mode 100644 index 00000000..fbfd4ac4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_7.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_7.png new file mode 100644 index 00000000..ad69bc41 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_8.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_8.png new file mode 100644 index 00000000..cf6322c6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_9.png new file mode 100644 index 00000000..e470bf42 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/dialogs_halfcheck_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/doc_actions_b_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/doc_actions_b_s.png new file mode 100644 index 00000000..34f1206f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/doc_actions_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/doc_blue_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/doc_blue_s.png new file mode 100644 index 00000000..466b3cb3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/doc_blue_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/doccancel_b_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/doccancel_b_s.png new file mode 100644 index 00000000..4eae493c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/doccancel_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/docload_b_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/docload_b_s.png new file mode 100644 index 00000000..e86d9347 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/docload_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/docpause_b_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/docpause_b_s.png new file mode 100644 index 00000000..fd117934 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/docpause_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/download_b.png b/TMessagesProj/src/main/res/drawable-xxhdpi/download_b.png deleted file mode 100644 index 0199ccc1..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/download_b.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/download_b_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/download_b_pressed.png deleted file mode 100644 index ba3e4dab..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/download_b_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/download_g.png b/TMessagesProj/src/main/res/drawable-xxhdpi/download_g.png deleted file mode 100644 index edc1b88e..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/download_g.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/download_g_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/download_g_pressed.png deleted file mode 100644 index 4a258462..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/download_g_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/file_b.png b/TMessagesProj/src/main/res/drawable-xxhdpi/file_b.png new file mode 100644 index 00000000..1c8598cd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/file_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_cancel.png b/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_cancel.png new file mode 100644 index 00000000..9d48270d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_cancel.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_cancel_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_cancel_s.png new file mode 100644 index 00000000..5e323f92 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_cancel_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_load.png b/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_load.png new file mode 100644 index 00000000..dc4dae1f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_load.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_load_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_load_s.png new file mode 100644 index 00000000..044304d9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_load_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_s.png new file mode 100644 index 00000000..925351b0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/file_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/file_g.png b/TMessagesProj/src/main/res/drawable-xxhdpi/file_g.png new file mode 100644 index 00000000..7dd85a3b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/file_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_cancel.png b/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_cancel.png new file mode 100644 index 00000000..1ccbe9d9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_cancel.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_cancel_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_cancel_s.png new file mode 100644 index 00000000..de91f915 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_cancel_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_load.png b/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_load.png new file mode 100644 index 00000000..bcddac3b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_load.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_load_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_load_s.png new file mode 100644 index 00000000..174947d7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_load_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_s.png new file mode 100644 index 00000000..8395b5ac Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/file_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_next.png b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_next.png new file mode 100644 index 00000000..4fe60888 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_next.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_pause.png b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_pause.png new file mode 100644 index 00000000..76833ff7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_play.png b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_play.png new file mode 100644 index 00000000..fe7ea25c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_previous.png b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_previous.png new file mode 100644 index 00000000..2c9310af Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_action_previous.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/ic_create.png b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_create.png new file mode 100644 index 00000000..54d4e808 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_create.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/ic_fp_40px.png b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_fp_40px.png new file mode 100644 index 00000000..f7e87240 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_fp_40px.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/ic_launcher_beta.png b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_launcher_beta.png new file mode 100644 index 00000000..25227b62 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_launcher_beta.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/ic_settings.png b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_settings.png new file mode 100644 index 00000000..c9535527 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_settings.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/ic_smiles_gif.png b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_smiles_gif.png new file mode 100644 index 00000000..13882c22 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/ic_smiles_gif.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/igvideo.png b/TMessagesProj/src/main/res/drawable-xxhdpi/igvideo.png deleted file mode 100644 index d13eab92..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/igvideo.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/list_circle.png b/TMessagesProj/src/main/res/drawable-xxhdpi/list_circle.png new file mode 100644 index 00000000..5a16cbaf Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/list_circle.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/location2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/location2.png new file mode 100644 index 00000000..01ea9f4d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/location2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/logo_avatar.png b/TMessagesProj/src/main/res/drawable-xxhdpi/logo_avatar.png new file mode 100644 index 00000000..df02f04f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/logo_avatar.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/managers.png b/TMessagesProj/src/main/res/drawable-xxhdpi/managers.png new file mode 100644 index 00000000..e777cb3d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/managers.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_admin.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_admin.png new file mode 100644 index 00000000..a51b598f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_admin.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_plus.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_plus.png new file mode 100644 index 00000000..968aa3ee Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_plus.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/menu_themes.png b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_themes.png new file mode 100644 index 00000000..eb03acd5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/menu_themes.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/miniplayer_close.png b/TMessagesProj/src/main/res/drawable-xxhdpi/miniplayer_close.png new file mode 100644 index 00000000..909458ac Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/miniplayer_close.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/miniplayer_pause.png b/TMessagesProj/src/main/res/drawable-xxhdpi/miniplayer_pause.png new file mode 100644 index 00000000..b3e388b9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/miniplayer_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/miniplayer_play.png b/TMessagesProj/src/main/res/drawable-xxhdpi/miniplayer_play.png new file mode 100644 index 00000000..e8a04810 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/miniplayer_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_10.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_10.png new file mode 100644 index 00000000..854c6be7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_11.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_11.png new file mode 100644 index 00000000..586404b5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_12.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_12.png new file mode 100644 index 00000000..c2a23cce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_2.png new file mode 100644 index 00000000..16d5b32c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_3.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_3.png new file mode 100644 index 00000000..b06c539a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_4.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_4.png new file mode 100644 index 00000000..2671398a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_5.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_5.png new file mode 100644 index 00000000..7ab17b55 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_6.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_6.png new file mode 100644 index 00000000..ca6a2ee4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_7.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_7.png new file mode 100644 index 00000000..6466f3ec Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_8.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_8.png new file mode 100644 index 00000000..de824689 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_9.png new file mode 100644 index 00000000..2edb08be Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_10.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_10.png new file mode 100644 index 00000000..6e88d21f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_11.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_11.png new file mode 100644 index 00000000..782c69b4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_12.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_12.png new file mode 100644 index 00000000..72ea825e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_2.png new file mode 100644 index 00000000..b6092d55 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_3.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_3.png new file mode 100644 index 00000000..8767cf63 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_4.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_4.png new file mode 100644 index 00000000..2f396656 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_5.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_5.png new file mode 100644 index 00000000..87a1711b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_6.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_6.png new file mode 100644 index 00000000..a3edcd1f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_7.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_7.png new file mode 100644 index 00000000..387e7e92 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_8.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_8.png new file mode 100644 index 00000000..47b68903 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_9.png new file mode 100644 index 00000000..da9b654a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_check_w_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_clock2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_clock2.png new file mode 100644 index 00000000..5130d83d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_clock2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_clock2_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_clock2_s.png new file mode 100644 index 00000000..af7cba16 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_clock2_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_10.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_10.png new file mode 100644 index 00000000..de824689 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_11.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_11.png new file mode 100644 index 00000000..8b527407 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_12.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_12.png new file mode 100644 index 00000000..66651fca Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_2.png new file mode 100644 index 00000000..f521b08f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_3.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_3.png new file mode 100644 index 00000000..694fc211 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_4.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_4.png new file mode 100644 index 00000000..660bdafe Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_5.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_5.png new file mode 100644 index 00000000..f869cdc6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_6.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_6.png new file mode 100644 index 00000000..3914a19f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_7.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_7.png new file mode 100644 index 00000000..23f12907 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_8.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_8.png new file mode 100644 index 00000000..f182637b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_9.png new file mode 100644 index 00000000..f4e17a0d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_10.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_10.png new file mode 100644 index 00000000..bd4e674d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_10.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_11.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_11.png new file mode 100644 index 00000000..56486bc4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_11.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_12.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_12.png new file mode 100644 index 00000000..5167821b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_12.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_2.png new file mode 100644 index 00000000..b6092d55 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_2.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_3.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_3.png new file mode 100644 index 00000000..8767cf63 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_4.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_4.png new file mode 100644 index 00000000..96ab31fa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_4.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_5.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_5.png new file mode 100644 index 00000000..88e9f6b6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_5.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_6.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_6.png new file mode 100644 index 00000000..360ef71a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_6.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_7.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_7.png new file mode 100644 index 00000000..4a938b9a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_7.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_8.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_8.png new file mode 100644 index 00000000..47b68903 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_8.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_9.png new file mode 100644 index 00000000..16753c87 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_halfcheck_w_9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5.9.png new file mode 100644 index 00000000..4495e417 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5_photo.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5_photo.9.png new file mode 100644 index 00000000..7ca493f7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5_photo_selected.9.png new file mode 100644 index 00000000..350b66fa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5_selected.9.png new file mode 100644 index 00000000..46463fdc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_5_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6.9.png new file mode 100644 index 00000000..219cc750 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6_photo.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6_photo.9.png new file mode 100644 index 00000000..138a80c2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6_photo_selected.9.png new file mode 100644 index 00000000..ab93b110 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6_selected.9.png new file mode 100644 index 00000000..467e051f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_6_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7.9.png new file mode 100644 index 00000000..a3393bc8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7_photo.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7_photo.9.png new file mode 100644 index 00000000..7ca493f7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7_photo_selected.9.png new file mode 100644 index 00000000..350b66fa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7_selected.9.png new file mode 100644 index 00000000..615e5bd4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_7_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8.9.png new file mode 100644 index 00000000..3db9979c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8_photo.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8_photo.9.png new file mode 100644 index 00000000..7ca493f7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8_photo_selected.9.png new file mode 100644 index 00000000..350b66fa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8_selected.9.png new file mode 100644 index 00000000..09abd80e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_in_8_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5.9.png new file mode 100644 index 00000000..cdd3c54d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5_photo.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5_photo.9.png new file mode 100644 index 00000000..02e3ad80 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5_photo_selected.9.png new file mode 100644 index 00000000..67713607 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5_selected.9.png new file mode 100644 index 00000000..f5d85ed2 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_5_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6.9.png new file mode 100644 index 00000000..a784271a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6_photo.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6_photo.9.png new file mode 100644 index 00000000..fb37e3e5 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6_photo_selected.9.png new file mode 100644 index 00000000..7ee12956 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6_selected.9.png new file mode 100644 index 00000000..df412b10 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_6_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7.9.png new file mode 100644 index 00000000..fbe4c8ed Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7_photo.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7_photo.9.png new file mode 100644 index 00000000..02e3ad80 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7_photo_selected.9.png new file mode 100644 index 00000000..67713607 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7_selected.9.png new file mode 100644 index 00000000..62079237 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_7_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8.9.png new file mode 100644 index 00000000..b7aa0237 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8_photo.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8_photo.9.png new file mode 100644 index 00000000..02e3ad80 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8_photo.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8_photo_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8_photo_selected.9.png new file mode 100644 index 00000000..67713607 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8_photo_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8_selected.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8_selected.9.png new file mode 100644 index 00000000..6ce8fda0 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/msg_out_8_selected.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/nocover.png b/TMessagesProj/src/main/res/drawable-xxhdpi/nocover.png new file mode 100644 index 00000000..61aab196 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/nocover.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/nocover_big.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/nocover_big.9.png new file mode 100644 index 00000000..eacbc19f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/nocover_big.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/nocover_small.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/nocover_small.9.png new file mode 100644 index 00000000..012386f9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/nocover_small.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/notify_members_off.png b/TMessagesProj/src/main/res/drawable-xxhdpi/notify_members_off.png new file mode 100644 index 00000000..3097e16f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/notify_members_off.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/notify_members_on.png b/TMessagesProj/src/main/res/drawable-xxhdpi/notify_members_on.png new file mode 100644 index 00000000..b468befd Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/notify_members_on.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pause_b_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pause_b_pressed.png deleted file mode 100644 index 14417454..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/pause_b_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pause_b_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pause_b_s.png new file mode 100644 index 00000000..3b056929 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pause_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pause_g_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pause_g_pressed.png deleted file mode 100644 index 6afeea45..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/pause_g_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pause_g_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pause_g_s.png new file mode 100644 index 00000000..ce7328a1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pause_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pause_w.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pause_w.png deleted file mode 100644 index 31bdd738..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/pause_w.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pause_w2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pause_w2.png deleted file mode 100644 index d4be9ec7..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/pause_w2.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pause_w2_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pause_w2_pressed.png deleted file mode 100644 index 94ce677c..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/pause_w2_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pause_w_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pause_w_pressed.png deleted file mode 100644 index 0f81862f..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/pause_w_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/phone_activate.png b/TMessagesProj/src/main/res/drawable-xxhdpi/phone_activate.png new file mode 100644 index 00000000..d422603d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/phone_activate.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_b.png b/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_b.png new file mode 100644 index 00000000..80d4d903 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_b_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_b_s.png new file mode 100644 index 00000000..6d29a268 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_g.png b/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_g.png new file mode 100644 index 00000000..d42899e9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_g_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_g_s.png new file mode 100644 index 00000000..bfa63bb4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_pressed.png new file mode 100644 index 00000000..1477b247 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/photocancel_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/photogif_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/photogif_pressed.png new file mode 100644 index 00000000..365f8f59 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/photogif_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_b.png b/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_b.png new file mode 100644 index 00000000..314b0241 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_b_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_b_s.png new file mode 100644 index 00000000..8b30d79e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_g.png b/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_g.png new file mode 100644 index 00000000..5f85ecce Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_g_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_g_s.png new file mode 100644 index 00000000..fdd61094 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_pressed.png new file mode 100644 index 00000000..df021f02 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/photoload_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/photopause.png b/TMessagesProj/src/main/res/drawable-xxhdpi/photopause.png deleted file mode 100644 index 62f9d3f8..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/photopause.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/phototime2.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/phototime2.9.png new file mode 100644 index 00000000..2f52ccc1 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/phototime2.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/phototime2_b.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/phototime2_b.9.png new file mode 100644 index 00000000..6ce439aa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/phototime2_b.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pl_back.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_back.png new file mode 100644 index 00000000..10fcfc17 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_back.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pl_next.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_next.png new file mode 100644 index 00000000..7895ed90 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_next.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pl_next_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_next_pressed.png new file mode 100644 index 00000000..fa5646ca Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_next_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pl_pause.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_pause.png new file mode 100644 index 00000000..10dac92f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pl_pause_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_pause_pressed.png new file mode 100644 index 00000000..1eb9c4eb Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_pause_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pl_play.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_play.png new file mode 100644 index 00000000..41d57747 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pl_play_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_play_pressed.png new file mode 100644 index 00000000..bc1b0696 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_play_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pl_previous.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_previous.png new file mode 100644 index 00000000..6d45e33c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_previous.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pl_previous_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_previous_pressed.png new file mode 100644 index 00000000..92baf19c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_previous_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pl_repeat.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_repeat.png new file mode 100644 index 00000000..a0404007 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_repeat.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pl_repeat1_active.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_repeat1_active.png new file mode 100644 index 00000000..49caea60 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_repeat1_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pl_repeat_active.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_repeat_active.png new file mode 100644 index 00000000..38266b9d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_repeat_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pl_shuffle.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_shuffle.png new file mode 100644 index 00000000..59108a06 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_shuffle.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/pl_shuffle_active.png b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_shuffle_active.png new file mode 100644 index 00000000..1ca88b2e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/pl_shuffle_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/play_b.png b/TMessagesProj/src/main/res/drawable-xxhdpi/play_b.png new file mode 100644 index 00000000..99e2c15c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/play_b.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/play_b_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/play_b_s.png new file mode 100644 index 00000000..c5c55105 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/play_b_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/play_g.png b/TMessagesProj/src/main/res/drawable-xxhdpi/play_g.png new file mode 100644 index 00000000..d4461d65 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/play_g.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/play_g_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/play_g_s.png new file mode 100644 index 00000000..d471364b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/play_g_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/play_w.png b/TMessagesProj/src/main/res/drawable-xxhdpi/play_w.png deleted file mode 100644 index be2cb867..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/play_w.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/play_w2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/play_w2.png deleted file mode 100644 index 263f27db..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/play_w2.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/play_w2_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/play_w2_pressed.png deleted file mode 100644 index 96e0e127..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/play_w2_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/play_w_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/play_w_pressed.png deleted file mode 100644 index 48aa6b65..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/play_w_pressed.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/player.png b/TMessagesProj/src/main/res/drawable-xxhdpi/player.png new file mode 100644 index 00000000..21217b2c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/player.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/playvideo_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/playvideo_pressed.png new file mode 100644 index 00000000..6d98bdf7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/playvideo_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/post_views.png b/TMessagesProj/src/main/res/drawable-xxhdpi/post_views.png new file mode 100644 index 00000000..c8601721 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/post_views.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/post_views_s.png b/TMessagesProj/src/main/res/drawable-xxhdpi/post_views_s.png new file mode 100644 index 00000000..7839b3d3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/post_views_s.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/post_views_w.png b/TMessagesProj/src/main/res/drawable-xxhdpi/post_views_w.png new file mode 100644 index 00000000..7ddf4de6 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/post_views_w.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/post_viewsg.png b/TMessagesProj/src/main/res/drawable-xxhdpi/post_viewsg.png new file mode 100644 index 00000000..b8889aa3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/post_viewsg.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/publish.png b/TMessagesProj/src/main/res/drawable-xxhdpi/publish.png new file mode 100644 index 00000000..6c02add3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/publish.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/publish_active.png b/TMessagesProj/src/main/res/drawable-xxhdpi/publish_active.png new file mode 100644 index 00000000..2d74763e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/publish_active.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/recorded.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/recorded.9.png new file mode 100644 index 00000000..0c72100a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/recorded.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/redcircle.png b/TMessagesProj/src/main/res/drawable-xxhdpi/redcircle.png new file mode 100644 index 00000000..927e62b3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/redcircle.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/s_pause.png b/TMessagesProj/src/main/res/drawable-xxhdpi/s_pause.png new file mode 100644 index 00000000..07deeb18 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/s_pause.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/s_pause_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/s_pause_pressed.png new file mode 100644 index 00000000..29423e28 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/s_pause_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/s_play.png b/TMessagesProj/src/main/res/drawable-xxhdpi/s_play.png new file mode 100644 index 00000000..4757ae74 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/s_play.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/s_play_pressed.png b/TMessagesProj/src/main/res/drawable-xxhdpi/s_play_pressed.png new file mode 100644 index 00000000..a9575a4c Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/s_play_pressed.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/search_down.png b/TMessagesProj/src/main/res/drawable-xxhdpi/search_down.png new file mode 100644 index 00000000..55352cb7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/search_down.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/search_share.png b/TMessagesProj/src/main/res/drawable-xxhdpi/search_share.png new file mode 100644 index 00000000..60007340 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/search_share.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/search_up.png b/TMessagesProj/src/main/res/drawable-xxhdpi/search_up.png new file mode 100644 index 00000000..35730561 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/search_up.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/share_arrow.png b/TMessagesProj/src/main/res/drawable-xxhdpi/share_arrow.png new file mode 100644 index 00000000..4360f963 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/share_arrow.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/share_round.png b/TMessagesProj/src/main/res/drawable-xxhdpi/share_round.png new file mode 100644 index 00000000..64fe260b Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/share_round.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/sheet_shadow.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/sheet_shadow.9.png new file mode 100644 index 00000000..1e8e6909 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/sheet_shadow.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/stickercounter.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/stickercounter.9.png new file mode 100644 index 00000000..a9ff07a7 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/stickercounter.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/switch_to_on3.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/switch_to_on3.9.png new file mode 100644 index 00000000..00fb83ec Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/switch_to_on3.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/system.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/system.9.png new file mode 100644 index 00000000..f4b4f35e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/system.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/system_black.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/system_black.9.png deleted file mode 100644 index 0aebf3ce..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/system_black.9.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/system_blue.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/system_blue.9.png deleted file mode 100644 index 1321d3c1..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/system_blue.9.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/system_loader.png b/TMessagesProj/src/main/res/drawable-xxhdpi/system_loader.png new file mode 100644 index 00000000..d2c6ec3a Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/system_loader.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/system_loader1.png b/TMessagesProj/src/main/res/drawable-xxhdpi/system_loader1.png deleted file mode 100644 index 26c828f2..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/system_loader1.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/system_loader2.png b/TMessagesProj/src/main/res/drawable-xxhdpi/system_loader2.png deleted file mode 100644 index dcf5caf4..00000000 Binary files a/TMessagesProj/src/main/res/drawable-xxhdpi/system_loader2.png and /dev/null differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tab_all.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tab_all.png new file mode 100644 index 00000000..318057b9 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tab_all.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tab_bot.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tab_bot.png new file mode 100644 index 00000000..33c486b4 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tab_bot.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tab_channel.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tab_channel.png new file mode 100644 index 00000000..cf8e5baa Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tab_channel.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tab_favs.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tab_favs.png new file mode 100644 index 00000000..4409173e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tab_favs.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tab_group.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tab_group.png new file mode 100644 index 00000000..5df1d920 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tab_group.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tab_supergroup.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tab_supergroup.png new file mode 100644 index 00000000..324f9c04 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tab_supergroup.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tab_user.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tab_user.png new file mode 100644 index 00000000..de2a86e8 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tab_user.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tip3.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tip3.png new file mode 100644 index 00000000..3fe46665 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tip3.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tip4.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tip4.png new file mode 100644 index 00000000..b78bf58d Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tip4.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tool_cropfix.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tool_cropfix.png new file mode 100644 index 00000000..4601e79e Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tool_cropfix.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tool_curve.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tool_curve.png new file mode 100644 index 00000000..5cc0a860 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tool_curve.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tool_fade.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tool_fade.png new file mode 100644 index 00000000..72d5a102 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tool_fade.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tool_rotate.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tool_rotate.png new file mode 100644 index 00000000..6043d8e3 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tool_rotate.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tool_tint.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tool_tint.png new file mode 100644 index 00000000..5d060588 Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tool_tint.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/tooltip.9.png b/TMessagesProj/src/main/res/drawable-xxhdpi/tooltip.9.png new file mode 100644 index 00000000..263f788f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/tooltip.9.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxhdpi/video_actions.png b/TMessagesProj/src/main/res/drawable-xxhdpi/video_actions.png new file mode 100644 index 00000000..bfc2dbad Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxhdpi/video_actions.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxxhdpi/ic_launcher_beta.png b/TMessagesProj/src/main/res/drawable-xxxhdpi/ic_launcher_beta.png new file mode 100644 index 00000000..3895b31f Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxxhdpi/ic_launcher_beta.png differ diff --git a/TMessagesProj/src/main/res/drawable-xxxhdpi/sheet_shadow.9.png b/TMessagesProj/src/main/res/drawable-xxxhdpi/sheet_shadow.9.png new file mode 100644 index 00000000..1520a1fc Binary files /dev/null and b/TMessagesProj/src/main/res/drawable-xxxhdpi/sheet_shadow.9.png differ diff --git a/TMessagesProj/src/main/res/drawable/attach_audio_states.xml b/TMessagesProj/src/main/res/drawable/attach_audio_states.xml new file mode 100644 index 00000000..881a09d0 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/attach_audio_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/attach_camera_states.xml b/TMessagesProj/src/main/res/drawable/attach_camera_states.xml new file mode 100644 index 00000000..3b437c24 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/attach_camera_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/attach_contact_states.xml b/TMessagesProj/src/main/res/drawable/attach_contact_states.xml new file mode 100644 index 00000000..f8dbdd4e --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/attach_contact_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/attach_file_states.xml b/TMessagesProj/src/main/res/drawable/attach_file_states.xml new file mode 100644 index 00000000..c5604e3a --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/attach_file_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/attach_gallery_states.xml b/TMessagesProj/src/main/res/drawable/attach_gallery_states.xml new file mode 100644 index 00000000..40a9cf0f --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/attach_gallery_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/attach_hide_states.xml b/TMessagesProj/src/main/res/drawable/attach_hide_states.xml new file mode 100644 index 00000000..6fb0453d --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/attach_hide_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/attach_location_states.xml b/TMessagesProj/src/main/res/drawable/attach_location_states.xml new file mode 100644 index 00000000..942b7063 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/attach_location_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/attach_send_states.xml b/TMessagesProj/src/main/res/drawable/attach_send_states.xml new file mode 100644 index 00000000..9377186e --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/attach_send_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/attach_video_states.xml b/TMessagesProj/src/main/res/drawable/attach_video_states.xml new file mode 100644 index 00000000..93eb9008 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/attach_video_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/bar_selector.xml b/TMessagesProj/src/main/res/drawable/bar_selector.xml deleted file mode 100644 index e7f8b624..00000000 --- a/TMessagesProj/src/main/res/drawable/bar_selector.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/bar_selector_blue.xml b/TMessagesProj/src/main/res/drawable/bar_selector_blue.xml deleted file mode 100644 index 83e87947..00000000 --- a/TMessagesProj/src/main/res/drawable/bar_selector_blue.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/bar_selector_cyan.xml b/TMessagesProj/src/main/res/drawable/bar_selector_cyan.xml deleted file mode 100644 index e9fb9cc2..00000000 --- a/TMessagesProj/src/main/res/drawable/bar_selector_cyan.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/bar_selector_green.xml b/TMessagesProj/src/main/res/drawable/bar_selector_green.xml deleted file mode 100644 index 2e88b9f4..00000000 --- a/TMessagesProj/src/main/res/drawable/bar_selector_green.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/bar_selector_mode.xml b/TMessagesProj/src/main/res/drawable/bar_selector_mode.xml deleted file mode 100644 index f3319e32..00000000 --- a/TMessagesProj/src/main/res/drawable/bar_selector_mode.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/bar_selector_picker.xml b/TMessagesProj/src/main/res/drawable/bar_selector_picker.xml deleted file mode 100644 index 658f2144..00000000 --- a/TMessagesProj/src/main/res/drawable/bar_selector_picker.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/bar_selector_pink.xml b/TMessagesProj/src/main/res/drawable/bar_selector_pink.xml deleted file mode 100644 index 9d81d09d..00000000 --- a/TMessagesProj/src/main/res/drawable/bar_selector_pink.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/bar_selector_red.xml b/TMessagesProj/src/main/res/drawable/bar_selector_red.xml deleted file mode 100644 index c00e47a4..00000000 --- a/TMessagesProj/src/main/res/drawable/bar_selector_red.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/bar_selector_violet.xml b/TMessagesProj/src/main/res/drawable/bar_selector_violet.xml deleted file mode 100644 index 405397c1..00000000 --- a/TMessagesProj/src/main/res/drawable/bar_selector_violet.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/bar_selector_yellow.xml b/TMessagesProj/src/main/res/drawable/bar_selector_yellow.xml deleted file mode 100644 index 98da9c12..00000000 --- a/TMessagesProj/src/main/res/drawable/bar_selector_yellow.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/bot_keyboard_states.xml b/TMessagesProj/src/main/res/drawable/bot_keyboard_states.xml new file mode 100644 index 00000000..3f0757f5 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/bot_keyboard_states.xml @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/check_profile_fixed.xml b/TMessagesProj/src/main/res/drawable/check_profile_fixed.xml new file mode 100644 index 00000000..591ea9d5 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/check_profile_fixed.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/field_carret.xml b/TMessagesProj/src/main/res/drawable/field_carret.xml new file mode 100644 index 00000000..63e19f9b --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/field_carret.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/TMessagesProj/src/main/res/drawable/ic_fingerprint_error.xml b/TMessagesProj/src/main/res/drawable/ic_fingerprint_error.xml new file mode 100644 index 00000000..be46116d --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/ic_fingerprint_error.xml @@ -0,0 +1,28 @@ + + + + + + diff --git a/TMessagesProj/src/main/res/drawable/bar_selector_orange.xml b/TMessagesProj/src/main/res/drawable/list_selector_white.xml similarity index 52% rename from TMessagesProj/src/main/res/drawable/bar_selector_orange.xml rename to TMessagesProj/src/main/res/drawable/list_selector_white.xml index e1880b1e..160ae131 100644 --- a/TMessagesProj/src/main/res/drawable/bar_selector_orange.xml +++ b/TMessagesProj/src/main/res/drawable/list_selector_white.xml @@ -1,19 +1,19 @@ - + + - + - + - + - + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/player_next_states.xml b/TMessagesProj/src/main/res/drawable/player_next_states.xml new file mode 100644 index 00000000..b3fe0312 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/player_next_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/player_pause_states.xml b/TMessagesProj/src/main/res/drawable/player_pause_states.xml new file mode 100644 index 00000000..713cd0bc --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/player_pause_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/player_play_states.xml b/TMessagesProj/src/main/res/drawable/player_play_states.xml new file mode 100644 index 00000000..92447f39 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/player_play_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/player_prev_states.xml b/TMessagesProj/src/main/res/drawable/player_prev_states.xml new file mode 100644 index 00000000..e34bbba2 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/player_prev_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/s_player_pause_states.xml b/TMessagesProj/src/main/res/drawable/s_player_pause_states.xml new file mode 100644 index 00000000..8d9ed544 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/s_player_pause_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/drawable/s_player_play_states.xml b/TMessagesProj/src/main/res/drawable/s_player_play_states.xml new file mode 100644 index 00000000..d5e885d1 --- /dev/null +++ b/TMessagesProj/src/main/res/drawable/s_player_play_states.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/identicon_layout.xml b/TMessagesProj/src/main/res/layout/identicon_layout.xml deleted file mode 100644 index 74ee9810..00000000 --- a/TMessagesProj/src/main/res/layout/identicon_layout.xml +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/player_big_notification.xml b/TMessagesProj/src/main/res/layout/player_big_notification.xml new file mode 100644 index 00000000..94cddaf8 --- /dev/null +++ b/TMessagesProj/src/main/res/layout/player_big_notification.xml @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/layout/player_small_notification.xml b/TMessagesProj/src/main/res/layout/player_small_notification.xml new file mode 100644 index 00000000..55d8fb0b --- /dev/null +++ b/TMessagesProj/src/main/res/layout/player_small_notification.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TMessagesProj/src/main/res/values-eo/strings.xml b/TMessagesProj/src/main/res/values-eo/strings.xml new file mode 100644 index 00000000..1eecb0a8 --- /dev/null +++ b/TMessagesProj/src/main/res/values-eo/strings.xml @@ -0,0 +1,1253 @@ + + + Telegram + Esperanto + Esperanto + eo + + Via telefonnumero + Konfirmu vian landokodon kaj tajpu vian telefonnumeron. + Elektu landon + Malĝusta landokodo + + Via kodo + Ni sendis tekstmesaĝon kun aktivigokodo al via telefono + Ni telefonos vin en %1$d:%2$02d + Ni telefonas vin... + Kodo + Ĉu malĝusta telefonnumero? + Ĉu vi ne ricevis la kodon? + + Via nomo + Agordi vian personnomon kaj familinomon + + Personnomo (nepra) + Familinomo (malnepra) + Nuligi registradon + + Agordoj + Kontaktoj + Nova grupo + hieraŭ + Neniu rezulto + Ankoraŭ neniu babilejo... + Ekmesaĝu per tuŝetu la butono por nova\nmesaĝo en la malsupra dekstra angulo aŭ\ntuŝetu la menubutonon por pli da opcioj. + Atendado de reto... + Konektado... + Ĝisdatigado... + Nova sekreta babilejo + Atendado de enretiĝado de %s... + Sekreta babilejo nuligita + Interŝanĝado de ĉifroŝlosiloj... + %s aliĝis al via sekreta babilado + Vi aliĝis al sekreta babilado + Vakigi la historion + Forigi el kaŝmemoro + Forigi kaj forlasi + Forigi babilejon + Forigita konto + Elektu babilejon + Tuŝadu por vidi + %1$s uzas malnovan version de Telegram, do sekretaj fotoj estos montraj en kongrueca reĝimo.\n\nKiam %2$s ĝisdatigos Telegram-on, fotoj kun tempiloj por unu minuto aŭ malpli ekfunkcios en \'Tuŝedu por vidi\' reĝimo, kaj vi estos sciigata kiam ajn la alia uzanto prenas ekranfoto. + MESAĜOJ + Serĉi + Silentigi sciigojn + Silentigi por %1$s + Malsilentigi + En %1$s + Malŝalti + KRADVORTOJ + ĴUSA + Antaŭrigardo de ligilo + + Promocii al administranto + Vi povas agordi malnepran priskribon por via grupo. + Forlasi grupon + Forigi grupon + Forlasi grupon + Forigi grupon + Vi perdos ĉiujn mesaĝojn en ĉi tiu kanalo. + Vi povas aldoni administrantojn por helpi vin direkti vian grupon. Tuŝadu por forigi ilin. + Atendu! Forigado de ĉi tiu grupo forigos ĉiujn membrojn kaj ĉiuj mesaĝoj estos forigita. Forigi la grupon kiel ajn? + Grupo kreita + un1 aldonis vin al ĉi tiu grupo + Ĉu vi certas, ke vi volas forlasi la grupon? + Bedaŭrinde, vi ne povas aldoni ĉi tiun uzanton al grupoj. + Bedaŭrinde, ĉi tiu grupo estas plena. + Bedaŭrinde, ĉi tiu uzanto decidis forlasi ĉi tiun grupon, do vi ne povas aldoni ĝin denove ĉi tien. + Bedaŭrinde, tro multe da administrantoj en ĉi tiu grupo. + Bedaŭrinde, tro multe da robotoj en ĉi tiu grupo. + Ĉi tiu grupo estas promociita al grupego + %1$s estas promociita al grupego + Blokitaj uzantoj estas forigitaj de tiu grupo kaj povas nur reveni, se estas invititaj de administranto. Invitligiloj ne funkcias por ili. + Nova kanalo + Kanalnomo + Komentoj + Se vi ŝaltas komentojn, personoj eblos diskuti viajn afiŝojn en la kanalo. + Aldoni kontaktojn al via kanalo + Personoj povas konigi ĉi tiun ligilon kun aliuloj kaj povas trovi vian kanalon per Telegram-serĉo. + ligilo + Personoj povas aliĝi al via kanalo sekvante ĉi tiun ligilon. Vi ĉiam povas senvalidigi la ligilon. + Priskribo + Vi povas agordi malnepran priskribon por via kanalo. + Publika kanalo + Publikaj kanaloj estas troveblaj per serĉo, ĉiu povas aldoniĝi. + Privata kanalo + Privataj kanaloj povas esti atingeblaj per invitligilo. + Ligilo + Invitligilo + Aldoni membrojn + Forlasi kanalon + Forlasi kanalon + Agordoj + ALDONIĜI + Informoj de kanalo + Elsendi + Komento + montri komentojn + Kio estas kanalo? + Kanaloj estas nova ilo por elsendi viajn mesaĝojn al granda spektantaro. + KREI KANALON + Bedaŭrinde, ĉi tiu nomo estas jam prenita. + Bedaŭrinde, ĉi tiu nomo estas malvalida. + Kanalnomoj devas havi almenaŭ 5 signojn. + La nomo ne devas superigi 32 signojn. + Kanalnomoj ne povas komenciĝi per cifero, + Kontrolado de nomo... + %1$s estas disponebla. + Membroj + Blokitaj uzantoj + Administrantoj + Forigi kanalon + Forigi kanalon + Atendu! Forigado de tiu kanalo ankaŭ forigos ĉiujn membrojn kaj mesaĝojn. Forigig ĉiumaniere? + Ĉu vi certas, ke vi volas forlasi la kanalon? + Vi perdos ĉiujn mesaĝojn en ĉi tiu babilejo. + Redakti + Rimarku ke se vi elektas publikan ligilon por via kanalo, kiu ajn eblos trovi ĝin per serĉilo kaj aliĝi.\n\nNe kreu ĉi tiun ligilon se vi volas ke via kanalo restu privata. + Elektu ligilon por via publika kanalo, tiel homoj povas trovi ĝin per serĉilo kaj konigu ĝin kun aliuloj.\n\nSe vi ne estas interesata, ni sugestas krei privatan kanalon anstataŭ. + Kanalo kreita + Kanalbildo ŝanĝita + Kanalbildo forigita + Kanalnomo ŝanĝita al un2 + Pardonu, vi kreis tro multe da publikaj kanaloj. Vi povas aŭ krei privatan kanalon aŭ forigi unu el viaj estantaj kanaloj unue. + Kontrolanto + Kreinto + Administranto + SILENTIGI + MALSILENTIGI + Aldoni administranton + Inviti per ligilo + Ĉu vi certas, ke vi volas farigi %1$sn administranto? + Forigi + Nur administrantoj de kanalo povas vidi tiun liston. + Ĉi tiu uzanto ankoraŭ ne aldoniĝis al la kanalo. Ĉi vi volas aldoni tiun? + Ĉiu, kiu havas Telegram instalita povos aldoniĝi al via kanalo per sekvado de tiu ligilo. + Vi povas aldoni administrantojn por helpi vin direkti vian kanalon. Tuŝadu por forigi administrantojn. + Ĉu vi volas aliĝi al la kanalo \'%1$s\'? + Bedaŭrinde, ĉi tiu babilejo ne estas disponebla. + Ĉu aldoni je %1$s al la kanalo? + Bedaŭrinde, ĉi tiu uzanto decidis forlasi ĉi tiun kanalon, do vi ne povas aldoni tiun denove tien. + Bedaŭrinde, vi ne povas aldoni tiun uzanton al kanaloj. + Bedaŭrinde, tro da administrantoj en tiu kanalo. + Bedaŭrinde, tro multe da roboroj en tiu kanalo. + Bedaŭrinde, vi povas aldoni nur unuajn 200 membrojn al kanalo. Notu, ke senlima nombro de personoj povas sekvi la ligilon de la kanalo + un1 aldonis vin al ĉi tiu kanalo + Vi aliĝis al la kanalo. + Forigi el kanalo + Bedaŭrinde, vi ne povas sendi mesaĝojn al tiu kanalo. + %1$s aldonis vin al la kanalo %2$s + Kanalbildo de %1$s ŝanĝita + %1$s sendis mesaĝon al la kanalo %2$s + %1$s sendis bildon al la kanalo %2$s + %1$s sendis videon al la kanalo %2$s + %1$s konigis kontakton kun la kanalo %2$s + %1$s sendis lokon al la kanalo %2$s + %1$s sendis dosieron al la kanalo %2$s + %1$s sendis movbildon al la kanalo %2$s + %1$s sendis sondosieron al la kanalo %2$s + %1$s sendis glumarkon al la kanalo %2$s + %1$s afiŝis mesaĝon + %1$s afiŝis bildon + %1$s afiŝis videon + %1$s afiŝis kontakton + %1$s afiŝis lokon + %1$s afiŝis dosieron + %1$s afiŝis movbildon + %1$s afiŝis sondosieron + %1$s afiŝis glumarkon + + Nova elsenda listo + Listnomo + Vi kreis elsendan liston + Aldoni ricevonton + Forigi de la elsenda listo. + + Aldonu dosierojn al la muzikbiblioteko por vidi ilin ĉi tie. + Muzikdosiero + Nekonata artisto + Nekonata titolo + + Elektu dosieron + Libera %1$s de %2$s + Nekonata eraro + Atingeraro + Ankoraŭ neniu dosiero... + La dosiergrando ne estu pli granda ol %1$s + Konservado ne muntita + USB-transigo aktivas + Interna konservado + Ekstera konservado + Radika dosierujo + SD-karto + Dosierujo + Sendi bildojn sen komptaktigo + + nevidebla + tajpas... + tajpas... + tajpas... + %1$s registras sondosieron... + %1$s sendas bildon... + %1$s sendas videon... + %1$s sendas dosieron... + registras sondosieron... + sendas bildon... + sendas videon... + sendas dosieron... + Ĉu vi havas demandon\npri Telegram? + Foti + Galerio + Loko + Video + Dosiero + Fotilo + Ankoraŭ neniu mesaĝo ĉi tie... + Plusendita mesaĝo + De + Neniu ĵusa + Mesaĝo + Mesaĝo + Konigi mian telefonnumeron + Aldoni al kontaktoj + %s invitis vin aliĝi sekretan babilejon. + Vi invitis je %s al aliĝi sekretan babilejon. + Funkcioj de sekretaj babilejoj: + Fino-al-fina ĉifrado + Neniu spuro en niaj serviloj + Memdetrua tempilo + Neniu plusendado + Vi estas forigita el ĉi tiu grupo + Vi forlasis ĉi tiun grupon + Forigi ĉi tiun grupon + Forigi ĉi tiun babilejon + TRENI POR NULIGI + Konservi en elŝutujo + Konservi en movbildujo + Ĉu forigi movbildon? + Konservi en muzikujo + Konigi + Apliki tradukdosieron + Nesubtenata kunsendaĵo + Agordi memdetruan tempilon + Servaj sciigoj + Ricevado de informo de ligilo... + Malfermi en retumilo + Kopii ligilon + Sendi %1$s + Ĉu malfermi ligilon %1$s? + RAPORTI SPAMON + ALDONI KONTAKTON + Ĉu vi certas, ke vi volas raporti spamon de ĉi tiu uzanto? + Ĉu vi certas, ke vi volas raporti spamon de ĉi tiu grupo? + Bedaŭrinde ĉi-momente vi nur povas sendi mesaĝojn al komunaj kontaktoj. + Bedaŭrinde ĉi-momente vi nur povas aldoni komunajn kontaktojn al grupoj. + https://telegram.org/faq#can-39t-send-messages-to-non-contacts + Pli informo + Sendi al... + Tuŝadu por atingi konservitajn movbildojn + + %1$s agordis la memdetruan tempilon al %2$s + Vi agordis la memdetruan tempilon al %1$s + %1$s malŝaltis la memdetruan tempilon + Vi malŝaltis la memdetruan tempilon + Vi havas novan mesaĝon + %1$s: %2$s + %1$s sendis mesaĝon al vi + %1$s sendis bildon al vi + %1$s sendis videon al vi + %1$s konigis kontakton kun vi + %1$s sendis lokon al vi + %1$s sendis dosieron al vi + %1$s sendis movbildon al vi + %1$s sendis sondosieron al vi + %1$s sendis glumarkon al vi + %1$s @ %2$s: %3$s + %1$s sendis mesaĝon al la grupo %2$s + %1$s sendis bildon al la grupo %2$s + %1$s sendis videon al la grupo %2$s + %1$s konigis kontakton kun la grupo %2$s + %1$s sendis lokon al la grupo %2$s + %1$s sendis dosieron al la grupo %2$s + %1$s sendis movbildon al la grupo %2$s + %1$s sendis sondosieron al la grupo %2$s + %1$s sendis glumarkon al la grupo %2$s + %1$s invitis vin al la grupo %2$s + %1$s ŝanĝis la grupnomon al %2$s + %1$s ŝanĝis la grupbildon de %2$s + %1$s invitis je %3$s al la grupo %2$s + %1$s revenis al la grupo %2$s + %1$s forigis je %3$s el la grupo %2$s + %1$s forigis vin el la grupo %2$s + %1$s forlasis la grupon %2$s + %1$s kreis Telegram-konton! + %1$s,\nNi detektis ensaluton en via konto de nova aparato je %2$s\n\nAparato: %3$s\nLoko: %4$s\n\nSe vi ne faris tion, vi povas fini tiun seancon per: Agordoj - Privateco kaj sekureco - Aktivaj seancoj.\n\nSe vi pensas, ke iu ensalutis en via konto kontraŭ via volo, vi povas ŝalti dufazan kontroladon per: Agordoj - Privateco kaj sekureco - Dufaza kontrolado.\n\nĜis,\nLa Telegram-teamo + %1$s ŝanĝis la profilbildon + %1$s aliĝis al grupo %2$s per invitligilo + Respondi + Respondi al %1$s + Respondi al %1$s + %1$s %2$s + + Elektu kontakton + Ankoraŭ neniu kontakto + Saluton, ni devus ŝanĝi al Telegram: https://telegram.org/dl + je + hieraŭ je + enreta + laste vidita + laste vidita + laste vidita ĵus nun + Inviti amikojn + TUTMONDA SERĈO + laste vidita lastatempe + laste vidita ene de semajno + laste vidita ene de monato + laste vidita antaŭ longe + Nova mesaĝo + + Sendi mesaĝon al... + Grupnomo + Grupnomo + %1$d/%2$d membroj + Ĉu vi volas aliĝi al la babilejo \'%1$s\'? + Bedaŭrinde, tiu grupo estas jam plena. + Pardonu, ŝajnas ke ĉi tiu babilejo ne ekzistas. + Ligilo kopiita al tondejo + Inviti al la grupo per ligilo + Invitligilo + Ĉu vi certas, ke vi volas senvalidigi ĉi tiun ligilon? Kiam la ligilo estas senvalidigita, neniu povos aliĝi per ĝi. + La antaŭa invitligilo nun estas malaktiva. Nova ligilo estas generita. + Revoki + Revoki ligilon + Kopii ligilon + Konigi ligilon + Ĉiu, kiu havas Telegram instalita povos aldoniĝi al via grupo per sekvado de tiu ligilo. + + Administrantoj + Ĉiuj membroj estas administrantoj + Ĉiu membro povas aldoni novajn membrojn, redakti nomon kaj foton de la grupo. + Nur administrantoj povas aldoni kaj forigi membrojn, redakti nomon kaj foton de la grupo. + + Konigitaj aŭdvidaĵoj + Agordoj + Aldoni membron + Agordi administrantojn + Forigi kaj forlasi grupon + Sciigoj + Forigi de la grupo + Promocii al grupego + Memoru, ke membroj de la grupo bezonas ĝisdatigi iliajn Telegram-aplikaĵojn al la lasta versio por vidi vian grupegon. Ĉu vi certas, ke vi volas promocii ĉi tiun grupon? + ]]>Limo de membroj atingita.]]>\n\nPor surpasi la limon kaj akiri pliajn funkciojn, promociu la grupon al supergrupo:\n\n• Supergrupoj povas teni ĝis %1$s membrojn\n• Novaj membroj vidas la tutan babilan historion\n• Administrantoj forigas mesaĝojn por ĉiuj \n• Sciigoj estas silentigitaj defaŭlte. + + Konigi + Aldoni + Aldoni kontakton + Bloki + Redakti + Forigi + Hejmtelefono + Poŝtelefono + Labortelefono + Alia telefono + Ĉefa telefono + Komenci sekretan babilejon + Eraro okazis. + Ĉifroŝlosilo + Memdetrua tempilo + Malŝaltita + Ĉi tiu bildo estas bildigo de la ĉifroŝlosilo por ĉi tiu sekreta babilejo kun ]]>%1$s]]>.
]]>Se ĉi tiu bildo aspektas same en la aparato de ]]>%2$s]]>, via babilado estas 200%% sekura.
]]>Lernu pli ĉe telegram.org
+ Nekonata + Informo + Telefonnumero + + Uzantnomo + Via uzantnomo + Bedaŭrinde, ĉi tiu uzantnomo estas jam prenita. + Bedaŭrinde, ĉi tiu uzantnomo estas malvalida. + Uzantnomo devas havi minimume 5 signojn. + La uzantnomo ne devas superigi 32 signojn. + Bedaŭrinde, uzantnomoj ne povas komenciĝi per cifero. + Vi povas elekti uzantnomon ĉe ]]>Telegram]]>. Se vi faros tion, aliuloj povas trovi vin per ĉi tiu uzantnomo kaj povas kontakti vin sen scii vian telefonnumeron.
]]>Vi povas uzi la signojn ]]>a–z]]>, ]]>0–9]]> kaj substrekoj. La minimuma longo estas ]]>5]]> signoj.
+ Kontrolado de uzantnomo... + %1$s estas disponebla. + Neniu + Eraro okazis. + + Glumarkaroj + Artistoj bonvenas aldoni siajn proprajn glumarkarojn per nia roboto @stickers.\n\nUzantoj povas aldoni glumarkarojn per tuŝi ilin, elekti \"Rigardi glumarkaron\" kaj elekti \"Aldoni glumarkaron\". + Aldoni glumarkaron + Rigardi glumarkaron + Glumarkaro ne trovita + Glumarkaro forigita + Nova glumarkaro aldonita + Kaŝi + Malkaŝi + Konigi + Kopii ligilon + Forigi + Ankoraŭ neniu glumarko + + Reagordi defaŭlte ĉiajn sciigojn + Tekstogrando de mesaĝoj + Fari demandon + Ŝalti animaciojn + Malbloki + Tuŝadu uzanton por malbloki. + Ankoraŭ neniu blokita uzanto + Sciigoj de mesaĝoj + Averto + Antaŭrigardo de mesaĝo + Sciigoj de grupoj + Sono + Enaplikaĵaj sciigoj + Enaplikaĵaj sonoj + Enaplikaĵe vibri + Vibri + Enaplikaĵaj antaŭrigardoj + Rekomencigi + Rekomencigi ĉiujn sciigojn + Malfari ĉiujn proprajn agordojn por ĉiuj el viaj kontaktoj kaj grupoj + Sciigoj kaj sonoj + Blokitaj uzantoj + Elsaluti + Nenia + Defaŭlta + Subteno + Nur se silenta + Fono de babilejoj + Mesaĝoj + Sendi per enen-klavo + Fini ĉiujn aliajn seancojn + Eventoj + Kontakto kreos Telegram-konton + Lingvo + Memoru, ke la subteno de Telegram estas farita de volontuloj. Ni penas respondi tiel rapida kiel eblas, sed oni povas daŭri dum momentoj.
]]>Vidu la oftajn demandojn]]>: ĝi havas respondojn por plejmultaj demandoj kaj gravajn konsilojn por problemsolvado]]>.
+ Demandi volontulon + Oftaj demandoj + https://telegram.org/faq + Ĉu forigi tradukdosieron? + Malĝusta tradukdosiero + Ŝaltita + Malŝaltita + Sciiga servo + Se Google Play-servoj sufiĉas laŭ vi por ricevi sciigojn, vi povas malŝalti la servon por sciigoj. Tamen ni rekomendas al vi lasi ĝin ŝaltita, do la aplikaĵo funkcias fone kaj vi ricevos tujajn sciigojn. + Ordigi laŭ + Importi kontaktojn + Personnomo + Familinomo + LED-koloro + Ŝprucaj sciigoj + Neniam + Nur kiam la ekrano estas ŝaltita + Nur kiam la ekrano estas malŝaltita + Ĉiam + Signa nombrilo + Mallonga + Longa + Sistema defaŭlta + Agorda defaŭlta + Aŭtomata elŝutado de aŭdvidaĵoj + Dum uzado de portebla reto + Dum uzado de sendrata reto + Dum retmigrado + Neniu aŭdvidaĵo + Ludi movbildojn aŭtomate + Konservi en galerio + Redakti nomon + Prioritato + Defaŭlta + Malalta + Alta + Maksimuma + Neniam + Ripeti sciigojn + Vi povas ŝanĝi vian telefonnumeron ligita al Telegram ĉi tie. Via konto kaj ĉiuj viaj nubaj datumoj — mesaĝoj, aŭdvidaĵoj, kontaktoj, k.t.p. estos movata al la nova telefonnumero.\n\nGrava:]]> ĉiuj viaj Telegram-kontaktoj akiros vian novan telefonnumeron]]> aldonita al siaj kontaktoj, se si havis vian malnovan telefonnumeron kaj vi ne blokis sin en Telegram. + Ĉiuj viaj Telegram-kontaktoj akiros vian novan telefonnumeron aldonita al siaj kontaktoj, se si havis vian malnovan telefonnumeron kaj vi ne blokis sin en Telegram. + ŜANĜI TELEFONNUMERON + Nova telefonnumero + Ni sendos tekstmesaĝon kun konfirmokodo al via nova telefonnumero + La telefonnumero %1$s estas jam konektita al Telegram-konto. Forigu tiun konton antaŭ la migrado al la nova telefonnumero. + Alia telefono + Malŝaltita + Malŝaltita + Malŝaltita + Malŝaltita + Enbabilejaj sonoj + Defaŭlta + Defaŭlta + Inteligentaj sciigoj + Malŝaltita + Soni maksimume %1$sn en %2$s + Soni maksimume + fojojn + en + minutoj + + Agordoj de kaŝmemoro + Loka datumbazo + Ĉu vakigi la kaŝmemorigita tekstmesaĝojn? + Vakigado de la loka datumbazo forigos la tekstojn de la kaŝmemorigitaj mesaĝoj kaj densigos la datumbazon por savi internan diskospacon. Telegram bezonas kelkajn datumojn por funkcii, do la grando de la datumbazo ne atingos nul.\n\nĈi tiu operacio povas daŭri dum kelkaj minutoj por kompletiĝi. + Vakigi la kaŝmemoron + Vakigi + Kalkulado... + Dosieroj + Bildoj + Sondosieroj + Videoj + Muzikdosieroj + Aliaj dosieroj + Malplena + Konservi aŭdvidaĵojn + Fotoj, videoj kaj aliaj dosieroj de la nuba babilejoj kiuj vi ne eniris]]> dum ĉi tiu periodo estos forigita de ĉi tiu aparato por savi diskospacon.\n\nĈiuj aŭdvidaĵoj restos en la Telegram-nubo kaj eblas reelŝuti ilin se vi bezonas ilin denove. + Eterne + + Aktivaj seancoj + Nuna seanco + Neniaj aktivaj seancoj + Vi povas ensaluti al Telegram de aliaj poŝtelefonoj, tabulkomputiloj kaj komputiloj per la sama telefonnumero. Ĉiuj viaj datumoj estos tuje sinkronigitaj. + Aktivaj seancoj + Administru viajn seancojn en aliaj aparatoj + Tuŝetu sur seanco por fini. + Ĉu fini ĉi tiun seancon? + neoficiala aplikaĵo + + Atingokoda ŝloso + Ŝanĝi atingokodon + Kiam vi agordas plian atingokodon, ŝlosila bildsimbolo aperos en la paĝo de babilejoj. Tuŝu por ŝlosi kaj malŝlosi vian Telegram-aplikaĵon.\n\nNoto: se vi forgesas la atingokodon, vi devos forigi kaj reinstali la aplikaĵon. Ĉiu sekreta babilo estos perdita. + Vi nun vidos ŝlosilan simbolon en la paĝo de babiloj. Tuŝu ĝin por ŝlosi vian Telegram-aplikaĵon kun via nova atingokodo. + Numero + Pasvorto + Tajpu vian aktualan atingokodon + Tajpu atingokodon + Tajpu vian novan atingokodon + Tajpu vian atingokodon + Tajpu vian novan atingokodon denove + Malĝusta atingokodo + Atingokodo ne kongruas + Aŭtomata ŝlosi + Postuli atingokodon se vi estas for por mallonga tempo. + en %1$s + Malŝaltita + Malŝlosi per fingropremaĵo + Konfirmi fingropremaĵon por daŭrigi + Fingrospura sentilo + Fingrospuro nerekonita. Provu denove + + Konigi fotojn kaj videojn en ĉi tiu babilejo kaj atingi ilin per ajna aparato de vi. + Konigitaj dosieroj + Konigitaj aŭdvidaĵoj + Konigitaj ligiloj + Konigita muzikdosieroj + Konigi muziekdosierojn en ĉi tiu babilejo kaj atingi ilin per ajna aparato de vi. + Konigi dosierojn en ĉi tiu babilejo kaj atingi ilin per ajna aparato de vi. + Konigi ligilojn en ĉi tiu babilejo kaj atingi ilin per ajna aparato de vi. + + Mapo + Satelito + Hibrida + m for + km for + Sendi vian nunan lokon + Sendi elektitan lokon + Loko + Preciza je %1$s + AŬ ELEKTU LOKON + + Montri ĉiujn aŭdvidaĵoj + Konservi en galerio + %1$d de %2$d + Galerio + Ĉiuj bildoj + Ĉiuj videoj + Ankoraŭ neniu bildo + Ankoraŭ neniu video + Elŝutu la aŭdvidaĵon unue + Neniu ĵusa bildo + Neniu ĵusa movbildo + SERĈI BILDOJN + SERĈI RETE + SERĈI MOVBILDOJN + Serĉi rete + Serĉi movbildojn + Stuci bildon + Redakti bildon + Plimultigi + Markoj + Kontrasto + Ekspono + Varmo + Satureco + Vinjeto + Ombroj + Grajno + Akrigi + Nebuligi + Malŝaltita + Lineara + Radiusa + Ĉu vi certas, ke vi volas forigi ĉi tiun bildon? + Ĉu vi certas, ke vi volas forigi ĉi tiun videon? + Ĉu ne konservi ŝanĝojn? + Ĉu vakigi la serĉhistorion? + Vakigi + Bildoj + Video + Aldoni apudskribon... + Apudskribo de bildo + Apudskribo de video + + Dufaza kontrolado + Agordi aldonitan pasvorton + Vi povas agordi pasvorton, kiu estos nepra por ensaluti per nova aparato krome la kodon kiun vi akiros en la tekstmesaĝo. + Via pasvorto + Tajpu vian pasvorton + Tajpu pasvorton + Tajpu vian novan pasvorton + Tajpu vian pasvorton denove + Restaŭrada retpoŝtadreso + Via retpoŝtadreso + Aldonu vian validan retpoŝtadreson. Ĝi estas la nura maniero por restaŭri forgesitan pasvorton. + Preterpasi + Averto + Ne, serioze.\n\nSe vi forgesos vian pasvorton, vi perdos atingon al via Telegram-konto. Ne estos vojo por restaŭri ĝin. + Preskaŭ tie! + Kontrolu vian retpoŝton (kaj ne forgesu la spamujon) por kompletigi la agordon de la dufaza kontrolado. + Sukceso! + Via pasvorto por dufaza kontrolado nun estas aktiva. + Ŝanĝi pasvorton + Malŝalti pasvorton + Agordi restaŭradan retpoŝtadreson + Ŝanĝi restaŭradan retpoŝtadreson + Ĉu vi certas, ke vi volas malŝalti vian pasvorton? + Pasvorta aludo + Kreu aludon por via pasvorto + Pasvortoj ne kongruas + Aborti dufazan kontroladon + Sekvu tiujn paŝojn por fini la agordon de la dufaza kontrolado:\n\n1. Kontrolu vian retpoŝto (ne forgesu la spamujon)\n%1$s\n\n2. Klaku la validigan ligilon. + Aludo devas esti malsama ol via pasvorto + Malĝusta retpoŝtadreso + Pardonu + Ĉar vi ankoraŭ ne provizas restaŭrada retpoŝtadreso dum agordante vian pasvorton, viaj restantaj opcioj estas memori vian pasvorton aŭ rekomencigi vian konton. + Ni sendis restaŭradan kodon al la via retpoŝtadreso:\n\n%1$s + Kontrolu vian retpoŝton kaj entajpu la 6-ciferan kodon kiun ni sendis tie. + Ĉu vi ne povas atingi vian retpoŝton %1$s? + Se vi ne povas restaŭri la aliron de via retpoŝto, viaj restantaj opcioj estas memori via pasvorton aŭ rekomencigi vian konton. + REKOMENCIGI MIAN KONTON + Vi perdos ĉiu da viaj babiloj kaj mesaĝoj, kune kiuj ajn aŭdvidaĵoj kaj dosieroj kiujn vi konigis, se vi daŭrigas la rekomencigo de via konto, + Averto + Ĉi tiu ago ne povas esti malfarita.\n\nSe vi rekomencigas vian konton, ĉiu da viaj mesaĝoj kaj babiloj estos forigita. + Rekomencigi + Pasvorto + Vi ŝaltis dufazan kontroladon, do via konto estas protektita per kroma pasvorto. + Ĉu forgesi pasvorton? + Restaŭrado de pasvorto + Kodo + Pasvorto malaktivigita + Vi ŝaltis dufazan kontroladon.\nVi bezonos la pasvorton, kiu vi agordis, por ensaluti en via Telegram-konto. + Via restaŭrada retpoŝtadreso %1$s ne estas aktiva ankoraŭ kaj atendas konfirmadon. + + Privateco kaj sekureco + Privateco + Laste vidita + Ĉiuj + Miaj kontaktoj + Neniu + Ĉiuj (-%1$d) + Miaj kontaktoj (+%1$d) + Miaj kontaktoj (-%1$d) + Miaj kontaktoj (-%1$d, +%2$d) + Neniu (+%1$d) + Sekureco + Konto memdetruas + Se vi estas for por + Se vi ne ensalutas almenaŭ unufoje ene de ĉi tiu periodo, via konto estos forigita kune ĉiu da viaj grupoj, mesaĝoj kaj kontaktoj. + Ĉu forigi vian konton? + Agordu kiu povas vidi vian \'Laste Vidita\' tempon. + Kiu povas vidi vian \'Laste Vidita\' tempon? + Aldoni esceptojn + Grava: vi ne povos la \'laste vidita\'-statusoj de homoj, kun kiu ne konigas vian \'laste vidita\'-statuson. Proksimuma \'laste vidita\'-statuso estos montrita anstataŭe (lastatempe, ene de semajno, ene de monato). + Ĉiam konigi kun + Neniam konigi kun + Ĉi tiuj agordoj transpasas la suprajn valorojn. + Ĉiam konigi + Ĉiam konigi kun uzantoj... + Neniam konigi + Neniam konigi kun uzantoj... + Aldoni uzantojn + Pardonu, tro da petoj. Malebla de ŝanĝi privatecajn agordojn nun, atendu. + Elsaluti ĉiujn aparatojn escepte ĉi tiu. + Tuŝadu uzanton por forigi. + + Redakti videon + Originala video + Redaktita video + Sendado de video... + Densigi videon + + roboto + Konigi + Aldoni al grupo + Agordoj + Helpo + havas atingon al mesaĝoj + ne havas atingon al mesaĝoj + Kion ĉi tiu roboto povas fari? + KOMENCI + REKOMENCI + Haltigi roboton + Rekomenci roboton + + Sekva + Reen + Finita + Malfermi + Konservi + Nuligi + Fermi + Aldoni + Redakti + Sendi + Telefoni + Kopii + Forigi + Forigi kaj haltigi + Plusendi + Reprovi + De fotilo + De galerio + Forigi bildon + Agordi + Bone + STUCI + + Vi aliĝis al grupo per invitligilo + un1 aliĝis al grupo per invitligilo + un1 forigis je un2 + un1 forlasis la grupon + un1 aldonis je un2 + un1 forigis la grupbildon + un1 ŝanĝis la grupbildon + un1 ŝanĝis la grupnomon al un2 + un1 kreis la grupon + Vi forigis je un2 + Vi forlasis la grupon + Vi aldonis je un2 + Vi forigis la grupbildon + Vi ŝanĝis la grupbildon + Vi ŝanĝis la grupnomon al un2 + Vi kreis la grupon + un1 forigis vin + un1 aldonis vin + un1 revenis al la grupo + Vi revenis al la grupo + Bildo + Video + Movbildo + Loko + Kontakto + Dosiero + Glumarko + Sondosiero + Vi + Vi kreis ekrankopion! + un1 kreis ekrankopion! + + Malĝusta telefonnumero + Kodo finiĝis. Ensalutu denove. + Tro da provoj, provu denove poste + Tro da provoj, provu denove je %1$s + Malĝusta kodo + Malĝusta personnomo + Malĝusta familinomo + Ŝargado... + Vi ne havas videolegilon, instalu videolegilon por daŭrigi + Sendu retpoŝton al sms@stel.com kaj diru nun pri via problemo. + Vi ne havas aplikaĵojn kiuj povas manipuli la dosieran tipon %1$s\', instalu aplikaĵon por daŭri + Ĉi tiu uzanto ankoraŭ ne havas Telegramon, ĉu sendu inviton? + Ĉu vi certas? + Ĉu aldoni %1$s al la babilejo %2$s? + Nombro de lastaj mesaĝoj por plusendi: + Ĉu aldoni %1$s al la grupo? + Ĉi tiu uzanto jam estas en ĉi tiu grupo + Ĉu plusendi mesaĝojn al %1$s? + Ĉu sendi mesaĝojn al %1$s? + Ĉu sendi kontakton al %1$s? + Ĉu vi certas, ke vi volas elsaluti?\n\nRimarku, ke vi glate povas uzi Telegram per ĉiuj da viaj aparatoj samtempe.\n\nMemoru, elsalutado forigos viajn sekretajn babilojn. + Ĉu vi certas, ke vi volas fini ĉiujn da la aliaj seancoj? + Ĉu vi certas, ke vi volas forigi kaj forlasi la grupon? + Ĉu vi certas, ke vi volas forigi ĉi tiun babilejon? + Ĉu vi certas, ke vi volas konigi vian telefonnumeron? + Ĉu vi certas, ke vi volas bloki ĉi tiun kontakton? + Ĉu vi certas, ke vi volas malbloki ĉi tiun kontakton? + Ĉu vi certas, ke vi volas forigi ĉi tiun kontakton? + Ĉu vi certas, ke vi volas komenci sekretan babilejon? + Ĉu vi certas, ke vi volas nuligi la registriĝon? + Ĉu vi certas, ke vi volas vakigi la historion? + Ĉu forigi ĉiuj kaŝmemorigitaj mesaĝoj kaj aŭdvidaĵoj de ĉi tiu kanalo? + Ĉu forigi ĉiuj kaŝmemorigitaj mesaĝoj kaj aŭdvidaĵoj de ĉi tiu grupego? + Ĉu vi certas, ke vi volas forigi %1$sn? + Ĉu sendi mesaĝojn al %1$s? + Ĉu sendi kontakton al %1$s? + Ĉu plusendi mesaĝojn al %1$s? + Bedaŭrinde, ĉi tiu funkcio estas nune ne disponebla en via lando. + Telegram-konto kun ĉi tiu uzantnomo ne ekzistas. + Ĉi tiu roboto ne povas aliĝi al grupoj. + + Telegram bezonas atingi viajn kontaktojn, do vi povas konekti kun viaj amikoj per ĉiuj viaj aparatoj. + Telegram devas atingi vian konservadon por ke vi povas sendi kaj konservi fotojn, videojn, muzikon kaj aliajn aŭdvidaĵojn. + Telegram devas atingi vian mikrofonon por ke vi povas sendi voĉmesaĝojn. + Telegram devas atingi vian lokon por ke vi povas konigi ĝin al viaj amikoj. + AGORDOJ + + Telegram + Rapida + Senpaga + Sekura + Forta + Nuba + Privata + La plej rapida]]> tujmesaĝilo de la mondo.]]>Ĝi estas senpaga]]> kaj sekura]]>. + Telegram]]> liveras mesaĝojn pli rapide ol]]>kiu ajn aplikaĵo. + Telegram]]> estas senpaga eterne. Neniu reklamo.]]>Neniu abona kosto. + Telegram]]> sekurigas viajn mesaĝojn]]>kontraŭ atakoj de kodumuloj. + Telegram]]> ne havas limojn por la grando de]]>viaj aŭdvidaĵoj kaj babilejoj. + Telegram]]> permesas vin atinigi viajn mesaĝojn]]>de multaj aparatoj. + Telegram]]>-mesaĝoj estas ĉifritaj forte]]>kaj povas memdetrui. + Ekmesaĝu + + %1$d enretaj + %1$d enreta + %1$d enretaj + %1$d enretaj + %1$d enretaj + %1$d enretaj + %1$d membroj + %1$d membro + %1$d membroj + %1$d membroj + %1$d membroj + %1$d membroj + kaj %1$d aliuloj tajpas + kaj %1$d aliulo tajpas + kaj %1$d aliuloj tajpas + kaj %1$d aliuloj tajpas + kaj %1$d aliuloj tajpas + kaj %1$d aliuloj tajpas + neniu nova mesaĝo + %1$d nova mesaĝo + %1$d novaj mesaĝoj + %1$d novaj mesaĝoj + %1$d novaj mesaĝoj + %1$d novaj mesaĝoj + neniu mesaĝo + %1$d mesaĝo + %1$d mesaĝoj + %1$d mesaĝoj + %1$d mesaĝoj + %1$d mesaĝoj + %1$d komentoj + %1$d komento + %1$d komentoj + %1$d komentoj + %1$d komentoj + %1$d komentoj + neniu konigaĵo + %1$d konigaĵo + %1$d konigaĵoj + %1$d konigaĵoj + %1$d konigaĵoj + %1$d konigaĵoj + el neniu babilejo + el %1$d babilejo + el %1$d babilejoj + el %1$d babilejoj + el %1$d babilejoj + el %1$d babilejoj + %1$d sekundoj + %1$d sekundo + %1$d sekundoj + %1$d sekundoj + %1$d sekundoj + %1$d sekundoj + %1$d minutoj + %1$d minuto + %1$d minutoj + %1$d minutoj + %1$d minutoj + %1$d minutoj + %1$d horoj + %1$d horo + %1$d horoj + %1$d horoj + %1$d horoj + %1$d horoj + %1$d tagoj + %1$d tago + %1$d tagoj + %1$d tagoj + %1$d tagoj + %1$d tagoj + %1$d semajnoj + %1$d semajno + %1$d semajnoj + %1$d semajnoj + %1$d semajnoj + %1$d semajnoj + %1$d monatoj + %1$d monato + %1$d monatoj + %1$d monatoj + %1$d monatoj + %1$d monatoj + %1$d jaroj + %1$d jaro + %1$d jaroj + %1$d jaroj + %1$d jaroj + %1$d jaroj + %1$d uzantoj + %1$d uzanto + %1$d uzantoj + %1$d uzantoj + %1$d uzantoj + %1$d uzantoj + %1$d fojoj + %1$d fojo + %1$d fojoj + %1$d fojoj + %1$d fojoj + %1$d fojoj + %1$d metroj + %1$d metro + %1$d metroj + %1$d metroj + %1$d metroj + %1$d metroj + %1$d glumarkoj + %1$d glumarko + %1$d glumarkoj + %1$d glumarkoj + %1$d glumarkoj + %1$d glumarkoj + %1$d bildo + %1$d bildo + %1$d bildo + %1$d bildoj + %1$d bildo + %1$d bildo + laste vidita %1$d minutoj antaŭe + laste vidita %1$d minuto antaŭe + laste vidita %1$d minutoj antaŭe + laste vidita %1$d minutoj antaŭe + laste vidita %1$d minutoj antaŭe + laste vidita %1$d minutoj antaŭe + laste vidita %1$d horoj antaŭe + laste vidita %1$d horo antaŭe + laste vidita %1$d horoj antaŭe + laste vidita %1$d horoj antaŭe + laste vidita %1$d horoj antaŭe + laste vidita %1$d horoj antaŭe + + %1$d plusenditaj mesaĝoj + Plusendita mesaĝo + %1$d plusenditaj mesaĝoj + %1$d plusenditaj mesaĝoj + %1$d plusenditaj mesaĝoj + %1$d plusenditaj mesaĝoj + %1$d plusenditaj dosieroj + Plusendita dosiero + %1$d plusenditaj dosieroj + %1$d plusenditaj dosieroj + %1$d plusenditaj dosieroj + %1$d plusenditaj dosieroj + %1$d plusenditaj bildoj + Plusendita bildo + %1$d plusenditaj bildoj + %1$d plusenditaj bildo + %1$d plusenditaj bildoj + %1$d plusenditaj bildo + %1$d plusenditaj videoj + Plusendita video + %1$d plusenditaj videoj + %1$d plusenditaj videoj + %1$d plusenditaj videoj + %1$d plusenditaj videoj + %1$d plusenditaj sondosieroj + Plusendita sondosiero + %1$d plusenditaj sondosieroj + %1$d plusenditaj sondosieroj + %1$d plusenditaj sondosieroj + %1$d plusenditaj sondosieroj + %1$d plusenditaj lokoj + Plusendita loko + %1$d plusenditaj lokoj + %1$d plusenditaj lokoj + %1$d plusenditaj lokoj + %1$d plusenditaj lokoj + %1$d plusenditaj kontaktoj + Plusendita kontakto + %1$d plusenditaj kontaktoj + %1$d plusenditaj kontaktoj + %1$d plusenditaj kontaktoj + %1$d plusenditaj kontaktoj + %1$d plusenditaj glumarkoj + Plusendita glumarko + %1$d plusenditaj glumarkoj + %1$d plusenditaj glumarkoj + %1$d plusenditaj glumarkoj + %1$d plusenditaj glumarkoj + kaj %1$d aliuloj + kaj %1$d aliulo + kaj %1$d aliuloj + kaj %1$d aliuloj + kaj %1$d aliuloj + kaj %1$d aliuloj + + MMMM yyyy + dd MMM + yy-MM-dd + yyyy-MM-dd + d-\'a\' \'de\' MMMM + d-\'a\' \'de\' MMMM yyyy + EEE + HH:mm + h:mm a + %1$s %2$s + + Plus Messenger por Android + Etosoj + Plus-agordoj + Malĝusta deksesuma kolorokodo! + Koloro de etoso + Rekomencigi agordojn de la etoso + Malfari ĉiujn agordojn de la etoso + Reagordi defaŭlte agordojn de etoso! + Ĝenerala + Ekranoj + Ĉefa ekrano + Ekrano de babilejoj + Ekrano de kontaktoj + Kapo + Vicoj + Listo de babilejoj + Listo de babilejoj + Listo de kontaktoj + Koloro de kapo + Koloro de nomoj + Grando de nomoj + Koloro de mesaĝoj + Grando de mesaĝoj + Koloro de tempoj/datoj + Grando de tempoj/datoj + Koloro de nombroj + Grando de nombroj + Koloro de vicoj + Fonkoloro de nombrilo + Koloro de statustoj + Grando de statustoj + Koloro de la dekstraj bobeloj + Koloro de la maldekstraj bobeloj + Koloro de datoj + Grando de datoj + Koloro de la bobeloj de datoj + Koloro de dekstra teksto + Koloro de maldekstra teksto + Koloro de dekstra tempo + Koloro de maldekstra tempo + Grando de tempo + Koloro de eniga kampo + Grando de eniga kampo + Fona koloro de eniga kampo + Fonkoloro de la emoji-klavaro + Koloro de la elektita emoji-langeto + Koloro de piktogramo de emoji-langeto + Koloro de enreta statusto + Muziko + Konservi etoson + Konservi vian etoson al la Telegram/Themes-dosierujo + Etoso konservita! + %1$s konservita al %2$s + Etoso ankoraŭ ne kreita. Apliku ajnan ŝanĝon unue + Agordoj restaŭrita per SD-karto + Neniu dosiero kun agordoj trovita en %s + SD-karto ne trovita. + Tajpu nomon + Etosoj + Apliki etoson + Apliki xml-etoson per loka dosierujo + Koloro de membro + Koloro de la markoj + Koloro de la silentigado + Sendi protokolojn + Ne estas protokoloj + Vakigi protokolojn + protokoloj forigitaj + Piktogramo por sendi + Kaŝi telefonnumeron en menuo + Koloro de glita krajono + Glita fonkoloro + G+-komunumo + Koloro de la tajpstatuso + Koloro de piktogramoj por tekstenigo + Naviga tirkesto + Listo de opcioj + Koloro de listo + Koloro de nomoj + Koloro de telefono + Grando de telefono + Koloro de profilbildo + Opcio por koloro de piktogramo + Koloro de opcioj + Grando de opcioj + Koloro de versio + Grando de versio + Koloro de titilo de kapo + Koloro de piktogramoj en la kapo + Koloro de piktogramo de langetoj + Koloro de piktogramo de neaktivaj langetoj + Koloro de nombrilo de langetoj + Fonkoloro de nombrilo de langetoj + Nombri babilejojn anstataŭ mesaĝoj + Nur nombri nesilentigitajn mesaĝojn + Kaŝi nombrilojn de langetoj + Koloro de apartigilo + Radiuso de profilbildo + Agordi koloron de membroj + Koloro de plusendita nomo + Titolo de kapo + Plusendi sen citado + Malŝalti ŝprucfenestron sur klako + Profilo + Kaŝi tajloritan fonon + Koloro de dekstraj ligiloj + Koloro de maldekstraj ligiloj + Etoso aplikita! + Klaku la OK-butonon por rekomenci la aplikaĵon + Montri emoji-ojn de la telefono + Stilo de bobeloj + Konservi originalan dosiernomon + Anstataŭ nur nombroj, dosieroj estas konversitaj en la formato nomo_dato + Grando de profilbildoj + Ĝisrandigi profilbildon supre + Marĝeno de profilbildo + Koloro de grupnomo + Grando de grupnomo + Koloro de nomo (nekonata numero) + Kaŝi ombron de tajlorita fono + Agordi fonkoloron + Fonkoloro + Grando de emoji-ŝprucfenestro + Nomkoloro en dekstra mesaĝo + Nomkoloro en maldekstra mesaĝo + Koloro de al piktogramoj + Ekrano por agordoj kaj etoso + Fonkoloro + Koloro de ombroj + Koloro de sekcioj + Koloro de titolo + Koloro de resumoj kaj subtekstoj + Tekstkoloro de bildoj kaj glumarkoj + Ĉu vi ŝatas vidi kelkajn etosojn kreitaj de aliaj uzantoj de Plus Messenger? + Uzi tiparon de la telefono + Plus Messenger restartos + Koloro de la gruppiktogramo + Koloro de konigitaj kontaktnomoj + Fonkoloro de kunsendaĵoj + Tekstkoloro de kunsendaĵoj + Montri kontaktbildon en ekrano de babilejo + Montri propran profilbildon en ekrano de babilejo + Montri propran profilbildon en ekrano de grupo + Ĝisrandigi propran profilbildon supre + Koloro de titoloj kaj butonoj de dialogoj + Montri uzantnomon kun membronomo + Ne haltigi sonojn + Koloro de listapartigilo + Centrigi profilbildon, nomon kaj telefonnumeron + Kolortransiro + Koloro de kolortransiro + Malŝaltita + Supra malsupra + Maldekstra dekstra + Supra-maldekstra malsupra-dekstra + Malsupra-maldekstra supra-dekstra + Apliki kolortransiron al listfonon + %s kopiita al tondejo + \n\nAliĝu al la oficiala anglalingva Plus Messenger-kanalo:\nhttps://telegram.me/plusmsgr + Elŝuti etosojn + Oficiala kanalo + Dialogoj + Klaku sur kontaktbildo + Klaku sur grupbildo + Profilo + Profilbildoj + Fonkoloro de silenta nombrilo + Koloro de marko de ordono de robotoj + Koloro de ordono de robotoj + Koloro de markitaj serĉrezultoj + %s estas ĝisdatigita + Kaŝi indikilo de uzantstatuso + Kaŝi langetojn + Ĉiu + Uzantoj + Grupoj + Grupegoj + Kanaloj + Robotoj + Plej ŝatataj + Alto de langetoj + Agordi kiel defaŭlta langeto + Rekomencigi defaŭltan langeton + Ordigi laŭ statuso + Ordigi laŭ lasta mesaĝo + Ordigi laŭ nelegitaj mesaĝoj + Malkaŝi langeton por grupegoj + Kaŝi langeton por grupegoj + Langetoj + Kaŝi/malkaŝi langetojn + Aldoni al plej ŝatataj + Forigi el al plej ŝatataj + Neniu plej ŝatata\n\nPor aldoni ajnan babilejon al ĉi tiu listo nur tuŝadi babilejon kaj klaku la butonon \'Aldoni al plej ŝatataj\'. + Ne kaŝi langetojn dum rulumado + Ŝovumi senfine inter langetoj + Montri \'konigi rekte\'-butonon + CITI + Maladministrantiĝi + Montri uzantnomon anstataŭ telefonnumero + Marki kiel legita + Marki ĉiujn babilejon kiel legitajn + Stilo de marko + Aldoni \'Konigi rekte\'-butonon al ŝprucmenuo + La \'Konigi rekte\'-butono respondas + Plej ŝatataj unue dum rekta konigado + redaktita + Reveni al grupo + Biografio + Redakti biografion +
diff --git a/TMessagesProj/src/main/res/values-eu/strings.xml b/TMessagesProj/src/main/res/values-eu/strings.xml new file mode 100644 index 00000000..0806d251 --- /dev/null +++ b/TMessagesProj/src/main/res/values-eu/strings.xml @@ -0,0 +1,1242 @@ + + + Telegram + Euskara + Basque + eu + + Zure telefono-zenbakia + Baiezta ezazu zure estatu kodea eta sar ezazu zure telefono zenbakia. + Estatua aukeratu + Estatu kode okerra + + Zure kodea + SMS bat bidali dizugu zure sakelako telefonora aktibazio zenbakiarekin + %1$d:%2$02d barru deituko dizugu + Deitzen... + Kodea + Zenbaki okerra? + Ez duzu koderik jaso? + + Zure izena + Idatzi zure izena eta abizena + + Izena (derrigorrezkoa) + Abizena (aukeran) + Deuseztatu izen ematea + + Ezarpenak + Kontaktuak + Talde berria + atzo + Emaitzarik ez + Oraindik kalakarik gabe + Hasi mezuak bidaltzen beheko\neskumako izkinean dagoen botoia sakatzen\nedo menu botoia sakatu aukera gehiagorako. + Sarearen zain... + Konektatzen... + Eguneratzen... + Ezkutuko kalaka berria + Itxaroten %s online egoteko... + Ezkutuko kalaka deuseztatu egin da + Elkarbanatzen zifraketa giltzak... + %s gehitu da zure ezkutuko kalakara. + Gehitu zara ezkutuko kalakara. + Historia garbitu + Katxetik ezabatu + Ezabatu eta irten + Kalaka ezabatu + Ezabatutako kontua + Aukeratu kalaka + Ikusteko ukitu eta mantendu + %1$s Telegram bertsio zahar bat ari da erabiltzen, beraz argazki sekretuak bateragarritasun moduan erakutsiko dira.\n\n%2$s Telegram eguneratzean, minutu bat edo gutxiagoko tenporizadorea daukaten argazkiak ikusi ahalko dira \"Ikusteko ukitu eta mantendu\" moduan, eta zure kontaktuak pantaila argazkia egiten duenean jakinaraziko zaizu. + MEZUAK + Bilatu + Jakinarazpenak isildu + Isildu denbora batez: %1$s + Soinua gaitu + %1$s-tan + Desgaitu + TRAOLA + Oraintsu bilatutakoa + Esteka aurreikusi + + Administratzaile egin + Zure taldearen deskribapena eman dezakezu. + Taldea Utzi + Taldea Ezabatu + Taldea utzi + Taldea ezabatu + Talde honetako mezu guztiak galduko dituzu. + Administratzailea gehitu dezakezu taldea maneiatzen laguntzeko. Aukeratu eta askatu ezabatzeko. + Itxoin! Talde hau ezabatzen baduzu taldekide eta mezu guztiak ezabatuko dituzu. Taldea ezabatu? + Taldea sortuta + un1 taldera gehitu da + Ziur zaude taldea utzi nahi duzula? + Barkatu, ezin duzu erabiltzaile hau taldeetara gehitu. + Barkatu, talde hau beteta dago. + Barkatu, erabiltzaile honek taldea uztea erabaki du, beraz ezin duzu berriz gonbidatu. + Barkatu, kudeatzaile gehiegi dago talde honetan. + Barlati. bot gehiegi dago talde honetan. + Talde hau, super-talde izatera eguneratu da + %1$s super-talde izatera eguneratu da + Blokeatutako erabiltzaileak taldetik ezabatzen dira eta kudeatzaile batek gonbidatzen baditu bakarrik ituzil daitezke. Gonbidapeneko loturek ez dute funtzionatzen eurentzat. + Kanal berria + Kanalaren izena + Erantzunak + Erantzunak aktibatzen badituzu, jendeak zure bidalketak eztabaidatu ditzake kanalean. + Kontaktuak zure kanalera gehitu + Jendeak lotura hauek zure kontaktuekin elkarbanatu ditzakezu Telegramen bilaketa erabiliz. + lotura + Jendea zure kanalera etorri daiteke lotura hau erabiliz. Lotura edozein momentutan bota dezakezu atzera. + Deskribapena + Zure kanalaren deskribapena sartu dezakezu. + Kanal publikoa + Kanal publikoak bilaketaren emaitzetan agertuko dira eta edonor sartu daiteke bertan. + Kanal pribatua + Kanal pribatuetara gonbidapeneko lotura erabiliz bakarrik sartu daiteke. + Lotura + Gonbidapeneko lotura + Kideak gehitu + Kanala utzi + Kanala utzi + Ezarpenak + Sartu + Kanalaren informazioa + Hedapena + Erantzuna + Erantzunak erakutsi + Zer da kanal bat? + Kanalak zure mezuak audientzia handi bati hedatzeko tresnak dira. + Kanala sortu + Barkatu, izen hori hartuta dago + Barkatu, izena ez da zuzena + Kanalen izenak gutxienez 5 karaktere izan behar dituzte + Izenak 32 karaktere baino gutxiago izan behar ditu. + Barkatu, izenak ezin du zenbaki batekin hasi. + Izene egiaztatzen... + %1$s eskuragarri dago. + Kideak + Blokeatutako erabiltzaileak + Kudeatzaileak + Kanala ezabatu + Kanala ezabatu + Kontuz! Kanal hau ezabatzen baduzu taldekide eta mezu guztiak ezabatuko dituzu. Kanala ezabatu? + Ziur zaude kanala utzi nahi duzula? + Kanal honetako mezu guztiak galduko dituzu. + Aldatu + Zure kanalarentzat lotura publikoa sortzen baduzu, edonork bilatu eta bertara sartu ahal izango du.\n\nEz sortu lotura hau, kanala pribatu izaten jarraitu nahi baduzu. + Aukeratu kanalarentzako lotura publikoa, horrela jendeak kanala aurkitu ahal izango du eta beste batzuekin partekatu.\n\nHorrelakorik ez baduzu nahi, kanal pribatua sortzea gomendatzen dizugu. + Kanala ondo sortu da + Kanalaren irudia aldatu egin da + Kanalren irudia ezabatu egin da + Kanalren izena un2 izatera aldatu da + Barkatu, kanal publiko gehiegi sortu dituzu. Kanal pribatu bat sor dezakezu, edo sortuta duzun kanal bat ezabatu. + Moderatzailea + Sortzailea + Kudeatzailea + Isilarazi + Soinua aktibatu + Kudeatzailea gehitu + Lotura bidez gonbidatu + %1$s kudeatzaile egin nahi duzu? + Ezabatu + Zerrenda hau kanalaren kudeatzaileek bakarrik ikusi dezakete. + Erabiltzaile hau ez da kanalera sartu. Gonbidatu egin nahi duzu? + Telegram duen edonor sar daiteke kanalera lotura hau erabiliz + Kanala kudeatzen laguntzeko kudeatzaileak gehitu ditzakezu. Sakatu eta mandatendu sakatuta kudeatzaileak ezabatzeko. + \'%1$s\' kanalera sartu nahi duzu? + Barkatu, txat hau ez dago eskuragarri.º + %1$s kanalera gehitu nahi duzu? + Barkatu, erabiltzaile honek kanala uztea erabaki du eta ezin duzu berriz gonbidatu. + Barkatu, ezin duzu erabiltzaile hau kanaletara gehitu. + Barkatu, kudeatzaile gehiegi daude kanal honetan. + Barkatu, bot gehiegi daude kanal honetan. + Barkatu, kanal batera lehenengo 200 erabiltzaileak bakarrik gehitu ditzakezu. Hala ere, kanalean nahi adina jende sar daiteke kanalaren lotura erabiliz. + un1 erabiltzaileak kanalera gehitu zaitu + Kanalera sartu zara + Kanaletik ezabatu + Barkatu, ezin duzu kanal honetara mezurik bidali. + %1$s erabiltzaileak %2$s kanalera gehitu zaitu + %1$s kanalaren irudia eguneratu da + %1$s erabiltzaileak %2$s kanalera mezua bidali du + %1$s erabiltzaileak irudia bidali du %2$s kanalera + %1$s erabiltzaileak bideoa bidali du %2$s kanalera + %1$s erabiltzaileak kontaktu bat bidali du %2$s kanalera + %1$s erabiltzaileak kokalekua bidali du %2$s kanalera + %1$s erabiltzaileak fitxategia bidali du %2$s kanalera + %1$s erabiltzaileak GIF bat bidali du %2$s kanalera + %1$s erabiltzaileak audioa bidali du %2$s kanalera + %1$s erabiltzaileak stickerra bidali du %2$s kanalera + %1$s erabiltzaileak mezua bidali du + %1$s erabiltzaileak irudia bidali du + %1$s erabiltzaileak bideoa bidali du + %1$s erabiltzaileak kontaktua bidali du + %1$s erabiltzaileak kokalekua bidali du + %1$s erabiltzaileak fitxategia bidali du + %1$s erabiltzaileak GIF bat bidali du + %1$s erabiltzaileak ahots-mezua bidali du + %1$s erabiltzaileak stickerra bidali du + + Difusio Zerrenda berria + Sartu zerrendaren izena + Difusio zerrenda bat sortu duzu + Hartzailea gehitu + Difusio zerrendatik atera + + Gehitu fitxategiak zure gailuaren musika bildumari hemen ikusteko. + Musika + Artista ezezaguna + Izenburu ezezaguna + + Aukeratu fitxategia + Libre %2$s-(e)tik %1$s + Akats ezezaguna + Atzipen akatsa + Fitxategirik ez... + Fitxategia ezin da %1$s baino handiagoa izan + Euskarria ez dago montatuta + Usb transferentzia gaituta + Barneko euskarria + Kanpoko euskarria + Sistemaren erroa + SD txartela + Karpeta + Irudiak konpresiorik gabe bidaltzeko + + ikustezina + idazten... + idazten ari da... + idazten ari dira... + %1$s audioa grabatzen ari da... + %1$s argazki bat bidaltzen ari da... + %1$s bideoa bidaltzen ari da... + %1$s fitxategia bidaltzen ari da... + audioa grabatzen... + argazkia bidaltzen... + bideoa bidaltzen... + fitxategia bidaltzen + Baduzu galderarik Telegram-i buruz? + Atera argazkia + Galeria + Kokalekua + Bideoa + Fitxategia + Kamara + Oraindik ez dago mezurik... + Partekatutako mezua + Igorlea + Berririk ez + Mezua + Mezua + Parteka ezazu nire kontaktu-informazioa + Kontaktuetara gehitu + %s-(e)k ezkutuko kalaka batera gonbidatu zaitu. + %s gonbidatu duzu ezkutuko kalaka batera. + Ezkutuko kalakak: + Muturretik-muturrerako zifraketa erabiltzen du + Ez du aztarnarik uzten gure zerbitzarietan + Badu autosuntsipenerako tenporizadorea + Ez du partekatzerik uzten + Talde honetatik kanporatu zaituzte + Talde hau utzi duzu + Ezabatu talde hau + Ezabatu kalaka hau + ARRASTATU DEUSEZTATZEKO + Deskargatutako fitxategiekin gorde + GIFetara gehitu + GIFa ezabatu? + Musikan gorde + Partekatu + Itzulpen fitxategia aplikatu + Fitxategi hau ezin da kudeatu + Autosuntsipenerako tenporizadorea ezarri + Zerbitzuaren jakinarazpenak + Estekaren informazioa lortzen... + Nabigatzailean ireki + URLa kopiatu + %1$s bidali + %1$s urla ireki? + Spama salatu + Kontaktua gehitu + Erabiltzaile honek spama bidali duela salatu nahi duzu? + Talde honetan spama dagoela salatu nahi duzu? + Barkatu, elkarren kontaktu zareten erabilzaileei bakarrik bidali diezaiekezu mezua. + Barkatu, elkarren kontaktu zareten erabiltzaileak bakarrik gehitu ditzakezu taldeetara. + https://telegram.org/faq#can-39t-send-messages-to-non-contacts + Informazio gehiago + Honi bidali... + Egin klik hemen gordetako GIFak ikusteko + + %1$s -(e)k autosuntsipenerako tenporizadorea %2$s-(e)ra ezarri du + Autosuntsipen tenporizadorea %1$s-(e)ra jarri duzu + %1$s-(e)k autosuntsipen tenporizadorea desgaitu du + Autosuntsipen tenporizadorea desgaitu duzu + Mezu berri bat daukazu + %1$s: %2$s + %1$s-(e)k mezu bat bidali dizu + %1$s-(e)k irudi bat bidali dizu + %1$s-(e)k bideo bat bidali dizu + %1$s-(e)k kontatu bat partekatu du zurekin + %1$s-(e)k mapa bidali dizu + %1$s-k fitxategi bat bidali dizu + %1$s erabiltzaileak GIF bat bidali dizu + %1$s-(e)k audio bat bidali dizu + %1$s-k sticker bat bidali dizu + %1$s @ %2$s: %3$s + %1$s-(e)k mezu bat bidali du %2$s taldera + %1$s-(e)k argazki bat bidali du %2$s taldera + %1$s-(e)k bideo bat bidali du %2$s taldera + %1$s-(e)k kontaktu bat partekatu du %2$s taldean + %1$s-(e)k mapa bidali du %2$s taldera + %1$s- fitxategi bat bidali du %2$s taldera + %1$s erabiltzaileak GIF bat bidali du %2$s taldera + %1$s-(e)k audio bat bidali du %2$s taldera + %1$s-k sticker bat bidali du %2$s taldera + %1$s-(e)k %2$s taldera gonbidatu zaitu + %1$s-(e)k %2$s taldearen izena aldatu du + %1$s-(e)k %2$s taldearen irudia eguneratu du + %1$s-(e)k %3$s %2$s taldera gonbidatu du + %1$s %2$s taldera itzuli da + %1$s-(e)k %3$s kanporatu du %2$s taldetik + %1$s-(e)k %2$s taldetik kanporatu zaitu + %1$s-(e)k %2$s taldea utzi du + %1$s-(e)k Telegram erabiltzen du! + %1$s,\negun eta ordu honetan %2$s gailu berri batekin zure kontuan sartu zarela detektatu dugu\n\nGailua: %3$s\nKokalekua/IP Helbidea: %4$s\n\nEz bazara zu izan, joan Ezarpenak - Pribatutasuna eta Segurtasuna - Sesioak atalera eta itxi sesio hori.\n\nZuk horrela nahi gabe norbait zure kontuan dabilela uste baduzu, bi pausutako egiaztapen sistema aktibatu dezakezu.\n\nAgur bat,\nTelegram Taldea + %1$s-(e)k bere profil argazkia eguneratu du + %1$s %2$s taldera sartu da gonbidapen estekaren bitartez. + Erantzun + %1$s-(r)i erantzun + %1$s-(r)i erantzun + %1$s %2$s + + Aukeratu kontaktua + Ez dago kontakturik oraindik + Aizu! Telegram-era alda gaitezen: https://telegram.org/dl + - + Atzo + online + azkenengo aldiz + azkenengo aldiz + azken aldiz oraintsu ikusia + Gonbidatu lagunak + BILAKETA OROKORRA + orain dela gutxi ikusita + azken astean konektatuta + azken hilabetean konektatuta + Aspaldian ezikusia + Mezu berria + + Bidali mezua honi... + Idatzi taldearen izena + Taldearen izena + %1$d/%2$d kide + \'%1$s\' txatera sartu nahi duzu? + Barkatu, taldea beteta dago. + Barkatu, txat hori ez dago + Esteka arbelean kopiatuta + Gonbidatu taldera esteka erabiliz + Gonbidapen esteka + Lotura hau bertan behera utzi nahi duzu? Behin hori eginda, inork ezingo du erabili. + Aurreko gonbidapen esteka desgaituta dago. Esteka berri bat sortu dugu. + Bertan behera utzi + Esteka bertan behera utzi + Esteka kopiatu + Lotura partekatu + Telegram darabilen edonor sartu daiteke zure taldera esteka hau erabiliz. + + Txataren kudeatzaileak + Kide guztiak kudeatzaileak dira + Kide guztiek kide berriak gehitu, izena eta irudia alda ditzakete. + Kudeatzaileak bakarrik gehitu eta ezabatu ditzakete erabiltzaileak eta izena eta irudia aldatu + + Partekatutako eduki multimedia + Ezarpenak + Gehitu kidea + Kudeatzaileak ezarri + Ezabatu eta utzi taldea + Jakinarazpenak + Kanporatu taldetik + Super-talde izatera eguneratu + Taldearen kideek beren Telegram aplikazioak eguneratu beharko dituzte zure super-taldea ikustea. Talde hau eguneratu nahi duzu? + ]]>Kideen mugara heldu zara.]]>\n\nMuga gainditzeko eta ezaugarrai gehiago lortzeko, eguneratu super-talde izatera:\n\n• Super-taldeak %1$s-ra iritsi daitezke\n• Erabiltzaile berriek txat historia guztia ikusi dezakete\n• Kudeatzaileek edozein mezu ezabatu dezakete.\n• Jakinarazpenak isilarazita daude defektuz + + Partekatu kontaktua + Gehitu kontaktua + Kontaktua gehitu + Blokeatu kontaktua + Aldatu + Ezabatu + Etxeko telefonoa + Telefono mugikorra + Laneko telefonoa + Beste telefono bat + Telefono nagusia + Hasi ezkutuko kalaka + Akats bat gertatu da. + Zifratzeko gakoa + Mezua deuseztatzeko denbora + Inoiz ez + Irudi hau ]]>%1$s]]>-(r)ekin duzun ezkutuko kalaka honetarako zifratzeko gakoaren ikusmena da.
]]>Irudi hau berdin ikusten bada ]]>%2$s\-(r)en]]> telefonoan, zure kalaka segurua da %%200ean.
]]>Ikasi gehiago telegram.org-n
+ Ezezaguna + Informazioa + Telefonoa + + Izena + Zure izena + Sentitzen dugu, izena hartuta dago. + Sentitzen dugu, izena ez da baliozkoa. + Izen batek gutxienez 5 karaktere izan behar ditu. + Izenak 32 karaktere baino gutxiago izan behar ditu. + Sentitzen dugu, izenak ezin du zenbaki batekin hasi. + ]]>Telegramen]]> erabiltzeko erabiltzaile-izena aukeratu dezakezu. Hori eginda, beste erabiltzaileek aurkitu egin zaitzakete zure telefono zenbakia ez badakite ere..
]]>Erabiltzaile-izenean ]]>a–z]]>, ]]>0–9]]> eta azpimarrak erabili ditzakezu. Gutxieneko luzera ]]>5]]> karakterekoa da.
+ Erabiltzaile izena begiratzen... + %1$s eskuragarri dago. + Ezer ez + Akats bat gertatu da. + + Eranskailuak + Edonork gehitu ditzake sticker multzoak @stickers bota erabiliz.\n\nErabiltzailaek stickerren gainean klik egin eta \"Stickerretara gehitu\" sakatuz has daitezke erabiltzen. + Eranskailuak gehitu + Eranskailuetara gehitu + Eranskailuak ez topatuta + Eranskailuak ezabatuta + Eranskailu berriak gehituta + Ezkutatu + Erakutsi + Partekatu + Esteka kopiatu + Ezabatu + Oraindik ez dago eranskailurik + + Berrezarri lehenetsitako jakinarazpen ezarpen guztiak + Mezuen testuaren tamaina + Galdetu zalantza + Gaitu animazioak + Desblokeatu + Desblokeatzeko ukitu eta mantendu erabiltzailean. + Erabiltzailea ez dago blokeatuta oraindik + Mezuen jakinarazpenak + Abisua + Mezuaren aurrebista + Talde jakinarazpenak + Soinua + In-app jakinarazpenak + In-App Soinuak + In-App dardara + Dardara + In-App aurrebista + Berezarri + Berrezarri jakinarazpen guztiak + Desegin pertsonalizatutako jakinarazpen ezarpen guztiak zure kontaktu eta talde guztietarako + Jakinarazpenak eta Soinuak + Blokeatutako erabiltzaileak + Saioa itxi + Soinurik ez + Lehenetsita + Laguntza + Isilpean besterik ez + Kalakaren atzeko planoa + Mezuak + Bidali enter teklari sakatuta + Bukatu beste saio guztiak + Gertaerak + Kontaktuak Telegram jarri du + Hizkuntza + Telegramen Laguntza bolondresek egiten dute. Ahalik eta azkarren erantzuten saiatzen gara, baina denbora gehiago hartzen du batzuetan...
]]>Begiratu Ohiko Galderak]]>: galdera gehienen inguruko erantzunak eta arazoentzatko aholkuak]]> daude bertan
+ Galdeiozu boluntario bati + Telegram-en FAQ + https://telegram.org/faq + Itzulpena ezabatu nahi al duzu? + Itzulpen-fitxategia okerra da + Gaituta + Desgaituta + Jakinarazpen zerbitzua + Jakinarazpenak jasotzeko Google Play Zerbitzuak nahiko badira zuretzat, Jakinarazpenentzako Zerbitzua desgaitu dezakezu. Hala ere aplikazioa atzekaldean ibiltzeko eta uneko jakinarazpenak jasotzeko gaituta izatea gomendatzen dizugu. + Ordenatze irizpidea + Kontaktuak inportatu + Izena + Abizenak + LEDaren kolorea + Popup Jakinarazpenak + Gainerakorrarik ez + Bakarrik pantaila piztuta dagoenean + Bakarrik pantaila itzalita dagoenean + Beti erakutsi gainerakorrak + Intsignia Kontagailua + Labur + Luze + Sistemaren lehenespena + Ezarpenen lehenespena + Fitxategi multimediak automatikoki deskargatu + Datu mugikorrak erabiliz + Wi-Fira konektatuta + Roaming-ean + Euskarririk ez + GIFak bakarrik martxan jarri + Galerian gorde + Izena editatu + Lehentasuna + Lehenetsita + Txikia + Handia + Handia + Inoiz ez + Jakinarazpenak errepikatu + Zure Telegram zenbakia hemen aldatu dezakezu. Zure kontua eta datu guztiak — mezuak, multimedia, kontaktuak, ... zenbaki berrira mugituko dira.\n\nGarrantzitsua:]]> zure kontaktu guztiei zure zenbaki berria]]> gehituko zaie beren kontaktuetara zure zenbaki zaharra badute eta blokeatu ez bazaituzte behintzat. + Zure Telegram kontaktuek zure zenbaki berria automatikoki jasoko dute beren helbide-liburuan beti ere zure helbide zaharra badute eta ez bazaituzte Telegramen blokeatuta. + ZENBAKIA ALDATU + Zenbaki berria + SMS bat bidaliko dizugu zure zenbaki berrira. + %1$s zenbakia Telegram kontu batera konektatuta dago jada. Mesedez kontua ezabatu zenbaki berrira mugitu baino lehen. + Beste bat + Desgaituta + Desgaituta + Desgaituta + Itzalita + Txateko soinuak + Lehenetsiak + Lehenetsiak + Jakinarazpen bizkorrak + Desgaituta + Jo gehienez %1$s %2$s tartean + Jo gehienez + alditan + tartean + minutuak + + Katxearen ezarpenak + Datu-base lokala + Katxeatutako testu-mezuak garbitu? + Datu-base lokala garbitzean, katxeatutako mezuak ezabatu eta datu-basea konprimatu egingo da disko espazioa garbitzeko. Telegramek datu batzuk behar ditu funtzionateko, beraz datu-basearen tamaina ez da guztiz zerora iritsiko.\n\nEragiketa honek minutu batzuk har ditzake. + Katxea garbitu + Garbitu + Kalkulatzen... + Dokumentuak + Irudiak + Ahots-mezuak + Bideoak + Musika + Beste fitxategiak + Hutsik + Multimedia mantendu + Denbora tarte honetan ikusi ez dituzun]]> irudi, bideo eta beste fitxategiak ezabatu egingo dira disko-espazioa aurreztekoa.\n\nFitxategi guztiak Telegramen zerbitzarietan egongo dira eta behar dituzunean deskargatu ahalko dituzu. + Betiko + + Aktibo dauden saioak + Oraingo sesioa + Ez dago aktibo dagoen beste saiorik + Telegramen sartu zaitezte beste eskuko telefono, tablet edo ordenagailu batetik, beti ere telefono zenbaki berdina erabiliz. Zure datu guztiak berehala sinkronizatuko dira. + Aktibo dauden saioak + Kontrolatu beste gailuetako saioak + Aukeratu sesio bat bertan behera uzteko. + Sesioa bukatu? + Aplikazio ez-ofiziala + + Pasakode bidez itxi + Pasakodea aldatu + Pasakode gehigarri bat ezartzen duzunean, txataren orrian giltzarrapo bat agertuko da. Aukeratu giltzarrapoa Telegram aplikazioa blokeatu eta desblokeatzeko. \n\nOharra: pasakodea ahazten baduzu, aplikazioa ezabatu eta berriz instalatu beharko duzu. Txat sekretu guztiak galdu egingo dira. + Orain txaten orrialdean giltzarrapo bat ikusiko duzu. Aukeratu giltzarrapoa zure Telegram aplikazioa zure pasakode berriarekin blokeatzeko. + PIN + Pasahitza + Idatzi zure egungo pasakodea + Idatzi pasakode bat + Idatzi zure pasakode berria + Idatzi zure pasakodea + Idatzi berriz pasakode berria + Pasakodea ez da zuzena + Pasakodeak ez dira berdinak + Automatikoki blokeatu + Pasakodea eskatu denbora askoz ez bada erabiltzen + %1$s + Desgaituta + Hatzmarka erabiliz desblokeatu + Baieztatu hatzmarka jarraitzeko + Ukipen sentsorea + Hatzmarka ezezaguna. Saiatu berriz. + + Partekatu argazki eta bideoak txat honetan eta lortu edozein gailutan + Partekatutako fitxategiak + Partekatutako media + Partekatutako estekak + Partekatutako musika + Partekatu musika txat honetan eta lortu zure edozein gailutatik + Banatu fitxategiak eta dokumentuak txat honetan eta zure edozein gailutatik hatzeman hauek + Estekak txatean banatu eta zure edozein gailutatik hatzeman hauek + + Mapa + Satelitea + Hibridoa + m -ra + km -ra + Zure uneko kokalekua bidali + Bidali aukeratutako kokalekua + Kokalekua + %1$sko zehaztasuna + EDO LEKUA AUKERATU + + Media guztia ikusi + Galerian gorde + %2$d-tik %1$d + Galeria + Argazki guztiak + Bideo guztiak + Oraindik argazkirik gabe + Ez dago bideorik + Lehenago jaitsi ezazu media + Ez dago argazki berririk + Ez dago GIF berririk + IRUDIAK BILATU + WEB ORRIKO BILAKETA + GIFak BILATU + Webgunean bilatu + GIFak bilatu + Moztu irudia + Irudia editatu + Hobetu + Nabarmenduak + Kontrastea + Esposizioa + Berotasuna + Saturazioa + Bineta + Itzalak + Pikorra + Garbia + Lausotu + Itzalita + Lineala + Erradiala + Ziur zaude argazki hau ezabatu nahi duzula? + Ziur zaude bideo hau ezabatu nahi duzula? + Aldaketak baztertu? + Bilaketa historia garbitu? + Garbitu + Argazkiak + Bideoa + Epigrafe bat gehitu... + Argazkiaren Epigrafea + Bideoaren epigrafea + + Bi pausotako egiaztapen sistema + Pasahitz Gehigarria Ezarri + Pasahitz bat ezarri dezakezu, horrela gailu berri batetik sartzen zarenean sartu egin beharko duzu SMS bidez jasotzen duzun kodeaz gain. + Zure Pasahitza + Idatzi zure pasahitza, mesedez + Pasahitz bat sartu + Zure pasahitz berria sartu, mesedez + Zure pasahitza berriro sartu, mesedez + Berreskuratze E-Posta + Zure Posta Elektronikoa + Zure baliozko posta elektronikoa gehitu. Ahaztutako pasahitz bat gogoratzeko era bakarra da. + Saltatu + Abisua + Ez, benetan.\n\nPasahitza ahazten baduzu, ezingo duzu Telegram kontua erabili. Ez dago berrezartzeko modurik. + Ia-ia lortu duzu! + Egiaztatu zure eposta helbidea (ez ahaztu spam karpeta), bi pausotako egiaztapen sistema guztiz konfiguratzeko. + Lortuta! + Bi Pausutako Baieztatzearen pasahitza badabil. + Pasahitza aldatu + Itzali Pasahitza + Berreskuratze E-Posta Ezarri + Aldatu Berreskuratze Pasahitza + Ziur zaude zure pasahitza ezeztatu nahi duzula? + Pasahitzaren Aztarna + Mesedez, sortu zure pasahitzaren aztarna + Pasahitzak ez dira berdinak + Bi pausutako baieztatzearen doitzea ezeztatu + Jarraitu pauso hauek bi pausotako egiaztapen sistemaren konfigurazioa bukatzeko:\n\n1. Begiratu zure eposta helbidea (ez ahaztu spam karpeta)\n%1$s\n\n2. Egin klik egiaztapen-loturan. + Aztarna ezin da izan zure pasahitza + E-Posta baliogabea + Barkatu + Ez duzunez berreskuratzeko epostarik ezarri zure pasahitza ezartzean, dituzun aukerak zure pasahitza gogoratzea edo zure kontua guztiz berrezartzea dira. + Berreskuratze kodea bidali dizugu emandako posta elektronikora:\n\n%1$s + Mesedez, zure posta elektronikoa kontsultatu eta bidali dizugun 6 zifrako kodea hemen sartu. + Arazoak dauzkazu zure %1$s posta elektronikoan sartzeko? + Ezin baduzu zure eposta helbidera sartu, dituzun aukerak zure pasahitza gogoratu edo zure kontua guztiz berrezartzea dira. + BEREZARRI NIRE KONTUA + Zure txat eta mezu guztiak galduko dituzu, eta baita banatutako media eta fitxategiak ere, zure kontua berezartzen baduzu. + Kontuz + Ekintza hau ezin da desegin. \n\nZure kontua berezartzen baduzu, zure mezu eta txat guztiak ezabatuko dira. + Berezarri + Pasahitza + Bi pausotako egiaztapen-sistema aktibatu duzu, beraz zure kontua beste pasahitz batekin babestuta dago. + Pasahitza ahaztuta? + Pasahitza Berreskuratzea + Kodea + Pasahitza ezeztatua + Bi pausotako egiaztapen-sistema katibatu duzu.\nPasahitza beharko duzu zure Telegram kontura sartzeko. + Zure %1$s berreskurapen-eposta ez dago oraindik aktibo, konfirmazio-zain dago. + + Pribatutasuna eta Segurtasuna + Pribatutasuna + Azken aldiz ikusia + Guztiak + Nire Kontaktuak + Inor ez + Guztiak (-%1$d) + Nire Kontaktuak (+%1$d) + Nire Kontaktuak (-%1$d) + Nire Kontaktuak (-%1$d, +%2$d) + Inor ez (+%1$d) + Segurtasuna + Kontua bakarrik deuseztu + Ez bazara sartu + Ez bazara sartu gutxienez behin denbora tarte honetan, zure kontua ezabatu egingo da, talde, mezu eta kontaktu guztiekin batera. + Zure kontua ezabatu? + Aldatu nork ikus dezake zure \"Azken aldiz ikusia\". + Nork ikus dezake zure \"Azken aldiz ikusia\"? + Salbuespenak gehitu + Garrantzitsua: ezingo duzu Azken aldiz noiz ikusia, zuk datu hori ez baduzu erakusten. Kasu horretan gutxi gora beherako denbora erakutsiko da (azken aldian, aste honetan, hilabete honetan). + Beti Partekatu Honekin + Ez Partekatu Inoiz Honekin + Ezarpen hauek, goiko balioak gainidatziko dituzte. + Partekatu Beti + Partekatu beti erabiltzaileekin... + Inoiz ez Partekatu + Inoiz ez partekatu erabiltzaileekin... + Erabiltzaileak Gehitu + Barkatu, eskaera gehiegi. Orain ezin dira pribatutasun aukerak aldatu, itxaron apur bat mesedez. + Irten gailu guztietatik, honetatik izan ezik + Erabiltzailea ezabatzeko ukitu eta mantendu. + + Bideoa editatu + Jatorrizko bideoa + Editatutako bideoa + Bideoa bidaltzen... + Bideoa Konprimatu + + bot + Partekatu + Taldera gehitu + Ezarpenak + Laguntza + mezuak ikus ditzake + ezin ditzake mezuak ikusi + Zer egin dezake bot honek? + HASI + BERRABIARAZI + Bot-a gelditu + Bot-a berrabiarazi + + Hurrengoa + Itzuli + Egin + Ireki + Gorde + Ezeztatu + Itxi + Gehitu + Aldatu + Bidali + Deitu + Kopiatu + Ezabatu + Ezabatu eta gelditu + Berbidali + Saiatu Berriro + Kameratik + Galeriatik + Ezabatu Irudia + Ezarri + Ados + MOZTU + + Taldera sartu zara gonbidapen estekaren bitartez. + un1 taldera sartu da gonbidapen estekaren bitartez. + un1-(e)k un2 kanporatu du + un1 erabiltzaileak taldea utzi du + un1-(e)k un2 gehitu du + un1-(e)k taldearen irudia ezabatu du + un1 talde-irudia aldatu du + un1-(e)k taldearen izena aldatu du un2-ra + un1-(e)k taldea sortu du + un2 ezabatu duzu + Taldea utzi duzu + un1-(e)k un2 gehitu du + un1-(e)k taldearen irudia ezabatu du + un1-(e)k taldearen irudia aldatu du + un1-(e)k taldearen izena aldatu du un2-ra + Taldea sortu duzu + un1 ezabatu zaitu + un1-(e)k gehitu zaitu + un1 taldera itzuli da + Taldera itzuli zara + Zure Telegram bertsioak ez du mezu mota hau onartzen. Egunera ezazu aplikazioa ikusteko: https://telegram.org/update + Irudia + Bideo + GIF + Kokalekua + Kontaktua + Fitxategia + Eranskailua + Audio + Zu + Pantailaren argazkia egin duzu! + Hartu pantaila argazkia + + Telefono zenbaki baliogabea + Kodea iraungi da, saioa hasi berriro, mesedez + Saio gehiegi, mesedez saiatu beranduago + Saiakera gehiegi, mesedez saiatu %1$s-tan + Kode baliogabea + Izen baliogabea + Abizen baliogabea + Kargatzen... + Ez duzu bideo erreproduzgailurik, mesedez instalatu bat eta jarraitu + Mesedez, posta bat bidali sms@stel.com helbidera eta kontaiguzu zure arazoa. + Ez duzu inolako aplikaziorik \'%1$s\' fitxategi mota erabili ahal izateko, mesedez instalatu bat eta jarraitu + Erabiltzaile honek ez dauka Telegram oraindik, gonbidapena bidaliko? + Ziur zaude? + %1$s erabiltzailea %2$s txatera gehitu? + Azkeneko zenbat mezu berbidali behar da: + Gehitu %1$s taldera? + Erabiltzailea talde honetan dago jadanik + Partekatu mezuak %1$s-(r)ekin? + %1$s-ri mezuak bidali? + Kontaktua %1$s erabiltzaileari bidali? + Ziur zaude saioa bukatu nahi duzula?\n\nGogoratu arazo barik erabil dezakezula Telegram zure gailu guztietan batera.\n\nGogoratu ere, saioa bukatzean zure Txat Sekretu guztiak ezabatuko direla. + Ziur zaude gainontzeko saio guztiak bukatu nahi dituzula? + Ziur zaude taldea ezabatu eta utzi nahi duzula? + Ziur zaude kalaka hau ezabatu nahi duzula? + Ziur zaude zure kontaktu xehetasunak konpartitu nahi dituzula? + Ziur zaude kontaktu hau blokeatu nahi duzula? + Ziur zaude kontaktu hau desblokeatu nahi duzula? + Ziur zaude kontaktu hau ezabatu nahi duzula? + Ziur zaude kalaka sekretu bat hasi nahi duzula? + Ziur zaude erregistroa bertan behera utzi nahi duzula? + Ziur zaude historia ezabatu nahi duzula? + Kanal honetatik katxeatutako testu eta multimedia guztiak ezabatu? + Super-talde honetatik katxeatutako testu eta multimedia guztiak ezabatu? + Ziur zaude %1$s ezabatu nahi duzula? + %1$s-ri mezuak bidali? + %1$s erabiltzaileari kontaktua bidali? + Partekatu mezuak %1$s-(r)ekin? + Sentitzen dugu, baina ezaugarri hau ezin duzu erabili zure estatuan. + Ez dago erabiltzaile izen hori daukan Telegram konturik. + Bot hau ezin da taldeetan sartu. + + Telegramek zure kontaktuetara sartzeko baimena behar du gailu guztietatik zure lagunekin kontaktuan jartzeko. + Telegramek irudiak, bideoak, musika eta beste fitxategiak gordetzeko zure diskora sartzeko baimena behar du. + Telegramek mikrofonoa erabiltzeko baimena behar du ahots-mezuak bidaltzeko + Telegramek zure kokalekua erabiltzeko baimena behar du, zure lagunekin partekatu ahal izateko + Ezarpenak + + Telegram + Azkarra + Doakoa + Segurua + Ahaltsua + Hodeian + Pribatua + Munduko mezularitza]]> aplikazio azkarrena.]]>Doakoaeta]]> segurua da]]>. + Plus Messenger]]> beste edozein aplikaziok baino]]>azkarrago bidaltzen ditu mezuak. + Plus Messenger]]> dohain da betiko. Ez dago iragarkirik.]]>Ez dago harpidetza kosturik. + Plus Messenger]]> zure mezuak hackerrengandik]]>babesten ditu. + Plus Messenger]]> ez du multimedia eta fitxategien]]>tamaina mugarik. + Plus Messenger]]> hainbat gailutatik zure mezuak irakurtzen]]>uzten dizu. + Plus Messenger]]> mezuak zifratuta daude eta ]]>bakarrik ezabatu daitezke. + Mezuak bidali! + + %1$d konektatuta + %1$d konektatuta + %1$d konektatuta + %1$d konektatuta + %1$d konektatuta + %1$d konektatuta + %1$d kide + kide %1$d + %1$d kide + %1$d kide + %1$d kide + %1$d kide + eta %1$d pertsona gehiago idazten ari da + eta %1$d pertsona gehiago idazten ari da + eta %1$d pertsona gehiago idazten ari da + eta %1$d pertsona gehiago idazten ari da + eta %1$d pertsona gehiago idazten ari da + eta %1$d pertsona gehiago idazten ari da + ez dago mezu berririk + mezu berri %1$d + %1$d mezu berriak + %1$d mezu berriak + %1$d mezu berriak + %1$d mezu berriak + Mezurik ez + mezu %1$d + %1$d mezu + %1$d mezu + %1$d mezu + %1$d mezu + %1$d erantzun + Erantzun %1$d + %1$d erantzun + %1$d erantzun + %1$d erantzun + %1$d erantzun + elementurik ez + Elementu %1$d + Elementu %1$d + %1$d elementu + %1$d elementu + %1$d elementu + txatetati ez + Txat %1$d\'etatik\' + %1$d txatetatik + %1$d txatetatik + %1$d txatetatik + %1$d txatetatik + %1$d segundu + %1$d segundu + %1$d segundu + %1$d segundu + %1$d segundu + %1$d segundu + %1$d minutu + %1$d minutu + %1$d minutu + %1$d minutu + %1$d minutu + %1$d minutu + %1$d ordu + %1$d ordu + %1$d ordu + %1$d ordu + %1$d ordu + %1$d ordu + %1$d egun + %1$d egun + %1$d egun + %1$d egun + %1$d egun + %1$d egun + %1$d aste + %1$d aste + %1$d aste + %1$d aste + %1$d aste + %1$d aste + %1$d hilabete + %1$d hilabete + %1$d hilabete + %1$d hilabete + %1$d hilabete + %1$d hilabete + %1$d urte + %1$d urte + %1$d urte + %1$d urte + %1$d urte + %1$d urte + %1$d erabiltzaile + %1$d erabiltzaile + %1$d erabiltzaile + %1$d erabiltzaile + %1$d erabiltzaile + %1$d erabiltzaile + %1$d alditan + Aldi %1$d\'en\' + %1$d alditan + %1$d alditan + %1$d alditan + %1$d alditan + %1$d metro + Metro %1$d + %1$d metro + %1$d metro + %1$d metro + %1$d metro + %1$d sticker + Sticker %1$d + %1$d sticker + %1$d sticker + %1$d sticker + %1$d sticker + %1$d argazki + Argazki %1$d + %1$d argazki + %1$d argazki + %1$d argazki + %1$d argazki + azken aldiz orain dela %1$d minutu ikusia + azken aldiz orain dela minutu %1$d ikusia + azken aldiz orain dela %1$d minutu ikusia + azken aldiz orain dela %1$d minutu ikusia + azken aldiz orain dela %1$d minutu ikusia + azken aldiz orain dela %1$d minutu ikusia + azken aldiz orain dela %1$d ordu ikusia + azken aldiz orain dela ordu %1$d ikusia + azken aldiz orain dela %1$d ordu ikusia + azken aldiz orain dela %1$d ordu ikusia + azken aldiz orain dela %1$d ordu ikusia + azken aldiz orain dela %1$d ordu ikusia + + Berbidalitako %1$d mezu + Berbidalitako mezua + Berbidalitako %1$d mezu + Berbidalitako %1$d mezu + Berbidalitako %1$d mezu + Berbidalitako %1$d mezu + Berbidalitako %1$d fitxategi + Berbidalitako fitxategia + Berbidalitako %1$d fitxategi + Berbidalitako %1$d fitxategi + Berbidalitako %1$d fitxategi + Berbidalitako %1$d fitxategi + Berbidalitako %1$d argazki + Berbidalitako argazkia + Berbidalitako %1$d argazki + Berbidalitako %1$d argazki + Berbidalitako %1$d argazki + Berbidalitako %1$d argazki + Berbidalitako %1$d bideo + Berbidalitako bideoa + Berbidalitako %1$d bideo + Berbidalitako %1$d bideo + Berbidalitako %1$d bideo + Berbidalitako %1$d bideo + Berbidalitako %1$d soinu + Berbidalitako soinua + Berbidalitako %1$d soinu + Berbidalitako %1$d soinu + Berbidalitako %1$d soinu + Berbidalitako %1$d soinu + Berbidalitako %1$d kokaleku + Berbidalitako kokalekua + Berbidalitako %1$d kokaleku + Berbidalitako %1$d kokaleku + Berbidalitako %1$d kokaleku + Berbidalitako %1$d kokaleku + Berbidalitako %1$d kontaktu + Berbidalitako kontaktua + Berbidalitako %1$d kontaktu + Berbidalitako %1$d kontaktu + Berbidalitako %1$d kontaktu + Berbidalitako %1$d kontaktu + Berbidalitako %1$d sticker + Berbidalitako stickerra + Berbidalitako %1$d sticker + Berbidalitako %1$d sticker + Berbidalitako %1$d sticker + Berbidalitako %1$d sticker + eta beste %1$d + eta beste %1$d + eta beste %1$d + eta beste %1$d + eta beste %1$d + eta beste %1$d + + yyyy MMMM + MMM dd + yy.MM.dd + yyyy.MM.dd + MMMM d + yyyy MMMM d + EEE + OO:mm + o:mm u + %1$s %2$s + + Plus Messenger, Androidentzako + Temaketa + Plus Ezarpenak + HEX color kodea txarto dago! + Tema kolorea + Berrabiazi Temaren Ezarpenak + Desegin temaren ezarpen guztiak + Berrabiazi temaren ezarpenak lehenetsi + Orokorra + Pantailak + Menu nagusia + Txat pantaila + Kontaktu pantaila + Goiburua + Ilarak + Txat zerrenda + Txaten zerrenda + Kontaktuen zerrenda + Goiburuko kolorea + Izenaren kolorea + Izenaren tamaina + Mezuaren kolorea + Mezuaren tamaina + Orduaren/Dataren kolorea + Orduaren/Dataren tamaina + Kontaketaren kolorea + Kontaketaren tamaina + Ilararen kolorea + Kontaketaren hondoaren kolorea + Egoeraren kolorea + Egoeraren tamaina + Eskuinaren burbuilaren kolorea + Ezkerraren burbuilaren kolorea + Dataren kolorea + Dataren tamaina + Dataren burbuilaren kolorea + Eskuinaren textuaren kolorea + Ezkerraren textuaren kolorea + Eskuinaren orduaren kolorea + Ezkerraren orduaren kolorea + Orduaren tamaina + Textuaren sarreraren kolorea + Textuaren sarreraren tamaina + Textuaren sarreraren hondoaren kolorea + Emoji-aren hondoaren kolorea + Emoji-aren etiketaren aukeratutako kolorea + Emoji-aren etiketaren ikono kolorea + Online kolorea + Musika + Gorde gaia + Gorde gaia Telegram/Themes karpetan + Gaia gordeta! + %1$s gordeta dago %2$s + Gaia oraindik ez dago aplikatuta. Mesedez, lehenengoz aplikatu MOD bat + Ezarpenak zaharberrituta SD txarteletik + Ez dira aurkitu ezarpenak %s + Ez dago SD txartelerik. + Izena idatzi + Gaiak + Gaiak aplikatu + Aplikatu XML gaia lokal karpetatik + Kide kolorea + Krispeta kolorea + Isilune kolorea + Erregistroak bidali + Ez daude erregistroak + Log-ak garbitu + Log-ak ezabatuta + Ikonoa bidali + Ezkutatu telefono-zenbakia menutik + Flotatzaile botoiaren arkatz kolorea + Flotatzaile botoiaren hondoaren kolorea + G+ Komunitatea + Idatzizko kolorea + Textuaren sarreraren ikonoen kolorea + Nabigazioaren tiradera + Ezarpen lista + Lista kolorea + Izenaren tamaina + Zenbakiaren kolorea + Zenbakiaren tamaina + Avatar kolorea + Ezarpen ikonoen kolorea + Ezarpen kolorea + Ezarpen tamaina + Bertsio kolorea + Bertsio tamaina + Goiburuko izenburu kolorea + Goiburuko ikonoen kolorea + Etiketen ikonoaren kolorea + Etiketen kontadorearen kolorea + Etiketen kontadorearen atzealdearen kolorea + Kontatu txatak mezuak baino + Kontatu bakarrik mutututa ez dauden mezuak + Ezkutatu etiketen kontadorea + Zatitzailearen kolorea + Avatar irratia + Jarri kideen kolorea + Bidali izenaren kolorea + Goiburu titulua + Bidali aipatu gabe + Desaktibatu pop-up clickatzean + Talde/Kontaktu profila + Ezkutatu hondo pertzonalizatuta + Eskuinaren linkaren kolorea + Ezkerraren linkaren kolorea + Gaia aplikatuta! + Sakatu OK aplikazioa berrabiazteko + Ikusi mugikorraren emojiak + Burbuila estiloa + Gorde jatorrizko artxiboa + Zenbakien lekuan, artxiboak gordeko dira izena_data formatuan + Avatar tamaina + Lerrokatu kontaktuaren avatarra goraino + Avatarren marjina + Taldearen izenaren kolorea + Taldearen izenaren tamaina + Izenaren kolorea (Zenbakia ezezaguna) + Ezkutatu hondo pertzonalizatuaren itzalak + Jarri hondoaren kolorea + Hondo colorea + Emojiaren kolorearen tamaina + Eskuinaren burbuilaren izenaren kolorea + Ezkerraren burbuilaren izenaren kolorea + Ikonoen kolorea + Ezarpenak/Gaiaketa pantaila + Hondoaren kolorea + Itzalaren kolorea + Sailaren kolorea + Tituluaren kolorea + Laburpen/Azpititulu kolorea + \'Argazki/Eranskailua\' textu kolorea + Sortutako gai batzuk begiratzea nahi izango zenuke Plus Messenger-eko beste erabiltzailekoak egindakoak? + Erabili gailuaren iturria + Plus Messenger berrerabiziko da + Taldeko ikono kolorea + Partekatuta kontaktuaren izenaren kolorea + Eranstu hondoaren kolorea + Eranstu textuaren kolorea + Ikusi kontaktuaren avatarra Txat pantailan + Ikusi gure avatarra Txat pantailan + Ikusi gure avatarra talde pantailan + Lerrokatu gure avatarra goraino + Elkarrizketa tituluaren/botoiaren kolorea + Ikusi erabiltzaile-izena kide izenarekin + Ez gelditu musika + Zerrendaren zatitzailearen kolorea + Erdiratu avatarra, izena eta zenbakia + Gradientea + Gradiente kolorea + Desaktivatuta + Gailur hondoa + Ezkerrekoa ezkuinekoa + Gailur-Ezkerrekoa Hondo-Ezkuinekoa + Hondo-Ezkerrekoa Gailur-Ezkuinekoa + Aplikatu gradiantea hondo listara + %s kopiatuta + +\n\nZatoz Plus Messenger-en kanal ofizialera: https://telegram.me/plusmsgr + Deskargatu gaiak + Kanal ofiziala + Elkarrizketak + Sakatu kontaktu argazkian + Sakatu talde argazkian + Profila + Profilaren argazkiak + Isilaren kontaketaren hondoaren kolorea + Bot aginduen Check-aren kolorea + Bot aginduen kolorea + Une gogoangarriko bilaketaren kolorea + %s berritu da + Ezkutatu erabiltzailearen estatuseko zeinua + Fitxak ezkutatu + Guztia + Erabiltzaileak + Taldeak + Supertaldeak + Kanalak + Bot-ak + Gogokoak + Etiketen altuera + Jarri etiketa lehenetsita bezala + Kendu etiketa lehenetsita + Status mota + Azken mezu mota + Ikusi gabe mezuen mota + Ikusi supertaldeen etiketa + Ezkutatu supertaldeen etiketa + Fitxak + Ezkutatu/Erakutsi Fitxak + Gogokoenetara gehitu + Gogokoenetatik ezabatu + Gustukorik ez\n\n Gehitzeko edozein txata lista honetara, presionatuta manten ezazu txata eta sakatu \"Gehitu gustokoera\". + Ez ezkutatu etiketak irristatzean + Swipe infinito etiketen artean + Ikusi \'parteka zuzena\' botoia + AIPATU + Kendu administratzaile listatik + Erabiltzaile-izena ordez, telefonoa erakutsi + Irakurri gisa markatu + Markatu dialogo guztiak irakurrita + Txertatu estiloa +
diff --git a/TMessagesProj/src/main/res/values-fa/strings.xml b/TMessagesProj/src/main/res/values-fa/strings.xml new file mode 100644 index 00000000..ecba5d1e --- /dev/null +++ b/TMessagesProj/src/main/res/values-fa/strings.xml @@ -0,0 +1,1407 @@ + + + تلگرام + فارسی + Persian + fa_IR + + شماره موبایل شما + ‫لطفاً کد کشورتون را تأیید \n و شماره تلفنتون رو وارد کنین. + یک کشور را انتخاب نمایید + کد کشور اشتباهه + + تایید تلفنی + ما یه پیامک به همراه کد فعالسازی به موبایلت ]]>%1$s]]> ارسال کردیم. + ما کد رو به ]]>تلگرامی]]> که روی دستگاه دیگه نصب کردی فرستادیم . + ما به شماره موبایلت ]]>%1$s]]> زنگ زدیم. لطفاً جواب نده، تلگرام خودش روند تایید رو انجام میده. + برای خوندن کد فعال سازی به شماره ی ]]>%1$s]]> زنگ می زنیم . + %1$d:%2$02d بهتون زنگ می زنیم + تا %1$d:%2$02d دیگه به شما یه پیامک می فرستیم . + در حال تماس ... + کد + شماره اشتباهه ؟ + هنوز کد رو نگرفتی ؟ + + نام شما + نام و نام خانوادگی خودتون رو بنویسید + + نام ( الزامی) + نام خانوادگی (الزامی) + بی خیال عضویت + + تنظیمات + مخاطبین + گروه تازه + دیروز + هیچ نتیجه ای پیدا نشد . + هنوز هیچ گفت و گویی نیستش + ‫با فشردن دکمه‌ی ارسال \n در گوشه‌ی بالا سمت راست \n پیام رسانی را آغاز کنید \n یا برای انتخاب‌های بیش‌تر \n دکمه‌ی فهرست را بزنید. + در انتظار شبکه ... + داره وصل میشه... + در حال به روز رسانی... + گفت و گوی مخفیانه تازه + در انتظار %s تا آنلاین بشه... + بی خیال گفت و گوی مخفیانه شدید + تبادل کلید های رمزنگاری ... + %s وارد گفت و گوی مخفیانه شما شد. + شما وارد گفت و گوی مخفیانه شدید . + ‫پاک کردن تاریخچه + از حافظه موقت پاکش کن + پاک کن و خارج شو + حذف گفت و گو + کاربری پاک شده + انتخاب گفت و گو + برای دیدن فشار بده و نگه دار + %1$s از یک نسخه قدیمی تلگرام استفاده می کنه، برای همین تصاویر سرّی در حالت سازگار نمایش داده میشه . + +زمانی که %2$s تلگرام رو به روز کنه ، عکس هایی با تایمر 1 دقیقه یا کمتر در حالت \"ضربه بزن و نگه دار تا ببینی\" شروع به کار می کنن، و هر موقع طرف مقابل از صفحه عکس بگیره شما مطلع میشید. + پیام ها + جستجو + اعلانات رو بی صدا کن + برای %1$s بی صدا کن + صداردار کردن + در %1$s + غیرفعال کن + هشتگ + اخیر + پیش نمایش لینک + + نوع گروه + نوع کانال + عمومی + خصوصی + مدیرش کن + برای گروه خودت می تونی یه توضیح بدی + ترک گروه + حذف گروه + ترک گروه + حذف گروه + همه پیامای این گروه رو از دست میدی + برای کمک به مدیریت گروهت می تونی چند تا مدیر دیگه هم اضافه کنی . روشون ضربه بزن و نگه دار تا حذفشون کنی . + وایسا بابا ! اگه گروه رو پاک کنی همه اعضا و مطلباشون پاک میشن ! مطمئنی ؟ + گروه درست شد + un1 شما رو به این گروه اضافه کرد + مطمئنی می خوای این گروه رو ترک کنی ؟ + ببخشید نمی تونی ایشون رو به گروه اضافه کنی + ببخشید این گروه تکمیله ! + ببخشید این کاربر گروه شما رو ترک کرده شما نمی تونی وباره دعوتش کنی . + ببخشید ، تعداد مدیرای این گروه خیلی زیاده. + ببخشید تعداد ربات ها تو این گروه بیش از حده ! + un1 \"%1$s\" را سنجاق کرد + un1 یه پیام رو سنجاق کرد + un1 یه عکس رو سنجاق کرد + un1 یه ویدیو رو سنجاق کرد + un1 یه فایل رو سنجاق کرد + un1 یه استیکر رو سنجاق کرد + un1 یه پیام صوتی رو سنجاق کرد + un1 یه مخاطب رو سنجاق کرد + un1 یه نقشه رو سنجاق کرد + un1 یه تصویر متحرک رو سنجاق کرد + un1 یه آهنگ رو سنجاق کرد + این گروه به یه ابرگروه تبدیل شد ! + %1$s به یه ابرگروه تبدیل شد . + کاربران مسدود از گروه حذف شدندو فقط اگه مدیر دعوتشون کنه می تونه دوباره عضو بشن . لینک دعوت هم براشون کار نمی کنه ! + کانال جدید + نام کانال + نظرات + اگر شما نظرات رو فعال کنی، همه می تونن تو کانال در مورد پست ها بحث کنن. + کسایی رو که می خوای به کانال اضافه کن + ملت می تونن این لینک رو با بقیه به اشتراک بذارن و با جستجوی تلگرام هم کانالت رو پیدا کنن . + بقیه می تونن این لینک رو با به اشتراک بذارن و می تونن گروه شما رو از طریق جستجوی تلگرام هم پیدا کنن. + لینک + +ملت می تونن با این لینک کانالت رو دنبال کنن . هر وقت بخوای می تونی لینک رو غیر فعال کنی . + دیگران از طریق این لینک می توانند وارد این گروه شوند. شما می توانید این لینک را در هر زمان غیرفعال کنید. + توضیحات (اختیاری) + توضیحات + می تونی یه توضیح کوتاه در مورد کانالت بنویسی . + کانال عمومی + گروه عمومی + کانال های عمومی رو میشه تو نتایج جستجو دید و هر کسی هم می تونه عضوش بشه . + گروه عمومی در جستجوها و تاریخچه گفتگوها نمایش داده می شوند و هر کسی می تواند عوض آن ها شود. + کانال خصوصی + گروه خصوصی + تو کانال های خصوصی فقط با دعوت نامه میشه عضو شد . + به گروه خصوصی فقط با داشتن لینک دعوت یا دعوت توسط بقیه اعضاء می توان وارد شد. + لینک + لینک دعوت + اعضا رو اضافه کن + بی خیال کانال + ترک کانال + تنظیمات + منو اضافه کن + اطلاعات کانال + سخن پراکنی + ارسال بی صدا + نظر + نظرات را نشان بده + کانال چیه؟ + با استفاده از کانال ها می تونی برای برای کلی مخاطب پیام بفرستی . + ایجاد کانال + ببخشید،این اسمو قبلا یکی انتخاب کرده + ببخشید، نمیشه این اسم رو انتخاب کنی + اسم کانال باید حداقل 5 کاراکتر باشه + اسم کانال نباید از 32 کاراکتر بیشتر باشه + اسم کانال رو نمی تونی با عدد شروع کنی + نام گروه باید حداقل 5 حرف داشته باشه + نام گروه با یک عدد نمیتونه شروع بشه. + در حال بررسی نام... + %1$s رو می تونی اسفاده کنی + اعضا + کاربران مسدود + مدیران + حذف کانال + حذف کانال + صبر کن بابا ! اگه کانال رو پاک کنی همه اعضا و همه پیام هات پاک میشن ها . مطمئنی می خوای پاکش کنی ؟ + مطمئنی می خوای کانال رو ترک کنی ؟ + همه پیام های این کانال رو از دست میدی . + ویرایش + یادت نره که اگه یه لینگ عمومی برای گروهت بزاری، همه میتونن اونو توی جستجو پیداش کنن.\n\nاگه میخوای سوپرگروهت خصوصی بمونه، این لینک رو درست نکن. + یادت نره اگه یه لینک عمومی برای کانالت بذاری هر کسی می تونه تو جستجو پیداش کنه و عضو بشه.\n\nاگه دوست داری کانالت خصوصی باشه این کارو نکن + لطفا یه لینک برای کانال عمومیت بذار که ملت بتونن تو جستجو پیداش کنن و توش عضو بشن.\n\n اگه دوست نداری می تونی به جاش یه کانال خصوصی درست کنی. + کانال ایجاد شد + عکس کانال تغییر یافت + عکس کانال حذف شد + اسم کانال به un2 تغییر یافت + ببخشید،تعداد کانالای عمومی شما بیش از حد شده . شما می تونی یکی از اونا رو پاک کنی یا اینکه از کانال خصوصی استفاده کنی . + ببخشیدا، ولی تعداد لینک های عمومی شما بیش از حد زیاده. چندتایی رو حذف کن یا چندتا گروه ها یا کانال هات رو خصوصی کن. + مدیر + سازنده + مدیر + بی صدا + با صدا + افزودن مدیر + دعوت با لینک + مطمئنی می خوای %1$s رو مدیر کنی ؟ + پاک کردن + فقط مدیران کانال می تونن این لیست رو ببینن + این بنده خدا هنوز وارد کانال نشده . می خوای دعوتش کنی ؟ + همه کاربرهای تلگرام می تونن با استفاده از این لینک عضو کانال شما بشن + شما می تونی برای کانالتون مدیر اضافه کنی . برای حذفش هم کافیه روش بزنی و نگه داری . + می خوای عضو کانال \'%1$s\' بشی ؟ + ببخشید،این گفتگو رو دیگه نمیشه دید . + متأسفانه شما از عضوشدن توی گروه های عمومی محروم شدی. + ببخشید، این گفتگو دیگه در دسترس نیست. + %1$s رو می خوای به کانال اضافه کنی ؟ + ببخشید این کاربر قبلا از کانال شما رفته برای همین نمی تونید دوباره اون رو دعوتش کنی + ببخشید ، تعداد اعضا برای این کانال خیلی زیاد شده نمی تونی کسی رو اضافه کنی + ببخشید ، تعداد مدیرا برای این کانال خیلی زیاد شده + ببخشید تعداد ربات ها برای این کانال بیش از حده ! + ببخشید ، شما کلا می تونی ۲۰۰ تا عضو به کانالت اضافه کنی البته برای عضویت با لینک محدودیتی نیست . + un1 شما را به کانال افزود + مبارکه ! وارد این کانال شدی. + مبارکه ! وارد این گروه شدی. + حذف از کانال + ببخشید، نمیشه این پیام رو به کانال بفرستی + %1$s شما رو به کانال %2$s اضافه کرد + عکس کانال %1$s عوض شد + %1$s یه پیام برای کانال %2$s فرستاد + %1$s یه عکس به کانال %2$s فرستاد + %1$s یه ویدیو به کانال %2$s فرستاد + %1$s یه مخاطب تو کانال %2$s به اشتراک گذاشت + %1$s یه مکان به کانال %2$s فرستاد + %1$s یه فایل به کانال %2$s فرستاد + %1$s یه تصویر متحرک به کانال %2$s فرستاد + %1$s یک پیام صوتی به کانال %2$s فرستاد + %1$s یک قطعه به کانال %2$s فرستاد. + %1$s یه استیکر به کانال %2$s ارسال کرد + %1$s یه پیام فرستاد + %1$s یه عکس فرستاد + %1$s یه ویدیو فرستاد + %1$s یه مخاطب فرستاد + %1$s یه مکان فرستاد + %1$s یه فایل فرستاد + %1$s یه تصویر متحرک فرستاد + %1$s یه صوت جدید فرستاد + %1$s یک قطعه فرستاد + %1$s یه استیکر فرستاد + چه کسانی می‌توانند اعضای جدید اضافه کنند؟ + تمام اعضا + فقط مدیران + هنگام ارسال پست به کاربران اطلاع داده خواهد شد + هنگام ارسال پست به کاربران اطلاع داده نخواهد شد + پیام ها رو امضا کن + نام مدیران را به پیامهایی که ارسال می کنند اضافه کنید + + لیست سخن‌پراکنی جدید + نام لیست رو وارد کن + شما لیست سخن‌پراکنی جدیدی ساختی + مخاطبتو انتخاب کن + از لیست سخن‌پراکنی حذف کن + + لطفا فایل ها رو تو کتابخونه موسیقی روی دستگاهت اضافه کن تا بتونی اینجا ببینیشون . + موسیقی + هنرمند ناشناخته + عنوان نامشخص + + انتخاب فایل + %1$s آزاد از %2$s + خطای ناشناخته + خطای دسترسی + هیچ فایلی هنوز وجود نداره... + حجم فایل نباید بیشتر از %1$s باشه + کارت حافظه نصب نشده + انتقال USB فعاله + حافظه داخلی + حافظه خارجی + + ریشه سامانه + کارت حافظه + ‫پوشه + ارسال عکس بدون فشرده سازی + + مخفی + در حال نوشتنه... + در حال نوشتنه... + د حال نوشتن هستن... + %1$s در حال ضبط پیام صوتی است... + %1$s در حال فرستادن عکسه... + %1$s در حال فرستادن ویدئو... + %1$s در حال فرستادن فایله... + در حال ضبط پیام صوتی ... + داره عکس می فرسته ... + داره ویدیو می فرسته ... + داره فایل می فرسته ... + در مورد تلگرام +سوال دارید ؟ + عکس بگیر + گالری + مکان + ویدیو + فایل + دوربین + هنوز هیچ پیام نیستش... + پیام فرستاده شده + از + هیچ مورد اخیرا وجود نداره + پیام + ‫پیام + اطلاعات تماس من رو به اشتراک بذار + ‫افزودن به مخاطبین + %s شما رو به یک گفت و گوی مخفیانه دعوت کرده + شما %s رو به یک گفت و گوی مخفیانه دعوت کردید + گفت و گوی مخفیانه: + از رمزنگاری آخر به آخر استفاده کن + هیچ ردی رو سرورهای ما نذار بمونه + تایمر از بین برنده خودکار باشه + اجازه نده کسی پیاماتو منتقل کنه + شما از گروه حذف شدی + شما این گروه رو ترک کردی + این گروه رو پاک کن + این گفت و گو رو پاک کن + بکش تا بی خیال بشه + ذخیره در دانلودها + ذخیره تو تصاویر متحرک + تصویر متحرک پاک بشه؟ + تو موسیقی ذخیره کن + اشتراک گذاری + تایید فایل زبان + نوع ضمیمه شما پشتیبانی نمیشه + تنظیم زمان‌سنج نابود کننده‌ی خودکار + اعلانات خدمات + اطلاعات لینک .... + تو مرورگر باز کن + کپی آدرس + ارسال %1$s + باز کردن %1$s ؟ + جفنگه ! + گزارش اسپم و ترک کردن + افزودن مخاطب + مطمئنی می خوای گزارش جفنگیات بدی ؟ + مطمئنی می خوای گزارش جفنگیات بدی ؟ + مطمئنی که میخوای درمورد این کانال گزارش اسپم بدی؟ + ببخشید،شما در حال حاضر فقط میتونی به مخاطبین متقابل خودت پیام بفرستی. + ببخشید،شما در حال حاضر فقط میتونی مخاطبین متقابل خودت رو به گروه اضافه کنی + https://telegram.org/faq#can-39t-send-messages-to-non-contacts + اطلاعات بیشتر + ارسال به... + اینجا ضربه بزن تا بتونی تصاویر متحرک ذخیره شده رو ببینی + سنجاق کردن + به همه اعضا خبر بده + آن پین کردن + مطمئنی که میخوای این پیام رو توی این گروه پین کنی؟ + مطمئنی که میخوای این پیام رو آن پین کنی؟ + محروم کردن کاربر + گزارش جفنگ + حذف همه ی پیام های %1$s + آخرین شکلک ها رو پاک کنم؟ + گزارش + جفنگه + ترویج خشونته + پورنوگرافیه یا غیر اخلاقیه + موارد دیگه + توضیحات + پیام سنجاق شده + + %1$s زمان تایمر رو %2$s گذاشته + شما زمان تایمر رو %1$s گذاشتی + %1$s تایمر رو خاموش کرد + شما تایمر رو خاموش کردی + شما یک پیام تازه دارید + %1$s: %2$s + %1$s برات یه پیام فرستاده + %1$s برات یه عکس فرستاده + %1$s برات یه ویدیو فرستاده + %1$s یه مخاطب رو با شما به اشتراک گذاشته + %1$s برات یه مکان فرستاده + %1$s یک فایل برای شما ارسال کرد + %1$s یه تصویر متحرک برات فرستاده + %1$s برایت یک پیام صوتی فرستاد + %1$s برای شما یک قطعه فرستاد + %1$s یک استیکر برای شما ارسال کرد + %1$s @ %2$s: %3$s + %1$s یک پیام برای گروه %2$s ارسال کرد + %1$s یک عکس برای گروه %2$s ارسال کرد + %1$s یک ویدیو برای گروه %2$s ارسال کرد + %1$s یک مخاطب برای گروه %2$s به اشتراک گذاشت + %1$s یک مکان برای گروه %2$s ارسال کرد + %1$s یک فایل به گروه %2$s ارسال کرد + %1$s یه تصویر متحرک به گروه %2$s فرستاد + %1$s یک پیام صوتی به گروه %2$s فرستاد + %1$s یک قطعه به گروه %2$s فرستاد + %1$s یک استیکر به گروه %2$s ارسال کرد + %1$s شما رو به گروه %2$s دعوت می کنه + %1$s اسم گروه %2$s رو تغییر داد + %1$s عکس گروه %2$s رو تغییر داد + %1$s %3$s رو به گروه %2$s دعوت کرد + %1$s به گروه %2$s برگشت + %1$s به گروه %2$s پیوست + %1$s %3$s رو از گروه %2$s حذف کرد + %1$s شما رو از گروه %2$s حذف کرد + %1$s از گروه %2$s رفت + %1$s وارد تلگرام شد ! + %1$s,\n ما یه ورود به اکانتت رو از یه دستگاه دیگه تو %2$s شناسایی کردیم. \n\n دستگاه: %3$s\ موقعیت: %4$s\n\nIf اگر این شما نیستی، میتونی با رفتن به تنظیمات - حریم خصوصی و امنیت - نشست ها بری و بهش پایان بدی. \n\n اگر فکر می کنی یکی دیگه وارد حسابت شده علیه شماست، میتونی تایید دو مرحله ای را از تنظیمات - حریم خصوصی و امنیت فعال کنی. \ n\nبا احترام، \n تیم تلگرام + %1$s عکس پروفایلشو عوض کرد + %1$s با لینک دعوت به گروه %2$s اضافه شد + جواب + پاسخ به %1$s + پاسخ به %1$s + %1$s %2$s + %1$s \"%2$s\" را به گروه %3$s پین کرد. + %1$s یک پیام به گروه %2$s پین کرد. + %1$s یک عکس به گروه %2$s پین کرد. + %1$s یک ویدیو به گروه %2$s پین کرد. + %1$s یک فایل به گروه %2$s پین کرد. + %1$s یک استیکر به گروه %2$s پین کرد. + %1$s یک پیام صوتی به گروه %2$s پین کرد. + %1$s یک مخاطب به گروه %2$s پین کرد. + %1$s یک نقشه به گروه %2$s پین کرد. + %1$s یک فایل GIF به گروه %2$s پین کرد. + %1$s یک قطعه به گروه %2$s پین کرد. + %1$s \"%2$s\" را پین کرد + %1$s یک پیام پین کرد. + %1$s یک عکس را پین کرد. + %1$s یک ویدیو را پین کرد. + %1$s یک فایل را پین کرد. + %1$s یک استیکر را پین کرد. + %1$s یک پیام صوتی را پین کرد. + %1$s یک مخاطب را پین کرد. + %1$s یک نقشه را پین کرد. + %1$s یک فایل GIF را پین کرد. + %1$s یک قطعه را پین کرد. + + مخاطبتو انتخاب کن + هیچ مخاطبی وجود نداره + سلام، بیا تو تلگرام : +http://goo.gl/jnmjnZ + در + دیروز در + آنلاین + آخرین باری که دیده شده + آخرین باری که دیده شده + تازه اینجا بوده + دوستان رو دعوت کن + جستجوی همگانی + آخرین به روز رسانی های اخیر + آخرین به روز رسانی ها تو یک هفته اخیر + آخرین به روزرسانی ها تو یک ماه اخیر + آخرین به روز رسانی های قبل یک ماه اخیر + پیام جدید + + ارسال پیام به ... + پس از ساختن گروه و تبدیل آن به یک ابرگروه، می‌توانی اعضای بیشتری اضافه کنی. + نام گروه رو وارد کن + نام گروه + %1$d/%2$d عضو + می خوای با \'%1$s\' صحبت کنی ؟ + ببخشید ظرفیت گروه تکمیله + ببخشید ، این گفت و گو دیگه وجود نداره . + لینک تو حافظه ذخیره شد + دعوت به گروه با لینک + لینک دعوت + مطمئنی می خوای لینک رو باطل کنی ؟ اگه باطل بشه دیگه هیچ کسی نمی تونه با لینک عضو بشه ها ! + لینک دعوت قبلی غیرفعاله . یه لینک دعوت تازه درست شده + باطلش کن + لینکو باطل کن + کپی کردن لینک + لینک رو به اشتراک بذار + همه کاربرای تلگرام می تونن با استفاده از این لینک عضو گروه شما بشن + + مدیران گفتگو + همه اعضا مدیرن ! + همه اعضا می تونن کاربر جدید اضافه کنن نام یا عکس گروه رو تغییر بدن + اضافه و کم کردن اعضا ، تغییر اسم و عکس گروه فقط کار مدیراست + + رسانه به اشتراک گذاشته شده + تنظیمات + افزودن عضو + انتخاب مدیرها + حذف و خروج از گروه + اعلان ها + حذف از گروه + ارتقا به ابرگروه + تبدیل به ابرگروه + تبدیل به ابرگروه + هشدار + این عمل غیرقابل بازگشت خواهد بود. امکان برگرداندن یک ابرگروه به یک گروه عادی وجود نخواهد داشت. + ]]>محدودیت اعضاء به سر رسیده است.]]>\n\nبرای داشتن اعضای بیشتر و قابلیت های اضافه، گروه را به ابرگروه ارتقا دهید. ابرگروه ها می توانند تا %1$s عضو داشته باشند.\n- اعضا می توانند همه ی پیام های گذشته را ببینند.\n- پیام های حذف شده برای همه ی اعضا هم حذف می شوند.\n- اعضا می توانند پیام های خودشان را ویرایش کنند.\nسازنده گروه می تواند یک لینک عمومی برای گروه ایجاد کند. + ]]>در ابرگروه ها:]]>\n\n- اعضای جدید می توانند همه ی پیام های گذشته را مشاهده کنند.\n- پیام های حذف شده برای همه ی اعضا هم حذف می شوند.\n- اعضا می توانند پیام های خودشان را ویرایش کنند.\n- سازنده ی گروه می تواند یک لینک عمومی برای گروه ایجاد کند. + ]]>نکته:]]> این عمل غیرقابل بازگشت خواهد بود. + + به اشتراک بذار + افزودن + اضافه کردن مخاطب + مسدود کردن + ویرایش + حذف + خونه + موبایل + کار + دیگه + اصلی + یه گفت و گوی مخفیانه راه بنداز + یه خطایی رخ داده . + کلید رمزنگاری + تایمر از بین برنده + خاموش + این تصویر و متن یک تصویر سازی از کلید رمزنگاری برای گفتگوی محرمانه هست با ]] %1$s]]>.
]]>اگه این تصویر شبیه تصویر ]]>%2$s]]> هست رمزگذاری تمامیت دستگاه تضمین شده است!
]]>اطلاعات بیشتر در telegram.org
+ https://telegram.org/faq#secret-chats + نامعلوم + اطلاعات + تلفن + + نام کاربری + نام کاربری شما + ببخشید ، این نام کاربری قبلا انتخاب شده + ببخشید، این نام کاربری معتبر نیست + نام کاربری باید حداقل 5 کاراکتر باشه + نام کاربری نباید از 32 کاراکتر بیشتر باشه + ببخشید، نام کاربری نمیتواند با عدد شروع بشه + شما می تونید یک نام کاربری در ]]> تلگرام ]]> انتخاب کنید. اگر این کار رو بکنید بقیه با این نام کاربری می تونند شما رو پیدا کنن و بدون داشتن شماره تلفنتون با شما در تماس باشن. +
]]> شما مجازید از ]]>a–z]]>, ]]>0–9]]> و زیرخط استفاده کنید. حداقل طول اون هم ]]>5]]> کاراکتر هستش.
+ در حال بررسی نام کاربری... + %1$s موجوده + هیچ کدوم + خطایی رخ داده + + استیکرها + هنرمندان می تونن بسته های استیکرشون رو با استفاده از ربات ما @stickers اضافه کنن.\n\n کاربران می توانند با ضربه به استیکر ها و انتخاب \"اضافه به استیکرها\" اونا رو اضافه کنن. + استیکر اضافه کن + به استیکرها اضافه کن + استیکرها پیدا نشدن + استیکرها پاک شدن + استیکرهای جدید اضافه شدن + پنهان کردن + نمایش دادن + اشتراک گذاری + کپی کردن لینک + پاک کردن + هیچ استیکری وجود نداره + با عرض پوزش، شما از حداکثر تعداد استیکر استفاده کرده اید. + + همه اعلان ها رو به حالت پیش فرض برگردون + اندازه پیام متنی + یه سوال دارم + فعال سازی پویانمایی + آزاد کردن + روی کاربر فشار بده و نگه دار تا آزاد بشه + هنوز هیچ کاربر مسدودی نیستش + اعلانات پیام ها + هشدار + پیش نمایش پیام + اعلان های گروه + صدا + اعلان های نرم افزار + صداهای داخل برنامه + لرزش داخل برنامه + لرزش + پیش نمایش داخل برنامه + تنظیم مجدد + همه اعلانات رو ریست کن + تنظیمات همه اعلانات سفارشی برای همه گروه ها و مخاطبین رو برگردون به حالت قبل + اعلانات و صداها + کاربران مسدود + خروج + بدون صدا + پیش فرض + پشتیبانی + فقط اگه بی صدا بود + پس زمینه گفت و گو + پیام ها + ارسال با اینتر + همه نشت‌های دیگه رو تموم کن + رویدادها + مخاطب وارد تلگرام شد + زبان + +لطفا توجه داشته باشید که پشتیبانی تلگرام توسط داوطلبان انجام میشه .ما تلاش می کنیم تا در اسرع وقت پاسخ بدیم اما ممکنه مدتی طول بکشه.
]]>اینجا رو یه نگاهی بنداز Telegram FAQ]]>:پاسخ بیشتر سوالات در اینجا موجوده عیب یابی]]>. +
+ یه داوطلب می خوام + سوالات رایج تلگرام + https://telegram.org/faq + سیاست های حریم خصوصی + https://telegram.org/privacy + فایل زبان پاک بشه ؟ + فایل زبان خرابه + فعال + غیرفعال + خدمات اعلانات + اگه گوگل پلی برای اعلانات کفایت می کنه می تونی خدمات اعلان ها رو غیرفعال کنی . +البته ما پیشنهاد می کنیم این گزینه رو فعال بذاری تا برنامه در حال اجرا باشه و اعلان ها رو بلافاصله نشون بده . + به ترتیب کن + مخاطب ها رو اضافه کن + نام + نام خانوادگی + رنگ ال ای دی + اعلان های پاپ آپ + بدون پاپ آپ + فقط وقتی صفحه روشنه + فقط وقتی صفحه خاموشه + همیشه پاپ آپ رو نشون بده + شماره نشان ها + کوتاه + بلند + پیش فرض سیستم + تنظیمات پیش فرض + رسانه ها رو خودکار دانلود کن + چه موقع از دیتا استفاده بشه + چه موقع از وای فای استفاده بشه + وقتی که رومینگ هستش + فایلی نیستش + نمایش خودکار تصاویر متحرک + برقراری مکالمه + تو گالری ذخیره کن + ویرایش نام + اولویت + پیش فرض + کم + زیاد + حداکثر + هیچ وقت + تکرار اطلاعیه + اینجا می‌تونی شماره‌ی تلگرام‌ت رو تغییر بدی. اکانتت و تمام داده‌های ابریت — پیام‌ها، رسانه‌ها، مخاطبین و غیره به شماره‌ی جدیدت منتقل میشن.\n\nمهم:]]> شماره‌ی جدیدت]]> به دفترچه آدرس مخاطبین تلگرامت اضافه میشه، در صورتی که اونا شماره‌ی قبلی شما رو داشته باشن و شمام اونا رو تو تلگرام مسدود نکرده باشی. + تمامی مخاطبین تلگرامت رو روی شماره جدید دریافت می کنی ، شماره های کسایی که گفت و گو می کردید و اونایی که حسابشون رو بلاک نکردی رو می تونی داشته باشی + تغییر شماره + شماره ی جدید + ما یک پیامک به شماره جدیتون با کد تاییدیه ارسال می کنیم . + فعلا شماره %1$s به تلگرامت وصله . لطفا قبل از مهاجرتت به شماره جدیدت اکانت قبلیت رو حذف کن . + دیگه + غیرفعال + غیرفعال + غیرفعال + خاموش + صداهای تو چت + پیش فرض + پیش فرض + اعلانیه های هوشمند + غیرفعال + حداکثر صدا %1$s بین %2$s + حداکثر صدا + زمان + بین + دقیقه + پیش نمایش پیوند + گفتگوهای محرمانه + مرورگر درون-برنامه + لینک ها را درون برنامه باز کن + اشتراک گذاری مستقیم + نمایش گفتگوهای گذشته در منوی اشتراک گذاری + + تنظیمات حافظه موقت + بانک اطلاعات محلی + حافظه موقت پیام های متنی پاک بشن ؟ + پاک کردن بانک اطلاعاتی محلی باعث میشه تا متن های ذخیره شده پاک بشن و حافظه داخلی دستگاهت آزاد بشه. تلگرام برای اینکه درست کار کنه نیاز داره تا بخشی از اونا رو نگه داره به همین خاطر حجمشون صفر نمیشه. \n\nاحتملا این عمل چند دقیقه طول بکشه. + حافظه موقت رو خالی کن ! + پاک کن + در حال محاسبه... + اسناد + تصاویر + پیام های صوتی + ویدیوها + موسیقی + بقیه فایل ها + خالی + رسانه ها رو نگه دار + با این کار همه تصاویر، فیلم ها و فایل هایی که ذخیره نکرده بودی و صرفا فضای دستگاهت رو اشغال می کرد، دسترسی نداری]]> از روی دستگاه شما پاک میشن تا فضای بیشتری در اختیار داشته باشی. + +\n\n نگران نباش تمام اطلاعات روی سرور های تلگرام باقی می مونه و می تونی در صورت نیاز دوباره اونا رو دانلود کنی. + برای همیشه + + نشست های فعال + نشست فعلی + هیچ نشست فعال دیگری نیستش + شما می تونید از طریق موبایل تبلت یا رایانه شخصیتون و با استفاده از یه شماره تلفن وارد تلگرام بشین . همه داده هاتون بلافاصله همگام سازی میشن . + نشست های فعال + کنترل نشست ها روی دستگاه های دیگه + برای پایان دادن روی نشست ضربه بزن + این نشستو تموم کنیم؟ + برنامه غیر رسمی + + قفل با گذرواژه + تغییر گذرواژه + وقتی که یه گذرواژه اضافی تنظیم می کنی،یه آیکن قفل بالای صفحه میادش . برای قفل کردن یا باز کردن برنامه تلگرام به اون ضربه بزن.\n\n توجه:اگر گذرواژه خودت رو فراموش کنی مجبور میشی برنامه رو دوباره نصب کنی و این جوری تمام گفت و گوهای محرمانت پاک میشن + الان شما یه آیکن قفل بالای صفحه چت هات می بینی . روش ضربه بزن تا برنامه تلگرامت رو با یه گذرواژه قفل کنی + کد پین + گذرواژه + گذواژه فعلی رو وارد کن + یه گذرواژه وارد کن + گذرواژه جدید رو وارد کن + گذرواژه خودت رو وارد کن + گذرواژه جدید رو دوباره وارد کن + گذرواژه معتبر نیستش + دو تا گذرواژه یکی نیستن + قفل خودکار + اگه یه مدتی نبودی گذرواژه بخواد + در %1$s + غیرفعال + با اثر انگشت باز کن + اثر انگشتت رو تایید کن تا ادامه بدیم + سنسور لمسی + اثر انگشت رو نشناختم ؛ دوباره امتحان کن + + فایل های به اشتراک گذاشته شده + رسانه های مشترک + پیوندهای به اشتراک گذاشته شده + موسیقی به اشتراک گذاشته شده + عکس ها و فیلم های این چت رو به اشتراک بذار و از طریق همه دستگاهات به اونا دسترسی داشته باش . + تو این گفت و گو یه موسیقی به اشتراک بذار و با هر کدوم از دستگاه هات اونا رو داشته باش . + فایل ها و اسناد این چت رو به اشتراک بذار و از طریق همه دستگاهات به اونا دسترسی داشته باش . + لینک های این چت رو به اشتراک بذار و از طریق همه دستگاهات به اونا دسترسی داشته باش . + عکس و فیلم های این گفتگو در اینجا نمایش داده می شود. + آهنگ های به اشتراک گذاشته شده در این گروه اینجا نمایش داده می شود. + فایل ها و اسناد رد و بدل شده در این گفتگو اینجا نمایش داده می شود. + لینک های رد و بدل شده در این گفتگو در اینجا نمایش داده می شود. + + نقشه + ماهواره + هیبرید + متر فاصله + کیلومتر فاصله + ارسال مکان فعلیت + ارسال مکان انتخابی + مکان + دقیقا به %1$s + یا یه مکان رو انتخاب کن + + نمایش همه رسانه ها + تو گالری ذخیره کن + %1$d از %2$d + گالری + همه عکس ها + همه ویدیوها + هنوز هیچ عکسی نیست + هنوز هیچ ویدیویی وجود نداره + اول زسانه ها رو دانلود کن + تصویر تازه‌ای وجود نداره + تصویر متحرک تازه ای وجود نداره + جستجوی تصاویر + جستجوی وب + جستجوی تصاویر متحرک + جستجوی وب + جستجوی تصاویر متحرک + بریدن تصویر + ویرایش عکس + بالا بردن + برجسته‌ها + کنتراست + آشکاری + گرمی + اشباع + شکل + سایه‌ها + دانه + تیز + محو شدن + رنگ + سایه ها + برجسته + منحنی + همه + قرمز + سبز + آبی + محو + خاموش + خطی + شعاعی + مطمئنی می خوای این عکس رو پاک کنی ؟ + مطمئنی می خوای این ویدیو رو پاک کنی ؟ + بی خیال تغییرات بشیم ؟ + تاریخچه جستجو پاک بشه؟ + پاک کردن + عکس ها + ویدئو + اضافه کردن توضیح... + توضیح عکس + توضیح ویدئو + شرح + + تایید دو مرحله ای + تنظیم گذرواژه‌ی اضافی + شما می تونی علاوه بر کد تاییدی که از طریق پیامک هنگام ورود دریافت می کنی، رمزی هم اضافه کنی . + گذرواژه‌ی شما + لطفا گذرواژه‌ی خودت رو وارد کن + یه گذرواژه وارد کن + لطفا گذرواژه‌ی جدید خودت رو وارد کن + لطفا گذرواژه‌ی خودت رو دوباره وارد کن + ایمیل بازیابی + ایمیل شما + لطفا ایمیل درست خودت رو وارد کن.این تنها راهیه که میشه رمزعبور فراموش شده خودت رو بازیابی کنی. + رد شو + هشدار + جدی جدی اگه رمزت رو فراموش کردی دسترسیت به حساب تلگرامت رو از دست میدیا. هیچ راه برگشتی وجود نداره ها ! + تقریبا تمومه! + لطفا ایمیل خودت رو برای راه اندازی تایید دو مرحله ای بررسی کن ( اگه ایمیلو پیدا نکردی پوشه هرزنامه ها یا اسپم رو هم بررسی کن ) + موفق شدی! + گذرواژه شما برای تایید دو مرحله ای الان فعاله + تغییر گذرواژه + گذرواژه رو خاموش کن + تنظیم ایمیل بازیابی + تغییر ایمیل بازیابی + مطمئنی می خوای گذرواژه رو غیر فعال کنی؟ + راهنمای گذرواژه + یه راهنما برای گذرواژه خود بذارید. + گذرواژه‌ها یکی نیستن + بی خیال راه اندازی تایید دو مرحله ای + برای راه اندازی تایید دو مرحله ای مراحل زیر رو انجام بده:\n\n1. ایمیل رو بررسی کن(پوشه هرزنامه رو یادت نره)\n%1$s\n\n2. روی لینک فعال سازی کلیک کن. + راهنما باید با گذرواژه شما متفاوت باشه + ایمیل اشتباهه + ببخشید + از اونجایی که شما هنگام ثبت گذرواژت ایمیلی برای بازیابی ارائه ندادی، گزینه های پیش روی شما به خاطر سپاری رمز یا بازنشاندن حساب شماست. + ما ایمیلی حاوی کد بازنشانی به آدرسی که شما داده بودی ارسال کردیم:\n\n%1$s + لطفا ایمیلت رو چک کن و کد 6 رقمی که برات ارسال کردیم رو اینجا وارد کن. + به ایمیل %1$s دسترسی نداری ؟ + اگر شما نمیتونی به حساب ایمیلت دسترسی داشته باشی، گزینه های پیش روی شما به خاطر سپاری رمز و یا بازنشاندن حساب شماست. + اکانت من رو ریست کن + اگه به بازنشانی حسابت اقدام کنی، همه مکالمات و پیام هات به همراه همه رسانه ها و فایل هایی که به اشتراک گذاشتی رو از دست میدی. + هشدار + این عمل غیر قابل بازگشت است.\nاگر شما حساب خود را ریست کنید، همه پیام ها و گفتگوها هم حذف خواهند شد. + تنظیم مجدد + گذرواژه + شما تایید دو مرحله‌ای رو فعال کردی ، در نتیجه حساب شما با یه گذرواژه‌ی اضافه محافظت میشه. + گذرواژه رو یادت رفته؟ + بازیابی گذرواژه + کد + گذرواژه غیرفعال شد. + شما تایید دو مرحله ای را فعال کردی.\nبرای ورود به حساب تلگرامت به این گذرواژه نیاز پیدا می کنی. + ایمیل بازیابی شما %1$s هنوز فعال نشده و در انتظار تاییده. + + حریم خصوصی و امنیت + حریم خصوصی + آخرین باری که دیده شده + همه + مخاطبین من + هیچ کس + همه (-%1$d) + مخاطبین من (+%1$d) + مخاطبین من (-%1$d) + مخاطبین من (-%1$d, +%2$d) + هیچ کس (+%1$d) + امنیت + پاک کننده خودکار حساب کاربری + اگر برای این مدت نبودید + اگه حداقل تو این بازه زمانی وارد تلگرام نشی حساب کاربری شما با همه اعضا و گروه ها و پیام هاش پاک میشن. + می خوای حساب کاربریتو پاک کنی ؟ + چه کسی می تونه آخرین زمان بازدید شما را ببینه رو تغییر بدید . + چه کسی می تونه آخرین زمان بازدید شما را ببینه ؟ + استثنا اضافه کن + توجه : شما قادر به دیدن آخرین زمان و تاریخ افرادی که جزء دوستانت نیستن ، نیستی ما زمان تقریبی اونا رو در میذاریم مثل (به تازگی، در عرض یک هفته ظرف یک ماه) + همیشه باهاش به اشتراک بذار + هیچ وقت باهاش اشتراک نذار + این تنظیمات جایگزین مقادیر بالا میشن . + همیشه به اشتراک بذار + همیشه با اینا به اشتراک بذار + اصلا هیچ وقت به اشتراک نذار + هیچ وقت با اینا به اشتراک نذار + اضافه کردن کاربران + متاسفیم ، درخواست های بسیاری داریم ، به همین دلیل نمی تونیم تنظیمات حریم خصوصی رو تغییر بدیم ، لطفا صبر کنید. + از همه دستگاه ها به جز این خارج شو . + روی کاربر ضربه بزن و نگه دار تا پاک بشه . + گروه ها + چه کسی می تواند من رو داخل گروه چت اضافه کند؟ + با دقت فرد به فرد همه افرادی که میتوانند شما را به گروهها و کانالها اضافه کنند محدود سازید + همیشه مجاز باشد + هیچ وقت مجاز نباشد + همیشه مجاز باشد... + هیچ وقت مجاز نباشد... + این کاربران علیرغم تنظیمات بالا خواهند یا نخواهند توانست شما را در گروهها و کانالها اضافه کنند + مشخص کنید چه افرادی میتوانند شما را در گروهها و کانالها اضافه کنند + متاسفانه بدلیل تنظیمات شخصی کاربر نمیتوان این کاربر را به گروه اضافه نمود + متاسفانه بدلیل تنظیمات شخصی کاربر نمیتوان این کاربر را به کانال اضافه نمود + متاسفانه بدلیل تنظیمات شخصی این کاربران نمیتوان با آنها یک گروه ایجاد نمود + + ویرایش ویدیو + ویدیو اصلی + ویدیو ویرایش شده + در حال ارسال ویدیو ... + ویدیو رو فشرده کن + + ربات + اشتراک گذاری + اضافه کردن به گروه + تنظیمات + راهنما + به پیام ها دسترسی داره + به پیام ها دسترسی نداره + این ربات چی کار می تونه بکنه؟ + شروع + شروع دوباره + متوقف کردن ربات + شروع دوباره ربات + + بعدی + قبلی + خوبه + بازش کن + ذخیره + بی خیال + ببند + اضافه کن + ویرایش + ارسال + تماس + کپی + حذف + هم پاک و هم متوقفش کن + انتقال + دوباره تلاش کن + از دوربین موبایل + از گالری + عکسو پاک کن + تنظیم کن + خوبه + بریدن + + شما با لینک دعوت به گروه وارد شدی. + un1 با لینک دعوت به گروه وارد شد. + un1 un2 رو پاک کرد + un1 گروه رو ترک کردش + un1 un2 رو اضافه کرد + un1 عکس گروه رو پاک کرد + un1 عکس گروه رو عوض کرد + un1 اسم گروه رو به un2 تغییر داد + un1 گروه رو ایجاد کرد + شما un2 رو پاکش کردی + شما گروه رو ترک کردی + شما un2 رو اضافه کردی + شما عکس گروه رو پاک کردی + شما عکس گروه رو عوض کردی + شما اسم گروه رو به un2 تغییر دادی + شما گروه رو ایجاد کردی + un1 شما رو پاک کرد + un1 شما رو اضافه کرد + un1 به گروه برگشت + un1 به گروه پیوست. + شما به گروه برگشتید + این پیام در نسخه تلگرام شما پشتیبانی نمیشه. برای مشاهده پیام، برنامه را بروزرسانی کن:https://telegram.org/update + عکس + ویدیو + تصویر متحرک + مکان + مخاطب + فایل + استیکر + پیام صوتی + شما + شما یه عکس از صفحه گرفتی! + un1 یه عکس از صفحه گرفت ! + + شماره تلفن همراه اشتباهه + کد منقضی شده دوباره وارد بشید + خیلی دیگه تلاش کردی یه خرده استراحت کن بعد ! + تعداد تلاش‌های شما خیلیه ، لطفا بعد از %1$s دوباره سعی کن. + کد نامعتبره + نام نامعتبره + نام خانوادگی نامعتبره + صبر کن داره میاد.... + شما هیچ برنامه ای برای پخش فیلم نداری یکی نصب کن بعد ادامه بده . + لطفا یه ایمیل به sms@stel.com ارسال کن و مشکلتو توضیح بده + شما هیچ برنامه برای باز کردن \'%1$s\', نداری . باید یکی نصب کنی + اینی که می گی که تلگرام نداره! می خوای دعوتش کنی ؟ + مطمئنی ؟ + می خوای %1$s رو به گفتگوی %2$s اضافه کنی ؟ + تعداد پیام های قبلی برای ارسال: + %1$s به گروه اضافه بشه؟ + این کاربر الان تو گروه عضو هستش + می خوای پیام ها رو به %1$s منتقل کنی ؟ + پیام ها رو به %1$s ارسال کنم؟ + مطمئنی می خوای اطلاعات تماس رو به %1$s بفرستی ؟ + مطمئنی می خوای خارج بشی ؟ \n\nNote شما می تونی از تلگرام تو همه دستگاه های خودت به صورت یکپارچه استفاده کنی ، با خروج از سیستم چت های امنیتی از بین میره . + مطمئنی می خوای همه نست های دیگه رو تموم کنی ؟ + مطمئنی که قصد حذف و ترک این گروه رو داری؟ + مطمئنی که قصد حذف این گفت و گو رو داری؟ + مطمئنی می خوای بقیه اطلاعات تماستو ببینن ؟ + مطمئنی می خوای طرف رو مسدود کنی ؟ + مطمئنی می خوای طرف رو باز کنی ؟ + مطمئنی می خوای طرف رو حذف کنی ؟ + مطمئنی که می خوای یه گفت و گوی مخفیانه راه بندازی ؟ + مطمئنی می خوای عضویتت رو لغو کنی ؟ + مطمئنی می خوای تاریخچه رو پاک کنی ؟ + +مطمئنی می خوای همه فایل های رسانه ای و متن های دانلود شده این کانال رو پاک کنی ؟ + حذف همه ی پیام های ذخیره شده ی این گروه؟ + مطمئنی می خوای %1$s رو پاک کنی ؟ + پیام‌ها به %1$s ارسال بشه؟ + مطمئنی می خوای اطلاعات تماس رو به %1$s بفرستی ؟ + پیام‌ها به %1$s منتقل بشه؟ + ببخشید، ما لیاقت نداریم این امکان رو توی ایران پشتیبانی کنیم ! تو رو خدا ما رو ببخشید . شرمنده ایم ! + هیچ حساب تلگرامی با این نام کاربری وجود نداره. + این ربات نمی تونه به گروه ها ملحق بشه. + دوست دارید پیش نمایش پیوند در گفتگوی محرمانه فعال باشد؟ توجه داشته باشید که پیش نمایش پیوند در سرور تلگرام ایجاد می شود. + لطفا توجه داشته باشید که رباتهای درونخطی توسط توسعه دهندگان شخص ثالث ارائه شده اند. برای این رباتی که کار می‌کند، تمام این نمادهایی که شما بعد از نام کاربری ربات تایپ می کنید به توسعه دهنده مربوطه ارسال میشوند + آیا مایل به فعالسازی \"برقراری مکالمه\" برای پیام صوتی هستید؟ + ببخشید ، نمی تونی این پیام رو ویرایش کنی. + لطفاً به تلگرام اجازه دریافت پیامک دهید، بدین ترتیب ما می توانیم روند تایید را به صورت خودکار انجام دهیم. + لطفاً به تلگرام اجازه دریافت تماس بدهید، بدین ترتیب ما می توانیم روند تایید را به صورت خودکار انجام دهیم. + لطفاً به تلگرام اجازه دریافت پیامک و تماس دهید، بدین ترتیب ما می توانیم روند تایید به صورت خودکار انجام دهیم. + + برای اینکه بتونی با دوستات تو هر دستگاهی ارتباط داشته باشی ؛ تلگرام نیاز داره تا بتونه مخاطب هات رو ببینه + برای اینکه بتونی تصاویر فایلای صوتی و تصویری یا هر چیز دیگه ای رو بفرستی یا ذخیره کنی تلگرام نیاز داره تا به حافظه موبایلت دسترسی داشته باشه + برای اینکه بتونی پیام صوتی بفرستی تلگرام نیاز داره تا به میکروفونت دسترسی داشته باشه + برای اینکه بتونی به دوستات بگی کجایی تلگرام نیاز داره تا به مکانت دسترسی داشته باشه + تنظیمات + + تلگرام + سریع + رایگان + امن + قدرتمند + بر پایه ابری + خصوصی + سریع ترین]]> برنامه پیارم رسان جهان .]]> رایگان]]> و امنه]]> + تلگرام]]> خیلی سریع تر از ]]>بقیه برنامه ارسال می کنه + تلگرام]]> برای همیشه رایگانه و تبلیغی نداره]]>هیچ هزینه اشتراکی هم نمی خواد + تلگرام]]> پیام های شما رو ]]>از حمله هکرها حفظ می کنه + تلگرام]]> هیچ محدودیتی برای ]]>حجم فایل ها و گفت و گو ها نداره + تلگرام]]>به شما این اجازه رو میده که]]>با دستگاه های مختلف وصل بشید + تلگرام]]> پیام ها رو به طور وحشتناکی ]]>رمز نگاری می کنه و شما می تونید اونا رو از بین ببرید + شروع پیام رسانی + + %1$d آنلاین + %1$d آنلاین + %1$d آنلاین + %1$d آنلاین + %1$d آنلاین + %1$d آنلاین + %1$d عضو + %1$d عضو + %1$d عضو + %1$d عضو + %1$d عضو + %1$d عضو + و %1$d عضو دیگه در حال تایپ هستن + و %1$d نفر دیگر در حال نوشتن هستند + و %1$d عضو دیگه در حال تایپ هستن + و %1$d عضو دیگه در حال تایپ هستن + و %1$d عضو دیگه در حال تایپ هستن + و %1$d عضو دیگه در حال تایپ هستن + پیام تازه ای نیستش + %1$d پیام تازه + %1$d پیام تازه + %1$d پیام تازه + %1$d پیام تازه + %1$d پیام تازه + بدون پیام + %1$d پیام + %1$d پیام + %1$d پیام + %1$d پیام + %1$d پیام + %1$d نظرات + %1$d نظر + %1$d نظرات + %1$d نظرات + %1$d نظرات + %1$d نظرات + هیچ یک از موارد + %1$d مورد + %1$d موارد + %1$d موارد + %1$d موارد بسیار زیادی + %1$d موارد دیگر + از هیچ گفتگویی + از %1$d گفتگو + از %1$d گفتگو + از %1$d گفتگو + از %1$d گفتگوی زیاد + از %1$d گفتگوی دیگر + %1$d ثانیه + %1$d ثانیه + %1$d ثانیه + %1$d ثانیه + %1$d ثانیه + %1$d ثانیه + %1$d دقیقه + %1$d دقیقه + %1$d دقیقه + %1$d دقیقه + %1$d دقیقه + %1$d دقیقه + %1$d ساعت + %1$d ساعت + %1$d ساعت + %1$d ساعت + %1$d ساعت + %1$d ساعت + %1$d روز + %1$d روز + %1$d روز + %1$d روز + %1$d روز + %1$d روز + %1$d هفته + %1$d هفته + %1$d هفته + %1$d هفته + %1$d هفته + %1$d هفته + %1$d ماه + %1$d ماه + %1$d ماه + %1$d ماه + %1$d ماه + %1$d ماه + %1$d سال + %1$d سال + %1$d سال + %1$d سال + %1$d سال + %1$d سال + %1$d کاربر + %1$d کاربر + %1$d کاربر + %1$d کاربر + %1$d کاربر + %1$d کاربر + %1$d بار + %1$d بار + %1$d بار + %1$d بار + %1$d بار + %1$d بار + %1$d متر + %1$d متر + %1$d متر + %1$d متر + %1$d متر + %1$d متر + %1$d استیکرها + %1$d استیکرها + %1$d استیکرها + %1$d استیکرها + %1$d استیکرها + %1$d استیکرها + %1$d عکس + %1$d عکس + %1$d عکس + %1$d عکس + %1$d عکس + %1$d عکس + آخرین بازدید %1$d دقیقه قبل + آخرین بازدید %1$d دقیقه قبل + آخرین بازدید %1$d دقیقه قبل + آخرین بازدید %1$d دقیقه قبل + آخرین بازدید %1$d دقیقه قبل + آخرین بازدید %1$d دقیقه قبل + آخرین بازدید %1$d ساعت قبل + آخرین بازدید %1$d ساعت قبل + آخرین بازدید %1$d ساعت قبل + آخرین بازدید %1$d ساعت قبل + آخرین بازدید %1$d ساعت قبل + آخرین بازدید %1$d ساعت قبل + + %1$d پیام های فرستاده شده + پیام فرستاده شده + %1$d پیام های فرستاده شده + %1$d پیام های فرستاده شده + %1$d پیام های فرستاده شده + %1$d پیام های فرستاده شده + %1$d فایل های فرستاده شده + فایل فرستاده شده + %1$d فایل های فرستاده شده + %1$d فایل های فرستاده شده + %1$d فایل های فرستاده شده + %1$d فایل های فرستاده شده + %1$d عکس های فرستاده شده + عکس فرستاده شده + %1$d عکس های فرستاده شده + %1$d عکس های فرستاده شده + %1$d عکس های فرستاده شده + %1$d عکس های فرستاده شده + %1$d ویدیو های فرستاده شده + ویدیو فرستاده شده + %1$d ویدیو های فرستاده شده + %1$d ویدیو های فرستاده شده + %1$d ویدیو های فرستاده شده + %1$d ویدیو های فرستاده شده + %1$d پیگیری های ارسال شده + پیگیری ارسال شده + %1$d پیگیری های ارسال شده + %1$d پیگیری های ارسال شده + %1$d پیگیری های ارسال شده + %1$d پیگیری های ارسال شده + %1$d پیام های صوتی فرستاده شده + پیام های صوتی فرستاده شده + %1$d پیام های صوتی فرستاده شده + %1$d پیام های صوتی فرستاده شده + %1$d پیام های صوتی فرستاده شده + %1$d پیام های صوتی فرستاده شده + %1$d مکان های ارسال شده + مکان ارسال شده + %1$d مکان های ارسال شده + %1$d مکان های ارسال شده + %1$d مکان های ارسال شده + %1$d مکان های ارسال شده + %1$d مخاطبین فرستاده شده + مخاطب فرستاده شده + %1$d مخاطبین فرستاده شده + %1$d مخاطبین فرستاده شده + %1$d مخاطبین فرستاده شده + %1$d مخاطبین فرستاده شده + %1$d استیکر های ارسال شده + استیکر ارسال شده + %1$d استیکر های ارسال شده + %1$d استیکر های ارسال شده + %1$d استیکر های ارسال شده + %1$d استیکر های ارسال شده + و %1$d سایر + و %1$d سایر + و %1$d سایر + و %1$d سایر + و %1$d سایر + و %1$d سایر + + MMMM yyyy + MMM dd + dd.MM.yy + dd.MM.yyyy + MMMM d + MMMM d, yyyy + EEE + HH:mm + h:mm a + %1$s در %2$s + + پیام رسان پلاس برای اندروید + قالب دهی + تنظیمات پلاس + کد هگز رنگ نامعتبر! + رنگ قالب + تنظیم مجدد تنظیمات قالب + لغو همه تنظیمات قالب + بازنشانی تنظیمات تم به پیش فرض! + عمومی + صفحه ها + صفحه اصلی + صفحه گفتوگو + صفحه مخاطبین + سربرگ + سطرها + لیست گفتوگو + لیست گفتوگوها + لیست مخاطبین + رنگ سربرگ + رنگ نام + اندازه نام + رنگ پیام + اندازه پیام + رنگ زمان / تاریخ + اندازه زمان / تاریخ + رنگ تعداد + اندازه تعداد + رنگ سطر + رنگ پس زمینه تعداد + رنگ وضعیت + اندازه وضعیت + رنگ حباب راست + رنگ حباب چپ + رنگ تاریخ + سایز تاریخ + رنگ حباب تاریخ + رنگ متن راست + رنگ متن چپ + رنگ زمان راست + رنگ زمان چپ + اندازه زمان + رنگ متن ورودی + اندازه متن ورودی + رنگ پس زمینه متن ورودی + رنگ پس زمینه شکلک ها + رنگ زبانه انتخاب شده شکلک + رنگ آیکن زبانه شکلک + رنگ آنلاین + موسیقی + ذخیره قالب + ذخیره قالب در پرونده Telegram/Themes + قالب ذخیره شد! + %1$s در %2$s ذخیره شد + قالب هنوز ایجاد نشده است. لطفا، ابتدا مودی را اعمال کنید. + تنظیمات بازسازی از کارت حافظه بازخوانی شد. + فایل بازسازی در پرونده %s یافت نشد. + کارت حافظه پیدا نشد. + نام را وارد کنید + قالب ها + اعمال قالب + اعمال قالب xml از پرونده محلی + رنگ عضو + رنگ تیک ها + رنگ بی صدا + ارسال گزارشات + گزارشی موجود نیست + پاک کردن گزارش ها + گزارش ها پاک شدند + نماد ارسال + مخفی کردن شماره تلفن از منو + رنگ مداد شناور + رنگ پس زمینه شناور + انجمن گوگل پلاس + رنگ نوشتن + رنگ نماد متن ورودی + کشوی پیمایش + لیست تنظیمات + رنگ لیست + اندازه نام + رنگ تلفن + اندازه تلفن + رنگ آواتار + رنگ نماد تنظیمات + رنگ تنظیمات + اندازه تنظیمات + رنگ نسخه + اندازه نسخه + رنگ عنوان سربرگ + رنگ نماد سربرگ + رنگ آیکون تب ها + رنگ آیکون تب های انتخاب نشده + رنگ شمارنده تب ها + رنگ پس زمینه شمارنده تب ها + شمردن چت ها به جای پیام ها + تنها شمردن چت هایی که ساکت نشده اند + مخفی کردن شمارنده تب ها + رنگ جداکننده + شعاع آواتار + تنظیم رنگ عضو + رنگ نام ارسال به دیگری + عنوان سربرگ + ارسال به دیگری بدون نقل قول + غیر فعال کردن پنجرک در کلیک + پروفایل + مخفی کردن پس زمینه سفارشی + رنگ پیوند راست + رنگ پیوند چپ + قالب اعمال شد! + برای راه اندازی مجدد برنامه تایید کنید + نمایش شکلک تلفن + سبک حباب + نام فایل اصلی را نگه دار + به جای فقط شماره های فایل ها در قالب نام_تاریخ ذخیره خواهد شد + اندازه آواتار + تراز آواتار مخاطب به بالا + حاشیه آواتار + رنگ نام گروه + اندازه نام گروه + رنگ نام (شماره نامعلوم) + مخفی کردن سایه پس زمینه سفارشی + تنظیم رنگ پس زمینه + رنگ پس زمینه + اندازه پنجرک شکلک + رنگ نام حباب راست ارسال به دیگری + رنگ نام حباب چپ ارسال به دیگری + رنگ آیکن ها + صفحه تنظیمات/قالب دهی + رنگ پس زمینه + رنگ سایه + رنگ بخش + رنگ عنوان + رنگ خلاصه/زیرنویس + رنگ متن \'عکس / استیکر\' + آیا می خواهید برخی از قالب های ساخته شده توسط دیگر کاربران پیام رسان پلاس را بررسی کنید؟ + استفاده از قلم دستگاه + پیام رسان پلاس مجددا راه اندازی می شود! + رنگ آیکن گروه + رنگ نام مخاطب به اشتراک گذاشته شده + رنگ پس زمینه ضمیمه + رنگ متن ضمیمه + نمایش تصویر مخاطب در صفحه گفتوگو + نمایش تصویر خود در صفحه گفتوگو + نمایش آواتار خود در صفحه گروه + تراز آواتار خود به بالا + عنوان گفت و گو / رنگ دکمه + نمایش نام کاربری با نام عضویت + صدا متوقف نشود + رنگ جدا کننده لیست + نام ، عکس و تلفن وسط چین + گرادینت + رنگ کجی + غیرفعال + بالا پایین + چپ راست + بالا-چپ پایین-راست + پایین-چپ بالا-راست + اعمال گرادینت به زمینه لیست + %s به کلیپبورد کپی شد + \n\nبه کانال رسمی پیام رسان پلاس بپیوندید:\nhttps://telegram.me/plusmsgrir + دانلود قالب ها + کانال رسمی + مکالمات + بر روی تصویر مخاطب کلیک کنید + بر روی تصویر گروه کلیک کنید + پروفایل + تصاویر پروفایل + رنگ پس زمینه شمارش سکوت + تیک رنگ دستورات ربات + رنگ دستورات ربات + پررنگ کردن رنگ جستوجو + %s بروز شدند + مخفی کردن وضعیت کاربر + مخفی کردن تب ها + همه + کاربران + گروه ها + سوپر گروه ها + کانال ها + رباط ها + علاقه مندی ها + ارتفاع تب ها + انتخاب بعنوان تب پیش فرض + بازنشانی تب پیش فرض + مرتب سازی بر اساس وضعیت + مرتب سازی بر اساس آخرین تماس + مرتب سازی بر اساس پیام خوانده نشده + نشان دادن تب سوپر گروه ها + مخفی کردن تب سوپر گروه ها + تب ها + نشان دادن/مخفی کردن تب ها + اضافه کردن به علاقه مندی ها + حذف از علاقه مندی ها + بندون علاقه مندی\n\nبرای اضافه کردن یک مخاطب به علاقه مندی ها، روی آن کلیک طولانی کنید و سپس اضافه کردن به علاقه ها را بفشارید + مخفی نکردن تب ها هنگام پیمایش + حرکت نامحدود بین تب ها + نشان دادن کلید اشتراک مستقیم + نقل قول + حذف از لیست مدیر ها + نشان دادن نام کاربری بجای شماره تلفن + علامت به عنوان خوانده شده + علامت گذاری همه دیالوگ ها به عنوان خوانده شده + مدل تیک ها + نشان دادن کلید اشتراک مستقیم در پاپ آپ منو + کلید اشتراک مستقیم پاسخ بدهد + هنگام اشتراک مستقیم ابتدا علاقه مندی ها نمایش داده شود +
diff --git a/TMessagesProj/src/main/res/values-he/strings.xml b/TMessagesProj/src/main/res/values-he/strings.xml new file mode 100644 index 00000000..b943fa5e --- /dev/null +++ b/TMessagesProj/src/main/res/values-he/strings.xml @@ -0,0 +1,1293 @@ + + + טלגרם + עברית + hebrew + he + + הטלפון שלך + נא אשר את קוד המדינה שלך והזן את מספר הטלפון שלך. + בחר מדינה + קוד מדינה שגוי + + הקוד שלך + שלחנו הודעת SMS עם קוד הפעלה לטלפון שלך. + אנחנו נתקשר אליך תוך %1$d:%2$02d + מתקשר אליך... + קוד + מספר שגוי? + "לא קיבלת את הקוד?" + + השם שלך + הגדר את שמך ותמונת הפרופיל שלך + + שם פרטי + שם משפחה + בטל רישום + + הגדרות + אנשי קשר + קבוצה חדשה + אתמול + אין תוצאות + אין שיחות עדיין... + התחל התכתבות על ידי לחיצה על\nכפתור העיפרון בפינה ימנית העליונה\nאו עבור למקטע אנשי הקשר... + ממתין לרשת... + מתחבר... + מעדכן... + שיחה חשאית חדשה + ממתין ל %s שיתחבר... + שיחה חשאית בוטלה + החלפת מפתחות הצפנה ... + %s הצטרף לשיחתך החשאית. + הצטרפת לשיחה החשאית. + נקה היסטוריה + מחק מהמטמון + מחק וצא + מחק שיחה + חשבון מחוק + בחר שיחה + לחץ והחזק כדי לראות + %1$s משתמש בגירסה ישנה של טלגרם, ולכן תמונות סודיות יוצגו במצב תאימות.\n\nלאחר ש %2$s יעדכן את טלגרם, תמונות עם שעון עצר של דקה או פחות יתחילו לעבוד במצב לחץ והחזק כדי לראות, ותקבל התראה בכל פעם שהצד השני מבצע צילום מסך. + הודעות + חיפוש + השתק התראות + השתק למשך %1$s + בטל השתקה + למשך %1$s + כבוי + תגיות + אחרונים + תצוגה מקדימה לקישור + + הגדר כמנהל + אתה יכול לתת תיאור לקבוצה שלך. + עזוב את הקבוצה + מחק קבוצה + עזוב את הקבוצה + מחק קבוצה + כל ההודעות בקבוצה ימחקו. + אתה יכול להוסיף מנהלים שיעזרו לך בניהול הקבוצה. לחץ והחזק כדי להסיר אותם. + חכה! מחיקת הקבוצה תמחק ממנה את כל המשתמשים וההודעות. למחוק את הקבוצה בכל זאת? + קבוצה נוצרה + un1 הוסיף אותך לקבוצה + אתה בטוח שאתה רוצה לעזוב את הקבוצה? + "מצטערים, אינך יכול להוסיף משתמש זה לקבוצה." + מצטערים, הקבוצה מלאה. + מצטערים, משתמש זה עזב את הקבוצה, ולכן אינך יכול לחבר אותו. + מצטערים, יותר מידי מנהלים בקבוצה זו. + מצטערים, יותר מידי רובוטים בקבוצה זו. + קבוצה זו שודרגה לסופר קבוצה + %1$s שודרגה לסופר קבוצה + "משתמשים חסומים שהוסרו מהקבוצה יכולים להתחבר רק על ידי הזמנת מנהל. קישור הזמנה לא יעבוד להם." + ערוץ חדש + שם ערוץ + תגובות + אם אתה מפעיל את תכונות התגובות, משתמשים יוכלו לדון על הודעה שלך בערוץ. + הוסף אנשי קשר לערוץ שלך + משתמשים יכולים לשתף קישור זה עם אחרים ולמצוא את הערוץ שלך על ידי חיפוש בטלגרם. + + קישור + משתמשים יוכלו להצטרף לערוץ שלך באמצעות קישור. אתה יכול להחליף את הקישור בכל עת. + תיאור + אתה יכול לתת תיאור לערוץ שלך. + ערוץ ציבורי + ערוצים ציבוריים מופיעים בחיפוש, כל אחד יכול להתחבר אליהם. + ערוץ פרטי + לערוץ פרטי ניתן להצטרף רק באמצעות קישור הזמנה. + קישור + קישור הזמנה + הוסף משתמשים + עזוב את הערוץ + עזוב את הערוץ + הגדרות + הצטרף + מידע ערוץ + רשימת שידור + תגובה + הצג תגובות + מה זה ערוץ? + ערוצים הם כלי חדש להפצת ההודעות שלך לקהלים גדולים. + צור ערוץ + מצטערים, השם כבר תפוס. + מצטערים, השם לא חוקי. + השם לא יכול להיות קצר יותר מ 5 תווים. + השם לא יכול להיות ארוך יותר מ 32 תווים. + "שם הערוץ לא יכול להתחיל במספר." + + + בודק שם… + %1$s זמין. + משתמשים + משתמשים חסומים + מנהלים + מחק ערוץ + מחק ערוץ + המתן! מחיקת הערוץ תסיר את כל המשתתפים ותמחק את כל הודעות. למחוק את הערוץ בכל זאת? + אתה בטוח שאתה רוצה לעזוב את הערוץ? + אתה תאבד את כל ההודעות בערוץ. + ערוך + + "בבקשה שים לב אם תבחר ליצור קישור ציבורי לקבוצה, כל אחד יוכל למצוא ולהצטרף לקבוצה. + אנא בחר קישור לערוץ הציבורי שלך, כך שמשתמשים יוכלו למצוא אותו בחיפוש ולשתף אותו עם אחרים.\n\nאם אתה לא מעוניים בכך, אנו מציעים שתיצור ערוץ פרטי. + ערוץ נוצר + תמונת ערוץ שונתה + תמונת ערוץ הוסרה + שם ערוץ שונה ל un2 + מצטערים, יצרת יותר מידי ערוצים ציבוריים. אתה יכול ליצור ערוץ פרטי או למחוק תחילה ערוץ קיים. + מפקח + יוצר + מנהל + השתק + בטל השתקה + הוסף מנהל + הזמן באמצעות קישור + אתה בטוח שאתה רוצה להפוך את %1$s למנהל? + הסר + רק מנהלי הערוץ יכולים לראות את הרשימה. + "משתמש זה לא התחבר עדיין לערוץ. רוצה להזמין אותו?" + כל מי שמשתמש בתוכנת טלגרם יוכל להצטרף לערוץ שלך על ידי הקישור הבא. + אתה יכול להוסיף מנהלים שיעזרו לך בניהול הערוץ. לחץ והחזק להסרת מנהל. + "אתה מעוניין להצטרף לערוץ '%1$s'?" + מצטערים, ערוץ זה אינו זמין יותר. + להוסיף את %1$s לערוץ? + מצטערים, משתמש זה עזב את הערוץ, ולכן אינך יכול להזמין אותו חזרה. + "מצטערים, אתה לא יכול לצרף משתמש זה לערוצים." + מצטערים, יש יותר מידי מנהלים בערוץ זה. + מצטערים, יש יותר מידי רובוטים בערוץ. + "מצטערים, אתה יכול להוסיף רק את ה 200 משתמשים הראשונים בערוץ. לידיעתך ניתן לצרף מספר בלתי מוגבל של משתמשים על ידי קישור." + un1 הוסיף אותך לערוץ + אתה מחובר לערוץ + הסר מהערוץ + "מצטערים, אינך יכול לשלוח הודעות בערוץ זה." + %1$s הוסיף אותך לערוץ %2$s + התמונה בערוץ %1$s עודכנה + %1$s שלח הודעה לערוץ %2$s + %1$s שלח תמונה לערוץ %2$s + %1$s שלח וידאו לערוץ %2$s + %1$s שיתף איש קשר בערוץ %2$s + %1$s שלח מיקום לערוץ %2$s + %1$s שלח קובץ לערוץ %2$s + %1$s שלח הנפשה לערוץ %2$s + %1$s שלח קובץ קול לערוץ %2$s + %1$s שלח מדבקה לערוץ %2$s + %1$s פירסם הודעה + %1$s פירסם תמונה + %1$s פירסם וידאו + %1$s פירסם איש קשר + %1$s פירסם מיקום + %1$s פירסם קובץ + %1$s פירסם הנפשה + %1$s פירסם הודעה קולית + %1$s פירסם מדבקה + מי יכול להוסיף משתמשים? + כל המשתמשים + רק מנהלים + משתמשים יקבלו התראה כאשר אתה מפרסם הודעה + משתמשים לא יקבלו התראה כאשר אתה מפרסם הודעה + סמן הודעות + הוסף את שמות המנהלים כאשר הם מפרסמים הודעה. + + רשימת שידור חדשה + הזן שם רשימת שידור + יצרת רשימת שידור + הוסף נמען + הסר מרשימת שידור + + הוסף בבקשה קבצים לתיקיית המוזיקה שלך במכשיר כדי לראות אותם כאן. + מוזיקה + אמן לא ידוע + שם לא ידוע + + בחר קובץ + חינם %1$s מתוך %2$s + שגיאה לא מוכרת + שגיאת גישה + אין קבצים עדיין... + "גודל הקובץ לא יכול להיות גדול מ %1$s" + אמצעי אחסון לא מחובר + העברה ב Usb פעילה + זיכרון פנימי + זיכרון חיצוני + System Root + כרטיס זיכרון + תיקיה + כדי לשלוח תמונות ללא דחיסה + + בלתי נראה + מקליד... + מקליד... + מקלידים... + %1$s מקליט קול... + %1$s שולח תמונה... + %1$s שולח וידאו... + %1$s שולח קובץ... + מקליט קול... + שולח תמונה... + שולח וידאו... + שולח קובץ... + יש לך שאלה\nעל טלגרם? + צלם תמונה + גלריה + מיקום + וידאו + קובץ + מצלמה + אין הודעות עדיין. + הודעה הועברה + מ + אין הודעות אחרונות + הודעה + כתוב הודעה + שתף את מידע האיש קשר שלי + הוסף לאנשי קשר + %s הזמין אותך להצטרף לשיחה חשאית. + הזמנת את %s להצטרף לשיחה חשאית. + שיחות חשאיות: + השתמש בהצפנה מקצה לקצה + לא משאיר עקבות בשרתים שלנו + קיים טיימר להשמדה עצמית + אל תאפשר העברת הודעה + נזרקת מהקבוצה + עזבת את הקבוצה + מחק קבוצה זו + מחק שיחה זו + החלק לביטול + שמור לתיקיית הורדות + שמור אל הנפשות + למחוק הנפשה? + שמור למוזיקה + שתף + החל קובץ שפה + קובץ מצורף לא נתמך. + הגדר זמן השמדה עצמית + שירות התראות + מקבל מידע קישור... + פתח בדפדפן + העתק כתובת + שלח %1$s + לפתוח את הקישור %1$s? + דווח ספאם + הוסף איש קשר + אתה בטוח שאתה רוצה לדווח על משתמש זה כספאם? + אתה בטוח שאתה רוצה לדווח על קבוצה זו כספאם? + מצטערים, אתה יכול לשלוח הודעות רק לאנשי קשר כעת. + מצטערים, אתה יכול להוסיף לקבוצה רק משתמשים שנמצאים באנשי הקשר שלך. + https://telegram.org/faq#can-39t-send-messages-to-non-contacts + מידע נוסף + שלח אל... + לחץ כאן לגשת להנפשות השמורות + + %1$s כיוון את השעון להשמדה עצמית %2$s + הינך מגדיר את שעון העצר להשמדה עצמית ל %1$s + %1$s ביטל את שעון ההשמדה העצמית + ביטלת את שעון ההשמדה העצמית + יש לך הודעה חדשה + %1$s: %2$s + %1$s שלח לך הודעה + %1$s שלח לך תמונה + %1$s שלח לך וידאו + %1$s שיתף איתך איש קשר + %1$s שלח לך מיקום + %1$s שלח לך קובץ + %1$s שלח לך הנפשה + %1$s שלח לך קובץ קול + %1$s שלח לך מדבקה + %1$s @ %2$s: %3$s + %1$s שלח הודעה לקבוצה %2$s + %1$s שלח תמונה לקבוצה %2$s + %1$s שלח וידאו לקבוצה %2$s + %1$s שיתף איש קשר בקבוצה %2$s + %1$s שלח מיקום לקבוצה %2$s + %1$s שלח קובץ לקבוצה %2$s + %1$s שלח הנפשה לקבוצה %2$s + %1$s שלח קובץ קול לקבוצה %2$s + %1$s שלח מדבקה לקבוצה %2$s + %1$s הזמין אותך לקבוצה %2$s + %1$s ערך את השם של קבוצת %2$s + %1$s ערך את התמונה של קבוצת %2$s + %1$s הזמין את %3$s לקבוצה %2$s + %1$s חזר לקבוצה %2$s + %1$s הסיר את %3$s מהקבוצה %2$s + %1$s הסיר אותך מהקבוצה %2$s + %1$s עזב את הקבוצה %2$s + %1$s הצטרף לטלגרם! + %1$s,\nקלטנו התחברות לחשבון שלך ממכשיר חדש ב %2$s\n\nהתקן: %3$s\nמיקום: %4$s\n\nאם זה לא אתה, אתה יכול לעבור להגדרות - פרטיות ואבטחה - חיבורים ולסגור את החיבור.\n\nאם אתה חושש שמישהו מנסה להתחבר לחשבון שלך בניגוד לרצונך, אתה יכול להפעיל אימות דו שלבי בהגדרות פרטיות ואבטחה.\n\nתודה,\nצוות טלגרם + %1$s עדכן את תמונת הפרופיל שלו + %1$s הצטרף לקבוצה %2$s באמצעות קישור הזמנה + השב + השב ל %1$s + השב ל %1$s + %1$s %2$s + + בחר איש קשר + אין אנשי קשר עדיין + "היי, בואו נעבור לטלגרם: https://telegram.org/dl" + ב + אתמול ב + מחובר + נראה לאחרונה + נראה לאחרונה + נראה לאחרונה ממש עכשיו + הזמן חברים + חיפוש כללי + נראה לאחרונה בתקופה האחרונה + נראה לאחרונה השבוע + נראה לאחרונה החודש + נראה לאחרונה לפני זמן רב + הודעה חדשה + + שלח הודעה ל... + תוכל להוסיף עוד משתמשים לאחר שתסיים ליצור את הקבוצה ולהמיר אותה לסופר קבוצה. + הזן שם לקבוצה + שם קבוצה + %1$d/%2$d משתמשים + "אתה מעוניין להצטרף לקבוצה '%1$s'?" + מצטערים, קבוצה זו מלאה כבר. + מצטערים, נראה שהקבוצה כבר לא קיימת. + קישור הועתק ללוח העריכה + הזמן לקבוצה באמצעות קישור + קישור הזמנה + אתה בטוח שאתה רוצה להחליף קישור זה? אם תעשה זאת, אף אחד לא יוכל יותר להשתמש בו כדי להתחבר לקבוצה. + קישור ההזמנה הקודם לא פעיל כעת. קישור חדש נוצר. + החלף + החלף קישור + העתק קישור + שתף קישור + כל אחד שמותקן לו טלגרם יוכל להתחבר אל הקבוצה על ידי הקישור הבא. + + מנהלי קבוצה + כל המשתמשים מנהלים + כל המשתמשים יכולים להוסיף משתמשים, ולערוך את השם והתמונה של הקבוצה. + רק מנהלים יכולים להוסיף ולהסיר משתמשים, ולערוך את שם ותמונת הקבוצה. + + מדיה משותפת + הגדרות + הוסף משתתף + הגדר מנהלים + מחק ועזוב קבוצה + התראות + הסר מהקבוצה + שדרג לסופר קבוצה + שים לב שמשתמשים חייבים לעדכן את תוכנת הטלגרם שלהם לגירסה אחרונה כדי להשתמש בסופר קבוצות. אתה בטוח שאתה רוצה לשדרג את הקבוצה? + <b>מגבלת מכסת חברים.</b>\n\nכדי להעלות את מכסת המשתמשים ולקבל תכונות נוספות, שדרג לסופר קבוצה:\n\n• בסופר קבוצות ניתן להשתתף עד %1$s\n• חברים חדשים רואים את כל ההיסטוריה\n• מנהלים יכולים למחוק הודעה לכולם\n• התראות מושתקות כברירת מחדל + + שתף + הוסף + הוסף איש קשר + חסום איש קשר + ערוך + מחק + בית + נייד + עבודה + אחר + ראשי + התחל שיחה חשאית + אירעה שגיאה. + מפתח הצפנה + שעון עצר להשמדה עצמית + כבוי + "תמונה זו היא הדמיה של מפתח ההצפנה לשיחה חשאית זו עם <b>%1$s</b>.<br><br>אם תמונה זו נראית זהה על הטלפון של <b>%2$s's</b> , השיחה שלך היא 200%% מאובטחת.<br><br>למד עוד ב telegram.org" + https://telegram.org/faq#secret-chats + לא ידוע + מידע + טלפון + + שם משתמש + שם המשתמש שלך + מצטערים, שם המשתמש כבר תפוס. + מצטערים, שם המשתמש לא חוקי. + שם המשתמש קצר יותר מ 5 תווים. + שם המשתמש לא יכול להיות ארוך יותר מ 32 תווים. + "מצטערים, שם המשתמש לא יכול להתחיל במספר." + אתה יכול לבחור שם משתמש לשימוש ב<b>טלגרם</b>. אם תעשה זאת, משתמשים אחרים יוכלו לחפש אותך על ידי שם משתמש זה וליצור איתך קשר מבלי לדעת את מספר הטלפון שלך.<br><br>ניתן להשתמש בתווים <b>a–z</b>, <b>0–9</b> וקו תחתון. מינימום אור שם משתמש <b>5</b> תווים. + בודק שם משתמש... + %1$s פנוי. + ללא + אירעה שגיאה. + + מדבקות + "אמנים מוזמנים להוסיף חבילות מדבקות משל עצמם על ידי שימוש ברובוט @stickers.\n\nמשתמשים יוכלו להוסיף אותם על ידי לחיצה עליהם ובחירה ב \"הוסף למדבקות\"." + הוסף מדבקות + הוסף למדבקות + לא נמצאו מדבקות + הסר + מדבקות חדשות נוספו + הסתר + הצג + שתף + העתק קישור + מדבקות הוסרו + אין מדבקות עדיין + מצטערים, הגעת למספר המקסימלי של חבילות מדבקות מוגדרות. + + אפס את כל הגדרות ההתראות לברירת המחדל + גודל טקסט בהודעות + שאל שאלה + אפשר אנימציות + הסר חסימה + הקש והחזק על משתמש לבטל את החסימה. + אין משתמשים חסומים עדיין + התראות על הודעות + התראה + תצוגה מקדימה של הודעה + הודעות קבוצה + צלילים + הודעות באפליקציה + צלילים באפליקציה + רטט באפליקציה + רטט + תצוגה מקדימה באפליקציה + איפוס + אפס את כל ההתראות + לבטל את כל הגדרות ההתראה המותאמות אישית לכל אנשי הקשר והקבוצות שלך + התראות וצלילים + משתמשים חסומים + התנתק + אין צלילים + ברירת מחדל + תמיכה + רק במצב שקט + רקע שיחה + הודעות + אנטר לשליחה + סגור את כל החיבורים האחרים + אירועים + איש קשר הצטרף לטלגרם + שפה + שים לב! התמיכה בטלגרם נעשית בהתנדבות. אנו מנסים לענות בהקדם האפשרי, אבל זה עלול לקחת זמן.<br><br>אנו בדוק בדף <a href=http://telegram.org/faq#general>שאלות ותשובות</a>: יש בו תשובות להרבה שאלות וטיפים חשובים <a href=http://telegram.org/faq#troubleshooting>לבעיות נפוצות</a>. + שאל מתנדבים + שאלות ותשובות + https://telegram.org/faq + למחוק תרגום? + קובץ תרגום לא תקין + פעיל + לא פעיל + שירות התראות + אם שירותי החנות של גוגל מספיקים עבורך לקבלת התראות, אתה יכול לכבות את שירות ההתראות. אך אנו ממליצים להשאיר את זה פעיל כדי שהתוכנה תעבוד ברקע ותספק לך התראות מיידיות. + מיין לפי + ייבא אנשי קשר + שם פרטי + שם משפחה + צבע חיווי + התראות בהודעה מוקפצת + ללא חלון קופץ + רק כאשר המסך דולק + רק כאשר המסך כבוי + הצג תמיד חלון קופץ + מספר הודעות בסמל + קצר + ארוך + ברירת מחדל של המערכת + הגדרות ברירת מחדל + הורדת מדיה אוטומטית + בעת שימוש בחיבור סלולרי + בעת חיבור לרשת אלחוטית + בעת נדידה + אין מדיה + הפעל הנפשות אוטומטית + הרם ודבר + שמור לגלריה + ערוך שם + עדיפות + ברירת מחדל + נמוך + גבוה + מקסימלי + לעולם לא + התראה חוזרת + אתה יכול לשנות כאן את מספר הטלפון המקושר לטלגרם. החשבון שלך וכל המידע המאוחסן בענן — הודעות, מדיה, אנשי קשר, ועוד. יועברו לחשבון במספר החדש.\n\n<b>חשוב מאוד:</b> כל אנשי הקשר שלך בטלגרם יראו את ה<b>מספר החדש</b> שלך בספר הטלפונים שלהם, במידה וכבר היה להם את המספר הקודם שלך ולא חסמת אותם בטלגרם. + "כל אנשי הקשר שלך בטלגרם יראו את המספר החדש שלך בספר הטלפונים שלהם, במידה וכבר היה להם את המספר הקודם שלך ולא חסמת אותם בטלגרם." + שנה מספר + מספר חדש + אנחנו נשלח הודעה עם קוד אימות למספר החדש. + המספר %1$s כבר מחובר לחשבון טלגרם. מחק בבקשה את החשבון לפני שאתה מחבר אותו לחשבון חדש. + אחר + כבוי + כבוי + כבוי + כבוי + צלילים בשיחה + ברירת מחדל + ברירת מחדל + התראות חכמות + כבוי + נשמע הרבה %1$s בתוך %2$s + דקות + פעמים + בתוך + נשמע הרבה + תצוגת קישורים מוקדמת + שיחה סודית + + הגדרות מטמון + מסד נתונים מקומי + למחוק מטמון הודעות טקסט? + מחיקת המטמון המקומי ימחק את הודעות הטקסט מהמטמון ויקטין את מסד הנתונים המקומי כדי לחסוך שטח אחסון. טלגרם צריכה נתונים מסויימים כדי לעבוד, ולכן מסד הנתונים לא יכול להיות בגודל אפס.\n\nפעולה זו יכולה לקחת כמה דקות. + נקה מטמון + מחק + מחשב... + מסמכים + תמונות + הודעות קוליות + וידאו + מוסיקה + קבצים אחרים + ריק + שמור מדיה + תמונות, וידאו וקבצים אחרים מהשיחות בענן ש<b>לא נגישות עבורך</b> בתקופת זמן זו יוסרו מההתקן על מנת לחסוך מקון.\n\nכל המדיה נשארת מאוחסנת בענן של טלגרם ותוכל להוריד אותה שוב אם תרצה. + לנצח + + חיבורים פעילים + חיבור נוכחי + אין חיבורים פעילים אחרים + אתה יכול להתחבר לטלגרם ממכשיר נייד, טאבלט או מחשב אחרים, על ידי שימוש באותו מספר. כל הנתונים שלך יסונכרנו מיידית. + חיבורים פעילים + שלוט על החיבורים שלך במכשירים אחרים. + לחץ על חיבור כדי לסגור אותו. + לסגור חיבור זה? + תוכנה לא רשמית + + קוד + שנה קוד + כאשר אתה מגדיר סיסמה נוספת, יופיע סמל מנעול בחלון השיחה. לחץ עליו כדי לפתוח או לנעול את טלגרם.\n\nשים לב: אם תשכח את הסיסמה, יהיה עליך להתקין את התוכנה מחדש. וכל השיחות החשאיות שלך ימחקו. + אתה תראה כעת סמל מנעול בשיחה. לחץ עליו כדי לנעול את תוכנת טלגרם עם סיסמה. + PIN + סיסמה + הזן את הסיסמה הנכונה שלך + הזן קוד + הזן את הקוד החדש שלך + הזן את הקוד שלך + הזן שוב את הקוד החדש שלך + קוד שגוי + הקודים לא תואמים + נעילה אוטומטית + תדרש סיסמה לאחר זמן של חוסר פעילות. + תוך %1$s + כבוי + שחרר על ידי טביעת אצבע + אמת את טביעת האצבע להמשך + חיישן מגע + טביעת האצבע לא מוכרת. נסה שוב + + שתף תמונות וסרטונים בשיחה זו וגש אליהם מכל ההתקנים שלך. + קבצים + מדיה משותפת + קישורים משותפים + מוזיקה משותפת + שתף מוזיקה ומסמכים בשיחה ותהיה לך אליהם גישה מכל מקום. + שתף קבצים ומסמכים בשיחה ותהיה לך אליהם גישה מכל מקום. + שתף קישורים בשיחה זו ותוכל לגשת אליהם מכל מכשיר. + + מפה + לווין + היברידי + מטר משם + ק\'מ משם + שלח מיקום + שלח מיקום שנבחר + שתף מיקום + מדויק ל %1$s + או בחר מקום + + הצג את כל המדיה + שמור לגלריה + %1$d מתוך %2$d + גלריה + כל התמונות + כל הסרטונים + אין עדיין תמונות + אין סרטונים עדיין + הורד בבקשה תחילה את המדיה + אין תמונות אחרונות + אין הנפשות אחרונות + חפש תמונות + חיפוש באינטרנט + חיפוש הנפשות + חיפוש באינטרנט + חיפוש הנפשות + גזור תמונה + ערוך תמונה + שפר + הבהרה + ניגודיות + חשיפה + חום + רוויה + Vignette + צללים + מגורען + ליטוש + דעיכה + גוון + צל + הדגשה + עיוות + הכל + אדום + ירוק + כחול + טשטוש + כבוי + קוי + מעגלי + אתה בטוח שאתה רוצה למחוק תמונה זו? + אתה בטוח שאתה רוצה למחוק וידאו זה? + לבטל שינויים? + למחוק היסטוריית חיפושים? + נקה + תמונות + וידאו + הוסף כיתוב... + כותרת תמונה + כותרת וידאו + טקסט + + אימות דו שלבי + הגדר סיסמה נוספת + אתה יכול להגדיר סיסמה נוספת שתידרש בעת חיבור החשבון למכשיר חדש בנוסף לקוד שמתקבל בהודעה. + הסיסמה שלך + הזן בבקשה את הסיסמה שלך + הזן סיסמה + הזן בבקשה את הסיסמה החדשה שלך + הזן בבקשה שוב את הסיסמה החדשה שלך + מייל שחזור + המייל שלך + הוסף בבקשה כתובת מייל חוקית שלך. רק דרכה תוכל לבצע שחזור סיסמה למקרה שתשכח. + דלג + אזהרה + לא, ברצינות.\n\nאם אתה תשכח את הסיסמה, אתה תאבד את הגישה לחשבון הטלגרם שלך. ולא תהיה דרך לשחזר אותו. + כמעט סיימנו! + "בדוק בבקשה את תיבת המייל (אל תשכח לבדוק גם את תיבת הספאם) כדי להשלים את הגדרת האימות דו שלבי." + הושלם! + סיסמת האימות הדו שלבי שלך פעילה כעת. + שנה סיסמה + כבה סיסמה + הגדר מייל לשחזור + שנה מייל שחזור + אתה בטוח שאתה רוצה לבטל את דרישת הסיסמה? + רמז לסיסמה + צור בבקשה רמז לסיסמה + הסיסמאות לא תואמות + צא מהגדרת אימות דו שלבי + אנא עקוב אחרי הפעולות להשלמת הגדרת אימות דו שלבי:\n\n1. בדוק את המייל (אל תשכח לבדוק גם בתיבת הספאם)\n%1$s\n\n2. לחץ על קישור האימות. + הרמז חייב להיות שונה מהסיסמה + מייל לא תקין + מצטערים + "כיון שלא סיפקת מייל לשחזור בעת הגדרת הסיסמה נותרו לך האפשרויות הבאות, להיזכר בסיסמה או לאפס את החשבון או לאפס את החשבון שלך." + שלחנו קוד שחזור לכתובת שמייל שסיפקת לנו:\n\n%1$s + בדוק בבקשה את המייל והזן כאן את קוד 6 הספרות שהתקבל במייל. + יש לך בעיות בגישה למייל %1$s? + "אם אין לך גישה אל המייל, נותרו לך האפשרויות הבאות להיזכר בסיסמה או לאפס את החשבון." + אפס את החשבון שלי + אתה תאבד את כל השיחות וההודעות שלך, כולל כל המדיה והקבצים המשותפים, אם תמשיך בתהליך האיפוס. + אזהרה + פעולה זו לא ניתנת לשחזור.\n\nאם תאפס את החשבון שלך, כל ההודעות והשיחות שלך ימחקו. + אפס + סיסמה + הפעלת אימות דו שלבי, ולכן החשבון שלך מוגן באמצעות סיסמה נוספת. + שכחת את הסיסמה? + שחזור סיסמה + קוד + סיסמה לא פעילה + הפעלת אימות דו שלבי.\nאתה צריך את הסיסמה שהגדרת כאן כדי להתחבר לחשבון הטלגרם שלך. + מייל לשחזור %1$s עדיין לא פעיל והוא ממתין לאימות. + + פרטיות ואבטחה + פרטיות + נראה לאחרונה + כל אחד + אנשי הקשר שלי + אף אחד + כל אחד (-%1$d) + אנשי הקשר שלי (+%1$d) + אנשי הקשר שלי (-%1$d) + אנשי הקשר שלי (-%1$d, +%2$d) + אף אחד (+%1$d) + אבטחה + השמדת חשבון אוטומטית + "אם אתה לא מחובר במשך" + אם לא תתחבר לחלוטין בתקופת הזמן שהוגדרה, החשבון שלך ימחק כולל כל הקבוצות, ההודעות ואנשי הקשר. + למחוק את החשבון שלך? + הגדר מי יכול לראות מתי נראית לאחרונה. + מי יוכל לראות מתי נראית לאחרונה? + הוסף חריגים + "חשוב: לא תוכל לראות מתי משתמשים אחרים נראו לאחרונה אם אתה לא משתף את המידע מתי אתה נראית לאחרונה. במקום זאת תוכל לראות מידע כללי על מתי הם נראו לאחרונה (בתקופה האחרונה, השבוע, החודש)." + שתף תמיד עם + לעולם אל תשתף עם + הגדרות אלו יעקפו את הערכים שמעל. + שתף תמיד + שתף תמיד עם משתמשים... + לעולם אל תשתף + לעולם אל תשתף עם משתמשים... + הוסף משתמשים + מצטערים, בקשות רבות מידי. לא ניתן לשנות את הגדרות הפרטיות כעת, נסה שוב מאוחר יותר. + התנתק בכל המכשירים מלבד ממכשיר זה. + לחץ והחזק על המשתמש כדי למחוק. + קבוצות + מי יכול להוסיף אותי לקבוצות + אתה יכול להגביל מי יכול להוסיף אותך לערוצים וקבוצות במפורט. + אפשר תמיד + לעולם אל תאפשר + אפשר תמיד... + לעולם אל תאפשר... + המשתמשים הבאים יוכלו או לא יוכלו להוסיף אותך לערוצים או קבוצות בהתאם להגדרות שמעל. + שנה את ההגדרה מי יוכל להוסיף אותך לערוצים וקבוצות. + "מצטערים, אתה לא יכול להוסיף משתמש זה לקבוצה בגלל הגדרות הפרטיות שלו." + "מצטערים, אתה לא יכול להוסיף משתמש זה לערוץ בגלל הגדרות הפרטיות שלו." + "מצטערים, אינך יכול ליצור קבוצה עם משתמש זה בגלל הגדרות פרטיות." + + ערוך וידאו + וידאו מקורי + וידאו ערוך + שולח וידאו... + דחוס וידאו + + רובוט + שתף + הוסף לקבוצה + הגדרות + עזרה + עם גישה להודעות + ללא גישה להודעות + מה הרובוט הזה עושה? + התחל + הפעל מחדש + עצור רובוט + הפעל רובוט מחדש + + הבא + חזור + סיום + פתח + שמור + ביטול + סגור + הוסף + ערוך + שלח + התקשר + העתק + מחק + מחק ועצור + העבר + נסה שוב + ממצלמה + מגלריה + מחק תמונה + הגדר + אישור + גזור + + הצטרפת לקבוצה על ידי קישור הזמנה + un1 הצטרף לקבוצה על ידי קישור הזמנה + un1 הסיר את un2 + un1 עזב את הקבוצה + un1 הוסיף את un2 + un1 הסיר את תמונת הקבוצה + un1 שינה את תמונה הקבוצה + un1 שינה את שם הקבוצה ל un2 + un1 יצר את הקבוצה + העפת את un2 + עזבת את הקבוצה + הוספת את un2 + הסרת את תמונת הקבוצה + שינית את תמונת הקבוצה + שינית את שם הקבוצה ל un2 + יצרת קבוצה + un1 העיף אותך + un1 הוסיף אותך + un1 חזר לקבוצה + חזרת אל הקבוצה + הודעה זו אינה נתמכת בגירסת הטלגרם שלך. עדכן את התוכנה כדי לראות: http://telegram.org/update + תמונה + וידאו + הנפשה + מיקום + איש קשר + קובץ + מדבקה + קול + אתה + צילמת את המסך! + un1 צילם את המסך! + + מספר טלפון לא חוקי + פג תוקף הקוד, אנא התחבר שוב. + יותר מידי נסיונות, נסה שוב מאוחר יותר + יותר מידי נסיונות, נסה שוב בעוד %1$s + קוד לא חוקי + שם פרטי לא חוקי + שם משפחה לא חוקי + טוען... + אין לך נגן וידאו, עליך להתקין אחד כדי להמשיך. + שלח לנו בבקשה מייל לכתובת sms@stel.com ופרט את התקלה שלך. + "אין לך אף תוכנה שיודעת לפתוח קובץ מסוג '%1$s', התקן בבקשה אחת כזו להמשך" + למשתמש זה אין עדיין טלגרם, לשלוח הזמנה? + האם אתה בטוח? + להוסיף את %1$s לקבוצה %2$s? + מספר ההודעות שיועברו: + להוסיף את %1$s לקבוצה? + משתמש זה מחובר כבר לקבוצה + להעביר הודעה אל %1$s? + שלח הודעות אל %1$s? + לשלוח איש קשר אל %1$s? + אתה בטוח שאתה רוצה להתנתק?\n\nאתה יכול להשתמש בתוכנת טלגרם סימולטנית במספר מכשירים.\n\nזכור, התנתקות תמחק את כל השיחות הסודיות שלך. + אתה בטוח שאתה רוצה לנתק את כל החיבורים האחרים? + אתה בטוח שאתה רוצה לעזוב ולמחוק קבוצה זו? + אתה בטוח שאתה רוצה למחוק שיחה זו? + אתה בטוח שאתה רוצה לשתף את המידע שלך? + אתה בטוח שאתה רוצה לחסום משתמש זה? + אתה בטוח שאתה רוצה לבטל את חסימת משתמש זה? + אתה בטוח שאתה רוצה למחוק איש קשר זה? + אתה בטוח שאתה רוצה להתחיל שיחה חשאית? + אתה בטוח שאתה רוצה לבטל את ההרשמה? + אתה בטוח שאתה רוצה למחוק את ההיסטוריה? + למחוק את כל מטמון המדיה וההודעות של ערוץ זה? + למחוק את כל מטמון המדיה וההודעות של סופר קבוצה זו? + אתה בטוח שאתה רוצה למחוק את %1$s? + שלח הודעות אל %1$s? + לשלוח איש קשר אל %1$s? + העבר הודעה אל %1$s? + מצטערים, תכונה זו לא זמינה עדיין במדינה שלך. + אין חשבון טלגרם עם שם משתמש זה. + "רובוט זה אינו יכול להצטרף לקבוצות." + אתה מעוניים להפעיל תצוגה מוקדמת מורחבת לקישורים בשיחות סודיות? שים לב שמידע הקישור נוצר בשרתי טלגרם. + "שים לב בבקשה רובוטים המופעלים תוך כדי כתיבה נוצרו על ידי מפתחים חיצוניים. על מנת שהרובוט יעבוד, תווים שאתה כותב לאחר שם המשתמש של הרובוט נשלחים ישירות למפתח." + אתה מעוניין להפעיל תכונת הרם ודבר בהודעות קוליות? + "מצטערים, אינך יכול לערוך הודעות." + + לטלגרם נדרשת הרשאה לאנשי הקשר שלך על מנת שתוכל לשוחח עם אנשי הקשר שלך מכל המכשירים. + לטלגרם נדרשת הרשאה לאחסון שלך כדי שתוכל לשלוח ולשמור תמונות, סרטים, מוזיקה ומדיה אחרת. + לטלגרם נדרשת הרשאה למיקרופון שלך כדי שתוכל לשלוח הודעות קוליות. + לטלגרם נדרשת הרשאה למיקום שלך כדי שתוכל לשתף אותו עם חבריך. + הגדרות + + Telegram + מהיר + חינם + בטוח + מאובטח + מבוסס ענן + פרטי + ברוך הבא<br/>לעידן חדש של התכתבויות. + <b>Telegram</b> מספק הודעות מהר יותר<br/>יותר מכל יישום אחר. + <b>Telegram</b> הוא חינמי לתמיד.<br/>אינו מכיל מודעות. ללא דמי מנוי. + <b>Telegram</b> אין מגבלות על הגודל<br/>על המדיה והשיחות שלך. + <b>Telegram</b> שומר את ההודעות שלך מוגנים<br/>מפני התקפות האקרים. + <b>Telegram</b> נותן לך גישה להודעות<br/>שלך במספר מכשירים במקביל. + <b>Telegram</b> ההודעות מוצפנות<br/>ובעלות יכולות השמדה עצמית + התחל להתכתב + + %1$d מחוברים + %1$d מחובר + %1$d מחוברים + %1$d מחוברים + %1$d מחוברים + %1$d מחובר + אין משתמשים + משתמש %1$d + %1$d משתמשים + %1$d משתמשים + %1$d משתמשים + %1$d משתמשים + ועוד %1$d אנשים כותבים + ועוד %1$d אנשים כותבים + ועוד %1$d אנשים כותבים + ועוד %1$d אנשים כותבים + ועוד %1$d אנשים כותבים + ועוד %1$d אנשים כותבים + אין הודעות חדשות + הודעה חדשה %1$d + %1$d הודעות חדשות + %1$d הודעות חדשות + %1$d הודעות חדשות + %1$d הודעות חדשות + אין הודעות + הודעה %1$d + %1$d הודעות + %1$d הודעות + %1$d הודעות + %1$d הודעות + %1$d תגובות + תגובה %1$d + %1$d תגובות + %1$d תגובות + %1$d תגובות + %1$d תגובות + אין פריטים + פריט %1$d + %1$d פריטים + %1$d פריטים + %1$d פריטים + %1$d פריטים + מאף שיחה + משיחה %1$d + מ %1$d שיחות + מ %1$d שיחות + מ %1$d שיחות + מ %1$d שיחות + %1$d שניות + שניה %1$d + %1$d שניות + %1$d שניות + %1$d שניות + %1$d שניות + %1$d דקות + דקה %1$d + %1$d דקות + %1$d דקות + %1$d דקות + %1$d דקות + %1$d שעות + שעה %1$d + %1$d שעות + %1$d שעות + %1$d שעות + %1$d שעות + %1$d ימים + יום %1$d + %1$d ימים + %1$d ימים + %1$d ימים + %1$d ימים + %1$d שבועות + שבוע %1$d + %1$d שבועות + %1$d שבועות + %1$d שבועות + %1$d שבועות + %1$d חודשים + חודש %1$d + %1$d חודשים + %1$d חודשים + %1$d חודשים + %1$d חודשים + %1$d שנים + שנה %1$d + %1$d שנים + %1$d שנים + %1$d שנים + %1$d שנים + %1$d משתמשים + משתמש %1$d + %1$d משתמשים + %1$d משתמשים + %1$d משתמשים + %1$d משתמשים + %1$d פעמים + פעם %1$d + %1$d פעמים + %1$d פעמים + %1$d פעמים + %1$d פעמים + %1$d מטרים + מטר %1$d + %1$d מטרים + %1$d מטרים + %1$d מטרים + %1$d מטרים + %1$d מדבקות + מדבקה %1$d + %1$d מדבקות + %1$d מדבקות + %1$d מדבקות + %1$d מדבקות + %1$d תמונות + תמונה %1$d + %1$d תמונות + %1$d תמונות + %1$d תמונות + %1$d תמונות + נראה לאחרונה לפני %1$d דקות + נראה לאחרונה לפני דקה %1$d + נראה לאחרונה לפני %1$d דקות + נראה לאחרונה לפני %1$d דקות + נראה לאחרונה לפני %1$d דקות + נראה לאחרונה לפני %1$d דקות + נראה לאחרונה לפני %1$d שעות + נראה לאחרונה לפני שעה %1$d + נראה לאחרונה לפני %1$d שעות + נראה לאחרונה לפני %1$d שעות + נראה לאחרונה לפני %1$d שעות + נראה לאחרונה לפני %1$d שעות + + %1$d הודעות הועברו + הודעה הועברה + %1$d הודעות הועברו + %1$d הודעות הועברו + %1$d הודעות הועברו + %1$d הודעות הועברו + %1$d קבצים הועברו + קובץ הועבר + %1$d קבצים הועברו + %1$d קבצים הועברו + %1$d קבצים הועברו + %1$d קבצים הועברו + %1$d תמונות הועברו + תמונה הועברה + %1$d תמונות הועברו + %1$d תמונות הועברו + %1$d תמונות הועברו + %1$d תמונות הועברו + %1$d סרטונים הועברו + סרטון הועבר + %1$d סרטונים הועברו + %1$d סרטונים הועברו + %1$d סרטונים הועברו + %1$d סרטונים הועברו + %1$d רצועות הועברו + רצועה הועברה + %1$d רצועות הועברו + %1$d רצועות הועברו + %1$d רצועות הועברו + %1$d רצועות הועברו + %1$d קבצי קול הועברו + קובץ קול הועבר + %1$d קבצי קול הועברו + %1$d קבצי קול הועברו + %1$d קבצי קול הועברו + %1$d קבצי קול הועברו + %1$d מיקומים הועברו + מיקום הועבר + %1$d מיקומים הועברו + %1$d מיקומים הועברו + %1$d מיקומים הועברו + %1$d מיקומים הועברו + %1$d אנשי קשר הועברו + איש קשר הועבר + %1$d אנשי קשר הועברו + %1$d אנשי קשר הועברו + %1$d אנשי קשר הועברו + %1$d אנשי קשר הועברו + %1$d מדבקות הועברו + %1$d מדבקות הועברו + מדבקה הועברה + %1$d מדבקות הועברו + %1$d מדבקות הועברו + %1$d מדבקות הועברו + ו %1$d אחרים + ו %1$d אחר + ו %1$d אחרים + ו %1$d אחרים + ו %1$d אחרים + ו %1$d אחרים + + MMMM yyyy + MMM dd + dd.MM.yy + dd.MM.yyyy + MMMM d + MMMM d, yyyy + EEE + HH:mm + h:mm a + %1$s ב %2$s + + טלגרם פלוס לאנדרואיד + מחיל עיצוב + הגדרות פלוס + קוד צבע שגוי! + צבע עיצוב + אפס הגדרות עיצוב + בטל את כל הגדרות העיצוב + אפס את הגדרות העיצוב לברירת המחדל! + כללי + מסכים + מסך ראשי + מסך שיחה + מסך אנשי קשר + כותרת + שורות + רשימת שיחות + רשימת שיחות + רשימת אנשי קשר + צבע כותרת + צבע שם + גודל טקסט שם + צבע הודעה + גודל טקסט הודעה + צבע תאריך/שעה + גודל טקסט תאריך/שעה + צבע מונה + גודל כתב מונה + צבע שורה + צבע רקע מונה + צבע סטטוס + גודל טקסט סטטוס + צבע בועה ימנית + צבע בועה שמאלית + צבע תאריך + גודל כתב תאריך + צבע בועת תאריך + צבע טקסט ימני + צבע טקסט שמאלי + צבע זמן ימני + צבע זמן שמאלי + גודל טקסט זמן + צבע שדה כתיבה + גודל טקסט בכתיבה + צבע רקע שדה כתיבה + צבע רקע סמיילי + צבע כרטיסיית סמיילי שנבחרה + צבע סמל כרטיסיית סמיילים + צבע מחובר + מוזיקה + שמור עיצוב + שמור את העיצוב שלך בתיקיה Telegram/Themes + עיצוב נשמר! + %1$s נשמר ב %2$s + לא נוצר עדיין עיצוב. החל שינוי כלשהו תחילה, בבקשה + העדפות שוחזרו מכרטיס זיכרון + לא נמצא קובץ העדפות ב %s + לא נמצא כרטיס זיכרון. + הזן שם + עיצובים + החל עיצוב + החל עיצוב מקובץ xml בתיקיה מקומית + צבע משתמש + צבע סימונים + צבע מושתק + שלח יומנים + אין יומנים + נקה יומנים + יומנים נמחקו + שלח סמל + הסתר מספר סלולרי מהתפריט + צבע עט צף + צבע רקע חלון צף + קהילה בגוגל פלוס + צבע מקליד + צבע סמל שדה כתיבה + מגירת ניווט + רשימת אפשרויות + צבע רשימה + גודל טקסט שם + צבע מספר טלפון + גודל טקסט מספר טלפון + צבע תמונה אישית + צבע סמל אפשרויות + צבע אפשרויות + גודל טקסט אפשרויות + צבע גירסה + גודל טקסט גירסה + צבע טקבט כותרת + צבע סמלים בכותרת + צבע סמל כרטיסיה + צבע מספר כרטיסיה + צבע רקע מספר כרטיסיה + מנה שיחות במקום הודעות + מנה רק הודעות שלא נקראו + הסתר מספרי כרטיסיות + צבע מפריד + רדיוס תמונה אישית + הגדר צבע משתמש + צבע שם הועבר מ + טקסט כותרת + העבר ללא קרדיט + בטל חלון קופץ בלחיצה + פרופיל קבוצה/איש קשר + הסתר רקע מותאם אישי + צבע קישור ימני + צבע קישור שמאלי + עיצוב הוחל! + לחץ אישור להפעלה מחדש של התוכנה + הצג סמיילים של הטלפון + סגנון בועה + שמור שמות קובץ מקוריים + במקום שם של מחרוזת מספרים בפורמט תאריך + גודל תמונה אישית + ישר תמונת איש קשר ללמעלה + גבולות תמונה אישית + צבע שם קבוצה + גודל טקסט שם קבוצה + צבע שם (משתמש לא מוכר) + הסתר צל רקע מותאם אישי + הגדר צבע רקע + צבע רקע + גודל חלון סמיילי + Forward right bubble name color + Forward left bubble name color + צבע סמלים + מסך הגדרות/עיצובים + צבע רקע + צבע צל + צבע אזור + צבע כותרת + צבע תוכן/כיתוביות + צבע טקסט \'תמונה/מדבקה\' + רוצה לבדוק עיצובים אחרים שנוצרו על ידי משתמשי טלגרם פלוס? + השתמש בגופן המכשיר + טלגרם פלוס יופעל מחדש + צבע סמל קבוצה + צבע איש קשר משותף + צבע רקע קובץ מצורף + צבע טקסט קובץ מצורף + הצג תמונת איש קשר בחלון השיחה + הצג את התמונה האישית שלי במסך השיחה + הצג את התמונה האישית שלי במסך הקבוצה + יישר את התמונה האישית שלי ללמעלה + צבע לחצן/כותרת תיבת דו שיח + הצג שם משתמש יחד עם שם התצוגה + אל תפסיק אודיו + צבע מפריד רשימה + יישר למרכז תמונת איש קשר, שם וטלפון + שיפוע + צבע שיפוע + כבוי + למעלה למטה + שמאל ימין + למעלה משמאל למטה מימין + למטה משמאל למעלה מימין + החל שיפוע לרשימת רקע + %s הועתק ללוח + + +התחבר לערוץ הרישמי של טלגרם פלוס: https://telegram.me/plusmsgr + הורד עיצובים + ערוץ רשמי + תיבות דו שיח + לחץ על תמונת איש קשר + לחץ על תמונת קבוצה + פרופיל + תמונות פרופיל + צבע רקע מונה מושתקים + בדוק צבע פקודות רובוט + צבע פקודות רובוט + צבע הדגשת ערך חיפש + %s עודכן + הסתר מידע מצב משתמש + הסתר כרטיסיות + הכל + משתמשים + קבוצות + סופר קבוצות + ערוצים + רובוטים + מועדפים + גובה כרטיסיות + הגדר ככרטיסית ברירת מחדל + אפס כרטיסית ברירת מחדל + מיין לפי סטטוס + מיין לפי הודעה אחרונה + מיין לפי הודעות שלא נקראו + הצג כרטיסיית סופר קבוצות + הסתר כרטיסית סופר קבוצות + כרטיסיות + הסתר/הצג כרטיסיות + הוסף למועדפים + מחק מהמועדפים + אין עדיין מועדפים\n\nכדי להוסיף שיחה כלשהי לרשימה פשוט לחץ והחזק על השיחה ואז לחץ על \'הוסף למועדפים\'. + אל תסתיר כרטיסיות בעת גלילה + מעבר אינסופי בין כרטיסיות + הצג לחצן \'שיתוף ישיר\' + ציטוט + הסר מרשימת המנהלים + הצג שם משתמש במקום מספר טלפון + סמן כנקרא + סמן את הכל כנקרא + בדוק עיצוב + diff --git a/TMessagesProj/src/main/res/values-iw/strings.xml b/TMessagesProj/src/main/res/values-iw/strings.xml new file mode 100644 index 00000000..a1d0f2d7 --- /dev/null +++ b/TMessagesProj/src/main/res/values-iw/strings.xml @@ -0,0 +1,1295 @@ + + + טלגרם + עברית + Hebrew + iw + + הטלפון שלך + נא אשר את קוד המדינה שלך והזן את מספר הטלפון שלך. + בחר מדינה + קוד מדינה שגוי + + הקוד שלך + שלחנו הודעת SMS עם קוד הפעלה לטלפון שלך. + אנחנו נתקשר אליך תוך %1$d:%2$02d + מתקשר אליך... + קוד + מספר שגוי? + "לא קיבלת את הקוד?" + + השם שלך + הגדר את שמך ותמונת הפרופיל שלך + + שם פרטי + שם משפחה + בטל רישום + + הגדרות + אנשי קשר + קבוצה חדשה + אתמול + אין תוצאות + אין שיחות עדיין... + התחל התכתבות על ידי לחיצה על\nכפתור העיפרון בפינה ימנית העליונה\nאו עבור למקטע אנשי הקשר... + ממתין לרשת... + מתחבר... + מעדכן... + שיחה חשאית חדשה + ממתין ל %s שיתחבר... + שיחה חשאית בוטלה + החלפת מפתחות הצפנה ... + %s הצטרף לשיחתך החשאית. + הצטרפת לשיחה החשאית. + נקה היסטוריה + מחק מהמטמון + מחק וצא + מחק שיחה + חשבון מחוק + בחר שיחה + לחץ והחזק כדי לראות + %1$s משתמש בגירסה ישנה של טלגרם, ולכן תמונות סודיות יוצגו במצב תאימות.\n\nלאחר ש %2$s יעדכן את טלגרם, תמונות עם שעון עצר של דקה או פחות יתחילו לעבוד במצב לחץ והחזק כדי לראות, ותקבל התראה בכל פעם שהצד השני מבצע צילום מסך. + הודעות + חיפוש + השתק התראות + השתק למשך %1$s + בטל השתקה + למשך %1$s + כבוי + תגיות + אחרונים + תצוגה מקדימה לקישור + + הגדר כמנהל + אתה יכול לתת תיאור לקבוצה שלך. + עזוב את הקבוצה + מחק קבוצה + עזוב את הקבוצה + מחק קבוצה + כל ההודעות בקבוצה ימחקו. + אתה יכול להוסיף מנהלים שיעזרו לך בניהול הקבוצה. לחץ והחזק כדי להסיר אותם. + חכה! מחיקת הקבוצה תמחק ממנה את כל המשתמשים וההודעות. למחוק את הקבוצה בכל זאת? + קבוצה נוצרה + un1 הוסיף אותך לקבוצה + אתה בטוח שאתה רוצה לעזוב את הקבוצה? + "מצטערים, אינך יכול להוסיף משתמש זה לקבוצה." + מצטערים, הקבוצה מלאה. + מצטערים, משתמש זה עזב את הקבוצה, ולכן אינך יכול לחבר אותו. + מצטערים, יותר מידי מנהלים בקבוצה זו. + מצטערים, יותר מידי רובוטים בקבוצה זו. + קבוצה זו שודרגה לסופר קבוצה + %1$s שודרגה לסופר קבוצה + "משתמשים חסומים שהוסרו מהקבוצה יכולים להתחבר רק על ידי הזמנת מנהל. קישור הזמנה לא יעבוד להם." + ערוץ חדש + שם ערוץ + תגובות + אם אתה מפעיל את תכונות התגובות, משתמשים יוכלו לדון על הודעה שלך בערוץ. + הוסף אנשי קשר לערוץ שלך + משתמשים יכולים לשתף קישור זה עם אחרים ולמצוא את הערוץ שלך על ידי חיפוש בטלגרם. + + קישור + משתמשים יוכלו להצטרף לערוץ שלך באמצעות קישור. אתה יכול להחליף את הקישור בכל עת. + תיאור + אתה יכול לתת תיאור לערוץ שלך. + ערוץ ציבורי + ערוצים ציבוריים מופיעים בחיפוש, כל אחד יכול להתחבר אליהם. + ערוץ פרטי + לערוץ פרטי ניתן להצטרף רק באמצעות קישור הזמנה. + קישור + קישור הזמנה + הוסף משתמשים + עזוב את הערוץ + עזוב את הערוץ + הגדרות + הצטרף + מידע ערוץ + רשימת שידור + תגובה + הצג תגובות + מה זה ערוץ? + ערוצים הם כלי חדש להפצת ההודעות שלך לקהלים גדולים. + צור ערוץ + מצטערים, השם כבר תפוס. + מצטערים, השם לא חוקי. + השם לא יכול להיות קצר יותר מ 5 תווים. + השם לא יכול להיות ארוך יותר מ 32 תווים. + "שם הערוץ לא יכול להתחיל במספר." + + + בודק שם… + %1$s זמין. + משתמשים + משתמשים חסומים + מנהלים + מחק ערוץ + מחק ערוץ + המתן! מחיקת הערוץ תסיר את כל המשתתפים ותמחק את כל הודעות. למחוק את הערוץ בכל זאת? + אתה בטוח שאתה רוצה לעזוב את הערוץ? + אתה תאבד את כל ההודעות בערוץ. + ערוך + + "בבקשה שים לב אם תבחר ליצור קישור ציבורי לקבוצה, כל אחד יוכל למצוא ולהצטרף לקבוצה. + אנא בחר קישור לערוץ הציבורי שלך, כך שמשתמשים יוכלו למצוא אותו בחיפוש ולשתף אותו עם אחרים.\n\nאם אתה לא מעוניים בכך, אנו מציעים שתיצור ערוץ פרטי. + ערוץ נוצר + תמונת ערוץ שונתה + תמונת ערוץ הוסרה + שם ערוץ שונה ל un2 + מצטערים, יצרת יותר מידי ערוצים ציבוריים. אתה יכול ליצור ערוץ פרטי או למחוק תחילה ערוץ קיים. + מפקח + יוצר + מנהל + השתק + בטל השתקה + הוסף מנהל + הזמן באמצעות קישור + אתה בטוח שאתה רוצה להפוך את %1$s למנהל? + הסר + רק מנהלי הערוץ יכולים לראות את הרשימה. + "משתמש זה לא התחבר עדיין לערוץ. רוצה להזמין אותו?" + כל מי שמשתמש בתוכנת טלגרם יוכל להצטרף לערוץ שלך על ידי הקישור הבא. + אתה יכול להוסיף מנהלים שיעזרו לך בניהול הערוץ. לחץ והחזק להסרת מנהל. + "אתה מעוניין להצטרף לערוץ '%1$s'?" + מצטערים, ערוץ זה אינו זמין יותר. + להוסיף את %1$s לערוץ? + מצטערים, משתמש זה עזב את הערוץ, ולכן אינך יכול להזמין אותו חזרה. + "מצטערים, אתה לא יכול לצרף משתמש זה לערוצים." + מצטערים, יש יותר מידי מנהלים בערוץ זה. + מצטערים, יש יותר מידי רובוטים בערוץ. + "מצטערים, אתה יכול להוסיף רק את ה 200 משתמשים הראשונים בערוץ. לידיעתך ניתן לצרף מספר בלתי מוגבל של משתמשים על ידי קישור." + un1 הוסיף אותך לערוץ + אתה מחובר לערוץ + הסר מהערוץ + "מצטערים, אינך יכול לשלוח הודעות בערוץ זה." + %1$s הוסיף אותך לערוץ %2$s + התמונה בערוץ %1$s עודכנה + %1$s שלח הודעה לערוץ %2$s + %1$s שלח תמונה לערוץ %2$s + %1$s שלח וידאו לערוץ %2$s + %1$s שיתף איש קשר בערוץ %2$s + %1$s שלח מיקום לערוץ %2$s + %1$s שלח קובץ לערוץ %2$s + %1$s שלח הנפשה לערוץ %2$s + %1$s שלח קובץ קול לערוץ %2$s + %1$s שלח מדבקה לערוץ %2$s + %1$s פירסם הודעה + %1$s פירסם תמונה + %1$s פירסם וידאו + %1$s פירסם איש קשר + %1$s פירסם מיקום + %1$s פירסם קובץ + %1$s פירסם הנפשה + %1$s פירסם הודעה קולית + %1$s פירסם מדבקה + מי יכול להוסיף משתמשים? + כל המשתמשים + רק מנהלים + משתמשים יקבלו התראה כאשר אתה מפרסם הודעה + משתמשים לא יקבלו התראה כאשר אתה מפרסם הודעה + סמן הודעות + הוסף את שמות המנהלים כאשר הם מפרסמים הודעה. + + רשימת שידור חדשה + הזן שם רשימת שידור + יצרת רשימת שידור + הוסף נמען + הסר מרשימת שידור + + הוסף בבקשה קבצים לתיקיית המוזיקה שלך במכשיר כדי לראות אותם כאן. + מוזיקה + אמן לא ידוע + שם לא ידוע + + בחר קובץ + חינם %1$s מתוך %2$s + שגיאה לא מוכרת + שגיאת גישה + אין קבצים עדיין... + "גודל הקובץ לא יכול להיות גדול מ %1$s" + אמצעי אחסון לא מחובר + העברה ב Usb פעילה + זיכרון פנימי + זיכרון חיצוני + System Root + כרטיס זיכרון + תיקיה + כדי לשלוח תמונות ללא דחיסה + + בלתי נראה + מקליד... + מקליד... + מקלידים... + %1$s מקליט קול... + %1$s שולח תמונה... + %1$s שולח וידאו... + %1$s שולח קובץ... + מקליט קול... + שולח תמונה... + שולח וידאו... + שולח קובץ... + יש לך שאלה\nעל טלגרם? + צלם תמונה + גלריה + מיקום + וידאו + קובץ + מצלמה + אין הודעות עדיין. + הודעה הועברה + מ + אין הודעות אחרונות + הודעה + כתוב הודעה + שתף את מידע האיש קשר שלי + הוסף לאנשי קשר + %s הזמין אותך להצטרף לשיחה חשאית. + הזמנת את %s להצטרף לשיחה חשאית. + שיחות חשאיות: + השתמש בהצפנה מקצה לקצה + לא משאיר עקבות בשרתים שלנו + קיים טיימר להשמדה עצמית + אל תאפשר העברת הודעה + נזרקת מהקבוצה + עזבת את הקבוצה + מחק קבוצה זו + מחק שיחה זו + החלק לביטול + שמור לתיקיית הורדות + שמור אל הנפשות + למחוק הנפשה? + שמור למוזיקה + שתף + החל קובץ שפה + קובץ מצורף לא נתמך. + הגדר זמן השמדה עצמית + שירות התראות + מקבל מידע קישור... + פתח בדפדפן + העתק כתובת + שלח %1$s + לפתוח את הקישור %1$s? + דווח ספאם + הוסף איש קשר + אתה בטוח שאתה רוצה לדווח על משתמש זה כספאם? + אתה בטוח שאתה רוצה לדווח על קבוצה זו כספאם? + מצטערים, אתה יכול לשלוח הודעות רק לאנשי קשר כעת. + מצטערים, אתה יכול להוסיף לקבוצה רק משתמשים שנמצאים באנשי הקשר שלך. + https://telegram.org/faq#can-39t-send-messages-to-non-contacts + מידע נוסף + שלח אל... + לחץ כאן לגשת להנפשות השמורות + + %1$s כיוון את השעון להשמדה עצמית %2$s + הינך מגדיר את שעון העצר להשמדה עצמית ל %1$s + %1$s ביטל את שעון ההשמדה העצמית + ביטלת את שעון ההשמדה העצמית + יש לך הודעה חדשה + %1$s: %2$s + %1$s שלח לך הודעה + %1$s שלח לך תמונה + %1$s שלח לך וידאו + %1$s שיתף איתך איש קשר + %1$s שלח לך מיקום + %1$s שלח לך קובץ + %1$s שלח לך הנפשה + %1$s שלח לך קובץ קול + %1$s שלח לך מדבקה + %1$s @ %2$s: %3$s + %1$s שלח הודעה לקבוצה %2$s + %1$s שלח תמונה לקבוצה %2$s + %1$s שלח וידאו לקבוצה %2$s + %1$s שיתף איש קשר בקבוצה %2$s + %1$s שלח מיקום לקבוצה %2$s + %1$s שלח קובץ לקבוצה %2$s + %1$s שלח הנפשה לקבוצה %2$s + %1$s שלח קובץ קול לקבוצה %2$s + %1$s שלח מדבקה לקבוצה %2$s + %1$s הזמין אותך לקבוצה %2$s + %1$s ערך את השם של קבוצת %2$s + %1$s ערך את התמונה של קבוצת %2$s + %1$s הזמין את %3$s לקבוצה %2$s + %1$s חזר לקבוצה %2$s + %1$s הסיר את %3$s מהקבוצה %2$s + %1$s הסיר אותך מהקבוצה %2$s + %1$s עזב את הקבוצה %2$s + %1$s הצטרף לטלגרם! + %1$s,\nקלטנו התחברות לחשבון שלך ממכשיר חדש ב %2$s\n\nהתקן: %3$s\nמיקום: %4$s\n\nאם זה לא אתה, אתה יכול לעבור להגדרות - פרטיות ואבטחה - חיבורים ולסגור את החיבור.\n\nאם אתה חושש שמישהו מנסה להתחבר לחשבון שלך בניגוד לרצונך, אתה יכול להפעיל אימות דו שלבי בהגדרות פרטיות ואבטחה.\n\nתודה,\nצוות טלגרם + %1$s עדכן את תמונת הפרופיל שלו + %1$s הצטרף לקבוצה %2$s באמצעות קישור הזמנה + השב + השב ל %1$s + השב ל %1$s + %1$s %2$s + + בחר איש קשר + אין אנשי קשר עדיין + "היי, בואו נעבור לטלגרם: https://telegram.org/dl" + ב + אתמול ב + מחובר + נראה לאחרונה + נראה לאחרונה + נראה לאחרונה ממש עכשיו + הזמן חברים + חיפוש כללי + נראה לאחרונה בתקופה האחרונה + נראה לאחרונה השבוע + נראה לאחרונה החודש + נראה לאחרונה לפני זמן רב + הודעה חדשה + + שלח הודעה ל... + תוכל להוסיף עוד משתמשים לאחר שתסיים ליצור את הקבוצה ולהמיר אותה לסופר קבוצה. + הזן שם לקבוצה + שם קבוצה + %1$d/%2$d משתמשים + "אתה מעוניין להצטרף לקבוצה '%1$s'?" + מצטערים, קבוצה זו מלאה כבר. + מצטערים, נראה שהקבוצה כבר לא קיימת. + קישור הועתק ללוח העריכה + הזמן לקבוצה באמצעות קישור + קישור הזמנה + אתה בטוח שאתה רוצה להחליף קישור זה? אם תעשה זאת, אף אחד לא יוכל יותר להשתמש בו כדי להתחבר לקבוצה. + קישור ההזמנה הקודם לא פעיל כעת. קישור חדש נוצר. + החלף + החלף קישור + העתק קישור + שתף קישור + כל אחד שמותקן לו טלגרם יוכל להתחבר אל הקבוצה על ידי הקישור הבא. + + מנהלי קבוצה + כל המשתמשים מנהלים + כל המשתמשים יכולים להוסיף משתמשים, ולערוך את השם והתמונה של הקבוצה. + רק מנהלים יכולים להוסיף ולהסיר משתמשים, ולערוך את שם ותמונת הקבוצה. + + מדיה משותפת + הגדרות + הוסף משתתף + הגדר מנהלים + מחק ועזוב קבוצה + התראות + הסר מהקבוצה + שדרג לסופר קבוצה + שים לב שמשתמשים חייבים לעדכן את תוכנת הטלגרם שלהם לגירסה אחרונה כדי להשתמש בסופר קבוצות. אתה בטוח שאתה רוצה לשדרג את הקבוצה? + <b>מגבלת מכסת חברים.</b>\n\nכדי להעלות את מכסת המשתמשים ולקבל תכונות נוספות, שדרג לסופר קבוצה:\n\n• בסופר קבוצות ניתן להשתתף עד %1$s\n• חברים חדשים רואים את כל ההיסטוריה\n• מנהלים יכולים למחוק הודעה לכולם\n• התראות מושתקות כברירת מחדל + + שתף + הוסף + הוסף איש קשר + חסום איש קשר + ערוך + מחק + בית + נייד + עבודה + אחר + ראשי + התחל שיחה חשאית + אירעה שגיאה. + מפתח הצפנה + שעון עצר להשמדה עצמית + כבוי + "תמונה זו היא הדמיה של מפתח ההצפנה לשיחה חשאית זו עם <b>%1$s</b>.<br><br>אם תמונה זו נראית זהה על הטלפון של <b>%2$s's</b> , השיחה שלך היא 200%% מאובטחת.<br><br>למד עוד ב telegram.org" + https://telegram.org/faq#secret-chats + לא ידוע + מידע + טלפון + + שם משתמש + שם המשתמש שלך + מצטערים, שם המשתמש כבר תפוס. + מצטערים, שם המשתמש לא חוקי. + שם המשתמש קצר יותר מ 5 תווים. + שם המשתמש לא יכול להיות ארוך יותר מ 32 תווים. + "מצטערים, שם המשתמש לא יכול להתחיל במספר." + אתה יכול לבחור שם משתמש לשימוש ב<b>טלגרם</b>. אם תעשה זאת, משתמשים אחרים יוכלו לחפש אותך על ידי שם משתמש זה וליצור איתך קשר מבלי לדעת את מספר הטלפון שלך.<br><br>ניתן להשתמש בתווים <b>a–z</b>, <b>0–9</b> וקו תחתון. מינימום אור שם משתמש <b>5</b> תווים. + בודק שם משתמש... + %1$s פנוי. + ללא + אירעה שגיאה. + + מדבקות + "אמנים מוזמנים להוסיף חבילות מדבקות משל עצמם על ידי שימוש ברובוט @stickers.\n\nמשתמשים יוכלו להוסיף אותם על ידי לחיצה עליהם ובחירה ב \"הוסף למדבקות\"." + הוסף מדבקות + הוסף למדבקות + לא נמצאו מדבקות + הסר + מדבקות חדשות נוספו + הסתר + הצג + שתף + העתק קישור + מדבקות הוסרו + אין מדבקות עדיין + מצטערים, הגעת למספר המקסימלי של חבילות מדבקות מוגדרות. + + אפס את כל הגדרות ההתראות לברירת המחדל + גודל טקסט בהודעות + שאל שאלה + אפשר אנימציות + הסר חסימה + הקש והחזק על משתמש לבטל את החסימה. + אין משתמשים חסומים עדיין + התראות על הודעות + התראה + תצוגה מקדימה של הודעה + הודעות קבוצה + צלילים + הודעות באפליקציה + צלילים באפליקציה + רטט באפליקציה + רטט + תצוגה מקדימה באפליקציה + איפוס + אפס את כל ההתראות + לבטל את כל הגדרות ההתראה המותאמות אישית לכל אנשי הקשר והקבוצות שלך + התראות וצלילים + משתמשים חסומים + התנתק + אין צלילים + ברירת מחדל + תמיכה + רק במצב שקט + רקע שיחה + הודעות + אנטר לשליחה + סגור את כל החיבורים האחרים + אירועים + איש קשר הצטרף לטלגרם + שפה + שים לב! התמיכה בטלגרם נעשית בהתנדבות. אנו מנסים לענות בהקדם האפשרי, אבל זה עלול לקחת זמן.<br><br>אנו בדוק בדף <a href=http://telegram.org/faq#general>שאלות ותשובות</a>: יש בו תשובות להרבה שאלות וטיפים חשובים <a href=http://telegram.org/faq#troubleshooting>לבעיות נפוצות</a>. + שאל מתנדבים + שאלות ותשובות + https://telegram.org/faq + למחוק תרגום? + קובץ תרגום לא תקין + פעיל + לא פעיל + שירות התראות + אם שירותי החנות של גוגל מספיקים עבורך לקבלת התראות, אתה יכול לכבות את שירות ההתראות. אך אנו ממליצים להשאיר את זה פעיל כדי שהתוכנה תעבוד ברקע ותספק לך התראות מיידיות. + מיין לפי + ייבא אנשי קשר + שם פרטי + שם משפחה + צבע חיווי + התראות בהודעה מוקפצת + ללא חלון קופץ + רק כאשר המסך דולק + רק כאשר המסך כבוי + הצג תמיד חלון קופץ + מספר הודעות בסמל + קצר + ארוך + ברירת מחדל של המערכת + הגדרות ברירת מחדל + הורדת מדיה אוטומטית + בעת שימוש בחיבור סלולרי + בעת חיבור לרשת אלחוטית + בעת נדידה + אין מדיה + הפעל הנפשות אוטומטית + הרם ודבר + שמור לגלריה + ערוך שם + עדיפות + ברירת מחדל + נמוך + גבוה + מקסימלי + לעולם לא + התראה חוזרת + אתה יכול לשנות כאן את מספר הטלפון המקושר לטלגרם. החשבון שלך וכל המידע המאוחסן בענן — הודעות, מדיה, אנשי קשר, ועוד. יועברו לחשבון במספר החדש.\n\n<b>חשוב מאוד:</b> כל אנשי הקשר שלך בטלגרם יראו את ה<b>מספר החדש</b> שלך בספר הטלפונים שלהם, במידה וכבר היה להם את המספר הקודם שלך ולא חסמת אותם בטלגרם. + "כל אנשי הקשר שלך בטלגרם יראו את המספר החדש שלך בספר הטלפונים שלהם, במידה וכבר היה להם את המספר הקודם שלך ולא חסמת אותם בטלגרם." + שנה מספר + מספר חדש + אנחנו נשלח הודעה עם קוד אימות למספר החדש. + המספר %1$s כבר מחובר לחשבון טלגרם. מחק בבקשה את החשבון לפני שאתה מחבר אותו לחשבון חדש. + אחר + כבוי + כבוי + כבוי + כבוי + צלילים בשיחה + ברירת מחדל + ברירת מחדל + התראות חכמות + כבוי + נשמע הרבה %1$s בתוך %2$s + דקות + פעמים + בתוך + נשמע הרבה + תצוגת קישורים מוקדמת + שיחה סודית + + הגדרות מטמון + מסד נתונים מקומי + למחוק מטמון הודעות טקסט? + מחיקת המטמון המקומי ימחק את הודעות הטקסט מהמטמון ויקטין את מסד הנתונים המקומי כדי לחסוך שטח אחסון. טלגרם צריכה נתונים מסויימים כדי לעבוד, ולכן מסד הנתונים לא יכול להיות בגודל אפס.\n\nפעולה זו יכולה לקחת כמה דקות. + נקה מטמון + מחק + מחשב... + מסמכים + תמונות + הודעות קוליות + וידאו + מוסיקה + קבצים אחרים + ריק + שמור מדיה + תמונות, וידאו וקבצים אחרים מהשיחות בענן ש<b>לא נגישות עבורך</b> בתקופת זמן זו יוסרו מההתקן על מנת לחסוך מקון.\n\nכל המדיה נשארת מאוחסנת בענן של טלגרם ותוכל להוריד אותה שוב אם תרצה. + לנצח + + חיבורים פעילים + חיבור נוכחי + אין חיבורים פעילים אחרים + אתה יכול להתחבר לטלגרם ממכשיר נייד, טאבלט או מחשב אחרים, על ידי שימוש באותו מספר. כל הנתונים שלך יסונכרנו מיידית. + חיבורים פעילים + שלוט על החיבורים שלך במכשירים אחרים. + לחץ על חיבור כדי לסגור אותו. + לסגור חיבור זה? + תוכנה לא רשמית + + קוד + שנה קוד + כאשר אתה מגדיר סיסמה נוספת, יופיע סמל מנעול בחלון השיחה. לחץ עליו כדי לפתוח או לנעול את טלגרם.\n\nשים לב: אם תשכח את הסיסמה, יהיה עליך להתקין את התוכנה מחדש. וכל השיחות החשאיות שלך ימחקו. + אתה תראה כעת סמל מנעול בשיחה. לחץ עליו כדי לנעול את תוכנת טלגרם עם סיסמה. + PIN + סיסמה + הזן את הסיסמה הנכונה שלך + הזן קוד + הזן את הקוד החדש שלך + הזן את הקוד שלך + הזן שוב את הקוד החדש שלך + קוד שגוי + הקודים לא תואמים + נעילה אוטומטית + תדרש סיסמה לאחר זמן של חוסר פעילות. + תוך %1$s + כבוי + שחרר על ידי טביעת אצבע + אמת את טביעת האצבע להמשך + חיישן מגע + טביעת האצבע לא מוכרת. נסה שוב + + שתף תמונות וסרטונים בשיחה זו וגש אליהם מכל ההתקנים שלך. + קבצים + מדיה משותפת + קישורים משותפים + מוזיקה משותפת + שתף מוזיקה ומסמכים בשיחה ותהיה לך אליהם גישה מכל מקום. + שתף קבצים ומסמכים בשיחה ותהיה לך אליהם גישה מכל מקום. + שתף קישורים בשיחה זו ותוכל לגשת אליהם מכל מכשיר. + + מפה + לווין + היברידי + מטר משם + ק\'מ משם + שלח מיקום + שלח מיקום שנבחר + שתף מיקום + מדויק ל %1$s + או בחר מקום + + הצג את כל המדיה + שמור לגלריה + %1$d מתוך %2$d + גלריה + כל התמונות + כל הסרטונים + אין עדיין תמונות + אין סרטונים עדיין + הורד בבקשה תחילה את המדיה + אין תמונות אחרונות + אין הנפשות אחרונות + חפש תמונות + חיפוש באינטרנט + חיפוש הנפשות + חיפוש באינטרנט + חיפוש הנפשות + גזור תמונה + ערוך תמונה + שפר + הבהרה + ניגודיות + חשיפה + חום + רוויה + Vignette + צללים + מגורען + ליטוש + דעיכה + גוון + צל + הדגשה + עיוות + הכל + אדום + ירוק + כחול + טשטוש + כבוי + קוי + מעגלי + אתה בטוח שאתה רוצה למחוק תמונה זו? + אתה בטוח שאתה רוצה למחוק וידאו זה? + לבטל שינויים? + למחוק היסטוריית חיפושים? + נקה + תמונות + וידאו + הוסף כיתוב... + כותרת תמונה + כותרת וידאו + טקסט + + אימות דו שלבי + הגדר סיסמה נוספת + אתה יכול להגדיר סיסמה נוספת שתידרש בעת חיבור החשבון למכשיר חדש בנוסף לקוד שמתקבל בהודעה. + הסיסמה שלך + הזן בבקשה את הסיסמה שלך + הזן סיסמה + הזן בבקשה את הסיסמה החדשה שלך + הזן בבקשה שוב את הסיסמה החדשה שלך + מייל שחזור + המייל שלך + הוסף בבקשה כתובת מייל חוקית שלך. רק דרכה תוכל לבצע שחזור סיסמה למקרה שתשכח. + דלג + אזהרה + לא, ברצינות.\n\nאם אתה תשכח את הסיסמה, אתה תאבד את הגישה לחשבון הטלגרם שלך. ולא תהיה דרך לשחזר אותו. + כמעט סיימנו! + "בדוק בבקשה את תיבת המייל (אל תשכח לבדוק גם את תיבת הספאם) כדי להשלים את הגדרת האימות דו שלבי." + הושלם! + סיסמת האימות הדו שלבי שלך פעילה כעת. + שנה סיסמה + כבה סיסמה + הגדר מייל לשחזור + שנה מייל שחזור + אתה בטוח שאתה רוצה לבטל את דרישת הסיסמה? + רמז לסיסמה + צור בבקשה רמז לסיסמה + הסיסמאות לא תואמות + צא מהגדרת אימות דו שלבי + אנא עקוב אחרי הפעולות להשלמת הגדרת אימות דו שלבי:\n\n1. בדוק את המייל (אל תשכח לבדוק גם בתיבת הספאם)\n%1$s\n\n2. לחץ על קישור האימות. + הרמז חייב להיות שונה מהסיסמה + מייל לא תקין + מצטערים + "כיון שלא סיפקת מייל לשחזור בעת הגדרת הסיסמה נותרו לך האפשרויות הבאות, להיזכר בסיסמה או לאפס את החשבון או לאפס את החשבון שלך." + שלחנו קוד שחזור לכתובת שמייל שסיפקת לנו:\n\n%1$s + בדוק בבקשה את המייל והזן כאן את קוד 6 הספרות שהתקבל במייל. + יש לך בעיות בגישה למייל %1$s? + "אם אין לך גישה אל המייל, נותרו לך האפשרויות הבאות להיזכר בסיסמה או לאפס את החשבון." + אפס את החשבון שלי + אתה תאבד את כל השיחות וההודעות שלך, כולל כל המדיה והקבצים המשותפים, אם תמשיך בתהליך האיפוס. + אזהרה + פעולה זו לא ניתנת לשחזור.\n\nאם תאפס את החשבון שלך, כל ההודעות והשיחות שלך ימחקו. + אפס + סיסמה + הפעלת אימות דו שלבי, ולכן החשבון שלך מוגן באמצעות סיסמה נוספת. + שכחת את הסיסמה? + שחזור סיסמה + קוד + סיסמה לא פעילה + הפעלת אימות דו שלבי.\nאתה צריך את הסיסמה שהגדרת כאן כדי להתחבר לחשבון הטלגרם שלך. + מייל לשחזור %1$s עדיין לא פעיל והוא ממתין לאימות. + + פרטיות ואבטחה + פרטיות + נראה לאחרונה + כל אחד + אנשי הקשר שלי + אף אחד + כל אחד (-%1$d) + אנשי הקשר שלי (+%1$d) + אנשי הקשר שלי (-%1$d) + אנשי הקשר שלי (-%1$d, +%2$d) + אף אחד (+%1$d) + אבטחה + השמדת חשבון אוטומטית + "אם אתה לא מחובר במשך" + אם לא תתחבר לחלוטין בתקופת הזמן שהוגדרה, החשבון שלך ימחק כולל כל הקבוצות, ההודעות ואנשי הקשר. + למחוק את החשבון שלך? + הגדר מי יכול לראות מתי נראית לאחרונה. + מי יוכל לראות מתי נראית לאחרונה? + הוסף חריגים + "חשוב: לא תוכל לראות מתי משתמשים אחרים נראו לאחרונה אם אתה לא משתף את המידע מתי אתה נראית לאחרונה. במקום זאת תוכל לראות מידע כללי על מתי הם נראו לאחרונה (בתקופה האחרונה, השבוע, החודש)." + שתף תמיד עם + לעולם אל תשתף עם + הגדרות אלו יעקפו את הערכים שמעל. + שתף תמיד + שתף תמיד עם משתמשים... + לעולם אל תשתף + לעולם אל תשתף עם משתמשים... + הוסף משתמשים + מצטערים, בקשות רבות מידי. לא ניתן לשנות את הגדרות הפרטיות כעת, נסה שוב מאוחר יותר. + התנתק בכל המכשירים מלבד ממכשיר זה. + לחץ והחזק על המשתמש כדי למחוק. + קבוצות + מי יכול להוסיף אותי לקבוצות + אתה יכול להגביל מי יכול להוסיף אותך לערוצים וקבוצות במפורט. + אפשר תמיד + לעולם אל תאפשר + אפשר תמיד... + לעולם אל תאפשר... + המשתמשים הבאים יוכלו או לא יוכלו להוסיף אותך לערוצים או קבוצות בהתאם להגדרות שמעל. + שנה את ההגדרה מי יוכל להוסיף אותך לערוצים וקבוצות. + "מצטערים, אתה לא יכול להוסיף משתמש זה לקבוצה בגלל הגדרות הפרטיות שלו." + "מצטערים, אתה לא יכול להוסיף משתמש זה לערוץ בגלל הגדרות הפרטיות שלו." + "מצטערים, אינך יכול ליצור קבוצה עם משתמש זה בגלל הגדרות פרטיות." + + ערוך וידאו + וידאו מקורי + וידאו ערוך + שולח וידאו... + דחוס וידאו + + רובוט + שתף + הוסף לקבוצה + הגדרות + עזרה + עם גישה להודעות + ללא גישה להודעות + מה הרובוט הזה עושה? + התחל + הפעל מחדש + עצור רובוט + הפעל רובוט מחדש + + הבא + חזור + סיום + פתח + שמור + ביטול + סגור + הוסף + ערוך + שלח + התקשר + העתק + מחק + מחק ועצור + העבר + נסה שוב + ממצלמה + מגלריה + מחק תמונה + הגדר + אישור + גזור + + הצטרפת לקבוצה על ידי קישור הזמנה + un1 הצטרף לקבוצה על ידי קישור הזמנה + un1 הסיר את un2 + un1 עזב את הקבוצה + un1 הוסיף את un2 + un1 הסיר את תמונת הקבוצה + un1 שינה את תמונה הקבוצה + un1 שינה את שם הקבוצה ל un2 + un1 יצר את הקבוצה + העפת את un2 + עזבת את הקבוצה + הוספת את un2 + הסרת את תמונת הקבוצה + שינית את תמונת הקבוצה + שינית את שם הקבוצה ל un2 + יצרת קבוצה + un1 העיף אותך + un1 הוסיף אותך + un1 חזר לקבוצה + חזרת אל הקבוצה + הודעה זו אינה נתמכת בגירסת הטלגרם שלך. עדכן את התוכנה כדי לראות: http://telegram.org/update + תמונה + וידאו + הנפשה + מיקום + איש קשר + קובץ + מדבקה + קול + אתה + צילמת את המסך! + un1 צילם את המסך! + + מספר טלפון לא חוקי + פג תוקף הקוד, אנא התחבר שוב. + יותר מידי נסיונות, נסה שוב מאוחר יותר + יותר מידי נסיונות, נסה שוב בעוד %1$s + קוד לא חוקי + שם פרטי לא חוקי + שם משפחה לא חוקי + טוען... + אין לך נגן וידאו, עליך להתקין אחד כדי להמשיך. + שלח לנו בבקשה מייל לכתובת sms@stel.com ופרט את התקלה שלך. + "אין לך אף תוכנה שיודעת לפתוח קובץ מסוג '%1$s', התקן בבקשה אחת כזו להמשך" + למשתמש זה אין עדיין טלגרם, לשלוח הזמנה? + האם אתה בטוח? + להוסיף את %1$s לקבוצה %2$s? + מספר ההודעות שיועברו: + להוסיף את %1$s לקבוצה? + משתמש זה מחובר כבר לקבוצה + להעביר הודעה אל %1$s? + שלח הודעות אל %1$s? + לשלוח איש קשר אל %1$s? + אתה בטוח שאתה רוצה להתנתק?\n\nאתה יכול להשתמש בתוכנת טלגרם סימולטנית במספר מכשירים.\n\nזכור, התנתקות תמחק את כל השיחות הסודיות שלך. + אתה בטוח שאתה רוצה לנתק את כל החיבורים האחרים? + אתה בטוח שאתה רוצה לעזוב ולמחוק קבוצה זו? + אתה בטוח שאתה רוצה למחוק שיחה זו? + אתה בטוח שאתה רוצה לשתף את המידע שלך? + אתה בטוח שאתה רוצה לחסום משתמש זה? + אתה בטוח שאתה רוצה לבטל את חסימת משתמש זה? + אתה בטוח שאתה רוצה למחוק איש קשר זה? + אתה בטוח שאתה רוצה להתחיל שיחה חשאית? + אתה בטוח שאתה רוצה לבטל את ההרשמה? + אתה בטוח שאתה רוצה למחוק את ההיסטוריה? + למחוק את כל מטמון המדיה וההודעות של ערוץ זה? + למחוק את כל מטמון המדיה וההודעות של סופר קבוצה זו? + אתה בטוח שאתה רוצה למחוק את %1$s? + שלח הודעות אל %1$s? + לשלוח איש קשר אל %1$s? + העבר הודעה אל %1$s? + מצטערים, תכונה זו לא זמינה עדיין במדינה שלך. + אין חשבון טלגרם עם שם משתמש זה. + "רובוט זה אינו יכול להצטרף לקבוצות." + אתה מעוניים להפעיל תצוגה מוקדמת מורחבת לקישורים בשיחות סודיות? שים לב שמידע הקישור נוצר בשרתי טלגרם. + "שים לב בבקשה רובוטים המופעלים תוך כדי כתיבה נוצרו על ידי מפתחים חיצוניים. על מנת שהרובוט יעבוד, תווים שאתה כותב לאחר שם המשתמש של הרובוט נשלחים ישירות למפתח." + אתה מעוניין להפעיל תכונת הרם ודבר בהודעות קוליות? + "מצטערים, אינך יכול לערוך הודעות." + + לטלגרם נדרשת הרשאה לאנשי הקשר שלך על מנת שתוכל לשוחח עם אנשי הקשר שלך מכל המכשירים. + לטלגרם נדרשת הרשאה לאחסון שלך כדי שתוכל לשלוח ולשמור תמונות, סרטים, מוזיקה ומדיה אחרת. + לטלגרם נדרשת הרשאה למיקרופון שלך כדי שתוכל לשלוח הודעות קוליות. + לטלגרם נדרשת הרשאה למיקום שלך כדי שתוכל לשתף אותו עם חבריך. + הגדרות + + Telegram + מהיר + חינם + בטוח + מאובטח + מבוסס ענן + פרטי + ברוך הבא<br/>לעידן חדש של התכתבויות. + <b>Telegram</b> מספק הודעות מהר יותר<br/>יותר מכל יישום אחר. + <b>Telegram</b> הוא חינמי לתמיד.<br/>אינו מכיל מודעות. ללא דמי מנוי. + <b>Telegram</b> אין מגבלות על הגודל<br/>על המדיה והשיחות שלך. + <b>Telegram</b> שומר את ההודעות שלך מוגנים<br/>מפני התקפות האקרים. + <b>Telegram</b> נותן לך גישה להודעות<br/>שלך במספר מכשירים במקביל. + <b>Telegram</b> ההודעות מוצפנות<br/>ובעלות יכולות השמדה עצמית + התחל להתכתב + + %1$d מחוברים + %1$d מחובר + %1$d מחוברים + %1$d מחוברים + %1$d מחוברים + %1$d מחובר + אין משתמשים + משתמש %1$d + %1$d משתמשים + %1$d משתמשים + %1$d משתמשים + %1$d משתמשים + ועוד %1$d אנשים כותבים + ועוד %1$d אנשים כותבים + ועוד %1$d אנשים כותבים + ועוד %1$d אנשים כותבים + ועוד %1$d אנשים כותבים + ועוד %1$d אנשים כותבים + אין הודעות חדשות + הודעה חדשה %1$d + %1$d הודעות חדשות + %1$d הודעות חדשות + %1$d הודעות חדשות + %1$d הודעות חדשות + אין הודעות + הודעה %1$d + %1$d הודעות + %1$d הודעות + %1$d הודעות + %1$d הודעות + %1$d תגובות + תגובה %1$d + %1$d תגובות + %1$d תגובות + %1$d תגובות + %1$d תגובות + אין פריטים + פריט %1$d + %1$d פריטים + %1$d פריטים + %1$d פריטים + %1$d פריטים + מאף שיחה + משיחה %1$d + מ %1$d שיחות + מ %1$d שיחות + מ %1$d שיחות + מ %1$d שיחות + %1$d שניות + שניה %1$d + %1$d שניות + %1$d שניות + %1$d שניות + %1$d שניות + %1$d דקות + דקה %1$d + %1$d דקות + %1$d דקות + %1$d דקות + %1$d דקות + %1$d שעות + שעה %1$d + %1$d שעות + %1$d שעות + %1$d שעות + %1$d שעות + %1$d ימים + יום %1$d + %1$d ימים + %1$d ימים + %1$d ימים + %1$d ימים + %1$d שבועות + שבוע %1$d + %1$d שבועות + %1$d שבועות + %1$d שבועות + %1$d שבועות + %1$d חודשים + חודש %1$d + %1$d חודשים + %1$d חודשים + %1$d חודשים + %1$d חודשים + %1$d שנים + שנה %1$d + %1$d שנים + %1$d שנים + %1$d שנים + %1$d שנים + %1$d משתמשים + משתמש %1$d + %1$d משתמשים + %1$d משתמשים + %1$d משתמשים + %1$d משתמשים + %1$d פעמים + פעם %1$d + %1$d פעמים + %1$d פעמים + %1$d פעמים + %1$d פעמים + %1$d מטרים + מטר %1$d + %1$d מטרים + %1$d מטרים + %1$d מטרים + %1$d מטרים + %1$d מדבקות + מדבקה %1$d + %1$d מדבקות + %1$d מדבקות + %1$d מדבקות + %1$d מדבקות + %1$d תמונות + תמונה %1$d + %1$d תמונות + %1$d תמונות + %1$d תמונות + %1$d תמונות + נראה לאחרונה לפני %1$d דקות + נראה לאחרונה לפני דקה %1$d + נראה לאחרונה לפני %1$d דקות + נראה לאחרונה לפני %1$d דקות + נראה לאחרונה לפני %1$d דקות + נראה לאחרונה לפני %1$d דקות + נראה לאחרונה לפני %1$d שעות + נראה לאחרונה לפני שעה %1$d + נראה לאחרונה לפני %1$d שעות + נראה לאחרונה לפני %1$d שעות + נראה לאחרונה לפני %1$d שעות + נראה לאחרונה לפני %1$d שעות + + %1$d הודעות הועברו + הודעה הועברה + %1$d הודעות הועברו + %1$d הודעות הועברו + %1$d הודעות הועברו + %1$d הודעות הועברו + %1$d קבצים הועברו + קובץ הועבר + %1$d קבצים הועברו + %1$d קבצים הועברו + %1$d קבצים הועברו + %1$d קבצים הועברו + %1$d תמונות הועברו + תמונה הועברה + %1$d תמונות הועברו + %1$d תמונות הועברו + %1$d תמונות הועברו + %1$d תמונות הועברו + %1$d סרטונים הועברו + סרטון הועבר + %1$d סרטונים הועברו + %1$d סרטונים הועברו + %1$d סרטונים הועברו + %1$d סרטונים הועברו + %1$d רצועות הועברו + רצועה הועברה + %1$d רצועות הועברו + %1$d רצועות הועברו + %1$d רצועות הועברו + %1$d רצועות הועברו + %1$d קבצי קול הועברו + קובץ קול הועבר + %1$d קבצי קול הועברו + %1$d קבצי קול הועברו + %1$d קבצי קול הועברו + %1$d קבצי קול הועברו + %1$d מיקומים הועברו + מיקום הועבר + %1$d מיקומים הועברו + %1$d מיקומים הועברו + %1$d מיקומים הועברו + %1$d מיקומים הועברו + %1$d אנשי קשר הועברו + איש קשר הועבר + %1$d אנשי קשר הועברו + %1$d אנשי קשר הועברו + %1$d אנשי קשר הועברו + %1$d אנשי קשר הועברו + %1$d מדבקות הועברו + %1$d מדבקות הועברו + מדבקה הועברה + %1$d מדבקות הועברו + %1$d מדבקות הועברו + %1$d מדבקות הועברו + ו %1$d אחרים + ו %1$d אחר + ו %1$d אחרים + ו %1$d אחרים + ו %1$d אחרים + ו %1$d אחרים + + MMMM yyyy + MMM dd + dd.MM.yy + dd.MM.yyyy + MMMM d + MMMM d, yyyy + EEE + HH:mm + h:mm a + %1$s ב %2$s + + פלוס מסנג\'ר לאנדרואיד + ערכות נושא + הגדרות פלוס + קוד צבע שגוי! + צבע עיצוב + אפס הגדרות עיצוב + בטל את כל הגדרות העיצוב + אפס את הגדרות העיצוב לברירת המחדל! + כללי + מסכים + מסך ראשי + מסך שיחה + מסך אנשי קשר + כותרת + שורות + רשימת שיחות + רשימת שיחות + רשימת אנשי קשר + צבע כותרת + צבע שם + גודל טקסט שם + צבע הודעה + גודל טקסט הודעה + צבע תאריך/שעה + גודל טקסט תאריך/שעה + צבע מונה + גודל כתב מונה + צבע שורה + צבע רקע מונה + צבע סטטוס + גודל טקסט סטטוס + צבע בועה ימנית + צבע בועה שמאלית + צבע תאריך + גודל כתב תאריך + צבע בועת תאריך + צבע טקסט ימני + צבע טקסט שמאלי + צבע זמן ימני + צבע זמן שמאלי + גודל טקסט זמן + צבע שדה כתיבה + גודל טקסט בכתיבה + צבע רקע שדה כתיבה + צבע רקע סמיילי + צבע כרטיסיית סמיילי שנבחרה + צבע סמל כרטיסיית סמיילים + צבע מחובר + מוזיקה + שמור עיצוב + שמור את העיצוב שלך בתיקיה Telegram/Themes + עיצוב נשמר! + %1$s נשמר ב %2$s + לא נוצר עדיין עיצוב. החל שינוי כלשהו תחילה, בבקשה + העדפות שוחזרו מכרטיס זיכרון + לא נמצא קובץ העדפות ב %s + לא נמצא כרטיס זיכרון. + הזן שם + עיצובים + החל עיצוב + החל עיצוב מקובץ xml בתיקיה מקומית + צבע משתמש + צבע סימונים + צבע מושתק + שלח יומנים + אין יומנים + נקה יומנים + יומנים נמחקו + שלח סמל + הסתר מספר סלולרי מהתפריט + צבע עט צף + צבע רקע חלון צף + קהילה בגוגל פלוס + צבע מקליד + צבע סמל שדה כתיבה + מגירת ניווט + רשימת אפשרויות + צבע רשימה + גודל טקסט שם + צבע מספר טלפון + גודל טקסט מספר טלפון + צבע תמונה אישית + צבע סמל אפשרויות + צבע אפשרויות + גודל טקסט אפשרויות + צבע גירסה + גודל טקסט גירסה + צבע טקבט כותרת + צבע סמלים בכותרת + צבע סמל כרטיסיה + צבע מספר כרטיסיה + צבע רקע מספר כרטיסיה + מנה שיחות במקום הודעות + מנה רק הודעות שלא נקראו + הסתר מספרי כרטיסיות + צבע מפריד + רדיוס תמונה אישית + הגדר צבע משתמש + צבע שם הועבר מ + טקסט כותרת + העבר ללא קרדיט + בטל חלון קופץ בלחיצה + פרופיל קבוצה/איש קשר + הסתר רקע מותאם אישי + צבע קישור ימני + צבע קישור שמאלי + עיצוב הוחל! + לחץ אישור להפעלה מחדש של התוכנה + הצג סמיילים של הטלפון + סגנון בועה + שמור שמות קובץ מקוריים + במקום שם של מחרוזת מספרים בפורמט תאריך + גודל תמונה אישית + ישר תמונת איש קשר ללמעלה + גבולות תמונה אישית + צבע שם קבוצה + גודל טקסט שם קבוצה + צבע שם (משתמש לא מוכר) + הסתר צל רקע מותאם אישי + הגדר צבע רקע + צבע רקע + גודל חלון סמיילי + Forward right bubble name color + Forward left bubble name color + צבע סמלים + מסך הגדרות/עיצובים + צבע רקע + צבע צל + צבע אזור + צבע כותרת + צבע תוכן/כיתוביות + צבע טקסט \'תמונה/מדבקה\' + רוצה לבדוק עיצובים אחרים שנוצרו על ידי משתמשי טלגרם פלוס? + השתמש בגופן המכשיר + טלגרם פלוס יופעל מחדש + צבע סמל קבוצה + צבע איש קשר משותף + צבע רקע קובץ מצורף + צבע טקסט קובץ מצורף + הצג תמונת איש קשר בחלון השיחה + הצג את התמונה האישית שלי במסך השיחה + הצג את התמונה האישית שלי במסך הקבוצה + יישר את התמונה האישית שלי ללמעלה + צבע לחצן/כותרת תיבת דו שיח + הצג שם משתמש יחד עם שם התצוגה + אל תפסיק אודיו + צבע מפריד רשימה + יישר למרכז תמונת איש קשר, שם וטלפון + שיפוע + צבע שיפוע + כבוי + למעלה למטה + שמאל ימין + למעלה משמאל למטה מימין + למטה משמאל למעלה מימין + החל שיפוע לרשימת רקע + %s הועתק ללוח + + +התחבר לערוץ הרישמי של טלגרם פלוס: https://telegram.me/plusmsgr + הורד עיצובים + ערוץ רשמי + תיבות דו שיח + לחץ על תמונת איש קשר + לחץ על תמונת קבוצה + פרופיל + תמונות פרופיל + צבע רקע מונה מושתקים + בדוק צבע פקודות רובוט + צבע פקודות רובוט + צבע הדגשת ערך חיפש + %s עודכן + הסתר מידע מצב משתמש + הסתר כרטיסיות + הכל + משתמשים + קבוצות + סופר קבוצות + ערוצים + רובוטים + מועדפים + גובה כרטיסיות + הגדר ככרטיסית ברירת מחדל + אפס כרטיסית ברירת מחדל + מיין לפי סטטוס + מיין לפי הודעה אחרונה + מיין לפי הודעות שלא נקראו + הצג כרטיסיית סופר קבוצות + הסתר כרטיסית סופר קבוצות + כרטיסיות + הסתר/הצג כרטיסיות + הוסף למועדפים + מחק מהמועדפים + אין עדיין מועדפים\n\nכדי להוסיף שיחה כלשהי לרשימה פשוט לחץ והחזק על השיחה ואז לחץ על \'הוסף למועדפים\'. + אל תסתיר כרטיסיות בעת גלילה + מעבר אינסופי בין כרטיסיות + הצג לחצן \'שיתוף ישיר\' + ציטוט + הסר מרשימת המנהלים + הצג שם משתמש במקום מספר טלפון + סמן כנקרא + סמן את הכל כנקרא + בדוק עיצוב + diff --git a/TMessagesProj/src/main/res/values-ja/strings.xml b/TMessagesProj/src/main/res/values-ja/strings.xml new file mode 100644 index 00000000..b7d8e78f --- /dev/null +++ b/TMessagesProj/src/main/res/values-ja/strings.xml @@ -0,0 +1,1058 @@ + + + Plus Messenger + 日本語 + Japanese + ja + + あなたの電話設定 + あなたの国番号を確認し、電話番号を入力してください。 + 国名を選択してください + 国番号が違います + + あなたの認証コードは + 認証コードをショートメッセージで送信しました。ご確認ください。 + 残り%1$d分%2$02d秒で入力のない場合には電話をかけます。 + あなたに電話をかけています… + 認証コード + お間違いでは? + 認証コードを受け取っておりませんか? + + あなたの名前 + 氏名を入力してください + + 名前 (必須) + 名字 (任意) + 登録を中止する + + 設定 + 連絡相手 + 新しいグループを作る + 昨日 + 結果はありません + チャットはありません + 右下の作成ボタンからメッセージを\n作成できます。もしくはメニューボタンで\n他のオプションを選びます。 + 通信待機中… + 接続中… + 更新中… + 秘密のチャットを行う + %s を待っています… + 秘密のチャットは中止になりました + 暗号鍵を交換しています… + %s が秘密のチャットに入りました + あなたは秘密のチャットに入りました + 履歴を消去する + 削除する + 内容を削除する + 削除されたアカウントです + チャットを選びます + 長押しして見る + %1$sが古いTelegramのため、秘密の写真は互換モードで表示されます。\n\n%2$sがTelegramを新しくすると、「1分間のタイマー付きの写真」は「長押しの間だけ表示される状態」になり、第三者がスクリーンショットを撮るたびにあなたへ通知が届きます。 + メッセージ + 内容を検索する + 通知を中断する + %1$sだけ中断する + 通知を再開する + %1$s + 無効 + ハッシュタグ + 最近の検索結果 + + 同時送信リストを作る + リスト名を入れてください + 同時送信リストを作成しました + 相手を追加する + 同時送信リストから削除する + + ライブラリに音楽ファイルを取り込むと表示されます。 + 音楽 + 不明なアーティスト + 不明なタイトル + + ファイルを選びます + 空き %1$s / %2$s + 不明なエラー + アクセスエラー + ファイルはありません + ファイルサイズの上限は %1$s です + ストレージがありません + USB転送可 + 内部ストレージ + 外部ストレージ + システム Root + SDカード + フォルダ + 画像を圧縮しないで送る + + 不可視 + 入力中… + が入力中… + が入力中… + %1$sが録音しています… + %1$sが写真を送信しています… + %1$sが動画を送信しています… + %1$sがファイルを送信しています… + 録音中… + 写真送信中… + 動画送信中… + ファイル送信中… + Telegramへの質問はありますか? + 撮影する + ギャラリー + 位置情報 + 動画 + ファイル + カメラ + メッセージはありません + 転送メッセージ + 送信 + 新しいメッセージはありません + メッセージ + メッセージ + 番号を共有する + 名前を編集する + %s が秘密のチャットに招待しています + %s を秘密のチャットに招待しています + 秘密のチャットとは: + 暗号化した直接通信です + サーバーには残りません + 自動消去タイマーを付けられます + 内容の転送はできません + あなたはこのグループから外されました + あなたはこのグループを外れました + このグループを削除する + このチャットを削除する + スライドして中止する + ダウンロードフォルダに保存する + 音楽を保存する + 共有する + 言語を設定する + サポートされない添付ファイルです + 自動消去タイマーを付ける + 通知サービス + リンク先情報を取得… + ブラウザで開く + URLをコピーする + 送信 %1$s + 開けるURL %1$s? + + %1$s が自動消去タイマーを %2$s にセットしました + 自動消去タイマーを %1$s にセットしました + %1$s が自動消去タイマーを無効にしました + 自動消去タイマーを無効にしました + 新しいメッセージが届いています + %1$s: %2$s + %1$s がメッセージを送りました + %1$s が写真を送りました + %1$s が動画を送りました + %1$s が連絡情報を共有しました + %1$s が位置情報を送りました + %1$s がファイルを送信しました + %1$s が音声を送りました + %1$s がステッカーを送信しました + %1$s @ %2$s: %3$s + %1$s がグループ %2$s にメッセージを送りました + %1$s がグループ %2$s に写真を送りました + %1$s がグループ %2$s に動画を送りました + %1$s がグループ %2$s で連絡情報を共有しました + %1$s がグループ %2$s に位置情報を送りました + %1$s がグループ %2$s にファイルを送信しました + %1$s がグループ %2$s に音声を送りました + %1$s がグループ %2$s にステッカーを送信しました + %1$s があなたをグループ %2$s に招待しました + %1$s がグループ %2$s の名前を編集しました + %1$s がグループ %2$s の写真を編集しました + %1$s が %3$s をグループ %2$s に招待しました + %1$s がグループ %2$s に戻りました + %1$s が %3$s をグループ %2$s から外しました + %1$s があなたをグループ %2$s から外しました + %1$s はグループ %2$s から外れました + %1$s がTelegramをはじめました! + %1$s,異なる機器 %2$s からのログインが検出されました。\n\n機器: %3$s\n位置: %4$s\n\nこのログインに覚えがない場合、設定 - プライバシーとセキュリティ - その他のセッションを終了する、でセッションを終了してください。.\n\n他の人が自分のアカウントにログインしたと思われた場合は2段階認証プロセスを使用する事をお勧めします。\n\nTelegramチーム + %1$s が自己紹介の写真を更新しました + %1$sが招待用のリンクでグループ%2$sに加わりました + 返信する + %1$sへの返信 + %1$sへの返信 + %1$s %2$s + + 相手を追加する + 相手がいません + Telegramを使いませんか?: https://telegram.org/dl + 今日の + 昨日の + オンライン + 既読 + 既読: + 招待する + グローバル検索 + 既読:最近 + 既読:今週中 + 既読:今月中 + 既読:かなり前 + 新しいメッセージ + + メッセージの宛先 + グループ名を入力してください + グループ名 + %1$d/%2$d 名 + グループ \'%1$s\' に参加しますか? + すみませんがグループの人数がもういっぱいです。 + すみませんがこのグループは存在していません。 + クリップボードにリンクをコピーしました + グループへの招待用リンクを作る + 招待用リンク + このリンクを取り消してもよいですか?あなたが取り消した場合このグループへのこのリンクを使用した参加ができなくなります。 + 前のリンクは無効です。新しいリンクが生成されています。 + 取消 + リンクを取り消す + リンクをコピーする + リンクを共有する + Telegramをインストールした人は誰でもこのリンクであなたのグループに参加できるようになります。 + + 共有するメディア + 設定 + 相手を追加する + グループを削除する + 通知 + グループから外す + + 番号を共有する + 名前を編集する + 名前を編集する + ブロックする + 名前を編集する + 名前を削除する + 自宅 + モバイル + 仕事中 + その他 + メイン + 秘密のチャットを行う + エラーが発生しました + 暗号鍵 + 自動消去タイマー + オフ + これは秘密鍵の画像です。]]>%1$s]]>との秘密のチャットで使用されます。
]]>この画像と ]]>%2$s]]> の画像が一致しているなら、あなたのチャットは200%%安全です。
]]>telegram.orgに説明があります。
+ 不明 + 情報 + 電話番号 + + ユーザー名 + あなたのユーザー名 + すみませんがこのユーザー名はすでに使われています。 + すみませんがこのユーザー名は設定できません。 + ユーザー名は5文字以上でお願いします。 + ユーザー名は32文字以下でお願いします。 + すみませんがユーザー名の先頭を数字にはできません。 + ユーザー名を]]>Telegram]]>に設定する事ができます。ユーザー名を設定しますと、あなたのユーザー名を知っている人があなたの電話番号を知らなくてもあなたにメッセージを送信する事ができるようになります。
]]>ユーザー名には]]>a-z]]>までの英字と]]>0-9]]>までの数字、それとアンダースコアを使用する事ができます。ユーザ名は]]>5]]>文字以上が必要です。
+ ユーザー名を確認しています… + %1$s は使用可能です。 + 未設定 + エラーが発生しました。 + + ステッカーの一覧 + "@stickersを利用したクリエイターによるステッカーパックの追加を歓迎します。\n\n利用者はそれらをタップする事でステッカーを追加する事ができます。" + ステッカーを追加する + ステッカーに追加する + ステッカーが見つかりません + ステッカーを消去しました + ステッカーを追加しました + 隠す + 使う + 共有する + リンクをコピーする + 消去する + ステッカーはありません + + すべての通知設定を初期状態に戻す + メッセージの文字サイズ + 質問する + アニメーション + ブロックを解除する + 長押しするとブロックを解除できます。 + ブロックした相手はいません + メッセージ通知 + お知らせ通知 + メッセージのプレビュー + グループ通知 + 通知音 + アプリ内通知 + アプリ内の通知音 + アプリ内のバイブレーション + バイブレーション + アプリ内のプレビュー + リセット + すべての通知をリセットする + 連絡相手およびグループ内の通知設定をすべて元に戻す + 通知とサウンド + ブロックした相手 + ログアウトする + 通知音なし + デフォルト + サポート + 消音時のみ + チャット画面の背景設定 + メッセージ + 改行キーを押して送信する + その他の端末からの接続を切る + イベント + Telegramと電話帳を同期する + 言語 + Telegramはボランティアによってサポートしています。可能な限り迅速に回答しますが、
]]>その前にTelegramに関するよくある質問]]>を見てください。そこにはよくある質問へのヒントや答え]]>が載っています。
+ 質問する + Telegram FAQ + https://telegram.org/faq + 言語ファイルを削除しますか? + 言語ファイルが間違っています + 有効 + 無効 + 通知サービス + Google Play開発者サービスで問題なく通知が届いていれば無効にしても良いですが、より確実に通知を受け取るためには有効にすることをおすすめします。 + 並び替え: + 連絡情報を取り込む + 名前 + 名字 + LEDの色 + ポップアップ通知 + ポップアップなし + 画面が点いている時のみ + 画面が消えている時のみ + ポップアップを常に表示する + 件数表示 + 短め + 長め + システムデフォルト + 初期設定 + メディアの自動ダウンロード + モバイル通信利用時 + Wi-Fi利用時 + ローミング接続利用時 + メディアなし + ギャラリーに保存する + 名前を編集する + 優先順位 + デフォルト + 低い + 高い + 最高 + 設定しない + 通知の繰り返し時間 + ここから電話番号の変更ができます。あなたのクラウド上のデータ、メッセージ、ファイル、グループ、連絡相手、その他はすべて新しい電話番号に移されます。\n\n重要:]]> あなたの新しい番号]]>はTelegramの連絡相手(あなたの以前の番号を知っていて、あなたがTelegramでブロックしていない相手)の電話帳に加えられます。 + あなたの新しい番号はTelegramの連絡相手(あなたの以前の番号を知っていて、あなたがTelegramでブロックしていない相手)の電話帳に加えられます。 + 電話番号を変更する + 新しい電話番号 + 認証コードは新しい電話番号にSMSで送信されます。 + %1$s はTelegramのアカウントで使用されています。移行する前にそのアカウントを削除してください。 + その他 + 無効 + 無効 + 無効 + ずっと + チャットのサウンド + デフォルト + デフォルト + スマート通知 + 無効 + サウンドを%2$sに%1$sまで鳴らす + サウンドを最大 + +   + 分間に鳴らす + + 現在の接続状況を見る + 使用中のセッション + 他に活動中のセッションはありません + 同じ電話番号でその他のモバイルやタブレットやデスクトップからのログインが可能です。データはすべて同期されます。 + 活動中のセッション + あなたの接続状況は他の機器からも制御可能です。 + 押すとそのセッションを終了する事ができます。 + このセッションを終了しますか? + 非公式アプリ + + 暗証番号でロックする + 暗証番号を変更する + 暗証番号を設定するとチャット画面をロックする事ができます。ロックの開閉は画面上にあるロックアイコンで行います。\n\n注意:暗証番号を忘れてしまった場合にはアプリの再インストールが必要になります。その時に秘密のチャットの内容は全て失われます。 + 暗証番号を設定するとチャット画面をロックする事ができます。ロックの開閉は画面上にあるロックアイコンで行います。 + PINコード + パスワード + 暗証番号を入力してください + 暗証番号を入力してください + 新しい暗証番号を入力してください + 暗証番号を入力してください + 暗証番号を再度入力してください + 不適な暗証番号です + 暗証番号が一致しません + 自動ロック + 指定した期間使用しない場合に暗証番号が必要となります。 + %1$s + 無効 + + 共有するメディアはありません + 共有したファイル + 共有するメディア + 共有したリンク + このチャットで共有したファイルもしくはドキュメントはあなたのどの機器からでもアクセスできます。 + このチャットで共有したリンクはどの機器からでもアクセスできます。 + + 地図 + 衛星 + ハイブリッド + m 離れています + km 離れています + あなたの現在位置を送信する + 選択した位置情報を送信する + 位置情報 + 誤差 %1$s + もしくは場所を選択してください + + すべてのメディアを表示する + ギャラリーに保存する + %1$d / %2$d + ギャラリー + すべての写真 + すべての動画 + 写真はありません + 動画はありません + 最初にメディアをダウンロードしてください + 新しい写真はありません + GIFはありません + 画像一覧 + WEB検索 + GIF一覧 + ウェブ検索 + GIFファイル検索 + 画像を切り取る + 画像編集 + 強調 + ハイライト + コントラスト + 明るさ + 色温度 + 彩度 + ビネット + 陰影 + グレイン + シャープ + ブラー + オフ + リニア + ラジアル + 本当にこの写真を削除しますか? + 本当にこの動画を削除しますか? + 変更を破棄しますか? + 検索履歴を消去しますか? + 消去する + 写真 + 動画 + 説明文を追加する… + 写真の説明文 + 動画の説明文 + + 2段階認証を設定する + パスワードを設定する + SMSによるコードの取得とは別に、新たな機器へのログイン時に使用するパスワードを設定する事ができます。 + あなたのパスワード + パスワードを入力してください + パスワードを入力してください + 新しいパスワードを入力してください + パスワードを再度入力してください + メールによる回復設定 + あなたのメールアドレス + パスワードを忘れた場合に使用するあなたの有効なメールアドレスを設定してください。 + 省略 + 注意 + もしもパスワードを忘れた場合、\nあなたはTelegramのアカウントに接続する方法を失う事になります。 + 確認してください! + 2段階認証を完了するために(迷惑メールフォルダも確認してください)、あなたのメールアドレスを確認してください。 + 完了しました! + あなたの2段階認証用のパスワードを有効にしました。 + パスワードを変更する + パスワードを無効にする + 回復用のメールアドレスを設定する + 回復用のメールアドレスを変更する + 本当に無しにしますか? + パスワードのヒント + パスワードのヒントを設定してください + パスワードが一致しません + 2段階認証の設定を中止する + 2段階認証を完了する手順です。\n\n1.%1$sのメールを確認(迷惑メールフォルダも確認してください)。\n\n2.メール本文にあるリンクをクリック。 + パスワードをそのままヒントとして入力しないでください + 無効なメールアドレス + すみません + パスワードの設定時に回復用のメールアドレスを設定していないので、あなたの残りの方法は、パスワードを覚えるか、アカウントをリセットするかのどちらかです。 + 回復用のコードをあなたのメールアドレス:%1$sに送信しました。 + メールに書いてある6桁のコードを入力してください。 + メールアドレス %1$s へのアクセスにトラブルでも発生しましたか? + メールへのアクセスができない場合、あなたの残りの方法は、パスワードを思い出すか、アカウントをリセットするかのどちらかです。 + 自分のアカウントをリセットする + アカウントをリセットすると、あなたが共有したメディアやファイルやメッセージなどがすべて失われます。 + 注意 + 実行しますと元には戻せません。\n\nあなたのメッセージはすべて削除されます。 + リセット + パスワード + 2段階認証を有効にしました。あなたのアカウントは設定したパスワードで保護されます。 + パスワードを忘れましたか? + パスワードを回復する + コード + パスワードが無効化されました + 2段階認証を有効にしました。\nあなたはログインごとに設定したパスワードを入力する必要があります。 + 回復用のメールアドレス %1$s の確認が済んでおりません。 + + プライバシーとセキュリティ + プライバシー + 既読の表示 + 誰にでも + 自分の連絡相手 + 誰にも + 誰にでも (-%1$d) + 自分の連絡相手 (+%1$d) + 自分の連絡相手 (-%1$d) + 自分の連絡相手 (-%1$d, +%2$d) + 誰にも (+%1$d) + セキュリティ + アカウントの自動削除 + 削除までのログアウト期間 + あなたがこの期間内にログインしなかった場合は、あなたのアカウントは、すべてのグループ、メッセージ、連絡相手と一緒に削除されます。 + アカウントを削除しますか? + あなたの既読時間を見られる人を選択します。 + 誰に既読時間を見せますか? + 例外を追加する + 重要:既読時間を見せない設定にしている相手の既読時間は見られません。代わりの時間表示は大まかな (最近、今週中、今月中) 内容になります。 + 見せる + 見せない + これらの設定は上記の内容を上書きします。 + 見せる + この人たちには見せる + 見せない + この人たちには見せない + 相手を追加する + 多くのリクエストが集中してプライバシー設定の変更ができません。今しばらくお待ちください。 + この端末を除くすべての端末からログアウトする。 + 削除したい相手を長押ししてください。 + + 動画の編集 + オリジナルの動画 + 編集済みの動画 + 動画を送信中… + 動画を圧縮する + + ロボット + 共有する + グループに追加する + 設定 + ヘルプ + メッセージを見る事ができます + メッセージを見る事ができません + このロボットは何ができますか? + はじめる + 再起動 + ロボットを止める + ロボットを再開する + + 次へ + 戻る + 完了 + 開く + キャンセル + 閉じる + 追加する + 編集する + 送信する + 呼び出す + コピーする + 削除する + 転送する + 再送する + カメラで撮る + ギャラリーから選ぶ + 写真を削除する + 設定 + 確定 + 切り取る + + あなたはリンク経由でグループに参加しました + un1がリンク経由でグループに参加しました + un1 は un2 を外しました + un1 はグループから外れました + un1 は un2 を追加しました + un1 はグループの写真を削除しました + un1 はグループの写真を変更しました + un1 は un2 のグループ名を変更しました + un1 がグループを作成しました + あなたは un2 を外しました + あなたはグループから外れました + あなたは un2 を追加しました + あなたはグループの写真を削除しました + あなたはグループの写真を変更しました + あなたは un2 のグループ名を変更しました + あなたはグループを作成しました + un1 はあなたを外しました + un1 はあなたを追加しました + un1 がグループに戻りました + あなたはこのグループに戻りました + このメッセージはこのバージョンではサポートできません。Telegramを更新してください:https://telegram.org/update + 写真 + 動画 + 位置情報 + 連絡相手 + ファイル + ステッカー + ミュージック + あなた + スクリーンショットが撮れました! + un1 がスクリーンショットを撮りました! + + 無効な電話番号です + 認証コードの有効期限が切れました。ログインし直してください。 + 回数が多すぎます。のちほどやりなおしてください。 + 処理が多数で追いつきません。%1$s に再度行ってください。 + 無効なコードです + 無効な名前です + 無効な名字です + ロード中… + 動画プレーヤーをインストールしてからやり直してください + sms@stel.comへ問題の内容を送信してください。 + \'%1$s\'を処理できるアプリがありません。インストールしてください + この方はTelegramを使用しておりません。招待しますか? + 本当によろしいですか? + %1$s をグループ %2$s に追加しますか? + 転送するメッセージの番号: + %1$s をグループに追加しますか? + この方はすでにグループの一員です。 + メッセージを %1$s に転送しますか? + %1$sにメッセージを送信しますか? + 本当にログアウトしますか?\n\nTelegramはあなたが所有するすべての端末から利用できます。\n\nログアウトを行うと、秘密のチャットの内容がすべて消えてしまう事に注意してください。 + 本当にその他の端末からのセッションを切りますか? + 本当に削除しますか? + 本当に削除しますか? + 電話番号を共有しますか? + この相手をブロックしますか? + この相手のブロックを解除しますか? + この相手を削除しますか? + 秘密のチャットをはじめますか? + 本当に中止しますか? + 本当に消去しますか? + 本当に%1$sを削除しますか? + %1$sへメッセージを送信しますか? + %1$sへメッセージを転送しますか? + すみませんがこの機能はあなたが登録した国では利用できません。 + このユーザ名のTelegramアカウントはありません。 + このロボットはグループに参加できません。 + + Plus Messenger + 速くて + 無料で + 安全で + 強力で + クラウドに基づいて + プライベートが守れる + 世界でも類のない]]> 高速]]> メッセージングアプリ。]]>これは 無料]]> で 安全]]>です。 + Plus Messenger]]>は他のアプリよりも速く送れます]]>。 + Plus Messenger]]>は永久に無料です。広告も]]>更新料もありません。 + Plus Messenger]]>はクラッカーから]]>あなたのメッセージを守ります。 + Plus Messenger]]>はあなたのチャットやファイルを]]>保存する容量に制限をかけません。 + Plus Messenger]]>へのアクセスは]]>さまざまな端末から行うことができます。 + Plus Messenger]]>のメッセージは厳重に暗号化されており]]>自ら消去する事もできます。 + はじめる + + %1$d オンライン + %1$d オンライン + %1$d オンライン + %1$d オンライン + %1$d オンライン + %1$d オンライン + 参加者なし + 参加者 %1$d名 + 参加者 %1$d名 + 参加者 %1$d名 + 参加者 %1$d名 + 参加者 %1$d名 + +%1$d名以上が入力中 + +%1$d名以上が入力中 + +%1$d名以上が入力中 + +%1$d名以上が入力中 + +%1$d名以上が入力中 + +%1$d名以上が入力中 + 新しいメッセージなし + %1$d件の新しいメッセージ + %1$d件の新しいメッセージ + %1$d件の新しいメッセージ + %1$d件の新しいメッセージ + %1$d件の新しいメッセージ + メッセージなし + %1$d件のメッセージ + %1$d件のメッセージ + %1$d件のメッセージ + %1$d件のメッセージ + %1$d件のメッセージ + アイテムなし + %1$d アイテム + %1$d アイテム + %1$d アイテム + %1$d アイテム + %1$d アイテム + チャット以外から + %1$d チャットから + %1$d チャットから + %1$d チャットから + %1$d チャットから + %1$d チャットから + %1$d秒間 + %1$d秒間 + %1$d秒間 + %1$d秒間 + %1$d秒間 + %1$d秒間 + %1$d分間 + %1$d分間 + %1$d分間 + %1$d分間 + %1$d分間 + %1$d分間 + %1$d時間 + %1$d時間 + %1$d時間 + %1$d時間 + %1$d時間 + %1$d時間 + %1$d日間 + %1$d日間 + %1$d日間 + %1$d日間 + %1$d日間 + %1$d日間 + %1$d週間 + %1$d週間 + %1$d週間 + %1$d週間 + %1$d週間 + %1$d週間 + %1$dヶ月 + %1$dヶ月 + %1$dヶ月 + %1$dヶ月 + %1$dヶ月 + %1$dヶ月 + %1$d年 + %1$d年 + %1$d年 + %1$d年 + %1$d年 + %1$d年 + ユーザーが%1$d人 + ユーザーが%1$d人 + ユーザーが%1$d人 + ユーザーが%1$d人 + ユーザーが%1$d人 + ユーザーが%1$d人 + %1$d回 + %1$d回 + %1$d回 + %1$d回 + %1$d回 + %1$d回 + %1$dメートル + %1$dメートル + %1$dメートル + %1$dメートル + %1$dメートル + %1$dメートル + %1$d個のステッカー + %1$d個のステッカー + %1$d個のステッカー + %1$d個のステッカー + %1$d個のステッカー + %1$d個のステッカー + 写真 %1$d枚 + 写真 %1$d枚 + 写真 %1$d枚 + 写真 %1$d枚 + 写真 %1$d枚 + 写真 %1$d枚 + + 転送メッセージ %1$d件 + 転送メッセージ + 転送メッセージ %1$d件 + 転送メッセージ %1$d件 + 転送メッセージ %1$d件 + 転送メッセージ %1$d件 + 転送ファイル %1$d件 + 転送ファイル + 転送ファイル %1$d件 + 転送ファイル %1$d件 + 転送ファイル %1$d件 + 転送ファイル %1$d件 + 転送写真 %1$d件 + 転送写真 + 転送写真 %1$d件 + 転送写真 %1$d件 + 転送写真 %1$d件 + 転送写真 %1$d件 + 転送動画 %1$d件 + 転送動画 + 転送動画 %1$d件 + 転送動画 %1$d件 + 転送動画 %1$d件 + 転送動画 %1$d件 + 転送音声 + 転送音声 + 転送音声 %1$d件 + 転送音声 %1$d件 + 転送音声 %1$d件 + 転送音声 %1$d件 + 転送位置情報 %1$d件 + 転送位置情報 + 転送位置情報 %1$d件 + 転送位置情報 %1$d件 + 転送位置情報 %1$d件 + 転送位置情報 %1$d件 + 転送連絡相手 %1$d件 + 転送連絡相手 + 転送連絡相手 %1$d件 + 転送連絡相手 %1$d件 + 転送連絡相手 %1$d件 + 転送連絡相手 %1$d件 + 転送ステッカー %1$d件 + 転送ステッカー + 転送ステッカー %1$d件 + 転送ステッカー %1$d件 + 転送ステッカー %1$d件 + 転送ステッカー %1$d件 + その他 %1$d件 + その他 %1$d件 + その他 %1$d件 + その他 %1$d件 + その他 %1$d件 + その他 %1$d件 + + yyyy\'年\' MMMM\'日\' + MMMdd\'日\' + yyyy\'年\'MM\'月\'dd\'日\' + yyyy\'年\'MM\'月\'dd\'日\' + MMMMd\'日\' + yyyy\'年\'MMMMd\'日\' + EEE + HH:mm + a h:mm + %1$sの%2$s + + Plus Messenger for Android + テーマを作成する + 設定 + 無効な16進数コードです + テーマの色 + テーマの設定をリセットする + テーマの設定をすべて元に戻す + テーマの状態がデフォルトに戻ります! + 通常 + 画面表示 + メイン画面 + チャット画面 + 連絡相手の表示画面 + ヘッダー + 行表示 + チャット一覧 + チャット一覧 + 連絡相手一覧 + ヘッダーの色 + 名前の色 + 名前の大きさ + メッセージの色 + メッセージの大きさ + 時刻表示の色 + 時刻表示の大きさ + カウントの色 + カウントの大きさ + 行の色 + カウントの背景色 + 状態表示の色 + 状態表示の大きさ + 右側の吹き出しの色 + 左側の吹き出しの色 + 日付の色 + 日付の大きさ + 吹き出し内の日付の色 + 右側のテキストの色 + 左側のテキストの色 + 右側の時刻の色 + 左側の時刻の色 + 時刻表示の大きさ + 入力中の文字の色 + 入力中の文字の大きさ + 入力欄の色 + 絵文字の背景色 + 絵文字を選択した際のタブの色 + 絵文字タブのアイコン色 + オンライン表示の色 + 音楽 + テーマを保存する + TelegramのThemesフォルダにテーマを保存します + テーマを保存しました! + %1$sが%2$sに保存しました + テーマは作成されていません。最初に任意のMODを適用してください。 + SDカードから設定を戻す + %sの中に設定ファイルはありません + SDカードがありません + 名前を入力してください + テーマをダウンロード + テーマを適用する + フォルダからxml形式のテーマ設定を取り込みます + メンバーの色 + チェックの色 + ミュートの色 + ログを送信する + ログがありません + ログを消去する + ログを消去しました + アイコンを送信する + メニュー画面から電話番号を隠す + 浮遊する鉛筆の色 + 浮遊する背景の色 + G+のコミュニティ + 入力中の文字色 + 文章入力アイコンの文字色 + 案内用の引き出し + オプションの一覧 + 一覧の色 + 名前の大きさ + 電話の色 + 電話の大きさ + アバターの色 + オプションのアイコンの色 + オプション表示の色 + オプション表示の大きさ + バージョン表示の色 + バージョン表示の大きさ + ヘッダーのタイトルの色 + ヘッダーのアイコンの色 + タブのアイコン色 + 選択していないタブのアイコン色 + タブ内のカウント色 + タブ内のカウントの背景色 + チャットのメッセージ数を数える + ミュートではないメッセージだけを数える + タブ内のカウントを隠す + 周器の色 + アバター周辺の丸み + メンバーの色を設定する + 転送した相手名の色 + ヘッダーのタイトル + 引用符をつけずに転送する + ポップアップのクリックを無効にする + プロフィール + 設定した背景を隠す + 右側のリンク色 + 左側のリンク色 + テーマを適用しました! + OKを押してアプリを再起動する + 内蔵された絵文字を表示する + 吹き出しの形 + ファイル名をそのままにする + 数字だけのファイル名が名前_日付の形になります + アバターの大きさ + 連絡相手のアバターを上部に持っていく + アバター周辺の隙間 + グループ名の文字色 + グループ名の大きさ + 名前の色(不明なメンバー用) + カスタム化した背景の影を隠す + 背景の色を設定する + 背景の色 + 絵文字のポップアップサイズ + 右側の吹き出しでの転送者名の色 + 左側の吹き出しでの転送者名の色 + アイコンの色 + 設定/テーマの作成画面 + 背景の色 + 影の色 + セクションの色 + タイトルの色 + 概要/サブタイトルの色 + 写真/ステッカーの文字の色 + Plus Messengerの利用者が作成した他のテーマをチェックしますか? + 内蔵フォントに切り替える + Plus Messengerを再起動します + グループアイコンの色 + 共有した連絡情報の色 + 背景に色をつける + テキストに色をつける + チャット画面に連絡用のアバターを表示する + チャット画面に自分のアバターを表示する + グループ画面に自分のアバターを表示する + 自分のアバターを上部に持っていく + ダイアログのタイトル/ボタンの色 + ユーザ名をメンバー名と共に表示する + オーディオを止めない + 周期リストの色 + アバターを名前と電話の間に表示する + グラデーション + グラデーションの色分け + 無効 + 上下 + 左右 + 上左-下右 + 下左-上右 + グラデーションを一覧に適用する + %sをクリップボードにコピーしました + +\n\nPlus Messengerの公式チャンネル:\nhttps://telegram.me/plusmsgr + テーマをダウンロード + 公式チャンネル + ダイアログ + クリック時の連絡写真 + クリック時のグループ写真 + プロフィール + プロフィール写真 + 色のない背景を数える + ロボットのコマンドに対するチェックの色 + ロボットのコマンドに対する色 + 検索へのハイライト色 + %sが更新されました + 相手の状態を隠す + タブを隠す + すべて + ユーザー + グループ + スーパーグループ + チャンネル + ロボット + お気に入り + タブの高さ + タブをデフォルトにする + タブをリセットする + 状態別に並べ替える + 時間別に並べ替える + 未読別に並べ替える + スーパーグループのタブを表示する + スーパーグループのタブを隠す + タブ + タブの公開/非公開 + お気に入りに追加する + お気に入りから削除する + お気に入りはありません\n\n追加するにはチャットを長押しして\'お気に入りに追加する\'を押してください。 + スクロール中でもタブを隠さない + タブのスワイプをループする + 共有ボタンを表示する + 引用 + 管理人一覧から削除する + ユーザ名をモバイルで表示する + 既読にする + すべて既読にする + チェックの形 + 直接シェアをポップアップメニューに加える + 直接共有返信(チャンネルを除く) + 直接シェアした時はお気に入りに追加する + トースト表示の日付を上部にする + 編集したマークを表示 + 編集 + 退出時のオプションを設定 + オプションを指定してからグループを脱退しますか? + グループを離れましたの表示を隠す + グループに加わりましたの表示を隠す + デフォルトのロボット用キーボードを隠す + グループに戻る + グループに戻った場合はそれをする事はできませんがよろしいですか? +
diff --git a/TMessagesProj/src/main/res/values-sr/strings.xml b/TMessagesProj/src/main/res/values-sr/strings.xml new file mode 100644 index 00000000..deeb3bbb --- /dev/null +++ b/TMessagesProj/src/main/res/values-sr/strings.xml @@ -0,0 +1,948 @@ + + + Српски + Serbian + sr + + Ваш телефон + Потврдите кôд ваше државе\nи унесите број телефона. + Одаберите државу + Погрешан кôд државе + + Ваш кôд + Послали смо СМС са кодом за активацију на ваш телефон + Позваћемо вас за %1$d:%2$02d + Позивамо вас... + Кôд + Погрешан број? + Нисте добили кôд? + + Ваше име + Упишите ваше име и презиме + + Име (обавезно) + Презиме (опционо) + Откажи регистрацију + + Поставке + Контакти + Нова група + јуче + Нема резултата + Још нема дописивања... + Почните дописивања притиском на дугме\nза нову поруку у доњем десном углу или\nпритисните дугме менија за више опција. + Чека се мрежа... + Повезивање... + Ажурирање... + Ново тајно дописивање + Чекам да %s буде на мрежи... + Тајно дописивање отказано + Размена шифрарских кључева... + %s се придружи тајном дописивању. + Придружили сте се тајном дописивању. + Очисти историјат + Обриши и изађи + Обриши дописивање + Обрисан налог + Одабери дописивање + Додирни и задржи да погледаш + %1$s користи старију верзију Телеграма, тако да ће тајне фотографије бити приказане у компатибилном режиму.\n\nКада %2$s ажурира Телеграм, фотографије са тајмером на 1 минут и мање ће радити у „Додирни и задржи да погледаш“ режиму, а ви ћете бити обавештени увек када друга страна уради снимак екрана. + ПОРУКЕ + Тражи + Искључи обавештења + Искључи на %1$s + Укључи + За %1$s + Искључи + Хеш ознаке + + Нова листа емитовања + Унесите назив листе + Направили сте листу емитовања + Додај примаоца + Обриши са листе емитовања + + + Изаберите фајл + Слободно %1$s од %2$s + Непозната грешка + Грешка приступа + Још увек нема фајлова... + Величина фајла не би требало да прелази %1$s + Складиштење није монтирано + УСБ пренос активан + Унутрашња меморија + Спољна меморија + Корен система + СД картица + Фасцикла + Да пошаљете слике без компресије + + невидљив + пише... + пише... + пишу... + %1$s снима аудио поруку... + %1$s шаље слику... + %1$s шаље видео... + %1$s шаље фајл... + снимам аудио поруку... + шаљем слику... + шаљем видео... + шаљем фајл... + Имате питање\nо Телеграму? + Усликај + Галерија + Локација + Видео + Фајл + Камера + Још увек нема порука... + Прослеђена порука + Од + Нема скорашњих + Порука + Порука + Дели мој контакт + Додај контакт + %s вас позива да се придружите тајном дописивању. + Позвали сте корисника %s да се придружи тајном дописивању. + Тајно дописивање: + користи end-to-end шифровање + без трагова на нашем серверу + има тајмер самоуништења + не дозвољава прослеђивање + Уклоњени сте из ове групе + Напустили сте ову групу + Обришите ову групу + Обришите ово дописивање + ПРЕВУЦИТЕ ПРСТОМ ДА ОТКАЖЕТЕ + Сачувајте у преузимања + Дели + Примени фајл са преводом + Неподржан прилог + Подеси тајмер самоуништења + Сервисна обавештења + Добављам податке о вези... + Отвори у прегледачу + Копирај УРЛ + Пошаљи %1$s + + %1$s подеси самоуништење на %2$s + Подесили сте тајмер за самоуништење на %1$s + %1$s искључи самоуништење + Искључили сте самоуништење + Имате нову поруку + %1$s: %2$s + %1$s вам посла поруку + %1$s вам посла слику + %1$s вам посла видео + %1$s дели контакт са вама + %1$s вам посла своју локацију + %1$s вам посла фајл + %1$s вам посла аудио фајл + %1$s вам посла налепницу + %1$s @ %2$s: %3$s + %1$s посла поруку групи %2$s + %1$s посла слику групи %2$s + %1$s посла видео групи %2$s + %1$s дели контакт с групом %2$s + %1$s посла локацију групи %2$s + %1$s посла фајл групи %2$s + %1$s посла аудио фајл групи %2$s + %1$s посла налепницу групи %2$s + %1$s вас позва у групу %2$s + %1$s измени назив групе %2$s + %1$s измени слику групе %2$s + %1$s позва корисника %3$s у групу %2$s + %1$s се врати у групу %2$s + %1$s уклони корисника %3$s из групе %2$s + %1$s вас уклони из групе %2$s + %1$s напусти групу %2$s + %1$s се придружи Телеграму! + %1$s,\nОткрили смо пријаву на ваш налог са новог уређаја %2$s\n\nУређај: %3$s\nЛокација: %4$s\n\nАко то нисте били ви, можете отићи у Поставке - Приватност и безбедност - Сесије и затворите ту сесију.\n\nАко сумњате да се неко други пријавио на ваш налог, можете укључити проверу у два корака у поставкама „Приватност и безбедност“.\n\nИскрено,\nТелеграм тим + %1$s освежи слику профила + %1$s се придружи групи %2$s преко позивне везе + Одговори + Одговори %1$s + Одговори %1$s + %1$s %2$s + + Изаберите контакт + Још нема контаката + Хеј, хајде да се пребацимо се на Телеграм: http://goo.gl/jnmjnZ + у + јуче у + на мрежи + примећен + примећен + Позовите пријатеље + ГЛОБАЛНА ПРЕТРАГА + примећен недавно + примећен пре недељу дана + примећен пре месец дана + примећен веома давно + Нова порука + + Пошаљи поруку... + Унесите назив групе + Назив групе + %1$d/%2$d чланова + Желите ли да се придружите групи „%1$s“? + Нажалост, ова група је попуњена. + Нажалост, ова група не постоји. + Веза копирана у клипборд + Позови у групу правећи везу + Позивна веза + Заиста желите да повучете ову везу? Ако то учините, више нико неће моћи помоћу ње да се придружи групи. + Претходна позивна веза је неактивна. Нова веза је генерисана. + Повуци + Повуци везу + Копирај везу + Дели везу + Свако ко има Телеграм моћи ће да се путем ове везе придружи вашој групи. + + Дељени медији + Поставке + Додај члана + Обриши и напусти групу + Обавештења + Уклони из групе + + Дели + Додај + Додај контакт + Блокирај + Измени + Обриши + Кућни + Мобилни + Посао + Друго + Главни + Започни тајно дописивање + Дошло је до грешке. + Шифрарски кључ + Тајмер самоуништења + искључено + Ова слика је визуелизација шифрованог кључа за ово тајно дописивање са корисником +]]>%1$s]]>.
]]>Ако ова слика изгледа идентично на телефону корисника ]]>%2$s]]>, ово дописивање је 200%% сигурно
]]>Сазнајте више о томе на telegram.org
+ Непознато + Подаци + Телефон + + Корисничко име + Ваше корисничко име + Жао нам је, ово корисничко име је већ заузето. + Жао нам је, ово корисничко име је неисправно. + Корисничко име мора имати најмање 5 знакова. + Корисничко име не сме прелазити 32 знака. + Жао нам је, корисничко име не можете започети бројем. + Можете одабрати корисничко име за ]]>Телеграм]]>. Ако то учините, други људи ће моћи да вас пронађу под тим корисничким именом и контактирају иако не знају ваш број.
]]>Можете користити ]]>a–z]]>, ]]>0–9]]> и доњу црту. Минимална дужина је ]]>5]]> знакова.
+ Проверавам корисничко име... + %1$s је доступно. + Нема + Дошло је до грешке. + + Налепнице + Уметници су добродошли да додају своје пакете налепница помоћу нашег @stickers бота.\n\nКорисници могу додавати налепнице тапнувши на њих и \"Додај у налепнице\". + Додај налепнице + Додај у налепнице + Нема налепница + Налепнице уклоњене + Нове налепнице додате + Сакриј + Прикажи + Дели + Копирај везу + Уклони + Још нема налепница + + Ресетујем поставке обавештења на подразумевано + Величина текста у порукама + Поставите питање + Укључи анимације + Одблокирај + Додирните и задржите на кориснику да га одблокирате. + Нема блокираних корисника + Обавештења о поруци + Упозорење + Преглед поруке + Обавештења групе + Звук + Обавештења у апликацији + Звукови у апликацији + Вибрација у апликацији + Вибрација + Преглед у апликацији + Ресетуј + Ресетуј сва обавештења + Поништава сва прилагођена обавештења за све ваше контакте и групе + Обавештења и звуци + Блокирани корисници + Одјави се + нечујно + подразумевано + Подршка + Само кад је утишан + Позадина дописивања + Поруке + Пошаљи са Ентер + Затвори све остале сесије + Догађаји + Контакт се придружио Телеграму + Језик + Имајте на уму да Телеграм Подршку раде волонтери. Трудимо се да одговоримо што брже можемо, али то може и потрјати.
]]>Молимо Вас прво погледајте Телеграм ЧПП]]>: ту се налазе одговори на већину питања и савети за решавање проблема]]>.
+ Питајте волонтера + Телеграм ЧПП + https://telegram.org/faq + Обрисати локализацију? + Неодговарајући фајл + Укључено + Искључено + Сервис обавештења + Ако су вам Гугл Плеј сервиси довољни да примате обавештења, можете онемогућити Сервис обавештења. Ипак препоручујемо вам да га оставите укљученим како би апликација радила у позадини а ви примали тренутна обавештења. + Сортирај по + Увези контакте + Име + Презиме + ЛЕД боја + Искачућа обавештења + без искакања + само кад је екран укључен + само кад је екран искључен + увек прикажи + Бројач на беџу + кратко + дугачко + Системски + Подразумеване поставке + Аутоматско преузимање медија + Када користите мобилни интернет + Када користите бежични интернет + Када сте у ромингу + ништа + Сачувај у галерију + Измени назив + Приоритет + подразумевано + низак + висок + највећи + никад + Понављај обавештења + Овде можете променити Телеграм број. Ваш налог и сви ваши подаци у облаку — поруке, медији, контакти итд. биће премештени на нови број.\n\nВажно:]]> сви ваши Телеграм контакти ће добити ваш нови број]]> и биће додат њиховом именику, под условом, да имају ваш стари број, а нисте их блокирали у Телеграму. + Сви ваши Телеграм контакти ће добити ваш нови број и биће додат њиховом именику, под условом, да имају ваш стари број, а нисте их блокирали у Телеграму. + ПРОМЕНИ БРОЈ + Нови број + Послаћемо СМС са кодом за потврду на ваш нови број. + Број %1$s је већ повезан на Телеграм налог. Обришете тај налог пре него што пређете на нови број. + Друго + искључена + искључена + Искључено + искључено + Звуци током дописивања + Подразумевано + Паметна обавештења + искључена + Звук највише %1$s за %2$s + Највише звукова + пута + за + минута + + Активне сесије + Тренутне сесије + Нема других активних сесија + Можете се пријавити на Телеграм са другог телефона, таблета или рачунара користећи исти број телефона. Сви ваши уређаји биће тренутно синхронизовани. + Активне сесије + Управљајте сесијама на другим уређајима. + Тапните на сесију да је прекинете. + Прекинути ову сесију? + незванична апликација + + Закључано лозинком + Промени лозинку + Када подесите додатну лозинку, иконица са катанцем ће се појавити на страници са дописивањима. Притисните је да бисте откључали вашу Телеграм апликацију.\n\nНапомена: ако заборавите лозинку, мораћете да обришете и реинсталирате апликацију. Сва тајна дописивања биће обрисана. + Иконица катанца ће се појавити на страни са дописивањима. Притисните је да би закључали Телеграм са новом лозинком. + ПИБ + Лозинка + Унесите тренутну лозинку + Унесите лозинку + Унесите нову лозинку + Унесите лозинку + Поново унесите нову лозинку + Погрешна лозинка + Лозинке се не поклапају + Ауто-закључавање + Захтева лозинку ако сте неко време одсутни. + за %1$s + искључено + + Делите слике и видео у овом дописивању и приступите им са било ког вашег уређаја. + Дељени медији + Делите фајлове и документе у овом дописивању и приступите им са било ког вашег уређаја. + + Мапа + Сателит + Хибридно + m удаљен + km удаљен + Пошаљите своју локацију + Пошаљите изабрану локацију + Локација + Прецизност %1$s + ИЛИ ИЗАБЕРИТЕ МЕСТО + + Прикажи све медије + Сачувај у галерију + %1$d од %2$d + Галерија + Све слике + Сви видео записи + Још нема слика + Нема видео записа + Прво преузмите медија фајл + Нема скорашњих слика + Нема скорашњих ГИФ слика + ПРОНАЂИ СЛИКЕ + ПРЕТРАГА ИНТЕРНЕТА + ПРОНАЂИ ГИФ СЛИКЕ + Претражи интернет + Претражи ГИФ слике + Исеци слику + Измени слику + Побољшај + Осветљење + Контраст + Експозиција + Топлина + Засићеност + Вињета + Сенке + Зрнасто + Оштрина + Замућење + искључено + Линеарно + Радијално + Заиста желите да обришете ову слику? + Заиста желите да обришете овај видео? + Одбацити промене? + Обрисати историјат претраге? + Обриши + Слике + Видео + Додај натпис... + Натпис слике + Натпис видеа + + Провера у два корака + Поставите додатну лозинку + Можете поставити лозинку која ће бити неопходна за пријаву са новог уређаја поред кода који добијете СМС-ом. + Ваша лозинка + Унесите тренутну лозинку + Унесите лозинку + Унесите нову лозинку + Поново унесите лозинку + Е-пошта за опоравак + Ваша е-адреса + Унесите вашу е-адресу. То је једини начин опоравка услед заборављене лозинке. + Прескочи + Упозорење + Не, озбиљно.\n\nАко заборавите лозинку, изгубићете приступ вашем Телеграм налогу. Неће бити начина да га повратите. + Још само мало! + Проверите вашу е-пошту (и фасциклу нежељене поште) да бисте довршили подешавање провере у два корака. + Успех! + Ваша лозинка за проверу у два корака сада је активна. + Измени лозинку + Искључи лозинку + Постави е-адресу за опоравак + Промени е-адресу за опоравак + Заиста желите да искључите вашу лозинку? + Наговештај за лозинку + Направите наговештај за вашу лозинку + Лозинке се не поклапају + Прекини подешавање провере у два корака + Следите следеће кораке да завршите подешавање провере у два корака:\n\n1. Проверите е-пошту (и фасциклу нежељене поште)\n%1$s\n\n2. Кликните на везу за потврду. + Наговештај се мора разликовати од лозинке + Неисправна е-адреса + Извините + Како нисте дали вашу е-адресу за опоравак, када поставите лозинку, остаје вам или да је добро упамтите или ресетујете ваш налог. + Послали смо код за опоравак на е-адресу коју сте нам дали:\n\n%1$s + Проверите пошту и унесите шестоцифрени код који смо вам послали. + Имате проблем да приступите пошти %1$s? + Ако не можете да приступите свом поштанском налогу остаје вам да добро упамтите лозинку или ресетујете ваш налог. + РЕСЕТУЈ МОЈ НАЛОГ + Ако наставите са поступком ресетовања, изгубићете сва дописивања и поруке, заједно са свим медијима и фајловима које сте делили. + Упозорење + Ова радња се не може повратити.\n\nАко ресетујете ваш налог, све ваше поруке и дописивања биће обрисани. + Ресетуј + Лозинка + Укључили сте проверу у два корака па је ваш налог додатно заштићен лозинком. + Заборавили сте лозинку? + Опоравак лозинке + Код + Лозинка деактивирана + Укључили сте проверу у два корака.\nТребаће вам лозинка коју сте овде поставили да се пријавите на Телеграм налог. + Ваша е-адреса %1$s још није активна и чека на потврду. + + Приватност и безбедност + Приватност + Време појављивања + Сви + Моји контакти + Нико + Сви (-%1$d) + Моји контакти (+%1$d) + Моји контакти (-%1$d) + Моји контакти (-%1$d, +%2$d) + Нико (+%1$d) + Безбедност + Самоуништење налога + Ако сте одсутни + Ако се не пријавите бар једном у овом периоду, ваш налог ће бити обрисан заједно са свим групама, порукама и контактима. + Бришете ваш налог? + Промените ко може да види време вашег последњег појављивања. + Ко може да види време вашег појављивања? + Додај изузетке + Важно: нећете моћи да видите време последњег појављивања људи са којима и ви не делите време вашег последњег појављивања. Уместо тога приказаће се приближно време (недавно, пре око недељу дана, пре око месец дана). + Увек дели са + Никад не дели са + Ове поставке ће надјачати вредности подешене изнад. + Увек дели + Увек дели са корисницима... + Никад не дели + Никад не дели са корисницима... + Додај кориснике + Жао нам је, превише је захтева. Није могуће променити поставке приватности. Молим сачекајте. + Одјави све уређаје осим овог. + Додирните и задржите на кориснику да га обришете. + + Измени видео + Оригиналан видео + Измењен видео + Шаљем видео... + Компресуј видео + + бот + дели + додај у групу + Поставке + Помоћ + има приступ порукама + нема приступ порукама + Шта овај бот може? + СТАРТ + + Следећи + Назад + Готово + Отвори + Одустани + Затвори + Додај + Измени + Пошаљи + Позови + Копирај + Обриши + Проследи + Понови + Усликај + Из галерије + Обриши слику + Постави + У реду + ИСЕЦИ + + Придружили сте се групи преко позивне везе + un1 се придружи групи преко позивне везе + un1 уклони корисника un2 + un1 напусти групу + un1 дода корисника un2 + un1 уклони слику групе + un1 промени слику групе + un1 промени назив групе у un2 + un1 направи групу + Уклонили сте корисника un2 + Напустили сте групу + Додали сте корисника un2 + Уклонили сте слику групе + Променили сте слику групе + Променили сте име групе у un2 + Направили сте групу + un1 вас уклони + un1 вас дода + un1 се врати у групу + Вратили сте се у групу + Ова порука није подржана на вашој верзији Телегпама. Да би сте је видели ажурирајте апликацију: https://telegram.org/update + слика + видео + локација + контакт + фајл + налепница + аудио + Ви + Направили сте снимак екрана! + un1 направи снимак екрана! + + Неисправан број телефона + Код је истекао. Пријавите се поново + Превише покушаја. Покушајте касније + Превише покушаја. Покушајте за %1$s + Неисправан код + Неисправно име + Неисправно презиме + Учитавам... + Немате видео плејер. Инсталирајте неки да бисте наставили + Пошаљите е-пошту на sms@stel.com и реците нам ваше проблеме. + Немате апликацију која отвара „%1$s“ фајл. Инсталирајте неку да бисте наставили + Корисник још увек нема Телеграм. Да пошаљите позивницу? + Да ли сте сигурни? + Додај %1$s групи %2$s? + Број порука за прослеђивање: + Додати корисника %1$s у групу? + Корисник је већ у групи + Проследи поруке кориснику %1$s? + Пошаљи поруке кориснику %1$s? + Заиста желите да се одјавите?\n\nИмајте на уму да Телеграм можете истовремено користити на свим вашим уређајима.\n\nЗапамтите, одјављивањем прекидате сва ваша тајна дописивања. + Заиста желите да прекинете све остале сесије? + Заиста желите да обришете и напустите групу? + Заиста желите да обришете ово дописивање? + Заиста желите да делите ваше податке? + Заиста желите да блокирате овај контакт? + Заиста желите да одблокирате овај контакт? + Заиста желите да обришете овај контакт? + Заиста желите да започнете тајно дописивање? + Заиста желите да откажете регистрацију? + Заиста желите да очистите историјат? + Заиста желите да обришете %1$s? + Пошаљите поруке кориснику %1$s? + Проследите поруке кориснику %1$s? + Жао нам је, ова могућност тренуто није доступна у вашој земљи. + Нема Телеграм налога са тим корисничким именом. + Овај бот се не може придружити групама. + + Телеграм + Брз + Бесплатан + Сигуран + Моћан + Базиран на облаку + Личан + На свету најбржа]]> апликација за размену порука.]]>Она је бесплатна]]> и безбедна]]>. + Телеграм]]> испоручује поруке брже од]]>било које друге апликације. + Телеграм]]> је заувек бесплатан. Без огласа.]]>Без претплате. + Телеграм]]> чува ваше поруке]]>од напада хакера. + Телеграм]]> нема ограничење за]]>ваше медије и дописивања. + Телеграм]]> вам омогућава приступ порукама]]>са више уређаја. + Телеграм]]> поруке су вишеструко шифроване]]>и могу се самоуништити. + Започни дописивање + + %1$d на мрежи + %1$d на мрежи + %1$d на мрежи + %1$d на мрежи + %1$d на мрежи + %1$d на мрежи + нема чланова + %1$d члан + %1$d члана + %1$d члана + %1$d чланова + %1$d чланова + и још %1$d особа куца + и још %1$d особа куца + и још %1$d особе куцају + и још %1$d особе куцају + и још %1$d особа куцају + и још %1$d особа куцају + нема нових порука + %1$d нова порука + %1$d нове поруке + %1$d нове поруке + %1$d нових порука + %1$d нових порука + нема порука + %1$d поруку + %1$d поруке + %1$d поруке + %1$d порука + %1$d порука + нема ставки + %1$d ставка + %1$d ставке + %1$d ставке + %1$d ставки + %1$d ставки + није из дописивања + из %1$d дописивања + из %1$d дописивања + из %1$d дописивања + из %1$d дописивања + из %1$d дописивања + %1$d секунди + %1$d секунд + %1$d секунде + %1$d секунде + %1$d секунди + %1$d секунди + %1$d минута + %1$d минут + %1$d минута + %1$d минута + %1$d минута + %1$d минута + %1$d сати + %1$d сат + %1$d сата + %1$d сата + %1$d сати + %1$d сати + %1$d дана + %1$d дан + %1$d дана + %1$d дана + %1$d дана + %1$d дана + %1$d недеља + %1$d недеља + %1$d недеље + %1$d недеље + %1$d недеља + %1$d недеља + %1$d месеци + %1$d месец + %1$d месеца + %1$d месеца + %1$d месеци + %1$d месеци + %1$d година + %1$d година + %1$d године + %1$d године + %1$d година + %1$d година + %1$d корисника + %1$d корисник + %1$d корисника + %1$d корисника + %1$d корисника + %1$d корисника + %1$d пута + %1$d пут + %1$d пута + %1$d пута + %1$d пута + %1$d пута + %1$d метара + %1$d метар + %1$d метра + %1$d метра + %1$d метара + %1$d метара + %1$d налепница + %1$d налепница + %1$d налепнице + %1$d налепнице + %1$d налепница + %1$d налепница + %1$d слике + %1$d слика + %1$d слике + %1$d слике + %1$d слика + %1$d слика + + %1$d прослеђених порука + прослеђена порука + %1$d прослеђене поруке + %1$d прослеђене порука + %1$d прослеђених порука + %1$d прослеђених порука + %1$d прослеђених фајлова + прослеђен фајл + %1$d прослеђена фајла + %1$d прослеђена фајла + %1$d прослеђених фајлова + %1$d прослеђених фајлова + %1$d прослеђених слика + прослеђена слика + %1$d прослеђене слике + %1$d прослеђене слике + %1$d прослеђених слика + %1$d прослеђених слика + %1$d прослеђених видеа + прослеђен видео + %1$d прослеђена видеа + %1$d прослеђена видеа + %1$d прослеђених видеа + %1$d прослеђених видеа + %1$d прослеђених аудио фајлова + прослеђен аудио фајл + %1$d прослеђена аудио фајла + %1$d прослеђена аудио фајла + %1$d прослеђених аудио фајлова + %1$d прослеђених аудио фајлова + %1$d прослеђених локација + прослеђена локација + %1$d прослеђене локације + %1$d прослеђене локације + %1$d прослеђених локација + %1$d прослеђених локација + %1$d прослеђених контаката + прослеђен контакт + %1$d прослеђена контакта + %1$d прослеђена контакта + %1$d прослеђених контаката + %1$d прослеђених контаката + %1$d прослеђених налепница + прослеђена налепница + %1$d прослеђене налепнице + %1$d прослеђене налепнице + %1$d прослеђених налепница + %1$d прослеђених налепница + и %1$d других + и %1$d други + и %1$d друга + и %1$d друга + и %1$d других + и %1$d других + + MMMM yyyy + dd MMM + dd.MM.yy + dd.MM.yyyy + d MMMM + d MMMM, yyyy + EEE + HH:mm + h:mm a + %1$s у %2$s + + Плус месенџер за Андроид + Прављење теме + Неисправан хексадецимални кôд боје! + Боја теме + Ресетуј поставке теме + Врати назад све поставке теме + Ресетуј поставке теме на подразумевано! + Опште + Екрани + Главни екран + Екран ћаскања + Екран контаката + Заглавље + Редови + Списак ћаскања + Списак ћаскања + Списак контаката + Боја заглавља + Боја имена + Величина имена + Боја поруке + Величина поруке + Боја времена/датума + Величина времена/датума + Боја бројача + Величина бројача + Боја реда + Боја позадине бројача + Боја стања + Величина стања + Боја балона десне стране + Боја балона леве стране + Боја датума + Величина датума + Боја балона датума + Боја текста десне стране + Боја текста леве стране + Боја времена десне стране + Боја времена леве стране + Величина времена + Боја поља за унос текста + Величина поља за унос текста + Боја позадине поља за унос текста + Боја позадине емоџија + Боја емоџи језичка + Онлине Боја + Музика + Сачувај тему + Сачувај тему у Telegram/Themes фасциклу + Тема сачувана! + %1$s сачувана у %2$s + Тема још није направљена. Најпре примените било који МОД + Поставке враћене са СД картице + Фајл поставки није нађен у %s + Није нађена СД картица. + Унесите име + Теме + Примени тему + Примени xml фајл теме из локалне фасцикле + Боја члана + Боја ознака + Боја утишавања + Пошаљи дневнике + Нема дневника + Икона слања + Сакриј број мобилног са менија + Боја плутајуће оловке + Боја плутајуће позадине + Г+ заједница + Боја индикатора куцања + Боја икона поља за унос текста + Фиока навигације + Списак опција + Боја списка + Величина имена + Боја телефона + Величина телефона + Боја аватара + Боја иконе опције + Боја опције + Величина опције + Боја издања + Величина издања + Боја заглавља + Боја икона заглавља + Боја раздвајача + Полупречник аватара + Постави боју члана + Боја имена прослеђивања + Наслов заглавља + Проследи без цитирања + Онемогући искачући прозор на клик + Профил групе/контакта + Сакриј прилагођену позадину + Боја везе с десне стране + Боја везе с леве стране + Тема примењена! + Кликните У реду да поново покренете апликацију + Прикажи емоџије телефона + Стил балона + Задржи оригинално име фајла + Уместо само бројева фајлови ће бити сачувани користећи формат име_датум + Величина аватара + Поравнај аватар на врх + Лева маргина аватара + Боја имена групе + Величина имена групе + Боја имена (непознатог броја) + Сакриј прилагођену сенку позадине + Постави боју позадине + Боја позадине + Величина фиоке емоџија + Боја имена прослеђивања с десна + Боја имена прослеђивања с лева + Боја икона + Екран поставки/тема + Боја позадине + Боја сенке + Боја одељка + Боја наслова + Боја резимеа/поднаслова +
diff --git a/TMessagesProj/src/main/res/values-uk/strings.xml b/TMessagesProj/src/main/res/values-uk/strings.xml new file mode 100644 index 00000000..8075e998 --- /dev/null +++ b/TMessagesProj/src/main/res/values-uk/strings.xml @@ -0,0 +1,795 @@ + + + Telegram + Українська + Ukrainian + uk + + Ваш телефон + Підтвердіть код вашої країни\n і введіть ваш номер телефону. + Оберіть країну + Невірний код країни + + Ваш код + Ми відправили SMS з кодом активації на ваш телефон + Ми зателефонуємо вам через %1$d:%2$02d + Телефонуємо вам... + Код + Невірний номер? + Не отримали код? + + Ваше ім\'я + Вкажіть ваше ім\'я та прізвище + + Ім\'я (обов\'язково) + Прізвище (не обов\'язково) + Скасувати реєстрацію + + Налаштування + Контакти + Нова група + учора + Немає результатів + Чатів поки немає... + Натисніть кнопку створення нового чату\n в нижньому правому куті\n або кнопку меню для додаткових опцій. + Очікування мережі ... + З\'єднання... + Оновлення... + Новий секретний чат + Очікування користувача %s в мережі... + Секретний чат скасовано + Обмін ключами шифрування... + %s приєднався(-лась) до вашого секретного чату. + Ви приєдналися до секретного чату. + Очистити історію + Видалити і вийти + Видалити чат + Видалити аккаунт + Оберіть чат + Натисніть і утримуйте для перегляду + %1$s використовує стару версію Telegram через що секретні фото будуть відображатися в режимі сумісності.\n\nПісля того, як %2$s оновить Telegram, фото з таймером на 1 хвилину і менше будуть відображатися в режимі «Для перегляду натиснути та утримувати». Ви будете повідомлені, коли інша сторона приймає картинку. + ПОВІДОМЛЕННЯ + Пошук + Вимкнути сповіщення + Вимкнути на %1$s + Увімкнути сповіщення + Через %1$s + Відключити + + + Новий список розсилки + Введіть ім\'я списку + Ви створили список розсилки + Додати одержувача + Виключити зі списку розсилки + + + Оберіть файл + Вільно %1$s із %2$s + Невідома помилка + Помилка доступу + Файлів поки що немає... + Розмір файлу не може перевищувати %1$s + Сховище не підключено + Передавання по USB активне + Внутрішнє сховище + Зовнішнє сховище + Корінь системи + Карта пам\'яті + Папка + Для відправки зображень без стиснення + + невидимий + друкує... + друкує... + друкують... + Є питання щодо Telegram? + Зробити світлину + Галерея + Місцезнаходження + Відео + Файл + Повідомлень поки немає... + Переслане повідомлення + Від + Немає нещодавніх + Повідомлення + Повідомлення + Поділитися своїми контактними даними + Додати в контакти + %s запросив/ла вас приєднатися до секретного чату. + Ви запросили %s приєднатися до секретного чату. + Секретні чати: + Використовують шифрування з кінця у кінець + Не залишають слідів на наших серверах + Мають таймери самознищення + Не дозволяють здійснювати пересилання + Вас видалили з цієї групи + Ви покинули цю групу + Видалити цю групу + Видалити цей чат + ПРОВЕДІТЬ ДЛЯ СКАСУВАННЯ + Зберегти до завантажень + Поділитись + Застосувати файл локалізації + Непідтримуване вкладення + Встановити таймер самознищення + Службові повідомлення + + %1$s встановив/ла таймер самознищення на %2$s + Ви встановили таймер самознищення на %1$s + %1$s вимкнули/ла таймер самознищення + Ви вимкнули таймер самознищення + У вас нове повідомлення + %1$s: %2$s + %1$s відправив/ла вам повідомлення + %1$s відправив/ла вам світлину + %1$s відправив/ла вам відео + %1$s поділився/лась з вами контактом + %1$s відправив/ла вам місцезнаходження + %1$s відправив/ла вам файл + %1$s відправив/ла вам стікер + %1$s @ %2$s: %3$s + %1$s відправив/ла повідомлення групі %2$s + %1$s відправив/ла фотографію групі %2$s + %1$s відправив/ла відео групі %2$s + %1$s поділився/лась контактом c групою %2$s + %1$s відправив/ла місцезнаходження групі %2$s + %1$s відправив/ла файл групі %2$s + %1$s відправив/ла стікер групі%2$s + %1$s запросив/ла вас до групи %2$s + %1$s змінив/ла ім\'я групи %2$s + %1$s змінив/ла світлину групи %2$s + %1$s запросив/ла користувача %3$s в групу %2$s + %1$s повернувся/лась в групу %2$s + %1$s видалив/ла користувача %3$s із групи %2$s + %1$s видалив/ла вас з групи %2$s + %1$s покинув/ла групу %2$s + %1$s приєднався/лась до Telegram! + %1$s оновив/ла світлину облікового запису + Відповісти + Відповісти %1$s + Відповісти %1$s + %1$s %2$s + + Оберіть контакт + Контактів поки що немає + Ей, давай переключимося на Telegram: https://telegram.org/dl + в + вчора о(об) + online + був/ла в мережі + був/ла в мережі + Запросити друзів + ГЛОБАЛЬНИЙ ПОШУК + був/ла в мережі тільки що + був/ла в мережі протягом тижня + був/ла в мережі протягом місяця + був/ла в мережі дуже давно + Нове повідомлення + + Надіслати повідомлення... + Уведіть назву групи + Назва групи + %1$d/%2$d учасників + + + Спільні медіа + Налаштування + Додати учасника + Видалити та покинути групу + Сповіщення + Видалити з групи + + Поділитися + Додати + Додати контакт + Заблокувати + Редагувати + Видалити + На головну + Стільниковий + Робота + Інше + Основний + Почати секретний чат + Сталася помилка. + Ключ шифрування + Таймер самознищення + Вимкнути + Це зображення є візуалізацією ключа шифрування для цього чату з користувачем ]]>%1$s]]>.
]]>Якщо це зображення ідентично зображенню на телефоні користувача ]]>%2$s\'s]]> ваш чат захищений на 200%%.
]]>Дізнайтеся більше на telegram.org
+ Невідомо + Інформація + Телефон + + Ім\'я кристувача + Ваше ім\'я + Вибачте, на жаль, це ім\'я вже зайнято. + Вибачте, вибране ім\'я некоректне. + Ім\'я користувача має складатися мінімум з 5 символів. + Ім\'я користувача не повинно містити більше 32 символів. + Вибачте, ім\'я користувача не повинно починатися з цифри. + Ви можете вибрати собі ім\'я користувача в ]]>Telegram]]>. Якщо ви зробите це, інші люди зможуть знайти вас по ньому і зв\'язатися з вами, не знаючи ваш номер телефону.
]]>Ви можете використовувати символи ]]>a–z]]>, ]]>0–9]]> та підкреслення. Мінімальна довжина становить ]]>5]]> символів.
+ Перевірка імені... + Ім\'я %1$s доступне. + Немає + Сталася помилка. + + + Скинути всі налаштування сповіщень на стандартні + Розмір тексту повідомлень + Задати питання + Увімкнути анімації + Розблокувати + Натисніть і утримуйте ім\'я користувача для розблокування + Заблокованих користувачів поки що немає + Сповіщення повідомлень + Сигнал + Попередній перегляд повідомлення + Сповіщення групи + Звук + В додатку + Звук у додатку + Вібрація у додатку + Вібрація + Попередній перегляд у додатку + Скинути + Скинути всі сповіщення + Скасувати всі власні налаштування сповіщень для всіх контактів і груп + Сповіщення та звук + Заблоковані користувачі + Вийти + Без звуку + За замовчуванням + Підтримка + Тло чату + Повідомлення + Відправлення по Enter + Вихід із усіх інших сеансів + Події + Контакт приєднався до Telegram + Мова + Запитати волонтера + Telegram FAQ + https://telegram.org/faq + Видалити локалізацію? + Некоректний файл локалізації + Увімкнено + Вимкнено + Служба сповіщень + Якщо сервісів Google Play вам достатньо для отримання повідомлень, ви можете відключити Службу повідомлень. Однак ми рекомендуємо вам залишити її включеною для роботи програми у фоновому режимі і отримання миттєвих повідомлень. + Сортувати за + Імпорт контактів + Ім\'я + Прізвище + Колір світлодіода + Спливаючі повідомлення + Не показувати + Тільки коли екран увімкнений + Тільки коли екран вимкнений + Завжди показувати + Лічильник значків + Коротка + Довга + Мова системи + Налаштування за замовчуванням + Автозавантаження медіа + При використанні мобільної мережі + При підключенні по Wi-Fi + У роумінгу + Немає медіа + Зберегти в галереї + Редагувати ім\'я + Приорітет + За замовчуванням + Низький + Високий + Максимальний + Ніколи + Повтор сповіщень + Тут ви можете змінити ваш номер Telegram. Ваш аккаунт і всі ваші дані - повідомлення, медіа, контакти і т. Д. Будуть перенесені на новий номер.\n\nВажливо:]]> всім вашим контактам Telegram ваш новий номер]]> буде автоматично доданий в адресну книгу, за умови, що у них був ваш старий номер і ви не блокували їх в Telegram. + Всім вашим контактам Telegram ваш новий номер буде автоматично доданий в адресну книгу, за умови, що у них був ваш старий номер і ви не блокували їх в Telegram. + ЗМІНИТИ НОМЕР + Новий номер + Ми відправимо СМС з кодом підтвердження на ваш новий номер. + Номер %1$s вже прив\'язаний до аккаунту Telegram. Видаліть цей аккаунт, перш ніж перейти на новий номер + Інше + Відключені + Відключений + + + + Змінити код доступа + Після встановлення додаткового коду блокування на сторінці чатів з\'явиться значок замка. Натискайте на нього для блокування і розблокування додатки Telegram.\n\nПРИМІТКА: якщо ви забудете код доступу, вам потрібно буде видалити і перевстановити цей додаток. Всі секретні чати будуть втрачені. + Тепер ви будете бачити значок замка на сторінці чатів. Натисніть на нього, щоб заблокувати додаток Telegram за допомогою вашого нового коду доступу. + ПІН-код + Пароль + Введіть ваш поточний код доступу + Введіть ваш новий код доступу + Введіть ваш код доступу + Повторіть ваш новий код доступу + Невірний код доступу + Коди доступу не збігаються + Автоблокування + Запитувати код доступу при відсутності вас протягом певного часу. + через %1$s + Відключена + + Поділіться фото і відео в цьому чаті і отримаєте доступ до них на будь-якому з ваших пристроїв. + Загальні медіа + Поділіться файлами і документами в цьому чаті і отримаєте доступ до них на будь-якому з ваших пристроїв. + + Карта + Супутникова + Гібридна + м звідси + км звідси + + Показати всі медіафайли + Зберегти до галереї + %1$d з %2$d + Галерея + Всі фотографії + Фотографій поки що немає + Спочатку завантажте медіа + Немає недавніх фото + Немає недавніх GIF + ШУКАТИ ЗОБРАЖЕННЯ + ПОШУК В МЕРЕЖІ + ПОШУК GIF + Пошук в мережі + Пошук GIF + Кадрувати зображення + Редагувати зображення + Автопокращення + Відблиски + Контраст + Експозиція + Тепло + Насиченість + Віньєтування + Тіні + Зернистість + Різкість + Розмиття + Впевнені, що хочете видалити це фото? + Впевнені, що хочете видалити це відео? + Скасувати зміни? + + + Конфіденційність і Безпека + Конфіденційність + Остання активність + Всі + Мої контакти + Ніхто + Всі (-%1$d) + Мої контакти (+%1$d) + Мої контакти (-%1$d) + Мої контакти (-%1$d, +%2$d) + Ніхто (+%1$d) + Безпека + Самознищення аккаунта + Якщо вас не було + Якщо ви не ввійдете хоча б раз в свій аккаунт протягом цього періоду, він буде вилучений з усіма групами, повідомленнями та контактами. + Видалити ваш аккаунт? + Змінити список тих, хто може бачити ваше останнє відвідування. + Хто може бачити час вашої останньої активності? + Додати виняток + Важливо: ви не зможете побачити час останньої активності людей, з якими ви не поділилися своїм часом останньої активності. Замість цього буде відображатися приблизний час (недавно, протягом тижня, протягом місяця). + Завжди ділитися з + Ніколи не ділитися з + Ці налаштування перевизначають значення вище. + Завжди ділитися + Завжди ділитися з... + Ніколи не ділитись + Ніколи не ділитись з... + Додати користувачів + Вибачте, занадто багато запитів. Неможливо змінити налаштування безпеки прямо зараз, будь ласка почекайте. + Завершує сеанси на всіх пристроях, крім поточного. + Натисніть і утримуйте на користувача для видалення. + + Редагувати відео + Оригінальне відео + Відредаговане відео + Відправлення відео... + Стиснути відео + + + Далі + Назад + Готово + Відкрити + Скасувати + Додати + Редагувати + Надіслати + Зателефонувати + Копіювати + Видалити + Переслати + Повторити + З камери + З галереї + Видалити світлину + Встановити + OK + КАДРУВАННЯ + + un1 видалив/ла користувача un2 + un1 додав/ла користувача un2 + un1 видалив/ла світлину групи + un1 змінив/ла світлину групи + un1 змінив/ла ім\'я групи на un2 + un1 створив/ла групу + Ви видалили користувача un2 + Ви додали користувача un2 + Ви видалили світлину групи + Ви змінили світлину групи + Ви змінили ім\'я групи на un2 + Ви створили групу + un1 видалив/ла вас + un1 додав/ла вас + un1 повернувся/лась в групу + Світлина + Відео + Місцезнаходження + Контакт + Файл + Стікер + Ви + Ви зробили скріншот! + un1 зробив/ла скріншот! + + Невірний номер телефону + Термін дії коду сплив, будь ласка, увійдіть знову + Забагато спроб, будь ласка, спробуйте знову пізніше + Невірний код + Невірне ім\'я + Невірне прізвище + Завантаження... + У вас немає додатку для відтворення відео, будь ласка, встановіть його для продовження + У вас немає додатків, які можуть обробляти файли типу \'%1$s\', будь ласка, встановіть одне для продовження. + У цього користувача поки що немає Telegram, відправити запрошення? + Ви впевнені? + Переслати повідомлення користувачу %1$s? + Відправити повідомлення %1$s? + Впевнені, що хочете вийти?\n\nЗверніть увагу на те, що ви можете з легкістю користуватися Telegram на всіх ваших пристроях одночасно.\n\nПам\'тайте, вихід знищує всі ваші секретні чати. + Впевнені, що хочете завершити всі інші сеанси? + Впевнені, що хочете видалити і покинути цю групу? + Впевнені, що хочете видалити цей чат? + Впевнені, що хочете поділитися своєю контактною інформацією? + Впевнені, що хочете заблокувати цей контакт? + Впевнені, що хочете розблокувати цей контакт? + Впевнені, що хочете видалити цей контакт? + Впевнені, що хочете почати секретний чат? + Ви впевнені, що хочете скасувати реєстрацію? + Впевнені, що хочете очистити історію? + Впевнені, що хочете видалити %1$s? + Відправити повідомлення %1$s? + Переслати повідомлення %1$s? + Вибачте, ця можливість поки недоступна у вашій країні. + + + Telegram + Швидко + Безкоштовн + Безпечн + Потужно + У хмарі + Приватно + Самий швидкий]]> месенджер у світі.]]>А ще безкоштовний]]> і безпечний]]>. + Telegram]]> доставляє повідомлення швидше, ніж]]>будь-який інший додаток. + Telegram]]> безкоштовний назавжди. Без реклами.]]>Без абонентської плати. + Telegram]]> зберігає ваші повідомлення у безпеці]]>від хакерських атак. + Telegram]]> не має обмежень на розмір]]>ваших медіа та чатів. + Telegram]]> дозволяє Вам отримувати доступ до Ваших повідомлень]]>на безлічі пристроїв. + Telegram]]> повідомлення надійно зашифровані]]>і можуть самознищуватися. + Почати спілкування + + %1$d в мережі + %1$d в мережі + %1$d в мережі + %1$d в мережі + %1$d в мережі + %1$d в мережі + %1$d учасник + %1$d учасників + %1$d учасника + %1$d учасників + %1$d учасників + і ще %1$d друкують + і ще %1$d друкує + і ще %1$d друкує + і ще %1$d друкує + і ще %1$d друкує + немає повідомлень + %1$d нове повідомлення + %1$d нових повідомлень + %1$d нових повідомлення + %1$d нових повідомлень + %1$d нових повідомлень + немає повідомлень + %1$d повідомлення + %1$d повідомлень + %1$d повідомлення + %1$d повідомлень + %1$d повідомлень + немає елементів + %1$d елемент + %1$d елемент + %1$d елемента + %1$d елемента + %1$d елементів + із 0 чатів + із %1$d чата + із %1$d чатів + із %1$d чатів + із %1$d чата + із %1$d чата + %1$d секунд + %1$d секунда + %1$d секунди + %1$d секунд + %1$d секунд + %1$d секунд + %1$d хвилин + %1$d хвилина + %1$d хвилини + %1$d хвилин + %1$d хвилин + %1$d хвилин + %1$d година + %1$d годин + %1$d години + %1$d годин + %1$d годин + %1$d годин + %1$d днів + %1$d день + %1$d дні + %1$d днів + %1$d днів + %1$d днів + %1$d тижнів + %1$d тиждень + %1$d тижнів + %1$d тижнів + %1$d тижнів + %1$d тижнів + %1$d місяців + %1$d місяць + %1$d місяці + %1$d місяців + %1$d місяців + %1$d місяців + %1$d років + %1$d рік + %1$d роки + %1$d років + %1$d років + %1$d років + %1$d користувачів + %1$d користувач + %1$d користувача + %1$d користувачів + %1$d користувачів + %1$d користувачів + + + MMMM yyyy + MMM dd + dd.MM.yy + dd.MM.yyyy + MMMM d + MMMM d, yyyy + EEE + HH:mm + h:mm a + %1$s в %2$s + + + Plus Messenger для Android + Оформлення + Налаштування Plus + Неправильний hex-код кольору! + Колір теми + Скинути налаштування теми + Скасувати всі налаштування теми + Скинути налаштування теми за замовчуванням! + Загальне + Додаткові налаштування + Основний екран + Екран чату + Екран контактів + Заголовок + Рядки + Список чатів + Список чатів + Список контактів + Колір заголовка + Колір ім’я + Розмір ім’я + Колір повідомлення + Розмір повідомлення + Колір часу/дати + Розмір часу/дати + Колір лічильника повідомлення + Розмір лічильника повідомлення + Колір колонки + Колір тла лічильника повідомлення + Колір статусу + Розмір статусу + Колір правої бульбашки + Колір лівої бульбашки + Колір дати + Розмір дати + Колір бульбашки дати + Колір тексту срава + Колір тексту зліва + Колір часу справа + Колір часу зліва + Розмір часу + Колір введеного тексту + Розмір введеного тексту + Колір тла для введення тексту + Колір тла Emoji + Колір вибраної вкладки emoji + Колір значка на вкладці emoji + Колір статусу \"у мережі\" + Музика + Зберегти тему + Збережіть свою тему до теки Telegram/Themes + Тема збережена! + %1$s збережено до %2$s + Тема не створена. Застосуйте спочатку мод Messenger Plus + Налаштування відновлені з карти пам’яті + Не знайдено файл налаштування %s + Карту пам’яті не знайдено. + Введіть назву + Теми + Застосувати тему + Встановити xml теми з локальної папки + Колір учасника + Колір галочки доставлення + Колір беззвучного режиму + Відправляти журнали + Немає журналів + Вилучити журнали + журнали вилучені + Колір значка \"відправити\" + Приховати номер телефону з меню + Колір значка олівця + Тло значка олівця + Спільнота Google+ + Колір тексту \"...набирає повідомлення\" + Колір значка на панелі введення + Бічне меню + Список налаштування меню + Колір заливки бічного меню + Розмір ім’я + Колір номера телефону + Розмір номера телефону + Колір аватара + Колір значка меню + Колір тексту меню + Розмір тексту меню + Колір версії програми + Розмір версії програми + Колір тексту заголовка + Колір заголовка значка + Колір значків на вкладці + Колір лічильника на вкладці + Колір тла лічильника на вкладці + Лічильник чатів замість лічильника повідомлень + Враховувати повідомлення тільки в чатах з сповіщеннями + Приховати лічильники на вкладках + Колір розділової лінії + Закруглення аватара + Встановити колір учасника + Колір ім’я в пересланому повідомлені + Назва у заголовку + Копіювати/Переслати + Увімкнути спливаючі сповіщення + Екрану профілю + Приховати фонове зображення + Колір посилання справа + Колір посилання зліва + Тема застосована! + Натисніть ОК для перезавантаження + Використовувати системні emoji + Стиль бульбашки + Оригінальна назва файлів + Завантажені файли в папці Telegram/Documents будуть мати формат \"Ім\'я файла_Дата завантаження\" + Розмір аватара + Розмістити аватар зверху + Відступ від аватара зліва + Колір назви групи + Розмір назви групи + Колір ім\'я (невідомого номеру) + Приховати фонову тінь + Встановити колір тла + Колір тла + Розмір панелі Emoji + Колір правої бульбашки форварда + Колір лівої бульбашки форварда + Колір значків + Екран Налаштування/Теми + Колір тла + Колір тіні + Колір секції + Колір заголовка + Колір підписів + Колір тексту \'Фото/Наліпок\' + Хочете переглянути теми, створені іншими користувачами Messenger Plus? + Використовувати шрифт пристрою + Plus Messenger буде перезавантажений + Колір значка групи + Колір ім’я переданого контакту + Колір тла вкладення + Колір тексту вкладення + Показати аватар контакту в чаті + Показати свій аватар в чаті + Показати свій аватар в чаті групи + Розміщення свого аватара зверху + Колір заголовку/кнопок діалогу + Показати ім\'я користувача з ім\'ям учасника + Не зупиняти аудіо + Колір роздільника списку + Центрувати аватар, ім\'я та телефон + Градієнт + Колір градієнта + Вимкнено + Зверху вниз + Зліва направо + Зверху наліво, знизу направо + Знизу наліво, зверху направо + Застосувати градієнт до тла списку + %s скопійовано до буферу обміну + +\n\nПриєднуйтесь до офіційного каналу Plus Messenger: https://telegram.me/plusmsgr + Завантажити теми + Офіційний канал + Діалоги + Натисніть на зображення контакту + Натисніть на зображення групи + Профіль + Зображення профіля + Колір тла лічильника повідомлень з вимк. сповіщеннями + Змінити колір команд бота + Колір команд бота + Колір підсвічування пошуку + %s оновлено + Приховати індикатор статусу користувача + Приховати вкладки + Всі + Користувачі + Групи + Супергрупи + Канали + Боти + Улюблені + Висота вкладок + Встановити як вкладку за замовчуванням + Скинути вкладку за замовчуванням + Сортувати за статусом + Сортувати за останнім повідомленням + Сортувати за непрочитаних повідомлень + Показати вкладку супергрупи + Приховати вкладку супергрупи + Вкладки + Показати/Приховати Вкладки + Додати до улюблених + Стерти з улюбленого + Немає улюблених\n\nДля додавання будь-якого чату в цей список, просто натисніть на назву чату і утримуйте, а потім виберіть \"Додати до улюблених\". + Не приховувати вкладки при прокрутці + Прокручування вкладок + Показувати кнопку \"надсилання\" + ЦИТАТА + Вилучити з списку адміністраторів + Показати ім\'я користувача замість номера телефону + Позначити як прочитане + Позначити всі діалоги як прочитані + Стиль мітки +
diff --git a/TMessagesProj/src/main/res/xml/automotive_app_desc.xml b/TMessagesProj/src/main/res/xml/automotive_app_desc.xml new file mode 100644 index 00000000..b6df3b51 --- /dev/null +++ b/TMessagesProj/src/main/res/xml/automotive_app_desc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file